/* simpleSplineRoute:
 * Given a simple (ccw) polygon, route an edge from tp to hp.
 */
pointf*
simpleSplineRoute (pointf tp, pointf hp, Ppoly_t poly, int* n_spl_pts,
    int polyline)
{
    Ppolyline_t pl, spl;
    Ppoint_t eps[2];
    Pvector_t evs[2];
    int i;

    eps[0].x = tp.x;
    eps[0].y = tp.y;
    eps[1].x = hp.x;
    eps[1].y = hp.y;
    if (Pshortestpath(&poly, eps, &pl) < 0)
        return NULL;

    if (polyline)
	make_polyline (pl, &spl);
    else {
	if (poly.pn > edgen) {
	    edges = ALLOC(poly.pn, edges, Pedge_t);
	    edgen = poly.pn;
	}
	for (i = 0; i < poly.pn; i++) {
	    edges[i].a = poly.ps[i];
	    edges[i].b = poly.ps[(i + 1) % poly.pn];
	}
#if 0
	if (pp->start.constrained) {
	    evs[0].x = cos(pp->start.theta);
	    evs[0].y = sin(pp->start.theta);
	} else
#endif
	    evs[0].x = evs[0].y = 0;
#if 0
	if (pp->end.constrained) {
	    evs[1].x = -cos(pp->end.theta);
	    evs[1].y = -sin(pp->end.theta);
	} else
#endif
	    evs[1].x = evs[1].y = 0;
	if (Proutespline(edges, poly.pn, pl, evs, &spl) < 0)
            return NULL;
    }

    if (mkspacep(spl.pn))
	return NULL;
    for (i = 0; i < spl.pn; i++) {
        ps[i] = spl.ps[i];
    }
    *n_spl_pts = spl.pn;
    return ps;
}
예제 #2
0
/* makeSpline:
 * Construct a spline connecting the endpoints of e, avoiding the npoly
 * obstacles obs.
 * The resultant spline is attached to the edge, the positions of any 
 * edge labels are computed, and the graph's bounding box is recomputed.
 * 
 * If chkPts is true, the function checks if one or both of the endpoints 
 * is on or inside one of the obstacles and, if so, tells the shortest path
 * computation to ignore them. 
 */
void makeSpline(graph_t* g, edge_t * e, Ppoly_t ** obs, int npoly, boolean chkPts)
{
    Ppolyline_t line, spline;
    Pvector_t slopes[2];
    int i, n_barriers;
    int pp, qp;
    Ppoint_t p, q;
    Pedge_t *barriers;

    line = ED_path(e);
    p = line.ps[0];
    q = line.ps[line.pn - 1];
    /* determine the polygons (if any) that contain the endpoints */
    pp = qp = POLYID_NONE;
    if (chkPts)
	for (i = 0; i < npoly; i++) {
	    if ((pp == POLYID_NONE) && in_poly(*obs[i], p))
		pp = i;
	    if ((qp == POLYID_NONE) && in_poly(*obs[i], q))
		qp = i;
	}

    make_barriers(obs, npoly, pp, qp, &barriers, &n_barriers);
    slopes[0].x = slopes[0].y = 0.0;
    slopes[1].x = slopes[1].y = 0.0;
    if (Proutespline(barriers, n_barriers, line, slopes, &spline) < 0) {
	agerr (AGERR, "makeSpline: failed to make spline edge (%s,%s)\n", agnameof(agtail(e)), agnameof(aghead(e)));
	return;
    }

    /* north why did you ever use int coords */
    if (Verbose > 1)
	fprintf(stderr, "spline %s %s\n", agnameof(agtail(e)), agnameof(aghead(e)));
    clip_and_install(e, aghead(e), spline.ps, spline.pn, &sinfo);
    free(barriers);
    addEdgeLabels(g, e, p, q);
}
/* 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;
}
예제 #4
0
파일: routespl.c 프로젝트: Chaduke/bah.mod
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;
}
예제 #5
0
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;
}
예제 #6
0
/* genroute:
 * Generate splines for e and cohorts.
 * Edges go from s to t.
 * Return 0 on success.
 */
