From bd7b0e2aedcf698fbeff2f601ec17521d6f279e8 Mon Sep 17 00:00:00 2001 From: Alessandro Ranellucci Date: Thu, 29 Aug 2013 11:47:59 +0200 Subject: [PATCH] Ported ExtrusionPath::Collection->chained_path --- lib/Slic3r/ExtrusionPath/Collection.pm | 36 ------------- lib/Slic3r/GCode.pm | 2 +- lib/Slic3r/GCode/Layer.pm | 6 +-- lib/Slic3r/Layer/Region.pm | 10 ++-- t/fill.t | 8 +-- xs/src/ExtrusionEntity.cpp | 38 +++++++++++-- xs/src/ExtrusionEntity.hpp | 13 ++++- xs/src/ExtrusionEntityCollection.cpp | 75 ++++++++++++++++++++++++++ xs/src/ExtrusionEntityCollection.hpp | 6 +++ xs/t/12_extrusionpathcollection.t | 29 +++++++++- xs/xsp/ExtrusionEntityCollection.xsp | 4 ++ 11 files changed, 170 insertions(+), 57 deletions(-) create mode 100644 xs/src/ExtrusionEntityCollection.cpp diff --git a/lib/Slic3r/ExtrusionPath/Collection.pm b/lib/Slic3r/ExtrusionPath/Collection.pm index 3be58d306..3dfffa702 100644 --- a/lib/Slic3r/ExtrusionPath/Collection.pm +++ b/lib/Slic3r/ExtrusionPath/Collection.pm @@ -2,42 +2,6 @@ package Slic3r::ExtrusionPath::Collection; use strict; use warnings; -sub first_point { - my $self = shift; - return $self->[0]->[0]; -} - -# (Same algorithm as Polyline::Collection) -sub chained_path { - my $self = shift; - my ($start_near, $no_reverse) = @_; - - my @my_paths = @$self; - return @my_paths if $self->no_sort; - - my @paths = (); - my $start_at; - my $endpoints = $no_reverse - ? [ map { @$_[0,0] } @my_paths ] - : [ map { @$_[0,-1] } @my_paths ]; - while (@my_paths) { - # find nearest point - my $start_index = defined $start_near - ? $start_near->nearest_point_index($endpoints) - : 0; - - my $path_index = int($start_index/2); - if ($start_index % 2 && !$no_reverse) { # index is end so reverse to make it the start - # path is reversed in place, but we got a copy from XS - $my_paths[$path_index]->reverse; - } - push @paths, splice @my_paths, $path_index, 1; - splice @$endpoints, $path_index*2, 2; - $start_near = $paths[-1]->last_point; - } - return @paths; -} - sub cleanup { my $self = shift; diff --git a/lib/Slic3r/GCode.pm b/lib/Slic3r/GCode.pm index e32121409..26cb7462d 100644 --- a/lib/Slic3r/GCode.pm +++ b/lib/Slic3r/GCode.pm @@ -228,7 +228,7 @@ sub extrude_loop { $extrusion_path->intersect_expolygons($self->_layer_overhangs); # reapply the nearest point search for starting point - @paths = Slic3r::ExtrusionPath::Collection->new(@paths)->chained_path($start_at, 1); + @paths = @{Slic3r::ExtrusionPath::Collection->new(@paths)->chained_path_from($start_at, 1)}; } else { push @paths, $extrusion_path; } diff --git a/lib/Slic3r/GCode/Layer.pm b/lib/Slic3r/GCode/Layer.pm index 7e74899df..aa6af1d60 100644 --- a/lib/Slic3r/GCode/Layer.pm +++ b/lib/Slic3r/GCode/Layer.pm @@ -111,12 +111,12 @@ sub process_layer { if ($layer->support_interface_fills) { $gcode .= $self->gcodegen->set_extruder($self->extruders->[$Slic3r::Config->support_material_interface_extruder-1]); $gcode .= $self->gcodegen->extrude_path($_, 'support material interface') - for $layer->support_interface_fills->chained_path($self->gcodegen->last_pos); + for @{$layer->support_interface_fills->chained_path_from($self->gcodegen->last_pos, 0)}; } if ($layer->support_fills) { $gcode .= $self->gcodegen->set_extruder($self->extruders->[$Slic3r::Config->support_material_extruder-1]); $gcode .= $self->gcodegen->extrude_path($_, 'support material') - for $layer->support_fills->chained_path($self->gcodegen->last_pos); + for @{$layer->support_fills->chained_path_from($self->gcodegen->last_pos, 0)}; } } @@ -214,7 +214,7 @@ sub _extrude_infill { for my $fill (@{ $island->{fills} }) { if ($fill->isa('Slic3r::ExtrusionPath::Collection')) { $gcode .= $self->gcodegen->extrude($_, 'fill') - for $fill->chained_path($self->gcodegen->last_pos); + for @{$fill->chained_path_from($self->gcodegen->last_pos, 0)}; } else { $gcode .= $self->gcodegen->extrude($fill, 'fill') ; } diff --git a/lib/Slic3r/Layer/Region.pm b/lib/Slic3r/Layer/Region.pm index 0c48ee7b9..5eb57928a 100644 --- a/lib/Slic3r/Layer/Region.pm +++ b/lib/Slic3r/Layer/Region.pm @@ -300,15 +300,13 @@ sub make_perimeters { $self->perimeters->append(@loops); # add thin walls as perimeters - push @{ $self->perimeters }, Slic3r::ExtrusionPath::Collection->new( - map { - Slic3r::ExtrusionPath->new( + push @{ $self->perimeters }, @{Slic3r::ExtrusionPath::Collection->new( + map Slic3r::ExtrusionPath->new( polyline => ($_->isa('Slic3r::Polygon') ? $_->split_at_first_point : $_), role => EXTR_ROLE_EXTERNAL_PERIMETER, flow_spacing => $self->perimeter_flow->spacing, - ); - } @{ $self->thin_walls } - )->chained_path; + ), @{ $self->thin_walls } + )->chained_path(0)}; } sub _fill_gaps { diff --git a/t/fill.t b/t/fill.t index 256d6235b..a4138f6bc 100644 --- a/t/fill.t +++ b/t/fill.t @@ -115,7 +115,7 @@ sub scale_points (@) { map [scale $_->[X], scale $_->[Y]], @_ } Slic3r::Polyline->new([0,10], [0,8], [0,5]), ]); is_deeply - [ map $_->[Y], map @$_, $collection->chained_path(Slic3r::Point->new(0,30)) ], + [ map $_->[Y], map @$_, $collection->chained_path(Slic3r::Point->new(0,30), 0) ], [20, 18, 15, 10, 8, 5], 'chained path'; } @@ -126,7 +126,7 @@ sub scale_points (@) { map [scale $_->[X], scale $_->[Y]], @_ } Slic3r::Polyline->new([10,5], [15,5], [20,5]), ]); is_deeply - [ map $_->[X], map @$_, $collection->chained_path(Slic3r::Point->new(30,0)) ], + [ map $_->[X], map @$_, $collection->chained_path(Slic3r::Point->new(30,0), 0) ], [reverse 4, 10, 15, 10, 15, 20], 'chained path'; } @@ -138,7 +138,7 @@ sub scale_points (@) { map [scale $_->[X], scale $_->[Y]], @_ } Slic3r::Polyline->new([0,10], [0,8], [0,5]), ); is_deeply - [ map $_->[Y], map @{$_->polyline}, $collection->chained_path(Slic3r::Point->new(0,30)) ], + [ map $_->[Y], map @{$_->polyline}, @{$collection->chained_path_from(Slic3r::Point->new(0,30), 0)} ], [20, 18, 15, 10, 8, 5], 'chained path'; } @@ -150,7 +150,7 @@ sub scale_points (@) { map [scale $_->[X], scale $_->[Y]], @_ } Slic3r::Polyline->new([10,5], [15,5], [20,5]), ); is_deeply - [ map $_->[X], map @{$_->polyline}, $collection->chained_path(Slic3r::Point->new(30,0)) ], + [ map $_->[X], map @{$_->polyline}, @{$collection->chained_path_from(Slic3r::Point->new(30,0), 0)} ], [reverse 4, 10, 15, 10, 15, 20], 'chained path'; } diff --git a/xs/src/ExtrusionEntity.cpp b/xs/src/ExtrusionEntity.cpp index 9c0012f54..7e8b48fc9 100644 --- a/xs/src/ExtrusionEntity.cpp +++ b/xs/src/ExtrusionEntity.cpp @@ -2,24 +2,36 @@ namespace Slic3r { +ExtrusionPath* +ExtrusionPath::clone() const +{ + return new ExtrusionPath (*this); +} + void ExtrusionPath::reverse() { this->polyline.reverse(); } -const Point* -ExtrusionPath::first_point() const +Point* +ExtrusionPath::first_point() { return &(this->polyline.points.front()); } -const Point* -ExtrusionPath::last_point() const +Point* +ExtrusionPath::last_point() { return &(this->polyline.points.back()); } +ExtrusionLoop* +ExtrusionLoop::clone() const +{ + return new ExtrusionLoop (*this); +} + ExtrusionPath* ExtrusionLoop::split_at_index(int index) { @@ -47,4 +59,22 @@ ExtrusionLoop::make_counter_clockwise() return this->polygon.make_counter_clockwise(); } +void +ExtrusionLoop::reverse() +{ + // no-op +} + +Point* +ExtrusionLoop::first_point() +{ + return &(this->polygon.points.front()); +} + +Point* +ExtrusionLoop::last_point() +{ + return &(this->polygon.points.front()); // in polygons, first == last +} + } diff --git a/xs/src/ExtrusionEntity.hpp b/xs/src/ExtrusionEntity.hpp index 0f8f1cb2a..0ce0f790a 100644 --- a/xs/src/ExtrusionEntity.hpp +++ b/xs/src/ExtrusionEntity.hpp @@ -25,10 +25,14 @@ enum ExtrusionRole { class ExtrusionEntity { public: + virtual ExtrusionEntity* clone() const = 0; virtual ~ExtrusionEntity() {}; ExtrusionRole role; double height; // vertical thickness of the extrusion expressed in mm double flow_spacing; + virtual void reverse() = 0; + virtual Point* first_point() = 0; + virtual Point* last_point() = 0; }; typedef std::vector ExtrusionEntitiesPtr; @@ -36,19 +40,24 @@ typedef std::vector ExtrusionEntitiesPtr; class ExtrusionPath : public ExtrusionEntity { public: + ExtrusionPath* clone() const; Polyline polyline; void reverse(); - const Point* first_point() const; - const Point* last_point() const; + Point* first_point(); + Point* last_point(); }; class ExtrusionLoop : public ExtrusionEntity { public: + ExtrusionLoop* clone() const; Polygon polygon; ExtrusionPath* split_at_index(int index); ExtrusionPath* split_at_first_point(); bool make_counter_clockwise(); + void reverse(); + Point* first_point(); + Point* last_point(); }; } diff --git a/xs/src/ExtrusionEntityCollection.cpp b/xs/src/ExtrusionEntityCollection.cpp new file mode 100644 index 000000000..2b0df0eb2 --- /dev/null +++ b/xs/src/ExtrusionEntityCollection.cpp @@ -0,0 +1,75 @@ +#include "ExtrusionEntityCollection.hpp" + +namespace Slic3r { + +ExtrusionEntityCollection* +ExtrusionEntityCollection::clone() const +{ + return new ExtrusionEntityCollection (*this); +} + +void +ExtrusionEntityCollection::reverse() +{ + for (ExtrusionEntitiesPtr::iterator it = this->entities.begin(); it != this->entities.end(); ++it) { + (*it)->reverse(); + } + std::reverse(this->entities.begin(), this->entities.end()); +} + +Point* +ExtrusionEntityCollection::first_point() +{ + return this->entities.front()->first_point(); +} + +Point* +ExtrusionEntityCollection::last_point() +{ + return this->entities.back()->last_point(); +} + +ExtrusionEntityCollection* +ExtrusionEntityCollection::chained_path(bool no_reverse) const +{ + if (this->entities.empty()) { + return new ExtrusionEntityCollection (); + } + return this->chained_path_from(this->entities.front()->first_point(), no_reverse); +} + +ExtrusionEntityCollection* +ExtrusionEntityCollection::chained_path_from(Point* start_near, bool no_reverse) const +{ + if (this->no_sort) return new ExtrusionEntityCollection(*this); + ExtrusionEntityCollection* retval = new ExtrusionEntityCollection; + ExtrusionEntitiesPtr my_paths = this->entities; + + Points endpoints; + for (ExtrusionEntitiesPtr::iterator it = my_paths.begin(); it != my_paths.end(); ++it) { + endpoints.push_back(*(*it)->first_point()); + if (no_reverse) { + endpoints.push_back(*(*it)->first_point()); + } else { + endpoints.push_back(*(*it)->last_point()); + } + } + + while (!my_paths.empty()) { + // find nearest point + int start_index = start_near->nearest_point_index(endpoints); + int path_index = start_index/2; + if (start_index % 2 && !no_reverse) { + my_paths.at(path_index) = my_paths.at(path_index)->clone(); // maybe we should clone them all when building my_paths? + my_paths.at(path_index)->reverse(); + } + retval->entities.push_back(my_paths.at(path_index)); + my_paths.erase(my_paths.begin() + path_index); + endpoints.erase(endpoints.begin() + 2*path_index, endpoints.begin() + 2*path_index + 2); + start_near = retval->entities.back()->last_point(); + } + + return retval; +} + +} diff --git a/xs/src/ExtrusionEntityCollection.hpp b/xs/src/ExtrusionEntityCollection.hpp index ed693da13..a7ea8bef0 100644 --- a/xs/src/ExtrusionEntityCollection.hpp +++ b/xs/src/ExtrusionEntityCollection.hpp @@ -9,9 +9,15 @@ namespace Slic3r { class ExtrusionEntityCollection : public ExtrusionEntity { public: + ExtrusionEntityCollection* clone() const; ExtrusionEntitiesPtr entities; bool no_sort; ExtrusionEntityCollection(): no_sort(false) {}; + ExtrusionEntityCollection* chained_path(bool no_reverse) const; + ExtrusionEntityCollection* chained_path_from(Point* start_near, bool no_reverse) const; + void reverse(); + Point* first_point(); + Point* last_point(); }; } diff --git a/xs/t/12_extrusionpathcollection.t b/xs/t/12_extrusionpathcollection.t index 0d913fa5b..176eac5c6 100644 --- a/xs/t/12_extrusionpathcollection.t +++ b/xs/t/12_extrusionpathcollection.t @@ -4,7 +4,7 @@ use strict; use warnings; use Slic3r::XS; -use Test::More tests => 9; +use Test::More tests => 12; my $points = [ [100, 100], @@ -41,5 +41,32 @@ isa_ok $collection->[3], 'Slic3r::ExtrusionLoop', 'correct object returned for l is scalar(@{$collection->[1]}), 1, 'appended collection was duplicated'; +{ + my $collection = Slic3r::ExtrusionPath::Collection->new( + map Slic3r::ExtrusionPath->new(polyline => $_, role => 0), + Slic3r::Polyline->new([0,15], [0,18], [0,20]), + Slic3r::Polyline->new([0,10], [0,8], [0,5]), + ); + is_deeply + [ map $_->y, map @{$_->polyline}, @{$collection->chained_path_from(Slic3r::Point->new(0,30), 0)} ], + [20, 18, 15, 10, 8, 5], + 'chained_path_from'; + is_deeply + [ map $_->y, map @{$_->polyline}, @{$collection->chained_path(0)} ], + [15, 18, 20, 10, 8, 5], + 'chained_path'; +} + +{ + my $collection = Slic3r::ExtrusionPath::Collection->new( + map Slic3r::ExtrusionPath->new(polyline => $_, role => 0), + Slic3r::Polyline->new([15,0], [10,0], [4,0]), + Slic3r::Polyline->new([10,5], [15,5], [20,5]), + ); + is_deeply + [ map $_->x, map @{$_->polyline}, @{$collection->chained_path_from(Slic3r::Point->new(30,0), 0)} ], + [reverse 4, 10, 15, 10, 15, 20], + 'chained_path_from'; +} __END__ diff --git a/xs/xsp/ExtrusionEntityCollection.xsp b/xs/xsp/ExtrusionEntityCollection.xsp index 89c84f57f..c0e3f39b8 100644 --- a/xs/xsp/ExtrusionEntityCollection.xsp +++ b/xs/xsp/ExtrusionEntityCollection.xsp @@ -10,6 +10,10 @@ ~ExtrusionEntityCollection(); void clear() %code{% THIS->entities.clear(); %}; + ExtrusionEntityCollection* chained_path(bool no_reverse) + %code{% const char* CLASS = "Slic3r::ExtrusionPath::Collection"; RETVAL = THIS->chained_path(no_reverse); %}; + ExtrusionEntityCollection* chained_path_from(Point* start_near, bool no_reverse) + %code{% const char* CLASS = "Slic3r::ExtrusionPath::Collection"; RETVAL = THIS->chained_path_from(start_near, no_reverse); %}; %{ SV*