BranchingTree.cpp 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196
  1. #include "BranchingTree.hpp"
  2. #include "PointCloud.hpp"
  3. #include <numeric>
  4. #include <optional>
  5. #include <algorithm>
  6. #include "libslic3r/TriangleMesh.hpp"
  7. namespace Slic3r { namespace branchingtree {
  8. void build_tree(PointCloud &nodes, Builder &builder)
  9. {
  10. constexpr size_t initK = 5;
  11. auto ptsqueue = nodes.start_queue();
  12. auto &properties = nodes.properties();
  13. struct NodeDistance
  14. {
  15. size_t node_id = Node::ID_NONE;
  16. float dst_branching = NaNf;
  17. float dst_euql = NaNf;
  18. };
  19. auto distances = reserve_vector<NodeDistance>(initK);
  20. double prev_dist_max = 0.;
  21. size_t K = initK;
  22. bool routed = true;
  23. size_t node_id = Node::ID_NONE;
  24. while ((!ptsqueue.empty() && builder.is_valid()) || !routed) {
  25. if (routed) {
  26. node_id = ptsqueue.top();
  27. ptsqueue.pop();
  28. }
  29. Node node = nodes.get(node_id);
  30. nodes.mark_unreachable(node_id);
  31. distances.clear();
  32. distances.reserve(K);
  33. float dmax = 0.;
  34. nodes.foreach_reachable(
  35. node.pos,
  36. [&distances, &dmax](size_t id, float dst_branching, float dst_euql) {
  37. distances.emplace_back(NodeDistance{id, dst_branching, dst_euql});
  38. dmax = std::max(dmax, dst_euql);
  39. }, K, prev_dist_max);
  40. std::sort(distances.begin(), distances.end(),
  41. [](auto &a, auto &b) { return a.dst_branching < b.dst_branching; });
  42. if (distances.empty()) {
  43. builder.report_unroutable(node);
  44. K = initK;
  45. prev_dist_max = 0.;
  46. routed = true;
  47. continue;
  48. }
  49. prev_dist_max = dmax;
  50. K *= 2;
  51. auto closest_it = distances.begin();
  52. routed = false;
  53. while (closest_it != distances.end() && !routed && builder.is_valid()) {
  54. size_t closest_node_id = closest_it->node_id;
  55. Node closest_node = nodes.get(closest_node_id);
  56. auto type = nodes.get_type(closest_node_id);
  57. float w = nodes.get(node_id).weight + closest_it->dst_branching;
  58. closest_node.Rmin = std::max(node.Rmin, closest_node.Rmin);
  59. switch (type) {
  60. case BED: {
  61. closest_node.weight = w;
  62. double max_br_len = nodes.properties().max_branch_length();
  63. if (closest_it->dst_branching > max_br_len) {
  64. std::optional<Vec3f> avo = builder.suggest_avoidance(node, max_br_len);
  65. if (!avo)
  66. break;
  67. Node new_node {*avo, node.Rmin};
  68. new_node.weight = nodes.get(node_id).weight + (node.pos - *avo).norm();
  69. new_node.left = node.id;
  70. if ((routed = builder.add_bridge(node, new_node))) {
  71. size_t new_idx = nodes.insert_junction(new_node);
  72. ptsqueue.push(new_idx);
  73. }
  74. } else if ((routed = builder.add_ground_bridge(node, closest_node))) {
  75. closest_node.left = closest_node.right = node_id;
  76. nodes.get(closest_node_id) = closest_node;
  77. nodes.mark_unreachable(closest_node_id);
  78. }
  79. break;
  80. }
  81. case MESH: {
  82. closest_node.weight = w;
  83. if ((routed = builder.add_mesh_bridge(node, closest_node))) {
  84. closest_node.left = closest_node.right = node_id;
  85. nodes.get(closest_node_id) = closest_node;
  86. nodes.mark_unreachable(closest_node_id);
  87. }
  88. break;
  89. }
  90. case LEAF:
  91. case JUNCTION: {
  92. auto max_slope = float(properties.max_slope());
  93. if (auto mergept = find_merge_pt(node.pos, closest_node.pos, max_slope)) {
  94. float mergedist_closest = (*mergept - closest_node.pos).norm();
  95. float mergedist_node = (*mergept - node.pos).norm();
  96. float Wnode = nodes.get(node_id).weight;
  97. float Wclosest = nodes.get(closest_node_id).weight;
  98. float Wsum = std::max(Wnode, Wclosest);
  99. float distsum = std::max(mergedist_closest, mergedist_node);
  100. w = Wsum + distsum;
  101. if (mergedist_closest > EPSILON && mergedist_node > EPSILON) {
  102. Node mergenode{*mergept, closest_node.Rmin};
  103. mergenode.weight = w;
  104. mergenode.id = int(nodes.next_junction_id());
  105. if ((routed = builder.add_merger(node, closest_node, mergenode))) {
  106. mergenode.left = node_id;
  107. mergenode.right = closest_node_id;
  108. size_t new_idx = nodes.insert_junction(mergenode);
  109. ptsqueue.push(new_idx);
  110. size_t qid = nodes.get_queue_idx(closest_node_id);
  111. if (qid != PointCloud::Unqueued)
  112. ptsqueue.remove(nodes.get_queue_idx(closest_node_id));
  113. nodes.mark_unreachable(closest_node_id);
  114. }
  115. } else if (closest_node.pos.z() < node.pos.z() &&
  116. (closest_node.left == Node::ID_NONE ||
  117. closest_node.right == Node::ID_NONE)) {
  118. closest_node.weight = w;
  119. if ((routed = builder.add_bridge(node, closest_node))) {
  120. if (closest_node.left == Node::ID_NONE)
  121. closest_node.left = node_id;
  122. else if (closest_node.right == Node::ID_NONE)
  123. closest_node.right = node_id;
  124. nodes.get(closest_node_id) = closest_node;
  125. }
  126. }
  127. }
  128. break;
  129. }
  130. case NONE:;
  131. }
  132. ++closest_it;
  133. }
  134. if (routed) {
  135. prev_dist_max = 0.;
  136. K = initK;
  137. }
  138. }
  139. }
  140. void build_tree(const indexed_triangle_set &its,
  141. const std::vector<Node> &support_roots,
  142. Builder &builder,
  143. const Properties &properties)
  144. {
  145. PointCloud nodes(its, support_roots, properties);
  146. build_tree(nodes, builder);
  147. }
  148. ExPolygon make_bed_poly(const indexed_triangle_set &its)
  149. {
  150. auto bb = bounding_box(its);
  151. BoundingBox bbcrd{scaled(to_2d(bb.min)), scaled(to_2d(bb.max))};
  152. bbcrd.offset(scaled(10.));
  153. Point min = bbcrd.min, max = bbcrd.max;
  154. ExPolygon ret = {{min.x(), min.y()},
  155. {max.x(), min.y()},
  156. {max.x(), max.y()},
  157. {min.x(), max.y()}};
  158. return ret;
  159. }
  160. }} // namespace Slic3r::branchingtree