Eclipse SUMO - Simulation of Urban MObility
Loading...
Searching...
No Matches
MSLCM_SL2015.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-2024 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// A lane change model for heterogeneous traffic (based on sub-lanes)
19/****************************************************************************/
20#include <config.h>
21
22#include <iostream>
25#include <microsim/MSEdge.h>
26#include <microsim/MSLane.h>
27#include <microsim/MSLink.h>
28#include <microsim/MSNet.h>
30#include <microsim/MSGlobals.h>
31#include <microsim/MSStop.h>
34#include "MSLCHelper.h"
35#include "MSLCM_SL2015.h"
36
37// ===========================================================================
38// variable definitions
39// ===========================================================================
40#define MAGIC_OFFSET 1.
41#define LOOK_FORWARD 10.
42
43#define JAM_FACTOR 1.
44
45#define LCA_RIGHT_IMPATIENCE -1.
46#define CUT_IN_LEFT_SPEED_THRESHOLD 27.
47#define MAX_ONRAMP_LENGTH 200.
48
49#define LOOK_AHEAD_MIN_SPEED 0.0
50#define LOOK_AHEAD_SPEED_MEMORY 0.9
51
52#define HELP_DECEL_FACTOR 1.0
53
54#define HELP_OVERTAKE (10.0 / 3.6)
55#define MIN_FALLBEHIND (7.0 / 3.6)
56
57#define URGENCY 2.0
58
59#define KEEP_RIGHT_TIME 5.0 // the number of seconds after which a vehicle should move to the right lane
60
61#define RELGAIN_NORMALIZATION_MIN_SPEED 10.0
62
63#define TURN_LANE_DIST 200.0 // the distance at which a lane leading elsewhere is considered to be a turn-lane that must be avoided
64#define GAIN_PERCEPTION_THRESHOLD 0.05 // the minimum relative speed gain which affects the behavior
65
66#define SPEED_GAIN_MIN_SECONDS 20.0
67
68#define ARRIVALPOS_LAT_THRESHOLD 100.0
69
70// the speed at which the desired lateral gap grows now further
71#define LATGAP_SPEED_THRESHOLD (50 / 3.6)
72// the speed at which the desired lateral gap shrinks now further.
73// @note: when setting LATGAP_SPEED_THRESHOLD = LATGAP_SPEED_THRESHOLD2, no speed-specif reduction of minGapLat is done
74#define LATGAP_SPEED_THRESHOLD2 (50 / 3.6)
75
76// intention to change decays over time
77#define SPEEDGAIN_DECAY_FACTOR 0.5
78// exponential averaging factor for expected sublane speeds
79#define SPEEDGAIN_MEMORY_FACTOR 0.5
80
81#define REACT_TO_STOPPED_DISTANCE 100
82
83
84// ===========================================================================
85// Debug flags
86// ===========================================================================
87//#define DEBUG_MANEUVER
88//#define DEBUG_WANTSCHANGE
89//#define DEBUG_STRATEGIC_CHANGE
90//#define DEBUG_KEEP_LATGAP
91//#define DEBUG_STATE
92//#define DEBUG_ACTIONSTEPS
93//#define DEBUG_COMMITTED_SPEED
94//#define DEBUG_PATCHSPEED
95//#define DEBUG_INFORM
96//#define DEBUG_ROUNDABOUTS
97//#define DEBUG_COOPERATE
98//#define DEBUG_SLOWDOWN
99//#define DEBUG_SAVE_BLOCKER_LENGTH
100//#define DEBUG_BLOCKING
101//#define DEBUG_TRACI
102//#define DEBUG_EXPECTED_SLSPEED
103//#define DEBUG_SLIDING
104//#define DEBUG_COND (myVehicle.getID() == "moped.18" || myVehicle.getID() == "moped.16")
105//#define DEBUG_COND (myVehicle.getID() == "Togliatti_71_0")
106#define DEBUG_COND (myVehicle.isSelected())
107//#define DEBUG_COND (myVehicle.getID() == "pkw150478" || myVehicle.getID() == "pkw150494" || myVehicle.getID() == "pkw150289")
108//#define DEBUG_COND (myVehicle.getID() == "A" || myVehicle.getID() == "B") // fail change to left
109//#define DEBUG_COND (myVehicle.getID() == "disabled") // test stops_overtaking
110//#define DEBUG_COND true
111
112
113// ===========================================================================
114// member method definitions
115// ===========================================================================
118 mySpeedGainProbabilityRight(0),
119 mySpeedGainProbabilityLeft(0),
120 myKeepRightProbability(0),
121 myLeadingBlockerLength(0),
122 myLeftSpace(0),
123 myLookAheadSpeed(LOOK_AHEAD_MIN_SPEED),
124 myLastEdge(nullptr),
125 myCanChangeFully(true),
126 mySafeLatDistRight(0),
127 mySafeLatDistLeft(0),
128 myStrategicParam(v.getVehicleType().getParameter().getLCParam(SUMO_ATTR_LCA_STRATEGIC_PARAM, 1)),
129 myCooperativeParam(v.getVehicleType().getParameter().getLCParam(SUMO_ATTR_LCA_COOPERATIVE_PARAM, 1)),
130 mySpeedGainParam(v.getVehicleType().getParameter().getLCParam(SUMO_ATTR_LCA_SPEEDGAIN_PARAM, 1)),
131 myKeepRightParam(v.getVehicleType().getParameter().getLCParam(SUMO_ATTR_LCA_KEEPRIGHT_PARAM, 1)),
132 myOppositeParam(v.getVehicleType().getParameter().getLCParam(SUMO_ATTR_LCA_OPPOSITE_PARAM, 1)),
133 mySublaneParam(v.getVehicleType().getParameter().getLCParam(SUMO_ATTR_LCA_SUBLANE_PARAM, 1)),
134 // by default use SUMO_ATTR_LCA_PUSHY. If that is not set, try SUMO_ATTR_LCA_PUSHYGAP
135 myMinGapLat(v.getVehicleType().getMinGapLat()),
136 myPushy(v.getVehicleType().getParameter().getLCParam(SUMO_ATTR_LCA_PUSHY,
137 1 - (v.getVehicleType().getParameter().getLCParam(SUMO_ATTR_LCA_PUSHYGAP,
138 MAX2(NUMERICAL_EPS, myMinGapLat)) /
139 MAX2(NUMERICAL_EPS, myMinGapLat)))),
140 myAssertive(v.getVehicleType().getParameter().getLCParam(SUMO_ATTR_LCA_ASSERTIVE, 1)),
141 myImpatience(v.getVehicleType().getParameter().getLCParam(SUMO_ATTR_LCA_IMPATIENCE, 0)),
142 myMinImpatience(myImpatience),
143 myTimeToImpatience(v.getVehicleType().getParameter().getLCParam(SUMO_ATTR_LCA_TIME_TO_IMPATIENCE, std::numeric_limits<double>::max())),
144 myAccelLat(v.getVehicleType().getParameter().getLCParam(SUMO_ATTR_LCA_ACCEL_LAT, 1.0)),
145 myTurnAlignmentDist(v.getVehicleType().getParameter().getLCParam(SUMO_ATTR_LCA_TURN_ALIGNMENT_DISTANCE, 0.0)),
146 myLookaheadLeft(v.getVehicleType().getParameter().getLCParam(SUMO_ATTR_LCA_LOOKAHEADLEFT, 2.0)),
147 mySpeedGainRight(v.getVehicleType().getParameter().getLCParam(SUMO_ATTR_LCA_SPEEDGAINRIGHT, 0.1)),
148 myLaneDiscipline(v.getVehicleType().getParameter().getLCParam(SUMO_ATTR_LCA_LANE_DISCIPLINE, 0.0)),
149 mySpeedGainLookahead(v.getVehicleType().getParameter().getLCParam(SUMO_ATTR_LCA_SPEEDGAIN_LOOKAHEAD, 5)),
150 myRoundaboutBonus(v.getVehicleType().getParameter().getLCParam(SUMO_ATTR_LCA_COOPERATIVE_ROUNDABOUT, myCooperativeParam)),
151 myCooperativeSpeed(v.getVehicleType().getParameter().getLCParam(SUMO_ATTR_LCA_COOPERATIVE_SPEED, myCooperativeParam)),
152 myKeepRightAcceptanceTime(v.getVehicleType().getParameter().getLCParam(SUMO_ATTR_LCA_KEEPRIGHT_ACCEPTANCE_TIME, -1)),
153 myOvertakeDeltaSpeedFactor(v.getVehicleType().getParameter().getLCParam(SUMO_ATTR_LCA_OVERTAKE_DELTASPEED_FACTOR, 0)),
154 mySigmaState(0) {
156}
157
161
162
163void
165 if (mySpeedGainParam <= 0) {
166 myChangeProbThresholdRight = std::numeric_limits<double>::max();
167 myChangeProbThresholdLeft = std::numeric_limits<double>::max();
168 } else {
171 }
173}
174
175
176bool
178 return DEBUG_COND;
179}
180
181
182int
184 int laneOffset,
185 LaneChangeAction alternatives,
186 const MSLeaderDistanceInfo& leaders,
187 const MSLeaderDistanceInfo& followers,
188 const MSLeaderDistanceInfo& blockers,
189 const MSLeaderDistanceInfo& neighLeaders,
190 const MSLeaderDistanceInfo& neighFollowers,
191 const MSLeaderDistanceInfo& neighBlockers,
192 const MSLane& neighLane,
193 const std::vector<MSVehicle::LaneQ>& preb,
194 MSVehicle** lastBlocked,
195 MSVehicle** firstBlocked,
196 double& latDist, double& maneuverDist, int& blocked) {
197
199 const std::string changeType = laneOffset == -1 ? "right" : (laneOffset == 1 ? "left" : "current");
200
201#ifdef DEBUG_MANEUVER
202 if (gDebugFlag2) {
203 std::cout << "\n" << SIMTIME
204 << std::setprecision(gPrecision)
205 << " veh=" << myVehicle.getID()
206 << " lane=" << myVehicle.getLane()->getID()
207 << " neigh=" << neighLane.getID()
208 << " pos=" << myVehicle.getPositionOnLane()
209 << " posLat=" << myVehicle.getLateralPositionOnLane()
210 << " posLatError=" << mySigmaState
211 << " speed=" << myVehicle.getSpeed()
212 << " considerChangeTo=" << changeType
213 << "\n";
214 }
215#endif
216
217 int result = _wantsChangeSublane(laneOffset,
218 alternatives,
219 leaders, followers, blockers,
220 neighLeaders, neighFollowers, neighBlockers,
221 neighLane, preb,
222 lastBlocked, firstBlocked, latDist, maneuverDist, blocked);
223
224 result = keepLatGap(result, leaders, followers, blockers,
225 neighLeaders, neighFollowers, neighBlockers,
226 neighLane, laneOffset, latDist, maneuverDist, blocked);
227
228 result |= getLCA(result, latDist);
229 // take into account lateral acceleration
230#if defined(DEBUG_MANEUVER) || defined(DEBUG_STATE)
231 double latDistTmp = latDist;
232#endif
233 latDist = SPEED2DIST(computeSpeedLat(latDist, maneuverDist, (result & LCA_URGENT) != 0));
234#if defined(DEBUG_MANEUVER) || defined(DEBUG_STATE)
235 if (gDebugFlag2 && latDist != latDistTmp) {
236 std::cout << SIMTIME << " veh=" << myVehicle.getID() << " maneuverDist=" << maneuverDist << " latDist=" << latDistTmp << " mySpeedPrev=" << mySpeedLat << " speedLat=" << DIST2SPEED(latDist) << " latDist2=" << latDist << "\n";
237 }
238
239 if (gDebugFlag2) {
240 if (result & LCA_WANTS_LANECHANGE) {
241 std::cout << SIMTIME
242 << " veh=" << myVehicle.getID()
243 << " wantsChangeTo=" << changeType
244 << " latDist=" << latDist
245 << " maneuverDist=" << maneuverDist
246 << " state=" << toString((LaneChangeAction)result)
247 << ((blocked & LCA_BLOCKED) ? " (blocked)" : "")
248 << ((blocked & LCA_OVERLAPPING) ? " (overlap)" : "")
249 << "\n\n";
250 } else {
251 std::cout << SIMTIME
252 << " veh=" << myVehicle.getID()
253 << " wantsNoChangeTo=" << changeType
254 << " state=" << toString((LaneChangeAction)result)
255 << "\n\n";
256 }
257 }
258#endif
259 gDebugFlag2 = false;
260 return result;
261}
262
263void
266 if (myVehicle.isActive()) {
267 if ((state & (LCA_STRATEGIC | LCA_SPEEDGAIN)) != 0 && (state & LCA_BLOCKED) != 0) {
269 } else {
270 // impatience decays only to the driver-specific level
272 }
273#ifdef DEBUG_STATE
274 if (DEBUG_COND) {
275 std::cout << SIMTIME << " veh=" << myVehicle.getID()
276 << " setOwnState=" << toString((LaneChangeAction)state)
277 << " myMinImpatience=" << myMinImpatience
278 << " myImpatience=" << myImpatience
279 << "\n";
280 }
281#endif
282 if ((state & LCA_STAY) != 0) {
283 myCanChangeFully = true;
284// if (DEBUG_COND) {
285// std::cout << " myCanChangeFully=true\n";
286// }
287 }
288 }
289}
290
291
292void
293MSLCM_SL2015::updateSafeLatDist(const double travelledLatDist) {
294 mySafeLatDistLeft -= travelledLatDist;
295 mySafeLatDistRight += travelledLatDist;
296
297 if (fabs(mySafeLatDistLeft) < NUMERICAL_EPS) {
299 }
300 if (fabs(mySafeLatDistRight) < NUMERICAL_EPS) {
302 }
303}
304
305
306double
307MSLCM_SL2015::patchSpeed(const double min, const double wanted, const double max, const MSCFModel& cfModel) {
309 // negative min speed may be passed when using ballistic updated
310 const double newSpeed = _patchSpeed(MAX2(min, 0.0), wanted, max, cfModel);
311#ifdef DEBUG_PATCHSPEED
312 if (gDebugFlag2) {
313 const std::string patched = (wanted != newSpeed ? " patched=" + toString(newSpeed) : "");
314 std::cout << SIMTIME
315 << " veh=" << myVehicle.getID()
316 << " lane=" << myVehicle.getLane()->getID()
317 << " pos=" << myVehicle.getPositionOnLane()
318 << " v=" << myVehicle.getSpeed()
319 << " min=" << min
320 << " wanted=" << wanted
321 << " max=" << max
322 << patched
323 << "\n\n";
324 }
325#endif
326 gDebugFlag2 = false;
327 return newSpeed;
328}
329
330
331double
332MSLCM_SL2015::_patchSpeed(double min, const double wanted, double max, const MSCFModel& cfModel) {
333 if (wanted <= 0) {
334 return wanted;
335 }
336
337 int state = myOwnState;
338
339 double nVSafe = wanted;
340 bool gotOne = false;
341 // letting vehicles merge in at the end of the lane in case of counter-lane change, step#2
342 // if we want to change and have a blocking leader and there is enough room for him in front of us
343 if (myLeadingBlockerLength != 0) {
345#ifdef DEBUG_PATCHSPEED
346 if (gDebugFlag2) {
347 std::cout << SIMTIME << " veh=" << myVehicle.getID() << " myLeadingBlockerLength=" << myLeadingBlockerLength << " space=" << space << "\n";
348 }
349#endif
350 if (space >= 0) { // XXX space > -MAGIC_OFFSET
351 // compute speed for decelerating towards a place which allows the blocking leader to merge in in front
353 max = MIN2(max, safe);
354 // if we are approaching this place
355 if (safe < wanted) {
356 if (safe < min) {
358 if (safe >= vMinEmergency) {
359 // permit harder braking if needed and helpful
360 min = MAX2(vMinEmergency, safe);
361 }
362 }
363#ifdef DEBUG_PATCHSPEED
364 if (gDebugFlag2) {
365 std::cout << SIMTIME << " veh=" << myVehicle.getID() << " slowing down for leading blocker, safe=" << safe << (safe + NUMERICAL_EPS < min ? " (not enough)" : "") << "\n";
366 }
367#endif
368 nVSafe = MAX2(min, safe);
369 gotOne = true;
370 }
371 }
372 }
373 const double coopWeight = MAX2(0.0, MIN2(1.0, myCooperativeSpeed));
374 for (auto i : myLCAccelerationAdvices) {
375 double accel = i.first;
376 double v = myVehicle.getSpeed() + ACCEL2SPEED(accel);
377 if (v >= min && v <= max) {
378 if (i.second) {
379 // own advice, no scaling needed
380 nVSafe = MIN2(v, nVSafe);
381 } else {
382 nVSafe = MIN2(v * coopWeight + (1 - coopWeight) * wanted, nVSafe);
383 }
384 gotOne = true;
385#ifdef DEBUG_PATCHSPEED
386 if (gDebugFlag2) {
387 std::cout << SIMTIME << " veh=" << myVehicle.getID() << " got accel=" << accel << " nVSafe=" << nVSafe << "\n";
388 }
389#endif
390 } else {
391#ifdef DEBUG_PATCHSPEED
392 if (v < min) {
393 if (gDebugFlag2) {
394 std::cout << SIMTIME << " veh=" << myVehicle.getID() << " ignoring low nVSafe=" << v << " (accel=" << accel << ") min=" << min << "\n";
395 }
396 } else {
397 if (gDebugFlag2) {
398 std::cout << SIMTIME << " veh=" << myVehicle.getID() << " ignoring high nVSafe=" << v << " (accel=" << accel << ") max=" << max << "\n";
399 }
400 }
401#endif
402 }
403 }
404
405 if (gotOne && !myDontBrake) {
406#ifdef DEBUG_PATCHSPEED
407 if (gDebugFlag2) {
408 std::cout << SIMTIME << " veh=" << myVehicle.getID() << " got vSafe\n";
409 }
410#endif
411 return nVSafe;
412 }
413
414 // check whether the vehicle is blocked
415 if ((state & LCA_WANTS_LANECHANGE) != 0 && (state & LCA_BLOCKED) != 0) {
416 if ((state & LCA_STRATEGIC) != 0) {
417 // necessary decelerations are controlled via vSafe. If there are
418 // none it means we should speed up
419#if defined(DEBUG_PATCHSPEED) || defined(DEBUG_STATE)
420 if (gDebugFlag2) {
421 std::cout << SIMTIME << " veh=" << myVehicle.getID() << " LCA_WANTS_LANECHANGE (strat, no vSafe)\n";
422 }
423#endif
424 return (max + wanted) / 2.0;
425 } else if ((state & LCA_COOPERATIVE) != 0) {
426 // only minor adjustments in speed should be done
427 if ((state & LCA_BLOCKED_BY_LEADER) != 0) {
428#if defined(DEBUG_PATCHSPEED) || defined(DEBUG_STATE)
429 if (gDebugFlag2) {
430 std::cout << SIMTIME << " veh=" << myVehicle.getID() << " LCA_BLOCKED_BY_LEADER (coop)\n";
431 }
432#endif
433 return (min + wanted) / 2.0;
434 }
435 if ((state & LCA_BLOCKED_BY_FOLLOWER) != 0) {
436#if defined(DEBUG_PATCHSPEED) || defined(DEBUG_STATE)
437 if (gDebugFlag2) {
438 std::cout << SIMTIME << " veh=" << myVehicle.getID() << " LCA_BLOCKED_BY_FOLLOWER (coop)\n";
439 }
440#endif
441 return (max + wanted) / 2.0;
442 }
443 //} else { // VARIANT_16
444 // // only accelerations should be performed
445 // if ((state & LCA_BLOCKED_BY_FOLLOWER) != 0) {
446 // if (gDebugFlag2) std::cout << SIMTIME << " veh=" << myVehicle.getID() << " LCA_BLOCKED_BY_FOLLOWER\n";
447 // return (max + wanted) / 2.0;
448 // }
449 }
450 }
451
452 /*
453 // decelerate if being a blocking follower
454 // (and does not have to change lanes)
455 if ((state & LCA_AMBLOCKINGFOLLOWER) != 0) {
456 if (fabs(max - myVehicle.getCarFollowModel().maxNextSpeed(myVehicle.getSpeed(), &myVehicle)) < 0.001 && min == 0) { // !!! was standing
457 if (gDebugFlag2) std::cout << SIMTIME << " veh=" << myVehicle.getID() << " LCA_AMBLOCKINGFOLLOWER (standing)\n";
458 return 0;
459 }
460 if (gDebugFlag2) std::cout << SIMTIME << " veh=" << myVehicle.getID() << " LCA_AMBLOCKINGFOLLOWER\n";
461
462 //return min; // VARIANT_3 (brakeStrong)
463 return (min + wanted) / 2.0;
464 }
465 if ((state & LCA_AMBACKBLOCKER) != 0) {
466 if (max <= myVehicle.getCarFollowModel().maxNextSpeed(myVehicle.getSpeed(), &myVehicle) && min == 0) { // !!! was standing
467 if (gDebugFlag2) std::cout << SIMTIME << " veh=" << myVehicle.getID() << " LCA_AMBACKBLOCKER (standing)\n";
468 //return min; VARIANT_9 (backBlockVSafe)
469 return nVSafe;
470 }
471 }
472 if ((state & LCA_AMBACKBLOCKER_STANDING) != 0) {
473 if (gDebugFlag2) std::cout << SIMTIME << " veh=" << myVehicle.getID() << " LCA_AMBACKBLOCKER_STANDING\n";
474 //return min;
475 return nVSafe;
476 }
477 */
478
479 // accelerate if being a blocking leader or blocking follower not able to brake
480 // (and does not have to change lanes)
481 if ((state & LCA_AMBLOCKINGLEADER) != 0) {
482#if defined(DEBUG_PATCHSPEED) || defined(DEBUG_STATE)
483 if (gDebugFlag2) {
484 std::cout << SIMTIME << " veh=" << myVehicle.getID() << " LCA_AMBLOCKINGLEADER\n";
485 }
486#endif
487 return (max + wanted) / 2.0;
488 }
489
490 if ((state & LCA_AMBLOCKINGFOLLOWER_DONTBRAKE) != 0) {
491#if defined(DEBUG_PATCHSPEED) || defined(DEBUG_STATE)
492 if (gDebugFlag2) {
493 std::cout << SIMTIME << " veh=" << myVehicle.getID() << " LCA_AMBLOCKINGFOLLOWER_DONTBRAKE\n";
494 }
495#endif
496 /*
497 // VARIANT_4 (dontbrake)
498 if (max <= myVehicle.getCarFollowModel().maxNextSpeed(myVehicle.getSpeed(), &myVehicle) && min == 0) { // !!! was standing
499 return wanted;
500 }
501 return (min + wanted) / 2.0;
502 */
503 }
504 return wanted;
505}
506
507
508void*
509MSLCM_SL2015::inform(void* info, MSVehicle* sender) {
510 Info* pinfo = (Info*) info;
511 if (pinfo->first >= 0) {
512 addLCSpeedAdvice(pinfo->first, false);
513 }
514 //myOwnState &= 0xffffffff; // reset all bits of MyLCAEnum but only those
515 myOwnState |= pinfo->second;
516#ifdef DEBUG_INFORM
518 std::cout << SIMTIME
519 << " veh=" << myVehicle.getID()
520 << " informedBy=" << sender->getID()
521 << " info=" << pinfo->second
522 << " vSafe=" << pinfo->first
523 << "\n";
524 }
525#else
526 UNUSED_PARAMETER(sender);
527#endif
528 delete pinfo;
529 return (void*) true;
530}
531
532
533void
534MSLCM_SL2015::msg(const CLeaderDist& cld, double speed, int state) {
535 assert(cld.first != 0);
536 ((MSVehicle*)cld.first)->getLaneChangeModel().inform(new Info(speed, state), &myVehicle);
537}
538
539
540double
542 int dir,
543 const CLeaderDist& neighLead,
544 double remainingSeconds) {
545 double plannedSpeed = MIN2(myVehicle.getSpeed(),
547 for (auto i : myLCAccelerationAdvices) {
548 double v = myVehicle.getSpeed() + ACCEL2SPEED(i.first);
550 plannedSpeed = MIN2(plannedSpeed, v);
551 }
552 }
553#ifdef DEBUG_INFORM
554 if (gDebugFlag2) {
555 std::cout << " informLeader speed=" << myVehicle.getSpeed() << " planned=" << plannedSpeed << "\n";
556 }
557#endif
558
559 if ((blocked & LCA_BLOCKED_BY_LEADER) != 0 && neighLead.first != 0) {
560 const MSVehicle* nv = neighLead.first;
562 //std::cout << SIMTIME << " ego=" << myVehicle.getID() << " ignoresDivergentBlockingLeader=" << nv->getID() << "\n";
563 return plannedSpeed;
564 }
565#ifdef DEBUG_INFORM
566 if (gDebugFlag2) std::cout << " blocked by leader nv=" << nv->getID() << " nvSpeed=" << nv->getSpeed() << " needGap="
568#endif
569 // decide whether we want to overtake the leader or follow it
570 const double dv = plannedSpeed - nv->getSpeed();
571 const double overtakeDist = (neighLead.second // drive to back of follower
572 + nv->getVehicleType().getLengthWithGap() // drive to front of follower
573 + myVehicle.getVehicleType().getLength() // ego back reaches follower front
574 + nv->getCarFollowModel().getSecureGap( // save gap to follower
576
577 if ((dv < myOvertakeDeltaSpeedFactor * myVehicle.getLane()->getSpeedLimit() + NUMERICAL_EPS
578 // overtaking on the right on an uncongested highway is forbidden (noOvertakeLCLeft)
580 // not enough space to overtake? (we will start to brake when approaching a dead end)
582 // not enough time to overtake?
583 || dv * remainingSeconds < overtakeDist)
584 && (!neighLead.first->isStopped() || (isOpposite() && neighLead.second >= 0))) {
585 // cannot overtake
586 msg(neighLead, -1, dir | LCA_AMBLOCKINGLEADER);
587 // slow down smoothly to follow leader
588 const double targetSpeed = getCarFollowModel().followSpeed(
589 &myVehicle, myVehicle.getSpeed(), neighLead.second, nv->getSpeed(), nv->getCarFollowModel().getMaxDecel());
590 if (targetSpeed < myVehicle.getSpeed()) {
591 // slow down smoothly to follow leader
592 const double decel = ACCEL2SPEED(MIN2(myVehicle.getCarFollowModel().getMaxDecel(),
593 MAX2(MIN_FALLBEHIND, (myVehicle.getSpeed() - targetSpeed) / remainingSeconds)));
594 //const double nextSpeed = MAX2(0., MIN2(plannedSpeed, myVehicle.getSpeed() - decel));
595 const double nextSpeed = MIN2(plannedSpeed, MAX2(0.0, myVehicle.getSpeed() - decel));
596#ifdef DEBUG_INFORM
597 if (gDebugFlag2) {
598 std::cout << SIMTIME
599 << " cannot overtake leader nv=" << nv->getID()
600 << " dv=" << dv
601 << " remainingSeconds=" << remainingSeconds
602 << " targetSpeed=" << targetSpeed
603 << " nextSpeed=" << nextSpeed
604 << "\n";
605 }
606#endif
607 addLCSpeedAdvice(nextSpeed);
608 return nextSpeed;
609 } else {
610 // leader is fast enough anyway
611#ifdef DEBUG_INFORM
612 if (gDebugFlag2) {
613 std::cout << SIMTIME
614 << " cannot overtake fast leader nv=" << nv->getID()
615 << " dv=" << dv
616 << " remainingSeconds=" << remainingSeconds
617 << " targetSpeed=" << targetSpeed
618 << "\n";
619 }
620#endif
621 addLCSpeedAdvice(targetSpeed);
622 return plannedSpeed;
623 }
624 } else {
625#ifdef DEBUG_INFORM
626 if (gDebugFlag2) {
627 std::cout << SIMTIME
628 << " wants to overtake leader nv=" << nv->getID()
629 << " dv=" << dv
630 << " remainingSeconds=" << remainingSeconds
631 << " currentGap=" << neighLead.second
633 << " overtakeDist=" << overtakeDist
634 << " leftSpace=" << myLeftSpace
635 << " blockerLength=" << myLeadingBlockerLength
636 << "\n";
637 }
638#endif
639 // overtaking, leader should not accelerate
640 msg(neighLead, nv->getSpeed(), dir | LCA_AMBLOCKINGLEADER);
641 return -1;
642 }
643 } else if (neighLead.first != 0) { // (remainUnblocked)
644 // we are not blocked now. make sure we stay far enough from the leader
645 const MSVehicle* nv = neighLead.first;
646 double dv, nextNVSpeed;
648 // XXX: the decrement (HELP_OVERTAKE) should be scaled with timestep length, I think.
649 // It seems to function as an estimate nv's speed in the next simstep!? (so HELP_OVERTAKE should be an acceleration value.)
650 nextNVSpeed = nv->getSpeed() - HELP_OVERTAKE; // conservative
651 dv = SPEED2DIST(myVehicle.getSpeed() - nextNVSpeed);
652 } else {
653 // Estimate neigh's speed after actionstep length
654 // @note The possible breaking can be underestimated by the formula, so this is a potential
655 // source of collisions if actionsteplength>simsteplength.
656 const double nvMaxDecel = HELP_OVERTAKE;
657 nextNVSpeed = nv->getSpeed() - nvMaxDecel * myVehicle.getActionStepLengthSecs(); // conservative
658 // Estimated gap reduction until next action step if own speed stays constant
659 dv = SPEED2DIST(myVehicle.getSpeed() - nextNVSpeed);
660 }
661 const double targetSpeed = getCarFollowModel().followSpeed(
662 &myVehicle, myVehicle.getSpeed(), neighLead.second - dv, nextNVSpeed, nv->getCarFollowModel().getMaxDecel());
663 addLCSpeedAdvice(targetSpeed);
664#ifdef DEBUG_INFORM
665 if (gDebugFlag2) {
666 std::cout << " not blocked by leader nv=" << nv->getID()
667 << " nvSpeed=" << nv->getSpeed()
668 << " gap=" << neighLead.second
669 << " nextGap=" << neighLead.second - dv
671 << " targetSpeed=" << targetSpeed
672 << "\n";
673 }
674#endif
675 return MIN2(targetSpeed, plannedSpeed);
676 } else {
677 // not overtaking
678 return plannedSpeed;
679 }
680}
681
682
683void
685 int dir,
686 const CLeaderDist& neighFollow,
687 double remainingSeconds,
688 double plannedSpeed) {
689 if ((blocked & LCA_BLOCKED_BY_FOLLOWER) != 0 && neighFollow.first != 0) {
690 const MSVehicle* nv = neighFollow.first;
692 //std::cout << SIMTIME << " ego=" << myVehicle.getID() << " ignoresDivergentBlockingFollower=" << nv->getID() << "\n";
693 return;
694 }
695#ifdef DEBUG_INFORM
696 if (gDebugFlag2) std::cout << " blocked by follower nv=" << nv->getID() << " nvSpeed=" << nv->getSpeed() << " needGap="
698#endif
699
700 // are we fast enough to cut in without any help?
701 if (plannedSpeed - nv->getSpeed() >= HELP_OVERTAKE) {
702 const double neededGap = nv->getCarFollowModel().getSecureGap(nv, &myVehicle, nv->getSpeed(), plannedSpeed, myVehicle.getCarFollowModel().getMaxDecel());
703 if ((neededGap - neighFollow.second) / remainingSeconds < (plannedSpeed - nv->getSpeed())) {
704#ifdef DEBUG_INFORM
705 if (gDebugFlag2) {
706 std::cout << " wants to cut in before nv=" << nv->getID() << " without any help neededGap=" << neededGap << "\n";
707 }
708#endif
709 // follower might even accelerate but not to much
710 msg(neighFollow, plannedSpeed - HELP_OVERTAKE, dir | LCA_AMBLOCKINGFOLLOWER);
711 return;
712 }
713 }
714 // decide whether we will request help to cut in before the follower or allow to be overtaken
715
716 // PARAMETERS
717 // assume other vehicle will assume the equivalent of 1 second of
718 // maximum deceleration to help us (will probably be spread over
719 // multiple seconds)
720 // -----------
721 const double helpDecel = nv->getCarFollowModel().getMaxDecel() * HELP_DECEL_FACTOR ;
722
723 // change in the gap between ego and blocker over 1 second (not STEP!)
724 const double neighNewSpeed = MAX2(0., nv->getSpeed() - ACCEL2SPEED(helpDecel));
725 const double neighNewSpeed1s = MAX2(0., nv->getSpeed() - helpDecel);
726 const double dv = plannedSpeed - neighNewSpeed1s;
727 // new gap between follower and self in case the follower does brake for 1s
728 const double decelGap = neighFollow.second + dv;
729 const double secureGap = nv->getCarFollowModel().getSecureGap(nv, &myVehicle, neighNewSpeed1s, plannedSpeed, myVehicle.getCarFollowModel().getMaxDecel());
730#ifdef DEBUG_INFORM
731 if (gDebugFlag2) {
732 std::cout << SIMTIME
733 << " egoV=" << myVehicle.getSpeed()
734 << " egoNV=" << plannedSpeed
735 << " nvNewSpeed=" << neighNewSpeed
736 << " nvNewSpeed1s=" << neighNewSpeed1s
737 << " deltaGap=" << dv
738 << " decelGap=" << decelGap
739 << " secGap=" << secureGap
740 << "\n";
741 }
742#endif
743 if (decelGap > 0 && decelGap >= secureGap) {
744 // if the blocking neighbor brakes it could actually help
745 // how hard does it actually need to be?
746 // to be safe in the next step the following equation has to hold:
747 // vsafe <= followSpeed(gap=currentGap - SPEED2DIST(vsafe), ...)
748 // we compute an upper bound on vsafe by doing the computation twice
749 const double vsafe1 = MAX2(neighNewSpeed, nv->getCarFollowModel().followSpeed(
750 nv, nv->getSpeed(), neighFollow.second + SPEED2DIST(plannedSpeed), plannedSpeed, myVehicle.getCarFollowModel().getMaxDecel()));
751 const double vsafe = MAX2(neighNewSpeed, nv->getCarFollowModel().followSpeed(
752 nv, nv->getSpeed(), neighFollow.second + SPEED2DIST(plannedSpeed - vsafe1), plannedSpeed, myVehicle.getCarFollowModel().getMaxDecel()));
753 // the following assertion cannot be guaranteed because the CFModel handles small gaps differently, see MSCFModel::maximumSafeStopSpeed
754 // assert(vsafe <= vsafe1);
755 msg(neighFollow, vsafe, dir | LCA_AMBLOCKINGFOLLOWER);
756#ifdef DEBUG_INFORM
757 if (gDebugFlag2) {
758 std::cout << " wants to cut in before nv=" << nv->getID()
759 << " vsafe1=" << vsafe1
760 << " vsafe=" << vsafe
761 << " newSecGap=" << nv->getCarFollowModel().getSecureGap(nv, &myVehicle, vsafe, plannedSpeed, myVehicle.getCarFollowModel().getMaxDecel())
762 << "\n";
763 }
764#endif
765 } else if (dv > 0 && dv * remainingSeconds > (secureGap - decelGap + POSITION_EPS)) {
766 // decelerating once is sufficient to open up a large enough gap in time
767 msg(neighFollow, neighNewSpeed, dir | LCA_AMBLOCKINGFOLLOWER);
768#ifdef DEBUG_INFORM
769 if (gDebugFlag2) {
770 std::cout << " wants to cut in before nv=" << nv->getID() << " (eventually)\n";
771 }
772#endif
773 } else if (dir == LCA_MRIGHT && !myAllowOvertakingRight && !nv->congested()) {
774 const double vhelp = MAX2(neighNewSpeed, HELP_OVERTAKE);
775 msg(neighFollow, vhelp, dir | LCA_AMBLOCKINGFOLLOWER);
776#ifdef DEBUG_INFORM
777 if (gDebugFlag2) {
778 std::cout << " wants to cut in before nv=" << nv->getID() << " (nv cannot overtake right)\n";
779 }
780#endif
781 } else {
782 double vhelp = MAX2(nv->getSpeed(), myVehicle.getSpeed() + HELP_OVERTAKE);
783 if (nv->getSpeed() > myVehicle.getSpeed() &&
785 || (dir == LCA_MLEFT && plannedSpeed > CUT_IN_LEFT_SPEED_THRESHOLD) // VARIANT_22 (slowDownLeft)
786 // XXX this is a hack to determine whether the vehicles is on an on-ramp. This information should be retrieved from the network itself
788 )) {
789 // let the follower slow down to increase the likelyhood that later vehicles will be slow enough to help
790 // follower should still be fast enough to open a gap
791 vhelp = MAX2(neighNewSpeed, myVehicle.getSpeed() + HELP_OVERTAKE);
792#ifdef DEBUG_INFORM
793 if (gDebugFlag2) {
794 std::cout << " wants right follower to slow down a bit\n";
795 }
796#endif
797 if ((nv->getSpeed() - myVehicle.getSpeed()) / helpDecel < remainingSeconds) {
798#ifdef DEBUG_INFORM
799 if (gDebugFlag2) {
800 std::cout << " wants to cut in before right follower nv=" << nv->getID() << " (eventually)\n";
801 }
802#endif
803 msg(neighFollow, vhelp, dir | LCA_AMBLOCKINGFOLLOWER);
804 return;
805 }
806 }
807 msg(neighFollow, vhelp, dir | LCA_AMBLOCKINGFOLLOWER);
808 // this follower is supposed to overtake us. slow down smoothly to allow this
809 const double overtakeDist = (neighFollow.second // follower reaches ego back
810 + myVehicle.getVehicleType().getLengthWithGap() // follower reaches ego front
811 + nv->getVehicleType().getLength() // follower back at ego front
812 + myVehicle.getCarFollowModel().getSecureGap( // follower has safe dist to ego
813 &myVehicle, nv, plannedSpeed, vhelp, nv->getCarFollowModel().getMaxDecel()));
814 // speed difference to create a sufficiently large gap
815 const double needDV = overtakeDist / remainingSeconds;
816 // make sure the deceleration is not to strong
818
819#ifdef DEBUG_INFORM
820 if (gDebugFlag2) {
821 std::cout << SIMTIME
822 << " veh=" << myVehicle.getID()
823 << " wants to be overtaken by=" << nv->getID()
824 << " overtakeDist=" << overtakeDist
825 << " vneigh=" << nv->getSpeed()
826 << " vhelp=" << vhelp
827 << " needDV=" << needDV
828 << " vsafe=" << myVehicle.getSpeed() + ACCEL2SPEED(myLCAccelerationAdvices.back().first)
829 << "\n";
830 }
831#endif
832 }
833 } else if (neighFollow.first != 0) {
834 const double vsafe = MSLCHelper::getSpeedPreservingSecureGap(myVehicle, *neighFollow.first, neighFollow.second, plannedSpeed);
835 msg(neighFollow, vsafe, dir | LCA_AMBLOCKINGFOLLOWER);
836#ifdef DEBUG_INFORM
837 if (gDebugFlag2) {
838 std::cout << " wants to cut in before non-blocking follower nv=" << neighFollow.first->getID() << "\n";
839 }
840#endif
841 }
842}
843
844double
845MSLCM_SL2015::informLeaders(int blocked, int dir,
846 const std::vector<CLeaderDist>& blockers,
847 double remainingSeconds) {
848 double plannedSpeed = myVehicle.getSpeed();
849 double space = myLeftSpace;
850 if (myLeadingBlockerLength != 0) {
851 // see patchSpeed @todo: refactor
853 if (space <= 0) {
854 // ignore leading blocker
855 space = myLeftSpace;
856 }
857 }
859 plannedSpeed = MIN2(plannedSpeed, safe);
860
861 for (std::vector<CLeaderDist>::const_iterator it = blockers.begin(); it != blockers.end(); ++it) {
862 plannedSpeed = MIN2(plannedSpeed, informLeader(blocked, dir, *it, remainingSeconds));
863 }
864 return plannedSpeed;
865}
866
867
868void
869MSLCM_SL2015::informFollowers(int blocked, int dir,
870 const std::vector<CLeaderDist>& blockers,
871 double remainingSeconds,
872 double plannedSpeed) {
873 // #3727
874 for (std::vector<CLeaderDist>::const_iterator it = blockers.begin(); it != blockers.end(); ++it) {
875 informFollower(blocked, dir, *it, remainingSeconds, plannedSpeed);
876 }
877}
878
879
880void
883 // keep information about strategic change direction
885#ifdef DEBUG_INFORM
886 if (debugVehicle()) {
887 std::cout << SIMTIME
888 << " veh=" << myVehicle.getID()
889 << " prepareStep"
890 << " myCanChangeFully=" << myCanChangeFully
891 << "\n";
892 }
893#endif
895 myLeftSpace = 0;
897 myDontBrake = false;
898 myCFRelated.clear();
899 myCFRelatedReady = false;
900 const double halfWidth = getWidth() * 0.5;
901 // only permit changing within lane bounds but open up the range depending on the checked duration in _wantsChangeSublane()
904 if (isOpposite()) {
906 }
907 // truncate to work around numerical instability between different builds
908 mySpeedGainProbabilityRight = ceil(mySpeedGainProbabilityRight * 100000.0) * 0.00001;
909 mySpeedGainProbabilityLeft = ceil(mySpeedGainProbabilityLeft * 100000.0) * 0.00001;
910 myKeepRightProbability = ceil(myKeepRightProbability * 100000.0) * 0.00001;
911 // updated myExpectedSublaneSpeeds
912 // XXX only do this when (sub)lane changing is possible
913 std::vector<double> newExpectedSpeeds;
914#ifdef DEBUG_INFORM
915 if (DEBUG_COND) {
916 std::cout << SIMTIME << " veh=" << myVehicle.getID() << " myExpectedSublaneSpeeds=" << toString(myExpectedSublaneSpeeds) << "\n";
917 }
918#endif
920 // initialize
921 const MSEdge* currEdge = &myVehicle.getLane()->getEdge();
922 const std::vector<MSLane*>& lanes = currEdge->getLanes();
923 for (std::vector<MSLane*>::const_iterator it_lane = lanes.begin(); it_lane != lanes.end(); ++it_lane) {
924 const int subLanes = MAX2(1, int(ceil((*it_lane)->getWidth() / MSGlobals::gLateralResolution)));
925 for (int i = 0; i < subLanes; ++i) {
926 newExpectedSpeeds.push_back((*it_lane)->getVehicleMaxSpeed(&myVehicle));
927 }
928 }
929 if (currEdge->canChangeToOpposite()) {
930 MSLane* opposite = lanes.back()->getOpposite();
931 const int subLanes = MAX2(1, int(ceil(opposite->getWidth() / MSGlobals::gLateralResolution)));
932 for (int i = 0; i < subLanes; ++i) {
933 newExpectedSpeeds.push_back(lanes.back()->getVehicleMaxSpeed(&myVehicle));
934 }
935 }
936 if (myExpectedSublaneSpeeds.size() > 0) {
937 // copy old values
938 assert(myLastEdge != 0);
939 if (myLastEdge->getSubLaneSides().size() == myExpectedSublaneSpeeds.size()) {
940 const int subLaneShift = computeSublaneShift(myLastEdge, currEdge);
941 if (subLaneShift < std::numeric_limits<int>::max()) {
942 for (int i = 0; i < (int)myExpectedSublaneSpeeds.size(); ++i) {
943 const int newI = i + subLaneShift;
944 if (newI > 0 && newI < (int)newExpectedSpeeds.size()) {
945 newExpectedSpeeds[newI] = myExpectedSublaneSpeeds[i];
946 }
947 }
948 }
949 }
950 }
951 myExpectedSublaneSpeeds = newExpectedSpeeds;
952 myLastEdge = currEdge;
953 }
954 assert(myExpectedSublaneSpeeds.size() == myVehicle.getLane()->getEdge().getSubLaneSides().size());
955 if (mySigma > 0) {
957 }
958}
959
960double
961MSLCM_SL2015::getExtraReservation(int bestLaneOffset) const {
962 if (bestLaneOffset < -1) {
963 return 20;
964 } else if (bestLaneOffset > 1) {
965 return 40;
966 }
967 return 0;
968}
969
970
971double
973 //OUProcess::step(double state, double dt, double timeScale, double noiseIntensity)
974 const double deltaState = OUProcess::step(mySigmaState,
976 MAX2(NUMERICAL_EPS, (1 - mySigma) * 100), mySigma) - mySigmaState;
977 const double scaledDelta = deltaState * myVehicle.getSpeed() / myVehicle.getLane()->getSpeedLimit();
978 return scaledDelta;
979}
980
981double
985
986int
987MSLCM_SL2015::computeSublaneShift(const MSEdge* prevEdge, const MSEdge* curEdge) {
988 // find the first lane that targets the new edge
989 int prevShift = 0;
990 for (const MSLane* const lane : prevEdge->getLanes()) {
991 for (const MSLink* const link : lane->getLinkCont()) {
992 if (&link->getLane()->getEdge() == curEdge) {
993 int curShift = 0;
994 const MSLane* target = link->getLane();
995 const std::vector<MSLane*>& lanes2 = curEdge->getLanes();
996 for (std::vector<MSLane*>::const_iterator it_lane2 = lanes2.begin(); it_lane2 != lanes2.end(); ++it_lane2) {
997 const MSLane* lane2 = *it_lane2;
998 if (lane2 == target) {
999 return prevShift + curShift;
1000 }
1001 MSLeaderInfo ahead(lane2->getWidth());
1002 curShift += ahead.numSublanes();
1003 }
1004 assert(false);
1005 }
1006 }
1007 MSLeaderInfo ahead(lane->getWidth());
1008 prevShift -= ahead.numSublanes();
1009 }
1010 return std::numeric_limits<int>::max();
1011}
1012
1013
1014void
1016 if (!myCanChangeFully) {
1017 // do not reset state yet so we can continue our maneuver but acknowledge
1018 // a change to the right (movement should continue due to lane alignment desire)
1019 if (getManeuverDist() < 0) {
1021 }
1022#ifdef DEBUG_STATE
1023 if (DEBUG_COND) {
1024 std::cout << SIMTIME << " veh=" << myVehicle.getID() << " state not reset. maneuverDist=" << getManeuverDist() << "\n";
1025 }
1026#endif
1027 return;
1028 }
1029 myOwnState = 0;
1030 // XX do not reset values for unfinished maneuvers
1034
1035 if (myVehicle.getBestLaneOffset() == 0) {
1036 // if we are not yet on our best lane there might still be unseen blockers
1037 // (during patchSpeed)
1039 myLeftSpace = 0;
1040 }
1043 myDontBrake = false;
1044#if defined(DEBUG_MANEUVER) || defined(DEBUG_STATE)
1045 if (DEBUG_COND) {
1046 std::cout << SIMTIME << " veh=" << myVehicle.getID() << " changed()\n";
1047 }
1048#endif
1049}
1050
1051
1052void
1064
1065
1066int
1068 int laneOffset,
1069 LaneChangeAction alternatives,
1070 const MSLeaderDistanceInfo& leaders,
1071 const MSLeaderDistanceInfo& followers,
1072 const MSLeaderDistanceInfo& blockers,
1073 const MSLeaderDistanceInfo& neighLeaders,
1074 const MSLeaderDistanceInfo& neighFollowers,
1075 const MSLeaderDistanceInfo& neighBlockers,
1076 const MSLane& neighLane,
1077 const std::vector<MSVehicle::LaneQ>& preb,
1078 MSVehicle** lastBlocked,
1079 MSVehicle** firstBlocked,
1080 double& latDist, double& maneuverDist, int& blocked) {
1081
1082 if (laneOffset != 0) {
1083 // update mySafeLatDist w.r.t. the direction being checkd
1084 const double halfWidth = getWidth() * 0.5;
1085 double center = getVehicleCenter();
1086 if (laneOffset < 0) {
1087 mySafeLatDistRight = center - halfWidth;
1088 } else {
1089 mySafeLatDistLeft = getLeftBorder() - center - halfWidth;
1090 }
1091 }
1092
1093 const SUMOTime currentTime = MSNet::getInstance()->getCurrentTimeStep();
1094 // compute bestLaneOffset
1095 MSVehicle::LaneQ curr, neigh, best;
1096 int bestLaneOffset = 0;
1097 double currentDist = 0;
1098 double neighDist = 0;
1099 const MSLane* prebLane = myVehicle.getLane();
1100 if (prebLane->getEdge().isInternal()) {
1101 // internal edges are not kept inside the bestLanes structure
1102 if (isOpposite()) {
1103 prebLane = prebLane->getNormalPredecessorLane();
1104 } else {
1105 prebLane = prebLane->getLinkCont()[0]->getLane();
1106 }
1107 }
1108 // special case: vehicle considers changing to the opposite direction edge
1109 const bool checkOpposite = &neighLane.getEdge() != &myVehicle.getLane()->getEdge();
1110 const int prebOffset = (checkOpposite ? 0 : laneOffset);
1111 for (int p = 0; p < (int) preb.size(); ++p) {
1112 if (preb[p].lane == prebLane && p + laneOffset >= 0) {
1113 assert(p + prebOffset < (int)preb.size());
1114 curr = preb[p];
1115 neigh = preb[p + prebOffset];
1116 currentDist = curr.length;
1117 neighDist = neigh.length;
1118 bestLaneOffset = curr.bestLaneOffset;
1119 // VARIANT_13 (equalBest)
1120 if (bestLaneOffset == 0 && preb[p + prebOffset].bestLaneOffset == 0 && !checkOpposite) {
1121#ifdef DEBUG_WANTSCHANGE
1122 if (gDebugFlag2) {
1123 std::cout << STEPS2TIME(currentTime)
1124 << " veh=" << myVehicle.getID()
1125 << " bestLaneOffsetOld=" << bestLaneOffset
1126 << " bestLaneOffsetNew=" << laneOffset
1127 << "\n";
1128 }
1129#endif
1130 bestLaneOffset = prebOffset;
1131 }
1132 best = preb[p + bestLaneOffset];
1133 break;
1134 }
1135 }
1136 assert(curr.lane != nullptr);
1137 assert(neigh.lane != nullptr);
1138 assert(best.lane != nullptr);
1139 double driveToNextStop = -std::numeric_limits<double>::max();
1140 UNUSED_PARAMETER(driveToNextStop); // XXX use when computing usableDist
1141 if (myVehicle.nextStopDist() < std::numeric_limits<double>::max()
1143 // vehicle can always drive up to stop distance
1144 // @note this information is dynamic and thus not available in updateBestLanes()
1145 // @note: nextStopDist was compute before the vehicle moved
1146 driveToNextStop = myVehicle.nextStopDist();
1147 const double stopPos = getForwardPos() + myVehicle.nextStopDist() - myVehicle.getLastStepDist();
1148#ifdef DEBUG_WANTS_CHANGE
1149 if (DEBUG_COND) {
1150 std::cout << SIMTIME << std::setprecision(gPrecision) << " veh=" << myVehicle.getID()
1151 << " stopDist=" << myVehicle.nextStopDist()
1152 << " lastDist=" << myVehicle.getLastStepDist()
1153 << " stopPos=" << stopPos
1154 << " currentDist=" << currentDist
1155 << " neighDist=" << neighDist
1156 << "\n";
1157 }
1158#endif
1159 currentDist = MAX2(currentDist, stopPos);
1160 neighDist = MAX2(neighDist, stopPos);
1161 }
1162 // direction specific constants
1163 const bool right = (laneOffset == -1);
1164 const bool left = (laneOffset == 1);
1165 const int myLca = (right ? LCA_MRIGHT : (left ? LCA_MLEFT : 0));
1166 const int lcaCounter = (right ? LCA_LEFT : (left ? LCA_RIGHT : LCA_NONE));
1167 const bool changeToBest = (right && bestLaneOffset < 0) || (left && bestLaneOffset > 0) || (laneOffset == 0 && bestLaneOffset == 0);
1168 // keep information about being a leader/follower but remove information
1169 // about previous lane change request or urgency
1170 int ret = (myOwnState & 0xffff0000);
1171
1172 // compute the distance when changing to the neighboring lane
1173 // (ensure we do not lap into the line behind neighLane since there might be unseen blockers)
1174 // minimum distance to move the vehicle fully onto the new lane
1175 double latLaneDist = laneOffset == 0 ? 0. : myVehicle.lateralDistanceToLane(laneOffset);
1176
1177 // VARIANT_5 (disableAMBACKBLOCKER1)
1178 /*
1179 if (leader.first != 0
1180 && (myOwnState & LCA_AMBLOCKINGFOLLOWER_DONTBRAKE) != 0
1181 && (leader.first->getLaneChangeModel().getOwnState() & LCA_AMBLOCKINGFOLLOWER_DONTBRAKE) != 0) {
1182
1183 myOwnState &= (0xffffffff - LCA_AMBLOCKINGFOLLOWER_DONTBRAKE);
1184 if (myVehicle.getSpeed() > SUMO_const_haltingSpeed) {
1185 myOwnState |= LCA_AMBACKBLOCKER;
1186 } else {
1187 ret |= LCA_AMBACKBLOCKER;
1188 myDontBrake = true;
1189 }
1190 }
1191 */
1192
1193#ifdef DEBUG_WANTSCHANGE
1194 if (gDebugFlag2) {
1195 std::cout << STEPS2TIME(currentTime)
1196 << " veh=" << myVehicle.getID()
1197 << " myState=" << toString((LaneChangeAction)myOwnState)
1198 << " firstBlocked=" << Named::getIDSecure(*firstBlocked)
1199 << " lastBlocked=" << Named::getIDSecure(*lastBlocked)
1200 << "\n leaders=" << leaders.toString()
1201 << "\n followers=" << followers.toString()
1202 << "\n blockers=" << blockers.toString()
1203 << "\n neighLeaders=" << neighLeaders.toString()
1204 << "\n neighFollowers=" << neighFollowers.toString()
1205 << "\n neighBlockers=" << neighBlockers.toString()
1206 << "\n changeToBest=" << changeToBest
1207 << " latLaneDist=" << latLaneDist
1208 << "\n expectedSpeeds=" << toString(myExpectedSublaneSpeeds)
1209 << std::endl;
1210 }
1211#endif
1212
1213 ret = slowDownForBlocked(lastBlocked, ret);
1214 // VARIANT_14 (furtherBlock)
1215 if (lastBlocked != firstBlocked) {
1216 ret = slowDownForBlocked(firstBlocked, ret);
1217 }
1218
1219
1220 // we try to estimate the distance which is necessary to get on a lane
1221 // we have to get on in order to keep our route
1222 // we assume we need something that depends on our velocity
1223 // and compare this with the free space on our wished lane
1224 //
1225 // if the free space is somehow less than the space we need, we should
1226 // definitely try to get to the desired lane
1227 //
1228 // this rule forces our vehicle to change the lane if a lane changing is necessary soon
1229 // lookAheadDistance:
1230 // we do not want the lookahead distance to change all the time so we discrectize the speed a bit
1231
1232 // VARIANT_18 (laHyst)
1235 } else {
1236 // FIXME: This strongly dependent on the value of TS, see LC2013 for the fix (l.1153, currently)
1239 }
1240 //myLookAheadSpeed = myVehicle.getLane()->getVehicleMaxSpeed(&myVehicle);
1241
1242 //double laDist = laSpeed > LOOK_FORWARD_SPEED_DIVIDER
1243 // ? laSpeed * LOOK_FORWARD_FAR
1244 // : laSpeed * LOOK_FORWARD_NEAR;
1245 double laDist = myLookAheadSpeed * LOOK_FORWARD * myStrategicParam * (right ? 1 : myLookaheadLeft);
1246 laDist += myVehicle.getVehicleType().getLengthWithGap() * 2.;
1247 // aggressive drivers may elect to use reduced strategic lookahead to optimize speed
1248 /*
1249 if (mySpeedGainProbabilityRight > myChangeProbThresholdRight
1250 || mySpeedGainProbabilityLeft > myChangeProbThresholdLeft) {
1251 laDist *= MAX2(0.0, (1 - myPushy));
1252 laDist *= MAX2(0,0, (1 - myAssertive));
1253 laDist *= MAX2(0,0, (2 - mySpeedGainParam));
1254 }
1255 */
1256
1257 // react to a stopped leader on the current lane
1258 if (bestLaneOffset == 0 && leaders.hasStoppedVehicle()) {
1259 // value is doubled for the check since we change back and forth
1260 // laDist = 0.5 * (myVehicle.getVehicleType().getLengthWithGap() + leader.first->getVehicleType().getLengthWithGap());
1261 // XXX determine length of longest stopped vehicle
1263 } else if (checkOpposite && isOpposite() && neighLeaders.hasStoppedVehicle()) {
1264 // compute exact distance to overtake stopped vehicle
1265 laDist = 0;
1266 for (int i = 0; i < neighLeaders.numSublanes(); ++i) {
1267 CLeaderDist vehDist = neighLeaders[i];
1268 if (vehDist.first != nullptr && vehDist.first->isStopped()) {
1269 laDist = MAX2(laDist, myVehicle.getVehicleType().getMinGap() + vehDist.second + vehDist.first->getVehicleType().getLengthWithGap());
1270 }
1271 }
1272 laDist += myVehicle.getVehicleType().getLength();
1273 }
1274 if (myStrategicParam < 0) {
1275 laDist = -1e3; // never perform strategic change
1276 }
1277
1278 // free space that is available for changing
1279 //const double neighSpeed = (neighLead.first != 0 ? neighLead.first->getSpeed() :
1280 // neighFollow.first != 0 ? neighFollow.first->getSpeed() :
1281 // best.lane->getSpeedLimit());
1282 // @note: while this lets vehicles change earlier into the correct direction
1283 // it also makes the vehicles more "selfish" and prevents changes which are necessary to help others
1284
1285 const double roundaboutBonus = MSLCHelper::getRoundaboutDistBonus(myVehicle, myRoundaboutBonus, curr, neigh, best);
1286 currentDist += roundaboutBonus;
1287 neighDist += roundaboutBonus;
1288
1289 if (laneOffset != 0) {
1290 ret = checkStrategicChange(ret,
1291 neighLane,
1292 laneOffset,
1293 leaders,
1294 neighLeaders,
1295 curr, neigh, best,
1296 bestLaneOffset,
1297 changeToBest,
1298 currentDist,
1299 neighDist,
1300 laDist,
1301 roundaboutBonus,
1302 latLaneDist,
1303 checkOpposite,
1304 latDist);
1305 }
1306
1307 if ((ret & LCA_STAY) != 0 && latDist == 0) {
1308 // ensure that mySafeLatDistLeft / mySafeLatDistRight are up to date for the
1309 // subsquent check with laneOffset = 0
1310 const double center = myVehicle.getCenterOnEdge();
1311 const double neighRight = getNeighRight(neighLane);
1312 updateGaps(neighLeaders, neighRight, center, 1.0, mySafeLatDistRight, mySafeLatDistLeft);
1313 updateGaps(neighFollowers, neighRight, center, 1.0, mySafeLatDistRight, mySafeLatDistLeft);
1314 // remove TraCI flags because it should not be included in "state-without-traci"
1315 ret = getCanceledState(laneOffset);
1316 return ret;
1317 }
1318 if ((ret & LCA_URGENT) != 0) {
1319 // prepare urgent lane change maneuver
1320 if (changeToBest && abs(bestLaneOffset) > 1
1321 && curr.bestContinuations.back()->getLinkCont().size() != 0
1322 ) {
1323 // there might be a vehicle which needs to counter-lane-change one lane further and we cannot see it yet
1324 const double reserve = MIN2(myLeftSpace - MAGIC_OFFSET - myVehicle.getVehicleType().getMinGap(), right ? 20.0 : 40.0);
1326#ifdef DEBUG_WANTSCHANGE
1327 if (gDebugFlag2) {
1328 std::cout << " reserving space for unseen blockers myLeadingBlockerLength=" << myLeadingBlockerLength << "\n";
1329 }
1330#endif
1331 }
1332
1333 // letting vehicles merge in at the end of the lane in case of counter-lane change, step#1
1334 // if there is a leader and he wants to change to the opposite direction
1335 MSVehicle* neighLeadLongest = const_cast<MSVehicle*>(getLongest(neighLeaders).first);
1336 const bool canContinue = curr.bestContinuations.size() > 1;
1337#ifdef DEBUG_WANTSCHANGE
1338 if (DEBUG_COND) {
1339 std::cout << SIMTIME << " veh=" << myVehicle.getID() << " neighLeaders=" << neighLeaders.toString() << " longest=" << Named::getIDSecure(neighLeadLongest) << " firstBlocked=" << Named::getIDSecure(*firstBlocked) << "\n";
1340 }
1341#endif
1342 bool canReserve = MSLCHelper::updateBlockerLength(myVehicle, neighLeadLongest, lcaCounter, myLeftSpace - MAGIC_OFFSET, canContinue, myLeadingBlockerLength);
1343 if (*firstBlocked != neighLeadLongest && tieBrakeLeader(*firstBlocked)) {
1344 canReserve &= MSLCHelper::updateBlockerLength(myVehicle, *firstBlocked, lcaCounter, myLeftSpace - MAGIC_OFFSET, canContinue, myLeadingBlockerLength);
1345 }
1346 if (!canReserve && !isOpposite()) {
1347 // we have a low-priority relief connection
1348 // std::cout << SIMTIME << " veh=" << myVehicle.getID() << " cannotReserve for blockers\n";
1349 myDontBrake = canContinue;
1350 }
1351
1352 std::vector<CLeaderDist> collectLeadBlockers;
1353 std::vector<CLeaderDist> collectFollowBlockers;
1354 int blockedFully = 0; // wether execution of the full maneuver is blocked
1355 maneuverDist = latDist;
1356 const double gapFactor = computeGapFactor(LCA_STRATEGIC);
1357 blocked = checkBlocking(neighLane, latDist, maneuverDist, laneOffset,
1358 leaders, followers, blockers,
1359 neighLeaders, neighFollowers, neighBlockers, &collectLeadBlockers, &collectFollowBlockers,
1360 false, gapFactor, &blockedFully);
1361
1362 const double absLaneOffset = fabs(bestLaneOffset != 0 ? bestLaneOffset : latDist / SUMO_const_laneWidth);
1363 const double remainingSeconds = ((ret & LCA_TRACI) == 0 ?
1364 MAX2(STEPS2TIME(TS), myLeftSpace / MAX2(myLookAheadSpeed, NUMERICAL_EPS) / absLaneOffset / URGENCY) :
1366 const double plannedSpeed = informLeaders(blocked, myLca, collectLeadBlockers, remainingSeconds);
1367 // coordinate with direct obstructions
1368 if (plannedSpeed >= 0) {
1369 // maybe we need to deal with a blocking follower
1370 informFollowers(blocked, myLca, collectFollowBlockers, remainingSeconds, plannedSpeed);
1371 }
1372 if (plannedSpeed > 0) {
1373 commitManoeuvre(blocked, blockedFully, leaders, neighLeaders, neighLane, maneuverDist);
1374 }
1375#if defined(DEBUG_WANTSCHANGE) || defined(DEBUG_STATE)
1376 if (gDebugFlag2) {
1377 std::cout << STEPS2TIME(currentTime)
1378 << " veh=" << myVehicle.getID()
1379 << " myLeftSpace=" << myLeftSpace
1380 << " changeFully=" << myCanChangeFully
1381 << " blockedFully=" << toString((LaneChangeAction)blockedFully)
1382 << " remainingSeconds=" << remainingSeconds
1383 << " plannedSpeed=" << plannedSpeed
1384 << " mySafeLatDistRight=" << mySafeLatDistRight
1385 << " mySafeLatDistLeft=" << mySafeLatDistLeft
1386 << "\n";
1387 }
1388#endif
1389 // remove TraCI flags because it should not be included in "state-without-traci"
1390 ret = getCanceledState(laneOffset);
1391 return ret;
1392 }
1393 // VARIANT_15
1394 if (roundaboutBonus > 0) {
1395
1396#ifdef DEBUG_WANTS_CHANGE
1397 if (DEBUG_COND) {
1398 std::cout << STEPS2TIME(currentTime)
1399 << " veh=" << myVehicle.getID()
1400 << " roundaboutBonus=" << roundaboutBonus
1401 << " myLeftSpace=" << myLeftSpace
1402 << "\n";
1403 }
1404#endif
1405 // try to use the inner lanes of a roundabout to increase throughput
1406 // unless we are approaching the exit
1407 if (left) {
1408 ret |= LCA_COOPERATIVE;
1409 if (!cancelRequest(ret | LCA_LEFT, laneOffset)) {
1410 if ((ret & LCA_STAY) == 0) {
1411 latDist = latLaneDist;
1412 maneuverDist = latLaneDist;
1413 blocked = checkBlocking(neighLane, latDist, maneuverDist, laneOffset,
1414 leaders, followers, blockers,
1415 neighLeaders, neighFollowers, neighBlockers);
1416 }
1417 return ret;
1418 } else {
1419 ret &= ~LCA_COOPERATIVE;
1420 }
1421 } else {
1423 }
1424 }
1425
1426 // --------
1427
1428 // -------- make place on current lane if blocking follower
1429 //if (amBlockingFollowerPlusNB()) {
1430 // std::cout << myVehicle.getID() << ", " << currentDistAllows(neighDist, bestLaneOffset, laDist)
1431 // << " neighDist=" << neighDist
1432 // << " currentDist=" << currentDist
1433 // << "\n";
1434 //}
1435 const double inconvenience = (latLaneDist < 0
1438#ifdef DEBUG_COOPERATE
1439 if (gDebugFlag2) {
1440 std::cout << STEPS2TIME(currentTime)
1441 << " veh=" << myVehicle.getID()
1442 << " amBlocking=" << amBlockingFollowerPlusNB()
1443 << " state=" << toString((LaneChangeAction)myOwnState)
1444 << " myLca=" << toString((LaneChangeAction)myLca)
1445 << " prevState=" << toString((LaneChangeAction)myPreviousState)
1446 << " inconvenience=" << inconvenience
1447 << " origLatDist=" << getManeuverDist()
1448 << " wantsChangeToHelp=" << (right ? "right" : "left")
1449 << " state=" << myOwnState
1450 << "\n";
1451 }
1452#endif
1453
1454 if (laneOffset != 0
1456 // VARIANT_6 : counterNoHelp
1457 && ((myOwnState & myLca) != 0))
1458 ||
1459 // continue previous cooperative change
1462 // change is in the right direction
1463 && (laneOffset * getManeuverDist() > 0)))
1464 && (inconvenience < myCooperativeParam)
1465 && (changeToBest || currentDistAllows(neighDist, abs(bestLaneOffset) + 1, laDist))) {
1466
1467 // VARIANT_2 (nbWhenChangingToHelp)
1468#ifdef DEBUG_COOPERATE
1469 if (gDebugFlag2) {
1470 std::cout << " wants cooperative change\n";
1471 }
1472#endif
1473
1474 ret |= LCA_COOPERATIVE | LCA_URGENT ;//| LCA_CHANGE_TO_HELP;
1475 if (!cancelRequest(ret | getLCA(ret, latLaneDist), laneOffset)) {
1476 latDist = amBlockingFollowerPlusNB() ? latLaneDist : getManeuverDist();
1477 maneuverDist = latDist;
1478 blocked = checkBlocking(neighLane, latDist, maneuverDist, laneOffset,
1479 leaders, followers, blockers,
1480 neighLeaders, neighFollowers, neighBlockers);
1481 return ret;
1482 } else {
1483 ret &= ~(LCA_COOPERATIVE | LCA_URGENT);
1484 }
1485 }
1486
1487 // --------
1488
1489
1492 //if ((blocked & LCA_BLOCKED) != 0) {
1493 // return ret;
1494 //}
1496
1497 // -------- higher speed
1498 //if ((congested(neighLead.first) && neighLead.second < 20) || predInteraction(leader.first)) { //!!!
1499 // return ret;
1500 //}
1501
1502 // iterate over all possible combinations of sublanes this vehicle might cover and check the potential speed
1503 const MSEdge& edge = (isOpposite() ? myVehicle.getLane()->getParallelOpposite() : myVehicle.getLane())->getEdge();
1504 const std::vector<double>& sublaneSides = edge.getSubLaneSides();
1505 assert(sublaneSides.size() == myExpectedSublaneSpeeds.size());
1506 const double vehWidth = getWidth();
1507 const double rightVehSide = getVehicleCenter() - 0.5 * vehWidth;
1508 const double leftVehSide = rightVehSide + vehWidth;
1509 // figure out next speed when staying where we are
1510 double defaultNextSpeed = std::numeric_limits<double>::max();
1512 int leftmostOnEdge = (int)sublaneSides.size() - 1;
1513 while (leftmostOnEdge > 0 && sublaneSides[leftmostOnEdge] > leftVehSide) {
1514 leftmostOnEdge--;
1515 }
1516 int rightmostOnEdge = leftmostOnEdge;
1517 while (rightmostOnEdge > 0 && sublaneSides[rightmostOnEdge] > rightVehSide + NUMERICAL_EPS) {
1518 defaultNextSpeed = MIN2(defaultNextSpeed, myExpectedSublaneSpeeds[rightmostOnEdge]);
1519#ifdef DEBUG_WANTSCHANGE
1520 if (gDebugFlag2) {
1521 std::cout << " adapted to current sublane=" << rightmostOnEdge << " defaultNextSpeed=" << defaultNextSpeed << "\n";
1522 std::cout << " sublaneSides[rightmostOnEdge]=" << sublaneSides[rightmostOnEdge] << " rightVehSide=" << rightVehSide << "\n";
1523 }
1524#endif
1525 rightmostOnEdge--;
1526 }
1527 defaultNextSpeed = MIN2(defaultNextSpeed, myExpectedSublaneSpeeds[rightmostOnEdge]);
1528#ifdef DEBUG_WANTSCHANGE
1529 if (gDebugFlag2) {
1530 std::cout << " adapted to current sublane=" << rightmostOnEdge << " defaultNextSpeed=" << defaultNextSpeed << "\n";
1531 std::cout << " sublaneSides[rightmostOnEdge]=" << sublaneSides[rightmostOnEdge] << " rightVehSide=" << rightVehSide << "\n";
1532 }
1533#endif
1534 double maxGain = -std::numeric_limits<double>::max();
1535 double maxGainRight = -std::numeric_limits<double>::max();
1536 double maxGainLeft = -std::numeric_limits<double>::max();
1537 double latDistNice = std::numeric_limits<double>::max();
1538
1539 const int iMin = MIN2(myVehicle.getLane()->getRightmostSublane(), neighLane.getRightmostSublane());
1540 double leftMax = MAX2(
1542 neighLane.getRightSideOnEdge() + neighLane.getWidth());
1543 double rightMin = MIN2(myVehicle.getLane()->getRightSideOnEdge(), neighLane.getRightSideOnEdge());
1544 if (checkOpposite || isOpposite()) {
1545 leftMax = getLeftBorder();
1546 } else {
1547 assert(leftMax <= edge.getWidth());
1548 }
1549 int sublaneCompact = MAX2(iMin, rightmostOnEdge - 1); // try to compactify to the right by default
1550
1551 const double laneBoundary = laneOffset < 0 ? myVehicle.getLane()->getRightSideOnEdge() : neighLane.getRightSideOnEdge();
1552 // if there is a neighboring lane we could change to, check sublanes on all lanes of the edge
1553 // but restrict maneuver to the currently visible lanes (current, neigh) to ensure safety
1554 // This way we can discover a fast lane beyond the immediate neighbor lane
1555 const double maxLatDist = leftMax - leftVehSide;
1556 const double minLatDist = rightMin - rightVehSide;
1557 const int iStart = laneOffset == 0 ? iMin : 0;
1558 const double rightEnd = laneOffset == 0 ? leftMax : (checkOpposite ? getLeftBorder() : edge.getWidth());
1559#ifdef DEBUG_WANTSCHANGE
1560 if (gDebugFlag2) std::cout
1561 << " checking sublanes rightmostOnEdge=" << rightmostOnEdge
1562 << " rightEnd=" << rightEnd
1563 << " leftmostOnEdge=" << leftmostOnEdge
1564 << " iStart=" << iStart
1565 << " iMin=" << iMin
1566 << " sublaneSides=" << sublaneSides.size()
1567 << " leftMax=" << leftMax
1568 << " minLatDist=" << minLatDist
1569 << " maxLatDist=" << maxLatDist
1570 << " sublaneCompact=" << sublaneCompact
1571 << "\n";
1572#endif
1573 for (int i = iStart; i < (int)sublaneSides.size(); ++i) {
1574 if (sublaneSides[i] + vehWidth < rightEnd) {
1575 // i is the rightmost sublane and the left side of vehicles still fits on the edge,
1576 // compute min speed of all sublanes covered by the vehicle in this case
1577 double vMin = myExpectedSublaneSpeeds[i];
1578 //std::cout << " i=" << i << "\n";
1579 int j = i;
1580 while (vMin > 0 && j < (int)sublaneSides.size() && sublaneSides[j] < sublaneSides[i] + vehWidth) {
1581 vMin = MIN2(vMin, myExpectedSublaneSpeeds[j]);
1582 //std::cout << " j=" << j << " vMin=" << vMin << " sublaneSides[j]=" << sublaneSides[j] << " leftVehSide=" << leftVehSide << " rightVehSide=" << rightVehSide << "\n";
1583 ++j;
1584 }
1585 // check whether the vehicle is between lanes
1586 if (laneOffset != 0 && overlap(sublaneSides[i], sublaneSides[i] + vehWidth, laneBoundary, laneBoundary)) {
1587 vMin *= (1 - myLaneDiscipline);
1588 }
1589 double relativeGain = (vMin - defaultNextSpeed) / MAX2(vMin, RELGAIN_NORMALIZATION_MIN_SPEED);
1590 const double currentLatDist = MIN2(MAX2(sublaneSides[i] - rightVehSide, minLatDist), maxLatDist);
1591 if (currentLatDist > 0 && myVehicle.getLane()->getBidiLane() != nullptr) {
1592 // penalize overtaking on the left if the lane is used in both
1593 // directions
1594 relativeGain *= 0.5;
1595 }
1596 // @note this is biased for changing to the left since we compare the sublanes in ascending order
1597 if (relativeGain > maxGain) {
1598 maxGain = relativeGain;
1599 if (maxGain > GAIN_PERCEPTION_THRESHOLD) {
1600 sublaneCompact = i;
1601 latDist = currentLatDist;
1602#ifdef DEBUG_WANTSCHANGE
1603 if (gDebugFlag2) {
1604 std::cout << " i=" << i << " newLatDist=" << latDist << " relGain=" << relativeGain << "\n";
1605 }
1606#endif
1607 }
1608 } else {
1609 // if anticipated gains to the left are higher then to the right and current gains are equal, prefer left
1610 if (currentLatDist > 0
1611 //&& latDist < 0 // #7184 compensates for #7185
1613 && relativeGain > GAIN_PERCEPTION_THRESHOLD
1614 && maxGain - relativeGain < NUMERICAL_EPS) {
1615 latDist = currentLatDist;
1616 }
1617 }
1618#ifdef DEBUG_WANTSCHANGE
1619 if (gDebugFlag2) {
1620 std::cout << " i=" << i << " rightmostOnEdge=" << rightmostOnEdge << " vMin=" << vMin << " relGain=" << relativeGain << " sublaneCompact=" << sublaneCompact << " curLatDist=" << currentLatDist << "\n";
1621 }
1622#endif
1623 if (currentLatDist < -NUMERICAL_EPS * myVehicle.getActionStepLengthSecs()) {
1624 maxGainRight = MAX2(maxGainRight, relativeGain);
1625 } else if (currentLatDist > NUMERICAL_EPS * myVehicle.getActionStepLengthSecs()) {
1626 maxGainLeft = MAX2(maxGainLeft, relativeGain);
1627 }
1628 const double subAlignDist = sublaneSides[i] - rightVehSide;
1629 if (fabs(subAlignDist) < fabs(latDistNice)) {
1630 latDistNice = subAlignDist;
1631#ifdef DEBUG_WANTSCHANGE
1632 if (gDebugFlag2) std::cout
1633 << " nicest sublane=" << i
1634 << " side=" << sublaneSides[i]
1635 << " rightSide=" << rightVehSide
1636 << " latDistNice=" << latDistNice
1637 << " maxGainR=" << maxGainRight
1638 << " maxGainL=" << maxGainLeft
1639 << "\n";
1640#endif
1641 }
1642 }
1643 }
1644 // updated change probabilities
1645 if (maxGainRight != -std::numeric_limits<double>::max()) {
1646#ifdef DEBUG_WANTSCHANGE
1647 if (gDebugFlag2) {
1648 std::cout << " speedGainR_old=" << mySpeedGainProbabilityRight;
1649 }
1650#endif
1652#ifdef DEBUG_WANTSCHANGE
1653 if (gDebugFlag2) {
1654 std::cout << " speedGainR_new=" << mySpeedGainProbabilityRight << "\n";
1655 }
1656#endif
1657 }
1658 if (maxGainLeft != -std::numeric_limits<double>::max()) {
1659#ifdef DEBUG_WANTSCHANGE
1660 if (gDebugFlag2) {
1661 std::cout << " speedGainL_old=" << mySpeedGainProbabilityLeft;
1662 }
1663#endif
1665#ifdef DEBUG_WANTSCHANGE
1666 if (gDebugFlag2) {
1667 std::cout << " speedGainL_new=" << mySpeedGainProbabilityLeft << "\n";
1668 }
1669#endif
1670 }
1671 // decay if there is no reason for or against changing (only if we have enough information)
1672 if ((fabs(maxGainRight) < NUMERICAL_EPS || maxGainRight == -std::numeric_limits<double>::max())
1673 && (right || (alternatives & LCA_RIGHT) == 0)) {
1675 }
1676 if ((fabs(maxGainLeft) < NUMERICAL_EPS || maxGainLeft == -std::numeric_limits<double>::max())
1677 && (left || (alternatives & LCA_LEFT) == 0)) {
1679 }
1680
1681
1682#ifdef DEBUG_WANTSCHANGE
1683 if (gDebugFlag2) std::cout << SIMTIME
1684 << " veh=" << myVehicle.getID()
1685 << " defaultNextSpeed=" << defaultNextSpeed
1686 << " maxGain=" << maxGain
1687 << " maxGainRight=" << maxGainRight
1688 << " maxGainLeft=" << maxGainLeft
1689 << " latDist=" << latDist
1690 << " latDistNice=" << latDistNice
1691 << " sublaneCompact=" << sublaneCompact
1692 << "\n";
1693#endif
1694
1695 if (!left) {
1696 // ONLY FOR CHANGING TO THE RIGHT
1697 // start keepRight maneuver when no speed loss is expected and continue
1698 // started maneuvers if the loss isn't too big
1699 if (right && myVehicle.getSpeed() > 0 && (maxGainRight >= 0
1700 || ((myPreviousState & LCA_KEEPRIGHT) != 0 && maxGainRight >= -myKeepRightParam))) {
1701 // honor the obligation to keep right (Rechtsfahrgebot)
1702 const double vMax = myVehicle.getLane()->getVehicleMaxSpeed(&myVehicle);
1703 const double roadSpeedFactor = vMax / myVehicle.getLane()->getSpeedLimit(); // differse from speedFactor if vMax < speedLimit
1704 double acceptanceTime;
1705 if (myKeepRightAcceptanceTime == -1) {
1706 // legacy behavior: scale acceptance time with current speed and
1707 // use old hard-coded constant
1708 acceptanceTime = 7 * roadSpeedFactor * MAX2(1.0, myVehicle.getSpeed());
1709 } else {
1710 acceptanceTime = myKeepRightAcceptanceTime * roadSpeedFactor;
1711 if (followers.hasVehicles()) {
1712 // reduce acceptanceTime if a follower vehicle is faster or wants to drive faster
1713 double minFactor = 1.0;
1714 for (int i = 0; i < followers.numSublanes(); ++i) {
1715 CLeaderDist follower = followers[i];
1716 if (follower.first != nullptr && follower.second < 2 * follower.first->getCarFollowModel().brakeGap(follower.first->getSpeed())) {
1717 if (follower.first->getSpeed() >= myVehicle.getSpeed()) {
1718 double factor = MAX2(1.0, myVehicle.getSpeed()) / MAX2(1.0, follower.first->getSpeed());
1719 const double fRSF = follower.first->getLane()->getVehicleMaxSpeed(follower.first) / follower.first->getLane()->getSpeedLimit();
1720 if (fRSF > roadSpeedFactor) {
1721 factor /= fRSF;
1722 }
1723 if (factor < minFactor) {
1724 minFactor = factor;
1725 }
1726 }
1727 }
1728 }
1729 acceptanceTime *= minFactor;
1730 }
1731 }
1732 double fullSpeedGap = MAX2(0., neighDist - myVehicle.getCarFollowModel().brakeGap(vMax));
1733 double fullSpeedDrivingSeconds = MIN2(acceptanceTime, fullSpeedGap / vMax);
1734 CLeaderDist neighLead = getSlowest(neighLeaders);
1735 if (neighLead.first != 0 && neighLead.first->getSpeed() < vMax) {
1736 fullSpeedGap = MAX2(0., MIN2(fullSpeedGap,
1737 neighLead.second - myVehicle.getCarFollowModel().getSecureGap(&myVehicle, neighLead.first,
1738 vMax, neighLead.first->getSpeed(), neighLead.first->getCarFollowModel().getMaxDecel())));
1739 fullSpeedDrivingSeconds = MIN2(fullSpeedDrivingSeconds, fullSpeedGap / (vMax - neighLead.first->getSpeed()));
1740 }
1741 const double deltaProb = (myChangeProbThresholdRight * (fullSpeedDrivingSeconds / acceptanceTime) / KEEP_RIGHT_TIME) * myVehicle.getActionStepLengthSecs();
1742 const bool isSlide = preventSliding(latLaneDist);
1743 // stay below threshold
1744 if (!isSlide || !wantsKeepRight(myKeepRightProbability + deltaProb)) {
1745 myKeepRightProbability += deltaProb;
1746 }
1747
1748#ifdef DEBUG_WANTSCHANGE
1749 if (gDebugFlag2) {
1750 std::cout << STEPS2TIME(currentTime)
1751 << " considering keepRight:"
1752 << " vMax=" << vMax
1753 << " neighDist=" << neighDist
1754 << " brakeGap=" << myVehicle.getCarFollowModel().brakeGap(myVehicle.getSpeed())
1755 << " leaderSpeed=" << (neighLead.first == 0 ? -1 : neighLead.first->getSpeed())
1756 << " secGap=" << (neighLead.first == 0 ? -1 : myVehicle.getCarFollowModel().getSecureGap(&myVehicle, neighLead.first,
1757 myVehicle.getSpeed(), neighLead.first->getSpeed(), neighLead.first->getCarFollowModel().getMaxDecel()))
1758 << " acceptanceTime=" << acceptanceTime
1759 << " fullSpeedGap=" << fullSpeedGap
1760 << " fullSpeedDrivingSeconds=" << fullSpeedDrivingSeconds
1761 << " dProb=" << deltaProb
1762 << " isSlide=" << isSlide
1763 << " keepRight=" << myKeepRightProbability
1764 << " speedGainL=" << mySpeedGainProbabilityLeft
1765 << "\n";
1766 }
1767#endif
1769 /*&& latLaneDist <= -NUMERICAL_EPS * myVehicle.getActionStepLengthSecs()*/) {
1770 ret |= LCA_KEEPRIGHT;
1771 assert(myVehicle.getLane()->getIndex() > neighLane.getIndex() || isOpposite());
1772 if (!cancelRequest(ret | LCA_RIGHT, laneOffset)) {
1773 latDist = latLaneDist;
1774 maneuverDist = latLaneDist;
1775 blocked = checkBlocking(neighLane, latDist, maneuverDist, laneOffset,
1776 leaders, followers, blockers,
1777 neighLeaders, neighFollowers, neighBlockers);
1778 return ret;
1779 } else {
1780 ret &= ~LCA_KEEPRIGHT;
1781 }
1782 }
1783 }
1784
1785 const double bidiRightFactor = myVehicle.getLane()->getBidiLane() == nullptr ? 1 : 0.05;
1786#ifdef DEBUG_WANTSCHANGE
1787 if (gDebugFlag2) {
1788 std::cout << STEPS2TIME(currentTime)
1789 << " speedGainR=" << mySpeedGainProbabilityRight
1790 << " speedGainL=" << mySpeedGainProbabilityLeft
1791 << " neighDist=" << neighDist
1792 << " neighTime=" << neighDist / MAX2(.1, myVehicle.getSpeed())
1793 << " rThresh=" << myChangeProbThresholdRight
1794 << " rThresh2=" << myChangeProbThresholdRight* bidiRightFactor
1795 << " latDist=" << latDist
1796 << "\n";
1797 }
1798#endif
1799
1800 // make changing on the right more attractive on bidi edges
1801 if (latDist < 0 && mySpeedGainProbabilityRight >= MAX2(myChangeProbThresholdRight * bidiRightFactor, mySpeedGainProbabilityLeft)
1802 && neighDist / MAX2(.1, myVehicle.getSpeed()) > 20.) {
1803 ret |= LCA_SPEEDGAIN;
1804 if (!cancelRequest(ret | getLCA(ret, latDist), laneOffset)) {
1805 int blockedFully = 0;
1806 maneuverDist = latDist;
1807 blocked = checkBlocking(neighLane, latDist, maneuverDist, laneOffset,
1808 leaders, followers, blockers,
1809 neighLeaders, neighFollowers, neighBlockers,
1810 nullptr, nullptr, false, 0, &blockedFully);
1811 //commitManoeuvre(blocked, blockedFully, leaders, neighLeaders, neighLane);
1812 return ret;
1813 } else {
1814 // @note: restore ret so subsequent calls to cancelRequest work correctly
1815 latDist = 0;
1816 ret &= ~LCA_SPEEDGAIN;
1817 }
1818 }
1819 }
1820 if (!right || isOpposite()) {
1821
1822 const bool stayInLane = myVehicle.getLateralPositionOnLane() + latDist < 0.5 * myVehicle.getLane()->getWidth();
1823#ifdef DEBUG_WANTSCHANGE
1824 if (gDebugFlag2) {
1825 std::cout << STEPS2TIME(currentTime)
1826 << " speedGainL=" << mySpeedGainProbabilityLeft
1827 << " speedGainR=" << mySpeedGainProbabilityRight
1828 << " latDist=" << latDist
1829 << " neighDist=" << neighDist
1830 << " neighTime=" << neighDist / MAX2(.1, myVehicle.getSpeed())
1831 << " lThresh=" << myChangeProbThresholdLeft
1832 << " stayInLane=" << stayInLane
1833 << "\n";
1834 }
1835#endif
1836
1838 // if we leave our lane, we should be able to stay in the new
1839 // lane for some time
1840 (stayInLane || neighDist / MAX2(.1, myVehicle.getSpeed()) > SPEED_GAIN_MIN_SECONDS)) {
1841 ret |= LCA_SPEEDGAIN;
1842 if (!cancelRequest(ret + getLCA(ret, latDist), laneOffset)) {
1843 int blockedFully = 0;
1844 maneuverDist = latDist;
1845 blocked = checkBlocking(neighLane, latDist, maneuverDist, laneOffset,
1846 leaders, followers, blockers,
1847 neighLeaders, neighFollowers, neighBlockers,
1848 nullptr, nullptr, false, 0, &blockedFully);
1849 //commitManoeuvre(blocked, blockedFully, leaders, neighLeaders, neighLane);
1850 return ret;
1851 } else {
1852 latDist = 0;
1853 ret &= ~LCA_SPEEDGAIN;
1854 }
1855 }
1856 }
1857
1858 double latDistSublane = 0.;
1859 const double halfLaneWidth = myVehicle.getLane()->getWidth() * 0.5;
1860 const double halfVehWidth = getWidth() * 0.5;
1863 && bestLaneOffset == 0
1865 // vehicle is on its final edge, on the correct lane and close to
1866 // its arrival position. Change to the desired lateral position
1870 break;
1872 latDistSublane = -halfLaneWidth + halfVehWidth - myVehicle.getLateralPositionOnLane();
1873 break;
1875 latDistSublane = -myVehicle.getLateralPositionOnLane();
1876 break;
1878 latDistSublane = halfLaneWidth - halfVehWidth - myVehicle.getLateralPositionOnLane();
1879 break;
1880 default:
1881 assert(false);
1882 }
1883#ifdef DEBUG_WANTSCHANGE
1884 if (gDebugFlag2) std::cout << SIMTIME
1885 << " arrivalPosLatProcedure=" << (int)myVehicle.getParameter().arrivalPosLatProcedure
1886 << " arrivalPosLat=" << myVehicle.getParameter().arrivalPosLat << "\n";
1887#endif
1888
1889 } else {
1890
1892 switch (align) {
1894 latDistSublane = -halfLaneWidth + halfVehWidth - getPosLat();
1895 break;
1897 latDistSublane = halfLaneWidth - halfVehWidth - getPosLat();
1898 break;
1901 latDistSublane = -getPosLat();
1902 break;
1904 latDistSublane = latDistNice;
1905 break;
1907 latDistSublane = sublaneSides[sublaneCompact] - rightVehSide;
1908 break;
1910 latDistSublane = myVehicle.getLateralPositionOnLane() - getPosLat();
1911 break;
1913 // sublane alignment should not cause the vehicle to leave the lane
1914 const double hw = myVehicle.getLane()->getWidth() / 2 - NUMERICAL_EPS;
1915 const double offset = MAX2(-hw, MIN2(hw, myVehicle.getVehicleType().getPreferredLateralAlignmentOffset()));
1916 latDistSublane = -getPosLat() + offset;
1917 }
1918 break;
1919 default:
1920 break;
1921 }
1922 }
1923 // only factor in preferred lateral alignment if there is no speedGain motivation or it runs in the same direction
1924 if (fabs(latDist) <= NUMERICAL_EPS * myVehicle.getActionStepLengthSecs() ||
1925 latDistSublane * latDist > 0) {
1926
1927#if defined(DEBUG_WANTSCHANGE) || defined(DEBUG_STATE) || defined(DEBUG_MANEUVER)
1928 if (gDebugFlag2) std::cout << SIMTIME
1930 << " mySpeedGainR=" << mySpeedGainProbabilityRight
1931 << " mySpeedGainL=" << mySpeedGainProbabilityLeft
1932 << " latDist=" << latDist
1933 << " latDistSublane=" << latDistSublane
1934 << " relGainSublane=" << computeSpeedGain(latDistSublane, defaultNextSpeed)
1935 << " maneuverDist=" << maneuverDist
1936 << " myCanChangeFully=" << myCanChangeFully
1937 << " myTurnAlignmentDist=" << myTurnAlignmentDist
1938 << " nextTurn=" << myVehicle.getNextTurn().first << ":" << toString(myVehicle.getNextTurn().second)
1939 << " prevState=" << toString((LaneChangeAction)myPreviousState)
1940 << "\n";
1941#endif
1942
1943 if ((latDistSublane < 0 && mySpeedGainProbabilityRight < mySpeedLossProbThreshold)
1944 || (latDistSublane > 0 && mySpeedGainProbabilityLeft < mySpeedLossProbThreshold)
1945 || computeSpeedGain(latDistSublane, defaultNextSpeed) < -mySublaneParam) {
1946 // do not risk losing speed
1947#if defined(DEBUG_WANTSCHANGE)
1948 if (gDebugFlag2) std::cout << " aborting sublane change to avoid speed loss (mySpeedLossProbThreshold=" << mySpeedLossProbThreshold
1949 << " speedGain=" << computeSpeedGain(latDistSublane, defaultNextSpeed) << ")\n";
1950#endif
1951 latDistSublane = 0;
1952 }
1953 // Ignore preferred lateral alignment if we are in the middle of an unfinished non-alignment maneuver into the opposite direction
1954 if (!myCanChangeFully
1956 && ((getManeuverDist() < 0 && latDistSublane > 0) || (getManeuverDist() > 0 && latDistSublane < 0))) {
1957#if defined(DEBUG_WANTSCHANGE)
1958 if (gDebugFlag2) {
1959 std::cout << " aborting sublane change due to prior maneuver\n";
1960 }
1961#endif
1962 latDistSublane = 0;
1963 }
1964 latDist = latDistSublane * (isOpposite() ? -1 : 1);
1965 // XXX first compute preferred adaptation and then override with speed
1966 // (this way adaptation is still done if changing for speedgain is
1967 // blocked)
1968 if (fabs(latDist) >= NUMERICAL_EPS * myVehicle.getActionStepLengthSecs()) {
1969#ifdef DEBUG_WANTSCHANGE
1970 if (gDebugFlag2) std::cout << SIMTIME
1971 << " adapting to preferred alignment=" << toString(myVehicle.getVehicleType().getPreferredLateralAlignment())
1972 << " latDist=" << latDist
1973 << "\n";
1974#endif
1975 ret |= LCA_SUBLANE;
1976 // include prior motivation when sublane-change is part of finishing an ongoing maneuver in the same direction
1977 if (getPreviousManeuverDist() * latDist > 0) {
1978 int priorReason = (myPreviousState & LCA_CHANGE_REASONS & ~LCA_SUBLANE);
1979 ret |= priorReason;
1980#ifdef DEBUG_WANTSCHANGE
1981 if (gDebugFlag2 && priorReason != 0) std::cout << " including prior reason " << toString((LaneChangeAction)priorReason)
1982 << " prevManeuverDist=" << getPreviousManeuverDist() << "\n";
1983#endif
1984 }
1985 if (!cancelRequest(ret + getLCA(ret, latDist), laneOffset)) {
1986 maneuverDist = latDist;
1987 blocked = checkBlocking(neighLane, latDist, maneuverDist, laneOffset,
1988 leaders, followers, blockers,
1989 neighLeaders, neighFollowers, neighBlockers);
1990 return ret;
1991 } else {
1992 ret &= ~LCA_SUBLANE;
1993 }
1994 } else {
1995 return ret | LCA_SUBLANE | LCA_STAY;
1996 }
1997 }
1998 latDist = 0;
1999
2000
2001 // --------
2002 /*
2003 if (changeToBest && bestLaneOffset == curr.bestLaneOffset && laneOffset != 0
2004 && (right
2005 ? mySpeedGainProbabilityRight > MAX2(0., mySpeedGainProbabilityLeft)
2006 : mySpeedGainProbabilityLeft > MAX2(0., mySpeedGainProbabilityRight))) {
2007 // change towards the correct lane, speedwise it does not hurt
2008 ret |= LCA_STRATEGIC;
2009 if (!cancelRequest(ret, laneOffset)) {
2010 latDist = latLaneDist;
2011 blocked = checkBlocking(neighLane, latDist, laneOffset,
2012 leaders, followers, blockers,
2013 neighLeaders, neighFollowers, neighBlockers);
2014 return ret;
2015 }
2016 }
2017 */
2018#ifdef DEBUG_WANTSCHANGE
2019 if (gDebugFlag2) {
2020 std::cout << STEPS2TIME(currentTime)
2021 << " veh=" << myVehicle.getID()
2022 << " mySpeedGainR=" << mySpeedGainProbabilityRight
2023 << " mySpeedGainL=" << mySpeedGainProbabilityLeft
2024 << " myKeepRight=" << myKeepRightProbability
2025 << "\n";
2026 }
2027#endif
2028 return ret;
2029}
2030
2031
2032int
2034 // if this vehicle is blocking someone in front, we maybe decelerate to let him in
2035 if ((*blocked) != nullptr) {
2036 double gap = (*blocked)->getPositionOnLane() - (*blocked)->getVehicleType().getLength() - myVehicle.getPositionOnLane() - myVehicle.getVehicleType().getMinGap();
2037#ifdef DEBUG_SLOWDOWN
2038 if (gDebugFlag2) {
2039 std::cout << SIMTIME
2040 << " veh=" << myVehicle.getID()
2041 << " blocked=" << Named::getIDSecure(*blocked)
2042 << " gap=" << gap
2043 << "\n";
2044 }
2045#endif
2046 if (gap > POSITION_EPS) {
2047 //const bool blockedWantsUrgentRight = (((*blocked)->getLaneChangeModel().getOwnState() & LCA_RIGHT != 0)
2048 // && ((*blocked)->getLaneChangeModel().getOwnState() & LCA_URGENT != 0));
2049
2051 //|| blockedWantsUrgentRight // VARIANT_10 (helpblockedRight)
2052 ) {
2053 if ((*blocked)->getSpeed() < SUMO_const_haltingSpeed) {
2055 } else {
2056 state |= LCA_AMBACKBLOCKER;
2057 }
2058 addLCSpeedAdvice(getCarFollowModel().followSpeed(
2060 (gap - POSITION_EPS), (*blocked)->getSpeed(),
2061 (*blocked)->getCarFollowModel().getMaxDecel()), false);
2062 //(*blocked) = 0; // VARIANT_14 (furtherBlock)
2063 }
2064 }
2065 }
2066 return state;
2067}
2068
2069
2070bool
2071MSLCM_SL2015::isBidi(const MSLane* lane) const {
2072 if (!MSNet::getInstance()->hasBidiEdges()) {
2073 return false;
2074 }
2075 if (lane == myVehicle.getLane()->getBidiLane()) {
2076 return true;
2077 }
2078 for (const MSLane* cand : myVehicle.getBestLanesContinuation()) {
2079 if (cand != nullptr && cand->getBidiLane() == lane) {
2080 return true;
2081 }
2082 }
2083 return false;
2084}
2085
2086void
2087MSLCM_SL2015::updateExpectedSublaneSpeeds(const MSLeaderDistanceInfo& ahead, int sublaneOffset, int laneIndex) {
2088 const std::vector<MSLane*>& lanes = myVehicle.getLane()->getEdge().getLanes();
2089 const std::vector<MSVehicle::LaneQ>& preb = myVehicle.getBestLanes();
2090 const MSLane* lane = isOpposite() ? myVehicle.getLane()->getParallelOpposite() : lanes[laneIndex];
2091 const MSLane* bidi = myVehicle.getLane()->getBidiLane();
2092 const double vMax = lane->getVehicleMaxSpeed(&myVehicle);
2093 assert(preb.size() == lanes.size() || isOpposite());
2094#ifdef DEBUG_EXPECTED_SLSPEED
2095 if (DEBUG_COND) {
2096 std::cout << SIMTIME << " veh=" << myVehicle.getID() << " updateExpectedSublaneSpeeds opposite=" << isOpposite()
2097 << " sublaneOffset=" << sublaneOffset << " laneIndex=" << laneIndex << " lane=" << lane->getID() << " ahead=" << ahead.toString() << "\n";
2098 }
2099#endif
2100
2101 for (int sublane = 0; sublane < (int)ahead.numSublanes(); ++sublane) {
2102 const int edgeSublane = sublane + sublaneOffset;
2103 if (edgeSublane >= (int)myExpectedSublaneSpeeds.size()) {
2104 // this may happen if a sibling lane is wider than the changer lane
2105 continue;
2106 }
2108 // lane allowed, find potential leaders and compute safe speeds
2109 // XXX anticipate future braking if leader has a lower speed than myVehicle
2110 const MSVehicle* leader = ahead[sublane].first;
2111 const double gap = ahead[sublane].second;
2112 double vSafe;
2113 if (leader == nullptr) {
2114 if (hasBlueLight()) {
2115 // can continue from any lane if necessary
2116 vSafe = vMax;
2117 } else {
2118 const int prebIndex = isOpposite() ? (int)preb.size() - 1 : laneIndex;
2119 const double dist = preb[prebIndex].length - myVehicle.getPositionOnLane();
2120 vSafe = getCarFollowModel().followSpeed(&myVehicle, vMax, dist, 0, 0);
2121 }
2122 } else if (bidi != nullptr && leader->getLane()->getBidiLane() != nullptr && isBidi(leader->getLane())) {
2123 // oncoming
2124 if (gap < (1 + mySpeedGainLookahead * 2) * (vMax + leader->getSpeed())) {
2125 vSafe = 0;
2126 } else {
2127 vSafe = vMax;
2128 }
2129#ifdef DEBUG_EXPECTED_SLSPEED
2130 if (DEBUG_COND) {
2131 std::cout << SIMTIME << " updateExpectedSublaneSpeeds sublane=" << sublane << " leader=" << leader->getID() << " bidi=" << bidi->getID() << " gap=" << gap << " vSafe=" << vSafe << "\n";
2132 }
2133#endif
2134 } else {
2135 if (leader->getAcceleration() > 0.5 * leader->getCarFollowModel().getMaxAccel()) {
2136 // assume that the leader will continue accelerating to its maximum speed
2137 vSafe = leader->getLane()->getVehicleMaxSpeed(leader);
2138 } else {
2140 &myVehicle, vMax, gap, leader->getSpeed(), leader->getCarFollowModel().getMaxDecel());
2141#ifdef DEBUG_EXPECTED_SLSPEED
2142 if (DEBUG_COND) {
2143 std::cout << " updateExpectedSublaneSpeeds edgeSublane=" << edgeSublane << " leader=" << leader->getID() << " gap=" << gap << " vSafe=" << vSafe << "\n";
2144 }
2145#endif
2146 vSafe = forecastAverageSpeed(vSafe, vMax, gap, leader->getSpeed());
2147 }
2148 }
2149 // take pedestrians into account
2150 if (lane->getEdge().getPersons().size() > 0 && lane->hasPedestrians()) {
2152 double foeRight, foeLeft;
2153 ahead.getSublaneBorders(sublane, 0, foeRight, foeLeft);
2154 // get all leaders ahead or overlapping
2155 const PersonDist pedLeader = lane->nextBlocking(myVehicle.getPositionOnLane() - myVehicle.getVehicleType().getLength(), foeRight, foeLeft);
2156 if (pedLeader.first != 0) {
2157 const double pedGap = pedLeader.second - myVehicle.getVehicleType().getMinGap() - myVehicle.getVehicleType().getLength();
2158 // we do not know the walking direction here so we take the pedestrian speed as 0
2159 vSafe = MIN2(getCarFollowModel().stopSpeed(&myVehicle, vMax, pedGap),
2160 forecastAverageSpeed(vSafe, vMax, pedGap, 0));
2161#ifdef DEBUG_EXPECTED_SLSPEED
2162 if (DEBUG_COND) {
2163 std::cout << " updateExpectedSublaneSpeeds edgeSublane=" << edgeSublane << " pedLeader=" << pedLeader.first->getID() << " gap=" << pedGap << " vSafe=" << vSafe << "\n";
2164 }
2165#endif
2166 }
2167 }
2168 // take bidi pedestrians into account
2169 if (bidi != nullptr && bidi->getEdge().getPersons().size() > 0 && bidi->hasPedestrians()) {
2171 double foeRight, foeLeft;
2172 ahead.getSublaneBorders(sublane, 0, foeRight, foeLeft);
2173 const double foeRightBidi = bidi->getWidth() - foeLeft;
2174 const double foeLeftBidi = bidi->getWidth() - foeRight;
2175 // get all leaders ahead or overlapping
2176 const double relativeBackPos = myVehicle.getLane()->getLength() - myVehicle.getPositionOnLane() + myVehicle.getLength();
2177 const double stopTime = ceil(myVehicle.getSpeed() / myVehicle.getCarFollowModel().getMaxDecel());
2178 PersonDist pedLeader = bidi->nextBlocking(relativeBackPos, foeRightBidi, foeLeftBidi, stopTime, true);
2179 if (pedLeader.first != 0) {
2180 const double pedGap = pedLeader.second - myVehicle.getVehicleType().getMinGap() - myVehicle.getVehicleType().getLength();
2181 // we do not know the walking direction here so we take the pedestrian speed as 0
2182 vSafe = MIN2(getCarFollowModel().stopSpeed(&myVehicle, vMax, pedGap),
2183 forecastAverageSpeed(vSafe, vMax, pedGap, 0));
2184#ifdef DEBUG_EXPECTED_SLSPEED
2185 if (DEBUG_COND) {
2186 std::cout << " updateExpectedSublaneSpeeds edgeSublane=" << edgeSublane << " pedLeader=" << pedLeader.first->getID() << " (bidi) gap=" << pedGap << " vSafe=" << vSafe << "\n";
2187 }
2188#endif
2189 }
2190 }
2191 vSafe = MIN2(vMax, vSafe);
2192 // forget old data when on the opposite side
2193 const double memoryFactor = isOpposite() ? 0 : pow(SPEEDGAIN_MEMORY_FACTOR, myVehicle.getActionStepLengthSecs());
2194 myExpectedSublaneSpeeds[edgeSublane] = memoryFactor * myExpectedSublaneSpeeds[edgeSublane] + (1 - memoryFactor) * vSafe;
2195 } else {
2196 // lane forbidden
2197 myExpectedSublaneSpeeds[edgeSublane] = -1;
2198 }
2199 }
2200 // XXX deal with leaders on subsequent lanes based on preb
2201}
2202
2203
2204double
2205MSLCM_SL2015::forecastAverageSpeed(double vSafe, double vMax, double gap, double vLeader) const {
2206 const double deltaV = vMax - vLeader;
2207 if (deltaV > 0 && gap / deltaV < mySpeedGainLookahead && mySpeedGainLookahead > 0) {
2208 // anticipate future braking by computing the average
2209 // speed over the next few seconds
2210 const double foreCastTime = mySpeedGainLookahead * 2;
2211 const double gapClosingTime = MAX2(0.0, gap / deltaV);
2212 const double vSafe2 = (gapClosingTime * vSafe + (foreCastTime - gapClosingTime) * vLeader) / foreCastTime;
2213#ifdef DEBUG_EXPECTED_SLSPEED
2214 if (DEBUG_COND && vSafe2 != vSafe) {
2215 std::cout << " foreCastTime=" << foreCastTime << " gapClosingTime=" << gapClosingTime << " extrapolated vSafe=" << vSafe2 << "\n";
2216 }
2217#endif
2218 vSafe = vSafe2;
2219 }
2220 return vSafe;
2221}
2222
2223
2224double
2225MSLCM_SL2015::computeSpeedGain(double latDistSublane, double defaultNextSpeed) const {
2226 double result = std::numeric_limits<double>::max();
2227 const std::vector<double>& sublaneSides = myVehicle.getLane()->getEdge().getSubLaneSides();
2228 const double vehWidth = getWidth();
2229 const double rightVehSide = myVehicle.getCenterOnEdge() - vehWidth * 0.5 + latDistSublane;
2230 const double leftVehSide = rightVehSide + vehWidth;
2231 for (int i = 0; i < (int)sublaneSides.size(); ++i) {
2232 const double leftSide = i + 1 < (int)sublaneSides.size() ? sublaneSides[i + 1] : MAX2(myVehicle.getLane()->getEdge().getWidth(), sublaneSides[i] + POSITION_EPS);
2233 if (overlap(rightVehSide, leftVehSide, sublaneSides[i], leftSide)) {
2234 result = MIN2(result, myExpectedSublaneSpeeds[i]);
2235 }
2236 //std::cout << " i=" << i << " rightVehSide=" << rightVehSide << " leftVehSide=" << leftVehSide << " sublaneR=" << sublaneSides[i] << " sublaneL=" << leftSide << " overlap=" << overlap(rightVehSide, leftVehSide, sublaneSides[i], leftSide) << " speed=" << myExpectedSublaneSpeeds[i] << " result=" << result << "\n";
2237 }
2238 return result - defaultNextSpeed;
2239}
2240
2241
2244 int iMax = -1;
2245 double maxLength = -1;
2246 for (int i = 0; i < ldi.numSublanes(); ++i) {
2247 const MSVehicle* veh = ldi[i].first;
2248 if (veh) {
2249 const double length = veh->getVehicleType().getLength();
2250 if (length > maxLength && tieBrakeLeader(veh)) {
2251 maxLength = length;
2252 iMax = i;
2253 }
2254 }
2255 }
2256 return iMax >= 0 ? ldi[iMax] : std::make_pair(nullptr, -1);
2257}
2258
2259
2260bool
2262 // tie braker if the leader is at the same lane position
2263 return veh != nullptr && (veh->getPositionOnLane() != myVehicle.getPositionOnLane()
2264 || veh->getSpeed() < myVehicle.getSpeed()
2265 || &veh->getLane()->getEdge() != &myVehicle.getLane()->getEdge()
2266 || veh->getLane()->getIndex() > myVehicle.getLane()->getIndex());
2267}
2268
2269
2272 int iMax = 0;
2273 double minSpeed = std::numeric_limits<double>::max();
2274 for (int i = 0; i < ldi.numSublanes(); ++i) {
2275 if (ldi[i].first != 0) {
2276 const double speed = ldi[i].first->getSpeed();
2277 if (speed < minSpeed) {
2278 minSpeed = speed;
2279 iMax = i;
2280 }
2281 }
2282 }
2283 return ldi[iMax];
2284}
2285
2286
2287int
2288MSLCM_SL2015::checkBlocking(const MSLane& neighLane, double& latDist, double maneuverDist, int laneOffset,
2289 const MSLeaderDistanceInfo& leaders,
2290 const MSLeaderDistanceInfo& followers,
2291 const MSLeaderDistanceInfo& /*blockers */,
2292 const MSLeaderDistanceInfo& neighLeaders,
2293 const MSLeaderDistanceInfo& neighFollowers,
2294 const MSLeaderDistanceInfo& /* neighBlockers */,
2295 std::vector<CLeaderDist>* collectLeadBlockers,
2296 std::vector<CLeaderDist>* collectFollowBlockers,
2297 bool keepLatGapManeuver,
2298 double gapFactor,
2299 int* retBlockedFully) {
2300 // truncate latDist according to maxSpeedLat
2301 const double maxDist = SPEED2DIST(getMaxSpeedLat2());
2302 latDist = MAX2(MIN2(latDist, maxDist), -maxDist);
2304 return 0;
2305 }
2306
2307 const double neighRight = getNeighRight(neighLane);
2308 if (!myCFRelatedReady) {
2309 updateCFRelated(followers, myVehicle.getLane()->getRightSideOnEdge(), false);
2311 if (laneOffset != 0) {
2312 updateCFRelated(neighFollowers, neighRight, false);
2313 updateCFRelated(neighLeaders, neighRight, true);
2314 }
2315 myCFRelatedReady = true;
2316 }
2317
2318 // reduce latDist to avoid blockage with overlapping vehicles (no minGapLat constraints)
2319 const double center = myVehicle.getCenterOnEdge();
2320 updateGaps(leaders, myVehicle.getLane()->getRightSideOnEdge(), center, gapFactor, mySafeLatDistRight, mySafeLatDistLeft, false, 0, latDist, collectLeadBlockers);
2321 updateGaps(followers, myVehicle.getLane()->getRightSideOnEdge(), center, gapFactor, mySafeLatDistRight, mySafeLatDistLeft, false, 0, latDist, collectFollowBlockers);
2322 if (laneOffset != 0) {
2323 updateGaps(neighLeaders, neighRight, center, gapFactor, mySafeLatDistRight, mySafeLatDistLeft, false, 0, latDist, collectLeadBlockers);
2324 updateGaps(neighFollowers, neighRight, center, gapFactor, mySafeLatDistRight, mySafeLatDistLeft, false, 0, latDist, collectFollowBlockers);
2325 }
2326#ifdef DEBUG_BLOCKING
2327 if (gDebugFlag2) {
2328 std::cout << " checkBlocking latDist=" << latDist << " mySafeLatDistRight=" << mySafeLatDistRight << " mySafeLatDistLeft=" << mySafeLatDistLeft << "\n";
2329 }
2330#endif
2331 // if we can move at least a little bit in the desired direction, do so (rather than block)
2332 const bool forcedTraCIChange = (myVehicle.hasInfluencer()
2335 if (latDist < 0) {
2336 if (mySafeLatDistRight <= NUMERICAL_EPS) {
2338 } else if (!forcedTraCIChange) {
2339 latDist = MAX2(latDist, -mySafeLatDistRight);
2340 }
2341 } else {
2342 if (mySafeLatDistLeft <= NUMERICAL_EPS) {
2344 } else if (!forcedTraCIChange) {
2345 latDist = MIN2(latDist, mySafeLatDistLeft);
2346 }
2347 }
2348
2349 myCanChangeFully = (maneuverDist == 0 || latDist == maneuverDist);
2350#ifdef DEBUG_BLOCKING
2351 if (gDebugFlag2) {
2352 std::cout << " checkBlocking fully=" << myCanChangeFully << " latDist=" << latDist << " maneuverDist=" << maneuverDist << "\n";
2353 }
2354#endif
2355 // destination sublanes must be safe
2356 // intermediate sublanes must not be blocked by overlapping vehicles
2357
2358 // XXX avoid checking the same leader multiple times
2359 // XXX ensure that only changes within the same lane are undertaken if laneOffset = 0
2360
2361 int blocked = 0;
2362 blocked |= checkBlockingVehicles(&myVehicle, leaders, laneOffset, latDist, myVehicle.getLane()->getRightSideOnEdge(), true,
2363 mySafeLatDistRight, mySafeLatDistLeft, collectLeadBlockers);
2364 blocked |= checkBlockingVehicles(&myVehicle, followers, laneOffset, latDist, myVehicle.getLane()->getRightSideOnEdge(), false,
2365 mySafeLatDistRight, mySafeLatDistLeft, collectFollowBlockers);
2366 if (laneOffset != 0) {
2367 blocked |= checkBlockingVehicles(&myVehicle, neighLeaders, laneOffset, latDist, neighRight, true,
2368 mySafeLatDistRight, mySafeLatDistLeft, collectLeadBlockers);
2369 blocked |= checkBlockingVehicles(&myVehicle, neighFollowers, laneOffset, latDist, neighRight, false,
2370 mySafeLatDistRight, mySafeLatDistLeft, collectFollowBlockers);
2371 }
2372
2373 int blockedFully = 0;
2374 blockedFully |= checkBlockingVehicles(&myVehicle, leaders, laneOffset, maneuverDist, myVehicle.getLane()->getRightSideOnEdge(), true,
2375 mySafeLatDistRight, mySafeLatDistLeft, collectLeadBlockers);
2376 blockedFully |= checkBlockingVehicles(&myVehicle, followers, laneOffset, maneuverDist, myVehicle.getLane()->getRightSideOnEdge(), false,
2377 mySafeLatDistRight, mySafeLatDistLeft, collectFollowBlockers);
2378 if (laneOffset != 0) {
2379 blockedFully |= checkBlockingVehicles(&myVehicle, neighLeaders, laneOffset, maneuverDist, neighRight, true,
2380 mySafeLatDistRight, mySafeLatDistLeft, collectLeadBlockers);
2381 blockedFully |= checkBlockingVehicles(&myVehicle, neighFollowers, laneOffset, maneuverDist, neighRight, false,
2382 mySafeLatDistRight, mySafeLatDistLeft, collectFollowBlockers);
2383 }
2384 if (retBlockedFully != nullptr) {
2385 *retBlockedFully = blockedFully;
2386 }
2387 if (blocked == 0 && !myCanChangeFully && myPushy == 0 && !keepLatGapManeuver) {
2388 // aggressive drivers immediately start moving towards potential
2389 // blockers and only check that the start of their maneuver (latDist) is safe. In
2390 // contrast, cautious drivers need to check latDist and origLatDist to
2391 // ensure that the maneuver can be finished without encroaching on other vehicles.
2392 blocked |= blockedFully;
2393 } else {
2394 // XXX: in case of action step length > simulation step length, pushing may lead to collisions,
2395 // because maneuver is continued until maneuverDist is reached (perhaps set maneuverDist=latDist)
2396 }
2397 if (collectFollowBlockers != nullptr && collectLeadBlockers != nullptr) {
2398 // prevent vehicles from being classified as leader and follower simultaneously
2399 for (std::vector<CLeaderDist>::const_iterator it2 = collectLeadBlockers->begin(); it2 != collectLeadBlockers->end(); ++it2) {
2400 for (std::vector<CLeaderDist>::iterator it = collectFollowBlockers->begin(); it != collectFollowBlockers->end();) {
2401 if ((*it2).first == (*it).first) {
2402#ifdef DEBUG_BLOCKING
2403 if (gDebugFlag2) {
2404 std::cout << " removed follower " << (*it).first->getID() << " because it is already a leader\n";
2405 }
2406#endif
2407 it = collectFollowBlockers->erase(it);
2408 } else {
2409 ++it;
2410 }
2411 }
2412 }
2413 }
2414 return blocked;
2415}
2416
2417
2418int
2420 const MSVehicle* ego, const MSLeaderDistanceInfo& vehicles,
2421 int laneOffset, double latDist, double foeOffset, bool leaders,
2422 double& safeLatGapRight, double& safeLatGapLeft,
2423 std::vector<CLeaderDist>* collectBlockers) const {
2424 // determine borders where safety/no-overlap conditions must hold
2425 const LaneChangeAction blockType = (laneOffset == 0
2427 : (laneOffset > 0
2430 const double vehWidth = getWidth();
2431 const double rightVehSide = ego->getRightSideOnEdge();
2432 const double leftVehSide = rightVehSide + vehWidth;
2433 const double rightVehSideDest = rightVehSide + latDist;
2434 const double leftVehSideDest = leftVehSide + latDist;
2435 const double rightNoOverlap = MIN2(rightVehSideDest, rightVehSide);
2436 const double leftNoOverlap = MAX2(leftVehSideDest, leftVehSide);
2437#ifdef DEBUG_BLOCKING
2438 if (gDebugFlag2) {
2439 std::cout << " checkBlockingVehicles"
2440 << " laneOffset=" << laneOffset
2441 << " latDist=" << latDist
2442 << " foeOffset=" << foeOffset
2443 << " vehRight=" << rightVehSide
2444 << " vehLeft=" << leftVehSide
2445 << " rightNoOverlap=" << rightNoOverlap
2446 << " leftNoOverlap=" << leftNoOverlap
2447 << " destRight=" << rightVehSideDest
2448 << " destLeft=" << leftVehSideDest
2449 << " leaders=" << leaders
2450 << " blockType=" << toString((LaneChangeAction) blockType)
2451 << "\n";
2452 }
2453#endif
2454 int result = 0;
2455 for (int i = 0; i < vehicles.numSublanes(); ++i) {
2456 CLeaderDist vehDist = vehicles[i];
2457 if (vehDist.first != 0 && myCFRelated.count(vehDist.first) == 0) {
2458 const MSVehicle* leader = vehDist.first;
2459 const MSVehicle* follower = ego;
2460 if (!leaders) {
2461 std::swap(leader, follower);
2462 }
2463 // only check the current stripe occupied by foe (transform into edge-coordinates)
2464 double foeRight, foeLeft;
2465 vehicles.getSublaneBorders(i, foeOffset, foeRight, foeLeft);
2466 const bool overlapBefore = overlap(rightVehSide, leftVehSide, foeRight, foeLeft);
2467 const bool overlapDest = overlap(rightVehSideDest, leftVehSideDest, foeRight, foeLeft);
2468 const bool overlapAny = overlap(rightNoOverlap, leftNoOverlap, foeRight, foeLeft);
2469#ifdef DEBUG_BLOCKING
2470 if (gDebugFlag2) {
2471 std::cout << " foe=" << vehDist.first->getID()
2472 << " gap=" << vehDist.second
2473 << " secGap=" << follower->getCarFollowModel().getSecureGap(follower, leader, follower->getSpeed(), leader->getSpeed(), leader->getCarFollowModel().getMaxDecel())
2474 << " foeRight=" << foeRight
2475 << " foeLeft=" << foeLeft
2476 << " overlapBefore=" << overlapBefore
2477 << " overlap=" << overlapAny
2478 << " overlapDest=" << overlapDest
2479 << "\n";
2480 }
2481#endif
2482 if (overlapAny) {
2483 if (vehDist.second < 0) {
2484 if (overlapBefore && !overlapDest && !outsideEdge()) {
2485#ifdef DEBUG_BLOCKING
2486 if (gDebugFlag2) {
2487 std::cout << " ignoring current overlap to come clear\n";
2488 }
2489#endif
2490 } else {
2491#ifdef DEBUG_BLOCKING
2492 if (gDebugFlag2) {
2493 std::cout << " overlap (" << toString((LaneChangeAction)blockType) << ")\n";
2494 }
2495#endif
2496 result |= (blockType | LCA_OVERLAPPING);
2497 if (collectBlockers == nullptr) {
2498 return result;
2499 } else {
2500 collectBlockers->push_back(vehDist);
2501 }
2502 }
2503 } else if (overlapDest || !myCanChangeFully) {
2504 // Estimate state after actionstep (follower may be accelerating!)
2505 // A comparison between secure gap depending on the expected speeds and the extrapolated gap
2506 // determines whether the s is blocking the lane change.
2507 // (Note that the longitudinal state update has already taken effect before LC dynamics (thus "-TS" below), would be affected by #3665)
2508
2509 // Use conservative estimate for time until next action step
2510 // (XXX: how can the ego know the foe's action step length?)
2511 const double timeTillAction = MAX2(follower->getActionStepLengthSecs(), leader->getActionStepLengthSecs()) - TS;
2512 // Ignore decel for follower
2513 const double followerAccel = MAX2(0., follower->getAcceleration());
2514 const double leaderAccel = leader->getAcceleration();
2515 // Expected gap after next actionsteps
2516 const double expectedGap = MSCFModel::gapExtrapolation(timeTillAction, vehDist.second, leader->getSpeed(), follower->getSpeed(), leaderAccel, followerAccel, std::numeric_limits<double>::max(), std::numeric_limits<double>::max());
2517
2518 // Determine expected speeds and corresponding secure gap at the extrapolated timepoint
2519 const double followerExpectedSpeed = follower->getSpeed() + timeTillAction * followerAccel;
2520 const double leaderExpectedSpeed = MAX2(0., leader->getSpeed() + timeTillAction * leaderAccel);
2521 const double expectedSecureGap = follower->getCarFollowModel().getSecureGap(follower, leader, followerExpectedSpeed, leaderExpectedSpeed, leader->getCarFollowModel().getMaxDecel());
2522
2523#if defined(DEBUG_ACTIONSTEPS) && defined(DEBUG_BLOCKING)
2524 if (gDebugFlag2) {
2525 std::cout << " timeTillAction=" << timeTillAction
2526 << " followerAccel=" << followerAccel
2527 << " followerExpectedSpeed=" << followerExpectedSpeed
2528 << " leaderAccel=" << leaderAccel
2529 << " leaderExpectedSpeed=" << leaderExpectedSpeed
2530 << "\n gap=" << vehDist.second
2531 << " gapChange=" << (expectedGap - vehDist.second)
2532 << " expectedGap=" << expectedGap
2533 << " expectedSecureGap=" << expectedSecureGap
2534 << " safeLatGapLeft=" << safeLatGapLeft
2535 << " safeLatGapRight=" << safeLatGapRight
2536 << std::endl;
2537 }
2538#endif
2539
2540 // @note for euler-update, a different value for secureGap2 may be obtained when applying safetyFactor to followerDecel rather than secureGap
2541 const double secureGap2 = expectedSecureGap * getSafetyFactor();
2542 if (expectedGap < secureGap2) {
2543 // Foe is a blocker. Update lateral safe gaps accordingly.
2544 if (foeRight > leftVehSide) {
2545 safeLatGapLeft = MIN2(safeLatGapLeft, foeRight - leftVehSide);
2546 } else if (foeLeft < rightVehSide) {
2547 safeLatGapRight = MIN2(safeLatGapRight, rightVehSide - foeLeft);
2548 }
2549
2550#ifdef DEBUG_BLOCKING
2551 if (gDebugFlag2) {
2552 std::cout << " blocked by " << vehDist.first->getID() << " gap=" << vehDist.second << " expectedGap=" << expectedGap
2553 << " expectedSecureGap=" << expectedSecureGap << " secGap2=" << secureGap2 << " safetyFactor=" << getSafetyFactor()
2554 << " safeLatGapLeft=" << safeLatGapLeft << " safeLatGapRight=" << safeLatGapRight
2555 << "\n";
2556 }
2557#endif
2558 result |= blockType;
2559 if (collectBlockers == nullptr) {
2560 return result;
2561 }
2562#ifdef DEBUG_BLOCKING
2563 } else if (gDebugFlag2 && expectedGap < expectedSecureGap) {
2564 std::cout << " ignore blocker " << vehDist.first->getID() << " gap=" << vehDist.second << " expectedGap=" << expectedGap
2565 << " expectedSecureGap=" << expectedSecureGap << " secGap2=" << secureGap2 << " safetyFactor=" << getSafetyFactor() << "\n";
2566#endif
2567 }
2568 if (collectBlockers != nullptr) {
2569 // collect non-blocking followers as well to make sure
2570 // they remain non-blocking
2571 collectBlockers->push_back(vehDist);
2572 }
2573 }
2574 }
2575 }
2576 }
2577 return result;
2578
2579}
2580
2581
2582void
2583MSLCM_SL2015::updateCFRelated(const MSLeaderDistanceInfo& vehicles, double foeOffset, bool leaders) {
2584 // to ensure that we do not ignore the wrong vehicles due to numerical
2585 // instability we slightly reduce the width
2586 const double vehWidth = myVehicle.getVehicleType().getWidth() - NUMERICAL_EPS;
2587 const double rightVehSide = myVehicle.getCenterOnEdge() - 0.5 * vehWidth;
2588 const double leftVehSide = rightVehSide + vehWidth;
2589#ifdef DEBUG_BLOCKING
2590 if (gDebugFlag2) {
2591 std::cout << " updateCFRelated foeOffset=" << foeOffset << " vehicles=" << vehicles.toString() << "\n";
2592 }
2593#endif
2594 for (int i = 0; i < vehicles.numSublanes(); ++i) {
2595 CLeaderDist vehDist = vehicles[i];
2596 if (vehDist.first != 0 && (myCFRelated.count(vehDist.first) == 0 || vehDist.second < 0)) {
2597 double foeRight, foeLeft;
2598 vehicles.getSublaneBorders(i, foeOffset, foeRight, foeLeft);
2599#ifdef DEBUG_BLOCKING
2600 if (gDebugFlag2) {
2601 std::cout << " foe=" << vehDist.first->getID() << " gap=" << vehDist.second
2602 << " sublane=" << i
2603 << " foeOffset=" << foeOffset
2604 << " egoR=" << rightVehSide << " egoL=" << leftVehSide
2605 << " iR=" << foeRight << " iL=" << foeLeft
2606 << " egoV=" << myVehicle.getSpeed() << " foeV=" << vehDist.first->getSpeed()
2607 << " egoE=" << myVehicle.getLane()->getEdge().getID() << " foeE=" << vehDist.first->getLane()->getEdge().getID()
2608 << "\n";
2609 }
2610#endif
2611 if (overlap(rightVehSide, leftVehSide, foeRight, foeLeft) && !outsideEdge() && (vehDist.second >= 0
2612 // avoid deadlock due to #3729
2613 || (!leaders
2616 && vehDist.first->getSpeed() < SUMO_const_haltingSpeed
2617 && -vehDist.second < vehDist.first->getVehicleType().getMinGap()
2618 && &(myVehicle.getLane()->getEdge()) != &(vehDist.first->getLane()->getEdge()))
2619 )) {
2620#ifdef DEBUG_BLOCKING
2621 if (gDebugFlag2) {
2622 std::cout << " ignoring cfrelated foe=" << vehDist.first->getID() << "\n";
2623 }
2624#endif
2625 myCFRelated.insert(vehDist.first);
2626 } else {
2627 const int erased = (int)myCFRelated.erase(vehDist.first);
2628#ifdef DEBUG_BLOCKING
2629 if (gDebugFlag2 && erased > 0) {
2630 std::cout << " restoring cfrelated foe=" << vehDist.first->getID() << "\n";
2631 }
2632#else
2633 UNUSED_PARAMETER(erased);
2634#endif
2635 }
2636 }
2637 }
2638}
2639
2640
2641bool
2642MSLCM_SL2015::overlap(double right, double left, double right2, double left2) {
2643 assert(right <= left);
2644 assert(right2 <= left2);
2645 return left2 >= right + NUMERICAL_EPS && left >= right2 + NUMERICAL_EPS;
2646}
2647
2648
2649int
2650MSLCM_SL2015::lowest_bit(int changeReason) {
2651 if ((changeReason & LCA_STRATEGIC) != 0) {
2652 return LCA_STRATEGIC;
2653 }
2654 if ((changeReason & LCA_COOPERATIVE) != 0) {
2655 return LCA_COOPERATIVE;
2656 }
2657 if ((changeReason & LCA_SPEEDGAIN) != 0) {
2658 return LCA_SPEEDGAIN;
2659 }
2660 if ((changeReason & LCA_KEEPRIGHT) != 0) {
2661 return LCA_KEEPRIGHT;
2662 }
2663 if ((changeReason & LCA_TRACI) != 0) {
2664 return LCA_TRACI;
2665 }
2666 return changeReason;
2667}
2668
2669
2672 // ignore dummy decisions (returned if mayChange() failes)
2673 if (sd1.state == 0) {
2674 return sd2;
2675 } else if (sd2.state == 0) {
2676 return sd1;
2677 }
2678 // LCA_SUBLANE is special because LCA_STAY|LCA_SUBLANE may override another LCA_SUBLANE command
2679 const bool want1 = ((sd1.state & LCA_WANTS_LANECHANGE) != 0) || ((sd1.state & LCA_SUBLANE) != 0 && (sd1.state & LCA_STAY) != 0);
2680 const bool want2 = ((sd2.state & LCA_WANTS_LANECHANGE) != 0) || ((sd2.state & LCA_SUBLANE) != 0 && (sd2.state & LCA_STAY) != 0);
2681 const bool can1 = ((sd1.state & LCA_BLOCKED) == 0);
2682 const bool can2 = ((sd2.state & LCA_BLOCKED) == 0);
2683 int reason1 = lowest_bit(sd1.state & LCA_CHANGE_REASONS);
2684 int reason2 = lowest_bit(sd2.state & LCA_CHANGE_REASONS);
2685#ifdef DEBUG_WANTSCHANGE
2686 if (DEBUG_COND) std::cout << SIMTIME
2687 << " veh=" << myVehicle.getID()
2688 << " state1=" << toString((LaneChangeAction)sd1.state)
2689 << " want1=" << (sd1.state & LCA_WANTS_LANECHANGE)
2690 << " dist1=" << sd1.latDist
2691 << " dir1=" << sd1.dir
2692 << " state2=" << toString((LaneChangeAction)sd2.state)
2693 << " want2=" << (sd2.state & LCA_WANTS_LANECHANGE)
2694 << " dist2=" << sd2.latDist
2695 << " dir2=" << sd2.dir
2696 << " reason1=" << toString((LaneChangeAction)reason1)
2697 << " reason2=" << toString((LaneChangeAction)reason2)
2698 << "\n";
2699#endif
2700 if (want1) {
2701 if (want2) {
2702 if ((sd1.state & LCA_TRACI) != 0 && (sd2.state & LCA_TRACI) != 0) {
2703 // influencer may assign LCA_WANTS_LANECHANGE despite latDist = 0
2704 if (sd1.latDist == 0 && sd2.latDist != 0) {
2705 return sd2;
2706 } else if (sd2.latDist == 0 && sd1.latDist != 0) {
2707 return sd1;
2708 }
2709 }
2710 // decide whether right or left has higher priority (lower value in enum LaneChangeAction)
2711 if (reason1 < reason2) {
2712 //if (DEBUG_COND) std::cout << " " << (sd1.state & LCA_CHANGE_REASONS) << " < " << (sd2.state & LCA_CHANGE_REASONS) << "\n";
2713 return (!can1 && can2 && sd1.sameDirection(sd2)) ? sd2 : sd1;
2714 //return sd1;
2715 } else if (reason1 > reason2) {
2716 //if (DEBUG_COND) std::cout << " " << (sd1.state & LCA_CHANGE_REASONS) << " > " << (sd2.state & LCA_CHANGE_REASONS) << "\n";
2717 return (!can2 && can1 && sd1.sameDirection(sd2)) ? sd1 : sd2;
2718 //return sd2;
2719 } else {
2720 // same priority.
2721 if ((sd1.state & LCA_SUBLANE) != 0) {
2722 // special treatment: prefer action with dir != 0
2723 if (sd1.dir == 0) {
2724 return sd2;
2725 } else if (sd2.dir == 0) {
2726 return sd1;
2727 } else {
2728 // prefer action that knows more about the desired direction
2729 // @note when deciding between right and left, right is always given as sd1
2730 assert(sd1.dir == -1);
2731 assert(sd2.dir == 1);
2732 if (sd1.latDist <= 0) {
2733 return sd1;
2734 } else if (sd2.latDist >= 0) {
2735 return sd2;
2736 }
2737 // when in doubt, prefer moving to the right
2738 return sd1.latDist <= sd2.latDist ? sd1 : sd2;
2739 }
2740 } else {
2741 if (can1) {
2742 if (can2) {
2743 return fabs(sd1.latDist) > fabs(sd2.latDist) ? sd1 : sd2;
2744 } else {
2745 return sd1;
2746 }
2747 } else {
2748 return sd2;
2749 }
2750 }
2751 }
2752 } else {
2753 return sd1;
2754 }
2755 } else {
2756 return sd2;
2757 }
2758
2759}
2760
2761
2763MSLCM_SL2015::getLCA(int state, double latDist) {
2764 return ((latDist == 0 || (state & LCA_CHANGE_REASONS) == 0)
2765 ? LCA_NONE : (latDist < 0 ? LCA_RIGHT : LCA_LEFT));
2766}
2767
2768
2769int
2771 const MSLane& neighLane,
2772 int laneOffset,
2773 const MSLeaderDistanceInfo& leaders,
2774 const MSLeaderDistanceInfo& neighLeaders,
2775 const MSVehicle::LaneQ& curr,
2776 const MSVehicle::LaneQ& neigh,
2777 const MSVehicle::LaneQ& best,
2778 int bestLaneOffset,
2779 bool changeToBest,
2780 double currentDist,
2781 double neighDist,
2782 double laDist,
2783 double roundaboutBonus,
2784 double latLaneDist,
2785 bool checkOpposite,
2786 double& latDist
2787 ) {
2788 const bool right = (laneOffset == -1);
2789 const bool left = (laneOffset == 1);
2790
2791 const double forwardPos = getForwardPos();
2792 myLeftSpace = currentDist - forwardPos;
2793 const double usableDist = (currentDist - forwardPos - best.occupation * JAM_FACTOR);
2794 //- (best.lane->getVehicleNumber() * neighSpeed)); // VARIANT 9 jfSpeed
2795 const double maxJam = MAX2(neigh.occupation, curr.occupation);
2796 const double neighLeftPlace = MAX2(0., neighDist - forwardPos - maxJam);
2797 // save the left space
2798
2799#ifdef DEBUG_STRATEGIC_CHANGE
2800 if (gDebugFlag2) {
2801 std::cout << SIMTIME
2802 << " veh=" << myVehicle.getID()
2803 << " forwardPos=" << forwardPos
2804 << " laSpeed=" << myLookAheadSpeed
2805 << " laDist=" << laDist
2806 << " currentDist=" << currentDist
2807 << " usableDist=" << usableDist
2808 << " bestLaneOffset=" << bestLaneOffset
2809 << " best.length=" << best.length
2810 << " maxJam=" << maxJam
2811 << " neighLeftPlace=" << neighLeftPlace
2812 << " myLeftSpace=" << myLeftSpace
2813 << "\n";
2814 }
2815#endif
2816
2817 if (laneOffset != 0 && changeToBest && bestLaneOffset == curr.bestLaneOffset
2818 && currentDistDisallows(usableDist, bestLaneOffset, laDist)) {
2820 latDist = latLaneDist;
2821 ret |= LCA_STRATEGIC | LCA_URGENT;
2822 } else {
2823 // VARIANT_20 (noOvertakeRight)
2824 if (left && avoidOvertakeRight() && neighLeaders.hasVehicles()) {
2825 // check for slower leader on the left. we should not overtake but
2826 // rather move left ourselves (unless congested)
2827 // XXX only adapt as much as possible to get a lateral gap
2828 CLeaderDist cld = getSlowest(neighLeaders);
2829 const MSVehicle* nv = cld.first;
2830 if (nv->getSpeed() < myVehicle.getSpeed()) {
2831 const double vSafe = getCarFollowModel().followSpeed(
2832 &myVehicle, myVehicle.getSpeed(), cld.second, nv->getSpeed(), nv->getCarFollowModel().getMaxDecel());
2833 addLCSpeedAdvice(vSafe);
2834 if (vSafe < myVehicle.getSpeed()) {
2836 }
2837#ifdef DEBUG_STRATEGIC_CHANGE
2838 if (gDebugFlag2) {
2839 std::cout << SIMTIME
2840 << " avoid overtaking on the right nv=" << nv->getID()
2841 << " nvSpeed=" << nv->getSpeed()
2842 << " mySpeedGainProbabilityR=" << mySpeedGainProbabilityRight
2843 << " plannedSpeed=" << myVehicle.getSpeed() + ACCEL2SPEED(myLCAccelerationAdvices.back().first)
2844 << "\n";
2845 }
2846#endif
2847 }
2848 }
2849
2850 // handling reaction to stopped for opposite direction driving NYI
2851 const bool noOpposites = &myVehicle.getLane()->getEdge() == &neighLane.getEdge();
2852 if (laneOffset != 0 && myStrategicParam >= 0 && noOpposites && mustOvertakeStopped(neighLane, leaders, neighLeaders, forwardPos, neighDist, right, latLaneDist, currentDist, latDist)) {
2853 if (latDist == 0) {
2854 ret |= LCA_STAY | LCA_STRATEGIC;
2855 } else {
2856 ret |= LCA_STRATEGIC | LCA_URGENT;
2857 }
2858
2859 } else if (!changeToBest && (currentDistDisallows(neighLeftPlace, abs(bestLaneOffset) + 2, laDist))) {
2860 // the opposite lane-changing direction should be done than the one examined herein
2861 // we'll check whether we assume we could change anyhow and get back in time...
2862 //
2863 // this rule prevents the vehicle from moving in opposite direction of the best lane
2864 // unless the way till the end where the vehicle has to be on the best lane
2865 // is long enough
2866#ifdef DEBUG_STRATEGIC_CHANGE
2867 if (gDebugFlag2) {
2868 std::cout << " veh=" << myVehicle.getID() << " could not change back and forth in time (1) neighLeftPlace=" << neighLeftPlace << "\n";
2869 }
2870#endif
2871 ret |= LCA_STAY | LCA_STRATEGIC;
2872 } else if (
2873 laneOffset != 0
2874 && bestLaneOffset == 0
2875 && !leaders.hasStoppedVehicle()
2876 && neigh.bestContinuations.back()->getLinkCont().size() != 0
2877 && roundaboutBonus == 0
2878 && !checkOpposite
2879 && neighDist < TURN_LANE_DIST
2880 && myStrategicParam >= 0) {
2881 // VARIANT_21 (stayOnBest)
2882 // we do not want to leave the best lane for a lane which leads elsewhere
2883 // unless our leader is stopped or we are approaching a roundabout
2884#ifdef DEBUG_STRATEGIC_CHANGE
2885 if (gDebugFlag2) {
2886 std::cout << " veh=" << myVehicle.getID() << " does not want to leave the bestLane (neighDist=" << neighDist << ")\n";
2887 }
2888#endif
2889 ret |= LCA_STAY | LCA_STRATEGIC;
2890 } else if (right
2891 && bestLaneOffset == 0
2892 && myVehicle.getLane()->getSpeedLimit() > 80. / 3.6
2894 ) {
2895 // let's also regard the case where the vehicle is driving on a highway...
2896 // in this case, we do not want to get to the dead-end of an on-ramp
2897#ifdef DEBUG_STRATEGIC_CHANGE
2898 if (gDebugFlag2) {
2899 std::cout << " veh=" << myVehicle.getID() << " does not want to get stranded on the on-ramp of a highway\n";
2900 }
2901#endif
2902 ret |= LCA_STAY | LCA_STRATEGIC;
2903 }
2904 }
2905 if ((ret & LCA_URGENT) == 0 && getShadowLane() != nullptr &&
2906 // ignore overlap if it goes in the correct direction
2907 bestLaneOffset * myVehicle.getLateralPositionOnLane() <= 0) {
2908 // no decision or decision to stay
2909 // make sure to stay within lane bounds in case the shadow lane ends
2910 //const double requiredDist = MAX2(2 * myVehicle.getLateralOverlap(), getSublaneWidth()) / SUMO_const_laneWidth * laDist;
2911 const double requiredDist = 2 * myVehicle.getLateralOverlap() / SUMO_const_laneWidth * laDist;
2912 double currentShadowDist = -myVehicle.getPositionOnLane();
2913 MSLane* shadowPrev = nullptr;
2914 for (std::vector<MSLane*>::const_iterator it = curr.bestContinuations.begin(); it != curr.bestContinuations.end(); ++it) {
2915 if (*it == nullptr) {
2916 continue;
2917 }
2918 MSLane* shadow = getShadowLane(*it);
2919 if (shadow == nullptr || currentShadowDist >= requiredDist) {
2920 break;
2921 }
2922 if (shadowPrev != nullptr) {
2923 currentShadowDist += shadowPrev->getEdge().getInternalFollowingLengthTo(&shadow->getEdge(), myVehicle.getVClass());
2924 }
2925 currentShadowDist += shadow->getLength();
2926 shadowPrev = shadow;
2927#ifdef DEBUG_STRATEGIC_CHANGE
2928 if (gDebugFlag2) {
2929 std::cout << " shadow=" << shadow->getID() << " currentShadowDist=" << currentShadowDist << "\n";
2930 }
2931#endif
2932 }
2933#ifdef DEBUG_STRATEGIC_CHANGE
2934 if (gDebugFlag2) {
2935 std::cout << " veh=" << myVehicle.getID() << " currentShadowDist=" << currentShadowDist << " requiredDist=" << requiredDist << " overlap=" << myVehicle.getLateralOverlap() << "\n";
2936 }
2937#endif
2938 if (currentShadowDist < requiredDist && currentShadowDist < usableDist) {
2939 myLeftSpace = currentShadowDist;
2941#ifdef DEBUG_STRATEGIC_CHANGE
2942 if (gDebugFlag2) {
2943 std::cout << " must change for shadowLane end latDist=" << latDist << " myLeftSpace=" << myLeftSpace << "\n";
2944 }
2945#endif
2946 ret |= LCA_STRATEGIC | LCA_URGENT | LCA_STAY ;
2947 }
2948 }
2949
2950 // check for overriding TraCI requests
2951#if defined(DEBUG_STRATEGIC_CHANGE) || defined(DEBUG_TRACI)
2952 if (gDebugFlag2) {
2953 std::cout << SIMTIME << " veh=" << myVehicle.getID() << " ret=" << ret;
2954 }
2955#endif
2956 // store state before canceling
2957 getCanceledState(laneOffset) |= ret;
2958 int retTraCI = myVehicle.influenceChangeDecision(ret);
2959 if ((retTraCI & LCA_TRACI) != 0) {
2960 if ((retTraCI & LCA_STAY) != 0) {
2961 ret = retTraCI;
2962 latDist = 0;
2963 } else if (((retTraCI & LCA_RIGHT) != 0 && laneOffset < 0)
2964 || ((retTraCI & LCA_LEFT) != 0 && laneOffset > 0)) {
2965 ret = retTraCI;
2966 latDist = latLaneDist;
2967 }
2968 }
2969#if defined(DEBUG_STRATEGIC_CHANGE) || defined(DEBUG_TRACI)
2970 if (gDebugFlag2) {
2971 std::cout << " reqAfterInfluence=" << toString((LaneChangeAction)retTraCI) << " ret=" << toString((LaneChangeAction)ret) << "\n";
2972 }
2973#endif
2974 return ret;
2975}
2976
2977
2978bool
2980 double posOnLane, double neighDist, bool right, double latLaneDist, double& currentDist, double& latDist) {
2981 bool mustOvertake = false;
2982 const bool checkOverTakeRight = avoidOvertakeRight();
2983 int rightmost;
2984 int leftmost;
2985 const bool curHasStopped = leaders.hasStoppedVehicle();
2986 const MSLane* neighBeyond = neighLane.getParallelLane(latLaneDist < 0 ? -1 : 1);
2987 const bool hasLaneBeyond = neighBeyond != nullptr && neighBeyond->allowsVehicleClass(myVehicle.getVClass());
2988 if (curHasStopped) {
2989 leaders.getSubLanes(&myVehicle, 0, rightmost, leftmost);
2990 for (int i = rightmost; i <= leftmost; i++) {
2991 const CLeaderDist& leader = leaders[i];
2992 if (leader.first != 0 && leader.first->isStopped() && leader.second < REACT_TO_STOPPED_DISTANCE) {
2993 const double overtakeDist = leader.second + myVehicle.getVehicleType().getLength() + leader.first->getVehicleType().getLengthWithGap();
2994 if (// current destination leaves enough space to overtake the leader
2995 MIN2(neighDist, currentDist) - posOnLane > overtakeDist
2996 // maybe do not overtake on the right at high speed
2997 && (!checkOverTakeRight || !right)
2998 && (!neighLead.hasStoppedVehicle() || hasLaneBeyond)
2999 //&& (neighLead.first == 0 || !neighLead.first->isStopped()
3000 // // neighboring stopped vehicle leaves enough space to overtake leader
3001 // || neighLead.second > overtakeDist))
3002 ) {
3003 // avoid becoming stuck behind a stopped leader
3004 currentDist = myVehicle.getPositionOnLane() + leader.second;
3005 latDist = latLaneDist;
3006 mustOvertake = true;
3007#ifdef DEBUG_WANTS_CHANGE
3008 if (DEBUG_COND) {
3009 std::cout << " veh=" << myVehicle.getID() << " overtake stopped leader=" << leader.first->getID()
3010 << " overtakeDist=" << overtakeDist
3011 << " remaining=" << MIN2(neighDist, currentDist) - posOnLane
3012 << "\n";
3013 }
3014#endif
3015 }
3016 }
3017
3018 }
3019 }
3020 if (!mustOvertake && !curHasStopped && neighLead.hasStoppedVehicle()) {
3021 // #todo fix this if the neigh lane has a different width
3022 const double offset = (latLaneDist < 0 ? -1 : 1) * myVehicle.getLane()->getWidth();
3023 neighLead.getSubLanes(&myVehicle, offset, rightmost, leftmost);
3024 for (int i = 0; i < neighLead.numSublanes(); i++) {
3025 const CLeaderDist& leader = leaders[i];
3026 if (leader.first != 0 && leader.first->isStopped() && leader.second < REACT_TO_STOPPED_DISTANCE) {
3027 mustOvertake = true;
3028 if (i >= rightmost && i <= leftmost) {
3029 latDist = myVehicle.getLateralOverlap() * (latLaneDist > 0 ? -1 : 1);
3030 break;
3031 }
3032 }
3033 }
3034 }
3035 return mustOvertake;
3036}
3037
3038
3039double
3041 return (state & LCA_STRATEGIC) != 0 ? MAX2(0.0, (1.0 - myPushy * (1 + 0.5 * myImpatience))) : 1.0;
3042}
3043
3044
3045int
3047 const MSLeaderDistanceInfo& leaders,
3048 const MSLeaderDistanceInfo& followers,
3049 const MSLeaderDistanceInfo& blockers,
3050 const MSLeaderDistanceInfo& neighLeaders,
3051 const MSLeaderDistanceInfo& neighFollowers,
3052 const MSLeaderDistanceInfo& neighBlockers,
3053 const MSLane& neighLane,
3054 int laneOffset,
3055 double& latDist,
3056 double& maneuverDist,
3057 int& blocked) {
3058
3059 /* @notes
3060 * vehicles may need to compromise between fulfilling lane change objectives
3061 * (LCA_STRATEGIC, LCA_SPEED etc) and maintaining lateral gap. The minimum
3062 * acceptable lateral gap depends on
3063 * - the cultural context (China vs Europe)
3064 * - the driver agressiveness (willingness to encroach on other vehicles to force them to move laterally as well)
3065 * - see @note in checkBlocking
3066 * - the vehicle type (car vs motorcycle)
3067 * - the current speed
3068 * - the speed difference
3069 * - the importance / urgency of the desired maneuver
3070 *
3071 * the object of this method is to evaluate the above circumstances and
3072 * either:
3073 * - allow the current maneuver (state, latDist)
3074 * - to override the current maneuver with a distance-keeping maneuver
3075 *
3076 *
3077 * laneChangeModel/driver parameters
3078 * - bool pushy (willingness to encroach)
3079 * - float minGap at 100km/h (to be interpolated for lower speeds (assume 0 at speed 0)
3080 * - gapFactors (a factor for each of the change reasons
3081 *
3082 * further assumptions
3083 * - the maximum of egoSpeed and deltaSpeed can be used when interpolating minGap
3084 * - distance keeping to the edges of the road can be ignored (for now)
3085 *
3086 * currentMinGap = minGap * min(1.0, max(v, abs(v - vOther)) / 100) * gapFactor[lc_reason]
3087 *
3088 * */
3089
3091 double gapFactor = computeGapFactor(state);
3092 const double oldLatDist = latDist;
3093 const double oldManeuverDist = maneuverDist;
3095 const int traciState = myVehicle.influenceChangeDecision(state);
3096
3097 // compute gaps after maneuver
3098 const double halfWidth = getWidth() * 0.5;
3099 // if the current maneuver is blocked we will stay where we are
3100 const double oldCenter = myVehicle.getCenterOnEdge();
3101 // surplus gaps. these are used to collect various constraints
3102 // if they do not permit the desired maneuvre, should override it to better maintain distance
3103 // stay within the current edge
3104 double surplusGapRight = oldCenter - halfWidth;
3105 double surplusGapLeft = getLeftBorder(laneOffset != 0) - oldCenter - halfWidth;
3106 const bool stayInLane = (laneOffset == 0
3107 || ((traciState & LCA_STRATEGIC) != 0
3108 && (traciState & LCA_STAY) != 0
3109 // permit wide vehicles to stay on the road
3110 && (surplusGapLeft >= 0 && surplusGapRight >= 0)));
3111
3112 if (isOpposite()) {
3113 std::swap(surplusGapLeft, surplusGapRight);
3114 }
3115#ifdef DEBUG_KEEP_LATGAP
3116 if (gDebugFlag2) {
3117 std::cout << "\n " << SIMTIME << " keepLatGap() laneOffset=" << laneOffset
3118 << " latDist=" << latDist
3119 << " maneuverDist=" << maneuverDist
3120 << " state=" << toString((LaneChangeAction)state)
3121 << " traciState=" << toString((LaneChangeAction)traciState)
3122 << " blocked=" << toString((LaneChangeAction)blocked)
3123 << " gapFactor=" << gapFactor
3124 << " stayInLane=" << stayInLane << "\n"
3125 << " stayInEdge: surplusGapRight=" << surplusGapRight << " surplusGapLeft=" << surplusGapLeft << "\n";
3126 }
3127#endif
3128 // staying within the edge overrides all minGap considerations
3129 if (surplusGapLeft < 0 || surplusGapRight < 0) {
3130 gapFactor = 0;
3131 }
3132
3133 // maintain gaps to vehicles on the current lane
3134 // ignore vehicles that are too far behind
3135 const double netOverlap = -myVehicle.getVehicleType().getLength() * 0.5;
3136 updateGaps(leaders, myVehicle.getLane()->getRightSideOnEdge(), oldCenter, gapFactor, surplusGapRight, surplusGapLeft, true);
3137 updateGaps(followers, myVehicle.getLane()->getRightSideOnEdge(), oldCenter, gapFactor, surplusGapRight, surplusGapLeft, true, netOverlap);
3138
3139 if (laneOffset != 0) {
3140 // maintain gaps to vehicles on the target lane
3141 const double neighRight = getNeighRight(neighLane);
3142 updateGaps(neighLeaders, neighRight, oldCenter, gapFactor, surplusGapRight, surplusGapLeft, true);
3143 updateGaps(neighFollowers, neighRight, oldCenter, gapFactor, surplusGapRight, surplusGapLeft, true, netOverlap);
3144 }
3145#ifdef DEBUG_KEEP_LATGAP
3146 if (gDebugFlag2) {
3147 std::cout << " minGapLat: surplusGapRight=" << surplusGapRight << " surplusGapLeft=" << surplusGapLeft << "\n"
3148 << " lastGaps: right=" << myLastLateralGapRight << " left=" << myLastLateralGapLeft << "\n";
3149 }
3150#endif
3151 // we also need to track the physical gap, in addition to the psychological gap
3152 double physicalGapLeft = myLastLateralGapLeft == NO_NEIGHBOR ? surplusGapLeft : myLastLateralGapLeft;
3153 double physicalGapRight = myLastLateralGapRight == NO_NEIGHBOR ? surplusGapRight : myLastLateralGapRight;
3154
3155 const double halfLaneWidth = myVehicle.getLane()->getWidth() * 0.5;
3156 const double posLat = myVehicle.getLateralPositionOnLane() * (isOpposite() ? -1 : 1);
3157 if (stayInLane || laneOffset == 1) {
3158 // do not move past the right boundary of the current lane (traffic wasn't checked there)
3159 // but assume it's ok to be where we are in case we are already beyond
3160 surplusGapRight = MIN2(surplusGapRight, MAX2(0.0, halfLaneWidth + posLat - halfWidth));
3161 physicalGapRight = MIN2(physicalGapRight, MAX2(0.0, halfLaneWidth + posLat - halfWidth));
3162 }
3163 if (stayInLane || laneOffset == -1) {
3164 // do not move past the left boundary of the current lane (traffic wasn't checked there)
3165 // but assume it's ok to be where we are in case we are already beyond
3166 surplusGapLeft = MIN2(surplusGapLeft, MAX2(0.0, halfLaneWidth - posLat - halfWidth));
3167 physicalGapLeft = MIN2(physicalGapLeft, MAX2(0.0, halfLaneWidth - posLat - halfWidth));
3168 }
3169#ifdef DEBUG_KEEP_LATGAP
3170 if (gDebugFlag2) {
3171 std::cout << " stayInLane: surplusGapRight=" << surplusGapRight << " surplusGapLeft=" << surplusGapLeft << "\n";
3172 }
3173#endif
3174
3175 if (surplusGapRight + surplusGapLeft < 0) {
3176 // insufficient lateral space to fulfill all requirements. apportion space proportionally
3177 if ((state & LCA_CHANGE_REASONS) == 0) {
3178 state |= LCA_SUBLANE;
3179 }
3180 const double equalDeficit = 0.5 * (surplusGapLeft + surplusGapRight);
3181 if (surplusGapRight < surplusGapLeft) {
3182 // shift further to the left but no further than there is physical space
3183 const double delta = MIN2(equalDeficit - surplusGapRight, physicalGapLeft);
3184 latDist = delta;
3185 maneuverDist = delta;
3186#ifdef DEBUG_KEEP_LATGAP
3187 if (gDebugFlag2) {
3188 std::cout << " insufficient latSpace, move left: delta=" << delta << "\n";
3189 }
3190#endif
3191 } else {
3192 // shift further to the right but no further than there is physical space
3193 const double delta = MIN2(equalDeficit - surplusGapLeft, physicalGapRight);
3194 latDist = -delta;
3195 maneuverDist = -delta;
3196#ifdef DEBUG_KEEP_LATGAP
3197 if (gDebugFlag2) {
3198 std::cout << " insufficient latSpace, move right: delta=" << delta << "\n";
3199 }
3200#endif
3201 }
3202 } else {
3203 // sufficient space. move as far as the gaps permit
3204 latDist = MAX2(MIN2(latDist, surplusGapLeft), -surplusGapRight);
3205 maneuverDist = MAX2(MIN2(maneuverDist, surplusGapLeft), -surplusGapRight);
3206 if ((state & LCA_KEEPRIGHT) != 0 && maneuverDist != oldManeuverDist) {
3207 // don't start keepRight unless it can be completed
3208 latDist = oldLatDist;
3209 maneuverDist = oldManeuverDist;
3210 }
3211#ifdef DEBUG_KEEP_LATGAP
3212 if (gDebugFlag2) {
3213 std::cout << " adapted latDist=" << latDist << " maneuverDist=" << maneuverDist << " (old=" << oldLatDist << ")\n";
3214 }
3215#endif
3216 }
3217 // take into account overriding traci sublane-request
3219 // @note: the influence is reset in MSAbstractLaneChangeModel::setOwnState at the end of the lane-changing code for this vehicle
3220 latDist = myVehicle.getInfluencer().getLatDist();
3221 maneuverDist = myVehicle.getInfluencer().getLatDist();
3222 if (latDist < 0) {
3224 } else {
3226 }
3227 state |= LCA_TRACI;
3228#ifdef DEBUG_KEEP_LATGAP
3229 if (gDebugFlag2) {
3230 std::cout << " traci influenced latDist=" << latDist << "\n";
3231 }
3232#endif
3233 }
3234 // if we cannot move in the desired direction, consider the maneuver blocked anyway
3235 const bool nonSublaneChange = (state & (LCA_STRATEGIC | LCA_COOPERATIVE | LCA_SPEEDGAIN | LCA_KEEPRIGHT)) != 0;
3236 const bool traciChange = ((state | traciState) & LCA_TRACI) != 0;
3237 if (nonSublaneChange && !traciChange) {
3238 if ((latDist < NUMERICAL_EPS * myVehicle.getActionStepLengthSecs()) && (oldLatDist > 0)) {
3239#ifdef DEBUG_KEEP_LATGAP
3240 if (gDebugFlag2) {
3241 std::cout << " wanted changeToLeft oldLatDist=" << oldLatDist << ", blocked latGap changeToRight\n";
3242 }
3243#endif
3244 latDist = oldLatDist; // restore old request for usage in decideDirection()
3246 } else if ((latDist > -NUMERICAL_EPS * myVehicle.getActionStepLengthSecs()) && (oldLatDist < 0)) {
3247#ifdef DEBUG_KEEP_LATGAP
3248 if (gDebugFlag2) {
3249 std::cout << " wanted changeToRight oldLatDist=" << oldLatDist << ", blocked latGap changeToLeft\n";
3250 }
3251#endif
3252 latDist = oldLatDist; // restore old request for usage in decideDirection()
3254 }
3255 }
3256 // if we move, even though we wish to stay, update the change reason (except for TraCI)
3257 if (fabs(latDist) > NUMERICAL_EPS * myVehicle.getActionStepLengthSecs() && oldLatDist == 0) {
3258 state &= (~(LCA_CHANGE_REASONS | LCA_STAY) | LCA_TRACI);
3259 }
3260 // update blocked status
3261 if (fabs(latDist - oldLatDist) > NUMERICAL_EPS * myVehicle.getActionStepLengthSecs()) {
3262#ifdef DEBUG_KEEP_LATGAP
3263 if (gDebugFlag2) {
3264 std::cout << " latDistUpdated=" << latDist << " oldLatDist=" << oldLatDist << "\n";
3265 }
3266#endif
3267 blocked = checkBlocking(neighLane, latDist, maneuverDist, laneOffset, leaders, followers, blockers, neighLeaders, neighFollowers, neighBlockers, nullptr, nullptr, nonSublaneChange);
3268 }
3269 if (fabs(latDist) > NUMERICAL_EPS * myVehicle.getActionStepLengthSecs()) {
3270 state = (state & ~LCA_STAY);
3271 if ((state & LCA_CHANGE_REASONS) == 0) {
3272 state |= LCA_SUBLANE;
3273 }
3274 } else {
3275 if ((state & LCA_SUBLANE) != 0) {
3276 state |= LCA_STAY;
3277 }
3278 // avoid setting blinker due to numerical issues
3279 latDist = 0;
3280 }
3281#if defined(DEBUG_KEEP_LATGAP) || defined(DEBUG_STATE)
3282 if (gDebugFlag2) {
3283 std::cout << " latDist2=" << latDist
3284 << " state2=" << toString((LaneChangeAction)state)
3285 << " lastGapLeft=" << myLastLateralGapLeft
3286 << " lastGapRight=" << myLastLateralGapRight
3287 << " blockedAfter=" << toString((LaneChangeAction)blocked)
3288 << "\n";
3289 }
3290#endif
3291 return state;
3292}
3293
3294
3295void
3296MSLCM_SL2015::updateGaps(const MSLeaderDistanceInfo& others, double foeOffset, double oldCenter, double gapFactor,
3297 double& surplusGapRight, double& surplusGapLeft,
3298 bool saveMinGap, double netOverlap,
3299 double latDist,
3300 std::vector<CLeaderDist>* collectBlockers) {
3301 if (others.hasVehicles()) {
3302 const double halfWidth = getWidth() * 0.5 + NUMERICAL_EPS;
3303 const double baseMinGap = myMinGapLat;
3304 for (int i = 0; i < others.numSublanes(); ++i) {
3305 if (others[i].first != 0 && others[i].second <= 0
3306 && myCFRelated.count(others[i].first) == 0
3307 && (netOverlap == 0 || others[i].second + others[i].first->getVehicleType().getMinGap() < netOverlap)) {
3309 const MSVehicle* foe = others[i].first;
3310 const double res = MSGlobals::gLateralResolution > 0 ? MSGlobals::gLateralResolution : others[i].first->getLane()->getWidth();
3311 double foeRight, foeLeft;
3312 others.getSublaneBorders(i, foeOffset, foeRight, foeLeft);
3313 const double foeCenter = foeRight + 0.5 * res;
3314 const double gap = MIN2(fabs(foeRight - oldCenter), fabs(foeLeft - oldCenter)) - halfWidth;
3316 const double desiredMinGap = baseMinGap * deltaV / LATGAP_SPEED_THRESHOLD;
3317 const double currentMinGap = desiredMinGap * gapFactor; // pushy vehicles may accept a lower lateral gap temporarily
3318 /*
3319 if (netOverlap != 0) {
3320 // foe vehicle is follower with its front ahead of the ego midpoint
3321 // scale gap requirements so it gets lower for foe which are further behind ego
3322 //
3323 // relOverlap approaches 0 as the foe gets closer to the midpoint and it equals 1 if the foe is driving head-to-head
3324 const double relOverlap = 1 - (others[i].second + others[i].first->getVehicleType().getMinGap()) / netOverlap;
3325 currentMinGap *= currOverlap * relOverlap;
3326 }
3327 */
3328#if defined(DEBUG_BLOCKING) || defined(DEBUG_KEEP_LATGAP)
3329 if (debugVehicle()) {
3330 std::cout << " updateGaps"
3331 << " i=" << i
3332 << " foe=" << foe->getID()
3333 << " foeRight=" << foeRight
3334 << " foeLeft=" << foeLeft
3335 << " oldCenter=" << oldCenter
3336 << " gap=" << others[i].second
3337 << " latgap=" << gap
3338 << " currentMinGap=" << currentMinGap
3339 << " surplusGapRight=" << surplusGapRight
3340 << " surplusGapLeft=" << surplusGapLeft
3341 << "\n";
3342 }
3343#endif
3344
3345 // If foe is maneuvering towards ego, reserve some additional distance.
3346 // But don't expect the foe to come closer than currentMinGap if it isn't already there.
3347 // (XXX: How can the ego know the foe's maneuver dist?)
3348 if (foeCenter < oldCenter) { // && foe->getLaneChangeModel().getSpeedLat() > 0) {
3349 const double foeManeuverDist = MAX2(0., foe->getLaneChangeModel().getManeuverDist());
3350 surplusGapRight = MIN3(surplusGapRight, gap - currentMinGap, MAX2(currentMinGap, gap - foeManeuverDist));
3351 } else { //if (foeCenter > oldCenter && foe->getLaneChangeModel().getSpeedLat() < 0) {
3352 const double foeManeuverDist = -MIN2(0., foe->getLaneChangeModel().getManeuverDist());
3353 surplusGapLeft = MIN3(surplusGapLeft, gap - currentMinGap, MAX2(currentMinGap, gap - foeManeuverDist));
3354 }
3355 if (saveMinGap) {
3356 if (foeCenter < oldCenter) {
3357#if defined(DEBUG_BLOCKING) || defined(DEBUG_KEEP_LATGAP)
3358 if (gDebugFlag2 && gap < myLastLateralGapRight) {
3359 std::cout << " new minimum rightGap=" << gap << "\n";
3360 }
3361#endif
3363 } else {
3364#if defined(DEBUG_BLOCKING) || defined(DEBUG_KEEP_LATGAP)
3365 if (gDebugFlag2 && gap < myLastLateralGapLeft) {
3366 std::cout << " new minimum leftGap=" << gap << "\n";
3367 }
3368#endif
3370 }
3371 }
3372 if (collectBlockers != nullptr) {
3373 // check if the vehicle is blocking a desire lane change
3374 if ((foeCenter < oldCenter && latDist < 0 && gap < (desiredMinGap - latDist))
3375 || (foeCenter > oldCenter && latDist > 0 && gap < (desiredMinGap + latDist))) {
3376 collectBlockers->push_back(others[i]);
3377 }
3378 }
3379 }
3380 }
3381 }
3382}
3383
3384
3385double
3387 return myVehicle.getVehicleType().getWidth() + NUMERICAL_EPS;
3388}
3389
3390
3391double
3392MSLCM_SL2015::computeSpeedLat(double latDist, double& maneuverDist, bool urgent) const {
3393 int currentDirection = mySpeedLat >= 0 ? 1 : -1;
3394 int directionWish = latDist >= 0 ? 1 : -1;
3395 double maxSpeedLat = myVehicle.getVehicleType().getMaxSpeedLat();
3396 double accelLat = myAccelLat;
3397 if (!urgent && (myLeftSpace > POSITION_EPS || myMaxSpeedLatFactor < 0)) {
3398 const double speedBound = myMaxSpeedLatStanding + myMaxSpeedLatFactor * myVehicle.getSpeed();
3399 if (myMaxSpeedLatFactor >= 0) {
3400 // speedbound increases with speed and needs an upper bound
3401 maxSpeedLat = MIN2(maxSpeedLat, speedBound);
3402 } else {
3403 // speedbound decreases with speed and needs a lower bound
3404 // (only useful if myMaxSpeedLatStanding > maxSpeedLat)
3405 maxSpeedLat = MAX2(maxSpeedLat, speedBound);
3406 // increase (never decrease) lateral acceleration in proportion
3407 accelLat *= MAX2(1.0, speedBound / myVehicle.getVehicleType().getMaxSpeedLat());
3408 }
3409 }
3410
3411#ifdef DEBUG_MANEUVER
3412 if (debugVehicle()) {
3413 std::cout << SIMTIME
3414 << " veh=" << myVehicle.getID()
3415 << " computeSpeedLat()"
3416 << " latDist=" << latDist
3417 << " maneuverDist=" << maneuverDist
3418 << " urgent=" << urgent
3419 << " speedLat=" << mySpeedLat
3420 << " currentDirection=" << currentDirection
3421 << " directionWish=" << directionWish
3422 << " myLeftSpace=" << myLeftSpace
3423 << " maxSpeedLat=" << maxSpeedLat
3424 << std::endl;
3425 }
3426#endif
3427 // reduced lateral speed (in the desired direction). Don't change direction against desired.
3428 double speedDecel;
3429 if (directionWish == 1) {
3430 speedDecel = MAX2(mySpeedLat - ACCEL2SPEED(accelLat), 0.);
3431 } else {
3432 speedDecel = MIN2(mySpeedLat + ACCEL2SPEED(accelLat), 0.);
3433 }
3434 // increased lateral speed (in the desired direction)
3435 double speedAccel = MAX2(MIN2(mySpeedLat + directionWish * ACCEL2SPEED(accelLat), maxSpeedLat), -maxSpeedLat);
3436
3437 // can we reach the target distance in a single step? (XXX: assumes "Euler" update)
3438 double speedBound = DIST2SPEED(latDist);
3439 // for lat-gap keeping maneuvres myOrigLatDist may be 0
3440 const double fullLatDist = latDist > 0 ? MIN2(mySafeLatDistLeft, MAX2(maneuverDist, latDist)) : MAX2(-mySafeLatDistRight, MIN2(maneuverDist, latDist));
3441
3442 // update maneuverDist, if safety constraints apply in its direction
3443 if (maneuverDist * latDist > 0) {
3444 maneuverDist = fullLatDist;
3445 }
3446
3447#ifdef DEBUG_MANEUVER
3448 if (debugVehicle()) {
3449 std::cout << " mySafeLatDistRight=" << mySafeLatDistRight
3450 << " mySafeLatDistLeft=" << mySafeLatDistLeft
3451 << " fullLatDist=" << fullLatDist
3452 << " speedAccel=" << speedAccel
3453 << " speedDecel=" << speedDecel
3454 << " speedBound=" << speedBound
3455 << std::endl;
3456 }
3457#endif
3458 if (speedDecel * speedAccel <= 0 && (
3459 // speedAccel and speedDecel bracket speed 0. This means we can end the maneuver
3460 (latDist >= 0 && speedAccel >= speedBound && speedBound >= speedDecel)
3461 || (latDist <= 0 && speedAccel <= speedBound && speedBound <= speedDecel))) {
3462 // we can reach the desired value in this step
3463#ifdef DEBUG_MANEUVER
3464 if (debugVehicle()) {
3465 std::cout << " computeSpeedLat a)\n";
3466 }
3467#endif
3468 return speedBound;
3469 }
3470 // are we currently moving in the wrong direction?
3471 if (latDist * mySpeedLat < 0) {
3472#ifdef DEBUG_MANEUVER
3473 if (debugVehicle()) {
3474 std::cout << " computeSpeedLat b)\n";
3475 }
3476#endif
3477 return emergencySpeedLat(speedAccel);
3478 }
3479 // check if the remaining distance allows to accelerate laterally
3480 double minDistAccel = SPEED2DIST(speedAccel) + currentDirection * MSCFModel::brakeGapEuler(fabs(speedAccel), accelLat, 0); // most we can move in the target direction
3481 if ((fabs(minDistAccel) < fabs(fullLatDist)) || (fabs(minDistAccel - fullLatDist) < NUMERICAL_EPS)) {
3482#ifdef DEBUG_MANEUVER
3483 if (debugVehicle()) {
3484 std::cout << " computeSpeedLat c)\n";
3485 }
3486#endif
3487 return speedAccel;
3488 } else {
3489#ifdef DEBUG_MANEUVER
3490 if (debugVehicle()) {
3491 std::cout << " minDistAccel=" << minDistAccel << "\n";
3492 }
3493#endif
3494 // check if the remaining distance allows to maintain current lateral speed
3495 double minDistCurrent = SPEED2DIST(mySpeedLat) + currentDirection * MSCFModel::brakeGapEuler(fabs(mySpeedLat), accelLat, 0);
3496 if ((fabs(minDistCurrent) < fabs(fullLatDist)) || (fabs(minDistCurrent - fullLatDist) < NUMERICAL_EPS)) {
3497#ifdef DEBUG_MANEUVER
3498 if (debugVehicle()) {
3499 std::cout << " computeSpeedLat d)\n";
3500 }
3501#endif
3502 return mySpeedLat;
3503 }
3504 }
3505 // reduce lateral speed
3506#ifdef DEBUG_MANEUVER
3507 if (debugVehicle()) {
3508 std::cout << " computeSpeedLat e)\n";
3509 }
3510#endif
3511 return emergencySpeedLat(speedDecel);
3512}
3513
3514
3515double
3516MSLCM_SL2015::emergencySpeedLat(double speedLat) const {
3517 // reduce lateral speed for safety purposes
3518 if (speedLat < 0 && SPEED2DIST(-speedLat) > mySafeLatDistRight) {
3519 speedLat = -DIST2SPEED(mySafeLatDistRight);
3520#ifdef DEBUG_MANEUVER
3521 if (debugVehicle()) {
3522 std::cout << " rightDanger speedLat=" << speedLat << "\n";
3523 }
3524#endif
3525 } else if (speedLat > 0 && SPEED2DIST(speedLat) > mySafeLatDistLeft) {
3526 speedLat = DIST2SPEED(mySafeLatDistLeft);
3527#ifdef DEBUG_MANEUVER
3528 if (debugVehicle()) {
3529 std::cout << " leftDanger speedLat=" << speedLat << "\n";
3530 }
3531#endif
3532 }
3533 return speedLat;
3534}
3535
3536
3540 // Check whether the vehicle should adapt its alignment to an upcoming turn
3541 if (myTurnAlignmentDist > 0) {
3542 const std::pair<double, const MSLink*>& turnInfo = myVehicle.getNextTurn();
3543 const LinkDirection turnDir = turnInfo.second == nullptr ? LinkDirection::NODIR : turnInfo.second->getDirection();
3544 const bool indirect = turnInfo.second == nullptr ? false : turnInfo.second->isIndirect();
3545 if (turnInfo.first < myTurnAlignmentDist) {
3546 // Vehicle is close enough to the link to change its default alignment
3547 switch (turnDir) {
3551 if (myVehicle.getLane()->getBidiLane() == nullptr) {
3552 // no left alignment on bidi lane to avoid blocking oncoming traffic
3554 }
3555 break;
3560 break;
3563 default:
3564 break;
3565 }
3566 }
3567 }
3568 return align;
3569}
3570
3571
3572void
3573MSLCM_SL2015::commitManoeuvre(int blocked, int blockedFully,
3574 const MSLeaderDistanceInfo& leaders,
3575 const MSLeaderDistanceInfo& neighLeaders,
3576 const MSLane& neighLane,
3577 double maneuverDist) {
3578 if (!blocked && !blockedFully && !myCanChangeFully) {
3579 // round to full action steps
3580 double secondsToLeaveLane;
3582 secondsToLeaveLane = ceil(fabs(maneuverDist) / myVehicle.getVehicleType().getMaxSpeedLat() / myVehicle.getActionStepLengthSecs()) * myVehicle.getActionStepLengthSecs();
3583 // XXX myAccelLat must be taken into account (refs #3601, see ballistic case for solution)
3584
3585 // XXX This also causes probs: if the difference between the current speed and the committed is higher than the maximal decel,
3586 // the vehicle may pass myLeftSpace before completing the maneuver.
3587 myCommittedSpeed = MIN3(myLeftSpace / secondsToLeaveLane,
3590#if defined(DEBUG_MANEUVER) || defined(DEBUG_COMMITTED_SPEED)
3591 if (debugVehicle()) {
3592 std::cout << SIMTIME << " veh=" << myVehicle.getID() << " myCommittedSpeed=" << myCommittedSpeed << " leftSpace=" << myLeftSpace << " secondsToLeave=" << secondsToLeaveLane << "\n";
3593 }
3594#endif
3595 } else {
3596
3597 // Calculate seconds needed for leaving lane assuming start from lateral speed zero, and lat.accel == -lat.decel
3598 secondsToLeaveLane = MSCFModel::estimateArrivalTime(fabs(maneuverDist), 0., 0., myVehicle.getVehicleType().getMaxSpeedLat(), myAccelLat, myAccelLat);
3599 // round to full action steps
3600 secondsToLeaveLane = ceil(secondsToLeaveLane / myVehicle.getActionStepLengthSecs()) * myVehicle.getActionStepLengthSecs();
3601
3602 // committed speed will eventually be pushed into a drive item during the next planMove() step. This item
3603 // will not be read before the next action step at current time + actionStepLength-TS, so we need to schedule the corresponding speed.
3604 const double timeTillActionStep = myVehicle.getActionStepLengthSecs() - TS;
3605 const double nextActionStepSpeed = MAX2(0., myVehicle.getSpeed() + timeTillActionStep * myVehicle.getAcceleration());
3606 double nextLeftSpace;
3607 if (nextActionStepSpeed > 0.) {
3608 nextLeftSpace = myLeftSpace - timeTillActionStep * (myVehicle.getSpeed() + nextActionStepSpeed) * 0.5;
3609 } else if (myVehicle.getAcceleration() == 0) {
3610 nextLeftSpace = myLeftSpace;
3611 } else {
3612 assert(myVehicle.getAcceleration() < 0.);
3613 nextLeftSpace = myLeftSpace + (myVehicle.getSpeed() * myVehicle.getSpeed() / myVehicle.getAcceleration()) * 0.5;
3614 }
3615 const double avoidArrivalSpeed = nextActionStepSpeed + ACCEL2SPEED(MSCFModel::avoidArrivalAccel(
3616 nextLeftSpace, secondsToLeaveLane - timeTillActionStep, nextActionStepSpeed, myVehicle.getCarFollowModel().getEmergencyDecel()));
3617
3618 myCommittedSpeed = MIN3(avoidArrivalSpeed,
3621
3622#if defined(DEBUG_MANEUVER) || defined(DEBUG_COMMITTED_SPEED)
3623 if (gDebugFlag2) {
3624 std::cout << SIMTIME
3625 << " veh=" << myVehicle.getID()
3626 << " avoidArrivalSpeed=" << avoidArrivalSpeed
3627 << " currentSpeed=" << myVehicle.getSpeed()
3628 << " myLeftSpace=" << myLeftSpace
3629 << "\n nextLeftSpace=" << nextLeftSpace
3630 << " nextActionStepSpeed=" << nextActionStepSpeed
3631 << " nextActionStepRemainingSeconds=" << secondsToLeaveLane - timeTillActionStep
3632 << "\n";
3633 }
3634#endif
3635 }
3636 myCommittedSpeed = commitFollowSpeed(myCommittedSpeed, maneuverDist, secondsToLeaveLane, leaders, myVehicle.getLane()->getRightSideOnEdge());
3637 myCommittedSpeed = commitFollowSpeed(myCommittedSpeed, maneuverDist, secondsToLeaveLane, neighLeaders, neighLane.getRightSideOnEdge());
3639 myCommittedSpeed = 0;
3640 }
3641#if defined(DEBUG_MANEUVER) || defined(DEBUG_COMMITTED_SPEED)
3642 if (gDebugFlag2) {
3643 std::cout << SIMTIME
3644 << " veh=" << myVehicle.getID()
3645 << " secondsToLeave=" << secondsToLeaveLane
3647 << " committed=" << myCommittedSpeed
3648 << "\n";
3649 }
3650#endif
3651 }
3652}
3653
3654double
3655MSLCM_SL2015::commitFollowSpeed(double speed, double latDist, double secondsToLeaveLane, const MSLeaderDistanceInfo& leaders, double foeOffset) const {
3656 if (leaders.hasVehicles()) {
3657 // we distinguish 3 cases
3658 // - vehicles with lateral overlap at the end of the maneuver: try to follow safely
3659 // - vehicles with overlap at the start of the maneuver: avoid collision within secondsToLeaveLane
3660 // - vehicles without overlap: ignore
3661
3662 const double maxDecel = myVehicle.getCarFollowModel().getMaxDecel();
3663 // temporarily use another decel value
3664 MSCFModel& cfmodel = const_cast<MSCFModel&>(myVehicle.getCarFollowModel());
3665 cfmodel.setMaxDecel(maxDecel / getSafetyFactor());
3666
3667 const double vehWidth = getWidth();
3668 const double rightVehSide = myVehicle.getCenterOnEdge() - 0.5 * vehWidth;
3669 const double leftVehSide = rightVehSide + vehWidth;
3670 const double rightVehSideDest = rightVehSide + latDist;
3671 const double leftVehSideDest = leftVehSide + latDist;
3672#if defined(DEBUG_MANEUVER) || defined(DEBUG_COMMITTED_SPEED)
3673 if (gDebugFlag2) {
3674 std::cout << " commitFollowSpeed"
3675 << " latDist=" << latDist
3676 << " foeOffset=" << foeOffset
3677 << " vehRight=" << rightVehSide
3678 << " vehLeft=" << leftVehSide
3679 << " destRight=" << rightVehSideDest
3680 << " destLeft=" << leftVehSideDest
3681 << "\n";
3682 }
3683#endif
3684 for (int i = 0; i < leaders.numSublanes(); ++i) {
3685 CLeaderDist vehDist = leaders[i];
3686 if (vehDist.first != 0) {
3687 const MSVehicle* leader = vehDist.first;
3688 // only check the current stripe occuped by foe (transform into edge-coordinates)
3689 double foeRight, foeLeft;
3690 leaders.getSublaneBorders(i, foeOffset, foeRight, foeLeft);
3691#if defined(DEBUG_MANEUVER) || defined(DEBUG_COMMITTED_SPEED)
3692 if (gDebugFlag2) {
3693 std::cout << " foe=" << vehDist.first->getID()
3694 << " gap=" << vehDist.second
3695 << " secGap=" << myVehicle.getCarFollowModel().getSecureGap(&myVehicle, leader, myVehicle.getSpeed(), leader->getSpeed(), leader->getCarFollowModel().getMaxDecel())
3696 << " foeRight=" << foeRight
3697 << " foeLeft=" << foeLeft
3698 << " overlapBefore=" << overlap(rightVehSide, leftVehSide, foeRight, foeLeft)
3699 << " overlapDest=" << overlap(rightVehSideDest, leftVehSideDest, foeRight, foeLeft)
3700 << "\n";
3701 }
3702#endif
3703 if (overlap(rightVehSideDest, leftVehSideDest, foeRight, foeLeft)) {
3704 // case 1
3705 const double vSafe = myVehicle.getCarFollowModel().followSpeed(
3706 &myVehicle, speed, vehDist.second, leader->getSpeed(), leader->getCarFollowModel().getMaxDecel());
3707 speed = MIN2(speed, vSafe);
3708#if defined(DEBUG_MANEUVER) || defined(DEBUG_COMMITTED_SPEED)
3709 if (gDebugFlag2) {
3710 std::cout << " case1 vsafe=" << vSafe << " speed=" << speed << "\n";
3711 }
3712#endif
3713 } else if (overlap(rightVehSide, leftVehSide, foeRight, foeLeft)) {
3714 // case 2
3715 const double vSafe = myVehicle.getCarFollowModel().followSpeedTransient(
3716 secondsToLeaveLane,
3717 &myVehicle, speed, vehDist.second, leader->getSpeed(), leader->getCarFollowModel().getMaxDecel());
3718 speed = MIN2(speed, vSafe);
3719#if defined(DEBUG_MANEUVER) || defined(DEBUG_COMMITTED_SPEED)
3720 if (gDebugFlag2) {
3721 std::cout << " case2 vsafe=" << vSafe << " speed=" << speed << "\n";
3722 }
3723#endif
3724 }
3725 }
3726 }
3727 // restore original deceleration
3728 cfmodel.setMaxDecel(maxDecel);
3729
3730 }
3731 return speed;
3732}
3733
3734double
3736 return 1 / ((1 + 0.5 * myImpatience) * myAssertive);
3737}
3738
3739double
3741 return myOppositeParam <= 0 ? std::numeric_limits<double>::max() : 1 / myOppositeParam;
3742}
3743
3744
3745std::string
3746MSLCM_SL2015::getParameter(const std::string& key) const {
3748 return toString(myStrategicParam);
3749 } else if (key == toString(SUMO_ATTR_LCA_COOPERATIVE_PARAM)) {
3751 } else if (key == toString(SUMO_ATTR_LCA_SPEEDGAIN_PARAM)) {
3752 return toString(mySpeedGainParam);
3753 } else if (key == toString(SUMO_ATTR_LCA_KEEPRIGHT_PARAM)) {
3754 return toString(myKeepRightParam);
3755 } else if (key == toString(SUMO_ATTR_LCA_OPPOSITE_PARAM)) {
3756 return toString(myOppositeParam);
3757 } else if (key == toString(SUMO_ATTR_LCA_SUBLANE_PARAM)) {
3758 return toString(mySublaneParam);
3759 } else if (key == toString(SUMO_ATTR_MINGAP_LAT)) {
3760 return toString(myMinGapLat);
3761 } else if (key == toString(SUMO_ATTR_LCA_PUSHY)) {
3762 return toString(myPushy);
3763 } else if (key == toString(SUMO_ATTR_LCA_PUSHYGAP)) {
3764 return toString((myPushy - 1) * myMinGapLat);
3765 } else if (key == toString(SUMO_ATTR_LCA_ASSERTIVE)) {
3766 return toString(myAssertive);
3767 } else if (key == toString(SUMO_ATTR_LCA_IMPATIENCE)) {
3768 return toString(myImpatience);
3769 } else if (key == toString(SUMO_ATTR_LCA_TIME_TO_IMPATIENCE)) {
3771 } else if (key == toString(SUMO_ATTR_LCA_ACCEL_LAT)) {
3772 return toString(myAccelLat);
3773 } else if (key == toString(SUMO_ATTR_LCA_LOOKAHEADLEFT)) {
3774 return toString(myLookaheadLeft);
3775 } else if (key == toString(SUMO_ATTR_LCA_SPEEDGAINRIGHT)) {
3776 return toString(mySpeedGainRight);
3777 } else if (key == toString(SUMO_ATTR_LCA_LANE_DISCIPLINE)) {
3778 return toString(myLaneDiscipline);
3779 } else if (key == toString(SUMO_ATTR_LCA_SIGMA)) {
3780 return toString(mySigma);
3785 } else if (key == toString(SUMO_ATTR_LCA_SPEEDGAIN_LOOKAHEAD)) {
3789 } else if (key == toString(SUMO_ATTR_LCA_COOPERATIVE_SPEED)) {
3791 } else if (key == toString(SUMO_ATTR_LCA_MAXSPEEDLATSTANDING)) {
3793 } else if (key == toString(SUMO_ATTR_LCA_MAXSPEEDLATFACTOR)) {
3795 } else if (key == toString(SUMO_ATTR_LCA_MAXDISTLATSTANDING)) {
3797 // access to internal state for debugging in sumo-gui (not documented since it may change at any time)
3798 } else if (key == "speedGainProbabilityRight") {
3800 } else if (key == "speedGainProbabilityLeft") {
3802 } else if (key == "keepRightProbability") {
3804 } else if (key == "lookAheadSpeed") {
3805 return toString(myLookAheadSpeed);
3806 } else if (key == "sigmaState") {
3807 return toString(mySigmaState);
3808 // motivation relative to threshold
3809 } else if (key == "speedGainRP") {
3811 } else if (key == "speedGainLP") {
3813 } else if (key == "keepRightP") {
3815 }
3816 throw InvalidArgument("Parameter '" + key + "' is not supported for laneChangeModel of type '" + toString(myModel) + "'");
3817}
3818
3819void
3820MSLCM_SL2015::setParameter(const std::string& key, const std::string& value) {
3821 double doubleValue;
3822 try {
3823 doubleValue = StringUtils::toDouble(value);
3824 } catch (NumberFormatException&) {
3825 throw InvalidArgument("Setting parameter '" + key + "' requires a number for laneChangeModel of type '" + toString(myModel) + "'");
3826 }
3828 myStrategicParam = doubleValue;
3829 } else if (key == toString(SUMO_ATTR_LCA_COOPERATIVE_PARAM)) {
3830 myCooperativeParam = doubleValue;
3831 } else if (key == toString(SUMO_ATTR_LCA_SPEEDGAIN_PARAM)) {
3832 mySpeedGainParam = doubleValue;
3833 } else if (key == toString(SUMO_ATTR_LCA_KEEPRIGHT_PARAM)) {
3834 myKeepRightParam = doubleValue;
3835 } else if (key == toString(SUMO_ATTR_LCA_OPPOSITE_PARAM)) {
3836 myOppositeParam = doubleValue;
3837 } else if (key == toString(SUMO_ATTR_LCA_SUBLANE_PARAM)) {
3838 mySublaneParam = doubleValue;
3839 } else if (key == toString(SUMO_ATTR_MINGAP_LAT)) {
3840 myMinGapLat = doubleValue;
3841 } else if (key == toString(SUMO_ATTR_LCA_PUSHY)) {
3842 myPushy = doubleValue;
3843 } else if (key == toString(SUMO_ATTR_LCA_PUSHYGAP)) {
3844 myPushy = 1 - doubleValue / myMinGapLat;
3845 } else if (key == toString(SUMO_ATTR_LCA_ASSERTIVE)) {
3846 myAssertive = doubleValue;
3847 } else if (key == toString(SUMO_ATTR_LCA_IMPATIENCE)) {
3848 myImpatience = doubleValue;
3849 myMinImpatience = doubleValue;
3850 } else if (key == toString(SUMO_ATTR_LCA_TIME_TO_IMPATIENCE)) {
3851 myTimeToImpatience = doubleValue;
3852 } else if (key == toString(SUMO_ATTR_LCA_ACCEL_LAT)) {
3853 myAccelLat = doubleValue;
3855 myTurnAlignmentDist = doubleValue;
3856 } else if (key == toString(SUMO_ATTR_LCA_LOOKAHEADLEFT)) {
3857 myLookaheadLeft = doubleValue;
3858 } else if (key == toString(SUMO_ATTR_LCA_SPEEDGAINRIGHT)) {
3859 mySpeedGainRight = doubleValue;
3860 } else if (key == toString(SUMO_ATTR_LCA_LANE_DISCIPLINE)) {
3861 myLaneDiscipline = doubleValue;
3862 } else if (key == toString(SUMO_ATTR_LCA_SIGMA)) {
3863 mySigma = doubleValue;
3865 myKeepRightAcceptanceTime = doubleValue;
3867 myOvertakeDeltaSpeedFactor = doubleValue;
3868 } else if (key == toString(SUMO_ATTR_LCA_SPEEDGAIN_LOOKAHEAD)) {
3869 mySpeedGainLookahead = doubleValue;
3871 myRoundaboutBonus = doubleValue;
3872 } else if (key == toString(SUMO_ATTR_LCA_COOPERATIVE_SPEED)) {
3873 myCooperativeSpeed = doubleValue;
3874 } else if (key == toString(SUMO_ATTR_LCA_MAXSPEEDLATSTANDING)) {
3875 myMaxSpeedLatStanding = doubleValue;
3876 } else if (key == toString(SUMO_ATTR_LCA_MAXSPEEDLATFACTOR)) {
3877 myMaxSpeedLatFactor = doubleValue;
3878 } else if (key == toString(SUMO_ATTR_LCA_MAXDISTLATSTANDING)) {
3879 myMaxDistLatStanding = doubleValue;
3880 // access to internal state
3881 } else if (key == "speedGainProbabilityRight") {
3882 mySpeedGainProbabilityRight = doubleValue;
3883 } else if (key == "speedGainProbabilityLeft") {
3884 mySpeedGainProbabilityLeft = doubleValue;
3885 } else if (key == "keepRightProbability") {
3886 myKeepRightProbability = doubleValue;
3887 } else if (key == "lookAheadSpeed") {
3888 myLookAheadSpeed = doubleValue;
3889 } else if (key == "sigmaState") {
3890 mySigmaState = doubleValue;
3891 } else {
3892 throw InvalidArgument("Setting parameter '" + key + "' is not supported for laneChangeModel of type '" + toString(myModel) + "'");
3893 }
3895}
3896
3897
3898int
3900 int laneOffset,
3902 int blocked,
3903 const std::pair<MSVehicle*, double>& leader,
3904 const std::pair<MSVehicle*, double>& follower,
3905 const std::pair<MSVehicle*, double>& neighLead,
3906 const std::pair<MSVehicle*, double>& neighFollow,
3907 const MSLane& neighLane,
3908 const std::vector<MSVehicle::LaneQ>& preb,
3909 MSVehicle** lastBlocked,
3910 MSVehicle** firstBlocked) {
3911
3912 const LaneChangeAction alternatives = LCA_NONE; // @todo pas this data
3913
3914#ifdef DEBUG_WANTSCHANGE
3915 if (DEBUG_COND) {
3916 std::cout << "\nWANTS_CHANGE\n" << SIMTIME
3917 //<< std::setprecision(10)
3918 << " veh=" << myVehicle.getID()
3919 << " lane=" << myVehicle.getLane()->getID()
3920 << " neigh=" << neighLane.getID()
3921 << " pos=" << myVehicle.getPositionOnLane()
3922 << " posLat=" << myVehicle.getLateralPositionOnLane()
3923 << " speed=" << myVehicle.getSpeed()
3924 << " considerChangeTo=" << (laneOffset == -1 ? "right" : "left")
3925 << "\n";
3926 }
3927#endif
3928
3929 double latDist = 0;
3930 const double laneWidth = myVehicle.getLane()->getWidth();
3931 MSLeaderDistanceInfo leaders(leader, laneWidth);
3932 MSLeaderDistanceInfo followers(follower, laneWidth);
3933 MSLeaderDistanceInfo blockers(std::make_pair((MSVehicle*)nullptr, -1), laneWidth);
3934 MSLeaderDistanceInfo neighLeaders(neighLead, laneWidth);
3935 MSLeaderDistanceInfo neighFollowers(neighFollow, laneWidth);
3936 MSLeaderDistanceInfo neighBlockers(std::make_pair((MSVehicle*)nullptr, -1), laneWidth);
3937
3938 double maneuverDist;
3939 int result = _wantsChangeSublane(laneOffset,
3940 alternatives,
3941 leaders, followers, blockers,
3942 neighLeaders, neighFollowers, neighBlockers,
3943 neighLane, preb,
3944 lastBlocked, firstBlocked, latDist, maneuverDist, blocked);
3945
3946 myCanChangeFully = true;
3947 // ignore sublane motivation
3948 result &= ~LCA_SUBLANE;
3949 result |= getLCA(result, latDist);
3950
3951#if defined(DEBUG_WANTSCHANGE) || defined(DEBUG_STATE)
3952 if (DEBUG_COND) {
3953 if (result & LCA_WANTS_LANECHANGE) {
3954 std::cout << SIMTIME
3955 << " veh=" << myVehicle.getID()
3956 << " wantsChangeTo=" << (laneOffset == -1 ? "right" : "left")
3957 << ((result & LCA_URGENT) ? " (urgent)" : "")
3958 << ((result & LCA_CHANGE_TO_HELP) ? " (toHelp)" : "")
3959 << ((result & LCA_STRATEGIC) ? " (strat)" : "")
3960 << ((result & LCA_COOPERATIVE) ? " (coop)" : "")
3961 << ((result & LCA_SPEEDGAIN) ? " (speed)" : "")
3962 << ((result & LCA_KEEPRIGHT) ? " (keepright)" : "")
3963 << ((result & LCA_TRACI) ? " (traci)" : "")
3964 << ((blocked & LCA_BLOCKED) ? " (blocked)" : "")
3965 << ((blocked & LCA_OVERLAPPING) ? " (overlap)" : "")
3966 << "\n\n\n";
3967 }
3968 }
3969#endif
3970
3971 return result;
3972}
3973
3974
3975double
3976MSLCM_SL2015::getLeftBorder(bool checkOpposite) const {
3977 return (myVehicle.getLane()->getEdge().getWidth()
3978 + ((myVehicle.getLane()->getParallelOpposite() != nullptr && checkOpposite) ? myVehicle.getLane()->getParallelOpposite()->getEdge().getWidth() : 0));
3979}
3980
3981double
3983 if (isOpposite()) {
3985 } else {
3986 return myVehicle.getCenterOnEdge();
3987 }
3988}
3989
3990double
3991MSLCM_SL2015::getNeighRight(const MSLane& neighLane) const {
3992 if (isOpposite()) {
3994 } else if ((&myVehicle.getLane()->getEdge() != &neighLane.getEdge())) {
3996 } else {
3997 // the normal case
3998 return neighLane.getRightSideOnEdge();
3999 }
4000}
4001
4002
4003bool
4004MSLCM_SL2015::preventSliding(double maneuverDist) const {
4005 // prevent wide maneuvers with unsufficient forward space
4006 if (fabs(maneuverDist) > myMaxDistLatStanding) {
4007 // emergency vehicles should not be restricted (TODO solve this with LCA_URGENT)
4009 return false;
4010 }
4011 const double brakeGap = myVehicle.getCarFollowModel().brakeGap(myVehicle.getSpeed());
4012 const bool isSlide = fabs(maneuverDist) > myMaxDistLatStanding + brakeGap * fabs(myMaxSpeedLatFactor);
4013#ifdef DEBUG_SLIDING
4014 if (gDebugFlag2) {
4015 std::cout << SIMTIME << " veh=" << myVehicle.getID() << " bgap=" << brakeGap << " maneuverDist=" << maneuverDist
4016 << " mds=" << myMaxDistLatStanding << " isSlide=" << isSlide << "\n";
4017 }
4018#endif
4019 return isSlide;
4020 }
4021 return false;
4022}
4023
4024bool
4025MSLCM_SL2015::wantsKeepRight(double keepRightProb) const {
4027}
4028
4029
4030bool
4031MSLCM_SL2015::saveBlockerLength(double length, double foeLeftSpace) {
4032 const bool canReserve = MSLCHelper::canSaveBlockerLength(myVehicle, length, myLeftSpace);
4033 if (!isOpposite() && (canReserve || myLeftSpace > foeLeftSpace)) {
4035 if (myLeftSpace == 0 && foeLeftSpace < 0) {
4036 // called from opposite overtaking, myLeftSpace must be initialized
4038 }
4039 return true;
4040 } else {
4041 return false;
4042 }
4043}
4044
4045
4046bool
4050/****************************************************************************/
long long int SUMOTime
Definition GUI.h:36
#define JAM_FACTOR
#define MAGIC_OFFSET
#define HELP_DECEL_FACTOR
#define LOOK_AHEAD_MIN_SPEED
#define LCA_RIGHT_IMPATIENCE
#define LOOK_FORWARD
#define HELP_OVERTAKE
#define REACT_TO_STOPPED_DISTANCE
#define KEEP_RIGHT_TIME
#define RELGAIN_NORMALIZATION_MIN_SPEED
#define CUT_IN_LEFT_SPEED_THRESHOLD
#define MAX_ONRAMP_LENGTH
#define MIN_FALLBEHIND
#define URGENCY
#define LOOK_AHEAD_SPEED_MEMORY
#define TURN_LANE_DIST
#define ARRIVALPOS_LAT_THRESHOLD
#define SPEEDGAIN_MEMORY_FACTOR
#define LOOK_AHEAD_MIN_SPEED
#define SPEEDGAIN_DECAY_FACTOR
#define LATGAP_SPEED_THRESHOLD
#define GAIN_PERCEPTION_THRESHOLD
#define SPEED_GAIN_MIN_SECONDS
#define LATGAP_SPEED_THRESHOLD2
std::pair< const MSVehicle *, double > CLeaderDist
std::pair< const MSPerson *, double > PersonDist
Definition MSPModel.h:41
#define STEPS2TIME(x)
Definition SUMOTime.h:55
#define SPEED2DIST(x)
Definition SUMOTime.h:45
#define ACCEL2SPEED(x)
Definition SUMOTime.h:51
#define TS
Definition SUMOTime.h:42
#define SIMTIME
Definition SUMOTime.h:62
#define DIST2SPEED(x)
Definition SUMOTime.h:47
LatAlignmentDefinition
Possible ways to choose the lateral alignment, i.e., how vehicles align themselves within their lane.
@ RIGHT
drive on the right side
@ GIVEN
The alignment as offset is given.
@ DEFAULT
No information given; use default.
@ LEFT
drive on the left side
@ ARBITRARY
maintain the current alignment
@ NICE
align with the closest sublane border
@ COMPACT
align with the rightmost sublane that allows keeping the current speed
@ CENTER
drive in the middle
@ SVC_EMERGENCY
public emergency vehicles
@ RIGHT
At the rightmost side of the lane.
@ GIVEN
The position is given.
@ DEFAULT
No information given; use default.
@ LEFT
At the leftmost side of the lane.
@ CENTER
At the center of the lane.
LinkDirection
The different directions a link between two lanes may take (or a stream between two edges)....
@ PARTLEFT
The link is a partial left direction.
@ RIGHT
The link is a (hard) right direction.
@ TURN
The link is a 180 degree turn.
@ LEFT
The link is a (hard) left direction.
@ STRAIGHT
The link is a straight direction.
@ TURN_LEFTHAND
The link is a 180 degree turn (left-hand network)
@ PARTRIGHT
The link is a partial right direction.
@ NODIR
The link has no direction (is a dead end link)
LaneChangeAction
The state of a vehicle's lane-change behavior.
@ LCA_BLOCKED_LEFT
blocked left
@ LCA_KEEPRIGHT
The action is due to the default of keeping right "Rechtsfahrgebot".
@ LCA_CHANGE_TO_HELP
@ LCA_BLOCKED
blocked in all directions
@ LCA_URGENT
The action is urgent (to be defined by lc-model)
@ LCA_BLOCKED_BY_RIGHT_LEADER
The vehicle is blocked by right leader.
@ LCA_STAY
Needs to stay on the current lane.
@ LCA_SUBLANE
used by the sublane model
@ LCA_BLOCKED_BY_LEADER
blocked by leader
@ LCA_AMBACKBLOCKER
@ LCA_BLOCKED_BY_LEFT_FOLLOWER
The vehicle is blocked by left follower.
@ LCA_AMBLOCKINGLEADER
@ LCA_AMBLOCKINGFOLLOWER_DONTBRAKE
@ LCA_COOPERATIVE
The action is done to help someone else.
@ LCA_OVERLAPPING
The vehicle is blocked being overlapping.
@ LCA_LEFT
Wants go to the left.
@ LCA_BLOCKED_RIGHT
blocked right
@ LCA_BLOCKED_BY_RIGHT_FOLLOWER
The vehicle is blocked by right follower.
@ LCA_STRATEGIC
The action is needed to follow the route (navigational lc)
@ LCA_AMBACKBLOCKER_STANDING
@ LCA_CHANGE_REASONS
reasons of lane change
@ LCA_TRACI
The action is due to a TraCI request.
@ LCA_SPEEDGAIN
The action is due to the wish to be faster (tactical lc)
@ LCA_WANTS_LANECHANGE
lane can change
@ LCA_RIGHT
Wants go to the right.
@ LCA_BLOCKED_BY_FOLLOWER
blocker by follower
@ LCA_BLOCKED_BY_LEFT_LEADER
@ LCA_AMBLOCKINGFOLLOWER
@ SUMO_ATTR_LCA_PUSHY
@ SUMO_ATTR_LCA_COOPERATIVE_SPEED
@ SUMO_ATTR_LCA_ASSERTIVE
@ SUMO_ATTR_LCA_LANE_DISCIPLINE
@ SUMO_ATTR_LCA_TURN_ALIGNMENT_DISTANCE
@ SUMO_ATTR_LCA_PUSHYGAP
@ SUMO_ATTR_LCA_LOOKAHEADLEFT
@ SUMO_ATTR_LCA_SPEEDGAIN_PARAM
@ SUMO_ATTR_LCA_MAXDISTLATSTANDING
@ SUMO_ATTR_LCA_IMPATIENCE
@ SUMO_ATTR_LCA_COOPERATIVE_ROUNDABOUT
@ SUMO_ATTR_LCA_SPEEDGAIN_LOOKAHEAD
@ SUMO_ATTR_LCA_MAXSPEEDLATFACTOR
@ SUMO_ATTR_LCA_MAXSPEEDLATSTANDING
@ SUMO_ATTR_LCA_KEEPRIGHT_PARAM
@ SUMO_ATTR_LCA_COOPERATIVE_PARAM
@ SUMO_ATTR_LCA_OPPOSITE_PARAM
@ SUMO_ATTR_MINGAP_LAT
@ SUMO_ATTR_LCA_OVERTAKE_DELTASPEED_FACTOR
@ SUMO_ATTR_LCA_SUBLANE_PARAM
@ SUMO_ATTR_LCA_SIGMA
@ SUMO_ATTR_LCA_ACCEL_LAT
@ SUMO_ATTR_LCA_STRATEGIC_PARAM
@ SUMO_ATTR_LCA_KEEPRIGHT_ACCEPTANCE_TIME
@ SUMO_ATTR_LCA_TIME_TO_IMPATIENCE
@ SUMO_ATTR_LCA_SPEEDGAINRIGHT
int gPrecision
the precision for floating point outputs
Definition StdDefs.cpp:26
bool gDebugFlag2
Definition StdDefs.cpp:38
const double SUMO_const_laneWidth
Definition StdDefs.h:48
#define UNUSED_PARAMETER(x)
Definition StdDefs.h:30
T MIN3(T a, T b, T c)
Definition StdDefs.h:89
T MIN2(T a, T b)
Definition StdDefs.h:76
const double SUMO_const_haltingSpeed
the speed threshold at which vehicles are considered as halting
Definition StdDefs.h:58
T MAX2(T a, T b)
Definition StdDefs.h:82
T MAX3(T a, T b, T c)
Definition StdDefs.h:96
std::string toString(const T &t, std::streamsize accuracy=gPrecision)
Definition ToString.h:46
A class responsible for exchanging messages between cars involved in lane-change interaction.
Interface for lane-change models.
double getForwardPos() const
get vehicle position relative to the forward direction lane
virtual void setOwnState(const int state)
int myPreviousState
lane changing state from the previous simulation step
double getManeuverDist() const
Returns the remaining unblocked distance for the current maneuver. (only used by sublane model)
int myOwnState
The current state of the vehicle.
MSLane * getShadowLane() const
Returns the lane the vehicle's shadow is on during continuous/sublane lane change.
double myCommittedSpeed
the speed when committing to a change maneuver
virtual LatAlignmentDefinition getDesiredAlignment() const
static bool myAllowOvertakingRight
whether overtaking on the right is permitted
void addLCSpeedAdvice(const double vSafe, bool ownAdvice=true)
Takes a vSafe (speed advice for speed in the next simulation step), converts it into an acceleration ...
const LaneChangeModel myModel
the type of this model
bool cancelRequest(int state, int laneOffset)
whether the influencer cancels the given request
std::vector< std::pair< double, bool > > myLCAccelerationAdvices
double getMaxSpeedLat2() const
return the max of maxSpeedLat and lcMaxSpeedLatStanding
const MSCFModel & getCarFollowModel() const
The vehicle's car following model.
double mySpeedLat
the current lateral speed
MSVehicle & myVehicle
The vehicle this lane-changer belongs to.
double myLastLateralGapLeft
the minimum lateral gaps to other vehicles that were found when last changing to the left and right
virtual bool debugVehicle() const
whether the current vehicles shall be debugged
virtual double getArrivalPos() const
Returns this vehicle's desired arrivalPos for its current route (may change on reroute)
const SUMOVehicleParameter & getParameter() const
Returns the vehicle's parameter (including departure definition)
double getLength() const
Returns the vehicle's length.
const MSEdge * getEdge() const
Returns the edge the vehicle is currently at.
MSStop & getNextStop()
double getWaitingSeconds() const
Returns the number of seconds waited (speed was lesser than 0.1m/s)
SUMOVehicleClass getVClass() const
Returns the vehicle's access class.
const MSRoute & getRoute() const
Returns the current route.
const MSVehicleType & getVehicleType() const
Returns the vehicle's type definition.
The car-following model abstraction.
Definition MSCFModel.h:55
virtual double maxNextSpeed(double speed, const MSVehicle *const veh) const
Returns the maximum speed given the current speed.
static double gapExtrapolation(const double duration, const double currentGap, double v1, double v2, double a1=0, double a2=0, const double maxV1=std::numeric_limits< double >::max(), const double maxV2=std::numeric_limits< double >::max())
return the resulting gap if, starting with gap currentGap, two vehicles continue with constant accele...
virtual double minNextSpeedEmergency(double speed, const MSVehicle *const veh=0) const
Returns the minimum speed after emergency braking, given the current speed (depends on the numerical ...
virtual double followSpeedTransient(double duration, const MSVehicle *const veh, double speed, double gap2pred, double predSpeed, double predMaxDecel) const
Computes the vehicle's follow speed that avoids a collision for the given amount of time.
double getEmergencyDecel() const
Get the vehicle type's maximal physically possible deceleration [m/s^2].
Definition MSCFModel.h:272
static double brakeGapEuler(const double speed, const double decel, const double headwayTime)
Definition MSCFModel.cpp:90
static double avoidArrivalAccel(double dist, double time, double speed, double maxDecel)
Computes the acceleration needed to arrive not before the given time.
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 void setMaxDecel(double decel)
Sets a new value for maximal comfortable deceleration [m/s^2].
Definition MSCFModel.h:536
@ LANE_CHANGE
the return value is used for lane change calculations
Definition MSCFModel.h:85
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:256
double brakeGap(const double speed) const
Returns the distance the vehicle needs to halt including driver's reaction time tau (i....
Definition MSCFModel.h:380
double getMaxDecel() const
Get the vehicle type's maximal comfortable deceleration [m/s^2].
Definition MSCFModel.h:264
static double estimateArrivalTime(double dist, double speed, double maxSpeed, double accel)
Computes the time needed to travel a distance dist given an initial speed and constant acceleration....
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)
double stopSpeed(const MSVehicle *const veh, const double speed, double gap, const CalcReason usage=CalcReason::CURRENT) const
Computes the vehicle's safe speed for approaching a non-moving obstacle (no dawdling)
Definition MSCFModel.h:168
A road/street connecting two junctions.
Definition MSEdge.h:77
const std::set< MSTransportable *, ComparatorNumericalIdLess > & getPersons() const
Returns this edge's persons set.
Definition MSEdge.h:204
const std::vector< MSLane * > & getLanes() const
Returns this edge's lanes.
Definition MSEdge.h:168
double getInternalFollowingLengthTo(const MSEdge *followerAfterInternal, SUMOVehicleClass vClass) const
returns the length of all internal edges on the junction until reaching the non-internal edge followe...
Definition MSEdge.cpp:922
bool canChangeToOpposite() const
whether this edge allows changing to the opposite direction edge
Definition MSEdge.cpp:1330
bool isInternal() const
return whether this edge is an internal edge
Definition MSEdge.h:268
double getWidth() const
Returns the edges's width (sum over all lanes)
Definition MSEdge.h:656
const std::vector< double > getSubLaneSides() const
Returns the right side offsets of this edge's sublanes.
Definition MSEdge.h:661
static double gLateralResolution
Definition MSGlobals.h:100
static bool gSemiImplicitEulerUpdate
Definition MSGlobals.h:53
static bool gLefthand
Whether lefthand-drive is being simulated.
Definition MSGlobals.h:174
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 updateBlockerLength(const MSVehicle &veh, MSVehicle *blocker, int lcaCounter, double leftSpace, bool reliefConnection, double &leadingBlockerLength)
static bool divergentRoute(const MSVehicle &v1, const MSVehicle &v2)
return whether the vehicles are on the same junction but on divergent paths
double mySafeLatDistRight
the lateral distance the vehicle can safely move in the currently considered direction
static bool overlap(double right, double left, double right2, double left2)
return whether the given intervals overlap
double _patchSpeed(double min, const double wanted, double max, const MSCFModel &cfModel)
double informLeaders(int blocked, int dir, const std::vector< CLeaderDist > &blockers, double remainingSeconds)
double myRoundaboutBonus
void commitManoeuvre(int blocked, int blockedFully, const MSLeaderDistanceInfo &leaders, const MSLeaderDistanceInfo &neighLeaders, const MSLane &neighLane, double maneuverDist)
commit to lane change maneuver potentially overriding safe speed
std::set< const MSVehicle * > myCFRelated
set of vehicles that are in a car-following relationship with ego (leader of followers)
void prepareStep() override
double myKeepRightProbability
double myMinImpatience
double commitFollowSpeed(double speed, double latDist, double secondsToLeaveLane, const MSLeaderDistanceInfo &leaders, double foeOffset) const
compute speed when committing to an urgent change that is safe in regard to leading vehicles
double getLeftBorder(bool checkOpposite=true) const
return current edge width optionally extended by opposite direction lane width
double myChangeProbThresholdRight
double informLeader(int blocked, int dir, const CLeaderDist &neighLead, double remainingSeconds)
double mySafeLatDistLeft
MSLCM_SL2015(MSVehicle &v)
int computeSublaneShift(const MSEdge *prevEdge, const MSEdge *curEdge)
compute shift so that prevSublane + shift = newSublane
double patchSpeed(const double min, const double wanted, const double max, const MSCFModel &cfModel) override
Called to adapt the speed in order to allow a lane change. It uses information on LC-related desired ...
double getSafetyFactor() const override
return factor for modifying the safety constraints of the car-following model
double myCooperativeSpeed
double computeSpeedLat(double latDist, double &maneuverDist, bool urgent) const override
decides the next lateral speed depending on the remaining lane change distance to be covered and upda...
std::vector< double > myExpectedSublaneSpeeds
expected travel speeds on all sublanes on the current edge(!)
double getWidth() const
return the width of this vehicle (padded for numerical stability)
bool myCanChangeFully
whether the current lane changing maneuver can be finished in a single step
void changed() override
int wantsChange(int laneOffset, MSAbstractLaneChangeModel::MSLCMessager &msgPass, int blocked, const std::pair< MSVehicle *, double > &leader, const std::pair< MSVehicle *, double > &follower, const std::pair< MSVehicle *, double > &neighLead, const std::pair< MSVehicle *, double > &neighFollow, const MSLane &neighLane, const std::vector< MSVehicle::LaneQ > &preb, MSVehicle **lastBlocked, MSVehicle **firstBlocked) override
Called to examine whether the vehicle wants to change using the given laneOffset (this is a wrapper a...
double myLaneDiscipline
bool outsideEdge() const
whether the ego vehicle is driving outside edgebounds
bool myDontBrake
flag to prevent speed adaptation by slowing down
std::string getParameter(const std::string &key) const override
try to retrieve the given parameter from this device. Throw exception for unsupported key
bool wantsKeepRight(double keepRightProb) const
check against thresholds
double forecastAverageSpeed(double vSafe, double vMax, double gap, double vLeader) const
estimate average speed over mySpeedGainLookahead time
void updateCFRelated(const MSLeaderDistanceInfo &vehicles, double foeOffset, bool leaders)
find leaders/followers that are already in a car-following relationship with ego
bool debugVehicle() const override
whether the current vehicles shall be debugged
double myAccelLat
int wantsChangeSublane(int laneOffset, LaneChangeAction alternatives, const MSLeaderDistanceInfo &leaders, const MSLeaderDistanceInfo &followers, const MSLeaderDistanceInfo &blockers, const MSLeaderDistanceInfo &neighLeaders, const MSLeaderDistanceInfo &neighFollowers, const MSLeaderDistanceInfo &neighBlockers, const MSLane &neighLane, const std::vector< MSVehicle::LaneQ > &preb, MSVehicle **lastBlocked, MSVehicle **firstBlocked, double &latDist, double &maneuverDist, int &blocked) override
Called to examine whether the vehicle wants to change with the given laneOffset (using the sublane mo...
LatAlignmentDefinition getDesiredAlignment() const override
double mySpeedGainProbabilityRight
a value for tracking the probability that a change to the right is beneficial
double myLookAheadSpeed
int slowDownForBlocked(MSVehicle **blocked, int state)
compute useful slowdowns for blocked vehicles
void initDerivedParameters()
init cached parameters derived directly from model parameters
int keepLatGap(int state, const MSLeaderDistanceInfo &leaders, const MSLeaderDistanceInfo &followers, const MSLeaderDistanceInfo &blockers, const MSLeaderDistanceInfo &neighLeaders, const MSLeaderDistanceInfo &neighFollowers, const MSLeaderDistanceInfo &neighBlockers, const MSLane &neighLane, int laneOffset, double &latDist, double &maneuverDist, int &blocked)
check whether lateral gap requirements are met override the current maneuver if necessary
bool tieBrakeLeader(const MSVehicle *veh) const
bool currentDistAllows(double dist, int laneOffset, double lookForwardDist)
CLeaderDist getLongest(const MSLeaderDistanceInfo &ldi) const
get the longest vehicle in the given info
double myCooperativeParam
double getNeighRight(const MSLane &neighLane) const
return the right offset of the neighboring lane relative to the current edge
double computeSpeedGain(double latDistSublane, double defaultNextSpeed) const
compute speedGain when moving by the given amount
double emergencySpeedLat(double speedLat) const
avoid unsafe lateral speed (overruling lcAccelLat)
double myKeepRightAcceptanceTime
double mySigmaState
void updateGaps(const MSLeaderDistanceInfo &others, double foeOffset, double oldCenter, double gapFactor, double &surplusGapRight, double &surplusGapLeft, bool saveMinGap=false, double netOverlap=0, double latDist=0, std::vector< CLeaderDist > *collectBlockers=0)
check remaining lateral gaps for the given foe vehicles and optionally update minimum lateral gaps
double mySpeedGainParam
virtual void updateSafeLatDist(const double travelledLatDist) override
Updates the value of safe lateral distances (mySafeLatDistLeft and mySafeLatDistRight) during maneuve...
const MSEdge * myLastEdge
expected travel speeds on all sublanes on the current edge(!)
double getOppositeSafetyFactor() const override
return factor for modifying the safety constraints for opposite-diretction overtaking of the car-foll...
int checkStrategicChange(int ret, const MSLane &neighLane, int laneOffset, const MSLeaderDistanceInfo &leaders, const MSLeaderDistanceInfo &neighLeaders, const MSVehicle::LaneQ &curr, const MSVehicle::LaneQ &neigh, const MSVehicle::LaneQ &best, int bestLaneOffset, bool changeToBest, double currentDist, double neighDist, double laDist, double roundaboutBonus, double latLaneDist, bool checkOpposite, double &latDist)
compute strategic lane change actions TODO: Better documentation, refs #2
StateAndDist decideDirection(StateAndDist sd1, StateAndDist sd2) const override
decide in which direction to move in case both directions are desirable
double myImpatience
double myOppositeParam
double myLeftSpace
std::pair< double, int > Info
information regarding save velocity (unused) and state flags of the ego vehicle
void msg(const CLeaderDist &cld, double speed, int state)
send a speed recommendation to the given vehicle
double myLookaheadLeft
int checkBlocking(const MSLane &neighLane, double &latDist, double maneuverDist, int laneOffset, const MSLeaderDistanceInfo &leaders, const MSLeaderDistanceInfo &followers, const MSLeaderDistanceInfo &blockers, const MSLeaderDistanceInfo &neighLeaders, const MSLeaderDistanceInfo &neighFollowers, const MSLeaderDistanceInfo &neighBlockers, std::vector< CLeaderDist > *collectLeadBlockers=0, std::vector< CLeaderDist > *collectFollowBlockers=0, bool keepLatGapManeuver=false, double gapFactor=0, int *retBlockedFully=0)
restrict latDist to permissible speed and determine blocking state depending on that distance
double myStrategicParam
double getVehicleCenter() const
return vehicle position relative to the current edge (extend by another virtual lane for opposite-dir...
int _wantsChangeSublane(int laneOffset, LaneChangeAction alternatives, const MSLeaderDistanceInfo &leaders, const MSLeaderDistanceInfo &followers, const MSLeaderDistanceInfo &blockers, const MSLeaderDistanceInfo &neighLeaders, const MSLeaderDistanceInfo &neighFollowers, const MSLeaderDistanceInfo &neighBlockers, const MSLane &neighLane, const std::vector< MSVehicle::LaneQ > &preb, MSVehicle **lastBlocked, MSVehicle **firstBlocked, double &latDist, double &maneuverDist, int &blocked)
helper function for doing the actual work
double getLateralDrift()
get lateral drift for the current step
double computeGapFactor(int state) const
compute the gap factor for the given state
double getPosLat()
get lateral position of this vehicle
bool preventSliding(double maneuverDist) const
bool isBidi(const MSLane *lane) const
check whether lane is an upcoming bidi lane
bool mustOvertakeStopped(const MSLane &neighLane, const MSLeaderDistanceInfo &leaders, const MSLeaderDistanceInfo &neighLead, double posOnLane, double neighDist, bool right, double latLaneDist, double &currentDist, double &latDist)
void * inform(void *info, MSVehicle *sender) override
double myMinGapLat
void informFollower(int blocked, int dir, const CLeaderDist &neighFollow, double remainingSeconds, double plannedSpeed)
decide whether we will try cut in before the follower or allow to be overtaken
void setParameter(const std::string &key, const std::string &value) override
try to set the given parameter for this laneChangeModel. Throw exception for unsupported key
bool saveBlockerLength(double length, double foeLeftSpace) override
reserve space at the end of the lane to avoid dead locks
double myOvertakeDeltaSpeedFactor
double myTurnAlignmentDist
double myLeadingBlockerLength
void setOwnState(const int state) override
int checkBlockingVehicles(const MSVehicle *ego, const MSLeaderDistanceInfo &vehicles, int laneOffset, double latDist, double foeOffset, bool leaders, double &safeLatGapRight, double &safeLatGapLeft, std::vector< CLeaderDist > *collectBlockers=0) const
check whether any of the vehicles overlaps with ego
void informFollowers(int blocked, int dir, const std::vector< CLeaderDist > &blockers, double remainingSeconds, double plannedSpeed)
call informFollower for multiple followers
double mySpeedGainLookahead
virtual ~MSLCM_SL2015()
double mySpeedLossProbThreshold
void resetState() override
bool myCFRelatedReady
double mySpeedGainProbabilityLeft
a value for tracking the probability that a change to the left is beneficial
double myAssertive
double mySpeedGainRight
static LaneChangeAction getLCA(int state, double latDist)
compute lane change action from desired lateral distance
double myChangeProbThresholdLeft
void updateExpectedSublaneSpeeds(const MSLeaderDistanceInfo &ahead, int sublaneOffset, int laneIndex) override
update expected speeds for each sublane of the current edge
bool currentDistDisallows(double dist, int laneOffset, double lookForwardDist)
double getExtraReservation(int bestLaneOffset) const override
reserve extra space for unseen blockers when more tnan one lane change is required
double myTimeToImpatience
static int lowest_bit(int changeReason)
return the most important change reason
static CLeaderDist getSlowest(const MSLeaderDistanceInfo &ldi)
get the slowest vehicle in the given info
bool amBlockingFollowerPlusNB()
double myKeepRightParam
double mySublaneParam
Representation of a lane in the micro simulation.
Definition MSLane.h:84
std::pair< const MSPerson *, double > nextBlocking(double minPos, double minRight, double maxLeft, double stopTime=0, bool bidi=false) const
This is just a wrapper around MSPModel::nextBlocking. You should always check using hasPedestrians be...
Definition MSLane.cpp:4490
MSLane * getParallelLane(int offset, bool includeOpposite=true) const
Returns the lane with the given offset parallel to this one or 0 if it does not exist.
Definition MSLane.cpp:2773
double getSpeedLimit() const
Returns the lane's maximum allowed speed.
Definition MSLane.h:592
double getLength() const
Returns the lane's length.
Definition MSLane.h:606
bool allowsVehicleClass(SUMOVehicleClass vclass) const
Definition MSLane.h:925
double getVehicleMaxSpeed(const SUMOTrafficObject *const veh) const
Returns the lane's maximum speed, given a vehicle's speed limit adaptation.
Definition MSLane.h:574
double getRightSideOnEdge() const
Definition MSLane.h:1194
bool hasPedestrians() const
whether the lane has pedestrians on it
Definition MSLane.cpp:4483
int getIndex() const
Returns the lane's index.
Definition MSLane.h:642
MSLane * getOpposite() const
return the neighboring opposite direction lane for lane changing or nullptr
Definition MSLane.cpp:4299
MSLane * getBidiLane() const
retrieve bidirectional lane or nullptr
Definition MSLane.cpp:4564
MSLane * getParallelOpposite() const
return the opposite direction lane of this lanes edge or nullptr
Definition MSLane.cpp:4305
MSEdge & getEdge() const
Returns the lane's edge.
Definition MSLane.h:764
const MSLane * getNormalPredecessorLane() const
get normal lane leading to this internal lane, for normal lanes, the lane itself is returned
Definition MSLane.cpp:3160
double getWidth() const
Returns the lane's width.
Definition MSLane.h:635
const std::vector< MSLink * > & getLinkCont() const
returns the container with all links !!!
Definition MSLane.h:724
int getRightmostSublane() const
Definition MSLane.h:1198
saves leader/follower vehicles and their distances relative to an ego vehicle
virtual std::string toString() const
print a debugging representation
bool hasStoppedVehicle() const
whether a stopped vehicle is leader
void getSublaneBorders(int sublane, double latOffset, double &rightSide, double &leftSide) const
int numSublanes() const
bool hasVehicles() const
void getSubLanes(const MSVehicle *veh, double latOffset, int &rightmost, int &leftmost) const
static MSNet * getInstance()
Returns the pointer to the unique instance of MSNet (singleton).
Definition MSNet.cpp:185
SUMOTime getCurrentTimeStep() const
Returns the current simulation step.
Definition MSNet.h:320
const MSEdge * getLastEdge() const
returns the destination edge
Definition MSRoute.cpp:91
const MSLane * lane
The lane to stop at (microsim only)
Definition MSStop.h:50
double getLatDist() const
Definition MSVehicle.h:1580
double changeRequestRemainingSeconds(const SUMOTime currentTime) const
Return the remaining number of seconds of the current laneTimeLine assuming one exists.
bool ignoreOverlap() const
Definition MSVehicle.h:1588
Representation of a vehicle in the micro simulation.
Definition MSVehicle.h:77
double getRightSideOnEdge(const MSLane *lane=0) const
Get the vehicle's lateral position on the edge of the given lane (or its current edge if lane == 0)
double getLeftSideOnEdge(const MSLane *lane=0) const
Get the vehicle's lateral position on the edge of the given lane (or its current edge if lane == 0)
bool isActive() const
Returns whether the current simulation step is an action point for the vehicle.
Definition MSVehicle.h:628
const std::pair< double, const MSLink * > & getNextTurn()
Get the distance and direction of the next upcoming turn for the vehicle (within its look-ahead range...
Definition MSVehicle.h:823
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
int influenceChangeDecision(int state)
allow TraCI to influence a lane change decision
double nextStopDist() const
return the distance to the next stop or doubleMax if there is none.
Definition MSVehicle.h:1031
double getAcceleration() const
Returns the vehicle's acceleration in m/s (this is computed as the last step's mean acceleration in c...
Definition MSVehicle.h:514
const std::vector< MSLane * > & getBestLanesContinuation() const
Returns the best sequence of lanes to continue the route starting at myLane.
int getBestLaneOffset() const
double lateralDistanceToLane(const int offset) const
Get the minimal lateral distance required to move fully onto the lane at given offset.
const MSLane * getLane() const
Returns the lane the vehicle is on.
Definition MSVehicle.h:581
double getLastStepDist() const
Get the distance the vehicle covered in the previous timestep.
Definition MSVehicle.h:381
Influencer & getInfluencer()
double getLateralPositionOnLane() const
Get the vehicle's lateral position on the lane.
Definition MSVehicle.h:413
bool congested() const
double getSpeed() const
Returns the vehicle's current speed.
Definition MSVehicle.h:490
const std::vector< LaneQ > & getBestLanes() const
Returns the description of best lanes to use in order to continue the route.
const MSCFModel & getCarFollowModel() const
Returns the vehicle's car following model definition.
Definition MSVehicle.h:965
double getPositionOnLane() const
Get the vehicle's position along the lane.
Definition MSVehicle.h:374
double getLateralOverlap() const
return the amount by which the vehicle extends laterally outside it's primary lane
bool hasInfluencer() const
whether the vehicle is individually influenced (via TraCI or special parameters)
Definition MSVehicle.h:1676
double getCenterOnEdge(const MSLane *lane=0) const
Get the vehicle's lateral position on the edge of the given lane (or its current edge if lane == 0)
double getLengthWithGap() const
Get vehicle's length including the minimum gap [m].
double getWidth() const
Get the width which vehicles of this class shall have when being drawn.
SUMOVehicleClass getVehicleClass() const
Get this vehicle type's vehicle class.
const LatAlignmentDefinition & getPreferredLateralAlignment() const
Get vehicle's preferred lateral alignment procedure.
double getMinGap() const
Get the free space in front of vehicles of this class.
double getMaxSpeedLat() const
Get vehicle's maximum lateral speed [m/s].
double getLength() const
Get vehicle's length [m].
double getPreferredLateralAlignmentOffset() const
Get vehicle's preferred lateral alignment offset (in m from center line)
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:67
const std::string & getID() const
Returns the id.
Definition Named.h:74
void step(double dt)
evolve for a time step of length dt.
double arrivalPosLat
(optional) The lateral position the vehicle shall arrive on
ArrivalPosLatDefinition arrivalPosLatProcedure
Information how the vehicle shall choose the lateral arrival position.
static double toDouble(const std::string &sData)
converts a string into the double value described by it by calling the char-type converter
#define DEBUG_COND
Definition json.hpp:4471
NLOHMANN_BASIC_JSON_TPL_DECLARATION void swap(nlohmann::NLOHMANN_BASIC_JSON_TPL &j1, nlohmann::NLOHMANN_BASIC_JSON_TPL &j2) noexcept(//NOLINT(readability-inconsistent-declaration-parameter-name) is_nothrow_move_constructible< nlohmann::NLOHMANN_BASIC_JSON_TPL >::value &&//NOLINT(misc-redundant-expression) is_nothrow_move_assignable< nlohmann::NLOHMANN_BASIC_JSON_TPL >::value)
exchanges the values of two JSON objects
Definition json.hpp:21884
bool sameDirection(const StateAndDist &other) const
A structure representing the best lanes for continuing the current route starting at 'lane'.
Definition MSVehicle.h:853
double length
The overall length which may be driven when using this lane without a lane change.
Definition MSVehicle.h:857
std::vector< MSLane * > bestContinuations
Definition MSVehicle.h:873
MSLane * lane
The described lane.
Definition MSVehicle.h:855
int bestLaneOffset
The (signed) number of lanes to be crossed to get to the lane which allows to continue the drive.
Definition MSVehicle.h:865
double occupation
The overall vehicle sum on consecutive lanes which can be passed without a lane change.
Definition MSVehicle.h:861