From 71af7100b0da2860e2f0560141764c569e9eb795 Mon Sep 17 00:00:00 2001 From: Benjamin Landers Date: Tue, 17 Jul 2018 11:34:02 -0700 Subject: [PATCH] Initial port of the geometry tests --- src/CMakeLists.txt | 1 + src/test/libslic3r/test_geometry.cpp | 286 +++++++++++++++++++++++++++ 2 files changed, 287 insertions(+) create mode 100644 src/test/libslic3r/test_geometry.cpp diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 4276d4701..12568f5c4 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -210,6 +210,7 @@ set(SLIC3R_TEST_SOURCES ${TESTDIR}/libslic3r/test_print.cpp ${TESTDIR}/libslic3r/test_skirt_brim.cpp ${TESTDIR}/libslic3r/test_test_data.cpp + ${TESTDIR}/libslic3r/test_geometry.cpp ) add_executable(slic3r slic3r.cpp) diff --git a/src/test/libslic3r/test_geometry.cpp b/src/test/libslic3r/test_geometry.cpp new file mode 100644 index 000000000..c8c2a2163 --- /dev/null +++ b/src/test/libslic3r/test_geometry.cpp @@ -0,0 +1,286 @@ + +#include + +#include "Point.hpp" +#include "BoundingBox.hpp" +#include "Polygon.hpp" +#include "Polyline.hpp" +#include "Line.hpp" +#include "Geometry.hpp" +#include "ClipperUtils.hpp" + +using namespace Slic3r; + +TEST_CASE("Polygon::contains works properly", ""){ + // this test was failing on Windows (GH #1950) + auto polygon = Polygon(std::vector({ + Point(207802834,-57084522), + Point(196528149,-37556190), + Point(173626821,-25420928), + Point(171285751,-21366123), + Point(118673592,-21366123), + Point(116332562,-25420928), + Point(93431208,-37556191), + Point(82156517,-57084523), + Point(129714478,-84542120), + Point(160244873,-84542120) + })); + auto point = Point(95706562, -57294774); + REQUIRE(polygon.contains(point)); +} + +SCENARIO("Intersections of line segments"){ + GIVEN("Integer coordinates"){ + auto line1 = Line(Point(5,15),Point(30,15)); + auto line2 = Line(Point(10,20), Point(10,10)); + THEN("The intersection is valid"){ + Point point; + line1.intersection(line2,&point); + REQUIRE(Point(10,15) == point); + } + } + + GIVEN("Scaled coordinates"){ + auto line1 = Line(Point(73.6310778185108/0.0000001, 371.74239268924/0.0000001), Point(73.6310778185108/0.0000001, 501.74239268924/0.0000001)); + auto line2 = Line(Point(75/0.0000001, 437.9853/0.0000001), Point(62.7484/0.0000001, 440.4223/0.0000001)); + THEN("There is still an intersection"){ + Point point; + REQUIRE(line1.intersection(line2,&point)); + } + } +} + +/* +Tests for unused methods still written in perl +{ + 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'; +} +{ + auto point = Point(736310778.185108, 5017423926.8924); + auto line = Line(Point((long int) 627484000, (long int) 3695776000), Point((long int) 750000000, (long int)3720147000)); + //is Slic3r::Geometry::point_in_segment($point, $line), 0, 'point_in_segment'; +} + +// Possible to delete +{ + //my $p1 = [10, 10]; + //my $p2 = [10, 20]; + //my $p3 = [10, 30]; + //my $p4 = [20, 20]; + //my $p5 = [0, 20]; + + THEN("Points in a line give the correct angles"){ + //is Slic3r::Geometry::angle3points($p2, $p3, $p1), PI(), 'angle3points'; + //is Slic3r::Geometry::angle3points($p2, $p1, $p3), PI(), 'angle3points'; + } + THEN("Left turns give the correct angle"){ + //is Slic3r::Geometry::angle3points($p2, $p4, $p3), PI()/2, 'angle3points'; + //is Slic3r::Geometry::angle3points($p2, $p1, $p4), PI()/2, 'angle3points'; + } + THEN("Right turns give the correct angle"){ + //is Slic3r::Geometry::angle3points($p2, $p3, $p4), PI()/2*3, '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'; +} + +SCENARIO("polygon_is_convex works"){ + GIVEN("A square of dimension 10"){ + //my $cw_square = [ [0,0], [0,10], [10,10], [10,0] ]; + THEN("It is not convex clockwise"){ + //is polygon_is_convex($cw_square), 0, 'cw square is not convex'; + } + THEN("It is convex counter-clockwise"){ + //is polygon_is_convex([ reverse @$cw_square ]), 1, 'ccw square is convex'; + } + + } + GIVEN("A concave polygon"){ + //my $convex1 = [ [0,0], [10,0], [10,10], [0,10], [0,6], [4,6], [4,4], [0,4] ]; + THEN("It is concave"){ + //is polygon_is_convex($convex1), 0, 'concave polygon'; + } + } +}*/ + + +TEST_CASE("Creating a polyline generates the obvious lines"){ + auto polyline = Polyline(); + polyline.points = std::vector({Point(0, 0), Point(10, 0), Point(20, 0)}); + REQUIRE(polyline.lines().at(0).a == Point(0,0)); + REQUIRE(polyline.lines().at(0).b == Point(10,0)); + REQUIRE(polyline.lines().at(1).a == Point(10,0)); + REQUIRE(polyline.lines().at(1).b == Point(20,0)); +} + +TEST_CASE("Splitting a Polygon generates a polyline correctly"){ + auto polygon = Polygon(std::vector({Point(0, 0), Point(10, 0), Point(5, 5)})); + auto split = polygon.split_at_index(1); + REQUIRE(split.points[0]==Point(10,0)); + REQUIRE(split.points[1]==Point(5,5)); + REQUIRE(split.points[2]==Point(0,0)); + REQUIRE(split.points[3]==Point(10,0)); +} + + +TEST_CASE("Bounding boxes are scaled appropriately"){ + auto bb = BoundingBox(std::vector({Point(0, 1), Point(10, 2), Point(20, 2)})); + bb.scale(2); + REQUIRE(bb.min == Point(0,2)); + REQUIRE(bb.max == Point(40,4)); +} + + +TEST_CASE("Offseting a line generates a polygon correctly"){ + auto line = Line(Point(10,10), Point(20,10)); + Polyline tmp(line); + Polygon area = offset(tmp,5).at(0); + REQUIRE(area.area() == Polygon(std::vector({Point(10,5),Point(20,5),Point(20,15),Point(10,15)})).area()); +} + + +TEST_CASE("Chained path working correctly"){ + // if chained_path() works correctly, these points should be joined with no diagonal paths + // (thus 26 units long) + std::vector points = {Point(26,26),Point(52,26),Point(0,26),Point(26,52),Point(26,0),Point(0,52),Point(52,52),Point(52,0)}; + std::vector indices; + Geometry::chained_path(points,indices); + for(Points::size_type i = 0; i < indices.size()-1;i++){ + double dist = points.at(indices.at(i)).distance_to(points.at(indices.at(i+1))); + REQUIRE(abs(dist-26) <= Geometry::epsilon); + } +} + +SCENARIO("Line distances"){ + GIVEN("A line"){ + auto line = Line(Point(0, 0), Point(20, 0)); + THEN("Points on the line segment have 0 distance"){ + REQUIRE(Point(0, 0).distance_to(line) == 0); + REQUIRE(Point(20, 0).distance_to(line) == 0); + REQUIRE(Point(10, 0).distance_to(line) == 0); + + } + THEN("Points off the line have the appropriate distance"){ + REQUIRE(Point(10, 10).distance_to(line) == 10); + REQUIRE(Point(50, 0).distance_to(line) == 30); + } + } +} + +SCENARIO("Polygon convex/concave detection"){ + GIVEN(("A Square with dimension 100")){ + auto square = Polygon /*new_scale*/(std::vector({ + Point(100,100), + Point(200,100), + Point(200,200), + Point(100,200)})); + THEN("It has 4 convex points counterclockwise"){ + REQUIRE(square.concave_points(PI*4/3).size() == 0); + REQUIRE(square.convex_points(PI*2/3).size() == 4); + } + THEN("It has 4 concave points clockwise"){ + square.make_clockwise(); + REQUIRE(square.concave_points(PI*4/3).size() == 4); + REQUIRE(square.convex_points(PI*2/3).size() == 0); + } + } + GIVEN("A Square with an extra colinearvertex"){ + auto square = Polygon /*new_scale*/(std::vector({ + Point(150,100), + Point(200,100), + Point(200,200), + Point(100,200), + Point(100,100)})); + THEN("It has 4 convex points counterclockwise"){ + REQUIRE(square.concave_points(PI*4/3).size() == 0); + REQUIRE(square.convex_points(PI*2/3).size() == 4); + } + } + GIVEN("A Square with an extra collinear vertex in different order"){ + auto square = Polygon /*new_scale*/(std::vector({ + Point(200,200), + Point(100,200), + Point(100,100), + Point(150,100), + Point(200,100)})); + THEN("It has 4 convex points counterclockwise"){ + REQUIRE(square.concave_points(PI*4/3).size() == 0); + REQUIRE(square.convex_points(PI*2/3).size() == 4); + } + } + + GIVEN("A triangle"){ + auto triangle = Polygon(std::vector({ + Point(16000170,26257364), + Point(714223,461012), + Point(31286371,461008) + })); + THEN("it has three convex vertices"){ + REQUIRE(triangle.concave_points(PI*4/3).size() == 0); + REQUIRE(triangle.convex_points(PI*2/3).size() == 3); + } + } + + GIVEN("A triangle with an extra collinear point"){ + auto triangle = Polygon(std::vector({ + Point(16000170,26257364), + Point(714223,461012), + Point(20000000,461012), + Point(31286371,461012) + })); + THEN("it has three convex vertices"){ + REQUIRE(triangle.concave_points(PI*4/3).size() == 0); + REQUIRE(triangle.convex_points(PI*2/3).size() == 3); + } + } + GIVEN("A polygon with concave vertices with angles of specifically 4/3pi"){ + // Two concave vertices of this polygon have angle = PI*4/3, so this test fails + // if epsilon is not used. + auto polygon = Polygon(std::vector({ + Point(60246458,14802768),Point(64477191,12360001), + Point(63727343,11060995),Point(64086449,10853608), + Point(66393722,14850069),Point(66034704,15057334), + Point(65284646,13758387),Point(61053864,16200839), + Point(69200258,30310849),Point(62172547,42483120), + Point(61137680,41850279),Point(67799985,30310848), + Point(51399866,1905506),Point(38092663,1905506), + Point(38092663,692699),Point(52100125,692699) + })); + THEN("the correct number of points are detected"){ + REQUIRE(polygon.concave_points(PI*4/3).size() == 6); + REQUIRE(polygon.convex_points(PI*2/3).size() == 10); + } + } +} + +TEST_CASE("Triangle Simplification does not result in less than 3 points"){ + auto triangle = Polygon(std::vector({ + Point(16000170,26257364), Point(714223,461012), Point(31286371,461008) + })); + REQUIRE(triangle.simplify(250000).at(0).points.size() == 3); +} + +