diff options
author | bubnikv <bubnikv@gmail.com> | 2016-11-02 12:47:00 +0300 |
---|---|---|
committer | bubnikv <bubnikv@gmail.com> | 2016-11-02 12:47:00 +0300 |
commit | 95ede7c4b8cc40fe0fcf1960f25dfa9c66843b29 (patch) | |
tree | 609d320018e09d27f4b945915572d0fdf6e8c906 /lib | |
parent | 3a31d37d3574093565ed4fc8baa7f90428d9324e (diff) |
Rewrote Fill2.pm to C++, deleted Perl infills for good.
Removed dependency on Perl Math::PlanePath module.
Fixed compilation with Visual Studio and SLIC3R_DEBUG: Visual Studio older than 2015 does not support the prinf type specifier %zu. Use %Iu instead.
C++11 move semantics enabled.
Diffstat (limited to 'lib')
-rw-r--r-- | lib/Slic3r.pm | 4 | ||||
-rw-r--r-- | lib/Slic3r/Fill.pm | 308 | ||||
-rw-r--r-- | lib/Slic3r/Fill/3DHoneycomb.pm | 230 | ||||
-rw-r--r-- | lib/Slic3r/Fill/Base.pm | 101 | ||||
-rw-r--r-- | lib/Slic3r/Fill/Concentric.pm | 57 | ||||
-rw-r--r-- | lib/Slic3r/Fill/Honeycomb.pm | 129 | ||||
-rw-r--r-- | lib/Slic3r/Fill/PlanePath.pm | 118 | ||||
-rw-r--r-- | lib/Slic3r/Fill/Rectilinear.pm | 172 | ||||
-rw-r--r-- | lib/Slic3r/Fill2.pm | 294 | ||||
-rw-r--r-- | lib/Slic3r/Layer.pm | 11 | ||||
-rw-r--r-- | lib/Slic3r/Print/GCode.pm | 4 | ||||
-rw-r--r-- | lib/Slic3r/Print/Object.pm | 26 | ||||
-rw-r--r-- | lib/Slic3r/Print/SupportMaterial.pm | 9 |
13 files changed, 12 insertions, 1451 deletions
diff --git a/lib/Slic3r.pm b/lib/Slic3r.pm index b7c265c41..a4e1d07d8 100644 --- a/lib/Slic3r.pm +++ b/lib/Slic3r.pm @@ -56,8 +56,6 @@ use Slic3r::Config; use Slic3r::ExPolygon; use Slic3r::ExtrusionLoop; use Slic3r::ExtrusionPath; -use Slic3r::Fill; -use Slic3r::Fill2; use Slic3r::Flow; use Slic3r::Format::AMF; use Slic3r::Format::OBJ; @@ -139,7 +137,7 @@ sub spawn_thread { # Otherwise run the task on the current thread. # Used for # Slic3r::Print::Object->layers->make_perimeters : This is a pure C++ function. -# Slic3r::Print::Object->layers->make_fill : This requires a rewrite of Fill.pm to C++. +# Slic3r::Print::Object->layers->make_fill : This is a pure C++ function. # Slic3r::Print::SupportMaterial::generate_toolpaths sub parallelize { my %params = @_; diff --git a/lib/Slic3r/Fill.pm b/lib/Slic3r/Fill.pm deleted file mode 100644 index 4e500d275..000000000 --- a/lib/Slic3r/Fill.pm +++ /dev/null @@ -1,308 +0,0 @@ -package Slic3r::Fill; -use Moo; - -use List::Util qw(max); -use Slic3r::ExtrusionPath ':roles'; -use Slic3r::Fill::3DHoneycomb; -use Slic3r::Fill::Base; -use Slic3r::Fill::Concentric; -use Slic3r::Fill::Honeycomb; -use Slic3r::Fill::PlanePath; -use Slic3r::Fill::Rectilinear; -use Slic3r::Flow ':roles'; -use Slic3r::Geometry qw(X Y PI scale chained_path deg2rad); -use Slic3r::Geometry::Clipper qw(union union_ex diff diff_ex intersection_ex offset offset2); -use Slic3r::Surface ':types'; - - -has 'bounding_box' => (is => 'ro', required => 0); -has 'fillers' => (is => 'rw', default => sub { {} }); - -our %FillTypes = ( - archimedeanchords => 'Slic3r::Fill::ArchimedeanChords', - rectilinear => 'Slic3r::Fill::Rectilinear', - grid => 'Slic3r::Fill::Grid', - flowsnake => 'Slic3r::Fill::Flowsnake', - octagramspiral => 'Slic3r::Fill::OctagramSpiral', - hilbertcurve => 'Slic3r::Fill::HilbertCurve', - line => 'Slic3r::Fill::Line', - concentric => 'Slic3r::Fill::Concentric', - honeycomb => 'Slic3r::Fill::Honeycomb', - '3dhoneycomb' => 'Slic3r::Fill::3DHoneycomb', -); - -sub filler { - my $self = shift; - my ($filler) = @_; - - if (!ref $self) { - return $FillTypes{$filler}->new; - } - - $self->fillers->{$filler} ||= $FillTypes{$filler}->new( - bounding_box => $self->bounding_box, - ); - return $self->fillers->{$filler}; -} - -sub make_fill { - my $self = shift; - my ($layerm) = @_; - - Slic3r::debugf "Filling layer %d:\n", $layerm->layer->id; - - my $fill_density = $layerm->region->config->fill_density; - my $infill_flow = $layerm->flow(FLOW_ROLE_INFILL); - my $solid_infill_flow = $layerm->flow(FLOW_ROLE_SOLID_INFILL); - my $top_solid_infill_flow = $layerm->flow(FLOW_ROLE_TOP_SOLID_INFILL); - - my @surfaces = (); - - # merge adjacent surfaces - # in case of bridge surfaces, the ones with defined angle will be attached to the ones - # without any angle (shouldn't this logic be moved to process_external_surfaces()?) - { - my @surfaces_with_bridge_angle = grep { $_->bridge_angle >= 0 } @{$layerm->fill_surfaces}; - - # group surfaces by distinct properties - my @groups = @{$layerm->fill_surfaces->group}; - - # merge compatible groups (we can generate continuous infill for them) - { - # cache flow widths and patterns used for all solid groups - # (we'll use them for comparing compatible groups) - my @is_solid = my @fw = my @pattern = (); - for (my $i = 0; $i <= $#groups; $i++) { - # we can only merge solid non-bridge surfaces, so discard - # non-solid surfaces - if ($groups[$i][0]->is_solid && (!$groups[$i][0]->is_bridge || $layerm->layer->id == 0)) { - $is_solid[$i] = 1; - $fw[$i] = ($groups[$i][0]->surface_type == S_TYPE_TOP) - ? $top_solid_infill_flow->width - : $solid_infill_flow->width; - $pattern[$i] = $groups[$i][0]->is_external - ? $layerm->region->config->external_fill_pattern - : 'rectilinear'; - } else { - $is_solid[$i] = 0; - $fw[$i] = 0; - $pattern[$i] = 'none'; - } - } - - # loop through solid groups - for (my $i = 0; $i <= $#groups; $i++) { - next if !$is_solid[$i]; - - # find compatible groups and append them to this one - for (my $j = $i+1; $j <= $#groups; $j++) { - next if !$is_solid[$j]; - - if ($fw[$i] == $fw[$j] && $pattern[$i] eq $pattern[$j]) { - # groups are compatible, merge them - push @{$groups[$i]}, @{$groups[$j]}; - splice @groups, $j, 1; - splice @is_solid, $j, 1; - splice @fw, $j, 1; - splice @pattern, $j, 1; - } - } - } - } - - # give priority to bridges - @groups = sort { ($a->[0]->bridge_angle >= 0) ? -1 : 0 } @groups; - - foreach my $group (@groups) { - my $union_p = union([ map $_->p, @$group ], 1); - - # subtract surfaces having a defined bridge_angle from any other - if (@surfaces_with_bridge_angle && $group->[0]->bridge_angle < 0) { - $union_p = diff( - $union_p, - [ map $_->p, @surfaces_with_bridge_angle ], - 1, - ); - } - - # subtract any other surface already processed - my $union = diff_ex( - $union_p, - [ map $_->p, @surfaces ], - 1, - ); - - push @surfaces, map $group->[0]->clone(expolygon => $_), @$union; - } - } - - # we need to detect any narrow surfaces that might collapse - # when adding spacing below - # such narrow surfaces are often generated in sloping walls - # by bridge_over_infill() and combine_infill() as a result of the - # subtraction of the combinable area from the layer infill area, - # which leaves small areas near the perimeters - # we are going to grow such regions by overlapping them with the void (if any) - # TODO: detect and investigate whether there could be narrow regions without - # any void neighbors - { - my $distance_between_surfaces = max( - $infill_flow->scaled_spacing, - $solid_infill_flow->scaled_spacing, - $top_solid_infill_flow->scaled_spacing, - ); - my $collapsed = diff( - [ map @{$_->expolygon}, @surfaces ], - offset2([ map @{$_->expolygon}, @surfaces ], -$distance_between_surfaces/2, +$distance_between_surfaces/2), - 1, - ); - push @surfaces, map Slic3r::Surface->new( - expolygon => $_, - surface_type => S_TYPE_INTERNALSOLID, - ), @{intersection_ex( - offset($collapsed, $distance_between_surfaces), - [ - (map @{$_->expolygon}, grep $_->surface_type == S_TYPE_INTERNALVOID, @surfaces), - (@$collapsed), - ], - 1, - )}; - } - - if (0) { - require "Slic3r/SVG.pm"; - Slic3r::SVG::output("fill_" . $layerm->print_z . ".svg", - expolygons => [ map $_->expolygon, grep !$_->is_solid, @surfaces ], - red_expolygons => [ map $_->expolygon, grep $_->is_solid, @surfaces ], - ); - } - - my @fills = (); - SURFACE: foreach my $surface (@surfaces) { - next if $surface->surface_type == S_TYPE_INTERNALVOID; - my $filler = $layerm->region->config->fill_pattern; - my $density = $fill_density; - my $role = ($surface->surface_type == S_TYPE_TOP) ? FLOW_ROLE_TOP_SOLID_INFILL - : $surface->is_solid ? FLOW_ROLE_SOLID_INFILL - : FLOW_ROLE_INFILL; - my $is_bridge = $layerm->layer->id > 0 && $surface->is_bridge; - my $is_solid = $surface->is_solid; - - if ($surface->is_solid) { - $density = 100; - $filler = 'rectilinear'; - if ($surface->is_external && !$is_bridge) { - $filler = $layerm->region->config->external_fill_pattern; - } - } else { - next SURFACE unless $density > 0; - } - - # get filler object - my $f = $self->filler($filler); - - # calculate the actual flow we'll be using for this infill - my $h = $surface->thickness == -1 ? $layerm->layer->height : $surface->thickness; - my $flow = $layerm->region->flow( - $role, - $h, - $is_bridge || $f->use_bridge_flow, - $layerm->layer->id == 0, - -1, - $layerm->layer->object, - ); - - # calculate flow spacing for infill pattern generation - my $using_internal_flow = 0; - if (!$is_solid && !$is_bridge) { - # it's internal infill, so we can calculate a generic flow spacing - # for all layers, for avoiding the ugly effect of - # misaligned infill on first layer because of different extrusion width and - # layer height - my $internal_flow = $layerm->region->flow( - FLOW_ROLE_INFILL, - $layerm->layer->object->config->layer_height, # TODO: handle infill_every_layers? - 0, # no bridge - 0, # no first layer - -1, # auto width - $layerm->layer->object, - ); - $f->spacing($internal_flow->spacing); - $using_internal_flow = 1; -# } elsif ($surface->surface_type == S_TYPE_INTERNALBRIDGE) { -# # The internal bridging layer will be sparse. -# $f->spacing($flow->spacing * 2.); - } else { - $f->spacing($flow->spacing); - } - - my $old_spacing = $f->spacing; - - $f->layer_id($layerm->layer->id); - $f->z($layerm->layer->print_z); - $f->angle(deg2rad($layerm->region->config->fill_angle)); - $f->loop_clipping(scale($flow->nozzle_diameter) * &Slic3r::LOOP_CLIPPING_LENGTH_OVER_NOZZLE_DIAMETER); - - # apply half spacing using this flow's own spacing and generate infill - my @polylines = map $f->fill_surface( - $_, - density => $density/100, - layer_height => $h, -#FIXME Vojtech disabled the automatic extrusion width adjustment as this feature quite often -# generated extrusions with excessive widths. -# The goal of the automatic line width adjustment was to fill in a region without a gap, but because -# the filled regions are mostly not aligned with the fill direction, very likely -# the extrusion width adjustment causes more harm than good. - dont_adjust => 1, - ), @{ $surface->offset(-scale($f->spacing)/2) }; - - next unless @polylines; - - # calculate actual flow from spacing (which might have been adjusted by the infill - # pattern generator) - if ($using_internal_flow) { - # if we used the internal flow we're not doing a solid infill - # so we can safely ignore the slight variation that might have - # been applied to $f->flow_spacing - } else { - if (abs($old_spacing - $f->spacing) > 0.3 * $old_spacing) { - print "Infill: Extreme spacing adjustment, from: ", $old_spacing, " to: ", $f->spacing, "\n"; - } - $flow = Slic3r::Flow->new_from_spacing( - spacing => $f->spacing, - nozzle_diameter => $flow->nozzle_diameter, - layer_height => $h, - bridge => $is_bridge || $f->use_bridge_flow, - ); - } - my $mm3_per_mm = $flow->mm3_per_mm; - - # save into layer - { - my $role = $is_bridge ? EXTR_ROLE_BRIDGE - : $is_solid ? (($surface->surface_type == S_TYPE_TOP) ? EXTR_ROLE_TOPSOLIDFILL : EXTR_ROLE_SOLIDFILL) - : EXTR_ROLE_FILL; - - push @fills, my $collection = Slic3r::ExtrusionPath::Collection->new; - $collection->no_sort($f->no_sort); - $collection->append( - map Slic3r::ExtrusionPath->new( - polyline => $_, - role => $role, - mm3_per_mm => $mm3_per_mm, - width => $flow->width, - height => $flow->height, - ), @polylines, - ); - } - } - - # add thin fill regions - foreach my $thin_fill (@{$layerm->thin_fills}) { - push @fills, Slic3r::ExtrusionPath::Collection->new($thin_fill); - } - - return @fills; -} - -1; diff --git a/lib/Slic3r/Fill/3DHoneycomb.pm b/lib/Slic3r/Fill/3DHoneycomb.pm deleted file mode 100644 index 3bf7e547f..000000000 --- a/lib/Slic3r/Fill/3DHoneycomb.pm +++ /dev/null @@ -1,230 +0,0 @@ -package Slic3r::Fill::3DHoneycomb; -use Moo; - -extends 'Slic3r::Fill::Base'; - -use POSIX qw(ceil fmod); -use Slic3r::Geometry qw(scale scaled_epsilon); -use Slic3r::Geometry::Clipper qw(intersection_pl); - -# require bridge flow since most of this pattern hangs in air -sub use_bridge_flow { 1 } - -sub fill_surface { - my ($self, $surface, %params) = @_; - - my $expolygon = $surface->expolygon; - my $bb = $expolygon->bounding_box; - my $size = $bb->size; - - my $distance = scale($self->spacing) / $params{density}; - - # align bounding box to a multiple of our honeycomb grid module - # (a module is 2*$distance since one $distance half-module is - # growing while the other $distance half-module is shrinking) - { - my $min = $bb->min_point; - $min->translate( - -($bb->x_min % (2*$distance)), - -($bb->y_min % (2*$distance)), - ); - $bb->merge_point($min); - } - - # generate pattern - my @polylines = map Slic3r::Polyline->new(@$_), - makeGrid( - scale($self->z), - $distance, - ceil($size->x / $distance) + 1, - ceil($size->y / $distance) + 1, #// - (($self->layer_id / $surface->thickness_layers) % 2) + 1, - ); - - # move pattern in place - $_->translate($bb->x_min, $bb->y_min) for @polylines; - - # clip pattern to boundaries - @polylines = @{intersection_pl(\@polylines, \@$expolygon)}; - - # connect lines - unless ($params{dont_connect} || !@polylines) { # prevent calling leftmost_point() on empty collections - my ($expolygon_off) = @{$expolygon->offset_ex(scaled_epsilon)}; - my $collection = Slic3r::Polyline::Collection->new(@polylines); - @polylines = (); - foreach my $polyline (@{$collection->chained_path_from($collection->leftmost_point, 0)}) { - # try to append this polyline to previous one if any - if (@polylines) { - my $line = Slic3r::Line->new($polylines[-1]->last_point, $polyline->first_point); - if ($line->length <= 1.5*$distance && $expolygon_off->contains_line($line)) { - $polylines[-1]->append_polyline($polyline); - next; - } - } - - # make a clone before $collection goes out of scope - push @polylines, $polyline->clone; - } - } - - # TODO: return ExtrusionLoop objects to get better chained paths - return @polylines; -} - - -=head1 DESCRIPTION - -Creates a contiguous sequence of points at a specified height that make -up a horizontal slice of the edges of a space filling truncated -octahedron tesselation. The octahedrons are oriented so that the -square faces are in the horizontal plane with edges parallel to the X -and Y axes. - -Credits: David Eccles (gringer). - -=head2 makeGrid(z, gridSize, gridWidth, gridHeight, curveType) - -Generate a set of curves (array of array of 2d points) that describe a -horizontal slice of a truncated regular octahedron with a specified -grid square size. - -=cut - -sub makeGrid { - my ($z, $gridSize, $gridWidth, $gridHeight, $curveType) = @_; - my $scaleFactor = $gridSize; - my $normalisedZ = $z / $scaleFactor; - my @points = makeNormalisedGrid($normalisedZ, $gridWidth, $gridHeight, $curveType); - foreach my $lineRef (@points) { - foreach my $pointRef (@$lineRef) { - $pointRef->[0] *= $scaleFactor; - $pointRef->[1] *= $scaleFactor; - } - } - return @points; -} - -=head1 FUNCTIONS -=cut - -=head2 colinearPoints(offset, gridLength) - -Generate an array of points that are in the same direction as the -basic printing line (i.e. Y points for columns, X points for rows) - -Note: a negative offset only causes a change in the perpendicular -direction - -=cut - -sub colinearPoints { - my ($offset, $baseLocation, $gridLength) = @_; - - my @points = (); - push @points, $baseLocation - abs($offset/2); - for (my $i = 0; $i < $gridLength; $i++) { - push @points, $baseLocation + $i + abs($offset/2); - push @points, $baseLocation + ($i+1) - abs($offset/2); - } - push @points, $baseLocation + $gridLength + abs($offset/2); - return @points; -} - -=head2 colinearPoints(offset, baseLocation, gridLength) - -Generate an array of points for the dimension that is perpendicular to -the basic printing line (i.e. X points for columns, Y points for rows) - -=cut - -sub perpendPoints { - my ($offset, $baseLocation, $gridLength) = @_; - - my @points = (); - my $side = 2*(($baseLocation) % 2) - 1; - push @points, $baseLocation - $offset/2 * $side; - for (my $i = 0; $i < $gridLength; $i++) { - $side = 2*(($i+$baseLocation) % 2) - 1; - push @points, $baseLocation + $offset/2 * $side; - push @points, $baseLocation + $offset/2 * $side; - } - push @points, $baseLocation - $offset/2 * $side; - - return @points; -} - -=head2 trim(pointArrayRef, minX, minY, maxX, maxY) - -Trims an array of points to specified rectangular limits. Point -components that are outside these limits are set to the limits. - -=cut - -sub trim { - my ($pointArrayRef, $minX, $minY, $maxX, $maxY) = @_; - - foreach (@$pointArrayRef) { - $_->[0] = ($_->[0] < $minX) ? $minX : (($_->[0] > $maxX) ? $maxX : $_->[0]); - $_->[1] = ($_->[1] < $minY) ? $minY : (($_->[1] > $maxY) ? $maxY : $_->[1]); - } -} - -=head2 makeNormalisedGrid(z, gridWidth, gridHeight, curveType) - -Generate a set of curves (array of array of 2d points) that describe a -horizontal slice of a truncated regular octahedron with edge length 1. - -curveType specifies which lines to print, 1 for vertical lines -(columns), 2 for horizontal lines (rows), and 3 for both. - -=cut - -sub makeNormalisedGrid { - my ($z, $gridWidth, $gridHeight, $curveType) = @_; - - ## offset required to create a regular octagram - my $octagramGap = 0.5; - - # sawtooth wave function for range f($z) = [-$octagramGap .. $octagramGap] - my $a = sqrt(2); # period - my $wave = abs(fmod($z, $a) - $a/2)/$a*4 - 1; - my $offset = $wave * $octagramGap; - - my @points = (); - if (($curveType & 1) != 0) { - for (my $x = 0; $x <= $gridWidth; $x++) { - my @xPoints = perpendPoints($offset, $x, $gridHeight); - my @yPoints = colinearPoints($offset, 0, $gridHeight); - # This is essentially @newPoints = zip(@xPoints, @yPoints) - my @newPoints = map [ $xPoints[$_], $yPoints[$_] ], 0..$#xPoints; - - # trim points to grid edges - #trim(\@newPoints, 0, 0, $gridWidth, $gridHeight); - - if ($x % 2 == 0){ - push @points, [ @newPoints ]; - } else { - push @points, [ reverse @newPoints ]; - } - } - } - if (($curveType & 2) != 0) { - for (my $y = 0; $y <= $gridHeight; $y++) { - my @xPoints = colinearPoints($offset, 0, $gridWidth); - my @yPoints = perpendPoints($offset, $y, $gridWidth); - my @newPoints = map [ $xPoints[$_], $yPoints[$_] ], 0..$#xPoints; - - # trim points to grid edges - #trim(\@newPoints, 0, 0, $gridWidth, $gridHeight); - - if ($y % 2 == 0) { - push @points, [ @newPoints ]; - } else { - push @points, [ reverse @newPoints ]; - } - } - } - return @points; -} - -1; diff --git a/lib/Slic3r/Fill/Base.pm b/lib/Slic3r/Fill/Base.pm deleted file mode 100644 index 482594a31..000000000 --- a/lib/Slic3r/Fill/Base.pm +++ /dev/null @@ -1,101 +0,0 @@ -package Slic3r::Fill::Base; -use Moo; - -has 'layer_id' => (is => 'rw'); -has 'z' => (is => 'rw'); # in unscaled coordinates -has 'angle' => (is => 'rw'); # in radians, ccw, 0 = East -has 'spacing' => (is => 'rw'); # in unscaled coordinates -has 'loop_clipping' => (is => 'rw', default => sub { 0 }); # in scaled coordinates -has 'bounding_box' => (is => 'ro', required => 0); # Slic3r::Geometry::BoundingBox object - -sub set_spacing { - my ($self, $spacing) = @_; - $self->spacing($spacing); -} - -sub set_angle { - my ($self, $angle) = @_; - $self->angle($angle); -} - -sub adjust_solid_spacing { - my $self = shift; - my %params = @_; - - my $number_of_lines = int($params{width} / $params{distance}) + 1; - return $params{distance} if $number_of_lines <= 1; - - my $extra_space = $params{width} % $params{distance}; - return $params{distance} + $extra_space / ($number_of_lines - 1); -} - -sub no_sort { 0 } -sub use_bridge_flow { 0 } - - -package Slic3r::Fill::WithDirection; -use Moo::Role; - -use Slic3r::Geometry qw(PI rad2deg); - -sub angles () { [0, PI/2] } - -sub infill_direction { - my $self = shift; - my ($surface) = @_; - - if (!defined $self->angle) { - warn "Using undefined infill angle"; - $self->angle(0); - } - - # set infill angle - my (@rotate); - $rotate[0] = $self->angle; - $rotate[1] = $self->bounding_box - ? $self->bounding_box->center - : $surface->expolygon->bounding_box->center; - my $shift = $rotate[1]->clone; - - if (defined $self->layer_id) { - # alternate fill direction - my $layer_num = $self->layer_id / $surface->thickness_layers; - my $angle = $self->angles->[$layer_num % @{$self->angles}]; - $rotate[0] = $self->angle + $angle if $angle; - } - - # use bridge angle - if ($surface->bridge_angle >= 0) { - Slic3r::debugf "Filling bridge with angle %d\n", rad2deg($surface->bridge_angle); - $rotate[0] = $surface->bridge_angle; - } - - $rotate[0] += PI/2; - $shift->rotate(@rotate); - return [\@rotate, $shift]; -} - -# this method accepts any object that implements rotate() and translate() -sub rotate_points { - my $self = shift; - my ($expolygon, $rotate_vector) = @_; - - # rotate points - my ($rotate, $shift) = @$rotate_vector; - $rotate = [ -$rotate->[0], $rotate->[1] ]; - $expolygon->rotate(@$rotate); - $expolygon->translate(@$shift); -} - -sub rotate_points_back { - my $self = shift; - my ($paths, $rotate_vector) = @_; - - my ($rotate, $shift) = @$rotate_vector; - $shift = [ map -$_, @$shift ]; - - $_->translate(@$shift) for @$paths; - $_->rotate(@$rotate) for @$paths; -} - -1; diff --git a/lib/Slic3r/Fill/Concentric.pm b/lib/Slic3r/Fill/Concentric.pm deleted file mode 100644 index ca1837c4e..000000000 --- a/lib/Slic3r/Fill/Concentric.pm +++ /dev/null @@ -1,57 +0,0 @@ -package Slic3r::Fill::Concentric; -use Moo; - -extends 'Slic3r::Fill::Base'; - -use Slic3r::Geometry qw(scale unscale X); -use Slic3r::Geometry::Clipper qw(offset offset2 union_pt_chained); - -sub no_sort { 1 } - -sub fill_surface { - my $self = shift; - my ($surface, %params) = @_; - - # no rotation is supported for this infill pattern - - my $expolygon = $surface->expolygon; - my $bounding_box = $expolygon->bounding_box; - - my $min_spacing = scale($self->spacing); - my $distance = $min_spacing / $params{density}; - - if ($params{density} == 1 && !$params{dont_adjust}) { - $distance = $self->adjust_solid_spacing( - width => $bounding_box->size->[X], - distance => $distance, - ); - $self->spacing(unscale $distance); - } - - my @loops = my @last = map $_->clone, @$expolygon; - while (@last) { - push @loops, @last = @{offset2(\@last, -($distance + 0.5*$min_spacing), +0.5*$min_spacing)}; - } - - # generate paths from the outermost to the innermost, to avoid - # adhesion problems of the first central tiny loops - @loops = map Slic3r::Polygon->new(@$_), - reverse @{union_pt_chained(\@loops)}; - - # split paths using a nearest neighbor search - my @paths = (); - my $last_pos = Slic3r::Point->new(0,0); - foreach my $loop (@loops) { - push @paths, $loop->split_at_index($last_pos->nearest_point_index(\@$loop)); - $last_pos = $paths[-1]->last_point; - } - - # clip the paths to prevent the extruder from getting exactly on the first point of the loop - $_->clip_end($self->loop_clipping) for @paths; - @paths = grep $_->is_valid, @paths; # remove empty paths (too short, thus eaten by clipping) - - # TODO: return ExtrusionLoop objects to get better chained paths - return @paths; -} - -1; diff --git a/lib/Slic3r/Fill/Honeycomb.pm b/lib/Slic3r/Fill/Honeycomb.pm deleted file mode 100644 index b0fbd65ff..000000000 --- a/lib/Slic3r/Fill/Honeycomb.pm +++ /dev/null @@ -1,129 +0,0 @@ -package Slic3r::Fill::Honeycomb; -use Moo; - -extends 'Slic3r::Fill::Base'; -with qw(Slic3r::Fill::WithDirection); - -has 'cache' => (is => 'rw', default => sub {{}}); - -use Slic3r::Geometry qw(PI X Y MIN MAX scale scaled_epsilon); -use Slic3r::Geometry::Clipper qw(intersection intersection_pl); - -sub angles () { [0, PI/3, PI/3*2] } - -sub fill_surface { - my $self = shift; - my ($surface, %params) = @_; - - my $rotate_vector = $self->infill_direction($surface); - - # cache hexagons math - my $cache_id = sprintf "d%s_s%s", $params{density}, $self->spacing; - my $m; - if (!($m = $self->cache->{$cache_id})) { - $m = $self->cache->{$cache_id} = {}; - my $min_spacing = scale($self->spacing); - $m->{distance} = $min_spacing / $params{density}; - $m->{hex_side} = $m->{distance} / (sqrt(3)/2); - $m->{hex_width} = $m->{distance} * 2; # $m->{hex_width} == $m->{hex_side} * sqrt(3); - my $hex_height = $m->{hex_side} * 2; - $m->{pattern_height} = $hex_height + $m->{hex_side}; - $m->{y_short} = $m->{distance} * sqrt(3)/3; - $m->{x_offset} = $min_spacing / 2; - $m->{y_offset} = $m->{x_offset} * sqrt(3)/3; - $m->{hex_center} = Slic3r::Point->new($m->{hex_width}/2, $m->{hex_side}); - } - - my @polygons = (); - { - # adjust actual bounding box to the nearest multiple of our hex pattern - # and align it so that it matches across layers - - my $bounding_box = $surface->expolygon->bounding_box; - { - # rotate bounding box according to infill direction - my $bb_polygon = $bounding_box->polygon; - $bb_polygon->rotate($rotate_vector->[0][0], $m->{hex_center}); - $bounding_box = $bb_polygon->bounding_box; - - # extend bounding box so that our pattern will be aligned with other layers - # $bounding_box->[X1] and [Y1] represent the displacement between new bounding box offset and old one - $bounding_box->merge_point(Slic3r::Point->new( - $bounding_box->x_min - ($bounding_box->x_min % $m->{hex_width}), - $bounding_box->y_min - ($bounding_box->y_min % $m->{pattern_height}), - )); - } - - my $x = $bounding_box->x_min; - while ($x <= $bounding_box->x_max) { - my $p = []; - - my @x = ($x + $m->{x_offset}, $x + $m->{distance} - $m->{x_offset}); - for (1..2) { - @$p = reverse @$p; # turn first half upside down - my @p = (); - for (my $y = $bounding_box->y_min; $y <= $bounding_box->y_max; $y += $m->{y_short} + $m->{hex_side} + $m->{y_short} + $m->{hex_side}) { - push @$p, - [ $x[1], $y + $m->{y_offset} ], - [ $x[0], $y + $m->{y_short} - $m->{y_offset} ], - [ $x[0], $y + $m->{y_short} + $m->{hex_side} + $m->{y_offset} ], - [ $x[1], $y + $m->{y_short} + $m->{hex_side} + $m->{y_short} - $m->{y_offset} ], - [ $x[1], $y + $m->{y_short} + $m->{hex_side} + $m->{y_short} + $m->{hex_side} + $m->{y_offset} ]; - } - @x = map $_ + $m->{distance}, reverse @x; # draw symmetrical pattern - $x += $m->{distance}; - } - - push @polygons, Slic3r::Polygon->new(@$p); - } - - $_->rotate(-$rotate_vector->[0][0], $m->{hex_center}) for @polygons; - } - - my @paths; - if ($params{complete} || 1) { - # we were requested to complete each loop; - # in this case we don't try to make more continuous paths - @paths = map $_->split_at_first_point, - @{intersection([ $surface->p ], \@polygons)}; - - } else { - # consider polygons as polylines without re-appending the initial point: - # this cuts the last segment on purpose, so that the jump to the next - # path is more straight - @paths = @{intersection_pl( - [ map Slic3r::Polyline->new(@$_), @polygons ], - [ @{$surface->expolygon} ], - )}; - - # connect paths - if (@paths) { # prevent calling leftmost_point() on empty collections - my $collection = Slic3r::Polyline::Collection->new(@paths); - @paths = (); - foreach my $path (@{$collection->chained_path_from($collection->leftmost_point, 0)}) { - if (@paths) { - # distance between first point of this path and last point of last path - my $distance = $paths[-1]->last_point->distance_to($path->first_point); - - if ($distance <= $m->{hex_width}) { - $paths[-1]->append_polyline($path); - next; - } - } - - # make a clone before $collection goes out of scope - push @paths, $path->clone; - } - } - - # clip paths again to prevent connection segments from crossing the expolygon boundaries - @paths = @{intersection_pl( - \@paths, - [ map @$_, @{$surface->expolygon->offset_ex(scaled_epsilon)} ], - )}; - } - - return @paths; -} - -1; diff --git a/lib/Slic3r/Fill/PlanePath.pm b/lib/Slic3r/Fill/PlanePath.pm deleted file mode 100644 index 556835ec4..000000000 --- a/lib/Slic3r/Fill/PlanePath.pm +++ /dev/null @@ -1,118 +0,0 @@ -package Slic3r::Fill::PlanePath; -use Moo; - -extends 'Slic3r::Fill::Base'; -with qw(Slic3r::Fill::WithDirection); - -use Slic3r::Geometry qw(scale X1 Y1 X2 Y2); -use Slic3r::Geometry::Clipper qw(intersection_pl); - -sub angles () { [0] } -sub multiplier () { 1 } - -sub process_polyline {} - -sub fill_surface { - my $self = shift; - my ($surface, %params) = @_; - - # rotate polygons - my $expolygon = $surface->expolygon->clone; - my $rotate_vector = $self->infill_direction($surface); - $self->rotate_points($expolygon, $rotate_vector); - - my $distance_between_lines = scale($self->spacing) / $params{density} * $self->multiplier; - - # align infill across layers using the object's bounding box - my $bb_polygon = $self->bounding_box->polygon; - $self->rotate_points($bb_polygon, $rotate_vector); - my $bounding_box = $bb_polygon->bounding_box; - - (ref $self) =~ /::([^:]+)$/; - my $path = "Math::PlanePath::$1"->new; - - my $translate = Slic3r::Point->new(0,0); # vector - if ($path->x_negative || $path->y_negative) { - # if the curve extends on both positive and negative coordinate space, - # center our expolygon around origin - $translate = $bounding_box->center->negative; - } else { - # if the curve does not extend in negative coordinate space, - # move expolygon entirely in positive coordinate space - $translate = $bounding_box->min_point->negative; - } - $expolygon->translate(@$translate); - $bounding_box->translate(@$translate); - - my ($n_lo, $n_hi) = $path->rect_to_n_range( - map { $_ / $distance_between_lines } - @{$bounding_box->min_point}, - @{$bounding_box->max_point}, - ); - - my $polyline = Slic3r::Polyline->new( - map [ map { $_ * $distance_between_lines } $path->n_to_xy($_) ], ($n_lo..$n_hi) - ); - return {} if @$polyline <= 1; - - $self->process_polyline($polyline, $bounding_box); - - my @paths = @{intersection_pl([$polyline], \@$expolygon)}; - - if (0) { - require "Slic3r/SVG.pm"; - Slic3r::SVG::output("fill.svg", - no_arrows => 1, - polygons => \@$expolygon, - green_polygons => [ $bounding_box->polygon ], - polylines => [ $polyline ], - red_polylines => \@paths, - ); - } - - # paths must be repositioned and rotated back - $_->translate(@{$translate->negative}) for @paths; - $self->rotate_points_back(\@paths, $rotate_vector); - - return @paths; -} - - -package Slic3r::Fill::ArchimedeanChords; -use Moo; -extends 'Slic3r::Fill::PlanePath'; -use Math::PlanePath::ArchimedeanChords; - - -package Slic3r::Fill::Flowsnake; -use Moo; -extends 'Slic3r::Fill::PlanePath'; -use Math::PlanePath::Flowsnake; -use Slic3r::Geometry qw(X); - -# Sorry, this fill is currently broken. - -sub process_polyline { - my $self = shift; - my ($polyline, $bounding_box) = @_; - - $_->[X] += $bounding_box->center->[X] for @$polyline; -} - - -package Slic3r::Fill::HilbertCurve; -use Moo; -extends 'Slic3r::Fill::PlanePath'; -use Math::PlanePath::HilbertCurve; - - -package Slic3r::Fill::OctagramSpiral; -use Moo; -extends 'Slic3r::Fill::PlanePath'; -use Math::PlanePath::OctagramSpiral; - -sub multiplier () { sqrt(2) } - - - -1; diff --git a/lib/Slic3r/Fill/Rectilinear.pm b/lib/Slic3r/Fill/Rectilinear.pm deleted file mode 100644 index 780b76291..000000000 --- a/lib/Slic3r/Fill/Rectilinear.pm +++ /dev/null @@ -1,172 +0,0 @@ -package Slic3r::Fill::Rectilinear; -use Moo; - -extends 'Slic3r::Fill::Base'; -with qw(Slic3r::Fill::WithDirection); - -has '_min_spacing' => (is => 'rw'); -has '_line_spacing' => (is => 'rw'); -has '_diagonal_distance' => (is => 'rw'); -has '_line_oscillation' => (is => 'rw'); - -use Slic3r::Geometry qw(scale unscale scaled_epsilon); -use Slic3r::Geometry::Clipper qw(intersection_pl); - -sub horizontal_lines { 0 } - -sub fill_surface { - my $self = shift; - my ($surface, %params) = @_; - - # rotate polygons so that we can work with vertical lines here - my $expolygon = $surface->expolygon->clone; - my $rotate_vector = $self->infill_direction($surface); - $self->rotate_points($expolygon, $rotate_vector); - - $self->_min_spacing(scale $self->spacing); - $self->_line_spacing($self->_min_spacing / $params{density}); - $self->_diagonal_distance($self->_line_spacing * 2); - $self->_line_oscillation($self->_line_spacing - $self->_min_spacing); # only for Line infill - my $bounding_box = $expolygon->bounding_box; - - # define flow spacing according to requested density - if ($params{density} == 1 && !$params{dont_adjust}) { - my $old_spacing = $self->spacing; - $self->_line_spacing($self->adjust_solid_spacing( - width => $bounding_box->size->x, - distance => $self->_line_spacing, - )); - $self->spacing(unscale $self->_line_spacing); - if (abs($old_spacing - $self->spacing) > 0.3 * $old_spacing) { - print "Infill2: Extreme spacing adjustment, from: ", $old_spacing, " to: ", $self->spacing, "\n"; - } - } else { - # extend bounding box so that our pattern will be aligned with other layers - $bounding_box->merge_point(Slic3r::Point->new( - $bounding_box->x_min - ($bounding_box->x_min % $self->_line_spacing), - $bounding_box->y_min - ($bounding_box->y_min % $self->_line_spacing), - )); - } - - # generate the basic pattern - my $x_max = $bounding_box->x_max + scaled_epsilon; - my @lines = (); - for (my $x = $bounding_box->x_min; $x <= $x_max; $x += $self->_line_spacing) { - push @lines, $self->_line($#lines, $x, $bounding_box->y_min, $bounding_box->y_max); - } - if ($self->horizontal_lines) { - my $y_max = $bounding_box->y_max + scaled_epsilon; - for (my $y = $bounding_box->y_min; $y <= $y_max; $y += $self->_line_spacing) { - push @lines, Slic3r::Polyline->new( - [$bounding_box->x_min, $y], - [$bounding_box->x_max, $y], - ); - } - } - - # clip paths against a slightly larger expolygon, so that the first and last paths - # are kept even if the expolygon has vertical sides - # the minimum offset for preventing edge lines from being clipped is scaled_epsilon; - # however we use a larger offset to support expolygons with slightly skewed sides and - # not perfectly straight - my @polylines = @{intersection_pl(\@lines, $expolygon->offset(+scale 0.02))}; - - my $extra = $self->_min_spacing * &Slic3r::INFILL_OVERLAP_OVER_SPACING; - foreach my $polyline (@polylines) { - my ($first_point, $last_point) = @$polyline[0,-1]; - if ($first_point->y > $last_point->y) { #> - ($first_point, $last_point) = ($last_point, $first_point); - } - $first_point->set_y($first_point->y - $extra); #-- - $last_point->set_y($last_point->y + $extra); #++ - } - - # connect lines - unless ($params{dont_connect} || !@polylines) { # prevent calling leftmost_point() on empty collections - # offset the expolygon by max(min_spacing/2, extra) - my ($expolygon_off) = @{$expolygon->offset_ex($self->_min_spacing/2)}; - my $collection = Slic3r::Polyline::Collection->new(@polylines); - @polylines = (); - - foreach my $polyline (@{$collection->chained_path_from($collection->leftmost_point, 0)}) { - if (@polylines) { - my $first_point = $polyline->first_point; - my $last_point = $polylines[-1]->last_point; - my @distance = map abs($first_point->$_ - $last_point->$_), qw(x y); - - # TODO: we should also check that both points are on a fill_boundary to avoid - # connecting paths on the boundaries of internal regions - if ($self->_can_connect(@distance) && $expolygon_off->contains_line(Slic3r::Line->new($last_point, $first_point))) { - $polylines[-1]->append_polyline($polyline); - next; - } - } - - # make a clone before $collection goes out of scope - push @polylines, $polyline->clone; - } - } - - # paths must be rotated back - $self->rotate_points_back(\@polylines, $rotate_vector); - - return @polylines; -} - -sub _line { - my ($self, $i, $x, $y_min, $y_max) = @_; - - return Slic3r::Polyline->new( - [$x, $y_min], - [$x, $y_max], - ); -} - -sub _can_connect { - my ($self, $dist_X, $dist_Y) = @_; - - return $dist_X <= $self->_diagonal_distance - && $dist_Y <= $self->_diagonal_distance; -} - - -package Slic3r::Fill::Line; -use Moo; -extends 'Slic3r::Fill::Rectilinear'; - -use Slic3r::Geometry qw(scaled_epsilon); - -sub _line { - my ($self, $i, $x, $y_min, $y_max) = @_; - - if ($i % 2) { - return Slic3r::Polyline->new( - [$x - $self->_line_oscillation, $y_min], - [$x + $self->_line_oscillation, $y_max], - ); - } else { - return Slic3r::Polyline->new( - [$x, $y_min], - [$x, $y_max], - ); - } -} - -sub _can_connect { - my ($self, $dist_X, $dist_Y) = @_; - - my $TOLERANCE = 10 * scaled_epsilon; - return ($dist_X >= ($self->_line_spacing - $self->_line_oscillation) - $TOLERANCE) - && ($dist_X <= ($self->_line_spacing + $self->_line_oscillation) + $TOLERANCE) - && $dist_Y <= $self->_diagonal_distance; -} - - -package Slic3r::Fill::Grid; -use Moo; -extends 'Slic3r::Fill::Rectilinear'; - -sub angles () { [0] } -sub horizontal_lines { 1 } - -1; diff --git a/lib/Slic3r/Fill2.pm b/lib/Slic3r/Fill2.pm deleted file mode 100644 index 940e47b06..000000000 --- a/lib/Slic3r/Fill2.pm +++ /dev/null @@ -1,294 +0,0 @@ -# This is derived from Fill.pm -# and it uses the C++ fillers. -package Slic3r::Fill2; -use Moo; - -use List::Util qw(max); -use Slic3r::ExtrusionPath ':roles'; - -use Slic3r::Flow ':roles'; -use Slic3r::Geometry qw(X Y PI scale chained_path deg2rad); -use Slic3r::Geometry::Clipper qw(union union_ex diff diff_ex intersection_ex offset offset2); -use Slic3r::Surface ':types'; - -has 'bounding_box' => (is => 'ro', required => 0); -has 'fillers' => (is => 'rw', default => sub { {} }); - -sub filler { - my $self = shift; - my ($filler) = @_; - - if (!ref $self) { - return Slic3r::Filler->new_from_type($filler); - } - - #print "Filler: ", $filler, "\n"; - $self->fillers->{$filler} ||= Slic3r::Filler->new_from_type($filler); - $self->fillers->{$filler}->set_bounding_box($self->bounding_box); - return $self->fillers->{$filler}; -} - - -# Generate infills for Slic3r::Layer::Region. -# The Slic3r::Layer::Region at this point of time may contain -# surfaces of various types (internal/bridge/top/bottom/solid). -# The infills are generated on the groups of surfaces with a compatible type. -# Returns an array of Slic3r::ExtrusionPath::Collection objects containing the infills generaed now -# and the thin fills generated by generate_perimeters(). -sub make_fill { - my $self = shift; - # of type - C++: LayerRegion, Perl: Slic3r::Layer::Region - my ($layerm) = @_; - - Slic3r::debugf "Filling layer %d:\n", $layerm->layer->id; - - my $fill_density = $layerm->region->config->fill_density; - my $infill_flow = $layerm->flow(FLOW_ROLE_INFILL); - my $solid_infill_flow = $layerm->flow(FLOW_ROLE_SOLID_INFILL); - my $top_solid_infill_flow = $layerm->flow(FLOW_ROLE_TOP_SOLID_INFILL); - - # Surfaces are of the type Slic3r::Surface - my @surfaces = (); - - # merge adjacent surfaces - # in case of bridge surfaces, the ones with defined angle will be attached to the ones - # without any angle (shouldn't this logic be moved to process_external_surfaces()?) - { - my @surfaces_with_bridge_angle = grep { $_->bridge_angle >= 0 } @{$layerm->fill_surfaces}; - - # group surfaces by distinct properties - # group is of type Slic3r::SurfaceCollection - my @groups = @{$layerm->fill_surfaces->group}; - - # merge compatible groups (we can generate continuous infill for them) - { - # cache flow widths and patterns used for all solid groups - # (we'll use them for comparing compatible groups) - my @is_solid = my @fw = my @pattern = (); - for (my $i = 0; $i <= $#groups; $i++) { - # we can only merge solid non-bridge surfaces, so discard - # non-solid surfaces - if ($groups[$i][0]->is_solid && (!$groups[$i][0]->is_bridge || $layerm->layer->id == 0)) { - $is_solid[$i] = 1; - $fw[$i] = ($groups[$i][0]->surface_type == S_TYPE_TOP) - ? $top_solid_infill_flow->width - : $solid_infill_flow->width; - $pattern[$i] = $groups[$i][0]->is_external - ? $layerm->region->config->external_fill_pattern - : 'rectilinear'; - } else { - $is_solid[$i] = 0; - $fw[$i] = 0; - $pattern[$i] = 'none'; - } - } - - # loop through solid groups - for (my $i = 0; $i <= $#groups; $i++) { - next if !$is_solid[$i]; - - # find compatible groups and append them to this one - for (my $j = $i+1; $j <= $#groups; $j++) { - next if !$is_solid[$j]; - - if ($fw[$i] == $fw[$j] && $pattern[$i] eq $pattern[$j]) { - # groups are compatible, merge them - push @{$groups[$i]}, @{$groups[$j]}; - splice @groups, $j, 1; - splice @is_solid, $j, 1; - splice @fw, $j, 1; - splice @pattern, $j, 1; - } - } - } - } - - # give priority to bridges - @groups = sort { ($a->[0]->bridge_angle >= 0) ? -1 : 0 } @groups; - - foreach my $group (@groups) { - # Make a union of polygons defining the infiill regions of a group, use a safety offset. - my $union_p = union([ map $_->p, @$group ], 1); - - # Subtract surfaces having a defined bridge_angle from any other, use a safety offset. - if (@surfaces_with_bridge_angle && $group->[0]->bridge_angle < 0) { - $union_p = diff( - $union_p, - [ map $_->p, @surfaces_with_bridge_angle ], - 1, - ); - } - - # subtract any other surface already processed - #FIXME Vojtech: Because the bridge surfaces came first, they are subtracted twice! - my $union = diff_ex( - $union_p, - [ map $_->p, @surfaces ], - 1, - ); - - push @surfaces, map $group->[0]->clone(expolygon => $_), @$union; - } - } - - # we need to detect any narrow surfaces that might collapse - # when adding spacing below - # such narrow surfaces are often generated in sloping walls - # by bridge_over_infill() and combine_infill() as a result of the - # subtraction of the combinable area from the layer infill area, - # which leaves small areas near the perimeters - # we are going to grow such regions by overlapping them with the void (if any) - # TODO: detect and investigate whether there could be narrow regions without - # any void neighbors - { - my $distance_between_surfaces = max( - $infill_flow->scaled_spacing, - $solid_infill_flow->scaled_spacing, - $top_solid_infill_flow->scaled_spacing, - ); - my $collapsed = diff( - [ map @{$_->expolygon}, @surfaces ], - offset2([ map @{$_->expolygon}, @surfaces ], -$distance_between_surfaces/2, +$distance_between_surfaces/2), - 1, - ); - push @surfaces, map Slic3r::Surface->new( - expolygon => $_, - surface_type => S_TYPE_INTERNALSOLID, - ), @{intersection_ex( - offset($collapsed, $distance_between_surfaces), - [ - (map @{$_->expolygon}, grep $_->surface_type == S_TYPE_INTERNALVOID, @surfaces), - (@$collapsed), - ], - 1, - )}; - } - - if (0) { - require "Slic3r/SVG.pm"; - Slic3r::SVG::output("fill_" . $layerm->print_z . ".svg", - expolygons => [ map $_->expolygon, grep !$_->is_solid, @surfaces ], - red_expolygons => [ map $_->expolygon, grep $_->is_solid, @surfaces ], - ); - } - - # Fills are of perl type Slic3r::ExtrusionPath::Collection, c++ type ExtrusionEntityCollection - my @fills = (); - SURFACE: foreach my $surface (@surfaces) { - next if $surface->surface_type == S_TYPE_INTERNALVOID; - my $filler = $layerm->region->config->fill_pattern; - my $density = $fill_density; - my $role = ($surface->surface_type == S_TYPE_TOP) ? FLOW_ROLE_TOP_SOLID_INFILL - : $surface->is_solid ? FLOW_ROLE_SOLID_INFILL - : FLOW_ROLE_INFILL; - my $is_bridge = $layerm->layer->id > 0 && $surface->is_bridge; - my $is_solid = $surface->is_solid; - - if ($surface->is_solid) { - $density = 100; - $filler = 'rectilinear'; - if ($surface->is_external && !$is_bridge) { - $filler = $layerm->region->config->external_fill_pattern; - } - } else { - next SURFACE unless $density > 0; - } - - # get filler object - my $f = $self->filler($filler); - - # calculate the actual flow we'll be using for this infill - my $h = $surface->thickness == -1 ? $layerm->layer->height : $surface->thickness; - my $flow = $layerm->region->flow( - $role, - $h, - $is_bridge || $f->use_bridge_flow, - $layerm->layer->id == 0, - -1, - $layerm->layer->object, - ); - - # calculate flow spacing for infill pattern generation - my $using_internal_flow = 0; - if (!$is_solid && !$is_bridge) { - # it's internal infill, so we can calculate a generic flow spacing - # for all layers, for avoiding the ugly effect of - # misaligned infill on first layer because of different extrusion width and - # layer height - my $internal_flow = $layerm->region->flow( - FLOW_ROLE_INFILL, - $layerm->layer->object->config->layer_height, # TODO: handle infill_every_layers? - 0, # no bridge - 0, # no first layer - -1, # auto width - $layerm->layer->object, - ); - $f->set_spacing($internal_flow->spacing); - $using_internal_flow = 1; - } else { - $f->set_spacing($flow->spacing); - } - - $f->set_layer_id($layerm->layer->id); - $f->set_z($layerm->layer->print_z); - $f->set_angle(deg2rad($layerm->region->config->fill_angle)); - $f->set_loop_clipping(scale($flow->nozzle_diameter) * &Slic3r::LOOP_CLIPPING_LENGTH_OVER_NOZZLE_DIAMETER); - - # apply half spacing using this flow's own spacing and generate infill - my @polylines = $f->fill_surface( - $surface, - density => $density/100, - layer_height => $h, - ); - next unless @polylines; - - - # calculate actual flow from spacing (which might have been adjusted by the infill - # pattern generator) - if ($using_internal_flow) { - # if we used the internal flow we're not doing a solid infill - # so we can safely ignore the slight variation that might have - # been applied to $f->flow_spacing - } else { - $flow = Slic3r::Flow->new_from_spacing( - spacing => $f->spacing, - nozzle_diameter => $flow->nozzle_diameter, - layer_height => $h, - bridge => $is_bridge || $f->use_bridge_flow, - ); - } - - # save into layer - { - my $role = $is_bridge ? EXTR_ROLE_BRIDGE - : $is_solid ? (($surface->surface_type == S_TYPE_TOP) ? EXTR_ROLE_TOPSOLIDFILL : EXTR_ROLE_SOLIDFILL) - : EXTR_ROLE_FILL; - - push @fills, my $collection = Slic3r::ExtrusionPath::Collection->new; - # Only concentric fills are not sorted. - $collection->no_sort($f->no_sort); - $collection->append( - map Slic3r::ExtrusionPath->new( - polyline => $_, - role => $role, - mm3_per_mm => $flow->mm3_per_mm, - width => $flow->width, - height => $flow->height, - ), map @$_, @polylines, - ); - } - } - - # add thin fill regions - # thin_fills are of C++ Slic3r::ExtrusionEntityCollection, perl type Slic3r::ExtrusionPath::Collection - # Unpacks the collection, creates multiple collections per path. - # The path type could be ExtrusionPath, ExtrusionLoop or ExtrusionEntityCollection. - # Why the paths are unpacked? - foreach my $thin_fill (@{$layerm->thin_fills}) { - push @fills, Slic3r::ExtrusionPath::Collection->new($thin_fill); - } - - return @fills; -} - -1; diff --git a/lib/Slic3r/Layer.pm b/lib/Slic3r/Layer.pm index f1a3d7a57..4bff9b61f 100644 --- a/lib/Slic3r/Layer.pm +++ b/lib/Slic3r/Layer.pm @@ -31,17 +31,6 @@ sub regions { return [ map $self->get_region($_), 0..($self->region_count-1) ]; } -sub make_fill { - my ($self) = @_; - - foreach my $layerm (@{$self->regions}) { - $layerm->fills->clear; - # Fearlessly enable the C++ fillers. - $layerm->fills->append($_) for $self->object->fill_maker2->make_fill($layerm); -# $layerm->fills->append($_) for $self->object->fill_maker->make_fill($layerm); - } -} - package Slic3r::Layer::Support; our @ISA = qw(Slic3r::Layer); diff --git a/lib/Slic3r/Print/GCode.pm b/lib/Slic3r/Print/GCode.pm index d837a4637..d1b0009ad 100644 --- a/lib/Slic3r/Print/GCode.pm +++ b/lib/Slic3r/Print/GCode.pm @@ -544,8 +544,8 @@ sub process_layer { } # process infill - # $layerm->fills is a collection of ExtrusionPath::Collection objects, each one containing - # the ExtrusionPath objects of a certain infill "group" (also called "surface" + # $layerm->fills is a collection of Slic3r::ExtrusionPath::Collection objects (C++ class ExtrusionEntityCollection), + # each one containing the ExtrusionPath objects of a certain infill "group" (also called "surface" # throughout the code). We can redefine the order of such Collections but we have to # do each one completely at once. foreach my $fill (@{$layerm->fills}) { diff --git a/lib/Slic3r/Print/Object.pm b/lib/Slic3r/Print/Object.pm index 5ca29789c..791731543 100644 --- a/lib/Slic3r/Print/Object.pm +++ b/lib/Slic3r/Print/Object.pm @@ -14,19 +14,6 @@ use Slic3r::Surface ':types'; # If enabled, phases of prepare_infill will be written into SVG files to an "out" directory. our $SLIC3R_DEBUG_SLICE_PROCESSING = 0; -# TODO: lazy -sub fill_maker { - my $self = shift; - return Slic3r::Fill->new(bounding_box => $self->bounding_box); -} - -# Vojtech's implementation: Create the C++ filler. -# TODO: lazy -sub fill_maker2 { - my $self = shift; - return Slic3r::Fill2->new(bounding_box => $self->bounding_box); -} - sub region_volumes { my $self = shift; return [ map $self->get_region_volumes($_), 0..($self->region_count - 1) ]; @@ -617,12 +604,12 @@ sub infill { thread_cb => sub { my $q = shift; while (defined (my $i = $q->dequeue)) { - $self->get_layer($i)->make_fill; + $self->get_layer($i)->make_fills; } }, no_threads_cb => sub { foreach my $layer (@{$self->layers}) { - $layer->make_fill; + $layer->make_fills; } }, ); @@ -678,14 +665,7 @@ sub _support_material { ); } else { # New supports, C++ implementation. - return Slic3r::Print::SupportMaterial2->new( - print_config => $self->print->config, - object_config => $self->config, - first_layer_flow => $first_layer_flow, - flow => $self->support_material_flow, - interface_flow => $self->support_material_flow(FLOW_ROLE_SUPPORT_MATERIAL_INTERFACE), - soluble_interface => ($self->config->support_material_contact_distance == 0), - ); + return Slic3r::Print::SupportMaterial2->new($self); } } diff --git a/lib/Slic3r/Print/SupportMaterial.pm b/lib/Slic3r/Print/SupportMaterial.pm index 875c5af1d..9dbfe4003 100644 --- a/lib/Slic3r/Print/SupportMaterial.pm +++ b/lib/Slic3r/Print/SupportMaterial.pm @@ -761,10 +761,13 @@ sub generate_toolpaths { # Allocate the fillers exclusively in the worker threads! Don't allocate them at the main thread, # as Perl copies the C++ pointers by default, so then the C++ objects are shared between threads! my %fillers = ( - interface => $object->fill_maker2->filler('rectilinear'), - support => $object->fill_maker2->filler($pattern), + interface => Slic3r::Filler->new_from_type('rectilinear'), + support => Slic3r::Filler->new_from_type($pattern), ); - + my $bounding_box = $object->bounding_box; + $fillers{interface}->set_bounding_box($object->bounding_box); + $fillers{support}->set_bounding_box($object->bounding_box); + # interface and contact infill if (@$interface || @$contact_infill) { $fillers{interface}->set_angle($interface_angle); |