diff --git a/src/libslic3r/Layer.cpp b/src/libslic3r/Layer.cpp index 37a24b54c..44fc18f91 100644 --- a/src/libslic3r/Layer.cpp +++ b/src/libslic3r/Layer.cpp @@ -568,19 +568,33 @@ void Layer::sort_perimeters_into_islands( const std::pair &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(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::max() : - (lslices[lslice_idx].point_projection(point) - point).cast().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::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( + 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::max() : + (lslices[lslice_idx].point_projection(point) - point).cast().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::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); + } } }