diff --git a/lib/Slic3r.pm b/lib/Slic3r.pm index 0bf56a08..f72dd1ea 100644 --- a/lib/Slic3r.pm +++ b/lib/Slic3r.pm @@ -3,6 +3,7 @@ package Slic3r; use strict; use warnings; +use Slic3r::ExtrusionPath; use Slic3r::Layer; use Slic3r::Line; use Slic3r::Perimeter; diff --git a/lib/Slic3r/ExtrusionPath.pm b/lib/Slic3r/ExtrusionPath.pm new file mode 100644 index 00000000..e462956f --- /dev/null +++ b/lib/Slic3r/ExtrusionPath.pm @@ -0,0 +1,6 @@ +package Slic3r::ExtrusionPath; +use Moose; + +extends 'Slic3r::Polyline'; + +1; diff --git a/lib/Slic3r/Layer.pm b/lib/Slic3r/Layer.pm index 733caa4b..933c5e6b 100644 --- a/lib/Slic3r/Layer.pm +++ b/lib/Slic3r/Layer.pm @@ -3,12 +3,16 @@ use Moose; use XXX; +# a sequential number of layer, starting at 0 has 'id' => ( is => 'ro', isa => 'Int', required => 1, ); +# index of points generated by slicing the original geometry +# keys are stringified coordinates (example: "0,0") +# each points connects exactly two segments has 'pointmap' => ( traits => ['Hash'], is => 'rw', @@ -19,12 +23,15 @@ has 'pointmap' => ( }, ); +# collection of segments generated by slicing the original geometry +# each segment is part of a closed polyline has 'lines' => ( is => 'rw', isa => 'ArrayRef[Slic3r::Line]', default => sub { [] }, ); +# collection of surfaces generated by slicing the original geometry has 'surfaces' => ( traits => ['Array'], is => 'rw', @@ -32,9 +39,19 @@ has 'surfaces' => ( default => sub { [] }, ); +# ordered collection of extrusion paths to build all perimeters has 'perimeters' => ( is => 'rw', - isa => 'ArrayRef[Slic3r::Polyline]', + isa => 'ArrayRef[Slic3r::ExtrusionPath]', + default => sub { [] }, +); + +# collection of surfaces generated by offsetting the innermost perimeter(s) +# they represent boundaries of areas to fill +has 'fill_surfaces' => ( + traits => ['Array'], + is => 'rw', + isa => 'ArrayRef[Slic3r::Surface]', default => sub { [] }, ); diff --git a/lib/Slic3r/Perimeter.pm b/lib/Slic3r/Perimeter.pm index 8d6beda7..ce6a8409 100644 --- a/lib/Slic3r/Perimeter.pm +++ b/lib/Slic3r/Perimeter.pm @@ -29,34 +29,22 @@ sub make_perimeter { # create other offsets for (my $loop = 1; $loop < $Slic3r::perimeter_offsets; $loop++) { - my ($contour_p, @holes_p) = map $self->_mgp_from_points_ref($_), @{ $perimeters[-1]->polygons }; - # generate offsets - my $contour_offsets = $contour_p->offset_polygon($Slic3r::flow_width / $Slic3r::resolution); - my @hole_offsets = map @$_, map $_->offset_polygon(- $Slic3r::flow_width / $Slic3r::resolution), @holes_p; + # offsetting a polygon can result in one or many offset polygons + my @offsets = $self->offset_polygon($perimeters[-1]); - # now we subtract perimeter offsets from the contour offset polygon - # this will generate a single polygon with correct holes and also - # will take care of collisions between contour offset and holes - foreach my $contour_points (@$contour_offsets) { - my $tmp = $self->_mgp_from_points_ref($contour_points)->convert2gpc; - foreach my $hole_points (@hole_offsets) { - $hole_points = $self->_mgp_from_points_ref($hole_points)->convert2gpc; - $tmp = GpcClip('DIFFERENCE', $tmp, $hole_points); - } + foreach my $offset_polygon (@offsets) { + my ($contour_p, @holes_p) = @{ $offset_polygon->polygons }; - my ($result) = Gpc2Polygons($tmp); - # now we've got $result, which is a Math::Geometry::Planar - # representing the inner surface including hole perimeters - - my $result_polylines = $result->polygons; - - ($contour_p, @holes_p) = @$result_polylines; push @{ $contours{$surface} }, $contour_p; push @{ $holes{$surface} }, @holes_p; - push @perimeters, $result; + push @perimeters, $offset_polygon; } } + + # create one more offset to be used as boundary for fill + push @{ $layer->fill_surfaces }, + map Slic3r::Surface->new_from_mgp($_), $self->offset_polygon($perimeters[-1]); } # generate paths for holes @@ -82,10 +70,42 @@ sub make_perimeter { # away from it to avoid the extruder to get two times there push @path_points, @$points, $points->[0]; } - push @{ $layer->perimeters }, Slic3r::Polyline->new_from_points(reverse @path_points); + push @{ $layer->perimeters }, Slic3r::ExtrusionPath->new_from_points(reverse @path_points); } } +sub offset_polygon { + my $self = shift; + my ($polygon) = @_; + + # $polygon holds a Math::Geometry::Planar object representing + # a polygon and its holes + my ($contour_p, @holes_p) = map $self->_mgp_from_points_ref($_), @{ $polygon->polygons }; + + # generate offsets + my $contour_offsets = $contour_p->offset_polygon($Slic3r::flow_width / $Slic3r::resolution); + my @hole_offsets = map @$_, map $_->offset_polygon(- $Slic3r::flow_width / $Slic3r::resolution), @holes_p; + + # now we subtract perimeter offsets from the contour offset polygon + # this will generate a single polygon with correct holes and also + # will take care of collisions between contour offset and holes + my @resulting_offsets = (); + foreach my $contour_points (@$contour_offsets) { + my $tmp = $self->_mgp_from_points_ref($contour_points)->convert2gpc; + foreach my $hole_points (@hole_offsets) { + $hole_points = $self->_mgp_from_points_ref($hole_points)->convert2gpc; + $tmp = GpcClip('DIFFERENCE', $tmp, $hole_points); + } + + my ($result) = Gpc2Polygons($tmp); + # now we've got $result, which is a Math::Geometry::Planar + # representing the inner surface including hole perimeters + push @resulting_offsets, $result; + } + + return @resulting_offsets; +} + sub _mgp_from_points_ref { my $self = shift; my ($points) = @_; diff --git a/lib/Slic3r/Polyline.pm b/lib/Slic3r/Polyline.pm index 27c1e543..592e5d31 100644 --- a/lib/Slic3r/Polyline.pm +++ b/lib/Slic3r/Polyline.pm @@ -40,7 +40,7 @@ sub new_from_points { : $_ } @points; - my $polyline = __PACKAGE__->new; + my $polyline = $class->new; my $previous_point; $previous_point = $points[-1] if $class eq 'Slic3r::Polyline::Closed'; foreach my $point (@points) { diff --git a/lib/Slic3r/Surface.pm b/lib/Slic3r/Surface.pm index d8ab0ddc..5333a7eb 100644 --- a/lib/Slic3r/Surface.pm +++ b/lib/Slic3r/Surface.pm @@ -42,6 +42,20 @@ sub BUILD { $_->hole_of($self) for @{ $self->holes }; } +sub new_from_mgp { + my $self = shift; + my ($polygon) = @_; + + my ($contour_p, @holes_p) = @{ $polygon->polygons }; + + return __PACKAGE__->new( + contour => Slic3r::Polyline::Closed->new_from_points(@$contour_p), + holes => [ + map Slic3r::Polyline::Closed->new_from_points(@$_), @holes_p + ], + ); +} + sub id { my $self = shift; return $self->contour->id;