Fix of #8597 - Assert on Windows about decrementing of std::vector::begin() in a specific case.

This commit is contained in:
Lukáš Hejl 2022-08-11 16:21:57 +02:00
parent e838acdcd1
commit f60b88ba3e
2 changed files with 55 additions and 34 deletions

View File

@ -329,61 +329,47 @@ void removeSmallAreas(Polygons &thiss, const double min_area_size, const bool re
}; };
auto new_end = thiss.end(); auto new_end = thiss.end();
if(remove_holes) if (remove_holes) {
{ for (auto it = thiss.begin(); it < new_end;) {
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) {
// All polygons smaller than target are removed by replacing them with a polygon from the back of the vector --new_end;
if(fabs(ClipperLib::Area(to_path(*it))) < min_area_size)
{
new_end--;
*it = std::move(*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 // For each polygon, computes the signed area, move small outlines at the end of the vector and keep pointer on small holes
std::vector<Polygon> small_holes; std::vector<Polygon> small_holes;
for(auto it = thiss.begin(); it < new_end; it++) { for (auto it = thiss.begin(); it < new_end;) {
double area = ClipperLib::Area(to_path(*it)); if (double area = ClipperLib::Area(to_path(*it)); fabs(area) < min_area_size) {
if (fabs(area) < min_area_size) if (area >= 0) {
{ --new_end;
if(area >= 0) if (it < new_end) {
{
new_end--;
if(it < new_end) {
std::swap(*new_end, *it); std::swap(*new_end, *it);
it--; continue;
} } else { // Don't self-swap the last Path
else
{ // Don't self-swap the last Path
break; break;
} }
} } else {
else
{
small_holes.push_back(*it); small_holes.push_back(*it);
} }
} }
++it;
} }
// Removes small holes that have their first point inside one of the removed outlines // 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 // Iterating in reverse ensures that unprocessed small holes won't be moved
const auto removed_outlines_start = new_end; const auto removed_outlines_start = new_end;
for(auto hole_it = small_holes.rbegin(); hole_it < small_holes.rend(); hole_it++) 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++)
for(auto outline_it = removed_outlines_start; outline_it < thiss.end() ; outline_it++) if (Polygon(*outline_it).contains(*hole_it->begin())) {
{
if(Polygon(*outline_it).contains(*hole_it->begin())) {
new_end--; new_end--;
*hole_it = std::move(*new_end); *hole_it = std::move(*new_end);
break; break;
} }
} }
}
}
thiss.resize(new_end-thiss.begin()); thiss.resize(new_end-thiss.begin());
} }

View File

@ -389,3 +389,38 @@ TEST_CASE("Arachne - #8633 - Shorter open perimeter", "[ArachneShorterOpenPerime
#endif #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<Arachne::VariableWidthLines> 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);
}