diff --git a/src/libslic3r/GCode/CoolingBuffer.hpp b/src/libslic3r/GCode/CoolingBuffer.hpp index 511089ad0..b0c35ecc5 100644 --- a/src/libslic3r/GCode/CoolingBuffer.hpp +++ b/src/libslic3r/GCode/CoolingBuffer.hpp @@ -1,7 +1,7 @@ #ifndef slic3r_CoolingBuffer_hpp_ #define slic3r_CoolingBuffer_hpp_ -#include "libslic3r.h" +#include "../libslic3r.h" #include #include diff --git a/src/libslic3r/Polygon.cpp b/src/libslic3r/Polygon.cpp index 4c2db2848..bd5ec3de5 100644 --- a/src/libslic3r/Polygon.cpp +++ b/src/libslic3r/Polygon.cpp @@ -15,7 +15,7 @@ Polyline Polygon::split_at_vertex(const Point &point) const // find index of point for (const Point &pt : this->points) if (pt == point) - return this->split_at_index(&pt - &this->points.front()); + return this->split_at_index(int(&pt - &this->points.front())); throw std::invalid_argument("Point not found"); return Polyline(); } @@ -394,4 +394,45 @@ bool remove_small(Polygons &polys, double min_area) return modified; } +void remove_collinear(Polygon &poly) +{ + if (poly.points.size() > 2) { + // copy points and append both 1 and last point in place to cover the boundaries + Points pp; + pp.reserve(poly.points.size()+2); + pp.push_back(poly.points.back()); + pp.insert(pp.begin()+1, poly.points.begin(), poly.points.end()); + pp.push_back(poly.points.front()); + // delete old points vector. Will be re-filled in the loop + poly.points.clear(); + + size_t i = 0; + size_t k = 0; + while (i < pp.size()-2) { + k = i+1; + const Point &p1 = pp[i]; + while (k < pp.size()-1) { + const Point &p2 = pp[k]; + const Point &p3 = pp[k+1]; + Line l(p1, p3); + if(l.distance_to(p2) < SCALED_EPSILON) { + k++; + } else { + if(i > 0) poly.points.push_back(p1); // implicitly removes the first point we appended above + i = k; + break; + } + } + if(k > pp.size()-2) break; // all remaining points are collinear and can be skipped + } + poly.points.push_back(pp[i]); + } +} + +void remove_collinear(Polygons &polys) +{ + for (Polygon &poly : polys) + remove_collinear(poly); +} + } diff --git a/src/libslic3r/Polygon.hpp b/src/libslic3r/Polygon.hpp index 42f938c72..19be3068b 100644 --- a/src/libslic3r/Polygon.hpp +++ b/src/libslic3r/Polygon.hpp @@ -86,6 +86,8 @@ extern bool remove_sticks(Polygons &polys); // Remove polygons with less than 3 edges. extern bool remove_degenerate(Polygons &polys); extern bool remove_small(Polygons &polys, double min_area); +extern void remove_collinear(Polygon &poly); +extern void remove_collinear(Polygons &polys); // Append a vector of polygons at the end of another vector of polygons. inline void polygons_append(Polygons &dst, const Polygons &src) { dst.insert(dst.end(), src.begin(), src.end()); } diff --git a/tests/libslic3r/CMakeLists.txt b/tests/libslic3r/CMakeLists.txt index ea83bf089..cfc7ea833 100644 --- a/tests/libslic3r/CMakeLists.txt +++ b/tests/libslic3r/CMakeLists.txt @@ -2,6 +2,7 @@ get_filename_component(_TEST_NAME ${CMAKE_CURRENT_LIST_DIR} NAME) add_executable(${_TEST_NAME}_tests ${_TEST_NAME}_tests.cpp test_geometry.cpp + test_polygon.cpp ) target_link_libraries(${_TEST_NAME}_tests test_common libslic3r) set_property(TARGET ${_TEST_NAME}_tests PROPERTY FOLDER "tests") diff --git a/tests/libslic3r/test_polygon.cpp b/tests/libslic3r/test_polygon.cpp new file mode 100644 index 000000000..8e9975843 --- /dev/null +++ b/tests/libslic3r/test_polygon.cpp @@ -0,0 +1,44 @@ +#include + +#include "libslic3r/Point.hpp" +#include "libslic3r/Polygon.hpp" + +using namespace Slic3r; + +// This test currently only covers remove_collinear_points. +// All remaining tests are to be ported from xs/t/06_polygon.t + +Slic3r::Points collinear_circle({ + Slic3r::Point::new_scale(0, 0), // 3 collinear points at beginning + Slic3r::Point::new_scale(10, 0), + Slic3r::Point::new_scale(20, 0), + Slic3r::Point::new_scale(30, 10), + Slic3r::Point::new_scale(40, 20), // 2 collinear points + Slic3r::Point::new_scale(40, 30), + Slic3r::Point::new_scale(30, 40), // 3 collinear points + Slic3r::Point::new_scale(20, 40), + Slic3r::Point::new_scale(10, 40), + Slic3r::Point::new_scale(-10, 20), + Slic3r::Point::new_scale(-20, 10), + Slic3r::Point::new_scale(-20, 0), // 3 collinear points at end + Slic3r::Point::new_scale(-10, 0), + Slic3r::Point::new_scale(-5, 0) +}); + +SCENARIO("Remove collinear points from Polygon") { + GIVEN("Polygon with collinear points"){ + Slic3r::Polygon p(collinear_circle); + WHEN("collinear points are removed") { + remove_collinear(p); + THEN("Leading collinear points are removed") { + REQUIRE(p.points.front() == Slic3r::Point::new_scale(20, 0)); + } + THEN("Trailing collinear points are removed") { + REQUIRE(p.points.back() == Slic3r::Point::new_scale(-20, 0)); + } + THEN("Number of remaining points is correct") { + REQUIRE(p.points.size() == 7); + } + } + } +}