Huge speed Boost (pun intended). Also fixes a problem where infill was escaping perimeters sometimes (#305).

This commit is contained in:
Alessandro Ranellucci 2012-04-09 11:04:32 +02:00
parent a800b97fdd
commit 5bfe19a8b9
6 changed files with 42 additions and 78 deletions

View File

@ -2,11 +2,12 @@ use Module::Build;
my $build = Module::Build->new( my $build = Module::Build->new(
module_name => 'Slic3r', module_name => 'Slic3r',
dist_abstract => 'STL-to-GCODE translator', dist_abstract => 'G-code generator for 3D printers',
dist_author => 'Alessandro Ranellucci <aar@cpan.org>', dist_author => 'Alessandro Ranellucci <aar@cpan.org>',
dist_version => '0.1', dist_version => '0.1',
license => 'perl', license => 'perl',
requires => { requires => {
'Boost::Geometry::Utils' => '0',
'File::Basename' => '0', 'File::Basename' => '0',
'Getopt::Long' => '0', 'Getopt::Long' => '0',
'Math::Clipper' => '1.05', 'Math::Clipper' => '1.05',

View File

@ -4,6 +4,7 @@ use warnings;
# an ExPolygon is a polygon with holes # an ExPolygon is a polygon with holes
use Boost::Geometry::Utils;
use Math::Geometry::Voronoi; use Math::Geometry::Voronoi;
use Slic3r::Geometry qw(X Y A B point_in_polygon same_line); use Slic3r::Geometry qw(X Y A B point_in_polygon same_line);
use Slic3r::Geometry::Clipper qw(union_ex JT_MITER); use Slic3r::Geometry::Clipper qw(union_ex JT_MITER);
@ -53,6 +54,11 @@ sub clipper_expolygon {
}; };
} }
sub boost_polygon {
my $self = shift;
return Boost::Geometry::Utils::polygon(@$self);
}
sub offset { sub offset {
my $self = shift; my $self = shift;
my ($distance, $scale, $joinType, $miterLimit) = @_; my ($distance, $scale, $joinType, $miterLimit) = @_;
@ -131,32 +137,10 @@ sub clip_line {
my $self = shift; my $self = shift;
my ($line) = @_; # line must be a Slic3r::Line object my ($line) = @_; # line must be a Slic3r::Line object
my @intersections = grep $_, map $_->intersection($line, 1), map $_->lines, @$self; return Boost::Geometry::Utils::polygon_linestring_intersection(
my @dir = ( $self->boost_polygon,
$line->[B][X] <=> $line->[A][X], $line->boost_linestring,
$line->[B][Y] <=> $line->[A][Y],
); );
@intersections = sort {
(($a->[X] <=> $b->[X]) == $dir[X]) && (($a->[Y] <=> $b->[Y]) == $dir[Y]) ? 1 : -1
} @intersections, @$line;
shift @intersections if $intersections[0]->coincides_with($intersections[1]);
pop @intersections if $intersections[-1]->coincides_with($intersections[-2]);
shift @intersections
if !$self->encloses_point($intersections[0])
&& !$self->point_on_segment($intersections[0]);
my @lines = ();
while (@intersections) {
# skip tangent points
my @points = splice @intersections, 0, 2;
next if !$points[1];
next if $points[0]->coincides_with($points[1]);
push @lines, [ @points ];
}
return [@lines];
} }
sub simplify { sub simplify {

View File

@ -34,23 +34,26 @@ sub fill_surface {
my $overlap_distance = scale $Slic3r::flow_width * 0.4; my $overlap_distance = scale $Slic3r::flow_width * 0.4;
my @paths = ();
my $x = $bounding_box->[X1]; my $x = $bounding_box->[X1];
my $is_line_pattern = $self->isa('Slic3r::Fill::Line'); my $is_line_pattern = $self->isa('Slic3r::Fill::Line');
my @vertical_lines = ();
for (my $i = 0; $x <= $bounding_box->[X2] + scale epsilon; $i++) { for (my $i = 0; $x <= $bounding_box->[X2] + scale epsilon; $i++) {
my $vertical_line = Slic3r::Line->new([$x, $bounding_box->[Y2]], [$x, $bounding_box->[Y1]]); my $vertical_line = Slic3r::Line->new([$x, $bounding_box->[Y2]], [$x, $bounding_box->[Y1]]);
if ($is_line_pattern && $i % 2) { if ($is_line_pattern && $i % 2) {
$vertical_line->[A][X] += $line_oscillation; $vertical_line->[A][X] += $line_oscillation;
$vertical_line->[B][X] -= $line_oscillation; $vertical_line->[B][X] -= $line_oscillation;
} }
my @clipped_lines = @{ $expolygon->clip_line($vertical_line) }; push @vertical_lines, $vertical_line;
for (@clipped_lines) { $x += $distance_between_lines;
}
my @paths = @{ Boost::Geometry::Utils::polygon_linestring_intersection(
$expolygon->boost_polygon,
Boost::Geometry::Utils::linestring(@vertical_lines),
) };
for (@paths) {
$_->[0][Y] += $overlap_distance; $_->[0][Y] += $overlap_distance;
$_->[-1][Y] -= $overlap_distance; $_->[-1][Y] -= $overlap_distance;
} }
push @paths, @clipped_lines;
$x += $distance_between_lines;
}
# connect lines # connect lines
{ {
@ -75,7 +78,7 @@ sub fill_surface {
# TODO: we should also check that both points are on a fill_boundary to avoid # TODO: we should also check that both points are on a fill_boundary to avoid
# connecting paths on the boundaries of internal regions # connecting paths on the boundaries of internal regions
if ($can_connect->(@distance, $paths[-1][-1], $path->points->[0]) if ($can_connect->(@distance, $paths[-1][-1], $path->points->[0])
&& $expolygon_off->encloses_line([ $paths[-1][-1], $path->points->[0] ])) { && $expolygon_off->encloses_line(Slic3r::Line->new($paths[-1][-1], $path->points->[0]))) {
push @{$paths[-1]}, @{$path->points}; push @{$paths[-1]}, @{$path->points};
next; next;
} }

View File

@ -2,6 +2,7 @@ package Slic3r::Line;
use strict; use strict;
use warnings; use warnings;
use Boost::Geometry::Utils;
use Slic3r::Geometry qw(A B X Y); use Slic3r::Geometry qw(A B X Y);
sub new { sub new {
@ -31,6 +32,11 @@ sub coordinates {
return ($self->a->coordinates, $self->b->coordinates); return ($self->a->coordinates, $self->b->coordinates);
} }
sub boost_linestring {
my $self = shift;
return Boost::Geometry::Utils::linestring($self);
}
sub coincides_with { sub coincides_with {
my $self = shift; my $self = shift;
my ($line) = @_; my ($line) = @_;

View File

@ -40,6 +40,11 @@ sub lines {
return @lines; return @lines;
} }
sub boost_linestring {
my $self = shift;
return Boost::Geometry::Utils::linestring($self);
}
sub merge_continuous_lines { sub merge_continuous_lines {
my $self = shift; my $self = shift;
@ -95,47 +100,12 @@ sub clip_with_expolygon {
my $self = shift; my $self = shift;
my ($expolygon) = @_; my ($expolygon) = @_;
#printf "Clipping polyline of %d points to expolygon of %d polygons and %d points\n", my $result = Boost::Geometry::Utils::polygon_linestring_intersection(
# scalar(@$self), scalar(@$expolygon), scalar(map @$_, @$expolygon); $expolygon->boost_polygon,
$self->boost_linestring,
my @polylines = (); );
my $current_polyline = []; bless $_, 'Slic3r::Polyline' for @$result;
foreach my $line ($self->lines) { return @$result;
my ($first_line, @other_lines) = @{ $expolygon->clip_line($line) };
next unless $first_line;
if (!@$current_polyline) {
push @$current_polyline, @$first_line;
} elsif ($first_line->[A]->coincides_with($current_polyline->[-1])) {
push @$current_polyline, $first_line->[B];
} else {
push @polylines, $current_polyline;
$current_polyline = [ @$first_line ];
}
foreach my $other_line (@other_lines) {
if (@$current_polyline) {
push @polylines, $current_polyline;
$current_polyline = [];
}
push @polylines, [ @$other_line ];
}
}
if (@$current_polyline) {
push @polylines, $current_polyline;
}
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->new($_), @polylines;
} }
sub bounding_box { sub bounding_box {

View File

@ -140,12 +140,12 @@ is_deeply $intersection, [ [12, 12], [18, 16] ], 'internal lines are preserved';
is is_counter_clockwise($small_circle), 0, "hole is clockwise"; is is_counter_clockwise($small_circle), 0, "hole is clockwise";
my $expolygon = Slic3r::ExPolygon->new($large_circle, $small_circle); my $expolygon = Slic3r::ExPolygon->new($large_circle, $small_circle);
$line = Slic3r::Line->new([152.741724,288.086671142818], [152.741724,34.166466971035]); $line = Slic3r::Line->new([152.742,288.086671142818], [152.742,34.166466971035]);
my $intersections = $expolygon->clip_line($line); my $intersections = $expolygon->clip_line($line);
is_deeply $intersections, [ is_deeply $intersections, [
[ [152.741724, 288.086671142818], [152.741724, 215.178806915206], ], [ [152.742, 288.087], [152.742, 215.179], ],
[ [152.741724, 108.087543109156], [152.741724, 35.166466971035] ], [ [152.742, 108.088], [152.742, 35.1665] ],
], 'line is clipped to square with hole'; ], 'line is clipped to square with hole';
} }