From 83b6b82188941744fe7b1a0ad04f5888b7900bb0 Mon Sep 17 00:00:00 2001
From: bubnikv <bubnikv@gmail.com>
Date: Mon, 16 Sep 2019 16:35:08 +0200
Subject: [PATCH 01/11] Refactored ExtrusionEntityCollection::flatten()

---
 src/libslic3r/ExtrusionEntityCollection.cpp | 26 ++++++++++-----------
 src/libslic3r/ExtrusionEntityCollection.hpp |  1 -
 2 files changed, 13 insertions(+), 14 deletions(-)

diff --git a/src/libslic3r/ExtrusionEntityCollection.cpp b/src/libslic3r/ExtrusionEntityCollection.cpp
index 9ae116c47..70c2348af 100644
--- a/src/libslic3r/ExtrusionEntityCollection.cpp
+++ b/src/libslic3r/ExtrusionEntityCollection.cpp
@@ -11,7 +11,7 @@ ExtrusionEntityCollection::ExtrusionEntityCollection(const ExtrusionPaths &paths
     this->append(paths);
 }
 
-ExtrusionEntityCollection& ExtrusionEntityCollection::operator= (const ExtrusionEntityCollection &other)
+ExtrusionEntityCollection& ExtrusionEntityCollection::operator=(const ExtrusionEntityCollection &other)
 {
     this->entities      = other.entities;
     for (size_t i = 0; i < this->entities.size(); ++i)
@@ -175,20 +175,20 @@ size_t ExtrusionEntityCollection::items_count() const
 }
 
 // Returns a single vector of pointers to all non-collection items contained in this one.
-void ExtrusionEntityCollection::flatten(ExtrusionEntityCollection* retval) const
-{
-    for (const ExtrusionEntity *entity : this->entities)
-        if (entity->is_collection())
-            retval->append(static_cast<const ExtrusionEntityCollection*>(entity)->flatten().entities);
-        else
-            retval->append(*entity);
-}
-
 ExtrusionEntityCollection ExtrusionEntityCollection::flatten() const
 {
-    ExtrusionEntityCollection coll;
-    this->flatten(&coll);
-    return coll;
+	struct Flatten {
+		ExtrusionEntityCollection out;
+		void recursive_do(const ExtrusionEntityCollection &collection) {
+			for (const ExtrusionEntity* entity : collection.entities)
+				if (entity->is_collection())
+					this->recursive_do(*static_cast<const ExtrusionEntityCollection*>(entity));
+				else
+					out.append(*entity);
+		}
+	} flatten;
+	flatten.recursive_do(*this);
+    return flatten.out;
 }
 
 double ExtrusionEntityCollection::min_mm3_per_mm() const
diff --git a/src/libslic3r/ExtrusionEntityCollection.hpp b/src/libslic3r/ExtrusionEntityCollection.hpp
index 4fe964ee1..221afc453 100644
--- a/src/libslic3r/ExtrusionEntityCollection.hpp
+++ b/src/libslic3r/ExtrusionEntityCollection.hpp
@@ -85,7 +85,6 @@ public:
     Polygons polygons_covered_by_spacing(const float scaled_epsilon = 0.f) const
         { Polygons out; this->polygons_covered_by_spacing(out, scaled_epsilon); return out; }
     size_t items_count() const;
-    void flatten(ExtrusionEntityCollection* retval) const;
     ExtrusionEntityCollection flatten() const;
     double min_mm3_per_mm() const;
     double total_volume() const override { double volume=0.; for (const auto& ent : entities) volume+=ent->total_volume(); return volume; }

From 93aa5ac6ce0649d696a315177dee9158ea00df8a Mon Sep 17 00:00:00 2001
From: YuSanka <yusanka@gmail.com>
Date: Tue, 17 Sep 2019 13:41:44 +0200
Subject: [PATCH 02/11] Fixed re-scaling under MSW for Layers editing

+ Clean code in GUI_ObjectManipulation.cpp
---
 src/slic3r/GUI/GUI_ObjectLayers.cpp       | 41 +++++++++++++++++++++++
 src/slic3r/GUI/GUI_ObjectLayers.hpp       |  1 +
 src/slic3r/GUI/GUI_ObjectManipulation.cpp | 14 --------
 src/slic3r/GUI/wxExtensions.cpp           | 29 ++++++++++++----
 4 files changed, 65 insertions(+), 20 deletions(-)

diff --git a/src/slic3r/GUI/GUI_ObjectLayers.cpp b/src/slic3r/GUI/GUI_ObjectLayers.cpp
index 822b137c3..9053cdd42 100644
--- a/src/slic3r/GUI/GUI_ObjectLayers.cpp
+++ b/src/slic3r/GUI/GUI_ObjectLayers.cpp
@@ -227,6 +227,42 @@ void ObjectLayers::msw_rescale()
 {
     m_bmp_delete.msw_rescale();
     m_bmp_add.msw_rescale();
+
+    m_grid_sizer->SetHGap(wxGetApp().em_unit());
+
+    // rescale edit-boxes
+    const int cells_cnt = m_grid_sizer->GetCols() * m_grid_sizer->GetEffectiveRowsCount();
+    for (int i = 0; i < cells_cnt; i++)
+    {
+        const wxSizerItem* item = m_grid_sizer->GetItem(i);
+        if (item->IsWindow())
+        {
+            LayerRangeEditor* editor = dynamic_cast<LayerRangeEditor*>(item->GetWindow());
+            if (editor != nullptr)
+                editor->msw_rescale();
+        }
+        else if (item->IsSizer()) // case when we have editor with buttons
+        {
+            wxSizerItem* e_item = item->GetSizer()->GetItem(size_t(0)); // editor
+            if (e_item->IsWindow()) {
+                LayerRangeEditor* editor = dynamic_cast<LayerRangeEditor*>(e_item->GetWindow());
+                if (editor != nullptr)
+                    editor->msw_rescale();
+            }
+
+            const std::vector<size_t> btns = {2, 3};  // del_btn, add_btn
+            for (auto btn : btns)
+            {
+                wxSizerItem* b_item = item->GetSizer()->GetItem(btn);
+                if (b_item->IsWindow()) {
+                    ScalableButton* button = dynamic_cast<ScalableButton*>(b_item->GetWindow());
+                    if (button != nullptr)
+                        button->msw_rescale();
+                }                
+            }
+        }
+    }
+    m_grid_sizer->Layout();
 }
 
 void ObjectLayers::reset_selection()
@@ -342,5 +378,10 @@ coordf_t LayerRangeEditor::get_value()
     return layer_height;
 }
 
+void LayerRangeEditor::msw_rescale()
+{
+    SetMinSize(wxSize(8 * wxGetApp().em_unit(), wxDefaultCoord));
+}
+
 } //namespace GUI
 } //namespace Slic3r 
\ No newline at end of file
diff --git a/src/slic3r/GUI/GUI_ObjectLayers.hpp b/src/slic3r/GUI/GUI_ObjectLayers.hpp
index f274183e2..c0de3be4c 100644
--- a/src/slic3r/GUI/GUI_ObjectLayers.hpp
+++ b/src/slic3r/GUI/GUI_ObjectLayers.hpp
@@ -49,6 +49,7 @@ public:
 
     EditorType          type() const {return m_type;}
     void                set_focus_data() const { m_set_focus_data(m_type);}
+    void                msw_rescale();
 
 private:
     coordf_t            get_value();
diff --git a/src/slic3r/GUI/GUI_ObjectManipulation.cpp b/src/slic3r/GUI/GUI_ObjectManipulation.cpp
index 695c81b5f..2295ac0b6 100644
--- a/src/slic3r/GUI/GUI_ObjectManipulation.cpp
+++ b/src/slic3r/GUI/GUI_ObjectManipulation.cpp
@@ -104,8 +104,6 @@ void msw_rescale_word_local_combo(wxBitmapComboBox* combo)
     
     combo->Append(_(L("World coordinates")));
     combo->Append(_(L("Local coordinates")));
