Slic3r should now be able to detect optimal bridging direction for any kind of bridge. #58

This commit is contained in:
Alessandro Ranellucci 2011-12-02 23:35:39 +01:00
parent 5375f5fef4
commit 792960aae1
9 changed files with 117 additions and 42 deletions

View File

@ -41,6 +41,7 @@ lib/Slic3r/TriangleMesh/IntersectionLine.pm
MANIFEST This list of files
README.markdown
slic3r.pl
t/angles.t
t/arcs.t
t/clean_polylines.t
t/clipper.t

View File

@ -53,7 +53,7 @@ sub make_fill {
{
my @surfaces_with_bridge_angle = grep defined $_->bridge_angle, @{$layer->fill_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 ], undef, 1);
# subtract surfaces having a defined bridge_angle from any other
if (@surfaces_with_bridge_angle && !defined $group->[0]->bridge_angle) {

View File

@ -14,10 +14,11 @@ our @EXPORT_OK = qw(
rotate_points move_points remove_coinciding_points clip_segment_polygon
sum_vectors multiply_vector subtract_vectors dot perp polygon_points_visibility
line_intersection bounding_box bounding_box_intersect same_point
longest_segment angle3points three_points_aligned
longest_segment angle3points three_points_aligned line_direction
polyline_remove_parallel_continuous_edges polyline_remove_acute_vertices
polygon_remove_acute_vertices polygon_remove_parallel_continuous_edges
shortest_path collinear scale unscale merge_collinear_lines
rad2deg_dir
);
use Slic3r::Geometry::DouglasPeucker qw(Douglas_Peucker);
@ -52,6 +53,14 @@ sub line_atan {
return atan2($line->[B][Y] - $line->[A][Y], $line->[B][X] - $line->[A][X]);
}
sub line_direction {
my ($line) = @_;
my $atan2 = line_atan($line);
return ($atan2 == PI) ? 0
: ($atan2 < 0) ? ($atan2 + PI)
: $atan2;
}
sub lines_parallel {
my ($line1, $line2) = @_;
@ -311,6 +320,13 @@ sub rad2deg {
return $rad / PI() * 180;
}
sub rad2deg_dir {
my ($rad) = @_;
$rad = ($rad < PI) ? (-$rad + PI/2) : ($rad + PI/2);
$rad += PI if $rad < 0;
return rad2deg($rad);
}
sub rotate_points {
my ($radians, $center, @points) = @_;
$center ||= [0,0];

View File

@ -9,6 +9,7 @@ our @EXPORT_OK = qw(explode_expolygon explode_expolygons safety_offset offset
is_counter_clockwise);
use Math::Clipper 1.02 ':all';
use Slic3r::Geometry qw(scale);
our $clipper = Math::Clipper->new;
sub explode_expolygon {
@ -23,15 +24,15 @@ sub explode_expolygons {
sub safety_offset {
my ($polygons) = @_;
return Math::Clipper::offset($polygons, 100, 100, JT_MITER, 2);
return Math::Clipper::offset($polygons, scale 1e-05, 100, JT_MITER, 2);
}
sub diff_ex {
my ($subject, $clip) = @_;
my ($subject, $clip, $safety_offset) = @_;
$clipper->clear;
$clipper->add_subject_polygons($subject);
$clipper->add_clip_polygons($clip);
$clipper->add_clip_polygons($safety_offset ? safety_offset($clip) : $clip);
return [
map Slic3r::ExPolygon->new($_),
@{ $clipper->ex_execute(CT_DIFFERENCE, PFT_NONZERO, PFT_NONZERO) },
@ -43,10 +44,10 @@ sub diff {
}
sub union_ex {
my ($polygons, $jointype) = @_;
my ($polygons, $jointype, $safety_offset) = @_;
$jointype = PFT_NONZERO unless defined $jointype;
$clipper->clear;
$clipper->add_subject_polygons($polygons);
$clipper->add_subject_polygons($safety_offset ? safety_offset($polygons) : $polygons);
return [
map Slic3r::ExPolygon->new($_),
@{ $clipper->ex_execute(CT_UNION, $jointype, $jointype) },
@ -54,11 +55,11 @@ sub union_ex {
}
sub intersection_ex {
my ($subject, $clip, $jointype) = @_;
my ($subject, $clip, $jointype, $safety_offset) = @_;
$jointype = PFT_NONZERO unless defined $jointype;
$clipper->clear;
$clipper->add_subject_polygons($subject);
$clipper->add_clip_polygons($clip);
$clipper->add_clip_polygons($safety_offset ? safety_offset($clip) : $clip);
return [
map Slic3r::ExPolygon->new($_),
@{ $clipper->ex_execute(CT_INTERSECTION, $jointype, $jointype) },

View File

@ -2,7 +2,7 @@ package Slic3r::Layer;
use Moo;
use Math::Clipper ':all';
use Slic3r::Geometry qw(scale collinear X Y A B PI);
use Slic3r::Geometry qw(scale collinear X Y A B PI rad2deg_dir);
use Slic3r::Geometry::Clipper qw(union_ex diff_ex intersection_ex is_counter_clockwise);
use XXX;
@ -224,7 +224,7 @@ sub process_bridges {
# offset the contour and intersect it with the internal surfaces to discover
# which of them has contact with our bridge
my @supporting_surfaces = ();
my ($contour_offset) = $expolygon->contour->offset($Slic3r::flow_width / $Slic3r::resolution);
my ($contour_offset) = $expolygon->contour->offset(scale $Slic3r::flow_width * sqrt(2));
foreach my $internal_surface (@internal_surfaces) {
my $intersection = intersection_ex([$contour_offset], [$internal_surface->contour->p]);
if (@$intersection) {
@ -236,7 +236,7 @@ sub process_bridges {
require "Slic3r/SVG.pm";
Slic3r::SVG::output(undef, "bridge.svg",
green_polygons => [ map $_->p, @supporting_surfaces ],
red_polygons => [ @$expolygon ],
#red_polygons => [ @$expolygon ],
);
}
@ -257,6 +257,7 @@ sub process_bridges {
$bridge_over_hole = 1;
} else {
foreach my $edge (@surface_edges) {
next unless @{$edge->points} >= 4;
shift @{$edge->points};
pop @{$edge->points};
}
@ -272,15 +273,21 @@ sub process_bridges {
Slic3r::SVG::output(undef, "bridge.svg",
polylines => [ map $_->p, @edges ],
);
exit if $self->id == 30;
}
if (@edges == 2) {
my @chords = map Slic3r::Line->new($_->points->[0], $_->points->[-1]), @edges;
my @midpoints = map $_->midpoint, @chords;
$bridge_angle = -Slic3r::Geometry::rad2deg(Slic3r::Geometry::line_atan(\@midpoints) + PI/2);
Slic3r::debugf "Optimal infill angle of bridge on layer %d is %d degrees\n", $self->id, $bridge_angle;
{
my $weighted_sum = 0;
my $total_length = 0;
foreach my $line (map $_->lines, @edges) {
my $len = $line->length;
$weighted_sum += $len * $line->direction;
$total_length += $len;
}
$bridge_angle = rad2deg_dir(($weighted_sum / $total_length) + PI/2);
}
Slic3r::debugf "Optimal infill angle of bridge on layer %d is %d degrees\n",
$self->id, $bridge_angle if defined $bridge_angle;
}
# now, extend our bridge by taking a portion of supporting surfaces

View File

@ -85,6 +85,11 @@ sub atan {
return Slic3r::Geometry::line_atan($self);
}
sub direction {
my $self = shift;
return Slic3r::Geometry::line_direction($self);
}
sub intersection {
my $self = shift;
my ($line, $require_crossing) = @_;

View File

@ -3,7 +3,7 @@ use Moo;
use Math::Clipper qw();
use Slic3r::Geometry qw(A B polyline_remove_parallel_continuous_edges polyline_remove_acute_vertices
polygon_remove_acute_vertices polygon_remove_parallel_continuous_edges move_points);
polygon_remove_acute_vertices polygon_remove_parallel_continuous_edges move_points same_point);
use Sub::Quote;
use XXX;
@ -156,9 +156,14 @@ sub clip_with_expolygon {
push @polylines, $current_polyline;
}
if (@polylines > 1 && scalar(@{$polylines[-1]}) == 2 && $polylines[-1][-1] eq $polylines[0][0]) {
unshift @{$polylines[0]}, $polylines[-1][0];
pop @polylines;
if (@polylines > 1 && same_point($polylines[-1][-1], $polylines[0][0])) {
if (scalar(@{$polylines[-1]}) == 2) {
unshift @{$polylines[0]}, $polylines[-1][0];
pop @polylines;
} else {
push @{$polylines[-1]}, $polylines[0][-1];
shift @polylines;
}
}
return map Slic3r::Polyline->cast($_), @polylines;

View File

@ -177,6 +177,7 @@ sub detect_surfaces_type {
my $expolygons = diff_ex(
[ map { ref $_ eq 'ARRAY' ? $_ : ref $_ eq 'Slic3r::ExPolygon' ? @$_ : $_->p } @$subject_surfaces ],
[ map { ref $_ eq 'ARRAY' ? $_ : ref $_ eq 'Slic3r::ExPolygon' ? @$_ : $_->p } @$clip_surfaces ],
1,
);
return grep $_->contour->is_printable,
map Slic3r::Surface->cast_from_expolygon($_, surface_type => $result_type),
@ -206,7 +207,6 @@ sub detect_surfaces_type {
# of current layer and upper one)
if ($upper_layer) {
@top = $surface_difference->($layer->surfaces, $upper_layer->surfaces, 'top');
} else {
# if no upper layer, all surfaces of this one are solid
@top = @{$layer->surfaces};
@ -217,22 +217,6 @@ sub detect_surfaces_type {
# of current layer and lower one)
if ($lower_layer) {
@bottom = $surface_difference->($layer->surfaces, $lower_layer->surfaces, 'bottom');
$_->contour->merge_continuous_lines for @bottom;
# merge_continuous_lines could return polylines with less than 3 points (thus invalid)
# actually, this shouldn't happen so it deserves further investigation
@bottom = grep $_->contour->is_valid, @bottom;
foreach my $surface (@bottom) {
$surface->contour->remove_acute_vertices;
# okay, this is an Ugly Hack(tm) to avoid floating point math problems
# with diagonal bridges. will find a nicer solution, promised.
my $offset = safety_offset([$surface->contour->p]);
@{$surface->contour->points} = map Slic3r::Point->new($_), @{ $offset->[0] };
}
} else {
# if no lower layer, all surfaces of this one are solid
@bottom = @{$layer->surfaces};
@ -391,7 +375,6 @@ sub infill_every_layers {
[ map $_->p, grep $_->surface_type eq 'internal', @{$layer->fill_surfaces} ],
);
next if !@$intersection;
my $intersection_offsetted = safety_offset([ map @$_, @$intersection ]);
# new fill surfaces of the current layer are:
# - any non-internal surface
@ -414,7 +397,8 @@ sub infill_every_layers {
map $_->p, grep $_->surface_type eq 'internal' && $_->depth_layers == $depth,
@{$layer->fill_surfaces},
],
$intersection_offsetted,
$intersection,
1,
)};
}
@{$layer->fill_surfaces} = @new_surfaces;
@ -435,7 +419,8 @@ sub infill_every_layers {
map $_->p, grep $_->surface_type eq 'internal' && $_->depth_layers == $depth,
@{$lower_layer->fill_surfaces},
],
$intersection_offsetted,
$intersection,
1,
)};
}
@{$lower_layer->fill_surfaces} = @new_surfaces;

55
t/angles.t Normal file
View File

@ -0,0 +1,55 @@
use Test::More;
use strict;
use warnings;
plan tests => 23;
BEGIN {
use FindBin;
use lib "$FindBin::Bin/../lib";
}
use Slic3r;
use Slic3r::Geometry qw(line_atan line_direction rad2deg_dir PI);
#==========================================================
{
is line_atan([ [0, 0], [10, 0] ]), (0), 'E atan2';
is line_atan([ [10, 0], [0, 0] ]), (PI), 'W atan2';
is line_atan([ [0, 0], [0, 10] ]), (PI/2), 'N atan2';
is line_atan([ [0, 10], [0, 0] ]), -(PI/2), 'S atan2';
is line_atan([ [10, 10], [0, 0] ]), -(PI*3/4), 'SW atan2';
is line_atan([ [0, 0], [10, 10] ]), (PI*1/4), 'NE atan2';
is line_atan([ [0, 10], [10, 0] ]), -(PI*1/4), 'SE atan2';
is line_atan([ [10, 0], [0, 10] ]), (PI*3/4), 'NW atan2';
}
#==========================================================
{
is line_direction([ [0, 0], [10, 0] ]), (0), 'E direction';
is line_direction([ [10, 0], [0, 0] ]), (0), 'W direction';
is line_direction([ [0, 0], [0, 10] ]), (PI/2), 'N direction';
is line_direction([ [0, 10], [0, 0] ]), (PI/2), 'S direction';
is line_direction([ [10, 10], [0, 0] ]), (PI*1/4), 'SW direction';
is line_direction([ [0, 0], [10, 10] ]), (PI*1/4), 'NE direction';
is line_direction([ [0, 10], [10, 0] ]), (PI*3/4), 'SE direction';
is line_direction([ [10, 0], [0, 10] ]), (PI*3/4), 'NW direction';
}
#==========================================================
{
is rad2deg_dir(0), 90, 'E (degrees)';
is rad2deg_dir(PI), 270, 'W (degrees)';
is rad2deg_dir(PI/2), 0, 'N (degrees)';
is rad2deg_dir(-(PI/2)), 180, 'S (degrees)';
is rad2deg_dir(PI*1/4), 45, 'NE (degrees)';
is rad2deg_dir(PI*3/4), 135, 'NW (degrees)';
is rad2deg_dir(PI/6), 60, '30°';
}
#==========================================================