diff --git a/src/libslic3r/SLA/SupportPointGenerator.cpp b/src/libslic3r/SLA/SupportPointGenerator.cpp
index 7cf559d80e..6b7fbe7ae6 100644
--- a/src/libslic3r/SLA/SupportPointGenerator.cpp
+++ b/src/libslic3r/SLA/SupportPointGenerator.cpp
@@ -498,6 +498,102 @@ void remove_supports_out_of_part(NearPoints& near_points, const LayerPart &part,
near_points.remove_out_of(extend_shape);
}
+///
+/// Detect existence of peninsula on current layer part
+///
+/// IN/OUT island part containing peninsulas
+/// minimal width of overhang to become peninsula
+void create_peninsulas(LayerPart &part, float min_peninsula_width) {
+ const Polygons below_polygons = get_polygons(part.prev_parts);
+ const Polygons below_expanded = expand(below_polygons, min_peninsula_width, ClipperLib::jtSquare);
+ const ExPolygon &part_shape = *part.shape;
+ ExPolygons over_peninsula = diff_ex(part_shape, below_expanded);
+ if (over_peninsula.empty())
+ return; // only tiny overhangs
+
+ // exist layer part over peninsula limit
+ ExPolygons peninsulas_shape = diff_ex(part_shape, below_polygons);
+
+ // IMPROVE: Anotate source of diff by ClipperLib_Z
+ Lines below_lines = to_lines(below_polygons);
+ auto get_angle = [](const Line &l) {
+ Point diff = l.b - l.a;
+ if (diff.x() < 0) // Only positive direction X
+ diff = -diff;
+ return atan2(diff.y(), diff.x());
+ };
+ std::vector belowe_line_angle; // define direction of line with positive X
+ belowe_line_angle.reserve(below_lines.size());
+ for (const Line& l : below_lines)
+ belowe_line_angle.push_back(get_angle(l));
+ std::vector idx(below_lines.size());
+ std::iota(idx.begin(), idx.end(), 0);
+ auto is_lower = [&belowe_line_angle](size_t i1, size_t i2) {
+ return belowe_line_angle[i1] < belowe_line_angle[i2]; };
+ std::sort(idx.begin(), idx.end(), is_lower);
+
+ auto is_overlap = [&get_angle, &idx, &is_lower, &below_lines, &belowe_line_angle]
+ (const Line &l) {
+ // allowed angle epsilon
+ const double angle_epsilon = 1e-3;
+ const double paralel_epsilon = scale_(1e-2);
+ double angle = get_angle(l);
+ double low_angle = angle - angle_epsilon;
+ bool is_over = false;
+ if (low_angle <= -M_PI_2) {
+ low_angle += M_PI;
+ is_over = true;
+ }
+ double hi_angle = angle + angle_epsilon;
+ if (hi_angle >= M_PI_2) {
+ hi_angle -= M_PI;
+ is_over = true;
+ }
+ int mayorit_idx = 0;
+ if (Point d = l.a - l.b;
+ abs(d.x()) < abs(d.y()))
+ mayorit_idx = 1;
+
+ coord_t low = l.a[mayorit_idx];
+ coord_t high = l.b[mayorit_idx];
+ if (low > high)
+ std::swap(low, high);
+
+ auto it_idx = std::lower_bound(idx.begin(), idx.end(), low_angle, is_lower);
+ if (is_over && it_idx == idx.end()) {
+ it_idx = idx.begin();
+ is_over = false;
+ }
+ while (is_over || it_idx != idx.end() || belowe_line_angle[*it_idx] < hi_angle) {
+ const Line &l2 = below_lines[*it_idx];
+ coord_t l2_low = l2.a[mayorit_idx];
+ coord_t l2_high = l2.b[mayorit_idx];
+ if (low > high)
+ std::swap(low, high);
+ if ((l2_high >= low && l2_low <= high) &&
+ l.distance_to(l2.a) < paralel_epsilon)
+ return true;
+ ++it_idx;
+ if (is_over && it_idx == idx.end()) {
+ it_idx = idx.begin();
+ is_over = false;
+ }
+ }
+ return false;
+ };
+
+ // anotate source of peninsula: overhang VS previous layer
+ for (const ExPolygon &peninsula : peninsulas_shape) {
+ // need to know shape and edges of peninsula
+ Lines lines = to_lines(peninsula);
+ std::vector is_outline(lines.size());
+ // when line overlap with belowe lines it is not outline
+ for (size_t i = 0; i < lines.size(); i++)
+ is_outline[i] = is_overlap(lines[i]);
+ part.peninsulas.push_back(Peninsula{peninsula, is_outline});
+ }
+}
+
} // namespace
#include "libslic3r/Execution/ExecutionSeq.hpp"
@@ -546,7 +642,7 @@ SupportPointGeneratorData Slic3r::sla::prepare_generator_data(
double sample_distance_in_um2 = sample_distance_in_um * sample_distance_in_um;
// Link parts by intersections
- execution::for_each(ex_seq, size_t(1), result.slices.size(),
+ execution::for_each(ex_tbb, size_t(1), result.slices.size(),
[&result, sample_distance_in_um2, throw_on_cancel](size_t layer_id) {
if ((layer_id % 2) == 0)
// Don't call the following function too often as it flushes CPU write caches due to synchronization primitves.
@@ -580,6 +676,18 @@ SupportPointGeneratorData Slic3r::sla::prepare_generator_data(
it_above->samples = sample_overhangs(*it_above, sample_distance_in_um2);
}
}, 8 /* gransize */);
+
+ // Detect peninsula
+ float min_peninsula_width = scale_(2); // [in scaled mm]
+ execution::for_each(ex_seq, size_t(1), result.slices.size(),
+ [&layers = result.layers, &min_peninsula_width, throw_on_cancel](size_t layer_id) {
+ if ((layer_id % 2) == 0)
+ // Don't call the following function too often as it flushes CPU write caches due to synchronization primitves.
+ throw_on_cancel();
+ LayerParts &parts = layers[layer_id].parts;
+ for (auto it_part = parts.begin(); it_part < parts.end(); ++it_part)
+ create_peninsulas(*it_part, min_peninsula_width);
+ }, 8 /* gransize */);
return result;
}
diff --git a/src/libslic3r/SLA/SupportPointGenerator.hpp b/src/libslic3r/SLA/SupportPointGenerator.hpp
index 86f69c3742..53f53eab95 100644
--- a/src/libslic3r/SLA/SupportPointGenerator.hpp
+++ b/src/libslic3r/SLA/SupportPointGenerator.hpp
@@ -78,6 +78,19 @@ using PartLinks = boost::container::small_vector;
using PartLinks = std::vector;
#endif
+// Large one layer overhang that needs to be supported on the overhanging side
+struct Peninsula{
+ // shape of peninsula some of edges are overhang
+ ExPolygon shape;
+
+ // same size as shape lines count
+ // convert shape to lines by to_lines(shape)
+ // True .. peninsula outline(coast)
+ // False .. connection to land(already supported by previous layer)
+ std::vector is_outline;
+};
+using Peninsulas = std::vector;
+
// Part on layer is defined by its shape
struct LayerPart {
// Pointer to expolygon stored in input
@@ -93,6 +106,9 @@ struct LayerPart {
// Parts from previous printed layer, which is connected to current part
PartLinks prev_parts;
PartLinks next_parts;
+
+ // half island is supported as special case
+ Peninsulas peninsulas;
};
///
@@ -156,6 +172,17 @@ using ThrowOnCancel = std::function;
// call to say progress of generation into gui in range from 0 to 100
using StatusFunction= std::function;
+struct PrepareGeneratorDataConfig
+{
+ // Discretization of overhangs outline,
+ // smaller will slow down the process but will be more precise
+ double discretize_overhang_sample_in_mm = 2.; // [in mm]
+
+ // Define minimal width of overhang to be considered as peninsula
+ // (partialy island - sampled not on edge)
+ coord_t peninsula_width = scale_(2.); // [in scaled mm]
+};
+
///
/// Prepare data for generate support points
/// Used for interactive resampling to store permanent data between configuration changes.,