mirror of
https://git.mirrors.martin98.com/https://github.com/prusa3d/PrusaSlicer.git
synced 2025-08-14 11:06:00 +08:00
Don't merge adjacent bridges so that more correct angles can be detected for each one
This commit is contained in:
parent
c69edf27e9
commit
a145f1b6aa
@ -411,11 +411,30 @@ sub prepare_fill_surfaces {
|
||||
sub process_external_surfaces {
|
||||
my $self = shift;
|
||||
|
||||
# enlarge top and bottom surfaces
|
||||
{
|
||||
# get all external surfaces
|
||||
my @top = grep $_->surface_type == S_TYPE_TOP, @{$self->fill_surfaces};
|
||||
my @bottom = grep $_->surface_type == S_TYPE_BOTTOM, @{$self->fill_surfaces};
|
||||
my $margin = scale 3; # TODO: ensure this is greater than the total thickness of the perimeters
|
||||
|
||||
my @bottom = ();
|
||||
foreach my $surface (grep $_->surface_type == S_TYPE_BOTTOM, @{$self->fill_surfaces}) {
|
||||
my ($grown) = $surface->expolygon->offset_ex(+$margin);
|
||||
|
||||
# detect bridge direction before merging grown surfaces otherwise adjacent bridges
|
||||
# would get merged into a single one while they need different directions
|
||||
my $angle = $self->id > 0
|
||||
? $self->_detect_bridge_direction($grown)
|
||||
: undef;
|
||||
|
||||
push @bottom, $surface->clone(expolygon => $grown, bridge_angle => $angle);
|
||||
}
|
||||
|
||||
my @top = ();
|
||||
foreach my $surface (grep $_->surface_type == S_TYPE_TOP, @{$self->fill_surfaces}) {
|
||||
# give priority to bottom surfaces
|
||||
my $grown = diff_ex(
|
||||
[ $surface->expolygon->offset(+$margin) ],
|
||||
[ map $_->p, @bottom ],
|
||||
);
|
||||
push @top, map $surface->clone(expolygon => $_), @$grown;
|
||||
}
|
||||
|
||||
# if we're slicing with no infill, we can't extend external surfaces
|
||||
# over non-existent infill
|
||||
@ -423,37 +442,18 @@ sub process_external_surfaces {
|
||||
? @{$self->fill_surfaces}
|
||||
: grep $_->surface_type != S_TYPE_INTERNAL, @{$self->fill_surfaces};
|
||||
|
||||
# offset them and intersect the results with the actual fill boundaries
|
||||
my $margin = scale 3; # TODO: ensure this is greater than the total thickness of the perimeters
|
||||
@top = @{intersection_ex(
|
||||
[ Slic3r::Geometry::Clipper::offset([ map $_->p, @top ], +$margin) ],
|
||||
[ map $_->p, @fill_boundaries ],
|
||||
undef,
|
||||
1, # to ensure adjacent expolygons are unified
|
||||
)};
|
||||
@bottom = @{intersection_ex(
|
||||
[ Slic3r::Geometry::Clipper::offset([ map $_->p, @bottom ], +$margin) ],
|
||||
[ map $_->p, @fill_boundaries ],
|
||||
undef,
|
||||
1, # to ensure adjacent expolygons are unified
|
||||
)};
|
||||
|
||||
# give priority to bottom surfaces
|
||||
@top = @{diff_ex(
|
||||
[ map @$_, @top ],
|
||||
[ map @$_, @bottom ],
|
||||
)};
|
||||
|
||||
# generate new surfaces
|
||||
# intersect the grown surfaces with the actual fill boundaries
|
||||
my @new_surfaces = ();
|
||||
push @new_surfaces, map Slic3r::Surface->new(
|
||||
expolygon => $_,
|
||||
surface_type => S_TYPE_TOP,
|
||||
), @top;
|
||||
push @new_surfaces, map Slic3r::Surface->new(
|
||||
expolygon => $_,
|
||||
surface_type => S_TYPE_BOTTOM,
|
||||
), @bottom;
|
||||
foreach my $group (Slic3r::Surface->group(@top, @bottom)) {
|
||||
push @new_surfaces,
|
||||
map $group->[0]->clone(expolygon => $_),
|
||||
@{intersection_ex(
|
||||
[ map $_->p, @$group ],
|
||||
[ map $_->p, @fill_boundaries ],
|
||||
undef,
|
||||
1, # to ensure adjacent expolygons are unified
|
||||
)};
|
||||
}
|
||||
|
||||
# subtract the new top surfaces from the other non-top surfaces and re-add them
|
||||
my @other = grep $_->surface_type != S_TYPE_TOP && $_->surface_type != S_TYPE_BOTTOM, @{$self->fill_surfaces};
|
||||
@ -464,25 +464,20 @@ sub process_external_surfaces {
|
||||
)};
|
||||
}
|
||||
@{$self->fill_surfaces} = @new_surfaces;
|
||||
}
|
||||
|
||||
# detect bridge direction (skip bottom layer)
|
||||
$self->_detect_bridges if $self->id > 0;
|
||||
}
|
||||
|
||||
sub _detect_bridges {
|
||||
sub _detect_bridge_direction {
|
||||
my $self = shift;
|
||||
my ($expolygon) = @_;
|
||||
|
||||
my @bottom = grep $_->surface_type == S_TYPE_BOTTOM, @{$self->fill_surfaces}; # surfaces
|
||||
my @lower = @{$self->layer->object->layers->[ $self->id - 1 ]->slices}; # expolygons
|
||||
|
||||
foreach my $surface (@bottom) {
|
||||
# detect what edges lie on lower slices
|
||||
my @edges = (); # polylines
|
||||
foreach my $lower (@lower) {
|
||||
# turn bridge contour and holes into polylines and then clip them
|
||||
# with each lower slice's contour
|
||||
my @clipped = map $_->split_at_first_point->clip_with_polygon($lower->contour), @{$surface->expolygon};
|
||||
my @clipped = map $_->split_at_first_point->clip_with_polygon($lower->contour), @$expolygon;
|
||||
if (@clipped == 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
|
||||
@ -499,14 +494,14 @@ sub _detect_bridges {
|
||||
}
|
||||
|
||||
Slic3r::debugf "Found bridge on layer %d with %d support(s)\n", $self->id, scalar(@edges);
|
||||
next if !@edges;
|
||||
return undef if !@edges;
|
||||
|
||||
my $bridge_angle = undef;
|
||||
|
||||
if (0) {
|
||||
require "Slic3r/SVG.pm";
|
||||
Slic3r::SVG::output("bridge_$surface.svg",
|
||||
expolygons => [ $surface->expolygon ],
|
||||
Slic3r::SVG::output("bridge_$expolygon.svg",
|
||||
expolygons => [ $expolygon ],
|
||||
red_expolygons => [ @lower ],
|
||||
polylines => [ @edges ],
|
||||
);
|
||||
@ -529,11 +524,11 @@ sub _detect_bridges {
|
||||
}
|
||||
} elsif (@edges) {
|
||||
# inset the bridge expolygon; we'll use this one to clip our test lines
|
||||
my $inset = [ $surface->expolygon->offset_ex($self->infill_flow->scaled_width) ];
|
||||
my $inset = [ $expolygon->offset_ex($self->infill_flow->scaled_width) ];
|
||||
|
||||
# detect anchors as intersection between our bridge expolygon and the lower slices
|
||||
my $anchors = intersection_ex(
|
||||
[ $surface->p ],
|
||||
[ @$expolygon ],
|
||||
[ map @$_, @lower ],
|
||||
undef,
|
||||
1, # safety offset required to avoid Clipper from detecting empty intersection while Boost actually found some @edges
|
||||
@ -580,8 +575,7 @@ sub _detect_bridges {
|
||||
Slic3r::debugf " Optimal infill angle of bridge on layer %d is %d degrees\n",
|
||||
$self->id, $bridge_angle if defined $bridge_angle;
|
||||
|
||||
$surface->bridge_angle($bridge_angle);
|
||||
}
|
||||
return $bridge_angle;
|
||||
}
|
||||
|
||||
1;
|
||||
|
Loading…
x
Reference in New Issue
Block a user