mirror of
https://github.com/SoftFever/OrcaSlicer.git
synced 2025-08-06 21:44:08 -06:00
New semantics for ExtrusionLoop objects. Early processing of perimeter overhangs for paralellizing such work and making G-code export lighter. Lots of refactoring. This should fix a number of minor bugs, including reversals of perimeter overhangs.
This commit is contained in:
parent
d2d885fc53
commit
c37ef2f18b
27 changed files with 618 additions and 423 deletions
|
@ -2,16 +2,4 @@ package Slic3r::ExtrusionLoop;
|
|||
use strict;
|
||||
use warnings;
|
||||
|
||||
sub split_at {
|
||||
my $self = shift;
|
||||
|
||||
return Slic3r::ExtrusionPath->new(
|
||||
polyline => $self->polygon->split_at(@_),
|
||||
role => $self->role,
|
||||
mm3_per_mm => $self->mm3_per_mm,
|
||||
width => $self->width,
|
||||
height => $self->height,
|
||||
);
|
||||
}
|
||||
|
||||
1;
|
||||
|
|
|
@ -19,7 +19,6 @@ has 'layer' => (is => 'rw');
|
|||
has 'region' => (is => 'rw');
|
||||
has '_layer_islands' => (is => 'rw');
|
||||
has '_upper_layer_islands' => (is => 'rw');
|
||||
has '_lower_layer_slices' => (is => 'ro', default => sub { Slic3r::ExPolygon::Collection->new });
|
||||
has 'shift_x' => (is => 'rw', default => sub {0} );
|
||||
has 'shift_y' => (is => 'rw', default => sub {0} );
|
||||
has 'z' => (is => 'rw');
|
||||
|
@ -111,17 +110,6 @@ sub change_layer {
|
|||
# avoid computing islands and overhangs if they're not needed
|
||||
$self->_layer_islands($layer->islands);
|
||||
$self->_upper_layer_islands($layer->upper_layer ? $layer->upper_layer->islands : []);
|
||||
$self->_lower_layer_slices->clear;
|
||||
if ($layer->lower_layer && ($self->print_config->overhangs || $self->print_config->start_perimeters_at_non_overhang)) {
|
||||
# We consider overhang any part where the entire nozzle diameter is not supported by the
|
||||
# lower layer, so we take lower slices and offset them by half the nozzle diameter used
|
||||
# in the current layer
|
||||
my $max_nozzle_diameter = max(map $layer->print->config->get_at('nozzle_diameter', $_->region->config->perimeter_extruder-1), @{$layer->regions});
|
||||
$self->_lower_layer_slices->append(
|
||||
# clone ExPolygons because they come from Surface objects but will be used outside here
|
||||
@{offset_ex([ map @$_, @{$layer->lower_layer->slices} ], +scale($max_nozzle_diameter/2))},
|
||||
);
|
||||
}
|
||||
if ($self->print_config->avoid_crossing_perimeters) {
|
||||
$self->layer_mp(Slic3r::GCode::MotionPlanner->new(
|
||||
islands => union_ex([ map @$_, @{$layer->slices} ], 1),
|
||||
|
@ -199,17 +187,17 @@ sub extrude_loop {
|
|||
|
||||
# extrude all loops ccw
|
||||
my $was_clockwise = $loop->make_counter_clockwise;
|
||||
my $polygon = $loop->polygon;
|
||||
|
||||
# find candidate starting points
|
||||
# start looking for concave vertices not being overhangs
|
||||
my $polygon = $loop->polygon;
|
||||
my @concave = ();
|
||||
if ($self->print_config->start_perimeters_at_concave_points) {
|
||||
@concave = $polygon->concave_points;
|
||||
}
|
||||
my @candidates = ();
|
||||
if ($self->print_config->start_perimeters_at_non_overhang) {
|
||||
@candidates = grep $self->_lower_layer_slices->contains_point($_), @concave;
|
||||
@candidates = grep !$loop->has_overhang_point($_), @concave;
|
||||
}
|
||||
if (!@candidates) {
|
||||
# if none, look for any concave vertex
|
||||
|
@ -217,11 +205,11 @@ sub extrude_loop {
|
|||
if (!@candidates) {
|
||||
# if none, look for any non-overhang vertex
|
||||
if ($self->print_config->start_perimeters_at_non_overhang) {
|
||||
@candidates = grep $self->_lower_layer_slices->contains_point($_), @$polygon;
|
||||
@candidates = grep !$loop->has_overhang_point($_), @$polygon;
|
||||
}
|
||||
if (!@candidates) {
|
||||
# if none, all points are valid candidates
|
||||
@candidates = @{$polygon};
|
||||
@candidates = @$polygon;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -234,71 +222,49 @@ sub extrude_loop {
|
|||
$last_pos->rotate(rand(2*PI), $self->print_config->print_center);
|
||||
}
|
||||
|
||||
# split the loop at the starting point and make a path
|
||||
my $start_at = $last_pos->nearest_point(\@candidates);
|
||||
my $extrusion_path = $loop->split_at($start_at);
|
||||
# split the loop at the starting point
|
||||
$loop->split_at($last_pos->nearest_point(\@candidates));
|
||||
|
||||
# clip the path to avoid the extruder to get exactly on the first point of the loop;
|
||||
# if polyline was shorter than the clipping distance we'd get a null polyline, so
|
||||
# we discard it in that case
|
||||
$extrusion_path->clip_end(scale($self->extruder->nozzle_diameter) * &Slic3r::LOOP_CLIPPING_LENGTH_OVER_NOZZLE_DIAMETER)
|
||||
if $self->enable_loop_clipping;
|
||||
return '' if !@{$extrusion_path->polyline};
|
||||
my $clip_length = $self->enable_loop_clipping
|
||||
? scale($self->extruder->nozzle_diameter) * &Slic3r::LOOP_CLIPPING_LENGTH_OVER_NOZZLE_DIAMETER
|
||||
: 0;
|
||||
|
||||
my @paths = ();
|
||||
# detect overhanging/bridging perimeters
|
||||
if ($self->layer->print->config->overhangs && $extrusion_path->is_perimeter && $self->_lower_layer_slices->count > 0) {
|
||||
# get non-overhang paths by intersecting this loop with the grown lower slices
|
||||
push @paths,
|
||||
map $_->clone,
|
||||
@{$extrusion_path->intersect_expolygons($self->_lower_layer_slices)};
|
||||
|
||||
# get overhang paths by checking what parts of this loop fall
|
||||
# outside the grown lower slices (thus where the distance between
|
||||
# the loop centerline and original lower slices is >= half nozzle diameter
|
||||
foreach my $path (@{$extrusion_path->subtract_expolygons($self->_lower_layer_slices)}) {
|
||||
$path = $path->clone;
|
||||
$path->role(EXTR_ROLE_OVERHANG_PERIMETER);
|
||||
$path->mm3_per_mm($self->region->flow(FLOW_ROLE_PERIMETER, -1, 1, 0, undef, $self->layer->object)->mm3_per_mm(-1));
|
||||
push @paths, $path;
|
||||
}
|
||||
|
||||
# reapply the nearest point search for starting point
|
||||
# (clone because the collection gets DESTROY'ed)
|
||||
my $collection = Slic3r::ExtrusionPath::Collection->new(@paths);
|
||||
@paths = map $_->clone, @{$collection->chained_path_from($start_at, 1)};
|
||||
} else {
|
||||
push @paths, $extrusion_path;
|
||||
}
|
||||
# get paths
|
||||
my @paths = @{$loop->clip_end($clip_length)};
|
||||
return '' if !@paths;
|
||||
|
||||
# apply the small perimeter speed
|
||||
my %params = ();
|
||||
if ($extrusion_path->is_perimeter && abs($extrusion_path->length) <= &Slic3r::SMALL_PERIMETER_LENGTH) {
|
||||
if ($paths[0]->is_perimeter && abs($loop->length) <= &Slic3r::SMALL_PERIMETER_LENGTH) {
|
||||
$params{speed} = 'small_perimeter';
|
||||
}
|
||||
|
||||
# extrude along the path
|
||||
my $gcode = join '', map $self->extrude_path($_, $description, %params), @paths;
|
||||
$self->wipe_path($extrusion_path->polyline->clone) if $self->enable_wipe;
|
||||
$self->wipe_path($paths[-1]->polyline->clone) if $self->enable_wipe; # TODO: don't limit wipe to last path
|
||||
|
||||
# make a little move inwards before leaving loop
|
||||
if ($loop->role == EXTR_ROLE_EXTERNAL_PERIMETER && defined $self->layer && $self->region->config->perimeters > 1) {
|
||||
if ($paths[-1]->role == EXTR_ROLE_EXTERNAL_PERIMETER && defined $self->layer && $self->region->config->perimeters > 1) {
|
||||
my $last_path_polyline = $paths[-1]->polyline;
|
||||
# detect angle between last and first segment
|
||||
# the side depends on the original winding order of the polygon (left for contours, right for holes)
|
||||
my @points = $was_clockwise ? (-2, 1) : (1, -2);
|
||||
my $angle = Slic3r::Geometry::angle3points(@{$extrusion_path->polyline}[0, @points]) / 3;
|
||||
my $angle = Slic3r::Geometry::angle3points(@$last_path_polyline[0, @points]) / 3;
|
||||
$angle *= -1 if $was_clockwise;
|
||||
|
||||
# create the destination point along the first segment and rotate it
|
||||
# we make sure we don't exceed the segment length because we don't know
|
||||
# the rotation of the second segment so we might cross the object boundary
|
||||
my $first_segment = Slic3r::Line->new(@{$extrusion_path->polyline}[0,1]);
|
||||
my $first_segment = Slic3r::Line->new(@$last_path_polyline[0,1]);
|
||||
my $distance = min(scale($self->extruder->nozzle_diameter), $first_segment->length);
|
||||
my $point = $first_segment->point_at($distance);
|
||||
$point->rotate($angle, $extrusion_path->first_point);
|
||||
$point->rotate($angle, $last_path_polyline->first_point);
|
||||
|
||||
# generate the travel move
|
||||
$gcode .= $self->travel_to($point, $loop->role, "move inwards before travel");
|
||||
$gcode .= $self->travel_to($point, $paths[-1]->role, "move inwards before travel");
|
||||
}
|
||||
|
||||
return $gcode;
|
||||
|
|
|
@ -8,6 +8,6 @@ our @EXPORT_OK = qw(offset offset_ex
|
|||
diff_ex diff union_ex intersection_ex xor_ex JT_ROUND JT_MITER
|
||||
JT_SQUARE is_counter_clockwise union_pt offset2 offset2_ex
|
||||
intersection intersection_pl diff_pl union CLIPPER_OFFSET_SCALE
|
||||
union_pt_chained);
|
||||
union_pt_chained diff_ppl intersection_ppl);
|
||||
|
||||
1;
|
||||
|
|
|
@ -3,7 +3,8 @@ use Moo;
|
|||
|
||||
use List::Util qw(first sum max min);
|
||||
use Slic3r::Geometry qw(PI unscale scaled_epsilon rad2deg epsilon directions_parallel_within);
|
||||
use Slic3r::Geometry::Clipper qw(intersection_pl intersection_ex union offset diff_pl union_ex);
|
||||
use Slic3r::Geometry::Clipper qw(intersection_pl intersection_ex union offset diff_pl union_ex
|
||||
intersection_ppl);
|
||||
|
||||
has 'expolygon' => (is => 'ro', required => 1);
|
||||
has 'lower_slices' => (is => 'rw', required => 1); # ExPolygons or ExPolygonCollection
|
||||
|
@ -26,7 +27,7 @@ sub BUILD {
|
|||
foreach my $lower (@{$self->lower_slices}) {
|
||||
# turn bridge contour and holes into polylines and then clip them
|
||||
# with each lower slice's contour
|
||||
push @$edges, map @{$_->clip_as_polyline([$lower->contour])}, @$grown;
|
||||
push @$edges, @{intersection_ppl($grown, [ $lower->contour ])};
|
||||
}
|
||||
Slic3r::debugf " bridge has %d support(s)\n", scalar(@$edges);
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@ use Slic3r::Flow ':roles';
|
|||
use Slic3r::Geometry qw(PI A B scale unscale chained_path points_coincide);
|
||||
use Slic3r::Geometry::Clipper qw(union_ex diff_ex intersection_ex
|
||||
offset offset_ex offset2 offset2_ex union_pt diff intersection
|
||||
union diff);
|
||||
union diff intersection_ppl diff_ppl);
|
||||
use Slic3r::Surface ':types';
|
||||
|
||||
has 'layer' => (
|
||||
|
@ -63,6 +63,8 @@ sub make_perimeters {
|
|||
|
||||
my $perimeter_flow = $self->flow(FLOW_ROLE_PERIMETER);
|
||||
my $mm3_per_mm = $perimeter_flow->mm3_per_mm($self->height);
|
||||
my $overhang_flow = $self->region->flow(FLOW_ROLE_PERIMETER, -1, 1, 0, undef, $self->layer->object);
|
||||
my $mm3_per_mm_overhang = $overhang_flow->mm3_per_mm(-1);
|
||||
my $pwidth = $perimeter_flow->scaled_width;
|
||||
my $pspacing = $perimeter_flow->scaled_spacing;
|
||||
my $solid_infill_flow = $self->flow(FLOW_ROLE_SOLID_INFILL);
|
||||
|
@ -229,6 +231,19 @@ sub make_perimeters {
|
|||
my $contours_pt = union_pt(\@contours);
|
||||
my $holes_pt = union_pt(\@holes);
|
||||
|
||||
# prepare grown lower layer slices for overhang detection
|
||||
my $lower_slices = Slic3r::ExPolygon::Collection->new;
|
||||
if ($self->layer->lower_layer && $self->layer->print->config->overhangs) {
|
||||
# We consider overhang any part where the entire nozzle diameter is not supported by the
|
||||
# lower layer, so we take lower slices and offset them by half the nozzle diameter used
|
||||
# in the current layer
|
||||
my $nozzle_diameter = $self->layer->print->config->get_at('nozzle_diameter', $self->region->config->perimeter_extruder-1);
|
||||
$lower_slices->append(
|
||||
@{offset_ex([ map @$_, @{$self->layer->lower_layer->slices} ], scale +$nozzle_diameter/2)},
|
||||
);
|
||||
}
|
||||
my $lower_slices_p = $lower_slices->polygons;
|
||||
|
||||
# prepare a coderef for traversing the PolyTree object
|
||||
# external contours are root items of $contours_pt
|
||||
# internal contours are the ones next to external
|
||||
|
@ -242,15 +257,6 @@ sub make_perimeters {
|
|||
foreach my $polynode (@$polynodes) {
|
||||
my $polygon = ($polynode->{outer} // $polynode->{hole})->clone;
|
||||
|
||||
# return ccw contours and cw holes
|
||||
# GCode.pm will convert all of them to ccw, but it needs to know
|
||||
# what the holes are in order to compute the correct inwards move
|
||||
if ($is_contour) {
|
||||
$polygon->make_counter_clockwise;
|
||||
} else {
|
||||
$polygon->make_clockwise;
|
||||
}
|
||||
|
||||
my $role = EXTR_ROLE_PERIMETER;
|
||||
if ($is_contour ? $depth == 0 : !@{ $polynode->{children} }) {
|
||||
# external perimeters are root level in case of contours
|
||||
|
@ -260,13 +266,62 @@ sub make_perimeters {
|
|||
$role = EXTR_ROLE_CONTOUR_INTERNAL_PERIMETER;
|
||||
}
|
||||
|
||||
$collection->append(Slic3r::ExtrusionLoop->new(
|
||||
polygon => $polygon,
|
||||
role => $role,
|
||||
mm3_per_mm => $mm3_per_mm,
|
||||
width => $perimeter_flow->width,
|
||||
height => $self->height,
|
||||
));
|
||||
# detect overhanging/bridging perimeters
|
||||
my @paths = ();
|
||||
if ($self->layer->print->config->overhangs && $lower_slices->count > 0) {
|
||||
# get non-overhang paths by intersecting this loop with the grown lower slices
|
||||
foreach my $polyline (@{ intersection_ppl([ $polygon ], $lower_slices_p) }) {
|
||||
push @paths, Slic3r::ExtrusionPath->new(
|
||||
polyline => $polyline,
|
||||
role => $role,
|
||||
mm3_per_mm => $mm3_per_mm,
|
||||
width => $perimeter_flow->width,
|
||||
height => $self->height,
|
||||
);
|
||||
}
|
||||
|
||||
# get overhang paths by checking what parts of this loop fall
|
||||
# outside the grown lower slices (thus where the distance between
|
||||
# the loop centerline and original lower slices is >= half nozzle diameter
|
||||
foreach my $polyline (@{ diff_ppl([ $polygon ], $lower_slices_p) }) {
|
||||
push @paths, Slic3r::ExtrusionPath->new(
|
||||
polyline => $polyline,
|
||||
role => EXTR_ROLE_OVERHANG_PERIMETER,
|
||||
mm3_per_mm => $mm3_per_mm_overhang,
|
||||
width => $overhang_flow->width,
|
||||
height => $self->height,
|
||||
);
|
||||
}
|
||||
|
||||
# reapply the nearest point search for starting point
|
||||
# (clone because the collection gets DESTROY'ed)
|
||||
# We allow polyline reversal because Clipper may have randomly
|
||||
# reversed polylines during clipping.
|
||||
my $collection = Slic3r::ExtrusionPath::Collection->new(@paths);
|
||||
@paths = map $_->clone, @{$collection->chained_path(0)};
|
||||
} else {
|
||||
push @paths, Slic3r::ExtrusionPath->new(
|
||||
polyline => $polygon->split_at_first_point,
|
||||
role => $role,
|
||||
mm3_per_mm => $mm3_per_mm,
|
||||
width => $perimeter_flow->width,
|
||||
height => $self->height,
|
||||
);
|
||||
}
|
||||
my $loop = Slic3r::ExtrusionLoop->new_from_paths(@paths);
|
||||
|
||||
# return ccw contours and cw holes
|
||||
# GCode.pm will convert all of them to ccw, but it needs to know
|
||||
# what the holes are in order to compute the correct inwards move
|
||||
# We do this on the final Loop object instead of the polygon because
|
||||
# overhang clipping might have reversed its order since Clipper does
|
||||
# not preserve polyline orientation.
|
||||
if ($is_contour) {
|
||||
$loop->make_counter_clockwise;
|
||||
} else {
|
||||
$loop->make_clockwise;
|
||||
}
|
||||
$collection->append($loop);
|
||||
|
||||
# save the children
|
||||
push @children, $polynode->{children};
|
||||
|
@ -367,11 +422,16 @@ sub _fill_gaps {
|
|||
Slic3r::debugf " %d gaps filled with extrusion width = %s\n", scalar @$this, $w
|
||||
if @$this;
|
||||
|
||||
return map {
|
||||
$_->isa('Slic3r::Polygon')
|
||||
? Slic3r::ExtrusionLoop->new(polygon => $_, %path_args)->split_at_first_point # should we keep these as loops?
|
||||
: Slic3r::ExtrusionPath->new(polyline => $_, %path_args),
|
||||
} @polylines;
|
||||
for my $i (0..$#polylines) {
|
||||
if ($polylines[$i]->isa('Slic3r::Polygon')) {
|
||||
my $loop = Slic3r::ExtrusionLoop->new;
|
||||
$loop->append(Slic3r::ExtrusionPath->new(polyline => $polylines[$i]->split_at_first_point, %path_args));
|
||||
$polylines[$i] = $loop;
|
||||
} else {
|
||||
$polylines[$i] = Slic3r::ExtrusionPath->new(polyline => $polylines[$i], %path_args);
|
||||
}
|
||||
}
|
||||
return @polylines;
|
||||
}
|
||||
|
||||
sub prepare_fill_surfaces {
|
||||
|
|
|
@ -51,41 +51,4 @@ sub concave_points {
|
|||
-1 .. ($#points-1);
|
||||
}
|
||||
|
||||
sub clip_as_polyline {
|
||||
my ($self, $polygons) = @_;
|
||||
|
||||
my $self_pl = $self->split_at_first_point;
|
||||
|
||||
# Clipper will remove a polyline segment if first point coincides with last one.
|
||||
# Until that bug is not fixed upstream, we move one of those points slightly.
|
||||
$self_pl->[0]->translate(1, 0);
|
||||
|
||||
my @polylines = @{intersection_pl([$self_pl], $polygons)};
|
||||
if (@polylines == 1) {
|
||||
if ($polylines[0][0]->coincides_with($self_pl->[0])) {
|
||||
# compensate the above workaround for Clipper bug
|
||||
$polylines[0][0]->translate(-1, 0);
|
||||
}
|
||||
} elsif (@polylines == 2) {
|
||||
# If the split_at_first_point() call above happens to split the polygon inside the clipping area
|
||||
# we would get two consecutive polylines instead of a single one, so we use this ugly hack to
|
||||
# recombine them back into a single one in order to trigger the @edges == 2 logic below.
|
||||
# This needs to be replaced with something way better.
|
||||
if ($polylines[0][-1]->coincides_with($self_pl->[-1]) && $polylines[-1][0]->coincides_with($self_pl->[0])) {
|
||||
my $p = $polylines[0]->clone;
|
||||
$p->pop_back;
|
||||
$p->append(@{$polylines[-1]});
|
||||
return [$p];
|
||||
}
|
||||
if ($polylines[0][0]->coincides_with($self_pl->[0]) && $polylines[-1][-1]->coincides_with($self_pl->[-1])) {
|
||||
my $p = $polylines[-1]->clone;
|
||||
$p->pop_back;
|
||||
$p->append(@{$polylines[0]});
|
||||
return [$p];
|
||||
}
|
||||
}
|
||||
|
||||
return [ @polylines ];
|
||||
}
|
||||
|
||||
1;
|
|
@ -705,12 +705,14 @@ sub make_skirt {
|
|||
for (my $i = $self->config->skirts; $i > 0; $i--) {
|
||||
$distance += scale $spacing;
|
||||
my $loop = offset([$convex_hull], $distance, 1, JT_ROUND, scale(0.1))->[0];
|
||||
$self->skirt->append(Slic3r::ExtrusionLoop->new(
|
||||
polygon => Slic3r::Polygon->new(@$loop),
|
||||
role => EXTR_ROLE_SKIRT,
|
||||
mm3_per_mm => $mm3_per_mm,
|
||||
width => $flow->width,
|
||||
height => $first_layer_height,
|
||||
$self->skirt->append(Slic3r::ExtrusionLoop->new_from_paths(
|
||||
Slic3r::ExtrusionPath->new(
|
||||
polyline => Slic3r::Polygon->new(@$loop)->split_at_first_point,
|
||||
role => EXTR_ROLE_SKIRT,
|
||||
mm3_per_mm => $mm3_per_mm,
|
||||
width => $flow->width,
|
||||
height => $first_layer_height,
|
||||
),
|
||||
));
|
||||
|
||||
if ($self->config->min_skirt_length > 0) {
|
||||
|
@ -788,12 +790,14 @@ sub make_brim {
|
|||
push @loops, @{offset2(\@islands, ($i + 0.5) * $flow->scaled_spacing, -1.0 * $flow->scaled_spacing, 100000, JT_SQUARE)};
|
||||
}
|
||||
|
||||
$self->brim->append(map Slic3r::ExtrusionLoop->new(
|
||||
polygon => Slic3r::Polygon->new(@$_),
|
||||
role => EXTR_ROLE_SKIRT,
|
||||
mm3_per_mm => $mm3_per_mm,
|
||||
width => $flow->width,
|
||||
height => $first_layer_height,
|
||||
$self->brim->append(map Slic3r::ExtrusionLoop->new_from_paths(
|
||||
Slic3r::ExtrusionPath->new(
|
||||
polyline => Slic3r::Polygon->new(@$_)->split_at_first_point,
|
||||
role => EXTR_ROLE_SKIRT,
|
||||
mm3_per_mm => $mm3_per_mm,
|
||||
width => $flow->width,
|
||||
height => $first_layer_height,
|
||||
),
|
||||
), reverse @{union_pt_chained(\@loops)});
|
||||
}
|
||||
|
||||
|
@ -913,7 +917,7 @@ sub write_gcode {
|
|||
|
||||
# calculate wiping points if needed
|
||||
if ($self->config->ooze_prevention) {
|
||||
my @skirt_points = map @$_, @{$self->skirt};
|
||||
my @skirt_points = map @$_, map @$_, @{$self->skirt};
|
||||
if (@skirt_points) {
|
||||
my $outer_skirt = convex_hull(\@skirt_points);
|
||||
my @skirts = ();
|
||||
|
|
|
@ -70,14 +70,20 @@ sub generate {
|
|||
$self->clip_with_shape($base, $shape) if @$shape;
|
||||
|
||||
# Install support layers into object.
|
||||
push @{$object->support_layers}, map Slic3r::Layer::Support->new(
|
||||
object => $object,
|
||||
id => $_,
|
||||
height => ($_ == 0) ? $support_z->[$_] : ($support_z->[$_] - $support_z->[$_-1]),
|
||||
print_z => $support_z->[$_],
|
||||
slice_z => -1,
|
||||
slices => [],
|
||||
), 0 .. $#$support_z;
|
||||
for my $i (0 .. $#$support_z) {
|
||||
push @{$object->support_layers}, Slic3r::Layer::Support->new(
|
||||
object => $object,
|
||||
id => $i,
|
||||
height => ($i == 0) ? $support_z->[$i] : ($support_z->[$i] - $support_z->[$i-1]),
|
||||
print_z => $support_z->[$i],
|
||||
slice_z => -1,
|
||||
slices => [],
|
||||
);
|
||||
if ($i >= 1) {
|
||||
$object->support_layers->[-2]->upper_layer($object->support_layers->[-1]);
|
||||
$object->support_layers->[-1]->lower_layer($object->support_layers->[-2]);
|
||||
}
|
||||
}
|
||||
|
||||
# Generate the actual toolpaths and save them into each layer.
|
||||
$self->generate_toolpaths($object, $overhang, $contact, $interface, $base);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue