Browse Source

Mosfet80 updatedpoli2tri (#5682)

* updated poli2tri library to last version
Kim Kulling 1 year ago
parent
commit
571ba09dc7

+ 2 - 3
contrib/poly2tri/LICENSE

@@ -1,7 +1,6 @@
-Poly2Tri Copyright (c) 2009-2010, Poly2Tri Contributors
-http://code.google.com/p/poly2tri/
-
+Copyright (c) 2009-2018, Poly2Tri Contributors
 All rights reserved.
+
 Redistribution and use in source and binary forms, with or without modification,
 are permitted provided that the following conditions are met:
 

+ 0 - 51
contrib/poly2tri/README

@@ -1,51 +0,0 @@
-==================
-INSTALLATION GUIDE
-==================
-
-------------
-Dependencies
-------------
-
-  Core poly2tri lib:
-  - Standard Template Library (STL)
-  
-  Testbed:
-  - gcc
-  - OpenGL
-  - GLFW (http://glfw.sf.net)
-  - Python
- 
-Waf (http://code.google.com/p/waf/) is used to compile the testbed.   
-A waf script (86kb) is included in the repositoty.
-
-----------------------------------------------
-Building the Testbed
-----------------------------------------------
-
-Posix/MSYS environment:
-
-  ./waf configure
-  ./waf build
-
-Windows command line:
-
-  python waf configure
-  python waf build
-
-----------------------------------------------
-Running the Examples
-----------------------------------------------
-
-Load data points from a file:
-p2t <filename> <center_x> <center_y> <zoom>
-
-Random distribution of points inside a consrained box:
-p2t random <num_points> <box_radius> <zoom>
-
-Examples:
-
-  ./p2t dude.dat 300 500 2
-  ./p2t nazca_monkey.dat 0 0 9
-  
-  ./p2t random 10 100 5.0
-  ./p2t random 1000 20000 0.025

+ 101 - 0
contrib/poly2tri/README.md

@@ -0,0 +1,101 @@
+Since there are no Input validation of the data given for triangulation you need
+to think about this. Poly2Tri does not support repeat points within epsilon.
+
+* If you have a cyclic function that generates random points make sure you don't
+  add the same coordinate twice.
+* If you are given input and aren't sure same point exist twice you need to
+  check for this yourself.
+* Only simple polygons are supported. You may add holes or interior Steiner points
+* Interior holes must not touch other holes, nor touch the polyline boundary
+* Use the library in this order:
+  1. Initialize CDT with a simple polyline (this defines the constrained edges)
+  2. Add holes if necessary (also simple polylines)
+  3. Add Steiner points
+  4. Triangulate
+
+Make sure you understand the preceding notice before posting an issue. If you have
+an issue not covered by the above, include your data-set with the problem.
+The only easy day was yesterday; have a nice day. <Mason Green>
+
+TESTBED INSTALLATION GUIDE
+==========================
+
+Dependencies
+------------
+
+Core poly2tri lib:
+
+* Standard Template Library (STL)
+
+Unit tests:
+* Boost (filesystem, test framework)
+
+Testbed:
+
+* OpenGL
+* [GLFW](http://glfw.sf.net)
+
+Build the library
+-----------------
+
+With the ninja build system installed:
+
+```
+mkdir build && cd build
+cmake -GNinja ..
+cmake --build .
+```
+
+Build and run with unit tests
+----------------------------
+
+With the ninja build system:
+
+```
+mkdir build && cd build
+cmake -GNinja -DP2T_BUILD_TESTS=ON ..
+cmake --build .
+ctest --output-on-failure
+```
+
+Build with the testbed
+-----------------
+
+```
+mkdir build && cd build
+cmake -GNinja -DP2T_BUILD_TESTBED=ON ..
+cmake --build .
+```
+
+Running the Examples
+--------------------
+
+Load data points from a file:
+```
+build/testbed/p2t <filename> <center_x> <center_y> <zoom>
+```
+Load data points from a file and automatically fit the geometry to the window:
+```
+build/testbed/p2t <filename>
+```
+Random distribution of points inside a constrained box:
+```
+build/testbed/p2t random <num_points> <box_radius> <zoom>
+```
+Examples:
+```
+build/testbed/p2t testbed/data/dude.dat 350 500 3
+
+build/testbed/p2t testbed/data/nazca_monkey.dat
+
+build/testbed/p2t random 10 100 5.0
+build/testbed/p2t random 1000 20000 0.025
+```
+
+References
+==========
+
+- Domiter V. and Zalik B. (2008) Sweep‐line algorithm for constrained Delaunay triangulation
+- FlipScan by library author Thomas Åhlén
+
+![FlipScan](doc/FlipScan.png)

+ 59 - 0
contrib/poly2tri/poly2tri/common/dll_symbol.h

@@ -0,0 +1,59 @@
+/*
+ * Poly2Tri Copyright (c) 2009-2022, Poly2Tri Contributors
+ * https://github.com/jhasse/poly2tri
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ *   this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ *   this list of conditions and the following disclaimer in the documentation
+ *   and/or other materials provided with the distribution.
+ * * Neither the name of Poly2Tri nor the names of its contributors may be
+ *   used to endorse or promote products derived from this software without specific
+ *   prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#if defined(_WIN32)
+#  pragma warning( disable: 4273)
+#  define P2T_COMPILER_DLLEXPORT __declspec(dllexport)
+#  define P2T_COMPILER_DLLIMPORT __declspec(dllimport)
+#elif defined(__GNUC__)
+#  define P2T_COMPILER_DLLEXPORT __attribute__ ((visibility ("default")))
+#  define P2T_COMPILER_DLLIMPORT __attribute__ ((visibility ("default")))
+#else
+#  define P2T_COMPILER_DLLEXPORT
+#  define P2T_COMPILER_DLLIMPORT
+#endif
+
+// We need to enable shard linkage explicitely
+#ifdef ASSIMP_BUILD_DLL_EXPORT
+#  define P2T_SHARED_EXPORTS 1
+#endif
+
+#ifndef P2T_DLL_SYMBOL
+#  if defined(P2T_STATIC_EXPORTS)
+#    define P2T_DLL_SYMBOL
+#  elif defined(P2T_SHARED_EXPORTS)
+#    define P2T_DLL_SYMBOL P2T_COMPILER_DLLEXPORT
+#  else
+#    define P2T_DLL_SYMBOL P2T_COMPILER_DLLIMPORT
+#  endif
+#endif

+ 78 - 32
contrib/poly2tri/poly2tri/common/shapes.cc

@@ -1,6 +1,6 @@
 /*
- * Poly2Tri Copyright (c) 2009-2010, Poly2Tri Contributors
- * http://code.google.com/p/poly2tri/
+ * Poly2Tri Copyright (c) 2009-2018, Poly2Tri Contributors
+ * https://github.com/jhasse/poly2tri
  *
  * All rights reserved.
  *
@@ -29,14 +29,24 @@
  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 #include "shapes.h"
+
+#include <cassert>
 #include <iostream>
 
 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;
+}
+
 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;
@@ -76,39 +86,37 @@ void Triangle::MarkNeighbor(Triangle& t)
 void Triangle::Clear()
 {
     Triangle *t;
-    for( int i=0; i<3; i++ )
-    {
-        t = neighbors_[i];
-        if( t != NULL )
-        {
-            t->ClearNeighbor( this );
-        }
+    for (auto& neighbor : neighbors_) {
+      t = neighbor;
+      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()
@@ -220,7 +228,7 @@ Point* Triangle::PointCW(const Point& point)
     return points_[1];
   }
   assert(0);
-  return NULL;
+  return nullptr;
 }
 
 // The point counter-clockwise to given point
@@ -234,7 +242,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
@@ -343,23 +362,50 @@ void Triangle::SetDelunayEdgeCW(const Point& p, bool e)
   }
 }
 
-// The neighbor across to given point
-Triangle& Triangle::NeighborAcross(const Point& opoint)
+void Triangle::DebugPrint()
 {
-  if (&opoint == points_[0]) {
-    return *neighbors_[0];
-  } else if (&opoint == points_[1]) {
-    return *neighbors_[1];
-  }
-  return *neighbors_[2];
+  std::cout << *points_[0] << " " << *points_[1] << " " << *points_[2] << std::endl;
 }
 
-void Triangle::DebugPrint()
+bool Triangle::CircumcicleContains(const Point& point) const
+{
+  assert(IsCounterClockwise());
+  const double dx = points_[0]->x - point.x;
+  const double dy = points_[0]->y - point.y;
+  const double ex = points_[1]->x - point.x;
+  const double ey = points_[1]->y - point.y;
+  const double fx = points_[2]->x - point.x;
+  const double fy = points_[2]->y - point.y;
+
+  const double ap = dx * dx + dy * dy;
+  const double bp = ex * ex + ey * ey;
+  const double cp = fx * fx + fy * fy;
+
+  return (dx * (fy * bp - cp * ey) - dy * (fx * bp - cp * ex) + ap * (fx * ey - fy * ex)) < 0;
+}
+
+bool Triangle::IsCounterClockwise() const
 {
-  using namespace std;
-  cout << points_[0]->x << "," << points_[0]->y << " ";
-  cout << points_[1]->x << "," << points_[1]->y << " ";
-  cout << points_[2]->x << "," << points_[2]->y << endl;
+  return (points_[1]->x - points_[0]->x) * (points_[2]->y - points_[0]->y) -
+             (points_[2]->x - points_[0]->x) * (points_[1]->y - points_[0]->y) >
+         0;
 }
 
+bool IsDelaunay(const std::vector<p2t::Triangle*>& triangles)
+{
+  for (const auto triangle : triangles) {
+    for (const auto other : triangles) {
+      if (triangle == other) {
+        continue;
+      }
+      for (int i = 0; i < 3; ++i) {
+        if (triangle->CircumcicleContains(*other->GetPoint(i))) {
+          return false;
+        }
+      }
+    }
+  }
+  return true;
 }
+
+} // namespace p2t

+ 27 - 21
contrib/poly2tri/poly2tri/common/shapes.h

@@ -1,6 +1,6 @@
 /*
- * Poly2Tri Copyright (c) 2009-2010, Poly2Tri Contributors
- * http://code.google.com/p/poly2tri/
+ * Poly2Tri Copyright (c) 2009-2018, Poly2Tri Contributors
+ * https://github.com/jhasse/poly2tri
  *
  * All rights reserved.
  *
@@ -29,22 +29,24 @@
  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-// Include guard
-#ifndef SHAPES_H
-#define SHAPES_H
+#pragma once
 
-#include <vector>
+#include "dll_symbol.h"
+
+#include <cmath>
 #include <cstddef>
 #include <stdexcept>
-#include <assert.h>
-#include <cmath>
-#include <string>
+#include <vector>
+
 
+#if defined(_WIN32)
+#  pragma warning( disable: 4251)
+#endif
 namespace p2t {
 
 struct Edge;
 
-struct Point {
+struct P2T_DLL_SYMBOL Point {
 
   double x, y;
 
@@ -59,7 +61,7 @@ struct Point {
   std::vector<Edge*> 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()
@@ -121,8 +123,10 @@ struct Point {
 
 };
 
+P2T_DLL_SYMBOL std::ostream& operator<<(std::ostream&, const Point&);
+
 // Represents a simple polygon's edge
-struct Edge {
+struct P2T_DLL_SYMBOL Edge {
 
   Point* p, *q;
 
@@ -138,9 +142,7 @@ struct Edge {
         p = &p2;
       } else if (p1.x == p2.x) {
         // Repeat points
-        // ASSIMP_CHANGE (aramis_acg)
-        throw std::runtime_error(std::string("repeat points"));
-        //assert(false);
+        throw std::runtime_error("Edge::Edge: p1 == p2");
       }
     }
 
@@ -151,7 +153,7 @@ struct Edge {
 // Triangle-based data structures are know to have better performance than quad-edge structures
 // See: J. Shewchuk, "Triangle: Engineering a 2D Quality Mesh Generator and Delaunay Triangulator"
 //      "Triangulations in CGAL"
-class Triangle {
+class P2T_DLL_SYMBOL Triangle {
 public:
 
 /// Constructor
@@ -178,6 +180,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);
@@ -205,12 +208,14 @@ void ClearDelunayEdges();
 inline bool IsInterior();
 inline void IsInterior(bool b);
 
-Triangle& NeighborAcross(const Point& opoint);
-
 void DebugPrint();
 
+bool CircumcicleContains(const Point&) const;
+
 private:
 
+bool IsCounterClockwise() const;
+
 /// Triangle points
 Point* points_[3];
 /// Neighbor list
@@ -258,7 +263,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.
@@ -322,6 +327,7 @@ inline void Triangle::IsInterior(bool b)
   interior_ = b;
 }
 
-}
+/// Is this set a valid delaunay triangulation?
+P2T_DLL_SYMBOL bool IsDelaunay(const std::vector<p2t::Triangle*>&);
 
-#endif
+}

+ 11 - 8
contrib/poly2tri/poly2tri/common/utils.h

@@ -1,6 +1,6 @@
 /*
- * Poly2Tri Copyright (c) 2009-2010, Poly2Tri Contributors
- * http://code.google.com/p/poly2tri/
+ * Poly2Tri Copyright (c) 2009-2018, Poly2Tri Contributors
+ * https://github.com/jhasse/poly2tri
  *
  * All rights reserved.
  *
@@ -29,14 +29,15 @@
  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-#ifndef UTILS_H
-#define UTILS_H
+#pragma once
 
 // Otherwise #defines like M_PI are undeclared under Visual Studio
 #define _USE_MATH_DEFINES
 
+#include "shapes.h"
+
+#include <cmath>
 #include <exception>
-#include <math.h>
 
 // C99 removes M_PI from math.h
 #ifndef M_PI
@@ -66,7 +67,11 @@ Orientation Orient2d(const Point& pa, const Point& pb, const Point& pc)
   double detleft = (pa.x - pc.x) * (pb.y - pc.y);
   double detright = (pa.y - pc.y) * (pb.x - pc.x);
   double val = detleft - detright;
-  if (val > -EPSILON && val < EPSILON) {
+
+// Using a tolerance here fails on concave-by-subepsilon boundaries
+//   if (val > -EPSILON && val < EPSILON) {
+// Using == on double makes -Wfloat-equal warnings yell at us
+  if (std::fpclassify(val) == FP_ZERO) {
     return COLLINEAR;
   } else if (val > 0) {
     return CCW;
@@ -123,5 +128,3 @@ bool InScanArea(const Point& pa, const Point& pb, const Point& pc, const Point&
 }
 
 }
-
-#endif

+ 3 - 6
contrib/poly2tri/poly2tri/poly2tri.h

@@ -1,6 +1,6 @@
 /*
- * Poly2Tri Copyright (c) 2009-2010, Poly2Tri Contributors
- * http://code.google.com/p/poly2tri/
+ * Poly2Tri Copyright (c) 2009-2018, Poly2Tri Contributors
+ * https://github.com/jhasse/poly2tri
  *
  * All rights reserved.
  *
@@ -29,10 +29,7 @@
  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-#ifndef POLY2TRI_H
-#define POLY2TRI_H
+#pragma once
 
 #include "common/shapes.h"
 #include "sweep/cdt.h"
-
-#endif

+ 10 - 8
contrib/poly2tri/poly2tri/sweep/advancing_front.cc

@@ -1,6 +1,6 @@
 /*
- * Poly2Tri Copyright (c) 2009-2010, Poly2Tri Contributors
- * http://code.google.com/p/poly2tri/
+ * Poly2Tri Copyright (c) 2009-2018, Poly2Tri Contributors
+ * https://github.com/jhasse/poly2tri
  *
  * All rights reserved.
  *
@@ -30,6 +30,8 @@
  */
 #include "advancing_front.h"
 
+#include <cassert>
+
 namespace p2t {
 
 AdvancingFront::AdvancingFront(Node& head, Node& tail)
@@ -44,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)
@@ -86,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;
     }
@@ -105,4 +107,4 @@ AdvancingFront::~AdvancingFront()
 {
 }
 
-}
+} // namespace p2t

+ 3 - 6
contrib/poly2tri/poly2tri/sweep/advancing_front.h

@@ -1,6 +1,6 @@
 /*
- * Poly2Tri Copyright (c) 2009-2010, Poly2Tri Contributors
- * http://code.google.com/p/poly2tri/
+ * Poly2Tri Copyright (c) 2009-2018, Poly2Tri Contributors
+ * https://github.com/jhasse/poly2tri
  *
  * All rights reserved.
  *
@@ -29,8 +29,7 @@
  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-#ifndef ADVANCED_FRONT_H
-#define ADVANCED_FRONT_H
+#pragma once
 
 #include "../common/shapes.h"
 
@@ -114,5 +113,3 @@ inline void AdvancingFront::set_search(Node* node)
 }
 
 }
-
-#endif

+ 3 - 3
contrib/poly2tri/poly2tri/sweep/cdt.cc

@@ -1,6 +1,6 @@
 /*
- * Poly2Tri Copyright (c) 2009-2010, Poly2Tri Contributors
- * http://code.google.com/p/poly2tri/
+ * 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

+ 6 - 7
contrib/poly2tri/poly2tri/sweep/cdt.h

@@ -1,6 +1,6 @@
 /*
- * Poly2Tri Copyright (c) 2009-2010, Poly2Tri Contributors
- * http://code.google.com/p/poly2tri/
+ * Poly2Tri Copyright (c) 2009-2018, Poly2Tri Contributors
+ * https://github.com/jhasse/poly2tri
  *
  * All rights reserved.
  *
@@ -29,13 +29,14 @@
  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-#ifndef CDT_H
-#define CDT_H
+#pragma once
 
 #include "advancing_front.h"
 #include "sweep_context.h"
 #include "sweep.h"
 
+#include "../common/dll_symbol.h"
+
 /**
  *
  * @author Mason Green <[email protected]>
@@ -44,7 +45,7 @@
 
 namespace p2t {
 
-class CDT
+class P2T_DLL_SYMBOL CDT
 {
 public:
 
@@ -101,5 +102,3 @@ public:
 };
 
 }
-
-#endif

+ 110 - 60
contrib/poly2tri/poly2tri/sweep/sweep.cc

@@ -1,6 +1,6 @@
 /*
- * Poly2Tri Copyright (c) 2009-2010, Poly2Tri Contributors
- * http://code.google.com/p/poly2tri/
+ * Poly2Tri Copyright (c) 2009-2018, Poly2Tri Contributors
+ * https://github.com/jhasse/poly2tri
  *
  * All rights reserved.
  *
@@ -28,24 +28,21 @@
  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
-#include <stdexcept>
 #include "sweep.h"
 #include "sweep_context.h"
 #include "advancing_front.h"
 #include "../common/utils.h"
 
-namespace p2t {
+#include <cassert>
+#include <stdexcept>
 
-#ifdef _MSC_VER
-#    pragma warning(push)
-#    pragma warning( disable : 4702 )
-#endif // _MSC_VER
+namespace p2t {
 
 // Triangulate simple polygon with holes
 void Sweep::Triangulate(SweepContext& tcx)
 {
   tcx.InitTriangulation();
-  tcx.CreateAdvancingFront(nodes_);
+  tcx.CreateAdvancingFront();
   // Sweep points; build mesh
   SweepPoints(tcx);
   // Clean up
@@ -57,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 ii = 0; ii < point.edge_list.size(); ii++) {
-      EdgeEvent(tcx, point.edge_list[ii], node);
+    for (auto& j : point.edge_list) {
+      EdgeEvent(tcx, j, node);
     }
   }
 }
@@ -68,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
@@ -111,9 +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)
-   return;
-
+  if (triangle == nullptr) {
+    throw std::runtime_error("EdgeEvent - null triangle");
+  }
   if (IsEdgeSideOfTriangle(*triangle, ep, eq)) {
     return;
   }
@@ -121,17 +126,14 @@ 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 {
-	  // ASSIMP_CHANGE (aramis_acg)
       throw std::runtime_error("EdgeEvent - collinear points not supported");
     }
     return;
@@ -140,18 +142,14 @@ 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 {
-      // ASSIMP_CHANGE (aramis_acg)
       throw std::runtime_error("EdgeEvent - collinear points not supported");
     }
     return;
@@ -162,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);
   }
 }
@@ -228,7 +227,6 @@ void Sweep::Fill(SweepContext& tcx, Node& node)
   if (!Legalize(tcx, *triangle)) {
     tcx.MapTriangleToNodes(*triangle);
   }
-
 }
 
 void Sweep::FillAdvancingFront(SweepContext& tcx, Node& n)
@@ -237,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);
@@ -247,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);
@@ -264,6 +262,35 @@ void Sweep::FillAdvancingFront(SweepContext& tcx, Node& n)
 }
 
 // True if HoleAngle exceeds 90 degrees.
+// LargeHole_DontFill checks if the advancing front has a large hole.
+// A "Large hole" is a triangle formed by a sequence of points in the advancing
+// front where three neighbor points form a triangle.
+// And angle between left-top, bottom, and right-top points is more than 90 degrees.
+// The first part of the algorithm reviews only three neighbor points, e.g. named A, B, C.
+// Additional part of this logic reviews a sequence of 5 points -
+// additionally reviews one point before and one after the sequence of three (A, B, C),
+// e.g. named X and Y.
+// In this case, angles are XBC and ABY and this if angles are negative or more
+// than 90 degrees LargeHole_DontFill returns true.
+// But there is a configuration when ABC has a negative angle but XBC or ABY is less
+// than 90 degrees and positive.
+// Then function LargeHole_DontFill return false and initiates filling.
+// This filling creates a triangle ABC and adds it to the advancing front.
+// But in the case when angle ABC is negative this triangle goes inside the advancing front
+// and can intersect previously created triangles.
+// This triangle leads to making wrong advancing front and problems in triangulation in the future.
+// Looks like such a triangle should not be created.
+// The simplest way to check and fix it is to check an angle ABC.
+// If it is negative LargeHole_DontFill should return true and
+// not initiate creating the ABC triangle in the advancing front.
+// X______A         Y
+//        \        /
+//         \      /
+//          \ B  /
+//           |  /
+//           | /
+//           |/
+//           C
 bool Sweep::LargeHole_DontFill(const Node* node) const {
 
   const Node* nextNode = node->next;
@@ -271,20 +298,28 @@ bool Sweep::LargeHole_DontFill(const Node* node) const {
   if (!AngleExceeds90Degrees(node->point, nextNode->point, prevNode->point))
           return false;
 
+  if (AngleIsNegative(node->point, nextNode->point, prevNode->point))
+          return true;
+
   // 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;
 }
 
+bool Sweep::AngleIsNegative(const Point* origin, const Point* pa, const Point* pb) const {
+    const double angle = Angle(origin, pa, pb);
+    return angle < 0;
+}
+
 bool Sweep::AngleExceeds90Degrees(const Point* origin, const Point* pa, const Point* pb) const {
   const double angle = Angle(origin, pa, pb);
   return ((angle > PI_div2) || (angle < -PI_div2));
@@ -306,7 +341,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;
@@ -599,7 +634,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
@@ -623,7 +658,6 @@ void Sweep::FillRightConcaveEdgeEvent(SweepContext& tcx, Edge* edge, Node& node)
       }
     }
   }
-
 }
 
 void Sweep::FillRightConvexEdgeEvent(SweepContext& tcx, Edge* edge, Node& node)
@@ -632,13 +666,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
     }
   }
@@ -677,13 +711,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
     }
   }
@@ -699,17 +733,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)) {
@@ -775,10 +814,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");
+  }
 
-  if (InScanArea(eq, *flip_triangle.PointCCW(eq), *flip_triangle.PointCW(eq), op)) {
+  Point* op_ptr = ot_ptr->OppositePoint(t, p);
+  if (op_ptr == nullptr) {
+    throw std::runtime_error("FlipScanEdgeEvent - null opposing point");
+  }
+
+  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
@@ -788,7 +843,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);
   }
@@ -797,14 +852,9 @@ void Sweep::FlipScanEdgeEvent(SweepContext& tcx, Point& ep, Point& eq, Triangle&
 Sweep::~Sweep() {
 
     // Clean up memory
-    for(size_t i = 0; i < nodes_.size(); i++) {
-        delete nodes_[i];
+    for (auto& node : nodes_) {
+      delete node;
     }
-
 }
 
-#ifdef _MSC_VER
-#    pragma warning( pop )
-#endif // _MSC_VER
-
-}
+} // namespace p2t

+ 5 - 7
contrib/poly2tri/poly2tri/sweep/sweep.h

@@ -1,6 +1,6 @@
 /*
- * Poly2Tri Copyright (c) 2009-2010, Poly2Tri Contributors
- * http://code.google.com/p/poly2tri/
+ * Poly2Tri Copyright (c) 2009-2018, Poly2Tri Contributors
+ * https://github.com/jhasse/poly2tri
  *
  * All rights reserved.
  *
@@ -33,11 +33,10 @@
  * 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, [email protected]
+ * "FlipScan" Constrained Edge Algorithm invented by Thomas Åhlén, [email protected]
  */
 
-#ifndef SWEEP_H
-#define SWEEP_H
+#pragma once
 
 #include <vector>
 
@@ -172,6 +171,7 @@ private:
   // Decision-making about when to Fill hole.
   // Contributed by ToolmakerSteve2
   bool LargeHole_DontFill(const Node* node) const;
+  bool AngleIsNegative(const Point* origin, const Point* pa, const Point* pb) const;
   bool AngleExceeds90Degrees(const Point* origin, const Point* pa, const Point* pb) const;
   bool AngleExceedsPlus90DegreesOrIsNegative(const Point* origin, const Point* pa, const Point* pb) const;
   double Angle(const Point* origin, const Point* pa, const Point* pb) const;
@@ -281,5 +281,3 @@ private:
 };
 
 }
