diff --git a/src/libslic3r/SLA/SupportPointGenerator.cpp b/src/libslic3r/SLA/SupportPointGenerator.cpp
index 12b819dd9a..93b06ed604 100644
--- a/src/libslic3r/SLA/SupportPointGenerator.cpp
+++ b/src/libslic3r/SLA/SupportPointGenerator.cpp
@@ -135,37 +135,6 @@ Point intersection(const Point &p1, const Point &p2, const Point &cnt, double r2
return {};
}
-///
-/// Uniformly sample Polygon,
-/// Use first point and each next point is first crosing radius from last added
-///
-/// Polygon to sample
-/// Squared distance for sampling
-/// Uniformly distributed points laying on input polygon
-/// with exception of first and last point(they are closer than dist2)
-Slic3r::Points sample(const Polygon &p, double dist2) {
- if (p.empty())
- return {};
-
- Slic3r::Points r;
- r.push_back(p.front());
- const Point *prev_pt = nullptr;
- for (size_t prev_i = 0; prev_i < p.size(); prev_i++) {
- size_t curr_i = (prev_i != p.size() - 1) ? prev_i + 1 : 0;
- const Point &pt = p.points[curr_i];
- double p_dist2 = (r.back() - pt).cast().squaredNorm();
- while (p_dist2 > dist2) { // line segment goes out of radius
- if (prev_pt == nullptr)
- prev_pt = &p.points[prev_i];
- r.push_back(intersection(*prev_pt, pt, r.back(), dist2));
- p_dist2 = (r.back() - pt).cast().squaredNorm();
- prev_pt = &r.back();
- }
- prev_pt = nullptr;
- }
- return r;
-}
-
coord_t get_supported_radius(const LayerSupportPoint &p, float z_distance, const SupportPointGeneratorConfig &config
) {
// TODO: calculate support radius
@@ -265,7 +234,157 @@ Grid2D support_island(const LayerPart &part, float part_z, const SupportPointGen
return part_grid;
}
-};
+///
+/// Copy parts from link to output
+///
+/// Links between part of mesh
+/// Collected polygons from links
+Polygons get_polygons(const PartLinks& part_links) {
+ size_t cnt = 0;
+ for (const PartLink &part_link : part_links)
+ cnt += 1 + part_link.part_it->shape->holes.size();
+
+ Polygons out;
+ out.reserve(cnt);
+ for (const PartLink &part_link : part_links) {
+ const ExPolygon &shape = *part_link.part_it->shape;
+ out.emplace_back(shape.contour);
+ append(out, shape.holes);
+ }
+ return out;
+}
+
+///
+/// Uniformly sample Polyline,
+/// Use first point and each next point is first crosing radius from last added
+///
+/// Begin of polyline points to sample
+/// End of polyline points to sample
+/// Squared distance for sampling
+/// Uniformly distributed points laying on input polygon
+/// with exception of first and last point(they are closer than dist2)
+Slic3r::Points sample(Points::const_iterator b, Points::const_iterator e, double dist2) {
+ assert(e-b >= 2);
+ if (e - b < 2)
+ return {}; // at least one line(2 points)
+
+ // IMPROVE1: start of sampling e.g. center of Polyline
+ // IMPROVE2: Random offset(To remove align of point between slices)
+ // IMPROVE3: Sample small overhangs with memory for last sample(OR in center)
+ Slic3r::Points r;
+ r.push_back(*b);
+
+ Points::const_iterator prev_pt = e;
+ for (Points::const_iterator it = b; it+1 < e; ++it){
+ const Point &pt = *(it+1);
+ double p_dist2 = (r.back() - pt).cast().squaredNorm();
+ while (p_dist2 > dist2) { // line segment goes out of radius
+ if (prev_pt == e)
+ prev_pt = it;
+ r.push_back(intersection(*prev_pt, pt, r.back(), dist2));
+ p_dist2 = (r.back() - pt).cast().squaredNorm();
+ prev_pt = r.end()-1; // r.back()
+ }
+ prev_pt = e;
+ }
+ return r;
+}
+
+bool contain_point(const Point &p, const Points &sorted_points) {
+ auto it = std::lower_bound(sorted_points.begin(), sorted_points.end(), p);
+ if (it == sorted_points.end())
+ return false;
+ ++it; // next point should be same as searched
+ if (it == sorted_points.end())
+ return false;
+ return it->x() == p.x() && it->y() == p.y();
+};
+
+bool exist_same_points(const ExPolygon &shape, const Points& prev_points) {
+ auto shape_points = to_points(shape);
+ return shape_points.end() !=
+ std::find_if(shape_points.begin(), shape_points.end(), [&prev_points](const Point &p) {
+ return contain_point(p, prev_points);
+ });
+}
+
+Points sample_overhangs(const LayerPart& part, double dist2) {
+ const ExPolygon &shape = *part.shape;
+
+ // Collect previous expolygons by links collected in loop before
+ Polygons prev_polygons = get_polygons(part.prev_parts);
+ assert(!prev_polygons.empty());
+ ExPolygons overhangs = diff_ex(shape, prev_polygons);
+ if (overhangs.empty()) // above part is smaller in whole contour
+ return {};
+
+ Points prev_points = to_points(prev_polygons);
+ std::sort(prev_points.begin(), prev_points.end());
+
+ // TODO: solve case when shape and prev points has same point
+ assert(!exist_same_points(shape, prev_points));
+
+ auto sample_overhang = [&prev_points, dist2](const Polygon &polygon, Points &samples) {
+ const Points &pts = polygon.points;
+ // first point which is not part of shape
+ Points::const_iterator first_bad = pts.end();
+ Points::const_iterator start_it = pts.end();
+ for (auto it = pts.begin(); it != pts.end(); ++it) {
+ const Point &p = *it;
+ if (contain_point(p, prev_points)) {
+ if (first_bad == pts.end()) {
+ // remember begining
+ first_bad = it;
+ }
+ if (start_it != pts.end()) {
+ // finish sampling
+ append(samples, sample(start_it, it, dist2));
+ // prepare for new start
+ start_it = pts.end();
+ }
+ } else if (start_it == pts.end()) {
+ start_it = it;
+ }
+ }
+
+ // sample last segment
+ if (start_it == pts.end()) { // tail is without points
+ if (first_bad != pts.begin()) // only begining
+ append(samples, sample(pts.begin(), first_bad, dist2));
+ } else { // tail contain points
+ if (first_bad == pts.begin()) { // only tail
+ append(samples, sample(start_it, pts.end(), dist2));
+ } else if (start_it == pts.begin()) { // whole polygon is overhang
+ assert(first_bad == pts.end());
+ Points pts2 = pts; // copy
+ pts2.push_back(pts.front());
+ append(samples, sample(pts2.begin(), pts2.end(), dist2));
+ } else { // need connect begining and tail
+ Points pts2;
+ pts2.reserve((pts.end() - start_it) +
+ (first_bad - pts.begin()));
+ for (auto it = start_it; it < pts.end(); ++it)
+ pts2.push_back(*it);
+ for (auto it = pts.begin(); it < first_bad; ++it)
+ pts2.push_back(*it);
+ append(samples, sample(pts2.begin(), pts2.end(), dist2));
+ }
+ }
+ };
+
+ Points samples;
+ for (const ExPolygon &overhang : overhangs) {
+ sample_overhang(overhang.contour, samples);
+ for (const Polygon &hole : overhang.holes) {
+ sample_overhang(hole, samples);
+ }
+ }
+ return samples;
+}
+
+} // namespace
+
+#include "libslic3r/Execution/ExecutionSeq.hpp"
SupportPointGeneratorData Slic3r::sla::prepare_generator_data(
std::vector &&slices,
@@ -295,24 +414,24 @@ SupportPointGeneratorData Slic3r::sla::prepare_generator_data(
// CPU write caches due to synchronization primitves.
throw_on_cancel();
- const double sample_distance_in_mm = scale_(2);
- const double sample_distance_in_mm2 = sample_distance_in_mm * sample_distance_in_mm;
-
Layer &layer = result.layers[layer_id];
const ExPolygons &islands = result.slices[layer_id];
layer.parts.reserve(islands.size());
- for (const ExPolygon &island : islands)
+ for (const ExPolygon &island : islands) {
layer.parts.push_back(LayerPart{
&island,
- get_extents(island.contour),
- sample(island.contour, sample_distance_in_mm2)
+ get_extents(island.contour)
+ // sample - only hangout part of expolygon could be known after linking
});
-
+ }
}, 32 /*gransize*/);
+ const double sample_distance_in_mm = scale_(2);
+ const double sample_distance_in_mm2 = sample_distance_in_mm * sample_distance_in_mm;
+
// Link parts by intersections
- execution::for_each(ex_tbb, size_t(1), result.slices.size(),
- [&result, throw_on_cancel] (size_t layer_id) {
+ execution::for_each(ex_seq, size_t(1), result.slices.size(),
+ [&result, sample_distance_in_mm2, 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();
@@ -335,6 +454,14 @@ SupportPointGeneratorData Slic3r::sla::prepare_generator_data(
it_above->prev_parts.emplace_back(PartLink{it_below});
it_below->next_parts.emplace_back(PartLink{it_above});
}
+
+ if (it_above->prev_parts.empty())
+ continue;
+
+ // IMPROVE: overhangs could be calculated with Z coordninate
+ // soo one will know source shape of point and do not have to search this information
+ // Get inspiration at https://github.com/Prusa-Development/PrusaSlicerPrivate/blob/e00c46f070ec3d6fc325640b0dd10511f8acf5f7/src/libslic3r/PerimeterGenerator.cpp#L399
+ it_above->samples = sample_overhangs(*it_above, sample_distance_in_mm2);
}
}, 8 /* gransize */);
return result;