Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
eclipse
GitHub Repository: eclipse/sumo
Path: blob/main/src/microsim/MSLaneChanger.h
185785 views
1
/****************************************************************************/
2
// Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3
// Copyright (C) 2002-2025 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
for (ConstChangerIt ce = myChanger.begin(); ce != myChanger.end(); ++ce) {
145
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
if (!ce->lane->myVehicles.empty()) {
157
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
};
352
353