/misc/src/release/graphviz-2.18-1/src/graphviz-2.18/lib/neatogen/stuff.c

Go to the documentation of this file.
00001 /* $Id: stuff.c,v 1.4 2007/11/16 22:55:03 erg Exp $ $Revision: 1.4 $ */
00002 /* vim:set shiftwidth=4 ts=8: */
00003 
00004 /**********************************************************
00005 *      This software is part of the graphviz package      *
00006 *                http://www.graphviz.org/                 *
00007 *                                                         *
00008 *            Copyright (c) 1994-2004 AT&T Corp.           *
00009 *                and is licensed under the                *
00010 *            Common Public License, Version 1.0           *
00011 *                      by AT&T Corp.                      *
00012 *                                                         *
00013 *        Information and Software Systems Research        *
00014 *              AT&T Research, Florham Park NJ             *
00015 **********************************************************/
00016 
00017 
00018 #ifdef HAVE_CONFIG_H
00019 #include "config.h"
00020 #endif
00021 
00022 #include        "neato.h"
00023 #include        "stress.h"
00024 #include        <time.h>
00025 #ifndef WIN32
00026 #include        <unistd.h>
00027 #endif
00028 
00029 static double Epsilon2;
00030 #ifndef HAVE_DRAND48
00031 double drand48(void)
00032 {
00033     double d;
00034     d = rand();
00035     d = d / RAND_MAX;
00036     return d;
00037 }
00038 #endif
00039 
00040 double fpow32(double x)
00041 {
00042     x = sqrt(x);
00043     return x * x * x;
00044 }
00045 
00046 double distvec(double *p0, double *p1, double *vec)
00047 {
00048     int k;
00049     double dist = 0.0;
00050 
00051     for (k = 0; k < Ndim; k++) {
00052         vec[k] = p0[k] - p1[k];
00053         dist += (vec[k] * vec[k]);
00054     }
00055     dist = sqrt(dist);
00056     return dist;
00057 }
00058 
00059 double **new_array(int m, int n, double ival)
00060 {
00061     double **rv;
00062     double *mem;
00063     int i, j;
00064 
00065     rv = N_NEW(m, double *);
00066     mem = N_NEW(m * n, double);
00067     for (i = 0; i < m; i++) {
00068         rv[i] = mem;
00069         mem = mem + n;
00070         for (j = 0; j < n; j++)
00071             rv[i][j] = ival;
00072     }
00073     return rv;
00074 }
00075 
00076 void free_array(double **rv)
00077 {
00078     if (rv) {
00079         free(rv[0]);
00080         free(rv);
00081     }
00082 }
00083 
00084 
00085 static double ***new_3array(int m, int n, int p, double ival)
00086 {
00087     double ***rv;
00088     int i, j, k;
00089 
00090     rv = N_NEW(m + 1, double **);
00091     for (i = 0; i < m; i++) {
00092         rv[i] = N_NEW(n + 1, double *);
00093         for (j = 0; j < n; j++) {
00094             rv[i][j] = N_NEW(p, double);
00095             for (k = 0; k < p; k++)
00096                 rv[i][j][k] = ival;
00097         }
00098         rv[i][j] = NULL;        /* NULL terminate so we can clean up */
00099     }
00100     rv[i] = NULL;
00101     return rv;
00102 }
00103 
00104 static void free_3array(double ***rv)
00105 {
00106     int i, j;
00107 
00108     if (rv) {
00109         for (i = 0; rv[i]; i++) {
00110             for (j = 0; rv[i][j]; j++)
00111                 free(rv[i][j]);
00112             free(rv[i]);
00113         }
00114         free(rv);
00115     }
00116 }
00117 
00118 double doubleattr(void *obj, int index, double defval)
00119 {
00120     double val;
00121     if (index < 0)
00122         return defval;
00123     if (sscanf(agxget(obj, index), "%lf", &val) < 1)
00124         return defval;
00125     return val;
00126 }
00127 
00128 /* degreeKind;
00129  * Returns degree of n ignoring loops and multiedges.
00130  * Returns 0, 1 or many (2)
00131  * For case of 1, returns other endpoint of edge.
00132  */
00133 static int degreeKind(graph_t * g, node_t * n, node_t ** op)
00134 {
00135     edge_t *ep;
00136     int deg = 0;
00137     node_t *other = NULL;
00138 
00139     for (ep = agfstedge(g, n); ep; ep = agnxtedge(g, ep, n)) {
00140         if (ep->head == ep->tail)
00141             continue;           /* ignore loops */
00142         if (deg == 1) {
00143             if (((ep->tail == n) && (ep->head == other)) ||     /* ignore multiedge */
00144                 ((ep->tail == other) && (ep->head == n)))
00145                 continue;
00146             return 2;
00147         } else {                /* deg == 0 */
00148             if (ep->tail == n)
00149                 other = ep->head;
00150             else
00151                 other = ep->tail;
00152             *op = other;
00153             deg++;
00154         }
00155     }
00156     return deg;
00157 }
00158 
00159 
00160 /* prune:
00161  * np is at end of a chain. If its degree is 0, remove it.
00162  * If its degree is 1, remove it and recurse.
00163  * If its degree > 1, stop.
00164  * The node next is the next node to be visited during iteration.
00165  * If it is equal to a node being deleted, set it to next one.
00166  * Delete from root graph, since G may be a connected component subgraph.
00167  * Return next.
00168  */
00169 static node_t *prune(graph_t * G, node_t * np, node_t * next)
00170 {
00171     node_t *other;
00172     int deg;
00173 
00174     while (np) {
00175         deg = degreeKind(G, np, &other);
00176         if (deg == 0) {
00177             if (next == np)
00178                 next = agnxtnode(G, np);
00179             agdelete(G->root, np);
00180             np = 0;
00181         } else if (deg == 1) {
00182             if (next == np)
00183                 next = agnxtnode(G, np);
00184             agdelete(G->root, np);
00185             np = other;
00186         } else
00187             np = 0;
00188 
00189     }
00190     return next;
00191 }
00192 
00193 static double setEdgeLen(graph_t * G, node_t * np, int lenx)
00194 {
00195     edge_t *ep;
00196     double total_len = 0.0;
00197     double len;
00198     for (ep = agfstout(G, np); ep; ep = agnxtout(G, ep)) {
00199         len = doubleattr(ep, lenx, 1.0);
00200         if (len <= 0) {
00201             agerr(AGERR, "bad edge len %f in %s ignored\n", len, G->name);
00202             len = 1.0;
00203         }
00204         ED_dist(ep) = len;
00205         total_len += len;
00206     }
00207     return total_len;
00208 }
00209 
00210 /* scan_graph_mode:
00211  * Prepare the graph and data structures depending on the layout mode.
00212  * If Reduce is true, eliminate singletons and trees. Since G may be a
00213  * subgraph, we remove the nodes from the root graph.
00214  * Return the number of nodes in the reduced graph.
00215  */
00216 int scan_graph_mode(graph_t * G, int mode)
00217 {
00218     int i, lenx, nV, nE, deg;
00219     char *str;
00220     node_t *np, *xp, *other;
00221     double total_len = 0.0;
00222 
00223     if (Verbose)
00224         fprintf(stderr, "Scanning graph %s, %d nodes\n", G->name,
00225                 agnnodes(G));
00226 
00227     /* Eliminate singletons and trees */
00228     if (Reduce) {
00229         for (np = agfstnode(G); np; np = xp) {
00230             xp = agnxtnode(G, np);
00231             deg = degreeKind(G, np, &other);
00232             if (deg == 0) {     /* singleton node */
00233                 agdelete(G->root, np);
00234             } else if (deg == 1) {
00235                 agdelete(G->root, np);
00236                 xp = prune(G, other, xp);
00237             }
00238         }
00239     }
00240     nV = agnnodes(G);
00241     nE = agnedges(G);
00242 
00243     lenx = agindex(G->root->proto->e, "len");
00244     if (mode == MODE_KK) {
00245         Epsilon = .0001 * nV;
00246         getdouble(G, "epsilon", &Epsilon);
00247         if ((str = agget(G->root, "Damping")))
00248             Damping = atof(str);
00249         else
00250             Damping = .99;
00251         GD_neato_nlist(G) = N_NEW(nV + 1, node_t *);
00252         for (i = 0, np = agfstnode(G); np; np = agnxtnode(G, np)) {
00253             GD_neato_nlist(G)[i] = np;
00254             ND_id(np) = i++;
00255             ND_heapindex(np) = -1;
00256             total_len += setEdgeLen(G, np, lenx);
00257         }
00258     } else {
00259         Epsilon = DFLT_TOLERANCE;
00260         getdouble(G, "epsilon", &Epsilon);
00261         for (i = 0, np = agfstnode(G); np; np = agnxtnode(G, np)) {
00262             ND_id(np) = i++;
00263             total_len += setEdgeLen(G, np, lenx);
00264         }
00265     }
00266 
00267     str = agget(G, "defaultdist");
00268     if (str && str[0])
00269         Initial_dist = MAX(Epsilon, atof(str));
00270     else
00271         Initial_dist = total_len / (nE > 0 ? nE : 1) * sqrt(nV) + 1;
00272 
00273     if (!Nop && (mode == MODE_KK)) {
00274         GD_dist(G) = new_array(nV, nV, Initial_dist);
00275         GD_spring(G) = new_array(nV, nV, 1.0);
00276         GD_sum_t(G) = new_array(nV, Ndim, 1.0);
00277         GD_t(G) = new_3array(nV, nV, Ndim, 0.0);
00278     }
00279 
00280     return nV;
00281 }
00282 
00283 int scan_graph(graph_t * g)
00284 {
00285     return scan_graph_mode(g, MODE_KK);
00286 }
00287 
00288 void free_scan_graph(graph_t * g)
00289 {
00290     /* int  nG; */
00291     free(GD_neato_nlist(g));
00292     if (!Nop) {
00293         free_array(GD_dist(g));
00294         free_array(GD_spring(g));
00295         free_array(GD_sum_t(g));
00296         /* nG = agnnodes(g); */
00297         free_3array(GD_t(g));
00298         GD_t(g) = NULL;
00299     }
00300 }
00301 
00302 void jitter_d(node_t * np, int nG, int n)
00303 {
00304     int k;
00305     for (k = n; k < Ndim; k++)
00306         ND_pos(np)[k] = nG * drand48();
00307 }
00308 
00309 void jitter3d(node_t * np, int nG)
00310 {
00311     jitter_d(np, nG, 2);
00312 }
00313 
00314 void randompos(node_t * np, int nG)
00315 {
00316     ND_pos(np)[0] = nG * drand48();
00317     ND_pos(np)[1] = nG * drand48();
00318     if (Ndim > 2)
00319         jitter3d(np, nG);
00320 }
00321 
00322 void initial_positions(graph_t * G, int nG)
00323 {
00324     int init, i;
00325     node_t *np;
00326     static int once = 0;
00327 
00328     if (Verbose)
00329         fprintf(stderr, "Setting initial positions\n");
00330 
00331     init = checkStart(G, nG, INIT_RANDOM);
00332     if (init == INIT_REGULAR)
00333         return;
00334     if ((init == INIT_SELF) && (once == 0)) {
00335         agerr(AGWARN, "start=%s not supported with mode=self - ignored\n");
00336         once = 1;
00337     }
00338 
00339     for (i = 0; (np = GD_neato_nlist(G)[i]); i++) {
00340         if (hasPos(np))
00341             continue;
00342         randompos(np, 1);
00343     }
00344 }
00345 
00346 void diffeq_model(graph_t * G, int nG)
00347 {
00348     int i, j, k;
00349     double dist, **D, **K, del[MAXDIM], f;
00350     node_t *vi, *vj;
00351     edge_t *e;
00352 
00353     if (Verbose) {
00354         fprintf(stderr, "Setting up spring model: ");
00355         start_timer();
00356     }
00357     /* init springs */
00358     K = GD_spring(G);
00359     D = GD_dist(G);
00360     for (i = 0; i < nG; i++) {
00361         for (j = 0; j < i; j++) {
00362             f = Spring_coeff / (D[i][j] * D[i][j]);
00363             if ((e =
00364                  agfindedge(G, GD_neato_nlist(G)[i],
00365                             GD_neato_nlist(G)[j])))
00366                 f = f * ED_factor(e);
00367             K[i][j] = K[j][i] = f;
00368         }
00369     }
00370 
00371     /* init differential equation solver */
00372     for (i = 0; i < nG; i++)
00373         for (k = 0; k < Ndim; k++)
00374             GD_sum_t(G)[i][k] = 0.0;
00375 
00376     for (i = 0; (vi = GD_neato_nlist(G)[i]); i++) {
00377         for (j = 0; j < nG; j++) {
00378             if (i == j)
00379                 continue;
00380             vj = GD_neato_nlist(G)[j];
00381             dist = distvec(ND_pos(vi), ND_pos(vj), del);
00382             for (k = 0; k < Ndim; k++) {
00383                 GD_t(G)[i][j][k] =
00384                     GD_spring(G)[i][j] * (del[k] -
00385                                           GD_dist(G)[i][j] * del[k] /
00386                                           dist);
00387                 GD_sum_t(G)[i][k] += GD_t(G)[i][j][k];
00388             }
00389         }
00390     }
00391     if (Verbose) {
00392         fprintf(stderr, "%.2f sec\n", elapsed_sec());
00393     }
00394 }
00395 
00396 /* total_e:
00397  * Return 2*energy of system.
00398  */
00399 static double total_e(graph_t * G, int nG)
00400 {
00401     int i, j, d;
00402     double e = 0.0;             /* 2*energy */
00403     double t0;                  /* distance squared */
00404     double t1;
00405     node_t *ip, *jp;
00406 
00407     for (i = 0; i < nG - 1; i++) {
00408         ip = GD_neato_nlist(G)[i];
00409         for (j = i + 1; j < nG; j++) {
00410             jp = GD_neato_nlist(G)[j];
00411             for (t0 = 0.0, d = 0; d < Ndim; d++) {
00412                 t1 = (ND_pos(ip)[d] - ND_pos(jp)[d]);
00413                 t0 += t1 * t1;
00414             }
00415             e = e + GD_spring(G)[i][j] *
00416                 (t0 + GD_dist(G)[i][j] * GD_dist(G)[i][j]
00417                  - 2.0 * GD_dist(G)[i][j] * sqrt(t0));
00418         }
00419     }
00420     return e;
00421 }
00422 
00423 void solve_model(graph_t * G, int nG)
00424 {
00425     node_t *np;
00426 
00427     Epsilon2 = Epsilon * Epsilon;
00428 
00429     while ((np = choose_node(G, nG))) {
00430         move_node(G, nG, np);
00431     }
00432     if (Verbose) {
00433         fprintf(stderr, "\nfinal e = %f", total_e(G, nG));
00434         fprintf(stderr, " %d%s iterations %.2f sec\n",
00435                 GD_move(G), (GD_move(G) == MaxIter ? "!" : ""),
00436                 elapsed_sec());
00437     }
00438     if (GD_move(G) == MaxIter)
00439         agerr(AGWARN, "Max. iterations (%d) reached on graph %s\n",
00440               MaxIter, G->name);
00441 }
00442 
00443 void update_arrays(graph_t * G, int nG, int i)
00444 {
00445     int j, k;
00446     double del[MAXDIM], dist, old;
00447     node_t *vi, *vj;
00448 
00449     vi = GD_neato_nlist(G)[i];
00450     for (k = 0; k < Ndim; k++)
00451         GD_sum_t(G)[i][k] = 0.0;
00452     for (j = 0; j < nG; j++) {
00453         if (i == j)
00454             continue;
00455         vj = GD_neato_nlist(G)[j];
00456         dist = distvec(ND_pos(vi), ND_pos(vj), del);
00457         for (k = 0; k < Ndim; k++) {
00458             old = GD_t(G)[i][j][k];
00459             GD_t(G)[i][j][k] =
00460                 GD_spring(G)[i][j] * (del[k] -
00461                                       GD_dist(G)[i][j] * del[k] / dist);
00462             GD_sum_t(G)[i][k] += GD_t(G)[i][j][k];
00463             old = GD_t(G)[j][i][k];
00464             GD_t(G)[j][i][k] = -GD_t(G)[i][j][k];
00465             GD_sum_t(G)[j][k] += (GD_t(G)[j][i][k] - old);
00466         }
00467     }
00468 }
00469 
00470 #define Msub(i,j)  M[(i)*Ndim+(j)]
00471 void D2E(graph_t * G, int nG, int n, double *M)
00472 {
00473     int i, l, k;
00474     node_t *vi, *vn;
00475     double scale, sq, t[MAXDIM];
00476     double **K = GD_spring(G);
00477     double **D = GD_dist(G);
00478 
00479     vn = GD_neato_nlist(G)[n];
00480     for (l = 0; l < Ndim; l++)
00481         for (k = 0; k < Ndim; k++)
00482             Msub(l, k) = 0.0;
00483     for (i = 0; i < nG; i++) {
00484         if (n == i)
00485             continue;
00486         vi = GD_neato_nlist(G)[i];
00487         sq = 0.0;
00488         for (k = 0; k < Ndim; k++) {
00489             t[k] = ND_pos(vn)[k] - ND_pos(vi)[k];
00490             sq += (t[k] * t[k]);
00491         }
00492         scale = 1 / fpow32(sq);
00493         for (k = 0; k < Ndim; k++) {
00494             for (l = 0; l < k; l++)
00495                 Msub(l, k) += K[n][i] * D[n][i] * t[k] * t[l] * scale;
00496             Msub(k, k) +=
00497                 K[n][i] * (1.0 - D[n][i] * (sq - (t[k] * t[k])) * scale);
00498         }
00499     }
00500     for (k = 1; k < Ndim; k++)
00501         for (l = 0; l < k; l++)
00502             Msub(k, l) = Msub(l, k);
00503 }
00504 
00505 void final_energy(graph_t * G, int nG)
00506 {
00507     fprintf(stderr, "iterations = %d final e = %f\n", GD_move(G),
00508             total_e(G, nG));
00509 }
00510 
00511 node_t *choose_node(graph_t * G, int nG)
00512 {
00513     int i, k;
00514     double m, max;
00515     node_t *choice, *np;
00516     static int cnt = 0;
00517 #if 0
00518     double e;
00519     static double save_e = MAXDOUBLE;
00520 #endif
00521 
00522     cnt++;
00523     if (GD_move(G) >= MaxIter)
00524         return NULL;
00525 #if 0
00526     if ((cnt % 100) == 0) {
00527         e = total_e(G, nG);
00528         if (e - save_e > 0)
00529             return NULL;
00530         save_e = e;
00531     }
00532 #endif
00533     max = 0.0;
00534     choice = NULL;
00535     for (i = 0; i < nG; i++) {
00536         np = GD_neato_nlist(G)[i];
00537         if (ND_pinned(np) > P_SET)
00538             continue;
00539         for (m = 0.0, k = 0; k < Ndim; k++)
00540             m += (GD_sum_t(G)[i][k] * GD_sum_t(G)[i][k]);
00541         /* could set the color=energy of the node here */
00542         if (m > max) {
00543             choice = np;
00544             max = m;
00545         }
00546     }
00547     if (max < Epsilon2)
00548         choice = NULL;
00549     else {
00550         if (Verbose && (cnt % 100 == 0)) {
00551             fprintf(stderr, "%.3f ", sqrt(max));
00552             if (cnt % 1000 == 0)
00553                 fprintf(stderr, "\n");
00554         }
00555 #if 0
00556         e = total_e(G, nG);
00557         if (fabs((e - save_e) / save_e) < 1e-5) {
00558             choice = NULL;
00559         }
00560 #endif
00561     }
00562     return choice;
00563 }
00564 
00565 void move_node(graph_t * G, int nG, node_t * n)
00566 {
00567     int i, m;
00568     static double *a, b[MAXDIM], c[MAXDIM];
00569 
00570     m = ND_id(n);
00571     a = ALLOC(Ndim * Ndim, a, double);
00572     D2E(G, nG, m, a);
00573     for (i = 0; i < Ndim; i++)
00574         c[i] = -GD_sum_t(G)[m][i];
00575     solve(a, b, c, Ndim);
00576     for (i = 0; i < Ndim; i++) {
00577         b[i] = (Damping + 2 * (1 - Damping) * drand48()) * b[i];
00578         ND_pos(n)[i] += b[i];
00579     }
00580     GD_move(G)++;
00581     update_arrays(G, nG, m);
00582     if (test_toggle()) {
00583         double sum = 0;
00584         for (i = 0; i < Ndim; i++) {
00585             sum += fabs(b[i]);
00586         }                       /* Why not squared? */
00587         sum = sqrt(sum);
00588         fprintf(stderr, "%s %.3f\n", n->name, sum);
00589     }
00590 }
00591 
00592 static node_t **Heap;
00593 static int Heapsize;
00594 static node_t *Src;
00595 
00596 void heapup(node_t * v)
00597 {
00598     int i, par;
00599     node_t *u;
00600 
00601     for (i = ND_heapindex(v); i > 0; i = par) {
00602         par = (i - 1) / 2;
00603         u = Heap[par];
00604         if (ND_dist(u) <= ND_dist(v))
00605             break;
00606         Heap[par] = v;
00607         ND_heapindex(v) = par;
00608         Heap[i] = u;
00609         ND_heapindex(u) = i;
00610     }
00611 }
00612 
00613 void heapdown(node_t * v)
00614 {
00615     int i, left, right, c;
00616     node_t *u;
00617 
00618     i = ND_heapindex(v);
00619     while ((left = 2 * i + 1) < Heapsize) {
00620         right = left + 1;
00621         if ((right < Heapsize)
00622             && (Heap[right]->u.dist < Heap[left]->u.dist))
00623             c = right;
00624         else
00625             c = left;
00626         u = Heap[c];
00627         if (ND_dist(v) <= ND_dist(u))
00628             break;
00629         Heap[c] = v;
00630         ND_heapindex(v) = c;
00631         Heap[i] = u;
00632         ND_heapindex(u) = i;
00633         i = c;
00634     }
00635 }
00636 
00637 void neato_enqueue(node_t * v)
00638 {
00639     int i;
00640 
00641     assert(ND_heapindex(v) < 0);
00642     i = Heapsize++;
00643     ND_heapindex(v) = i;
00644     Heap[i] = v;
00645     if (i > 0)
00646         heapup(v);
00647 }
00648 
00649 node_t *neato_dequeue(void)
00650 {
00651     int i;
00652     node_t *rv, *v;
00653 
00654     if (Heapsize == 0)
00655         return NULL;
00656     rv = Heap[0];
00657     i = --Heapsize;
00658     v = Heap[i];
00659     Heap[0] = v;
00660     ND_heapindex(v) = 0;
00661     if (i > 1)
00662         heapdown(v);
00663     ND_heapindex(rv) = -1;
00664     return rv;
00665 }
00666 
00667 void shortest_path(graph_t * G, int nG)
00668 {
00669     node_t *v;
00670 
00671     Heap = N_NEW(nG + 1, node_t *);
00672     if (Verbose) {
00673         fprintf(stderr, "Calculating shortest paths: ");
00674         start_timer();
00675     }
00676     for (v = agfstnode(G); v; v = agnxtnode(G, v))
00677         s1(G, v);
00678     if (Verbose) {
00679         fprintf(stderr, "%.2f sec\n", elapsed_sec());
00680     }
00681     free(Heap);
00682 }
00683 
00684 void s1(graph_t * G, node_t * node)
00685 {
00686     node_t *v, *u;
00687     edge_t *e;
00688     int t;
00689     double f;
00690 
00691     for (t = 0; (v = GD_neato_nlist(G)[t]); t++)
00692         ND_dist(v) = Initial_dist;
00693     Src = node;
00694     ND_dist(Src) = 0;
00695     ND_hops(Src) = 0;
00696     neato_enqueue(Src);
00697 
00698     while ((v = neato_dequeue())) {
00699         if (v != Src)
00700             make_spring(G, Src, v, ND_dist(v));
00701         for (e = agfstedge(G, v); e; e = agnxtedge(G, e, v)) {
00702             if ((u = e->head) == v)
00703                 u = e->tail;
00704             f = ND_dist(v) + ED_dist(e);
00705             if (ND_dist(u) > f) {
00706                 ND_dist(u) = f;
00707                 if (ND_heapindex(u) >= 0)
00708                     heapup(u);
00709                 else {
00710                     ND_hops(u) = ND_hops(v) + 1;
00711                     neato_enqueue(u);
00712                 }
00713             }
00714         }
00715     }
00716 }
00717 
00718 void make_spring(graph_t * G, node_t * u, node_t * v, double f)
00719 {
00720     int i, j;
00721 
00722     i = ND_id(u);
00723     j = ND_id(v);
00724     GD_dist(G)[i][j] = GD_dist(G)[j][i] = f;
00725 }
00726 
00727 int allow_edits(int nsec)
00728 {
00729 #ifdef INTERACTIVE
00730     static int onetime = TRUE;
00731     static FILE *fp;
00732     static fd_set fd;
00733     static struct timeval tv;
00734 
00735     char buf[256], name[256];
00736     double x, y;
00737     node_t *np;
00738 
00739     if (onetime) {
00740         fp = fopen("/dev/tty", "r");
00741         if (fp == NULL)
00742             exit(1);
00743         setbuf(fp, NULL);
00744         tv.tv_usec = 0;
00745         onetime = FALSE;
00746     }
00747     tv.tv_sec = nsec;
00748     FD_ZERO(&fd);
00749     FD_SET(fileno(fp), &fd);
00750     if (select(32, &fd, (fd_set *) 0, (fd_set *) 0, &tv) > 0) {
00751         fgets(buf, sizeof(buf), fp);
00752         switch (buf[0]) {
00753         case 'm':               /* move node */
00754             if (sscanf(buf + 1, "%s %lf%lf", name, &x, &y) == 3) {
00755                 np = getnode(G, name);
00756                 if (np) {
00757                     NP_pos(np)[0] = x;
00758                     NP_pos(np)[1] = y;
00759                     diffeq_model();
00760                 }
00761             }
00762             break;
00763         case 'q':
00764             return FALSE;
00765         default:
00766             agerr(AGERR, "unknown command '%s', ignored\n", buf);
00767         }
00768         return TRUE;
00769     }
00770 #endif
00771     return FALSE;
00772 }

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