00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018 #ifdef HAVE_CONFIG_H
00019 #include "config.h"
00020 #endif
00021
00022 #include <time.h>
00023 #ifndef WIN32
00024 #include <unistd.h>
00025 #endif
00026 #include "neato.h"
00027 #include "pack.h"
00028 #include "stress.h"
00029 #ifdef DIGCOLA
00030 #include "digcola.h"
00031 #endif
00032 #include "kkutils.h"
00033 #include "pointset.h"
00034 #include <ctype.h>
00035
00036 #ifndef HAVE_SRAND48
00037 #define srand48 srand
00038 #endif
00039
00040 static attrsym_t *N_pos;
00041 static int Pack;
00042
00043
00044 static char *cc_pfx = "_neato_cc";
00045
00046 void neato_nodesize(node_t * n, boolean flip)
00047 {
00048 int w;
00049
00050 w = ND_xsize(n) = POINTS(ND_width(n));
00051 ND_lw_i(n) = ND_rw_i(n) = w / 2;
00052 ND_ht_i(n) = ND_ysize(n) = POINTS(ND_height(n));
00053 }
00054
00055 void neato_init_node(node_t * n)
00056 {
00057 common_init_node(n);
00058 ND_pos(n) = N_NEW(GD_ndim(n->graph), double);
00059 neato_nodesize(n, GD_flip(n->graph));
00060 }
00061
00062 void neato_init_edge(edge_t * e)
00063 {
00064 common_init_edge(e);
00065
00066 ED_factor(e) = late_double(e, E_weight, 1.0, 1.0);
00067 }
00068
00069 int user_pos(attrsym_t * posptr, attrsym_t * pinptr, node_t * np, int nG)
00070 {
00071 double *pvec;
00072 char *p, c;
00073 double z;
00074
00075 if (posptr == NULL)
00076 return FALSE;
00077 pvec = ND_pos(np);
00078 p = agxget(np, posptr->index);
00079 if (p[0]) {
00080 c = '\0';
00081 if ((Ndim >= 3) &&
00082 (sscanf(p, "%lf,%lf,%lf%c", pvec, pvec+1, pvec+2, &c) >= 3)){
00083 ND_pinned(np) = P_SET;
00084 if (PSinputscale > 0.0) {
00085 int i;
00086 for (i = 0; i < Ndim; i++)
00087 pvec[i] = pvec[i] / PSinputscale;
00088 }
00089 if (Ndim > 3)
00090 jitter_d(np, nG, 3);
00091 if ((c == '!')
00092 || (pinptr && mapbool(agxget(np, pinptr->index))))
00093 ND_pinned(np) = P_PIN;
00094 return TRUE;
00095 }
00096 else if (sscanf(p, "%lf,%lf%c", pvec, pvec + 1, &c) >= 2) {
00097 ND_pinned(np) = P_SET;
00098 if (PSinputscale > 0.0) {
00099 int i;
00100 for (i = 0; i < Ndim; i++)
00101 pvec[i] = pvec[i] / PSinputscale;
00102 }
00103 if (Ndim > 2) {
00104 if (N_z && (p = agxget(np, N_z->index)) &&
00105 (sscanf(p,"%lf",&z) == 1)) {
00106 if (PSinputscale > 0.0) {
00107 pvec[2] = z / PSinputscale;
00108 }
00109 else
00110 pvec[2] = z;
00111 jitter_d(np, nG, 3);
00112 }
00113 else
00114 jitter3d(np, nG);
00115 }
00116 if ((c == '!')
00117 || (pinptr && mapbool(agxget(np, pinptr->index))))
00118 ND_pinned(np) = P_PIN;
00119 return TRUE;
00120 } else
00121 agerr(AGERR, "node %s, position %s, expected two doubles\n",
00122 np->name, p);
00123 }
00124 return FALSE;
00125 }
00126
00127 void neato_init_node_edge(graph_t * g)
00128 {
00129 node_t *n;
00130 edge_t *e;
00131 int nG = agnnodes(g);
00132 attrsym_t *N_pin;
00133
00134 N_pos = agfindattr(g->proto->n, "pos");
00135 N_pin = agfindattr(g->proto->n, "pin");
00136
00137 for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
00138 neato_init_node(n);
00139 user_pos(N_pos, N_pin, n, nG);
00140 }
00141 for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
00142 for (e = agfstout(g, n); e; e = agnxtout(g, e))
00143 neato_init_edge(e);
00144 }
00145 }
00146
00147 void neato_cleanup_node(node_t * n)
00148 {
00149 if (ND_shape(n)) {
00150 ND_shape(n)->fns->freefn(n);
00151 }
00152 free(ND_pos(n));
00153 free_label(ND_label(n));
00154 memset(&(n->u), 0, sizeof(Agnodeinfo_t));
00155 }
00156
00157 void neato_free_splines(edge_t * e)
00158 {
00159 int i;
00160 if (ED_spl(e)) {
00161 for (i = 0; i < ED_spl(e)->size; i++)
00162 free(ED_spl(e)->list[i].list);
00163 free(ED_spl(e)->list);
00164 free(ED_spl(e));
00165 }
00166 ED_spl(e) = NULL;
00167 }
00168
00169 void neato_cleanup_edge(edge_t * e)
00170 {
00171 neato_free_splines(e);
00172 free_label(ED_label(e));
00173 memset(&(e->u), 0, sizeof(Agedgeinfo_t));
00174 }
00175
00176 void neato_cleanup_graph(graph_t * g)
00177 {
00178 if (Nop || (Pack < 0))
00179 free_scan_graph(g);
00180 if (g != g->root) memset(&(g->u), 0, sizeof(Agraphinfo_t));
00181 }
00182
00183 void neato_cleanup(graph_t * g)
00184 {
00185 node_t *n;
00186 edge_t *e;
00187
00188 for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
00189 for (e = agfstout(g, n); e; e = agnxtout(g, e)) {
00190 neato_cleanup_edge(e);
00191 }
00192 neato_cleanup_node(n);
00193 }
00194 neato_cleanup_graph(g);
00195 }
00196
00197 static int numFields(unsigned char *pos)
00198 {
00199 int cnt = 0;
00200 unsigned char c;
00201
00202 do {
00203 while (isspace(*pos))
00204 pos++;
00205 if ((c = *pos)) {
00206 cnt++;
00207 while ((c = *pos) && !isspace(c) && (c != ';'))
00208 pos++;
00209 }
00210 } while (isspace(c));
00211 return cnt;
00212 }
00213
00214 static void set_elabel(edge_t * e, textlabel_t * l, char *name)
00215 {
00216 double x, y;
00217 point pt;
00218 char *lp;
00219 lp = agget(e, name);
00220 if (lp && (sscanf(lp, "%lf,%lf", &x, &y) == 2)) {
00221 pt.x = (int) (x);
00222 pt.y = (int) (y);
00223 l->p = pt;
00224 l->set = TRUE;
00225 }
00226 }
00227
00228 #ifdef IPSEPCOLA
00229 static cluster_data* cluster_map(graph_t *mastergraph, graph_t *g)
00230 {
00231
00232 graph_t *mg, *subg;
00233 node_t *mm, *mn;
00234 node_t *n;
00235 edge_t *me;
00236
00237 int **cs,*cn;
00238 int i,j,nclusters=0;
00239 boolean* assigned = N_NEW(agnnodes(g), boolean);
00240 cluster_data *cdata = GNEW(cluster_data);
00241
00242 cdata->ntoplevel = agnnodes(g);
00243 mm = mastergraph->meta_node;
00244 mg = mm->graph;
00245 for (me = agfstout(mg, mm); me; me = agnxtout(mg, me)) {
00246 mn = me->head;
00247 subg = agusergraph(mn);
00248 if (!strncmp(subg->name, "cluster", 7)) {
00249 nclusters++;
00250 }
00251 }
00252 cdata->nvars=0;
00253 cdata->nclusters = nclusters;
00254 cs = cdata->clusters = N_GNEW(nclusters,int*);
00255 cn = cdata->clustersizes = N_GNEW(nclusters,int);
00256
00257 for (me = agfstout(mg, mm); me; me = agnxtout(mg, me)) {
00258 mn = me->head;
00259 subg = agusergraph(mn);
00260
00261 if (!strncmp(subg->name, "cluster", 7)) {
00262 int *c;
00263
00264 *cn = agnnodes(subg);
00265 cdata->nvars += *cn;
00266 c = *cs++ = N_GNEW(*cn++,int);
00267
00268 for (n = agfstnode(subg); n; n = agnxtnode(subg, n)) {
00269 node_t *gn;
00270 int ind = 0;
00271 for (gn = agfstnode(g); gn; gn = agnxtnode(g, gn)) {
00272 if(gn->id==n->id) break;
00273 ind++;
00274 }
00275
00276 *c++=ind;
00277 assigned[ind]=TRUE;
00278 cdata->ntoplevel--;
00279 }
00280 }
00281 }
00282 cdata->bb=N_GNEW(cdata->nclusters,boxf);
00283 cdata->toplevel=N_GNEW(cdata->ntoplevel,int);
00284 for(i=j=0;i<agnnodes(g);i++) {
00285 if(!assigned[i]) {
00286 cdata->toplevel[j++]=i;
00287 }
00288 }
00289 assert(cdata->ntoplevel==agnnodes(g)-cdata->nvars);
00290 free (assigned);
00291 return cdata;
00292 }
00293
00294 static void freeClusterData(cluster_data *c) {
00295 if(c->nclusters>0) {
00296 free(c->clusters[0]);
00297 free(c->clusters);
00298 free(c->clustersizes);
00299 free(c->toplevel);
00300 free(c->bb);
00301 }
00302 free(c);
00303 }
00304 #endif
00305
00306
00307
00308
00309
00310
00311 static int user_spline(attrsym_t * E_pos, edge_t * e)
00312 {
00313 char *pos;
00314 int i, n, npts, nc;
00315 point *ps = 0;
00316 point *pp;
00317 double x, y;
00318 int sflag = 0, eflag = 0;
00319 point sp = { 0, 0 }, ep = {
00320 0, 0};
00321 bezier *newspl;
00322 int more = 1;
00323 int stype, etype;
00324
00325 pos = agxget(e, E_pos->index);
00326 if (*pos == '\0')
00327 return 0;
00328
00329 arrow_flags(e, &stype, &etype);
00330 do {
00331
00332 i = sscanf(pos, "s,%lf,%lf%n", &x, &y, &nc);
00333 if (i == 2) {
00334 sflag = 1;
00335 pos = pos + nc;
00336 sp.x = (int) (x);
00337 sp.y = (int) (y);
00338 }
00339
00340
00341 i = sscanf(pos, " e,%lf,%lf%n", &x, &y, &nc);
00342 if (i == 2) {
00343 eflag = 1;
00344 pos = pos + nc;
00345 ep.x = (int) (x);
00346 ep.y = (int) (y);
00347 }
00348
00349 npts = numFields((unsigned char *) pos);
00350 n = npts;
00351 if ((n < 4) || (n % 3 != 1)) {
00352 neato_free_splines(e);
00353 return 0;
00354 }
00355 ps = ALLOC(n, 0, point);
00356 pp = ps;
00357 while (n) {
00358 i = sscanf(pos, "%lf,%lf%n", &x, &y, &nc);
00359 if (i < 2) {
00360 free(ps);
00361 neato_free_splines(e);
00362 return 0;
00363 }
00364 pos = pos + nc;
00365 pp->x = (int) (x);
00366 pp->y = (int) (y);
00367 pp++;
00368 n--;
00369 }
00370 while (isspace(*pos)) pos++;
00371 if (*pos == '\0')
00372 more = 0;
00373 else
00374 pos++;
00375
00376
00377 newspl = new_spline(e, npts);
00378 if (sflag) {
00379 newspl->sflag = stype;
00380 newspl->sp = sp;
00381 }
00382 if (eflag) {
00383 newspl->eflag = etype;
00384 newspl->ep = ep;
00385 }
00386 for (i = 0; i < npts; i++) {
00387 newspl->list[i] = ps[i];
00388 }
00389 free(ps);
00390 } while (more);
00391
00392 if (ED_label(e))
00393 set_elabel(e, ED_label(e), "lp");
00394 if (ED_head_label(e))
00395 set_elabel(e, ED_head_label(e), "head_lp");
00396 if (ED_tail_label(e))
00397 set_elabel(e, ED_tail_label(e), "tail_lp");
00398
00399 return 1;
00400 }
00401
00402
00403
00404
00405
00406
00407
00408
00409
00410 typedef enum { NoEdges, SomeEdges, AllEdges } pos_edge;
00411
00412
00413
00414
00415
00416
00417 static pos_edge nop_init_edges(Agraph_t * g)
00418 {
00419 node_t *n;
00420 edge_t *e;
00421 int nedges = 0;
00422 attrsym_t *E_pos = agfindattr(g->proto->e, "pos");
00423
00424 if (!E_pos || (Nop < 2))
00425 return NoEdges;
00426
00427 for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
00428 for (e = agfstout(g, n); e; e = agnxtout(g, e)) {
00429 if (user_spline(E_pos, e)) {
00430 nedges++;
00431 }
00432 }
00433 }
00434 if (nedges) {
00435 if (nedges == agnedges(g))
00436 return AllEdges;
00437 else
00438 return SomeEdges;
00439 } else
00440 return NoEdges;
00441 }
00442
00443
00444
00445
00446
00447 #define BS "%d,%d,%d,%d"
00448
00449 static int chkBB(Agraph_t * g, attrsym_t * G_bb)
00450 {
00451 char *s;
00452 box bb;
00453
00454 s = agxget(g, G_bb->index);
00455 if (sscanf(s, BS, &bb.LL.x, &bb.LL.y, &bb.UR.x, &bb.UR.y) == 4) {
00456 if (bb.LL.y > bb.UR.y) {
00457
00458
00459
00460
00461 int tmp = bb.LL.y;
00462 bb.LL.y = bb.UR.y;
00463 bb.UR.y = tmp;
00464 }
00465 GD_bb(g) = bb;
00466 return 1;
00467 } else
00468 return 0;
00469 }
00470
00471 static void add_cluster(Agraph_t * g, Agraph_t * subg)
00472 {
00473 int cno;
00474 cno = ++(GD_n_cluster(g));
00475 GD_clust(g) = ZALLOC(cno + 1, GD_clust(g), graph_t *, GD_n_cluster(g));
00476 GD_clust(g)[cno] = subg;
00477 do_graph_label(subg);
00478 }
00479
00480
00481 static void nop_init_graphs(Agraph_t *, attrsym_t *, attrsym_t *);
00482
00483
00484
00485 static void
00486 dfs(node_t * mn, Agraph_t * g, attrsym_t * G_lp, attrsym_t * G_bb)
00487 {
00488 graph_t *subg;
00489
00490 subg = agusergraph(mn);
00491 if (!strncmp(subg->name, "cluster", 7) && chkBB(subg, G_bb)) {
00492 add_cluster(g, subg);
00493 nop_init_graphs(subg, G_lp, G_bb);
00494 } else {
00495 graph_t *mg = g->meta_node->graph;
00496 edge_t *me;
00497 for (me = agfstout(mg, mn); me; me = agnxtout(mg, me)) {
00498 dfs(me->head, g, G_lp, G_bb);
00499 }
00500 }
00501 }
00502
00503
00504
00505
00506
00507
00508 static void
00509 nop_init_graphs(Agraph_t * g, attrsym_t * G_lp, attrsym_t * G_bb)
00510 {
00511 graph_t *mg;
00512 edge_t *me;
00513 char *s;
00514 point p;
00515
00516 if (GD_label(g) && G_lp) {
00517 s = agxget(g, G_lp->index);
00518 if (sscanf(s, "%d,%d", &p.x, &p.y) == 2) {
00519 GD_label(g)->set = TRUE;
00520 GD_label(g)->p = p;
00521 }
00522 }
00523
00524 if (!G_bb)
00525 return;
00526 mg = g->meta_node->graph;
00527 for (me = agfstout(mg, g->meta_node); me; me = agnxtout(mg, me)) {
00528 dfs(me->head, g, G_lp, G_bb);
00529 }
00530 }
00531
00532
00533
00534
00535
00536 static void translateE(edge_t * e, point offset)
00537 {
00538 int i, j;
00539 point *pt;
00540 bezier *bez;
00541
00542 bez = ED_spl(e)->list;
00543 for (i = 0; i < ED_spl(e)->size; i++) {
00544 pt = bez->list;
00545 for (j = 0; j < bez->size; j++) {
00546 pt->x -= offset.x;
00547 pt->y -= offset.y;
00548 pt++;
00549 }
00550 if (bez->sflag) {
00551 bez->sp.x -= offset.x;
00552 bez->sp.y -= offset.y;
00553 }
00554 if (bez->eflag) {
00555 bez->ep.x -= offset.x;
00556 bez->ep.y -= offset.y;
00557 }
00558 bez++;
00559 }
00560
00561 if (ED_label(e) && ED_label(e)->set) {
00562 ED_label(e)->p.x -= offset.x;
00563 ED_label(e)->p.y -= offset.y;
00564 }
00565 if (ED_head_label(e) && ED_head_label(e)->set) {
00566 ED_head_label(e)->p.x -= offset.x;
00567 ED_head_label(e)->p.y -= offset.y;
00568 }
00569 if (ED_tail_label(e) && ED_tail_label(e)->set) {
00570 ED_tail_label(e)->p.x -= offset.x;
00571 ED_tail_label(e)->p.y -= offset.y;
00572 }
00573 }
00574
00575
00576
00577 static void translateG(Agraph_t * g, point offset)
00578 {
00579 int i;
00580
00581 GD_bb(g).UR.x -= offset.x;
00582 GD_bb(g).UR.y -= offset.y;
00583 GD_bb(g).LL.x -= offset.x;
00584 GD_bb(g).LL.y -= offset.y;
00585
00586 if (GD_label(g) && GD_label(g)->set) {
00587 GD_label(g)->p.x -= offset.x;
00588 GD_label(g)->p.y -= offset.y;
00589 }
00590
00591 for (i = 1; i <= GD_n_cluster(g); i++)
00592 translateG(GD_clust(g)[i], offset);
00593 }
00594
00595
00596
00597 static void translate(Agraph_t * g, pos_edge posEdges)
00598 {
00599 node_t *n;
00600 edge_t *e;
00601 pointf offset;
00602
00603 offset = cvt2ptf(GD_bb(g).LL);
00604 for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
00605 ND_pos(n)[0] -= offset.x;
00606 ND_pos(n)[1] -= offset.y;
00607 }
00608 if (posEdges != NoEdges) {
00609 for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
00610 for (e = agfstout(g, n); e; e = agnxtout(g, e))
00611 if (ED_spl(e))
00612 translateE(e, GD_bb(g).LL);
00613 }
00614 }
00615 translateG(g, GD_bb(g).LL);
00616 }
00617
00618
00619
00620
00621
00622
00623
00624
00625
00626 int init_nop(Agraph_t * g, int adjust)
00627 {
00628 int i;
00629 node_t *np;
00630 pos_edge posEdges;
00631 attrsym_t *G_lp = agfindattr(g, "lp");
00632 attrsym_t *G_bb = agfindattr(g, "bb");
00633
00634
00635 if (!G_bb)
00636 G_bb = agraphattr(g, "bb", "");
00637
00638 scan_graph(g);
00639 for (i = 0; (np = GD_neato_nlist(g)[i]); i++) {
00640 if (!hasPos(np) && strncmp(np->name, "cluster", 7)) {
00641 agerr(AGERR, "node %s in graph %s has no position\n",
00642 np->name, g->name);
00643 return 1;
00644 }
00645 }
00646 nop_init_graphs(g, G_lp, G_bb);
00647 posEdges = nop_init_edges(g);
00648
00649 if (adjust && Nop == 1)
00650 adjustNodes(g);
00651
00652
00653 if (!chkBB(g, G_bb))
00654 compute_bb(g);
00655
00656
00657
00658
00659 if (adjust && (GD_bb(g).LL.x || GD_bb(g).LL.y))
00660 translate(g, posEdges);
00661
00662 if (!adjust) {
00663 node_t *n;
00664 State = GVSPLINES;
00665 for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
00666 ND_coord_i(n).x = POINTS(ND_pos(n)[0]);
00667 ND_coord_i(n).y = POINTS(ND_pos(n)[1]);
00668 }
00669 }
00670 else if (posEdges != AllEdges)
00671 spline_edges0(g);
00672 else {
00673 State = GVSPLINES;
00674 neato_set_aspect(g);
00675 }
00676 return 0;
00677 }
00678
00679 void neato_init_graphn(Agraph_t * g, int dfltdim)
00680 {
00681 setEdgeType (g, ET_LINE);
00682 GD_ndim(g->root) = late_int(g, agfindattr(g, "dim"), dfltdim, 2);
00683 Ndim = GD_ndim(g->root) = MIN(GD_ndim(g->root), MAXDIM);
00684 neato_init_node_edge(g);
00685 }
00686
00687 void neato_init_graph(Agraph_t * g)
00688 {
00689 neato_init_graphn(g, 2);
00690 }
00691
00692 static int neatoModel(graph_t * g)
00693 {
00694 char *p = agget(g, "model");
00695 char c;
00696
00697 if (!p || (!(c = *p)))
00698 return MODEL_SHORTPATH;
00699 if ((c == 'c') && streq(p, "circuit"))
00700 return MODEL_CIRCUIT;
00701 if (c == 's') {
00702 if (streq(p, "subset"))
00703 return MODEL_SUBSET;
00704 else if (streq(p, "shortpath"))
00705 return MODEL_SHORTPATH;
00706 }
00707 agerr(AGWARN,
00708 "Unknown value %s for attribute \"model\" in graph %s - ignored\n",
00709 p, g->name);
00710 return MODEL_SHORTPATH;
00711 }
00712
00713
00714
00715 static int neatoMode(graph_t * g)
00716 {
00717 char *str;
00718 int mode = MODE_MAJOR;
00719
00720 str = agget(g, "mode");
00721 if (str && *str) {
00722 if (streq(str, "KK"))
00723 mode = MODE_KK;
00724 else if (streq(str, "major"))
00725 mode = MODE_MAJOR;
00726 #ifdef DIGCOLA
00727 else if (streq(str, "hier"))
00728 mode = MODE_HIER;
00729 #ifdef IPSEPCOLA
00730 else if (streq(str, "ipsep"))
00731 mode = MODE_IPSEP;
00732 #endif
00733 #endif
00734 else
00735 agerr(AGWARN,
00736 "Illegal value %s for attribute \"mode\" in graph %s - ignored\n",
00737 str, g->name);
00738 }
00739
00740 return mode;
00741 }
00742
00743
00744
00745
00746 static int checkEdge(PointMap * pm, edge_t * ep, int idx)
00747 {
00748 int i = ND_id(ep->tail);
00749 int j = ND_id(ep->head);
00750 int tmp;
00751
00752 if (i > j) {
00753 tmp = i;
00754 i = j;
00755 j = tmp;
00756 }
00757 return insertPM(pm, i, j, idx);
00758 }
00759
00760 #ifdef DIGCOLA
00761
00762
00763
00764 static void
00765 dfsCycle (vtx_data* graph, int i,int mode)
00766 {
00767 node_t *np, *hp;
00768 int j, e, f;
00769
00770
00771
00772 double x = (mode==MODE_IPSEP?-1.0:1.0);
00773
00774 np = graph[i].np;
00775 ND_mark(np) = TRUE;
00776 ND_onstack(np) = TRUE;
00777 for (e = 1; e < graph[i].nedges; e++) {
00778 if (graph[i].edists[e] == 1.0) continue;
00779 j = graph[i].edges[e];
00780 hp = graph[j].np;
00781 if (ND_onstack(hp)) {
00782 graph[i].edists[e] = x;
00783 for (f = 1; (f < graph[j].nedges) &&(graph[j].edges[f] != i); f++) ;
00784 assert (f < graph[j].nedges);
00785 graph[j].edists[f] = -1.0;
00786 }
00787 else if (ND_mark(hp) == FALSE) dfsCycle(graph, j, mode);
00788
00789 }
00790 ND_onstack(np) = FALSE;
00791 }
00792
00793
00794
00795
00796 static void
00797 acyclic (vtx_data* graph, int nv, int mode)
00798 {
00799 int i;
00800 node_t* np;
00801
00802 for (i = 0; i < nv; i++) {
00803 np = graph[i].np;
00804 ND_mark(np) = FALSE;
00805 ND_onstack(np) = FALSE;
00806 }
00807 for (i = 0; i < nv; i++) {
00808 if (ND_mark(graph[i].np)) continue;
00809 dfsCycle (graph, i, mode);
00810 }
00811
00812 }
00813 #endif
00814
00815
00816
00817
00818
00819
00820
00821
00822
00823
00824
00825
00826
00827
00828
00829
00830
00831
00832
00833 static vtx_data *makeGraphData(graph_t * g, int nv, int *nedges, int mode, int model)
00834 {
00835 vtx_data *graph;
00836 int ne = agnedges(g);
00837 int *edges;
00838 float *ewgts = NULL;
00839 node_t *np;
00840 edge_t *ep;
00841 float *eweights = NULL;
00842 #ifdef DIGCOLA
00843 float *edists = NULL;
00844 #endif
00845 int haveLen;
00846 int haveWt;
00847 int haveDir;
00848 PointMap *ps = newPM();
00849 int i, i_nedges, idx;
00850
00851
00852 if (model == MODEL_SUBSET) {
00853 haveLen = FALSE;
00854 haveWt = FALSE;
00855 } else {
00856 haveLen = (agindex(g->root->proto->e, "len") >= 0);
00857 haveWt = (E_weight != 0);
00858 }
00859 if (mode == MODE_HIER || mode == MODE_IPSEP)
00860 haveDir = TRUE;
00861 else
00862 haveDir = FALSE;
00863
00864 graph = N_GNEW(nv, vtx_data);
00865 edges = N_GNEW(2 * ne + nv, int);
00866 if (haveLen || haveDir)
00867 ewgts = N_GNEW(2 * ne + nv, float);
00868 if (haveWt)
00869 eweights = N_GNEW(2 * ne + nv, float);
00870 #ifdef DIGCOLA
00871 if (haveDir)
00872 edists = N_GNEW(2*ne+nv,float);
00873 #endif
00874
00875 i = 0;
00876 ne = 0;
00877 for (np = agfstnode(g); np; np = agnxtnode(g, np)) {
00878 int j = 1;
00879 clearPM(ps);
00880 assert(ND_id(np) == i);
00881 graph[i].np = np;
00882 graph[i].edges = edges++;
00883 if (haveLen || haveDir)
00884 graph[i].ewgts = ewgts++;
00885 else
00886 graph[i].ewgts = NULL;
00887 if (haveWt)
00888 graph[i].eweights = eweights++;
00889 else
00890 graph[i].eweights = NULL;
00891 #ifdef DIGCOLA
00892 if (haveDir) {
00893 graph[i].edists = edists++;
00894 }
00895 else
00896 graph[i].edists = NULL;
00897 #endif
00898 i_nedges = 1;
00899
00900 for (ep = agfstedge(g, np); ep; ep = agnxtedge(g, ep, np)) {
00901 if (ep->head == ep->tail)
00902 continue;
00903 idx = checkEdge(ps, ep, j);
00904 if (idx != j) {
00905 if (haveWt)
00906 graph[i].eweights[idx] += ED_factor(ep);
00907 if (haveLen) {
00908 int curlen = graph[i].ewgts[idx];
00909 graph[i].ewgts[idx] = MAX(ED_dist(ep), curlen);
00910 }
00911 } else {
00912 node_t *vp = (((ep->tail) == np) ? ep->head : ep->tail);
00913 ne++;
00914 j++;
00915
00916 *edges++ = ND_id(vp);
00917 if (haveWt)
00918 *eweights++ = ED_factor(ep);
00919 if (haveLen)
00920 *ewgts++ = ED_dist(ep);
00921 else if (haveDir)
00922 *ewgts++ = 1.0;
00923 #ifdef DIGCOLA
00924 if (haveDir) {
00925 char *s = agget(ep,"dir");
00926 if(s&&!strncmp(s,"none",4)) {
00927 *edists++ = 0;
00928 } else {
00929 *edists++ = (np == ep->head ? 1.0 : -1.0);
00930 }
00931 }
00932 #endif
00933 i_nedges++;
00934 }
00935 }
00936
00937 graph[i].nedges = i_nedges;
00938 graph[i].edges[0] = i;
00939 #ifdef USE_STYLES
00940 graph[i].styles = NULL;
00941 #endif
00942 i++;
00943 }
00944 #ifdef DIGCOLA
00945 if (haveDir) {
00946
00947 acyclic (graph, nv, mode);
00948 }
00949 #endif
00950
00951 ne /= 2;
00952
00953
00954 if (ne != agnedges(g)) {
00955 edges = RALLOC(2 * ne + nv, graph[0].edges, int);
00956 if (haveLen)
00957 ewgts = RALLOC(2 * ne + nv, graph[0].ewgts, float);
00958 if (haveWt)
00959 eweights = RALLOC(2 * ne + nv, graph[0].eweights, float);
00960
00961 for (i = 0; i < nv; i++) {
00962 int sz = graph[i].nedges;
00963 graph[i].edges = edges;
00964 edges += sz;
00965 if (haveLen) {
00966 graph[i].ewgts = ewgts;
00967 ewgts += sz;
00968 }
00969 if (haveWt) {
00970 graph[i].eweights = eweights;
00971 eweights += sz;
00972 }
00973 }
00974 }
00975
00976 *nedges = ne;
00977 freePM(ps);
00978 return graph;
00979 }
00980
00981 static void freeGraphData(vtx_data * graph)
00982 {
00983 if (graph != NULL) {
00984 if (graph[0].edges != NULL)
00985 free(graph[0].edges);
00986 if (graph[0].ewgts != NULL)
00987 free(graph[0].ewgts);
00988 #ifdef UNIMPLEMENTED
00989 if (graph[0].elens != NULL)
00990 free(graph[0].elens);
00991 #endif
00992 #ifdef USE_STYLES
00993 if (graph[0].styles != NULL)
00994 free(graph[0].styles);
00995 #endif
00996 free(graph);
00997 }
00998 }
00999
01000 static void initRegular(graph_t * G, int nG)
01001 {
01002 double a, da;
01003 node_t *np;
01004
01005 a = 0.0;
01006 da = (2 * M_PI) / nG;
01007 for (np = agfstnode(G); np; np = agnxtnode(G, np)) {
01008 ND_pos(np)[0] = nG * Spring_coeff * cos(a);
01009 ND_pos(np)[1] = nG * Spring_coeff * sin(a);
01010 ND_pinned(np) = P_SET;
01011 a = a + da;
01012 if (Ndim > 2)
01013 jitter3d(np, nG);
01014 }
01015 }
01016
01017 #define SLEN(s) (sizeof(s)-1)
01018 #define SMART "self"
01019 #define REGULAR "regular"
01020 #define RANDOM "random"
01021
01022
01023
01024
01025
01026
01027
01028
01029
01030
01031 int
01032 setSeed (graph_t * G, int dflt, long* seedp)
01033 {
01034 char smallbuf[32];
01035 char *p = agget(G, "start");
01036 int init = dflt;
01037
01038 if (!p || (*p == '\0')) return dflt;
01039 if (isalpha(*(unsigned char *)p)) {
01040 if (!strncmp(p, SMART, SLEN(SMART))) {
01041 init = INIT_SELF;
01042 p += SLEN(SMART);
01043 } else if (!strncmp(p, REGULAR, SLEN(REGULAR))) {
01044 init = INIT_REGULAR;
01045 p += SLEN(REGULAR);
01046 } else if (!strncmp(p, RANDOM, SLEN(RANDOM))) {
01047 init = INIT_RANDOM;
01048 p += SLEN(RANDOM);
01049 }
01050 else init = dflt;
01051 }
01052 else if (isdigit(*(unsigned char *)p)) {
01053 init = INIT_RANDOM;
01054 }
01055
01056 if (init == INIT_RANDOM) {
01057 long seed;
01058
01059 if (!isdigit(*(unsigned char *)p) || sscanf(p, "%ld", &seed) < 1) {
01060 #ifdef MSWIN32
01061 seed = (unsigned) time(NULL);
01062 #else
01063 seed = (unsigned) getpid() ^ (unsigned) time(NULL);
01064 #endif
01065 sprintf(smallbuf, "%ld", seed);
01066 agset(G, "start", smallbuf);
01067 }
01068 *seedp = seed;
01069 }
01070 return init;
01071 }
01072
01073
01074
01075
01076
01077
01078
01079
01080
01081
01082
01083 int checkStart(graph_t * G, int nG, int dflt)
01084 {
01085 long seed;
01086 int init;
01087
01088 seed = 1;
01089 init = setSeed (G, dflt, &seed);
01090 if (N_pos && (init != INIT_RANDOM)) {
01091 agerr(AGWARN, "node positions are ignored unless start=random\n");
01092 }
01093 if (init == INIT_REGULAR) initRegular(G, nG);
01094 srand48(seed);
01095 return init;
01096 }
01097
01098 #ifdef UNUSED
01099 void dumpData(graph_t * g, vtx_data * gp, int nv, int ne)
01100 {
01101 node_t *v;
01102 int i, j, n;
01103
01104 fprintf(stderr, "n %d e %d\n", nv, ne);
01105 for (v = agfstnode(g); v; v = agnxtnode(g, v)) {
01106 fprintf(stderr, "\"%s\" %d\n", v->name, ND_id(v));
01107 }
01108 for (i = 0; i < nv; i++) {
01109 n = gp[i].nedges;
01110 fprintf(stderr, "[%d] %d\n", i, n);
01111 for (j = 0; j < n; j++) {
01112 fprintf(stderr, " %3d", gp[i].edges[j]);
01113 }
01114 fputs("\n", stderr);
01115 if (gp[i].ewgts)
01116 for (j = 0; j < n; j++) {
01117 fprintf(stderr, " %3f", gp[i].ewgts[j]);
01118 }
01119 fputs("\n", stderr);
01120
01121 }
01122 }
01123 #endif
01124
01125
01126
01127
01128
01129
01130
01131 static void
01132 majorization(graph_t *mg, graph_t * g, int nv, int mode, int model, int dim, int steps)
01133 {
01134 double **coords;
01135 int ne;
01136 int i;
01137 node_t *v;
01138 vtx_data *gp;
01139
01140 int init;
01141
01142 init = checkStart(g, nv, (mode == MODE_HIER ? INIT_SELF : INIT_RANDOM));
01143 coords = N_GNEW(dim, double *);
01144 coords[0] = N_GNEW(nv * dim, double);
01145 for (i = 1; i < Ndim; i++) {
01146 coords[i] = coords[0] + i * nv;
01147 }
01148 if (Verbose) {
01149 fprintf(stderr, "model %d smart_init %d iterations %d tol %f\n",
01150 model, (init == INIT_SELF), MaxIter, Epsilon);
01151 fprintf(stderr, "convert graph: ");
01152 start_timer();
01153 }
01154 gp = makeGraphData(g, nv, &ne, mode, model);
01155
01156 if (Verbose) {
01157 fprintf(stderr, "%d nodes %.2f sec\n", nv, elapsed_sec());
01158 }
01159
01160 #ifdef DIGCOLA
01161 if (mode != MODE_MAJOR) {
01162 double lgap = late_double(g, agfindattr(g, "levelsgap"), 0.0, -MAXDOUBLE);
01163 if (mode == MODE_HIER) {
01164 stress_majorization_with_hierarchy(gp, nv, ne, coords, Ndim,
01165 (init == INIT_SELF), model, MaxIter, lgap);
01166 }
01167 #ifdef IPSEPCOLA
01168 else {
01169 char* str;
01170 adjust_data* am;
01171 ipsep_options opt;
01172 pointf nsize[nv];
01173 cluster_data *cs = (cluster_data*)cluster_map(mg,g);
01174 opt.edge_gap = lgap;
01175 #ifdef MOSEK
01176 opt.mosek = 0;
01177 #endif
01178 opt.nsize = nsize;
01179 opt.clusters = cs;
01180 str = agget(g, "diredgeconstraints");
01181 if (mapbool(str)) {
01182 opt.diredges = 1;
01183 if(Verbose)
01184 fprintf(stderr,"Generating Edge Constraints...\n");
01185 } else if (str && !strncasecmp(str,"hier",4)) {
01186 opt.diredges = 2;
01187 if(Verbose)
01188 fprintf(stderr,"Generating DiG-CoLa Edge Constraints...\n");
01189 }
01190 else opt.diredges = 0;
01191 am = graphAdjustMode (g);
01192 if (am->mode == AM_IPSEP) {
01193 opt.noverlap = 1;
01194 if(Verbose)
01195 fprintf(stderr,"Generating Non-overlap Constraints...\n");
01196 } else if (am->mode == AM_VPSC) {
01197 opt.noverlap = 2;
01198 if(Verbose)
01199 fprintf(stderr,"Removing overlaps as postprocess...\n");
01200 }
01201 else opt.noverlap = 0;
01202 #ifdef MOSEK
01203 str = agget(g, "mosek");
01204 if(str && !strncmp(str,"true",4)) {
01205 opt.mosek = 1;
01206 if(Verbose)
01207 fprintf(stderr,"Using Mosek for constraint optimization...\n");
01208 }
01209 #endif
01210 if ((str = agget(g, "sep")) &&
01211 (i = sscanf(str, "%lf,%lf", &opt.gap.x, &opt.gap.y))) {
01212 if (i == 1) opt.gap.y = opt.gap.x;
01213 if(Verbose)
01214 fprintf(stderr,"gap=%f,%f\n",opt.gap.x,opt.gap.y);
01215 }
01216 else opt.gap.x = opt.gap.y = 0;
01217 for (i=0, v = agfstnode(g); v; v = agnxtnode(g, v),i++) {
01218 nsize[i].x = ND_width(v);
01219 nsize[i].y = ND_height(v);
01220 }
01221
01222 stress_majorization_cola(gp, nv, ne, coords, Ndim, model, MaxIter, &opt);
01223 freeClusterData(cs);
01224 }
01225 #endif
01226 }
01227 else
01228 #endif
01229 stress_majorization_kD_mkernel(gp, nv, ne, coords, Ndim,
01230 (init == INIT_SELF), model, MaxIter);
01231
01232
01233 for (v = agfstnode(g); v; v = agnxtnode(g, v)) {
01234 int idx = ND_id(v);
01235 int i;
01236 for (i = 0; i < Ndim; i++) {
01237 ND_pos(v)[i] = coords[i][idx];
01238 }
01239 }
01240 freeGraphData(gp);
01241 free(coords[0]);
01242 free(coords);
01243 }
01244
01245 static void subset_model(Agraph_t * G, int nG)
01246 {
01247 int i, j, ne;
01248 DistType **Dij;
01249 vtx_data *gp;
01250
01251 gp = makeGraphData(G, nG, &ne, MODE_KK, MODEL_SUBSET);
01252 Dij = compute_apsp_artifical_weights(gp, nG);
01253 for (i = 0; i < nG; i++) {
01254 for (j = 0; j < nG; j++) {
01255 GD_dist(G)[i][j] = Dij[i][j];
01256 }
01257 }
01258 free(Dij[0]);
01259 free(Dij);
01260 freeGraphData(gp);
01261 }
01262
01263
01264
01265
01266 static void kkNeato(Agraph_t * g, int nG, int model)
01267 {
01268 if (model == MODEL_SUBSET) {
01269 subset_model(g, nG);
01270 } else if (model == MODEL_CIRCUIT) {
01271 if (!circuit_model(g, nG)) {
01272 agerr(AGWARN,
01273 "graph %s is disconnected. Hence, the circuit model\n",
01274 g->name);
01275 agerr(AGPREV,
01276 "is undefined. Reverting to the shortest path model.\n");
01277 agerr(AGPREV,
01278 "Alternatively, consider running neato using -Gpack=true or decomposing\n");
01279 agerr(AGPREV, "the graph into connected components.\n");
01280 shortest_path(g, nG);
01281 }
01282 } else
01283 shortest_path(g, nG);
01284 initial_positions(g, nG);
01285 diffeq_model(g, nG);
01286 if (Verbose) {
01287 fprintf(stderr, "Solving model %d iterations %d tol %f\n",
01288 model, MaxIter, Epsilon);
01289 start_timer();
01290 }
01291 solve_model(g, nG);
01292 }
01293
01294
01295
01296
01297 void neatoLayout(Agraph_t * mg, Agraph_t * g, int layoutMode, int layoutModel)
01298 {
01299 int nG;
01300 char *str;
01301
01302 if ((str = agget(g, "maxiter")))
01303 MaxIter = atoi(str);
01304 else if (layoutMode == MODE_MAJOR)
01305 MaxIter = DFLT_ITERATIONS;
01306 else
01307 MaxIter = 100 * agnnodes(g);
01308
01309 nG = scan_graph_mode(g, layoutMode);
01310 if ((nG < 2) || (MaxIter <=0))
01311 return;
01312 if (layoutMode)
01313 majorization(mg, g, nG, layoutMode, layoutModel, Ndim, MaxIter);
01314 else
01315 kkNeato(g, nG, layoutModel);
01316 }
01317
01318
01319
01320
01321
01322 static void
01323 addZ (Agraph_t* g)
01324 {
01325 node_t* n;
01326 char buf[BUFSIZ];
01327
01328 if ((Ndim >= 3) && N_z) {
01329 for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
01330 sprintf(buf, "%d", POINTS(ND_pos(n)[2]));
01331 agxset(n, N_z->index, buf);
01332 }
01333 }
01334 }
01335
01336
01337
01338 void neato_layout(Agraph_t * g)
01339 {
01340 int layoutMode;
01341 int model;
01342 pack_mode mode;
01343
01344 if (Nop) {
01345 int save = PSinputscale;
01346 int ret;
01347 PSinputscale = POINTS_PER_INCH;
01348 neato_init_graph(g);
01349 addZ (g);
01350 ret = init_nop(g, 1);
01351 PSinputscale = save;
01352 if (ret) {
01353 agerr(AGPREV, "as required by the -n flag\n");
01354 exit(1);
01355 }
01356 } else {
01357 neato_init_graph(g);
01358 layoutMode = neatoMode(g);
01359 model = neatoModel(g);
01360 mode = getPackMode(g, l_undef);
01361 Pack = getPack(g, -1, CL_OFFSET);
01362
01363 if (mode == l_undef) {
01364
01365
01366
01367 if ((Pack < 0) && layoutMode)
01368 Pack = CL_OFFSET;
01369 mode = l_node;
01370 } else if (Pack < 0)
01371 Pack = CL_OFFSET;
01372 if (Pack >= 0) {
01373 graph_t *gc;
01374 graph_t **cc;
01375 int n_cc;
01376 int i;
01377 pack_info pinfo;
01378 boolean pin;
01379
01380 cc = pccomps(g, &n_cc, cc_pfx, &pin);
01381
01382 for (i = 0; i < n_cc; i++) {
01383 gc = cc[i];
01384 nodeInduce(gc);
01385 neatoLayout(g, gc, layoutMode, model);
01386 adjustNodes(gc);
01387 }
01388 if (n_cc > 1) {
01389 boolean *bp;
01390 if (pin) {
01391 bp = N_NEW(n_cc, boolean);
01392 bp[0] = TRUE;
01393 } else
01394 bp = 0;
01395 pinfo.margin = Pack;
01396 pinfo.doSplines = 0;
01397 pinfo.mode = mode;
01398 pinfo.fixed = bp;
01399 packGraphs(n_cc, cc, 0, &pinfo);
01400 if (bp)
01401 free(bp);
01402 }
01403 compute_bb(g);
01404 addZ (g);
01405 spline_edges(g);
01406
01407
01408 for (i = 0; i < n_cc; i++) {
01409 gc = cc[i];
01410 free_scan_graph(gc);
01411 agdelete(g, gc);
01412 }
01413 free (cc);
01414 #ifdef IPSEPCOLA
01415 {
01416 graph_t *mg, *subg;
01417 node_t *mm, *mn;
01418 edge_t *me;
01419 mm = g->meta_node;
01420 mg = mm->graph;
01421 for (me = agfstout(mg, mm); me; me = agnxtout(mg, me)) {
01422 mn = me->head;
01423 subg = agusergraph(mn);
01424 if (!strncmp(subg->name, "cluster", 7)) {
01425 add_cluster(g,subg);
01426 compute_bb(subg);
01427 }
01428 }
01429 }
01430 #endif
01431 } else {
01432 neatoLayout(g, g, layoutMode, model);
01433 adjustNodes(g);
01434 addZ (g);
01435 spline_edges(g);
01436 }
01437 }
01438 dotneato_postprocess(g);
01439 }