graph_edit_arranger.cpp 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559
  1. /**************************************************************************/
  2. /* graph_edit_arranger.cpp */
  3. /**************************************************************************/
  4. /* This file is part of: */
  5. /* GODOT ENGINE */
  6. /* https://godotengine.org */
  7. /**************************************************************************/
  8. /* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
  9. /* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
  10. /* */
  11. /* Permission is hereby granted, free of charge, to any person obtaining */
  12. /* a copy of this software and associated documentation files (the */
  13. /* "Software"), to deal in the Software without restriction, including */
  14. /* without limitation the rights to use, copy, modify, merge, publish, */
  15. /* distribute, sublicense, and/or sell copies of the Software, and to */
  16. /* permit persons to whom the Software is furnished to do so, subject to */
  17. /* the following conditions: */
  18. /* */
  19. /* The above copyright notice and this permission notice shall be */
  20. /* included in all copies or substantial portions of the Software. */
  21. /* */
  22. /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
  23. /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
  24. /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
  25. /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
  26. /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
  27. /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
  28. /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
  29. /**************************************************************************/
  30. #include "graph_edit_arranger.h"
  31. #include "scene/gui/graph_edit.h"
  32. void GraphEditArranger::arrange_nodes() {
  33. ERR_FAIL_NULL(graph_edit);
  34. if (!arranging_graph) {
  35. arranging_graph = true;
  36. } else {
  37. return;
  38. }
  39. Dictionary node_names;
  40. HashSet<StringName> selected_nodes;
  41. bool arrange_entire_graph = true;
  42. for (int i = graph_edit->get_child_count() - 1; i >= 0; i--) {
  43. GraphNode *graph_element = Object::cast_to<GraphNode>(graph_edit->get_child(i));
  44. if (!graph_element) {
  45. continue;
  46. }
  47. node_names[graph_element->get_name()] = graph_element;
  48. if (graph_element->is_selected()) {
  49. arrange_entire_graph = false;
  50. }
  51. }
  52. HashMap<StringName, HashSet<StringName>> upper_neighbours;
  53. HashMap<StringName, Pair<int, int>> port_info;
  54. Vector2 origin(FLT_MAX, FLT_MAX);
  55. float gap_v = 100.0f;
  56. float gap_h = 100.0f;
  57. List<GraphEdit::Connection> connection_list;
  58. graph_edit->get_connection_list(&connection_list);
  59. for (int i = graph_edit->get_child_count() - 1; i >= 0; i--) {
  60. GraphNode *graph_element = Object::cast_to<GraphNode>(graph_edit->get_child(i));
  61. if (!graph_element) {
  62. continue;
  63. }
  64. if (graph_element->is_selected() || arrange_entire_graph) {
  65. selected_nodes.insert(graph_element->get_name());
  66. HashSet<StringName> s;
  67. for (List<GraphEdit::Connection>::Element *E = connection_list.front(); E; E = E->next()) {
  68. GraphNode *p_from = Object::cast_to<GraphNode>(node_names[E->get().from_node]);
  69. if (E->get().to_node == graph_element->get_name() && (p_from->is_selected() || arrange_entire_graph) && E->get().to_node != E->get().from_node) {
  70. if (!s.has(p_from->get_name())) {
  71. s.insert(p_from->get_name());
  72. }
  73. String s_connection = String(p_from->get_name()) + " " + String(E->get().to_node);
  74. StringName _connection(s_connection);
  75. Pair<int, int> ports(E->get().from_port, E->get().to_port);
  76. port_info.insert(_connection, ports);
  77. }
  78. }
  79. upper_neighbours.insert(graph_element->get_name(), s);
  80. }
  81. }
  82. if (!selected_nodes.size()) {
  83. arranging_graph = false;
  84. return;
  85. }
  86. HashMap<int, Vector<StringName>> layers = _layering(selected_nodes, upper_neighbours);
  87. _crossing_minimisation(layers, upper_neighbours);
  88. Dictionary root, align, sink, shift;
  89. _horizontal_alignment(root, align, layers, upper_neighbours, selected_nodes);
  90. HashMap<StringName, Vector2> new_positions;
  91. Vector2 default_position(FLT_MAX, FLT_MAX);
  92. Dictionary inner_shift;
  93. HashSet<StringName> block_heads;
  94. for (const StringName &E : selected_nodes) {
  95. inner_shift[E] = 0.0f;
  96. sink[E] = E;
  97. shift[E] = FLT_MAX;
  98. new_positions.insert(E, default_position);
  99. if ((StringName)root[E] == E) {
  100. block_heads.insert(E);
  101. }
  102. }
  103. _calculate_inner_shifts(inner_shift, root, node_names, align, block_heads, port_info);
  104. for (const StringName &E : block_heads) {
  105. _place_block(E, gap_v, layers, root, align, node_names, inner_shift, sink, shift, new_positions);
  106. }
  107. origin.y = Object::cast_to<GraphNode>(node_names[layers[0][0]])->get_position_offset().y - (new_positions[layers[0][0]].y + (float)inner_shift[layers[0][0]]);
  108. origin.x = Object::cast_to<GraphNode>(node_names[layers[0][0]])->get_position_offset().x;
  109. for (const StringName &E : block_heads) {
  110. StringName u = E;
  111. float start_from = origin.y + new_positions[E].y;
  112. do {
  113. Vector2 cal_pos;
  114. cal_pos.y = start_from + (real_t)inner_shift[u];
  115. new_positions.insert(u, cal_pos);
  116. u = align[u];
  117. } while (u != E);
  118. }
  119. // Compute horizontal coordinates individually for layers to get uniform gap.
  120. float start_from = origin.x;
  121. float largest_node_size = 0.0f;
  122. for (unsigned int i = 0; i < layers.size(); i++) {
  123. Vector<StringName> layer = layers[i];
  124. for (int j = 0; j < layer.size(); j++) {
  125. float current_node_size = Object::cast_to<GraphNode>(node_names[layer[j]])->get_size().x;
  126. largest_node_size = MAX(largest_node_size, current_node_size);
  127. }
  128. for (int j = 0; j < layer.size(); j++) {
  129. float current_node_size = Object::cast_to<GraphNode>(node_names[layer[j]])->get_size().x;
  130. Vector2 cal_pos = new_positions[layer[j]];
  131. if (current_node_size == largest_node_size) {
  132. cal_pos.x = start_from;
  133. } else {
  134. float current_node_start_pos = start_from;
  135. if (current_node_size < largest_node_size / 2) {
  136. if (!(i || j)) {
  137. start_from -= (largest_node_size - current_node_size);
  138. }
  139. current_node_start_pos = start_from + largest_node_size - current_node_size;
  140. }
  141. cal_pos.x = current_node_start_pos;
  142. }
  143. new_positions.insert(layer[j], cal_pos);
  144. }
  145. start_from += largest_node_size + gap_h;
  146. largest_node_size = 0.0f;
  147. }
  148. graph_edit->emit_signal(SNAME("begin_node_move"));
  149. for (const StringName &E : selected_nodes) {
  150. GraphNode *graph_node = Object::cast_to<GraphNode>(node_names[E]);
  151. graph_node->set_drag(true);
  152. Vector2 pos = (new_positions[E]);
  153. if (graph_edit->is_snapping_enabled()) {
  154. float snapping_distance = graph_edit->get_snapping_distance();
  155. pos = pos.snapped(Vector2(snapping_distance, snapping_distance));
  156. }
  157. graph_node->set_position_offset(pos);
  158. graph_node->set_drag(false);
  159. }
  160. graph_edit->emit_signal(SNAME("end_node_move"));
  161. arranging_graph = false;
  162. }
  163. int GraphEditArranger::_set_operations(SET_OPERATIONS p_operation, HashSet<StringName> &r_u, const HashSet<StringName> &r_v) {
  164. switch (p_operation) {
  165. case GraphEditArranger::IS_EQUAL: {
  166. for (const StringName &E : r_u) {
  167. if (!r_v.has(E)) {
  168. return 0;
  169. }
  170. }
  171. return r_u.size() == r_v.size();
  172. } break;
  173. case GraphEditArranger::IS_SUBSET: {
  174. if (r_u.size() == r_v.size() && !r_u.size()) {
  175. return 1;
  176. }
  177. for (const StringName &E : r_u) {
  178. if (!r_v.has(E)) {
  179. return 0;
  180. }
  181. }
  182. return 1;
  183. } break;
  184. case GraphEditArranger::DIFFERENCE: {
  185. Vector<StringName> common;
  186. for (const StringName &E : r_u) {
  187. if (r_v.has(E)) {
  188. common.append(E);
  189. }
  190. }
  191. for (const StringName &E : common) {
  192. r_u.erase(E);
  193. }
  194. return r_u.size();
  195. } break;
  196. case GraphEditArranger::UNION: {
  197. for (const StringName &E : r_v) {
  198. if (!r_u.has(E)) {
  199. r_u.insert(E);
  200. }
  201. }
  202. return r_u.size();
  203. } break;
  204. default:
  205. break;
  206. }
  207. return -1;
  208. }
  209. HashMap<int, Vector<StringName>> GraphEditArranger::_layering(const HashSet<StringName> &r_selected_nodes, const HashMap<StringName, HashSet<StringName>> &r_upper_neighbours) {
  210. HashMap<int, Vector<StringName>> l;
  211. HashSet<StringName> p = r_selected_nodes, q = r_selected_nodes, u, z;
  212. int current_layer = 0;
  213. bool selected = false;
  214. while (!_set_operations(GraphEditArranger::IS_EQUAL, q, u)) {
  215. _set_operations(GraphEditArranger::DIFFERENCE, p, u);
  216. for (const StringName &E : p) {
  217. HashSet<StringName> n = r_upper_neighbours[E];
  218. if (_set_operations(GraphEditArranger::IS_SUBSET, n, z)) {
  219. Vector<StringName> t;
  220. t.push_back(E);
  221. if (!l.has(current_layer)) {
  222. l.insert(current_layer, Vector<StringName>{});
  223. }
  224. selected = true;
  225. t.append_array(l[current_layer]);
  226. l.insert(current_layer, t);
  227. u.insert(E);
  228. }
  229. }
  230. if (!selected) {
  231. current_layer++;
  232. uint32_t previous_size_z = z.size();
  233. _set_operations(GraphEditArranger::UNION, z, u);
  234. if (z.size() == previous_size_z) {
  235. WARN_PRINT("Graph contains cycle(s). The cycle(s) will not be rearranged accurately.");
  236. Vector<StringName> t;
  237. if (l.has(0)) {
  238. t.append_array(l[0]);
  239. }
  240. for (const StringName &E : p) {
  241. t.push_back(E);
  242. }
  243. l.insert(0, t);
  244. break;
  245. }
  246. }
  247. selected = false;
  248. }
  249. return l;
  250. }
  251. Vector<StringName> GraphEditArranger::_split(const Vector<StringName> &r_layer, const HashMap<StringName, Dictionary> &r_crossings) {
  252. if (!r_layer.size()) {
  253. return Vector<StringName>();
  254. }
  255. const StringName &p = r_layer[Math::random(0, r_layer.size() - 1)];
  256. Vector<StringName> left;
  257. Vector<StringName> right;
  258. for (int i = 0; i < r_layer.size(); i++) {
  259. if (p != r_layer[i]) {
  260. const StringName &q = r_layer[i];
  261. int cross_pq = r_crossings[p][q];
  262. int cross_qp = r_crossings[q][p];
  263. if (cross_pq > cross_qp) {
  264. left.push_back(q);
  265. } else {
  266. right.push_back(q);
  267. }
  268. }
  269. }
  270. left.push_back(p);
  271. left.append_array(right);
  272. return left;
  273. }
  274. void GraphEditArranger::_horizontal_alignment(Dictionary &r_root, Dictionary &r_align, const HashMap<int, Vector<StringName>> &r_layers, const HashMap<StringName, HashSet<StringName>> &r_upper_neighbours, const HashSet<StringName> &r_selected_nodes) {
  275. for (const StringName &E : r_selected_nodes) {
  276. r_root[E] = E;
  277. r_align[E] = E;
  278. }
  279. if (r_layers.size() == 1) {
  280. return;
  281. }
  282. for (unsigned int i = 1; i < r_layers.size(); i++) {
  283. Vector<StringName> lower_layer = r_layers[i];
  284. Vector<StringName> upper_layer = r_layers[i - 1];
  285. int r = -1;
  286. for (int j = 0; j < lower_layer.size(); j++) {
  287. Vector<Pair<int, StringName>> up;
  288. const StringName &current_node = lower_layer[j];
  289. for (int k = 0; k < upper_layer.size(); k++) {
  290. const StringName &adjacent_neighbour = upper_layer[k];
  291. if (r_upper_neighbours[current_node].has(adjacent_neighbour)) {
  292. up.push_back(Pair<int, StringName>(k, adjacent_neighbour));
  293. }
  294. }
  295. int start = (up.size() - 1) / 2;
  296. int end = (up.size() - 1) % 2 ? start + 1 : start;
  297. for (int p = start; p <= end; p++) {
  298. StringName Align = r_align[current_node];
  299. if (Align == current_node && r < up[p].first) {
  300. r_align[up[p].second] = lower_layer[j];
  301. r_root[current_node] = r_root[up[p].second];
  302. r_align[current_node] = r_root[up[p].second];
  303. r = up[p].first;
  304. }
  305. }
  306. }
  307. }
  308. }
  309. void GraphEditArranger::_crossing_minimisation(HashMap<int, Vector<StringName>> &r_layers, const HashMap<StringName, HashSet<StringName>> &r_upper_neighbours) {
  310. if (r_layers.size() == 1) {
  311. return;
  312. }
  313. for (unsigned int i = 1; i < r_layers.size(); i++) {
  314. Vector<StringName> upper_layer = r_layers[i - 1];
  315. Vector<StringName> lower_layer = r_layers[i];
  316. HashMap<StringName, Dictionary> c;
  317. for (int j = 0; j < lower_layer.size(); j++) {
  318. const StringName &p = lower_layer[j];
  319. Dictionary d;
  320. for (int k = 0; k < lower_layer.size(); k++) {
  321. unsigned int crossings = 0;
  322. const StringName &q = lower_layer[k];
  323. if (j != k) {
  324. for (int h = 1; h < upper_layer.size(); h++) {
  325. if (r_upper_neighbours[p].has(upper_layer[h])) {
  326. for (int g = 0; g < h; g++) {
  327. if (r_upper_neighbours[q].has(upper_layer[g])) {
  328. crossings++;
  329. }
  330. }
  331. }
  332. }
  333. }
  334. d[q] = crossings;
  335. }
  336. c.insert(p, d);
  337. }
  338. r_layers.insert(i, _split(lower_layer, c));
  339. }
  340. }
  341. void GraphEditArranger::_calculate_inner_shifts(Dictionary &r_inner_shifts, const Dictionary &r_root, const Dictionary &r_node_names, const Dictionary &r_align, const HashSet<StringName> &r_block_heads, const HashMap<StringName, Pair<int, int>> &r_port_info) {
  342. for (const StringName &E : r_block_heads) {
  343. real_t left = 0;
  344. StringName u = E;
  345. StringName v = r_align[u];
  346. while (u != v && (StringName)r_root[u] != v) {
  347. String _connection = String(u) + " " + String(v);
  348. GraphNode *gnode_from = Object::cast_to<GraphNode>(r_node_names[u]);
  349. GraphNode *gnode_to = Object::cast_to<GraphNode>(r_node_names[v]);
  350. Pair<int, int> ports = r_port_info[_connection];
  351. int port_from = ports.first;
  352. int port_to = ports.second;
  353. Vector2 pos_from = gnode_from->get_output_port_position(port_from) * graph_edit->get_zoom();
  354. Vector2 pos_to = gnode_to->get_input_port_position(port_to) * graph_edit->get_zoom();
  355. real_t s = (real_t)r_inner_shifts[u] + (pos_from.y - pos_to.y) / graph_edit->get_zoom();
  356. r_inner_shifts[v] = s;
  357. left = MIN(left, s);
  358. u = v;
  359. v = (StringName)r_align[v];
  360. }
  361. u = E;
  362. do {
  363. r_inner_shifts[u] = (real_t)r_inner_shifts[u] - left;
  364. u = (StringName)r_align[u];
  365. } while (u != E);
  366. }
  367. }
  368. float GraphEditArranger::_calculate_threshold(StringName p_v, StringName p_w, const Dictionary &r_node_names, const HashMap<int, Vector<StringName>> &r_layers, const Dictionary &r_root, const Dictionary &r_align, const Dictionary &r_inner_shift, real_t p_current_threshold, const HashMap<StringName, Vector2> &r_node_positions) {
  369. #define MAX_ORDER 2147483647
  370. #define ORDER(node, layers) \
  371. for (unsigned int i = 0; i < layers.size(); i++) { \
  372. int index = layers[i].find(node); \
  373. if (index > 0) { \
  374. order = index; \
  375. break; \
  376. } \
  377. order = MAX_ORDER; \
  378. }
  379. int order = MAX_ORDER;
  380. float threshold = p_current_threshold;
  381. if (p_v == p_w) {
  382. int min_order = MAX_ORDER;
  383. GraphEdit::Connection incoming;
  384. List<GraphEdit::Connection> connection_list;
  385. graph_edit->get_connection_list(&connection_list);
  386. for (List<GraphEdit::Connection>::Element *E = connection_list.front(); E; E = E->next()) {
  387. if (E->get().to_node == p_w) {
  388. ORDER(E->get().from_node, r_layers);
  389. if (min_order > order) {
  390. min_order = order;
  391. incoming = E->get();
  392. }
  393. }
  394. }
  395. if (incoming.from_node != StringName()) {
  396. GraphNode *gnode_from = Object::cast_to<GraphNode>(r_node_names[incoming.from_node]);
  397. GraphNode *gnode_to = Object::cast_to<GraphNode>(r_node_names[p_w]);
  398. Vector2 pos_from = gnode_from->get_output_port_position(incoming.from_port) * graph_edit->get_zoom();
  399. Vector2 pos_to = gnode_to->get_input_port_position(incoming.to_port) * graph_edit->get_zoom();
  400. // If connected block node is selected, calculate thershold or add current block to list.
  401. if (gnode_from->is_selected()) {
  402. Vector2 connected_block_pos = r_node_positions[r_root[incoming.from_node]];
  403. if (connected_block_pos.y != FLT_MAX) {
  404. //Connected block is placed, calculate threshold.
  405. threshold = connected_block_pos.y + (real_t)r_inner_shift[incoming.from_node] - (real_t)r_inner_shift[p_w] + pos_from.y - pos_to.y;
  406. }
  407. }
  408. }
  409. }
  410. if (threshold == FLT_MIN && (StringName)r_align[p_w] == p_v) {
  411. // This time, pick an outgoing edge and repeat as above!
  412. int min_order = MAX_ORDER;
  413. GraphEdit::Connection outgoing;
  414. List<GraphEdit::Connection> connection_list;
  415. graph_edit->get_connection_list(&connection_list);
  416. for (List<GraphEdit::Connection>::Element *E = connection_list.front(); E; E = E->next()) {
  417. if (E->get().from_node == p_w) {
  418. ORDER(E->get().to_node, r_layers);
  419. if (min_order > order) {
  420. min_order = order;
  421. outgoing = E->get();
  422. }
  423. }
  424. }
  425. if (outgoing.to_node != StringName()) {
  426. GraphNode *gnode_from = Object::cast_to<GraphNode>(r_node_names[p_w]);
  427. GraphNode *gnode_to = Object::cast_to<GraphNode>(r_node_names[outgoing.to_node]);
  428. Vector2 pos_from = gnode_from->get_output_port_position(outgoing.from_port) * graph_edit->get_zoom();
  429. Vector2 pos_to = gnode_to->get_input_port_position(outgoing.to_port) * graph_edit->get_zoom();
  430. // If connected block node is selected, calculate thershold or add current block to list.
  431. if (gnode_to->is_selected()) {
  432. Vector2 connected_block_pos = r_node_positions[r_root[outgoing.to_node]];
  433. if (connected_block_pos.y != FLT_MAX) {
  434. //Connected block is placed. Calculate threshold
  435. threshold = connected_block_pos.y + (real_t)r_inner_shift[outgoing.to_node] - (real_t)r_inner_shift[p_w] + pos_from.y - pos_to.y;
  436. }
  437. }
  438. }
  439. }
  440. #undef MAX_ORDER
  441. #undef ORDER
  442. return threshold;
  443. }
  444. void GraphEditArranger::_place_block(StringName p_v, float p_delta, const HashMap<int, Vector<StringName>> &r_layers, const Dictionary &r_root, const Dictionary &r_align, const Dictionary &r_node_name, const Dictionary &r_inner_shift, Dictionary &r_sink, Dictionary &r_shift, HashMap<StringName, Vector2> &r_node_positions) {
  445. #define PRED(node, layers) \
  446. for (unsigned int i = 0; i < layers.size(); i++) { \
  447. int index = layers[i].find(node); \
  448. if (index > 0) { \
  449. predecessor = layers[i][index - 1]; \
  450. break; \
  451. } \
  452. predecessor = StringName(); \
  453. }
  454. StringName predecessor;
  455. StringName successor;
  456. Vector2 pos = r_node_positions[p_v];
  457. if (pos.y == FLT_MAX) {
  458. pos.y = 0;
  459. bool initial = false;
  460. StringName w = p_v;
  461. real_t threshold = FLT_MIN;
  462. do {
  463. PRED(w, r_layers);
  464. if (predecessor != StringName()) {
  465. StringName u = r_root[predecessor];
  466. _place_block(u, p_delta, r_layers, r_root, r_align, r_node_name, r_inner_shift, r_sink, r_shift, r_node_positions);
  467. threshold = _calculate_threshold(p_v, w, r_node_name, r_layers, r_root, r_align, r_inner_shift, threshold, r_node_positions);
  468. if ((StringName)r_sink[p_v] == p_v) {
  469. r_sink[p_v] = r_sink[u];
  470. }
  471. Vector2 predecessor_root_pos = r_node_positions[u];
  472. Vector2 predecessor_node_size = Object::cast_to<GraphNode>(r_node_name[predecessor])->get_size();
  473. if (r_sink[p_v] != r_sink[u]) {
  474. real_t sc = pos.y + (real_t)r_inner_shift[w] - predecessor_root_pos.y - (real_t)r_inner_shift[predecessor] - predecessor_node_size.y - p_delta;
  475. r_shift[r_sink[u]] = MIN(sc, (real_t)r_shift[r_sink[u]]);
  476. } else {
  477. real_t sb = predecessor_root_pos.y + (real_t)r_inner_shift[predecessor] + predecessor_node_size.y - (real_t)r_inner_shift[w] + p_delta;
  478. sb = MAX(sb, threshold);
  479. if (initial) {
  480. pos.y = sb;
  481. } else {
  482. pos.y = MAX(pos.y, sb);
  483. }
  484. initial = false;
  485. }
  486. }
  487. threshold = _calculate_threshold(p_v, w, r_node_name, r_layers, r_root, r_align, r_inner_shift, threshold, r_node_positions);
  488. w = r_align[w];
  489. } while (w != p_v);
  490. r_node_positions.insert(p_v, pos);
  491. }
  492. #undef PRED
  493. }