00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018 #ifdef HAVE_CONFIG_H
00019 #include "config.h"
00020 #endif
00021
00022 #include "neato.h"
00023 #include "adjust.h"
00024 #include "pathplan.h"
00025 #include "vispath.h"
00026 #ifndef HAVE_DRAND48
00027 extern double drand48(void);
00028 #endif
00029
00030 #define P2PF(p, pf) (pf.x = p.x, pf.y = p.y)
00031 #define PF2P(pf, p) (p.x = ROUND (pf.x), p.y = ROUND (pf.y))
00032
00033 extern void printvis(vconfig_t * cp);
00034 extern int in_poly(Ppoly_t argpoly, Ppoint_t q);
00035
00036 static boolean spline_merge(node_t * n)
00037 {
00038 return FALSE;
00039 }
00040
00041 static boolean swap_ends_p(edge_t * e)
00042 {
00043 return FALSE;
00044 }
00045
00046 static splineInfo sinfo = { swap_ends_p, spline_merge };
00047
00048 static void
00049 make_barriers(Ppoly_t ** poly, int npoly, int pp, int qp,
00050 Pedge_t ** barriers, int *n_barriers)
00051 {
00052 int i, j, k, n, b;
00053 Pedge_t *bar;
00054
00055 n = 0;
00056 for (i = 0; i < npoly; i++) {
00057 if (i == pp)
00058 continue;
00059 if (i == qp)
00060 continue;
00061 n = n + poly[i]->pn;
00062 }
00063 bar = N_GNEW(n, Pedge_t);
00064 b = 0;
00065 for (i = 0; i < npoly; i++) {
00066 if (i == pp)
00067 continue;
00068 if (i == qp)
00069 continue;
00070 for (j = 0; j < poly[i]->pn; j++) {
00071 k = j + 1;
00072 if (k >= poly[i]->pn)
00073 k = 0;
00074 bar[b].a = poly[i]->ps[j];
00075 bar[b].b = poly[i]->ps[k];
00076 b++;
00077 }
00078 }
00079 assert(b == n);
00080 *barriers = bar;
00081 *n_barriers = n;
00082 }
00083
00084
00085
00086 static Ppoint_t recPt(double x, double y, point c, double sep)
00087 {
00088 Ppoint_t p;
00089
00090 p.x = (x * sep) + c.x;
00091 p.y = (y * sep) + c.y;
00092 return p;
00093 }
00094
00095 static void makePortLabels(edge_t * e)
00096 {
00097 if (ED_head_label(e) && !ED_head_label(e)->set) {
00098 place_portlabel(e, TRUE);
00099 updateBB(e->tail->graph, ED_head_label(e));
00100 }
00101 if (ED_tail_label(e) && !ED_tail_label(e)->set) {
00102 place_portlabel(e, FALSE);
00103 updateBB(e->tail->graph, ED_tail_label(e));
00104 }
00105 }
00106
00107
00108
00109
00110
00111 static void endPoints(splines * spl, point * p, point * q)
00112 {
00113 bezier bz;
00114
00115 bz = spl->list[0];
00116 if (bz.sflag)
00117 *p = bz.sp;
00118 else
00119 *p = bz.list[0];
00120 bz = spl->list[spl->size - 1];
00121 if (bz.eflag)
00122 *q = bz.ep;
00123 else
00124 *q = bz.list[bz.size - 1];
00125 }
00126
00127
00128
00129
00130
00131 static point
00132 polylineMidpoint (splines* spl, point* pp, point* pq)
00133 {
00134 bezier bz;
00135 int i, j, k;
00136 double d, dist = 0;
00137 point m;
00138 pointf pf, qf, mf;
00139
00140 for (i = 0; i < spl->size; i++) {
00141 bz = spl->list[i];
00142 for (j = 0, k=3; k < bz.size; j+=3,k+=3) {
00143 P2PF (bz.list[j],pf);
00144 P2PF (bz.list[k],qf);
00145 dist += DIST(pf,qf);
00146 }
00147 }
00148 dist /= 2;
00149 for (i = 0; i < spl->size; i++) {
00150 bz = spl->list[i];
00151 for (j = 0, k=3; k < bz.size; j+=3,k+=3) {
00152 P2PF (bz.list[j],pf);
00153 P2PF (bz.list[k],qf);
00154 d = DIST(pf,qf);
00155 if (d >= dist) {
00156 *pp = bz.list[j];
00157 *pq = bz.list[k];
00158 mf.x = ((qf.x*dist) + (pf.x*(d-dist)))/d;
00159 mf.y = ((qf.y*dist) + (pf.y*(d-dist)))/d;
00160 PF2P(mf, m);
00161 return m;
00162 }
00163 else
00164 dist -= d;
00165 }
00166 }
00167 assert (FALSE);
00168 return m;
00169 }
00170
00171 #define LEFTOF(a,b,c) (((a.y - b.y)*(c.x - b.x) - (c.y - b.y)*(a.x - b.x)) > 0)
00172 #define MAXLABELWD (POINTS_PER_INCH/2.0)
00173
00174
00175
00176
00177
00178
00179
00180
00181
00182
00183
00184 static void addEdgeLabels(edge_t * e, point rp, point rq)
00185 {
00186 int et = EDGE_TYPE (e->head->graph->root);
00187 point p, q;
00188 point d;
00189 point ld;
00190 point sp;
00191 point del;
00192 pointf spf;
00193 double f, ht, wd, dist2;
00194 int leftOf;
00195
00196 if (ED_label(e) && !ED_label(e)->set) {
00197 endPoints(ED_spl(e), &p, &q);
00198 if ((p.x == q.x) && (p.y == q.y)) {
00199 p = rp;
00200 q = rq;
00201 sp = p;
00202 }
00203 else if (et == ET_SPLINE) {
00204 d.x = (q.x + p.x) / 2;
00205 d.y = (p.y + q.y) / 2;
00206 sp = dotneato_closest(ED_spl(e), d);
00207 }
00208 else {
00209 sp = polylineMidpoint (ED_spl(e), &p, &q);
00210 }
00211 del.x = q.x - p.x;
00212 del.y = q.y - p.y;
00213 dist2 = del.x*del.x + del.y*del.y;
00214 ht = (ED_label(e)->dimen.y + 2)/2.0;
00215 spf.x = sp.x;
00216 spf.y = sp.y;
00217 if (dist2) {
00218 wd = (MIN(ED_label(e)->dimen.x + 2, MAXLABELWD))/2.0;
00219 leftOf = LEFTOF(p, q, sp);
00220 if ((leftOf && (del.y >= 0)) || (!leftOf && (del.y < 0))) {
00221 if (del.x*del.y >= 0)
00222 ht *= -1;
00223 }
00224 else {
00225 wd *= -1;
00226 if (del.x*del.y < 0)
00227 ht *= -1;
00228 }
00229 f = (del.y*wd - del.x*ht)/dist2;
00230 ld.x = -f*del.y;
00231 ld.y = f*del.x;
00232 }
00233 else {
00234 ld.x = 0;
00235 ld.y = -ht;
00236 }
00237
00238 ED_label(e)->p.x = spf.x + ld.x;
00239 ED_label(e)->p.y = spf.y + ld.y;
00240 ED_label(e)->set = TRUE;
00241 updateBB(e->tail->graph, ED_label(e));
00242 }
00243 makePortLabels(e);
00244 }
00245
00246 typedef struct {
00247 node_t *n1;
00248 point p1;
00249 node_t *n2;
00250 point p2;
00251 } edgeinfo;
00252 typedef struct {
00253 Dtlink_t link;
00254 edgeinfo id;
00255 edge_t *e;
00256 } edgeitem;
00257
00258 static void *newitem(Dt_t * d, edgeitem * obj, Dtdisc_t * disc)
00259 {
00260 edgeitem *newp;
00261
00262 NOTUSED(disc);
00263 newp = NEW(edgeitem);
00264 newp->id = obj->id;
00265 newp->e = obj->e;
00266 ED_count(newp->e) = 1;
00267
00268 return newp;
00269 }
00270
00271 static void freeitem(Dt_t * d, edgeitem * obj, Dtdisc_t * disc)
00272 {
00273 free(obj);
00274 }
00275
00276 static int
00277 cmpitems(Dt_t * d, edgeinfo * key1, edgeinfo * key2, Dtdisc_t * disc)
00278 {
00279 int x;
00280
00281 if (key1->n1 > key2->n1)
00282 return 1;
00283 if (key1->n1 < key2->n1)
00284 return -1;
00285 if (key1->n2 > key2->n2)
00286 return 1;
00287 if (key1->n2 < key2->n2)
00288 return -1;
00289
00290 if ((x = key1->p1.x - key2->p1.x))
00291 return x;
00292 if ((x = key1->p1.y - key2->p1.y))
00293 return x;
00294 if ((x = key1->p2.x - key2->p2.x))
00295 return x;
00296 return (key1->p2.y - key2->p2.y);
00297 }
00298
00299 Dtdisc_t edgeItemDisc = {
00300 offsetof(edgeitem, id),
00301 sizeof(edgeinfo),
00302 offsetof(edgeitem, link),
00303 (Dtmake_f) newitem,
00304 (Dtfree_f) freeitem,
00305 (Dtcompar_f) cmpitems,
00306 0,
00307 0,
00308 0
00309 };
00310
00311
00312
00313
00314
00315
00316
00317
00318 static edge_t *equivEdge(Dt_t * map, edge_t * e)
00319 {
00320 edgeinfo test;
00321 edgeitem dummy;
00322 edgeitem *ip;
00323
00324 if (e->tail < e->head) {
00325 test.n1 = e->tail;
00326 test.p1 = ED_tail_port(e).p;
00327 test.n2 = e->head;
00328 test.p2 = ED_head_port(e).p;
00329 } else if (e->tail > e->head) {
00330 test.n2 = e->tail;
00331 test.p2 = ED_tail_port(e).p;
00332 test.n1 = e->head;
00333 test.p1 = ED_head_port(e).p;
00334 } else {
00335 point hp = ED_head_port(e).p;
00336 point tp = ED_tail_port(e).p;
00337 if (tp.x < hp.x) {
00338 test.p1 = tp;
00339 test.p2 = hp;
00340 } else if (tp.x > hp.x) {
00341 test.p1 = hp;
00342 test.p2 = tp;
00343 } else if (tp.y < hp.y) {
00344 test.p1 = tp;
00345 test.p2 = hp;
00346 } else if (tp.y > hp.y) {
00347 test.p1 = hp;
00348 test.p2 = tp;
00349 } else {
00350 test.p1 = test.p2 = tp;
00351 }
00352 test.n2 = test.n1 = e->tail;
00353 }
00354 dummy.id = test;
00355 dummy.e = e;
00356 ip = dtinsert(map, &dummy);
00357 return ip->e;
00358 }
00359
00360
00361
00362
00363
00364
00365
00366
00367 void makeSelfArcs(path * P, edge_t * e, int stepx)
00368 {
00369 int cnt = ED_count(e);
00370
00371 if (cnt == 1) {
00372 edge_t *edges1[1];
00373 edges1[0] = e;
00374 makeSelfEdge(P, edges1, 0, 1, stepx, stepx, &sinfo);
00375 if (ED_label(e))
00376 updateBB(e->tail->graph, ED_label(e));
00377 makePortLabels(e);
00378 } else {
00379 int i;
00380 edge_t **edges = N_GNEW(cnt, edge_t *);
00381 for (i = 0; i < cnt; i++) {
00382 edges[i] = e;
00383 e = ED_to_virt(e);
00384 }
00385 makeSelfEdge(P, edges, 0, cnt, stepx, stepx, &sinfo);
00386 for (i = 0; i < cnt; i++) {
00387 e = edges[i];
00388 if (ED_label(e))
00389 updateBB(e->tail->graph, ED_label(e));
00390 makePortLabels(e);
00391 }
00392 free(edges);
00393 }
00394 }
00395
00396 static void makeStraightEdge(graph_t * g, edge_t * e)
00397 {
00398 point dumb[4];
00399 node_t *n = e->tail;
00400 node_t *head = e->head;
00401 int e_cnt = ED_count(e);
00402 pointf perp;
00403 point del;
00404 edge_t *e0;
00405 int i, j, xstep, dx;
00406 double l_perp;
00407 point dumber[4];
00408 point p, q;
00409
00410 p = dumb[1] = dumb[0] = add_points(ND_coord_i(n), ED_tail_port(e).p);
00411 q = dumb[2] = dumb[3] =
00412 add_points(ND_coord_i(head), ED_head_port(e).p);
00413
00414 if (e_cnt == 1) {
00415 clip_and_install(e, e->head, dumb, 4, &sinfo);
00416 addEdgeLabels(e, p, q);
00417 return;
00418 }
00419
00420 e0 = e;
00421 perp.x = dumb[0].y - dumb[3].y;
00422 perp.y = dumb[3].x - dumb[0].x;
00423 if ((perp.x == 0) && (perp.y == 0)) {
00424
00425 dumb[1] = dumb[0];
00426 dumb[2] = dumb[3];
00427 del.x = 0;
00428 del.y = 0;
00429 }
00430 else {
00431 l_perp = sqrt(perp.x * perp.x + perp.y * perp.y);
00432 xstep = GD_nodesep(g);
00433 dx = xstep * (e_cnt - 1) / 2;
00434 dumb[1].x = dumb[0].x + (dx * perp.x) / l_perp;
00435 dumb[1].y = dumb[0].y + (dx * perp.y) / l_perp;
00436 dumb[2].x = dumb[3].x + (dx * perp.x) / l_perp;
00437 dumb[2].y = dumb[3].y + (dx * perp.y) / l_perp;
00438 del.x = -xstep * perp.x / l_perp;
00439 del.y = -xstep * perp.y / l_perp;
00440 }
00441
00442 for (i = 0; i < e_cnt; i++) {
00443 if (e0->head == head) {
00444 p = dumb[0];
00445 q = dumb[3];
00446 for (j = 0; j < 4; j++) {
00447 dumber[j] = dumb[j];
00448 }
00449 } else {
00450 p = dumb[3];
00451 q = dumb[0];
00452 for (j = 0; j < 4; j++) {
00453 dumber[3 - j] = dumb[j];
00454 }
00455 }
00456 clip_and_install(e0, e0->head, dumber, 4, &sinfo);
00457 addEdgeLabels(e0, p, q);
00458 e0 = ED_to_virt(e0);
00459 dumb[1].x += del.x;
00460 dumb[1].y += del.y;
00461 dumb[2].x += del.x;
00462 dumb[2].y += del.y;
00463 }
00464 }
00465
00466
00467
00468
00469
00470
00471
00472
00473
00474
00475
00476 Ppoly_t *makeObstacle(node_t * n, double SEP)
00477 {
00478 Ppoly_t *obs;
00479 polygon_t *poly;
00480 double adj = 0.0;
00481 int j, sides;
00482 pointf polyp;
00483 box b;
00484 point pt;
00485 field_t *fld;
00486 epsf_t *desc;
00487
00488 switch (shapeOf(n)) {
00489 case SH_POLY:
00490 case SH_POINT:
00491 obs = NEW(Ppoly_t);
00492 poly = (polygon_t *) ND_shape_info(n);
00493 if (poly->sides >= 3) {
00494 sides = poly->sides;
00495 } else {
00496 sides = 8;
00497 adj = drand48() * .01;
00498 }
00499 obs->pn = sides;
00500 obs->ps = N_NEW(sides, Ppoint_t);
00501
00502 for (j = 0; j < sides; j++) {
00503 if (poly->sides >= 3) {
00504 polyp.x = poly->vertices[j].x * SEP;
00505 polyp.y = poly->vertices[j].y * SEP;
00506 } else {
00507 double c, s;
00508 c = cos(2.0 * M_PI * j / sides + adj);
00509 s = sin(2.0 * M_PI * j / sides + adj);
00510 polyp.x = SEP * c * (ND_lw_i(n) + ND_rw_i(n)) / 2.0;
00511 polyp.y = SEP * s * ND_ht_i(n) / 2.0;
00512 }
00513 obs->ps[sides - j - 1].x = polyp.x + ND_coord_i(n).x;
00514 obs->ps[sides - j - 1].y = polyp.y + ND_coord_i(n).y;
00515 }
00516 break;
00517 case SH_RECORD:
00518 fld = (field_t *) ND_shape_info(n);
00519 b = fld->b;
00520 obs = NEW(Ppoly_t);
00521 obs->pn = 4;
00522 obs->ps = N_NEW(4, Ppoint_t);
00523
00524 pt = ND_coord_i(n);
00525 obs->ps[0] = recPt(b.LL.x, b.LL.y, pt, SEP);
00526 obs->ps[1] = recPt(b.LL.x, b.UR.y, pt, SEP);
00527 obs->ps[2] = recPt(b.UR.x, b.UR.y, pt, SEP);
00528 obs->ps[3] = recPt(b.UR.x, b.LL.y, pt, SEP);
00529 break;
00530 case SH_EPSF:
00531 desc = (epsf_t *) (ND_shape_info(n));
00532 obs = NEW(Ppoly_t);
00533 obs->pn = 4;
00534 obs->ps = N_NEW(4, Ppoint_t);
00535
00536 pt = ND_coord_i(n);
00537 obs->ps[0] = recPt(-ND_lw_i(n), -ND_ht_i(n), pt, SEP);
00538 obs->ps[1] = recPt(-ND_lw_i(n), ND_ht_i(n), pt, SEP);
00539 obs->ps[2] = recPt(ND_rw_i(n), ND_ht_i(n), pt, SEP);
00540 obs->ps[3] = recPt(ND_rw_i(n), -ND_ht_i(n), pt, SEP);
00541 break;
00542 default:
00543 obs = NULL;
00544 break;
00545 }
00546 return obs;
00547 }
00548
00549
00550
00551
00552
00553
00554
00555
00556
00557
00558 Ppolyline_t
00559 getPath(edge_t * e, vconfig_t * vconfig, int chkPts, Ppoly_t ** obs,
00560 int npoly)
00561 {
00562 Ppolyline_t line;
00563 int pp, qp;
00564 Ppoint_t p, q;
00565 point p1, q1;
00566
00567 p1 = add_points(ND_coord_i(e->tail), ED_tail_port(e).p);
00568 q1 = add_points(ND_coord_i(e->head), ED_head_port(e).p);
00569 P2PF(p1, p);
00570 P2PF(q1, q);
00571
00572
00573 pp = qp = POLYID_NONE;
00574 if (chkPts) {
00575 pp = ND_lim(e->tail);
00576 qp = ND_lim(e->head);
00577
00578
00579
00580
00581
00582
00583
00584
00585 }
00586 Pobspath(vconfig, p, pp, q, qp, &line);
00587 return line;
00588 }
00589
00590
00591
00592 static void
00593 makePolyline(edge_t * e)
00594 {
00595 int i;
00596 Ppolyline_t spl, line = ED_path(e);
00597 point* ispline;
00598 point p1, q1;
00599 Ppoint_t p0, q0;
00600
00601 p0 = line.ps[0];
00602 q0 = line.ps[line.pn - 1];
00603 make_polyline (line, &spl);
00604 ispline = N_GNEW(spl.pn, point);
00605 for (i=0; i < spl.pn; i++) {
00606 PF2P (spl.ps[i], ispline[i]);
00607 }
00608
00609 if (Verbose > 1)
00610 fprintf(stderr, "polyline %s %s\n", e->tail->name, e->head->name);
00611 clip_and_install(e, e->head, ispline, spl.pn, &sinfo);
00612 free(ispline);
00613 PF2P(p0, p1);
00614 PF2P(q0, q1);
00615 addEdgeLabels(e, p1, q1);
00616 }
00617
00618
00619
00620
00621
00622
00623
00624
00625
00626
00627
00628 void makeSpline(edge_t * e, Ppoly_t ** obs, int npoly, boolean chkPts)
00629 {
00630 Ppolyline_t line, spline;
00631 Pvector_t slopes[2];
00632 int i, n_barriers;
00633 int pp, qp;
00634 Ppoint_t p, q;
00635 point *ispline;
00636 Pedge_t *barriers;
00637 point p1, q1;
00638
00639 line = ED_path(e);
00640 p = line.ps[0];
00641 q = line.ps[line.pn - 1];
00642
00643 pp = qp = POLYID_NONE;
00644 if (chkPts)
00645 for (i = 0; i < npoly; i++) {
00646 if ((pp == POLYID_NONE) && in_poly(*obs[i], p))
00647 pp = i;
00648 if ((qp == POLYID_NONE) && in_poly(*obs[i], q))
00649 qp = i;
00650 }
00651
00652 make_barriers(obs, npoly, pp, qp, &barriers, &n_barriers);
00653 slopes[0].x = slopes[0].y = 0.0;
00654 slopes[1].x = slopes[1].y = 0.0;
00655 Proutespline(barriers, n_barriers, line, slopes, &spline);
00656
00657
00658 ispline = N_GNEW(spline.pn, point);
00659 for (i = 0; i < spline.pn; i++) {
00660 ispline[i].x = ROUND(spline.ps[i].x);
00661 ispline[i].y = ROUND(spline.ps[i].y);
00662 }
00663 if (Verbose > 1)
00664 fprintf(stderr, "spline %s %s\n", e->tail->name, e->head->name);
00665 clip_and_install(e, e->head, ispline, spline.pn, &sinfo);
00666 free(ispline);
00667 free(barriers);
00668 PF2P(p, p1);
00669 PF2P(q, q1);
00670 addEdgeLabels(e, p1, q1);
00671 }
00672
00673
00674
00675
00676
00677
00678
00679
00680
00681
00682 static int _spline_edges(graph_t * g, double SEP, int edgetype)
00683 {
00684 node_t *n;
00685 edge_t *e;
00686 Ppoly_t **obs = 0;
00687 Ppoly_t *obp;
00688 int i = 0, npoly;
00689 vconfig_t *vconfig = 0;
00690 path *P = NULL;
00691 int useEdges = (Nop > 1);
00692 #ifdef ORTHO
00693 extern void orthoEdges (Agraph_t* g, int useLbls, splineInfo* sinfo);
00694 #endif
00695
00696
00697 if (edgetype != ET_LINE) {
00698 obs = N_NEW(agnnodes(g), Ppoly_t *);
00699 for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
00700 obp = makeObstacle(n, SEP);
00701 if (obp) {
00702 ND_lim(n) = i;
00703 obs[i++] = obp;
00704 }
00705 else
00706 ND_lim(n) = POLYID_NONE;
00707 }
00708 } else {
00709 obs = 0;
00710 }
00711 npoly = i;
00712 if (obs) {
00713 if (Plegal_arrangement(obs, npoly)) {
00714 if (edgetype != ET_ORTHO) vconfig = Pobsopen(obs, npoly);
00715 }
00716 else if (Verbose)
00717 fprintf(stderr,
00718 "nodes touch - falling back to straight line edges\n");
00719 }
00720
00721
00722 if (Verbose)
00723 fprintf(stderr, "Creating edges using %s\n",
00724 (edgetype == ET_ORTHO) ? "orthogonal lines" :
00725 (vconfig ? (edgetype == ET_SPLINE ? "splines" : "polylines") :
00726 "line segments"));
00727 if (vconfig) {
00728
00729 for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
00730 for (e = agfstout(g, n); e; e = agnxtout(g, e)) {
00731 ED_path(e) = getPath(e, vconfig, TRUE, obs, npoly);
00732 }
00733 }
00734 }
00735 #ifdef ORTHO
00736 else if (edgetype == ET_ORTHO) {
00737 orthoEdges (g, 0, &sinfo);
00738 useEdges = 1;
00739 }
00740 #endif
00741
00742
00743 for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
00744 for (e = agfstout(g, n); e; e = agnxtout(g, e)) {
00745 node_t *head = e->head;
00746 if (useEdges && ED_spl(e)) {
00747 addEdgeLabels(e,
00748 add_points(ND_coord_i(n), ED_tail_port(e).p),
00749 add_points(ND_coord_i(head),
00750 ED_head_port(e).p));
00751 } else if (n == head) {
00752 if (ED_count(e) == 0) continue;
00753 if (!P) {
00754 P = NEW(path);
00755 P->boxes = N_NEW(agnnodes(g) + 20 * 2 * 9, box);
00756 }
00757 makeSelfArcs(P, e, GD_nodesep(g));
00758 } else if (vconfig) {
00759 if (edgetype == ET_SPLINE)
00760 makeSpline(e, obs, npoly, TRUE);
00761 else
00762 makePolyline(e);
00763 } else if (ED_count(e)) {
00764 makeStraightEdge(g, e);
00765 }
00766 }
00767 }
00768
00769 if (vconfig)
00770 Pobsclose (vconfig);
00771 if (P) {
00772 free(P->boxes);
00773 free(P);
00774 }
00775 if (obs) {
00776 for (i=0; i < npoly; i++)
00777 free (obs[i]);
00778 free (obs);
00779 }
00780 return 0;
00781 }
00782
00783
00784
00785
00786
00787
00788
00789
00790
00791
00792
00793
00794
00795
00796 int
00797 splineEdges(graph_t * g, int (*edgefn) (graph_t *, double, int),
00798 int edgetype)
00799 {
00800 node_t *n;
00801 edge_t *e;
00802 double SEP;
00803 Dt_t *map;
00804 char* marg;
00805
00806
00807
00808
00809
00810
00811 if ((marg = agget(g, "esep")))
00812 SEP = 1.0 + atof(marg);
00813 else
00814
00815 SEP = 1.0 + SEPFACT*(expFactor(g) - 1.0);
00816
00817
00818 map = dtopen(&edgeItemDisc, Dtoset);
00819 for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
00820 for (e = agfstout(g, n); e; e = agnxtout(g, e)) {
00821 edge_t *leader = equivEdge(map, e);
00822 if (leader != e) {
00823 ED_count(leader)++;
00824 ED_to_virt(e) = ED_to_virt(leader);
00825 ED_to_virt(leader) = e;
00826 }
00827 }
00828 }
00829 dtclose(map);
00830
00831 if (edgefn(g, SEP, edgetype))
00832 return 1;
00833
00834 State = GVSPLINES;
00835 return 0;
00836 }
00837
00838
00839
00840
00841
00842 int spline_edges1(graph_t * g, int edgetype)
00843 {
00844 return splineEdges(g, _spline_edges, edgetype);
00845 }
00846
00847
00848
00849
00850
00851
00852
00853
00854
00855
00856
00857
00858
00859
00860
00861 void spline_edges0(graph_t * g)
00862 {
00863 int et = EDGE_TYPE (g->root);
00864 neato_set_aspect(g);
00865 if (et == ET_NONE) return;
00866 #ifndef ORTHO
00867 if (et == ET_ORTHO) {
00868 agerr (AGWARN, "Orthogonal edges not yet supported\n");
00869 et = ET_PLINE;
00870 GD_flags(g->root) &= ~ET_ORTHO;
00871 GD_flags(g->root) |= ET_PLINE;
00872 }
00873 #endif
00874 spline_edges1(g, et);
00875 }
00876
00877
00878
00879
00880
00881
00882
00883 void spline_edges(graph_t * g)
00884 {
00885 node_t *n;
00886 pointf offset;
00887
00888 compute_bb(g);
00889 offset = cvt2ptf(GD_bb(g).LL);
00890 for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
00891 ND_pos(n)[0] -= offset.x;
00892 ND_pos(n)[1] -= offset.y;
00893 }
00894 GD_bb(g).UR.x -= GD_bb(g).LL.x;
00895 GD_bb(g).UR.y -= GD_bb(g).LL.y;
00896 GD_bb(g).LL.x = 0;
00897 GD_bb(g).LL.y = 0;
00898 spline_edges0(g);
00899 }
00900
00901
00902
00903
00904
00905 static void scaleEdge(edge_t * e, double xf, double yf)
00906 {
00907 int i, j;
00908 point *pt;
00909 bezier *bez;
00910 point delh, delt;
00911
00912 delh.x = POINTS(ND_pos(e->head)[0] * (xf - 1.0));
00913 delh.y = POINTS(ND_pos(e->head)[1] * (yf - 1.0));
00914 delt.x = POINTS(ND_pos(e->tail)[0] * (xf - 1.0));
00915 delt.y = POINTS(ND_pos(e->tail)[1] * (yf - 1.0));
00916
00917 bez = ED_spl(e)->list;
00918 for (i = 0; i < ED_spl(e)->size; i++) {
00919 pt = bez->list;
00920 for (j = 0; j < bez->size; j++) {
00921 if ((i == 0) && (j == 0)) {
00922 pt->x += delt.x;
00923 pt->y += delt.y;
00924 }
00925 else if ((i == ED_spl(e)->size-1) && (j == bez->size-1)) {
00926 pt->x += delh.x;
00927 pt->y += delh.y;
00928 }
00929 else {
00930 pt->x *= xf;
00931 pt->y *= yf;
00932 }
00933 pt++;
00934 }
00935 if (bez->sflag) {
00936 bez->sp.x += delt.x;
00937 bez->sp.y += delt.y;
00938 }
00939 if (bez->eflag) {
00940 bez->ep.x += delh.x;
00941 bez->ep.y += delh.y;
00942 }
00943 bez++;
00944 }
00945
00946 if (ED_label(e) && ED_label(e)->set) {
00947 ED_label(e)->p.x *= xf;
00948 ED_label(e)->p.y *= yf;
00949 }
00950 if (ED_head_label(e) && ED_head_label(e)->set) {
00951 ED_head_label(e)->p.x += delh.x;
00952 ED_head_label(e)->p.y += delh.y;
00953 }
00954 if (ED_tail_label(e) && ED_tail_label(e)->set) {
00955 ED_tail_label(e)->p.x += delt.x;
00956 ED_tail_label(e)->p.y += delt.y;
00957 }
00958 }
00959
00960
00961
00962
00963 static void scaleBB(graph_t * g, double xf, double yf)
00964 {
00965 int i;
00966
00967 GD_bb(g).UR.x *= xf;
00968 GD_bb(g).UR.y *= yf;
00969 GD_bb(g).LL.x *= xf;
00970 GD_bb(g).LL.y *= yf;
00971
00972 if (GD_label(g) && GD_label(g)->set) {
00973 GD_label(g)->p.x *= xf;
00974 GD_label(g)->p.y *= yf;
00975 }
00976
00977 for (i = 1; i <= GD_n_cluster(g); i++)
00978 scaleBB(GD_clust(g)[i], xf, yf);
00979 }
00980
00981
00982
00983
00984
00985 static void _neato_set_aspect(graph_t * g)
00986 {
00987
00988 double xf, yf, actual, desired;
00989 node_t *n;
00990
00991
00992 if (GD_drawing(g)->ratio_kind) {
00993
00994 assert(GD_bb(g).LL.x == 0);
00995 assert(GD_bb(g).LL.y == 0);
00996 if (GD_flip(g)) {
00997 int t = GD_bb(g).UR.x;
00998 GD_bb(g).UR.x = GD_bb(g).UR.y;
00999 GD_bb(g).UR.y = t;
01000 }
01001 if (GD_drawing(g)->ratio_kind == R_FILL) {
01002
01003 if (GD_drawing(g)->size.x <= 0)
01004 return;
01005 xf = (double) GD_drawing(g)->size.x / (double) GD_bb(g).UR.x;
01006 yf = (double) GD_drawing(g)->size.y / (double) GD_bb(g).UR.y;
01007
01008 if ((xf < 1.0) || (yf < 1.0)) {
01009 if (xf < yf) {
01010 yf = yf / xf;
01011 xf = 1.0;
01012 } else {
01013 xf = xf / yf;
01014 yf = 1.0;
01015 }
01016 }
01017 } else if (GD_drawing(g)->ratio_kind == R_EXPAND) {
01018 if (GD_drawing(g)->size.x <= 0)
01019 return;
01020 xf = (double) GD_drawing(g)->size.x / (double) GD_bb(g).UR.x;
01021 yf = (double) GD_drawing(g)->size.y / (double) GD_bb(g).UR.y;
01022 if ((xf > 1.0) && (yf > 1.0)) {
01023 double scale = MIN(xf, yf);
01024 xf = yf = scale;
01025 } else
01026 return;
01027 } else if (GD_drawing(g)->ratio_kind == R_VALUE) {
01028 desired = GD_drawing(g)->ratio;
01029 actual = ((double) GD_bb(g).UR.y) / ((double) GD_bb(g).UR.x);
01030 if (actual < desired) {
01031 yf = desired / actual;
01032 xf = 1.0;
01033 } else {
01034 xf = actual / desired;
01035 yf = 1.0;
01036 }
01037 } else
01038 return;
01039 if (GD_flip(g)) {
01040 double t = xf;
01041 xf = yf;
01042 yf = t;
01043 }
01044
01045 if (Nop > 1) {
01046 edge_t *e;
01047 for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
01048 for (e = agfstout(g, n); e; e = agnxtout(g, e))
01049 if (ED_spl(e))
01050 scaleEdge(e, xf, yf);
01051 }
01052 }
01053
01054
01055
01056 for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
01057 ND_pos(n)[0] = ND_pos(n)[0] * xf;
01058 ND_pos(n)[1] = ND_pos(n)[1] * yf;
01059 }
01060 scaleBB(g, xf, yf);
01061 }
01062 }
01063
01064
01065
01066
01067
01068
01069 void neato_set_aspect(graph_t * g)
01070 {
01071 node_t *n;
01072
01073 _neato_set_aspect(g);
01074 for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
01075 ND_coord_i(n).x = POINTS(ND_pos(n)[0]);
01076 ND_coord_i(n).y = POINTS(ND_pos(n)[1]);
01077 }
01078 }
01079