class2.c 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299
  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. /* classify edges for mincross/nodepos/splines, using given ranks */
  11. #include <dotgen/dot.h>
  12. #include <stdbool.h>
  13. #include <stdlib.h>
  14. #include <util/alloc.h>
  15. static node_t*
  16. label_vnode(graph_t * g, edge_t * orig)
  17. {
  18. node_t *v;
  19. pointf dimen;
  20. dimen = ED_label(orig)->dimen;
  21. v = virtual_node(g);
  22. ND_label(v) = ED_label(orig);
  23. ND_lw(v) = GD_nodesep(agroot(v));
  24. if (!ED_label_ontop(orig)) {
  25. if (GD_flip(agroot(g))) {
  26. ND_ht(v) = dimen.x;
  27. ND_rw(v) = dimen.y;
  28. } else {
  29. ND_ht(v) = dimen.y;
  30. ND_rw(v) = dimen.x;
  31. }
  32. }
  33. return v;
  34. }
  35. static void
  36. incr_width(graph_t * g, node_t * v)
  37. {
  38. int width = GD_nodesep(g) / 2;
  39. ND_lw(v) += width;
  40. ND_rw(v) += width;
  41. }
  42. static node_t *plain_vnode(graph_t *g) {
  43. node_t *v;
  44. v = virtual_node(g);
  45. incr_width(g, v);
  46. return v;
  47. }
  48. static node_t *leader_of(node_t * v) {
  49. graph_t *clust;
  50. node_t *rv;
  51. if (ND_ranktype(v) != CLUSTER) {
  52. rv = UF_find(v);
  53. } else {
  54. clust = ND_clust(v);
  55. rv = GD_rankleader(clust)[ND_rank(v)];
  56. }
  57. return rv;
  58. }
  59. /* make_chain:
  60. * Create chain of dummy nodes for edge orig.
  61. */
  62. static void
  63. make_chain(graph_t * g, node_t * from, node_t * to, edge_t * orig)
  64. {
  65. int r, label_rank;
  66. node_t *u, *v;
  67. edge_t *e;
  68. u = from;
  69. if (ED_label(orig))
  70. label_rank = (ND_rank(from) + ND_rank(to)) / 2;
  71. else
  72. label_rank = -1;
  73. assert(ED_to_virt(orig) == NULL);
  74. for (r = ND_rank(from) + 1; r <= ND_rank(to); r++) {
  75. if (r < ND_rank(to)) {
  76. if (r == label_rank)
  77. v = label_vnode(g, orig);
  78. else
  79. v = plain_vnode(g);
  80. ND_rank(v) = r;
  81. } else
  82. v = to;
  83. e = virtual_edge(u, v, orig);
  84. virtual_weight(e);
  85. u = v;
  86. }
  87. assert(ED_to_virt(orig) != NULL);
  88. }
  89. static void
  90. interclrep(graph_t * g, edge_t * e)
  91. {
  92. node_t *t, *h;
  93. edge_t *ve;
  94. t = leader_of(agtail(e));
  95. h = leader_of(aghead(e));
  96. if (ND_rank(t) > ND_rank(h)) {
  97. node_t *t0 = t;
  98. t = h;
  99. h = t0;
  100. }
  101. if (ND_clust(t) != ND_clust(h)) {
  102. if ((ve = find_fast_edge(t, h))) {
  103. merge_chain(g, e, ve, true);
  104. return;
  105. }
  106. if (ND_rank(t) == ND_rank(h))
  107. return;
  108. make_chain(g, t, h, e);
  109. /* mark as cluster edge */
  110. for (ve = ED_to_virt(e); ve && ND_rank(aghead(ve)) <= ND_rank(h);
  111. ve = ND_out(aghead(ve)).list[0])
  112. ED_edge_type(ve) = CLUSTER_EDGE;
  113. }
  114. /* else ignore intra-cluster edges at this point */
  115. }
  116. static bool is_cluster_edge(edge_t *e) {
  117. return ND_ranktype(agtail(e)) == CLUSTER || ND_ranktype(aghead(e)) == CLUSTER;
  118. }
  119. void merge_chain(graph_t *g, edge_t *e, edge_t *f, bool update_count) {
  120. edge_t *rep;
  121. int lastrank = MAX(ND_rank(agtail(e)), ND_rank(aghead(e)));
  122. assert(ED_to_virt(e) == NULL);
  123. ED_to_virt(e) = f;
  124. rep = f;
  125. do {
  126. /* interclust multi-edges are not counted now */
  127. if (update_count)
  128. ED_count(rep) += ED_count(e);
  129. ED_xpenalty(rep) += ED_xpenalty(e);
  130. ED_weight(rep) += ED_weight(e);
  131. if (ND_rank(aghead(rep)) == lastrank)
  132. break;
  133. incr_width(g, aghead(rep));
  134. rep = ND_out(aghead(rep)).list[0];
  135. } while (rep);
  136. }
  137. bool mergeable(edge_t *e, edge_t *f) {
  138. return e && f && agtail(e) == agtail(f) && aghead(e) == aghead(f) &&
  139. ED_label(e) == ED_label(f) && ports_eq(e, f);
  140. }
  141. void class2(graph_t * g)
  142. {
  143. int c;
  144. node_t *n, *t, *h;
  145. edge_t *e, *prev, *opp;
  146. GD_nlist(g) = NULL;
  147. mark_clusters(g);
  148. for (c = 1; c <= GD_n_cluster(g); c++)
  149. build_skeleton(g, GD_clust(g)[c]);
  150. for (n = agfstnode(g); n; n = agnxtnode(g, n))
  151. for (e = agfstout(g, n); e; e = agnxtout(g, e)) {
  152. if (ND_weight_class(aghead(e)) <= 2)
  153. ND_weight_class(aghead(e))++;
  154. if (ND_weight_class(agtail(e)) <= 2)
  155. ND_weight_class(agtail(e))++;
  156. }
  157. for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
  158. if (ND_clust(n) == NULL && n == UF_find(n)) {
  159. fast_node(g, n);
  160. }
  161. prev = NULL;
  162. for (e = agfstout(g, n); e; e = agnxtout(g, e)) {
  163. /* already processed */
  164. if (ED_to_virt(e)) {
  165. prev = e;
  166. continue;
  167. }
  168. /* edges involving sub-clusters of g */
  169. if (is_cluster_edge(e)) {
  170. /* following is new cluster multi-edge code */
  171. if (mergeable(prev, e)) {
  172. if (ED_to_virt(prev)) {
  173. merge_chain(g, e, ED_to_virt(prev), false);
  174. other_edge(e);
  175. } else if (ND_rank(agtail(e)) == ND_rank(aghead(e))) {
  176. merge_oneway(e, prev);
  177. other_edge(e);
  178. }
  179. /* else is an intra-cluster edge */
  180. continue;
  181. }
  182. interclrep(g, e);
  183. prev = e;
  184. continue;
  185. }
  186. /* merge multi-edges */
  187. if (prev && agtail(e) == agtail(prev) && aghead(e) == aghead(prev)) {
  188. if (ND_rank(agtail(e)) == ND_rank(aghead(e))) {
  189. merge_oneway(e, prev);
  190. other_edge(e);
  191. continue;
  192. }
  193. if (ED_label(e) == NULL && ED_label(prev) == NULL
  194. && ports_eq(e, prev)) {
  195. if (Concentrate)
  196. ED_edge_type(e) = IGNORED;
  197. else {
  198. merge_chain(g, e, ED_to_virt(prev), true);
  199. other_edge(e);
  200. }
  201. continue;
  202. }
  203. /* parallel edges with different labels fall through here */
  204. }
  205. /* self edges */
  206. if (agtail(e) == aghead(e)) {
  207. other_edge(e);
  208. prev = e;
  209. continue;
  210. }
  211. t = UF_find(agtail(e));
  212. h = UF_find(aghead(e));
  213. /* non-leader leaf nodes */
  214. if (agtail(e) != t || aghead(e) != h) {
  215. /* FIX need to merge stuff */
  216. continue;
  217. }
  218. /* flat edges */
  219. if (ND_rank(agtail(e)) == ND_rank(aghead(e))) {
  220. flat_edge(g, e);
  221. prev = e;
  222. continue;
  223. }
  224. /* forward edges */
  225. if (ND_rank(aghead(e)) > ND_rank(agtail(e))) {
  226. make_chain(g, agtail(e), aghead(e), e);
  227. prev = e;
  228. continue;
  229. }
  230. /* backward edges */
  231. else {
  232. /* avoid when opp==e in undirected graph */
  233. for (opp = agfstout(g, aghead(e)); opp != NULL; opp = agnxtout(g, opp)) {
  234. if (aghead(opp) != agtail(e) || aghead(opp) == aghead(e) ||
  235. ED_edge_type(opp) == IGNORED) {
  236. continue;
  237. }
  238. /* shadows a forward edge */
  239. if (ED_to_virt(opp) == NULL)
  240. make_chain(g, agtail(opp), aghead(opp), opp);
  241. if (ED_label(e) == NULL && ED_label(opp) == NULL
  242. && ports_eq(e, opp)) {
  243. if (Concentrate) {
  244. ED_edge_type(e) = IGNORED;
  245. ED_conc_opp_flag(opp) = true;
  246. } else { /* see above. this is getting out of hand */
  247. other_edge(e);
  248. merge_chain(g, e, ED_to_virt(opp), true);
  249. }
  250. break;
  251. }
  252. }
  253. if (opp != NULL) {
  254. continue;
  255. }
  256. make_chain(g, aghead(e), agtail(e), e);
  257. prev = e;
  258. }
  259. }
  260. }
  261. /* since decompose() is not called on subgraphs */
  262. if (g != dot_root(g)) {
  263. free(GD_comp(g).list);
  264. GD_comp(g).list = gv_alloc(sizeof(node_t *));
  265. GD_comp(g).list[0] = GD_nlist(g);
  266. }
  267. }