Fixed Layer::sort_perimeters_into_islands() for fuzzy skin:

1) An extrusion sample is taken for sorting extrusions into island
   so that a sample deep inside its island is taken with high probability.
2) With fuzzy skin active, the inexact search is done with bounding boxes
   inflated with the fuzzying distance.
This commit is contained in:
Vojtech Bubnik 2023-01-16 17:01:28 +01:00
parent 511408841a
commit 52ea2edf84

View File

@ -568,19 +568,33 @@ void Layer::sort_perimeters_into_islands(
const std::pair<ExtrusionRange, ExtrusionRange> &extrusions = perimeter_and_gapfill_ranges[islice];
Point sample;
bool sample_set = false;
if (! extrusions.first.empty()) {
sample = this_layer_region.perimeters().entities[*extrusions.first.begin()]->first_point();
sample_set = true;
} else if (! extrusions.second.empty()) {
sample = this_layer_region.thin_fills().entities[*extrusions.second.begin()]->first_point();
sample_set = true;
} else {
for (uint32_t iexpoly : fill_expolygons_ranges[islice])
if (const ExPolygon &expoly = fill_expolygons[iexpoly]; ! expoly.empty()) {
sample = expoly.contour.points.front();
// 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_set = true;
break;
}
if (! sample_set) {
// If there is no infill, take a sample of some inner perimeter.
for (uint32_t iperimeter : extrusions.first)
if (const ExtrusionEntity &ee = *this_layer_region.perimeters().entities[iperimeter]; ! ee.role().is_external()) {
sample = ee.first_point();
sample_set = true;
break;
}
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_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_set = true;
}
}
}
// There may be a valid empty island.
// assert(sample_set);
@ -729,27 +743,37 @@ void Layer::sort_perimeters_into_islands(
perimeter_slices_queue.pop_back();
break;
}
// If anything fails to be sorted in using exact fit, try to find a closest island.
auto point_inside_surface_dist2 =
[&lslices = this->lslices, &lslices_ex = this->lslices_ex, bbox_eps = scaled<coord_t>(this->object()->print()->config().gcode_resolution.value) + SCALED_EPSILON]
(const size_t lslice_idx, const Point &point) {
const BoundingBox &bbox = lslices_ex[lslice_idx].bbox;
return
point.x() < bbox.min.x() - bbox_eps || point.x() > bbox.max.x() + bbox_eps ||
point.y() < bbox.min.y() - bbox_eps || point.y() > bbox.max.y() + bbox_eps ?
std::numeric_limits<double>::max() :
(lslices[lslice_idx].point_projection(point) - point).cast<double>().squaredNorm();
};
for (auto it_source_slice = perimeter_slices_queue.begin(); it_source_slice != perimeter_slices_queue.end(); ++ it_source_slice) {
double d2min = std::numeric_limits<double>::max();
int lslice_idx_min = -1;
for (int lslice_idx = int(lslices_ex.size()) - 1; lslice_idx >= 0; -- lslice_idx)
if (double d2 = point_inside_surface_dist2(lslice_idx, it_source_slice->second); d2 < d2min) {
d2min = d2;
lslice_idx_min = lslice_idx;
}
assert(lslice_idx_min != -1);
insert_into_island(lslice_idx_min, it_source_slice->first);
if (! perimeter_slices_queue.empty()) {
// If the slice sample was not fitted into any slice using exact fit, try to find a closest island as a last resort.
// This should be a rare event especially if the sample point was taken from infill or inner perimeter,
// however we may land here for external perimeter only islands with fuzzy skin applied.
// Check whether fuzzy skin was enabled and adjust the bounding box accordingly.
const PrintConfig &print_config = this->object()->print()->config();
const PrintRegionConfig &region_config = this_layer_region.region().config();
const auto bbox_eps = scaled<coord_t>(
EPSILON + print_config.gcode_resolution.value +
(region_config.fuzzy_skin.value == FuzzySkinType::None ? 0. : region_config.fuzzy_skin_thickness.value));
auto point_inside_surface_dist2 =
[&lslices = this->lslices, &lslices_ex = this->lslices_ex, bbox_eps]
(const size_t lslice_idx, const Point &point) {
const BoundingBox &bbox = lslices_ex[lslice_idx].bbox;
return
point.x() < bbox.min.x() - bbox_eps || point.x() > bbox.max.x() + bbox_eps ||
point.y() < bbox.min.y() - bbox_eps || point.y() > bbox.max.y() + bbox_eps ?
std::numeric_limits<double>::max() :
(lslices[lslice_idx].point_projection(point) - point).cast<double>().squaredNorm();
};
for (auto it_source_slice = perimeter_slices_queue.begin(); it_source_slice != perimeter_slices_queue.end(); ++ it_source_slice) {
double d2min = std::numeric_limits<double>::max();
int lslice_idx_min = -1;
for (int lslice_idx = int(lslices_ex.size()) - 1; lslice_idx >= 0; -- lslice_idx)
if (double d2 = point_inside_surface_dist2(lslice_idx, it_source_slice->second); d2 < d2min) {
d2min = d2;
lslice_idx_min = lslice_idx;
}
assert(lslice_idx_min != -1);
insert_into_island(lslice_idx_min, it_source_slice->first);
}
}
}