FIX: classify enforced support overhangs

jira: STUDIO-11484
Change-Id: I4b9e5a86b095bc788c803a22a551c6a9c1fad95e
This commit is contained in:
jiaxi.chen 2025-04-09 11:56:51 +08:00 committed by lane.wei
parent 6d2f21ef4c
commit c03e133404

View File

@ -876,25 +876,36 @@ void TreeSupport::detect_overhangs(bool check_support_necessity/* = false*/)
std::chrono::time_point<clock_> t0{ clock_::now() };
// main part of overhang detection can be parallel
tbb::concurrent_vector<ExPolygons> overhangs_all_layers(m_object->layer_count());
auto enforcers = m_object->slice_support_enforcers();
auto blockers = m_object->slice_support_blockers();
m_vertical_enforcer_points.clear();
m_object->project_and_append_custom_facets(false, EnforcerBlockerType::BLOCKER, blockers);
m_object->project_and_append_custom_facets(false, EnforcerBlockerType::ENFORCER, enforcers, &m_vertical_enforcer_points);
tbb::parallel_for(tbb::blocked_range<size_t>(0, m_object->layer_count()),
[&](const tbb::blocked_range<size_t>& range) {
for (size_t layer_nr = range.begin(); layer_nr < range.end(); layer_nr++) {
if (m_object->print()->canceled())
break;
if (!is_auto(stype) && layer_nr > enforce_support_layers)
// FIXME the param enforce_support_layers is not set yet
if (!(is_auto(stype) || (enforce_support_layers > 0 && layer_nr >= enforce_support_layers) || (layer_nr < enforcers.size() && !enforcers[layer_nr].empty())))
continue;
Layer* layer = m_object->get_layer(layer_nr);
if (layer->lower_layer == nullptr) {
for (auto& slice : layer->lslices_extrudable) {
ExPolygons curr_polys = layer->lslices_extrudable;
if (layer_nr < blockers.size() && !blockers[layer_nr].empty())
curr_polys = diff_ex(curr_polys, offset_ex(union_(blockers[layer_nr]), scale_(radius_sample_resolution)));
for (auto& slice : curr_polys) {
auto bbox_size = get_extents(slice).size();
if (!((bbox_size.x() > length_thresh_well_supported || bbox_size.y() > length_thresh_well_supported))
&& g_config_support_sharp_tails) {
layer->sharp_tails.push_back(slice);
layer->sharp_tails_height.push_back(layer->height);
}
#ifdef SUPPORT_TREE_DEBUG_TO_SVG
SVG::export_expolygons(debug_out_path("sharp_tail_orig_%.02f.svg", layer->print_z), {slice});
#endif
}
continue;
}
@ -905,10 +916,32 @@ void TreeSupport::detect_overhangs(bool check_support_necessity/* = false*/)
coordf_t support_offset_scaled = scale_(lower_layer_offset);
ExPolygons& curr_polys = layer->lslices_extrudable;
ExPolygons& lower_polys = lower_layer->lslices_extrudable;
// normal overhang
ExPolygons lower_layer_offseted = offset_ex(lower_polys, support_offset_scaled, SUPPORT_SURFACES_OFFSET_PARAMETERS);
// add enforcer
ExPolygons enforced_overhangs;
ExPolygons blocker;
if (!enforcers.empty())
enforced_overhangs = intersection_ex(diff_ex(layer->lslices_extrudable, lower_layer->lslices_extrudable), enforcers[layer_nr]);
if (is_auto(stype)) {
// normal overhang
overhangs_all_layers[layer_nr] = std::move(diff_ex(curr_polys, lower_layer_offseted));
// if is auto, add blocker first
if (layer_nr < blockers.size() && !blockers[layer_nr].empty()) {
// Arthur: union_ is a must because after mirroring, the blocker polygons are in left-hand coordinates, ie clockwise,
// which are not valid polygons, and will be removed by offset_ex. union_ can make these polygons right.
blocker = offset_ex(union_(blockers[layer_nr]), scale_(radius_sample_resolution));
if (!blocker.empty()) overhangs_all_layers[layer_nr] = diff_ex(overhangs_all_layers[layer_nr], blocker);
}
if (!enforced_overhangs.empty()) overhangs_all_layers[layer_nr] = union_ex(overhangs_all_layers[layer_nr], enforced_overhangs);
}
else if (layer_nr < enforcers.size() && lower_layer) {
if (!enforced_overhangs.empty()) {
// FIXME this is a hack to make enforcers work on steep overhangs. See STUDIO-7538.
enforced_overhangs = diff_ex(offset_ex(enforced_overhangs, enforcer_overhang_offset), lower_layer->lslices_extrudable);
overhangs_all_layers[layer_nr] = std::move(enforced_overhangs);
}
}
double duration{ std::chrono::duration_cast<second_>(clock_::now() - t0).count() };
if (duration > 30 || overhangs_all_layers[layer_nr].size() > 100) {
@ -919,8 +952,11 @@ void TreeSupport::detect_overhangs(bool check_support_necessity/* = false*/)
}
if (is_auto(stype) && config_detect_sharp_tails)
{
ExPolygons curr = curr_polys;
if (!blocker.empty()) curr = diff_ex(curr, blocker);
if (!enforced_overhangs.empty()) curr = union_ex(curr, enforced_overhangs);
// BBS detect sharp tail
for (const ExPolygon& expoly : curr_polys) {
for (const ExPolygon& expoly : curr) {
bool is_sharp_tail = false;
// 1. nothing below
// this is a sharp tail region if it's floating and non-ignorable
@ -1015,7 +1051,13 @@ void TreeSupport::detect_overhangs(bool check_support_necessity/* = false*/)
// BBS detect sharp tail
const ExPolygons& lower_layer_sharptails = lower_layer->sharp_tails;
const auto& lower_layer_sharptails_height = lower_layer->sharp_tails_height;
for (ExPolygon& expoly : layer->lslices_extrudable) {
ExPolygons curr_polys = layer->lslices_extrudable;
if (!blockers.empty() && layer_nr < blockers.size() && !blockers[layer_nr].empty())
curr_polys = diff_ex(curr_polys, offset_ex(union_(blockers[layer_nr]), scale_(radius_sample_resolution)));
if (!enforcers.empty() && layer_nr < enforcers.size() && !enforcers[layer_nr].empty())
curr_polys = union_ex(curr_polys, intersection_ex(diff_ex(layer->lslices_extrudable, lower_layer->lslices_extrudable), enforcers[layer_nr]));
for (ExPolygon& expoly : curr_polys) {
bool is_sharp_tail = false;
float accum_height = layer->height;
do {
@ -1088,12 +1130,6 @@ void TreeSupport::detect_overhangs(bool check_support_necessity/* = false*/)
}
}
auto enforcers = m_object->slice_support_enforcers();
auto blockers = m_object->slice_support_blockers();
m_vertical_enforcer_points.clear();
m_object->project_and_append_custom_facets(false, EnforcerBlockerType::ENFORCER, enforcers, &m_vertical_enforcer_points);
m_object->project_and_append_custom_facets(false, EnforcerBlockerType::BLOCKER, blockers);
for (auto &cluster : overhangClusters) {
// remove small overhangs
@ -1142,8 +1178,31 @@ void TreeSupport::detect_overhangs(bool check_support_necessity/* = false*/)
auto lower_layer = layer->lower_layer;
if (support_critical_regions_only && is_auto(stype)) {
layer->loverhangs.clear(); // remove oridinary overhangs, only keep cantilevers and sharp tails (added later)
if (lower_layer == nullptr || enforcers.empty() || layer_nr >= enforcers.size() || enforcers[layer_nr].empty()) {
layer->loverhangs.clear();
layer->loverhangs_with_type.clear();
} else {
ExPolygons enforced_overhangs = intersection_ex(diff_ex(layer->lslices_extrudable, lower_layer->lslices_extrudable), enforcers[layer_nr]);
ExPolygons loverhangs_new;
std::vector<std::pair<ExPolygon, int>> loverhangs_with_type_new;
if (!enforced_overhangs.empty()) {
for (auto &overhang_part : layer->loverhangs_with_type) {
const auto &overhang = overhang_part.first;
auto type = overhang_part.second;
if (type & OverhangType::Cantilever || type & OverhangType::SharpTail) continue;
if (!overlaps(enforced_overhangs, overhang)) continue;
ExPolygons overhangs = intersection_ex(enforced_overhangs, overhang);
if (!overhangs.empty()) {
for (const auto &expoly : overhangs) {
loverhangs_new.emplace_back(expoly);
loverhangs_with_type_new.emplace_back(std::make_pair(expoly, type));
}
}
}
}
layer->loverhangs = std::move(loverhangs_new);
layer->loverhangs_with_type = std::move(loverhangs_with_type_new);
}
for (auto &cantilever : layer->cantilevers) add_overhang(layer, cantilever, OverhangType::Cantilever);
}
@ -1168,19 +1227,6 @@ void TreeSupport::detect_overhangs(bool check_support_necessity/* = false*/)
}
}
if (layer_nr < blockers.size()) {
// Arthur: union_ is a must because after mirroring, the blocker polygons are in left-hand coordinates, ie clockwise,
// which are not valid polygons, and will be removed by offset_ex. union_ can make these polygons right.
ExPolygons blocker = offset_ex(union_(blockers[layer_nr]), scale_(radius_sample_resolution));
auto old_overhangs_with_type = layer->loverhangs_with_type;
layer->loverhangs.clear();
layer->loverhangs_with_type.clear();
for (auto &poly : old_overhangs_with_type) {
ExPolygons polydiff = diff_ex(poly.first, blocker);
for (auto &diff : polydiff) add_overhang(layer, diff, OverhangType(poly.second));
}
}
if (max_bridge_length > 0 && layer->loverhangs.size() > 0 && lower_layer) {
// do not break bridge as the interface will be poor, see #4318
bool break_bridge = false;
@ -1188,16 +1234,6 @@ void TreeSupport::detect_overhangs(bool check_support_necessity/* = false*/)
}
int nDetected = layer->loverhangs.size();
// enforcers now follow same logic as normal support. See STUDIO-3692
if (layer_nr < enforcers.size() && lower_layer) {
ExPolygons enforced_overhangs = intersection_ex(diff_ex(layer->lslices_extrudable, lower_layer->lslices_extrudable), enforcers[layer_nr]);
if (!enforced_overhangs.empty()) {
// FIXME this is a hack to make enforcers work on steep overhangs. See STUDIO-7538.
enforced_overhangs = diff_ex(offset_ex(enforced_overhangs, enforcer_overhang_offset), lower_layer->lslices_extrudable);
for (auto &poly : enforced_overhangs) add_overhang(layer, poly, OverhangType::Normal);
}
}
int nEnforced = layer->loverhangs.size();
//// add sharp tail overhangs
//append(layer->loverhangs, sharp_tail_overhangs);