diff --git a/CMakeLists.txt b/CMakeLists.txt
index 90ebd1e5b..1e6cf45bd 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -34,6 +34,8 @@ option(SLIC3R_PERL_XS           "Compile XS Perl module and enable Perl unit and
 option(SLIC3R_ASAN              "Enable ASan on Clang and GCC" 0)
 option(SLIC3R_SYNTAXONLY        "Only perform source code correctness checking, no binary output (UNIX only)" 0)
 
+set(SLIC3R_GTK "2" CACHE STRING "GTK version to use with wxWidgets on Linux")
+
 # Proposal for C++ unit tests and sandboxes
 option(SLIC3R_BUILD_SANDBOXES   "Build development sandboxes" OFF)
 option(SLIC3R_BUILD_TESTS       "Build unit tests" OFF)
diff --git a/doc/How to build - Windows.md b/doc/How to build - Windows.md
index 627f1c99b..020b28958 100644
--- a/doc/How to build - Windows.md	
+++ b/doc/How to build - Windows.md	
@@ -91,6 +91,10 @@ You can also use the Visual Studio GUI or other generators as mentioned above.
 The `DESTDIR` option is the location where the bundle will be installed.
 This may be customized. If you leave it empty, the `DESTDIR` will be places inside the same `build` directory.
 
+Warning: If the `build` directory is nested too deep inside other folders, various file paths during the build
+become too long and the build might fail due to file writing errors. For this reason, it is recommended to
+place the `build` directory relatively close to the drive root.
+
 Note that the build variant that you may choose using Visual Studio (i.e. _Release_ or _Debug_ etc.) when building the dependency package is **not relevant**.
 The dependency build will by default build _both_ the _Release_ and _Debug_ variants regardless of what you choose in Visual Studio.
 You can disable building of the debug variant by passing the `-DDEP_DEBUG=OFF` option to CMake, this will only produce a _Release_ build.
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index aae3436ae..a6ae94391 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -60,6 +60,7 @@ if (SLIC3R_GUI)
     endif()
 
     if (CMAKE_SYSTEM_NAME STREQUAL "Linux")
+        set (wxWidgets_CONFIG_OPTIONS "--toolkit=gtk${SLIC3R_GTK}")
         if (SLIC3R_WX_STABLE)
             find_package(wxWidgets 3.0 REQUIRED COMPONENTS base core adv html gl)
         else ()
diff --git a/src/libslic3r/Format/AMF.cpp b/src/libslic3r/Format/AMF.cpp
index f5219263d..ff1da37cc 100644
--- a/src/libslic3r/Format/AMF.cpp
+++ b/src/libslic3r/Format/AMF.cpp
@@ -175,6 +175,11 @@ struct AMFParserContext
         bool  mirrory_set;
         float mirrorz;
         bool  mirrorz_set;
+
+        bool anything_set() const { return deltax_set || deltay_set || deltaz_set ||
+                                           rx_set || ry_set || rz_set ||
+                                           scalex_set || scaley_set || scalez_set ||
+                                           mirrorx_set || mirrory_set || mirrorz_set; }
     };
 
     struct Object {
@@ -644,11 +649,7 @@ void AMFParserContext::endDocument()
             continue;
         }
         for (const Instance &instance : object.second.instances)
-#if ENABLE_VOLUMES_CENTERING_FIXES
-        {
-#else
-            if (instance.deltax_set && instance.deltay_set) {
-#endif // ENABLE_VOLUMES_CENTERING_FIXES
+            if (instance.anything_set()) {
                 ModelInstance *mi = m_model.objects[object.second.idx]->add_instance();
                 mi->set_offset(Vec3d(instance.deltax_set ? (double)instance.deltax : 0.0, instance.deltay_set ? (double)instance.deltay : 0.0, instance.deltaz_set ? (double)instance.deltaz : 0.0));
                 mi->set_rotation(Vec3d(instance.rx_set ? (double)instance.rx : 0.0, instance.ry_set ? (double)instance.ry : 0.0, instance.rz_set ? (double)instance.rz : 0.0));
diff --git a/src/libslic3r/MTUtils.hpp b/src/libslic3r/MTUtils.hpp
index 1e0fb426a..1f6ca1a23 100644
--- a/src/libslic3r/MTUtils.hpp
+++ b/src/libslic3r/MTUtils.hpp
@@ -56,6 +56,113 @@ public:
     }
 };
 
+template<class Vector,
+         class Value = typename Vector::value_type>
+class IndexBasedIterator {
+    static const size_t NONE = size_t(-1);
+
+    std::reference_wrapper<Vector> m_index_ref;
+    size_t m_idx = NONE;
+public:
+
+    using value_type = Value;
+    using pointer = Value *;
+    using reference = Value &;
+    using difference_type = long;
+    using iterator_category = std::random_access_iterator_tag;
+
+    inline explicit
+    IndexBasedIterator(Vector& index, size_t idx):
+        m_index_ref(index), m_idx(idx) {}
+
+    // Post increment
+    inline IndexBasedIterator operator++(int) {
+        IndexBasedIterator cpy(*this); ++m_idx; return cpy;
+    }
+
+    inline IndexBasedIterator operator--(int) {
+        IndexBasedIterator cpy(*this); --m_idx; return cpy;
+    }
+
+    inline IndexBasedIterator& operator++() {
+        ++m_idx; return *this;
+    }
+
+    inline IndexBasedIterator& operator--() {
+        --m_idx; return *this;
+    }
+
+    inline IndexBasedIterator& operator+=(difference_type l) {
+        m_idx += size_t(l); return *this;
+    }
+
+    inline IndexBasedIterator operator+(difference_type l) {
+        auto cpy = *this; cpy += l; return cpy;
+    }
+
+    inline IndexBasedIterator& operator-=(difference_type l) {
+        m_idx -= size_t(l); return *this;
+    }
+
+    inline IndexBasedIterator operator-(difference_type l) {
+        auto cpy = *this; cpy -= l; return cpy;
+    }
+
+    operator difference_type() { return difference_type(m_idx); }
+
+    inline bool is_end() const { return m_idx >= m_index_ref.get().size();}
+
+    inline Value & operator*() const {
+        assert(m_idx < m_index_ref.get().size());
+        return m_index_ref.get().operator[](m_idx);
+    }
+
+    inline Value * operator->() const {
+        assert(m_idx < m_index_ref.get().size());
+        return &m_index_ref.get().operator[](m_idx);
+    }
+
+    inline bool operator ==(const IndexBasedIterator& other) {
+        size_t e = m_index_ref.get().size();
+        return m_idx == other.m_idx || (m_idx >= e && other.m_idx >= e);
+    }
+
+    inline bool operator !=(const IndexBasedIterator& other) {
+        return !(*this == other);
+    }
+
+    inline bool operator <=(const IndexBasedIterator& other) {
+        return (m_idx < other.m_idx) || (*this == other);
+    }
+
+    inline bool operator <(const IndexBasedIterator& other) {
+        return m_idx < other.m_idx && (*this != other);
+    }
+
+    inline bool operator >=(const IndexBasedIterator& other) {
+        return m_idx > other.m_idx || *this == other;
+    }
+
+    inline bool operator >(const IndexBasedIterator& other) {
+        return m_idx > other.m_idx && *this != other;
+    }
+};
+
+template<class It> class Range {
+    It from, to;
+public:
+    It begin() const { return from; }
+    It end() const { return to; }
+    using Type = It;
+
+    Range() = default;
+    Range(It &&b, It &&e):
+        from(std::forward<It>(b)), to(std::forward<It>(e)) {}
+
+    inline size_t size() const { return end() - begin(); }
+    inline bool empty() const { return size() == 0; }
+};
+
 }
 
 #endif // MTUTILS_HPP
diff --git a/src/libslic3r/SLA/SLASupportTree.cpp b/src/libslic3r/SLA/SLASupportTree.cpp
index df9990822..34dd80cee 100644
--- a/src/libslic3r/SLA/SLASupportTree.cpp
+++ b/src/libslic3r/SLA/SLASupportTree.cpp
@@ -2240,6 +2240,18 @@ SlicedSupports SLASupportTree::slice(float layerh, float init_layerh) const
     return ret;
 }
 
