From f612d4c64e727b028e5291414b8a5b4da72e87b4 Mon Sep 17 00:00:00 2001 From: Alessandro Ranellucci Date: Mon, 15 Jul 2013 12:14:22 +0200 Subject: [PATCH] Ported ExtrusionPath to XS. Failing test for Surface --- lib/Slic3r/ExPolygon.pm | 2 +- lib/Slic3r/ExtrusionPath.pm | 82 ++++------------------- lib/Slic3r/Fill.pm | 2 +- lib/Slic3r/Fill/Base.pm | 2 +- lib/Slic3r/GCode.pm | 3 +- lib/Slic3r/Geometry.pm | 5 +- lib/Slic3r/Layer/Region.pm | 4 +- lib/Slic3r/Polygon.pm | 3 + lib/Slic3r/Polyline.pm | 27 ++++++-- lib/Slic3r/Print/Object.pm | 25 ++++--- t/fill.t | 2 +- t/freeze.t | 30 --------- t/shells.t | 26 ++++++-- xs/lib/Slic3r/XS.pm | 80 +++++++++++++++++++++-- xs/src/ExtrusionEntity.hpp | 60 +++++++++++++++++ xs/src/Polyline.hpp | 8 +++ xs/t/05_surface.t | 6 +- xs/t/06_polygon.t | 22 +++++++ xs/t/07_extrusionpath.t | 37 +++++++++++ xs/xsp/ExtrusionPath.xsp | 126 ++++++++++++++++++++++++++++++++++++ xs/xsp/Polygon.xsp | 29 +++++++++ xs/xsp/Polyline.xsp | 45 +++++++++++++ xs/xsp/my.map | 8 ++- xs/xsp/typemap.xspt | 10 ++- 24 files changed, 501 insertions(+), 143 deletions(-) delete mode 100644 t/freeze.t create mode 100644 xs/src/ExtrusionEntity.hpp create mode 100644 xs/t/06_polygon.t create mode 100644 xs/t/07_extrusionpath.t create mode 100644 xs/xsp/ExtrusionPath.xsp create mode 100644 xs/xsp/Polygon.xsp create mode 100644 xs/xsp/Polyline.xsp diff --git a/lib/Slic3r/ExPolygon.pm b/lib/Slic3r/ExPolygon.pm index 8330bb7f2..1d1793a71 100644 --- a/lib/Slic3r/ExPolygon.pm +++ b/lib/Slic3r/ExPolygon.pm @@ -298,7 +298,7 @@ sub medial_axis { } package Slic3r::ExPolygon::XS; -use base 'Slic3r::ExPolygon'; +use parent 'Slic3r::ExPolygon'; package Slic3r::ExPolygon::Collection; use Slic3r::Geometry qw(X1 Y1); diff --git a/lib/Slic3r/ExtrusionPath.pm b/lib/Slic3r/ExtrusionPath.pm index 3409a5975..2234aa9e2 100644 --- a/lib/Slic3r/ExtrusionPath.pm +++ b/lib/Slic3r/ExtrusionPath.pm @@ -1,8 +1,10 @@ package Slic3r::ExtrusionPath; -use Moo; +use strict; +use warnings; + +use parent -norequire, qw(Slic3r::Polyline::XS); +use parent qw(Exporter); -require Exporter; -our @ISA = qw(Exporter); our @EXPORT_OK = qw(EXTR_ROLE_PERIMETER EXTR_ROLE_EXTERNAL_PERIMETER EXTR_ROLE_CONTOUR_INTERNAL_PERIMETER EXTR_ROLE_OVERHANG_PERIMETER EXTR_ROLE_FILL EXTR_ROLE_SOLIDFILL EXTR_ROLE_TOPSOLIDFILL EXTR_ROLE_BRIDGE @@ -10,67 +12,22 @@ our @EXPORT_OK = qw(EXTR_ROLE_PERIMETER EXTR_ROLE_EXTERNAL_PERIMETER our %EXPORT_TAGS = (roles => \@EXPORT_OK); use Slic3r::Geometry qw(PI X Y epsilon deg2rad rotate_points); - -# the underlying Slic3r::Polyline objects holds the geometry -has 'polyline' => ( - is => 'rw', - required => 1, - handles => [qw(merge_continuous_lines lines length reverse clip_end)], -); - -# height is the vertical thickness of the extrusion expressed in mm -has 'height' => (is => 'rw'); -has 'flow_spacing' => (is => 'rw', required => 1); -has 'role' => (is => 'rw', required => 1); - -use constant EXTR_ROLE_PERIMETER => 0; -use constant EXTR_ROLE_EXTERNAL_PERIMETER => 1; -use constant EXTR_ROLE_OVERHANG_PERIMETER => 2; -use constant EXTR_ROLE_CONTOUR_INTERNAL_PERIMETER => 3; -use constant EXTR_ROLE_FILL => 4; -use constant EXTR_ROLE_SOLIDFILL => 5; -use constant EXTR_ROLE_TOPSOLIDFILL => 6; -use constant EXTR_ROLE_BRIDGE => 7; -use constant EXTR_ROLE_INTERNALBRIDGE => 8; -use constant EXTR_ROLE_SKIRT => 9; -use constant EXTR_ROLE_SUPPORTMATERIAL => 10; -use constant EXTR_ROLE_GAPFILL => 11; - -use constant PACK_FMT => 'ffca*'; +sub polyline { $_[0] } # class or object method sub pack { my $self = shift; - my %args = @_; if (ref $self) { - %args = map { $_ => $self->$_ } qw(height flow_spacing role polyline); + return $self; + } else { + return $self->new(@_); } - - my $o = \ pack PACK_FMT, - $args{height} // -1, - $args{flow_spacing} || -1, - $args{role} // (die "Missing mandatory attribute 'role'"), #/ - $args{polyline}->serialize; - - bless $o, 'Slic3r::ExtrusionPath::Packed'; - return $o; } # no-op, this allows to use both packed and non-packed objects in Collections sub unpack { $_[0] } -sub clone { - my $self = shift; - my %p = @_; - - $p{polyline} ||= $self->polyline->clone; - return (ref $self)->new( - (map { $_ => $self->$_ } qw(polyline height flow_spacing role)), - %p, - ); -} - sub clip_with_polygon { my $self = shift; my ($polygon) = @_; @@ -91,7 +48,7 @@ sub intersect_expolygons { my ($expolygons) = @_; return map $self->clone(polyline => Slic3r::Polyline->new(@$_)), - @{Boost::Geometry::Utils::multi_polygon_multi_linestring_intersection($expolygons, [$self->polyline])}; + @{Boost::Geometry::Utils::multi_polygon_multi_linestring_intersection($expolygons, [$self->arrayref])}; } sub subtract_expolygons { @@ -99,12 +56,12 @@ sub subtract_expolygons { my ($expolygons) = @_; return map $self->clone(polyline => Slic3r::Polyline->new(@$_)), - @{Boost::Geometry::Utils::multi_linestring_multi_polygon_difference([$self->polyline], $expolygons)}; + @{Boost::Geometry::Utils::multi_linestring_multi_polygon_difference([$self->arrayref], $expolygons)}; } sub simplify { my $self = shift; - $self->polyline($self->polyline->simplify(@_)); + $self->set_polyline($self->as_polyline->simplify(@_)); } sub points { @@ -285,19 +242,4 @@ sub detect_arcs { return @paths; } -package Slic3r::ExtrusionPath::Packed; -sub unpack { - my $self = shift; - - my ($height, $flow_spacing, $role, $polyline_s) - = unpack Slic3r::ExtrusionPath::PACK_FMT, $$self; - - return Slic3r::ExtrusionPath->new( - height => ($height == -1) ? undef : $height, - flow_spacing => ($flow_spacing == -1) ? undef : $flow_spacing, - role => $role, - polyline => Slic3r::Polyline->deserialize($polyline_s), - ); -} - 1; diff --git a/lib/Slic3r/Fill.pm b/lib/Slic3r/Fill.pm index d88def835..1efe8163d 100644 --- a/lib/Slic3r/Fill.pm +++ b/lib/Slic3r/Fill.pm @@ -185,7 +185,7 @@ sub make_fill { : $is_bridge ? EXTR_ROLE_BRIDGE : $is_solid - ? ($surface->surface_type == S_TYPE_TOP ? EXTR_ROLE_TOPSOLIDFILL : EXTR_ROLE_SOLIDFILL) + ? (($surface->surface_type == S_TYPE_TOP) ? EXTR_ROLE_TOPSOLIDFILL : EXTR_ROLE_SOLIDFILL) : EXTR_ROLE_FILL), height => $surface->thickness, flow_spacing => $params->{flow_spacing} || (warn "Warning: no flow_spacing was returned by the infill engine, please report this to the developer\n"), diff --git a/lib/Slic3r/Fill/Base.pm b/lib/Slic3r/Fill/Base.pm index f1e530ecb..d0c9d4f30 100644 --- a/lib/Slic3r/Fill/Base.pm +++ b/lib/Slic3r/Fill/Base.pm @@ -27,7 +27,7 @@ sub infill_direction { } # use bridge angle - if (defined $surface->bridge_angle) { + if ($surface->bridge_angle != -1) { Slic3r::debugf "Filling bridge with angle %d\n", $surface->bridge_angle; $rotate[0] = Slic3r::Geometry::deg2rad($surface->bridge_angle); } diff --git a/lib/Slic3r/GCode.pm b/lib/Slic3r/GCode.pm index 1807f84ee..a657dc011 100644 --- a/lib/Slic3r/GCode.pm +++ b/lib/Slic3r/GCode.pm @@ -256,7 +256,6 @@ sub extrude_path { my $self = shift; my ($path, $description, %params) = @_; - $path = $path->unpack if $path->isa('Slic3r::ExtrusionPath::Packed'); $path->simplify(&Slic3r::SCALED_RESOLUTION); # detect arcs @@ -293,7 +292,7 @@ sub extrude_path { $area = ($s**2) * PI/4; } else { my $s = $path->flow_spacing; - my $h = $path->height // $self->layer->height; + my $h = (defined $path->height && $path->height != -1) ? $path->height : $self->layer->height; $area = $self->extruder->mm3_per_mm($s, $h); } diff --git a/lib/Slic3r/Geometry.pm b/lib/Slic3r/Geometry.pm index 337b0b564..b082dc7b5 100644 --- a/lib/Slic3r/Geometry.pm +++ b/lib/Slic3r/Geometry.pm @@ -228,8 +228,9 @@ sub point_is_on_left_of_segment { } sub polyline_lines { - my ($polygon) = @_; - return map Slic3r::Line->new($polygon->[$_], $polygon->[$_+1]), 0 .. $#$polygon-1; + my ($polyline) = @_; + my @points = @$polyline; + return map Slic3r::Line->new(@points[$_, $_+1]), 0 .. $#points-1; } sub polygon_lines { diff --git a/lib/Slic3r/Layer/Region.pm b/lib/Slic3r/Layer/Region.pm index 5771316c4..602475533 100644 --- a/lib/Slic3r/Layer/Region.pm +++ b/lib/Slic3r/Layer/Region.pm @@ -352,7 +352,7 @@ sub _fill_gaps { foreach my $expolygon (@infill) { my @paths = $filler->fill_surface( - Slic3r::Surface->new(expolygon => $expolygon), + Slic3r::Surface->new(expolygon => $expolygon, surface_type => S_TYPE_INTERNALSOLID), density => 1, flow_spacing => $flow->spacing, ); @@ -573,7 +573,7 @@ sub _detect_bridges { Slic3r::debugf " Optimal infill angle of bridge on layer %d is %d degrees\n", $self->id, $bridge_angle if defined $bridge_angle; - $surface->bridge_angle($bridge_angle); + $surface->bridge_angle($bridge_angle // -1); } } diff --git a/lib/Slic3r/Polygon.pm b/lib/Slic3r/Polygon.pm index f743ac543..1025755b5 100644 --- a/lib/Slic3r/Polygon.pm +++ b/lib/Slic3r/Polygon.pm @@ -163,4 +163,7 @@ sub concave_points { -1 .. ($#$self-1); } +package Slic3r::Polygon::XS; +use parent -norequire, qw(Slic3r::Polygon Slic3r::Polyline::XS); + 1; \ No newline at end of file diff --git a/lib/Slic3r/Polyline.pm b/lib/Slic3r/Polyline.pm index b979abad0..39a936372 100644 --- a/lib/Slic3r/Polyline.pm +++ b/lib/Slic3r/Polyline.pm @@ -22,6 +22,9 @@ sub clone { Storable::dclone($_[0]) } +# compability with ::XS +sub arrayref { $_[0] } + sub serialize { my $self = shift; return pack 'l*', map @$_, @$self; @@ -59,7 +62,7 @@ sub simplify { my $self = shift; my $tolerance = shift || 10; - my $simplified = Boost::Geometry::Utils::linestring_simplify($self, $tolerance); + my $simplified = Boost::Geometry::Utils::linestring_simplify($self->arrayref, $tolerance); return (ref $self)->new(@$simplified); } @@ -70,7 +73,7 @@ sub reverse { sub length { my $self = shift; - return Boost::Geometry::Utils::linestring_length($self); + return Boost::Geometry::Utils::linestring_length($self->arrayref); } sub grow { @@ -161,14 +164,25 @@ sub scale { return $self; } +sub pop_back { + my $self = shift; + return pop @$self; +} + +sub append { + my $self = shift; + push @$self, @_; +} + # removes the given distance from the end of the polyline sub clip_end { my $self = shift; my ($distance) = @_; while ($distance > 0) { - my $last_point = pop @$self; - last if !@$self; + my $last_point = $self->[-1]; + $self->pop_back; + last if @$self == 0; my $last_segment_length = $last_point->distance_to($self->[-1]); if ($last_segment_length <= $distance) { @@ -177,7 +191,7 @@ sub clip_end { } my $new_point = Slic3r::Geometry::point_along_segment($last_point, $self->[-1], $distance); - push @$self, Slic3r::Point->new($new_point); + $self->append(Slic3r::Point->new($new_point)); $distance = 0; } } @@ -244,4 +258,7 @@ sub chained_path { return map $items_map{"$_"}, @paths; } +package Slic3r::Polyline::XS; +use parent qw(Slic3r::Polyline); + 1; diff --git a/lib/Slic3r/Print/Object.pm b/lib/Slic3r/Print/Object.pm index 240c4d3dc..8e56673cd 100644 --- a/lib/Slic3r/Print/Object.pm +++ b/lib/Slic3r/Print/Object.pm @@ -589,14 +589,14 @@ sub discover_horizontal_shells { # and the latter contains the enlarged external surfaces my $solid = [ map $_->expolygon, grep $_->surface_type == $type, @{$layerm->slices}, @{$layerm->fill_surfaces} ]; next if !@$solid; - Slic3r::debugf "Layer %d has %s surfaces\n", $i, ($type == S_TYPE_TOP ? 'top' : 'bottom'); + Slic3r::debugf "Layer %d has %s surfaces\n", $i, ($type == S_TYPE_TOP) ? 'top' : 'bottom'; my $solid_layers = ($type == S_TYPE_TOP) ? $Slic3r::Config->top_solid_layers : $Slic3r::Config->bottom_solid_layers; - for (my $n = $type == S_TYPE_TOP ? $i-1 : $i+1; + for (my $n = ($type == S_TYPE_TOP) ? $i-1 : $i+1; abs($n - $i) <= $solid_layers-1; - $type == S_TYPE_TOP ? $n-- : $n++) { + ($type == S_TYPE_TOP) ? $n-- : $n++) { next if $n < 0 || $n >= $self->layer_count; Slic3r::debugf " looking for neighbors on layer %d...\n", $n; @@ -607,7 +607,7 @@ sub discover_horizontal_shells { # intersections have contours and holes my $new_internal_solid = intersection_ex( [ map @$_, @$solid ], - [ map $_->p, grep { $_->surface_type == S_TYPE_INTERNAL || $_->surface_type == S_TYPE_INTERNALSOLID } @neighbor_fill_surfaces ], + [ map $_->p, grep { ($_->surface_type == S_TYPE_INTERNAL) || ($_->surface_type == S_TYPE_INTERNALSOLID) } @neighbor_fill_surfaces ], undef, 1, ); next if !@$new_internal_solid; @@ -658,25 +658,22 @@ sub discover_horizontal_shells { # assign resulting internal surfaces to layer my $neighbor_fill_surfaces = $self->layers->[$n]->regions->[$region_id]->fill_surfaces; - @$neighbor_fill_surfaces = (); - push @$neighbor_fill_surfaces, Slic3r::Surface->new - (expolygon => $_, surface_type => S_TYPE_INTERNAL) - for @$internal; + $neighbor_fill_surfaces->clear; + $neighbor_fill_surfaces->append(map Slic3r::Surface->new + (expolygon => $_, surface_type => S_TYPE_INTERNAL), @$internal); # assign new internal-solid surfaces to layer - push @$neighbor_fill_surfaces, Slic3r::Surface->new - (expolygon => $_, surface_type => S_TYPE_INTERNALSOLID) - for @$internal_solid; + $neighbor_fill_surfaces->append(map Slic3r::Surface->new + (expolygon => $_, surface_type => S_TYPE_INTERNALSOLID), @$internal_solid); # assign top and bottom surfaces to layer - foreach my $s (Slic3r::Surface->group(grep { $_->surface_type == S_TYPE_TOP || $_->surface_type == S_TYPE_BOTTOM } @neighbor_fill_surfaces)) { + foreach my $s (Slic3r::Surface->group(grep { ($_->surface_type == S_TYPE_TOP) || ($_->surface_type == S_TYPE_BOTTOM) } @neighbor_fill_surfaces)) { my $solid_surfaces = diff_ex( [ map $_->p, @$s ], [ map @$_, @$internal_solid, @$internal ], 1, ); - push @$neighbor_fill_surfaces, $s->[0]->clone(expolygon => $_) - for @$solid_surfaces; + $neighbor_fill_surfaces->append(map $s->[0]->clone(expolygon => $_), @$solid_surfaces); } } } diff --git a/t/fill.t b/t/fill.t index 28c2509bd..58c539ba9 100644 --- a/t/fill.t +++ b/t/fill.t @@ -33,7 +33,7 @@ sub scale_points (@) { map [scale $_->[X], scale $_->[Y]], @_ } } { - my $expolygon = Slic3r::ExPolygon->new([ scale_points [0,0], [50,0], [50,50], [0,50] ]); + my $expolygon = Slic3r::ExPolygon::XS->new([ scale_points [0,0], [50,0], [50,50], [0,50] ]); my $filler = Slic3r::Fill::Rectilinear->new( bounding_box => $expolygon->bounding_box, ); diff --git a/t/freeze.t b/t/freeze.t deleted file mode 100644 index 07fd020d2..000000000 --- a/t/freeze.t +++ /dev/null @@ -1,30 +0,0 @@ -use Test::More tests => 1; -use strict; -use warnings; - -BEGIN { - use FindBin; - use lib "$FindBin::Bin/../lib"; -} - -use Slic3r; -use Slic3r::Test; -use Storable qw(nstore retrieve); -use Time::HiRes qw(gettimeofday tv_interval); - -{ - my $t0 = [gettimeofday]; - my $print = Slic3r::Test::init_print('20mm_cube', scale => 2); - my $gcode = Slic3r::Test::gcode($print); - ###diag sprintf 'Slicing took %s seconds', tv_interval($t0); - - my $t1 = [gettimeofday]; - nstore $print, 'print.dat'; - $print = retrieve 'print.dat'; - unlink 'print.dat'; - ###diag sprintf 'Freezing and retrieving took %s seconds', tv_interval($t1); - - isa_ok $print, 'Slic3r::Print', 'restored Print object'; -} - -__END__ diff --git a/t/shells.t b/t/shells.t index 56a3ca595..7abca9b13 100644 --- a/t/shells.t +++ b/t/shells.t @@ -1,4 +1,4 @@ -use Test::More tests => 3; +use Test::More tests => 4; use strict; use warnings; @@ -15,6 +15,10 @@ use Slic3r::Test; my $config = Slic3r::Config->new_from_defaults; $config->set('skirts', 0); $config->set('perimeters', 0); + $config->set('solid_infill_speed', 99); + $config->set('top_solid_infill_speed', 99); + $config->set('first_layer_speed', '100%'); + $config->set('cooling', 0); my $test = sub { my ($conf) = @_; @@ -28,20 +32,31 @@ use Slic3r::Test; if ($self->Z > 0) { $layers_with_shells{$self->Z} //= 0; - $layers_with_shells{$self->Z} = 1 if $info->{extruding} && $info->{dist_XY} > 0; + $layers_with_shells{$self->Z} = 1 + if $info->{extruding} + && $info->{dist_XY} > 0 + && ($args->{F} // $self->F) == $config->solid_infill_speed*60; } }); my @shells = @layers_with_shells{sort { $a <=> $b } keys %layers_with_shells}; - fail "wrong number of bottom solid layers" + fail "insufficient number of bottom solid layers" unless !defined(first { !$_ } @shells[0..$config->bottom_solid_layers-1]); - fail "wrong number of top solid layers" + fail "excessive number of bottom solid layers" + unless scalar(grep $_, @shells[0 .. $#shells/2]) != $config->bottom_solid_layers; + fail "insufficient number of top solid layers" unless !defined(first { !$_ } @shells[-$config->top_solid_layers..-1]); + fail "excessive number of top solid layers" + unless scalar(grep $_, @shells[($#shells/2)..$#shells]) != $config->top_solid_layers; 1; }; ok $test->(), "proper number of shells is applied"; - $config->set('fill_density', 0); + $config->set('top_solid_layers', 0); + $config->set('bottom_solid_layers', 0); + ok $test->(), "no shells are applied when both top and bottom are set to zero"; + + $config->set('fill_density', 0); ok $test->(), "proper number of shells is applied even when fill density is none"; } @@ -55,6 +70,7 @@ use Slic3r::Test; $config->set('cooling', 0); $config->set('solid_infill_speed', 99); $config->set('top_solid_infill_speed', 99); + $config->set('first_layer_speed', '100%'); my $print = Slic3r::Test::init_print('V', config => $config); my %layers_with_solid_infill = (); # Z => 1 diff --git a/xs/lib/Slic3r/XS.pm b/xs/lib/Slic3r/XS.pm index 1d1ef3eae..498c0df70 100644 --- a/xs/lib/Slic3r/XS.pm +++ b/xs/lib/Slic3r/XS.pm @@ -15,10 +15,78 @@ package Slic3r::ExPolygon::XS; use overload '@{}' => sub { $_[0]->arrayref }; +package Slic3r::Polyline::XS; +use overload + '@{}' => sub { $_[0]->arrayref }, + 'fallback' => 1; + +package Slic3r::Polygon::XS; +use overload + '@{}' => sub { $_[0]->arrayref }; + package Slic3r::ExPolygon::Collection; use overload '@{}' => sub { $_[0]->arrayref }; +package Slic3r::ExtrusionLoop; + +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{role}, # required + $args{height} // -1, + $args{flow_spacing} // -1, + ); +} + +sub clone { + my ($self, %args) = @_; + + return (ref $self)->_new( + $args{polygon} // $self->polygon->clone, + $args{role} // $self->role, + $args{height} // $self->height, + $args{flow_spacing} // $self->flow_spacing, + ); +} + +package Slic3r::ExtrusionPath; +use overload + '@{}' => sub { $_[0]->arrayref }, + 'fallback' => 1; + +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{role}, # required + $args{height} // -1, + $args{flow_spacing} // -1, + ); +} + +sub clone { + my ($self, %args) = @_; + + return (ref $self)->_new( + $args{polyline} // $self->as_polyline, + $args{role} // $self->role, + $args{height} // $self->height, + $args{flow_spacing} // $self->flow_spacing, + ); +} + package Slic3r::Surface; sub new { @@ -29,12 +97,12 @@ sub new { if defined $args{bridge_angle} && $args{bridge_angle} < 0; return $class->_new( - delete $args{expolygon}, # required - delete $args{surface_type}, # required - delete $args{thickness} // -1, - delete $args{thickness_layers} // 1, - delete $args{bridge_angle} // -1, - delete $args{extra_perimeters} // 0, + $args{expolygon} // (die "Missing required expolygon\n"), + $args{surface_type} // (die "Missing required surface_type\n"), + $args{thickness} // -1, + $args{thickness_layers} // 1, + $args{bridge_angle} // -1, + $args{extra_perimeters} // 0, ); } diff --git a/xs/src/ExtrusionEntity.hpp b/xs/src/ExtrusionEntity.hpp new file mode 100644 index 000000000..257bd3ff2 --- /dev/null +++ b/xs/src/ExtrusionEntity.hpp @@ -0,0 +1,60 @@ +#ifndef slic3r_ExtrusionEntity_hpp_ +#define slic3r_ExtrusionEntity_hpp_ + +extern "C" { +#include "EXTERN.h" +#include "perl.h" +#include "XSUB.h" +#include "ppport.h" +} + +#include "Polygon.hpp" +#include "Polyline.hpp" + +namespace Slic3r { + +enum ExtrusionRole { + erPerimeter, + erExternalPerimeter, + erOverhangPerimeter, + erContourInternalPerimeter, + erFill, + erSolidFill, + erTopSolidFill, + erBrige, + erInternalBridge, + erSkirt, + erSupportMaterial, + erGapFill, +}; + +class ExtrusionEntity +{ + public: + ExtrusionRole role; + double height; // vertical thickness of the extrusion expressed in mm + double flow_spacing; +}; + +class ExtrusionPath : public ExtrusionEntity +{ + public: + Polyline polyline; + void reverse(); +}; + +class ExtrusionLoop : public ExtrusionEntity +{ + public: + Polygon polygon; +}; + +void +ExtrusionPath::reverse() +{ + this->polyline.reverse(); +} + +} + +#endif diff --git a/xs/src/Polyline.hpp b/xs/src/Polyline.hpp index 65285126d..0941314c1 100644 --- a/xs/src/Polyline.hpp +++ b/xs/src/Polyline.hpp @@ -9,6 +9,7 @@ extern "C" { } #include "Point.hpp" +#include namespace Slic3r { @@ -19,6 +20,7 @@ class Polyline void scale(double factor); void translate(double x, double y); void rotate(double angle, Point* center); + void reverse(); }; typedef std::vector Polylines; @@ -49,6 +51,12 @@ Polyline::rotate(double angle, Point* center) } } +void +Polyline::reverse() +{ + std::reverse(this->points.begin(), this->points.end()); +} + void perl2polyline(SV* poly_sv, Polyline& poly) { diff --git a/xs/t/05_surface.t b/xs/t/05_surface.t index a881c8198..94b308a83 100644 --- a/xs/t/05_surface.t +++ b/xs/t/05_surface.t @@ -4,7 +4,7 @@ use strict; use warnings; use Slic3r::XS; -use Test::More tests => 10; +use Test::More tests => 11; my $square = [ # ccw [100, 100], @@ -49,6 +49,10 @@ is $surface->extra_perimeters, 2, 'extra_perimeters'; is scalar(@$collection), 0, 'clear collection'; $collection->append($surface); is scalar(@$collection), 1, 'append to collection'; + + my $item = $collection->[0]; + $item->surface_type(Slic3r::Surface::S_TYPE_INTERNAL); + is $item->surface_type, $collection->[0]->surface_type, 'changing item affects actual item'; } __END__ diff --git a/xs/t/06_polygon.t b/xs/t/06_polygon.t new file mode 100644 index 000000000..cca7032b8 --- /dev/null +++ b/xs/t/06_polygon.t @@ -0,0 +1,22 @@ +#!/usr/bin/perl + +use strict; +use warnings; + +use Slic3r::XS; +use Test::More tests => 3; + +my $square = [ # ccw + [100, 100], + [200, 100], + [200, 200], + [100, 200], +]; + +my $polygon = Slic3r::Polygon::XS->new(@$square); +is_deeply [ @$polygon ], [ @$square ], 'polygon roundtrip'; + +isa_ok $polygon->arrayref, 'Slic3r::Polygon', 'Perl polygon is blessed'; +isa_ok $polygon->[0], 'Slic3r::Point', 'Perl points are blessed'; + +__END__ diff --git a/xs/t/07_extrusionpath.t b/xs/t/07_extrusionpath.t new file mode 100644 index 000000000..5a8d4c5c1 --- /dev/null +++ b/xs/t/07_extrusionpath.t @@ -0,0 +1,37 @@ +#!/usr/bin/perl + +use strict; +use warnings; + +use Slic3r::XS; +use Test::More tests => 7; + +my $points = [ + [100, 100], + [200, 100], + [200, 200], +]; + +my $path = Slic3r::ExtrusionPath->new( + polyline => Slic3r::Polyline::XS->new(@$points), + role => Slic3r::ExtrusionPath::EXTR_ROLE_EXTERNAL_PERIMETER, +); +isa_ok $path->as_polyline, 'Slic3r::Polyline::XS', 'path polyline'; +is_deeply [ @{ $path->as_polyline } ], [ @$points ], 'path points roundtrip'; + +$path->reverse; +is_deeply [ @{ $path->as_polyline } ], [ reverse @$points ], 'reverse path'; + +$path->append([ 150, 150 ]); +is scalar(@{ $path }), 4, 'append to path'; + +$path->pop_back; +is scalar(@{ $path }), 3, 'pop_back from path'; + +$path = $path->clone; + +is $path->role, Slic3r::ExtrusionPath::EXTR_ROLE_EXTERNAL_PERIMETER, 'role'; +$path->role(Slic3r::ExtrusionPath::EXTR_ROLE_FILL); +is $path->role, Slic3r::ExtrusionPath::EXTR_ROLE_FILL, 'modify role'; + +__END__ diff --git a/xs/xsp/ExtrusionPath.xsp b/xs/xsp/ExtrusionPath.xsp new file mode 100644 index 000000000..d27573d22 --- /dev/null +++ b/xs/xsp/ExtrusionPath.xsp @@ -0,0 +1,126 @@ +%module{Slic3r::XS}; + +%{ +#include +#include "ExtrusionEntity.hpp" +%} + +%name{Slic3r::ExtrusionPath} class ExtrusionPath { + ~ExtrusionPath(); + SV* arrayref() + %code{% RETVAL = polyline2perl(THIS->polyline); %}; + void pop_back() + %code{% THIS->polyline.points.pop_back(); %}; + void reverse(); +%{ + +ExtrusionPath* +_new(CLASS, polyline_sv, role, height, flow_spacing) + char* CLASS; + SV* polyline_sv; + ExtrusionRole role; + double height; + 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); + } + 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: + if (items > 1) { + THIS->role = (ExtrusionRole)SvUV(ST(1)); + } + RETVAL = THIS->role; + OUTPUT: + RETVAL + +double +ExtrusionPath::height(...) + CODE: + if (items > 1) { + THIS->height = (double)SvNV(ST(1)); + } + RETVAL = THIS->height; + OUTPUT: + RETVAL + +double +ExtrusionPath::flow_spacing(...) + CODE: + if (items > 1) { + THIS->flow_spacing = (double)SvNV(ST(1)); + } + RETVAL = THIS->flow_spacing; + OUTPUT: + RETVAL + +void +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); + } + THIS->polyline.points.push_back(p); + } + +%} +}; + +%package{Slic3r::ExtrusionPath}; +%{ + +IV +_constant() + ALIAS: + EXTR_ROLE_PERIMETER = erPerimeter + EXTR_ROLE_EXTERNAL_PERIMETER = erExternalPerimeter + EXTR_ROLE_OVERHANG_PERIMETER = erOverhangPerimeter + EXTR_ROLE_CONTOUR_INTERNAL_PERIMETER = erContourInternalPerimeter + EXTR_ROLE_FILL = erFill + EXTR_ROLE_SOLIDFILL = erSolidFill + EXTR_ROLE_TOPSOLIDFILL = erTopSolidFill + EXTR_ROLE_BRIDGE = erBrige + EXTR_ROLE_INTERNALBRIDGE = erInternalBridge + EXTR_ROLE_SKIRT = erSkirt + EXTR_ROLE_SUPPORTMATERIAL = erSupportMaterial + EXTR_ROLE_GAPFILL = erGapFill + PROTOTYPE: + CODE: + RETVAL = ix; + OUTPUT: RETVAL + +%} + diff --git a/xs/xsp/Polygon.xsp b/xs/xsp/Polygon.xsp new file mode 100644 index 000000000..daffd819c --- /dev/null +++ b/xs/xsp/Polygon.xsp @@ -0,0 +1,29 @@ +%module{Slic3r::XS}; + +%{ +#include +#include "Polygon.hpp" +%} + +%name{Slic3r::Polygon::XS} class Polygon { + ~Polygon(); + Polygon* clone() + %code{% const char* CLASS = "Slic3r::Polygon::XS"; RETVAL = new Polygon(*THIS); %}; + SV* arrayref() + %code{% RETVAL = polygon2perl(*THIS); %}; +%{ + +Polygon* +Polygon::new(...) + CODE: + RETVAL = new Polygon (); + // ST(0) is class name, ST(1) is first point + RETVAL->points.resize(items-1); + for (unsigned int i = 1; i < items; i++) { + perl2point(ST(i), RETVAL->points[i-1]); + } + OUTPUT: + RETVAL + +%} +}; diff --git a/xs/xsp/Polyline.xsp b/xs/xsp/Polyline.xsp new file mode 100644 index 000000000..925b799dc --- /dev/null +++ b/xs/xsp/Polyline.xsp @@ -0,0 +1,45 @@ +%module{Slic3r::XS}; + +%{ +#include +#include "Polyline.hpp" +%} + +%name{Slic3r::Polyline::XS} class Polyline { + ~Polyline(); + Polyline* clone() + %code{% const char* CLASS = "Slic3r::Polyline::XS"; RETVAL = new Polyline(*THIS); %}; + SV* arrayref() + %code{% RETVAL = polyline2perl(*THIS); %}; + void pop_back() + %code{% THIS->points.pop_back(); %}; + void reverse(); +%{ + +Polyline* +Polyline::new(...) + CODE: + RETVAL = new Polyline (); + // ST(0) is class name, ST(1) is first point + RETVAL->points.resize(items-1); + for (unsigned int i = 1; i < items; i++) { + perl2point(ST(i), RETVAL->points[i-1]); + } + OUTPUT: + RETVAL + +void +Polyline::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); + } + THIS->points.push_back(p); + } + +%} +}; diff --git a/xs/xsp/my.map b/xs/xsp/my.map index c5476e220..7e565f533 100644 --- a/xs/xsp/my.map +++ b/xs/xsp/my.map @@ -1,8 +1,14 @@ ZTable* O_OBJECT TriangleMesh* O_OBJECT Point* O_OBJECT +Polyline* O_OBJECT +Polygon* O_OBJECT ExPolygon* O_OBJECT ExPolygonCollection* O_OBJECT -SurfaceType T_UV +ExtrusionPath* O_OBJECT +ExtrusionLoop* O_OBJECT Surface* O_OBJECT SurfaceCollection* O_OBJECT + +ExtrusionRole T_UV +SurfaceType T_UV diff --git a/xs/xsp/typemap.xspt b/xs/xsp/typemap.xspt index fc6f43631..62c73e92b 100644 --- a/xs/xsp/typemap.xspt +++ b/xs/xsp/typemap.xspt @@ -4,9 +4,17 @@ %typemap{AV*}; %typemap{Point*}; %typemap{ExPolygon*}; +%typemap{Polyline*}; +%typemap{Polygon*}; %typemap{SurfaceType}{parsed}{ %cpp_type{SurfaceType}; %precall_code{% $CVar = (SurfaceType)SvUV($PerlVar); %}; -}; \ No newline at end of file +}; +%typemap{ExtrusionRole}{parsed}{ + %cpp_type{ExtrusionRole}; + %precall_code{% + $CVar = (ExtrusionRole)SvUV($PerlVar); + %}; +};