Browse Source

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

Vojtech Bubnik 4 years ago
parent
commit
a2959ec944
5 changed files with 37 additions and 19 deletions
  1. 21 10
      src/libslic3r/Layer.cpp
  2. 8 2
      src/libslic3r/Layer.hpp
  3. 1 1
      src/libslic3r/Print.hpp
  4. 5 5
      src/libslic3r/PrintObject.cpp
  5. 2 1
      xs/xsp/Layer.xsp

+ 21 - 10
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);
+    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)
+            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)
-            // 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->slices.set(layerm->raw_slices, stInternal);
+    } else {
+        assert(m_regions.size() == 1);
+        m_regions.front()->slices.set(this->lslices, stInternal);
     }
 }
 

+ 8 - 2
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 <class T> bool any_internal_region_slice_contains(const T &item) const {

+ 1 - 1
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<unsigned int>   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.

+ 5 - 5
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<size_t>(0, m_layers.size()),
         [this](const tbb::blocked_range<size_t>& 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;

+ 2 - 1
xs/xsp/Layer.xsp

@@ -70,7 +70,8 @@
         %code%{ RETVAL = dynamic_cast<SupportLayer*>(THIS); %};
     
     void make_slices();
-    void merge_slices();
+    void backup_untyped_slices();
+    void restore_untyped_slices();
     void make_perimeters();
     void make_fills();