LibreCAD
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
entitycontainer.h
Go to the documentation of this file.
1 #pragma once
2 
3 #include <memory>
4 #include <limits>
5 #include <string>
6 #include <vector>
7 
8 #include "cad/const.h"
9 #include "cad/base/id.h"
11 
12 #include "cad/vo/entitydistance.h"
15 #include "cad/primitive/line.h"
16 
17 namespace lc {
18  class Layer;
32  template <typename CT>
34  public:
41  _tree = new QuadTree<CT>(geo::Area(geo::Coordinate(-500000., -500000.),
42  geo::Coordinate(500000., 500000.)
43  ));
44  }
45 
51  _tree = new QuadTree<CT>(*other._tree);
52  }
53 
54 
55  virtual ~EntityContainer() {
56  delete _tree;
57  }
58 
60  if (this != &ec) {
61  _tree = new QuadTree<CT>(*ec._tree);
62  }
63 
64  return *this;
65  }
66 
72  void insert(CT entity) {
73  _tree->insert(entity);
74  }
75 
76 
82  void combine(const EntityContainer& entities) {
83  for (auto i : entities.asVector(std::numeric_limits<short>::max())) {
84  _tree->insert(i);
85  }
86  }
87 
92  void remove(CT entity) {
93  _tree->erase(entity);
94  }
95 
103  std::vector<CT> asVector(short maxLevel = std::numeric_limits<short>::max()) const {
104  return _tree->retrieve(maxLevel);
105  }
112  CT entityByID(ID_DATATYPE id) const {
113  return _tree->entityByID(id);
114  }
115 
122  EntityContainer entitiesByLayer(const Layer_CSPtr layer) const {
123  EntityContainer container;
124 
125  for (auto i : asVector(std::numeric_limits<short>::max())) {
126  if (i->layer() == layer) {
127  container.insert(i);
128  }
129  }
130 
131  return container;
132  }
133 
141  EntityContainer entitiesByMetaType(const std::string& metaName) const {
142  EntityContainer container;
143 
144  for (auto i : asVector(std::numeric_limits<short>::max())) {
145  // if (i->metaInfo(metaName) != nullptr) {
146  // container.insert(i);
147  // }
148  }
149 
150  return container;
151  }
152 
162  const short maxLevel = std::numeric_limits<short>::max()) const {
163  EntityContainer container;
164  std::vector<CT> entities = _tree->retrieve(area, maxLevel);
165 
166  for (auto i : entities) {
167  // If the item fully with's with the selection area sinmply add it
168  if (i->boundingBox().inArea(area)) {
169  container.insert(i);
170  }
171  }
172 
173  return container;
174  }
175 
180  geo::Area extends;
181  const std::vector<CT> entities = _tree->retrieve();
182  if (entities.size() > 0) {
183  extends = entities[0]->boundingBox();
184  for (const auto &i : entities) {
185  extends = extends.merge(i->boundingBox());
186  }
187  }
188  return extends;
189  }
190 
204  const short maxLevel = std::numeric_limits<short>::max()) const {
205  EntityContainer container;
206  std::vector<CT> entities = _tree->retrieve(area, maxLevel);
207 
208  for (auto i : entities) {
209 
210  // If the item fully with's with the selection area sinmply add it
211  if (i->boundingBox().inArea(area)) {
212  container.insert(i);
213  continue;
214  }
215 
216  // if it has 2 corners inside area, we know for 100% sure that the entity, or
217  // at least part of it is located within area
218  // We test for 2 (not 1) because for exampke with a arc we can have one corner inside
219  // The area, but still not intersecting with area
220  auto c = i->boundingBox().numCornersInside(area);
221 
222  if (c == 2) {
223  container.insert(i);
224  continue;
225  }
226 
227  // Path to area intersection testing
228  lc::Intersect intersect(Intersect::OnEntity, 10e-4);
229 
230  auto &&v = area.top();
231  visitorDispatcher<bool, lc::GeoEntityVisitor>(intersect, v, *i.get());
232  if (!intersect.result().empty()) {
233  container.insert(i);
234  continue;
235  }
236 
237  v = area.left();
238  visitorDispatcher<bool, GeoEntityVisitor>(intersect, v, *i.get());
239  if (!intersect.result().empty()) {
240  container.insert(i);
241  continue;
242  }
243 
244  v = area.bottom();
245  visitorDispatcher<bool, GeoEntityVisitor>(intersect, v, *i.get());
246  if (!intersect.result().empty()) {
247  container.insert(i);
248  continue;
249  }
250 
251  v = area.right();
252  visitorDispatcher<bool, GeoEntityVisitor>(intersect, v, *i.get());
253  if (!intersect.result().empty()) {
254  container.insert(i);
255  continue;
256  }
257  }
258 
259  return container;
260  }
261 
273  const short maxLevel = std::numeric_limits<short>::max()) const {
274  EntityContainer container;
275 
276  std::vector<CT> &&entities = _tree->retrieve(area, maxLevel);
277 
278  for (auto &i : entities) {
279  // If the item fully with's with the selection area simply add it
280  if (i->boundingBox().overlaps(area)) {
281  container.insert(i);
282  }
283  }
284 
285  return container;
286  }
287 
294  std::vector<lc::EntityDistance> getEntityPathsNearCoordinate(const lc::geo::Coordinate& point,
295  double distance) const {
296 
297  const auto area = lc::geo::Area(lc::geo::Coordinate(point.x(), point.y())+distance/2.,
298  lc::geo::Coordinate(point.x(),point.y())+distance/2.);
299  std::vector<CT> ent = _tree->retrieve(area);
300 
301  // Now calculate for each entity if we are near the entities path
302  std::vector<lc::EntityDistance> entities;
303  for (auto item : ent) {
304  Snapable_CSPtr entity = std::dynamic_pointer_cast<const lc::Snapable>(item);
305 
306  if (entity != nullptr) { // Not all entities might be snapable, so we only test if this is possible.
307  lc::geo::Coordinate eCoordinate = entity->nearestPointOnPath(point);
308  if (eCoordinate.distanceTo(point) < distance) {
309  entities.emplace_back(item, eCoordinate);
310  }
311  }
312  }
313 
314  return entities;
315  }
316 
323  return _tree->bounds();
324  }
325 
330  void optimise() {
331  _tree->optimise();
332  }
333 
334 
346  template<typename U, typename T> void each(T func) {
347  _tree->template each<U>(func);
348  }
349 
350  template<typename U, typename T> void each(T func) const {
351  _tree->template each<const U>(func);
352  }
353  private:
355  };
356 }
The EntityContainer class manages a set of entities. This call will allow to select (but not manipula...
bool erase(const E entity)
remove Remove entity from quad tree
Definition: quadtree.h:571
virtual ~EntityContainer()
double x() const
Returns x of Coordinate.
Definition: geocoordinate.h:26
#define ID_DATATYPE
Definition: id.h:7
Vector right() const
right vector of this area
Definition: geoarea.h:242
const E entityByID(ID_DATATYPE id) const
Definition: quadtree.h:583
lc::geo::Area bounds() const
bound returns the size of the document
calculate the intersection pojnts of 2 entities
Definition: intersect.h:35
EntityContainer entitiesByLayer(const Layer_CSPtr layer) const
findEntitiesByLayer Return a entities container with all entities from a specific layer ...
EntityContainer(const EntityContainer &other)
EntityContainer Copy Constructor.
double y() const
Returns y of Coordinate.
Definition: geocoordinate.h:34
bool optimise()
optimise Optmise this tree. Current implementation will remove empty nodes up till the root node ...
Definition: quadtree.h:294
void optimise()
optimise this container
Area merge(const Area &other) const
merge two area's and expand if required to largest containing area
Definition: geoarea.h:156
EntityContainer & operator=(const EntityContainer &ec)
Definition: cadentity.h:12
void each(T func) const
EntityContainer entitiesWithinAndCrossingAreaFast(const geo::Area &area, const short maxLevel=std::numeric_limits< short >::max()) const
entitiesWithinAndCrossingAreaFast Find all entities within a selected area. Unlike entitiesWithinAndC...
geo::Area bounds() const
bounds of the root portion of the tree
Definition: quadtree.h:223
geo::Area boundingBox() const
Vector top() const
top vector of this area
Definition: geoarea.h:198
std::vector< E > retrieve(const geo::Area &area, const short maxLevel=SHRT_MAX) const
retrieve all object's that are located within a given area
Definition: quadtree.h:172
EntityContainer entitiesByMetaType(const std::string &metaName) const
entitiesByMetaType Return all entities that contain's a specific metaInfo
QuadTree< CT > * _tree
Vector bottom() const
bottom vector of this area
Definition: geoarea.h:216
void insert(const E entity)
insert Insert entity into the quad tree
Definition: quadtree.h:541
std::vector< lc::EntityDistance > getEntityPathsNearCoordinate(const lc::geo::Coordinate &point, double distance) const
getEntityPathsNearCoordinate
EntityContainer()
EntityContainer Default constructor. Usually you would retrieve a EntityContainer from the document...
double distanceTo(const geo::Coordinate &c) const
std::vector< CT > asVector(short maxLevel=std::numeric_limits< short >::max()) const
asVector return all entities as std::vector optionally up until a given level This is useful to retur...
Vector left() const
left vector for this area
Definition: geoarea.h:207
EntityContainer entitiesFullWithinArea(const geo::Area &area, const short maxLevel=std::numeric_limits< short >::max()) const
entitiesByArea Find all entities within a selected area based on boundingbox of the entities ...
void combine(const EntityContainer &entities)
Add all entities to this container Any entity that already exists will get replaced.
void insert(CT entity)
add an entity to the EntityContainer If the entity already exists, it will be replaced ...
EntityContainer entitiesWithinAndCrossingArea(const geo::Area &area, const short maxLevel=std::numeric_limits< short >::max()) const
entitiesWithinAndCrossingArea Find all entities within a selected area or where the path is crossing ...
CT entityByID(ID_DATATYPE id) const
entityByID return a entity by it's id, return's a empty shared ptr when not found ...