From 6d40ec93f680ec32ca97c15c05eff79df0eb7a9d Mon Sep 17 00:00:00 2001 From: Kiss Lorand <50251547+kisslorand@users.noreply.github.com> Date: Sat, 17 Oct 2026 00:04:57 +0300 Subject: [PATCH] Fix missing tree support paths and misplaced extra walls (#16549) --- src/libslic3r/Support/SupportCommon.cpp | 13 ++++------ src/libslic3r/Support/TreeSupport.cpp | 32 ++++++++----------------- src/libslic3r/Support/TreeSupport.hpp | 1 - 3 files changed, 15 insertions(+), 31 deletions(-) diff --git a/src/libslic3r/Support/SupportCommon.cpp b/src/libslic3r/Support/SupportCommon.cpp index 481213fe48..dddbfcf189 100644 --- a/src/libslic3r/Support/SupportCommon.cpp +++ b/src/libslic3r/Support/SupportCommon.cpp @@ -707,8 +707,10 @@ void tree_supports_generate_paths( false); } if (eec) { - std::reverse(eec->entities.begin(), eec->entities.end()); - dst.emplace_back(eec.release()); + if (!eec->empty()) { + std::reverse(eec->entities.begin(), eec->entities.end()); + dst.emplace_back(eec.release()); + } } } } @@ -1825,12 +1827,7 @@ void generate_support_toolpaths( no_sort = true; } else if (support_params.support_style == SupportMaterialStyle::smsTreeOrganic && (config.support_base_pattern == smpNone || config.support_base_pattern == smpDefault)) { - // Orca: A special case for the hollow Organic supports - // Orca: If the tree supports are too tall, use a double wall to make it stronger - SupportParameters support_params2 = support_params; - if (support_layer.print_z > 100.0) - support_params2.tree_branch_diameter_double_wall_area_scaled = 0.1; - tree_supports_generate_paths(base_layer.extrusions, base_layer.polygons_to_extrude(), flow, support_params2); + tree_supports_generate_paths(base_layer.extrusions, base_layer.polygons_to_extrude(), flow, support_params); done = true; } if (! done) diff --git a/src/libslic3r/Support/TreeSupport.cpp b/src/libslic3r/Support/TreeSupport.cpp index 5187e73a25..70ab0b06f1 100644 --- a/src/libslic3r/Support/TreeSupport.cpp +++ b/src/libslic3r/Support/TreeSupport.cpp @@ -2149,7 +2149,9 @@ void TreeSupport::draw_circles() const bool with_lightning_infill = m_support_params.base_fill_pattern == ipLightning; coordf_t support_extrusion_width = m_support_params.support_extrusion_width; const float tree_brim_width = config.tree_support_brim_width.value; - + // Reinforce branches moving more than half a support-line width between layers. + // Square the threshold for comparison with the squared XY movement below. + const double max_move_sq = sqr(double(scale_(m_object_config->support_line_width / 2))); // Belt floor: the first object layer is not on a flat bed — it rests on the // tilted, moving belt. So the first-object-layer adhesion features (the tree // support brim, the hybrid first-layer base expansion) must be suppressed: @@ -2201,7 +2203,7 @@ void TreeSupport::draw_circles() size_t first_base_roof_area = 0; bool floor_interface_as_base = false; bool has_circle_node = false; - bool need_extra_wall = false; + ExPolygons extra_wall_areas; ExPolygons collision_sharp_tails; ExPolygons collision_base; auto get_collision = [&](bool sharp_tail) -> ExPolygons &{ @@ -2279,7 +2281,6 @@ void TreeSupport::draw_circles() // area = diff_clipped({ ExPolygon(circle) }, get_collision(node.is_sharp_tail && node.distance_to_top <= 0)); if (!area.empty()) has_circle_node = true; - if (node.need_extra_wall) need_extra_wall = true; // merge overhang to get a smoother interface surface // Do not merge when buildplate_only is on, because some underneath nodes may have been deleted. @@ -2294,6 +2295,10 @@ void TreeSupport::draw_circles() } } + // Use the Pythagorean theorem to compare movement magnitude (dx² + dy²) without a square root. + if (node.is_processed && node.movement.cast().squaredNorm() > max_move_sq) + append(extra_wall_areas, area); + if (obj_layer_nr>0 && node.distance_to_top < 0) append(roof_gap_areas, area); else if (obj_layer_nr > 0 && node.support_roof_layers_below == 1 && @@ -2530,7 +2535,8 @@ void TreeSupport::draw_circles() //if (area(expoly) < SQ(scale_(1))) continue; area_groups.emplace_back(&expoly, SupportLayer::BaseType, max_layers_above_base); area_groups.back().need_infill = overlaps({ expoly }, area_poly); - area_groups.back().need_extra_wall = need_extra_wall && !area_groups.back().need_infill; + area_groups.back().need_extra_wall = !area_groups.back().need_infill && + !extra_wall_areas.empty() && overlaps({expoly}, extra_wall_areas); } for (size_t roof_idx = 0; roof_idx < ts_layer->roof_areas.size(); ++roof_idx) { auto &expoly = ts_layer->roof_areas[roof_idx]; @@ -3433,11 +3439,6 @@ void TreeSupport::smooth_nodes() } } - float max_move = scale_(m_object_config->support_line_width / 2); - // if the branch is very tall, the tip also needs extra wall - float thresh_tall_branch = 100; - float thresh_dist_to_top = 30; - for (int layer_nr = 0; layer_nr< contact_nodes.size(); layer_nr++) { std::vector &curr_layer_nodes = contact_nodes[layer_nr]; if (curr_layer_nodes.empty()) continue; @@ -3447,20 +3448,17 @@ void TreeSupport::smooth_nodes() std::vector radii; std::vector branch; SupportNode * p_node = node; - float total_height = 0; // add a fixed head if it's not a polygon node, see STUDIO-4403 // Polygon node can't be added because the move distance might be huge, making the nodes in between jump and dangling if (node->child && node->child->type!=ePolygon) { pts.push_back(p_node->child->position); radii.push_back(p_node->child->radius); branch.push_back(p_node->child); - total_height += p_node->child->height; } do { pts.push_back(p_node->position); radii.push_back(p_node->radius); branch.push_back(p_node); - total_height += p_node->height; p_node = p_node->parent; } while (p_node && !p_node->is_processed); if (pts.size() < 3) continue; @@ -3479,9 +3477,6 @@ void TreeSupport::smooth_nodes() branch[i]->radius = radii1[i]; branch[i]->movement = (pts[i + 1] - pts[i - 1]) / 2; branch[i]->is_processed = true; - if (branch[i]->parents.size() > 1 || (branch[i]->movement.x() > max_move || branch[i]->movement.y() > max_move) || - (total_height > thresh_tall_branch && branch[i]->dist_mm_to_top < thresh_dist_to_top)) - branch[i]->need_extra_wall = true; BOOST_LOG_TRIVIAL(info) << "smooth_nodes: layer_nr=" << layer_nr << ", i=" << i << ", pt=" << pt << ", movement=" << branch[i]->movement << ", radius=" << branch[i]->radius; } } @@ -3489,13 +3484,6 @@ void TreeSupport::smooth_nodes() std::swap(pts, pts1); std::swap(radii, radii1); } - else { - // interpolate need_extra_wall in the end - for (size_t i = 1; i < branch.size() - 1; i++) { - if (branch[i - 1]->need_extra_wall && branch[i + 1]->need_extra_wall) - branch[i]->need_extra_wall = true; - } - } } } } diff --git a/src/libslic3r/Support/TreeSupport.hpp b/src/libslic3r/Support/TreeSupport.hpp index d8bb241fee..e6f651077f 100644 --- a/src/libslic3r/Support/TreeSupport.hpp +++ b/src/libslic3r/Support/TreeSupport.hpp @@ -135,7 +135,6 @@ struct SupportNode TreeNodeType type = eCircle; bool is_corner = false; bool is_processed = false; - bool need_extra_wall = false; bool is_sharp_tail = false; bool valid = true; ExPolygon overhang; // when type==ePolygon, set this value to get original overhang area