From f761691b7d733a19d6c8fb42d03f23c5956d6f00 Mon Sep 17 00:00:00 2001
From: tamasmeszaros <meszaros.q@gmail.com>
Date: Fri, 4 Jan 2019 16:24:10 +0100
Subject: [PATCH 01/14] Pad now has adjustable wall tilt and maintains wall
 thickness properly.

Edges are not rounded yet.
---
 src/libslic3r/SLA/SLABasePool.cpp    | 208 ++++++++++++++++++---------
 src/libslic3r/SLA/SLABasePool.hpp    |   6 +-
 src/libslic3r/SLA/SLASupportTree.cpp |   8 +-
 src/libslic3r/SLAPrint.cpp           |   2 +-
 4 files changed, 149 insertions(+), 75 deletions(-)

diff --git a/src/libslic3r/SLA/SLABasePool.cpp b/src/libslic3r/SLA/SLABasePool.cpp
index 21bd124f7..a819d16ca 100644
--- a/src/libslic3r/SLA/SLABasePool.cpp
+++ b/src/libslic3r/SLA/SLABasePool.cpp
@@ -457,104 +457,172 @@ void base_plate(const TriangleMesh &mesh, ExPolygons &output, float h,
 void create_base_pool(const ExPolygons &ground_layer, TriangleMesh& out,
                       const PoolConfig& cfg)
 {
-    double mdist = 2*(1.8*cfg.min_wall_thickness_mm + 4*cfg.edge_radius_mm) +
-                   cfg.max_merge_distance_mm;
 
-    auto concavehs = concave_hull(ground_layer, mdist, cfg.throw_on_cancel);
+    double mergedist = 2*(1.8*cfg.min_wall_thickness_mm /*+ 4*cfg.edge_radius_mm*/)+
+                       cfg.max_merge_distance_mm;
+
+    auto concavehs = concave_hull(ground_layer, mergedist, cfg.throw_on_cancel);
+
+
     for(ExPolygon& concaveh : concavehs) {
         if(concaveh.contour.points.empty()) return;
         concaveh.holes.clear();
 
-        const coord_t WALL_THICKNESS = mm(cfg.min_wall_thickness_mm);
-
-        const coord_t WALL_DISTANCE = mm(2*cfg.edge_radius_mm) +
-                                      coord_t(0.8*WALL_THICKNESS);
-
-        const coord_t HEIGHT = mm(cfg.min_wall_height_mm);
+        const double thickness      = cfg.min_wall_thickness_mm;
+        const double wingheight     = cfg.min_wall_height_mm;
+        const coord_t s_thickness   = mm(thickness);
+//        const coord_t s_eradius     = mm(cfg.edge_radius_mm);
+        const coord_t s_safety_dist = /*2*s_eradius +*/ coord_t(0.8*s_thickness);
+        // const coord_t wheight = mm(cfg.min_wall_height_mm);
+        const double tilt = PI/4;
+        coord_t s_wingdist = mm(wingheight / std::tan(tilt));
 
+        // Here lies the trick that does the smooting only with clipper offset
+        // calls. The offset is configured to round edges. Inner edges will
+        // be rounded because we offset twice: ones to get the outer (top) plate
+        // and again to get the inner (bottom) plate
         auto outer_base = concaveh;
-        offset(outer_base, WALL_THICKNESS+WALL_DISTANCE);
+        offset(outer_base, s_safety_dist + s_wingdist + s_thickness);
         auto inner_base = outer_base;
-        offset(inner_base, -WALL_THICKNESS);
-        inner_base.holes.clear(); outer_base.holes.clear();
+        auto middle_base = outer_base;
+        offset(inner_base, -(s_thickness + s_wingdist));
+        offset(middle_base, -s_thickness);
+        inner_base.holes.clear();   // bottom contour
+        middle_base.holes.clear();  // contour of the cavity-top
+        outer_base.holes.clear();   // bottom contour, also for the cavity
 
+        // Punching a hole in the top plate for the cavity
         ExPolygon top_poly;
         top_poly.contour = outer_base.contour;
-        top_poly.holes.emplace_back(inner_base.contour);
+        top_poly.holes.emplace_back(middle_base.contour);
         auto& tph = top_poly.holes.back().points;
         std::reverse(tph.begin(), tph.end());
 
         Contour3D pool;
 
-        ExPolygon ob = outer_base; double wh = 0;
+        double fullheight = wingheight + thickness;
+        auto& thrcl = cfg.throw_on_cancel;
 
-        // now we will calculate the angle or portion of the circle from
-        // pi/2 that will connect perfectly with the bottom plate.
-        // this is a tangent point calculation problem and the equation can
-        // be found for example here:
-        // http://www.ambrsoft.com/TrigoCalc/Circles2/CirclePoint/CirclePointDistance.htm
-        // the y coordinate would be:
-        // y = cy + (r^2*py - r*px*sqrt(px^2 + py^2 - r^2) / (px^2 + py^2)
-        // where px and py are the coordinates of the point outside the circle
-        // cx and cy are the circle center, r is the radius
-        // to get the angle we use arcsin function and subtract 90 degrees then
-        // flip the sign to get the right input to the round_edge function.
-        double r = cfg.edge_radius_mm;
-        double cy = 0;
-        double cx = 0;
-        double px = cfg.min_wall_thickness_mm;
-        double py = r - cfg.min_wall_height_mm;
-
-        double pxcx = px - cx;
-        double pycy = py - cy;
-        double b_2 = pxcx*pxcx + pycy*pycy;
-        double r_2 = r*r;
-        double D = std::sqrt(b_2 - r_2);
-        double vy = (r_2*pycy - r*pxcx*D) / b_2;
-        double phi = -(std::asin(vy/r) * 180 / PI - 90);
-
-        auto curvedwalls = round_edges(ob,
-                                       r,
-                                       phi,  // 170 degrees
-                                       0,    // z position of the input plane
-                                       true,
-                                       cfg.throw_on_cancel,
-                                       ob, wh);
-
-        pool.merge(curvedwalls);
-
-        ExPolygon ob_contr = ob;
-        ob_contr.holes.clear();
-
-        auto pwalls = walls(ob_contr, inner_base, wh, -cfg.min_wall_height_mm,
-                            cfg.throw_on_cancel);
+        auto pwalls = walls(top_poly, inner_base, 0, -fullheight, thrcl);
         pool.merge(pwalls);
 
-        Polygons top_triangles, bottom_triangles;
+        auto cavitywalls = walls(inner_base, middle_base, -wingheight, 0, thrcl);
+        pool.merge(cavitywalls);
+
+        Polygons top_triangles, middle_triangles, bottom_triangles;
+
         triangulate(top_poly, top_triangles);
+        triangulate(inner_base, middle_triangles);
         triangulate(inner_base, bottom_triangles);
         auto top_plate = convert(top_triangles, 0, false);
-        auto bottom_plate = convert(bottom_triangles, -HEIGHT, true);
-
-        ob = inner_base; wh = 0;
-        // rounded edge generation for the inner bed
-        curvedwalls = round_edges(ob,
-                                  cfg.edge_radius_mm,
-                                  90,   // 90 degrees
-                                  0,    // z position of the input plane
-                                  false,
-                                  cfg.throw_on_cancel,
-                                  ob, wh);
-        pool.merge(curvedwalls);
-
-        auto innerbed = inner_bed(ob, cfg.min_wall_height_mm/2 + wh, wh);
+        auto middle_plate = convert(middle_triangles, -mm(wingheight), false);
+        auto bottom_plate = convert(bottom_triangles, -mm(fullheight), true);
 
         pool.merge(top_plate);
+        pool.merge(middle_plate);
         pool.merge(bottom_plate);
-        pool.merge(innerbed);
 
         out.merge(mesh(pool));
     }
+
+//    double mdist = 2*(1.8*cfg.min_wall_thickness_mm + 4*cfg.edge_radius_mm) +
+//                   cfg.max_merge_distance_mm;
+
+//    auto concavehs = concave_hull(ground_layer, mdist, cfg.throw_on_cancel);
+//    for(ExPolygon& concaveh : concavehs) {
+//        if(concaveh.contour.points.empty()) return;
+//        concaveh.holes.clear();
+
+//        const coord_t WALL_THICKNESS = mm(cfg.min_wall_thickness_mm);
+
+//        const coord_t WALL_DISTANCE = mm(2*cfg.edge_radius_mm) +
+//                                      coord_t(0.8*WALL_THICKNESS);
+
+//        const coord_t HEIGHT = mm(cfg.min_wall_height_mm);
+
+//        auto outer_base = concaveh;
+//        offset(outer_base, WALL_THICKNESS+WALL_DISTANCE);
+//        auto inner_base = outer_base;
+//        offset(inner_base, -WALL_THICKNESS);
+//        inner_base.holes.clear(); outer_base.holes.clear();
+
+//        ExPolygon top_poly;
+//        top_poly.contour = outer_base.contour;
+//        top_poly.holes.emplace_back(inner_base.contour);
+//        auto& tph = top_poly.holes.back().points;
+//        std::reverse(tph.begin(), tph.end());
+
+//        Contour3D pool;
+
+//        ExPolygon ob = outer_base; double wh = 0;
+
+//        // now we will calculate the angle or portion of the circle from
+//        // pi/2 that will connect perfectly with the bottom plate.
+//        // this is a tangent point calculation problem and the equation can
+//        // be found for example here:
+//        // http://www.ambrsoft.com/TrigoCalc/Circles2/CirclePoint/CirclePointDistance.htm
+//        // the y coordinate would be:
+//        // y = cy + (r^2*py - r*px*sqrt(px^2 + py^2 - r^2) / (px^2 + py^2)
+//        // where px and py are the coordinates of the point outside the circle
+//        // cx and cy are the circle center, r is the radius
+//        // to get the angle we use arcsin function and subtract 90 degrees then
+//        // flip the sign to get the right input to the round_edge function.
+//        double r = cfg.edge_radius_mm;
+//        double cy = 0;
+//        double cx = 0;
+//        double px = cfg.min_wall_thickness_mm;
+//        double py = r - cfg.min_wall_height_mm;
+
+//        double pxcx = px - cx;
+//        double pycy = py - cy;
+//        double b_2 = pxcx*pxcx + pycy*pycy;
+//        double r_2 = r*r;
+//        double D = std::sqrt(b_2 - r_2);
+//        double vy = (r_2*pycy - r*pxcx*D) / b_2;
+//        double phi = -(std::asin(vy/r) * 180 / PI - 90);
+
+//        auto curvedwalls = round_edges(ob,
+//                                       r,
+//                                       phi,  // 170 degrees
+//                                       0,    // z position of the input plane
+//                                       true,
+//                                       cfg.throw_on_cancel,
+//                                       ob, wh);
+
+//        pool.merge(curvedwalls);
+
+//        ExPolygon ob_contr = ob;
+//        ob_contr.holes.clear();
+
+//        auto pwalls = walls(ob_contr, inner_base, wh, -cfg.min_wall_height_mm,
+//                            cfg.throw_on_cancel);
+//        pool.merge(pwalls);
+
+//        Polygons top_triangles, bottom_triangles;
+//        triangulate(top_poly, top_triangles);
+//        triangulate(inner_base, bottom_triangles);
+//        auto top_plate = convert(top_triangles, 0, false);
+//        auto bottom_plate = convert(bottom_triangles, -HEIGHT, true);
+
+//        ob = inner_base; wh = 0;
+//        // rounded edge generation for the inner bed
+//        curvedwalls = round_edges(ob,
+//                                  cfg.edge_radius_mm,
+//                                  90,   // 90 degrees
+//                                  0,    // z position of the input plane
+//                                  false,
+//                                  cfg.throw_on_cancel,
+//                                  ob, wh);
+//        pool.merge(curvedwalls);
+
+//        auto innerbed = inner_bed(ob, cfg.min_wall_height_mm/2 + wh, wh);
+
+//        pool.merge(top_plate);
+//        pool.merge(bottom_plate);
+//        pool.merge(innerbed);
+
+//        out.merge(mesh(pool));
+//    }
 }
 
 }
