diff --git a/lib/Slic3r/GCode.pm b/lib/Slic3r/GCode.pm index b147e9173..2c41f4c3a 100644 --- a/lib/Slic3r/GCode.pm +++ b/lib/Slic3r/GCode.pm @@ -264,8 +264,7 @@ sub extrude_loop { # the rotation of the second segment so we might cross the object boundary my $first_segment = Slic3r::Line->new(@{$extrusion_path->polyline}[0,1]); my $distance = min(scale $extrusion_path->flow_spacing, $first_segment->length); - my $point = Slic3r::Geometry::point_along_segment(@$first_segment, $distance); - $point = Slic3r::Point->new(@$point); + my $point = $first_segment->point_at($distance); $point->rotate($angle, $extrusion_path->first_point); # generate the travel move @@ -474,8 +473,8 @@ sub retract { my $wipe_path; if ($self->extruder->wipe && $self->wipe_path) { my @points = @{$self->wipe_path}; - $wipe_path = Slic3r::Polyline->new($self->last_pos, @{$self->wipe_path}[1..$#{$self->wipe_path}]) - ->clip_start($self->extruder->scaled_wipe_distance); + $wipe_path = Slic3r::Polyline->new($self->last_pos, @{$self->wipe_path}[1..$#{$self->wipe_path}]); + $wipe_path->clip_end($wipe_path->length - $self->extruder->scaled_wipe_distance); } # prepare moves diff --git a/lib/Slic3r/Polyline.pm b/lib/Slic3r/Polyline.pm index 6a60b0d0f..a59a6c196 100644 --- a/lib/Slic3r/Polyline.pm +++ b/lib/Slic3r/Polyline.pm @@ -35,11 +35,6 @@ sub simplify { return __PACKAGE__->new(@$simplified); } -sub length { - my $self = shift; - return Boost::Geometry::Utils::linestring_length($self->pp); -} - sub grow { my $self = shift; my ($distance, $scale, $joinType, $miterLimit) = @_; @@ -85,53 +80,6 @@ sub align_to_origin { return $self->translate(-$bb->x_min, -$bb->y_min); } -# removes the given distance from the end of the polyline -sub clip_end { - my $self = shift; - my ($distance) = @_; - - while ($distance > 0) { - my $last_point = $self->last_point->clone; - $self->pop_back; - last if @$self == 0; - - my $last_segment_length = $last_point->distance_to($self->last_point); - if ($last_segment_length <= $distance) { - $distance -= $last_segment_length; - next; - } - - my $new_point = Slic3r::Geometry::point_along_segment($last_point, $self->last_point, $distance); - $self->append($new_point); - $distance = 0; - } -} - -# only keeps the given distance at the beginning of the polyline -sub clip_start { - my $self = shift; - my ($distance) = @_; - - my @my_points = @$self; - my $points = [ $my_points[0]->clone ]; - - for (my $i = 1; $distance > 0 && $i <= $#my_points; $i++) { - my $point = $my_points[$i]; - my $segment_length = $point->distance_to($my_points[$i-1]); - if ($segment_length <= $distance) { - $distance -= $segment_length; - push @$points, $point; - next; - } - - my $new_point = Slic3r::Geometry::point_along_segment($my_points[$i-1], $point, $distance); - push @$points, Slic3r::Point->new(@$new_point); - $distance = 0; - } - - return __PACKAGE__->new(@$points); -} - # this method returns a collection of points picked on the polygon contour # so that they are evenly spaced according to the input distance # (find a better name!) diff --git a/xs/src/Line.cpp b/xs/src/Line.cpp index 42a201324..4f60a2304 100644 --- a/xs/src/Line.cpp +++ b/xs/src/Line.cpp @@ -42,6 +42,18 @@ Line::midpoint() const return new Point ((this->a.x + this->b.x) / 2.0, (this->a.y + this->b.y) / 2.0); } +Point* +Line::point_at(double distance) const +{ + double len = this->length(); + Point* p = new Point(this->a); + if (this->a.x != this->b.x) + p->x = this->a.x + (this->b.x - this->a.x) * distance / len; + if (this->a.y != this->b.y) + p->y = this->a.y + (this->b.y - this->a.y) * distance / len; + return p; +} + #ifdef SLIC3RXS void Line::from_SV(SV* line_sv) diff --git a/xs/src/Line.hpp b/xs/src/Line.hpp index d6675e5af..795590d5e 100644 --- a/xs/src/Line.hpp +++ b/xs/src/Line.hpp @@ -19,6 +19,7 @@ class Line void reverse(); double length() const; Point* midpoint() const; + Point* point_at(double distance) const; #ifdef SLIC3RXS void from_SV(SV* line_sv); diff --git a/xs/src/MultiPoint.cpp b/xs/src/MultiPoint.cpp index 06aaa0ef2..8e24c9941 100644 --- a/xs/src/MultiPoint.cpp +++ b/xs/src/MultiPoint.cpp @@ -38,6 +38,17 @@ MultiPoint::first_point() const return new Point(this->points.front()); } +double +MultiPoint::length() const +{ + Lines lines = this->lines(); + double len = 0; + for (Lines::iterator it = lines.begin(); it != lines.end(); ++it) { + len += it->length(); + } + return len; +} + #ifdef SLIC3RXS void MultiPoint::from_SV(SV* poly_sv) diff --git a/xs/src/MultiPoint.hpp b/xs/src/MultiPoint.hpp index 0c20eb357..2473551fd 100644 --- a/xs/src/MultiPoint.hpp +++ b/xs/src/MultiPoint.hpp @@ -1,6 +1,7 @@ #ifndef slic3r_MultiPoint_hpp_ #define slic3r_MultiPoint_hpp_ +#include "Line.hpp" #include "Point.hpp" #include #include @@ -17,6 +18,8 @@ class MultiPoint void reverse(); Point* first_point() const; virtual Point* last_point() const = 0; + virtual Lines lines() const = 0; + double length() const; #ifdef SLIC3RXS void from_SV(SV* poly_sv); diff --git a/xs/src/Polyline.cpp b/xs/src/Polyline.cpp index 3046f6b47..7f7c36f12 100644 --- a/xs/src/Polyline.cpp +++ b/xs/src/Polyline.cpp @@ -19,6 +19,27 @@ Polyline::lines() const return lines; } +// removes the given distance from the end of the polyline +void +Polyline::clip_end(double distance) +{ + while (distance > 0) { + Point last_point = *this->last_point(); + this->points.pop_back(); + if (this->points.empty()) break; + + double last_segment_length = last_point.distance_to(this->last_point()); + if (last_segment_length <= distance) { + distance -= last_segment_length; + continue; + } + + Line segment(last_point, *this->last_point()); + this->points.push_back(*segment.point_at(distance)); + distance = 0; + } +} + #ifdef SLIC3RXS SV* Polyline::to_SV_ref() diff --git a/xs/src/Polyline.hpp b/xs/src/Polyline.hpp index 5ec702726..2636dc406 100644 --- a/xs/src/Polyline.hpp +++ b/xs/src/Polyline.hpp @@ -10,6 +10,7 @@ class Polyline : public MultiPoint { public: Point* last_point() const; Lines lines() const; + void clip_end(double distance); #ifdef SLIC3RXS SV* to_SV_ref(); diff --git a/xs/t/09_polyline.t b/xs/t/09_polyline.t index e141a9c2f..d18f6fbc7 100644 --- a/xs/t/09_polyline.t +++ b/xs/t/09_polyline.t @@ -4,7 +4,7 @@ use strict; use warnings; use Slic3r::XS; -use Test::More tests => 5; +use Test::More tests => 6; my $points = [ [100, 100], @@ -28,4 +28,10 @@ is_deeply [ map $_->pp, @$lines ], [ $polyline->append_polyline($polyline->clone); is_deeply $polyline->pp, [ @$points, @$points ], 'append_polyline'; +{ + my $len = $polyline->length; + $polyline->clip_end($len/3); + ok abs($polyline->length - ($len-($len/3))) < 1, 'clip_end'; +} + __END__ diff --git a/xs/xsp/Line.xsp b/xs/xsp/Line.xsp index d3a3ce37c..39c54b48c 100644 --- a/xs/xsp/Line.xsp +++ b/xs/xsp/Line.xsp @@ -23,6 +23,8 @@ double length(); Point* midpoint() %code{% const char* CLASS = "Slic3r::Point"; RETVAL = THIS->midpoint(); %}; + Point* point_at(double distance) + %code{% const char* CLASS = "Slic3r::Point"; RETVAL = THIS->point_at(distance); %}; %{ Line* diff --git a/xs/xsp/Polygon.xsp b/xs/xsp/Polygon.xsp index 58c3d0883..810940c53 100644 --- a/xs/xsp/Polygon.xsp +++ b/xs/xsp/Polygon.xsp @@ -23,6 +23,7 @@ %code{% const char* CLASS = "Slic3r::Polyline"; RETVAL = THIS->split_at_index(index); %}; Polyline* split_at_first_point() %code{% const char* CLASS = "Slic3r::Polyline"; RETVAL = THIS->split_at_first_point(); %}; + double length(); double area(); bool is_counter_clockwise(); bool is_clockwise(); diff --git a/xs/xsp/Polyline.xsp b/xs/xsp/Polyline.xsp index 3f681f3cb..9566cb3cd 100644 --- a/xs/xsp/Polyline.xsp +++ b/xs/xsp/Polyline.xsp @@ -23,6 +23,8 @@ %code{% const char* CLASS = "Slic3r::Point"; RETVAL = THIS->first_point(); %}; Point* last_point() %code{% const char* CLASS = "Slic3r::Point"; RETVAL = THIS->last_point(); %}; + double length(); + void clip_end(double distance); %{ Polyline*