|
SUMO - Simulation of Urban MObility
|
00001 /****************************************************************************/ 00007 // Some geometrical helpers 00008 /****************************************************************************/ 00009 // SUMO, Simulation of Urban MObility; see http://sumo.sourceforge.net/ 00010 // Copyright (C) 2001-2011 DLR (http://www.dlr.de/) and contributors 00011 /****************************************************************************/ 00012 // 00013 // This program is free software; you can redistribute it and/or modify 00014 // it under the terms of the GNU General Public License as published by 00015 // the Free Software Foundation; either version 2 of the License, or 00016 // (at your option) any later version. 00017 // 00018 /****************************************************************************/ 00019 00020 00021 // =========================================================================== 00022 // included modules 00023 // =========================================================================== 00024 #ifdef _MSC_VER 00025 #include <windows_config.h> 00026 #else 00027 #include <config.h> 00028 #endif 00029 00030 #include <cmath> 00031 #include <algorithm> 00032 #include <iostream> 00033 #include "GeomHelper.h" 00034 #include <utils/common/StdDefs.h> 00035 #include <utils/common/ToString.h> 00036 00037 #ifdef CHECK_MEMORY_LEAKS 00038 #include <foreign/nvwa/debug_new.h> 00039 #endif // CHECK_MEMORY_LEAKS 00040 00041 00042 // =========================================================================== 00043 // method definitions 00044 // =========================================================================== 00045 bool 00046 GeomHelper::intersects(SUMOReal x1, SUMOReal y1, SUMOReal x2, SUMOReal y2, 00047 SUMOReal x3, SUMOReal y3, SUMOReal x4, SUMOReal y4) { 00048 /* Compute a1, b1, c1, where line joining points 1 and 2 00049 * is "a1 x + b1 y + c1 = 0". 00050 */ 00051 SUMOReal a1 = y2 - y1; 00052 SUMOReal b1 = x1 - x2; 00053 SUMOReal c1 = x2 * y1 - x1 * y2; 00054 00055 /* Compute r3 and r4. 00056 */ 00057 SUMOReal r3 = SUMOReal(a1 * x3 + b1 * y3 + c1); 00058 SUMOReal r4 = SUMOReal(a1 * x4 + b1 * y4 + c1); 00059 00060 /* Check signs of r3 and r4. If both point 3 and point 4 lie on 00061 * same side of line 1, the line segments do not intersect. 00062 */ 00063 if (r3 != 0 && 00064 r4 != 0 && 00065 ((r3<0&&r4<0)||(r3>0&&r4>0))) { 00066 return (false); 00067 } 00068 00069 /* Compute a2, b2, c2 */ 00070 SUMOReal a2 = y4 - y3; 00071 SUMOReal b2 = x3 - x4; 00072 SUMOReal c2 = x4 * y3 - x3 * y4; 00073 00074 /* Compute r1 and r2 */ 00075 SUMOReal r1 = a2 * x1 + b2 * y1 + c2; 00076 SUMOReal r2 = a2 * x2 + b2 * y2 + c2; 00077 00078 /* Check signs of r1 and r2. If both point 1 and point 2 lie 00079 * on same side of second line segment, the line segments do 00080 * not intersect. 00081 */ 00082 if (r1 != 0 && 00083 r2 != 0 && 00084 ((r1<0&&r2<0)||(r1>0&&r2>0))) { 00085 return (false); 00086 } 00087 00088 /* Line segments intersect: compute intersection point. 00089 */ 00090 SUMOReal denom = a1 * b2 - a2 * b1; 00091 if (denom == 0) { 00092 return (false); 00093 } 00094 // SUMOReal offset = denom < 0 ? - denom / 2 : denom / 2; 00095 00096 return true; 00097 } 00098 00099 00100 00101 00102 bool 00103 GeomHelper::intersects(const Position& p11, const Position& p12, 00104 const Position& p21, const Position& p22) { 00105 return intersects(p11.x(), p11.y(), p12.x(), p12.y(), 00106 p21.x(), p21.y(), p22.x(), p22.y()); 00107 } 00108 00109 00110 Position 00111 GeomHelper::intersection_position(const Position& p11, 00112 const Position& p12, 00113 const Position& p21, 00114 const Position& p22) { 00115 /*void Intersect_Lines(SUMOReal p11.x(),SUMOReal p11.y(),SUMOReal p12.x(),SUMOReal p12.y(), 00116 SUMOReal p21.x(),SUMOReal p21.y(),SUMOReal p22.x(),SUMOReal p22.y(), 00117 SUMOReal *xi,SUMOReal *yi) 00118 {*/ 00119 // this function computes the intersection of the sent lines 00120 // and returns the intersection point, note that the function assumes 00121 // the lines intersect. the function can handle vertical as well 00122 // as horizontal lines. note the function isn't very clever, it simply 00123 //applies the math, but we don't need speed since this is a 00124 //pre-processing step 00125 00126 double a1,b1,c1, // constants of linear equations 00127 a2,b2,c2, 00128 det_inv, m1, m2; // the inverse of the determinant of the coefficient 00129 00130 // compute slopes, note the cludge for infinity, however, this will 00131 // be close enough 00132 00133 if ((p12.x()-p11.x())!=0) { 00134 m1 = (p12.y()-p11.y())/(p12.x()-p11.x()); 00135 } else { 00136 m1 = (SUMOReal)1e+10; // close enough to infinity 00137 } 00138 00139 if ((p22.x()-p21.x())!=0) { 00140 m2 = (p22.y()-p21.y())/(p22.x()-p21.x()); 00141 } else { 00142 m2 = (SUMOReal)1e+10; // close enough to infinity 00143 } 00144 00145 // compute constants 00146 00147 a1 = m1; 00148 a2 = m2; 00149 00150 b1 = -1; 00151 b2 = -1; 00152 00153 c1 = (p11.y()-m1*p11.x()); 00154 c2 = (p21.y()-m2*p21.x()); 00155 00156 // compute the inverse of the determinate 00157 det_inv = 1/(a1*b2 - a2*b1); 00158 00159 // use Kramers rule to compute xi and yi 00160 return Position( 00161 ((b1*c2 - b2*c1)*det_inv), 00162 ((a2*c1 - a1*c2)*det_inv)); 00163 } 00164 00165 00166 00167 /* 00168 Return the angle between two vectors on a plane 00169 The angle is from vector 1 to vector 2, positive anticlockwise 00170 The result is between -pi -> pi 00171 */ 00172 SUMOReal 00173 GeomHelper::Angle2D(SUMOReal x1, SUMOReal y1, SUMOReal x2, SUMOReal y2) { 00174 SUMOReal dtheta = atan2(y2,x2) - atan2(y1,x1); 00175 while (dtheta > (SUMOReal) PI) { 00176 dtheta -= (SUMOReal)(2.0*PI); 00177 } 00178 while (dtheta < (SUMOReal) -PI) { 00179 dtheta += (SUMOReal)(2.0*PI); 00180 } 00181 return dtheta; 00182 } 00183 00184 00185 Position 00186 GeomHelper::interpolate(const Position& p1, 00187 const Position& p2, SUMOReal length) { 00188 const SUMOReal oldlen = p1.distanceTo(p2); 00189 const SUMOReal x = p1.x() + (p2.x() - p1.x()) * length / oldlen; 00190 const SUMOReal y = p1.y() + (p2.y() - p1.y()) * length / oldlen; 00191 return Position(x, y); 00192 } 00193 00194 00195 Position 00196 GeomHelper::extrapolate_first(const Position& p1, 00197 const Position& p2, SUMOReal length) { 00198 const SUMOReal oldlen = p1.distanceTo(p2); 00199 const SUMOReal x = p1.x() - (p2.x() - p1.x()) * length / oldlen; 00200 const SUMOReal y = p1.y() - (p2.y() - p1.y()) * length / oldlen; 00201 return Position(x, y); 00202 } 00203 00204 00205 Position 00206 GeomHelper::extrapolate_second(const Position& p1, 00207 const Position& p2, SUMOReal length) { 00208 const SUMOReal oldlen = p1.distanceTo(p2); 00209 const SUMOReal x = p2.x() - (p1.x() - p2.x()) * length / oldlen; 00210 const SUMOReal y = p2.y() - (p1.y() - p2.y()) * length / oldlen; 00211 return Position(x, y); 00212 } 00213 00214 00215 SUMOReal 00216 GeomHelper::nearest_position_on_line_to_point(const Position& LineStart, 00217 const Position& LineEnd, 00218 const Position& Point, bool perpendicular) { 00219 SUMOReal u = (((Point.x() - LineStart.x()) * (LineEnd.x() - LineStart.x())) + 00220 ((Point.y() - LineStart.y()) * (LineEnd.y() - LineStart.y())) 00221 ) / LineStart.distanceSquaredTo(LineEnd); 00222 if (u < 0.0f || u > 1.0f) { // closest point does not fall within the line segment 00223 if (perpendicular) { 00224 return -1; 00225 } 00226 if (u < 0.0f) { 00227 return 0.0f; 00228 } 00229 return LineStart.distanceTo(LineEnd); 00230 } 00231 return u * LineStart.distanceTo(LineEnd); 00232 } 00233 00234 00235 SUMOReal 00236 GeomHelper::distancePointLine(const Position& point, 00237 const Position& lineStart, 00238 const Position& lineEnd) { 00239 SUMOReal u = (((point.x() - lineStart.x()) * (lineEnd.x() - lineStart.x())) + 00240 ((point.y() - lineStart.y()) * (lineEnd.y() - lineStart.y())) 00241 ) / lineStart.distanceSquaredTo(lineEnd); 00242 if (u < 0.0f || u > 1.0f) { 00243 return -1; // closest point does not fall within the line segment 00244 } 00245 Position intersection( 00246 lineStart.x() + u *(lineEnd.x() - lineStart.x()), 00247 lineStart.y() + u *(lineEnd.y() - lineStart.y())); 00248 return point.distanceTo(intersection); 00249 } 00250 00251 00252 00253 SUMOReal 00254 GeomHelper::closestDistancePointLine(const Position& point, 00255 const Position& lineStart, 00256 const Position& lineEnd, 00257 Position& outIntersection) { 00258 Position directVec(lineEnd.x()-lineStart.x(), lineEnd.y()-lineStart.y()); 00259 SUMOReal u = (((point.x() - lineStart.x()) * directVec.x()) + 00260 ((point.y() - lineStart.y()) * directVec.y())) / 00261 (directVec.x() * directVec.x() + 00262 directVec.y() * directVec.y()); 00263 00264 // if closest point does not fall within the line segment 00265 // return line start or line end 00266 00267 if (u >= 0.0f && u <= 1.0f) { 00268 outIntersection.set( 00269 lineStart.x() + u * directVec.x(), 00270 lineStart.y() + u * directVec.y()); 00271 } else { 00272 if (u < 0.0f) { 00273 outIntersection = lineStart; 00274 } 00275 if (u > 1.0f) { 00276 outIntersection = lineEnd; 00277 } 00278 } 00279 return point.distanceTo(outIntersection); 00280 } 00281 00282 00283 00284 Position 00285 GeomHelper::transfer_to_side(Position& p, 00286 const Position& lineBeg, 00287 const Position& lineEnd, 00288 SUMOReal amount) { 00289 const SUMOReal dx = lineBeg.x() - lineEnd.x(); 00290 const SUMOReal dy = lineBeg.y() - lineEnd.y(); 00291 const SUMOReal length = sqrt(dx*dx + dy*dy); 00292 if (length > 0) { 00293 p.add(dy*amount/length, -dx*amount/length); 00294 } 00295 return p; 00296 } 00297 00298 00299 00300 Position 00301 GeomHelper::crossPoint(const Boundary& b, const PositionVector& v) { 00302 if (v.intersects(Position(b.xmin(), b.ymin()), Position(b.xmin(), b.ymax()))) { 00303 return v.intersectsAtPoint( 00304 Position(b.xmin(), b.ymin()), 00305 Position(b.xmin(), b.ymax())); 00306 } 00307 if (v.intersects(Position(b.xmax(), b.ymin()), Position(b.xmax(), b.ymax()))) { 00308 return v.intersectsAtPoint( 00309 Position(b.xmax(), b.ymin()), 00310 Position(b.xmax(), b.ymax())); 00311 } 00312 if (v.intersects(Position(b.xmin(), b.ymin()), Position(b.xmax(), b.ymin()))) { 00313 return v.intersectsAtPoint( 00314 Position(b.xmin(), b.ymin()), 00315 Position(b.xmax(), b.ymin())); 00316 } 00317 if (v.intersects(Position(b.xmin(), b.ymax()), Position(b.xmax(), b.ymax()))) { 00318 return v.intersectsAtPoint( 00319 Position(b.xmin(), b.ymax()), 00320 Position(b.xmax(), b.ymax())); 00321 } 00322 throw 1; 00323 } 00324 00325 std::pair<SUMOReal, SUMOReal> 00326 GeomHelper::getNormal90D_CW(const Position& beg, 00327 const Position& end, 00328 SUMOReal wanted_offset) { 00329 const SUMOReal length = sqrt((beg.x()-end.x())*(beg.x()-end.x()) + (beg.y()-end.y())*(beg.y()-end.y())); 00330 return getNormal90D_CW(beg, end, length, wanted_offset); 00331 } 00332 00333 00334 std::pair<SUMOReal, SUMOReal> 00335 GeomHelper::getNormal90D_CW(const Position& beg, 00336 const Position& end, 00337 SUMOReal length, SUMOReal wanted_offset) { 00338 if (beg == end) { 00339 throw InvalidArgument("same points at " + toString(beg)); 00340 } 00341 return std::pair<SUMOReal, SUMOReal> 00342 ((beg.y()-end.y())*wanted_offset/length, (end.x()-beg.x())*wanted_offset/length); 00343 } 00344 00345 00346 SUMOReal 00347 GeomHelper::getCCWAngleDiff(SUMOReal angle1, SUMOReal angle2) throw() { 00348 SUMOReal v = angle2 - angle1; 00349 if (v<0) { 00350 v = 360 + v; 00351 } 00352 return v; 00353 } 00354 00355 00356 SUMOReal 00357 GeomHelper::getCWAngleDiff(SUMOReal angle1, SUMOReal angle2) throw() { 00358 SUMOReal v = angle1 - angle2; 00359 if (v<0) { 00360 v = 360 + v; 00361 } 00362 return v; 00363 } 00364 00365 00366 SUMOReal 00367 GeomHelper::getMinAngleDiff(SUMOReal angle1, SUMOReal angle2) throw() { 00368 return MIN2(getCWAngleDiff(angle1, angle2), getCCWAngleDiff(angle1, angle2)); 00369 } 00370 00371 00372 SUMOReal 00373 GeomHelper::getMaxAngleDiff(SUMOReal angle1, SUMOReal angle2) throw() { 00374 return MAX2(getCWAngleDiff(angle1, angle2), getCCWAngleDiff(angle1, angle2)); 00375 } 00376 00377 00378 00379 /****************************************************************************/ 00380