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
|
@ -9,11 +9,4 @@ sub bounding_box {
|
|||
return $self->contour->bounding_box;
|
||||
}
|
||||
|
||||
package Slic3r::ExPolygon::Collection;
|
||||
|
||||
sub size {
|
||||
my $self = shift;
|
||||
return [ Slic3r::Geometry::size_2D([ map @$_, map @$_, @$self ]) ];
|
||||
}
|
||||
|
||||
1;
|
||||
|
|
|
@ -9,13 +9,6 @@ our @ISA = qw(Exporter);
|
|||
our @EXPORT_OK = qw(
|
||||
PI epsilon
|
||||
|
||||
angle3points
|
||||
collinear
|
||||
dot
|
||||
line_intersection
|
||||
normalize
|
||||
polyline_lines
|
||||
polygon_is_convex
|
||||
scale
|
||||
unscale
|
||||
scaled_epsilon
|
||||
|
@ -26,7 +19,6 @@ our @EXPORT_OK = qw(
|
|||
chained_path_from
|
||||
deg2rad
|
||||
rad2deg
|
||||
rad2deg_dir
|
||||
);
|
||||
|
||||
use constant PI => 4 * atan2(1, 1);
|
||||
|
@ -43,136 +35,6 @@ sub scaled_epsilon () { epsilon / &Slic3r::SCALING_FACTOR }
|
|||
sub scale ($) { $_[0] / &Slic3r::SCALING_FACTOR }
|
||||
sub unscale ($) { $_[0] * &Slic3r::SCALING_FACTOR }
|
||||
|
||||
# used by geometry.t
|
||||
sub polyline_lines {
|
||||
my ($polyline) = @_;
|
||||
my @points = @$polyline;
|
||||
return map Slic3r::Line->new(@points[$_, $_+1]), 0 .. $#points-1;
|
||||
}
|
||||
|
||||
# polygon must be simple (non complex) and ccw
|
||||
sub polygon_is_convex {
|
||||
my ($points) = @_;
|
||||
for (my $i = 0; $i <= $#$points; $i++) {
|
||||
my $angle = angle3points($points->[$i-1], $points->[$i-2], $points->[$i]);
|
||||
return 0 if $angle < PI;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
sub normalize {
|
||||
my ($line) = @_;
|
||||
|
||||
my $len = sqrt( ($line->[X]**2) + ($line->[Y]**2) + ($line->[Z]**2) )
|
||||
or return [0, 0, 0]; # to avoid illegal division by zero
|
||||
return [ map $_ / $len, @$line ];
|
||||
}
|
||||
|
||||
# 2D dot product
|
||||
# used by 3DScene.pm
|
||||
sub dot {
|
||||
my ($u, $v) = @_;
|
||||
return $u->[X] * $v->[X] + $u->[Y] * $v->[Y];
|
||||
}
|
||||
|
||||
sub line_intersection {
|
||||
my ($line1, $line2, $require_crossing) = @_;
|
||||
$require_crossing ||= 0;
|
||||
|
||||
my $intersection = _line_intersection(map @$_, @$line1, @$line2);
|
||||
return (ref $intersection && $intersection->[1] == $require_crossing)
|
||||
? $intersection->[0]
|
||||
: undef;
|
||||
}
|
||||
|
||||
# Used by test cases.
|
||||
sub collinear {
|
||||
my ($line1, $line2, $require_overlapping) = @_;
|
||||
my $intersection = _line_intersection(map @$_, @$line1, @$line2);
|
||||
return 0 unless !ref($intersection)
|
||||
&& ($intersection eq 'parallel collinear'
|
||||
|| ($intersection eq 'parallel vertical' && abs($line1->[A][X] - $line2->[A][X]) < epsilon));
|
||||
|
||||
if ($require_overlapping) {
|
||||
my @box_a = bounding_box([ $line1->[0], $line1->[1] ]);
|
||||
my @box_b = bounding_box([ $line2->[0], $line2->[1] ]);
|
||||
return 0 unless bounding_box_intersect( 2, @box_a, @box_b );
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
sub _line_intersection {
|
||||
my ( $x0, $y0, $x1, $y1, $x2, $y2, $x3, $y3 ) = @_;
|
||||
|
||||
my ($x, $y); # The as-yet-undetermined intersection point.
|
||||
|
||||
my $dy10 = $y1 - $y0; # dyPQ, dxPQ are the coordinate differences
|
||||
my $dx10 = $x1 - $x0; # between the points P and Q.
|
||||
my $dy32 = $y3 - $y2;
|
||||
my $dx32 = $x3 - $x2;
|
||||
|
||||
my $dy10z = abs( $dy10 ) < epsilon; # Is the difference $dy10 "zero"?
|
||||
my $dx10z = abs( $dx10 ) < epsilon;
|
||||
my $dy32z = abs( $dy32 ) < epsilon;
|
||||
my $dx32z = abs( $dx32 ) < epsilon;
|
||||
|
||||
my $dyx10; # The slopes.
|
||||
my $dyx32;
|
||||
|
||||
$dyx10 = $dy10 / $dx10 unless $dx10z;
|
||||
$dyx32 = $dy32 / $dx32 unless $dx32z;
|
||||
|
||||
# Now we know all differences and the slopes;
|
||||
# we can detect horizontal/vertical special cases.
|
||||
# E.g., slope = 0 means a horizontal line.
|
||||
|
||||
unless ( defined $dyx10 or defined $dyx32 ) {
|
||||
return "parallel vertical";
|
||||
}
|
||||
elsif ( $dy10z and not $dy32z ) { # First line horizontal.
|
||||
$y = $y0;
|
||||
$x = $x2 + ( $y - $y2 ) * $dx32 / $dy32;
|
||||
}
|
||||
elsif ( not $dy10z and $dy32z ) { # Second line horizontal.
|
||||
$y = $y2;
|
||||
$x = $x0 + ( $y - $y0 ) * $dx10 / $dy10;
|
||||
}
|
||||
elsif ( $dx10z and not $dx32z ) { # First line vertical.
|
||||
$x = $x0;
|
||||
$y = $y2 + $dyx32 * ( $x - $x2 );
|
||||
}
|
||||
elsif ( not $dx10z and $dx32z ) { # Second line vertical.
|
||||
$x = $x2;
|
||||
$y = $y0 + $dyx10 * ( $x - $x0 );
|
||||
}
|
||||
elsif ( abs( $dyx10 - $dyx32 ) < epsilon ) {
|
||||
# The slopes are suspiciously close to each other.
|
||||
# Either we have parallel collinear or just parallel lines.
|
||||
|
||||
# The bounding box checks have already weeded the cases
|
||||
# "parallel horizontal" and "parallel vertical" away.
|
||||
|
||||
my $ya = $y0 - $dyx10 * $x0;
|
||||
my $yb = $y2 - $dyx32 * $x2;
|
||||
|
||||
return "parallel collinear" if abs( $ya - $yb ) < epsilon;
|
||||
return "parallel";
|
||||
}
|
||||
else {
|
||||
# None of the special cases matched.
|
||||
# We have a "honest" line intersection.
|
||||
|
||||
$x = ($y2 - $y0 + $dyx10*$x0 - $dyx32*$x2)/($dyx10 - $dyx32);
|
||||
$y = $y0 + $dyx10 * ($x - $x0);
|
||||
}
|
||||
|
||||
my $h10 = $dx10 ? ($x - $x0) / $dx10 : ($dy10 ? ($y - $y0) / $dy10 : 1);
|
||||
my $h32 = $dx32 ? ($x - $x2) / $dx32 : ($dy32 ? ($y - $y2) / $dy32 : 1);
|
||||
|
||||
return [Slic3r::Point->new($x, $y), $h10 >= 0 && $h10 <= 1 && $h32 >= 0 && $h32 <= 1];
|
||||
}
|
||||
|
||||
# 2D
|
||||
sub bounding_box {
|
||||
my ($points) = @_;
|
||||
|
@ -199,36 +61,4 @@ sub size_2D {
|
|||
);
|
||||
}
|
||||
|
||||
# Used by sub collinear, which is used by test cases.
|
||||
# bounding_box_intersect($d, @a, @b)
|
||||
# Return true if the given bounding boxes @a and @b intersect
|
||||
# in $d dimensions. Used by sub collinear.
|
||||
sub bounding_box_intersect {
|
||||
my ( $d, @bb ) = @_; # Number of dimensions and box coordinates.
|
||||
my @aa = splice( @bb, 0, 2 * $d ); # The first box.
|
||||
# (@bb is the second one.)
|
||||
|
||||
# Must intersect in all dimensions.
|
||||
for ( my $i_min = 0; $i_min < $d; $i_min++ ) {
|
||||
my $i_max = $i_min + $d; # The index for the maximum.
|
||||
return 0 if ( $aa[ $i_max ] + epsilon ) < $bb[ $i_min ];
|
||||
return 0 if ( $bb[ $i_max ] + epsilon ) < $aa[ $i_min ];
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
# Used by test cases.
|
||||
# this assumes a CCW rotation from $p2 to $p3 around $p1
|
||||
sub angle3points {
|
||||
my ($p1, $p2, $p3) = @_;
|
||||
# p1 is the center
|
||||
|
||||
my $angle = atan2($p2->[X] - $p1->[X], $p2->[Y] - $p1->[Y])
|
||||
- atan2($p3->[X] - $p1->[X], $p3->[Y] - $p1->[Y]);
|
||||
|
||||
# we only want to return only positive angles
|
||||
return $angle <= 0 ? $angle + 2*PI() : $angle;
|
||||
}
|
||||
|
||||
1;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue