patchworkinit.c 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156
  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 <assert.h>
  11. #include <cgraph/list.h>
  12. #include <common/render.h>
  13. #include <common/utils.h>
  14. #include <patchwork/patchwork.h>
  15. #include <limits.h>
  16. #include <neatogen/adjust.h>
  17. #include <pack/pack.h>
  18. #include <neatogen/neatoprocs.h>
  19. #include <stdbool.h>
  20. /* the following code shamelessly copied from lib/fdpgen/layout.c
  21. and should be extracted and made into a common function */
  22. DEFINE_LIST(clist, graph_t*)
  23. /* mkClusters:
  24. * Attach list of immediate child clusters.
  25. * NB: By convention, the indexing starts at 1.
  26. * If pclist is NULL, the graph is the root graph or a cluster
  27. * If pclist is non-NULL, we are recursively scanning a non-cluster
  28. * subgraph for cluster children.
  29. */
  30. static void
  31. mkClusters (graph_t * g, clist_t* pclist, graph_t* parent)
  32. {
  33. graph_t* subg;
  34. clist_t list = {0};
  35. clist_t* clist;
  36. if (pclist == NULL) {
  37. // [0] is empty. The clusters are in [1..cnt].
  38. clist_append(&list, NULL);
  39. clist = &list;
  40. }
  41. else
  42. clist = pclist;
  43. for (subg = agfstsubg(g); subg; subg = agnxtsubg(subg)) {
  44. if (is_a_cluster(subg)) {
  45. agbindrec(subg, "Agraphinfo_t", sizeof(Agraphinfo_t), true);
  46. clist_append(clist, subg);
  47. mkClusters(subg, NULL, subg);
  48. }
  49. else {
  50. mkClusters(subg, clist, parent);
  51. }
  52. }
  53. if (pclist == NULL) {
  54. assert(clist_size(&list) - 1 <= INT_MAX);
  55. GD_n_cluster(g) = (int)(clist_size(&list) - 1);
  56. if (clist_size(&list) > 1) {
  57. clist_shrink_to_fit(&list);
  58. GD_clust(g) = clist_detach(&list);
  59. } else {
  60. clist_free(&list);
  61. }
  62. }
  63. }
  64. static void patchwork_init_node(node_t * n)
  65. {
  66. agset(n,"shape","box");
  67. }
  68. static void patchwork_init_edge(edge_t * e)
  69. {
  70. agbindrec(e, "Agedgeinfo_t", sizeof(Agnodeinfo_t), true); // edge custom data
  71. }
  72. static void patchwork_init_node_edge(graph_t * g)
  73. {
  74. node_t *n;
  75. edge_t *e;
  76. int i = 0;
  77. rdata* alg = gv_calloc(agnnodes(g), sizeof(rdata));
  78. GD_neato_nlist(g) = gv_calloc(agnnodes(g) + 1, sizeof(node_t*));
  79. for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
  80. agbindrec(n, "Agnodeinfo_t", sizeof(Agnodeinfo_t), true); // node custom data
  81. ND_alg(n) = alg + i;
  82. GD_neato_nlist(g)[i++] = n;
  83. patchwork_init_node(n);
  84. for (e = agfstout(g, n); e; e = agnxtout(g, e)) {
  85. patchwork_init_edge(e);
  86. }
  87. }
  88. }
  89. static void patchwork_init_graph(graph_t * g)
  90. {
  91. N_shape = agattr(g, AGNODE, "shape","box");
  92. setEdgeType (g, EDGETYPE_LINE);
  93. Ndim = GD_ndim(g) = 2; /* The algorithm only makes sense in 2D */
  94. mkClusters(g, NULL, g);
  95. patchwork_init_node_edge(g);
  96. }
  97. /* patchwork_layout:
  98. * The current version makes no use of edges, neither for a notion of connectivity
  99. * nor during drawing.
  100. */
  101. void patchwork_layout(Agraph_t *g)
  102. {
  103. patchwork_init_graph(g);
  104. if ((agnnodes(g) == 0) && (GD_n_cluster(g) == 0)) return;
  105. patchworkLayout (g);
  106. dotneato_postprocess(g);
  107. }
  108. static void patchwork_cleanup_graph(graph_t * g)
  109. {
  110. free(GD_neato_nlist(g));
  111. free(GD_clust(g));
  112. }
  113. void patchwork_cleanup(graph_t * g)
  114. {
  115. node_t *n;
  116. edge_t *e;
  117. n = agfstnode(g);
  118. if (!n) return;
  119. free (ND_alg(n));
  120. for (; n; n = agnxtnode(g, n)) {
  121. for (e = agfstout(g, n); e; e = agnxtout(g, e)) {
  122. gv_cleanup_edge(e);
  123. }
  124. gv_cleanup_node(n);
  125. }
  126. patchwork_cleanup_graph(g);
  127. }
  128. /**
  129. * @dir lib/patchwork
  130. * @brief squarified [treemap](https://en.wikipedia.org/wiki/Treemapping) layout engine, API patchwork/patchwork.h
  131. * @ingroup engines
  132. *
  133. * [Patchwork layout user manual](https://graphviz.org/docs/layouts/patchwork/)
  134. *
  135. * Other @ref engines
  136. */