SUMO - Simulation of Urban MObility

GeomHelper.cpp

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