diff --git a/src/libslic3r/SLA/SLABasePool.hpp b/src/libslic3r/SLA/SLABasePool.hpp
index 62c4971eb..3917d995b 100644
--- a/src/libslic3r/SLA/SLABasePool.hpp
+++ b/src/libslic3r/SLA/SLABasePool.hpp
@@ -49,7 +49,11 @@ void create_base_pool(const ExPolygons& base_plate,
 /// min_wall_thickness and it should be corrected in the future. This method
 /// will return the correct value for further processing.
 inline double get_pad_elevation(const PoolConfig& cfg) {
-    return cfg.min_wall_height_mm / 2.0;
+    return cfg.min_wall_thickness_mm;
+}
+
+inline double get_pad_fullheight(const PoolConfig& cfg) {
+    return cfg.min_wall_height_mm + cfg.min_wall_thickness_mm;
 }
 
 }
diff --git a/src/libslic3r/SLA/SLASupportTree.cpp b/src/libslic3r/SLA/SLASupportTree.cpp
index 746acc547..5239255b1 100644
--- a/src/libslic3r/SLA/SLASupportTree.cpp
+++ b/src/libslic3r/SLA/SLASupportTree.cpp
@@ -515,7 +515,8 @@ struct Pad {
         double ground_level,
         const PoolConfig& pcfg) :
         cfg(pcfg),
