Prusa Slicer 2.6.0
Loading...
Searching...
No Matches
Slic3r::branchingtree Namespace Reference

Classes

class  Builder
 
struct  Node
 
class  PointCloud
 
class  Properties
 
struct  TraverseReturnT
 

Enumerations

enum  PtType {
  LEAF , MESH , BED , JUNCTION ,
  NONE
}
 

Functions

void build_tree (PointCloud &nodes, Builder &builder)
 
void build_tree (const indexed_triangle_set &its, const std::vector< Node > &support_roots, Builder &builder, const Properties &properties)
 
ExPolygon make_bed_poly (const indexed_triangle_set &its)
 
bool is_occupied (const Node &n)
 
void build_tree (const indexed_triangle_set &its, const std::vector< Node > &support_leafs, Builder &&builder, const Properties &properties={})
 
std::optional< Vec3ffind_merge_pt (const Vec3f &A, const Vec3f &B, float max_slope)
 
void to_eigen_mesh (const indexed_triangle_set &its, Eigen::MatrixXd &V, Eigen::MatrixXi &F)
 
std::vector< Nodesample_mesh (const indexed_triangle_set &its, double radius)
 
std::vector< Nodesample_bed (const ExPolygons &bed, float z, double radius)
 
BoundingBox3Base< Vec3fget_support_cone_bb (const Vec3f &p, const Properties &props)
 
template<class PC , class Fn >
void traverse (PC &&pc, size_t root, Fn &&fn)
 
void build_tree (PointCloud &&pc, Builder &builder)
 

Variables

template<class Fn >
constexpr bool IsTraverseFn = std::is_invocable_v<Fn, Node&>
 

Class Documentation

◆ Slic3r::branchingtree::TraverseReturnT

struct Slic3r::branchingtree::TraverseReturnT
Class Members
bool to_left: 1
bool to_right: 1

Enumeration Type Documentation

◆ PtType

Enumerator
LEAF 
MESH 
BED 
JUNCTION 
NONE 
30{ LEAF, MESH, BED, JUNCTION, NONE };
@ LEAF
Definition PointCloud.hpp:30
@ NONE
Definition PointCloud.hpp:30
@ BED
Definition PointCloud.hpp:30
@ MESH
Definition PointCloud.hpp:30
@ JUNCTION
Definition PointCloud.hpp:30

Function Documentation

◆ build_tree() [1/4]

void Slic3r::branchingtree::build_tree ( const indexed_triangle_set its,
const std::vector< Node > &  support_leafs,
Builder &&  builder,
const Properties properties = {} 
)
inline
144 {})
145{
146 build_tree(its, support_leafs, builder, properties);
147}

◆ build_tree() [2/4]

void Slic3r::branchingtree::build_tree ( const indexed_triangle_set its,
const std::vector< Node > &  support_roots,
Builder builder,
const Properties properties 
)
175{
176 PointCloud nodes(its, support_roots, properties);
177
178 build_tree(nodes, builder);
179}
Definition PointCloud.hpp:48
void build_tree(PointCloud &nodes, Builder &builder)
Definition BranchingTree.cpp:12

References build_tree().

+ Here is the call graph for this function:

◆ build_tree() [3/4]

void Slic3r::branchingtree::build_tree ( PointCloud &&  pc,
Builder builder 
)
inline
290{
291 build_tree(pc, builder);
292}

References build_tree().

+ Here is the call graph for this function:

◆ build_tree() [4/4]

