Better bridge direction detection. #1068

This commit is contained in:
Alessandro Ranellucci 2013-03-29 23:49:58 +01:00
parent 5beb2187d3
commit d4119b0eb1

View File

@ -1,8 +1,9 @@
package Slic3r::Layer::Region; package Slic3r::Layer::Region;
use Moo; use Moo;
use List::Util qw(sum first);
use Slic3r::ExtrusionPath ':roles'; use Slic3r::ExtrusionPath ':roles';
use Slic3r::Geometry qw(PI scale chained_path_items points_coincide); use Slic3r::Geometry qw(PI X1 X2 Y1 Y2 A B scale chained_path_items points_coincide);
use Slic3r::Geometry::Clipper qw(safety_offset union_ex diff_ex intersection_ex); use Slic3r::Geometry::Clipper qw(safety_offset union_ex diff_ex intersection_ex);
use Slic3r::Surface ':types'; use Slic3r::Surface ':types';
@ -556,9 +557,9 @@ sub process_external_surfaces {
if (0) { if (0) {
require "Slic3r/SVG.pm"; require "Slic3r/SVG.pm";
Slic3r::SVG::output("bridge.svg", Slic3r::SVG::output("bridge_$surface.svg",
polygons => [ $surface->p ], expolygons => [ $surface->expolygon ],
red_polygons => [ map @$_, @lower ], red_expolygons => [ @lower ],
polylines => [ @edges ], polylines => [ @edges ],
); );
} }
@ -579,16 +580,51 @@ sub process_external_surfaces {
$bridge_angle = Slic3r::Geometry::rad2deg_dir($line->direction); $bridge_angle = Slic3r::Geometry::rad2deg_dir($line->direction);
} }
} elsif (@edges) { } elsif (@edges) {
my $center = Slic3r::Geometry::bounding_box_center([ map @$_, @edges ]); # inset the bridge expolygon; we'll use this one to clip our test lines
my $x = my $y = 0; my $inset = [ $surface->expolygon->offset_ex($self->infill_flow->scaled_width) ];
foreach my $point (map @$_, @edges) {
my $line = Slic3r::Line->new($center, $point); # detect anchors as intersection between our bridge expolygon and the lower slices
my $dir = $line->direction; my $anchors = intersection_ex(
my $len = $line->length; [ $surface->p ],
$x += cos($dir) * $len; [ map @$_, @lower ],
$y += sin($dir) * $len; );
# we'll now try several directions using a rudimentary visibility check:
# bridge in several directions and then sum the length of lines having both
# endpoints within anchors
my %directions = (); # angle => score
my $angle_increment = PI/36; # 5°
my $line_increment = $self->infill_flow->scaled_width;
for (my $angle = 0; $angle <= PI; $angle += $angle_increment) {
# rotate everything - the center point doesn't matter
$_->rotate($angle, [0,0]) for @$inset, @$anchors;
# generate lines in this direction
my $bounding_box = [ Slic3r::Geometry::bounding_box([ map @$_, map @$_, @$anchors ]) ];
my @lines = ();
for (my $x = $bounding_box->[X1]; $x <= $bounding_box->[X2]; $x += $line_increment) {
push @lines, [ [$x, $bounding_box->[Y1]], [$x, $bounding_box->[Y2]] ];
}
# TODO: use a multi_polygon_multi_linestring_intersection() call
my @clipped_lines = map @{ Boost::Geometry::Utils::polygon_multi_linestring_intersection($_, \@lines) }, @$inset;
# remove any line not having both endpoints within anchors
@clipped_lines = grep {
my $line = $_;
!(first { $_->encloses_point_quick($line->[A]) } @$anchors)
&& !(first { $_->encloses_point_quick($line->[B]) } @$anchors);
} @clipped_lines;
# sum length of bridged lines
$directions{-$angle} = sum(map Slic3r::Geometry::line_length($_), @clipped_lines) // 0;
} }
$bridge_angle = Slic3r::Geometry::rad2deg_dir(atan2($y, $x));
# this could be slightly optimized with a max search instead of the sort
my @sorted_directions = sort { $directions{$a} <=> $directions{$b} } keys %directions;
# the best direction is the one causing most lines to be bridged
$bridge_angle = Slic3r::Geometry::rad2deg_dir($sorted_directions[-1]);
} }
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",