diff --git a/src/libslic3r/CutSurface.cpp b/src/libslic3r/CutSurface.cpp
index 1283474755..412eaa42e2 100644
--- a/src/libslic3r/CutSurface.cpp
+++ b/src/libslic3r/CutSurface.cpp
@@ -455,6 +455,25 @@ ProjectionDistances choose_best_distance(
const BoundingBox &shapes_bb,
const ShapePoint2index &shape_point_2_index);
+///
+/// Merge 2 cuts together, cut off inner part
+///
+/// [In/Out] surface cut
+/// Cut to intersect with
+/// Source of surface
+/// True when merge otherwise False
+bool merge_cut(CutAOI &cut1, const CutAOI &cut2, const CutMesh &mesh);
+
+///
+/// Merge cuts together
+///
+/// [In/Out] cutted surface of model
+/// Source of surface
+/// Filtered indicies of Cut from best projection distances
+void merge_cuts(CutAOIs &cuts,
+ const CutMesh &mesh,
+ const std::vector &use_cut_indices);
+
///
/// Filter out cuts which are behind another.
/// Prevent overlapping embossed shape in space.
@@ -707,6 +726,9 @@ SurfaceCut Slic3r::cut_surface(const indexed_triangle_set &model,
// for each point collect all projection distances
std::vector distances =
priv::create_distances(cutAOIs, cgal_model, shapes_points, cgal_shape, projection_ratio, vert_shape_map);
+
+ // NOTE: it will be fine to calc AOIs range,
+ // not only outline but all vertices in direction of emboss - faster check on intersection
#ifdef DEBUG_OUTPUT_DIR
auto [front,back] = projection.create_front_back(shapes_bb.center());
@@ -722,6 +744,20 @@ SurfaceCut Slic3r::cut_surface(const indexed_triangle_set &model,
priv::store(best_projection, cutAOIs, cgal_model, DEBUG_OUTPUT_DIR + "best_projection.obj"); // only debug
#endif // DEBUG_OUTPUT_DIR
+ std::vector is_best_cut(cutAOIs.size(), {false});
+ for (const priv::ProjectionDistance &d : best_projection)
+ is_best_cut[d.aoi_index] = true;
+ std::vector best_cut_indices;
+ for (size_t i = 0; i < cutAOIs.size(); ++i)
+ if (is_best_cut[i]) best_cut_indices.push_back(i);
+
+ // cut off part + filtrate cutAOIs
+ priv::merge_cuts(cutAOIs, cgal_model, best_cut_indices);
+#ifdef DEBUG_OUTPUT_DIR
+ priv::store(cutAOIs, cgal_model, DEBUG_OUTPUT_DIR + "merged-aois/");
+ // only debug
+#endif // DEBUG_OUTPUT_DIR
+
// Filter out NO top one cuts
priv::filter_cuts(cutAOIs, cgal_model, shapes,
shape_point_2_index, projection, vert_shape_map);
@@ -1877,14 +1913,13 @@ std::vector priv::create_distances(
for (size_t i = 0; i < 3; i++) {
float val = start[i] - end[i];
// abs value
- if (val < 0.f) val *= -1;
+ if (val < 0.f) val *= -1.f;
if (max_val < val) {
max_val = val;
max_i = i;
}
}
- float ratio = (p[max_i] - start[max_i]) / max_val;
- return (ratio - projection_ratio) * max_val;
+ return (p[max_i] - start[max_i]) - projection_ratio * (end[max_i] - start[max_i]);
};
std::vector distances(shapes_points);
@@ -1902,17 +1937,6 @@ std::vector priv::create_distances(
ProjectionDistance pd;
pd.aoi_index = &cut - &cuts.front();
pd.hi_index = &hi - &cut.second.front();
- // Option to not calculate distance when exist only one AOI
- //if (pds.empty()) {
- // // first is without calc of distance
- // pds.push_back(std::move(pd));
- // continue;
- //} else if (pds.size() == 1) {
- // // calculate distance first item
- // ProjectionDistance &prev = pds.front();
- // HI hi = cuts[prev.aoi_index].second[prev.hi_index];
- // prev.distance = calc_distance(pi, mesh.source(hi));
- //}
pd.distance = calc_distance(pi, vi);
pds.push_back(std::move(pd));
}
@@ -1920,30 +1944,6 @@ std::vector priv::create_distances(
return distances;
}
-//uint32_t get_closest_point_id(const ExPolygons &shapes, const Point &p) {
-// float distance_sq = std::numeric_limits::max();
-// uint32_t closest_id{0};
-// uint32_t id{0};
-// auto get_closest = [&p, &id, &closest_id, &distance_sq](const Points &pts) {
-// for (const Point &p_ : pts) {
-// Point dp = p - p_;
-// float d = dp.x() * dp.x() + dp.y() * dp.y();
-// if (distance_sq > d) {
-// distance_sq = d;
-// closest_id = id;
-// }
-// ++id;
-// }
-// };
-//
-// for (const ExPolygon &shape : shapes) {
-// get_closest(shape.contour.points);
-// for (const Polygon &hole : shape.holes)
-// get_closest(hole.points);
-// }
-// return closest_id;
-//}
-
priv::ProjectionDistances priv::choose_best_distance(
const std::vector &distances,
const ExPolygons &shapes,
@@ -2317,6 +2317,100 @@ void priv::store(const Vec3f &vertex,
its_write_obj(its, file.c_str());
}
+bool priv::merge_cut(CutAOI &cut1, const CutAOI &cut2, const CutMesh &mesh)
+{
+ // create cgal model and merge it together
+
+ return false;
+}
+
+void priv::merge_cuts(CutAOIs &cuts,
+ const CutMesh &mesh,
+ const std::vector &use_cut_indices)
+{
+ auto create_bb = [&mesh](const CutAOI &cut) -> BoundingBoxf3 {
+ Vec3f min(std::numeric_limits::min(),
+ std::numeric_limits::min(),
+ std::numeric_limits::min());
+ Vec3f max(std::numeric_limits::max(),
+ std::numeric_limits::max(),
+ std::numeric_limits::max());
+ for (const FI &fi : cut.first) {
+ HI hi = mesh.halfedge(fi);
+ for (VI vi : {mesh.source(hi), mesh.target(hi),
+ mesh.target(mesh.next(hi))}) {
+ const P3 &p = mesh.point(vi);
+ for (size_t i = 0; i < 3; i++) {
+ if (min[i] > p[i]) min[i] = p[i];
+ if (max[i] < p[i]) max[i] = p[i];
+ }
+ }
+ }
+ return BoundingBoxf3(min.cast(), max.cast());
+ };
+
+ // create bounding boxes for cuts
+ std::vector bbs;
+ bbs.reserve(cuts.size());
+ for (const CutAOI &cut : cuts)
+ bbs.push_back(create_bb(cut));
+ // extend used bb by intersecting bb
+ // NOTE: after merge 2 cuts could appear new intersection on surface of merged in
+
+ std::vector> merge_order;
+ std::vector del_cuts(cuts.size(), {true});
+ for (size_t cut_index : use_cut_indices) del_cuts[cut_index] = false;
+
+ // find intersection of cuts by Bounding boxes intersection
+ for (size_t cut_index : use_cut_indices) {
+ // check if cut is merged into another one
+ if (del_cuts[cut_index]) continue;
+ BoundingBoxf3& result_bb = bbs[cut_index];
+ CutAOI &cut = cuts[cut_index];
+ // all merged cuts into cut_index
+ std::vector merged(cuts.size(), {false});
+
+ // merged in last iteration
+ std::vector new_merged;
+ bool exist_new_extension;
+ bool is_first = true;
+ do {
+ exist_new_extension = false;
+ new_merged = std::vector(cuts.size(), {false});
+ for (const BoundingBoxf3 &bb : bbs) {
+ size_t bb_index = &bb - &bbs.front();
+ // do not merge itself
+ if (cut_index == bb_index) continue;
+ if (!is_first && merged[cut_index]) continue;
+ if (!bb.intersects(result_bb)) {
+ if (is_first) continue;
+ bool has_new_intersection = false;
+ for (size_t i = 0; i < cuts.size(); i++) {
+ if (!new_merged[i]) continue;
+ if (!bbs[i].intersects(bb)) continue;
+ has_new_intersection = true;
+ }
+ if (!has_new_intersection) continue;
+ }
+ if(!merge_cut(cut, cuts[bb_index], mesh)) continue;
+ result_bb = create_bb(cut);
+ merged[bb_index] = true;
+ del_cuts[bb_index] = true;
+ new_merged[bb_index] = true;
+ // extend result_bb
+ exist_new_extension = true;
+ }
+ is_first = false;
+ } while (exist_new_extension);
+ }
+
+ // remove flagged cuts
+ for (size_t i = del_cuts.size(); i > 0; --i) {
+ size_t index = i - 1;
+ if (del_cuts[index]) cuts.erase(cuts.begin() + index);
+ }
+}
+
void priv::filter_cuts(CutAOIs &cuts,
const CutMesh &mesh,
const ExPolygons &shapes,