+SlicedSupports SLASupportTree::slice(const std::vector<float> &heights,
+                                     float cr) const
+{
+    TriangleMesh fullmesh = m_impl->merged_mesh();
+    fullmesh.merge(get_pad());
+    TriangleMeshSlicer slicer(&fullmesh);
+    SlicedSupports ret;
+    slicer.slice(heights, cr, &ret, get().ctl().cancelfn);
+
+    return ret;
+}
+
 const TriangleMesh &SLASupportTree::add_pad(const SliceLayer& baseplate,
                                             const PoolConfig& pcfg) const
 {
diff --git a/src/libslic3r/SLA/SLASupportTree.hpp b/src/libslic3r/SLA/SLASupportTree.hpp
index 74d7da9ca..66677e4d7 100644
--- a/src/libslic3r/SLA/SLASupportTree.hpp
+++ b/src/libslic3r/SLA/SLASupportTree.hpp
@@ -181,6 +181,8 @@ public:
     /// Get the sliced 2d layers of the support geometry.
     SlicedSupports slice(float layerh, float init_layerh = -1.0) const;
 
+    SlicedSupports slice(const std::vector<float>&, float closing_radius) const;
+
     /// Adding the "pad" (base pool) under the supports
     const TriangleMesh& add_pad(const SliceLayer& baseplate,
                                 const PoolConfig& pcfg) const;
diff --git a/src/libslic3r/SLAPrint.cpp b/src/libslic3r/SLAPrint.cpp
index 83fa61fdd..79834908f 100644
--- a/src/libslic3r/SLAPrint.cpp
+++ b/src/libslic3r/SLAPrint.cpp
@@ -30,7 +30,6 @@ public:
     std::vector<sla::SupportPoint> support_points;     // all the support points (manual/auto)
     SupportTreePtr   support_tree_ptr;   // the supports
     SlicedSupports   support_slices;     // sliced supports
-    std::vector<LevelID>    level_ids;
 
     inline SupportData(const TriangleMesh& trmesh): emesh(trmesh) {}
 };
@@ -567,6 +566,18 @@ sla::SupportConfig make_support_cfg(const SLAPrintObjectConfig& c) {
     return scfg;
 }
 
+sla::PoolConfig make_pool_config(const SLAPrintObjectConfig& c) {
+    sla::PoolConfig pcfg;
+
+    pcfg.min_wall_thickness_mm = c.pad_wall_thickness.getFloat();
+    pcfg.wall_slope = c.pad_wall_slope.getFloat();
+    pcfg.edge_radius_mm = c.pad_edge_radius.getFloat();
+    pcfg.max_merge_distance_mm = c.pad_max_merge_distance.getFloat();
+    pcfg.min_wall_height_mm = c.pad_wall_height.getFloat();
+
+    return pcfg;
+}
+
 void swapXY(ExPolygon& expoly) {
     for(auto& p : expoly.contour.points) std::swap(p(X), p(Y));
     for(auto& h : expoly.holes) for(auto& p : h.points) std::swap(p(X), p(Y));
@@ -591,25 +602,9 @@ std::string SLAPrint::validate() const
     return "";
 }
 
-std::vector<float> SLAPrint::calculate_heights(const BoundingBoxf3& bb3d,
-                                               float elevation,
-                                               float initial_layer_height,
-                                               float layer_height) const
-{
-    std::vector<float> heights;
-    float minZ = float(bb3d.min(Z)) - float(elevation);
-    float maxZ = float(bb3d.max(Z));
-    auto flh = float(layer_height);
-    auto gnd = float(bb3d.min(Z));
-
-    for(float h = minZ + initial_layer_height; h < maxZ; h += flh)
-        if(h >= gnd) heights.emplace_back(h);
-
-    return heights;
-}
-
 template<class...Args>
