Patching the new Layer::sort_perimeters_into_islands() for super

ugly models.
Fixes #9561, #9562
This commit is contained in:
Vojtech Bubnik 2023-02-07 13:58:06 +01:00
parent 991aedd37c
commit 340b685a0d
3 changed files with 21 additions and 5 deletions

View File

@ -31,6 +31,9 @@ public:
virtual void reverse() = 0;
virtual const Point& first_point() const = 0;
virtual const Point& last_point() const = 0;
// Returns an approximately middle point of a path, loop or an extrusion collection.
// Used to get a sample point of an extrusion or extrusion collection, which is possibly deep inside its island.
virtual const Point& middle_point() const = 0;
// Produce a list of 2D polygons covered by the extruded paths, offsetted by the extrusion width.
// Increase the offset by scaled_epsilon to achieve an overlap, so a union will produce no gaps.
virtual void polygons_covered_by_width(Polygons &out, const float scaled_epsilon) const = 0;
@ -81,6 +84,7 @@ public:
void reverse() override { this->polyline.reverse(); }
const Point& first_point() const override { return this->polyline.points.front(); }
const Point& last_point() const override { return this->polyline.points.back(); }
const Point& middle_point() const override { return this->polyline.points[this->polyline.size() / 2]; }
size_t size() const { return this->polyline.size(); }
bool empty() const { return this->polyline.empty(); }
bool is_closed() const { return ! this->empty() && this->polyline.points.front() == this->polyline.points.back(); }
@ -153,6 +157,7 @@ public:
void reverse() override;
const Point& first_point() const override { return this->paths.front().polyline.points.front(); }
const Point& last_point() const override { return this->paths.back().polyline.points.back(); }
const Point& middle_point() const override { auto &path = this->paths[this->paths.size() / 2]; return path.polyline.points[path.polyline.size() / 2]; }
size_t size() const { return this->paths.size(); }
bool empty() const { return this->paths.empty(); }
double length() const override;
@ -204,6 +209,7 @@ public:
void reverse() override;
const Point& first_point() const override { return this->paths.front().polyline.points.front(); }
const Point& last_point() const override { assert(this->first_point() == this->paths.back().polyline.points.back()); return this->first_point(); }
const Point& middle_point() const override { auto& path = this->paths[this->paths.size() / 2]; return path.polyline.points[path.polyline.size() / 2]; }
Polygon polygon() const;
double length() const override;
bool split_at_vertex(const Point &point, const double scaled_epsilon = scaled<double>(0.001));

View File

@ -102,6 +102,7 @@ public:
void reverse() override;
const Point& first_point() const override { return this->entities.front()->first_point(); }
const Point& last_point() const override { return this->entities.back()->last_point(); }
const Point& middle_point() const override { return this->entities[this->entities.size() / 2]->middle_point(); }
// Produce a list of 2D polygons covered by the extruded paths, offsetted by the extrusion width.
// Increase the offset by scaled_epsilon to achieve an overlap, so a union will produce no gaps.
void polygons_covered_by_width(Polygons &out, const float scaled_epsilon) const override;

View File

@ -578,7 +578,7 @@ void Layer::sort_perimeters_into_islands(
// Take a sample deep inside its island if available. Infills are usually quite far from the island boundary.
for (uint32_t iexpoly : fill_expolygons_ranges[islice])
if (const ExPolygon &expoly = fill_expolygons[iexpoly]; ! expoly.empty()) {
sample = expoly.contour.points.front();
sample = expoly.contour.points[expoly.contour.points.size() / 2];
sample_set = true;
break;
}
@ -589,12 +589,12 @@ void Layer::sort_perimeters_into_islands(
if (ee.is_collection()) {
for (const ExtrusionEntity *ee2 : dynamic_cast<const ExtrusionEntityCollection&>(ee).entities)
if (! ee2->role().is_external()) {
sample = ee2->first_point();
sample = ee2->middle_point();
sample_set = true;
goto loop_end;
}
} else if (! ee.role().is_external()) {
sample = ee.first_point();
sample = ee.middle_point();
sample_set = true;
break;
}
@ -603,12 +603,12 @@ void Layer::sort_perimeters_into_islands(
if (! sample_set) {
if (! extrusions.second.empty()) {
// If there is no inner perimeter, take a sample of some gap fill extrusion.
sample = this_layer_region.thin_fills().entities[*extrusions.second.begin()]->first_point();
sample = this_layer_region.thin_fills().entities[*extrusions.second.begin()]->middle_point();
sample_set = true;
}
if (! sample_set && ! extrusions.first.empty()) {
// As a last resort, take a sample of some external perimeter.
sample = this_layer_region.perimeters().entities[*extrusions.first.begin()]->first_point();
sample = this_layer_region.perimeters().entities[*extrusions.first.begin()]->middle_point();
sample_set = true;
}
}
@ -835,6 +835,15 @@ void Layer::sort_perimeters_into_islands(
d2min = d2;
lslice_idx_min = lslice_idx;
}
if (lslice_idx_min == -1) {
// This should not happen, but Arachne seems to produce a perimeter point far outside its source contour.
// As a last resort, find the closest source contours to the sample point.
for (int lslice_idx = int(lslices_ex.size()) - 1; lslice_idx >= 0; -- lslice_idx)
if (double d2 = (lslices[lslice_idx].point_projection(it_source_slice->second) - it_source_slice->second).cast<double>().squaredNorm(); d2 < d2min) {
d2min = d2;
lslice_idx_min = lslice_idx;
}
}
assert(lslice_idx_min != -1);
insert_into_island(lslice_idx_min, it_source_slice->first);
}