diff --git a/lib/Slic3r/ExtrusionPath.pm b/lib/Slic3r/ExtrusionPath.pm index be97e3baa..5b8cff611 100644 --- a/lib/Slic3r/ExtrusionPath.pm +++ b/lib/Slic3r/ExtrusionPath.pm @@ -27,22 +27,6 @@ sub clip_with_expolygon { $self->polyline->clip_with_expolygon($expolygon); } -sub intersect_expolygons { - my $self = shift; - my ($expolygons_pp) = @_; - - return map $self->clone(polyline => Slic3r::Polyline->new(@$_)), - @{Boost::Geometry::Utils::multi_polygon_multi_linestring_intersection($expolygons_pp, [$self->pp])}; -} - -sub subtract_expolygons { - my $self = shift; - my ($expolygons_pp) = @_; - - return map $self->clone(polyline => Slic3r::Polyline->new(@$_)), - @{Boost::Geometry::Utils::multi_linestring_multi_polygon_difference([$self->pp], $expolygons_pp)}; -} - sub simplify { my $self = shift; $self->polyline($self->polyline->simplify(@_)); diff --git a/lib/Slic3r/GCode.pm b/lib/Slic3r/GCode.pm index 55ae1b6e4..008ab4669 100644 --- a/lib/Slic3r/GCode.pm +++ b/lib/Slic3r/GCode.pm @@ -17,7 +17,7 @@ has 'layer_count' => (is => 'ro', required => 1 ); has 'layer' => (is => 'rw'); has '_layer_islands' => (is => 'rw'); has '_upper_layer_islands' => (is => 'rw'); -has '_layer_overhangs_pp' => (is => 'rw'); +has '_layer_overhangs' => (is => 'ro', default => sub { Slic3r::ExPolygon::Collection->new }); has 'shift_x' => (is => 'rw', default => sub {0} ); has 'shift_y' => (is => 'rw', default => sub {0} ); has 'z' => (is => 'rw'); @@ -95,12 +95,13 @@ sub change_layer { # avoid computing islands and overhangs if they're not needed $self->_layer_islands($layer->islands); $self->_upper_layer_islands($layer->upper_layer ? $layer->upper_layer->islands : []); - $self->_layer_overhangs_pp( - # clone ExPolygons because they come from Surface objects but will be used outside here - ($layer->id > 0 && ($layer->config->overhangs || $Slic3r::Config->start_perimeters_at_non_overhang)) - ? [ map $_->expolygon->pp, grep $_->surface_type == S_TYPE_BOTTOM, map @{$_->slices}, @{$layer->regions} ] - : [] + $self->_layer_overhangs->clear; + if ($layer->id > 0 && ($layer->config->overhangs || $Slic3r::Config->start_perimeters_at_non_overhang)) { + $self->_layer_overhangs->append( + # clone ExPolygons because they come from Surface objects but will be used outside here + map $_->expolygon, map @{$_->slices->filter_by_type(S_TYPE_BOTTOM)}, @{$layer->regions} ); + } if ($self->config->avoid_crossing_perimeters) { $self->layer_mp(Slic3r::GCode::MotionPlanner->new( islands => union_ex([ map @$_, @{$layer->slices} ], 1), @@ -176,7 +177,7 @@ sub extrude_loop { } my @candidates = (); if ($Slic3r::Config->start_perimeters_at_non_overhang) { - @candidates = grep !Boost::Geometry::Utils::point_covered_by_multi_polygon($_->pp, $self->_layer_overhangs_pp), @concave; + @candidates = grep !$self->_layer_overhangs->contains_point($_), @concave; } if (!@candidates) { # if none, look for any concave vertex @@ -184,7 +185,7 @@ sub extrude_loop { if (!@candidates) { # if none, look for any non-overhang vertex if ($Slic3r::Config->start_perimeters_at_non_overhang) { - @candidates = grep !Boost::Geometry::Utils::point_covered_by_multi_polygon($_->pp, $self->_layer_overhangs_pp), @$polygon; + @candidates = grep !$self->_layer_overhangs->contains_point($_), @$polygon; } if (!@candidates) { # if none, all points are valid candidates @@ -214,10 +215,11 @@ sub extrude_loop { my @paths = (); # detect overhanging/bridging perimeters - if ($self->layer->config->overhangs && $extrusion_path->is_perimeter && @{$self->_layer_overhangs_pp}) { + if ($self->layer->config->overhangs && $extrusion_path->is_perimeter && $self->_layer_overhangs->count > 0) { # get non-overhang paths by subtracting overhangs from the loop push @paths, - $extrusion_path->subtract_expolygons($self->_layer_overhangs_pp); + map $_->clone, + @{$extrusion_path->subtract_expolygons($self->_layer_overhangs)}; # get overhang paths by intersecting overhangs with the loop push @paths, @@ -226,7 +228,8 @@ sub extrude_loop { $_->flow_spacing($self->extruder->bridge_flow->width); $_ } - $extrusion_path->intersect_expolygons($self->_layer_overhangs_pp); + map $_->clone, + @{$extrusion_path->intersect_expolygons($self->_layer_overhangs)}; # reapply the nearest point search for starting point # (clone because the collection gets DESTROY'ed) diff --git a/xs/src/ExPolygonCollection.cpp b/xs/src/ExPolygonCollection.cpp index d0f84990c..da257ca39 100644 --- a/xs/src/ExPolygonCollection.cpp +++ b/xs/src/ExPolygonCollection.cpp @@ -2,6 +2,18 @@ namespace Slic3r { +ExPolygonCollection::operator Polygons() const +{ + Polygons polygons; + for (ExPolygons::const_iterator it = this->expolygons.begin(); it != this->expolygons.end(); ++it) { + polygons.push_back(it->contour); + for (Polygons::const_iterator ith = it->holes.begin(); ith != it->holes.end(); ++ith) { + polygons.push_back(*ith); + } + } + return polygons; +} + void ExPolygonCollection::scale(double factor) { @@ -26,4 +38,13 @@ ExPolygonCollection::rotate(double angle, Point* center) } } +bool +ExPolygonCollection::contains_point(const Point* point) const +{ + for (ExPolygons::const_iterator it = this->expolygons.begin(); it != this->expolygons.end(); ++it) { + if (it->contains_point(point)) return true; + } + return false; +} + } diff --git a/xs/src/ExPolygonCollection.hpp b/xs/src/ExPolygonCollection.hpp index 357b7fb50..d4b7d8162 100644 --- a/xs/src/ExPolygonCollection.hpp +++ b/xs/src/ExPolygonCollection.hpp @@ -10,9 +10,11 @@ class ExPolygonCollection { public: ExPolygons expolygons; + operator Polygons() const; void scale(double factor); void translate(double x, double y); void rotate(double angle, Point* center); + bool contains_point(const Point* point) const; }; } diff --git a/xs/src/ExtrusionEntity.cpp b/xs/src/ExtrusionEntity.cpp index 974e8910f..e6461a9f8 100644 --- a/xs/src/ExtrusionEntity.cpp +++ b/xs/src/ExtrusionEntity.cpp @@ -1,4 +1,7 @@ #include "ExtrusionEntity.hpp" +#include "ExtrusionEntityCollection.hpp" +#include "ExPolygonCollection.hpp" +#include "ClipperUtils.hpp" namespace Slic3r { @@ -26,6 +29,36 @@ ExtrusionPath::last_point() const return new Point(this->polyline.points.back()); } +ExtrusionEntityCollection* +ExtrusionPath::intersect_expolygons(ExPolygonCollection* collection) const +{ + // perform clipping + Polylines clipped; + intersection(this->polyline, *collection, clipped); + return this->_inflate_collection(clipped); +} + +ExtrusionEntityCollection* +ExtrusionPath::subtract_expolygons(ExPolygonCollection* collection) const +{ + // perform clipping + Polylines clipped; + diff(this->polyline, *collection, clipped); + return this->_inflate_collection(clipped); +} + +ExtrusionEntityCollection* +ExtrusionPath::_inflate_collection(const Polylines &polylines) const +{ + ExtrusionEntityCollection* retval = new ExtrusionEntityCollection(); + for (Polylines::const_iterator it = polylines.begin(); it != polylines.end(); ++it) { + ExtrusionPath* path = this->clone(); + path->polyline = *it; + retval->entities.push_back(path); + } + return retval; +} + ExtrusionLoop* ExtrusionLoop::clone() const { diff --git a/xs/src/ExtrusionEntity.hpp b/xs/src/ExtrusionEntity.hpp index c9dd6b080..6d5dc9a89 100644 --- a/xs/src/ExtrusionEntity.hpp +++ b/xs/src/ExtrusionEntity.hpp @@ -7,6 +7,9 @@ namespace Slic3r { +class ExPolygonCollection; +class ExtrusionEntityCollection; + enum ExtrusionRole { erPerimeter, erExternalPerimeter, @@ -45,6 +48,10 @@ class ExtrusionPath : public ExtrusionEntity void reverse(); Point* first_point() const; Point* last_point() const; + ExtrusionEntityCollection* intersect_expolygons(ExPolygonCollection* collection) const; + ExtrusionEntityCollection* subtract_expolygons(ExPolygonCollection* collection) const; + private: + ExtrusionEntityCollection* _inflate_collection(const Polylines &polylines) const; }; class ExtrusionLoop : public ExtrusionEntity diff --git a/xs/src/Polyline.cpp b/xs/src/Polyline.cpp index fc3950757..326a309d7 100644 --- a/xs/src/Polyline.cpp +++ b/xs/src/Polyline.cpp @@ -1,7 +1,15 @@ #include "Polyline.hpp" +#include "Polygon.hpp" namespace Slic3r { +Polyline::operator Polylines() const +{ + Polylines polylines(1); + polylines.push_back(*this); + return polylines; +} + Point* Polyline::last_point() const { diff --git a/xs/src/Polyline.hpp b/xs/src/Polyline.hpp index c17b97f9f..59410dd2d 100644 --- a/xs/src/Polyline.hpp +++ b/xs/src/Polyline.hpp @@ -6,8 +6,12 @@ namespace Slic3r { +class Polyline; +typedef std::vector Polylines; + class Polyline : public MultiPoint { public: + operator Polylines() const; Point* last_point() const; Lines lines() const; void clip_end(double distance); @@ -20,8 +24,6 @@ class Polyline : public MultiPoint { #endif }; -typedef std::vector Polylines; - } #endif diff --git a/xs/xsp/ExPolygonCollection.xsp b/xs/xsp/ExPolygonCollection.xsp index 0e6e50c00..7a108235f 100644 --- a/xs/xsp/ExPolygonCollection.xsp +++ b/xs/xsp/ExPolygonCollection.xsp @@ -16,6 +16,7 @@ void rotate(double angle, Point* center); int count() %code{% RETVAL = THIS->expolygons.size(); %}; + bool contains_point(Point* point); %{ ExPolygonCollection* diff --git a/xs/xsp/ExtrusionPath.xsp b/xs/xsp/ExtrusionPath.xsp index db2db16ad..2f92b3f45 100644 --- a/xs/xsp/ExtrusionPath.xsp +++ b/xs/xsp/ExtrusionPath.xsp @@ -20,6 +20,10 @@ %code{% const char* CLASS = "Slic3r::Point"; RETVAL = THIS->first_point(); %}; Point* last_point() %code{% const char* CLASS = "Slic3r::Point"; RETVAL = THIS->last_point(); %}; + ExtrusionEntityCollection* intersect_expolygons(ExPolygonCollection* collection) + %code{% const char* CLASS = "Slic3r::ExtrusionPath::Collection"; RETVAL = THIS->intersect_expolygons(collection); %}; + ExtrusionEntityCollection* subtract_expolygons(ExPolygonCollection* collection) + %code{% const char* CLASS = "Slic3r::ExtrusionPath::Collection"; RETVAL = THIS->subtract_expolygons(collection); %}; %{ ExtrusionPath* diff --git a/xs/xsp/typemap.xspt b/xs/xsp/typemap.xspt index 1928e91f2..22659855a 100644 --- a/xs/xsp/typemap.xspt +++ b/xs/xsp/typemap.xspt @@ -7,6 +7,7 @@ %typemap{AV*}; %typemap{Point*}; %typemap{ExPolygon*}; +%typemap{ExPolygonCollection*}; %typemap{Line*}; %typemap{Polyline*}; %typemap{Polygon*};