LCOV - code coverage report
Current view: top level - src/utils/common - MapMatcher.h (source / functions) Coverage Total Hit
Test: lcov.info Lines: 89.8 % 98 88
Test Date: 2024-11-22 15:46:21 Functions: 91.7 % 12 11

            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    MapMatcher.h
      15              : /// @author  Jakob Erdmann
      16              : /// @date    Thu, 7 March 2024
      17              : ///
      18              : // Utility functions for matching locations to edges (during route parsing)
      19              : /****************************************************************************/
      20              : #pragma once
      21              : #include <config.h>
      22              : 
      23              : #include <utils/geom/GeoConvHelper.h>
      24              : #include <utils/vehicle/SUMOVTypeParameter.h>
      25              : #include "NamedRTree.h"
      26              : #include "RandHelper.h"
      27              : #include "SUMOVehicleClass.h"
      28              : #include "MsgHandler.h"
      29              : 
      30              : #define JUNCTION_TAZ_MISSING_HELP "\nSet option '--junction-taz' or load a TAZ-file"
      31              : 
      32              : // ===========================================================================
      33              : // class declarations
      34              : // ===========================================================================
      35              : 
      36              : // ===========================================================================
      37              : // class definitions
      38              : // ===========================================================================
      39              : /**
      40              :  * @class MapMatcher
      41              :  * @brief Provides utility functions for matching locations to edges (during route parsing)
      42              :  */
      43              : 
      44              : template<class E, class L, class N>
      45              : class MapMatcher {
      46              : protected:
      47        95318 :     MapMatcher(bool matchJunctions, bool matchTAZ, double matchDistance, MsgHandler* errorOutput):
      48        95318 :         myMapMatchTAZ(matchTAZ),
      49        95318 :         myLaneTree(nullptr),
      50        95318 :         myMapMatchJunctions(matchJunctions),
      51        95318 :         myMapMatchingDistance(matchDistance),
      52        95318 :         myErrorOutput(errorOutput) {}
      53              : 
      54              :     virtual ~MapMatcher() {
      55          177 :         delete myLaneTree;
      56        92561 :     }
      57              : 
      58          831 :     void parseGeoEdges(const PositionVector& positions, bool geo, SUMOVehicleClass vClass,
      59              :                        std::vector<const E*>& into, const std::string& rid, bool isFrom, bool& ok, bool forceEdge = false) {
      60          831 :         if (geo && !GeoConvHelper::getFinal().usingGeoProjection()) {
      61            0 :             WRITE_ERROR(TL("Cannot convert geo-positions because the network has no geo-reference"));
      62            0 :             ok = false;
      63            0 :             return;
      64              :         }
      65         1684 :         for (Position pos : positions) {
      66          853 :             Position orig = pos;
      67          853 :             if (geo) {
      68          156 :                 GeoConvHelper::getFinal().x2cartesian_const(pos);
      69              :             }
      70          853 :             double dist = MIN2(10.0, myMapMatchingDistance);
      71          853 :             const L* best = getClosestLane(pos, vClass, dist);
      72          853 :             while (best == nullptr && dist < myMapMatchingDistance) {
      73            0 :                 dist = MIN2(dist * 2, myMapMatchingDistance);
      74            0 :                 best = getClosestLane(pos, vClass, dist);
      75              :             }
      76          853 :             if (best == nullptr) {
      77           36 :                 myErrorOutput->inform("No edge found near position " + toString(orig, geo ? gPrecisionGeo : gPrecision) + " within the route " + rid + ".");
      78           18 :                 ok = false;
      79              :             } else {
      80          835 :                 const E* bestEdge = &best->getEdge();
      81          854 :                 while (bestEdge->isInternal()) {
      82           19 :                     bestEdge = bestEdge->getSuccessors().front();
      83              :                 }
      84          835 :                 if ((myMapMatchJunctions || myMapMatchTAZ) && !forceEdge) {
      85          442 :                     if (myMapMatchTAZ) {
      86           69 :                         bestEdge = getTaz(pos, bestEdge, isFrom);
      87              :                     } else {
      88          373 :                         bestEdge = getJunctionTaz(pos, bestEdge, vClass, isFrom);
      89              :                     }
      90          442 :                     if (bestEdge != nullptr) {
      91          427 :                         into.push_back(bestEdge);
      92              :                     } else {
      93           15 :                         ok = false;
      94              :                     }
      95              :                 } else {
      96              :                     // handle multiple via locations on the same edge without loops
      97          393 :                     if (positions.size() == 1 || into.empty() || into.back() != bestEdge) {
      98          371 :                         into.push_back(bestEdge);
      99              :                     }
     100              :                 }
     101              :             }
     102              :         }
     103              :     }
     104              : 
     105              : 
     106              :     /// @brief find closest lane within distance for the given position or nullptr
     107          853 :     const L* getClosestLane(const Position& pos, SUMOVehicleClass vClass, double distance = -1.) {
     108          853 :         NamedRTree* t = getLaneTree();
     109          853 :         Boundary b;
     110          853 :         b.add(pos);
     111          853 :         b.grow(distance < 0 ? myMapMatchingDistance : distance);
     112          853 :         const float cmin[2] = {(float) b.xmin(), (float) b.ymin()};
     113          853 :         const float cmax[2] = {(float) b.xmax(), (float) b.ymax()};
     114              :         std::set<const Named*> lanes;
     115              :         Named::StoringVisitor sv(lanes);
     116          853 :         t->Search(cmin, cmax, sv);
     117              :         // use closest
     118              :         double minDist = std::numeric_limits<double>::max();
     119              :         const L* best = nullptr;
     120         2943 :         for (const Named* o : lanes) {
     121              :             const L* cand = static_cast<const L*>(o);
     122         2090 :             if (!cand->allowsVehicleClass(vClass)) {
     123          104 :                 continue;
     124              :             }
     125         1986 :             double dist = cand->getShape().distance2D(pos);
     126         1986 :             if (dist < minDist) {
     127              :                 minDist = dist;
     128              :                 best = cand;
     129              :             }
     130              :         }
     131          853 :         return best;
     132          853 :     }
     133              : 
     134              :     /// @brief find closest junction taz given the closest edge
     135          373 :     const E* getJunctionTaz(const Position& pos, const E* closestEdge, SUMOVehicleClass vClass, bool isFrom) {
     136          373 :         if (closestEdge == nullptr) {
     137              :             return nullptr;
     138              :         } else {
     139              :             const N* fromJunction = closestEdge->getFromJunction();
     140              :             const N* toJunction = closestEdge->getToJunction();
     141          373 :             const bool fromCloser = (fromJunction->getPosition().distanceSquaredTo2D(pos) <
     142          245 :                                      toJunction->getPosition().distanceSquaredTo2D(pos));
     143          373 :             const E* fromSource = retrieveEdge(fromJunction->getID() + "-source");
     144          373 :             const E* fromSink = retrieveEdge(fromJunction->getID() + "-sink");
     145          373 :             const E* toSource = retrieveEdge(toJunction->getID() + "-source");
     146          373 :             const E* toSink = retrieveEdge(toJunction->getID() + "-sink");
     147          373 :             if (fromSource == nullptr || fromSink == nullptr) {
     148            0 :                 myErrorOutput->inform("Junction-taz '" + fromJunction->getID() + "' not found when mapping position " + toString(pos) + "." + JUNCTION_TAZ_MISSING_HELP);
     149            0 :                 return nullptr;
     150              :             }
     151          373 :             if (toSource == nullptr || toSink == nullptr) {
     152            0 :                 myErrorOutput->inform("Junction-taz '" + toJunction->getID() + "' not found when mapping position " + toString(pos) + "." + JUNCTION_TAZ_MISSING_HELP);
     153            0 :                 return nullptr;
     154              :             }
     155          373 :             const bool fromPossible = isFrom ? fromSource->getSuccessors(vClass).size() > 0 : fromSink->getPredecessors().size() > 0;
     156          373 :             const bool toPossible = isFrom ? toSource->getSuccessors(vClass).size() > 0 : toSink->getPredecessors().size() > 0;
     157              :             //std::cout << "getJunctionTaz pos=" << pos << " isFrom=" << isFrom << " closest=" << closestEdge->getID() << " fromPossible=" << fromPossible << " toPossible=" << toPossible << "\n";
     158          373 :             if (fromCloser && fromPossible) {
     159              :                 // return closest if possible
     160          185 :                 return isFrom ? fromSource : fromSink;
     161          208 :             } else if (!fromCloser && toPossible) {
     162              :                 // return closest if possible
     163          395 :                 return isFrom ? toSource : toSink;
     164              :             } else {
     165              :                 // return possible
     166            7 :                 if (fromPossible) {
     167            0 :                     return isFrom ? fromSource : fromSink;
     168              :                 } else {
     169           14 :                     return isFrom ? toSource : toSink;
     170              :                 }
     171              :             }
     172              :         }
     173              :     }
     174              : 
     175              :     /// @brief find closest junction taz given the closest edge
     176           69 :     const E* getTaz(const Position& pos, const E* closestEdge, bool isFrom) {
     177           69 :         if (closestEdge == nullptr) {
     178              :             return nullptr;
     179              :         } else {
     180              :             std::vector<const E*> cands;
     181           69 :             if (isFrom) {
     182          144 :                 for (const E* e : closestEdge->getPredecessors()) {
     183          106 :                     if (e->isTazConnector()) {
     184           75 :                         cands.push_back(e);
     185              :                     }
     186              :                 }
     187              :             } else {
     188           89 :                 for (const E* e : closestEdge->getSuccessors()) {
     189           58 :                     if (e->isTazConnector()) {
     190           27 :                         cands.push_back(e);
     191              :                     }
     192              :                 }
     193              :             }
     194           69 :             if (cands.size() == 0) {
     195           60 :                 myErrorOutput->inform("Taz for edge '" + closestEdge->getID() + "' not found when mapping position " + toString(pos) + "." + JUNCTION_TAZ_MISSING_HELP);
     196           15 :                 return nullptr;
     197              :             }
     198           54 :             if (cands.size() > 1) {
     199           16 :                 return cands[RandHelper::rand((int)cands.size(), getRNG())];
     200              :             } else {
     201           38 :                 return cands.front();
     202              :             }
     203           69 :         }
     204              :     }
     205              : 
     206           16 :     virtual SumoRNG* getRNG() {
     207           16 :         return nullptr;
     208              :     }
     209              : 
     210              :     virtual void initLaneTree(NamedRTree* tree) = 0;
     211              : 
     212              :     virtual E* retrieveEdge(const std::string& id) = 0;
     213              : 
     214              :     bool myMapMatchTAZ;
     215              : 
     216              : private:
     217              :     /// @brief initialize lane-RTree
     218          853 :     NamedRTree* getLaneTree() {
     219          853 :         if (myLaneTree == nullptr) {
     220          192 :             myLaneTree = new NamedRTree();
     221          192 :             initLaneTree(myLaneTree);
     222              :         }
     223          853 :         return myLaneTree;
     224              :     }
     225              : 
     226              :     /// @brief RTree for finding lanes
     227              :     NamedRTree* myLaneTree;
     228              :     bool myMapMatchJunctions;
     229              :     double myMapMatchingDistance;
     230              :     MsgHandler* myErrorOutput;
     231              : 
     232              : 
     233              : private:
     234              :     /// @brief Invalidated copy constructor
     235              :     MapMatcher(const MapMatcher& s) = delete;
     236              : 
     237              :     /// @brief Invalidated assignment operator
     238              :     MapMatcher& operator=(const MapMatcher& s) = delete;
     239              : };
        

Generated by: LCOV version 2.0-1