ENH: improve tree support and fix a bug

1. use tree slim's merge strategy in hybrid support
2. do not break bridge in hybrid support
3. fix "support on buildplate only" not working. The cause is: with
   independent support layer height, contact_nodes are not synced with
   object layers, so the previous way of accessing contact nodes in
   unsupported_branch_leaves no longer works. To fix that, we add
   obj_layer_nr.
   Jira: STUDIO-2250

Change-Id: Idfc9b0bb10425de6414f7eae2cf5467cedf1d669
(cherry picked from commit 8780d5a7e92e298cbbccbb3bd1825197d387a340)
This commit is contained in:
Arthur 2023-02-15 14:20:31 +08:00 committed by Lane.Wei
parent 5df5cb9ff4
commit bf8f163b5a
2 changed files with 23 additions and 19 deletions

View File

@ -701,7 +701,7 @@ TreeSupport::TreeSupport(PrintObject& object, const SlicingParameters &slicing_p
m_support_params.support_extrusion_width = m_object_config->support_line_width.value > 0 ? m_object_config->support_line_width : m_object_config->line_width; m_support_params.support_extrusion_width = m_object_config->support_line_width.value > 0 ? m_object_config->support_line_width : m_object_config->line_width;
support_type = m_object_config->support_type; support_type = m_object_config->support_type;
is_slim = is_tree_slim(support_type, m_object_config->support_style); is_slim = is_tree_slim(support_type, m_object_config->support_style);
MAX_BRANCH_RADIUS = is_slim ? 5.0 : 10.0; MAX_BRANCH_RADIUS = 10.0;
tree_support_branch_diameter_angle = 5.0;//is_slim ? 10.0 : 5.0; tree_support_branch_diameter_angle = 5.0;//is_slim ? 10.0 : 5.0;
// 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;
@ -1005,8 +1005,10 @@ void TreeSupport::detect_overhangs()
} }
if (bridge_no_support && overhang_areas.size()>0) { if (max_bridge_length > 0 && overhang_areas.size()>0) {
m_object->remove_bridges_from_contacts(lower_layer, layer, extrusion_width_scaled, &overhang_areas, max_bridge_length, true); // do not break bridge for normal part in TreeHybrid
bool break_bridge = !(config.support_style == smsTreeHybrid && area(overhang_areas) > m_support_params.thresh_big_overhang);
m_object->remove_bridges_from_contacts(lower_layer, layer, extrusion_width_scaled, &overhang_areas, max_bridge_length, break_bridge);
} }
SupportLayer* ts_layer = m_object->get_support_layer(layer_nr + m_raft_layers); SupportLayer* ts_layer = m_object->get_support_layer(layer_nr + m_raft_layers);
@ -2641,7 +2643,7 @@ void TreeSupport::drop_nodes(std::vector<std::vector<Node*>>& contact_nodes)
if (node.distance_to_top < 0) { if (node.distance_to_top < 0) {
// gap nodes do not merge or move // gap nodes do not merge or move
Node* next_node = new Node(p_node->position, p_node->distance_to_top + 1, p_node->skin_direction, p_node->support_roof_layers_below - 1, p_node->to_buildplate, p_node, Node* next_node = new Node(p_node->position, p_node->distance_to_top + 1, layer_nr_next, p_node->support_roof_layers_below - 1, p_node->to_buildplate, p_node,
print_z_next, height_next); print_z_next, height_next);
get_max_move_dist(next_node); get_max_move_dist(next_node);
next_node->is_merged = false; next_node->is_merged = false;
@ -2776,7 +2778,7 @@ void TreeSupport::drop_nodes(std::vector<std::vector<Node*>>& contact_nodes)
parent = neighbour->parent; parent = neighbour->parent;
const bool to_buildplate = !is_inside_ex(m_ts_data->get_avoidance(0, layer_nr_next), next_position); const bool to_buildplate = !is_inside_ex(m_ts_data->get_avoidance(0, layer_nr_next), next_position);
Node * next_node = new Node(next_position, new_distance_to_top, node.skin_direction, new_support_roof_layers_below, to_buildplate, p_node, Node * next_node = new Node(next_position, new_distance_to_top, layer_nr_next, new_support_roof_layers_below, to_buildplate, p_node,
print_z_next, height_next, new_dist_mm_to_top); print_z_next, height_next, new_dist_mm_to_top);
next_node->movement = next_position - node.position; next_node->movement = next_position - node.position;
get_max_move_dist(next_node); get_max_move_dist(next_node);
@ -2822,7 +2824,7 @@ void TreeSupport::drop_nodes(std::vector<std::vector<Node*>>& contact_nodes)
if (node.type == ePolygon) { if (node.type == ePolygon) {
// polygon node do not merge or move // polygon node do not merge or move
const bool to_buildplate = !is_inside_ex(m_ts_data->m_layer_outlines[layer_nr], p_node->position); const bool to_buildplate = !is_inside_ex(m_ts_data->m_layer_outlines[layer_nr], p_node->position);
Node * next_node = new Node(p_node->position, p_node->distance_to_top + 1, p_node->skin_direction, p_node->support_roof_layers_below - 1, to_buildplate, Node * next_node = new Node(p_node->position, p_node->distance_to_top + 1, layer_nr_next, p_node->support_roof_layers_below - 1, to_buildplate,
p_node, print_z_next, height_next); p_node, print_z_next, height_next);
next_node->max_move_dist = 0; next_node->max_move_dist = 0;
next_node->is_merged = false; next_node->is_merged = false;
@ -2889,13 +2891,13 @@ void TreeSupport::drop_nodes(std::vector<std::vector<Node*>>& contact_nodes)
if (is_line_cut_by_contour(node.position, neighbour)) continue; if (is_line_cut_by_contour(node.position, neighbour)) continue;
if (is_slim) if (/*is_slim*/1)
sum_direction += direction * (1 / dist2_to_neighbor); sum_direction += direction * (1 / dist2_to_neighbor);
else else
sum_direction += direction; sum_direction += direction;
} }
if (is_slim) if (/*is_slim*/1)
move_to_neighbor_center = sum_direction; move_to_neighbor_center = sum_direction;
else { else {
if (vsize2_with_unscale(sum_direction) <= max_move_distance2) { if (vsize2_with_unscale(sum_direction) <= max_move_distance2) {
@ -2966,7 +2968,7 @@ void TreeSupport::drop_nodes(std::vector<std::vector<Node*>>& contact_nodes)
} }
const bool to_buildplate = !is_inside_ex(m_ts_data->m_layer_outlines[layer_nr], next_layer_vertex);// !is_inside_ex(m_ts_data->get_avoidance(m_ts_data->m_xy_distance, layer_nr - 1), next_layer_vertex); const bool to_buildplate = !is_inside_ex(m_ts_data->m_layer_outlines[layer_nr], next_layer_vertex);// !is_inside_ex(m_ts_data->get_avoidance(m_ts_data->m_xy_distance, layer_nr - 1), next_layer_vertex);
Node * next_node = new Node(next_layer_vertex, node.distance_to_top + 1, node.skin_direction, node.support_roof_layers_below - 1, to_buildplate, p_node, Node * next_node = new Node(next_layer_vertex, node.distance_to_top + 1, layer_nr_next, node.support_roof_layers_below - 1, to_buildplate, p_node,
print_z_next, height_next); print_z_next, height_next);
next_node->movement = movement; next_node->movement = movement;
get_max_move_dist(next_node); get_max_move_dist(next_node);
@ -2995,8 +2997,9 @@ void TreeSupport::drop_nodes(std::vector<std::vector<Node*>>& contact_nodes)
{ {
const auto& entry = unsupported_branch_leaves.back(); const auto& entry = unsupported_branch_leaves.back();
Node* i_node = entry.second; Node* i_node = entry.second;
for (size_t i_layer = entry.first; i_node != nullptr; ++i_layer, i_node = i_node->parent) for (; i_node != nullptr; i_node = i_node->parent)
{ {
size_t i_layer = i_node->obj_layer_nr;
std::vector<Node*>::iterator to_erase = std::find(contact_nodes[i_layer].begin(), contact_nodes[i_layer].end(), i_node); std::vector<Node*>::iterator to_erase = std::find(contact_nodes[i_layer].begin(), contact_nodes[i_layer].end(), i_node);
if (to_erase != contact_nodes[i_layer].end()) if (to_erase != contact_nodes[i_layer].end())
{ {
@ -3332,7 +3335,6 @@ void TreeSupport::generate_contact_points(std::vector<std::vector<TreeSupport::N
BoundingBox bounding_box = m_object->bounding_box(); BoundingBox bounding_box = m_object->bounding_box();
const Point bounding_box_size = bounding_box.max - bounding_box.min; const Point bounding_box_size = bounding_box.max - bounding_box.min;
constexpr double rotate_angle = 22.0 / 180.0 * M_PI; constexpr double rotate_angle = 22.0 / 180.0 * M_PI;
constexpr double thresh_big_overhang = SQ(scale_(10));
const auto center = bounding_box_middle(bounding_box); const auto center = bounding_box_middle(bounding_box);
const auto sin_angle = std::sin(rotate_angle); const auto sin_angle = std::sin(rotate_angle);
@ -3392,11 +3394,11 @@ void TreeSupport::generate_contact_points(std::vector<std::vector<TreeSupport::N
for (const ExPolygon &overhang_part : overhang) for (const ExPolygon &overhang_part : overhang)
{ {
BoundingBox overhang_bounds = get_extents(overhang_part); BoundingBox overhang_bounds = get_extents(overhang_part);
if (config.support_style.value==smsTreeHybrid && overhang_part.area() > thresh_big_overhang) { if (config.support_style.value==smsTreeHybrid && overhang_part.area() > m_support_params.thresh_big_overhang) {
Point candidate = overhang_bounds.center(); Point candidate = overhang_bounds.center();
if (!overhang_part.contains(candidate)) if (!overhang_part.contains(candidate))
move_inside_expoly(overhang_part, candidate); move_inside_expoly(overhang_part, candidate);
Node *contact_node = new Node(candidate, -z_distance_top_layers, (layer_nr) % 2, support_roof_layers + z_distance_top_layers, true, Node::NO_PARENT, print_z, Node *contact_node = new Node(candidate, -z_distance_top_layers, layer_nr, support_roof_layers + z_distance_top_layers, true, Node::NO_PARENT, print_z,
height, z_distance_top); height, z_distance_top);
contact_node->type = ePolygon; contact_node->type = ePolygon;
contact_node->overhang = &overhang_part; contact_node->overhang = &overhang_part;
@ -3424,7 +3426,7 @@ void TreeSupport::generate_contact_points(std::vector<std::vector<TreeSupport::N
//if (!is_inside_ex(m_ts_data->get_collision(0, layer_nr), candidate)) //if (!is_inside_ex(m_ts_data->get_collision(0, layer_nr), candidate))
{ {
constexpr bool to_buildplate = true; constexpr bool to_buildplate = true;
Node * contact_node = new Node(candidate, -z_distance_top_layers, (layer_nr) % 2, support_roof_layers + z_distance_top_layers, to_buildplate, Node * contact_node = new Node(candidate, -z_distance_top_layers, layer_nr, support_roof_layers + z_distance_top_layers, to_buildplate,
Node::NO_PARENT, print_z, height, z_distance_top); Node::NO_PARENT, print_z, height, z_distance_top);
contact_node->overhang = &overhang_part; contact_node->overhang = &overhang_part;
curr_nodes.emplace_back(contact_node); curr_nodes.emplace_back(contact_node);
@ -3447,7 +3449,7 @@ void TreeSupport::generate_contact_points(std::vector<std::vector<TreeSupport::N
if (!overhang_part.contains(candidate)) if (!overhang_part.contains(candidate))
move_inside_expoly(overhang_part, candidate); move_inside_expoly(overhang_part, candidate);
constexpr bool to_buildplate = true; constexpr bool to_buildplate = true;
Node *contact_node = new Node(candidate, -z_distance_top_layers, layer_nr % 2, support_roof_layers + z_distance_top_layers, to_buildplate, Node::NO_PARENT, Node *contact_node = new Node(candidate, -z_distance_top_layers, layer_nr, support_roof_layers + z_distance_top_layers, to_buildplate, Node::NO_PARENT,
print_z, height, z_distance_top); print_z, height, z_distance_top);
contact_node->overhang = &overhang_part; contact_node->overhang = &overhang_part;
curr_nodes.emplace_back(contact_node); curr_nodes.emplace_back(contact_node);
@ -3462,7 +3464,7 @@ void TreeSupport::generate_contact_points(std::vector<std::vector<TreeSupport::N
auto v1 = (pt - points[(i - 1 + nSize) % nSize]).cast<double>().normalized(); auto v1 = (pt - points[(i - 1 + nSize) % nSize]).cast<double>().normalized();
auto v2 = (pt - points[(i + 1) % nSize]).cast<double>().normalized(); auto v2 = (pt - points[(i + 1) % nSize]).cast<double>().normalized();
if (v1.dot(v2) > -0.7) { // angle smaller than 135 degrees if (v1.dot(v2) > -0.7) { // angle smaller than 135 degrees
Node *contact_node = new Node(pt, -z_distance_top_layers, layer_nr % 2, support_roof_layers + z_distance_top_layers, true, Node::NO_PARENT, print_z, Node *contact_node = new Node(pt, -z_distance_top_layers, layer_nr, support_roof_layers + z_distance_top_layers, true, Node::NO_PARENT, print_z,
height, z_distance_top); height, z_distance_top);
contact_node->overhang = &overhang_part; contact_node->overhang = &overhang_part;
contact_node->is_corner = true; contact_node->is_corner = true;

View File

@ -221,7 +221,7 @@ public:
Node() Node()
: distance_to_top(0) : distance_to_top(0)
, position(Point(0, 0)) , position(Point(0, 0))
, skin_direction(false) , obj_layer_nr(0)
, support_roof_layers_below(0) , support_roof_layers_below(0)
, support_floor_layers_above(0) , support_floor_layers_above(0)
, to_buildplate(true) , to_buildplate(true)
@ -230,11 +230,11 @@ public:
, height(0.0) , height(0.0)
{} {}
Node(const Point position, const int distance_to_top, const bool skin_direction, const int support_roof_layers_below, const bool to_buildplate, Node* parent, Node(const Point position, const int distance_to_top, const int obj_layer_nr, const int support_roof_layers_below, const bool to_buildplate, Node* parent,
coordf_t print_z_, coordf_t height_, coordf_t dist_mm_to_top_=0) coordf_t print_z_, coordf_t height_, coordf_t dist_mm_to_top_=0)
: distance_to_top(distance_to_top) : distance_to_top(distance_to_top)
, position(position) , position(position)
, skin_direction(skin_direction) , obj_layer_nr(obj_layer_nr)
, support_roof_layers_below(support_roof_layers_below) , support_roof_layers_below(support_roof_layers_below)
, support_floor_layers_above(0) , support_floor_layers_above(0)
, to_buildplate(to_buildplate) , to_buildplate(to_buildplate)
@ -298,6 +298,7 @@ public:
*/ */
int support_roof_layers_below; int support_roof_layers_below;
int support_floor_layers_above; int support_floor_layers_above;
int obj_layer_nr;
/*! /*!
* \brief Whether to try to go towards the build plate. * \brief Whether to try to go towards the build plate.
@ -362,6 +363,7 @@ public:
InfillPattern interface_fill_pattern; InfillPattern interface_fill_pattern;
InfillPattern contact_fill_pattern; InfillPattern contact_fill_pattern;
bool with_sheath; bool with_sheath;
const double thresh_big_overhang = SQ(scale_(10));
}; };
int avg_node_per_layer = 0; int avg_node_per_layer = 0;