From a2959ec944c8a1423a382169818284d500270f15 Mon Sep 17 00:00:00 2001 From: Vojtech Bubnik Date: Fri, 11 Dec 2020 12:21:07 +0100 Subject: [PATCH] Fix of re-slicing with multiple regions. This is a fix of a bug, which was in Slic3r forever, where raw slices were not cached, but recalculated from classified regions, where merging the regions did not produce the original contour reliably. Fixes [2.3.0-beta2] Odd bad slicing related to infill (?) percentage #5407 --- src/libslic3r/Layer.cpp | 33 ++++++++++++++++++++++----------- src/libslic3r/Layer.hpp | 10 ++++++++-- src/libslic3r/Print.hpp | 2 +- src/libslic3r/PrintObject.cpp | 10 +++++----- xs/xsp/Layer.xsp | 3 ++- 5 files changed, 38 insertions(+), 20 deletions(-) diff --git a/src/libslic3r/Layer.cpp b/src/libslic3r/Layer.cpp index 29b20d2e1..975274445 100644 --- a/src/libslic3r/Layer.cpp +++ b/src/libslic3r/Layer.cpp @@ -64,19 +64,30 @@ void Layer::make_slices() this->lslices.emplace_back(std::move(slices[i])); } -// Merge typed slices into untyped slices. This method is used to revert the effects of detect_surfaces_type() called for posPrepareInfill. -void Layer::merge_slices() +static inline bool layer_needs_raw_backup(const Layer *layer) { - if (m_regions.size() == 1 && (this->id() > 0 || this->object()->config().elefant_foot_compensation.value == 0)) { - // Optimization, also more robust. Don't merge classified pieces of layerm->slices, - // but use the non-split islands of a layer. For a single region print, these shall be equal. - // Don't use this optimization on 1st layer with Elephant foot compensation applied, as this->lslices are uncompensated, - // while regions are compensated. - m_regions.front()->slices.set(this->lslices, stInternal); - } else { + return ! (layer->regions().size() == 1 && (layer->id() > 0 || layer->object()->config().elefant_foot_compensation.value == 0)); +} + +void Layer::backup_untyped_slices() +{ + if (layer_needs_raw_backup(this)) { for (LayerRegion *layerm : m_regions) - // without safety offset, artifacts are generated (upstream Slic3r GH #2494) - layerm->slices.set(union_ex(to_polygons(std::move(layerm->slices.surfaces)), true), stInternal); + layerm->raw_slices = to_expolygons(layerm->slices.surfaces); + } else { + assert(m_regions.size() == 1); + m_regions.front()->raw_slices.clear(); + } +} + +void Layer::restore_untyped_slices() +{ + if (layer_needs_raw_backup(this)) { + for (LayerRegion *layerm : m_regions) + layerm->slices.set(layerm->raw_slices, stInternal); + } else { + assert(m_regions.size() == 1); + m_regions.front()->slices.set(this->lslices, stInternal); } } diff --git a/src/libslic3r/Layer.hpp b/src/libslic3r/Layer.hpp index 8285b5493..508269f1a 100644 --- a/src/libslic3r/Layer.hpp +++ b/src/libslic3r/Layer.hpp @@ -28,6 +28,10 @@ public: // collection of surfaces generated by slicing the original geometry // divided by type top/bottom/internal SurfaceCollection slices; + // Backed up slices before they are split into top/bottom/internal. + // Only backed up for multi-region layers or layers with elephant foot compensation. + //FIXME Review whether not to simplify the code by keeping the raw_slices all the time. + ExPolygons raw_slices; // collection of extrusion paths/loops filling gaps // These fills are generated by the perimeter generator. @@ -125,8 +129,10 @@ public: // Test whether whether there are any slices assigned to this layer. bool empty() const; void make_slices(); - // Merge typed slices into untyped slices. This method is used to revert the effects of detect_surfaces_type() called for posPrepareInfill. - void merge_slices(); + // Backup and restore raw sliced regions if needed. + //FIXME Review whether not to simplify the code by keeping the raw_slices all the time. + void backup_untyped_slices(); + void restore_untyped_slices(); // 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/Print.hpp b/src/libslic3r/Print.hpp index 1d9f3f722..e65d67cb5 100644 --- a/src/libslic3r/Print.hpp +++ b/src/libslic3r/Print.hpp @@ -186,7 +186,7 @@ public: // returns 0-based indices of extruders used to print the object (without brim, support and other helper extrusions) std::vector object_extruders() const; - // Called when slicing to SVG (see Print.pm sub export_svg), and used by perimeters.t + // Called by make_perimeters() void slice(); // Helpers to slice support enforcer / blocker meshes by the support generator. diff --git a/src/libslic3r/PrintObject.cpp b/src/libslic3r/PrintObject.cpp index 2babb0d73..84dfb6e0a 100644 --- a/src/libslic3r/PrintObject.cpp +++ b/src/libslic3r/PrintObject.cpp @@ -97,6 +97,7 @@ PrintBase::ApplyStatus PrintObject::set_instances(PrintInstances &&instances) return status; } +// Called by make_perimeters() // 1) Decides Z positions of the layers, // 2) Initializes layers and their regions // 3) Slices the object meshes @@ -104,8 +105,6 @@ PrintBase::ApplyStatus PrintObject::set_instances(PrintInstances &&instances) // 5) Applies size compensation (offsets the slices in XY plane) // 6) Replaces bad slices by the slices reconstructed from the upper/lower layer // Resulting expolygons of layer regions are marked as Internal. -// -// this should be idempotent void PrintObject::slice() { if (! this->set_started(posSlice)) @@ -125,7 +124,7 @@ void PrintObject::slice() // Simplify slices if required. if (m_print->config().resolution) this->simplify_slices(scale_(this->print()->config().resolution)); - // Update bounding boxes + // Update bounding boxes, back up raw slices of complex models. tbb::parallel_for( tbb::blocked_range(0, m_layers.size()), [this](const tbb::blocked_range& range) { @@ -136,6 +135,7 @@ void PrintObject::slice() layer.lslices_bboxes.reserve(layer.lslices.size()); for (const ExPolygon &expoly : layer.lslices) layer.lslices_bboxes.emplace_back(get_extents(expoly)); + layer.backup_untyped_slices(); } }); if (m_layers.empty()) @@ -157,10 +157,10 @@ void PrintObject::make_perimeters() m_print->set_status(20, L("Generating perimeters")); BOOST_LOG_TRIVIAL(info) << "Generating perimeters..." << log_memory_info(); - // merge slices if they were split into types + // Revert the typed slices into untyped slices. if (m_typed_slices) { for (Layer *layer : m_layers) { - layer->merge_slices(); + layer->restore_untyped_slices(); m_print->throw_if_canceled(); } m_typed_slices = false; diff --git a/xs/xsp/Layer.xsp b/xs/xsp/Layer.xsp index 6ca953f82..fdcc26eb6 100644 --- a/xs/xsp/Layer.xsp +++ b/xs/xsp/Layer.xsp @@ -70,7 +70,8 @@ %code%{ RETVAL = dynamic_cast(THIS); %}; void make_slices(); - void merge_slices(); + void backup_untyped_slices(); + void restore_untyped_slices(); void make_perimeters(); void make_fills();