package Slic3r::Fill::Concentric; use Moo; extends 'Slic3r::Fill::Base'; use Slic3r::ExtrusionPath ':roles'; use Slic3r::Geometry qw(scale unscale X1 Y1 X2 Y2); 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 $params{flow_spacing}; my $distance = $min_spacing / $params{density}; my $flow_spacing = $params{flow_spacing}; if ($params{density} == 1) { $distance = $self->adjust_solid_spacing( width => $bounding_box->[X2] - $bounding_box->[X1], distance => $distance, ); $flow_spacing = unscale $distance; } my @contour_loops = (); my @hole_loops = (); my @last_offsets = ($expolygon->offset_ex($distance)); while (@last_offsets) { my @new_offsets = (); foreach my $last_expolygon (@last_offsets) { my @offsets = $last_expolygon->offset_ex(-$distance); foreach my $offset (@offsets) { push @new_offsets, $offset; push @contour_loops, $offset->contour; push @hole_loops, $offset->holes; } } @last_offsets = @new_offsets; } my @loops = (@contour_loops, reverse @hole_loops); # make paths my @paths = (); my $cur_pos = Slic3r::Point->new( ($bounding_box->[X1] + $bounding_box->[X2]) / 2, ($bounding_box->[Y1] + $bounding_box->[Y2]) / 2, ); foreach my $loop (map Slic3r::ExtrusionLoop->new(polygon => $_, role => EXTR_ROLE_FILL), @loops) { # extrude all loops ccw $loop->polygon->make_counter_clockwise; # find the point of the loop that is closest to the current extruder position my $index = $loop->nearest_point_index_to($cur_pos); $cur_pos = $loop->polygon->[0]; # split the loop at the starting point and make a path my $path = $loop->split_at_index($index); # clip the path to avoid the extruder to get exactly on the first point of the loop $path->clip_end(scale($self->layer ? $self->layer->flow->width : $Slic3r::flow->width) * 0.15); push @paths, $path->points if @{$path->points}; } return { flow_spacing => $flow_spacing }, @paths; } 1;