From d0701cdcd4b7a9677e130a3126e4575eb3b135fa Mon Sep 17 00:00:00 2001 From: Alessandro Ranellucci Date: Mon, 15 Jul 2013 16:21:09 +0200 Subject: [PATCH] Implemented Slic3r::ExtrusionLoop --- lib/Slic3r/ExtrusionLoop.pm | 50 ++++++--------------------- lib/Slic3r/GCode.pm | 12 +++---- lib/Slic3r/Polygon.pm | 4 ++- lib/Slic3r/Test/SectionCut.pm | 1 - xs/lib/Slic3r/XS.pm | 17 ++++----- xs/src/Polygon.hpp | 10 ++++++ xs/src/Polyline.hpp | 10 ++++++ xs/t/08_extrusionloop.t | 29 ++++++++++++++++ xs/xsp/ExtrusionLoop.xsp | 65 +++++++++++++++++++++++++++++++++++ xs/xsp/ExtrusionPath.xsp | 35 ++++--------------- 10 files changed, 145 insertions(+), 88 deletions(-) create mode 100644 xs/t/08_extrusionloop.t create mode 100644 xs/xsp/ExtrusionLoop.xsp diff --git a/lib/Slic3r/ExtrusionLoop.pm b/lib/Slic3r/ExtrusionLoop.pm index 02f33c603b..2f4933a8a9 100644 --- a/lib/Slic3r/ExtrusionLoop.pm +++ b/lib/Slic3r/ExtrusionLoop.pm @@ -1,38 +1,20 @@ package Slic3r::ExtrusionLoop; -use Moo; +use strict; +use warnings; use Slic3r::Geometry qw(same_point); -# the underlying Slic3r::Polygon objects holds the geometry -has 'polygon' => ( - is => 'rw', - required => 1, - handles => [qw(is_printable nearest_point_index_to reverse)], -); - -has 'flow_spacing' => (is => 'rw', required => 1); - -# see EXTR_ROLE_* constants in ExtrusionPath.pm -has 'role' => (is => 'rw', required => 1); - -use constant PACK_FMT => 'fca*'; +sub polygon { $_[0] } # class or object method sub pack { my $self = shift; - my %args = @_; if (ref $self) { - %args = map { $_ => $self->$_ } qw(flow_spacing role polygon); + return $self; + } else { + return $self->new(@_); } - - my $o = \ pack PACK_FMT, - $args{flow_spacing} || -1, - $args{role} // (die "Missing mandatory attribute 'role'"), #/ - $args{polygon}->serialize; - - bless $o, 'Slic3r::ExtrusionLoop::Packed'; - return $o; } # no-op @@ -42,9 +24,10 @@ sub split_at_index { my $self = shift; return Slic3r::ExtrusionPath->new( - polyline => $self->polygon->split_at_index(@_), + polyline => $self->as_polygon->split_at_index(@_), role => $self->role, flow_spacing => $self->flow_spacing, + height => $self->height, ); } @@ -52,9 +35,10 @@ sub split_at { my $self = shift; return Slic3r::ExtrusionPath->new( - polyline => $self->polygon->split_at(@_), + polyline => $self->as_polygon->split_at(@_), role => $self->role, flow_spacing => $self->flow_spacing, + height => $self->height, ); } @@ -68,18 +52,4 @@ sub first_point { return $self->polygon->[0]; } -package Slic3r::ExtrusionLoop::Packed; -sub unpack { - my $self = shift; - - my ($flow_spacing, $role, $polygon_s) - = unpack Slic3r::ExtrusionLoop::PACK_FMT, $$self; - - return Slic3r::ExtrusionLoop->new( - flow_spacing => ($flow_spacing == -1) ? undef : $flow_spacing, - role => $role, - polygon => Slic3r::Polygon->deserialize($polygon_s), - ); -} - 1; diff --git a/lib/Slic3r/GCode.pm b/lib/Slic3r/GCode.pm index e38bf4a118..804581792f 100644 --- a/lib/Slic3r/GCode.pm +++ b/lib/Slic3r/GCode.pm @@ -142,7 +142,7 @@ sub move_z { sub extrude { my $self = shift; - ($_[0]->isa('Slic3r::ExtrusionLoop') || $_[0]->isa('Slic3r::ExtrusionLoop::Packed')) + $_[0]->isa('Slic3r::ExtrusionLoop') ? $self->extrude_loop(@_) : $self->extrude_path(@_); } @@ -152,14 +152,14 @@ sub extrude_loop { my ($loop, $description) = @_; # extrude all loops ccw - $loop = $loop->unpack if $loop->isa('Slic3r::ExtrusionLoop::Packed'); - my $was_clockwise = $loop->polygon->make_counter_clockwise; + my $polygon = $loop->as_polygon; + my $was_clockwise = $polygon->make_counter_clockwise; # find candidate starting points # start looking for concave vertices not being overhangs my @concave = (); if ($Slic3r::Config->start_perimeters_at_concave_points) { - @concave = $loop->polygon->concave_points; + @concave = $polygon->concave_points; } my @candidates = (); if ($Slic3r::Config->start_perimeters_at_non_overhang) { @@ -171,11 +171,11 @@ 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($_, $self->_layer_overhangs), @{$loop->polygon}; + @candidates = grep !Boost::Geometry::Utils::point_covered_by_multi_polygon($_, $self->_layer_overhangs), @{$polygon}; } if (!@candidates) { # if none, all points are valid candidates - @candidates = @{$loop->polygon}; + @candidates = @{$polygon}; } } } diff --git a/lib/Slic3r/Polygon.pm b/lib/Slic3r/Polygon.pm index 1025755b58..252cd1c168 100644 --- a/lib/Slic3r/Polygon.pm +++ b/lib/Slic3r/Polygon.pm @@ -10,6 +10,8 @@ use Slic3r::Geometry qw(polygon_lines polygon_remove_parallel_continuous_edges PI X1 X2 Y1 Y2 epsilon); use Slic3r::Geometry::Clipper qw(JT_MITER); +sub arrayref { $_[0] } + sub lines { my $self = shift; return polygon_lines($self); @@ -22,7 +24,7 @@ sub wkt { sub is_counter_clockwise { my $self = shift; - return Slic3r::Geometry::Clipper::is_counter_clockwise($self); + return Slic3r::Geometry::Clipper::is_counter_clockwise($self->arrayref); } sub make_counter_clockwise { diff --git a/lib/Slic3r/Test/SectionCut.pm b/lib/Slic3r/Test/SectionCut.pm index b2403ef399..0409659260 100644 --- a/lib/Slic3r/Test/SectionCut.pm +++ b/lib/Slic3r/Test/SectionCut.pm @@ -85,7 +85,6 @@ sub _plot { my @paths = map { $_->polyline->translate(@$copy); $_ } map { $_->isa('Slic3r::ExtrusionLoop') ? $_->split_at_first_point : $_ } - map { ref($_) =~ /::Packed$/ ? $_->unpack : $_ } map { $_->isa('Slic3r::ExtrusionPath::Collection') ? @{$_->paths} : $_ } grep defined $_, $filter->($layer); diff --git a/xs/lib/Slic3r/XS.pm b/xs/lib/Slic3r/XS.pm index 498c0df705..cd115a372d 100644 --- a/xs/lib/Slic3r/XS.pm +++ b/xs/lib/Slic3r/XS.pm @@ -29,16 +29,15 @@ use overload '@{}' => sub { $_[0]->arrayref }; package Slic3r::ExtrusionLoop; +use overload + '@{}' => sub { $_[0]->arrayref }, + 'fallback' => 1; sub new { my ($class, %args) = @_; - my $polygon = ref($args{polygon}) eq 'Slic3r::Polygon::XS' - ? $args{polygon} - : Slic3r::Polygon::XS->new(@{$args{polygon}}); - return $class->_new( - $polygon, # required + $args{polygon}, # required $args{role}, # required $args{height} // -1, $args{flow_spacing} // -1, @@ -49,7 +48,7 @@ sub clone { my ($self, %args) = @_; return (ref $self)->_new( - $args{polygon} // $self->polygon->clone, + $args{polygon} // $self->as_polygon, $args{role} // $self->role, $args{height} // $self->height, $args{flow_spacing} // $self->flow_spacing, @@ -64,12 +63,8 @@ use overload sub new { my ($class, %args) = @_; - my $polyline = ref($args{polyline}) eq 'Slic3r::Polyline::XS' - ? $args{polyline} - : Slic3r::Polyline::XS->new(@{$args{polyline}}); - return $class->_new( - $polyline, # required + $args{polyline}, # required $args{role}, # required $args{height} // -1, $args{flow_spacing} // -1, diff --git a/xs/src/Polygon.hpp b/xs/src/Polygon.hpp index 264cc3b9cd..6d31796feb 100644 --- a/xs/src/Polygon.hpp +++ b/xs/src/Polygon.hpp @@ -29,6 +29,16 @@ perl2polygon(SV* poly_sv, Polygon& poly) } } +void +perl2polygon_check(SV* poly_sv, Polygon& poly) +{ + if (sv_isobject(poly_sv) && (SvTYPE(SvRV(poly_sv)) == SVt_PVMG)) { + poly = *(Polygon*)SvIV((SV*)SvRV( poly_sv )); + } else { + perl2polygon(poly_sv, poly); + } +} + SV* polygon2perl(Polygon& poly) { const unsigned int num_points = poly.points.size(); diff --git a/xs/src/Polyline.hpp b/xs/src/Polyline.hpp index 3c34d0f124..e349615807 100644 --- a/xs/src/Polyline.hpp +++ b/xs/src/Polyline.hpp @@ -68,6 +68,16 @@ perl2polyline(SV* poly_sv, Polyline& poly) } } +void +perl2polyline_check(SV* poly_sv, Polyline& poly) +{ + if (sv_isobject(poly_sv) && (SvTYPE(SvRV(poly_sv)) == SVt_PVMG)) { + poly = *(Polyline*)SvIV((SV*)SvRV( poly_sv )); + } else { + perl2polyline(poly_sv, poly); + } +} + SV* polyline2perl(Polyline& poly) { const unsigned int num_points = poly.points.size(); diff --git a/xs/t/08_extrusionloop.t b/xs/t/08_extrusionloop.t new file mode 100644 index 0000000000..f880a9f185 --- /dev/null +++ b/xs/t/08_extrusionloop.t @@ -0,0 +1,29 @@ +#!/usr/bin/perl + +use strict; +use warnings; + +use Slic3r::XS; +use Test::More tests => 4; + +my $square = [ + [100, 100], + [200, 100], + [200, 200], + [100, 200], +]; + +my $loop = Slic3r::ExtrusionLoop->new( + polygon => Slic3r::Polygon::XS->new(@$square), + role => Slic3r::ExtrusionPath::EXTR_ROLE_EXTERNAL_PERIMETER, +); +isa_ok $loop->as_polygon, 'Slic3r::Polygon::XS', 'loop polygon'; +is_deeply [ @{ $loop->as_polygon } ], [ @$square ], 'polygon points roundtrip'; + +$loop = $loop->clone; + +is $loop->role, Slic3r::ExtrusionPath::EXTR_ROLE_EXTERNAL_PERIMETER, 'role'; +$loop->role(Slic3r::ExtrusionPath::EXTR_ROLE_FILL); +is $loop->role, Slic3r::ExtrusionPath::EXTR_ROLE_FILL, 'modify role'; + +__END__ diff --git a/xs/xsp/ExtrusionLoop.xsp b/xs/xsp/ExtrusionLoop.xsp new file mode 100644 index 0000000000..a092572587 --- /dev/null +++ b/xs/xsp/ExtrusionLoop.xsp @@ -0,0 +1,65 @@ +%module{Slic3r::XS}; + +%{ +#include +#include "ExtrusionEntity.hpp" +%} + +%name{Slic3r::ExtrusionLoop} class ExtrusionLoop { + ~ExtrusionLoop(); + SV* arrayref() + %code{% RETVAL = polygon2perl(THIS->polygon); %}; + Polygon* as_polygon() + %code{% const char* CLASS = "Slic3r::Polygon::XS"; RETVAL = new Polygon(THIS->polygon); %}; + void set_polygon(SV* polygon_sv) + %code{% perl2polygon_check(polygon_sv, THIS->polygon); %}; +%{ + +ExtrusionLoop* +_new(CLASS, polygon_sv, role, height, flow_spacing) + char* CLASS; + SV* polygon_sv; + ExtrusionRole role; + double height; + double flow_spacing; + CODE: + RETVAL = new ExtrusionLoop (); + perl2polygon_check(polygon_sv, RETVAL->polygon); + RETVAL->role = role; + RETVAL->height = height; + RETVAL->flow_spacing = flow_spacing; + OUTPUT: + RETVAL + +ExtrusionRole +ExtrusionLoop::role(...) + CODE: + if (items > 1) { + THIS->role = (ExtrusionRole)SvUV(ST(1)); + } + RETVAL = THIS->role; + OUTPUT: + RETVAL + +double +ExtrusionLoop::height(...) + CODE: + if (items > 1) { + THIS->height = (double)SvNV(ST(1)); + } + RETVAL = THIS->height; + OUTPUT: + RETVAL + +double +ExtrusionLoop::flow_spacing(...) + CODE: + if (items > 1) { + THIS->flow_spacing = (double)SvNV(ST(1)); + } + RETVAL = THIS->flow_spacing; + OUTPUT: + RETVAL + +%} +}; diff --git a/xs/xsp/ExtrusionPath.xsp b/xs/xsp/ExtrusionPath.xsp index d27573d22c..9d832b56ef 100644 --- a/xs/xsp/ExtrusionPath.xsp +++ b/xs/xsp/ExtrusionPath.xsp @@ -9,6 +9,10 @@ ~ExtrusionPath(); SV* arrayref() %code{% RETVAL = polyline2perl(THIS->polyline); %}; + Polyline* as_polyline() + %code{% const char* CLASS = "Slic3r::Polyline::XS"; RETVAL = new Polyline(THIS->polyline); %}; + void set_polyline(SV* polyline_sv) + %code{% perl2polyline_check(polyline_sv, THIS->polyline); %}; void pop_back() %code{% THIS->polyline.points.pop_back(); %}; void reverse(); @@ -23,36 +27,13 @@ _new(CLASS, polyline_sv, role, height, flow_spacing) double flow_spacing; CODE: RETVAL = new ExtrusionPath (); - if (sv_isobject(polyline_sv) && (SvTYPE(SvRV(polyline_sv)) == SVt_PVMG)) { - RETVAL->polyline = *(Polyline*)SvIV((SV*)SvRV( polyline_sv )); - } else { - perl2polyline(polyline_sv, RETVAL->polyline); - } + perl2polyline_check(polyline_sv, RETVAL->polyline); RETVAL->role = role; RETVAL->height = height; RETVAL->flow_spacing = flow_spacing; OUTPUT: RETVAL -Polyline* -ExtrusionPath::as_polyline() - PREINIT: - const char* CLASS = "Slic3r::Polyline::XS"; - CODE: - RETVAL = new Polyline(THIS->polyline); - OUTPUT: - RETVAL - -void -ExtrusionPath::set_polyline(polyline_sv) - SV* polyline_sv; - CODE: - if (sv_isobject(polyline_sv) && (SvTYPE(SvRV(polyline_sv)) == SVt_PVMG)) { - THIS->polyline = *(Polyline*)SvIV((SV*)SvRV( polyline_sv )); - } else { - perl2polyline(polyline_sv, THIS->polyline); - } - ExtrusionRole ExtrusionPath::role(...) CODE: @@ -88,11 +69,7 @@ ExtrusionPath::append(...) CODE: for (unsigned int i = 1; i < items; i++) { Point p; - if (sv_isobject(ST(i)) && (SvTYPE(SvRV(ST(i))) == SVt_PVMG)) { - p = *(Point*)SvIV((SV*)SvRV( ST(i) )); - } else { - perl2point(ST(i), p); - } + perl2point_check(ST(i), p); THIS->polyline.points.push_back(p); }