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