Eclipse SUMO - Simulation of Urban MObility
Loading...
Searching...
No Matches
MSLCHelper.cpp
Go to the documentation of this file.
1/****************************************************************************/
2// Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3// Copyright (C) 2013-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/****************************************************************************/
18// Common functions for lane change models
19/****************************************************************************/
20
21#include <microsim/MSEdge.h>
22#include <microsim/MSLane.h>
23#include <microsim/MSLink.h>
24#include <microsim/MSVehicle.h>
26#include "MSLCHelper.h"
27
28// ===========================================================================
29// Debug flags
30// ===========================================================================
31//#define DEBUG_WANTS_CHANGE
32//#define DEBUG_SAVE_BLOCKER_LENGTH
33//#define DEBUG_UNWILLING_TO_HELP
34
35#define DEBUG_COND (veh.isSelected())
36//#define DEBUG_COND (true)
37
38
39// ===========================================================================
40// member method definitions
41// ===========================================================================
42
43double
45 double bonusParam,
46 const MSVehicle::LaneQ& curr,
47 const MSVehicle::LaneQ& neigh,
48 const MSVehicle::LaneQ& best) {
49 if (veh.getLaneChangeModel().isOpposite()) {
50 return 0;
51 }
52 const MSVehicle::LaneQ& inner = neigh.lane->getIndex() > curr.lane->getIndex() ? neigh : curr;
53#ifdef DEBUG_WANTS_CHANGE
54 const bool debugVehicle = veh.getLaneChangeModel().debugVehicle();
55 if (debugVehicle) {
56 std::cout << SIMTIME << " veh=" << veh.getID() << " getRoundaboutDistBonus bonusParam=" << bonusParam
57 << " curr=" << curr.lane->getID()
58 << " neigh=" << neigh.lane->getID()
59 << " inner=" << inner.lane->getID()
60 << " best=" << best.lane->getID()
61 << "\n innerCont=" << toString(inner.bestContinuations)
62 << "\n bestCont=" << toString(best.bestContinuations)
63 << "\n";
64 }
65#endif
66 if (neigh.lane == inner.lane && curr.bestContinuations.size() < neigh.bestContinuations.size()) {
67 // the current lane does not continue to the roundabout and we need a strategic change first.
68 return 0;
69 }
70
71 int roundaboutJunctionsAhead = 0;
72 bool enteredRoundabout = false;
73 double seen = -veh.getPositionOnLane();
74
75 // first check using only normal lanes
76 for (int i = 0; i < (int)best.bestContinuations.size(); i++) {
77 const MSLane* lane = best.bestContinuations[i];
78 if (lane == nullptr) {
79 lane = veh.getLane();
80 }
81 if ((!enteredRoundabout || lane->getEdge().isRoundabout()) && i >= (int)inner.bestContinuations.size()) {
82 // no bonus if we cannot continue on the inner lane until leaving the roundabout
83#ifdef DEBUG_WANTS_CHANGE
84 if (debugVehicle) {
85 std::cout << " noBonus: inner does not continue (lane=" << lane->getID() << ")\n";
86 }
87#endif
88 return 0;
89 }
90 if (seen > 300) {
91 // avoid long look-ahead
92#ifdef DEBUG_WANTS_CHANGE
93 if (debugVehicle) {
94 std::cout << " noBonus: seen=" << seen << " (lane=" << lane->getID() << ")\n";
95 }
96#endif
97 return 0;
98 }
99 const MSJunction* junction = lane->getEdge().getToJunction();
100 if (lane->getEdge().isRoundabout()) {
101 enteredRoundabout = true;
102 if (junction->getIncoming().size() + junction->getOutgoing().size() > 2) {
103 roundaboutJunctionsAhead++;
104 }
105 } else if (enteredRoundabout) {
106 // only check the first roundabout
107 break;
108 }
109 seen += lane->getLength();
110 }
111 // no bonus if we want to take the next exit
112 if (roundaboutJunctionsAhead < 2) {
113#ifdef DEBUG_WANTS_CHANGE
114 if (debugVehicle) {
115 std::cout << " noBonus: roundaboutJunctionsAhead=" << roundaboutJunctionsAhead << "\n";
116 }
117#endif
118 return 0;
119 }
120 // compute bonus value based on jamming and exact distances (taking into
121 // account internal lanes)
122 double occupancyOuter = 0;
123 double occupancyInner = 0;
124 double distanceInRoundabout = 0;
125 MSLane* prevNormal = nullptr;
126 MSLane* prevInner = nullptr;
127 enteredRoundabout = false;
128 for (int i = 0; i < (int)best.bestContinuations.size(); i++) {
129 MSLane* lane = best.bestContinuations[i];
130 if (lane == nullptr) {
131 continue;
132 }
133 if (lane->getEdge().isRoundabout()) {
134 enteredRoundabout = true;
135 } else if (enteredRoundabout) {
136 // only check the first roundabout
137 break;
138 }
139 MSLane* via = nullptr;
140 if (prevNormal != nullptr) {
141 for (MSLink* link : prevNormal->getLinkCont()) {
142 if (link->getLane() == lane) {
143 via = link->getViaLane();
144 }
145 }
146 }
147 if (enteredRoundabout) {
148 distanceInRoundabout += lane->getLength();
149 if (via != nullptr) {
150 distanceInRoundabout += via->getLength();
151 }
152 }
153 // discount vehicles that are upstream from ego
154 const double upstreamDiscount = &lane->getEdge() == &veh.getLane()->getEdge()
155 ? (lane->getLength() - veh.getPositionOnLane()) / lane->getLength() : 1;
156 prevNormal = lane;
157 occupancyOuter += upstreamDiscount * lane->getBruttoVehLenSum();
158#ifdef DEBUG_WANTS_CHANGE
159 if (debugVehicle) {
160 std::cout << " lane=" << lane->getID() << " occ=" << lane->getBruttoVehLenSum() << " discount=" << upstreamDiscount << " outer=" << occupancyOuter << "\n";
161 }
162#endif
163 if (via != nullptr) {
164 occupancyOuter += via->getBruttoVehLenSum();
165#ifdef DEBUG_WANTS_CHANGE
166 if (debugVehicle) {
167 std::cout << " via=" << via->getID() << " occ=" << via->getBruttoVehLenSum() << " outer=" << occupancyOuter << "\n";
168 }
169#endif
170 }
171 if (i < (int)inner.bestContinuations.size()) {
172 MSLane* innerLane = inner.bestContinuations[i];
173 occupancyInner += upstreamDiscount * innerLane->getBruttoVehLenSum();
174#ifdef DEBUG_WANTS_CHANGE
175 if (debugVehicle) {
176 std::cout << " inner=" << innerLane->getID() << " occ=" << innerLane->getBruttoVehLenSum() << " discount=" << upstreamDiscount << " inner=" << occupancyInner << "\n";
177 }
178#endif
179 if (prevInner != nullptr) {
180 for (MSLink* link : prevInner->getLinkCont()) {
181 if (link->getLane() == innerLane && link->getViaLane() != nullptr) {
182 occupancyInner += link->getViaLane()->getBruttoVehLenSum();
183#ifdef DEBUG_WANTS_CHANGE
184 if (debugVehicle) {
185 std::cout << " innerVia=" << link->getViaLane()->getID() << " occ=" << link->getViaLane()->getBruttoVehLenSum() << " inner=" << occupancyInner << "\n";
186 }
187#endif
188 }
189 }
190 }
191 prevInner = innerLane;
192 }
193 }
194
195#ifdef DEBUG_WANTS_CHANGE
196 if (debugVehicle) {
197 std::cout << " distanceInRoundabout=" << distanceInRoundabout
198 << " roundaboutJunctionsAhead=" << roundaboutJunctionsAhead
199 << " occupancyInner=" << occupancyInner
200 << " occupancyOuter=" << occupancyOuter
201 << "\n";
202 }
203#endif
204 if (abs(curr.bestLaneOffset) > 1 && enteredRoundabout) {
206 const double reservation = veh.getLaneChangeModel().getExtraReservation(curr.bestLaneOffset);
207 const double leftSpace = distanceInRoundabout - reservation - veh.getPositionOnLane();
208#ifdef DEBUG_WANTS_CHANGE
209 if (debugVehicle) {
210 std::cout << " bGap=" << bGap << " reserving=" << reservation << " leftover=" << (leftSpace - bGap) << "\n";
211 }
212#endif
213 if (bGap > leftSpace) {
214 return 0;
215 }
216 }
217
218 const double maxOccupancy = MAX2(occupancyInner, occupancyOuter);
219 // give some bonus for using the inside lane at equal occupancy
220 const double bonus = roundaboutJunctionsAhead * 7.5;
221 const double relativeJam = (occupancyOuter - occupancyInner + bonus) / (maxOccupancy + bonus);
222 // no bonus if the inner lane or the left lane entering the roundabout is jammed
223 double jamFactor = MAX2(0.0, relativeJam);
224 if (veh.getLane()->getEdge().isRoundabout() && curr.lane->getIndex() > neigh.lane->getIndex()) {
225 // only use jamFactor when deciding to move to the inside lane but prefer
226 // staying inside if the distance allows it
227 jamFactor = 1;
228 }
229 const double result = distanceInRoundabout * jamFactor * bonusParam * 9; // the 9 is abitrary and only there for backward compatibility
230#ifdef DEBUG_WANTS_CHANGE
231 if (debugVehicle) {
232 std::cout << " relativeJam=" << relativeJam
233 << " jamFactor=" << jamFactor
234 << " distanceBonus=" << result
235 << "\n";
236 }
237#endif
238 return result;
239}
240
241
242bool
243MSLCHelper::updateBlockerLength(const MSVehicle& veh, MSVehicle* blocker, int lcaCounter, double leftSpace, bool reliefConnection, double& leadingBlockerLength) {
244#ifdef DEBUG_SAVE_BLOCKER_LENGTH
245 if (DEBUG_COND) {
246 std::cout << SIMTIME
247 << " veh=" << veh.getID()
248 << " saveBlockerLength blocker=" << Named::getIDSecure(blocker)
249 << " bState=" << (blocker == 0 ? "None" : toString((LaneChangeAction)blocker->getLaneChangeModel().getOwnState()))
250 << "\n";
251 }
252#endif
253 if (blocker != nullptr && (blocker->getLaneChangeModel().getOwnState() & lcaCounter) != 0) {
254 // is there enough space in front of us for the blocker?
255 const double required = blocker->getVehicleType().getLengthWithGap() + veh.getVehicleType().getMinGap();
256 const double potential = leftSpace - veh.getCarFollowModel().brakeGap(
257 veh.getSpeed(), veh.getCarFollowModel().getMaxDecel(), 0);
258 if (required <= potential) {
259 // save at least his length in myLeadingBlockerLength
260 leadingBlockerLength = MAX2(required, leadingBlockerLength);
261#ifdef DEBUG_SAVE_BLOCKER_LENGTH
262 if (DEBUG_COND) {
263 std::cout << SIMTIME
264 << " veh=" << veh.getID()
265 << " required=" << required
266 << " potential=" << potential
267 << " blocker=" << Named::getIDSecure(blocker)
268 << " saving myLeadingBlockerLength=" << leadingBlockerLength
269 << "\n";
270 }
271#endif
272 } else {
273 // we cannot save enough space for the blocker. It needs to save
274 // space for ego instead
275 const double required2 = veh.getVehicleType().getLengthWithGap() + blocker->getVehicleType().getMinGap();
276 const double foeLeftSpace = leftSpace - veh.getPositionOnLane() + blocker->getPositionOnLane() - POSITION_EPS;
277 const bool canReserve = blocker->getLaneChangeModel().saveBlockerLength(required2, foeLeftSpace);
278 //reliefConnection ? std::numeric_limits<double>::max() : leftSpace);
279#ifdef DEBUG_SAVE_BLOCKER_LENGTH
280 if (DEBUG_COND) {
281 std::cout << SIMTIME
282 << " veh=" << veh.getID()
283 << " required=" << required
284 << " potential=" << potential
285 << " blocker=" << Named::getIDSecure(blocker)
286 << " required2=" << required2
287 << " foeCanReserve=" << canReserve
288 << " myReserved=" << leadingBlockerLength
289 << " reliefConnection=" << reliefConnection
290 << "\n";
291 }
292#endif
293 if (!canReserve && !reliefConnection) {
294 const int blockerState = blocker->getLaneChangeModel().getOwnState();
295 if ((blockerState & LCA_STRATEGIC) != 0
296 && (blockerState & LCA_URGENT) != 0) {
297 // reserve anyway and try to avoid deadlock with emergency deceleration
298 leadingBlockerLength = MAX2(required, leadingBlockerLength);
299#ifdef DEBUG_SAVE_BLOCKER_LENGTH
300 if (DEBUG_COND) {
301 std::cout << " reserving anyway to avoid deadlock (will cause emergency braking)\n";
302 }
303#endif
304 }
305 }
306 return canReserve;
307 }
308 }
309 return true;
310}
311
312
313bool
314MSLCHelper::canSaveBlockerLength(const MSVehicle& veh, double requested, double leftSpace) {
315 const double potential = leftSpace - veh.getCarFollowModel().brakeGap(veh.getSpeed(), veh.getCarFollowModel().getMaxDecel(), veh.getActionStepLengthSecs());
316#ifdef DEBUG_SAVE_BLOCKER_LENGTH
317 if (DEBUG_COND) {
318 std::cout << SIMTIME << " canSaveBlockerLength veh=" << veh.getID() << " requested=" << requested << " leftSpace=" << leftSpace << " potential=" << potential << "\n";
319 }
320#endif
321 return potential >= requested;
322}
323
324
325bool
327 // a sufficient, but not necessary condition for divergence
328 return (v1.getLane()->isInternal() && v2.getLane()->isInternal()
330 && &v1.getLane()->getEdge() != &v2.getLane()->getEdge());
331}
332
333
334double
335MSLCHelper::getSpeedPreservingSecureGap(const MSVehicle& leader, const MSVehicle& follower, double currentGap, double leaderPlannedSpeed) {
336 // whatever speed the follower choses in the next step, it will change both
337 // the secureGap and the required followSpeed.
338 // Let's assume the leader maintains speed
339 const double nextGap = currentGap + SPEED2DIST(leaderPlannedSpeed - follower.getSpeed());
340 double sGap = follower.getCarFollowModel().getSecureGap(&follower, &leader, follower.getSpeed(), leaderPlannedSpeed, leader.getCarFollowModel().getMaxDecel());
341 if (nextGap >= sGap) {
342 // follower may still accelerate
343 const double nextGapMin = currentGap + SPEED2DIST(leaderPlannedSpeed - follower.getCarFollowModel().maxNextSpeed(follower.getSpeed(), &follower));
344 const double vSafe = follower.getCarFollowModel().followSpeed(
345 &follower, follower.getSpeed(), nextGapMin, leaderPlannedSpeed, leader.getCarFollowModel().getMaxDecel());
346 return MAX2(vSafe, follower.getSpeed());
347 } else {
348 // follower must brake. The following brakes conservatively since the actual gap will be lower due to braking.
349 const double vSafe = follower.getCarFollowModel().followSpeed(
350 &follower, follower.getSpeed(), nextGap, leaderPlannedSpeed, leader.getCarFollowModel().getMaxDecel());
351 // avoid emergency deceleration
352 return MAX2(vSafe, follower.getCarFollowModel().minNextSpeed(follower.getSpeed(), &follower));
353 }
354}
355
356
357bool
358MSLCHelper::isBidiLeader(const MSVehicle* leader, const std::vector<MSLane*>& cont) {
359 if (leader == nullptr) {
360 return false;
361 }
362 const MSLane* lane1 = leader->getLane()->getNormalSuccessorLane()->getBidiLane();
363 const MSLane* lane2 = leader->getLane()->getNormalPredecessorLane()->getBidiLane();
364 if (lane1 == nullptr && lane2 == nullptr) {
365 return false;
366 }
367 bool result = std::find(cont.begin(), cont.end(), lane1) != cont.end();
368 if (!result && lane1 != lane2 && lane2 != nullptr) {
369 result = std::find(cont.begin(), cont.end(), lane2) != cont.end();
370 }
371 return result;
372}
373
374
375bool
376MSLCHelper::isBidiFollower(const MSVehicle* ego, const MSVehicle* follower) {
377 if (follower == nullptr) {
378 return false;
379 }
380 bool result = false;
381 const MSLane* lane1 = follower->getLane()->getNormalSuccessorLane()->getBidiLane();
382 const MSLane* lane2 = follower->getLane()->getNormalPredecessorLane()->getBidiLane();
383 const ConstMSEdgeVector& route = ego->getRoute().getEdges();
384 if (lane1 != nullptr) {
385 result = std::find(route.begin(), route.end(), &lane1->getEdge()) != route.end();
386 }
387 if (!result && lane1 != lane2 && lane2 != nullptr) {
388 result = std::find(route.begin(), route.end(), &lane2->getEdge()) != route.end();
389 }
390 return result;
391}
392
393
394bool
395MSLCHelper::unwillingToHelp(const MSVehicle& ego, double plannedSpeed, const MSVehicle& nv) {
397 // ego vehicle has not been waiting long enough to be eligible for unconditional help
399 // neighhbor not willing to help because ego is much slower
400#ifdef DEBUG_UNWILLING_TO_HELP
401 if (DEBUG_COND) {
402 std::cout << "\n nv=" << nv.getID() << " not willing to help because ego is much slower\n";
403 }
404#endif
405 return true;
406 }
407 const double nvLaneMax = nv.getLane()->getVehicleMaxSpeed(&nv);
408 if (nv.getSpeed() / nvLaneMax < nv.getLaneChangeModel().getCooperativeMinSpeed()) {
409 // neighbor not willing to help because it is already to slow and does not want to disturb the flow
410#ifdef DEBUG_UNWILLING_TO_HELP
411 if (DEBUG_COND) {
412 std::cout << "\n nv=" << nv.getID() << " not willing to help because it is already too slow\n";
413 }
414#endif
415 return true;
416 }
417 }
418 return false;
419}
420/****************************************************************************/
std::vector< const MSEdge * > ConstMSEdgeVector
Definition MSEdge.h:74
#define SPEED2DIST(x)
Definition SUMOTime.h:48
#define ACCEL2SPEED(x)
Definition SUMOTime.h:54
#define SIMTIME
Definition SUMOTime.h:65
LaneChangeAction
The state of a vehicle's lane-change behavior.
@ LCA_URGENT
The action is urgent (to be defined by lc-model)
@ LCA_STRATEGIC
The action is needed to follow the route (navigational lc)
T MAX2(T a, T b)
Definition StdDefs.h:86
std::string toString(const T &t, std::streamsize accuracy=gPrecision)
Definition ToString.h:49
virtual double getExtraReservation(int bestLaneOffset, double neighExtraDist=0) const
virtual bool saveBlockerLength(double, double)
reserve space at the end of the lane to avoid dead locks
virtual bool debugVehicle() const
whether the current vehicles shall be debugged
const MSRoute & getRoute() const
Returns the current route.
const MSVehicleType & getVehicleType() const
Returns the vehicle's type definition.
virtual double maxNextSpeed(double speed, const MSVehicle *const veh) const
Returns the maximum speed given the current speed.
virtual double minNextSpeed(double speed, const MSVehicle *const veh=0) const
Returns the minimum speed given the current speed (depends on the numerical update scheme and its ste...
virtual double getSecureGap(const MSVehicle *const veh, const MSVehicle *const, const double speed, const double leaderSpeed, const double leaderMaxDecel) const
Returns the minimum gap to reserve if the leader is braking at maximum (>=0)
double getMaxAccel() const
Get the vehicle type's maximum acceleration [m/s^2].
Definition MSCFModel.h:277
double brakeGap(const double speed) const
Returns the distance the vehicle needs to halt including driver's reaction time tau (i....
Definition MSCFModel.h:424
double getMaxDecel() const
Get the vehicle type's maximal comfortable deceleration [m/s^2].
Definition MSCFModel.h:285
virtual double followSpeed(const MSVehicle *const veh, double speed, double gap2pred, double predSpeed, double predMaxDecel, const MSVehicle *const pred=0, const CalcReason usage=CalcReason::CURRENT) const =0
Computes the vehicle's follow speed (no dawdling)
const MSJunction * getToJunction() const
Definition MSEdge.h:427
const MSJunction * getFromJunction() const
Definition MSEdge.h:423
bool isRoundabout() const
Definition MSEdge.h:742
The base class for an intersection.
Definition MSJunction.h:58
const ConstMSEdgeVector & getOutgoing() const
Definition MSJunction.h:114
const ConstMSEdgeVector & getIncoming() const
Definition MSJunction.h:108
static bool isBidiFollower(const MSVehicle *ego, const MSVehicle *follower)
static bool canSaveBlockerLength(const MSVehicle &veh, double requested, double leftSpace)
static double getSpeedPreservingSecureGap(const MSVehicle &leader, const MSVehicle &follower, double currentGap, double leaderPlannedSpeed)
static double getRoundaboutDistBonus(const MSVehicle &veh, double bonusParam, const MSVehicle::LaneQ &curr, const MSVehicle::LaneQ &neigh, const MSVehicle::LaneQ &best)
static bool isBidiLeader(const MSVehicle *leader, const std::vector< MSLane * > &cont)
static bool updateBlockerLength(const MSVehicle &veh, MSVehicle *blocker, int lcaCounter, double leftSpace, bool reliefConnection, double &leadingBlockerLength)
static bool unwillingToHelp(const MSVehicle &ego, double plannedSpeed, const MSVehicle &nv)
whether the neighboring vehicle nv is unwilling to yield to help ego merge
static bool divergentRoute(const MSVehicle &v1, const MSVehicle &v2)
return whether the vehicles are on the same junction but on divergent paths
Representation of a lane in the micro simulation.
Definition MSLane.h:84
const MSLane * getNormalSuccessorLane() const
get normal lane following this internal lane, for normal lanes, the lane itself is returned
Definition MSLane.cpp:3296
double getBruttoVehLenSum() const
Returns the sum of lengths of vehicles, including their minGaps, which were on the lane during the la...
Definition MSLane.h:1190
double getLength() const
Returns the lane's length.
Definition MSLane.h:632
double getVehicleMaxSpeed(const SUMOTrafficObject *const veh) const
Returns the lane's maximum speed, given a vehicle's speed limit adaptation.
Definition MSLane.h:575
int getIndex() const
Returns the lane's index.
Definition MSLane.h:668
bool isInternal() const
Definition MSLane.cpp:2659
MSLane * getBidiLane() const
retrieve bidirectional lane or nullptr
Definition MSLane.cpp:4750
MSEdge & getEdge() const
Returns the lane's edge.
Definition MSLane.h:790
const MSLane * getNormalPredecessorLane() const
get normal lane leading to this internal lane, for normal lanes, the lane itself is returned
Definition MSLane.cpp:3286
const std::vector< MSLink * > & getLinkCont() const
returns the container with all links !!!
Definition MSLane.h:750
const ConstMSEdgeVector & getEdges() const
Definition MSRoute.h:128
Representation of a vehicle in the micro simulation.
Definition MSVehicle.h:77
SUMOTime getWaitingTime(const bool accumulated=false) const
Returns the SUMOTime waited (speed was lesser than 0.1m/s)
Definition MSVehicle.h:670
MSAbstractLaneChangeModel & getLaneChangeModel()
double getActionStepLengthSecs() const
Returns the vehicle's action step length in secs, i.e. the interval between two action points.
Definition MSVehicle.h:533
const MSLane * getLane() const
Returns the lane the vehicle is on.
Definition MSVehicle.h:581
double getSpeed() const
Returns the vehicle's current speed.
Definition MSVehicle.h:490
const MSCFModel & getCarFollowModel() const
Returns the vehicle's car following model definition.
Definition MSVehicle.h:973
double getPositionOnLane() const
Get the vehicle's position along the lane.
Definition MSVehicle.h:374
double getLengthWithGap() const
Get vehicle's length including the minimum gap [m].
double getMinGap() const
Get the free space in front of vehicles of this class.
static std::string getIDSecure(const T *obj, const std::string &fallBack="NULL")
get an identifier for Named-like object which may be Null
Definition Named.h:66
const std::string & getID() const
Returns the id.
Definition Named.h:73
#define DEBUG_COND
A structure representing the best lanes for continuing the current route starting at 'lane'.
Definition MSVehicle.h:861
std::vector< MSLane * > bestContinuations
Definition MSVehicle.h:881
MSLane * lane
The described lane.
Definition MSVehicle.h:863
int bestLaneOffset
The (signed) number of lanes to be crossed to get to the lane which allows to continue the drive.
Definition MSVehicle.h:873