mirror of
https://github.com/SoftFever/OrcaSlicer.git
synced 2025-07-08 23:46:24 -06:00
ENH: [Tree Support] smooth_nodes and draw ellipse works
1. smooth nodes' positions 2. draw ellipse along movement direction 3. fix a bug of radius not smooth 4. fix a bug of Tree Strong having too large radius 5. fix a bug in plan_layer_heights: when wipe tower is enabled, independent_support_layer_height is false, and all support layers should be exactly the same as the object. Jira: STUDIO-1785 6. move support style popup message to on_value_change, so only show the popup when the user changes support type or style. Change-Id: Ibced7a28f436d96000ee35a7194b68bb5a20a32d (cherry picked from commit 0d814b07e433533c8de1b7a04bf52b577de0778d)
This commit is contained in:
parent
629e68f4a0
commit
3e7b5e7657
3 changed files with 75 additions and 61 deletions
|
@ -27,7 +27,7 @@
|
||||||
#define TAU (2.0 * M_PI)
|
#define TAU (2.0 * M_PI)
|
||||||
#define NO_INDEX (std::numeric_limits<unsigned int>::max())
|
#define NO_INDEX (std::numeric_limits<unsigned int>::max())
|
||||||
|
|
||||||
// #define SUPPORT_TREE_DEBUG_TO_SVG
|
//#define SUPPORT_TREE_DEBUG_TO_SVG
|
||||||
|
|
||||||
namespace Slic3r
|
namespace Slic3r
|
||||||
{
|
{
|
||||||
|
@ -1890,7 +1890,7 @@ void TreeSupport::generate_support_areas()
|
||||||
drop_nodes(contact_nodes);
|
drop_nodes(contact_nodes);
|
||||||
profiler.stage_finish(STAGE_DROP_DOWN_NODES);
|
profiler.stage_finish(STAGE_DROP_DOWN_NODES);
|
||||||
|
|
||||||
// smooth_nodes(contact_nodes);
|
smooth_nodes(contact_nodes);
|
||||||
|
|
||||||
#if !USE_PLAN_LAYER_HEIGHTS
|
#if !USE_PLAN_LAYER_HEIGHTS
|
||||||
// Adjust support layer heights
|
// Adjust support layer heights
|
||||||
|
@ -1943,20 +1943,24 @@ coordf_t TreeSupport::calc_branch_radius(coordf_t base_radius, size_t layers_to_
|
||||||
return radius;
|
return radius;
|
||||||
}
|
}
|
||||||
|
|
||||||
coordf_t TreeSupport::calc_branch_radius(coordf_t base_radius, coordf_t mm_to_top, double diameter_angle_scale_factor)
|
coordf_t TreeSupport::calc_branch_radius(coordf_t base_radius, coordf_t mm_to_top, double diameter_angle_scale_factor)
|
||||||
{
|
{
|
||||||
double radius;
|
double radius;
|
||||||
if (mm_to_top > base_radius)
|
coordf_t tip_height = base_radius;// this is a 45 degree tip
|
||||||
|
if (mm_to_top > tip_height)
|
||||||
{
|
{
|
||||||
radius = base_radius + mm_to_top * diameter_angle_scale_factor;
|
radius = base_radius + (mm_to_top-tip_height) * diameter_angle_scale_factor;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
radius = mm_to_top * diameter_angle_scale_factor;
|
radius = mm_to_top;// this is a 45 degree tip
|
||||||
}
|
}
|
||||||
|
|
||||||
radius = std::max(radius, MIN_BRANCH_RADIUS);
|
radius = std::max(radius, MIN_BRANCH_RADIUS);
|
||||||
radius = std::min(radius, MAX_BRANCH_RADIUS);
|
radius = std::min(radius, MAX_BRANCH_RADIUS);
|
||||||
|
// if have interface layers, radius should be larger
|
||||||
|
if (m_object_config->support_interface_top_layers.value > 0)
|
||||||
|
radius = std::max(radius, base_radius);
|
||||||
return radius;
|
return radius;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2093,14 +2097,9 @@ void TreeSupport::draw_circles(const std::vector<std::vector<Node*>>& contact_no
|
||||||
else {
|
else {
|
||||||
Polygon circle;
|
Polygon circle;
|
||||||
size_t layers_to_top = node.distance_to_top;
|
size_t layers_to_top = node.distance_to_top;
|
||||||
double scale;
|
double scale = calc_branch_radius(branch_radius, node.dist_mm_to_top, diameter_angle_scale_factor) / branch_radius;
|
||||||
if (top_interface_layers>0) { // if has interface, branch circles should be larger
|
|
||||||
scale = static_cast<double>(layers_to_top + 1) / tip_layers;
|
if (/*is_slim*/1) { // draw ellipse along movement direction
|
||||||
scale = layers_to_top < tip_layers ? (0.5 + scale / 2) : (1 + static_cast<double>(layers_to_top - tip_layers) * diameter_angle_scale_factor);
|
|
||||||
} else { // directly calc scale from the radius used in drop_nodes
|
|
||||||
scale = calc_branch_radius(branch_radius, node.dist_mm_to_top, diameter_angle_scale_factor) / branch_radius;
|
|
||||||
}
|
|
||||||
if (is_slim && 0) {
|
|
||||||
double moveX = node.movement.x() / (scale * branch_radius_scaled);
|
double moveX = node.movement.x() / (scale * branch_radius_scaled);
|
||||||
double moveY = node.movement.y() / (scale * branch_radius_scaled);
|
double moveY = node.movement.y() / (scale * branch_radius_scaled);
|
||||||
const double vsize_inv = 0.5 / (0.01 + std::sqrt(moveX * moveX + moveY * moveY));
|
const double vsize_inv = 0.5 / (0.01 + std::sqrt(moveX * moveX + moveY * moveY));
|
||||||
|
@ -2517,36 +2516,31 @@ void TreeSupport::drop_nodes(std::vector<std::vector<Node*>>& contact_nodes)
|
||||||
//m_object->print()->set_status(59, "Support: preparing avoidance regions ");
|
//m_object->print()->set_status(59, "Support: preparing avoidance regions ");
|
||||||
// get all the possible radiis
|
// get all the possible radiis
|
||||||
std::vector<std::set<coordf_t> > all_layer_radius(m_highest_overhang_layer+1);
|
std::vector<std::set<coordf_t> > all_layer_radius(m_highest_overhang_layer+1);
|
||||||
std::vector<std::set<int> > all_layer_node_dist(m_highest_overhang_layer+1);
|
std::vector<std::set<coordf_t>> all_layer_node_dist(m_highest_overhang_layer + 1);
|
||||||
for (size_t layer_nr = m_highest_overhang_layer; layer_nr > 0; layer_nr--)
|
for (size_t layer_nr = m_highest_overhang_layer; layer_nr > 0; layer_nr--)
|
||||||
{
|
{
|
||||||
auto& layer_contact_nodes = contact_nodes[layer_nr];
|
|
||||||
auto& layer_radius = all_layer_radius[layer_nr];
|
auto& layer_radius = all_layer_radius[layer_nr];
|
||||||
auto& layer_node_dist = all_layer_node_dist[layer_nr];
|
auto& layer_node_dist = all_layer_node_dist[layer_nr];
|
||||||
if (!layer_contact_nodes.empty()) {
|
for (Node *p_node : contact_nodes[layer_nr]) {
|
||||||
for (Node* p_node : layer_contact_nodes) {
|
layer_node_dist.emplace(p_node->dist_mm_to_top);
|
||||||
layer_node_dist.emplace(p_node->distance_to_top);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (layer_nr < m_highest_overhang_layer) {
|
if (layer_nr < m_highest_overhang_layer && layer_heights[layer_nr].second>0) {
|
||||||
for (auto node_dist : all_layer_node_dist[layer_nr + 1])
|
for (auto node_dist : all_layer_node_dist[layer_nr + 1])
|
||||||
layer_node_dist.emplace(node_dist+1);
|
layer_node_dist.emplace(node_dist + layer_heights[layer_nr].second);
|
||||||
}
|
}
|
||||||
for (auto node_dist : layer_node_dist) {
|
for (auto node_dist : layer_node_dist) {
|
||||||
layer_radius.emplace(calc_branch_radius(branch_radius, node_dist, tip_layers, diameter_angle_scale_factor));
|
layer_radius.emplace(calc_branch_radius(branch_radius, node_dist, diameter_angle_scale_factor));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// parallel pre-compute avoidance
|
// parallel pre-compute avoidance
|
||||||
tbb::parallel_for(tbb::blocked_range<size_t>(1, m_highest_overhang_layer),
|
tbb::parallel_for(tbb::blocked_range<size_t>(1, m_highest_overhang_layer), [&](const tbb::blocked_range<size_t> &range) {
|
||||||
[&](const tbb::blocked_range<size_t>& range) {
|
for (size_t layer_nr = range.begin(); layer_nr < range.end(); layer_nr++) {
|
||||||
for (size_t layer_nr = range.begin(); layer_nr < range.end(); layer_nr++) {
|
for (auto node_radius : all_layer_radius[layer_nr]) {
|
||||||
for (auto node_dist : all_layer_node_dist[layer_nr])
|
m_ts_data->get_avoidance(0, layer_nr);
|
||||||
{
|
m_ts_data->get_avoidance(node_radius, layer_nr);
|
||||||
m_ts_data->get_avoidance(0, layer_nr - 1);
|
|
||||||
m_ts_data->get_avoidance(calc_branch_radius(branch_radius, node_dist, tip_layers, diameter_angle_scale_factor), layer_nr - 1);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
|
});
|
||||||
|
|
||||||
BOOST_LOG_TRIVIAL(debug) << "before m_avoidance_cache.size()=" << m_ts_data->m_avoidance_cache.size();
|
BOOST_LOG_TRIVIAL(debug) << "before m_avoidance_cache.size()=" << m_ts_data->m_avoidance_cache.size();
|
||||||
}
|
}
|
||||||
|
@ -2715,10 +2709,17 @@ void TreeSupport::drop_nodes(std::vector<std::vector<Node*>>& contact_nodes)
|
||||||
Node* neighbour = nodes_per_part[group_index][neighbours[0]];
|
Node* neighbour = nodes_per_part[group_index][neighbours[0]];
|
||||||
size_t new_distance_to_top = std::max(node.distance_to_top, neighbour->distance_to_top) + 1;
|
size_t new_distance_to_top = std::max(node.distance_to_top, neighbour->distance_to_top) + 1;
|
||||||
size_t new_support_roof_layers_below = std::max(node.support_roof_layers_below, neighbour->support_roof_layers_below) - 1;
|
size_t new_support_roof_layers_below = std::max(node.support_roof_layers_below, neighbour->support_roof_layers_below) - 1;
|
||||||
double new_dist_mm_to_top = std::max(node.dist_mm_to_top, neighbour->dist_mm_to_top) + node.height;
|
double new_dist_mm_to_top = std::max(node.dist_mm_to_top + node.height, neighbour->dist_mm_to_top+neighbour->height);
|
||||||
|
Node * parent;
|
||||||
|
if (p_node->parent && neighbour->parent)
|
||||||
|
parent = ((node.dist_mm_to_top >= neighbour->dist_mm_to_top && p_node->parent) ? p_node : neighbour)->parent;
|
||||||
|
else if (p_node->parent)
|
||||||
|
parent = p_node->parent;
|
||||||
|
else
|
||||||
|
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, node.skin_direction, new_support_roof_layers_below, to_buildplate, parent,
|
||||||
layer_heights[layer_nr_next].first, layer_heights[layer_nr_next].second, new_dist_mm_to_top);
|
layer_heights[layer_nr_next].first, layer_heights[layer_nr_next].second, 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);
|
||||||
|
@ -2883,6 +2884,17 @@ void TreeSupport::drop_nodes(std::vector<std::vector<Node*>>& contact_nodes)
|
||||||
|
|
||||||
next_layer_vertex += movement;
|
next_layer_vertex += movement;
|
||||||
|
|
||||||
|
if (group_index == 0) {
|
||||||
|
// Avoid collisions.
|
||||||
|
const coordf_t max_move_between_samples = get_max_move_dist(&node, 1) + radius_sample_resolution + EPSILON; // 100 micron extra for rounding errors.
|
||||||
|
bool is_outside = move_out_expolys(avoid_layer, next_layer_vertex, radius_sample_resolution + EPSILON, max_move_between_samples);
|
||||||
|
if (!is_outside) {
|
||||||
|
Point candidate_vertex = node.position;
|
||||||
|
is_outside = move_out_expolys(avoid_layer, candidate_vertex, radius_sample_resolution + EPSILON, max_move_between_samples);
|
||||||
|
if (is_outside) { next_layer_vertex = candidate_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);
|
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, node.skin_direction, node.support_roof_layers_below - 1, to_buildplate, p_node,
|
||||||
print_z_next, height_next);
|
print_z_next, height_next);
|
||||||
|
@ -3013,7 +3025,8 @@ void TreeSupport::smooth_nodes(std::vector<std::vector<Node *>> &contact_nodes)
|
||||||
|
|
||||||
std::vector<Point> pts1 = pts;
|
std::vector<Point> pts1 = pts;
|
||||||
// TODO here we assume layer height gap is constant. If not true, need to consider height jump
|
// TODO here we assume layer height gap is constant. If not true, need to consider height jump
|
||||||
for (size_t k = 0; k < 2; k++) {
|
// TODO it seems the smooth iterations can't be larger than 1, otherwise some nodes will fly away
|
||||||
|
for (size_t k = 0; k < 1; k++) {
|
||||||
for (size_t i = 1; i < pts.size() - 1; i++) {
|
for (size_t i = 1; i < pts.size() - 1; i++) {
|
||||||
size_t i2 = i >= 2 ? i - 2 : 0;
|
size_t i2 = i >= 2 ? i - 2 : 0;
|
||||||
size_t i3 = i < pts.size() - 2 ? i + 2 : pts.size() - 1;
|
size_t i3 = i < pts.size() - 2 ? i + 2 : pts.size() - 1;
|
||||||
|
@ -3024,7 +3037,9 @@ void TreeSupport::smooth_nodes(std::vector<std::vector<Node *>> &contact_nodes)
|
||||||
}
|
}
|
||||||
for (size_t i = 1; i < pts.size() - 1; i++) {
|
for (size_t i = 1; i < pts.size() - 1; i++) {
|
||||||
if (!is_processed[branch[i]]) {
|
if (!is_processed[branch[i]]) {
|
||||||
branch[i]->position = pts[i];
|
// do not move if the new position is too far away
|
||||||
|
if (vsize2_with_unscale(branch[i]->position - pts[i]) < SQ(m_support_params.support_extrusion_width * 2)) { branch[i]->position = pts[i]; }
|
||||||
|
branch[i]->movement = branch[i]->parent ? (branch[i]->position - branch[i]->parent->position) : Point(0, 0);
|
||||||
is_processed[branch[i]] = true;
|
is_processed[branch[i]] = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3128,6 +3143,7 @@ void TreeSupport::adjust_layer_heights(std::vector<std::vector<Node*>>& contact_
|
||||||
std::vector<std::pair<coordf_t, coordf_t>> TreeSupport::plan_layer_heights(std::vector<std::vector<Node*>>& contact_nodes)
|
std::vector<std::pair<coordf_t, coordf_t>> TreeSupport::plan_layer_heights(std::vector<std::vector<Node*>>& contact_nodes)
|
||||||
{
|
{
|
||||||
const PrintObjectConfig& config = m_object->config();
|
const PrintObjectConfig& config = m_object->config();
|
||||||
|
const PrintConfig & print_config = m_object->print()->config();
|
||||||
const coordf_t max_layer_height = m_slicing_params.max_layer_height;
|
const coordf_t max_layer_height = m_slicing_params.max_layer_height;
|
||||||
const coordf_t layer_height = config.layer_height.value;
|
const coordf_t layer_height = config.layer_height.value;
|
||||||
coordf_t z_distance_top = m_slicing_params.gap_support_object;
|
coordf_t z_distance_top = m_slicing_params.gap_support_object;
|
||||||
|
@ -3141,7 +3157,7 @@ std::vector<std::pair<coordf_t, coordf_t>> TreeSupport::plan_layer_heights(std::
|
||||||
std::vector<std::pair<coordf_t, coordf_t>> layer_heights(contact_nodes.size(), std::pair<coordf_t, coordf_t>(0.0, 0.0));
|
std::vector<std::pair<coordf_t, coordf_t>> layer_heights(contact_nodes.size(), std::pair<coordf_t, coordf_t>(0.0, 0.0));
|
||||||
std::vector<int> bounds;
|
std::vector<int> bounds;
|
||||||
|
|
||||||
if (!USE_PLAN_LAYER_HEIGHTS || layer_height == max_layer_height) {
|
if (!USE_PLAN_LAYER_HEIGHTS || layer_height == max_layer_height || !print_config.independent_support_layer_height) {
|
||||||
for (int layer_nr = 0; layer_nr < contact_nodes.size(); layer_nr++) {
|
for (int layer_nr = 0; layer_nr < contact_nodes.size(); layer_nr++) {
|
||||||
layer_heights[layer_nr].first = m_object->get_layer(layer_nr)->print_z;
|
layer_heights[layer_nr].first = m_object->get_layer(layer_nr)->print_z;
|
||||||
layer_heights[layer_nr].second = m_object->get_layer(layer_nr)->height;
|
layer_heights[layer_nr].second = m_object->get_layer(layer_nr)->height;
|
||||||
|
|
|
@ -349,30 +349,6 @@ void ConfigManipulation::update_print_fff_config(DynamicPrintConfig* config, con
|
||||||
is_msg_dlg_already_exist = false;
|
is_msg_dlg_already_exist = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// BBS
|
|
||||||
if (config->opt_bool("enable_support") && is_tree(config->opt_enum<SupportType>("support_type"))
|
|
||||||
&& (config->opt_enum<SupportMaterialStyle>("support_style")==smsDefault || config->opt_enum<SupportMaterialStyle>("support_style")==smsTreeSlim)
|
|
||||||
&& !(config->opt_float("support_top_z_distance")==0 && config->opt_int("support_interface_top_layers")==0 && config->opt_int("tree_support_wall_count")==2))
|
|
||||||
{
|
|
||||||
wxString msg_text = _(L("We have added an experimental style \"Tree Slim\" that features smaller support volume but weaker strength.\n"
|
|
||||||
"We recommand using it with: 0 interface layers, 0 top distance, 2 walls.\n"));
|
|
||||||
if (is_global_config)
|
|
||||||
msg_text += "\n" + _(L("Change these settings automatically? \n"
|
|
||||||
"Yes - Change these settings automatically\n"
|
|
||||||
"No - Do not change these settings for me"));
|
|
||||||
MessageDialog dialog(m_msg_dlg_parent, msg_text, "", wxICON_WARNING | (is_global_config ? wxYES | wxNO : wxOK));
|
|
||||||
DynamicPrintConfig new_conf = *config;
|
|
||||||
is_msg_dlg_already_exist = true;
|
|
||||||
auto answer = dialog.ShowModal();
|
|
||||||
if (!is_global_config || answer == wxID_YES) {
|
|
||||||
new_conf.set_key_value("support_top_z_distance", new ConfigOptionFloat(0));
|
|
||||||
new_conf.set_key_value("support_interface_top_layers", new ConfigOptionInt(0));
|
|
||||||
new_conf.set_key_value("tree_support_wall_count", new ConfigOptionInt(2));
|
|
||||||
}
|
|
||||||
apply(config, &new_conf);
|
|
||||||
is_msg_dlg_already_exist = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// BBS
|
// BBS
|
||||||
int filament_cnt = wxGetApp().preset_bundle->filament_presets.size();
|
int filament_cnt = wxGetApp().preset_bundle->filament_presets.size();
|
||||||
#if 0
|
#if 0
|
||||||
|
|
|
@ -1416,6 +1416,28 @@ void Tab::on_value_change(const std::string& opt_key, const boost::any& value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// BBS popup a message to ask the user to set optimum parameters for tree support
|
||||||
|
if (opt_key == "support_type" || opt_key == "support_style") {
|
||||||
|
// BBS
|
||||||
|
if (is_tree_slim(m_config->opt_enum<SupportType>("support_type"), m_config->opt_enum<SupportMaterialStyle>("support_style")) &&
|
||||||
|
!(m_config->opt_float("support_top_z_distance") == 0 && m_config->opt_int("support_interface_top_layers") == 0 && m_config->opt_int("tree_support_wall_count") == 2)) {
|
||||||
|
wxString msg_text = _L("We have added an experimental style \"Tree Slim\" that features smaller support volume but weaker strength.\n"
|
||||||
|
"We recommand using it with: 0 interface layers, 0 top distance, 2 walls.");
|
||||||
|
msg_text += "\n\n" + _L("Change these settings automatically? \n"
|
||||||
|
"Yes - Change these settings automatically\n"
|
||||||
|
"No - Do not change these settings for me");
|
||||||
|
MessageDialog dialog(wxGetApp().plater(), msg_text, "Suggestion", wxICON_WARNING | wxYES | wxNO);
|
||||||
|
DynamicPrintConfig new_conf = *m_config;
|
||||||
|
if (dialog.ShowModal() == wxID_YES) {
|
||||||
|
new_conf.set_key_value("support_top_z_distance", new ConfigOptionFloat(0));
|
||||||
|
new_conf.set_key_value("support_interface_top_layers", new ConfigOptionInt(0));
|
||||||
|
new_conf.set_key_value("tree_support_wall_count", new ConfigOptionInt(2));
|
||||||
|
m_config_manipulation.apply(m_config, &new_conf);
|
||||||
|
}
|
||||||
|
wxGetApp().plater()->update();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// BBS
|
// BBS
|
||||||
#if 0
|
#if 0
|
||||||
if (opt_key == "extruders_count")
|
if (opt_key == "extruders_count")
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue