|
Graphviz
2.31.20130522.0446
|
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
1.7.5