/misc/src/release/graphviz-2.18-1/src/graphviz-2.18/lib/neatogen/poly.c

Go to the documentation of this file.
00001 /* $Id: poly.c,v 1.5 2008/03/03 23:01:52 ellson Exp $ $Revision: 1.5 $ */
00002 /* vim:set shiftwidth=4 ts=8: */
00003 
00004 /**********************************************************
00005 *      This software is part of the graphviz package      *
00006 *                http://www.graphviz.org/                 *
00007 *                                                         *
00008 *            Copyright (c) 1994-2004 AT&T Corp.           *
00009 *                and is licensed under the                *
00010 *            Common Public License, Version 1.0           *
00011 *                      by AT&T Corp.                      *
00012 *                                                         *
00013 *        Information and Software Systems Research        *
00014 *              AT&T Research, Florham Park NJ             *
00015 **********************************************************/
00016 
00017 /* poly.c
00018  */
00019 
00020 #include "neato.h"
00021 #include <assert.h>
00022 #include <string.h>
00023 #include <math.h>
00024 #include "poly.h"
00025 #include "mem.h"
00026 
00027 
00028 #define BOX 1
00029 #define ISBOX(p) ((p)->kind & BOX)
00030 #define CIRCLE 2
00031 #define ISCIRCLE(p) ((p)->kind & CIRCLE)
00032 
00033 static int maxcnt = 0;
00034 static Point *tp1 = NULL;
00035 static Point *tp2 = NULL;
00036 static Point *tp3 = NULL;
00037 
00038 void polyFree()
00039 {
00040     maxcnt = 0;
00041     free(tp1);
00042     free(tp2);
00043     free(tp3);
00044     tp1 = NULL;
00045     tp2 = NULL;
00046     tp3 = NULL;
00047 }
00048 
00049 void breakPoly(Poly * pp)
00050 {
00051     free(pp->verts);
00052 }
00053 
00054 static void bbox(Point * verts, int cnt, Point * o, Point * c)
00055 {
00056     double xmin, ymin, xmax, ymax;
00057     int i;
00058 
00059     xmin = xmax = verts->x;
00060     ymin = ymax = verts->y;
00061     for (i = 1; i < cnt; i++) {
00062         verts++;
00063         if (verts->x < xmin)
00064             xmin = verts->x;
00065         if (verts->y < ymin)
00066             ymin = verts->y;
00067         if (verts->x > xmax)
00068             xmax = verts->x;
00069         if (verts->y > ymax)
00070             ymax = verts->y;
00071     }
00072     o->x = xmin;
00073     o->y = ymin;
00074     c->x = xmax;
00075     c->y = ymax;
00076 }
00077 
00078 #ifdef OLD
00079 static void inflate(Point * prev, Point * cur, Point * next, double margin)
00080 {
00081     double theta = atan2(prev->y - cur->y, prev->x - cur->x);
00082     double phi = atan2(next->y - cur->y, next->x - cur->x);
00083     double beta = (theta + phi) / 2.0;
00084     double gamma = (M_PI + phi - theta) / 2.0;
00085     double denom;
00086 
00087     denom = cos(gamma);
00088     cur->x -= margin * (cos(beta)) / denom;
00089     cur->y -= margin * (sin(beta)) / denom;
00090 }
00091 
00092 static void inflatePts(Point * verts, int cnt, double margin)
00093 {
00094     int i;
00095     Point first;
00096     Point savepoint;
00097     Point prevpoint;
00098     Point *prev = &prevpoint;
00099     Point *cur;
00100     Point *next;
00101 
00102     first = verts[0];
00103     prevpoint = verts[cnt - 1];
00104     cur = &verts[0];
00105     next = &verts[1];
00106     for (i = 0; i < cnt - 1; i++) {
00107         savepoint = *cur;
00108         inflate(prev, cur, next, margin);
00109         cur++;
00110         next++;
00111         prevpoint = savepoint;
00112     }
00113 
00114     next = &first;
00115     inflate(prev, cur, next, margin);
00116 }
00117 #else
00118 static void inflatePts(Point * verts, int cnt, double margin)
00119 {
00120     int i;
00121     Point *cur;
00122 
00123     cur = &verts[0];
00124     for (i = 0; i < cnt; i++) {
00125         cur->x *= margin;
00126         cur->y *= margin;
00127         cur++;
00128     }
00129 }
00130 #endif
00131 
00132 static int isBox(Point * verts, int cnt)
00133 {
00134     if (cnt != 4)
00135         return 0;
00136 
00137     if (verts[0].y == verts[1].y)
00138         return ((verts[2].y == verts[3].y) &&
00139                 (verts[0].x == verts[3].x) && (verts[1].x == verts[2].x));
00140     else
00141         return ((verts[0].x == verts[1].x) &&
00142                 (verts[2].x == verts[3].x) &&
00143                 (verts[0].y == verts[3].y) && (verts[1].y == verts[2].y));
00144 }
00145 
00146 static Point makeScaledPoint(int x, int y)
00147 {
00148     Point rv;
00149     rv.x = PS2INCH(x);
00150     rv.y = PS2INCH(y);
00151     return rv;
00152 }
00153 
00154 static Point *genRound(Agnode_t * n, int *sidep)
00155 {
00156     int sides = 0;
00157     Point *verts;
00158     char *p = agget(n, "samplepoints");
00159     int i;
00160 
00161     if (p)
00162         sides = atoi(p);
00163     if (sides < 3)
00164         sides = DFLT_SAMPLE;
00165     verts = N_GNEW(sides, Point);
00166     for (i = 0; i < sides; i++) {
00167         verts[i].x =
00168             ND_width(n) / 2.0 * cos(i / (double) sides * M_PI * 2.0);
00169         verts[i].y =
00170             ND_height(n) / 2.0 * sin(i / (double) sides * M_PI * 2.0);
00171     }
00172     *sidep = sides;
00173     return verts;
00174 }
00175 
00176 #define PUTPT(P,X,Y) ((P).x=(X),(P).y=(Y))
00177 
00178 void makePoly(Poly * pp, Agnode_t * n, double margin)
00179 {
00180     int i;
00181     int sides;
00182     Point *verts;
00183     polygon_t *poly;
00184     box b;
00185 
00186     if (ND_clust(n)) {
00187         Point b;
00188         sides = 4;
00189         b.x = ND_width(n) / 2.0;
00190         b.y = ND_height(n) / 2.0;
00191         pp->kind = BOX;
00192         verts = N_GNEW(sides, Point);
00193         PUTPT(verts[0], b.x, b.y);
00194         PUTPT(verts[1], -b.x, b.y);
00195         PUTPT(verts[2], -b.x, -b.y);
00196         PUTPT(verts[3], b.x, -b.y);
00197     } else
00198         switch (shapeOf(n)) {
00199         case SH_POLY:
00200             poly = (polygon_t *) ND_shape_info(n);
00201             sides = poly->sides;
00202             if (sides >= 3) {   /* real polygon */
00203                 verts = N_GNEW(sides, Point);
00204                 for (i = 0; i < sides; i++) {
00205                     verts[i].x = PS2INCH(poly->vertices[i].x);
00206                     verts[i].y = PS2INCH(poly->vertices[i].y);
00207                 }
00208             } else
00209                 verts = genRound(n, &sides);
00210 
00211             if (streq(ND_shape(n)->name, "box"))
00212                 pp->kind = BOX;
00213             else if (streq(ND_shape(n)->name, "polygon")
00214                      && isBox(verts, sides))
00215                 pp->kind = BOX;
00216             else if ((poly->sides < 3) && poly->regular)
00217                 pp->kind = CIRCLE;
00218             else
00219                 pp->kind = 0;
00220 
00221             break;
00222         case SH_RECORD:
00223             sides = 4;
00224             verts = N_GNEW(sides, Point);
00225             b = ((field_t *) ND_shape_info(n))->b;
00226             verts[0] = makeScaledPoint(b.LL.x, b.LL.y);
00227             verts[1] = makeScaledPoint(b.UR.x, b.LL.y);
00228             verts[2] = makeScaledPoint(b.UR.x, b.UR.y);
00229             verts[3] = makeScaledPoint(b.LL.x, b.UR.y);
00230             pp->kind = BOX;
00231             break;
00232         case SH_POINT:
00233             pp->kind = CIRCLE;
00234             verts = genRound(n, &sides);
00235             break;
00236         default:
00237             agerr(AGERR, "makePoly: unknown shape type %s\n",
00238                   ND_shape(n)->name);
00239             exit(1);
00240         }
00241 
00242 #ifdef OLD
00243     if (margin != 0.0)
00244         inflatePts(verts, sides, margin);
00245 #else
00246     if (margin != 1.0)
00247         inflatePts(verts, sides, margin);
00248 #endif
00249 
00250     pp->verts = verts;
00251     pp->nverts = sides;
00252     bbox(verts, sides, &pp->origin, &pp->corner);
00253 
00254     if (sides > maxcnt)
00255         maxcnt = sides;
00256 }
00257 
00258 static int
00259 pintersect(Point originp, Point cornerp, Point originq, Point cornerq)
00260 {
00261     return ((originp.x <= cornerq.x) && (originq.x <= cornerp.x) &&
00262             (originp.y <= cornerq.y) && (originq.y <= cornerp.y));
00263 }
00264 
00265 #define Pin 1
00266 #define Qin 2
00267 #define Unknown 0
00268 
00269 #define advance(A,B,N) (B++, A = (A+1)%N)
00270 
00271 static int edgesIntersect(Point * P, Point * Q, int n, int m)
00272 {
00273     int a = 0;
00274     int b = 0;
00275     int aa = 0;
00276     int ba = 0;
00277     int a1, b1;
00278     Point A, B;
00279     double cross;
00280     int bHA, aHB;
00281     Point p;
00282     int inflag = Unknown;
00283     /* int      i = 0; */
00284     /* int      Reset = 0; */
00285 
00286     do {
00287         a1 = (a + n - 1) % n;
00288         b1 = (b + m - 1) % m;
00289 
00290         subPt(&A, P[a], P[a1]);
00291         subPt(&B, Q[b], Q[b1]);
00292 
00293         cross = area_2(origin, A, B);
00294         bHA = leftOf(P[a1], P[a], Q[b]);
00295         aHB = leftOf(Q[b1], Q[b], P[a]);
00296 
00297         /* If A & B intersect, update inflag. */
00298         if (intersection(P[a1], P[a], Q[b1], Q[b], &p))
00299             return 1;
00300 
00301         /* Advance rules. */
00302         if ((cross == 0) && !bHA && !aHB) {
00303             if (inflag == Pin)
00304                 advance(b, ba, m);
00305             else
00306                 advance(a, aa, n);
00307         } else if (cross >= 0)
00308             if (bHA)
00309                 advance(a, aa, n);
00310             else {
00311                 advance(b, ba, m);
00312         } else {                /* if ( cross < 0 ) */
00313 
00314             if (aHB)
00315                 advance(b, ba, m);
00316             else
00317                 advance(a, aa, n);
00318         }
00319 
00320     } while (((aa < n) || (ba < m)) && (aa < 2 * n) && (ba < 2 * m));
00321 
00322     return 0;
00323 
00324 }
00325 
00326 static int inPoly(Point vertex[], int n, Point q)
00327 {
00328     int i, i1;                  /* point index; i1 = i-1 mod n */
00329     double x;                   /* x intersection of e with ray */
00330     double crossings = 0;       /* number of edge/ray crossings */
00331 
00332     if (tp3 == NULL)
00333         tp3 = N_GNEW(maxcnt, Point);
00334 
00335     /* Shift so that q is the origin. */
00336     for (i = 0; i < n; i++) {
00337         tp3[i].x = vertex[i].x - q.x;
00338         tp3[i].y = vertex[i].y - q.y;
00339     }
00340 
00341     /* For each edge e=(i-1,i), see if crosses ray. */
00342     for (i = 0; i < n; i++) {
00343         i1 = (i + n - 1) % n;
00344 
00345         /* if edge is horizontal, test to see if the point is on it */
00346         if ((tp3[i].y == 0) && (tp3[i1].y == 0)) {
00347             if ((tp3[i].x * tp3[i1].x) < 0) {
00348                 return 1;
00349             } else {
00350                 continue;
00351             }
00352         }
00353 
00354         /* if e straddles the x-axis... */
00355         if (((tp3[i].y >= 0) && (tp3[i1].y <= 0)) ||
00356             ((tp3[i1].y >= 0) && (tp3[i].y <= 0))) {
00357             /* e straddles ray, so compute intersection with ray. */
00358             x = (tp3[i].x * tp3[i1].y - tp3[i1].x * tp3[i].y)
00359                 / (double) (tp3[i1].y - tp3[i].y);
00360 
00361             /* if intersect at origin, we've found intersection */
00362             if (x == 0)
00363                 return 1;;
00364 
00365             /* crosses ray if strictly positive intersection. */
00366             if (x > 0) {
00367                 if ((tp3[i].y == 0) || (tp3[i1].y == 0)) {
00368                     crossings += .5;    /* goes thru vertex */
00369                 } else {
00370                     crossings += 1.0;
00371                 }
00372             }
00373         }
00374     }
00375 
00376     /* q inside if an odd number of crossings. */
00377     if ((((int) crossings) % 2) == 1)
00378         return 1;
00379     else
00380         return 0;
00381 }
00382 
00383 static int inBox(Point p, Point origin, Point corner)
00384 {
00385     return ((p.x <= corner.x) &&
00386             (p.x >= origin.x) && (p.y <= corner.y) && (p.y >= origin.y));
00387 
00388 }
00389 
00390 static void transCopy(Point * inp, int cnt, Point off, Point * outp)
00391 {
00392     int i;
00393 
00394     for (i = 0; i < cnt; i++) {
00395         outp->x = inp->x + off.x;
00396         outp->y = inp->y + off.y;
00397         inp++;
00398         outp++;
00399     }
00400 }
00401 
00402 int polyOverlap(Point p, Poly * pp, Point q, Poly * qp)
00403 {
00404     Point op, cp;
00405     Point oq, cq;
00406 
00407     /* translate bounding boxes */
00408     addPt(&op, p, pp->origin);
00409     addPt(&cp, p, pp->corner);
00410     addPt(&oq, q, qp->origin);
00411     addPt(&cq, q, qp->corner);
00412 
00413     /* If bounding boxes don't overlap, done */
00414     if (!pintersect(op, cp, oq, cq))
00415         return 0;
00416 
00417     if (ISBOX(pp) && ISBOX(qp))
00418         return 1;
00419     if (ISCIRCLE(pp) && ISCIRCLE(qp)) {
00420         double d =
00421             (pp->corner.x - pp->origin.x + qp->corner.x - qp->origin.x);
00422         double dx = p.x - q.x;
00423         double dy = p.y - q.y;
00424         if ((dx * dx + dy * dy) > (d * d) / 4.0)
00425             return 0;
00426         else
00427             return 1;
00428     }
00429 
00430     if (tp1 == NULL) {
00431         tp1 = N_GNEW(maxcnt, Point);
00432         tp2 = N_GNEW(maxcnt, Point);
00433     }
00434 
00435     transCopy(pp->verts, pp->nverts, p, tp1);
00436     transCopy(qp->verts, qp->nverts, q, tp2);
00437     return (edgesIntersect(tp1, tp2, pp->nverts, qp->nverts) ||
00438             (inBox(*tp1, oq, cq) && inPoly(tp2, qp->nverts, *tp1)) ||
00439             (inBox(*tp2, op, cp) && inPoly(tp1, pp->nverts, *tp2)));
00440 }

Generated on Mon Mar 31 19:03:27 2008 for Graphviz by  doxygen 1.5.1