-//     combo->SetSelection(0);
-//     combo->SetValue(combo->GetString(0));
 
     wxBitmap empty_bmp(1, combo->GetFont().GetPixelSize().y + 2);
     empty_bmp.SetWidth(0);
@@ -141,20 +139,10 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent) :
 
     ConfigOptionDef def;
 
-    // Objects(sub-objects) name
-//     def.label = L("Name");
-//     def.gui_type = "legend";
-//     def.tooltip = L("Object name");
-//     def.width = 21 * wxGetApp().em_unit();
-//     def.default_value = new ConfigOptionString{ " " };
-//     m_og->append_single_option_line(Option(def, "object_name"));
-
     Line line = Line{ "Name", "Object name" };
 
     auto manifold_warning_icon = [this](wxWindow* parent) {
         m_fix_throught_netfab_bitmap = new wxStaticBitmap(parent, wxID_ANY, wxNullBitmap);
-//         auto sizer = new wxBoxSizer(wxHORIZONTAL);
-//         sizer->Add(m_fix_throught_netfab_bitmap);
 
         if (is_windows10())
             m_fix_throught_netfab_bitmap->Bind(wxEVT_CONTEXT_MENU, [this](wxCommandEvent &e)
@@ -167,11 +155,9 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent) :
                 update_warning_icon_state(wxGetApp().obj_list()->get_mesh_errors_list());
             });
 
-//         return sizer;
         return m_fix_throught_netfab_bitmap;
     };
 
- //   line.append_widget(manifold_warning_icon);
     line.near_label_widget = manifold_warning_icon;
     def.label = "";
     def.gui_type = "legend";
diff --git a/src/slic3r/GUI/wxExtensions.cpp b/src/slic3r/GUI/wxExtensions.cpp
index 5f1e779d6..bf5500cf4 100644
--- a/src/slic3r/GUI/wxExtensions.cpp
+++ b/src/slic3r/GUI/wxExtensions.cpp
@@ -460,6 +460,9 @@ void ObjectDataViewModelNode::init_container()
 #endif  //__WXGTK__
 }
 
+#define LAYER_ROOT_ICON "edit_layers_all"
+#define LAYER_ICON      "edit_layers_some"
+
 ObjectDataViewModelNode::ObjectDataViewModelNode(ObjectDataViewModelNode* parent, const ItemType type) :
     m_parent(parent),
     m_type(type),
@@ -478,7 +481,7 @@ ObjectDataViewModelNode::ObjectDataViewModelNode(ObjectDataViewModelNode* parent
     }
     else if (type == itLayerRoot)
     {
-        m_bmp = create_scaled_bitmap(nullptr, "edit_layers_all");    // FIXME: pass window ptr
+        m_bmp = create_scaled_bitmap(nullptr, LAYER_ROOT_ICON);    // FIXME: pass window ptr
         m_name = _(L("Layers"));
     }
 
@@ -507,7 +510,7 @@ ObjectDataViewModelNode::ObjectDataViewModelNode(ObjectDataViewModelNode* parent
     }
     const std::string label_range = (boost::format(" %.2f-%.2f ") % layer_range.first % layer_range.second).str();
     m_name = _(L("Range")) + label_range + "(" + _(L("mm")) + ")";
-    m_bmp = create_scaled_bitmap(nullptr, "edit_layers_some");    // FIXME: pass window ptr
+    m_bmp = create_scaled_bitmap(nullptr, LAYER_ICON);    // FIXME: pass window ptr
 
     set_action_icon();
     init_container();
@@ -581,6 +584,9 @@ void ObjectDataViewModelNode::msw_rescale()
     if (!m_action_icon_name.empty())
         m_action_icon = create_scaled_bitmap(nullptr, m_action_icon_name);
 
+    if (m_printable != piUndef)
+        m_printable_icon = create_scaled_bitmap(nullptr, m_printable == piPrintable ? "eye_open.png" : "eye_closed.png");
+
     if (!m_opt_categories.empty())
         update_settings_digest_bitmaps();
 }
@@ -1766,11 +1772,22 @@ void ObjectDataViewModel::Rescale()
         ObjectDataViewModelNode *node = (ObjectDataViewModelNode*)item.GetID();
         node->msw_rescale();
 
-        if (node->m_type & itVolume)
+        switch (node->m_type)
+        {
+        case itObject:
+            if (node->m_bmp.IsOk()) node->m_bmp = *m_warning_bmp;
+            break;
+        case itVolume:
             node->m_bmp = GetVolumeIcon(node->m_volume_type, node->m_bmp.GetWidth() != node->m_bmp.GetHeight());
-
-        if (node->m_type & itObject && node->m_bmp.IsOk())
-            node->m_bmp = *m_warning_bmp;
+            break;
+        case itLayerRoot:
+            node->m_bmp = create_scaled_bitmap(nullptr, LAYER_ROOT_ICON);    // FIXME: pass window ptr
+            break;
+        case itLayer:
+            node->m_bmp = create_scaled_bitmap(nullptr, LAYER_ICON);    // FIXME: pass window ptr
+            break;
+        default: break;
+        }
 
         ItemChanged(item);
     }

From b6292247e88c7ace1a7c406c0d560e954a448373 Mon Sep 17 00:00:00 2001
From: Lukas Matena <lukasmatena@seznam.cz>
Date: Tue, 17 Sep 2019 09:17:53 +0200
Subject: [PATCH 03/11] Unproject on mesh in the SLA gizmo is now performed by
 the MeshRaycaster class

---
 src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp | 60 ++++---------
 src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp |  3 +
 src/slic3r/GUI/MeshUtils.cpp                 | 92 ++++++++++++++++++++
 src/slic3r/GUI/MeshUtils.hpp                 | 24 +++++
 4 files changed, 137 insertions(+), 42 deletions(-)

diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp
index 80afb29b1..ee98ffc84 100644
--- a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp
+++ b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp
@@ -368,10 +368,14 @@ void GLGizmoSlaSupports::update_mesh()
     // If this is different mesh than last time or if the AABB tree is uninitialized, recalculate it.
     if (m_model_object_id != m_model_object->id() || (m_AABB.m_left == NULL && m_AABB.m_right == NULL))
     {
+        //############################šš
         m_AABB.deinit();
         m_AABB.init(
             MapMatrixXfUnaligned(m_its->vertices.front().data(), m_its->vertices.size(), 3),
             MapMatrixXiUnaligned(m_its->indices.front().data(), m_its->indices.size(), 3));
+        //############################šš
+
+        m_mesh_raycaster.reset(new MeshRaycaster(*m_mesh));
     }
 
     m_model_object_id = m_model_object->id();
