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();
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<Polygon> 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--;
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())) {
new_end--;
*hole_it = std::move(*new_end);
break;
}
}
}
}
thiss.resize(new_end-thiss.begin());
}

View File

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