ACloudViewer  3.9.4
A Modern Library for 3D Data Processing
ecvPolyline.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 "ecvPolyline.h"
9 
10 // Local
11 #include "ecvCone.h"
12 #include "ecvDisplayTools.h"
13 #include "ecvPointCloud.h"
14 
15 ccPolyline::ccPolyline(GenericIndexedCloudPersist* associatedCloud)
16  : Polyline(associatedCloud), ccShiftedObject("Polyline") {
17  set2DMode(false);
18  setTransformFlag(true);
19  setForeground(true);
20  setVisible(true);
21  lockVisibility(false);
23  showVertices(false);
25  setWidth(0);
26  showArrow(false, 0, 0);
27 
28  ccGenericPointCloud* cloud =
29  dynamic_cast<ccGenericPointCloud*>(associatedCloud);
30  if (cloud) {
33  }
34 }
35 
37  : Polyline(associatedCloud.cloneThis(nullptr)),
38  ccShiftedObject("Polyline") {
39  this->set2DMode(false);
40  this->setTransformFlag(true);
41  this->setForeground(true);
42  this->setVisible(true);
43  this->lockVisibility(false);
45  this->showColors(true);
46  this->showVertices(false);
47  this->setVertexMarkerWidth(3);
48  this->setWidth(2);
49  this->showArrow(false, 0, 0);
50 
51  int verticesCount = getAssociatedCloud()->size();
52  if (this->reserve(verticesCount)) {
53  this->addPointIndex(0, verticesCount);
54  this->setVisible(true);
55 
56  bool closed = false;
57  CCVector3 start =
60  getAssociatedCloud()->getPoint(verticesCount - 1)->u);
61  if (cloudViewer::LessThanEpsilon((end - start).norm())) {
62  closed = true;
63  } else {
64  closed = false;
65  }
66 
67  this->setClosed(closed);
68 
69  setGlobalScale(associatedCloud.getGlobalScale());
70  setGlobalShift(associatedCloud.getGlobalShift());
71  } else {
72  cloudViewer::utility::LogError("[ccPolyline] not enough memory!");
73  }
74 }
75 
77  : Polyline(0), ccShiftedObject(poly) {
78  initWith(nullptr, poly);
79 }
80 
81 bool ccPolyline::initWith(ccPointCloud* vertices, const ccPolyline& poly) {
82  bool success = true;
83  if (!vertices) {
84  ccPointCloud* cloud =
85  dynamic_cast<ccPointCloud*>(poly.m_theAssociatedCloud);
86  ccPointCloud* clone =
87  cloud ? cloud->partialClone(&poly) : ccPointCloud::From(&poly);
88  if (clone) {
89  if (cloud)
90  clone->setName(
91  cloud->getName()); // as 'partialClone' adds the
92  // '.extract' suffix by default
93  else
96  } else {
97  // not enough memory?
99  "[ccPolyline::initWith] Not enough memory to duplicate "
100  "vertices!");
101  success = false;
102  }
103 
104  vertices = clone;
105  }
106 
107  if (vertices) {
108  setAssociatedCloud(vertices);
109  addChild(vertices);
110  // vertices->setEnabled(false);
111  assert(m_theAssociatedCloud);
112  if (m_theAssociatedCloud) {
114  CVLog::Warning("[ccPolyline::initWith] Not enough memory");
115  success = false;
116  }
117  }
118  }
119 
120  importParametersFrom(poly);
121 
122  return success;
123 }
124 
126  setClosed(poly.m_isClosed);
127  set2DMode(poly.m_mode2D);
129  setVisible(poly.isVisible());
131  setColor(poly.m_rgbColor);
132  setWidth(poly.m_width);
133  showColors(poly.colorsShown());
134  showVertices(poly.verticesShown());
136  setVisible(poly.isVisible());
141  setMetaData(poly.metaData());
142 }
143 
144 void ccPolyline::set2DMode(bool state) { m_mode2D = state; }
145 
146 void ccPolyline::setForeground(bool state) { m_foreground = state; }
147 
148 void ccPolyline::showArrow(bool state,
149  unsigned vertIndex,
150  PointCoordinateType length) {
151  m_showArrow = state;
152  m_arrowIndex = vertIndex;
153  m_arrowLength = length;
154 }
155 
156 ccBBox ccPolyline::getOwnBB(bool withGLFeatures /*=false*/) {
157  ccBBox emptyBox;
158  getBoundingBox(emptyBox.minCorner(), emptyBox.maxCorner());
159  emptyBox.setValidity(
160  (!is2DMode() || !withGLFeatures) &&
161  size() !=
162  0); // a 2D polyline is considered as a purely 'GL' fature
163  return emptyBox;
164 }
165 
166 bool ccPolyline::hasColors() const { return true; }
167 
169  // transparent call
171 
172  // invalidate the bounding-box
173  //(and we hope the vertices will be updated as well!)
175 }
176 
177 // unit arrow
178 static QSharedPointer<ccCone> c_unitArrow(0);
179 
181  unsigned vertCount = size();
182  if (vertCount < 2) return;
183 
184  bool draw = false;
185 
186  if (MACRO_Draw3D(context)) {
187  draw = !m_mode2D;
188  } else if (m_mode2D) {
189  bool drawFG = MACRO_Foreground(context);
190  draw = ((drawFG && m_foreground) || (!drawFG && !m_foreground));
191  }
192 
193  if (!draw) return;
194 
195  if (ecvDisplayTools::GetMainWindow() == nullptr) return;
196 
197  if (isColorOverridden()) {
198  context.defaultPolylineColor = getTempColor();
199  } else if (colorsShown()) {
200  context.defaultPolylineColor = m_rgbColor;
201  }
202 
203  if (m_showVertices) {
204  context.defaultPointSize = static_cast<unsigned>(m_vertMarkWidth);
205  }
206 
207  // display polyline
208  if (vertCount > 1) {
209  if (m_width != 0) {
210  context.currentLineWidth = m_width;
211  } else {
212  context.currentLineWidth = context.defaultLineWidth;
213  }
214 
216 
217  // display arrow
218  if (m_showArrow && m_arrowIndex < vertCount &&
219  (m_arrowIndex > 0 || m_isClosed)) {
220  const CCVector3* P0 = getPoint(
221  m_arrowIndex == 0 ? vertCount - 1 : m_arrowIndex - 1);
222  const CCVector3* P1 = getPoint(m_arrowIndex);
223  // direction of the last polyline chunk
224  CCVector3 u = *P1 - *P0;
225  u.normalize();
226 
227  if (m_mode2D) {
228  u *= -m_arrowLength;
229  static const PointCoordinateType s_defaultArrowAngle =
230  static_cast<PointCoordinateType>(
232  static const PointCoordinateType cost =
233  cos(s_defaultArrowAngle);
234  static const PointCoordinateType sint =
235  sin(s_defaultArrowAngle);
236  CCVector3 A(cost * u.x - sint * u.y, sint * u.x + cost * u.y,
237  0);
238  CCVector3 B(cost * u.x + sint * u.y, -sint * u.x + cost * u.y,
239  0);
240  // glFunc->glBegin(GL_POLYGON);
241  // ccGL::Vertex3v(glFunc, (A + *P1).u);
242  // ccGL::Vertex3v(glFunc, (B + *P1).u);
243  // ccGL::Vertex3v(glFunc, (*P1).u);
244  // glFunc->glEnd();
245  } else {
246  if (!c_unitArrow) {
247  c_unitArrow =
248  QSharedPointer<ccCone>(new ccCone(0.5, 0.0, 1.0));
249  c_unitArrow->showColors(true);
250  c_unitArrow->showNormals(false);
251  c_unitArrow->setVisible(true);
252  c_unitArrow->setEnabled(true);
253  }
254  if (colorsShown())
255  c_unitArrow->setTempColor(m_rgbColor);
256  else
257  c_unitArrow->setTempColor(context.pointsDefaultCol);
258  // build-up unit arrow own 'context'
259  CC_DRAW_CONTEXT markerContext = context;
260  markerContext.drawingFlags &=
261  (~CC_ENTITY_PICKING); // we must remove the 'push
262  // name flag' so that the
263  // sphere doesn't push its
264  // own!
265 
266  markerContext.transformInfo.setTranslationStart(
267  CCVector3(P1->x, P1->y, P1->z));
269  CCVector3d(u.x, u.y, u.z), CCVector3d(0, 0, PC_ONE));
270  markerContext.transformInfo.setTransformation(rotMat.inverse(),
271  false);
272  markerContext.transformInfo.setScale(
274  markerContext.transformInfo.setTranslationEnd(
275  CCVector3(0.0, 0.0, -0.5));
276  c_unitArrow->draw(markerContext);
277  }
278  }
279  }
280 }
281 
283 
284 bool ccPolyline::toFile_MeOnly(QFile& out, short dataVersion) const {
285  assert(out.isOpen() && (out.openMode() & QIODevice::WriteOnly));
286  if (dataVersion < 31) {
287  assert(false);
288  return false;
289  }
290 
291  if (!ccHObject::toFile_MeOnly(out, dataVersion)) return false;
292 
293  // we can't save the associated cloud here (as it may be shared by multiple
294  // polylines) so instead we save it's unique ID (dataVersion>=28) WARNING:
295  // the cloud must be saved in the same BIN file! (responsibility of the
296  // caller)
297  ccPointCloud* vertices = dynamic_cast<ccPointCloud*>(m_theAssociatedCloud);
298  if (!vertices) {
300  "[ccPolyline::toFile_MeOnly] Polyline vertices is not a "
301  "ccPointCloud structure?!");
302  return false;
303  }
304  uint32_t vertUniqueID =
305  (m_theAssociatedCloud ? (uint32_t)vertices->getUniqueID() : 0);
306  if (out.write((const char*)&vertUniqueID, 4) < 0) return WriteError();
307 
308  // number of points (references to) (dataVersion>=28)
309  uint32_t pointCount = size();
310  if (out.write((const char*)&pointCount, 4) < 0) return WriteError();
311 
312  // points (references to) (dataVersion>=28)
313  for (uint32_t i = 0; i < pointCount; ++i) {
314  uint32_t pointIndex = getPointGlobalIndex(i);
315  if (out.write((const char*)&pointIndex, 4) < 0) return WriteError();
316  }
317 
318  //'global shift & scale' (dataVersion>=39)
319  saveShiftInfoToFile(out);
320 
321  QDataStream outStream(&out);
322 
323  // Closing state (dataVersion>=28)
324  outStream << m_isClosed;
325 
326  // RGB Color (dataVersion>=28)
327  outStream << m_rgbColor.r;
328  outStream << m_rgbColor.g;
329  outStream << m_rgbColor.b;
330 
331  // 2D mode (dataVersion>=28)
332  outStream << m_mode2D;
333 
334  // Foreground mode (dataVersion>=28)
335  outStream << m_foreground;
336 
337  // The width of the line (dataVersion>=31)
338  outStream << m_width;
339 
340  return true;
341 }
342 
344  short minVersion = (isShifted() ? 39 : 31);
345  return std::max(minVersion, ccHObject::minimumFileVersion_MeOnly());
346 }
347 
349  short dataVersion,
350  int flags,
351  LoadedIDMap& oldToNewIDMap) {
352  if (!ccHObject::fromFile_MeOnly(in, dataVersion, flags, oldToNewIDMap))
353  return false;
354 
355  if (dataVersion < 28) return false;
356 
357  // as the associated cloud (=vertices) can't be saved directly (as it may be
358  // shared by multiple polylines) we only store its unique ID
359  // (dataVersion>=28) --> we hope we will find it at loading time (i.e. this
360  // is the responsibility of the caller to make sure that all dependencies
361  // are saved together)
362  uint32_t vertUniqueID = 0;
363  if (in.read((char*)&vertUniqueID, 4) < 0) return ReadError();
364  //[DIRTY] WARNING: temporarily, we set the vertices unique ID in the
365  //'m_associatedCloud' pointer!!!
366  *(uint32_t*)(&m_theAssociatedCloud) = vertUniqueID;
367 
368  // number of points (references to) (dataVersion>=28)
369  uint32_t pointCount = 0;
370  if (in.read((char*)&pointCount, 4) < 0) return ReadError();
371  if (!reserve(pointCount)) return false;
372 
373  // points (references to) (dataVersion>=28)
374  for (uint32_t i = 0; i < pointCount; ++i) {
375  uint32_t pointIndex = 0;
376  if (in.read((char*)&pointIndex, 4) < 0) return ReadError();
377  addPointIndex(pointIndex);
378  }
379 
380  //'global shift & scale' (dataVersion>=39)
381  m_globalScale = 1.0;
382  m_globalShift = CCVector3d(0, 0, 0);
383  if (dataVersion >= 39) {
384  if (!loadShiftInfoFromFile(in)) {
385  return ReadError();
386  }
387  }
388 
389  QDataStream inStream(&in);
390 
391  // Closing state (dataVersion>=28)
392  inStream >> m_isClosed;
393 
394  // RGB Color (dataVersion>=28)
395  inStream >> m_rgbColor.r;
396  inStream >> m_rgbColor.g;
397  inStream >> m_rgbColor.b;
398 
399  // 2D mode (dataVersion>=28)
400  inStream >> m_mode2D;
401 
402  // Foreground mode (dataVersion>=28)
403  inStream >> m_foreground;
404 
405  // Width of the line (dataVersion>=31)
406  m_width = 0;
407  if (dataVersion >= 31) {
409  1);
410  }
411 
412  return true;
413 }
414 
416  std::vector<ccPolyline*>& parts) {
417  parts.clear();
418 
419  // not enough vertices?
420  unsigned vertCount = size();
421  if (vertCount <= 2) {
422  parts.push_back(new ccPolyline(*this));
423  return true;
424  }
425 
426  unsigned startIndex = 0;
427  unsigned lastIndex = vertCount - 1;
428  while (startIndex <= lastIndex) {
429  unsigned stopIndex = startIndex;
430  while (stopIndex < lastIndex &&
431  (*getPoint(stopIndex + 1) - *getPoint(stopIndex)).norm() <=
432  maxEdgeLength) {
433  ++stopIndex;
434  }
435 
436  // number of vertices for the current part
437  unsigned partSize = stopIndex - startIndex + 1;
438 
439  // if the polyline is closed we have to look backward for the first
440  // segment!
441  if (startIndex == 0) {
442  if (isClosed()) {
443  unsigned realStartIndex = vertCount;
444  while (realStartIndex > stopIndex &&
445  (*getPoint(realStartIndex - 1) -
446  *getPoint(realStartIndex % vertCount))
447  .norm() <= maxEdgeLength) {
448  --realStartIndex;
449  }
450 
451  if (realStartIndex == stopIndex) {
452  // whole loop
453  parts.push_back(new ccPolyline(*this));
454  return true;
455  } else if (realStartIndex < vertCount) {
456  partSize += (vertCount - realStartIndex);
457  assert(realStartIndex != 0);
458  lastIndex = realStartIndex - 1;
459  // warning: we shift the indexes!
460  startIndex = realStartIndex;
461  stopIndex += vertCount;
462  }
463  } else if (partSize == vertCount) {
464  // whole polyline
465  parts.push_back(new ccPolyline(*this));
466  return true;
467  }
468  }
469 
470  if (partSize > 1) // otherwise we skip that point
471  {
472  // create the corresponding part
474  if (!ref.reserve(partSize)) {
475  CVLog::Error("[ccPolyline::split] Not enough memory!");
476  return false;
477  }
478 
479  for (unsigned i = startIndex; i <= stopIndex; ++i) {
480  ref.addPointIndex(i % vertCount);
481  }
482 
483  ccPointCloud* vertices =
484  dynamic_cast<ccPointCloud*>(m_theAssociatedCloud);
485  ccPointCloud* subset = vertices ? vertices->partialClone(&ref)
486  : ccPointCloud::From(&ref);
487  ccPolyline* part = new ccPolyline(subset);
488  part->initWith(subset, *this);
489  part->setClosed(false); // by definition!
490  parts.push_back(part);
491  }
492 
493  // forward
494  startIndex = (stopIndex % vertCount) + 1;
495  }
496 
497  return true;
498 }
499 
500 bool ccPolyline::add(const ccPointCloud& cloud) {
501  if (cloud.IsEmpty()) {
502  return false;
503  }
504 
505  if (!this->getAssociatedCloud()) {
506  ccPointCloud* vertices =
507  const_cast<ccPointCloud&>(cloud).cloneThis(nullptr);
508  return initWith(vertices, *this);
509  }
510 
511  ccPointCloud* oldCloud = static_cast<ccPointCloud*>(m_theAssociatedCloud);
512  if (!oldCloud) {
514  "[ccPolyline::add] invalid associated cloud!");
515  return false;
516  }
517  unsigned int newCount = cloud.size();
518  unsigned int currentSize = oldCloud->size();
519  if (!oldCloud->reserve(currentSize + newCount)) {
520  cloudViewer::utility::LogWarning("[ccPolyline] Not enough memory!");
521  return false;
522  }
523 
524  // copy new indexes (warning: no duplicate check!)
525  for (unsigned i = 0; i < newCount; ++i) {
526  oldCloud->addPoint(*cloud.getPoint(i));
527  }
528  addPointIndex(currentSize, currentSize + newCount);
529 
530  return true;
531 }
532 
534  PointCoordinateType length = 0;
535 
536  unsigned vertCount = size();
537  if (vertCount > 1 && m_theAssociatedCloud) {
538  unsigned lastVert = isClosed() ? vertCount : vertCount - 1;
539  for (unsigned i = 0; i < lastVert; ++i) {
540  CCVector3 A;
541  getPoint(i, A);
542  CCVector3 B;
543  getPoint((i + 1) % vertCount, B);
544 
545  length += (B - A).norm();
546  }
547  }
548 
549  return length;
550 }
551 
553  if (m_parent && m_parent->getParent() &&
555  return m_parent->getParent()->getUniqueID();
556  else
557  return getUniqueID();
558 }
559 
560 unsigned ccPolyline::segmentCount() const {
561  unsigned count = size();
562  if (count && !isClosed()) {
563  --count;
564  }
565  return count;
566 }
567 
570 
571  ccPointCloud* pc = dynamic_cast<ccPointCloud*>(m_theAssociatedCloud);
572  if (pc && pc->getParent() == this) {
573  // auto transfer the global shift info to the vertices
574  pc->setGlobalShift(shift);
575  }
576 }
577 
578 void ccPolyline::setGlobalScale(double scale) {
580 
581  ccPointCloud* pc = dynamic_cast<ccPointCloud*>(m_theAssociatedCloud);
582  if (pc && pc->getParent() == this) {
583  // auto transfer the global scale info to the vertices
584  pc->setGlobalScale(scale);
585  }
586 }
587 
589  double samplingParameter,
590  bool withRGB) {
591  if (samplingParameter <= 0 || size() < 2) {
592  assert(false);
593  return nullptr;
594  }
595 
596  // we must compute the total length of the polyline
597  double L = this->computeLength();
598 
599  unsigned pointCount = 0;
600  if (densityBased) {
601  pointCount = static_cast<unsigned>(ceil(L * samplingParameter));
602  } else {
603  pointCount = static_cast<unsigned>(samplingParameter);
604  }
605 
606  if (pointCount == 0) {
607  assert(false);
608  return nullptr;
609  }
610 
611  // convert to real point cloud
612  ccPointCloud* cloud =
613  new ccPointCloud(getName() + "." + QObject::tr("sampled"));
614  if (!cloud->reserve(pointCount)) {
615  CVLog::Warning("[ccPolyline::samplePoints] Not enough memory");
616  delete cloud;
617  return nullptr;
618  }
619 
620  double samplingStep = L / pointCount;
621  double s = 0.0; // current sampled point curvilinear position
622  unsigned indexA = 0; // index of the segment start vertex
623  double sA = 0.0; // curvilinear pos of the segment start vertex
624 
625  for (unsigned i = 0; i < pointCount;) {
626  unsigned indexB = ((indexA + 1) % size());
627  const CCVector3& A = *getPoint(indexA);
628  const CCVector3& B = *getPoint(indexB);
629  CCVector3 AB = B - A;
630  double lAB = AB.normd();
631 
632  double relativePos = s - sA;
633  if (relativePos >= lAB) {
634  // specific case: last point
635  if (i + 1 == pointCount) {
636  // assert(relativePos < lAB * 1.01); //it should only be a
637  // rounding issue in the worst case
638  relativePos = lAB;
639  } else // skip this segment
640  {
641  ++indexA;
642  sA += lAB;
643  continue;
644  }
645  }
646 
647  // now for the interpolation work
648  double alpha = relativePos / lAB;
649  alpha = std::max(alpha, 0.0); // just in case
650  alpha = std::min(alpha, 1.0);
651 
652  CCVector3 P = A + static_cast<PointCoordinateType>(alpha) * AB;
653  cloud->addPoint(P);
654 
655  // proceed to the next point
656  ++i;
657  s += samplingStep;
658  }
659 
660  if (withRGB) {
661  if (isColorOverridden()) {
662  // we use the default 'temporary' color
663  cloud->setRGBColor(getTempColor());
664  } else if (colorsShown()) {
665  // we use the default color
666  cloud->setRGBColor(m_rgbColor);
667  }
668  }
669 
670  // import parameters from the source
671  cloud->setGlobalShift(getGlobalShift());
672  cloud->setGlobalScale(getGlobalScale());
674 
675  return cloud;
676 }
677 
678 Eigen::Vector3d ccPolyline::GetMinBound() const {
680 }
681 
682 Eigen::Vector3d ccPolyline::GetMaxBound() const {
684 }
685 
686 Eigen::Vector3d ccPolyline::GetCenter() const {
688 }
689 
691  std::vector<CCVector3> points;
692  for (unsigned index : m_theIndexes) {
693  points.push_back(*m_theAssociatedCloud->getPoint(index));
694  }
696 }
697 
699  if (!m_theAssociatedCloud) {
700  return ecvOrientedBBox();
701  }
702 
703  std::vector<CCVector3> points;
704  for (unsigned index : m_theIndexes) {
705  points.push_back(*m_theAssociatedCloud->getPoint(index));
706  }
708 }
709 
710 ccPolyline& ccPolyline::Transform(const Eigen::Matrix4d& transformation) {
711  GenericIndexedCloudPersist* asCloud = getAssociatedCloud();
712  if (!asCloud) {
713  return *this;
714  }
715  ccPointCloud* cloud = static_cast<ccPointCloud*>(asCloud);
716  if (cloud) {
717  cloud->Transform(transformation);
718  }
719 
720  return *this;
721 }
722 
723 ccPolyline& ccPolyline::Translate(const Eigen::Vector3d& translation,
724  bool relative) {
725  GenericIndexedCloudPersist* asCloud = getAssociatedCloud();
726  if (!asCloud) {
727  return *this;
728  }
729  ccPointCloud* cloud = static_cast<ccPointCloud*>(asCloud);
730  if (cloud) {
731  cloud->Translate(translation, relative);
732  }
733  return *this;
734 }
735 
736 ccPolyline& ccPolyline::Scale(const double s, const Eigen::Vector3d& center) {
737  GenericIndexedCloudPersist* asCloud = getAssociatedCloud();
738  if (!asCloud) {
739  return *this;
740  }
741  ccPointCloud* cloud = static_cast<ccPointCloud*>(asCloud);
742  if (cloud) {
743  cloud->Scale(s, center);
744  }
745  return *this;
746 }
747 
748 ccPolyline& ccPolyline::Rotate(const Eigen::Matrix3d& R,
749  const Eigen::Vector3d& center) {
750  GenericIndexedCloudPersist* asCloud = getAssociatedCloud();
751  if (!asCloud) {
752  return *this;
753  }
754  ccPointCloud* cloud = static_cast<ccPointCloud*>(asCloud);
755  if (cloud) {
756  cloud->Rotate(R, center);
757  }
758  return *this;
759 }
760 
762  if (polyline.IsEmpty()) return (*this);
763  if (!polyline.getAssociatedCloud()) {
765  "[ccPolyline] Cannot find associated cloud in polyline!");
766  return (*this);
767  }
768 
769  if (m_theAssociatedCloud == polyline.getAssociatedCloud()) {
770  if (!cloudViewer::ReferenceCloud::add(polyline)) {
771  cloudViewer::utility::LogError("[ccPolyline] Not enough memory!");
772  return (*this);
773  }
774  } else {
775  const ccPointCloud* cloud =
776  static_cast<const ccPointCloud*>(polyline.getAssociatedCloud());
777  if (!cloud || !add(*cloud)) {
779  "[ccPolyline] adding ccPolyline failed!");
780  }
781  }
782 
783  return (*this);
784 }
785 
787  if (this == &polyline) {
788  return (*this);
789  }
790 
791  this->clear();
792  *this += polyline;
793  // import other parameters
794  this->importParametersFrom(polyline);
795  return (*this);
796 }
797 
799  return (ccPolyline(*this) += polyline);
800 }
801 
803  unsigned iterationCount) const {
804  if (iterationCount == 0) {
805  assert(false);
807  "[ccPolyline::smoothChaikin] Invalid input (iteration count)");
808  return nullptr;
809  }
810 
811  if (ratio < 0.05f || ratio > 0.45f) {
812  assert(false);
813  CVLog::Warning("[ccPolyline::smoothChaikin] invalid ratio");
814  return nullptr;
815  }
816 
817  if (size() < 3) {
818  CVLog::Warning("[ccPolyline::smoothChaikin] not enough segments");
819  return nullptr;
820  }
821 
822  const cloudViewer::GenericIndexedCloudPersist* currentIterationVertices =
823  this; // a polyline is actually a ReferenceCloud!
824  ccPolyline* smoothPoly = nullptr;
825 
826  bool openPoly = !isClosed();
827 
828  for (unsigned it = 0; it < iterationCount; ++it) {
829  // reserve memory for the new vertices
830  unsigned vertCount = currentIterationVertices->size();
831  unsigned segmentCount = (openPoly ? vertCount - 1 : vertCount);
832 
833  ccPointCloud* newStateVertices = new ccPointCloud("vertices");
834  if (!newStateVertices->reserve(segmentCount * 2)) {
835  CVLog::Warning("[ccPolyline::smoothChaikin] not enough memory");
836  delete newStateVertices;
837  newStateVertices = nullptr;
838  delete currentIterationVertices;
839  currentIterationVertices = nullptr;
840  return nullptr;
841  }
842 
843  if (openPoly) {
844  // we always keep the first vertex
845  newStateVertices->addPoint(*currentIterationVertices->getPoint(0));
846  }
847 
848  for (unsigned i = 0; i < segmentCount; ++i) {
849  unsigned iP = i;
850  unsigned iQ = ((iP + 1) % vertCount);
851 
852  const CCVector3& P = *currentIterationVertices->getPoint(iP);
853  const CCVector3& Q = *currentIterationVertices->getPoint(iQ);
854 
855  if (!openPoly || i != 0) {
856  CCVector3 P0 = (PC_ONE - ratio) * P + ratio * Q;
857  newStateVertices->addPoint(P0);
858  }
859 
860  if (!openPoly || i + 1 != segmentCount) {
861  CCVector3 P1 = ratio * P + (PC_ONE - ratio) * Q;
862  newStateVertices->addPoint(P1);
863  }
864  }
865 
866  if (openPoly) {
867  // we always keep the last vertex
868  newStateVertices->addPoint(*currentIterationVertices->getPoint(
869  currentIterationVertices->size() - 1));
870  }
871 
872  if (currentIterationVertices != this) {
873  delete currentIterationVertices;
874  currentIterationVertices = nullptr;
875  }
876  currentIterationVertices = newStateVertices;
877 
878  // last iteration?
879  if (it + 1 == iterationCount) {
880  smoothPoly = new ccPolyline(newStateVertices);
881  smoothPoly->addChild(newStateVertices);
882  newStateVertices->setEnabled(false);
883  if (!smoothPoly->reserve(newStateVertices->size())) {
884  CVLog::Warning("[ccPolyline::smoothChaikin] not enough memory");
885  delete smoothPoly;
886  return nullptr;
887  }
888  smoothPoly->addPointIndex(0, newStateVertices->size());
889 
890  // copy state
891  smoothPoly->importParametersFrom(*this);
892  smoothPoly->setName(getName() +
893  QString(".smoothed (ratio=%1)").arg(ratio));
894  }
895  }
896 
897  return smoothPoly;
898 }
899 
901  ccPolyline** polyline /*=nullptr*/) {
902  if (!cloud) {
903  assert(false);
904  return false;
905  }
906 
907  // check whether the input point cloud acts as the vertices of a polyline
908  {
909  ccHObject* parent = cloud->getParent();
910  if (parent && parent->isKindOf(CV_TYPES::POLY_LINE) &&
911  static_cast<ccPolyline*>(parent)->getAssociatedCloud() == cloud) {
912  if (polyline) {
913  *polyline = static_cast<ccPolyline*>(parent);
914  }
915  return true;
916  }
917  }
918 
919  // now check the children
920  for (unsigned i = 0; i < cloud->getChildrenNumber(); ++i) {
921  ccHObject* child = cloud->getChild(i);
922  if (child && child->isKindOf(CV_TYPES::POLY_LINE) &&
923  static_cast<ccPolyline*>(child)->getAssociatedCloud() == cloud) {
924  if (polyline) {
925  *polyline = static_cast<ccPolyline*>(child);
926  }
927  return true;
928  }
929  }
930 
931  return false;
932 }
933 
935  std::vector<ccPolyline*>& output) {
936  if (!m_theAssociatedCloud) {
937  assert(false);
938  return false;
939  }
940  unsigned vertCount = size();
941 
942  // vertices visibility
943  ccGenericPointCloud* verticesCloud =
944  dynamic_cast<ccGenericPointCloud*>(getAssociatedCloud());
945  if (!verticesCloud) {
946  // no visibility table instantiated
948  "[ccPolyline::createNewPolylinesFromSelection] Unsupported "
949  "vertex cloud");
950  return false;
951  }
952  const ccGenericPointCloud::VisibilityTableType& verticesVisibility =
953  verticesCloud->getTheVisibilityArray();
954  if (verticesVisibility.size() < verticesCloud->size()) {
955  // no visibility table instantiated
957  "[ccPolyline::createNewPolylinesFromSelection] No visibility "
958  "table instantiated");
959  return false;
960  }
961 
962  bool success = true;
963  {
964  ccPolyline* chunkPoly = nullptr;
965  ccPointCloud* chunkCloud = nullptr;
966 
967  unsigned maxIndex = (m_isClosed ? vertCount : vertCount - 1);
968  for (unsigned i = 0; i < maxIndex; ++i) {
969  unsigned nextIndex = ((i + 1) % vertCount);
970 
971  unsigned pointIndex = getPointGlobalIndex(i);
972  unsigned nextPointIndex = getPointGlobalIndex(nextIndex);
973 
974  bool kept = false;
975  if (verticesVisibility.at(pointIndex) == POINT_VISIBLE &&
976  verticesVisibility.at(nextPointIndex) ==
977  POINT_VISIBLE) // segment should be kept
978  {
979  kept = true;
980 
981  const CCVector3* P0 = verticesCloud->getPoint(pointIndex);
982  const CCVector3* P1 = verticesCloud->getPoint(nextPointIndex);
983 
984  // recreate a chunk if none is ready yet
985  static const unsigned DefaultPolySizeIncrement = 64;
986  if (!chunkPoly) {
987  chunkCloud = new ccPointCloud("vertices");
988  chunkCloud->setEnabled(false);
989  chunkPoly = new ccPolyline(chunkCloud);
990  chunkPoly->addChild(chunkCloud);
991  if (!chunkPoly->reserve(DefaultPolySizeIncrement) ||
992  !chunkCloud->reserve(DefaultPolySizeIncrement)) {
993  delete chunkCloud;
994  success = false;
995  break;
996  }
997  chunkPoly->addPointIndex(0);
998  chunkCloud->addPoint(*P0);
999  } else if (chunkPoly->size() == chunkPoly->capacity()) {
1000  if (!chunkPoly->reserve(chunkPoly->size() +
1001  DefaultPolySizeIncrement) ||
1002  !chunkCloud->reserve(chunkCloud->size() +
1003  DefaultPolySizeIncrement)) {
1004  success = false;
1005  break;
1006  }
1007  }
1008 
1009  // add the next vertex
1010  chunkPoly->addPointIndex(chunkCloud->size());
1011  chunkCloud->addPoint(*P1);
1012  }
1013 
1014  if (!kept || i + 1 == maxIndex) {
1015  // store the active chunk (if any)
1016  if (chunkPoly) {
1017  chunkPoly->importParametersFrom(*this);
1018  chunkPoly->setName(getName() +
1019  QString(".segmented (part %1)")
1020  .arg(output.size() + 1));
1021  chunkCloud->shrinkToFit();
1022  chunkPoly->resize(chunkPoly->size());
1023  try {
1024  output.push_back(chunkPoly);
1025  } catch (const std::bad_alloc&) {
1026  success = false;
1027  break;
1028  }
1029  chunkPoly = nullptr;
1030  }
1031  }
1032  }
1033  }
1034 
1035  if (!success) {
1037  "[ccPolyline::createNewPolylinesFromSelection] Not enough "
1038  "memory");
1039  // delete the already created polylines
1040  for (ccPolyline* poly : output) {
1041  delete poly;
1042  }
1043  output.clear();
1044  }
1045 
1046  return success;
1047 }
1048 
1050  PointCoordinateType radius,
1051  unsigned resolution /*=48*/) {
1052  if (resolution < 4) {
1053  CVLog::Warning("[ccPolyline::Circle] Resolution is too small");
1054  return nullptr;
1055  }
1056 
1057  ccPointCloud* vertices = new ccPointCloud("vertices");
1058  ccPolyline* circle = new ccPolyline(vertices);
1059  if (!vertices->reserve(resolution) || !circle->reserve(resolution)) {
1060  CVLog::Error(QObject::tr("Not enough memory"));
1061  delete circle;
1062  return nullptr;
1063  }
1064 
1065  double angleStep_rad = 2 * M_PI / resolution;
1066  for (unsigned i = 0; i < resolution; ++i) {
1067  CCVector3 P = center + CCVector3(cos(i * angleStep_rad) * radius,
1068  sin(i * angleStep_rad) * radius, 0);
1069  vertices->addPoint(P);
1070  }
1071 
1072  vertices->setEnabled(false);
1073  circle->addChild(vertices);
1074  circle->addPointIndex(0, resolution);
1075  circle->setClosed(true);
1076  circle->setName("Circle");
1077  circle->setEnabled(true);
1078  circle->setVisible(true);
1079 
1080  return circle;
1081 }
constexpr unsigned char POINT_VISIBLE
Definition: CVConst.h:92
constexpr PointCoordinateType PC_ONE
'1' as a PointCoordinateType value
Definition: CVConst.h:67
constexpr double M_PI
Pi.
Definition: CVConst.h:19
Vector3Tpl< double > CCVector3d
Double 3D Vector.
Definition: CVGeom.h:804
Vector3Tpl< PointCoordinateType > CCVector3
Default 3D Vector.
Definition: CVGeom.h:798
float PointCoordinateType
Type of the coordinates of a (N-D) point.
Definition: CVTypes.h:16
int width
int count
int points
static bool Warning(const char *format,...)
Prints out a formatted warning message in console.
Definition: CVLog.cpp:133
static bool Error(const char *format,...)
Display an error dialog with formatted message.
Definition: CVLog.cpp:143
Type y
Definition: CVGeom.h:137
Type x
Definition: CVGeom.h:137
Type z
Definition: CVGeom.h:137
void normalize()
Sets vector norm to unity.
Definition: CVGeom.h:428
double normd() const
Returns vector norm (forces double precision output)
Definition: CVGeom.h:426
static Vector3Tpl fromArray(const int a[3])
Constructor from an int array.
Definition: CVGeom.h:268
Bounding box structure.
Definition: ecvBBox.h:25
static ccBBox CreateFromPoints(const std::vector< CCVector3 > &points)
Definition: ecvBBox.cpp:82
Cone (primitive)
Definition: ecvCone.h:16
virtual bool colorsShown() const
Returns whether colors are shown or not.
virtual bool isVisible() const
Returns whether entity is visible or not.
virtual bool isVisibilityLocked() const
Returns whether visibility is locked or not.
virtual void lockVisibility(bool state)
Locks/unlocks visibility.
virtual void setVisible(bool state)
Sets entity visibility.
virtual bool isColorOverridden() const
virtual void showColors(bool state)
Sets colors visibility.
virtual const ecvColor::Rgb & getTempColor() const
Returns current temporary (unique) color.
static ccGLMatrixTpl< double > FromToRotation(const Vector3Tpl< double > &from, const Vector3Tpl< double > &to)
Creates a transformation matrix that rotates a vector to another.
ccGLMatrixTpl< T > inverse() const
Returns inverse transformation.
Float version of ccGLMatrixTpl.
Definition: ecvGLMatrix.h:19
Double version of ccGLMatrixTpl.
Definition: ecvGLMatrix.h:56
A 3D cloud interface with associated features (color, normals, octree, etc.)
virtual VisibilityTableType & getTheVisibilityArray()
Returns associated visibility array.
std::vector< unsigned char > VisibilityTableType
Array of "visibility" information for each point.
Hierarchical CLOUDVIEWER Object.
Definition: ecvHObject.h:25
virtual const ccGLMatrix & getGLTransformationHistory() const
Returns the transformation 'history' matrix.
Definition: ecvHObject.h:631
void draw(CC_DRAW_CONTEXT &context) override
Draws entity and its children.
virtual short minimumFileVersion_MeOnly() const
virtual bool fromFile_MeOnly(QFile &in, short dataVersion, int flags, LoadedIDMap &oldToNewIDMap)
Loads own object data.
virtual bool toFile_MeOnly(QFile &out, short dataVersion) const
Save own object data.
unsigned getChildrenNumber() const
Returns the number of children.
Definition: ecvHObject.h:312
virtual void setGLTransformationHistory(const ccGLMatrix &mat)
Sets the transformation 'history' matrix (handle with care!)
Definition: ecvHObject.h:635
virtual void applyGLTransformation(const ccGLMatrix &trans)
Applies a GL transformation to the entity.
Definition: ecvHObject.cpp:944
ccHObject * getParent() const
Returns parent object.
Definition: ecvHObject.h:245
ccHObject * m_parent
Parent.
Definition: ecvHObject.h:709
virtual bool addChild(ccHObject *child, int dependencyFlags=DP_PARENT_OF_OTHER, int insertIndex=-1)
Adds a child.
Definition: ecvHObject.cpp:534
ccHObject * getChild(unsigned childPos) const
Returns the ith child.
Definition: ecvHObject.h:325
const QVariantMap & metaData() const
Returns meta-data map (const only)
Definition: ecvObject.h:184
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.
Definition: ecvObject.cpp:216
bool isA(CV_CLASS_ENUM type) const
Definition: ecvObject.h:131
virtual void setName(const QString &name)
Sets object name.
Definition: ecvObject.h:75
virtual void setEnabled(bool state)
Sets the "enabled" property.
Definition: ecvObject.h:102
bool isKindOf(CV_CLASS_ENUM type) const
Definition: ecvObject.h:128
A 3D cloud and its associated features (color, normals, scalar fields, etc.)
ccPointCloud * partialClone(const cloudViewer::ReferenceCloud *selection, int *warnings=nullptr, bool withChildEntities=true) const
Creates a new point cloud object from a ReferenceCloud (selection)
virtual bool IsEmpty() const override
virtual ccPointCloud & Rotate(const Eigen::Matrix3d &R, const Eigen::Vector3d &center) override
Apply rotation to the geometry coordinates and normals. Given a rotation matrix , and center ,...
bool reserve(unsigned numberOfPoints) override
Reserves memory for all the active features.
virtual ccPointCloud & Translate(const Eigen::Vector3d &translation, bool relative=true) override
Apply translation to the geometry coordinates.
static ccPointCloud * From(const cloudViewer::GenericIndexedCloud *cloud, const ccGenericPointCloud *sourceCloud=nullptr)
Creates a new point cloud object from a GenericIndexedCloud.
virtual ccPointCloud & Scale(const double s, const Eigen::Vector3d &center) override
Apply scaling to the geometry coordinates. Given a scaling factor , and center , a given point is tr...
void shrinkToFit()
Removes unused capacity.
bool setRGBColor(ColorCompType r, ColorCompType g, ColorCompType b)
Set a unique color for the whole cloud (shortcut)
virtual ccPointCloud & Transform(const Eigen::Matrix4d &trans) override
Apply transformation (4x4 matrix) to the geometry coordinates.
Colored polyline.
Definition: ecvPolyline.h:24
static ccPolyline * Circle(const CCVector3 &center, PointCoordinateType radius, unsigned resolution=48)
Creates a circle as a polyline.
ccPolyline operator+(const ccPolyline &polyline) const
void setTransformFlag(bool state)
Defines if the polyline is considered as processed polyline.
Definition: ecvPolyline.h:68
PointCoordinateType computeLength() const
Computes the polyline length.
short minimumFileVersion_MeOnly() const override
virtual ccPolyline & Translate(const Eigen::Vector3d &translation, bool relative=true) override
Apply translation to the geometry coordinates.
void setForeground(bool state)
Defines if the polyline is drawn in background or foreground.
static bool IsCloudVerticesOfPolyline(ccGenericPointCloud *cloud, ccPolyline **polyline=nullptr)
Helper to determine if the input cloud acts as vertices of a polyline.
bool toFile_MeOnly(QFile &out, short dataVersion) const override
Save own object data.
bool fromFile_MeOnly(QFile &in, short dataVersion, int flags, LoadedIDMap &oldToNewIDMap) override
Loads own object data.
bool verticesShown() const
Whether the polyline vertices should be displayed or not.
Definition: ecvPolyline.h:131
unsigned m_arrowIndex
Arrow index.
Definition: ecvPolyline.h:279
bool createNewPolylinesFromSelection(std::vector< ccPolyline * > &output)
Creates a polyline mesh with the selected vertices only.
void set2DMode(bool state)
Defines if the polyline is considered as 2D or 3D.
virtual void drawMeOnly(CC_DRAW_CONTEXT &context) override
Draws the entity only (not its children)
virtual void setGlobalScale(double scale) override
virtual ccPolyline & Transform(const Eigen::Matrix4d &transformation) override
Apply transformation (4x4 matrix) to the geometry coordinates.
virtual ccPolyline & Rotate(const Eigen::Matrix3d &R, const Eigen::Vector3d &center) override
Apply rotation to the geometry coordinates and normals. Given a rotation matrix , and center ,...
virtual ccBBox GetAxisAlignedBoundingBox() const override
Returns an axis-aligned bounding box of the geometry.
virtual bool hasColors() const override
Returns whether colors are enabled or not.
PointCoordinateType m_width
Width of the line.
Definition: ecvPolyline.h:256
ccPointCloud * samplePoints(bool densityBased, double samplingParameter, bool withRGB)
Samples points on the polyline.
bool is2DMode() const
Returns whether the polyline is considered as 2D or 3D.
Definition: ecvPolyline.h:63
bool m_showArrow
Whether to show an arrow or not.
Definition: ecvPolyline.h:275
ecvColor::Rgb m_rgbColor
Unique RGB color.
Definition: ecvPolyline.h:253
virtual void setGlobalShift(const CCVector3d &shift) override
Sets shift applied to original coordinates (information storage only)
void showArrow(bool state, unsigned vertIndex, PointCoordinateType length)
Shows an arrow in place of a given vertex.
ccPolyline & operator+=(const ccPolyline &polyline)
virtual ccPolyline & Scale(const double s, const Eigen::Vector3d &center) override
Apply scaling to the geometry coordinates. Given a scaling factor , and center , a given point is tr...
virtual ecvOrientedBBox GetOrientedBoundingBox() const override
ccPolyline(GenericIndexedCloudPersist *associatedCloud)
Default constructor.
Definition: ecvPolyline.cpp:15
bool m_foreground
Definition: ecvPolyline.h:266
void setVertexMarkerWidth(int width)
Sets the width of vertex markers.
Definition: ecvPolyline.h:137
void importParametersFrom(const ccPolyline &poly)
Copy the parameters from another polyline.
ccPolyline & operator=(const ccPolyline &polyline)
virtual Eigen::Vector3d GetMaxBound() const override
Returns max bounds for geometry coordinates.
virtual void applyGLTransformation(const ccGLMatrix &trans) override
Applies a GL transformation to the entity.
void showVertices(bool state)
Sets whether to display or hide the polyline vertices.
Definition: ecvPolyline.h:129
virtual ccBBox getOwnBB(bool withGLFeatures=false) override
Returns the entity's own bounding-box.
bool add(const ccPointCloud &cloud)
Add another reference cloud.
unsigned segmentCount() const
Returns the number of segments.
virtual bool IsEmpty() const override
Definition: ecvPolyline.h:188
PointCoordinateType m_arrowLength
Arrow length.
Definition: ecvPolyline.h:277
virtual unsigned getUniqueIDForDisplay() const override
Returns object unqiue ID used for display.
int m_vertMarkWidth
Vertex marker width.
Definition: ecvPolyline.h:272
bool m_showVertices
Whether vertices should be displayed or not.
Definition: ecvPolyline.h:269
bool initWith(ccPointCloud *vertices, const ccPolyline &poly)
Definition: ecvPolyline.cpp:81
virtual Eigen::Vector3d GetMinBound() const override
Returns min bounds for geometry coordinates.
int getVertexMarkerWidth() const
Returns the width of vertex markers.
Definition: ecvPolyline.h:139
virtual Eigen::Vector3d GetCenter() const override
Returns the center of the geometry coordinates.
bool m_mode2D
Whether polyline should be considered as 2D (true) or 3D (false)
Definition: ecvPolyline.h:259
bool split(PointCoordinateType maxEdgeLength, std::vector< ccPolyline * > &parts)
Splits the polyline into several parts based on a maximum edge length.
void setColor(const ecvColor::Rgb &col)
Sets the polyline color.
Definition: ecvPolyline.h:81
ccPolyline * smoothChaikin(PointCoordinateType ratio, unsigned iterationCount) const
Smoothes the polyline (Chaikin algorithm)
void setWidth(PointCoordinateType width)
Sets the width of the line.
QMultiMap< unsigned, unsigned > LoadedIDMap
Map of loaded unique IDs (old ID --> new ID)
static bool ReadError()
Sends a custom error message (read error) and returns 'false'.
static bool WriteError()
Sends a custom error message (write error) and returns 'false'.
static void CoordsFromDataStream(QDataStream &stream, int flags, PointCoordinateType *out, unsigned count=1)
Shifted entity interface.
double m_globalScale
Global scale (typically applied at loading time)
CCVector3d m_globalShift
Global shift (typically applied at loading time)
bool loadShiftInfoFromFile(QFile &in)
Serialization helper (input)
bool isShifted() const
Returns whether the cloud is shifted or not.
virtual void setGlobalShift(double x, double y, double z)
Sets shift applied to original coordinates (information storage only)
virtual const CCVector3d & getGlobalShift() const
Returns the shift applied to original coordinates.
virtual void setGlobalScale(double scale)
virtual double getGlobalScale() const
Returns the scale applied to original coordinates.
bool saveShiftInfoToFile(QFile &out) const
Serialization helper (output)
Vector3Tpl< T > getCenter() const
Returns center.
Definition: BoundingBox.h:164
const Vector3Tpl< T > & maxCorner() const
Returns max corner (const)
Definition: BoundingBox.h:156
void setValidity(bool state)
Sets bonding box validity.
Definition: BoundingBox.h:200
const Vector3Tpl< T > & minCorner() const
Returns min corner (const)
Definition: BoundingBox.h:154
virtual unsigned size() const =0
Returns the number of points.
A generic 3D point cloud with index-based and presistent access to points.
virtual const CCVector3 * getPoint(unsigned index) const =0
Returns the ith point.
void addPoint(const CCVector3 &P)
Adds a 3D point to the database.
unsigned size() const override
Definition: PointCloudTpl.h:38
const CCVector3 * getPoint(unsigned index) const override
void setClosed(bool state)
Sets whether the polyline is closed or not.
Definition: Polyline.h:29
void clear(bool unusedParam=true) override
Clears the cloud.
Definition: Polyline.cpp:15
bool isClosed() const
Returns whether the polyline is closed or not.
Definition: Polyline.h:26
bool m_isClosed
Closing state.
Definition: Polyline.h:36
A very simple point cloud (no point duplication)
BoundingBox m_bbox
Bounding-box.
virtual bool addPointIndex(unsigned globalIndex)
Point global index insertion mechanism.
void getBoundingBox(CCVector3 &bbMin, CCVector3 &bbMax) override
Returns the cloud bounding box.
virtual GenericIndexedCloudPersist * getAssociatedCloud()
Returns the associated (source) cloud.
unsigned size() const override
Returns the number of points.
void invalidateBoundingBox()
Invalidates the bounding-box.
ReferencesContainer m_theIndexes
Indexes of (some of) the associated cloud points.
virtual unsigned getPointGlobalIndex(unsigned localIndex) const
GenericIndexedCloudPersist * m_theAssociatedCloud
Associated cloud.
virtual bool resize(unsigned n)
Presets the size of the vector used to store point references.
virtual unsigned capacity() const
Returns max capacity.
bool add(const ReferenceCloud &cloud)
Add another reference cloud.
virtual void setAssociatedCloud(GenericIndexedCloudPersist *cloud)
Sets the associated (source) cloud.
virtual bool reserve(unsigned n)
Reserves some memory for hosting the point references.
const CCVector3 * getPoint(unsigned index) const override
Returns the ith point.
static void Draw(const CC_DRAW_CONTEXT &context, const ccHObject *obj)
static QMainWindow * GetMainWindow()
static ecvOrientedBBox CreateFromPoints(const std::vector< Eigen::Vector3d > &points)
#define LogWarning(...)
Definition: Logging.h:72
#define LogError(...)
Definition: Logging.h:60
#define MACRO_Draw3D(context)
#define MACRO_Foreground(context)
@ CC_ENTITY_PICKING
static QSharedPointer< ccCone > c_unitArrow(0)
ImGuiContext * context
Definition: Window.cpp:76
@ POLY_LINE
Definition: CVTypes.h:112
@ FACET
Definition: CVTypes.h:109
MiniVec< float, N > ceil(const MiniVec< float, N > &a)
Definition: MiniVec.h:89
float DegreesToRadians(int degrees)
Convert degrees to radians.
Definition: CVMath.h:98
bool LessThanEpsilon(float x)
Test a floating point number against our epsilon (a very small number).
Definition: CVMath.h:23
constexpr Rgb white(MAX, MAX, MAX)
void setScale(const CCVector3 &scale)
void setTranslationEnd(const CCVector3 &trans)
void setTranslationStart(const CCVector3 &trans)
void setTransformation(const ccGLMatrixd &transform, bool updateTranslation=true, bool useEuler=false)
Display context.
int drawingFlags
Drawing options (see below)
TransformInfo transformInfo