Refactored Clipper wrapper functions

This commit is contained in:
Alessandro Ranellucci 2016-11-21 18:30:35 +01:00
parent be00f64243
commit 9fcd7f38de
27 changed files with 449 additions and 767 deletions

View File

@ -5,9 +5,9 @@ use warnings;
require Exporter; require Exporter;
our @ISA = qw(Exporter); our @ISA = qw(Exporter);
our @EXPORT_OK = qw(offset offset_ex our @EXPORT_OK = qw(offset offset_ex
diff_ex diff union_ex intersection_ex xor_ex JT_ROUND JT_MITER diff_ex diff union_ex intersection_ex JT_ROUND JT_MITER
JT_SQUARE is_counter_clockwise union_pt offset2 offset2_ex JT_SQUARE is_counter_clockwise union_pt offset2 offset2_ex
intersection intersection_pl diff_pl union CLIPPER_OFFSET_SCALE intersection intersection_pl diff_pl union CLIPPER_OFFSET_SCALE
union_pt_chained diff_ppl intersection_ppl); union_pt_chained intersection_ppl);
1; 1;

View File

@ -30,12 +30,11 @@ BridgeDetector::BridgeDetector(const ExPolygon &_expolygon, const ExPolygonColle
{ {
/* outset our bridge by an arbitrary amout; we'll use this outer margin /* outset our bridge by an arbitrary amout; we'll use this outer margin
for detecting anchors */ for detecting anchors */
Polygons grown; Polygons grown = offset(this->expolygon, this->extrusion_width);
offset((Polygons)this->expolygon, &grown, this->extrusion_width);
// detect what edges lie on lower slices by turning bridge contour and holes // detect what edges lie on lower slices by turning bridge contour and holes
// into polylines and then clipping them with each lower slice's contour // into polylines and then clipping them with each lower slice's contour
intersection(grown, this->lower_slices.contours(), &this->_edges); this->_edges = intersection_pl(grown, this->lower_slices.contours());
#ifdef SLIC3R_DEBUG #ifdef SLIC3R_DEBUG
printf(" bridge has %zu support(s)\n", this->_edges.size()); printf(" bridge has %zu support(s)\n", this->_edges.size());
@ -43,7 +42,7 @@ BridgeDetector::BridgeDetector(const ExPolygon &_expolygon, const ExPolygonColle
// detect anchors as intersection between our bridge expolygon and the lower slices // detect anchors as intersection between our bridge expolygon and the lower slices
// safety offset required to avoid Clipper from detecting empty intersection while Boost actually found some edges // safety offset required to avoid Clipper from detecting empty intersection while Boost actually found some edges
intersection(grown, this->lower_slices, &this->_anchors, true); this->_anchors = intersection_ex(grown, this->lower_slices, true);
/* /*
if (0) { if (0) {
@ -65,8 +64,7 @@ BridgeDetector::detect_angle()
/* Outset the bridge expolygon by half the amount we used for detecting anchors; /* Outset the bridge expolygon by half the amount we used for detecting anchors;
we'll use this one to clip our test lines and be sure that their endpoints we'll use this one to clip our test lines and be sure that their endpoints
are inside the anchors and not on their contours leading to false negatives. */ are inside the anchors and not on their contours leading to false negatives. */
Polygons clip_area; Polygons clip_area = offset(this->expolygon, +this->extrusion_width/2);
offset(this->expolygon, &clip_area, +this->extrusion_width/2);
/* we'll now try several directions using a rudimentary visibility check: /* we'll now try several directions using a rudimentary visibility check:
bridge in several directions and then sum the length of lines having both bridge in several directions and then sum the length of lines having both
@ -131,8 +129,7 @@ BridgeDetector::detect_angle()
for (coord_t y = bb.min.y; y <= bb.max.y; y += line_increment) for (coord_t y = bb.min.y; y <= bb.max.y; y += line_increment)
lines.push_back(Line(Point(bb.min.x, y), Point(bb.max.x, y))); lines.push_back(Line(Point(bb.min.x, y), Point(bb.max.x, y)));
Lines clipped_lines; Lines clipped_lines = intersection_ln(lines, my_clip_area);
intersection(lines, my_clip_area, &clipped_lines);
// remove any line not having both endpoints within anchors // remove any line not having both endpoints within anchors
for (size_t i = 0; i < clipped_lines.size(); ++i) { for (size_t i = 0; i < clipped_lines.size(); ++i) {
@ -194,11 +191,11 @@ BridgeDetector::detect_angle()
return true; return true;
} }
void Polygons
BridgeDetector::coverage(double angle, Polygons* coverage) const BridgeDetector::coverage(double angle) const
{ {
if (angle == -1) angle = this->angle; if (angle == -1) angle = this->angle;
if (angle == -1) return; if (angle == -1) return Polygons();
// Clone our expolygon and rotate it so that we work with vertical lines. // Clone our expolygon and rotate it so that we work with vertical lines.
ExPolygon expolygon = this->expolygon; ExPolygon expolygon = this->expolygon;
@ -207,8 +204,7 @@ BridgeDetector::coverage(double angle, Polygons* coverage) const
/* Outset the bridge expolygon by half the amount we used for detecting anchors; /* Outset the bridge expolygon by half the amount we used for detecting anchors;
we'll use this one to generate our trapezoids and be sure that their vertices we'll use this one to generate our trapezoids and be sure that their vertices
are inside the anchors and not on their contours leading to false negatives. */ are inside the anchors and not on their contours leading to false negatives. */
ExPolygons grown; ExPolygons grown = offset_ex(expolygon, this->extrusion_width/2.0);
offset(expolygon, &grown, this->extrusion_width/2.0);
// Compute trapezoids according to a vertical orientation // Compute trapezoids according to a vertical orientation
Polygons trapezoids; Polygons trapezoids;
@ -226,9 +222,7 @@ BridgeDetector::coverage(double angle, Polygons* coverage) const
Polygons covered; Polygons covered;
for (Polygons::const_iterator trapezoid = trapezoids.begin(); trapezoid != trapezoids.end(); ++trapezoid) { for (Polygons::const_iterator trapezoid = trapezoids.begin(); trapezoid != trapezoids.end(); ++trapezoid) {
Lines lines = trapezoid->lines(); Lines supported = intersection_ln(trapezoid->lines(), anchors);
Lines supported;
intersection(lines, anchors, &supported);
// not nice, we need a more robust non-numeric check // not nice, we need a more robust non-numeric check
for (size_t i = 0; i < supported.size(); ++i) { for (size_t i = 0; i < supported.size(); ++i) {
@ -242,14 +236,13 @@ BridgeDetector::coverage(double angle, Polygons* coverage) const
} }
// merge trapezoids and rotate them back // merge trapezoids and rotate them back
Polygons _coverage; Polygons _coverage = union_(covered);
union_(covered, &_coverage);
for (Polygons::iterator p = _coverage.begin(); p != _coverage.end(); ++p) for (Polygons::iterator p = _coverage.begin(); p != _coverage.end(); ++p)
p->rotate(-(PI/2.0 - angle), Point(0,0)); p->rotate(-(PI/2.0 - angle), Point(0,0));
// intersect trapezoids with actual bridge area to remove extra margins // intersect trapezoids with actual bridge area to remove extra margins
// and append it to result // and append it to result
intersection(_coverage, this->expolygon, coverage); return intersection(_coverage, this->expolygon);
/* /*
if (0) { if (0) {
@ -268,22 +261,14 @@ BridgeDetector::coverage(double angle, Polygons* coverage) const
*/ */
} }
Polygons
BridgeDetector::coverage(double angle) const
{
Polygons pp;
this->coverage(angle, &pp);
return pp;
}
/* This method returns the bridge edges (as polylines) that are not supported /* This method returns the bridge edges (as polylines) that are not supported
but would allow the entire bridge area to be bridged with detected angle but would allow the entire bridge area to be bridged with detected angle
if supported too */ if supported too */
void Polylines
BridgeDetector::unsupported_edges(double angle, Polylines* unsupported) const BridgeDetector::unsupported_edges(double angle) const
{ {
if (angle == -1) angle = this->angle; if (angle == -1) angle = this->angle;
if (angle == -1) return; if (angle == -1) return Polylines();
// get bridge edges (both contour and holes) // get bridge edges (both contour and holes)
Polylines bridge_edges; Polylines bridge_edges;
@ -293,10 +278,10 @@ BridgeDetector::unsupported_edges(double angle, Polylines* unsupported) const
} }
// get unsupported edges // get unsupported edges
Polygons grown_lower; Polylines _unsupported = diff_pl(
offset(this->lower_slices, &grown_lower, +this->extrusion_width); bridge_edges,
Polylines _unsupported; offset(this->lower_slices, +this->extrusion_width)
diff(bridge_edges, grown_lower, &_unsupported); );
/* Split into individual segments and filter out edges parallel to the bridging angle /* Split into individual segments and filter out edges parallel to the bridging angle
TODO: angle tolerance should probably be based on segment length and flow width, TODO: angle tolerance should probably be based on segment length and flow width,
@ -304,13 +289,15 @@ BridgeDetector::unsupported_edges(double angle, Polylines* unsupported) const
extrusions would be anchored within such length (i.e. a slightly non-parallel bridging extrusions would be anchored within such length (i.e. a slightly non-parallel bridging
direction might still benefit from anchors if long enough) direction might still benefit from anchors if long enough)
double angle_tolerance = PI / 180.0 * 5.0; */ double angle_tolerance = PI / 180.0 * 5.0; */
Polylines unsupported;
for (Polylines::const_iterator polyline = _unsupported.begin(); polyline != _unsupported.end(); ++polyline) { for (Polylines::const_iterator polyline = _unsupported.begin(); polyline != _unsupported.end(); ++polyline) {
Lines lines = polyline->lines(); Lines lines = polyline->lines();
for (Lines::const_iterator line = lines.begin(); line != lines.end(); ++line) { for (Lines::const_iterator line = lines.begin(); line != lines.end(); ++line) {
if (!Slic3r::Geometry::directions_parallel(line->direction(), angle)) if (!Slic3r::Geometry::directions_parallel(line->direction(), angle))
unsupported->push_back(*line); unsupported.push_back(*line);
} }
} }
return unsupported;
/* /*
if (0) { if (0) {
@ -328,12 +315,4 @@ BridgeDetector::unsupported_edges(double angle, Polylines* unsupported) const
*/ */
} }
Polylines
BridgeDetector::unsupported_edges(double angle) const
{
Polylines pp;
this->unsupported_edges(angle, &pp);
return pp;
}
} }

View File

