SUMO - Simulation of Urban MObility

GeomHelper.cpp

Go to the documentation of this file.
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 
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Friends Defines