LibreCAD
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
lwpolyline.cpp
Go to the documentation of this file.
1 #include <memory>
2 #include <cmath>
4 #include "cad/geometry/geoarc.h"
8 #include <cad/primitive/arc.h>
9 #include <cad/primitive/line.h>
10 
11 using namespace lc;
12 using namespace entity;
13 
14 
15 LWPolyline::LWPolyline(const std::vector<LWVertex2D> &vertex,
16  double width,
17  double elevation,
18  double tickness,
19  bool closed,
20  geo::Coordinate const &extrusionDirection,
21  const Layer_CSPtr layer,
22  const MetaInfo_CSPtr metaInfo,
23  const Block_CSPtr block) :
24  CADEntity(layer, metaInfo, block),
25  _vertex(vertex),
26  _width(width),
27  _elevation(elevation),
28  _tickness(tickness),
29  _closed(closed),
30  _extrusionDirection(extrusionDirection) {
31 
33 
34 }
35 
36 LWPolyline::LWPolyline(const LWPolyline_CSPtr other, bool sameID) : CADEntity(other, sameID),
37  _vertex(other->_vertex),
38  _width(other->_width),
39  _elevation(other->_elevation),
40  _tickness(other->_tickness),
41  _closed(other->_closed),
42  _extrusionDirection(other->_extrusionDirection) {
44 }
45 
46 CADEntity_CSPtr LWPolyline::move(const geo::Coordinate &offset) const {
47  std::vector<LWVertex2D> newVertex;
48  for (auto vertex : _vertex) {
49  newVertex.emplace_back(vertex.location() + offset, vertex.bulge(), vertex.startWidth(), vertex.endWidth());
50  }
51  auto newEntity = std::make_shared<LWPolyline>(newVertex, width(), elevation(), tickness(), closed(),
53  newEntity->setID(this->id());
54  return newEntity;
55 }
56 
57 CADEntity_CSPtr LWPolyline::copy(const geo::Coordinate &offset) const {
58  std::vector<LWVertex2D> newVertex;
59  for (auto vertex : _vertex) {
60  newVertex.emplace_back(vertex.location() + offset, vertex.bulge(), vertex.startWidth(), vertex.endWidth());
61  }
62  auto newEntity = std::make_shared<LWPolyline>(newVertex, width(), elevation(), tickness(), closed(),
64  return newEntity;
65 }
66 
67 CADEntity_CSPtr LWPolyline::rotate(const geo::Coordinate &rotation_center, const double rotation_angle) const {
68  std::vector<LWVertex2D> newVertex;
69  for (auto vertex : _vertex) {
70  newVertex.emplace_back(vertex.location().rotate(rotation_center, rotation_angle), vertex.bulge(),
71  vertex.startWidth(), vertex.endWidth());
72  }
73  auto newEntity = std::make_shared<LWPolyline>(newVertex, width(), elevation(), tickness(), closed(),
75  return newEntity;
76 }
77 
78 CADEntity_CSPtr LWPolyline::scale(const geo::Coordinate &scale_center, const geo::Coordinate &scale_factor) const {
79  std::vector<LWVertex2D> newVertex;
80  if (scale_factor.x() != scale_factor.y()) {
81  // TODO decide what to do with non-uniform scale factors
82  }
83  for (auto vertex : _vertex) {
84  newVertex.emplace_back(vertex.location().scale(scale_center, scale_factor), vertex.bulge() * scale_factor.x(),
85  vertex.startWidth(), vertex.endWidth());
86  }
87  auto newEntity = std::make_shared<LWPolyline>(newVertex, width(), elevation(), tickness(), closed(),
89  return newEntity;
90 }
91 
93  if(_entities.size() == 0) {
94  return geo::Area();
95  }
96 
97  auto it = _entities.begin();
98  geo::Area area = (*it)->boundingBox();
99  it++;
100 
101  while(it != _entities.end()) {
102  area = area.merge((*it)->boundingBox());
103  it++;
104  }
105 
106  return area;
107 }
108 
109 CADEntity_CSPtr LWPolyline::modify(Layer_CSPtr layer, const MetaInfo_CSPtr metaInfo, Block_CSPtr block) const {
110  auto newEntity = std::make_shared<LWPolyline>(
111  _vertex,
112  _width,
113  _elevation,
114  _tickness,
115  _closed,
117  layer,
118  metaInfo,
119  block
120  );
121  newEntity->setID(this->id());
122 
123  return newEntity;
124 }
125 
127  auto itr = _vertex.begin();
128  auto lastPoint = itr;
129  itr++;
130  while (itr != vertex().end()) {
131  if (lastPoint->bulge() != 0.) {
132  _entities.push_back(std::make_shared<const Arc>(
133  geo::Arc::createArcBulge(lastPoint->location(), itr->location(), lastPoint->bulge()),
134  layer(),
135  metaInfo(),
136  block()
137  ));
138  }
139  else {
140  _entities.push_back(std::make_shared<const Line>(lastPoint->location(), itr->location(), layer(), metaInfo(), block()));
141  }
142  lastPoint = itr;
143  itr++;
144  }
145 
146  if (_closed) {
147  auto firstP = _vertex.begin();
148  if (lastPoint->bulge() != 0.) {
149  _entities.push_back(std::make_shared<const Arc>(
150  geo::Arc::createArcBulge(lastPoint->location(), firstP->location(), lastPoint->bulge()),
151  layer(),
152  metaInfo(),
153  block()
154  ));
155  }
156  else {
157  _entities.push_back(std::make_shared<const Line>(lastPoint->location(), firstP->location(), layer(), metaInfo(), block()));
158  }
159  }
160 }
161 
162 std::vector<EntityCoordinate> LWPolyline::snapPoints(const geo::Coordinate &coord, const SimpleSnapConstrain &constrain,
163  double minDistanceToSnap,
164  int maxNumberOfSnapPoints) const {
165  std::vector<EntityCoordinate> points;
166  if (constrain.constrain() & SimpleSnapConstrain::LOGICAL) {
167  const auto &&entities = asEntities();
168  for (auto &geoItem : entities) {
169  if (auto vector = std::dynamic_pointer_cast<const geo::Vector>(geoItem)) {
170  points.emplace_back(vector->start(), -1);
171  points.emplace_back(vector->end(), -2);
172  } else if (auto arc = std::dynamic_pointer_cast<const geo::Arc>(geoItem)) {
173  points.emplace_back(arc->startP(), -3);
174  points.emplace_back(arc->endP(), -4);
175  points.emplace_back(arc->center(), -5);
176 
177  // Add 4 coordinates
178  // Top Point
179  if (arc->isAngleBetween(.5 * M_PI)) {
180  const auto coord = arc->center() + lc::geo::Coordinate(0., arc->radius());
181  points.emplace_back(coord, 1);
182  }
183  // Right Point
184  if (arc->isAngleBetween(0)) {
185  const auto coord = arc->center() + lc::geo::Coordinate(arc->radius(), 0.);
186  points.emplace_back(coord, 2);
187  }
188  // Left Point
189  if (arc->isAngleBetween(M_PI)) {
190  const auto coord = arc->center() + lc::geo::Coordinate(-arc->radius(), 0.);
191  points.emplace_back(coord, 3);
192  }
193  // Bottom Point
194  if (arc->isAngleBetween(-.5 * M_PI)) {
195  const auto coord = arc->center() + lc::geo::Coordinate(0., -arc->radius());
196  points.emplace_back(coord, 4);
197  }
198  } else {
199  std::cerr << "Unknown entity found in LWPolyline during snapPoints generation" << std::endl;
200  }
201  }
202  }
203 
204  if (constrain.constrain() & SimpleSnapConstrain::ON_ENTITY) {
205  auto &&info = nearestPointOnPath2(coord);
206  geo::Coordinate npoe = std::get<0>(info);
207  if (auto &arc = std::get<2>(info)) {
208  const double a = (npoe - arc->center()).angle();
209  if (arc->isAngleBetween(a)) {
210  points.emplace_back(npoe, -6);
211  }
212  } else if (auto &vector = std::get<1>(info)) {
213  if (vector->nearestPointOnEntity(coord).distanceTo(coord) < minDistanceToSnap) {
214  points.emplace_back(npoe, -7);
215  }
216  }
217  }
218 
219  if (constrain.constrain() & SimpleSnapConstrain::ON_ENTITYPATH) {
220  geo::Coordinate npoe = nearestPointOnPath(coord);
221  points.emplace_back(npoe, -1);
222  }
223 
224  // Cleanup array of snappoints
225  Snapable::snapPointsCleanup(points, coord, maxNumberOfSnapPoints, minDistanceToSnap);
226  return points;
227 }
228 
230  auto &&info = nearestPointOnPath2(coord);
231  return std::get<0>(info);
232 }
233 
234 std::tuple<geo::Coordinate, std::shared_ptr<const geo::Vector>, std::shared_ptr<const geo::Arc>> LWPolyline::nearestPointOnPath2(
235  const geo::Coordinate &coord) const {
236  const auto &&entities = asEntities();
237 
238  double minimumDistance = std::numeric_limits<double>::max();
239  std::shared_ptr<const geo::Vector> nearestVector = nullptr;
240  std::shared_ptr<const geo::Arc> nearestArc = nullptr;
241  geo::Coordinate nearestCoordinate;
242  for (auto &geoItem : entities) {
243  if (auto vector = std::dynamic_pointer_cast<const geo::Vector>(geoItem)) {
244  auto npoe = vector->nearestPointOnPath(coord);
245  auto thisDistance = npoe.distanceTo(coord);
246  if (thisDistance < minimumDistance) {
247  minimumDistance = thisDistance;
248  nearestCoordinate = npoe;
249  nearestVector = vector;
250  }
251  } else if (auto arc = std::dynamic_pointer_cast<const geo::Arc>(geoItem)) {
252  auto npoe = arc->nearestPointOnPath(coord);
253  auto thisDistance = npoe.distanceTo(coord);
254  if (thisDistance < minimumDistance) {
255  minimumDistance = thisDistance;
256  nearestCoordinate = npoe;
257  nearestArc = arc;
258  }
259  } else {
260  std::cerr << "Unknown entity found in LWPolyline during boundingBox generation" << std::endl;
261  }
262  }
263  return std::make_tuple(nearestCoordinate, nearestVector, nearestArc);
264 }
265 
266 
267 std::map<unsigned int, lc::geo::Coordinate> LWPolyline::dragPoints() const {
268  std::map<unsigned int, geo::Coordinate> dragPoints;
269  unsigned int i = 0;
270 
271  for(auto vertex : _vertex) {
272  dragPoints[i] = vertex.location();
273  i++;
274  }
275 
276  return dragPoints;
277 }
278 
279 
280 CADEntity_CSPtr LWPolyline::setDragPoints(std::map<unsigned int, lc::geo::Coordinate> dragPoints) const {
281  try {
282  std::vector<LWVertex2D> newVertex;
283  unsigned int i = 0;
284 
285  for(auto vertex : _vertex) {
286  newVertex.push_back(LWVertex2D(dragPoints[i], vertex.bulge(), vertex.startWidth(), vertex.endWidth()));
287  i++;
288  }
289 
290  auto newEntity = std::make_shared<LWPolyline>(newVertex, width(), elevation(), tickness(), closed(), extrusionDirection(), layer(), metaInfo());
291  newEntity->setID(id());
292  return newEntity;
293  }
294  catch(std::out_of_range& e) {
295  return shared_from_this();
296  }
297 }
298 
299 std::vector<CADEntity_CSPtr> const LWPolyline::asEntities() const {
300  return _entities;
301 }
virtual CADEntity_CSPtr modify(Layer_CSPtr layer, const MetaInfo_CSPtr metaInfo, Block_CSPtr block) const override
modify Return a new entity with the same ID bit with possible modified metainfo and/pr layer informat...
Definition: lwpolyline.cpp:109
geo::Coordinate const & extrusionDirection() const
Definition: lwpolyline.h:125
virtual CADEntity_CSPtr scale(const geo::Coordinate &scale_center, const geo::Coordinate &scale_factor) const override
scale, scales the entity
Definition: lwpolyline.cpp:78
virtual CADEntity_CSPtr move(const geo::Coordinate &offset) const override
move, moves by an offset
Definition: lwpolyline.cpp:46
static const uint16_t LOGICAL
Definition: snapconstrain.h:22
double x() const
Returns x of Coordinate.
Definition: geocoordinate.h:26
double elevation() const
Definition: lwpolyline.h:117
std::vector< LWVertex2D > const & vertex() const
Definition: lwpolyline.h:129
static const uint16_t ON_ENTITYPATH
Definition: snapconstrain.h:19
Layer_CSPtr layer() const
layer return the layer this entity is placed on
Definition: cadentity.cpp:29
double y() const
Returns y of Coordinate.
Definition: geocoordinate.h:34
double width() const
Definition: lwpolyline.h:113
virtual geo::Coordinate nearestPointOnPath(const geo::Coordinate &coord) const override
Find the nearest point on the path for this entity for the coordinate coord The path of a entity that...
Definition: lwpolyline.cpp:229
Area merge(const Area &other) const
merge two area's and expand if required to largest containing area
Definition: geoarea.h:156
virtual std::map< unsigned int, lc::geo::Coordinate > dragPoints() const override
Get all points of the entity that can be dragged.
Definition: lwpolyline.cpp:267
static Arc createArcBulge(const Coordinate &p1, const Coordinate &p2, const double bulge)
Definition: geoarc.cpp:51
MetaInfo_CSPtr metaInfo() const
Definition: cadentity.h:123
static const uint16_t ON_ENTITY
Definition: snapconstrain.h:18
Definition: cadentity.h:12
LWPolyline(const std::vector< LWVertex2D > &vertex, double width, double elevation, double tickness, bool closed, geo::Coordinate const &extrusionDirection, const Layer_CSPtr layer, const MetaInfo_CSPtr metaInfo=nullptr, const Block_CSPtr block=nullptr)
Definition: lwpolyline.cpp:15
const double _width
Definition: lwpolyline.h:153
virtual CADEntity_CSPtr rotate(const geo::Coordinate &rotation_center, const double rotation_angle) const override
rotate, rotate operation
Definition: lwpolyline.cpp:67
static void snapPointsCleanup(std::vector< EntityCoordinate > &points, const geo::Coordinate &reference, const unsigned int maxNumberOfSnapPoints, const double minDistanceToSnap)
Definition: snapable.h:53
std::tuple< geo::Coordinate, std::shared_ptr< const geo::Vector >, std::shared_ptr< const geo::Arc > > nearestPointOnPath2(const geo::Coordinate &coord) const
Definition: lwpolyline.cpp:234
const double _tickness
Definition: lwpolyline.h:155
const geo::Coordinate _extrusionDirection
Definition: lwpolyline.h:157
bool closed() const
Definition: lwpolyline.h:133
double tickness() const
Definition: lwpolyline.h:121
const double _elevation
Definition: lwpolyline.h:154
virtual CADEntity_CSPtr setDragPoints(std::map< unsigned int, lc::geo::Coordinate > dragPoints) const override
Return modified entity.
Definition: lwpolyline.cpp:280
std::vector< CADEntity_CSPtr > _entities
Definition: lwpolyline.h:158
Block_CSPtr block() const
Return the current entity block.
Definition: cadentity.cpp:33
virtual const geo::Area boundingBox() const override
boundingBox of the entity
Definition: lwpolyline.cpp:92
#define M_PI
Definition: const.h:16
const uint16_t constrain() const
Definition: snapconstrain.h:47
virtual CADEntity_CSPtr copy(const geo::Coordinate &offset) const override
copy, copies by an offset
Definition: lwpolyline.cpp:57
const std::vector< LWVertex2D > _vertex
Definition: lwpolyline.h:152
double distanceTo(const geo::Coordinate &c) const
virtual std::vector< EntityCoordinate > snapPoints(const geo::Coordinate &coord, const SimpleSnapConstrain &constrain, double minDistanceToSnap, int maxNumberOfSnapPoints) const override
Find a number of snap points the line has available This function returns a ordered list...
Definition: lwpolyline.cpp:162
void generateEntities()
Generate entities of the polyline.
Definition: lwpolyline.cpp:126
std::vector< CADEntity_CSPtr > const asEntities() const
Definition: lwpolyline.cpp:299