Don't merge adjacent bridges so that more correct angles can be detected for each one

This commit is contained in:
Alessandro Ranellucci 2013-07-26 12:31:25 +02:00
parent c69edf27e9
commit a145f1b6aa

View File

@ -411,11 +411,30 @@ sub prepare_fill_surfaces {
sub process_external_surfaces { sub process_external_surfaces {
my $self = shift; my $self = shift;
# enlarge top and bottom surfaces my $margin = scale 3; # TODO: ensure this is greater than the total thickness of the perimeters
{
# get all external surfaces my @bottom = ();
my @top = grep $_->surface_type == S_TYPE_TOP, @{$self->fill_surfaces}; foreach my $surface (grep $_->surface_type == S_TYPE_BOTTOM, @{$self->fill_surfaces}) {
my @bottom = 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 # if we're slicing with no infill, we can't extend external surfaces
# over non-existent infill # over non-existent infill
@ -423,37 +442,18 @@ sub process_external_surfaces {
? @{$self->fill_surfaces} ? @{$self->fill_surfaces}
: grep $_->surface_type != S_TYPE_INTERNAL, @{$self->fill_surfaces}; : grep $_->surface_type != S_TYPE_INTERNAL, @{$self->fill_surfaces};
# offset them and intersect the results with the actual fill boundaries # intersect the grown surfaces 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
my @new_surfaces = (); my @new_surfaces = ();
push @new_surfaces, map Slic3r::Surface->new( foreach my $group (Slic3r::Surface->group(@top, @bottom)) {
expolygon => $_, push @new_surfaces,
surface_type => S_TYPE_TOP, map $group->[0]->clone(expolygon => $_),
), @top; @{intersection_ex(
push @new_surfaces, map Slic3r::Surface->new( [ map $_->p, @$group ],
expolygon => $_, [ map $_->p, @fill_boundaries ],
surface_type => S_TYPE_BOTTOM, undef,
), @bottom; 1, # to ensure adjacent expolygons are unified
)};
}
# subtract the new top surfaces from the other non-top surfaces and re-add them # 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}; 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; @{$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 $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 my @lower = @{$self->layer->object->layers->[ $self->id - 1 ]->slices}; # expolygons
foreach my $surface (@bottom) {
# detect what edges lie on lower slices # detect what edges lie on lower slices
my @edges = (); # polylines my @edges = (); # polylines
foreach my $lower (@lower) { foreach my $lower (@lower) {
# turn bridge contour and holes into polylines and then clip them # turn bridge contour and holes into polylines and then clip them
# with each lower slice's contour # 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 (@clipped == 2) {
# If the split_at_first_point() call above happens to split the polygon inside the clipping area # 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 # 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); 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; my $bridge_angle = undef;
if (0) { if (0) {
require "Slic3r/SVG.pm"; require "Slic3r/SVG.pm";
Slic3r::SVG::output("bridge_$surface.svg", Slic3r::SVG::output("bridge_$expolygon.svg",
expolygons => [ $surface->expolygon ], expolygons => [ $expolygon ],
red_expolygons => [ @lower ], red_expolygons => [ @lower ],
polylines => [ @edges ], polylines => [ @edges ],
); );
@ -529,11 +524,11 @@ sub _detect_bridges {
} }
} elsif (@edges) { } elsif (@edges) {
# inset the bridge expolygon; we'll use this one to clip our test lines # 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 # detect anchors as intersection between our bridge expolygon and the lower slices
my $anchors = intersection_ex( my $anchors = intersection_ex(
[ $surface->p ], [ @$expolygon ],
[ map @$_, @lower ], [ map @$_, @lower ],
undef, undef,
1, # safety offset required to avoid Clipper from detecting empty intersection while Boost actually found some @edges 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", Slic3r::debugf " Optimal infill angle of bridge on layer %d is %d degrees\n",
$self->id, $bridge_angle if defined $bridge_angle; $self->id, $bridge_angle if defined $bridge_angle;
$surface->bridge_angle($bridge_angle); return $bridge_angle;
}
} }
1; 1;