@@ -389,51 +393,22 @@ bool GLGizmoSlaSupports::unproject_on_mesh(const Vec2d& mouse_pos, std::pair<Vec
         update_mesh();
 
     const Camera& camera = m_parent.get_camera();
-    const std::array<int, 4>& viewport = camera.get_viewport();
-    const Transform3d& modelview_matrix = camera.get_view_matrix();
-    const Transform3d& projection_matrix = camera.get_projection_matrix();
-
-    Vec3d point1;
-    Vec3d point2;
-    ::gluUnProject(mouse_pos(0), viewport[3] - mouse_pos(1), 0.f, modelview_matrix.data(), projection_matrix.data(), viewport.data(), &point1(0), &point1(1), &point1(2));
-    ::gluUnProject(mouse_pos(0), viewport[3] - mouse_pos(1), 1.f, modelview_matrix.data(), projection_matrix.data(), viewport.data(), &point2(0), &point2(1), &point2(2));
-
-    std::vector<igl::Hit> hits;
-
     const Selection& selection = m_parent.get_selection();
     const GLVolume* volume = selection.get_volume(*selection.get_volume_idxs().begin());
+    Geometry::Transformation trafo = volume->get_instance_transformation();
+    trafo.set_offset(trafo.get_offset() + Vec3d(0., 0., m_z_shift));
 
-    point1(2) -= m_z_shift;
-	point2(2) -= m_z_shift;
+    // The raycaster query
+    std::vector<Vec3f> hits;
+    std::vector<Vec3f> normals;
+    m_mesh_raycaster->unproject_on_mesh(mouse_pos, trafo.get_matrix(), camera, &hits, &normals);
 
-    Transform3d inv = volume->get_instance_transformation().get_matrix().inverse();
-
-    point1 = inv * point1;
-    point2 = inv * point2;
-
-    if (!m_AABB.intersect_ray(
-        MapMatrixXfUnaligned(m_its->vertices.front().data(), m_its->vertices.size(), 3),
-        MapMatrixXiUnaligned(m_its->indices.front().data(), m_its->indices.size(), 3),
-        point1.cast<float>(), (point2-point1).cast<float>(), hits))
-        return false; // no intersection found
-
-    std::sort(hits.begin(), hits.end(), [](const igl::Hit& a, const igl::Hit& b) { return a.t < b.t; });
-
-    // Now let's iterate through the points and find the first that is not clipped:
-    unsigned int i=0;
-    Vec3f bc;
-    Vec3f a;
-    Vec3f b;
-    Vec3f result;
-    for (i=0; i<hits.size(); ++i) {
-        igl::Hit& hit = hits[i];
-        int fid = hit.id;   // facet id
-        bc = Vec3f(1-hit.u-hit.v, hit.u, hit.v); // barycentric coordinates of the hit
-        a = (m_its->vertices[m_its->indices[fid](1)] - m_its->vertices[m_its->indices[fid](0)]);
-        b = (m_its->vertices[m_its->indices[fid](2)] - m_its->vertices[m_its->indices[fid](0)]);
-        result = bc(0) * m_its->vertices[m_its->indices[fid](0)] + bc(1) * m_its->vertices[m_its->indices[fid](1)] + bc(2)*m_its->vertices[m_its->indices[fid](2)];
-        if (m_clipping_plane_distance == 0.f || !is_point_clipped(result.cast<double>()))
-            break;
+    // We must also take care of the clipping plane (if active)
+    unsigned i = 0;
+    if (m_clipping_plane_distance != 0.f) {
+        for (i=0; i<hits.size(); ++i)
+            if (! is_point_clipped(hits[i].cast<double>()))
+                break;
     }
 
     if (i==hits.size() || (hits.size()-i) % 2 != 0) {
@@ -443,7 +418,7 @@ bool GLGizmoSlaSupports::unproject_on_mesh(const Vec2d& mouse_pos, std::pair<Vec
     }
 
     // Calculate and return both the point and the facet normal.
-    pos_and_normal = std::make_pair(result, a.cross(b));
+    pos_and_normal = std::make_pair(hits[i], normals[i]);
     return true;
 }
 
@@ -1105,6 +1080,7 @@ void GLGizmoSlaSupports::on_set_state()
             m_its = nullptr;
             m_object_clipper.reset();
             m_supports_clipper.reset();
+            m_mesh_raycaster.reset();
         }
     }
     m_old_state = m_state;
diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp
index 7bef33e1b..8a55f65d1 100644
--- a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp
+++ b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp
@@ -20,6 +20,7 @@ namespace GUI {
 
 class ClippingPlane;
 class MeshClipper;
+class MeshRaycaster;
 enum class SLAGizmoEventType : unsigned char;
 
 class GLGizmoSlaSupports : public GLGizmoBase
@@ -38,6 +39,8 @@ private:
     typedef Eigen::Map<const Eigen::Matrix<float, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor | Eigen::DontAlign>> MapMatrixXfUnaligned;
     typedef Eigen::Map<const Eigen::Matrix<int, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor | Eigen::DontAlign>> MapMatrixXiUnaligned;
     igl::AABB<MapMatrixXfUnaligned, 3> m_AABB;
+
+    std::unique_ptr<MeshRaycaster> m_mesh_raycaster;
     const TriangleMesh* m_mesh;
     const indexed_triangle_set* m_its;
     mutable const TriangleMesh* m_supports_mesh;
diff --git a/src/slic3r/GUI/MeshUtils.cpp b/src/slic3r/GUI/MeshUtils.cpp
index 9542f0b1f..e6af61621 100644
--- a/src/slic3r/GUI/MeshUtils.cpp
+++ b/src/slic3r/GUI/MeshUtils.cpp
@@ -3,6 +3,15 @@
 #include "libslic3r/Tesselate.hpp"
 #include "libslic3r/TriangleMesh.hpp"
 
+#include "slic3r/GUI/Camera.hpp"
+
+// There is an L function in igl that would be overridden by our localization macro.
+#undef L
+#include <igl/AABB.h>
+
+#include <GL/glew.h>
+
+
 namespace Slic3r {
 namespace GUI {
 
@@ -90,6 +99,89 @@ void MeshClipper::recalculate_triangles()
 }
 
 
+class MeshRaycaster::AABBWrapper {
+public:
+    AABBWrapper(const TriangleMesh* mesh);
+    ~AABBWrapper() { m_AABB.deinit(); }
+
+    typedef Eigen::Map<const Eigen::Matrix<float, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor | Eigen::DontAlign>> MapMatrixXfUnaligned;
+    typedef Eigen::Map<const Eigen::Matrix<int, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor | Eigen::DontAlign>> MapMatrixXiUnaligned;
+    igl::AABB<MapMatrixXfUnaligned, 3> m_AABB;
+
+};
+
+MeshRaycaster::AABBWrapper::AABBWrapper(const TriangleMesh* mesh)
+{
+    const indexed_triangle_set* its = &mesh->its;
+    m_AABB.init(
+        MapMatrixXfUnaligned(its->vertices.front().data(), its->vertices.size(), 3),
+        MapMatrixXiUnaligned(its->indices.front().data(), its->indices.size(), 3));
+}
+
+
+MeshRaycaster::MeshRaycaster(const TriangleMesh& mesh)
+    : m_AABB_wrapper(new AABBWrapper(&mesh)), m_mesh(&mesh)
+{
+}
+
+MeshRaycaster::~MeshRaycaster()
+{
+    delete m_AABB_wrapper;
+}
+
+
+bool MeshRaycaster::unproject_on_mesh(const Vec2d& mouse_pos, const Transform3d& trafo,
+                                      const Camera& camera, std::vector<Vec3f>* positions, std::vector<Vec3f>* normals) const
+{
+    const std::array<int, 4>& viewport = camera.get_viewport();
+    const Transform3d& model_mat = camera.get_view_matrix();
+    const Transform3d& proj_mat = camera.get_projection_matrix();
+
+    Vec3d pt1;
+    Vec3d pt2;
+    ::gluUnProject(mouse_pos(0), viewport[3] - mouse_pos(1), 0.f, model_mat.data(), proj_mat.data(), viewport.data(), &pt1(0), &pt1(1), &pt1(2));
+    ::gluUnProject(mouse_pos(0), viewport[3] - mouse_pos(1), 1.f, model_mat.data(), proj_mat.data(), viewport.data(), &pt2(0), &pt2(1), &pt2(2));
+
+    std::vector<igl::Hit> hits;
+
+    Transform3d inv = trafo.inverse();
+
+    pt1 = inv * pt1;
+    pt2 = inv * pt2;
+
+    if (! m_AABB_wrapper->m_AABB.intersect_ray(
+        AABBWrapper::MapMatrixXfUnaligned(m_mesh->its.vertices.front().data(), m_mesh->its.vertices.size(), 3),
+        AABBWrapper::MapMatrixXiUnaligned(m_mesh->its.indices.front().data(), m_mesh->its.indices.size(), 3),
+        pt1.cast<float>(), (pt2-pt1).cast<float>(), hits))
+        return false; // no intersection found
+
+    std::sort(hits.begin(), hits.end(), [](const igl::Hit& a, const igl::Hit& b) { return a.t < b.t; });
+
+    // Now stuff the points in the provided vector and calculate normals if asked about them:
+    if (positions != nullptr) {
+        positions->clear();
+        if (normals != nullptr)
+            normals->clear();
+        Vec3f bc;
+        Vec3f a;
+        Vec3f b;
+        int fid = 0;
+        for (const igl::Hit& hit : hits) {
+            fid = hit.id;
+            bc = Vec3f(1-hit.u-hit.v, hit.u, hit.v); // barycentric coordinates of the hit
+            a = (m_mesh->its.vertices[m_mesh->its.indices[fid](1)] - m_mesh->its.vertices[m_mesh->its.indices[fid](0)]);
+            b = (m_mesh->its.vertices[m_mesh->its.indices[fid](2)] - m_mesh->its.vertices[m_mesh->its.indices[fid](0)]);
+            positions->push_back(bc(0) * m_mesh->its.vertices[m_mesh->its.indices[fid](0)] + bc(1) * m_mesh->its.vertices[m_mesh->its.indices[fid](1)] + bc(2) * m_mesh->its.vertices[m_mesh->its.indices[fid](2)]);
+
+            if (normals != nullptr)
+                normals->push_back(a.cross(b));
+        }
+    }
+
+    return true;
+}
+
+
 
 } // namespace GUI
 } // namespace Slic3r
