/misc/src/release/graphviz-2.18-1/src/graphviz-2.18/lib/fdpgen/clusteredges.c

Go to the documentation of this file.
00001 /* $Id: clusteredges.c,v 1.2 2007/01/15 21:03:57 erg Exp $ $Revision: 1.2 $ */
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 /* clusteredges.c:
00019  * Written by Emden R. Gansner
00020  *
00021  * Code for handling spline edges around clusters.
00022  */
00023 
00024 /* uses PRIVATE interface */
00025 #define FDP_PRIVATE 1
00026 
00027 #ifdef HAVE_CONFIG_H
00028 #include <config.h>
00029 #endif
00030 
00031 #include <clusteredges.h>
00032 #include <fdp.h>
00033 #include <neatoprocs.h>
00034 #include "vispath.h"
00035 
00036 typedef struct {
00037     int cnt;
00038     int sz;
00039     Ppoly_t **obs;
00040 } objlist;
00041 
00042 /* addObj:
00043  * Add an object to the list. The array is increased if necessary.
00044  */
00045 #define INIT_SZ 100
00046 
00047 #ifdef DEBUG
00048 static void dumpObj(Ppoly_t * p)
00049 {
00050     int j;
00051     Ppoint_t pt;
00052     for (j = 0; j < p->pn; j++) {
00053         pt = p->ps[j];
00054         fprintf(stderr, " %.3g %.3g", pt.x, pt.y);
00055     }
00056     fputs("\n", stderr);
00057 }
00058 
00059 static void dumpObjlist(objlist * l)
00060 {
00061     int i;
00062     for (i = 0; i < l->cnt; i++) {
00063         dumpObj(l->obs[i]);
00064     }
00065 }
00066 #endif
00067 
00068 static void addObj(objlist * l, Ppoly_t * obj)
00069 {
00070     if (l->sz == l->cnt) {
00071         if (l->obs) {
00072             l->sz *= 2;
00073             l->obs = RALLOC(l->sz, l->obs, Ppoly_t *);
00074         } else {
00075             l->obs = N_GNEW(INIT_SZ, Ppoly_t *);
00076             l->sz = INIT_SZ;
00077         }
00078     }
00079     l->obs[l->cnt++] = obj;
00080 }
00081 
00082 /* freeObjlist:
00083  * Release memory.
00084  */
00085 static void freeObjlist(objlist * l)
00086 {
00087     if (l) {
00088         free(l->obs);
00089         free(l);
00090     }
00091 }
00092 
00093 /* resetObjlist:
00094  * Reset objlist so it can be reused, using
00095  * the same memory.
00096  */
00097 static void resetObjlist(objlist * l)
00098 {
00099     l->cnt = 0;
00100 }
00101 
00102 /* makeClustObs:
00103  * Create an obstacle corresponding to a cluster's bbox.
00104  */
00105 static Ppoly_t *makeClustObs(graph_t * g, double SEP)
00106 {
00107     Ppoly_t *obs = NEW(Ppoly_t);
00108     box bb = GD_bb(g);
00109     boxf newbb;
00110     Ppoint_t ctr;
00111     double delta = SEP - 1.0;
00112 
00113     obs->pn = 4;
00114     obs->ps = N_NEW(4, Ppoint_t);
00115 
00116     ctr.x = (bb.UR.x + bb.LL.x) / 2.0;
00117     ctr.y = (bb.UR.y + bb.LL.y) / 2.0;
00118 
00119     newbb.UR.x = SEP * bb.UR.x - delta * ctr.x;
00120     newbb.UR.y = SEP * bb.UR.y - delta * ctr.y;
00121     newbb.LL.x = SEP * bb.LL.x - delta * ctr.x;
00122     newbb.LL.y = SEP * bb.LL.y - delta * ctr.y;
00123 
00124     /* CW order */
00125     obs->ps[0].x = newbb.LL.x;
00126     obs->ps[0].y = newbb.LL.y;
00127     obs->ps[1].x = newbb.LL.x;
00128     obs->ps[1].y = newbb.UR.y;
00129     obs->ps[2].x = newbb.UR.x;
00130     obs->ps[2].y = newbb.UR.y;
00131     obs->ps[3].x = newbb.UR.x;
00132     obs->ps[3].y = newbb.LL.y;
00133 
00134     return obs;
00135 }
00136 
00137 /* addGraphObjs:
00138  * Add all top-level clusters and nodes with g as their smallest
00139  * containing graph to the list l.
00140  * Don't add any objects equal to tex or hex.
00141  * Return the list.
00142  */
00143 static void
00144 addGraphObjs(objlist * l, graph_t * g, void *tex, void *hex, double SEP)
00145 {
00146     node_t *n;
00147     graph_t *sg;
00148     int i;
00149 
00150     for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
00151         if ((PARENT(n) == g) && (n != tex) && (n != hex)
00152             && !IS_CLUST_NODE(n)) {
00153             addObj(l, makeObstacle(n, SEP));
00154         }
00155     }
00156     for (i = 1; i <= GD_n_cluster(g); i++) {
00157         sg = GD_clust(g)[i];
00158         if ((sg != tex) && (sg != hex)) {
00159             addObj(l, makeClustObs(sg, SEP));
00160         }
00161     }
00162 }
00163 
00164 /* raiseLevel:
00165  * Add barrier objects for node n, in graph *gp of level maxlvl, up to
00166  * level minlvl. 
00167  * Assume maxlvl > minlvl.
00168  * Return appended list, plus pass back last cluster processed in gp.
00169  */
00170 static void
00171 raiseLevel(objlist * l, int maxlvl, void *ex, int minlvl, graph_t ** gp,
00172            double SEP)
00173 {
00174     graph_t *g = *gp;
00175     int i;
00176 
00177     for (i = maxlvl; i > minlvl; i--) {
00178         addGraphObjs(l, g, ex, NULL, SEP);
00179         ex = g;
00180         g = GPARENT(g);
00181     }
00182     *gp = (graph_t *) ex;
00183 }
00184 
00185 /* objectList:
00186  * Create array of all objects (nodes and clusters) to be avoided
00187  * when routing edge e. Make sure it never adds the endpoints of the
00188  * edge, or any graph containing the endpoints.
00189  * Return the list.
00190  * Assume e is not a loop.
00191  */
00192 static objlist *objectList(edge_t * ep, double SEP)
00193 {
00194     node_t *h = ep->head;
00195     node_t *t = ep->tail;
00196     graph_t *hg = PARENT(h);
00197     graph_t *tg = PARENT(t);
00198     int hlevel;
00199     int tlevel;
00200     void *hex;                  /* Objects to be excluded from list */
00201     void *tex;
00202     objlist *list = NEW(objlist);
00203 
00204     /* If either endpoint is a cluster node, we move up one level */
00205     if (IS_CLUST_NODE(h)) {
00206         hex = hg;
00207         hg = GPARENT(hg);
00208     } else
00209         hex = h;
00210     if (IS_CLUST_NODE(t)) {
00211         tex = tg;
00212         tg = GPARENT(tg);
00213     } else
00214         tex = t;
00215 
00216     hlevel = LEVEL(hg);
00217     tlevel = LEVEL(tg);
00218     if (hlevel > tlevel) {
00219         raiseLevel(list, hlevel, hex, tlevel, &hg, SEP);
00220         hex = hg;
00221         hg = GPARENT(hg);
00222     } else if (tlevel > hlevel) {
00223         raiseLevel(list, tlevel, tex, hlevel, &tg, SEP);
00224         tex = tg;
00225         tg = GPARENT(tg);
00226     }
00227 
00228     /* hg and tg always have the same level */
00229     while (hg != tg) {
00230         addGraphObjs(list, hg, NULL, hex, SEP);
00231         addGraphObjs(list, tg, tex, NULL, SEP);
00232         hex = hg;
00233         hg = GPARENT(hg);
00234         tex = tg;
00235         tg = GPARENT(tg);
00236     }
00237     addGraphObjs(list, tg, tex, hex, SEP);
00238 
00239     return list;
00240 }
00241 
00242 /* compoundEdges:
00243  * Construct edges as splines, avoiding clusters when required.
00244  * We still don't implement spline multiedges, so we just copy
00245  * one spline to all the other edges.
00246  * Returns 0 on success. Failure indicates the obstacle configuration
00247  * for some edge had overlaps.
00248  */
00249 int compoundEdges(graph_t * g, double SEP, int edgetype)
00250 {
00251     node_t *n;
00252     node_t *head;
00253     edge_t *e;
00254     edge_t *e0;
00255     objlist *objl = NULL;
00256     path *P = NULL;
00257     vconfig_t *vconfig;
00258     int rv = 0;
00259 
00260     for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
00261         for (e = agfstout(g, n); e; e = agnxtout(g, e)) {
00262             head = e->head;
00263             if ((n == head) && ED_count(e)) {   /* self arc */
00264                 if (!P) {
00265                     P = NEW(path);
00266                     P->boxes = N_NEW(agnnodes(g) + 20 * 2 * 9, box);
00267                 }
00268                 makeSelfArcs(P, e, GD_nodesep(g));
00269             } else if (ED_count(e)) {
00270                 objl = objectList(e, SEP);
00271                 if (Plegal_arrangement(objl->obs, objl->cnt))
00272                     vconfig = Pobsopen(objl->obs, objl->cnt);
00273                 else {
00274                     if (Verbose)
00275                         fprintf(stderr,
00276                                 "nodes touch - falling back to straight line edges\n");
00277                     rv = 1;
00278                     continue;
00279                 }
00280 
00281                 /* For efficiency, it should be possible to copy the spline
00282                  * from the first edge to the rest. However, one has to deal
00283                  * with change in direction, different arrowheads, labels, etc.
00284                  */
00285                 for (e0 = e; e0; e0 = ED_to_virt(e0)) {
00286                     ED_path(e0) =
00287                         getPath(e0, vconfig, 0, objl->obs, objl->cnt);
00288                     makeSpline(e0, objl->obs, objl->cnt, FALSE);
00289                 }
00290                 resetObjlist(objl);
00291             }
00292         }
00293     }
00294     freeObjlist(objl);
00295     if (P) {
00296         free(P->boxes);
00297         free(P);
00298     }
00299     return rv;
00300 }

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