LCOV - code coverage report
Current view: top level - src/microsim/traffic_lights - MSDriveWay.h (source / functions) Coverage Total Hit
Test: lcov.info Lines: 100.0 % 9 9
Test Date: 2026-03-02 16:00:03 Functions: - 0 0

            Line data    Source code
       1              : /****************************************************************************/
       2              : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
       3              : // Copyright (C) 2002-2026 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    MSDriveWay.h
      15              : /// @author  Jakob Erdmann
      16              : /// @date    December 2021
      17              : ///
      18              : // A sequende of rail tracks (lanes) that may be used as a "set route" (Fahrstraße)
      19              : /****************************************************************************/
      20              : #pragma once
      21              : #include <config.h>
      22              : 
      23              : #include <utils/common/Named.h>
      24              : #include <microsim/MSMoveReminder.h>
      25              : #include <microsim/MSRoute.h>
      26              : 
      27              : // ===========================================================================
      28              : // class declarations
      29              : // ===========================================================================
      30              : class SUMOVehicle;
      31              : class MSLane;
      32              : class MSLink;
      33              : class MSRailSignal;
      34              : 
      35              : // ===========================================================================
      36              : // class definitions
      37              : // ===========================================================================
      38              : /**
      39              :  * @class MSDriveWay
      40              :  */
      41              : class MSDriveWay : public MSMoveReminder, public Named {
      42              : public:
      43              :     typedef std::pair<const SUMOVehicle* const, const MSLink::ApproachingVehicleInformation> Approaching;
      44              :     typedef std::set<const MSLane*, ComparatorNumericalIdLess> LaneSet;
      45              :     typedef std::map<const MSLane*, int, ComparatorNumericalIdLess> LaneVisitedMap;
      46              : 
      47         4895 :     struct VehicleEvent {
      48         1832 :         VehicleEvent(SUMOTime _time, bool _isEntry, const std::string& _id, Notification _reason):
      49         1832 :             time(_time), isEntry(_isEntry), id(_id), reason(_reason) {}
      50              :         SUMOTime time;
      51              :         bool isEntry;
      52              :         std::string id;
      53              :         Notification reason;
      54              :     };
      55              : 
      56              :     /*  The driveways (Fahrstrassen) for each link index of MSRailSignal
      57              :      *  Each link index has at least one driveway
      58              :      *  A driveway describes one possible route that passes the signal up to
      59              :      *  the next secure point
      60              :      *  When a signal guards a switch (indirect guard) that signal stores two
      61              :      *  or more driveways
      62              :      */
      63              :     MSDriveWay(const MSLink* origin, const std::string& id, bool temporary = false);
      64              : 
      65              :     /// @brief Destructor
      66              :     virtual ~MSDriveWay();
      67              : 
      68              :     static void cleanup();
      69              : 
      70              :     static void clearState();
      71              : 
      72              :     static bool haveDriveWays() {
      73          494 :         return myGlobalDriveWayIndex > 0;
      74              :     }
      75              : 
      76              :     static const MSDriveWay* retrieveDepartDriveWay(const MSEdge* edge, const std::string& id);
      77              : 
      78              :     bool notifyEnter(SUMOTrafficObject& veh, Notification reason, const MSLane* enteredLane);
      79              :     bool notifyLeave(SUMOTrafficObject& veh, double lastPos, Notification reason, const MSLane* enteredLane = 0);
      80              :     bool notifyLeaveBack(SUMOTrafficObject& veh, Notification reason, const MSLane* leftLane);
      81              :     bool notifyReroute(SUMOTrafficObject& veh);
      82              : 
      83              :     /// @brief Wether there is a flank conflict with the given driveway
      84              :     bool flankConflict(const MSDriveWay& other) const;
      85              : 
      86              :     /// @brief Wether there is a crossing conflict with the given driveway
      87              :     bool crossingConflict(const MSDriveWay& other) const;
      88              : 
      89              :     /// @brief Wether there is a bidi conflict with the given driveway
      90              :     bool bidiBlockedBy(const MSDriveWay& other) const;
      91              : 
      92              :     /// @brief Wether there is a bidi conflict with the end of the given driveway
      93              :     bool bidiBlockedByEnd(const MSDriveWay& other) const;
      94              : 
      95              :     /// @brief Wether the route of other passes into the forward section of this driveway
      96              :     bool forwardRouteConflict(std::set<const MSEdge*> forward, const MSDriveWay& other, bool secondCheck = false);
      97              : 
      98              :     /// @brief whether any of myConflictLanes is occupied (vehicles that are the target of a join must be ignored)
      99              :     bool conflictLaneOccupied(bool store = true, const SUMOVehicle* ego = nullptr) const;
     100              : 
     101              :     /// @brief whether any of myFoes is occupied (vehicles that are the target of a join must be ignored)
     102              :     bool foeDriveWayOccupied(bool store, const SUMOVehicle* ego, MSEdgeVector& occupied) const;
     103              : 
     104              :     /// @brief whether any of my Foes is being approached
     105              :     bool foeDriveWayApproached() const;
     106              : 
     107              :     /// @brief attempt reserve this driveway for the given vehicle
     108              :     bool reserve(const Approaching& closest, MSEdgeVector& occupied);
     109              : 
     110              :     /// @brief Write block items for this driveway
     111              :     void writeBlocks(OutputDevice& od) const;
     112              :     void writeBlockVehicles(OutputDevice& od) const;
     113              : 
     114              :     const std::vector<const MSEdge*>& getRoute() const {
     115              :         return myRoute;
     116              :     }
     117              : 
     118              :     const std::vector<const MSLane*>& getFlank() const {
     119              :         return myFlank;
     120              :     }
     121              : 
     122              :     const std::vector<const MSLane*>& getBidi() const {
     123              :         return myBidi;
     124              :     }
     125              : 
     126              :     const std::vector<MSLink*>& getConflictLinks() const {
     127              :         return myConflictLinks;
     128              :     }
     129              : 
     130              :     int getNumericalID() const {
     131        32540 :         return myNumericalID;
     132              :     }
     133              : 
     134              :     const std::vector<VehicleEvent>& getEvents() const {
     135              :         return myVehicleEvents;
     136              :     }
     137              : 
     138              :     void setEvents(const std::vector<VehicleEvent>& events) {
     139              :         myVehicleEvents = events;
     140              :     }
     141              : 
     142              :     void setVehicle(const std::string& vehID) {
     143         8136 :         myFirstVehicle = vehID;
     144         3092 :     }
     145              : 
     146              :     const std::vector<MSDriveWay*>& getFoes() const {
     147              :         return myFoes;
     148              :     }
     149              : 
     150              :     const std::vector<const MSLane*>& getForward() const {
     151              :         return myForward;
     152              :     }
     153              : 
     154              :     /// @brief whether the give route matches this driveway
     155              :     bool match(MSRouteIterator firstIt, MSRouteIterator endIt) const;
     156              : 
     157              :     void addDWDeadlock(const std::vector<const MSDriveWay*>& deadlockFoes);
     158              : 
     159              :     bool isDepartDriveway() const {
     160      9768979 :         return myOrigin == nullptr;
     161              :     };
     162              : 
     163              :     const MSLink* getOrigin() const {
     164              :         return myOrigin;
     165              :     }
     166              : 
     167              :     /// @brief whether the given train is on this driveway
     168              :     bool hasTrain(SUMOVehicle* veh) const;
     169              : 
     170              :     const std::vector<MSDriveWay*>& getSubDriveWays() const {
     171              :         return mySubDriveWays;
     172              :     }
     173              : 
     174              :     bool foundSignal() const {
     175              :         return myFoundSignal;
     176              :     }
     177              : 
     178              :     static void init();
     179              : 
     180              :     static bool hasRS(const MSEdge* cur, const MSEdge* next);
     181              : 
     182              :     /// @brief Whether veh must yield to the foe train
     183              :     static bool mustYield(const Approaching& veh, const Approaching& foe);
     184              : 
     185              :     /// @brief construct a new driveway by searching along the given route until all block structures are found
     186              :     static MSDriveWay* buildDriveWay(const std::string& id, const MSLink* link, MSRouteIterator first, MSRouteIterator end);
     187              : 
     188              :     /// @brief return logicID_linkIndex in a way that allows clicking in sumo-gui
     189              :     static std::string getClickableTLLinkID(const MSLink* link);
     190              : 
     191              :     static const MSDriveWay* getDepartureDriveway(const SUMOVehicle* veh, bool init = false);
     192              : 
     193              :     static void writeDepatureBlocks(OutputDevice& od, bool writeVehicles);
     194              : 
     195              :     /** @brief Save driveway occupancy into the given stream */
     196              :     static void saveState(OutputDevice& out);
     197              :     static void loadState(const SUMOSAXAttributes& attrs, int tag);
     198              : 
     199              : protected:
     200              : 
     201              :     /// @brief global driveway index
     202              :     int myNumericalID;
     203              : 
     204              :     /// @brief the link that enters this driveway or nullptr for a departure driveWay
     205              :     const MSLink* myOrigin;
     206              : 
     207              :     /// @brief whether the current signal is switched green for a train approaching this block
     208              :     const SUMOVehicle* myActive;
     209              : 
     210              :     /// @brief list of edges for matching against train routes
     211              :     std::vector<const MSEdge*> myRoute;
     212              : 
     213              :     /// @brief number of edges in myRoute where overlap with other driveways is forbidden
     214              :     int myCoreSize;
     215              : 
     216              :     /// @brief number of normal edges in myForward
     217              :     int myForwardEdgeCount;
     218              : 
     219              :     /// @brief whether this driveway ends its forward section with a rail signal (and thus comprises a full block)
     220              :     bool myFoundSignal;
     221              :     bool myFoundJump;
     222              :     bool myTerminateRoute;
     223              :     /// @brief whether driveway building was aborted due to MAX_BLOCK_LENGTH
     224              :     bool myAbortedBuild;
     225              :     /// @brief whether driveway building was aborted when no further bidi edge was found
     226              :     bool myBidiEnded;
     227              :     bool myIsSubDriveway;
     228              : 
     229              :     /* @brief the actual driveway part up to the next railsignal (halting position)
     230              :      * This must be free of other trains */
     231              :     std::vector<const MSLane*> myForward;
     232              : 
     233              :     /* @brief the list of bidirectional edges that can enter the forward
     234              :      * section and which must also be free of traffic
     235              :      * (up to the first element that could give protection) */
     236              :     std::vector<const MSLane*> myBidi;
     237              : 
     238              :     /* @brief the list of bidirectional edges that can enter the forward
     239              :      * section and which might contain deadlock-relevant traffic */
     240              :     std::vector<const MSLane*> myBidiExtended;
     241              : 
     242              :     /* @brief the list of edges that merge with the forward section
     243              :      * (found via backward search, up to the first element that could give protection) */
     244              :     std::vector<const MSLane*> myFlank;
     245              : 
     246              :     /// @brief the lanes that must be clear of trains before this signal can switch to green
     247              :     std::vector<const MSLane*> myConflictLanes;
     248              : 
     249              :     /* The conflict links for this block
     250              :      * Conflict resolution must be performed if vehicles are approaching the
     251              :      * current link and any of the conflict links */
     252              :     std::vector<MSLink*> myConflictLinks;
     253              : 
     254              :     /// @brief Whether the approaching vehicle is prevent from driving by another vehicle approaching the given link
     255              :     bool hasLinkConflict(const Approaching& closest, const MSLink* foeLink) const;
     256              : 
     257              :     /// @brief Wether this driveway (route) overlaps with the given one
     258              :     bool overlap(const MSDriveWay& other) const;
     259              : 
     260              :     /* @brief determine route that identifies this driveway (a subset of the
     261              :      * vehicle route)
     262              :      * collects:
     263              :      *   myRoute
     264              :      *   myForward
     265              :      *   myBidi
     266              :      *   myProtectedBidi
     267              :      *
     268              :      * returns edge that is assumed to safe from oncoming-deadlock or nullptr
     269              :      */
     270              :     void buildRoute(const MSLink* origin, MSRouteIterator next, MSRouteIterator end, LaneVisitedMap& visited, std::set<MSLink*>&);
     271              : 
     272              :     /* @brief find switches that threaten this driveway
     273              :      * @param[out] flankSwitches collect the switches
     274              :      */
     275              :     void checkFlanks(const MSLink* originLink, const std::vector<const MSLane*>& lanes, const LaneVisitedMap& visited, bool allFoes, bool movingBlock, std::set<MSLink*>& flankSwitches) const;
     276              : 
     277              :     /* @brief find links that cross the driveway without entering it
     278              :      * @param[out] flankSwitches collect the switches
     279              :      */
     280              :     void checkCrossingFlanks(MSLink* dwLink, const LaneVisitedMap& visited, std::set<MSLink*>& flankSwitches) const;
     281              : 
     282              :     /* @brief find upstream protection from the given link
     283              :      * @param[out] flank: the stored flank lanes
     284              :      */
     285              :     void findFlankProtection(MSLink* link, MSLink* origLink, std::vector<const MSLane*>& flank);
     286              : 
     287              :     /// @brief add all driveWays that start at the given link as foes
     288              :     void addFoes(const MSLink* link);
     289              : 
     290              :     /// @brief add sidings for the given foe
     291              :     void addSidings(MSDriveWay* foe, bool addToFoe = false);
     292              : 
     293              :     /// @brief derive foe driveways based on myBidi or myBidiExtended
     294              :     void addBidiFoes(const MSRailSignal* ownSignal, bool extended);
     295              : 
     296              :     /// @brief derive foe driveways that start at the same signal
     297              :     void addParallelFoes(const MSLink* link, const MSEdge* first);
     298              : 
     299              :     /// @brief derive foe driveways that enter the bidi section by reversing
     300              :     void addReversalFoes(bool movingBlock);
     301              : 
     302              :     /* @brief build shortened driveway that ends where the foe train leaves the conflict zone of this driveway
     303              :      * @return whether the foe has received a new entry in myFoes
     304              :      */
     305              :     bool buildSubFoe(MSDriveWay* foe, bool movingBlock);
     306              : 
     307              :     /// @brief add symmetical conflict link for foes when building a new driveway
     308              :     void addConflictLink(const MSLink* link);
     309              : 
     310              :     /// @brief return whether a siding can be used. If a siding exist but is occupied, also return the occupied driveway in the siding
     311              :     std::pair<bool, const MSDriveWay*> canUseSiding(const SUMOVehicle* ego, const MSDriveWay* foe, bool recurse = true) const;
     312              : 
     313              :     bool isFoeOrSubFoe(const MSDriveWay* foe) const;
     314              : 
     315              :     bool forwardEndOnRoute(const MSDriveWay* foe) const;
     316              : 
     317              :     void addSwitchFoes(MSLink* link);
     318              : 
     319              :     bool haveSubTrains() const;
     320              : 
     321              :     /// @brief compute distance along the forward section up to lastIndex
     322              :     double getForwardDistance(int lastIndex) const;
     323              : 
     324              :     /* @brief whether the train would have matched this driveway in it's past
     325              :      * @return If matching, returns the number of edges the vehicle has gone past the start of the driveway,
     326              :      *         Indicate no-match by returning a negative value */
     327              :     int matchesPastRoute(SUMOVehicle& sveh) const;
     328              : 
     329              :     /// @brief helper method for notifyEnter
     330              :     void enterDriveWay(SUMOVehicle& sveh, Notification reason);
     331              : 
     332              :     static bool hasJoin(const SUMOVehicle* ego, const SUMOVehicle* foe);
     333              : 
     334              :     static bool isSwitch(const MSLink* link);
     335              : 
     336              :     void _saveState(OutputDevice& out) const;
     337              : 
     338              :     /// @brief return logicID_linkIndex
     339              :     static std::string getTLLinkID(const MSLink* link);
     340              : 
     341              :     /// @brief return junctionID_junctionLinkIndex
     342              :     static std::string getJunctionLinkID(const MSLink* link);
     343              : 
     344              :     /// @brief print link descriptions
     345              :     static std::string formatVisitedMap(const LaneVisitedMap& visited);
     346              : 
     347              :     /// @brief append to map by map index and avoid undefined behavior
     348              :     static void appendMapIndex(LaneVisitedMap& map, const MSLane* lane);
     349              : 
     350              : private:
     351              : 
     352              :     struct Siding {
     353         2551 :         Siding(int s, int e, double l) : start(s), end(e), length(l) {}
     354              :         // indices along route
     355              :         int start;
     356              :         int end;
     357              :         double length;
     358              :     };
     359              : 
     360              :     std::set<SUMOVehicle*, ComparatorNumericalIdLess> myTrains;
     361              : 
     362              :     std::vector<VehicleEvent> myVehicleEvents;
     363              :     std::vector<MSDriveWay*> myFoes;
     364              :     std::map<const MSDriveWay*, std::vector<Siding>, ComparatorIdLess> mySidings;
     365              :     std::vector<std::set <const MSDriveWay*> > myDeadlocks;
     366              : 
     367              :     /* @brief shortened versions of this driveway to be used as foes instead of the long original
     368              :      * (ends as soon as the train has left a particular conflict section)
     369              :      * they are never attached to a LinkInfo and thus never the target of the match() function */
     370              :     std::vector<MSDriveWay*> mySubDriveWays;
     371              : 
     372              :     /// @brief track own occurences in myReversalDriveWays for cleanup in destructor
     373              :     std::vector<const MSEdge*> myReversals;
     374              : 
     375              :     /// @brief the first vehicle using this driveway
     376              :     std::string myFirstVehicle;
     377              : 
     378              :     static int myGlobalDriveWayIndex;
     379              :     static bool myWriteVehicles;
     380              :     static double myMovingBlockMaxDist;
     381              :     static std::set<const MSEdge*> myBlockLengthWarnings;
     382              : 
     383              :     /// @brief all driveways passing the given switch (used to look up flank foes)
     384              :     static std::map<const MSLink*, std::vector<MSDriveWay*> > mySwitchDriveWays;
     385              : 
     386              :     /// @brief all driveways reversing on the given switch (used to look up flank foes)
     387              :     static std::map<const MSEdge*, std::vector<MSDriveWay*> > myReversalDriveWays;
     388              : 
     389              :     /// @brief all driveways that do not start at a rail signal (and are only used at departure)
     390              :     static std::map<const MSEdge*, std::vector<MSDriveWay*>, ComparatorNumericalIdLess > myDepartureDriveways;
     391              :     static std::map<const MSJunction*, int> myDepartDrivewayIndex;
     392              :     /// @brief all driveways that do not start at a rail signal (and are only used at departure) by end edge
     393              :     static std::map<const MSEdge*, std::vector<MSDriveWay*> > myDepartureDrivewaysEnds;
     394              : 
     395              :     /// @brief all driveways that end on the given edge
     396              :     static std::map<const MSEdge*, std::vector<MSDriveWay*>, ComparatorNumericalIdLess> myEndingDriveways;
     397              : 
     398              :     /// @brief lookup table for state loading
     399              :     static std::map<ConstMSEdgeVector, MSDriveWay*> myDriveWayRouteLookup;
     400              :     static std::map<std::string, MSDriveWay*> myDriveWayLookup;
     401              : 
     402              : };
        

Generated by: LCOV version 2.0-1