diff --git a/src/libslic3r/Arachne/WallToolPaths.cpp b/src/libslic3r/Arachne/WallToolPaths.cpp index 3552f6680..8399ae06e 100644 --- a/src/libslic3r/Arachne/WallToolPaths.cpp +++ b/src/libslic3r/Arachne/WallToolPaths.cpp @@ -329,60 +329,46 @@ void removeSmallAreas(Polygons &thiss, const double min_area_size, const bool re }; auto new_end = thiss.end(); - if(remove_holes) - { - for(auto it = thiss.begin(); it < new_end; it++) - { - // All polygons smaller than target are removed by replacing them with a polygon from the back of the vector - if(fabs(ClipperLib::Area(to_path(*it))) < min_area_size) - { - new_end--; + if (remove_holes) { + for (auto it = thiss.begin(); it < new_end;) { + // All polygons smaller than target are removed by replacing them with a polygon from the back of the vector. + if (fabs(ClipperLib::Area(to_path(*it))) < min_area_size) { + --new_end; *it = std::move(*new_end); - it--; // wind back the iterator such that the polygon just swaped in is checked next + continue; // Don't increment the iterator such that the polygon just swapped in is checked next. } + ++it; } - } - else - { + } else { // For each polygon, computes the signed area, move small outlines at the end of the vector and keep pointer on small holes std::vector small_holes; - for(auto it = thiss.begin(); it < new_end; it++) { - double area = ClipperLib::Area(to_path(*it)); - if (fabs(area) < min_area_size) - { - if(area >= 0) - { - new_end--; - if(it < new_end) { + for (auto it = thiss.begin(); it < new_end;) { + if (double area = ClipperLib::Area(to_path(*it)); fabs(area) < min_area_size) { + if (area >= 0) { + --new_end; + if (it < new_end) { std::swap(*new_end, *it); - it--; - } - else - { // Don't self-swap the last Path + continue; + } else { // Don't self-swap the last Path break; } - } - else - { + } else { small_holes.push_back(*it); } } + ++it; } // Removes small holes that have their first point inside one of the removed outlines // Iterating in reverse ensures that unprocessed small holes won't be moved const auto removed_outlines_start = new_end; - for(auto hole_it = small_holes.rbegin(); hole_it < small_holes.rend(); hole_it++) - { - for(auto outline_it = removed_outlines_start; outline_it < thiss.end() ; outline_it++) - { - if(Polygon(*outline_it).contains(*hole_it->begin())) { + for (auto hole_it = small_holes.rbegin(); hole_it < small_holes.rend(); hole_it++) + for (auto outline_it = removed_outlines_start; outline_it < thiss.end(); outline_it++) + if (Polygon(*outline_it).contains(*hole_it->begin())) { new_end--; *hole_it = std::move(*new_end); break; } - } - } } thiss.resize(new_end-thiss.begin()); } diff --git a/tests/libslic3r/test_arachne.cpp b/tests/libslic3r/test_arachne.cpp index c309fe6c8..b8af0fdcc 100644 --- a/tests/libslic3r/test_arachne.cpp +++ b/tests/libslic3r/test_arachne.cpp @@ -388,4 +388,39 @@ TEST_CASE("Arachne - #8633 - Shorter open perimeter", "[ArachneShorterOpenPerime export_perimeters_to_svg(debug_out_path("arachne-shorter-open-perimeter-8633-%d.svg", poly_idx), input_polygons, perimeters, union_ex(wallToolPaths.getInnerContour())); #endif } +} + +// This test case was distilled from GitHub issue #8597. +// There was just an issue with decrementing std::vector::begin() in a specific case. +TEST_CASE("Arachne - #8597 - removeSmallAreas", "[ArachneRemoveSmallAreas8597]") { + const Polygon poly_0 = { + Point(-38768167, -3636556), + Point(-38763631, -3617883), + Point(-38763925, -3617820), + Point(-38990169, -3919539), + Point(-38928506, -3919539), + }; + + const Polygon poly_1 = { + Point(-39521732, -4480560), + Point(-39383333, -4398498), + Point(-39119825, -3925307), + Point(-39165608, -3926212), + Point(-39302205, -3959445), + Point(-39578719, -4537002), + }; + + Polygons polygons = {poly_0, poly_1}; + coord_t spacing = 407079; + coord_t inset_count = 2; + + Arachne::WallToolPaths wallToolPaths(polygons, spacing, spacing, inset_count, 0, 0.2, PrintObjectConfig::defaults(), PrintConfig::defaults()); + wallToolPaths.generate(); + std::vector perimeters = wallToolPaths.getToolPaths(); + +#ifdef ARACHNE_DEBUG_OUT + export_perimeters_to_svg(debug_out_path("arachne-remove-small-areas-8597.svg"), polygons, perimeters, union_ex(wallToolPaths.getInnerContour())); +#endif + + REQUIRE(perimeters.size() == 1); } \ No newline at end of file