mirror of
https://github.com/SoftFever/OrcaSlicer.git
synced 2025-07-10 08:17:51 -06:00
Clean up tree support code
(cherry picked from commit bambulab/BambuStudio@39ae64fc53) Co-authored-by: Arthur <arthur.tang@bambulab.com>
This commit is contained in:
parent
4034ffea18
commit
51290a853d
2 changed files with 223 additions and 477 deletions
|
@ -39,15 +39,6 @@ namespace Slic3r
|
||||||
{
|
{
|
||||||
#define unscale_(val) ((val) * SCALING_FACTOR)
|
#define unscale_(val) ((val) * SCALING_FACTOR)
|
||||||
|
|
||||||
inline unsigned int round_divide(unsigned int dividend, unsigned int divisor) //!< Return dividend divided by divisor rounded to the nearest integer
|
|
||||||
{
|
|
||||||
return (dividend + divisor / 2) / divisor;
|
|
||||||
}
|
|
||||||
inline unsigned int round_up_divide(unsigned int dividend, unsigned int divisor) //!< Return dividend divided by divisor rounded to the nearest integer
|
|
||||||
{
|
|
||||||
return (dividend + divisor - 1) / divisor;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline double dot_with_unscale(const Point a, const Point b)
|
inline double dot_with_unscale(const Point a, const Point b)
|
||||||
{
|
{
|
||||||
return unscale_(a(0)) * unscale_(b(0)) + unscale_(a(1)) * unscale_(b(1));
|
return unscale_(a(0)) * unscale_(b(0)) + unscale_(a(1)) * unscale_(b(1));
|
||||||
|
@ -206,8 +197,8 @@ static void draw_contours_and_nodes_to_svg
|
||||||
const ExPolygons &overhangs,
|
const ExPolygons &overhangs,
|
||||||
const ExPolygons &overhangs_after_offset,
|
const ExPolygons &overhangs_after_offset,
|
||||||
const ExPolygons &outlines_below,
|
const ExPolygons &outlines_below,
|
||||||
const std::vector<TreeSupport::Node*> &layer_nodes,
|
const std::vector<SupportNode*> &layer_nodes,
|
||||||
const std::vector<TreeSupport::Node*> &lower_layer_nodes,
|
const std::vector<SupportNode*> &lower_layer_nodes,
|
||||||
std::string name_prefix,
|
std::string name_prefix,
|
||||||
std::vector<std::string> legends = { "overhang","avoid","outlines" }, std::vector<std::string> colors = { "blue","red","yellow" }
|
std::vector<std::string> legends = { "overhang","avoid","outlines" }, std::vector<std::string> colors = { "blue","red","yellow" }
|
||||||
)
|
)
|
||||||
|
@ -216,7 +207,7 @@ static void draw_contours_and_nodes_to_svg
|
||||||
bbox.merge(get_extents(overhangs_after_offset));
|
bbox.merge(get_extents(overhangs_after_offset));
|
||||||
bbox.merge(get_extents(outlines_below));
|
bbox.merge(get_extents(outlines_below));
|
||||||
Points layer_pts;
|
Points layer_pts;
|
||||||
for (TreeSupport::Node* node : layer_nodes) {
|
for (SupportNode* node : layer_nodes) {
|
||||||
layer_pts.push_back(node->position);
|
layer_pts.push_back(node->position);
|
||||||
}
|
}
|
||||||
bbox.merge(get_extents(layer_pts));
|
bbox.merge(get_extents(layer_pts));
|
||||||
|
@ -255,14 +246,14 @@ static void draw_contours_and_nodes_to_svg
|
||||||
#if 0
|
#if 0
|
||||||
// lower layer points
|
// lower layer points
|
||||||
layer_pts.clear();
|
layer_pts.clear();
|
||||||
for (TreeSupport::Node *node : lower_layer_nodes) {
|
for (SupportNode *node : lower_layer_nodes) {
|
||||||
layer_pts.push_back(node->position);
|
layer_pts.push_back(node->position);
|
||||||
}
|
}
|
||||||
svg.draw(layer_pts, "black", coord_t(scale_(0.1)));
|
svg.draw(layer_pts, "black", coord_t(scale_(0.1)));
|
||||||
|
|
||||||
// higher layer points
|
// higher layer points
|
||||||
layer_pts.clear();
|
layer_pts.clear();
|
||||||
for (TreeSupport::Node* node : layer_nodes) {
|
for (SupportNode* node : layer_nodes) {
|
||||||
if(node->parent)
|
if(node->parent)
|
||||||
layer_pts.push_back(node->parent->position);
|
layer_pts.push_back(node->parent->position);
|
||||||
}
|
}
|
||||||
|
@ -1269,50 +1260,9 @@ static void _make_loops(ExtrusionEntitiesPtr& loops_entities, ExPolygons &suppor
|
||||||
expoly_list.erase(first_iter);
|
expoly_list.erase(first_iter);
|
||||||
}
|
}
|
||||||
|
|
||||||
// draw connected loops
|
extrusion_entities_append_loops(loops_entities, std::move(loops), role, float(flow.mm3_per_mm()), float(flow.width()), float(flow.height()));
|
||||||
if (/*wall_count > 1 && wall_count<5*/0) {
|
|
||||||
// TODO this method may drop some contours
|
|
||||||
wall_count = std::min(wall_count, loops.size());
|
|
||||||
Polylines polylines;
|
|
||||||
polylines.push_back(Polyline());
|
|
||||||
Polyline& polyline = polylines.back();
|
|
||||||
Point end_pt;
|
|
||||||
Point end_dir;
|
|
||||||
for (int wall_idx = 0; wall_idx < wall_count; wall_idx++) {
|
|
||||||
Polygon &loop = loops[wall_idx];
|
|
||||||
if (loop.size()<3) continue;
|
|
||||||
// break the closed loop if this is not the last loop, so the next loop can attach to the end_pt
|
|
||||||
//if (wall_idx != wall_count - 1 && loop.first_point() == loop.last_point())
|
|
||||||
// loop.points.pop_back();
|
|
||||||
|
|
||||||
if (wall_idx == 0) {
|
}
|
||||||
polyline.append(loop.points);
|
|
||||||
} else {
|
|
||||||
double d = loop.distance_to(end_pt);
|
|
||||||
if (d < scale_(2)) { // if current loop is close to the previous one
|
|
||||||
polyline.append(end_pt);
|
|
||||||
ExtrusionPath expath;
|
|
||||||
expath.polyline.append(loop.points);
|
|
||||||
ExtrusionLoop extru_loop(expath);
|
|
||||||
extru_loop.split_at(end_pt, false);
|
|
||||||
polyline.append(extru_loop.as_polyline());
|
|
||||||
}else{// create a new polylie if they are far away
|
|
||||||
polylines.push_back(Polyline());
|
|
||||||
polyline = polylines.back();
|
|
||||||
polyline.append(loop.points);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
end_pt = polyline.points.back();
|
|
||||||
end_dir = end_pt - polyline.points[polyline.points.size() - 2];
|
|
||||||
Point perpendicular_dir = turn90_ccw(end_dir);
|
|
||||||
end_pt = end_pt + normal(perpendicular_dir, flow.scaled_spacing());
|
|
||||||
}
|
|
||||||
|
|
||||||
extrusion_entities_append_paths(loops_entities, polylines, role, float(flow.mm3_per_mm()), float(flow.width()), float(flow.height()));
|
|
||||||
} else {
|
|
||||||
extrusion_entities_append_loops(loops_entities, std::move(loops), role, float(flow.mm3_per_mm()), float(flow.width()), float(flow.height()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void make_perimeter_and_inner_brim(ExtrusionEntitiesPtr &dst, const ExPolygon &support_area, size_t wall_count, const Flow &flow, ExtrusionRole role)
|
static void make_perimeter_and_inner_brim(ExtrusionEntitiesPtr &dst, const ExPolygon &support_area, size_t wall_count, const Flow &flow, ExtrusionRole role)
|
||||||
{
|
{
|
||||||
|
@ -1654,210 +1604,6 @@ void TreeSupport::generate_toolpaths()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Polygons TreeSupport::spanning_tree_to_polygon(const std::vector<MinimumSpanningTree>& spanning_trees, Polygons layer_contours, int layer_nr)
|
|
||||||
{
|
|
||||||
Polygons polys;
|
|
||||||
auto& mst_line_x_layer_contour_cache = m_mst_line_x_layer_contour_caches[layer_nr];
|
|
||||||
for (MinimumSpanningTree mst : spanning_trees) {
|
|
||||||
std::vector<Point> points = mst.vertices();
|
|
||||||
if (points.size() == 0)
|
|
||||||
continue;
|
|
||||||
std::map<Point, bool> visited;
|
|
||||||
for (int i=0;i<points.size();i++)
|
|
||||||
visited.emplace(points[i],false);
|
|
||||||
|
|
||||||
std::unordered_set<Line, LineHash> to_ignore;
|
|
||||||
for (int i = 0; i < points.size(); i++) {
|
|
||||||
if (visited[points[i]] == true)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
Polygon poly;
|
|
||||||
bool has_next = true;
|
|
||||||
Point pt1 = points[i];
|
|
||||||
poly.points.push_back(pt1);
|
|
||||||
visited[pt1] = true;
|
|
||||||
|
|
||||||
while (has_next) {
|
|
||||||
const std::vector<Point>& neighbours = mst.adjacent_nodes(pt1);
|
|
||||||
if (neighbours.empty())
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
double min_ccw = std::numeric_limits<double>::max();
|
|
||||||
Point pt_selected = neighbours[0];
|
|
||||||
has_next = false;
|
|
||||||
for (Point pt2 : neighbours) {
|
|
||||||
if (to_ignore.find(Line(pt1, pt2)) == to_ignore.end()) {
|
|
||||||
auto iter = mst_line_x_layer_contour_cache.find({ pt1,pt2 });
|
|
||||||
if (iter != mst_line_x_layer_contour_cache.end()) {
|
|
||||||
if (iter->second)
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
Polylines pls;
|
|
||||||
pls.emplace_back(pt1, pt2);
|
|
||||||
Polylines pls_intersect = intersection_pl(pls, layer_contours);
|
|
||||||
mst_line_x_layer_contour_cache.insert({ {pt1, pt2}, !pls_intersect.empty() });
|
|
||||||
mst_line_x_layer_contour_cache.insert({ {pt2, pt1}, !pls_intersect.empty() });
|
|
||||||
if (!pls_intersect.empty())
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (poly.points.size() < 2 || visited[pt2]==false)
|
|
||||||
{
|
|
||||||
pt_selected = pt2;
|
|
||||||
has_next = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
double curr_ccw = pt2.ccw(pt1, poly.points.back());
|
|
||||||
if (curr_ccw < min_ccw)
|
|
||||||
{
|
|
||||||
min_ccw = curr_ccw;
|
|
||||||
pt_selected = pt2;
|
|
||||||
has_next = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (has_next) {
|
|
||||||
poly.points.push_back(pt_selected);
|
|
||||||
to_ignore.insert(Line(pt1, pt_selected));
|
|
||||||
visited[pt_selected] = true;
|
|
||||||
pt1 = pt_selected;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
polys.emplace_back(std::move(poly));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return polys;
|
|
||||||
}
|
|
||||||
|
|
||||||
Polygons TreeSupport::contact_nodes_to_polygon(const std::vector<Node*>& contact_nodes, Polygons layer_contours, int layer_nr, std::vector<double>& radiis, std::vector<bool>& is_interface)
|
|
||||||
{
|
|
||||||
Polygons polys;
|
|
||||||
std::vector<MinimumSpanningTree> spanning_trees;
|
|
||||||
std::vector<double> radiis_mtree;
|
|
||||||
std::vector<bool> is_interface_mtree;
|
|
||||||
// generate minimum spanning trees
|
|
||||||
{
|
|
||||||
std::map<Node*, bool> visited;
|
|
||||||
for (int i = 0; i < contact_nodes.size(); i++)
|
|
||||||
visited.emplace(contact_nodes[i], false);
|
|
||||||
std::unordered_set<Line, LineHash> to_ignore;
|
|
||||||
|
|
||||||
// generate minimum spaning trees
|
|
||||||
for (int i = 0; i < contact_nodes.size(); i++) {
|
|
||||||
Node* node = contact_nodes[i];
|
|
||||||
if (visited[node])
|
|
||||||
continue;
|
|
||||||
|
|
||||||
std::vector<Point> points_to_mstree;
|
|
||||||
double radius = 0;
|
|
||||||
Point pt1 = node->position;
|
|
||||||
points_to_mstree.push_back(pt1);
|
|
||||||
visited[node] = true;
|
|
||||||
radius += node->radius;
|
|
||||||
|
|
||||||
for (int j = i + 1; j < contact_nodes.size(); j++) {
|
|
||||||
Node* node2 = contact_nodes[j];
|
|
||||||
Point pt2 = node2->position;
|
|
||||||
// connect to this neighbor if:
|
|
||||||
// 1) both are interface or both are not
|
|
||||||
// 3) not readly added
|
|
||||||
// 4) won't cross perimeters: this is not right since we need to check all possible connections
|
|
||||||
if ((node->support_roof_layers_below > 0) == (node2->support_roof_layers_below > 0)
|
|
||||||
&& to_ignore.find(Line(pt1, pt2)) == to_ignore.end())
|
|
||||||
{
|
|
||||||
points_to_mstree.emplace_back(pt2);
|
|
||||||
visited[node2] = true;
|
|
||||||
radius += node2->radius;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
spanning_trees.emplace_back(points_to_mstree);
|
|
||||||
radiis_mtree.push_back(radius / points_to_mstree.size());
|
|
||||||
is_interface_mtree.push_back(node->support_roof_layers_below > 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
auto lines = spanning_tree_to_lines(spanning_trees);
|
|
||||||
#if 1
|
|
||||||
// convert mtree to polygon
|
|
||||||
for (int k = 0; k < spanning_trees.size(); k++) {
|
|
||||||
auto& mst_line_x_layer_contour_cache = m_mst_line_x_layer_contour_caches[layer_nr];
|
|
||||||
MinimumSpanningTree mst = spanning_trees[k];
|
|
||||||
std::vector<Point> points = mst.vertices();
|
|
||||||
std::map<Point, bool> visited;
|
|
||||||
for (int i = 0; i < points.size(); i++)
|
|
||||||
visited.emplace(points[i], false);
|
|
||||||
|
|
||||||
std::unordered_set<Line, LineHash> to_ignore;
|
|
||||||
for (int i = 0; i < points.size(); i++) {
|
|
||||||
if (visited[points[i]])
|
|
||||||
continue;
|
|
||||||
|
|
||||||
Polygon poly;
|
|
||||||
Point pt1 = points[i];
|
|
||||||
poly.points.push_back(pt1);
|
|
||||||
visited[pt1] = true;
|
|
||||||
|
|
||||||
bool has_next = true;
|
|
||||||
while (has_next)
|
|
||||||
{
|
|
||||||
const std::vector<Point>& neighbours = mst.adjacent_nodes(pt1);
|
|
||||||
double min_ccw = -std::numeric_limits<double>::max();
|
|
||||||
Point pt_selected;
|
|
||||||
has_next = false;
|
|
||||||
for (Point pt2 : neighbours) {
|
|
||||||
if (to_ignore.find(Line(pt1, pt2)) == to_ignore.end()) {
|
|
||||||
auto iter = mst_line_x_layer_contour_cache.find({ pt1,pt2 });
|
|
||||||
if (iter != mst_line_x_layer_contour_cache.end()) {
|
|
||||||
if (iter->second)
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
Polylines pls;
|
|
||||||
pls.emplace_back(pt1, pt2);
|
|
||||||
Polylines pls_intersect = intersection_pl(pls, layer_contours);
|
|
||||||
mst_line_x_layer_contour_cache.insert({ {pt1, pt2}, !pls_intersect.empty() });
|
|
||||||
mst_line_x_layer_contour_cache.insert({ {pt2, pt1}, !pls_intersect.empty() });
|
|
||||||
if (!pls_intersect.empty())
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (poly.points.size() < 2)
|
|
||||||
{
|
|
||||||
pt_selected = pt2;
|
|
||||||
has_next = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
double curr_ccw = pt2.ccw(pt1, poly.points.rbegin()[1]);
|
|
||||||
if (curr_ccw > min_ccw)
|
|
||||||
{
|
|
||||||
has_next = true;
|
|
||||||
min_ccw = curr_ccw;
|
|
||||||
pt_selected = pt2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!has_next)
|
|
||||||
break;
|
|
||||||
|
|
||||||
poly.points.push_back(pt_selected);
|
|
||||||
to_ignore.insert(Line(pt1, pt_selected));
|
|
||||||
visited[pt_selected] = true;
|
|
||||||
pt1 = pt_selected;
|
|
||||||
}
|
|
||||||
polys.emplace_back(std::move(poly));
|
|
||||||
radiis.push_back(radiis_mtree[k]);
|
|
||||||
is_interface.push_back(is_interface_mtree[k]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
polys = spanning_tree_to_polygon(spanning_trees, layer_contours, layer_nr, radiis);
|
|
||||||
#endif
|
|
||||||
return polys;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void TreeSupport::generate()
|
void TreeSupport::generate()
|
||||||
{
|
{
|
||||||
if (m_support_params.support_style == smsOrganic) {
|
if (m_support_params.support_style == smsOrganic) {
|
||||||
|
@ -1865,7 +1611,7 @@ void TreeSupport::generate()
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<std::vector<Node*>> contact_nodes(m_object->layers().size());
|
std::vector<std::vector<SupportNode*>> contact_nodes(m_object->layers().size());
|
||||||
|
|
||||||
profiler.stage_start(STAGE_total);
|
profiler.stage_start(STAGE_total);
|
||||||
|
|
||||||
|
@ -1907,7 +1653,7 @@ if (!m_object->config().tree_support_adaptive_layer_height)
|
||||||
|
|
||||||
for (auto& layer : contact_nodes)
|
for (auto& layer : contact_nodes)
|
||||||
{
|
{
|
||||||
for (Node* p_node : layer)
|
for (SupportNode* p_node : layer)
|
||||||
{
|
{
|
||||||
delete p_node;
|
delete p_node;
|
||||||
}
|
}
|
||||||
|
@ -2061,7 +1807,7 @@ Polygons TreeSupport::get_trim_support_regions(
|
||||||
return polygons_trimming;
|
return polygons_trimming;
|
||||||
}
|
}
|
||||||
|
|
||||||
void TreeSupport::draw_circles(const std::vector<std::vector<Node*>>& contact_nodes)
|
void TreeSupport::draw_circles(const std::vector<std::vector<SupportNode*>>& contact_nodes)
|
||||||
{
|
{
|
||||||
const PrintObjectConfig &config = m_object->config();
|
const PrintObjectConfig &config = m_object->config();
|
||||||
const Print* print = m_object->print();
|
const Print* print = m_object->print();
|
||||||
|
@ -2123,7 +1869,7 @@ void TreeSupport::draw_circles(const std::vector<std::vector<Node*>>& contact_no
|
||||||
if (print->canceled())
|
if (print->canceled())
|
||||||
break;
|
break;
|
||||||
|
|
||||||
const std::vector<Node*>& curr_layer_nodes = contact_nodes[layer_nr];
|
const std::vector<SupportNode*>& curr_layer_nodes = contact_nodes[layer_nr];
|
||||||
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);
|
||||||
assert(ts_layer != nullptr);
|
assert(ts_layer != nullptr);
|
||||||
|
|
||||||
|
@ -2134,7 +1880,7 @@ void TreeSupport::draw_circles(const std::vector<std::vector<Node*>>& contact_no
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
Node* first_node = curr_layer_nodes.front();
|
SupportNode* first_node = curr_layer_nodes.front();
|
||||||
ts_layer->print_z = first_node->print_z;
|
ts_layer->print_z = first_node->print_z;
|
||||||
ts_layer->height = first_node->height;
|
ts_layer->height = first_node->height;
|
||||||
if (ts_layer->height < EPSILON) {
|
if (ts_layer->height < EPSILON) {
|
||||||
|
@ -2155,12 +1901,12 @@ void TreeSupport::draw_circles(const std::vector<std::vector<Node*>>& contact_no
|
||||||
BOOST_LOG_TRIVIAL(debug) << "circles at layer " << layer_nr << " contact nodes size=" << contact_nodes[layer_nr].size();
|
BOOST_LOG_TRIVIAL(debug) << "circles at layer " << layer_nr << " contact nodes size=" << contact_nodes[layer_nr].size();
|
||||||
//Draw the support areas and add the roofs appropriately to the support roof instead of normal areas.
|
//Draw the support areas and add the roofs appropriately to the support roof instead of normal areas.
|
||||||
ts_layer->lslices.reserve(contact_nodes[layer_nr].size());
|
ts_layer->lslices.reserve(contact_nodes[layer_nr].size());
|
||||||
for (const Node* p_node : contact_nodes[layer_nr])
|
for (const SupportNode* p_node : contact_nodes[layer_nr])
|
||||||
{
|
{
|
||||||
if (print->canceled())
|
if (print->canceled())
|
||||||
break;
|
break;
|
||||||
|
|
||||||
const Node& node = *p_node;
|
const SupportNode& node = *p_node;
|
||||||
ExPolygons area;
|
ExPolygons area;
|
||||||
// Generate directly from overhang polygon if one of the following is true:
|
// Generate directly from overhang polygon if one of the following is true:
|
||||||
// 1) node is a normal part of hybrid support
|
// 1) node is a normal part of hybrid support
|
||||||
|
@ -2347,7 +2093,7 @@ void TreeSupport::draw_circles(const std::vector<std::vector<Node*>>& contact_no
|
||||||
std::vector<Polygons> overhangs;
|
std::vector<Polygons> overhangs;
|
||||||
for (int layer_nr = 1; layer_nr < m_object->layer_count(); layer_nr++) {
|
for (int layer_nr = 1; layer_nr < m_object->layer_count(); layer_nr++) {
|
||||||
if (print->canceled()) break;
|
if (print->canceled()) break;
|
||||||
const std::vector<Node*>& curr_layer_nodes = contact_nodes[layer_nr];
|
const std::vector<SupportNode*>& curr_layer_nodes = contact_nodes[layer_nr];
|
||||||
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);
|
||||||
assert(ts_layer != nullptr);
|
assert(ts_layer != nullptr);
|
||||||
|
|
||||||
|
@ -2439,7 +2185,7 @@ void TreeSupport::draw_circles(const std::vector<std::vector<Node*>>& contact_no
|
||||||
if (print->canceled()) break;
|
if (print->canceled()) break;
|
||||||
m_object->print()->set_status(66, (boost::format(_L("Support: fix holes at layer %d")) % layer_nr).str());
|
m_object->print()->set_status(66, (boost::format(_L("Support: fix holes at layer %d")) % layer_nr).str());
|
||||||
|
|
||||||
const std::vector<Node*>& curr_layer_nodes = contact_nodes[layer_nr];
|
const std::vector<SupportNode*>& curr_layer_nodes = contact_nodes[layer_nr];
|
||||||
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);
|
||||||
assert(ts_layer != nullptr);
|
assert(ts_layer != nullptr);
|
||||||
|
|
||||||
|
@ -2547,7 +2293,7 @@ void TreeSupport::draw_circles(const std::vector<std::vector<Node*>>& contact_no
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void TreeSupport::drop_nodes(std::vector<std::vector<Node*>>& contact_nodes)
|
void TreeSupport::drop_nodes(std::vector<std::vector<SupportNode*>>& contact_nodes)
|
||||||
{
|
{
|
||||||
const PrintObjectConfig &config = m_object->config();
|
const PrintObjectConfig &config = m_object->config();
|
||||||
// Use Minimum Spanning Tree to connect the points on each layer and move them while dropping them down.
|
// Use Minimum Spanning Tree to connect the points on each layer and move them while dropping them down.
|
||||||
|
@ -2573,7 +2319,7 @@ void TreeSupport::drop_nodes(std::vector<std::vector<Node*>>& contact_nodes)
|
||||||
if (config.tree_support_branch_angle.value < 30.0) return config.tree_support_branch_angle.value;
|
if (config.tree_support_branch_angle.value < 30.0) return config.tree_support_branch_angle.value;
|
||||||
return (radius - MIN_BRANCH_RADIUS) / (MAX_BRANCH_RADIUS - MIN_BRANCH_RADIUS) * (config.tree_support_branch_angle.value - 30.0) + 30.0;
|
return (radius - MIN_BRANCH_RADIUS) / (MAX_BRANCH_RADIUS - MIN_BRANCH_RADIUS) * (config.tree_support_branch_angle.value - 30.0) + 30.0;
|
||||||
};
|
};
|
||||||
auto get_max_move_dist = [this, &config, branch_radius, tip_layers, diameter_angle_scale_factor, wall_count, support_extrusion_width, support_line_width](const Node *node, int power = 1) {
|
auto get_max_move_dist = [this, &config, branch_radius, tip_layers, diameter_angle_scale_factor, wall_count, support_extrusion_width, support_line_width](const SupportNode *node, int power = 1) {
|
||||||
double move_dist = node->max_move_dist;
|
double move_dist = node->max_move_dist;
|
||||||
if (node->max_move_dist == 0) {
|
if (node->max_move_dist == 0) {
|
||||||
if (node->radius == 0) node->radius = calc_branch_radius(branch_radius, node->dist_mm_to_top, diameter_angle_scale_factor);
|
if (node->radius == 0) node->radius = calc_branch_radius(branch_radius, node->dist_mm_to_top, diameter_angle_scale_factor);
|
||||||
|
@ -2594,7 +2340,7 @@ void TreeSupport::drop_nodes(std::vector<std::vector<Node*>>& contact_nodes)
|
||||||
std::vector<LayerHeightData> &layer_heights = m_ts_data->layer_heights;
|
std::vector<LayerHeightData> &layer_heights = m_ts_data->layer_heights;
|
||||||
if (layer_heights.empty()) return;
|
if (layer_heights.empty()) return;
|
||||||
|
|
||||||
std::unordered_set<Node*> to_free_node_set;
|
std::unordered_set<SupportNode*> to_free_node_set;
|
||||||
m_spanning_trees.resize(contact_nodes.size());
|
m_spanning_trees.resize(contact_nodes.size());
|
||||||
//m_mst_line_x_layer_contour_caches.resize(contact_nodes.size());
|
//m_mst_line_x_layer_contour_caches.resize(contact_nodes.size());
|
||||||
|
|
||||||
|
@ -2613,7 +2359,7 @@ void TreeSupport::drop_nodes(std::vector<std::vector<Node*>>& contact_nodes)
|
||||||
if (layer_heights[layer_nr].height < EPSILON) continue;
|
if (layer_heights[layer_nr].height < EPSILON) continue;
|
||||||
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];
|
||||||
for (Node *p_node : contact_nodes[layer_nr]) {
|
for (SupportNode *p_node : contact_nodes[layer_nr]) {
|
||||||
layer_node_dist.emplace(p_node->dist_mm_to_top);
|
layer_node_dist.emplace(p_node->dist_mm_to_top);
|
||||||
}
|
}
|
||||||
size_t layer_nr_next = layer_heights[layer_nr].next_layer_nr;
|
size_t layer_nr_next = layer_heights[layer_nr].next_layer_nr;
|
||||||
|
@ -2655,7 +2401,7 @@ void TreeSupport::drop_nodes(std::vector<std::vector<Node*>>& contact_nodes)
|
||||||
coordf_t print_z_next = layer_heights[layer_nr_next].print_z;
|
coordf_t print_z_next = layer_heights[layer_nr_next].print_z;
|
||||||
coordf_t height_next = layer_heights[layer_nr_next].height;
|
coordf_t height_next = layer_heights[layer_nr_next].height;
|
||||||
|
|
||||||
std::deque<std::pair<size_t, Node*>> unsupported_branch_leaves; // All nodes that are leaves on this layer that would result in unsupported ('mid-air') branches.
|
std::deque<std::pair<size_t, SupportNode*>> unsupported_branch_leaves; // All nodes that are leaves on this layer that would result in unsupported ('mid-air') branches.
|
||||||
const Layer* ts_layer = m_object->get_support_layer(layer_nr);
|
const Layer* ts_layer = m_object->get_support_layer(layer_nr);
|
||||||
|
|
||||||
m_object->print()->set_status(60, (boost::format(_L("Support: propagate branches at layer %d")) % layer_nr).str());
|
m_object->print()->set_status(60, (boost::format(_L("Support: propagate branches at layer %d")) % layer_nr).str());
|
||||||
|
@ -2685,14 +2431,14 @@ void TreeSupport::drop_nodes(std::vector<std::vector<Node*>>& contact_nodes)
|
||||||
|
|
||||||
//Group together all nodes for each part.
|
//Group together all nodes for each part.
|
||||||
const ExPolygons& parts = m_ts_data->get_avoidance(0, layer_nr);
|
const ExPolygons& parts = m_ts_data->get_avoidance(0, layer_nr);
|
||||||
std::vector<std::unordered_map<Point, Node*, PointHash>> nodes_per_part(1 + parts.size()); //All nodes that aren't inside a part get grouped together in the 0th part.
|
std::vector<std::unordered_map<Point, SupportNode*, PointHash>> nodes_per_part(1 + parts.size()); //All nodes that aren't inside a part get grouped together in the 0th part.
|
||||||
for (Node* p_node : layer_contact_nodes)
|
for (SupportNode* p_node : layer_contact_nodes)
|
||||||
{
|
{
|
||||||
const Node& node = *p_node;
|
const SupportNode& node = *p_node;
|
||||||
|
|
||||||
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, layer_nr_next, p_node->support_roof_layers_below - 1, p_node->to_buildplate, p_node,
|
SupportNode* next_node = new SupportNode(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;
|
||||||
|
@ -2747,10 +2493,10 @@ void TreeSupport::drop_nodes(std::vector<std::vector<Node*>>& contact_nodes)
|
||||||
profiler.tic();
|
profiler.tic();
|
||||||
//std::vector<MinimumSpanningTree>& spanning_trees = m_spanning_trees[layer_nr];
|
//std::vector<MinimumSpanningTree>& spanning_trees = m_spanning_trees[layer_nr];
|
||||||
std::vector<MinimumSpanningTree> spanning_trees;
|
std::vector<MinimumSpanningTree> spanning_trees;
|
||||||
for (const std::unordered_map<Point, Node*, PointHash>& group : nodes_per_part)
|
for (const std::unordered_map<Point, SupportNode*, PointHash>& group : nodes_per_part)
|
||||||
{
|
{
|
||||||
std::vector<Point> points_to_buildplate;
|
std::vector<Point> points_to_buildplate;
|
||||||
for (const std::pair<const Point, Node*>& entry : group)
|
for (const std::pair<const Point, SupportNode*>& entry : group)
|
||||||
{
|
{
|
||||||
points_to_buildplate.emplace_back(entry.first); //Just the position of the node.
|
points_to_buildplate.emplace_back(entry.first); //Just the position of the node.
|
||||||
}
|
}
|
||||||
|
@ -2767,11 +2513,11 @@ void TreeSupport::drop_nodes(std::vector<std::vector<Node*>>& contact_nodes)
|
||||||
{
|
{
|
||||||
const MinimumSpanningTree& mst = spanning_trees[group_index];
|
const MinimumSpanningTree& mst = spanning_trees[group_index];
|
||||||
//In the first pass, merge all nodes that are close together.
|
//In the first pass, merge all nodes that are close together.
|
||||||
std::unordered_set<Node*> to_delete;
|
std::unordered_set<SupportNode*> to_delete;
|
||||||
for (const std::pair<const Point, Node*>& entry : nodes_per_part[group_index])
|
for (const std::pair<const Point, SupportNode*>& entry : nodes_per_part[group_index])
|
||||||
{
|
{
|
||||||
Node* p_node = entry.second;
|
SupportNode* p_node = entry.second;
|
||||||
Node& node = *p_node;
|
SupportNode& node = *p_node;
|
||||||
if (to_delete.find(p_node) != to_delete.end())
|
if (to_delete.find(p_node) != to_delete.end())
|
||||||
{
|
{
|
||||||
continue; //Delete this node (don't create a new node for it on the next layer).
|
continue; //Delete this node (don't create a new node for it on the next layer).
|
||||||
|
@ -2780,7 +2526,7 @@ void TreeSupport::drop_nodes(std::vector<std::vector<Node*>>& contact_nodes)
|
||||||
if (node.type == ePolygon) {
|
if (node.type == ePolygon) {
|
||||||
// Remove all neighbours that are completely inside the polygon and merge them into this node.
|
// Remove all neighbours that are completely inside the polygon and merge them into this node.
|
||||||
for (const Point &neighbour : neighbours) {
|
for (const Point &neighbour : neighbours) {
|
||||||
Node * neighbour_node = nodes_per_part[group_index][neighbour];
|
SupportNode * neighbour_node = nodes_per_part[group_index][neighbour];
|
||||||
coord_t neighbour_radius = scale_(calc_branch_radius(branch_radius, neighbour_node->dist_mm_to_top, diameter_angle_scale_factor));
|
coord_t neighbour_radius = scale_(calc_branch_radius(branch_radius, neighbour_node->dist_mm_to_top, diameter_angle_scale_factor));
|
||||||
Point pt_north = neighbour + Point(0, neighbour_radius), pt_south = neighbour - Point(0, neighbour_radius),
|
Point pt_north = neighbour + Point(0, neighbour_radius), pt_south = neighbour - Point(0, neighbour_radius),
|
||||||
pt_west = neighbour - Point(neighbour_radius, 0), pt_east = neighbour + Point(neighbour_radius, 0);
|
pt_west = neighbour - Point(neighbour_radius, 0), pt_east = neighbour + Point(neighbour_radius, 0);
|
||||||
|
@ -2812,8 +2558,8 @@ void TreeSupport::drop_nodes(std::vector<std::vector<Node*>>& contact_nodes)
|
||||||
move_out_expolys(avoid_layer, next_position, radius_sample_resolution + EPSILON, max_move_between_samples);
|
move_out_expolys(avoid_layer, next_position, radius_sample_resolution + EPSILON, max_move_between_samples);
|
||||||
}
|
}
|
||||||
|
|
||||||
Node* neighbour = nodes_per_part[group_index][neighbours[0]];
|
SupportNode* neighbour = nodes_per_part[group_index][neighbours[0]];
|
||||||
Node* node_;
|
SupportNode* node_;
|
||||||
if (p_node->parent && neighbour->parent)
|
if (p_node->parent && neighbour->parent)
|
||||||
node_ = (node.dist_mm_to_top >= neighbour->dist_mm_to_top && p_node->parent) ? p_node : neighbour;
|
node_ = (node.dist_mm_to_top >= neighbour->dist_mm_to_top && p_node->parent) ? p_node : neighbour;
|
||||||
else
|
else
|
||||||
|
@ -2821,7 +2567,7 @@ void TreeSupport::drop_nodes(std::vector<std::vector<Node*>>& contact_nodes)
|
||||||
// Make sure the next pass doesn't drop down either of these (since that already happened).
|
// Make sure the next pass doesn't drop down either of these (since that already happened).
|
||||||
node_->merged_neighbours.push_front(node_ == p_node ? neighbour : p_node);
|
node_->merged_neighbours.push_front(node_ == p_node ? neighbour : p_node);
|
||||||
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, node_->distance_to_top + 1, layer_nr_next, node_->support_roof_layers_below-1, to_buildplate, node_,
|
SupportNode * next_node = new SupportNode(next_position, node_->distance_to_top + 1, layer_nr_next, node_->support_roof_layers_below-1, to_buildplate, node_,
|
||||||
print_z_next, height_next);
|
print_z_next, height_next);
|
||||||
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);
|
||||||
|
@ -2839,7 +2585,7 @@ void TreeSupport::drop_nodes(std::vector<std::vector<Node*>>& contact_nodes)
|
||||||
{
|
{
|
||||||
if (vsize2_with_unscale(neighbour - node.position) < /*max_move_distance2*/get_max_move_dist(&node,2))
|
if (vsize2_with_unscale(neighbour - node.position) < /*max_move_distance2*/get_max_move_dist(&node,2))
|
||||||
{
|
{
|
||||||
Node* neighbour_node = nodes_per_part[group_index][neighbour];
|
SupportNode* neighbour_node = nodes_per_part[group_index][neighbour];
|
||||||
if (neighbour_node->type == ePolygon) continue;
|
if (neighbour_node->type == ePolygon) continue;
|
||||||
|
|
||||||
node.distance_to_top = std::max(node.distance_to_top, neighbour_node->distance_to_top);
|
node.distance_to_top = std::max(node.distance_to_top, neighbour_node->distance_to_top);
|
||||||
|
@ -2855,10 +2601,10 @@ void TreeSupport::drop_nodes(std::vector<std::vector<Node*>>& contact_nodes)
|
||||||
}
|
}
|
||||||
|
|
||||||
//In the second pass, move all middle nodes.
|
//In the second pass, move all middle nodes.
|
||||||
for (const std::pair<const Point, Node*>& entry : nodes_per_part[group_index])
|
for (const std::pair<const Point, SupportNode*>& entry : nodes_per_part[group_index])
|
||||||
{
|
{
|
||||||
Node* p_node = entry.second;
|
SupportNode* p_node = entry.second;
|
||||||
const Node& node = *p_node;
|
const SupportNode& node = *p_node;
|
||||||
if (to_delete.find(p_node) != to_delete.end())
|
if (to_delete.find(p_node) != to_delete.end())
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
|
@ -2866,7 +2612,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, layer_nr_next, p_node->support_roof_layers_below - 1, to_buildplate,
|
SupportNode * next_node = new SupportNode(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;
|
||||||
|
@ -2887,7 +2633,7 @@ void TreeSupport::drop_nodes(std::vector<std::vector<Node*>>& contact_nodes)
|
||||||
unsupported_branch_leaves.push_front({ layer_nr, p_node });
|
unsupported_branch_leaves.push_front({ layer_nr, p_node });
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
Node* pn = p_node;
|
SupportNode* pn = p_node;
|
||||||
for (int i = 0; i <= bottom_interface_layers && pn; i++, pn = pn->parent)
|
for (int i = 0; i <= bottom_interface_layers && pn; i++, pn = pn->parent)
|
||||||
pn->support_floor_layers_above = bottom_interface_layers - i + 1; // +1 so the parent node has support_floor_layers_above=2
|
pn->support_floor_layers_above = bottom_interface_layers - i + 1; // +1 so the parent node has support_floor_layers_above=2
|
||||||
to_delete.insert(p_node);
|
to_delete.insert(p_node);
|
||||||
|
@ -2897,7 +2643,7 @@ void TreeSupport::drop_nodes(std::vector<std::vector<Node*>>& contact_nodes)
|
||||||
// if the link between parent and current is cut by contours, mark current as bottom contact node
|
// if the link between parent and current is cut by contours, mark current as bottom contact node
|
||||||
if (p_node->parent && intersection_ln({p_node->position, p_node->parent->position}, layer_contours).empty()==false)
|
if (p_node->parent && intersection_ln({p_node->position, p_node->parent->position}, layer_contours).empty()==false)
|
||||||
{
|
{
|
||||||
Node* pn = p_node->parent;
|
SupportNode* pn = p_node->parent;
|
||||||
for (int i = 0; i <= bottom_interface_layers && pn; i++, pn = pn->parent)
|
for (int i = 0; i <= bottom_interface_layers && pn; i++, pn = pn->parent)
|
||||||
pn->support_floor_layers_above = bottom_interface_layers - i + 1;
|
pn->support_floor_layers_above = bottom_interface_layers - i + 1;
|
||||||
to_delete.insert(p_node);
|
to_delete.insert(p_node);
|
||||||
|
@ -2919,7 +2665,7 @@ void TreeSupport::drop_nodes(std::vector<std::vector<Node*>>& contact_nodes)
|
||||||
Point sum_direction(0, 0);
|
Point sum_direction(0, 0);
|
||||||
for (const Point &neighbour : neighbours) {
|
for (const Point &neighbour : neighbours) {
|
||||||
// do not move to the neighbor to be deleted
|
// do not move to the neighbor to be deleted
|
||||||
Node *neighbour_node = nodes_per_part[group_index][neighbour];
|
SupportNode *neighbour_node = nodes_per_part[group_index][neighbour];
|
||||||
if (to_delete.find(neighbour_node) != to_delete.end()) continue;
|
if (to_delete.find(neighbour_node) != to_delete.end()) continue;
|
||||||
|
|
||||||
Point direction = neighbour - node.position;
|
Point direction = neighbour - node.position;
|
||||||
|
@ -3010,7 +2756,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, layer_nr_next, node.support_roof_layers_below - 1, to_buildplate, p_node,
|
SupportNode * next_node = new SupportNode(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);
|
||||||
|
@ -3038,11 +2784,11 @@ void TreeSupport::drop_nodes(std::vector<std::vector<Node*>>& contact_nodes)
|
||||||
for (;! unsupported_branch_leaves.empty(); unsupported_branch_leaves.pop_back())
|
for (;! unsupported_branch_leaves.empty(); unsupported_branch_leaves.pop_back())
|
||||||
{
|
{
|
||||||
const auto& entry = unsupported_branch_leaves.back();
|
const auto& entry = unsupported_branch_leaves.back();
|
||||||
Node* i_node = entry.second;
|
SupportNode* i_node = entry.second;
|
||||||
for (; i_node != nullptr; i_node = i_node->parent)
|
for (; i_node != nullptr; i_node = i_node->parent)
|
||||||
{
|
{
|
||||||
size_t i_layer = i_node->obj_layer_nr;
|
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<SupportNode*>::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())
|
||||||
{
|
{
|
||||||
// update the parent-child chain
|
// update the parent-child chain
|
||||||
|
@ -3053,7 +2799,7 @@ void TreeSupport::drop_nodes(std::vector<std::vector<Node*>>& contact_nodes)
|
||||||
contact_nodes[i_layer].erase(to_erase);
|
contact_nodes[i_layer].erase(to_erase);
|
||||||
to_free_node_set.insert(i_node);
|
to_free_node_set.insert(i_node);
|
||||||
|
|
||||||
for (Node* neighbour : i_node->merged_neighbours)
|
for (SupportNode* neighbour : i_node->merged_neighbours)
|
||||||
{
|
{
|
||||||
unsupported_branch_leaves.push_front({ i_layer, neighbour });
|
unsupported_branch_leaves.push_front({ i_layer, neighbour });
|
||||||
}
|
}
|
||||||
|
@ -3064,32 +2810,32 @@ void TreeSupport::drop_nodes(std::vector<std::vector<Node*>>& contact_nodes)
|
||||||
|
|
||||||
BOOST_LOG_TRIVIAL(debug) << "after m_avoidance_cache.size()=" << m_ts_data->m_avoidance_cache.size();
|
BOOST_LOG_TRIVIAL(debug) << "after m_avoidance_cache.size()=" << m_ts_data->m_avoidance_cache.size();
|
||||||
|
|
||||||
for (Node *node : to_free_node_set)
|
for (SupportNode *node : to_free_node_set)
|
||||||
{
|
{
|
||||||
delete node;
|
delete node;
|
||||||
}
|
}
|
||||||
to_free_node_set.clear();
|
to_free_node_set.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void TreeSupport::smooth_nodes(std::vector<std::vector<Node *>> &contact_nodes)
|
void TreeSupport::smooth_nodes(std::vector<std::vector<SupportNode *>> &contact_nodes)
|
||||||
{
|
{
|
||||||
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<SupportNode *> &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 (SupportNode *node : curr_layer_nodes) {
|
||||||
node->is_processed = 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 = 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<SupportNode *> &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 (SupportNode *node : curr_layer_nodes) {
|
||||||
if (!node->is_processed) {
|
if (!node->is_processed) {
|
||||||
std::vector<Point> pts;
|
std::vector<Point> pts;
|
||||||
std::vector<Node *> branch;
|
std::vector<SupportNode *> branch;
|
||||||
Node * p_node = node;
|
SupportNode * p_node = node;
|
||||||
// add a fixed head
|
// add a fixed head
|
||||||
if (node->child) {
|
if (node->child) {
|
||||||
pts.push_back(p_node->child->position);
|
pts.push_back(p_node->child->position);
|
||||||
|
@ -3125,11 +2871,11 @@ void TreeSupport::smooth_nodes(std::vector<std::vector<Node *>> &contact_nodes)
|
||||||
}
|
}
|
||||||
// save tree structure for viewing in python
|
// save tree structure for viewing in python
|
||||||
auto& tree_nodes = m_ts_data->tree_nodes;
|
auto& tree_nodes = m_ts_data->tree_nodes;
|
||||||
std::map<Node*, int> ptr2idx;
|
std::map<SupportNode*, int> ptr2idx;
|
||||||
std::map<int, Node*> idx2ptr;
|
std::map<int, SupportNode*> idx2ptr;
|
||||||
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<SupportNode*>& curr_layer_nodes = contact_nodes[layer_nr];
|
||||||
for (Node* node : curr_layer_nodes) {
|
for (SupportNode* node : curr_layer_nodes) {
|
||||||
ptr2idx.emplace(node, tree_nodes.size());
|
ptr2idx.emplace(node, tree_nodes.size());
|
||||||
idx2ptr.emplace(tree_nodes.size(), node);
|
idx2ptr.emplace(tree_nodes.size(), node);
|
||||||
tree_nodes.emplace_back(node->position, node->print_z);
|
tree_nodes.emplace_back(node->position, node->print_z);
|
||||||
|
@ -3137,7 +2883,7 @@ void TreeSupport::smooth_nodes(std::vector<std::vector<Node *>> &contact_nodes)
|
||||||
}
|
}
|
||||||
for (size_t i = 0; i < tree_nodes.size(); i++) {
|
for (size_t i = 0; i < tree_nodes.size(); i++) {
|
||||||
TreeNode& tree_node = tree_nodes[i];
|
TreeNode& tree_node = tree_nodes[i];
|
||||||
Node* p_node = idx2ptr[i];
|
SupportNode* p_node = idx2ptr[i];
|
||||||
if (p_node->child)
|
if (p_node->child)
|
||||||
tree_node.children.push_back(ptr2idx[p_node->child]);
|
tree_node.children.push_back(ptr2idx[p_node->child]);
|
||||||
if(p_node->parent)
|
if(p_node->parent)
|
||||||
|
@ -3159,7 +2905,7 @@ void TreeSupport::smooth_nodes(std::vector<std::vector<Node *>> &contact_nodes)
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void TreeSupport::adjust_layer_heights(std::vector<std::vector<Node*>>& contact_nodes)
|
void TreeSupport::adjust_layer_heights(std::vector<std::vector<SupportNode*>>& contact_nodes)
|
||||||
{
|
{
|
||||||
if (contact_nodes.empty())
|
if (contact_nodes.empty())
|
||||||
return;
|
return;
|
||||||
|
@ -3170,8 +2916,8 @@ void TreeSupport::adjust_layer_heights(std::vector<std::vector<Node*>>& contact_
|
||||||
// TODO can we merge layers in a way that guaranttees smoothness?
|
// TODO can we merge layers in a way that guaranttees smoothness?
|
||||||
if (!print_config.independent_support_layer_height || is_slim) {
|
if (!print_config.independent_support_layer_height || is_slim) {
|
||||||
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<SupportNode*>& curr_layer_nodes = contact_nodes[layer_nr];
|
||||||
for (Node* node : curr_layer_nodes) {
|
for (SupportNode* node : curr_layer_nodes) {
|
||||||
node->print_z = m_object->get_layer(layer_nr)->print_z;
|
node->print_z = m_object->get_layer(layer_nr)->print_z;
|
||||||
node->height = m_object->get_layer(layer_nr)->height;
|
node->height = m_object->get_layer(layer_nr)->height;
|
||||||
}
|
}
|
||||||
|
@ -3190,14 +2936,14 @@ void TreeSupport::adjust_layer_heights(std::vector<std::vector<Node*>>& contact_
|
||||||
if (layer_height == max_layer_height) return;
|
if (layer_height == max_layer_height) return;
|
||||||
|
|
||||||
extremes.push_back(0);
|
extremes.push_back(0);
|
||||||
for (Node* node : contact_nodes[0]) {
|
for (SupportNode* node : contact_nodes[0]) {
|
||||||
node->print_z = m_object->get_layer(0)->print_z;
|
node->print_z = m_object->get_layer(0)->print_z;
|
||||||
node->height = m_object->get_layer(0)->height;
|
node->height = m_object->get_layer(0)->height;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int layer_nr = 1; layer_nr < contact_nodes.size(); layer_nr++) {
|
for (int layer_nr = 1; layer_nr < contact_nodes.size(); layer_nr++) {
|
||||||
std::vector<Node*>& curr_layer_nodes = contact_nodes[layer_nr];
|
std::vector<SupportNode*>& curr_layer_nodes = contact_nodes[layer_nr];
|
||||||
for (Node* node : curr_layer_nodes) {
|
for (SupportNode* node : curr_layer_nodes) {
|
||||||
if (node->support_roof_layers_below >0 || node->support_floor_layers_above == bot_intf_layers) {
|
if (node->support_roof_layers_below >0 || node->support_floor_layers_above == bot_intf_layers) {
|
||||||
extremes.push_back(layer_nr);
|
extremes.push_back(layer_nr);
|
||||||
break;
|
break;
|
||||||
|
@ -3206,7 +2952,7 @@ void TreeSupport::adjust_layer_heights(std::vector<std::vector<Node*>>& contact_
|
||||||
|
|
||||||
if (extremes.back() == layer_nr) {
|
if (extremes.back() == layer_nr) {
|
||||||
// contact layer use the same print_z and layer height with object layer
|
// contact layer use the same print_z and layer height with object layer
|
||||||
for (Node* node : curr_layer_nodes) {
|
for (SupportNode* node : curr_layer_nodes) {
|
||||||
node->print_z = m_object->get_layer(layer_nr)->print_z;
|
node->print_z = m_object->get_layer(layer_nr)->print_z;
|
||||||
node->height = m_object->get_layer(layer_nr)->height;
|
node->height = m_object->get_layer(layer_nr)->height;
|
||||||
}
|
}
|
||||||
|
@ -3230,11 +2976,11 @@ void TreeSupport::adjust_layer_heights(std::vector<std::vector<Node*>>& contact_
|
||||||
coordf_t print_z = extr1z + step;
|
coordf_t print_z = extr1z + step;
|
||||||
assert(step >= layer_height - EPSILON);
|
assert(step >= layer_height - EPSILON);
|
||||||
for (int layer_nr = extr1_layer_nr + 1; layer_nr < extr2_layer_nr; layer_nr++) {
|
for (int layer_nr = extr1_layer_nr + 1; layer_nr < extr2_layer_nr; layer_nr++) {
|
||||||
std::vector<Node*>& 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;
|
||||||
|
|
||||||
if (std::abs(print_z - curr_layer_nodes[0]->print_z) < step / 2 + EPSILON) {
|
if (std::abs(print_z - curr_layer_nodes[0]->print_z) < step / 2 + EPSILON) {
|
||||||
for (Node* node : curr_layer_nodes) {
|
for (SupportNode* node : curr_layer_nodes) {
|
||||||
node->print_z = print_z;
|
node->print_z = print_z;
|
||||||
node->height = step;
|
node->height = step;
|
||||||
}
|
}
|
||||||
|
@ -3242,7 +2988,7 @@ void TreeSupport::adjust_layer_heights(std::vector<std::vector<Node*>>& contact_
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// can't clear curr_layer_nodes, or the model will have empty layers
|
// can't clear curr_layer_nodes, or the model will have empty layers
|
||||||
for (Node* node : curr_layer_nodes) {
|
for (SupportNode* node : curr_layer_nodes) {
|
||||||
node->print_z = 0.0;
|
node->print_z = 0.0;
|
||||||
node->height = 0.0;
|
node->height = 0.0;
|
||||||
}
|
}
|
||||||
|
@ -3251,7 +2997,7 @@ void TreeSupport::adjust_layer_heights(std::vector<std::vector<Node*>>& contact_
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<LayerHeightData> TreeSupport::plan_layer_heights(std::vector<std::vector<Node *>> &contact_nodes)
|
std::vector<LayerHeightData> TreeSupport::plan_layer_heights(std::vector<std::vector<SupportNode *>> &contact_nodes)
|
||||||
{
|
{
|
||||||
const PrintObjectConfig& config = m_object->config();
|
const PrintObjectConfig& config = m_object->config();
|
||||||
const PrintConfig & print_config = m_object->print()->config();
|
const PrintConfig & print_config = m_object->print()->config();
|
||||||
|
@ -3350,7 +3096,7 @@ std::vector<LayerHeightData> TreeSupport::plan_layer_heights(std::vector<std::ve
|
||||||
return layer_heights;
|
return layer_heights;
|
||||||
}
|
}
|
||||||
|
|
||||||
void TreeSupport::generate_contact_points(std::vector<std::vector<TreeSupport::Node*>>& contact_nodes)
|
void TreeSupport::generate_contact_points(std::vector<std::vector<SupportNode*>>& contact_nodes)
|
||||||
{
|
{
|
||||||
const PrintObjectConfig &config = m_object->config();
|
const PrintObjectConfig &config = m_object->config();
|
||||||
const coordf_t point_spread = scale_(config.tree_support_branch_distance.value);
|
const coordf_t point_spread = scale_(config.tree_support_branch_distance.value);
|
||||||
|
@ -3423,7 +3169,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);
|
||||||
if (!(config.support_on_build_plate_only && is_inside_ex(m_ts_data->m_layer_outlines_below[layer_nr], candidate))) {
|
if (!(config.support_on_build_plate_only && is_inside_ex(m_ts_data->m_layer_outlines_below[layer_nr], candidate))) {
|
||||||
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,
|
SupportNode* contact_node = new SupportNode(candidate, -z_distance_top_layers, layer_nr, support_roof_layers + z_distance_top_layers, true, SupportNode::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;
|
||||||
|
@ -3452,8 +3198,8 @@ 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, support_roof_layers + z_distance_top_layers, to_buildplate,
|
SupportNode * contact_node = new SupportNode(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);
|
SupportNode::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);
|
||||||
added = true;
|
added = true;
|
||||||
|
@ -3475,7 +3221,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, support_roof_layers + z_distance_top_layers, to_buildplate, Node::NO_PARENT,
|
SupportNode *contact_node = new SupportNode(candidate, -z_distance_top_layers, layer_nr, support_roof_layers + z_distance_top_layers, to_buildplate, SupportNode::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);
|
||||||
|
@ -3491,7 +3237,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, support_roof_layers + z_distance_top_layers, true, Node::NO_PARENT, print_z,
|
SupportNode *contact_node = new SupportNode(pt, -z_distance_top_layers, layer_nr, support_roof_layers + z_distance_top_layers, true, SupportNode::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;
|
||||||
|
@ -3551,16 +3297,16 @@ void TreeSupport::generate_contact_points(std::vector<std::vector<TreeSupport::N
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void TreeSupport::insert_dropped_node(std::vector<Node*>& nodes_layer, Node* p_node)
|
void TreeSupport::insert_dropped_node(std::vector<SupportNode*>& nodes_layer, SupportNode* p_node)
|
||||||
{
|
{
|
||||||
std::vector<Node*>::iterator conflicting_node_it = std::find(nodes_layer.begin(), nodes_layer.end(), p_node);
|
std::vector<SupportNode*>::iterator conflicting_node_it = std::find(nodes_layer.begin(), nodes_layer.end(), p_node);
|
||||||
if (conflicting_node_it == nodes_layer.end()) //No conflict.
|
if (conflicting_node_it == nodes_layer.end()) //No conflict.
|
||||||
{
|
{
|
||||||
nodes_layer.emplace_back(p_node);
|
nodes_layer.emplace_back(p_node);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Node* conflicting_node = *conflicting_node_it;
|
SupportNode* conflicting_node = *conflicting_node_it;
|
||||||
conflicting_node->distance_to_top = std::max(conflicting_node->distance_to_top, p_node->distance_to_top);
|
conflicting_node->distance_to_top = std::max(conflicting_node->distance_to_top, p_node->distance_to_top);
|
||||||
conflicting_node->support_roof_layers_below = std::max(conflicting_node->support_roof_layers_below, p_node->support_roof_layers_below);
|
conflicting_node->support_roof_layers_below = std::max(conflicting_node->support_roof_layers_below, p_node->support_roof_layers_below);
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,6 +41,142 @@ struct TreeNode {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum TreeNodeType {
|
||||||
|
eCircle,
|
||||||
|
eSquare,
|
||||||
|
ePolygon
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief Represents the metadata of a node in the tree.
|
||||||
|
*/
|
||||||
|
struct SupportNode
|
||||||
|
{
|
||||||
|
static constexpr SupportNode* NO_PARENT = nullptr;
|
||||||
|
|
||||||
|
SupportNode()
|
||||||
|
: distance_to_top(0)
|
||||||
|
, position(Point(0, 0))
|
||||||
|
, obj_layer_nr(0)
|
||||||
|
, support_roof_layers_below(0)
|
||||||
|
, support_floor_layers_above(0)
|
||||||
|
, to_buildplate(true)
|
||||||
|
, parent(nullptr)
|
||||||
|
, print_z(0.0)
|
||||||
|
, height(0.0)
|
||||||
|
{}
|
||||||
|
|
||||||
|
// when dist_mm_to_top_==0, new node's dist_mm_to_top=parent->dist_mm_to_top + parent->height;
|
||||||
|
SupportNode(const Point position, const int distance_to_top, const int obj_layer_nr, const int support_roof_layers_below, const bool to_buildplate, SupportNode* parent,
|
||||||
|
coordf_t print_z_, coordf_t height_, coordf_t dist_mm_to_top_=0)
|
||||||
|
: distance_to_top(distance_to_top)
|
||||||
|
, position(position)
|
||||||
|
, obj_layer_nr(obj_layer_nr)
|
||||||
|
, support_roof_layers_below(support_roof_layers_below)
|
||||||
|
, support_floor_layers_above(0)
|
||||||
|
, to_buildplate(to_buildplate)
|
||||||
|
, parent(parent)
|
||||||
|
, print_z(print_z_)
|
||||||
|
, height(height_)
|
||||||
|
, dist_mm_to_top(dist_mm_to_top_)
|
||||||
|
{
|
||||||
|
if (parent) {
|
||||||
|
type = parent->type;
|
||||||
|
overhang = parent->overhang;
|
||||||
|
if (dist_mm_to_top==0)
|
||||||
|
dist_mm_to_top = parent->dist_mm_to_top + parent->height;
|
||||||
|
parent->child = this;
|
||||||
|
for (auto& neighbor : parent->merged_neighbours)
|
||||||
|
neighbor->child = this;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef DEBUG // Clear the delete node's data so if there's invalid access after, we may get a clue by inspecting that node.
|
||||||
|
~SupportNode()
|
||||||
|
{
|
||||||
|
parent = nullptr;
|
||||||
|
merged_neighbours.clear();
|
||||||
|
}
|
||||||
|
#endif // DEBUG
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief The number of layers to go to the top of this branch.
|
||||||
|
* Negative value means it's a virtual node between support and overhang, which doesn't need to be extruded.
|
||||||
|
*/
|
||||||
|
int distance_to_top;
|
||||||
|
coordf_t dist_mm_to_top = 0; // dist to bottom contact in mm
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief The position of this node on the layer.
|
||||||
|
*/
|
||||||
|
Point position;
|
||||||
|
Point movement; // movement towards neighbor center or outline
|
||||||
|
mutable double radius = 0.0;
|
||||||
|
mutable double max_move_dist = 0.0;
|
||||||
|
TreeNodeType type = eCircle;
|
||||||
|
bool is_merged = false; // this node is generated by merging upper nodes
|
||||||
|
bool is_corner = false;
|
||||||
|
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.
|
||||||
|
*
|
||||||
|
* This determines in which direction we should reduce the width of the
|
||||||
|
* branch.
|
||||||
|
*/
|
||||||
|
bool skin_direction;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief The number of support roof layers below this one.
|
||||||
|
*
|
||||||
|
* When a contact point is created, it is determined whether the mesh
|
||||||
|
* needs to be supported with support roof or not, since that is a
|
||||||
|
* per-mesh setting. This is stored in this variable in order to track
|
||||||
|
* how far we need to extend that support roof downwards.
|
||||||
|
*/
|
||||||
|
int support_roof_layers_below;
|
||||||
|
int support_floor_layers_above;
|
||||||
|
int obj_layer_nr;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief Whether to try to go towards the build plate.
|
||||||
|
*
|
||||||
|
* If the node is inside the collision areas, it has no choice but to go
|
||||||
|
* towards the model. If it is not inside the collision areas, it must
|
||||||
|
* go towards the build plate to prevent a scar on the surface.
|
||||||
|
*/
|
||||||
|
bool to_buildplate;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief The originating node for this one, one layer higher.
|
||||||
|
*
|
||||||
|
* In order to prune branches that can't have any support (because they
|
||||||
|
* can't be on the model and the path to the buildplate isn't clear),
|
||||||
|
* the entire branch needs to be known.
|
||||||
|
*/
|
||||||
|
SupportNode* parent;
|
||||||
|
SupportNode* child = nullptr;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief All neighbours (on the same layer) that where merged into this node.
|
||||||
|
*
|
||||||
|
* In order to prune branches that can't have any support (because they
|
||||||
|
* can't be on the model and the path to the buildplate isn't clear),
|
||||||
|
* the entire branch needs to be known.
|
||||||
|
*/
|
||||||
|
std::list<SupportNode*> merged_neighbours;
|
||||||
|
|
||||||
|
coordf_t print_z;
|
||||||
|
coordf_t height;
|
||||||
|
|
||||||
|
bool operator==(const SupportNode& other) const
|
||||||
|
{
|
||||||
|
return position == other.position;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Lazily generates tree guidance volumes.
|
* \brief Lazily generates tree guidance volumes.
|
||||||
*
|
*
|
||||||
|
@ -227,140 +363,6 @@ public:
|
||||||
|
|
||||||
void detect_overhangs(bool detect_first_sharp_tail_only=false);
|
void detect_overhangs(bool detect_first_sharp_tail_only=false);
|
||||||
|
|
||||||
enum NodeType {
|
|
||||||
eCircle,
|
|
||||||
eSquare,
|
|
||||||
ePolygon
|
|
||||||
};
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* \brief Represents the metadata of a node in the tree.
|
|
||||||
*/
|
|
||||||
struct Node
|
|
||||||
{
|
|
||||||
static constexpr Node* NO_PARENT = nullptr;
|
|
||||||
|
|
||||||
Node()
|
|
||||||
: distance_to_top(0)
|
|
||||||
, position(Point(0, 0))
|
|
||||||
, obj_layer_nr(0)
|
|
||||||
, support_roof_layers_below(0)
|
|
||||||
, support_floor_layers_above(0)
|
|
||||||
, to_buildplate(true)
|
|
||||||
, parent(nullptr)
|
|
||||||
, print_z(0.0)
|
|
||||||
, height(0.0)
|
|
||||||
{}
|
|
||||||
|
|
||||||
// when dist_mm_to_top_==0, new node's dist_mm_to_top=parent->dist_mm_to_top + parent->height;
|
|
||||||
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)
|
|
||||||
: distance_to_top(distance_to_top)
|
|
||||||
, position(position)
|
|
||||||
, obj_layer_nr(obj_layer_nr)
|
|
||||||
, support_roof_layers_below(support_roof_layers_below)
|
|
||||||
, support_floor_layers_above(0)
|
|
||||||
, to_buildplate(to_buildplate)
|
|
||||||
, parent(parent)
|
|
||||||
, print_z(print_z_)
|
|
||||||
, height(height_)
|
|
||||||
, dist_mm_to_top(dist_mm_to_top_)
|
|
||||||
{
|
|
||||||
if (parent) {
|
|
||||||
type = parent->type;
|
|
||||||
overhang = parent->overhang;
|
|
||||||
if (dist_mm_to_top==0)
|
|
||||||
dist_mm_to_top = parent->dist_mm_to_top + parent->height;
|
|
||||||
parent->child = this;
|
|
||||||
for (auto& neighbor : parent->merged_neighbours)
|
|
||||||
neighbor->child = this;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef DEBUG // Clear the delete node's data so if there's invalid access after, we may get a clue by inspecting that node.
|
|
||||||
~Node()
|
|
||||||
{
|
|
||||||
parent = nullptr;
|
|
||||||
merged_neighbours.clear();
|
|
||||||
}
|
|
||||||
#endif // DEBUG
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* \brief The number of layers to go to the top of this branch.
|
|
||||||
* Negative value means it's a virtual node between support and overhang, which doesn't need to be extruded.
|
|
||||||
*/
|
|
||||||
int distance_to_top;
|
|
||||||
coordf_t dist_mm_to_top = 0; // dist to bottom contact in mm
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* \brief The position of this node on the layer.
|
|
||||||
*/
|
|
||||||
Point position;
|
|
||||||
Point movement; // movement towards neighbor center or outline
|
|
||||||
mutable double radius = 0.0;
|
|
||||||
mutable double max_move_dist = 0.0;
|
|
||||||
NodeType type = eCircle;
|
|
||||||
bool is_merged = false; // this node is generated by merging upper nodes
|
|
||||||
bool is_corner = false;
|
|
||||||
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.
|
|
||||||
*
|
|
||||||
* This determines in which direction we should reduce the width of the
|
|
||||||
* branch.
|
|
||||||
*/
|
|
||||||
bool skin_direction;
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* \brief The number of support roof layers below this one.
|
|
||||||
*
|
|
||||||
* When a contact point is created, it is determined whether the mesh
|
|
||||||
* needs to be supported with support roof or not, since that is a
|
|
||||||
* per-mesh setting. This is stored in this variable in order to track
|
|
||||||
* how far we need to extend that support roof downwards.
|
|
||||||
*/
|
|
||||||
int support_roof_layers_below;
|
|
||||||
int support_floor_layers_above;
|
|
||||||
int obj_layer_nr;
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* \brief Whether to try to go towards the build plate.
|
|
||||||
*
|
|
||||||
* If the node is inside the collision areas, it has no choice but to go
|
|
||||||
* towards the model. If it is not inside the collision areas, it must
|
|
||||||
* go towards the build plate to prevent a scar on the surface.
|
|
||||||
*/
|
|
||||||
bool to_buildplate;
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* \brief The originating node for this one, one layer higher.
|
|
||||||
*
|
|
||||||
* In order to prune branches that can't have any support (because they
|
|
||||||
* can't be on the model and the path to the buildplate isn't clear),
|
|
||||||
* the entire branch needs to be known.
|
|
||||||
*/
|
|
||||||
Node *parent;
|
|
||||||
Node *child = nullptr;
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* \brief All neighbours (on the same layer) that where merged into this node.
|
|
||||||
*
|
|
||||||
* In order to prune branches that can't have any support (because they
|
|
||||||
* can't be on the model and the path to the buildplate isn't clear),
|
|
||||||
* the entire branch needs to be known.
|
|
||||||
*/
|
|
||||||
std::list<Node*> merged_neighbours;
|
|
||||||
|
|
||||||
coordf_t print_z;
|
|
||||||
coordf_t height;
|
|
||||||
|
|
||||||
bool operator==(const Node& other) const
|
|
||||||
{
|
|
||||||
return position == other.position;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
int avg_node_per_layer = 0;
|
int avg_node_per_layer = 0;
|
||||||
float nodes_angle = 0;
|
float nodes_angle = 0;
|
||||||
|
@ -418,7 +420,7 @@ private:
|
||||||
* save the resulting support polygons to.
|
* save the resulting support polygons to.
|
||||||
* \param contact_nodes The nodes to draw as support.
|
* \param contact_nodes The nodes to draw as support.
|
||||||
*/
|
*/
|
||||||
void draw_circles(const std::vector<std::vector<Node*>>& contact_nodes);
|
void draw_circles(const std::vector<std::vector<SupportNode*>>& contact_nodes);
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Drops down the nodes of the tree support towards the build plate.
|
* \brief Drops down the nodes of the tree support towards the build plate.
|
||||||
|
@ -432,18 +434,18 @@ private:
|
||||||
* dropped down. The nodes are dropped to lower layers inside the same
|
* dropped down. The nodes are dropped to lower layers inside the same
|
||||||
* vector of layers.
|
* vector of layers.
|
||||||
*/
|
*/
|
||||||
void drop_nodes(std::vector<std::vector<Node *>> &contact_nodes);
|
void drop_nodes(std::vector<std::vector<SupportNode*>>& contact_nodes);
|
||||||
|
|
||||||
void smooth_nodes(std::vector<std::vector<Node *>> &contact_nodes);
|
void smooth_nodes(std::vector<std::vector<SupportNode*>>& contact_nodes);
|
||||||
|
|
||||||
void adjust_layer_heights(std::vector<std::vector<Node*>>& contact_nodes);
|
void adjust_layer_heights(std::vector<std::vector<SupportNode*>>& contact_nodes);
|
||||||
|
|
||||||
/*! BBS: MusangKing: maximum layer height
|
/*! BBS: MusangKing: maximum layer height
|
||||||
* \brief Optimize the generation of tree support by pre-planning the layer_heights
|
* \brief Optimize the generation of tree support by pre-planning the layer_heights
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
std::vector<LayerHeightData> plan_layer_heights(std::vector<std::vector<Node *>> &contact_nodes);
|
std::vector<LayerHeightData> plan_layer_heights(std::vector<std::vector<SupportNode*>>& contact_nodes);
|
||||||
/*!
|
/*!
|
||||||
* \brief Creates points where support contacts the model.
|
* \brief Creates points where support contacts the model.
|
||||||
*
|
*
|
||||||
|
@ -457,18 +459,16 @@ private:
|
||||||
* \return For each layer, a list of points where the tree should connect
|
* \return For each layer, a list of points where the tree should connect
|
||||||
* with the model.
|
* with the model.
|
||||||
*/
|
*/
|
||||||
void generate_contact_points(std::vector<std::vector<Node*>>& contact_nodes);
|
void generate_contact_points(std::vector<std::vector<SupportNode*>>& contact_nodes);
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Add a node to the next layer.
|
* \brief Add a node to the next layer.
|
||||||
*
|
*
|
||||||
* If a node is already at that position in the layer, the nodes are merged.
|
* If a node is already at that position in the layer, the nodes are merged.
|
||||||
*/
|
*/
|
||||||
void insert_dropped_node(std::vector<Node*>& nodes_layer, Node* node);
|
void insert_dropped_node(std::vector<SupportNode*>& nodes_layer, SupportNode* node);
|
||||||
void create_tree_support_layers();
|
void create_tree_support_layers();
|
||||||
void generate_toolpaths();
|
void generate_toolpaths();
|
||||||
Polygons spanning_tree_to_polygon(const std::vector<MinimumSpanningTree>& spanning_trees, Polygons layer_contours, int layer_nr);
|
|
||||||
Polygons contact_nodes_to_polygon(const std::vector<Node*>& contact_nodes, Polygons layer_contours, int layer_nr, std::vector<double>& radiis, std::vector<bool>& is_interface);
|
|
||||||
coordf_t calc_branch_radius(coordf_t base_radius, size_t layers_to_top, size_t tip_layers, double diameter_angle_scale_factor);
|
coordf_t calc_branch_radius(coordf_t base_radius, size_t layers_to_top, size_t tip_layers, double diameter_angle_scale_factor);
|
||||||
coordf_t calc_branch_radius(coordf_t base_radius, coordf_t mm_to_top, double diameter_angle_scale_factor);
|
coordf_t calc_branch_radius(coordf_t base_radius, coordf_t mm_to_top, double diameter_angle_scale_factor);
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue