Merge branch 'master' of https://github.com/prusa3d/Slic3r into objects_centering
This commit is contained in:
commit
16bd7325c1
@ -50,7 +50,6 @@ if (SLIC3R_GUI)
|
|||||||
if(WIN32)
|
if(WIN32)
|
||||||
message(STATUS "WXWIN environment set to: $ENV{WXWIN}")
|
message(STATUS "WXWIN environment set to: $ENV{WXWIN}")
|
||||||
elseif(UNIX)
|
elseif(UNIX)
|
||||||
message(STATUS "wx-config path: ${wxWidgets_CONFIG_EXECUTABLE}")
|
|
||||||
set(wxWidgets_USE_UNICODE ON)
|
set(wxWidgets_USE_UNICODE ON)
|
||||||
if(SLIC3R_STATIC)
|
if(SLIC3R_STATIC)
|
||||||
set(wxWidgets_USE_STATIC ON)
|
set(wxWidgets_USE_STATIC ON)
|
||||||
@ -72,6 +71,10 @@ if (SLIC3R_GUI)
|
|||||||
find_package(wxWidgets 3.1 REQUIRED COMPONENTS base core adv html gl)
|
find_package(wxWidgets 3.1 REQUIRED COMPONENTS base core adv html gl)
|
||||||
endif ()
|
endif ()
|
||||||
|
|
||||||
|
if(UNIX)
|
||||||
|
message(STATUS "wx-config path: ${wxWidgets_CONFIG_EXECUTABLE}")
|
||||||
|
endif()
|
||||||
|
|
||||||
include(${wxWidgets_USE_FILE})
|
include(${wxWidgets_USE_FILE})
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
@ -310,16 +310,15 @@ ExPolygon::medial_axis(double max_width, double min_width, Polylines* polylines)
|
|||||||
polylines->insert(polylines->end(), tp.begin(), tp.end());
|
polylines->insert(polylines->end(), tp.begin(), tp.end());
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
/*
|
||||||
ExPolygon::get_trapezoids(Polygons* polygons) const
|
void ExPolygon::get_trapezoids(Polygons* polygons) const
|
||||||
{
|
{
|
||||||
ExPolygons expp;
|
ExPolygons expp;
|
||||||
expp.push_back(*this);
|
expp.push_back(*this);
|
||||||
boost::polygon::get_trapezoids(*polygons, expp);
|
boost::polygon::get_trapezoids(*polygons, expp);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void ExPolygon::get_trapezoids(Polygons* polygons, double angle) const
|
||||||
ExPolygon::get_trapezoids(Polygons* polygons, double angle) const
|
|
||||||
{
|
{
|
||||||
ExPolygon clone = *this;
|
ExPolygon clone = *this;
|
||||||
clone.rotate(PI/2 - angle, Point(0,0));
|
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)
|
for (Polygons::iterator polygon = polygons->begin(); polygon != polygons->end(); ++polygon)
|
||||||
polygon->rotate(-(PI/2 - angle), Point(0,0));
|
polygon->rotate(-(PI/2 - angle), Point(0,0));
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
// This algorithm may return more trapezoids than necessary
|
// This algorithm may return more trapezoids than necessary
|
||||||
// (i.e. it may break a single trapezoid in several because
|
// (i.e. it may break a single trapezoid in several because
|
||||||
// other parts of the object have x coordinates in the middle)
|
// other parts of the object have x coordinates in the middle)
|
||||||
void
|
void ExPolygon::get_trapezoids2(Polygons* polygons) const
|
||||||
ExPolygon::get_trapezoids2(Polygons* polygons) const
|
|
||||||
{
|
{
|
||||||
// get all points of this ExPolygon
|
// get all points of this ExPolygon
|
||||||
Points pp = *this;
|
Points pp = *this;
|
||||||
@ -370,8 +369,7 @@ ExPolygon::get_trapezoids2(Polygons* polygons) const
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void ExPolygon::get_trapezoids2(Polygons* polygons, double angle) const
|
||||||
ExPolygon::get_trapezoids2(Polygons* polygons, double angle) const
|
|
||||||
{
|
{
|
||||||
ExPolygon clone = *this;
|
ExPolygon clone = *this;
|
||||||
clone.rotate(PI/2 - angle, Point(0,0));
|
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
|
// While this triangulates successfully, it's NOT a constrained triangulation
|
||||||
// as it will create more vertices on the boundaries than the ones supplied.
|
// as it will create more vertices on the boundaries than the ones supplied.
|
||||||
void
|
void ExPolygon::triangulate(Polygons* polygons) const
|
||||||
ExPolygon::triangulate(Polygons* polygons) const
|
|
||||||
{
|
{
|
||||||
// first make trapezoids
|
// first make trapezoids
|
||||||
Polygons trapezoids;
|
Polygons trapezoids;
|
||||||
@ -394,8 +391,8 @@ ExPolygon::triangulate(Polygons* polygons) const
|
|||||||
polygon->triangulate_convex(polygons);
|
polygon->triangulate_convex(polygons);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
/*
|
||||||
ExPolygon::triangulate_pp(Polygons* polygons) const
|
void ExPolygon::triangulate_pp(Polygons* polygons) const
|
||||||
{
|
{
|
||||||
// convert polygons
|
// convert polygons
|
||||||
std::list<TPPLPoly> input;
|
std::list<TPPLPoly> input;
|
||||||
@ -452,9 +449,113 @@ ExPolygon::triangulate_pp(Polygons* polygons) const
|
|||||||
polygons->push_back(p);
|
polygons->push_back(p);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
void
|
std::list<TPPLPoly> expoly_to_polypartition_input(const ExPolygon &ex)
|
||||||
ExPolygon::triangulate_p2t(Polygons* polygons) const
|
{
|
||||||
|
std::list<TPPLPoly> 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<TPPLPoly> expoly_to_polypartition_input(const ExPolygons &expps)
|
||||||
|
{
|
||||||
|
std::list<TPPLPoly> 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<Point> polypartition_output_to_triangles(const std::list<TPPLPoly> &output)
|
||||||
|
{
|
||||||
|
size_t num_triangles = 0;
|
||||||
|
for (const TPPLPoly &poly : output)
|
||||||
|
if (poly.GetNumPoints() >= 3)
|
||||||
|
num_triangles += (size_t)poly.GetNumPoints() - 2;
|
||||||
|
std::vector<Point> 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<TPPLPoly> input = expoly_to_polypartition_input(expp);
|
||||||
|
// perform triangulation
|
||||||
|
std::list<TPPLPoly> 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);
|
ExPolygons expp = simplify_polygons_ex(*this, true);
|
||||||
|
|
||||||
@ -478,16 +579,21 @@ ExPolygon::triangulate_p2t(Polygons* polygons) const
|
|||||||
}
|
}
|
||||||
|
|
||||||
// perform triangulation
|
// perform triangulation
|
||||||
cdt.Triangulate();
|
try {
|
||||||
std::vector<p2t::Triangle*> triangles = cdt.GetTriangles();
|
cdt.Triangulate();
|
||||||
|
std::vector<p2t::Triangle*> triangles = cdt.GetTriangles();
|
||||||
for (std::vector<p2t::Triangle*>::const_iterator triangle = triangles.begin(); triangle != triangles.end(); ++triangle) {
|
|
||||||
Polygon p;
|
for (std::vector<p2t::Triangle*>::const_iterator triangle = triangles.begin(); triangle != triangles.end(); ++triangle) {
|
||||||
for (int i = 0; i <= 2; ++i) {
|
Polygon p;
|
||||||
p2t::Point* point = (*triangle)->GetPoint(i);
|
for (int i = 0; i <= 2; ++i) {
|
||||||
p.points.push_back(Point(point->x, point->y));
|
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)
|
for (p2t::Point *ptr : ContourPoints)
|
||||||
@ -495,8 +601,7 @@ ExPolygon::triangulate_p2t(Polygons* polygons) const
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Lines
|
Lines ExPolygon::lines() const
|
||||||
ExPolygon::lines() const
|
|
||||||
{
|
{
|
||||||
Lines lines = this->contour.lines();
|
Lines lines = this->contour.lines();
|
||||||
for (Polygons::const_iterator h = this->holes.begin(); h != this->holes.end(); ++h) {
|
for (Polygons::const_iterator h = this->holes.begin(); h != this->holes.end(); ++h) {
|
||||||
|
@ -6,6 +6,9 @@
|
|||||||
#include "Polyline.hpp"
|
#include "Polyline.hpp"
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
// polygon class of the polypartition library
|
||||||
|
class TPPLPoly;
|
||||||
|
|
||||||
namespace Slic3r {
|
namespace Slic3r {
|
||||||
|
|
||||||
class ExPolygon;
|
class ExPolygon;
|
||||||
@ -55,12 +58,13 @@ public:
|
|||||||
void simplify(double tolerance, ExPolygons* expolygons) const;
|
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, ThickPolylines* polylines) const;
|
||||||
void medial_axis(double max_width, double min_width, Polylines* 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) const;
|
||||||
void get_trapezoids(Polygons* polygons, double angle) const;
|
// void get_trapezoids(Polygons* polygons, double angle) const;
|
||||||
void get_trapezoids2(Polygons* polygons) const;
|
void get_trapezoids2(Polygons* polygons) const;
|
||||||
void get_trapezoids2(Polygons* polygons, double angle) const;
|
void get_trapezoids2(Polygons* polygons, double angle) const;
|
||||||
void triangulate(Polygons* polygons) 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;
|
void triangulate_p2t(Polygons* polygons) const;
|
||||||
Lines lines() const;
|
Lines lines() const;
|
||||||
};
|
};
|
||||||
@ -297,6 +301,10 @@ extern std::vector<BoundingBox> get_extents_vector(const ExPolygons &polygons);
|
|||||||
|
|
||||||
extern bool remove_sticks(ExPolygon &poly);
|
extern bool remove_sticks(ExPolygon &poly);
|
||||||
|
|
||||||
|
extern std::list<TPPLPoly> expoly_to_polypartition_input(const ExPolygons &expp);
|
||||||
|
extern std::list<TPPLPoly> expoly_to_polypartition_input(const ExPolygon &ex);
|
||||||
|
extern std::vector<Point> polypartition_output_to_triangles(const std::list<TPPLPoly> &output);
|
||||||
|
|
||||||
} // namespace Slic3r
|
} // namespace Slic3r
|
||||||
|
|
||||||
// start Boost
|
// start Boost
|
||||||
|
@ -41,7 +41,7 @@
|
|||||||
|
|
||||||
namespace Slic3r {
|
namespace Slic3r {
|
||||||
|
|
||||||
TriangleMesh::TriangleMesh(const Pointf3s &points, const std::vector<Vec3crd>& facets )
|
TriangleMesh::TriangleMesh(const Pointf3s &points, const std::vector<Vec3crd>& facets)
|
||||||
: repaired(false)
|
: repaired(false)
|
||||||
{
|
{
|
||||||
stl_initialize(&this->stl);
|
stl_initialize(&this->stl);
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Poly2Tri Copyright (c) 2009-2010, Poly2Tri Contributors
|
* Poly2Tri Copyright (c) 2009-2018, Poly2Tri Contributors
|
||||||
* http://code.google.com/p/poly2tri/
|
* https://github.com/jhasse/poly2tri
|
||||||
*
|
*
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
@ -29,10 +29,16 @@
|
|||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
#include "shapes.h"
|
#include "shapes.h"
|
||||||
|
|
||||||
|
#include <cassert>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
namespace p2t {
|
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)
|
Triangle::Triangle(Point& a, Point& b, Point& c)
|
||||||
{
|
{
|
||||||
points_[0] = &a; points_[1] = &b; points_[2] = &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]) {
|
if (p == points_[0]) {
|
||||||
return 0;
|
return 0;
|
||||||
@ -163,7 +169,7 @@ int Triangle::Index(const Point* p) const
|
|||||||
return -1;
|
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_[0] == p1) {
|
||||||
if (points_[1] == p2) {
|
if (points_[1] == p2) {
|
||||||
@ -259,7 +265,7 @@ Triangle* Triangle::NeighborCCW(const Point& point)
|
|||||||
return neighbors_[1];
|
return neighbors_[1];
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Triangle::GetConstrainedEdgeCCW(const Point& p) const
|
bool Triangle::GetConstrainedEdgeCCW(const Point& p)
|
||||||
{
|
{
|
||||||
if (&p == points_[0]) {
|
if (&p == points_[0]) {
|
||||||
return constrained_edge[2];
|
return constrained_edge[2];
|
||||||
@ -269,7 +275,7 @@ bool Triangle::GetConstrainedEdgeCCW(const Point& p) const
|
|||||||
return constrained_edge[1];
|
return constrained_edge[1];
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Triangle::GetConstrainedEdgeCW(const Point& p) const
|
bool Triangle::GetConstrainedEdgeCW(const Point& p)
|
||||||
{
|
{
|
||||||
if (&p == points_[0]) {
|
if (&p == points_[0]) {
|
||||||
return constrained_edge[1];
|
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]) {
|
if (&p == points_[0]) {
|
||||||
return delaunay_edge[2];
|
return delaunay_edge[2];
|
||||||
@ -311,7 +317,7 @@ bool Triangle::GetDelunayEdgeCCW(const Point& p) const
|
|||||||
return delaunay_edge[1];
|
return delaunay_edge[1];
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Triangle::GetDelunayEdgeCW(const Point& p) const
|
bool Triangle::GetDelunayEdgeCW(const Point& p)
|
||||||
{
|
{
|
||||||
if (&p == points_[0]) {
|
if (&p == points_[0]) {
|
||||||
return delaunay_edge[1];
|
return delaunay_edge[1];
|
||||||
@ -356,10 +362,7 @@ Triangle& Triangle::NeighborAcross(const Point& opoint)
|
|||||||
|
|
||||||
void Triangle::DebugPrint()
|
void Triangle::DebugPrint()
|
||||||
{
|
{
|
||||||
using namespace std;
|
std::cout << *points_[0] << " " << *points_[1] << " " << *points_[2] << std::endl;
|
||||||
cout << points_[0]->x << "," << points_[0]->y << " ";
|
|
||||||
cout << points_[1]->x << "," << points_[1]->y << " ";
|
|
||||||
cout << points_[2]->x << "," << points_[2]->y << endl;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Poly2Tri Copyright (c) 2009-2010, Poly2Tri Contributors
|
* Poly2Tri Copyright (c) 2009-2018, Poly2Tri Contributors
|
||||||
* http://code.google.com/p/poly2tri/
|
* https://github.com/jhasse/poly2tri
|
||||||
*
|
*
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
@ -33,10 +33,10 @@
|
|||||||
#ifndef SHAPES_H
|
#ifndef SHAPES_H
|
||||||
#define SHAPES_H
|
#define SHAPES_H
|
||||||
|
|
||||||
#include <vector>
|
|
||||||
#include <cstddef>
|
|
||||||
#include <assert.h>
|
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
|
#include <cstddef>
|
||||||
|
#include <stdexcept>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
namespace p2t {
|
namespace p2t {
|
||||||
|
|
||||||
@ -119,6 +119,8 @@ struct Point {
|
|||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
std::ostream& operator<<(std::ostream&, const Point&);
|
||||||
|
|
||||||
// Represents a simple polygon's edge
|
// Represents a simple polygon's edge
|
||||||
struct Edge {
|
struct Edge {
|
||||||
|
|
||||||
@ -130,13 +132,13 @@ struct Edge {
|
|||||||
if (p1.y > p2.y) {
|
if (p1.y > p2.y) {
|
||||||
q = &p1;
|
q = &p1;
|
||||||
p = &p2;
|
p = &p2;
|
||||||
} else if (p1.y == p2.y) {
|
} else if (std::abs(p1.y - p2.y) < 1e-10) {
|
||||||
if (p1.x > p2.x) {
|
if (p1.x > p2.x) {
|
||||||
q = &p1;
|
q = &p1;
|
||||||
p = &p2;
|
p = &p2;
|
||||||
} else if (p1.x == p2.x) {
|
} else if (std::abs(p1.x - p2.x) < 1e-10) {
|
||||||
// Repeat points
|
// 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(Edge& edge);
|
||||||
void MarkConstrainedEdge(Point* p, Point* q);
|
void MarkConstrainedEdge(Point* p, Point* q);
|
||||||
|
|
||||||
int Index(const Point* p) const;
|
int Index(const Point* p);
|
||||||
int EdgeIndex(const Point* p1, const Point* p2) const;
|
int EdgeIndex(const Point* p1, const Point* p2);
|
||||||
|
|
||||||
Triangle* NeighborCW(const Point& point);
|
Triangle* NeighborCW(const Point& point);
|
||||||
Triangle* NeighborCCW(const Point& point);
|
Triangle* NeighborCCW(const Point& point);
|
||||||
bool GetConstrainedEdgeCCW(const Point& p) const;
|
bool GetConstrainedEdgeCCW(const Point& p);
|
||||||
bool GetConstrainedEdgeCW(const Point& p) const;
|
bool GetConstrainedEdgeCW(const Point& p);
|
||||||
void SetConstrainedEdgeCCW(const Point& p, bool ce);
|
void SetConstrainedEdgeCCW(const Point& p, bool ce);
|
||||||
void SetConstrainedEdgeCW(const Point& p, bool ce);
|
void SetConstrainedEdgeCW(const Point& p, bool ce);
|
||||||
bool GetDelunayEdgeCCW(const Point& p) const;
|
bool GetDelunayEdgeCCW(const Point& p);
|
||||||
bool GetDelunayEdgeCW(const Point& p) const;
|
bool GetDelunayEdgeCW(const Point& p);
|
||||||
void SetDelunayEdgeCCW(const Point& p, bool e);
|
void SetDelunayEdgeCCW(const Point& p, bool e);
|
||||||
void SetDelunayEdgeCW(const Point& p, bool e);
|
void SetDelunayEdgeCW(const Point& p, bool e);
|
||||||
|
|
||||||
bool Contains(const Point* p) const;
|
bool Contains(const Point* p);
|
||||||
bool Contains(const Edge& e) const;
|
bool Contains(const Edge& e);
|
||||||
bool Contains(const Point* p, const Point* q) const;
|
bool Contains(const Point* p, const Point* q);
|
||||||
void Legalize(Point& point);
|
void Legalize(Point& point);
|
||||||
void Legalize(Point& opoint, Point& npoint);
|
void Legalize(Point& opoint, Point& npoint);
|
||||||
/**
|
/**
|
||||||
@ -198,7 +200,7 @@ void ClearNeighbor(const Triangle *triangle);
|
|||||||
void ClearNeighbors();
|
void ClearNeighbors();
|
||||||
void ClearDelunayEdges();
|
void ClearDelunayEdges();
|
||||||
|
|
||||||
inline bool IsInterior() const;
|
inline bool IsInterior();
|
||||||
inline void IsInterior(bool b);
|
inline void IsInterior(bool b);
|
||||||
|
|
||||||
Triangle& NeighborAcross(const Point& opoint);
|
Triangle& NeighborAcross(const Point& opoint);
|
||||||
@ -293,22 +295,22 @@ inline Triangle* Triangle::GetNeighbor(int index)
|
|||||||
return neighbors_[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];
|
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);
|
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);
|
return Contains(p) && Contains(q);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool Triangle::IsInterior() const
|
inline bool Triangle::IsInterior()
|
||||||
{
|
{
|
||||||
return interior_;
|
return interior_;
|
||||||
}
|
}
|
||||||
@ -320,4 +322,4 @@ inline void Triangle::IsInterior(bool b)
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Poly2Tri Copyright (c) 2009-2010, Poly2Tri Contributors
|
* Poly2Tri Copyright (c) 2009-2018, Poly2Tri Contributors
|
||||||
* http://code.google.com/p/poly2tri/
|
* https://github.com/jhasse/poly2tri
|
||||||
*
|
*
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
@ -34,11 +34,18 @@
|
|||||||
|
|
||||||
// Otherwise #defines like M_PI are undeclared under Visual Studio
|
// Otherwise #defines like M_PI are undeclared under Visual Studio
|
||||||
#ifndef _USE_MATH_DEFINES
|
#ifndef _USE_MATH_DEFINES
|
||||||
#define _USE_MATH_DEFINES
|
#define _USE_MATH_DEFINES
|
||||||
#endif /* _USE_MATH_DEFINES */
|
#endif /* _USE_MATH_DEFINES */
|
||||||
|
|
||||||
|
#include "shapes.h"
|
||||||
|
|
||||||
|
#include <cmath>
|
||||||
#include <exception>
|
#include <exception>
|
||||||
#include <math.h>
|
|
||||||
|
// C99 removes M_PI from math.h
|
||||||
|
#ifndef M_PI
|
||||||
|
#define M_PI 3.14159265358979323846264338327
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace p2t {
|
namespace p2t {
|
||||||
|
|
||||||
@ -121,4 +128,4 @@ bool InScanArea(const Point& pa, const Point& pb, const Point& pc, const Point&
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Poly2Tri Copyright (c) 2009-2010, Poly2Tri Contributors
|
* Poly2Tri Copyright (c) 2009-2018, Poly2Tri Contributors
|
||||||
* http://code.google.com/p/poly2tri/
|
* https://github.com/jhasse/poly2tri
|
||||||
*
|
*
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
@ -35,4 +35,4 @@
|
|||||||
#include "common/shapes.h"
|
#include "common/shapes.h"
|
||||||
#include "sweep/cdt.h"
|
#include "sweep/cdt.h"
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Poly2Tri Copyright (c) 2009-2010, Poly2Tri Contributors
|
* Poly2Tri Copyright (c) 2009-2018, Poly2Tri Contributors
|
||||||
* http://code.google.com/p/poly2tri/
|
* https://github.com/jhasse/poly2tri
|
||||||
*
|
*
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
@ -30,6 +30,8 @@
|
|||||||
*/
|
*/
|
||||||
#include "advancing_front.h"
|
#include "advancing_front.h"
|
||||||
|
|
||||||
|
#include <cassert>
|
||||||
|
|
||||||
namespace p2t {
|
namespace p2t {
|
||||||
|
|
||||||
AdvancingFront::AdvancingFront(Node& head, Node& tail)
|
AdvancingFront::AdvancingFront(Node& head, Node& tail)
|
||||||
@ -105,4 +107,4 @@ AdvancingFront::~AdvancingFront()
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Poly2Tri Copyright (c) 2009-2010, Poly2Tri Contributors
|
* Poly2Tri Copyright (c) 2009-2018, Poly2Tri Contributors
|
||||||
* http://code.google.com/p/poly2tri/
|
* https://github.com/jhasse/poly2tri
|
||||||
*
|
*
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
@ -115,4 +115,4 @@ inline void AdvancingFront::set_search(Node* node)
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Poly2Tri Copyright (c) 2009-2010, Poly2Tri Contributors
|
* Poly2Tri Copyright (c) 2009-2018, Poly2Tri Contributors
|
||||||
* http://code.google.com/p/poly2tri/
|
* https://github.com/jhasse/poly2tri
|
||||||
*
|
*
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
@ -68,4 +68,4 @@ CDT::~CDT()
|
|||||||
delete sweep_;
|
delete sweep_;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Poly2Tri Copyright (c) 2009-2010, Poly2Tri Contributors
|
* Poly2Tri Copyright (c) 2009-2018, Poly2Tri Contributors
|
||||||
* http://code.google.com/p/poly2tri/
|
* https://github.com/jhasse/poly2tri
|
||||||
*
|
*
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
@ -102,4 +102,4 @@ public:
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Poly2Tri Copyright (c) 2009-2010, Poly2Tri Contributors
|
* Poly2Tri Copyright (c) 2009-2018, Poly2Tri Contributors
|
||||||
* http://code.google.com/p/poly2tri/
|
* https://github.com/jhasse/poly2tri
|
||||||
*
|
*
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
@ -28,19 +28,21 @@
|
|||||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
#include <stdexcept>
|
|
||||||
#include "sweep.h"
|
#include "sweep.h"
|
||||||
#include "sweep_context.h"
|
#include "sweep_context.h"
|
||||||
#include "advancing_front.h"
|
#include "advancing_front.h"
|
||||||
#include "../common/utils.h"
|
#include "../common/utils.h"
|
||||||
|
|
||||||
|
#include <cassert>
|
||||||
|
#include <stdexcept>
|
||||||
|
|
||||||
namespace p2t {
|
namespace p2t {
|
||||||
|
|
||||||
// Triangulate simple polygon with holes
|
// Triangulate simple polygon with holes
|
||||||
void Sweep::Triangulate(SweepContext& tcx)
|
void Sweep::Triangulate(SweepContext& tcx)
|
||||||
{
|
{
|
||||||
tcx.InitTriangulation();
|
tcx.InitTriangulation();
|
||||||
tcx.CreateAdvancingFront(nodes_);
|
tcx.CreateAdvancingFront();
|
||||||
// Sweep points; build mesh
|
// Sweep points; build mesh
|
||||||
SweepPoints(tcx);
|
SweepPoints(tcx);
|
||||||
// Clean up
|
// Clean up
|
||||||
@ -699,13 +701,6 @@ void Sweep::FlipEdgeEvent(SweepContext& tcx, Point& ep, Point& eq, Triangle* t,
|
|||||||
Triangle& ot = t->NeighborAcross(p);
|
Triangle& ot = t->NeighborAcross(p);
|
||||||
Point& op = *ot.OppositePoint(*t, 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)) {
|
if (InScanArea(p, *t->PointCCW(p), *t->PointCW(p), op)) {
|
||||||
// Lets rotate shared edge one vertex CW
|
// Lets rotate shared edge one vertex CW
|
||||||
RotateTrianglePair(*t, p, ot, op);
|
RotateTrianglePair(*t, p, ot, op);
|
||||||
@ -772,13 +767,6 @@ void Sweep::FlipScanEdgeEvent(SweepContext& tcx, Point& ep, Point& eq, Triangle&
|
|||||||
Triangle& ot = t.NeighborAcross(p);
|
Triangle& ot = t.NeighborAcross(p);
|
||||||
Point& op = *ot.OppositePoint(t, 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)) {
|
if (InScanArea(eq, *flip_triangle.PointCCW(eq), *flip_triangle.PointCW(eq), op)) {
|
||||||
// flip with new edge op->eq
|
// flip with new edge op->eq
|
||||||
FlipEdgeEvent(tcx, eq, op, &ot, op);
|
FlipEdgeEvent(tcx, eq, op, &ot, op);
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Poly2Tri Copyright (c) 2009-2010, Poly2Tri Contributors
|
* Poly2Tri Copyright (c) 2009-2018, Poly2Tri Contributors
|
||||||
* http://code.google.com/p/poly2tri/
|
* https://github.com/jhasse/poly2tri
|
||||||
*
|
*
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
@ -282,4 +282,4 @@ private:
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Poly2Tri Copyright (c) 2009-2010, Poly2Tri Contributors
|
* Poly2Tri Copyright (c) 2009-2018, Poly2Tri Contributors
|
||||||
* http://code.google.com/p/poly2tri/
|
* https://github.com/jhasse/poly2tri
|
||||||
*
|
*
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
@ -120,10 +120,9 @@ Node& SweepContext::LocateNode(const Point& point)
|
|||||||
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
|
// Initial triangle
|
||||||
Triangle* triangle = new Triangle(*points_[0], *tail_, *head_);
|
Triangle* triangle = new Triangle(*points_[0], *tail_, *head_);
|
||||||
|
|
||||||
@ -169,8 +168,8 @@ void SweepContext::MeshClean(Triangle& triangle)
|
|||||||
triangles.push_back(&triangle);
|
triangles.push_back(&triangle);
|
||||||
|
|
||||||
while(!triangles.empty()){
|
while(!triangles.empty()){
|
||||||
Triangle *t = triangles.back();
|
Triangle *t = triangles.back();
|
||||||
triangles.pop_back();
|
triangles.pop_back();
|
||||||
|
|
||||||
if (t != NULL && !t->IsInterior()) {
|
if (t != NULL && !t->IsInterior()) {
|
||||||
t->IsInterior(true);
|
t->IsInterior(true);
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Poly2Tri Copyright (c) 2009-2010, Poly2Tri Contributors
|
* Poly2Tri Copyright (c) 2009-2018, Poly2Tri Contributors
|
||||||
* http://code.google.com/p/poly2tri/
|
* https://github.com/jhasse/poly2tri
|
||||||
*
|
*
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
@ -70,7 +70,7 @@ Node& LocateNode(const Point& point);
|
|||||||
|
|
||||||
void RemoveNode(Node* node);
|
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
|
/// Try to map a node to all sides of this triangle that don't have a neighbor
|
||||||
void MapTriangleToNodes(Triangle& t);
|
void MapTriangleToNodes(Triangle& t);
|
||||||
|
@ -25,6 +25,8 @@
|
|||||||
#include <list>
|
#include <list>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <set>
|
#include <set>
|
||||||
|
#include <vector>
|
||||||
|
#include <stdexcept>
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
@ -66,21 +68,26 @@ void TPPLPoly::Triangle(TPPLPoint &p1, TPPLPoint &p2, TPPLPoint &p3) {
|
|||||||
points[2] = p3;
|
points[2] = p3;
|
||||||
}
|
}
|
||||||
|
|
||||||
TPPLPoly::TPPLPoly(const TPPLPoly &src) {
|
TPPLPoly::TPPLPoly(const TPPLPoly &src) : TPPLPoly() {
|
||||||
hole = src.hole;
|
hole = src.hole;
|
||||||
numpoints = src.numpoints;
|
numpoints = src.numpoints;
|
||||||
points = new TPPLPoint[numpoints];
|
|
||||||
memcpy(points, src.points, numpoints*sizeof(TPPLPoint));
|
|
||||||
}
|
|
||||||
|
|
||||||
TPPLPoly& TPPLPoly::operator=(const TPPLPoly &src) {
|
if(numpoints > 0) {
|
||||||
if(&src != this) {
|
|
||||||
Clear();
|
|
||||||
hole = src.hole;
|
|
||||||
numpoints = src.numpoints;
|
|
||||||
points = new TPPLPoint[numpoints];
|
points = new TPPLPoint[numpoints];
|
||||||
memcpy(points, src.points, numpoints*sizeof(TPPLPoint));
|
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;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -105,16 +112,11 @@ void TPPLPoly::SetOrientation(int orientation) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void TPPLPoly::Invert() {
|
void TPPLPoly::Invert() {
|
||||||
long i;
|
std::reverse(points, points + numpoints);
|
||||||
TPPLPoint *invpoints;
|
}
|
||||||
|
|
||||||
invpoints = new TPPLPoint[numpoints];
|
TPPLPartition::PartitionVertex::PartitionVertex() : previous(NULL), next(NULL) {
|
||||||
for(i=0;i<numpoints;i++) {
|
|
||||||
invpoints[i] = points[numpoints-i-1];
|
|
||||||
}
|
|
||||||
|
|
||||||
delete [] points;
|
|
||||||
points = invpoints;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TPPLPoint TPPLPartition::Normalize(const TPPLPoint &p) {
|
TPPLPoint TPPLPartition::Normalize(const TPPLPoint &p) {
|
||||||
@ -169,10 +171,10 @@ int TPPLPartition::Intersects(TPPLPoint &p11, TPPLPoint &p12, TPPLPoint &p21, TP
|
|||||||
}
|
}
|
||||||
|
|
||||||
//removes holes from inpolys by merging them with non-holes
|
//removes holes from inpolys by merging them with non-holes
|
||||||
int TPPLPartition::RemoveHoles(list<TPPLPoly> *inpolys, list<TPPLPoly> *outpolys) {
|
int TPPLPartition::RemoveHoles(TPPLPolyList *inpolys, TPPLPolyList *outpolys) {
|
||||||
list<TPPLPoly> polys;
|
TPPLPolyList polys;
|
||||||
list<TPPLPoly>::iterator holeiter,polyiter,iter,iter2;
|
TPPLPolyList::iterator holeiter,polyiter,iter,iter2;
|
||||||
long i,i2,holepointindex,polypointindex = 0;
|
long i,i2,holepointindex,polypointindex;
|
||||||
TPPLPoint holepoint,polypoint,bestpolypoint;
|
TPPLPoint holepoint,polypoint,bestpolypoint;
|
||||||
TPPLPoint linep1,linep2;
|
TPPLPoint linep1,linep2;
|
||||||
TPPLPoint v1,v2;
|
TPPLPoint v1,v2;
|
||||||
@ -183,14 +185,14 @@ int TPPLPartition::RemoveHoles(list<TPPLPoly> *inpolys, list<TPPLPoly> *outpolys
|
|||||||
|
|
||||||
//check for trivial case (no holes)
|
//check for trivial case (no holes)
|
||||||
hasholes = false;
|
hasholes = false;
|
||||||
for(iter = inpolys->begin(); iter!=inpolys->end(); ++iter) {
|
for(iter = inpolys->begin(); iter!=inpolys->end(); iter++) {
|
||||||
if(iter->IsHole()) {
|
if(iter->IsHole()) {
|
||||||
hasholes = true;
|
hasholes = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(!hasholes) {
|
if(!hasholes) {
|
||||||
for(iter = inpolys->begin(); iter!=inpolys->end(); ++iter) {
|
for(iter = inpolys->begin(); iter!=inpolys->end(); iter++) {
|
||||||
outpolys->push_back(*iter);
|
outpolys->push_back(*iter);
|
||||||
}
|
}
|
||||||
return 1;
|
return 1;
|
||||||
@ -201,7 +203,7 @@ int TPPLPartition::RemoveHoles(list<TPPLPoly> *inpolys, list<TPPLPoly> *outpolys
|
|||||||
while(1) {
|
while(1) {
|
||||||
//find the hole point with the largest x
|
//find the hole point with the largest x
|
||||||
hasholes = false;
|
hasholes = false;
|
||||||
for(iter = polys.begin(); iter!=polys.end(); ++iter) {
|
for(iter = polys.begin(); iter!=polys.end(); iter++) {
|
||||||
if(!iter->IsHole()) continue;
|
if(!iter->IsHole()) continue;
|
||||||
|
|
||||||
if(!hasholes) {
|
if(!hasholes) {
|
||||||
@ -221,7 +223,7 @@ int TPPLPartition::RemoveHoles(list<TPPLPoly> *inpolys, list<TPPLPoly> *outpolys
|
|||||||
holepoint = holeiter->GetPoint(holepointindex);
|
holepoint = holeiter->GetPoint(holepointindex);
|
||||||
|
|
||||||
pointfound = false;
|
pointfound = false;
|
||||||
for(iter = polys.begin(); iter!=polys.end(); ++iter) {
|
for(iter = polys.begin(); iter!=polys.end(); iter++) {
|
||||||
if(iter->IsHole()) continue;
|
if(iter->IsHole()) continue;
|
||||||
for(i=0; i < iter->GetNumPoints(); i++) {
|
for(i=0; i < iter->GetNumPoints(); i++) {
|
||||||
if(iter->GetPoint(i).x <= holepoint.x) continue;
|
if(iter->GetPoint(i).x <= holepoint.x) continue;
|
||||||
@ -237,7 +239,7 @@ int TPPLPartition::RemoveHoles(list<TPPLPoly> *inpolys, list<TPPLPoly> *outpolys
|
|||||||
if(v2.x > v1.x) continue;
|
if(v2.x > v1.x) continue;
|
||||||
}
|
}
|
||||||
pointvisible = true;
|
pointvisible = true;
|
||||||
for(iter2 = polys.begin(); iter2!=polys.end(); ++iter2) {
|
for(iter2 = polys.begin(); iter2!=polys.end(); iter2++) {
|
||||||
if(iter2->IsHole()) continue;
|
if(iter2->IsHole()) continue;
|
||||||
for(i2=0; i2 < iter2->GetNumPoints(); i2++) {
|
for(i2=0; i2 < iter2->GetNumPoints(); i2++) {
|
||||||
linep1 = iter2->GetPoint(i2);
|
linep1 = iter2->GetPoint(i2);
|
||||||
@ -280,7 +282,7 @@ int TPPLPartition::RemoveHoles(list<TPPLPoly> *inpolys, list<TPPLPoly> *outpolys
|
|||||||
polys.push_back(newpoly);
|
polys.push_back(newpoly);
|
||||||
}
|
}
|
||||||
|
|
||||||
for(iter = polys.begin(); iter!=polys.end(); ++iter) {
|
for(iter = polys.begin(); iter!=polys.end(); iter++) {
|
||||||
outpolys->push_back(*iter);
|
outpolys->push_back(*iter);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -335,7 +337,7 @@ bool TPPLPartition::InCone(PartitionVertex *v, TPPLPoint &p) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void TPPLPartition::UpdateVertexReflexity(PartitionVertex *v) {
|
void TPPLPartition::UpdateVertexReflexity(PartitionVertex *v) {
|
||||||
PartitionVertex *v1,*v3;
|
PartitionVertex *v1 = NULL,*v3 = NULL;
|
||||||
v1 = v->previous;
|
v1 = v->previous;
|
||||||
v3 = v->next;
|
v3 = v->next;
|
||||||
v->isConvex = !IsReflex(v1->p,v->p,v3->p);
|
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) {
|
void TPPLPartition::UpdateVertex(PartitionVertex *v, PartitionVertex *vertices, long numvertices) {
|
||||||
long i;
|
long i;
|
||||||
PartitionVertex *v1,*v3;
|
PartitionVertex *v1 = NULL,*v3 = NULL;
|
||||||
TPPLPoint vec1,vec3;
|
TPPLPoint vec1,vec3;
|
||||||
|
|
||||||
v1 = v->previous;
|
v1 = v->previous;
|
||||||
@ -372,10 +374,12 @@ void TPPLPartition::UpdateVertex(PartitionVertex *v, PartitionVertex *vertices,
|
|||||||
}
|
}
|
||||||
|
|
||||||
//triangulation by ear removal
|
//triangulation by ear removal
|
||||||
int TPPLPartition::Triangulate_EC(TPPLPoly *poly, list<TPPLPoly> *triangles) {
|
int TPPLPartition::Triangulate_EC(TPPLPoly *poly, TPPLPolyList *triangles) {
|
||||||
|
if(!poly->Valid()) return 0;
|
||||||
|
|
||||||
long numvertices;
|
long numvertices;
|
||||||
PartitionVertex *vertices;
|
PartitionVertex *vertices = NULL;
|
||||||
PartitionVertex *ear;
|
PartitionVertex *ear = NULL;
|
||||||
TPPLPoly triangle;
|
TPPLPoly triangle;
|
||||||
long i,j;
|
long i,j;
|
||||||
bool earfound;
|
bool earfound;
|
||||||
@ -446,21 +450,23 @@ int TPPLPartition::Triangulate_EC(TPPLPoly *poly, list<TPPLPoly> *triangles) {
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int TPPLPartition::Triangulate_EC(list<TPPLPoly> *inpolys, list<TPPLPoly> *triangles) {
|
int TPPLPartition::Triangulate_EC(TPPLPolyList *inpolys, TPPLPolyList *triangles) {
|
||||||
list<TPPLPoly> outpolys;
|
TPPLPolyList outpolys;
|
||||||
list<TPPLPoly>::iterator iter;
|
TPPLPolyList::iterator iter;
|
||||||
|
|
||||||
if(!RemoveHoles(inpolys,&outpolys)) return 0;
|
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;
|
if(!Triangulate_EC(&(*iter),triangles)) return 0;
|
||||||
}
|
}
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int TPPLPartition::ConvexPartition_HM(TPPLPoly *poly, list<TPPLPoly> *parts) {
|
int TPPLPartition::ConvexPartition_HM(TPPLPoly *poly, TPPLPolyList *parts) {
|
||||||
list<TPPLPoly> triangles;
|
if(!poly->Valid()) return 0;
|
||||||
list<TPPLPoly>::iterator iter1,iter2;
|
|
||||||
TPPLPoly *poly1,*poly2;
|
TPPLPolyList triangles;
|
||||||
|
TPPLPolyList::iterator iter1,iter2;
|
||||||
|
TPPLPoly *poly1 = NULL,*poly2 = NULL;
|
||||||
TPPLPoly newpoly;
|
TPPLPoly newpoly;
|
||||||
TPPLPoint d1,d2,p1,p2,p3;
|
TPPLPoint d1,d2,p1,p2,p3;
|
||||||
long i11,i12,i21,i22,i13,i23,j,k;
|
long i11,i12,i21,i22,i13,i23,j,k;
|
||||||
@ -486,7 +492,7 @@ int TPPLPartition::ConvexPartition_HM(TPPLPoly *poly, list<TPPLPoly> *parts) {
|
|||||||
|
|
||||||
if(!Triangulate_EC(poly,&triangles)) return 0;
|
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);
|
poly1 = &(*iter1);
|
||||||
for(i11=0;i11<poly1->GetNumPoints();i11++) {
|
for(i11=0;i11<poly1->GetNumPoints();i11++) {
|
||||||
d1 = poly1->GetPoint(i11);
|
d1 = poly1->GetPoint(i11);
|
||||||
@ -494,7 +500,7 @@ int TPPLPartition::ConvexPartition_HM(TPPLPoly *poly, list<TPPLPoly> *parts) {
|
|||||||
d2 = poly1->GetPoint(i12);
|
d2 = poly1->GetPoint(i12);
|
||||||
|
|
||||||
isdiagonal = false;
|
isdiagonal = false;
|
||||||
for(iter2 = iter1; iter2 != triangles.end(); ++iter2) {
|
for(iter2 = iter1; iter2 != triangles.end(); iter2++) {
|
||||||
if(iter1 == iter2) continue;
|
if(iter1 == iter2) continue;
|
||||||
poly2 = &(*iter2);
|
poly2 = &(*iter2);
|
||||||
|
|
||||||
@ -550,19 +556,19 @@ int TPPLPartition::ConvexPartition_HM(TPPLPoly *poly, list<TPPLPoly> *parts) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for(iter1 = triangles.begin(); iter1 != triangles.end(); ++iter1) {
|
for(iter1 = triangles.begin(); iter1 != triangles.end(); iter1++) {
|
||||||
parts->push_back(*iter1);
|
parts->push_back(*iter1);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int TPPLPartition::ConvexPartition_HM(list<TPPLPoly> *inpolys, list<TPPLPoly> *parts) {
|
int TPPLPartition::ConvexPartition_HM(TPPLPolyList *inpolys, TPPLPolyList *parts) {
|
||||||
list<TPPLPoly> outpolys;
|
TPPLPolyList outpolys;
|
||||||
list<TPPLPoly>::iterator iter;
|
TPPLPolyList::iterator iter;
|
||||||
|
|
||||||
if(!RemoveHoles(inpolys,&outpolys)) return 0;
|
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;
|
if(!ConvexPartition_HM(&(*iter),parts)) return 0;
|
||||||
}
|
}
|
||||||
return 1;
|
return 1;
|
||||||
@ -571,14 +577,16 @@ int TPPLPartition::ConvexPartition_HM(list<TPPLPoly> *inpolys, list<TPPLPoly> *p
|
|||||||
//minimum-weight polygon triangulation by dynamic programming
|
//minimum-weight polygon triangulation by dynamic programming
|
||||||
//O(n^3) time complexity
|
//O(n^3) time complexity
|
||||||
//O(n^2) space complexity
|
//O(n^2) space complexity
|
||||||
int TPPLPartition::Triangulate_OPT(TPPLPoly *poly, list<TPPLPoly> *triangles) {
|
int TPPLPartition::Triangulate_OPT(TPPLPoly *poly, TPPLPolyList *triangles) {
|
||||||
|
if(!poly->Valid()) return 0;
|
||||||
|
|
||||||
long i,j,k,gap,n;
|
long i,j,k,gap,n;
|
||||||
DPState **dpstates;
|
DPState **dpstates = NULL;
|
||||||
TPPLPoint p1,p2,p3,p4;
|
TPPLPoint p1,p2,p3,p4;
|
||||||
long bestvertex;
|
long bestvertex;
|
||||||
tppl_float weight,minweight,d1,d2;
|
tppl_float weight,minweight,d1,d2;
|
||||||
Diagonal diagonal,newdiagonal;
|
Diagonal diagonal,newdiagonal;
|
||||||
list<Diagonal> diagonals;
|
DiagonalList diagonals;
|
||||||
TPPLPoly triangle;
|
TPPLPoly triangle;
|
||||||
int ret = 1;
|
int ret = 1;
|
||||||
|
|
||||||
@ -703,7 +711,7 @@ int TPPLPartition::Triangulate_OPT(TPPLPoly *poly, list<TPPLPoly> *triangles) {
|
|||||||
|
|
||||||
void TPPLPartition::UpdateState(long a, long b, long w, long i, long j, DPState2 **dpstates) {
|
void TPPLPartition::UpdateState(long a, long b, long w, long i, long j, DPState2 **dpstates) {
|
||||||
Diagonal newdiagonal;
|
Diagonal newdiagonal;
|
||||||
list<Diagonal> *pairs;
|
DiagonalList *pairs = NULL;
|
||||||
long w2;
|
long w2;
|
||||||
|
|
||||||
w2 = dpstates[a][b].weight;
|
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) {
|
void TPPLPartition::TypeA(long i, long j, long k, PartitionVertex *vertices, DPState2 **dpstates) {
|
||||||
list<Diagonal> *pairs;
|
DiagonalList *pairs = NULL;
|
||||||
list<Diagonal>::iterator iter,lastiter;
|
DiagonalList::iterator iter,lastiter;
|
||||||
long top;
|
long top;
|
||||||
long w;
|
long w;
|
||||||
|
|
||||||
@ -742,7 +750,7 @@ void TPPLPartition::TypeA(long i, long j, long k, PartitionVertex *vertices, DPS
|
|||||||
iter = pairs->end();
|
iter = pairs->end();
|
||||||
lastiter = pairs->end();
|
lastiter = pairs->end();
|
||||||
while(iter!=pairs->begin()) {
|
while(iter!=pairs->begin()) {
|
||||||
--iter;
|
iter--;
|
||||||
if(!IsReflex(vertices[iter->index2].p,vertices[j].p,vertices[k].p)) lastiter = iter;
|
if(!IsReflex(vertices[iter->index2].p,vertices[j].p,vertices[k].p)) lastiter = iter;
|
||||||
else break;
|
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) {
|
void TPPLPartition::TypeB(long i, long j, long k, PartitionVertex *vertices, DPState2 **dpstates) {
|
||||||
list<Diagonal> *pairs;
|
DiagonalList *pairs = NULL;
|
||||||
list<Diagonal>::iterator iter,lastiter;
|
DiagonalList::iterator iter,lastiter;
|
||||||
long top;
|
long top;
|
||||||
long w;
|
long w;
|
||||||
|
|
||||||
@ -778,7 +786,7 @@ void TPPLPartition::TypeB(long i, long j, long k, PartitionVertex *vertices, DPS
|
|||||||
while(iter!=pairs->end()) {
|
while(iter!=pairs->end()) {
|
||||||
if(!IsReflex(vertices[i].p,vertices[j].p,vertices[iter->index1].p)) {
|
if(!IsReflex(vertices[i].p,vertices[j].p,vertices[iter->index1].p)) {
|
||||||
lastiter = iter;
|
lastiter = iter;
|
||||||
++iter;
|
iter++;
|
||||||
}
|
}
|
||||||
else break;
|
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);
|
UpdateState(i,k,w,j,top,dpstates);
|
||||||
}
|
}
|
||||||
|
|
||||||
int TPPLPartition::ConvexPartition_OPT(TPPLPoly *poly, list<TPPLPoly> *parts) {
|
int TPPLPartition::ConvexPartition_OPT(TPPLPoly *poly, TPPLPolyList *parts) {
|
||||||
|
if(!poly->Valid()) return 0;
|
||||||
|
|
||||||
TPPLPoint p1,p2,p3,p4;
|
TPPLPoint p1,p2,p3,p4;
|
||||||
PartitionVertex *vertices;
|
PartitionVertex *vertices = NULL;
|
||||||
DPState2 **dpstates;
|
DPState2 **dpstates = NULL;
|
||||||
long i,j,k,n,gap;
|
long i,j,k,n,gap;
|
||||||
list<Diagonal> diagonals,diagonals2;
|
DiagonalList diagonals,diagonals2;
|
||||||
Diagonal diagonal,newdiagonal;
|
Diagonal diagonal,newdiagonal;
|
||||||
list<Diagonal> *pairs,*pairs2;
|
DiagonalList *pairs = NULL,*pairs2 = NULL;
|
||||||
list<Diagonal>::iterator iter,iter2;
|
DiagonalList::iterator iter,iter2;
|
||||||
int ret;
|
int ret;
|
||||||
TPPLPoly newpoly;
|
TPPLPoly newpoly;
|
||||||
list<long> indices;
|
vector<long> indices;
|
||||||
list<long>::iterator iiter;
|
vector<long>::iterator iiter;
|
||||||
bool ijreal,jkreal;
|
bool ijreal,jkreal;
|
||||||
|
|
||||||
n = poly->GetNumPoints();
|
n = poly->GetNumPoints();
|
||||||
@ -919,7 +929,7 @@ int TPPLPartition::ConvexPartition_OPT(TPPLPoly *poly, list<TPPLPoly> *parts) {
|
|||||||
}
|
}
|
||||||
if(!vertices[diagonal.index1].isConvex) {
|
if(!vertices[diagonal.index1].isConvex) {
|
||||||
iter = pairs->end();
|
iter = pairs->end();
|
||||||
--iter;
|
iter--;
|
||||||
j = iter->index2;
|
j = iter->index2;
|
||||||
newdiagonal.index1 = j;
|
newdiagonal.index1 = j;
|
||||||
newdiagonal.index2 = diagonal.index2;
|
newdiagonal.index2 = diagonal.index2;
|
||||||
@ -933,7 +943,7 @@ int TPPLPartition::ConvexPartition_OPT(TPPLPoly *poly, list<TPPLPoly> *parts) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
iter2 = pairs2->end();
|
iter2 = pairs2->end();
|
||||||
--iter2;
|
iter2--;
|
||||||
if(iter->index1 != iter2->index1) pairs2->pop_back();
|
if(iter->index1 != iter2->index1) pairs2->pop_back();
|
||||||
else break;
|
else break;
|
||||||
}
|
}
|
||||||
@ -1003,7 +1013,7 @@ int TPPLPartition::ConvexPartition_OPT(TPPLPoly *poly, list<TPPLPoly> *parts) {
|
|||||||
pairs = &(dpstates[diagonal.index1][diagonal.index2].pairs);
|
pairs = &(dpstates[diagonal.index1][diagonal.index2].pairs);
|
||||||
if(!vertices[diagonal.index1].isConvex) {
|
if(!vertices[diagonal.index1].isConvex) {
|
||||||
iter = pairs->end();
|
iter = pairs->end();
|
||||||
--iter;
|
iter--;
|
||||||
j = iter->index2;
|
j = iter->index2;
|
||||||
if(iter->index1 != iter->index2) ijreal = false;
|
if(iter->index1 != iter->index2) ijreal = false;
|
||||||
} else {
|
} else {
|
||||||
@ -1031,10 +1041,10 @@ int TPPLPartition::ConvexPartition_OPT(TPPLPoly *poly, list<TPPLPoly> *parts) {
|
|||||||
indices.push_back(j);
|
indices.push_back(j);
|
||||||
}
|
}
|
||||||
|
|
||||||
indices.sort();
|
std::sort(indices.begin(), indices.end());
|
||||||
newpoly.Init((long)indices.size());
|
newpoly.Init((long)indices.size());
|
||||||
k=0;
|
k=0;
|
||||||
for(iiter = indices.begin();iiter!=indices.end(); ++iiter) {
|
for(iiter = indices.begin();iiter!=indices.end();iiter++) {
|
||||||
newpoly[k] = vertices[*iiter].p;
|
newpoly[k] = vertices[*iiter].p;
|
||||||
k++;
|
k++;
|
||||||
}
|
}
|
||||||
@ -1055,18 +1065,19 @@ int TPPLPartition::ConvexPartition_OPT(TPPLPoly *poly, list<TPPLPoly> *parts) {
|
|||||||
//the algorithm used here is outlined in the book
|
//the algorithm used here is outlined in the book
|
||||||
//"Computational Geometry: Algorithms and Applications"
|
//"Computational Geometry: Algorithms and Applications"
|
||||||
//by Mark de Berg, Otfried Cheong, Marc van Kreveld and Mark Overmars
|
//by Mark de Berg, Otfried Cheong, Marc van Kreveld and Mark Overmars
|
||||||
int TPPLPartition::MonotonePartition(list<TPPLPoly> *inpolys, list<TPPLPoly> *monotonePolys) {
|
int TPPLPartition::MonotonePartition(TPPLPolyList *inpolys, TPPLPolyList *monotonePolys) {
|
||||||
list<TPPLPoly>::iterator iter;
|
TPPLPolyList::iterator iter;
|
||||||
MonotoneVertex *vertices;
|
MonotoneVertex *vertices = NULL;
|
||||||
long i,numvertices,vindex,vindex2,newnumvertices,maxnumvertices;
|
long i,numvertices,vindex,vindex2,newnumvertices,maxnumvertices;
|
||||||
long polystartindex, polyendindex;
|
long polystartindex, polyendindex;
|
||||||
TPPLPoly *poly;
|
TPPLPoly *poly = NULL;
|
||||||
MonotoneVertex *v,*v2,*vprev,*vnext;
|
MonotoneVertex *v = NULL,*v2 = NULL,*vprev = NULL,*vnext = NULL;
|
||||||
ScanLineEdge newedge;
|
ScanLineEdge newedge;
|
||||||
bool error = false;
|
bool error = false;
|
||||||
|
|
||||||
numvertices = 0;
|
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();
|
numvertices += iter->GetNumPoints();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1075,7 +1086,7 @@ int TPPLPartition::MonotonePartition(list<TPPLPoly> *inpolys, list<TPPLPoly> *mo
|
|||||||
newnumvertices = numvertices;
|
newnumvertices = numvertices;
|
||||||
|
|
||||||
polystartindex = 0;
|
polystartindex = 0;
|
||||||
for(iter = inpolys->begin(); iter != inpolys->end(); ++iter) {
|
for(iter = inpolys->begin(); iter != inpolys->end(); iter++) {
|
||||||
poly = &(*iter);
|
poly = &(*iter);
|
||||||
polyendindex = polystartindex + poly->GetNumPoints()-1;
|
polyendindex = polystartindex + poly->GetNumPoints()-1;
|
||||||
for(i=0;i<poly->GetNumPoints();i++) {
|
for(i=0;i<poly->GetNumPoints();i++) {
|
||||||
@ -1130,6 +1141,7 @@ int TPPLPartition::MonotonePartition(list<TPPLPoly> *inpolys, list<TPPLPoly> *mo
|
|||||||
set<ScanLineEdge>::iterator *edgeTreeIterators,edgeIter;
|
set<ScanLineEdge>::iterator *edgeTreeIterators,edgeIter;
|
||||||
edgeTreeIterators = new set<ScanLineEdge>::iterator[maxnumvertices];
|
edgeTreeIterators = new set<ScanLineEdge>::iterator[maxnumvertices];
|
||||||
pair<set<ScanLineEdge>::iterator,bool> edgeTreeRet;
|
pair<set<ScanLineEdge>::iterator,bool> edgeTreeRet;
|
||||||
|
for(i = 0; i<numvertices; i++) edgeTreeIterators[i] = edgeTree.end();
|
||||||
|
|
||||||
//for each vertex
|
//for each vertex
|
||||||
for(i=0;i<numvertices;i++) {
|
for(i=0;i<numvertices;i++) {
|
||||||
@ -1152,16 +1164,15 @@ int TPPLPartition::MonotonePartition(list<TPPLPoly> *inpolys, list<TPPLPoly> *mo
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case TPPL_VERTEXTYPE_END:
|
case TPPL_VERTEXTYPE_END:
|
||||||
|
if (edgeTreeIterators[v->previous] == edgeTree.end()) {
|
||||||
|
error = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
//if helper(ei-1) is a merge vertex
|
//if helper(ei-1) is a merge vertex
|
||||||
if(vertextypes[helpers[v->previous]]==TPPL_VERTEXTYPE_MERGE) {
|
if(vertextypes[helpers[v->previous]]==TPPL_VERTEXTYPE_MERGE) {
|
||||||
//Insert the diagonal connecting vi to helper(ei-1) in D.
|
//Insert the diagonal connecting vi to helper(ei-1) in D.
|
||||||
AddDiagonal(vertices,&newnumvertices,vindex,helpers[v->previous]);
|
AddDiagonal(vertices,&newnumvertices,vindex,helpers[v->previous],
|
||||||
vertextypes[newnumvertices-2] = vertextypes[vindex];
|
vertextypes, edgeTreeIterators, &edgeTree, helpers);
|
||||||
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]];
|
|
||||||
}
|
}
|
||||||
//Delete ei-1 from T
|
//Delete ei-1 from T
|
||||||
edgeTree.erase(edgeTreeIterators[v->previous]);
|
edgeTree.erase(edgeTreeIterators[v->previous]);
|
||||||
@ -1176,15 +1187,10 @@ int TPPLPartition::MonotonePartition(list<TPPLPoly> *inpolys, list<TPPLPoly> *mo
|
|||||||
error = true;
|
error = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
--edgeIter;
|
edgeIter--;
|
||||||
//Insert the diagonal connecting vi to helper(ej) in D.
|
//Insert the diagonal connecting vi to helper(ej) in D.
|
||||||
AddDiagonal(vertices,&newnumvertices,vindex,helpers[edgeIter->index]);
|
AddDiagonal(vertices,&newnumvertices,vindex,helpers[edgeIter->index],
|
||||||
vertextypes[newnumvertices-2] = vertextypes[vindex];
|
vertextypes, edgeTreeIterators, &edgeTree, helpers);
|
||||||
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]];
|
|
||||||
vindex2 = newnumvertices-2;
|
vindex2 = newnumvertices-2;
|
||||||
v2 = &(vertices[vindex2]);
|
v2 = &(vertices[vindex2]);
|
||||||
//helper(e j)<29>vi
|
//helper(e j)<29>vi
|
||||||
@ -1199,16 +1205,15 @@ int TPPLPartition::MonotonePartition(list<TPPLPoly> *inpolys, list<TPPLPoly> *mo
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case TPPL_VERTEXTYPE_MERGE:
|
case TPPL_VERTEXTYPE_MERGE:
|
||||||
|
if (edgeTreeIterators[v->previous] == edgeTree.end()) {
|
||||||
|
error = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
//if helper(ei-1) is a merge vertex
|
//if helper(ei-1) is a merge vertex
|
||||||
if(vertextypes[helpers[v->previous]]==TPPL_VERTEXTYPE_MERGE) {
|
if(vertextypes[helpers[v->previous]]==TPPL_VERTEXTYPE_MERGE) {
|
||||||
//Insert the diagonal connecting vi to helper(ei-1) in D.
|
//Insert the diagonal connecting vi to helper(ei-1) in D.
|
||||||
AddDiagonal(vertices,&newnumvertices,vindex,helpers[v->previous]);
|
AddDiagonal(vertices,&newnumvertices,vindex,helpers[v->previous],
|
||||||
vertextypes[newnumvertices-2] = vertextypes[vindex];
|
vertextypes, edgeTreeIterators, &edgeTree, helpers);
|
||||||
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]];
|
|
||||||
vindex2 = newnumvertices-2;
|
vindex2 = newnumvertices-2;
|
||||||
v2 = &(vertices[vindex2]);
|
v2 = &(vertices[vindex2]);
|
||||||
}
|
}
|
||||||
@ -1222,17 +1227,12 @@ int TPPLPartition::MonotonePartition(list<TPPLPoly> *inpolys, list<TPPLPoly> *mo
|
|||||||
error = true;
|
error = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
--edgeIter;
|
edgeIter--;
|
||||||
//if helper(ej) is a merge vertex
|
//if helper(ej) is a merge vertex
|
||||||
if(vertextypes[helpers[edgeIter->index]]==TPPL_VERTEXTYPE_MERGE) {
|
if(vertextypes[helpers[edgeIter->index]]==TPPL_VERTEXTYPE_MERGE) {
|
||||||
//Insert the diagonal connecting vi to helper(e j) in D.
|
//Insert the diagonal connecting vi to helper(e j) in D.
|
||||||
AddDiagonal(vertices,&newnumvertices,vindex2,helpers[edgeIter->index]);
|
AddDiagonal(vertices,&newnumvertices,vindex2,helpers[edgeIter->index],
|
||||||
vertextypes[newnumvertices-2] = vertextypes[vindex2];
|
vertextypes, edgeTreeIterators, &edgeTree, helpers);
|
||||||
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]];
|
|
||||||
}
|
}
|
||||||
//helper(e j)<29>vi
|
//helper(e j)<29>vi
|
||||||
helpers[edgeIter->index] = vindex2;
|
helpers[edgeIter->index] = vindex2;
|
||||||
@ -1241,16 +1241,15 @@ int TPPLPartition::MonotonePartition(list<TPPLPoly> *inpolys, list<TPPLPoly> *mo
|
|||||||
case TPPL_VERTEXTYPE_REGULAR:
|
case TPPL_VERTEXTYPE_REGULAR:
|
||||||
//if the interior of P lies to the right of vi
|
//if the interior of P lies to the right of vi
|
||||||
if(Below(v->p,vertices[v->previous].p)) {
|
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 helper(ei-1) is a merge vertex
|
||||||
if(vertextypes[helpers[v->previous]]==TPPL_VERTEXTYPE_MERGE) {
|
if(vertextypes[helpers[v->previous]]==TPPL_VERTEXTYPE_MERGE) {
|
||||||
//Insert the diagonal connecting vi to helper(ei-1) in D.
|
//Insert the diagonal connecting vi to helper(ei-1) in D.
|
||||||
AddDiagonal(vertices,&newnumvertices,vindex,helpers[v->previous]);
|
AddDiagonal(vertices,&newnumvertices,vindex,helpers[v->previous],
|
||||||
vertextypes[newnumvertices-2] = vertextypes[vindex];
|
vertextypes, edgeTreeIterators, &edgeTree, helpers);
|
||||||
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]];
|
|
||||||
vindex2 = newnumvertices-2;
|
vindex2 = newnumvertices-2;
|
||||||
v2 = &(vertices[vindex2]);
|
v2 = &(vertices[vindex2]);
|
||||||
}
|
}
|
||||||
@ -1272,17 +1271,12 @@ int TPPLPartition::MonotonePartition(list<TPPLPoly> *inpolys, list<TPPLPoly> *mo
|
|||||||
error = true;
|
error = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
--edgeIter;
|
edgeIter--;
|
||||||
//if helper(ej) is a merge vertex
|
//if helper(ej) is a merge vertex
|
||||||
if(vertextypes[helpers[edgeIter->index]]==TPPL_VERTEXTYPE_MERGE) {
|
if(vertextypes[helpers[edgeIter->index]]==TPPL_VERTEXTYPE_MERGE) {
|
||||||
//Insert the diagonal connecting vi to helper(e j) in D.
|
//Insert the diagonal connecting vi to helper(e j) in D.
|
||||||
AddDiagonal(vertices,&newnumvertices,vindex,helpers[edgeIter->index]);
|
AddDiagonal(vertices,&newnumvertices,vindex,helpers[edgeIter->index],
|
||||||
vertextypes[newnumvertices-2] = vertextypes[vindex];
|
vertextypes, edgeTreeIterators, &edgeTree, helpers);
|
||||||
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]];
|
|
||||||
}
|
}
|
||||||
//helper(e j)<29>vi
|
//helper(e j)<29>vi
|
||||||
helpers[edgeIter->index] = vindex;
|
helpers[edgeIter->index] = vindex;
|
||||||
@ -1342,7 +1336,10 @@ int TPPLPartition::MonotonePartition(list<TPPLPoly> *inpolys, list<TPPLPoly> *mo
|
|||||||
}
|
}
|
||||||
|
|
||||||
//adds a diagonal to the doubly-connected list of vertices
|
//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<ScanLineEdge>::iterator *edgeTreeIterators,
|
||||||
|
set<ScanLineEdge> *edgeTree, long *helpers)
|
||||||
|
{
|
||||||
long newindex1,newindex2;
|
long newindex1,newindex2;
|
||||||
|
|
||||||
newindex1 = *numvertices;
|
newindex1 = *numvertices;
|
||||||
@ -1364,6 +1361,18 @@ void TPPLPartition::AddDiagonal(MonotoneVertex *vertices, long *numvertices, lon
|
|||||||
|
|
||||||
vertices[index2].next = newindex1;
|
vertices[index2].next = newindex1;
|
||||||
vertices[newindex1].previous = index2;
|
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) {
|
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
|
//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;
|
if(vertices[index1].p.y > vertices[index2].p.y) return true;
|
||||||
else if(vertices[index1].p.y == vertices[index2].p.y) {
|
else if(vertices[index1].p.y == vertices[index2].p.y) {
|
||||||
if(vertices[index1].p.x > vertices[index2].p.x) return true;
|
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
|
//triangulates monotone polygon
|
||||||
//O(n) time, O(n) space complexity
|
//O(n) time, O(n) space complexity
|
||||||
int TPPLPartition::TriangulateMonotone(TPPLPoly *inPoly, list<TPPLPoly> *triangles) {
|
int TPPLPartition::TriangulateMonotone(TPPLPoly *inPoly, TPPLPolyList *triangles) {
|
||||||
|
if(!inPoly->Valid()) return 0;
|
||||||
|
|
||||||
long i,i2,j,topindex,bottomindex,leftindex,rightindex,vindex;
|
long i,i2,j,topindex,bottomindex,leftindex,rightindex,vindex;
|
||||||
TPPLPoint *points;
|
TPPLPoint *points = NULL;
|
||||||
long numpoints;
|
long numpoints;
|
||||||
TPPLPoly triangle;
|
TPPLPoly triangle;
|
||||||
|
|
||||||
numpoints = inPoly->GetNumPoints();
|
numpoints = inPoly->GetNumPoints();
|
||||||
points = inPoly->GetPoints();
|
points = inPoly->GetPoints();
|
||||||
|
|
||||||
//trivial calses
|
//trivial case
|
||||||
if(numpoints < 3) return 0;
|
|
||||||
if(numpoints == 3) {
|
if(numpoints == 3) {
|
||||||
triangles->push_back(*inPoly);
|
triangles->push_back(*inPoly);
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
topindex = 0; bottomindex=0;
|
topindex = 0; bottomindex=0;
|
||||||
@ -1544,19 +1555,19 @@ int TPPLPartition::TriangulateMonotone(TPPLPoly *inPoly, list<TPPLPoly> *triangl
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int TPPLPartition::Triangulate_MONO(list<TPPLPoly> *inpolys, list<TPPLPoly> *triangles) {
|
int TPPLPartition::Triangulate_MONO(TPPLPolyList *inpolys, TPPLPolyList *triangles) {
|
||||||
list<TPPLPoly> monotone;
|
TPPLPolyList monotone;
|
||||||
list<TPPLPoly>::iterator iter;
|
TPPLPolyList::iterator iter;
|
||||||
|
|
||||||
if(!MonotonePartition(inpolys,&monotone)) return 0;
|
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;
|
if(!TriangulateMonotone(&(*iter),triangles)) return 0;
|
||||||
}
|
}
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int TPPLPartition::Triangulate_MONO(TPPLPoly *poly, list<TPPLPoly> *triangles) {
|
int TPPLPartition::Triangulate_MONO(TPPLPoly *poly, TPPLPolyList *triangles) {
|
||||||
list<TPPLPoly> polys;
|
TPPLPolyList polys;
|
||||||
polys.push_back(*poly);
|
polys.push_back(*poly);
|
||||||
|
|
||||||
return Triangulate_MONO(&polys, triangles);
|
return Triangulate_MONO(&polys, triangles);
|
||||||
|
@ -18,9 +18,11 @@
|
|||||||
//OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
//OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
//THE SOFTWARE.
|
//THE SOFTWARE.
|
||||||
|
|
||||||
|
#ifndef POLYPARTITION_H
|
||||||
|
#define POLYPARTITION_H
|
||||||
|
|
||||||
#include <list>
|
#include <list>
|
||||||
using namespace std;
|
#include <set>
|
||||||
|
|
||||||
typedef double tppl_float;
|
typedef double tppl_float;
|
||||||
|
|
||||||
@ -29,315 +31,349 @@ typedef double tppl_float;
|
|||||||
|
|
||||||
//2D point structure
|
//2D point structure
|
||||||
struct TPPLPoint {
|
struct TPPLPoint {
|
||||||
tppl_float x;
|
tppl_float x;
|
||||||
tppl_float y;
|
tppl_float y;
|
||||||
|
// User-specified vertex identifier. Note that this isn't used internally
|
||||||
TPPLPoint operator + (const TPPLPoint& p) const {
|
// by the library, but will be faithfully copied around.
|
||||||
TPPLPoint r;
|
int id;
|
||||||
r.x = x + p.x;
|
|
||||||
r.y = y + p.y;
|
TPPLPoint operator + (const TPPLPoint& p) const {
|
||||||
return r;
|
TPPLPoint r;
|
||||||
}
|
r.x = x + p.x;
|
||||||
|
r.y = y + p.y;
|
||||||
TPPLPoint operator - (const TPPLPoint& p) const {
|
return r;
|
||||||
TPPLPoint r;
|
}
|
||||||
r.x = x - p.x;
|
|
||||||
r.y = y - p.y;
|
TPPLPoint operator - (const TPPLPoint& p) const {
|
||||||
return r;
|
TPPLPoint r;
|
||||||
}
|
r.x = x - p.x;
|
||||||
|
r.y = y - p.y;
|
||||||
TPPLPoint operator * (const tppl_float f ) const {
|
return r;
|
||||||
TPPLPoint r;
|
}
|
||||||
r.x = x*f;
|
|
||||||
r.y = y*f;
|
TPPLPoint operator * (const tppl_float f ) const {
|
||||||
return r;
|
TPPLPoint r;
|
||||||
}
|
r.x = x*f;
|
||||||
|
r.y = y*f;
|
||||||
TPPLPoint operator / (const tppl_float f ) const {
|
return r;
|
||||||
TPPLPoint r;
|
}
|
||||||
r.x = x/f;
|
|
||||||
r.y = y/f;
|
TPPLPoint operator / (const tppl_float f ) const {
|
||||||
return r;
|
TPPLPoint r;
|
||||||
}
|
r.x = x/f;
|
||||||
|
r.y = y/f;
|
||||||
bool operator==(const TPPLPoint& p) const {
|
return r;
|
||||||
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 true;
|
||||||
bool operator!=(const TPPLPoint& p) const {
|
else return false;
|
||||||
if((x == p.x)&&(y==p.y)) return false;
|
}
|
||||||
else return true;
|
|
||||||
}
|
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
|
//Polygon implemented as an array of points with a 'hole' flag
|
||||||
class TPPLPoly {
|
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;
|
TPPLPoint *GetPoints() {
|
||||||
long numpoints;
|
return points;
|
||||||
bool hole;
|
}
|
||||||
|
|
||||||
|
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
|
//checks whether a polygon is valid or not
|
||||||
TPPLPoly();
|
inline bool Valid() const { return this->numpoints >= 3; }
|
||||||
~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);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#ifdef TPPL_ALLOCATOR
|
||||||
|
typedef std::list<TPPLPoly, TPPL_ALLOCATOR(TPPLPoly)> TPPLPolyList;
|
||||||
|
#else
|
||||||
|
typedef std::list<TPPLPoly> TPPLPolyList;
|
||||||
|
#endif
|
||||||
|
|
||||||
class TPPLPartition {
|
class TPPLPartition {
|
||||||
protected:
|
protected:
|
||||||
struct PartitionVertex {
|
struct PartitionVertex {
|
||||||
bool isActive;
|
bool isActive;
|
||||||
bool isConvex;
|
bool isConvex;
|
||||||
bool isEar;
|
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;
|
#ifdef TPPL_ALLOCATOR
|
||||||
tppl_float angle;
|
typedef std::list<Diagonal, TPPL_ALLOCATOR(Diagonal)> DiagonalList;
|
||||||
PartitionVertex *previous;
|
#else
|
||||||
PartitionVertex *next;
|
typedef std::list<Diagonal> DiagonalList;
|
||||||
};
|
#endif
|
||||||
|
|
||||||
struct MonotoneVertex {
|
//dynamic programming state for minimum-weight triangulation
|
||||||
TPPLPoint p;
|
struct DPState {
|
||||||
long previous;
|
bool visible;
|
||||||
long next;
|
tppl_float weight;
|
||||||
};
|
long bestvertex;
|
||||||
|
};
|
||||||
class VertexSorter{
|
|
||||||
MonotoneVertex *vertices;
|
//dynamic programming state for convex partitioning
|
||||||
public:
|
struct DPState2 {
|
||||||
VertexSorter(MonotoneVertex *v) : vertices(v) {}
|
bool visible;
|
||||||
bool operator() (long index1, long index2) const;
|
long weight;
|
||||||
};
|
DiagonalList pairs;
|
||||||
|
};
|
||||||
struct Diagonal {
|
|
||||||
long index1;
|
//edge that intersects the scanline
|
||||||
long index2;
|
struct ScanLineEdge {
|
||||||
};
|
mutable long index;
|
||||||
|
TPPLPoint p1;
|
||||||
//dynamic programming state for minimum-weight triangulation
|
TPPLPoint p2;
|
||||||
struct DPState {
|
|
||||||
bool visible;
|
//determines if the edge is to the left of another edge
|
||||||
tppl_float weight;
|
bool operator< (const ScanLineEdge & other) const;
|
||||||
long bestvertex;
|
|
||||||
};
|
bool IsConvex(const TPPLPoint& p1, const TPPLPoint& p2, const TPPLPoint& p3) const;
|
||||||
|
};
|
||||||
//dynamic programming state for convex partitioning
|
|
||||||
struct DPState2 {
|
//standard helper functions
|
||||||
bool visible;
|
bool IsConvex(TPPLPoint& p1, TPPLPoint& p2, TPPLPoint& p3);
|
||||||
long weight;
|
bool IsReflex(TPPLPoint& p1, TPPLPoint& p2, TPPLPoint& p3);
|
||||||
list<Diagonal> pairs;
|
bool IsInside(TPPLPoint& p1, TPPLPoint& p2, TPPLPoint& p3, TPPLPoint &p);
|
||||||
};
|
|
||||||
|
bool InCone(TPPLPoint &p1, TPPLPoint &p2, TPPLPoint &p3, TPPLPoint &p);
|
||||||
//edge that intersects the scanline
|
bool InCone(PartitionVertex *v, TPPLPoint &p);
|
||||||
struct ScanLineEdge {
|
|
||||||
long index;
|
int Intersects(TPPLPoint &p11, TPPLPoint &p12, TPPLPoint &p21, TPPLPoint &p22);
|
||||||
TPPLPoint p1;
|
|
||||||
TPPLPoint p2;
|
TPPLPoint Normalize(const TPPLPoint &p);
|
||||||
|
tppl_float Distance(const TPPLPoint &p1, const TPPLPoint &p2);
|
||||||
//determines if the edge is to the left of another edge
|
|
||||||
bool operator< (const ScanLineEdge & other) const;
|
//helper functions for Triangulate_EC
|
||||||
|
void UpdateVertexReflexity(PartitionVertex *v);
|
||||||
bool IsConvex(const TPPLPoint& p1, const TPPLPoint& p2, const TPPLPoint& p3) const;
|
void UpdateVertex(PartitionVertex *v,PartitionVertex *vertices, long numvertices);
|
||||||
};
|
|
||||||
|
//helper functions for ConvexPartition_OPT
|
||||||
//standard helper functions
|
void UpdateState(long a, long b, long w, long i, long j, DPState2 **dpstates);
|
||||||
bool IsConvex(TPPLPoint& p1, TPPLPoint& p2, TPPLPoint& p3);
|
void TypeA(long i, long j, long k, PartitionVertex *vertices, DPState2 **dpstates);
|
||||||
bool IsReflex(TPPLPoint& p1, TPPLPoint& p2, TPPLPoint& p3);
|
void TypeB(long i, long j, long k, PartitionVertex *vertices, DPState2 **dpstates);
|
||||||
bool IsInside(TPPLPoint& p1, TPPLPoint& p2, TPPLPoint& p3, TPPLPoint &p);
|
|
||||||
|
//helper functions for MonotonePartition
|
||||||
bool InCone(TPPLPoint &p1, TPPLPoint &p2, TPPLPoint &p3, TPPLPoint &p);
|
bool Below(TPPLPoint &p1, TPPLPoint &p2);
|
||||||
bool InCone(PartitionVertex *v, TPPLPoint &p);
|
void AddDiagonal(MonotoneVertex *vertices, long *numvertices, long index1, long index2,
|
||||||
|
char *vertextypes, std::set<ScanLineEdge>::iterator *edgeTreeIterators,
|
||||||
int Intersects(TPPLPoint &p11, TPPLPoint &p12, TPPLPoint &p21, TPPLPoint &p22);
|
std::set<ScanLineEdge> *edgeTree, long *helpers);
|
||||||
|
|
||||||
TPPLPoint Normalize(const TPPLPoint &p);
|
//triangulates a monotone polygon, used in Triangulate_MONO
|
||||||
tppl_float Distance(const TPPLPoint &p1, const TPPLPoint &p2);
|
int TriangulateMonotone(TPPLPoly *inPoly, TPPLPolyList *triangles);
|
||||||
|
|
||||||
//helper functions for Triangulate_EC
|
public:
|
||||||
void UpdateVertexReflexity(PartitionVertex *v);
|
|
||||||
void UpdateVertex(PartitionVertex *v,PartitionVertex *vertices, long numvertices);
|
//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
|
||||||
//helper functions for ConvexPartition_OPT
|
//time complexity: O(h*(n^2)), h is the number of holes, n is the number of vertices
|
||||||
void UpdateState(long a, long b, long w, long i, long j, DPState2 **dpstates);
|
//space complexity: O(n)
|
||||||
void TypeA(long i, long j, long k, PartitionVertex *vertices, DPState2 **dpstates);
|
//params:
|
||||||
void TypeB(long i, long j, long k, PartitionVertex *vertices, DPState2 **dpstates);
|
// inpolys : a list of polygons that can contain holes
|
||||||
|
// vertices of all non-hole polys have to be in counter-clockwise order
|
||||||
//helper functions for MonotonePartition
|
// vertices of all hole polys have to be in clockwise order
|
||||||
bool Below(TPPLPoint &p1, TPPLPoint &p2);
|
// outpolys : a list of polygons without holes
|
||||||
void AddDiagonal(MonotoneVertex *vertices, long *numvertices, long index1, long index2);
|
//returns 1 on success, 0 on failure
|
||||||
|
int RemoveHoles(TPPLPolyList *inpolys, TPPLPolyList *outpolys);
|
||||||
//triangulates a monotone polygon, used in Triangulate_MONO
|
|
||||||
int TriangulateMonotone(TPPLPoly *inPoly, list<TPPLPoly> *triangles);
|
//triangulates a polygon by ear clipping
|
||||||
|
//time complexity O(n^2), n is the number of vertices
|
||||||
public:
|
//space complexity: O(n)
|
||||||
|
//params:
|
||||||
//simple heuristic procedure for removing holes from a list of polygons
|
// poly : an input polygon to be triangulated
|
||||||
//works by creating a diagonal from the rightmost hole vertex to some visible vertex
|
// vertices have to be in counter-clockwise order
|
||||||
//time complexity: O(h*(n^2)), h is the number of holes, n is the number of vertices
|
// triangles : a list of triangles (result)
|
||||||
//space complexity: O(n)
|
//returns 1 on success, 0 on failure
|
||||||
//params:
|
int Triangulate_EC(TPPLPoly *poly, TPPLPolyList *triangles);
|
||||||
// inpolys : a list of polygons that can contain holes
|
|
||||||
// vertices of all non-hole polys have to be in counter-clockwise order
|
//triangulates a list of polygons that may contain holes by ear clipping algorithm
|
||||||
// vertices of all hole polys have to be in clockwise order
|
//first calls RemoveHoles to get rid of the holes, and then Triangulate_EC for each resulting polygon
|
||||||
// outpolys : a list of polygons without holes
|
//time complexity: O(h*(n^2)), h is the number of holes, n is the number of vertices
|
||||||
//returns 1 on success, 0 on failure
|
//space complexity: O(n)
|
||||||
int RemoveHoles(list<TPPLPoly> *inpolys, list<TPPLPoly> *outpolys);
|
//params:
|
||||||
|
// inpolys : a list of polygons to be triangulated (can contain holes)
|
||||||
//triangulates a polygon by ear clipping
|
// vertices of all non-hole polys have to be in counter-clockwise order
|
||||||
//time complexity O(n^2), n is the number of vertices
|
// vertices of all hole polys have to be in clockwise order
|
||||||
//space complexity: O(n)
|
// triangles : a list of triangles (result)
|
||||||
//params:
|
//returns 1 on success, 0 on failure
|
||||||
// poly : an input polygon to be triangulated
|
int Triangulate_EC(TPPLPolyList *inpolys, TPPLPolyList *triangles);
|
||||||
// vertices have to be in counter-clockwise order
|
|
||||||
// triangles : a list of triangles (result)
|
//creates an optimal polygon triangulation in terms of minimal edge length
|
||||||
//returns 1 on success, 0 on failure
|
//time complexity: O(n^3), n is the number of vertices
|
||||||
int Triangulate_EC(TPPLPoly *poly, list<TPPLPoly> *triangles);
|
//space complexity: O(n^2)
|
||||||
|
//params:
|
||||||
//triangulates a list of polygons that may contain holes by ear clipping algorithm
|
// poly : an input polygon to be triangulated
|
||||||
//first calls RemoveHoles to get rid of the holes, and then Triangulate_EC for each resulting polygon
|
// vertices have to be in counter-clockwise order
|
||||||
//time complexity: O(h*(n^2)), h is the number of holes, n is the number of vertices
|
// triangles : a list of triangles (result)
|
||||||
//space complexity: O(n)
|
//returns 1 on success, 0 on failure
|
||||||
//params:
|
int Triangulate_OPT(TPPLPoly *poly, TPPLPolyList *triangles);
|
||||||
// inpolys : a list of polygons to be triangulated (can contain holes)
|
|
||||||
// vertices of all non-hole polys have to be in counter-clockwise order
|
//triangulates a polygons by firstly partitioning it into monotone polygons
|
||||||
// vertices of all hole polys have to be in clockwise order
|
//time complexity: O(n*log(n)), n is the number of vertices
|
||||||
// triangles : a list of triangles (result)
|
//space complexity: O(n)
|
||||||
//returns 1 on success, 0 on failure
|
//params:
|
||||||
int Triangulate_EC(list<TPPLPoly> *inpolys, list<TPPLPoly> *triangles);
|
// poly : an input polygon to be triangulated
|
||||||
|
// vertices have to be in counter-clockwise order
|
||||||
//creates an optimal polygon triangulation in terms of minimal edge length
|
// triangles : a list of triangles (result)
|
||||||
//time complexity: O(n^3), n is the number of vertices
|
//returns 1 on success, 0 on failure
|
||||||
//space complexity: O(n^2)
|
int Triangulate_MONO(TPPLPoly *poly, TPPLPolyList *triangles);
|
||||||
//params:
|
|
||||||
// poly : an input polygon to be triangulated
|
//triangulates a list of polygons by firstly partitioning them into monotone polygons
|
||||||
// vertices have to be in counter-clockwise order
|
//time complexity: O(n*log(n)), n is the number of vertices
|
||||||
// triangles : a list of triangles (result)
|
//space complexity: O(n)
|
||||||
//returns 1 on success, 0 on failure
|
//params:
|
||||||
int Triangulate_OPT(TPPLPoly *poly, list<TPPLPoly> *triangles);
|
// inpolys : a list of polygons to be triangulated (can contain holes)
|
||||||
|
// vertices of all non-hole polys have to be in counter-clockwise order
|
||||||
//triangulates a polygons by firstly partitioning it into monotone polygons
|
// vertices of all hole polys have to be in clockwise order
|
||||||
//time complexity: O(n*log(n)), n is the number of vertices
|
// triangles : a list of triangles (result)
|
||||||
//space complexity: O(n)
|
//returns 1 on success, 0 on failure
|
||||||
//params:
|
int Triangulate_MONO(TPPLPolyList *inpolys, TPPLPolyList *triangles);
|
||||||
// poly : an input polygon to be triangulated
|
|
||||||
// vertices have to be in counter-clockwise order
|
//creates a monotone partition of a list of polygons that can contain holes
|
||||||
// triangles : a list of triangles (result)
|
//time complexity: O(n*log(n)), n is the number of vertices
|
||||||
//returns 1 on success, 0 on failure
|
//space complexity: O(n)
|
||||||
int Triangulate_MONO(TPPLPoly *poly, list<TPPLPoly> *triangles);
|
//params:
|
||||||
|
// inpolys : a list of polygons to be triangulated (can contain holes)
|
||||||
//triangulates a list of polygons by firstly partitioning them into monotone polygons
|
// vertices of all non-hole polys have to be in counter-clockwise order
|
||||||
//time complexity: O(n*log(n)), n is the number of vertices
|
// vertices of all hole polys have to be in clockwise order
|
||||||
//space complexity: O(n)
|
// monotonePolys : a list of monotone polygons (result)
|
||||||
//params:
|
//returns 1 on success, 0 on failure
|
||||||
// inpolys : a list of polygons to be triangulated (can contain holes)
|
int MonotonePartition(TPPLPolyList *inpolys, TPPLPolyList *monotonePolys);
|
||||||
// vertices of all non-hole polys have to be in counter-clockwise order
|
|
||||||
// vertices of all hole polys have to be in clockwise order
|
//partitions a polygon into convex polygons by using Hertel-Mehlhorn algorithm
|
||||||
// triangles : a list of triangles (result)
|
//the algorithm gives at most four times the number of parts as the optimal algorithm
|
||||||
//returns 1 on success, 0 on failure
|
//however, in practice it works much better than that and often gives optimal partition
|
||||||
int Triangulate_MONO(list<TPPLPoly> *inpolys, list<TPPLPoly> *triangles);
|
//uses triangulation obtained by ear clipping as intermediate result
|
||||||
|
//time complexity O(n^2), n is the number of vertices
|
||||||
//creates a monotone partition of a list of polygons that can contain holes
|
//space complexity: O(n)
|
||||||
//time complexity: O(n*log(n)), n is the number of vertices
|
//params:
|
||||||
//space complexity: O(n)
|
// poly : an input polygon to be partitioned
|
||||||
//params:
|
// vertices have to be in counter-clockwise order
|
||||||
// inpolys : a list of polygons to be triangulated (can contain holes)
|
// parts : resulting list of convex polygons
|
||||||
// vertices of all non-hole polys have to be in counter-clockwise order
|
//returns 1 on success, 0 on failure
|
||||||
// vertices of all hole polys have to be in clockwise order
|
int ConvexPartition_HM(TPPLPoly *poly, TPPLPolyList *parts);
|
||||||
// monotonePolys : a list of monotone polygons (result)
|
|
||||||
//returns 1 on success, 0 on failure
|
//partitions a list of polygons into convex parts by using Hertel-Mehlhorn algorithm
|
||||||
int MonotonePartition(list<TPPLPoly> *inpolys, list<TPPLPoly> *monotonePolys);
|
//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
|
||||||
//partitions a polygon into convex polygons by using Hertel-Mehlhorn algorithm
|
//uses triangulation obtained by ear clipping as intermediate result
|
||||||
//the algorithm gives at most four times the number of parts as the optimal algorithm
|
//time complexity O(n^2), n is the number of vertices
|
||||||
//however, in practice it works much better than that and often gives optimal partition
|
//space complexity: O(n)
|
||||||
//uses triangulation obtained by ear clipping as intermediate result
|
//params:
|
||||||
//time complexity O(n^2), n is the number of vertices
|
// inpolys : an input list of polygons to be partitioned
|
||||||
//space complexity: O(n)
|
// vertices of all non-hole polys have to be in counter-clockwise order
|
||||||
//params:
|
// vertices of all hole polys have to be in clockwise order
|
||||||
// poly : an input polygon to be partitioned
|
// parts : resulting list of convex polygons
|
||||||
// vertices have to be in counter-clockwise order
|
//returns 1 on success, 0 on failure
|
||||||
// parts : resulting list of convex polygons
|
int ConvexPartition_HM(TPPLPolyList *inpolys, TPPLPolyList *parts);
|
||||||
//returns 1 on success, 0 on failure
|
|
||||||
int ConvexPartition_HM(TPPLPoly *poly, list<TPPLPoly> *parts);
|
//optimal convex partitioning (in terms of number of resulting convex polygons)
|
||||||
|
//using the Keil-Snoeyink algorithm
|
||||||
//partitions a list of polygons into convex parts by using Hertel-Mehlhorn algorithm
|
//M. Keil, J. Snoeyink, "On the time bound for convex decomposition of simple polygons", 1998
|
||||||
//the algorithm gives at most four times the number of parts as the optimal algorithm
|
//time complexity O(n^3), n is the number of vertices
|
||||||
//however, in practice it works much better than that and often gives optimal partition
|
//space complexity: O(n^3)
|
||||||
//uses triangulation obtained by ear clipping as intermediate result
|
// poly : an input polygon to be partitioned
|
||||||
//time complexity O(n^2), n is the number of vertices
|
// vertices have to be in counter-clockwise order
|
||||||
//space complexity: O(n)
|
// parts : resulting list of convex polygons
|
||||||
//params:
|
//returns 1 on success, 0 on failure
|
||||||
// inpolys : an input list of polygons to be partitioned
|
int ConvexPartition_OPT(TPPLPoly *poly, TPPLPolyList *parts);
|
||||||
// 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<TPPLPoly> *inpolys, list<TPPLPoly> *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<TPPLPoly> *parts);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
||||||
|
@ -1959,7 +1959,7 @@ bool GLBed::on_init_from_file(const std::string& filename, bool useVBOs)
|
|||||||
{
|
{
|
||||||
model = Model::read_from_file(filename);
|
model = Model::read_from_file(filename);
|
||||||
}
|
}
|
||||||
catch (std::exception &e)
|
catch (std::exception & /* ex */)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -1978,7 +1978,7 @@ bool GLBed::on_init_from_file(const std::string& filename, bool useVBOs)
|
|||||||
else
|
else
|
||||||
m_volume.indexed_vertex_array.load_mesh_flat_shading(mesh);
|
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);
|
set_color(color, 4);
|
||||||
|
|
||||||
m_volume.bounding_box = m_volume.indexed_vertex_array.bounding_box();
|
m_volume.bounding_box = m_volume.indexed_vertex_array.bounding_box();
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
#include "GLCanvas3D.hpp"
|
#include "GLCanvas3D.hpp"
|
||||||
|
|
||||||
#include "admesh/stl.h"
|
#include "admesh/stl.h"
|
||||||
|
#include "polypartition.h"
|
||||||
#include "libslic3r/libslic3r.h"
|
#include "libslic3r/libslic3r.h"
|
||||||
#include "libslic3r/ClipperUtils.hpp"
|
#include "libslic3r/ClipperUtils.hpp"
|
||||||
#include "libslic3r/PrintConfig.hpp"
|
#include "libslic3r/PrintConfig.hpp"
|
||||||
@ -6431,6 +6432,219 @@ void GLCanvas3D::_render_camera_target() const
|
|||||||
}
|
}
|
||||||
#endif // ENABLE_SHOW_CAMERA_TARGET
|
#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<GLdouble> 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<double>(pt[0]));
|
||||||
|
coords.emplace_back(unscale<double>(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<double>(pt[0]));
|
||||||
|
coords.emplace_back(unscale<double>(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<Vec3d> 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<Vec3d> 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<TPPLPoly> input = expoly_to_polypartition_input(poly);
|
||||||
|
std::list<TPPLPoly> 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<double>(pt2->x), unscale<double>(pt2->y), z);
|
||||||
|
triangles.emplace_back(unscale<double>(pt1->x), unscale<double>(pt1->y), z);
|
||||||
|
triangles.emplace_back(unscale<double>(pt0->x), unscale<double>(pt0->y), z);
|
||||||
|
} else {
|
||||||
|
triangles.emplace_back(unscale<double>(pt0->x), unscale<double>(pt0->y), z);
|
||||||
|
triangles.emplace_back(unscale<double>(pt1->x), unscale<double>(pt1->y), z);
|
||||||
|
triangles.emplace_back(unscale<double>(pt2->x), unscale<double>(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
|
void GLCanvas3D::_render_sla_slices() const
|
||||||
{
|
{
|
||||||
if (!m_use_clipping_planes || wxGetApp().preset_bundle->printers.get_edited_preset().printer_technology() != ptSLA)
|
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];
|
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 shift_z = obj->get_current_elevation();
|
||||||
double min_z = clip_min_z - shift_z;
|
double min_z = clip_min_z - shift_z;
|
||||||
double max_z = clip_max_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_caps_bottom == m_sla_caps[0].triangles.end())
|
||||||
if (it != 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)) {
|
||||||
bottom_obj_triangles = it->second.object;
|
m_sla_caps[0].z = min_z;
|
||||||
bottom_sup_triangles = it->second.suppports;
|
it_caps_bottom->second.object.clear();
|
||||||
}
|
it_caps_bottom->second.supports.clear();
|
||||||
}
|
}
|
||||||
|
if (it_caps_top == m_sla_caps[1].triangles.end())
|
||||||
if (m_sla_caps[1].matches(max_z))
|
it_caps_top = m_sla_caps[1].triangles.emplace(i, SlaCap::Triangles()).first;
|
||||||
{
|
if (! m_sla_caps[1].matches(max_z)) {
|
||||||
SlaCap::ObjectIdToTrianglesMap::const_iterator it = m_sla_caps[1].triangles.find(i);
|
m_sla_caps[1].z = max_z;
|
||||||
if (it != m_sla_caps[1].triangles.end())
|
it_caps_top->second.object.clear();
|
||||||
{
|
it_caps_top->second.supports.clear();
|
||||||
top_obj_triangles = it->second.object;
|
|
||||||
top_sup_triangles = it->second.suppports;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
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<SLAPrintObject::Instance>& instances = obj->instances();
|
const std::vector<SLAPrintObject::Instance>& instances = obj->instances();
|
||||||
struct InstanceTransform
|
struct InstanceTransform
|
||||||
@ -6501,86 +6713,22 @@ void GLCanvas3D::_render_sla_slices() const
|
|||||||
|
|
||||||
if (it_min_z != index.end())
|
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()))
|
if (bottom_obj_triangles.empty() && (it_min_z->second.model_slices_idx < model_slices.size()))
|
||||||
{
|
bottom_obj_triangles = triangulate_expolygons(model_slices[it_min_z->second.model_slices_idx], min_z, true);
|
||||||
// calculate model bottom cap
|
// calculate support 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));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (bottom_sup_triangles.empty() && (it_min_z->second.support_slices_idx < support_slices.size()))
|
if (bottom_sup_triangles.empty() && (it_min_z->second.support_slices_idx < support_slices.size()))
|
||||||
{
|
bottom_sup_triangles = triangulate_expolygons(support_slices[it_min_z->second.support_slices_idx], min_z, true);
|
||||||
// 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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (it_max_z != index.end())
|
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()))
|
if (top_obj_triangles.empty() && (it_max_z->second.model_slices_idx < model_slices.size()))
|
||||||
{
|
top_obj_triangles = triangulate_expolygons(model_slices[it_max_z->second.model_slices_idx], max_z, false);
|
||||||
// calculate model top cap
|
// calculate support 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));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (top_sup_triangles.empty() && (it_max_z->second.support_slices_idx < support_slices.size()))
|
if (top_sup_triangles.empty() && (it_max_z->second.support_slices_idx < support_slices.size()))
|
||||||
{
|
top_sup_triangles = triangulate_expolygons(support_slices[it_max_z->second.support_slices_idx], max_z, false);
|
||||||
// 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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -780,7 +780,7 @@ private:
|
|||||||
struct Triangles
|
struct Triangles
|
||||||
{
|
{
|
||||||
Pointf3s object;
|
Pointf3s object;
|
||||||
Pointf3s suppports;
|
Pointf3s supports;
|
||||||
};
|
};
|
||||||
typedef std::map<unsigned int, Triangles> ObjectIdToTrianglesMap;
|
typedef std::map<unsigned int, Triangles> ObjectIdToTrianglesMap;
|
||||||
double z;
|
double z;
|
||||||
|
@ -245,8 +245,6 @@ void show_info(wxWindow* parent, const wxString& message, const wxString& title)
|
|||||||
|
|
||||||
void warning_catcher(wxWindow* parent, const wxString& message)
|
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);
|
wxMessageDialog msg(parent, message, _(L("Warning")), wxOK | wxICON_WARNING);
|
||||||
msg.ShowModal();
|
msg.ShowModal();
|
||||||
}
|
}
|
||||||
|
@ -30,6 +30,10 @@ PrintHostSendDialog::PrintHostSendDialog(const fs::path &path)
|
|||||||
, txt_filename(new wxTextCtrl(this, wxID_ANY, path.filename().wstring()))
|
, txt_filename(new wxTextCtrl(this, wxID_ANY, path.filename().wstring()))
|
||||||
, box_print(new wxCheckBox(this, wxID_ANY, _(L("Start printing after upload"))))
|
, 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.")));
|
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);
|
label_dir_hint->Wrap(CONTENT_WIDTH);
|
||||||
|
|
||||||
|
@ -5,7 +5,7 @@ use warnings;
|
|||||||
|
|
||||||
use List::Util qw(first sum);
|
use List::Util qw(first sum);
|
||||||
use Slic3r::XS;
|
use Slic3r::XS;
|
||||||
use Test::More tests => 33;
|
use Test::More tests => 31;
|
||||||
|
|
||||||
use constant PI => 4 * atan2(1, 1);
|
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';
|
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__
|
__END__
|
||||||
|
@ -31,14 +31,10 @@
|
|||||||
Polygons simplify_p(double tolerance);
|
Polygons simplify_p(double tolerance);
|
||||||
Polylines medial_axis(double max_width, double min_width)
|
Polylines medial_axis(double max_width, double min_width)
|
||||||
%code{% THIS->medial_axis(max_width, min_width, &RETVAL); %};
|
%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)
|
Polygons get_trapezoids2(double angle)
|
||||||
%code{% THIS->get_trapezoids2(&RETVAL, angle); %};
|
%code{% THIS->get_trapezoids2(&RETVAL, angle); %};
|
||||||
Polygons triangulate()
|
Polygons triangulate()
|
||||||
%code{% THIS->triangulate(&RETVAL); %};
|
%code{% THIS->triangulate(&RETVAL); %};
|
||||||
Polygons triangulate_pp()
|
|
||||||
%code{% THIS->triangulate_pp(&RETVAL); %};
|
|
||||||
%{
|
%{
|
||||||
|
|
||||||
ExPolygon*
|
ExPolygon*
|
||||||
|
Loading…
Reference in New Issue
Block a user