/****************************************************************************/1// Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo2// Copyright (C) 2002-2025 German Aerospace Center (DLR) and others.3// This program and the accompanying materials are made available under the4// terms of the Eclipse Public License 2.0 which is available at5// https://www.eclipse.org/legal/epl-2.0/6// This Source Code may also be made available under the following Secondary7// Licenses when the conditions for such availability set forth in the Eclipse8// Public License 2.0 are satisfied: GNU General Public License, version 29// or later which is available at10// https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html11// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later12/****************************************************************************/13/// @file MSLaneChanger.h14/// @author Christian Roessel15/// @author Daniel Krajzewicz16/// @author Michael Behrisch17/// @author Jakob Erdmann18/// @date Fri, 01 Feb 200219///20// Performs lane changing of vehicles21/****************************************************************************/22#pragma once23#include <config.h>2425#include "MSLane.h"26#include "MSEdge.h"27#include "MSVehicle.h"28#include <vector>29#include <utils/iodevices/OutputDevice.h>303132// ===========================================================================33// class declarations34// ===========================================================================353637// ===========================================================================38// class definitions39// ===========================================================================40/**41* @class MSLaneChanger42* @brief Performs lane changing of vehicles43*/44class MSLaneChanger {45public:46/// Constructor47MSLaneChanger(const std::vector<MSLane*>* lanes, bool allowChanging);4849/// Destructor.50virtual ~MSLaneChanger();5152/// Start lane-change-process for all vehicles on the edge'e lanes.53void laneChange(SUMOTime t);5455public:56/** Structure used for lane-change. For every lane you have to57know four vehicles, the change-candidate veh and its follower58and leader. Further, information about the last vehicle that changed59into this lane is needed */60struct ChangeElem {6162ChangeElem(MSLane* _lane);6364/// @brief Register that vehicle belongs to Changer Item to after LC decisions65void registerHop(MSVehicle* vehicle);6667///@brief the leader vehicle for the current change candidate68MSVehicle* lead;69///@brief the lane corresponding to this ChangeElem (the current change candidate is on this lane)70MSLane* lane;71///@brief last vehicle that changed into this lane72MSVehicle* hoppedVeh;73/// @brief the next vehicle downstream of the ego vehicle that is blocked from changing to this lane74MSVehicle* lastBlocked;75/// @brief the farthest downstream vehicle on this edge that is blocked from changing to this lane76MSVehicle* firstBlocked;77/// @brief the next vehicle downstream of the ego vehicle that is stopped (and thus an obstacle)78MSVehicle* lastStopped;7980double dens;8182/// @brief whether changing is possible to either direction83bool mayChangeRight;84bool mayChangeLeft;8586/// relative indices of internal lanes with the same origin lane (siblings)87/// only used for changes on internal edges88std::vector<int> siblings;8990/// @name Members which are used only by MSLaneChangerSublane91/// @{92// the vehicles in front of the current vehicle (only on the current edge, continously updated during change() )93MSLeaderInfo ahead;9495// the vehicles in front of the current vehicle (including those on the next edge, contiously update during change() ))96MSLeaderDistanceInfo aheadNext;9798/// vehicles that cannot be stored in ahead because they are outside the lane bounds99std::vector<MSVehicle*> outsideBounds;100101/// visibility distance to the closest zipper link that may be encountered when driving on this lane102double zipperDist;103104/// the back position of the last blocked vehicle that wants to change to this lane105double lastBlockedBackPos;106107/// the waiting time of the last blocked vehicle that wants to change to this lane108SUMOTime lastBlockedWaitingTime;109///@}110111};112113public:114/** @brief The list of changers;115For each lane, a ChangeElem is being build */116typedef std::vector< ChangeElem > Changer;117118/// the iterator moving over the ChangeElems119typedef Changer::iterator ChangerIt;120121/// the iterator moving over the ChangeElems122typedef Changer::const_iterator ConstChangerIt;123124/// @brief return changer (only to be used by MSLaneChangerSublane from another instance)125Changer& getChanger() {126return myChanger;127}128129/// @brief retrieve properties of a blocked vehicle that wants to chane to the lane with the given index130std::pair<double, SUMOTime> getLastBlocked(int index) const;131132void postloadInitLC();133134protected:135/// Initialize the changer before looping over all vehicles.136virtual void initChanger();137138/** @brief Check if there is a single change-candidate in the changer.139Returns true if there is one. */140bool vehInChanger() const {141// If there is at least one valid vehicle under the veh's in myChanger142// return true.143for (ConstChangerIt ce = myChanger.begin(); ce != myChanger.end(); ++ce) {144if (veh(ce) != 0) {145return true;146}147}148return false;149}150151/** Returns the furthes unhandled vehicle on this change-elements lane152or 0 if there is none. */153MSVehicle* veh(ConstChangerIt ce) const {154// If ce has a valid vehicle, return it. Otherwise return 0.155if (!ce->lane->myVehicles.empty()) {156return ce->lane->myVehicles.back();157} else {158return 0;159}160}161162163/** Find a new candidate and try to change it. */164virtual bool change();165166167/** try changing to the opposite direction edge. */168bool changeOpposite(MSVehicle* vehicle, std::pair<MSVehicle*, double> leader, MSVehicle* lastStopped);169170std::pair<MSVehicle* const, double> getOncomingVehicle(const MSLane* opposite, std::pair<MSVehicle*,171double> neighOncoming, double searchDist, double& vMax, const MSVehicle* overtaken = nullptr,172MSLane::MinorLinkMode mLinkMode = MSLane::MinorLinkMode::FOLLOW_NEVER);173174std::pair<MSVehicle* const, double> getOncomingOppositeVehicle(const MSVehicle* vehicle,175std::pair<MSVehicle*, double> overtaken, double searchDist);176177/** Update changer for vehicles that did not change */178void registerUnchanged(MSVehicle* vehicle);179180/// @brief Take into account traci LC-commands.181/// @note This is currently only used within non-actionsteps.182void checkTraCICommands(MSVehicle* vehicle);183184/// @brief Execute TraCI LC-commands.185/// @note This is currently only used within non-actionsteps for the non-sublane model.186/// @return whether lane was changed187bool applyTraCICommands(MSVehicle* vehicle);188189/** After the possible change, update the changer. */190virtual void updateChanger(bool vehHasChanged);191192/** During lane-change a temporary vehicle container is filled within193the lanes (bad practice to modify foreign members, I know). Swap194this container with the real one. */195void updateLanes(SUMOTime t);196197/** @brief Find current candidate.198If there is none, myChanger.end() is returned. */199ChangerIt findCandidate();200201/* @brief check whether lane changing in the given direction is desirable202* and possible */203int checkChangeWithinEdge(204int laneOffset,205const std::pair<MSVehicle* const, double>& leader,206const std::vector<MSVehicle::LaneQ>& preb) const;207208/* @brief check whether lane changing in the given direction is desirable209* and possible */210int checkChange(211int laneOffset,212const MSLane* targetLane,213const std::pair<MSVehicle* const, double>& leader,214const std::pair<MSVehicle* const, double>& follower,215const std::pair<MSVehicle* const, double>& neighLead,216const std::pair<MSVehicle* const, double>& neighFollow,217const std::vector<MSVehicle::LaneQ>& preb) const;218219/* @brief call lanechange model to check the merits of an opposite-direction220* change and update state accordingly */221virtual bool checkChangeOpposite(222MSVehicle* vehicle,223int laneOffset,224MSLane* targetLane,225const std::pair<MSVehicle* const, double>& leader,226const std::pair<MSVehicle* const, double>& neighLead,227const std::pair<MSVehicle* const, double>& neighFollow,228const std::vector<MSVehicle::LaneQ>& preb);229230231/* @brief start the lane change maneuver (and finish it instantly if gLaneChangeDuration == 0)232* @return False when aborting the change due to being remote controlled*/233bool startChange(MSVehicle* vehicle, ChangerIt& from, int direction);234235/// @brief continue a lane change maneuver and return whether the vehicle has completely moved onto the new lane (used if gLaneChangeDuration > 0)236bool continueChange(MSVehicle* vehicle, ChangerIt& from);237238std::pair<MSVehicle* const, double> getRealFollower(const ChangerIt& target) const;239240std::pair<MSVehicle* const, double> getRealLeader(const ChangerIt& target) const;241242/// @brief whether changing to the lane in the given direction should be considered243bool mayChange(int direction) const;244245/// @brief return the closer follower of ego246static MSVehicle* getCloserFollower(const double maxPos, MSVehicle* follow1, MSVehicle* follow2);247248/** @brief Compute the time and space required for overtaking the given leader249* @param[in] vehicle The vehicle that wants to overtake250* @param[in] leader The vehicle to be overtaken251* @param[in] gap The gap between vehicle and leader252* @param[out] timeToOvertake The time for overtaking253* @param[out] spaceToOvertake The space for overtaking254*/255static void computeOvertakingTime(const MSVehicle* vehicle, double vMax, const MSVehicle* leader, double gap, double& timeToOvertake, double& spaceToOvertake);256257/** @brief return leader vehicle that is to be overtaken258* @param[out] maxSpace The maxium space that can be used for the overtaking maneuver (limits speed)259* @param[in] vehicle The vehicle that wants to overtake260* @param[in] leader The vehicle to be overtaken and the gap to this vehicle261* @param[in] maxLookAhead The maximum lookahead distance262*263* This methods calls itself recursively to find the leader of a column of264* vehicles to be overtaken (if there is no sufficient gap for stopping in between)265*/266static std::pair<MSVehicle*, double> getColumnleader(double& maxSpace, MSVehicle* vehicle, std::pair<MSVehicle*, double> leader, double maxLookAhead = std::numeric_limits<double>::max());267268/// @brief return the next lane in conts beyond lane or nullptr269static const MSLane* getLaneAfter(const MSLane* lane, const std::vector<MSLane*>& conts, bool allowMinor, bool& contsEnd);270271/// @brief whether vehicle has an opposite-direction stop within relevant range272static bool hasOppositeStop(MSVehicle* vehicle);273274/// @brief decide whether to change (back or forth) for an opposite stop275bool checkOppositeStop(MSVehicle* vehicle, const MSLane* oncomingLane, const MSLane* opposite, std::pair<MSVehicle*, double> leader);276277/** @brief avoid opposite-diretion deadlock when vehicles are stopped on both sides of the road278* The method may call saveBlockerLength to affect vehicle speed in the next step279*/280bool avoidDeadlock(MSVehicle* vehicle,281std::pair<MSVehicle*, double> neighLead,282std::pair<MSVehicle*, double> overtaken,283std::pair<MSVehicle*, double> leader);284285/** @brief keep stopping to resolve opposite-diretion deadlock while there is oncoming traffic286* The method may call saveBlockerLength to affect vehicle speed in the next step287*/288bool resolveDeadlock(MSVehicle* vehicle,289std::pair<MSVehicle* const, double> leader,290std::pair<MSVehicle*, double> neighLead,291std::pair<MSVehicle*, double> overtaken);292293/// @brief check whether to keep stopping for oncoming vehicles in the deadlock zone294bool yieldToDeadlockOncoming(const MSVehicle* vehicle, const MSVehicle* stoppedNeigh, double dist);295296/// @brief check whether to yield for oncoming vehicles that have waited longer for opposite overtaking297bool yieldToOppositeWaiting(const MSVehicle* vehicle, const MSVehicle* stoppedNeigh, double dist, SUMOTime deltaWait = 0);298299/// @brief determine for how long the vehicle can drive safely on the opposite side300double computeSafeOppositeLength(MSVehicle* vehicle, double oppositeLength, const MSLane* source, double usableDist,301std::pair<MSVehicle*, double> oncoming, double vMax, double oncomingSpeed,302std::pair<MSVehicle*, double> neighLead,303std::pair<MSVehicle*, double> overtaken,304std::pair<MSVehicle*, double> neighFollow,305double surplusGap, const MSLane* opposite,306bool canOvertake);307308// @brief compute distance that can safely be driven on the opposite side309static double computeSurplusGap(const MSVehicle* vehicle, const MSLane* opposite, std::pair<MSVehicle*, double> oncoming, double timeToOvertake,310double spaceToOvertake, double& oncomingSpeed, bool oncomingOpposite = false);311312// @brief find hilltop within searchDistance313static bool foundHilltop(MSVehicle* vehicle, bool foundHill, double searchDist, const std::vector<MSLane*>& bestLanes, int view, double pos, double lastMax, double hilltopThreshold);314315/// @brief add LaneQ for opposite lanes316static std::vector<MSVehicle::LaneQ> getBestLanesOpposite(MSVehicle* vehicle, const MSLane* stopLane, double oppositeLength);317318/// @brief compute maximum maneuver speed319static double getMaxOvertakingSpeed(const MSVehicle* vehicle, double maxSpaceToOvertake);320321protected:322/// Container for ChangeElemements, one for every lane in the edge.323Changer myChanger;324325/** Change-candidate. Last of the vehicles in changer. Only this one326will try to change. Every vehicle on the edge will be a candidate327once in the change-process. */328ChangerIt myCandi;329330/* @brief Whether vehicles may start to change lanes on this edge331* (finishing a change in progress is always permitted) */332const bool myAllowsChanging;333334/// @brief whether this edge allows changing to the opposite direction edge335const bool myChangeToOpposite;336337/* @brief whether neigboring lanes target the same outgoing edge but have different foe links and338* therefore require an extra MSLink::opened check before changing */339bool checkOpened;340341private:342/// Default constructor.343MSLaneChanger();344345/// Copy constructor.346MSLaneChanger(const MSLaneChanger&);347348/// Assignment operator.349MSLaneChanger& operator=(const MSLaneChanger&);350};351352353