void Slic3r::branchingtree::build_tree ( PointCloud nodes,
Builder builder 
)
13{
14 constexpr size_t initK = 5;
15
16 auto ptsqueue = nodes.start_queue();
17 auto &properties = nodes.properties();
18
19 struct NodeDistance
20 {
21 size_t node_id = Node::ID_NONE;
22 float dst_branching = NaNf;
23 float dst_euql = NaNf;
24 };
25 auto distances = reserve_vector<NodeDistance>(initK);
26 double prev_dist_max = 0.;
27 size_t K = initK;
28 bool routed = true;
29 size_t node_id = Node::ID_NONE;
30
31 while ((!ptsqueue.empty() && builder.is_valid()) || !routed) {
32 if (routed) {
33 node_id = ptsqueue.top();
34 ptsqueue.pop();
35 }
36
37 Node node = nodes.get(node_id);
38 nodes.mark_unreachable(node_id);
39
40 distances.clear();
41 distances.reserve(K);
42
43 float dmax = 0.;
45 node.pos,
46 [&distances, &dmax](size_t id, float dst_branching, float dst_euql) {
47 distances.emplace_back(NodeDistance{id, dst_branching, dst_euql});
48 dmax = std::max(dmax, dst_euql);
49 }, K, prev_dist_max);
50
51 std::sort(distances.begin(), distances.end(),
52 [](auto &a, auto &b) { return a.dst_branching < b.dst_branching; });
53
54 if (distances.empty()) {
55 builder.report_unroutable(node);
56 K = initK;
57 prev_dist_max = 0.;
58 routed = true;
59
60 continue;
61 }
62
63 prev_dist_max = dmax;
64 K *= 2;
65
66 auto closest_it = distances.begin();
67 routed = false;
68 while (closest_it != distances.end() && !routed && builder.is_valid()) {
69 size_t closest_node_id = closest_it->node_id;
70 Node closest_node = nodes.get(closest_node_id);
71
72 auto type = nodes.get_type(closest_node_id);
73 float w = nodes.get(node_id).weight + closest_it->dst_branching;
74 closest_node.Rmin = std::max(node.Rmin, closest_node.Rmin);
75
76 switch (type) {
77 case BED: {
78 closest_node.weight = w;
79 double max_br_len = nodes.properties().max_branch_length();
80 if (closest_it->dst_branching > max_br_len) {
81 std::optional<Vec3f> avo = builder.suggest_avoidance(node, max_br_len);
82 if (!avo)
83 break;
84
85 Node new_node {*avo, node.Rmin};
86 new_node.weight = nodes.get(node_id).weight + (node.pos - *avo).norm();
87 new_node.left = node.id;
88 if ((routed = builder.add_bridge(node, new_node))) {
89 size_t new_idx = nodes.insert_junction(new_node);
90 ptsqueue.push(new_idx);
91 }
92 } else if ((routed = builder.add_ground_bridge(node, closest_node))) {
93 closest_node.left = closest_node.right = node_id;
94 nodes.get(closest_node_id) = closest_node;
95 nodes.mark_unreachable(closest_node_id);
96 }
97
98 break;
99 }
100 case MESH: {
101 closest_node.weight = w;
102 if ((routed = builder.add_mesh_bridge(node, closest_node))) {
103 closest_node.left = closest_node.right = node_id;
104 nodes.get(closest_node_id) = closest_node;
105 nodes.mark_unreachable(closest_node_id);
106 }
107
108 break;
109 }
110 case LEAF:
111 case JUNCTION: {
112 auto max_slope = float(properties.max_slope());
113
114 if (auto mergept = find_merge_pt(node.pos, closest_node.pos, max_slope)) {
115
116 float mergedist_closest = (*mergept - closest_node.pos).norm();
117 float mergedist_node = (*mergept - node.pos).norm();
118 float Wnode = nodes.get(node_id).weight;
119 float Wclosest = nodes.get(closest_node_id).weight;
120 float Wsum = std::max(Wnode, Wclosest);
121 float distsum = std::max(mergedist_closest, mergedist_node);
122 w = Wsum + distsum;
123
124 if (mergedist_closest > EPSILON && mergedist_node > EPSILON) {
125 Node mergenode{*mergept, closest_node.Rmin};
126 mergenode.weight = w;
127 mergenode.id = int(nodes.next_junction_id());
128
129 if ((routed = builder.add_merger(node, closest_node, mergenode))) {
130 mergenode.left = node_id;
131 mergenode.right = closest_node_id;
132 size_t new_idx = nodes.insert_junction(mergenode);
133 ptsqueue.push(new_idx);
134 size_t qid = nodes.get_queue_idx(closest_node_id);
135
136 if (qid != PointCloud::Unqueued)
137 ptsqueue.remove(nodes.get_queue_idx(closest_node_id));
138
139 nodes.mark_unreachable(closest_node_id);
140 }
141 } else if (closest_node.pos.z() < node.pos.z() &&
142 (closest_node.left == Node::ID_NONE ||
143 closest_node.right == Node::ID_NONE)) {
144 closest_node.weight = w;
145 if ((routed = builder.add_bridge(node, closest_node))) {
146 if (closest_node.left == Node::ID_NONE)
147 closest_node.left = node_id;
148 else if (closest_node.right == Node::ID_NONE)
149 closest_node.right = node_id;
150
151 nodes.get(closest_node_id) = closest_node;
152 }
153 }
154 }
155
156 break;
157 }
158 case NONE:;
159 }
160
161 ++closest_it;
162 }
163
164 if (routed) {
165 prev_dist_max = 0.;
166 K = initK;
167 }
168 }
169}
double BLASFUNC() dmax(int *, double *, int *)
virtual bool add_bridge(const Node &from, const Node &to)=0
virtual bool add_mesh_bridge(const Node &from, const Node &to)=0
virtual bool add_ground_bridge(const Node &from, const Node &to)=0
virtual std::optional< Vec3f > suggest_avoidance(const Node &from, float max_bridge_len) const
Definition BranchingTree.hpp:108
virtual bool is_valid() const
Definition BranchingTree.hpp:118
virtual bool add_merger(const Node &node, const Node &closest, const Node &merge_node)=0
virtual void report_unroutable(const Node &j)=0
PtType get_type(size_t node_id) const
Definition PointCloud.hpp:128
size_t next_junction_id() const
Definition PointCloud.hpp:166
void mark_unreachable(size_t node_id)
Definition PointCloud.hpp:190
size_t insert_junction(const Node &p)
Definition PointCloud.hpp:171
size_t get_queue_idx(size_t node_id) const
Definition PointCloud.hpp:162
const Node & get(size_t node_id) const
Definition PointCloud.hpp:140
const Properties & properties() const noexcept
Definition PointCloud.hpp:188
auto start_queue()
Definition PointCloud.hpp:243
void foreach_reachable(const Vec3f &pos, Fn &&visitor, size_t k, double min_dist=0.)
Definition PointCloud.hpp:202
Properties & max_branch_length(double val) noexcept
Definition BranchingTree.hpp:49
static constexpr double EPSILON
Definition libslic3r.h:51
CGAL::Simple_cartesian< double > K
Definition VoronoiUtilsCgal.cpp:19
std::optional< Vec3f > find_merge_pt(const Vec3f &A, const Vec3f &B, float max_slope)
Definition PointCloud.cpp:10
constexpr float NaNf
Definition libslic3r.h:364
float weight
Definition BranchingTree.hpp:74

