diff --git a/lib/Slic3r/Fill/Honeycomb.pm b/lib/Slic3r/Fill/Honeycomb.pm index 0f91f5ae2..e5786e199 100644 --- a/lib/Slic3r/Fill/Honeycomb.pm +++ b/lib/Slic3r/Fill/Honeycomb.pm @@ -96,9 +96,9 @@ sub fill_surface { # connect paths { - my $collection = Slic3r::Polyline::Collection->new(polylines => [@paths]); + my $collection = Slic3r::Polyline::Collection->new(@paths); @paths = (); - foreach my $path ($collection->chained_path) { + foreach my $path (@{$collection->chained_path(0)}) { if (@paths) { # distance between first point of this path and last point of last path my $distance = $paths[-1]->last_point->distance_to($path->first_point); diff --git a/lib/Slic3r/Fill/Rectilinear.pm b/lib/Slic3r/Fill/Rectilinear.pm index 259df5a05..e77c8688a 100644 --- a/lib/Slic3r/Fill/Rectilinear.pm +++ b/lib/Slic3r/Fill/Rectilinear.pm @@ -66,9 +66,7 @@ sub fill_surface { # connect lines unless ($params{dont_connect}) { my ($expolygon_off) = @{$expolygon->offset_ex(scale $params{flow_spacing}/2)}; - my $collection = Slic3r::Polyline::Collection->new( - polylines => [ @polylines ], - ); + my $collection = Slic3r::Polyline::Collection->new(@polylines); @polylines = (); my $tolerance = 10 * scaled_epsilon; @@ -80,7 +78,7 @@ sub fill_surface { } : sub { $_[X] <= $diagonal_distance && $_[Y] <= $diagonal_distance }; - foreach my $polyline ($collection->chained_path) { + foreach my $polyline (@{$collection->chained_path(0)}) { if (@polylines) { my $first_point = $polyline->first_point; my $last_point = $polylines[-1]->last_point; diff --git a/lib/Slic3r/Polyline.pm b/lib/Slic3r/Polyline.pm index 7633f315f..30aaff3a4 100644 --- a/lib/Slic3r/Polyline.pm +++ b/lib/Slic3r/Polyline.pm @@ -163,38 +163,4 @@ sub regular_points { return @points; } -package Slic3r::Polyline::Collection; -use Moo; - -has 'polylines' => (is => 'ro', default => sub { [] }); - -# Note that our polylines will be reversed in place when necessary. -sub chained_path { - my $self = shift; - my ($start_near, $no_reverse) = @_; - - my @my_paths = @{$self->polylines}; - - 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 - $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; -} - 1; diff --git a/t/fill.t b/t/fill.t index a4138f6bc..a3af4fa6d 100644 --- a/t/fill.t +++ b/t/fill.t @@ -110,23 +110,23 @@ sub scale_points (@) { map [scale $_->[X], scale $_->[Y]], @_ } } { - my $collection = Slic3r::Polyline::Collection->new(polylines => [ + my $collection = Slic3r::Polyline::Collection->new( Slic3r::Polyline->new([0,15], [0,18], [0,20]), Slic3r::Polyline->new([0,10], [0,8], [0,5]), - ]); + ); is_deeply - [ map $_->[Y], map @$_, $collection->chained_path(Slic3r::Point->new(0,30), 0) ], + [ map $_->[Y], map @$_, @{$collection->chained_path(Slic3r::Point->new(0,30), 0)} ], [20, 18, 15, 10, 8, 5], 'chained path'; } { - my $collection = Slic3r::Polyline::Collection->new(polylines => [ + my $collection = Slic3r::Polyline::Collection->new( Slic3r::Polyline->new([4,0], [10,0], [15,0]), Slic3r::Polyline->new([10,5], [15,5], [20,5]), - ]); + ); is_deeply - [ map $_->[X], map @$_, $collection->chained_path(Slic3r::Point->new(30,0), 0) ], + [ map $_->[X], map @$_, @{$collection->chained_path(Slic3r::Point->new(30,0), 0)} ], [reverse 4, 10, 15, 10, 15, 20], 'chained path'; } diff --git a/xs/lib/Slic3r/XS.pm b/xs/lib/Slic3r/XS.pm index aa85a765c..97f73c360 100644 --- a/xs/lib/Slic3r/XS.pm +++ b/xs/lib/Slic3r/XS.pm @@ -27,6 +27,11 @@ use overload '@{}' => sub { $_[0]->arrayref }, 'fallback' => 1; +package Slic3r::Polyline::Collection; +use overload + '@{}' => sub { $_[0]->arrayref }, + 'fallback' => 1; + package Slic3r::Polygon; use overload '@{}' => sub { $_[0]->arrayref }, diff --git a/xs/src/Polyline.cpp b/xs/src/Polyline.cpp index 70fa6c77e..166e297c0 100644 --- a/xs/src/Polyline.cpp +++ b/xs/src/Polyline.cpp @@ -12,4 +12,12 @@ Polyline::lines() return lines; } +SV* +Polyline::to_SV_ref() const +{ + SV* sv = newSV(0); + sv_setref_pv( sv, "Slic3r::Polyline", new Polyline(*this) ); + return sv; +} + } diff --git a/xs/src/Polyline.hpp b/xs/src/Polyline.hpp index 67daf794c..d6d067ca5 100644 --- a/xs/src/Polyline.hpp +++ b/xs/src/Polyline.hpp @@ -9,6 +9,7 @@ namespace Slic3r { class Polyline : public MultiPoint { public: Lines lines(); + SV* to_SV_ref() const; }; typedef std::vector Polylines; diff --git a/xs/src/PolylineCollection.cpp b/xs/src/PolylineCollection.cpp new file mode 100644 index 000000000..16fe9fc5a --- /dev/null +++ b/xs/src/PolylineCollection.cpp @@ -0,0 +1,46 @@ +#include "PolylineCollection.hpp" + +namespace Slic3r { + +PolylineCollection* +PolylineCollection::chained_path(bool no_reverse) const +{ + if (this->polylines.empty()) { + return new PolylineCollection (); + } + return this->chained_path_from(this->polylines.front().first_point(), no_reverse); +} + +PolylineCollection* +PolylineCollection::chained_path_from(const Point* start_near, bool no_reverse) const +{ + PolylineCollection* retval = new PolylineCollection; + Polylines my_paths = this->polylines; + + Points endpoints; + for (Polylines::const_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).reverse(); + } + retval->polylines.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->polylines.back().last_point(); + } + + return retval; +} + +} diff --git a/xs/src/PolylineCollection.hpp b/xs/src/PolylineCollection.hpp new file mode 100644 index 000000000..96afb0ec5 --- /dev/null +++ b/xs/src/PolylineCollection.hpp @@ -0,0 +1,19 @@ +#ifndef slic3r_PolylineCollection_hpp_ +#define slic3r_PolylineCollection_hpp_ + +#include +#include "Polyline.hpp" + +namespace Slic3r { + +class PolylineCollection +{ + public: + Polylines polylines; + PolylineCollection* chained_path(bool no_reverse) const; + PolylineCollection* chained_path_from(const Point* start_near, bool no_reverse) const; +}; + +} + +#endif diff --git a/xs/t/13_polylinecollection.t b/xs/t/13_polylinecollection.t new file mode 100644 index 000000000..9b36e7ffa --- /dev/null +++ b/xs/t/13_polylinecollection.t @@ -0,0 +1,35 @@ +#!/usr/bin/perl + +use strict; +use warnings; + +use Slic3r::XS; +use Test::More tests => 3; + +{ + my $collection = Slic3r::Polyline::Collection->new( + Slic3r::Polyline->new([0,15], [0,18], [0,20]), + Slic3r::Polyline->new([0,10], [0,8], [0,5]), + ); + is_deeply + [ map $_->y, map @$_, @{$collection->chained_path_from(Slic3r::Point->new(0,30), 0)} ], + [20, 18, 15, 10, 8, 5], + 'chained_path_from'; + is_deeply + [ map $_->y, map @$_, @{$collection->chained_path(0)} ], + [15, 18, 20, 10, 8, 5], + 'chained_path'; +} + +{ + my $collection = Slic3r::Polyline::Collection->new( + Slic3r::Polyline->new([15,0], [10,0], [4,0]), + Slic3r::Polyline->new([10,5], [15,5], [20,5]), + ); + is_deeply + [ map $_->x, map @$_, @{$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/PolylineCollection.xsp b/xs/xsp/PolylineCollection.xsp new file mode 100644 index 000000000..e26cd5041 --- /dev/null +++ b/xs/xsp/PolylineCollection.xsp @@ -0,0 +1,69 @@ +%module{Slic3r::XS}; + +%{ +#include +#include "PolylineCollection.hpp" +%} + +%name{Slic3r::Polyline::Collection} class PolylineCollection { + ~PolylineCollection(); + PolylineCollection* clone() + %code{% const char* CLASS = "Slic3r::Polyline::Collection"; RETVAL = new PolylineCollection(*THIS); %}; + void clear() + %code{% THIS->polylines.clear(); %}; + PolylineCollection* chained_path(bool no_reverse) + %code{% const char* CLASS = "Slic3r::Polyline::Collection"; RETVAL = THIS->chained_path(no_reverse); %}; + PolylineCollection* chained_path_from(Point* start_near, bool no_reverse) + %code{% const char* CLASS = "Slic3r::Polyline::Collection"; RETVAL = THIS->chained_path_from(start_near, no_reverse); %}; +%{ + +PolylineCollection* +PolylineCollection::new(...) + CODE: + RETVAL = new PolylineCollection (); + // ST(0) is class name, others are Polylines + RETVAL->polylines.resize(items-1); + for (unsigned int i = 1; i < items; i++) { + // Note: a COPY of the input is stored + RETVAL->polylines[i-1].from_SV_check(ST(i)); + } + OUTPUT: + RETVAL + +SV* +PolylineCollection::arrayref() + CODE: + AV* av = newAV(); + av_fill(av, THIS->polylines.size()-1); + int i = 0; + for (Polylines::iterator it = THIS->polylines.begin(); it != THIS->polylines.end(); ++it) { + av_store(av, i++, (*it).to_SV_ref()); + } + RETVAL = newRV_noinc((SV*)av); + OUTPUT: + RETVAL + +SV* +PolylineCollection::pp() + CODE: + AV* av = newAV(); + av_fill(av, THIS->polylines.size()-1); + int i = 0; + for (Polylines::iterator it = THIS->polylines.begin(); it != THIS->polylines.end(); ++it) { + av_store(av, i++, (*it).to_SV_pureperl()); + } + RETVAL = newRV_noinc((SV*)av); + OUTPUT: + RETVAL + +void +PolylineCollection::append(...) + CODE: + for (unsigned int i = 1; i < items; i++) { + Polyline polyline; + polyline.from_SV_check( ST(i) ); + THIS->polylines.push_back(polyline); + } + +%} +}; diff --git a/xs/xsp/my.map b/xs/xsp/my.map index 386112ac1..df282539b 100644 --- a/xs/xsp/my.map +++ b/xs/xsp/my.map @@ -3,6 +3,7 @@ TriangleMesh* O_OBJECT Point* O_OBJECT Line* O_OBJECT Polyline* O_OBJECT +PolylineCollection* O_OBJECT Polygon* O_OBJECT ExPolygon* O_OBJECT ExPolygonCollection* O_OBJECT