Very large refactoring. Ditched Slic3r::Polyline::Closed and reorganized geometric classes.

This commit is contained in:
Alessandro Ranellucci 2011-12-30 19:59:51 +01:00
parent 2def6a9787
commit 8ed91a8ec4
20 changed files with 293 additions and 349 deletions

View file

@ -30,7 +30,6 @@ lib/Slic3r/Perimeter.pm
lib/Slic3r/Point.pm lib/Slic3r/Point.pm
lib/Slic3r/Polygon.pm lib/Slic3r/Polygon.pm
lib/Slic3r/Polyline.pm lib/Slic3r/Polyline.pm
lib/Slic3r/Polyline/Closed.pm
lib/Slic3r/Print.pm lib/Slic3r/Print.pm
lib/Slic3r/Skein.pm lib/Slic3r/Skein.pm
lib/Slic3r/STL.pm lib/Slic3r/STL.pm

View file

@ -25,7 +25,6 @@ use Slic3r::Perimeter;
use Slic3r::Point; use Slic3r::Point;
use Slic3r::Polygon; use Slic3r::Polygon;
use Slic3r::Polyline; use Slic3r::Polyline;
use Slic3r::Polyline::Closed;
use Slic3r::Print; use Slic3r::Print;
use Slic3r::Skein; use Slic3r::Skein;
use Slic3r::STL; use Slic3r::STL;

View file

