Ported "avoid crossing perimeters" and bridging unit tests from Perl
to C++. Further reduced Perl bindings. Got rid of the ExPolygonCollection wrapper, replaced with ExPolygons.
This commit is contained in:
parent
a627614b58
commit
576c167bd5
42 changed files with 204 additions and 1006 deletions
93
t/angles.t
93
t/angles.t
|
@ -1,93 +0,0 @@
|
|||
use Test::More;
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
plan tests => 34;
|
||||
|
||||
BEGIN {
|
||||
use FindBin;
|
||||
use lib "$FindBin::Bin/../lib";
|
||||
use local::lib "$FindBin::Bin/../local-lib";
|
||||
}
|
||||
|
||||
use Slic3r;
|
||||
use Slic3r::Geometry qw(rad2deg_dir angle3points 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_orientation([ [0, 0], [10, 0] ]), (0), 'E orientation';
|
||||
is line_orientation([ [0, 0], [0, 10] ]), (PI/2), 'N orientation';
|
||||
is line_orientation([ [10, 0], [0, 0] ]), (PI), 'W orientation';
|
||||
is line_orientation([ [0, 10], [0, 0] ]), (PI*3/2), 'S orientation';
|
||||
|
||||
is line_orientation([ [0, 0], [10, 10] ]), (PI*1/4), 'NE orientation';
|
||||
is line_orientation([ [10, 0], [0, 10] ]), (PI*3/4), 'NW orientation';
|
||||
is line_orientation([ [10, 10], [0, 0] ]), (PI*5/4), 'SW orientation';
|
||||
is line_orientation([ [0, 10], [10, 0] ]), (PI*7/4), 'SE orientation';
|
||||
}
|
||||
|
||||
#==========================================================
|
||||
|
||||
{
|
||||
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°';
|
||||
is rad2deg_dir(PI/6*2), 30, '60°';
|
||||
}
|
||||
|
||||
#==========================================================
|
||||
|
||||
{
|
||||
is angle3points([0,0], [10,0], [0,10]), PI/2, 'CW angle3points';
|
||||
is angle3points([0,0], [0,10], [10,0]), PI/2*3, 'CCW angle3points';
|
||||
}
|
||||
|
||||
#==========================================================
|
||||
|
||||
sub line_atan {
|
||||
my ($l) = @_;
|
||||
return Slic3r::Line->new(@$l)->atan2_;
|
||||
}
|
||||
|
||||
sub line_orientation {
|
||||
my ($l) = @_;
|
||||
return Slic3r::Line->new(@$l)->orientation;
|
||||
}
|
||||
|
||||
sub line_direction {
|
||||
my ($l) = @_;
|
||||
return Slic3r::Line->new(@$l)->direction;
|
||||
}
|
|
@ -1,22 +0,0 @@
|
|||
use Test::More tests => 1;
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
BEGIN {
|
||||
use FindBin;
|
||||
use lib "$FindBin::Bin/../lib";
|
||||
use local::lib "$FindBin::Bin/../local-lib";
|
||||
}
|
||||
|
||||
use List::Util qw(first sum);
|
||||
use Slic3r;
|
||||
use Slic3r::Test;
|
||||
|
||||
{
|
||||
my $config = Slic3r::Config::new_from_defaults;
|
||||
$config->set('avoid_crossing_perimeters', 2);
|
||||
my $print = Slic3r::Test::init_print('20mm_cube', config => $config, duplicate => 2);
|
||||
ok my $gcode = Slic3r::Test::gcode($print), "no crash with avoid_crossing_perimeters and multiple objects";
|
||||
}
|
||||
|
||||
__END__
|
137
t/bridges.t
137
t/bridges.t
|
@ -1,137 +0,0 @@
|
|||
use Test::More tests => 16;
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
BEGIN {
|
||||
use FindBin;
|
||||
use lib "$FindBin::Bin/../lib";
|
||||
use local::lib "$FindBin::Bin/../local-lib";
|
||||
}
|
||||
|
||||
use List::Util qw(first sum);
|
||||
use Slic3r;
|
||||
use Slic3r::Geometry qw(scale epsilon deg2rad rad2deg);
|
||||
use Slic3r::Test;
|
||||
|
||||
{
|
||||
my $test = sub {
|
||||
my ($bridge_size, $rotate, $expected_angle, $tolerance) = @_;
|
||||
|
||||
my ($x, $y) = @$bridge_size;
|
||||
my $lower = Slic3r::ExPolygon->new(
|
||||
Slic3r::Polygon->new_scale([-2,-2], [$x+2,-2], [$x+2,$y+2], [-2,$y+2]),
|
||||
Slic3r::Polygon->new_scale([0,0], [0,$y], [$x,$y], [$x,0]),
|
||||
);
|
||||
$lower->translate(scale 20, scale 20); # avoid negative coordinates for easier SVG preview
|
||||
$lower->rotate(deg2rad($rotate), [$x/2,$y/2]);
|
||||
my $bridge = $lower->[1]->clone;
|
||||
$bridge->reverse;
|
||||
$bridge = Slic3r::ExPolygon->new($bridge);
|
||||
|
||||
ok check_angle([$lower], $bridge, $expected_angle, $tolerance), 'correct bridge angle for O-shaped overhang';
|
||||
};
|
||||
|
||||
$test->([20,10], 0, 90);
|
||||
$test->([10,20], 0, 0);
|
||||
$test->([20,10], 45, 135, 20);
|
||||
$test->([20,10], 135, 45, 20);
|
||||
}
|
||||
|
||||
{
|
||||
my $bridge = Slic3r::ExPolygon->new(
|
||||
Slic3r::Polygon->new_scale([0,0], [20,0], [20,10], [0,10]),
|
||||
);
|
||||
my $lower = [
|
||||
Slic3r::ExPolygon->new(
|
||||
Slic3r::Polygon->new_scale([-2,0], [0,0], [0,10], [-2,10]),
|
||||
),
|
||||
];
|
||||
$_->translate(scale 20, scale 20) for $bridge, @$lower; # avoid negative coordinates for easier SVG preview
|
||||
|
||||
$lower->[1] = $lower->[0]->clone;
|
||||
$lower->[1]->translate(scale 22, 0);
|
||||
|
||||
ok check_angle($lower, $bridge, 0), 'correct bridge angle for two-sided bridge';
|
||||
}
|
||||
|
||||
{
|
||||
my $bridge = Slic3r::ExPolygon->new(
|
||||
Slic3r::Polygon->new_scale([0,0], [20,0], [10,10], [0,10]),
|
||||
);
|
||||
my $lower = [
|
||||
Slic3r::ExPolygon->new(
|
||||
Slic3r::Polygon->new_scale([0,0], [0,10], [10,10], [10,12], [-2,12], [-2,-2], [22,-2], [22,0]),
|
||||
),
|
||||
];
|
||||
$_->translate(scale 20, scale 20) for $bridge, @$lower; # avoid negative coordinates for easier SVG preview
|
||||
|
||||
ok check_angle($lower, $bridge, 135), 'correct bridge angle for C-shaped overhang';
|
||||
}
|
||||
|
||||
{
|
||||
my $bridge = Slic3r::ExPolygon->new(
|
||||
Slic3r::Polygon->new_scale([10,10],[20,10],[20,20], [10,20]),
|
||||
);
|
||||
my $lower = [
|
||||
Slic3r::ExPolygon->new(
|
||||
Slic3r::Polygon->new_scale([10,10],[10,20],[20,20],[30,30],[0,30],[0,0]),
|
||||
),
|
||||
];
|
||||
$_->translate(scale 20, scale 20) for $bridge, @$lower; # avoid negative coordinates for easier SVG preview
|
||||
|
||||
ok check_angle($lower, $bridge, 45, undef, $bridge->area/2), 'correct bridge angle for square overhang with L-shaped anchors';
|
||||
}
|
||||
|
||||
sub check_angle {
|
||||
my ($lower, $bridge, $expected, $tolerance, $expected_coverage) = @_;
|
||||
|
||||
if (ref($lower) eq 'ARRAY') {
|
||||
$lower = Slic3r::ExPolygon::Collection->new(@$lower);
|
||||
}
|
||||
|
||||
$expected_coverage //= -1;
|
||||
$expected_coverage = $bridge->area if $expected_coverage == -1;
|
||||
|
||||
my $bd = Slic3r::BridgeDetector->new($bridge, $lower, scale 0.5);
|
||||
|
||||
$tolerance //= rad2deg($bd->resolution) + epsilon;
|
||||
$bd->detect_angle;
|
||||
my $result = $bd->angle;
|
||||
my $coverage = $bd->coverage;
|
||||
is sum(map $_->area, @$coverage), $expected_coverage, 'correct coverage area';
|
||||
|
||||
# our epsilon is equal to the steps used by the bridge detection algorithm
|
||||
###use XXX; YYY [ rad2deg($result), $expected ];
|
||||
# returned value must be non-negative, check for that too
|
||||
my $delta=rad2deg($result) - $expected;
|
||||
$delta-=180 if $delta>=180 - epsilon;
|
||||
return defined $result && $result>=0 && abs($delta) < $tolerance;
|
||||
}
|
||||
|
||||
{
|
||||
my $config = Slic3r::Config::new_from_defaults;
|
||||
$config->set('top_solid_layers', 0); # to prevent bridging on sparse infill
|
||||
$config->set('bridge_speed', 99);
|
||||
|
||||
my $print = Slic3r::Test::init_print('bridge', config => $config);
|
||||
|
||||
my %extrusions = (); # angle => length
|
||||
Slic3r::GCode::Reader->new->parse(Slic3r::Test::gcode($print), sub {
|
||||
my ($self, $cmd, $args, $info) = @_;
|
||||
|
||||
if ($cmd eq 'G1' && ($args->{F} // $self->F)/60 == $config->bridge_speed) {
|
||||
my $line = Slic3r::Line->new_scale(
|
||||
[ $self->X, $self->Y ],
|
||||
[ $info->{new_X}, $info->{new_Y} ],
|
||||
);
|
||||
my $angle = $line->direction;
|
||||
$extrusions{$angle} //= 0;
|
||||
$extrusions{$angle} += $line->length;
|
||||
}
|
||||
});
|
||||
ok !!%extrusions, "bridge is generated";
|
||||
my ($main_angle) = sort { $extrusions{$b} <=> $extrusions{$a} } keys %extrusions;
|
||||
is $main_angle, 0, "bridge has the expected direction";
|
||||
}
|
||||
|
||||
__END__
|
|
@ -1,87 +0,0 @@
|
|||
use Test::More;
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
plan tests => 11;
|
||||
|
||||
BEGIN {
|
||||
use FindBin;
|
||||
use lib "$FindBin::Bin/../lib";
|
||||
use local::lib "$FindBin::Bin/../local-lib";
|
||||
}
|
||||
|
||||
use Slic3r;
|
||||
use Slic3r::Geometry qw(collinear);
|
||||
|
||||
#==========================================================
|
||||
|
||||
{
|
||||
my @lines = (
|
||||
Slic3r::Line->new([0,4], [4,2]),
|
||||
Slic3r::Line->new([2,3], [8,0]),
|
||||
Slic3r::Line->new([6,1], [8,0]),
|
||||
);
|
||||
is collinear($lines[0], $lines[1]), 1, 'collinear';
|
||||
is collinear($lines[1], $lines[2]), 1, 'collinear';
|
||||
is collinear($lines[0], $lines[2]), 1, 'collinear';
|
||||
}
|
||||
|
||||
#==========================================================
|
||||
|
||||
{
|
||||
# horizontal
|
||||
my @lines = (
|
||||
Slic3r::Line->new([0,1], [5,1]),
|
||||
Slic3r::Line->new([2,1], [8,1]),
|
||||
);
|
||||
is collinear($lines[0], $lines[1]), 1, 'collinear';
|
||||
}
|
||||
|
||||
#==========================================================
|
||||
|
||||
{
|
||||
# vertical
|
||||
my @lines = (
|
||||
Slic3r::Line->new([1,0], [1,5]),
|
||||
Slic3r::Line->new([1,2], [1,8]),
|
||||
);
|
||||
is collinear($lines[0], $lines[1]), 1, 'collinear';
|
||||
}
|
||||
|
||||
#==========================================================
|
||||
|
||||
{
|
||||
# non overlapping
|
||||
my @lines = (
|
||||
Slic3r::Line->new([0,1], [5,1]),
|
||||
Slic3r::Line->new([7,1], [10,1]),
|
||||
);
|
||||
is collinear($lines[0], $lines[1], 1), 0, 'non overlapping';
|
||||
is collinear($lines[0], $lines[1], 0), 1, 'overlapping';
|
||||
}
|
||||
|
||||
#==========================================================
|
||||
|
||||
{
|
||||
# with one common point
|
||||
my @lines = (
|
||||
Slic3r::Line->new([0,4], [4,2]),
|
||||
Slic3r::Line->new([4,2], [8,0]),
|
||||
);
|
||||
is collinear($lines[0], $lines[1], 1), 1, 'one common point';
|
||||
is collinear($lines[0], $lines[1], 0), 1, 'one common point';
|
||||
}
|
||||
|
||||
#==========================================================
|
||||
|
||||
{
|
||||
# not collinear
|
||||
my @lines = (
|
||||
Slic3r::Line->new([290000000,690525600], [285163380,684761540]),
|
||||
Slic3r::Line->new([285163380,684761540], [193267599,575244400]),
|
||||
);
|
||||
is collinear($lines[0], $lines[1], 0), 0, 'not collinear';
|
||||
is collinear($lines[0], $lines[1], 1), 0, 'not collinear';
|
||||
}
|
||||
|
||||
#==========================================================
|
64
t/geometry.t
64
t/geometry.t
|
@ -2,7 +2,7 @@ use Test::More;
|
|||
use strict;
|
||||
use warnings;
|
||||
|
||||
plan tests => 26;
|
||||
plan tests => 11;
|
||||
|
||||
BEGIN {
|
||||
use FindBin;
|
||||
|
@ -11,7 +11,7 @@ BEGIN {
|
|||
}
|
||||
|
||||
use Slic3r;
|
||||
use Slic3r::Geometry qw(PI polygon_is_convex
|
||||
use Slic3r::Geometry qw(PI
|
||||
chained_path_from epsilon scale);
|
||||
|
||||
{
|
||||
|
@ -27,18 +27,6 @@ use Slic3r::Geometry qw(PI polygon_is_convex
|
|||
|
||||
#==========================================================
|
||||
|
||||
my $line1 = [ [5, 15], [30, 15] ];
|
||||
my $line2 = [ [10, 20], [10, 10] ];
|
||||
is_deeply Slic3r::Geometry::line_intersection($line1, $line2, 1)->arrayref, [10, 15], 'line_intersection';
|
||||
|
||||
#==========================================================
|
||||
|
||||
$line1 = [ [73.6310778185108/0.0000001, 371.74239268924/0.0000001], [73.6310778185108/0.0000001, 501.74239268924/0.0000001] ];
|
||||
$line2 = [ [75/0.0000001, 437.9853/0.0000001], [62.7484/0.0000001, 440.4223/0.0000001] ];
|
||||
isnt Slic3r::Geometry::line_intersection($line1, $line2, 1), undef, 'line_intersection';
|
||||
|
||||
#==========================================================
|
||||
|
||||
my $polygons = [
|
||||
Slic3r::Polygon->new( # contour, ccw
|
||||
[45919000, 515273900], [14726100, 461246400], [14726100, 348753500], [33988700, 315389800],
|
||||
|
@ -57,54 +45,6 @@ my $polygons = [
|
|||
),
|
||||
];
|
||||
|
||||
#==========================================================
|
||||
|
||||
{
|
||||
my $p1 = [10, 10];
|
||||
my $p2 = [10, 20];
|
||||
my $p3 = [10, 30];
|
||||
my $p4 = [20, 20];
|
||||
my $p5 = [0, 20];
|
||||
|
||||
is Slic3r::Geometry::angle3points($p2, $p3, $p1), PI(), 'angle3points';
|
||||
is Slic3r::Geometry::angle3points($p2, $p1, $p3), PI(), 'angle3points';
|
||||
is Slic3r::Geometry::angle3points($p2, $p3, $p4), PI()/2*3, 'angle3points';
|
||||
is Slic3r::Geometry::angle3points($p2, $p4, $p3), PI()/2, 'angle3points';
|
||||
is Slic3r::Geometry::angle3points($p2, $p1, $p4), PI()/2, 'angle3points';
|
||||
is Slic3r::Geometry::angle3points($p2, $p1, $p5), PI()/2*3, 'angle3points';
|
||||
}
|
||||
|
||||
{
|
||||
my $p1 = [30, 30];
|
||||
my $p2 = [20, 20];
|
||||
my $p3 = [10, 10];
|
||||
my $p4 = [30, 10];
|
||||
|
||||
is Slic3r::Geometry::angle3points($p2, $p1, $p3), PI(), 'angle3points';
|
||||
is Slic3r::Geometry::angle3points($p2, $p1, $p4), PI()/2*3, 'angle3points';
|
||||
is Slic3r::Geometry::angle3points($p2, $p1, $p1), 2*PI(), 'angle3points';
|
||||
}
|
||||
|
||||
#==========================================================
|
||||
|
||||
{
|
||||
my $cw_square = [ [0,0], [0,10], [10,10], [10,0] ];
|
||||
is polygon_is_convex($cw_square), 0, 'cw square is not convex';
|
||||
is polygon_is_convex([ reverse @$cw_square ]), 1, 'ccw square is convex';
|
||||
|
||||
my $convex1 = [ [0,0], [10,0], [10,10], [0,10], [0,6], [4,6], [4,4], [0,4] ];
|
||||
is polygon_is_convex($convex1), 0, 'concave polygon';
|
||||
}
|
||||
|
||||
#==========================================================
|
||||
|
||||
{
|
||||
my $polyline = Slic3r::Polyline->new([0, 0], [10, 0], [20, 0]);
|
||||
is_deeply [ map $_->pp, @{$polyline->lines} ], [
|
||||
[ [0, 0], [10, 0] ],
|
||||
[ [10, 0], [20, 0] ],
|
||||
], 'polyline_lines';
|
||||
}
|
||||
|
||||
#==========================================================
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue