From: ellson Date: Tue, 18 Oct 2005 18:29:03 +0000 (+0000) Subject: back out the geom.[ch] changes that apparently broke neato X-Git-Tag: LAST_LIBGRAPH~32^2~7309 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=ce440e6756bc34f87975798adc853bfe3d02ddb0;p=graphviz back out the geom.[ch] changes that apparently broke neato --- diff --git a/lib/common/Makefile.am b/lib/common/Makefile.am index 8a17068a4..a8155db0e 100644 --- a/lib/common/Makefile.am +++ b/lib/common/Makefile.am @@ -10,7 +10,7 @@ AM_CPPFLAGS = \ -I$(top_srcdir)/lib/cdt @GD_INCLUDES@ @EXPAT_INCLUDES@ @Z_INCLUDES@ pkginclude_HEADERS = const.h globals.h htmllex.h htmltable.h macros.h \ - pointset.h render.h renderprocs.h types.h utils.h colortbl.h geom.h + pointset.h render.h renderprocs.h types.h utils.h colortbl.h noinst_LTLIBRARIES = libcommon.la if !DISABLE_CODEGENS @@ -23,7 +23,7 @@ libcommon_la_SOURCES = arrows.c colxlate.c fontmetrics.c \ args.c gdtextsize.c gdusershape.c \ globals.c htmllex.c htmlparse.y htmltable.c input.c \ pointset.c postproc.c psusershape.c routespl.c splines.c \ - svgusershape.c timing.c labels.c ns.c shapes.c utils.c geom.c \ + svgusershape.c timing.c labels.c ns.c shapes.c utils.c \ output.c emit.c $(CODEGENS) psgen.o psgen.lo : ps.h diff --git a/lib/common/arrows.c b/lib/common/arrows.c index 909d30ad7..e566853ec 100644 --- a/lib/common/arrows.c +++ b/lib/common/arrows.c @@ -22,6 +22,10 @@ #define EPSILON .0001 +#define sqr(a) ((double) (a) * (a)) +#define dstsq(a, b) (sqr (a.x - b.x) + sqr (a.y - b.y)) +#define dst(a, b) sqrt (dsts + /* standard arrow length in points */ #define ARROW_LENGTH 10. @@ -231,7 +235,7 @@ double arrow_length(edge_t * e, int flag) /* inside function for calls to bezier_clip */ static boolean inside(inside_t * inside_context, pointf p) { - return DIST2(p, inside_context->a.p[0]) <= inside_context->a.r[0]; + return dstsq(p, inside_context->a.p[0]) <= inside_context->a.r[0]; } int arrowEndClip(edge_t* e, point * ps, int startp, @@ -244,7 +248,7 @@ int arrowEndClip(edge_t* e, point * ps, int startp, elen = arrow_length(e, eflag); elen2 = elen * elen; spl->eflag = eflag, spl->ep = ps[endp + 3]; - if (endp > startp && DIST2(ps[endp], ps[endp + 3]) < elen2) { + if (endp > startp && dstsq(ps[endp], ps[endp + 3]) < elen2) { endp -= 3; } P2PF(ps[endp], sp[3]); @@ -273,7 +277,7 @@ int arrowStartClip(edge_t* e, point * ps, int startp, slen = arrow_length(e, sflag); slen2 = slen * slen; spl->sflag = sflag, spl->sp = ps[startp]; - if (endp > startp && DIST2(ps[startp], ps[startp + 3]) < slen2) { + if (endp > startp && dstsq(ps[startp], ps[startp + 3]) < slen2) { startp += 3; } P2PF(ps[startp + 3], sp[0]); diff --git a/lib/common/diagen.c b/lib/common/diagen.c index f2cd74cc7..0c5d07483 100644 --- a/lib/common/diagen.c +++ b/lib/common/diagen.c @@ -637,7 +637,7 @@ int ellipse_connection(pointf cp, pointf p) int box_connection(node_t * n, pointf p) { int i = 0, j, sides, conn = 0, peripheries, z; - double xsize, ysize, mindist2 = 0.0, dist2; + double xsize, ysize, mindist = 0.0, dist; polygon_t *poly; pointf P, *vertices; static point *A; @@ -673,13 +673,13 @@ int box_connection(node_t * n, pointf p) z = 0; while (z < i) { - dist2 = DIST2(p, diapt(A[z])); + dist = DIST(p.x, p.y, diapt(A[z]).x, diapt(A[z]).y); if (z == 0) { - mindist2 = dist2; + mindist = dist; conn = 0; } - if (dist2 < mindist2) { - mindist2 = dist2; + if (dist < mindist) { + mindist = dist; conn = 2 * z; } z++; @@ -687,11 +687,11 @@ int box_connection(node_t * n, pointf p) z = 0; while (z < i) { - P.x = (diapt(A[z]).x + diapt(A[z + 1]).x) / 2; - P.y = (diapt(A[z]).y + diapt(A[z + 1]).y) / 2; - dist2 = DIST2(p, P); - if (dist2 < mindist2) { - mindist2 = dist2; + dist = + DIST(p.x, p.y, (diapt(A[z]).x + diapt(A[z + 1]).x) / 2, + (diapt(A[z]).y + diapt(A[z + 1]).y) / 2); + if (dist < mindist) { + mindist = dist; conn = 2 * z + 1; } z++; diff --git a/lib/common/emit.c b/lib/common/emit.c index 6628d155f..870493e58 100644 --- a/lib/common/emit.c +++ b/lib/common/emit.c @@ -677,7 +677,7 @@ static void emit_attachment(GVJ_t * job, textlabel_t * lp, splines * spl) PF2P(lp->dimen, sz); A[0] = pointof(lp->p.x + sz.x / 2, lp->p.y - sz.y / 2); A[1] = pointof(A[0].x - sz.x, A[0].y); - A[2] = closest_spline_point(spl, lp->p); + A[2] = dotneato_closest(spl, lp->p); /* Don't use edge style to draw attachment */ gvrender_set_style(job, job->gvc->defaultlinestyle); /* Use font color to draw attachment diff --git a/lib/common/macros.h b/lib/common/macros.h index a42a23c50..d3ecaf8f9 100644 --- a/lib/common/macros.h +++ b/lib/common/macros.h @@ -29,10 +29,6 @@ #define NOTUSED(var) (void) var #endif -#ifndef NULL -#define NULL (void *)0 -#endif - #ifndef NIL #define NIL(type) ((type)0) #endif @@ -103,10 +99,7 @@ #define ROUND(f) ((f>=0)?(int)(f + .5):(int)(f - .5)) #define RADIANS(deg) ((deg)/180.0 * PI) #define DEGREES(rad) ((rad)/PI * 180.0) - -#define DIST2(p1,p2) (((p1.x) - (p2.x))*((p1.x) - (p2.x)) + ((p1.y) - (p2.y))*((p1.y) - (p2.y))) -#define DIST(p1,p2) (sqrt(DIST2((p1),(p2)))) - +#define DIST(x1,y1,x2,y2) (sqrt(((x1) - (x2))*((x1) - (x2)) + ((y1) - (y2))*((y1) - (y2)))) #define POINTS_PER_INCH 72 #define POINTS(f_inch) (ROUND((f_inch)*POINTS_PER_INCH)) #define PS2INCH(ps) ((ps)/(double)POINTS_PER_INCH) diff --git a/lib/common/utils.c b/lib/common/utils.c index b339cf8d0..965ba02ae 100644 --- a/lib/common/utils.c +++ b/lib/common/utils.c @@ -241,6 +241,176 @@ point coord(node_t * n) return cvt2pt(pf); } +point pointof(int x, int y) +{ + point rv; + rv.x = x, rv.y = y; + return rv; +} + +point cvt2pt(pointf p) +{ + point rv; + rv.x = POINTS(p.x); + rv.y = POINTS(p.y); + return rv; +} + +pointf cvt2ptf(point p) +{ + pointf rv; + rv.x = PS2INCH(p.x); + rv.y = PS2INCH(p.y); + return rv; +} + +box boxof(int llx, int lly, int urx, int ury) +{ + box b; + + b.LL.x = llx, b.LL.y = lly; + b.UR.x = urx, b.UR.y = ury; + return b; +} + +boxf boxfof(double llx, double lly, double urx, double ury) +{ + boxf b; + + b.LL.x = llx, b.LL.y = lly; + b.UR.x = urx, b.UR.y = ury; + return b; +} + +box mkbox(point p0, point p1) +{ + box rv; + + if (p0.x < p1.x) { + rv.LL.x = p0.x; + rv.UR.x = p1.x; + } else { + rv.LL.x = p1.x; + rv.UR.x = p0.x; + } + if (p0.y < p1.y) { + rv.LL.y = p0.y; + rv.UR.y = p1.y; + } else { + rv.LL.y = p1.y; + rv.UR.y = p0.y; + } + return rv; +} + +boxf mkboxf(pointf p0, pointf p1) +{ + boxf rv; + + if (p0.x < p1.x) { + rv.LL.x = p0.x; + rv.UR.x = p1.x; + } else { + rv.LL.x = p1.x; + rv.UR.x = p0.x; + } + if (p0.y < p1.y) { + rv.LL.y = p0.y; + rv.UR.y = p1.y; + } else { + rv.LL.y = p1.y; + rv.UR.y = p0.y; + } + return rv; +} + +point add_points(point p0, point p1) +{ + p0.x += p1.x; + p0.y += p1.y; + return p0; +} + +point sub_points(point p0, point p1) +{ + p0.x -= p1.x; + p0.y -= p1.y; + return p0; +} + +pointf add_pointfs(pointf p0, pointf p1) +{ + p0.x += p1.x; + p0.y += p1.y; + return p0; +} + +pointf sub_pointfs(pointf p0, pointf p1) +{ + p0.x -= p1.x; + p0.y -= p1.y; + return p0; +} + +point exch_xy(point p) +{ + int t; + t = p.x; + p.x = p.y; + p.y = t; + return p; +} + +pointf exch_xyf(pointf p) +{ + double t; + t = p.x; + p.x = p.y; + p.y = t; + return p; +} + +/* from Glassner's Graphics Gems */ +#define W_DEGREE 5 + +/* + * Bezier : + * Evaluate a Bezier curve at a particular parameter value + * Fill in control points for resulting sub-curves if "Left" and + * "Right" are non-null. + * + */ +pointf Bezier(pointf * V, int degree, double t, pointf * Left, + pointf * Right) +{ + int i, j; /* Index variables */ + pointf Vtemp[W_DEGREE + 1][W_DEGREE + 1]; + + /* Copy control points */ + for (j = 0; j <= degree; j++) { + Vtemp[0][j] = V[j]; + } + + /* Triangle computation */ + for (i = 1; i <= degree; i++) { + for (j = 0; j <= degree - i; j++) { + Vtemp[i][j].x = + (1.0 - t) * Vtemp[i - 1][j].x + t * Vtemp[i - 1][j + 1].x; + Vtemp[i][j].y = + (1.0 - t) * Vtemp[i - 1][j].y + t * Vtemp[i - 1][j + 1].y; + } + } + + if (Left != NULL) + for (j = 0; j <= degree; j++) + Left[j] = Vtemp[j][0]; + if (Right != NULL) + for (j = 0; j <= degree; j++) + Right[j] = Vtemp[degree - j][j]; + + return (Vtemp[degree][0]); +} + #ifdef DEBUG edge_t *debug_getedge(graph_t * g, char *s0, char *s1) { @@ -437,6 +607,74 @@ void cat_libfile(FILE * ofp, char **arglib, char **stdlib) } } +box box_bb(box b0, box b1) +{ + box b; + + b.LL.x = MIN(b0.LL.x, b1.LL.x); + b.LL.y = MIN(b0.LL.y, b1.LL.y); + b.UR.x = MAX(b0.UR.x, b1.UR.x); + b.UR.y = MAX(b0.UR.y, b1.UR.y); + + return b; +} + +boxf boxf_bb(boxf b0, boxf b1) +{ + boxf b; + + b.LL.x = MIN(b0.LL.x, b1.LL.x); + b.LL.y = MIN(b0.LL.y, b1.LL.y); + b.UR.x = MAX(b0.UR.x, b1.UR.x); + b.UR.y = MAX(b0.UR.y, b1.UR.y); + + return b; +} + +box box_intersect(box b0, box b1) +{ + box b; + + b.LL.x = MAX(b0.LL.x, b1.LL.x); + b.LL.y = MAX(b0.LL.y, b1.LL.y); + b.UR.x = MIN(b0.UR.x, b1.UR.x); + b.UR.y = MIN(b0.UR.y, b1.UR.y); + + return b; +} + +boxf boxf_intersect(boxf b0, boxf b1) +{ + boxf b; + + b.LL.x = MAX(b0.LL.x, b1.LL.x); + b.LL.y = MAX(b0.LL.y, b1.LL.y); + b.UR.x = MIN(b0.UR.x, b1.UR.x); + b.UR.y = MIN(b0.UR.y, b1.UR.y); + + return b; +} + +boolean box_overlap(box b0, box b1) +{ + return OVERLAP(b0, b1); +} + +boolean boxf_overlap(boxf b0, boxf b1) +{ + return OVERLAP(b0, b1); +} + +boolean box_contains(box b0, box b1) +{ + return CONTAINS(b0, b1); +} + +boolean boxf_contains(boxf b0, boxf b1) +{ + return CONTAINS(b0, b1); +} + int maptoken(char *p, char **name, int *val) { int i; @@ -459,6 +697,149 @@ int mapbool(char *p) return atoi(p); } +static double dist2(pointf p, pointf q) /* return square of dist between p and q */ +{ + double d0, d1; + + d0 = p.x - q.x; + d1 = p.y - q.y; + return (d0 * d0 + d1 * d1); +} + +point dotneato_closest(splines * spl, point p) +{ + int i, j, k, besti, bestj; + double bestdist2, d2, dlow2, dhigh2; /* squares of distances */ + double low, high, t; + pointf c[4], pt2, pt; + point rv; + bezier bz; + + besti = bestj = -1; + bestdist2 = 1e+38; + P2PF(p, pt); + for (i = 0; i < spl->size; i++) { + bz = spl->list[i]; + for (j = 0; j < bz.size; j++) { + pointf b; + + b.x = bz.list[j].x; + b.y = bz.list[j].y; + d2 = dist2(b, pt); + if ((bestj == -1) || (d2 < bestdist2)) { + besti = i; + bestj = j; + bestdist2 = d2; + } + } + } + + bz = spl->list[besti]; + j = bestj / 3; + if (j >= spl->size) + j--; + for (k = 0; k < 4; k++) { + c[k].x = bz.list[j + k].x; + c[k].y = bz.list[j + k].y; + } + low = 0.0; + high = 1.0; + dlow2 = dist2(c[0], pt); + dhigh2 = dist2(c[3], pt); + do { + t = (low + high) / 2.0; + pt2 = Bezier(c, 3, t, NULL, NULL); + if (fabs(dlow2 - dhigh2) < 1.0) + break; + if (fabs(high - low) < .00001) + break; + if (dlow2 < dhigh2) { + high = t; + dhigh2 = dist2(pt2, pt); + } else { + low = t; + dlow2 = dist2(pt2, pt); + } + } while (1); + PF2P(pt2, rv); + return rv; +} + +point spline_at_y(splines * spl, int y) +{ + int i, j; + double low, high, d, t; + pointf c[4], pt2; + point pt; + static bezier bz; + +/* this caching seems to prevent pt.x from getting set from bz.list[0].x + - optimizer problem ? */ + +#if 0 + static splines *mem = NULL; + + if (mem != spl) { + mem = spl; +#endif + for (i = 0; i < spl->size; i++) { + bz = spl->list[i]; + if (BETWEEN(bz.list[bz.size - 1].y, y, bz.list[0].y)) + break; + } +#if 0 + } +#endif + if (y > bz.list[0].y) + pt = bz.list[0]; + else if (y < bz.list[bz.size - 1].y) + pt = bz.list[bz.size - 1]; + else { + for (i = 0; i < bz.size; i += 3) { + for (j = 0; j < 3; j++) { + if ((bz.list[i + j].y <= y) && (y <= bz.list[i + j + 1].y)) + break; + if ((bz.list[i + j].y >= y) && (y >= bz.list[i + j + 1].y)) + break; + } + if (j < 3) + break; + } + assert(i < bz.size); + for (j = 0; j < 4; j++) { + c[j].x = bz.list[i + j].x; + c[j].y = bz.list[i + j].y; + /* make the spline be monotonic in Y, awful but it works for now */ + if ((j > 0) && (c[j].y > c[j - 1].y)) + c[j].y = c[j - 1].y; + } + low = 0.0; + high = 1.0; + do { + t = (low + high) / 2.0; + pt2 = Bezier(c, 3, t, NULL, NULL); + d = pt2.y - y; + if (ABS(d) <= 1) + break; + if (d < 0) + high = t; + else + low = t; + } while (1); + pt.x = pt2.x; + pt.y = pt2.y; + } + pt.y = y; + return pt; +} + +point neato_closest(splines * spl, point p) +{ +/* this is a stub so that we can share a common emit.c between dot and neato */ + + return spline_at_y(spl, p.y); +} + static int Tflag; void toggle(int s) { @@ -667,6 +1048,104 @@ int common_init_edge(edge_t * e) return r; } +/* flip_ptf: + * Transform point => + * LR - rotate ccw by 90 + * BT - reflect across x axis + * RL - TB o LR + */ +point flip_pt(point p, int rankdir) +{ + int x = p.x, y = p.y; + switch (rankdir) { + case RANKDIR_TB: + break; + case RANKDIR_LR: + p.x = -y; + p.y = x; + break; + case RANKDIR_BT: + p.x = x; + p.y = -y; + break; + case RANKDIR_RL: + p.x = y; + p.y = x; + break; + } + return p; +} + +/* flip_ptf: + * flip_pt for pointf type. + */ +pointf flip_ptf(pointf p, int rankdir) +{ + double x = p.x, y = p.y; + switch (rankdir) { + case RANKDIR_TB: + break; + case RANKDIR_LR: + p.x = -y; + p.y = x; + break; + case RANKDIR_BT: + p.x = x; + p.y = -y; + break; + case RANKDIR_RL: + p.x = y; + p.y = x; + break; + } + return p; +} + +/* invflip_pt: + * Transform point => + * LR - rotate cw by 90 + * BT - reflect across x axis + * RL - TB o LR + * Note that flip and invflip only differ on LR + */ +point invflip_pt(point p, int rankdir) +{ + int x = p.x, y = p.y; + switch (rankdir) { + case RANKDIR_TB: + break; + case RANKDIR_LR: + p.x = y; + p.y = -x; + break; + case RANKDIR_BT: + p.x = x; + p.y = -y; + break; + case RANKDIR_RL: + p.x = y; + p.y = x; + break; + } + return p; +} + +box flip_rec_box(box b, point p) +{ + box rv; + /* flip box */ + rv.UR.x = b.UR.y; + rv.UR.y = b.UR.x; + rv.LL.x = b.LL.y; + rv.LL.y = b.LL.x; + /* move box */ + rv.LL.x += p.x; + rv.LL.y += p.y; + rv.UR.x += p.x; + rv.UR.y += p.y; + return rv; +} + /* addLabelBB: */ static box addLabelBB(box bb, textlabel_t * lp, boolean flipxy) @@ -731,14 +1210,24 @@ void compute_bb(graph_t * g) b.LL = sub_points(pt, s2); b.UR = add_points(pt, s2); - EXPANDBB(b,b); + bb.LL.x = MIN(bb.LL.x, b.LL.x); + bb.LL.y = MIN(bb.LL.y, b.LL.y); + bb.UR.x = MAX(bb.UR.x, b.UR.x); + bb.UR.y = MAX(bb.UR.y, b.UR.y); for (e = agfstout(g, n); e; e = agnxtout(g, e)) { if (ED_spl(e) == 0) continue; for (i = 0; i < ED_spl(e)->size; i++) { for (j = 0; j < ED_spl(e)->list[i].size; j++) { pt = ED_spl(e)->list[i].list[j]; - EXPANDBP(bb,pt); + if (bb.LL.x > pt.x) + bb.LL.x = pt.x; + if (bb.LL.y > pt.y) + bb.LL.y = pt.y; + if (bb.UR.x < pt.x) + bb.UR.x = pt.x; + if (bb.UR.y < pt.y) + bb.UR.y = pt.y; } } if (ED_label(e) && ED_label(e)->set) @@ -747,7 +1236,10 @@ void compute_bb(graph_t * g) } for (i = 1; i <= GD_n_cluster(g); i++) { - EXPANDBB(bb,GD_clust(g)[i]->u.bb); + bb.LL.x = MIN(bb.LL.x, GD_clust(g)[i]->u.bb.LL.x); + bb.LL.y = MIN(bb.LL.y, GD_clust(g)[i]->u.bb.LL.y); + bb.UR.x = MAX(bb.UR.x, GD_clust(g)[i]->u.bb.UR.x); + bb.UR.y = MAX(bb.UR.y, GD_clust(g)[i]->u.bb.UR.y); } GD_bb(g) = bb; @@ -1271,6 +1763,138 @@ utf8ToLatin1 (char* s) return ns; } +/* + *-------------------------------------------------------------- + * + * lineToBox -- + * + * Determine whether a line lies entirely inside, entirely + * outside, or overlapping a given rectangular area. + * + * Results: + * -1 is returned if the line given by p1 and p2 + * is entirely outside the rectangle given by b. + * 0 is returned if the polygon overlaps the rectangle, and + * 1 is returned if the polygon is entirely inside the rectangle. + * + * Side effects: + * None. + * + *-------------------------------------------------------------- + */ + +/* This code steals liberally from algorithms in tk/generic/tkTrig.c -- jce */ + +static int lineToBox(pointf p1, pointf p2, boxf b) +{ + int inside1, inside2; + + /* + * First check the two points individually to see whether they + * are inside the rectangle or not. + */ + + inside1 = (p1.x >= b.LL.x) && (p1.x <= b.UR.x) + && (p1.y >= b.LL.y) && (p1.y <= b.UR.y); + inside2 = (p2.x >= b.LL.x) && (p2.x <= b.UR.x) + && (p2.y >= b.LL.y) && (p2.y <= b.UR.y); + if (inside1 != inside2) { + return 0; + } + if (inside1 & inside2) { + return 1; + } + + /* + * Both points are outside the rectangle, but still need to check + * for intersections between the line and the rectangle. Horizontal + * and vertical lines are particularly easy, so handle them + * separately. + */ + + if (p1.x == p2.x) { + /* + * Vertical line. + */ + + if (((p1.y >= b.LL.y) ^ (p2.y >= b.LL.y)) + && (p1.x >= b.LL.x) + && (p1.x <= b.UR.x)) { + return 0; + } + } else if (p1.y == p2.y) { + /* + * Horizontal line. + */ + if (((p1.x >= b.LL.x) ^ (p2.x >= b.LL.x)) + && (p1.y >= b.LL.y) + && (p1.y <= b.UR.y)) { + return 0; + } + } else { + double m, x, y, low, high; + + /* + * Diagonal line. Compute slope of line and use + * for intersection checks against each of the + * sides of the rectangle: left, right, bottom, top. + */ + + m = (p2.y - p1.y)/(p2.x - p1.x); + if (p1.x < p2.x) { + low = p1.x; high = p2.x; + } else { + low = p2.x; high = p1.x; + } + + /* + * Left edge. + */ + + y = p1.y + (b.LL.x - p1.x)*m; + if ((b.LL.x >= low) && (b.LL.x <= high) + && (y >= b.LL.y) && (y <= b.UR.y)) { + return 0; + } + + /* + * Right edge. + */ + + y += (b.UR.x - b.LL.x)*m; + if ((y >= b.LL.y) && (y <= b.UR.y) + && (b.UR.x >= low) && (b.UR.x <= high)) { + return 0; + } + + /* + * Bottom edge. + */ + + if (p1.y < p2.y) { + low = p1.y; high = p2.y; + } else { + low = p2.y; high = p1.y; + } + x = p1.x + (b.LL.y - p1.y)/m; + if ((x >= b.LL.x) && (x <= b.UR.x) + && (b.LL.y >= low) && (b.LL.y <= high)) { + return 0; + } + + /* + * Top edge. + */ + + x += (b.UR.y - b.LL.y)/m; + if ((x >= b.LL.x) && (x <= b.UR.x) + && (b.UR.y >= low) && (b.UR.y <= high)) { + return 0; + } + } + return -1; +} + boolean overlap_node(node_t *n, boxf b) { boxf bb; diff --git a/lib/common/utils.h b/lib/common/utils.h index c4729b6f9..dcc324951 100644 --- a/lib/common/utils.h +++ b/lib/common/utils.h @@ -25,8 +25,6 @@ extern "C" { #include "config.h" #endif -#include "geom.h" - #ifndef HAVE_STRCASECMP extern int strcasecmp(const char *s1, const char *s2); #endif @@ -57,6 +55,38 @@ extern "C" { extern void UF_singleton(Agnode_t *); extern void UF_setname(Agnode_t *, Agnode_t *); + extern point pointof(int, int); + extern pointf cvt2ptf(point); + extern point cvt2pt(pointf); + extern point add_points(point, point); + extern pointf add_pointfs(pointf, pointf); + extern point sub_points(point, point); + extern pointf sub_pointfs(pointf, pointf); + extern point exch_xy(point p); + extern pointf exch_xyf(pointf p); + extern point flip_pt(point p, int rankdir); + extern pointf flip_ptf(pointf p, int rankdir); + extern point invflip_pt(point p, int rankdir); + + extern box boxof(int llx, int lly, int urx, int ury); + extern boxf boxfof(double llx, double lly, double urx, double ury); + extern box mkbox(point, point); + extern boxf mkboxf(pointf, pointf); + extern box box_bb(box, box); + extern boxf boxf_bb(boxf, boxf); + extern box box_intersect(box, box); + extern boxf boxf_intersect(boxf, boxf); + extern boolean box_overlap(box, box); + extern boolean boxf_overlap(boxf, boxf); + extern boolean box_contains(box, box); + extern boolean boxf_contains(boxf, boxf); + extern box flip_rec_box(box b, point p); + + extern pointf Bezier(pointf *, int, double, pointf *, pointf *); + extern point dotneato_closest(splines * spl, point p); + extern point neato_closest(splines * spl, point p); + extern point spline_at_y(splines * spl, int y); + extern char *username(void); extern char *safefile(char *shapefilename); extern void cat_libfile(FILE *, char **, char **); diff --git a/lib/common/vrmlgen.c b/lib/common/vrmlgen.c index 493d849ce..963172530 100644 --- a/lib/common/vrmlgen.c +++ b/lib/common/vrmlgen.c @@ -91,6 +91,13 @@ typedef struct context_t { static context_t cstk[MAXNEST]; static int SP; +static double DIST2(pointf p, point q) +{ + double delx = p.x - q.x; + double dely = p.y - q.y; + return (delx*delx + dely*dely); +} + static char *nodeURL(node_t * n, char *buf) { sprintf(buf, "node%d.png", n->id); @@ -480,6 +487,16 @@ static void vrml_textline(point p, textline_t * line) } } +static double +idist2 (point p0, point p1) +{ + double delx, dely; + + delx = p0.x - p1.x; + dely = p0.y - p1.y; + return (delx*delx + dely*dely); +} + /* interpolate_zcoord: * Given 2 points in 3D p = (fst.x,fst.y,fstz) and q = (snd.x, snd.y, sndz), * and a point p1 in the xy plane lying on the line segment connecting @@ -502,8 +519,8 @@ interpolate_zcoord(pointf p1, point fst, double fstz, point snd, double sndz) rv = fstz + (sndz - fstz) * (p1.y - fst.y) / (snd.y - fst.y); } else { - len = DIST(fst, snd); - d = DIST(p1, fst)/len; + len = sqrt(idist2(fst, snd)); + d = sqrt(DIST2(p1, fst))/len; rv = fstz + d*(sndz - fstz); } return rv; @@ -552,8 +569,8 @@ doSegment (point* A, point p0, double z0, point p1, double z1) dely = p0.y - p1.y; delz = z0 - z1; EdgeLen = sqrt(delx*delx + dely*dely + delz*delz); - d0 = DIST(A[0],p0); - d1 = DIST(A[3],p1); + d0 = sqrt(idist2(A[0],p0)); + d1 = sqrt(idist2(A[3],p1)); CylHt = EdgeLen - d0 - d1; TailHt = HeadHt = 0; @@ -640,15 +657,15 @@ doArrowhead (point* A) p0.x = (A[0].x + A[2].x)/2.0; p0.y = (A[0].y + A[2].y)/2.0; - rad = DIST(A[0],A[2])/2.0; - ht = DIST(p0,A[1]); + rad = sqrt(idist2(A[0],A[2]))/2.0; + ht = sqrt(DIST2(p0,A[1])); y = (CylHt + ht)/2.0; tp = ND_coord_i(Curedge->tail); hp = ND_coord_i(Curedge->head); fprintf(Output_file, "Transform {\n"); - if (DIST2(A[1], tp) < DIST2(A[1], hp)) { + if (idist2(A[1], tp) < idist2(A[1], hp)) { TailHt = ht; fprintf(Output_file, " translation 0 -%.3f 0\n", y); fprintf(Output_file, " rotation 0 0 1 %.3f\n", PI); diff --git a/lib/dotgen/dotsplines.c b/lib/dotgen/dotsplines.c index 7e86d0b33..95cb2bd1a 100644 --- a/lib/dotgen/dotsplines.c +++ b/lib/dotgen/dotsplines.c @@ -1920,6 +1920,74 @@ static edge_t *bot_bound(edge_t * e, int side) return ans; } +static double dist2(pointf p, pointf q) /* square of distance between p and q */ +{ + double d0, d1; + + d0 = p.x - q.x; + d1 = p.y - q.y; + return (d0 * d0 + d1 * d1); +} + +point closest(splines * spl, point p) +{ + int i, j, k, besti, bestj; + double bestdist2, d2, dlow2, dhigh2; /* squares of distance */ + double low, high, t; + pointf c[4], pt2, pt; + point rv; + bezier bz; + + besti = bestj = -1; + bestdist2 = 1e+38; + P2PF(p, pt); + for (i = 0; i < spl->size; i++) { + bz = spl->list[i]; + for (j = 0; j < bz.size; j++) { + pointf b; + + b.x = bz.list[j].x; + b.y = bz.list[j].y; + d2 = dist2(b, pt); + if ((bestj == -1) || (d2 < bestdist2)) { + besti = i; + bestj = j; + bestdist2 = d2; + } + } + } + + bz = spl->list[besti]; + j = bestj / 3; + if (j >= spl->size) + j--; + for (k = 0; k < 4; k++) { + c[k].x = bz.list[j + k].x; + c[k].y = bz.list[j + k].y; + } + low = 0.0; + high = 1.0; + dlow2 = dist2(c[0], pt); + dhigh2 = dist2(c[3], pt); + do { + t = (low + high) / 2.0; + pt2 = Bezier(c, 3, t, NULL, NULL); + if (fabs(dlow2 - dhigh2) < 1.0) + break; + if (fabs(high - low) < .00001) + break; + if (dlow2 < dhigh2) { + high = t; + dhigh2 = dist2(pt2, pt); + } else { + low = t; + dlow2 = dist2(pt2, pt); + } + } while (1); + PF2P(pt2, rv); + return rv; +} + /* common routines */ edge_t* diff --git a/lib/neatogen/neatosplines.c b/lib/neatogen/neatosplines.c index a77d49b55..d63cc3fa0 100644 --- a/lib/neatogen/neatosplines.c +++ b/lib/neatogen/neatosplines.c @@ -160,7 +160,7 @@ static void addEdgeLabels(edge_t * e, point rp, point rq) del.y = q.y - p.y; dist2 = del.x*del.x + del.y*del.y; ht = (ED_label(e)->dimen.y + 2)/2.0; - sp = closest_spline_point(ED_spl(e), d); + sp = dotneato_closest(ED_spl(e), d); spf.x = sp.x; spf.y = sp.y; if (dist2) {