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