From fd1d3a85af719ad8632838f324f436dfc06208fd Mon Sep 17 00:00:00 2001 From: nirvn Date: Sat, 13 Nov 2021 11:19:43 +0700 Subject: [PATCH 1/3] Update poly2tri library to latest master revision, fixing self-intersection crash --- external/poly2tri/common/shapes.cc | 48 +++++----- external/poly2tri/common/shapes.h | 7 +- external/poly2tri/common/utils.h | 2 - external/poly2tri/sweep/advancing_front.cc | 10 +- external/poly2tri/sweep/cdt.cc | 4 +- external/poly2tri/sweep/sweep.cc | 106 +++++++++++++-------- external/poly2tri/sweep/sweep.h | 2 +- external/poly2tri/sweep/sweep_context.cc | 26 ++--- external/poly2tri/sweep/sweep_context.h | 2 +- 9 files changed, 118 insertions(+), 89 deletions(-) diff --git a/external/poly2tri/common/shapes.cc b/external/poly2tri/common/shapes.cc index e3a7a05f84a8..ed821752aab6 100644 --- a/external/poly2tri/common/shapes.cc +++ b/external/poly2tri/common/shapes.cc @@ -35,6 +35,10 @@ namespace p2t { +Point::Point(double x, double y) : x(x), y(y) +{ +} + std::ostream& operator<<(std::ostream& out, const Point& point) { return out << point.x << "," << point.y; } @@ -42,7 +46,7 @@ std::ostream& operator<<(std::ostream& out, const Point& point) { Triangle::Triangle(Point& a, Point& b, Point& c) { points_[0] = &a; points_[1] = &b; points_[2] = &c; - neighbors_[0] = NULL; neighbors_[1] = NULL; neighbors_[2] = NULL; + neighbors_[0] = nullptr; neighbors_[1] = nullptr; neighbors_[2] = nullptr; constrained_edge[0] = constrained_edge[1] = constrained_edge[2] = false; delaunay_edge[0] = delaunay_edge[1] = delaunay_edge[2] = false; interior_ = false; @@ -85,36 +89,36 @@ void Triangle::Clear() for( int i=0; i<3; i++ ) { t = neighbors_[i]; - if( t != NULL ) + if( t != nullptr ) { t->ClearNeighbor( this ); } } ClearNeighbors(); - points_[0]=points_[1]=points_[2] = NULL; + points_[0]=points_[1]=points_[2] = nullptr; } void Triangle::ClearNeighbor(const Triangle *triangle ) { if( neighbors_[0] == triangle ) { - neighbors_[0] = NULL; + neighbors_[0] = nullptr; } else if( neighbors_[1] == triangle ) { - neighbors_[1] = NULL; + neighbors_[1] = nullptr; } else { - neighbors_[2] = NULL; + neighbors_[2] = nullptr; } } void Triangle::ClearNeighbors() { - neighbors_[0] = NULL; - neighbors_[1] = NULL; - neighbors_[2] = NULL; + neighbors_[0] = nullptr; + neighbors_[1] = nullptr; + neighbors_[2] = nullptr; } void Triangle::ClearDelunayEdges() @@ -226,7 +230,7 @@ Point* Triangle::PointCW(const Point& point) return points_[1]; } assert(0); - return NULL; + return nullptr; } // The point counter-clockwise to given point @@ -240,7 +244,18 @@ Point* Triangle::PointCCW(const Point& point) return points_[0]; } assert(0); - return NULL; + return nullptr; +} + +// The neighbor across to given point +Triangle* Triangle::NeighborAcross(const Point& point) +{ + if (&point == points_[0]) { + return neighbors_[0]; + } else if (&point == points_[1]) { + return neighbors_[1]; + } + return neighbors_[2]; } // The neighbor clockwise to given point @@ -349,17 +364,6 @@ void Triangle::SetDelunayEdgeCW(const Point& p, bool e) } } -// The neighbor across to given point -Triangle& Triangle::NeighborAcross(const Point& opoint) -{ - if (&opoint == points_[0]) { - return *neighbors_[0]; - } else if (&opoint == points_[1]) { - return *neighbors_[1]; - } - return *neighbors_[2]; -} - void Triangle::DebugPrint() { std::cout << *points_[0] << " " << *points_[1] << " " << *points_[2] << std::endl; diff --git a/external/poly2tri/common/shapes.h b/external/poly2tri/common/shapes.h index 43bb40a3f385..5bf8c8fb4839 100644 --- a/external/poly2tri/common/shapes.h +++ b/external/poly2tri/common/shapes.h @@ -57,7 +57,7 @@ struct Point { std::vector edge_list; /// Construct using coordinates. - Point(double x, double y) : x(x), y(y) {} + Point(double x, double y); /// Set this point to all zeros. void set_zero() @@ -176,6 +176,7 @@ void MarkConstrainedEdge(Point* p, Point* q); int Index(const Point* p); int EdgeIndex(const Point* p1, const Point* p2); +Triangle* NeighborAcross(const Point& point); Triangle* NeighborCW(const Point& point); Triangle* NeighborCCW(const Point& point); bool GetConstrainedEdgeCCW(const Point& p); @@ -203,8 +204,6 @@ void ClearDelunayEdges(); inline bool IsInterior(); inline void IsInterior(bool b); -Triangle& NeighborAcross(const Point& opoint); - void DebugPrint(); bool CircumcicleContains(const Point&) const; @@ -260,7 +259,7 @@ inline bool operator ==(const Point& a, const Point& b) inline bool operator !=(const Point& a, const Point& b) { - return !(a.x == b.x) && !(a.y == b.y); + return !(a.x == b.x) || !(a.y == b.y); } /// Peform the dot product on two vectors. diff --git a/external/poly2tri/common/utils.h b/external/poly2tri/common/utils.h index b4b78bf0be03..f71334c5d380 100644 --- a/external/poly2tri/common/utils.h +++ b/external/poly2tri/common/utils.h @@ -33,9 +33,7 @@ #define UTILS_H // Otherwise #defines like M_PI are undeclared under Visual Studio -#ifndef _USE_MATH_DEFINES #define _USE_MATH_DEFINES -#endif #include "shapes.h" diff --git a/external/poly2tri/sweep/advancing_front.cc b/external/poly2tri/sweep/advancing_front.cc index 66e2a5d0d393..b8e9609efcd1 100644 --- a/external/poly2tri/sweep/advancing_front.cc +++ b/external/poly2tri/sweep/advancing_front.cc @@ -46,21 +46,21 @@ Node* AdvancingFront::LocateNode(double x) Node* node = search_node_; if (x < node->value) { - while ((node = node->prev) != NULL) { + while ((node = node->prev) != nullptr) { if (x >= node->value) { search_node_ = node; return node; } } } else { - while ((node = node->next) != NULL) { + while ((node = node->next) != nullptr) { if (x < node->value) { search_node_ = node->prev; return node->prev; } } } - return NULL; + return nullptr; } Node* AdvancingFront::FindSearchNode(double x) @@ -88,13 +88,13 @@ Node* AdvancingFront::LocatePoint(const Point* point) } } } else if (px < nx) { - while ((node = node->prev) != NULL) { + while ((node = node->prev) != nullptr) { if (point == node->point) { break; } } } else { - while ((node = node->next) != NULL) { + while ((node = node->next) != nullptr) { if (point == node->point) break; } diff --git a/external/poly2tri/sweep/cdt.cc b/external/poly2tri/sweep/cdt.cc index 8496aa1da411..4dfe6a6419ed 100644 --- a/external/poly2tri/sweep/cdt.cc +++ b/external/poly2tri/sweep/cdt.cc @@ -1,5 +1,5 @@ /* - * Poly2Tri Copyright (c) 2009-2018, Poly2Tri Contributors + * Poly2Tri Copyright (c) 2009-2021, Poly2Tri Contributors * https://github.com/jhasse/poly2tri * * All rights reserved. @@ -68,4 +68,4 @@ CDT::~CDT() delete sweep_; } -} +} // namespace p2t diff --git a/external/poly2tri/sweep/sweep.cc b/external/poly2tri/sweep/sweep.cc index 45aa1db3b65a..3267a41774f1 100644 --- a/external/poly2tri/sweep/sweep.cc +++ b/external/poly2tri/sweep/sweep.cc @@ -54,8 +54,8 @@ void Sweep::SweepPoints(SweepContext& tcx) for (size_t i = 1; i < tcx.point_count(); i++) { Point& point = *tcx.GetPoint(i); Node* node = &PointEvent(tcx, point); - for (unsigned int i = 0; i < point.edge_list.size(); i++) { - EdgeEvent(tcx, point.edge_list[i], node); + for (unsigned int j = 0; j < point.edge_list.size(); j++) { + EdgeEvent(tcx, point.edge_list[j], node); } } } @@ -65,17 +65,25 @@ void Sweep::FinalizationPolygon(SweepContext& tcx) // Get an Internal triangle to start with Triangle* t = tcx.front()->head()->next->triangle; Point* p = tcx.front()->head()->next->point; - while (!t->GetConstrainedEdgeCW(*p)) { + while (t && !t->GetConstrainedEdgeCW(*p)) { t = t->NeighborCCW(*p); } // Collect interior triangles constrained by edges - tcx.MeshClean(*t); + if (t) { + tcx.MeshClean(*t); + } } Node& Sweep::PointEvent(SweepContext& tcx, Point& point) { - Node& node = tcx.LocateNode(point); + Node* node_ptr = tcx.LocateNode(point); + if (!node_ptr || !node_ptr->point || !node_ptr->next || !node_ptr->next->point) + { + throw std::runtime_error("PointEvent - null node"); + } + + Node& node = *node_ptr; Node& new_node = NewFrontTriangle(tcx, point, node); // Only need to check +epsilon since point never have smaller @@ -108,6 +116,9 @@ void Sweep::EdgeEvent(SweepContext& tcx, Edge* edge, Node* node) void Sweep::EdgeEvent(SweepContext& tcx, Point& ep, Point& eq, Triangle* triangle, Point& point) { + if (triangle == nullptr) { + throw std::runtime_error("EdgeEvent - null triangle"); + } if (IsEdgeSideOfTriangle(*triangle, ep, eq)) { return; } @@ -115,16 +126,15 @@ void Sweep::EdgeEvent(SweepContext& tcx, Point& ep, Point& eq, Triangle* triangl Point* p1 = triangle->PointCCW(point); Orientation o1 = Orient2d(eq, *p1, ep); if (o1 == COLLINEAR) { - if( triangle->Contains(&eq, p1)) { - triangle->MarkConstrainedEdge(&eq, p1 ); + if (triangle->Contains(&eq, p1)) { + triangle->MarkConstrainedEdge(&eq, p1); // We are modifying the constraint maybe it would be better to // not change the given constraint and just keep a variable for the new constraint tcx.edge_event.constrained_edge->q = p1; - triangle = &triangle->NeighborAcross(point); - EdgeEvent( tcx, ep, *p1, triangle, *p1 ); + triangle = triangle->NeighborAcross(point); + EdgeEvent(tcx, ep, *p1, triangle, *p1); } else { - std::runtime_error("EdgeEvent - collinear points not supported"); - assert(0); + throw std::runtime_error("EdgeEvent - collinear points not supported"); } return; } @@ -132,16 +142,15 @@ void Sweep::EdgeEvent(SweepContext& tcx, Point& ep, Point& eq, Triangle* triangl Point* p2 = triangle->PointCW(point); Orientation o2 = Orient2d(eq, *p2, ep); if (o2 == COLLINEAR) { - if( triangle->Contains(&eq, p2)) { - triangle->MarkConstrainedEdge(&eq, p2 ); + if (triangle->Contains(&eq, p2)) { + triangle->MarkConstrainedEdge(&eq, p2); // We are modifying the constraint maybe it would be better to // not change the given constraint and just keep a variable for the new constraint tcx.edge_event.constrained_edge->q = p2; - triangle = &triangle->NeighborAcross(point); - EdgeEvent( tcx, ep, *p2, triangle, *p2 ); + triangle = triangle->NeighborAcross(point); + EdgeEvent(tcx, ep, *p2, triangle, *p2); } else { - std::runtime_error("EdgeEvent - collinear points not supported"); - assert(0); + throw std::runtime_error("EdgeEvent - collinear points not supported"); } return; } @@ -151,12 +160,13 @@ void Sweep::EdgeEvent(SweepContext& tcx, Point& ep, Point& eq, Triangle* triangl // that will cross edge if (o1 == CW) { triangle = triangle->NeighborCCW(point); - } else{ + } else { triangle = triangle->NeighborCW(point); } EdgeEvent(tcx, ep, eq, triangle, point); } else { // This triangle crosses constraint so lets flippin start! + assert(triangle); FlipEdgeEvent(tcx, ep, eq, triangle, point); } } @@ -217,7 +227,6 @@ void Sweep::Fill(SweepContext& tcx, Node& node) if (!Legalize(tcx, *triangle)) { tcx.MapTriangleToNodes(*triangle); } - } void Sweep::FillAdvancingFront(SweepContext& tcx, Node& n) @@ -226,7 +235,7 @@ void Sweep::FillAdvancingFront(SweepContext& tcx, Node& n) // Fill right holes Node* node = n.next; - while (node->next) { + while (node && node->next) { // if HoleAngle exceeds 90 degrees then break. if (LargeHole_DontFill(node)) break; Fill(tcx, *node); @@ -236,7 +245,7 @@ void Sweep::FillAdvancingFront(SweepContext& tcx, Node& n) // Fill left holes node = n.prev; - while (node->prev) { + while (node && node->prev) { // if HoleAngle exceeds 90 degrees then break. if (LargeHole_DontFill(node)) break; Fill(tcx, *node); @@ -263,12 +272,12 @@ bool Sweep::LargeHole_DontFill(const Node* node) const { // Check additional points on front. const Node* next2Node = nextNode->next; // "..Plus.." because only want angles on same side as point being added. - if ((next2Node != NULL) && !AngleExceedsPlus90DegreesOrIsNegative(node->point, next2Node->point, prevNode->point)) + if ((next2Node != nullptr) && !AngleExceedsPlus90DegreesOrIsNegative(node->point, next2Node->point, prevNode->point)) return false; const Node* prev2Node = prevNode->prev; // "..Plus.." because only want angles on same side as point being added. - if ((prev2Node != NULL) && !AngleExceedsPlus90DegreesOrIsNegative(node->point, nextNode->point, prev2Node->point)) + if ((prev2Node != nullptr) && !AngleExceedsPlus90DegreesOrIsNegative(node->point, nextNode->point, prev2Node->point)) return false; return true; @@ -295,7 +304,7 @@ double Sweep::Angle(const Point* origin, const Point* pa, const Point* pb) const */ const double px = origin->x; const double py = origin->y; - const double ax = pa->x- px; + const double ax = pa->x - px; const double ay = pa->y - py; const double bx = pb->x - px; const double by = pb->y - py; @@ -588,7 +597,7 @@ void Sweep::FillRightBelowEdgeEvent(SweepContext& tcx, Edge* edge, Node& node) if (Orient2d(*node.point, *node.next->point, *node.next->next->point) == CCW) { // Concave FillRightConcaveEdgeEvent(tcx, edge, node); - } else{ + } else { // Convex FillRightConvexEdgeEvent(tcx, edge, node); // Retry this one @@ -612,7 +621,6 @@ void Sweep::FillRightConcaveEdgeEvent(SweepContext& tcx, Edge* edge, Node& node) } } } - } void Sweep::FillRightConvexEdgeEvent(SweepContext& tcx, Edge* edge, Node& node) @@ -621,13 +629,13 @@ void Sweep::FillRightConvexEdgeEvent(SweepContext& tcx, Edge* edge, Node& node) if (Orient2d(*node.next->point, *node.next->next->point, *node.next->next->next->point) == CCW) { // Concave FillRightConcaveEdgeEvent(tcx, edge, *node.next); - } else{ + } else { // Convex // Next above or below edge? if (Orient2d(*edge->q, *node.next->next->point, *edge->p) == CCW) { // Below FillRightConvexEdgeEvent(tcx, edge, *node.next); - } else{ + } else { // Above } } @@ -666,13 +674,13 @@ void Sweep::FillLeftConvexEdgeEvent(SweepContext& tcx, Edge* edge, Node& node) if (Orient2d(*node.prev->point, *node.prev->prev->point, *node.prev->prev->prev->point) == CW) { // Concave FillLeftConcaveEdgeEvent(tcx, edge, *node.prev); - } else{ + } else { // Convex // Next above or below edge? if (Orient2d(*edge->q, *node.prev->prev->point, *edge->p) == CW) { // Below FillLeftConvexEdgeEvent(tcx, edge, *node.prev); - } else{ + } else { // Above } } @@ -688,17 +696,22 @@ void Sweep::FillLeftConcaveEdgeEvent(SweepContext& tcx, Edge* edge, Node& node) if (Orient2d(*node.point, *node.prev->point, *node.prev->prev->point) == CW) { // Next is concave FillLeftConcaveEdgeEvent(tcx, edge, node); - } else{ + } else { // Next is convex } } } - } void Sweep::FlipEdgeEvent(SweepContext& tcx, Point& ep, Point& eq, Triangle* t, Point& p) { - Triangle& ot = t->NeighborAcross(p); + assert(t); + Triangle* ot_ptr = t->NeighborAcross(p); + if (ot_ptr == nullptr) + { + throw std::runtime_error("FlipEdgeEvent - null neighbor across"); + } + Triangle& ot = *ot_ptr; Point& op = *ot.OppositePoint(*t, p); if (InScanArea(p, *t->PointCCW(p), *t->PointCW(p), op)) { @@ -764,10 +777,26 @@ Point& Sweep::NextFlipPoint(Point& ep, Point& eq, Triangle& ot, Point& op) void Sweep::FlipScanEdgeEvent(SweepContext& tcx, Point& ep, Point& eq, Triangle& flip_triangle, Triangle& t, Point& p) { - Triangle& ot = t.NeighborAcross(p); - Point& op = *ot.OppositePoint(t, p); + Triangle* ot_ptr = t.NeighborAcross(p); + if (ot_ptr == nullptr) { + throw std::runtime_error("FlipScanEdgeEvent - null neighbor across"); + } + + Point* op_ptr = ot_ptr->OppositePoint(t, p); + if (op_ptr == nullptr) { + throw std::runtime_error("FlipScanEdgeEvent - null opposing point"); + } - if (InScanArea(eq, *flip_triangle.PointCCW(eq), *flip_triangle.PointCW(eq), op)) { + Point* p1 = flip_triangle.PointCCW(eq); + Point* p2 = flip_triangle.PointCW(eq); + if (p1 == nullptr || p2 == nullptr) { + throw std::runtime_error("FlipScanEdgeEvent - null on either of points"); + } + + Triangle& ot = *ot_ptr; + Point& op = *op_ptr; + + if (InScanArea(eq, *p1, *p2, op)) { // flip with new edge op->eq FlipEdgeEvent(tcx, eq, op, &ot, op); // TODO: Actually I just figured out that it should be possible to @@ -777,7 +806,7 @@ void Sweep::FlipScanEdgeEvent(SweepContext& tcx, Point& ep, Point& eq, Triangle& // also need to set a new flip_triangle first // Turns out at first glance that this is somewhat complicated // so it will have to wait. - } else{ + } else { Point& newP = NextFlipPoint(ep, eq, ot, op); FlipScanEdgeEvent(tcx, ep, eq, flip_triangle, ot, newP); } @@ -792,5 +821,4 @@ Sweep::~Sweep() { } -} - +} // namespace p2t diff --git a/external/poly2tri/sweep/sweep.h b/external/poly2tri/sweep/sweep.h index ccf4ef7b0291..895b0e825769 100644 --- a/external/poly2tri/sweep/sweep.h +++ b/external/poly2tri/sweep/sweep.h @@ -33,7 +33,7 @@ * Zalik, B.(2008)'Sweep-line algorithm for constrained Delaunay triangulation', * International Journal of Geographical Information Science * - * "FlipScan" Constrained Edge Algorithm invented by Thomas ?hl?n, thahlen@gmail.com + * "FlipScan" Constrained Edge Algorithm invented by Thomas Åhlén, thahlen@gmail.com */ #ifndef SWEEP_H diff --git a/external/poly2tri/sweep/sweep_context.cc b/external/poly2tri/sweep/sweep_context.cc index b5c3d5a7dc8e..79bc5e7e3550 100644 --- a/external/poly2tri/sweep/sweep_context.cc +++ b/external/poly2tri/sweep/sweep_context.cc @@ -35,12 +35,12 @@ namespace p2t { SweepContext::SweepContext(const std::vector& polyline) : points_(polyline), - front_(0), - head_(0), - tail_(0), - af_head_(0), - af_middle_(0), - af_tail_(0) + front_(nullptr), + head_(nullptr), + tail_(nullptr), + af_head_(nullptr), + af_middle_(nullptr), + af_tail_(nullptr) { InitEdges(points_); } @@ -87,8 +87,8 @@ void SweepContext::InitTriangulation() double dx = kAlpha * (xmax - xmin); double dy = kAlpha * (ymax - ymin); - head_ = new Point(xmax + dx, ymin - dy); - tail_ = new Point(xmin - dx, ymin - dy); + head_ = new Point(xmin - dx, ymin - dy); + tail_ = new Point(xmax + dx, ymin - dy); // Sort points along y-axis std::sort(points_.begin(), points_.end(), cmp); @@ -114,17 +114,17 @@ void SweepContext::AddToMap(Triangle* triangle) map_.push_back(triangle); } -Node& SweepContext::LocateNode(const Point& point) +Node* SweepContext::LocateNode(const Point& point) { // TODO implement search tree - return *front_->LocateNode(point.x); + return front_->LocateNode(point.x); } void SweepContext::CreateAdvancingFront() { // Initial triangle - Triangle* triangle = new Triangle(*points_[0], *tail_, *head_); + Triangle* triangle = new Triangle(*points_[0], *head_, *tail_); map_.push_back(triangle); @@ -171,7 +171,7 @@ void SweepContext::MeshClean(Triangle& triangle) Triangle *t = triangles.back(); triangles.pop_back(); - if (t != NULL && !t->IsInterior()) { + if (t != nullptr && !t->IsInterior()) { t->IsInterior(true); triangles_.push_back(t); for (int i = 0; i < 3; i++) { @@ -207,4 +207,4 @@ SweepContext::~SweepContext() } -} +} // namespace p2t diff --git a/external/poly2tri/sweep/sweep_context.h b/external/poly2tri/sweep/sweep_context.h index b6bc1cd828c8..47d970b7bcfb 100644 --- a/external/poly2tri/sweep/sweep_context.h +++ b/external/poly2tri/sweep/sweep_context.h @@ -66,7 +66,7 @@ Point* tail() const; size_t point_count() const; -Node& LocateNode(const Point& point); +Node* LocateNode(const Point& point); void RemoveNode(Node* node); From bc9cd2668f2b8bb1808622ffa74f76c0f3392525 Mon Sep 17 00:00:00 2001 From: nirvn Date: Sat, 13 Nov 2021 11:20:19 +0700 Subject: [PATCH 2/3] Re-apply @jef-n warning fix in the poly2tri library --- external/poly2tri/common/utils.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/external/poly2tri/common/utils.h b/external/poly2tri/common/utils.h index f71334c5d380..b4b78bf0be03 100644 --- a/external/poly2tri/common/utils.h +++ b/external/poly2tri/common/utils.h @@ -33,7 +33,9 @@ #define UTILS_H // Otherwise #defines like M_PI are undeclared under Visual Studio +#ifndef _USE_MATH_DEFINES #define _USE_MATH_DEFINES +#endif #include "shapes.h" From 29859bb073562194c56fe30f146ab14d2a4cd27f Mon Sep 17 00:00:00 2001 From: nirvn Date: Sat, 13 Nov 2021 11:22:06 +0700 Subject: [PATCH 3/3] [tessallator] Remove self-intersecting skip, crash fixed in upstream library (fixes #46021) --- src/core/qgstessellator.cpp | 65 ------------------------------------- 1 file changed, 65 deletions(-) diff --git a/src/core/qgstessellator.cpp b/src/core/qgstessellator.cpp index 4c486bdc08c4..04ae1efd13a5 100644 --- a/src/core/qgstessellator.cpp +++ b/src/core/qgstessellator.cpp @@ -431,64 +431,6 @@ static QgsPolygon *_transform_polygon_to_new_base( const QgsPolygon &polygon, co return p; } -static bool _check_intersecting_rings( const QgsPolygon &polygon ) -{ - std::vector< std::unique_ptr< QgsGeometryEngine > > ringEngines; - ringEngines.reserve( 1 + polygon.numInteriorRings() ); - ringEngines.emplace_back( QgsGeometry::createGeometryEngine( polygon.exteriorRing() ) ); - for ( int i = 0; i < polygon.numInteriorRings(); ++i ) - ringEngines.emplace_back( QgsGeometry::createGeometryEngine( polygon.interiorRing( i ) ) ); - - // we need to make sure that the polygon has no rings with self-intersection: that may - // crash the tessellator. The original geometry maybe have been valid and the self-intersection - // was introduced when transforming to a new base (in a rare case when all points are not in the same plane) - - for ( const std::unique_ptr< QgsGeometryEngine > &ring : ringEngines ) - { - if ( !ring->isSimple() ) - return false; - } - - // At this point we assume that input polygons are valid according to the OGC definition. - // This means e.g. no duplicate points, polygons are simple (no butterfly shaped polygon with self-intersection), - // internal rings are inside exterior rings, rings do not cross each other, no dangles. - - // There is however an issue with polygons where rings touch: - // +---+ - // | | - // | +-+-+ - // | | | | - // | +-+ | - // | | - // +-----+ - // This is a valid polygon with one exterior and one interior ring that touch at one point, - // but poly2tri library does not allow interior rings touch each other or exterior ring. - // TODO: Handle the situation better - rather than just detecting the problem, try to fix - // it by converting touching rings into one ring. - - if ( ringEngines.size() > 1 ) - { - for ( size_t i = 0; i < ringEngines.size(); ++i ) - { - std::unique_ptr< QgsGeometryEngine > &first = ringEngines.at( i ); - if ( polygon.numInteriorRings() > 1 ) - first->prepareGeometry(); - - // TODO this is inefficient - QgsGeometryEngine::intersects only works with QgsAbstractGeometry - // objects and accordingly we have to use those, instead of the previously build geos - // representations available in ringEngines - // This needs addressing by extending the QgsGeometryEngine relation tests to allow testing against - // another QgsGeometryEngine object. - for ( int interiorRing = static_cast< int >( i ); interiorRing < polygon.numInteriorRings(); ++interiorRing ) - { - if ( first->intersects( polygon.interiorRing( interiorRing ) ) ) - return false; - } - } - } - return true; -} - double _minimum_distance_between_coordinates( const QgsPolygon &polygon ) { @@ -687,13 +629,6 @@ void QgsTessellator::addPolygon( const QgsPolygon &polygon, float extrusionHeigh } } - if ( !_check_intersecting_rings( *polygonNew ) ) - { - // skip the polygon - it would cause a crash inside poly2tri library - QgsMessageLog::logMessage( QObject::tr( "polygon rings self-intersect or intersect each other - skipping" ), QObject::tr( "3D" ) ); - return; - } - QList< std::vector > polylinesToDelete; QHash z;