123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196 |
- #include "BranchingTree.hpp"
- #include "PointCloud.hpp"
- #include <numeric>
- #include <optional>
- #include <algorithm>
- #include "libslic3r/TriangleMesh.hpp"
- namespace Slic3r { namespace branchingtree {
- void build_tree(PointCloud &nodes, Builder &builder)
- {
- constexpr size_t initK = 5;
- auto ptsqueue = nodes.start_queue();
- auto &properties = nodes.properties();
- struct NodeDistance
- {
- size_t node_id = Node::ID_NONE;
- float dst_branching = NaNf;
- float dst_euql = NaNf;
- };
- auto distances = reserve_vector<NodeDistance>(initK);
- double prev_dist_max = 0.;
- size_t K = initK;
- bool routed = true;
- size_t node_id = Node::ID_NONE;
- while ((!ptsqueue.empty() && builder.is_valid()) || !routed) {
- if (routed) {
- node_id = ptsqueue.top();
- ptsqueue.pop();
- }
- Node node = nodes.get(node_id);
- nodes.mark_unreachable(node_id);
- distances.clear();
- distances.reserve(K);
- float dmax = 0.;
- nodes.foreach_reachable(
- node.pos,
- [&distances, &dmax](size_t id, float dst_branching, float dst_euql) {
- distances.emplace_back(NodeDistance{id, dst_branching, dst_euql});
- dmax = std::max(dmax, dst_euql);
- }, K, prev_dist_max);
- std::sort(distances.begin(), distances.end(),
- [](auto &a, auto &b) { return a.dst_branching < b.dst_branching; });
- if (distances.empty()) {
- builder.report_unroutable(node);
- K = initK;
- prev_dist_max = 0.;
- routed = true;
- continue;
- }
- prev_dist_max = dmax;
- K *= 2;
- auto closest_it = distances.begin();
- routed = false;
- while (closest_it != distances.end() && !routed && builder.is_valid()) {
- size_t closest_node_id = closest_it->node_id;
- Node closest_node = nodes.get(closest_node_id);
- auto type = nodes.get_type(closest_node_id);
- float w = nodes.get(node_id).weight + closest_it->dst_branching;
- closest_node.Rmin = std::max(node.Rmin, closest_node.Rmin);
- switch (type) {
- case BED: {
- closest_node.weight = w;
- double max_br_len = nodes.properties().max_branch_length();
- if (closest_it->dst_branching > max_br_len) {
- std::optional<Vec3f> avo = builder.suggest_avoidance(node, max_br_len);
- if (!avo)
- break;
- Node new_node {*avo, node.Rmin};
- new_node.weight = nodes.get(node_id).weight + (node.pos - *avo).norm();
- new_node.left = node.id;
- if ((routed = builder.add_bridge(node, new_node))) {
- size_t new_idx = nodes.insert_junction(new_node);
- ptsqueue.push(new_idx);
- }
- } else if ((routed = builder.add_ground_bridge(node, closest_node))) {
- closest_node.left = closest_node.right = node_id;
- nodes.get(closest_node_id) = closest_node;
- nodes.mark_unreachable(closest_node_id);
- }
- break;
- }
- case MESH: {
- closest_node.weight = w;
- if ((routed = builder.add_mesh_bridge(node, closest_node))) {
- closest_node.left = closest_node.right = node_id;
- nodes.get(closest_node_id) = closest_node;
- nodes.mark_unreachable(closest_node_id);
- }
- break;
- }
- case LEAF:
- case JUNCTION: {
- auto max_slope = float(properties.max_slope());
- if (auto mergept = find_merge_pt(node.pos, closest_node.pos, max_slope)) {
- float mergedist_closest = (*mergept - closest_node.pos).norm();
- float mergedist_node = (*mergept - node.pos).norm();
- float Wnode = nodes.get(node_id).weight;
- float Wclosest = nodes.get(closest_node_id).weight;
- float Wsum = std::max(Wnode, Wclosest);
- float distsum = std::max(mergedist_closest, mergedist_node);
- w = Wsum + distsum;
- if (mergedist_closest > EPSILON && mergedist_node > EPSILON) {
- Node mergenode{*mergept, closest_node.Rmin};
- mergenode.weight = w;
- mergenode.id = int(nodes.next_junction_id());
- if ((routed = builder.add_merger(node, closest_node, mergenode))) {
- mergenode.left = node_id;
- mergenode.right = closest_node_id;
- size_t new_idx = nodes.insert_junction(mergenode);
- ptsqueue.push(new_idx);
- size_t qid = nodes.get_queue_idx(closest_node_id);
- if (qid != PointCloud::Unqueued)
- ptsqueue.remove(nodes.get_queue_idx(closest_node_id));
- nodes.mark_unreachable(closest_node_id);
- }
- } else if (closest_node.pos.z() < node.pos.z() &&
- (closest_node.left == Node::ID_NONE ||
- closest_node.right == Node::ID_NONE)) {
- closest_node.weight = w;
- if ((routed = builder.add_bridge(node, closest_node))) {
- if (closest_node.left == Node::ID_NONE)
- closest_node.left = node_id;
- else if (closest_node.right == Node::ID_NONE)
- closest_node.right = node_id;
- nodes.get(closest_node_id) = closest_node;
- }
- }
- }
- break;
- }
- case NONE:;
- }
- ++closest_it;
- }
- if (routed) {
- prev_dist_max = 0.;
- K = initK;
- }
- }
- }
- void build_tree(const indexed_triangle_set &its,
- const std::vector<Node> &support_roots,
- Builder &builder,
- const Properties &properties)
- {
- PointCloud nodes(its, support_roots, properties);
- build_tree(nodes, builder);
- }
- ExPolygon make_bed_poly(const indexed_triangle_set &its)
- {
- auto bb = bounding_box(its);
- BoundingBox bbcrd{scaled(to_2d(bb.min)), scaled(to_2d(bb.max))};
- bbcrd.offset(scaled(10.));
- Point min = bbcrd.min, max = bbcrd.max;
- ExPolygon ret = {{min.x(), min.y()},
- {max.x(), min.y()},
- {max.x(), max.y()},
- {min.x(), max.y()}};
- return ret;
- }
- }} // namespace Slic3r::branchingtree
|