00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
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) {
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
00284
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
00298 if (intersection(P[a1], P[a], Q[b1], Q[b], &p))
00299 return 1;
00300
00301
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 {
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;
00329 double x;
00330 double crossings = 0;
00331
00332 if (tp3 == NULL)
00333 tp3 = N_GNEW(maxcnt, Point);
00334
00335
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
00342 for (i = 0; i < n; i++) {
00343 i1 = (i + n - 1) % n;
00344
00345
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
00355 if (((tp3[i].y >= 0) && (tp3[i1].y <= 0)) ||
00356 ((tp3[i1].y >= 0) && (tp3[i].y <= 0))) {
00357
00358 x = (tp3[i].x * tp3[i1].y - tp3[i1].x * tp3[i].y)
00359 / (double) (tp3[i1].y - tp3[i].y);
00360
00361
00362 if (x == 0)
00363 return 1;;
00364
00365
00366 if (x > 0) {
00367 if ((tp3[i].y == 0) || (tp3[i1].y == 0)) {
00368 crossings += .5;
00369 } else {
00370 crossings += 1.0;
00371 }
00372 }
00373 }
00374 }
00375
00376
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
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
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 }