From 57e28b53f24670e5867958ff95ea9e1ba0cd6d4e Mon Sep 17 00:00:00 2001
From: tamasmeszaros <meszaros.q@gmail.com>
Date: Tue, 26 Mar 2019 10:57:45 +0100
Subject: [PATCH] Further refactor and simplification of slice index and print
 data.

---
 src/libslic3r/SLAPrint.cpp    |  85 ++++++++++++++------------
 src/libslic3r/SLAPrint.hpp    | 108 +++++++++++++++++-----------------
 src/slic3r/GUI/GLCanvas3D.cpp |   8 +--
 3 files changed, 105 insertions(+), 96 deletions(-)

diff --git a/src/libslic3r/SLAPrint.cpp b/src/libslic3r/SLAPrint.cpp
index 03dd6045c..e4b45d9a4 100644
--- a/src/libslic3r/SLAPrint.cpp
+++ b/src/libslic3r/SLAPrint.cpp
@@ -698,7 +698,7 @@ void SLAPrint::process()
             id < po.m_model_slices.size() && mit != po.m_slice_index.end();
             id++)
         {
-            mit->set_model_slice_idx(id); ++mit;
+            mit->set_model_slice_idx(po, id); ++mit;
         }
     };
 
@@ -894,7 +894,7 @@ void SLAPrint::process()
             i < sd->support_slices.size() && i < po.m_slice_index.size();
             ++i)
         {
-            po.m_slice_index[i].set_support_slice_idx(i);
+            po.m_slice_index[i].set_support_slice_idx(po, i);
         }
     };
 
@@ -924,7 +924,7 @@ void SLAPrint::process()
         for(SLAPrintObject * o : m_objects) {
             coord_t gndlvl = o->get_slice_index().front().print_level() - ilhs;
 
-            for(auto& slicerecord : o->get_slice_index()) {
+            for(const SliceRecord& slicerecord : o->get_slice_index()) {
                 coord_t lvlid = slicerecord.print_level() - gndlvl;
 
                 // Neat trick to round the layer levels to the grid.
@@ -932,21 +932,13 @@ void SLAPrint::process()
 
                 auto it = std::lower_bound(m_printer_input.begin(),
                                            m_printer_input.end(),
-                                           LayerRefs(lvlid));
+                                           PrintLayer(lvlid));
 
                 if(it == m_printer_input.end() || it->level != lvlid)
-                    it = m_printer_input.insert(it, LayerRefs(lvlid));
+                    it = m_printer_input.insert(it, PrintLayer(lvlid));
 
-                auto& lyrs = *it;
 
-                const ExPolygons& objslices = o->get_slices_from_record(slicerecord, soModel);
-                const ExPolygons& supslices = o->get_slices_from_record(slicerecord, soSupport);
-
-                if(!objslices.empty())
-                    lyrs.refs.emplace_back(objslices, o->instances());
-
-                if(!supslices.empty())
-                    lyrs.refs.emplace_back(supslices, o->instances());
+                it->slices.emplace_back(std::cref(slicerecord));
             }
         }
 
