ACloudViewer  3.9.4
A Modern Library for 3D Data Processing
ccGeoObject.cpp
Go to the documentation of this file.
1 // ----------------------------------------------------------------------------
2 // - CloudViewer: www.cloudViewer.org -
3 // ----------------------------------------------------------------------------
4 // Copyright (c) 2018-2024 www.cloudViewer.org
5 // SPDX-License-Identifier: MIT
6 // ----------------------------------------------------------------------------
7 
8 #include "ccGeoObject.h"
9 
10 #include "ccPinchNode.h"
11 #include "ccTopologyRelation.h"
12 
15  bool singleSurface)
16  : ccHObject(name) {
17  m_app = app;
18 
19  // add "interior", "upper" and "lower" HObjects
20  if (!singleSurface) {
22  generateUpper();
23  generateLower();
24  }
25  // generate GID
26  assignGID();
27 
28  init(singleSurface);
29 }
30 
32  : ccHObject(obj->getName()) {
33  m_app = app;
34 
35  // n.b. object should already have upper, inner and lower children
36  // n.b.b sometimes it doesn't as children are stripped before the object is
37  // created!
38 
39  // copy GID key
40  QVariant GID = obj->getMetaData("GID");
41  if (GID.isValid()) {
42  _gID = GID.toUInt();
43  } else {
44  assignGID(); // no GID defined, assign a new one
45  }
46 
48 }
49 
50 void ccGeoObject::assignGID() {
51  // get uniquely descriptive hash
52  _gID = static_cast<unsigned int>(std::hash<std::string>{}(
53  QString::asprintf("%s%d", getName().toLatin1().data(),
54  getUniqueID())
55  .toStdString()));
56 }
57 
58 void ccGeoObject::init(bool singleSurface) {
59  // add metadata tag defining the ccCompass class type
60  QVariantMap* map = new QVariantMap();
61  if (singleSurface) {
62  map->insert("ccCompassType", "GeoObjectSS"); // single-surface
63  // GeoObject
64  } else {
65  map->insert("ccCompassType", "GeoObject");
66  }
67  map->insert("GID", getGID());
68  setMetaData(*map, true);
69 }
70 
72 
73 ccHObject* ccGeoObject::getRegion(int mappingRegion) {
75  return this; // SingleSurface GeoObjects only have a single region;
76  // this is essentially a combined upper, lower and
77  // interior
78  }
79 
80  // for normal GeoObjects, look for the specific region
81  switch (mappingRegion) {
83  // check region hasn't been deleted...
85  // not found - make or find a new one
87  }
88  return m_interior;
90  // check region hasn't been deleted...
91  if (!m_app->dbRootObject()->find(m_upper_id)) {
92  // not found - make or find a new one
93  generateUpper();
94  }
95  return m_upper;
97  // check region hasn't been deleted...
98  if (!m_app->dbRootObject()->find(m_lower_id)) {
99  // item has been deleted... make or find a new one
100  generateLower();
101  }
102  return m_lower;
103  default:
104  return nullptr;
105  }
106 }
107 
108 // gets the topological relationship between this GeoObject and another
110  ccTopologyRelation* r = getRelation(
111  this, getUniqueID(),
112  obj->getUniqueID()); // search for a relation belonging to us
113  bool invert = false;
114  if (!r) // not found - search for a relation belonging to obj
115  {
116  r = getRelation(obj, getUniqueID(), obj->getUniqueID());
117  invert = true; // we need to invert backwards relationships (i.e. Obj
118  // OLDER THAN this, so this YOUNGER THAN Obj)
119  }
120 
121  if (r) // a relation was found
122  {
123  *out = r; // set out pointer
124 
125  if (!invert) {
126  return r->getType();
127  } else { // we need to invert backwards relationships (i.e. Obj OLDER
128  // THAN this, so this YOUNGER THAN Obj)
130  }
131  } else {
132  *out = nullptr;
134  }
135 }
136 
137 // recurse down the tree looking for the specified topology relationship
138 ccTopologyRelation* ccGeoObject::getRelation(ccHObject* obj, int id1, int id2) {
139  // is this object the relation we are looking for?
141  ccTopologyRelation* r = dynamic_cast<ccTopologyRelation*>(obj);
142  if (r) {
143  if ((r->getOlderID() == id1 && r->getYoungerID() == id2) ||
144  (r->getOlderID() == id2 && r->getYoungerID() == id1)) {
145  return r; // already has relationship between these objects
146  }
147  }
148  }
149 
150  // search children
151  for (unsigned i = 0; i < obj->getChildrenNumber(); i++) {
152  ccTopologyRelation* r = getRelation(obj->getChild(i), id1, id2);
153  if (r) {
154  return r; // cascade positive respones up
155  }
156  }
157 
158  return nullptr; // nothing found
159 }
160 
161 // adds a topological relationship between this GeoObject and another
163  int type,
164  ecvMainAppInterface* app) {
165  // does this relation already exist??
166  ccTopologyRelation* out = nullptr;
167  getRelationTo(obj2, &out);
168 
169  if (out) {
170  // todo: ask if relation should be replaced?
171  app->dispToConsole("Relation already exists!",
173  return nullptr;
174  }
175 
176  // all good - create and add a new one (assume relation is in the younger
177  // form)
178  ccGeoObject* younger = this;
179  ccGeoObject* older = obj2;
180 
181  // if relation is in older form, invert it
185  type = ccTopologyRelation::invertType(type); // invert type
186 
187  // flip start and end (i.e. we are older than obj2)
188  younger = obj2;
189  older = this;
190  }
191 
192  // build point cloud for TopologyRelation
193  ccPointCloud* verts = new ccPointCloud("vertices");
194  assert(verts);
195  verts->setEnabled(false); // this is used for storage only!
196  verts->setVisible(false); // this is used for storage only!
197 
198  // build TopologyRelation
200  verts, older->getUniqueID(), younger->getUniqueID(), type);
201  t->constructGraphic(older, younger);
202 
203  // always store with younger member
205  m_app->addToDB(this, false, false, false, true);
206 
207  return t;
208 }
209 
210 void ccGeoObject::setActive(bool active) {
211  for (ccHObject* c : m_children) {
212  recurseChildren(c, active);
213  }
214 }
215 
216 void ccGeoObject::recurseChildren(ccHObject* par, bool highlight) {
217  // set if par is a measurement
218  ccMeasurement* m = dynamic_cast<ccMeasurement*>(par);
219  if (m) {
220  // is this object in the upper boundary?
221  bool upperBoundary = false;
222  ccHObject* p = par->getParent();
223  while (p && highlight) // if highlight is set to false, we don't need
224  // to bother
225  {
227  // yes!
228  upperBoundary = true;
229  break;
230  } else if (ccGeoObject::isGeoObjectLower(p) |
232  // different region - bail
233  break;
234  }
235  p = p->getParent(); // continue looking/recursing upwards
236  }
237 
238  if (upperBoundary) {
239  m->setAlternate(highlight); // upper boundary drawn in cyan
240  } else {
241  m->setAlternate(false); // disable alternate colour if it was
242  // previously active
243  m->setHighlight(
244  highlight); // other boundaries/regions drawn in green
245  }
246 
247  // draw labels (except for trace objects and tips, when the child plane
248  // object will hold the useful info)
249  if (!ccTrace::isTrace(par) && !ccPinchNode::isPinchNode(par)) {
250  par->showNameIn3D(highlight);
251  }
252 
253  if (highlight) // show active objects...
254  {
255  par->setVisible(true);
256  } else // hide annoying graphics on leaving traceMode (we basically
257  // only want traces to be visible)
258  {
260  par->setVisible(false);
261  }
262  }
263  }
264 
265  // recurse
266  for (unsigned i = 0; i < par->getChildrenNumber(); i++) {
267  ccHObject* c = par->getChild(i);
268  recurseChildren(c, highlight);
269  }
270 }
271 
273  // check interior doesn't already exist
274  for (unsigned i = 0; i < getChildrenNumber(); i++) {
275  ccHObject* c = getChild(i);
277  m_interior = c;
278  m_interior_id = c->getUniqueID();
279  return;
280  }
281  }
282 
283  m_interior = new ccHObject("Interior");
284 
285  // give them associated property flags
286  QVariantMap* map = new QVariantMap();
287  map->insert("ccCompassType", "GeoInterior");
288  m_interior->setMetaData(*map, true);
289 
290  // add these to the scene graph
293 }
294 
296  // check upper doesn't already exist
297  for (unsigned i = 0; i < getChildrenNumber(); i++) {
298  ccHObject* c = getChild(i);
300  m_upper = c;
301  m_upper_id = c->getUniqueID();
302  return;
303  }
304  }
305 
306  m_upper = new ccHObject("Upper Boundary");
307 
308  QVariantMap* map = new QVariantMap();
309  map->insert("ccCompassType", "GeoUpperBoundary");
310  m_upper->setMetaData(*map, true);
311 
312  addChild(m_upper);
314 }
315 
317  // check lower doesn't already exist
318  for (unsigned i = 0; i < getChildrenNumber(); i++) {
319  ccHObject* c = getChild(i);
321  m_lower = c;
322  m_lower_id = c->getUniqueID();
323  return;
324  }
325  }
326 
327  m_lower = new ccHObject("Lower Boundary");
328 
329  QVariantMap* map = new QVariantMap();
330  map->insert("ccCompassType", "GeoLowerBoundary");
331  m_lower->setMetaData(*map, true);
332 
333  addChild(m_lower);
335 }
336 
338  if (object->hasMetaData("ccCompassType")) {
339  return object->getMetaData("ccCompassType")
340  .toString()
341  .contains("GeoObject");
342  }
343  return false;
344 }
345 
347  if (object->hasMetaData("ccCompassType")) {
348  return object->getMetaData("ccCompassType")
349  .toString()
350  .contains("GeoUpperBoundary");
351  }
352  return false;
353 }
354 
356  if (object->hasMetaData("ccCompassType")) {
357  return object->getMetaData("ccCompassType")
358  .toString()
359  .contains("GeoLowerBoundary");
360  }
361  return false;
362 }
363 
365  if (object->hasMetaData("ccCompassType")) {
366  return object->getMetaData("ccCompassType")
367  .toString()
368  .contains("GeoInterior");
369  }
370  return false;
371 }
372 
374  if (object->hasMetaData("ccCompassType")) {
375  return object->getMetaData("ccCompassType")
376  .toString()
377  .contains("GeoObjectSS");
378  }
379  return false;
380 }
381 
383  while (object != nullptr) {
384  // is this a GeoObject?
385  if (ccGeoObject::isGeoObject(object)) {
386  return dynamic_cast<ccGeoObject*>(object);
387  }
388 
389  object = object->getParent();
390  }
391 
392  return nullptr;
393 }
394 
396  // recurse up until we find a georegion
397  ccHObject* parent = object->getParent();
398  while (parent != nullptr &&
399  !(isGeoObjectUpper(parent) | isGeoObjectLower(parent) |
400  isGeoObjectInterior(parent) | isSingleSurfaceGeoObject(parent))) {
401  parent = parent->getParent();
402  }
403 
404  if (parent == nullptr) {
405  return -1;
406  } else if (ccGeoObject::isGeoObjectInterior(parent) |
407  isSingleSurfaceGeoObject(parent)) {
408  return ccGeoObject::INTERIOR;
409  } else if (ccGeoObject::isGeoObjectUpper(parent)) {
411  } else if (ccGeoObject::isGeoObjectLower(parent)) {
413  } else {
414  return -2; // unknown ...should never happen?
415  }
416 }
std::string name
char type
virtual void setVisible(bool state)
Sets entity visibility.
virtual void showNameIn3D(bool state)
Sets whether name should be displayed in 3D.
static bool isFitPlane(ccHObject *object)
Definition: ccFitPlane.cpp:99
int getRelationTo(ccGeoObject *obj, ccTopologyRelation **out=nullptr)
void setActive(bool active)
static ccGeoObject * getGeoObjectParent(ccHObject *object)
int m_upper_id
Definition: ccGeoObject.h:72
static bool isGeoObjectInterior(ccHObject *object)
ccHObject * m_lower
Definition: ccGeoObject.h:76
static const int INTERIOR
Definition: ccGeoObject.h:54
static const int UPPER_BOUNDARY
Definition: ccGeoObject.h:55
ccHObject * m_upper
Definition: ccGeoObject.h:71
void generateInterior()
void generateLower()
ccPointCloud * m_associatedCloud
Definition: ccGeoObject.h:64
static int getGeoObjectRegion(ccHObject *object)
ccHObject * getRegion(int mappingRegion)
Definition: ccGeoObject.cpp:73
int m_lower_id
Definition: ccGeoObject.h:77
ccPointCloud * getAssociatedCloud()
Definition: ccGeoObject.cpp:71
ccHObject * m_interior
Definition: ccGeoObject.h:67
ccTopologyRelation * addRelationTo(ccGeoObject *obj2, int type, ecvMainAppInterface *app)
static bool isGeoObjectLower(ccHObject *object)
void generateUpper()
int m_interior_id
Definition: ccGeoObject.h:68
static bool isGeoObject(ccHObject *object)
static bool isSingleSurfaceGeoObject(ccHObject *object)
ccGeoObject(QString name, ecvMainAppInterface *app, bool singleSurface)
Definition: ccGeoObject.cpp:13
static const int LOWER_BOUNDARY
Definition: ccGeoObject.h:56
static bool isGeoObjectUpper(ccHObject *object)
ecvMainAppInterface * m_app
Definition: ccGeoObject.h:60
unsigned int getGID()
Definition: ccGeoObject.h:51
Hierarchical CLOUDVIEWER Object.
Definition: ecvHObject.h:25
ccHObject * find(unsigned uniqueID)
Finds an entity in this object hierarchy.
unsigned getChildrenNumber() const
Returns the number of children.
Definition: ecvHObject.h:312
virtual bool addChild(ccHObject *child, int dependencyFlags=DP_PARENT_OF_OTHER, int insertIndex=-1)
Adds a child.
ccHObject * getParent() const
Returns parent object.
Definition: ecvHObject.h:245
ccHObject(QString name=QString())
Default constructor.
ccHObject * getChild(unsigned childPos) const
Returns the ith child.
Definition: ecvHObject.h:325
Container m_children
Children.
Definition: ecvHObject.h:712
void setAlternate(bool isActive)
Definition: ccMeasurement.h:50
void setHighlight(bool isActive)
Definition: ccMeasurement.h:49
virtual QString getName() const
Returns object name.
Definition: ecvObject.h:72
virtual unsigned getUniqueID() const
Returns object unique ID.
Definition: ecvObject.h:86
void setMetaData(const QString &key, const QVariant &data)
Sets a meta-data element.
QVariant getMetaData(const QString &key) const
Returns a given associated meta data.
bool hasMetaData(const QString &key) const
Returns whether a meta-data element with the given key exists or not.
virtual void setEnabled(bool state)
Sets the "enabled" property.
Definition: ecvObject.h:102
static bool isPinchNode(ccHObject *obj)
Definition: ccPinchNode.cpp:34
A 3D cloud and its associated features (color, normals, scalar fields, etc.)
static bool isPointPair(ccHObject *object)
static int invertType(int type)
static const int UNKNOWN
static const int NOT_OLDER_THAN
static const int IMMEDIATELY_PRECEDES
static const int OLDER_THAN
void constructGraphic(ccGeoObject *older, ccGeoObject *younger)
static bool isTopologyRelation(ccHObject *obj)
static bool isTrace(ccHObject *object)
Definition: ccTrace.cpp:1102
Main application interface (for plugins)
virtual ccHObject * dbRootObject()=0
Returns DB root (as a ccHObject)
virtual void addToDB(ccHObject *obj, bool updateZoom=false, bool autoExpandDBTree=true, bool checkDimensions=false, bool autoRedraw=true)=0
virtual void dispToConsole(QString message, ConsoleMessageLevel level=STD_CONSOLE_MESSAGE)=0