diff --git a/src/slic3r/GUI/MeshUtils.hpp b/src/slic3r/GUI/MeshUtils.hpp
index f97003a91..cadc821dd 100644
--- a/src/slic3r/GUI/MeshUtils.hpp
+++ b/src/slic3r/GUI/MeshUtils.hpp
@@ -14,6 +14,8 @@ class TriangleMeshSlicer;
 
 namespace GUI {
 
+class Camera;
+
 
 
 class ClippingPlane
@@ -86,6 +88,28 @@ private:
 };
 
 
+
+
+class MeshRaycaster {
+public:
+    MeshRaycaster(const TriangleMesh& mesh);
+    ~MeshRaycaster();
+    void set_transformation(const Geometry::Transformation& trafo);
+    void set_camera(const Camera& camera);
+
+    bool unproject_on_mesh(const Vec2d& mouse_pos, const Transform3d& trafo, const Camera& camera,
+                           std::vector<Vec3f>* positions = nullptr, std::vector<Vec3f>* normals = nullptr) const;
+
+private:
+    // PIMPL wrapper around igl::AABB so I don't have to include the header-only IGL here
+    class AABBWrapper;
+    AABBWrapper* m_AABB_wrapper;
+
+    const TriangleMesh* m_mesh = nullptr;
+
+
+};
+
     
 } // namespace GUI
 } // namespace Slic3r

From 3694bf3da97fbbcbabe0ec15607eda8236a8ca39 Mon Sep 17 00:00:00 2001
From: Lukas Matena <lukasmatena@seznam.cz>
Date: Tue, 17 Sep 2019 10:47:01 +0200
Subject: [PATCH 04/11] Added functions get_hit_pos, get_hit_normal, ready to
 implement intersect_ray

---
 src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp |  2 +-
 src/slic3r/GUI/MeshUtils.cpp                 | 52 ++++++++++++++------
 src/slic3r/GUI/MeshUtils.hpp                 |  6 +--
 3 files changed, 41 insertions(+), 19 deletions(-)

diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp
index ee98ffc84..04ad8a460 100644
--- a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp
+++ b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp
@@ -503,7 +503,7 @@ bool GLGizmoSlaSupports::gizmo_event(SLAGizmoEventType action, const Vec2d& mous
             // clipping plane nor obscured by the mesh.
             for (const unsigned int i : selected_idxs) {
                 const sla::SupportPoint &support_point = m_editing_cache[i].support_point;
-                if (!is_point_clipped(support_point.pos.cast<double>())) {
+                if (! is_point_clipped(support_point.pos.cast<double>())) {
                     bool is_obscured = false;
                     // Cast a ray in the direction of the camera and look for intersection with the mesh:
                     std::vector<igl::Hit> hits;
diff --git a/src/slic3r/GUI/MeshUtils.cpp b/src/slic3r/GUI/MeshUtils.cpp
index e6af61621..26697acc5 100644
--- a/src/slic3r/GUI/MeshUtils.cpp
+++ b/src/slic3r/GUI/MeshUtils.cpp
@@ -108,14 +108,19 @@ public:
     typedef Eigen::Map<const Eigen::Matrix<int, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor | Eigen::DontAlign>> MapMatrixXiUnaligned;
     igl::AABB<MapMatrixXfUnaligned, 3> m_AABB;
 
+    Vec3f get_hit_pos(const igl::Hit& hit) const;
+    Vec3f get_hit_normal(const igl::Hit& hit) const;
+
+private:
+    const TriangleMesh* m_mesh;
 };
 
 MeshRaycaster::AABBWrapper::AABBWrapper(const TriangleMesh* mesh)
+    : m_mesh(mesh)
 {
-    const indexed_triangle_set* its = &mesh->its;
     m_AABB.init(
-        MapMatrixXfUnaligned(its->vertices.front().data(), its->vertices.size(), 3),
-        MapMatrixXiUnaligned(its->indices.front().data(), its->indices.size(), 3));
+        MapMatrixXfUnaligned(m_mesh->its.vertices.front().data(), m_mesh->its.vertices.size(), 3),
+        MapMatrixXiUnaligned(m_mesh->its.indices.front().data(), m_mesh->its.indices.size(), 3));
 }
 
 
@@ -129,6 +134,23 @@ MeshRaycaster::~MeshRaycaster()
     delete m_AABB_wrapper;
 }
 
+Vec3f MeshRaycaster::AABBWrapper::get_hit_pos(const igl::Hit& hit) const
+{
+    const stl_triangle_vertex_indices& indices = m_mesh->its.indices[hit.id];
+    return Vec3f((1-hit.u-hit.v) * m_mesh->its.vertices[indices(0)]
+               + hit.u           * m_mesh->its.vertices[indices(1)]
+               + hit.v           * m_mesh->its.vertices[indices(2)]);
+}
+
+
+Vec3f MeshRaycaster::AABBWrapper::get_hit_normal(const igl::Hit& hit) const
+{
+    const stl_triangle_vertex_indices& indices = m_mesh->its.indices[hit.id];
+    Vec3f a(m_mesh->its.vertices[indices(1)] - m_mesh->its.vertices[indices(0)]);
+    Vec3f b(m_mesh->its.vertices[indices(2)] - m_mesh->its.vertices[indices(0)]);
+    return Vec3f(a.cross(b));
+}
+
 
 bool MeshRaycaster::unproject_on_mesh(const Vec2d& mouse_pos, const Transform3d& trafo,
                                       const Camera& camera, std::vector<Vec3f>* positions, std::vector<Vec3f>* normals) const
@@ -139,8 +161,8 @@ bool MeshRaycaster::unproject_on_mesh(const Vec2d& mouse_pos, const Transform3d&
 
     Vec3d pt1;
     Vec3d pt2;
-    ::gluUnProject(mouse_pos(0), viewport[3] - mouse_pos(1), 0.f, model_mat.data(), proj_mat.data(), viewport.data(), &pt1(0), &pt1(1), &pt1(2));
-    ::gluUnProject(mouse_pos(0), viewport[3] - mouse_pos(1), 1.f, model_mat.data(), proj_mat.data(), viewport.data(), &pt2(0), &pt2(1), &pt2(2));
+    ::gluUnProject(mouse_pos(0), viewport[3] - mouse_pos(1), 0., model_mat.data(), proj_mat.data(), viewport.data(), &pt1(0), &pt1(1), &pt1(2));
+    ::gluUnProject(mouse_pos(0), viewport[3] - mouse_pos(1), 1., model_mat.data(), proj_mat.data(), viewport.data(), &pt2(0), &pt2(1), &pt2(2));
 
     std::vector<igl::Hit> hits;
 
@@ -162,19 +184,11 @@ bool MeshRaycaster::unproject_on_mesh(const Vec2d& mouse_pos, const Transform3d&
         positions->clear();
         if (normals != nullptr)
             normals->clear();
-        Vec3f bc;
-        Vec3f a;
-        Vec3f b;
-        int fid = 0;
         for (const igl::Hit& hit : hits) {
-            fid = hit.id;
-            bc = Vec3f(1-hit.u-hit.v, hit.u, hit.v); // barycentric coordinates of the hit
-            a = (m_mesh->its.vertices[m_mesh->its.indices[fid](1)] - m_mesh->its.vertices[m_mesh->its.indices[fid](0)]);
-            b = (m_mesh->its.vertices[m_mesh->its.indices[fid](2)] - m_mesh->its.vertices[m_mesh->its.indices[fid](0)]);
-            positions->push_back(bc(0) * m_mesh->its.vertices[m_mesh->its.indices[fid](0)] + bc(1) * m_mesh->its.vertices[m_mesh->its.indices[fid](1)] + bc(2) * m_mesh->its.vertices[m_mesh->its.indices[fid](2)]);
+            positions->push_back(m_AABB_wrapper->get_hit_pos(hit));
 
             if (normals != nullptr)
-                normals->push_back(a.cross(b));
+                normals->push_back(m_AABB_wrapper->get_hit_normal(hit));
         }
     }
 
@@ -182,6 +196,14 @@ bool MeshRaycaster::unproject_on_mesh(const Vec2d& mouse_pos, const Transform3d&
 }
 
 
+std::vector<size_t> MeshRaycaster::get_unobscured_idxs(const Transform3d& trafo, const Camera& camera, const std::vector<Vec3f>& points) const
+{
+
+
+    return std::vector<size_t>();
+}
+
+
 
 } // namespace GUI
 } // namespace Slic3r