-
-#endif

+ 25 - 30
contrib/poly2tri/poly2tri/sweep/sweep_context.cc

@@ -1,6 +1,6 @@
 /*
- * Poly2Tri Copyright (c) 2009-2010, Poly2Tri Contributors
- * http://code.google.com/p/poly2tri/
+ * Poly2Tri Copyright (c) 2009-2022, Poly2Tri Contributors
+ * https://github.com/jhasse/poly2tri
  *
  * All rights reserved.
  *
@@ -34,13 +34,13 @@
 
 namespace p2t {
 
-SweepContext::SweepContext(const std::vector<Point*>& polyline) : points_(polyline),
-  front_(0),
-  head_(0),
-  tail_(0),
-  af_head_(0),
-  af_middle_(0),
-  af_tail_(0)
+SweepContext::SweepContext(std::vector<Point*> polyline) : points_(std::move(polyline)),
+  front_(nullptr),
+  head_(nullptr),
+  tail_(nullptr),
+  af_head_(nullptr),
+  af_middle_(nullptr),
+  af_tail_(nullptr)
 {
   InitEdges(points_);
 }
@@ -48,8 +48,8 @@ SweepContext::SweepContext(const std::vector<Point*>& polyline) : points_(polyli
 void SweepContext::AddHole(const std::vector<Point*>& polyline)
 {
   InitEdges(polyline);
-  for(unsigned int i = 0; i < polyline.size(); i++) {
-    points_.push_back(polyline[i]);
+  for (auto i : polyline) {
+    points_.push_back(i);
   }
 }
 
@@ -73,8 +73,8 @@ void SweepContext::InitTriangulation()
   double ymax(points_[0]->y), ymin(points_[0]->y);
 
   // Calculate bounds.
-  for (unsigned int i = 0; i < points_.size(); i++) {
-    Point& p = *points_[i];
+  for (auto& point : points_) {
+    Point& p = *point;
     if (p.x > xmax)
       xmax = p.x;
     if (p.x < xmin)
@@ -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,18 +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(const std::vector<Node*>& nodes)
+void SweepContext::CreateAdvancingFront()
 {
 
-  (void) nodes;
   // Initial triangle
-  Triangle* triangle = new Triangle(*points_[0], *tail_, *head_);
+  Triangle* triangle = new Triangle(*points_[0], *head_, *tail_);
 
   map_.push_back(triangle);
 
@@ -172,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++) {
@@ -195,17 +194,13 @@ SweepContext::~SweepContext()
     delete af_middle_;
     delete af_tail_;
 
-    typedef std::list<Triangle*> type_list;
-
-    for(type_list::iterator iter = map_.begin(); iter != map_.end(); ++iter) {
-        Triangle* ptr = *iter;
-        delete ptr;
+    for (auto ptr : map_) {
+      delete ptr;
     }
 
-     for(unsigned int i = 0; i < edge_list.size(); i++) {
-        delete edge_list[i];
+    for (auto& i : edge_list) {
+      delete i;
     }
-
 }
 
-}
+} // namespace p2t

+ 11 - 13
contrib/poly2tri/poly2tri/sweep/sweep_context.h

@@ -1,6 +1,6 @@
 /*
- * Poly2Tri Copyright (c) 2009-2010, Poly2Tri Contributors
- * http://code.google.com/p/poly2tri/
+ * Poly2Tri Copyright (c) 2009-2022, Poly2Tri Contributors
+ * https://github.com/jhasse/poly2tri
  *
  * All rights reserved.
  *
@@ -29,8 +29,7 @@
  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-#ifndef SWEEP_CONTEXT_H
-#define SWEEP_CONTEXT_H
+#pragma once
 
 #include <list>
 #include <vector>
@@ -52,7 +51,7 @@ class SweepContext {
 public:
 
 /// Constructor
-SweepContext(const std::vector<Point*>& polyline);
+explicit SweepContext(std::vector<Point*> polyline);
 /// Destructor
 ~SweepContext();
 
@@ -66,11 +65,11 @@ Point* tail() const;
 
 size_t point_count() const;
 
-Node& LocateNode(const Point& point);
+Node* LocateNode(const Point& point);
 
 void RemoveNode(Node* node);
 
-void CreateAdvancingFront(const std::vector<Node*>& nodes);
+void CreateAdvancingFront();
 
 /// Try to map a node to all sides of this triangle that don't have a neighbor
 void MapTriangleToNodes(Triangle& t);
@@ -103,15 +102,16 @@ struct Basin {
   double width;
   bool left_highest;
 
-  Basin() : left_node(NULL), bottom_node(NULL), right_node(NULL), width(0.0), left_highest(false)
+  Basin()
+  : left_node(nullptr), bottom_node(nullptr), right_node(nullptr), width(0.0), left_highest(false)
   {
   }
 
   void Clear()
   {
-    left_node = NULL;
-    bottom_node = NULL;
-    right_node = NULL;
+    left_node = nullptr;
+    bottom_node = nullptr;
+    right_node = nullptr;
     width = 0.0;
     left_highest = false;
   }
@@ -182,5 +182,3 @@ inline Point* SweepContext::tail() const
 }
 
 }
-
-#endif