@ -40,6 +40,11 @@ sub holes {
return @$self[1..$#$self]; return @$self[1..$#$self];
} }
sub lines {
my $self = shift;
return map $_->lines, @$self;
}
sub clipper_expolygon { sub clipper_expolygon {
my $self = shift; my $self = shift;
return { return {
@ -106,7 +111,7 @@ sub bounding_box {
sub clip_line { sub clip_line {
my $self = shift; my $self = shift;
my ($line) = @_; my ($line) = @_;
$line = Slic3r::Line->cast($line); $line = Slic3r::Line->new($line) if ref $line eq 'ARRAY';
my @intersections = grep $_, map $_->intersection($line, 1), map $_->lines, @$self; my @intersections = grep $_, map $_->intersection($line, 1), map $_->lines, @$self;
my @dir = ( my @dir = (
@ -203,6 +208,8 @@ sub medial_axis {
} }
return undef if !@skeleton_lines; return undef if !@skeleton_lines;
return undef if !@skeleton_lines;
# now build a single polyline # now build a single polyline
my $polyline = []; my $polyline = [];
{ {
@ -248,7 +255,7 @@ sub medial_axis {
if (Slic3r::Geometry::same_point($polyline->[0], $polyline->[-1])) { if (Slic3r::Geometry::same_point($polyline->[0], $polyline->[-1])) {
return Slic3r::Polygon->new(@$polyline[0..$#$polyline-1]); return Slic3r::Polygon->new(@$polyline[0..$#$polyline-1]);
} else { } else {
return Slic3r::Polyline->cast($polyline); return Slic3r::Polyline->new($polyline);
} }
} }

View file

@ -3,11 +3,21 @@ use Moo;
use XXX; use XXX;
extends 'Slic3r::Polyline::Closed'; # the underlying Slic3r::Polygon objects holds the geometry
has 'polygon' => (
is => 'ro',
required => 1,
handles => [qw(is_printable nearest_point_to)],
);
# perimeter/fill/solid-fill/bridge/skirt # perimeter/fill/solid-fill/bridge/skirt
has 'role' => (is => 'rw', required => 1); has 'role' => (is => 'rw', required => 1);
sub BUILD {
my $self = shift;
bless $self->polygon, 'Slic3r::Polygon';
}
sub split_at { sub split_at {
my $self = shift; my $self = shift;
my ($point) = @_; my ($point) = @_;
@ -16,8 +26,8 @@ sub split_at {
# find index of point # find index of point
my $i = -1; my $i = -1;
for (my $n = 0; $n <= $#{$self->points}; $n++) { for (my $n = 0; $n <= $#{$self->polygon}; $n++) {ZZZ "here" if ref $self->polygon->[$n] eq 'ARRAY';
if ($point->id eq $self->points->[$n]->id) { if ($point->id eq $self->polygon->[$n]->id) {
$i = $n; $i = $n;
last; last;
} }
@ -25,10 +35,13 @@ sub split_at {
die "Point not found" if $i == -1; die "Point not found" if $i == -1;
my @new_points = (); my @new_points = ();
push @new_points, @{$self->points}[$i .. $#{$self->points}]; push @new_points, @{$self->polygon}[$i .. $#{$self->polygon}];
push @new_points, @{$self->points}[0 .. $i]; push @new_points, @{$self->polygon}[0 .. $i];
return Slic3r::ExtrusionPath->new(points => [@new_points], role => $self->role); return Slic3r::ExtrusionPath->new(
polyline => Slic3r::Polyline->new(\@new_points),
role => $self->role,
);
} }
1; 1;

View file

@ -1,7 +1,15 @@
package Slic3r::ExtrusionPath; package Slic3r::ExtrusionPath;
use Moo; use Moo;
extends 'Slic3r::Polyline'; use Slic3r::Geometry qw(PI X Y epsilon deg2rad rotate_points);
use XXX;
# the underlying Slic3r::Polyline objects holds the geometry
has 'polyline' => (
is => 'ro',
required => 1,
handles => [qw(merge_continuous_lines lines)],
);
# this integer represents the vertical thickness of the extrusion # this integer represents the vertical thickness of the extrusion
# expressed in layers # expressed in layers
@ -12,8 +20,10 @@ has 'flow_spacing' => (is => 'rw');
# perimeter/fill/solid-fill/bridge/skirt # perimeter/fill/solid-fill/bridge/skirt
has 'role' => (is => 'rw', required => 1); has 'role' => (is => 'rw', required => 1);
use Slic3r::Geometry qw(PI X Y epsilon deg2rad rotate_points); sub BUILD {
use XXX; my $self = shift;
bless $self->polyline, 'Slic3r::Polyline';
}
sub clip_end { sub clip_end {
my $self = shift; my $self = shift;
@ -35,6 +45,11 @@ sub clip_end {
} }
} }
sub points {
my $self = shift;
return $self->polyline;
}
sub endpoints { sub endpoints {
my $self = shift; my $self = shift;
return ($self->points->[0], $self->points->[-1]); return ($self->points->[0], $self->points->[-1]);
@ -68,8 +83,8 @@ sub split_at_acute_angles {
# if the angle between $p[-2], $p[-1], $p3 is too acute # if the angle between $p[-2], $p[-1], $p3 is too acute
# then consider $p3 only as a starting point of a new # then consider $p3 only as a starting point of a new
# path and stop the current one as it is # path and stop the current one as it is
push @paths, (ref $self)->cast( push @paths, (ref $self)->new(
[@p], polyline => Slic3r::Polyline->new(\@p),
role => $self->role, role => $self->role,
depth_layers => $self->depth_layers, depth_layers => $self->depth_layers,
); );
@ -79,8 +94,8 @@ sub split_at_acute_angles {
push @p, $p3; push @p, $p3;
} }
} }
push @paths, (ref $self)->cast( push @paths, (ref $self)->new(
[@p], polyline => Slic3r::Polyline->new(\@p),
role => $self->role, role => $self->role,
depth_layers => $self->depth_layers, depth_layers => $self->depth_layers,
) if @p > 1; ) if @p > 1;
@ -168,7 +183,7 @@ sub detect_arcs {
} }
my $arc = Slic3r::ExtrusionPath::Arc->new( my $arc = Slic3r::ExtrusionPath::Arc->new(
points => [@arc_points], polyline => Slic3r::Polyline->new(\@arc_points),
role => $self->role, role => $self->role,
orientation => $orientation, orientation => $orientation,
center => $arc_center, center => $arc_center,
@ -177,7 +192,7 @@ sub detect_arcs {
# points 0..$i form a linear path # points 0..$i form a linear path
push @paths, (ref $self)->new( push @paths, (ref $self)->new(
points => [ @points[0..$i] ], polyline => Slic3r::Polyline->new(@points[0..$i]),
role => $self->role, role => $self->role,
depth_layers => $self->depth_layers, depth_layers => $self->depth_layers,
) if $i > 0; ) if $i > 0;
@ -196,7 +211,7 @@ sub detect_arcs {
# remaining points form a linear path # remaining points form a linear path
push @paths, (ref $self)->new( push @paths, (ref $self)->new(
points => [@points], polyline => Slic3r::Polyline->new(\@points),
role => $self->role, role => $self->role,
depth_layers => $self->depth_layers, depth_layers => $self->depth_layers,
) if @points > 1; ) if @points > 1;

View file

@ -71,7 +71,8 @@ sub make_fill {
1, 1,
); );
push @surfaces, map Slic3r::Surface->cast_from_expolygon($_, push @surfaces, map Slic3r::Surface->new(
expolygon => $_,
surface_type => $group->[0]->surface_type, surface_type => $group->[0]->surface_type,
bridge_angle => $group->[0]->bridge_angle, bridge_angle => $group->[0]->bridge_angle,
depth_layers => $group->[0]->depth_layers, depth_layers => $group->[0]->depth_layers,
@ -100,7 +101,8 @@ sub make_fill {
[ @offsets ], [ @offsets ],
); );
push @new_surfaces, map Slic3r::Surface->cast_from_expolygon($_, push @new_surfaces, map Slic3r::Surface->new(
expolygon => $_,
surface_type => $surface->surface_type, surface_type => $surface->surface_type,
bridge_angle => $surface->bridge_angle, bridge_angle => $surface->bridge_angle,
depth_layers => $surface->depth_layers, depth_layers => $surface->depth_layers,
@ -111,7 +113,7 @@ sub make_fill {
# organize infill surfaces using a shortest path search # organize infill surfaces using a shortest path search
@surfaces = @{shortest_path([ @surfaces = @{shortest_path([
map [ $_->contour->points->[0], $_ ], @surfaces, map [ $_->contour->[0], $_ ], @surfaces,
])}; ])};
SURFACE: foreach my $surface (@surfaces) { SURFACE: foreach my $surface (@surfaces) {
@ -145,15 +147,14 @@ sub make_fill {
# save into layer # save into layer
push @{ $layer->fills }, Slic3r::ExtrusionPath::Collection->new( push @{ $layer->fills }, Slic3r::ExtrusionPath::Collection->new(
paths => [ paths => [
map Slic3r::ExtrusionPath->cast( map Slic3r::ExtrusionPath->new(
[ @$_ ], polyline => Slic3r::Polyline->new(@$_),
role => ($is_bridge ? 'bridge' : $is_solid ? 'solid-fill' : 'fill'), role => ($is_bridge ? 'bridge' : $is_solid ? 'solid-fill' : 'fill'),
depth_layers => $surface->depth_layers, depth_layers => $surface->depth_layers,
flow_spacing => $params->{flow_spacing}, flow_spacing => $params->{flow_spacing},
), @paths, ), @paths,
], ],
) if @paths; ) if @paths;
###$layer->fills->[-1]->cleanup;
} }
} }

View file

@ -51,7 +51,7 @@ sub fill_surface {
($bounding_box->[X1] + $bounding_box->[X2]) / 2, ($bounding_box->[X1] + $bounding_box->[X2]) / 2,
($bounding_box->[Y1] + $bounding_box->[Y2]) / 2, ($bounding_box->[Y1] + $bounding_box->[Y2]) / 2,
); );
foreach my $loop (map Slic3r::ExtrusionLoop->cast($_, role => 'fill'), @loops) { foreach my $loop (map Slic3r::ExtrusionLoop->new(polygon => $_, role => 'fill'), @loops) {
# find the point of the loop that is closest to the current extruder position # find the point of the loop that is closest to the current extruder position
$cur_pos = $loop->nearest_point_to($cur_pos); $cur_pos = $loop->nearest_point_to($cur_pos);

View file

@ -40,7 +40,7 @@ sub fill_surface {
my $path = "Math::PlanePath::$1"->new; my $path = "Math::PlanePath::$1"->new;
my @n = $self->get_n($path, [map +($_ / $distance_between_lines), @$bounding_box]); my @n = $self->get_n($path, [map +($_ / $distance_between_lines), @$bounding_box]);
my $polyline = Slic3r::Polyline->cast([ my $polyline = Slic3r::Polyline->new([
map [ map {$_*$distance_between_lines} $path->n_to_xy($_) ], @n, map [ map {$_*$distance_between_lines} $path->n_to_xy($_) ], @n,
]); ]);
return {} if !@{$polyline->points}; return {} if !@{$polyline->points};

View file

@ -55,7 +55,7 @@ sub fill_surface {
# connect lines # connect lines
{ {
my $collection = Slic3r::ExtrusionPath::Collection->new( my $collection = Slic3r::ExtrusionPath::Collection->new(
paths => [ map Slic3r::ExtrusionPath->cast([ @$_ ], role => 'bogus'), @paths ], paths => [ map Slic3r::ExtrusionPath->new(polyline => Slic3r::Polyline->new(@$_), role => 'bogus'), @paths ],
); );
@paths = (); @paths = ();

View file

@ -24,23 +24,15 @@ has 'lines' => (
); );
# collection of surfaces generated by slicing the original geometry # collection of surfaces generated by slicing the original geometry
has 'slices' => ( has 'slices' => (is => 'ro', default => sub { [] });
is => 'rw',
#isa => 'ArrayRef[Slic3r::Surface]',
default => sub { [] },
);
# collection of polygons or polylines representing thin walls contained # collection of polygons or polylines representing thin walls contained
# in the original geometry # in the original geometry
has 'thin_walls' => (is => 'rw', default => sub { [] }); has 'thin_walls' => (is => 'ro', default => sub { [] });
# collection of surfaces generated by offsetting the innermost perimeter(s) # collection of expolygons generated by offsetting the innermost perimeter(s)
# they represent boundaries of areas to fill # they represent boundaries of areas to fill
has 'fill_boundaries' => ( has 'fill_boundaries' => (is => 'ro', default => sub { [] });
is => 'rw',
#isa => 'ArrayRef[Slic3r::Surface]',
default => sub { [] },
);
# collection of surfaces generated by clipping the slices to the fill boundaries # collection of surfaces generated by clipping the slices to the fill boundaries
has 'surfaces' => ( has 'surfaces' => (
@ -150,7 +142,7 @@ sub make_surfaces {
scalar(@$expolygons), scalar(map $_->holes, @$expolygons), scalar(@$loops); scalar(@$expolygons), scalar(map $_->holes, @$expolygons), scalar(@$loops);
push @{$self->slices}, push @{$self->slices},
map Slic3r::Surface->cast_from_expolygon($_, surface_type => 'internal'), map Slic3r::Surface->new(expolygon => $_, surface_type => 'internal'),
@$expolygons; @$expolygons;
} }
@ -160,8 +152,8 @@ sub make_surfaces {
my @surfaces = @{$self->slices}; my @surfaces = @{$self->slices};
@{$self->slices} = (); @{$self->slices} = ();
foreach my $surface (@surfaces) { foreach my $surface (@surfaces) {
push @{$self->slices}, map Slic3r::Surface->cast_from_expolygon push @{$self->slices}, map Slic3r::Surface->new
($_, surface_type => 'internal'), (expolygon => $_, surface_type => 'internal'),
$surface->expolygon->offset_ex(-$distance); $surface->expolygon->offset_ex(-$distance);
} }
@ -183,7 +175,7 @@ sub make_surfaces {
if (0) { if (0) {
require "Slic3r/SVG.pm"; require "Slic3r/SVG.pm";
Slic3r::SVG::output(undef, "surfaces.svg", Slic3r::SVG::output(undef, "surfaces.svg",
polygons => [ map $_->contour->p, @{$self->slices} ], polygons => [ map $_->contour, @{$self->slices} ],
red_polygons => [ map $_->p, map @{$_->holes}, @{$self->slices} ], red_polygons => [ map $_->p, map @{$_->holes}, @{$self->slices} ],
); );
} }
@ -210,7 +202,7 @@ sub prepare_fill_surfaces {
(map $_->p, grep $_->surface_type eq 'top', @surfaces), (map $_->p, grep $_->surface_type eq 'top', @surfaces),
(map @$_, map $_->expolygon->safety_offset, @$small_internal), (map @$_, map $_->expolygon->safety_offset, @$small_internal),
]); ]);
my @top = map Slic3r::Surface->cast_from_expolygon($_, surface_type => 'top'), @$union; my @top = map Slic3r::Surface->new(expolygon => $_, surface_type => 'top'), @$union;
@surfaces = (grep($_->surface_type ne 'top', @surfaces), @top); @surfaces = (grep($_->surface_type ne 'top', @surfaces), @top);
} }
@ -242,7 +234,8 @@ sub remove_small_surfaces {
@offsets = map $_->offset_ex($distance), @offsets; @offsets = map $_->offset_ex($distance), @offsets;
@offsets = @{ union_ex([ map @$_, @offsets ], undef, 1) }; @offsets = @{ union_ex([ map @$_, @offsets ], undef, 1) };
push @{$self->fill_surfaces}, map Slic3r::Surface->cast_from_expolygon($_, push @{$self->fill_surfaces}, map Slic3r::Surface->new(
expolygon => $_,
surface_type => $surface->surface_type), @offsets; surface_type => $surface->surface_type), @offsets;
} }
@ -257,7 +250,8 @@ sub remove_small_surfaces {
[ map $_->p, @surfaces ], [ map $_->p, @surfaces ],
[ map $_->p, @{$self->fill_surfaces} ], [ map $_->p, @{$self->fill_surfaces} ],
); );
push @{$self->fill_surfaces}, map Slic3r::Surface->cast_from_expolygon($_, push @{$self->fill_surfaces}, map Slic3r::Surface->new(
expolygon => $_,
surface_type => 'internal-solid'), @$diff; surface_type => 'internal-solid'), @$diff;
} }
} }
@ -382,7 +376,8 @@ sub process_bridges {
[ $bridge_offset ], [ $bridge_offset ],
); );
push @bridges, map Slic3r::Surface->cast_from_expolygon($_, push @bridges, map Slic3r::Surface->new(
expolygon => $_,
surface_type => $surface->surface_type, surface_type => $surface->surface_type,
bridge_angle => $bridge_angle, bridge_angle => $bridge_angle,
), @$intersection; ), @$intersection;
@ -405,7 +400,8 @@ sub process_bridges {
[ map $_->p, @bridges ], [ map $_->p, @bridges ],
); );
push @bridges, map Slic3r::Surface->cast_from_expolygon($_, push @bridges, map Slic3r::Surface->new(
expolygon => $_,
surface_type => $surfaces->[0]->surface_type, surface_type => $surfaces->[0]->surface_type,
bridge_angle => $surfaces->[0]->bridge_angle, bridge_angle => $surfaces->[0]->bridge_angle,
), @$union; ), @$union;
@ -424,7 +420,8 @@ sub process_bridges {
[ $bridge->p ], [ $bridge->p ],
); );
push @{$self->fill_surfaces}, map Slic3r::Surface->cast_from_expolygon($_, push @{$self->fill_surfaces}, map Slic3r::Surface->new(
expolygon => $_,
surface_type => $bridge->surface_type, surface_type => $bridge->surface_type,
bridge_angle => $bridge->bridge_angle, bridge_angle => $bridge->bridge_angle,
), @$actual_bridge; ), @$actual_bridge;
@ -436,7 +433,8 @@ sub process_bridges {
[ map $_->p, @$group ], [ map $_->p, @$group ],
[ map $_->p, @bridges ], [ map $_->p, @bridges ],
); );
push @{$self->fill_surfaces}, map Slic3r::Surface->cast_from_expolygon($_, push @{$self->fill_surfaces}, map Slic3r::Surface->new(
expolygon => $_,
surface_type => $group->[0]->surface_type), @$difference; surface_type => $group->[0]->surface_type), @$difference;
} }
} }

View file

@ -21,13 +21,6 @@ sub new {
return $self; return $self;
} }
sub cast {
my $class = shift;
my ($line) = @_;
return $line if ref $line eq __PACKAGE__;
return $class->new($line);
}
sub a { $_[0][0] } sub a { $_[0][0] }
sub b { $_[0][1] } sub b { $_[0][1] }

View file

@ -30,7 +30,7 @@ sub make_perimeter {
# organize perimeter surfaces using a shortest path search # organize perimeter surfaces using a shortest path search
my @surfaces = @{shortest_path([ my @surfaces = @{shortest_path([
map [ $_->contour->points->[0], $_ ], @{$layer->slices}, map [ $_->contour->[0], $_ ], @{$layer->slices},
])}; ])};
foreach my $surface (@surfaces) { foreach my $surface (@surfaces) {
@ -50,9 +50,7 @@ sub make_perimeter {
# create one more offset to be used as boundary for fill # create one more offset to be used as boundary for fill
{ {
my @fill_boundaries = map Slic3r::Surface->cast_from_expolygon my @fill_boundaries = map $_->offset_ex(-$distance), @last_offsets;
($_, surface_type => $surface->surface_type),
map $_->offset_ex(-$distance), @last_offsets;
# TODO: diff(offset(@last_offsets, -$distance/2), offset(@fill_boundaries, +$distance/2)) # TODO: diff(offset(@last_offsets, -$distance/2), offset(@fill_boundaries, +$distance/2))
# this represents the small gaps that we need to treat like thin polygons, # this represents the small gaps that we need to treat like thin polygons,
@ -66,12 +64,12 @@ sub make_perimeter {
foreach my $island (@perimeters) { foreach my $island (@perimeters) {
# do holes starting from innermost one # do holes starting from innermost one
foreach my $hole (map $_->holes, map @$_, @$island) { foreach my $hole (map $_->holes, map @$_, @$island) {
push @{ $layer->perimeters }, Slic3r::ExtrusionLoop->cast($hole, role => 'perimeter'); push @{ $layer->perimeters }, Slic3r::ExtrusionLoop->new(polygon => $hole, role => 'perimeter');
} }
# do contours starting from innermost one # do contours starting from innermost one
foreach my $contour (map $_->contour, map @$_, reverse @$island) { foreach my $contour (map $_->contour, map @$_, reverse @$island) {
push @{ $layer->perimeters }, Slic3r::ExtrusionLoop->cast($contour, role => 'perimeter'); push @{ $layer->perimeters }, Slic3r::ExtrusionLoop->new(polygon => $contour, role => 'perimeter');
} }
} }
@ -83,9 +81,9 @@ sub make_perimeter {
# add thin walls as perimeters # add thin walls as perimeters
for (@{ $layer->thin_walls }) { for (@{ $layer->thin_walls }) {
if ($_->isa('Slic3r::Polygon')) { if ($_->isa('Slic3r::Polygon')) {
push @{ $layer->perimeters }, Slic3r::ExtrusionLoop->cast($_, role => 'perimeter'); push @{ $layer->perimeters }, Slic3r::ExtrusionLoop->new(polygon => $_, role => 'perimeter');
} else { } else {
push @{ $layer->perimeters }, Slic3r::ExtrusionPath->cast($_->points, role => 'perimeter'); push @{ $layer->perimeters }, Slic3r::ExtrusionPath->new(polyline => $_->points, role => 'perimeter');
} }
} }
} }

View file

@ -3,11 +3,10 @@ use strict;
use warnings; use warnings;
# a polygon is a closed polyline. # a polygon is a closed polyline.
# if you're asking why there's a Slic3r::Polygon as well use parent 'Slic3r::Polyline';
# as a Slic3r::Polyline::Closed you're right. I plan to
# ditch the latter and port everything to this class.
use Slic3r::Geometry qw(polygon_lines polygon_remove_parallel_continuous_edges use Slic3r::Geometry qw(polygon_lines polygon_remove_parallel_continuous_edges
scale polygon_remove_acute_vertices
polygon_segment_having_point point_in_polygon move_points rotate_points); polygon_segment_having_point point_in_polygon move_points rotate_points);
use Slic3r::Geometry::Clipper qw(JT_MITER); use Slic3r::Geometry::Clipper qw(JT_MITER);
@ -31,12 +30,6 @@ sub clone {
return (ref $self)->new(map $_->clone, @$self); return (ref $self)->new(map $_->clone, @$self);
} }
# legacy method, to be removed when we ditch Slic3r::Polyline::Closed
sub closed_polyline {
my $self = shift;
return Slic3r::Polyline::Closed->cast($self);
}
sub lines { sub lines {
my $self = shift; my $self = shift;
return map Slic3r::Line->new($_), polygon_lines($self); return map Slic3r::Line->new($_), polygon_lines($self);
@ -44,7 +37,20 @@ sub lines {
sub cleanup { sub cleanup {
my $self = shift; my $self = shift;
$self->merge_continuous_lines;
}
sub merge_continuous_lines {
my $self = shift;
polygon_remove_parallel_continuous_edges($self); polygon_remove_parallel_continuous_edges($self);
bless $_, 'Slic3r::Point' for @$self;
}
sub remove_acute_vertices {
my $self = shift;
polygon_remove_acute_vertices($self);
bless $_, 'Slic3r::Point' for @$self;
} }
sub point_on_segment { sub point_on_segment {
@ -106,7 +112,8 @@ sub subdivide {
# $num_points is the number of points to add between $i-1 and $i # $num_points is the number of points to add between $i-1 and $i
my $spacing = $len / ($num_points + 1); my $spacing = $len / ($num_points + 1);
my @new_points = map Slic3r::Geometry::point_along_segment($self->[$i-1], $self->[$i], $spacing * $_), my @new_points = map Slic3r::Point->new($_),
map Slic3r::Geometry::point_along_segment($self->[$i-1], $self->[$i], $spacing * $_),
1..$num_points; 1..$num_points;
splice @$self, $i, 0, @new_points; splice @$self, $i, 0, @new_points;
@ -114,4 +121,22 @@ sub subdivide {
} }
} }
# returns false if the polyline is too tight to be printed
sub is_printable {
my $self = shift;
# try to get an inwards offset
# for a distance equal to half of the extrusion width;
# if no offset is possible, then polyline is not printable
my $p = $self->clone;
@$p = reverse @$p if !Math::Clipper::is_counter_clockwise($p);
my $offsets = Math::Clipper::offset([$p], -(scale $Slic3r::flow_spacing / 2), $Slic3r::resolution * 100000, JT_MITER, 2);
return @$offsets ? 1 : 0;
}
sub is_valid {
my $self = shift;
return @{$self->points} >= 3;
}
1; 1;

View file

@ -1,38 +1,37 @@
package Slic3r::Polyline; package Slic3r::Polyline;
use Moo; use strict;
use warnings;
use Math::Clipper qw(); use Math::Clipper qw();
use Slic3r::Geometry qw(A B polyline_remove_parallel_continuous_edges polyline_remove_acute_vertices use Slic3r::Geometry qw(A B polyline_remove_parallel_continuous_edges polyline_remove_acute_vertices
polygon_remove_acute_vertices polygon_remove_parallel_continuous_edges move_points same_point); move_points same_point);
use Sub::Quote;
use XXX; use XXX;
# arrayref of ordered points # the constructor accepts an array(ref) of points
has 'points' => ( sub new {
is => 'rw', my $class = shift;
required => 1, my $self;
default => sub { [] }, if (@_ == 1) {
isa => quote_sub q{ use Carp; confess "invalid points" if grep ref $_ ne 'Slic3r::Point', @{$_[0]} }, $self = [ @{$_[0]} ];
); } else {
$self = [ @_ ];
}
bless $self, $class;
bless $_, 'Slic3r::Point' for @$self;
$self;
}
sub id { sub id {
my $self = shift; my $self = shift;
return join ' - ', sort map $_->id, @{$self->points}; return join ' - ', sort map $_->id, @$self;
}
sub cast {
my $class = shift;
my ($points, %args) = @_;
$points = [ map Slic3r::Point->cast($_), @$points ];
return $class->new(points => $points, %args);
} }
sub lines { sub lines {
my $self = shift; my $self = shift;
my @lines = (); my @lines = ();
my $previous_point; my $previous_point;
foreach my $point (@{ $self->points }) { foreach my $point (@$self) {
if ($previous_point) { if ($previous_point) {
push @lines, Slic3r::Line->new($previous_point, $point); push @lines, Slic3r::Line->new($previous_point, $point);
} }
@ -41,43 +40,25 @@ sub lines {
return @lines; return @lines;
} }
sub p {
my $self = shift;
return [ @{$self->points} ];
}
sub merge_continuous_lines { sub merge_continuous_lines {
my $self = shift; my $self = shift;
my $points = $self->p;
if ($self->isa('Slic3r::Polyline::Closed')) { polyline_remove_parallel_continuous_edges($self);
polygon_remove_parallel_continuous_edges($points); bless $_, 'Slic3r::Point' for @$self;
} else {
polyline_remove_parallel_continuous_edges($points);
}
@{$self->points} = map Slic3r::Point->new($_), @$points;
} }
sub remove_acute_vertices { sub remove_acute_vertices {
my $self = shift; my $self = shift;
my $points = $self->p; polyline_remove_acute_vertices($self);
if ($self->isa('Slic3r::Polyline::Closed')) { bless $_, 'Slic3r::Point' for @$self;
polygon_remove_acute_vertices($points);
} else {
polyline_remove_acute_vertices($points);
}
@{$self->points} = map Slic3r::Point->new($_), @$points;
} }
sub cleanup { sub simplify {
my $self = shift; my $self = shift;
my $tolerance = shift || 10; my $tolerance = shift || 10;
my $points = $self->p; @$self = Slic3r::Geometry::Douglas_Peucker($self, $tolerance);
push @$points, $points->[0] if $self->isa('Slic3r::Polyline::Closed'); bless $_, 'Slic3r::Point' for @$self;
my @clean_points = map Slic3r::Point->new($_),
Slic3r::Geometry::Douglas_Peucker($self->p, $tolerance);
pop @clean_points if $self->isa('Slic3r::Polyline::Closed');
@{$self->points} = @clean_points;
} }
sub reverse_points { sub reverse_points {
@ -104,7 +85,7 @@ sub nearest_point_to {
my $self = shift; my $self = shift;
my ($point) = @_; my ($point) = @_;
$point = Slic3r::Geometry::nearest_point($point, $self->p); $point = Slic3r::Geometry::nearest_point($point, $self);
return Slic3r::Point->new($point); return Slic3r::Point->new($point);
} }
@ -166,7 +147,7 @@ sub clip_with_expolygon {
} }
} }
return map Slic3r::Polyline->cast($_), @polylines; return map Slic3r::Polyline->new($_), @polylines;
} }
sub bounding_box { sub bounding_box {

View file

@ -1,49 +0,0 @@
package Slic3r::Polyline::Closed;
use Moo;
extends 'Slic3r::Polyline';
use Math::Clipper qw(JT_MITER);
use Slic3r::Geometry qw(scale);
sub lines {
my $self = shift;
my @lines = $self->SUPER::lines(@_);
# since this is a closed polyline, we just add a line at the end,
# connecting the last and the first point
push @lines, Slic3r::Line->new($self->points->[-1], $self->points->[0]);
return @lines;
}
sub encloses_point {
my $self = shift;
my ($point) = @_;
return Slic3r::Geometry::point_in_polygon($point->p, $self->p);
}
# returns false if the polyline is too tight to be printed
sub is_printable {
my $self = shift;
# try to get an inwards offset
# for a distance equal to half of the extrusion width;
# if no offset is possible, then polyline is not printable
my $p = $self->p;
@$p = reverse @$p if !Math::Clipper::is_counter_clockwise($p);
my $offsets = Math::Clipper::offset([$p], -(scale $Slic3r::flow_spacing / 2), $Slic3r::resolution * 100000, JT_MITER, 2);
return @$offsets ? 1 : 0;
}
sub is_valid {
my $self = shift;
return @{$self->points} >= 3;
}
sub polygon {
my $self = shift;
return Slic3r::Polygon->new($self->points);
}
1;

View file

@ -125,8 +125,8 @@ sub new_from_mesh {
[ map $_->expolygon->holes, @upper_surfaces, @lower_surfaces, ], [ map $_->expolygon->holes, @upper_surfaces, @lower_surfaces, ],
); );
@{$layer->slices} = map Slic3r::Surface->cast_from_expolygon @{$layer->slices} = map Slic3r::Surface->new
($_, surface_type => 'internal'), (expolygon => $_, surface_type => 'internal'),
@$diff; @$diff;
} }
@ -178,7 +178,7 @@ sub detect_surfaces_type {
1, 1,
); );
return grep $_->contour->is_printable, return grep $_->contour->is_printable,
map Slic3r::Surface->cast_from_expolygon($_, surface_type => $result_type), map Slic3r::Surface->new(expolygon => $_, surface_type => $result_type),
@$expolygons; @$expolygons;
}; };
@ -223,7 +223,7 @@ sub detect_surfaces_type {
@internal = $surface_difference->($layer->slices, [@top, @bottom], 'internal'); @internal = $surface_difference->($layer->slices, [@top, @bottom], 'internal');
# save surfaces to layer # save surfaces to layer
$layer->slices([ @bottom, @top, @internal ]); @{$layer->slices} = (@bottom, @top, @internal);
Slic3r::debugf " layer %d has %d bottom, %d top and %d internal surfaces\n", Slic3r::debugf " layer %d has %d bottom, %d top and %d internal surfaces\n",
$layer->id, scalar(@bottom), scalar(@top), scalar(@internal); $layer->id, scalar(@bottom), scalar(@top), scalar(@internal);
@ -235,10 +235,10 @@ sub detect_surfaces_type {
foreach my $surface (@{$layer->slices}) { foreach my $surface (@{$layer->slices}) {
my $intersection = intersection_ex( my $intersection = intersection_ex(
[ $surface->p ], [ $surface->p ],
[ map $_->p, @{$layer->fill_boundaries} ], [ map @$_, @{$layer->fill_boundaries} ],
); );
push @{$layer->surfaces}, map Slic3r::Surface->cast_from_expolygon push @{$layer->surfaces}, map Slic3r::Surface->new
($_, surface_type => $surface->surface_type), (expolygon => $_, surface_type => $surface->surface_type),
@$intersection; @$intersection;
} }
} }
@ -298,13 +298,13 @@ sub discover_horizontal_shells {
# assign resulting inner surfaces to layer # assign resulting inner surfaces to layer
my $neighbor_fill_surfaces = $self->layers->[$n]->fill_surfaces; my $neighbor_fill_surfaces = $self->layers->[$n]->fill_surfaces;
@$neighbor_fill_surfaces = (); @$neighbor_fill_surfaces = ();
push @$neighbor_fill_surfaces, Slic3r::Surface->cast_from_expolygon push @$neighbor_fill_surfaces, Slic3r::Surface->new
($_, surface_type => 'internal') (expolygon => $_, surface_type => 'internal')
for @$internal; for @$internal;
# assign new internal-solid surfaces to layer # assign new internal-solid surfaces to layer
push @$neighbor_fill_surfaces, Slic3r::Surface->cast_from_expolygon push @$neighbor_fill_surfaces, Slic3r::Surface->new
($_, surface_type => 'internal-solid') (expolygon => $_, surface_type => 'internal-solid')
for @$internal_solid; for @$internal_solid;
# assign top and bottom surfaces to layer # assign top and bottom surfaces to layer
@ -313,8 +313,8 @@ sub discover_horizontal_shells {
[ map $_->p, @$s ], [ map $_->p, @$s ],
[ map @$_, @$internal_solid, @$internal ], [ map @$_, @$internal_solid, @$internal ],
); );
push @$neighbor_fill_surfaces, Slic3r::Surface->cast_from_expolygon push @$neighbor_fill_surfaces, Slic3r::Surface->new
($_, surface_type => $s->[0]->surface_type, bridge_angle => $s->[0]->bridge_angle) (expolygon => $_, surface_type => $s->[0]->surface_type, bridge_angle => $s->[0]->bridge_angle)
for @$solid_surfaces; for @$solid_surfaces;
} }
} }
@ -341,7 +341,10 @@ sub extrude_skirt {
for (my $i = $Slic3r::skirts - 1; $i >= 0; $i--) { for (my $i = $Slic3r::skirts - 1; $i >= 0; $i--) {
my $distance = scale ($Slic3r::skirt_distance + ($Slic3r::flow_spacing * $i)); my $distance = scale ($Slic3r::skirt_distance + ($Slic3r::flow_spacing * $i));
my $outline = offset([$convex_hull], $distance, $Slic3r::resolution * 100, JT_ROUND); my $outline = offset([$convex_hull], $distance, $Slic3r::resolution * 100, JT_ROUND);
push @skirts, Slic3r::ExtrusionLoop->cast([ @{$outline->[0]} ], role => 'skirt'); push @skirts, Slic3r::ExtrusionLoop->new(
polygon => Slic3r::Polygon->new(@{$outline->[0]}),
role => 'skirt',
);
} }
# apply skirts to all layers # apply skirts to all layers
@ -387,12 +390,12 @@ sub infill_every_layers {
{ {
my @new_surfaces = (); my @new_surfaces = ();
push @new_surfaces, grep $_->surface_type ne 'internal', @{$layer->fill_surfaces}; push @new_surfaces, grep $_->surface_type ne 'internal', @{$layer->fill_surfaces};
push @new_surfaces, map Slic3r::Surface->cast_from_expolygon push @new_surfaces, map Slic3r::Surface->new
($_, surface_type => 'internal', depth_layers => $d + 1), @$intersection; (expolygon => $_, surface_type => 'internal', depth_layers => $d + 1), @$intersection;
foreach my $depth (reverse $d..$Slic3r::infill_every_layers) { foreach my $depth (reverse $d..$Slic3r::infill_every_layers) {
push @new_surfaces, map Slic3r::Surface->cast_from_expolygon push @new_surfaces, map Slic3r::Surface->new
($_, surface_type => 'internal', depth_layers => $depth), (expolygon => $_, surface_type => 'internal', depth_layers => $depth),
# difference between our internal layers with depth == $depth # difference between our internal layers with depth == $depth
# and the intersection found # and the intersection found
@ -413,8 +416,8 @@ sub infill_every_layers {
my @new_surfaces = (); my @new_surfaces = ();
push @new_surfaces, grep $_->surface_type ne 'internal', @{$lower_layer->fill_surfaces}; push @new_surfaces, grep $_->surface_type ne 'internal', @{$lower_layer->fill_surfaces};
foreach my $depth (1..$Slic3r::infill_every_layers) { foreach my $depth (1..$Slic3r::infill_every_layers) {
push @new_surfaces, map Slic3r::Surface->cast_from_expolygon push @new_surfaces, map Slic3r::Surface->new
($_, surface_type => 'internal', depth_layers => $depth), (expolygon => $_, surface_type => 'internal', depth_layers => $depth),
# difference between internal layers with depth == $depth # difference between internal layers with depth == $depth
# and the intersection found # and the intersection found

View file

@ -1,17 +1,10 @@
package Slic3r::Surface; package Slic3r::Surface;
use Moo; use Moo;
has 'contour' => ( has 'expolygon' => (
is => 'ro', is => 'ro',
#isa => 'Slic3r::Polyline::Closed',
required => 1, required => 1,
); handles => [qw(encloses_point lines contour holes)],
has 'holes' => (
traits => ['Array'],
is => 'rw',
#isa => 'ArrayRef[Slic3r::Polyline::Closed]',
default => sub { [] },
); );
has 'surface_type' => ( has 'surface_type' => (
@ -24,31 +17,6 @@ has 'depth_layers' => (is => 'ro', default => sub {1});
has 'bridge_angle' => (is => 'ro'); has 'bridge_angle' => (is => 'ro');
sub cast_from_polygon {
my $class = shift;
my ($polygon, %args) = @_;
return $class->new(
contour => Slic3r::Polyline::Closed->cast($polygon),
%args,
);
}
sub cast_from_expolygon {
my $class = shift;
my ($expolygon, %args) = @_;
if (ref $expolygon eq 'HASH') {
$expolygon = Slic3r::ExPolygon->new($expolygon);
}
return $class->new(
contour => $expolygon->contour->closed_polyline,
holes => [ map $_->closed_polyline, $expolygon->holes ],
%args,
);
}
# static method to group surfaces having same surface_type, bridge_angle and depth_layers # static method to group surfaces having same surface_type, bridge_angle and depth_layers
sub group { sub group {
my $class = shift; my $class = shift;
@ -73,7 +41,7 @@ sub add_hole {
my $self = shift; my $self = shift;
my ($hole) = @_; my ($hole) = @_;
push @{ $self->holes }, $hole; push @$self, $hole;
} }
sub id { sub id {
@ -81,15 +49,6 @@ sub id {
return $self->contour->id; return $self->contour->id;
} }
sub encloses_point {
my $self = shift;
my ($point) = @_;
return 0 if !$self->contour->encloses_point($point);
return 0 if grep $_->encloses_point($point), @{ $self->holes };
return 1;
}
sub clipper_polygon { sub clipper_polygon {
my $self = shift; my $self = shift;
@ -102,18 +61,8 @@ sub clipper_polygon {
} }
sub p { sub p {
my $self = shift; my $self = shift;use XXX; ZZZ $self->expolygon if !eval { 1 if @{$self->expolygon}; 1 };
return ($self->contour->p, map $_->p, @{$self->holes}); return @{$self->expolygon};
}
sub expolygon {
my $self = shift;
return Slic3r::ExPolygon->new($self->contour->p, map $_->p, @{$self->holes});
}
sub lines {
my $self = shift;
return @{ $self->contour->lines }, map @{ $_->lines }, @{ $self->holes };
} }
1; 1;

View file

@ -13,13 +13,13 @@ use Slic3r;
use Slic3r::Geometry qw(epsilon); use Slic3r::Geometry qw(epsilon);
{ {
my $path = Slic3r::ExtrusionPath->cast([ my $path = Slic3r::ExtrusionPath->new(polyline => Slic3r::Polyline->new(
[135322.42,26654.96], [187029.11,99546.23], [222515.14,92381.93], [258001.16,99546.23], [135322.42,26654.96], [187029.11,99546.23], [222515.14,92381.93], [258001.16,99546.23],
[286979.42,119083.91], [306517.1,148062.17], [313681.4,183548.2], [286979.42,119083.91], [306517.1,148062.17], [313681.4,183548.2],
[306517.1,219034.23], [286979.42,248012.49], [258001.16,267550.17], [222515.14,274714.47], [306517.1,219034.23], [286979.42,248012.49], [258001.16,267550.17], [222515.14,274714.47],
[187029.11,267550.17], [158050.85,248012.49], [138513.17,219034.23], [131348.87,183548.2], [187029.11,267550.17], [158050.85,248012.49], [138513.17,219034.23], [131348.87,183548.2],
[86948.77,175149.09], [119825.35,100585], [86948.77,175149.09], [119825.35,100585],
], role => 'fill'); ), role => 'fill');
my $collection = Slic3r::ExtrusionPath::Collection->new(paths => [$path]); my $collection = Slic3r::ExtrusionPath::Collection->new(paths => [$path]);
$collection->detect_arcs(30); $collection->detect_arcs(30);
@ -31,14 +31,17 @@ use Slic3r::Geometry qw(epsilon);
#========================================================== #==========================================================
{ {
my $path1 = Slic3r::ExtrusionPath->cast([ my $path1 = Slic3r::ExtrusionPath->new(polyline => Slic3r::Polyline->new(
[10,20], [10.7845909572784,19.9691733373313], [11.5643446504023,19.8768834059514], [10,20], [10.7845909572784,19.9691733373313], [11.5643446504023,19.8768834059514],
[12.3344536385591,19.7236992039768], [13.0901699437495,19.5105651629515], [12.3344536385591,19.7236992039768], [13.0901699437495,19.5105651629515],
[13.8268343236509,19.2387953251129], [14.5399049973955,18.9100652418837], [13.8268343236509,19.2387953251129], [14.5399049973955,18.9100652418837],
[15.2249856471595,18.5264016435409], [15.8778525229247,18.0901699437495], [15.2249856471595,18.5264016435409], [15.8778525229247,18.0901699437495],
[16.4944804833018,17.6040596560003], [16.4944804833018,17.6040596560003],
], role => 'fill'); ), role => 'fill');
my $path2 = Slic3r::ExtrusionPath->cast([ reverse @{$path1->points} ], role => 'fill'); my $path2 = Slic3r::ExtrusionPath->new(
polyline => Slic3r::Polyline->new(reverse @{$path1->points}),
role => 'fill',
);
my $collection1 = Slic3r::ExtrusionPath::Collection->new(paths => [$path1]); my $collection1 = Slic3r::ExtrusionPath::Collection->new(paths => [$path1]);
my $collection2 = Slic3r::ExtrusionPath::Collection->new(paths => [$path2]); my $collection2 = Slic3r::ExtrusionPath::Collection->new(paths => [$path2]);

View file

@ -2,7 +2,7 @@ use Test::More;
use strict; use strict;
use warnings; use warnings;
plan tests => 4; plan tests => 3;
BEGIN { BEGIN {
use FindBin; use FindBin;
@ -11,14 +11,17 @@ BEGIN {
use Slic3r; use Slic3r;
my $polyline = Slic3r::Polyline::Closed->cast([ {
my $polygon = Slic3r::Polygon->new([
[5,0], [10,0], [15,0], [20,0], [20,10], [20,30], [0,0], [5,0], [10,0], [15,0], [20,0], [20,10], [20,30], [0,0],
]); ]);
$polyline->merge_continuous_lines; $polygon->merge_continuous_lines;
is scalar(@{$polyline->points}), 3, 'merge_continuous_lines'; is scalar(@$polygon), 3, 'merge_continuous_lines';
}
my $gear = [ {
my $gear = [
[144.9694,317.1543], [145.4181,301.5633], [146.3466,296.921], [131.8436,294.1643], [131.7467,294.1464], [144.9694,317.1543], [145.4181,301.5633], [146.3466,296.921], [131.8436,294.1643], [131.7467,294.1464],
[121.7238,291.5082], [117.1631,290.2776], [107.9198,308.2068], [100.1735,304.5101], [104.9896,290.3672], [121.7238,291.5082], [117.1631,290.2776], [107.9198,308.2068], [100.1735,304.5101], [104.9896,290.3672],
[106.6511,286.2133], [93.453,279.2327], [81.0065,271.4171], [67.7886,286.5055], [60.7927,280.1127], [106.6511,286.2133], [93.453,279.2327], [81.0065,271.4171], [67.7886,286.5055], [60.7927,280.1127],
@ -48,18 +51,23 @@ my $gear = [
[234.9061,298.5798], [227.0321,286.2841], [225.2505,281.8301], [211.5387,287.8187], [202.3025,291.0935], [234.9061,298.5798], [227.0321,286.2841], [225.2505,281.8301], [211.5387,287.8187], [202.3025,291.0935],
[197.307,292.831], [199.808,313.1906], [191.5298,315.0787], [187.3082,299.8172], [186.4201,295.3766], [197.307,292.831], [199.808,313.1906], [191.5298,315.0787], [187.3082,299.8172], [186.4201,295.3766],
[180.595,296.0487], [161.7854,297.4248], [156.8058,297.6214], [154.3395,317.8592], [180.595,296.0487], [161.7854,297.4248], [156.8058,297.6214], [154.3395,317.8592],
]; ];
$polyline = Slic3r::Polyline::Closed->cast($gear); my $polygon = Slic3r::Polygon->new($gear);
$polyline->merge_continuous_lines; $polygon->merge_continuous_lines;
note sprintf "original points: %d\nnew points: %d", scalar(@$gear), scalar(@{$polyline->points}); note sprintf "original points: %d\nnew points: %d", scalar(@$gear), scalar(@$polygon);
ok @{$polyline->points} < @$gear, 'gear was simplified using merge_continuous_lines'; ok @$polygon < @$gear, 'gear was simplified using merge_continuous_lines';
my $num_points = scalar @{$polyline->points}; # simplify() is not being used, so we don't test it
$polyline->cleanup; if (0) {
note sprintf "original points: %d\nnew points: %d", $num_points, scalar(@{$polyline->points}); my $num_points = scalar @$polygon;
ok @{$polyline->points} < $num_points, 'gear was further simplified using Douglas-Peucker'; $polygon->simplify;
note sprintf "original points: %d\nnew points: %d", $num_points, scalar(@$polygon);
ok @$polygon < $num_points, 'gear was further simplified using Douglas-Peucker';
}
}
my $circle = [ {
my $circle = [
[3744.8,8045.8],[3788.1,8061.4],[3940.6,8116.3],[3984.8,8129.2],[4140.6,8174.4],[4185.5,8184.4],[4343.8,8219.9], [3744.8,8045.8],[3788.1,8061.4],[3940.6,8116.3],[3984.8,8129.2],[4140.6,8174.4],[4185.5,8184.4],[4343.8,8219.9],
[4389.2,8227.1],[4549.4,8252.4],[4595.2,8256.7],[4756.6,8272],[4802.6,8273.4],[4964.7,8278.5],[5010.7,8277.1], [4389.2,8227.1],[4549.4,8252.4],[4595.2,8256.7],[4756.6,8272],[4802.6,8273.4],[4964.7,8278.5],[5010.7,8277.1],
[5172.8,8272],[5218.6,8267.7],[5380,8252.4],[5425.5,8245.2],[5585.6,8219.9],[5630.5,8209.8],[5788.8,8174.4], [5172.8,8272],[5218.6,8267.7],[5380,8252.4],[5425.5,8245.2],[5585.6,8219.9],[5630.5,8209.8],[5788.8,8174.4],
@ -89,9 +97,10 @@ my $circle = [
[2283.7,6912.5],[2311.9,6948.8],[2411.4,7077],[2441.8,7111.5],[2549,7233.2],[2581.5,7265.7],[2696.2,7380.4], [2283.7,6912.5],[2311.9,6948.8],[2411.4,7077],[2441.8,7111.5],[2549,7233.2],[2581.5,7265.7],[2696.2,7380.4],
[2730.7,7410.8],[2852.4,7518],[2888.8,7546.2],[3016.9,7645.7],[3055,7671.5],[3189.1,7762.7],[3228.7,7786.1], [2730.7,7410.8],[2852.4,7518],[2888.8,7546.2],[3016.9,7645.7],[3055,7671.5],[3189.1,7762.7],[3228.7,7786.1],
[3368.3,7868.6],[3409.2,7889.5],[3553.8,7963.2],[3596,7981.4], [3368.3,7868.6],[3409.2,7889.5],[3553.8,7963.2],[3596,7981.4],
]; ];
$polyline = Slic3r::Polyline::Closed->cast($circle); my $polygon = Slic3r::Polygon->new($circle);
$polyline->merge_continuous_lines; $polygon->merge_continuous_lines;
note sprintf "original points: %d\nnew points: %d", scalar(@$circle), scalar(@{$polyline->points}); note sprintf "original points: %d\nnew points: %d", scalar(@$circle), scalar(@$polygon);
ok @{$polyline->points} >= @$gear/3, 'circle was simplified using merge_continuous_lines'; ok @$polygon >= @$circle/3, 'circle was simplified using merge_continuous_lines';
}

View file

@ -103,8 +103,8 @@ is_deeply $intersection, [ [12, 12], [18, 16] ], 'internal lines are preserved';
], 'tangent line is clipped to square with hole'; ], 'tangent line is clipped to square with hole';
} }
{ {
my $polyline = Slic3r::Polyline->cast([ [5, 18], [25, 18], [25, 15], [15, 15], [15, 12], [12, 12], [12, 5] ]); my $polyline = Slic3r::Polyline->new([ [5, 18], [25, 18], [25, 15], [15, 15], [15, 12], [12, 12], [12, 5] ]);
is_deeply [ map $_->p, $polyline->clip_with_expolygon($expolygon) ], [ is_deeply [ map $_, $polyline->clip_with_expolygon($expolygon) ], [
[ [10, 18], [20, 18] ], [ [10, 18], [20, 18] ],
[ [20, 15], [16, 15] ], [ [20, 15], [16, 15] ],
[ [15, 14], [15, 12], [12, 12], [12, 10] ], [ [15, 14], [15, 12], [12, 12], [12, 10] ],