00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include "dot.h"
00023
00024 #define NSUB 9
00025 #define CHUNK 128
00026
00027 #define MINW 16
00028 #define HALFMINW 8
00029
00030 #define FWDEDGE 16
00031 #define BWDEDGE 32
00032
00033 #define MAINGRAPH 64
00034 #define AUXGRAPH 128
00035 #define GRAPHTYPEMASK 192
00036
00037 #define MAKEFWDEDGE(new, old) { \
00038 edge_t *newp; \
00039 newp = new; \
00040 *newp = *old; \
00041 newp->tail = old->head; \
00042 newp->head = old->tail; \
00043 ED_tail_port(newp) = ED_head_port(old); \
00044 ED_head_port(newp) = ED_tail_port(old); \
00045 ED_edge_type(newp) = VIRTUAL; \
00046 ED_to_orig(newp) = old; \
00047 }
00048
00049 #define P2PF(p, pf) (pf.x = p.x, pf.y = p.y)
00050
00051 #ifdef OBSOLETE
00052 static int flatsidemap[16][6] = {
00053 {BOTTOM, BOTTOM, BOTTOM, CCW, CCW, FALSE},
00054 {TOP, TOP, TOP, CW, CW, FALSE},
00055 {RIGHT, LEFT, BOTTOM, CW, CW, TRUE},
00056 {BOTTOM, TOP, RIGHT, CCW, CW, TRUE},
00057 {TOP, BOTTOM, RIGHT, CW, CCW, TRUE},
00058 {RIGHT, TOP, RIGHT, CCW, CW, TRUE},
00059 {RIGHT, BOTTOM, RIGHT, CW, CCW, TRUE},
00060 {TOP, LEFT, TOP, CW, CCW, TRUE},
00061 {BOTTOM, LEFT, BOTTOM, CCW, CW, TRUE},
00062 {RIGHT, RIGHT, BOTTOM, CW, CCW, TRUE},
00063 {LEFT, LEFT, BOTTOM, CCW, CW, TRUE},
00064 {LEFT, BOTTOM, BOTTOM, CCW, CCW, FALSE},
00065 {TOP, RIGHT, TOP, CW, CW, FALSE},
00066 {LEFT, TOP, TOP, CW, CW, FALSE},
00067 {BOTTOM, RIGHT, BOTTOM, CCW, CCW, FALSE},
00068 {LEFT, RIGHT, BOTTOM, CCW, CCW, FALSE},
00069 };
00070 #endif
00071
00072 #define AVG(a, b) ((a + b) / 2)
00073
00074 static box boxes[1000];
00075 typedef struct {
00076 int LeftBound, RightBound, Splinesep, Multisep;
00077 box* Rank_box;
00078 } spline_info_t;
00079
00080 static void adjustregularpath(path *, int, int);
00081 static Agedge_t *bot_bound(Agedge_t *, int);
00082 static boolean pathscross(Agnode_t *, Agnode_t *, Agedge_t *, Agedge_t *);
00083 #ifdef OBSOLETE
00084 static void chooseflatsides(pathend_t *, pathend_t *, int *, int *, int *,
00085 int *, int *, int *);
00086 static void completeflatpath(path *, pathend_t *, pathend_t *,
00087 box *, box *, int, int);
00088 static box makeflatend(box, int, int, box);
00089 static box makeflatcomponent(box, box, int, int, int, int, int);
00090 #endif
00091 static Agraph_t *cl_bound(Agnode_t *, Agnode_t *);
00092 static int cl_vninside(Agraph_t *, Agnode_t *);
00093 static void completeregularpath(path *, Agedge_t *, Agedge_t *,
00094 pathend_t *, pathend_t *, box *, int, int);
00095 static int edgecmp(Agedge_t **, Agedge_t **);
00096 static void make_flat_edge(spline_info_t*, path *, Agedge_t **, int, int, int);
00097 static void make_regular_edge(spline_info_t*, path *, Agedge_t **, int, int, int);
00098 static box makeregularend(box, int, int);
00099 static box maximal_bbox(spline_info_t*, Agnode_t *, Agedge_t *, Agedge_t *);
00100 static Agnode_t *neighbor(Agnode_t *, Agedge_t *, Agedge_t *, int);
00101 static void place_vnlabel(Agnode_t *);
00102 static box rank_box(spline_info_t* sp, Agraph_t *, int);
00103 static void recover_slack(Agedge_t *, path *);
00104 static void resize_vn(Agnode_t *, int, int, int);
00105 static void setflags(Agedge_t *, int, int, int);
00106 static int straight_len(Agnode_t *);
00107 static Agedge_t *straight_path(Agedge_t *, int, point *, int *);
00108 static Agedge_t *top_bound(Agedge_t *, int);
00109
00110 #define GROWEDGES (edges = ALLOC (n_edges + CHUNK, edges, edge_t*))
00111
00112 static edge_t*
00113 getmainedge(edge_t * e)
00114 {
00115 edge_t *le = e;
00116 while (ED_to_virt(le))
00117 le = ED_to_virt(le);
00118 while (ED_to_orig(le))
00119 le = ED_to_orig(le);
00120 return le;
00121 }
00122
00123 static boolean spline_merge(node_t * n)
00124 {
00125 return ((ND_node_type(n) == VIRTUAL)
00126 && ((ND_in(n).size > 1) || (ND_out(n).size > 1)));
00127 }
00128
00129 static boolean swap_ends_p(edge_t * e)
00130 {
00131 while (ED_to_orig(e))
00132 e = ED_to_orig(e);
00133 if (ND_rank(e->head) > ND_rank(e->tail))
00134 return FALSE;
00135 if (ND_rank(e->head) < ND_rank(e->tail))
00136 return TRUE;
00137 if (ND_order(e->head) >= ND_order(e->tail))
00138 return FALSE;
00139 return TRUE;
00140 }
00141
00142 static splineInfo sinfo = { swap_ends_p, spline_merge };
00143
00144 int portcmp(port p0, port p1)
00145 {
00146 int rv;
00147 if (p1.defined == FALSE)
00148 return (p0.defined ? 1 : 0);
00149 if (p0.defined == FALSE)
00150 return -1;
00151 rv = p0.p.x - p1.p.x;
00152 if (rv == 0)
00153 rv = p0.p.y - p1.p.y;
00154 return rv;
00155 }
00156
00157
00158
00159 static void swap_bezier(bezier * old, bezier * new)
00160 {
00161 point *list;
00162 point *lp;
00163 point *olp;
00164 int i, sz;
00165
00166 sz = old->size;
00167 list = N_GNEW(sz, point);
00168 lp = list;
00169 olp = old->list + (sz - 1);
00170 for (i = 0; i < sz; i++) {
00171 *lp++ = *olp--;
00172 }
00173
00174 new->list = list;
00175 new->size = sz;
00176 new->sflag = old->eflag;
00177 new->eflag = old->sflag;
00178 new->sp = old->ep;
00179 new->ep = old->sp;
00180 }
00181
00182
00183
00184 static void swap_spline(splines * s)
00185 {
00186 bezier *list;
00187 bezier *lp;
00188 bezier *olp;
00189 int i, sz;
00190
00191 sz = s->size;
00192 list = N_GNEW(sz, bezier);
00193 lp = list;
00194 olp = s->list + (sz - 1);
00195 for (i = 0; i < sz; i++) {
00196 swap_bezier(olp--, lp++);
00197 }
00198
00199
00200 for (i = 0; i < sz; i++)
00201 free(s->list[i].list);
00202 free(s->list);
00203
00204 s->list = list;
00205 }
00206
00207
00208
00209
00210
00211
00212
00213 static void edge_normalize(graph_t * g)
00214 {
00215 edge_t *e;
00216 node_t *n;
00217
00218 for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
00219 for (e = agfstout(g, n); e; e = agnxtout(g, e)) {
00220 if (sinfo.swapEnds(e) && ED_spl(e))
00221 swap_spline(ED_spl(e));
00222 }
00223 }
00224 }
00225
00226
00227
00228
00229
00230
00231
00232
00233 static void _dot_splines(graph_t * g, int normalize)
00234 {
00235 int i, j, k, n_nodes, n_edges, ind, cnt;
00236 node_t *n;
00237 edge_t fwdedgea, fwdedgeb;
00238 edge_t *e, *e0, *e1, *ea, *eb, *le0, *le1, **edges;
00239 path *P;
00240 spline_info_t sd;
00241 int et = EDGE_TYPE(g->root);
00242
00243 if (et == ET_NONE) return;
00244
00245 mark_lowclusters(g);
00246 routesplinesinit();
00247 P = NEW(path);
00248
00249 sd.Splinesep = GD_nodesep(g) / 4;
00250 sd.Multisep = GD_nodesep(g);
00251 edges = N_NEW(CHUNK, edge_t *);
00252
00253
00254 sd.LeftBound = sd.RightBound = 0;
00255 n_edges = n_nodes = 0;
00256 for (i = GD_minrank(g); i <= GD_maxrank(g); i++) {
00257 n_nodes += GD_rank(g)[i].n;
00258 if ((n = GD_rank(g)[i].v[0]))
00259 sd.LeftBound = MIN(sd.LeftBound, (ND_coord_i(n).x - ND_lw_i(n)));
00260 if (GD_rank(g)[i].n && (n = GD_rank(g)[i].v[GD_rank(g)[i].n - 1]))
00261 sd.RightBound = MAX(sd.RightBound, (ND_coord_i(n).x + ND_rw_i(n)));
00262 sd.LeftBound -= MINW;
00263 sd.RightBound += MINW;
00264
00265 for (j = 0; j < GD_rank(g)[i].n; j++) {
00266 n = GD_rank(g)[i].v[j];
00267
00268
00269
00270 if (ND_alg(n)) {
00271 edge_t* fe = (edge_t*)ND_alg(n);
00272 assert (ED_label(fe));
00273 ED_label(fe)->p = ND_coord_i(n);
00274 }
00275 if ((ND_node_type(n) != NORMAL) &&
00276 (sinfo.splineMerge(n) == FALSE))
00277 continue;
00278 for (k = 0; (e = ND_out(n).list[k]); k++) {
00279 if ((ED_edge_type(e) == FLATORDER)
00280 || (ED_edge_type(e) == IGNORED))
00281 continue;
00282 setflags(e, REGULAREDGE, FWDEDGE, MAINGRAPH);
00283 edges[n_edges++] = e;
00284 if (n_edges % CHUNK == 0)
00285 GROWEDGES;
00286 }
00287 if (ND_flat_out(n).list)
00288 for (k = 0; (e = ND_flat_out(n).list[k]); k++) {
00289 setflags(e, FLATEDGE, 0, AUXGRAPH);
00290 edges[n_edges++] = e;
00291 if (n_edges % CHUNK == 0)
00292 GROWEDGES;
00293 }
00294 if (ND_other(n).list) {
00295
00296
00297
00298
00299
00300 if (ND_node_type(n) == NORMAL) {
00301 int tmp = ND_rw_i(n);
00302 ND_rw_i(n) = ND_mval(n);
00303 ND_mval(n) = tmp;
00304 }
00305 for (k = 0; (e = ND_other(n).list[k]); k++) {
00306 setflags(e, 0, 0, AUXGRAPH);
00307 edges[n_edges++] = e;
00308 if (n_edges % CHUNK == 0)
00309 GROWEDGES;
00310 }
00311 }
00312 }
00313 }
00314
00315
00316
00317
00318
00319
00320
00321 qsort((char *) &edges[0], n_edges, sizeof(edges[0]),
00322 (qsort_cmpf) edgecmp);
00323
00324
00325 P->boxes = N_NEW(n_nodes + 20 * 2 * NSUB, box);
00326 sd.Rank_box = N_NEW(i, box);
00327
00328 if (et == ET_LINE) {
00329
00330 for (n = GD_nlist(g); n; n = ND_next(n)) {
00331 if ((ND_node_type(n) == VIRTUAL) && (ND_label(n))) {
00332 place_vnlabel(n);
00333 }
00334 }
00335 }
00336
00337 for (i = 0; i < n_edges;) {
00338 ind = i;
00339 le0 = getmainedge((e0 = edges[i++]));
00340 ea = (ED_tail_port(e0).defined
00341 || ED_head_port(e0).defined) ? e0 : le0;
00342 if (ED_tree_index(ea) & BWDEDGE) {
00343 MAKEFWDEDGE(&fwdedgea, ea);
00344 ea = &fwdedgea;
00345 }
00346 for (cnt = 1; i < n_edges; cnt++, i++) {
00347 if (le0 != (le1 = getmainedge((e1 = edges[i]))))
00348 break;
00349 if (ED_adjacent(e0)) continue;
00350 eb = (ED_tail_port(e1).defined
00351 || ED_head_port(e1).defined) ? e1 : le1;
00352 if (ED_tree_index(eb) & BWDEDGE) {
00353 MAKEFWDEDGE(&fwdedgeb, eb);
00354 eb = &fwdedgeb;
00355 }
00356 if (portcmp(ED_tail_port(ea), ED_tail_port(eb)))
00357 break;
00358 if (portcmp(ED_head_port(ea), ED_head_port(eb)))
00359 break;
00360 if ((ED_tree_index(e0) & EDGETYPEMASK) == FLATEDGE
00361 && ED_label(e0) != ED_label(e1))
00362 break;
00363 if (ED_tree_index(edges[i]) & MAINGRAPH)
00364 break;
00365 }
00366
00367 if (e0->tail == e0->head) {
00368 int b, sizey, r;
00369 n = e0->tail;
00370 r = ND_rank(n);
00371 if (r == GD_maxrank(g)) {
00372 if (r > 0)
00373 sizey = ND_coord_i(GD_rank(g)[r-1].v[0]).y - ND_coord_i(n).y;
00374 else
00375 sizey = ND_ht_i(n);
00376 }
00377 else if (r == GD_minrank(g)) {
00378 sizey = ND_coord_i(n).y - ND_coord_i(GD_rank(g)[r+1].v[0]).y;
00379 }
00380 else {
00381 int upy = ND_coord_i(GD_rank(g)[r-1].v[0]).y - ND_coord_i(n).y;
00382 int dwny = ND_coord_i(n).y - ND_coord_i(GD_rank(g)[r+1].v[0]).y;
00383 sizey = MIN(upy, dwny);
00384 }
00385 makeSelfEdge(P, edges, ind, cnt, sd.Multisep, sizey/2, &sinfo);
00386 for (b = 0; b < cnt; b++) {
00387 e = edges[ind+b];
00388 if (ED_label(e))
00389 updateBB(g, ED_label(e));
00390 }
00391 }
00392 else if (ND_rank(e0->tail) == ND_rank(e0->head)) {
00393 make_flat_edge(&sd, P, edges, ind, cnt, et);
00394 }
00395 else
00396 make_regular_edge(&sd, P, edges, ind, cnt, et);
00397 }
00398
00399
00400 for (n = GD_nlist(g); n; n = ND_next(n)) {
00401 if ((ND_node_type(n) == VIRTUAL) && (ND_label(n))) {
00402 place_vnlabel(n);
00403 updateBB(g, ND_label(n));
00404 }
00405 }
00406
00407
00408
00409 if (normalize)
00410 edge_normalize(g);
00411
00412
00413
00414 if (E_headlabel || E_taillabel) {
00415 for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
00416 if (E_headlabel) {
00417 for (e = agfstin(g, n); e; e = agnxtin(g, e))
00418 if (ED_head_label(e)) {
00419 place_portlabel(e, TRUE);
00420 updateBB(g, ED_head_label(e));
00421 }
00422 }
00423 if (E_taillabel) {
00424 for (e = agfstout(g, n); e; e = agnxtout(g, e)) {
00425 if (ED_tail_label(e)) {
00426 place_portlabel(e, FALSE);
00427 updateBB(g, ED_tail_label(e));
00428 }
00429 }
00430 }
00431 }
00432 }
00433
00434
00435 free(edges);
00436 free(P->boxes);
00437 free(P);
00438 free(sd.Rank_box);
00439 routesplinesterm();
00440 State = GVSPLINES;
00441 }
00442
00443
00444
00445
00446 void dot_splines(graph_t * g)
00447 {
00448 _dot_splines (g, 1);
00449 }
00450
00451
00452
00453
00454
00455 static void
00456 place_vnlabel(node_t * n)
00457 {
00458 pointf dimen;
00459 double width;
00460 edge_t *e;
00461 if (ND_in(n).size == 0)
00462 return;
00463 for (e = ND_out(n).list[0]; ED_edge_type(e) != NORMAL;
00464 e = ED_to_orig(e));
00465 dimen = ED_label(e)->dimen;
00466 width = GD_flip(n->graph) ? dimen.y : dimen.x;
00467 ED_label(e)->p.x = ND_coord_i(n).x + width / 2.0;
00468 ED_label(e)->p.y = ND_coord_i(n).y;
00469 }
00470
00471 static void
00472 setflags(edge_t *e, int hint1, int hint2, int f3)
00473 {
00474 int f1, f2;
00475 if (hint1 != 0)
00476 f1 = hint1;
00477 else {
00478 if (e->tail == e->head)
00479 if (ED_tail_port(e).defined || ED_head_port(e).defined)
00480 f1 = SELFWPEDGE;
00481 else
00482 f1 = SELFNPEDGE;
00483 else if (ND_rank(e->tail) == ND_rank(e->head))
00484 f1 = FLATEDGE;
00485 else
00486 f1 = REGULAREDGE;
00487 }
00488 if (hint2 != 0)
00489 f2 = hint2;
00490 else {
00491 if (f1 == REGULAREDGE)
00492 f2 = (ND_rank(e->tail) < ND_rank(e->head)) ? FWDEDGE : BWDEDGE;
00493 else if (f1 == FLATEDGE)
00494 f2 = (ND_order(e->tail) < ND_order(e->head)) ?
00495 FWDEDGE : BWDEDGE;
00496 else
00497 f2 = FWDEDGE;
00498 }
00499 ED_tree_index(e) = (f1 | f2 | f3);
00500 }
00501
00502
00503
00504
00505
00506
00507
00508
00509
00510
00511
00512
00513 static int edgecmp(edge_t** ptr0, edge_t** ptr1)
00514 {
00515 edge_t fwdedgea, fwdedgeb, *e0, *e1, *ea, *eb, *le0, *le1;
00516 int et0, et1, v0, v1, rv;
00517
00518 e0 = (edge_t *) * ptr0;
00519 e1 = (edge_t *) * ptr1;
00520 et0 = ED_tree_index(e0) & EDGETYPEMASK;
00521 et1 = ED_tree_index(e1) & EDGETYPEMASK;
00522 if (et0 != et1)
00523 return (et1 - et0);
00524 le0 = getmainedge(e0);
00525 le1 = getmainedge(e1);
00526 v0 = ND_rank(le0->tail) - ND_rank(le0->head), v0 = ABS(v0);
00527 v1 = ND_rank(le1->tail) - ND_rank(le1->head), v1 = ABS(v1);
00528 if (v0 != v1)
00529 return (v0 - v1);
00530 v0 = ND_coord_i(le0->tail).x - ND_coord_i(le0->head).x, v0 = ABS(v0);
00531 v1 = ND_coord_i(le1->tail).x - ND_coord_i(le1->head).x, v1 = ABS(v1);
00532 if (v0 != v1)
00533 return (v0 - v1);
00534
00535
00536 if (le0->id != le1->id)
00537 return (le0->id - le1->id);
00538 ea = (ED_tail_port(e0).defined || ED_head_port(e0).defined) ? e0 : le0;
00539 if (ED_tree_index(ea) & BWDEDGE) {
00540 MAKEFWDEDGE(&fwdedgea, ea);
00541 ea = &fwdedgea;
00542 }
00543 eb = (ED_tail_port(e1).defined || ED_head_port(e1).defined) ? e1 : le1;
00544 if (ED_tree_index(eb) & BWDEDGE) {
00545 MAKEFWDEDGE(&fwdedgeb, eb);
00546 eb = &fwdedgeb;
00547 }
00548 if ((rv = portcmp(ED_tail_port(ea), ED_tail_port(eb))))
00549 return rv;
00550 if ((rv = portcmp(ED_head_port(ea), ED_head_port(eb))))
00551 return rv;
00552 v0 = ED_tree_index(e0) & GRAPHTYPEMASK;
00553 v1 = ED_tree_index(e1) & GRAPHTYPEMASK;
00554 if (v0 != v1)
00555 return (v0 - v1);
00556 if (et0 == FLATEDGE && ED_label(e0) != ED_label(e1))
00557 return (int) (ED_label(e0) - ED_label(e1));
00558 return (e0->id - e1->id);
00559 }
00560
00561 #if 0
00562
00563
00564
00565
00566
00567 static int
00568 fledgecmp(edge_t** ptr0, edge_t** ptr1)
00569 {
00570 edge_t *e0, *e1;
00571 point tp0, tp1, hp0, hp1;
00572 int y0, y1;
00573
00574 e0 = *ptr0;
00575 e1 = *ptr1;
00576 tp0 = ED_tail_port(e0).p;
00577 hp0 = ED_head_port(e0).p;
00578 tp1 = ED_tail_port(e1).p;
00579 hp1 = ED_head_port(e1).p;
00580 y0 = (tp0.y + hp0.y)/2;
00581 y1 = (tp1.y + hp1.y)/2;
00582 if (y0 != y1) return (y0-y1);
00583 if ((tp0.y == hp0.y) && (tp1.y == hp1.y)) {
00584 if ((tp0.x <= tp1.x) && (hp0.x >= hp1.x)) {
00585 if (tp0.y <= 0) return -1;
00586 else return 1;
00587 }
00588 else if ((tp0.x >= tp1.x) && (hp0.x <= hp1.x)) {
00589 if (tp0.y <= 0) return 1;
00590 else return -1;
00591 }
00592 }
00593 return (e0->id - e1->id);
00594
00595 }
00596
00597 #define LABEL_SPACE 8
00598
00599
00600
00601
00602
00603
00604 static void
00605 setFlatAdjPos (edge_t** edges, int n_edges, int flip, box* boxes, edge_t* e0)
00606 {
00607 int r, i, x, boxw, availht;
00608 edge_t* e;
00609 double y, wd, ht, totalht = 0;
00610 textlabel_t* lbl;
00611 node_t *tn, *hn;
00612 graph_t* g;
00613
00614 assert(0);
00615 tn = e0->tail, hn = e0->head;
00616 g = tn->graph;
00617 x = (ND_coord_i(tn).x + ND_coord_i(hn).x)/2;
00618 y = ND_coord_i(tn).y;
00619 r = ND_rank(tn);
00620 availht = GD_rank(g)[r].ht2 + GD_rank(g)[r].ht1 + GD_ranksep(g);
00621 boxw = (ND_coord_i(hn).x - ND_coord_i(tn).x - ND_rw_i(tn) - ND_lw_i(hn))/3;
00622 for (i = 0; i < n_edges; i++) {
00623 if (!((lbl = ED_label(e)))) continue;
00624 if (flip) {
00625 ht = lbl->dimen.x;
00626 wd = lbl->dimen.y;
00627 }
00628 else {
00629 ht = lbl->dimen.y;
00630 wd = lbl->dimen.x;
00631 }
00632 totalht += ht;
00633 boxw = MAX(boxw, wd);
00634 }
00635 for (i = 0; i < n_edges; i++) {
00636 e = edges[i];
00637 lbl = ED_label(e);
00638 if (GD_flip(g)) ht = lbl->dimen.x;
00639 else ht = lbl->dimen.y;
00640 lbl->p.x = x;
00641 lbl->p.y = ROUND(y - ht/2);
00642 y -= ht + LABEL_SPACE;
00643 }
00644 }
00645 #endif
00646
00647
00648
00649 static struct {
00650 attrsym_t* E_constr;
00651 attrsym_t* E_samehead;
00652 attrsym_t* E_sametail;
00653 attrsym_t* E_weight;
00654 attrsym_t* E_minlen;
00655 attrsym_t* N_group;
00656 int State;
00657 } attr_state;
00658
00659
00660
00661
00662
00663
00664
00665
00666 static graph_t*
00667 cloneGraph (graph_t* g)
00668 {
00669 Agsym_t* sym;
00670 graph_t* auxg;
00671 Agsym_t **list;
00672
00673 auxg = agopen ("auxg", AG_IS_DIRECTED(g)?AGDIGRAPH:AGRAPH);
00674 agraphattr(auxg, "rank", "");
00675 GD_drawing(auxg) = NEW(layout_t);
00676 GD_drawing(auxg)->quantum = GD_drawing(g)->quantum;
00677 GD_drawing(auxg)->dpi = GD_drawing(g)->dpi;
00678
00679 GD_charset(auxg) = GD_charset (g);
00680 if (GD_flip(g))
00681 SET_RANKDIR(auxg, RANKDIR_TB);
00682 else
00683 SET_RANKDIR(auxg, RANKDIR_LR);
00684 GD_nodesep(auxg) = GD_nodesep(g);
00685 GD_ranksep(auxg) = GD_ranksep(g);
00686
00687 list = g->root->univ->nodeattr->list;
00688 while ((sym = *list++)) {
00689 agnodeattr (auxg, sym->name, sym->value);
00690 }
00691
00692 list = g->root->univ->edgeattr->list;
00693 while ((sym = *list++)) {
00694 agedgeattr (auxg, sym->name, sym->value);
00695 }
00696
00697 attr_state.E_constr = E_constr;
00698 attr_state.E_samehead = E_samehead;
00699 attr_state.E_sametail = E_sametail;
00700 attr_state.E_weight = E_weight;
00701 attr_state.E_minlen = E_minlen;
00702 attr_state.N_group = N_group;
00703 attr_state.State = State;
00704 E_constr = NULL;
00705 E_samehead = agfindattr(auxg->proto->e, "samehead");
00706 E_sametail = agfindattr(auxg->proto->e, "sametail");
00707 E_weight = agfindattr(auxg->proto->e, "weight");
00708 if (!E_weight)
00709 E_weight = agedgeattr (auxg, "weight", "");
00710 E_minlen = NULL;
00711 N_group = NULL;
00712
00713 return auxg;
00714 }
00715
00716
00717
00718 static void
00719 cleanupCloneGraph (graph_t* g)
00720 {
00721
00722 E_constr = attr_state.E_constr;
00723 E_samehead = attr_state.E_samehead;
00724 E_sametail = attr_state.E_sametail;
00725 E_weight = attr_state.E_weight;
00726 E_minlen = attr_state.E_minlen;
00727 N_group = attr_state.N_group;
00728 State = attr_state.State;
00729
00730 dot_cleanup(g);
00731 agclose(g);
00732 }
00733
00734
00735
00736
00737
00738
00739 static node_t*
00740 cloneNode (graph_t* g, node_t* orign, int flipped)
00741 {
00742 node_t* n = agnode(g, orign->name);
00743 agcopyattr (orign, n);
00744 if (shapeOf(orign) == SH_RECORD) {
00745 int lbllen = strlen(ND_label(orign)->text);
00746 char* buf = N_GNEW(lbllen+3,char);
00747 sprintf (buf, "{%s}", ND_label(orign)->text);
00748 agset (n, "label", buf);
00749 }
00750
00751 return n;
00752 }
00753
00754
00755
00756 static edge_t*
00757 cloneEdge (graph_t* g, node_t* tn, node_t* hn, edge_t* orig)
00758 {
00759 edge_t* e = agedge(g, tn, hn);
00760 for (; ED_edge_type(orig) != NORMAL; orig = ED_to_orig(orig));
00761 agcopyattr (orig, e);
00762
00763 return e;
00764 }
00765
00766
00767
00768
00769 static point
00770 transform (point p, point del, int flip)
00771 {
00772 if (flip) {
00773 int i = p.x;
00774 p.x = p.y;
00775 p.y = -i;
00776 }
00777 return add_points(p, del);
00778 }
00779
00780
00781
00782 static void
00783 makeSimpleFlat (node_t* tn, node_t* hn, edge_t** edges, int ind, int cnt, int et)
00784 {
00785 edge_t* e = edges[ind];
00786 point points[10];
00787 int i, pointn, stepy = (cnt > 1) ? ND_ht_i(tn) / (cnt - 1) : 0;
00788 point tp = add_points(ND_coord_i(tn), ED_tail_port(e).p);
00789 point hp = add_points(ND_coord_i(hn), ED_head_port(e).p);
00790 int dy = tp.y - ((cnt > 1) ? ND_ht_i(tn) / 2 : 0);
00791 for (i = 0; i < cnt; i++) {
00792 e = edges[ind + i];
00793 pointn = 0;
00794 if ((et == ET_SPLINE) || (et == ET_LINE)) {
00795 points[pointn++] = tp;
00796 points[pointn++] = pointof((2 * tp.x + hp.x) / 3, dy);
00797 points[pointn++] = pointof((2 * hp.x + tp.x) / 3, dy);
00798 points[pointn++] = hp;
00799 }
00800 else {
00801 points[pointn++] = tp;
00802 points[pointn++] = tp;
00803 points[pointn++] = pointof((2 * tp.x + hp.x) / 3, dy);
00804 points[pointn++] = pointof((2 * tp.x + hp.x) / 3, dy);
00805 points[pointn++] = pointof((2 * tp.x + hp.x) / 3, dy);
00806 points[pointn++] = pointof((2 * hp.x + tp.x) / 3, dy);
00807 points[pointn++] = pointof((2 * hp.x + tp.x) / 3, dy);
00808 points[pointn++] = pointof((2 * hp.x + tp.x) / 3, dy);
00809 points[pointn++] = hp;
00810 points[pointn++] = hp;
00811 }
00812 dy += stepy;
00813 clip_and_install(e, e->head, points, pointn, &sinfo);
00814 }
00815 }
00816
00817
00818
00819
00820
00821
00822
00823 static void
00824 make_flat_adj_edges(path* P, edge_t** edges, int ind, int cnt, edge_t* e0,
00825 int et)
00826 {
00827 node_t* n;
00828 node_t *tn, *hn;
00829 edge_t* e;
00830 int labels = 0, ports = 0;
00831 graph_t* g;
00832 graph_t* auxg;
00833 graph_t* subg;
00834 node_t *auxt, *auxh;
00835 edge_t* auxe;
00836 int i, j, midx, midy, leftx, rightx;
00837 point del;
00838 edge_t* hvye = NULL;
00839
00840 g = e0->tail->graph;
00841 tn = e0->tail, hn = e0->head;
00842 for (i = 0; i < cnt; i++) {
00843 e = edges[ind + i];
00844 if (ND_label(e)) labels++;
00845 if (ED_tail_port(e).defined || ED_head_port(e).defined) ports = 1;
00846 }
00847
00848
00849 if ((labels == 0) && (ports == 0)) {
00850 makeSimpleFlat (tn, hn, edges, ind, cnt, et);
00851 return;
00852 }
00853
00854 auxg = cloneGraph (g);
00855 subg = agsubg (auxg, "xxx");
00856 agset (subg, "rank", "source");
00857 rightx = ND_coord_i(hn).x;
00858 leftx = ND_coord_i(tn).x;
00859 if (GD_flip(g)) {
00860 node_t* n;
00861 n = tn;
00862 tn = hn;
00863 hn = n;
00864 }
00865 auxt = cloneNode(subg, tn, GD_flip(g));
00866 auxh = cloneNode(auxg, hn, GD_flip(g));
00867 for (i = 0; i < cnt; i++) {
00868 e = edges[ind + i];
00869 if (e->tail == tn)
00870 auxe = cloneEdge (auxg, auxt, auxh, e);
00871 else
00872 auxe = cloneEdge (auxg, auxh, auxt, e);
00873 ED_alg(e) = auxe;
00874 if (!hvye && !ED_tail_port(e0).defined && !ED_head_port(e0).defined) {
00875 hvye = auxe;
00876 ED_alg(hvye) = e;
00877 }
00878 }
00879 if (!hvye) {
00880 hvye = agedge (auxg, auxt, auxh);
00881 }
00882 agxset (hvye, E_weight->index, "10000");
00883 GD_gvc(auxg) = GD_gvc(g);
00884 setEdgeType (auxg, et);
00885 dot_init_node_edge(auxg);
00886
00887 dot_rank(auxg);
00888 dot_mincross(auxg);
00889 dot_position(auxg);
00890
00891
00892 midx = (ND_coord_i(tn).x - ND_rw_i(tn) + ND_coord_i(hn).x + ND_lw_i(hn))/2;
00893 midy = (ND_coord_i(auxt).x + ND_coord_i(auxh).x)/2;
00894 for (n = GD_nlist(auxg); n; n = ND_next(n)) {
00895 if (n == auxt) {
00896 ND_coord_i(n).y = rightx;
00897 ND_coord_i(n).x = midy;
00898 }
00899 else if (n == auxh) {
00900 ND_coord_i(n).y = leftx;
00901 ND_coord_i(n).x = midy;
00902 }
00903 else ND_coord_i(n).y = midx;
00904 }
00905 dot_sameports(auxg);
00906 _dot_splines(auxg, 0);
00907 dotneato_postprocess(auxg);
00908
00909
00910 if (GD_flip(g)) {
00911 del.x = ND_coord_i(tn).x - ND_coord_i(auxt).y;
00912 del.y = ND_coord_i(tn).y + ND_coord_i(auxt).x;
00913 }
00914 else {
00915 del.x = ND_coord_i(tn).x - ND_coord_i(auxt).x;
00916 del.y = ND_coord_i(tn).y - ND_coord_i(auxt).y;
00917 }
00918 for (i = 0; i < cnt; i++) {
00919 bezier* auxbz;
00920 bezier* bz;
00921
00922 e = edges[ind + i];
00923 auxe = (edge_t*)ED_alg(e);
00924 if ((auxe == hvye) & !ED_alg(auxe)) continue;
00925 auxbz = ED_spl(auxe)->list;
00926 bz = new_spline(e, auxbz->size);
00927 if (GD_flip(g)) {
00928 bz->sflag = auxbz->eflag;
00929 bz->sp = transform(auxbz->ep, del, 1);
00930 bz->eflag = auxbz->sflag;
00931 bz->ep = transform(auxbz->sp, del, 1);
00932 }
00933 else {
00934 bz->sflag = auxbz->sflag;
00935 bz->sp = transform(auxbz->sp, del, 0);
00936 bz->eflag = auxbz->eflag;
00937 bz->ep = transform(auxbz->ep, del, 0);
00938 }
00939 for (j = 0; j < auxbz->size; j++) {
00940 point pt;
00941 pt = bz->list[j] = transform(auxbz->list[j], del, GD_flip(g));
00942 update_bb(g, pt);
00943 }
00944 if (ED_label(e)) {
00945 ED_label(e)->p = transform(ED_label(auxe)->p, del, GD_flip(g));
00946 updateBB(g, ED_label(e));
00947 }
00948 }
00949
00950 cleanupCloneGraph (auxg);
00951 }
00952
00953
00954
00955 static void
00956 makeFlatEnd (spline_info_t* sp, path* P, node_t* n, edge_t* e, pathend_t* endp,
00957 boolean isBegin)
00958 {
00959 box b;
00960 graph_t* g = n->graph;
00961
00962 b = endp->nb = maximal_bbox(sp, n, NULL, e);
00963 endp->sidemask = TOP;
00964 if (isBegin) beginpath(P, e, FLATEDGE, endp, FALSE);
00965 else endpath(P, e, FLATEDGE, endp, FALSE);
00966 b.UR.y = endp->boxes[endp->boxn - 1].UR.y;
00967 b.LL.y = endp->boxes[endp->boxn - 1].LL.y;
00968 b = makeregularend(b, TOP, ND_coord_i(n).y + GD_rank(g)[ND_rank(n)].ht2);
00969 if (b.LL.x < b.UR.x && b.LL.y < b.UR.y)
00970 endp->boxes[endp->boxn++] = b;
00971 }
00972
00973
00974 static void
00975 makeBottomFlatEnd (spline_info_t* sp, path* P, node_t* n, edge_t* e,
00976 pathend_t* endp, boolean isBegin)
00977 {
00978 box b;
00979 graph_t* g = n->graph;
00980
00981 b = endp->nb = maximal_bbox(sp, n, NULL, e);
00982 endp->sidemask = BOTTOM;
00983 if (isBegin) beginpath(P, e, FLATEDGE, endp, FALSE);
00984 else endpath(P, e, FLATEDGE, endp, FALSE);
00985 b.UR.y = endp->boxes[endp->boxn - 1].UR.y;
00986 b.LL.y = endp->boxes[endp->boxn - 1].LL.y;
00987 b = makeregularend(b, BOTTOM, ND_coord_i(n).y - GD_rank(g)[ND_rank(n)].ht2);
00988 if (b.LL.x < b.UR.x && b.LL.y < b.UR.y)
00989 endp->boxes[endp->boxn++] = b;
00990 }
00991
00992
00993
00994
00995 static void
00996 make_flat_labeled_edge(spline_info_t* sp, path* P, edge_t* e, int et)
00997 {
00998 graph_t *g;
00999 node_t *tn, *hn, *ln;
01000 point *ps;
01001 pathend_t tend, hend;
01002 box lb;
01003 int boxn, i, pn, ydelta;
01004 edge_t *f;
01005 point points[7];
01006
01007 g = e->tail->graph;
01008 tn = e->tail;
01009 hn = e->head;
01010
01011 for (f = ED_to_virt(e); ED_to_virt(f); f = ED_to_virt(f));
01012 ln = f->tail;
01013 ED_label(e)->p = ND_coord_i(ln);
01014
01015 if (et == ET_LINE) {
01016 point startp, endp, lp;
01017 startp = add_points(ND_coord_i(tn), ED_tail_port(e).p);
01018 endp = add_points(ND_coord_i(hn), ED_head_port(e).p);
01019 lp = ED_label(e)->p;
01020 lp.y -= (ED_label(e)->dimen.y)/2.0;
01021 points[1] = points[0] = startp;
01022 points[2] = points[3] = points[4] = lp;
01023 points[5] = points[6] = endp;
01024 ps = points;
01025 pn = 7;
01026 }
01027 else {
01028 lb.LL.x = ND_coord_i(ln).x - ND_lw_i(ln);
01029 lb.UR.x = ND_coord_i(ln).x + ND_rw_i(ln);
01030 lb.UR.y = ND_coord_i(ln).y + ND_ht_i(ln)/2;
01031 ydelta = ND_coord_i(ln).y - GD_rank(g)[ND_rank(tn)].ht1 -
01032 ND_coord_i(tn).y + GD_rank(g)[ND_rank(tn)].ht2;
01033 ydelta /= 6;
01034 lb.LL.y = lb.UR.y - MAX(5,ydelta);
01035
01036 boxn = 0;
01037 makeFlatEnd (sp, P, tn, e, &tend, TRUE);
01038 makeFlatEnd (sp, P, hn, e, &hend, FALSE);
01039
01040 boxes[boxn].LL.x = tend.boxes[tend.boxn - 1].LL.x;
01041 boxes[boxn].LL.y = tend.boxes[tend.boxn - 1].UR.y;
01042 boxes[boxn].UR.x = lb.LL.x;
01043 boxes[boxn].UR.y = lb.LL.y;
01044 boxn++;
01045 boxes[boxn].LL.x = tend.boxes[tend.boxn - 1].LL.x;
01046 boxes[boxn].LL.y = lb.LL.y;
01047 boxes[boxn].UR.x = hend.boxes[hend.boxn - 1].UR.x;
01048 boxes[boxn].UR.y = lb.UR.y;
01049 boxn++;
01050 boxes[boxn].LL.x = lb.UR.x;
01051 boxes[boxn].UR.y = lb.LL.y;
01052 boxes[boxn].LL.y = hend.boxes[hend.boxn - 1].UR.y;
01053 boxes[boxn].UR.x = hend.boxes[hend.boxn - 1].UR.x;
01054 boxn++;
01055
01056 for (i = 0; i < tend.boxn; i++) add_box(P, tend.boxes[i]);
01057 for (i = 0; i < boxn; i++) add_box(P, boxes[i]);
01058 for (i = hend.boxn - 1; i >= 0; i--) add_box(P, hend.boxes[i]);
01059
01060 if (et == ET_SPLINE) ps = routesplines(P, &pn);
01061 else ps = routepolylines(P, &pn);
01062 if (pn == 0) return;
01063 }
01064 clip_and_install(e, e->head, ps, pn, &sinfo);
01065 }
01066
01067
01068
01069 static void
01070 make_flat_bottom_edges(spline_info_t* sp, path * P, edge_t ** edges, int
01071 ind, int cnt, edge_t* e, int splines)
01072 {
01073 node_t *tn, *hn;
01074 int j, i, stepx, stepy, vspace, r;
01075 rank_t* nextr;
01076 int pn;
01077 point *ps;
01078 pathend_t tend, hend;
01079 graph_t* g;
01080
01081 tn = e->tail, hn = e->head;
01082 g = tn->graph;
01083 r = ND_rank(tn);
01084 if (r < GD_maxrank(g)) {
01085 nextr = GD_rank(g) + (r+1);
01086 vspace = ND_coord_i(tn).y - GD_rank(g)[r].pht1 -
01087 (ND_coord_i(nextr->v[0]).y + nextr->pht2);
01088 }
01089 else {
01090 vspace = GD_ranksep(g);
01091 }
01092 stepx = sp->Multisep / (cnt+1);
01093 stepy = vspace / (cnt+1);
01094
01095 makeBottomFlatEnd (sp, P, tn, e, &tend, TRUE);
01096 makeBottomFlatEnd (sp, P, hn, e, &hend, FALSE);
01097
01098 for (i = 0; i < cnt; i++) {
01099 int boxn;
01100 box b;
01101 e = edges[ind + i];
01102 boxn = 0;
01103
01104 b = tend.boxes[tend.boxn - 1];
01105 boxes[boxn].LL.x = b.LL.x;
01106 boxes[boxn].UR.y = b.LL.y;
01107 boxes[boxn].UR.x = b.UR.x + (i + 1) * stepx;
01108 boxes[boxn].LL.y = b.LL.y - (i + 1) * stepy;
01109 boxn++;
01110 boxes[boxn].LL.x = tend.boxes[tend.boxn - 1].LL.x;
01111 boxes[boxn].UR.y = boxes[boxn-1].LL.y;
01112 boxes[boxn].UR.x = hend.boxes[hend.boxn - 1].UR.x;
01113 boxes[boxn].LL.y = boxes[boxn].UR.y - stepy;
01114 boxn++;
01115 b = hend.boxes[hend.boxn - 1];
01116 boxes[boxn].UR.x = b.UR.x;
01117 boxes[boxn].UR.y = b.LL.y;
01118 boxes[boxn].LL.x = b.LL.x - (i + 1) * stepx;
01119 boxes[boxn].LL.y = boxes[boxn-1].UR.y;
01120 boxn++;
01121
01122 for (j = 0; j < tend.boxn; j++) add_box(P, tend.boxes[j]);
01123 for (j = 0; j < boxn; j++) add_box(P, boxes[j]);
01124 for (j = hend.boxn - 1; j >= 0; j--) add_box(P, hend.boxes[j]);
01125
01126 if (splines) ps = routesplines(P, &pn);
01127 else ps = routepolylines(P, &pn);
01128 if (pn == 0)
01129 return;
01130 clip_and_install(e, e->head, ps, pn, &sinfo);
01131 P->nbox = 0;
01132 }
01133 }
01134
01135
01136
01137
01138
01139
01140
01141
01142
01143
01144 static void
01145 make_flat_edge(spline_info_t* sp, path * P, edge_t ** edges, int ind, int cnt, int et)
01146 {
01147 node_t *tn, *hn;
01148 edge_t fwdedge, *e;
01149 int j, i, stepx, stepy, vspace, r;
01150 int tside, hside, pn;
01151 point *ps;
01152 pathend_t tend, hend;
01153 graph_t* g;
01154
01155
01156 e = edges[ind];
01157 if (ED_tree_index(e) & BWDEDGE) {
01158 MAKEFWDEDGE(&fwdedge, e);
01159 e = &fwdedge;
01160 }
01161 if (ED_adjacent(edges[ind])) {
01162 make_flat_adj_edges (P, edges, ind, cnt, e, et);
01163 return;
01164 }
01165 if (ED_label(e)) {
01166 make_flat_labeled_edge (sp, P, e, et);
01167 return;
01168 }
01169
01170 if (et == ET_LINE) {
01171 makeSimpleFlat (e->tail, e->head, edges, ind, cnt, et);
01172 return;
01173 }
01174
01175 tside = ED_tail_port(e).side;
01176 hside = ED_head_port(e).side;
01177 if (((tside == BOTTOM) && (hside != TOP)) ||
01178 ((hside == BOTTOM) && (tside != TOP))) {
01179 make_flat_bottom_edges (sp, P, edges, ind, cnt, e, et == ET_SPLINE);
01180 return;
01181 }
01182
01183 tn = e->tail, hn = e->head;
01184 g = tn->graph;
01185 r = ND_rank(tn);
01186 if (r > 0) {
01187 rank_t* prevr;
01188 if (GD_has_labels(g) & EDGE_LABEL)
01189 prevr = GD_rank(g) + (r-2);
01190 else
01191 prevr = GD_rank(g) + (r-1);
01192 vspace = ND_coord_i(prevr->v[0]).y - prevr->ht1 - ND_coord_i(tn).y - GD_rank(g)[r].ht2;
01193 }
01194 else {
01195 vspace = GD_ranksep(g);
01196 }
01197 stepx = sp->Multisep / (cnt+1);
01198 stepy = vspace / (cnt+1);
01199
01200 makeFlatEnd (sp, P, tn, e, &tend, TRUE);
01201 makeFlatEnd (sp, P, hn, e, &hend, FALSE);
01202
01203 for (i = 0; i < cnt; i++) {
01204 int boxn;
01205 box b;
01206 e = edges[ind + i];
01207 boxn = 0;
01208
01209 b = tend.boxes[tend.boxn - 1];
01210 boxes[boxn].LL.x = b.LL.x;
01211 boxes[boxn].LL.y = b.UR.y;
01212 boxes[boxn].UR.x = b.UR.x + (i + 1) * stepx;
01213 boxes[boxn].UR.y = b.UR.y + (i + 1) * stepy;
01214 boxn++;
01215 boxes[boxn].LL.x = tend.boxes[tend.boxn - 1].LL.x;
01216 boxes[boxn].LL.y = boxes[boxn-1].UR.y;
01217 boxes[boxn].UR.x = hend.boxes[hend.boxn - 1].UR.x;
01218 boxes[boxn].UR.y = boxes[boxn].LL.y + stepy;
01219 boxn++;
01220 b = hend.boxes[hend.boxn - 1];
01221 boxes[boxn].UR.x = b.UR.x;
01222 boxes[boxn].LL.y = b.UR.y;
01223 boxes[boxn].LL.x = b.LL.x - (i + 1) * stepx;
01224 boxes[boxn].UR.y = boxes[boxn-1].LL.y;
01225 boxn++;
01226
01227 for (j = 0; j < tend.boxn; j++) add_box(P, tend.boxes[j]);
01228 for (j = 0; j < boxn; j++) add_box(P, boxes[j]);
01229 for (j = hend.boxn - 1; j >= 0; j--) add_box(P, hend.boxes[j]);
01230
01231 if (et == ET_SPLINE) ps = routesplines(P, &pn);
01232 else ps = routepolylines(P, &pn);
01233 if (pn == 0)
01234 return;
01235 clip_and_install(e, e->head, ps, pn, &sinfo);
01236 P->nbox = 0;
01237 }
01238 }
01239
01240
01241
01242
01243 static int
01244 leftOf (point p1, point p2, point p3)
01245 {
01246 int d;
01247
01248 d = ((p1.y - p2.y) * (p3.x - p2.x)) -
01249 ((p3.y - p2.y) * (p1.x - p2.x));
01250 return (d > 0);
01251 }
01252
01253
01254
01255
01256
01257
01258
01259
01260
01261
01262
01263
01264
01265
01266
01267
01268 static int
01269 makeLineEdge(edge_t* fe, point* points, node_t** hp)
01270 {
01271 int delr, pn;
01272 node_t* hn;
01273 node_t* tn;
01274 edge_t* e = fe;
01275 point startp, endp, lp;
01276 pointf dimen;
01277 double width, height;
01278
01279 while (ED_edge_type(e) != NORMAL)
01280 e = ED_to_orig(e);
01281 hn = e->head;
01282 tn = e->tail;
01283 delr = ABS(ND_rank(hn)-ND_rank(tn));
01284 if ((delr == 1) || ((delr == 2) && (GD_has_labels(hn->graph) & EDGE_LABEL)))
01285 return 0;
01286 if (fe->tail == e->tail) {
01287 *hp = hn;
01288 startp = add_points(ND_coord_i(tn), ED_tail_port(e).p);
01289 endp = add_points(ND_coord_i(hn), ED_head_port(e).p);
01290 }
01291 else {
01292 *hp = tn;
01293 startp = add_points(ND_coord_i(hn), ED_head_port(e).p);
01294 endp = add_points(ND_coord_i(tn), ED_tail_port(e).p);
01295 }
01296
01297 if (ED_label(e)) {
01298 dimen = ED_label(e)->dimen;
01299 if (GD_flip(hn->graph)) {
01300 width = dimen.y;
01301 height = dimen.x;
01302 }
01303 else {
01304 width = dimen.x;
01305 height = dimen.y;
01306 }
01307
01308 lp = ED_label(e)->p;
01309 if (leftOf (endp,startp,lp)) {
01310 lp.x += width/2.0;
01311 lp.y -= height/2.0;
01312 }
01313 else {
01314 lp.x -= width/2.0;
01315 lp.y += height/2.0;
01316 }
01317
01318 points[1] = points[0] = startp;
01319 points[2] = points[3] = points[4] = lp;
01320 points[5] = points[6] = endp;
01321 pn = 7;
01322 }
01323 else {
01324 points[1] = points[0] = startp;
01325 points[3] = points[2] = endp;
01326 pn = 4;
01327 }
01328
01329 return pn;
01330 }
01331
01332
01333
01334 static void
01335 make_regular_edge(spline_info_t* sp, path * P, edge_t ** edges, int ind, int cnt, int et)
01336 {
01337 graph_t *g;
01338 node_t *tn, *hn;
01339 edge_t fwdedgea, fwdedgeb, fwdedge, *e, *fe, *le, *segfirst;
01340 point *ps;
01341 pathend_t tend, hend;
01342 box b;
01343 int boxn, sl, si, smode, i, j, dx, pn, hackflag, longedge;
01344 point points[1000], points2[1000];
01345 int pointn;
01346
01347 sl = 0;
01348 e = edges[ind];
01349 g = e->tail->graph;
01350 hackflag = FALSE;
01351 if (ABS(ND_rank(e->tail) - ND_rank(e->head)) > 1) {
01352 fwdedgea = *e;
01353 if (ED_tree_index(e) & BWDEDGE) {
01354 MAKEFWDEDGE(&fwdedgeb, e);
01355 fwdedgea.tail = e->head;
01356 fwdedgea.u.tail_port = ED_head_port(e);
01357 } else {
01358 fwdedgeb = *e;
01359 fwdedgea.tail = e->tail;
01360 }
01361 le = getmainedge(e);
01362 while (ED_to_virt(le))
01363 le = ED_to_virt(le);
01364 fwdedgea.head = le->head;
01365 fwdedgea.u.head_port.defined = FALSE;
01366 fwdedgea.u.edge_type = VIRTUAL;
01367 fwdedgea.u.head_port.p.x = fwdedgea.u.head_port.p.y = 0;
01368 fwdedgea.u.to_orig = e;
01369 e = &fwdedgea;
01370 hackflag = TRUE;
01371 } else {
01372 if (ED_tree_index(e) & BWDEDGE) {
01373 MAKEFWDEDGE(&fwdedgea, e);
01374 e = &fwdedgea;
01375 }
01376 }
01377 fe = e;
01378
01379
01380
01381 if ((et == ET_LINE) && (pointn = makeLineEdge (fe, points, &hn))) {
01382 }
01383 else {
01384 int splines = et == ET_SPLINE;
01385 boxn = 0;
01386 pointn = 0;
01387 segfirst = e;
01388 tn = e->tail;
01389 hn = e->head;
01390 b = tend.nb = maximal_bbox(sp, tn, NULL, e);
01391 beginpath(P, e, REGULAREDGE, &tend, spline_merge(e->tail));
01392 b.UR.y = tend.boxes[tend.boxn - 1].UR.y;
01393 b.LL.y = tend.boxes[tend.boxn - 1].LL.y;
01394 b = makeregularend(b, BOTTOM,
01395 ND_coord_i(tn).y - GD_rank(tn->graph)[ND_rank(tn)].ht1);
01396 if (b.LL.x < b.UR.x && b.LL.y < b.UR.y)
01397 tend.boxes[tend.boxn++] = b;
01398 longedge = 0;
01399 smode = FALSE, si = -1;
01400 while (ND_node_type(hn) == VIRTUAL && !sinfo.splineMerge(hn)) {
01401 longedge = 1;
01402 boxes[boxn++] = rank_box(sp, g, ND_rank(tn));
01403 if (!smode
01404 && ((sl = straight_len(hn)) >=
01405 ((GD_has_labels(g) & EDGE_LABEL) ? 4 + 1 : 2 + 1))) {
01406 smode = TRUE;
01407 si = 1, sl -= 2;
01408 }
01409 if (!smode || si > 0) {
01410 si--;
01411 boxes[boxn++] = maximal_bbox(sp, hn, e, ND_out(hn).list[0]);
01412 e = ND_out(hn).list[0];
01413 tn = e->tail;
01414 hn = e->head;
01415 continue;
01416 }
01417 hend.nb = maximal_bbox(sp, hn, e, ND_out(hn).list[0]);
01418 endpath(P, e, REGULAREDGE, &hend, spline_merge(e->head));
01419 b = makeregularend(hend.boxes[hend.boxn - 1], TOP,
01420 ND_coord_i(hn).y + GD_rank(hn->graph)[ND_rank(hn)].ht2);
01421 if (b.LL.x < b.UR.x && b.LL.y < b.UR.y)
01422 hend.boxes[hend.boxn++] = b;
01423 P->end.theta = M_PI / 2, P->end.constrained = TRUE;
01424 completeregularpath(P, segfirst, e, &tend, &hend, boxes, boxn, 1);
01425 if (splines) ps = routesplines(P, &pn);
01426 else {
01427 ps = routepolylines (P, &pn);
01428 if ((et == ET_LINE) && (pn > 4)) {
01429 ps[1] = ps[0];
01430 ps[3] = ps[2] = ps[pn-1];
01431 pn = 4;
01432 }
01433 }
01434 if (pn == 0)
01435 return;
01436 for (i = 0; i < pn; i++)
01437 points[pointn++] = ps[i];
01438 e = straight_path(ND_out(hn).list[0], sl, points, &pointn);
01439 recover_slack(segfirst, P);
01440 segfirst = e;
01441 tn = e->tail;
01442 hn = e->head;
01443 boxn = 0;
01444 tend.nb = maximal_bbox(sp, tn, ND_in(tn).list[0], e);
01445 beginpath(P, e, REGULAREDGE, &tend, spline_merge(e->tail));
01446 b = makeregularend(tend.boxes[tend.boxn - 1], BOTTOM,
01447 ND_coord_i(tn).y - GD_rank(tn->graph)[ND_rank(tn)].ht1);
01448 if (b.LL.x < b.UR.x && b.LL.y < b.UR.y)
01449 tend.boxes[tend.boxn++] = b;
01450 P->start.theta = -M_PI / 2, P->start.constrained = TRUE;
01451 smode = FALSE;
01452 }
01453 boxes[boxn++] = rank_box(sp, g, ND_rank(tn));
01454 b = hend.nb = maximal_bbox(sp, hn, e, NULL);
01455 endpath(P, hackflag ? &fwdedgeb : e, REGULAREDGE, &hend,
01456 spline_merge(e->head));
01457 b.UR.y = hend.boxes[hend.boxn - 1].UR.y;
01458 b.LL.y = hend.boxes[hend.boxn - 1].LL.y;
01459 b = makeregularend(b, TOP,
01460 ND_coord_i(hn).y + GD_rank(hn->graph)[ND_rank(hn)].ht2);
01461 if (b.LL.x < b.UR.x && b.LL.y < b.UR.y)
01462 hend.boxes[hend.boxn++] = b;
01463 completeregularpath(P, segfirst, e, &tend, &hend, boxes, boxn,
01464 longedge);
01465 if (splines) ps = routesplines(P, &pn);
01466 else ps = routepolylines (P, &pn);
01467 if ((et == ET_LINE) && (pn > 4)) {
01468
01469
01470
01471
01472 ps[1] = ps[0];
01473 ps[3] = ps[2] = ps[pn-1];
01474 pn = 4;
01475 }
01476 if (pn == 0)
01477 return;
01478 for (i = 0; i < pn; i++)
01479 points[pointn++] = ps[i];
01480 recover_slack(segfirst, P);
01481 hn = hackflag ? fwdedgeb.head : e->head;
01482 }
01483
01484
01485
01486 if (cnt == 1) {
01487 clip_and_install(fe, hn, points, pointn, &sinfo);
01488 return;
01489 }
01490 dx = sp->Multisep * (cnt - 1) / 2;
01491 for (i = 1; i < pointn - 1; i++)
01492 points[i].x -= dx;
01493 for (i = 0; i < pointn; i++)
01494 points2[i] = points[i];
01495 clip_and_install(fe, hn, points2, pointn, &sinfo);
01496 for (j = 1; j < cnt; j++) {
01497 e = edges[ind + j];
01498 if (ED_tree_index(e) & BWDEDGE) {
01499 MAKEFWDEDGE(&fwdedge, e);
01500 e = &fwdedge;
01501 }
01502 for (i = 1; i < pointn - 1; i++)
01503 points[i].x += sp->Multisep;
01504 for (i = 0; i < pointn; i++)
01505 points2[i] = points[i];
01506 clip_and_install(e, e->head, points2, pointn, &sinfo);
01507 }
01508 }
01509
01510
01511
01512 #ifdef OBSOLETE
01513 static void
01514 chooseflatsides(pathend_t* tendp, pathend_t *hendp,
01515 int* tsidep, int* hsidep, int* msidep, int* tdirp,
01516 int* hdirp, int* crossp)
01517 {
01518 int i;
01519
01520 for (i = 0; i < 16; i++)
01521 if ((flatsidemap[i][0] & tendp->sidemask) &&
01522 (flatsidemap[i][1] & hendp->sidemask))
01523 break;
01524 if (i == 16)
01525 abort();
01526 *tsidep = flatsidemap[i][0], *hsidep = flatsidemap[i][1];
01527 *msidep = flatsidemap[i][2];
01528 *tdirp = flatsidemap[i][3], *hdirp = flatsidemap[i][4];
01529 *crossp = flatsidemap[i][5];
01530 }
01531
01532 static void
01533 completeflatpath(path * P,
01534 pathend_t * tendp, pathend_t * hendp,
01535 int tside, int hside, int mside, int tdir, int hdir,
01536 box * arg_lb, box * arg_rb, int w, int h)
01537 {
01538 int i, side, boxn;
01539 box boxes[8];
01540 box tb, hb;
01541 box lb, rb;
01542 lb = *arg_lb;
01543 rb = *arg_rb;
01544
01545 tb = makeflatend(tendp->boxes[tendp->boxn - 1], tside, tdir, lb);
01546 hb = makeflatend(hendp->boxes[hendp->boxn - 1], hside, OTHERDIR(hdir),
01547 rb);
01548
01549 boxn = 0;
01550 for (side = tside;; side = NEXTSIDE(side, tdir)) {
01551 boxes[boxn++] = makeflatcomponent(lb, rb, side,
01552 (side == mside) ? 0 : -1, tdir,
01553 w, h);
01554 if (side == mside)
01555 break;
01556 }
01557 if (mside == RIGHT)
01558 mside = LEFT;
01559 if (mside != hside) {
01560 for (side = NEXTSIDE(mside, hdir);; side = NEXTSIDE(side, hdir)) {
01561 boxes[boxn++] = makeflatcomponent(lb, rb, side, 1, hdir, w, h);
01562 if (side == hside)
01563 break;
01564 }
01565 }
01566
01567 for (i = 0; i < tendp->boxn; i++)
01568 add_box(P, tendp->boxes[i]);
01569 if (tb.LL.x != tb.UR.x && tb.LL.y != tb.UR.y)
01570 add_box(P, tb);
01571 for (i = 0; i < boxn; i++)
01572 add_box(P, boxes[i]);
01573 if (hb.LL.x != hb.UR.x && hb.LL.y != hb.UR.y)
01574 add_box(P, hb);
01575 for (i = hendp->boxn - 1; i >= 0; i--)
01576 add_box(P, hendp->boxes[i]);
01577 }
01578
01579 static box
01580 makeflatend(box b, int side, int dir, box bb)
01581 {
01582 box eb = { {0, 0}, {0, 0} };
01583
01584 switch (side) {
01585 case BOTTOM:
01586 eb = boxof(b.LL.x, bb.LL.y, b.UR.x, b.LL.y);
01587 if (dir == CCW)
01588 eb.UR.x += (bb.UR.x - b.UR.x) / 2;
01589 else
01590 eb.LL.x -= (b.LL.x - bb.LL.x) / 2;
01591 break;
01592 case RIGHT:
01593 eb = boxof(b.UR.x, b.LL.y, bb.UR.x, b.UR.y);
01594 if (dir == CCW)
01595 eb.UR.y += (bb.UR.y - b.UR.y) / 2;
01596 else
01597 eb.LL.y -= (b.LL.y - bb.LL.y) / 2;
01598 break;
01599 case TOP:
01600 eb = boxof(b.LL.x, b.UR.y, b.UR.x, bb.UR.y);
01601 if (dir == CCW)
01602 eb.LL.x -= (b.LL.x - bb.LL.x) / 2;
01603 else
01604 eb.UR.x += (bb.UR.x - b.UR.x) / 2;
01605 break;
01606 case LEFT:
01607 eb = boxof(bb.LL.x, b.LL.y, b.LL.x, b.UR.y);
01608 if (dir == CCW)
01609 eb.LL.y -= (bb.UR.y - b.UR.y) / 2;
01610 else
01611 eb.UR.y += (b.LL.y - bb.LL.y) / 2;
01612 break;
01613 }
01614 return eb;
01615 }
01616
01617 static box makeflatcomponent(lb, rb, side, mode, dir, w, h)
01618 box lb, rb;
01619 int side, mode, dir, w, h;
01620 {
01621 box b = { {0, 0}, {0, 0} };
01622
01623
01624
01625
01626 switch (side) {
01627 case BOTTOM:
01628 b.LL.x = lb.LL.x - w, b.UR.x = rb.UR.x + w;
01629 if (mode <= 0)
01630 b.LL.y = lb.LL.y - h, b.UR.y = lb.LL.y;
01631 else
01632 b.LL.y = rb.LL.y - h, b.UR.y = rb.LL.y;
01633 break;
01634 case RIGHT:
01635 if (mode == -1) {
01636 b.LL.x = lb.UR.x, b.UR.x = lb.UR.x + w;
01637 b.LL.y = lb.LL.y, b.UR.y = lb.UR.y;
01638 } else if (mode == 0) {
01639 b.LL.x = lb.UR.x, b.UR.x = lb.UR.x + w;
01640 if (dir == CCW)
01641 b.LL.y = lb.LL.y, b.UR.y = rb.UR.y;
01642 else
01643 b.LL.y = rb.LL.y, b.UR.y = lb.UR.y;
01644 } else {
01645 b.LL.x = rb.UR.x, b.UR.x = rb.UR.x + w;
01646 b.LL.y = rb.LL.y, b.UR.y = rb.UR.y;
01647 }
01648 break;
01649 case TOP:
01650 b.LL.x = lb.LL.x - w, b.UR.x = rb.UR.x + w;
01651 if (mode <= 0)
01652 b.LL.y = lb.UR.y, b.UR.y = lb.UR.y + h;
01653 else
01654 b.LL.y = rb.UR.y, b.UR.y = rb.UR.y + h;
01655 break;
01656 case LEFT:
01657 if (mode == -1) {
01658 b.LL.x = lb.LL.x - w, b.UR.x = lb.LL.x;
01659 b.LL.y = lb.LL.y, b.UR.y = lb.UR.y;
01660 } else if (mode == 0) {
01661 b.LL.x = lb.LL.x - w, b.UR.x = lb.LL.x;
01662 if (dir == CCW)
01663 b.LL.y = lb.LL.y, b.UR.y = rb.UR.y;
01664 else
01665 b.LL.y = rb.LL.y, b.UR.y = lb.UR.y;
01666 } else {
01667 b.LL.x = rb.LL.x - w, b.UR.x = rb.LL.x;
01668 b.LL.y = rb.LL.y, b.UR.y = rb.UR.y;
01669 }
01670 break;
01671 }
01672 return b;
01673 }
01674 static void
01675 completeflatpath(path* P, pathend_t* tendp, pathend_t* hendp,
01676 box* lbp, box* rbp, int w, int h)
01677 {
01678 int i;
01679 box wbox;
01680 box tb, hb;
01681 box lb, rb;
01682 lb = *lbp;
01683 rb = *rbp;
01684
01685 tb = makeflatend(tendp->boxes[tendp->boxn - 1], TOP, CW, lb);
01686 hb = makeflatend(hendp->boxes[hendp->boxn - 1], TOP, CCW, rb);
01687
01688 wbox = makeflatcomponent(lb, rb, TOP, 0, CW, w, h);
01689
01690 for (i = 0; i < tendp->boxn; i++)
01691 add_box(P, tendp->boxes[i]);
01692 add_box(P, tb);
01693 add_box(P, wbox);
01694 for (i = hendp->boxn - 1; i >= 0; i--)
01695 add_box(P, hendp->boxes[i]);
01696 }
01697 #endif
01698
01699
01700
01701 #define DONT_WANT_ANY_ENDPOINT_PATH_REFINEMENT
01702 #ifdef DONT_WANT_ANY_ENDPOINT_PATH_REFINEMENT
01703 static void
01704 completeregularpath(path * P, edge_t * first, edge_t * last,
01705 pathend_t * tendp, pathend_t * hendp, box * boxes,
01706 int boxn, int flag)
01707 {
01708 edge_t *uleft, *uright, *lleft, *lright;
01709 int i, fb, lb;
01710 splines *spl;
01711 point *pp;
01712 int pn;
01713
01714 fb = lb = -1;
01715 uleft = uright = NULL;
01716 uleft = top_bound(first, -1), uright = top_bound(first, 1);
01717 if (uleft) {
01718 spl = getsplinepoints(uleft);
01719 pp = spl->list[0].list, pn = spl->list[0].size;
01720 P->ulpp = &pp[0];
01721 }
01722 if (uright) {
01723 spl = getsplinepoints(uright);
01724 pp = spl->list[0].list, pn = spl->list[0].size;
01725 P->urpp = &pp[0];
01726 }
01727 lleft = lright = NULL;
01728 lleft = bot_bound(last, -1), lright = bot_bound(last, 1);
01729 if (lleft) {
01730 spl = getsplinepoints(lleft);
01731 pp = spl->list[spl->size - 1].list, pn =
01732 spl->list[spl->size - 1].size;
01733 P->llpp = &pp[pn - 1];
01734 }
01735 if (lright) {
01736 spl = getsplinepoints(lright);
01737 pp = spl->list[spl->size - 1].list, pn =
01738 spl->list[spl->size - 1].size;
01739 P->lrpp = &pp[pn - 1];
01740 }
01741 for (i = 0; i < tendp->boxn; i++)
01742 add_box(P, tendp->boxes[i]);
01743 fb = P->nbox + 1;
01744 lb = fb + boxn - 3;
01745 for (i = 0; i < boxn; i++)
01746 add_box(P, boxes[i]);
01747 for (i = hendp->boxn - 1; i >= 0; i--)
01748 add_box(P, hendp->boxes[i]);
01749 adjustregularpath(P, fb, lb);
01750 }
01751 #else
01752 void refineregularends(edge_t * left, edge_t * right, pathend_t * endp,
01753 int dir, box b, box * boxes, int *boxnp);
01754
01755
01756 static void
01757 completeregularpath(path * P, edge_t * first, edge_t * last,
01758 pathend_t * tendp, pathend_t * hendp, box * boxes,
01759 int boxn, int flag)
01760 {
01761 edge_t *uleft, *uright, *lleft, *lright;
01762 box uboxes[NSUB], lboxes[NSUB];
01763 box b;
01764 int uboxn, lboxn, i, y, fb, lb;
01765
01766 fb = lb = -1;
01767 uleft = uright = NULL;
01768 if (flag || ND_rank(first->tail) + 1 != ND_rank(last->head))
01769 uleft = top_bound(first, -1), uright = top_bound(first, 1);
01770 refineregularends(uleft, uright, tendp, 1, boxes[0], uboxes, &uboxn);
01771 lleft = lright = NULL;
01772 if (flag || ND_rank(first->tail) + 1 != ND_rank(last->head))
01773 lleft = bot_bound(last, -1), lright = bot_bound(last, 1);
01774 refineregularends(lleft, lright, hendp, -1, boxes[boxn - 1], lboxes,
01775 &lboxn);
01776 for (i = 0; i < tendp->boxn; i++)
01777 add_box(P, tendp->boxes[i]);
01778 if (ND_rank(first->tail) + 1 == ND_rank(last->head)) {
01779 if ((!uleft && !uright) && (lleft || lright)) {
01780 b = boxes[0];
01781 y = b.UR.y - b.LL.y;
01782 for (i = 0; i < NSUB; i++) {
01783 uboxes[i] = b;
01784 uboxes[i].UR.y = b.UR.y - y * i / NSUB;
01785 uboxes[i].LL.y = b.UR.y - y * (i + 1) / NSUB;
01786 }
01787 uboxn = NSUB;
01788 } else if ((uleft || uright) && (!lleft && !lright)) {
01789 b = boxes[boxn - 1];
01790 y = b.UR.y - b.LL.y;
01791 for (i = 0; i < NSUB; i++) {
01792 lboxes[i] = b;
01793 lboxes[i].UR.y = b.UR.y - y * i / NSUB;
01794 lboxes[i].LL.y = b.UR.y - y * (i + 1) / NSUB;
01795 }
01796 lboxn = NSUB;
01797 }
01798 for (i = 0; i < uboxn; i++) {
01799 uboxes[i].LL.x = MAX(uboxes[i].LL.x, lboxes[i].LL.x);
01800 uboxes[i].UR.x = MIN(uboxes[i].UR.x, lboxes[i].UR.x);
01801 }
01802 for (i = 0; i < uboxn; i++)
01803 add_box(P, uboxes[i]);
01804 } else {
01805 for (i = 0; i < uboxn; i++)
01806 add_box(P, uboxes[i]);
01807 fb = P->nbox;
01808 lb = fb + boxn - 3;
01809 for (i = 1; i < boxn - 1; i++)
01810 add_box(P, boxes[i]);
01811 for (i = 0; i < lboxn; i++)
01812 add_box(P, lboxes[i]);
01813 }
01814 for (i = hendp->boxn - 1; i >= 0; i--)
01815 add_box(P, hendp->boxes[i]);
01816 adjustregularpath(P, fb, lb);
01817 }
01818 #endif
01819
01820
01821
01822
01823
01824
01825 static box makeregularend(box b, int side, int y)
01826 {
01827 box newb;
01828 switch (side) {
01829 case BOTTOM:
01830 newb = boxof(b.LL.x, y, b.UR.x, b.LL.y);
01831 break;
01832 case TOP:
01833 newb = boxof(b.LL.x, b.UR.y, b.UR.x, y);
01834 break;
01835 }
01836 return newb;
01837 }
01838
01839 #ifndef DONT_WANT_ANY_ENDPOINT_PATH_REFINEMENT
01840 void refineregularends(left, right, endp, dir, b, boxes, boxnp)
01841 edge_t *left, *right;
01842 pathend_t *endp;
01843 int dir;
01844 box b;
01845 box *boxes;
01846 int *boxnp;
01847 {
01848 splines *lspls, *rspls;
01849 point pp, cp;
01850 box eb;
01851 box *bp;
01852 int y, i, j, k;
01853 int nsub;
01854
01855 y = b.UR.y - b.LL.y;
01856 if ((y == 1) || (!left && !right)) {
01857 boxes[0] = b;
01858 *boxnp = 1;
01859 return;
01860 }
01861 nsub = MIN(NSUB, y);
01862 for (i = 0; i < nsub; i++) {
01863 boxes[i] = b;
01864 boxes[i].UR.y = b.UR.y - y * i / nsub;
01865 boxes[i].LL.y = b.UR.y - y * (i + 1) / nsub;
01866 if (boxes[i].UR.y == boxes[i].LL.y)
01867 abort();
01868 }
01869 *boxnp = nsub;
01870
01871 for (j = 0; j < endp->boxn; j++) {
01872 eb = endp->boxes[j];
01873 y = eb.UR.y - eb.LL.y;
01874 #ifdef STEVE_AND_LEFTY_GRASPING_AT_STRAWS
01875 if (y < 15)
01876 continue;
01877 #else
01878 if (y < nsub)
01879 continue;
01880 #endif
01881 for (k = endp->boxn - 1; k > j; k--)
01882 endp->boxes[k + (nsub - 1)] = endp->boxes[k];
01883 for (i = 0; i < nsub; i++) {
01884 bp = &endp->boxes[j + ((dir == 1) ? i : (nsub - i - 1))];
01885 *bp = eb;
01886 bp->UR.y = eb.UR.y - y * i / nsub;
01887 bp->LL.y = eb.UR.y - y * (i + 1) / nsub;
01888 if (bp->UR.y == bp->LL.y)
01889 abort();
01890 }
01891 endp->boxn += (nsub - 1);
01892 j += nsub - 1;
01893 }
01894 if (left) {
01895 lspls = getsplinepoints(left);
01896 pp = spline_at_y(lspls, boxes[0].UR.y);
01897 for (i = 0; i < nsub; i++) {
01898 cp = spline_at_y(lspls, boxes[i].LL.y);
01899
01900 boxes[i].LL.x = MAX(pp.x, cp.x);
01901 pp = cp;
01902 }
01903 pp = spline_at_y(lspls, (dir == 1) ?
01904 endp->boxes[1].UR.y : endp->boxes[1].LL.y);
01905 for (i = 1; i < endp->boxn; i++) {
01906 cp = spline_at_y(lspls, (dir == 1) ?
01907 endp->boxes[i].LL.y : endp->boxes[i].UR.y);
01908 endp->boxes[i].LL.x = MIN(endp->nb.UR.x, MAX(pp.x, cp.x));
01909 pp = cp;
01910 }
01911 i = (dir == 1) ? 0 : *boxnp - 1;
01912 if (boxes[i].LL.x > endp->boxes[endp->boxn - 1].UR.x - MINW)
01913 boxes[i].LL.x = endp->boxes[endp->boxn - 1].UR.x - MINW;
01914 }
01915 if (right) {
01916 rspls = getsplinepoints(right);
01917 pp = spline_at_y(rspls, boxes[0].UR.y);
01918 for (i = 0; i < nsub; i++) {
01919 cp = spline_at_y(rspls, boxes[i].LL.y);
01920
01921 boxes[i].UR.x = AVG(pp.x, cp.x);
01922 pp = cp;
01923 }
01924 pp = spline_at_y(rspls, (dir == 1) ?
01925 endp->boxes[1].UR.y : endp->boxes[1].LL.y);
01926 for (i = 1; i < endp->boxn; i++) {
01927 cp = spline_at_y(rspls, (dir == 1) ?
01928 endp->boxes[i].LL.y : endp->boxes[i].UR.y);
01929 endp->boxes[i].UR.x = MAX(endp->nb.LL.x, AVG(pp.x, cp.x));
01930 pp = cp;
01931 }
01932 i = (dir == 1) ? 0 : *boxnp - 1;
01933 if (boxes[i].UR.x < endp->boxes[endp->boxn - 1].LL.x + MINW)
01934 boxes[i].UR.x = endp->boxes[endp->boxn - 1].LL.x + MINW;
01935 }
01936 }
01937 #endif
01938
01939
01940
01941
01942
01943
01944
01945
01946
01947
01948
01949
01950
01951
01952
01953
01954
01955 static void adjustregularpath(path * P, int fb, int lb)
01956 {
01957 box *bp1, *bp2;
01958 int i, x;
01959
01960 for (i = fb-1; i < lb+1; i++) {
01961 bp1 = &P->boxes[i];
01962 if ((i - fb) % 2 == 0) {
01963 if (bp1->LL.x >= bp1->UR.x) {
01964 x = (bp1->LL.x + bp1->UR.x) / 2;
01965 bp1->LL.x = x - HALFMINW, bp1->UR.x = x + HALFMINW;
01966 }
01967 } else {
01968 if (bp1->LL.x + MINW > bp1->UR.x) {
01969 x = (bp1->LL.x + bp1->UR.x) / 2;
01970 bp1->LL.x = x - HALFMINW, bp1->UR.x = x + HALFMINW;
01971 }
01972 }
01973 }
01974 for (i = 0; i < P->nbox - 1; i++) {
01975 bp1 = &P->boxes[i], bp2 = &P->boxes[i + 1];
01976 if (i >= fb && i <= lb && (i - fb) % 2 == 0) {
01977 if (bp1->LL.x + MINW > bp2->UR.x)
01978 bp2->UR.x = bp1->LL.x + MINW;
01979 if (bp1->UR.x - MINW < bp2->LL.x)
01980 bp2->LL.x = bp1->UR.x - MINW;
01981 } else if (i + 1 >= fb && i < lb && (i + 1 - fb) % 2 == 0) {
01982 if (bp1->LL.x + MINW > bp2->UR.x)
01983 bp1->LL.x = bp2->UR.x - MINW;
01984 if (bp1->UR.x - MINW < bp2->LL.x)
01985 bp1->UR.x = bp2->LL.x + MINW;
01986 }
01987 #ifdef OLD
01988 else {
01989 if (bp1->LL.x + MINW > bp2->UR.x) {
01990 x = (bp1->LL.x + bp2->UR.x) / 2;
01991 bp1->LL.x = x - HALFMINW;
01992 bp2->UR.x = x + HALFMINW;
01993 }
01994 if (bp1->UR.x - MINW < bp2->LL.x) {
01995 x = (bp1->UR.x + bp2->LL.x) / 2;
01996 bp1->UR.x = x + HALFMINW;
01997 bp2->LL.x = x - HALFMINW;
01998 }
01999 }
02000 #endif
02001 }
02002 }
02003
02004 static box rank_box(spline_info_t* sp, graph_t * g, int r)
02005 {
02006 box b;
02007 node_t * left0, *left1;
02008
02009 b = sp->Rank_box[r];
02010 if (b.LL.x == b.UR.x) {
02011 left0 = GD_rank(g)[r].v[0];
02012
02013 left1 = GD_rank(g)[r + 1].v[0];
02014
02015 b.LL.x = sp->LeftBound;
02016 b.LL.y = ND_coord_i(left1).y + GD_rank(g)[r + 1].ht2;
02017 b.UR.x = sp->RightBound;
02018 b.UR.y = ND_coord_i(left0).y - GD_rank(g)[r].ht1;
02019 sp->Rank_box[r] = b;
02020 }
02021 return b;
02022 }
02023
02024
02025 static int straight_len(node_t * n)
02026 {
02027 int cnt = 0;
02028 node_t *v;
02029
02030 v = n;
02031 while (1) {
02032 v = ND_out(v).list[0]->head;
02033 if (ND_node_type(v) != VIRTUAL)
02034 break;
02035 if ((ND_out(v).size != 1) || (ND_in(v).size != 1))
02036 break;
02037 if (ND_coord_i(v).x != ND_coord_i(n).x)
02038 break;
02039 cnt++;
02040 }
02041 return cnt;
02042 }
02043
02044 static edge_t *straight_path(edge_t * e, int cnt, point * plist, int *np)
02045 {
02046 int n = *np;
02047 edge_t *f = e;
02048
02049 while (cnt--)
02050 f = ND_out(f->head).list[0];
02051 plist[(*np)++] = plist[n - 1];
02052 plist[(*np)++] = plist[n - 1];
02053 plist[(*np)] = ND_coord_i(f->tail);
02054 return f;
02055 }
02056
02057 static void recover_slack(edge_t * e, path * p)
02058 {
02059 int b;
02060 node_t *vn;
02061
02062 b = 0;
02063 for (vn = e->head;
02064 ND_node_type(vn) == VIRTUAL && !sinfo.splineMerge(vn);
02065 vn = ND_out(vn).list[0]->head) {
02066 while ((b < p->nbox) && (p->boxes[b].LL.y > ND_coord_i(vn).y))
02067 b++;
02068 if (b >= p->nbox)
02069 break;
02070 if (p->boxes[b].UR.y < ND_coord_i(vn).y)
02071 continue;
02072 if (ND_label(vn))
02073 resize_vn(vn, p->boxes[b].LL.x, p->boxes[b].UR.x,
02074 p->boxes[b].UR.x + ND_rw_i(vn));
02075 else
02076 resize_vn(vn, p->boxes[b].LL.x, (p->boxes[b].LL.x +
02077 p->boxes[b].UR.x) / 2,
02078 p->boxes[b].UR.x);
02079 }
02080 }
02081
02082 static void resize_vn(vn, lx, cx, rx)
02083 node_t *vn;
02084 int lx, cx, rx;
02085 {
02086 ND_coord_i(vn).x = cx;
02087 ND_lw_i(vn) = cx - lx, ND_rw_i(vn) = rx - cx;
02088 }
02089
02090
02091 static edge_t *top_bound(edge_t * e, int side)
02092 {
02093 edge_t *f, *ans = NULL;
02094 int i;
02095
02096 for (i = 0; (f = ND_out(e->tail).list[i]); i++) {
02097 #if 0
02098 if (ED_tail_port(e).p.x != ED_tail_port(f).p.x)
02099 continue;
02100 #endif
02101 if (side * (ND_order(f->head) - ND_order(e->head)) <= 0)
02102 continue;
02103 if ((ED_spl(f) == NULL)
02104 && ((ED_to_orig(f) == NULL) || (ED_to_orig(f)->u.spl == NULL)))
02105 continue;
02106 if ((ans == NULL)
02107 || (side * (ND_order(ans->head) - ND_order(f->head)) > 0))
02108 ans = f;
02109 }
02110 return ans;
02111 }
02112
02113 static edge_t *bot_bound(edge_t * e, int side)
02114 {
02115 edge_t *f, *ans = NULL;
02116 int i;
02117
02118 for (i = 0; (f = ND_in(e->head).list[i]); i++) {
02119 #if 0
02120 if (ED_head_port(e).p.x != ED_head_port(f).p.x)
02121 continue;
02122 #endif
02123 if (side * (ND_order(f->tail) - ND_order(e->tail)) <= 0)
02124 continue;
02125 if ((ED_spl(f) == NULL)
02126 && ((ED_to_orig(f) == NULL) || (ED_to_orig(f)->u.spl == NULL)))
02127 continue;
02128 if ((ans == NULL)
02129 || (side * (ND_order(ans->tail) - ND_order(f->tail)) > 0))
02130 ans = f;
02131 }
02132 return ans;
02133 }
02134
02135 point closest(splines * spl, point p)
02136 {
02137 int i, j, k, besti, bestj;
02138 double bestdist2, d2, dlow2, dhigh2;
02139 double low, high, t;
02140 pointf c[4], pt2, pt;
02141 point rv;
02142 bezier bz;
02143
02144 besti = bestj = -1;
02145 bestdist2 = 1e+38;
02146 P2PF(p, pt);
02147 for (i = 0; i < spl->size; i++) {
02148 bz = spl->list[i];
02149 for (j = 0; j < bz.size; j++) {
02150 pointf b;
02151
02152 b.x = bz.list[j].x;
02153 b.y = bz.list[j].y;
02154 d2 = DIST2(b, pt);
02155 if ((bestj == -1) || (d2 < bestdist2)) {
02156 besti = i;
02157 bestj = j;
02158 bestdist2 = d2;
02159 }
02160 }
02161 }
02162
02163 bz = spl->list[besti];
02164 j = bestj / 3;
02165 if (j >= spl->size)
02166 j--;
02167 for (k = 0; k < 4; k++) {
02168 c[k].x = bz.list[j + k].x;
02169 c[k].y = bz.list[j + k].y;
02170 }
02171 low = 0.0;
02172 high = 1.0;
02173 dlow2 = DIST2(c[0], pt);
02174 dhigh2 = DIST2(c[3], pt);
02175 do {
02176 t = (low + high) / 2.0;
02177 pt2 = Bezier(c, 3, t, NULL, NULL);
02178 if (fabs(dlow2 - dhigh2) < 1.0)
02179 break;
02180 if (fabs(high - low) < .00001)
02181 break;
02182 if (dlow2 < dhigh2) {
02183 high = t;
02184 dhigh2 = DIST2(pt2, pt);
02185 } else {
02186 low = t;
02187 dlow2 = DIST2(pt2, pt);
02188 }
02189 } while (1);
02190 PF2P(pt2, rv);
02191 return rv;
02192 }
02193
02194
02195
02196 static int cl_vninside(graph_t * cl, node_t * n)
02197 {
02198 return (BETWEEN(GD_bb(cl).LL.x, ND_coord_i(n).x, GD_bb(cl).UR.x) &&
02199 BETWEEN(GD_bb(cl).LL.y, ND_coord_i(n).y, GD_bb(cl).UR.y));
02200 }
02201
02202
02203
02204 static graph_t *cl_bound(n, adj)
02205 node_t *n, *adj;
02206 {
02207 graph_t *rv, *cl, *tcl, *hcl;
02208 edge_t *orig;
02209
02210 rv = NULL;
02211 if (ND_node_type(n) == NORMAL)
02212 tcl = hcl = ND_clust(n);
02213 else {
02214 orig = ND_out(n).list[0]->u.to_orig;
02215 tcl = ND_clust(orig->tail);
02216 hcl = ND_clust(orig->head);
02217 }
02218 if (ND_node_type(adj) == NORMAL) {
02219 cl = ND_clust(adj);
02220 if (cl && (cl != tcl) && (cl != hcl))
02221 rv = cl;
02222 } else {
02223 orig = ED_to_orig(ND_out(adj).list[0]);
02224 cl = ND_clust(orig->tail);
02225 if (cl && (cl != tcl) && (cl != hcl) && cl_vninside(cl, adj))
02226 rv = cl;
02227 else {
02228 cl = ND_clust(orig->head);
02229 if (cl && (cl != tcl) && (cl != hcl) && cl_vninside(cl, adj))
02230 rv = cl;
02231 }
02232 }
02233 return rv;
02234 }
02235
02236
02237
02238
02239
02240
02241
02242
02243
02244 #define FUDGE 4
02245
02246 static box maximal_bbox(spline_info_t* sp, node_t* vn, edge_t* ie, edge_t* oe)
02247 {
02248 int nb, b;
02249 graph_t *g = vn->graph, *left_cl, *right_cl;
02250 node_t *left, *right;
02251 box rv;
02252
02253 left_cl = right_cl = NULL;
02254
02255
02256 b = ND_coord_i(vn).x - ND_lw_i(vn) - FUDGE;
02257 if ((left = neighbor(vn, ie, oe, -1))) {
02258 if ((left_cl = cl_bound(vn, left)))
02259 nb = GD_bb(left_cl).UR.x + sp->Splinesep;
02260 else {
02261 nb = ND_coord_i(left).x + ND_mval(left);
02262 if (ND_node_type(left) == NORMAL)
02263 nb += GD_nodesep(g) / 2;
02264 else
02265 nb += sp->Splinesep;
02266 }
02267 if (nb < b)
02268 b = nb;
02269 rv.LL.x = b;
02270 } else
02271 rv.LL.x = MIN(b, sp->LeftBound);
02272
02273
02274 if ((ND_node_type(vn) == VIRTUAL) && (ND_label(vn)))
02275 b = ND_coord_i(vn).x + 10;
02276 else
02277 b = ND_coord_i(vn).x + ND_rw_i(vn) + FUDGE;
02278 if ((right = neighbor(vn, ie, oe, 1))) {
02279 if ((right_cl = cl_bound(vn, right)))
02280 nb = GD_bb(right_cl).LL.x - sp->Splinesep;
02281 else {
02282 nb = ND_coord_i(right).x - ND_lw_i(right);
02283 if (ND_node_type(right) == NORMAL)
02284 nb -= GD_nodesep(g) / 2;
02285 else
02286 nb -= sp->Splinesep;
02287 }
02288 if (nb > b)
02289 b = nb;
02290 rv.UR.x = b;
02291 } else
02292 rv.UR.x = MAX(b, sp->RightBound);
02293
02294 if ((ND_node_type(vn) == VIRTUAL) && (ND_label(vn)))
02295 rv.UR.x -= ND_rw_i(vn);
02296
02297 rv.LL.y = ND_coord_i(vn).y - GD_rank(g)[ND_rank(vn)].ht1;
02298 rv.UR.y = ND_coord_i(vn).y + GD_rank(g)[ND_rank(vn)].ht2;
02299 return rv;
02300 }
02301
02302 static node_t *neighbor(vn, ie, oe, dir)
02303 node_t *vn;
02304 edge_t *ie, *oe;
02305 int dir;
02306 {
02307 int i;
02308 node_t *n, *rv = NULL;
02309 rank_t *rank = &(GD_rank(vn->graph)[ND_rank(vn)]);
02310
02311 for (i = ND_order(vn) + dir; ((i >= 0) && (i < rank->n)); i += dir) {
02312 n = rank->v[i];
02313 if ((ND_node_type(n) == VIRTUAL) && (ND_label(n))) {
02314 rv = n;
02315 break;
02316 }
02317 if (ND_node_type(n) == NORMAL) {
02318 rv = n;
02319 break;
02320 }
02321 if (pathscross(n, vn, ie, oe) == FALSE) {
02322 rv = n;
02323 break;
02324 }
02325 }
02326 return rv;
02327 }
02328
02329 static boolean pathscross(n0, n1, ie1, oe1)
02330 node_t *n0, *n1;
02331 edge_t *ie1, *oe1;
02332 {
02333 edge_t *e0, *e1;
02334 node_t *na, *nb;
02335 int order, cnt;
02336
02337 order = (ND_order(n0) > ND_order(n1));
02338 if ((ND_out(n0).size != 1) && (ND_out(n0).size != 1))
02339 return FALSE;
02340 e1 = oe1;
02341 if (ND_out(n0).size == 1 && e1) {
02342 e0 = ND_out(n0).list[0];
02343 for (cnt = 0; cnt < 2; cnt++) {
02344 if ((na = e0->head) == (nb = e1->head))
02345 break;
02346 if (order != (ND_order(na) > ND_order(nb)))
02347 return TRUE;
02348 if ((ND_out(na).size != 1) || (ND_node_type(na) == NORMAL))
02349 break;
02350 e0 = ND_out(na).list[0];
02351 if ((ND_out(nb).size != 1) || (ND_node_type(nb) == NORMAL))
02352 break;
02353 e1 = ND_out(nb).list[0];
02354 }
02355 }
02356 e1 = ie1;
02357 if (ND_in(n0).size == 1 && e1) {
02358 e0 = ND_in(n0).list[0];
02359 for (cnt = 0; cnt < 2; cnt++) {
02360 if ((na = e0->tail) == (nb = e1->tail))
02361 break;
02362 if (order != (ND_order(na) > ND_order(nb)))
02363 return TRUE;
02364 if ((ND_in(na).size != 1) || (ND_node_type(na) == NORMAL))
02365 break;
02366 e0 = ND_in(na).list[0];
02367 if ((ND_in(nb).size != 1) || (ND_node_type(nb) == NORMAL))
02368 break;
02369 e1 = ND_in(nb).list[0];
02370 }
02371 }
02372 return FALSE;
02373 }
02374
02375 #ifdef DEBUG
02376 void showpath(path * p)
02377 {
02378 int i;
02379 point LL, UR;
02380
02381 fprintf(stderr, "%%!PS\n");
02382 for (i = 0; i < p->nbox; i++) {
02383 LL = p->boxes[i].LL;
02384 UR = p->boxes[i].UR;
02385 fprintf(stderr,
02386 "newpath %d %d moveto %d %d lineto %d %d lineto %d %d lineto closepath stroke\n",
02387 LL.x, LL.y, UR.x, LL.y, UR.x, UR.y, LL.x, UR.y);
02388 }
02389 fprintf(stderr, "showpage\n");
02390 }
02391 #endif