From 5a1e1bc10c887a3408194cd546b2a704b94d08f3 Mon Sep 17 00:00:00 2001
From: Lukas Matena <lukasmatena@seznam.cz>
Date: Wed, 19 Jun 2019 10:15:01 +0200
Subject: [PATCH 1/3] GUI_ObjectManipulation.cpp - Removed implicit capture by
 value in some of the lambdas

---
 src/slic3r/GUI/GUI_ObjectManipulation.cpp | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/src/slic3r/GUI/GUI_ObjectManipulation.cpp b/src/slic3r/GUI/GUI_ObjectManipulation.cpp
index 310000ecc..4ccaa6847 100644
--- a/src/slic3r/GUI/GUI_ObjectManipulation.cpp
+++ b/src/slic3r/GUI/GUI_ObjectManipulation.cpp
@@ -185,7 +185,7 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent) :
         unsigned int axis_idx = (axis[0] - 'x'); // 0, 1 or 2
 
         // We will add a button to toggle mirroring to each axis:
-        auto mirror_button = [=](wxWindow* parent) {
+        auto mirror_button = [this, mirror_btn_width, axis_idx, &label](wxWindow* parent) {
             wxSize btn_size(em_unit(parent) * mirror_btn_width, em_unit(parent) * mirror_btn_width);
             auto btn = new ScalableButton(parent, wxID_ANY, "mirroring_off.png", wxEmptyString, btn_size, wxDefaultPosition, wxBU_EXACTFIT | wxNO_BORDER | wxTRANSPARENT_WINDOW);
             btn->SetToolTip(wxString::Format(_(L("Toggle %s axis mirroring")), label));
@@ -195,7 +195,7 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent) :
             auto sizer = new wxBoxSizer(wxHORIZONTAL);
             sizer->Add(btn);
 
-            btn->Bind(wxEVT_BUTTON, [=](wxCommandEvent &e) {
+            btn->Bind(wxEVT_BUTTON, [this, axis_idx](wxCommandEvent &e) {
                 Axis axis = (Axis)(axis_idx + X);
                 if (m_mirror_buttons[axis_idx].second == mbHidden)
                     return;
@@ -258,13 +258,13 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent) :
                 return btn;
             };
             // Add reset scale button
-            auto reset_scale_button = [=](wxWindow* parent) {
+            auto reset_scale_button = [this](wxWindow* parent) {
                 auto btn = new ScalableButton(parent, wxID_ANY, ScalableBitmap(parent, "undo"));
                 btn->SetToolTip(_(L("Reset scale")));
                 m_reset_scale_button = btn;
                 auto sizer = new wxBoxSizer(wxHORIZONTAL);
                 sizer->Add(btn, wxBU_EXACTFIT);
-                btn->Bind(wxEVT_BUTTON, [=](wxCommandEvent &e) {
+                btn->Bind(wxEVT_BUTTON, [this](wxCommandEvent &e) {
                     change_scale_value(0, 100.);
                     change_scale_value(1, 100.);
                     change_scale_value(2, 100.);
@@ -275,13 +275,13 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent) :
         }
         else if (option_name == "Rotation") {
             // Add reset rotation button
-            auto reset_rotation_button = [=](wxWindow* parent) {
+            auto reset_rotation_button = [this](wxWindow* parent) {
                 auto btn = new ScalableButton(parent, wxID_ANY, ScalableBitmap(parent, "undo"));
                 btn->SetToolTip(_(L("Reset rotation")));
                 m_reset_rotation_button = btn;
                 auto sizer = new wxBoxSizer(wxHORIZONTAL);
                 sizer->Add(btn, wxBU_EXACTFIT);
-                btn->Bind(wxEVT_BUTTON, [=](wxCommandEvent &e) {
+                btn->Bind(wxEVT_BUTTON, [this](wxCommandEvent &e) {
                     GLCanvas3D* canvas = wxGetApp().plater()->canvas3D();
                     Selection& selection = canvas->get_selection();
 

From 3d8c3804fab810568adedce76836ea97e7e1c71d Mon Sep 17 00:00:00 2001
From: Lukas Matena <lukasmatena@seznam.cz>
Date: Wed, 19 Jun 2019 10:46:42 +0200
Subject: [PATCH 2/3] Added 'drop to bed' button into object manipulation panel

---
 resources/icons/drop_to_bed.png           | Bin 0 -> 528 bytes
 src/slic3r/GUI/3DScene.hpp                |   2 +
 src/slic3r/GUI/GUI_ObjectManipulation.cpp |  57 +++++++++++++++++++++-
 src/slic3r/GUI/GUI_ObjectManipulation.hpp |   1 +
 4 files changed, 59 insertions(+), 1 deletion(-)
 create mode 100644 resources/icons/drop_to_bed.png

diff --git a/resources/icons/drop_to_bed.png b/resources/icons/drop_to_bed.png
new file mode 100644
index 0000000000000000000000000000000000000000..b60e1b137d9d12a1cfc177de1d51eb7c7093aa7b
GIT binary patch
literal 528
zcmV+r0`L8aP)<h;3K|Lk000e1NJLTq000mG000mO1^@s6AM^iV00004b3#c}2nYxW
zd<bNS0005UNkl<ZIE|%JO-L$H6h1QzLk>pZ4MY$`uvwNR!r;okMbKJk8Mr7Sc?B_4
zw3vhk*&h#jJRY=Z9WH}5j=0iAViLG<V(cviCuTyFff`%LjazRFqO+QF`2H^Q0eo{P
z002=GI~>QMuMqqF{$nne8*(H`8hk~-;c&PlNg4nEF!<Q(^)&qL_xoe9SS(ww*Dp-d
zd<um^E0s#+L{XG$?2fUtokKVrUSnBy0wKhEJf3-u<E8{b*tEkk<Pr!376d`qXt&#U
z`FwuKvaA;XfMT(@mrN!PQmNEswOak#YPE{C2_limmec8U%d)(K$p8SBWxW&%g>8fo
zAB{$(kqK(G+PT~9o+ZhoNVD0z(sliTyuVApvaFM$sJEMv_I2*lK8?hfruj57K`<Cx
zW*Ei+!+s20<23neDW2ySy<V@-Xf!Tu6O>9N$uNw6@pwG@@d=4U;%B$pZI{dC<B<te
zRh3m$m1&wDBi&u&G?Ha`_oL{43Gl4WO#D#Nz7F1%w6C*1H@Wqx09oZfb>sB#M&HN#
z(T$${eQO-sVHtp7jYUy>bJR3V$(^0?{b#F314aL;=?9riril=m#u&2t-<ntTVz!g#
SPj1ct0000<MNUMnLSTY21@CSE

literal 0
HcmV?d00001

diff --git a/src/slic3r/GUI/3DScene.hpp b/src/slic3r/GUI/3DScene.hpp
index 0414a1ed3..3090688e6 100644
--- a/src/slic3r/GUI/3DScene.hpp
+++ b/src/slic3r/GUI/3DScene.hpp
@@ -409,6 +409,8 @@ public:
     BoundingBoxf3        transformed_convex_hull_bounding_box(const Transform3d &trafo) const;
     // caching variant
     const BoundingBoxf3& transformed_convex_hull_bounding_box() const;
+    // convex hull
+    const TriangleMesh*  convex_hull() const { return m_convex_hull.get(); }
 
     bool                empty() const { return this->indexed_vertex_array.empty(); }
     bool                indexed() const { return this->indexed_vertex_array.indexed(); }
diff --git a/src/slic3r/GUI/GUI_ObjectManipulation.cpp b/src/slic3r/GUI/GUI_ObjectManipulation.cpp
index 4ccaa6847..7363b2c16 100644
--- a/src/slic3r/GUI/GUI_ObjectManipulation.cpp
+++ b/src/slic3r/GUI/GUI_ObjectManipulation.cpp
@@ -17,6 +17,28 @@ namespace Slic3r
 namespace GUI
 {
 
+
+// Helper function to be used by drop to bed button. Returns lowest point of this
+// volume in world coordinate system.
+static double get_volume_min_z(const GLVolume* volume)
+{
+    const Transform3f& world_matrix = volume->world_matrix().cast<float>();
+
+    // need to get the ModelVolume pointer
+    const ModelObject* mo = wxGetApp().model_objects()->at(volume->composite_id.object_id);
+    const ModelVolume* mv = mo->volumes[volume->composite_id.volume_id];
+    const TriangleMesh& hull = mv->get_convex_hull();
+
+    float min_z = std::numeric_limits<float>::max();
+    for (const stl_facet& facet : hull.stl.facet_start) {
+        for (int i = 0; i < 3; ++ i)
+            min_z = std::min(min_z, Vec3f::UnitZ().dot(world_matrix * facet.vertex[i]));
+    }
+    return min_z;
+}
+
+
+
 static wxBitmapComboBox* create_word_local_combo(wxWindow *parent)
 {
     wxSize size(15 * wxGetApp().em_unit(), -1);
@@ -310,6 +332,33 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent) :
             };
             line.append_widget(reset_rotation_button);
         }
+        else if (option_name == "Position") {
+            // Add drop to bed button
+            auto drop_to_bed_button = [=](wxWindow* parent) {
+                auto btn = new ScalableButton(parent, wxID_ANY, ScalableBitmap(parent, "drop_to_bed.png"));
+                btn->SetToolTip(_(L("Drop to bed")));
+                m_drop_to_bed_button = btn;
+                auto sizer = new wxBoxSizer(wxHORIZONTAL);
+                sizer->Add(btn, wxBU_EXACTFIT);
+                btn->Bind(wxEVT_BUTTON, [=](wxCommandEvent &e) {
+                    // ???
+                    GLCanvas3D* canvas = wxGetApp().plater()->canvas3D();
+                    Selection& selection = canvas->get_selection();
+
+                    if (selection.is_single_volume() || selection.is_single_modifier()) {
+                        const GLVolume* volume = selection.get_volume(*selection.get_volume_idxs().begin());
+
+                        Vec3d diff = m_cache.position - Vec3d(0., 0., get_volume_min_z(volume));
+
+                        change_position_value(0, diff.x());
+                        change_position_value(1, diff.y());
+                        change_position_value(2, diff.z());
+                    }
+                });
+            return sizer;
+            };
+            line.append_widget(drop_to_bed_button);
+        }
         // Add empty bmp (Its size have to be equal to PrusaLockButton) in front of "Size" option to label alignment
         else if (option_name == "Size") {
             line.near_label_widget = [this](wxWindow* parent) {
@@ -534,11 +583,13 @@ void ObjectManipulation::update_reset_buttons_visibility()
 
     bool show_rotation = false;
     bool show_scale = false;
+    bool show_drop_to_bed = false;
 
     if (selection.is_single_full_instance() || selection.is_single_modifier() || selection.is_single_volume()) {
         const GLVolume* volume = selection.get_volume(*selection.get_volume_idxs().begin());
         Vec3d rotation;
         Vec3d scale;
+        double min_z = 0.;
 
         if (selection.is_single_full_instance()) {
             rotation = volume->get_instance_rotation();
@@ -547,14 +598,17 @@ void ObjectManipulation::update_reset_buttons_visibility()
         else {
             rotation = volume->get_volume_rotation();
             scale = volume->get_volume_scaling_factor();
+            min_z = get_volume_min_z(volume);
         }
         show_rotation = !rotation.isApprox(Vec3d::Zero());
         show_scale = !scale.isApprox(Vec3d::Ones());
+        show_drop_to_bed = (std::abs(min_z) > EPSILON);
     }
 
-    wxGetApp().CallAfter([this, show_rotation, show_scale]{
+    wxGetApp().CallAfter([this, show_rotation, show_scale, show_drop_to_bed]{
         m_reset_rotation_button->Show(show_rotation);
         m_reset_scale_button->Show(show_scale);
+        m_drop_to_bed_button->Show(show_drop_to_bed);
     });
 }
 
@@ -867,6 +921,7 @@ void ObjectManipulation::msw_rescale()
     m_mirror_bitmap_hidden.msw_rescale();
     m_reset_scale_button->msw_rescale();
     m_reset_rotation_button->msw_rescale();
+    m_drop_to_bed_button->msw_rescale();
 
     get_og()->msw_rescale();
 }
diff --git a/src/slic3r/GUI/GUI_ObjectManipulation.hpp b/src/slic3r/GUI/GUI_ObjectManipulation.hpp
index cc2154514..e4e190b5b 100644
--- a/src/slic3r/GUI/GUI_ObjectManipulation.hpp
+++ b/src/slic3r/GUI/GUI_ObjectManipulation.hpp
@@ -56,6 +56,7 @@ class ObjectManipulation : public OG_Settings
     // Non-owning pointers to the reset buttons, so we can hide and show them.
     ScalableButton* m_reset_scale_button = nullptr;
     ScalableButton* m_reset_rotation_button = nullptr;
+    ScalableButton* m_drop_to_bed_button = nullptr;
 
     // Mirroring buttons and their current state
     enum MirrorButtonState {

From 0481f33ceb4dd64098e3b0c9c324bc32a82ba5f3 Mon Sep 17 00:00:00 2001
From: Lukas Matena <lukasmatena@seznam.cz>
Date: Wed, 19 Jun 2019 11:52:37 +0200
Subject: [PATCH 3/3] Drop to bed function now accounts for instance
 transformation

---
 src/slic3r/GUI/GUI_ObjectManipulation.cpp | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/src/slic3r/GUI/GUI_ObjectManipulation.cpp b/src/slic3r/GUI/GUI_ObjectManipulation.cpp
index 7363b2c16..d5445c6af 100644
--- a/src/slic3r/GUI/GUI_ObjectManipulation.cpp
+++ b/src/slic3r/GUI/GUI_ObjectManipulation.cpp
@@ -348,7 +348,8 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent) :
                     if (selection.is_single_volume() || selection.is_single_modifier()) {
                         const GLVolume* volume = selection.get_volume(*selection.get_volume_idxs().begin());
 
-                        Vec3d diff = m_cache.position - Vec3d(0., 0., get_volume_min_z(volume));
+                        const Geometry::Transformation& instance_trafo = volume->get_instance_transformation();
+                        Vec3d diff = m_cache.position - instance_trafo.get_matrix(true).inverse() * Vec3d(0., 0., get_volume_min_z(volume));
 
                         change_position_value(0, diff.x());
                         change_position_value(1, diff.y());