-void report_status(SLAPrint& p, int st, const std::string& msg, Args&&...args) {
+void report_status(SLAPrint& p, int st, const std::string& msg, Args&&...args)
+{
     BOOST_LOG_TRIVIAL(info) << st << "% " << msg;
     p.set_status(st, msg, std::forward<Args>(args)...);
 }
@@ -620,12 +615,19 @@ void SLAPrint::process()
     using namespace sla;
     using ExPolygon = Slic3r::ExPolygon;
 
+    if(m_objects.empty()) return;
+
     // Assumption: at this point the print objects should be populated only with
     // the model objects we have to process and the instances are also filtered
 
     // shortcut to initial layer height
     double ilhd = m_material_config.initial_layer_height.getFloat();
     auto   ilh  = float(ilhd);
+    double lhd  = m_objects.front()->m_config.layer_height.getFloat();
+    float  lh   = float(lhd);
+
+    auto ilhs = LevelID(ilhd / SCALING_FACTOR);
+    auto lhs  = LevelID(lhd  / SCALING_FACTOR);
     const size_t objcount = m_objects.size();
 
     const unsigned min_objstatus = 0;   // where the per object operations start
@@ -646,24 +648,59 @@ void SLAPrint::process()
 
     // Slicing the model object. This method is oversimplified and needs to
     // be compared with the fff slicing algorithm for verification
-    auto slice_model = [this, ilh](SLAPrintObject& po) {
-        double lh = po.m_config.layer_height.getFloat();
-
+    auto slice_model = [this, ilhs, lhs, ilh, lh](SLAPrintObject& po) {
         TriangleMesh mesh = po.transformed_mesh();
+
+        // We need to prepare the slice index...
+
+        auto&& bb3d = mesh.bounding_box();
+        double minZ = bb3d.min(Z) - po.get_elevation();
+        double maxZ = bb3d.max(Z);
+
+        auto minZs = LevelID(minZ / SCALING_FACTOR);
+        auto maxZs = LevelID(maxZ / SCALING_FACTOR);
+
+        po.m_slice_index.clear();
+        po.m_slice_index.reserve(size_t(maxZs - (minZs + ilhs) / lhs) + 1);
+        po.m_slice_index.emplace_back(minZs + ilhs, float(minZ) + ilh / 2.f, ilh);
+
+        for(LevelID h = minZs + ilhs + lhs; h <= maxZs; h += lhs) {
+            po.m_slice_index.emplace_back(h, float(h*SCALING_FACTOR) - lh / 2.f, lh);
+        }
+
+        auto slindex_it = po.search_slice_index(float(bb3d.min(Z)));
+
+        if(slindex_it == po.m_slice_index.end())
+            throw std::runtime_error(L("Slicing had to be stopped "
+                                       "due to an internal error."));
+
+        po.m_model_height_levels.clear();
+        po.m_model_height_levels.reserve(po.m_slice_index.size());
+        for(auto it = slindex_it; it != po.m_slice_index.end(); ++it)
+        {
+            po.m_model_height_levels.emplace_back(it->slice_level());
+        }
+
         TriangleMeshSlicer slicer(&mesh);
 
-        // The 1D grid heights
-        std::vector<float> heights = calculate_heights(mesh.bounding_box(),
-                                                       float(po.get_elevation()),
-                                                       ilh, float(lh));
+        po.m_model_slices.clear();
+        slicer.slice(po.m_model_height_levels,
+                     float(po.config().slice_closing_radius.value),
+                     &po.m_model_slices,
+                     [this](){ throw_if_canceled(); });
 
-        auto& layers = po.m_model_slices; layers.clear();
-		slicer.slice(heights, float(po.config().slice_closing_radius.value), &layers, [this](){ throw_if_canceled(); });
+        auto mit = slindex_it;
+        for(size_t id = 0;
+            id < po.m_model_slices.size() && mit != po.m_slice_index.end();
+            id++)
+        {
+            mit->set_model_slice_idx(id); ++mit;
+        }
     };
 
     // In this step we check the slices, identify island and cover them with
     // support points. Then we sprinkle the rest of the mesh.
-    auto support_points = [this, ilh](SLAPrintObject& po) {
+    auto support_points = [this](SLAPrintObject& po) {
         const ModelObject& mo = *po.m_model_object;
         po.m_supportdata.reset(
                     new SLAPrintObject::SupportData(po.transformed_mesh()) );
@@ -680,12 +717,7 @@ void SLAPrint::process()
         if (mo.sla_points_status != sla::PointsStatus::UserModified) {
 
             // calculate heights of slices (slices are calculated already)
-            double lh = po.m_config.layer_height.getFloat();
-
-            std::vector<float> heights =
-                    calculate_heights(po.transformed_mesh().bounding_box(),
-                                      float(po.get_elevation()),
-                                      ilh, float(lh));
+            const std::vector<float>& heights = po.m_model_height_levels;
 
             this->throw_if_canceled();
             SLAAutoSupports::Config config;
@@ -831,86 +863,34 @@ void SLAPrint::process()
     // Slicing the support geometries similarly to the model slicing procedure.
     // If the pad had been added previously (see step "base_pool" than it will
     // be part of the slices)
-    auto slice_supports = [ilh](SLAPrintObject& po) {
+    auto slice_supports = [](SLAPrintObject& po) {
         auto& sd = po.m_supportdata;
+
+        if(sd) sd->support_slices.clear();
+
         if(sd && sd->support_tree_ptr) {
-            auto lh = float(po.m_config.layer_height.getFloat());
-            sd->support_slices = sd->support_tree_ptr->slice(lh, ilh);
+
+            std::vector<float> heights; heights.reserve(po.m_slice_index.size());
+
+            for(auto& rec : po.m_slice_index) {
+                heights.emplace_back(rec.slice_level());
+            }
+
+            sd->support_slices = sd->support_tree_ptr->slice(
+                        heights, float(po.config().slice_closing_radius.value));
+        }
+
+        for(size_t i = 0;
+            i < sd->support_slices.size() && i < po.m_slice_index.size();
+            ++i)
+        {
+            po.m_slice_index[i].set_support_slice_idx(i);
         }
     };
 
     // We have the layer polygon collection but we need to unite them into
     // an index where the key is the height level in discrete levels (clipper)
-    auto index_slices = [this, ilhd](SLAPrintObject& po) {
-        po.m_slice_index.clear();
-        auto sih = LevelID(scale_(ilhd));
-
-        // Establish the slice grid boundaries
-        auto bb = po.transformed_mesh().bounding_box();
-        double modelgnd = bb.min(Z);
-        double elevation = po.get_elevation();
-        double lh = po.m_config.layer_height.getFloat();
-        double minZ = modelgnd - elevation;
-
-        // scaled values:
-        auto sminZ = LevelID(scale_(minZ));
-        auto smaxZ = LevelID(scale_(bb.max(Z)));
-        auto smodelgnd = LevelID(scale_(modelgnd));
-        auto slh = LevelID(scale_(lh));
-
-        // It is important that the next levels match the levels in
-        // model_slice method. Only difference is that here it works with
-        // scaled coordinates
-        po.m_level_ids.clear();
-        for(LevelID h = sminZ + sih; h < smaxZ; h += slh)
-            if(h >= smodelgnd) po.m_level_ids.emplace_back(h);
-
-        std::vector<ExPolygons>& oslices = po.m_model_slices;
-
-        // If everything went well this code should not run at all, but
-        // let's be robust...
-        // assert(levelids.size() == oslices.size());
-        if(po.m_level_ids.size() < oslices.size()) { // extend the levels until...
-
-            BOOST_LOG_TRIVIAL(warning)
-                    << "Height level mismatch at rasterization!\n";
-
-            LevelID lastlvl = po.m_level_ids.back();
-            while(po.m_level_ids.size() < oslices.size()) {
-                lastlvl += slh;
-                po.m_level_ids.emplace_back(lastlvl);
-            }
-        }
-
-        for(size_t i = 0; i < oslices.size(); ++i) {
-            LevelID h = po.m_level_ids[i];
-
-            float fh = float(double(h) * SCALING_FACTOR);
-
-            // now for the public slice index:
-            SLAPrintObject::SliceRecord& sr = po.m_slice_index[fh];
-            // There should be only one slice layer for each print object
-            assert(sr.model_slices_idx == SLAPrintObject::SliceRecord::NONE);
-            sr.model_slices_idx = i;
-        }
-
-        if(po.m_supportdata) { // deal with the support slices if present
-            std::vector<ExPolygons>& sslices = po.m_supportdata->support_slices;
-            po.m_supportdata->level_ids.clear();
-            po.m_supportdata->level_ids.reserve(sslices.size());
-
-            for(int i = 0; i < int(sslices.size()); ++i) {
-                LevelID h = sminZ + sih + i * slh;
-                po.m_supportdata->level_ids.emplace_back(h);
-
-                float fh = float(double(h) * SCALING_FACTOR);
-
-                SLAPrintObject::SliceRecord& sr = po.m_slice_index[fh];
-                assert(sr.support_slices_idx == SLAPrintObject::SliceRecord::NONE);
-                sr.support_slices_idx = SLAPrintObject::SliceRecord::Idx(i);
-            }
-        }
-
+    auto index_slices = [this/*, ilhd*/](SLAPrintObject& /*po*/) {
         // Using RELOAD_SLA_PREVIEW to tell the Plater to pass the update status to the 3D preview to load the SLA slices.
         report_status(*this, -2, "", SlicingStatus::RELOAD_SLA_PREVIEW);
     };
@@ -923,30 +903,18 @@ void SLAPrint::process()
         m_printer_input.clear();
 
         for(SLAPrintObject * o : m_objects) {
-            auto& po = *o;
-            std::vector<ExPolygons>& oslices = po.m_model_slices;
+            LevelID gndlvl = o->get_slice_index().front().key();
+            for(auto& slicerecord : o->get_slice_index()) {
+                auto& lyrs = m_printer_input[slicerecord.key() - gndlvl];
 
-            // We need to adjust the min Z level of the slices to be zero
-            LevelID smfirst =
-                    po.m_supportdata && !po.m_supportdata->level_ids.empty() ?
-                        po.m_supportdata->level_ids.front() : 0;
-            LevelID mfirst = po.m_level_ids.empty()? 0 : po.m_level_ids.front();
-            LevelID gndlvl = -(std::min(smfirst, mfirst));
+                const ExPolygons& objslices = o->get_slices_from_record(slicerecord, soModel);
+                const ExPolygons& supslices = o->get_slices_from_record(slicerecord, soSupport);
 
-            // now merge this object's support and object slices with the rest
-            // of the print object slices
+                if(!objslices.empty())
+                    lyrs.emplace_back(objslices, o->instances());
 
-            for(size_t i = 0; i < oslices.size(); ++i) {
-                auto& lyrs = m_printer_input[gndlvl + po.m_level_ids[i]];
-                lyrs.emplace_back(oslices[i], po.m_instances);
-            }
-
-            if(!po.m_supportdata) continue;
-            std::vector<ExPolygons>& sslices = po.m_supportdata->support_slices;
-            for(size_t i = 0; i < sslices.size(); ++i) {
-                LayerRefs& lyrs =
-                       m_printer_input[gndlvl + po.m_supportdata->level_ids[i]];
-                lyrs.emplace_back(sslices[i], po.m_instances);
+                if(!supslices.empty())
+                    lyrs.emplace_back(supslices, o->instances());
             }
         }
 
@@ -1249,13 +1217,13 @@ void SLAPrint::fill_statistics()
 
     // find highest object
     // Which is a better bet? To compare by max_z or by number of layers in the index?
-    double max_z = 0.;
+    float max_z = 0.;
 	size_t max_layers_cnt = 0;
     size_t highest_obj_idx = 0;
 	for (SLAPrintObject *&po : m_objects) {
         const SLAPrintObject::SliceIndex& slice_index = po->get_slice_index();
         if (! slice_index.empty()) {
-            double z = (-- slice_index.end())->first;
+            float z = (-- slice_index.end())->slice_level();
             size_t cnt = slice_index.size();
             //if (z > max_z) {
             if (cnt > max_layers_cnt) {
@@ -1275,7 +1243,7 @@ void SLAPrint::fill_statistics()
     int sliced_layer_cnt = 0;
     for (const auto& layer : highest_obj_slice_index)
     {
-        const double l_height = (layer.first == highest_obj_slice_index.begin()->first) ? init_layer_height : layer_height;
+        const double l_height = (layer.key() == highest_obj_slice_index.begin()->key()) ? init_layer_height : layer_height;
 
         // Calculation of the consumed material 
 
@@ -1284,21 +1252,22 @@ void SLAPrint::fill_statistics()
 
         for (SLAPrintObject * po : m_objects)
         {
-            const SLAPrintObject::SliceRecord *record = nullptr;
+            const SLAPrintObject::_SliceRecord *record = nullptr;
             {
                 const SLAPrintObject::SliceIndex& index = po->get_slice_index();
-                auto key = layer.first;
-				const SLAPrintObject::SliceIndex::const_iterator it_key = index.lower_bound(key - float(EPSILON));
-                if (it_key == index.end() || it_key->first > key + EPSILON)
+                auto it = po->search_slice_index(layer.slice_level() - float(EPSILON));
+                if (it == index.end() || it->slice_level() > layer.slice_level() + float(EPSILON))
                     continue;
-                record = &it_key->second;
+                record = &(*it);
             }
 
-            if (record->model_slices_idx != SLAPrintObject::SliceRecord::NONE)
-                append(model_polygons, get_all_polygons(po->get_model_slices()[record->model_slices_idx], po->instances()));
-            
-            if (record->support_slices_idx != SLAPrintObject::SliceRecord::NONE)
-                append(supports_polygons, get_all_polygons(po->get_support_slices()[record->support_slices_idx], po->instances()));
+            const ExPolygons &modelslices = po->get_slices_from_record(*record, soModel);
+            if (!modelslices.empty())
+                append(model_polygons, get_all_polygons(modelslices, po->instances()));
+
+            const ExPolygons &supportslices = po->get_slices_from_record(*record, soSupport);
+            if (!supportslices.empty())
+                append(supports_polygons, get_all_polygons(supportslices, po->instances()));
         }
         
         model_polygons = union_(model_polygons);
@@ -1394,11 +1363,15 @@ bool SLAPrintObject::invalidate_state_by_config_options(const std::vector<t_conf
     for (const t_config_option_key &opt_key : opt_keys) {
 		if (   opt_key == "layer_height"
             || opt_key == "faded_layers"
+            || opt_key == "pad_enable"
+            || opt_key == "pad_wall_thickness"
+            || opt_key == "supports_enable"
+            || opt_key == "support_object_elevation"
             || opt_key == "slice_closing_radius") {
 			steps.emplace_back(slaposObjectSlice);
         } else if (
-               opt_key == "supports_enable"
-            || opt_key == "support_points_density_relative"
+
+               opt_key == "support_points_density_relative"
             || opt_key == "support_points_minimal_distance") {
             steps.emplace_back(slaposSupportPoints);
 		} else if (
@@ -1413,12 +1386,10 @@ bool SLAPrintObject::invalidate_state_by_config_options(const std::vector<t_conf
             || opt_key == "support_critical_angle"
             || opt_key == "support_max_bridge_length"
             || opt_key == "support_max_pillar_link_distance"
-            || opt_key == "support_object_elevation") {
+            ) {
             steps.emplace_back(slaposSupportTree);
         } else if (
-               opt_key == "pad_enable"
-            || opt_key == "pad_wall_thickness"
-            || opt_key == "pad_wall_height"
+               opt_key == "pad_wall_height"
             || opt_key == "pad_max_merge_distance"
             || opt_key == "pad_wall_slope"
             || opt_key == "pad_edge_radius") {
@@ -1474,11 +1445,7 @@ double SLAPrintObject::get_elevation() const {
         // its walls but currently it is half of its thickness. Whatever it
         // will be in the future, we provide the config to the get_pad_elevation
         // method and we will have the correct value
-        sla::PoolConfig pcfg;
-        pcfg.min_wall_height_mm = m_config.pad_wall_height.getFloat();
-        pcfg.min_wall_thickness_mm = m_config.pad_wall_thickness.getFloat();
-        pcfg.edge_radius_mm = m_config.pad_edge_radius.getFloat();
-        pcfg.max_merge_distance_mm = m_config.pad_max_merge_distance.getFloat();
+        sla::PoolConfig pcfg = make_pool_config(m_config);
         ret += sla::get_pad_elevation(pcfg);
     }
 
@@ -1502,6 +1469,7 @@ double SLAPrintObject::get_current_elevation() const
 namespace { // dummy empty static containers for return values in some methods
 const std::vector<ExPolygons> EMPTY_SLICES;
 const TriangleMesh EMPTY_MESH;
+const ExPolygons EMPTY_SLICE;
 }
 
 const std::vector<sla::SupportPoint>& SLAPrintObject::get_support_points() const
@@ -1509,6 +1477,72 @@ const std::vector<sla::SupportPoint>& SLAPrintObject::get_support_points() const
     return m_supportdata->support_points;
 }
 
+SLAPrintObject::SliceIndex::iterator
+SLAPrintObject::search_slice_index(float slice_level)
+{
+    _SliceRecord query(0, slice_level, 0);
+    auto it = std::lower_bound(m_slice_index.begin(), m_slice_index.end(),
+                               query,
+                               [](const _SliceRecord& r1, const _SliceRecord& r2)
+    {
+        return r1.slice_level() < r2.slice_level();
+    });
+
+    return it;
+}
+
+SLAPrintObject::SliceIndex::const_iterator
+SLAPrintObject::search_slice_index(float slice_level) const
+{
+    _SliceRecord query(0, slice_level, 0);
+    auto it = std::lower_bound(m_slice_index.cbegin(), m_slice_index.cend(),
+                               query,
+                               [](const _SliceRecord& r1, const _SliceRecord& r2)
+    {
+        return r1.slice_level() < r2.slice_level();
+    });
+
+    return it;
+}
+
+SLAPrintObject::SliceIndex::iterator
+SLAPrintObject::search_slice_index(SLAPrintObject::_SliceRecord::Key key,
+                                   bool exact)
+{
+    _SliceRecord query(key, 0.f, 0.f);
+    auto it = std::lower_bound(m_slice_index.begin(), m_slice_index.end(),
+                               query,
+                               [](const _SliceRecord& r1, const _SliceRecord& r2)
+    {
+        return r1.key() < r2.key();
+    });
+
+    // Return valid iterator only if the keys really match
+    if(exact && it != m_slice_index.end() && it->key() != key)
+        it = m_slice_index.end();
+
+    return it;
+}
+
+SLAPrintObject::SliceIndex::const_iterator
+SLAPrintObject::search_slice_index(SLAPrintObject::_SliceRecord::Key key,
+                                   bool exact) const
+{
+    _SliceRecord query(key, 0.f, 0.f);
+    auto it = std::lower_bound(m_slice_index.cbegin(), m_slice_index.cend(),
+                               query,
+                               [](const _SliceRecord& r1, const _SliceRecord& r2)
+    {
+        return r1.key() < r2.key();
+    });
+
+    // Return valid iterator only if the keys really match
+    if(exact && it != m_slice_index.end() && it->key() != key)
+        it = m_slice_index.end();
+
+    return it;
+}
+
 const std::vector<ExPolygons> &SLAPrintObject::get_support_slices() const
 {
     // assert(is_step_done(slaposSliceSupports));
@@ -1516,7 +1550,30 @@ const std::vector<ExPolygons> &SLAPrintObject::get_support_slices() const
     return m_supportdata->support_slices;
 }
 
-const SLAPrintObject::SliceIndex &SLAPrintObject::get_slice_index() const
+const ExPolygons &SLAPrintObject::get_slices_from_record(
+        const _SliceRecord &rec,
+        SliceOrigin o) const
+{
+    size_t idx = o == soModel ? rec.get_model_slice_idx() :
+                                rec.get_support_slice_idx();
+
+    const std::vector<ExPolygons>& v = o == soModel? get_model_slices() :
+                                                     get_support_slices();
+
+    if(idx >= v.size()) return EMPTY_SLICE;
+
+    return idx >= v.size() ? EMPTY_SLICE : v[idx];
+}
+
+const ExPolygons &SLAPrintObject::get_slices_from_record(
+        SLAPrintObject::SliceRecordConstIterator it, SliceOrigin o) const
+{
+    if(it.is_end()) return EMPTY_SLICE;
+    return get_slices_from_record(*it, o);
+}
+
+const std::vector<SLAPrintObject::_SliceRecord>&
+SLAPrintObject::get_slice_index() const
 {
     // assert(is_step_done(slaposIndexSlices));
     return m_slice_index;
diff --git a/src/libslic3r/SLAPrint.hpp b/src/libslic3r/SLAPrint.hpp
index c06e2fc77..fbe2821b2 100644
--- a/src/libslic3r/SLAPrint.hpp
+++ b/src/libslic3r/SLAPrint.hpp
@@ -6,6 +6,7 @@
 #include "PrintExport.hpp"
 #include "Point.hpp"
 #include "MTUtils.hpp"
+#include <iterator>
 
 namespace Slic3r {
 
@@ -35,12 +36,19 @@ using _SLAPrintObjectBase =
 // the printer (rasterizer) in the SLAPrint class.
 using LevelID = long long;
 
+enum SliceOrigin { soSupport, soModel };
+
 class SLAPrintObject : public _SLAPrintObjectBase
 {
 private: // Prevents erroneous use by other classes.
     using Inherited = _SLAPrintObjectBase;
 
 public:
+
+    // I refuse to grantee copying (Tamas)
+    SLAPrintObject(const SLAPrintObject&) = delete;
+    SLAPrintObject& operator=(const SLAPrintObject&) = delete;
+
     const SLAPrintObjectConfig& config() const { return m_config; }
     const Transform3d&          trafo()  const { return m_trafo; }
 
@@ -82,40 +90,146 @@ public:
     // pad is not, then without the pad, otherwise the full value is returned.
     double get_current_elevation() const;
 
-    // These two methods should be callable on the client side (e.g. UI thread)
-    // when the appropriate steps slaposObjectSlice and slaposSliceSupports
-    // are ready. All the print objects are processed before slapsRasterize so
-    // it is safe to call them during and/or after slapsRasterize.
-    const std::vector<ExPolygons>& get_model_slices() const;
-    const std::vector<ExPolygons>& get_support_slices() const;
-
     // This method returns the support points of this SLAPrintObject.
     const std::vector<sla::SupportPoint>& get_support_points() const;
 
+    // The public Slice record structure. It corresponds to one printable layer.
+    // To get the sliced polygons, use SLAPrintObject::get_slices_from_record
+    class SliceRecord {
+    public:
+        using Key = LevelID;
+
+    private:
+        Key   m_print_z = 0;      // Top of the layer
+        float m_slice_z = 0.f;    // Exact level of the slice
+        float m_height = 0.f;     // Height of the sliced layer
+
+    protected:
+        SliceRecord(Key key, float slicez, float height):
+            m_print_z(key), m_slice_z(slicez), m_height(height) {}
+
+    public:
+
+        // The key will be the integer height level of the top of the layer.
+        inline Key key() const { return m_print_z; }
+
+        // Returns the exact floating point Z coordinate of the slice
+        inline float slice_level() const { return m_slice_z; }
+
+        // Returns the current layer height
+        inline float layer_height() const { return m_height; }
+    };
+
+private:
+
     // An index record referencing the slices
     // (get_model_slices(), get_support_slices()) where the keys are the height
     // levels of the model in scaled-clipper coordinates. The levels correspond
     // to the z coordinate of the object coordinate system.
-    struct SliceRecord {
-        using Key = float;
+    class _SliceRecord: public SliceRecord {
+    public:
+        static const size_t NONE = size_t(-1); // this will be the max limit of size_t
+    private:
+        size_t m_model_slices_idx = NONE;
+        size_t m_support_slices_idx = NONE;
 
-        using Idx = size_t;
-        static const Idx NONE = Idx(-1); // this will be the max limit of size_t
+    public:
+        _SliceRecord(Key key, float slicez, float height):
+            SliceRecord(key, slicez, height) {}
 
-        Idx model_slices_idx = NONE;
-        Idx support_slices_idx = NONE;
+        // Methods for setting the indices into the slice vectors.
+        void set_model_slice_idx(size_t id) { m_model_slices_idx = id; }
+        void set_support_slice_idx(size_t id) { m_support_slices_idx = id; }
+
+        inline size_t get_model_slice_idx() const { return m_model_slices_idx; }
+        inline size_t get_support_slice_idx() const { return m_support_slices_idx; }
     };
 
-    using SliceIndex = std::map<SliceRecord::Key, SliceRecord>;
+    // Slice index will be a plain vector sorted by the integer height levels
+    using SliceIndex = std::vector<_SliceRecord>;
 
     // Retrieve the slice index which is readable only after slaposIndexSlices
     // is done.
     const SliceIndex& get_slice_index() const;
 
-    // I refuse to grantee copying (Tamas)
-    SLAPrintObject(const SLAPrintObject&) = delete;
-    SLAPrintObject& operator=(const SLAPrintObject&) = delete;
+    // Search slice index for the closest slice to the given level
+    SliceIndex::iterator search_slice_index(float slice_level);
+    SliceIndex::const_iterator search_slice_index(float slice_level) const;
 
+    // Search the slice index for a particular level in integer coordinates.
+    // If no such layer is present, it will return m_slice_index.end()
+    // This behavior can be suppressed by the second parameter. If it is true
+    // the method will return the closest (non-equal) record
+    SliceIndex::iterator search_slice_index(_SliceRecord::Key key, bool exact = false);
+    SliceIndex::const_iterator search_slice_index(_SliceRecord::Key key, bool = false) const;
+
+    const std::vector<ExPolygons>& get_model_slices() const;
+    const std::vector<ExPolygons>& get_support_slices() const;
+
+public:
+
+    // Should work as a polymorphic bidirectional iterator to the slice records
+    using SliceRecordConstIterator =
+        IndexBasedIterator<const SliceIndex, const _SliceRecord>;
+
+    // /////////////////////////////////////////////////////////////////////////
+    //
+    // These two methods should be callable on the client side (e.g. UI thread)
+    // when the appropriate steps slaposObjectSlice and slaposSliceSupports
+    // are ready. All the print objects are processed before slapsRasterize so
+    // it is safe to call them during and/or after slapsRasterize.
+    //
+    // /////////////////////////////////////////////////////////////////////////
+
+    // Get the slice records from a range of slice levels (inclusive). Floating
+    // point keys are the levels where the model was sliced with the mesh
+    // slicer. Integral keys are the keys of the slice records, which
+    // correspond to the top of each layer.. The end() method of the returned
+    // range points *after* the last valid element. This is for being
+    // consistent with std and makeing range based for loops work. use
+    // std::prev(range.end()) or --range.end() to get the last element.
+    template<class Key> Range<SliceRecordConstIterator>
+    get_slice_records(Key from, Key to = std::numeric_limits<Key>::max()) const
+    {
+        SliceIndex::const_iterator it_from, it_to;
+        if(std::is_integral<Key>::value) {
+            it_from = search_slice_index(SliceRecord::Key(from));
+            it_to   = search_slice_index(SliceRecord::Key(to));
+        } else if(std::is_floating_point<Key>::value) {
+            it_from = search_slice_index(float(from));
+            it_to   = search_slice_index(float(to));
+        } else return {
+            SliceRecordConstIterator(m_slice_index, _SliceRecord::NONE ),
+            SliceRecordConstIterator(m_slice_index, _SliceRecord::NONE ),
+        };
+
+        auto start = m_slice_index.begin();
+
+        size_t bidx = it_from == m_slice_index.end() ? _SliceRecord::NONE :
+                                                        size_t(it_from - start);
+
+        size_t eidx = it_to   == m_slice_index.end() ? _SliceRecord::NONE :
+                                                       size_t(it_to - start) + 1;
+
+        return {
+            SliceRecordConstIterator(m_slice_index, bidx),
+            SliceRecordConstIterator(m_slice_index, eidx),
+        };
+    }
+
+    // Get all the slice records as a range.
+    inline Range<SliceRecordConstIterator> get_slice_records() const {
+        return {
+            SliceRecordConstIterator(m_slice_index, 0),
+            SliceRecordConstIterator(m_slice_index, m_slice_index.size())
+        };
+    }
+
+    const ExPolygons& get_slices_from_record(SliceRecordConstIterator it,
+                                             SliceOrigin o) const;
+
+    const ExPolygons& get_slices_from_record(const _SliceRecord& rec,
+                                             SliceOrigin o) const;
 protected:
     // to be called from SLAPrint only.
     friend class SLAPrint;
@@ -145,8 +259,10 @@ protected:
 private:
     // Object specific configuration, pulled from the configuration layer.
     SLAPrintObjectConfig                    m_config;
+
     // Translation in Z + Rotation by Y and Z + Scaling / Mirroring.
     Transform3d                             m_trafo = Transform3d::Identity();
+
     std::vector<Instance> 					m_instances;
 
     // Individual 2d slice polygons from lower z to higher z levels
@@ -154,11 +270,9 @@ private:
 
     // Exact (float) height levels mapped to the slices. Each record contains
     // the index to the model and the support slice vectors.
-    SliceIndex                              m_slice_index;
+    std::vector<_SliceRecord>               m_slice_index;
 
-    // The height levels corrected and scaled up in integer values. This will
-    // be used at rasterization.
-    std::vector<LevelID>                    m_level_ids;
+    std::vector<float>                      m_model_height_levels;
 
     // Caching the transformed (m_trafo) raw mesh of the object
     mutable CachedObject<TriangleMesh>      m_transformed_rmesh;
@@ -236,6 +350,11 @@ public:
     }
     const PrintObjects& objects() const { return m_objects; }
 
+    const SLAPrintConfig&     print_config() const { return m_print_config; }
+    const SLAPrinterConfig&   printer_config() const { return m_printer_config; }
+    const SLAMaterialConfig&  material_config() const { return m_material_config; }
+
+
 	std::string         output_filename() const override;
 
     const SLAPrintStatistics&      print_statistics() const { return m_print_statistics; }
@@ -249,11 +368,6 @@ private:
     // Invalidate steps based on a set of parameters changed.
     bool invalidate_state_by_config_options(const std::vector<t_config_option_key> &opt_keys);
 
-    std::vector<float> calculate_heights(const BoundingBoxf3& bb,
-                                         float elevation,
-                                         float initial_layer_height,
-                                         float layer_height) const;
-
     void fill_statistics();
 
     SLAPrintConfig                  m_print_config;
diff --git a/src/slic3r/GUI/Field.cpp b/src/slic3r/GUI/Field.cpp
index 026b62ab5..9cd933160 100644
--- a/src/slic3r/GUI/Field.cpp
+++ b/src/slic3r/GUI/Field.cpp
@@ -540,7 +540,10 @@ void Choice::BUILD() {
 	else{
 		for (auto el : m_opt.enum_labels.empty() ? m_opt.enum_values : m_opt.enum_labels) {
 			const wxString& str = _(el);//m_opt_id == "support" ? _(el) : el;
-            temp->Append(str, create_scaled_bitmap("empty_icon.png"));
+			//FIXME Vojtech: Why is the single column empty icon necessary? It is a workaround of some kind, but what for?
+			// Please document such workarounds by comments!
+            // temp->Append(str, create_scaled_bitmap("empty_icon.png"));
+            temp->Append(str, wxNullBitmap);
 		}
 		set_selection();
 	}
diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp
index 1bcc53efd..3192e7861 100644
--- a/src/slic3r/GUI/GLCanvas3D.cpp
+++ b/src/slic3r/GUI/GLCanvas3D.cpp
@@ -2293,11 +2293,13 @@ int GLCanvas3D::check_volumes_outside_state() const
     return (int)state;
 }
 
-void GLCanvas3D::toggle_sla_auxiliaries_visibility(bool visible)
+void GLCanvas3D::toggle_sla_auxiliaries_visibility(bool visible, const ModelObject* mo, int instance_idx)
 {
     for (GLVolume* vol : m_volumes.volumes) {
-        if (vol->composite_id.volume_id < 0)
-             vol->is_active = visible;
+        if ((mo == nullptr || m_model->objects[vol->composite_id.object_id] == mo)
+        && (instance_idx == -1 || vol->composite_id.instance_id == instance_idx)
+        && vol->composite_id.volume_id < 0)
+            vol->is_active = visible;
     }
 
     m_render_sla_auxiliaries = visible;
@@ -2313,7 +2315,7 @@ void GLCanvas3D::toggle_model_objects_visibility(bool visible, const ModelObject
         }
     }
     if (visible && !mo)
-        toggle_sla_auxiliaries_visibility(true);
+        toggle_sla_auxiliaries_visibility(true, mo, instance_idx);
 
     if (!mo && !visible && !m_model->objects.empty() && (m_model->objects.size() > 1 || m_model->objects.front()->instances.size() > 1))
         _set_warning_texture(WarningTexture::SomethingNotShown, true);
@@ -4971,24 +4973,20 @@ void GLCanvas3D::_render_sla_slices() const
     {
         const SLAPrintObject* obj = print_objects[i];
 
-        double shift_z = obj->get_current_elevation();
-        double min_z = clip_min_z - shift_z;
-        double max_z = clip_max_z - shift_z;
-
         SlaCap::ObjectIdToTrianglesMap::iterator it_caps_bottom = m_sla_caps[0].triangles.find(i);
         SlaCap::ObjectIdToTrianglesMap::iterator it_caps_top    = m_sla_caps[1].triangles.find(i);
         {
 			if (it_caps_bottom == m_sla_caps[0].triangles.end())
 				it_caps_bottom = m_sla_caps[0].triangles.emplace(i, SlaCap::Triangles()).first;
-            if (! m_sla_caps[0].matches(min_z)) {
-				m_sla_caps[0].z = min_z;
+            if (! m_sla_caps[0].matches(clip_min_z)) {
+				m_sla_caps[0].z = clip_min_z;
                 it_caps_bottom->second.object.clear();
                 it_caps_bottom->second.supports.clear();
             }
             if (it_caps_top == m_sla_caps[1].triangles.end())
 				it_caps_top = m_sla_caps[1].triangles.emplace(i, SlaCap::Triangles()).first;
-            if (! m_sla_caps[1].matches(max_z)) {
-				m_sla_caps[1].z = max_z;
+            if (! m_sla_caps[1].matches(clip_max_z)) {
+				m_sla_caps[1].z = clip_max_z;
                 it_caps_top->second.object.clear();
                 it_caps_top->second.supports.clear();
             }
@@ -5008,36 +5006,39 @@ void GLCanvas3D::_render_sla_slices() const
         std::vector<InstanceTransform> instance_transforms;
         for (const SLAPrintObject::Instance& inst : instances)
         {
-            instance_transforms.push_back({ to_3d(unscale(inst.shift), shift_z), Geometry::rad2deg(inst.rotation) });
+			instance_transforms.push_back({ to_3d(unscale(inst.shift), 0.), Geometry::rad2deg(inst.rotation) });
         }
 
         if ((bottom_obj_triangles.empty() || bottom_sup_triangles.empty() || top_obj_triangles.empty() || top_sup_triangles.empty()) && obj->is_step_done(slaposIndexSlices))
         {
-            const std::vector<ExPolygons>& model_slices = obj->get_model_slices();
-            const std::vector<ExPolygons>& support_slices = obj->get_support_slices();
-
-            const SLAPrintObject::SliceIndex& index = obj->get_slice_index();
-            SLAPrintObject::SliceIndex::const_iterator it_min_z = std::find_if(index.begin(), index.end(), [min_z](const SLAPrintObject::SliceIndex::value_type& id) -> bool { return std::abs(min_z - id.first) < EPSILON; });
-            SLAPrintObject::SliceIndex::const_iterator it_max_z = std::find_if(index.begin(), index.end(), [max_z](const SLAPrintObject::SliceIndex::value_type& id) -> bool { return std::abs(max_z - id.first) < EPSILON; });
-
-            if (it_min_z != index.end())
-            {
+            double initial_layer_height = print->material_config().initial_layer_height.value;
+            LevelID key_zero = obj->get_slice_records().begin()->key();
+			LevelID key_low  = LevelID((clip_min_z - initial_layer_height) / SCALING_FACTOR) + key_zero;
+			LevelID key_high = LevelID((clip_max_z - initial_layer_height) / SCALING_FACTOR) + key_zero;
+			auto slice_range = obj->get_slice_records(key_low - LevelID(SCALED_EPSILON), key_high - LevelID(SCALED_EPSILON));
+            auto it_low  = slice_range.begin();
+            auto it_high = std::prev(slice_range.end());
+    
+            if (! it_low.is_end() && it_low->key() < key_low + LevelID(SCALED_EPSILON)) {
+                const ExPolygons& obj_bottom = obj->get_slices_from_record(it_low, soModel);
+                const ExPolygons& sup_bottom = obj->get_slices_from_record(it_low, soSupport);
                 // calculate model bottom cap
-                if (bottom_obj_triangles.empty() && (it_min_z->second.model_slices_idx < model_slices.size()))
-                    bottom_obj_triangles = triangulate_expolygons_3d(model_slices[it_min_z->second.model_slices_idx], min_z, true);
+                if (bottom_obj_triangles.empty() && !obj_bottom.empty())
+                    bottom_obj_triangles = triangulate_expolygons_3d(obj_bottom, clip_min_z, true);
                 // calculate support bottom cap
-                if (bottom_sup_triangles.empty() && (it_min_z->second.support_slices_idx < support_slices.size()))
-                    bottom_sup_triangles = triangulate_expolygons_3d(support_slices[it_min_z->second.support_slices_idx], min_z, true);
+                if (bottom_sup_triangles.empty() && !sup_bottom.empty())
+                    bottom_sup_triangles = triangulate_expolygons_3d(sup_bottom, clip_min_z, true);
             }
 
-            if (it_max_z != index.end())
-            {
+            if (! it_high.is_end() && it_high->key() < key_high + LevelID(SCALED_EPSILON)) {
+                const ExPolygons& obj_top = obj->get_slices_from_record(it_high, soModel);
+                const ExPolygons& sup_top = obj->get_slices_from_record(it_high, soSupport);
                 // calculate model top cap
-                if (top_obj_triangles.empty() && (it_max_z->second.model_slices_idx < model_slices.size()))
-                    top_obj_triangles = triangulate_expolygons_3d(model_slices[it_max_z->second.model_slices_idx], max_z, false);
+                if (top_obj_triangles.empty() && !obj_top.empty())
+                    top_obj_triangles = triangulate_expolygons_3d(obj_top, clip_max_z, false);
                 // calculate support top cap
-                if (top_sup_triangles.empty() && (it_max_z->second.support_slices_idx < support_slices.size()))
-					top_sup_triangles = triangulate_expolygons_3d(support_slices[it_max_z->second.support_slices_idx], max_z, false);
+                if (top_sup_triangles.empty() && !sup_top.empty())
+                    top_sup_triangles = triangulate_expolygons_3d(sup_top, clip_max_z, false);
             }
         }
 
diff --git a/src/slic3r/GUI/GLCanvas3D.hpp b/src/slic3r/GUI/GLCanvas3D.hpp
index d9e38c4e0..29e0fbb08 100644
--- a/src/slic3r/GUI/GLCanvas3D.hpp
+++ b/src/slic3r/GUI/GLCanvas3D.hpp
@@ -584,6 +584,9 @@ private:
     bool m_regenerate_volumes;
     bool m_moving;
     bool m_tab_down;
+
+    // Following variable is obsolete and it should be safe to remove it.
+    // I just don't want to do it now before a release (Lukas Matena 24.3.2019)
     bool m_render_sla_auxiliaries;
 
     std::string m_color_by;
@@ -610,7 +613,7 @@ public:
     void reset_volumes();
     int check_volumes_outside_state() const;
 
-    void toggle_sla_auxiliaries_visibility(bool visible);
+    void toggle_sla_auxiliaries_visibility(bool visible, const ModelObject* mo = nullptr, int instance_idx = -1);
     void toggle_model_objects_visibility(bool visible, const ModelObject* mo = nullptr, int instance_idx = -1);
 
     void set_config(const DynamicPrintConfig* config);
diff --git a/src/slic3r/GUI/GLToolbar.cpp b/src/slic3r/GUI/GLToolbar.cpp
index ac79784ad..2f7f13f6f 100644
--- a/src/slic3r/GUI/GLToolbar.cpp
+++ b/src/slic3r/GUI/GLToolbar.cpp
@@ -157,7 +157,6 @@ GLToolbar::GLToolbar(GLToolbar::EType type)
 #if ENABLE_SVG_ICONS
     , m_icons_texture_dirty(true)
 #endif // ENABLE_SVG_ICONS
-    , m_mouse_capture({ false, false, false, nullptr })
     , m_tooltip("")
 {
 }
@@ -410,6 +409,16 @@ bool GLToolbar::on_mouse(wxMouseEvent& evt, GLCanvas3D& parent)
     bool processed = false;
 
     // mouse anywhere
+    if (!evt.Dragging() && !evt.Leaving() && !evt.Entering() && (m_mouse_capture.parent != nullptr))
+    {
+        if (m_mouse_capture.any() && (evt.LeftUp() || evt.MiddleUp() || evt.RightUp()))
+            // prevents loosing selection into the scene if mouse down was done inside the toolbar and mouse up was down outside it,
+            // as when switching between views
+            processed = true;
+
+        m_mouse_capture.reset();
+    }
+
     if (evt.Moving())
         m_tooltip = update_hover_state(mouse_pos, parent);
     else if (evt.LeftUp())
@@ -418,17 +427,9 @@ bool GLToolbar::on_mouse(wxMouseEvent& evt, GLCanvas3D& parent)
         m_mouse_capture.middle = false;
     else if (evt.RightUp())
         m_mouse_capture.right = false;
-    else if (m_mouse_capture.any())
-    {
-        if (evt.Dragging())
-            processed = true;
-        else if (evt.Entering() && (m_mouse_capture.parent == &parent))
-            // Resets the mouse capture state to avoid setting the dragging event as processed when, for example,
-            // the item action opens a modal dialog
-            // Keeps the mouse capture state if the entering event happens on different parent from the one
-            // who received the button down event, to prevent, for example, dragging when switching between scene views 
-            m_mouse_capture.reset();
-    }
+    else if (evt.Dragging() && m_mouse_capture.any())
+        // if the button down was done on this toolbar, prevent from dragging into the scene
+        processed = true;
 
     int item_id = contains_mouse(mouse_pos, parent);
     if (item_id == -1)
diff --git a/src/slic3r/GUI/GLToolbar.hpp b/src/slic3r/GUI/GLToolbar.hpp
index 95953795f..5fac1f5b2 100644
--- a/src/slic3r/GUI/GLToolbar.hpp
+++ b/src/slic3r/GUI/GLToolbar.hpp
@@ -238,6 +238,8 @@ private:
         bool right;
         GLCanvas3D* parent;
 
+        MouseCapture() { reset(); }
+
         bool any() const { return left || middle || right; }
         void reset() { left = middle = right = false; parent = nullptr; }
     };
diff --git a/src/slic3r/GUI/GUI_ObjectSettings.cpp b/src/slic3r/GUI/GUI_ObjectSettings.cpp
index 3781cbf45..dbfdb8e6c 100644
--- a/src/slic3r/GUI/GUI_ObjectSettings.cpp
+++ b/src/slic3r/GUI/GUI_ObjectSettings.cpp
@@ -10,6 +10,8 @@
 
 #include "I18N.hpp"
 
+#include <wx/wupdlock.h>
+
 namespace Slic3r
 {
 namespace GUI
@@ -40,7 +42,7 @@ void OG_Settings::Hide()
 void OG_Settings::UpdateAndShow(const bool show)
 {
     Show(show);
-//     m_parent->Layout();
+//    m_parent->Layout();
 }
 
 wxSizer* OG_Settings::get_sizer()
@@ -84,6 +86,7 @@ void ObjectSettings::update_settings_list()
 			btn->Bind(wxEVT_BUTTON, [opt_key, config, this](wxEvent &event) {
 				config->erase(opt_key);
                 wxTheApp->CallAfter([this]() { 
+                    wxWindowUpdateLocker noUpdates(m_parent);
                     update_settings_list(); 
                     m_parent->Layout(); 
                 });
@@ -119,7 +122,7 @@ void ObjectSettings::update_settings_list()
                 if (cat.second.size() == 1 && cat.second[0] == "extruder")
                     continue;
 
-                auto optgroup = std::make_shared<ConfigOptionsGroup>(m_parent, cat.first, config, false, extra_column);
+                auto optgroup = std::make_shared<ConfigOptionsGroup>(m_og->ctrl_parent(), cat.first, config, false, extra_column);
                 optgroup->label_width = 15 * wxGetApp().em_unit();//150;
                 optgroup->sidetext_width = 7 * wxGetApp().em_unit();//70;
 
diff --git a/src/slic3r/GUI/GUI_Preview.cpp b/src/slic3r/GUI/GUI_Preview.cpp
index 9bb6c9790..2361ff6d3 100644
--- a/src/slic3r/GUI/GUI_Preview.cpp
+++ b/src/slic3r/GUI/GUI_Preview.cpp
@@ -769,19 +769,17 @@ void Preview::load_print_as_sla()
     unsigned int n_layers = 0;
     const SLAPrint* print = m_process->sla_print();
 
-    std::set<double> zs;
+    std::vector<double> zs;
+    double initial_layer_height = print->material_config().initial_layer_height.value;
     for (const SLAPrintObject* obj : print->objects())
-    {
-        double shift_z = obj->get_current_elevation();
         if (obj->is_step_done(slaposIndexSlices))
         {
-            const SLAPrintObject::SliceIndex& index = obj->get_slice_index();
-            for (const SLAPrintObject::SliceIndex::value_type& id : index)
-            {
-                zs.insert(shift_z + id.first);
-            }
+            auto slicerecords = obj->get_slice_records();
+            auto low_coord = slicerecords.begin()->key();
+            for (auto& rec : slicerecords)
+                zs.emplace_back(initial_layer_height + (rec.key() - low_coord) * SCALING_FACTOR);
         }
-    }
+    sort_remove_duplicates(zs);
 
     n_layers = (unsigned int)zs.size();
     if (n_layers == 0)
@@ -796,11 +794,7 @@ void Preview::load_print_as_sla()
         show_hide_ui_elements("none");
 
         if (n_layers > 0)
-        {
-            std::vector<double> layer_zs;
-            std::copy(zs.begin(), zs.end(), std::back_inserter(layer_zs));
-            update_sliders(layer_zs);
-        }
+            update_sliders(zs);
 
         m_loaded = true;
     }
diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp
index c629f2172..31f6b0278 100644
--- a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp
+++ b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp
@@ -666,7 +666,7 @@ RENDER_AGAIN:
     m_imgui->end();
 
     if (m_editing_mode != m_old_editing_state) { // user toggled between editing/non-editing mode
-        m_parent.toggle_sla_auxiliaries_visibility(!m_editing_mode);
+        m_parent.toggle_sla_auxiliaries_visibility(!m_editing_mode, m_model_object, m_active_instance);
         force_refresh = true;
     }
     m_old_editing_state = m_editing_mode;
diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp
index a2ab8c3f1..e15882125 100644
--- a/src/slic3r/GUI/Plater.cpp
+++ b/src/slic3r/GUI/Plater.cpp
@@ -327,8 +327,7 @@ void PresetComboBox::set_label_marker(int item, LabelItemType label_item_type)
 
 void PresetComboBox::check_selection()
 {
-    if (this->last_selected != GetSelection())
-        this->last_selected = GetSelection();
+    this->last_selected = GetSelection();
 }
 
 // Frequently changed parameters
@@ -829,10 +828,7 @@ void Sidebar::update_presets(Preset::Type preset_type)
             preset_bundle.sla_materials.update_platter_ui(p->combo_sla_material);
         }
 		// Update the printer choosers, update the dirty flags.
-        auto prev_selection = p->combo_printer->GetSelection();
 		preset_bundle.printers.update_platter_ui(p->combo_printer);
-        if (prev_selection != p->combo_printer->GetSelection())
-            p->combo_printer->check_selection();
 		// Update the filament choosers to only contain the compatible presets, update the color preview,
 		// update the dirty flags.
         if (print_tech == ptFFF) {
@@ -1717,8 +1713,8 @@ std::vector<size_t> Plater::priv::load_model_objects(const ModelObjectPtrs &mode
             object->center_around_origin();
             new_instances.emplace_back(object->add_instance());
 #else /* AUTOPLACEMENT_ON_LOAD */
-            // if object has no defined position(s) we need to rearrange everything after loading               object->center_around_origin();
-            need_arrange = true;                
+            // if object has no defined position(s) we need to rearrange everything after loading
+            need_arrange = true;
              // add a default instance and center object around origin  
             object->center_around_origin();  // also aligns object to Z = 0 
             ModelInstance* instance = object->add_instance();   
diff --git a/src/slic3r/GUI/Preset.cpp b/src/slic3r/GUI/Preset.cpp
index 3da4c1871..82223b15c 100644
--- a/src/slic3r/GUI/Preset.cpp
+++ b/src/slic3r/GUI/Preset.cpp
@@ -988,6 +988,7 @@ void PresetCollection::update_platter_ui(GUI::PresetComboBox *ui)
 
 	ui->SetSelection(selected_preset_item);
 	ui->SetToolTip(ui->GetString(selected_preset_item));
+    ui->check_selection();
 	ui->Thaw();
 }
 
diff --git a/src/slic3r/GUI/Preset.hpp b/src/slic3r/GUI/Preset.hpp
index ee795f2b9..ac1171e18 100644
--- a/src/slic3r/GUI/Preset.hpp
+++ b/src/slic3r/GUI/Preset.hpp
@@ -11,9 +11,10 @@
 #include "slic3r/Utils/Semver.hpp"
 
 class wxBitmap;
-class wxChoice;
 class wxBitmapComboBox;
+class wxChoice;
 class wxItemContainer;
+class wxString;
 
 namespace Slic3r {
 
diff --git a/src/slic3r/GUI/PresetBundle.cpp b/src/slic3r/GUI/PresetBundle.cpp
index 9f4261372..f78a04126 100644
--- a/src/slic3r/GUI/PresetBundle.cpp
+++ b/src/slic3r/GUI/PresetBundle.cpp
@@ -1529,6 +1529,7 @@ void PresetBundle::update_platter_filament_ui(unsigned int idx_extruder, GUI::Pr
 	}
 	ui->SetSelection(selected_preset_item);
 	ui->SetToolTip(ui->GetString(selected_preset_item));
+    ui->check_selection();
     ui->Thaw();
 }