diff --git a/src/slic3r/GUI/MeshUtils.hpp b/src/slic3r/GUI/MeshUtils.hpp
index cadc821dd..5c11053ab 100644
--- a/src/slic3r/GUI/MeshUtils.hpp
+++ b/src/slic3r/GUI/MeshUtils.hpp
@@ -100,14 +100,14 @@ public:
     bool unproject_on_mesh(const Vec2d& mouse_pos, const Transform3d& trafo, const Camera& camera,
                            std::vector<Vec3f>* positions = nullptr, std::vector<Vec3f>* normals = nullptr) const;
 
+    std::vector<size_t> get_unobscured_idxs(const Transform3d& trafo, const Camera& camera,
+                                            const std::vector<Vec3f>& points) const;
+
 private:
     // PIMPL wrapper around igl::AABB so I don't have to include the header-only IGL here
     class AABBWrapper;
     AABBWrapper* m_AABB_wrapper;
-
     const TriangleMesh* m_mesh = nullptr;
-
-
 };
 
     

From 1dfd8a0e621fc5ea3731d0fd407ba121f550ebf7 Mon Sep 17 00:00:00 2001
From: Lukas Matena <lukasmatena@seznam.cz>
Date: Tue, 17 Sep 2019 14:14:26 +0200
Subject: [PATCH 05/11] MeshRaycaster class is now used in SLA gizmo when
 selecting by rectangle

---
 src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp | 84 +++++---------------
 src/slic3r/GUI/MeshUtils.cpp                 | 45 ++++++++++-
 src/slic3r/GUI/MeshUtils.hpp                 |  4 +-
 3 files changed, 63 insertions(+), 70 deletions(-)

diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp
index 04ad8a460..f15bc806b 100644
--- a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp
+++ b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp
@@ -479,76 +479,28 @@ bool GLGizmoSlaSupports::gizmo_event(SLAGizmoEventType action, const Vec2d& mous
             GLSelectionRectangle::EState rectangle_status = m_selection_rectangle.get_state();
 
             // First collect positions of all the points in world coordinates.
-            const Transform3d& instance_matrix = m_model_object->instances[m_active_instance]->get_transformation().get_matrix();
+            Geometry::Transformation trafo = m_model_object->instances[m_active_instance]->get_transformation();
+            trafo.set_offset(trafo.get_offset() + Vec3d(0., 0., m_z_shift));
             std::vector<Vec3d> points;
-            for (unsigned int i=0; i<m_editing_cache.size(); ++i) {
-                const sla::SupportPoint &support_point = m_editing_cache[i].support_point;
-                points.push_back(instance_matrix * support_point.pos.cast<double>());
-                points.back()(2) += m_z_shift;
-            }
+            for (unsigned int i=0; i<m_editing_cache.size(); ++i)
+                points.push_back(trafo.get_matrix() * m_editing_cache[i].support_point.pos.cast<double>());
+
             // Now ask the rectangle which of the points are inside.
-            const Camera& camera = m_parent.get_camera();
-            std::vector<unsigned int> selected_idxs = m_selection_rectangle.stop_dragging(m_parent, points);
+            std::vector<Vec3f> points_inside;
+            std::vector<unsigned int> points_idxs = m_selection_rectangle.stop_dragging(m_parent, points);
+            for (size_t idx : points_idxs)
+                points_inside.push_back((trafo.get_matrix() * points[idx]).cast<float>());
 
-            // we'll recover current look direction (in world coords) and transform it to model coords.
-            const Selection& selection = m_parent.get_selection();
-            const GLVolume* volume = selection.get_volume(*selection.get_volume_idxs().begin());
-            const Transform3d& instance_matrix_no_translation_no_scaling = volume->get_instance_transformation().get_matrix(true,false,true);
-            Vec3f direction_to_camera = -camera.get_dir_forward().cast<float>();
-            Vec3f direction_to_camera_mesh = (instance_matrix_no_translation_no_scaling.inverse().cast<float>() * direction_to_camera).normalized().eval();
-            Vec3f scaling = volume->get_instance_scaling_factor().cast<float>();
-            direction_to_camera_mesh = Vec3f(direction_to_camera_mesh(0)*scaling(0), direction_to_camera_mesh(1)*scaling(1), direction_to_camera_mesh(2)*scaling(2));
-
-            // Iterate over all points in the rectangle and check that they are neither clipped by the
-            // clipping plane nor obscured by the mesh.
-            for (const unsigned int i : selected_idxs) {
-                const sla::SupportPoint &support_point = m_editing_cache[i].support_point;
+            // Only select/deselect points that are actually visible
+            for (size_t idx :  m_mesh_raycaster->get_unobscured_idxs(trafo, m_parent.get_camera(), points_inside,
+                          [this](const Vec3f& pt) { return is_point_clipped(pt.cast<double>()); }))
+            {
+                const sla::SupportPoint &support_point = m_editing_cache[points_idxs[idx]].support_point;
                 if (! is_point_clipped(support_point.pos.cast<double>())) {
-                    bool is_obscured = false;
-                    // Cast a ray in the direction of the camera and look for intersection with the mesh:
-                    std::vector<igl::Hit> hits;
-                    // Offset the start of the ray to the front of the ball + EPSILON to account for numerical inaccuracies.
-                    if (m_AABB.intersect_ray(
-                            MapMatrixXfUnaligned(m_its->vertices.front().data(), m_its->vertices.size(), 3),
-                            MapMatrixXiUnaligned(m_its->indices.front().data(), m_its->indices.size(), 3),
-                            support_point.pos + direction_to_camera_mesh * (support_point.head_front_radius + EPSILON), direction_to_camera_mesh, hits)) {
-                        std::sort(hits.begin(), hits.end(), [](const igl::Hit& h1, const igl::Hit& h2) { return h1.t < h2.t; });
-
-                        if (m_clipping_plane_distance != 0.f) {
-                            // If the closest hit facet normal points in the same direction as the ray,
-                            // we are looking through the mesh and should therefore discard the point:
-                            int fid = hits.front().id;   // facet id
-                            Vec3f a = (m_its->vertices[m_its->indices[fid](1)] - m_its->vertices[m_its->indices[fid](0)]);
-                            Vec3f b = (m_its->vertices[m_its->indices[fid](2)] - m_its->vertices[m_its->indices[fid](0)]);
-                            if ((a.cross(b)).dot(direction_to_camera_mesh) > 0.f)
-                                is_obscured = true;
-
-                            // Eradicate all hits that are on clipped surfaces:
-                            for (unsigned int j=0; j<hits.size(); ++j) {
-                                const igl::Hit& hit = hits[j];
-                                int fid = hit.id;   // facet id
-
-                                Vec3f bc = Vec3f(1-hit.u-hit.v, hit.u, hit.v); // barycentric coordinates of the hit
-                                Vec3f hit_pos = bc(0) * m_its->vertices[m_its->indices[fid](0)] + bc(1) * m_its->vertices[m_its->indices[fid](1)] + bc(2)*m_its->vertices[m_its->indices[fid](2)];
-                                if (is_point_clipped(hit_pos.cast<double>())) {
-                                    hits.erase(hits.begin()+j);
-                                    --j;
-                                }
-                            }
-                        }
-
-                        // FIXME: the intersection could in theory be behind the camera, but as of now we only have camera direction.
-                        // Also, the threshold is in mesh coordinates, not in actual dimensions.
-                        if (!hits.empty())
-                            is_obscured = true;
-                    }
-
-                    if (!is_obscured) {
-                        if (rectangle_status == GLSelectionRectangle::Deselect)
-                            unselect_point(i);
-                        else
-                            select_point(i);
-                    }
+                    if (rectangle_status == GLSelectionRectangle::Deselect)
+                        unselect_point(points_idxs[idx]);
+                    else
+                        select_point(points_idxs[idx]);
                 }
             }
             return true;
diff --git a/src/slic3r/GUI/MeshUtils.cpp b/src/slic3r/GUI/MeshUtils.cpp
index 26697acc5..2c0089053 100644
--- a/src/slic3r/GUI/MeshUtils.cpp
+++ b/src/slic3r/GUI/MeshUtils.cpp
@@ -196,11 +196,52 @@ bool MeshRaycaster::unproject_on_mesh(const Vec2d& mouse_pos, const Transform3d&
 }
 
 
-std::vector<size_t> MeshRaycaster::get_unobscured_idxs(const Transform3d& trafo, const Camera& camera, const std::vector<Vec3f>& points) const
+std::vector<unsigned> MeshRaycaster::get_unobscured_idxs(const Geometry::Transformation& trafo, const Camera& camera, const std::vector<Vec3f>& points,
+                                                       std::function<bool(const Vec3f&)> fn_ignore_hit) const
 {
+    std::vector<unsigned> out;
 
+    const Transform3d& instance_matrix_no_translation_no_scaling = trafo.get_matrix(true,false,true);
+    Vec3f direction_to_camera = -camera.get_dir_forward().cast<float>();
+    Vec3f direction_to_camera_mesh = (instance_matrix_no_translation_no_scaling.inverse().cast<float>() * direction_to_camera).normalized().eval();
+    Vec3f scaling = trafo.get_scaling_factor().cast<float>();
+    direction_to_camera_mesh = Vec3f(direction_to_camera_mesh(0)*scaling(0), direction_to_camera_mesh(1)*scaling(1), direction_to_camera_mesh(2)*scaling(2));
 
-    return std::vector<size_t>();
+    for (size_t i=0; i<points.size(); ++i) {
+        const Vec3f& pt = points[i];
+        bool is_obscured = false;
+        // Cast a ray in the direction of the camera and look for intersection with the mesh:
+        std::vector<igl::Hit> hits;
+        // Offset the start of the ray to the front of the ball + EPSILON to account for numerical inaccuracies.
+        if (m_AABB_wrapper->m_AABB.intersect_ray(
+                AABBWrapper::MapMatrixXfUnaligned(m_mesh->its.vertices.front().data(), m_mesh->its.vertices.size(), 3),
+                AABBWrapper::MapMatrixXiUnaligned(m_mesh->its.indices.front().data(), m_mesh->its.indices.size(), 3),
+                pt + direction_to_camera_mesh * EPSILON, direction_to_camera_mesh, hits)) {
+
+            std::sort(hits.begin(), hits.end(), [](const igl::Hit& h1, const igl::Hit& h2) { return h1.t < h2.t; });
+            // If the closest hit facet normal points in the same direction as the ray,
+            // we are looking through the mesh and should therefore discard the point:
+            if (m_AABB_wrapper->get_hit_normal(hits.front()).dot(direction_to_camera_mesh) > 0.f)
+                is_obscured = true;
+
+            // Eradicate all hits that the caller wants to ignore
+            for (unsigned j=0; j<hits.size(); ++j) {
+                const igl::Hit& hit = hits[j];
+                if (fn_ignore_hit(m_AABB_wrapper->get_hit_pos(hit))) {
+                    hits.erase(hits.begin()+j);
+                    --j;
+                }
+            }
+            // FIXME: the intersection could in theory be behind the camera, but as of now we only have camera direction.
+            // Also, the threshold is in mesh coordinates, not in actual dimensions.
+            if (! hits.empty())
+                is_obscured = true;
+        }
+        if (! is_obscured)
+            out.push_back(i);
+    }
+
+    return out;
 }
 
 
diff --git a/src/slic3r/GUI/MeshUtils.hpp b/src/slic3r/GUI/MeshUtils.hpp
index 5c11053ab..2573b4b89 100644
--- a/src/slic3r/GUI/MeshUtils.hpp
+++ b/src/slic3r/GUI/MeshUtils.hpp
@@ -100,8 +100,8 @@ public:
     bool unproject_on_mesh(const Vec2d& mouse_pos, const Transform3d& trafo, const Camera& camera,
                            std::vector<Vec3f>* positions = nullptr, std::vector<Vec3f>* normals = nullptr) const;
 
-    std::vector<size_t> get_unobscured_idxs(const Transform3d& trafo, const Camera& camera,
-                                            const std::vector<Vec3f>& points) const;
+    std::vector<unsigned> get_unobscured_idxs(const Geometry::Transformation& trafo, const Camera& camera,
+                                              const std::vector<Vec3f>& points, std::function<bool(const Vec3f&)> fn_ignore_hit) const;
 
 private:
     // PIMPL wrapper around igl::AABB so I don't have to include the header-only IGL here

From 6bcafd7c830ddfe5e8a6974f455d26279b0f0603 Mon Sep 17 00:00:00 2001
From: Lukas Matena <lukasmatena@seznam.cz>
Date: Tue, 17 Sep 2019 14:56:46 +0200
Subject: [PATCH 06/11] SLA gizmo no more uses IGL code directly, all was moved
 to the new MeshRaycaster class

---
 src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp | 36 +++-----------------
 src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp |  7 ----
 src/slic3r/GUI/MeshUtils.cpp                 | 18 +++++++++-
 src/slic3r/GUI/MeshUtils.hpp                 |  2 ++
 4 files changed, 24 insertions(+), 39 deletions(-)

diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp
index f15bc806b..992f4912a 100644
--- a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp
+++ b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp
@@ -296,8 +296,9 @@ void GLGizmoSlaSupports::render_points(const Selection& selection, bool picking)
         // Matrices set, we can render the point mark now.
         // If in editing mode, we'll also render a cone pointing to the sphere.
         if (m_editing_mode) {
+            // in case the normal is not yet cached, find and cache it
             if (m_editing_cache[i].normal == Vec3f::Zero())
-                update_cache_entry_normal(i); // in case the normal is not yet cached, find and cache it
+                m_mesh_raycaster->get_closest_point(m_editing_cache[i].support_point.pos, &m_editing_cache[i].normal);
 
             Eigen::Quaterniond q;
             q.setFromTwoVectors(Vec3d{0., 0., 1.}, instance_scaling_matrix_inverse * m_editing_cache[i].normal.cast<double>());
@@ -366,17 +367,8 @@ void GLGizmoSlaSupports::update_mesh()
     m_its = &m_mesh->its;
 
     // If this is different mesh than last time or if the AABB tree is uninitialized, recalculate it.
-    if (m_model_object_id != m_model_object->id() || (m_AABB.m_left == NULL && m_AABB.m_right == NULL))
-    {
-        //############################šš
-        m_AABB.deinit();
-        m_AABB.init(
-            MapMatrixXfUnaligned(m_its->vertices.front().data(), m_its->vertices.size(), 3),
-            MapMatrixXiUnaligned(m_its->indices.front().data(), m_its->indices.size(), 3));
-        //############################šš
-
+    if (m_model_object_id != m_model_object->id() || ! m_mesh_raycaster)
         m_mesh_raycaster.reset(new MeshRaycaster(*m_mesh));
-    }
 
     m_model_object_id = m_model_object->id();
     disable_editing_mode();
@@ -389,7 +381,7 @@ void GLGizmoSlaSupports::update_mesh()
 bool GLGizmoSlaSupports::unproject_on_mesh(const Vec2d& mouse_pos, std::pair<Vec3f, Vec3f>& pos_and_normal)
 {
     // if the gizmo doesn't have the V, F structures for igl, calculate them first:
-    if (m_its == nullptr)
+    if (! m_mesh_raycaster)
         update_mesh();
 
     const Camera& camera = m_parent.get_camera();
@@ -658,23 +650,6 @@ std::vector<const ConfigOption*> GLGizmoSlaSupports::get_config_options(const st
 }
 
 
-void GLGizmoSlaSupports::update_cache_entry_normal(size_t i) const
-{
-    int idx = 0;
-    Eigen::Matrix<float, 1, 3> pp = m_editing_cache[i].support_point.pos;
-    Eigen::Matrix<float, 1, 3> cc;
-    m_AABB.squared_distance(
-        MapMatrixXfUnaligned(m_its->vertices.front().data(), m_its->vertices.size(), 3),
-        MapMatrixXiUnaligned(m_its->indices.front().data(), m_its->indices.size(), 3),
-        pp, idx, cc);
-    Vec3f a = (m_its->vertices[m_its->indices[idx](1)] - m_its->vertices[m_its->indices[idx](0)]);
-    Vec3f b = (m_its->vertices[m_its->indices[idx](2)] - m_its->vertices[m_its->indices[idx](0)]);
-    m_editing_cache[i].normal = a.cross(b);
-}
-
-
-
-
 ClippingPlane GLGizmoSlaSupports::get_sla_clipping_plane() const
 {
     if (!m_model_object || m_state == Off || m_clipping_plane_distance == 0.f)
@@ -1027,8 +1002,7 @@ void GLGizmoSlaSupports::on_set_state()
             m_parent.toggle_model_objects_visibility(true);
             m_normal_cache.clear();
             m_clipping_plane_distance = 0.f;
-            // Release triangle mesh slicer and the AABB spatial search structure.
-            m_AABB.deinit();
+            // Release clippers and the AABB raycaster.
             m_its = nullptr;
             m_object_clipper.reset();
             m_supports_clipper.reset();
diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp
index 8a55f65d1..cf5245f19 100644
--- a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp
+++ b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp
@@ -4,11 +4,6 @@
 #include "GLGizmoBase.hpp"
 #include "slic3r/GUI/GLSelectionRectangle.hpp"
 
-// There is an L function in igl that would be overridden by our localization macro - let's undefine it...
-#undef L
-#include <igl/AABB.h>
-#include "slic3r/GUI/I18N.hpp"  // ...and redefine again when we are done with the igl code
-
 #include "libslic3r/SLA/SLACommon.hpp"
 #include <wx/dialog.h>
 
@@ -38,7 +33,6 @@ private:
     GLUquadricObj* m_quadric;
     typedef Eigen::Map<const Eigen::Matrix<float, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor | Eigen::DontAlign>> MapMatrixXfUnaligned;
     typedef Eigen::Map<const Eigen::Matrix<int, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor | Eigen::DontAlign>> MapMatrixXiUnaligned;
-    igl::AABB<MapMatrixXfUnaligned, 3> m_AABB;
 
     std::unique_ptr<MeshRaycaster> m_mesh_raycaster;
     const TriangleMesh* m_mesh;
@@ -101,7 +95,6 @@ private:
     void render_clipping_plane(const Selection& selection) const;
     bool is_mesh_update_necessary() const;
     void update_mesh();
-    void update_cache_entry_normal(size_t i) const;
     bool unsaved_changes() const;
 
     bool m_lock_unique_islands = false;
diff --git a/src/slic3r/GUI/MeshUtils.cpp b/src/slic3r/GUI/MeshUtils.cpp
index 2c0089053..e559020e9 100644
--- a/src/slic3r/GUI/MeshUtils.cpp
+++ b/src/slic3r/GUI/MeshUtils.cpp
@@ -240,11 +240,27 @@ std::vector<unsigned> MeshRaycaster::get_unobscured_idxs(const Geometry::Transfo
         if (! is_obscured)
             out.push_back(i);
     }
-
     return out;
 }
 
 
+Vec3f MeshRaycaster::get_closest_point(const Vec3f& point, Vec3f* normal) const
+{
+    int idx = 0;
+    Eigen::Matrix<float, 1, 3> closest_point;
+    m_AABB_wrapper->m_AABB.squared_distance(
+        AABBWrapper::MapMatrixXfUnaligned(m_mesh->its.vertices.front().data(), m_mesh->its.vertices.size(), 3),
+        AABBWrapper::MapMatrixXiUnaligned(m_mesh->its.indices.front().data(), m_mesh->its.indices.size(), 3),
+        point, idx, closest_point);
+    if (normal) {
+        igl::Hit imag_hit;
+        imag_hit.id = idx;
+        *normal = m_AABB_wrapper->get_hit_normal(imag_hit);
+    }
+    return closest_point;
+}
+
+
 
 } // namespace GUI
 } // namespace Slic3r
diff --git a/src/slic3r/GUI/MeshUtils.hpp b/src/slic3r/GUI/MeshUtils.hpp
index 2573b4b89..21c375e81 100644
--- a/src/slic3r/GUI/MeshUtils.hpp
+++ b/src/slic3r/GUI/MeshUtils.hpp
@@ -103,6 +103,8 @@ public:
     std::vector<unsigned> get_unobscured_idxs(const Geometry::Transformation& trafo, const Camera& camera,
                                               const std::vector<Vec3f>& points, std::function<bool(const Vec3f&)> fn_ignore_hit) const;
 
+    Vec3f get_closest_point(const Vec3f& point, Vec3f* normal = nullptr) const;
+
 private:
     // PIMPL wrapper around igl::AABB so I don't have to include the header-only IGL here
     class AABBWrapper;

From f4910cafed7d1cc28c7db0eb952dced90c66a9de Mon Sep 17 00:00:00 2001
From: Enrico Turri <enricoturri@seznam.cz>
Date: Tue, 17 Sep 2019 15:30:54 +0200
Subject: [PATCH 07/11] Fixed selection after adding a modifier by loading it
 from file

---
 src/slic3r/GUI/GUI_ObjectList.cpp | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/src/slic3r/GUI/GUI_ObjectList.cpp b/src/slic3r/GUI/GUI_ObjectList.cpp
index 51098647f..49f0f6fa2 100644
--- a/src/slic3r/GUI/GUI_ObjectList.cpp
+++ b/src/slic3r/GUI/GUI_ObjectList.cpp
@@ -1667,6 +1667,10 @@ void ObjectList::load_subobject(ModelVolumeType type)
         
     if (sel_item)
         select_item(sel_item);
+
+#ifndef __WXOSX__ //#ifdef __WXMSW__ // #ys_FIXME
+    selection_changed();
+#endif //no __WXOSX__ //__WXMSW__
 }
 
 void ObjectList::load_part( ModelObject* model_object,

From cd7895065afc839a09cc430130960b6941f6020a Mon Sep 17 00:00:00 2001
From: Enrico Turri <enricoturri@seznam.cz>
Date: Tue, 17 Sep 2019 15:48:39 +0200
Subject: [PATCH 08/11] Fixed typo

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

diff --git a/src/slic3r/GUI/MeshUtils.hpp b/src/slic3r/GUI/MeshUtils.hpp
index 21c375e81..a2be2677b 100644
--- a/src/slic3r/GUI/MeshUtils.hpp
+++ b/src/slic3r/GUI/MeshUtils.hpp
@@ -14,7 +14,7 @@ class TriangleMeshSlicer;
 
 namespace GUI {
 
-class Camera;
+struct Camera;
 
 
 

From 741e98804cf2a32172cc7989d53202c99c76feb1 Mon Sep 17 00:00:00 2001
From: Lukas Matena <lukasmatena@seznam.cz>
Date: Wed, 18 Sep 2019 11:47:19 +0200
Subject: [PATCH 09/11] Purging volumes dialog now uses filament colour in case
 extruder color is undefined

---
 src/slic3r/GUI/Plater.cpp | 11 ++++++++++-
 src/slic3r/GUI/Plater.hpp |  1 +
 2 files changed, 11 insertions(+), 1 deletion(-)

diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp
index c5aad48a9..e548ed3ba 100644
--- a/src/slic3r/GUI/Plater.cpp
+++ b/src/slic3r/GUI/Plater.cpp
@@ -522,7 +522,11 @@ FreqChangedParams::FreqChangedParams(wxWindow* parent) :
             const std::vector<double> &init_extruders = (project_config.option<ConfigOptionFloats>("wiping_volumes_extruders"))->values;
 
             const DynamicPrintConfig* config = &wxGetApp().preset_bundle->printers.get_edited_preset().config;
-            const std::vector<std::string> &extruder_colours = (config->option<ConfigOptionStrings>("extruder_colour"))->values;
+            std::vector<std::string> extruder_colours = (config->option<ConfigOptionStrings>("extruder_colour"))->values;
+            const std::vector<std::string>& filament_colours = (wxGetApp().plater()->get_plater_config()->option<ConfigOptionStrings>("filament_colour"))->values;
+            for (size_t i=0; i<extruder_colours.size(); ++i)
+                if (extruder_colours[i] == "")
+                    extruder_colours[i] = filament_colours[i];
 
             WipingDialog dlg(parent, cast<float>(init_matrix), cast<float>(init_extruders), extruder_colours);
 
@@ -4838,6 +4842,11 @@ void Plater::on_activate()
 	this->p->show_delayed_error_message();
 }
 
+const DynamicPrintConfig* Plater::get_plater_config() const
+{
+    return p->config;
+}
+
 wxString Plater::get_project_filename(const wxString& extension) const
 {
     return p->get_project_filename(extension);
diff --git a/src/slic3r/GUI/Plater.hpp b/src/slic3r/GUI/Plater.hpp
index 6b488fef1..0dc298566 100644
--- a/src/slic3r/GUI/Plater.hpp
+++ b/src/slic3r/GUI/Plater.hpp
@@ -213,6 +213,7 @@ public:
     void on_config_change(const DynamicPrintConfig &config);
     // On activating the parent window.
     void on_activate();
+    const DynamicPrintConfig* get_plater_config() const;
 
     void update_object_menu();
 

From 76a657ce5217ffb92cfa1b68e2080575186e3244 Mon Sep 17 00:00:00 2001
From: Lukas Matena <lukasmatena@seznam.cz>
Date: Wed, 18 Sep 2019 12:54:21 +0200
Subject: [PATCH 10/11] Plater.cpp - better added a range-check when selecting
 filament color in purging volumes dialog

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

diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp
index e548ed3ba..0dc7519e8 100644
--- a/src/slic3r/GUI/Plater.cpp
+++ b/src/slic3r/GUI/Plater.cpp
@@ -525,7 +525,7 @@ FreqChangedParams::FreqChangedParams(wxWindow* parent) :
             std::vector<std::string> extruder_colours = (config->option<ConfigOptionStrings>("extruder_colour"))->values;
             const std::vector<std::string>& filament_colours = (wxGetApp().plater()->get_plater_config()->option<ConfigOptionStrings>("filament_colour"))->values;
             for (size_t i=0; i<extruder_colours.size(); ++i)
-                if (extruder_colours[i] == "")
+                if (extruder_colours[i] == "" && i < filament_colours.size())
                     extruder_colours[i] = filament_colours[i];
 
             WipingDialog dlg(parent, cast<float>(init_matrix), cast<float>(init_extruders), extruder_colours);

From 94212fa2a92b5d01be5da8235f02423249dd7b2a Mon Sep 17 00:00:00 2001
From: bubnikv <bubnikv@gmail.com>
Date: Thu, 19 Sep 2019 08:56:47 +0200
Subject: [PATCH 11/11] Another fix of admesh on big endian architectures,
 fixes #2879

---
 src/admesh/stl_io.cpp | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/src/admesh/stl_io.cpp b/src/admesh/stl_io.cpp
index af9bb4f98..ddf377c78 100644
--- a/src/admesh/stl_io.cpp
+++ b/src/admesh/stl_io.cpp
@@ -151,8 +151,8 @@ bool stl_write_binary(stl_file *stl, const char *file, const char *label)
 	memcpy(buffer, &stl->stats.number_of_facets, 4);
 	stl_internal_reverse_quads(buffer, 4);
 	fwrite(buffer, 4, 1, fp);
-	for (size_t i = 0; i < stl->stats.number_of_facets; ++ i) {
-		memcpy(buffer, stl->facet_start + i, 50);
+	for (const stl_facet &facet : stl->facet_start) {
+		memcpy(buffer, &facet, 50);
 		// Convert to little endian.
 		stl_internal_reverse_quads(buffer, 48);
 		fwrite(buffer, SIZEOF_STL_FACET, 1, fp);