References Slic3r::branchingtree::Builder::add_bridge(), Slic3r::branchingtree::Builder::add_ground_bridge(), Slic3r::branchingtree::Builder::add_merger(), Slic3r::branchingtree::Builder::add_mesh_bridge(), BED, dmax(), EPSILON, find_merge_pt(), Slic3r::branchingtree::PointCloud::foreach_reachable(), Slic3r::branchingtree::PointCloud::get(), Slic3r::branchingtree::PointCloud::get_queue_idx(), Slic3r::branchingtree::PointCloud::get_type(), Slic3r::branchingtree::Node::ID_NONE, Slic3r::branchingtree::PointCloud::insert_junction(), Slic3r::branchingtree::Builder::is_valid(), JUNCTION, LEAF, Slic3r::branchingtree::Node::left, Slic3r::branchingtree::PointCloud::mark_unreachable(), Slic3r::branchingtree::Properties::max_branch_length(), MESH, Slic3r::NaNf, Slic3r::branchingtree::PointCloud::next_junction_id(), NONE, Slic3r::branchingtree::Node::pos, Slic3r::branchingtree::PointCloud::properties(), Slic3r::branchingtree::Builder::report_unroutable(), Slic3r::branchingtree::Node::right, Slic3r::branchingtree::Node::Rmin, Slic3r::branchingtree::PointCloud::start_queue(), Slic3r::branchingtree::Builder::suggest_avoidance(), Slic3r::branchingtree::PointCloud::Unqueued, and Slic3r::branchingtree::Node::weight.

Referenced by build_tree(), build_tree(), and Slic3r::sla::create_branching_tree().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ find_merge_pt()

std::optional< Vec3f > Slic3r::branchingtree::find_merge_pt ( const Vec3f A,
const Vec3f B,
float  max_slope 
)
11{
12 return sla::find_merge_pt(A, B, max_slope);
13}

References Slic3r::sla::find_merge_pt().

Referenced by build_tree(), and Slic3r::branchingtree::PointCloud::get_distance().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ get_support_cone_bb()