@@ -998,25 +990,40 @@ void SLAPrint::process()
         {
             if(canceled()) return;
 
-            LayerRefs& lrange = m_printer_input[level_id];
+            PrintLayer& lrange = m_printer_input[level_id];
 
             // Switch to the appropriate layer in the printer
             printer.begin_layer(level_id);
 
-            for(auto& lyrref : lrange.refs) { // for all layers in the current level
+            for(const SliceRecord& slrecord : lrange.slices)
+            { // for all layers in the current level
+
                 if(canceled()) break;
-                const Layer& sl = lyrref.lref;   // get the layer reference
-                const LayerCopies& copies = lyrref.copies;
+
+                // get the layer reference
+                const ExPolygons& objslice = slrecord.get_slice(soModel);
+                const ExPolygons& supslice = slrecord.get_slice(soModel);
+                const SLAPrintObject *po = slrecord.print_obj();
+                assert(po != nullptr);
 
                 // Draw all the polygons in the slice to the actual layer.
-                for(auto& cp : copies) {
-                    for(ExPolygon slice : sl) {
+                for(const SLAPrintObject::Instance& tr : po->instances()) {
+                    for(ExPolygon poly : objslice) {
                         // The order is important here:
                         // apply rotation before translation...
-                        slice.rotate(double(cp.rotation));
-                        slice.translate(cp.shift(X), cp.shift(Y));
-                        if(flpXY) swapXY(slice);
-                        printer.draw_polygon(slice, level_id);
+                        poly.rotate(double(tr.rotation));
+                        poly.translate(tr.shift(X), tr.shift(Y));
+                        if(flpXY) swapXY(poly);
+                        printer.draw_polygon(poly, level_id);
+                    }
+
+                    for(ExPolygon poly : supslice) {
+                        // The order is important here:
+                        // apply rotation before translation...
+                        poly.rotate(double(tr.rotation));
+                        poly.translate(tr.shift(X), tr.shift(Y));
+                        if(flpXY) swapXY(poly);
+                        printer.draw_polygon(poly, level_id);
                     }
                 }
             }
@@ -1026,11 +1033,13 @@ void SLAPrint::process()
 
             // Status indication guarded with the spinlock
             auto st = ist + unsigned(sd*level_id*slot/m_printer_input.size());
-            { std::lock_guard<SpinMutex> lck(slck);
-            if( st > pst) {
-                report_status(*this, int(st), PRINT_STEP_LABELS[slapsRasterize]);
-                pst = st;
-            }
+            {
+                std::lock_guard<SpinMutex> lck(slck);
+                if( st > pst) {
+                    report_status(*this, int(st),
+                                  PRINT_STEP_LABELS[slapsRasterize]);
+                    pst = st;
+                }
             }
         };
 
@@ -1290,11 +1299,11 @@ void SLAPrint::fill_statistics()
                 record = &slr;
             }
 
-            const ExPolygons &modelslices = po->get_slices_from_record(*record, soModel);
+            const ExPolygons &modelslices = record->get_slice(soModel);
             if (!modelslices.empty())
                 append(model_polygons, get_all_polygons(modelslices, po->instances()));
 
-            const ExPolygons &supportslices = po->get_slices_from_record(*record, soSupport);
+            const ExPolygons &supportslices = record->get_slice(soSupport);
             if (!supportslices.empty())
                 append(supports_polygons, get_all_polygons(supportslices, po->instances()));
         }
@@ -1515,15 +1524,15 @@ const std::vector<ExPolygons> &SLAPrintObject::get_support_slices() const
     return m_supportdata->support_slices;
 }
 
-const ExPolygons &SLAPrintObject::get_slices_from_record(
-        const SliceRecord &rec,
-        SliceOrigin o) const
+const ExPolygons &SliceRecord::get_slice(SliceOrigin o) const
 {
-    size_t idx = o == soModel ? rec.get_model_slice_idx() :
-                                rec.get_support_slice_idx();
+    size_t idx = o == soModel ? m_model_slices_idx :
+                                m_support_slices_idx;
 
-    const std::vector<ExPolygons>& v = o == soModel? get_model_slices() :
-                                                     get_support_slices();
+    if(m_po == nullptr) return EMPTY_SLICE;
+
+    const std::vector<ExPolygons>& v = o == soModel? m_po->get_model_slices() :
+                                                     m_po->get_support_slices();
 
     if(idx >= v.size()) return EMPTY_SLICE;
 
diff --git a/src/libslic3r/SLAPrint.hpp b/src/libslic3r/SLAPrint.hpp
index 42317aa2e..6947cc80d 100644
--- a/src/libslic3r/SLAPrint.hpp
+++ b/src/libslic3r/SLAPrint.hpp
@@ -38,8 +38,9 @@ using _SLAPrintObjectBase =
 
 enum SliceOrigin { soSupport, soModel };
 
+class SLAPrintObject;
+
 // The public Slice record structure. It corresponds to one printable layer.
-// To get the sliced polygons, use SLAPrintObject::get_slices_from_record
 class SliceRecord {
 public:
     // this will be the max limit of size_t
@@ -54,6 +55,7 @@ private:
 
     size_t m_model_slices_idx = NONE;
     size_t m_support_slices_idx = NONE;
+    const SLAPrintObject *m_po = nullptr;
 
 public:
 
@@ -61,38 +63,28 @@ public:
         m_print_z(key), m_slice_z(slicez), m_height(height) {}
 
     // The key will be the integer height level of the top of the layer.
-    inline coord_t print_level() const { return m_print_z; }
+    coord_t print_level() const { return m_print_z; }
 
     // Returns the exact floating point Z coordinate of the slice
-    inline float slice_level() const { return m_slice_z; }
+    float slice_level() const { return m_slice_z; }
 
     // Returns the current layer height
-    inline float layer_height() const { return m_height; }
+    float layer_height() const { return m_height; }
 
     bool is_valid() const { return std::isnan(m_slice_z); }
 
-    template <class T> inline T level() const {
-        static_assert(std::is_integral<T>::value ||
-                      std::is_floating_point<T>::value,
-                      "Slice record level is only valid for numeric types!");
-        if (std::is_integral<T>::value) return T(print_level());
-        else return T(slice_level());
-    }
-
-    template <class T> inline static SliceRecord create(T val) {
-        static_assert(std::is_integral<T>::value ||
-                      std::is_floating_point<T>::value,
-                      "Slice record level is only valid for numeric types!");
-        if (std::is_integral<T>::value) return { coord_t(val), 0.f, 0.f };
-        else return { 0, float(val), 0.f };
-    }
+    const SLAPrintObject* print_obj() const { return m_po; }
 
     // Methods for setting the indices into the slice vectors.
-    void set_model_slice_idx(size_t id) { m_model_slices_idx = id; }
-    void set_support_slice_idx(size_t id) { m_support_slices_idx = id; }
+    void set_model_slice_idx(const SLAPrintObject &po, size_t id) {
+        m_po = &po; m_model_slices_idx = id;
+    }
 
-    inline size_t get_model_slice_idx() const { return m_model_slices_idx; }
-    inline size_t get_support_slice_idx() const { return m_support_slices_idx; }
+    void set_support_slice_idx(const SLAPrintObject& po, size_t id) {
+        m_po = &po; m_support_slices_idx = id;
+    }
+
+    const ExPolygons& get_slice(SliceOrigin o) const;
 };
 
 
@@ -153,6 +145,16 @@ public:
 
 private:
 
+    template <class T> inline static T level(const SliceRecord& sr) {
+        static_assert(std::is_arithmetic<T>::value, "Arithmetic only!");
+        return std::is_integral<T>::value ? T(sr.print_level()) : T(sr.slice_level());
+    }
+
+    template <class T> inline static SliceRecord create_slice_record(T val) {
+        static_assert(std::is_arithmetic<T>::value, "Arithmetic only!");
+        return std::is_integral<T>::value ? SliceRecord{ coord_t(val), 0.f, 0.f } : SliceRecord{ 0, float(val), 0.f };
+    }
+
     // This is a template method for searching the slice index either by
     // an integer key: print_level or a floating point key: slice_level.
     // The eps parameter gives the max deviation in + or - direction.
@@ -162,23 +164,23 @@ private:
     static auto closest_slice_record(Container& cont, T lvl, T eps) -> decltype (cont.begin())
     {
         if(cont.empty()) return cont.end();
-        if(cont.size() == 1 && std::abs(cont.front().template level<T>() - lvl) > eps)
+        if(cont.size() == 1 && std::abs(level<T>(cont.front()) - lvl) > eps)
             return cont.end();
 
-        SliceRecord query = SliceRecord::create(lvl);
+        SliceRecord query = create_slice_record(lvl);
 
         auto it = std::lower_bound(cont.begin(), cont.end(), query,
                                    [](const SliceRecord& r1,
                                       const SliceRecord& r2)
         {
-            return r1.level<T>() < r2.level<T>();
+            return level<T>(r1) < level<T>(r2);
         });
 
-        T diff = std::abs(it->template level<T>() - lvl);
+        T diff = std::abs(level<T>(*it) - lvl);
 
         if(it != cont.begin()) {
             auto it_prev = std::prev(it);
-            T diff_prev = std::abs(it_prev->template level<T>() - lvl);
+            T diff_prev = std::abs(level<T>(*it_prev) - lvl);
             if(diff_prev < diff) { diff = diff_prev; it = it_prev; }
         }
 
@@ -226,9 +228,6 @@ public:
         return *it;
     }
 
-    // Get the actual slice polygons using a valid slice record.
-    const ExPolygons& get_slices_from_record(
-            const SliceRecord& rec, SliceOrigin o) const;
 protected:
     // to be called from SLAPrint only.
     friend class SLAPrint;
@@ -327,6 +326,24 @@ private: // Prevents erroneous use by other classes.
     typedef PrintBaseWithState<SLAPrintStep, slapsCount> Inherited;
 
 public:
+
+    // An aggregation of SliceRecord-s from all the print objects for each
+    // occupied layer. Slice record levels dont have to match exactly.
+    // They are unified if the level difference is within +/- SCALED_EPSILON
+    struct PrintLayer {
+        coord_t level;
+
+        // The collection of slice records for the current level.
+        std::vector<std::reference_wrapper<const SliceRecord>> slices;
+
+        explicit PrintLayer(coord_t lvl) : level(lvl) {}
+
+        // for being sorted in their container (see m_printer_input)
+        bool operator<(const PrintLayer& other) const {
+            return level < other.level;
+        }
+    };
+
     SLAPrint(): m_stepmask(slapsCount, true) {}
 
     virtual ~SLAPrint() override { this->clear(); }
@@ -360,6 +377,10 @@ public:
 
     std::string validate() const override;
 
+    // The aggregated and leveled print records from various objects.
+    // TODO: use this structure for the preview in the future.
+    const std::vector<PrintLayer>& print_layers() const { return m_printer_input; }
+
 private:
     using SLAPrinter = FilePrinter<FilePrinterFormat::SLA_PNGZIP>;
     using SLAPrinterPtr = std::unique_ptr<SLAPrinter>;
@@ -377,29 +398,8 @@ private:
     PrintObjects                    m_objects;
     std::vector<bool>               m_stepmask;
 
-    // Definition of the print input map. It consists of the slices indexed
-    // with scaled (clipper) Z coordinates. Also contains the instance
-    // transformations in scaled and filtered version. This is enough for the
-    // rasterizer to be able to draw every layer in the right position
-    using Layer = ExPolygons;
-    using LayerCopies = std::vector<SLAPrintObject::Instance>;
-    struct LayerRef {
-        std::reference_wrapper<const Layer> lref;
-        std::reference_wrapper<const LayerCopies> copies;
-        LayerRef(const Layer& lyr, const LayerCopies& cp) :
-            lref(std::cref(lyr)), copies(std::cref(cp)) {}
-    };
-
-    // One level may contain multiple slices from multiple objects and their
-    // supports
-    struct LayerRefs {
-        coord_t level;
-        std::vector<LayerRef> refs;
-        bool operator<(const LayerRefs& other) const { return level < other.level; }
-        explicit LayerRefs(coord_t lvl) : level(lvl) {}
-    };
-
-    std::vector<LayerRefs>                  m_printer_input;
+    // Ready-made data for rasterization.
+    std::vector<PrintLayer>                 m_printer_input;
 
     // The printer itself
     SLAPrinterPtr                           m_printer;
diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp
index c6a90a8cc..4bda48bcd 100644
--- a/src/slic3r/GUI/GLCanvas3D.cpp
+++ b/src/slic3r/GUI/GLCanvas3D.cpp
@@ -5021,8 +5021,8 @@ void GLCanvas3D::_render_sla_slices() const
             SliceRecord slice_high = obj->closest_slice_to_print_level(key_high, coord_t(SCALED_EPSILON));
     
             if (! slice_low.is_valid()) {
-                const ExPolygons& obj_bottom = obj->get_slices_from_record(slice_low, soModel);
-                const ExPolygons& sup_bottom = obj->get_slices_from_record(slice_low, soSupport);
+                const ExPolygons& obj_bottom = slice_low.get_slice(soModel);
+                const ExPolygons& sup_bottom = slice_low.get_slice(soSupport);
                 // calculate model bottom cap
                 if (bottom_obj_triangles.empty() && !obj_bottom.empty())
                     bottom_obj_triangles = triangulate_expolygons_3d(obj_bottom, clip_min_z, true);
@@ -5032,8 +5032,8 @@ void GLCanvas3D::_render_sla_slices() const
             }
 
             if (! slice_high.is_valid()) {
-                const ExPolygons& obj_top = obj->get_slices_from_record(slice_high, soModel);
-                const ExPolygons& sup_top = obj->get_slices_from_record(slice_high, soSupport);
+                const ExPolygons& obj_top = slice_high.get_slice(soModel);
+                const ExPolygons& sup_top = slice_high.get_slice(soSupport);
                 // calculate model top cap
                 if (top_obj_triangles.empty() && !obj_top.empty())
                     top_obj_triangles = triangulate_expolygons_3d(obj_top, clip_max_z, false);