Ported ExtrusionPath to XS. Failing test for Surface

This commit is contained in:
Alessandro Ranellucci 2013-07-15 12:14:22 +02:00
parent 8c1e1cc3ea
commit f612d4c64e
24 changed files with 501 additions and 143 deletions

View File

@ -298,7 +298,7 @@ sub medial_axis {
} }
package Slic3r::ExPolygon::XS; package Slic3r::ExPolygon::XS;
use base 'Slic3r::ExPolygon'; use parent 'Slic3r::ExPolygon';
package Slic3r::ExPolygon::Collection; package Slic3r::ExPolygon::Collection;
use Slic3r::Geometry qw(X1 Y1); use Slic3r::Geometry qw(X1 Y1);

View File

@ -1,8 +1,10 @@
package Slic3r::ExtrusionPath; 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 our @EXPORT_OK = qw(EXTR_ROLE_PERIMETER EXTR_ROLE_EXTERNAL_PERIMETER
EXTR_ROLE_CONTOUR_INTERNAL_PERIMETER EXTR_ROLE_OVERHANG_PERIMETER EXTR_ROLE_CONTOUR_INTERNAL_PERIMETER EXTR_ROLE_OVERHANG_PERIMETER
EXTR_ROLE_FILL EXTR_ROLE_SOLIDFILL EXTR_ROLE_TOPSOLIDFILL EXTR_ROLE_BRIDGE 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); our %EXPORT_TAGS = (roles => \@EXPORT_OK);
use Slic3r::Geometry qw(PI X Y epsilon deg2rad rotate_points); use Slic3r::Geometry qw(PI X Y epsilon deg2rad rotate_points);
sub polyline { $_[0] }
# 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*';
# class or object method # class or object method
sub pack { sub pack {
my $self = shift; my $self = shift;
my %args = @_;
if (ref $self) { 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 # no-op, this allows to use both packed and non-packed objects in Collections
sub unpack { $_[0] } 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 { sub clip_with_polygon {
my $self = shift; my $self = shift;
my ($polygon) = @_; my ($polygon) = @_;
@ -91,7 +48,7 @@ sub intersect_expolygons {
my ($expolygons) = @_; my ($expolygons) = @_;
return map $self->clone(polyline => Slic3r::Polyline->new(@$_)), 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 { sub subtract_expolygons {
@ -99,12 +56,12 @@ sub subtract_expolygons {
my ($expolygons) = @_; my ($expolygons) = @_;
return map $self->clone(polyline => Slic3r::Polyline->new(@$_)), 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 { sub simplify {
my $self = shift; my $self = shift;
$self->polyline($self->polyline->simplify(@_)); $self->set_polyline($self->as_polyline->simplify(@_));
} }
sub points { sub points {
@ -285,19 +242,4 @@ sub detect_arcs {
return @paths; 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; 1;

View File

@ -185,7 +185,7 @@ sub make_fill {
: $is_bridge : $is_bridge
? EXTR_ROLE_BRIDGE ? EXTR_ROLE_BRIDGE
: $is_solid : $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), : EXTR_ROLE_FILL),
height => $surface->thickness, 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"), flow_spacing => $params->{flow_spacing} || (warn "Warning: no flow_spacing was returned by the infill engine, please report this to the developer\n"),

View File

@ -27,7 +27,7 @@ sub infill_direction {
} }
# use bridge angle # use bridge angle
if (defined $surface->bridge_angle) { if ($surface->bridge_angle != -1) {
Slic3r::debugf "Filling bridge with angle %d\n", $surface->bridge_angle; Slic3r::debugf "Filling bridge with angle %d\n", $surface->bridge_angle;
$rotate[0] = Slic3r::Geometry::deg2rad($surface->bridge_angle); $rotate[0] = Slic3r::Geometry::deg2rad($surface->bridge_angle);
} }

View File

@ -256,7 +256,6 @@ sub extrude_path {
my $self = shift; my $self = shift;
my ($path, $description, %params) = @_; my ($path, $description, %params) = @_;
$path = $path->unpack if $path->isa('Slic3r::ExtrusionPath::Packed');
$path->simplify(&Slic3r::SCALED_RESOLUTION); $path->simplify(&Slic3r::SCALED_RESOLUTION);
# detect arcs # detect arcs
@ -293,7 +292,7 @@ sub extrude_path {
$area = ($s**2) * PI/4; $area = ($s**2) * PI/4;
} else { } else {
my $s = $path->flow_spacing; 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); $area = $self->extruder->mm3_per_mm($s, $h);
} }

View File

@ -228,8 +228,9 @@ sub point_is_on_left_of_segment {
} }
sub polyline_lines { sub polyline_lines {
my ($polygon) = @_; my ($polyline) = @_;
return map Slic3r::Line->new($polygon->[$_], $polygon->[$_+1]), 0 .. $#$polygon-1; my @points = @$polyline;
return map Slic3r::Line->new(@points[$_, $_+1]), 0 .. $#points-1;
} }
sub polygon_lines { sub polygon_lines {

View File

@ -352,7 +352,7 @@ sub _fill_gaps {
foreach my $expolygon (@infill) { foreach my $expolygon (@infill) {
my @paths = $filler->fill_surface( my @paths = $filler->fill_surface(
Slic3r::Surface->new(expolygon => $expolygon), Slic3r::Surface->new(expolygon => $expolygon, surface_type => S_TYPE_INTERNALSOLID),
density => 1, density => 1,
flow_spacing => $flow->spacing, 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", Slic3r::debugf " Optimal infill angle of bridge on layer %d is %d degrees\n",
$self->id, $bridge_angle if defined $bridge_angle; $self->id, $bridge_angle if defined $bridge_angle;
$surface->bridge_angle($bridge_angle); $surface->bridge_angle($bridge_angle // -1);
} }
} }

View File

@ -163,4 +163,7 @@ sub concave_points {
-1 .. ($#$self-1); -1 .. ($#$self-1);
} }
package Slic3r::Polygon::XS;
use parent -norequire, qw(Slic3r::Polygon Slic3r::Polyline::XS);
1; 1;

View File

@ -22,6 +22,9 @@ sub clone {
Storable::dclone($_[0]) Storable::dclone($_[0])
} }
# compability with ::XS
sub arrayref { $_[0] }
sub serialize { sub serialize {
my $self = shift; my $self = shift;
return pack 'l*', map @$_, @$self; return pack 'l*', map @$_, @$self;
@ -59,7 +62,7 @@ sub simplify {
my $self = shift; my $self = shift;
my $tolerance = shift || 10; 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); return (ref $self)->new(@$simplified);
} }
@ -70,7 +73,7 @@ sub reverse {
sub length { sub length {
my $self = shift; my $self = shift;
return Boost::Geometry::Utils::linestring_length($self); return Boost::Geometry::Utils::linestring_length($self->arrayref);
} }
sub grow { sub grow {
@ -161,14 +164,25 @@ sub scale {
return $self; 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 # removes the given distance from the end of the polyline
sub clip_end { sub clip_end {
my $self = shift; my $self = shift;
my ($distance) = @_; my ($distance) = @_;
while ($distance > 0) { while ($distance > 0) {
my $last_point = pop @$self; my $last_point = $self->[-1];
last if !@$self; $self->pop_back;
last if @$self == 0;
my $last_segment_length = $last_point->distance_to($self->[-1]); my $last_segment_length = $last_point->distance_to($self->[-1]);
if ($last_segment_length <= $distance) { 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); 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; $distance = 0;
} }
} }
@ -244,4 +258,7 @@ sub chained_path {
return map $items_map{"$_"}, @paths; return map $items_map{"$_"}, @paths;
} }
package Slic3r::Polyline::XS;
use parent qw(Slic3r::Polyline);
1; 1;

View File

@ -589,14 +589,14 @@ sub discover_horizontal_shells {
# and the latter contains the enlarged external surfaces # and the latter contains the enlarged external surfaces
my $solid = [ map $_->expolygon, grep $_->surface_type == $type, @{$layerm->slices}, @{$layerm->fill_surfaces} ]; my $solid = [ map $_->expolygon, grep $_->surface_type == $type, @{$layerm->slices}, @{$layerm->fill_surfaces} ];
next if !@$solid; 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) my $solid_layers = ($type == S_TYPE_TOP)
? $Slic3r::Config->top_solid_layers ? $Slic3r::Config->top_solid_layers
: $Slic3r::Config->bottom_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; 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; next if $n < 0 || $n >= $self->layer_count;
Slic3r::debugf " looking for neighbors on layer %d...\n", $n; Slic3r::debugf " looking for neighbors on layer %d...\n", $n;
@ -607,7 +607,7 @@ sub discover_horizontal_shells {
# intersections have contours and holes # intersections have contours and holes
my $new_internal_solid = intersection_ex( my $new_internal_solid = intersection_ex(
[ map @$_, @$solid ], [ 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, undef, 1,
); );
next if !@$new_internal_solid; next if !@$new_internal_solid;
@ -658,25 +658,22 @@ sub discover_horizontal_shells {
# assign resulting internal surfaces to layer # assign resulting internal surfaces to layer
my $neighbor_fill_surfaces = $self->layers->[$n]->regions->[$region_id]->fill_surfaces; my $neighbor_fill_surfaces = $self->layers->[$n]->regions->[$region_id]->fill_surfaces;
@$neighbor_fill_surfaces = (); $neighbor_fill_surfaces->clear;
push @$neighbor_fill_surfaces, Slic3r::Surface->new $neighbor_fill_surfaces->append(map Slic3r::Surface->new
(expolygon => $_, surface_type => S_TYPE_INTERNAL) (expolygon => $_, surface_type => S_TYPE_INTERNAL), @$internal);
for @$internal;
# assign new internal-solid surfaces to layer # assign new internal-solid surfaces to layer
push @$neighbor_fill_surfaces, Slic3r::Surface->new $neighbor_fill_surfaces->append(map Slic3r::Surface->new
(expolygon => $_, surface_type => S_TYPE_INTERNALSOLID) (expolygon => $_, surface_type => S_TYPE_INTERNALSOLID), @$internal_solid);
for @$internal_solid;
# assign top and bottom surfaces to layer # 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( my $solid_surfaces = diff_ex(
[ map $_->p, @$s ], [ map $_->p, @$s ],
[ map @$_, @$internal_solid, @$internal ], [ map @$_, @$internal_solid, @$internal ],
1, 1,
); );
push @$neighbor_fill_surfaces, $s->[0]->clone(expolygon => $_) $neighbor_fill_surfaces->append(map $s->[0]->clone(expolygon => $_), @$solid_surfaces);
for @$solid_surfaces;
} }
} }
} }

View File

@ -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( my $filler = Slic3r::Fill::Rectilinear->new(
bounding_box => $expolygon->bounding_box, bounding_box => $expolygon->bounding_box,
); );

View File

@ -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__

View File

@ -1,4 +1,4 @@
use Test::More tests => 3; use Test::More tests => 4;
use strict; use strict;
use warnings; use warnings;
@ -15,6 +15,10 @@ use Slic3r::Test;
my $config = Slic3r::Config->new_from_defaults; my $config = Slic3r::Config->new_from_defaults;
$config->set('skirts', 0); $config->set('skirts', 0);
$config->set('perimeters', 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 $test = sub {
my ($conf) = @_; my ($conf) = @_;
@ -28,20 +32,31 @@ use Slic3r::Test;
if ($self->Z > 0) { if ($self->Z > 0) {
$layers_with_shells{$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}; 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]); 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]); 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; 1;
}; };
ok $test->(), "proper number of shells is applied"; 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"; 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('cooling', 0);
$config->set('solid_infill_speed', 99); $config->set('solid_infill_speed', 99);
$config->set('top_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 $print = Slic3r::Test::init_print('V', config => $config);
my %layers_with_solid_infill = (); # Z => 1 my %layers_with_solid_infill = (); # Z => 1

View File

@ -15,10 +15,78 @@ package Slic3r::ExPolygon::XS;
use overload use overload
'@{}' => sub { $_[0]->arrayref }; '@{}' => 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; package Slic3r::ExPolygon::Collection;
use overload use overload
'@{}' => sub { $_[0]->arrayref }; '@{}' => 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; package Slic3r::Surface;
sub new { sub new {
@ -29,12 +97,12 @@ sub new {
if defined $args{bridge_angle} && $args{bridge_angle} < 0; if defined $args{bridge_angle} && $args{bridge_angle} < 0;
return $class->_new( return $class->_new(
delete $args{expolygon}, # required $args{expolygon} // (die "Missing required expolygon\n"),
delete $args{surface_type}, # required $args{surface_type} // (die "Missing required surface_type\n"),
delete $args{thickness} // -1, $args{thickness} // -1,
delete $args{thickness_layers} // 1, $args{thickness_layers} // 1,
delete $args{bridge_angle} // -1, $args{bridge_angle} // -1,
delete $args{extra_perimeters} // 0, $args{extra_perimeters} // 0,
); );
} }

View File

@ -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

View File

@ -9,6 +9,7 @@ extern "C" {
} }
#include "Point.hpp" #include "Point.hpp"
#include <algorithm>
namespace Slic3r { namespace Slic3r {
@ -19,6 +20,7 @@ class Polyline
void scale(double factor); void scale(double factor);
void translate(double x, double y); void translate(double x, double y);
void rotate(double angle, Point* center); void rotate(double angle, Point* center);
void reverse();
}; };
typedef std::vector<Polyline> Polylines; typedef std::vector<Polyline> Polylines;
@ -49,6 +51,12 @@ Polyline::rotate(double angle, Point* center)
} }
} }
void
Polyline::reverse()
{
std::reverse(this->points.begin(), this->points.end());
}
void void
perl2polyline(SV* poly_sv, Polyline& poly) perl2polyline(SV* poly_sv, Polyline& poly)
{ {

View File

@ -4,7 +4,7 @@ use strict;
use warnings; use warnings;
use Slic3r::XS; use Slic3r::XS;
use Test::More tests => 10; use Test::More tests => 11;
my $square = [ # ccw my $square = [ # ccw
[100, 100], [100, 100],
@ -49,6 +49,10 @@ is $surface->extra_perimeters, 2, 'extra_perimeters';
is scalar(@$collection), 0, 'clear collection'; is scalar(@$collection), 0, 'clear collection';
$collection->append($surface); $collection->append($surface);
is scalar(@$collection), 1, 'append to collection'; 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__ __END__

22
xs/t/06_polygon.t Normal file
View File

@ -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__

37
xs/t/07_extrusionpath.t Normal file
View File

@ -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__

126
xs/xsp/ExtrusionPath.xsp Normal file
View File

@ -0,0 +1,126 @@
%module{Slic3r::XS};
%{
#include <myinit.h>
#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
%}

29
xs/xsp/Polygon.xsp Normal file
View File

@ -0,0 +1,29 @@
%module{Slic3r::XS};
%{
#include <myinit.h>
#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
%}
};

45
xs/xsp/Polyline.xsp Normal file
View File

@ -0,0 +1,45 @@
%module{Slic3r::XS};
%{
#include <myinit.h>
#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);
}
%}
};

View File

@ -1,8 +1,14 @@
ZTable* O_OBJECT ZTable* O_OBJECT
TriangleMesh* O_OBJECT TriangleMesh* O_OBJECT
Point* O_OBJECT Point* O_OBJECT
Polyline* O_OBJECT
Polygon* O_OBJECT
ExPolygon* O_OBJECT ExPolygon* O_OBJECT
ExPolygonCollection* O_OBJECT ExPolygonCollection* O_OBJECT
SurfaceType T_UV ExtrusionPath* O_OBJECT
ExtrusionLoop* O_OBJECT
Surface* O_OBJECT Surface* O_OBJECT
SurfaceCollection* O_OBJECT SurfaceCollection* O_OBJECT
ExtrusionRole T_UV
SurfaceType T_UV

View File

@ -4,9 +4,17 @@
%typemap{AV*}; %typemap{AV*};
%typemap{Point*}; %typemap{Point*};
%typemap{ExPolygon*}; %typemap{ExPolygon*};
%typemap{Polyline*};
%typemap{Polygon*};
%typemap{SurfaceType}{parsed}{ %typemap{SurfaceType}{parsed}{
%cpp_type{SurfaceType}; %cpp_type{SurfaceType};
%precall_code{% %precall_code{%
$CVar = (SurfaceType)SvUV($PerlVar); $CVar = (SurfaceType)SvUV($PerlVar);
%}; %};
}; };
%typemap{ExtrusionRole}{parsed}{
%cpp_type{ExtrusionRole};
%precall_code{%
$CVar = (ExtrusionRole)SvUV($PerlVar);
%};
};