Graphviz  2.29.20120524.0446
lib/neatogen/neatoinit.c
Go to the documentation of this file.
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 #ifdef HAVE_CONFIG_H
00016 #include "config.h"
00017 #endif
00018 
00019 #include <time.h>
00020 #ifndef WIN32
00021 #include <unistd.h>
00022 #endif
00023 #include <ctype.h>
00024 
00025 #include "neato.h"
00026 #include "pack.h"
00027 #include "stress.h"
00028 #ifdef DIGCOLA
00029 #include "digcola.h"
00030 #endif
00031 #include "kkutils.h"
00032 #include "pointset.h"
00033 
00034 #ifndef HAVE_SRAND48
00035 #define srand48 srand
00036 #endif
00037 
00038 static attrsym_t *N_pos;
00039 static int Pack;                /* If >= 0, layout components separately and pack together
00040                                  * The value of Pack gives margins around graphs.
00041                                  */
00042 static char *cc_pfx = "_neato_cc";
00043 
00044 void neato_init_node(node_t * n)
00045 {
00046 #ifdef WITH_CGRAPH
00047     agbindrec(n, "Agnodeinfo_t", sizeof(Agnodeinfo_t), TRUE);   //node custom data
00048 #endif /* WITH_CGRAPH */
00049     common_init_node(n);
00050     ND_pos(n) = N_NEW(GD_ndim(agraphof(n)), double);
00051     gv_nodesize(n, GD_flip(agraphof(n)));
00052 }
00053 
00054 static void neato_init_edge(edge_t * e)
00055 {
00056 #ifdef WITH_CGRAPH
00057         agbindrec(e, "Agedgeinfo_t", sizeof(Agedgeinfo_t), TRUE);       //node custom data
00058 #endif /* WITH_CGRAPH */
00059     common_init_edge(e);
00060 #ifndef WITH_CGRAPH
00061 
00062 #endif /* WITH_CGRAPH */
00063     ED_factor(e) = late_double(e, E_weight, 1.0, 1.0);
00064 }
00065 
00066 int user_pos(attrsym_t * posptr, attrsym_t * pinptr, node_t * np, int nG)
00067 {
00068     double *pvec;
00069     char *p, c;
00070     double z;
00071 
00072     if (posptr == NULL)
00073         return FALSE;
00074     pvec = ND_pos(np);
00075 #ifndef WITH_CGRAPH
00076     p = agxget(np, posptr->index);
00077 #else
00078     p = agxget(np, posptr);
00079 #endif
00080     if (p[0]) {
00081         c = '\0';
00082         if ((Ndim >= 3) && 
00083             (sscanf(p, "%lf,%lf,%lf%c", pvec, pvec+1, pvec+2, &c) >= 3)){
00084             ND_pinned(np) = P_SET;
00085             if (PSinputscale > 0.0) {
00086                 int i;
00087                 for (i = 0; i < Ndim; i++)
00088                     pvec[i] = pvec[i] / PSinputscale;
00089             }
00090             if (Ndim > 3)
00091                 jitter_d(np, nG, 3);
00092 #ifndef WITH_CGRAPH
00093             if ((c == '!') || (pinptr && mapbool(agxget(np, pinptr->index))))
00094 #else
00095             if ((c == '!') || (pinptr && mapbool(agxget(np, pinptr))))
00096 #endif
00097                 ND_pinned(np) = P_PIN;
00098             return TRUE;
00099         }
00100         else if (sscanf(p, "%lf,%lf%c", pvec, pvec + 1, &c) >= 2) {
00101             ND_pinned(np) = P_SET;
00102             if (PSinputscale > 0.0) {
00103                 int i;
00104                 for (i = 0; i < Ndim; i++)
00105                     pvec[i] = pvec[i] / PSinputscale;
00106             }
00107             if (Ndim > 2) {
00108 #ifndef WITH_CGRAPH
00109                 if (N_z && (p = agxget(np, N_z->index)) && (sscanf(p,"%lf",&z) == 1)) { 
00110 #else
00111                 if (N_z && (p = agxget(np, N_z)) && (sscanf(p,"%lf",&z) == 1)) { 
00112 #endif
00113                     if (PSinputscale > 0.0) {
00114                         pvec[2] = z / PSinputscale;
00115                     }
00116                     else
00117                         pvec[2] = z;
00118                     jitter_d(np, nG, 3);
00119                 }
00120                 else
00121                     jitter3d(np, nG);
00122             }
00123 #ifndef WITH_CGRAPH
00124             if ((c == '!') || (pinptr && mapbool(agxget(np, pinptr->index))))
00125 #else
00126             if ((c == '!') || (pinptr && mapbool(agxget(np, pinptr))))
00127 #endif
00128                 ND_pinned(np) = P_PIN;
00129             return TRUE;
00130         } else
00131             agerr(AGERR, "node %s, position %s, expected two doubles\n",
00132                   agnameof(np), p);
00133     }
00134     return FALSE;
00135 }
00136 
00137 static void neato_init_node_edge(graph_t * g)
00138 {
00139     node_t *n;
00140     edge_t *e;
00141     int nG = agnnodes(g);
00142     attrsym_t *N_pin;
00143 
00144     N_pos = agfindnodeattr(g, "pos");
00145     N_pin = agfindnodeattr(g, "pin");
00146 
00147     for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
00148         neato_init_node(n);
00149         user_pos(N_pos, N_pin, n, nG);  /* set user position if given */
00150     }
00151     for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
00152         for (e = agfstout(g, n); e; e = agnxtout(g, e))
00153             neato_init_edge(e);
00154     }
00155 }
00156 
00157 static void neato_cleanup_graph(graph_t * g)
00158 {
00159     if (Nop || (Pack < 0))
00160         free_scan_graph(g);
00161     if (g != agroot(g))
00162 #ifndef WITH_CGRAPH
00163         memset(&(g->u), 0, sizeof(Agraphinfo_t));
00164 #else /* WITH_CGRAPH */
00165         agclean(g, AGRAPH , "Agraphinfo_t");
00166 #endif /* WITH_CGRAPH */
00167 }
00168 
00169 void neato_cleanup(graph_t * g)
00170 {
00171     node_t *n;
00172     edge_t *e;
00173 
00174     for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
00175         for (e = agfstout(g, n); e; e = agnxtout(g, e)) {
00176             gv_cleanup_edge(e);
00177         }
00178         gv_cleanup_node(n);
00179     }
00180     neato_cleanup_graph(g);
00181 }
00182 
00183 static int numFields(unsigned char *pos)
00184 {
00185     int cnt = 0;
00186     unsigned char c;
00187 
00188     do {
00189         while (isspace(*pos))
00190             pos++;              /* skip white space */
00191         if ((c = *pos)) { /* skip token */
00192             cnt++;
00193             while ((c = *pos) && !isspace(c) && (c != ';'))
00194                 pos++;
00195         }
00196     } while (isspace(c));
00197     return cnt;
00198 }
00199 
00200 static void set_label(void* obj, textlabel_t * l, char *name)
00201 {
00202     double x, y;
00203     char *lp;
00204     lp = agget(obj, name);
00205     if (lp && (sscanf(lp, "%lf,%lf", &x, &y) == 2)) {
00206         l->pos = pointfof(x, y);
00207         l->set = TRUE;
00208     }
00209 }
00210 
00211 #ifdef IPSEPCOLA
00212 static cluster_data* cluster_map(graph_t *mastergraph, graph_t *g)
00213 {
00214 #ifndef WITH_CGRAPH
00215     /* search meta-graph to find clusters */
00216     graph_t *mg;
00217     node_t *mm, *mn;
00218     edge_t *me;
00219 #endif
00220     graph_t *subg;
00221     node_t *n;
00222      /* array of arrays of node indices in each cluster */
00223     int **cs,*cn;
00224     int i,j,nclusters=0;
00225     boolean* assigned = N_NEW(agnnodes(g), boolean);
00226     cluster_data *cdata = GNEW(cluster_data);
00227 
00228     cdata->ntoplevel = agnnodes(g);
00229 #ifndef WITH_CGRAPH
00230     mm = mastergraph->meta_node;
00231     mg = agraphof(mm); 
00232     for (me = agfstout(mg, mm); me; me = agnxtout(mg, me)) {
00233         mn = aghead(me);
00234         subg = agusergraph(mn);
00235 #else
00236     for (subg = agfstsubg(mastergraph); subg; subg = agnxtsubg(subg)) {
00237 #endif
00238         if (!strncmp(agnameof(subg), "cluster", 7)) {
00239             nclusters++;
00240         }
00241     }
00242     cdata->nvars=0;
00243     cdata->nclusters = nclusters;
00244     cs = cdata->clusters = N_GNEW(nclusters,int*);
00245     cn = cdata->clustersizes = N_GNEW(nclusters,int);
00246 #ifndef WITH_CGRAPH
00247     /* fprintf(stderr,"search %d clusters...\n",nclusters); */
00248     for (me = agfstout(mg, mm); me; me = agnxtout(mg, me)) {
00249         mn = me->head;
00250         subg = agusergraph(mn);
00251 #else
00252     for (subg = agfstsubg(mastergraph); subg; subg = agnxtsubg(subg)) {
00253 #endif
00254         /* clusters are processed by separate calls to ordered_edges */
00255         if (!strncmp(agnameof(subg), "cluster", 7)) {
00256             int *c;
00257 
00258             *cn = agnnodes(subg);
00259             cdata->nvars += *cn;
00260             c = *cs++ = N_GNEW(*cn++,int);
00261             /* fprintf(stderr,"Cluster with %d nodes...\n",agnnodes(subg)); */
00262             for (n = agfstnode(subg); n; n = agnxtnode(subg, n)) {
00263                 node_t *gn;
00264                 int ind = 0;
00265                 for (gn = agfstnode(g); gn; gn = agnxtnode(g, gn)) {
00266                     if(AGSEQ(gn)==AGSEQ(n)) break;
00267                     ind++;
00268                 }
00269                 /* fprintf(stderr,"  node=%s, id=%d, ind=%d\n",agnameof(n),n->id,ind); */
00270                 *c++=ind;
00271                 assigned[ind]=TRUE;
00272                 cdata->ntoplevel--;
00273             }
00274         }
00275     }
00276     cdata->bb=N_GNEW(cdata->nclusters,boxf);
00277     cdata->toplevel=N_GNEW(cdata->ntoplevel,int);
00278     for(i=j=0;i<agnnodes(g);i++) {
00279         if(!assigned[i]) {
00280             cdata->toplevel[j++]=i;
00281         }
00282     }
00283     assert(cdata->ntoplevel==agnnodes(g)-cdata->nvars);
00284     free (assigned);
00285     return cdata;
00286 }
00287 
00288 static void freeClusterData(cluster_data *c) {
00289     if(c->nclusters>0) {
00290         free(c->clusters[0]);
00291         free(c->clusters);
00292         free(c->clustersizes);
00293         free(c->toplevel);
00294         free(c->bb);
00295     }
00296     free(c);
00297 }
00298 #endif
00299 
00300 /* user_spline:
00301  * Attempt to use already existing pos info for spline
00302  * Return 1 if successful, 0 otherwise.
00303  * Assume E_pos != NULL and ED_spl(e) == NULL.
00304  */
00305 static int user_spline(attrsym_t * E_pos, edge_t * e)
00306 {
00307     char *pos;
00308     int i, n, npts, nc;
00309     pointf *ps = 0;
00310     pointf *pp;
00311     double x, y;
00312     int sflag = 0, eflag = 0;
00313     pointf sp = { 0, 0 }, ep = { 0, 0};
00314     bezier *newspl;
00315     int more = 1;
00316     int stype, etype;
00317     static boolean warned;
00318 
00319 #ifndef WITH_CGRAPH
00320     pos = agxget(e, E_pos->index);
00321 #else
00322     pos = agxget(e, E_pos);
00323 #endif
00324     if (*pos == '\0')
00325         return 0;
00326 
00327     arrow_flags(e, &stype, &etype);
00328     do {
00329         /* check for s head */
00330         i = sscanf(pos, "s,%lf,%lf%n", &x, &y, &nc);
00331         if (i == 2) {
00332             sflag = 1;
00333             pos = pos + nc;
00334             sp.x = x;
00335             sp.y = y;
00336         }
00337 
00338         /* check for e head */
00339         i = sscanf(pos, " e,%lf,%lf%n", &x, &y, &nc);
00340         if (i == 2) {
00341             eflag = 1;
00342             pos = pos + nc;
00343             ep.x = x;
00344             ep.y = y;
00345         }
00346 
00347         npts = numFields((unsigned char *) pos);        /* count potential points */
00348         n = npts;
00349         if ((n < 4) || (n % 3 != 1)) {
00350             gv_free_splines(e);
00351             if (!warned) {
00352                 warned = 1;
00353 #ifndef WITH_CGRAPH
00354                 agerr(AGWARN, "pos attribute for edge (%s,%s) doesn't have 3n+1 points\n", e->tail->name, e->head->name);
00355 #else
00356                 agerr(AGWARN, "pos attribute for edge (%s,%s) doesn't have 3n+1 points\n", agnameof(agtail(e)), agnameof(aghead(e)));
00357 #endif
00358             }
00359             return 0;
00360         }
00361         ps = ALLOC(n, 0, pointf);
00362         pp = ps;
00363         while (n) {
00364             i = sscanf(pos, "%lf,%lf%n", &x, &y, &nc);
00365             if (i < 2) {
00366                 if (!warned) {
00367                     warned = 1;
00368 #ifndef WITH_CGRAPH
00369                     agerr(AGWARN, "syntax error in pos attribute for edge (%s,%s)\n", e->tail->name, e->head->name);
00370 #else
00371                     agerr(AGWARN, "syntax error in pos attribute for edge (%s,%s)\n", agnameof(agtail(e)), agnameof(aghead(e)));
00372 #endif
00373                 }
00374                 free(ps);
00375                 gv_free_splines(e);
00376                 return 0;
00377             }
00378             pos = pos + nc;
00379             pp->x = x;
00380             pp->y = y;
00381             pp++;
00382             n--;
00383         }
00384         while (isspace(*pos)) pos++;
00385         if (*pos == '\0')
00386             more = 0;
00387         else
00388             pos++;
00389 
00390         /* parsed successfully; create spline */
00391         newspl = new_spline(e, npts);
00392         if (sflag) {
00393             newspl->sflag = stype;
00394             newspl->sp = sp;
00395         }
00396         if (eflag) {
00397             newspl->eflag = etype;
00398             newspl->ep = ep;
00399         }
00400         for (i = 0; i < npts; i++) {
00401             newspl->list[i] = ps[i];
00402         }
00403         free(ps);
00404     } while (more);
00405 
00406     if (ED_label(e))
00407         set_label(e, ED_label(e), "lp");
00408     if (ED_xlabel(e))
00409         set_label(e, ED_xlabel(e), "xlp");
00410     if (ED_head_label(e))
00411         set_label(e, ED_head_label(e), "head_lp");
00412     if (ED_tail_label(e))
00413         set_label(e, ED_tail_label(e), "tail_lp");
00414 
00415     return 1;
00416 }
00417 
00418 /* Nop can be:
00419  *  0 - do full layout
00420  *  1 - assume initial node positions, do (optional) adjust and all splines
00421  *  2 - assume final node and edges positions, do nothing except compute
00422  *      missing splines
00423  */
00424 
00425  /* Indicates the amount of edges with position information */
00426 typedef enum { NoEdges, SomeEdges, AllEdges } pos_edge;
00427 
00428 /* nop_init_edges:
00429  * Check edges for position info.
00430  * If position info exists, check for edge label positions.
00431  * Return number of edges with position info.
00432  */
00433 static pos_edge nop_init_edges(Agraph_t * g)
00434 {
00435     node_t *n;
00436     edge_t *e;
00437     int nedges = 0;
00438     attrsym_t *E_pos;
00439 
00440     if (agnedges(g) == 0)
00441         return AllEdges;
00442 
00443     E_pos = agfindedgeattr(g, "pos");
00444     if (!E_pos || (Nop < 2))
00445         return NoEdges;
00446 
00447     for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
00448         for (e = agfstout(g, n); e; e = agnxtout(g, e)) {
00449             if (user_spline(E_pos, e)) {
00450                 nedges++;
00451             }
00452         }
00453     }
00454     if (nedges) {
00455         if (nedges == agnedges(g))
00456             return AllEdges;
00457         else
00458             return SomeEdges;
00459     } else
00460         return NoEdges;
00461 }
00462 
00463 /* chkBB:
00464  * Scans for a correct bb attribute. If available, sets it
00465  * in the graph and returns 1.
00466  */
00467 #define BS "%lf,%lf,%lf,%lf"
00468 
00469 static int chkBB(Agraph_t * g, attrsym_t * G_bb, boxf* bbp)
00470 {
00471     char *s;
00472     boxf bb;
00473 
00474 #ifndef WITH_CGRAPH
00475     s = agxget(g, G_bb->index);
00476 #else
00477     s = agxget(g, G_bb);
00478 #endif
00479     if (sscanf(s, BS, &bb.LL.x, &bb.LL.y, &bb.UR.x, &bb.UR.y) == 4) {
00480         if (bb.LL.y > bb.UR.y) {
00481         /* If the LL.y coordinate is bigger than the UR.y coordinate,
00482          * we assume the input was produced using -y, so we normalize
00483          * the bb. 
00484          */
00485             double tmp = bb.LL.y;
00486             bb.LL.y = bb.UR.y;
00487             bb.UR.y = tmp;
00488         }
00489         *bbp = bb;
00490         return 1;
00491     } else
00492         return 0;
00493 }
00494 
00495 static void add_cluster(Agraph_t * g, Agraph_t * subg)
00496 {
00497     int cno;
00498     cno = ++(GD_n_cluster(g));
00499     GD_clust(g) = ZALLOC(cno + 1, GD_clust(g), graph_t *, GD_n_cluster(g));
00500     GD_clust(g)[cno] = subg;
00501     do_graph_label(subg);
00502 }
00503 
00504 
00505 static void nop_init_graphs(Agraph_t *, attrsym_t *, attrsym_t *);
00506 
00507 /* dfs:
00508  */
00509 static void
00510 #ifndef WITH_CGRAPH
00511 dfs(node_t * mn, Agraph_t * g, attrsym_t * G_lp, attrsym_t * G_bb)
00512 #else /* WITH_CGRAPH */
00513 dfs(Agraph_t * subg, Agraph_t * g, attrsym_t * G_lp, attrsym_t * G_bb)
00514 #endif /* WITH_CGRAPH */
00515 {
00516     boxf bb;
00517 
00518 #ifndef WITH_CGRAPH
00519     graph_t *subg = agusergraph(mn);
00520 #endif
00521     if (!strncmp(agnameof(subg), "cluster", 7) && chkBB(subg, G_bb, &bb)) {
00522 #ifdef WITH_CGRAPH
00523         agbindrec(subg, "Agraphinfo_t", sizeof(Agraphinfo_t), TRUE);
00524 #endif
00525         GD_bb(subg) = bb;
00526         add_cluster(g, subg);
00527         nop_init_graphs(subg, G_lp, G_bb);
00528     } else {
00529 #ifndef WITH_CGRAPH
00530         graph_t *mg = g->meta_node->graph;
00531         edge_t *me;
00532         for (me = agfstout(mg, mn); me; me = agnxtout(mg, me)) {
00533             dfs(me->head, g, G_lp, G_bb);
00534 #else
00535         graph_t *mg;
00536         for (mg = agfstsubg(g); subg; subg = agnxtsubg(subg)) {
00537             dfs(mg, g, G_lp, G_bb);
00538 #endif
00539         }
00540     }
00541 }
00542 
00543 /* nop_init_graphs:
00544  * Read in clusters and graph label info.
00545  * A subgraph is a cluster if its name starts with "cluster" and
00546  * it has a valid bb.
00547  */
00548 static void
00549 nop_init_graphs(Agraph_t * g, attrsym_t * G_lp, attrsym_t * G_bb)
00550 {
00551 #ifndef WITH_CGRAPH
00552     graph_t *mg;
00553     edge_t *me;
00554 #else
00555     graph_t *subg;
00556 #endif
00557     char *s;
00558     double x, y;
00559 
00560     if (GD_label(g) && G_lp) {
00561 #ifndef WITH_CGRAPH
00562         s = agxget(g, G_lp->index);
00563 #else
00564         s = agxget(g, G_lp);
00565 #endif
00566         if (sscanf(s, "%lf,%lf", &x, &y) == 2) {
00567             GD_label(g)->pos = pointfof(x, y);
00568             GD_label(g)->set = TRUE;
00569         }
00570     }
00571 
00572     if (!G_bb)
00573         return;
00574 #ifndef WITH_CGRAPH
00575     mg = g->meta_node->graph;
00576     for (me = agfstout(mg, g->meta_node); me; me = agnxtout(mg, me)) {
00577         dfs(me->head, g, G_lp, G_bb);
00578 #else /* WITH_CGRAPH */
00579     for (subg = agfstsubg(g); subg; subg = agnxtsubg(subg)) {
00580         dfs(subg, g, G_lp, G_bb);
00581 #endif /* WITH_CGRAPH */
00582     }
00583 }
00584 
00585 /* translateE:
00586  * Translate edge by offset.
00587  * Assume ED_spl(e) != NULL
00588  */
00589 static void translateE(edge_t * e, pointf offset)
00590 {
00591     int i, j;
00592     pointf *pt;
00593     bezier *bez;
00594 
00595     bez = ED_spl(e)->list;
00596     for (i = 0; i < ED_spl(e)->size; i++) {
00597         pt = bez->list;
00598         for (j = 0; j < bez->size; j++) {
00599             pt->x -= offset.x;
00600             pt->y -= offset.y;
00601             pt++;
00602         }
00603         if (bez->sflag) {
00604             bez->sp.x -= offset.x;
00605             bez->sp.y -= offset.y;
00606         }
00607         if (bez->eflag) {
00608             bez->ep.x -= offset.x;
00609             bez->ep.y -= offset.y;
00610         }
00611         bez++;
00612     }
00613 
00614     if (ED_label(e) && ED_label(e)->set) {
00615         ED_label(e)->pos.x -= offset.x;
00616         ED_label(e)->pos.y -= offset.y;
00617     }
00618     if (ED_xlabel(e) && ED_xlabel(e)->set) {
00619         ED_xlabel(e)->pos.x -= offset.x;
00620         ED_xlabel(e)->pos.y -= offset.y;
00621     }
00622     if (ED_head_label(e) && ED_head_label(e)->set) {
00623         ED_head_label(e)->pos.x -= offset.x;
00624         ED_head_label(e)->pos.y -= offset.y;
00625     }
00626     if (ED_tail_label(e) && ED_tail_label(e)->set) {
00627         ED_tail_label(e)->pos.x -= offset.x;
00628         ED_tail_label(e)->pos.y -= offset.y;
00629     }
00630 }
00631 
00632 /* translateG:
00633  */
00634 static void translateG(Agraph_t * g, pointf offset)
00635 {
00636     int i;
00637 
00638     GD_bb(g).UR.x -= offset.x;
00639     GD_bb(g).UR.y -= offset.y;
00640     GD_bb(g).LL.x -= offset.x;
00641     GD_bb(g).LL.y -= offset.y;
00642 
00643     if (GD_label(g) && GD_label(g)->set) {
00644         GD_label(g)->pos.x -= offset.x;
00645         GD_label(g)->pos.y -= offset.y;
00646     }
00647 
00648     for (i = 1; i <= GD_n_cluster(g); i++)
00649         translateG(GD_clust(g)[i], offset);
00650 }
00651 
00652 /* translate:
00653  */
00654 static void translate(Agraph_t * g, pos_edge posEdges)
00655 {
00656     node_t *n;
00657     edge_t *e;
00658     pointf offset;
00659     pointf ll;
00660 
00661     ll = GD_bb(g).LL;
00662 
00663     offset.x = PS2INCH(ll.x);
00664     offset.y = PS2INCH(ll.y);
00665     for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
00666         ND_pos(n)[0] -= offset.x;
00667         ND_pos(n)[1] -= offset.y;
00668     }
00669     if (posEdges != NoEdges) {
00670         for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
00671             for (e = agfstout(g, n); e; e = agnxtout(g, e))
00672                 if (ED_spl(e))
00673                     translateE(e, ll);
00674         }
00675     }
00676     translateG(g, ll);
00677 }
00678 
00679 /* init_nop:
00680  * This assumes all nodes have been positioned.
00681  * It also assumes none of the * relevant fields in A*info_t have been set.
00682  * The input may provide additional position information for
00683  * clusters, edges and labels. If certain position information
00684  * is missing, init_nop will use a standard neato technique to
00685  * supply it.
00686  *
00687  * If adjust is false, init_nop does nothing but initialize all
00688  * of the basic graph information. No tweaking of positions or 
00689  * filling in edge splines is done.
00690  *
00691  * Returns 0 on normal success, 1 if postprocess should be avoided, and -1
00692  * on failure.
00693  */
00694 int init_nop(Agraph_t * g, int adjust)
00695 {
00696     int i;
00697     node_t *np;
00698     pos_edge posEdges;          /* How many edges have spline info */
00699     attrsym_t *G_lp = agfindgraphattr(g, "lp");
00700     attrsym_t *G_bb = agfindgraphattr(g, "bb");
00701     int didAdjust = 0;  /* Have nodes been moved? */
00702     int haveBackground;
00703 
00704     /* If G_bb not defined, define it */
00705     if (!G_bb)
00706 #ifndef WITH_CGRAPH
00707         G_bb = agraphattr(g, "bb", "");
00708 #else /* WITH_CGRAPH */
00709         G_bb = agattr(g, AGRAPH, "bb", "");
00710 #endif /* WITH_CGRAPH */
00711 
00712     scan_graph(g);              /* mainly to set up GD_neato_nlist */
00713     for (i = 0; (np = GD_neato_nlist(g)[i]); i++) {
00714         if (!hasPos(np) && strncmp(agnameof(np), "cluster", 7)) {
00715             agerr(AGERR, "node %s in graph %s has no position\n",
00716                   agnameof(np), agnameof(g));
00717             return -1;
00718         }
00719         if (ND_xlabel(np))
00720             set_label(np, ND_xlabel(np), "xlp");
00721     }
00722     nop_init_graphs(g, G_lp, G_bb);
00723     posEdges = nop_init_edges(g);
00724 
00725     if (GD_drawing(g)->xdots) {
00726         haveBackground = 1;
00727         GD_drawing(g)->ratio_kind = R_NONE; /* Turn off any aspect change if background present */
00728     }
00729     else
00730         haveBackground = 0;
00731 
00732     if (adjust && (Nop == 1) && !haveBackground)
00733         didAdjust = adjustNodes(g);
00734 
00735     if (didAdjust) {
00736         if (GD_label(g)) GD_label(g)->set = FALSE;
00737 /* FIX: 
00738  *   - if nodes are moved, clusters are no longer valid.
00739  */
00740     }
00741 
00742 #if 0
00743     /* If g does not have a good "bb" attribute or we adjusted the nodes, 
00744      * compute it. 
00745      */
00746     if (!chkBB(g, G_bb) || didAdjust)
00747 #endif
00748         compute_bb(g);
00749 
00750     /* Adjust bounding box for any background */
00751     if (haveBackground)
00752         GD_bb(g) = xdotBB (g);
00753 
00754     /* At this point, all bounding boxes should be correctly defined.
00755      * If necessary, we translate the graph to the origin.
00756      */
00757     if (adjust && !haveBackground && (ROUND(abs(GD_bb(g).LL.x)) || ROUND(abs(GD_bb(g).LL.y))))
00758         translate(g, posEdges);
00759 
00760     if (!adjust) {
00761         node_t *n;
00762         State = GVSPLINES;
00763         for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
00764             ND_coord(n).x = POINTS_PER_INCH * (ND_pos(n)[0]);
00765             ND_coord(n).y = POINTS_PER_INCH * (ND_pos(n)[1]);
00766         }
00767     }
00768     else if (posEdges != AllEdges)
00769         spline_edges0(g);
00770     else {
00771         State = GVSPLINES;
00772         neato_set_aspect(g);
00773     }
00774     return haveBackground;
00775 }
00776 
00777 static void neato_init_graph (Agraph_t * g)
00778 {
00779     int outdim;
00780 
00781     setEdgeType (g, ET_LINE);
00782     outdim = late_int(g, agfindgraphattr(g, "dimen"), 2, 2);
00783     GD_ndim(agroot(g)) = late_int(g, agfindgraphattr(g, "dim"), outdim, 2);
00784     Ndim = GD_ndim(g->root) = MIN(GD_ndim(g->root), MAXDIM);
00785     GD_odim(g->root) = MIN(outdim, Ndim);
00786     neato_init_node_edge(g);
00787 }
00788 
00789 static int neatoModel(graph_t * g)
00790 {
00791     char *p = agget(g, "model");
00792     char c;
00793 
00794     if (!p || (!(c = *p)))    /* if p is NULL or "" */
00795         return MODEL_SHORTPATH;
00796     if ((c == 'c') && streq(p, "circuit"))
00797         return MODEL_CIRCUIT;
00798     if (c == 's') {
00799         if (streq(p, "subset"))
00800             return MODEL_SUBSET;
00801         else if (streq(p, "shortpath"))
00802             return MODEL_SHORTPATH;
00803     }
00804     if ((c == 'm') && streq(p, "mds")) {
00805 #ifndef WITH_CGRAPH
00806         if (agindex(g->root->proto->e, "len") >= 0)
00807 #else /* WITH_CGRAPH */
00808         if (agattr(g, AGEDGE, "len", 0))
00809 #endif /* WITH_CGRAPH */
00810             return MODEL_MDS;
00811         else {
00812             agerr(AGWARN,
00813                 "edges in graph %s have no len attribute. Hence, the mds model\n", agnameof(g));
00814             agerr(AGPREV, "is inappropriate. Reverting to the shortest path model.\n");
00815             return MODEL_SHORTPATH;
00816         }
00817     }
00818     agerr(AGWARN,
00819           "Unknown value %s for attribute \"model\" in graph %s - ignored\n",
00820           p, agnameof(g));
00821     return MODEL_SHORTPATH;
00822 }
00823 
00824 /* neatoMode:
00825  */
00826 static int neatoMode(graph_t * g)
00827 {
00828     char *str;
00829     int mode = MODE_MAJOR;      /* default mode */
00830 
00831     str = agget(g, "mode");
00832     if (str && *str) {
00833         if (streq(str, "KK"))
00834             mode = MODE_KK;
00835         else if (streq(str, "major"))
00836             mode = MODE_MAJOR;
00837 #ifdef DIGCOLA
00838         else if (streq(str, "hier"))
00839             mode = MODE_HIER;
00840 #ifdef IPSEPCOLA
00841         else if (streq(str, "ipsep"))
00842             mode = MODE_IPSEP;
00843 #endif
00844 #endif
00845         else
00846             agerr(AGWARN,
00847                   "Illegal value %s for attribute \"mode\" in graph %s - ignored\n",
00848                   str, agnameof(g));
00849     }
00850 
00851     return mode;
00852 }
00853 
00854 /* checkEdge:
00855  *
00856  */
00857 static int checkEdge(PointMap * pm, edge_t * ep, int idx)
00858 {
00859     int i = ND_id(agtail(ep));
00860     int j = ND_id(aghead(ep));
00861     int tmp;
00862 
00863     if (i > j) {
00864         tmp = i;
00865         i = j;
00866         j = tmp;
00867     }
00868     return insertPM(pm, i, j, idx);
00869 }
00870 
00871 #ifdef DIGCOLA
00872 /* dfsCycle:
00873  * dfs for breaking cycles in vtxdata
00874  */
00875 static void
00876 dfsCycle (vtx_data* graph, int i,int mode, node_t* nodes[])
00877 {
00878     node_t *np, *hp;
00879     int j, e, f;
00880     /* if mode is IPSEP make it an in-edge
00881      * at both ends, so that an edge constraint won't be generated!
00882      */
00883     double x = (mode==MODE_IPSEP?-1.0:1.0);
00884 
00885     np = nodes[i];
00886     ND_mark(np) = TRUE;
00887     ND_onstack(np) = TRUE;
00888     for (e = 1; e < graph[i].nedges; e++) {
00889         if (graph[i].edists[e] == 1.0) continue;  /* in edge */
00890         j = graph[i].edges[e];
00891         hp = nodes[j];
00892         if (ND_onstack(hp)) {  /* back edge: reverse it */
00893             graph[i].edists[e] = x;
00894             for (f = 1; (f < graph[j].nedges) &&(graph[j].edges[f] != i); f++) ;
00895             assert (f < graph[j].nedges);
00896             graph[j].edists[f] = -1.0;
00897         }
00898         else if (ND_mark(hp) == FALSE) dfsCycle(graph, j, mode, nodes);
00899 
00900     }
00901     ND_onstack(np) = FALSE;
00902 }
00903 
00904 /* acyclic:
00905  * Do a dfs of the vtx_data, looking for cycles, reversing edges.
00906  */
00907 static void
00908 acyclic (vtx_data* graph, int nv, int mode, node_t* nodes[])
00909 {
00910     int i;
00911     node_t* np;
00912 
00913     for (i = 0; i < nv; i++) {
00914         np = nodes[i];
00915         ND_mark(np) = FALSE;
00916         ND_onstack(np) = FALSE;
00917     }
00918     for (i = 0; i < nv; i++) {
00919         if (ND_mark(nodes[i])) continue;
00920         dfsCycle (graph, i, mode, nodes);       
00921     }
00922 
00923 }
00924 #endif
00925 
00926 /* makeGraphData:
00927  * Create sparse graph representation via arrays.
00928  * Each node is represented by a vtx_data.
00929  * The index of each neighbor is stored in the edges array;
00930  * the corresponding edge lengths and weights go on ewgts and eweights.
00931  * We do not allocate the latter 2 if the graph does not use them.
00932  * By convention, graph[i].edges[0] == i.
00933  * The values graph[i].ewgts[0] and graph[i].eweights[0] are left undefined.
00934  *
00935  * In constructing graph from g, we neglect loops. We track multiedges (ignoring
00936  * direction). Edge weights are additive; the final edge length is the max.
00937  *
00938  * If direction is used, we set the edists field, -1 for tail, +1 for head. 
00939  * graph[i].edists[0] is left undefined. If multiedges exist, the direction
00940  * of the first one encountered is used. Finally, a pass is made to guarantee
00941  * the graph is acyclic.
00942  *
00943  */
00944 static vtx_data *makeGraphData(graph_t * g, int nv, int *nedges, int mode, int model, node_t*** nodedata)
00945 {
00946     vtx_data *graph;
00947     node_t** nodes;
00948     int ne = agnedges(g);       /* upper bound */
00949     int *edges;
00950     float *ewgts = NULL;
00951     node_t *np;
00952     edge_t *ep;
00953     float *eweights = NULL;
00954 #ifdef DIGCOLA
00955     float *edists = NULL;
00956 #endif
00957 #ifndef WITH_CGRAPH
00958     int haveLen;
00959 #else
00960     attrsym_t *haveLen;
00961 #endif
00962     int haveWt;
00963     int haveDir;
00964     PointMap *ps = newPM();
00965     int i, i_nedges, idx;
00966 
00967     /* lengths and weights unused in reweight model */
00968     if (model == MODEL_SUBSET) {
00969         haveLen = FALSE;
00970         haveWt = FALSE;
00971     } else {
00972 #ifndef WITH_CGRAPH
00973         haveLen = (agindex(g->root->proto->e, "len") >= 0);
00974 #else /* WITH_CGRAPH */
00975         haveLen = agattr(g, AGEDGE, "len", 0) ;
00976 #endif /* WITH_CGRAPH */
00977         haveWt = (E_weight != 0);
00978     }
00979     if (mode == MODE_HIER || mode == MODE_IPSEP)
00980         haveDir = TRUE;
00981     else
00982         haveDir = FALSE;
00983 
00984     graph = N_GNEW(nv, vtx_data);
00985     nodes = N_GNEW(nv, node_t*);
00986     edges = N_GNEW(2 * ne + nv, int);   /* reserve space for self loops */
00987     if (haveLen || haveDir)
00988         ewgts = N_GNEW(2 * ne + nv, float);
00989     if (haveWt)
00990         eweights = N_GNEW(2 * ne + nv, float);
00991 #ifdef DIGCOLA
00992     if (haveDir)
00993         edists = N_GNEW(2*ne+nv,float);
00994 #endif
00995 
00996     i = 0;
00997     ne = 0;
00998     for (np = agfstnode(g); np; np = agnxtnode(g, np)) {
00999         int j = 1;              /* index of neighbors */
01000         clearPM(ps);
01001         assert(ND_id(np) == i);
01002         nodes[i] = np;
01003         graph[i].edges = edges++;       /* reserve space for the self loop */
01004         if (haveLen || haveDir)
01005             graph[i].ewgts = ewgts++;
01006         else
01007             graph[i].ewgts = NULL;
01008         if (haveWt)
01009             graph[i].eweights = eweights++;
01010         else
01011             graph[i].eweights = NULL;
01012 #ifdef DIGCOLA
01013         if (haveDir) {
01014             graph[i].edists = edists++;
01015         }
01016         else
01017             graph[i].edists = NULL;
01018 #endif
01019         i_nedges = 1;           /* one for the self */
01020 
01021         for (ep = agfstedge(g, np); ep; ep = agnxtedge(g, ep, np)) {
01022             if (aghead(ep) == agtail(ep))
01023                 continue;       /* ignore loops */
01024             idx = checkEdge(ps, ep, j);
01025             if (idx != j) {     /* seen before */
01026                 if (haveWt)
01027                     graph[i].eweights[idx] += ED_factor(ep);
01028                 if (haveLen) {
01029                     int curlen = graph[i].ewgts[idx];
01030                     graph[i].ewgts[idx] = MAX(ED_dist(ep), curlen);
01031                 }
01032             } else {
01033                 node_t *vp = (((agtail(ep)) == np) ? aghead(ep) : agtail(ep));
01034                 ne++;
01035                 j++;
01036 
01037                 *edges++ = ND_id(vp);
01038                 if (haveWt)
01039                     *eweights++ = ED_factor(ep);
01040                 if (haveLen)
01041                     *ewgts++ = ED_dist(ep);
01042                 else if (haveDir)
01043                     *ewgts++ = 1.0;
01044 #ifdef DIGCOLA
01045                 if (haveDir) {
01046                     char *s = agget(ep,"dir");
01047                     if(s&&!strncmp(s,"none",4)) {
01048                         *edists++ = 0;
01049                     } else {
01050                         *edists++ = (np == aghead(ep) ? 1.0 : -1.0);
01051                     }
01052                 }
01053 #endif
01054                 i_nedges++;
01055             }
01056         }
01057 
01058         graph[i].nedges = i_nedges;
01059         graph[i].edges[0] = i;
01060 #ifdef USE_STYLES
01061         graph[i].styles = NULL;
01062 #endif
01063         i++;
01064     }
01065 #ifdef DIGCOLA
01066     if (haveDir) {
01067     /* Make graph acyclic */
01068         acyclic (graph, nv, mode, nodes);
01069     }
01070 #endif
01071 
01072     ne /= 2;                    /* every edge is counted twice */
01073 
01074     /* If necessary, release extra memory. */
01075     if (ne != agnedges(g)) {
01076         edges = RALLOC(2 * ne + nv, graph[0].edges, int);
01077         if (haveLen)
01078             ewgts = RALLOC(2 * ne + nv, graph[0].ewgts, float);
01079         if (haveWt)
01080             eweights = RALLOC(2 * ne + nv, graph[0].eweights, float);
01081 
01082         for (i = 0; i < nv; i++) {
01083             int sz = graph[i].nedges;
01084             graph[i].edges = edges;
01085             edges += sz;
01086             if (haveLen) {
01087                 graph[i].ewgts = ewgts;
01088                 ewgts += sz;
01089             }
01090             if (haveWt) {
01091                 graph[i].eweights = eweights;
01092                 eweights += sz;
01093             }
01094         }
01095     }
01096 
01097     *nedges = ne;
01098     if (nodedata)
01099         *nodedata = nodes;
01100     else
01101         free (nodes);
01102     freePM(ps);
01103     return graph;
01104 }
01105 
01106 static void initRegular(graph_t * G, int nG)
01107 {
01108     double a, da;
01109     node_t *np;
01110 
01111     a = 0.0;
01112     da = (2 * M_PI) / nG;
01113     for (np = agfstnode(G); np; np = agnxtnode(G, np)) {
01114         ND_pos(np)[0] = nG * Spring_coeff * cos(a);
01115         ND_pos(np)[1] = nG * Spring_coeff * sin(a);
01116         ND_pinned(np) = P_SET;
01117         a = a + da;
01118         if (Ndim > 2)
01119             jitter3d(np, nG);
01120     }
01121 }
01122 
01123 #define SLEN(s) (sizeof(s)-1)
01124 #define SMART   "self"
01125 #define REGULAR "regular"
01126 #define RANDOM  "random"
01127 
01128 /* setSeed:
01129  * Analyze "start" attribute. If unset, return dflt.
01130  * If it begins with self, regular, or random, return set init to same,
01131  * else set init to dflt.
01132  * If init is random, look for value integer suffix to use a seed; if not
01133  * found, use time to set seed and store seed in graph.
01134  * Return seed in seedp.
01135  * Return init.
01136  */
01137 int
01138 setSeed (graph_t * G, int dflt, long* seedp)
01139 {
01140     char smallbuf[32];
01141     char *p = agget(G, "start");
01142     int init = dflt;
01143 
01144     if (!p || (*p == '\0')) return dflt;
01145     if (isalpha(*(unsigned char *)p)) {
01146         if (!strncmp(p, SMART, SLEN(SMART))) {
01147             init = INIT_SELF;
01148             p += SLEN(SMART);
01149         } else if (!strncmp(p, REGULAR, SLEN(REGULAR))) {
01150             init = INIT_REGULAR;
01151             p += SLEN(REGULAR);
01152         } else if (!strncmp(p, RANDOM, SLEN(RANDOM))) {
01153             init = INIT_RANDOM;
01154             p += SLEN(RANDOM);
01155         }
01156         else init = dflt;
01157     }
01158     else if (isdigit(*(unsigned char *)p)) {
01159         init = INIT_RANDOM;
01160     }
01161     
01162     if (init == INIT_RANDOM) {
01163         long seed;
01164         /* Check for seed value */
01165         if (!isdigit(*(unsigned char *)p) || sscanf(p, "%ld", &seed) < 1) {
01166 #if defined(MSWIN32) || defined(WIN32)
01167             seed = (unsigned) time(NULL);
01168 #else
01169             seed = (unsigned) getpid() ^ (unsigned) time(NULL);
01170 #endif
01171             sprintf(smallbuf, "%ld", seed);
01172             agset(G, "start", smallbuf);
01173         }
01174         *seedp = seed;
01175     }
01176     return init;
01177 }
01178 
01179 /* checkExp:
01180  * Allow various weights for the scale factor in used to calculate stress.
01181  * At present, only 1 or 2 are allowed, with 2 the default.
01182  */
01183 #define exp_name "stresswt"
01184 
01185 static int checkExp (graph_t * G)
01186 {
01187     int exp = late_int(G, agfindgraphattr(G, exp_name), 2, 0);
01188     if ((exp == 0) || (exp > 2)) {
01189         agerr (AGWARN, "%s attribute value must be 1 or 2 - ignoring\n", exp_name);
01190         exp = 2;
01191     }
01192     return exp;
01193 }
01194 
01195 /* checkStart:
01196  * Analyzes start attribute, setting seed.
01197  * If set,
01198  *   If start is regular, places nodes and returns INIT_REGULAR.
01199  *   If start is self, returns INIT_SELF.
01200  *   If start is random, returns INIT_RANDOM
01201  *   Set RNG seed
01202  * else return default
01203  * 
01204  */
01205 int checkStart(graph_t * G, int nG, int dflt)
01206 {
01207     long seed;
01208     int init;
01209 
01210     seed = 1;
01211     init = setSeed (G, dflt, &seed); 
01212     if (N_pos && (init != INIT_RANDOM)) {
01213         agerr(AGWARN, "node positions are ignored unless start=random\n");
01214     }
01215     if (init == INIT_REGULAR) initRegular(G, nG);
01216     srand48(seed);
01217     return init;
01218 }
01219 
01220 #ifdef DEBUG_COLA
01221 void dumpData(graph_t * g, vtx_data * gp, int nv, int ne)
01222 {
01223     node_t *v;
01224     int i, j, n;
01225 
01226     fprintf(stderr, "#nodes %d #edges %d\n", nv, ne);
01227     for (v = agfstnode(g); v; v = agnxtnode(g, v)) {
01228         fprintf(stderr, "\"%s\" %d\n", agnameof(v), ND_id(v));
01229     }
01230     for (i = 0; i < nv; i++) {
01231         n = gp[i].nedges;
01232         fprintf(stderr, "[%d] %d\n", i, n);
01233         for (j = 0; j < n; j++) {
01234             fprintf(stderr, "  %3d", gp[i].edges[j]);
01235         }
01236         fputs("\n", stderr);
01237         if (gp[i].ewgts) {
01238             fputs("  ewgts", stderr);
01239             for (j = 0; j < n; j++) {
01240                 fprintf(stderr, "  %3f", gp[i].ewgts[j]);
01241             }
01242             fputs("\n", stderr);
01243         }
01244         if (gp[i].eweights) {
01245             fputs("  eweights", stderr);
01246             for (j = 0; j < n; j++) {
01247                 fprintf(stderr, "  %3f", gp[i].eweights[j]);
01248             }
01249             fputs("\n", stderr);
01250         }
01251         if (gp[i].edists) {
01252             fputs("  edists", stderr);
01253             for (j = 0; j < n; j++) {
01254                 fprintf(stderr, "  %3f", gp[i].edists[j]);
01255             }
01256             fputs("\n", stderr);
01257         }
01258         fputs("\n", stderr);
01259 
01260     }
01261 }
01262 void dumpClusterData (cluster_data* dp)
01263 {
01264   int i, j, sz;
01265 
01266   fprintf (stderr, "nvars %d nclusters %d ntoplevel %d\n", dp->nvars, dp->nclusters, dp->ntoplevel);
01267   fprintf (stderr, "Clusters:\n");
01268   for (i = 0; i < dp->nclusters; i++) {
01269     sz = dp->clustersizes[i];
01270     fprintf (stderr, "  [%d] %d vars\n", i, sz);
01271     for (j = 0; j < sz; j++)
01272       fprintf (stderr, "  %d", dp->clusters[i][j]);
01273     fprintf (stderr, "\n");
01274   }
01275     
01276 
01277   fprintf (stderr, "Toplevel:\n");
01278   for (i = 0; i < dp->ntoplevel; i++)
01279     fprintf (stderr, "  %d\n", dp->toplevel[i]);
01280 
01281   fprintf (stderr, "Boxes:\n");
01282   for (i = 0; i < dp->nclusters; i++) {
01283     boxf bb = dp->bb[i];
01284     fprintf (stderr, "  (%f,%f) (%f,%f)\n", bb.LL.x, bb.LL.y, bb.UR.x, bb.UR.y);
01285   }
01286 }
01287 void dumpOpts (ipsep_options* opp, int nv)
01288 {
01289   int i;
01290 
01291   fprintf (stderr, "diredges %d edge_gap %f noverlap %d gap (%f,%f)\n", opp->diredges, opp->edge_gap, opp->noverlap, opp->gap.x, opp->gap.y);
01292   for (i = 0; i < nv; i++)
01293     fprintf (stderr, "  (%f,%f)\n", opp->nsize[i].x, opp->nsize[i].y);
01294   if (opp->clusters)
01295     dumpClusterData (opp->clusters);
01296 }
01297 #endif
01298 
01299 /* majorization:
01300  * Solve stress using majorization.
01301  * Old neato attributes to incorporate:
01302  *  weight
01303  * mode will be MODE_MAJOR, MODE_HIER or MODE_IPSEP
01304  */
01305 static void
01306 majorization(graph_t *mg, graph_t * g, int nv, int mode, int model, int dim, int steps, adjust_data* am)
01307 {
01308     double **coords;
01309     int ne;
01310     int i, rv = 0;
01311     node_t *v;
01312     vtx_data *gp;
01313     node_t** nodes;
01314 #ifdef DIGCOLA
01315 #ifdef IPSEPCOLA
01316     expand_t margin;
01317 #endif
01318 #endif
01319     int init = checkStart(g, nv, (mode == MODE_HIER ? INIT_SELF : INIT_RANDOM));
01320     int opts = checkExp (g);
01321         
01322     if (init == INIT_SELF)
01323         opts |= opt_smart_init;
01324 
01325     coords = N_GNEW(dim, double *);
01326     coords[0] = N_GNEW(nv * dim, double);
01327     for (i = 1; i < Ndim; i++) {
01328         coords[i] = coords[0] + i * nv;
01329     }
01330     if (Verbose) {
01331         fprintf(stderr, "model %d smart_init %d stresswt %d iterations %d tol %f\n",
01332                 model, (init == INIT_SELF), opts & opt_exp_flag, MaxIter, Epsilon);
01333         fprintf(stderr, "convert graph: ");
01334         start_timer();
01335 #ifdef WITH_CGRAPH
01336         fprintf(stderr, "majorization\n");
01337 //      fprintf(stderr, "%i\n", count_nodes(g));
01338 
01339 #endif /* WITH_CGRAPH */
01340     }
01341     gp = makeGraphData(g, nv, &ne, mode, model, &nodes);
01342 
01343     if (Verbose) {
01344         fprintf(stderr, "%d nodes %.2f sec\n", nv, elapsed_sec());
01345     }
01346 
01347 #ifdef DIGCOLA
01348     if (mode != MODE_MAJOR) {
01349         double lgap = late_double(g, agfindgraphattr(g, "levelsgap"), 0.0, -MAXDOUBLE);
01350         if (mode == MODE_HIER) {        
01351             rv = stress_majorization_with_hierarchy(gp, nv, ne, coords, nodes, Ndim,
01352                        opts, model, MaxIter, lgap);
01353         } 
01354 #ifdef IPSEPCOLA
01355         else {
01356             char* str;
01357             ipsep_options opt;
01358             pointf* nsize;
01359             cluster_data *cs = (cluster_data*)cluster_map(mg,g);
01360             nsize = N_GNEW(nv, pointf);
01361             opt.edge_gap = lgap;
01362 #ifdef MOSEK
01363             opt.mosek = 0;
01364 #endif /* MOSEK */
01365             opt.nsize = nsize;
01366             opt.clusters = cs;
01367             str = agget(g, "diredgeconstraints");
01368             if (mapbool(str)) {
01369                 opt.diredges = 1;
01370                 if(Verbose)
01371                     fprintf(stderr,"Generating Edge Constraints...\n");
01372             } else if (str && !strncasecmp(str,"hier",4)) {
01373                 opt.diredges = 2;
01374                 if(Verbose)
01375                     fprintf(stderr,"Generating DiG-CoLa Edge Constraints...\n");
01376             }
01377             else opt.diredges = 0;
01378             if (am->mode == AM_IPSEP) {
01379                 opt.noverlap = 1;
01380                 if(Verbose)
01381                     fprintf(stderr,"Generating Non-overlap Constraints...\n");
01382             } else if (am->mode == AM_VPSC) {
01383                 opt.noverlap = 2;
01384                 if(Verbose)
01385                     fprintf(stderr,"Removing overlaps as postprocess...\n");
01386             }  
01387             else opt.noverlap = 0;
01388 #ifdef MOSEK
01389             str = agget(g, "mosek");
01390             if(str && !strncmp(str,"true",4)) {
01391                 opt.mosek = 1;
01392                 if(Verbose)
01393                     fprintf(stderr,"Using Mosek for constraint optimization...\n");
01394             }
01395 #endif /* MOSEK */
01396             margin = sepFactor (g);
01397             /* Multiply by 2 since opt.gap is the gap size, not the margin */
01398             if (margin.doAdd) {
01399                 opt.gap.x = 2.0*PS2INCH(margin.x);
01400                 opt.gap.y = 2.0*PS2INCH(margin.y);
01401             }
01402             else opt.gap.x = opt.gap.y = 2.0*PS2INCH(DFLT_MARGIN);
01403             if(Verbose)
01404                 fprintf(stderr,"gap=%f,%f\n",opt.gap.x,opt.gap.y);
01405             for (i=0, v = agfstnode(g); v; v = agnxtnode(g, v),i++) {
01406                 nsize[i].x = ND_width(v);
01407                 nsize[i].y = ND_height(v);
01408             }
01409 
01410 #ifdef DEBUG_COLA
01411             fprintf (stderr, "nv %d ne %d Ndim %d model %d MaxIter %d\n", nv, ne, Ndim, model, MaxIter);
01412             fprintf (stderr, "Nodes:\n");
01413             for (i = 0; i < nv; i++) {
01414                 fprintf (stderr, "  %s (%f,%f)\n", nodes[i]->name, coords[0][i],  coords[1][i]);
01415             }
01416             fprintf (stderr, "\n");
01417             dumpData(g, gp, nv, ne);
01418             fprintf (stderr, "\n");
01419             dumpOpts (&opt, nv);
01420 #endif
01421             rv = stress_majorization_cola(gp, nv, ne, coords, nodes, Ndim, model, MaxIter, &opt);
01422             freeClusterData(cs);
01423             free (nsize);
01424         }
01425 #endif
01426     }
01427     else
01428 #endif
01429         rv = stress_majorization_kD_mkernel(gp, nv, ne, coords, nodes, Ndim, opts, model, MaxIter);
01430 
01431     if (rv < 0) {
01432         agerr(AGPREV, "layout aborted\n");
01433     }
01434     else for (v = agfstnode(g); v; v = agnxtnode(g, v)) { /* store positions back in nodes */
01435         int idx = ND_id(v);
01436         int i;
01437         for (i = 0; i < Ndim; i++) {
01438             ND_pos(v)[i] = coords[i][idx];
01439         }
01440     }
01441     freeGraphData(gp);
01442     free(coords[0]);
01443     free(coords);
01444     free(nodes);
01445 }
01446 
01447 static void subset_model(Agraph_t * G, int nG)
01448 {
01449     int i, j, ne;
01450     DistType **Dij;
01451     vtx_data *gp;
01452 
01453     gp = makeGraphData(G, nG, &ne, MODE_KK, MODEL_SUBSET, NULL);
01454     Dij = compute_apsp_artifical_weights(gp, nG);
01455     for (i = 0; i < nG; i++) {
01456         for (j = 0; j < nG; j++) {
01457             GD_dist(G)[i][j] = Dij[i][j];
01458         }
01459     }
01460     free(Dij[0]);
01461     free(Dij);
01462     freeGraphData(gp);
01463 }
01464 
01465 /* mds_model:
01466  * Assume the matrix already contains shortest path values.
01467  * Use the actual lengths provided the input for edges.
01468  */
01469 static void mds_model(graph_t * g, int nG)
01470 {
01471     long i, j;
01472     node_t *v;
01473     edge_t *e;
01474 
01475     for (v = agfstnode(g); v; v = agnxtnode(g, v)) {
01476         for (e = agfstout(g, v); e; e = agnxtout(g, e)) {
01477             i = AGSEQ(agtail(e));
01478             j = AGSEQ(aghead(e));
01479             if (i == j)
01480                 continue;
01481             GD_dist(g)[i][j] = GD_dist(g)[j][i] = ED_dist(e);
01482         }
01483     }
01484 }
01485 
01486 /* kkNeato:
01487  * Solve using gradient descent a la Kamada-Kawai.
01488  */
01489 static void kkNeato(Agraph_t * g, int nG, int model)
01490 {
01491     if (model == MODEL_SUBSET) {
01492         subset_model(g, nG);
01493     } else if (model == MODEL_CIRCUIT) {
01494         if (!circuit_model(g, nG)) {
01495             agerr(AGWARN,
01496                   "graph %s is disconnected. Hence, the circuit model\n",
01497                   agnameof(g));
01498             agerr(AGPREV,
01499                   "is undefined. Reverting to the shortest path model.\n");
01500             agerr(AGPREV,
01501                   "Alternatively, consider running neato using -Gpack=true or decomposing\n");
01502             agerr(AGPREV, "the graph into connected components.\n");
01503             shortest_path(g, nG);
01504         }
01505     } else if (model == MODEL_MDS) {
01506         shortest_path(g, nG);
01507         mds_model(g, nG);
01508     } else
01509         shortest_path(g, nG);
01510     initial_positions(g, nG);
01511     diffeq_model(g, nG);
01512     if (Verbose) {
01513         fprintf(stderr, "Solving model %d iterations %d tol %f\n",
01514                 model, MaxIter, Epsilon);
01515         start_timer();
01516     }
01517     solve_model(g, nG);
01518 }
01519 
01520 /* neatoLayout:
01521  * Use stress optimization to layout a single component
01522  */
01523 static void 
01524 neatoLayout(Agraph_t * mg, Agraph_t * g, int layoutMode, int layoutModel,
01525   adjust_data* am)
01526 {
01527     int nG;
01528     char *str;
01529 
01530     if ((str = agget(g, "maxiter")))
01531         MaxIter = atoi(str);
01532     else if (layoutMode == MODE_MAJOR)
01533         MaxIter = DFLT_ITERATIONS;
01534     else
01535         MaxIter = 100 * agnnodes(g);
01536 
01537     nG = scan_graph_mode(g, layoutMode);
01538     if ((nG < 2) || (MaxIter <=0))
01539         return;
01540     if (layoutMode)
01541         majorization(mg, g, nG, layoutMode, layoutModel, Ndim, MaxIter, am);
01542     else
01543         kkNeato(g, nG, layoutModel);
01544 }
01545 
01546 /* addZ;
01547  * If dimension == 3 and z attribute is declared, 
01548  * attach z value to nodes if not defined.
01549  */
01550 static void addZ (Agraph_t* g)
01551 {
01552     node_t* n;
01553     char    buf[BUFSIZ];
01554 
01555     if ((Ndim >= 3) && N_z) { 
01556         for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
01557             sprintf(buf, "%lf", POINTS_PER_INCH * (ND_pos(n)[2]));
01558 #ifndef WITH_CGRAPH
01559             agxset(n, N_z->index, buf);
01560 #else /* WITH_CGRAPH */
01561             agxset(n, N_z, buf);
01562 #endif /* WITH_CGRAPH */
01563         }
01564     }
01565 }
01566 
01567 #ifdef IPSEPCOLA
01568 static void
01569 addCluster (graph_t* g)
01570 {
01571     graph_t *subg;
01572 #ifndef WITH_CGRAPH
01573     graph_t *mg;
01574     node_t *mm, *mn;
01575     edge_t *me;
01576     mm = g->meta_node;
01577     mg = agraphof(mm);
01578     for (me = agfstout(mg, mm); me; me = agnxtout(mg, me)) {
01579         mn = aghead(me);
01580         subg = agusergraph(mn);
01581 #else
01582     for (subg = agfstsubg(agroot(g)); subg; subg = agnxtsubg(subg)) {
01583 #endif
01584         if (!strncmp(agnameof(subg), "cluster", 7)) {
01585 #ifdef WITH_CGRAPH
01586             agbindrec(subg, "Agraphinfo_t", sizeof(Agraphinfo_t), TRUE);
01587 #endif
01588             add_cluster(g, subg);
01589             compute_bb(subg);
01590         }
01591    }
01592 }
01593 #endif
01594 
01595 /* neato_layout:
01596  */
01597 void neato_layout(Agraph_t * g)
01598 {
01599     int layoutMode;
01600     int model;
01601     pack_mode mode;
01602     pack_info pinfo;
01603     adjust_data am;
01604 
01605     if (Nop) {
01606         int save = PSinputscale;
01607         int ret;
01608         PSinputscale = POINTS_PER_INCH;
01609         neato_init_graph(g);
01610         addZ (g);
01611         ret = init_nop(g, 1);
01612         PSinputscale = save;
01613         if (ret < 0) {
01614             agerr(AGPREV, "as required by the -n flag\n");
01615             return;
01616         }
01617         else gv_postprocess(g, !ret);
01618     } else {
01619         neato_init_graph(g);
01620         layoutMode = neatoMode(g);
01621         graphAdjustMode (g, &am, 0);
01622         model = neatoModel(g);
01623         mode = getPackModeInfo (g, l_undef, &pinfo);
01624         Pack = getPack(g, -1, CL_OFFSET);
01625         /* pack if just packmode defined. */
01626         if (mode == l_undef) {
01627             /* If the user has not indicated packing but we are
01628              * using the new neato, turn packing on.
01629              */
01630             if ((Pack < 0) && layoutMode)
01631                 Pack = CL_OFFSET;
01632             pinfo.mode = l_node;
01633         } else if (Pack < 0)
01634             Pack = CL_OFFSET;
01635         if (Pack >= 0) {
01636             graph_t *gc;
01637             graph_t **cc;
01638             int n_cc;
01639             int i;
01640             boolean pin;
01641 
01642             cc = pccomps(g, &n_cc, cc_pfx, &pin);
01643 
01644             if (n_cc > 1) {
01645                 boolean *bp;
01646                 for (i = 0; i < n_cc; i++) {
01647                     gc = cc[i];
01648                     nodeInduce(gc);
01649                     neatoLayout(g, gc, layoutMode, model, &am);
01650                     removeOverlapWith(gc, &am);
01651                     setEdgeType (gc, ET_LINE);
01652                     spline_edges(gc);
01653                 }
01654                 if (pin) {
01655                     bp = N_NEW(n_cc, boolean);
01656                     bp[0] = TRUE;
01657                 } else
01658                     bp = 0;
01659                 pinfo.margin = Pack;
01660                 pinfo.fixed = bp;
01661                 pinfo.doSplines = 1;
01662                 packGraphs(n_cc, cc, g, &pinfo);
01663                 if (bp)
01664                     free(bp);
01665             }
01666             else {
01667                 neatoLayout(g, g, layoutMode, model, &am);
01668                 removeOverlapWith(g, &am);
01669                 spline_edges(g);
01670             }
01671             compute_bb(g);
01672             addZ (g);
01673 
01674             /* cleanup and remove component subgraphs */
01675             for (i = 0; i < n_cc; i++) {
01676                 gc = cc[i];
01677                 free_scan_graph(gc);
01678 #ifdef WITH_CGRAPH
01679                 agdelrec (gc, "Agraphinfo_t"); 
01680 #endif
01681                 agdelete(g, gc);
01682             }
01683             free (cc);
01684 #ifdef IPSEPCOLA
01685             addCluster (g);
01686 #endif
01687         } else {
01688             neatoLayout(g, g, layoutMode, model, &am);
01689             removeOverlapWith(g, &am);
01690             addZ (g);
01691             spline_edges(g);
01692         }
01693         dotneato_postprocess(g);
01694     }
01695 }