mirror of
https://git.mirrors.martin98.com/https://github.com/prusa3d/PrusaSlicer.git
synced 2025-05-29 09:37:23 +08:00
Bugfix: some bridges were not detected correctly. #57
This commit is contained in:
parent
52270d6b95
commit
b03afc7f1c
@ -51,8 +51,8 @@ sub make_fill {
|
|||||||
# merge overlapping surfaces
|
# merge overlapping surfaces
|
||||||
my @surfaces = ();
|
my @surfaces = ();
|
||||||
{
|
{
|
||||||
my @surfaces_with_bridge_angle = grep defined $_->bridge_angle, @{$layer->surfaces};
|
my @surfaces_with_bridge_angle = grep defined $_->bridge_angle, @{$layer->fill_surfaces};
|
||||||
foreach my $group (Slic3r::Surface->group({merge_solid => 1}, @{$layer->surfaces})) {
|
foreach my $group (Slic3r::Surface->group({merge_solid => 1}, @{$layer->fill_surfaces})) {
|
||||||
my $union = union_ex([ map $_->p, @$group ]);
|
my $union = union_ex([ map $_->p, @$group ]);
|
||||||
|
|
||||||
# subtract surfaces having a defined bridge_angle from any other
|
# subtract surfaces having a defined bridge_angle from any other
|
||||||
@ -90,7 +90,7 @@ sub make_fill {
|
|||||||
my $is_solid = $surface->surface_type =~ /^(top|bottom)$/;
|
my $is_solid = $surface->surface_type =~ /^(top|bottom)$/;
|
||||||
|
|
||||||
# force 100% density and rectilinear fill for external surfaces
|
# force 100% density and rectilinear fill for external surfaces
|
||||||
if (($surface->surface_type ne 'internal') && ($Slic3r::solid_layers >= 1)) {
|
if ($surface->surface_type ne 'internal') {
|
||||||
$density = 1;
|
$density = 1;
|
||||||
$filler = $is_bridge ? 'rectilinear' : $Slic3r::solid_fill_pattern;
|
$filler = $is_bridge ? 'rectilinear' : $Slic3r::solid_fill_pattern;
|
||||||
$flow_width = $Slic3r::nozzle_diameter if $is_bridge;
|
$flow_width = $Slic3r::nozzle_diameter if $is_bridge;
|
||||||
|
@ -30,6 +30,13 @@ has 'surfaces' => (
|
|||||||
default => sub { [] },
|
default => sub { [] },
|
||||||
);
|
);
|
||||||
|
|
||||||
|
# collection of surfaces for infill
|
||||||
|
has 'fill_surfaces' => (
|
||||||
|
is => 'rw',
|
||||||
|
#isa => 'ArrayRef[Slic3r::Surface]',
|
||||||
|
default => sub { [] },
|
||||||
|
);
|
||||||
|
|
||||||
# ordered collection of extrusion paths to build all perimeters
|
# ordered collection of extrusion paths to build all perimeters
|
||||||
has 'perimeters' => (
|
has 'perimeters' => (
|
||||||
is => 'rw',
|
is => 'rw',
|
||||||
@ -77,24 +84,6 @@ sub print_z {
|
|||||||
+ ($self->id * $Slic3r::layer_height)) / $Slic3r::resolution;
|
+ ($self->id * $Slic3r::layer_height)) / $Slic3r::resolution;
|
||||||
}
|
}
|
||||||
|
|
||||||
sub add_surface {
|
|
||||||
my $self = shift;
|
|
||||||
my (@vertices) = @_;
|
|
||||||
|
|
||||||
# convert arrayref points to Point objects
|
|
||||||
@vertices = map Slic3r::Point->new($_), @vertices;
|
|
||||||
|
|
||||||
my $surface = Slic3r::Surface->new(
|
|
||||||
contour => Slic3r::Polyline::Closed->new(points => \@vertices),
|
|
||||||
);
|
|
||||||
push @{ $self->surfaces }, $surface;
|
|
||||||
|
|
||||||
# make sure our contour has its points in counter-clockwise order
|
|
||||||
$surface->contour->make_counter_clockwise;
|
|
||||||
|
|
||||||
return $surface;
|
|
||||||
}
|
|
||||||
|
|
||||||
sub add_line {
|
sub add_line {
|
||||||
my $self = shift;
|
my $self = shift;
|
||||||
my ($line) = @_;
|
my ($line) = @_;
|
||||||
@ -125,14 +114,52 @@ sub make_surfaces {
|
|||||||
#);
|
#);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sub prepare_fill_surfaces {
|
||||||
|
my $self = shift;
|
||||||
|
|
||||||
|
my @surfaces = @{$self->surfaces};
|
||||||
|
|
||||||
|
# merge too small internal surfaces with their surrounding tops
|
||||||
|
# (if they're too small, they can be treated as solid)
|
||||||
|
{
|
||||||
|
my $min_area = ((7 * $Slic3r::flow_width / $Slic3r::resolution)**2) * PI;
|
||||||
|
my $small_internal = [
|
||||||
|
grep { $_->expolygon->contour->area <= $min_area }
|
||||||
|
grep { $_->surface_type eq 'internal' }
|
||||||
|
@surfaces
|
||||||
|
];
|
||||||
|
foreach my $s (@$small_internal) {
|
||||||
|
@surfaces = grep $_ ne $s, @surfaces;
|
||||||
|
}
|
||||||
|
my $union = union_ex([
|
||||||
|
(map $_->p, grep $_->surface_type eq 'top', @surfaces),
|
||||||
|
(map @$_, map $_->expolygon->safety_offset, @$small_internal),
|
||||||
|
]);
|
||||||
|
my @top = map Slic3r::Surface->cast_from_expolygon($_, surface_type => 'top'), @$union;
|
||||||
|
@surfaces = (grep($_->surface_type ne 'top', @surfaces), @top);
|
||||||
|
}
|
||||||
|
|
||||||
|
# remove top/bottom surfaces
|
||||||
|
if ($Slic3r::solid_layers == 0) {
|
||||||
|
@surfaces = grep $_->surface_type eq 'internal', @surfaces;
|
||||||
|
}
|
||||||
|
|
||||||
|
# remove internal surfaces
|
||||||
|
if ($Slic3r::fill_density == 0) {
|
||||||
|
@surfaces = grep $_->surface_type ne 'internal', @surfaces;
|
||||||
|
}
|
||||||
|
|
||||||
|
$self->fill_surfaces([@surfaces]);
|
||||||
|
}
|
||||||
|
|
||||||
sub remove_small_surfaces {
|
sub remove_small_surfaces {
|
||||||
my $self = shift;
|
my $self = shift;
|
||||||
my @good_surfaces = ();
|
my @good_surfaces = ();
|
||||||
|
|
||||||
my $distance = ($Slic3r::flow_width / 2 / $Slic3r::resolution);
|
my $distance = ($Slic3r::flow_width / 2 / $Slic3r::resolution);
|
||||||
|
|
||||||
my @surfaces = @{$self->surfaces};
|
my @surfaces = @{$self->fill_surfaces};
|
||||||
@{$self->surfaces} = ();
|
@{$self->fill_surfaces} = ();
|
||||||
foreach my $surface (@surfaces) {
|
foreach my $surface (@surfaces) {
|
||||||
# offset inwards
|
# offset inwards
|
||||||
my @offsets = $surface->expolygon->offset_ex(-$distance);
|
my @offsets = $surface->expolygon->offset_ex(-$distance);
|
||||||
@ -144,13 +171,13 @@ sub remove_small_surfaces {
|
|||||||
# the difference between $surface->expolygon and @offsets
|
# the difference between $surface->expolygon and @offsets
|
||||||
# is what we can't print since it's too small
|
# is what we can't print since it's too small
|
||||||
|
|
||||||
push @{$self->surfaces}, map Slic3r::Surface->cast_from_expolygon($_,
|
push @{$self->fill_surfaces}, map Slic3r::Surface->cast_from_expolygon($_,
|
||||||
surface_type => $surface->surface_type), @offsets;
|
surface_type => $surface->surface_type), @offsets;
|
||||||
}
|
}
|
||||||
|
|
||||||
Slic3r::debugf "removed %d small surfaces at layer %d\n",
|
Slic3r::debugf "removed %d small surfaces at layer %d\n",
|
||||||
(@surfaces - @{$self->surfaces}), $self->id
|
(@surfaces - @{$self->fill_surfaces}), $self->id
|
||||||
if @{$self->surfaces} != @surfaces;
|
if @{$self->fill_surfaces} != @surfaces;
|
||||||
}
|
}
|
||||||
|
|
||||||
sub remove_small_perimeters {
|
sub remove_small_perimeters {
|
||||||
@ -178,7 +205,7 @@ sub process_bridges {
|
|||||||
|
|
||||||
my @solid_surfaces = grep {
|
my @solid_surfaces = grep {
|
||||||
($_->surface_type eq 'bottom' && $self->id > 0) || $_->surface_type eq 'top'
|
($_->surface_type eq 'bottom' && $self->id > 0) || $_->surface_type eq 'top'
|
||||||
} @{$self->surfaces} or return;
|
} @{$self->fill_surfaces} or return;
|
||||||
|
|
||||||
my @internal_surfaces = grep $_->surface_type =~ /internal/, @{$self->surfaces};
|
my @internal_surfaces = grep $_->surface_type =~ /internal/, @{$self->surfaces};
|
||||||
|
|
||||||
@ -197,11 +224,13 @@ sub process_bridges {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#use Slic3r::SVG;
|
if (0) {
|
||||||
#Slic3r::SVG::output(undef, "bridge.svg",
|
require "Slic3r/SVG.pm";
|
||||||
# green_polygons => [ map $_->p, @supporting_surfaces ],
|
Slic3r::SVG::output(undef, "bridge.svg",
|
||||||
# red_polygons => [ @$expolygon ],
|
green_polygons => [ map $_->p, @supporting_surfaces ],
|
||||||
#);
|
red_polygons => [ @$expolygon ],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
next SURFACE unless @supporting_surfaces;
|
next SURFACE unless @supporting_surfaces;
|
||||||
Slic3r::debugf " Found $description on layer %d with %d support(s)\n",
|
Slic3r::debugf " Found $description on layer %d with %d support(s)\n",
|
||||||
@ -215,7 +244,8 @@ sub process_bridges {
|
|||||||
my @edges = (); # edges are POLYLINES
|
my @edges = (); # edges are POLYLINES
|
||||||
foreach my $supporting_surface (@supporting_surfaces) {
|
foreach my $supporting_surface (@supporting_surfaces) {
|
||||||
my @surface_edges = $supporting_surface->contour->clip_with_polygon($contour_offset);
|
my @surface_edges = $supporting_surface->contour->clip_with_polygon($contour_offset);
|
||||||
if (@surface_edges == 1 && @{$supporting_surface->contour->p} == @{$surface_edges[0]->p}) {
|
if (@supporting_surfaces == 1 && @surface_edges == 1
|
||||||
|
&& @{$supporting_surface->contour->p} == @{$surface_edges[0]->p}) {
|
||||||
$bridge_over_hole = 1;
|
$bridge_over_hole = 1;
|
||||||
} else {
|
} else {
|
||||||
foreach my $edge (@surface_edges) {
|
foreach my $edge (@surface_edges) {
|
||||||
@ -234,6 +264,7 @@ sub process_bridges {
|
|||||||
Slic3r::SVG::output(undef, "bridge.svg",
|
Slic3r::SVG::output(undef, "bridge.svg",
|
||||||
polylines => [ map $_->p, @edges ],
|
polylines => [ map $_->p, @edges ],
|
||||||
);
|
);
|
||||||
|
exit if $self->id == 30;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (@edges == 2) {
|
if (@edges == 2) {
|
||||||
@ -288,8 +319,8 @@ sub process_bridges {
|
|||||||
|
|
||||||
# apply bridges to layer
|
# apply bridges to layer
|
||||||
{
|
{
|
||||||
my @surfaces = @{$self->surfaces};
|
my @surfaces = @{$self->fill_surfaces};
|
||||||
@{$self->surfaces} = ();
|
@{$self->fill_surfaces} = ();
|
||||||
|
|
||||||
# intersect layer surfaces with bridges to get actual bridges
|
# intersect layer surfaces with bridges to get actual bridges
|
||||||
foreach my $bridge (@bridges) {
|
foreach my $bridge (@bridges) {
|
||||||
@ -298,7 +329,7 @@ sub process_bridges {
|
|||||||
[ $bridge->p ],
|
[ $bridge->p ],
|
||||||
);
|
);
|
||||||
|
|
||||||
push @{$self->surfaces}, map Slic3r::Surface->cast_from_expolygon($_,
|
push @{$self->fill_surfaces}, map Slic3r::Surface->cast_from_expolygon($_,
|
||||||
surface_type => $bridge->surface_type,
|
surface_type => $bridge->surface_type,
|
||||||
bridge_angle => $bridge->bridge_angle,
|
bridge_angle => $bridge->bridge_angle,
|
||||||
), @$actual_bridge;
|
), @$actual_bridge;
|
||||||
@ -310,7 +341,7 @@ sub process_bridges {
|
|||||||
[ map $_->p, @$group ],
|
[ map $_->p, @$group ],
|
||||||
[ map $_->p, @bridges ],
|
[ map $_->p, @bridges ],
|
||||||
);
|
);
|
||||||
push @{$self->surfaces}, map Slic3r::Surface->cast_from_expolygon($_,
|
push @{$self->fill_surfaces}, map Slic3r::Surface->cast_from_expolygon($_,
|
||||||
surface_type => $group->[0]->surface_type), @$difference;
|
surface_type => $group->[0]->surface_type), @$difference;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -205,14 +205,7 @@ sub detect_surfaces_type {
|
|||||||
# find top surfaces (difference between current surfaces
|
# find top surfaces (difference between current surfaces
|
||||||
# of current layer and upper one)
|
# of current layer and upper one)
|
||||||
if ($upper_layer) {
|
if ($upper_layer) {
|
||||||
# only consider those upper surfaces that are not small
|
@top = $surface_difference->($layer->surfaces, $upper_layer->surfaces, 'top');
|
||||||
# (if they're too small, the interface with them can be treated
|
|
||||||
# like a continuous solid surface instead of cutting a little
|
|
||||||
# internal surface in it)
|
|
||||||
my $min_area = ((7 * $Slic3r::flow_width / $Slic3r::resolution)**2) * PI;
|
|
||||||
my $upper_surfaces = [ grep { $_->expolygon->contour->area > $min_area } @{$upper_layer->surfaces} ];
|
|
||||||
|
|
||||||
@top = $surface_difference->($layer->surfaces, $upper_surfaces, 'top');
|
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
# if no upper layer, all surfaces of this one are solid
|
# if no upper layer, all surfaces of this one are solid
|
||||||
@ -275,7 +268,7 @@ sub discover_horizontal_shells {
|
|||||||
my $layer = $self->layers->[$i];
|
my $layer = $self->layers->[$i];
|
||||||
foreach my $type (qw(top bottom)) {
|
foreach my $type (qw(top bottom)) {
|
||||||
# find surfaces of current type for current layer
|
# find surfaces of current type for current layer
|
||||||
my @surfaces = grep $_->surface_type eq $type, @{$layer->surfaces} or next;
|
my @surfaces = grep $_->surface_type eq $type, @{$layer->fill_surfaces} or next;
|
||||||
my $surfaces_p = [ map $_->p, @surfaces ];
|
my $surfaces_p = [ map $_->p, @surfaces ];
|
||||||
Slic3r::debugf "Layer %d has %d surfaces of type '%s'\n",
|
Slic3r::debugf "Layer %d has %d surfaces of type '%s'\n",
|
||||||
$i, scalar(@surfaces), $type;
|
$i, scalar(@surfaces), $type;
|
||||||
@ -287,7 +280,7 @@ sub discover_horizontal_shells {
|
|||||||
next if $n < 0 || $n >= $self->layer_count;
|
next if $n < 0 || $n >= $self->layer_count;
|
||||||
Slic3r::debugf " looking for neighbors on layer %d...\n", $n;
|
Slic3r::debugf " looking for neighbors on layer %d...\n", $n;
|
||||||
|
|
||||||
my $surfaces = $self->layers->[$n]->surfaces;
|
my $surfaces = $self->layers->[$n]->fill_surfaces;
|
||||||
my @neighbor = @$surfaces;
|
my @neighbor = @$surfaces;
|
||||||
|
|
||||||
# find intersection between @surfaces and current layer's surfaces
|
# find intersection between @surfaces and current layer's surfaces
|
||||||
@ -378,7 +371,7 @@ sub infill_every_layers {
|
|||||||
my $layer = $self->layer($i);
|
my $layer = $self->layer($i);
|
||||||
|
|
||||||
# skip layer if no internal fill surfaces
|
# skip layer if no internal fill surfaces
|
||||||
next if !grep $_->surface_type eq 'internal', @{$layer->surfaces};
|
next if !grep $_->surface_type eq 'internal', @{$layer->fill_surfaces};
|
||||||
|
|
||||||
# for each possible depth, look for intersections with the lower layer
|
# for each possible depth, look for intersections with the lower layer
|
||||||
# we do this from the greater depth to the smaller
|
# we do this from the greater depth to the smaller
|
||||||
@ -388,13 +381,13 @@ sub infill_every_layers {
|
|||||||
|
|
||||||
# select surfaces of the lower layer having the depth we're looking for
|
# select surfaces of the lower layer having the depth we're looking for
|
||||||
my @lower_surfaces = grep $_->depth_layers == $d && $_->surface_type eq 'internal',
|
my @lower_surfaces = grep $_->depth_layers == $d && $_->surface_type eq 'internal',
|
||||||
@{$lower_layer->surfaces};
|
@{$lower_layer->fill_surfaces};
|
||||||
next if !@lower_surfaces;
|
next if !@lower_surfaces;
|
||||||
|
|
||||||
# calculate intersection between our surfaces and theirs
|
# calculate intersection between our surfaces and theirs
|
||||||
my $intersection = intersection_ex(
|
my $intersection = intersection_ex(
|
||||||
[ map $_->p, grep $_->depth_layers <= $d, @lower_surfaces ],
|
[ map $_->p, grep $_->depth_layers <= $d, @lower_surfaces ],
|
||||||
[ map $_->p, grep $_->surface_type eq 'internal', @{$layer->surfaces} ],
|
[ map $_->p, grep $_->surface_type eq 'internal', @{$layer->fill_surfaces} ],
|
||||||
);
|
);
|
||||||
next if !@$intersection;
|
next if !@$intersection;
|
||||||
my $intersection_offsetted = safety_offset([ map @$_, @$intersection ]);
|
my $intersection_offsetted = safety_offset([ map @$_, @$intersection ]);
|
||||||
@ -405,7 +398,7 @@ sub infill_every_layers {
|
|||||||
# - any internal surface not belonging to the intersection (with its original depth)
|
# - any internal surface not belonging to the intersection (with its original depth)
|
||||||
{
|
{
|
||||||
my @new_surfaces = ();
|
my @new_surfaces = ();
|
||||||
push @new_surfaces, grep $_->surface_type ne 'internal', @{$layer->surfaces};
|
push @new_surfaces, grep $_->surface_type ne 'internal', @{$layer->fill_surfaces};
|
||||||
push @new_surfaces, map Slic3r::Surface->cast_from_expolygon
|
push @new_surfaces, map Slic3r::Surface->cast_from_expolygon
|
||||||
($_, surface_type => 'internal', depth_layers => $d + 1), @$intersection;
|
($_, surface_type => 'internal', depth_layers => $d + 1), @$intersection;
|
||||||
|
|
||||||
@ -418,18 +411,18 @@ sub infill_every_layers {
|
|||||||
@{diff_ex(
|
@{diff_ex(
|
||||||
[
|
[
|
||||||
map $_->p, grep $_->surface_type eq 'internal' && $_->depth_layers == $depth,
|
map $_->p, grep $_->surface_type eq 'internal' && $_->depth_layers == $depth,
|
||||||
@{$layer->surfaces},
|
@{$layer->fill_surfaces},
|
||||||
],
|
],
|
||||||
$intersection_offsetted,
|
$intersection_offsetted,
|
||||||
)};
|
)};
|
||||||
}
|
}
|
||||||
@{$layer->surfaces} = @new_surfaces;
|
@{$layer->fill_surfaces} = @new_surfaces;
|
||||||
}
|
}
|
||||||
|
|
||||||
# now we remove the intersections from lower layer
|
# now we remove the intersections from lower layer
|
||||||
{
|
{
|
||||||
my @new_surfaces = ();
|
my @new_surfaces = ();
|
||||||
push @new_surfaces, grep $_->surface_type ne 'internal', @{$lower_layer->surfaces};
|
push @new_surfaces, grep $_->surface_type ne 'internal', @{$lower_layer->fill_surfaces};
|
||||||
foreach my $depth (1..$Slic3r::infill_every_layers) {
|
foreach my $depth (1..$Slic3r::infill_every_layers) {
|
||||||
push @new_surfaces, map Slic3r::Surface->cast_from_expolygon
|
push @new_surfaces, map Slic3r::Surface->cast_from_expolygon
|
||||||
($_, surface_type => 'internal', depth_layers => $depth),
|
($_, surface_type => 'internal', depth_layers => $depth),
|
||||||
@ -439,12 +432,12 @@ sub infill_every_layers {
|
|||||||
@{diff_ex(
|
@{diff_ex(
|
||||||
[
|
[
|
||||||
map $_->p, grep $_->surface_type eq 'internal' && $_->depth_layers == $depth,
|
map $_->p, grep $_->surface_type eq 'internal' && $_->depth_layers == $depth,
|
||||||
@{$lower_layer->surfaces},
|
@{$lower_layer->fill_surfaces},
|
||||||
],
|
],
|
||||||
$intersection_offsetted,
|
$intersection_offsetted,
|
||||||
)};
|
)};
|
||||||
}
|
}
|
||||||
@{$lower_layer->surfaces} = @new_surfaces;
|
@{$lower_layer->fill_surfaces} = @new_surfaces;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -45,6 +45,10 @@ sub go {
|
|||||||
$self->status_cb->(30, "Detecting solid surfaces...");
|
$self->status_cb->(30, "Detecting solid surfaces...");
|
||||||
$print->detect_surfaces_type;
|
$print->detect_surfaces_type;
|
||||||
|
|
||||||
|
# prepare fill surfaces
|
||||||
|
$self->status_cb->(35, "Preparing infill surfaces...");
|
||||||
|
$_->prepare_fill_surfaces for @{$print->layers};
|
||||||
|
|
||||||
# this will remove unprintable surfaces
|
# this will remove unprintable surfaces
|
||||||
# (those that are too tight for extrusion)
|
# (those that are too tight for extrusion)
|
||||||
$self->status_cb->(40, "Cleaning up...");
|
$self->status_cb->(40, "Cleaning up...");
|
||||||
|
@ -60,8 +60,8 @@ sub group {
|
|||||||
my $type = ($params->{merge_solid} && $surface->surface_type =~ /top|bottom|solid/)
|
my $type = ($params->{merge_solid} && $surface->surface_type =~ /top|bottom|solid/)
|
||||||
? 'solid'
|
? 'solid'
|
||||||
: $surface->surface_type;
|
: $surface->surface_type;
|
||||||
$type .= "_" . ($_[0]->bridge_angle || '');
|
$type .= "_" . ($surface->bridge_angle || '');
|
||||||
$type .= "_" . $_[0]->depth_layers;
|
$type .= "_" . $surface->depth_layers;
|
||||||
$unique_types{$type} ||= [];
|
$unique_types{$type} ||= [];
|
||||||
push @{ $unique_types{$type} }, $surface;
|
push @{ $unique_types{$type} }, $surface;
|
||||||
}
|
}
|
||||||
|
@ -68,7 +68,7 @@ sub make_loops {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
my $sparse_lines = [ map $_->line, @lines ];
|
my $sparse_lines = [ map $_->line, grep $_, @lines ];
|
||||||
|
|
||||||
# detect closed loops
|
# detect closed loops
|
||||||
if (0) {
|
if (0) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user