From 19b1aa081d4b81d30e5fa8eacdf5a74ff3ce3fae Mon Sep 17 00:00:00 2001
From: tamasmeszaros <meszaros.q@gmail.com>
Date: Wed, 7 Nov 2018 15:29:13 +0100
Subject: [PATCH] SLAPrint concept under its way.

---
 src/libslic3r/CMakeLists.txt         |   2 -
 src/libslic3r/SLA/SLARotfinder.cpp   |  31 --
 src/libslic3r/SLA/SLASupportTree.cpp |  51 ++-
 src/libslic3r/SLA/SLASupportTree.hpp |  14 +
 src/libslic3r/SLABasePool.cpp        | 531 ---------------------------
 src/libslic3r/SLABasePool.hpp        |  32 --
 src/slic3r/CMakeLists.txt            |   2 +
 src/slic3r/GUI/GLGizmo.cpp           |  12 +-
 src/slic3r/GUI/Plater.cpp            |   9 +-
 src/slic3r/GUI/SLAPrint.cpp          |  21 ++
 src/slic3r/GUI/SLAPrint.hpp          | 138 +++++++
 11 files changed, 225 insertions(+), 618 deletions(-)
 delete mode 100644 src/libslic3r/SLABasePool.cpp
 delete mode 100644 src/libslic3r/SLABasePool.hpp
 create mode 100644 src/slic3r/GUI/SLAPrint.cpp
 create mode 100644 src/slic3r/GUI/SLAPrint.hpp

