From e8c08d8f915364706213068d81e248b4b3e49fc6 Mon Sep 17 00:00:00 2001
From: Enrico Turri <enricoturri@seznam.cz>
Date: Tue, 16 Apr 2019 08:50:46 +0200
Subject: [PATCH 1/4] Switch to regular shading when manipulating an object
 with gizmos while layers editing is active

---
 src/slic3r/GUI/GLCanvas3D.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp
index 43e91064f..2c86bfd97 100644
--- a/src/slic3r/GUI/GLCanvas3D.cpp
+++ b/src/slic3r/GUI/GLCanvas3D.cpp
@@ -3657,7 +3657,7 @@ void GLCanvas3D::_render_objects() const
         m_volumes.set_clipping_plane(m_camera_clipping_plane.get_data());
 
         m_shader.start_using();
-        if (m_picking_enabled && m_layers_editing.is_enabled() && (m_layers_editing.last_object_id != -1) && (m_layers_editing.object_max_z() > 0.0f)) {
+        if (m_picking_enabled && !m_gizmos.is_dragging() && m_layers_editing.is_enabled() && (m_layers_editing.last_object_id != -1) && (m_layers_editing.object_max_z() > 0.0f)) {
             int object_id = m_layers_editing.last_object_id;
             m_volumes.render_VBOs(GLVolumeCollection::Opaque, false, m_camera.get_view_matrix(), [object_id](const GLVolume &volume) {
                 // Which volume to paint without the layer height profile shader?

From a177a7e1da19be236de27d53c01fa3124e5ffb0e Mon Sep 17 00:00:00 2001
From: Lukas Matena <lukasmatena@seznam.cz>
Date: Mon, 15 Apr 2019 16:20:29 +0200
Subject: [PATCH 2/4] SLA gizmo clipping now also triangulates the cuts on
 support structure

---
 src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp | 93 ++++++++++++++++++--
 src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp |  7 +-
 2 files changed, 92 insertions(+), 8 deletions(-)

diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp
index aa88f9dd5..569684a15 100644
--- a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp
+++ b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp
@@ -51,6 +51,9 @@ void GLGizmoSlaSupports::set_sla_support_data(ModelObject* model_object, const S
         return;
     }
 
+    if (m_model_object != model_object)
+        m_print_object_idx = -1;
+
     m_model_object = model_object;
     m_active_instance = selection.get_instance_idx();
 
@@ -111,32 +114,91 @@ void GLGizmoSlaSupports::render_clipping_plane(const Selection& selection, const
     if (m_clipping_plane_distance == 0.f)
         return;
 
+    // First cache instance transformation to be used later.
     const GLVolume* vol = selection.get_volume(*selection.get_volume_idxs().begin());
     Transform3f instance_matrix = vol->get_instance_transformation().get_matrix().cast<float>();
     Transform3f instance_matrix_no_translation_no_scaling = vol->get_instance_transformation().get_matrix(true,false,true).cast<float>();
     Vec3f scaling = vol->get_instance_scaling_factor().cast<float>();
+    Vec3d instance_offset = vol->get_instance_offset();
 
+    // Calculate distance from mesh origin to the clipping plane (in mesh coordinates).
     Vec3f up_noscale = instance_matrix_no_translation_no_scaling.inverse() * direction_to_camera.cast<float>();
     Vec3f up = Vec3f(up_noscale(0)*scaling(0), up_noscale(1)*scaling(1), up_noscale(2)*scaling(2));
     float height_mesh = (m_active_instance_bb_radius - m_clipping_plane_distance * 2*m_active_instance_bb_radius) * (up_noscale.norm()/up.norm());
 
+    // Get transformation of the supports and calculate how far from its origin the clipping plane is.
+    Transform3d supports_trafo = Transform3d::Identity();
+    supports_trafo = supports_trafo.rotate(Eigen::AngleAxisd(vol->get_instance_rotation()(2), Vec3d::UnitZ()));
+    Vec3f up_supports = (supports_trafo.inverse() * direction_to_camera).cast<float>();
+    supports_trafo = supports_trafo.pretranslate(Vec3d(instance_offset(0), instance_offset(1), vol->get_sla_shift_z()));
+    // Instance and supports origin do not coincide, so the following is quite messy:
+    float height_supports = height_mesh * (up.norm() / up_supports.norm()) + instance_offset(2) * (direction_to_camera(2) / direction_to_camera.norm());
+
+    // In case either of these was recently changed, the cached triangulated ExPolygons are invalid now.
+    // We are gonna recalculate them both for the object and for the support structures.
     if (m_clipping_plane_distance != m_old_clipping_plane_distance
      || m_old_direction_to_camera != direction_to_camera) {
 
-        std::vector<ExPolygons> list_of_expolys;
+        m_old_direction_to_camera = direction_to_camera;
+        m_old_clipping_plane_distance = m_clipping_plane_distance;
+
+        // Now initialize the TMS for the object, perform the cut and save the result.
         if (! m_tms) {
             m_tms.reset(new TriangleMeshSlicer);
             m_tms->init(const_cast<TriangleMesh*>(&m_mesh), [](){});
         }
-
+        std::vector<ExPolygons> list_of_expolys;
         m_tms->set_up_direction(up);
         m_tms->slice(std::vector<float>{height_mesh}, 0.f, &list_of_expolys, [](){});
         m_triangles = triangulate_expolygons_2f(list_of_expolys[0]);
 
-        m_old_direction_to_camera = direction_to_camera;
-        m_old_clipping_plane_distance = m_clipping_plane_distance;
+
+
+        // Next, ask the backend if supports are already calculated. If so, we are gonna cut them too.
+        // First we need a pointer to the respective SLAPrintObject. The index into objects vector is
+        // cached so we don't have todo it on each render. We only search for the po if needed:
+        if (m_print_object_idx < 0 || (int)m_parent.sla_print()->objects().size() != m_print_objects_count) {
+            m_print_objects_count = m_parent.sla_print()->objects().size();
+            m_print_object_idx = -1;
+            for (const SLAPrintObject* po : m_parent.sla_print()->objects()) {
+                ++m_print_object_idx;
+                if (po->model_object()->id() == m_model_object->id())
+                    break;
+            }
+        }
+        if (m_print_object_idx >= 0) {
+            const SLAPrintObject* print_object = m_parent.sla_print()->objects()[m_print_object_idx];
+
+            if (print_object->is_step_done(slaposSupportTree)) {
+                // If the supports are already calculated, save the timestamp of the respective step
+                // so we can later tell they were recalculated.
+                size_t timestamp = print_object->step_state_with_timestamp(slaposSupportTree).timestamp;
+
+                if (!m_supports_tms || (int)timestamp != m_old_timestamp) {
+                    // The timestamp has changed - stash the mesh and initialize the TMS.
+                    m_supports_mesh = print_object->support_mesh();
+                    m_supports_tms.reset(new TriangleMeshSlicer);
+                    m_supports_tms->init(const_cast<TriangleMesh*>(&m_supports_mesh), [](){});
+                    m_old_timestamp = timestamp;
+                }
+
+                // The TMS is initialized - let's do the cutting:
+                list_of_expolys.clear();
+                m_supports_tms->set_up_direction(up_supports);
+                m_supports_tms->slice(std::vector<float>{height_supports}, 0.f, &list_of_expolys, [](){});
+                m_supports_triangles = triangulate_expolygons_2f(list_of_expolys[0]);
+            }
+            else {
+                // The supports are not valid. We better dump the cached data.
+                m_supports_tms.reset();
+                m_supports_triangles.clear();
+            }
+        }
     }
 
+    // At this point we have the triangulated cuts for both the object and supports - let's render.
+    ::glColor3f(1.0f, 0.37f, 0.0f);
+
 	if (! m_triangles.empty()) {
 		::glPushMatrix();
 		::glTranslated(0.0, 0.0, m_z_shift);
@@ -146,11 +208,26 @@ void GLGizmoSlaSupports::render_clipping_plane(const Selection& selection, const
 		Eigen::AngleAxisf aa(q);
 		::glRotatef(aa.angle() * (180./M_PI), aa.axis()(0), aa.axis()(1), aa.axis()(2));
 		::glTranslatef(0.f, 0.f, -0.001f); // to make sure the cut is safely beyond the near clipping plane
-		::glColor3f(1.0f, 0.37f, 0.0f);
         ::glBegin(GL_TRIANGLES);
-        ::glColor3f(1.0f, 0.37f, 0.0f);
         for (const Vec2f& point : m_triangles)
             ::glVertex3f(point(0), point(1), height_mesh);
+
+        ::glEnd();
+		::glPopMatrix();
+	}
+
+    if (! m_supports_triangles.empty()) {
+		::glPushMatrix();
+        ::glMultMatrixd(supports_trafo.data());
+        Eigen::Quaternionf q;
+		q.setFromTwoVectors(Vec3f::UnitZ(), up_supports);
+		Eigen::AngleAxisf aa(q);
+		::glRotatef(aa.angle() * (180./M_PI), aa.axis()(0), aa.axis()(1), aa.axis()(2));
+		::glTranslatef(0.f, 0.f, -0.001f); // to make sure the cut is safely beyond the near clipping plane
+        ::glBegin(GL_TRIANGLES);
+        for (const Vec2f& point : m_supports_triangles)
+            ::glVertex3f(point(0), point(1), height_supports);
+
         ::glEnd();
 		::glPopMatrix();
 	}
@@ -974,10 +1051,12 @@ void GLGizmoSlaSupports::on_set_state()
                 m_clipping_plane_distance = 0.f;
                 // Release copy of the mesh, triangle slicer and the AABB spatial search structure.
 				m_mesh.clear();
+                m_supports_mesh.clear();
                 m_AABB.deinit();
 				m_V = Eigen::MatrixXf();
 				m_F = Eigen::MatrixXi();
-                m_tms.reset(nullptr);
+                m_tms.reset();
+                m_supports_tms.reset();
             });
         }
         m_old_state = m_state;
diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp
index c74559e2f..41dd117d6 100644
--- a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp
+++ b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp
@@ -37,7 +37,12 @@ private:
     Eigen::MatrixXi m_F; // facets indices
     igl::AABB<Eigen::MatrixXf,3> m_AABB;
     TriangleMesh m_mesh;
+    mutable TriangleMesh m_supports_mesh;
     mutable std::vector<Vec2f> m_triangles;
+    mutable std::vector<Vec2f> m_supports_triangles;
+    mutable int m_old_timestamp = -1;
+    mutable int m_print_object_idx = -1;
+    mutable int m_print_objects_count = -1;
 
     class CacheEntry {
     public:
@@ -79,7 +84,6 @@ private:
     bool m_old_editing_state = false;       // To keep track of whether the user toggled between the modes (needed for imgui refreshes).
     float m_new_point_head_diameter;        // Size of a new point.
     float m_minimal_point_distance = 20.f;
-    float m_density = 100.f;
     mutable std::vector<CacheEntry> m_editing_mode_cache; // a support point and whether it is currently selected
     float m_clipping_plane_distance = 0.f;
     mutable float m_old_clipping_plane_distance = 0.f;
@@ -101,6 +105,7 @@ private:
     int m_canvas_height;
 
     mutable std::unique_ptr<TriangleMeshSlicer> m_tms;
+    mutable std::unique_ptr<TriangleMeshSlicer> m_supports_tms;
 
     std::vector<const ConfigOption*> get_config_options(const std::vector<std::string>& keys) const;
     bool is_point_clipped(const Vec3d& point, const Vec3d& direction_to_camera) const;

From f33e9bf6095eb4d54fce5946a75e2780fb1502d5 Mon Sep 17 00:00:00 2001
From: Lukas Matena <lukasmatena@seznam.cz>
Date: Mon, 15 Apr 2019 21:58:13 +0200
Subject: [PATCH 3/4] TriangleMeshSlicer is now initialized by const-pointer to
 the mesh, responsibility for calling require_shared_vertices is left to the
 caller

---
 src/libslic3r/Model.cpp                      |  1 +
 src/libslic3r/PrintObject.cpp                |  2 ++
 src/libslic3r/SLA/SLABasePool.cpp            |  1 +
 src/libslic3r/SLA/SLASupportTree.cpp         |  2 ++
 src/libslic3r/SLAPrint.cpp                   |  1 +
 src/libslic3r/TriangleMesh.cpp               |  6 ++++--
 src/libslic3r/TriangleMesh.hpp               | 12 +++++-------
 src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp |  2 ++
 8 files changed, 18 insertions(+), 9 deletions(-)

diff --git a/src/libslic3r/Model.cpp b/src/libslic3r/Model.cpp
index 6b16855e8..5a0558977 100644
--- a/src/libslic3r/Model.cpp
+++ b/src/libslic3r/Model.cpp
@@ -1189,6 +1189,7 @@ ModelObjectPtrs ModelObject::cut(size_t instance, coordf_t z, bool keep_upper, b
             volume->mesh.transform(instance_matrix * volume_matrix, true);
 
             // Perform cut
+            volume->mesh.require_shared_vertices(); // TriangleMeshSlicer needs this
             TriangleMeshSlicer tms(&volume->mesh);
             tms.cut(float(z), &upper_mesh, &lower_mesh);
 
diff --git a/src/libslic3r/PrintObject.cpp b/src/libslic3r/PrintObject.cpp
index 0b51f36ec..bb03d1e9d 100644
--- a/src/libslic3r/PrintObject.cpp
+++ b/src/libslic3r/PrintObject.cpp
@@ -1813,6 +1813,7 @@ std::vector<ExPolygons> PrintObject::_slice_volumes(const std::vector<float> &z,
             TriangleMeshSlicer mslicer;
             const Print *print = this->print();
             auto callback = TriangleMeshSlicer::throw_on_cancel_callback_type([print](){print->throw_if_canceled();});
+            mesh.require_shared_vertices(); // TriangleMeshSlicer needs this
             mslicer.init(&mesh, callback);
 			mslicer.slice(z, float(m_config.slice_closing_radius.value), &layers, callback);
             m_print->throw_if_canceled();
@@ -1840,6 +1841,7 @@ std::vector<ExPolygons> PrintObject::_slice_volume(const std::vector<float> &z,
         TriangleMeshSlicer mslicer;
         const Print *print = this->print();
         auto callback = TriangleMeshSlicer::throw_on_cancel_callback_type([print](){print->throw_if_canceled();});
+        mesh.require_shared_vertices(); // TriangleMeshSlicer needs this
         mslicer.init(&mesh, callback);
         mslicer.slice(z, float(m_config.slice_closing_radius.value), &layers, callback);
         m_print->throw_if_canceled();
diff --git a/src/libslic3r/SLA/SLABasePool.cpp b/src/libslic3r/SLA/SLABasePool.cpp
index 2aabaa590..94b6c7d9b 100644
--- a/src/libslic3r/SLA/SLABasePool.cpp
+++ b/src/libslic3r/SLA/SLABasePool.cpp
@@ -552,6 +552,7 @@ void base_plate(const TriangleMesh &mesh, ExPolygons &output, float h,
                 float layerh, ThrowOnCancel thrfn)
 {
     TriangleMesh m = mesh;
+    m.require_shared_vertices(); // TriangleMeshSlicer needs this
     TriangleMeshSlicer slicer(&m);
 
     auto bb = mesh.bounding_box();
diff --git a/src/libslic3r/SLA/SLASupportTree.cpp b/src/libslic3r/SLA/SLASupportTree.cpp
index bb0e5e007..37a6bae4b 100644
--- a/src/libslic3r/SLA/SLASupportTree.cpp
+++ b/src/libslic3r/SLA/SLASupportTree.cpp
@@ -2231,6 +2231,7 @@ SlicedSupports SLASupportTree::slice(float layerh, float init_layerh) const
 
     TriangleMesh fullmesh = m_impl->merged_mesh();
     fullmesh.merge(get_pad());
+    fullmesh.require_shared_vertices(); // TriangleMeshSlicer needs this
     TriangleMeshSlicer slicer(&fullmesh);
     SlicedSupports ret;
     slicer.slice(heights, 0.f, &ret, get().ctl().cancelfn);
@@ -2243,6 +2244,7 @@ SlicedSupports SLASupportTree::slice(const std::vector<float> &heights,
 {
     TriangleMesh fullmesh = m_impl->merged_mesh();
     fullmesh.merge(get_pad());
+    fullmesh.require_shared_vertices(); // TriangleMeshSlicer needs this
     TriangleMeshSlicer slicer(&fullmesh);
     SlicedSupports ret;
     slicer.slice(heights, cr, &ret, get().ctl().cancelfn);
diff --git a/src/libslic3r/SLAPrint.cpp b/src/libslic3r/SLAPrint.cpp
index e5a574463..b7191970d 100644
--- a/src/libslic3r/SLAPrint.cpp
+++ b/src/libslic3r/SLAPrint.cpp
@@ -706,6 +706,7 @@ void SLAPrint::process()
             po.m_model_height_levels.emplace_back(it->slice_level());
         }
 
+        mesh.require_shared_vertices(); // TriangleMeshSlicer needs this
         TriangleMeshSlicer slicer(&mesh);
 
         po.m_model_slices.clear();
diff --git a/src/libslic3r/TriangleMesh.cpp b/src/libslic3r/TriangleMesh.cpp
index 2d603661d..f449ac2b4 100644
--- a/src/libslic3r/TriangleMesh.cpp
+++ b/src/libslic3r/TriangleMesh.cpp
@@ -607,10 +607,12 @@ void TriangleMesh::require_shared_vertices()
     BOOST_LOG_TRIVIAL(trace) << "TriangleMeshSlicer::require_shared_vertices - end";
 }
 
-void TriangleMeshSlicer::init(TriangleMesh *_mesh, throw_on_cancel_callback_type throw_on_cancel)
+void TriangleMeshSlicer::init(const TriangleMesh *_mesh, throw_on_cancel_callback_type throw_on_cancel)
 {
     mesh = _mesh;
-    _mesh->require_shared_vertices();
+    if (! mesh->has_shared_vertices())
+        throw std::invalid_argument("TriangleMeshSlicer was passed a mesh without shared vertices.");
+
     throw_on_cancel();
     facets_edges.assign(_mesh->stl.stats.number_of_facets * 3, -1);
     v_scaled_shared.assign(_mesh->stl.v_shared, _mesh->stl.v_shared + _mesh->stl.stats.shared_vertices);
diff --git a/src/libslic3r/TriangleMesh.hpp b/src/libslic3r/TriangleMesh.hpp
index 4bf5ce039..60ddcca08 100644
--- a/src/libslic3r/TriangleMesh.hpp
+++ b/src/libslic3r/TriangleMesh.hpp
@@ -67,18 +67,17 @@ public:
     TriangleMesh convex_hull_3d() const;
     void reset_repair_stats();
     bool needed_repair() const;
+    void require_shared_vertices();
+    bool   has_shared_vertices() const { return stl.v_shared != NULL; }
     size_t facets_count() const { return this->stl.stats.number_of_facets; }
     bool   empty() const { return this->facets_count() == 0; }
-
     bool is_splittable() const;
 
     stl_file stl;
     bool repaired;
-    
+
 private:
-    void require_shared_vertices();
     std::deque<uint32_t> find_unvisited_neighbors(std::vector<unsigned char> &facet_visited) const;
-    friend class TriangleMeshSlicer;
 };
 
 enum FacetEdgeType { 
@@ -159,9 +158,8 @@ class TriangleMeshSlicer
 public:
     typedef std::function<void()> throw_on_cancel_callback_type;
     TriangleMeshSlicer() : mesh(nullptr) {}
-    // Not quite nice, but the constructor and init() methods require non-const mesh pointer to be able to call mesh->require_shared_vertices()
-	TriangleMeshSlicer(TriangleMesh* mesh) { this->init(mesh, [](){}); }
-    void init(TriangleMesh *mesh, throw_on_cancel_callback_type throw_on_cancel);
+	TriangleMeshSlicer(const TriangleMesh* mesh) { this->init(mesh, [](){}); }
+    void init(const TriangleMesh *mesh, throw_on_cancel_callback_type throw_on_cancel);
     void slice(const std::vector<float> &z, std::vector<Polygons>* layers, throw_on_cancel_callback_type throw_on_cancel) const;
     void slice(const std::vector<float> &z, const float closing_radius, std::vector<ExPolygons>* layers, throw_on_cancel_callback_type throw_on_cancel) const;
     enum FacetSliceType {
diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp
index 569684a15..af27c2f9f 100644
--- a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp
+++ b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp
@@ -178,6 +178,7 @@ void GLGizmoSlaSupports::render_clipping_plane(const Selection& selection, const
                     // The timestamp has changed - stash the mesh and initialize the TMS.
                     m_supports_mesh = print_object->support_mesh();
                     m_supports_tms.reset(new TriangleMeshSlicer);
+                    m_supports_mesh.require_shared_vertices(); // TriangleMeshSlicer needs this
                     m_supports_tms->init(const_cast<TriangleMesh*>(&m_supports_mesh), [](){});
                     m_old_timestamp = timestamp;
                 }
@@ -411,6 +412,7 @@ void GLGizmoSlaSupports::update_mesh()
     Eigen::MatrixXi& F = m_F;
     // This mesh does not account for the possible Z up SLA offset.
     m_mesh = m_model_object->raw_mesh();
+    m_mesh.require_shared_vertices(); // TriangleMeshSlicer needs this
     const stl_file& stl = m_mesh.stl;
     V.resize(3 * stl.stats.number_of_facets, 3);
     F.resize(stl.stats.number_of_facets, 3);

From 63ce3c3150fcf8bf4d068894857acdce49fbc5c6 Mon Sep 17 00:00:00 2001
From: Lukas Matena <lukasmatena@seznam.cz>
Date: Mon, 15 Apr 2019 22:24:10 +0200
Subject: [PATCH 4/4] SLA gizmo now does not make redundant copies of the
 object and supports meshes

---
 src/libslic3r/SLA/SLASupportTree.cpp         |  4 ++++
 src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp | 20 ++++++++++----------
 src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp |  4 ++--
 3 files changed, 16 insertions(+), 12 deletions(-)

diff --git a/src/libslic3r/SLA/SLASupportTree.cpp b/src/libslic3r/SLA/SLASupportTree.cpp
index 37a6bae4b..75f9b0140 100644
--- a/src/libslic3r/SLA/SLASupportTree.cpp
+++ b/src/libslic3r/SLA/SLASupportTree.cpp
@@ -817,6 +817,10 @@ public:
 
         meshcache = mesh(merged);
 
+        // The mesh will be passed by const-pointer to TriangleMeshSlicer,
+        // which will need this.
+        meshcache.require_shared_vertices();
+
         // TODO: Is this necessary?
         //meshcache.repair();
 
diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp
index af27c2f9f..2285e2520 100644
--- a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp
+++ b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp
@@ -145,7 +145,7 @@ void GLGizmoSlaSupports::render_clipping_plane(const Selection& selection, const
         // Now initialize the TMS for the object, perform the cut and save the result.
         if (! m_tms) {
             m_tms.reset(new TriangleMeshSlicer);
-            m_tms->init(const_cast<TriangleMesh*>(&m_mesh), [](){});
+            m_tms->init(m_mesh, [](){});
         }
         std::vector<ExPolygons> list_of_expolys;
         m_tms->set_up_direction(up);
@@ -176,10 +176,10 @@ void GLGizmoSlaSupports::render_clipping_plane(const Selection& selection, const
 
                 if (!m_supports_tms || (int)timestamp != m_old_timestamp) {
                     // The timestamp has changed - stash the mesh and initialize the TMS.
-                    m_supports_mesh = print_object->support_mesh();
+                    m_supports_mesh = &print_object->support_mesh();
                     m_supports_tms.reset(new TriangleMeshSlicer);
-                    m_supports_mesh.require_shared_vertices(); // TriangleMeshSlicer needs this
-                    m_supports_tms->init(const_cast<TriangleMesh*>(&m_supports_mesh), [](){});
+                    // The mesh should already have the shared vertices calculated.
+                    m_supports_tms->init(m_supports_mesh, [](){});
                     m_old_timestamp = timestamp;
                 }
 
@@ -410,10 +410,12 @@ void GLGizmoSlaSupports::update_mesh()
     wxBusyCursor wait;
     Eigen::MatrixXf& V = m_V;
     Eigen::MatrixXi& F = m_F;
+    // We rely on SLA model object having a single volume,
+    // this way we can use that mesh directly.
     // This mesh does not account for the possible Z up SLA offset.
-    m_mesh = m_model_object->raw_mesh();
-    m_mesh.require_shared_vertices(); // TriangleMeshSlicer needs this
-    const stl_file& stl = m_mesh.stl;
+    m_mesh = &m_model_object->volumes.front()->mesh;
+    const_cast<TriangleMesh*>(m_mesh)->require_shared_vertices(); // TriangleMeshSlicer needs this
+    const stl_file& stl = m_mesh->stl;
     V.resize(3 * stl.stats.number_of_facets, 3);
     F.resize(stl.stats.number_of_facets, 3);
     for (unsigned int i=0; i<stl.stats.number_of_facets; ++i) {
@@ -1051,9 +1053,7 @@ void GLGizmoSlaSupports::on_set_state()
                 m_editing_mode = false; // so it is not active next time the gizmo opens
                 m_editing_mode_cache.clear();
                 m_clipping_plane_distance = 0.f;
-                // Release copy of the mesh, triangle slicer and the AABB spatial search structure.
-				m_mesh.clear();
-                m_supports_mesh.clear();
+                // Release triangle mesh slicer and the AABB spatial search structure.
                 m_AABB.deinit();
 				m_V = Eigen::MatrixXf();
 				m_F = Eigen::MatrixXi();
diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp
index 41dd117d6..a06a3502c 100644
--- a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp
+++ b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp
@@ -36,8 +36,8 @@ private:
     Eigen::MatrixXf m_V; // vertices
     Eigen::MatrixXi m_F; // facets indices
     igl::AABB<Eigen::MatrixXf,3> m_AABB;
-    TriangleMesh m_mesh;
-    mutable TriangleMesh m_supports_mesh;
+    const TriangleMesh* m_mesh;
+    mutable const TriangleMesh* m_supports_mesh;
     mutable std::vector<Vec2f> m_triangles;
     mutable std::vector<Vec2f> m_supports_triangles;
     mutable int m_old_timestamp = -1;