LCOV - code coverage report
Current view: top level - src/utils/common - MapMatcher.h (source / functions) Hit Total Coverage
Test: lcov.info Lines: 64 75 85.3 %
Date: 2024-05-02 15:31:40 Functions: 8 8 100.0 %

          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 "SUMOVehicleClass.h"
      27             : #include "MsgHandler.h"
      28             : 
      29             : #define JUNCTION_TAZ_MISSING_HELP "\nSet option '--junction-taz' or load a TAZ-file"
      30             : 
      31             : // ===========================================================================
      32             : // class declarations
      33             : // ===========================================================================
      34             : 
      35             : // ===========================================================================
      36             : // class definitions
      37             : // ===========================================================================
      38             : /**
      39             :  * @class MapMatcher
      40             :  * @brief Provides utility functions for matching locations to edges (during route parsing)
      41             :  */
      42             : 
      43             : template<class E, class L, class N>
      44             : class MapMatcher {
      45             : protected:
      46       65895 :     MapMatcher(bool matchJunctions, double matchDistance, MsgHandler* errorOutput):
      47       65895 :         myLaneTree(nullptr),
      48       65895 :         myMapMatchJunctions(matchJunctions),
      49       65895 :         myMapMatchingDistance(matchDistance),
      50       65895 :         myErrorOutput(errorOutput) {}
      51             : 
      52             :     virtual ~MapMatcher() {
      53         101 :         delete myLaneTree;
      54       65550 :     }
      55             : 
      56         500 :     void parseGeoEdges(const PositionVector& positions, bool geo, SUMOVehicleClass vClass,
      57             :                        std::vector<const E*>& into, const std::string& rid, bool isFrom, bool& ok) {
      58         500 :         if (geo && !GeoConvHelper::getFinal().usingGeoProjection()) {
      59           0 :             WRITE_ERROR(TL("Cannot convert geo-positions because the network has no geo-reference"));
      60           0 :             return;
      61             :         }
      62        1022 :         for (Position pos : positions) {
      63         522 :             Position orig = pos;
      64         522 :             if (geo) {
      65         102 :                 GeoConvHelper::getFinal().x2cartesian_const(pos);
      66             :             }
      67         522 :             double dist = MIN2(10.0, myMapMatchingDistance);
      68         522 :             const E* best = getClosestEdge(pos, dist, vClass);
      69         522 :             while (best == nullptr && dist < myMapMatchingDistance) {
      70           0 :                 dist = MIN2(dist * 2, myMapMatchingDistance);
      71           0 :                 best = getClosestEdge(pos, dist, vClass);
      72             :             }
      73         522 :             if (best == nullptr) {
      74          22 :                 myErrorOutput->inform("No edge found near position " + toString(orig, geo ? gPrecisionGeo : gPrecision) + " within the route " + rid + ".");
      75          11 :                 ok = false;
      76             :             } else {
      77         511 :                 if (myMapMatchJunctions) {
      78         260 :                     best = getJunctionTaz(pos, best, vClass, isFrom);
      79         260 :                     if (best != nullptr) {
      80         260 :                         into.push_back(best);
      81             :                     }
      82             :                 } else {
      83             :                     // handle multiple via locations on the same edge without loops
      84         251 :                     if (positions.size() == 1 || into.empty() || into.back() != best) {
      85         229 :                         into.push_back(best);
      86             :                     }
      87             :                 }
      88             :             }
      89             :         }
      90             :     }
      91             : 
      92             : 
      93             :     /// @brief find closest edge within distance for the given position or nullptr
      94         522 :     const E* getClosestEdge(const Position& pos, double distance, SUMOVehicleClass vClass) {
      95         522 :         NamedRTree* t = getLaneTree();
      96         522 :         Boundary b;
      97         522 :         b.add(pos);
      98         522 :         b.grow(distance);
      99         522 :         const float cmin[2] = {(float) b.xmin(), (float) b.ymin()};
     100         522 :         const float cmax[2] = {(float) b.xmax(), (float) b.ymax()};
     101             :         std::set<const Named*> lanes;
     102             :         Named::StoringVisitor sv(lanes);
     103         522 :         t->Search(cmin, cmax, sv);
     104             :         // use closest
     105             :         double minDist = std::numeric_limits<double>::max();
     106             :         const L* best = nullptr;
     107        1697 :         for (const Named* o : lanes) {
     108             :             const L* cand = static_cast<const L*>(o);
     109        1175 :             if (!cand->allowsVehicleClass(vClass)) {
     110          68 :                 continue;
     111             :             }
     112        1107 :             double dist = cand->getShape().distance2D(pos);
     113        1107 :             if (dist < minDist) {
     114             :                 minDist = dist;
     115             :                 best = cand;
     116             :             }
     117             :         }
     118         522 :         if (best == nullptr) {
     119             :             return nullptr;
     120             :         } else {
     121             :             const E* bestEdge = &best->getEdge();
     122         515 :             while (bestEdge->isInternal()) {
     123           4 :                 bestEdge = bestEdge->getSuccessors().front();
     124             :             }
     125         511 :             return bestEdge;
     126             :         }
     127         522 :     }
     128             : 
     129             :     /// @brief find closest junction taz given the closest edge
     130         260 :     const E* getJunctionTaz(const Position& pos, const E* closestEdge, SUMOVehicleClass vClass, bool isFrom) {
     131         260 :         if (closestEdge == nullptr) {
     132             :             return nullptr;
     133             :         } else {
     134             :             const N* fromJunction = closestEdge->getFromJunction();
     135             :             const N* toJunction = closestEdge->getToJunction();
     136         260 :             const bool fromCloser = (fromJunction->getPosition().distanceSquaredTo2D(pos) <
     137         140 :                     toJunction->getPosition().distanceSquaredTo2D(pos));
     138         260 :             const E* fromSource = retrieveEdge(fromJunction->getID() + "-source");
     139         260 :             const E* fromSink = retrieveEdge(fromJunction->getID() + "-sink");
     140         260 :             const E* toSource = retrieveEdge(toJunction->getID() + "-source");
     141         260 :             const E* toSink = retrieveEdge(toJunction->getID() + "-sink");
     142         260 :             if (fromSource == nullptr || fromSink == nullptr) {
     143           0 :                 myErrorOutput->inform("Junction-taz '" + fromJunction->getID() + "' not found when mapping position " + toString(pos) + "." + JUNCTION_TAZ_MISSING_HELP);
     144           0 :                 return nullptr;
     145             :             }
     146         260 :             if (toSource == nullptr || toSink == nullptr) {
     147           0 :                 myErrorOutput->inform("Junction-taz '" + toJunction->getID() + "' not found when mapping position " + toString(pos) + "." + JUNCTION_TAZ_MISSING_HELP);
     148           0 :                 return nullptr;
     149             :             }
     150         260 :             const bool fromPossible = isFrom ? fromSource->getSuccessors(vClass).size() > 0 : fromSink->getPredecessors().size() > 0;
     151         260 :             const bool toPossible = isFrom ? toSource->getSuccessors(vClass).size() > 0 : toSink->getPredecessors().size() > 0;
     152             :             //std::cout << "getJunctionTaz pos=" << pos << " isFrom=" << isFrom << " closest=" << closestEdge->getID() << " fromPossible=" << fromPossible << " toPossible=" << toPossible << "\n";
     153         260 :             if (fromCloser && fromPossible) {
     154             :                 // return closest if possible
     155         141 :                 return isFrom ? fromSource : fromSink;
     156         139 :             } else if (!fromCloser && toPossible) {
     157             :                 // return closest if possible
     158         271 :                 return isFrom ? toSource : toSink;
     159             :             } else {
     160             :                 // return possible
     161           0 :                 if (fromPossible) {
     162           0 :                     return isFrom ? fromSource : fromSink;
     163             :                 } else {
     164           0 :                     return isFrom ? toSource : toSink;
     165             :                 }
     166             :             }
     167             :         }
     168             :     }
     169             : 
     170             : 
     171             :     virtual void initLaneTree(NamedRTree* tree) = 0;
     172             : 
     173             :     virtual E* retrieveEdge(const std::string& id) = 0;
     174             : 
     175             : private:
     176             :     /// @brief initialize lane-RTree
     177         522 :     NamedRTree* getLaneTree() {
     178         522 :         if (myLaneTree == nullptr) {
     179         106 :             myLaneTree = new NamedRTree();
     180         106 :             initLaneTree(myLaneTree);
     181             :         }
     182         522 :         return myLaneTree;
     183             :     }
     184             : 
     185             :     /// @brief RTree for finding lanes
     186             :     NamedRTree* myLaneTree;
     187             :     bool myMapMatchJunctions;
     188             :     double myMapMatchingDistance;
     189             :     MsgHandler* myErrorOutput;
     190             : 
     191             : 
     192             : private:
     193             :     /// @brief Invalidated copy constructor
     194             :     MapMatcher(const MapMatcher& s) = delete;
     195             : 
     196             :     /// @brief Invalidated assignment operator
     197             :     MapMatcher& operator=(const MapMatcher& s) = delete;
     198             : };

Generated by: LCOV version 1.14