BoundingBox3Base< Vec3f > Slic3r::branchingtree::get_support_cone_bb ( const Vec3f p,
const Properties props 
)
inline
33{
34 double gnd = props.ground_level() - EPSILON;
35 double h = p.z() - gnd;
36 double phi = PI / 2 - props.max_slope();
37 auto r = float(std::min(h * std::tan(phi), props.max_branch_length() * std::sin(phi)));
38
39 Vec3f bb_min = {p.x() - r, p.y() - r, float(gnd)};
40 Vec3f bb_max = {p.x() + r, p.y() + r, p.z()};
41
42 return {bb_min, bb_max};
43}
Properties & ground_level(double val) noexcept
Definition BranchingTree.hpp:31
Properties & max_slope(double val) noexcept
Definition BranchingTree.hpp:25
static constexpr double PI
Definition libslic3r.h:58

References EPSILON, Slic3r::branchingtree::Properties::ground_level(), Slic3r::branchingtree::Properties::max_branch_length(), Slic3r::branchingtree::Properties::max_slope(), and PI.

+ Here is the call graph for this function:

◆ is_occupied()

bool Slic3r::branchingtree::is_occupied ( const Node n)
inline
81{
82 return n.left != Node::ID_NONE && n.right != Node::ID_NONE;
83}
int left
Definition BranchingTree.hpp:67
int right
Definition BranchingTree.hpp:67

References Slic3r::branchingtree::Node::ID_NONE, Slic3r::branchingtree::Node::left, and Slic3r::branchingtree::Node::right.

◆ make_bed_poly()

ExPolygon Slic3r::branchingtree::make_bed_poly ( const indexed_triangle_set its)
182{
183 auto bb = bounding_box(its);
184
185 BoundingBox bbcrd{scaled(to_2d(bb.min)), scaled(to_2d(bb.max))};
186 bbcrd.offset(scaled(10.));
187 Point min = bbcrd.min, max = bbcrd.max;
188 ExPolygon ret = {{min.x(), min.y()},
189 {max.x(), min.y()},
190 {max.x(), max.y()},
191 {min.x(), max.y()}};
192
193 return ret;
194}
void offset(coordf_t delta)
Definition BoundingBox.cpp:175
Definition BoundingBox.hpp:181
Definition ExPolygon.hpp:16
Definition Point.hpp:158
EIGEN_STRONG_INLINE EIGEN_DEVICE_FUNC half() min(const half &a, const half &b)
Definition Half.h:507
EIGEN_STRONG_INLINE EIGEN_DEVICE_FUNC half() max(const half &a, const half &b)
Definition Half.h:516
BoundingBox scaled(const BoundingBoxf &bb)
Definition BoundingBox.hpp:240
Eigen::Matrix< typename Derived::Scalar, 2, 1, Eigen::DontAlign > to_2d(const Eigen::MatrixBase< Derived > &ptN)
Definition Point.hpp:121
unsigned short x
Definition Half.h:57

References Slic3r::bounding_box(), make_bed_poly(), Slic3r::BoundingBoxBase< PointType, APointsType >::offset(), Slic3r::scaled(), Slic3r::to_2d(), and Eigen::half_impl::__half_raw::x.

Referenced by Slic3r::sla::create_branching_tree(), and make_bed_poly().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ sample_bed()

std::vector< Node > Slic3r::branchingtree::sample_bed ( const ExPolygons bed,
float  z,
double  radius 
)
76{
77 auto triangles = triangulate_expolygons_3d(bed, z);
79 its.vertices.reserve(triangles.size());
80
81 for (size_t i = 0; i < triangles.size(); i += 3) {
82 its.vertices.emplace_back(triangles[i].cast<float>());
83 its.vertices.emplace_back(triangles[i + 1].cast<float>());
84 its.vertices.emplace_back(triangles[i + 2].cast<float>());
85
86 its.indices.emplace_back(i, i + 1, i + 2);
87 }
88
89 return sample_mesh(its, radius);
90}
std::vector< Vec3d > triangulate_expolygons_3d(const ExPolygons &polys, coordf_t z, bool flip)
Definition Tesselate.cpp:198
Definition stl.h:157
std::vector< stl_vertex > vertices
Definition stl.h:165
std::vector< stl_triangle_vertex_indices > indices
Definition stl.h:164

References indexed_triangle_set::indices, sample_mesh(), Slic3r::triangulate_expolygons_3d(), and indexed_triangle_set::vertices.

