Graphviz  2.31.20130522.0446
lib/common/geom.c
Go to the documentation of this file.
00001 /* $Id$ $Revision$ */
00002 /* vim:set shiftwidth=4 ts=8: */
00003 
00004 /*************************************************************************
00005  * Copyright (c) 2011 AT&T Intellectual Property 
00006  * All rights reserved. This program and the accompanying materials
00007  * are made available under the terms of the Eclipse Public License v1.0
00008  * which accompanies this distribution, and is available at
00009  * http://www.eclipse.org/legal/epl-v10.html
00010  *
00011  * Contributors: See CVS logs. Details at http://www.graphviz.org/
00012  *************************************************************************/
00013 
00014 /* geometric functions (e.g. on points and boxes) with application to, but
00015  * no specific dependance on graphs */
00016 
00017 #ifdef HAVE_CONFIG_H
00018 #include "config.h"
00019 #endif
00020 
00021 #include "geom.h"
00022 #include "geomprocs.h"
00023 #ifdef WIN32
00024 #define inline 
00025 #endif
00026 
00027 box mkbox(point p, point q)
00028 {
00029     box r;
00030 
00031     if (p.x < q.x) {
00032         r.LL.x = p.x;
00033         r.UR.x = q.x;
00034     } else {
00035         r.LL.x = q.x;
00036         r.UR.x = p.x;
00037     }
00038     if (p.y < q.y) {
00039         r.LL.y = p.y;
00040         r.UR.y = q.y;
00041     } else {
00042         r.LL.y = q.y;
00043         r.UR.y = p.y;
00044     }
00045     return r;
00046 }
00047 
00048 boxf mkboxf(pointf p, pointf q)
00049 {
00050     boxf r;
00051 
00052     if (p.x < q.x) {
00053         r.LL.x = p.x;
00054         r.UR.x = q.x;
00055     } else {
00056         r.LL.x = q.x;
00057         r.UR.x = p.x;
00058     }
00059     if (p.y < q.y) {
00060         r.LL.y = p.y;
00061         r.UR.y = q.y;
00062     } else {
00063         r.LL.y = q.y;
00064         r.UR.y = p.y;
00065     }
00066     return r;
00067 }
00068 
00069 /*
00070  *--------------------------------------------------------------
00071  *
00072  * lineToBox --
00073  *
00074  *      Determine whether a line lies entirely inside, entirely
00075  *      outside, or overlapping a given rectangular area.
00076  *
00077  * Results:
00078  *      -1 is returned if the line given by p and q
00079  *      is entirely outside the rectangle given by b.
00080  *      0 is returned if the polygon overlaps the rectangle, and
00081  *      1 is returned if the polygon is entirely inside the rectangle.
00082  *
00083  * Side effects:
00084  *      None.
00085  *
00086  *--------------------------------------------------------------
00087  */
00088 
00089 /* This code steals liberally from algorithms in tk/generic/tkTrig.c -- jce */
00090 
00091 int lineToBox(pointf p, pointf q, boxf b)
00092 {
00093     int inside1, inside2;
00094 
00095     /*
00096      * First check the two points individually to see whether they
00097      * are inside the rectangle or not.
00098      */
00099 
00100     inside1 = (p.x >= b.LL.x) && (p.x <= b.UR.x)
00101             && (p.y >= b.LL.y) && (p.y <= b.UR.y);
00102     inside2 = (q.x >= b.LL.x) && (q.x <= b.UR.x)
00103             && (q.y >= b.LL.y) && (q.y <= b.UR.y);
00104     if (inside1 != inside2) {
00105         return 0;
00106     }
00107     if (inside1 & inside2) {
00108         return 1;
00109     }
00110 
00111     /*
00112      * Both points are outside the rectangle, but still need to check
00113      * for intersections between the line and the rectangle.  Horizontal
00114      * and vertical lines are particularly easy, so handle them
00115      * separately.
00116      */
00117 
00118     if (p.x == q.x) {
00119         /*
00120          * Vertical line.
00121          */
00122 
00123         if (((p.y >= b.LL.y) ^ (q.y >= b.LL.y))
00124                 && (p.x >= b.LL.x)
00125                 && (p.x <= b.UR.x)) {
00126             return 0;
00127         }
00128     } else if (p.y == q.y) {
00129         /*
00130          * Horizontal line.
00131          */
00132         if (((p.x >= b.LL.x) ^ (q.x >= b.LL.x))
00133                 && (p.y >= b.LL.y)
00134                 && (p.y <= b.UR.y)) {
00135             return 0;
00136         }
00137     } else {
00138         double m, x, y, low, high;
00139 
00140         /*
00141          * Diagonal line.  Compute slope of line and use
00142          * for intersection checks against each of the
00143          * sides of the rectangle: left, right, bottom, top.
00144          */
00145 
00146         m = (q.y - p.y)/(q.x - p.x);
00147         if (p.x < q.x) {
00148             low = p.x;  high = q.x;
00149         } else {
00150             low = q.x; high = p.x;
00151         }
00152 
00153         /*
00154          * Left edge.
00155          */
00156 
00157         y = p.y + (b.LL.x - p.x)*m;
00158         if ((b.LL.x >= low) && (b.LL.x <= high)
00159                 && (y >= b.LL.y) && (y <= b.UR.y)) {
00160             return 0;
00161         }
00162 
00163         /*
00164          * Right edge.
00165          */
00166 
00167         y += (b.UR.x - b.LL.x)*m;
00168         if ((y >= b.LL.y) && (y <= b.UR.y)
00169                 && (b.UR.x >= low) && (b.UR.x <= high)) {
00170             return 0;
00171         }
00172 
00173         /*
00174          * Bottom edge.
00175          */
00176 
00177         if (p.y < q.y) {
00178             low = p.y;  high = q.y;
00179         } else {
00180             low = q.y; high = p.y;
00181         }
00182         x = p.x + (b.LL.y - p.y)/m;
00183         if ((x >= b.LL.x) && (x <= b.UR.x)
00184                 && (b.LL.y >= low) && (b.LL.y <= high)) {
00185             return 0;
00186         }
00187 
00188         /*
00189          * Top edge.
00190          */
00191 
00192         x += (b.UR.y - b.LL.y)/m;
00193         if ((x >= b.LL.x) && (x <= b.UR.x)
00194                 && (b.UR.y >= low) && (b.UR.y <= high)) {
00195             return 0;
00196         }
00197     }
00198     return -1;
00199 }
00200 #ifdef WIN32_STATIC
00201 #define inline
00202 #endif
00203 void rect2poly(pointf *p)
00204 {
00205     p[3].x = p[2].x = p[1].x;
00206     p[2].y = p[1].y;
00207     p[3].y = p[0].y;
00208     p[1].x = p[0].x;
00209 }
00210 
00211 static pointf rotatepf(pointf p, int cwrot)
00212 {
00213     static double sina, cosa;
00214     static int last_cwrot;
00215     pointf P;
00216 
00217     /* cosa is initially wrong for a cwrot of 0
00218      * this caching only works because we are never called for 0 rotations */
00219     if (cwrot != last_cwrot) {
00220         sincos(cwrot / (2 * M_PI), &sina, &cosa);
00221         last_cwrot = cwrot;
00222     }
00223     P.x = p.x * cosa - p.y * sina;
00224     P.y = p.y * cosa + p.x * sina;
00225     return P;
00226 }
00227 
00228 static point rotatep(point p, int cwrot)
00229 {
00230     pointf pf;
00231 
00232     P2PF(p, pf);
00233     pf = rotatepf(pf, cwrot);
00234     PF2P(pf, p);
00235     return p;
00236 }
00237 
00238 point cwrotatep(point p, int cwrot)
00239 {
00240     int x = p.x, y = p.y;
00241     switch (cwrot) {
00242     case 0:
00243         break;
00244     case 90:
00245         p.x = y;
00246         p.y = -x;
00247         break;
00248     case 180:
00249         p.x = x;
00250         p.y = -y;
00251         break;
00252     case 270:
00253         p.x = y;
00254         p.y = x;
00255         break;
00256     default:
00257         if (cwrot < 0)
00258             return ccwrotatep(p, -cwrot);
00259         if (cwrot > 360)
00260             return cwrotatep(p, cwrot%360);
00261         return rotatep(p, cwrot);
00262     }
00263     return p;
00264 }
00265 
00266 pointf cwrotatepf(pointf p, int cwrot)
00267 {
00268     double x = p.x, y = p.y;
00269     switch (cwrot) {
00270     case 0:
00271         break;
00272     case 90:
00273         p.x = y;
00274         p.y = -x;
00275         break;
00276     case 180:
00277         p.x = x;
00278         p.y = -y;
00279         break;
00280     case 270:
00281         p.x = y;
00282         p.y = x;
00283         break;
00284     default:
00285         if (cwrot < 0)
00286             return ccwrotatepf(p, -cwrot);
00287         if (cwrot > 360)
00288             return cwrotatepf(p, cwrot%360);
00289         return rotatepf(p, cwrot);
00290     }
00291     return p;
00292 }
00293 
00294 point ccwrotatep(point p, int ccwrot)
00295 {
00296     int x = p.x, y = p.y;
00297     switch (ccwrot) {
00298     case 0:
00299         break;
00300     case 90:
00301         p.x = -y;
00302         p.y = x;
00303         break;
00304     case 180:
00305         p.x = x;
00306         p.y = -y;
00307         break;
00308     case 270:
00309         p.x = y;
00310         p.y = x;
00311         break;
00312     default:
00313         if (ccwrot < 0)
00314             return cwrotatep(p, -ccwrot);
00315         if (ccwrot > 360)
00316             return ccwrotatep(p, ccwrot%360);
00317         return rotatep(p, 360-ccwrot);
00318     }
00319     return p;
00320 }
00321 
00322 pointf ccwrotatepf(pointf p, int ccwrot)
00323 {
00324     double x = p.x, y = p.y;
00325     switch (ccwrot) {
00326     case 0:
00327         break;
00328     case 90:
00329         p.x = -y;
00330         p.y = x;
00331         break;
00332     case 180:
00333         p.x = x;
00334         p.y = -y;
00335         break;
00336     case 270:
00337         p.x = y;
00338         p.y = x;
00339         break;
00340     default:
00341         if (ccwrot < 0)
00342             return cwrotatepf(p, -ccwrot);
00343         if (ccwrot > 360)
00344             return ccwrotatepf(p, ccwrot%360);
00345         return rotatepf(p, 360-ccwrot);
00346     }
00347     return p;
00348 }
00349 
00350 inline box flip_rec_box(box b, point p)
00351 {
00352     box r;
00353     /* flip box */
00354     r.UR.x = b.UR.y;
00355     r.UR.y = b.UR.x;
00356     r.LL.x = b.LL.y;
00357     r.LL.y = b.LL.x;
00358     /* move box */
00359     r.LL.x += p.x;
00360     r.LL.y += p.y;
00361     r.UR.x += p.x;
00362     r.UR.y += p.y;
00363     return r;
00364 }
00365 
00366 boxf flip_rec_boxf(boxf b, pointf p)
00367 {
00368     boxf r;
00369     /* flip box */
00370     r.UR.x = b.UR.y;
00371     r.UR.y = b.UR.x;
00372     r.LL.x = b.LL.y;
00373     r.LL.y = b.LL.x;
00374     /* move box */
00375     r.LL.x += p.x;
00376     r.LL.y += p.y;
00377     r.UR.x += p.x;
00378     r.UR.y += p.y;
00379     return r;
00380 }
00381 
00382 #ifdef WIN32_STATIC
00383 #undef inline
00384 #endif
00385 
00386 
00387 #define SMALL 0.0000000001
00388 
00389 /* ptToLine2:
00390  * Return distance from point p to line a-b squared.
00391  */
00392 double ptToLine2 (pointf a, pointf b, pointf p)
00393 {
00394   double dx = b.x-a.x;
00395   double dy = b.y-a.y;
00396   double a2 = (p.y-a.y)*dx - (p.x-a.x)*dy;
00397   a2 *= a2;   /* square - ensures that it is positive */
00398   if (a2 < SMALL) return 0.;  /* avoid 0/0 problems */
00399   return a2 / (dx*dx + dy*dy);
00400 }
00401 
00402 #define dot(v,w) (v.x*w.x+v.y*w.y)
00403 
00404 /* line_intersect:
00405  * Computes intersection of lines a-b and c-d, returning intersection
00406  * point in *p.
00407  * Returns 0 if no intersection (lines parallel), 1 otherwise.
00408  */
00409 int line_intersect (pointf a, pointf b, pointf c, pointf d, pointf* p)
00410 {
00411 
00412     pointf mv = sub_pointf(b,a);
00413     pointf lv = sub_pointf(d,c);
00414     pointf ln = perp (lv);
00415     double lc = -dot(ln,c);
00416     double dt = dot(ln,mv);
00417 
00418     if (fabs(dt) < SMALL) return 0;
00419 
00420     *p = sub_pointf(a,scale((dot(ln,a)+lc)/dt,mv));
00421     return 1;
00422 }
00423