mirror of
https://github.com/SoftFever/OrcaSlicer.git
synced 2025-07-26 16:13:58 -06:00
Cleaner logic for perimeters, thin walls and gaps. More correct results and faster processing
This commit is contained in:
parent
d4d8045905
commit
abe56f96da
1 changed files with 69 additions and 74 deletions
|
@ -145,8 +145,9 @@ sub _merge_loops {
|
||||||
sub make_perimeters {
|
sub make_perimeters {
|
||||||
my $self = shift;
|
my $self = shift;
|
||||||
|
|
||||||
my $perimeter_spacing = $self->perimeter_flow->scaled_spacing;
|
my $pwidth = $self->perimeter_flow->scaled_width;
|
||||||
my $infill_spacing = $self->solid_infill_flow->scaled_spacing;
|
my $pspacing = $self->perimeter_flow->scaled_spacing;
|
||||||
|
my $ispacing = $self->solid_infill_flow->scaled_spacing;
|
||||||
my $gap_area_threshold = $self->perimeter_flow->scaled_width ** 2;
|
my $gap_area_threshold = $self->perimeter_flow->scaled_width ** 2;
|
||||||
|
|
||||||
$self->perimeters->clear;
|
$self->perimeters->clear;
|
||||||
|
@ -155,7 +156,8 @@ sub make_perimeters {
|
||||||
|
|
||||||
my @contours = (); # array of Polygons with ccw orientation
|
my @contours = (); # array of Polygons with ccw orientation
|
||||||
my @holes = (); # array of Polygons with cw orientation
|
my @holes = (); # array of Polygons with cw orientation
|
||||||
my @gaps = (); # array of Polygons
|
my @thin_walls = (); # array of ExPolygons
|
||||||
|
my @gaps = (); # array of ExPolygons
|
||||||
|
|
||||||
# we need to process each island separately because we might have different
|
# we need to process each island separately because we might have different
|
||||||
# extra perimeters for each one
|
# extra perimeters for each one
|
||||||
|
@ -163,44 +165,51 @@ sub make_perimeters {
|
||||||
# detect how many perimeters must be generated for this island
|
# detect how many perimeters must be generated for this island
|
||||||
my $loop_number = $self->config->perimeters + ($surface->extra_perimeters || 0);
|
my $loop_number = $self->config->perimeters + ($surface->extra_perimeters || 0);
|
||||||
|
|
||||||
# generate loops
|
|
||||||
# (one more than necessary so that we can detect gaps even after the desired
|
|
||||||
# number of perimeters has been generated)
|
|
||||||
my @last = @{$surface->expolygon};
|
my @last = @{$surface->expolygon};
|
||||||
my @this_gaps = ();
|
my @last_gaps = ();
|
||||||
for my $i (0 .. $loop_number) {
|
for my $i (1 .. $loop_number) { # outer loop is 1
|
||||||
# external loop only needs half inset distance
|
my @offsets = ();
|
||||||
my $spacing = ($i == 0)
|
if ($i == 1) {
|
||||||
? $perimeter_spacing / 2
|
# the minimum thickness of a single loop is:
|
||||||
: $perimeter_spacing;
|
# width/2 + spacing/2 + spacing/2 + width/2
|
||||||
|
@offsets = @{offset2(\@last, -(0.5*$pwidth + 0.5*$pspacing - 1), +(0.5*$pspacing - 1))};
|
||||||
|
|
||||||
my @offsets = @{offset2_ex(\@last, -1.5*$spacing, +0.5*$spacing)};
|
# look for thin walls
|
||||||
# clone polygons because these ExPolygons will go out of scope very soon
|
if ($self->config->thin_walls) {
|
||||||
my @contours_offsets = map $_->contour->clone, @offsets;
|
my $diff = diff_ex(
|
||||||
my @holes_offsets = map $_->clone, map @{$_->holes}, @offsets;
|
\@last,
|
||||||
@offsets = map $_->clone, (@contours_offsets, @holes_offsets); # turn @offsets from ExPolygons to Polygons
|
offset(\@offsets, +0.5*$pwidth),
|
||||||
|
|
||||||
# where offset2() collapses the expolygon, then there's no room for an inner loop
|
|
||||||
# and we can extract the gap for later processing
|
|
||||||
if ($Slic3r::Config->gap_fill_speed > 0 && $self->config->fill_density > 0) {
|
|
||||||
my $diff = diff(
|
|
||||||
offset(\@last, -0.5*$spacing),
|
|
||||||
# +2 on the offset here makes sure that Clipper float truncation
|
|
||||||
# won't shrink the clip polygon to be smaller than intended.
|
|
||||||
offset(\@offsets, +0.5*$spacing + 2),
|
|
||||||
);
|
);
|
||||||
push @gaps, (@this_gaps = grep abs($_->area) >= $gap_area_threshold, @$diff);
|
push @thin_walls, grep abs($_->area) >= $gap_area_threshold, @$diff;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
@offsets = @{offset2(\@last, -(1.5*$pspacing - 1), +(0.5*$pspacing - 1))};
|
||||||
|
|
||||||
|
# look for gaps
|
||||||
|
if ($Slic3r::Config->gap_fill_speed > 0 && $self->config->fill_density > 0) {
|
||||||
|
my $diff = diff_ex(
|
||||||
|
offset(\@last, -0.5*$pspacing),
|
||||||
|
offset(\@offsets, +0.5*$pspacing),
|
||||||
|
);
|
||||||
|
push @gaps, @last_gaps = grep abs($_->area) >= $gap_area_threshold, @$diff;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
last if !@offsets || $i == $loop_number;
|
last if !@offsets;
|
||||||
push @contours, @contours_offsets;
|
# clone polygons because these ExPolygons will go out of scope very soon
|
||||||
push @holes, @holes_offsets;
|
|
||||||
@last = @offsets;
|
@last = @offsets;
|
||||||
|
foreach my $polygon (@offsets) {
|
||||||
|
if ($polygon->is_counter_clockwise) {
|
||||||
|
push @contours, $polygon;
|
||||||
|
} else {
|
||||||
|
push @holes, $polygon;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
# make sure we don't infill narrow parts that are already gap-filled
|
# make sure we don't infill narrow parts that are already gap-filled
|
||||||
# (we only consider this surface's gaps to reduce the diff() complexity)
|
# (we only consider this surface's gaps to reduce the diff() complexity)
|
||||||
@last = @{diff(\@last, \@this_gaps)};
|
@last = @{diff(\@last, \@last_gaps)};
|
||||||
|
|
||||||
# create one more offset to be used as boundary for fill
|
# create one more offset to be used as boundary for fill
|
||||||
# we offset by half the perimeter spacing (to get to the actual infill boundary)
|
# we offset by half the perimeter spacing (to get to the actual infill boundary)
|
||||||
|
@ -209,8 +218,8 @@ sub make_perimeters {
|
||||||
$self->fill_surfaces->append(
|
$self->fill_surfaces->append(
|
||||||
@{offset2_ex(
|
@{offset2_ex(
|
||||||
[ map $_->simplify_as_polygons(&Slic3r::SCALED_RESOLUTION), @{union_ex(\@last)} ],
|
[ map $_->simplify_as_polygons(&Slic3r::SCALED_RESOLUTION), @{union_ex(\@last)} ],
|
||||||
-($perimeter_spacing/2 + $infill_spacing/2),
|
-($pspacing/2 + $ispacing/2),
|
||||||
+$infill_spacing/2,
|
+$ispacing/2,
|
||||||
)}
|
)}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -280,20 +289,8 @@ sub make_perimeters {
|
||||||
|
|
||||||
# detect thin walls by offsetting slices by half extrusion inwards
|
# detect thin walls by offsetting slices by half extrusion inwards
|
||||||
# and add them as perimeters
|
# and add them as perimeters
|
||||||
if ($self->config->thin_walls) {
|
if (@thin_walls) {
|
||||||
# we use spacing here because there could be a case where
|
my @p = map $_->medial_axis($pspacing), @thin_walls;
|
||||||
# the slice collapses with width but doesn't collapse with spacing,
|
|
||||||
# thus causing both perimeters and medial axis to be generated
|
|
||||||
my $width = $self->perimeter_flow->scaled_spacing;
|
|
||||||
my $diff = diff_ex(
|
|
||||||
[ map $_->p, @{$self->slices} ],
|
|
||||||
offset2([ map $_->p, @{$self->slices} ], -$width*0.5, +$width*0.5),
|
|
||||||
1,
|
|
||||||
);
|
|
||||||
|
|
||||||
my $area_threshold = $width ** 2;
|
|
||||||
if (@$diff = grep { $_->area > $area_threshold } @$diff) {
|
|
||||||
my @p = map $_->medial_axis($width), @$diff;
|
|
||||||
my @paths = ();
|
my @paths = ();
|
||||||
for my $p (@p) {
|
for my $p (@p) {
|
||||||
my %params = (
|
my %params = (
|
||||||
|
@ -312,13 +309,14 @@ sub make_perimeters {
|
||||||
|
|
||||||
# in the mean time we subtract thin walls from the detected gaps so that we don't
|
# in the mean time we subtract thin walls from the detected gaps so that we don't
|
||||||
# reprocess them, causing overlapping thin walls and zigzag.
|
# reprocess them, causing overlapping thin walls and zigzag.
|
||||||
@gaps = @{diff(
|
# Note: this is probably not necessary anymore since we're detecting thin walls
|
||||||
\@gaps,
|
# and gaps at the same time
|
||||||
|
@gaps = @{diff_ex(
|
||||||
|
[ map @$_, @gaps ],
|
||||||
[ map $_->grow($self->perimeter_flow->scaled_width), @p ],
|
[ map $_->grow($self->perimeter_flow->scaled_width), @p ],
|
||||||
1,
|
1,
|
||||||
)};
|
)};
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
$self->_fill_gaps(\@gaps);
|
$self->_fill_gaps(\@gaps);
|
||||||
}
|
}
|
||||||
|
@ -329,9 +327,6 @@ sub _fill_gaps {
|
||||||
|
|
||||||
return unless @$gaps;
|
return unless @$gaps;
|
||||||
|
|
||||||
# turn gaps into ExPolygons
|
|
||||||
$gaps = union_ex($gaps);
|
|
||||||
|
|
||||||
my $filler = $self->layer->object->fill_maker->filler('rectilinear');
|
my $filler = $self->layer->object->fill_maker->filler('rectilinear');
|
||||||
$filler->layer_id($self->layer->id);
|
$filler->layer_id($self->layer->id);
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue