point *routesplines(path * pp, int *npoints) { Ppoly_t poly; Ppolyline_t pl, spl; int splinepi; Ppoint_t eps[2]; Pvector_t evs[2]; int edgei, prev, next; point sp[4]; int pi, bi, si; double t; box *boxes; int boxn; edge_t* realedge; int flip; nedges++; nboxes += pp->nbox; for (realedge = (edge_t *) pp->data; #ifdef NOTNOW origedge = realedge; #endif realedge && ED_edge_type(realedge) != NORMAL; realedge = ED_to_orig(realedge)); if (!realedge) { agerr(AGERR, "in routesplines, cannot find NORMAL edge\n"); abort(); } boxes = pp->boxes; boxn = pp->nbox; checkpath(boxn, boxes, pp); #ifdef DEBUG if (debugleveln(realedge, 1)) printboxes(boxn, boxes); if (debugleveln(realedge, 3)) { psprintinit(1); psprintboxes(boxn, boxes); } #endif if (boxn * 8 > polypointn) { polypoints = ALLOC(boxn * 8, polypoints, Ppoint_t); polypointn = boxn * 8; } if ((boxn > 1) && (boxes[0].LL.y > boxes[1].LL.y)) { flip = 1; for (bi = 0; bi < boxn; bi++) { int v = boxes[bi].UR.y; boxes[bi].UR.y = -1*boxes[bi].LL.y; boxes[bi].LL.y = -v; } } else flip = 0; if (realedge->tail != realedge->head) { /* I assume that the path goes either down only or up - right - down */ for (bi = 0, pi = 0; bi < boxn; bi++) { next = prev = 0; if (bi > 0) prev = (boxes[bi].LL.y > boxes[bi - 1].LL.y) ? -1 : 1; if (bi < boxn - 1) next = (boxes[bi + 1].LL.y > boxes[bi].LL.y) ? 1 : -1; if (prev != next) { if (next == -1 || prev == 1) { polypoints[pi].x = boxes[bi].LL.x; polypoints[pi++].y = boxes[bi].UR.y; polypoints[pi].x = boxes[bi].LL.x; polypoints[pi++].y = boxes[bi].LL.y; } else { polypoints[pi].x = boxes[bi].UR.x; polypoints[pi++].y = boxes[bi].LL.y; polypoints[pi].x = boxes[bi].UR.x; polypoints[pi++].y = boxes[bi].UR.y; } } else if (prev == 0) { /* single box */ polypoints[pi].x = boxes[bi].LL.x; polypoints[pi++].y = boxes[bi].UR.y; polypoints[pi].x = boxes[bi].LL.x; polypoints[pi++].y = boxes[bi].LL.y; } else { if (!(prev == -1 && next == -1)) abort(); } } for (bi = boxn - 1; bi >= 0; bi--) { next = prev = 0; if (bi < boxn - 1) prev = (boxes[bi].LL.y > boxes[bi + 1].LL.y) ? -1 : 1; if (bi > 0) next = (boxes[bi - 1].LL.y > boxes[bi].LL.y) ? 1 : -1; if (prev != next) { if (next == -1 || prev == 1 ) { polypoints[pi].x = boxes[bi].LL.x; polypoints[pi++].y = boxes[bi].UR.y; polypoints[pi].x = boxes[bi].LL.x; polypoints[pi++].y = boxes[bi].LL.y; } else { polypoints[pi].x = boxes[bi].UR.x; polypoints[pi++].y = boxes[bi].LL.y; polypoints[pi].x = boxes[bi].UR.x; polypoints[pi++].y = boxes[bi].UR.y; } } else if (prev == 0) { /* single box */ polypoints[pi].x = boxes[bi].UR.x; polypoints[pi++].y = boxes[bi].LL.y; polypoints[pi].x = boxes[bi].UR.x; polypoints[pi++].y = boxes[bi].UR.y; } else { if (!(prev == -1 && next == -1)) { /* it went badly, e.g. degenerate box in boxlist */ *npoints = 0; abort(); /* for correctness sake, it's best to just stop */ return ps; /* could also be reported as a lost edge (no spline) */ } polypoints[pi].x = boxes[bi].UR.x; polypoints[pi++].y = boxes[bi].LL.y; polypoints[pi].x = boxes[bi].UR.x; polypoints[pi++].y = boxes[bi].UR.y; polypoints[pi].x = boxes[bi].LL.x; polypoints[pi++].y = boxes[bi].UR.y; polypoints[pi].x = boxes[bi].LL.x; polypoints[pi++].y = boxes[bi].LL.y; } } } else { #ifdef OBSOLETE /* new, more generalized approach for self-edges. We do not assume any monotonicity about the box path, only that it is simply connected. We build up the constraint poly by walking the box path from one end to the other and back in the recursive function append(). A better approach to all of this might be to dispense with the box paths altogether and just compute the constraint poly directly, but this needs to be done as part of a more thorough overhaul. */ point p0, p1; box b0, b1; b0 = pp->boxes[0]; b1 = pp->boxes[1]; /* determine 'starting' segment (side of b0) for box path search */ if (b0.UR.x == b1.LL.x) { p0 = b0.LL; p1 = mkpt(b0.LL.x, b0.UR.y); } else if (b0.LL.y == b1.UR.y) { p0 = mkpt(b0.LL.x, b0.UR.y); p1 = b0.UR; } else if (b0.LL.x == b1.UR.x) { p0 = b0.UR; p1 = mkpt(b0.UR.x, b0.LL.y); } else if (b0.UR.y == b1.LL.y) { p0 = mkpt(b0.UR.x, b0.LL.y); p1 = b0.LL; } else abort(); pi = append(pp, 0, p0, p1, 0); #else abort(); #endif } if (flip) { int i; for (bi = 0; bi < boxn; bi++) { int v = boxes[bi].UR.y; boxes[bi].UR.y = -1*boxes[bi].LL.y; boxes[bi].LL.y = -v; } for (i = 0; i < pi; i++) polypoints[i].y *= -1; } for (bi = 0; bi < boxn; bi++) boxes[bi].LL.x = INT_MAX, boxes[bi].UR.x = INT_MIN; poly.ps = polypoints, poly.pn = pi; eps[0].x = pp->start.p.x, eps[0].y = pp->start.p.y; eps[1].x = pp->end.p.x, eps[1].y = pp->end.p.y; if (Pshortestpath(&poly, eps, &pl) == -1) abort(); #ifdef DEBUG if (debugleveln(realedge, 3)) { psprintpoly(poly); psprintline(pl); } #endif if (poly.pn > edgen) { edges = ALLOC(poly.pn, edges, Pedge_t); edgen = poly.pn; } for (edgei = 0; edgei < poly.pn; edgei++) { edges[edgei].a = polypoints[edgei]; edges[edgei].b = polypoints[(edgei + 1) % poly.pn]; } if (pp->start.constrained) { evs[0].x = cos(pp->start.theta); evs[0].y = sin(pp->start.theta); } else evs[0].x = evs[0].y = 0; if (pp->end.constrained) { evs[1].x = -cos(pp->end.theta); evs[1].y = -sin(pp->end.theta); } else evs[1].x = evs[1].y = 0; if (Proutespline(edges, poly.pn, pl, evs, &spl) == -1) abort(); #ifdef DEBUG if (debugleveln(realedge, 3)) { psprintspline(spl); psprintinit(0); } #endif mkspacep(spl.pn); for (bi = 0; bi <= boxn; bi++) { boxes[bi].LL.x = INT_MAX; boxes[bi].UR.x = INT_MIN; } for (splinepi = 0; splinepi < spl.pn; splinepi++) { ps[splinepi].x = spl.ps[splinepi].x; ps[splinepi].y = spl.ps[splinepi].y; } for (splinepi = 0; splinepi + 3 < spl.pn; splinepi += 3) { for (si = 0; si <= 10 * boxn; si++) { t = si / (10.0 * boxn); sp[0] = ps[splinepi]; sp[1] = ps[splinepi + 1]; sp[2] = ps[splinepi + 2]; sp[3] = ps[splinepi + 3]; sp[0].x = sp[0].x + t * (sp[1].x - sp[0].x); sp[0].y = sp[0].y + t * (sp[1].y - sp[0].y); sp[1].x = sp[1].x + t * (sp[2].x - sp[1].x); sp[1].y = sp[1].y + t * (sp[2].y - sp[1].y); sp[2].x = sp[2].x + t * (sp[3].x - sp[2].x); sp[2].y = sp[2].y + t * (sp[3].y - sp[2].y); sp[0].x = sp[0].x + t * (sp[1].x - sp[0].x); sp[0].y = sp[0].y + t * (sp[1].y - sp[0].y); sp[1].x = sp[1].x + t * (sp[2].x - sp[1].x); sp[1].y = sp[1].y + t * (sp[2].y - sp[1].y); sp[0].x = sp[0].x + t * (sp[1].x - sp[0].x); sp[0].y = sp[0].y + t * (sp[1].y - sp[0].y); for (bi = 0; bi < boxn; bi++) { if (sp[0].y <= boxes[bi].UR.y && sp[0].y >= boxes[bi].LL.y) { if (boxes[bi].LL.x > sp[0].x) boxes[bi].LL.x = sp[0].x; if (boxes[bi].UR.x < sp[0].x) boxes[bi].UR.x = sp[0].x; } } } } *npoints = spl.pn; #ifdef DEBUG if (GD_showboxes(realedge->head->graph) == 2 || GD_showboxes(realedge->tail->graph) == 2 || ED_showboxes(realedge) == 2 || ND_showboxes(realedge->head) == 2 || ND_showboxes(realedge->tail) == 2) printboxes(boxn, boxes); #endif return ps; }
/* append: */ static int append(path * path, int bi, point p0, point p1, int polysz) { point v[8]; /* worst case 4 corners + 2 segs * 2 points each */ point w[8]; box b = path->boxes[bi]; box bb; int i, i0, npw, delta; point q0 = { 0, 0 }, q1 = { 0, 0}, r; int pn; /* v = 4 corners of b, p0 and p1 */ pn = 0; v[pn++] = b.LL; v[pn++] = mkpt(b.UR.x, b.LL.y); v[pn++] = b.UR; v[pn++] = mkpt(b.LL.x, b.UR.y); v[pn++] = p0; v[pn++] = p1; if (bi + 1 < path->nbox) { bb = path->boxes[bi + 1]; /* determine points q0,q1 where b and bb touch and append to v */ if (b.UR.x == bb.LL.x) { q0.x = q1.x = b.UR.x; q0.y = MIN(b.UR.y, bb.UR.y); q1.y = MAX(b.LL.y, bb.LL.y); } else if (b.LL.x == bb.UR.x) { q0.x = q1.x = b.LL.x; q0.y = MIN(b.UR.y, bb.UR.y); q1.y = MAX(b.LL.y, bb.LL.y); } else if (b.UR.y == bb.LL.y) { q0.y = q1.y = b.UR.y; q0.x = MIN(b.UR.x, bb.UR.x); q1.x = MAX(b.LL.x, bb.LL.x); } else if (b.LL.y == bb.UR.y) { q0.y = q1.y = b.LL.y; q0.x = MIN(b.UR.x, bb.UR.x); q1.x = MAX(b.LL.x, bb.LL.x); } else abort(); v[pn++] = q0; v[pn++] = q1; } /* sort v so that the cyclic order is p0, all other points, p1 */ B = b; qsort(v, pn, sizeof(v[0]), cmpf); /* eliminate duplicates and record i0 = index of p0 in w */ w[0] = v[0]; npw = 1; i0 = -1; for (i = 0; i < pn; i++) { if (pteq(w[npw - 1], p0)) i0 = npw - 1; if (!pteq(v[i], w[npw - 1])) w[npw++] = v[i]; } i = i0; if (bi == 0) polysz = appendpt(p0, polysz); if (pteq(p1, w[(i0 + 1) % npw])) delta = -1; else if (pteq(p1, w[(i0 - 1 + npw) % npw])) delta = 1; else abort(); do { i = (i + delta + npw) % npw; /* go to the next point in order */ r = w[i]; /* call it r */ /* append r to current poly, except p0 and p1 are special cases */ if ((bi == 0) || (!pteq(r, p0) && !pteq(r, p1))) polysz = appendpt(r, polysz); if (pteq(r, p1)) break; if (bi + 1 < path->nbox) { /* recur when we hit the next box */ if (pteq(r, q0)) { polysz = append(path, bi + 1, q0, q1, polysz); polysz = appendpt(q1, polysz); /* assumes q1 != p0 and p1 */ i += delta; /* skip q1 */ } else if (pteq(r, q1)) { polysz = append(path, bi + 1, q1, q0, polysz); polysz = appendpt(q0, polysz); i += delta; } } } while (i != i0); return polysz; }
point *routesplines (path* pp, int* npoints) { Ppoly_t poly; Ppolyline_t pl, spl; int splinepi; Ppoint_t eps[2]; Pvector_t evs[2]; int edgei, prev, next; point sp[4]; int pi, bi, si; double t; nedges++; nboxes += pp->nbox; for (realedge = origedge = (edge_t *) pp->data; realedge && realedge->u.edge_type != NORMAL; realedge = realedge->u.to_orig) ; if (!realedge) { fprintf (stderr, "in routesplines, cannot find NORMAL edge\n"); abort (); } thepath = pp; boxes = pp->boxes; boxn = pp->nbox; checkpath (); if (realedge->head->graph->u.showboxes == 1 || realedge->tail->graph->u.showboxes == 1 || realedge->u.showboxes == 1 || realedge->head->u.showboxes == 1|| realedge->tail->u.showboxes == 1) printpsboxes (); if (boxn * 8 > polypointn) { if (!polypoints) { if (!(polypoints = (Ppoint_t *)malloc (sizeof (Ppoint_t) * boxn * 8))) abort (); } else { if (!(polypoints = (Ppoint_t *)realloc (polypoints, sizeof (Ppoint_t) * boxn * 8))) abort (); } polypointn = pp->nbox * 8; } if (realedge->tail != realedge->head) { /* I assume that the path goes either down only or up - right - down */ for (bi = 0, pi = 0; bi < boxn; bi++) { next = prev = 0; if (bi > 0) prev = (boxes[bi].LL.y > boxes[bi - 1].LL.y) ? -1 : 1; if (bi < boxn - 1) next = (boxes[bi + 1].LL.y > boxes[bi].LL.y) ? 1 : -1; if (prev != next) { if (next == -1 || prev == 1) { polypoints[pi].x = boxes[bi].LL.x; polypoints[pi++].y = boxes[bi].UR.y; polypoints[pi].x = boxes[bi].LL.x; polypoints[pi++].y = boxes[bi].LL.y; } else { polypoints[pi].x = boxes[bi].UR.x; polypoints[pi++].y = boxes[bi].LL.y; polypoints[pi].x = boxes[bi].UR.x; polypoints[pi++].y = boxes[bi].UR.y; } } else { if (!(prev == -1 && next == -1)) abort (); } } for (bi = boxn - 1; bi >= 0; bi--) { next = prev = 0; if (bi < boxn - 1) prev = (boxes[bi].LL.y > boxes[bi + 1].LL.y) ? -1 : 1; if (bi > 0) next = (boxes[bi - 1].LL.y > boxes[bi].LL.y) ? 1 : -1; if (prev != next) { if (next == -1 || prev == 1) { polypoints[pi].x = boxes[bi].LL.x; polypoints[pi++].y = boxes[bi].UR.y; polypoints[pi].x = boxes[bi].LL.x; polypoints[pi++].y = boxes[bi].LL.y; } else { polypoints[pi].x = boxes[bi].UR.x; polypoints[pi++].y = boxes[bi].LL.y; polypoints[pi].x = boxes[bi].UR.x; polypoints[pi++].y = boxes[bi].UR.y; } } else { if (!(prev == -1 && next == -1)) abort (); polypoints[pi].x = boxes[bi].UR.x; polypoints[pi++].y = boxes[bi].LL.y; polypoints[pi].x = boxes[bi].UR.x; polypoints[pi++].y = boxes[bi].UR.y; polypoints[pi].x = boxes[bi].LL.x; polypoints[pi++].y = boxes[bi].UR.y; polypoints[pi].x = boxes[bi].LL.x; polypoints[pi++].y = boxes[bi].LL.y; } } } else { /* new, more generalized approach for self-edges. We do not assume any monotonicity about the box path, only that it is simply connected. We build up the constraint poly by walking the box path from one end to the other and back in the recursive function append(). A better approach to all of this might be to dispense with the box paths altogether and just compute the constraint poly directly, but this needs to be done as part of a more thorough overhaul. */ point p0, p1; box b0,b1; b0 = pp->boxes[0]; b1 = pp->boxes[1]; /* determine 'starting' segment (side of b0) for box path search */ if (b0.UR.x == b1.LL.x) {p0 = b0.LL; p1 = mkpt(b0.LL.x,b0.UR.y);} else if (b0.LL.y == b1.UR.y) {p0 = mkpt(b0.LL.x,b0.UR.y); p1 = b0.UR;} else if (b0.LL.x == b1.UR.x) {p0 = b0.UR; p1 = mkpt(b0.UR.x,b0.LL.y);} else if (b0.UR.y == b1.LL.y) {p0 = mkpt(b0.UR.x,b0.LL.y); p1 = b0.LL;} else abort(); polysz = 0; append(pp,0,p0,p1); pi = polysz; } for (bi = 0; bi < boxn; bi++) boxes[bi].LL.x = INT_MAX, boxes[bi].UR.x = INT_MIN; poly.ps = polypoints, poly.pn = pi; eps[0].x = pp->start.p.x, eps[0].y = pp->start.p.y; eps[1].x = pp->end.p.x, eps[1].y = pp->end.p.y; if (Pshortestpath (&poly, eps, &pl) == -1) abort (); if (poly.pn > edgen) { if (!edges) { if (!(edges = (Pedge_t *)malloc (sizeof (Pedge_t) * poly.pn))) abort (); } else { if (!(edges = (Pedge_t *)realloc (edges, sizeof (Pedge_t) * poly.pn))) abort (); } edgen = poly.pn; } for (edgei = 0; edgei < poly.pn; edgei++) { edges[edgei].a = polypoints[edgei]; edges[edgei].b = polypoints[(edgei + 1) % poly.pn]; } if (pp->start.constrained) { evs[0].x = cos (pp->start.theta); evs[0].y = sin (pp->start.theta); } else evs[0].x = evs[0].y = 0; if (pp->end.constrained) { evs[1].x = -cos (pp->end.theta); evs[1].y = -sin (pp->end.theta); } else evs[1].x = evs[1].y = 0; if (Proutespline (edges, poly.pn, pl, evs, &spl) == -1) abort (); mkspacep (spl.pn); for (bi = 0; bi <= boxn; bi++) boxes[bi].LL.x = minbbox.LL.x, boxes[bi].UR.x = minbbox.UR.x; for (splinepi = 0; splinepi < spl.pn; splinepi++) { ps[splinepi].x = (int)spl.ps[splinepi].x; ps[splinepi].y = (int)spl.ps[splinepi].y; } for (splinepi = 0; splinepi < spl.pn; splinepi += 3) { for (si = 0; si <= 10 * boxn; si++) { t = si / (10.0 * boxn); sp[0] = ps[splinepi]; sp[1] = ps[splinepi + 1]; sp[2] = ps[splinepi + 2]; sp[3] = ps[splinepi + 3]; sp[0].x = (int)(sp[0].x + t * (sp[1].x - sp[0].x)); sp[0].y = (int)(sp[0].y + t * (sp[1].y - sp[0].y)); sp[1].x = (int)(sp[1].x + t * (sp[2].x - sp[1].x)); sp[1].y = (int)(sp[1].y + t * (sp[2].y - sp[1].y)); sp[2].x = (int)(sp[2].x + t * (sp[3].x - sp[2].x)); sp[2].y = (int)(sp[2].y + t * (sp[3].y - sp[2].y)); sp[0].x = (int)(sp[0].x + t * (sp[1].x - sp[0].x)); sp[0].y = (int)(sp[0].y + t * (sp[1].y - sp[0].y)); sp[1].x = (int)(sp[1].x + t * (sp[2].x - sp[1].x)); sp[1].y = (int)(sp[1].y + t * (sp[2].y - sp[1].y)); sp[0].x = (int)(sp[0].x + t * (sp[1].x - sp[0].x)); sp[0].y = (int)(sp[0].y + t * (sp[1].y - sp[0].y)); for (bi = 0; bi < boxn; bi++) { if (sp[0].y <= boxes[bi].UR.y && sp[0].y >= boxes[bi].LL.y) { if (boxes[bi].LL.x > sp[0].x) boxes[bi].LL.x = sp[0].x; if (boxes[bi].UR.x < sp[0].x) boxes[bi].UR.x = sp[0].x; } } } } *npoints = spl.pn; if (realedge->head->graph->u.showboxes == 2 || realedge->tail->graph->u.showboxes == 2 || realedge->u.showboxes == 2 || realedge->head->u.showboxes == 2|| realedge->tail->u.showboxes == 2) printpsboxes (); return ps; }