9
* return polygon for a given route
12
#ifndef DONOTDEBUGANYMORE
13
void printregion( Ppoly_t *region)
17
fprintf(stderr,"%%!PS\nnewpath\n");
18
fprintf(stderr,"100 100 translate .5 .5 scale\n");
19
for (i = 0; i < region->pn; i++)
20
fprintf(stderr,"%lf %lf %s\n",region->ps[i].x,region->ps[i].y,
21
(i ==0? "moveto" : "lineto"));
22
fprintf(stderr,"closepath stroke showpage\n");
26
typedef struct tmproute_s {
27
ilcurve_t bound[2]; /* left and right sides of region */
33
static ilcoord_t c(double x, double y) {ilcoord_t rv; rv.x = x; rv.y = y; return rv;}
35
static ilcurve_t *get_unclipped_curve(Agedge_t *e)
37
return dd_path(e)->unclipped_path;
40
static Ppoly_t *allocpoly(Agraph_t *g, int npts)
44
rv = agalloc(g,sizeof(Ppoly_t));
45
rv->ps = agalloc(g,sizeof(Ppoint_t)*npts);
49
static void freepoly(Agraph_t *g, Ppoly_t *poly)
55
/* get the spacing box below rank r */
56
static double y_below(ddview_t *view, int r, double fract) /* from top */
61
rd = dd_rankd(view,r);
62
val = rd->y_base + rd->delta_below + fract * rd->space_below;
66
static ilbool local_crossing(Agnode_t *v, Agnode_t *w)
68
int vw_order,vvww_order,i,pass,pathlen;
70
Agedge_t *(*f)(Agnode_t *);
73
vw_order = dd_order(w) - dd_order(v);
76
for (pass = 0; pass < 2; pass++) {
77
f = (pass == 0? agfstin: agfstout);
78
for (i = 0; i < pathlen; i++) {
79
if (NOT(dd_is_a_vnode(vv))) break;
80
if (NOT(dd_is_a_vnode(ww))) break;
83
vvww_order = dd_order(ww) - dd_order(vv);
84
if (vw_order * vvww_order < 0) return TRUE;
90
static Agnode_t *bounding_node(ddview_t *view, Agnode_t *inp, int dir)
95
while ((w = dd_relnode(view,v,dir))) {
96
if (NOT(dd_is_a_vnode(w))) break;
97
/* just did this for testing */
99
if (NOT(local_crossing(v,w))) break;
105
static double dd_bound(ddview_t *view, Agnode_t *u, int side)
111
assert(BASE(view)->bb.valid);
112
sep = il_nodesep(BASE(view)).x/2.0;
115
if ((w = bounding_node(view,u,1)))
116
rv = dd_pos(w).x - dd_nodesize(view,w).x/2.0 - sep;
117
else rv = BASE(view)->bb.size.ur.x;
120
if ((w = bounding_node(view,u,-1)))
121
rv = dd_pos(w).x + dd_nodesize(view,w).x/2.0 + sep;
122
else rv = BASE(view)->bb.size.ll.x;
131
static void append_vnode(tmproute_t *route, ddview_t *view, Agnode_t *virt);
133
static void append_curve(tmproute_t *, int side, ilcurve_t *curve, double y0, double y1);
135
static void append_side(tmproute_t *, int side, double x, double y0, double y1);
136
static void append_point(tmproute_t *, int side, double x, double y);
137
static void append_box(tmproute_t *rp, ddview_t *view, int toprank, double f0, double f1);
138
static Agedge_t *neighboring_edge(ddview_t *view, Agnode_t *n, Agedge_t *e, int side);
139
static void term_route(tmproute_t *rv, ddview_t *view, Agnode_t *n,
140
Agedge_t *e, ilcoord_t port, double fract);
141
static Ppoly_t *define_boundary_poly(Agraph_t *g, tmproute_t *tmp);
143
static tmproute_t *tmproute(Agraph_t *g, int npts)
148
rv = agalloc(g,sizeof(tmproute_t));
149
for (i = 0; i < 2; i++) {
151
rv->bound[i].p = agalloc(g,npts * sizeof(ilcoord_t));
156
static void term_route(tmproute_t *rv, ddview_t *view, Agnode_t *n, Agedge_t *e, ilcoord_t port, double fract)
160
double leftx_port, leftx_cept, rightx_port, rightx_cept;
165
if (n == agtail(e)) {rb = r; e = AGMKOUT(e);}
166
else {rb = r - 1; e = AGMKIN(e);}
168
y_cept = y_below(view,rb,fract);
170
if ((ne = neighboring_edge(view,n,e,LEFT)) && (curve = get_unclipped_curve(ne))) {
171
leftx_port = il_intersect_at_y(curve,port.y).x;
172
leftx_cept = il_intersect_at_y(curve,y_cept).x;
175
leftx_port = leftx_cept = dd_bound(view,n,LEFT);
178
if ((ne = neighboring_edge(view,n,e,RIGHT)) && (curve = get_unclipped_curve(ne))) {
179
rightx_port = il_intersect_at_y(curve,port.y).x;
180
rightx_cept = il_intersect_at_y(curve,y_cept).x;
183
rightx_port = rightx_cept = dd_bound(view,n,RIGHT);
186
if (leftx_port > rightx_port)
187
{double t = leftx_port; leftx_port = rightx_port; rightx_port = t;}
189
if (leftx_cept > rightx_cept)
190
{double t = leftx_cept; leftx_cept = rightx_cept; rightx_cept = t;}
192
if (port.y < y_cept) {
193
append_point(rv, LEFT, leftx_port, port.y);
194
append_point(rv, LEFT, leftx_cept, y_cept);
195
append_point(rv, RIGHT, rightx_port, port.y);
196
append_point(rv, RIGHT, rightx_cept, y_cept);
199
append_point(rv, LEFT, leftx_cept, y_cept);
200
append_point(rv, LEFT, leftx_port, port.y);
201
append_point(rv, RIGHT, rightx_cept, y_cept);
202
append_point(rv, RIGHT, rightx_port, port.y);
206
static Agedge_t *neighboring_edge(ddview_t *view, Agnode_t *n, Agedge_t *e, int side)
209
#ifdef NEIGHBORING_EDGE
210
int delta,delta0, dir;
213
if (AGTYPE(e) == AGINEDGE) f = agfstin(aghead(e));
214
else f = agfstout(agtail(e));
217
#ifdef NEIGHBORING_EDGE
218
if (side == LEFT) dir = -1; else dir = 1;
222
if (dd_espec(f)->pos) {
223
delta = dd_order(f->node) - dd_order(e->node);
224
if (delta * dir > 0) {
226
if ((rv == NILedge) || (delta < delta0)) {
233
if (AGTYPE(e) == AGINEDGE) f = agnxtin(f);
234
else f = agnxtout(f);
241
static void append_curve(tmproute_t *rp, int side, ilcurve_t *curve, double y0, double y1)
245
if (y0 > y1) {double temp = y0; y0 = y1; y1 = temp;}
246
i = rp->bound[side].n;
247
rp->bound[side].n += 2;
248
rp->bound[side].p[i++] = il_intersect_at_y(curve,y0);
249
rp->bound[side].p[i++] = il_intersect_at_y(curve,y1);
253
static void add_extrema(tmproute_t *rp, ddview_t *view, double y)
256
i = rp->bound[LEFT].n++;
257
rp->bound[LEFT].p[i] = c(BASE(view)->bb.size.ll.x,y);
258
i = rp->bound[RIGHT].n++;
259
rp->bound[RIGHT].p[i] = c(BASE(view)->bb.size.ur.x,y);
262
static void append_box(tmproute_t *rp, ddview_t *view, int toprank, double f0, double f1)
266
y = y_below(view, toprank, f0);
267
add_extrema(rp,view,y);
268
y = y_below(view, toprank, f1);
269
add_extrema(rp,view,y);
272
static void append_side(tmproute_t *rp, int side, double x, double arg_y0, double arg_y1)
277
if (arg_y0 < arg_y1) {y0 = arg_y0; y1 = arg_y1;}
278
else {y0 = arg_y1; y1 = arg_y0;}
279
i = rp->bound[side].n;
280
rp->bound[side].n += 2;
281
rp->bound[side].p[i++] = c(x,y0);
282
rp->bound[side].p[i++] = c(x,y1);
285
static void append_point(tmproute_t *rp, int side, double x, double y)
289
i = rp->bound[side].n++;
290
rp->bound[side].p[i].x = x;
291
rp->bound[side].p[i].y = y;
294
/* this appends the part of the path needed to route through a vnode box */
295
static void append_vnode(tmproute_t *route, ddview_t *view, Agnode_t *virt)
298
double top_y, bot_y, left_x, right_x;
301
top_y = y_below(view,r-1,1.0);
302
bot_y = y_below(view,r,0.0);
303
left_x = dd_bound(view, virt, LEFT);
304
right_x = dd_bound(view, virt, RIGHT);
305
assert(left_x < right_x);
306
append_side(route,LEFT,left_x,top_y, bot_y);
307
append_side(route,RIGHT,right_x,top_y, bot_y);
310
static Ppoint_t pppoint(double x, double y)
311
{Ppoint_t rv; rv.x = x; rv.y = y; return rv;}
313
static Ppoint_t cvtpt(ilcoord_t p)
314
{Ppoint_t rv; rv.x = (double)p.x; rv.y = (double)p.y; return rv;}
316
static ilcoord_t uncvtpt(Ppoint_t p)
317
{ilcoord_t rv; rv.x = p.x; rv.y = p.y; return rv;}
319
static ilcoord_t addpt(ilcoord_t p, ilcoord_t q)
320
{ilcoord_t rv; rv.x = p.x + q.x; rv.y = p.y + q.y; return rv;}
322
static ilbool pt_eq(Ppoint_t p, Ppoint_t q)
324
return ((p.x == q.x) && (p.y == q.y));
327
/* destructive conversion */
328
static Ppoly_t *define_boundary_poly(Agraph_t *g, tmproute_t *tmp)
333
max_npts = tmp->bound[0].n + tmp->bound[1].n;
334
rv = allocpoly(g,max_npts);
336
for (i = 0; i < tmp->bound[0].n; i++)
337
if ((j == 0) || !pt_eq(rv->ps[j-1],cvtpt(tmp->bound[0].p[i])))
338
rv->ps[j++] = cvtpt(tmp->bound[0].p[i]);
339
for (i = tmp->bound[1].n - 1; i >= 0; i--)
340
if ((j == 0) || !pt_eq(rv->ps[j-1],cvtpt(tmp->bound[1].p[i])))
341
rv->ps[j++] = cvtpt(tmp->bound[1].p[i]);
343
agfree(g,tmp->bound[0].p);
344
agfree(g,tmp->bound[1].p);
349
Ppoly_t *dd_forward_edge_region(ddview_t *view, Agnode_t *tl, Agnode_t *hd,Agedge_t **inp, ilcoord_t tp, ilcoord_t hp)
357
/* 2 points for each vnode side, 2 points for each inter-rank box side,
358
plus 5 for head and 5 for tail termination */
359
route = tmproute(view->layout, (dd_rank(hd) - r)*4 + 10);
362
term_route(route,view,tl,inp[0],tp,prev_fract);
364
for (i = 0; inp[i+1]; i++) {
365
append_box(route,view,r++,prev_fract,1.0);
366
append_vnode(route,view,inp[i]->node);
370
append_box(route,view,r++,prev_fract,.7);
371
term_route(route,view,hd,inp[i],hp,.7);
373
rv = define_boundary_poly(view->layout,route);
377
Ppoly_t *dd_flat_edge_region(ddview_t *view, Agnode_t *tl, Agnode_t *hd, ilcoord_t tp, ilcoord_t hp)
379
int i, ix, n_obstacles;
380
double xleft, xright, y;
381
Agnode_t *left, *right, *obstacle;
382
ilcoord_t lp,rp,size;
386
if (dd_order(tl) < dd_order(hd)) {left = tl; right = hd; lp = tp; rp = hp;}
387
else {left = hd; right = tl; lp = hp; rp = tp;}
388
n_obstacles = dd_order(right) - dd_order(left) - 1;
389
rv = allocpoly(view->layout,4 + n_obstacles * 2);
390
rd = dd_rankd(view,dd_rank(tl));
392
/* walk along bottom */
394
if (n_obstacles == 0) {
395
y = rd->y_base + rd->delta_below;
396
rv->ps[ix++] = pppoint(lp.x,y);
397
rv->ps[ix++] = pppoint(rp.x,y);
400
rv->ps[ix++] = cvtpt(lp);
402
for (i = 0; i < n_obstacles; i++) {
403
obstacle = dd_right(view,obstacle);
404
size = dd_nodesize(view,obstacle);
405
y = rd->y_base - size.y / 2.0;
406
xleft = dd_pos(obstacle).x - size.x / 2.0;
407
xright = xleft + size.x;
408
rv->ps[ix++] = pppoint(xleft,y);
409
rv->ps[ix++] = pppoint(xright,y);
411
rv->ps[ix++] = cvtpt(rp);
415
y = rd->y_base - rd->delta_above - dd_ranksep(view) / 2.0; ;
416
rv->ps[ix++] = pppoint(rp.x,y);
417
rv->ps[ix++] = pppoint(lp.x,y);
422
static void get_vnode_path(ddview_t *view, Agedge_t *view_edge, Agedge_t **result)
428
e = dd_first_elt(view_edge);
429
f = dd_last_elt(view_edge);
433
e = agfstout(e->node);
435
result[i++] = NILedge;
438
static void adjust_vpath(ddview_t *view, Agedge_t **vpath, ilcurve_t *curve)
444
double lb,rb,halfwidth,least_move;
446
for (i = 0; (e = vpath[i]); i++) {
448
if (dd_is_a_vnode(vnode)) {
449
Agnode_t *left = dd_left(view, vnode);
450
Agnode_t *right = dd_right(view, vnode);
453
x = il_intersect_at_y(curve, y).x;
454
halfwidth = dd_nodesize(view,vnode).x / 2.0;
455
lb = dd_bound(view,vnode,LEFT) + halfwidth;
457
rb = dd_bound(view,vnode,RIGHT) - halfwidth;
460
/* don't move if it's too small */
461
least_move = BASE(view)->client->separation.x;
462
if ((x < rb) && (x > lb) && fabs(x - dd_pos(vnode).x) >= least_move)
464
/* it's possible that local_crossing() swaps vnode order */
465
while ((left = dd_left(view, vnode))) {
466
/* for testing - should never happen right now! */
467
if (dd_pos(left).x > x){
468
abort();dd_exchange(view,left,vnode);
472
while ((right = dd_right(view, vnode))) {
473
if (dd_pos(right).x < x){abort();dd_exchange(view,right,vnode);}
480
static void set_actual_x(ddview_t *view, ddpath_t *path)
487
curve = &(path->base.client->pos->def.curve);
488
for (ve = path->first; dd_is_a_vnode(ve->node); ve = ve->node->out) {
489
vn = ve->node; nd = dd_node(vn);
490
nd->actual_x = il_intersect_at_y(curve,nd->cur.pos.y).x;
491
nd->actual_x_valid = TRUE;
495
void dd_make_edge_spline(ddview_t *view, ddpath_t *path)
499
Agedge_t *view_edge, **vpath;
501
ilcoord_t tailpt, headpt;
502
ilcurve_t *unclipped,*clipped;
505
Ppoint_t endpoints[2];
506
Pvector_t endslopes[2];
507
Ppolyline_t polyline_route, spline_route;
512
assert(path->unclipped_path == NILcurve);
514
layout = view->layout;
515
tl = dd_rep(agtail(path->model));
516
hd = dd_rep(aghead(path->model));
518
reversed = (dd_rank(tl) > dd_rank(hd));
519
if (reversed) {Agnode_t *temp; temp = tl; tl = hd; hd = temp;}
520
tailpt = addpt(path->base.client->tail.port,dd_pos(tl));
521
headpt = addpt(path->base.client->head.port,dd_pos(hd));
523
if (tl == hd) { /* self arc */
527
sep = view->base.client->separation;
528
unclipped = il_newcurve(agheap(layout),IL_SPLINE,100);
529
farpt.x = dd_pos(tl).x + dd_nodesize(view,tl).x / 2.0 + 2.0 * sep.x;
530
rb = dd_bound(view, tl, RIGHT);
531
if (dd_right(view,tl) == NILnode) rb += 2.0 * sep.x; /* ok to grow */
532
if (farpt.x > rb) farpt.x = rb;
533
farpt.y = (tailpt.y + headpt.y) / 2.0;
534
unclipped->p[0] = tailpt;
535
unclipped->p[1] = ilcoord(tailpt.x,tailpt.y + sep.y / 2.0);
536
unclipped->p[2] = ilcoord(farpt.x,farpt.y + sep.y / 2.0);
537
unclipped->p[3] = farpt;
538
unclipped->p[4] = ilcoord(farpt.x,farpt.y - sep.y / 2.0);
539
unclipped->p[5] = ilcoord(headpt.x,headpt.y - sep.y / 2.0);
540
unclipped->p[6] = headpt;
542
vpath = NIL(Agedge_t**);
546
if (dd_rank(tl) == dd_rank(hd)) {
547
region = dd_flat_edge_region(view,tl,hd,tailpt,headpt);
548
vpath = NIL(Agedge_t**);
551
view_edge = path->first;
552
vpath = agalloc(layout,sizeof(Agedge_t*)*(view->config->high - view->config->low + 2));
553
get_vnode_path(view, view_edge, vpath);
554
dd_check_vnode_path(view, vpath);
555
region = dd_forward_edge_region(view,tl,hd,vpath,tailpt,headpt);
558
endpoints[0] = cvtpt(tailpt);
559
endpoints[1] = cvtpt(headpt);
560
endslopes[0].x = endslopes[0].y = 0.0;
561
endslopes[1].x = endslopes[1].y = 0.0;
562
Pshortestpath(region, endpoints, &polyline_route);
565
Ppolybarriers(polys, 1, &barriers, &n_barriers);
567
assert(!Proutespline (barriers, n_barriers, polyline_route,
568
endslopes, &spline_route));
571
unclipped = il_newcurve(agheap(layout),IL_SPLINE,spline_route.pn);
572
for (i = 0; i < spline_route.pn; i++)
573
unclipped->p[i] = uncvtpt(spline_route.ps[i]);
574
unclipped->n = spline_route.pn;
576
freepoly(layout,region);
578
/* do not free these because they are reused by path/shortest.c */
579
/* free(polyline_route.ps); free(spline_route.ps); */
581
path->unclipped_path = unclipped;
582
clipped = il_clip_endpoints(BASE(view),unclipped, dd_nspec(tl), dd_nspec(hd));
584
for (i = 0; i < clipped->n / 2; i++) {
585
ilcoord_t t = clipped->p[i];
586
clipped->p[i] = clipped->p[clipped->n - i - 1];
587
clipped->p[clipped->n - i - 1] = t;
590
il_freeshape(agheap(DDmodel(BASE(view)->client)),path->base.client->pos);
591
path->base.client->pos =
592
il_newshape(agheap(DDmodel(BASE(view)->client)),clipped,NILshape);
594
adjust_vpath(view, vpath, unclipped);
595
agfree(layout,vpath);
596
set_actual_x(view, path);