23 #include <tbb/parallel_for.h>
48 unsigned _nearestPointIndex,
49 float _nearestPointSquareDist)
71 const std::vector<Vertex2D>&
points,
72 const std::vector<HullPointFlags>& pointFlags,
74 bool allowLongerChunks =
false,
75 double minCosAngle = -1.0) {
80 const unsigned pointCount =
static_cast<unsigned>(
points.size());
84 static_cast<unsigned int>(0), pointCount, [&](
unsigned int i) {
89 if (P.
index == (*itA)->index || P.
index == (*itB)->index) {
95 if (AB.
x * AP.y - AB.
y * AP.x < 0) {
100 if (minCosAngle > -1.0) {
103 AP.
x * PB.
x + AP.y * PB.
y;
107 std::sqrt(AP.norm2() * PB.
norm2()));
108 if (dotProd < minDotProd) {
115 if (
dot >= 0 &&
dot <= squareLengthAB) {
118 if (minDist2 < 0 || dist2 < minDist2) {
126 if (squareLengthAP >= minSquareEdgeLength &&
127 squareLengthBP >= minSquareEdgeLength &&
128 (allowLongerChunks ||
129 (squareLengthAP < squareLengthAB ||
130 squareLengthBP < squareLengthAB))) {
138 for (
unsigned i = 0; i < pointCount; ++i) {
143 if (P.
index == (*itA)->index || P.
index == (*itB)->index) {
149 if (AB.
x * AP.
y - AB.
y * AP.
x < 0) {
154 if (minCosAngle > -1.0) {
158 minCosAngle * std::sqrt(AP.
norm2() * PB.
norm2()));
159 if (dotProd < minDotProd) {
165 if (
dot >= 0 &&
dot <= squareLengthAB) {
168 if (minDist2 < 0 || dist2 < minDist2) {
174 if (squareLengthAP >= minSquareEdgeLength &&
175 squareLengthBP >= minSquareEdgeLength &&
176 (allowLongerChunks || (squareLengthAP < squareLengthAB ||
177 squareLengthBP < squareLengthAB))) {
186 return (minDist2 < 0 ? minDist2 : minDist2 / squareLengthAB);
190 std::vector<Vertex2D>&
points,
191 std::list<Vertex2D*>& hullPoints,
195 bool enableVisualDebugMode ,
196 double maxAngleDeg ) {
203 if (hullPoints.size() < 2 || maxSquareEdgeLength < 0)
return true;
205 unsigned pointCount =
static_cast<unsigned>(
points.size());
207 std::vector<HullPointFlags> pointFlags;
216 maxAngleDeg <= 0 ? -1.0 : std::cos(maxAngleDeg *
M_PI / 180.0);
222 for (
size_t i = 0; i < pointCount; ++i) {
233 minSquareEdgeLength =
234 (maxP - minP).norm2() /
237 minSquareEdgeLength =
238 std::min(minSquareEdgeLength, maxSquareEdgeLength / 10);
241 for (
VertexIterator itA = hullPoints.begin(); itA != hullPoints.end();
245 if (itB == hullPoints.end()) itB = hullPoints.begin();
246 if ((**itB - **itA).norm2() < minSquareEdgeLength) {
248 hullPoints.erase(itB);
252 if (contourType !=
FULL) {
261 it != hullPoints.end(); ++it) {
262 if ((*it)->x < (*itLeft)->x ||
263 ((*it)->x == (*itLeft)->x && (*it)->y < (*itLeft)->y)) {
266 if ((*it)->x > (*itRight)->x ||
267 ((*it)->x == (*itRight)->x &&
268 (*it)->y < (*itRight)->y)) {
273 assert(itLeft != itRight);
277 if (itBefore == hullPoints.begin()) itBefore = hullPoints.end();
281 if (itAfter == hullPoints.end()) itAfter = hullPoints.begin();
284 ((**itBefore - **itLeft).
cross(**itAfter - **itLeft) <
286 contourType ==
LOWER);
287 if (!forward)
std::swap(itLeft, itRight);
291 std::list<Vertex2D*> halfHullPoints;
294 if (it == hullPoints.end()) it = hullPoints.begin();
295 halfHullPoints.push_back(*it);
296 if (it == itRight)
break;
298 }
catch (
const std::bad_alloc&) {
303 hullPoints = halfHullPoints;
306 if (hullPoints.size() < 2) {
317 if (enableVisualDebugMode) {
319 debugDialog.setGeometry(50, 50, 800, 600);
325 debugCloud->
reserve(pointCount);
326 for (
size_t i = 0; i < pointCount; ++i) {
339 debugContour =
new ccPolyline(debugContourVertices);
340 debugContour->
addChild(debugContourVertices);
341 unsigned hullSize =
static_cast<unsigned>(hullPoints.size());
342 debugContour->
reserve(hullSize);
343 debugContourVertices->
reserve(hullSize);
346 itA != hullPoints.end(); ++itA, ++index) {
369 bool somethingHasChanged =
true;
370 while (somethingHasChanged) {
372 somethingHasChanged =
false;
383 std::multiset<Edge> edges;
385 assert(hullPoints.size() >= 2);
386 size_t initEdgeCount = hullPoints.size();
387 if (contourType !=
FULL) --initEdgeCount;
390 for (
size_t i = 0; i < initEdgeCount; ++i) {
393 if (itB == hullPoints.end()) itB = hullPoints.begin();
397 if ((**itB - **itA).norm2() > maxSquareEdgeLength) {
398 unsigned nearestPointIndex = 0;
400 nearestPointIndex, itA, itB,
points, pointFlags,
401 minSquareEdgeLength, step > 1, minCosAngle);
403 if (minSquareDist >= 0) {
404 Edge e(itA, nearestPointIndex, minSquareDist);
413 if (contourType !=
FULL)
414 pointFlags[(*hullPoints.rbegin())->index] =
POINT_USED;
416 while (!edges.empty()) {
419 Edge e = *edges.begin();
420 edges.erase(edges.begin());
425 if (itB == hullPoints.end()) {
426 assert(contourType ==
FULL);
427 itB = hullPoints.begin();
432 assert(pointFlags[P.
index] ==
439 if (enableVisualDebugMode && !debugDialog.
isSkipped()) {
443 for (
size_t i = 0; i < pointCount; ++i) {
445 if (&P == *itA) indexA =
static_cast<unsigned>(i);
446 if (&P == *itB) indexB =
static_cast<unsigned>(i);
461 QString(
"nearest point found index #%1 (dist = %2)")
487 bool intersect =
false;
491 itI != hullPoints.end(); ++itI, ++itJ) {
492 if (itJ == hullPoints.end()) {
493 if (contourType ==
FULL)
494 itJ = hullPoints.begin();
499 if (((*itI)->index != (*itA)->index &&
500 (*itJ)->index != (*itA)->index &&
502 segmentIntersect(**itI, **itJ, **itA,
504 ((*itI)->index != (*itB)->index &&
505 (*itJ)->index != (*itB)->index &&
507 segmentIntersect(**itI, **itJ, P,
517 itB == hullPoints.begin() ? hullPoints.end() : itB,
523 somethingHasChanged =
true;
525 if (enableVisualDebugMode && !debugDialog.
isSkipped()) {
527 debugContourVertices->
clear();
529 static_cast<unsigned>(hullPoints.size());
530 debugContourVertices->
reserve(hullSize);
533 it != hullPoints.end(); ++it, ++index) {
538 debugContour->
reserve(hullSize);
543 "point has been added to contour",
true);
548 if (!edges.empty()) {
549 std::vector<VertexIterator> removed;
550 std::multiset<Edge>::const_iterator lastValidIt =
552 for (std::multiset<Edge>::const_iterator it =
554 it != edges.end(); ++it) {
555 if ((*it).nearestPointIndex ==
558 removed.push_back((*it).itA);
561 if (edges.empty())
break;
562 if (lastValidIt != edges.end())
573 for (
size_t i = 0; i < removed.size(); ++i) {
577 if (itD == hullPoints.end())
578 itD = hullPoints.begin();
580 unsigned nearestPointIndex = 0;
583 nearestPointIndex, itC, itD,
points,
584 pointFlags, minSquareEdgeLength,
587 if (minSquareDist >= 0) {
588 Edge e(itC, nearestPointIndex, minSquareDist);
595 if ((P - **itA).norm2() > maxSquareEdgeLength) {
596 unsigned nearestPointIndex = 0;
600 minSquareEdgeLength,
false,
603 if (minSquareDist >= 0) {
604 Edge e(itA, nearestPointIndex, minSquareDist);
608 if ((**itB - P).norm2() > maxSquareEdgeLength) {
609 unsigned nearestPointIndex = 0;
613 minSquareEdgeLength,
false,
616 if (minSquareDist >= 0) {
617 Edge e(itP, nearestPointIndex, minSquareDist);
622 if (enableVisualDebugMode)
624 "[rejected] new edge would intersect the "
631 assert(enableVisualDebugMode);
639 assert(enableVisualDebugMode);
651 if (!allowMultiPass)
break;
666 std::vector<unsigned>* originalPointIndexes ,
667 bool enableVisualDebugMode ,
668 double maxAngleDeg ) {
671 if (!
points)
return nullptr;
673 unsigned ptsCount =
points->size();
674 if (ptsCount < 3)
return nullptr;
686 std::vector<Vertex2D> points2D;
689 if (preferredUpDir !=
nullptr) {
698 if (preferredNormDim !=
nullptr) {
701 preferredPlaneEq[0] = preferredNormDim[0];
702 preferredPlaneEq[1] = preferredNormDim[1];
703 preferredPlaneEq[2] = preferredNormDim[2];
706 planeEq = preferredPlaneEq;
708 if (preferredUpDir !=
nullptr) {
719 "[ExtractFlatContour] Failed to project the points on the LS "
720 "plane (not enough memory?)!");
727 for (
unsigned i = 0; i < ptsCount; ++i) points2D[i].index = i;
734 maxEdgeLength * maxEdgeLength,
735 enableVisualDebugMode, maxAngleDeg)) {
737 "[ExtractFlatContour] Failed to compute the convex hull of the "
742 if (originalPointIndexes) {
744 originalPointIndexes->resize(hullPoints.size(), 0);
745 }
catch (
const std::bad_alloc&) {
747 CVLog::Error(
"[ExtractFlatContour] Not enough memory!");
752 for (Hull2D::const_iterator it = hullPoints.begin();
753 it != hullPoints.end(); ++it, ++i) {
754 (*originalPointIndexes)[i] = (*it)->index;
758 unsigned hullPtsCount =
static_cast<unsigned>(hullPoints.size());
763 if (!contourVertices->
reserve(hullPtsCount)) {
764 delete contourVertices;
765 contourVertices =
nullptr;
766 CVLog::Error(
"[ExtractFlatContour] Not enough memory!");
771 for (Hull2D::const_iterator it = hullPoints.begin();
772 it != hullPoints.end(); ++it) {
773 contourVertices->
addPoint(O +
X * (*it)->x + Y * (*it)->
y);
775 contourVertices->
setName(
"vertices");
781 if (contourPolyline->
reserve(hullPtsCount)) {
785 contourPolyline->
setName(
"contour");
786 contourPolyline->
addChild(contourVertices);
788 delete contourPolyline;
789 contourPolyline =
nullptr;
791 "[ExtractFlatContour] Not enough memory to create the contour "
795 return contourPolyline;
802 std::vector<ccPolyline*>& parts,
803 bool allowSplitting ,
805 bool enableVisualDebugMode ) {
811 preferredDim, 0,
FULL, 0, enableVisualDebugMode);
814 }
else if (!allowSplitting) {
815 parts.push_back(basePoly);
820 bool success = basePoly->
split(maxEdgeLength, parts);
Vector3Tpl< PointCoordinateType > CCVector3
Default 3D Vector.
float PointCoordinateType
Type of the coordinates of a (N-D) point.
static bool Warning(const char *format,...)
Prints out a formatted warning message in console.
static bool Error(const char *format,...)
Display an error dialog with formatted message.
Type dot(const Vector2Tpl &v) const
Dot product.
Type norm2() const
Returns vector square norm.
Vector3Tpl cross(const Vector3Tpl &v) const
Cross product.
static void vnormalize(PointCoordinateType p[])
static PointCoordinateType vdot(const PointCoordinateType p[], const PointCoordinateType q[])
2D label (typically attached to points)
bool addPickedPoint(ccGenericPointCloud *cloud, unsigned pointIndex, bool entityCenter=false)
Adds a point to this label.
void setDisplayedIn2D(bool state)
Whether to display the label in 2D.
virtual void setVisible(bool state)
Sets entity visibility.
virtual void setSelected(bool state)
Selects/Unselects entity.
void setPointSize(unsigned size=0)
Sets point size.
ccBBox getOwnBB(bool withGLFeatures=false) override
Returns the entity's own bounding-box.
virtual bool addChild(ccHObject *child, int dependencyFlags=DP_PARENT_OF_OTHER, int insertIndex=-1)
Adds a child.
virtual void setName(const QString &name)
Sets object name.
virtual void setEnabled(bool state)
Sets the "enabled" property.
A 3D cloud and its associated features (color, normals, scalar fields, etc.)
bool reserve(unsigned numberOfPoints) override
Reserves memory for all the active features.
void clear() override
Clears the entity from all its points and features.
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.
A generic 3D point cloud with index-based and presistent access to points.
bool projectPointsOn2DPlane(std::vector< Vec2D > &points2D, const PointCoordinateType *planeEquation=nullptr, CCVector3 *O=nullptr, CCVector3 *X=nullptr, CCVector3 *Y=nullptr, InputVectorsUsage vectorsUsage=None)
Projects points on the best fitting LS plane.
void addPoint(const CCVector3 &P)
Adds a 3D point to the database.
void setClosed(bool state)
Sets whether the polyline is closed or not.
void clear(bool unusedParam=true) override
Clears the cloud.
virtual bool addPointIndex(unsigned globalIndex)
Point global index insertion mechanism.
virtual bool reserve(unsigned n)
Reserves some memory for hosting the point references.
__host__ __device__ float3 cross(float3 a, float3 b)
__host__ __device__ float dot(float2 a, float2 b)
constexpr Rgb red(MAX, 0, 0)
void swap(cloudViewer::core::SmallVectorImpl< T > &LHS, cloudViewer::core::SmallVectorImpl< T > &RHS)
Implement std::swap in terms of SmallVector swap.
unsigned nearestPointIndex
float nearestPointSquareDist
bool operator<(const Edge &e) const
Edge(const VertexIterator &A, unsigned _nearestPointIndex, float _nearestPointSquareDist)