Faster algorithm for rectilinear fill
This commit is contained in:
parent
33d7b8c7cf
commit
5daaf454b1
@ -62,7 +62,7 @@ our $temperature = 200;
|
|||||||
our $retract_length = 1; # mm
|
our $retract_length = 1; # mm
|
||||||
our $retract_restart_extra = 0; # mm
|
our $retract_restart_extra = 0; # mm
|
||||||
our $retract_speed = 40; # mm/sec
|
our $retract_speed = 40; # mm/sec
|
||||||
our $retract_before_travel = 1; # mm
|
our $retract_before_travel = 2; # mm
|
||||||
|
|
||||||
# skirt options
|
# skirt options
|
||||||
our $skirts = 1;
|
our $skirts = 1;
|
||||||
|
@ -218,6 +218,10 @@ sub validate {
|
|||||||
$Slic3r::print_center = [ split /,/, $Slic3r::print_center ]
|
$Slic3r::print_center = [ split /,/, $Slic3r::print_center ]
|
||||||
if !ref $Slic3r::print_center;
|
if !ref $Slic3r::print_center;
|
||||||
|
|
||||||
|
# --fill-type
|
||||||
|
die "Invalid value for --fill-type\n"
|
||||||
|
if !exists $Slic3r::Fill::FillTypes{$Slic3r::fill_type};
|
||||||
|
|
||||||
# --fill-density
|
# --fill-density
|
||||||
die "Invalid value for --fill-density\n"
|
die "Invalid value for --fill-density\n"
|
||||||
if $Slic3r::fill_density < 0 || $Slic3r::fill_density > 1;
|
if $Slic3r::fill_density < 0 || $Slic3r::fill_density > 1;
|
||||||
|
@ -69,15 +69,11 @@ sub extrude {
|
|||||||
|
|
||||||
my $gcode = "";
|
my $gcode = "";
|
||||||
|
|
||||||
# reset extrusion distance counter
|
# retract if distance from previous position is greater or equal to the one
|
||||||
if (!$Slic3r::use_relative_e_distances) {
|
# specified by the user *and* to the maximum distance between infill lines
|
||||||
$self->extrusion_distance(0);
|
my $distance_from_last_pos = Slic3r::Geometry::distance_between_points($self->last_pos, $path->points->[0]->p) * $Slic3r::resolution;
|
||||||
$gcode .= "G92 E0 ; reset extrusion distance\n";
|
if ($distance_from_last_pos >= $Slic3r::retract_before_travel
|
||||||
}
|
&& $distance_from_last_pos >= $Slic3r::flow_width / $Slic3r::fill_density * sqrt(2)) {
|
||||||
|
|
||||||
# retract
|
|
||||||
if (Slic3r::Geometry::distance_between_points($self->last_pos, $path->points->[0]->p) * $Slic3r::resolution
|
|
||||||
>= $Slic3r::retract_before_travel) {
|
|
||||||
$gcode .= $self->retract;
|
$gcode .= $self->retract;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,12 +3,14 @@ use Moo;
|
|||||||
|
|
||||||
use Slic3r::Fill::Base;
|
use Slic3r::Fill::Base;
|
||||||
use Slic3r::Fill::Rectilinear;
|
use Slic3r::Fill::Rectilinear;
|
||||||
|
use Slic3r::Fill::Rectilinear2;
|
||||||
|
|
||||||
has 'print' => (is => 'ro', required => 1);
|
has 'print' => (is => 'ro', required => 1);
|
||||||
has 'fillers' => (is => 'rw', default => sub { {} });
|
has 'fillers' => (is => 'rw', default => sub { {} });
|
||||||
|
|
||||||
our %FillTypes = (
|
our %FillTypes = (
|
||||||
rectilinear => 'Slic3r::Fill::Rectilinear',
|
rectilinear => 'Slic3r::Fill::Rectilinear',
|
||||||
|
rectilinear2 => 'Slic3r::Fill::Rectilinear2',
|
||||||
);
|
);
|
||||||
|
|
||||||
sub BUILD {
|
sub BUILD {
|
||||||
|
@ -7,10 +7,6 @@ use constant X1 => 0;
|
|||||||
use constant Y1 => 1;
|
use constant Y1 => 1;
|
||||||
use constant X2 => 2;
|
use constant X2 => 2;
|
||||||
use constant Y2 => 3;
|
use constant Y2 => 3;
|
||||||
use constant A => 0;
|
|
||||||
use constant B => 1;
|
|
||||||
use constant X => 0;
|
|
||||||
use constant Y => 1;
|
|
||||||
|
|
||||||
use XXX;
|
use XXX;
|
||||||
|
|
||||||
@ -18,119 +14,23 @@ sub fill_surface {
|
|||||||
my $self = shift;
|
my $self = shift;
|
||||||
my ($surface, %params) = @_;
|
my ($surface, %params) = @_;
|
||||||
|
|
||||||
my $polygons = [ $surface->p ];
|
|
||||||
|
|
||||||
# rotate polygons so that we can work with vertical lines here
|
# rotate polygons so that we can work with vertical lines here
|
||||||
|
my $polygons = [ $surface->p ];
|
||||||
my $rotate_vector = $self->infill_direction($polygons);
|
my $rotate_vector = $self->infill_direction($polygons);
|
||||||
$self->rotate_points($polygons, $rotate_vector);
|
$self->rotate_points($polygons, $rotate_vector);
|
||||||
|
|
||||||
|
my $bounding_box = [ Slic3r::Geometry::bounding_box(map @$_, $polygons) ];
|
||||||
|
my $surface_width = $bounding_box->[X2] - $bounding_box->[X1];
|
||||||
|
my $surface_height = $bounding_box->[Y2] - $bounding_box->[Y1];
|
||||||
|
|
||||||
my $distance_between_lines = $Slic3r::flow_width / $Slic3r::resolution / $params{density};
|
my $distance_between_lines = $Slic3r::flow_width / $Slic3r::resolution / $params{density};
|
||||||
my $number_of_lines = int(0.99999999 + $self->max_print_dimension / $distance_between_lines); # ceil
|
|
||||||
|
|
||||||
#printf "distance = %f\n", $distance_between_lines;
|
|
||||||
#printf "number_of_lines = %d\n", $number_of_lines;
|
|
||||||
|
|
||||||
# this arrayref will hold intersection points of the fill grid with surface segments
|
my @paths = ();
|
||||||
my $points = [ map [], 0..$number_of_lines-1 ];
|
my $x = $bounding_box->[X1];
|
||||||
foreach my $line (map Slic3r::Geometry::polygon_lines($_), @$polygons) {
|
while ($x < $bounding_box->[X2]) {
|
||||||
|
my $vertical_line = [ [$x, $bounding_box->[Y2]], [$x, $bounding_box->[Y1]] ];
|
||||||
# find out the coordinates
|
push @paths, @{ Slic3r::Geometry::clip_segment_complex_polygon($vertical_line, $polygons) };
|
||||||
my @coordinates = map @$_, @$line;
|
$x += int($distance_between_lines);
|
||||||
|
|
||||||
# get the extents of the segment along the primary axis
|
|
||||||
my @line_c = sort { $a <=> $b } @coordinates[X1, X2];
|
|
||||||
Slic3r::debugf "Segment %d,%d - %d,%d (extents: %f, %f)\n", @coordinates, @line_c;
|
|
||||||
|
|
||||||
for (my $c = int($line_c[0] / $distance_between_lines) * $distance_between_lines;
|
|
||||||
$c <= $line_c[1]; $c += $distance_between_lines) {
|
|
||||||
next if $c < $line_c[0] || $c > $line_c[1];
|
|
||||||
my $i = sprintf('%.0f', $c / $distance_between_lines) - 1;
|
|
||||||
#printf "CURRENT \$i = %d, \$c = %f\n", $i, $c;
|
|
||||||
|
|
||||||
# if the segment is parallel to our ray, there will be two intersection points
|
|
||||||
if ($line_c[0] == $line_c[1]) {
|
|
||||||
Slic3r::debugf " Segment is parallel!\n";
|
|
||||||
push @{ $points->[$i] }, $coordinates[Y1], $coordinates[Y2];
|
|
||||||
Slic3r::debugf " intersections at %f (%d) = %f, %f\n", $c, $i, $points->[$i][-2], $points->[$i][-1];
|
|
||||||
} else {
|
|
||||||
Slic3r::debugf " Segment NOT parallel!\n";
|
|
||||||
# one point of intersection
|
|
||||||
push @{ $points->[$i] }, $coordinates[Y1] + ($coordinates[Y2] - $coordinates[Y1])
|
|
||||||
* ($c - $coordinates[X1]) / ($coordinates[X2] - $coordinates[X1]);
|
|
||||||
Slic3r::debugf " intersection at %f (%d) = %f\n", $c, $i, $points->[$i][-1];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
# sort and remove duplicates
|
|
||||||
for (my $i = 0; $i <= $#$points; $i++) {
|
|
||||||
my %h = map { sprintf("%.9f", $_) => 1 } @{ $points->[$i] };
|
|
||||||
$points->[$i] = [ sort { $a <=> $b } keys %h ];
|
|
||||||
}
|
|
||||||
|
|
||||||
# generate extrusion paths
|
|
||||||
my (@paths, @path_points) = ();
|
|
||||||
my $direction = 0;
|
|
||||||
|
|
||||||
my $stop_path = sub {
|
|
||||||
# defensive programming
|
|
||||||
if (@path_points == 1) {
|
|
||||||
#warn "There shouldn't be only one point in the current path";
|
|
||||||
}
|
|
||||||
|
|
||||||
# if we were constructing a path, stop it
|
|
||||||
push @paths, [ @path_points ] if @path_points > 1;
|
|
||||||
@path_points = ();
|
|
||||||
};
|
|
||||||
|
|
||||||
# loop until we have spare points
|
|
||||||
CYCLE: while (scalar map(@$_, @$points) > 1) {
|
|
||||||
# loop through rows
|
|
||||||
ROW: for (my $i = 0; $i <= $#$points; $i++) {
|
|
||||||
my $row = $points->[$i] or next ROW;
|
|
||||||
Slic3r::debugf "\nProcessing row %d (direction: %d)...\n", $i, $direction;
|
|
||||||
if (!@$row) {
|
|
||||||
Slic3r::debugf " no points\n";
|
|
||||||
$stop_path->();
|
|
||||||
next ROW;
|
|
||||||
}
|
|
||||||
Slic3r::debugf " points = %s\n", join ', ', @$row if $Slic3r::debug;
|
|
||||||
|
|
||||||
# coordinate of current row
|
|
||||||
my $c = ($i + 1) * $distance_between_lines;
|
|
||||||
|
|
||||||
# need to start a path?
|
|
||||||
if (!@path_points) {
|
|
||||||
Slic3r::debugf " path starts at %d\n", $row->[0];
|
|
||||||
push @path_points, [ $c, shift @$row ];
|
|
||||||
}
|
|
||||||
|
|
||||||
my @search_points = @$row;
|
|
||||||
@search_points = reverse @search_points if $direction == 1;
|
|
||||||
my @connectable_points = $self->find_connectable_points($polygons, $path_points[-1], $c, [@search_points]);
|
|
||||||
Slic3r::debugf " ==> found %d connectable points = %s\n", scalar(@connectable_points),
|
|
||||||
join ', ', @connectable_points if $Slic3r::debug;
|
|
||||||
|
|
||||||
if (!@connectable_points && @path_points && $path_points[-1][0] != $c) {
|
|
||||||
# no connectable in this row
|
|
||||||
$stop_path->();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (@connectable_points == 1 && $path_points[0][0] != $c
|
|
||||||
&& (($connectable_points[0] == $row->[-1] && $direction == 0)
|
|
||||||
|| ($connectable_points[0] == $row->[0] && $direction == 1))) {
|
|
||||||
$i--; # keep searching on current row in the opposite direction
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach my $p (@connectable_points) {
|
|
||||||
push @path_points, [ $c, $p ];
|
|
||||||
@$row = grep $_ != $p, @$row; # remove point from row
|
|
||||||
}
|
|
||||||
|
|
||||||
# invert direction
|
|
||||||
$direction = $direction ? 0 : 1;
|
|
||||||
}
|
|
||||||
$stop_path->() if @path_points;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
# paths must be rotated back
|
# paths must be rotated back
|
||||||
@ -139,21 +39,4 @@ sub fill_surface {
|
|||||||
return @paths;
|
return @paths;
|
||||||
}
|
}
|
||||||
|
|
||||||
# this function will select the first contiguous block of
|
|
||||||
# points connectable to a given one
|
|
||||||
sub find_connectable_points {
|
|
||||||
my $self = shift;
|
|
||||||
my ($polygons, $point, $c, $points) = @_;
|
|
||||||
|
|
||||||
my @connectable_points = ();
|
|
||||||
foreach my $p (@$points) {
|
|
||||||
if (!Slic3r::Geometry::can_connect_points($point, [ $c, $p ], $polygons)) {
|
|
||||||
@connectable_points ? last : next;
|
|
||||||
}
|
|
||||||
push @connectable_points, $p;
|
|
||||||
$point = [ $c, $p ] if $point->[0] != $c;
|
|
||||||
}
|
|
||||||
return @connectable_points;
|
|
||||||
}
|
|
||||||
|
|
||||||
1;
|
1;
|
||||||
|
159
lib/Slic3r/Fill/Rectilinear2.pm
Normal file
159
lib/Slic3r/Fill/Rectilinear2.pm
Normal file
@ -0,0 +1,159 @@
|
|||||||
|
package Slic3r::Fill::Rectilinear2;
|
||||||
|
use Moo;
|
||||||
|
|
||||||
|
extends 'Slic3r::Fill::Base';
|
||||||
|
|
||||||
|
use constant X1 => 0;
|
||||||
|
use constant Y1 => 1;
|
||||||
|
use constant X2 => 2;
|
||||||
|
use constant Y2 => 3;
|
||||||
|
use constant A => 0;
|
||||||
|
use constant B => 1;
|
||||||
|
use constant X => 0;
|
||||||
|
use constant Y => 1;
|
||||||
|
|
||||||
|
use XXX;
|
||||||
|
|
||||||
|
sub fill_surface {
|
||||||
|
my $self = shift;
|
||||||
|
my ($surface, %params) = @_;
|
||||||
|
|
||||||
|
my $polygons = [ $surface->p ];
|
||||||
|
|
||||||
|
# rotate polygons so that we can work with vertical lines here
|
||||||
|
my $rotate_vector = $self->infill_direction($polygons);
|
||||||
|
$self->rotate_points($polygons, $rotate_vector);
|
||||||
|
|
||||||
|
my $distance_between_lines = $Slic3r::flow_width / $Slic3r::resolution / $params{density};
|
||||||
|
my $number_of_lines = int(0.99999999 + $self->max_print_dimension / $distance_between_lines); # ceil
|
||||||
|
|
||||||
|
#printf "distance = %f\n", $distance_between_lines;
|
||||||
|
#printf "number_of_lines = %d\n", $number_of_lines;
|
||||||
|
|
||||||
|
# this arrayref will hold intersection points of the fill grid with surface segments
|
||||||
|
my $points = [ map [], 0..$number_of_lines-1 ];
|
||||||
|
foreach my $line (map Slic3r::Geometry::polygon_lines($_), @$polygons) {
|
||||||
|
|
||||||
|
# find out the coordinates
|
||||||
|
my @coordinates = map @$_, @$line;
|
||||||
|
|
||||||
|
# get the extents of the segment along the primary axis
|
||||||
|
my @line_c = sort { $a <=> $b } @coordinates[X1, X2];
|
||||||
|
Slic3r::debugf "Segment %d,%d - %d,%d (extents: %f, %f)\n", @coordinates, @line_c;
|
||||||
|
|
||||||
|
for (my $c = int($line_c[0] / $distance_between_lines) * $distance_between_lines;
|
||||||
|
$c <= $line_c[1]; $c += $distance_between_lines) {
|
||||||
|
next if $c < $line_c[0] || $c > $line_c[1];
|
||||||
|
my $i = sprintf('%.0f', $c / $distance_between_lines) - 1;
|
||||||
|
#printf "CURRENT \$i = %d, \$c = %f\n", $i, $c;
|
||||||
|
|
||||||
|
# if the segment is parallel to our ray, there will be two intersection points
|
||||||
|
if ($line_c[0] == $line_c[1]) {
|
||||||
|
Slic3r::debugf " Segment is parallel!\n";
|
||||||
|
push @{ $points->[$i] }, $coordinates[Y1], $coordinates[Y2];
|
||||||
|
Slic3r::debugf " intersections at %f (%d) = %f, %f\n", $c, $i, $points->[$i][-2], $points->[$i][-1];
|
||||||
|
} else {
|
||||||
|
Slic3r::debugf " Segment NOT parallel!\n";
|
||||||
|
# one point of intersection
|
||||||
|
push @{ $points->[$i] }, $coordinates[Y1] + ($coordinates[Y2] - $coordinates[Y1])
|
||||||
|
* ($c - $coordinates[X1]) / ($coordinates[X2] - $coordinates[X1]);
|
||||||
|
Slic3r::debugf " intersection at %f (%d) = %f\n", $c, $i, $points->[$i][-1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# sort and remove duplicates
|
||||||
|
for (my $i = 0; $i <= $#$points; $i++) {
|
||||||
|
my %h = map { sprintf("%.9f", $_) => 1 } @{ $points->[$i] };
|
||||||
|
$points->[$i] = [ sort { $a <=> $b } keys %h ];
|
||||||
|
}
|
||||||
|
|
||||||
|
# generate extrusion paths
|
||||||
|
my (@paths, @path_points) = ();
|
||||||
|
my $direction = 0;
|
||||||
|
|
||||||
|
my $stop_path = sub {
|
||||||
|
# defensive programming
|
||||||
|
if (@path_points == 1) {
|
||||||
|
#warn "There shouldn't be only one point in the current path";
|
||||||
|
}
|
||||||
|
|
||||||
|
# if we were constructing a path, stop it
|
||||||
|
push @paths, [ @path_points ] if @path_points > 1;
|
||||||
|
@path_points = ();
|
||||||
|
};
|
||||||
|
|
||||||
|
# loop until we have spare points
|
||||||
|
CYCLE: while (scalar map(@$_, @$points) > 1) {
|
||||||
|
# loop through rows
|
||||||
|
ROW: for (my $i = 0; $i <= $#$points; $i++) {
|
||||||
|
my $row = $points->[$i] or next ROW;
|
||||||
|
Slic3r::debugf "\nProcessing row %d (direction: %d)...\n", $i, $direction;
|
||||||
|
if (!@$row) {
|
||||||
|
Slic3r::debugf " no points\n";
|
||||||
|
$stop_path->();
|
||||||
|
next ROW;
|
||||||
|
}
|
||||||
|
Slic3r::debugf " points = %s\n", join ', ', @$row if $Slic3r::debug;
|
||||||
|
|
||||||
|
# coordinate of current row
|
||||||
|
my $c = ($i + 1) * $distance_between_lines;
|
||||||
|
|
||||||
|
# need to start a path?
|
||||||
|
if (!@path_points) {
|
||||||
|
Slic3r::debugf " path starts at %d\n", $row->[0];
|
||||||
|
push @path_points, [ $c, shift @$row ];
|
||||||
|
}
|
||||||
|
|
||||||
|
my @search_points = @$row;
|
||||||
|
@search_points = reverse @search_points if $direction == 1;
|
||||||
|
my @connectable_points = $self->find_connectable_points($polygons, $path_points[-1], $c, [@search_points]);
|
||||||
|
Slic3r::debugf " ==> found %d connectable points = %s\n", scalar(@connectable_points),
|
||||||
|
join ', ', @connectable_points if $Slic3r::debug;
|
||||||
|
|
||||||
|
if (!@connectable_points && @path_points && $path_points[-1][0] != $c) {
|
||||||
|
# no connectable in this row
|
||||||
|
$stop_path->();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (@connectable_points == 1 && $path_points[0][0] != $c
|
||||||
|
&& (($connectable_points[0] == $row->[-1] && $direction == 0)
|
||||||
|
|| ($connectable_points[0] == $row->[0] && $direction == 1))) {
|
||||||
|
$i--; # keep searching on current row in the opposite direction
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach my $p (@connectable_points) {
|
||||||
|
push @path_points, [ $c, $p ];
|
||||||
|
@$row = grep $_ != $p, @$row; # remove point from row
|
||||||
|
}
|
||||||
|
|
||||||
|
# invert direction
|
||||||
|
$direction = $direction ? 0 : 1;
|
||||||
|
}
|
||||||
|
$stop_path->() if @path_points;
|
||||||
|
}
|
||||||
|
|
||||||
|
# paths must be rotated back
|
||||||
|
$self->rotate_points_back(\@paths, $rotate_vector);
|
||||||
|
|
||||||
|
return @paths;
|
||||||
|
}
|
||||||
|
|
||||||
|
# this function will select the first contiguous block of
|
||||||
|
# points connectable to a given one
|
||||||
|
sub find_connectable_points {
|
||||||
|
my $self = shift;
|
||||||
|
my ($polygons, $point, $c, $points) = @_;
|
||||||
|
|
||||||
|
my @connectable_points = ();
|
||||||
|
foreach my $p (@$points) {
|
||||||
|
if (!Slic3r::Geometry::can_connect_points($point, [ $c, $p ], $polygons)) {
|
||||||
|
@connectable_points ? last : next;
|
||||||
|
}
|
||||||
|
push @connectable_points, $p;
|
||||||
|
$point = [ $c, $p ] if $point->[0] != $c;
|
||||||
|
}
|
||||||
|
return @connectable_points;
|
||||||
|
}
|
||||||
|
|
||||||
|
1;
|
@ -316,15 +316,10 @@ sub polygon_points_visibility {
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
my $i = 0;
|
|
||||||
sub line_intersection {
|
sub line_intersection {
|
||||||
my ($line1, $line2, $require_crossing) = @_;
|
my ($line1, $line2, $require_crossing) = @_;
|
||||||
$require_crossing ||= 0;
|
$require_crossing ||= 0;
|
||||||
|
|
||||||
Slic3r::SVG::output(undef, "line_intersection_" . $i++ . ".svg",
|
|
||||||
lines => [ $line1, $line2 ],
|
|
||||||
) if 0;
|
|
||||||
|
|
||||||
my $intersection = _line_intersection(map @$_, @$line1, @$line2);
|
my $intersection = _line_intersection(map @$_, @$line1, @$line2);
|
||||||
return (ref $intersection && $intersection->[1] == $require_crossing)
|
return (ref $intersection && $intersection->[1] == $require_crossing)
|
||||||
? $intersection->[0]
|
? $intersection->[0]
|
||||||
@ -460,16 +455,23 @@ sub clip_segment_complex_polygon {
|
|||||||
my ($line, $polygons) = @_;
|
my ($line, $polygons) = @_;
|
||||||
|
|
||||||
my @intersections = grep $_, map line_intersection($line, $_, 1),
|
my @intersections = grep $_, map line_intersection($line, $_, 1),
|
||||||
map polygon_lines($_), @$polygons;
|
map polygon_lines($_), @$polygons or return ();
|
||||||
|
|
||||||
@intersections = sort { "$a->[X],$a->[Y]" cmp "$b->[X],$b->[Y]" } @intersections;
|
# this is not very elegant, however it works
|
||||||
|
@intersections = sort { sprintf("%020f,%020f", @$a) cmp sprintf("%020f,%020f", @$b) } @intersections;
|
||||||
|
|
||||||
shift(@intersections) if !grep(point_in_polygon($intersections[0], $_), @$polygons)
|
shift(@intersections) if !grep(point_in_polygon($intersections[0], $_), @$polygons)
|
||||||
&& !grep(polygon_segment_having_point($_, $intersections[0]), @$polygons);
|
&& !grep(polygon_segment_having_point($_, $intersections[0]), @$polygons);
|
||||||
|
|
||||||
|
# defensive programming
|
||||||
|
die "Invalid intersections" if @intersections % 2 != 0;
|
||||||
|
|
||||||
my @lines = ();
|
my @lines = ();
|
||||||
while (@intersections) {
|
while (@intersections) {
|
||||||
push @lines, [ shift(@intersections), shift(@intersections) ];
|
# skip tangent points
|
||||||
|
my @points = map shift @intersections, 1..2;
|
||||||
|
next if points_coincide(@points);
|
||||||
|
push @lines, [ @points ];
|
||||||
}
|
}
|
||||||
return [@lines];
|
return [@lines];
|
||||||
}
|
}
|
||||||
|
@ -22,14 +22,14 @@ sub output {
|
|||||||
|
|
||||||
my $svg = svg($print);
|
my $svg = svg($print);
|
||||||
|
|
||||||
foreach my $type (qw(polygons polylines)) {
|
foreach my $type (qw(polygons polylines white_polygons red_polylines)) {
|
||||||
if ($things{$type}) {
|
if ($things{$type}) {
|
||||||
my $method = $type eq 'polygons' ? 'polygon' : 'polyline';
|
my $method = $type =~ /polygons/ ? 'polygon' : 'polyline';
|
||||||
my $g = $svg->group(
|
my $g = $svg->group(
|
||||||
style => {
|
style => {
|
||||||
'stroke-width' => 2,
|
'stroke-width' => 2,
|
||||||
'stroke' => 'black',
|
'stroke' => $type =~ /red_/ ? 'red' : 'black',
|
||||||
'fill' => 'none',
|
'fill' => $type eq 'polygons' ? 'grey' : 'none',
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
foreach my $polygon (@{$things{$type}}) {
|
foreach my $polygon (@{$things{$type}}) {
|
||||||
|
@ -44,6 +44,7 @@ GetOptions(
|
|||||||
# print options
|
# print options
|
||||||
'perimeters=i' => \$Slic3r::perimeter_offsets,
|
'perimeters=i' => \$Slic3r::perimeter_offsets,
|
||||||
'solid-layers=i' => \$Slic3r::solid_layers,
|
'solid-layers=i' => \$Slic3r::solid_layers,
|
||||||
|
'fill-type=s' => \$Slic3r::fill_type,
|
||||||
'fill-density=f' => \$Slic3r::fill_density,
|
'fill-density=f' => \$Slic3r::fill_density,
|
||||||
'fill-angle=i' => \$Slic3r::fill_angle,
|
'fill-angle=i' => \$Slic3r::fill_angle,
|
||||||
'temperature=i' => \$Slic3r::temperature,
|
'temperature=i' => \$Slic3r::temperature,
|
||||||
|
52
t/polyclip.t
52
t/polyclip.t
@ -1,14 +1,26 @@
|
|||||||
use Test::More;
|
use Test::More;
|
||||||
|
|
||||||
plan tests => 10;
|
plan tests => 13;
|
||||||
|
|
||||||
BEGIN {
|
BEGIN {
|
||||||
use FindBin;
|
use FindBin;
|
||||||
use lib "$FindBin::Bin/../lib";
|
use lib "$FindBin::Bin/../lib";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
use Math::Clipper qw(is_counter_clockwise);
|
||||||
use Slic3r;
|
use Slic3r;
|
||||||
|
|
||||||
|
#==========================================================
|
||||||
|
|
||||||
|
is Slic3r::Geometry::point_in_segment([10, 10], [ [5, 10], [20, 10] ]), 1, 'point in horizontal segment';
|
||||||
|
is Slic3r::Geometry::point_in_segment([30, 10], [ [5, 10], [20, 10] ]), 0, 'point not in horizontal segment';
|
||||||
|
is Slic3r::Geometry::point_in_segment([10, 10], [ [10, 5], [10, 20] ]), 1, 'point in vertical segment';
|
||||||
|
is Slic3r::Geometry::point_in_segment([10, 30], [ [10, 5], [10, 20] ]), 0, 'point not in vertical segment';
|
||||||
|
is Slic3r::Geometry::point_in_segment([15, 15], [ [10, 10], [20, 20] ]), 1, 'point in diagonal segment';
|
||||||
|
is Slic3r::Geometry::point_in_segment([20, 15], [ [10, 10], [20, 20] ]), 0, 'point not in diagonal segment';
|
||||||
|
|
||||||
|
#==========================================================
|
||||||
|
|
||||||
my $square = [ # ccw
|
my $square = [ # ccw
|
||||||
[10, 10],
|
[10, 10],
|
||||||
[20, 10],
|
[20, 10],
|
||||||
@ -52,11 +64,35 @@ is_deeply $intersections, [
|
|||||||
|
|
||||||
#==========================================================
|
#==========================================================
|
||||||
|
|
||||||
is Slic3r::Geometry::point_in_segment([10, 10], [ [5, 10], [20, 10] ]), 1, 'point in horizontal segment';
|
my $large_circle = [ # ccw
|
||||||
is Slic3r::Geometry::point_in_segment([30, 10], [ [5, 10], [20, 10] ]), 0, 'point not in horizontal segment';
|
[151.8639,288.1192], [133.2778,284.6011], [115.0091,279.6997], [98.2859,270.8606], [82.2734,260.7933],
|
||||||
is Slic3r::Geometry::point_in_segment([10, 10], [ [10, 5], [10, 20] ]), 1, 'point in vertical segment';
|
[68.8974,247.4181], [56.5622,233.0777], [47.7228,216.3558], [40.1617,199.0172], [36.6431,180.4328],
|
||||||
is Slic3r::Geometry::point_in_segment([10, 30], [ [10, 5], [10, 20] ]), 0, 'point not in vertical segment';
|
[34.932,165.2312], [37.5567,165.1101], [41.0547,142.9903], [36.9056,141.4295], [40.199,124.1277],
|
||||||
is Slic3r::Geometry::point_in_segment([15, 15], [ [10, 10], [20, 20] ]), 1, 'point in diagonal segment';
|
[47.7776,106.7972], [56.6335,90.084], [68.9831,75.7557], [82.3712,62.3948], [98.395,52.3429],
|
||||||
is Slic3r::Geometry::point_in_segment([20, 15], [ [10, 10], [20, 20] ]), 0, 'point not in diagonal segment';
|
[115.1281,43.5199], [133.4004,38.6374], [151.9884,35.1378], [170.8905,35.8571], [189.6847,37.991],
|
||||||
|
[207.5349,44.2488], [224.8662,51.8273], [240.0786,63.067], [254.407,75.4169], [265.6311,90.6406],
|
||||||
|
[275.6832,106.6636], [281.9225,124.52], [286.8064,142.795], [287.5061,161.696], [286.7874,180.5972],
|
||||||
|
[281.8856,198.8664], [275.6283,216.7169], [265.5604,232.7294], [254.3211,247.942], [239.9802,260.2776],
|
||||||
|
[224.757,271.5022], [207.4179,279.0635], [189.5605,285.3035], [170.7649,287.4188],
|
||||||
|
];
|
||||||
|
is is_counter_clockwise($large_circle), 1, "contour is counter-clockwise";
|
||||||
|
|
||||||
|
my $small_circle = [ # cw
|
||||||
|
[158.227,215.9007], [164.5136,215.9007], [175.15,214.5007], [184.5576,210.6044], [190.2268,207.8743],
|
||||||
|
[199.1462,201.0306], [209.0146,188.346], [213.5135,177.4829], [214.6979,168.4866], [216.1025,162.3325],
|
||||||
|
[214.6463,151.2703], [213.2471,145.1399], [209.0146,134.9203], [199.1462,122.2357], [189.8944,115.1366],
|
||||||
|
[181.2504,111.5567], [175.5684,108.8205], [164.5136,107.3655], [158.2269,107.3655], [147.5907,108.7656],
|
||||||
|
[138.183,112.6616], [132.5135,115.3919], [123.5943,122.2357], [113.7259,134.92], [109.2269,145.7834],
|
||||||
|
[108.0426,154.7799], [106.638,160.9339], [108.0941,171.9957], [109.4933,178.1264], [113.7259,188.3463],
|
||||||
|
[123.5943,201.0306], [132.8461,208.1296], [141.4901,211.7094], [147.172,214.4458],
|
||||||
|
];
|
||||||
|
is is_counter_clockwise($small_circle), 0, "hole is clockwise";
|
||||||
|
|
||||||
|
$line = [ [152.741724,288.086671142818], [152.741724,34.166466971035] ];
|
||||||
|
|
||||||
|
my $intersections = Slic3r::Geometry::clip_segment_complex_polygon($line, [ $large_circle, $small_circle ]);
|
||||||
|
is_deeply $intersections, [
|
||||||
|
[ [152.741724, 35.166466971035], [152.741724, 108.087543109156] ],
|
||||||
|
[ [152.741724, 215.178806915206], [152.741724, 288.086671142818] ],
|
||||||
|
], 'line is clipped to square with hole';
|
||||||
|
|
||||||
#==========================================================
|
|
||||||
|
Loading…
Reference in New Issue
Block a user