Referenced by Slic3r::sla::create_branching_tree().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ sample_mesh()

std::vector< Node > Slic3r::branchingtree::sample_mesh ( const indexed_triangle_set its,
double  radius 
)
29{
30 std::vector<Node> ret;
31
32 double surface_area = 0.;
33 for (const Vec3i &face : its.indices) {
34 std::array<Vec3f, 3> tri = {its.vertices[face(0)],
35 its.vertices[face(1)],
36 its.vertices[face(2)]};
37
38 auto U = tri[1] - tri[0], V = tri[2] - tri[0];
39 surface_area += 0.5 * U.cross(V).norm();
40 }
41
42 int N = surface_area / (PI * radius * radius);
43
44 Eigen::MatrixXd B;
45 Eigen::MatrixXi FI;
46 Eigen::MatrixXd V;
47 Eigen::MatrixXi F;
48 to_eigen_mesh(its, V, F);
49 igl::random_points_on_mesh(N, V, F, B, FI);
50
51 ret.reserve(size_t(N));
52 for (int i = 0; i < FI.size(); i++) {
53 int face_id = FI(i);
54
55 if (face_id < 0 || face_id >= int(its.indices.size()))
56 continue;
57
58 Vec3i face = its.indices[face_id];
59
60 if (face(0) >= int(its.vertices.size()) ||
61 face(1) >= int(its.vertices.size()) ||
62 face(2) >= int(its.vertices.size()))
63 continue;
64
65 Vec3f c = B.row(i)(0) * its.vertices[face(0)] +
66 B.row(i)(1) * its.vertices[face(1)] +
67 B.row(i)(2) * its.vertices[face(2)];
68
69 ret.emplace_back(c);
70 }
71
72 return ret;
73}
IGL_INLINE void random_points_on_mesh(const int n, const Eigen::PlainObjectBase< DerivedV > &V, const Eigen::PlainObjectBase< DerivedF > &F, Eigen::PlainObjectBase< DerivedB > &B, Eigen::PlainObjectBase< DerivedFI > &FI)
Definition random_points_on_mesh.cpp:16

References Slic3r::F, indexed_triangle_set::indices, PI, igl::random_points_on_mesh(), to_eigen_mesh(), and indexed_triangle_set::vertices.

Referenced by Slic3r::sla::create_branching_tree(), and sample_bed().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ to_eigen_mesh()

void Slic3r::branchingtree::to_eigen_mesh ( const indexed_triangle_set its,
Eigen::MatrixXd &  V,
Eigen::MatrixXi &  F 
)
18{
19 V.resize(its.vertices.size(), 3);
20 F.resize(its.indices.size(), 3);
21 for (unsigned int i = 0; i < its.indices.size(); ++i)
22 F.row(i) = its.indices[i];
23
24 for (unsigned int i = 0; i < its.vertices.size(); ++i)
25 V.row(i) = its.vertices[i].cast<double>();
26}
@ F
Definition libslic3r.h:102

References Slic3r::F, indexed_triangle_set::indices, and indexed_triangle_set::vertices.

Referenced by sample_mesh().

+ Here is the caller graph for this function:

◆ traverse()

template<class PC , class Fn >
void Slic3r::branchingtree::traverse ( PC &&  pc,
size_t  root,
Fn &&  fn 
)
267{
268 if (auto nodeptr = pc.find(root); nodeptr != nullptr) {
269 auto &nroot = *nodeptr;
270 TraverseReturnT ret{true, true};
271
272 if constexpr (std::is_same_v<std::invoke_result_t<Fn, decltype(nroot)>, void>) {
273 // Our fn has no return value
274 fn(nroot);
275 } else {
276 // Fn returns instructions about how to continue traversing
277 ret = fn(nroot);
278 }
279
280 if (ret.to_left && nroot.left >= 0)
281 traverse(pc, nroot.left, fn);
282 if (ret.to_right && nroot.right >= 0)
283 traverse(pc, nroot.right, fn);
284 }
285}
void traverse(const Tree< Dims, T > &tree, Predicate &&pred, Fn &&callback)
Definition AABBTreeIndirect.hpp:981
Definition PointCloud.hpp:261

References traverse().

Referenced by traverse().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

Variable Documentation

◆ IsTraverseFn

template<class Fn >
constexpr bool Slic3r::branchingtree::IsTraverseFn = std::is_invocable_v<Fn, Node&>
constexpr