diff --git a/lib/Slic3r/ExPolygon.pm b/lib/Slic3r/ExPolygon.pm index 6adb650c21..6337cb9a1a 100644 --- a/lib/Slic3r/ExPolygon.pm +++ b/lib/Slic3r/ExPolygon.pm @@ -12,11 +12,6 @@ sub offset { return Slic3r::Geometry::Clipper::offset(\@$self, @_); } -sub offset_ex { - my $self = shift; - return Slic3r::Geometry::Clipper::offset_ex(\@$self, @_); -} - sub noncollapsing_offset_ex { my $self = shift; my ($distance, @params) = @_; diff --git a/lib/Slic3r/Geometry.pm b/lib/Slic3r/Geometry.pm index 286a73e2de..ca262fc766 100644 --- a/lib/Slic3r/Geometry.pm +++ b/lib/Slic3r/Geometry.pm @@ -14,10 +14,8 @@ our @EXPORT_OK = qw( dot line_intersection normalize - point_in_segment polyline_lines polygon_is_convex - polygon_segment_having_point scale unscale scaled_epsilon @@ -45,30 +43,6 @@ sub scaled_epsilon () { epsilon / &Slic3r::SCALING_FACTOR } sub scale ($) { $_[0] / &Slic3r::SCALING_FACTOR } sub unscale ($) { $_[0] * &Slic3r::SCALING_FACTOR } -# used by geometry.t, polygon_segment_having_point -sub point_in_segment { - my ($point, $line) = @_; - - my ($x, $y) = @$point; - my $line_p = $line->pp; - my @line_x = sort { $a <=> $b } $line_p->[A][X], $line_p->[B][X]; - my @line_y = sort { $a <=> $b } $line_p->[A][Y], $line_p->[B][Y]; - - # check whether the point is in the segment bounding box - return 0 unless $x >= ($line_x[0] - epsilon) && $x <= ($line_x[1] + epsilon) - && $y >= ($line_y[0] - epsilon) && $y <= ($line_y[1] + epsilon); - - # if line is vertical, check whether point's X is the same as the line - if ($line_p->[A][X] == $line_p->[B][X]) { - return abs($x - $line_p->[A][X]) < epsilon ? 1 : 0; - } - - # calculate the Y in line at X of the point - my $y3 = $line_p->[A][Y] + ($line_p->[B][Y] - $line_p->[A][Y]) - * ($x - $line_p->[A][X]) / ($line_p->[B][X] - $line_p->[A][X]); - return abs($y3 - $y) < epsilon ? 1 : 0; -} - # used by geometry.t sub polyline_lines { my ($polyline) = @_; @@ -76,17 +50,6 @@ sub polyline_lines { return map Slic3r::Line->new(@points[$_, $_+1]), 0 .. $#points-1; } -# given a $polygon, return the (first) segment having $point -# used by geometry.t -sub polygon_segment_having_point { - my ($polygon, $point) = @_; - - foreach my $line (@{ $polygon->lines }) { - return $line if point_in_segment($point, $line); - } - return undef; -} - # polygon must be simple (non complex) and ccw sub polygon_is_convex { my ($points) = @_; diff --git a/lib/Slic3r/Geometry/Clipper.pm b/lib/Slic3r/Geometry/Clipper.pm index b7a7da7727..cfcb622fdb 100644 --- a/lib/Slic3r/Geometry/Clipper.pm +++ b/lib/Slic3r/Geometry/Clipper.pm @@ -6,9 +6,9 @@ require Exporter; our @ISA = qw(Exporter); our @EXPORT_OK = qw( offset - offset_ex offset2_ex + offset2_ex diff_ex diff union_ex intersection_ex JT_ROUND JT_MITER JT_SQUARE - intersection intersection_pl diff_pl union); + intersection diff_pl union); 1; diff --git a/lib/Slic3r/Print/Object.pm b/lib/Slic3r/Print/Object.pm index 0385f88b88..f03a97ea3a 100644 --- a/lib/Slic3r/Print/Object.pm +++ b/lib/Slic3r/Print/Object.pm @@ -7,7 +7,7 @@ use List::Util qw(min max sum first); use Slic3r::Flow ':roles'; use Slic3r::Geometry qw(scale epsilon); use Slic3r::Geometry::Clipper qw(diff diff_ex intersection intersection_ex union union_ex - offset offset_ex offset2_ex JT_MITER); + offset offset2_ex JT_MITER); use Slic3r::Print::State ':steps'; use Slic3r::Surface ':types'; diff --git a/t/geometry.t b/t/geometry.t index bb72b22e17..874dab9877 100644 --- a/t/geometry.t +++ b/t/geometry.t @@ -2,7 +2,7 @@ use Test::More; use strict; use warnings; -plan tests => 30; +plan tests => 27; BEGIN { use FindBin; @@ -39,44 +39,6 @@ isnt Slic3r::Geometry::line_intersection($line1, $line2, 1), undef, 'line_inters #========================================================== -{ - my $polygon = Slic3r::Polygon->new( - [45919000, 515273900], [14726100, 461246400], [14726100, 348753500], [33988700, 315389800], - [43749700, 343843000], [45422300, 352251500], [52362100, 362637800], [62748400, 369577600], - [75000000, 372014700], [87251500, 369577600], [97637800, 362637800], [104577600, 352251500], - [107014700, 340000000], [104577600, 327748400], [97637800, 317362100], [87251500, 310422300], - [82789200, 309534700], [69846100, 294726100], [254081000, 294726100], [285273900, 348753500], - [285273900, 461246400], [254081000, 515273900], - ); - - # this points belongs to $polyline - # note: it's actually a vertex, while we should better check an intermediate point - my $point = Slic3r::Point->new(104577600, 327748400); - - local $Slic3r::Geometry::epsilon = 1E-5; - is_deeply Slic3r::Geometry::polygon_segment_having_point($polygon, $point)->pp, - [ [107014700, 340000000], [104577600, 327748400] ], - 'polygon_segment_having_point'; -} - -#========================================================== - -{ - my $point = Slic3r::Point->new(736310778.185108, 5017423926.8924); - my $line = Slic3r::Line->new([627484000, 3695776000], [750000000, 3720147000]); - is Slic3r::Geometry::point_in_segment($point, $line), 0, 'point_in_segment'; -} - -#========================================================== - -{ - my $point = Slic3r::Point->new(736310778.185108, 5017423926.8924); - my $line = Slic3r::Line->new([627484000, 3695776000], [750000000, 3720147000]); - is Slic3r::Geometry::point_in_segment($point, $line), 0, 'point_in_segment'; -} - -#========================================================== - my $polygons = [ Slic3r::Polygon->new( # contour, ccw [45919000, 515273900], [14726100, 461246400], [14726100, 348753500], [33988700, 315389800], diff --git a/t/polyclip.t b/t/polyclip.t deleted file mode 100644 index 0808c7be99..0000000000 --- a/t/polyclip.t +++ /dev/null @@ -1,121 +0,0 @@ -use Test::More; -use strict; -use warnings; - -plan tests => 18; - -BEGIN { - use FindBin; - use lib "$FindBin::Bin/../lib"; - use local::lib "$FindBin::Bin/../local-lib"; -} - -use Slic3r; -use Slic3r::Geometry::Clipper qw(intersection_pl); - -#========================================================== - -is Slic3r::Geometry::point_in_segment(Slic3r::Point->new(10, 10), Slic3r::Line->new([5, 10], [20, 10])), 1, 'point in horizontal segment'; -is Slic3r::Geometry::point_in_segment(Slic3r::Point->new(30, 10), Slic3r::Line->new([5, 10], [20, 10])), 0, 'point not in horizontal segment'; -is Slic3r::Geometry::point_in_segment(Slic3r::Point->new(10, 10), Slic3r::Line->new([10, 5], [10, 20])), 1, 'point in vertical segment'; -is Slic3r::Geometry::point_in_segment(Slic3r::Point->new(10, 30), Slic3r::Line->new([10, 5], [10, 20])), 0, 'point not in vertical segment'; -is Slic3r::Geometry::point_in_segment(Slic3r::Point->new(15, 15), Slic3r::Line->new([10, 10], [20, 20])), 1, 'point in diagonal segment'; -is Slic3r::Geometry::point_in_segment(Slic3r::Point->new(20, 15), Slic3r::Line->new([10, 10], [20, 20])), 0, 'point not in diagonal segment'; - -#========================================================== - -my $square = Slic3r::Polygon->new( # ccw - [100, 100], - [200, 100], - [200, 200], - [100, 200], -); - -#========================================================== - -{ - my $hole_in_square = [ # cw - [140, 140], - [140, 160], - [160, 160], - [160, 140], - ]; - my $expolygon = Slic3r::ExPolygon->new($square, $hole_in_square); - #is $expolygon->contains_point(Slic3r::Point->new(100, 100)), 1, 'corner point is recognized'; - #is $expolygon->contains_point(Slic3r::Point->new(100, 180)), 1, 'point on contour is recognized'; - #is $expolygon->contains_point(Slic3r::Point->new(140, 150)), 1, 'point on hole contour is recognized'; - #is $expolygon->contains_point(Slic3r::Point->new(140, 140)), 1, 'point on hole corner is recognized'; - { - my $intersection = intersection_pl([Slic3r::Polyline->new([150,180], [150,150])], \@$expolygon); - is $intersection->[0]->length, Slic3r::Line->new([150, 180], [150, 160])->length, - 'line is clipped to square with hole'; - } - { - my $intersection = intersection_pl([Slic3r::Polyline->new([150,150], [150,120])], \@$expolygon); - is $intersection->[0]->length, Slic3r::Line->new([150, 140], [150, 120])->length, - 'line is clipped to square with hole'; - } - { - my $intersection = intersection_pl([Slic3r::Polyline->new([120,180], [180,180])], \@$expolygon); - is $intersection->[0]->length, Slic3r::Line->new([120,180], [180,180])->length, - 'line is clipped to square with hole'; - } - { - my $intersection = intersection_pl([Slic3r::Polyline->new([50, 150], [300, 150])], \@$expolygon); - is $intersection->[0]->length, Slic3r::Line->new([100, 150], [140, 150])->length, - 'line is clipped to square with hole'; - is $intersection->[1]->length, Slic3r::Line->new([160, 150], [200, 150])->length, - 'line is clipped to square with hole'; - } - { - my $intersection = intersection_pl([Slic3r::Polyline->new([300, 150], [50, 150])], \@$expolygon); - is $intersection->[0]->length, Slic3r::Line->new([200, 150], [160, 150])->length, - 'reverse line is clipped to square with hole'; - is $intersection->[1]->length, Slic3r::Line->new([140, 150], [100, 150])->length, - 'reverse line is clipped to square with hole'; - } - { - my $intersection = intersection_pl([Slic3r::Polyline->new([100,180], [200,180])], \@$expolygon); - is $intersection->[0]->length, Slic3r::Line->new([100,180], [200,180])->length, - 'tangent line is clipped to square with hole'; - } -} - -#========================================================== - -{ - my $large_circle = Slic3r::Polygon->new_scale( # ccw - [151.8639,288.1192], [133.2778,284.6011], [115.0091,279.6997], [98.2859,270.8606], [82.2734,260.7933], - [68.8974,247.4181], [56.5622,233.0777], [47.7228,216.3558], [40.1617,199.0172], [36.6431,180.4328], - [34.932,165.2312], [37.5567,165.1101], [41.0547,142.9903], [36.9056,141.4295], [40.199,124.1277], - [47.7776,106.7972], [56.6335,90.084], [68.9831,75.7557], [82.3712,62.3948], [98.395,52.3429], - [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], - ); - ok $large_circle->is_counter_clockwise, "contour is counter-clockwise"; - - my $small_circle = Slic3r::Polygon->new_scale( # 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], - ); - ok $small_circle->is_clockwise, "hole is clockwise"; - - my $expolygon = Slic3r::ExPolygon->new($large_circle, $small_circle); - my $line = Slic3r::Polyline->new_scale([152.742,288.086671142818], [152.742,34.166466971035]); - - my $intersection = intersection_pl([$line], \@$expolygon); - is $intersection->[0]->length, Slic3r::Line->new([152742000, 288086661], [152742000, 215178843])->length, - 'line is clipped to square with hole'; - is $intersection->[1]->length, Slic3r::Line->new([152742000, 108087507], [152742000, 35166477])->length, - 'line is clipped to square with hole'; -} - -#========================================================== diff --git a/tests/libslic3r/test_clipper_utils.cpp b/tests/libslic3r/test_clipper_utils.cpp index 1b2b45eca7..b357d8ca83 100644 --- a/tests/libslic3r/test_clipper_utils.cpp +++ b/tests/libslic3r/test_clipper_utils.cpp @@ -188,6 +188,46 @@ SCENARIO("Various Clipper operations - t/clipper.t", "[ClipperUtils]") { REQUIRE(intersection.front().area() == Approx(match.area())); } } + + ExPolygons expolygons { ExPolygon { square, hole_in_square } }; + WHEN("Clipping line 1") { + Polylines intersection = intersection_pl({ Polyline { { 15, 18 }, { 15, 15 } } }, expolygons); + THEN("line is clipped to square with hole") { + REQUIRE((Vec2f(15, 18) - Vec2f(15, 16)).norm() == Approx(intersection.front().length())); + } + } + WHEN("Clipping line 2") { + Polylines intersection = intersection_pl({ Polyline { { 15, 15 }, { 15, 12 } } }, expolygons); + THEN("line is clipped to square with hole") { + REQUIRE((Vec2f(15, 14) - Vec2f(15, 12)).norm() == Approx(intersection.front().length())); + } + } + WHEN("Clipping line 3") { + Polylines intersection = intersection_pl({ Polyline { { 12, 18 }, { 18, 18 } } }, expolygons); + THEN("line is clipped to square with hole") { + REQUIRE((Vec2f(18, 18) - Vec2f(12, 18)).norm() == Approx(intersection.front().length())); + } + } + WHEN("Clipping line 4") { + Polylines intersection = intersection_pl({ Polyline { { 5, 15 }, { 30, 15 } } }, expolygons); + THEN("line is clipped to square with hole") { + REQUIRE((Vec2f(14, 15) - Vec2f(10, 15)).norm() == Approx(intersection.front().length())); + REQUIRE((Vec2f(20, 15) - Vec2f(16, 15)).norm() == Approx(intersection[1].length())); + } + } + WHEN("Clipping line 5") { + Polylines intersection = intersection_pl({ Polyline { { 30, 15 }, { 5, 15 } } }, expolygons); + THEN("reverse line is clipped to square with hole") { + REQUIRE((Vec2f(20, 15) - Vec2f(16, 15)).norm() == Approx(intersection.front().length())); + REQUIRE((Vec2f(14, 15) - Vec2f(10, 15)).norm() == Approx(intersection[1].length())); + } + } + WHEN("Clipping line 6") { + Polylines intersection = intersection_pl({ Polyline { { 10, 18 }, { 20, 18 } } }, expolygons); + THEN("tangent line is clipped to square with hole") { + REQUIRE((Vec2f(20, 18) - Vec2f(10, 18)).norm() == Approx(intersection.front().length())); + } + } } GIVEN("square with hole 2") { // CCW oriented contour @@ -223,6 +263,44 @@ SCENARIO("Various Clipper operations - t/clipper.t", "[ClipperUtils]") { } } } + GIVEN("circle") { + Slic3r::ExPolygon circle_with_hole { Polygon::new_scale({ + { 151.8639,288.1192 }, {133.2778,284.6011}, { 115.0091,279.6997 }, { 98.2859,270.8606 }, { 82.2734,260.7933 }, + { 68.8974,247.4181 }, { 56.5622,233.0777 }, { 47.7228,216.3558 }, { 40.1617,199.0172 }, { 36.6431,180.4328 }, + { 34.932,165.2312 }, { 37.5567,165.1101 }, { 41.0547,142.9903 }, { 36.9056,141.4295 }, { 40.199,124.1277 }, + { 47.7776,106.7972 }, { 56.6335,90.084 }, { 68.9831,75.7557 }, { 82.3712,62.3948 }, { 98.395,52.3429 }, + { 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 } + }) }; + circle_with_hole.holes = { Polygon::new_scale({ + { 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 } + }) }; + THEN("contour is counter-clockwise") { + REQUIRE(circle_with_hole.contour.is_counter_clockwise()); + } + THEN("hole is counter-clockwise") { + REQUIRE(circle_with_hole.holes.size() == 1); + REQUIRE(circle_with_hole.holes.front().is_clockwise()); + } + + WHEN("clipping a line") { + auto line = Polyline::new_scale({ { 152.742,288.086671142818 }, { 152.742,34.166466971035 } }); + Polylines intersection = intersection_pl({ line }, { circle_with_hole }); + THEN("clipped to two pieces") { + REQUIRE(intersection.front().length() == Approx((Vec2d(152742000, 215178843) - Vec2d(152742000, 288086661)).norm())); + REQUIRE(intersection[1].length() == Approx((Vec2d(152742000, 35166477) - Vec2d(152742000, 108087507)).norm())); + } + } + } } template diff --git a/xs/xsp/Clipper.xsp b/xs/xsp/Clipper.xsp index eae3afeffb..18f8dec072 100644 --- a/xs/xsp/Clipper.xsp +++ b/xs/xsp/Clipper.xsp @@ -30,17 +30,6 @@ offset(polygons, delta, joinType = Slic3r::ClipperLib::jtMiter, miterLimit = 3) OUTPUT: RETVAL -ExPolygons -offset_ex(polygons, delta, joinType = Slic3r::ClipperLib::jtMiter, miterLimit = 3) - Polygons polygons - const float delta - Slic3r::ClipperLib::JoinType joinType - double miterLimit - CODE: - RETVAL = offset_ex(polygons, delta, joinType, miterLimit); - OUTPUT: - RETVAL - ExPolygons offset2_ex(polygons, delta1, delta2, joinType = Slic3r::ClipperLib::jtMiter, miterLimit = 3) Polygons polygons @@ -102,15 +91,6 @@ intersection_ex(subject, clip, safety_offset = false) OUTPUT: RETVAL -Polylines -intersection_pl(subject, clip) - Polylines subject - Polygons clip - CODE: - RETVAL = intersection_pl(subject, clip); - OUTPUT: - RETVAL - Polygons union(subject, safety_offset = false) Polygons subject diff --git a/xs/xsp/Surface.xsp b/xs/xsp/Surface.xsp index 49d988333c..8804b851bb 100644 --- a/xs/xsp/Surface.xsp +++ b/xs/xsp/Surface.xsp @@ -82,16 +82,6 @@ Surface::polygons() OUTPUT: RETVAL -Surfaces -Surface::offset(delta, joinType = ClipperLib::jtMiter, miterLimit = 3) - const float delta - Slic3r::ClipperLib::JoinType joinType - double miterLimit - CODE: - surfaces_append(RETVAL, offset_ex(THIS->expolygon, delta, joinType, miterLimit), *THIS); - OUTPUT: - RETVAL - %} };