Skip to content

Commit

Permalink
Ported "avoid crossing perimeters" and bridging unit tests from Perl
Browse files Browse the repository at this point in the history
to C++.
Further reduced Perl bindings.
Got rid of the ExPolygonCollection wrapper, replaced with ExPolygons.
  • Loading branch information
bubnikv committed May 4, 2022
1 parent a627614 commit 576c167
Show file tree
Hide file tree
Showing 42 changed files with 204 additions and 1,006 deletions.
7 changes: 0 additions & 7 deletions lib/Slic3r/ExPolygon.pm
Original file line number Diff line number Diff line change
Expand Up @@ -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;
170 changes: 0 additions & 170 deletions lib/Slic3r/Geometry.pm
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -26,7 +19,6 @@ our @EXPORT_OK = qw(
chained_path_from
deg2rad
rad2deg
rad2deg_dir
);

use constant PI => 4 * atan2(1, 1);
Expand All @@ -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) = @_;
Expand All @@ -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;
2 changes: 0 additions & 2 deletions src/libslic3r/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,6 @@ set(SLIC3R_SOURCES
enum_bitmask.hpp
ExPolygon.cpp
ExPolygon.hpp
ExPolygonCollection.cpp
ExPolygonCollection.hpp
Extruder.cpp
Extruder.hpp
ExtrusionEntity.cpp
Expand Down
6 changes: 4 additions & 2 deletions src/libslic3r/ClipperUtils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -240,7 +240,7 @@ TResult clipper_union(

// Perform union of input polygons using the positive rule, convert to ExPolygons.
//FIXME is there any benefit of not doing the boolean / using pftEvenOdd?
ExPolygons ClipperPaths_to_Slic3rExPolygons(const ClipperLib::Paths &input, bool do_union)
inline ExPolygons ClipperPaths_to_Slic3rExPolygons(const ClipperLib::Paths &input, bool do_union)
{
return PolyTreeToExPolygons(clipper_union<ClipperLib::PolyTree>(input, do_union ? ClipperLib::pftNonZero : ClipperLib::pftEvenOdd));
}
Expand Down Expand Up @@ -438,7 +438,7 @@ Slic3r::Polygons offset(const Slic3r::SurfacesPtr &surfaces, const float delta,
{ return to_polygons(expolygons_offset(surfaces, delta, joinType, miterLimit)); }
Slic3r::ExPolygons offset_ex(const Slic3r::ExPolygon &expolygon, const float delta, ClipperLib::JoinType joinType, double miterLimit)
//FIXME one may spare one Clipper Union call.
{ return ClipperPaths_to_Slic3rExPolygons(expolygon_offset(expolygon, delta, joinType, miterLimit)); }
{ return ClipperPaths_to_Slic3rExPolygons(expolygon_offset(expolygon, delta, joinType, miterLimit), /* do union */ false); }
Slic3r::ExPolygons offset_ex(const Slic3r::ExPolygons &expolygons, const float delta, ClipperLib::JoinType joinType, double miterLimit)
{ return PolyTreeToExPolygons(expolygons_offset_pt(expolygons, delta, joinType, miterLimit)); }
Slic3r::ExPolygons offset_ex(const Slic3r::Surfaces &surfaces, const float delta, ClipperLib::JoinType joinType, double miterLimit)
Expand Down Expand Up @@ -713,6 +713,8 @@ Slic3r::Polylines intersection_pl(const Slic3r::Polylines &subject, const Slic3r
{ return _clipper_pl_open(ClipperLib::ctIntersection, ClipperUtils::PolylinesProvider(subject), ClipperUtils::SinglePathProvider(clip.points)); }
Slic3r::Polylines intersection_pl(const Slic3r::Polyline &subject, const Slic3r::Polygons &clip)
{ return _clipper_pl_open(ClipperLib::ctIntersection, ClipperUtils::SinglePathProvider(subject.points), ClipperUtils::PolygonsProvider(clip)); }
Slic3r::Polylines intersection_pl(const Slic3r::Polyline &subject, const Slic3r::ExPolygons &clip)
{ return _clipper_pl_open(ClipperLib::ctIntersection, ClipperUtils::SinglePathProvider(subject.points), ClipperUtils::ExPolygonsProvider(clip)); }
Slic3r::Polylines intersection_pl(const Slic3r::Polylines &subject, const Slic3r::Polygons &clip)
{ return _clipper_pl_open(ClipperLib::ctIntersection, ClipperUtils::PolylinesProvider(subject), ClipperUtils::PolygonsProvider(clip)); }
Slic3r::Polylines intersection_pl(const Slic3r::Polylines &subject, const Slic3r::ExPolygons &clip)
Expand Down
16 changes: 12 additions & 4 deletions src/libslic3r/ClipperUtils.hpp
Original file line number Diff line number Diff line change
@@ -1,17 +1,27 @@
#ifndef slic3r_ClipperUtils_hpp_
#define slic3r_ClipperUtils_hpp_

//#define SLIC3R_USE_CLIPPER2

#include "libslic3r.h"
#include "clipper.hpp"
#include "ExPolygon.hpp"
#include "Polygon.hpp"
#include "Surface.hpp"

#ifdef SLIC3R_USE_CLIPPER2

#include <clipper2.clipper.h>

#else /* SLIC3R_USE_CLIPPER2 */

#include "clipper.hpp"
// import these wherever we're included
using Slic3r::ClipperLib::jtMiter;
using Slic3r::ClipperLib::jtRound;
using Slic3r::ClipperLib::jtSquare;

#endif /* SLIC3R_USE_CLIPPER2 */

namespace Slic3r {

static constexpr const float ClipperSafetyOffset = 10.f;
Expand Down Expand Up @@ -298,9 +308,6 @@ namespace ClipperUtils {
};
}

// Perform union of input polygons using the non-zero rule, convert to ExPolygons.
ExPolygons ClipperPaths_to_Slic3rExPolygons(const ClipperLib::Paths &input, bool do_union = false);

// offset Polygons
// Wherever applicable, please use the expand() / shrink() variants instead, they convey their purpose better.
Slic3r::Polygons offset(const Slic3r::Polygon &polygon, const float delta, ClipperLib::JoinType joinType = DefaultJoinType, double miterLimit = DefaultMiterLimit);
Expand Down Expand Up @@ -429,6 +436,7 @@ Slic3r::ExPolygons intersection_ex(const Slic3r::Surfaces &subject, const Slic3r
Slic3r::ExPolygons intersection_ex(const Slic3r::SurfacesPtr &subject, const Slic3r::ExPolygons &clip, ApplySafetyOffset do_safety_offset = ApplySafetyOffset::No);
Slic3r::Polylines intersection_pl(const Slic3r::Polylines &subject, const Slic3r::Polygon &clip);
Slic3r::Polylines intersection_pl(const Slic3r::Polyline &subject, const Slic3r::Polygons &clip);
Slic3r::Polylines intersection_pl(const Slic3r::Polyline &subject, const Slic3r::ExPolygons &clip);
Slic3r::Polylines intersection_pl(const Slic3r::Polylines &subject, const Slic3r::Polygons &clip);
Slic3r::Polylines intersection_pl(const Slic3r::Polylines &subject, const Slic3r::ExPolygons &clip);
Slic3r::Polylines intersection_pl(const Slic3r::Polygons &subject, const Slic3r::Polygons &clip);
Expand Down
5 changes: 0 additions & 5 deletions src/libslic3r/EdgeGrid.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -136,11 +136,6 @@ void EdgeGrid::Grid::create(const ExPolygons &expolygons, coord_t resolution)
create_from_m_contours(resolution);
}

void EdgeGrid::Grid::create(const ExPolygonCollection &expolygons, coord_t resolution)
{
create(expolygons.expolygons, resolution);
}

// m_contours has been initialized. Now fill in the edge grid.
void EdgeGrid::Grid::create_from_m_contours(coord_t resolution)
{
Expand Down
5 changes: 1 addition & 4 deletions src/libslic3r/EdgeGrid.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
#include "Point.hpp"
#include "BoundingBox.hpp"
#include "ExPolygon.hpp"
#include "ExPolygonCollection.hpp"

namespace Slic3r {
namespace EdgeGrid {
Expand Down Expand Up @@ -112,7 +111,6 @@ class Grid
void create(const std::vector<Points> &polygons, coord_t resolution) { this->create(polygons, resolution, false); }
void create(const ExPolygon &expoly, coord_t resolution);
void create(const ExPolygons &expolygons, coord_t resolution);
void create(const ExPolygonCollection &expolygons, coord_t resolution);

const std::vector<Contour>& contours() const { return m_contours; }

Expand All @@ -123,7 +121,6 @@ class Grid
bool intersect(const Polygons &polygons) { for (size_t i = 0; i < polygons.size(); ++ i) if (intersect(polygons[i])) return true; return false; }
bool intersect(const ExPolygon &expoly) { if (intersect(expoly.contour)) return true; for (size_t i = 0; i < expoly.holes.size(); ++ i) if (intersect(expoly.holes[i])) return true; return false; }
bool intersect(const ExPolygons &expolygons) { for (size_t i = 0; i < expolygons.size(); ++ i) if (intersect(expolygons[i])) return true; return false; }
bool intersect(const ExPolygonCollection &expolygons) { return intersect(expolygons.expolygons); }

// Test, whether a point is inside a contour.
bool inside(const Point &pt);
Expand Down Expand Up @@ -391,7 +388,7 @@ class Grid

// Referencing the source contours.
// This format allows one to work with any Slic3r fixed point contour format
// (Polygon, ExPolygon, ExPolygonCollection etc).
// (Polygon, ExPolygon, ExPolygons etc).
std::vector<Contour> m_contours;

// Referencing a contour and a line segment of m_contours.
Expand Down
2 changes: 1 addition & 1 deletion src/libslic3r/ExPolygon.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
namespace Slic3r {

class ExPolygon;
typedef std::vector<ExPolygon> ExPolygons;
using ExPolygons = std::vector<ExPolygon>;

class ExPolygon
{
Expand Down
Loading

0 comments on commit 576c167

Please sign in to comment.