diff options
author | bubnikv <bubnikv@gmail.com> | 2016-09-12 12:29:39 +0300 |
---|---|---|
committer | bubnikv <bubnikv@gmail.com> | 2016-09-12 12:29:39 +0300 |
commit | 9fcc8fe9aeacb8edf6206787574cf1a84c88a5cc (patch) | |
tree | 549776f3a63d4eb240d0caaf7a63fa6259dac031 /lib | |
parent | ca98e2655a4a5875947598f404791ea6c0313609 (diff) | |
parent | d022493297a110a9f982786ed696528c1d79d0f1 (diff) |
Meged with release_candidate_1_3
Diffstat (limited to 'lib')
-rw-r--r-- | lib/Slic3r.pm | 2 | ||||
-rw-r--r-- | lib/Slic3r/Fill.pm | 52 | ||||
-rw-r--r-- | lib/Slic3r/Fill/3DHoneycomb.pm | 230 | ||||
-rw-r--r-- | lib/Slic3r/Fill/Base.pm | 91 | ||||
-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 | 168 | ||||
-rw-r--r-- | lib/Slic3r/GUI.pm | 1 | ||||
-rw-r--r-- | lib/Slic3r/GUI/MainFrame.pm | 7 | ||||
-rw-r--r-- | lib/Slic3r/GUI/Plater/2DToolpaths.pm | 170 | ||||
-rw-r--r-- | lib/Slic3r/Print/SupportMaterial.pm | 24 |
12 files changed, 197 insertions, 852 deletions
diff --git a/lib/Slic3r.pm b/lib/Slic3r.pm index aa9aea28c..4df83f99a 100644 --- a/lib/Slic3r.pm +++ b/lib/Slic3r.pm @@ -193,7 +193,9 @@ sub thread_cleanup { *Slic3r::ExtrusionLoop::DESTROY = sub {}; *Slic3r::ExtrusionPath::DESTROY = sub {}; *Slic3r::ExtrusionPath::Collection::DESTROY = sub {}; + *Slic3r::ExtrusionSimulator::DESTROY = sub {}; *Slic3r::Flow::DESTROY = sub {}; + *Slic3r::Filler::Destroy = sub {}; *Slic3r::GCode::DESTROY = sub {}; *Slic3r::GCode::AvoidCrossingPerimeters::DESTROY = sub {}; *Slic3r::GCode::OozePrevention::DESTROY = sub {}; diff --git a/lib/Slic3r/Fill.pm b/lib/Slic3r/Fill.pm index 8c63fde59..ec9038b12 100644 --- a/lib/Slic3r/Fill.pm +++ b/lib/Slic3r/Fill.pm @@ -3,45 +3,25 @@ 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; + return Slic3r::Filler->new_from_type($filler); } - - $self->fillers->{$filler} ||= $FillTypes{$filler}->new( - bounding_box => $self->bounding_box, - ); + + $self->fillers->{$filler} ||= Slic3r::Filler->new_from_type($filler); + $self->fillers->{$filler}->set_bounding_box($self->bounding_box); return $self->fillers->{$filler}; } @@ -227,25 +207,25 @@ sub make_fill { -1, # auto width $layerm->layer->object, ); - $f->spacing($internal_flow->spacing); + $f->set_spacing($internal_flow->spacing); $using_internal_flow = 1; } else { - $f->spacing($flow->spacing); + $f->set_spacing($flow->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); + $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 = map $f->fill_surface( - $_, + my @polylines = $f->fill_surface( + $surface, density => $density/100, layer_height => $h, - ), @{ $surface->offset(-scale($f->spacing)/2) }; - + ); next unless @polylines; + # calculate actual flow from spacing (which might have been adjusted by the infill # pattern generator) @@ -278,7 +258,7 @@ sub make_fill { mm3_per_mm => $mm3_per_mm, width => $flow->width, height => $flow->height, - ), @polylines, + ), map @$_, @polylines, ); } } 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 75c8e03e6..000000000 --- a/lib/Slic3r/Fill/Base.pm +++ /dev/null @@ -1,91 +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 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 0922ff771..000000000 --- a/lib/Slic3r/Fill/Rectilinear.pm +++ /dev/null @@ -1,168 +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}) { - $self->_line_spacing($self->adjust_solid_spacing( - width => $bounding_box->size->x, - distance => $self->_line_spacing, - )); - $self->spacing(unscale $self->_line_spacing); - } 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/GUI.pm b/lib/Slic3r/GUI.pm index 7f4a028a5..1c811fa78 100644 --- a/lib/Slic3r/GUI.pm +++ b/lib/Slic3r/GUI.pm @@ -40,6 +40,7 @@ use Wx 0.9901 qw(:bitmap :dialog :icon :id :misc :systemsettings :toplevelwindow :filedialog :font); use Wx::Event qw(EVT_IDLE EVT_COMMAND); use base 'Wx::App'; +#use base 'Wx::AppConsole'; use constant FILE_WILDCARDS => { known => 'Known files (*.stl, *.obj, *.amf, *.xml)|*.stl;*.STL;*.obj;*.OBJ;*.amf;*.AMF;*.xml;*.XML', diff --git a/lib/Slic3r/GUI/MainFrame.pm b/lib/Slic3r/GUI/MainFrame.pm index d97ad22ef..4c04066bb 100644 --- a/lib/Slic3r/GUI/MainFrame.pm +++ b/lib/Slic3r/GUI/MainFrame.pm @@ -294,8 +294,13 @@ sub _init_menubar { $self->_append_menu_item($helpMenu, "&About Slic3r", 'Show about dialog', sub { wxTheApp->about; }); + if (Slic3r::GUI::debugged()) { + $self->_append_menu_item($helpMenu, "&Debug", 'Break to debugger', sub { + Slic3r::GUI::break_to_debugger(); + }); + } } - + # menubar # assign menubar to frame after appending items, otherwise special items # will not be handled correctly diff --git a/lib/Slic3r/GUI/Plater/2DToolpaths.pm b/lib/Slic3r/GUI/Plater/2DToolpaths.pm index ee59c2980..66d669b11 100644 --- a/lib/Slic3r/GUI/Plater/2DToolpaths.pm +++ b/lib/Slic3r/GUI/Plater/2DToolpaths.pm @@ -1,10 +1,13 @@ +# 2D preview of the tool paths of a single layer, using a thin line. +# OpenGL is used to render the paths. + package Slic3r::GUI::Plater::2DToolpaths; use strict; use warnings; use utf8; use Slic3r::Print::State ':steps'; -use Wx qw(:misc :sizer :slider :statictext wxWHITE); +use Wx qw(:misc :sizer :slider :statictext :keycode wxWHITE wxWANTS_CHARS); use Wx::Event qw(EVT_SLIDER EVT_KEY_DOWN); use base qw(Wx::Panel Class::Accessor); @@ -14,7 +17,7 @@ sub new { my $class = shift; my ($parent, $print) = @_; - my $self = $class->SUPER::new($parent, -1, wxDefaultPosition); + my $self = $class->SUPER::new($parent, -1, wxDefaultPosition, wxDefaultSize, wxWANTS_CHARS); $self->SetBackgroundColour(wxWHITE); # init GUI elements @@ -48,17 +51,21 @@ sub new { }); EVT_KEY_DOWN($canvas, sub { my ($s, $event) = @_; - my $key = $event->GetKeyCode; - if ($key == 85 || $key == 315) { + if ($key == 85 || $key == WXK_LEFT) { + # Keys: 'D' or WXK_LEFT $slider->SetValue($slider->GetValue + 1); $self->set_z($self->{layers_z}[$slider->GetValue]); - } elsif ($key == 68 || $key == 317) { + } elsif ($key == 68 || $key == WXK_RIGHT) { + # Keys: 'U' or WXK_RIGHT $slider->SetValue($slider->GetValue - 1); $self->set_z($self->{layers_z}[$slider->GetValue]); + } elsif ($key >= 49 && $key <= 55) { + # Keys: '1' to '3' + $canvas->set_simulation_mode($key - 49); } }); - + $self->SetSizer($sizer); $self->SetMinSize($self->GetSize); $sizer->SetSizeHints($self); @@ -132,6 +139,10 @@ __PACKAGE__->mk_accessors(qw( _zoom _camera_target _drag_start_xy + _texture_name + _texture_size + _extrusion_simulator + _simulation_mode )); # make OpenGL::Array thread-safe @@ -155,7 +166,13 @@ sub new { # 2D point in model space $self->_camera_target(Slic3r::Pointf->new(0,0)); - + + # Texture for the extrusion simulator. The texture will be allocated / reallocated on Resize. + $self->_texture_name(0); + $self->_texture_size(Slic3r::Point->new(0,0)); + $self->_extrusion_simulator(Slic3r::ExtrusionSimulator->new()); + $self->_simulation_mode(0); + EVT_PAINT($self, sub { my $dc = Wx::PaintDC->new($self); $self->Render($dc); @@ -210,6 +227,21 @@ sub new { return $self; } +sub Destroy { + my ($self) = @_; + + # Deallocate the OpenGL resources. + my $context = $self->GetContext; + if ($context and $self->texture_id) { + $self->SetCurrent($context); + glDeleteTextures(1, ($self->texture_id)); + $self->SetCurrent(0); + $self->texture_id(0); + $self->texture_size(new Slic3r::Point(0, 0)); + } + return $self->SUPER::Destroy; +} + sub mouse_event { my ($self, $e) = @_; @@ -278,6 +310,14 @@ sub set_z { $self->Refresh; } +sub set_simulation_mode +{ + my ($self, $mode) = @_; + $self->_simulation_mode($mode); + $self->_dirty(1); + $self->Refresh; +} + sub Render { my ($self, $dc) = @_; @@ -299,7 +339,43 @@ sub Render { glDisable(GL_DEPTH_TEST); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); - + + if ($self->_simulation_mode and $self->_texture_name and $self->_texture_size->x() > 0 and $self->_texture_size->y() > 0) { + $self->_simulate_extrusion(); + my ($x, $y) = $self->GetSizeWH; + glEnable(GL_TEXTURE_2D); + glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE,GL_REPLACE); + glBindTexture(GL_TEXTURE_2D, $self->_texture_name); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexImage2D_c(GL_TEXTURE_2D, + 0, # level (0 normal, heighr is form mip-mapping) + GL_RGBA, # internal format + $self->_texture_size->x(), $self->_texture_size->y(), + 0, # border + GL_RGBA, # format RGBA color data + GL_UNSIGNED_BYTE, # unsigned byte data + $self->_extrusion_simulator->image_ptr()); # ptr to texture data + glMatrixMode(GL_PROJECTION); + glPushMatrix(); + glLoadIdentity(); + glOrtho(0, 1, 0, 1, 0, 1); + glBegin(GL_QUADS); + glTexCoord2f(0, 0); + glVertex2f(0, 0); + glTexCoord2f($x/$self->_texture_size->x(), 0); + glVertex2f(1, 0); + glTexCoord2f($x/$self->_texture_size->x(), $y/$self->_texture_size->y()); + glVertex2f(1, 1); + glTexCoord2f(0, $y/$self->_texture_size->y()); + glVertex2f(0, 1); + glEnd(); + glPopMatrix(); + glBindTexture(GL_TEXTURE_2D, 0); + } + # anti-alias if (0) { glEnable(GL_LINE_SMOOTH); @@ -308,8 +384,9 @@ sub Render { glHint(GL_POLYGON_SMOOTH_HINT, GL_DONT_CARE); } + # Tesselator triangulates polygons with holes on the fly for the rendering purposes only. my $tess; - if (!(&Wx::wxMSW && $OpenGL::VERSION < 0.6704)) { + if ($self->_simulation_mode() == 0 and !(&Wx::wxMSW && $OpenGL::VERSION < 0.6704)) { # We can't use the GLU tesselator on MSW with older OpenGL versions # because of an upstream bug: # http://sourceforge.net/p/pogl/bugs/16/ @@ -448,8 +525,42 @@ sub _draw_path { glVertex2f(@{$line->a}); glVertex2f(@{$line->b}); glEnd(); + } + } +} + +sub _simulate_extrusion { + my ($self) = @_; + $self->_extrusion_simulator->reset_accumulator(); + foreach my $layer (@{$self->layers}) { + if (abs($layer->print_z - $self->z) < epsilon) { + my $object = $layer->object; + my @shifts = (defined $object) ? @{$object->_shifted_copies} : (Slic3r::Point->new(0, 0)); + foreach my $layerm (@{$layer->regions}) { + my @extrusions = (); + if ($object->step_done(STEP_PERIMETERS)) { + push @extrusions, @$_ for @{$layerm->perimeters}; + } + if ($object->step_done(STEP_INFILL)) { + push @extrusions, @$_ for @{$layerm->fills}; + } + foreach my $extrusion_entity (@extrusions) { + my @paths = $extrusion_entity->isa('Slic3r::ExtrusionLoop') + ? @$extrusion_entity + : ($extrusion_entity); + foreach my $path (@paths) { + print "width: ", $path->width, + " height: ", $path->height, + " mm3_per_mm: ", $path->mm3_per_mm, + " height2: ", $path->mm3_per_mm / $path->height, + "\n"; + $self->_extrusion_simulator->extrude_to_accumulator($path, $_, $self->_simulation_mode()) for @shifts; + } + } + } } } + $self->_extrusion_simulator->evaluate_accumulator($self->_simulation_mode()); } sub InitGL { @@ -457,6 +568,10 @@ sub InitGL { return if $self->init; return unless $self->GetContext; + + my $texture_id = 0; + ($texture_id) = glGenTextures_p(1); + $self->_texture_name($texture_id); $self->init(1); } @@ -489,6 +604,33 @@ sub Resize { $self->SetCurrent($self->GetContext); my ($x, $y) = $self->GetSizeWH; + + if ($self->_texture_size->x() < $x or $self->_texture_size->y() < $y) { + # Allocate a large enough OpenGL texture with power of 2 dimensions. + $self->_texture_size->set_x(1) if ($self->_texture_size->x() == 0); + $self->_texture_size->set_y(1) if ($self->_texture_size->y() == 0); + $self->_texture_size->set_x($self->_texture_size->x() * 2) while ($self->_texture_size->x() < $x); + $self->_texture_size->set_y($self->_texture_size->y() * 2) while ($self->_texture_size->y() < $y); + #print "screen size ", $x, "x", $y; + #print "texture size ", $self->_texture_size->x(), "x", $self->_texture_size->y(); + # Initialize an empty texture. + glBindTexture(GL_TEXTURE_2D, $self->_texture_name); + if (1) { + glTexImage2D_c(GL_TEXTURE_2D, + 0, # level (0 normal, heighr is form mip-mapping) + GL_RGBA, # internal format + $self->_texture_size->x(), $self->_texture_size->y(), + 0, # border + GL_RGBA, # format RGBA color data + GL_UNSIGNED_BYTE, # unsigned byte data + 0); # ptr to texture data + } + glBindTexture(GL_TEXTURE_2D, 0); + $self->_extrusion_simulator->set_image_size($self->_texture_size); + } + $self->_extrusion_simulator->set_viewport(Slic3r::Geometry::BoundingBox->new_from_points( + [Slic3r::Point->new(0, 0), Slic3r::Point->new($x, $y)])); + glViewport(0, 0, $x, $y); glMatrixMode(GL_PROJECTION); @@ -544,10 +686,18 @@ sub Resize { $x2 = $x1 + $new_x; } glOrtho($x1, $x2, $y1, $y2, 0, 1); - + + # Set the adjusted bounding box at the extrusion simulator. + #print "Scene bbox ", $bb->x_min, ",", $bb->y_min, " ", $bb->x_max, ",", $bb->y_max, "\n"; + #print "Setting simulator bbox ", $x1, ",", $y1, " ", $x2, ",", $y2, "\n"; + $self->_extrusion_simulator->set_bounding_box( + Slic3r::Geometry::BoundingBox->new_from_points( + [Slic3r::Point->new($x1, $y1), Slic3r::Point->new($x2, $y2)])); + glMatrixMode(GL_MODELVIEW); } +# Thick line drawing is not used anywhere. Probably not tested? sub line { my ( $x1, $y1, $x2, $y2, # coordinates of the line diff --git a/lib/Slic3r/Print/SupportMaterial.pm b/lib/Slic3r/Print/SupportMaterial.pm index eea6397af..acfa5efee 100644 --- a/lib/Slic3r/Print/SupportMaterial.pm +++ b/lib/Slic3r/Print/SupportMaterial.pm @@ -675,8 +675,8 @@ sub generate_toolpaths { # interface and contact infill if (@$interface || @$contact_infill) { - $fillers{interface}->angle($interface_angle); - $fillers{interface}->spacing($_interface_flow->spacing); + $fillers{interface}->set_angle($interface_angle); + $fillers{interface}->set_spacing($_interface_flow->spacing); # find centerline of the external loop $interface = offset2($interface, +scaled_epsilon, -(scaled_epsilon + $_interface_flow->scaled_width/2)); @@ -702,7 +702,7 @@ sub generate_toolpaths { my @paths = (); foreach my $expolygon (@{union_ex($interface)}) { - my @p = $fillers{interface}->fill_surface( + my $polylines = $fillers{interface}->fill_surface( Slic3r::Surface->new(expolygon => $expolygon, surface_type => S_TYPE_INTERNAL), density => $interface_density, layer_height => $layer->height, @@ -711,12 +711,12 @@ sub generate_toolpaths { my $mm3_per_mm = $_interface_flow->mm3_per_mm; push @paths, map Slic3r::ExtrusionPath->new( - polyline => Slic3r::Polyline->new(@$_), + polyline => $_, role => EXTR_ROLE_SUPPORTMATERIAL_INTERFACE, mm3_per_mm => $mm3_per_mm, width => $_interface_flow->width, height => $layer->height, - ), @p; + ), @$polylines, } $layer->support_interface_fills->append(@paths); @@ -725,11 +725,11 @@ sub generate_toolpaths { # support or flange if (@$base) { my $filler = $fillers{support}; - $filler->angle($angles[ ($layer_id) % @angles ]); + $filler->set_angle($angles[ ($layer_id) % @angles ]); # We don't use $base_flow->spacing because we need a constant spacing # value that guarantees that all layers are correctly aligned. - $filler->spacing($flow->spacing); + $filler->set_spacing($flow->spacing); my $density = $support_density; my $base_flow = $_flow; @@ -742,13 +742,13 @@ sub generate_toolpaths { # base flange if ($layer_id == 0) { $filler = $fillers{interface}; - $filler->angle($self->object_config->support_material_angle + 90); + $filler->set_angle($self->object_config->support_material_angle + 90); $density = 0.5; $base_flow = $self->first_layer_flow; # use the proper spacing for first layer as we don't need to align # its pattern to the other layers - $filler->spacing($base_flow->spacing); + $filler->set_spacing($base_flow->spacing); } else { # draw a perimeter all around support infill # TODO: use brim ordering algorithm @@ -767,7 +767,7 @@ sub generate_toolpaths { my $mm3_per_mm = $base_flow->mm3_per_mm; foreach my $expolygon (@$to_infill) { - my @p = $filler->fill_surface( + my $polylines = $filler->fill_surface( Slic3r::Surface->new(expolygon => $expolygon, surface_type => S_TYPE_INTERNAL), density => $density, layer_height => $layer->height, @@ -775,12 +775,12 @@ sub generate_toolpaths { ); push @paths, map Slic3r::ExtrusionPath->new( - polyline => Slic3r::Polyline->new(@$_), + polyline => $_, role => EXTR_ROLE_SUPPORTMATERIAL, mm3_per_mm => $mm3_per_mm, width => $base_flow->width, height => $layer->height, - ), @p; + ), @$polylines; } $layer->support_fills->append(@paths); |