/misc/src/release/graphviz-2.18-1/src/graphviz-2.18/lib/twopigen/circle.c

Go to the documentation of this file.
00001 /* $Id: circle.c,v 1.3 2008/03/03 23:01:52 ellson Exp $ $Revision: 1.3 $ */
00002 /* vim:set shiftwidth=4 ts=8: */
00003 
00004 /**********************************************************
00005 *      This software is part of the graphviz package      *
00006 *                http://www.graphviz.org/                 *
00007 *                                                         *
00008 *            Copyright (c) 1994-2004 AT&T Corp.           *
00009 *                and is licensed under the                *
00010 *            Common Public License, Version 1.0           *
00011 *                      by AT&T Corp.                      *
00012 *                                                         *
00013 *        Information and Software Systems Research        *
00014 *              AT&T Research, Florham Park NJ             *
00015 **********************************************************/
00016 
00017 
00018 #include    "circle.h"
00019 #define DEF_RANKSEP 1.00
00020 #define UNSET 10.00
00021 
00022 /* dfs to set distance from a particular leaf.
00023  * Note that termination is implicit in the test
00024  * for reduced number of steps. Proof?
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)) {     /* handles loops and multiedges */
00040             SLEAF(next) = nsteps;
00041             setNStepsToLeaf(g, next, n);
00042         }
00043     }
00044 }
00045 
00046 /* isLeaf:
00047  * Return true if n is a leaf node.
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;           /* loop */
00060         if (neighp) {
00061             if (neighp != np)
00062                 return 0;       /* two different neighbors */
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         /* STSIZE(n) = 0; */
00077         /* NCHILD(n) = 0; */
00078         SCENTER(n) = INF;
00079         THETA(n) = UNSET;       /* marks theta as unset, since 0 <= theta <= 2PI */
00080         if (isLeaf(g, n))
00081             SLEAF(n) = 0;
00082         else
00083             SLEAF(n) = INF;
00084     }
00085 }
00086 
00087 /*
00088  * Working recursively in from each leaf node (ie, each node
00089  * with nStepsToLeaf == 0; see initLayout), set the
00090  * minimum value of nStepsToLeaf for each node.  Using
00091  * that information, assign some node to be the centerNode.
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     /* With just 1 or 2 nodes, return anything. */
00100     if (agnnodes(g) <= 2)
00101         return (agfstnode(g));
00102 
00103     /* dfs from each leaf node */
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 /* dfs to set distance from center
00119  * Note that termination is implicit in the test
00120  * for reduced number of steps. Proof?
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)) {   /* handles loops and multiedges */
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  * Work out from the center and determine the value of
00149  * nStepsToCenter and parent node for each node.
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     /* find the maximum number of steps from the center */
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 /* Sets each node's subtreeSize, which counts the number of 
00170  * leaves in subtree rooted at the node.
00171  * At present, this is done bottom-up.
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;           /* handles loops */
00202 
00203         if (SPAN(next) != 0.0)
00204             continue;           /* multiedges */
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  /* Set the node positions for the 2nd and later rings. */
00220 static void setChildPositions(Agraph_t * sg, Agnode_t * n)
00221 {
00222     Agnode_t *next;
00223     Agedge_t *ep;
00224     double theta;               /* theta is the lower boundary radius of the fan */
00225 
00226     if (SPARENT(n) == 0)        /* center */
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;           /* handles loops */
00236         if (THETA(next) != UNSET)
00237             continue;           /* handles multiedges */
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     /* Convert circular to cartesian coordinates */
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                           /* not used */
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 /* circleLayout:
00303  *  We assume sg is is connected and non-empty.
00304  *  Also, if center != 0, we are guaranteed that center is
00305  *  in the graph.
00306  */
00307 void circleLayout(Agraph_t * sg, Agnode_t * center)
00308 {
00309     /* int maxNStepsToCenter; */
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     /* maxNStepsToCenter = setParentNodes(sg,center); */
00326     setParentNodes(sg, center);
00327 
00328     setSubtreeSize(sg);
00329 
00330     setSubtreeSpans(sg, center);
00331 
00332     setPositions(sg, center);
00333 
00334     setAbsolutePos(sg);
00335     /* dumpGraph (sg); */
00336 }

Generated on Mon Mar 31 19:03:28 2008 for Graphviz by  doxygen 1.5.1