flat.c 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339
  1. /*************************************************************************
  2. * Copyright (c) 2011 AT&T Intellectual Property
  3. * All rights reserved. This program and the accompanying materials
  4. * are made available under the terms of the Eclipse Public License v1.0
  5. * which accompanies this distribution, and is available at
  6. * https://www.eclipse.org/legal/epl-v10.html
  7. *
  8. * Contributors: Details at https://graphviz.org
  9. *************************************************************************/
  10. #include <dotgen/dot.h>
  11. #include <stdbool.h>
  12. #include <stddef.h>
  13. #include <util/alloc.h>
  14. static node_t *make_vn_slot(graph_t * g, int r, int pos)
  15. {
  16. int i;
  17. node_t **v, *n;
  18. v = GD_rank(g)[r].v = gv_recalloc(GD_rank(g)[r].v, GD_rank(g)[r].n + 1,
  19. GD_rank(g)[r].n + 2, sizeof(node_t *));
  20. for (i = GD_rank(g)[r].n; i > pos; i--) {
  21. v[i] = v[i - 1];
  22. ND_order(v[i])++;
  23. }
  24. n = v[pos] = virtual_node(g);
  25. ND_order(n) = pos;
  26. ND_rank(n) = r;
  27. v[++(GD_rank(g)[r].n)] = NULL;
  28. return v[pos];
  29. }
  30. #define HLB 0 /* hard left bound */
  31. #define HRB 1 /* hard right bound */
  32. #define SLB 2 /* soft left bound */
  33. #define SRB 3 /* soft right bound */
  34. static void findlr(node_t * u, node_t * v, int *lp, int *rp)
  35. {
  36. int l, r;
  37. l = ND_order(u);
  38. r = ND_order(v);
  39. if (l > r) {
  40. int t = l;
  41. l = r;
  42. r = t;
  43. }
  44. *lp = l;
  45. *rp = r;
  46. }
  47. static void setbounds(node_t * v, int *bounds, int lpos, int rpos)
  48. {
  49. int i, l, r, ord;
  50. edge_t *f;
  51. if (ND_node_type(v) == VIRTUAL) {
  52. ord = ND_order(v);
  53. if (ND_in(v).size == 0) { /* flat */
  54. assert(ND_out(v).size == 2);
  55. findlr(aghead(ND_out(v).list[0]), aghead(ND_out(v).list[1]), &l,
  56. &r);
  57. /* the other flat edge could be to the left or right */
  58. if (r <= lpos)
  59. bounds[SLB] = bounds[HLB] = ord;
  60. else if (l >= rpos)
  61. bounds[SRB] = bounds[HRB] = ord;
  62. /* could be spanning this one */
  63. else if ((l < lpos) && (r > rpos)); /* ignore */
  64. /* must have intersecting ranges */
  65. else {
  66. if ((l < lpos) || ((l == lpos) && (r < rpos)))
  67. bounds[SLB] = ord;
  68. if ((r > rpos) || ((r == rpos) && (l > lpos)))
  69. bounds[SRB] = ord;
  70. }
  71. } else { /* forward */
  72. bool onleft, onright;
  73. onleft = onright = false;
  74. for (i = 0; (f = ND_out(v).list[i]); i++) {
  75. if (ND_order(aghead(f)) <= lpos) {
  76. onleft = true;
  77. continue;
  78. }
  79. if (ND_order(aghead(f)) >= rpos) {
  80. onright = true;
  81. continue;
  82. }
  83. }
  84. if (onleft && !onright)
  85. bounds[HLB] = ord + 1;
  86. if (onright && !onleft)
  87. bounds[HRB] = ord - 1;
  88. }
  89. }
  90. }
  91. static int flat_limits(graph_t * g, edge_t * e)
  92. {
  93. int lnode, rnode, r, bounds[4], lpos, rpos, pos;
  94. node_t **rank;
  95. r = ND_rank(agtail(e)) - 1;
  96. rank = GD_rank(g)[r].v;
  97. lnode = 0;
  98. rnode = GD_rank(g)[r].n - 1;
  99. bounds[HLB] = bounds[SLB] = lnode - 1;
  100. bounds[HRB] = bounds[SRB] = rnode + 1;
  101. findlr(agtail(e), aghead(e), &lpos, &rpos);
  102. while (lnode <= rnode) {
  103. setbounds(rank[lnode], bounds, lpos, rpos);
  104. if (lnode != rnode)
  105. setbounds(rank[rnode], bounds, lpos, rpos);
  106. lnode++;
  107. rnode--;
  108. if (bounds[HRB] - bounds[HLB] <= 1)
  109. break;
  110. }
  111. if (bounds[HLB] <= bounds[HRB])
  112. pos = (bounds[HLB] + bounds[HRB] + 1) / 2;
  113. else
  114. pos = (bounds[SLB] + bounds[SRB] + 1) / 2;
  115. return pos;
  116. }
  117. /* flat_node:
  118. * Create virtual node representing edge label between
  119. * actual ends of edge e.
  120. * This node is characterized by being virtual and having a non-NULL
  121. * ND_alg pointing to e.
  122. */
  123. static void
  124. flat_node(edge_t * e)
  125. {
  126. int r, place;
  127. double ypos, h2;
  128. graph_t *g;
  129. node_t *n, *vn;
  130. edge_t *ve;
  131. pointf dimen;
  132. if (ED_label(e) == NULL)
  133. return;
  134. g = dot_root(agtail(e));
  135. r = ND_rank(agtail(e));
  136. place = flat_limits(g, e);
  137. /* grab ypos = LL.y of label box before make_vn_slot() */
  138. if ((n = GD_rank(g)[r - 1].v[0]))
  139. ypos = ND_coord(n).y - GD_rank(g)[r - 1].ht1;
  140. else {
  141. n = GD_rank(g)[r].v[0];
  142. ypos = ND_coord(n).y + GD_rank(g)[r].ht2 + GD_ranksep(g);
  143. }
  144. vn = make_vn_slot(g, r - 1, place);
  145. dimen = ED_label(e)->dimen;
  146. if (GD_flip(g)) {
  147. double f = dimen.x;
  148. dimen.x = dimen.y;
  149. dimen.y = f;
  150. }
  151. ND_ht(vn) = dimen.y;
  152. h2 = ND_ht(vn) / 2;
  153. ND_lw(vn) = ND_rw(vn) = dimen.x / 2;
  154. ND_label(vn) = ED_label(e);
  155. ND_coord(vn).y = ypos + h2;
  156. ve = virtual_edge(vn, agtail(e), e); /* was NULL? */
  157. ED_tail_port(ve).p.x = -ND_lw(vn);
  158. ED_head_port(ve).p.x = ND_rw(agtail(e));
  159. ED_edge_type(ve) = FLATORDER;
  160. ve = virtual_edge(vn, aghead(e), e);
  161. ED_tail_port(ve).p.x = ND_rw(vn);
  162. ED_head_port(ve).p.x = ND_lw(aghead(e));
  163. ED_edge_type(ve) = FLATORDER;
  164. /* another assumed symmetry of ht1/ht2 of a label node */
  165. if (GD_rank(g)[r - 1].ht1 < h2)
  166. GD_rank(g)[r - 1].ht1 = h2;
  167. if (GD_rank(g)[r - 1].ht2 < h2)
  168. GD_rank(g)[r - 1].ht2 = h2;
  169. ND_alg(vn) = e;
  170. }
  171. static void abomination(graph_t * g)
  172. {
  173. int r;
  174. assert(GD_minrank(g) == 0);
  175. /* 3 = one for new rank, one for sentinel, one for off-by-one */
  176. r = GD_maxrank(g) + 3;
  177. rank_t *rptr = gv_recalloc(GD_rank(g), GD_maxrank(g) + 1, r,
  178. sizeof(rank_t));
  179. GD_rank(g) = rptr + 1;
  180. for (r = GD_maxrank(g); r >= 0; r--)
  181. GD_rank(g)[r] = GD_rank(g)[r - 1];
  182. GD_rank(g)[r].n = GD_rank(g)[r].an = 0;
  183. GD_rank(g)[r].v = GD_rank(g)[r].av = gv_calloc(2, sizeof(node_t *));
  184. GD_rank(g)[r].flat = NULL;
  185. GD_rank(g)[r].ht1 = GD_rank(g)[r].ht2 = 1;
  186. GD_rank(g)[r].pht1 = GD_rank(g)[r].pht2 = 1;
  187. GD_minrank(g)--;
  188. }
  189. /* checkFlatAdjacent:
  190. * Check if tn and hn are adjacent.
  191. * If so, set adjacent bit on all related edges.
  192. * Assume e is flat.
  193. */
  194. static void
  195. checkFlatAdjacent (edge_t* e)
  196. {
  197. node_t* tn = agtail(e);
  198. node_t* hn = aghead(e);
  199. int i, lo, hi;
  200. node_t* n;
  201. rank_t *rank;
  202. if (ND_order(tn) < ND_order(hn)) {
  203. lo = ND_order(tn);
  204. hi = ND_order(hn);
  205. }
  206. else {
  207. lo = ND_order(hn);
  208. hi = ND_order(tn);
  209. }
  210. rank = &(GD_rank(dot_root(tn))[ND_rank(tn)]);
  211. for (i = lo + 1; i < hi; i++) {
  212. n = rank->v[i];
  213. if ((ND_node_type(n) == VIRTUAL && ND_label(n)) ||
  214. ND_node_type(n) == NORMAL)
  215. break;
  216. }
  217. if (i == hi) { /* adjacent edge */
  218. do {
  219. ED_adjacent(e) = 1;
  220. e = ED_to_virt(e);
  221. } while (e);
  222. }
  223. }
  224. /* flat_edges:
  225. * Process flat edges.
  226. * First, mark flat edges as having adjacent endpoints or not.
  227. *
  228. * Second, if there are edge labels, nodes are placed on ranks 0,2,4,...
  229. * If we have a labeled flat edge on rank 0, add a rank -1.
  230. *
  231. * Finally, create label information. Add a virtual label node in the
  232. * previous rank for each labeled, non-adjacent flat edge. If this is
  233. * done for any edge, return true, so that main code will reset y coords.
  234. * For labeled adjacent flat edges, store label width in representative edge.
  235. * FIX: We should take into account any extra height needed for the latter
  236. * labels.
  237. *
  238. * We leave equivalent flat edges in ND_other. Their ED_virt field should
  239. * still point to the class representative.
  240. */
  241. int
  242. flat_edges(graph_t * g)
  243. {
  244. int i;
  245. bool reset = false;
  246. node_t *n;
  247. edge_t *e;
  248. for (n = GD_nlist(g); n; n = ND_next(n)) {
  249. if (ND_flat_out(n).list) {
  250. for (size_t j = 0; (e = ND_flat_out(n).list[j]); j++) {
  251. checkFlatAdjacent (e);
  252. }
  253. }
  254. for (size_t j = 0; j < ND_other(n).size; j++) {
  255. e = ND_other(n).list[j];
  256. if (ND_rank(aghead(e)) == ND_rank(agtail(e)))
  257. checkFlatAdjacent (e);
  258. }
  259. }
  260. if ((GD_rank(g)[0].flat) || (GD_n_cluster(g) > 0)) {
  261. bool found = false;
  262. for (i = 0; (n = GD_rank(g)[0].v[i]); i++) {
  263. for (size_t j = 0; (e = ND_flat_in(n).list[j]); j++) {
  264. if ((ED_label(e)) && !ED_adjacent(e)) {
  265. abomination(g);
  266. found = true;
  267. break;
  268. }
  269. }
  270. if (found)
  271. break;
  272. }
  273. }
  274. rec_save_vlists(g);
  275. for (n = GD_nlist(g); n; n = ND_next(n)) {
  276. /* if n is the tail of any flat edge, one will be in flat_out */
  277. if (ND_flat_out(n).list) {
  278. for (i = 0; (e = ND_flat_out(n).list[i]); i++) {
  279. if (ED_label(e)) {
  280. if (ED_adjacent(e)) {
  281. if (GD_flip(g)) ED_dist(e) = ED_label(e)->dimen.y;
  282. else ED_dist(e) = ED_label(e)->dimen.x;
  283. }
  284. else {
  285. reset = true;
  286. flat_node(e);
  287. }
  288. }
  289. }
  290. /* look for other flat edges with labels */
  291. for (size_t j = 0; j < ND_other(n).size; j++) {
  292. edge_t* le;
  293. e = ND_other(n).list[j];
  294. if (ND_rank(agtail(e)) != ND_rank(aghead(e))) continue;
  295. if (agtail(e) == aghead(e)) continue; /* skip loops */
  296. le = e;
  297. while (ED_to_virt(le)) le = ED_to_virt(le);
  298. ED_adjacent(e) = ED_adjacent(le);
  299. if (ED_label(e)) {
  300. if (ED_adjacent(e)) {
  301. double lw;
  302. if (GD_flip(g)) lw = ED_label(e)->dimen.y;
  303. else lw = ED_label(e)->dimen.x;
  304. ED_dist(le) = MAX(lw,ED_dist(le));
  305. }
  306. else {
  307. reset = true;
  308. flat_node(e);
  309. }
  310. }
  311. }
  312. }
  313. }
  314. if (reset) {
  315. checkLabelOrder(g);
  316. rec_reset_vlists(g);
  317. }
  318. return reset;
  319. }