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