ENH: improve tree supports

1. speedup organic tree support by using parallel for intersection of bed area
jira: STUDIO-8451
2. add extra wall for hybrid tree support's tall branches
3. disable circle fitting for tree support. This feature produces inconsistent
   circles for tree supports.
4. expose the option tree_support_branch_diameter_angle. Tree supports'
   strength can be improved by increasing this value.

Change-Id: If3688ca895df98a77f6ca538077daf8fe94e53f1
This commit is contained in:
Arthur 2024-10-15 14:48:31 +08:00 committed by Lane.Wei
parent abed638cb3
commit 7697eb3dc8
13 changed files with 81 additions and 125 deletions

View File

@ -835,8 +835,8 @@ static std::vector<std::string> s_Preset_print_options {
"wipe_tower_no_sparse_layers", "compatible_printers", "compatible_printers_condition", "inherits", "wipe_tower_no_sparse_layers", "compatible_printers", "compatible_printers_condition", "inherits",
"flush_into_infill", "flush_into_objects", "flush_into_support","process_notes", "flush_into_infill", "flush_into_objects", "flush_into_support","process_notes",
// BBS // BBS
"tree_support_branch_angle", "tree_support_wall_count", "tree_support_branch_distance", "tree_support_branch_angle", "tree_support_wall_count", "tree_support_branch_distance", "tree_support_branch_diameter",
"tree_support_branch_diameter", "tree_support_branch_diameter_angle",
"detect_narrow_internal_solid_infill", "detect_narrow_internal_solid_infill",
"gcode_add_line_number", "enable_arc_fitting", "precise_z_height", "infill_combination", /*"adaptive_layer_height",*/ "gcode_add_line_number", "enable_arc_fitting", "precise_z_height", "infill_combination", /*"adaptive_layer_height",*/
"support_bottom_interface_spacing", "enable_overhang_speed", "overhang_1_4_speed", "overhang_2_4_speed", "overhang_3_4_speed", "overhang_4_4_speed", "overhang_totally_speed", "support_bottom_interface_spacing", "enable_overhang_speed", "overhang_1_4_speed", "overhang_2_4_speed", "overhang_3_4_speed", "overhang_4_4_speed", "overhang_totally_speed",

View File

@ -3587,7 +3587,7 @@ void PrintConfigDef::init_fff_params()
def->set_default_value(new ConfigOptionInt(30)); def->set_default_value(new ConfigOptionInt(30));
def = this->add("tree_support_branch_angle", coFloat); def = this->add("tree_support_branch_angle", coFloat);
def->label = L("Tree support branch angle"); def->label = L("Branch angle");
def->category = L("Support"); def->category = L("Support");
def->tooltip = L("This setting determines the maximum overhang angle that t he branches of tree support allowed to make." def->tooltip = L("This setting determines the maximum overhang angle that t he branches of tree support allowed to make."
"If the angle is increased, the branches can be printed more horizontally, allowing them to reach farther."); "If the angle is increased, the branches can be printed more horizontally, allowing them to reach farther.");
@ -3598,7 +3598,7 @@ void PrintConfigDef::init_fff_params()
def->set_default_value(new ConfigOptionFloat(40.)); def->set_default_value(new ConfigOptionFloat(40.));
def = this->add("tree_support_branch_distance", coFloat); def = this->add("tree_support_branch_distance", coFloat);
def->label = L("Tree support branch distance"); def->label = L("Branch distance");
def->category = L("Support"); def->category = L("Support");
def->tooltip = L("This setting determines the distance between neighboring tree support nodes."); def->tooltip = L("This setting determines the distance between neighboring tree support nodes.");
def->sidetext = L("mm"); def->sidetext = L("mm");
@ -3608,7 +3608,7 @@ void PrintConfigDef::init_fff_params()
def->set_default_value(new ConfigOptionFloat(5.)); def->set_default_value(new ConfigOptionFloat(5.));
def = this->add("tree_support_branch_diameter", coFloat); def = this->add("tree_support_branch_diameter", coFloat);
def->label = L("Tree support branch diameter"); def->label = L("Branch diameter");
def->category = L("Support"); def->category = L("Support");
def->tooltip = L("This setting determines the initial diameter of support nodes."); def->tooltip = L("This setting determines the initial diameter of support nodes.");
def->sidetext = L("mm"); def->sidetext = L("mm");
@ -3617,6 +3617,18 @@ void PrintConfigDef::init_fff_params()
def->mode = comAdvanced; def->mode = comAdvanced;
def->set_default_value(new ConfigOptionFloat(5.)); def->set_default_value(new ConfigOptionFloat(5.));
def = this->add("tree_support_branch_diameter_angle", coFloat);
def->label = L("Branch diameter angle");
def->category = L("Support");
def->tooltip = L("The angle of the branches' diameter as they gradually become thicker towards the bottom. "
"An angle of 0 will cause the branches to have uniform thickness over their length. "
"A bit of an angle can increase stability of the tree support.");
def->sidetext = L("°");
def->min = 0.0;
def->max = 15;
def->mode = comAdvanced;
def->set_default_value(new ConfigOptionFloat(5.));
def = this->add("tree_support_wall_count", coInt); def = this->add("tree_support_wall_count", coInt);
def->label = L("Support wall loops"); def->label = L("Support wall loops");
def->category = L("Support"); def->category = L("Support");

View File

@ -768,6 +768,7 @@ PRINT_CONFIG_CLASS_DEFINE(
((ConfigOptionFloat, tree_support_branch_distance)) ((ConfigOptionFloat, tree_support_branch_distance))
((ConfigOptionFloat, tree_support_branch_diameter)) ((ConfigOptionFloat, tree_support_branch_diameter))
((ConfigOptionFloat, tree_support_branch_angle)) ((ConfigOptionFloat, tree_support_branch_angle))
((ConfigOptionFloat, tree_support_branch_diameter_angle))
((ConfigOptionInt, tree_support_wall_count)) ((ConfigOptionInt, tree_support_wall_count))
((ConfigOptionBool, detect_narrow_internal_solid_infill)) ((ConfigOptionBool, detect_narrow_internal_solid_infill))
// ((ConfigOptionBool, adaptive_layer_height)) // ((ConfigOptionBool, adaptive_layer_height))

View File

@ -538,7 +538,8 @@ void PrintObject::simplify_extrusion_path()
} }
if (this->set_started(posSimplifySupportPath)) { if (this->set_started(posSimplifySupportPath)) {
//BBS: share same progress //BBS: disable circle simplification for support as it causes separation of support walls
#if 0
m_print->set_status(75, L("Optimizing toolpath")); m_print->set_status(75, L("Optimizing toolpath"));
BOOST_LOG_TRIVIAL(debug) << "Simplify extrusion path of support in parallel - start"; BOOST_LOG_TRIVIAL(debug) << "Simplify extrusion path of support in parallel - start";
tbb::parallel_for( tbb::parallel_for(
@ -552,6 +553,7 @@ void PrintObject::simplify_extrusion_path()
); );
m_print->throw_if_canceled(); m_print->throw_if_canceled();
BOOST_LOG_TRIVIAL(debug) << "Simplify extrusion path of support in parallel - end"; BOOST_LOG_TRIVIAL(debug) << "Simplify extrusion path of support in parallel - end";
#endif
this->set_done(posSimplifySupportPath); this->set_done(posSimplifySupportPath);
} }
} }
@ -791,6 +793,7 @@ bool PrintObject::invalidate_state_by_config_options(
|| opt_key == "tree_support_branch_distance" || opt_key == "tree_support_branch_distance"
|| opt_key == "tree_support_branch_diameter" || opt_key == "tree_support_branch_diameter"
|| opt_key == "tree_support_branch_angle" || opt_key == "tree_support_branch_angle"
|| opt_key == "tree_support_branch_diameter_angle"
|| opt_key == "tree_support_wall_count") { || opt_key == "tree_support_wall_count") {
steps.emplace_back(posSupportMaterial); steps.emplace_back(posSupportMaterial);
} else if ( } else if (
@ -3503,90 +3506,8 @@ template void PrintObject::remove_bridges_from_contacts<Polygons>(
SupportNecessaryType PrintObject::is_support_necessary() SupportNecessaryType PrintObject::is_support_necessary()
{ {
static const double super_overhang_area_threshold = SQ(scale_(5.0));
const double cantilevel_dist_thresh = scale_(6); const double cantilevel_dist_thresh = scale_(6);
#if 0
double threshold_rad = (m_config.support_threshold_angle.value < EPSILON ? 30 : m_config.support_threshold_angle.value + 1) * M_PI / 180.;
int enforce_support_layers = m_config.enforce_support_layers;
const coordf_t extrusion_width = m_config.line_width.value;
const coordf_t extrusion_width_scaled = scale_(extrusion_width);
float max_bridge_length = scale_(m_config.max_bridge_length.value);
const bool bridge_no_support = max_bridge_length > 0;// config.bridge_no_support.value;
for (size_t layer_nr = enforce_support_layers + 1; layer_nr < this->layer_count(); layer_nr++) {
Layer* layer = m_layers[layer_nr];
Layer* lower_layer = layer->lower_layer;
coordf_t support_offset_scaled = extrusion_width_scaled * 0.9;
ExPolygons lower_layer_offseted = offset_ex(lower_layer->lslices, support_offset_scaled, SUPPORT_SURFACES_OFFSET_PARAMETERS);
// 1. check sharp tail
for (const LayerRegion* layerm : layer->regions()) {
for (const ExPolygon& expoly : layerm->raw_slices) {
// detect sharp tail
if (intersection_ex({ expoly }, lower_layer_offseted).empty())
return SharpTail;
}
}
// 2. check overhang area
ExPolygons super_overhang_expolys = std::move(diff_ex(layer->lslices, lower_layer_offseted));
super_overhang_expolys.erase(std::remove_if(
super_overhang_expolys.begin(),
super_overhang_expolys.end(),
[extrusion_width_scaled](ExPolygon& area) {
return offset_ex(area, -0.1 * extrusion_width_scaled).empty();
}),
super_overhang_expolys.end());
// remove bridge
if (bridge_no_support)
remove_bridges_from_contacts(lower_layer, layer, extrusion_width_scaled, &super_overhang_expolys, max_bridge_length);
Polygons super_overhang_polys = to_polygons(super_overhang_expolys);
super_overhang_polys.erase(std::remove_if(
super_overhang_polys.begin(),
super_overhang_polys.end(),
[extrusion_width_scaled](Polygon& area) {
return offset_ex(area, -0.1 * extrusion_width_scaled).empty();
}),
super_overhang_polys.end());
double super_overhang_area = 0.0;
for (Polygon& poly : super_overhang_polys) {
bool is_ccw = poly.is_counter_clockwise();
double area_ = poly.area();
if (is_ccw) {
if (area_ > super_overhang_area_threshold)
return LargeOverhang;
super_overhang_area += area_;
}
else {
super_overhang_area -= area_;
}
}
//if (super_overhang_area > super_overhang_area_threshold)
// return LargeOverhang;
// 3. check overhang distance
const double distance_threshold_scaled = extrusion_width_scaled * 2;
ExPolygons lower_layer_offseted_2 = offset_ex(lower_layer->lslices, distance_threshold_scaled, SUPPORT_SURFACES_OFFSET_PARAMETERS);
ExPolygons exceed_overhang = std::move(diff_ex(super_overhang_polys, lower_layer_offseted_2));
exceed_overhang.erase(std::remove_if(
exceed_overhang.begin(),
exceed_overhang.end(),
[extrusion_width_scaled](ExPolygon& area) {
// tolerance for 1 extrusion width offset
return offset_ex(area, -0.5 * extrusion_width_scaled).empty();
}),
exceed_overhang.end());
if (!exceed_overhang.empty())
return LargeOverhang;
}
#else
TreeSupport tree_support(*this, m_slicing_params); TreeSupport tree_support(*this, m_slicing_params);
tree_support.support_type = SupportType::stTreeAuto; // need to set support type to fully utilize the power of feature detection tree_support.support_type = SupportType::stTreeAuto; // need to set support type to fully utilize the power of feature detection
tree_support.detect_overhangs(true); tree_support.detect_overhangs(true);
@ -3595,7 +3516,7 @@ SupportNecessaryType PrintObject::is_support_necessary()
return SharpTail; return SharpTail;
else if (tree_support.has_cantilever && tree_support.max_cantilever_dist > cantilevel_dist_thresh) else if (tree_support.has_cantilever && tree_support.max_cantilever_dist > cantilevel_dist_thresh)
return Cantilever; return Cantilever;
#endif
return NoNeedSupp; return NoNeedSupp;
} }

View File

@ -65,8 +65,8 @@ std::pair<SupportGeneratorLayersPtr, SupportGeneratorLayersPtr> generate_interfa
if (! intermediate_layers.empty() && support_params.has_interfaces()) { if (! intermediate_layers.empty() && support_params.has_interfaces()) {
// For all intermediate layers, collect top contact surfaces, which are not further than support_material_interface_layers. // For all intermediate layers, collect top contact surfaces, which are not further than support_material_interface_layers.
BOOST_LOG_TRIVIAL(debug) << "PrintObjectSupportMaterial::generate_interface_layers() in parallel - start"; BOOST_LOG_TRIVIAL(debug) << "PrintObjectSupportMaterial::generate_interface_layers() in parallel - start";
const bool snug_supports = config.support_style.value == smsSnug; const bool snug_supports = support_params.support_style == smsSnug;
const bool smooth_supports = config.support_style.value != smsGrid; const bool smooth_supports = support_params.support_style != smsGrid;
SupportGeneratorLayersPtr &interface_layers = base_and_interface_layers.first; SupportGeneratorLayersPtr &interface_layers = base_and_interface_layers.first;
SupportGeneratorLayersPtr &base_interface_layers = base_and_interface_layers.second; SupportGeneratorLayersPtr &base_interface_layers = base_and_interface_layers.second;
@ -1351,6 +1351,10 @@ SupportGeneratorLayersPtr generate_support_layers(
append(layers_sorted, intermediate_layers); append(layers_sorted, intermediate_layers);
append(layers_sorted, interface_layers); append(layers_sorted, interface_layers);
append(layers_sorted, base_interface_layers); append(layers_sorted, base_interface_layers);
// remove dupliated layers
std::sort(layers_sorted.begin(), layers_sorted.end());
layers_sorted.erase(std::unique(layers_sorted.begin(), layers_sorted.end()), layers_sorted.end());
// Sort the layers lexicographically by a raising print_z and a decreasing height. // Sort the layers lexicographically by a raising print_z and a decreasing height.
std::sort(layers_sorted.begin(), layers_sorted.end(), [](auto *l1, auto *l2) { return *l1 < *l2; }); std::sort(layers_sorted.begin(), layers_sorted.end(), [](auto *l1, auto *l2) { return *l1 < *l2; });
int layer_id = 0; int layer_id = 0;
@ -1582,7 +1586,7 @@ void generate_support_toolpaths(
{ {
SupportLayer &support_layer = *support_layers[support_layer_id]; SupportLayer &support_layer = *support_layers[support_layer_id];
LayerCache &layer_cache = layer_caches[support_layer_id]; LayerCache &layer_cache = layer_caches[support_layer_id];
const float support_interface_angle = (config.support_style.value == smsGrid || config.support_interface_pattern == smipRectilinear) ? const float support_interface_angle = (support_params.support_style == smsGrid || config.support_interface_pattern == smipRectilinear) ?
support_params.interface_angle : support_params.raft_interface_angle(support_layer.interface_id()); support_params.interface_angle : support_params.raft_interface_angle(support_layer.interface_id());
// Find polygons with the same print_z. // Find polygons with the same print_z.
@ -1744,8 +1748,12 @@ void generate_support_toolpaths(
filler->link_max_length = coord_t(scale_(filler->spacing * link_max_length_factor / density)); filler->link_max_length = coord_t(scale_(filler->spacing * link_max_length_factor / density));
sheath = true; sheath = true;
no_sort = true; no_sort = true;
} else if (config.support_style == SupportMaterialStyle::smsTreeOrganic) { } else if (support_params.support_style == SupportMaterialStyle::smsTreeOrganic) {
tree_supports_generate_paths(base_layer.extrusions, base_layer.polygons_to_extrude(), flow, support_params); // if the tree supports are too tall, use 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);
done = true; done = true;
} }
if (! done) if (! done)

View File

@ -164,6 +164,17 @@ struct SupportParameters {
object_config.tree_support_wall_count.value == 0 ? 0.25 * sqr(scaled<double>(5.0)) * M_PI : object_config.tree_support_wall_count.value == 0 ? 0.25 * sqr(scaled<double>(5.0)) * M_PI :
std::numeric_limits<double>::max(); std::numeric_limits<double>::max();
support_style = object_config.support_style;
if (support_style == smsDefault) {
// organic support doesn't work with variable layer heights (including adaptive layer height and height range modifier, see #4313)
if (!object.has_variable_layer_heights) {
BOOST_LOG_TRIVIAL(warning) << "tree support default to organic support";
support_style = smsTreeOrganic;
} else {
BOOST_LOG_TRIVIAL(warning) << "tree support default to hybrid tree due to adaptive layer height";
support_style = smsTreeHybrid;
}
}
} }
// Both top / bottom contacts and interfaces are soluble. // Both top / bottom contacts and interfaces are soluble.
bool soluble_interface; bool soluble_interface;
@ -214,6 +225,7 @@ struct SupportParameters {
coordf_t raft_interface_density; coordf_t raft_interface_density;
coordf_t support_spacing; coordf_t support_spacing;
coordf_t support_density; coordf_t support_density;
SupportMaterialStyle support_style = smsDefault;
InfillPattern base_fill_pattern; InfillPattern base_fill_pattern;
InfillPattern interface_fill_pattern; InfillPattern interface_fill_pattern;

View File

@ -600,27 +600,16 @@ TreeSupport::TreeSupport(PrintObject& object, const SlicingParameters &slicing_p
m_print_config = &m_object->print()->config(); m_print_config = &m_object->print()->config();
m_raft_layers = slicing_params.base_raft_layers + slicing_params.interface_raft_layers; m_raft_layers = slicing_params.base_raft_layers + slicing_params.interface_raft_layers;
support_type = m_object_config->support_type; support_type = m_object_config->support_type;
support_style = m_object_config->support_style;
if (support_style == smsDefault) {
// organic support doesn't work with variable layer heights (including adaptive layer height and height range modifier, see #4313)
if (!m_object->has_variable_layer_heights) {
BOOST_LOG_TRIVIAL(warning) << "tree support default to organic support";
support_style = smsTreeOrganic;
}
else {
BOOST_LOG_TRIVIAL(warning) << "tree support default to hybrid tree due to adaptive layer height";
support_style = smsTreeHybrid;
}
}
SupportMaterialPattern support_pattern = m_object_config->support_base_pattern; SupportMaterialPattern support_pattern = m_object_config->support_base_pattern;
if (support_style == smsTreeHybrid && support_pattern == smpDefault) if (m_support_params.support_style == smsTreeHybrid && support_pattern == smpDefault)
support_pattern = smpRectilinear; support_pattern = smpRectilinear;
if(support_pattern == smpLightning) if(support_pattern == smpLightning)
m_support_params.base_fill_pattern = ipLightning; m_support_params.base_fill_pattern = ipLightning;
is_slim = is_tree_slim(support_type, support_style); is_slim = is_tree_slim(support_type, m_support_params.support_style);
is_strong = is_tree(support_type) && support_style == smsTreeStrong; is_strong = is_tree(support_type) && m_support_params.support_style == smsTreeStrong;
base_radius = std::max(MIN_BRANCH_RADIUS, m_object_config->tree_support_branch_diameter.value / 2); base_radius = std::max(MIN_BRANCH_RADIUS, m_object_config->tree_support_branch_diameter.value / 2);
// by default tree support needs no infill, unless it's tree hybrid which contains normal nodes. // by default tree support needs no infill, unless it's tree hybrid which contains normal nodes.
with_infill = support_pattern != smpNone && support_pattern != smpDefault; with_infill = support_pattern != smpNone && support_pattern != smpDefault;
@ -1546,7 +1535,10 @@ void TreeSupport::generate_toolpaths()
erSupportMaterial, filler_support.get(), support_density); erSupportMaterial, filler_support.get(), support_density);
} }
else { else {
tree_supports_generate_paths(ts_layer->support_fills.entities, loops, flow, m_support_params); SupportParameters support_params = m_support_params;
if (area_group.need_extra_wall && object_config.tree_support_wall_count.value == 0)
support_params.tree_branch_diameter_double_wall_area_scaled = 0.1;
tree_supports_generate_paths(ts_layer->support_fills.entities, loops, flow, support_params);
} }
} }
} }
@ -1652,7 +1644,7 @@ void TreeSupport::move_bounds_to_contact_nodes(std::vector<TreeSupport3D::Suppor
void TreeSupport::generate() void TreeSupport::generate()
{ {
if (support_style == smsTreeOrganic) { if (m_support_params.support_style == smsTreeOrganic) {
generate_tree_support_3D(*m_object, this, this->throw_on_cancel); generate_tree_support_3D(*m_object, this, this->throw_on_cancel);
return; return;
} }
@ -2984,6 +2976,10 @@ void TreeSupport::smooth_nodes()
} }
float max_move = scale_(m_object_config->support_line_width / 2); 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++) { for (int layer_nr = 0; layer_nr< contact_nodes.size(); layer_nr++) {
std::vector<SupportNode *> &curr_layer_nodes = contact_nodes[layer_nr]; std::vector<SupportNode *> &curr_layer_nodes = contact_nodes[layer_nr];
if (curr_layer_nodes.empty()) continue; if (curr_layer_nodes.empty()) continue;
@ -2993,17 +2989,20 @@ void TreeSupport::smooth_nodes()
std::vector<double> radii; std::vector<double> radii;
std::vector<SupportNode *> branch; std::vector<SupportNode *> branch;
SupportNode * p_node = node; SupportNode * p_node = node;
float total_height = 0;
// add a fixed head if it's not a polygon node, see STUDIO-4403 // 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 // 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) { if (node->child && node->child->type!=ePolygon) {
pts.push_back(p_node->child->position); pts.push_back(p_node->child->position);
radii.push_back(p_node->child->radius); radii.push_back(p_node->child->radius);
branch.push_back(p_node->child); branch.push_back(p_node->child);
total_height += p_node->child->height;
} }
do { do {
pts.push_back(p_node->position); pts.push_back(p_node->position);
radii.push_back(p_node->radius); radii.push_back(p_node->radius);
branch.push_back(p_node); branch.push_back(p_node);
total_height += p_node->height;
p_node = p_node->parent; p_node = p_node->parent;
} while (p_node && !p_node->is_processed); } while (p_node && !p_node->is_processed);
if (pts.size() < 3) continue; if (pts.size() < 3) continue;
@ -3022,7 +3021,8 @@ void TreeSupport::smooth_nodes()
branch[i]->radius = radii1[i]; branch[i]->radius = radii1[i];
branch[i]->movement = (pts[i + 1] - pts[i - 1]) / 2; branch[i]->movement = (pts[i + 1] - pts[i - 1]) / 2;
branch[i]->is_processed = true; branch[i]->is_processed = true;
if (branch[i]->parents.size()>1 || (branch[i]->movement.x() > max_move || branch[i]->movement.y() > max_move)) 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; branch[i]->need_extra_wall = true;
BOOST_LOG_TRIVIAL(trace) << "smooth_nodes: layer_nr=" << layer_nr << ", i=" << i << ", pt=" << pt << ", movement=" << branch[i]->movement << ", radius=" << branch[i]->radius; BOOST_LOG_TRIVIAL(trace) << "smooth_nodes: layer_nr=" << layer_nr << ", i=" << i << ", pt=" << pt << ", movement=" << branch[i]->movement << ", radius=" << branch[i]->radius;
} }
@ -3419,7 +3419,7 @@ void TreeSupport::generate_contact_points()
const auto& overhang_type = this->overhang_types[&overhang_part]; const auto& overhang_type = this->overhang_types[&overhang_part];
is_sharp_tail = overhang_type == OverhangType::SharpTail; is_sharp_tail = overhang_type == OverhangType::SharpTail;
ExPolygons overhangs_regular; ExPolygons overhangs_regular;
if (support_style == smsTreeHybrid && overhang_part.area() > m_support_params.thresh_big_overhang && !is_sharp_tail) { if (m_support_params.support_style == smsTreeHybrid && overhang_part.area() > m_support_params.thresh_big_overhang && !is_sharp_tail) {
overhangs_regular = offset_ex(intersection_ex({overhang_part}, m_ts_data->m_layer_outlines_below[layer_nr - 1]), radius_scaled); overhangs_regular = offset_ex(intersection_ex({overhang_part}, m_ts_data->m_layer_outlines_below[layer_nr - 1]), radius_scaled);
ExPolygons overhangs_normal = diff_ex({overhang_part}, overhangs_regular); ExPolygons overhangs_normal = diff_ex({overhang_part}, overhangs_regular);
if (area(overhangs_normal) > m_support_params.thresh_big_overhang) { if (area(overhangs_normal) > m_support_params.thresh_big_overhang) {

View File

@ -399,7 +399,6 @@ public:
bool has_cantilever = false; bool has_cantilever = false;
double max_cantilever_dist = 0; double max_cantilever_dist = 0;
SupportType support_type; SupportType support_type;
SupportMaterialStyle support_style;
std::unique_ptr<FillLightning::Generator> generator; std::unique_ptr<FillLightning::Generator> generator;
std::unordered_map<double, size_t> printZ_to_lightninglayer; std::unordered_map<double, size_t> printZ_to_lightninglayer;

View File

@ -37,6 +37,7 @@
#define TBB_PREVIEW_GLOBAL_CONTROL 1 #define TBB_PREVIEW_GLOBAL_CONTROL 1
#include <tbb/global_control.h> #include <tbb/global_control.h>
#include <tbb/parallel_for.h> #include <tbb/parallel_for.h>
#include <tbb/parallel_for_each.h>
#include <tbb/spin_mutex.h> #include <tbb/spin_mutex.h>
#if defined(TREE_SUPPORT_SHOW_ERRORS) && defined(_WIN32) #if defined(TREE_SUPPORT_SHOW_ERRORS) && defined(_WIN32)
@ -4332,15 +4333,17 @@ static void generate_support_areas(Print &print, TreeSupport* tree_support, cons
SupportGeneratorLayersPtr layers_sorted = generate_support_layers(print_object, raft_layers, bottom_contacts, top_contacts, intermediate_layers, interface_layers, base_interface_layers); SupportGeneratorLayersPtr layers_sorted = generate_support_layers(print_object, raft_layers, bottom_contacts, top_contacts, intermediate_layers, interface_layers, base_interface_layers);
// BBS: This is a hack to avoid the support being generated outside the bed area. See #4769. // BBS: This is a hack to avoid the support being generated outside the bed area. See #4769.
for (SupportGeneratorLayer *layer : layers_sorted) { tbb::parallel_for_each(layers_sorted.begin(), layers_sorted.end(), [&](SupportGeneratorLayer *layer) {
if (layer) layer->polygons = intersection(layer->polygons, volumes.m_bed_area); if (layer) layer->polygons = intersection(layer->polygons, volumes.m_bed_area);
} });
// Don't fill in the tree supports, make them hollow with just a single sheath line. // Don't fill in the tree supports, make them hollow with just a single sheath line.
print.set_status(69, _L("Generating support")); print.set_status(69, _L("Generating support"));
generate_support_toolpaths(print_object.support_layers(), print_object.config(), support_params, print_object.slicing_parameters(), generate_support_toolpaths(print_object.support_layers(), print_object.config(), support_params, print_object.slicing_parameters(),
raft_layers, bottom_contacts, top_contacts, intermediate_layers, interface_layers, base_interface_layers); raft_layers, bottom_contacts, top_contacts, intermediate_layers, interface_layers, base_interface_layers);
auto t_end = std::chrono::high_resolution_clock::now();
BOOST_LOG_TRIVIAL(info) << "Total time of organic tree support: " << 0.001 * std::chrono::duration_cast<std::chrono::microseconds>(t_end - t_start).count() << " ms";
#if 0 #if 0
//#ifdef SLIC3R_DEBUG //#ifdef SLIC3R_DEBUG
{ {

View File

@ -77,13 +77,12 @@ struct TreeSupportMeshGroupSettings {
this->support_wall_count = std::max(1, config.tree_support_wall_count.value); // at least 1 wall for organic tree support this->support_wall_count = std::max(1, config.tree_support_wall_count.value); // at least 1 wall for organic tree support
this->support_roof_line_distance = scaled<coord_t>(config.support_interface_spacing.value) + this->support_roof_line_width; this->support_roof_line_distance = scaled<coord_t>(config.support_interface_spacing.value) + this->support_roof_line_width;
double support_tree_angle_slow = 25;// TODO add a setting? double support_tree_angle_slow = 25;// TODO add a setting?
double support_tree_branch_diameter_angle = 5; // TODO add a setting?
double tree_support_tip_diameter = 0.8; double tree_support_tip_diameter = 0.8;
this->support_tree_branch_distance = scaled<coord_t>(config.tree_support_branch_distance.value); this->support_tree_branch_distance = scaled<coord_t>(config.tree_support_branch_distance.value);
this->support_tree_angle = std::clamp<double>(config.tree_support_branch_angle * M_PI / 180., 0., 0.5 * M_PI - EPSILON); this->support_tree_angle = std::clamp<double>(config.tree_support_branch_angle * M_PI / 180., 0., 0.5 * M_PI - EPSILON);
this->support_tree_angle_slow = std::clamp<double>(support_tree_angle_slow * M_PI / 180., 0., this->support_tree_angle - EPSILON); this->support_tree_angle_slow = std::clamp<double>(support_tree_angle_slow * M_PI / 180., 0., this->support_tree_angle - EPSILON);
this->support_tree_branch_diameter = scaled<coord_t>(config.tree_support_branch_diameter.value); this->support_tree_branch_diameter = scaled<coord_t>(config.tree_support_branch_diameter.value);
this->support_tree_branch_diameter_angle = std::clamp<double>(support_tree_branch_diameter_angle * M_PI / 180., 0., 0.5 * M_PI - EPSILON); this->support_tree_branch_diameter_angle = std::clamp<double>(config.tree_support_branch_diameter_angle * M_PI / 180., 0., 0.5 * M_PI - EPSILON);
this->support_tree_top_rate = 30; // percent this->support_tree_top_rate = 30; // percent
// this->support_tree_tip_diameter = this->support_line_width; // this->support_tree_tip_diameter = this->support_line_width;
this->support_tree_tip_diameter = std::clamp(scaled<coord_t>(tree_support_tip_diameter), 0, this->support_tree_branch_diameter); this->support_tree_tip_diameter = std::clamp(scaled<coord_t>(tree_support_tip_diameter), 0, this->support_tree_branch_diameter);

View File

@ -623,11 +623,11 @@ void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig *config, co
//toggle_field("support_closing_radius", have_support_material && support_style == smsSnug); //toggle_field("support_closing_radius", have_support_material && support_style == smsSnug);
bool support_is_tree = config->opt_bool("enable_support") && is_tree(support_type); bool support_is_tree = config->opt_bool("enable_support") && is_tree(support_type);
for (auto el : {"tree_support_branch_angle", "tree_support_branch_distance", "tree_support_branch_diameter"}) for (auto el : {"tree_support_branch_angle", "tree_support_branch_distance", "tree_support_branch_diameter", "tree_support_branch_diameter_angle"})
toggle_field(el, support_is_tree); toggle_field(el, support_is_tree);
// hide tree support settings when normal is selected // hide tree support settings when normal is selected
for (auto el : {"tree_support_branch_angle", "tree_support_branch_distance", "tree_support_branch_diameter", "max_bridge_length"}) for (auto el : {"tree_support_branch_angle", "tree_support_branch_distance", "tree_support_branch_diameter", "tree_support_branch_diameter_angle", "max_bridge_length"})
toggle_line(el, support_is_tree); toggle_line(el, support_is_tree);
toggle_line("support_critical_regions_only", is_auto(support_type) && support_is_tree); toggle_line("support_critical_regions_only", is_auto(support_type) && support_is_tree);

View File

@ -86,7 +86,7 @@ std::map<std::string, std::vector<SimpleSettingData>> SettingsFactory::OBJECT_C
{ L("Support"), {{"brim_type", "",1},{"brim_width", "",2},{"brim_object_gap", "",3}, { L("Support"), {{"brim_type", "",1},{"brim_width", "",2},{"brim_object_gap", "",3},
{"enable_support", "",4},{"support_type", "",5},{"support_threshold_angle", "",6},{"support_on_build_plate_only", "",7}, {"enable_support", "",4},{"support_type", "",5},{"support_threshold_angle", "",6},{"support_on_build_plate_only", "",7},
{"support_filament", "",8},{"support_interface_filament", "",9},{"support_expansion", "",24},{"support_style", "",25}, {"support_filament", "",8},{"support_interface_filament", "",9},{"support_expansion", "",24},{"support_style", "",25},
{"tree_support_branch_angle", "",10}, {"tree_support_wall_count", "",11},//tree support {"tree_support_branch_angle", "",10}, {"tree_support_wall_count", "",11},{"tree_support_branch_diameter_angle", "",11},//tree support
{"support_top_z_distance", "",13},{"support_bottom_z_distance", "",12},{"support_base_pattern", "",14},{"support_base_pattern_spacing", "",15}, {"support_top_z_distance", "",13},{"support_bottom_z_distance", "",12},{"support_base_pattern", "",14},{"support_base_pattern_spacing", "",15},
{"support_interface_top_layers", "",16},{"support_interface_bottom_layers", "",17},{"support_interface_spacing", "",18},{"support_bottom_interface_spacing", "",19}, {"support_interface_top_layers", "",16},{"support_interface_bottom_layers", "",17},{"support_interface_spacing", "",18},{"support_bottom_interface_spacing", "",19},
{"support_object_xy_distance", "",20}, {"bridge_no_support", "",21},{"max_bridge_length", "",22},{"support_critical_regions_only", "",23},{"support_remove_small_overhang","",27}, {"support_object_xy_distance", "",20}, {"bridge_no_support", "",21},{"max_bridge_length", "",22},{"support_critical_regions_only", "",23},{"support_remove_small_overhang","",27},

View File

@ -2104,13 +2104,14 @@ void TabPrint::build()
optgroup->append_single_option_line("support_object_xy_distance", "support"); optgroup->append_single_option_line("support_object_xy_distance", "support");
optgroup->append_single_option_line("support_object_first_layer_gap", "support"); optgroup->append_single_option_line("support_object_first_layer_gap", "support");
optgroup->append_single_option_line("bridge_no_support", "support#base-pattern"); optgroup->append_single_option_line("bridge_no_support", "support#base-pattern");
optgroup->append_single_option_line("max_bridge_length", "support#base-pattern"); optgroup->append_single_option_line("max_bridge_length", "support#tree-support-only-options");
optgroup->append_single_option_line("independent_support_layer_height", "support"); optgroup->append_single_option_line("independent_support_layer_height", "support");
optgroup = page->new_optgroup(L("Tree Support"), L"param_advanced"); optgroup = page->new_optgroup(L("Tree Support"), L"param_advanced");
optgroup->append_single_option_line("tree_support_branch_distance", "support#tree-support-only-options"); optgroup->append_single_option_line("tree_support_branch_distance", "support#tree-support-only-options");
optgroup->append_single_option_line("tree_support_branch_diameter", "support#tree-support-only-options"); optgroup->append_single_option_line("tree_support_branch_diameter", "support#tree-support-only-options");
optgroup->append_single_option_line("tree_support_branch_angle", "support#tree-support-only-options"); optgroup->append_single_option_line("tree_support_branch_angle", "support#tree-support-only-options");
optgroup->append_single_option_line("tree_support_branch_diameter_angle", "support#tree-support-only-options");
page = add_options_page(L("Others"), "advanced"); page = add_options_page(L("Others"), "advanced");
optgroup = page->new_optgroup(L("Bed adhension"), L"param_adhension"); optgroup = page->new_optgroup(L("Bed adhension"), L"param_adhension");