@ -18,9 +18,7 @@ class BridgeDetector {
BridgeDetector(const ExPolygon &_expolygon, const ExPolygonCollection &_lower_slices, coord_t _extrusion_width); BridgeDetector(const ExPolygon &_expolygon, const ExPolygonCollection &_lower_slices, coord_t _extrusion_width);
bool detect_angle(); bool detect_angle();
void coverage(double angle, Polygons* coverage) const;
Polygons coverage(double angle = -1) const; Polygons coverage(double angle = -1) const;
void unsupported_edges(double angle, Polylines* unsupported) const;
Polylines unsupported_edges(double angle = -1) const; Polylines unsupported_edges(double angle = -1) const;
private: private:

View File

@ -5,54 +5,53 @@ namespace Slic3r {
//----------------------------------------------------------- //-----------------------------------------------------------
// legacy code from Clipper documentation // legacy code from Clipper documentation
void AddOuterPolyNodeToExPolygons(ClipperLib::PolyNode& polynode, Slic3r::ExPolygons* expolygons) void AddOuterPolyNodeToExPolygons(ClipperLib::PolyNode& polynode, ExPolygons* expolygons)
{ {
size_t cnt = expolygons->size(); size_t cnt = expolygons->size();
expolygons->resize(cnt + 1); expolygons->resize(cnt + 1);
ClipperPath_to_Slic3rMultiPoint(polynode.Contour, &(*expolygons)[cnt].contour); (*expolygons)[cnt].contour = ClipperPath_to_Slic3rMultiPoint<Polygon>(polynode.Contour);
(*expolygons)[cnt].holes.resize(polynode.ChildCount()); (*expolygons)[cnt].holes.resize(polynode.ChildCount());
for (int i = 0; i < polynode.ChildCount(); ++i) for (int i = 0; i < polynode.ChildCount(); ++i)
{ {
ClipperPath_to_Slic3rMultiPoint(polynode.Childs[i]->Contour, &(*expolygons)[cnt].holes[i]); (*expolygons)[cnt].holes[i] = ClipperPath_to_Slic3rMultiPoint<Polygon>(polynode.Childs[i]->Contour);
//Add outer polygons contained by (nested within) holes ... //Add outer polygons contained by (nested within) holes ...
for (int j = 0; j < polynode.Childs[i]->ChildCount(); ++j) for (int j = 0; j < polynode.Childs[i]->ChildCount(); ++j)
AddOuterPolyNodeToExPolygons(*polynode.Childs[i]->Childs[j], expolygons); AddOuterPolyNodeToExPolygons(*polynode.Childs[i]->Childs[j], expolygons);
} }
} }
void PolyTreeToExPolygons(ClipperLib::PolyTree& polytree, Slic3r::ExPolygons* expolygons) ExPolygons
PolyTreeToExPolygons(ClipperLib::PolyTree& polytree)
{ {
expolygons->clear(); ExPolygons retval;
for (int i = 0; i < polytree.ChildCount(); ++i) for (int i = 0; i < polytree.ChildCount(); ++i)
AddOuterPolyNodeToExPolygons(*polytree.Childs[i], expolygons); AddOuterPolyNodeToExPolygons(*polytree.Childs[i], &retval);
return retval;
} }
//----------------------------------------------------------- //-----------------------------------------------------------
template <class T> template <class T>
void T
ClipperPath_to_Slic3rMultiPoint(const ClipperLib::Path &input, T* output) ClipperPath_to_Slic3rMultiPoint(const ClipperLib::Path &input)
{ {
output->points.clear(); T retval;
for (ClipperLib::Path::const_iterator pit = input.begin(); pit != input.end(); ++pit) { for (ClipperLib::Path::const_iterator pit = input.begin(); pit != input.end(); ++pit)
output->points.push_back(Slic3r::Point( (*pit).X, (*pit).Y )); retval.points.push_back(Point( (*pit).X, (*pit).Y ));
} return retval;
} }
template void ClipperPath_to_Slic3rMultiPoint<Slic3r::Polygon>(const ClipperLib::Path &input, Slic3r::Polygon* output);
template <class T> template <class T>
void T
ClipperPaths_to_Slic3rMultiPoints(const ClipperLib::Paths &input, T* output) ClipperPaths_to_Slic3rMultiPoints(const ClipperLib::Paths &input)
{ {
output->clear(); T retval;
for (ClipperLib::Paths::const_iterator it = input.begin(); it != input.end(); ++it) { for (ClipperLib::Paths::const_iterator it = input.begin(); it != input.end(); ++it)
typename T::value_type p; retval.push_back(ClipperPath_to_Slic3rMultiPoint<typename T::value_type>(*it));
ClipperPath_to_Slic3rMultiPoint(*it, &p); return retval;
output->push_back(p);
}
} }
void ExPolygons
ClipperPaths_to_Slic3rExPolygons(const ClipperLib::Paths &input, Slic3r::ExPolygons* output) ClipperPaths_to_Slic3rExPolygons(const ClipperLib::Paths &input)
{ {
// init Clipper // init Clipper
ClipperLib::Clipper clipper; ClipperLib::Clipper clipper;
@ -64,29 +63,26 @@ ClipperPaths_to_Slic3rExPolygons(const ClipperLib::Paths &input, Slic3r::ExPolyg
clipper.Execute(ClipperLib::ctUnion, polytree, ClipperLib::pftEvenOdd, ClipperLib::pftEvenOdd); // offset results work with both EvenOdd and NonZero clipper.Execute(ClipperLib::ctUnion, polytree, ClipperLib::pftEvenOdd, ClipperLib::pftEvenOdd); // offset results work with both EvenOdd and NonZero
// write to ExPolygons object // write to ExPolygons object
output->clear(); return PolyTreeToExPolygons(polytree);
PolyTreeToExPolygons(polytree, output);
} }
void ClipperLib::Path
Slic3rMultiPoint_to_ClipperPath(const Slic3r::MultiPoint &input, ClipperLib::Path* output) Slic3rMultiPoint_to_ClipperPath(const MultiPoint &input)
{ {
output->clear(); ClipperLib::Path retval;
for (Slic3r::Points::const_iterator pit = input.points.begin(); pit != input.points.end(); ++pit) { for (Points::const_iterator pit = input.points.begin(); pit != input.points.end(); ++pit)
output->push_back(ClipperLib::IntPoint( (*pit).x, (*pit).y )); retval.push_back(ClipperLib::IntPoint( (*pit).x, (*pit).y ));
} return retval;
} }
template <class T> template <class T>
void ClipperLib::Paths
Slic3rMultiPoints_to_ClipperPaths(const T &input, ClipperLib::Paths* output) Slic3rMultiPoints_to_ClipperPaths(const T &input)
{ {
output->clear(); ClipperLib::Paths retval;
for (typename T::const_iterator it = input.begin(); it != input.end(); ++it) { for (typename T::const_iterator it = input.begin(); it != input.end(); ++it)
ClipperLib::Path p; retval.push_back(Slic3rMultiPoint_to_ClipperPath(*it));
Slic3rMultiPoint_to_ClipperPath(*it, &p); return retval;
output->push_back(p);
}
} }
void void
@ -100,13 +96,12 @@ scaleClipperPolygons(ClipperLib::Paths &polygons, const double scale)
} }
} }
void ClipperLib::Paths
offset(const Slic3r::Polygons &polygons, ClipperLib::Paths* retval, const float delta, _offset(const Polygons &polygons, const float delta,
double scale, ClipperLib::JoinType joinType, double miterLimit) double scale, ClipperLib::JoinType joinType, double miterLimit)
{ {
// read input // read input
ClipperLib::Paths input; ClipperLib::Paths input = Slic3rMultiPoints_to_ClipperPaths(polygons);
Slic3rMultiPoints_to_ClipperPaths(polygons, &input);
// scale input // scale input
scaleClipperPolygons(input, scale); scaleClipperPolygons(input, scale);
@ -119,40 +114,20 @@ offset(const Slic3r::Polygons &polygons, ClipperLib::Paths* retval, const float
co.MiterLimit = miterLimit; co.MiterLimit = miterLimit;
} }
co.AddPaths(input, joinType, ClipperLib::etClosedPolygon); co.AddPaths(input, joinType, ClipperLib::etClosedPolygon);
co.Execute(*retval, (delta*scale)); ClipperLib::Paths retval;
co.Execute(retval, (delta*scale));
// unscale output // unscale output
scaleClipperPolygons(*retval, 1/scale); scaleClipperPolygons(retval, 1/scale);
return retval;
} }
void ClipperLib::Paths
offset(const Slic3r::Polygons &polygons, Slic3r::Polygons* retval, const float delta, _offset(const Polylines &polylines, const float delta,
double scale, ClipperLib::JoinType joinType, double miterLimit)
{
// perform offset
ClipperLib::Paths output;
offset(polygons, &output, delta, scale, joinType, miterLimit);
// convert into ExPolygons
ClipperPaths_to_Slic3rMultiPoints(output, retval);
}
Slic3r::Polygons
offset(const Slic3r::Polygons &polygons, const float delta,
double scale, ClipperLib::JoinType joinType, double miterLimit)
{
Slic3r::Polygons pp;
offset(polygons, &pp, delta, scale, joinType, miterLimit);
return pp;
}
void
offset(const Slic3r::Polylines &polylines, ClipperLib::Paths* retval, const float delta,
double scale, ClipperLib::JoinType joinType, double miterLimit) double scale, ClipperLib::JoinType joinType, double miterLimit)
{ {
// read input // read input
ClipperLib::Paths input; ClipperLib::Paths input = Slic3rMultiPoints_to_ClipperPaths(polylines);
Slic3rMultiPoints_to_ClipperPaths(polylines, &input);
// scale input // scale input
scaleClipperPolygons(input, scale); scaleClipperPolygons(input, scale);
@ -165,82 +140,78 @@ offset(const Slic3r::Polylines &polylines, ClipperLib::Paths* retval, const floa
co.MiterLimit = miterLimit; co.MiterLimit = miterLimit;
} }
co.AddPaths(input, joinType, ClipperLib::etOpenButt); co.AddPaths(input, joinType, ClipperLib::etOpenButt);
co.Execute(*retval, (delta*scale)); ClipperLib::Paths retval;
co.Execute(retval, (delta*scale));
// unscale output // unscale output
scaleClipperPolygons(*retval, 1/scale); scaleClipperPolygons(retval, 1/scale);
return retval;
} }
void Polygons
offset(const Slic3r::Polylines &polylines, Slic3r::Polygons* retval, const float delta, offset(const Polygons &polygons, const float delta,
double scale, ClipperLib::JoinType joinType, double miterLimit) double scale, ClipperLib::JoinType joinType, double miterLimit)
{ {
// perform offset // perform offset
ClipperLib::Paths output; ClipperLib::Paths output = _offset(polygons, delta, scale, joinType, miterLimit);
offset(polylines, &output, delta, scale, joinType, miterLimit);
// convert into ExPolygons // convert into ExPolygons
ClipperPaths_to_Slic3rMultiPoints(output, retval); return ClipperPaths_to_Slic3rMultiPoints<Polygons>(output);
} }
void Polygons
offset(const Slic3r::Surface &surface, Slic3r::Surfaces* retval, const float delta, offset(const Polylines &polylines, const float delta,
double scale, ClipperLib::JoinType joinType, double miterLimit) double scale, ClipperLib::JoinType joinType, double miterLimit)
{ {
// perform offset // perform offset
Slic3r::ExPolygons expp; ClipperLib::Paths output = _offset(polylines, delta, scale, joinType, miterLimit);
offset(surface.expolygon, &expp, delta, scale, joinType, miterLimit);
// convert into ExPolygons
return ClipperPaths_to_Slic3rMultiPoints<Polygons>(output);
}
Surfaces
offset(const Surface &surface, const float delta,
double scale, ClipperLib::JoinType joinType, double miterLimit)
{
// perform offset
ExPolygons expp = offset_ex(surface.expolygon, delta, scale, joinType, miterLimit);
// clone the input surface for each expolygon we got // clone the input surface for each expolygon we got
retval->clear(); Surfaces retval;
retval->reserve(expp.size()); retval.reserve(expp.size());
for (ExPolygons::iterator it = expp.begin(); it != expp.end(); ++it) { for (ExPolygons::iterator it = expp.begin(); it != expp.end(); ++it) {
Surface s = surface; // clone Surface s = surface; // clone
s.expolygon = *it; s.expolygon = *it;
retval->push_back(s); retval.push_back(s);
} }
return retval;
} }
void ExPolygons
offset(const Slic3r::Polygons &polygons, Slic3r::ExPolygons* retval, const float delta, offset_ex(const Polygons &polygons, const float delta,
double scale, ClipperLib::JoinType joinType, double miterLimit) double scale, ClipperLib::JoinType joinType, double miterLimit)
{ {
// perform offset // perform offset
ClipperLib::Paths output; ClipperLib::Paths output = _offset(polygons, delta, scale, joinType, miterLimit);
offset(polygons, &output, delta, scale, joinType, miterLimit);
// convert into ExPolygons // convert into ExPolygons
ClipperPaths_to_Slic3rExPolygons(output, retval); return ClipperPaths_to_Slic3rExPolygons(output);
} }
Slic3r::ExPolygons ExPolygons
offset_ex(const Slic3r::Polygons &polygons, const float delta, offset_ex(const ExPolygons &expolygons, const float delta,
double scale, ClipperLib::JoinType joinType, double miterLimit) double scale, ClipperLib::JoinType joinType, double miterLimit)
{ {
Slic3r::ExPolygons expp; return offset_ex(to_polygons(expolygons), delta, scale, joinType, miterLimit);
offset(polygons, &expp, delta, scale, joinType, miterLimit);
return expp;
} }
Slic3r::ExPolygons ClipperLib::Paths
offset_ex(const Slic3r::ExPolygons &expolygons, const float delta, _offset2(const Polygons &polygons, const float delta1, const float delta2,
double scale, ClipperLib::JoinType joinType, double miterLimit) const double scale, const ClipperLib::JoinType joinType, const double miterLimit)
{
Slic3r::Polygons pp;
for (Slic3r::ExPolygons::const_iterator ex = expolygons.begin(); ex != expolygons.end(); ++ex) {
Slic3r::Polygons pp2 = *ex;
pp.insert(pp.end(), pp2.begin(), pp2.end());
}
return offset_ex(pp, delta, scale, joinType, miterLimit);
}
void
offset2(const Slic3r::Polygons &polygons, ClipperLib::Paths* retval, const float delta1,
const float delta2, const double scale, const ClipperLib::JoinType joinType, const double miterLimit)
{ {
// read input // read input
ClipperLib::Paths input; ClipperLib::Paths input = Slic3rMultiPoints_to_ClipperPaths(polygons);
Slic3rMultiPoints_to_ClipperPaths(polygons, &input);
// scale input // scale input
scaleClipperPolygons(input, scale); scaleClipperPolygons(input, scale);
@ -261,62 +232,44 @@ offset2(const Slic3r::Polygons &polygons, ClipperLib::Paths* retval, const float
// perform second offset // perform second offset
co.Clear(); co.Clear();
co.AddPaths(output1, joinType, ClipperLib::etClosedPolygon); co.AddPaths(output1, joinType, ClipperLib::etClosedPolygon);
co.Execute(*retval, (delta2*scale)); ClipperLib::Paths retval;
co.Execute(retval, (delta2*scale));
// unscale output // unscale output
scaleClipperPolygons(*retval, 1/scale); scaleClipperPolygons(retval, 1/scale);
return retval;
} }
void Polygons
offset2(const Slic3r::Polygons &polygons, Slic3r::Polygons* retval, const float delta1, offset2(const Polygons &polygons, const float delta1, const float delta2,
const float delta2, const double scale, const ClipperLib::JoinType joinType, const double miterLimit) const double scale, const ClipperLib::JoinType joinType, const double miterLimit)
{ {
// perform offset // perform offset
ClipperLib::Paths output; ClipperLib::Paths output = _offset2(polygons, delta1, delta2, scale, joinType, miterLimit);
offset2(polygons, &output, delta1, delta2, scale, joinType, miterLimit);
// convert into ExPolygons // convert into ExPolygons
ClipperPaths_to_Slic3rMultiPoints(output, retval); return ClipperPaths_to_Slic3rMultiPoints<Polygons>(output);
} }
Slic3r::Polygons ExPolygons
offset2(const Slic3r::Polygons &polygons, const float delta1, offset2_ex(const Polygons &polygons, const float delta1, const float delta2,
const float delta2, const double scale, const ClipperLib::JoinType joinType, const double miterLimit) const double scale, const ClipperLib::JoinType joinType, const double miterLimit)
{
Slic3r::Polygons pp;
offset2(polygons, &pp, delta1, delta2, scale, joinType, miterLimit);
return pp;
}
void
offset2(const Slic3r::Polygons &polygons, Slic3r::ExPolygons* retval, const float delta1,
const float delta2, const double scale, const ClipperLib::JoinType joinType, const double miterLimit)
{ {
// perform offset // perform offset
ClipperLib::Paths output; ClipperLib::Paths output = _offset2(polygons, delta1, delta2, scale, joinType, miterLimit);
offset2(polygons, &output, delta1, delta2, scale, joinType, miterLimit);
// convert into ExPolygons // convert into ExPolygons
ClipperPaths_to_Slic3rExPolygons(output, retval); return ClipperPaths_to_Slic3rExPolygons(output);
}
Slic3r::ExPolygons
offset2_ex(const Slic3r::Polygons &polygons, const float delta1,
const float delta2, const double scale, const ClipperLib::JoinType joinType, const double miterLimit)
{
Slic3r::ExPolygons expp;
offset2(polygons, &expp, delta1, delta2, scale, joinType, miterLimit);
return expp;
} }
template <class T> template <class T>
void _clipper_do(const ClipperLib::ClipType clipType, const Slic3r::Polygons &subject, T
const Slic3r::Polygons &clip, T* retval, const ClipperLib::PolyFillType fillType, const bool safety_offset_) _clipper_do(const ClipperLib::ClipType clipType, const Polygons &subject,
const Polygons &clip, const ClipperLib::PolyFillType fillType, const bool safety_offset_)
{ {
// read input // read input
ClipperLib::Paths input_subject, input_clip; ClipperLib::Paths input_subject = Slic3rMultiPoints_to_ClipperPaths(subject);
Slic3rMultiPoints_to_ClipperPaths(subject, &input_subject); ClipperLib::Paths input_clip = Slic3rMultiPoints_to_ClipperPaths(clip);
Slic3rMultiPoints_to_ClipperPaths(clip, &input_clip);
// perform safety offset // perform safety offset
if (safety_offset_) { if (safety_offset_) {
@ -336,17 +289,19 @@ void _clipper_do(const ClipperLib::ClipType clipType, const Slic3r::Polygons &su
clipper.AddPaths(input_clip, ClipperLib::ptClip, true); clipper.AddPaths(input_clip, ClipperLib::ptClip, true);
// perform operation // perform operation
clipper.Execute(clipType, *retval, fillType, fillType); T retval;
clipper.Execute(clipType, retval, fillType, fillType);
return retval;
} }
void _clipper_do(const ClipperLib::ClipType clipType, const Slic3r::Polylines &subject, ClipperLib::PolyTree
const Slic3r::Polygons &clip, ClipperLib::PolyTree* retval, const ClipperLib::PolyFillType fillType, _clipper_do(const ClipperLib::ClipType clipType, const Polylines &subject,
const Polygons &clip, const ClipperLib::PolyFillType fillType,
const bool safety_offset_) const bool safety_offset_)
{ {
// read input // read input
ClipperLib::Paths input_subject, input_clip; ClipperLib::Paths input_subject = Slic3rMultiPoints_to_ClipperPaths(subject);
Slic3rMultiPoints_to_ClipperPaths(subject, &input_subject); ClipperLib::Paths input_clip = Slic3rMultiPoints_to_ClipperPaths(clip);
Slic3rMultiPoints_to_ClipperPaths(clip, &input_clip);
// perform safety offset // perform safety offset
if (safety_offset_) safety_offset(&input_clip); if (safety_offset_) safety_offset(&input_clip);
@ -360,285 +315,133 @@ void _clipper_do(const ClipperLib::ClipType clipType, const Slic3r::Polylines &s
clipper.AddPaths(input_clip, ClipperLib::ptClip, true); clipper.AddPaths(input_clip, ClipperLib::ptClip, true);
// perform operation // perform operation
clipper.Execute(clipType, *retval, fillType, fillType); ClipperLib::PolyTree retval;
clipper.Execute(clipType, retval, fillType, fillType);
return retval;
} }
void _clipper(ClipperLib::ClipType clipType, const Slic3r::Polygons &subject, Polygons
const Slic3r::Polygons &clip, Slic3r::Polygons* retval, bool safety_offset_) _clipper(ClipperLib::ClipType clipType, const Polygons &subject,
const Polygons &clip, bool safety_offset_)
{ {
// perform operation // perform operation
ClipperLib::Paths output; ClipperLib::Paths output = _clipper_do<ClipperLib::Paths>(clipType, subject, clip, ClipperLib::pftNonZero, safety_offset_);
_clipper_do<ClipperLib::Paths>(clipType, subject, clip, &output, ClipperLib::pftNonZero, safety_offset_);
// convert into Polygons // convert into Polygons
ClipperPaths_to_Slic3rMultiPoints(output, retval); return ClipperPaths_to_Slic3rMultiPoints<Polygons>(output);
} }
void _clipper(ClipperLib::ClipType clipType, const Slic3r::Polygons &subject, ExPolygons
const Slic3r::Polygons &clip, Slic3r::ExPolygons* retval, bool safety_offset_) _clipper_ex(ClipperLib::ClipType clipType, const Polygons &subject,
const Polygons &clip, bool safety_offset_)
{ {
// perform operation // perform operation
ClipperLib::PolyTree polytree; ClipperLib::PolyTree polytree = _clipper_do<ClipperLib::PolyTree>(clipType, subject, clip, ClipperLib::pftNonZero, safety_offset_);
_clipper_do<ClipperLib::PolyTree>(clipType, subject, clip, &polytree, ClipperLib::pftNonZero, safety_offset_);
// convert into ExPolygons // convert into ExPolygons
PolyTreeToExPolygons(polytree, retval); return PolyTreeToExPolygons(polytree);
} }
void _clipper(ClipperLib::ClipType clipType, const Slic3r::Polylines &subject, Polylines
const Slic3r::Polygons &clip, Slic3r::Polylines* retval, bool safety_offset_) _clipper_pl(ClipperLib::ClipType clipType, const Polylines &subject,
const Polygons &clip, bool safety_offset_)
{ {
// perform operation // perform operation
ClipperLib::PolyTree polytree; ClipperLib::PolyTree polytree = _clipper_do(clipType, subject, clip, ClipperLib::pftNonZero, safety_offset_);
_clipper_do(clipType, subject, clip, &polytree, ClipperLib::pftNonZero, safety_offset_);
// convert into Polylines // convert into Polylines
ClipperLib::Paths output; ClipperLib::Paths output;
ClipperLib::PolyTreeToPaths(polytree, output); ClipperLib::PolyTreeToPaths(polytree, output);
ClipperPaths_to_Slic3rMultiPoints(output, retval); return ClipperPaths_to_Slic3rMultiPoints<Polylines>(output);
} }
void _clipper(ClipperLib::ClipType clipType, const Slic3r::Lines &subject, Polylines
const Slic3r::Polygons &clip, Slic3r::Lines* retval, bool safety_offset_) _clipper_pl(ClipperLib::ClipType clipType, const Polygons &subject,
{ const Polygons &clip, bool safety_offset_)
// convert Lines to Polylines
Slic3r::Polylines polylines;
polylines.reserve(subject.size());
for (Slic3r::Lines::const_iterator line = subject.begin(); line != subject.end(); ++line)
polylines.push_back(*line);
// perform operation
_clipper(clipType, polylines, clip, &polylines, safety_offset_);
// convert Polylines to Lines
for (Slic3r::Polylines::const_iterator polyline = polylines.begin(); polyline != polylines.end(); ++polyline)
retval->push_back(*polyline);
}
void _clipper(ClipperLib::ClipType clipType, const Slic3r::Polygons &subject,
const Slic3r::Polygons &clip, Slic3r::Polylines* retval, bool safety_offset_)
{ {
// transform input polygons into polylines // transform input polygons into polylines
Slic3r::Polylines polylines; Polylines polylines;
polylines.reserve(subject.size()); polylines.reserve(subject.size());
for (Slic3r::Polygons::const_iterator polygon = subject.begin(); polygon != subject.end(); ++polygon) for (Polygons::const_iterator polygon = subject.begin(); polygon != subject.end(); ++polygon)
polylines.push_back(*polygon); // implicit call to split_at_first_point() polylines.push_back(*polygon); // implicit call to split_at_first_point()
// perform clipping // perform clipping
_clipper(clipType, polylines, clip, retval, safety_offset_); Polylines retval = _clipper_pl(clipType, polylines, clip, safety_offset_);
/* If the split_at_first_point() call above happens to split the polygon inside the clipping area /* If the split_at_first_point() call above happens to split the polygon inside the clipping area
we would get two consecutive polylines instead of a single one, so we go through them in order we would get two consecutive polylines instead of a single one, so we go through them in order
to recombine continuous polylines. */ to recombine continuous polylines. */
for (size_t i = 0; i < retval->size(); ++i) { for (size_t i = 0; i < retval.size(); ++i) {
for (size_t j = i+1; j < retval->size(); ++j) { for (size_t j = i+1; j < retval.size(); ++j) {
if ((*retval)[i].points.back().coincides_with((*retval)[j].points.front())) { if (retval[i].points.back().coincides_with(retval[j].points.front())) {
/* If last point of i coincides with first point of j, /* If last point of i coincides with first point of j,
append points of j to i and delete j */ append points of j to i and delete j */
(*retval)[i].points.insert((*retval)[i].points.end(), (*retval)[j].points.begin()+1, (*retval)[j].points.end()); retval[i].points.insert(retval[i].points.end(), retval[j].points.begin()+1, retval[j].points.end());
retval->erase(retval->begin() + j); retval.erase(retval.begin() + j);
--j; --j;
} else if ((*retval)[i].points.front().coincides_with((*retval)[j].points.back())) { } else if (retval[i].points.front().coincides_with(retval[j].points.back())) {
/* If first point of i coincides with last point of j, /* If first point of i coincides with last point of j,
prepend points of j to i and delete j */ prepend points of j to i and delete j */
(*retval)[i].points.insert((*retval)[i].points.begin(), (*retval)[j].points.begin(), (*retval)[j].points.end()-1); retval[i].points.insert(retval[i].points.begin(), retval[j].points.begin(), retval[j].points.end()-1);
retval->erase(retval->begin() + j); retval.erase(retval.begin() + j);
--j; --j;
} else if ((*retval)[i].points.front().coincides_with((*retval)[j].points.front())) { } else if (retval[i].points.front().coincides_with(retval[j].points.front())) {
/* Since Clipper does not preserve orientation of polylines, /* Since Clipper does not preserve orientation of polylines,
also check the case when first point of i coincides with first point of j. */ also check the case when first point of i coincides with first point of j. */
(*retval)[j].reverse(); retval[j].reverse();
(*retval)[i].points.insert((*retval)[i].points.begin(), (*retval)[j].points.begin(), (*retval)[j].points.end()-1); retval[i].points.insert(retval[i].points.begin(), retval[j].points.begin(), retval[j].points.end()-1);
retval->erase(retval->begin() + j); retval.erase(retval.begin() + j);
--j; --j;
} else if ((*retval)[i].points.back().coincides_with((*retval)[j].points.back())) { } else if (retval[i].points.back().coincides_with(retval[j].points.back())) {
/* Since Clipper does not preserve orientation of polylines, /* Since Clipper does not preserve orientation of polylines,
also check the case when last point of i coincides with last point of j. */ also check the case when last point of i coincides with last point of j. */
(*retval)[j].reverse(); retval[j].reverse();
(*retval)[i].points.insert((*retval)[i].points.end(), (*retval)[j].points.begin()+1, (*retval)[j].points.end()); retval[i].points.insert(retval[i].points.end(), retval[j].points.begin()+1, retval[j].points.end());
retval->erase(retval->begin() + j); retval.erase(retval.begin() + j);
--j; --j;
} }
} }
} }
}
template <class SubjectType, class ResultType>
void diff(const SubjectType &subject, const Slic3r::Polygons &clip, ResultType* retval, bool safety_offset_)
{
_clipper(ClipperLib::ctDifference, subject, clip, retval, safety_offset_);
}
template void diff<Slic3r::Polygons, Slic3r::ExPolygons>(const Slic3r::Polygons &subject, const Slic3r::Polygons &clip, Slic3r::ExPolygons* retval, bool safety_offset_);
template void diff<Slic3r::Polygons, Slic3r::Polygons>(const Slic3r::Polygons &subject, const Slic3r::Polygons &clip, Slic3r::Polygons* retval, bool safety_offset_);
template void diff<Slic3r::Polygons, Slic3r::Polylines>(const Slic3r::Polygons &subject, const Slic3r::Polygons &clip, Slic3r::Polylines* retval, bool safety_offset_);
template void diff<Slic3r::Polylines, Slic3r::Polylines>(const Slic3r::Polylines &subject, const Slic3r::Polygons &clip, Slic3r::Polylines* retval, bool safety_offset_);
template void diff<Slic3r::Lines, Slic3r::Lines>(const Slic3r::Lines &subject, const Slic3r::Polygons &clip, Slic3r::Lines* retval, bool safety_offset_);
template <class SubjectType, class ResultType>
void diff(const SubjectType &subject, const Slic3r::ExPolygons &clip, ResultType* retval, bool safety_offset_)
{
Slic3r::Polygons pp;
for (Slic3r::ExPolygons::const_iterator ex = clip.begin(); ex != clip.end(); ++ex) {
Slic3r::Polygons ppp = *ex;
pp.insert(pp.end(), ppp.begin(), ppp.end());
}
diff(subject, pp, retval, safety_offset_);
}
template void diff<Slic3r::Polygons, Slic3r::ExPolygons>(const Slic3r::Polygons &subject, const Slic3r::ExPolygons &clip, Slic3r::ExPolygons* retval, bool safety_offset_);
template <class ResultType>
void diff(const Slic3r::ExPolygons &subject, const Slic3r::ExPolygons &clip, ResultType* retval, bool safety_offset_)
{
Slic3r::Polygons pp;
for (Slic3r::ExPolygons::const_iterator ex = subject.begin(); ex != subject.end(); ++ex) {
Slic3r::Polygons ppp = *ex;
pp.insert(pp.end(), ppp.begin(), ppp.end());
}
diff(pp, clip, retval, safety_offset_);
}
Slic3r::Polygons
diff(const Slic3r::Polygons &subject, const Slic3r::Polygons &clip, bool safety_offset_)
{
Slic3r::Polygons pp;
diff(subject, clip, &pp, safety_offset_);
return pp;
}
template <class SubjectType, class ClipType>
Slic3r::ExPolygons
diff_ex(const SubjectType &subject, const ClipType &clip, bool safety_offset_)
{
Slic3r::ExPolygons expp;
diff(subject, clip, &expp, safety_offset_);
return expp;
}
template Slic3r::ExPolygons diff_ex<Slic3r::Polygons, Slic3r::Polygons>(const Slic3r::Polygons &subject, const Slic3r::Polygons &clip, bool safety_offset_);
template Slic3r::ExPolygons diff_ex<Slic3r::Polygons, Slic3r::ExPolygons>(const Slic3r::Polygons &subject, const Slic3r::ExPolygons &clip, bool safety_offset_);
template Slic3r::ExPolygons diff_ex<Slic3r::ExPolygons, Slic3r::ExPolygons>(const Slic3r::ExPolygons &subject, const Slic3r::ExPolygons &clip, bool safety_offset_);
template <class SubjectType, class ResultType>
void intersection(const SubjectType &subject, const Slic3r::Polygons &clip, ResultType* retval, bool safety_offset_)
{
_clipper(ClipperLib::ctIntersection, subject, clip, retval, safety_offset_);
}
template void intersection<Slic3r::Polygons, Slic3r::ExPolygons>(const Slic3r::Polygons &subject, const Slic3r::Polygons &clip, Slic3r::ExPolygons* retval, bool safety_offset_);
template void intersection<Slic3r::Polygons, Slic3r::Polygons>(const Slic3r::Polygons &subject, const Slic3r::Polygons &clip, Slic3r::Polygons* retval, bool safety_offset_);
template void intersection<Slic3r::Polygons, Slic3r::Polylines>(const Slic3r::Polygons &subject, const Slic3r::Polygons &clip, Slic3r::Polylines* retval, bool safety_offset_);
template void intersection<Slic3r::Polylines, Slic3r::Polylines>(const Slic3r::Polylines &subject, const Slic3r::Polygons &clip, Slic3r::Polylines* retval, bool safety_offset_);
template void intersection<Slic3r::Lines, Slic3r::Lines>(const Slic3r::Lines &subject, const Slic3r::Polygons &clip, Slic3r::Lines* retval, bool safety_offset_);
template <class SubjectType>
SubjectType intersection(const SubjectType &subject, const Slic3r::Polygons &clip, bool safety_offset_)
{
SubjectType pp;
intersection(subject, clip, &pp, safety_offset_);
return pp;
}
template Slic3r::Polygons intersection<Slic3r::Polygons>(const Slic3r::Polygons &subject, const Slic3r::Polygons &clip, bool safety_offset_);
template Slic3r::Polylines intersection<Slic3r::Polylines>(const Slic3r::Polylines &subject, const Slic3r::Polygons &clip, bool safety_offset_);
template Slic3r::Lines intersection<Slic3r::Lines>(const Slic3r::Lines &subject, const Slic3r::Polygons &clip, bool safety_offset_);
Slic3r::ExPolygons
intersection_ex(const Slic3r::Polygons &subject, const Slic3r::Polygons &clip, bool safety_offset_)
{
Slic3r::ExPolygons expp;
intersection(subject, clip, &expp, safety_offset_);
return expp;
}
template <class SubjectType>
bool intersects(const SubjectType &subject, const Slic3r::Polygons &clip, bool safety_offset_)
{
SubjectType retval;
intersection(subject, clip, &retval, safety_offset_);
return !retval.empty();
}
template bool intersects<Slic3r::Polygons>(const Slic3r::Polygons &subject, const Slic3r::Polygons &clip, bool safety_offset_);
template bool intersects<Slic3r::Polylines>(const Slic3r::Polylines &subject, const Slic3r::Polygons &clip, bool safety_offset_);
template bool intersects<Slic3r::Lines>(const Slic3r::Lines &subject, const Slic3r::Polygons &clip, bool safety_offset_);
void xor_(const Slic3r::Polygons &subject, const Slic3r::Polygons &clip, Slic3r::ExPolygons* retval,
bool safety_offset_)
{
_clipper(ClipperLib::ctXor, subject, clip, retval, safety_offset_);
}
template <class T>
void union_(const Slic3r::Polygons &subject, T* retval, bool safety_offset_)
{
Slic3r::Polygons p;
_clipper(ClipperLib::ctUnion, subject, p, retval, safety_offset_);
}
template void union_<Slic3r::ExPolygons>(const Slic3r::Polygons &subject, Slic3r::ExPolygons* retval, bool safety_offset_);
template void union_<Slic3r::Polygons>(const Slic3r::Polygons &subject, Slic3r::Polygons* retval, bool safety_offset_);
Slic3r::Polygons
union_(const Slic3r::Polygons &subject, bool safety_offset)
{
Polygons pp;
union_(subject, &pp, safety_offset);
return pp;
}
Slic3r::ExPolygons
union_ex(const Slic3r::Polygons &subject, bool safety_offset)
{
ExPolygons expp;
union_(subject, &expp, safety_offset);
return expp;
}
Slic3r::ExPolygons
union_ex(const Slic3r::Surfaces &subject, bool safety_offset)
{
Polygons pp;
for (Slic3r::Surfaces::const_iterator s = subject.begin(); s != subject.end(); ++s) {
Polygons spp = *s;
pp.insert(pp.end(), spp.begin(), spp.end());
}
return union_ex(pp, safety_offset);
}
void union_(const Slic3r::Polygons &subject1, const Slic3r::Polygons &subject2, Slic3r::Polygons* retval, bool safety_offset)
{
Polygons pp = subject1;
pp.insert(pp.end(), subject2.begin(), subject2.end());
union_(pp, retval, safety_offset);
}
Slic3r::Polygons
union_(const Slic3r::ExPolygons &subject1, const Slic3r::ExPolygons &subject2, bool safety_offset)
{
Polygons pp;
for (Slic3r::ExPolygons::const_iterator it = subject1.begin(); it != subject1.end(); ++it) {
Polygons spp = *it;
pp.insert(pp.end(), spp.begin(), spp.end());
}
for (Slic3r::ExPolygons::const_iterator it = subject2.begin(); it != subject2.end(); ++it) {
Polygons spp = *it;
pp.insert(pp.end(), spp.begin(), spp.end());
}
Polygons retval;
union_(pp, &retval, safety_offset);
return retval; return retval;
} }
void union_pt(const Slic3r::Polygons &subject, ClipperLib::PolyTree* retval, bool safety_offset_) Lines
_clipper_ln(ClipperLib::ClipType clipType, const Lines &subject, const Polygons &clip,
bool safety_offset_)
{ {
Slic3r::Polygons clip; // convert Lines to Polylines
_clipper_do<ClipperLib::PolyTree>(ClipperLib::ctUnion, subject, clip, retval, ClipperLib::pftEvenOdd, safety_offset_); Polylines polylines;
polylines.reserve(subject.size());
for (Lines::const_iterator line = subject.begin(); line != subject.end(); ++line)
polylines.push_back(*line);
// perform operation
polylines = _clipper_pl(clipType, polylines, clip, safety_offset_);
// convert Polylines to Lines
Lines retval;
for (Polylines::const_iterator polyline = polylines.begin(); polyline != polylines.end(); ++polyline)
retval.push_back(*polyline);
return retval;
} }
void union_pt_chained(const Slic3r::Polygons &subject, Slic3r::Polygons* retval, bool safety_offset_) ClipperLib::PolyTree
union_pt(const Polygons &subject, bool safety_offset_)
{ {
ClipperLib::PolyTree pt; return _clipper_do<ClipperLib::PolyTree>(ClipperLib::ctUnion, subject, Polygons(), ClipperLib::pftEvenOdd, safety_offset_);
union_pt(subject, &pt, safety_offset_);
traverse_pt(pt.Childs, retval);
} }
static void traverse_pt(ClipperLib::PolyNodes &nodes, Slic3r::Polygons* retval) Polygons
union_pt_chained(const Polygons &subject, bool safety_offset_)
{
ClipperLib::PolyTree polytree = union_pt(subject, safety_offset_);
Polygons retval;
traverse_pt(polytree.Childs, &retval);
return retval;
}
static void traverse_pt(ClipperLib::PolyNodes &nodes, Polygons* retval)
{ {
/* use a nearest neighbor search to order these children /* use a nearest neighbor search to order these children
TODO: supply start_near to chained_path() too? */ TODO: supply start_near to chained_path() too? */
@ -660,19 +463,19 @@ static void traverse_pt(ClipperLib::PolyNodes &nodes, Slic3r::Polygons* retval)
// traverse the next depth // traverse the next depth
traverse_pt((*it)->Childs, retval); traverse_pt((*it)->Childs, retval);
Polygon p; Polygon p = ClipperPath_to_Slic3rMultiPoint<Polygon>((*it)->Contour);
ClipperPath_to_Slic3rMultiPoint((*it)->Contour, &p);
retval->push_back(p); retval->push_back(p);
if ((*it)->IsHole()) retval->back().reverse(); // ccw if ((*it)->IsHole()) retval->back().reverse(); // ccw
} }
} }
void simplify_polygons(const Slic3r::Polygons &subject, Slic3r::Polygons* retval, bool preserve_collinear) Polygons
simplify_polygons(const Polygons &subject, bool preserve_collinear)
{ {
// convert into Clipper polygons // convert into Clipper polygons
ClipperLib::Paths input_subject, output; ClipperLib::Paths input_subject = Slic3rMultiPoints_to_ClipperPaths(subject);
Slic3rMultiPoints_to_ClipperPaths(subject, &input_subject);
ClipperLib::Paths output;
if (preserve_collinear) { if (preserve_collinear) {
ClipperLib::Clipper c; ClipperLib::Clipper c;
c.PreserveCollinear(true); c.PreserveCollinear(true);
@ -684,21 +487,18 @@ void simplify_polygons(const Slic3r::Polygons &subject, Slic3r::Polygons* retval
} }
// convert into Slic3r polygons // convert into Slic3r polygons
ClipperPaths_to_Slic3rMultiPoints(output, retval); return ClipperPaths_to_Slic3rMultiPoints<Polygons>(output);
} }
void simplify_polygons(const Slic3r::Polygons &subject, Slic3r::ExPolygons* retval, bool preserve_collinear) ExPolygons
simplify_polygons_ex(const Polygons &subject, bool preserve_collinear)
{ {
if (!preserve_collinear) { if (!preserve_collinear) {
Polygons polygons; return union_ex(simplify_polygons(subject, preserve_collinear));
simplify_polygons(subject, &polygons, preserve_collinear);
union_(polygons, retval);
return;
} }
// convert into Clipper polygons // convert into Clipper polygons
ClipperLib::Paths input_subject; ClipperLib::Paths input_subject = Slic3rMultiPoints_to_ClipperPaths(subject);
Slic3rMultiPoints_to_ClipperPaths(subject, &input_subject);
ClipperLib::PolyTree polytree; ClipperLib::PolyTree polytree;
@ -709,7 +509,7 @@ void simplify_polygons(const Slic3r::Polygons &subject, Slic3r::ExPolygons* retv
c.Execute(ClipperLib::ctUnion, polytree, ClipperLib::pftNonZero, ClipperLib::pftNonZero); c.Execute(ClipperLib::ctUnion, polytree, ClipperLib::pftNonZero, ClipperLib::pftNonZero);
// convert into ExPolygons // convert into ExPolygons
PolyTreeToExPolygons(polytree, retval); return PolyTreeToExPolygons(polytree);
} }
void safety_offset(ClipperLib::Paths* paths) void safety_offset(ClipperLib::Paths* paths)

View File

@ -22,22 +22,19 @@ void AddOuterPolyNodeToExPolygons(ClipperLib::PolyNode& polynode, Slic3r::ExPoly
void PolyTreeToExPolygons(ClipperLib::PolyTree& polytree, Slic3r::ExPolygons& expolygons); void PolyTreeToExPolygons(ClipperLib::PolyTree& polytree, Slic3r::ExPolygons& expolygons);
//----------------------------------------------------------- //-----------------------------------------------------------
void Slic3rMultiPoint_to_ClipperPath(const Slic3r::MultiPoint &input, ClipperLib::Path* output); ClipperLib::Path Slic3rMultiPoint_to_ClipperPath(const Slic3r::MultiPoint &input);
template <class T> template <class T>
void Slic3rMultiPoints_to_ClipperPaths(const T &input, ClipperLib::Paths* output); ClipperLib::Paths Slic3rMultiPoints_to_ClipperPaths(const T &input);
template <class T> template <class T>
void ClipperPath_to_Slic3rMultiPoint(const ClipperLib::Path &input, T* output); T ClipperPath_to_Slic3rMultiPoint(const ClipperLib::Path &input);
template <class T> template <class T>
void ClipperPaths_to_Slic3rMultiPoints(const ClipperLib::Paths &input, T* output); T ClipperPaths_to_Slic3rMultiPoints(const ClipperLib::Paths &input);
void ClipperPaths_to_Slic3rExPolygons(const ClipperLib::Paths &input, Slic3r::ExPolygons* output); Slic3r::ExPolygons ClipperPaths_to_Slic3rExPolygons(const ClipperLib::Paths &input);
void scaleClipperPolygons(ClipperLib::Paths &polygons, const double scale); void scaleClipperPolygons(ClipperLib::Paths &polygons, const double scale);
// offset Polygons // offset Polygons
void offset(const Slic3r::Polygons &polygons, ClipperLib::Paths* retval, const float delta, ClipperLib::Paths _offset(const Slic3r::Polygons &polygons, const float delta,
double scale = 100000, ClipperLib::JoinType joinType = ClipperLib::jtMiter,
double miterLimit = 3);
void offset(const Slic3r::Polygons &polygons, Slic3r::Polygons* retval, const float delta,
double scale = 100000, ClipperLib::JoinType joinType = ClipperLib::jtMiter, double scale = 100000, ClipperLib::JoinType joinType = ClipperLib::jtMiter,
double miterLimit = 3); double miterLimit = 3);
Slic3r::Polygons offset(const Slic3r::Polygons &polygons, const float delta, Slic3r::Polygons offset(const Slic3r::Polygons &polygons, const float delta,
@ -45,19 +42,16 @@ Slic3r::Polygons offset(const Slic3r::Polygons &polygons, const float delta,
double miterLimit = 3); double miterLimit = 3);
// offset Polylines // offset Polylines
void offset(const Slic3r::Polylines &polylines, ClipperLib::Paths* retval, const float delta, ClipperLib::Paths _offset(const Slic3r::Polylines &polylines, const float delta,
double scale = 100000, ClipperLib::JoinType joinType = ClipperLib::jtSquare, double scale = 100000, ClipperLib::JoinType joinType = ClipperLib::jtSquare,
double miterLimit = 3); double miterLimit = 3);
void offset(const Slic3r::Polylines &polylines, Slic3r::Polygons* retval, const float delta, Slic3r::Polygons offset(const Slic3r::Polylines &polylines, const float delta,
double scale = 100000, ClipperLib::JoinType joinType = ClipperLib::jtSquare, double scale = 100000, ClipperLib::JoinType joinType = ClipperLib::jtSquare,
double miterLimit = 3); double miterLimit = 3);
void offset(const Slic3r::Surface &surface, Slic3r::Surfaces* retval, const float delta, Slic3r::Surfaces offset(const Slic3r::Surface &surface, const float delta,
double scale = 100000, ClipperLib::JoinType joinType = ClipperLib::jtSquare, double scale = 100000, ClipperLib::JoinType joinType = ClipperLib::jtSquare,
double miterLimit = 3); double miterLimit = 3);
void offset(const Slic3r::Polygons &polygons, Slic3r::ExPolygons* retval, const float delta,
double scale = 100000, ClipperLib::JoinType joinType = ClipperLib::jtMiter,
double miterLimit = 3);
Slic3r::ExPolygons offset_ex(const Slic3r::Polygons &polygons, const float delta, Slic3r::ExPolygons offset_ex(const Slic3r::Polygons &polygons, const float delta,
double scale = 100000, ClipperLib::JoinType joinType = ClipperLib::jtMiter, double scale = 100000, ClipperLib::JoinType joinType = ClipperLib::jtMiter,
double miterLimit = 3); double miterLimit = 3);
@ -65,78 +59,159 @@ Slic3r::ExPolygons offset_ex(const Slic3r::ExPolygons &expolygons, const float d
double scale = 100000, ClipperLib::JoinType joinType = ClipperLib::jtMiter, double scale = 100000, ClipperLib::JoinType joinType = ClipperLib::jtMiter,
double miterLimit = 3); double miterLimit = 3);
void offset2(const Slic3r::Polygons &polygons, ClipperLib::Paths* retval, const float delta1, ClipperLib::Paths _offset2(const Slic3r::Polygons &polygons, const float delta1,
const float delta2, double scale = 100000, ClipperLib::JoinType joinType = ClipperLib::jtMiter,
double miterLimit = 3);
void offset2(const Slic3r::Polygons &polygons, Slic3r::Polygons* retval, const float delta1,
const float delta2, double scale = 100000, ClipperLib::JoinType joinType = ClipperLib::jtMiter, const float delta2, double scale = 100000, ClipperLib::JoinType joinType = ClipperLib::jtMiter,
double miterLimit = 3); double miterLimit = 3);
Slic3r::Polygons offset2(const Slic3r::Polygons &polygons, const float delta1, Slic3r::Polygons offset2(const Slic3r::Polygons &polygons, const float delta1,
const float delta2, double scale = 100000, ClipperLib::JoinType joinType = ClipperLib::jtMiter, const float delta2, double scale = 100000, ClipperLib::JoinType joinType = ClipperLib::jtMiter,
double miterLimit = 3); double miterLimit = 3);
void offset2(const Slic3r::Polygons &polygons, Slic3r::ExPolygons* retval, const float delta1,
const float delta2, double scale = 100000, ClipperLib::JoinType joinType = ClipperLib::jtMiter,
double miterLimit = 3);
Slic3r::ExPolygons offset2_ex(const Slic3r::Polygons &polygons, const float delta1, Slic3r::ExPolygons offset2_ex(const Slic3r::Polygons &polygons, const float delta1,
const float delta2, double scale = 100000, ClipperLib::JoinType joinType = ClipperLib::jtMiter, const float delta2, double scale = 100000, ClipperLib::JoinType joinType = ClipperLib::jtMiter,
double miterLimit = 3); double miterLimit = 3);
template <class T> template <class T>
void _clipper_do(ClipperLib::ClipType clipType, const Slic3r::Polygons &subject, T _clipper_do(ClipperLib::ClipType clipType, const Slic3r::Polygons &subject,
const Slic3r::Polygons &clip, T* retval, bool safety_offset_); const Slic3r::Polygons &clip, const ClipperLib::PolyFillType fillType, bool safety_offset_ = false);
void _clipper_do(ClipperLib::ClipType clipType, const Slic3r::Polylines &subject,
const Slic3r::Polygons &clip, ClipperLib::Paths* retval, bool safety_offset_);
void _clipper(ClipperLib::ClipType clipType, const Slic3r::Polygons &subject,
const Slic3r::Polygons &clip, Slic3r::Polygons* retval, bool safety_offset_);
void _clipper(ClipperLib::ClipType clipType, const Slic3r::Polygons &subject,
const Slic3r::Polygons &clip, Slic3r::ExPolygons* retval, bool safety_offset_);
void _clipper(ClipperLib::ClipType clipType, const Slic3r::Polylines &subject,
const Slic3r::Polygons &clip, Slic3r::Polylines* retval);
void _clipper(ClipperLib::ClipType clipType, const Slic3r::Lines &subject,
const Slic3r::Polygons &clip, Slic3r::Lines* retval);
template <class SubjectType, class ResultType> ClipperLib::PolyTree _clipper_do(ClipperLib::ClipType clipType, const Slic3r::Polylines &subject,
void diff(const SubjectType &subject, const Slic3r::Polygons &clip, ResultType* retval, bool safety_offset_ = false); const Slic3r::Polygons &clip, const ClipperLib::PolyFillType fillType, bool safety_offset_ = false);
template <class SubjectType, class ResultType> Slic3r::Polygons _clipper(ClipperLib::ClipType clipType,
void diff(const SubjectType &subject, const Slic3r::ExPolygons &clip, ResultType* retval, bool safety_offset_ = false); const Slic3r::Polygons &subject, const Slic3r::Polygons &clip, bool safety_offset_ = false);
Slic3r::ExPolygons _clipper_ex(ClipperLib::ClipType clipType,
const Slic3r::Polygons &subject, const Slic3r::Polygons &clip, bool safety_offset_ = false);
Slic3r::Polylines _clipper_pl(ClipperLib::ClipType clipType,
const Slic3r::Polylines &subject, const Slic3r::Polygons &clip, bool safety_offset_ = false);
Slic3r::Polylines _clipper_pl(ClipperLib::ClipType clipType,
const Slic3r::Polygons &subject, const Slic3r::Polygons &clip, bool safety_offset_ = false);
Slic3r::Lines _clipper_ln(ClipperLib::ClipType clipType,
const Slic3r::Lines &subject, const Slic3r::Polygons &clip, bool safety_offset_ = false);
Slic3r::Polygons diff(const Slic3r::Polygons &subject, const Slic3r::Polygons &clip, bool safety_offset_ = false); // diff
inline Slic3r::Polygons
diff(const Slic3r::Polygons &subject, const Slic3r::Polygons &clip, bool safety_offset_ = false)
{
return _clipper(ClipperLib::ctDifference, subject, clip, safety_offset_);
}
template <class SubjectType, class ClipType> inline Slic3r::ExPolygons
Slic3r::ExPolygons diff_ex(const SubjectType &subject, const ClipType &clip, bool safety_offset_ = false); diff_ex(const Slic3r::Polygons &subject, const Slic3r::Polygons &clip, bool safety_offset_ = false)
{
return _clipper_ex(ClipperLib::ctDifference, subject, clip, safety_offset_);
}
template <class SubjectType, class ResultType> inline Slic3r::ExPolygons
void intersection(const SubjectType &subject, const Slic3r::Polygons &clip, ResultType* retval, bool safety_offset_ = false); diff_ex(const Slic3r::ExPolygons &subject, const Slic3r::ExPolygons &clip, bool safety_offset_ = false)
{
return _clipper_ex(ClipperLib::ctDifference, to_polygons(subject), to_polygons(clip), safety_offset_);
}
template <class SubjectType> inline Slic3r::Polygons
SubjectType intersection(const SubjectType &subject, const Slic3r::Polygons &clip, bool safety_offset_ = false); diff(const Slic3r::ExPolygons &subject, const Slic3r::ExPolygons &clip, bool safety_offset_ = false)
{
return _clipper(ClipperLib::ctDifference, to_polygons(subject), to_polygons(clip), safety_offset_);
}
Slic3r::ExPolygons inline Slic3r::Polylines
intersection_ex(const Slic3r::Polygons &subject, const Slic3r::Polygons &clip, bool safety_offset_ = false); diff_pl(const Slic3r::Polygons &subject, const Slic3r::Polygons &clip, bool safety_offset_ = false)
{
return _clipper_pl(ClipperLib::ctDifference, subject, clip, safety_offset_);
}
template <class SubjectType> inline Slic3r::Polylines
bool intersects(const SubjectType &subject, const Slic3r::Polygons &clip, bool safety_offset_ = false); diff_pl(const Slic3r::Polylines &subject, const Slic3r::Polygons &clip, bool safety_offset_ = false)
{
return _clipper_pl(ClipperLib::ctDifference, subject, clip, safety_offset_);
}
void xor_(const Slic3r::Polygons &subject, const Slic3r::Polygons &clip, Slic3r::ExPolygons* retval, inline Slic3r::Lines
bool safety_offset_ = false); diff_ln(const Slic3r::Lines &subject, const Slic3r::Polygons &clip, bool safety_offset_ = false)
{
return _clipper_ln(ClipperLib::ctDifference, subject, clip, safety_offset_);
}
template <class T> // intersection
void union_(const Slic3r::Polygons &subject, T* retval, bool safety_offset_ = false); inline Slic3r::Polygons
intersection(const Slic3r::Polygons &subject, const Slic3r::Polygons &clip, bool safety_offset_ = false)
{
return _clipper(ClipperLib::ctIntersection, subject, clip, safety_offset_);
}
Slic3r::Polygons union_(const Slic3r::Polygons &subject, bool safety_offset = false); inline Slic3r::ExPolygons
Slic3r::ExPolygons union_ex(const Slic3r::Polygons &subject, bool safety_offset = false); intersection_ex(const Slic3r::Polygons &subject, const Slic3r::Polygons &clip, bool safety_offset_ = false)
Slic3r::ExPolygons union_ex(const Slic3r::Surfaces &subject, bool safety_offset = false); {
return _clipper_ex(ClipperLib::ctIntersection, subject, clip, safety_offset_);
}
void union_(const Slic3r::Polygons &subject1, const Slic3r::Polygons &subject2, Slic3r::Polygons* retval, bool safety_offset = false); inline Slic3r::ExPolygons
Slic3r::Polygons union_(const Slic3r::ExPolygons &subject1, const Slic3r::ExPolygons &subject2, bool safety_offset = false); intersection_ex(const Slic3r::ExPolygons &subject, const Slic3r::ExPolygons &clip, bool safety_offset_ = false)
{
return _clipper_ex(ClipperLib::ctIntersection, to_polygons(subject), to_polygons(clip), safety_offset_);
}
void union_pt(const Slic3r::Polygons &subject, ClipperLib::PolyTree* retval, bool safety_offset_ = false); inline Slic3r::Polygons
void union_pt_chained(const Slic3r::Polygons &subject, Slic3r::Polygons* retval, bool safety_offset_ = false); intersection(const Slic3r::ExPolygons &subject, const Slic3r::ExPolygons &clip, bool safety_offset_ = false)
{
return _clipper(ClipperLib::ctIntersection, to_polygons(subject), to_polygons(clip), safety_offset_);
}
inline Slic3r::Polylines
intersection_pl(const Slic3r::Polygons &subject, const Slic3r::Polygons &clip, bool safety_offset_ = false)
{
return _clipper_pl(ClipperLib::ctIntersection, subject, clip, safety_offset_);
}
inline Slic3r::Polylines
intersection_pl(const Slic3r::Polylines &subject, const Slic3r::Polygons &clip, bool safety_offset_ = false)
{
return _clipper_pl(ClipperLib::ctIntersection, subject, clip, safety_offset_);
}
inline Slic3r::Lines
intersection_ln(const Slic3r::Lines &subject, const Slic3r::Polygons &clip, bool safety_offset_ = false)
{
return _clipper_ln(ClipperLib::ctIntersection, subject, clip, safety_offset_);
}
// union
inline Slic3r::Polygons
union_(const Slic3r::Polygons &subject, bool safety_offset_ = false)
{
return _clipper(ClipperLib::ctUnion, subject, Slic3r::Polygons(), safety_offset_);
}
inline Slic3r::Polygons
union_(const Slic3r::Polygons &subject, const Slic3r::Polygons &subject2, bool safety_offset_ = false)
{
return _clipper(ClipperLib::ctUnion, subject, subject2, safety_offset_);
}
inline Slic3r::ExPolygons
union_ex(const Slic3r::Polygons &subject, bool safety_offset_ = false)
{
return _clipper_ex(ClipperLib::ctUnion, subject, Slic3r::Polygons(), safety_offset_);
}
inline Slic3r::ExPolygons
union_ex(const Slic3r::ExPolygons &subject, bool safety_offset_ = false)
{
return _clipper_ex(ClipperLib::ctUnion, to_polygons(subject), Slic3r::Polygons(), safety_offset_);
}
inline Slic3r::ExPolygons
union_ex(const Slic3r::Surfaces &subject, bool safety_offset_ = false)
{
return _clipper_ex(ClipperLib::ctUnion, to_polygons(subject), Slic3r::Polygons(), safety_offset_);
}
ClipperLib::PolyTree union_pt(const Slic3r::Polygons &subject, bool safety_offset_ = false);
Slic3r::Polygons union_pt_chained(const Slic3r::Polygons &subject, bool safety_offset_ = false);
static void traverse_pt(ClipperLib::PolyNodes &nodes, Slic3r::Polygons* retval); static void traverse_pt(ClipperLib::PolyNodes &nodes, Slic3r::Polygons* retval);
void simplify_polygons(const Slic3r::Polygons &subject, Slic3r::Polygons* retval, bool preserve_collinear = false); /* OTHER */
void simplify_polygons(const Slic3r::Polygons &subject, Slic3r::ExPolygons* retval, bool preserve_collinear = false); Slic3r::Polygons simplify_polygons(const Slic3r::Polygons &subject, bool preserve_collinear = false);
Slic3r::ExPolygons simplify_polygons_ex(const Slic3r::Polygons &subject, bool preserve_collinear = false);
void safety_offset(ClipperLib::Paths* paths); void safety_offset(ClipperLib::Paths* paths);

View File

@ -90,9 +90,7 @@ ExPolygon::contains(const Line &line) const
bool bool
ExPolygon::contains(const Polyline &polyline) const ExPolygon::contains(const Polyline &polyline) const
{ {
Polylines pl_out; return diff_pl((Polylines)polyline, *this).empty();
diff((Polylines)polyline, *this, &pl_out);
return pl_out.empty();
} }
bool bool
@ -152,8 +150,7 @@ ExPolygon::simplify_p(double tolerance) const
p.points.pop_back(); p.points.pop_back();
pp.push_back(p); pp.push_back(p);
} }
simplify_polygons(pp, &pp); return simplify_polygons(pp);
return pp;
} }
ExPolygons ExPolygons
@ -346,8 +343,7 @@ ExPolygon::get_trapezoids2(Polygons* polygons) const
poly[3].y = bb.max.y; poly[3].y = bb.max.y;
// intersect with this expolygon // intersect with this expolygon
Polygons trapezoids; Polygons trapezoids = intersection(poly, *this);
intersection<Polygons,Polygons>(poly, *this, &trapezoids);
// append results to return value // append results to return value
polygons->insert(polygons->end(), trapezoids.begin(), trapezoids.end()); polygons->insert(polygons->end(), trapezoids.begin(), trapezoids.end());
@ -384,10 +380,7 @@ ExPolygon::triangulate_pp(Polygons* polygons) const
// convert polygons // convert polygons
std::list<TPPLPoly> input; std::list<TPPLPoly> input;
Polygons pp = *this; ExPolygons expp = simplify_polygons_ex(*this, true);
simplify_polygons(pp, &pp, true);
ExPolygons expp;
union_(pp, &expp);
for (ExPolygons::const_iterator ex = expp.begin(); ex != expp.end(); ++ex) { for (ExPolygons::const_iterator ex = expp.begin(); ex != expp.end(); ++ex) {
// contour // contour
@ -440,8 +433,7 @@ ExPolygon::triangulate_pp(Polygons* polygons) const
void void
ExPolygon::triangulate_p2t(Polygons* polygons) const ExPolygon::triangulate_p2t(Polygons* polygons) const
{ {
ExPolygons expp; ExPolygons expp = simplify_polygons_ex(*this, true);
simplify_polygons(*this, &expp, true);
for (ExPolygons::const_iterator ex = expp.begin(); ex != expp.end(); ++ex) { for (ExPolygons::const_iterator ex = expp.begin(); ex != expp.end(); ++ex) {
// TODO: prevent duplicate points // TODO: prevent duplicate points
@ -505,4 +497,15 @@ ExPolygon::dump_perl() const
return ret.str(); return ret.str();
} }
Polygons
to_polygons(const ExPolygons &expolygons)
{
Slic3r::Polygons pp;
for (ExPolygons::const_iterator ex = expolygons.begin(); ex != expolygons.end(); ++ex) {
Slic3r::Polygons ppp = *ex;
pp.insert(pp.end(), ppp.begin(), ppp.end());
}
return pp;
}
} }

View File

@ -45,6 +45,8 @@ class ExPolygon
std::string dump_perl() const; std::string dump_perl() const;
}; };
Polygons to_polygons(const ExPolygons &expolygons);
} }
// start Boost // start Boost

