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; }
/* routesplines: * Route a path using the path info in pp. This includes start and end points * plus a collection of contiguous boxes contain the terminal points. The boxes * are converted into a containing polygon. A shortest path is constructed within * the polygon from between the terminal points. If polyline is true, this path * is converted to a spline representation. Otherwise, we call the path planner to * convert the polyline into a smooth spline staying within the polygon. In both * cases, the function returns an array of the computed control points. The number * of these points is given in npoints. * * Note that the returned points are stored in a single array, so the points must be * used before another call to this function. * * During cleanup, the function determines the x-extent of the spline in the box, so * the box can be shrunk to the minimum width. The extra space can then be used by other * edges. * * If a catastrophic error, return NULL. */ static pointf *_routesplines(path * pp, int *npoints, int polyline) { Ppoly_t poly; Ppolyline_t pl, spl; int splinepi; Ppoint_t eps[2]; Pvector_t evs[2]; int edgei, prev, next; int pi, bi; boxf *boxes; int boxn; edge_t* realedge; int flip; int loopcnt, delta = INIT_DELTA; boolean unbounded; 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"); return NULL; } boxes = pp->boxes; boxn = pp->nbox; if (checkpath(boxn, boxes, pp)) return NULL; #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++) { double v = boxes[bi].UR.y; boxes[bi].UR.y = -1*boxes[bi].LL.y; boxes[bi].LL.y = -v; } } else flip = 0; if (agtail(realedge) != aghead(realedge)) { /* 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)) { agerr(AGERR, "in routesplines, illegal values of prev %d and next %d, line %d\n", prev, next, __LINE__); return NULL; } } } 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 */ agerr(AGERR, "in routesplines, illegal values of prev %d and next %d, line %d\n", prev, next, __LINE__); return NULL; /* for correctness sake, it's best to just stop */ } 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 { agerr(AGERR, "in routesplines, edge is a loop at %s\n", agnameof(aghead(realedge))); return NULL; } 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) < 0) { agerr(AGERR, "in routesplines, Pshortestpath failed\n"); return NULL; } #ifdef DEBUG if (debugleveln(realedge, 3)) { psprintpoly(poly); psprintline(pl); } #endif if (polyline) { make_polyline (pl, &spl); } else { 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) < 0) { agerr(AGERR, "in routesplines, Proutespline failed\n"); return NULL; } #ifdef DEBUG if (debugleveln(realedge, 3)) { psprintspline(spl); psprintinit(0); } #endif } if (mkspacep(spl.pn)) return NULL; /* Bailout if no memory left */ for (bi = 0; bi < boxn; bi++) { boxes[bi].LL.x = INT_MAX; boxes[bi].UR.x = INT_MIN; } unbounded = TRUE; for (splinepi = 0; splinepi < spl.pn; splinepi++) { ps[splinepi] = spl.ps[splinepi]; } for (loopcnt = 0; unbounded && (loopcnt < LOOP_TRIES); loopcnt++) { limitBoxes (boxes, boxn, ps, spl.pn, delta); /* The following check is necessary because if a box is not very * high, it is possible that the sampling above might miss it. * Therefore, we make the sample finer until all boxes have * valid values. cf. bug 456. Would making sp[] pointfs help? */ for (bi = 0; bi < boxn; bi++) { /* these fp equality tests are used only to detect if the * values have been changed since initialization - ok */ if ((boxes[bi].LL.x == INT_MAX) || (boxes[bi].UR.x == INT_MIN)) { delta *= 2; /* try again with a finer interval */ if (delta > INT_MAX/boxn) /* in limitBoxes, boxn*delta must fit in an int, so give up */ loopcnt = LOOP_TRIES; break; } } if (bi == boxn) unbounded = FALSE; } if (unbounded) { /* Either an extremely short, even degenerate, box, or some failure with the path * planner causing the spline to miss some boxes. In any case, use the shortest path * to bound the boxes. This will probably mean a bad edge, but we avoid an infinite * loop and we can see the bad edge, and even use the showboxes scaffolding. */ Ppolyline_t polyspl; agerr(AGWARN, "Unable to reclaim box space in spline routing for edge \"%s\" -> \"%s\". Something is probably seriously wrong.\n", agnameof(agtail(realedge)), agnameof(aghead(realedge))); make_polyline (pl, &polyspl); limitBoxes (boxes, boxn, polyspl.ps, polyspl.pn, INIT_DELTA); free (polyspl.ps); } *npoints = spl.pn; #ifdef DEBUG if (GD_showboxes(agraphof(aghead(realedge))) == 2 || GD_showboxes(agraphof(agtail(realedge))) == 2 || ED_showboxes(realedge) == 2 || ND_showboxes(aghead(realedge)) == 2 || ND_showboxes(agtail(realedge)) == 2) printboxes(boxn, boxes); #endif return ps; }
static pointf *_routesplines(path * pp, int *npoints, int polyline) { Ppoly_t poly; Ppolyline_t pl, spl; int splinepi; Ppoint_t eps[2]; Pvector_t evs[2]; int edgei, prev, next; pointf sp[4]; int pi, bi, si; double t; boxf *boxes; int boxn; edge_t* realedge; int flip; int delta = 10; 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++) { double v = boxes[bi].UR.y; boxes[bi].UR.y = -1*boxes[bi].LL.y; boxes[bi].LL.y = -v; } } else flip = 0; if (agtail(realedge) != aghead(realedge)) { /* 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 { abort(); } 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 (polyline) { make_polyline (pl, &spl); } else { 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] = spl.ps[splinepi]; } REDO: for (splinepi = 0; splinepi + 3 < spl.pn; splinepi += 3) { int num_div = delta * boxn; for (si = 0; si <= num_div; si++) { t = si / (double)num_div; 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++) { /* this tested ok on 64bit machines, but on 32bit we need this FUDGE * or graphs/directed/records.gv fails */ #define FUDGE .0001 if (sp[0].y <= boxes[bi].UR.y+FUDGE && sp[0].y >= boxes[bi].LL.y-FUDGE) { 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; } } } } /* The following check is necessary because if a box is not very * high, it is possible that the sampling above might miss it. * Therefore, we make the sample finer until all boxes have * valid values. cf. bug 456. Would making sp[] pointfs help? */ for (bi = 0; bi < boxn; bi++) { /* these fp equality tests are used only to detect if the * values have been changed since initialization - ok */ if ((boxes[bi].LL.x == INT_MAX) || (boxes[bi].UR.x == INT_MIN)) { delta *= 2; goto REDO; } } *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; }