static int 
genroute(graph_t* g, tripoly_t * trip, int s, int t, edge_t * e, int doPolyline)
{
    pointf eps[2];
    Pvector_t evs[2];
    pointf **cpts;		/* lists of control points */
    Ppoly_t poly;
    Ppolyline_t pl, spl;
    int i, j;
    Ppolyline_t mmpl;
    Pedge_t *medges = N_GNEW(trip->poly.pn, Pedge_t);
    int pn;
    int mult = ED_count(e);
    node_t* head = aghead(e);

    eps[0].x = trip->poly.ps[s].x, eps[0].y = trip->poly.ps[s].y;
    eps[1].x = trip->poly.ps[t].x, eps[1].y = trip->poly.ps[t].y;
    Pshortestpath(&(trip->poly), eps, &pl);

    if (pl.pn == 2) {
	makeStraightEdge(agraphof(head), e, doPolyline);
	return 0;
    }

    evs[0].x = evs[0].y = 0;
    evs[1].x = evs[1].y = 0;

    if ((mult == 1) || Concentrate) {
	poly = trip->poly;
	for (j = 0; j < poly.pn; j++) {
	    medges[j].a = poly.ps[j];
	    medges[j].b = poly.ps[(j + 1) % poly.pn];
	}
	tweakPath (poly, s, t, pl);
	Proutespline(medges, poly.pn, pl, evs, &spl);
	finishEdge (g, e, spl, aghead(e) != head, eps[0], eps[1]);
	free(medges);

	return 0;
    }
    
    pn = 2 * (pl.pn - 1);

    cpts = N_NEW(pl.pn - 2, pointf *);
    for (i = 0; i < pl.pn - 2; i++) {
	cpts[i] =
	    mkCtrlPts(t, mult+1, pl.ps[i], pl.ps[i + 1], pl.ps[i + 2], trip);
	if (!cpts[i]) {
	    agerr(AGWARN, "Could not create control points for multiple spline for edge (%s,%s)\n", agnameof(agtail(e)), agnameof(aghead(e)));
	    return 1;
	}
    }

    poly.ps = N_GNEW(pn, pointf);
    poly.pn = pn;

    for (i = 0; i < mult; i++) {
	poly.ps[0] = eps[0];
	for (j = 1; j < pl.pn - 1; j++) {
	    poly.ps[j] = cpts[j - 1][i];
	}
	poly.ps[pl.pn - 1] = eps[1];
	for (j = 1; j < pl.pn - 1; j++) {
	    poly.ps[pn - j] = cpts[j - 1][i + 1];
	}
	Pshortestpath(&poly, eps, &mmpl);

	if (doPolyline) {
	    make_polyline (mmpl, &spl);
	}
	else {
	    for (j = 0; j < poly.pn; j++) {
		medges[j].a = poly.ps[j];
		medges[j].b = poly.ps[(j + 1) % poly.pn];
	    }
	    tweakPath (poly, 0, pl.pn-1, mmpl);
	    Proutespline(medges, poly.pn, mmpl, evs, &spl);
	}
	finishEdge (g, e, spl, aghead(e) != head, eps[0], eps[1]);

	e = ED_to_virt(e);
    }

    for (i = 0; i < pl.pn - 2; i++)
	free(cpts[i]);
    free(cpts);
    free(medges);
    free(poly.ps);
    return 0;
}
예제 #7
0
/* process vgpane methods */
static int
vgpanecmd(ClientData clientData, Tcl_Interp * interp, int argc,
	  char *argv[])
{
    int vargc, length, i, j, n, result;
    char c, *s, **vargv, vbuf[30];
    vgpane_t *vgp, **vgpp;
    point p, q, *ps;
    poly *tpp;
    double alpha, gain;
    Pvector_t slopes[2];
    Ppolyline_t line, spline;
    int pp, qp;			/* polygon indices for p, q */
    Pedge_t *barriers;
    int n_barriers;

    if (argc < 2) {
	Tcl_AppendResult(interp, "wrong # args: should be \"",
			 " ", argv[0], " method ?arg arg ...?\"",
			 (char *) NULL);
	return TCL_ERROR;
    }
    if (!(vgpp = (vgpane_t **) tclhandleXlate(vgpaneTable, argv[0]))) {
	Tcl_AppendResult(interp, "Invalid handle: \"", argv[0],
			 "\"", (char *) NULL);
	return TCL_ERROR;
    }
    vgp = *vgpp;

    c = argv[1][0];
    length = strlen(argv[1]);

    if ((c == 'c') && (strncmp(argv[1], "coords", length) == 0)) {
	if ((argc < 3)) {
	    Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
			     " ", argv[1], " id ?x1 y1 x2 y2...?\"",
			     (char *) NULL);
	    return TCL_ERROR;
	}
	if (sscanf(argv[2], "%d", &polyid) != 1) {
	    Tcl_AppendResult(interp, "not an integer: ", argv[2],
			     (char *) NULL);
	    return TCL_ERROR;
	}
	if (argc == 3) {
	    /* find poly and return its coordinates */
	    for (i = 0; i < vgp->Npoly; i++) {
		if (vgp->poly[i].id == polyid) {
		    n = vgp->poly[i].boundary.pn;
		    for (j = 0; j < n; j++) {
			appendpoint(interp, vgp->poly[i].boundary.ps[j]);
		    }
		    return TCL_OK;
		}
	    }
	    Tcl_AppendResult(interp, " no such polygon: ", argv[2],
			     (char *) NULL);
	    return TCL_ERROR;
	}
	/* accept either inline or delimited list */
	if ((argc == 4)) {
	    result =
		Tcl_SplitList(interp, argv[3], &vargc,
			      (CONST84 char ***) &vargv);
	    if (result != TCL_OK) {
		return result;
	    }
	} else {
	    vargc = argc - 3;
	    vargv = &argv[3];
	}
	if (!vargc || vargc % 2) {
	    Tcl_AppendResult(interp,
			     "There must be a multiple of two terms in the list.",
			     (char *) NULL);
	    return TCL_ERROR;
	}

	/* remove old poly, add modified polygon to the end with 
	   the same id as the original */

	if (!(remove_poly(vgp, polyid))) {
	    Tcl_AppendResult(interp, " no such polygon: ", argv[2],
			     (char *) NULL);
	    return TCL_ERROR;
	}

	return (insert_poly(interp, vgp, polyid, vargv, vargc));

    } else if ((c == 'd') && (strncmp(argv[1], "debug", length) == 0)) {
	/* debug only */
	printf("debug output goes here\n");
	return TCL_OK;

    } else if ((c == 'd') && (strncmp(argv[1], "delete", length) == 0)) {
	/* delete a vgpane and all memory associated with it */
	if (vgp->vc)
	    Pobsclose(vgp->vc);
	free(vgp->poly);	/* ### */
	Tcl_DeleteCommand(interp, argv[0]);
	free((char *) tclhandleFree(vgpaneTable, argv[0]));
	return TCL_OK;

    } else if ((c == 'f') && (strncmp(argv[1], "find", length) == 0)) {
	/* find the polygon that the point is inside and return it
	   id, or null */
	if ((argc < 3)) {
	    Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
			     " ", argv[1], " x y\"", (char *) NULL);
	    return TCL_ERROR;
	}
	if (argc == 3) {
	    result =
		Tcl_SplitList(interp, argv[2], &vargc,
			      (CONST84 char ***) &vargv);
	    if (result != TCL_OK) {
		return result;
	    }
	} else {
	    vargc = argc - 2;
	    vargv = &argv[2];
	}
	result = scanpoint(interp, &vargv[0], &p);
	if (result != TCL_OK)
	    return result;

	/* determine the polygons (if any) that contain the point */
	for (i = 0; i < vgp->Npoly; i++) {
	    if (in_poly(vgp->poly[i].boundary, p)) {
		sprintf(vbuf, "%d", vgp->poly[i].id);
		Tcl_AppendElement(interp, vbuf);
	    }
	}
	return TCL_OK;

    } else if ((c == 'i') && (strncmp(argv[1], "insert", length) == 0)) {
	/* add poly to end poly list, and it coordinates to the end of 
	   the point list */
	if ((argc < 3)) {
	    Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
			     " ", argv[1], " x1 y1 x2 y2 ...\"",
			     (char *) NULL);
	    return TCL_ERROR;
	}
	/* accept either inline or delimited list */
	if ((argc == 3)) {
	    result =
		Tcl_SplitList(interp, argv[2], &vargc,
			      (CONST84 char ***) &vargv);
	    if (result != TCL_OK) {
		return result;
	    }
	} else {
	    vargc = argc - 2;
	    vargv = &argv[2];
	}

	if (!vargc || vargc % 2) {
	    Tcl_AppendResult(interp,
			     "There must be a multiple of two terms in the list.",
			     (char *) NULL);
	    return TCL_ERROR;
	}

	polyid++;

	result = insert_poly(interp, vgp, polyid, vargv, vargc);
	if (result != TCL_OK)
	    return result;

	sprintf(vbuf, "%d", polyid);
	Tcl_AppendResult(interp, vbuf, (char *) NULL);
	return TCL_OK;

    } else if ((c == 'l') && (strncmp(argv[1], "list", length) == 0)) {
	/* return list of polygon ids */
	for (i = 0; i < vgp->Npoly; i++) {
	    sprintf(vbuf, "%d", vgp->poly[i].id);
	    Tcl_AppendElement(interp, vbuf);
	}
	return TCL_OK;

    } else if ((c == 'p') && (strncmp(argv[1], "path", length) == 0)) {
	/* return a list of points corresponding to the shortest path
	   that does not cross the remaining "visible" polygons. */
	if ((argc < 3)) {
	    Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
			     " ", argv[1], " x1 y1 x2 y2\"",
			     (char *) NULL);
	    return TCL_ERROR;
	}
	if (argc == 3) {
	    result =
		Tcl_SplitList(interp, argv[2], &vargc,
			      (CONST84 char ***) &vargv);
	    if (result != TCL_OK) {
		return result;
	    }
	} else {
	    vargc = argc - 2;
	    vargv = &argv[2];
	}
	if ((vargc < 4)) {
	    Tcl_AppendResult(interp,
			     "invalid points: should be: \"x1 y1 x2 y2\"",
			     (char *) NULL);
	    return TCL_ERROR;
	}
	result = scanpoint(interp, &vargv[0], &p);
	if (result != TCL_OK)
	    return result;
	result = scanpoint(interp, &vargv[2], &q);
	if (result != TCL_OK)
	    return result;

	/* only recompute the visibility graph if we have to */
	if ((vc_refresh(vgp))) {
	    Pobspath(vgp->vc, p, POLYID_UNKNOWN, q, POLYID_UNKNOWN, &line);

	    for (i = 0; i < line.pn; i++) {
		appendpoint(interp, line.ps[i]);
	    }
	}

	return TCL_OK;

    } else if ((c == 'b') && (strncmp(argv[1], "bind", length) == 0)) {
	if ((argc < 2) || (argc > 4)) {
	    Tcl_AppendResult(interp, "wrong # args: should be \"",
			     argv[0], " bind triangle ?command?\"",
			     (char *) NULL);
	    return TCL_ERROR;
	}
	if (argc == 2) {
	    Tcl_AppendElement(interp, "triangle");
	    return TCL_OK;
	}
	length = strlen(argv[2]);
	if (strncmp(argv[2], "triangle", length) == 0) {
	    s = vgp->triangle_cmd;
	    if (argc == 4)
		vgp->triangle_cmd = s = buildBindings(s, argv[3]);
	} else {
	    Tcl_AppendResult(interp, "unknown event \"", argv[2],
			     "\": must be one of:\n\ttriangle.",
			     (char *) NULL);
	    return TCL_ERROR;
	}
	if (argc == 3)
	    Tcl_AppendResult(interp, s, (char *) NULL);
	return TCL_OK;

    } else if ((c == 'b') && (strncmp(argv[1], "bpath", length) == 0)) {
	/* return a list of points corresponding to the shortest path
	   that does not cross the remaining "visible" polygons. */
	if ((argc < 3)) {
	    Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
			     " ", argv[1], " x1 y1 x2 y2\"",
			     (char *) NULL);
	    return TCL_ERROR;
	}
	if (argc == 3) {
	    result =
		Tcl_SplitList(interp, argv[2], &vargc,
			      (CONST84 char ***) &vargv);
	    if (result != TCL_OK) {
		return result;
	    }
	} else {
	    vargc = argc - 2;
	    vargv = &argv[2];
	}
	if ((vargc < 4)) {
	    Tcl_AppendResult(interp,
			     "invalid points: should be: \"x1 y1 x2 y2\"",
			     (char *) NULL);
	    return TCL_ERROR;
	}

	result = scanpoint(interp, &vargv[0], &p);
	if (result != TCL_OK)
	    return result;
	result = scanpoint(interp, &vargv[2], &q);
	if (result != TCL_OK)
	    return result;

	/* determine the polygons (if any) that contain the endpoints */
	pp = qp = POLYID_NONE;
	for (i = 0; i < vgp->Npoly; i++) {
	    tpp = &(vgp->poly[i]);
	    if ((pp == POLYID_NONE) && in_poly(tpp->boundary, p))
		pp = i;
	    if ((qp == POLYID_NONE) && in_poly(tpp->boundary, q))
		qp = i;
	}

	if (vc_refresh(vgp)) {
	    /*Pobspath(vgp->vc, p, pp, q, qp, &line); */
	    Pobspath(vgp->vc, p, POLYID_UNKNOWN, q, POLYID_UNKNOWN, &line);
	    make_barriers(vgp, pp, qp, &barriers, &n_barriers);
	    slopes[0].x = slopes[0].y = 0.0;
	    slopes[1].x = slopes[1].y = 0.0;
	    Proutespline(barriers, n_barriers, line, slopes, &spline);

	    for (i = 0; i < spline.pn; i++) {
		appendpoint(interp, spline.ps[i]);
	    }
	}
	return TCL_OK;

    } else if ((c == 'b') && (strncmp(argv[1], "bbox", length) == 0)) {
	if ((argc < 3)) {
	    Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
			     " ", argv[1], " id\"", (char *) NULL);
	    return TCL_ERROR;
	}
	if (sscanf(argv[2], "%d", &polyid) != 1) {
	    Tcl_AppendResult(interp, "not an integer: ", argv[2],
			     (char *) NULL);
	    return TCL_ERROR;
	}
	for (i = 0; i < vgp->Npoly; i++) {
	    if (vgp->poly[i].id == polyid) {
		Ppoly_t pp = vgp->poly[i].boundary;
		point LL, UR;
		LL = UR = pp.ps[0];
		for (j = 1; j < pp.pn; j++) {
		    p = pp.ps[j];
		    if (p.x > UR.x)
			UR.x = p.x;
		    if (p.y > UR.y)
			UR.y = p.y;
		    if (p.x < LL.x)
			LL.x = p.x;
		    if (p.y < LL.y)
			LL.y = p.y;
		}
		appendpoint(interp, LL);
		appendpoint(interp, UR);
		return TCL_OK;
	    }
	}
	Tcl_AppendResult(interp, " no such polygon: ", argv[2],
			 (char *) NULL);
	return TCL_ERROR;

    } else if ((c == 'c') && (strncmp(argv[1], "center", length) == 0)) {
	if ((argc < 3)) {
	    Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
			     " ", argv[1], " id\"", (char *) NULL);
	    return TCL_ERROR;
	}
	if (sscanf(argv[2], "%d", &polyid) != 1) {
	    Tcl_AppendResult(interp, "not an integer: ", argv[2],
			     (char *) NULL);
	    return TCL_ERROR;
	}
	for (i = 0; i < vgp->Npoly; i++) {
	    if (vgp->poly[i].id == polyid) {
		appendpoint(interp, center(vgp->poly[i].boundary.ps,
					   vgp->poly[i].boundary.pn));
		return TCL_OK;
	    }
	}
	Tcl_AppendResult(interp, " no such polygon: ", argv[2],
			 (char *) NULL);
	return TCL_ERROR;

    } else if ((c == 't')
	       && (strncmp(argv[1], "triangulate", length) == 0)) {
	if ((argc < 2)) {
	    Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
			     " id ", (char *) NULL);
	    return TCL_ERROR;
	}

	if (sscanf(argv[2], "%d", &polyid) != 1) {
	    Tcl_AppendResult(interp, "not an integer: ", argv[2],
			     (char *) NULL);
	    return TCL_ERROR;
	}

	for (i = 0; i < vgp->Npoly; i++) {
	    if (vgp->poly[i].id == polyid) {
		Ptriangulate(&(vgp->poly[i].boundary), triangle_callback,
			     vgp);
		return TCL_OK;
	    }
	}
	Tcl_AppendResult(interp, " no such polygon: ", argv[2],
			 (char *) NULL);
	return TCL_ERROR;
    } else if ((c == 'r') && (strncmp(argv[1], "rotate", length) == 0)) {
	if ((argc < 4)) {
	    Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
			     " ", argv[1], " id alpha\"", (char *) NULL);
	    return TCL_ERROR;
	}
	if (sscanf(argv[2], "%d", &polyid) != 1) {
	    Tcl_AppendResult(interp, "not an integer: ", argv[2],
			     (char *) NULL);
	    return TCL_ERROR;
	}
	if (sscanf(argv[3], "%lg", &alpha) != 1) {
	    Tcl_AppendResult(interp, "not an angle in radians: ", argv[3],
			     (char *) NULL);
	    return TCL_ERROR;
	}
	for (i = 0; i < vgp->Npoly; i++) {
	    if (vgp->poly[i].id == polyid) {
		n = vgp->poly[i].boundary.pn;
		ps = vgp->poly[i].boundary.ps;
		p = center(ps, n);
		for (j = 0; j < n; j++) {
		    appendpoint(interp, rotate(p, ps[j], alpha));
		}
		return TCL_OK;
	    }
	}
	Tcl_AppendResult(interp, " no such polygon: ", argv[2],
			 (char *) NULL);
	return TCL_ERROR;

    } else if ((c == 's') && (strncmp(argv[1], "scale", length) == 0)) {
	if ((argc < 4)) {
	    Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
			     " ", argv[1], " id gain\"", (char *) NULL);
	    return TCL_ERROR;
	}
	if (sscanf(argv[2], "%d", &polyid) != 1) {
	    Tcl_AppendResult(interp, "not an integer: ", argv[2],
			     (char *) NULL);
	    return TCL_ERROR;
	}
	if (sscanf(argv[3], "%lg", &gain) != 1) {
	    Tcl_AppendResult(interp, "not a number: ", argv[3],
			     (char *) NULL);
	    return TCL_ERROR;
	}
	for (i = 0; i < vgp->Npoly; i++) {
	    if (vgp->poly[i].id == polyid) {
		n = vgp->poly[i].boundary.pn;
		ps = vgp->poly[i].boundary.ps;
		for (j = 0; j < n; j++) {
		    appendpoint(interp, scale(p, ps[j], gain));
		}
		return TCL_OK;
	    }
	}
	Tcl_AppendResult(interp, " no such polygon: ", argv[2],
			 (char *) NULL);
	return TCL_ERROR;

    } else if ((c == 'r') && (strncmp(argv[1], "remove", length) == 0)) {
	if ((argc < 3)) {
	    Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
			     " ", argv[1], " id\"", (char *) NULL);
	    return TCL_ERROR;
	}
	if (sscanf(argv[2], "%d", &polyid) != 1) {
	    Tcl_AppendResult(interp, "not an integer: ", argv[2],
			     (char *) NULL);
	    return TCL_ERROR;
	}

	if (remove_poly(vgp, polyid))
	    return TCL_OK;

	Tcl_AppendResult(interp, " no such polygon: ", argv[2],
			 (char *) NULL);
	return TCL_ERROR;
    }

    Tcl_AppendResult(interp, "bad method \"", argv[1],
		     "\" must be one of:",
		     "\n\tbbox, bind, bpath, center, coords, delete, find,",
		     "\n\tinsert, list, path, remove, rotate, scale, triangulate.",
		     (char *) NULL);
    return TCL_ERROR;
}
예제 #8
0
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;
}