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