diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index fd5a735d7..b5948674a 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -50,7 +50,6 @@ if (SLIC3R_GUI) if(WIN32) message(STATUS "WXWIN environment set to: $ENV{WXWIN}") elseif(UNIX) - message(STATUS "wx-config path: ${wxWidgets_CONFIG_EXECUTABLE}") set(wxWidgets_USE_UNICODE ON) if(SLIC3R_STATIC) set(wxWidgets_USE_STATIC ON) @@ -72,6 +71,10 @@ if (SLIC3R_GUI) find_package(wxWidgets 3.1 REQUIRED COMPONENTS base core adv html gl) endif () + if(UNIX) + message(STATUS "wx-config path: ${wxWidgets_CONFIG_EXECUTABLE}") + endif() + include(${wxWidgets_USE_FILE}) endif() diff --git a/src/libslic3r/ExPolygon.cpp b/src/libslic3r/ExPolygon.cpp index 00bb4ffe4..f9c470450 100644 --- a/src/libslic3r/ExPolygon.cpp +++ b/src/libslic3r/ExPolygon.cpp @@ -310,16 +310,15 @@ ExPolygon::medial_axis(double max_width, double min_width, Polylines* polylines) polylines->insert(polylines->end(), tp.begin(), tp.end()); } -void -ExPolygon::get_trapezoids(Polygons* polygons) const +/* +void ExPolygon::get_trapezoids(Polygons* polygons) const { ExPolygons expp; expp.push_back(*this); boost::polygon::get_trapezoids(*polygons, expp); } -void -ExPolygon::get_trapezoids(Polygons* polygons, double angle) const +void ExPolygon::get_trapezoids(Polygons* polygons, double angle) const { ExPolygon clone = *this; clone.rotate(PI/2 - angle, Point(0,0)); @@ -327,12 +326,12 @@ ExPolygon::get_trapezoids(Polygons* polygons, double angle) const for (Polygons::iterator polygon = polygons->begin(); polygon != polygons->end(); ++polygon) polygon->rotate(-(PI/2 - angle), Point(0,0)); } +*/ // This algorithm may return more trapezoids than necessary // (i.e. it may break a single trapezoid in several because // other parts of the object have x coordinates in the middle) -void -ExPolygon::get_trapezoids2(Polygons* polygons) const +void ExPolygon::get_trapezoids2(Polygons* polygons) const { // get all points of this ExPolygon Points pp = *this; @@ -370,8 +369,7 @@ ExPolygon::get_trapezoids2(Polygons* polygons) const } } -void -ExPolygon::get_trapezoids2(Polygons* polygons, double angle) const +void ExPolygon::get_trapezoids2(Polygons* polygons, double angle) const { ExPolygon clone = *this; clone.rotate(PI/2 - angle, Point(0,0)); @@ -382,8 +380,7 @@ ExPolygon::get_trapezoids2(Polygons* polygons, double angle) const // While this triangulates successfully, it's NOT a constrained triangulation // as it will create more vertices on the boundaries than the ones supplied. -void -ExPolygon::triangulate(Polygons* polygons) const +void ExPolygon::triangulate(Polygons* polygons) const { // first make trapezoids Polygons trapezoids; @@ -394,8 +391,8 @@ ExPolygon::triangulate(Polygons* polygons) const polygon->triangulate_convex(polygons); } -void -ExPolygon::triangulate_pp(Polygons* polygons) const +/* +void ExPolygon::triangulate_pp(Polygons* polygons) const { // convert polygons std::list input; @@ -452,9 +449,113 @@ ExPolygon::triangulate_pp(Polygons* polygons) const polygons->push_back(p); } } +*/ -void -ExPolygon::triangulate_p2t(Polygons* polygons) const +std::list expoly_to_polypartition_input(const ExPolygon &ex) +{ + std::list input; + // contour + { + input.emplace_back(); + TPPLPoly &p = input.back(); + p.Init(int(ex.contour.points.size())); + for (const Point &point : ex.contour.points) { + size_t i = &point - &ex.contour.points.front(); + p[i].x = point(0); + p[i].y = point(1); + } + p.SetHole(false); + } + // holes + for (const Polygon &hole : ex.holes) { + input.emplace_back(); + TPPLPoly &p = input.back(); + p.Init(hole.points.size()); + for (const Point &point : hole.points) { + size_t i = &point - &hole.points.front(); + p[i].x = point(0); + p[i].y = point(1); + } + p.SetHole(true); + } + return input; +} + +std::list expoly_to_polypartition_input(const ExPolygons &expps) +{ + std::list input; + for (const ExPolygon &ex : expps) { + // contour + { + input.emplace_back(); + TPPLPoly &p = input.back(); + p.Init(int(ex.contour.points.size())); + for (const Point &point : ex.contour.points) { + size_t i = &point - &ex.contour.points.front(); + p[i].x = point(0); + p[i].y = point(1); + } + p.SetHole(false); + } + // holes + for (const Polygon &hole : ex.holes) { + input.emplace_back(); + TPPLPoly &p = input.back(); + p.Init(hole.points.size()); + for (const Point &point : hole.points) { + size_t i = &point - &hole.points.front(); + p[i].x = point(0); + p[i].y = point(1); + } + p.SetHole(true); + } + } + return input; +} + +std::vector polypartition_output_to_triangles(const std::list &output) +{ + size_t num_triangles = 0; + for (const TPPLPoly &poly : output) + if (poly.GetNumPoints() >= 3) + num_triangles += (size_t)poly.GetNumPoints() - 2; + std::vector triangles; + triangles.reserve(triangles.size() + num_triangles * 3); + for (const TPPLPoly &poly : output) { + long num_points = poly.GetNumPoints(); + if (num_points >= 3) { + const TPPLPoint *pt0 = &poly[0]; + const TPPLPoint *pt1 = nullptr; + const TPPLPoint *pt2 = &poly[1]; + for (long i = 2; i < num_points; ++ i) { + pt1 = pt2; + pt2 = &poly[i]; + triangles.emplace_back(coord_t(pt0->x), coord_t(pt0->y)); + triangles.emplace_back(coord_t(pt1->x), coord_t(pt1->y)); + triangles.emplace_back(coord_t(pt2->x), coord_t(pt2->y)); + } + } + } + return triangles; +} + +void ExPolygon::triangulate_pp(Points *triangles) const +{ + ExPolygons expp = union_ex(simplify_polygons(to_polygons(*this), true)); + std::list input = expoly_to_polypartition_input(expp); + // perform triangulation + std::list output; + int res = TPPLPartition().Triangulate_MONO(&input, &output); +// int TPPLPartition::Triangulate_EC(TPPLPolyList *inpolys, TPPLPolyList *triangles) { + if (res != 1) + throw std::runtime_error("Triangulation failed"); + *triangles = polypartition_output_to_triangles(output); +} + +// Uses the Poly2tri library maintained by Jan Niklas Hasse @jhasse // https://github.com/jhasse/poly2tri +// See https://github.com/jhasse/poly2tri/blob/master/README.md for the limitations of the library! +// No duplicate points are allowed, no very close points, holes must not touch outer contour etc. +void ExPolygon::triangulate_p2t(Polygons* polygons) const { ExPolygons expp = simplify_polygons_ex(*this, true); @@ -478,16 +579,21 @@ ExPolygon::triangulate_p2t(Polygons* polygons) const } // perform triangulation - cdt.Triangulate(); - std::vector triangles = cdt.GetTriangles(); - - for (std::vector::const_iterator triangle = triangles.begin(); triangle != triangles.end(); ++triangle) { - Polygon p; - for (int i = 0; i <= 2; ++i) { - p2t::Point* point = (*triangle)->GetPoint(i); - p.points.push_back(Point(point->x, point->y)); + try { + cdt.Triangulate(); + std::vector triangles = cdt.GetTriangles(); + + for (std::vector::const_iterator triangle = triangles.begin(); triangle != triangles.end(); ++triangle) { + Polygon p; + for (int i = 0; i <= 2; ++i) { + p2t::Point* point = (*triangle)->GetPoint(i); + p.points.push_back(Point(point->x, point->y)); + } + polygons->push_back(p); } - polygons->push_back(p); + } catch (const std::runtime_error & /* err */) { + assert(false); + // just ignore, don't triangulate } for (p2t::Point *ptr : ContourPoints) @@ -495,8 +601,7 @@ ExPolygon::triangulate_p2t(Polygons* polygons) const } } -Lines -ExPolygon::lines() const +Lines ExPolygon::lines() const { Lines lines = this->contour.lines(); for (Polygons::const_iterator h = this->holes.begin(); h != this->holes.end(); ++h) { diff --git a/src/libslic3r/ExPolygon.hpp b/src/libslic3r/ExPolygon.hpp index 4833ee49e..afbc0931e 100644 --- a/src/libslic3r/ExPolygon.hpp +++ b/src/libslic3r/ExPolygon.hpp @@ -6,6 +6,9 @@ #include "Polyline.hpp" #include +// polygon class of the polypartition library +class TPPLPoly; + namespace Slic3r { class ExPolygon; @@ -55,12 +58,13 @@ public: void simplify(double tolerance, ExPolygons* expolygons) const; void medial_axis(double max_width, double min_width, ThickPolylines* polylines) const; void medial_axis(double max_width, double min_width, Polylines* polylines) const; - void get_trapezoids(Polygons* polygons) const; - void get_trapezoids(Polygons* polygons, double angle) const; +// void get_trapezoids(Polygons* polygons) const; +// void get_trapezoids(Polygons* polygons, double angle) const; void get_trapezoids2(Polygons* polygons) const; void get_trapezoids2(Polygons* polygons, double angle) const; void triangulate(Polygons* polygons) const; - void triangulate_pp(Polygons* polygons) const; + // Triangulate into triples of points. + void triangulate_pp(Points *triangles) const; void triangulate_p2t(Polygons* polygons) const; Lines lines() const; }; @@ -297,6 +301,10 @@ extern std::vector get_extents_vector(const ExPolygons &polygons); extern bool remove_sticks(ExPolygon &poly); +extern std::list expoly_to_polypartition_input(const ExPolygons &expp); +extern std::list expoly_to_polypartition_input(const ExPolygon &ex); +extern std::vector polypartition_output_to_triangles(const std::list &output); + } // namespace Slic3r // start Boost diff --git a/src/libslic3r/TriangleMesh.cpp b/src/libslic3r/TriangleMesh.cpp index ff8c20289..4648b95c0 100644 --- a/src/libslic3r/TriangleMesh.cpp +++ b/src/libslic3r/TriangleMesh.cpp @@ -41,7 +41,7 @@ namespace Slic3r { -TriangleMesh::TriangleMesh(const Pointf3s &points, const std::vector& facets ) +TriangleMesh::TriangleMesh(const Pointf3s &points, const std::vector& facets) : repaired(false) { stl_initialize(&this->stl); diff --git a/src/poly2tri/common/shapes.cc b/src/poly2tri/common/shapes.cc index 54aeaba6a..fe99a8d1a 100644 --- a/src/poly2tri/common/shapes.cc +++ b/src/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,10 +29,16 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "shapes.h" + +#include #include namespace p2t { +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; @@ -150,7 +156,7 @@ void Triangle::Legalize(Point& opoint, Point& npoint) } } -int Triangle::Index(const Point* p) const +int Triangle::Index(const Point* p) { if (p == points_[0]) { return 0; @@ -163,7 +169,7 @@ int Triangle::Index(const Point* p) const return -1; } -int Triangle::EdgeIndex(const Point* p1, const Point* p2) const +int Triangle::EdgeIndex(const Point* p1, const Point* p2) { if (points_[0] == p1) { if (points_[1] == p2) { @@ -259,7 +265,7 @@ Triangle* Triangle::NeighborCCW(const Point& point) return neighbors_[1]; } -bool Triangle::GetConstrainedEdgeCCW(const Point& p) const +bool Triangle::GetConstrainedEdgeCCW(const Point& p) { if (&p == points_[0]) { return constrained_edge[2]; @@ -269,7 +275,7 @@ bool Triangle::GetConstrainedEdgeCCW(const Point& p) const return constrained_edge[1]; } -bool Triangle::GetConstrainedEdgeCW(const Point& p) const +bool Triangle::GetConstrainedEdgeCW(const Point& p) { if (&p == points_[0]) { return constrained_edge[1]; @@ -301,7 +307,7 @@ void Triangle::SetConstrainedEdgeCW(const Point& p, bool ce) } } -bool Triangle::GetDelunayEdgeCCW(const Point& p) const +bool Triangle::GetDelunayEdgeCCW(const Point& p) { if (&p == points_[0]) { return delaunay_edge[2]; @@ -311,7 +317,7 @@ bool Triangle::GetDelunayEdgeCCW(const Point& p) const return delaunay_edge[1]; } -bool Triangle::GetDelunayEdgeCW(const Point& p) const +bool Triangle::GetDelunayEdgeCW(const Point& p) { if (&p == points_[0]) { return delaunay_edge[1]; @@ -356,10 +362,7 @@ Triangle& Triangle::NeighborAcross(const Point& opoint) void Triangle::DebugPrint() { - 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; + std::cout << *points_[0] << " " << *points_[1] << " " << *points_[2] << std::endl; } -} \ No newline at end of file +} diff --git a/src/poly2tri/common/shapes.h b/src/poly2tri/common/shapes.h index 3b8a5247e..7f0b1e76a 100644 --- a/src/poly2tri/common/shapes.h +++ b/src/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. * @@ -33,10 +33,10 @@ #ifndef SHAPES_H #define SHAPES_H -#include -#include -#include #include +#include +#include +#include namespace p2t { @@ -119,6 +119,8 @@ struct Point { }; +std::ostream& operator<<(std::ostream&, const Point&); + // Represents a simple polygon's edge struct Edge { @@ -130,13 +132,13 @@ struct Edge { if (p1.y > p2.y) { q = &p1; p = &p2; - } else if (p1.y == p2.y) { + } else if (std::abs(p1.y - p2.y) < 1e-10) { if (p1.x > p2.x) { q = &p1; p = &p2; - } else if (p1.x == p2.x) { + } else if (std::abs(p1.x - p2.x) < 1e-10) { // Repeat points - assert(false); + throw std::runtime_error("Edge::Edge: p1 == p2"); } } @@ -171,23 +173,23 @@ void MarkConstrainedEdge(int index); void MarkConstrainedEdge(Edge& edge); void MarkConstrainedEdge(Point* p, Point* q); -int Index(const Point* p) const; -int EdgeIndex(const Point* p1, const Point* p2) const; +int Index(const Point* p); +int EdgeIndex(const Point* p1, const Point* p2); Triangle* NeighborCW(const Point& point); Triangle* NeighborCCW(const Point& point); -bool GetConstrainedEdgeCCW(const Point& p) const; -bool GetConstrainedEdgeCW(const Point& p) const; +bool GetConstrainedEdgeCCW(const Point& p); +bool GetConstrainedEdgeCW(const Point& p); void SetConstrainedEdgeCCW(const Point& p, bool ce); void SetConstrainedEdgeCW(const Point& p, bool ce); -bool GetDelunayEdgeCCW(const Point& p) const; -bool GetDelunayEdgeCW(const Point& p) const; +bool GetDelunayEdgeCCW(const Point& p); +bool GetDelunayEdgeCW(const Point& p); void SetDelunayEdgeCCW(const Point& p, bool e); void SetDelunayEdgeCW(const Point& p, bool e); -bool Contains(const Point* p) const; -bool Contains(const Edge& e) const; -bool Contains(const Point* p, const Point* q) const; +bool Contains(const Point* p); +bool Contains(const Edge& e); +bool Contains(const Point* p, const Point* q); void Legalize(Point& point); void Legalize(Point& opoint, Point& npoint); /** @@ -198,7 +200,7 @@ void ClearNeighbor(const Triangle *triangle); void ClearNeighbors(); void ClearDelunayEdges(); -inline bool IsInterior() const; +inline bool IsInterior(); inline void IsInterior(bool b); Triangle& NeighborAcross(const Point& opoint); @@ -293,22 +295,22 @@ inline Triangle* Triangle::GetNeighbor(int index) return neighbors_[index]; } -inline bool Triangle::Contains(const Point* p) const +inline bool Triangle::Contains(const Point* p) { return p == points_[0] || p == points_[1] || p == points_[2]; } -inline bool Triangle::Contains(const Edge& e) const +inline bool Triangle::Contains(const Edge& e) { return Contains(e.p) && Contains(e.q); } -inline bool Triangle::Contains(const Point* p, const Point* q) const +inline bool Triangle::Contains(const Point* p, const Point* q) { return Contains(p) && Contains(q); } -inline bool Triangle::IsInterior() const +inline bool Triangle::IsInterior() { return interior_; } @@ -320,4 +322,4 @@ inline void Triangle::IsInterior(bool b) } -#endif \ No newline at end of file +#endif diff --git a/src/poly2tri/common/utils.h b/src/poly2tri/common/utils.h index 4bcb76361..9a9e14a8a 100644 --- a/src/poly2tri/common/utils.h +++ b/src/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. * @@ -34,11 +34,18 @@ // Otherwise #defines like M_PI are undeclared under Visual Studio #ifndef _USE_MATH_DEFINES - #define _USE_MATH_DEFINES + #define _USE_MATH_DEFINES #endif /* _USE_MATH_DEFINES */ +#include "shapes.h" + +#include #include -#include + +// C99 removes M_PI from math.h +#ifndef M_PI +#define M_PI 3.14159265358979323846264338327 +#endif namespace p2t { @@ -121,4 +128,4 @@ bool InScanArea(const Point& pa, const Point& pb, const Point& pc, const Point& } -#endif \ No newline at end of file +#endif diff --git a/src/poly2tri/poly2tri.h b/src/poly2tri/poly2tri.h index 29a08d052..c959d131f 100644 --- a/src/poly2tri/poly2tri.h +++ b/src/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. * @@ -35,4 +35,4 @@ #include "common/shapes.h" #include "sweep/cdt.h" -#endif \ No newline at end of file +#endif diff --git a/src/poly2tri/sweep/advancing_front.cc b/src/poly2tri/sweep/advancing_front.cc index 38723beef..66e2a5d0d 100644 --- a/src/poly2tri/sweep/advancing_front.cc +++ b/src/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 + namespace p2t { AdvancingFront::AdvancingFront(Node& head, Node& tail) @@ -105,4 +107,4 @@ AdvancingFront::~AdvancingFront() { } -} \ No newline at end of file +} diff --git a/src/poly2tri/sweep/advancing_front.h b/src/poly2tri/sweep/advancing_front.h index 645dcec97..3de070824 100644 --- a/src/poly2tri/sweep/advancing_front.h +++ b/src/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. * @@ -115,4 +115,4 @@ inline void AdvancingFront::set_search(Node* node) } -#endif \ No newline at end of file +#endif diff --git a/src/poly2tri/sweep/cdt.cc b/src/poly2tri/sweep/cdt.cc index 09d088ae3..8496aa1da 100644 --- a/src/poly2tri/sweep/cdt.cc +++ b/src/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-2018, Poly2Tri Contributors + * https://github.com/jhasse/poly2tri * * All rights reserved. * @@ -68,4 +68,4 @@ CDT::~CDT() delete sweep_; } -} \ No newline at end of file +} diff --git a/src/poly2tri/sweep/cdt.h b/src/poly2tri/sweep/cdt.h index ea3286d9a..efeeda388 100644 --- a/src/poly2tri/sweep/cdt.h +++ b/src/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. * @@ -102,4 +102,4 @@ public: } -#endif \ No newline at end of file +#endif diff --git a/src/poly2tri/sweep/sweep.cc b/src/poly2tri/sweep/sweep.cc index 8d2b576e8..45aa1db3b 100644 --- a/src/poly2tri/sweep/sweep.cc +++ b/src/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,19 +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 #include "sweep.h" #include "sweep_context.h" #include "advancing_front.h" #include "../common/utils.h" +#include +#include + 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 @@ -699,13 +701,6 @@ void Sweep::FlipEdgeEvent(SweepContext& tcx, Point& ep, Point& eq, Triangle* t, Triangle& ot = t->NeighborAcross(p); Point& op = *ot.OppositePoint(*t, p); - if (&ot == NULL) { - // If we want to integrate the fillEdgeEvent do it here - // With current implementation we should never get here - //throw new RuntimeException( "[BUG:FIXME] FLIP failed due to missing triangle"); - assert(0); - } - if (InScanArea(p, *t->PointCCW(p), *t->PointCW(p), op)) { // Lets rotate shared edge one vertex CW RotateTrianglePair(*t, p, ot, op); @@ -772,13 +767,6 @@ void Sweep::FlipScanEdgeEvent(SweepContext& tcx, Point& ep, Point& eq, Triangle& Triangle& ot = t.NeighborAcross(p); Point& op = *ot.OppositePoint(t, p); - if (&t.NeighborAcross(p) == NULL) { - // If we want to integrate the fillEdgeEvent do it here - // With current implementation we should never get here - //throw new RuntimeException( "[BUG:FIXME] FLIP failed due to missing triangle"); - assert(0); - } - if (InScanArea(eq, *flip_triangle.PointCCW(eq), *flip_triangle.PointCW(eq), op)) { // flip with new edge op->eq FlipEdgeEvent(tcx, eq, op, &ot, op); diff --git a/src/poly2tri/sweep/sweep.h b/src/poly2tri/sweep/sweep.h index 33e34a714..ccf4ef7b0 100644 --- a/src/poly2tri/sweep/sweep.h +++ b/src/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. * @@ -282,4 +282,4 @@ private: } -#endif \ No newline at end of file +#endif diff --git a/src/poly2tri/sweep/sweep_context.cc b/src/poly2tri/sweep/sweep_context.cc index a9f1fdf8e..4a220dc82 100644 --- a/src/poly2tri/sweep/sweep_context.cc +++ b/src/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-2018, Poly2Tri Contributors + * https://github.com/jhasse/poly2tri * * All rights reserved. * @@ -120,10 +120,9 @@ Node& SweepContext::LocateNode(const Point& point) return *front_->LocateNode(point.x); } -void SweepContext::CreateAdvancingFront(const std::vector& nodes) +void SweepContext::CreateAdvancingFront() { - (void) nodes; // Initial triangle Triangle* triangle = new Triangle(*points_[0], *tail_, *head_); @@ -169,8 +168,8 @@ void SweepContext::MeshClean(Triangle& triangle) triangles.push_back(&triangle); while(!triangles.empty()){ - Triangle *t = triangles.back(); - triangles.pop_back(); + Triangle *t = triangles.back(); + triangles.pop_back(); if (t != NULL && !t->IsInterior()) { t->IsInterior(true); diff --git a/src/poly2tri/sweep/sweep_context.h b/src/poly2tri/sweep/sweep_context.h index ba0d06581..b6bc1cd82 100644 --- a/src/poly2tri/sweep/sweep_context.h +++ b/src/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-2018, Poly2Tri Contributors + * https://github.com/jhasse/poly2tri * * All rights reserved. * @@ -70,7 +70,7 @@ Node& LocateNode(const Point& point); void RemoveNode(Node* node); -void CreateAdvancingFront(const std::vector& nodes); +void CreateAdvancingFront(); /// Try to map a node to all sides of this triangle that don't have a neighbor void MapTriangleToNodes(Triangle& t); diff --git a/src/polypartition/polypartition.cpp b/src/polypartition/polypartition.cpp index 9c5917251..c1d6a4c83 100644 --- a/src/polypartition/polypartition.cpp +++ b/src/polypartition/polypartition.cpp @@ -25,6 +25,8 @@ #include #include #include +#include +#include using namespace std; @@ -66,21 +68,26 @@ void TPPLPoly::Triangle(TPPLPoint &p1, TPPLPoint &p2, TPPLPoint &p3) { points[2] = p3; } -TPPLPoly::TPPLPoly(const TPPLPoly &src) { +TPPLPoly::TPPLPoly(const TPPLPoly &src) : TPPLPoly() { hole = src.hole; numpoints = src.numpoints; - points = new TPPLPoint[numpoints]; - memcpy(points, src.points, numpoints*sizeof(TPPLPoint)); -} -TPPLPoly& TPPLPoly::operator=(const TPPLPoly &src) { - if(&src != this) { - Clear(); - hole = src.hole; - numpoints = src.numpoints; + if(numpoints > 0) { points = new TPPLPoint[numpoints]; memcpy(points, src.points, numpoints*sizeof(TPPLPoint)); } +} + +TPPLPoly& TPPLPoly::operator=(const TPPLPoly &src) { + Clear(); + hole = src.hole; + numpoints = src.numpoints; + + if(numpoints > 0) { + points = new TPPLPoint[numpoints]; + memcpy(points, src.points, numpoints*sizeof(TPPLPoint)); + } + return *this; } @@ -105,16 +112,11 @@ void TPPLPoly::SetOrientation(int orientation) { } void TPPLPoly::Invert() { - long i; - TPPLPoint *invpoints; + std::reverse(points, points + numpoints); +} - invpoints = new TPPLPoint[numpoints]; - for(i=0;i *inpolys, list *outpolys) { - list polys; - list::iterator holeiter,polyiter,iter,iter2; - long i,i2,holepointindex,polypointindex = 0; +int TPPLPartition::RemoveHoles(TPPLPolyList *inpolys, TPPLPolyList *outpolys) { + TPPLPolyList polys; + TPPLPolyList::iterator holeiter,polyiter,iter,iter2; + long i,i2,holepointindex,polypointindex; TPPLPoint holepoint,polypoint,bestpolypoint; TPPLPoint linep1,linep2; TPPLPoint v1,v2; @@ -183,14 +185,14 @@ int TPPLPartition::RemoveHoles(list *inpolys, list *outpolys //check for trivial case (no holes) hasholes = false; - for(iter = inpolys->begin(); iter!=inpolys->end(); ++iter) { + for(iter = inpolys->begin(); iter!=inpolys->end(); iter++) { if(iter->IsHole()) { hasholes = true; break; } } if(!hasholes) { - for(iter = inpolys->begin(); iter!=inpolys->end(); ++iter) { + for(iter = inpolys->begin(); iter!=inpolys->end(); iter++) { outpolys->push_back(*iter); } return 1; @@ -201,7 +203,7 @@ int TPPLPartition::RemoveHoles(list *inpolys, list *outpolys while(1) { //find the hole point with the largest x hasholes = false; - for(iter = polys.begin(); iter!=polys.end(); ++iter) { + for(iter = polys.begin(); iter!=polys.end(); iter++) { if(!iter->IsHole()) continue; if(!hasholes) { @@ -221,7 +223,7 @@ int TPPLPartition::RemoveHoles(list *inpolys, list *outpolys holepoint = holeiter->GetPoint(holepointindex); pointfound = false; - for(iter = polys.begin(); iter!=polys.end(); ++iter) { + for(iter = polys.begin(); iter!=polys.end(); iter++) { if(iter->IsHole()) continue; for(i=0; i < iter->GetNumPoints(); i++) { if(iter->GetPoint(i).x <= holepoint.x) continue; @@ -237,7 +239,7 @@ int TPPLPartition::RemoveHoles(list *inpolys, list *outpolys if(v2.x > v1.x) continue; } pointvisible = true; - for(iter2 = polys.begin(); iter2!=polys.end(); ++iter2) { + for(iter2 = polys.begin(); iter2!=polys.end(); iter2++) { if(iter2->IsHole()) continue; for(i2=0; i2 < iter2->GetNumPoints(); i2++) { linep1 = iter2->GetPoint(i2); @@ -280,7 +282,7 @@ int TPPLPartition::RemoveHoles(list *inpolys, list *outpolys polys.push_back(newpoly); } - for(iter = polys.begin(); iter!=polys.end(); ++iter) { + for(iter = polys.begin(); iter!=polys.end(); iter++) { outpolys->push_back(*iter); } @@ -335,7 +337,7 @@ bool TPPLPartition::InCone(PartitionVertex *v, TPPLPoint &p) { } void TPPLPartition::UpdateVertexReflexity(PartitionVertex *v) { - PartitionVertex *v1,*v3; + PartitionVertex *v1 = NULL,*v3 = NULL; v1 = v->previous; v3 = v->next; v->isConvex = !IsReflex(v1->p,v->p,v3->p); @@ -343,7 +345,7 @@ void TPPLPartition::UpdateVertexReflexity(PartitionVertex *v) { void TPPLPartition::UpdateVertex(PartitionVertex *v, PartitionVertex *vertices, long numvertices) { long i; - PartitionVertex *v1,*v3; + PartitionVertex *v1 = NULL,*v3 = NULL; TPPLPoint vec1,vec3; v1 = v->previous; @@ -372,10 +374,12 @@ void TPPLPartition::UpdateVertex(PartitionVertex *v, PartitionVertex *vertices, } //triangulation by ear removal -int TPPLPartition::Triangulate_EC(TPPLPoly *poly, list *triangles) { +int TPPLPartition::Triangulate_EC(TPPLPoly *poly, TPPLPolyList *triangles) { + if(!poly->Valid()) return 0; + long numvertices; - PartitionVertex *vertices; - PartitionVertex *ear; + PartitionVertex *vertices = NULL; + PartitionVertex *ear = NULL; TPPLPoly triangle; long i,j; bool earfound; @@ -446,21 +450,23 @@ int TPPLPartition::Triangulate_EC(TPPLPoly *poly, list *triangles) { return 1; } -int TPPLPartition::Triangulate_EC(list *inpolys, list *triangles) { - list outpolys; - list::iterator iter; +int TPPLPartition::Triangulate_EC(TPPLPolyList *inpolys, TPPLPolyList *triangles) { + TPPLPolyList outpolys; + TPPLPolyList::iterator iter; if(!RemoveHoles(inpolys,&outpolys)) return 0; - for(iter=outpolys.begin();iter!=outpolys.end();++iter) { + for(iter=outpolys.begin();iter!=outpolys.end();iter++) { if(!Triangulate_EC(&(*iter),triangles)) return 0; } return 1; } -int TPPLPartition::ConvexPartition_HM(TPPLPoly *poly, list *parts) { - list triangles; - list::iterator iter1,iter2; - TPPLPoly *poly1,*poly2; +int TPPLPartition::ConvexPartition_HM(TPPLPoly *poly, TPPLPolyList *parts) { + if(!poly->Valid()) return 0; + + TPPLPolyList triangles; + TPPLPolyList::iterator iter1,iter2; + TPPLPoly *poly1 = NULL,*poly2 = NULL; TPPLPoly newpoly; TPPLPoint d1,d2,p1,p2,p3; long i11,i12,i21,i22,i13,i23,j,k; @@ -486,7 +492,7 @@ int TPPLPartition::ConvexPartition_HM(TPPLPoly *poly, list *parts) { if(!Triangulate_EC(poly,&triangles)) return 0; - for(iter1 = triangles.begin(); iter1 != triangles.end(); ++iter1) { + for(iter1 = triangles.begin(); iter1 != triangles.end(); iter1++) { poly1 = &(*iter1); for(i11=0;i11GetNumPoints();i11++) { d1 = poly1->GetPoint(i11); @@ -494,7 +500,7 @@ int TPPLPartition::ConvexPartition_HM(TPPLPoly *poly, list *parts) { d2 = poly1->GetPoint(i12); isdiagonal = false; - for(iter2 = iter1; iter2 != triangles.end(); ++iter2) { + for(iter2 = iter1; iter2 != triangles.end(); iter2++) { if(iter1 == iter2) continue; poly2 = &(*iter2); @@ -550,19 +556,19 @@ int TPPLPartition::ConvexPartition_HM(TPPLPoly *poly, list *parts) { } } - for(iter1 = triangles.begin(); iter1 != triangles.end(); ++iter1) { + for(iter1 = triangles.begin(); iter1 != triangles.end(); iter1++) { parts->push_back(*iter1); } return 1; } -int TPPLPartition::ConvexPartition_HM(list *inpolys, list *parts) { - list outpolys; - list::iterator iter; +int TPPLPartition::ConvexPartition_HM(TPPLPolyList *inpolys, TPPLPolyList *parts) { + TPPLPolyList outpolys; + TPPLPolyList::iterator iter; if(!RemoveHoles(inpolys,&outpolys)) return 0; - for(iter=outpolys.begin();iter!=outpolys.end();++iter) { + for(iter=outpolys.begin();iter!=outpolys.end();iter++) { if(!ConvexPartition_HM(&(*iter),parts)) return 0; } return 1; @@ -571,14 +577,16 @@ int TPPLPartition::ConvexPartition_HM(list *inpolys, list *p //minimum-weight polygon triangulation by dynamic programming //O(n^3) time complexity //O(n^2) space complexity -int TPPLPartition::Triangulate_OPT(TPPLPoly *poly, list *triangles) { +int TPPLPartition::Triangulate_OPT(TPPLPoly *poly, TPPLPolyList *triangles) { + if(!poly->Valid()) return 0; + long i,j,k,gap,n; - DPState **dpstates; + DPState **dpstates = NULL; TPPLPoint p1,p2,p3,p4; long bestvertex; tppl_float weight,minweight,d1,d2; Diagonal diagonal,newdiagonal; - list diagonals; + DiagonalList diagonals; TPPLPoly triangle; int ret = 1; @@ -703,7 +711,7 @@ int TPPLPartition::Triangulate_OPT(TPPLPoly *poly, list *triangles) { void TPPLPartition::UpdateState(long a, long b, long w, long i, long j, DPState2 **dpstates) { Diagonal newdiagonal; - list *pairs; + DiagonalList *pairs = NULL; long w2; w2 = dpstates[a][b].weight; @@ -725,8 +733,8 @@ void TPPLPartition::UpdateState(long a, long b, long w, long i, long j, DPState2 } void TPPLPartition::TypeA(long i, long j, long k, PartitionVertex *vertices, DPState2 **dpstates) { - list *pairs; - list::iterator iter,lastiter; + DiagonalList *pairs = NULL; + DiagonalList::iterator iter,lastiter; long top; long w; @@ -742,7 +750,7 @@ void TPPLPartition::TypeA(long i, long j, long k, PartitionVertex *vertices, DPS iter = pairs->end(); lastiter = pairs->end(); while(iter!=pairs->begin()) { - --iter; + iter--; if(!IsReflex(vertices[iter->index2].p,vertices[j].p,vertices[k].p)) lastiter = iter; else break; } @@ -756,8 +764,8 @@ void TPPLPartition::TypeA(long i, long j, long k, PartitionVertex *vertices, DPS } void TPPLPartition::TypeB(long i, long j, long k, PartitionVertex *vertices, DPState2 **dpstates) { - list *pairs; - list::iterator iter,lastiter; + DiagonalList *pairs = NULL; + DiagonalList::iterator iter,lastiter; long top; long w; @@ -778,7 +786,7 @@ void TPPLPartition::TypeB(long i, long j, long k, PartitionVertex *vertices, DPS while(iter!=pairs->end()) { if(!IsReflex(vertices[i].p,vertices[j].p,vertices[iter->index1].p)) { lastiter = iter; - ++iter; + iter++; } else break; } @@ -789,19 +797,21 @@ void TPPLPartition::TypeB(long i, long j, long k, PartitionVertex *vertices, DPS UpdateState(i,k,w,j,top,dpstates); } -int TPPLPartition::ConvexPartition_OPT(TPPLPoly *poly, list *parts) { +int TPPLPartition::ConvexPartition_OPT(TPPLPoly *poly, TPPLPolyList *parts) { + if(!poly->Valid()) return 0; + TPPLPoint p1,p2,p3,p4; - PartitionVertex *vertices; - DPState2 **dpstates; + PartitionVertex *vertices = NULL; + DPState2 **dpstates = NULL; long i,j,k,n,gap; - list diagonals,diagonals2; + DiagonalList diagonals,diagonals2; Diagonal diagonal,newdiagonal; - list *pairs,*pairs2; - list::iterator iter,iter2; + DiagonalList *pairs = NULL,*pairs2 = NULL; + DiagonalList::iterator iter,iter2; int ret; TPPLPoly newpoly; - list indices; - list::iterator iiter; + vector indices; + vector::iterator iiter; bool ijreal,jkreal; n = poly->GetNumPoints(); @@ -919,7 +929,7 @@ int TPPLPartition::ConvexPartition_OPT(TPPLPoly *poly, list *parts) { } if(!vertices[diagonal.index1].isConvex) { iter = pairs->end(); - --iter; + iter--; j = iter->index2; newdiagonal.index1 = j; newdiagonal.index2 = diagonal.index2; @@ -933,7 +943,7 @@ int TPPLPartition::ConvexPartition_OPT(TPPLPoly *poly, list *parts) { break; } iter2 = pairs2->end(); - --iter2; + iter2--; if(iter->index1 != iter2->index1) pairs2->pop_back(); else break; } @@ -1003,7 +1013,7 @@ int TPPLPartition::ConvexPartition_OPT(TPPLPoly *poly, list *parts) { pairs = &(dpstates[diagonal.index1][diagonal.index2].pairs); if(!vertices[diagonal.index1].isConvex) { iter = pairs->end(); - --iter; + iter--; j = iter->index2; if(iter->index1 != iter->index2) ijreal = false; } else { @@ -1031,10 +1041,10 @@ int TPPLPartition::ConvexPartition_OPT(TPPLPoly *poly, list *parts) { indices.push_back(j); } - indices.sort(); + std::sort(indices.begin(), indices.end()); newpoly.Init((long)indices.size()); k=0; - for(iiter = indices.begin();iiter!=indices.end(); ++iiter) { + for(iiter = indices.begin();iiter!=indices.end();iiter++) { newpoly[k] = vertices[*iiter].p; k++; } @@ -1055,18 +1065,19 @@ int TPPLPartition::ConvexPartition_OPT(TPPLPoly *poly, list *parts) { //the algorithm used here is outlined in the book //"Computational Geometry: Algorithms and Applications" //by Mark de Berg, Otfried Cheong, Marc van Kreveld and Mark Overmars -int TPPLPartition::MonotonePartition(list *inpolys, list *monotonePolys) { - list::iterator iter; - MonotoneVertex *vertices; +int TPPLPartition::MonotonePartition(TPPLPolyList *inpolys, TPPLPolyList *monotonePolys) { + TPPLPolyList::iterator iter; + MonotoneVertex *vertices = NULL; long i,numvertices,vindex,vindex2,newnumvertices,maxnumvertices; long polystartindex, polyendindex; - TPPLPoly *poly; - MonotoneVertex *v,*v2,*vprev,*vnext; + TPPLPoly *poly = NULL; + MonotoneVertex *v = NULL,*v2 = NULL,*vprev = NULL,*vnext = NULL; ScanLineEdge newedge; bool error = false; numvertices = 0; - for(iter = inpolys->begin(); iter != inpolys->end(); ++iter) { + for(iter = inpolys->begin(); iter != inpolys->end(); iter++) { + if(!iter->Valid()) return 0; numvertices += iter->GetNumPoints(); } @@ -1075,7 +1086,7 @@ int TPPLPartition::MonotonePartition(list *inpolys, list *mo newnumvertices = numvertices; polystartindex = 0; - for(iter = inpolys->begin(); iter != inpolys->end(); ++iter) { + for(iter = inpolys->begin(); iter != inpolys->end(); iter++) { poly = &(*iter); polyendindex = polystartindex + poly->GetNumPoints()-1; for(i=0;iGetNumPoints();i++) { @@ -1130,6 +1141,7 @@ int TPPLPartition::MonotonePartition(list *inpolys, list *mo set::iterator *edgeTreeIterators,edgeIter; edgeTreeIterators = new set::iterator[maxnumvertices]; pair::iterator,bool> edgeTreeRet; + for(i = 0; i *inpolys, list *mo break; case TPPL_VERTEXTYPE_END: + if (edgeTreeIterators[v->previous] == edgeTree.end()) { + error = true; + break; + } //if helper(ei-1) is a merge vertex if(vertextypes[helpers[v->previous]]==TPPL_VERTEXTYPE_MERGE) { //Insert the diagonal connecting vi to helper(ei-1) in D. - AddDiagonal(vertices,&newnumvertices,vindex,helpers[v->previous]); - vertextypes[newnumvertices-2] = vertextypes[vindex]; - edgeTreeIterators[newnumvertices-2] = edgeTreeIterators[vindex]; - helpers[newnumvertices-2] = helpers[vindex]; - vertextypes[newnumvertices-1] = vertextypes[helpers[v->previous]]; - edgeTreeIterators[newnumvertices-1] = edgeTreeIterators[helpers[v->previous]]; - helpers[newnumvertices-1] = helpers[helpers[v->previous]]; + AddDiagonal(vertices,&newnumvertices,vindex,helpers[v->previous], + vertextypes, edgeTreeIterators, &edgeTree, helpers); } //Delete ei-1 from T edgeTree.erase(edgeTreeIterators[v->previous]); @@ -1176,15 +1187,10 @@ int TPPLPartition::MonotonePartition(list *inpolys, list *mo error = true; break; } - --edgeIter; + edgeIter--; //Insert the diagonal connecting vi to helper(ej) in D. - AddDiagonal(vertices,&newnumvertices,vindex,helpers[edgeIter->index]); - vertextypes[newnumvertices-2] = vertextypes[vindex]; - edgeTreeIterators[newnumvertices-2] = edgeTreeIterators[vindex]; - helpers[newnumvertices-2] = helpers[vindex]; - vertextypes[newnumvertices-1] = vertextypes[helpers[edgeIter->index]]; - edgeTreeIterators[newnumvertices-1] = edgeTreeIterators[helpers[edgeIter->index]]; - helpers[newnumvertices-1] = helpers[helpers[edgeIter->index]]; + AddDiagonal(vertices,&newnumvertices,vindex,helpers[edgeIter->index], + vertextypes, edgeTreeIterators, &edgeTree, helpers); vindex2 = newnumvertices-2; v2 = &(vertices[vindex2]); //helper(e j)�vi @@ -1199,16 +1205,15 @@ int TPPLPartition::MonotonePartition(list *inpolys, list *mo break; case TPPL_VERTEXTYPE_MERGE: + if (edgeTreeIterators[v->previous] == edgeTree.end()) { + error = true; + break; + } //if helper(ei-1) is a merge vertex if(vertextypes[helpers[v->previous]]==TPPL_VERTEXTYPE_MERGE) { //Insert the diagonal connecting vi to helper(ei-1) in D. - AddDiagonal(vertices,&newnumvertices,vindex,helpers[v->previous]); - vertextypes[newnumvertices-2] = vertextypes[vindex]; - edgeTreeIterators[newnumvertices-2] = edgeTreeIterators[vindex]; - helpers[newnumvertices-2] = helpers[vindex]; - vertextypes[newnumvertices-1] = vertextypes[helpers[v->previous]]; - edgeTreeIterators[newnumvertices-1] = edgeTreeIterators[helpers[v->previous]]; - helpers[newnumvertices-1] = helpers[helpers[v->previous]]; + AddDiagonal(vertices,&newnumvertices,vindex,helpers[v->previous], + vertextypes, edgeTreeIterators, &edgeTree, helpers); vindex2 = newnumvertices-2; v2 = &(vertices[vindex2]); } @@ -1222,17 +1227,12 @@ int TPPLPartition::MonotonePartition(list *inpolys, list *mo error = true; break; } - --edgeIter; + edgeIter--; //if helper(ej) is a merge vertex if(vertextypes[helpers[edgeIter->index]]==TPPL_VERTEXTYPE_MERGE) { //Insert the diagonal connecting vi to helper(e j) in D. - AddDiagonal(vertices,&newnumvertices,vindex2,helpers[edgeIter->index]); - vertextypes[newnumvertices-2] = vertextypes[vindex2]; - edgeTreeIterators[newnumvertices-2] = edgeTreeIterators[vindex2]; - helpers[newnumvertices-2] = helpers[vindex2]; - vertextypes[newnumvertices-1] = vertextypes[helpers[edgeIter->index]]; - edgeTreeIterators[newnumvertices-1] = edgeTreeIterators[helpers[edgeIter->index]]; - helpers[newnumvertices-1] = helpers[helpers[edgeIter->index]]; + AddDiagonal(vertices,&newnumvertices,vindex2,helpers[edgeIter->index], + vertextypes, edgeTreeIterators, &edgeTree, helpers); } //helper(e j)�vi helpers[edgeIter->index] = vindex2; @@ -1241,16 +1241,15 @@ int TPPLPartition::MonotonePartition(list *inpolys, list *mo case TPPL_VERTEXTYPE_REGULAR: //if the interior of P lies to the right of vi if(Below(v->p,vertices[v->previous].p)) { + if (edgeTreeIterators[v->previous] == edgeTree.end()) { + error = true; + break; + } //if helper(ei-1) is a merge vertex if(vertextypes[helpers[v->previous]]==TPPL_VERTEXTYPE_MERGE) { //Insert the diagonal connecting vi to helper(ei-1) in D. - AddDiagonal(vertices,&newnumvertices,vindex,helpers[v->previous]); - vertextypes[newnumvertices-2] = vertextypes[vindex]; - edgeTreeIterators[newnumvertices-2] = edgeTreeIterators[vindex]; - helpers[newnumvertices-2] = helpers[vindex]; - vertextypes[newnumvertices-1] = vertextypes[helpers[v->previous]]; - edgeTreeIterators[newnumvertices-1] = edgeTreeIterators[helpers[v->previous]]; - helpers[newnumvertices-1] = helpers[helpers[v->previous]]; + AddDiagonal(vertices,&newnumvertices,vindex,helpers[v->previous], + vertextypes, edgeTreeIterators, &edgeTree, helpers); vindex2 = newnumvertices-2; v2 = &(vertices[vindex2]); } @@ -1272,17 +1271,12 @@ int TPPLPartition::MonotonePartition(list *inpolys, list *mo error = true; break; } - --edgeIter; + edgeIter--; //if helper(ej) is a merge vertex if(vertextypes[helpers[edgeIter->index]]==TPPL_VERTEXTYPE_MERGE) { //Insert the diagonal connecting vi to helper(e j) in D. - AddDiagonal(vertices,&newnumvertices,vindex,helpers[edgeIter->index]); - vertextypes[newnumvertices-2] = vertextypes[vindex]; - edgeTreeIterators[newnumvertices-2] = edgeTreeIterators[vindex]; - helpers[newnumvertices-2] = helpers[vindex]; - vertextypes[newnumvertices-1] = vertextypes[helpers[edgeIter->index]]; - edgeTreeIterators[newnumvertices-1] = edgeTreeIterators[helpers[edgeIter->index]]; - helpers[newnumvertices-1] = helpers[helpers[edgeIter->index]]; + AddDiagonal(vertices,&newnumvertices,vindex,helpers[edgeIter->index], + vertextypes, edgeTreeIterators, &edgeTree, helpers); } //helper(e j)�vi helpers[edgeIter->index] = vindex; @@ -1342,7 +1336,10 @@ int TPPLPartition::MonotonePartition(list *inpolys, list *mo } //adds a diagonal to the doubly-connected list of vertices -void TPPLPartition::AddDiagonal(MonotoneVertex *vertices, long *numvertices, long index1, long index2) { +void TPPLPartition::AddDiagonal(MonotoneVertex *vertices, long *numvertices, long index1, long index2, + char *vertextypes, set::iterator *edgeTreeIterators, + set *edgeTree, long *helpers) +{ long newindex1,newindex2; newindex1 = *numvertices; @@ -1364,6 +1361,18 @@ void TPPLPartition::AddDiagonal(MonotoneVertex *vertices, long *numvertices, lon vertices[index2].next = newindex1; vertices[newindex1].previous = index2; + + //update all relevant structures + vertextypes[newindex1] = vertextypes[index1]; + edgeTreeIterators[newindex1] = edgeTreeIterators[index1]; + helpers[newindex1] = helpers[index1]; + if(edgeTreeIterators[newindex1] != edgeTree->end()) + edgeTreeIterators[newindex1]->index = newindex1; + vertextypes[newindex2] = vertextypes[index2]; + edgeTreeIterators[newindex2] = edgeTreeIterators[index2]; + helpers[newindex2] = helpers[index2]; + if(edgeTreeIterators[newindex2] != edgeTree->end()) + edgeTreeIterators[newindex2]->index = newindex2; } bool TPPLPartition::Below(TPPLPoint &p1, TPPLPoint &p2) { @@ -1375,7 +1384,7 @@ bool TPPLPartition::Below(TPPLPoint &p1, TPPLPoint &p2) { } //sorts in the falling order of y values, if y is equal, x is used instead -bool TPPLPartition::VertexSorter::operator() (long index1, long index2) const { +bool TPPLPartition::VertexSorter::operator() (long index1, long index2) { if(vertices[index1].p.y > vertices[index2].p.y) return true; else if(vertices[index1].p.y == vertices[index2].p.y) { if(vertices[index1].p.x > vertices[index2].p.x) return true; @@ -1412,19 +1421,21 @@ bool TPPLPartition::ScanLineEdge::operator < (const ScanLineEdge & other) const //triangulates monotone polygon //O(n) time, O(n) space complexity -int TPPLPartition::TriangulateMonotone(TPPLPoly *inPoly, list *triangles) { +int TPPLPartition::TriangulateMonotone(TPPLPoly *inPoly, TPPLPolyList *triangles) { + if(!inPoly->Valid()) return 0; + long i,i2,j,topindex,bottomindex,leftindex,rightindex,vindex; - TPPLPoint *points; + TPPLPoint *points = NULL; long numpoints; TPPLPoly triangle; numpoints = inPoly->GetNumPoints(); points = inPoly->GetPoints(); - //trivial calses - if(numpoints < 3) return 0; + //trivial case if(numpoints == 3) { triangles->push_back(*inPoly); + return 1; } topindex = 0; bottomindex=0; @@ -1544,19 +1555,19 @@ int TPPLPartition::TriangulateMonotone(TPPLPoly *inPoly, list *triangl return 1; } -int TPPLPartition::Triangulate_MONO(list *inpolys, list *triangles) { - list monotone; - list::iterator iter; +int TPPLPartition::Triangulate_MONO(TPPLPolyList *inpolys, TPPLPolyList *triangles) { + TPPLPolyList monotone; + TPPLPolyList::iterator iter; if(!MonotonePartition(inpolys,&monotone)) return 0; - for(iter = monotone.begin(); iter!=monotone.end(); ++iter) { + for(iter = monotone.begin(); iter!=monotone.end();iter++) { if(!TriangulateMonotone(&(*iter),triangles)) return 0; } return 1; } -int TPPLPartition::Triangulate_MONO(TPPLPoly *poly, list *triangles) { - list polys; +int TPPLPartition::Triangulate_MONO(TPPLPoly *poly, TPPLPolyList *triangles) { + TPPLPolyList polys; polys.push_back(*poly); return Triangulate_MONO(&polys, triangles); diff --git a/src/polypartition/polypartition.h b/src/polypartition/polypartition.h index 20ec0e24f..a89873296 100644 --- a/src/polypartition/polypartition.h +++ b/src/polypartition/polypartition.h @@ -18,9 +18,11 @@ //OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN //THE SOFTWARE. +#ifndef POLYPARTITION_H +#define POLYPARTITION_H #include -using namespace std; +#include typedef double tppl_float; @@ -29,315 +31,349 @@ typedef double tppl_float; //2D point structure struct TPPLPoint { - tppl_float x; - tppl_float y; - - TPPLPoint operator + (const TPPLPoint& p) const { - TPPLPoint r; - r.x = x + p.x; - r.y = y + p.y; - return r; - } - - TPPLPoint operator - (const TPPLPoint& p) const { - TPPLPoint r; - r.x = x - p.x; - r.y = y - p.y; - return r; - } - - TPPLPoint operator * (const tppl_float f ) const { - TPPLPoint r; - r.x = x*f; - r.y = y*f; - return r; - } - - TPPLPoint operator / (const tppl_float f ) const { - TPPLPoint r; - r.x = x/f; - r.y = y/f; - return r; - } - - bool operator==(const TPPLPoint& p) const { - if((x == p.x)&&(y==p.y)) return true; - else return false; - } - - bool operator!=(const TPPLPoint& p) const { - if((x == p.x)&&(y==p.y)) return false; - else return true; - } + tppl_float x; + tppl_float y; + // User-specified vertex identifier. Note that this isn't used internally + // by the library, but will be faithfully copied around. + int id; + + TPPLPoint operator + (const TPPLPoint& p) const { + TPPLPoint r; + r.x = x + p.x; + r.y = y + p.y; + return r; + } + + TPPLPoint operator - (const TPPLPoint& p) const { + TPPLPoint r; + r.x = x - p.x; + r.y = y - p.y; + return r; + } + + TPPLPoint operator * (const tppl_float f ) const { + TPPLPoint r; + r.x = x*f; + r.y = y*f; + return r; + } + + TPPLPoint operator / (const tppl_float f ) const { + TPPLPoint r; + r.x = x/f; + r.y = y/f; + return r; + } + + bool operator==(const TPPLPoint& p) const { + if((x == p.x)&&(y==p.y)) return true; + else return false; + } + + bool operator!=(const TPPLPoint& p) const { + if((x == p.x)&&(y==p.y)) return false; + else return true; + } }; + //Polygon implemented as an array of points with a 'hole' flag class TPPLPoly { -protected: + protected: + + TPPLPoint *points; + long numpoints; + bool hole; + + public: + + //constructors/destructors + TPPLPoly(); + ~TPPLPoly(); + + TPPLPoly(const TPPLPoly &src); + TPPLPoly& operator=(const TPPLPoly &src); + + //getters and setters + long GetNumPoints() const { + return numpoints; + } + + bool IsHole() const { + return hole; + } + + void SetHole(bool hole) { + this->hole = hole; + } + + TPPLPoint &GetPoint(long i) { + return points[i]; + } + + const TPPLPoint &GetPoint(long i) const { + return points[i]; + } - TPPLPoint *points; - long numpoints; - bool hole; + TPPLPoint *GetPoints() { + return points; + } + + TPPLPoint& operator[] (int i) { + return points[i]; + } -public: + const TPPLPoint& operator[] (int i) const { + return points[i]; + } + + //clears the polygon points + void Clear(); + + //inits the polygon with numpoints vertices + void Init(long numpoints); + + //creates a triangle with points p1,p2,p3 + void Triangle(TPPLPoint &p1, TPPLPoint &p2, TPPLPoint &p3); + + //inverts the orfer of vertices + void Invert(); + + //returns the orientation of the polygon + //possible values: + // TPPL_CCW : polygon vertices are in counter-clockwise order + // TPPL_CW : polygon vertices are in clockwise order + // 0 : the polygon has no (measurable) area + int GetOrientation() const; + + //sets the polygon orientation + //orientation can be + // TPPL_CCW : sets vertices in counter-clockwise order + // TPPL_CW : sets vertices in clockwise order + void SetOrientation(int orientation); - //constructors/destructors - TPPLPoly(); - ~TPPLPoly(); - - TPPLPoly(const TPPLPoly &src); - TPPLPoly& operator=(const TPPLPoly &src); - - //getters and setters - long GetNumPoints() const { - return numpoints; - } - - bool IsHole() const { - return hole; - } - - void SetHole(bool hole) { - this->hole = hole; - } - - TPPLPoint &GetPoint(long i) { - return points[i]; - } - - TPPLPoint *GetPoints() { - return points; - } - - TPPLPoint& operator[] (int i) { - return points[i]; - } - - //clears the polygon points - void Clear(); - - //inits the polygon with numpoints vertices - void Init(long numpoints); - - //creates a triangle with points p1,p2,p3 - void Triangle(TPPLPoint &p1, TPPLPoint &p2, TPPLPoint &p3); - - //inverts the orfer of vertices - void Invert(); - - //returns the orientation of the polygon - //possible values: - // TPPL_CCW : polygon vertices are in counter-clockwise order - // TPPL_CW : polygon vertices are in clockwise order - // 0 : the polygon has no (measurable) area - int GetOrientation() const; - - //sets the polygon orientation - //orientation can be - // TPPL_CCW : sets vertices in counter-clockwise order - // TPPL_CW : sets vertices in clockwise order - void SetOrientation(int orientation); + //checks whether a polygon is valid or not + inline bool Valid() const { return this->numpoints >= 3; } }; +#ifdef TPPL_ALLOCATOR +typedef std::list TPPLPolyList; +#else +typedef std::list TPPLPolyList; +#endif + class TPPLPartition { -protected: - struct PartitionVertex { - bool isActive; - bool isConvex; - bool isEar; + protected: + struct PartitionVertex { + bool isActive; + bool isConvex; + bool isEar; + + TPPLPoint p; + tppl_float angle; + PartitionVertex *previous; + PartitionVertex *next; + + PartitionVertex(); + }; + + struct MonotoneVertex { + TPPLPoint p; + long previous; + long next; + }; + + class VertexSorter{ + MonotoneVertex *vertices; + public: + VertexSorter(MonotoneVertex *v) : vertices(v) {} + bool operator() (long index1, long index2); + }; + + struct Diagonal { + long index1; + long index2; + }; - TPPLPoint p; - tppl_float angle; - PartitionVertex *previous; - PartitionVertex *next; - }; - - struct MonotoneVertex { - TPPLPoint p; - long previous; - long next; - }; - - class VertexSorter{ - MonotoneVertex *vertices; - public: - VertexSorter(MonotoneVertex *v) : vertices(v) {} - bool operator() (long index1, long index2) const; - }; - - struct Diagonal { - long index1; - long index2; - }; - - //dynamic programming state for minimum-weight triangulation - struct DPState { - bool visible; - tppl_float weight; - long bestvertex; - }; - - //dynamic programming state for convex partitioning - struct DPState2 { - bool visible; - long weight; - list pairs; - }; - - //edge that intersects the scanline - struct ScanLineEdge { - long index; - TPPLPoint p1; - TPPLPoint p2; - - //determines if the edge is to the left of another edge - bool operator< (const ScanLineEdge & other) const; - - bool IsConvex(const TPPLPoint& p1, const TPPLPoint& p2, const TPPLPoint& p3) const; - }; - - //standard helper functions - bool IsConvex(TPPLPoint& p1, TPPLPoint& p2, TPPLPoint& p3); - bool IsReflex(TPPLPoint& p1, TPPLPoint& p2, TPPLPoint& p3); - bool IsInside(TPPLPoint& p1, TPPLPoint& p2, TPPLPoint& p3, TPPLPoint &p); - - bool InCone(TPPLPoint &p1, TPPLPoint &p2, TPPLPoint &p3, TPPLPoint &p); - bool InCone(PartitionVertex *v, TPPLPoint &p); - - int Intersects(TPPLPoint &p11, TPPLPoint &p12, TPPLPoint &p21, TPPLPoint &p22); - - TPPLPoint Normalize(const TPPLPoint &p); - tppl_float Distance(const TPPLPoint &p1, const TPPLPoint &p2); - - //helper functions for Triangulate_EC - void UpdateVertexReflexity(PartitionVertex *v); - void UpdateVertex(PartitionVertex *v,PartitionVertex *vertices, long numvertices); - - //helper functions for ConvexPartition_OPT - void UpdateState(long a, long b, long w, long i, long j, DPState2 **dpstates); - void TypeA(long i, long j, long k, PartitionVertex *vertices, DPState2 **dpstates); - void TypeB(long i, long j, long k, PartitionVertex *vertices, DPState2 **dpstates); - - //helper functions for MonotonePartition - bool Below(TPPLPoint &p1, TPPLPoint &p2); - void AddDiagonal(MonotoneVertex *vertices, long *numvertices, long index1, long index2); - - //triangulates a monotone polygon, used in Triangulate_MONO - int TriangulateMonotone(TPPLPoly *inPoly, list *triangles); - -public: - - //simple heuristic procedure for removing holes from a list of polygons - //works by creating a diagonal from the rightmost hole vertex to some visible vertex - //time complexity: O(h*(n^2)), h is the number of holes, n is the number of vertices - //space complexity: O(n) - //params: - // inpolys : a list of polygons that can contain holes - // vertices of all non-hole polys have to be in counter-clockwise order - // vertices of all hole polys have to be in clockwise order - // outpolys : a list of polygons without holes - //returns 1 on success, 0 on failure - int RemoveHoles(list *inpolys, list *outpolys); - - //triangulates a polygon by ear clipping - //time complexity O(n^2), n is the number of vertices - //space complexity: O(n) - //params: - // poly : an input polygon to be triangulated - // vertices have to be in counter-clockwise order - // triangles : a list of triangles (result) - //returns 1 on success, 0 on failure - int Triangulate_EC(TPPLPoly *poly, list *triangles); - - //triangulates a list of polygons that may contain holes by ear clipping algorithm - //first calls RemoveHoles to get rid of the holes, and then Triangulate_EC for each resulting polygon - //time complexity: O(h*(n^2)), h is the number of holes, n is the number of vertices - //space complexity: O(n) - //params: - // inpolys : a list of polygons to be triangulated (can contain holes) - // vertices of all non-hole polys have to be in counter-clockwise order - // vertices of all hole polys have to be in clockwise order - // triangles : a list of triangles (result) - //returns 1 on success, 0 on failure - int Triangulate_EC(list *inpolys, list *triangles); - - //creates an optimal polygon triangulation in terms of minimal edge length - //time complexity: O(n^3), n is the number of vertices - //space complexity: O(n^2) - //params: - // poly : an input polygon to be triangulated - // vertices have to be in counter-clockwise order - // triangles : a list of triangles (result) - //returns 1 on success, 0 on failure - int Triangulate_OPT(TPPLPoly *poly, list *triangles); - - //triangulates a polygons by firstly partitioning it into monotone polygons - //time complexity: O(n*log(n)), n is the number of vertices - //space complexity: O(n) - //params: - // poly : an input polygon to be triangulated - // vertices have to be in counter-clockwise order - // triangles : a list of triangles (result) - //returns 1 on success, 0 on failure - int Triangulate_MONO(TPPLPoly *poly, list *triangles); - - //triangulates a list of polygons by firstly partitioning them into monotone polygons - //time complexity: O(n*log(n)), n is the number of vertices - //space complexity: O(n) - //params: - // inpolys : a list of polygons to be triangulated (can contain holes) - // vertices of all non-hole polys have to be in counter-clockwise order - // vertices of all hole polys have to be in clockwise order - // triangles : a list of triangles (result) - //returns 1 on success, 0 on failure - int Triangulate_MONO(list *inpolys, list *triangles); - - //creates a monotone partition of a list of polygons that can contain holes - //time complexity: O(n*log(n)), n is the number of vertices - //space complexity: O(n) - //params: - // inpolys : a list of polygons to be triangulated (can contain holes) - // vertices of all non-hole polys have to be in counter-clockwise order - // vertices of all hole polys have to be in clockwise order - // monotonePolys : a list of monotone polygons (result) - //returns 1 on success, 0 on failure - int MonotonePartition(list *inpolys, list *monotonePolys); - - //partitions a polygon into convex polygons by using Hertel-Mehlhorn algorithm - //the algorithm gives at most four times the number of parts as the optimal algorithm - //however, in practice it works much better than that and often gives optimal partition - //uses triangulation obtained by ear clipping as intermediate result - //time complexity O(n^2), n is the number of vertices - //space complexity: O(n) - //params: - // poly : an input polygon to be partitioned - // vertices have to be in counter-clockwise order - // parts : resulting list of convex polygons - //returns 1 on success, 0 on failure - int ConvexPartition_HM(TPPLPoly *poly, list *parts); - - //partitions a list of polygons into convex parts by using Hertel-Mehlhorn algorithm - //the algorithm gives at most four times the number of parts as the optimal algorithm - //however, in practice it works much better than that and often gives optimal partition - //uses triangulation obtained by ear clipping as intermediate result - //time complexity O(n^2), n is the number of vertices - //space complexity: O(n) - //params: - // inpolys : an input list of polygons to be partitioned - // vertices of all non-hole polys have to be in counter-clockwise order - // vertices of all hole polys have to be in clockwise order - // parts : resulting list of convex polygons - //returns 1 on success, 0 on failure - int ConvexPartition_HM(list *inpolys, list *parts); - - //optimal convex partitioning (in terms of number of resulting convex polygons) - //using the Keil-Snoeyink algorithm - //M. Keil, J. Snoeyink, "On the time bound for convex decomposition of simple polygons", 1998 - //time complexity O(n^3), n is the number of vertices - //space complexity: O(n^3) - // poly : an input polygon to be partitioned - // vertices have to be in counter-clockwise order - // parts : resulting list of convex polygons - //returns 1 on success, 0 on failure - int ConvexPartition_OPT(TPPLPoly *poly, list *parts); +#ifdef TPPL_ALLOCATOR + typedef std::list DiagonalList; +#else + typedef std::list DiagonalList; +#endif + + //dynamic programming state for minimum-weight triangulation + struct DPState { + bool visible; + tppl_float weight; + long bestvertex; + }; + + //dynamic programming state for convex partitioning + struct DPState2 { + bool visible; + long weight; + DiagonalList pairs; + }; + + //edge that intersects the scanline + struct ScanLineEdge { + mutable long index; + TPPLPoint p1; + TPPLPoint p2; + + //determines if the edge is to the left of another edge + bool operator< (const ScanLineEdge & other) const; + + bool IsConvex(const TPPLPoint& p1, const TPPLPoint& p2, const TPPLPoint& p3) const; + }; + + //standard helper functions + bool IsConvex(TPPLPoint& p1, TPPLPoint& p2, TPPLPoint& p3); + bool IsReflex(TPPLPoint& p1, TPPLPoint& p2, TPPLPoint& p3); + bool IsInside(TPPLPoint& p1, TPPLPoint& p2, TPPLPoint& p3, TPPLPoint &p); + + bool InCone(TPPLPoint &p1, TPPLPoint &p2, TPPLPoint &p3, TPPLPoint &p); + bool InCone(PartitionVertex *v, TPPLPoint &p); + + int Intersects(TPPLPoint &p11, TPPLPoint &p12, TPPLPoint &p21, TPPLPoint &p22); + + TPPLPoint Normalize(const TPPLPoint &p); + tppl_float Distance(const TPPLPoint &p1, const TPPLPoint &p2); + + //helper functions for Triangulate_EC + void UpdateVertexReflexity(PartitionVertex *v); + void UpdateVertex(PartitionVertex *v,PartitionVertex *vertices, long numvertices); + + //helper functions for ConvexPartition_OPT + void UpdateState(long a, long b, long w, long i, long j, DPState2 **dpstates); + void TypeA(long i, long j, long k, PartitionVertex *vertices, DPState2 **dpstates); + void TypeB(long i, long j, long k, PartitionVertex *vertices, DPState2 **dpstates); + + //helper functions for MonotonePartition + bool Below(TPPLPoint &p1, TPPLPoint &p2); + void AddDiagonal(MonotoneVertex *vertices, long *numvertices, long index1, long index2, + char *vertextypes, std::set::iterator *edgeTreeIterators, + std::set *edgeTree, long *helpers); + + //triangulates a monotone polygon, used in Triangulate_MONO + int TriangulateMonotone(TPPLPoly *inPoly, TPPLPolyList *triangles); + + public: + + //simple heuristic procedure for removing holes from a list of polygons + //works by creating a diagonal from the rightmost hole vertex to some visible vertex + //time complexity: O(h*(n^2)), h is the number of holes, n is the number of vertices + //space complexity: O(n) + //params: + // inpolys : a list of polygons that can contain holes + // vertices of all non-hole polys have to be in counter-clockwise order + // vertices of all hole polys have to be in clockwise order + // outpolys : a list of polygons without holes + //returns 1 on success, 0 on failure + int RemoveHoles(TPPLPolyList *inpolys, TPPLPolyList *outpolys); + + //triangulates a polygon by ear clipping + //time complexity O(n^2), n is the number of vertices + //space complexity: O(n) + //params: + // poly : an input polygon to be triangulated + // vertices have to be in counter-clockwise order + // triangles : a list of triangles (result) + //returns 1 on success, 0 on failure + int Triangulate_EC(TPPLPoly *poly, TPPLPolyList *triangles); + + //triangulates a list of polygons that may contain holes by ear clipping algorithm + //first calls RemoveHoles to get rid of the holes, and then Triangulate_EC for each resulting polygon + //time complexity: O(h*(n^2)), h is the number of holes, n is the number of vertices + //space complexity: O(n) + //params: + // inpolys : a list of polygons to be triangulated (can contain holes) + // vertices of all non-hole polys have to be in counter-clockwise order + // vertices of all hole polys have to be in clockwise order + // triangles : a list of triangles (result) + //returns 1 on success, 0 on failure + int Triangulate_EC(TPPLPolyList *inpolys, TPPLPolyList *triangles); + + //creates an optimal polygon triangulation in terms of minimal edge length + //time complexity: O(n^3), n is the number of vertices + //space complexity: O(n^2) + //params: + // poly : an input polygon to be triangulated + // vertices have to be in counter-clockwise order + // triangles : a list of triangles (result) + //returns 1 on success, 0 on failure + int Triangulate_OPT(TPPLPoly *poly, TPPLPolyList *triangles); + + //triangulates a polygons by firstly partitioning it into monotone polygons + //time complexity: O(n*log(n)), n is the number of vertices + //space complexity: O(n) + //params: + // poly : an input polygon to be triangulated + // vertices have to be in counter-clockwise order + // triangles : a list of triangles (result) + //returns 1 on success, 0 on failure + int Triangulate_MONO(TPPLPoly *poly, TPPLPolyList *triangles); + + //triangulates a list of polygons by firstly partitioning them into monotone polygons + //time complexity: O(n*log(n)), n is the number of vertices + //space complexity: O(n) + //params: + // inpolys : a list of polygons to be triangulated (can contain holes) + // vertices of all non-hole polys have to be in counter-clockwise order + // vertices of all hole polys have to be in clockwise order + // triangles : a list of triangles (result) + //returns 1 on success, 0 on failure + int Triangulate_MONO(TPPLPolyList *inpolys, TPPLPolyList *triangles); + + //creates a monotone partition of a list of polygons that can contain holes + //time complexity: O(n*log(n)), n is the number of vertices + //space complexity: O(n) + //params: + // inpolys : a list of polygons to be triangulated (can contain holes) + // vertices of all non-hole polys have to be in counter-clockwise order + // vertices of all hole polys have to be in clockwise order + // monotonePolys : a list of monotone polygons (result) + //returns 1 on success, 0 on failure + int MonotonePartition(TPPLPolyList *inpolys, TPPLPolyList *monotonePolys); + + //partitions a polygon into convex polygons by using Hertel-Mehlhorn algorithm + //the algorithm gives at most four times the number of parts as the optimal algorithm + //however, in practice it works much better than that and often gives optimal partition + //uses triangulation obtained by ear clipping as intermediate result + //time complexity O(n^2), n is the number of vertices + //space complexity: O(n) + //params: + // poly : an input polygon to be partitioned + // vertices have to be in counter-clockwise order + // parts : resulting list of convex polygons + //returns 1 on success, 0 on failure + int ConvexPartition_HM(TPPLPoly *poly, TPPLPolyList *parts); + + //partitions a list of polygons into convex parts by using Hertel-Mehlhorn algorithm + //the algorithm gives at most four times the number of parts as the optimal algorithm + //however, in practice it works much better than that and often gives optimal partition + //uses triangulation obtained by ear clipping as intermediate result + //time complexity O(n^2), n is the number of vertices + //space complexity: O(n) + //params: + // inpolys : an input list of polygons to be partitioned + // vertices of all non-hole polys have to be in counter-clockwise order + // vertices of all hole polys have to be in clockwise order + // parts : resulting list of convex polygons + //returns 1 on success, 0 on failure + int ConvexPartition_HM(TPPLPolyList *inpolys, TPPLPolyList *parts); + + //optimal convex partitioning (in terms of number of resulting convex polygons) + //using the Keil-Snoeyink algorithm + //M. Keil, J. Snoeyink, "On the time bound for convex decomposition of simple polygons", 1998 + //time complexity O(n^3), n is the number of vertices + //space complexity: O(n^3) + // poly : an input polygon to be partitioned + // vertices have to be in counter-clockwise order + // parts : resulting list of convex polygons + //returns 1 on success, 0 on failure + int ConvexPartition_OPT(TPPLPoly *poly, TPPLPolyList *parts); }; + + +#endif diff --git a/src/slic3r/GUI/3DScene.cpp b/src/slic3r/GUI/3DScene.cpp index a96731e46..d10d9e0eb 100644 --- a/src/slic3r/GUI/3DScene.cpp +++ b/src/slic3r/GUI/3DScene.cpp @@ -1959,7 +1959,7 @@ bool GLBed::on_init_from_file(const std::string& filename, bool useVBOs) { model = Model::read_from_file(filename); } - catch (std::exception &e) + catch (std::exception & /* ex */) { return false; } @@ -1978,7 +1978,7 @@ bool GLBed::on_init_from_file(const std::string& filename, bool useVBOs) else m_volume.indexed_vertex_array.load_mesh_flat_shading(mesh); - float color[4] = { 0.235f, 0.235, 0.235f, 1.0f }; + float color[4] = { 0.235f, 0.235f, 0.235f, 1.0f }; set_color(color, 4); m_volume.bounding_box = m_volume.indexed_vertex_array.bounding_box(); diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 13ece5d13..3b2662d6f 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -2,6 +2,7 @@ #include "GLCanvas3D.hpp" #include "admesh/stl.h" +#include "polypartition.h" #include "libslic3r/libslic3r.h" #include "libslic3r/ClipperUtils.hpp" #include "libslic3r/PrintConfig.hpp" @@ -6431,6 +6432,219 @@ void GLCanvas3D::_render_camera_target() const } #endif // ENABLE_SHOW_CAMERA_TARGET +class TessWrapper { +public: + static Pointf3s tesselate(const ExPolygon &expoly, double z_, bool flipped_) + { + z = z_; + flipped = flipped_; + triangles.clear(); + intersection_points.clear(); + std::vector coords; + { + size_t num_coords = expoly.contour.points.size(); + for (const Polygon &poly : expoly.holes) + num_coords += poly.points.size(); + coords.reserve(num_coords * 3); + } + GLUtesselator *tess = gluNewTess(); // create a tessellator + // register callback functions + gluTessCallback(tess, GLU_TESS_BEGIN, (void(__stdcall*)(void))tessBeginCB); + gluTessCallback(tess, GLU_TESS_END, (void(__stdcall*)(void))tessEndCB); + gluTessCallback(tess, GLU_TESS_ERROR, (void(__stdcall*)(void))tessErrorCB); + gluTessCallback(tess, GLU_TESS_VERTEX, (void(__stdcall*)())tessVertexCB); + gluTessCallback(tess, GLU_TESS_COMBINE, (void (__stdcall*)(void))tessCombineCB); + gluTessBeginPolygon(tess, 0); // with NULL data + gluTessBeginContour(tess); + for (const Point &pt : expoly.contour.points) { + coords.emplace_back(unscale(pt[0])); + coords.emplace_back(unscale(pt[1])); + coords.emplace_back(0.); + gluTessVertex(tess, &coords[coords.size() - 3], &coords[coords.size() - 3]); + } + gluTessEndContour(tess); + for (const Polygon &poly : expoly.holes) { + gluTessBeginContour(tess); + for (const Point &pt : poly.points) { + coords.emplace_back(unscale(pt[0])); + coords.emplace_back(unscale(pt[1])); + coords.emplace_back(0.); + gluTessVertex(tess, &coords[coords.size() - 3], &coords[coords.size() - 3]); + } + gluTessEndContour(tess); + } + gluTessEndPolygon(tess); + gluDeleteTess(tess); + return std::move(triangles); + } + +private: + static void tessBeginCB(GLenum which) + { + assert(which == GL_TRIANGLES || which == GL_TRIANGLE_FAN || which == GL_TRIANGLE_STRIP); + if (!(which == GL_TRIANGLES || which == GL_TRIANGLE_FAN || which == GL_TRIANGLE_STRIP)) + printf("Co je to za haluz!?\n"); + primitive_type = which; + num_points = 0; + } + + static void tessEndCB() + { + num_points = 0; + } + + static void tessVertexCB(const GLvoid *data) + { + if (data == nullptr) + return; + const GLdouble *ptr = (const GLdouble*)data; + ++ num_points; + if (num_points == 1) { + memcpy(pt0, ptr, sizeof(GLdouble) * 3); + } else if (num_points == 2) { + memcpy(pt1, ptr, sizeof(GLdouble) * 3); + } else { + bool flip = flipped; + if (primitive_type == GL_TRIANGLE_STRIP && num_points == 4) { + flip = !flip; + num_points = 2; + } + triangles.emplace_back(pt0[0], pt0[1], z); + if (flip) { + triangles.emplace_back(ptr[0], ptr[1], z); + triangles.emplace_back(pt1[0], pt1[1], z); + } else { + triangles.emplace_back(pt1[0], pt1[1], z); + triangles.emplace_back(ptr[0], ptr[1], z); + } + if (primitive_type == GL_TRIANGLE_STRIP) { + memcpy(pt0, pt1, sizeof(GLdouble) * 3); + memcpy(pt1, ptr, sizeof(GLdouble) * 3); + } else if (primitive_type == GL_TRIANGLE_FAN) { + memcpy(pt1, ptr, sizeof(GLdouble) * 3); + } else { + assert(which == GL_TRIANGLES); + assert(num_points == 3); + num_points = 0; + } + } + } + + static void tessCombineCB(const GLdouble newVertex[3], const GLdouble *neighborVertex[4], const GLfloat neighborWeight[4], GLdouble **outData) + { + intersection_points.emplace_back(newVertex[0], newVertex[1], newVertex[2]); + *outData = intersection_points.back().data(); + } + + static void tessErrorCB(GLenum errorCode) + { + const GLubyte *errorStr; + errorStr = gluErrorString(errorCode); + printf("Error: %s\n", (const char*)errorStr); + } + + static GLenum primitive_type; + static GLdouble pt0[3]; + static GLdouble pt1[3]; + static int num_points; + static Pointf3s triangles; + static std::deque intersection_points; + static double z; + static bool flipped; +}; + +GLenum TessWrapper::primitive_type; +GLdouble TessWrapper::pt0[3]; +GLdouble TessWrapper::pt1[3]; +int TessWrapper::num_points; +Pointf3s TessWrapper::triangles; +std::deque TessWrapper::intersection_points; +double TessWrapper::z; +bool TessWrapper::flipped; + +static Pointf3s triangulate_expolygons(const ExPolygons &polys, coordf_t z, bool flip) +{ + Pointf3s triangles; +#if 0 + for (const ExPolygon& poly : polys) { + Polygons poly_triangles; + // poly.triangulate() is based on a trapezoidal decomposition implemented in an extremely expensive way by clipping the whole input contour with a polygon! + poly.triangulate(&poly_triangles); + // poly.triangulate_p2t() is based on the poly2tri library, which is not quite stable, it often ends up in a nice stack overflow! + // poly.triangulate_p2t(&poly_triangles); + for (const Polygon &t : poly_triangles) + if (flip) { + triangles.emplace_back(to_3d(unscale(t.points[2]), z)); + triangles.emplace_back(to_3d(unscale(t.points[1]), z)); + triangles.emplace_back(to_3d(unscale(t.points[0]), z)); + } else { + triangles.emplace_back(to_3d(unscale(t.points[0]), z)); + triangles.emplace_back(to_3d(unscale(t.points[1]), z)); + triangles.emplace_back(to_3d(unscale(t.points[2]), z)); + } + } +#else + +// for (const ExPolygon &poly : union_ex(simplify_polygons(to_polygons(polys), true))) { + for (const ExPolygon &poly : polys) { + append(triangles, TessWrapper::tesselate(poly, z, flip)); + continue; + + std::list input = expoly_to_polypartition_input(poly); + std::list output; + // int res = TPPLPartition().Triangulate_MONO(&input, &output); + int res = TPPLPartition().Triangulate_EC(&input, &output); + if (res == 1) { + // Triangulation succeeded. Convert to triangles. + size_t num_triangles = 0; + for (const TPPLPoly &poly : output) + if (poly.GetNumPoints() >= 3) + num_triangles += (size_t)poly.GetNumPoints() - 2; + triangles.reserve(triangles.size() + num_triangles * 3); + for (const TPPLPoly &poly : output) { + long num_points = poly.GetNumPoints(); + if (num_points >= 3) { + const TPPLPoint *pt0 = &poly[0]; + const TPPLPoint *pt1 = nullptr; + const TPPLPoint *pt2 = &poly[1]; + for (long i = 2; i < num_points; ++i) { + pt1 = pt2; + pt2 = &poly[i]; + if (flip) { + triangles.emplace_back(unscale(pt2->x), unscale(pt2->y), z); + triangles.emplace_back(unscale(pt1->x), unscale(pt1->y), z); + triangles.emplace_back(unscale(pt0->x), unscale(pt0->y), z); + } else { + triangles.emplace_back(unscale(pt0->x), unscale(pt0->y), z); + triangles.emplace_back(unscale(pt1->x), unscale(pt1->y), z); + triangles.emplace_back(unscale(pt2->x), unscale(pt2->y), z); + } + } + } + } + } else { + // Triangulation by polypartition failed. Use the expensive slow implementation. + Polygons poly_triangles; + // poly.triangulate() is based on a trapezoidal decomposition implemented in an extremely expensive way by clipping the whole input contour with a polygon! + poly.triangulate(&poly_triangles); + // poly.triangulate_p2t() is based on the poly2tri library, which is not quite stable, it often ends up in a nice stack overflow! + // poly.triangulate_p2t(&poly_triangles); + for (const Polygon &t : poly_triangles) + if (flip) { + triangles.emplace_back(to_3d(unscale(t.points[2]), z)); + triangles.emplace_back(to_3d(unscale(t.points[1]), z)); + triangles.emplace_back(to_3d(unscale(t.points[0]), z)); + } else { + triangles.emplace_back(to_3d(unscale(t.points[0]), z)); + triangles.emplace_back(to_3d(unscale(t.points[1]), z)); + triangles.emplace_back(to_3d(unscale(t.points[2]), z)); + } + } + } +#endif + return triangles; +} + void GLCanvas3D::_render_sla_slices() const { if (!m_use_clipping_planes || wxGetApp().preset_bundle->printers.get_edited_preset().printer_technology() != ptSLA) @@ -6448,34 +6662,32 @@ void GLCanvas3D::_render_sla_slices() const { const SLAPrintObject* obj = print_objects[i]; - Pointf3s bottom_obj_triangles; - Pointf3s bottom_sup_triangles; - Pointf3s top_obj_triangles; - Pointf3s top_sup_triangles; - double shift_z = obj->get_current_elevation(); double min_z = clip_min_z - shift_z; double max_z = clip_max_z - shift_z; - if (m_sla_caps[0].matches(min_z)) + SlaCap::ObjectIdToTrianglesMap::iterator it_caps_bottom = m_sla_caps[0].triangles.find(i); + SlaCap::ObjectIdToTrianglesMap::iterator it_caps_top = m_sla_caps[1].triangles.find(i); { - SlaCap::ObjectIdToTrianglesMap::const_iterator it = m_sla_caps[0].triangles.find(i); - if (it != m_sla_caps[0].triangles.end()) - { - bottom_obj_triangles = it->second.object; - bottom_sup_triangles = it->second.suppports; - } - } - - if (m_sla_caps[1].matches(max_z)) - { - SlaCap::ObjectIdToTrianglesMap::const_iterator it = m_sla_caps[1].triangles.find(i); - if (it != m_sla_caps[1].triangles.end()) - { - top_obj_triangles = it->second.object; - top_sup_triangles = it->second.suppports; + if (it_caps_bottom == m_sla_caps[0].triangles.end()) + it_caps_bottom = m_sla_caps[0].triangles.emplace(i, SlaCap::Triangles()).first; + if (! m_sla_caps[0].matches(min_z)) { + m_sla_caps[0].z = min_z; + it_caps_bottom->second.object.clear(); + it_caps_bottom->second.supports.clear(); + } + if (it_caps_top == m_sla_caps[1].triangles.end()) + it_caps_top = m_sla_caps[1].triangles.emplace(i, SlaCap::Triangles()).first; + if (! m_sla_caps[1].matches(max_z)) { + m_sla_caps[1].z = max_z; + it_caps_top->second.object.clear(); + it_caps_top->second.supports.clear(); } } + Pointf3s &bottom_obj_triangles = it_caps_bottom->second.object; + Pointf3s &bottom_sup_triangles = it_caps_bottom->second.supports; + Pointf3s &top_obj_triangles = it_caps_top->second.object; + Pointf3s &top_sup_triangles = it_caps_top->second.supports; const std::vector& instances = obj->instances(); struct InstanceTransform @@ -6501,86 +6713,22 @@ void GLCanvas3D::_render_sla_slices() const if (it_min_z != index.end()) { + // calculate model bottom cap if (bottom_obj_triangles.empty() && (it_min_z->second.model_slices_idx < model_slices.size())) - { - // calculate model bottom cap - const ExPolygons& polys = model_slices[it_min_z->second.model_slices_idx]; - for (const ExPolygon& poly : polys) - { - Polygons poly_triangles; - poly.triangulate(&poly_triangles); - for (const Polygon& t : poly_triangles) - { - for (int v = 2; v >= 0; --v) - { - bottom_obj_triangles.emplace_back(to_3d(unscale(t.points[v]), min_z)); - } - } - } - } - + bottom_obj_triangles = triangulate_expolygons(model_slices[it_min_z->second.model_slices_idx], min_z, true); + // calculate support bottom cap if (bottom_sup_triangles.empty() && (it_min_z->second.support_slices_idx < support_slices.size())) - { - // calculate support bottom cap - const ExPolygons& polys = support_slices[it_min_z->second.support_slices_idx]; - for (const ExPolygon& poly : polys) - { - Polygons poly_triangles; - poly.triangulate(&poly_triangles); - for (const Polygon& t : poly_triangles) - { - for (int v = 2; v >= 0; --v) - { - bottom_sup_triangles.emplace_back(to_3d(unscale(t.points[v]), min_z)); - } - } - } - - m_sla_caps[0].triangles.insert(SlaCap::ObjectIdToTrianglesMap::value_type(i, { bottom_obj_triangles, bottom_sup_triangles })); - m_sla_caps[0].z = min_z; - } + bottom_sup_triangles = triangulate_expolygons(support_slices[it_min_z->second.support_slices_idx], min_z, true); } if (it_max_z != index.end()) { + // calculate model top cap if (top_obj_triangles.empty() && (it_max_z->second.model_slices_idx < model_slices.size())) - { - // calculate model top cap - const ExPolygons& polys = model_slices[it_max_z->second.model_slices_idx]; - for (const ExPolygon& poly : polys) - { - Polygons poly_triangles; - poly.triangulate(&poly_triangles); - for (const Polygon& t : poly_triangles) - { - for (int v = 0; v < 3; ++v) - { - top_obj_triangles.emplace_back(to_3d(unscale(t.points[v]), max_z)); - } - } - } - } - + top_obj_triangles = triangulate_expolygons(model_slices[it_max_z->second.model_slices_idx], max_z, false); + // calculate support top cap if (top_sup_triangles.empty() && (it_max_z->second.support_slices_idx < support_slices.size())) - { - // calculate support top cap - const ExPolygons& polys = support_slices[it_max_z->second.support_slices_idx]; - for (const ExPolygon& poly : polys) - { - Polygons poly_triangles; - poly.triangulate(&poly_triangles); - for (const Polygon& t : poly_triangles) - { - for (int v = 0; v < 3; ++v) - { - top_sup_triangles.emplace_back(to_3d(unscale(t.points[v]), max_z)); - } - } - } - } - - m_sla_caps[1].triangles.insert(SlaCap::ObjectIdToTrianglesMap::value_type(i, { top_obj_triangles, top_sup_triangles })); - m_sla_caps[1].z = max_z; + top_sup_triangles = triangulate_expolygons(support_slices[it_max_z->second.support_slices_idx], max_z, false); } } diff --git a/src/slic3r/GUI/GLCanvas3D.hpp b/src/slic3r/GUI/GLCanvas3D.hpp index ba5ef386c..9458d9ca2 100644 --- a/src/slic3r/GUI/GLCanvas3D.hpp +++ b/src/slic3r/GUI/GLCanvas3D.hpp @@ -780,7 +780,7 @@ private: struct Triangles { Pointf3s object; - Pointf3s suppports; + Pointf3s supports; }; typedef std::map ObjectIdToTrianglesMap; double z; diff --git a/src/slic3r/GUI/GUI.cpp b/src/slic3r/GUI/GUI.cpp index 0ff4ed161..148285e86 100644 --- a/src/slic3r/GUI/GUI.cpp +++ b/src/slic3r/GUI/GUI.cpp @@ -245,8 +245,6 @@ void show_info(wxWindow* parent, const wxString& message, const wxString& title) void warning_catcher(wxWindow* parent, const wxString& message) { - if (message == "GLUquadricObjPtr | " + _(L("Attempt to free unreferenced scalar")) ) - return; wxMessageDialog msg(parent, message, _(L("Warning")), wxOK | wxICON_WARNING); msg.ShowModal(); } diff --git a/src/slic3r/GUI/PrintHostDialogs.cpp b/src/slic3r/GUI/PrintHostDialogs.cpp index 5790823a1..d6b5f3469 100644 --- a/src/slic3r/GUI/PrintHostDialogs.cpp +++ b/src/slic3r/GUI/PrintHostDialogs.cpp @@ -30,6 +30,10 @@ PrintHostSendDialog::PrintHostSendDialog(const fs::path &path) , txt_filename(new wxTextCtrl(this, wxID_ANY, path.filename().wstring())) , box_print(new wxCheckBox(this, wxID_ANY, _(L("Start printing after upload")))) { +#ifdef __APPLE__ + txt_filename->OSXDisableAllSmartSubstitutions(); +#endif + auto *label_dir_hint = new wxStaticText(this, wxID_ANY, _(L("Use forward slashes ( / ) as a directory separator if needed."))); label_dir_hint->Wrap(CONTENT_WIDTH); diff --git a/xs/t/04_expolygon.t b/xs/t/04_expolygon.t index 5c10651f8..39da22f0a 100644 --- a/xs/t/04_expolygon.t +++ b/xs/t/04_expolygon.t @@ -5,7 +5,7 @@ use warnings; use List::Util qw(first sum); use Slic3r::XS; -use Test::More tests => 33; +use Test::More tests => 31; use constant PI => 4 * atan2(1, 1); @@ -133,10 +133,4 @@ is $expolygon->area, 100*100-20*20, 'area'; is scalar(grep { $_->area == 100*200 } @$polygons), 1, 'trapezoids have expected area'; } -{ - my $triangles = $expolygon->triangulate_pp; - is scalar(@$triangles), 8, 'expected number of triangles'; - is sum(map $_->area, @$triangles), $expolygon->area, 'sum of triangles area equals original expolygon area'; -} - __END__ diff --git a/xs/xsp/ExPolygon.xsp b/xs/xsp/ExPolygon.xsp index d45b7f6b1..bb138732f 100644 --- a/xs/xsp/ExPolygon.xsp +++ b/xs/xsp/ExPolygon.xsp @@ -31,14 +31,10 @@ Polygons simplify_p(double tolerance); Polylines medial_axis(double max_width, double min_width) %code{% THIS->medial_axis(max_width, min_width, &RETVAL); %}; - Polygons get_trapezoids(double angle) - %code{% THIS->get_trapezoids(&RETVAL, angle); %}; Polygons get_trapezoids2(double angle) %code{% THIS->get_trapezoids2(&RETVAL, angle); %}; Polygons triangulate() %code{% THIS->triangulate(&RETVAL); %}; - Polygons triangulate_pp() - %code{% THIS->triangulate_pp(&RETVAL); %}; %{ ExPolygon*