From c03e1334044c0fe9ab5d668ae53f0010bc596e7e Mon Sep 17 00:00:00 2001 From: "jiaxi.chen" Date: Wed, 9 Apr 2025 11:56:51 +0800 Subject: [PATCH] FIX: classify enforced support overhangs jira: STUDIO-11484 Change-Id: I4b9e5a86b095bc788c803a22a551c6a9c1fad95e --- src/libslic3r/Support/TreeSupport.cpp | 114 +++++++++++++++++--------- 1 file changed, 75 insertions(+), 39 deletions(-) diff --git a/src/libslic3r/Support/TreeSupport.cpp b/src/libslic3r/Support/TreeSupport.cpp index 0bda1af34..6ad3aabb8 100644 --- a/src/libslic3r/Support/TreeSupport.cpp +++ b/src/libslic3r/Support/TreeSupport.cpp @@ -876,25 +876,36 @@ void TreeSupport::detect_overhangs(bool check_support_necessity/* = false*/) std::chrono::time_point t0{ clock_::now() }; // main part of overhang detection can be parallel tbb::concurrent_vector 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(0, m_object->layer_count()), [&](const tbb::blocked_range& 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; + ExPolygons lower_layer_offseted = offset_ex(lower_polys, support_offset_scaled, SUPPORT_SURFACES_OFFSET_PARAMETERS); - // normal overhang - ExPolygons lower_layer_offseted = offset_ex(lower_polys, support_offset_scaled, SUPPORT_SURFACES_OFFSET_PARAMETERS); - overhangs_all_layers[layer_nr] = std::move(diff_ex(curr_polys, lower_layer_offseted)); + // 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(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) - layer->loverhangs_with_type.clear(); + 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> 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);