diff --git a/src/libslic3r/CMakeLists.txt b/src/libslic3r/CMakeLists.txt
index be31734df..0c6ae0a62 100644
--- a/src/libslic3r/CMakeLists.txt
+++ b/src/libslic3r/CMakeLists.txt
@@ -149,8 +149,6 @@ add_library(libslic3r STATIC
     Technologies.hpp
     TriangleMesh.cpp
     TriangleMesh.hpp
-    SLABasePool.hpp
-    SLABasePool.cpp
     utils.cpp
     Utils.hpp
     SLA/SLABoilerPlate.hpp
diff --git a/src/libslic3r/SLA/SLARotfinder.cpp b/src/libslic3r/SLA/SLARotfinder.cpp
index 1ecd74e0e..05cea7748 100644
--- a/src/libslic3r/SLA/SLARotfinder.cpp
+++ b/src/libslic3r/SLA/SLARotfinder.cpp
@@ -10,37 +10,6 @@
 namespace Slic3r {
 namespace sla {
 
-EigenMesh3D to_eigenmesh(const TriangleMesh& tmesh) {
-
-    const stl_file& stl = tmesh.stl;
-
-    EigenMesh3D outmesh;
-    auto& V = outmesh.V;
-    auto& F = outmesh.F;
-
-    V.resize(3*stl.stats.number_of_facets, 3);
-    F.resize(stl.stats.number_of_facets, 3);
-    for (unsigned int i=0; i<stl.stats.number_of_facets; ++i) {
-        const stl_facet* facet = stl.facet_start+i;
-        V(3*i+0, 0) = facet->vertex[0](0); V(3*i+0, 1) =
-                facet->vertex[0](1); V(3*i+0, 2) = facet->vertex[0](2);
-        V(3*i+1, 0) = facet->vertex[1](0); V(3*i+1, 1) =
-                facet->vertex[1](1); V(3*i+1, 2) = facet->vertex[1](2);
-        V(3*i+2, 0) = facet->vertex[2](0); V(3*i+2, 1) =
-                facet->vertex[2](1); V(3*i+2, 2) = facet->vertex[2](2);
-
-        F(i, 0) = 3*i+0;
-        F(i, 1) = 3*i+1;
-        F(i, 2) = 3*i+2;
-    }
-
-    return outmesh;
-}
-
-inline EigenMesh3D to_eigenmesh(const ModelObject& modelobj) {
-    return to_eigenmesh(modelobj.raw_mesh());
-}
-
 std::array<double, 3> find_best_rotation(const ModelObject& modelobj,
                                          float accuracy,
                                          std::function<void(unsigned)> statuscb,
diff --git a/src/libslic3r/SLA/SLASupportTree.cpp b/src/libslic3r/SLA/SLASupportTree.cpp
index 34821f7ae..d8cff3519 100644
--- a/src/libslic3r/SLA/SLASupportTree.cpp
+++ b/src/libslic3r/SLA/SLASupportTree.cpp
@@ -536,19 +536,9 @@ enum { // For indexing Eigen vectors as v(X), v(Y), v(Z) instead of numbers
   X, Y, Z
 };
 
-EigenMesh3D to_eigenmesh(const Model& model) {
-    TriangleMesh combined_mesh;
+EigenMesh3D to_eigenmesh(const TriangleMesh& tmesh) {
 
-    for(ModelObject *o : model.objects) {
-        TriangleMesh tmp = o->raw_mesh();
-        for(ModelInstance * inst: o->instances) {
-            TriangleMesh ttmp(tmp);
-            inst->transform_mesh(&ttmp);
-            combined_mesh.merge(ttmp);
-        }
-    }
-
-    const stl_file& stl = combined_mesh.stl;
+    const stl_file& stl = tmesh.stl;
 
     EigenMesh3D outmesh;
     auto& V = outmesh.V;
@@ -573,6 +563,27 @@ EigenMesh3D to_eigenmesh(const Model& model) {
     return outmesh;
 }
 
+EigenMesh3D to_eigenmesh(const ModelObject& modelobj) {
+    return to_eigenmesh(modelobj.raw_mesh());
+}
+
+EigenMesh3D to_eigenmesh(const Model& model) {
+    TriangleMesh combined_mesh;
+
+    for(ModelObject *o : model.objects) {
+        TriangleMesh tmp = o->raw_mesh();
+        for(ModelInstance * inst: o->instances) {
+            TriangleMesh ttmp(tmp);
+            inst->transform_mesh(&ttmp);
+            combined_mesh.merge(ttmp);
+        }
+    }
+
+    return to_eigenmesh(combined_mesh);
+}
+
+
+
 Vec3d model_coord(const ModelInstance& object, const Vec3f& mesh_coord) {
     return object.transform_vector(mesh_coord.cast<double>());
 }
@@ -595,13 +606,24 @@ PointSet support_points(const Model& model) {
     return ret;
 }
 
+PointSet support_points(const ModelObject& modelobject, std::size_t instance_id)
+{
+    PointSet ret(modelobject.sla_support_points.size(), 3);
+    long i = 0;
+    ModelInstance *inst = modelobject.instances[instance_id];
+    for(const Vec3f& msource : modelobject.sla_support_points) {
+        ret.row(i++) = model_coord(*inst, msource);
+    }
+    return ret;
+}
+
 double ray_mesh_intersect(const Vec3d& s,
                           const Vec3d& dir,
                           const EigenMesh3D& m);
 
 PointSet normals(const PointSet& points, const EigenMesh3D& mesh);
 
-Vec2d to_vec2(const Vec3d& v3) {
+inline Vec2d to_vec2(const Vec3d& v3) {
     return {v3(X), v3(Y)};
 }
 
@@ -1612,7 +1634,6 @@ void add_sla_supports(Model &model,
               << " seconds" << std::endl;
 
     bench.start();
-    SLASupportTree::Impl& stree = _stree.get();
     ModelObject* o = model.add_object();
     o->add_instance();
 
@@ -1648,7 +1669,7 @@ void add_sla_supports(Model &model,
               << " second." << std::endl;
 
     bench.start();
-    poolmesh.translate(0, 0, poolcfg.min_wall_height_mm / 2);
+    poolmesh.translate(.0f, .0f, float(poolcfg.min_wall_height_mm / 2));
     o->add_volume(poolmesh);
     bench.stop();
 
diff --git a/src/libslic3r/SLA/SLASupportTree.hpp b/src/libslic3r/SLA/SLASupportTree.hpp
index fe611a2ee..1e913cf88 100644
--- a/src/libslic3r/SLA/SLASupportTree.hpp
+++ b/src/libslic3r/SLA/SLASupportTree.hpp
@@ -20,6 +20,7 @@ typedef std::vector<Vec3crd>                            Points3;
 class TriangleMesh;
 class Model;
 class ModelInstance;
+class ModelObject;
 class ExPolygon;
 
 using SliceLayer = std::vector<ExPolygon>;
@@ -31,6 +32,9 @@ struct SupportConfig {
     // Radius in mm of the pointing side of the head.
     double head_front_radius_mm = 0.2;
 
+    // How much the pinhead has to penetrate the model surface
+    double head_penetraiton = 0.2;
+
     // Radius of the back side of the 3d arrow.
     double head_back_radius_mm = 0.5;
 
@@ -39,6 +43,10 @@ struct SupportConfig {
 
     // Radius in mm of the support pillars.
     // Warning: this value will be at most 65% of head_back_radius_mm
+    // TODO: This parameter is invalid. The pillar radius will be dynamic in
+    // nature. Merged pillars will have an increased thickness. This parameter
+    // may serve as the maximum radius, or maybe an increase when two are merged
+    // The default radius will be derived from head_back_radius_mm
     double pillar_radius_mm = 0.8;
 
     // Radius in mm of the pillar base.
@@ -63,6 +71,8 @@ struct Controller {
     std::function<bool(void)> stopcondition = [](){ return false; };
 };
 
+/// An index-triangle structure for libIGL functions. Also serves as an
+/// alternative (raw) input format for the SLASupportTree
 struct EigenMesh3D {
     Eigen::MatrixXd V;
     Eigen::MatrixXi F;
@@ -80,8 +90,12 @@ void create_head(TriangleMesh&, double r1_mm, double r2_mm, double width_mm);
 void add_sla_supports(Model& model, const SupportConfig& cfg = {},
                       const Controller& ctl = {});
 
+EigenMesh3D to_eigenmesh(const TriangleMesh& m);
 EigenMesh3D to_eigenmesh(const Model& model);
+EigenMesh3D to_eigenmesh(const ModelObject& model);
+
 PointSet support_points(const Model& model);
+PointSet support_points(const ModelObject& modelobject, size_t instance_id = 0);
 
 /* ************************************************************************** */
 
diff --git a/src/libslic3r/SLABasePool.cpp b/src/libslic3r/SLABasePool.cpp
deleted file mode 100644
index f3683865c..000000000
--- a/src/libslic3r/SLABasePool.cpp
+++ /dev/null
@@ -1,531 +0,0 @@
-#include <functional>
-#include <numeric>
-
-#include "SLABasePool.hpp"
-#include "ExPolygon.hpp"
-#include "TriangleMesh.hpp"
-#include "ClipperUtils.hpp"
-#include "boost/log/trivial.hpp"
-
-//#include "SVG.hpp"
-
-namespace Slic3r { namespace sla {
-
-namespace {
-
-using coord_t = Point::coord_type;
-
-/// get the scaled clipper units for a millimeter value
-inline coord_t mm(double v) { return coord_t(v/SCALING_FACTOR); }
-
-/// Get x and y coordinates (because we are eigenizing...)
-inline coord_t x(const Point& p) { return p(0); }
-inline coord_t y(const Point& p) { return p(1); }
-inline coord_t& x(Point& p) { return p(0); }
-inline coord_t& y(Point& p) { return p(1); }
-
-inline coordf_t x(const Vec3d& p) { return p(0); }
-inline coordf_t y(const Vec3d& p) { return p(1); }
-inline coordf_t z(const Vec3d& p) { return p(2); }
-inline coordf_t& x(Vec3d& p) { return p(0); }
-inline coordf_t& y(Vec3d& p) { return p(1); }
-inline coordf_t& z(Vec3d& p) { return p(2); }
-
-inline coord_t& x(Vec3crd& p) { return p(0); }
-inline coord_t& y(Vec3crd& p) { return p(1); }
-inline coord_t& z(Vec3crd& p) { return p(2); }
-inline coord_t x(const Vec3crd& p) { return p(0); }
-inline coord_t y(const Vec3crd& p) { return p(1); }
-inline coord_t z(const Vec3crd& p) { return p(2); }
-
-inline void triangulate(const ExPolygon& expoly, Polygons& triangles) {
-    expoly.triangulate_p2t(&triangles);
-}
-
-inline Polygons triangulate(const ExPolygon& expoly) {
-    Polygons tri; triangulate(expoly, tri); return tri;
-}
-
-using Indices = std::vector<Vec3crd>;
-
-/// Intermediate struct for a 3D mesh
-struct Contour3D {
-    Pointf3s points;
-    Indices indices;
-
-    void merge(const Contour3D& ctr) {
-        auto s3 = coord_t(points.size());
-        auto s = coord_t(indices.size());
-
-        points.insert(points.end(), ctr.points.begin(), ctr.points.end());
-        indices.insert(indices.end(), ctr.indices.begin(), ctr.indices.end());
-
-        for(auto n = s; n < indices.size(); n++) {
-            auto& idx = indices[n]; x(idx) += s3; y(idx) += s3; z(idx) += s3;
-        }
-    }
-};
-
-/// Convert the triangulation output to an intermediate mesh.
-inline Contour3D convert(const Polygons& triangles, coord_t z, bool dir) {
-
-    Pointf3s points;
-    points.reserve(3*triangles.size());
-    Indices indices;
-    indices.reserve(points.size());
-
-    for(auto& tr : triangles) {
-        auto c = coord_t(points.size()), b = c++, a = c++;
-        if(dir) indices.emplace_back(a, b, c);
-        else indices.emplace_back(c, b, a);
-        for(auto& p : tr.points) {
-            points.emplace_back(unscale(x(p), y(p), z));
-        }
-    }
-
-    return {points, indices};
-}
-
-/// Only a debug function to generate top and bottom plates from a 2D shape.
-/// It is not used in the algorithm directly.
-inline Contour3D roofs(const ExPolygon& poly, coord_t z_distance) {
-    Polygons triangles = triangulate(poly);
-
-    auto lower = convert(triangles, 0, false);
-    auto upper = convert(triangles, z_distance, true);
-    lower.merge(upper);
-    return lower;
-}
-
-inline Contour3D walls(const ExPolygon& floor_plate, const ExPolygon& ceiling,
-                       double floor_z_mm, double ceiling_z_mm) {
-    using std::transform; using std::back_inserter;
-
-    ExPolygon poly;
-    poly.contour.points = floor_plate.contour.points;
-    poly.holes.emplace_back(ceiling.contour);
-    auto& h = poly.holes.front();
-    std::reverse(h.points.begin(), h.points.end());
-    Polygons tri = triangulate(poly);
-
-    Contour3D ret;
-    ret.points.reserve(tri.size() * 3);
-
-    double fz = floor_z_mm;
-    double cz = ceiling_z_mm;
-    auto& rp = ret.points;
-    auto& rpi = ret.indices;
-    ret.indices.reserve(tri.size() * 3);
-
-    coord_t idx = 0;
-
-    auto hlines = h.lines();
-    auto is_upper = [&hlines](const Point& p) {
-        return std::any_of(hlines.begin(), hlines.end(),
-                               [&p](const Line& l) {
-            return l.distance_to(p) < mm(0.01);
-        });
-    };
-
-    std::for_each(tri.begin(), tri.end(),
-                  [&rp, &rpi, &poly, &idx, is_upper, fz, cz](const Polygon& pp)
-    {
-        for(auto& p : pp.points)
-            if(is_upper(p))
-                rp.emplace_back(unscale(x(p), y(p), mm(cz)));
-            else rp.emplace_back(unscale(x(p), y(p), mm(fz)));
-
-        coord_t a = idx++, b = idx++, c = idx++;
-        if(fz > cz) rpi.emplace_back(c, b, a);
-        else rpi.emplace_back(a, b, c);
-    });
-
-    return ret;
-}
-
-/// Mesh from an existing contour.
-inline TriangleMesh mesh(const Contour3D& ctour) {
-    return {ctour.points, ctour.indices};
-}
-
-/// Mesh from an evaporating 3D contour
-inline TriangleMesh mesh(Contour3D&& ctour) {
-    return {std::move(ctour.points), std::move(ctour.indices)};
-}
-
-/// Offsetting with clipper and smoothing the edges into a curvature.
-inline void offset(ExPolygon& sh, coord_t distance) {
-    using ClipperLib::ClipperOffset;
-    using ClipperLib::jtRound;
-    using ClipperLib::etClosedPolygon;
-    using ClipperLib::Paths;
-    using ClipperLib::Path;
-
-    auto&& ctour = Slic3rMultiPoint_to_ClipperPath(sh.contour);
-    auto&& holes = Slic3rMultiPoints_to_ClipperPaths(sh.holes);
-
-    // If the input is not at least a triangle, we can not do this algorithm
-    if(ctour.size() < 3 ||
-       std::any_of(holes.begin(), holes.end(),
-                   [](const Path& p) { return p.size() < 3; })
-            ) {
-        BOOST_LOG_TRIVIAL(error) << "Invalid geometry for offsetting!";
-        return;
-    }
-
-    ClipperOffset offs;
-    offs.ArcTolerance = 0.01*mm(1);
-    Paths result;
-    offs.AddPath(ctour, jtRound, etClosedPolygon);
-    offs.AddPaths(holes, jtRound, etClosedPolygon);
-    offs.Execute(result, static_cast<double>(distance));
-
-    // Offsetting reverts the orientation and also removes the last vertex
-    // so boost will not have a closed polygon.
-
-    bool found_the_contour = false;
-    sh.holes.clear();
-    for(auto& r : result) {
-        if(ClipperLib::Orientation(r)) {
-            // We don't like if the offsetting generates more than one contour
-            // but throwing would be an overkill. Instead, we should warn the
-            // caller about the inability to create correct geometries
-            if(!found_the_contour) {
-                auto rr = ClipperPath_to_Slic3rPolygon(r);
-                sh.contour.points.swap(rr.points);
-                found_the_contour = true;
-            } else {
-                BOOST_LOG_TRIVIAL(warning)
-                        << "Warning: offsetting result is invalid!";
-            }
-        } else {
-            // TODO If there are multiple contours we can't be sure which hole
-            // belongs to the first contour. (But in this case the situation is
-            // bad enough to let it go...)
-            sh.holes.emplace_back(ClipperPath_to_Slic3rPolygon(r));
-        }
-    }
-}
-
-template<class ExP, class D>
-inline Contour3D round_edges(const ExPolygon& base_plate,
-                            double radius_mm,
-                            double degrees,
-                            double ceilheight_mm,
-                            bool dir,
-                            ExP&& last_offset = ExP(), D&& last_height = D())
-{
-    auto ob = base_plate;
-    auto ob_prev = ob;
-    double wh = ceilheight_mm, wh_prev = wh;
-    Contour3D curvedwalls;
-
-    const size_t steps = 6;     // steps for 180 degrees
-    degrees = std::fmod(degrees, 180);
-    const int portion = int(steps*degrees / 90);
-    const double ystep_mm = radius_mm/steps;
-    coord_t s = dir? 1 : -1;
-    double xxprev = 0;
-    for(int i = 0; i < portion; i++) {
-        ob = base_plate;
-
-        // The offset is given by the equation: x = sqrt(r^2 - y^2)
-        // which can be derived from the circle equation. y is the current
-        // height for which the offset is calculated and x is the offset itself
-        // r is the radius of the circle that is used to smooth the edges
-
-        double r2 = radius_mm * radius_mm;
-        double y2 = steps*ystep_mm - i*ystep_mm;
-        y2 *= y2;
-
-        double xx = sqrt(r2 - y2);
-
-        offset(ob, s*mm(xx));
-        wh = ceilheight_mm - i*ystep_mm;
-
-        Contour3D pwalls;
-        if(xxprev < xx) pwalls = walls(ob, ob_prev, wh, wh_prev);
-        else pwalls = walls(ob_prev, ob, wh_prev, wh);
-
-        curvedwalls.merge(pwalls);
-        ob_prev = ob;
-        wh_prev = wh;
-        xxprev = xx;
-    }
-
-    last_offset = std::move(ob);
-    last_height = wh;
-
-    return curvedwalls;
-}
-
-/// Generating the concave part of the 3D pool with the bottom plate and the
-/// side walls.
-inline Contour3D inner_bed(const ExPolygon& poly, double depth_mm,
-                           double begin_h_mm = 0) {
-
-    Polygons triangles = triangulate(poly);
-
-    coord_t depth = mm(depth_mm);
-    coord_t begin_h = mm(begin_h_mm);
-
-    auto bottom = convert(triangles, -depth + begin_h, false);
-    auto lines = poly.lines();
-
-    // Generate outer walls
-    auto fp = [](const Point& p, Point::coord_type z) {
-        return unscale(x(p), y(p), z);
-    };
-
-    for(auto& l : lines) {
-        auto s = coord_t(bottom.points.size());
-
-        bottom.points.emplace_back(fp(l.a, -depth + begin_h));
-        bottom.points.emplace_back(fp(l.b, -depth + begin_h));
-        bottom.points.emplace_back(fp(l.a, begin_h));
-        bottom.points.emplace_back(fp(l.b, begin_h));
-
-        bottom.indices.emplace_back(s + 3, s + 1, s);
-        bottom.indices.emplace_back(s + 2, s + 3, s);
-    }
-
-    return bottom;
-}
-
-/// Unification of polygons (with clipper) preserving holes as well.
-inline ExPolygons unify(const ExPolygons& shapes) {
-    using ClipperLib::ptSubject;
-
-    ExPolygons retv;
-
-    bool closed = true;
-    bool valid = true;
-
-    ClipperLib::Clipper clipper;
-
-    for(auto& path : shapes) {
-        auto clipperpath = Slic3rMultiPoint_to_ClipperPath(path.contour);
-
-        if(!clipperpath.empty())
-            valid &= clipper.AddPath(clipperpath, ptSubject, closed);
-
-        auto clipperholes = Slic3rMultiPoints_to_ClipperPaths(path.holes);
-
-        for(auto& hole : clipperholes) {
-            if(!hole.empty())
-                valid &= clipper.AddPath(hole, ptSubject, closed);
-        }
-    }
-
-    if(!valid) BOOST_LOG_TRIVIAL(warning) << "Unification of invalid shapes!";
-
-    ClipperLib::PolyTree result;
-    clipper.Execute(ClipperLib::ctUnion, result, ClipperLib::pftNonZero);
-
-    retv.reserve(static_cast<size_t>(result.Total()));
-
-    // Now we will recursively traverse the polygon tree and serialize it
-    // into an ExPolygon with holes. The polygon tree has the clipper-ish
-    // PolyTree structure which alternates its nodes as contours and holes
-
-    // A "declaration" of function for traversing leafs which are holes
-    std::function<void(ClipperLib::PolyNode*, ExPolygon&)> processHole;
-
-    // Process polygon which calls processHoles which than calls processPoly
-    // again until no leafs are left.
-    auto processPoly = [&retv, &processHole](ClipperLib::PolyNode *pptr) {
-        ExPolygon poly;
-        poly.contour.points = ClipperPath_to_Slic3rPolygon(pptr->Contour);
-        for(auto h : pptr->Childs) { processHole(h, poly); }
-        retv.push_back(poly);
-    };
-
-    // Body of the processHole function
-    processHole = [&processPoly](ClipperLib::PolyNode *pptr, ExPolygon& poly)
-    {
-        poly.holes.emplace_back();
-        poly.holes.back().points = ClipperPath_to_Slic3rPolygon(pptr->Contour);
-        for(auto c : pptr->Childs) processPoly(c);
-    };
-
-    // Wrapper for traversing.
-    auto traverse = [&processPoly] (ClipperLib::PolyNode *node)
-    {
-        for(auto ch : node->Childs) {
-            processPoly(ch);
-        }
-    };
-
-    // Here is the actual traverse
-    traverse(&result);
-
-    return retv;
-}
-
-inline Point centroid(Points& pp) {
-    Point c;
-    switch(pp.size()) {
-    case 0: break;
-    case 1: c = pp.front(); break;
-    case 2: c = (pp[0] + pp[1]) / 2; break;
-    default: {
-        Polygon p;
-        p.points.swap(pp);
-        c = p.centroid();
-        pp.swap(p.points);
-        break;
-    }
-    }
-
-    return c;
-}
-
-inline Point centroid(const ExPolygon& poly) {
-    return poly.contour.centroid();
-}
-
-/// A fake concave hull that is constructed by connecting separate shapes
-/// with explicit bridges. Bridges are generated from each shape's centroid
-/// to the center of the "scene" which is the centroid calculated from the shape
-/// centroids (a star is created...)
-inline ExPolygons concave_hull(const ExPolygons& polys, double max_dist_mm = 50)
-{
-    if(polys.empty()) return ExPolygons();
-
-    ExPolygons punion = unify(polys);   // could be redundant
-
-    if(punion.size() == 1) return punion;
-
-    // We get the centroids of all the islands in the 2D slice
-    Points centroids; centroids.reserve(punion.size());
-    std::transform(punion.begin(), punion.end(), std::back_inserter(centroids),
-                   [](const ExPolygon& poly) { return centroid(poly); });
-
-    // Centroid of the centroids of islands. This is where the additional
-    // connector sticks are routed.
-    Point cc = centroid(centroids);
-
-    punion.reserve(punion.size() + centroids.size());
-
-    std::transform(centroids.begin(), centroids.end(),
-                   std::back_inserter(punion),
-                   [cc, max_dist_mm](const Point& c) {
-
-        double dx = x(c) - x(cc), dy = y(c) - y(cc);
-        double l = std::sqrt(dx * dx + dy * dy);
-        double nx = dx / l, ny = dy / l;
-        double max_dist = mm(max_dist_mm);
-
-        if(l > max_dist) return ExPolygon();
-
-        ExPolygon r;
-        auto& ctour = r.contour.points;
-
-        ctour.reserve(3);
-        ctour.emplace_back(cc);
-
-        Point d(coord_t(mm(1)*nx), coord_t(mm(1)*ny));
-        ctour.emplace_back(c + Point( -y(d),  x(d) ));
-        ctour.emplace_back(c + Point(  y(d), -x(d) ));
-        offset(r, mm(1));
-
-        return r;
-    });
-
-    punion = unify(punion);
-
-    return punion;
-}
-
-}
-
-void ground_layer(const TriangleMesh &mesh, ExPolygons &output, float h)
-{
-    TriangleMesh m = mesh;
-    TriangleMeshSlicer slicer(&m);
-
-    std::vector<ExPolygons> tmp;
-
-    slicer.slice({h}, &tmp, [](){});
-
-    output = tmp.front();
-}
-
-void create_base_pool(const ExPolygons &ground_layer, TriangleMesh& out,
-                      double min_wall_thickness_mm,
-                      double min_wall_height_mm,
-                      double max_merge_distance_mm)
-{
-    auto concavehs = concave_hull(ground_layer, max_merge_distance_mm);
-    for(ExPolygon& concaveh : concavehs) {
-        if(concaveh.contour.points.empty()) return;
-        concaveh.holes.clear();
-
-        BoundingBox bb(concaveh);
-        coord_t w = x(bb.max) - x(bb.min);
-        coord_t h = y(bb.max) - y(bb.min);
-
-        auto wall_thickness = coord_t((w+h)*0.01);
-
-        const coord_t WALL_THICKNESS = mm(min_wall_thickness_mm) +
-                                       wall_thickness;
-
-        const coord_t WALL_DISTANCE = coord_t(0.3*WALL_THICKNESS);
-        const coord_t HEIGHT = mm(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;
-        auto curvedwalls = round_edges(ob,
-                                       1,    // radius 1 mm
-                                       170,  // 170 degrees
-                                       0,    // z position of the input plane
-                                       true,
-                                       ob, wh);
-        pool.merge(curvedwalls);
-
-        ExPolygon ob_contr = ob;
-        ob_contr.holes.clear();
-
-        auto pwalls = walls(ob_contr, inner_base, wh, -min_wall_height_mm);
-        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;
-        curvedwalls = round_edges(ob,
-                                  1,    // radius 1 mm
-                                  90,  // 170 degrees
-                                  0,    // z position of the input plane
-                                  false,
-                                  ob, wh);
-        pool.merge(curvedwalls);
-
-        auto innerbed = inner_bed(ob, 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/SLABasePool.hpp b/src/libslic3r/SLABasePool.hpp
deleted file mode 100644
index 55c94df07..000000000
--- a/src/libslic3r/SLABasePool.hpp
+++ /dev/null
@@ -1,32 +0,0 @@
-#ifndef SLASUPPORTPOOL_HPP
-#define SLASUPPORTPOOL_HPP
-
-#include <vector>
-
-namespace Slic3r {
-
-class ExPolygon;
-class TriangleMesh;
-
-namespace sla {
-
-using ExPolygons = std::vector<ExPolygon>;
-
-/// Calculate the polygon representing the slice of the lowest layer of mesh
-void ground_layer(const TriangleMesh& mesh,
-                  ExPolygons& output,
-                  float height = 0.1f);
-
-/// Calculate the pool for the mesh for SLA printing
-void create_base_pool(const ExPolygons& ground_layer,
-                      TriangleMesh& output_mesh,
-                      double min_wall_thickness_mm = 2,
-                      double min_wall_height_mm = 5,
-                      double max_merge_distance_mm = 50
-                      );
-
-}
-
-}
-
-#endif // SLASUPPORTPOOL_HPP
diff --git a/src/slic3r/CMakeLists.txt b/src/slic3r/CMakeLists.txt
index 509e0b665..37366e483 100644
--- a/src/slic3r/CMakeLists.txt
+++ b/src/slic3r/CMakeLists.txt
@@ -121,6 +121,8 @@ add_library(libslic3r_gui STATIC
     Utils/Time.hpp
     Utils/HexFile.cpp
     Utils/HexFile.hpp
+    GUI/SLAPrint.hpp
+    GUI/SLAPrint.cpp
     AppController.hpp
     AppController.cpp
     AppControllerWx.cpp
diff --git a/src/slic3r/GUI/GLGizmo.cpp b/src/slic3r/GUI/GLGizmo.cpp
index b793f9626..2c8c7630a 100644
--- a/src/slic3r/GUI/GLGizmo.cpp
+++ b/src/slic3r/GUI/GLGizmo.cpp
@@ -1612,16 +1612,20 @@ void GLGizmoSlaSupports::on_deactivate() {
         std::cout << st << "% "  << msg << std::endl;
     };
 
-    const Model& model = *m_model_object->get_model();
-    auto emesh = sla::to_eigenmesh(model);
-    sla::PointSet input = sla::support_points(model);
+    TriangleMesh&& m = m_model_object->raw_mesh();
+    auto&& trafo = m_model_object_matrix.cast<float>();
+    m.transform(trafo);
+    auto emesh = sla::to_eigenmesh(m);
+
     sla::SupportConfig cfg;
+    sla::PointSet input = sla::support_points(*m_model_object, 0 /*instance*/);
 
     sla::SLASupportTree stree(input, emesh, cfg, supportctl);
 
     TriangleMesh output;
     stree.merged_mesh(output);
-    m_model_object->add_volume(output);
+
+    _3DScene::reload_scene(m_parent.get_wxglcanvas(), false);
 }
 
 Vec3f GLGizmoSlaSupports::unproject_on_mesh(const Vec2d& mouse_pos)
diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp
index df1a42a19..af6c08d7c 100644
--- a/src/slic3r/GUI/Plater.cpp
+++ b/src/slic3r/GUI/Plater.cpp
@@ -33,6 +33,7 @@
 #include "libslic3r/Format/AMF.hpp"
 #include "libslic3r/Format/3mf.hpp"
 #include "slic3r/AppController.hpp"
+#include "SLAPrint.hpp"
 #include "GUI.hpp"
 #include "GUI_App.hpp"
 #include "GUI_ObjectList.hpp"
@@ -853,6 +854,7 @@ struct Plater::priv
     // Data
     Slic3r::DynamicPrintConfig *config;
     Slic3r::Print print;
+    Slic3r::SLAPrint slaprint;
     Slic3r::Model model;
     Slic3r::GCodePreviewData gcode_preview_data;
 
@@ -954,7 +956,8 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame) :
     })),
     notebook(new wxNotebook(q, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxNB_BOTTOM)),
     sidebar(new Sidebar(q)),
-    canvas3D(GLCanvas3DManager::create_wxglcanvas(notebook))
+    canvas3D(GLCanvas3DManager::create_wxglcanvas(notebook)),
+    slaprint(&model)
 {
     background_process.set_print(&print);
     background_process.set_gcode_preview_data(&gcode_preview_data);
@@ -1438,7 +1441,7 @@ void Plater::priv::arrange()
     main_frame->app_controller()->arrange_model();
 
     // ignore arrange failures on purpose: user has visual feedback and we don't need to warn him
-    // when parts don't fit in print bed
+    // when parts don't fit in print bed
 
     update();
 }
@@ -2258,7 +2261,7 @@ void Plater::changed_object(int obj_idx)
         _3DScene::reload_scene(p->canvas3D, false);
     }
 
-    // update print
+    // update print
     if (list->is_parts_changed() || list->is_part_settings_changed()) {
         this->p->schedule_background_process();
 #if !ENABLE_MODIFIED_CAMERA_TARGET
diff --git a/src/slic3r/GUI/SLAPrint.cpp b/src/slic3r/GUI/SLAPrint.cpp
new file mode 100644
index 000000000..52957b854
--- /dev/null
+++ b/src/slic3r/GUI/SLAPrint.cpp
@@ -0,0 +1,21 @@
+#include "SLAPrint.hpp"
+
+namespace Slic3r {
+
+void SLAPrint::synch() {
+    m_gcfg = m_config_reader();
+    // TODO: check model objects and instances
+}
+
+bool SLAPrint::start(std::shared_ptr<BackgroundProcess> scheduler) {
+    if(!m_process || !m_process->is_running()) set_scheduler(scheduler);
+    if(!m_process) return false;
+
+    m_process->schedule([this, scheduler](){
+
+    });
+
+    return true;
+}
+
+}
diff --git a/src/slic3r/GUI/SLAPrint.hpp b/src/slic3r/GUI/SLAPrint.hpp
new file mode 100644
index 000000000..b1354e8d0
--- /dev/null
+++ b/src/slic3r/GUI/SLAPrint.hpp
@@ -0,0 +1,138 @@
+#include <libslic3r.h>
+#include "Point.hpp"
+#include "SLA/SLASupportTree.hpp"
+
+#include <string>
+#include <memory>
+#include <unordered_map>
+#include <atomic>
+
+namespace Slic3r {
+
+class Model;
+class ModelObject;
+class ModelInstance;
+class GLCanvas3D;
+class DynamicPrintConfig;
+
+// Ok, this will be the driver to create background threads. Possibly
+// implemented using a BackgroundSlicingProcess or something derived from that
+// The methods should be thread safe, obviously...
+class BackgroundProcess {
+public:
+
+    virtual ~BackgroundProcess() {}
+
+    virtual void schedule(std::function<void()> fn) = 0;
+
+    virtual void status(unsigned st, const std::string& msg) = 0;
+
+    virtual bool is_canceled() = 0;
+
+    virtual void on_input_changed(std::function<void()> synchfn) = 0;
+
+    virtual bool is_running() = 0;
+};
+
+/**
+ * @brief This class is the high level FSM for the SLA printing process.
+ *
+ * It should support the background processing framework and contain the
+ * metadata for the support geometries and their slicing. It should also
+ * dispatch the SLA printing configuration values to the appropriate calculation
+ * steps.
+ *
+ * TODO (decide): The last important feature is the support for visualization
+ * which (at least for now) will be implemented as a method(s) returning the
+ * triangle meshes or receiving the rendering canvas and drawing on that
+ * directly.
+ *
+ * TODO: This class has to be implement the Print interface (not defined yet)
+ * to be usable as the input to the BackgroundSlicingProcess.
+ */
+class SLAPrint /* : public Print */ {
+public:
+
+    enum CallType {
+        BLOCKING, NON_BLOCKING
+    };
+
+    struct GlobalConfig {
+        double width_mm;
+        double height_mm;
+        unsigned long width_px;
+        unsigned long height_px;
+        // ...
+    };
+
+private:
+
+    struct PrintObjectInstance {
+        Transform3f tr;
+        std::unique_ptr<sla::SLASupportTree> support_tree_ptr;
+        SlicedSupports slice_cache;
+    };
+
+    using InstanceMap = std::unordered_map<ModelInstance*, PrintObjectInstance>;
+
+    struct PrintObject {
+        sla::EigenMesh3D emesh;
+        InstanceMap instances;
+    };
+
+    using ObjectMap = std::unordered_map<ModelObject*, PrintObject>;
+
+    // Input data channels: ***************************************************
+
+    const Model *m_model = nullptr; // The model itself
+
+    // something to read out the config profiles and return the values we need.
+    std::function<GlobalConfig()> m_config_reader;
+    // ************************************************************************
+
+    GlobalConfig m_gcfg;
+    ObjectMap m_data;
+    std::shared_ptr<BackgroundProcess> m_process;
+
+    // For now it will just stop the whole process and invalidate everything
+    void synch();
+    std::atomic<bool> m_dirty;
+
+    void set_scheduler(std::shared_ptr<BackgroundProcess> scheduler) {
+        if(scheduler && !scheduler->is_running()) {
+            m_process = scheduler;
+            m_process->on_input_changed([this] {
+                /*synch(); */
+                m_dirty.store(true);
+            });
+        }
+    }
+
+public:
+
+    SLAPrint(const Model * model,
+                    std::function<SLAPrint::GlobalConfig(void)> cfgreader = [](){ return SLAPrint::GlobalConfig(); },
+                    std::shared_ptr<BackgroundProcess> scheduler = {}):
+        m_model(model), m_config_reader(cfgreader)
+    {
+        synch();
+        m_dirty.store(false);
+        set_scheduler(scheduler);
+    }
+
+    // This will start the calculation using the
+    bool start(std::shared_ptr<BackgroundProcess> scheduler);
+
+    // Get the full support structure (including the supports)
+    // This should block until the supports are not ready?
+    bool support_mesh(TriangleMesh& output, CallType calltype = BLOCKING);
+
+    // Exporting to the final zip file, or possibly other format.
+    // filepath is reserved to be a zip filename or directory or anything
+    // that a particular format requires.
+    // (I know, we will use zipped PNG, but everything changes here so quickly)
+    bool export_layers(const std::string& filepath,
+                       CallType calltype = BLOCKING);
+};
+
+}