/misc/src/release/graphviz-2.18-1/src/graphviz-2.18/lib/common/geom.c

Go to the documentation of this file.
00001 /* $Id: geom.c,v 1.16 2006/12/07 22:49:35 erg Exp $ $Revision: 1.16 $ */
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 /* geometric functions (e.g. on points and boxes) with application to, but
00018  * no specific dependance on graphs */
00019 
00020 #include "geom.h"
00021 #include "geomprocs.h"
00022 
00023 point pointof(int x, int y)
00024 {
00025     point rv;
00026     rv.x = x, rv.y = y;
00027     return rv;
00028 }
00029 
00030 pointf pointfof(double x, double y)
00031 {
00032     pointf rv;
00033     rv.x = x, rv.y = y;
00034     return rv;
00035 }
00036 
00037 point cvt2pt(pointf p)
00038 {
00039     point rv;
00040     rv.x = POINTS(p.x);
00041     rv.y = POINTS(p.y);
00042     return rv;
00043 }
00044 
00045 pointf cvt2ptf(point p)
00046 {
00047     pointf rv;
00048     rv.x = PS2INCH(p.x);
00049     rv.y = PS2INCH(p.y);
00050     return rv;
00051 }
00052 
00053 box boxof(int llx, int lly, int urx, int ury)
00054 {
00055     box b;
00056 
00057     b.LL.x = llx, b.LL.y = lly;
00058     b.UR.x = urx, b.UR.y = ury;
00059     return b;
00060 }
00061 
00062 boxf boxfof(double llx, double lly, double urx, double ury)
00063 {
00064     boxf b;
00065 
00066     b.LL.x = llx, b.LL.y = lly;
00067     b.UR.x = urx, b.UR.y = ury;
00068     return b;
00069 }
00070 
00071 box mkbox(point p0, point p1)
00072 {
00073     box rv;
00074 
00075     if (p0.x < p1.x) {
00076         rv.LL.x = p0.x;
00077         rv.UR.x = p1.x;
00078     } else {
00079         rv.LL.x = p1.x;
00080         rv.UR.x = p0.x;
00081     }
00082     if (p0.y < p1.y) {
00083         rv.LL.y = p0.y;
00084         rv.UR.y = p1.y;
00085     } else {
00086         rv.LL.y = p1.y;
00087         rv.UR.y = p0.y;
00088     }
00089     return rv;
00090 }
00091 
00092 boxf mkboxf(pointf p0, pointf p1)
00093 {
00094     boxf rv;
00095 
00096     if (p0.x < p1.x) {
00097         rv.LL.x = p0.x;
00098         rv.UR.x = p1.x;
00099     } else {
00100         rv.LL.x = p1.x;
00101         rv.UR.x = p0.x;
00102     }
00103     if (p0.y < p1.y) {
00104         rv.LL.y = p0.y;
00105         rv.UR.y = p1.y;
00106     } else {
00107         rv.LL.y = p1.y;
00108         rv.UR.y = p0.y;
00109     }
00110     return rv;
00111 }
00112 
00113 point add_points(point p0, point p1)
00114 {
00115     p0.x += p1.x;
00116     p0.y += p1.y;
00117     return p0;
00118 }
00119 
00120 point sub_points(point p0, point p1)
00121 {
00122     p0.x -= p1.x;
00123     p0.y -= p1.y;
00124     return p0;
00125 }
00126 
00127 pointf add_pointfs(pointf p0, pointf p1)
00128 {
00129     p0.x += p1.x;
00130     p0.y += p1.y;
00131     return p0;
00132 }
00133 
00134 pointf sub_pointfs(pointf p0, pointf p1)
00135 {
00136     p0.x -= p1.x;
00137     p0.y -= p1.y;
00138     return p0;
00139 }
00140 
00141 point exch_xy(point p)
00142 {
00143     int t;
00144     t = p.x;
00145     p.x = p.y;
00146     p.y = t;
00147     return p;
00148 }
00149 
00150 pointf exch_xyf(pointf p)
00151 {
00152     double t;
00153     t = p.x;
00154     p.x = p.y;
00155     p.y = t;
00156     return p;
00157 }
00158 
00159 box box_bb(box b0, box b1)
00160 {
00161     box b;
00162 
00163     b.LL.x = MIN(b0.LL.x, b1.LL.x);
00164     b.LL.y = MIN(b0.LL.y, b1.LL.y);
00165     b.UR.x = MAX(b0.UR.x, b1.UR.x);
00166     b.UR.y = MAX(b0.UR.y, b1.UR.y);
00167 
00168     return b;
00169 }
00170 
00171 boxf boxf_bb(boxf b0, boxf b1)
00172 {
00173     boxf b;
00174 
00175     b.LL.x = MIN(b0.LL.x, b1.LL.x);
00176     b.LL.y = MIN(b0.LL.y, b1.LL.y);
00177     b.UR.x = MAX(b0.UR.x, b1.UR.x);
00178     b.UR.y = MAX(b0.UR.y, b1.UR.y);
00179 
00180     return b;
00181 }
00182 
00183 box box_intersect(box b0, box b1)
00184 {
00185     box b;
00186 
00187     b.LL.x = MAX(b0.LL.x, b1.LL.x);
00188     b.LL.y = MAX(b0.LL.y, b1.LL.y);
00189     b.UR.x = MIN(b0.UR.x, b1.UR.x);
00190     b.UR.y = MIN(b0.UR.y, b1.UR.y);
00191 
00192     return b;
00193 }
00194 
00195 boxf boxf_intersect(boxf b0, boxf b1)
00196 {
00197     boxf b;
00198 
00199     b.LL.x = MAX(b0.LL.x, b1.LL.x);
00200     b.LL.y = MAX(b0.LL.y, b1.LL.y);
00201     b.UR.x = MIN(b0.UR.x, b1.UR.x);
00202     b.UR.y = MIN(b0.UR.y, b1.UR.y);
00203 
00204     return b;
00205 }
00206 
00207 int box_overlap(box b0, box b1)
00208 {
00209     return OVERLAP(b0, b1);
00210 }
00211 
00212 int boxf_overlap(boxf b0, boxf b1)
00213 {
00214     return OVERLAP(b0, b1);
00215 }
00216 
00217 int box_contains(box b0, box b1)
00218 {
00219     return CONTAINS(b0, b1);
00220 }
00221 
00222 int boxf_contains(boxf b0, boxf b1)
00223 {
00224     return CONTAINS(b0, b1);
00225 }
00226 
00227 /*
00228  *--------------------------------------------------------------
00229  *
00230  * lineToBox --
00231  *
00232  *      Determine whether a line lies entirely inside, entirely
00233  *      outside, or overlapping a given rectangular area.
00234  *
00235  * Results:
00236  *      -1 is returned if the line given by p1 and p2
00237  *      is entirely outside the rectangle given by b.
00238  *      0 is returned if the polygon overlaps the rectangle, and
00239  *      1 is returned if the polygon is entirely inside the rectangle.
00240  *
00241  * Side effects:
00242  *      None.
00243  *
00244  *--------------------------------------------------------------
00245  */
00246 
00247 /* This code steals liberally from algorithms in tk/generic/tkTrig.c -- jce */
00248 
00249 int lineToBox(pointf p1, pointf p2, boxf b)
00250 {
00251     int inside1, inside2;
00252 
00253     /*
00254      * First check the two points individually to see whether they
00255      * are inside the rectangle or not.
00256      */
00257 
00258     inside1 = (p1.x >= b.LL.x) && (p1.x <= b.UR.x)
00259             && (p1.y >= b.LL.y) && (p1.y <= b.UR.y);
00260     inside2 = (p2.x >= b.LL.x) && (p2.x <= b.UR.x)
00261             && (p2.y >= b.LL.y) && (p2.y <= b.UR.y);
00262     if (inside1 != inside2) {
00263         return 0;
00264     }
00265     if (inside1 & inside2) {
00266         return 1;
00267     }
00268 
00269     /*
00270      * Both points are outside the rectangle, but still need to check
00271      * for intersections between the line and the rectangle.  Horizontal
00272      * and vertical lines are particularly easy, so handle them
00273      * separately.
00274      */
00275 
00276     if (p1.x == p2.x) {
00277         /*
00278          * Vertical line.
00279          */
00280 
00281         if (((p1.y >= b.LL.y) ^ (p2.y >= b.LL.y))
00282                 && (p1.x >= b.LL.x)
00283                 && (p1.x <= b.UR.x)) {
00284             return 0;
00285         }
00286     } else if (p1.y == p2.y) {
00287         /*
00288          * Horizontal line.
00289          */
00290         if (((p1.x >= b.LL.x) ^ (p2.x >= b.LL.x))
00291                 && (p1.y >= b.LL.y)
00292                 && (p1.y <= b.UR.y)) {
00293             return 0;
00294         }
00295     } else {
00296         double m, x, y, low, high;
00297 
00298         /*
00299          * Diagonal line.  Compute slope of line and use
00300          * for intersection checks against each of the
00301          * sides of the rectangle: left, right, bottom, top.
00302          */
00303 
00304         m = (p2.y - p1.y)/(p2.x - p1.x);
00305         if (p1.x < p2.x) {
00306             low = p1.x;  high = p2.x;
00307         } else {
00308             low = p2.x; high = p1.x;
00309         }
00310 
00311         /*
00312          * Left edge.
00313          */
00314 
00315         y = p1.y + (b.LL.x - p1.x)*m;
00316         if ((b.LL.x >= low) && (b.LL.x <= high)
00317                 && (y >= b.LL.y) && (y <= b.UR.y)) {
00318             return 0;
00319         }
00320 
00321         /*
00322          * Right edge.
00323          */
00324 
00325         y += (b.UR.x - b.LL.x)*m;
00326         if ((y >= b.LL.y) && (y <= b.UR.y)
00327                 && (b.UR.x >= low) && (b.UR.x <= high)) {
00328             return 0;
00329         }
00330 
00331         /*
00332          * Bottom edge.
00333          */
00334 
00335         if (p1.y < p2.y) {
00336             low = p1.y;  high = p2.y;
00337         } else {
00338             low = p2.y; high = p1.y;
00339         }
00340         x = p1.x + (b.LL.y - p1.y)/m;
00341         if ((x >= b.LL.x) && (x <= b.UR.x)
00342                 && (b.LL.y >= low) && (b.LL.y <= high)) {
00343             return 0;
00344         }
00345 
00346         /*
00347          * Top edge.
00348          */
00349 
00350         x += (b.UR.y - b.LL.y)/m;
00351         if ((x >= b.LL.x) && (x <= b.UR.x)
00352                 && (b.UR.y >= low) && (b.UR.y <= high)) {
00353             return 0;
00354         }
00355     }
00356     return -1;
00357 }
00358 
00359 void rect2poly(pointf *p)
00360 {
00361     p[3].x = p[2].x = p[1].x;
00362     p[2].y = p[1].y;
00363     p[3].y = p[0].y;
00364     p[1].x = p[0].x;
00365 }
00366 
00367 static pointf rotatepf(pointf p, int cwrot)
00368 {
00369     static double sina, cosa;
00370     static int last_cwrot;
00371     pointf P;
00372 
00373     /* cosa is initially wrong for a cwrot of 0
00374      * this caching only works because we are never called for 0 rotations */
00375     if (cwrot != last_cwrot) {
00376         sincos(cwrot / (2 * M_PI), &sina, &cosa);
00377         last_cwrot = cwrot;
00378     }
00379     P.x = p.x * cosa - p.y * sina;
00380     P.y = p.y * cosa + p.x * sina;
00381     return P;
00382 }
00383 
00384 static point rotatep(point p, int cwrot)
00385 {
00386     pointf pf;
00387 
00388     P2PF(p, pf);
00389     pf = rotatepf(pf, cwrot);
00390     PF2P(pf, p);
00391     return p;
00392 }
00393 
00394 point cwrotatep(point p, int cwrot)
00395 {
00396     int x = p.x, y = p.y;
00397     switch (cwrot) {
00398     case 0:
00399         break;
00400     case 90:
00401         p.x = y;
00402         p.y = -x;
00403         break;
00404     case 180:
00405         p.x = x;
00406         p.y = -y;
00407         break;
00408     case 270:
00409         p.x = y;
00410         p.y = x;
00411         break;
00412     default:
00413         if (cwrot < 0)
00414             return ccwrotatep(p, -cwrot);
00415         if (cwrot > 360)
00416             return cwrotatep(p, cwrot%360);
00417         return rotatep(p, cwrot);
00418     }
00419     return p;
00420 }
00421 
00422 pointf cwrotatepf(pointf p, int cwrot)
00423 {
00424     double x = p.x, y = p.y;
00425     switch (cwrot) {
00426     case 0:
00427         break;
00428     case 90:
00429         p.x = y;
00430         p.y = -x;
00431         break;
00432     case 180:
00433         p.x = x;
00434         p.y = -y;
00435         break;
00436     case 270:
00437         p.x = y;
00438         p.y = x;
00439         break;
00440     default:
00441         if (cwrot < 0)
00442             return ccwrotatepf(p, -cwrot);
00443         if (cwrot > 360)
00444             return cwrotatepf(p, cwrot%360);
00445         return rotatepf(p, cwrot);
00446     }
00447     return p;
00448 }
00449 
00450 point ccwrotatep(point p, int ccwrot)
00451 {
00452     int x = p.x, y = p.y;
00453     switch (ccwrot) {
00454     case 0:
00455         break;
00456     case 90:
00457         p.x = -y;
00458         p.y = x;
00459         break;
00460     case 180:
00461         p.x = x;
00462         p.y = -y;
00463         break;
00464     case 270:
00465         p.x = y;
00466         p.y = x;
00467         break;
00468     default:
00469         if (ccwrot < 0)
00470             return cwrotatep(p, -ccwrot);
00471         if (ccwrot > 360)
00472             return ccwrotatep(p, ccwrot%360);
00473         return rotatep(p, 360-ccwrot);
00474     }
00475     return p;
00476 }
00477 
00478 pointf ccwrotatepf(pointf p, int ccwrot)
00479 {
00480     double x = p.x, y = p.y;
00481     switch (ccwrot) {
00482     case 0:
00483         break;
00484     case 90:
00485         p.x = -y;
00486         p.y = x;
00487         break;
00488     case 180:
00489         p.x = x;
00490         p.y = -y;
00491         break;
00492     case 270:
00493         p.x = y;
00494         p.y = x;
00495         break;
00496     default:
00497         if (ccwrot < 0)
00498             return cwrotatepf(p, -ccwrot);
00499         if (ccwrot > 360)
00500             return ccwrotatepf(p, ccwrot%360);
00501         return rotatepf(p, 360-ccwrot);
00502     }
00503     return p;
00504 }
00505 
00506 box flip_rec_box(box b, point p)
00507 {
00508     box rv;
00509     /* flip box */
00510     rv.UR.x = b.UR.y;
00511     rv.UR.y = b.UR.x;
00512     rv.LL.x = b.LL.y;
00513     rv.LL.y = b.LL.x;
00514     /* move box */
00515     rv.LL.x += p.x;
00516     rv.LL.y += p.y;
00517     rv.UR.x += p.x;
00518     rv.UR.y += p.y;
00519     return rv;
00520 }
00521 
00522 /* ptToLine2:
00523  * Return distance from point p to line a-b squared.
00524  */
00525 double ptToLine2 (pointf a, pointf b, pointf p)
00526 {
00527   double dx = b.x-a.x;
00528   double dy = b.y-a.y;
00529   double a2 = (p.y-a.y)*dx - (p.x-a.x)*dy;
00530   a2 *= a2;   /* square - ensures that it is positive */
00531   if (a2 < .00001) return 0.;  /* avoid 0/0 problems */
00532   return a2 / (dx*dx + dy*dy);
00533 }

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