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:
parent
511408841a
commit
52ea2edf84
@ -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 ®ion_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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user