LCOV - code coverage report
Current view: top level - src/utils/router - RailEdge.h (source / functions) Coverage Total Hit
Test: lcov.info Lines: 98.9 % 88 87
Test Date: 2024-10-24 15:46:30 Functions: 100.0 % 17 17

            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    RailEdge.h
      15              : /// @author  Jakob Erdmann
      16              : /// @date    26.02.2020
      17              : ///
      18              : // The RailEdge is a wrapper around a ROEdge or a MSEdge used for railway routing
      19              : /****************************************************************************/
      20              : #pragma once
      21              : #include <config.h>
      22              : #include <cassert>
      23              : 
      24              : //#define RailEdge_DEBUG_TURNS
      25              : //#define RailEdge_DEBUG_INIT
      26              : //#define RailEdge_DEBUG_SUCCESSORS
      27              : #define RailEdge_DEBUGID ""
      28              : //#define RailEdge_DEBUG_COND(obj) ((obj != 0 && (obj)->getID() == RailEdge_DEBUGID))
      29              : #define RailEdge_DEBUG_COND(obj) (true)
      30              : 
      31              : #define REVERSAL_SLACK (POSITION_EPS + NUMERICAL_EPS)
      32              : 
      33              : // ===========================================================================
      34              : // class definitions
      35              : // ===========================================================================
      36              : /// @brief the edge type representing backward edges
      37              : template<class E, class V>
      38              : class RailEdge {
      39              : public:
      40              :     typedef RailEdge<E, V> _RailEdge;
      41              :     typedef std::vector<std::pair<const _RailEdge*, const _RailEdge*> > ConstEdgePairVector;
      42              : 
      43       142814 :     RailEdge(const E* orig) :
      44       142814 :         myNumericalID(orig->getNumericalID()),
      45       142814 :         myOriginal(orig),
      46       142814 :         myTurnaround(nullptr),
      47       142814 :         myIsVirtual(true)
      48       142814 :     { }
      49              : 
      50         3017 :     RailEdge(const E* turnStart, const E* turnEnd, int numericalID) :
      51         3017 :         myNumericalID(numericalID),
      52         6034 :         myID("TrainReversal!" + turnStart->getID() + "->" + turnEnd->getID()),
      53         3017 :         myOriginal(nullptr),
      54         3017 :         myTurnaround(nullptr),
      55         3017 :         myIsVirtual(true),
      56         3017 :         myMaxLength(turnStart->getLength() - REVERSAL_SLACK),
      57         6034 :         myStartLength(turnStart->getLength() - REVERSAL_SLACK) {
      58         3017 :         myViaSuccessors.push_back(std::make_pair(turnEnd->getRailwayRoutingEdge(), nullptr));
      59         3017 :     }
      60              : 
      61              :     /// @brief Destructor.
      62       291662 :     virtual ~RailEdge() {
      63         3017 :         delete myTurnaround;
      64       440510 :     }
      65              : 
      66              :     void update(double maxTrainLength, const std::vector<const E*>& replacementEdges) {
      67       196708 :         if (maxTrainLength > myMaxLength) {
      68         4905 :             myMaxLength = maxTrainLength;
      69         4905 :             myReplacementEdges = replacementEdges;
      70              : #ifdef RailEdge_DEBUG_INIT
      71              :             std::cout << "    update RailEdge " << getID() << " myMaxLength=" << myMaxLength << " repl=" << toString(myReplacementEdges) << "\n";
      72              : #endif
      73              :         }
      74              :     }
      75              : 
      76       198171 :     void addVirtualTurns(const E* forward, const E* backward,
      77              :                          std::vector<_RailEdge*>& railEdges, int& numericalID, double dist,
      78              :                          double maxTrainLength, const std::vector<const E*>& replacementEdges) {
      79              :         // search backwards until dist and add virtual turnaround edges with
      80              :         // replacement edges up to the real turnaround
      81              : #ifdef RailEdge_DEBUG_INIT
      82              :         std::cout << "addVirtualTurns forward=" << forward->getID() << " backward=" << backward->getID() << " dist=" << dist
      83              :                   << " maxLength=" << maxTrainLength << " repl=" << toString(replacementEdges) << "\n";
      84              : #endif
      85       198171 :         if (dist <= 0) {
      86              :             return;
      87              :         }
      88       739187 :         for (const E* prev : forward->getPredecessors()) {
      89       613938 :             if (prev == backward) {
      90       122486 :                 continue;
      91              :             }
      92              :             const E* bidi = prev->getBidiEdge();
      93       491452 :             if (bidi != nullptr && backward->isConnectedTo(*bidi, SVC_IGNORING)) {
      94       219636 :                 _RailEdge* prevRailEdge = prev->getRailwayRoutingEdge();
      95       219636 :                 if (prevRailEdge->myTurnaround == nullptr) {
      96         2200 :                     prevRailEdge->myTurnaround = new _RailEdge(prev, bidi, numericalID++);
      97         2200 :                     prevRailEdge->myViaSuccessors.push_back(std::make_pair(prevRailEdge->myTurnaround, nullptr));
      98         2200 :                     railEdges.push_back(prevRailEdge->myTurnaround);
      99              : #ifdef RailEdge_DEBUG_INIT
     100              :                     std::cout << "  RailEdge " << prevRailEdge->getID() << " virtual turnaround " << prevRailEdge->myTurnaround->getID() << "\n";
     101              : #endif
     102              :                 }
     103              :                 /*
     104              :                 // doesn't compile though I don't know why
     105              :                 auto itFound = std::find(replacementEdges.begin(), replacementEdges.end(), prev);
     106              :                 bool notFound = itFound == replacementEdges.end();
     107              :                 */
     108              :                 bool notFound = true;
     109      1976978 :                 for (const E* r : replacementEdges) {
     110      1780270 :                     if (r == prev) {
     111              :                         notFound = false;
     112              :                         break;
     113              :                     }
     114              :                 }
     115              : 
     116       219636 :                 if (notFound) {
     117              :                     // prevent loops in replacementEdges
     118       196708 :                     prevRailEdge->myTurnaround->update(prev->getLength() + maxTrainLength - REVERSAL_SLACK, replacementEdges);
     119              :                     std::vector<const E*> replacementEdges2;
     120       196708 :                     replacementEdges2.push_back(prev);
     121       196708 :                     replacementEdges2.insert(replacementEdges2.end(), replacementEdges.begin(), replacementEdges.end());
     122       196708 :                     addVirtualTurns(prev, bidi, railEdges, numericalID, dist - prev->getLength(),
     123              :                                     maxTrainLength + prev->getLength(), replacementEdges2);
     124       196708 :                 }
     125              :             }
     126              :         }
     127              :     }
     128              : 
     129        34376 :     void init(std::vector<_RailEdge*>& railEdges, int& numericalID, double maxTrainLength) {
     130              :         // replace turnaround-via with an explicit RailEdge that checks length
     131        71874 :         for (const auto& viaPair : myOriginal->getViaSuccessors()) {
     132        37498 :             if (viaPair.first == myOriginal->getBidiEdge()) {
     133              :                 // direction reversal
     134         1463 :                 if (myTurnaround == nullptr) {
     135          817 :                     myTurnaround = new _RailEdge(myOriginal, viaPair.first, numericalID++);
     136          817 :                     myViaSuccessors.push_back(std::make_pair(myTurnaround, nullptr));
     137          817 :                     railEdges.push_back(myTurnaround);
     138              : #ifdef RailEdge_DEBUG_INIT
     139              :                     std::cout << "   added new turnaround " << myTurnaround->getID() << "\n";
     140              : #endif
     141              :                 }
     142              : #ifdef RailEdge_DEBUG_INIT
     143              :                 std::cout << "RailEdge " << getID() << " actual turnaround " << myTurnaround->getID() << "\n";
     144              : #endif
     145         1463 :                 myTurnaround->myIsVirtual = false;
     146              :                 // ensure at least one virtual turnaround (at the start of the
     147              :                 // edge) to avoid driving up to the end of long edges
     148         1463 :                 const double initialDist = MAX2(maxTrainLength - getLength(), POSITION_EPS);
     149         2926 :                 addVirtualTurns(myOriginal, viaPair.first, railEdges, numericalID,
     150              :                                 initialDist, getLength(), std::vector<const E*> {myOriginal});
     151              :             } else {
     152        72070 :                 myViaSuccessors.push_back(std::make_pair(viaPair.first->getRailwayRoutingEdge(),
     153        36035 :                                           viaPair.second == nullptr ? nullptr : viaPair.second->getRailwayRoutingEdge()));
     154              :             }
     155              :         }
     156              : #ifdef RailEdge_DEBUG_SUCCESSORS
     157              :         std::cout << "RailEdge " << getID() << " successors=" << myViaSuccessors.size() << " orig=" << myOriginal->getViaSuccessors().size() << "\n";
     158              :         for (const auto& viaPair : myViaSuccessors) {
     159              :             std::cout << "    " << viaPair.first->getID() << "\n";
     160              :         }
     161              : #endif
     162        34376 :     }
     163              : 
     164              :     /// @brief Returns the index (numeric id) of the edge
     165              :     inline int getNumericalID() const {
     166      1048242 :         return myNumericalID;
     167              :     }
     168              : 
     169              :     /// @brief Returns the original edge
     170              :     const E* getOriginal() const {
     171      1646362 :         return myOriginal;
     172              :     }
     173              : 
     174              :     /** @brief Returns the id of the edge
     175              :      * @return The original edge's id
     176              :      */
     177              :     const std::string& getID() const {
     178           76 :         return myOriginal != nullptr ? myOriginal->getID() : myID;
     179              :     }
     180              : 
     181       447908 :     void insertOriginalEdges(double length, std::vector<const E*>& into) const {
     182       447908 :         if (myOriginal != nullptr) {
     183       383811 :             into.push_back(myOriginal);
     184              :         } else {
     185        64097 :             double seen = myStartLength;
     186              :             int nPushed = 0;
     187              :             //std::cout << "insertOriginalEdges e=" << getID() << " length=" << length << " seen=" << seen << " into=" << toString(into) << "\n";
     188        64097 :             if (seen >= length && !myIsVirtual) {
     189              :                 return;
     190              :             }
     191              :             // we need to find a replacement edge that has a real turn
     192       108604 :             for (const E* edge : myReplacementEdges) {
     193       108580 :                 into.push_back(edge);
     194       108580 :                 nPushed++;
     195       108580 :                 seen += edge->getLength() - REVERSAL_SLACK;
     196              :                 //std::cout << "insertOriginalEdges e=" << getID() << " length=" << length << " seen=" << seen << " into=" << toString(into) << "\n";
     197       108580 :                 if (seen >= length && edge->isConnectedTo(*edge->getBidiEdge(), SVC_IGNORING)) {
     198              :                     break;
     199              :                 }
     200              :             }
     201        56530 :             const int last = (int)into.size() - 1;
     202       165110 :             for (int i = 0; i < nPushed; i++) {
     203       108580 :                 into.push_back(into[last - i]->getBidiEdge());
     204              :             }
     205              :         }
     206              :     }
     207              : 
     208              :     /** @brief Returns the length of the edge
     209              :      * @return The original edge's length
     210              :      */
     211              :     double getLength() const {
     212       504873 :         return myOriginal == nullptr ? 0 : myOriginal->getLength();
     213              :     }
     214              : 
     215              :     //const RailEdge* getBidiEdge() const {
     216              :     //    return myOriginal->getBidiEdge()->getRailwayRoutingEdge();
     217              :     //}
     218              : 
     219              :     bool isInternal() const {
     220       501947 :         return myOriginal->isInternal();
     221              :     }
     222              : 
     223       939044 :     inline bool prohibits(const V* const vehicle) const {
     224              : #ifdef RailEdge_DEBUG_TURNS
     225              :         if (myOriginal == nullptr && RailEdge_DEBUG_COND(vehicle)) {
     226              :             std::cout << getID() << " maxLength=" << myMaxLength << " veh=" << vehicle->getID() << " length=" << vehicle->getLength() << "\n";
     227              :         }
     228              : #endif
     229       939937 :         return vehicle->getLength() > myMaxLength || (myOriginal != nullptr && myOriginal->prohibits(vehicle));
     230              :     }
     231              : 
     232              :     inline bool restricts(const V* const vehicle) const {
     233            0 :         return myOriginal != nullptr && myOriginal->restricts(vehicle);
     234              :     }
     235              : 
     236       752917 :     const ConstEdgePairVector& getViaSuccessors(SUMOVehicleClass vClass = SVC_IGNORING, bool ignoreTransientPermissions = false) const {
     237              :         UNUSED_PARAMETER(ignoreTransientPermissions); // @todo this should be changed (somewhat hidden by #14756)
     238       752917 :         if (vClass == SVC_IGNORING || myOriginal == nullptr || myOriginal->isTazConnector()) { // || !MSNet::getInstance()->hasPermissions()) {
     239        76428 :             return myViaSuccessors;
     240              :         }
     241              : #ifdef HAVE_FOX
     242       676489 :         FXMutexLock lock(mySuccessorMutex);
     243              : #endif
     244              :         auto i = myClassesViaSuccessorMap.find(vClass);
     245       676489 :         if (i != myClassesViaSuccessorMap.end()) {
     246              :             // can use cached value
     247       669673 :             return i->second;
     248              :         }
     249              :         // instantiate vector
     250         6816 :         ConstEdgePairVector& result = myClassesViaSuccessorMap[vClass];
     251              :         // this vClass is requested for the first time. rebuild all successors
     252        15692 :         for (const auto& viaPair : myViaSuccessors) {
     253         8876 :             if (viaPair.first->myOriginal == nullptr
     254         7211 :                     || viaPair.first->myOriginal->isTazConnector()
     255        16055 :                     || myOriginal->isConnectedTo(*viaPair.first->myOriginal, vClass)) {
     256         8863 :                 result.push_back(viaPair);
     257              :             }
     258              :         }
     259              :         return result;
     260              :     }
     261              : 
     262              :     bool isVirtual() const {
     263        76398 :         return myIsVirtual;
     264              :     }
     265              : 
     266              : private:
     267              :     const int myNumericalID;
     268              :     const std::string myID;
     269              :     const E* myOriginal;
     270              :     _RailEdge* myTurnaround;
     271              :     bool myIsVirtual;
     272              : 
     273              :     /// @brief actual edges to return when passing this (turnaround) edge - only forward
     274              :     std::vector<const E*> myReplacementEdges;
     275              : 
     276              :     /// @brief maximum train length for passing this (turnaround) edge
     277              :     double myMaxLength = std::numeric_limits<double>::max();
     278              :     /// @brief length of the edge where this turn starts
     279              :     double myStartLength = 0;
     280              : 
     281              :     /// @brief The successors available for a given vClass
     282              :     mutable std::map<SUMOVehicleClass, ConstEdgePairVector> myClassesViaSuccessorMap;
     283              : 
     284              :     mutable ConstEdgePairVector myViaSuccessors;
     285              : 
     286              : #ifdef HAVE_FOX
     287              :     /// @brief Mutex for accessing successor edges
     288              :     mutable FXMutex mySuccessorMutex;
     289              : #endif
     290              : 
     291              : };
        

Generated by: LCOV version 2.0-1