-        zlevel(ground_level + sla::get_pad_elevation(pcfg))
+        zlevel(ground_level +
+               (sla::get_pad_fullheight(pcfg) - sla::get_pad_elevation(pcfg)) )
     {
         ExPolygons basep;
         cfg.throw_on_cancel();
@@ -523,7 +524,8 @@ struct Pad {
         // The 0.1f is the layer height with which the mesh is sampled and then
         // the layers are unified into one vector of polygons.
         base_plate(object_support_mesh, basep,
-                   float(cfg.min_wall_height_mm), 0.1f, pcfg.throw_on_cancel);
+                   float(cfg.min_wall_height_mm + cfg.min_wall_thickness_mm),
+                   0.1f, pcfg.throw_on_cancel);
 
         for(auto& bp : baseplate) basep.emplace_back(bp);
 
@@ -781,7 +783,7 @@ public:
     // WITH THE PAD
     double full_height() const {
         if(merged_mesh().empty() && !pad().empty())
-            return pad().cfg.min_wall_height_mm;
+            return get_pad_fullheight(pad().cfg);
 
         double h = mesh_height();
         if(!pad().empty()) h += sla::get_pad_elevation(pad().cfg);
diff --git a/src/libslic3r/SLAPrint.cpp b/src/libslic3r/SLAPrint.cpp
index f45d805b6..aa759a47a 100644
--- a/src/libslic3r/SLAPrint.cpp
+++ b/src/libslic3r/SLAPrint.cpp
@@ -630,7 +630,7 @@ void SLAPrint::process()
             sla::PoolConfig pcfg(wt, h, md, er);
 
             ExPolygons bp;
-            double pad_h = sla::get_pad_elevation(pcfg);
+            double pad_h = sla::get_pad_fullheight(pcfg);
             auto&& trmesh = po.transformed_mesh();
 
             // This call can get pretty time consuming

From fa5c96dfb9e3a75b97e8eb8670a6af0d4b65894e Mon Sep 17 00:00:00 2001
From: tamasmeszaros <meszaros.q@gmail.com>
Date: Fri, 4 Jan 2019 16:57:27 +0100
Subject: [PATCH 02/14] Recover outer top radius for the new pad.

Inner top, bottom and outer bottom radius still missing.
---
 src/libslic3r/SLA/SLABasePool.cpp | 57 ++++++++++++++++++++++++++-----
 1 file changed, 49 insertions(+), 8 deletions(-)

diff --git a/src/libslic3r/SLA/SLABasePool.cpp b/src/libslic3r/SLA/SLABasePool.cpp
index a819d16ca..598e6f66d 100644
--- a/src/libslic3r/SLA/SLABasePool.cpp
+++ b/src/libslic3r/SLA/SLABasePool.cpp
@@ -458,7 +458,7 @@ void create_base_pool(const ExPolygons &ground_layer, TriangleMesh& out,
                       const PoolConfig& cfg)
 {
 
-    double mergedist = 2*(1.8*cfg.min_wall_thickness_mm /*+ 4*cfg.edge_radius_mm*/)+
+    double mergedist = 2*(1.8*cfg.min_wall_thickness_mm + 4*cfg.edge_radius_mm)+
                        cfg.max_merge_distance_mm;
 
     auto concavehs = concave_hull(ground_layer, mergedist, cfg.throw_on_cancel);
@@ -470,12 +470,16 @@ void create_base_pool(const ExPolygons &ground_layer, TriangleMesh& out,
 
         const double thickness      = cfg.min_wall_thickness_mm;
         const double wingheight     = cfg.min_wall_height_mm;
-        const coord_t s_thickness   = mm(thickness);
-//        const coord_t s_eradius     = mm(cfg.edge_radius_mm);
-        const coord_t s_safety_dist = /*2*s_eradius +*/ coord_t(0.8*s_thickness);
-        // const coord_t wheight = mm(cfg.min_wall_height_mm);
+        const double fullheight     = wingheight + thickness;
         const double tilt = PI/4;
-        coord_t s_wingdist = mm(wingheight / std::tan(tilt));
+        const double wingdist       = wingheight / std::tan(tilt);
+
+        // scaled values
+        const coord_t s_thickness   = mm(thickness);
+        const coord_t s_eradius     = mm(cfg.edge_radius_mm);
+        const coord_t s_safety_dist = 2*s_eradius + coord_t(0.8*s_thickness);
+        // const coord_t wheight    = mm(cfg.min_wall_height_mm);
+        coord_t s_wingdist          = mm(wingdist);
 
         // Here lies the trick that does the smooting only with clipper offset
         // calls. The offset is configured to round edges. Inner edges will
@@ -500,10 +504,47 @@ void create_base_pool(const ExPolygons &ground_layer, TriangleMesh& out,
 
         Contour3D pool;
 
-        double fullheight = wingheight + thickness;
+        ExPolygon ob = outer_base; double wh = 0;
+
+        // now we will calculate the angle or portion of the circle from
+        // pi/2 that will connect perfectly with the bottom plate.
+        // this is a tangent point calculation problem and the equation can
+        // be found for example here:
+        // http://www.ambrsoft.com/TrigoCalc/Circles2/CirclePoint/CirclePointDistance.htm
+        // the y coordinate would be:
+        // y = cy + (r^2*py - r*px*sqrt(px^2 + py^2 - r^2) / (px^2 + py^2)
+        // where px and py are the coordinates of the point outside the circle
+        // cx and cy are the circle center, r is the radius
+        // to get the angle we use arcsin function and subtract 90 degrees then
+        // flip the sign to get the right input to the round_edge function.
+        double r = cfg.edge_radius_mm;
+        double cy = 0;
+        double cx = 0;
+        double px = thickness + wingdist;
+        double py = r - fullheight;
+
+        double pxcx = px - cx;
+        double pycy = py - cy;
+        double b_2 = pxcx*pxcx + pycy*pycy;
+        double r_2 = r*r;
+        double D = std::sqrt(b_2 - r_2);
+        double vy = (r_2*pycy - r*pxcx*D) / b_2;
+        double phi = -(std::asin(vy/r) * 180 / PI - 90);
+
+        auto curvedwalls = round_edges(ob,
+                                       r,
+                                       phi,  // 170 degrees
+                                       0,    // z position of the input plane
+                                       true,
+                                       cfg.throw_on_cancel,
+                                       ob, wh);
+
+        pool.merge(curvedwalls);
+
+
         auto& thrcl = cfg.throw_on_cancel;
 
-        auto pwalls = walls(top_poly, inner_base, 0, -fullheight, thrcl);
+        auto pwalls = walls(ob, inner_base, wh, -fullheight, thrcl);
         pool.merge(pwalls);
 
         auto cavitywalls = walls(inner_base, middle_base, -wingheight, 0, thrcl);

From 0c7fbe0a9356999bc1da5573e75929cfa8948cc1 Mon Sep 17 00:00:00 2001
From: tamasmeszaros <meszaros.q@gmail.com>
Date: Mon, 7 Jan 2019 10:07:49 +0100
Subject: [PATCH 03/14] Comments and cosmetics for the new pad code.

---
 src/libslic3r/SLA/SLABasePool.cpp | 51 ++++++++++++++++++++-----------
 1 file changed, 33 insertions(+), 18 deletions(-)

diff --git a/src/libslic3r/SLA/SLABasePool.cpp b/src/libslic3r/SLA/SLABasePool.cpp
index 598e6f66d..5dbbb0440 100644
--- a/src/libslic3r/SLA/SLABasePool.cpp
+++ b/src/libslic3r/SLA/SLABasePool.cpp
@@ -461,26 +461,34 @@ void create_base_pool(const ExPolygons &ground_layer, TriangleMesh& out,
     double mergedist = 2*(1.8*cfg.min_wall_thickness_mm + 4*cfg.edge_radius_mm)+
                        cfg.max_merge_distance_mm;
 
+    // Here we get the base polygon from which the pad has to be generated.
+    // We create an artificial concave hull from this polygon and that will
+    // serve as the bottom plate of the pad. We will offset this concave hull
+    // and then offset back the result with clipper with rounding edges ON. This
+    // trick will create a nice rounded pad shape.
     auto concavehs = concave_hull(ground_layer, mergedist, cfg.throw_on_cancel);
 
+    const double thickness      = cfg.min_wall_thickness_mm;
+    const double wingheight     = cfg.min_wall_height_mm;
+    const double fullheight     = wingheight + thickness;
+    const double tilt = PI/4;
+    const double wingdist       = wingheight / std::tan(tilt);
+
+    // scaled values
+    const coord_t s_thickness   = mm(thickness);
+    const coord_t s_eradius     = mm(cfg.edge_radius_mm);
+    const coord_t s_safety_dist = 2*s_eradius + coord_t(0.8*s_thickness);
+    // const coord_t wheight    = mm(cfg.min_wall_height_mm);
+    coord_t s_wingdist          = mm(wingdist);
+
+    auto& thrcl = cfg.throw_on_cancel;
 
     for(ExPolygon& concaveh : concavehs) {
         if(concaveh.contour.points.empty()) return;
+
+        // Get rif of any holes in the concave hull output.
         concaveh.holes.clear();
 
-        const double thickness      = cfg.min_wall_thickness_mm;
-        const double wingheight     = cfg.min_wall_height_mm;
-        const double fullheight     = wingheight + thickness;
-        const double tilt = PI/4;
-        const double wingdist       = wingheight / std::tan(tilt);
-
-        // scaled values
-        const coord_t s_thickness   = mm(thickness);
-        const coord_t s_eradius     = mm(cfg.edge_radius_mm);
-        const coord_t s_safety_dist = 2*s_eradius + coord_t(0.8*s_thickness);
-        // const coord_t wheight    = mm(cfg.min_wall_height_mm);
-        coord_t s_wingdist          = mm(wingdist);
-
         // Here lies the trick that does the smooting only with clipper offset
         // calls. The offset is configured to round edges. Inner edges will
         // be rounded because we offset twice: ones to get the outer (top) plate
@@ -515,6 +523,8 @@ void create_base_pool(const ExPolygons &ground_layer, TriangleMesh& out,
         // y = cy + (r^2*py - r*px*sqrt(px^2 + py^2 - r^2) / (px^2 + py^2)
         // where px and py are the coordinates of the point outside the circle
         // cx and cy are the circle center, r is the radius
+        // We place the circle center to (0, 0) in the calculation the make
+        // things easier.
         // to get the angle we use arcsin function and subtract 90 degrees then
         // flip the sign to get the right input to the round_edge function.
         double r = cfg.edge_radius_mm;
@@ -531,25 +541,30 @@ void create_base_pool(const ExPolygons &ground_layer, TriangleMesh& out,
         double vy = (r_2*pycy - r*pxcx*D) / b_2;
         double phi = -(std::asin(vy/r) * 180 / PI - 90);
 
+
+        // Generate the smoothed edge geometry
         auto curvedwalls = round_edges(ob,
                                        r,
                                        phi,  // 170 degrees
                                        0,    // z position of the input plane
                                        true,
-                                       cfg.throw_on_cancel,
+                                       thrcl,
                                        ob, wh);
-
         pool.merge(curvedwalls);
 
-
-        auto& thrcl = cfg.throw_on_cancel;
-
+        // Now that we have the rounded edge connencting the top plate with
+        // the outer side walls, we can generate and merge the sidewall geometry
         auto pwalls = walls(ob, inner_base, wh, -fullheight, thrcl);
         pool.merge(pwalls);
 
+        // Next is the cavity walls connecting to the top plate's artificially
+        // created hole.
         auto cavitywalls = walls(inner_base, middle_base, -wingheight, 0, thrcl);
         pool.merge(cavitywalls);
 
+        // Now we need to triangulate the top and bottom plates as well as the
+        // cavity bottom plate which is the same as the bottom plate but it is
+        // eleveted by the thickness.
         Polygons top_triangles, middle_triangles, bottom_triangles;
 
         triangulate(top_poly, top_triangles);

From 4d0c0ac7483eac299fea266d9a35e8e10e3cd5de Mon Sep 17 00:00:00 2001
From: YuSanka <yusanka@gmail.com>
Date: Tue, 8 Jan 2019 11:47:05 +0100
Subject: [PATCH 04/14] Fix of Cyrillic named files inside the object list
 (part of the #1622)

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

diff --git a/src/slic3r/GUI/GUI_ObjectList.cpp b/src/slic3r/GUI/GUI_ObjectList.cpp
index 0b6c38bd8..729946dbf 100644
--- a/src/slic3r/GUI/GUI_ObjectList.cpp
+++ b/src/slic3r/GUI/GUI_ObjectList.cpp
@@ -849,7 +849,7 @@ void ObjectList::load_part( ModelObject* model_object,
                 new_volume->set_type(static_cast<ModelVolume::Type>(type));
                 new_volume->name = boost::filesystem::path(input_file).filename().string();
 
-                part_names.Add(new_volume->name);
+                part_names.Add(from_u8(new_volume->name));
 
                 // set a default extruder value, since user can't add it manually
                 new_volume->config.set_key_value("extruder", new ConfigOptionInt(0));
@@ -903,7 +903,7 @@ void ObjectList::load_generic_subobject(const std::string& type_name, const int
     m_parts_changed = true;
     parts_changed(obj_idx);
 
-    select_item(m_objects_model->AddVolumeChild(GetSelection(), name, type));
+    select_item(m_objects_model->AddVolumeChild(GetSelection(), from_u8(name), type));
 #ifndef __WXOSX__ //#ifdef __WXMSW__ // #ys_FIXME
     selection_changed();
 #endif //no __WXOSX__ //__WXMSW__
@@ -1031,7 +1031,7 @@ void ObjectList::split()
         parent = item;
 
     for (auto id = 0; id < model_object->volumes.size(); id++) {
-        const auto vol_item = m_objects_model->AddVolumeChild(parent, model_object->volumes[id]->name,
+        const auto vol_item = m_objects_model->AddVolumeChild(parent, from_u8(model_object->volumes[id]->name),
                                             model_object->volumes[id]->is_modifier() ? 
                                                 ModelVolume::PARAMETER_MODIFIER : ModelVolume::MODEL_PART,
                                             model_object->volumes[id]->config.has("extruder") ?
@@ -1188,7 +1188,7 @@ void ObjectList::part_selection_changed()
 void ObjectList::add_object_to_list(size_t obj_idx)
 {
     auto model_object = (*m_objects)[obj_idx];
-    wxString item_name = model_object->name;
+    wxString item_name = from_u8(model_object->name);
     const auto item = m_objects_model->Add(item_name,
                       !model_object->config.has("extruder") ? 0 :
                       model_object->config.option<ConfigOptionInt>("extruder")->value);
@@ -1207,8 +1207,8 @@ void ObjectList::add_object_to_list(size_t obj_idx)
     if (model_object->volumes.size() > 1) {
         for (auto id = 0; id < model_object->volumes.size(); id++) {
             auto vol_item = m_objects_model->AddVolumeChild(item,
-                model_object->volumes[id]->name,
-                model_object->volumes[id]->type()/*ModelVolume::MODEL_PART*/,
+                from_u8(model_object->volumes[id]->name),
+                model_object->volumes[id]->type(),
                 !model_object->volumes[id]->config.has("extruder") ? 0 :
                 model_object->volumes[id]->config.option<ConfigOptionInt>("extruder")->value,
                 false);

From 24e0c9b79e7faca2a3cf5a07c216648b385daf1a Mon Sep 17 00:00:00 2001
From: YuSanka <yusanka@gmail.com>
Date: Tue, 8 Jan 2019 13:34:47 +0100
Subject: [PATCH 05/14] Added "uniform scaling" button

---
 src/slic3r/GUI/GUI_ObjectManipulation.cpp | 24 +++++++++++++++++++++--
 src/slic3r/GUI/GUI_ObjectManipulation.hpp |  4 ++++
 2 files changed, 26 insertions(+), 2 deletions(-)

diff --git a/src/slic3r/GUI/GUI_ObjectManipulation.cpp b/src/slic3r/GUI/GUI_ObjectManipulation.cpp
index f763cc5a1..1cdf87be2 100644
--- a/src/slic3r/GUI/GUI_ObjectManipulation.cpp
+++ b/src/slic3r/GUI/GUI_ObjectManipulation.cpp
@@ -19,7 +19,7 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent) :
     OG_Settings(parent, true)
 {
     m_og->set_name(_(L("Object Manipulation")));
-    m_og->label_width = 100;
+    m_og->label_width = 125;
     m_og->set_grid_vgap(5);
     
     m_og->m_on_change = [this](const std::string& opt_key, const boost::any& value) {
@@ -150,7 +150,7 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent) :
     m_og->append_line(line);
 
 
-    auto add_og_to_object_settings = [](const std::string& option_name, const std::string& sidetext)
+    auto add_og_to_object_settings = [this](const std::string& option_name, const std::string& sidetext)
     {
         Line line = { _(option_name), "" };
         ConfigOptionDef def;
@@ -164,6 +164,26 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent) :
             def.max = 360;
         }
 
+        // Add "uniform scaling" button in front of "Scale" option 
+        else if (option_name == "Scale") {
+            line.near_label_widget = [this](wxWindow* parent) {
+                auto btn = new PrusaLockButton(parent, wxID_ANY);
+                btn->Bind(wxEVT_BUTTON, [btn, this](wxCommandEvent &event){
+                    event.Skip();
+                    wxTheApp->CallAfter([btn, this]() { set_uniform_scaling(btn->IsLocked()); });
+                });
+                return btn;
+            };
+        }
+
+        // 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) {
+                return new wxStaticBitmap(parent, wxID_ANY, wxNullBitmap, wxDefaultPosition, 
+                                          wxBitmap(from_u8(var("one_layer_lock_on.png")), wxBITMAP_TYPE_PNG).GetSize());
+            };
+        }
+
         const std::string lower_name = boost::algorithm::to_lower_copy(option_name);
 
         std::vector<std::string> axes{ "x", "y", "z" };
diff --git a/src/slic3r/GUI/GUI_ObjectManipulation.hpp b/src/slic3r/GUI/GUI_ObjectManipulation.hpp
index 97cd2b639..57eb93b71 100644
--- a/src/slic3r/GUI/GUI_ObjectManipulation.hpp
+++ b/src/slic3r/GUI/GUI_ObjectManipulation.hpp
@@ -74,6 +74,7 @@ class ObjectManipulation : public OG_Settings
     Vec3d           m_new_scale;
     Vec3d           m_new_size;
     bool            m_new_enabled;
+    bool            m_uniform_scale {false};
 
 public:
     ObjectManipulation(wxWindow* parent);
@@ -88,6 +89,9 @@ public:
 	// Called from the App to update the UI if dirty.
 	void		update_if_dirty();
 
+    void        set_uniform_scaling(const bool uniform_scale) { m_uniform_scale = uniform_scale;}
+    bool        get_uniform_scaling() const { return m_uniform_scale; }
+
 private:
     void reset_settings_value();
 

From f26ec7feb37c9a088b99e9df74922e0d15ede149 Mon Sep 17 00:00:00 2001
From: tamasmeszaros <meszaros.q@gmail.com>
Date: Tue, 8 Jan 2019 14:03:41 +0100
Subject: [PATCH 06/14] pad wall smoothing only for the top of the wall.

---
 src/libslic3r/SLA/SLABasePool.cpp | 195 +++++++++---------------------
 1 file changed, 55 insertions(+), 140 deletions(-)

diff --git a/src/libslic3r/SLA/SLABasePool.cpp b/src/libslic3r/SLA/SLABasePool.cpp
index 5dbbb0440..fb68ae1d0 100644
--- a/src/libslic3r/SLA/SLABasePool.cpp
+++ b/src/libslic3r/SLA/SLABasePool.cpp
@@ -215,41 +215,67 @@ inline Contour3D roofs(const ExPolygon& poly, coord_t z_distance) {
     return lower;
 }
 
-template<class ExP, class D>
 Contour3D round_edges(const ExPolygon& base_plate,
                       double radius_mm,
                       double degrees,
                       double ceilheight_mm,
                       bool dir,
                       ThrowOnCancel throw_on_cancel,
-                      ExP&& last_offset = ExP(), D&& last_height = D())
+                      ExPolygon& last_offset, double& last_height)
 {
     auto ob = base_plate;
     auto ob_prev = ob;
     double wh = ceilheight_mm, wh_prev = wh;
     Contour3D curvedwalls;
 
-    int steps = 15; // int(std::ceil(10*std::pow(radius_mm, 1.0/3)));
+    int steps = 30;
     double stepx = radius_mm / steps;
     coord_t s = dir? 1 : -1;
     degrees = std::fmod(degrees, 180);
 
-    if(degrees >= 90) {
-        for(int i = 1; i <= steps; ++i) {
-            throw_on_cancel();
+    // we use sin for x distance because we interpret the angle starting from
+    // PI/2
+    int tos = degrees < 90?
+               int(radius_mm*std::cos(degrees * PI / 180 - PI/2) / stepx) : steps;
 
+    for(int i = 1; i <= tos; ++i) {
+        throw_on_cancel();
+
+        ob = base_plate;
+
+        double r2 = radius_mm * radius_mm;
+        double xx = i*stepx;
+        double x2 = xx*xx;
+        double stepy = std::sqrt(r2 - x2);
+
+        offset(ob, s*mm(xx));
+        wh = ceilheight_mm - radius_mm + stepy;
+
+        Contour3D pwalls;
+        pwalls = walls(ob, ob_prev, wh, wh_prev, throw_on_cancel);
+
+        curvedwalls.merge(pwalls);
+        ob_prev = ob;
+        wh_prev = wh;
+    }
+
+    if(degrees > 90) {
+        double tox = radius_mm - radius_mm*std::cos(degrees * PI / 180 - PI/2);
+        int tos = int(tox / stepx);
+
+        for(int i = 1; i <= tos; ++i) {
+            throw_on_cancel();
             ob = base_plate;
 
             double r2 = radius_mm * radius_mm;
-            double xx = i*stepx;
+            double xx = radius_mm - i*stepx;
             double x2 = xx*xx;
             double stepy = std::sqrt(r2 - x2);
-
             offset(ob, s*mm(xx));
-            wh = ceilheight_mm - radius_mm + stepy;
+            wh = ceilheight_mm - radius_mm - stepy;
 
             Contour3D pwalls;
-            pwalls = walls(ob, ob_prev, wh, wh_prev, throw_on_cancel);
+            pwalls = walls(ob_prev, ob, wh_prev, wh, throw_on_cancel);
 
             curvedwalls.merge(pwalls);
             ob_prev = ob;
@@ -257,28 +283,6 @@ Contour3D round_edges(const ExPolygon& base_plate,
         }
     }
 
-    double tox = radius_mm - radius_mm*std::sin(degrees * PI / 180);
-    int tos = int(tox / stepx);
-
-    for(int i = 1; i <= tos; ++i) {
-        throw_on_cancel();
-        ob = base_plate;
-
-        double r2 = radius_mm * radius_mm;
-        double xx = radius_mm - i*stepx;
-        double x2 = xx*xx;
-        double stepy = std::sqrt(r2 - x2);
-        offset(ob, s*mm(xx));
-        wh = ceilheight_mm - radius_mm - stepy;
-
-        Contour3D pwalls;
-        pwalls = walls(ob_prev, ob, wh_prev, wh, throw_on_cancel);
-
-        curvedwalls.merge(pwalls);
-        ob_prev = ob;
-        wh_prev = wh;
-    }
-
     last_offset = std::move(ob);
     last_height = wh;
 
@@ -543,23 +547,33 @@ void create_base_pool(const ExPolygons &ground_layer, TriangleMesh& out,
 
 
         // Generate the smoothed edge geometry
-        auto curvedwalls = round_edges(ob,
-                                       r,
-                                       phi,  // 170 degrees
-                                       0,    // z position of the input plane
-                                       true,
-                                       thrcl,
-                                       ob, wh);
-        pool.merge(curvedwalls);
+        auto walledges = round_edges(ob,
+                                     r,
+                                     phi,  // 170 degrees
+                                     0,    // z position of the input plane
+                                     true,
+                                     thrcl,
+                                     ob, wh);
+        pool.merge(walledges);
 
         // Now that we have the rounded edge connencting the top plate with
         // the outer side walls, we can generate and merge the sidewall geometry
         auto pwalls = walls(ob, inner_base, wh, -fullheight, thrcl);
         pool.merge(pwalls);
 
+        // Generate the smoothed edge geometry
+        auto cavityedges = round_edges(middle_base,
+                                       r,
+                                       phi - 90,  // 170 degrees
+                                       0,    // z position of the input plane
+                                       false,
+                                       thrcl,
+                                       ob, wh);
+        pool.merge(cavityedges);
+
         // Next is the cavity walls connecting to the top plate's artificially
         // created hole.
-        auto cavitywalls = walls(inner_base, middle_base, -wingheight, 0, thrcl);
+        auto cavitywalls = walls(inner_base, ob, -wingheight, wh, thrcl);
         pool.merge(cavitywalls);
 
         // Now we need to triangulate the top and bottom plates as well as the
@@ -580,105 +594,6 @@ void create_base_pool(const ExPolygons &ground_layer, TriangleMesh& out,
 
         out.merge(mesh(pool));
     }
-
-//    double mdist = 2*(1.8*cfg.min_wall_thickness_mm + 4*cfg.edge_radius_mm) +
-//                   cfg.max_merge_distance_mm;
-
-//    auto concavehs = concave_hull(ground_layer, mdist, cfg.throw_on_cancel);
-//    for(ExPolygon& concaveh : concavehs) {
-//        if(concaveh.contour.points.empty()) return;
-//        concaveh.holes.clear();
-
-//        const coord_t WALL_THICKNESS = mm(cfg.min_wall_thickness_mm);
-
-//        const coord_t WALL_DISTANCE = mm(2*cfg.edge_radius_mm) +
-//                                      coord_t(0.8*WALL_THICKNESS);
-
-//        const coord_t HEIGHT = mm(cfg.min_wall_height_mm);
-
-//        auto outer_base = concaveh;
-//        offset(outer_base, WALL_THICKNESS+WALL_DISTANCE);
-//        auto inner_base = outer_base;
-//        offset(inner_base, -WALL_THICKNESS);
-//        inner_base.holes.clear(); outer_base.holes.clear();
-
-//        ExPolygon top_poly;
-//        top_poly.contour = outer_base.contour;
-//        top_poly.holes.emplace_back(inner_base.contour);
-//        auto& tph = top_poly.holes.back().points;
-//        std::reverse(tph.begin(), tph.end());
-
-//        Contour3D pool;
-
-//        ExPolygon ob = outer_base; double wh = 0;
-
-//        // now we will calculate the angle or portion of the circle from
-//        // pi/2 that will connect perfectly with the bottom plate.
-//        // this is a tangent point calculation problem and the equation can
-//        // be found for example here:
-//        // http://www.ambrsoft.com/TrigoCalc/Circles2/CirclePoint/CirclePointDistance.htm
-//        // the y coordinate would be:
-//        // y = cy + (r^2*py - r*px*sqrt(px^2 + py^2 - r^2) / (px^2 + py^2)
-//        // where px and py are the coordinates of the point outside the circle
-//        // cx and cy are the circle center, r is the radius
-//        // to get the angle we use arcsin function and subtract 90 degrees then
-//        // flip the sign to get the right input to the round_edge function.
-//        double r = cfg.edge_radius_mm;
-//        double cy = 0;
-//        double cx = 0;
-//        double px = cfg.min_wall_thickness_mm;
-//        double py = r - cfg.min_wall_height_mm;
-
-//        double pxcx = px - cx;
-//        double pycy = py - cy;
-//        double b_2 = pxcx*pxcx + pycy*pycy;
-//        double r_2 = r*r;
-//        double D = std::sqrt(b_2 - r_2);
-//        double vy = (r_2*pycy - r*pxcx*D) / b_2;
-//        double phi = -(std::asin(vy/r) * 180 / PI - 90);
-
-//        auto curvedwalls = round_edges(ob,
-//                                       r,
-//                                       phi,  // 170 degrees
-//                                       0,    // z position of the input plane
-//                                       true,
-//                                       cfg.throw_on_cancel,
-//                                       ob, wh);
-
-//        pool.merge(curvedwalls);
-
-//        ExPolygon ob_contr = ob;
-//        ob_contr.holes.clear();
-
-//        auto pwalls = walls(ob_contr, inner_base, wh, -cfg.min_wall_height_mm,
-//                            cfg.throw_on_cancel);
-//        pool.merge(pwalls);
-
-//        Polygons top_triangles, bottom_triangles;
-//        triangulate(top_poly, top_triangles);
-//        triangulate(inner_base, bottom_triangles);
-//        auto top_plate = convert(top_triangles, 0, false);
-//        auto bottom_plate = convert(bottom_triangles, -HEIGHT, true);
-
-//        ob = inner_base; wh = 0;
-//        // rounded edge generation for the inner bed
-//        curvedwalls = round_edges(ob,
-//                                  cfg.edge_radius_mm,
-//                                  90,   // 90 degrees
-//                                  0,    // z position of the input plane
-//                                  false,
-//                                  cfg.throw_on_cancel,
-//                                  ob, wh);
-//        pool.merge(curvedwalls);
-
-//        auto innerbed = inner_bed(ob, cfg.min_wall_height_mm/2 + wh, wh);
-
-//        pool.merge(top_plate);
-//        pool.merge(bottom_plate);
-//        pool.merge(innerbed);
-
-//        out.merge(mesh(pool));
-//    }
 }
 
 }

From e269758df70ede2cc279d43e8c3e2c8b8066fce2 Mon Sep 17 00:00:00 2001
From: tamasmeszaros <meszaros.q@gmail.com>
Date: Tue, 8 Jan 2019 14:42:29 +0100
Subject: [PATCH 07/14] Don't generate the pad cavity if the depth is zero.

---
 src/libslic3r/SLA/SLABasePool.cpp | 61 ++++++++++++++++++-------------
 1 file changed, 35 insertions(+), 26 deletions(-)

diff --git a/src/libslic3r/SLA/SLABasePool.cpp b/src/libslic3r/SLA/SLABasePool.cpp
index fb68ae1d0..f1e79357d 100644
--- a/src/libslic3r/SLA/SLABasePool.cpp
+++ b/src/libslic3r/SLA/SLABasePool.cpp
@@ -498,21 +498,23 @@ void create_base_pool(const ExPolygons &ground_layer, TriangleMesh& out,
         // be rounded because we offset twice: ones to get the outer (top) plate
         // and again to get the inner (bottom) plate
         auto outer_base = concaveh;
+        outer_base.holes.clear();
         offset(outer_base, s_safety_dist + s_wingdist + s_thickness);
         auto inner_base = outer_base;
-        auto middle_base = outer_base;
         offset(inner_base, -(s_thickness + s_wingdist));
-        offset(middle_base, -s_thickness);
-        inner_base.holes.clear();   // bottom contour
-        middle_base.holes.clear();  // contour of the cavity-top
-        outer_base.holes.clear();   // bottom contour, also for the cavity
 
         // Punching a hole in the top plate for the cavity
         ExPolygon top_poly;
+        ExPolygon middle_base;
         top_poly.contour = outer_base.contour;
-        top_poly.holes.emplace_back(middle_base.contour);
-        auto& tph = top_poly.holes.back().points;
-        std::reverse(tph.begin(), tph.end());
+
+        if(wingheight > 0) {
+            middle_base = outer_base;
+            offset(middle_base, -s_thickness);
+            top_poly.holes.emplace_back(middle_base.contour);
+            auto& tph = top_poly.holes.back().points;
+            std::reverse(tph.begin(), tph.end());
+        }
 
         Contour3D pool;
 
@@ -549,7 +551,7 @@ void create_base_pool(const ExPolygons &ground_layer, TriangleMesh& out,
         // Generate the smoothed edge geometry
         auto walledges = round_edges(ob,
                                      r,
-                                     phi,  // 170 degrees
+                                     phi,
                                      0,    // z position of the input plane
                                      true,
                                      thrcl,
@@ -561,37 +563,44 @@ void create_base_pool(const ExPolygons &ground_layer, TriangleMesh& out,
         auto pwalls = walls(ob, inner_base, wh, -fullheight, thrcl);
         pool.merge(pwalls);
 
-        // Generate the smoothed edge geometry
-        auto cavityedges = round_edges(middle_base,
-                                       r,
-                                       phi - 90,  // 170 degrees
-                                       0,    // z position of the input plane
-                                       false,
-                                       thrcl,
-                                       ob, wh);
-        pool.merge(cavityedges);
+        if(wingheight > 0) {
+            // Generate the smoothed edge geometry
+            auto cavityedges = round_edges(middle_base,
+                                           r,
+                                           phi - 90, // from tangent lines
+                                           0,
+                                           false,
+                                           thrcl,
+                                           ob, wh);
+            pool.merge(cavityedges);
 
-        // Next is the cavity walls connecting to the top plate's artificially
-        // created hole.
-        auto cavitywalls = walls(inner_base, ob, -wingheight, wh, thrcl);
-        pool.merge(cavitywalls);
+            // Next is the cavity walls connecting to the top plate's
+            // artificially created hole.
+            auto cavitywalls = walls(inner_base, ob, -wingheight, wh, thrcl);
+            pool.merge(cavitywalls);
+        }
 
         // Now we need to triangulate the top and bottom plates as well as the
         // cavity bottom plate which is the same as the bottom plate but it is
         // eleveted by the thickness.
-        Polygons top_triangles, middle_triangles, bottom_triangles;
+        Polygons top_triangles, bottom_triangles;
 
         triangulate(top_poly, top_triangles);
-        triangulate(inner_base, middle_triangles);
         triangulate(inner_base, bottom_triangles);
+
         auto top_plate = convert(top_triangles, 0, false);
-        auto middle_plate = convert(middle_triangles, -mm(wingheight), false);
         auto bottom_plate = convert(bottom_triangles, -mm(fullheight), true);
 
         pool.merge(top_plate);
-        pool.merge(middle_plate);
         pool.merge(bottom_plate);
 
+        if(wingheight > 0) {
+            Polygons middle_triangles;
+            triangulate(inner_base, middle_triangles);
+            auto middle_plate = convert(middle_triangles, -mm(wingheight), false);
+            pool.merge(middle_plate);
+        }
+
         out.merge(mesh(pool));
     }
 }

From 7cf67db3321fa4bcae03405be6d6938777b5efa4 Mon Sep 17 00:00:00 2001
From: Enrico Turri <enricoturri@seznam.cz>
Date: Tue, 8 Jan 2019 15:16:40 +0100
Subject: [PATCH 08/14] Uniform scale is sidebar

---
 src/slic3r/GUI/GLCanvas3D.cpp             | 10 ++++++----
 src/slic3r/GUI/GUI_ObjectManipulation.cpp |  5 ++++-
 2 files changed, 10 insertions(+), 5 deletions(-)

diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp
index a6d0f4e9d..c8bd71754 100644
--- a/src/slic3r/GUI/GLCanvas3D.cpp
+++ b/src/slic3r/GUI/GLCanvas3D.cpp
@@ -2513,7 +2513,9 @@ void GLCanvas3D::Selection::_render_sidebar_rotation_hints(const std::string& si
 
 void GLCanvas3D::Selection::_render_sidebar_scale_hints(const std::string& sidebar_field) const
 {
-    if (boost::ends_with(sidebar_field, "x") || requires_uniform_scale())
+    bool uniform_scale = requires_uniform_scale() || wxGetApp().obj_manipul()->get_uniform_scaling();
+
+    if (boost::ends_with(sidebar_field, "x") || uniform_scale)
     {
         ::glPushMatrix();
         ::glRotated(-90.0, 0.0, 0.0, 1.0);
@@ -2521,14 +2523,14 @@ void GLCanvas3D::Selection::_render_sidebar_scale_hints(const std::string& sideb
         ::glPopMatrix();
     }
 
-    if (boost::ends_with(sidebar_field, "y") || requires_uniform_scale())
+    if (boost::ends_with(sidebar_field, "y") || uniform_scale)
     {
         ::glPushMatrix();
         _render_sidebar_scale_hint(Y);
         ::glPopMatrix();
     }
 
-    if (boost::ends_with(sidebar_field, "z") || requires_uniform_scale())
+    if (boost::ends_with(sidebar_field, "z") || uniform_scale)
     {
         ::glPushMatrix();
         ::glRotated(90.0, 1.0, 0.0, 0.0);
@@ -2559,7 +2561,7 @@ void GLCanvas3D::Selection::_render_sidebar_rotation_hint(Axis axis) const
 
 void GLCanvas3D::Selection::_render_sidebar_scale_hint(Axis axis) const
 {
-    m_arrow.set_color((requires_uniform_scale() ? UNIFORM_SCALE_COLOR : AXES_COLOR[axis]), 3);
+    m_arrow.set_color(((requires_uniform_scale() || wxGetApp().obj_manipul()->get_uniform_scaling()) ? UNIFORM_SCALE_COLOR : AXES_COLOR[axis]), 3);
 
     ::glTranslated(0.0, 5.0, 0.0);
     m_arrow.render();
diff --git a/src/slic3r/GUI/GUI_ObjectManipulation.cpp b/src/slic3r/GUI/GUI_ObjectManipulation.cpp
index 1cdf87be2..84025bae0 100644
--- a/src/slic3r/GUI/GUI_ObjectManipulation.cpp
+++ b/src/slic3r/GUI/GUI_ObjectManipulation.cpp
@@ -399,6 +399,9 @@ void ObjectManipulation::update_if_dirty()
 
     m_cache.rotation = m_new_rotation;
 
+//    if (wxGetApp().plater()->canvas3D()->get_selection().requires_uniform_scale())
+//        m_uniform_scale = true;
+
     if (m_new_enabled)
         m_og->enable();
     else
@@ -499,7 +502,7 @@ void ObjectManipulation::change_scale_value(const Vec3d& scale)
 {
     Vec3d scaling_factor = scale;
     const GLCanvas3D::Selection& selection = wxGetApp().plater()->canvas3D()->get_selection();
-    if (selection.requires_uniform_scale())
+    if (m_uniform_scale || selection.requires_uniform_scale())
     {
 #if ENABLE_IMPROVED_SIDEBAR_OBJECTS_MANIPULATION
         Vec3d abs_scale_diff = (scale - m_cache.scale).cwiseAbs();

From 2ccdfe68531265a51f6f5a7a8788cdbdf765b74f Mon Sep 17 00:00:00 2001
From: Enrico Turri <enricoturri@seznam.cz>
Date: Tue, 8 Jan 2019 15:26:27 +0100
Subject: [PATCH 09/14] Fixed typo

---
 src/libslic3r/Geometry.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/libslic3r/Geometry.cpp b/src/libslic3r/Geometry.cpp
index ba9c7b00e..fc5b158c7 100644
--- a/src/libslic3r/Geometry.cpp
+++ b/src/libslic3r/Geometry.cpp
@@ -1194,7 +1194,7 @@ Vec3d extract_euler_angles(const Eigen::Matrix<double, 3, 3, Eigen::DontAlign>&
     }
     else
     {
-        angles(1) = 0.0;
+        angles(0) = 0.0;
         angles(1) = ::atan2(-rotation_matrix(2, 0), sy);
         angles(2) = (angles(1) >-0.0) ? ::atan2(rotation_matrix(1, 2), rotation_matrix(1, 1)) : ::atan2(-rotation_matrix(1, 2), rotation_matrix(1, 1));
     }

From 6efcdd1ddf5bd57b110370cc314f275cded3fb2d Mon Sep 17 00:00:00 2001
From: YuSanka <yusanka@gmail.com>
Date: Tue, 8 Jan 2019 16:05:49 +0100
Subject: [PATCH 10/14] Added wxEVT_TEXT_ENTER handling for TextCtrl, SpinCtrl
 & PointCtrl (but it doesn't work under OSX) (fix of #1518)

---
 src/slic3r/GUI/Field.cpp | 97 ++++++++++++++++++++++++++--------------
 src/slic3r/GUI/Field.hpp | 12 +++--
 2 files changed, 72 insertions(+), 37 deletions(-)

diff --git a/src/slic3r/GUI/Field.cpp b/src/slic3r/GUI/Field.cpp
index 91052570d..2c7bce613 100644
--- a/src/slic3r/GUI/Field.cpp
+++ b/src/slic3r/GUI/Field.cpp
@@ -66,12 +66,8 @@ void Field::PostInitialize()
 	BUILD();
 }
 
-void Field::on_kill_focus(wxEvent& event)
+void Field::on_kill_focus()
 {
-    // Without this, there will be nasty focus bugs on Windows.
-    // Also, docs for wxEvent::Skip() say "In general, it is recommended to skip all 
-    // non-command events to allow the default handling to take place."
-	event.Skip();
 	// call the registered function if it is available
     if (m_on_kill_focus!=nullptr) 
         m_on_kill_focus(m_opt_id);
@@ -250,11 +246,23 @@ void TextCtrl::BUILD() {
 		break; 
 	}
 
-    const long style = m_opt.multiline ? wxTE_MULTILINE : 0;
+    const long style = m_opt.multiline ? wxTE_MULTILINE : wxTE_PROCESS_ENTER/*0*/;
 	auto temp = new wxTextCtrl(m_parent, wxID_ANY, text_value, wxDefaultPosition, size, style);
 
 	temp->SetToolTip(get_tooltip_text(text_value));
 
+    if (style == wxTE_PROCESS_ENTER) {
+        temp->Bind(wxEVT_TEXT_ENTER, ([this, temp](wxEvent& e)
+        {
+#if !defined(__WXGTK__)
+            e.Skip();
+            temp->GetToolTip()->Enable(true);
+#endif // __WXGTK__
+            propagate_value();
+            bEnterPressed = true;
+        }), temp->GetId());
+    }
+
     temp->Bind(wxEVT_SET_FOCUS, ([this](wxEvent& e) { on_set_focus(e); }), temp->GetId());
     
 	temp->Bind(wxEVT_LEFT_DOWN, ([temp](wxEvent& event)
@@ -272,14 +280,15 @@ void TextCtrl::BUILD() {
 
 	temp->Bind(wxEVT_KILL_FOCUS, ([this, temp](wxEvent& e)
 	{
-#if !defined(__WXGTK__)
 		e.Skip();
+#if !defined(__WXGTK__)
 		temp->GetToolTip()->Enable(true);
 #endif // __WXGTK__
-        if (is_defined_input_value<wxTextCtrl>(window, m_opt.type))
-            on_change_field();
-        else
-            on_kill_focus(e);
+        if (bEnterPressed) {
+            bEnterPressed = false;
+            return;
+        }
+        propagate_value();
 	}), temp->GetId());
     /*
         temp->Bind(wxEVT_TEXT, ([this](wxCommandEvent& evt)
@@ -311,6 +320,14 @@ void TextCtrl::BUILD() {
     window = dynamic_cast<wxWindow*>(temp);
 }	
 
+void TextCtrl::propagate_value()
+{
+    if (is_defined_input_value<wxTextCtrl>(window, m_opt.type))
+        on_change_field();
+    else
+        on_kill_focus();
+}
+
 boost::any& TextCtrl::get_value()
 {
 	wxString ret_str = static_cast<wxTextCtrl*>(window)->GetValue();
@@ -398,7 +415,7 @@ void SpinCtrl::BUILD() {
 	const int max_val = m_opt.max < 2147483647 ? m_opt.max : 2147483647;
 
 	auto temp = new wxSpinCtrl(m_parent, wxID_ANY, text_value, wxDefaultPosition, size,
-		0, min_val, max_val, default_value);
+		0|wxTE_PROCESS_ENTER, min_val, max_val, default_value);
 
 #ifndef __WXOSX__
     // #ys_FIXME_KILL_FOCUS 
@@ -407,15 +424,23 @@ void SpinCtrl::BUILD() {
     // and on TEXT event under OSX
 	temp->Bind(wxEVT_KILL_FOCUS, ([this](wxEvent& e)
 	{
-        if (tmp_value < 0)
-	        on_kill_focus(e);
-        else {
-            e.Skip();
-            on_change_field();
+        e.Skip();
+        if (bEnterPressed) {
+            bEnterPressed = false;
+            return;
         }
+
+        propagate_value();
 	}), temp->GetId());
 
-	temp->Bind(wxEVT_SPINCTRL, ([this](wxCommandEvent e) {  on_change_field();  }), temp->GetId());
+    temp->Bind(wxEVT_SPINCTRL, ([this](wxCommandEvent e) {  on_change_field();  }), temp->GetId()); 
+    
+    temp->Bind(wxEVT_TEXT_ENTER, ([this](wxCommandEvent e)
+    {
+        e.Skip();
+        propagate_value();
+        bEnterPressed = true;
+    }), temp->GetId());
 #endif
 
 	temp->Bind(wxEVT_TEXT, ([this](wxCommandEvent e)
@@ -430,12 +455,7 @@ void SpinCtrl::BUILD() {
 			tmp_value = std::stoi(value);
         else tmp_value = -9999;
 #ifdef __WXOSX__
-        if (tmp_value < 0) {
-            if (m_on_kill_focus != nullptr)
-                m_on_kill_focus(m_opt_id);
-        }
-        else 
-            on_change_field();
+        propagate_value();
 #endif
 	}), temp->GetId());
 	
@@ -445,6 +465,14 @@ void SpinCtrl::BUILD() {
 	window = dynamic_cast<wxWindow*>(temp);
 }
 
+void SpinCtrl::propagate_value()
+{
+    if (tmp_value < 0)
+        on_kill_focus();
+    else
+        on_change_field();
+}
+
 void Choice::BUILD() {
 	auto size = wxSize(wxDefaultSize);
 	if (m_opt.height >= 0) size.SetHeight(m_opt.height);
@@ -483,7 +511,7 @@ void Choice::BUILD() {
                     on_change_field();
             }
             else
-                on_kill_focus(e);
+                on_kill_focus();
         }), temp->GetId());
     }
 
@@ -755,8 +783,8 @@ void PointCtrl::BUILD()
 	val = default_pt(1);
 	wxString Y = val - int(val) == 0 ? wxString::Format(_T("%i"), int(val)) : wxNumberFormatter::ToString(val, 2, wxNumberFormatter::Style_None);
 
-	x_textctrl = new wxTextCtrl(m_parent, wxID_ANY, X, wxDefaultPosition, field_size);
-	y_textctrl = new wxTextCtrl(m_parent, wxID_ANY, Y, wxDefaultPosition, field_size);
+	x_textctrl = new wxTextCtrl(m_parent, wxID_ANY, X, wxDefaultPosition, field_size, wxEVT_TEXT_ENTER);
+	y_textctrl = new wxTextCtrl(m_parent, wxID_ANY, Y, wxDefaultPosition, field_size, wxEVT_TEXT_ENTER);
 
 	temp->Add(new wxStaticText(m_parent, wxID_ANY, "x : "), 0, wxALIGN_CENTER_VERTICAL, 0);
 	temp->Add(x_textctrl);
@@ -766,8 +794,11 @@ void PointCtrl::BUILD()
 // 	x_textctrl->Bind(wxEVT_TEXT, ([this](wxCommandEvent e) { on_change_field(); }), x_textctrl->GetId());
 // 	y_textctrl->Bind(wxEVT_TEXT, ([this](wxCommandEvent e) { on_change_field(); }), y_textctrl->GetId());
 
-    x_textctrl->Bind(wxEVT_KILL_FOCUS, ([this](wxEvent& e) { OnKillFocus(e, x_textctrl); }), x_textctrl->GetId());
-    y_textctrl->Bind(wxEVT_KILL_FOCUS, ([this](wxEvent& e) { OnKillFocus(e, x_textctrl); }), y_textctrl->GetId());
+    x_textctrl->Bind(wxEVT_TEXT_ENTER, ([this](wxCommandEvent e) { propagate_value(x_textctrl); }), x_textctrl->GetId());
+	y_textctrl->Bind(wxEVT_TEXT_ENTER, ([this](wxCommandEvent e) { propagate_value(y_textctrl); }), y_textctrl->GetId());
+
+    x_textctrl->Bind(wxEVT_KILL_FOCUS, ([this](wxEvent& e) { e.Skip(); propagate_value(x_textctrl); }), x_textctrl->GetId());
+    y_textctrl->Bind(wxEVT_KILL_FOCUS, ([this](wxEvent& e) { e.Skip(); propagate_value(y_textctrl); }), y_textctrl->GetId());
 
 	// 	// recast as a wxWindow to fit the calling convention
 	sizer = dynamic_cast<wxSizer*>(temp);
@@ -776,14 +807,12 @@ void PointCtrl::BUILD()
 	y_textctrl->SetToolTip(get_tooltip_text(X+", "+Y));
 }
 
-void PointCtrl::OnKillFocus(wxEvent& e, wxTextCtrl* win)
+void PointCtrl::propagate_value(wxTextCtrl* win)
 {
-    e.Skip();
-    if (!win->GetValue().empty()) {
+    if (!win->GetValue().empty()) 
         on_change_field();
-    }
     else
-        on_kill_focus(e);
+        on_kill_focus();
 }
 
 void PointCtrl::set_value(const Vec2d& value, bool change_event)
diff --git a/src/slic3r/GUI/Field.hpp b/src/slic3r/GUI/Field.hpp
index 4a19b6103..bcc94c7ba 100644
--- a/src/slic3r/GUI/Field.hpp
+++ b/src/slic3r/GUI/Field.hpp
@@ -74,7 +74,7 @@ protected:
     /// Call the attached on_kill_focus method. 
 	//! It's important to use wxEvent instead of wxFocusEvent,
 	//! in another case we can't unfocused control at all
-	void			on_kill_focus(wxEvent& event);
+	void			on_kill_focus();
     /// Call the attached on_change method. 
     void			on_set_focus(wxEvent& event);
     /// Call the attached on_change method. 
@@ -226,6 +226,8 @@ protected:
 
 	// current value
 	boost::any			m_value;
+
+    bool    bEnterPressed = false;
     
 	friend class OptionsGroup;
 };
@@ -252,6 +254,8 @@ public:
 	~TextCtrl() {}
 
     void BUILD();
+    // Propagate value from field to the OptionGroupe and Config after kill_focus/ENTER
+    void propagate_value();
     wxWindow* window {nullptr};
 
     virtual void	set_value(const std::string& value, bool change_event = false) {
@@ -310,6 +314,8 @@ public:
 
 	wxWindow*		window{ nullptr };
 	void			BUILD() override;
+    /// Propagate value from field to the OptionGroupe and Config after kill_focus/ENTER
+    void	        propagate_value() ;
 
 	void			set_value(const std::string& value, bool change_event = false) {
 		m_disable_change_event = !change_event;
@@ -393,8 +399,8 @@ public:
 	wxTextCtrl*		y_textctrl{ nullptr };
 
 	void			BUILD()  override;
-
-    void            OnKillFocus(wxEvent& e, wxTextCtrl* win);
+    // Propagate value from field to the OptionGroupe and Config after kill_focus/ENTER
+    void            propagate_value(wxTextCtrl* win);
 	void			set_value(const Vec2d& value, bool change_event = false);
 	void			set_value(const boost::any& value, bool change_event = false);
 	boost::any&		get_value() override;

From 6d7e2b2dd76348b49c54f51be66ebc36ac8617a6 Mon Sep 17 00:00:00 2001
From: YuSanka <yusanka@gmail.com>
Date: Wed, 9 Jan 2019 08:48:25 +0100
Subject: [PATCH 11/14] Added SetLock() function for PrusaLockButton

---
 src/slic3r/GUI/GUI_ObjectManipulation.cpp | 8 ++++++--
 src/slic3r/GUI/GUI_ObjectManipulation.hpp | 2 ++
 src/slic3r/GUI/wxExtensions.cpp           | 6 ++++++
 src/slic3r/GUI/wxExtensions.hpp           | 1 +
 4 files changed, 15 insertions(+), 2 deletions(-)

diff --git a/src/slic3r/GUI/GUI_ObjectManipulation.cpp b/src/slic3r/GUI/GUI_ObjectManipulation.cpp
index 84025bae0..17371ccf6 100644
--- a/src/slic3r/GUI/GUI_ObjectManipulation.cpp
+++ b/src/slic3r/GUI/GUI_ObjectManipulation.cpp
@@ -172,6 +172,7 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent) :
                     event.Skip();
                     wxTheApp->CallAfter([btn, this]() { set_uniform_scaling(btn->IsLocked()); });
                 });
+                m_lock_bnt = btn;
                 return btn;
             };
         }
@@ -399,8 +400,11 @@ void ObjectManipulation::update_if_dirty()
 
     m_cache.rotation = m_new_rotation;
 
-//    if (wxGetApp().plater()->canvas3D()->get_selection().requires_uniform_scale())
-//        m_uniform_scale = true;
+    if (wxGetApp().plater()->canvas3D()->get_selection().requires_uniform_scale()) {
+//         m_uniform_scale = true;
+        m_lock_bnt->SetLock(true);
+//         m_lock_bnt->Disable();
+    }
 
     if (m_new_enabled)
         m_og->enable();
diff --git a/src/slic3r/GUI/GUI_ObjectManipulation.hpp b/src/slic3r/GUI/GUI_ObjectManipulation.hpp
index 57eb93b71..d0afa528e 100644
--- a/src/slic3r/GUI/GUI_ObjectManipulation.hpp
+++ b/src/slic3r/GUI/GUI_ObjectManipulation.hpp
@@ -7,6 +7,7 @@
 #include "GLCanvas3D.hpp"
 
 class wxStaticText;
+class PrusaLockButton;
 
 namespace Slic3r {
 namespace GUI {
@@ -75,6 +76,7 @@ class ObjectManipulation : public OG_Settings
     Vec3d           m_new_size;
     bool            m_new_enabled;
     bool            m_uniform_scale {false};
+    PrusaLockButton* m_lock_bnt{ nullptr };
 
 public:
     ObjectManipulation(wxWindow* parent);
diff --git a/src/slic3r/GUI/wxExtensions.cpp b/src/slic3r/GUI/wxExtensions.cpp
index 466580074..9ffa649cc 100644
--- a/src/slic3r/GUI/wxExtensions.cpp
+++ b/src/slic3r/GUI/wxExtensions.cpp
@@ -2216,6 +2216,12 @@ void PrusaLockButton::OnButton(wxCommandEvent& event)
     event.Skip();
 }
 
+void PrusaLockButton::SetLock(bool lock)
+{
+    m_is_pushed = lock;
+    enter_button(true);
+}
+
 void PrusaLockButton::enter_button(const bool enter)
 {
     wxBitmap* icon = m_is_pushed ?
diff --git a/src/slic3r/GUI/wxExtensions.hpp b/src/slic3r/GUI/wxExtensions.hpp
index b951c5635..b6f7a4220 100644
--- a/src/slic3r/GUI/wxExtensions.hpp
+++ b/src/slic3r/GUI/wxExtensions.hpp
@@ -851,6 +851,7 @@ public:
     void    OnLeaveBtn(wxMouseEvent& event) { enter_button(false); event.Skip(); }
 
     bool    IsLocked() const { return m_is_pushed; }
+    void    SetLock(bool lock);
 
 protected:
     void    enter_button(const bool enter);

From 410211a3e44e60bd6fbc2284b86b457f60a268f5 Mon Sep 17 00:00:00 2001
From: Enrico Turri <enricoturri@seznam.cz>
Date: Wed, 9 Jan 2019 09:47:05 +0100
Subject: [PATCH 12/14] Completed uniform scale in sidebar

---
 src/slic3r/GUI/GUI_ObjectManipulation.cpp | 9 ++++++---
 src/slic3r/GUI/wxExtensions.cpp           | 1 +
 2 files changed, 7 insertions(+), 3 deletions(-)

diff --git a/src/slic3r/GUI/GUI_ObjectManipulation.cpp b/src/slic3r/GUI/GUI_ObjectManipulation.cpp
index 17371ccf6..a03b0a212 100644
--- a/src/slic3r/GUI/GUI_ObjectManipulation.cpp
+++ b/src/slic3r/GUI/GUI_ObjectManipulation.cpp
@@ -401,9 +401,12 @@ void ObjectManipulation::update_if_dirty()
     m_cache.rotation = m_new_rotation;
 
     if (wxGetApp().plater()->canvas3D()->get_selection().requires_uniform_scale()) {
-//         m_uniform_scale = true;
         m_lock_bnt->SetLock(true);
-//         m_lock_bnt->Disable();
+        m_lock_bnt->Disable();
+    }
+    else {
+        m_lock_bnt->SetLock(m_uniform_scale);
+        m_lock_bnt->Enable();
     }
 
     if (m_new_enabled)
@@ -562,7 +565,7 @@ void ObjectManipulation::change_size_value(const Vec3d& size)
     Vec3d scale = 100.0 * Vec3d(size(0) / ref_size(0), size(1) / ref_size(1), size(2) / ref_size(2));
     Vec3d scaling_factor = scale;
 
-    if (selection.requires_uniform_scale())
+    if (m_uniform_scale || selection.requires_uniform_scale())
     {
         Vec3d abs_scale_diff = (scale - m_cache.scale).cwiseAbs();
         double max_diff = abs_scale_diff(X);
diff --git a/src/slic3r/GUI/wxExtensions.cpp b/src/slic3r/GUI/wxExtensions.cpp
index 9ffa649cc..61aee6a67 100644
--- a/src/slic3r/GUI/wxExtensions.cpp
+++ b/src/slic3r/GUI/wxExtensions.cpp
@@ -2201,6 +2201,7 @@ PrusaLockButton::PrusaLockButton(   wxWindow *parent,
     SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW));
 #endif // __WXMSW__
     SetBitmap(m_bmp_unlock_on);
+    SetBitmapDisabled(m_bmp_lock_on);
 
     //button events
     Bind(wxEVT_BUTTON,          &PrusaLockButton::OnButton, this);

From abc38ebc824cd151ca5c612a4583b4a23dac615e Mon Sep 17 00:00:00 2001
From: Enrico Turri <enricoturri@seznam.cz>
Date: Wed, 9 Jan 2019 10:12:04 +0100
Subject: [PATCH 13/14] Fixed orientation of visual hints for sidebar scale
 fields

---
 src/slic3r/GUI/GLCanvas3D.cpp | 13 +++++++++----
 1 file changed, 9 insertions(+), 4 deletions(-)

diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp
index c8bd71754..9d70fbc1b 100644
--- a/src/slic3r/GUI/GLCanvas3D.cpp
+++ b/src/slic3r/GUI/GLCanvas3D.cpp
@@ -2039,11 +2039,17 @@ void GLCanvas3D::Selection::render_sidebar_hints(const std::string& sidebar_fiel
     const Vec3d& center = get_bounding_box().center();
 
     if (is_single_full_instance())
+    {
         ::glTranslated(center(0), center(1), center(2));
+        if (boost::starts_with(sidebar_field, "scale"))
+        {
+            Transform3d orient_matrix = (*m_volumes)[*m_list.begin()]->get_instance_transformation().get_matrix(true, false, true, true);
+            ::glMultMatrixd(orient_matrix.data());
+        }
+    }
     else if (is_single_volume() || is_single_modifier())
     {
-        const GLVolume* volume = (*m_volumes)[*m_list.begin()];
-        Transform3d orient_matrix = volume->get_instance_transformation().get_matrix(true, false, true, true);
+        Transform3d orient_matrix = (*m_volumes)[*m_list.begin()]->get_instance_transformation().get_matrix(true, false, true, true);
         const Vec3d& offset = get_bounding_box().center();
 
         ::glTranslated(offset(0), offset(1), offset(2));
@@ -2054,8 +2060,7 @@ void GLCanvas3D::Selection::render_sidebar_hints(const std::string& sidebar_fiel
         ::glTranslated(center(0), center(1), center(2));
         if (requires_local_axes())
         {
-            const GLVolume* volume = (*m_volumes)[*m_list.begin()];
-            Transform3d orient_matrix = volume->get_instance_transformation().get_matrix(true, false, true, true);
+            Transform3d orient_matrix = (*m_volumes)[*m_list.begin()]->get_instance_transformation().get_matrix(true, false, true, true);
             ::glMultMatrixd(orient_matrix.data());
         }
     }

From 2dadf4b5dc153f734d4b095d62d99224dc0502c7 Mon Sep 17 00:00:00 2001
From: YuSanka <yusanka@gmail.com>
Date: Wed, 9 Jan 2019 10:30:29 +0100
Subject: [PATCH 14/14] Fixed a crash after settings adding for the instance
 from the scene's context menu

---
 src/slic3r/GUI/GUI_ObjectList.cpp | 11 +++++++++--
 1 file changed, 9 insertions(+), 2 deletions(-)

diff --git a/src/slic3r/GUI/GUI_ObjectList.cpp b/src/slic3r/GUI/GUI_ObjectList.cpp
index 729946dbf..bc54b2321 100644
--- a/src/slic3r/GUI/GUI_ObjectList.cpp
+++ b/src/slic3r/GUI/GUI_ObjectList.cpp
@@ -633,8 +633,10 @@ void ObjectList::get_settings_choice(const wxString& category_name)
 
 
     // Add settings item for object
-    const auto item = GetSelection();
+    auto item = GetSelection();
     if (item) {
+        if (m_objects_model->GetItemType(item) == itInstance)
+            item = m_objects_model->GetTopParent(item);
         const auto settings_item = m_objects_model->IsSettingsItem(item) ? item : m_objects_model->GetSettingsItem(item);
         select_item(settings_item ? settings_item :
             m_objects_model->AddSettingsChild(item));
@@ -903,7 +905,8 @@ void ObjectList::load_generic_subobject(const std::string& type_name, const int
     m_parts_changed = true;
     parts_changed(obj_idx);
 
-    select_item(m_objects_model->AddVolumeChild(GetSelection(), from_u8(name), type));
+    const auto object_item = m_objects_model->GetTopParent(GetSelection());
+    select_item(m_objects_model->AddVolumeChild(object_item, from_u8(name), type));
 #ifndef __WXOSX__ //#ifdef __WXMSW__ // #ys_FIXME
     selection_changed();
 #endif //no __WXOSX__ //__WXMSW__
@@ -1156,6 +1159,10 @@ void ObjectList::part_selection_changed()
                 else if (m_objects_model->GetItemType(item) == itInstance) {
                     og_name = _(L("Instance manipulation"));
                     update_and_show_manipulations = true;
+
+                    // fill m_config by object's values
+                    const int obj_idx_ = m_objects_model->GetObjectIdByItem(item);
+                    m_config = &(*m_objects)[obj_idx_]->config;
                 }
             }