2014-04-28 18:14:20 +00:00
|
|
|
#include "BoundingBox.hpp"
|
2013-07-16 19:04:14 +00:00
|
|
|
#include "ExPolygon.hpp"
|
2014-01-09 18:56:12 +00:00
|
|
|
#include "Geometry.hpp"
|
2013-07-16 19:04:14 +00:00
|
|
|
#include "Polygon.hpp"
|
2014-01-09 16:26:39 +00:00
|
|
|
#include "Line.hpp"
|
2013-11-21 14:12:06 +00:00
|
|
|
#include "ClipperUtils.hpp"
|
2014-04-25 10:40:21 +00:00
|
|
|
#include "polypartition.h"
|
2014-05-01 10:07:11 +00:00
|
|
|
#include "poly2tri/poly2tri.h"
|
2014-04-25 10:40:21 +00:00
|
|
|
|
2014-04-28 18:14:20 +00:00
|
|
|
#include <algorithm>
|
2014-04-25 10:40:21 +00:00
|
|
|
#include <list>
|
2013-07-16 19:04:14 +00:00
|
|
|
|
|
|
|
namespace Slic3r {
|
|
|
|
|
2014-01-09 16:26:39 +00:00
|
|
|
ExPolygon::operator Points() const
|
|
|
|
{
|
|
|
|
Points points;
|
|
|
|
Polygons pp = *this;
|
|
|
|
for (Polygons::const_iterator poly = pp.begin(); poly != pp.end(); ++poly) {
|
|
|
|
for (Points::const_iterator point = poly->points.begin(); point != poly->points.end(); ++point)
|
|
|
|
points.push_back(*point);
|
|
|
|
}
|
|
|
|
return points;
|
|
|
|
}
|
|
|
|
|
2013-11-21 14:12:06 +00:00
|
|
|
ExPolygon::operator Polygons() const
|
|
|
|
{
|
2014-01-09 16:26:39 +00:00
|
|
|
Polygons polygons;
|
2014-01-16 18:02:50 +00:00
|
|
|
polygons.reserve(this->holes.size() + 1);
|
2013-11-21 14:12:06 +00:00
|
|
|
polygons.push_back(this->contour);
|
|
|
|
for (Polygons::const_iterator it = this->holes.begin(); it != this->holes.end(); ++it) {
|
|
|
|
polygons.push_back(*it);
|
|
|
|
}
|
|
|
|
return polygons;
|
|
|
|
}
|
|
|
|
|
2013-07-16 19:04:14 +00:00
|
|
|
void
|
|
|
|
ExPolygon::scale(double factor)
|
|
|
|
{
|
|
|
|
contour.scale(factor);
|
|
|
|
for (Polygons::iterator it = holes.begin(); it != holes.end(); ++it) {
|
|
|
|
(*it).scale(factor);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
ExPolygon::translate(double x, double y)
|
|
|
|
{
|
|
|
|
contour.translate(x, y);
|
|
|
|
for (Polygons::iterator it = holes.begin(); it != holes.end(); ++it) {
|
|
|
|
(*it).translate(x, y);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2014-04-24 11:43:24 +00:00
|
|
|
ExPolygon::rotate(double angle, const Point ¢er)
|
2013-07-16 19:04:14 +00:00
|
|
|
{
|
|
|
|
contour.rotate(angle, center);
|
|
|
|
for (Polygons::iterator it = holes.begin(); it != holes.end(); ++it) {
|
|
|
|
(*it).rotate(angle, center);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-08-26 20:50:26 +00:00
|
|
|
double
|
|
|
|
ExPolygon::area() const
|
|
|
|
{
|
|
|
|
double a = this->contour.area();
|
|
|
|
for (Polygons::const_iterator it = this->holes.begin(); it != this->holes.end(); ++it) {
|
|
|
|
a -= -(*it).area(); // holes have negative area
|
|
|
|
}
|
|
|
|
return a;
|
|
|
|
}
|
|
|
|
|
2013-08-26 21:27:51 +00:00
|
|
|
bool
|
|
|
|
ExPolygon::is_valid() const
|
|
|
|
{
|
|
|
|
if (!this->contour.is_valid() || !this->contour.is_counter_clockwise()) return false;
|
|
|
|
for (Polygons::const_iterator it = this->holes.begin(); it != this->holes.end(); ++it) {
|
|
|
|
if (!(*it).is_valid() || (*it).is_counter_clockwise()) return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2013-11-21 14:12:06 +00:00
|
|
|
bool
|
2014-04-24 14:40:10 +00:00
|
|
|
ExPolygon::contains_line(const Line &line) const
|
2013-11-21 14:12:06 +00:00
|
|
|
{
|
2014-01-16 18:02:50 +00:00
|
|
|
Polylines pl;
|
2014-04-24 14:40:10 +00:00
|
|
|
pl.push_back(line);
|
2013-11-21 14:12:06 +00:00
|
|
|
|
|
|
|
Polylines pl_out;
|
|
|
|
diff(pl, *this, pl_out);
|
|
|
|
return pl_out.empty();
|
|
|
|
}
|
|
|
|
|
2013-11-21 15:21:42 +00:00
|
|
|
bool
|
2014-04-24 14:40:10 +00:00
|
|
|
ExPolygon::contains_point(const Point &point) const
|
2013-11-21 15:21:42 +00:00
|
|
|
{
|
|
|
|
if (!this->contour.contains_point(point)) return false;
|
|
|
|
for (Polygons::const_iterator it = this->holes.begin(); it != this->holes.end(); ++it) {
|
|
|
|
if (it->contains_point(point)) return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2013-11-21 19:25:24 +00:00
|
|
|
Polygons
|
2013-11-22 01:16:10 +00:00
|
|
|
ExPolygon::simplify_p(double tolerance) const
|
2013-11-21 19:25:24 +00:00
|
|
|
{
|
2014-01-16 18:02:50 +00:00
|
|
|
Polygons pp;
|
|
|
|
pp.reserve(this->holes.size() + 1);
|
2013-11-22 01:16:10 +00:00
|
|
|
|
|
|
|
// contour
|
|
|
|
Polygon p = this->contour;
|
|
|
|
p.points = MultiPoint::_douglas_peucker(p.points, tolerance);
|
|
|
|
pp.push_back(p);
|
|
|
|
|
|
|
|
// holes
|
|
|
|
for (Polygons::const_iterator it = this->holes.begin(); it != this->holes.end(); ++it) {
|
|
|
|
p = *it;
|
|
|
|
p.points = MultiPoint::_douglas_peucker(p.points, tolerance);
|
|
|
|
pp.push_back(p);
|
|
|
|
}
|
|
|
|
simplify_polygons(pp, pp);
|
|
|
|
return pp;
|
2013-11-21 19:25:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
ExPolygons
|
|
|
|
ExPolygon::simplify(double tolerance) const
|
|
|
|
{
|
2013-11-22 01:16:10 +00:00
|
|
|
Polygons pp = this->simplify_p(tolerance);
|
|
|
|
ExPolygons expp;
|
|
|
|
union_(pp, expp);
|
|
|
|
return expp;
|
2013-11-21 19:25:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
ExPolygon::simplify(double tolerance, ExPolygons &expolygons) const
|
|
|
|
{
|
|
|
|
ExPolygons ep = this->simplify(tolerance);
|
|
|
|
expolygons.reserve(expolygons.size() + ep.size());
|
|
|
|
expolygons.insert(expolygons.end(), ep.begin(), ep.end());
|
|
|
|
}
|
|
|
|
|
2014-01-09 16:26:39 +00:00
|
|
|
void
|
2014-03-09 16:46:02 +00:00
|
|
|
ExPolygon::medial_axis(double max_width, double min_width, Polylines* polylines) const
|
2014-01-09 16:26:39 +00:00
|
|
|
{
|
2014-01-09 18:56:12 +00:00
|
|
|
// init helper object
|
2014-03-09 16:46:02 +00:00
|
|
|
Slic3r::Geometry::MedialAxis ma(max_width, min_width);
|
2014-01-09 18:56:12 +00:00
|
|
|
|
2014-01-09 16:26:39 +00:00
|
|
|
// populate list of segments for the Voronoi diagram
|
2014-03-09 16:46:02 +00:00
|
|
|
this->contour.lines(&ma.lines);
|
|
|
|
for (Polygons::const_iterator hole = this->holes.begin(); hole != this->holes.end(); ++hole)
|
|
|
|
hole->lines(&ma.lines);
|
2014-01-09 16:26:39 +00:00
|
|
|
|
|
|
|
// compute the Voronoi diagram
|
2014-01-09 18:56:12 +00:00
|
|
|
ma.build(polylines);
|
2014-01-09 16:26:39 +00:00
|
|
|
|
2014-03-15 15:53:20 +00:00
|
|
|
// extend initial and final segments of each polyline (they will be clipped)
|
2014-05-21 13:03:31 +00:00
|
|
|
// unless they represent closed loops
|
2014-03-15 15:53:20 +00:00
|
|
|
for (Polylines::iterator polyline = polylines->begin(); polyline != polylines->end(); ++polyline) {
|
2014-05-21 13:03:31 +00:00
|
|
|
if (polyline->points.front().coincides_with(polyline->points.back())) continue;
|
2014-03-15 15:53:20 +00:00
|
|
|
polyline->extend_start(max_width);
|
|
|
|
polyline->extend_end(max_width);
|
|
|
|
}
|
|
|
|
|
2014-01-09 16:26:39 +00:00
|
|
|
// clip segments to our expolygon area
|
|
|
|
intersection(*polylines, *this, *polylines);
|
|
|
|
}
|
|
|
|
|
2014-04-24 11:43:24 +00:00
|
|
|
void
|
|
|
|
ExPolygon::get_trapezoids(Polygons* polygons) const
|
|
|
|
{
|
|
|
|
ExPolygons expp;
|
|
|
|
expp.push_back(*this);
|
|
|
|
boost::polygon::get_trapezoids(*polygons, expp);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
ExPolygon::get_trapezoids(Polygons* polygons, double angle) const
|
|
|
|
{
|
|
|
|
ExPolygon clone = *this;
|
|
|
|
clone.rotate(PI/2 - angle, Point(0,0));
|
|
|
|
clone.get_trapezoids(polygons);
|
|
|
|
for (Polygons::iterator polygon = polygons->begin(); polygon != polygons->end(); ++polygon)
|
|
|
|
polygon->rotate(-(PI/2 - angle), Point(0,0));
|
|
|
|
}
|
|
|
|
|
2014-04-28 18:14:20 +00:00
|
|
|
// This algorithm may return more trapezoids than necessary
|
|
|
|
// (i.e. it may break a single trapezoid in several because
|
|
|
|
// other parts of the object have x coordinates in the middle)
|
|
|
|
void
|
|
|
|
ExPolygon::get_trapezoids2(Polygons* polygons) const
|
|
|
|
{
|
|
|
|
// get all points of this ExPolygon
|
|
|
|
Points pp = *this;
|
|
|
|
|
|
|
|
// build our bounding box
|
|
|
|
BoundingBox bb(pp);
|
|
|
|
|
|
|
|
// get all x coordinates
|
|
|
|
std::vector<coord_t> xx;
|
|
|
|
xx.reserve(pp.size());
|
|
|
|
for (Points::const_iterator p = pp.begin(); p != pp.end(); ++p)
|
|
|
|
xx.push_back(p->x);
|
|
|
|
std::sort(xx.begin(), xx.end());
|
|
|
|
|
|
|
|
// find trapezoids by looping from first to next-to-last coordinate
|
|
|
|
for (std::vector<coord_t>::const_iterator x = xx.begin(); x != xx.end()-1; ++x) {
|
|
|
|
coord_t next_x = *(x + 1);
|
|
|
|
if (*x == next_x) continue;
|
|
|
|
|
|
|
|
// build rectangle
|
|
|
|
Polygon poly;
|
|
|
|
poly.points.resize(4);
|
|
|
|
poly[0].x = *x;
|
|
|
|
poly[0].y = bb.min.y;
|
|
|
|
poly[1].x = next_x;
|
|
|
|
poly[1].y = bb.min.y;
|
|
|
|
poly[2].x = next_x;
|
|
|
|
poly[2].y = bb.max.y;
|
|
|
|
poly[3].x = *x;
|
|
|
|
poly[3].y = bb.max.y;
|
|
|
|
|
|
|
|
// intersect with this expolygon
|
|
|
|
Polygons trapezoids;
|
2014-05-08 09:07:37 +00:00
|
|
|
intersection<Polygons,Polygons>(poly, *this, trapezoids);
|
2014-04-28 18:14:20 +00:00
|
|
|
|
|
|
|
// append results to return value
|
|
|
|
polygons->insert(polygons->end(), trapezoids.begin(), trapezoids.end());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
ExPolygon::get_trapezoids2(Polygons* polygons, double angle) const
|
|
|
|
{
|
|
|
|
ExPolygon clone = *this;
|
|
|
|
clone.rotate(PI/2 - angle, Point(0,0));
|
|
|
|
clone.get_trapezoids2(polygons);
|
|
|
|
for (Polygons::iterator polygon = polygons->begin(); polygon != polygons->end(); ++polygon)
|
|
|
|
polygon->rotate(-(PI/2 - angle), Point(0,0));
|
|
|
|
}
|
|
|
|
|
2014-05-01 08:37:38 +00:00
|
|
|
// While this triangulates successfully, it's NOT a constrained triangulation
|
|
|
|
// as it will create more vertices on the boundaries than the ones supplied.
|
2014-04-24 15:06:16 +00:00
|
|
|
void
|
|
|
|
ExPolygon::triangulate(Polygons* polygons) const
|
|
|
|
{
|
|
|
|
// first make trapezoids
|
|
|
|
Polygons trapezoids;
|
2014-04-28 18:19:26 +00:00
|
|
|
this->get_trapezoids2(&trapezoids);
|
2014-04-24 15:06:16 +00:00
|
|
|
|
|
|
|
// then triangulate each trapezoid
|
|
|
|
for (Polygons::iterator polygon = trapezoids.begin(); polygon != trapezoids.end(); ++polygon)
|
|
|
|
polygon->triangulate_convex(polygons);
|
|
|
|
}
|
|
|
|
|
2014-04-25 10:40:21 +00:00
|
|
|
void
|
2014-05-01 08:37:38 +00:00
|
|
|
ExPolygon::triangulate_pp(Polygons* polygons) const
|
2014-04-25 10:40:21 +00:00
|
|
|
{
|
|
|
|
// convert polygons
|
|
|
|
std::list<TPPLPoly> input;
|
|
|
|
|
2014-05-01 08:37:38 +00:00
|
|
|
Polygons pp = *this;
|
|
|
|
simplify_polygons(pp, pp, true);
|
|
|
|
ExPolygons expp;
|
|
|
|
union_(pp, expp);
|
|
|
|
|
|
|
|
for (ExPolygons::const_iterator ex = expp.begin(); ex != expp.end(); ++ex) {
|
|
|
|
// contour
|
|
|
|
{
|
|
|
|
TPPLPoly p;
|
|
|
|
p.Init(ex->contour.points.size());
|
|
|
|
//printf("%zu\n0\n", ex->contour.points.size());
|
|
|
|
for (Points::const_iterator point = ex->contour.points.begin(); point != ex->contour.points.end(); ++point) {
|
|
|
|
p[ point-ex->contour.points.begin() ].x = point->x;
|
|
|
|
p[ point-ex->contour.points.begin() ].y = point->y;
|
|
|
|
//printf("%ld %ld\n", point->x, point->y);
|
|
|
|
}
|
|
|
|
p.SetHole(false);
|
|
|
|
input.push_back(p);
|
2014-04-25 10:40:21 +00:00
|
|
|
}
|
|
|
|
|
2014-05-01 08:37:38 +00:00
|
|
|
// holes
|
|
|
|
for (Polygons::const_iterator hole = ex->holes.begin(); hole != ex->holes.end(); ++hole) {
|
|
|
|
TPPLPoly p;
|
|
|
|
p.Init(hole->points.size());
|
|
|
|
//printf("%zu\n1\n", hole->points.size());
|
|
|
|
for (Points::const_iterator point = hole->points.begin(); point != hole->points.end(); ++point) {
|
|
|
|
p[ point-hole->points.begin() ].x = point->x;
|
|
|
|
p[ point-hole->points.begin() ].y = point->y;
|
|
|
|
//printf("%ld %ld\n", point->x, point->y);
|
|
|
|
}
|
|
|
|
p.SetHole(true);
|
|
|
|
input.push_back(p);
|
2014-04-25 10:40:21 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// perform triangulation
|
|
|
|
std::list<TPPLPoly> output;
|
|
|
|
int res = TPPLPartition().Triangulate_MONO(&input, &output);
|
|
|
|
if (res != 1) CONFESS("Triangulation failed");
|
|
|
|
|
|
|
|
// convert output polygons
|
|
|
|
for (std::list<TPPLPoly>::iterator poly = output.begin(); poly != output.end(); ++poly) {
|
|
|
|
long num_points = poly->GetNumPoints();
|
|
|
|
Polygon p;
|
|
|
|
p.points.resize(num_points);
|
|
|
|
for (long i = 0; i < num_points; ++i) {
|
|
|
|
p.points[i].x = (*poly)[i].x;
|
|
|
|
p.points[i].y = (*poly)[i].y;
|
|
|
|
}
|
|
|
|
polygons->push_back(p);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-05-01 10:07:11 +00:00
|
|
|
void
|
|
|
|
ExPolygon::triangulate_p2t(Polygons* polygons) const
|
|
|
|
{
|
|
|
|
ExPolygons expp;
|
|
|
|
simplify_polygons(*this, expp, true);
|
|
|
|
|
|
|
|
for (ExPolygons::const_iterator ex = expp.begin(); ex != expp.end(); ++ex) {
|
|
|
|
p2t::CDT* cdt;
|
|
|
|
|
|
|
|
// TODO: prevent duplicate points
|
|
|
|
|
|
|
|
// contour
|
|
|
|
{
|
|
|
|
std::vector<p2t::Point*> points;
|
|
|
|
for (Points::const_iterator point = ex->contour.points.begin(); point != ex->contour.points.end(); ++point) {
|
|
|
|
points.push_back(new p2t::Point(point->x, point->y));
|
|
|
|
}
|
|
|
|
cdt = new p2t::CDT(points);
|
|
|
|
}
|
|
|
|
|
|
|
|
// holes
|
|
|
|
for (Polygons::const_iterator hole = ex->holes.begin(); hole != ex->holes.end(); ++hole) {
|
|
|
|
std::vector<p2t::Point*> points;
|
|
|
|
for (Points::const_iterator point = hole->points.begin(); point != hole->points.end(); ++point) {
|
|
|
|
points.push_back(new p2t::Point(point->x, point->y));
|
|
|
|
}
|
|
|
|
cdt->AddHole(points);
|
|
|
|
}
|
|
|
|
|
|
|
|
// perform triangulation
|
|
|
|
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 (int i = 0; i <= 2; ++i) {
|
|
|
|
p2t::Point* point = (*triangle)->GetPoint(i);
|
|
|
|
p.points.push_back(Point(point->x, point->y));
|
|
|
|
}
|
|
|
|
polygons->push_back(p);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-09-13 12:48:40 +00:00
|
|
|
#ifdef SLIC3RXS
|
2014-04-27 17:18:53 +00:00
|
|
|
|
|
|
|
REGISTER_CLASS(ExPolygon, "ExPolygon");
|
|
|
|
|
2013-07-16 19:04:14 +00:00
|
|
|
SV*
|
2013-09-09 20:27:58 +00:00
|
|
|
ExPolygon::to_AV() {
|
2013-07-16 19:04:14 +00:00
|
|
|
const unsigned int num_holes = this->holes.size();
|
|
|
|
AV* av = newAV();
|
|
|
|
av_extend(av, num_holes); // -1 +1
|
|
|
|
|
2014-05-08 12:52:48 +00:00
|
|
|
av_store(av, 0, perl_to_SV_ref(this->contour));
|
2013-07-16 19:04:14 +00:00
|
|
|
|
|
|
|
for (unsigned int i = 0; i < num_holes; i++) {
|
2014-05-08 12:52:48 +00:00
|
|
|
av_store(av, i+1, perl_to_SV_ref(this->holes[i]));
|
2013-07-16 19:04:14 +00:00
|
|
|
}
|
|
|
|
return newRV_noinc((SV*)av);
|
|
|
|
}
|
|
|
|
|
|
|
|
SV*
|
2013-09-03 17:26:58 +00:00
|
|
|
ExPolygon::to_SV_pureperl() const
|
2013-07-16 19:04:14 +00:00
|
|
|
{
|
|
|
|
const unsigned int num_holes = this->holes.size();
|
|
|
|
AV* av = newAV();
|
|
|
|
av_extend(av, num_holes); // -1 +1
|
|
|
|
av_store(av, 0, this->contour.to_SV_pureperl());
|
|
|
|
for (unsigned int i = 0; i < num_holes; i++) {
|
|
|
|
av_store(av, i+1, this->holes[i].to_SV_pureperl());
|
|
|
|
}
|
|
|
|
return newRV_noinc((SV*)av);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
ExPolygon::from_SV(SV* expoly_sv)
|
|
|
|
{
|
|
|
|
AV* expoly_av = (AV*)SvRV(expoly_sv);
|
|
|
|
const unsigned int num_polygons = av_len(expoly_av)+1;
|
|
|
|
this->holes.resize(num_polygons-1);
|
|
|
|
|
|
|
|
SV** polygon_sv = av_fetch(expoly_av, 0, 0);
|
|
|
|
this->contour.from_SV(*polygon_sv);
|
|
|
|
for (unsigned int i = 0; i < num_polygons-1; i++) {
|
|
|
|
polygon_sv = av_fetch(expoly_av, i+1, 0);
|
|
|
|
this->holes[i].from_SV(*polygon_sv);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
ExPolygon::from_SV_check(SV* expoly_sv)
|
|
|
|
{
|
|
|
|
if (sv_isobject(expoly_sv) && (SvTYPE(SvRV(expoly_sv)) == SVt_PVMG)) {
|
2014-04-27 17:18:53 +00:00
|
|
|
if (!sv_isa(expoly_sv, perl_class_name(this)) && !sv_isa(expoly_sv, perl_class_name_ref(this)))
|
|
|
|
CONFESS("Not a valid %s object", perl_class_name(this));
|
2013-07-16 19:04:14 +00:00
|
|
|
// a XS ExPolygon was supplied
|
|
|
|
*this = *(ExPolygon *)SvIV((SV*)SvRV( expoly_sv ));
|
|
|
|
} else {
|
|
|
|
// a Perl arrayref was supplied
|
|
|
|
this->from_SV(expoly_sv);
|
|
|
|
}
|
|
|
|
}
|
2013-09-13 12:48:40 +00:00
|
|
|
#endif
|
2013-07-16 19:04:14 +00:00
|
|
|
|
|
|
|
}
|