From 3d1f2f0cb66e77f70c6d8c71e1f0b9424a3538c9 Mon Sep 17 00:00:00 2001
From: PavelMikus <pavel.mikus.mail@seznam.cz>
Date: Wed, 20 Jul 2022 16:23:03 +0200
Subject: [PATCH] implemented graph traversal, keeping the segments and the
 location of the weakest point for each island

---
 src/libslic3r/CMakeLists.txt                  |    3 +-
 src/libslic3r/SupportSpotsGenerator.cpp       | 1262 +++++++++--------
 .../SupportSpotsGeneratorRefactoring.cpp      |  972 -------------
 src/slic3r/GUI/BonjourDialog.hpp              |    2 +
 4 files changed, 708 insertions(+), 1531 deletions(-)
 delete mode 100644 src/libslic3r/SupportSpotsGeneratorRefactoring.cpp

diff --git a/src/libslic3r/CMakeLists.txt b/src/libslic3r/CMakeLists.txt
index 0c4fd2079..e47818835 100644
--- a/src/libslic3r/CMakeLists.txt
+++ b/src/libslic3r/CMakeLists.txt
@@ -245,8 +245,7 @@ set(SLIC3R_SOURCES
     SlicingAdaptive.hpp
     Subdivide.cpp
     Subdivide.hpp
-#    SupportSpotsGenerator.cpp
-    SupportSpotsGeneratorRefactoring.cpp
+    SupportSpotsGenerator.cpp
     SupportSpotsGenerator.hpp
     SupportMaterial.cpp
     SupportMaterial.hpp
diff --git a/src/libslic3r/SupportSpotsGenerator.cpp b/src/libslic3r/SupportSpotsGenerator.cpp
index 08d734a38..4512c795b 100644
--- a/src/libslic3r/SupportSpotsGenerator.cpp
+++ b/src/libslic3r/SupportSpotsGenerator.cpp
@@ -2,6 +2,7 @@
 
 #include "tbb/parallel_for.h"
 #include "tbb/blocked_range.h"
+#include "tbb/blocked_range2d.h"
 #include "tbb/parallel_reduce.h"
 #include <boost/log/trivial.hpp>
 #include <cmath>
@@ -23,29 +24,32 @@
 
 namespace Slic3r {
 
-static const size_t NULL_ACC_ID = std::numeric_limits<size_t>::max();
-
 class ExtrusionLine
 {
 public:
     ExtrusionLine() :
-            a(Vec2f::Zero()), b(Vec2f::Zero()), len(0.0f), external_perimeter(false) {
+            a(Vec2f::Zero()), b(Vec2f::Zero()), len(0.0f), origin_entity(nullptr) {
     }
-    ExtrusionLine(const Vec2f &_a, const Vec2f &_b, bool external_perimeter) :
-            a(_a), b(_b), len((_a - _b).norm()), external_perimeter(external_perimeter) {
+    ExtrusionLine(const Vec2f &_a, const Vec2f &_b, const ExtrusionEntity *origin_entity) :
+            a(_a), b(_b), len((_a - _b).norm()), origin_entity(origin_entity) {
     }
 
     float length() {
         return (a - b).norm();
     }
 
+    bool is_external_perimeter() const {
+        assert(origin_entity != nullptr);
+        return origin_entity->role() == erExternalPerimeter;
+    }
+
     Vec2f a;
     Vec2f b;
     float len;
-    bool external_perimeter;
+    const ExtrusionEntity *origin_entity;
 
+    bool support_point_generated = false;
     float malformation = 0.0f;
-    size_t stability_accumulator_id = NULL_ACC_ID;
 
     static const constexpr int Dim = 2;
     using Scalar = Vec2f::Scalar;
@@ -60,29 +64,136 @@ auto get_b(ExtrusionLine &&l) {
 
 namespace SupportSpotsGenerator {
 
-void Issues::add(const Issues &layer_issues) {
-    supports_nedded.insert(supports_nedded.end(), layer_issues.supports_nedded.begin(),
-            layer_issues.supports_nedded.end());
-    curling_up.insert(curling_up.end(), layer_issues.curling_up.begin(), layer_issues.curling_up.end());
+SupportPoint::SupportPoint(const Vec3f &position, float force, const Vec3f &direction) :
+        position(position), force(force), direction(direction) {
 }
 
-bool Issues::empty() const {
-    return supports_nedded.empty() && curling_up.empty();
-}
+class LinesDistancer {
+private:
+    std::vector<ExtrusionLine> lines;
+    AABBTreeIndirect::Tree<2, float> tree;
 
-SupportPoint::SupportPoint(const Vec3f &position, float weight) :
-        position(position), weight(weight) {
-}
+public:
+    explicit LinesDistancer(std::vector<ExtrusionLine> &lines) :
+            lines(lines) {
+        tree = AABBTreeLines::build_aabb_tree_over_indexed_lines(this->lines);
+    }
 
-CurledFilament::CurledFilament(const Vec3f &position, float estimated_height) :
-        position(position), estimated_height(estimated_height) {
-}
+    // negative sign means inside
+    float signed_distance_from_lines(const Vec2f &point, size_t &nearest_line_index_out,
+            Vec2f &nearest_point_out) const {
+        auto distance = AABBTreeLines::squared_distance_to_indexed_lines(lines, tree, point, nearest_line_index_out,
+                nearest_point_out);
+        if (distance < 0)
+            return std::numeric_limits<float>::infinity();
 
-CurledFilament::CurledFilament(const Vec3f &position) :
-        position(position), estimated_height(0.0f) {
-}
+        distance = sqrt(distance);
+        const ExtrusionLine &line = lines[nearest_line_index_out];
+        Vec2f v1 = line.b - line.a;
+        Vec2f v2 = point - line.a;
+        if ((v1.x() * v2.y()) - (v1.y() * v2.x()) > 0.0) {
+            distance *= -1;
+        }
+        return distance;
+    }
 
-struct VoxelGrid {
+    const ExtrusionLine& get_line(size_t line_idx) const {
+        return lines[line_idx];
+    }
+
+    const std::vector<ExtrusionLine>& get_lines() const {
+        return lines;
+    }
+};
+
+static const size_t NULL_ISLAND = std::numeric_limits<size_t>::max();
+
+class PixelGrid {
+    Vec2f pixel_size;
+    Vec2f origin;
+    Vec2f size;
+    Vec2i pixel_count;
+
+    std::vector<size_t> pixels { };
+
+public:
+    PixelGrid(const PrintObject *po, float resolution) {
+        pixel_size = Vec2f(resolution, resolution);
+
+        Vec2crd size_half = po->size().head<2>().cwiseQuotient(Vec2crd(2, 2)) + Vec2crd::Ones();
+        Vec2f min = unscale(Vec2crd(-size_half.x(), -size_half.y())).cast<float>();
+        Vec2f max = unscale(Vec2crd(size_half.x(), size_half.y())).cast<float>();
+
+        origin = min;
+        size = max - min;
+        pixel_count = size.cwiseQuotient(pixel_size).cast<int>() + Vec2i::Ones();
+
+        pixels.resize(pixel_count.y() * pixel_count.x());
+        clear();
+    }
+
+    void distribute_edge(const Vec2f &p1, const Vec2f &p2, size_t value) {
+        Vec2f dir = (p2 - p1);
+        float length = dir.norm();
+        if (length < 0.1) {
+            return;
+        }
+        float step_size = this->pixel_size.x() / 2.0;
+
+        float distributed_length = 0;
+        while (distributed_length < length) {
+            float next_len = std::min(length, distributed_length + step_size);
+            Vec2f location = p1 + ((next_len / length) * dir);
+            this->access_pixel(location) = value;
+
+            distributed_length = next_len;
+        }
+    }
+
+    void clear() {
+        for (size_t &val : pixels) {
+            val = NULL_ISLAND;
+        }
+    }
+
+    float pixel_area() const {
+        return this->pixel_size.x() * this->pixel_size.y();
+    }
+
+    size_t get_pixel(const Vec2i &coords) const {
+        return pixels[this->to_pixel_index(coords)];
+    }
+
+    Vec2i get_pixel_count() {
+        return pixel_count;
+    }
+
+    Vec2f get_pixel_center(const Vec2i &coords) const {
+        return origin + coords.cast<float>().cwiseProduct(this->pixel_size)
+                + this->pixel_size.cwiseQuotient(Vec2f(2.0f, 2.0f));
+    }
+
+private:
+    Vec2i to_pixel_coords(const Vec2f &position) const {
+        Vec2i pixel_coords = (position - this->origin).cwiseQuotient(this->pixel_size).cast<int>();
+        return pixel_coords;
+    }
+
+    size_t to_pixel_index(const Vec2i &pixel_coords) const {
+        assert(pixel_coords.x() >= 0);
+        assert(pixel_coords.x() < pixel_count.x());
+        assert(pixel_coords.y() >= 0);
+        assert(pixel_coords.y() < pixel_count.y());
+
+        return pixel_coords.y() * pixel_count.x() + pixel_coords.x();
+    }
+
+    size_t& access_pixel(const Vec2f &position) {
+        return pixels[this->to_pixel_index(this->to_pixel_coords(position))];
+    }
+};
+
+struct SupportGridFilter {
 private:
     Vec3f cell_size;
     Vec3f origin;
@@ -92,7 +203,7 @@ private:
     std::unordered_set<size_t> taken_cells { };
 
 public:
-    VoxelGrid(const PrintObject *po, float voxel_size) {
+    SupportGridFilter(const PrintObject *po, float voxel_size) {
         cell_size = Vec3f(voxel_size, voxel_size, voxel_size);
 
         Vec2crd size_half = po->size().head<2>().cwiseQuotient(Vec2crd(2, 2)) + Vec2crd::Ones();
@@ -137,197 +248,25 @@ public:
 
 };
 
-class LayerLinesDistancer {
-private:
-    std::vector<ExtrusionLine> lines;
-    AABBTreeIndirect::Tree<2, float> tree;
-
-public:
-    explicit LayerLinesDistancer(std::vector<ExtrusionLine> &&lines) :
-            lines(lines) {
-        tree = AABBTreeLines::build_aabb_tree_over_indexed_lines(this->lines);
-    }
-
-    // negative sign means inside
-    float signed_distance_from_lines(const Vec2f &point, size_t &nearest_line_index_out,
-            Vec2f &nearest_point_out) const {
-        auto distance = AABBTreeLines::squared_distance_to_indexed_lines(lines, tree, point, nearest_line_index_out,
-                nearest_point_out);
-        if (distance < 0)
-            return std::numeric_limits<float>::infinity();
-
-        distance = sqrt(distance);
-        const ExtrusionLine &line = lines[nearest_line_index_out];
-        Vec2f v1 = line.b - line.a;
-        Vec2f v2 = point - line.a;
-        if ((v1.x() * v2.y()) - (v1.y() * v2.x()) > 0.0) {
-            distance *= -1;
-        }
-        return distance;
-    }
-
-    const ExtrusionLine& get_line(size_t line_idx) const {
-        return lines[line_idx];
-    }
-
-    const std::vector<ExtrusionLine>& get_lines() const {
-        return lines;
-    }
-
-    void set_new_acc_id(size_t line_idx, size_t acc_id) {
-        lines[line_idx].stability_accumulator_id = acc_id;
-    }
+struct IslandConnection {
+    float area;
+    Vec3f centroid_accumulator;
 };
 
-// StabilityAccumulator accumulates extrusions for each connected model part from bed to current printed layer.
-//  If the originaly disconected parts meet in the layer, their stability accumulators get merged and continue as one.
-// (think legs of table, which get connected when the top desk is being printed).
-// The class gathers mass, centroid mass, sticking force (bed extrusions, support points) and sticking centroid for the
-// connected part. These values are then used to check global part stability.
-class StabilityAccumulator {
-private:
-    std::vector<Vec2f> support_points { };
-    Vec3f centroid_accumulator = Vec3f::Zero();
-    float accumulated_volume { };
-    Vec2f sticking_centroid_accumulator = Vec2f::Zero();
-    float accumulated_sticking_force { };
+struct Island {
+    std::unordered_map<size_t, IslandConnection> connected_islands;
+    std::vector<Vec3f> pivot_points; // for support points present on this layer (or bed extrusions)
+    float volume;
+    Vec3f volume_centroid_accumulator;
+    float sticking_force; // for support points present on this layer (or bed extrusions)
+    Vec3f sticking_centroid_accumulator;
 
-public:
-    StabilityAccumulator() = default;
-
-    void add_base_extrusion(const ExtrusionLine &line, float sticking_force, float print_z, float mm3_per_mm) {
-        accumulated_sticking_force += sticking_force;
-        sticking_centroid_accumulator += sticking_force * ((line.a + line.b) / 2.0f);
-        support_points.push_back(line.a);
-        support_points.push_back(line.b);
-        add_extrusion(line, print_z, mm3_per_mm);
-    }
-
-    void add_support_point(const Vec2f &position, float sticking_force) {
-        support_points.push_back(position);
-        accumulated_sticking_force += sticking_force;
-        sticking_centroid_accumulator += sticking_force * position;
-    }
-
-    void add_extrusion(const ExtrusionLine &line, float print_z, float mm3_per_mm) {
-        float volume = line.len * mm3_per_mm;
-        accumulated_volume += volume;
-        Vec2f center = (line.a + line.b) / 2.0f;
-        centroid_accumulator += volume * Vec3f(center.x(), center.y(), print_z);
-    }
-
-    Vec3f get_centroid() const {
-        if (accumulated_volume <= 0.0f) {
-            return Vec3f::Zero();
-        }
-        return centroid_accumulator / accumulated_volume;
-    }
-
-    float get_sticking_force() const {
-        return accumulated_sticking_force;
-    }
-
-    float get_accumulated_volume() const {
-        return accumulated_volume;
-    }
-
-    const std::vector<Vec2f>& get_support_points() const {
-        return support_points;
-    }
-
-    Vec2f get_sticking_centroid() const {
-        if (accumulated_sticking_force <= 0.0f) {
-            return Vec2f::Zero();
-        }
-        return sticking_centroid_accumulator / accumulated_sticking_force;
-    }
-
-    void add_from(const StabilityAccumulator &acc) {
-        this->support_points.insert(this->support_points.end(), acc.support_points.begin(),
-                acc.support_points.end());
-        this->centroid_accumulator += acc.centroid_accumulator;
-        this->accumulated_volume += acc.accumulated_volume;
-        this->accumulated_sticking_force += acc.accumulated_sticking_force;
-        this->sticking_centroid_accumulator += acc.sticking_centroid_accumulator;
-    }
+    std::vector<ExtrusionLine> external_lines;
 };
 
-// StabilityAccumulators class is wrapper over the vector of stability accumualtors. It provides a level of indirection
-// between accumulator ID and the accumulator instance itself. While each extrusion line has one id, which is asigned
-// when algorithm reaches the line's layer, the accumulator this id points to can change due to merging.
-struct StabilityAccumulators {
-private:
-    size_t next_id = 0;
-    std::unordered_map<size_t, size_t> mapping;
-    std::vector<StabilityAccumulator> accumulators;
-
-    void merge_to(size_t from_id, size_t to_id) {
-        StabilityAccumulator &from_acc = this->access(from_id);
-        StabilityAccumulator &to_acc = this->access(to_id);
-        if (&from_acc == &to_acc) {
-            return;
-        }
-        to_acc.add_from(from_acc);
-        mapping[from_id] = mapping[to_id];
-        from_acc = StabilityAccumulator { };
-
-    }
-
-public:
-    StabilityAccumulators() = default;
-
-    size_t create_accumulator() {
-        size_t id = next_id;
-        next_id++;
-        mapping[id] = accumulators.size();
-        accumulators.push_back(StabilityAccumulator { });
-        return id;
-    }
-
-    StabilityAccumulator& access(size_t id) {
-        return accumulators[mapping[id]];
-    }
-
-    void merge_accumulators(size_t id_a, size_t id_b) {
-        size_t from_id = std::max(id_a, id_b);
-        size_t to_id = std::min(id_a, id_b);
-        if (from_id == NULL_ACC_ID || to_id == NULL_ACC_ID) {
-            return;
-        }
-        StabilityAccumulator &from_acc = this->access(from_id);
-        StabilityAccumulator &to_acc = this->access(to_id);
-        if (&from_acc == &to_acc) {
-            return;
-        }
-        to_acc.add_from(from_acc);
-        mapping[from_id] = mapping[to_id];
-        from_acc = StabilityAccumulator { };
-    }
-
-#ifdef DEBUG_FILES
-    Vec3f get_accumulator_color(size_t id) {
-        if (mapping.find(id) == mapping.end()) {
-            BOOST_LOG_TRIVIAL(debug)
-            << "SSG: ERROR: uknown accumulator ID: " << id;
-            return Vec3f(1.0f, 1.0f, 1.0f);
-        }
-
-        size_t pseudornd = ((mapping[id] + 127) * 33331 + 6907) % 987;
-        return value_to_rgbf(0.0f, float(987), float(pseudornd));
-    }
-
-    void log_accumulators() {
-        for (size_t i = 0; i < accumulators.size(); ++i) {
-            const auto &acc = accumulators[i];
-            BOOST_LOG_TRIVIAL(debug)
-            << "SSG: accumulator POS: " << i << "\n"
-                    << "SSG: get_accumulated_volume: " << acc.get_accumulated_volume() << "\n"
-                    << "SSG: get_sticking_force: " << acc.get_sticking_force() << "\n"
-                    << "SSG: support points count: " << acc.get_support_points().size() << "\n";
-
-        }
-    }
-#endif
+struct LayerIslands {
+    std::vector<Island> islands;
+    float layer_z;
 };
 
 float get_flow_width(const LayerRegion *region, ExtrusionRole role) {
@@ -375,28 +314,18 @@ struct ExtrusionPropertiesAccumulator {
     }
 };
 
-// check_extrusion_entity_stability checks each extrusion for local issues, appends the extrusion
-// into checked lines, and gives it a stability accumulator id. If support is needed it pushes it
-// into issues as well.
-// Rules for stability accumulator id assigment:
-// If there is close extrusion under, use min extrusion id between the id of the previous line,
-//      and id of line under. Also merge the accumulators of those two ids!
-// If there is no close extrusion under, use id of the previous extrusion line.
-// If there is no previous line, create new stability accumulator.
 void check_extrusion_entity_stability(const ExtrusionEntity *entity,
-        StabilityAccumulators &stability_accs,
-        Issues &issues,
-        std::vector<ExtrusionLine> &checked_lines,
+        std::vector<ExtrusionLine> &checked_lines_out,
         float print_z,
         const LayerRegion *layer_region,
-        const LayerLinesDistancer &prev_layer_lines,
+        const LinesDistancer &prev_layer_lines,
+        Issues &issues,
         const Params &params) {
 
     if (entity->is_collection()) {
         for (const auto *e : static_cast<const ExtrusionEntityCollection*>(entity)->entities) {
-            check_extrusion_entity_stability(e, stability_accs, issues, checked_lines, print_z, layer_region,
-                    prev_layer_lines,
-                    params);
+            check_extrusion_entity_stability(e, checked_lines_out, print_z, layer_region, prev_layer_lines,
+                    issues, params);
         }
     } else { //single extrusion path, with possible varying parameters
         const auto to_vec3f = [print_z](const Vec2f &point) {
@@ -406,8 +335,7 @@ void check_extrusion_entity_stability(const ExtrusionEntity *entity,
         entity->collect_points(points);
         std::vector<ExtrusionLine> lines;
         lines.reserve(points.size() * 1.5);
-        bool is_ex_perimeter = entity->role() == erExternalPerimeter;
-        lines.emplace_back(unscaled(points[0]).cast<float>(), unscaled(points[0]).cast<float>(), is_ex_perimeter);
+        lines.emplace_back(unscaled(points[0]).cast<float>(), unscaled(points[0]).cast<float>(), entity);
         for (int point_idx = 0; point_idx < int(points.size() - 1); ++point_idx) {
             Vec2f start = unscaled(points[point_idx]).cast<float>();
             Vec2f next = unscaled(points[point_idx + 1]).cast<float>();
@@ -419,11 +347,10 @@ void check_extrusion_entity_stability(const ExtrusionEntity *entity,
             for (int i = 0; i < lines_count; ++i) {
                 Vec2f a(start + v * (i * step_size));
                 Vec2f b(start + v * ((i + 1) * step_size));
-                lines.emplace_back(a, b, is_ex_perimeter);
+                lines.emplace_back(a, b, entity);
             }
         }
 
-        size_t current_stability_acc = NULL_ACC_ID;
         ExtrusionPropertiesAccumulator bridging_acc { };
         ExtrusionPropertiesAccumulator malformation_acc { };
         bridging_acc.add_distance(params.bridge_distance + 1.0f); // Initialise unsupported distance with larger than tolerable distance ->
@@ -432,8 +359,6 @@ void check_extrusion_entity_stability(const ExtrusionEntity *entity,
 
         for (size_t line_idx = 0; line_idx < lines.size(); ++line_idx) {
             ExtrusionLine &current_line = lines[line_idx];
-            float mm3_per_mm = float(entity->min_mm3_per_mm());
-
             float curr_angle = 0;
             if (line_idx + 1 < lines.size()) {
                 const Vec2f v1 = current_line.b - current_line.a;
@@ -448,28 +373,16 @@ void check_extrusion_entity_stability(const ExtrusionEntity *entity,
             float dist_from_prev_layer = prev_layer_lines.signed_distance_from_lines(current_line.b, nearest_line_idx,
                     nearest_point);
 
-            if (dist_from_prev_layer < flow_width) {
-                const ExtrusionLine &nearest_line = prev_layer_lines.get_line(nearest_line_idx);
-                size_t acc_id = nearest_line.stability_accumulator_id;
-                stability_accs.merge_accumulators(acc_id, current_stability_acc);
-                current_stability_acc = std::min(acc_id, current_stability_acc);
-                current_line.stability_accumulator_id = current_stability_acc;
-                stability_accs.access(current_stability_acc).add_extrusion(current_line, print_z, mm3_per_mm);
+            if (fabs(dist_from_prev_layer) < flow_width) {
                 bridging_acc.reset();
             } else {
                 bridging_acc.add_distance(current_line.len);
-                if (current_stability_acc == NULL_ACC_ID) {
-                    current_stability_acc = stability_accs.create_accumulator();
-                }
-                StabilityAccumulator &current_segment = stability_accs.access(current_stability_acc);
-                current_line.stability_accumulator_id = current_stability_acc;
-                current_segment.add_extrusion(current_line, print_z, mm3_per_mm);
                 if (bridging_acc.distance // if unsupported distance is larger than bridge distance linearly decreased by curvature, enforce supports.
                 > params.bridge_distance
                         / (1.0f + (bridging_acc.max_curvature
                                 * params.bridge_distance_decrease_by_curvature_factor / PI))) {
-                    current_segment.add_support_point(current_line.b, 0.0f); // Do not count extrusion supports into the sticking force. They can be very densely placed, causing algorithm to overestimate stickiness.
-                    issues.supports_nedded.emplace_back(to_vec3f(current_line.b), 1.0);
+                    issues.support_points.emplace_back(to_vec3f(current_line.b), 0.0f, Vec3f(0.f, 0.0f, -1.0f));
+                    current_line.support_point_generated = true;
                     bridging_acc.reset();
                 }
             }
@@ -481,166 +394,83 @@ void check_extrusion_entity_stability(const ExtrusionEntity *entity,
             }
             if (dist_from_prev_layer > flow_width * 0.3) {
                 malformation_acc.add_distance(current_line.len);
-                current_line.malformation += 0.15
-                        * (0.8 + 0.2 * malformation_acc.max_curvature / (1.0f + 0.5f * malformation_acc.distance));
+                current_line.malformation += 0.15f
+                        * (0.8f + 0.2f * malformation_acc.max_curvature / (1.0f + 0.5f * malformation_acc.distance));
             } else {
                 malformation_acc.reset();
             }
         }
-        checked_lines.insert(checked_lines.end(), lines.begin(), lines.end());
+        checked_lines_out.insert(checked_lines_out.end(), lines.begin(), lines.end());
     }
 }
 
-//check_layer_global_stability checks stability of the accumulators that are still present on the current line
-// ( this is determined from the gathered checked_lines vector)
-// For each accumulator and each its extrusion, forces and torques (weight, bed movement, extruder pressure, stickness to bed)
-// are computed and if stability is not sufficient, support points are added
-// accumualtors are filtered by their pointer address, since one accumulator can have multiple IDs due to merging
-void check_layer_global_stability(StabilityAccumulators &stability_accs,
-        VoxelGrid &supports_presence_grid,
-        Issues &issues,
-        float flow_width,
-        const std::vector<ExtrusionLine> &checked_lines,
-        float print_z,
+std::tuple<LayerIslands, PixelGrid> reckon_islands(
+        const Layer *layer, bool first_layer,
+        size_t prev_layer_islands_count,
+        const PixelGrid &prev_layer_grid,
+        const std::vector<ExtrusionLine> &layer_lines,
         const Params &params) {
-    std::unordered_map<StabilityAccumulator*, std::vector<ExtrusionLine>> layer_accs_w_lines;
-    for (size_t i = 0; i < checked_lines.size(); ++i) {
-        layer_accs_w_lines[&stability_accs.access(checked_lines[i].stability_accumulator_id)].push_back(
-                checked_lines[i]);
-    }
 
-    for (auto &accumulator : layer_accs_w_lines) {
-        StabilityAccumulator *acc = accumulator.first;
-        LayerLinesDistancer acc_lines(std::move(accumulator.second));
-
-        if (acc->get_support_points().empty()) {
-            // acc_lines cannot be empty - if the accumulator has no extrusion in the current layer, it is not considered in stability computation
-            acc->add_support_point(acc_lines.get_line(0).a, 0.0f);
-            issues.supports_nedded.emplace_back(to_3d(acc_lines.get_line(0).a, print_z), 0.0);
-        }
-        const std::vector<Vec2f> &support_points = acc->get_support_points();
-
-        auto coord_fn = [&support_points](size_t idx, size_t dim) {
-            return support_points[idx][dim];
-        };
-        KDTreeIndirect<2, float, decltype(coord_fn)> supports_tree(coord_fn, support_points.size());
-
-        for (const ExtrusionLine &line : acc_lines.get_lines()) {
-            Vec2f line_dir = (line.b - line.a).normalized();
-            Vec2f pivot_site_search_point = line.b + line_dir * 300.0f;
-            size_t pivot_idx = find_closest_point(supports_tree, pivot_site_search_point);
-            const Vec2f &pivot = support_points[pivot_idx];
-
-            const Vec2f &sticking_centroid = acc->get_sticking_centroid();
-            float sticking_arm = (pivot - sticking_centroid).norm();
-            float sticking_torque = sticking_arm * acc->get_sticking_force();
-
-            float mass = acc->get_accumulated_volume() * params.filament_density;
-            const Vec3f &mass_centorid = acc->get_centroid();
-            float weight = mass * params.gravity_constant;
-            float weight_arm = (pivot - mass_centorid.head<2>()).norm();
-            float weight_torque = weight_arm * weight;
-
-            float bed_movement_arm = mass_centorid.z();
-            float bed_movement_force = params.max_acceleration * mass;
-            float bed_movement_torque = bed_movement_force * bed_movement_arm;
-
-            Vec3f extruder_pressure_direction = to_3d(line_dir, 0.0f);
-            extruder_pressure_direction.z() = -0.2 - line.malformation * 0.5;
-            extruder_pressure_direction.normalize();
-            float conflict_torque_arm = (to_3d(Vec2f(pivot - line.b), print_z).cross(
-                    extruder_pressure_direction)).norm();
-            float extruder_conflict_force = params.tolerable_extruder_conflict_force +
-                    std::min(line.malformation, 1.0f) * params.malformations_additive_conflict_extruder_force;
-            float extruder_conflict_torque = extruder_conflict_force * conflict_torque_arm;
-
-            float total_torque = bed_movement_torque + extruder_conflict_torque - weight_torque - sticking_torque;
-
-            if (total_torque > 0) {
-                Vec2f target_point;
-                size_t _idx;
-                acc_lines.signed_distance_from_lines(pivot_site_search_point, _idx, target_point);
-                if (!supports_presence_grid.position_taken(to_3d(target_point, print_z))) {
-                    float area = params.support_points_interface_radius * params.support_points_interface_radius
-                            * float(PI);
-                    float sticking_force = area * params.support_adhesion;
-                    acc->add_support_point(target_point, sticking_force);
-                    issues.supports_nedded.emplace_back(to_3d(target_point, print_z),
-                            extruder_conflict_torque - sticking_torque);
-                    supports_presence_grid.take_position(to_3d(target_point, print_z));
-                }
-            }
-#if 0
-            BOOST_LOG_TRIVIAL(debug)
-            << "SSG: sticking_arm: " << sticking_arm;
-            BOOST_LOG_TRIVIAL(debug)
-            << "SSG: sticking_torque: " << sticking_torque;
-            BOOST_LOG_TRIVIAL(debug)
-            << "SSG: weight_arm: " << sticking_arm;
-            BOOST_LOG_TRIVIAL(debug)
-            << "SSG: weight_torque: " << weight_torque;
-            BOOST_LOG_TRIVIAL(debug)
-            << "SSG: bed_movement_arm: " << bed_movement_arm;
-            BOOST_LOG_TRIVIAL(debug)
-            << "SSG: bed_movement_torque: " << bed_movement_torque;
-            BOOST_LOG_TRIVIAL(debug)
-            << "SSG: conflict_torque_arm: " << conflict_torque_arm;
-            BOOST_LOG_TRIVIAL(debug)
-            << "SSG: extruder_conflict_torque: " << extruder_conflict_torque;
-            BOOST_LOG_TRIVIAL(debug)
-            << "SSG: total_torque: " << total_torque << "   printz: " << print_z;
-#endif
-        }
-    }
-}
-
-void reckon_thin_islands(StabilityAccumulators &stability_accs,
-        float flow_width,
-        float mm3_per_mm,
-        float print_z,
-        LayerLinesDistancer &layer_lines,
-        const Params& params) {
-    const std::vector<ExtrusionLine> &lines = layer_lines.get_lines();
-    std::vector<std::pair<size_t,size_t>> extrusions; //start and end idx (one beyond last extrusion) [start,end)
-    Vec2f current_pt = lines[0].a;
-    std::pair<size_t,size_t> current_ext(0,1);
-    for (size_t lidx = 0; lidx < lines.size(); ++lidx) {
-        const ExtrusionLine& line = lines[lidx];
-        if (line.a == current_pt) {
-            current_ext.second = lidx + 1;
+    //extract extrusions (connected paths from multiple lines) from the layer_lines. belonging to single polyline is determined by origin_entity ptr.
+    // result is a vector of [start, end) index pairs into the layer_lines vector
+    std::vector<std::pair<size_t, size_t>> extrusions; //start and end idx (one beyond last extrusion) [start,end)
+    const ExtrusionEntity *current_ex = nullptr;
+    for (size_t lidx = 0; lidx < layer_lines.size(); ++lidx) {
+        const ExtrusionLine &line = layer_lines[lidx];
+        if (line.origin_entity == current_ex) {
+            extrusions.back().second = lidx + 1;
         } else {
-            extrusions.push_back(current_ext);
-            current_ext.first = lidx;
-            current_ext.second = lidx + 1;
+            extrusions.emplace_back(lidx, lidx + 1);
+            current_ex = line.origin_entity;
         }
-        current_pt = line.b;
     }
 
-    std::vector<LayerLinesDistancer> islands;
-    std::vector<std::vector<size_t>> island_extrusions;
+    std::vector<LinesDistancer> islands; // these search trees will be used to determine to which island does the extrusion begin
+    std::vector<std::vector<size_t>> island_extrusions; //final assigment of each extrusion to an island
+    // initliaze the search from external perimeters - at the beginning, there is island candidate for each external perimeter.
+    // some of them will disappear (e.g. holes)
     for (size_t e = 0; e < extrusions.size(); ++e) {
-        if (lines[extrusions[e].first].external_perimeter) {
+        if (layer_lines[extrusions[e].first].is_external_perimeter()) {
             std::vector<ExtrusionLine> copy(extrusions[e].second - extrusions[e].first);
             for (size_t ex_line_idx = extrusions[e].first; ex_line_idx < extrusions[e].second; ++ex_line_idx) {
-                copy[ex_line_idx-extrusions[e].first] = lines[ex_line_idx];
+                copy[ex_line_idx - extrusions[e].first] = layer_lines[ex_line_idx];
             }
-            islands.emplace_back(std::move(copy));
-            island_extrusions.push_back({e});
+            islands.emplace_back(copy);
+            island_extrusions.push_back( { e });
         }
     }
+    // backup code if islands not found - this can currently happen, as external perimeters may be also pure overhang perimeters, and there is no
+    // way to distinguish external extrusions with total certainty.
+    // If that happens, just make the first extrusion into island - it may be wrong, but it won't crash.
+    if (islands.empty() && !extrusions.empty()) {
+        std::vector<ExtrusionLine> copy(extrusions[0].second - extrusions[0].first);
+        for (size_t ex_line_idx = extrusions[0].first; ex_line_idx < extrusions[0].second; ++ex_line_idx) {
+            copy[ex_line_idx - extrusions[0].first] = layer_lines[ex_line_idx];
+        }
+        islands.emplace_back(copy);
+        island_extrusions.push_back( { 0 });
+    }
 
-    for (size_t i = 0; i < islands.size(); ++i) {
-        for (size_t e = 0; e < extrusions.size(); ++e) {
-            if (!lines[extrusions[e].first].external_perimeter){
+    // assign non external extrusions to islands
+    for (size_t e = 0; e < extrusions.size(); ++e) {
+        if (!layer_lines[extrusions[e].first].is_external_perimeter()) {
+            bool island_assigned = false;
+            for (size_t i = 0; i < islands.size(); ++i) {
                 size_t _idx;
                 Vec2f _pt;
-                if (islands[i].signed_distance_from_lines(lines[extrusions[e].first].a, _idx, _pt) < 0) {
+                if (islands[i].signed_distance_from_lines(layer_lines[extrusions[e].first].a, _idx, _pt) < 0) {
                     island_extrusions[i].push_back(e);
+                    island_assigned = true;
+                    break;
                 }
             }
+            if (!island_assigned) { // If extrusion is not assigned for some reason, push it into the first island. As with the previous backup code,
+                // it may be wrong, but it won't crash
+                island_extrusions[0].push_back(e);
+            }
         }
     }
-
+    // merge islands which are embedded within each other (mainly holes)
     for (size_t i = 0; i < islands.size(); ++i) {
         if (islands[i].get_lines().empty()) {
             continue;
@@ -659,241 +489,570 @@ void reckon_thin_islands(StabilityAccumulators &stability_accs,
         }
     }
 
-    size_t islands_count = 0;
-    for (const std::vector<size_t>& island_ex : island_extrusions) {
+    float flow_width = get_flow_width(layer->regions()[0], erExternalPerimeter);
+    // after filtering the layer lines into islands, build the result LayerIslands structure.
+    LayerIslands result { };
+    result.layer_z = layer->slice_z;
+    std::vector<size_t> line_to_island_mapping(layer_lines.size(), NULL_ISLAND);
+    for (const std::vector<size_t> &island_ex : island_extrusions) {
         if (island_ex.empty()) {
             continue;
         }
-        islands_count++;
-        float cross_section = 0.0f;
-        size_t acc_id = NULL_ACC_ID;
+
+        Island island { };
+        island.external_lines.insert(island.external_lines.end(),
+                layer_lines.begin() + extrusions[island_ex[0]].first,
+                layer_lines.begin() + extrusions[island_ex[0]].second);
         for (size_t extrusion_idx : island_ex) {
             for (size_t lidx = extrusions[extrusion_idx].first; lidx < extrusions[extrusion_idx].second; ++lidx) {
-                const ExtrusionLine& line = lines[lidx];
-                cross_section += line.len * flow_width;
-                stability_accs.merge_accumulators(acc_id, line.stability_accumulator_id);
-                acc_id = std::min(acc_id, line.stability_accumulator_id);
+                line_to_island_mapping[lidx] = result.islands.size();
+                const ExtrusionLine &line = layer_lines[lidx];
+                float volume = line.origin_entity->min_mm3_per_mm() * line.len;
+                island.volume += volume;
+                island.volume_centroid_accumulator += to_3d(Vec2f((line.a + line.b) / 2.0f), float(layer->print_z))
+                        * volume;
+
+                if (first_layer) {
+                    float sticking_force = line.len * flow_width * params.base_adhesion;
+                    island.sticking_force += sticking_force;
+                    island.sticking_centroid_accumulator += sticking_force
+                            * to_3d(Vec2f((line.a + line.b) / 2.0f), float(layer->print_z));
+                    if (line.is_external_perimeter()) {
+                        island.pivot_points.push_back(to_3d(Vec2f(line.b), float(layer->print_z)));
+                    }
+                } else if (layer_lines[lidx].support_point_generated) {
+                    float support_interface_area = params.support_points_interface_radius
+                            * params.support_points_interface_radius
+                            * float(PI);
+                    float sticking_force = support_interface_area * params.support_adhesion;
+                    island.sticking_force += sticking_force;
+                    island.sticking_centroid_accumulator += sticking_force
+                            * to_3d(Vec2f(line.b), float(layer->print_z));
+                    island.pivot_points.push_back(to_3d(Vec2f(line.b), float(layer->print_z)));
+                }
             }
         }
+        result.islands.push_back(island);
+    }
 
-        float max_force = cross_section * params.tensile_strength;
-
-        if (stability_accs.access(acc_id).get_sticking_force() > max_force) {
-            BOOST_LOG_TRIVIAL(debug) << "SSG: Forking new accumulator for island because tensile strenth is too low: " << max_force;
-            BOOST_LOG_TRIVIAL(debug) << "SSG: sticking force: " << stability_accs.access(acc_id).get_sticking_force();
-
-            size_t new_acc_id = stability_accs.create_accumulator();
-            StabilityAccumulator& acc = stability_accs.access(new_acc_id);
-
-            for (size_t extrusion_idx : island_ex) {
-                for (size_t lidx = extrusions[extrusion_idx].first; lidx < extrusions[extrusion_idx].second; ++lidx) {
-                    const ExtrusionLine& line = lines[lidx];
-                    float tensile_strength = params.tensile_strength * line.len * flow_width;
-                    acc.add_base_extrusion(line, tensile_strength, print_z, mm3_per_mm);
-                    layer_lines.set_new_acc_id(lidx, new_acc_id);
+    //LayerIslands structure built. Now determine connections and their areas to the previous layer using raterization.
+    PixelGrid current_layer_grid = prev_layer_grid;
+    current_layer_grid.clear();
+    // build index image of current layer
+    tbb::parallel_for(tbb::blocked_range<size_t>(0, layer_lines.size()),
+            [&layer_lines, &current_layer_grid, &line_to_island_mapping](
+                    tbb::blocked_range<size_t> r) {
+                for (size_t i = r.begin(); i < r.end(); ++i) {
+                    size_t island = line_to_island_mapping[i];
+                    const ExtrusionLine &line = layer_lines[i];
+                    current_layer_grid.distribute_edge(line.a, line.b, island);
                 }
+            });
+
+    //compare the image of previous layer with the current layer. For each pair of overlapping valid pixels, add pixel area to the respective island connection
+    for (size_t x = 0; x < size_t(current_layer_grid.get_pixel_count().x()); ++x) {
+        for (size_t y = 0; y < size_t(current_layer_grid.get_pixel_count().y()); ++y) {
+            Vec2i coords = Vec2i(x, y);
+            if (current_layer_grid.get_pixel(coords) != NULL_ISLAND
+                    && prev_layer_grid.get_pixel(coords) != NULL_ISLAND) {
+                IslandConnection& connection = result.islands[current_layer_grid.get_pixel(coords)]
+                                                              .connected_islands[prev_layer_grid.get_pixel(coords)];
+                connection.area += current_layer_grid.pixel_area();
+                connection.centroid_accumulator += to_3d(current_layer_grid.get_pixel_center(coords), result.layer_z) * current_layer_grid.pixel_area();
             }
         }
     }
 
-    BOOST_LOG_TRIVIAL(debug) << "SSG: There are " << islands_count << " islands on printz: " << print_z;
-
+    return {result, current_layer_grid};
 }
 
-Issues
-check_object_stability(const PrintObject *po, const Params &params) {
+struct ObjectPart {
+    float volume { };
+    Vec3f volume_centroid_accumulator = Vec3f::Zero();
+    float sticking_force { };
+    Vec3f sticking_centroid_accumulator = Vec3f::Zero();
+    std::vector<Vec3f> pivot_points { };
+
+    void add(const ObjectPart &other) {
+        this->volume_centroid_accumulator += other.volume_centroid_accumulator;
+        this->volume += other.volume;
+        this->sticking_force += other.sticking_force;
+        this->sticking_centroid_accumulator += other.sticking_centroid_accumulator;
+        this->pivot_points.insert(this->pivot_points.end(), other.pivot_points.begin(), other.pivot_points.end());
+    }
+
+    ObjectPart(const Island &island) {
+        this->volume = island.volume;
+        this->volume_centroid_accumulator = island.volume_centroid_accumulator;
+        this->sticking_force = island.sticking_force;
+        this->sticking_centroid_accumulator = island.sticking_centroid_accumulator;
+        this->pivot_points = island.pivot_points;
+    }
+
+    ObjectPart() = default;
+};
+
+struct WeakestConnection {
+    float area = 0.0f;
+    Vec3f centroid_accumulator = Vec3f::Zero();
+
+    void add(const WeakestConnection& other) {
+        this->area += other.area;
+        this->centroid_accumulator += other.centroid_accumulator;
+    }
+};
+
+Issues check_global_stability(const std::vector<LayerIslands> &islands_graph, const Params &params) {
+    Issues issues { };
+    size_t next_part_idx = 0;
+    std::unordered_map<size_t, ObjectPart> active_object_parts;
+    std::unordered_map<size_t, size_t> prev_island_to_object_part_mapping;
+    std::unordered_map<size_t, size_t> next_island_to_object_part_mapping;
+
+    std::unordered_map<size_t, WeakestConnection> prev_island_to_weakest_connection;
+    std::unordered_map<size_t, WeakestConnection> next_island_to_weakest_connection;
+
+    for (size_t layer_idx = 0; layer_idx < islands_graph.size(); ++layer_idx) {
+        float layer_z = islands_graph[layer_idx].layer_z;
+        std::unordered_set<size_t> layer_active_parts;
+        std::cout << "at layer: " << layer_idx << "  the following island to object mapping is used:" << std::endl;
+        for (const auto &m : prev_island_to_object_part_mapping) {
+            std::cout << "island " << m.first << " maps to part " << m.second << std::endl;
+            Vec3f connection_center = prev_island_to_weakest_connection[m.first].centroid_accumulator /  prev_island_to_weakest_connection[m.first].area;
+            std::cout << " island has weak point with connection area: " <<
+                    prev_island_to_weakest_connection[m.first].area << " and center: " <<
+                    connection_center.x() << " " << connection_center.y() << " " << connection_center.z() << std::endl;
+        }
+
+        for (size_t island_idx = 0; island_idx < islands_graph[layer_idx].islands.size(); ++island_idx) {
+            const Island &island = islands_graph[layer_idx].islands[island_idx];
+            if (island.connected_islands.empty()) { //new object part emerging
+                size_t part_idx = next_part_idx;
+                next_part_idx++;
+                active_object_parts.emplace(part_idx, ObjectPart(island));
+                next_island_to_object_part_mapping.emplace(island_idx, part_idx);
+                next_island_to_weakest_connection.emplace(island_idx,
+                        WeakestConnection{INFINITY, Vec3f::Zero()});
+                layer_active_parts.insert(part_idx);
+            } else {
+                size_t final_part_idx{};
+                WeakestConnection transfered_weakest_connection{};
+                WeakestConnection new_weakest_connection{};
+                // MERGE parts
+                {
+                    std::unordered_set<size_t> part_indices;
+                    for (const auto &connection : island.connected_islands) {
+                        part_indices.insert(prev_island_to_object_part_mapping.at(connection.first));
+                        transfered_weakest_connection.add(prev_island_to_weakest_connection.at(connection.first));
+                        new_weakest_connection.area += connection.second.area;
+                        new_weakest_connection.centroid_accumulator += connection.second.centroid_accumulator;
+                    }
+                    final_part_idx = *part_indices.begin();
+                    for (size_t part_idx : part_indices) {
+                        if (final_part_idx != part_idx) {
+                            std::cout << "at layer: " << layer_idx << "  merging object part: " << part_idx
+                                    << " into final part: " << final_part_idx << std::endl;
+                            active_object_parts.at(final_part_idx).add(active_object_parts.at(part_idx));
+                            active_object_parts.erase(part_idx);
+                        }
+                    }
+                }
+                auto estimate_strength = [layer_z](const WeakestConnection& conn){
+                    float radius = fsqrt(conn.area / PI);
+                    float arm_len_estimate = std::max(0.001f, layer_z - (conn.centroid_accumulator.z() / conn.area));
+                    return radius * conn.area / arm_len_estimate;
+                };
+
+                if (estimate_strength(transfered_weakest_connection) < estimate_strength(new_weakest_connection)) {
+                    new_weakest_connection = transfered_weakest_connection;
+                }
+                next_island_to_weakest_connection.emplace(island_idx, new_weakest_connection);
+                next_island_to_object_part_mapping.emplace(island_idx, final_part_idx);
+                ObjectPart &part = active_object_parts[final_part_idx];
+                part.add(ObjectPart(island));
+                layer_active_parts.insert(final_part_idx);
+            }
+        }
+
+        std::unordered_set<size_t> parts_to_delete;
+        for (const auto &part : active_object_parts) {
+            if (layer_active_parts.find(part.first) == layer_active_parts.end()) {
+                parts_to_delete.insert(part.first);
+            } else {
+                std::cout << "at layer " << layer_idx << " part is still active: " << part.first << std::endl;
+            }
+        }
+        for (size_t part_id : parts_to_delete) {
+            active_object_parts.erase(part_id);
+            std::cout << " at layer: " << layer_idx << " removing object part " << part_id << std::endl;
+        }
+        prev_island_to_object_part_mapping = next_island_to_object_part_mapping;
+        next_island_to_object_part_mapping.clear();
+        prev_island_to_weakest_connection = next_island_to_weakest_connection;
+        next_island_to_weakest_connection.clear();
+
+    }
+    return issues;
+}
+
+/*
+
+ // islands_graph.back() refers to the top most (current) layer
+ for (size_t island_idx = 0; island_idx < islands_graph.back().islands.size(); ++island_idx) {
+ Island &island = islands_graph.back().islands[island_idx];
+
+ std::vector<ExtrusionLine> island_external_lines;
+ for (size_t lidx : islands_lines[island_idx]) {
+ island_external_lines.push_back(layer_lines[lidx]);
+ }
+ LinesDistancer island_lines_dist(island_external_lines);
+ Accumulator acc = island; // in acc, we accumulate the mass and other properties of the object part as we traverse the islands down to bed
+ // There is one object part for each island at the top most layer, and each one is computed individually -
+ // Some of the calculations will be done multiple times
+ int layer_idx = islands_graph.size() - 1;
+ // traverse the islands graph down, and for each connection area, calculate if it holds or breaks
+ while (acc.connected_islands.size() > 0) {
+ //test for break between layer_idx and layer_idx -1;
+ LayerIslands below = islands_graph[layer_idx - 1]; // must exist, see while condition
+ layer_idx--;
+ // initialize variables that we will accumulate over all islands, which are connected to the current object part
+ std::vector<Vec2f> pivot_points;
+ Vec2f sticking_centroid;
+ float connection_area = 0;
+ for (const auto &pair : acc.connected_islands) {
+ const Island &below_i = below.islands[pair.first];
+ Vec2f centroid = (below_i.volume_centroid_accumulator / below_i.volume).head<2>(); // centroid of the island 'below_i'; TODO it should be centroid of the connection area
+ pivot_points.push_back(centroid); // for object parts, we also consider breaking pivots in the centroids of the islands
+ sticking_centroid += centroid * pair.second; // pair.second is connection area in mm^2
+ connection_area += pair.second;
+ }
+ sticking_centroid /= connection_area; //normalize to get final sticking centroid
+ for (const Vec3f &p_point : acc.pivot_points) {
+ pivot_points.push_back(p_point.head<2>());
+ }
+ // Now we have accumulated pivot points, connection area and sticking centroid of the whole layer to the current object part
+
+ // create KD tree over current pivot points
+ auto coord_fn = [&pivot_points](size_t idx, size_t dim) {
+ return pivot_points[idx][dim];
+ };
+ KDTreeIndirect<2, float, decltype(coord_fn)> pivot_points_tree(coord_fn, pivot_points.size());
+
+ // iterate over extrusions at top layer island, check each for stability
+ for (const ExtrusionLine &line : island_external_lines) {
+ Vec2f line_dir = (line.b - line.a).normalized();
+ Vec2f pivot_site_search_point = line.b + line_dir * 300.0f;
+ size_t pivot_idx = find_closest_point(pivot_points_tree, pivot_site_search_point);
+ const Vec2f &pivot = pivot_points[pivot_idx];
+
+ float sticking_arm = (pivot - sticking_centroid).norm();
+ float sticking_torque = sticking_arm * connection_area * params.tensile_strength; // For breakage in between layers, we compute with tensile strength, not bed adhesion
+
+ float mass = acc.volume * params.filament_density;
+ const Vec3f &mass_centorid = acc.volume_centroid_accumulator / acc.volume;
+ float weight = mass * params.gravity_constant;
+ float weight_arm = (pivot - mass_centorid.head<2>()).norm();
+ float weight_torque = weight_arm * weight;
+
+ float bed_movement_arm = mass_centorid.z();
+ float bed_movement_force = params.max_acceleration * mass;
+ float bed_movement_torque = bed_movement_force * bed_movement_arm;
+
+ Vec3f extruder_pressure_direction = to_3d(line_dir, 0.0f);
+ extruder_pressure_direction.z() = -0.2 - line.malformation * 0.5;
+ extruder_pressure_direction.normalize();
+ float conflict_torque_arm = (to_3d(Vec2f(pivot - line.b), print_z).cross(
+ extruder_pressure_direction)).norm();
+ float extruder_conflict_force = params.tolerable_extruder_conflict_force +
+ std::min(line.malformation, 1.0f) * params.malformations_additive_conflict_extruder_force;
+ float extruder_conflict_torque = extruder_conflict_force * conflict_torque_arm;
+
+ float total_torque = bed_movement_torque + extruder_conflict_torque - weight_torque - sticking_torque;
+
+ if (total_torque > 0) {
+ Vec2f target_point { };
+ size_t _idx { };
+ island_lines_dist.signed_distance_from_lines(pivot_site_search_point, _idx, target_point);
+ if (!supports_presence_grid.position_taken(to_3d(target_point, print_z))) {
+ float area = params.support_points_interface_radius * params.support_points_interface_radius
+ * float(PI);
+ float sticking_force = area * params.support_adhesion;
+ Vec3f support_point = to_3d(target_point, print_z);
+ island.pivot_points.push_back(support_point);
+ island.sticking_force += sticking_force;
+ island.sticking_centroid_accumulator += sticking_force * support_point;
+ issues.support_points.emplace_back(support_point,
+ extruder_conflict_torque - sticking_torque, extruder_pressure_direction);
+ supports_presence_grid.take_position(to_3d(target_point, print_z));
+ }
+ }
+ #if 0
+ BOOST_LOG_TRIVIAL(debug)
+ << "SSG: sticking_arm: " << sticking_arm;
+ BOOST_LOG_TRIVIAL(debug)
+ << "SSG: sticking_torque: " << sticking_torque;
+ BOOST_LOG_TRIVIAL(debug)
+ << "SSG: weight_arm: " << sticking_arm;
+ BOOST_LOG_TRIVIAL(debug)
+ << "SSG: weight_torque: " << weight_torque;
+ BOOST_LOG_TRIVIAL(debug)
+ << "SSG: bed_movement_arm: " << bed_movement_arm;
+ BOOST_LOG_TRIVIAL(debug)
+ << "SSG: bed_movement_torque: " << bed_movement_torque;
+ BOOST_LOG_TRIVIAL(debug)
+ << "SSG: conflict_torque_arm: " << conflict_torque_arm;
+ BOOST_LOG_TRIVIAL(debug)
+ << "SSG: extruder_conflict_torque: " << extruder_conflict_torque;
+ BOOST_LOG_TRIVIAL(debug)
+ << "SSG: total_torque: " << total_torque << "   printz: " << print_z;
+ #endif
+ }
+
+ std::unordered_map<size_t, float> tmp = acc.connected_islands;
+ acc.connected_islands.clear();
+ // finally, add gathered islands to accumulator, and continue down to next layer
+ for (const auto &pair : tmp) {
+ const Island &below_i = below.islands[pair.first];
+ for (const auto &below_islands : below_i.connected_islands) {
+ acc.connected_islands[below_islands.first] += below_islands.second;
+ }
+ for (const Vec3f &pivot_p : below_i.pivot_points) {
+ acc.pivot_points.push_back(pivot_p);
+ }
+ acc.sticking_centroid_accumulator += below_i.sticking_centroid_accumulator;
+ acc.sticking_force += below_i.sticking_force;
+ acc.volume += below_i.volume;
+ acc.volume_centroid_accumulator += below_i.volume_centroid_accumulator;
+ }
+ }
+
+ // We have arrived to the bed level, now check for stability of the object part on the bed
+ std::vector<Vec2f> pivot_points;
+ for (const Vec3f &p_point : acc.pivot_points) {
+ pivot_points.push_back(p_point.head<2>());
+ }
+ auto coord_fn = [&pivot_points](size_t idx, size_t dim) {
+ return pivot_points[idx][dim];
+ };
+ KDTreeIndirect<2, float, decltype(coord_fn)> pivot_points_tree(coord_fn, pivot_points.size());
+
+ for (const ExtrusionLine &line : island_external_lines) {
+ Vec2f line_dir = (line.b - line.a).normalized();
+ Vec2f pivot_site_search_point = line.b + line_dir * 300.0f;
+ size_t pivot_idx = find_closest_point(pivot_points_tree, pivot_site_search_point);
+ const Vec2f &pivot = pivot_points[pivot_idx];
+
+ const Vec2f &sticking_centroid = acc.sticking_centroid_accumulator.head<2>() / acc.sticking_force;
+ float sticking_arm = (pivot - sticking_centroid).norm();
+ float sticking_torque = sticking_arm * acc.sticking_force;
+
+ float mass = acc.volume * params.filament_density;
+ const Vec3f &mass_centorid = acc.volume_centroid_accumulator / acc.volume;
+ float weight = mass * params.gravity_constant;
+ float weight_arm = (pivot - mass_centorid.head<2>()).norm();
+ float weight_torque = weight_arm * weight;
+
+ float bed_movement_arm = mass_centorid.z();
+ float bed_movement_force = params.max_acceleration * mass;
+ float bed_movement_torque = bed_movement_force * bed_movement_arm;
+
+ Vec3f extruder_pressure_direction = to_3d(line_dir, 0.0f);
+ extruder_pressure_direction.z() = -0.2 - line.malformation * 0.5;
+ extruder_pressure_direction.normalize();
+ float conflict_torque_arm = (to_3d(Vec2f(pivot - line.b), print_z).cross(
+ extruder_pressure_direction)).norm();
+ float extruder_conflict_force = params.tolerable_extruder_conflict_force +
+ std::min(line.malformation, 1.0f) * params.malformations_additive_conflict_extruder_force;
+ float extruder_conflict_torque = extruder_conflict_force * conflict_torque_arm;
+
+ float total_torque = bed_movement_torque + extruder_conflict_torque - weight_torque - sticking_torque;
+
+ if (total_torque > 0) {
+ Vec2f target_point;
+ size_t _idx;
+ island_lines_dist.signed_distance_from_lines(pivot_site_search_point, _idx, target_point);
+ if (!supports_presence_grid.position_taken(to_3d(target_point, print_z))) {
+ float area = params.support_points_interface_radius * params.support_points_interface_radius
+ * float(PI);
+ float sticking_force = area * params.support_adhesion;
+ Vec3f support_point = to_3d(target_point, print_z);
+ island.pivot_points.push_back(support_point);
+ island.sticking_force += sticking_force;
+ island.sticking_centroid_accumulator += sticking_force * support_point;
+ issues.support_points.emplace_back(support_point,
+ extruder_conflict_torque - sticking_torque, extruder_pressure_direction);
+ supports_presence_grid.take_position(to_3d(target_point, print_z));
+ }
+ }
+ #if 0
+ BOOST_LOG_TRIVIAL(debug)
+ << "SSG: sticking_arm: " << sticking_arm;
+ BOOST_LOG_TRIVIAL(debug)
+ << "SSG: sticking_torque: " << sticking_torque;
+ BOOST_LOG_TRIVIAL(debug)
+ << "SSG: weight_arm: " << sticking_arm;
+ BOOST_LOG_TRIVIAL(debug)
+ << "SSG: weight_torque: " << weight_torque;
+ BOOST_LOG_TRIVIAL(debug)
+ << "SSG: bed_movement_arm: " << bed_movement_arm;
+ BOOST_LOG_TRIVIAL(debug)
+ << "SSG: bed_movement_torque: " << bed_movement_torque;
+ BOOST_LOG_TRIVIAL(debug)
+ << "SSG: conflict_torque_arm: " << conflict_torque_arm;
+ BOOST_LOG_TRIVIAL(debug)
+ << "SSG: extruder_conflict_torque: " << extruder_conflict_torque;
+ BOOST_LOG_TRIVIAL(debug)
+ << "SSG: total_torque: " << total_torque << "   printz: " << print_z;
+ #endif
+ }
+ }
+
+ return issues;
+ */
+
+std::tuple<Issues, std::vector<LayerIslands>> check_extrusions_and_build_graph(const PrintObject *po,
+        const Params &params) {
 #ifdef DEBUG_FILES
-    FILE *debug_acc = boost::nowide::fopen(debug_out_path("accumulators.obj").c_str(), "w");
+    FILE *segmentation_f = boost::nowide::fopen(debug_out_path("segmentation.obj").c_str(), "w");
     FILE *malform_f = boost::nowide::fopen(debug_out_path("malformations.obj").c_str(), "w");
 #endif
-    StabilityAccumulators stability_accs;
-    LayerLinesDistancer prev_layer_lines { { } };
+
     Issues issues { };
-    std::vector<ExtrusionLine> checked_lines;
-    VoxelGrid supports_presence_grid { po, params.min_distance_between_support_points };
+    std::vector<LayerIslands> islands_graph;
+    std::vector<ExtrusionLine> layer_lines;
+    float flow_width = get_flow_width(po->layers()[po->layer_count() - 1]->regions()[0], erExternalPerimeter);
+    PixelGrid prev_layer_grid(po, flow_width);
 
     // PREPARE BASE LAYER
-    float max_flow_width = 0.0f;
     const Layer *layer = po->layers()[0];
-    float base_print_z = layer->print_z;
     for (const LayerRegion *layer_region : layer->regions()) {
         for (const ExtrusionEntity *ex_entity : layer_region->perimeters.entities) {
             for (const ExtrusionEntity *perimeter : static_cast<const ExtrusionEntityCollection*>(ex_entity)->entities) {
-                const float flow_width = get_flow_width(layer_region, perimeter->role());
-                max_flow_width = std::max(flow_width, max_flow_width);
-                const float mm3_per_mm = float(perimeter->min_mm3_per_mm());
-                int id = stability_accs.create_accumulator();
-                StabilityAccumulator &acc = stability_accs.access(id);
                 Points points { };
                 perimeter->collect_points(points);
                 for (int point_idx = 0; point_idx < int(points.size() - 1); ++point_idx) {
                     Vec2f start = unscaled(points[point_idx]).cast<float>();
                     Vec2f next = unscaled(points[point_idx + 1]).cast<float>();
-                    ExtrusionLine line { start, next, perimeter->role() == erExternalPerimeter };
-                    line.stability_accumulator_id = id;
-                    float line_sticking_force = line.len * flow_width * params.base_adhesion;
-                    acc.add_base_extrusion(line, line_sticking_force, base_print_z, mm3_per_mm);
-                    checked_lines.push_back(line);
+                    ExtrusionLine line { start, next, perimeter };
+                    layer_lines.push_back(line);
                 }
                 if (perimeter->is_loop()) {
                     Vec2f start = unscaled(points[points.size() - 1]).cast<float>();
                     Vec2f next = unscaled(points[0]).cast<float>();
-                    ExtrusionLine line { start, next, perimeter->role() == erExternalPerimeter };
-                    line.stability_accumulator_id = id;
-                    float line_sticking_force = line.len * flow_width * params.base_adhesion;
-                    acc.add_base_extrusion(line, line_sticking_force, base_print_z, mm3_per_mm);
-                    checked_lines.push_back(line);
+                    ExtrusionLine line { start, next, perimeter };
+                    layer_lines.push_back(line);
                 }
             } // perimeter
         } // ex_entity
         for (const ExtrusionEntity *ex_entity : layer_region->fills.entities) {
             for (const ExtrusionEntity *fill : static_cast<const ExtrusionEntityCollection*>(ex_entity)->entities) {
-                const float flow_width = get_flow_width(layer_region, fill->role());
-                max_flow_width = std::max(flow_width, max_flow_width);
-                const float mm3_per_mm = float(fill->min_mm3_per_mm());
-                int id = stability_accs.create_accumulator();
-                StabilityAccumulator &acc = stability_accs.access(id);
                 Points points { };
                 fill->collect_points(points);
                 for (int point_idx = 0; point_idx < int(points.size() - 1); ++point_idx) {
                     Vec2f start = unscaled(points[point_idx]).cast<float>();
                     Vec2f next = unscaled(points[point_idx + 1]).cast<float>();
-                    ExtrusionLine line { start, next, false };
-                    line.stability_accumulator_id = id;
-                    float line_sticking_force = line.len * flow_width * params.base_adhesion;
-                    acc.add_base_extrusion(line, line_sticking_force, base_print_z, mm3_per_mm);
-                    checked_lines.push_back(line);
+                    ExtrusionLine line { start, next, fill };
+                    layer_lines.push_back(line);
                 }
             } // fill
         } // ex_entity
     } // region
 
-    //MERGE BASE LAYER STABILITY ACCS
-    prev_layer_lines = LayerLinesDistancer { std::move(checked_lines) };
-    for (const ExtrusionLine &l : prev_layer_lines.get_lines()) {
-        size_t nearest_line_idx;
-        Vec2f nearest_pt;
-        Vec2f line_dir = (l.b - l.a).normalized();
-        Vec2f site_search_location = l.a + Vec2f(line_dir.y(), -line_dir.x()) * max_flow_width;
-        float dist = prev_layer_lines.signed_distance_from_lines(site_search_location, nearest_line_idx, nearest_pt);
-        if (std::abs(dist) < max_flow_width) {
-            size_t other_line_acc_id = prev_layer_lines.get_line(nearest_line_idx).stability_accumulator_id;
-            stability_accs.merge_accumulators(other_line_acc_id, l.stability_accumulator_id);
+    auto [layer_islands, layer_grid] = reckon_islands(layer, true, 0, prev_layer_grid,
+            layer_lines, params);
+    islands_graph.push_back(std::move(layer_islands));
+#ifdef DEBUG_FILES
+    for (size_t x = 0; x < size_t(layer_grid.get_pixel_count().x()); ++x) {
+        for (size_t y = 0; y < size_t(layer_grid.get_pixel_count().y()); ++y) {
+            Vec2i coords = Vec2i(x, y);
+            size_t island_idx = layer_grid.get_pixel(coords);
+            if (layer_grid.get_pixel(coords) != NULL_ISLAND) {
+                Vec2f pos = layer_grid.get_pixel_center(coords);
+                size_t pseudornd = ((island_idx + 127) * 33331 + 6907) % 23;
+                Vec3f color = value_to_rgbf(0.0f, float(23), float(pseudornd));
+                fprintf(segmentation_f, "v %f %f %f  %f %f %f\n", pos[0],
+                        pos[1], layer->print_z, color[0], color[1], color[2]);
+            }
         }
     }
-
-#ifdef DEBUG_FILES
-    for (const auto &line : prev_layer_lines.get_lines()) {
-        Vec3f color = stability_accs.get_accumulator_color(line.stability_accumulator_id);
-        fprintf(debug_acc, "v %f %f %f  %f %f %f\n", line.b[0],
-                line.b[1], base_print_z, color[0], color[1], color[2]);
+    for (const auto &line : layer_lines) {
+        if (line.malformation > 0.0f) {
+            Vec3f color = value_to_rgbf(0, 1.0f, line.malformation);
+            fprintf(malform_f, "v %f %f %f  %f %f %f\n", line.b[0],
+                    line.b[1], layer->print_z, color[0], color[1], color[2]);
+        }
     }
-
-    stability_accs.log_accumulators();
 #endif
+    LinesDistancer external_lines(layer_lines);
+    layer_lines.clear();
+    prev_layer_grid = layer_grid;
 
-    //CHECK STABILITY OF ALL LAYERS
     for (size_t layer_idx = 1; layer_idx < po->layer_count(); ++layer_idx) {
         const Layer *layer = po->layers()[layer_idx];
-        checked_lines = std::vector<ExtrusionLine> { };
-        std::vector<std::pair<Vec2f, size_t>> fill_points;
-        float max_fill_flow_width = 0.0f;
-
-        float print_z = layer->print_z;
         for (const LayerRegion *layer_region : layer->regions()) {
             for (const ExtrusionEntity *ex_entity : layer_region->perimeters.entities) {
                 for (const ExtrusionEntity *perimeter : static_cast<const ExtrusionEntityCollection*>(ex_entity)->entities) {
-                    check_extrusion_entity_stability(perimeter, stability_accs, issues, checked_lines, print_z,
-                            layer_region,
-                            prev_layer_lines, params);
+                    check_extrusion_entity_stability(perimeter, layer_lines, layer->print_z, layer_region,
+                            external_lines, issues, params);
                 } // perimeter
             } // ex_entity
             for (const ExtrusionEntity *ex_entity : layer_region->fills.entities) {
                 for (const ExtrusionEntity *fill : static_cast<const ExtrusionEntityCollection*>(ex_entity)->entities) {
                     if (fill->role() == ExtrusionRole::erGapFill
                             || fill->role() == ExtrusionRole::erBridgeInfill) {
-                        check_extrusion_entity_stability(fill, stability_accs, issues, checked_lines, print_z,
-                                layer_region,
-                                prev_layer_lines, params);
+                        check_extrusion_entity_stability(fill, layer_lines, layer->print_z, layer_region,
+                                external_lines, issues, params);
                     } else {
-                        const float flow_width = get_flow_width(layer_region, fill->role());
-                        max_fill_flow_width = std::max(max_fill_flow_width, flow_width);
-                        Vec2f start = unscaled(fill->first_point()).cast<float>();
-                        size_t nearest_line_idx;
-                        Vec2f nearest_pt;
-                        float dist = prev_layer_lines.signed_distance_from_lines(start, nearest_line_idx, nearest_pt);
-                        if (dist < flow_width) {
-                            size_t acc_id = prev_layer_lines.get_line(nearest_line_idx).stability_accumulator_id;
-                            StabilityAccumulator &acc = stability_accs.access(acc_id);
-                            Points points { };
-                            const float mm3_per_mm = float(fill->min_mm3_per_mm());
-                            fill->collect_points(points);
-                            for (int point_idx = 0; point_idx < int(points.size() - 1); ++point_idx) {
-                                Vec2f start = unscaled(points[point_idx]).cast<float>();
-                                Vec2f next = unscaled(points[point_idx + 1]).cast<float>();
-                                ExtrusionLine line { start, next, false };
-                                line.stability_accumulator_id = acc_id;
-                                acc.add_extrusion(line, print_z, mm3_per_mm);
-                            }
-                            fill_points.emplace_back(start, acc_id);
-                        } else {
-                            BOOST_LOG_TRIVIAL(debug)
-                            << "SSG: ERROR: seem that infill starts in the air? on printz: " << print_z;
+                        Points points { };
+                        fill->collect_points(points);
+                        for (int point_idx = 0; point_idx < int(points.size() - 1); ++point_idx) {
+                            Vec2f start = unscaled(points[point_idx]).cast<float>();
+                            Vec2f next = unscaled(points[point_idx + 1]).cast<float>();
+                            ExtrusionLine line { start, next, fill };
+                            layer_lines.push_back(line);
                         }
                     }
                 } // fill
             } // ex_entity
         } // region
 
-        prev_layer_lines = LayerLinesDistancer { std::move(checked_lines) };
-
-        for (const std::pair<Vec2f, size_t> &fill_point : fill_points) {
-            size_t nearest_line_idx;
-            Vec2f nearest_pt;
-            float dist = prev_layer_lines.signed_distance_from_lines(fill_point.first, nearest_line_idx, nearest_pt);
-            if (dist < max_fill_flow_width) {
-                size_t other_line_acc_id = prev_layer_lines.get_line(nearest_line_idx).stability_accumulator_id;
-                stability_accs.merge_accumulators(other_line_acc_id, fill_point.second);
-            } else {
-                BOOST_LOG_TRIVIAL(debug)
-                << "SSG: ERROR: seem that infill starts in the air? on printz: " << print_z;
-            }
-        }
-
-        float flow_width = get_flow_width(layer->regions()[0], erExternalPerimeter);
-
-        check_layer_global_stability(stability_accs,
-                supports_presence_grid,
-                issues,
-                flow_width,
-                prev_layer_lines.get_lines(),
-                print_z,
-                params);
-
-        reckon_thin_islands(stability_accs, flow_width, flow_width*layer->height, print_z, prev_layer_lines, params);
+        auto [layer_islands, layer_grid] = reckon_islands(layer, true, 0, prev_layer_grid,
+                layer_lines, params);
+        islands_graph.push_back(std::move(layer_islands));
 
 #ifdef DEBUG_FILES
-        for (const auto &line : prev_layer_lines.get_lines()) {
-            Vec3f color = value_to_rgbf(0, 1.0f, line.malformation);
-            fprintf(malform_f, "v %f %f %f  %f %f %f\n", line.b[0],
-                    line.b[1], print_z, color[0], color[1], color[2]);
+        for (size_t x = 0; x < size_t(layer_grid.get_pixel_count().x()); ++x) {
+            for (size_t y = 0; y < size_t(layer_grid.get_pixel_count().y()); ++y) {
+                Vec2i coords = Vec2i(x, y);
+                size_t island_idx = layer_grid.get_pixel(coords);
+                if (layer_grid.get_pixel(coords) != NULL_ISLAND) {
+                    Vec2f pos = layer_grid.get_pixel_center(coords);
+                    size_t pseudornd = ((island_idx + 127) * 33331 + 6907) % 23;
+                    Vec3f color = value_to_rgbf(0.0f, float(23), float(pseudornd));
+                    fprintf(segmentation_f, "v %f %f %f  %f %f %f\n", pos[0],
+                            pos[1], layer->print_z, color[0], color[1], color[2]);
+                }
+            }
         }
-        for (const auto &line : prev_layer_lines.get_lines()) {
-            Vec3f color = stability_accs.get_accumulator_color(line.stability_accumulator_id);
-            fprintf(debug_acc, "v %f %f %f  %f %f %f\n", line.b[0],
-                    line.b[1], print_z, color[0], color[1], color[2]);
+        for (const auto &line : layer_lines) {
+            if (line.malformation > 0.0f) {
+                Vec3f color = value_to_rgbf(0, 1.0f, line.malformation);
+                fprintf(malform_f, "v %f %f %f  %f %f %f\n", line.b[0],
+                        line.b[1], layer->print_z, color[0], color[1], color[2]);
+            }
         }
-        stability_accs.log_accumulators();
 #endif
+        external_lines = LinesDistancer(layer_lines);
+        layer_lines.clear();
+        prev_layer_grid = layer_grid;
     }
 
 #ifdef DEBUG_FILES
-    fclose(debug_acc);
+    fclose(segmentation_f);
     fclose(malform_f);
 #endif
 
-    std::cout << " SUPP: " << issues.supports_nedded.size() << std::endl;
-    return issues;
+    return {issues, islands_graph};
 }
 
 #ifdef DEBUG_FILES
@@ -907,46 +1066,35 @@ void debug_export(Issues issues, std::string file_name) {
             return;
         }
 
-        for (size_t i = 0; i < issues.supports_nedded.size(); ++i) {
-            fprintf(fp, "v %f %f %f  %f %f %f\n", issues.supports_nedded[i].position(0),
-                    issues.supports_nedded[i].position(1),
-                    issues.supports_nedded[i].position(2), 1.0, 0.0, 1.0);
+        for (size_t i = 0; i < issues.support_points.size(); ++i) {
+            fprintf(fp, "v %f %f %f  %f %f %f\n", issues.support_points[i].position(0),
+                    issues.support_points[i].position(1),
+                    issues.support_points[i].position(2), 1.0, 0.0, 1.0);
         }
 
         fclose(fp);
     }
-    {
-        FILE *fp = boost::nowide::fopen(debug_out_path((file_name + "_curling.obj").c_str()).c_str(), "w");
-        if (fp == nullptr) {
-            BOOST_LOG_TRIVIAL(error)
-            << "Debug files: Couldn't open " << file_name << " for writing";
-            return;
-        }
-
-        for (size_t i = 0; i < issues.curling_up.size(); ++i) {
-            fprintf(fp, "v %f %f %f  %f %f %f\n", issues.curling_up[i].position(0),
-                    issues.curling_up[i].position(1),
-                    issues.curling_up[i].position(2), 0.0, 1.0, 0.0);
-        }
-        fclose(fp);
-    }
 }
 #endif
 
 std::vector<size_t> quick_search(const PrintObject *po, const Params &params) {
-    check_object_stability(po, params);
     return {};
 }
 
-Issues
-full_search(const PrintObject *po, const Params &params) {
-    auto issues = check_object_stability(po, params);
+Issues full_search(const PrintObject *po, const Params &params) {
+    auto [local_issues, graph] = check_extrusions_and_build_graph(po, params);
+    Issues global_issues = check_global_stability(graph, params);
 #ifdef DEBUG_FILES
-    debug_export(issues, "issues");
+    debug_export(local_issues, "local_issues");
+    debug_export(global_issues, "global_issues");
 #endif
-    return issues;
 
+    global_issues.support_points.insert(global_issues.support_points.end(),
+            local_issues.support_points.begin(), local_issues.support_points.end());
+
+    return global_issues;
 }
+
 } //SupportableIssues End
 }
 
diff --git a/src/libslic3r/SupportSpotsGeneratorRefactoring.cpp b/src/libslic3r/SupportSpotsGeneratorRefactoring.cpp
deleted file mode 100644
index a2275c637..000000000
--- a/src/libslic3r/SupportSpotsGeneratorRefactoring.cpp
+++ /dev/null
@@ -1,972 +0,0 @@
-#include "SupportSpotsGenerator.hpp"
-
-#include "tbb/parallel_for.h"
-#include "tbb/blocked_range.h"
-#include "tbb/blocked_range2d.h"
-#include "tbb/parallel_reduce.h"
-#include <boost/log/trivial.hpp>
-#include <cmath>
-#include <unordered_set>
-#include <stack>
-
-#include "AABBTreeLines.hpp"
-#include "KDTreeIndirect.hpp"
-#include "libslic3r/Layer.hpp"
-#include "libslic3r/ClipperUtils.hpp"
-#include "Geometry/ConvexHull.hpp"
-
-#define DEBUG_FILES
-
-#ifdef DEBUG_FILES
-#include <boost/nowide/cstdio.hpp>
-#include "libslic3r/Color.hpp"
-#endif
-
-namespace Slic3r {
-
-class ExtrusionLine
-{
-public:
-    ExtrusionLine() :
-            a(Vec2f::Zero()), b(Vec2f::Zero()), len(0.0f), origin_entity(nullptr) {
-    }
-    ExtrusionLine(const Vec2f &_a, const Vec2f &_b, const ExtrusionEntity *origin_entity) :
-            a(_a), b(_b), len((_a - _b).norm()), origin_entity(origin_entity) {
-    }
-
-    float length() {
-        return (a - b).norm();
-    }
-
-    bool is_external_perimeter() const {
-        assert(origin_entity != nullptr);
-        return origin_entity->role() == erExternalPerimeter;
-    }
-
-    Vec2f a;
-    Vec2f b;
-    float len;
-    const ExtrusionEntity *origin_entity;
-
-    bool support_point_generated = false;
-    float malformation = 0.0f;
-
-    static const constexpr int Dim = 2;
-    using Scalar = Vec2f::Scalar;
-};
-
-auto get_a(ExtrusionLine &&l) {
-    return l.a;
-}
-auto get_b(ExtrusionLine &&l) {
-    return l.b;
-}
-
-namespace SupportSpotsGenerator {
-
-SupportPoint::SupportPoint(const Vec3f &position, float force, const Vec3f &direction) :
-        position(position), force(force), direction(direction) {
-}
-
-class LinesDistancer {
-private:
-    std::vector<ExtrusionLine> lines;
-    AABBTreeIndirect::Tree<2, float> tree;
-
-public:
-    explicit LinesDistancer(std::vector<ExtrusionLine> &lines) :
-            lines(lines) {
-        tree = AABBTreeLines::build_aabb_tree_over_indexed_lines(this->lines);
-    }
-
-    // negative sign means inside
-    float signed_distance_from_lines(const Vec2f &point, size_t &nearest_line_index_out,
-            Vec2f &nearest_point_out) const {
-        auto distance = AABBTreeLines::squared_distance_to_indexed_lines(lines, tree, point, nearest_line_index_out,
-                nearest_point_out);
-        if (distance < 0)
-            return std::numeric_limits<float>::infinity();
-
-        distance = sqrt(distance);
-        const ExtrusionLine &line = lines[nearest_line_index_out];
-        Vec2f v1 = line.b - line.a;
-        Vec2f v2 = point - line.a;
-        if ((v1.x() * v2.y()) - (v1.y() * v2.x()) > 0.0) {
-            distance *= -1;
-        }
-        return distance;
-    }
-
-    const ExtrusionLine& get_line(size_t line_idx) const {
-        return lines[line_idx];
-    }
-
-    const std::vector<ExtrusionLine>& get_lines() const {
-        return lines;
-    }
-};
-
-static const size_t NULL_ISLAND = std::numeric_limits<size_t>::max();
-
-class PixelGrid {
-    Vec2f pixel_size;
-    Vec2f origin;
-    Vec2f size;
-    Vec2i pixel_count;
-
-    std::vector<size_t> pixels { };
-
-public:
-    PixelGrid(const PrintObject *po, float resolution) {
-        pixel_size = Vec2f(resolution, resolution);
-
-        Vec2crd size_half = po->size().head<2>().cwiseQuotient(Vec2crd(2, 2)) + Vec2crd::Ones();
-        Vec2f min = unscale(Vec2crd(-size_half.x(), -size_half.y())).cast<float>();
-        Vec2f max = unscale(Vec2crd(size_half.x(), size_half.y())).cast<float>();
-
-        origin = min;
-        size = max - min;
-        pixel_count = size.cwiseQuotient(pixel_size).cast<int>() + Vec2i::Ones();
-
-        pixels.resize(pixel_count.y() * pixel_count.x());
-        clear();
-    }
-
-    void distribute_edge(const Vec2f &p1, const Vec2f &p2, size_t value) {
-        Vec2f dir = (p2 - p1);
-        float length = dir.norm();
-        if (length < 0.1) {
-            return;
-        }
-        float step_size = this->pixel_size.x() / 2.0;
-
-        float distributed_length = 0;
-        while (distributed_length < length) {
-            float next_len = std::min(length, distributed_length + step_size);
-            Vec2f location = p1 + ((next_len / length) * dir);
-            this->access_pixel(location) = value;
-
-            distributed_length = next_len;
-        }
-    }
-
-    void clear() {
-        for (size_t &val : pixels) {
-            val = NULL_ISLAND;
-        }
-    }
-
-    float pixel_area() const {
-        return this->pixel_size.x() * this->pixel_size.y();
-    }
-
-    size_t get_pixel(const Vec2i &coords) const {
-        return pixels[this->to_pixel_index(coords)];
-    }
-
-    Vec2i get_pixel_count() {
-        return pixel_count;
-    }
-
-    Vec2f get_pixel_center(const Vec2i &coords) const {
-        return origin + coords.cast<float>().cwiseProduct(this->pixel_size)
-                + this->pixel_size.cwiseQuotient(Vec2f(2.0f, 2.0f));
-    }
-
-private:
-    Vec2i to_pixel_coords(const Vec2f &position) const {
-        Vec2i pixel_coords = (position - this->origin).cwiseQuotient(this->pixel_size).cast<int>();
-        return pixel_coords;
-    }
-
-    size_t to_pixel_index(const Vec2i &pixel_coords) const {
-        assert(pixel_coords.x() >= 0);
-        assert(pixel_coords.x() < pixel_count.x());
-        assert(pixel_coords.y() >= 0);
-        assert(pixel_coords.y() < pixel_count.y());
-
-        return pixel_coords.y() * pixel_count.x() + pixel_coords.x();
-    }
-
-    size_t& access_pixel(const Vec2f &position) {
-        return pixels[this->to_pixel_index(this->to_pixel_coords(position))];
-    }
-};
-
-struct SupportGridFilter {
-private:
-    Vec3f cell_size;
-    Vec3f origin;
-    Vec3f size;
-    Vec3i cell_count;
-
-    std::unordered_set<size_t> taken_cells { };
-
-public:
-    SupportGridFilter(const PrintObject *po, float voxel_size) {
-        cell_size = Vec3f(voxel_size, voxel_size, voxel_size);
-
-        Vec2crd size_half = po->size().head<2>().cwiseQuotient(Vec2crd(2, 2)) + Vec2crd::Ones();
-        Vec3f min = unscale(Vec3crd(-size_half.x(), -size_half.y(), 0)).cast<float>() - cell_size;
-        Vec3f max = unscale(Vec3crd(size_half.x(), size_half.y(), po->height())).cast<float>() + cell_size;
-
-        origin = min;
-        size = max - min;
-        cell_count = size.cwiseQuotient(cell_size).cast<int>() + Vec3i::Ones();
-    }
-
-    Vec3i to_cell_coords(const Vec3f &position) const {
-        Vec3i cell_coords = (position - this->origin).cwiseQuotient(this->cell_size).cast<int>();
-        return cell_coords;
-    }
-
-    size_t to_cell_index(const Vec3i &cell_coords) const {
-        assert(cell_coords.x() >= 0);
-        assert(cell_coords.x() < cell_count.x());
-        assert(cell_coords.y() >= 0);
-        assert(cell_coords.y() < cell_count.y());
-        assert(cell_coords.z() >= 0);
-        assert(cell_coords.z() < cell_count.z());
-
-        return cell_coords.z() * cell_count.x() * cell_count.y()
-                + cell_coords.y() * cell_count.x()
-                + cell_coords.x();
-    }
-
-    Vec3f get_cell_center(const Vec3i &cell_coords) const {
-        return origin + cell_coords.cast<float>().cwiseProduct(this->cell_size)
-                + this->cell_size.cwiseQuotient(Vec3f(2.0f, 2.0f, 2.0));
-    }
-
-    void take_position(const Vec3f &position) {
-        taken_cells.insert(to_cell_index(to_cell_coords(position)));
-    }
-
-    bool position_taken(const Vec3f &position) const {
-        return taken_cells.find(to_cell_index(to_cell_coords(position))) != taken_cells.end();
-    }
-
-};
-
-struct Island {
-    std::unordered_map<size_t, float> islands_under_with_connection_area;
-    std::vector<Vec3f> pivot_points;
-    float volume;
-    Vec3f volume_centroid_accumulator;
-    float sticking_force; // for support points present on this layer (or bed extrusions)
-    Vec3f sticking_centroid_accumulator;
-};
-
-struct LayerIslands {
-    std::vector<Island> islands;
-};
-
-float get_flow_width(const LayerRegion *region, ExtrusionRole role) {
-    switch (role) {
-        case ExtrusionRole::erBridgeInfill:
-            return region->flow(FlowRole::frExternalPerimeter).width();
-        case ExtrusionRole::erExternalPerimeter:
-            return region->flow(FlowRole::frExternalPerimeter).width();
-        case ExtrusionRole::erGapFill:
-            return region->flow(FlowRole::frInfill).width();
-        case ExtrusionRole::erPerimeter:
-            return region->flow(FlowRole::frPerimeter).width();
-        case ExtrusionRole::erSolidInfill:
-            return region->flow(FlowRole::frSolidInfill).width();
-        case ExtrusionRole::erInternalInfill:
-            return region->flow(FlowRole::frInfill).width();
-        case ExtrusionRole::erTopSolidInfill:
-            return region->flow(FlowRole::frTopSolidInfill).width();
-        default:
-            return region->flow(FlowRole::frPerimeter).width();
-    }
-}
-
-// Accumulator of current extruion path properties
-// It remembers unsuported distance and maximum accumulated curvature over that distance.
-// Used to determine local stability issues (too long bridges, extrusion curves into air)
-struct ExtrusionPropertiesAccumulator {
-    float distance = 0; //accumulated distance
-    float curvature = 0; //accumulated signed ccw angles
-    float max_curvature = 0; //max absolute accumulated value
-
-    void add_distance(float dist) {
-        distance += dist;
-    }
-
-    void add_angle(float ccw_angle) {
-        curvature += ccw_angle;
-        max_curvature = std::max(max_curvature, std::abs(curvature));
-    }
-
-    void reset() {
-        distance = 0;
-        curvature = 0;
-        max_curvature = 0;
-    }
-};
-
-void check_extrusion_entity_stability(const ExtrusionEntity *entity,
-        std::vector<ExtrusionLine> &checked_lines_out,
-        float print_z,
-        const LayerRegion *layer_region,
-        const LinesDistancer &prev_layer_lines,
-        Issues &issues,
-        const Params &params) {
-
-    if (entity->is_collection()) {
-        for (const auto *e : static_cast<const ExtrusionEntityCollection*>(entity)->entities) {
-            check_extrusion_entity_stability(e, checked_lines_out, print_z, layer_region, prev_layer_lines,
-                    issues, params);
-        }
-    } else { //single extrusion path, with possible varying parameters
-        const auto to_vec3f = [print_z](const Vec2f &point) {
-            return Vec3f(point.x(), point.y(), print_z);
-        };
-        Points points { };
-        entity->collect_points(points);
-        std::vector<ExtrusionLine> lines;
-        lines.reserve(points.size() * 1.5);
-        lines.emplace_back(unscaled(points[0]).cast<float>(), unscaled(points[0]).cast<float>(), entity);
-        for (int point_idx = 0; point_idx < int(points.size() - 1); ++point_idx) {
-            Vec2f start = unscaled(points[point_idx]).cast<float>();
-            Vec2f next = unscaled(points[point_idx + 1]).cast<float>();
-            Vec2f v = next - start; // vector from next to current
-            float dist_to_next = v.norm();
-            v.normalize();
-            int lines_count = int(std::ceil(dist_to_next / params.bridge_distance));
-            float step_size = dist_to_next / lines_count;
-            for (int i = 0; i < lines_count; ++i) {
-                Vec2f a(start + v * (i * step_size));
-                Vec2f b(start + v * ((i + 1) * step_size));
-                lines.emplace_back(a, b, entity);
-            }
-        }
-
-        ExtrusionPropertiesAccumulator bridging_acc { };
-        ExtrusionPropertiesAccumulator malformation_acc { };
-        bridging_acc.add_distance(params.bridge_distance + 1.0f); // Initialise unsupported distance with larger than tolerable distance ->
-        // -> it prevents extruding perimeter starts and short loops into air.
-        const float flow_width = get_flow_width(layer_region, entity->role());
-
-        for (size_t line_idx = 0; line_idx < lines.size(); ++line_idx) {
-            ExtrusionLine &current_line = lines[line_idx];
-            float curr_angle = 0;
-            if (line_idx + 1 < lines.size()) {
-                const Vec2f v1 = current_line.b - current_line.a;
-                const Vec2f v2 = lines[line_idx + 1].b - lines[line_idx + 1].a;
-                curr_angle = angle(v1, v2);
-            }
-            bridging_acc.add_angle(curr_angle);
-            malformation_acc.add_angle(std::max(0.0f, curr_angle));
-
-            size_t nearest_line_idx;
-            Vec2f nearest_point;
-            float dist_from_prev_layer = prev_layer_lines.signed_distance_from_lines(current_line.b, nearest_line_idx,
-                    nearest_point);
-
-            if (fabs(dist_from_prev_layer) < flow_width) {
-                bridging_acc.reset();
-            } else {
-                bridging_acc.add_distance(current_line.len);
-                if (bridging_acc.distance // if unsupported distance is larger than bridge distance linearly decreased by curvature, enforce supports.
-                > params.bridge_distance
-                        / (1.0f + (bridging_acc.max_curvature
-                                * params.bridge_distance_decrease_by_curvature_factor / PI))) {
-                    issues.support_points.emplace_back(to_vec3f(current_line.b), 0.0f, Vec3f(0.f, 0.0f, -1.0f));
-                    current_line.support_point_generated = true;
-                    bridging_acc.reset();
-                }
-            }
-
-            //malformation
-            if (fabs(dist_from_prev_layer) < flow_width * 2.0f) {
-                const ExtrusionLine &nearest_line = prev_layer_lines.get_line(nearest_line_idx);
-                current_line.malformation += 0.9 * nearest_line.malformation;
-            }
-            if (dist_from_prev_layer > flow_width * 0.3) {
-                malformation_acc.add_distance(current_line.len);
-                current_line.malformation += 0.15
-                        * (0.8 + 0.2 * malformation_acc.max_curvature / (1.0f + 0.5f * malformation_acc.distance));
-            } else {
-                malformation_acc.reset();
-            }
-        }
-        checked_lines_out.insert(checked_lines_out.end(), lines.begin(), lines.end());
-    }
-}
-
-std::tuple<LayerIslands, PixelGrid, std::vector<size_t>> reckon_islands(
-        const Layer *layer, bool first_layer,
-        size_t prev_layer_islands_count,
-        const PixelGrid &prev_layer_grid,
-        const std::vector<ExtrusionLine> &layer_lines,
-        const Params &params) {
-
-    //extract extrusions (connected paths from multiple lines) from the layer_lines. belonging to single polyline is determined by origin_entity ptr.
-    // result is a vector of [start, end) index pairs into the layer_lines vector
-    std::vector<std::pair<size_t, size_t>> extrusions; //start and end idx (one beyond last extrusion) [start,end)
-    const ExtrusionEntity *current_ex = nullptr;
-    for (size_t lidx = 0; lidx < layer_lines.size(); ++lidx) {
-        const ExtrusionLine &line = layer_lines[lidx];
-        if (line.origin_entity == current_ex) {
-            extrusions.back().second = lidx + 1;
-        } else {
-            extrusions.emplace_back(lidx, lidx + 1);
-            current_ex = line.origin_entity;
-        }
-    }
-
-    std::vector<LinesDistancer> islands; // these search trees will be used to determine to which island does the extrusion begin
-    std::vector<std::vector<size_t>> island_extrusions; //final assigment of each extrusion to an island
-    // initliaze the search from external perimeters - at the beginning, there is island candidate for each external perimeter.
-    // some of them will disappear (e.g. holes)
-    for (size_t e = 0; e < extrusions.size(); ++e) {
-        if (layer_lines[extrusions[e].first].is_external_perimeter()) {
-            std::vector<ExtrusionLine> copy(extrusions[e].second - extrusions[e].first);
-            for (size_t ex_line_idx = extrusions[e].first; ex_line_idx < extrusions[e].second; ++ex_line_idx) {
-                copy[ex_line_idx - extrusions[e].first] = layer_lines[ex_line_idx];
-            }
-            islands.emplace_back(copy);
-            island_extrusions.push_back( { e });
-        }
-    }
-    // backup code if islands not found - this can currently happen, as external perimeters may be also pure overhang perimeters, and there is no
-    // way to distinguish external extrusions with total certainty.
-    // If that happens, just make the first extrusion into island - it may be wrong, but it won't crash.
-    if (islands.empty() && !extrusions.empty()) {
-        std::vector<ExtrusionLine> copy(extrusions[0].second - extrusions[0].first);
-        for (size_t ex_line_idx = extrusions[0].first; ex_line_idx < extrusions[0].second; ++ex_line_idx) {
-            copy[ex_line_idx - extrusions[0].first] = layer_lines[ex_line_idx];
-        }
-        islands.emplace_back(copy);
-        island_extrusions.push_back( { 0 });
-    }
-
-    // assign non external extrusions to islands
-    for (size_t e = 0; e < extrusions.size(); ++e) {
-        if (!layer_lines[extrusions[e].first].is_external_perimeter()) {
-            bool island_assigned = false;
-            for (size_t i = 0; i < islands.size(); ++i) {
-                size_t _idx;
-                Vec2f _pt;
-                if (islands[i].signed_distance_from_lines(layer_lines[extrusions[e].first].a, _idx, _pt) < 0) {
-                    island_extrusions[i].push_back(e);
-                    island_assigned = true;
-                    break;
-                }
-            }
-            if (!island_assigned) { // If extrusion is not assigned for some reason, push it into the first island. As with the previous backup code,
-                    // it may be wrong, but it won't crash
-                island_extrusions[0].push_back(e);
-            }
-        }
-    }
-    // merge islands which are embedded within each other (mainly holes)
-    for (size_t i = 0; i < islands.size(); ++i) {
-        if (islands[i].get_lines().empty()) {
-            continue;
-        }
-        for (size_t j = 0; j < islands.size(); ++j) {
-            if (islands[j].get_lines().empty() || i == j) {
-                continue;
-            }
-            size_t _idx;
-            Vec2f _pt;
-            if (islands[i].signed_distance_from_lines(islands[j].get_line(0).a, _idx, _pt) < 0) {
-                island_extrusions[i].insert(island_extrusions[i].end(), island_extrusions[j].begin(),
-                        island_extrusions[j].end());
-                island_extrusions[j].clear();
-            }
-        }
-    }
-
-    float flow_width = get_flow_width(layer->regions()[0], erExternalPerimeter);
-    // after filtering the layer lines into islands, build the result LayerIslands structure.
-    LayerIslands result { };
-    std::vector<size_t> line_to_island_mapping(layer_lines.size(), NULL_ISLAND);
-    for (const std::vector<size_t> &island_ex : island_extrusions) {
-        if (island_ex.empty()) {
-            continue;
-        }
-
-        Island island { };
-        for (size_t extrusion_idx : island_ex) {
-            for (size_t lidx = extrusions[extrusion_idx].first; lidx < extrusions[extrusion_idx].second; ++lidx) {
-                line_to_island_mapping[lidx] = result.islands.size();
-                const ExtrusionLine &line = layer_lines[lidx];
-                float volume = line.origin_entity->min_mm3_per_mm() * line.len;
-                island.volume += volume;
-                island.volume_centroid_accumulator += to_3d(Vec2f((line.a + line.b) / 2.0f), float(layer->print_z))
-                        * volume;
-
-                if (first_layer) {
-                    float sticking_force = line.len * flow_width * params.base_adhesion;
-                    island.sticking_force += sticking_force;
-                    island.sticking_centroid_accumulator += sticking_force
-                            * to_3d(Vec2f((line.a + line.b) / 2.0f), float(layer->print_z));
-                    if (line.is_external_perimeter()) {
-                        island.pivot_points.push_back(to_3d(Vec2f(line.b), float(layer->print_z)));
-                    }
-                } else if (layer_lines[lidx].support_point_generated) {
-                    float support_interface_area = params.support_points_interface_radius
-                            * params.support_points_interface_radius
-                            * float(PI);
-                    float sticking_force = support_interface_area * params.support_adhesion;
-                    island.sticking_force += sticking_force;
-                    island.sticking_centroid_accumulator += sticking_force
-                            * to_3d(Vec2f(line.b), float(layer->print_z));
-                    island.pivot_points.push_back(to_3d(Vec2f(line.b), float(layer->print_z)));
-                }
-            }
-        }
-        result.islands.push_back(island);
-    }
-
-    //LayerIslands structure built. Now determine connections and their areas to the previous layer using raterization.
-    PixelGrid current_layer_grid = prev_layer_grid;
-    current_layer_grid.clear();
-    // build index image of current layer
-    tbb::parallel_for(tbb::blocked_range<size_t>(0, layer_lines.size()),
-            [&layer_lines, &current_layer_grid, &line_to_island_mapping](
-                    tbb::blocked_range<size_t> r) {
-                for (size_t i = r.begin(); i < r.end(); ++i) {
-                    size_t island = line_to_island_mapping[i];
-                    const ExtrusionLine &line = layer_lines[i];
-                    current_layer_grid.distribute_edge(line.a, line.b, island);
-                }
-            });
-
-    //compare the image of previous layer with the current layer. For each pair of overlapping valid pixels, add pixel area to the respecitve island connection
-    for (size_t x = 0; x < size_t(current_layer_grid.get_pixel_count().x()); ++x) {
-        for (size_t y = 0; y < size_t(current_layer_grid.get_pixel_count().y()); ++y) {
-            Vec2i coords = Vec2i(x, y);
-            if (current_layer_grid.get_pixel(coords) != NULL_ISLAND
-                    && prev_layer_grid.get_pixel(coords) != NULL_ISLAND) {
-                result.islands[current_layer_grid.get_pixel(coords)].islands_under_with_connection_area[prev_layer_grid.get_pixel(
-                        coords)] +=
-                        current_layer_grid.pixel_area();
-            }
-        }
-    }
-    return {result, current_layer_grid, line_to_island_mapping};
-}
-
-void check_global_stability(
-        float print_z,
-        std::vector<LayerIslands> &islands_graph,
-        SupportGridFilter &supports_presence_grid,
-        const std::vector<ExtrusionLine> &layer_lines,
-        const std::vector<size_t> &line_to_island_mapping,
-        Issues &issues,
-        const Params &params
-        ) {
-    // vector of islands, where each contains vector of line indices (to layer_lines vector)
-    // basically reverse of line_to_island_mapping
-    std::vector<std::vector<size_t>> islands_lines(islands_graph.back().islands.size());
-    for (size_t lidx = 0; lidx < layer_lines.size(); ++lidx) {
-        if (layer_lines[lidx].origin_entity->role() == erExternalPerimeter) {
-            islands_lines[line_to_island_mapping[lidx]].push_back(lidx);
-        }
-    }
-
-    using Accumulator = Island;
-
-    // islands_graph.back() refers to the top most (current) layer
-    for (size_t island_idx = 0; island_idx < islands_graph.back().islands.size(); ++island_idx) {
-        Island &island = islands_graph.back().islands[island_idx];
-
-        std::vector<ExtrusionLine> island_external_lines;
-        for (size_t lidx : islands_lines[island_idx]) {
-            island_external_lines.push_back(layer_lines[lidx]);
-        }
-        LinesDistancer island_lines_dist(island_external_lines);
-        Accumulator acc = island; // in acc, we accumulate the mass and other properties of the object part as we traverse the islands down to bed
-        // There is one object part for each island at the top most layer, and each one is computed individually -
-        // Some of the calculations will be done multiple times
-        int layer_idx = islands_graph.size() - 1;
-        // traverse the islands graph down, and for each connection area, calculate if it holds or breaks
-        while (acc.islands_under_with_connection_area.size() > 0) {
-            //test for break between layer_idx and layer_idx -1;
-            LayerIslands below = islands_graph[layer_idx - 1]; // must exist, see while condition
-            layer_idx--;
-            // initialize variables that we will accumulate over all islands, which are connected to the current object part
-            std::vector<Vec2f> pivot_points;
-            Vec2f sticking_centroid;
-            float connection_area = 0;
-            for (const auto &pair : acc.islands_under_with_connection_area) {
-                const Island &below_i = below.islands[pair.first];
-                Vec2f centroid = (below_i.volume_centroid_accumulator / below_i.volume).head<2>(); // centroid of the island 'below_i'; TODO it should be centroid of the connection area
-                pivot_points.push_back(centroid); // for object parts, we also consider breaking pivots in the centroids of the islands
-                sticking_centroid += centroid * pair.second; // pair.second is connection area in mm^2
-                connection_area += pair.second;
-            }
-            sticking_centroid /= connection_area; //normalize to get final sticking centroid
-            for (const Vec3f &p_point : acc.pivot_points) {
-                pivot_points.push_back(p_point.head<2>());
-            }
-            // Now we have accumulated pivot points, connection area and sticking centroid of the whole layer to the current object part
-
-            // create KD tree over current pivot points
-            auto coord_fn = [&pivot_points](size_t idx, size_t dim) {
-                return pivot_points[idx][dim];
-            };
-            KDTreeIndirect<2, float, decltype(coord_fn)> pivot_points_tree(coord_fn, pivot_points.size());
-
-            // iterate over extrusions at top layer island, check each for stability
-            for (const ExtrusionLine &line : island_external_lines) {
-                Vec2f line_dir = (line.b - line.a).normalized();
-                Vec2f pivot_site_search_point = line.b + line_dir * 300.0f;
-                size_t pivot_idx = find_closest_point(pivot_points_tree, pivot_site_search_point);
-                const Vec2f &pivot = pivot_points[pivot_idx];
-
-                float sticking_arm = (pivot - sticking_centroid).norm();
-                float sticking_torque = sticking_arm * connection_area * params.tensile_strength; // For breakage in between layers, we compute with tensile strength, not bed adhesion
-
-                float mass = acc.volume * params.filament_density;
-                const Vec3f &mass_centorid = acc.volume_centroid_accumulator / acc.volume;
-                float weight = mass * params.gravity_constant;
-                float weight_arm = (pivot - mass_centorid.head<2>()).norm();
-                float weight_torque = weight_arm * weight;
-
-                float bed_movement_arm = mass_centorid.z();
-                float bed_movement_force = params.max_acceleration * mass;
-                float bed_movement_torque = bed_movement_force * bed_movement_arm;
-
-                Vec3f extruder_pressure_direction = to_3d(line_dir, 0.0f);
-                extruder_pressure_direction.z() = -0.2 - line.malformation * 0.5;
-                extruder_pressure_direction.normalize();
-                float conflict_torque_arm = (to_3d(Vec2f(pivot - line.b), print_z).cross(
-                        extruder_pressure_direction)).norm();
-                float extruder_conflict_force = params.tolerable_extruder_conflict_force +
-                        std::min(line.malformation, 1.0f) * params.malformations_additive_conflict_extruder_force;
-                float extruder_conflict_torque = extruder_conflict_force * conflict_torque_arm;
-
-                float total_torque = bed_movement_torque + extruder_conflict_torque - weight_torque - sticking_torque;
-
-                if (total_torque > 0) {
-                    Vec2f target_point { };
-                    size_t _idx { };
-                    island_lines_dist.signed_distance_from_lines(pivot_site_search_point, _idx, target_point);
-                    if (!supports_presence_grid.position_taken(to_3d(target_point, print_z))) {
-                        float area = params.support_points_interface_radius * params.support_points_interface_radius
-                                * float(PI);
-                        float sticking_force = area * params.support_adhesion;
-                        Vec3f support_point = to_3d(target_point, print_z);
-                        island.pivot_points.push_back(support_point);
-                        island.sticking_force += sticking_force;
-                        island.sticking_centroid_accumulator += sticking_force * support_point;
-                        issues.support_points.emplace_back(support_point,
-                                extruder_conflict_torque - sticking_torque, extruder_pressure_direction);
-                        supports_presence_grid.take_position(to_3d(target_point, print_z));
-                    }
-                }
-#if 0
-                BOOST_LOG_TRIVIAL(debug)
-                << "SSG: sticking_arm: " << sticking_arm;
-                BOOST_LOG_TRIVIAL(debug)
-                << "SSG: sticking_torque: " << sticking_torque;
-                BOOST_LOG_TRIVIAL(debug)
-                << "SSG: weight_arm: " << sticking_arm;
-                BOOST_LOG_TRIVIAL(debug)
-                << "SSG: weight_torque: " << weight_torque;
-                BOOST_LOG_TRIVIAL(debug)
-                << "SSG: bed_movement_arm: " << bed_movement_arm;
-                BOOST_LOG_TRIVIAL(debug)
-                << "SSG: bed_movement_torque: " << bed_movement_torque;
-                BOOST_LOG_TRIVIAL(debug)
-                << "SSG: conflict_torque_arm: " << conflict_torque_arm;
-                BOOST_LOG_TRIVIAL(debug)
-                << "SSG: extruder_conflict_torque: " << extruder_conflict_torque;
-                BOOST_LOG_TRIVIAL(debug)
-                << "SSG: total_torque: " << total_torque << "   printz: " << print_z;
-    #endif
-            }
-
-            std::unordered_map<size_t, float> tmp = acc.islands_under_with_connection_area;
-            acc.islands_under_with_connection_area.clear();
-            // finally, add gathered islands to accumulator, and continue down to next layer
-            for (const auto &pair : tmp) {
-                const Island &below_i = below.islands[pair.first];
-                for (const auto &below_islands : below_i.islands_under_with_connection_area) {
-                    acc.islands_under_with_connection_area[below_islands.first] += below_islands.second;
-                }
-                for (const Vec3f &pivot_p : below_i.pivot_points) {
-                    acc.pivot_points.push_back(pivot_p);
-                }
-                acc.sticking_centroid_accumulator += below_i.sticking_centroid_accumulator;
-                acc.sticking_force += below_i.sticking_force;
-                acc.volume += below_i.volume;
-                acc.volume_centroid_accumulator += below_i.volume_centroid_accumulator;
-            }
-        }
-
-        // We have arrived to the bed level, now check for stability of the object part on the bed
-        std::vector<Vec2f> pivot_points;
-        for (const Vec3f &p_point : acc.pivot_points) {
-            pivot_points.push_back(p_point.head<2>());
-        }
-        auto coord_fn = [&pivot_points](size_t idx, size_t dim) {
-            return pivot_points[idx][dim];
-        };
-        KDTreeIndirect<2, float, decltype(coord_fn)> pivot_points_tree(coord_fn, pivot_points.size());
-
-        for (const ExtrusionLine &line : island_external_lines) {
-            Vec2f line_dir = (line.b - line.a).normalized();
-            Vec2f pivot_site_search_point = line.b + line_dir * 300.0f;
-            size_t pivot_idx = find_closest_point(pivot_points_tree, pivot_site_search_point);
-            const Vec2f &pivot = pivot_points[pivot_idx];
-
-            const Vec2f &sticking_centroid = acc.sticking_centroid_accumulator.head<2>() / acc.sticking_force;
-            float sticking_arm = (pivot - sticking_centroid).norm();
-            float sticking_torque = sticking_arm * acc.sticking_force;
-
-            float mass = acc.volume * params.filament_density;
-            const Vec3f &mass_centorid = acc.volume_centroid_accumulator / acc.volume;
-            float weight = mass * params.gravity_constant;
-            float weight_arm = (pivot - mass_centorid.head<2>()).norm();
-            float weight_torque = weight_arm * weight;
-
-            float bed_movement_arm = mass_centorid.z();
-            float bed_movement_force = params.max_acceleration * mass;
-            float bed_movement_torque = bed_movement_force * bed_movement_arm;
-
-            Vec3f extruder_pressure_direction = to_3d(line_dir, 0.0f);
-            extruder_pressure_direction.z() = -0.2 - line.malformation * 0.5;
-            extruder_pressure_direction.normalize();
-            float conflict_torque_arm = (to_3d(Vec2f(pivot - line.b), print_z).cross(
-                    extruder_pressure_direction)).norm();
-            float extruder_conflict_force = params.tolerable_extruder_conflict_force +
-                    std::min(line.malformation, 1.0f) * params.malformations_additive_conflict_extruder_force;
-            float extruder_conflict_torque = extruder_conflict_force * conflict_torque_arm;
-
-            float total_torque = bed_movement_torque + extruder_conflict_torque - weight_torque - sticking_torque;
-
-            if (total_torque > 0) {
-                Vec2f target_point;
-                size_t _idx;
-                island_lines_dist.signed_distance_from_lines(pivot_site_search_point, _idx, target_point);
-                if (!supports_presence_grid.position_taken(to_3d(target_point, print_z))) {
-                    float area = params.support_points_interface_radius * params.support_points_interface_radius
-                            * float(PI);
-                    float sticking_force = area * params.support_adhesion;
-                    Vec3f support_point = to_3d(target_point, print_z);
-                    island.pivot_points.push_back(support_point);
-                    island.sticking_force += sticking_force;
-                    island.sticking_centroid_accumulator += sticking_force * support_point;
-                    issues.support_points.emplace_back(support_point,
-                            extruder_conflict_torque - sticking_torque, extruder_pressure_direction);
-                    supports_presence_grid.take_position(to_3d(target_point, print_z));
-                }
-            }
-#if 0
-                 BOOST_LOG_TRIVIAL(debug)
-                 << "SSG: sticking_arm: " << sticking_arm;
-                 BOOST_LOG_TRIVIAL(debug)
-                 << "SSG: sticking_torque: " << sticking_torque;
-                 BOOST_LOG_TRIVIAL(debug)
-                 << "SSG: weight_arm: " << sticking_arm;
-                 BOOST_LOG_TRIVIAL(debug)
-                 << "SSG: weight_torque: " << weight_torque;
-                 BOOST_LOG_TRIVIAL(debug)
-                 << "SSG: bed_movement_arm: " << bed_movement_arm;
-                 BOOST_LOG_TRIVIAL(debug)
-                 << "SSG: bed_movement_torque: " << bed_movement_torque;
-                 BOOST_LOG_TRIVIAL(debug)
-                 << "SSG: conflict_torque_arm: " << conflict_torque_arm;
-                 BOOST_LOG_TRIVIAL(debug)
-                 << "SSG: extruder_conflict_torque: " << extruder_conflict_torque;
-                 BOOST_LOG_TRIVIAL(debug)
-                 << "SSG: total_torque: " << total_torque << "   printz: " << print_z;
-     #endif
-        }
-    }
-}
-
-Issues check_object_stability(const PrintObject *po, const Params &params) {
-#ifdef DEBUG_FILES
-    FILE *segmentation_f = boost::nowide::fopen(debug_out_path("segmentation.obj").c_str(), "w");
-    FILE *malform_f = boost::nowide::fopen(debug_out_path("malformations.obj").c_str(), "w");
-#endif
-
-    Issues issues { };
-    std::vector<LayerIslands> islands_graph;
-    std::vector<ExtrusionLine> layer_lines;
-    float flow_width = get_flow_width(po->layers()[po->layer_count() - 1]->regions()[0], erExternalPerimeter);
-    PixelGrid prev_layer_grid(po, flow_width);
-    SupportGridFilter supports_presence_grid { po, params.min_distance_between_support_points };
-
-    // PREPARE BASE LAYER
-    const Layer *layer = po->layers()[0];
-    for (const LayerRegion *layer_region : layer->regions()) {
-        for (const ExtrusionEntity *ex_entity : layer_region->perimeters.entities) {
-            for (const ExtrusionEntity *perimeter : static_cast<const ExtrusionEntityCollection*>(ex_entity)->entities) {
-                Points points { };
-                perimeter->collect_points(points);
-                for (int point_idx = 0; point_idx < int(points.size() - 1); ++point_idx) {
-                    Vec2f start = unscaled(points[point_idx]).cast<float>();
-                    Vec2f next = unscaled(points[point_idx + 1]).cast<float>();
-                    ExtrusionLine line { start, next, perimeter };
-                    layer_lines.push_back(line);
-                }
-                if (perimeter->is_loop()) {
-                    Vec2f start = unscaled(points[points.size() - 1]).cast<float>();
-                    Vec2f next = unscaled(points[0]).cast<float>();
-                    ExtrusionLine line { start, next, perimeter };
-                    layer_lines.push_back(line);
-                }
-            } // perimeter
-        } // ex_entity
-        for (const ExtrusionEntity *ex_entity : layer_region->fills.entities) {
-            for (const ExtrusionEntity *fill : static_cast<const ExtrusionEntityCollection*>(ex_entity)->entities) {
-                Points points { };
-                fill->collect_points(points);
-                for (int point_idx = 0; point_idx < int(points.size() - 1); ++point_idx) {
-                    Vec2f start = unscaled(points[point_idx]).cast<float>();
-                    Vec2f next = unscaled(points[point_idx + 1]).cast<float>();
-                    ExtrusionLine line { start, next, fill };
-                    layer_lines.push_back(line);
-                }
-            } // fill
-        } // ex_entity
-    } // region
-
-    auto [layer_islands, layer_grid, line_to_island_mapping] = reckon_islands(layer, true, 0, prev_layer_grid,
-            layer_lines, params);
-    islands_graph.push_back(std::move(layer_islands));
-#ifdef DEBUG_FILES
-    for (size_t x = 0; x < size_t(layer_grid.get_pixel_count().x()); ++x) {
-        for (size_t y = 0; y < size_t(layer_grid.get_pixel_count().y()); ++y) {
-            Vec2i coords = Vec2i(x, y);
-            size_t island_idx = layer_grid.get_pixel(coords);
-            if (layer_grid.get_pixel(coords) != NULL_ISLAND) {
-                Vec2f pos = layer_grid.get_pixel_center(coords);
-                size_t pseudornd = ((island_idx + 127) * 33331 + 6907) % 23;
-                Vec3f color = value_to_rgbf(0.0f, float(23), float(pseudornd));
-                fprintf(segmentation_f, "v %f %f %f  %f %f %f\n", pos[0],
-                        pos[1], layer->print_z, color[0], color[1], color[2]);
-            }
-        }
-    }
-    for (const auto &line : layer_lines) {
-        if (line.malformation > 0.0f) {
-            Vec3f color = value_to_rgbf(0, 1.0f, line.malformation);
-            fprintf(malform_f, "v %f %f %f  %f %f %f\n", line.b[0],
-                    line.b[1], layer->print_z, color[0], color[1], color[2]);
-        }
-    }
-#endif
-    LinesDistancer external_lines(layer_lines);
-    layer_lines.clear();
-    prev_layer_grid = layer_grid;
-
-    for (size_t layer_idx = 1; layer_idx < po->layer_count(); ++layer_idx) {
-        const Layer *layer = po->layers()[layer_idx];
-        for (const LayerRegion *layer_region : layer->regions()) {
-            for (const ExtrusionEntity *ex_entity : layer_region->perimeters.entities) {
-                for (const ExtrusionEntity *perimeter : static_cast<const ExtrusionEntityCollection*>(ex_entity)->entities) {
-                    check_extrusion_entity_stability(perimeter, layer_lines, layer->print_z, layer_region,
-                            external_lines, issues, params);
-                } // perimeter
-            } // ex_entity
-            for (const ExtrusionEntity *ex_entity : layer_region->fills.entities) {
-                for (const ExtrusionEntity *fill : static_cast<const ExtrusionEntityCollection*>(ex_entity)->entities) {
-                    if (fill->role() == ExtrusionRole::erGapFill
-                            || fill->role() == ExtrusionRole::erBridgeInfill) {
-                        check_extrusion_entity_stability(fill, layer_lines, layer->print_z, layer_region,
-                                external_lines, issues, params);
-                    } else {
-                        Points points { };
-                        fill->collect_points(points);
-                        for (int point_idx = 0; point_idx < int(points.size() - 1); ++point_idx) {
-                            Vec2f start = unscaled(points[point_idx]).cast<float>();
-                            Vec2f next = unscaled(points[point_idx + 1]).cast<float>();
-                            ExtrusionLine line { start, next, fill };
-                            layer_lines.push_back(line);
-                        }
-                    }
-                } // fill
-            } // ex_entity
-        } // region
-
-        auto [layer_islands, layer_grid, line_to_island_mapping] = reckon_islands(layer, true, 0, prev_layer_grid,
-                layer_lines, params);
-        islands_graph.push_back(std::move(layer_islands));
-
-        check_global_stability(layer->print_z, islands_graph, supports_presence_grid, layer_lines,
-                line_to_island_mapping, issues, params);
-
-#ifdef DEBUG_FILES
-        for (size_t x = 0; x < size_t(layer_grid.get_pixel_count().x()); ++x) {
-            for (size_t y = 0; y < size_t(layer_grid.get_pixel_count().y()); ++y) {
-                Vec2i coords = Vec2i(x, y);
-                size_t island_idx = layer_grid.get_pixel(coords);
-                if (layer_grid.get_pixel(coords) != NULL_ISLAND) {
-                    Vec2f pos = layer_grid.get_pixel_center(coords);
-                    size_t pseudornd = ((island_idx + 127) * 33331 + 6907) % 23;
-                    Vec3f color = value_to_rgbf(0.0f, float(23), float(pseudornd));
-                    fprintf(segmentation_f, "v %f %f %f  %f %f %f\n", pos[0],
-                            pos[1], layer->print_z, color[0], color[1], color[2]);
-                }
-            }
-        }
-        for (const auto &line : layer_lines) {
-            if (line.malformation > 0.0f) {
-                Vec3f color = value_to_rgbf(0, 1.0f, line.malformation);
-                fprintf(malform_f, "v %f %f %f  %f %f %f\n", line.b[0],
-                        line.b[1], layer->print_z, color[0], color[1], color[2]);
-            }
-        }
-#endif
-        external_lines = LinesDistancer(layer_lines);
-        layer_lines.clear();
-        prev_layer_grid = layer_grid;
-    }
-
-#ifdef DEBUG_FILES
-    fclose(segmentation_f);
-    fclose(malform_f);
-#endif
-
-    return issues;
-}
-
-#ifdef DEBUG_FILES
-void debug_export(Issues issues, std::string file_name) {
-    Slic3r::CNumericLocalesSetter locales_setter;
-    {
-        FILE *fp = boost::nowide::fopen(debug_out_path((file_name + "_supports.obj").c_str()).c_str(), "w");
-        if (fp == nullptr) {
-            BOOST_LOG_TRIVIAL(error)
-            << "Debug files: Couldn't open " << file_name << " for writing";
-            return;
-        }
-
-        for (size_t i = 0; i < issues.support_points.size(); ++i) {
-            fprintf(fp, "v %f %f %f  %f %f %f\n", issues.support_points[i].position(0),
-                    issues.support_points[i].position(1),
-                    issues.support_points[i].position(2), 1.0, 0.0, 1.0);
-        }
-
-        fclose(fp);
-    }
-}
-#endif
-
-std::vector<size_t> quick_search(const PrintObject *po, const Params &params) {
-    check_object_stability(po, params);
-    return {};
-}
-
-Issues
-full_search(const PrintObject *po, const Params &params) {
-    auto issues = check_object_stability(po, params);
-#ifdef DEBUG_FILES
-    debug_export(issues, "issues");
-#endif
-    return issues;
-}
-
-} //SupportableIssues End
-}
-
diff --git a/src/slic3r/GUI/BonjourDialog.hpp b/src/slic3r/GUI/BonjourDialog.hpp
index 8bfc076c4..5bb61131d 100644
--- a/src/slic3r/GUI/BonjourDialog.hpp
+++ b/src/slic3r/GUI/BonjourDialog.hpp
@@ -8,6 +8,8 @@
 
 #include <wx/dialog.h>
 #include <wx/string.h>
+#include <boost/asio.hpp>
+#include <boost/nowide/convert.hpp>
 
 #include "libslic3r/PrintConfig.hpp"