From c9727b5a57d0e78c386130c1eee5bb330d3b7cee Mon Sep 17 00:00:00 2001 From: Vojtech Bubnik Date: Wed, 8 Dec 2021 09:45:48 +0100 Subject: [PATCH] Fix of Random placment of top fill throughout model #7442 For this particular model, ClipperLib numerical instability causes one of the internal surfaces to turn into bridging surfaces on reslicing. The issue was fixed by reverting to untyped slices if possible. --- src/libslic3r/Layer.cpp | 21 ++++++++++++++++++++- src/libslic3r/Layer.hpp | 2 ++ src/libslic3r/LayerRegion.cpp | 3 +-- src/libslic3r/PrintObject.cpp | 11 +++++++++++ 4 files changed, 34 insertions(+), 3 deletions(-) diff --git a/src/libslic3r/Layer.cpp b/src/libslic3r/Layer.cpp index 5c661ed68..f99cc674d 100644 --- a/src/libslic3r/Layer.cpp +++ b/src/libslic3r/Layer.cpp @@ -92,6 +92,25 @@ void Layer::restore_untyped_slices() } } +// Similar to Layer::restore_untyped_slices() +// To improve robustness of detect_surfaces_type() when reslicing (working with typed slices), see GH issue #7442. +// Only resetting layerm->slices if Slice::extra_perimeters is always zero or it will not be used anymore +// after the perimeter generator. +void Layer::restore_untyped_slices_no_extra_perimeters() +{ + if (layer_needs_raw_backup(this)) { + for (LayerRegion *layerm : m_regions) + if (layerm->region().config().extra_perimeters.value <= 0) + layerm->slices.set(layerm->raw_slices, stInternal); + } else { + assert(m_regions.size() == 1); + LayerRegion *layerm = m_regions.front(); + // This optimization is correct, as extra_perimeters are only reused by prepare_infill() with multi-regions. + //if (layerm->region().config().extra_perimeters.value <= 0) + layerm->slices.set(this->lslices, stInternal); + } +} + ExPolygons Layer::merged(float offset_scaled) const { assert(offset_scaled >= 0.f); @@ -179,7 +198,7 @@ void Layer::make_perimeters() // group slices (surfaces) according to number of extra perimeters std::map slices; // extra_perimeters => [ surface, surface... ] for (LayerRegion *layerm : layerms) { - for (Surface &surface : layerm->slices.surfaces) + for (const Surface &surface : layerm->slices.surfaces) slices[surface.extra_perimeters].emplace_back(surface); if (layerm->region().config().fill_density > layerm_config->region().config().fill_density) layerm_config = layerm; diff --git a/src/libslic3r/Layer.hpp b/src/libslic3r/Layer.hpp index 516b6da9b..0071c7f6e 100644 --- a/src/libslic3r/Layer.hpp +++ b/src/libslic3r/Layer.hpp @@ -137,6 +137,8 @@ public: //FIXME Review whether not to simplify the code by keeping the raw_slices all the time. void backup_untyped_slices(); void restore_untyped_slices(); + // To improve robustness of detect_surfaces_type() when reslicing (working with typed slices), see GH issue #7442. + void restore_untyped_slices_no_extra_perimeters(); // Slices merged into islands, to be used by the elephant foot compensation to trim the individual surfaces with the shrunk merged slices. ExPolygons merged(float offset) const; template bool any_internal_region_slice_contains(const T &item) const { diff --git a/src/libslic3r/LayerRegion.cpp b/src/libslic3r/LayerRegion.cpp index 4dbffe7b0..fd29d6d54 100644 --- a/src/libslic3r/LayerRegion.cpp +++ b/src/libslic3r/LayerRegion.cpp @@ -51,8 +51,7 @@ void LayerRegion::slices_to_fill_surfaces_clipped() // so we're safe. This guarantees idempotence of prepare_infill() also in case // that combine_infill() turns some fill_surface into VOID surfaces. // Collect polygons per surface type. - std::vector by_surface; - by_surface.assign(size_t(stCount), SurfacesPtr()); + std::array by_surface; for (Surface &surface : this->slices.surfaces) by_surface[size_t(surface.surface_type)].emplace_back(&surface); // Trim surfaces by the fill_boundaries. diff --git a/src/libslic3r/PrintObject.cpp b/src/libslic3r/PrintObject.cpp index 97d13af75..05b8c9eb6 100644 --- a/src/libslic3r/PrintObject.cpp +++ b/src/libslic3r/PrintObject.cpp @@ -227,6 +227,17 @@ void PrintObject::prepare_infill() m_print->set_status(30, L("Preparing infill")); + if (m_typed_slices) { + // To improve robustness of detect_surfaces_type() when reslicing (working with typed slices), see GH issue #7442. + // The preceding step (perimeter generator) only modifies extra_perimeters and the extra perimeters are only used by discover_vertical_shells() + // with more than a single region. If this step does not use Surface::extra_perimeters or Surface::extra_perimeters is always zero, it is safe + // to reset to the untyped slices before re-runnning detect_surfaces_type(). + for (Layer* layer : m_layers) { + layer->restore_untyped_slices_no_extra_perimeters(); + m_print->throw_if_canceled(); + } + } + // This will assign a type (top/bottom/internal) to $layerm->slices. // Then the classifcation of $layerm->slices is transfered onto // the $layerm->fill_surfaces by clipping $layerm->fill_surfaces