mirror of
https://github.com/SoftFever/OrcaSlicer.git
synced 2025-07-10 00:07:52 -06:00
ENH: improve smoothness of tree supports
1. Instead of smoothing top-down, now we smooth tree branches bottom-up, and do not stop at merged nodes. 2. Fix a bug where some nodes don't have child. This is critical for bottom-up smoothing. Change-Id: Iac0fecd81dac541ca390bcf5cbdfe7fd66cfd3a2 (cherry picked from commit 536a8a4f0ef76fa0358f4b4b181c4c7e7fff8bc7)
This commit is contained in:
parent
763cf8ebfc
commit
719f273fa2
2 changed files with 69 additions and 34 deletions
|
@ -27,6 +27,9 @@
|
||||||
|
|
||||||
// #define SUPPORT_TREE_DEBUG_TO_SVG
|
// #define SUPPORT_TREE_DEBUG_TO_SVG
|
||||||
|
|
||||||
|
#if SUPPORT_TREE_DEBUG_TO_SVG
|
||||||
|
#include "nlohmann/json.hpp"
|
||||||
|
#endif
|
||||||
namespace Slic3r
|
namespace Slic3r
|
||||||
{
|
{
|
||||||
#define unscale_(val) ((val) * SCALING_FACTOR)
|
#define unscale_(val) ((val) * SCALING_FACTOR)
|
||||||
|
@ -2983,64 +2986,94 @@ void TreeSupport::drop_nodes(std::vector<std::vector<Node*>>& contact_nodes)
|
||||||
|
|
||||||
void TreeSupport::smooth_nodes(std::vector<std::vector<Node *>> &contact_nodes)
|
void TreeSupport::smooth_nodes(std::vector<std::vector<Node *>> &contact_nodes)
|
||||||
{
|
{
|
||||||
std::map<Node *, bool> is_processed;
|
|
||||||
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<Node *> &curr_layer_nodes = contact_nodes[layer_nr];
|
std::vector<Node *> &curr_layer_nodes = contact_nodes[layer_nr];
|
||||||
if (curr_layer_nodes.empty()) continue;
|
if (curr_layer_nodes.empty()) continue;
|
||||||
for (Node *node : curr_layer_nodes) {
|
for (Node *node : curr_layer_nodes) {
|
||||||
is_processed.emplace(node, false);
|
node->is_processed = false;
|
||||||
if (layer_nr == 0) node->is_merged = true; // nodes on plate are also merged nodes
|
if (layer_nr == 0) node->is_merged = true; // nodes on plate are also merged nodes
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int layer_nr = contact_nodes.size()-1; layer_nr >=0 ; layer_nr--) {
|
for (int layer_nr = 0; layer_nr< contact_nodes.size(); layer_nr++) {
|
||||||
std::vector<Node *> &curr_layer_nodes = contact_nodes[layer_nr];
|
std::vector<Node *> &curr_layer_nodes = contact_nodes[layer_nr];
|
||||||
if (curr_layer_nodes.empty()) continue;
|
if (curr_layer_nodes.empty()) continue;
|
||||||
for (Node *node : curr_layer_nodes) {
|
for (Node *node : curr_layer_nodes) {
|
||||||
if (!is_processed[node]) {
|
if (!node->is_processed) {
|
||||||
std::vector<Point> pts;
|
std::vector<Point> pts;
|
||||||
std::vector<Node *> branch;
|
std::vector<Node *> branch;
|
||||||
Node * p_node = node;
|
Node * p_node = node;
|
||||||
// add head for second path from the merged node if there are multiple ones
|
// add a fixed head
|
||||||
if (!node->is_merged && node->parent) {
|
if (node->child) {
|
||||||
pts.push_back(p_node->parent->position);
|
pts.push_back(p_node->child->position);
|
||||||
branch.push_back(p_node->parent);
|
branch.push_back(p_node->child);
|
||||||
}
|
}
|
||||||
do {
|
do {
|
||||||
pts.push_back(p_node->position);
|
pts.push_back(p_node->position);
|
||||||
//is_processed[p_node] = true;
|
|
||||||
branch.push_back(p_node);
|
branch.push_back(p_node);
|
||||||
p_node = p_node->child;
|
p_node = p_node->parent;
|
||||||
} while (p_node && !p_node->is_merged && !is_processed[p_node]);
|
} while (p_node && !p_node->is_processed);
|
||||||
// TODO is it necessary to add tail also?
|
|
||||||
if (p_node && p_node->is_merged) {
|
|
||||||
pts.push_back(p_node->position);
|
|
||||||
branch.push_back(p_node);
|
|
||||||
}
|
|
||||||
if (pts.size() < 3) continue;
|
if (pts.size() < 3) continue;
|
||||||
|
|
||||||
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
|
||||||
// TODO it seems the smooth iterations can't be larger than 1, otherwise some nodes will fly away
|
const int iterations = 100;
|
||||||
for (size_t k = 0; k < 50; k++) {
|
for (size_t k = 0; k < iterations; 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;
|
||||||
Point pt = (pts[i2] + pts[i - 1] + pts[i] + pts[i + 1] + pts[i3]) / 5;
|
Point pt = (pts[i2] + pts[i - 1] + pts[i] + pts[i + 1] + pts[i3]) / 5;
|
||||||
pts1[i] = pt;
|
pts1[i] = pt;
|
||||||
|
if (k == iterations - 1) {
|
||||||
|
branch[i]->position = pt;
|
||||||
|
branch[i]->movement = (pts[i + 1] - pts[i - 1]) / 2;
|
||||||
|
branch[i]->is_processed = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
std::swap(pts, pts1);
|
if (k < iterations - 1)
|
||||||
}
|
std::swap(pts, pts1);
|
||||||
for (size_t i = 1; i < pts.size() - 1; i++) {
|
|
||||||
if (!is_processed[branch[i]]) {
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#if SUPPORT_TREE_DEBUG_TO_SVG
|
||||||
|
// save tree structure for viewing in python
|
||||||
|
struct TreeNode {
|
||||||
|
Vec3f pos;
|
||||||
|
std::vector<int> children; // index of children in the storing vector
|
||||||
|
TreeNode(Point pt, float z) {
|
||||||
|
pos = { float(unscale_(pt.x())),float(unscale_(pt.y())),z };
|
||||||
|
}
|
||||||
|
};
|
||||||
|
std::vector<TreeNode> tree_nodes;
|
||||||
|
std::map<Node*, int> ptr2idx;
|
||||||
|
std::map<int, Node*> idx2ptr;
|
||||||
|
for (int layer_nr = 0; layer_nr < contact_nodes.size(); layer_nr++) {
|
||||||
|
std::vector<Node*>& curr_layer_nodes = contact_nodes[layer_nr];
|
||||||
|
for (Node* node : curr_layer_nodes) {
|
||||||
|
ptr2idx.emplace(node, tree_nodes.size());
|
||||||
|
idx2ptr.emplace(tree_nodes.size(), node);
|
||||||
|
tree_nodes.emplace_back(node->position, node->print_z);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (size_t i = 0; i < tree_nodes.size(); i++) {
|
||||||
|
TreeNode& tree_node = tree_nodes[i];
|
||||||
|
Node* p_node = idx2ptr[i];
|
||||||
|
if (p_node->child)
|
||||||
|
tree_node.children.push_back(ptr2idx[p_node->child]);
|
||||||
|
}
|
||||||
|
nlohmann::json jj;
|
||||||
|
for (size_t i = 0; i < tree_nodes.size(); i++) {
|
||||||
|
nlohmann::json j;
|
||||||
|
j["pos"] = tree_nodes[i].pos;
|
||||||
|
j["children"] = tree_nodes[i].children;
|
||||||
|
jj.push_back(j);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::ofstream ofs("tree_nodes.json");
|
||||||
|
ofs << jj.dump();
|
||||||
|
ofs.close();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void TreeSupport::adjust_layer_heights(std::vector<std::vector<Node*>>& contact_nodes)
|
void TreeSupport::adjust_layer_heights(std::vector<std::vector<Node*>>& contact_nodes)
|
||||||
|
|
|
@ -259,6 +259,8 @@ public:
|
||||||
if (dist_mm_to_top==0)
|
if (dist_mm_to_top==0)
|
||||||
dist_mm_to_top = parent->dist_mm_to_top + parent->height;
|
dist_mm_to_top = parent->dist_mm_to_top + parent->height;
|
||||||
parent->child = this;
|
parent->child = this;
|
||||||
|
for (auto& neighbor : parent->merged_neighbours)
|
||||||
|
neighbor->child = this;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -280,15 +282,15 @@ public:
|
||||||
/*!
|
/*!
|
||||||
* \brief The position of this node on the layer.
|
* \brief The position of this node on the layer.
|
||||||
*/
|
*/
|
||||||
Point position;
|
Point position;
|
||||||
|
Point movement; // movement towards neighbor center or outline
|
||||||
Point movement; // movement towards neighbor center or outline
|
mutable double radius = 0.0;
|
||||||
mutable double radius = 0.0;
|
mutable double max_move_dist = 0.0;
|
||||||
mutable double max_move_dist = 0.0;
|
NodeType type = eCircle;
|
||||||
NodeType type = eCircle;
|
bool is_merged = false; // this node is generated by merging upper nodes
|
||||||
bool is_merged = false; // this node is generated by merging upper nodes
|
|
||||||
bool is_corner = false;
|
bool is_corner = false;
|
||||||
const ExPolygon* overhang = nullptr; // when type==ePolygon, set this value to get original overhang area
|
bool is_processed = false;
|
||||||
|
const ExPolygon *overhang = nullptr; // when type==ePolygon, set this value to get original overhang area
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief The direction of the skin lines above the tip of the branch.
|
* \brief The direction of the skin lines above the tip of the branch.
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue