00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018 #include "circle.h"
00019 #define DEF_RANKSEP 1.00
00020 #define UNSET 10.00
00021
00022
00023
00024
00025
00026 static void setNStepsToLeaf(Agraph_t * g, Agnode_t * n, Agnode_t * prev)
00027 {
00028 Agnode_t *next;
00029 Agedge_t *ep;
00030 int nsteps = SLEAF(n) + 1;
00031
00032 for (ep = agfstedge(g, n); ep; ep = agnxtedge(g, ep, n)) {
00033 if ((next = ep->tail) == n)
00034 next = ep->head;
00035
00036 if (prev == next)
00037 continue;
00038
00039 if (nsteps < SLEAF(next)) {
00040 SLEAF(next) = nsteps;
00041 setNStepsToLeaf(g, next, n);
00042 }
00043 }
00044 }
00045
00046
00047
00048
00049 static int isLeaf(Agraph_t * g, Agnode_t * n)
00050 {
00051 Agedge_t *ep;
00052 Agnode_t *neighp = 0;
00053 Agnode_t *np;
00054
00055 for (ep = agfstedge(g, n); ep; ep = agnxtedge(g, ep, n)) {
00056 if ((np = ep->tail) == n)
00057 np = ep->head;
00058 if (n == np)
00059 continue;
00060 if (neighp) {
00061 if (neighp != np)
00062 return 0;
00063 } else
00064 neighp = np;
00065 }
00066 return 1;
00067 }
00068
00069 static void initLayout(Agraph_t * g)
00070 {
00071 Agnode_t *n;
00072 int nnodes = agnnodes(g);
00073 int INF = nnodes * nnodes;
00074
00075 for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
00076
00077
00078 SCENTER(n) = INF;
00079 THETA(n) = UNSET;
00080 if (isLeaf(g, n))
00081 SLEAF(n) = 0;
00082 else
00083 SLEAF(n) = INF;
00084 }
00085 }
00086
00087
00088
00089
00090
00091
00092
00093 static Agnode_t *findCenterNode(Agraph_t * g)
00094 {
00095 Agnode_t *n;
00096 Agnode_t *center = NULL;
00097 int maxNStepsToLeaf = 0;
00098
00099
00100 if (agnnodes(g) <= 2)
00101 return (agfstnode(g));
00102
00103
00104 for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
00105 if (SLEAF(n) == 0)
00106 setNStepsToLeaf(g, n, 0);
00107 }
00108
00109 for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
00110 if (SLEAF(n) > maxNStepsToLeaf) {
00111 maxNStepsToLeaf = SLEAF(n);
00112 center = n;
00113 }
00114 }
00115 return center;
00116 }
00117
00118
00119
00120
00121
00122 static void setNStepsToCenter(Agraph_t * g, Agnode_t * n, Agnode_t * prev)
00123 {
00124 Agnode_t *next;
00125 Agedge_t *ep;
00126 int nsteps = SCENTER(n) + 1;
00127
00128 for (ep = agfstedge(g, n); ep; ep = agnxtedge(g, ep, n)) {
00129 if ((next = ep->tail) == n)
00130 next = ep->head;
00131
00132 if (prev == next)
00133 continue;
00134
00135 if (nsteps < SCENTER(next)) {
00136 SCENTER(next) = nsteps;
00137 if (SPARENT(next))
00138 NCHILD(SPARENT(next))--;
00139 SPARENT(next) = n;
00140 NCHILD(n)++;
00141 setNStepsToCenter(g, next, n);
00142 }
00143 }
00144 }
00145
00146
00147
00148
00149
00150
00151 static int setParentNodes(Agraph_t * sg, Agnode_t * center)
00152 {
00153 Agnode_t *n;
00154 int maxn = 0;
00155
00156 SCENTER(center) = 0;
00157 SPARENT(center) = 0;
00158 setNStepsToCenter(sg, center, 0);
00159
00160
00161 for (n = agfstnode(sg); n; n = agnxtnode(sg, n)) {
00162 if (SCENTER(n) > maxn) {
00163 maxn = SCENTER(n);
00164 }
00165 }
00166 return maxn;
00167 }
00168
00169
00170
00171
00172
00173 static void setSubtreeSize(Agraph_t * g)
00174 {
00175 Agnode_t *n;
00176 Agnode_t *parent;
00177
00178 for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
00179 if (NCHILD(n) > 0)
00180 continue;
00181 STSIZE(n)++;
00182 parent = SPARENT(n);
00183 while (parent) {
00184 STSIZE(parent)++;
00185 parent = SPARENT(parent);
00186 }
00187 }
00188 }
00189
00190 static void setChildSubtreeSpans(Agraph_t * g, Agnode_t * n)
00191 {
00192 Agedge_t *ep;
00193 Agnode_t *next;
00194 double ratio;
00195
00196 ratio = SPAN(n) / STSIZE(n);
00197 for (ep = agfstedge(g, n); ep; ep = agnxtedge(g, ep, n)) {
00198 if ((next = ep->tail) == n)
00199 next = ep->head;
00200 if (SPARENT(next) != n)
00201 continue;
00202
00203 if (SPAN(next) != 0.0)
00204 continue;
00205 (SPAN(next) = ratio * STSIZE(next));
00206
00207 if (NCHILD(next) > 0) {
00208 setChildSubtreeSpans(g, next);
00209 }
00210 }
00211 }
00212
00213 static void setSubtreeSpans(Agraph_t * sg, Agnode_t * center)
00214 {
00215 SPAN(center) = 2 * M_PI;
00216 setChildSubtreeSpans(sg, center);
00217 }
00218
00219
00220 static void setChildPositions(Agraph_t * sg, Agnode_t * n)
00221 {
00222 Agnode_t *next;
00223 Agedge_t *ep;
00224 double theta;
00225
00226 if (SPARENT(n) == 0)
00227 theta = 0;
00228 else
00229 theta = THETA(n) - SPAN(n) / 2;
00230
00231 for (ep = agfstedge(sg, n); ep; ep = agnxtedge(sg, ep, n)) {
00232 if ((next = ep->tail) == n)
00233 next = ep->head;
00234 if (SPARENT(next) != n)
00235 continue;
00236 if (THETA(next) != UNSET)
00237 continue;
00238
00239 THETA(next) = theta + SPAN(next) / 2.0;
00240 theta += SPAN(next);
00241
00242 if (NCHILD(next) > 0)
00243 setChildPositions(sg, next);
00244 }
00245 }
00246
00247 static void setPositions(Agraph_t * sg, Agnode_t * center)
00248 {
00249 THETA(center) = 0;
00250 setChildPositions(sg, center);
00251 }
00252
00253 static void setAbsolutePos(Agraph_t * g)
00254 {
00255 char *p;
00256 Agnode_t *n;
00257 double xf;
00258 double hyp;
00259
00260 p = late_string(g, agfindattr(g->root, "ranksep"), NULL);
00261 if (p) {
00262 if (sscanf(p, "%lf", &xf) == 0)
00263 xf = DEF_RANKSEP;
00264 else {
00265 if (xf < MIN_RANKSEP)
00266 xf = MIN_RANKSEP;
00267 }
00268 } else
00269 xf = DEF_RANKSEP;
00270 if (Verbose)
00271 fprintf(stderr, "Rank separation = %f\n", xf);
00272
00273
00274 for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
00275 hyp = xf * (SCENTER(n));
00276 ND_pos(n)[0] = hyp * cos(THETA(n));
00277 ND_pos(n)[1] = hyp * sin(THETA(n));
00278 }
00279 }
00280
00281 #if 0
00282 static void dumpGraph(Agraph_t * g)
00283 {
00284 Agnode_t *n;
00285 char *p;
00286
00287 fprintf(stderr,
00288 " : leaf stsz nkids cntr parent span theta\n");
00289 for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
00290 if (SPARENT(n))
00291 p = SPARENT(n)->name;
00292 else
00293 p = "<C>";
00294 fprintf(stderr, "%4s :%6d%6d%6d%6d%7s%7.3f%7.3f%8.3f%8.3f\n",
00295 n->name, SLEAF(n), STSIZE(n), NCHILD(n),
00296 SCENTER(n), p, SPAN(n), THETA(n), ND_pos(n)[0],
00297 ND_pos(n)[1]);
00298 }
00299 }
00300 #endif
00301
00302
00303
00304
00305
00306
00307 void circleLayout(Agraph_t * sg, Agnode_t * center)
00308 {
00309
00310
00311 if (agnnodes(sg) == 1) {
00312 Agnode_t *n = agfstnode(sg);
00313 ND_pos(n)[0] = 0;
00314 ND_pos(n)[1] = 0;
00315 return;
00316 }
00317
00318 initLayout(sg);
00319
00320 if (!center)
00321 center = findCenterNode(sg);
00322 if (Verbose)
00323 fprintf(stderr, "root = %s\n", center->name);
00324
00325
00326 setParentNodes(sg, center);
00327
00328 setSubtreeSize(sg);
00329
00330 setSubtreeSpans(sg, center);
00331
00332 setPositions(sg, center);
00333
00334 setAbsolutePos(sg);
00335
00336 }