View File

@ -36,8 +36,7 @@ void
ExtrusionPath::intersect_expolygons(const ExPolygonCollection &collection, ExtrusionEntityCollection* retval) const ExtrusionPath::intersect_expolygons(const ExPolygonCollection &collection, ExtrusionEntityCollection* retval) const
{ {
// perform clipping // perform clipping
Polylines clipped; Polylines clipped = intersection_pl(this->polyline, collection);
intersection<Polylines,Polylines>(this->polyline, collection, &clipped);
return this->_inflate_collection(clipped, retval); return this->_inflate_collection(clipped, retval);
} }
@ -45,8 +44,7 @@ void
ExtrusionPath::subtract_expolygons(const ExPolygonCollection &collection, ExtrusionEntityCollection* retval) const ExtrusionPath::subtract_expolygons(const ExPolygonCollection &collection, ExtrusionEntityCollection* retval) const
{ {
// perform clipping // perform clipping
Polylines clipped; Polylines clipped = diff_pl(this->polyline, collection);
diff<Polylines,Polylines>(this->polyline, collection, &clipped);
return this->_inflate_collection(clipped, retval); return this->_inflate_collection(clipped, retval);
} }
@ -113,9 +111,7 @@ ExtrusionPath::_inflate_collection(const Polylines &polylines, ExtrusionEntityCo
Polygons Polygons
ExtrusionPath::grow() const ExtrusionPath::grow() const
{ {
Polygons pp; return offset(this->polyline, +scale_(this->width/2));
offset(this->polyline, &pp, +scale_(this->width/2));
return pp;
} }
ExtrusionLoop* ExtrusionLoop*

View File

@ -283,11 +283,8 @@ GCode::change_layer(const Layer &layer)
this->first_layer = (layer.id() == 0); this->first_layer = (layer.id() == 0);
// avoid computing islands and overhangs if they're not needed // avoid computing islands and overhangs if they're not needed
if (this->config.avoid_crossing_perimeters) { if (this->config.avoid_crossing_perimeters)
ExPolygons islands; this->avoid_crossing_perimeters.init_layer_mp(union_ex(layer.slices, true));
union_(layer.slices, &islands, true);
this->avoid_crossing_perimeters.init_layer_mp(islands);
}
std::string gcode; std::string gcode;
if (this->layer_count > 0) { if (this->layer_count > 0) {

View File

@ -149,20 +149,6 @@ deg2rad(double angle)
return PI * angle / 180.0; return PI * angle / 180.0;
} }
void
simplify_polygons(const Polygons &polygons, double tolerance, Polygons* retval)
{
Polygons pp;
for (Polygons::const_iterator it = polygons.begin(); it != polygons.end(); ++it) {
Polygon p = *it;
p.points.push_back(p.points.front());
p.points = MultiPoint::_douglas_peucker(p.points, tolerance);
p.points.pop_back();
pp.push_back(p);
}
Slic3r::simplify_polygons(pp, retval);
}
double double
linint(double value, double oldmin, double oldmax, double newmin, double newmax) linint(double value, double oldmin, double oldmax, double newmin, double newmax)
{ {

View File

@ -23,7 +23,6 @@ template<class T> bool contains(const std::vector<T> &vector, const Point &point
double rad2deg(double angle); double rad2deg(double angle);
double rad2deg_dir(double angle); double rad2deg_dir(double angle);
double deg2rad(double angle); double deg2rad(double angle);
void simplify_polygons(const Polygons &polygons, double tolerance, Polygons* retval);
class ArrangeItem { class ArrangeItem {
public: public:

View File

@ -110,7 +110,7 @@ Layer::make_slices()
Polygons region_slices_p = (*layerm)->slices; Polygons region_slices_p = (*layerm)->slices;
slices_p.insert(slices_p.end(), region_slices_p.begin(), region_slices_p.end()); slices_p.insert(slices_p.end(), region_slices_p.begin(), region_slices_p.end());
} }
union_(slices_p, &slices); slices = union_ex(slices_p);
} }
this->slices.expolygons.clear(); this->slices.expolygons.clear();
@ -229,8 +229,8 @@ Layer::make_perimeters()
if (!fill_surfaces.surfaces.empty()) { if (!fill_surfaces.surfaces.empty()) {
for (LayerRegionPtrs::iterator l = layerms.begin(); l != layerms.end(); ++l) { for (LayerRegionPtrs::iterator l = layerms.begin(); l != layerms.end(); ++l) {
ExPolygons expp = intersection_ex( ExPolygons expp = intersection_ex(
fill_surfaces, (Polygons) fill_surfaces,
(*l)->slices (Polygons) (*l)->slices
); );
(*l)->fill_surfaces.surfaces.clear(); (*l)->fill_surfaces.surfaces.clear();

View File

@ -45,9 +45,8 @@ LayerRegion::flow(FlowRole role, bool bridge, double width) const
void void
LayerRegion::merge_slices() LayerRegion::merge_slices()
{ {
ExPolygons expp;
// without safety offset, artifacts are generated (GH #2494) // without safety offset, artifacts are generated (GH #2494)
union_(this->slices, &expp, true); ExPolygons expp = union_ex((Polygons)this->slices, true);
this->slices.surfaces.clear(); this->slices.surfaces.clear();
this->slices.surfaces.reserve(expp.size()); this->slices.surfaces.reserve(expp.size());

View File

@ -155,12 +155,12 @@ MotionPlanner::shortest_path(const Point &from, const Point &to)
if (!grown_env.contains(from)) { if (!grown_env.contains(from)) {
// delete second point while the line connecting first to third crosses the // delete second point while the line connecting first to third crosses the
// boundaries as many times as the current first to second // boundaries as many times as the current first to second
while (polyline.points.size() > 2 && intersection((Lines)Line(from, polyline.points[2]), grown_env).size() == 1) { while (polyline.points.size() > 2 && intersection_ln(Line(from, polyline.points[2]), grown_env).size() == 1) {
polyline.points.erase(polyline.points.begin() + 1); polyline.points.erase(polyline.points.begin() + 1);
} }
} }
if (!grown_env.contains(to)) { if (!grown_env.contains(to)) {
while (polyline.points.size() > 2 && intersection((Lines)Line(*(polyline.points.end() - 3), to), grown_env).size() == 1) { while (polyline.points.size() > 2 && intersection_ln(Line(*(polyline.points.end() - 3), to), grown_env).size() == 1) {
polyline.points.erase(polyline.points.end() - 2); polyline.points.erase(polyline.points.end() - 2);
} }
} }
@ -294,7 +294,7 @@ MotionPlannerEnv::nearest_env_point(const Point &from, const Point &to) const
size_t result = from.nearest_waypoint_index(pp, to); size_t result = from.nearest_waypoint_index(pp, to);
// as we assume 'from' is outside env, any node will require at least one crossing // as we assume 'from' is outside env, any node will require at least one crossing
if (intersection((Lines)Line(from, pp[result]), this->island).size() > 1) { if (intersection_ln(Line(from, pp[result]), this->island).size() > 1) {
// discard result // discard result
pp.erase(pp.begin() + result); pp.erase(pp.begin() + result);
} else { } else {

View File

@ -343,8 +343,7 @@ PerimeterGenerator::_traverse_loops(const PerimeterGeneratorLoops &loops,
&& !(this->object_config->support_material && this->object_config->support_material_contact_distance.value == 0)) { && !(this->object_config->support_material && this->object_config->support_material_contact_distance.value == 0)) {
// get non-overhang paths by intersecting this loop with the grown lower slices // get non-overhang paths by intersecting this loop with the grown lower slices
{ {
Polylines polylines; Polylines polylines = intersection_pl(loop->polygon, this->_lower_slices_p);
intersection((Polygons)loop->polygon, this->_lower_slices_p, &polylines);
for (Polylines::const_iterator polyline = polylines.begin(); polyline != polylines.end(); ++polyline) { for (Polylines::const_iterator polyline = polylines.begin(); polyline != polylines.end(); ++polyline) {
ExtrusionPath path(role); ExtrusionPath path(role);
@ -360,8 +359,7 @@ PerimeterGenerator::_traverse_loops(const PerimeterGeneratorLoops &loops,
// outside the grown lower slices (thus where the distance between // outside the grown lower slices (thus where the distance between
// the loop centerline and original lower slices is >= half nozzle diameter // the loop centerline and original lower slices is >= half nozzle diameter
{ {
Polylines polylines; Polylines polylines = diff_pl(loop->polygon, this->_lower_slices_p);
diff((Polygons)loop->polygon, this->_lower_slices_p, &polylines);
for (Polylines::const_iterator polyline = polylines.begin(); polyline != polylines.end(); ++polyline) { for (Polylines::const_iterator polyline = polylines.begin(); polyline != polylines.end(); ++polyline) {
ExtrusionPath path(erOverhangPerimeter); ExtrusionPath path(erOverhangPerimeter);

View File

@ -86,17 +86,13 @@ Polygon::equally_spaced_points(double distance) const
double double
Polygon::area() const Polygon::area() const
{ {
ClipperLib::Path p; return ClipperLib::Area(Slic3rMultiPoint_to_ClipperPath(*this));
Slic3rMultiPoint_to_ClipperPath(*this, &p);
return ClipperLib::Area(p);
} }
bool bool
Polygon::is_counter_clockwise() const Polygon::is_counter_clockwise() const
{ {
ClipperLib::Path p; return ClipperLib::Orientation(Slic3rMultiPoint_to_ClipperPath(*this));
Slic3rMultiPoint_to_ClipperPath(*this, &p);
return ClipperLib::Orientation(p);
} }
bool bool
@ -157,10 +153,7 @@ Polygon::simplify(double tolerance) const
Polygon p(MultiPoint::_douglas_peucker(points, tolerance)); Polygon p(MultiPoint::_douglas_peucker(points, tolerance));
p.points.pop_back(); p.points.pop_back();
Polygons pp; return simplify_polygons(p);
pp.push_back(p);
simplify_polygons(pp, &pp);
return pp;
} }
void void

View File

@ -607,20 +607,16 @@ Print::validate() const
object->model_object()->instances.front()->transform_polygon(&convex_hull); object->model_object()->instances.front()->transform_polygon(&convex_hull);
// grow convex hull with the clearance margin // grow convex hull with the clearance margin
{ convex_hull = offset(convex_hull, scale_(this->config.extruder_clearance_radius.value)/2, 1, jtRound, scale_(0.1)).front();
Polygons grown_hull;
offset(convex_hull, &grown_hull, scale_(this->config.extruder_clearance_radius.value)/2, 1, jtRound, scale_(0.1));
convex_hull = grown_hull.front();
}
// now we check that no instance of convex_hull intersects any of the previously checked object instances // now we check that no instance of convex_hull intersects any of the previously checked object instances
for (Points::const_iterator copy = object->_shifted_copies.begin(); copy != object->_shifted_copies.end(); ++copy) { for (Points::const_iterator copy = object->_shifted_copies.begin(); copy != object->_shifted_copies.end(); ++copy) {
Polygon p = convex_hull; Polygon p = convex_hull;
p.translate(*copy); p.translate(*copy);
if (intersects(a, p)) if (!intersection(a, p).empty())
throw PrintValidationException("Some objects are too close; your extruder will collide with them."); throw PrintValidationException("Some objects are too close; your extruder will collide with them.");
union_(a, p, &a); a = union_(a, p);
} }
} }
} }

View File

@ -429,7 +429,7 @@ PrintObject::bridge_over_infill()
#endif #endif
// compute the remaning internal solid surfaces as difference // compute the remaning internal solid surfaces as difference
ExPolygons not_to_bridge = diff_ex(internal_solid, to_bridge, true); ExPolygons not_to_bridge = diff_ex(internal_solid, to_polygons(to_bridge), true);
// build the new collection of fill_surfaces // build the new collection of fill_surfaces
{ {

View File

@ -54,4 +54,15 @@ Surface::is_bridge() const
|| this->surface_type == stInternalBridge; || this->surface_type == stInternalBridge;
} }
Polygons
to_polygons(const Surfaces &surfaces)
{
Slic3r::Polygons pp;
for (Surfaces::const_iterator s = surfaces.begin(); s != surfaces.end(); ++s) {
Slic3r::Polygons ppp = *s;
pp.insert(pp.end(), ppp.begin(), ppp.end());
}
return pp;
}
} }

View File

@ -34,6 +34,8 @@ class Surface
typedef std::vector<Surface> Surfaces; typedef std::vector<Surface> Surfaces;
typedef std::vector<Surface*> SurfacesPtr; typedef std::vector<Surface*> SurfacesPtr;
Polygons to_polygons(const Surfaces &surfaces);
} }
#endif #endif

View File

@ -390,10 +390,7 @@ TriangleMesh::horizontal_projection() const
} }
// the offset factor was tuned using groovemount.stl // the offset factor was tuned using groovemount.stl
offset(pp, &pp, 0.01 / SCALING_FACTOR); return union_ex(offset(pp, 0.01 / SCALING_FACTOR), true);
ExPolygons retval;
union_(pp, &retval, true);
return retval;
} }
Polygon Polygon
@ -848,14 +845,13 @@ TriangleMeshSlicer::make_expolygons(const Polygons &loops, ExPolygons* slices)
if (area[*loop_idx] > +EPSILON) { if (area[*loop_idx] > +EPSILON) {
p_slices.push_back(*loop); p_slices.push_back(*loop);
} else if (area[*loop_idx] < -EPSILON) { } else if (area[*loop_idx] < -EPSILON) {
diff(p_slices, *loop, &p_slices); p_slices = diff(p_slices, *loop);
} }
} }
// perform a safety offset to merge very close facets (TODO: find test case for this) // perform a safety offset to merge very close facets (TODO: find test case for this)
double safety_offset = scale_(0.0499); double safety_offset = scale_(0.0499);
ExPolygons ex_slices; ExPolygons ex_slices = offset2_ex(p_slices, +safety_offset, -safety_offset);
offset2(p_slices, &ex_slices, +safety_offset, -safety_offset);
#ifdef SLIC3R_DEBUG #ifdef SLIC3R_DEBUG
size_t holes_count = 0; size_t holes_count = 0;

View File

@ -531,8 +531,7 @@ SV*
polynode2perl(const ClipperLib::PolyNode& node) polynode2perl(const ClipperLib::PolyNode& node)
{ {
HV* hv = newHV(); HV* hv = newHV();
Slic3r::Polygon p; Polygon p = ClipperPath_to_Slic3rMultiPoint<Polygon>(node.Contour);
ClipperPath_to_Slic3rMultiPoint(node.Contour, &p);
if (node.IsHole()) { if (node.IsHole()) {
(void)hv_stores( hv, "hole", Slic3r::perl_to_SV_clone_ref(p) ); (void)hv_stores( hv, "hole", Slic3r::perl_to_SV_clone_ref(p) );
} else { } else {

View File

@ -8,6 +8,40 @@
%package{Slic3r::Geometry::Clipper}; %package{Slic3r::Geometry::Clipper};
Polygons offset(Polygons polygons, float delta, double scale = CLIPPER_OFFSET_SCALE,
ClipperLib::JoinType joinType = ClipperLib::jtMiter, double miterLimit = 3);
ExPolygons offset_ex(Polygons polygons, float delta, double scale = CLIPPER_OFFSET_SCALE,
ClipperLib::JoinType joinType = ClipperLib::jtMiter, double miterLimit = 3);
Polygons offset2(Polygons polygons, float delta1, float delta2, double scale = CLIPPER_OFFSET_SCALE,
ClipperLib::JoinType joinType = ClipperLib::jtMiter, double miterLimit = 3);
ExPolygons offset2_ex(Polygons polygons, float delta1, float delta2, double scale = CLIPPER_OFFSET_SCALE,
ClipperLib::JoinType joinType = ClipperLib::jtMiter, double miterLimit = 3);
Polygons diff(Polygons subject, Polygons clip, bool safety_offset = false);
ExPolygons diff_ex(Polygons subject, Polygons clip, bool safety_offset = false);
Polylines diff_pl(Polylines subject, Polygons clip);
Polygons intersection(Polygons subject, Polygons clip, bool safety_offset = false);
ExPolygons intersection_ex(Polygons subject, Polygons clip, bool safety_offset = false);
Polylines intersection_pl(Polylines subject, Polygons clip);
%name{intersection_ppl} Polylines intersection_pl(Polygons subject, Polygons clip);
%name{union} Polygons union_(Polygons subject, bool safety_offset = false);
ExPolygons union_ex(Polygons subject, bool safety_offset = false);
Polygons union_pt_chained(Polygons subject, bool safety_offset = false);
Polygons simplify_polygons(Polygons subject);
%{ %{
IV IV
@ -21,188 +55,15 @@ _constant()
RETVAL = ix; RETVAL = ix;
OUTPUT: RETVAL OUTPUT: RETVAL
Polygons
offset(polygons, delta, scale = CLIPPER_OFFSET_SCALE, joinType = ClipperLib::jtMiter, miterLimit = 3)
Polygons polygons
const float delta
double scale
ClipperLib::JoinType joinType
double miterLimit
CODE:
offset(polygons, &RETVAL, delta, scale, joinType, miterLimit);
OUTPUT:
RETVAL
ExPolygons
offset_ex(polygons, delta, scale = CLIPPER_OFFSET_SCALE, joinType = ClipperLib::jtMiter, miterLimit = 3)
Polygons polygons
const float delta
double scale
ClipperLib::JoinType joinType
double miterLimit
CODE:
offset(polygons, &RETVAL, delta, scale, joinType, miterLimit);
OUTPUT:
RETVAL
Polygons
offset2(polygons, delta1, delta2, scale = CLIPPER_OFFSET_SCALE, joinType = ClipperLib::jtMiter, miterLimit = 3)
Polygons polygons
const float delta1
const float delta2
double scale
ClipperLib::JoinType joinType
double miterLimit
CODE:
offset2(polygons, &RETVAL, delta1, delta2, scale, joinType, miterLimit);
OUTPUT:
RETVAL
ExPolygons
offset2_ex(polygons, delta1, delta2, scale = CLIPPER_OFFSET_SCALE, joinType = ClipperLib::jtMiter, miterLimit = 3)
Polygons polygons
const float delta1
const float delta2
double scale
ClipperLib::JoinType joinType
double miterLimit
CODE:
offset2(polygons, &RETVAL, delta1, delta2, scale, joinType, miterLimit);
OUTPUT:
RETVAL
Polygons
diff(subject, clip, safety_offset = false)
Polygons subject
Polygons clip
bool safety_offset
CODE:
diff(subject, clip, &RETVAL, safety_offset);
OUTPUT:
RETVAL
ExPolygons
diff_ex(subject, clip, safety_offset = false)
Polygons subject
Polygons clip
bool safety_offset
CODE:
diff(subject, clip, &RETVAL, safety_offset);
OUTPUT:
RETVAL
Polylines
diff_pl(subject, clip)
Polylines subject
Polygons clip
CODE:
diff(subject, clip, &RETVAL);
OUTPUT:
RETVAL
Polylines
diff_ppl(subject, clip)
Polygons subject
Polygons clip
CODE:
diff(subject, clip, &RETVAL);
OUTPUT:
RETVAL
Polygons
intersection(subject, clip, safety_offset = false)
Polygons subject
Polygons clip
bool safety_offset
CODE:
intersection(subject, clip, &RETVAL, safety_offset);
OUTPUT:
RETVAL
ExPolygons
intersection_ex(subject, clip, safety_offset = false)
Polygons subject
Polygons clip
bool safety_offset
CODE:
intersection(subject, clip, &RETVAL, safety_offset);
OUTPUT:
RETVAL
Polylines
intersection_pl(subject, clip)
Polylines subject
Polygons clip
CODE:
intersection(subject, clip, &RETVAL);
OUTPUT:
RETVAL
Polylines
intersection_ppl(subject, clip)
Polygons subject
Polygons clip
CODE:
intersection(subject, clip, &RETVAL);
OUTPUT:
RETVAL
ExPolygons
xor_ex(subject, clip, safety_offset = false)
Polygons subject
Polygons clip
bool safety_offset
CODE:
xor_(subject, clip, &RETVAL, safety_offset);
OUTPUT:
RETVAL
Polygons
union(subject, safety_offset = false)
Polygons subject
bool safety_offset
CODE:
union_(subject, &RETVAL, safety_offset);
OUTPUT:
RETVAL
ExPolygons
union_ex(subject, safety_offset = false)
Polygons subject
bool safety_offset
CODE:
union_(subject, &RETVAL, safety_offset);
OUTPUT:
RETVAL
SV* SV*
union_pt(subject, safety_offset = false) union_pt(subject, safety_offset = false)
Polygons subject Polygons subject
bool safety_offset bool safety_offset
CODE: CODE:
// perform operation // perform operation
ClipperLib::PolyTree polytree; ClipperLib::PolyTree polytree = union_pt(subject, safety_offset);
union_pt(subject, &polytree, safety_offset);
RETVAL = polynode_children_2_perl(polytree); RETVAL = polynode_children_2_perl(polytree);
OUTPUT: OUTPUT:
RETVAL RETVAL
Polygons
union_pt_chained(subject, safety_offset = false)
Polygons subject
bool safety_offset
CODE:
union_pt_chained(subject, &RETVAL, safety_offset);
OUTPUT:
RETVAL
Polygons
simplify_polygons(subject)
Polygons subject
CODE:
simplify_polygons(subject, &RETVAL);
OUTPUT:
RETVAL
%} %}

View File

@ -81,15 +81,6 @@ deg2rad(angle)
OUTPUT: OUTPUT:
RETVAL RETVAL
Polygons
simplify_polygons(polygons, tolerance)
Polygons polygons
double tolerance
CODE:
Slic3r::Geometry::simplify_polygons(polygons, tolerance, &RETVAL);
OUTPUT:
RETVAL
IV IV
_constant() _constant()

View File

@ -86,7 +86,7 @@ Polyline::grow(delta, scale = CLIPPER_OFFSET_SCALE, joinType = ClipperLib::jtSqu
ClipperLib::JoinType joinType ClipperLib::JoinType joinType
double miterLimit double miterLimit
CODE: CODE:
offset(*THIS, &RETVAL, delta, scale, joinType, miterLimit); RETVAL = offset(*THIS, delta, scale, joinType, miterLimit);
OUTPUT: OUTPUT:
RETVAL RETVAL

View File

@ -89,7 +89,7 @@ Surface::offset(delta, scale = CLIPPER_OFFSET_SCALE, joinType = ClipperLib::jtMi
ClipperLib::JoinType joinType ClipperLib::JoinType joinType
double miterLimit double miterLimit
CODE: CODE:
offset(*THIS, &RETVAL, delta, scale, joinType, miterLimit); RETVAL = offset(*THIS, delta, scale, joinType, miterLimit);
OUTPUT: OUTPUT:
RETVAL RETVAL

View File

@ -198,7 +198,8 @@
%typemap{LayerPtrs*}; %typemap{LayerPtrs*};
%typemap{SupportLayerPtrs*}; %typemap{SupportLayerPtrs*};
%typemap{ClipperLib::JoinType}{simple};
%typemap{ClipperLib::PolyFillType}{simple};
%typemap{Axis}{parsed}{ %typemap{Axis}{parsed}{
%cpp_type{Axis}; %cpp_type{Axis};
%precall_code{% %precall_code{%