LCOV - code coverage report
Current view: top level - src/utils/geom - GeomHelper.cpp (source / functions) Coverage Total Hit
Test: lcov.info Lines: 68.9 % 151 104
Test Date: 2024-11-22 15:46:21 Functions: 82.4 % 17 14

            Line data    Source code
       1              : /****************************************************************************/
       2              : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
       3              : // Copyright (C) 2001-2024 German Aerospace Center (DLR) and others.
       4              : // This program and the accompanying materials are made available under the
       5              : // terms of the Eclipse Public License 2.0 which is available at
       6              : // https://www.eclipse.org/legal/epl-2.0/
       7              : // This Source Code may also be made available under the following Secondary
       8              : // Licenses when the conditions for such availability set forth in the Eclipse
       9              : // Public License 2.0 are satisfied: GNU General Public License, version 2
      10              : // or later which is available at
      11              : // https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html
      12              : // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
      13              : /****************************************************************************/
      14              : /// @file    GeomHelper.cpp
      15              : /// @author  Daniel Krajzewicz
      16              : /// @author  Friedemann Wesner
      17              : /// @author  Jakob Erdmann
      18              : /// @author  Michael Behrisch
      19              : /// @date    Sept 2002
      20              : ///
      21              : // Some static methods performing geometrical operations
      22              : /****************************************************************************/
      23              : #include <config.h>
      24              : 
      25              : #include <cmath>
      26              : #include <limits>
      27              : #include <algorithm>
      28              : #include <iostream>
      29              : #include <utils/common/StdDefs.h>
      30              : #include <utils/common/ToString.h>
      31              : #include <utils/common/MsgHandler.h>
      32              : #include "Boundary.h"
      33              : #include "GeomHelper.h"
      34              : 
      35              : // ===========================================================================
      36              : // static members
      37              : // ===========================================================================
      38              : const double GeomHelper::INVALID_OFFSET = -1;
      39              : 
      40              : 
      41              : // ===========================================================================
      42              : // method definitions
      43              : // ===========================================================================
      44              : 
      45              : void
      46        58616 : GeomHelper::findLineCircleIntersections(const Position& c, double radius, const Position& p1, const Position& p2,
      47              :                                         std::vector<double>& into) {
      48        58616 :     const double dx = p2.x() - p1.x();
      49        58616 :     const double dy = p2.y() - p1.y();
      50              : 
      51        58616 :     const double A = dx * dx + dy * dy;
      52        58616 :     const double B = 2 * (dx * (p1.x() - c.x()) + dy * (p1.y() - c.y()));
      53        58616 :     const double C = (p1.x() - c.x()) * (p1.x() - c.x()) + (p1.y() - c.y()) * (p1.y() - c.y()) - radius * radius;
      54              : 
      55        58616 :     const double det = B * B - 4 * A * C;
      56        58616 :     if ((A <= 0.0000001) || (det < 0)) {
      57              :         // No real solutions.
      58              :         return;
      59              :     }
      60        39164 :     if (det == 0) {
      61              :         // One solution.
      62            0 :         const double t = -B / (2 * A);
      63            0 :         if (t >= 0. && t <= 1.) {
      64            0 :             into.push_back(t);
      65              :         }
      66              :     } else {
      67              :         // Two solutions.
      68        39164 :         const double t = (double)((-B + sqrt(det)) / (2 * A));
      69              :         Position intersection(p1.x() + t * dx, p1.y() + t * dy);
      70        39164 :         if (t >= 0. && t <= 1.) {
      71          492 :             into.push_back(t);
      72              :         }
      73        39164 :         const double t2 = (double)((-B - sqrt(det)) / (2 * A));
      74        39164 :         if (t2 >= 0. && t2 <= 1.) {
      75          520 :             into.push_back(t2);
      76              :         }
      77              :     }
      78              : }
      79              : 
      80              : 
      81              : double
      82    161710921 : GeomHelper::angle2D(const Position& p1, const Position& p2) {
      83    161710921 :     return angleDiff(atan2(p1.y(), p1.x()), atan2(p2.y(), p2.x()));
      84              : }
      85              : 
      86              : 
      87              : double
      88     78935874 : GeomHelper::nearest_offset_on_line_to_point2D(const Position& lineStart,
      89              :         const Position& lineEnd,
      90              :         const Position& p, bool perpendicular) {
      91              :     const double lineLength2D = lineStart.distanceTo2D(lineEnd);
      92     78935874 :     if (lineLength2D == 0.) {
      93              :         return 0.;
      94              :     }
      95              :     // scalar product equals length of orthogonal projection times length of vector being projected onto
      96              :     // dividing the scalar product by the distance gives the relative position
      97     78780421 :     const double u = (((p.x() - lineStart.x()) * (lineEnd.x() - lineStart.x())) +
      98     78780421 :                       ((p.y() - lineStart.y()) * (lineEnd.y() - lineStart.y()))
      99     78780421 :                      ) / lineLength2D;
     100     78780421 :     if (u < 0. || u > lineLength2D) {  // closest point does not fall within the line segment
     101     57788440 :         if (perpendicular) {
     102              :             return INVALID_OFFSET;
     103              :         }
     104     51459505 :         if (u < 0.) {
     105              :             return 0.;
     106              :         }
     107     20772231 :         return lineLength2D;
     108              :     }
     109              :     return u;
     110              : }
     111              : 
     112              : 
     113              : double
     114            0 : GeomHelper::nearest_offset_on_line_to_point25D(const Position& lineStart,
     115              :         const Position& lineEnd,
     116              :         const Position& p, bool perpendicular) {
     117            0 :     double result = nearest_offset_on_line_to_point2D(lineStart, lineEnd, p, perpendicular);
     118            0 :     if (result != INVALID_OFFSET) {
     119              :         const double lineLength2D = lineStart.distanceTo2D(lineEnd);
     120            0 :         const double lineLength = lineStart.distanceTo(lineEnd);
     121            0 :         result *= (lineLength / lineLength2D);
     122              :     }
     123            0 :     return result;
     124              : }
     125              : 
     126              : Position
     127            0 : GeomHelper::crossPoint(const Boundary& b, const PositionVector& v) {
     128            0 :     if (v.intersects(Position(b.xmin(), b.ymin()), Position(b.xmin(), b.ymax()))) {
     129              :         return v.intersectionPosition2D(
     130            0 :                    Position(b.xmin(), b.ymin()),
     131            0 :                    Position(b.xmin(), b.ymax()));
     132              :     }
     133            0 :     if (v.intersects(Position(b.xmax(), b.ymin()), Position(b.xmax(), b.ymax()))) {
     134              :         return v.intersectionPosition2D(
     135            0 :                    Position(b.xmax(), b.ymin()),
     136            0 :                    Position(b.xmax(), b.ymax()));
     137              :     }
     138            0 :     if (v.intersects(Position(b.xmin(), b.ymin()), Position(b.xmax(), b.ymin()))) {
     139              :         return v.intersectionPosition2D(
     140            0 :                    Position(b.xmin(), b.ymin()),
     141            0 :                    Position(b.xmax(), b.ymin()));
     142              :     }
     143            0 :     if (v.intersects(Position(b.xmin(), b.ymax()), Position(b.xmax(), b.ymax()))) {
     144              :         return v.intersectionPosition2D(
     145            0 :                    Position(b.xmin(), b.ymax()),
     146            0 :                    Position(b.xmax(), b.ymax()));
     147              :     }
     148            0 :     throw 1;
     149              : }
     150              : 
     151              : double
     152      1290818 : GeomHelper::getCCWAngleDiff(double angle1, double angle2) {
     153      1290818 :     double v = angle2 - angle1;
     154      1290818 :     if (v < 0) {
     155       630516 :         v = 360 + v;
     156              :     }
     157      1290818 :     return v;
     158              : }
     159              : 
     160              : 
     161              : double
     162      1300236 : GeomHelper::getCWAngleDiff(double angle1, double angle2) {
     163      1300236 :     double v = angle1 - angle2;
     164      1300236 :     if (v < 0) {
     165       620610 :         v = 360 + v;
     166              :     }
     167      1300236 :     return v;
     168              : }
     169              : 
     170              : 
     171              : double
     172      1286032 : GeomHelper::getMinAngleDiff(double angle1, double angle2) {
     173      1286032 :     return MIN2(getCWAngleDiff(angle1, angle2), getCCWAngleDiff(angle1, angle2));
     174              : }
     175              : 
     176              : 
     177              : double
     178    168336938 : GeomHelper::angleDiff(const double angle1, const double angle2) {
     179    168336938 :     double dtheta = angle2 - angle1;
     180    170688613 :     while (dtheta > (double) M_PI) {
     181      2351675 :         dtheta -= (double)(2.0 * M_PI);
     182              :     }
     183    170512018 :     while (dtheta < (double) - M_PI) {
     184      2175080 :         dtheta += (double)(2.0 * M_PI);
     185              :     }
     186    168336938 :     return dtheta;
     187              : }
     188              : 
     189              : 
     190              : double
     191      4117041 : GeomHelper::naviDegree(const double angle) {
     192      4117041 :     double degree = RAD2DEG(M_PI / 2. - angle);
     193      4117041 :     if (std::isinf(degree)) {
     194              :         //assert(false);
     195              :         return 0;
     196              :     }
     197      4117041 :     while (degree >= 360.) {
     198            0 :         degree -= 360.;
     199              :     }
     200      4925424 :     while (degree < 0.) {
     201       808383 :         degree += 360.;
     202              :     }
     203              :     return degree;
     204              : }
     205              : 
     206              : 
     207              : double
     208        21899 : GeomHelper::fromNaviDegree(const double angle) {
     209        21899 :     return M_PI / 2. - DEG2RAD(angle);
     210              : }
     211              : 
     212              : 
     213              : double
     214     21043914 : GeomHelper::legacyDegree(const double angle, const bool positive) {
     215     21043914 :     double degree = -RAD2DEG(M_PI / 2. + angle);
     216     21043914 :     if (positive) {
     217      2216711 :         while (degree >= 360.) {
     218            0 :             degree -= 360.;
     219              :         }
     220      3895718 :         while (degree < 0.) {
     221      1679007 :             degree += 360.;
     222              :         }
     223              :     } else {
     224     18827203 :         while (degree >= 180.) {
     225            0 :             degree -= 360.;
     226              :         }
     227     23543066 :         while (degree < -180.) {
     228      4715863 :             degree += 360.;
     229              :         }
     230              :     }
     231     21043914 :     return degree;
     232              : }
     233              : 
     234              : PositionVector
     235            0 : GeomHelper::makeCircle(const double radius, const Position& center, unsigned int nPoints) {
     236            0 :     if (nPoints < 3) {
     237            0 :         WRITE_ERROR(TL("GeomHelper::makeCircle() requires nPoints>=3"));
     238              :     }
     239            0 :     PositionVector circle;
     240            0 :     circle.push_back({radius, 0});
     241            0 :     for (unsigned int i = 1; i < nPoints; ++i) {
     242            0 :         const double a = 2.0 * M_PI * (double)i / (double) nPoints;
     243            0 :         circle.push_back({radius * cos(a), radius * sin(a)});
     244              :     }
     245            0 :     circle.push_back({radius, 0});
     246            0 :     circle.add(center);
     247            0 :     return circle;
     248            0 : }
     249              : 
     250              : 
     251              : PositionVector
     252           69 : GeomHelper::makeRing(const double radius1, const double radius2, const Position& center, unsigned int nPoints) {
     253           69 :     if (nPoints < 3) {
     254            0 :         WRITE_ERROR("GeomHelper::makeRing() requires nPoints>=3");
     255              :     }
     256           69 :     if (radius1 >= radius2) {
     257            0 :         WRITE_ERROR("GeomHelper::makeRing() requires radius2>radius1");
     258              :     }
     259           69 :     PositionVector ring;
     260           69 :     ring.push_back({radius1, 0});
     261           69 :     ring.push_back({radius2, 0});
     262         2346 :     for (unsigned int i = 1; i < nPoints; ++i) {
     263         2277 :         const double a = 2.0 * M_PI * (double)i / (double) nPoints;
     264         2277 :         ring.push_back({radius2 * cos(a), radius2 * sin(a)});
     265              :     }
     266           69 :     ring.push_back({radius2, 0});
     267           69 :     ring.push_back({radius1, 0});
     268         2346 :     for (unsigned int i = 1; i < nPoints; ++i) {
     269         2277 :         const double a = -2.0 * M_PI * (double)i / (double) nPoints;
     270         2277 :         ring.push_back({radius1 * cos(a), radius1 * sin(a)});
     271              :     }
     272           69 :     ring.push_back({radius1, 0});
     273           69 :     ring.add(center);
     274           69 :     return ring;
     275            0 : }
     276              : 
     277              : 
     278              : 
     279              : const Position
     280        47899 : GeomHelper::calculateLotSpacePosition(const PositionVector& shape, const int index, const double spaceDim, const double angle,
     281              :                                       const double width, const double length) {
     282              :     //declare pos
     283              :     Position pos;
     284              :     // declare shape offsets
     285        47899 :     const Position startOffset = shape.positionAtOffset(spaceDim * (index));
     286        47899 :     const Position endOffset = shape.positionAtOffset(spaceDim * (index + 1));
     287              :     // continue depending of nagle
     288        47899 :     if (angle == 0) {
     289              :         // parking parallel to the road
     290        46702 :         pos = endOffset;
     291              :     } else {
     292              :         // angled parking
     293         1197 :         const double hlp_angle = fabs(((double)atan2((endOffset.x() - startOffset.x()), (startOffset.y() - endOffset.y())) * (double)180.0 / (double)M_PI) - 180);
     294         1197 :         if (angle >= 0 && angle <= 90) {
     295          772 :             pos.setx((startOffset.x() + endOffset.x()) / 2 - (width / 2) * (1 - cos(angle / 180 * M_PI)) * cos(hlp_angle / 180 * M_PI));
     296          772 :             pos.sety((startOffset.y() + endOffset.y()) / 2 + (width / 2) * (1 - cos(angle / 180 * M_PI)) * sin(hlp_angle / 180 * M_PI));
     297          772 :             pos.setz((startOffset.z() + endOffset.z()) / 2);
     298          324 :         } else if (angle > 90 && angle <= 180) {
     299            0 :             pos.setx((startOffset.x() + endOffset.x()) / 2 - (width / 2) * (1 + cos(angle / 180 * M_PI)) * cos(hlp_angle / 180 * M_PI));
     300            0 :             pos.sety((startOffset.y() + endOffset.y()) / 2 + (width / 2) * (1 + cos(angle / 180 * M_PI)) * sin(hlp_angle / 180 * M_PI));
     301            0 :             pos.setz((startOffset.z() + endOffset.z()) / 2);
     302          425 :         } else if (angle > 180 && angle <= 270) {
     303          320 :             pos.setx((startOffset.x() + endOffset.x()) / 2 - (length)*sin((angle - hlp_angle) / 180 * M_PI) - (width / 2) * (1 + cos(angle / 180 * M_PI)) * cos(hlp_angle / 180 * M_PI));
     304          320 :             pos.sety((startOffset.y() + endOffset.y()) / 2 + (length)*cos((angle - hlp_angle) / 180 * M_PI) + (width / 2) * (1 + cos(angle / 180 * M_PI)) * sin(hlp_angle / 180 * M_PI));
     305          320 :             pos.setz((startOffset.z() + endOffset.z()) / 2);
     306            4 :         } else if (angle > 270 && angle < 360) {
     307            0 :             pos.setx((startOffset.x() + endOffset.x()) / 2 - (length)*sin((angle - hlp_angle) / 180 * M_PI) - (width / 2) * (1 - cos(angle / 180 * M_PI)) * cos(hlp_angle / 180 * M_PI));
     308            0 :             pos.sety((startOffset.y() + endOffset.y()) / 2 + (length)*cos((angle - hlp_angle) / 180 * M_PI) + (width / 2) * (1 - cos(angle / 180 * M_PI)) * sin(hlp_angle / 180 * M_PI));
     309            0 :             pos.setz((startOffset.z() + endOffset.z()) / 2);
     310              :         } else {
     311          105 :             pos = (startOffset + endOffset) * 0.5;
     312              :         }
     313              :     }
     314        47899 :     return pos;
     315              : }
     316              : 
     317              : 
     318              : double
     319        47899 : GeomHelper::calculateLotSpaceAngle(const PositionVector& shape, const int index, const double spaceDim, const double angle) {
     320              :     // declare shape offsets
     321        47899 :     const Position startOffset = shape.positionAtOffset(spaceDim * (index));
     322        47899 :     const Position endOffset = shape.positionAtOffset(spaceDim * (index + 1));
     323              :     // return angle
     324        47899 :     return ((double)atan2((endOffset.x() - startOffset.x()), (startOffset.y() - endOffset.y())) * (double)180.0 / (double)M_PI) + angle;
     325              : }
     326              : 
     327              : 
     328              : double
     329        47899 : GeomHelper::calculateLotSpaceSlope(const PositionVector& shape, const int index, const double spaceDim) {
     330        47899 :     return shape.slopeDegreeAtOffset(spaceDim * (index + 1));
     331              : }
     332              : 
     333              : /****************************************************************************/
        

Generated by: LCOV version 2.0-1