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 2001-2010 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     /* Compute a2, b2, c2 */
00069     SUMOReal a2 = y4 - y3;
00070     SUMOReal b2 = x3 - x4;
00071     SUMOReal c2 = x4 * y3 - x3 * y4;
00072 
00073     /* Compute r1 and r2 */
00074     SUMOReal r1 = a2 * x1 + b2 * y1 + c2;
00075     SUMOReal r2 = a2 * x2 + b2 * y2 + c2;
00076 
00077     /* Check signs of r1 and r2.  If both point 1 and point 2 lie
00078      * on same side of second line segment, the line segments do
00079      * not intersect.
00080      */
00081     if (r1 != 0 &&
00082             r2 != 0 &&
00083             ((r1<0&&r2<0)||(r1>0&&r2>0)))
00084         return (false);
00085 
00086     /* Line segments intersect: compute intersection point.
00087      */
00088     SUMOReal denom = a1 * b2 - a2 * b1;
00089     if (denom == 0)
00090         return (false);
00091 //    SUMOReal offset = denom < 0 ? - denom / 2 : denom / 2;
00092 
00093     return true;
00094 }
00095 
00096 
00097 
00098 
00099 bool
00100 GeomHelper::intersects(const Position2D &p11, const Position2D &p12,
00101                        const Position2D &p21, const Position2D &p22) {
00102     return intersects(p11.x(), p11.y(), p12.x(), p12.y(),
00103                       p21.x(), p21.y(), p22.x(), p22.y());
00104 }
00105 
00106 
00107 Position2D
00108 GeomHelper::intersection_position(const Position2D &p11,
00109                                   const Position2D &p12,
00110                                   const Position2D &p21,
00111                                   const Position2D &p22) {
00112     /*void Intersect_Lines(SUMOReal p11.x(),SUMOReal p11.y(),SUMOReal p12.x(),SUMOReal p12.y(),
00113                          SUMOReal p21.x(),SUMOReal p21.y(),SUMOReal p22.x(),SUMOReal p22.y(),
00114                          SUMOReal *xi,SUMOReal *yi)
00115     {*/
00116     // this function computes the intersection of the sent lines
00117     // and returns the intersection point, note that the function assumes
00118     // the lines intersect. the function can handle vertical as well
00119     // as horizontal lines. note the function isn't very clever, it simply
00120     //applies the math, but we don't need speed since this is a
00121     //pre-processing step
00122 
00123     double a1,b1,c1, // constants of linear equations
00124     a2,b2,c2,
00125     det_inv, m1, m2;  // the inverse of the determinant of the coefficient
00126 
00127     // compute slopes, note the cludge for infinity, however, this will
00128     // be close enough
00129 
00130     if ((p12.x()-p11.x())!=0)
00131         m1 = (p12.y()-p11.y())/(p12.x()-p11.x());
00132     else
00133         m1 = (SUMOReal)1e+10;   // close enough to infinity
00134 
00135     if ((p22.x()-p21.x())!=0)
00136         m2 = (p22.y()-p21.y())/(p22.x()-p21.x());
00137     else
00138         m2 = (SUMOReal)1e+10;   // close enough to infinity
00139 
00140     // compute constants
00141 
00142     a1 = m1;
00143     a2 = m2;
00144 
00145     b1 = -1;
00146     b2 = -1;
00147 
00148     c1 = (p11.y()-m1*p11.x());
00149     c2 = (p21.y()-m2*p21.x());
00150 
00151     // compute the inverse of the determinate
00152     det_inv = 1/(a1*b2 - a2*b1);
00153 
00154     // use Kramers rule to compute xi and yi
00155     return Position2D(
00156                ((b1*c2 - b2*c1)*det_inv),
00157                ((a2*c1 - a1*c2)*det_inv));
00158 }
00159 
00160 
00161 
00162 /*
00163    Return the angle between two vectors on a plane
00164    The angle is from vector 1 to vector 2, positive anticlockwise
00165    The result is between -pi -> pi
00166 */
00167 SUMOReal
00168 GeomHelper::Angle2D(SUMOReal x1, SUMOReal y1, SUMOReal x2, SUMOReal y2) {
00169     SUMOReal dtheta,theta1,theta2;
00170 
00171     theta1 = atan2(y1,x1);
00172     theta2 = atan2(y2,x2);
00173     dtheta = theta2 - theta1;
00174     while (dtheta > (SUMOReal) PI)
00175         dtheta -= (SUMOReal)(2.0*PI);
00176     while (dtheta < (SUMOReal) -PI)
00177         dtheta += (SUMOReal)(2.0*PI);
00178 
00179     return(dtheta);
00180 }
00181 
00182 
00183 Position2D
00184 GeomHelper::interpolate(const Position2D &p1,
00185                         const Position2D &p2, SUMOReal length) {
00186     SUMOReal oldlen = p1.distanceTo(p2);
00187     SUMOReal x = p1.x() + (p2.x() - p1.x()) * length / oldlen;
00188     SUMOReal y = p1.y() + (p2.y() - p1.y()) * length / oldlen;
00189     return Position2D(x, y);
00190 }
00191 
00192 
00193 Position2D
00194 GeomHelper::extrapolate_first(const Position2D &p1,
00195                               const Position2D &p2, SUMOReal length) {
00196     SUMOReal oldlen = p1.distanceTo(p2);
00197     SUMOReal x = p1.x() - (p2.x() - p1.x()) * (length) / oldlen;
00198     SUMOReal y = p1.y() - (p2.y() - p1.y()) * (length) / oldlen;
00199     return Position2D(x, y);
00200 }
00201 
00202 
00203 Position2D
00204 GeomHelper::extrapolate_second(const Position2D &p1,
00205                                const Position2D &p2, SUMOReal length) {
00206     SUMOReal oldlen = p1.distanceTo(p2);
00207     SUMOReal x = p2.x() - (p1.x() - p2.x()) * (length) / oldlen;
00208     SUMOReal y = p2.y() - (p1.y() - p2.y()) * (length) / oldlen;
00209     return Position2D(x, y);
00210 }
00211 
00212 
00213 SUMOReal
00214 GeomHelper::nearest_position_on_line_to_point(const Position2D &LineStart,
00215         const Position2D &LineEnd,
00216         const Position2D &Point) {
00217     SUMOReal u = (((Point.x() - LineStart.x()) * (LineEnd.x() - LineStart.x())) +
00218                   ((Point.y() - LineStart.y()) * (LineEnd.y() - LineStart.y()))
00219                  ) / LineStart.distanceSquaredTo(LineEnd);
00220     if (u < 0.0f || u > 1.0f)
00221         return -1;   // closest point does not fall within the line segment
00222     return u * LineStart.distanceTo(LineEnd);
00223 }
00224 
00225 
00226 SUMOReal
00227 GeomHelper::distancePointLine(const Position2D &point,
00228                               const Position2D &lineStart,
00229                               const Position2D &lineEnd) {
00230     SUMOReal u = (((point.x() - lineStart.x()) * (lineEnd.x() - lineStart.x())) +
00231                   ((point.y() - lineStart.y()) * (lineEnd.y() - lineStart.y()))
00232                  ) / lineStart.distanceSquaredTo(lineEnd);
00233     if (u < 0.0f || u > 1.0f)
00234         return -1;   // closest point does not fall within the line segment
00235     Position2D intersection(
00236         lineStart.x() + u *(lineEnd.x() - lineStart.x()),
00237         lineStart.y() + u *(lineEnd.y() - lineStart.y()));
00238     return point.distanceTo(intersection);
00239 }
00240 
00241 
00242 
00243 SUMOReal
00244 GeomHelper::closestDistancePointLine(const Position2D &point,
00245                                      const Position2D &lineStart,
00246                                      const Position2D &lineEnd,
00247                                      Position2D& outIntersection) {
00248     Position2D directVec(lineEnd.x()-lineStart.x(), lineEnd.y()-lineStart.y());
00249     SUMOReal u = (((point.x() - lineStart.x()) * directVec.x()) +
00250                   ((point.y() - lineStart.y()) * directVec.y())) /
00251                  (directVec.x() * directVec.x() +
00252                   directVec.y() * directVec.y());
00253 
00254     // if closest point does not fall within the line segment
00255     // return line start or line end
00256 
00257     if (u >= 0.0f && u <= 1.0f) {
00258         outIntersection.set(
00259             lineStart.x() + u * directVec.x(),
00260             lineStart.y() + u * directVec.y());
00261     } else {
00262         if (u < 0.0f) {
00263             outIntersection = lineStart;
00264         }
00265         if (u > 1.0f) {
00266             outIntersection = lineEnd;
00267         }
00268     }
00269     return point.distanceTo(outIntersection);
00270 }
00271 
00272 
00273 
00274 Position2D
00275 GeomHelper::transfer_to_side(Position2D &p,
00276                              const Position2D &lineBeg,
00277                              const Position2D &lineEnd,
00278                              SUMOReal amount) {
00279     SUMOReal dx = lineBeg.x() - lineEnd.x();
00280     SUMOReal dy = lineBeg.y() - lineEnd.y();
00281     SUMOReal length = sqrt(
00282                           (lineBeg.x() - lineEnd.x())*(lineBeg.x() - lineEnd.x())
00283                           +
00284                           (lineBeg.y() - lineEnd.y())*(lineBeg.y() - lineEnd.y()));
00285     if (dx<0) { // fromX<toX -> to right
00286         if (dy>0) { // to up right -> lanes to down right (+, +)
00287             p.add(dy*amount/length, -dx*amount/length);
00288         } else if (dy<0) { // to down right -> lanes to down left (-, +)
00289             p.add(dy*amount/length, -dx*amount/length);
00290         } else { // to right -> lanes to down (0, +)
00291             p.add(0, -dx*amount/length);
00292         }
00293     } else if (dx>0) { // fromX>toX -> to left
00294         if (dy>0) { // to up left -> lanes to up right (+, -)
00295             p.add(dy*amount/length, -dx*amount/length);
00296         } else if (dy<0) { // to down left -> lanes to up left (-, -)
00297             p.add(dy*amount/length, -dx*amount/length);
00298         } else { // to left -> lanes to up (0, -)
00299             p.add(0, -dx*amount/length);
00300         }
00301     } else { // fromX==toX
00302         if (dy>0) { // to up -> lanes to right (+, 0)
00303             p.add(dy*amount/length, 0);
00304         } else if (dy<0) { // to down -> lanes to left (-, 0)
00305             p.add(dy*amount/length, 0);
00306         } else { // zero !
00307             throw 1;
00308         }
00309     }
00310     return p;
00311 }
00312 
00313 
00314 
00315 Position2D
00316 GeomHelper::crossPoint(const Boundary &b, const Position2DVector &v) {
00317     if (v.intersects(Position2D(b.xmin(), b.ymin()), Position2D(b.xmin(), b.ymax()))) {
00318         return v.intersectsAtPoint(
00319                    Position2D(b.xmin(), b.ymin()),
00320                    Position2D(b.xmin(), b.ymax()));
00321     }
00322     if (v.intersects(Position2D(b.xmax(), b.ymin()), Position2D(b.xmax(), b.ymax()))) {
00323         return v.intersectsAtPoint(
00324                    Position2D(b.xmax(), b.ymin()),
00325                    Position2D(b.xmax(), b.ymax()));
00326     }
00327     if (v.intersects(Position2D(b.xmin(), b.ymin()), Position2D(b.xmax(), b.ymin()))) {
00328         return v.intersectsAtPoint(
00329                    Position2D(b.xmin(), b.ymin()),
00330                    Position2D(b.xmax(), b.ymin()));
00331     }
00332     if (v.intersects(Position2D(b.xmin(), b.ymax()), Position2D(b.xmax(), b.ymax()))) {
00333         return v.intersectsAtPoint(
00334                    Position2D(b.xmin(), b.ymax()),
00335                    Position2D(b.xmax(), b.ymax()));
00336     }
00337     throw 1;
00338 }
00339 
00340 std::pair<SUMOReal, SUMOReal>
00341 GeomHelper::getNormal90D_CW(const Position2D &beg,
00342                             const Position2D &end,
00343                             SUMOReal wanted_offset) {
00344     SUMOReal length = sqrt((beg.x()-end.x())*(beg.x()-end.x()) + (beg.y()-end.y())*(beg.y()-end.y()));
00345     return getNormal90D_CW(beg, end, length, wanted_offset);
00346 }
00347 
00348 
00349 std::pair<SUMOReal, SUMOReal>
00350 GeomHelper::getNormal90D_CW(const Position2D &beg,
00351                             const Position2D &end,
00352                             SUMOReal length, SUMOReal wanted_offset) {
00353     if (beg == end) {
00354         throw InvalidArgument("same points at " + toString(beg));
00355     }
00356     return std::pair<SUMOReal, SUMOReal>
00357            ((beg.y()-end.y())*wanted_offset/length, (end.x()-beg.x())*wanted_offset/length);
00358 }
00359 
00360 
00361 SUMOReal
00362 GeomHelper::getCCWAngleDiff(SUMOReal angle1, SUMOReal angle2) throw() {
00363     if (angle1<0) {
00364         angle1 = 360 + angle1;
00365     }
00366     if (angle2<0) {
00367         angle2 = 360 + angle2;
00368     }
00369     if (angle1>=angle2) {
00370         return angle1 - angle2;
00371     }
00372     return angle1 + 360 - angle2;
00373 }
00374 
00375 
00376 SUMOReal
00377 GeomHelper::getCWAngleDiff(SUMOReal angle1, SUMOReal angle2) throw() {
00378     if (angle1<0) {
00379         angle1 = 360 + angle1;
00380     }
00381     if (angle2<0) {
00382         angle2 = 360 + angle2;
00383     }
00384     if (angle1<=angle2) {
00385         return angle2 - angle1;
00386     }
00387     return 360 - angle1 + angle2;
00388 }
00389 
00390 
00391 SUMOReal
00392 GeomHelper::getMinAngleDiff(SUMOReal angle1, SUMOReal angle2) throw() {
00393     return MIN2(getCWAngleDiff(angle1, angle2), getCCWAngleDiff(angle1, angle2));
00394 }
00395 
00396 
00397 SUMOReal
00398 GeomHelper::getMaxAngleDiff(SUMOReal angle1, SUMOReal angle2) throw() {
00399     return MAX2(getCWAngleDiff(angle1, angle2), getCCWAngleDiff(angle1, angle2));
00400 }
00401 
00402 
00403 
00404 /****************************************************************************/
00405 

Generated on Wed May 5 00:06:29 2010 for Sumo - Simulation of Urban MObility by  doxygen 1.5.6