LCOV - code coverage report
Current view: top level - src/microsim - MSLaneChanger.h (source / functions) Coverage Total Hit
Test: lcov.info Lines: 100.0 % 4 4
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    MSLaneChanger.h
      15              : /// @author  Christian Roessel
      16              : /// @author  Daniel Krajzewicz
      17              : /// @author  Michael Behrisch
      18              : /// @author  Jakob Erdmann
      19              : /// @date    Fri, 01 Feb 2002
      20              : ///
      21              : // Performs lane changing of vehicles
      22              : /****************************************************************************/
      23              : #pragma once
      24              : #include <config.h>
      25              : 
      26              : #include "MSLane.h"
      27              : #include "MSEdge.h"
      28              : #include "MSVehicle.h"
      29              : #include <vector>
      30              : #include <utils/iodevices/OutputDevice.h>
      31              : 
      32              : 
      33              : // ===========================================================================
      34              : // class declarations
      35              : // ===========================================================================
      36              : 
      37              : 
      38              : // ===========================================================================
      39              : // class definitions
      40              : // ===========================================================================
      41              : /**
      42              :  * @class MSLaneChanger
      43              :  * @brief Performs lane changing of vehicles
      44              :  */
      45              : class MSLaneChanger {
      46              : public:
      47              :     /// Constructor
      48              :     MSLaneChanger(const std::vector<MSLane*>* lanes, bool allowChanging);
      49              : 
      50              :     /// Destructor.
      51              :     virtual ~MSLaneChanger();
      52              : 
      53              :     /// Start lane-change-process for all vehicles on the edge'e lanes.
      54              :     void laneChange(SUMOTime t);
      55              : 
      56              : public:
      57              :     /** Structure used for lane-change. For every lane you have to
      58              :         know four vehicles, the change-candidate veh and its follower
      59              :         and leader. Further, information about the last vehicle that changed
      60              :         into this lane is needed */
      61              :     struct ChangeElem {
      62              : 
      63              :         ChangeElem(MSLane* _lane);
      64              : 
      65              :         /// @brief Register that vehicle belongs to Changer Item to after LC decisions
      66              :         void registerHop(MSVehicle* vehicle);
      67              : 
      68              :         ///@brief the leader vehicle for the current change candidate
      69              :         MSVehicle*                lead;
      70              :         ///@brief the lane corresponding to this ChangeElem (the current change candidate is on this lane)
      71              :         MSLane*                   lane;
      72              :         ///@brief last vehicle that changed into this lane
      73              :         MSVehicle*                hoppedVeh;
      74              :         /// @brief the next vehicle downstream of the ego vehicle that is blocked from changing to this lane
      75              :         MSVehicle*                lastBlocked;
      76              :         /// @brief the farthest downstream vehicle on this edge that is blocked from changing to this lane
      77              :         MSVehicle*                firstBlocked;
      78              :         /// @brief the next vehicle downstream of the ego vehicle that is stopped (and thus an obstacle)
      79              :         MSVehicle*                lastStopped;
      80              : 
      81              :         double dens;
      82              : 
      83              :         /// @brief whether changing is possible to either direction
      84              :         bool mayChangeRight;
      85              :         bool mayChangeLeft;
      86              : 
      87              :         /// relative indices of internal lanes with the same origin lane (siblings)
      88              :         /// only used for changes on internal edges
      89              :         std::vector<int>          siblings;
      90              : 
      91              :         /// @name Members which are used only by MSLaneChangerSublane
      92              :         /// @{
      93              :         // the vehicles in front of the current vehicle (only on the current edge, continously updated during change() )
      94              :         MSLeaderInfo ahead;
      95              : 
      96              :         // the vehicles in front of the current vehicle (including those on the next edge, contiously update during change() ))
      97              :         MSLeaderDistanceInfo aheadNext;
      98              : 
      99              :         /// vehicles that cannot be stored in ahead because they are outside the lane bounds
     100              :         std::vector<MSVehicle*>  outsideBounds;
     101              : 
     102              :         /// visibility distance to the closest zipper link that may be encountered when driving on this lane
     103              :         double zipperDist;
     104              : 
     105              :         /// the back position of the last blocked vehicle that wants to change to this lane
     106              :         double lastBlockedBackPos;
     107              : 
     108              :         /// the waiting time of the last blocked vehicle that wants to change to this lane
     109              :         SUMOTime lastBlockedWaitingTime;
     110              :         ///@}
     111              : 
     112              :     };
     113              : 
     114              : public:
     115              :     /** @brief The list of changers;
     116              :         For each lane, a ChangeElem is being build */
     117              :     typedef std::vector< ChangeElem > Changer;
     118              : 
     119              :     /// the iterator moving over the ChangeElems
     120              :     typedef Changer::iterator ChangerIt;
     121              : 
     122              :     /// the iterator moving over the ChangeElems
     123              :     typedef Changer::const_iterator ConstChangerIt;
     124              : 
     125              :     /// @brief return changer (only to be used by MSLaneChangerSublane from another instance)
     126              :     Changer& getChanger() {
     127              :         return myChanger;
     128              :     }
     129              : 
     130              :     /// @brief retrieve properties of a blocked vehicle that wants to chane to the lane with the given index
     131              :     std::pair<double, SUMOTime> getLastBlocked(int index) const;
     132              : 
     133              :     void postloadInitLC();
     134              : 
     135              : protected:
     136              :     /// Initialize the changer before looping over all vehicles.
     137              :     virtual void initChanger();
     138              : 
     139              :     /** @brief Check if there is a single change-candidate in the changer.
     140              :         Returns true if there is one. */
     141              :     bool vehInChanger() const {
     142              :         // If there is at least one valid vehicle under the veh's in myChanger
     143              :         // return true.
     144    566882506 :         for (ConstChangerIt ce = myChanger.begin(); ce != myChanger.end(); ++ce) {
     145    369887185 :             if (veh(ce) != 0) {
     146              :                 return true;
     147              :             }
     148              :         }
     149              :         return false;
     150              :     }
     151              : 
     152              :     /** Returns the furthes unhandled vehicle on this change-elements lane
     153              :         or 0 if there is none. */
     154              :     MSVehicle* veh(ConstChangerIt ce) const {
     155              :         // If ce has a valid vehicle, return it. Otherwise return 0.
     156   5776940005 :         if (!ce->lane->myVehicles.empty()) {
     157   5483346940 :             return ce->lane->myVehicles.back();
     158              :         } else {
     159              :             return 0;
     160              :         }
     161              :     }
     162              : 
     163              : 
     164              :     /** Find a new candidate and try to change it. */
     165              :     virtual bool change();
     166              : 
     167              : 
     168              :     /** try changing to the opposite direction edge. */
     169              :     bool changeOpposite(MSVehicle* vehicle, std::pair<MSVehicle*, double> leader, MSVehicle* lastStopped);
     170              : 
     171              :     std::pair<MSVehicle* const, double> getOncomingVehicle(const MSLane* opposite, std::pair<MSVehicle*,
     172              :             double> neighOncoming, double searchDist, double& vMax, const MSVehicle* overtaken = nullptr,
     173              :             MSLane::MinorLinkMode mLinkMode = MSLane::MinorLinkMode::FOLLOW_NEVER);
     174              : 
     175              :     std::pair<MSVehicle* const, double> getOncomingOppositeVehicle(const MSVehicle* vehicle,
     176              :             std::pair<MSVehicle*, double> overtaken, double searchDist);
     177              : 
     178              :     /** Update changer for vehicles that did not change */
     179              :     void registerUnchanged(MSVehicle* vehicle);
     180              : 
     181              :     /// @brief Take into account traci LC-commands.
     182              :     /// @note This is currently only used within non-actionsteps.
     183              :     void checkTraCICommands(MSVehicle* vehicle);
     184              : 
     185              :     /// @brief Execute TraCI LC-commands.
     186              :     /// @note This is currently only used within non-actionsteps for the non-sublane model.
     187              :     /// @return whether lane was changed
     188              :     bool applyTraCICommands(MSVehicle* vehicle);
     189              : 
     190              :     /** After the possible change, update the changer. */
     191              :     virtual void updateChanger(bool vehHasChanged);
     192              : 
     193              :     /** During lane-change a temporary vehicle container is filled within
     194              :         the lanes (bad practice to modify foreign members, I know). Swap
     195              :         this container with the real one. */
     196              :     void updateLanes(SUMOTime t);
     197              : 
     198              :     /** @brief Find current candidate.
     199              :         If there is none, myChanger.end() is returned. */
     200              :     ChangerIt findCandidate();
     201              : 
     202              :     /* @brief check whether lane changing in the given direction is desirable
     203              :      * and possible */
     204              :     int checkChangeWithinEdge(
     205              :         int laneOffset,
     206              :         const std::pair<MSVehicle* const, double>& leader,
     207              :         const std::vector<MSVehicle::LaneQ>& preb) const;
     208              : 
     209              :     /* @brief check whether lane changing in the given direction is desirable
     210              :      * and possible */
     211              :     int checkChange(
     212              :         int laneOffset,
     213              :         const MSLane* targetLane,
     214              :         const std::pair<MSVehicle* const, double>& leader,
     215              :         const std::pair<MSVehicle* const, double>& follower,
     216              :         const std::pair<MSVehicle* const, double>& neighLead,
     217              :         const std::pair<MSVehicle* const, double>& neighFollow,
     218              :         const std::vector<MSVehicle::LaneQ>& preb) const;
     219              : 
     220              :     /* @brief call lanechange model to check the merits of an opposite-direction
     221              :      * change and update state accordingly */
     222              :     virtual bool checkChangeOpposite(
     223              :         MSVehicle* vehicle,
     224              :         int laneOffset,
     225              :         MSLane* targetLane,
     226              :         const std::pair<MSVehicle* const, double>& leader,
     227              :         const std::pair<MSVehicle* const, double>& neighLead,
     228              :         const std::pair<MSVehicle* const, double>& neighFollow,
     229              :         const std::vector<MSVehicle::LaneQ>& preb);
     230              : 
     231              : 
     232              :     /*  @brief start the lane change maneuver (and finish it instantly if gLaneChangeDuration == 0)
     233              :      *  @return False when aborting the change due to being remote controlled*/
     234              :     bool startChange(MSVehicle* vehicle, ChangerIt& from, int direction);
     235              : 
     236              :     ///  @brief continue a lane change maneuver and return whether the vehicle has completely moved onto the new lane (used if gLaneChangeDuration > 0)
     237              :     bool continueChange(MSVehicle* vehicle, ChangerIt& from);
     238              : 
     239              :     std::pair<MSVehicle* const, double> getRealFollower(const ChangerIt& target) const;
     240              : 
     241              :     std::pair<MSVehicle* const, double> getRealLeader(const ChangerIt& target) const;
     242              : 
     243              :     /// @brief whether changing to the lane in the given direction should be considered
     244              :     bool mayChange(int direction) const;
     245              : 
     246              :     /// @brief return the closer follower of ego
     247              :     static MSVehicle* getCloserFollower(const double maxPos, MSVehicle* follow1, MSVehicle* follow2);
     248              : 
     249              :     /** @brief Compute the time and space required for overtaking the given leader
     250              :      * @param[in] vehicle The vehicle that wants to overtake
     251              :      * @param[in] leader The vehicle to be overtaken
     252              :      * @param[in] gap The gap between vehicle and leader
     253              :      * @param[out] timeToOvertake The time for overtaking
     254              :      * @param[out] spaceToOvertake The space for overtaking
     255              :      */
     256              :     static void computeOvertakingTime(const MSVehicle* vehicle, double vMax, const MSVehicle* leader, double gap, double& timeToOvertake, double& spaceToOvertake);
     257              : 
     258              :     /** @brief return leader vehicle that is to be overtaken
     259              :      * @param[out] maxSpace The maxium space that can be used for the overtaking maneuver (limits speed)
     260              :      * @param[in] vehicle The vehicle that wants to overtake
     261              :      * @param[in] leader The vehicle to be overtaken and the gap to this vehicle
     262              :      * @param[in] maxLookAhead The maximum lookahead distance
     263              :      *
     264              :      * This methods calls itself recursively to find the leader of a column of
     265              :      * vehicles to be overtaken (if there is no sufficient gap for stopping in between)
     266              :      */
     267              :     static std::pair<MSVehicle*, double> getColumnleader(double& maxSpace, MSVehicle* vehicle, std::pair<MSVehicle*, double> leader, double maxLookAhead = std::numeric_limits<double>::max());
     268              : 
     269              :     /// @brief return the next lane in conts beyond lane or nullptr
     270              :     static const MSLane* getLaneAfter(const MSLane* lane, const std::vector<MSLane*>& conts, bool allowMinor, bool& contsEnd);
     271              : 
     272              :     /// @brief whether vehicle has an opposite-direction stop within relevant range
     273              :     static bool hasOppositeStop(MSVehicle* vehicle);
     274              : 
     275              :     /// @brief decide whether to change (back or forth) for an opposite stop
     276              :     bool checkOppositeStop(MSVehicle* vehicle, const MSLane* oncomingLane, const MSLane* opposite, std::pair<MSVehicle*, double> leader);
     277              : 
     278              :     /** @brief avoid opposite-diretion deadlock when vehicles are stopped on both sides of the road
     279              :      * The method may call saveBlockerLength to affect vehicle speed in the next step
     280              :      */
     281              :     bool avoidDeadlock(MSVehicle* vehicle,
     282              :                        std::pair<MSVehicle*, double> neighLead,
     283              :                        std::pair<MSVehicle*, double> overtaken,
     284              :                        std::pair<MSVehicle*, double> leader);
     285              : 
     286              :     /** @brief keep stopping to resolve opposite-diretion deadlock while there is oncoming traffic
     287              :      * The method may call saveBlockerLength to affect vehicle speed in the next step
     288              :      */
     289              :     bool resolveDeadlock(MSVehicle* vehicle,
     290              :                          std::pair<MSVehicle* const, double> leader,
     291              :                          std::pair<MSVehicle*, double> neighLead,
     292              :                          std::pair<MSVehicle*, double> overtaken);
     293              : 
     294              :     /// @brief check whether to keep stopping for oncoming vehicles in the deadlock zone
     295              :     bool yieldToDeadlockOncoming(const MSVehicle* vehicle, const MSVehicle* stoppedNeigh, double dist);
     296              : 
     297              :     /// @brief check whether to yield for oncoming vehicles that have waited longer for opposite overtaking
     298              :     bool yieldToOppositeWaiting(const MSVehicle* vehicle, const MSVehicle* stoppedNeigh, double dist, SUMOTime deltaWait = 0);
     299              : 
     300              :     /// @brief determine for how long the vehicle can drive safely on the opposite side
     301              :     double computeSafeOppositeLength(MSVehicle* vehicle, double oppositeLength, const MSLane* source, double usableDist,
     302              :                                      std::pair<MSVehicle*, double> oncoming, double vMax, double oncomingSpeed,
     303              :                                      std::pair<MSVehicle*, double> neighLead,
     304              :                                      std::pair<MSVehicle*, double> overtaken,
     305              :                                      std::pair<MSVehicle*, double> neighFollow,
     306              :                                      double surplusGap, const MSLane* opposite,
     307              :                                      bool canOvertake);
     308              : 
     309              :     // @brief compute distance that can safely be driven on the opposite side
     310              :     static double computeSurplusGap(const MSVehicle* vehicle, const MSLane* opposite, std::pair<MSVehicle*, double> oncoming, double timeToOvertake,
     311              :                                     double spaceToOvertake, double& oncomingSpeed, bool oncomingOpposite = false);
     312              : 
     313              :     // @brief find hilltop within searchDistance
     314              :     static bool foundHilltop(MSVehicle* vehicle, bool foundHill, double searchDist, const std::vector<MSLane*>& bestLanes, int view, double pos, double lastMax, double hilltopThreshold);
     315              : 
     316              :     /// @brief add LaneQ for opposite lanes
     317              :     static std::vector<MSVehicle::LaneQ> getBestLanesOpposite(MSVehicle* vehicle, const MSLane* stopLane, double oppositeLength);
     318              : 
     319              :     /// @brief compute maximum maneuver speed
     320              :     static double getMaxOvertakingSpeed(const MSVehicle* vehicle, double maxSpaceToOvertake);
     321              : 
     322              : protected:
     323              :     /// Container for ChangeElemements, one for every lane in the edge.
     324              :     Changer   myChanger;
     325              : 
     326              :     /** Change-candidate. Last of the vehicles in changer. Only this one
     327              :         will try to change. Every vehicle on the edge will be a candidate
     328              :         once in the change-process. */
     329              :     ChangerIt myCandi;
     330              : 
     331              :     /* @brief Whether vehicles may start to change lanes on this edge
     332              :      * (finishing a change in progress is always permitted) */
     333              :     const bool myAllowsChanging;
     334              : 
     335              :     /// @brief whether this edge allows changing to the opposite direction edge
     336              :     const bool myChangeToOpposite;
     337              : 
     338              :     /* @brief whether neigboring lanes target the same outgoing edge but have different foe links and
     339              :      * therefore require an extra MSLink::opened check before changing */
     340              :     bool checkOpened;
     341              : 
     342              : private:
     343              :     /// Default constructor.
     344              :     MSLaneChanger();
     345              : 
     346              :     /// Copy constructor.
     347              :     MSLaneChanger(const MSLaneChanger&);
     348              : 
     349              :     /// Assignment operator.
     350              :     MSLaneChanger& operator=(const MSLaneChanger&);
     351              : };
        

Generated by: LCOV version 2.0-1