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