From d7f55253cd636c228adee9a54468ef52d8f377b0 Mon Sep 17 00:00:00 2001
From: Lukas Matena <lukasmatena@seznam.cz>
Date: Tue, 16 Aug 2022 13:24:57 +0200
Subject: [PATCH] Cut: allow enabling/disabling an island

---
 src/slic3r/GUI/Gizmos/GLGizmoCut.cpp     |  45 +++---
 src/slic3r/GUI/Gizmos/GLGizmoCut.hpp     |   2 +-
 src/slic3r/GUI/Gizmos/GLGizmosCommon.cpp |  10 ++
 src/slic3r/GUI/Gizmos/GLGizmosCommon.hpp |   4 +
 src/slic3r/GUI/MeshUtils.cpp             | 177 ++++++++++++-----------
 src/slic3r/GUI/MeshUtils.hpp             |  22 ++-
 6 files changed, 150 insertions(+), 110 deletions(-)

diff --git a/src/slic3r/GUI/Gizmos/GLGizmoCut.cpp b/src/slic3r/GUI/Gizmos/GLGizmoCut.cpp
index 7b6c729f8..905e39db3 100644
--- a/src/slic3r/GUI/Gizmos/GLGizmoCut.cpp
+++ b/src/slic3r/GUI/Gizmos/GLGizmoCut.cpp
@@ -1117,7 +1117,8 @@ void GLGizmoCut3D::on_dragging(const UpdateData& data)
     else if (m_hover_id >= m_connectors_group_id && m_connector_mode == CutConnectorMode::Manual)
     {
         std::pair<Vec3d, Vec3d> pos_and_normal;
-        if (!unproject_on_cut_plane(data.mouse_pos.cast<double>(), pos_and_normal))
+        Vec3d pos_world;
+        if (!unproject_on_cut_plane(data.mouse_pos.cast<double>(), pos_and_normal, pos_world))
             return;
         connectors[m_hover_id - m_connectors_group_id].pos    = pos_and_normal.first;
         update_raycasters_for_picking_transform();
@@ -1773,7 +1774,7 @@ void GLGizmoCut3D::perform_cut(const Selection& selection)
 
 // Unprojects the mouse position on the mesh and saves hit point and normal of the facet into pos_and_normal
 // Return false if no intersection was found, true otherwise.
-bool GLGizmoCut3D::unproject_on_cut_plane(const Vec2d& mouse_position, std::pair<Vec3d, Vec3d>& pos_and_normal)
+bool GLGizmoCut3D::unproject_on_cut_plane(const Vec2d& mouse_position, std::pair<Vec3d, Vec3d>& pos_and_normal, Vec3d& pos_world)
 {
     const float sla_shift = m_c->selection_info()->get_sla_shift();
 
@@ -1788,8 +1789,8 @@ bool GLGizmoCut3D::unproject_on_cut_plane(const Vec2d& mouse_position, std::pair
         ++mesh_id;
         if (!mv->is_model_part())
             continue;
-        Vec3f hit;
         Vec3f normal;
+        Vec3f hit;
         bool clipping_plane_was_hit = false;
 
 //        const Transform3d volume_trafo = get_volume_transformation(mv);
@@ -1806,6 +1807,7 @@ bool GLGizmoCut3D::unproject_on_cut_plane(const Vec2d& mouse_position, std::pair
 
             // Return both the point and the facet normal.
             pos_and_normal = std::make_pair(hit_d, normal.cast<double>());
+            pos_world = hit.cast<double>();
             return true;
         }
     }
@@ -1916,27 +1918,32 @@ bool GLGizmoCut3D::gizmo_event(SLAGizmoEventType action, const Vec2d& mouse_posi
 
     CutConnectors& connectors = m_c->selection_info()->model_object()->cut_connectors;
 
-    if (action == SLAGizmoEventType::LeftDown && !shift_down && m_connectors_editing) {
+    if (action == SLAGizmoEventType::LeftDown && !shift_down) {
         // If there is no selection and no hovering, add new point
         if (m_hover_id == -1 && !control_down && !alt_down) {
             std::pair<Vec3d, Vec3d> pos_and_normal;
-            if (unproject_on_cut_plane(mouse_position.cast<double>(), pos_and_normal)) {
+            Vec3d pos_world;
+            if (unproject_on_cut_plane(mouse_position.cast<double>(), pos_and_normal, pos_world)) {
                 const Vec3d& hit = pos_and_normal.first;
-                // The clipping plane was clicked, hit containts coordinates of the hit in world coords.
-                //std::cout << hit.x() << "\t" << hit.y() << "\t" << hit.z() << std::endl;
-                Plater::TakeSnapshot snapshot(wxGetApp().plater(), _L("Add connector"), UndoRedo::SnapshotType::GizmoAction);
 
-                connectors.emplace_back(hit, Geometry::Transformation(m_rotation_m).get_rotation(), 
-                                        float(m_connector_size * 0.5), float(m_connector_depth_ratio), 
-                                        float(0.01f * m_connector_size_tolerance), float(0.01f * m_connector_depth_ratio_tolerance),
-                                        CutConnectorAttributes( CutConnectorType(m_connector_type), 
-                                                                CutConnectorStyle(m_connector_style), 
-                                                                CutConnectorShape(m_connector_shape_id)));
-                std::fill(m_selected.begin(), m_selected.end(), false);
-                m_selected.push_back(true);
-                assert(m_selected.size() == connectors.size());
-                update_model_object();
-                m_parent.set_as_dirty();
+                if (m_connectors_editing) {
+
+                    Plater::TakeSnapshot snapshot(wxGetApp().plater(), _L("Add connector"), UndoRedo::SnapshotType::GizmoAction);
+
+                    connectors.emplace_back(hit, Geometry::Transformation(m_rotation_m).get_rotation(), 
+                                            float(m_connector_size * 0.5), float(m_connector_depth_ratio), 
+                                            float(0.01f * m_connector_size_tolerance), float(0.01f * m_connector_depth_ratio_tolerance),
+                                            CutConnectorAttributes( CutConnectorType(m_connector_type), 
+                                                                    CutConnectorStyle(m_connector_style), 
+                                                                    CutConnectorShape(m_connector_shape_id)));
+                    std::fill(m_selected.begin(), m_selected.end(), false);
+                    m_selected.push_back(true);
+                    assert(m_selected.size() == connectors.size());
+                    update_model_object();
+                    m_parent.set_as_dirty();
+                } else {
+                    m_c->object_clipper()->pass_mouse_click(pos_world);
+                }
 
                 return true;
             }
diff --git a/src/slic3r/GUI/Gizmos/GLGizmoCut.hpp b/src/slic3r/GUI/Gizmos/GLGizmoCut.hpp
index 81a69e425..a7892a9cd 100644
--- a/src/slic3r/GUI/Gizmos/GLGizmoCut.hpp
+++ b/src/slic3r/GUI/Gizmos/GLGizmoCut.hpp
@@ -139,7 +139,7 @@ public:
     GLGizmoCut3D(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id);
 
     std::string get_tooltip() const override;
-    bool unproject_on_cut_plane(const Vec2d& mouse_pos, std::pair<Vec3d, Vec3d>& pos_and_normal);
+    bool unproject_on_cut_plane(const Vec2d& mouse_pos, std::pair<Vec3d, Vec3d>& pos_and_normal, Vec3d& pos_world);
     bool gizmo_event(SLAGizmoEventType action, const Vec2d& mouse_position, bool shift_down, bool alt_down, bool control_down);
 
     /// <summary>
diff --git a/src/slic3r/GUI/Gizmos/GLGizmosCommon.cpp b/src/slic3r/GUI/Gizmos/GLGizmosCommon.cpp
index 97f3cb9a8..a08836c28 100644
--- a/src/slic3r/GUI/Gizmos/GLGizmosCommon.cpp
+++ b/src/slic3r/GUI/Gizmos/GLGizmosCommon.cpp
@@ -494,6 +494,16 @@ void ObjectClipper::set_behavior(bool hide_clipped, bool fill_cut, double contou
         clipper->set_behaviour(fill_cut, contour_width);
 }
 
+void ObjectClipper::pass_mouse_click(const Vec3d& pt)
+{
+    for (auto& clipper : m_clippers)
+        clipper->pass_mouse_click(pt);
+}
+
+std::vector<Vec3d> ObjectClipper::get_disabled_contours() const
+{
+    return std::vector<Vec3d>();
+}
 
 void SupportsClipper::on_update()
 {
diff --git a/src/slic3r/GUI/Gizmos/GLGizmosCommon.hpp b/src/slic3r/GUI/Gizmos/GLGizmosCommon.hpp
index 925408008..7c41a64b9 100644
--- a/src/slic3r/GUI/Gizmos/GLGizmosCommon.hpp
+++ b/src/slic3r/GUI/Gizmos/GLGizmosCommon.hpp
@@ -262,6 +262,10 @@ public:
     void set_position_by_ratio(double pos, bool keep_normal);
     void set_range_and_pos(const Vec3d& cpl_normal, double cpl_offset, double pos);
     void set_behavior(bool hide_clipped, bool fill_cut, double contour_width);
+    
+    void pass_mouse_click(const Vec3d& pt);
+    std::vector<Vec3d> get_disabled_contours() const;
+
 
 
 protected:
diff --git a/src/slic3r/GUI/MeshUtils.cpp b/src/slic3r/GUI/MeshUtils.cpp
index bbf1f7652..74fe82494 100644
--- a/src/slic3r/GUI/MeshUtils.cpp
+++ b/src/slic3r/GUI/MeshUtils.cpp
@@ -23,7 +23,7 @@ namespace GUI {
 void MeshClipper::set_behaviour(bool fill_cut, double contour_width)
 {
     if (fill_cut != m_fill_cut || contour_width != m_contour_width)
-        m_triangles_valid = false;
+        m_result.reset();
     m_fill_cut = fill_cut;
     m_contour_width = contour_width;
 }
@@ -34,7 +34,7 @@ void MeshClipper::set_plane(const ClippingPlane& plane)
 {
     if (m_plane != plane) {
         m_plane = plane;
-        m_triangles_valid = false;
+        m_result.reset();
     }
 }
 
@@ -43,7 +43,7 @@ void MeshClipper::set_limiting_plane(const ClippingPlane& plane)
 {
     if (m_limiting_plane != plane) {
         m_limiting_plane = plane;
-        m_triangles_valid = false;
+        m_result.reset();
     }
 }
 
@@ -53,7 +53,7 @@ void MeshClipper::set_mesh(const TriangleMesh& mesh)
 {
     if (m_mesh != &mesh) {
         m_mesh = &mesh;
-        m_triangles_valid = false;
+        m_result.reset();
     }
 }
 
@@ -61,7 +61,7 @@ void MeshClipper::set_negative_mesh(const TriangleMesh& mesh)
 {
     if (m_negative_mesh != &mesh) {
         m_negative_mesh = &mesh;
-        m_triangles_valid = false;
+        m_result.reset();
     }
 }
 
@@ -71,7 +71,7 @@ void MeshClipper::set_transformation(const Geometry::Transformation& trafo)
 {
     if (! m_trafo.get_matrix().isApprox(trafo.get_matrix())) {
         m_trafo = trafo;
-        m_triangles_valid = false;
+        m_result.reset();
     }
 }
 
@@ -81,12 +81,9 @@ void MeshClipper::render_cut(const ColorRGBA& color)
 void MeshClipper::render_cut()
 #endif // ENABLE_LEGACY_OPENGL_REMOVAL
 {
-    if (! m_triangles_valid)
+    if (! m_result)
         recalculate_triangles();
 #if ENABLE_LEGACY_OPENGL_REMOVAL
-    if (m_model.vertices_count() == 0 || m_model.indices_count() == 0)
-        return;
-
     GLShaderProgram* curr_shader = wxGetApp().get_current_shader();
     if (curr_shader != nullptr)
         curr_shader->stop_using();
@@ -97,8 +94,10 @@ void MeshClipper::render_cut()
         const Camera& camera = wxGetApp().plater()->get_camera();
         shader->set_uniform("view_model_matrix", camera.get_view_matrix());
         shader->set_uniform("projection_matrix", camera.get_projection_matrix());
-        m_model.set_color(color);
-        m_model.render();
+        for (CutIsland& isl : m_result->cut_islands) {
+            isl.model.set_color(isl.disabled ? ColorRGBA(1.f, 0.f, 0.f, 1.f) : color);
+            isl.model.render();
+        }
         shader->stop_using();
     }
 
@@ -117,7 +116,7 @@ void MeshClipper::render_contour(const ColorRGBA& color)
 void MeshClipper::render_contour()
 #endif // ENABLE_LEGACY_OPENGL_REMOVAL
 {
-    if (! m_triangles_valid)
+    if (! m_result)
         recalculate_triangles();
 #if ENABLE_LEGACY_OPENGL_REMOVAL
     GLShaderProgram* curr_shader = wxGetApp().get_current_shader();
@@ -130,8 +129,10 @@ void MeshClipper::render_contour()
         const Camera& camera = wxGetApp().plater()->get_camera();
         shader->set_uniform("view_model_matrix", camera.get_view_matrix());
         shader->set_uniform("projection_matrix", camera.get_projection_matrix());
-        m_model_expanded.set_color(color);
-        m_model_expanded.render();
+        for (CutIsland& isl : m_result->cut_islands) {
+            isl.model_expanded.set_color(color);
+            isl.model_expanded.render();
+        }
         shader->stop_using();
     }
 
@@ -145,8 +146,24 @@ void MeshClipper::render_contour()
 
 
 
+void MeshClipper::pass_mouse_click(const Vec3d& point_in)
+{
+    if (! m_result || m_result->cut_islands.empty())
+        return;
+    Vec3d point = m_result->trafo.inverse() * point_in;
+    Point pt_2d = Point::new_scale(Vec2d(point.x(), point.y()));
+
+    for (CutIsland& isl : m_result->cut_islands) {
+        if (isl.expoly_bb.contains(pt_2d) && isl.expoly.contains(pt_2d))
+            isl.disabled = ! isl.disabled;
+    }
+}
+
 void MeshClipper::recalculate_triangles()
 {
+    m_result = ClipResult();
+
+
 #if ENABLE_WORLD_COORDINATE
     const Transform3f instance_matrix_no_translation_no_scaling = m_trafo.get_rotation_matrix().cast<float>();
 #else
@@ -176,6 +193,8 @@ void MeshClipper::recalculate_triangles()
     tr.rotate(q);
     tr = m_trafo.get_matrix() * tr;
 
+    m_result->trafo = tr;
+
     if (m_limiting_plane != ClippingPlane::ClipsNothing())
     {
         // Now remove whatever ended up below the limiting plane (e.g. sinking objects).
@@ -231,88 +250,72 @@ void MeshClipper::recalculate_triangles()
 
     tr.pretranslate(0.001 * m_plane.get_normal().normalized()); // to avoid z-fighting
 
-    std::vector<Vec2f> triangles2d = m_fill_cut
-        ? triangulate_expolygons_2f(expolys, m_trafo.get_matrix().matrix().determinant() < 0.)
-        : std::vector<Vec2f>();
 
 #if ENABLE_LEGACY_OPENGL_REMOVAL
-    m_model.reset();
+    std::vector<Vec2f> triangles2d;
 
-    GLModel::Geometry init_data;
-    init_data.format = { GLModel::Geometry::EPrimitiveType::Triangles, GLModel::Geometry::EVertexLayout::P3N3 };
-    init_data.reserve_vertices(triangles2d.size());
-    init_data.reserve_indices(triangles2d.size());
+    for (const ExPolygon& exp : expolys) {
+        triangles2d.clear();
 
-    // vertices + indices
-    for (auto it = triangles2d.cbegin(); it != triangles2d.cend(); it = it + 3) {
-        init_data.add_vertex((Vec3f)(tr * Vec3d((*(it + 0)).x(), (*(it + 0)).y(), height_mesh)).cast<float>(), (Vec3f)up.cast<float>());
-        init_data.add_vertex((Vec3f)(tr * Vec3d((*(it + 1)).x(), (*(it + 1)).y(), height_mesh)).cast<float>(), (Vec3f)up.cast<float>());
-        init_data.add_vertex((Vec3f)(tr * Vec3d((*(it + 2)).x(), (*(it + 2)).y(), height_mesh)).cast<float>(), (Vec3f)up.cast<float>());
-        const size_t idx = it - triangles2d.cbegin();
-        init_data.add_triangle((unsigned int)idx, (unsigned int)idx + 1, (unsigned int)idx + 2);
+        m_result->cut_islands.push_back(CutIsland());
+        CutIsland& isl = m_result->cut_islands.back();
+
+        if (m_fill_cut) {
+            triangles2d = triangulate_expolygon_2f(exp, m_trafo.get_matrix().matrix().determinant() < 0.);
+            GLModel::Geometry init_data;
+            init_data.format = { GLModel::Geometry::EPrimitiveType::Triangles, GLModel::Geometry::EVertexLayout::P3N3 };
+            init_data.reserve_vertices(triangles2d.size());
+            init_data.reserve_indices(triangles2d.size());
+
+            // vertices + indices
+            for (auto it = triangles2d.cbegin(); it != triangles2d.cend(); it = it + 3) {
+                init_data.add_vertex((Vec3f)(tr * Vec3d((*(it + 0)).x(), (*(it + 0)).y(), height_mesh)).cast<float>(), (Vec3f)up.cast<float>());
+                init_data.add_vertex((Vec3f)(tr * Vec3d((*(it + 1)).x(), (*(it + 1)).y(), height_mesh)).cast<float>(), (Vec3f)up.cast<float>());
+                init_data.add_vertex((Vec3f)(tr * Vec3d((*(it + 2)).x(), (*(it + 2)).y(), height_mesh)).cast<float>(), (Vec3f)up.cast<float>());
+                const size_t idx = it - triangles2d.cbegin();
+                init_data.add_triangle((unsigned int)idx, (unsigned int)idx + 1, (unsigned int)idx + 2);
+            }
+
+            if (!init_data.is_empty())
+                isl.model.init_from(std::move(init_data));
+        }
+
+        if (m_contour_width != 0.) {
+            triangles2d.clear();
+            ExPolygons expolys_exp = offset_ex(exp, scale_(m_contour_width));
+            expolys_exp = diff_ex(expolys_exp, ExPolygons({exp}));
+            triangles2d = triangulate_expolygons_2f(expolys_exp, m_trafo.get_matrix().matrix().determinant() < 0.);
+            GLModel::Geometry init_data = GLModel::Geometry();
+            init_data.format = { GLModel::Geometry::EPrimitiveType::Triangles, GLModel::Geometry::EVertexLayout::P3N3 };
+            init_data.reserve_vertices(triangles2d.size());
+            init_data.reserve_indices(triangles2d.size());
+
+            // vertices + indices
+            for (auto it = triangles2d.cbegin(); it != triangles2d.cend(); it = it + 3) {
+                init_data.add_vertex((Vec3f)(tr * Vec3d((*(it + 0)).x(), (*(it + 0)).y(), height_mesh)).cast<float>(), (Vec3f)up.cast<float>());
+                init_data.add_vertex((Vec3f)(tr * Vec3d((*(it + 1)).x(), (*(it + 1)).y(), height_mesh)).cast<float>(), (Vec3f)up.cast<float>());
+                init_data.add_vertex((Vec3f)(tr * Vec3d((*(it + 2)).x(), (*(it + 2)).y(), height_mesh)).cast<float>(), (Vec3f)up.cast<float>());
+                const size_t idx = it - triangles2d.cbegin();
+                init_data.add_triangle((unsigned short)idx, (unsigned short)idx + 1, (unsigned short)idx + 2);
+            }
+
+            if (!init_data.is_empty())
+                isl.model_expanded.init_from(std::move(init_data));
+        }
+
+        isl.expoly = std::move(exp);
+        isl.expoly_bb = get_extents(exp);
     }
-
-    if (!init_data.is_empty())
-        m_model.init_from(std::move(init_data));
 #else
-    m_vertex_array.release_geometry();
-    for (auto it=triangles2d.cbegin(); it != triangles2d.cend(); it=it+3) {
-        m_vertex_array.push_geometry(tr * Vec3d((*(it+0))(0), (*(it+0))(1), height_mesh), up);
-        m_vertex_array.push_geometry(tr * Vec3d((*(it+1))(0), (*(it+1))(1), height_mesh), up);
-        m_vertex_array.push_geometry(tr * Vec3d((*(it+2))(0), (*(it+2))(1), height_mesh), up);
-        const size_t idx = it - triangles2d.cbegin();
-        m_vertex_array.push_triangle(idx, idx+1, idx+2);
-    }
-    m_vertex_array.finalize_geometry(true);
-#endif // ENABLE_LEGACY_OPENGL_REMOVAL
-
-
-    triangles2d = {};
-    if (m_contour_width != 0.) {
-        ExPolygons expolys_exp = offset_ex(expolys, scale_(m_contour_width));
-        expolys_exp = diff_ex(expolys_exp, expolys);
-        triangles2d = triangulate_expolygons_2f(expolys_exp, m_trafo.get_matrix().matrix().determinant() < 0.);
-    }
-
-
-#if ENABLE_LEGACY_OPENGL_REMOVAL
-    m_model_expanded.reset();
-
-    init_data = GLModel::Geometry();
-    init_data.format = { GLModel::Geometry::EPrimitiveType::Triangles, GLModel::Geometry::EVertexLayout::P3N3 };
-    init_data.reserve_vertices(triangles2d.size());
-    init_data.reserve_indices(triangles2d.size());
-
-    // vertices + indices
-    for (auto it = triangles2d.cbegin(); it != triangles2d.cend(); it = it + 3) {
-        init_data.add_vertex((Vec3f)(tr * Vec3d((*(it + 0)).x(), (*(it + 0)).y(), height_mesh)).cast<float>(), (Vec3f)up.cast<float>());
-        init_data.add_vertex((Vec3f)(tr * Vec3d((*(it + 1)).x(), (*(it + 1)).y(), height_mesh)).cast<float>(), (Vec3f)up.cast<float>());
-        init_data.add_vertex((Vec3f)(tr * Vec3d((*(it + 2)).x(), (*(it + 2)).y(), height_mesh)).cast<float>(), (Vec3f)up.cast<float>());
-        const size_t idx = it - triangles2d.cbegin();
-        init_data.add_triangle((unsigned short)idx, (unsigned short)idx + 1, (unsigned short)idx + 2);
-        //if (init_data./*format.*/index_type == GLModel::Geometry::EIndexType::USHORT)
-        //    init_data.add_ushort_triangle((unsigned short)idx, (unsigned short)idx + 1, (unsigned short)idx + 2);
-        //else
-        //    init_data.add_uint_triangle((unsigned int)idx, (unsigned int)idx + 1, (unsigned int)idx + 2);
-    }
-
-    if (!init_data.is_empty())
-        m_model_expanded.init_from(std::move(init_data));
-#else
-    m_vertex_array_expanded.release_geometry();
-    for (auto it=triangles2d.cbegin(); it != triangles2d.cend(); it=it+3) {
-        m_vertex_array_expanded.push_geometry(tr * Vec3d((*(it+0))(0), (*(it+0))(1), height_mesh), up);
-        m_vertex_array_expanded.push_geometry(tr * Vec3d((*(it+1))(0), (*(it+1))(1), height_mesh), up);
-        m_vertex_array_expanded.push_geometry(tr * Vec3d((*(it+2))(0), (*(it+2))(1), height_mesh), up);
-        const size_t idx = it - triangles2d.cbegin();
-        m_vertex_array_expanded.push_triangle(idx, idx+1, idx+2);
-    }
-    m_vertex_array_expanded.finalize_geometry(true);
+    #error NOT IMPLEMENTED
 #endif // ENABLE_LEGACY_OPENGL_REMOVAL
 
 
 
-    m_triangles_valid = true;
+#if ENABLE_LEGACY_OPENGL_REMOVAL
+#else
+    #error NOT IMPLEMENTED
+#endif // ENABLE_LEGACY_OPENGL_REMOVAL
 }
 
 
diff --git a/src/slic3r/GUI/MeshUtils.hpp b/src/slic3r/GUI/MeshUtils.hpp
index 5df4236a6..726f228ca 100644
--- a/src/slic3r/GUI/MeshUtils.hpp
+++ b/src/slic3r/GUI/MeshUtils.hpp
@@ -14,6 +14,7 @@
 #endif // ENABLE_LEGACY_OPENGL_REMOVAL
 
 #include <cfloat>
+#include <optional>
 #if ENABLE_RAYCAST_PICKING
 #include <memory>
 #endif // ENABLE_RAYCAST_PICKING
@@ -112,6 +113,9 @@ public:
     void render_cut();
 #endif // ENABLE_LEGACY_OPENGL_REMOVAL
 
+    void pass_mouse_click(const Vec3d& pt);
+
+
 private:
     void recalculate_triangles();
 
@@ -121,12 +125,24 @@ private:
     ClippingPlane m_plane;
     ClippingPlane m_limiting_plane = ClippingPlane::ClipsNothing();
 #if ENABLE_LEGACY_OPENGL_REMOVAL
-    GLModel m_model;
-    GLModel m_model_expanded;
+
+    struct CutIsland {
+        GLModel model;
+        GLModel model_expanded;
+        ExPolygon expoly;
+        BoundingBox expoly_bb;
+        bool disabled = false;
+    };
+    struct ClipResult {
+        std::vector<CutIsland> cut_islands;
+        Transform3d trafo; // this rotates the cut into world coords
+    };
+    std::optional<ClipResult> m_result;
+    
 #else
+    #error NOT IMLEMENTED
     GLIndexedVertexArray m_vertex_array;
 #endif // ENABLE_LEGACY_OPENGL_REMOVAL
-    bool m_triangles_valid = false;
     bool m_fill_cut = true;
     double m_contour_width = 0.;
 };