circular.c 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157
  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 <circogen/circular.h>
  11. #include <circogen/blocktree.h>
  12. #include <circogen/circpos.h>
  13. #include <util/agxbuf.h>
  14. #define MINDIST 1.0
  15. /* Set attributes based on original root graph.
  16. * This is obtained by taking a node of g, finding its node
  17. * in the original graph, and finding that node's graph.
  18. */
  19. static void initGraphAttrs(Agraph_t * g, circ_state * state)
  20. {
  21. node_t *n = agfstnode(g);
  22. Agraph_t *rootg = agraphof(ORIGN(n));
  23. attrsym_t *G_mindist = agattr(rootg, AGRAPH, "mindist", NULL);
  24. attrsym_t *N_root = agattr(rootg, AGNODE, "root", NULL);
  25. char *rootname = agget(rootg, "root");
  26. initBlocklist(&state->bl);
  27. state->orderCount = 1;
  28. state->min_dist = late_double(rootg, G_mindist, MINDIST, 0.0);
  29. state->N_root = N_root;
  30. state->rootname = rootname;
  31. }
  32. static block_t*
  33. createOneBlock(Agraph_t * g, circ_state * state)
  34. {
  35. Agraph_t *subg;
  36. agxbuf name = {0};
  37. block_t *bp;
  38. Agnode_t* n;
  39. agxbprint(&name, "_block_%d", state->blockCount++);
  40. subg = agsubg(g, agxbuse(&name), 1);
  41. agxbfree(&name);
  42. bp = mkBlock(subg);
  43. for (n = agfstnode(g); n; n = agnxtnode(g,n)) {
  44. agsubnode(bp->sub_graph, n, 1);
  45. BLOCK(n) = bp;
  46. }
  47. return bp;
  48. }
  49. /* Do circular layout of g.
  50. * Assume g is strict.
  51. * g is a "connected" component of the derived graph of the
  52. * original graph.
  53. * We make state static so that it keeps a record of block numbers used
  54. * in a graph; it gets reset when a new root graph is used.
  55. */
  56. void circularLayout(Agraph_t *g, Agraph_t *realg, int *blockCount) {
  57. block_t *root;
  58. if (agnnodes(g) == 1) {
  59. Agnode_t *n = agfstnode(g);
  60. ND_pos(n)[0] = 0;
  61. ND_pos(n)[1] = 0;
  62. return;
  63. }
  64. circ_state state = {.blockCount = *blockCount};
  65. initGraphAttrs(g, &state);
  66. if (mapbool(agget(realg, "oneblock")))
  67. root = createOneBlock(g, &state);
  68. else
  69. root = createBlocktree(g, &state);
  70. circPos(g, root, &state);
  71. /* cleanup:
  72. * We need to cleanup objects created in initGraphAttrs
  73. * and all blocks. All graph objects are components of the
  74. * initial derived graph and will be freed when it is closed.
  75. */
  76. freeBlocktree(root);
  77. *blockCount = state.blockCount;
  78. }
  79. #ifdef DEBUG
  80. void prGraph(Agraph_t * g)
  81. {
  82. Agnode_t *n;
  83. Agedge_t *e;
  84. fprintf(stderr, "%s\n", agnameof(g));
  85. for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
  86. fprintf(stderr, "%s (%p)\n", agnameof(n), n);
  87. for (e = agfstout(g, n); e; e = agnxtout(g, e)) {
  88. fprintf(stderr, "%s", agnameof(n));
  89. fprintf(stderr, " -- %s (%p)\n", agnameof(aghead(e)), e);
  90. }
  91. }
  92. }
  93. void prData(Agnode_t * n, int pass)
  94. {
  95. char *pname;
  96. char *bname;
  97. char *tname;
  98. char *name1;
  99. char *name2;
  100. int dist1, dist2;
  101. if (PARENT(n))
  102. pname = agnameof(PARENT(n));
  103. else
  104. pname = "<P0>";
  105. if (BLOCK(n))
  106. bname = agnameof(BLOCK(n)->sub_graph);
  107. else {
  108. pname = "<B0>";
  109. bname = "";
  110. }
  111. fprintf(stderr, "%s: %x %s %s ", agnameof(n), FLAGS(n), pname, bname);
  112. switch (pass) {
  113. case 0:
  114. fprintf(stderr, "%d %d\n", VAL(n), LOWVAL(n));
  115. break;
  116. case 1:
  117. if (TPARENT(n))
  118. tname = agnameof(TPARENT(n));
  119. else
  120. tname = "<ROOT>";
  121. dist1 = DISTONE(n);
  122. if (dist1 > 0)
  123. name1 = agnameof(LEAFONE(n));
  124. else
  125. name1 = "<null>";
  126. dist2 = DISTTWO(n);
  127. if (dist2 > 0)
  128. name2 = agnameof(LEAFTWO(n));
  129. else
  130. name2 = "<null>";
  131. fprintf(stderr, "%s %s %d %s %d\n", tname, name1, dist1, name2,
  132. dist2);
  133. break;
  134. default:
  135. fprintf(stderr, "%d\n", POSITION(n));
  136. break;
  137. }
  138. }
  139. #endif