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 LOOK_FORWARD 10.
41
42#define JAM_FACTOR 1.
43
44#define LCA_RIGHT_IMPATIENCE -1.
45#define CUT_IN_LEFT_SPEED_THRESHOLD 27.
46#define MAX_ONRAMP_LENGTH 200.
47
48#define LOOK_AHEAD_MIN_SPEED 0.0
49#define LOOK_AHEAD_SPEED_MEMORY 0.9
50
51#define HELP_DECEL_FACTOR 1.0
52
53#define HELP_OVERTAKE (10.0 / 3.6)
54#define MIN_FALLBEHIND (7.0 / 3.6)
55
56#define URGENCY 2.0
57
58#define KEEP_RIGHT_TIME 5.0 // the number of seconds after which a vehicle should move to the right lane
59
60#define RELGAIN_NORMALIZATION_MIN_SPEED 10.0
61
62#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
63#define GAIN_PERCEPTION_THRESHOLD 0.05 // the minimum relative speed gain which affects the behavior
64
65#define ARRIVALPOS_LAT_THRESHOLD 100.0
66
67// the speed at which the desired lateral gap grows now further
68#define LATGAP_SPEED_THRESHOLD (50 / 3.6)
69// the speed at which the desired lateral gap shrinks now further.
70// @note: when setting LATGAP_SPEED_THRESHOLD = LATGAP_SPEED_THRESHOLD2, no speed-specif reduction of minGapLat is done
71#define LATGAP_SPEED_THRESHOLD2 (50 / 3.6)
72
73// intention to change decays over time
74#define SPEEDGAIN_DECAY_FACTOR 0.5
75// exponential averaging factor for expected sublane speeds
76#define SPEEDGAIN_MEMORY_FACTOR 0.5
77
78#define REACT_TO_STOPPED_DISTANCE 100
79
80
81// ===========================================================================
82// Debug flags
83// ===========================================================================
84//#define DEBUG_MANEUVER
85//#define DEBUG_WANTSCHANGE
86//#define DEBUG_DECISION
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) {
342 double space = myLeftSpace - myLeadingBlockerLength - POSITION_EPS;
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) {
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
850 space -= myLeadingBlockerLength - POSITION_EPS - myVehicle.getVehicleType().getMinGap();
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;
1032#if defined(DEBUG_MANEUVER) || defined(DEBUG_STATE)
1033 if (DEBUG_COND) {
1034 std::cout << SIMTIME << " veh=" << myVehicle.getID() << " changed()\n";
1035 }
1036#endif
1037}
1038
1039
1040void
1052
1053
1054int
1056 int laneOffset,
1057 LaneChangeAction alternatives,
1058 const MSLeaderDistanceInfo& leaders,
1059 const MSLeaderDistanceInfo& followers,
1060 const MSLeaderDistanceInfo& blockers,
1061 const MSLeaderDistanceInfo& neighLeaders,
1062 const MSLeaderDistanceInfo& neighFollowers,
1063 const MSLeaderDistanceInfo& neighBlockers,
1064 const MSLane& neighLane,
1065 const std::vector<MSVehicle::LaneQ>& preb,
1066 MSVehicle** lastBlocked,
1067 MSVehicle** firstBlocked,
1068 double& latDist, double& maneuverDist, int& blocked) {
1069
1070 if (laneOffset != 0) {
1071 // update mySafeLatDist w.r.t. the direction being checkd
1072 const double halfWidth = getWidth() * 0.5;
1073 double center = getVehicleCenter();
1074 if (laneOffset < 0) {
1075 mySafeLatDistRight = center - halfWidth;
1076 } else {
1077 mySafeLatDistLeft = getLeftBorder() - center - halfWidth;
1078 }
1079 }
1080
1081 const SUMOTime currentTime = MSNet::getInstance()->getCurrentTimeStep();
1082 // compute bestLaneOffset
1083 MSVehicle::LaneQ curr, neigh, best;
1084 int bestLaneOffset = 0;
1085 double currentDist = 0;
1086 double neighDist = 0;
1087 const MSLane* prebLane = myVehicle.getLane();
1088 if (prebLane->getEdge().isInternal()) {
1089 // internal edges are not kept inside the bestLanes structure
1090 if (isOpposite()) {
1091 prebLane = prebLane->getNormalPredecessorLane();
1092 } else {
1093 prebLane = prebLane->getLinkCont()[0]->getLane();
1094 }
1095 }
1096 // special case: vehicle considers changing to the opposite direction edge
1097 const bool checkOpposite = &neighLane.getEdge() != &myVehicle.getLane()->getEdge();
1098 const int prebOffset = (checkOpposite ? 0 : laneOffset);
1099 for (int p = 0; p < (int) preb.size(); ++p) {
1100 if (preb[p].lane == prebLane && p + laneOffset >= 0) {
1101 assert(p + prebOffset < (int)preb.size());
1102 curr = preb[p];
1103 neigh = preb[p + prebOffset];
1104 currentDist = curr.length;
1105 neighDist = neigh.length;
1106 bestLaneOffset = curr.bestLaneOffset;
1107 // VARIANT_13 (equalBest)
1108 if (bestLaneOffset == 0 && preb[p + prebOffset].bestLaneOffset == 0 && !checkOpposite) {
1109#ifdef DEBUG_WANTSCHANGE
1110 if (gDebugFlag2) {
1111 std::cout << STEPS2TIME(currentTime)
1112 << " veh=" << myVehicle.getID()
1113 << " bestLaneOffsetOld=" << bestLaneOffset
1114 << " bestLaneOffsetNew=" << laneOffset
1115 << "\n";
1116 }
1117#endif
1118 bestLaneOffset = prebOffset;
1119 }
1120 best = preb[p + bestLaneOffset];
1121 break;
1122 }
1123 }
1124 assert(curr.lane != nullptr);
1125 assert(neigh.lane != nullptr);
1126 assert(best.lane != nullptr);
1127 double driveToNextStop = -std::numeric_limits<double>::max();
1128 UNUSED_PARAMETER(driveToNextStop); // XXX use when computing usableDist
1129 if (myVehicle.nextStopDist() < std::numeric_limits<double>::max()
1131 // vehicle can always drive up to stop distance
1132 // @note this information is dynamic and thus not available in updateBestLanes()
1133 // @note: nextStopDist was compute before the vehicle moved
1134 driveToNextStop = myVehicle.nextStopDist();
1135 const double stopPos = getForwardPos() + myVehicle.nextStopDist() - myVehicle.getLastStepDist();
1136#ifdef DEBUG_WANTS_CHANGE
1137 if (DEBUG_COND) {
1138 std::cout << SIMTIME << std::setprecision(gPrecision) << " veh=" << myVehicle.getID()
1139 << " stopDist=" << myVehicle.nextStopDist()
1140 << " lastDist=" << myVehicle.getLastStepDist()
1141 << " stopPos=" << stopPos
1142 << " currentDist=" << currentDist
1143 << " neighDist=" << neighDist
1144 << "\n";
1145 }
1146#endif
1147 currentDist = MAX2(currentDist, stopPos);
1148 neighDist = MAX2(neighDist, stopPos);
1149 }
1150 // direction specific constants
1151 const bool right = (laneOffset == -1);
1152 const bool left = (laneOffset == 1);
1153 const int myLca = (right ? LCA_MRIGHT : (left ? LCA_MLEFT : 0));
1154 const int lcaCounter = (right ? LCA_LEFT : (left ? LCA_RIGHT : LCA_NONE));
1155 const bool changeToBest = (right && bestLaneOffset < 0) || (left && bestLaneOffset > 0) || (laneOffset == 0 && bestLaneOffset == 0);
1156 // keep information about being a leader/follower but remove information
1157 // about previous lane change request or urgency
1158 int ret = (myOwnState & 0xffff0000);
1159
1160 // compute the distance when changing to the neighboring lane
1161 // (ensure we do not lap into the line behind neighLane since there might be unseen blockers)
1162 // minimum distance to move the vehicle fully onto the new lane
1163 double latLaneDist = laneOffset == 0 ? 0. : myVehicle.lateralDistanceToLane(laneOffset);
1164
1165 // VARIANT_5 (disableAMBACKBLOCKER1)
1166 /*
1167 if (leader.first != 0
1168 && (myOwnState & LCA_AMBLOCKINGFOLLOWER_DONTBRAKE) != 0
1169 && (leader.first->getLaneChangeModel().getOwnState() & LCA_AMBLOCKINGFOLLOWER_DONTBRAKE) != 0) {
1170
1171 myOwnState &= (0xffffffff - LCA_AMBLOCKINGFOLLOWER_DONTBRAKE);
1172 if (myVehicle.getSpeed() > SUMO_const_haltingSpeed) {
1173 myOwnState |= LCA_AMBACKBLOCKER;
1174 } else {
1175 ret |= LCA_AMBACKBLOCKER;
1176 myDontBrake = true;
1177 }
1178 }
1179 */
1180
1181#ifdef DEBUG_WANTSCHANGE
1182 if (gDebugFlag2) {
1183 std::cout << STEPS2TIME(currentTime)
1184 << " veh=" << myVehicle.getID()
1185 << " myState=" << toString((LaneChangeAction)myOwnState)
1186 << " firstBlocked=" << Named::getIDSecure(*firstBlocked)
1187 << " lastBlocked=" << Named::getIDSecure(*lastBlocked)
1188 << "\n leaders=" << leaders.toString()
1189 << "\n followers=" << followers.toString()
1190 << "\n blockers=" << blockers.toString()
1191 << "\n neighLeaders=" << neighLeaders.toString()
1192 << "\n neighFollowers=" << neighFollowers.toString()
1193 << "\n neighBlockers=" << neighBlockers.toString()
1194 << "\n changeToBest=" << changeToBest
1195 << " latLaneDist=" << latLaneDist
1196 << " alts=" << toString((LaneChangeAction)alternatives)
1197 << "\n expectedSpeeds=" << toString(myExpectedSublaneSpeeds)
1198 << std::endl;
1199 }
1200#endif
1201
1202 ret = slowDownForBlocked(lastBlocked, ret);
1203 // VARIANT_14 (furtherBlock)
1204 if (lastBlocked != firstBlocked) {
1205 ret = slowDownForBlocked(firstBlocked, ret);
1206 }
1207
1208
1209 // we try to estimate the distance which is necessary to get on a lane
1210 // we have to get on in order to keep our route
1211 // we assume we need something that depends on our velocity
1212 // and compare this with the free space on our wished lane
1213 //
1214 // if the free space is somehow less than the space we need, we should
1215 // definitely try to get to the desired lane
1216 //
1217 // this rule forces our vehicle to change the lane if a lane changing is necessary soon
1218 // lookAheadDistance:
1219 // we do not want the lookahead distance to change all the time so we discrectize the speed a bit
1220
1221 // VARIANT_18 (laHyst)
1224 } else {
1225 // FIXME: This strongly dependent on the value of TS, see LC2013 for the fix (l.1153, currently)
1228 }
1229 //myLookAheadSpeed = myVehicle.getLane()->getVehicleMaxSpeed(&myVehicle);
1230
1231 //double laDist = laSpeed > LOOK_FORWARD_SPEED_DIVIDER
1232 // ? laSpeed * LOOK_FORWARD_FAR
1233 // : laSpeed * LOOK_FORWARD_NEAR;
1234 double laDist = myLookAheadSpeed * LOOK_FORWARD * myStrategicParam * (right ? 1 : myLookaheadLeft);
1235 laDist += myVehicle.getVehicleType().getLengthWithGap() * 2.;
1236 // aggressive drivers may elect to use reduced strategic lookahead to optimize speed
1237 /*
1238 if (mySpeedGainProbabilityRight > myChangeProbThresholdRight
1239 || mySpeedGainProbabilityLeft > myChangeProbThresholdLeft) {
1240 laDist *= MAX2(0.0, (1 - myPushy));
1241 laDist *= MAX2(0,0, (1 - myAssertive));
1242 laDist *= MAX2(0,0, (2 - mySpeedGainParam));
1243 }
1244 */
1245
1246 // react to a stopped leader on the current lane
1247 if (bestLaneOffset == 0 && leaders.hasStoppedVehicle()) {
1248 // value is doubled for the check since we change back and forth
1249 // laDist = 0.5 * (myVehicle.getVehicleType().getLengthWithGap() + leader.first->getVehicleType().getLengthWithGap());
1250 // XXX determine length of longest stopped vehicle
1252 } else if (checkOpposite && isOpposite() && neighLeaders.hasStoppedVehicle()) {
1253 // compute exact distance to overtake stopped vehicle
1254 laDist = 0;
1255 for (int i = 0; i < neighLeaders.numSublanes(); ++i) {
1256 CLeaderDist vehDist = neighLeaders[i];
1257 if (vehDist.first != nullptr && vehDist.first->isStopped()) {
1258 laDist = MAX2(laDist, myVehicle.getVehicleType().getMinGap() + vehDist.second + vehDist.first->getVehicleType().getLengthWithGap());
1259 }
1260 }
1261 laDist += myVehicle.getVehicleType().getLength();
1262 }
1263 if (myStrategicParam < 0) {
1264 laDist = -1e3; // never perform strategic change
1265 }
1266
1267 // free space that is available for changing
1268 //const double neighSpeed = (neighLead.first != 0 ? neighLead.first->getSpeed() :
1269 // neighFollow.first != 0 ? neighFollow.first->getSpeed() :
1270 // best.lane->getSpeedLimit());
1271 // @note: while this lets vehicles change earlier into the correct direction
1272 // it also makes the vehicles more "selfish" and prevents changes which are necessary to help others
1273
1274 const double roundaboutBonus = MSLCHelper::getRoundaboutDistBonus(myVehicle, myRoundaboutBonus, curr, neigh, best);
1275 currentDist += roundaboutBonus;
1276 neighDist += roundaboutBonus;
1277
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 - POSITION_EPS, 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 - POSITION_EPS, canContinue, myLeadingBlockerLength);
1331 if (*firstBlocked != neighLeadLongest && tieBrakeLeader(*firstBlocked)) {
1332 canReserve &= MSLCHelper::updateBlockerLength(myVehicle, *firstBlocked, lcaCounter, myLeftSpace - POSITION_EPS, 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 double currentLatDist = sublaneSides[i] - rightVehSide;
1583 if ((laneOffset == 0 && (currentLatDist > maxLatDist || currentLatDist < minLatDist))
1584 || (laneOffset < 0 && currentLatDist > maxLatDist)
1585 || (laneOffset > 0 && currentLatDist < minLatDist)) {
1586#ifdef DEBUG_WANTSCHANGE
1587 if (gDebugFlag2) {
1588 std::cout << " i=" << i << " currentLatDist=" << currentLatDist << " outOfBounds\n";
1589 }
1590#endif
1591 continue;
1592 }
1593 currentLatDist = MIN2(MAX2(currentLatDist, minLatDist), maxLatDist);
1594 if (currentLatDist > 0 && myVehicle.getLane()->getBidiLane() != nullptr) {
1595 // penalize overtaking on the left if the lane is used in both
1596 // directions
1597 relativeGain *= 0.5;
1598 }
1599 // @note only consider change if it is compatible with the current direction (same sign or laneOffset == 0)
1600 if (relativeGain > maxGain && currentLatDist * laneOffset >= 0) {
1601 maxGain = relativeGain;
1602 if (maxGain > GAIN_PERCEPTION_THRESHOLD) {
1603 sublaneCompact = i;
1604 latDist = currentLatDist;
1605#ifdef DEBUG_WANTSCHANGE
1606 if (gDebugFlag2) {
1607 std::cout << " i=" << i << " vMin=" << vMin << " newLatDist=" << latDist << " relGain=" << relativeGain << "\n";
1608 }
1609#endif
1610 }
1611 } else {
1612 // if anticipated gains to the left are higher then to the right and current gains are equal, prefer left
1613 if (currentLatDist > 0
1614 //&& latDist < 0 // #7184 compensates for #7185
1616 && relativeGain > GAIN_PERCEPTION_THRESHOLD
1617 && maxGain - relativeGain < NUMERICAL_EPS) {
1618 latDist = currentLatDist;
1619 }
1620 }
1621#ifdef DEBUG_WANTSCHANGE
1622 if (gDebugFlag2) {
1623 std::cout << " i=" << i << " rightmostOnEdge=" << rightmostOnEdge << " vMin=" << vMin << " relGain=" << relativeGain << " sublaneCompact=" << sublaneCompact << " curLatDist=" << currentLatDist << "\n";
1624 }
1625#endif
1626 if (currentLatDist < -NUMERICAL_EPS * myVehicle.getActionStepLengthSecs()) {
1627 maxGainRight = MAX2(maxGainRight, relativeGain);
1628 } else if (currentLatDist > NUMERICAL_EPS * myVehicle.getActionStepLengthSecs()) {
1629 maxGainLeft = MAX2(maxGainLeft, relativeGain);
1630 }
1631 const double subAlignDist = sublaneSides[i] - rightVehSide;
1632 if (fabs(subAlignDist) < fabs(latDistNice)) {
1633 latDistNice = subAlignDist;
1634#ifdef DEBUG_WANTSCHANGE
1635 if (gDebugFlag2) std::cout
1636 << " nicest sublane=" << i
1637 << " side=" << sublaneSides[i]
1638 << " rightSide=" << rightVehSide
1639 << " latDistNice=" << latDistNice
1640 << " maxGainR=" << (maxGainRight == -std::numeric_limits<double>::max() ? "n/a" : toString(maxGainRight))
1641 << " maxGainL=" << (maxGainLeft == -std::numeric_limits<double>::max() ? "n/a" : toString(maxGainLeft))
1642 << "\n";
1643#endif
1644 }
1645 }
1646 }
1647 // updated change probabilities
1648 if (maxGainRight != -std::numeric_limits<double>::max()) {
1649#ifdef DEBUG_WANTSCHANGE
1650 if (gDebugFlag2) {
1651 std::cout << " speedGainR_old=" << mySpeedGainProbabilityRight;
1652 }
1653#endif
1655#ifdef DEBUG_WANTSCHANGE
1656 if (gDebugFlag2) {
1657 std::cout << " speedGainR_new=" << mySpeedGainProbabilityRight << "\n";
1658 }
1659#endif
1660 }
1661 if (maxGainLeft != -std::numeric_limits<double>::max()) {
1662#ifdef DEBUG_WANTSCHANGE
1663 if (gDebugFlag2) {
1664 std::cout << " speedGainL_old=" << mySpeedGainProbabilityLeft;
1665 }
1666#endif
1668#ifdef DEBUG_WANTSCHANGE
1669 if (gDebugFlag2) {
1670 std::cout << " speedGainL_new=" << mySpeedGainProbabilityLeft << "\n";
1671 }
1672#endif
1673 }
1674 // decay if there is no reason for or against changing (only if we have enough information)
1675 if ((fabs(maxGainRight) < NUMERICAL_EPS || maxGainRight == -std::numeric_limits<double>::max())
1676 && (right || (alternatives & LCA_RIGHT) == 0)) {
1678 }
1679 if ((fabs(maxGainLeft) < NUMERICAL_EPS || maxGainLeft == -std::numeric_limits<double>::max())
1680 && (left || (alternatives & LCA_LEFT) == 0)) {
1682 }
1683
1684
1685#ifdef DEBUG_WANTSCHANGE
1686 if (gDebugFlag2) std::cout << SIMTIME
1687 << " veh=" << myVehicle.getID()
1688 << " defaultNextSpeed=" << defaultNextSpeed
1689 << " maxGain=" << maxGain
1690 << " maxGainRight=" << maxGainRight
1691 << " maxGainLeft=" << maxGainLeft
1692 << " probRight=" << mySpeedGainProbabilityRight
1693 << " probLeft=" << mySpeedGainProbabilityLeft
1694 << " latDist=" << latDist
1695 << " latDistNice=" << latDistNice
1696 << " sublaneCompact=" << sublaneCompact
1697 << "\n";
1698#endif
1699
1700 if (!left) {
1701 // ONLY FOR CHANGING TO THE RIGHT
1702 // start keepRight maneuver when no speed loss is expected and continue
1703 // started maneuvers if the loss isn't too big
1704 if (right && myVehicle.getSpeed() > 0 && (maxGainRight >= 0
1705 || ((myPreviousState & LCA_KEEPRIGHT) != 0 && maxGainRight >= -myKeepRightParam))) {
1706 // honor the obligation to keep right (Rechtsfahrgebot)
1707 const double vMax = myVehicle.getLane()->getVehicleMaxSpeed(&myVehicle);
1708 const double roadSpeedFactor = vMax / myVehicle.getLane()->getSpeedLimit(); // differse from speedFactor if vMax < speedLimit
1709 double acceptanceTime;
1710 if (myKeepRightAcceptanceTime == -1) {
1711 // legacy behavior: scale acceptance time with current speed and
1712 // use old hard-coded constant
1713 acceptanceTime = 7 * roadSpeedFactor * MAX2(1.0, myVehicle.getSpeed());
1714 } else {
1715 acceptanceTime = myKeepRightAcceptanceTime * roadSpeedFactor;
1716 if (followers.hasVehicles()) {
1717 // reduce acceptanceTime if a follower vehicle is faster or wants to drive faster
1718 double minFactor = 1.0;
1719 for (int i = 0; i < followers.numSublanes(); ++i) {
1720 CLeaderDist follower = followers[i];
1721 if (follower.first != nullptr && follower.second < 2 * follower.first->getCarFollowModel().brakeGap(follower.first->getSpeed())) {
1722 if (follower.first->getSpeed() >= myVehicle.getSpeed()) {
1723 double factor = MAX2(1.0, myVehicle.getSpeed()) / MAX2(1.0, follower.first->getSpeed());
1724 const double fRSF = follower.first->getLane()->getVehicleMaxSpeed(follower.first) / follower.first->getLane()->getSpeedLimit();
1725 if (fRSF > roadSpeedFactor) {
1726 factor /= fRSF;
1727 }
1728 if (factor < minFactor) {
1729 minFactor = factor;
1730 }
1731 }
1732 }
1733 }
1734 acceptanceTime *= minFactor;
1735 }
1736 }
1737 double fullSpeedGap = MAX2(0., neighDist - myVehicle.getCarFollowModel().brakeGap(vMax));
1738 double fullSpeedDrivingSeconds = MIN2(acceptanceTime, fullSpeedGap / vMax);
1739 CLeaderDist neighLead = getSlowest(neighLeaders);
1740 if (neighLead.first != 0 && neighLead.first->getSpeed() < vMax) {
1741 fullSpeedGap = MAX2(0., MIN2(fullSpeedGap,
1742 neighLead.second - myVehicle.getCarFollowModel().getSecureGap(&myVehicle, neighLead.first,
1743 vMax, neighLead.first->getSpeed(), neighLead.first->getCarFollowModel().getMaxDecel())));
1744 fullSpeedDrivingSeconds = MIN2(fullSpeedDrivingSeconds, fullSpeedGap / (vMax - neighLead.first->getSpeed()));
1745 }
1746 const double deltaProb = (myChangeProbThresholdRight * (fullSpeedDrivingSeconds / acceptanceTime) / KEEP_RIGHT_TIME) * myVehicle.getActionStepLengthSecs();
1747 const bool isSlide = preventSliding(latLaneDist);
1748 // stay below threshold
1749 if (!isSlide || !wantsKeepRight(myKeepRightProbability + deltaProb)) {
1750 myKeepRightProbability += deltaProb;
1751 }
1752
1753#ifdef DEBUG_WANTSCHANGE
1754 if (gDebugFlag2) {
1755 std::cout << STEPS2TIME(currentTime)
1756 << " considering keepRight:"
1757 << " vMax=" << vMax
1758 << " neighDist=" << neighDist
1759 << " brakeGap=" << myVehicle.getCarFollowModel().brakeGap(myVehicle.getSpeed())
1760 << " leaderSpeed=" << (neighLead.first == 0 ? -1 : neighLead.first->getSpeed())
1761 << " secGap=" << (neighLead.first == 0 ? -1 : myVehicle.getCarFollowModel().getSecureGap(&myVehicle, neighLead.first,
1762 myVehicle.getSpeed(), neighLead.first->getSpeed(), neighLead.first->getCarFollowModel().getMaxDecel()))
1763 << " acceptanceTime=" << acceptanceTime
1764 << " fullSpeedGap=" << fullSpeedGap
1765 << " fullSpeedDrivingSeconds=" << fullSpeedDrivingSeconds
1766 << " dProb=" << deltaProb
1767 << " isSlide=" << isSlide
1768 << " keepRight=" << myKeepRightProbability
1769 << " speedGainL=" << mySpeedGainProbabilityLeft
1770 << "\n";
1771 }
1772#endif
1774 /*&& latLaneDist <= -NUMERICAL_EPS * myVehicle.getActionStepLengthSecs()*/) {
1775 ret |= LCA_KEEPRIGHT;
1776 assert(myVehicle.getLane()->getIndex() > neighLane.getIndex() || isOpposite());
1777 if (!cancelRequest(ret | LCA_RIGHT, laneOffset)) {
1778 latDist = latLaneDist;
1779 maneuverDist = latLaneDist;
1780 blocked = checkBlocking(neighLane, latDist, maneuverDist, laneOffset,
1781 leaders, followers, blockers,
1782 neighLeaders, neighFollowers, neighBlockers);
1783 return ret;
1784 } else {
1785 ret &= ~LCA_KEEPRIGHT;
1786 }
1787 }
1788 }
1789
1790 const double bidiRightFactor = myVehicle.getLane()->getBidiLane() == nullptr && !isOpposite() ? 1 : 0.05;
1791#ifdef DEBUG_WANTSCHANGE
1792 if (gDebugFlag2) {
1793 std::cout << STEPS2TIME(currentTime)
1794 << " speedGainR=" << mySpeedGainProbabilityRight
1795 << " speedGainL=" << mySpeedGainProbabilityLeft
1796 << " neighDist=" << neighDist
1797 << " neighTime=" << neighDist / MAX2(.1, myVehicle.getSpeed())
1798 << " rThresh=" << myChangeProbThresholdRight
1799 << " rThresh2=" << myChangeProbThresholdRight* bidiRightFactor
1800 << " latDist=" << latDist
1801 << "\n";
1802 }
1803#endif
1804
1805 // make changing on the right more attractive on bidi edges
1806 if (latDist < 0 && mySpeedGainProbabilityRight >= myChangeProbThresholdRight * bidiRightFactor
1807 && neighDist / MAX2(.1, myVehicle.getSpeed()) > mySpeedGainRemainTime) {
1808 ret |= LCA_SPEEDGAIN;
1809 if (!cancelRequest(ret | getLCA(ret, latDist), laneOffset)) {
1810 int blockedFully = 0;
1811 maneuverDist = latDist;
1812 blocked = checkBlocking(neighLane, latDist, maneuverDist, laneOffset,
1813 leaders, followers, blockers,
1814 neighLeaders, neighFollowers, neighBlockers,
1815 nullptr, nullptr, false, 0, &blockedFully);
1816 //commitManoeuvre(blocked, blockedFully, leaders, neighLeaders, neighLane);
1817 return ret;
1818 } else {
1819 // @note: restore ret so subsequent calls to cancelRequest work correctly
1820 latDist = 0;
1821 ret &= ~LCA_SPEEDGAIN;
1822 }
1823 }
1824 }
1825 if (!right || isOpposite()) {
1826
1827 const bool stayInLane = myVehicle.getLateralPositionOnLane() + latDist < 0.5 * myVehicle.getLane()->getWidth();
1828#ifdef DEBUG_WANTSCHANGE
1829 if (gDebugFlag2) {
1830 std::cout << STEPS2TIME(currentTime)
1831 << " speedGainL=" << mySpeedGainProbabilityLeft
1832 << " speedGainR=" << mySpeedGainProbabilityRight
1833 << " latDist=" << latDist
1834 << " neighDist=" << neighDist
1835 << " neighTime=" << neighDist / MAX2(.1, myVehicle.getSpeed())
1836 << " lThresh=" << myChangeProbThresholdLeft
1837 << " stayInLane=" << stayInLane
1838 << "\n";
1839 }
1840#endif
1841
1843 // if we leave our lane, we should be able to stay in the new
1844 // lane for some time
1845 (stayInLane || neighDist / MAX2(.1, myVehicle.getSpeed()) > mySpeedGainRemainTime)) {
1846 ret |= LCA_SPEEDGAIN;
1847 if (!cancelRequest(ret + getLCA(ret, latDist), laneOffset)) {
1848 int blockedFully = 0;
1849 maneuverDist = latDist;
1850 blocked = checkBlocking(neighLane, latDist, maneuverDist, laneOffset,
1851 leaders, followers, blockers,
1852 neighLeaders, neighFollowers, neighBlockers,
1853 nullptr, nullptr, false, 0, &blockedFully);
1854 //commitManoeuvre(blocked, blockedFully, leaders, neighLeaders, neighLane);
1855 return ret;
1856 } else {
1857 latDist = 0;
1858 ret &= ~LCA_SPEEDGAIN;
1859 }
1860 }
1861 }
1862
1863 double latDistSublane = 0.;
1864 const double halfLaneWidth = myVehicle.getLane()->getWidth() * 0.5;
1865 const double halfVehWidth = getWidth() * 0.5;
1868 && bestLaneOffset == 0
1870 // vehicle is on its final edge, on the correct lane and close to
1871 // its arrival position. Change to the desired lateral position
1875 break;
1877 latDistSublane = -halfLaneWidth + halfVehWidth - myVehicle.getLateralPositionOnLane();
1878 break;
1880 latDistSublane = -myVehicle.getLateralPositionOnLane();
1881 break;
1883 latDistSublane = halfLaneWidth - halfVehWidth - myVehicle.getLateralPositionOnLane();
1884 break;
1885 default:
1886 assert(false);
1887 }
1888#ifdef DEBUG_WANTSCHANGE
1889 if (gDebugFlag2) std::cout << SIMTIME
1890 << " arrivalPosLatProcedure=" << (int)myVehicle.getParameter().arrivalPosLatProcedure
1891 << " arrivalPosLat=" << myVehicle.getParameter().arrivalPosLat << "\n";
1892#endif
1893
1894 } else {
1895
1897 switch (align) {
1899 latDistSublane = -halfLaneWidth + halfVehWidth - getPosLat();
1900 break;
1902 latDistSublane = halfLaneWidth - halfVehWidth - getPosLat();
1903 break;
1906 latDistSublane = -getPosLat();
1907 break;
1909 latDistSublane = latDistNice;
1910 break;
1912 latDistSublane = sublaneSides[sublaneCompact] - rightVehSide;
1913 break;
1915 latDistSublane = myVehicle.getLateralPositionOnLane() - getPosLat();
1916 const double hLW = myVehicle.getLane()->getWidth() * 0.5;
1917 const double posLat = myVehicle.getLateralPositionOnLane();
1918 if (fabs(posLat) > hLW) {
1919 // vehicle is not within it's current lane
1920 if (posLat > 0) {
1921 latDistSublane -= (posLat - hLW);
1922 } else {
1923 latDistSublane += (-posLat - hLW);
1924 }
1925 } else {
1926 const double edgeWidth = myVehicle.getCurrentEdge()->getWidth();
1927 if (getWidth() < edgeWidth) {
1928 if (rightVehSide < 0) {
1929 latDistSublane -= rightVehSide;
1930 } else if (leftVehSide > edgeWidth) {
1931 latDistSublane -= leftVehSide - edgeWidth;
1932 }
1933 }
1934 }
1935 break;
1936 }
1938 // sublane alignment should not cause the vehicle to leave the lane
1939 const double hw = myVehicle.getLane()->getWidth() / 2 - NUMERICAL_EPS;
1940 const double offset = MAX2(-hw, MIN2(hw, myVehicle.getVehicleType().getPreferredLateralAlignmentOffset()));
1941 latDistSublane = -getPosLat() + offset;
1942 }
1943 break;
1944 default:
1945 break;
1946 }
1947 }
1948 // only factor in preferred lateral alignment if there is no speedGain motivation or it runs in the same direction
1949 if (fabs(latDist) <= NUMERICAL_EPS * myVehicle.getActionStepLengthSecs() ||
1950 latDistSublane * latDist > 0) {
1951
1952#if defined(DEBUG_WANTSCHANGE) || defined(DEBUG_STATE) || defined(DEBUG_MANEUVER)
1953 if (gDebugFlag2) std::cout << SIMTIME
1955 << " mySpeedGainR=" << mySpeedGainProbabilityRight
1956 << " mySpeedGainL=" << mySpeedGainProbabilityLeft
1957 << " latDist=" << latDist
1958 << " latDistSublane=" << latDistSublane
1959 << " relGainSublane=" << computeSpeedGain(latDistSublane, defaultNextSpeed)
1960 << " maneuverDist=" << maneuverDist
1961 << " myCanChangeFully=" << myCanChangeFully
1962 << " myTurnAlignmentDist=" << myTurnAlignmentDist
1963 << " nextTurn=" << myVehicle.getNextTurn().first << ":" << toString(myVehicle.getNextTurn().second)
1964 << " prevState=" << toString((LaneChangeAction)myPreviousState)
1965 << "\n";
1966#endif
1967
1968 if ((latDistSublane < 0 && mySpeedGainProbabilityRight < mySpeedLossProbThreshold)
1969 || (latDistSublane > 0 && mySpeedGainProbabilityLeft < mySpeedLossProbThreshold)
1970 || computeSpeedGain(latDistSublane, defaultNextSpeed) < -mySublaneParam) {
1971 // do not risk losing speed
1972#if defined(DEBUG_WANTSCHANGE)
1973 if (gDebugFlag2) std::cout << " aborting sublane change to avoid speed loss (mySpeedLossProbThreshold=" << mySpeedLossProbThreshold
1974 << " speedGain=" << computeSpeedGain(latDistSublane, defaultNextSpeed) << ")\n";
1975#endif
1976 latDistSublane = 0;
1977 }
1978 // Ignore preferred lateral alignment if we are in the middle of an unfinished non-alignment maneuver into the opposite direction
1979 if (!myCanChangeFully
1981 && ((getManeuverDist() < 0 && latDistSublane > 0) || (getManeuverDist() > 0 && latDistSublane < 0))) {
1982#if defined(DEBUG_WANTSCHANGE)
1983 if (gDebugFlag2) {
1984 std::cout << " aborting sublane change due to prior maneuver\n";
1985 }
1986#endif
1987 latDistSublane = 0;
1988 }
1989 latDist = latDistSublane * (isOpposite() ? -1 : 1);
1990 // XXX first compute preferred adaptation and then override with speed
1991 // (this way adaptation is still done if changing for speedgain is
1992 // blocked)
1993 if (fabs(latDist) >= NUMERICAL_EPS * myVehicle.getActionStepLengthSecs()) {
1994#ifdef DEBUG_WANTSCHANGE
1995 if (gDebugFlag2) std::cout << SIMTIME
1996 << " adapting to preferred alignment=" << toString(myVehicle.getVehicleType().getPreferredLateralAlignment())
1997 << " latDist=" << latDist
1998 << "\n";
1999#endif
2000 ret |= LCA_SUBLANE;
2001 // include prior motivation when sublane-change is part of finishing an ongoing maneuver in the same direction
2002 if (getPreviousManeuverDist() * latDist > 0) {
2003 int priorReason = (myPreviousState & LCA_CHANGE_REASONS & ~LCA_SUBLANE);
2004 ret |= priorReason;
2005#ifdef DEBUG_WANTSCHANGE
2006 if (gDebugFlag2 && priorReason != 0) std::cout << " including prior reason " << toString((LaneChangeAction)priorReason)
2007 << " prevManeuverDist=" << getPreviousManeuverDist() << "\n";
2008#endif
2009 }
2010 if (!cancelRequest(ret + getLCA(ret, latDist), laneOffset)) {
2011 maneuverDist = latDist;
2012 blocked = checkBlocking(neighLane, latDist, maneuverDist, laneOffset,
2013 leaders, followers, blockers,
2014 neighLeaders, neighFollowers, neighBlockers);
2015 return ret;
2016 } else {
2017 ret &= ~LCA_SUBLANE;
2018 }
2019 } else {
2020 return ret | LCA_SUBLANE | LCA_STAY;
2021 }
2022 }
2023 latDist = 0;
2024
2025
2026 // --------
2027 /*
2028 if (changeToBest && bestLaneOffset == curr.bestLaneOffset && laneOffset != 0
2029 && (right
2030 ? mySpeedGainProbabilityRight > MAX2(0., mySpeedGainProbabilityLeft)
2031 : mySpeedGainProbabilityLeft > MAX2(0., mySpeedGainProbabilityRight))) {
2032 // change towards the correct lane, speedwise it does not hurt
2033 ret |= LCA_STRATEGIC;
2034 if (!cancelRequest(ret, laneOffset)) {
2035 latDist = latLaneDist;
2036 blocked = checkBlocking(neighLane, latDist, laneOffset,
2037 leaders, followers, blockers,
2038 neighLeaders, neighFollowers, neighBlockers);
2039 return ret;
2040 }
2041 }
2042 */
2043#ifdef DEBUG_WANTSCHANGE
2044 if (gDebugFlag2) {
2045 std::cout << STEPS2TIME(currentTime)
2046 << " veh=" << myVehicle.getID()
2047 << " mySpeedGainR=" << mySpeedGainProbabilityRight
2048 << " mySpeedGainL=" << mySpeedGainProbabilityLeft
2049 << " myKeepRight=" << myKeepRightProbability
2050 << "\n";
2051 }
2052#endif
2053 return ret;
2054}
2055
2056
2057int
2059 // if this vehicle is blocking someone in front, we maybe decelerate to let him in
2060 if ((*blocked) != nullptr) {
2061 double gap = (*blocked)->getPositionOnLane() - (*blocked)->getVehicleType().getLength() - myVehicle.getPositionOnLane() - myVehicle.getVehicleType().getMinGap();
2062#ifdef DEBUG_SLOWDOWN
2063 if (gDebugFlag2) {
2064 std::cout << SIMTIME
2065 << " veh=" << myVehicle.getID()
2066 << " blocked=" << Named::getIDSecure(*blocked)
2067 << " gap=" << gap
2068 << "\n";
2069 }
2070#endif
2071 if (gap > POSITION_EPS) {
2072 //const bool blockedWantsUrgentRight = (((*blocked)->getLaneChangeModel().getOwnState() & LCA_RIGHT != 0)
2073 // && ((*blocked)->getLaneChangeModel().getOwnState() & LCA_URGENT != 0));
2074
2076 //|| blockedWantsUrgentRight // VARIANT_10 (helpblockedRight)
2077 ) {
2078 if ((*blocked)->getSpeed() < SUMO_const_haltingSpeed) {
2080 } else {
2081 state |= LCA_AMBACKBLOCKER;
2082 }
2083 addLCSpeedAdvice(getCarFollowModel().followSpeed(
2085 (gap - POSITION_EPS), (*blocked)->getSpeed(),
2086 (*blocked)->getCarFollowModel().getMaxDecel()), false);
2087 //(*blocked) = 0; // VARIANT_14 (furtherBlock)
2088 }
2089 }
2090 }
2091 return state;
2092}
2093
2094
2095bool
2096MSLCM_SL2015::isBidi(const MSLane* lane) const {
2097 if (!MSNet::getInstance()->hasBidiEdges()) {
2098 return false;
2099 }
2100 if (lane == myVehicle.getLane()->getBidiLane()) {
2101 return true;
2102 }
2103 for (const MSLane* cand : myVehicle.getBestLanesContinuation()) {
2104 if (cand != nullptr && cand->getBidiLane() == lane) {
2105 return true;
2106 }
2107 }
2108 return false;
2109}
2110
2111void
2112MSLCM_SL2015::updateExpectedSublaneSpeeds(const MSLeaderDistanceInfo& ahead, int sublaneOffset, int laneIndex) {
2113 const std::vector<MSLane*>& lanes = myVehicle.getLane()->getEdge().getLanes();
2114 const std::vector<MSVehicle::LaneQ>& preb = myVehicle.getBestLanes();
2115 const MSLane* lane = isOpposite() ? myVehicle.getLane()->getParallelOpposite() : lanes[laneIndex];
2116 const MSLane* next = myVehicle.getBestLanesContinuation().size() > 1 ? myVehicle.getBestLanesContinuation()[1] : nullptr;
2117 const MSLink* link = next != nullptr ? lane->getLinkTo(next) : nullptr;
2118 const double shift = link != nullptr ? link->getLateralShift() + 0.5 * (lane->getWidth() - next->getWidth()) : 0;
2119 const MSLane* bidi = myVehicle.getLane()->getBidiLane();
2120 const double vMax = lane->getVehicleMaxSpeed(&myVehicle);
2121 assert(preb.size() == lanes.size() || isOpposite());
2122#ifdef DEBUG_EXPECTED_SLSPEED
2123 if (DEBUG_COND) {
2124 std::cout << SIMTIME << " veh=" << myVehicle.getID() << " updateExpectedSublaneSpeeds opposite=" << isOpposite()
2125 << " sublaneOffset=" << sublaneOffset << " laneIndex=" << laneIndex << " lane=" << lane->getID() << " ahead=" << ahead.toString() << "\n";
2126 }
2127#endif
2128
2129 for (int sublane = 0; sublane < (int)ahead.numSublanes(); ++sublane) {
2130 const int edgeSublane = sublane + sublaneOffset;
2131 if (edgeSublane >= (int)myExpectedSublaneSpeeds.size()) {
2132 // this may happen if a sibling lane is wider than the changer lane
2133 continue;
2134 }
2135 if (link != nullptr && lane->getWidth() > next->getWidth() + NUMERICAL_EPS && MSGlobals::gLateralResolution > 0 && sublaneEnds(sublane, next, shift)) {
2136 // sublane does not continue, discourage from use
2137 myExpectedSublaneSpeeds[edgeSublane] = 0;
2138#ifdef DEBUG_EXPECTED_SLSPEED
2139 if (DEBUG_COND) {
2140 std::cout << " updateExpectedSublaneSpeeds sublane=" << sublane << " doesNotContinue\n";
2141 }
2142#endif
2143 continue;
2145 // lane allowed, find potential leaders and compute safe speeds
2146 // XXX anticipate future braking if leader has a lower speed than myVehicle
2147 const MSVehicle* leader = ahead[sublane].first;
2148 const double gap = ahead[sublane].second;
2149 double vSafe;
2150 if (leader == nullptr) {
2151 if (hasBlueLight()) {
2152 // can continue from any lane if necessary
2153 vSafe = vMax;
2154 } else {
2155 const int prebIndex = isOpposite() ? (int)preb.size() - 1 : laneIndex;
2156 const double dist = preb[prebIndex].length - myVehicle.getPositionOnLane();
2157 vSafe = getCarFollowModel().followSpeed(&myVehicle, vMax, dist, 0, 0);
2158 }
2159 } else if (bidi != nullptr && leader->getLane()->getBidiLane() != nullptr && isBidi(leader->getLane())) {
2160 // oncoming
2161 if (gap < (1 + mySpeedGainLookahead * 2) * (vMax + leader->getSpeed())) {
2162 vSafe = 0;
2163 } else {
2164 vSafe = vMax;
2165 }
2166#ifdef DEBUG_EXPECTED_SLSPEED
2167 if (DEBUG_COND) {
2168 std::cout << SIMTIME << " updateExpectedSublaneSpeeds sublane=" << sublane << " leader=" << leader->getID() << " bidi=" << bidi->getID() << " gap=" << gap << " vSafe=" << vSafe << "\n";
2169 }
2170#endif
2171 } else {
2172 if (leader->getAcceleration() > 0.5 * leader->getCarFollowModel().getMaxAccel()) {
2173 // assume that the leader will continue accelerating to its maximum speed
2174 vSafe = leader->getLane()->getVehicleMaxSpeed(leader);
2175 } else {
2177 &myVehicle, vMax, gap, leader->getSpeed(), leader->getCarFollowModel().getMaxDecel());
2178#ifdef DEBUG_EXPECTED_SLSPEED
2179 if (DEBUG_COND) {
2180 std::cout << " updateExpectedSublaneSpeeds edgeSublane=" << edgeSublane << " leader=" << leader->getID() << " gap=" << gap << " vSafe=" << vSafe << "\n";
2181 }
2182#endif
2183 vSafe = forecastAverageSpeed(vSafe, vMax, gap, leader->getSpeed());
2184 }
2185 }
2186 // take pedestrians into account
2187 if (lane->getEdge().getPersons().size() > 0 && lane->hasPedestrians()) {
2189 double foeRight, foeLeft;
2190 ahead.getSublaneBorders(sublane, 0, foeRight, foeLeft);
2191 // get all leaders ahead or overlapping
2192 const PersonDist pedLeader = lane->nextBlocking(myVehicle.getPositionOnLane() - myVehicle.getVehicleType().getLength(), foeRight, foeLeft);
2193 if (pedLeader.first != 0) {
2194 const double pedGap = pedLeader.second - myVehicle.getVehicleType().getMinGap() - myVehicle.getVehicleType().getLength();
2195 // we do not know the walking direction here so we take the pedestrian speed as 0
2196 vSafe = MIN2(getCarFollowModel().stopSpeed(&myVehicle, vMax, pedGap),
2197 forecastAverageSpeed(vSafe, vMax, pedGap, 0));
2198#ifdef DEBUG_EXPECTED_SLSPEED
2199 if (DEBUG_COND) {
2200 std::cout << " updateExpectedSublaneSpeeds edgeSublane=" << edgeSublane << " pedLeader=" << pedLeader.first->getID() << " gap=" << pedGap << " vSafe=" << vSafe << "\n";
2201 }
2202#endif
2203 }
2204 }
2205 // take bidi pedestrians into account
2206 if (bidi != nullptr && bidi->getEdge().getPersons().size() > 0 && bidi->hasPedestrians()) {
2208 double foeRight, foeLeft;
2209 ahead.getSublaneBorders(sublane, 0, foeRight, foeLeft);
2210 const double foeRightBidi = bidi->getWidth() - foeLeft;
2211 const double foeLeftBidi = bidi->getWidth() - foeRight;
2212 // get all leaders ahead or overlapping
2213 const double relativeBackPos = myVehicle.getLane()->getLength() - myVehicle.getPositionOnLane() + myVehicle.getLength();
2214 const double stopTime = ceil(myVehicle.getSpeed() / myVehicle.getCarFollowModel().getMaxDecel());
2215 PersonDist pedLeader = bidi->nextBlocking(relativeBackPos, foeRightBidi, foeLeftBidi, stopTime, true);
2216 if (pedLeader.first != 0) {
2217 const double pedGap = pedLeader.second - myVehicle.getVehicleType().getMinGap() - myVehicle.getVehicleType().getLength();
2218 // we do not know the walking direction here so we take the pedestrian speed as 0
2219 vSafe = MIN2(getCarFollowModel().stopSpeed(&myVehicle, vMax, pedGap),
2220 forecastAverageSpeed(vSafe, vMax, pedGap, 0));
2221#ifdef DEBUG_EXPECTED_SLSPEED
2222 if (DEBUG_COND) {
2223 std::cout << " updateExpectedSublaneSpeeds edgeSublane=" << edgeSublane << " pedLeader=" << pedLeader.first->getID() << " (bidi) gap=" << pedGap << " vSafe=" << vSafe << "\n";
2224 }
2225#endif
2226 }
2227 }
2228 vSafe = MIN2(vMax, vSafe);
2229 // forget old data when on the opposite side
2230 const double memoryFactor = isOpposite() ? 0 : pow(SPEEDGAIN_MEMORY_FACTOR, myVehicle.getActionStepLengthSecs());
2231 myExpectedSublaneSpeeds[edgeSublane] = memoryFactor * myExpectedSublaneSpeeds[edgeSublane] + (1 - memoryFactor) * vSafe;
2232 } else {
2233 // lane forbidden
2234 myExpectedSublaneSpeeds[edgeSublane] = -1;
2235#ifdef DEBUG_EXPECTED_SLSPEED
2236 if (DEBUG_COND) {
2237 std::cout << " updateExpectedSublaneSpeeds edgeSublane=" << edgeSublane << " lane " << lane->getID() << " forbidden\n";
2238 }
2239#endif
2240 }
2241 }
2242 // XXX deal with leaders on subsequent lanes based on preb
2243}
2244
2245
2246bool
2247MSLCM_SL2015::sublaneEnds(int i, const MSLane* next, double shift) {
2248 const double side = i * MSGlobals::gLateralResolution + shift;
2249 return ((side < -NUMERICAL_EPS
2250 && (next->getParallelLane(-1) == nullptr || !next->getParallelLane(-1)->allowsVehicleClass(myVehicle.getVClass())))
2251 || (side + MSGlobals::gLateralResolution > next->getWidth()
2252 && (next->getParallelLane(1) == nullptr || !next->getParallelLane(1)->allowsVehicleClass(myVehicle.getVClass()))));
2253}
2254
2255
2256double
2257MSLCM_SL2015::forecastAverageSpeed(double vSafe, double vMax, double gap, double vLeader) const {
2258 const double deltaV = vMax - vLeader;
2259 if (deltaV > 0 && gap / deltaV < mySpeedGainLookahead && mySpeedGainLookahead > 0) {
2260 // anticipate future braking by computing the average
2261 // speed over the next few seconds
2262 const double foreCastTime = mySpeedGainLookahead * 2;
2263 const double gapClosingTime = MAX2(0.0, gap / deltaV);
2264 const double vSafe2 = (gapClosingTime * vSafe + (foreCastTime - gapClosingTime) * vLeader) / foreCastTime;
2265#ifdef DEBUG_EXPECTED_SLSPEED
2266 if (DEBUG_COND && vSafe2 != vSafe) {
2267 std::cout << " foreCastTime=" << foreCastTime << " gapClosingTime=" << gapClosingTime << " extrapolated vSafe=" << vSafe2 << "\n";
2268 }
2269#endif
2270 vSafe = vSafe2;
2271 }
2272 return vSafe;
2273}
2274
2275
2276double
2277MSLCM_SL2015::computeSpeedGain(double latDistSublane, double defaultNextSpeed) const {
2278 double result = std::numeric_limits<double>::max();
2279 const std::vector<double>& sublaneSides = myVehicle.getLane()->getEdge().getSubLaneSides();
2280 const double vehWidth = getWidth();
2281 const double rightVehSide = myVehicle.getCenterOnEdge() - vehWidth * 0.5 + latDistSublane;
2282 const double leftVehSide = rightVehSide + vehWidth;
2283 for (int i = 0; i < (int)sublaneSides.size(); ++i) {
2284 const double leftSide = i + 1 < (int)sublaneSides.size() ? sublaneSides[i + 1] : MAX2(myVehicle.getLane()->getEdge().getWidth(), sublaneSides[i] + POSITION_EPS);
2285 if (overlap(rightVehSide, leftVehSide, sublaneSides[i], leftSide)) {
2286 result = MIN2(result, myExpectedSublaneSpeeds[i]);
2287 }
2288 //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";
2289 }
2290 return result - defaultNextSpeed;
2291}
2292
2293
2296 int iMax = -1;
2297 double maxLength = -1;
2298 for (int i = 0; i < ldi.numSublanes(); ++i) {
2299 const MSVehicle* veh = ldi[i].first;
2300 if (veh) {
2301 const double length = veh->getVehicleType().getLength();
2302 if (length > maxLength && tieBrakeLeader(veh)) {
2303 maxLength = length;
2304 iMax = i;
2305 }
2306 }
2307 }
2308 return iMax >= 0 ? ldi[iMax] : std::make_pair(nullptr, -1);
2309}
2310
2311
2312bool
2314 // tie braker if the leader is at the same lane position
2315 return veh != nullptr && (veh->getPositionOnLane() != myVehicle.getPositionOnLane()
2316 || veh->getSpeed() < myVehicle.getSpeed()
2317 || &veh->getLane()->getEdge() != &myVehicle.getLane()->getEdge()
2318 || veh->getLane()->getIndex() > myVehicle.getLane()->getIndex());
2319}
2320
2321
2324 int iMax = 0;
2325 double minSpeed = std::numeric_limits<double>::max();
2326 for (int i = 0; i < ldi.numSublanes(); ++i) {
2327 if (ldi[i].first != 0) {
2328 const double speed = ldi[i].first->getSpeed();
2329 if (speed < minSpeed) {
2330 minSpeed = speed;
2331 iMax = i;
2332 }
2333 }
2334 }
2335 return ldi[iMax];
2336}
2337
2338
2339int
2340MSLCM_SL2015::checkBlocking(const MSLane& neighLane, double& latDist, double maneuverDist, int laneOffset,
2341 const MSLeaderDistanceInfo& leaders,
2342 const MSLeaderDistanceInfo& followers,
2343 const MSLeaderDistanceInfo& /*blockers */,
2344 const MSLeaderDistanceInfo& neighLeaders,
2345 const MSLeaderDistanceInfo& neighFollowers,
2346 const MSLeaderDistanceInfo& /* neighBlockers */,
2347 std::vector<CLeaderDist>* collectLeadBlockers,
2348 std::vector<CLeaderDist>* collectFollowBlockers,
2349 bool keepLatGapManeuver,
2350 double gapFactor,
2351 int* retBlockedFully) {
2352 // truncate latDist according to maxSpeedLat
2353 const double maxDist = SPEED2DIST(getMaxSpeedLat2());
2354 latDist = MAX2(MIN2(latDist, maxDist), -maxDist);
2356 return 0;
2357 }
2358
2359 const double neighRight = getNeighRight(neighLane);
2360 if (!myCFRelatedReady) {
2361 updateCFRelated(followers, myVehicle.getLane()->getRightSideOnEdge(), false);
2363 if (laneOffset != 0) {
2364 updateCFRelated(neighFollowers, neighRight, false);
2365 updateCFRelated(neighLeaders, neighRight, true);
2366 }
2367 myCFRelatedReady = true;
2368 }
2369
2370 // reduce latDist to avoid blockage with overlapping vehicles (no minGapLat constraints)
2371 const double center = myVehicle.getCenterOnEdge();
2372 updateGaps(leaders, myVehicle.getLane()->getRightSideOnEdge(), center, gapFactor, mySafeLatDistRight, mySafeLatDistLeft, false, 0, latDist, collectLeadBlockers);
2373 updateGaps(followers, myVehicle.getLane()->getRightSideOnEdge(), center, gapFactor, mySafeLatDistRight, mySafeLatDistLeft, false, 0, latDist, collectFollowBlockers);
2374 if (laneOffset != 0) {
2375 updateGaps(neighLeaders, neighRight, center, gapFactor, mySafeLatDistRight, mySafeLatDistLeft, false, 0, latDist, collectLeadBlockers);
2376 updateGaps(neighFollowers, neighRight, center, gapFactor, mySafeLatDistRight, mySafeLatDistLeft, false, 0, latDist, collectFollowBlockers);
2377 }
2378#ifdef DEBUG_BLOCKING
2379 if (gDebugFlag2) {
2380 std::cout << " checkBlocking latDist=" << latDist << " mySafeLatDistRight=" << mySafeLatDistRight << " mySafeLatDistLeft=" << mySafeLatDistLeft << "\n";
2381 }
2382#endif
2383 // if we can move at least a little bit in the desired direction, do so (rather than block)
2384 const bool forcedTraCIChange = (myVehicle.hasInfluencer()
2387 if (latDist < 0) {
2388 if (mySafeLatDistRight <= NUMERICAL_EPS) {
2390 } else if (!forcedTraCIChange) {
2391 latDist = MAX2(latDist, -mySafeLatDistRight);
2392 }
2393 } else {
2394 if (mySafeLatDistLeft <= NUMERICAL_EPS) {
2396 } else if (!forcedTraCIChange) {
2397 latDist = MIN2(latDist, mySafeLatDistLeft);
2398 }
2399 }
2400
2401 myCanChangeFully = (maneuverDist == 0 || latDist == maneuverDist);
2402#ifdef DEBUG_BLOCKING
2403 if (gDebugFlag2) {
2404 std::cout << " checkBlocking latDist=" << latDist << " maneuverDist=" << maneuverDist << "\n";
2405 }
2406#endif
2407 // destination sublanes must be safe
2408 // intermediate sublanes must not be blocked by overlapping vehicles
2409
2410 // XXX avoid checking the same leader multiple times
2411 // XXX ensure that only changes within the same lane are undertaken if laneOffset = 0
2412
2413 int blocked = 0;
2414 blocked |= checkBlockingVehicles(&myVehicle, leaders, laneOffset, latDist, myVehicle.getLane()->getRightSideOnEdge(), true,
2415 mySafeLatDistRight, mySafeLatDistLeft, collectLeadBlockers);
2416 blocked |= checkBlockingVehicles(&myVehicle, followers, laneOffset, latDist, myVehicle.getLane()->getRightSideOnEdge(), false,
2417 mySafeLatDistRight, mySafeLatDistLeft, collectFollowBlockers);
2418 if (laneOffset != 0) {
2419 blocked |= checkBlockingVehicles(&myVehicle, neighLeaders, laneOffset, latDist, neighRight, true,
2420 mySafeLatDistRight, mySafeLatDistLeft, collectLeadBlockers);
2421 blocked |= checkBlockingVehicles(&myVehicle, neighFollowers, laneOffset, latDist, neighRight, false,
2422 mySafeLatDistRight, mySafeLatDistLeft, collectFollowBlockers);
2423 }
2424
2425 int blockedFully = 0;
2426 blockedFully |= checkBlockingVehicles(&myVehicle, leaders, laneOffset, maneuverDist, myVehicle.getLane()->getRightSideOnEdge(), true,
2427 mySafeLatDistRight, mySafeLatDistLeft, collectLeadBlockers);
2428 blockedFully |= checkBlockingVehicles(&myVehicle, followers, laneOffset, maneuverDist, myVehicle.getLane()->getRightSideOnEdge(), false,
2429 mySafeLatDistRight, mySafeLatDistLeft, collectFollowBlockers);
2430 if (laneOffset != 0) {
2431 blockedFully |= checkBlockingVehicles(&myVehicle, neighLeaders, laneOffset, maneuverDist, neighRight, true,
2432 mySafeLatDistRight, mySafeLatDistLeft, collectLeadBlockers);
2433 blockedFully |= checkBlockingVehicles(&myVehicle, neighFollowers, laneOffset, maneuverDist, neighRight, false,
2434 mySafeLatDistRight, mySafeLatDistLeft, collectFollowBlockers);
2435 }
2436 if (retBlockedFully != nullptr) {
2437 *retBlockedFully = blockedFully;
2438 }
2439#ifdef DEBUG_BLOCKING
2440 if (gDebugFlag2) {
2441 std::cout << " blocked=" << blocked << " (" << toString((LaneChangeAction)blocked) << ") blockedFully=" << toString((LaneChangeAction)blockedFully)
2442 << " canChangeFully=" << myCanChangeFully << " keepLatGapManeuver=" << keepLatGapManeuver << "\n";
2443 }
2444#endif
2445 if (blocked == 0 && !myCanChangeFully && myPushy == 0 && !keepLatGapManeuver) {
2446 // aggressive drivers immediately start moving towards potential
2447 // blockers and only check that the start of their maneuver (latDist) is safe. In
2448 // contrast, cautious drivers need to check latDist and origLatDist to
2449 // ensure that the maneuver can be finished without encroaching on other vehicles.
2450 blocked |= blockedFully;
2451 } else {
2452 // XXX: in case of action step length > simulation step length, pushing may lead to collisions,
2453 // because maneuver is continued until maneuverDist is reached (perhaps set maneuverDist=latDist)
2454 }
2455#ifdef DEBUG_BLOCKING
2456 if (gDebugFlag2) {
2457 std::cout << " blocked2=" << blocked << " (" << toString((LaneChangeAction)blocked) << ")\n";
2458 }
2459#endif
2460 if (collectFollowBlockers != nullptr && collectLeadBlockers != nullptr) {
2461 // prevent vehicles from being classified as leader and follower simultaneously
2462 for (std::vector<CLeaderDist>::const_iterator it2 = collectLeadBlockers->begin(); it2 != collectLeadBlockers->end(); ++it2) {
2463 for (std::vector<CLeaderDist>::iterator it = collectFollowBlockers->begin(); it != collectFollowBlockers->end();) {
2464 if ((*it2).first == (*it).first) {
2465#ifdef DEBUG_BLOCKING
2466 if (gDebugFlag2) {
2467 std::cout << " removed follower " << (*it).first->getID() << " because it is already a leader\n";
2468 }
2469#endif
2470 it = collectFollowBlockers->erase(it);
2471 } else {
2472 ++it;
2473 }
2474 }
2475 }
2476 }
2477 return blocked;
2478}
2479
2480
2481int
2483 const MSVehicle* ego, const MSLeaderDistanceInfo& vehicles,
2484 int laneOffset, double latDist, double foeOffset, bool leaders,
2485 double& safeLatGapRight, double& safeLatGapLeft,
2486 std::vector<CLeaderDist>* collectBlockers) const {
2487 // determine borders where safety/no-overlap conditions must hold
2488 const LaneChangeAction blockType = (laneOffset == 0
2490 : (laneOffset > 0
2493 const double vehWidth = getWidth();
2494 const double rightVehSide = ego->getRightSideOnEdge();
2495 const double leftVehSide = rightVehSide + vehWidth;
2496 const double rightVehSideDest = rightVehSide + latDist;
2497 const double leftVehSideDest = leftVehSide + latDist;
2498 const double rightNoOverlap = MIN2(rightVehSideDest, rightVehSide);
2499 const double leftNoOverlap = MAX2(leftVehSideDest, leftVehSide);
2500#ifdef DEBUG_BLOCKING
2501 if (gDebugFlag2) {
2502 std::cout << " checkBlockingVehicles"
2503 << " laneOffset=" << laneOffset
2504 << " latDist=" << latDist
2505 << " foeOffset=" << foeOffset
2506 << " vehRight=" << rightVehSide
2507 << " vehLeft=" << leftVehSide
2508 << " rightNoOverlap=" << rightNoOverlap
2509 << " leftNoOverlap=" << leftNoOverlap
2510 << " destRight=" << rightVehSideDest
2511 << " destLeft=" << leftVehSideDest
2512 << " leaders=" << leaders
2513 << " blockType=" << toString((LaneChangeAction) blockType)
2514 << "\n";
2515 }
2516#endif
2517 int result = 0;
2518 for (int i = 0; i < vehicles.numSublanes(); ++i) {
2519 CLeaderDist vehDist = vehicles[i];
2520 if (vehDist.first != 0 && myCFRelated.count(vehDist.first) == 0) {
2521 const MSVehicle* leader = vehDist.first;
2522 const MSVehicle* follower = ego;
2523 if (!leaders) {
2524 std::swap(leader, follower);
2525 }
2526 // only check the current stripe occupied by foe (transform into edge-coordinates)
2527 double foeRight, foeLeft;
2528 vehicles.getSublaneBorders(i, foeOffset, foeRight, foeLeft);
2529 const bool overlapBefore = overlap(rightVehSide, leftVehSide, foeRight, foeLeft);
2530 const bool overlapDest = overlap(rightVehSideDest, leftVehSideDest, foeRight, foeLeft);
2531 const bool overlapAny = overlap(rightNoOverlap, leftNoOverlap, foeRight, foeLeft);
2532#ifdef DEBUG_BLOCKING
2533 if (gDebugFlag2) {
2534 std::cout << " foe=" << vehDist.first->getID()
2535 << " gap=" << vehDist.second
2536 << " secGap=" << follower->getCarFollowModel().getSecureGap(follower, leader, follower->getSpeed(), leader->getSpeed(), leader->getCarFollowModel().getMaxDecel())
2537 << " foeRight=" << foeRight
2538 << " foeLeft=" << foeLeft
2539 << " overlapBefore=" << overlapBefore
2540 << " overlap=" << overlapAny
2541 << " overlapDest=" << overlapDest
2542 << "\n";
2543 }
2544#endif
2545 if (overlapAny) {
2546 if (vehDist.second < 0) {
2547 if (overlapBefore && !overlapDest && !outsideEdge()) {
2548#ifdef DEBUG_BLOCKING
2549 if (gDebugFlag2) {
2550 std::cout << " ignoring current overlap to come clear\n";
2551 }
2552#endif
2553 } else {
2554#ifdef DEBUG_BLOCKING
2555 if (gDebugFlag2) {
2556 std::cout << " overlap (" << toString((LaneChangeAction)blockType) << ")\n";
2557 }
2558#endif
2559 result |= (blockType | LCA_OVERLAPPING);
2560 if (collectBlockers == nullptr) {
2561 return result;
2562 } else {
2563 collectBlockers->push_back(vehDist);
2564 }
2565 }
2566 } else if (overlapDest || !myCanChangeFully) {
2567 // Estimate state after actionstep (follower may be accelerating!)
2568 // A comparison between secure gap depending on the expected speeds and the extrapolated gap
2569 // determines whether the s is blocking the lane change.
2570 // (Note that the longitudinal state update has already taken effect before LC dynamics (thus "-TS" below), would be affected by #3665)
2571
2572 // Use conservative estimate for time until next action step
2573 // (XXX: how can the ego know the foe's action step length?)
2574 const double timeTillAction = MAX2(follower->getActionStepLengthSecs(), leader->getActionStepLengthSecs()) - TS;
2575 // Ignore decel for follower
2576 const double followerAccel = MAX2(0., follower->getAcceleration());
2577 const double leaderAccel = leader->getAcceleration();
2578 // Expected gap after next actionsteps
2579 const double expectedGap = MSCFModel::gapExtrapolation(timeTillAction, vehDist.second, leader->getSpeed(), follower->getSpeed(), leaderAccel, followerAccel, std::numeric_limits<double>::max(), std::numeric_limits<double>::max());
2580
2581 // Determine expected speeds and corresponding secure gap at the extrapolated timepoint
2582 const double followerExpectedSpeed = follower->getSpeed() + timeTillAction * followerAccel;
2583 const double leaderExpectedSpeed = MAX2(0., leader->getSpeed() + timeTillAction * leaderAccel);
2584 const double expectedSecureGap = follower->getCarFollowModel().getSecureGap(follower, leader, followerExpectedSpeed, leaderExpectedSpeed, leader->getCarFollowModel().getMaxDecel());
2585
2586#if defined(DEBUG_ACTIONSTEPS) && defined(DEBUG_BLOCKING)
2587 if (gDebugFlag2) {
2588 std::cout << " timeTillAction=" << timeTillAction
2589 << " followerAccel=" << followerAccel
2590 << " followerExpectedSpeed=" << followerExpectedSpeed
2591 << " leaderAccel=" << leaderAccel
2592 << " leaderExpectedSpeed=" << leaderExpectedSpeed
2593 << "\n gap=" << vehDist.second
2594 << " gapChange=" << (expectedGap - vehDist.second)
2595 << " expectedGap=" << expectedGap
2596 << " expectedSecureGap=" << expectedSecureGap
2597 << " safeLatGapLeft=" << safeLatGapLeft
2598 << " safeLatGapRight=" << safeLatGapRight
2599 << std::endl;
2600 }
2601#endif
2602
2603 // @note for euler-update, a different value for secureGap2 may be obtained when applying safetyFactor to followerDecel rather than secureGap
2604 const double secureGap2 = expectedSecureGap * getSafetyFactor();
2605 if (expectedGap < secureGap2) {
2606 // Foe is a blocker. Update lateral safe gaps accordingly.
2607 if (foeRight > leftVehSide) {
2608 safeLatGapLeft = MIN2(safeLatGapLeft, foeRight - leftVehSide);
2609 } else if (foeLeft < rightVehSide) {
2610 safeLatGapRight = MIN2(safeLatGapRight, rightVehSide - foeLeft);
2611 }
2612
2613#ifdef DEBUG_BLOCKING
2614 if (gDebugFlag2) {
2615 std::cout << " blocked by " << vehDist.first->getID() << " gap=" << vehDist.second << " expectedGap=" << expectedGap
2616 << " expectedSecureGap=" << expectedSecureGap << " secGap2=" << secureGap2 << " safetyFactor=" << getSafetyFactor()
2617 << " safeLatGapLeft=" << safeLatGapLeft << " safeLatGapRight=" << safeLatGapRight
2618 << "\n";
2619 }
2620#endif
2621 result |= blockType;
2622 if (collectBlockers == nullptr) {
2623 return result;
2624 }
2625#ifdef DEBUG_BLOCKING
2626 } else if (gDebugFlag2 && expectedGap < expectedSecureGap) {
2627 std::cout << " ignore blocker " << vehDist.first->getID() << " gap=" << vehDist.second << " expectedGap=" << expectedGap
2628 << " expectedSecureGap=" << expectedSecureGap << " secGap2=" << secureGap2 << " safetyFactor=" << getSafetyFactor() << "\n";
2629#endif
2630 }
2631 if (collectBlockers != nullptr) {
2632 // collect non-blocking followers as well to make sure
2633 // they remain non-blocking
2634 collectBlockers->push_back(vehDist);
2635 }
2636 }
2637 }
2638 }
2639 }
2640 return result;
2641
2642}
2643
2644
2645void
2646MSLCM_SL2015::updateCFRelated(const MSLeaderDistanceInfo& vehicles, double foeOffset, bool leaders) {
2647 // to ensure that we do not ignore the wrong vehicles due to numerical
2648 // instability we slightly reduce the width
2649 const double vehWidth = myVehicle.getVehicleType().getWidth() - NUMERICAL_EPS;
2650 const double rightVehSide = myVehicle.getCenterOnEdge() - 0.5 * vehWidth;
2651 const double leftVehSide = rightVehSide + vehWidth;
2652#ifdef DEBUG_BLOCKING
2653 if (gDebugFlag2) {
2654 std::cout << " updateCFRelated foeOffset=" << foeOffset << " vehicles=" << vehicles.toString() << "\n";
2655 }
2656#endif
2657 for (int i = 0; i < vehicles.numSublanes(); ++i) {
2658 CLeaderDist vehDist = vehicles[i];
2659 if (vehDist.first != 0 && (myCFRelated.count(vehDist.first) == 0 || vehDist.second < 0)) {
2660 double foeRight, foeLeft;
2661 vehicles.getSublaneBorders(i, foeOffset, foeRight, foeLeft);
2662#ifdef DEBUG_BLOCKING
2663 if (gDebugFlag2) {
2664 std::cout << " foe=" << vehDist.first->getID() << " gap=" << vehDist.second
2665 << " sublane=" << i
2666 << " foeOffset=" << foeOffset
2667 << " egoR=" << rightVehSide << " egoL=" << leftVehSide
2668 << " iR=" << foeRight << " iL=" << foeLeft
2669 << " egoV=" << myVehicle.getSpeed() << " foeV=" << vehDist.first->getSpeed()
2670 << " egoE=" << myVehicle.getLane()->getEdge().getID() << " foeE=" << vehDist.first->getLane()->getEdge().getID()
2671 << "\n";
2672 }
2673#endif
2674 if (overlap(rightVehSide, leftVehSide, foeRight, foeLeft) && !outsideEdge() && (vehDist.second >= 0
2675 // avoid deadlock due to #3729
2676 || (!leaders
2679 && vehDist.first->getSpeed() < SUMO_const_haltingSpeed
2680 && -vehDist.second < vehDist.first->getVehicleType().getMinGap()
2681 && &(myVehicle.getLane()->getEdge()) != &(vehDist.first->getLane()->getEdge()))
2682 )) {
2683#ifdef DEBUG_BLOCKING
2684 if (gDebugFlag2) {
2685 std::cout << " ignoring cfrelated foe=" << vehDist.first->getID() << "\n";
2686 }
2687#endif
2688 myCFRelated.insert(vehDist.first);
2689 } else {
2690 const int erased = (int)myCFRelated.erase(vehDist.first);
2691#ifdef DEBUG_BLOCKING
2692 if (gDebugFlag2 && erased > 0) {
2693 std::cout << " restoring cfrelated foe=" << vehDist.first->getID() << "\n";
2694 }
2695#else
2696 UNUSED_PARAMETER(erased);
2697#endif
2698 }
2699 }
2700 }
2701}
2702
2703
2704bool
2705MSLCM_SL2015::overlap(double right, double left, double right2, double left2) {
2706 assert(right <= left);
2707 assert(right2 <= left2);
2708 return left2 >= right + NUMERICAL_EPS && left >= right2 + NUMERICAL_EPS;
2709}
2710
2711
2712int
2713MSLCM_SL2015::lowest_bit(int changeReason) {
2714 if ((changeReason & LCA_STRATEGIC) != 0) {
2715 return LCA_STRATEGIC;
2716 }
2717 if ((changeReason & LCA_COOPERATIVE) != 0) {
2718 return LCA_COOPERATIVE;
2719 }
2720 if ((changeReason & LCA_SPEEDGAIN) != 0) {
2721 return LCA_SPEEDGAIN;
2722 }
2723 if ((changeReason & LCA_KEEPRIGHT) != 0) {
2724 return LCA_KEEPRIGHT;
2725 }
2726 if ((changeReason & LCA_TRACI) != 0) {
2727 return LCA_TRACI;
2728 }
2729 return changeReason;
2730}
2731
2732
2735 // ignore dummy decisions (returned if mayChange() failes)
2736 if (sd1.state == 0) {
2737 return sd2;
2738 } else if (sd2.state == 0) {
2739 return sd1;
2740 }
2741 // LCA_SUBLANE is special because LCA_STAY|LCA_SUBLANE may override another LCA_SUBLANE command
2742 const bool want1 = ((sd1.state & LCA_WANTS_LANECHANGE) != 0) || ((sd1.state & LCA_SUBLANE) != 0 && (sd1.state & LCA_STAY) != 0);
2743 const bool want2 = ((sd2.state & LCA_WANTS_LANECHANGE) != 0) || ((sd2.state & LCA_SUBLANE) != 0 && (sd2.state & LCA_STAY) != 0);
2744 const bool can1 = ((sd1.state & LCA_BLOCKED) == 0);
2745 const bool can2 = ((sd2.state & LCA_BLOCKED) == 0);
2746 int reason1 = lowest_bit(sd1.state & LCA_CHANGE_REASONS);
2747 int reason2 = lowest_bit(sd2.state & LCA_CHANGE_REASONS);
2748#ifdef DEBUG_DECISION
2749 if (DEBUG_COND) std::cout << SIMTIME
2750 << " veh=" << myVehicle.getID()
2751 << " state1=" << toString((LaneChangeAction)sd1.state)
2752 << " want1=" << (sd1.state & LCA_WANTS_LANECHANGE)
2753 << " dist1=" << sd1.latDist
2754 << " dir1=" << sd1.dir
2755 << " state2=" << toString((LaneChangeAction)sd2.state)
2756 << " want2=" << (sd2.state & LCA_WANTS_LANECHANGE)
2757 << " dist2=" << sd2.latDist
2758 << " dir2=" << sd2.dir
2759 << " reason1=" << toString((LaneChangeAction)reason1)
2760 << " reason2=" << toString((LaneChangeAction)reason2)
2761 << "\n";
2762#endif
2763 if (want1) {
2764 if (want2) {
2765 if ((sd1.state & LCA_TRACI) != 0 && (sd2.state & LCA_TRACI) != 0) {
2766 // influencer may assign LCA_WANTS_LANECHANGE despite latDist = 0
2767 if (sd1.latDist == 0 && sd2.latDist != 0) {
2768 return sd2;
2769 } else if (sd2.latDist == 0 && sd1.latDist != 0) {
2770 return sd1;
2771 }
2772 }
2773 // decide whether right or left has higher priority (lower value in enum LaneChangeAction)
2774 if (reason1 < reason2) {
2775 //if (DEBUG_COND) std::cout << " " << (sd1.state & LCA_CHANGE_REASONS) << " < " << (sd2.state & LCA_CHANGE_REASONS) << "\n";
2776 return (!can1 && can2 && sd1.sameDirection(sd2)) ? sd2 : sd1;
2777 //return sd1;
2778 } else if (reason1 > reason2) {
2779 //if (DEBUG_COND) std::cout << " " << (sd1.state & LCA_CHANGE_REASONS) << " > " << (sd2.state & LCA_CHANGE_REASONS) << "\n";
2780 return (!can2 && can1 && sd1.sameDirection(sd2)) ? sd1 : sd2;
2781 //return sd2;
2782 } else {
2783 // same priority.
2784 if ((sd1.state & LCA_SUBLANE) != 0) {
2785 // special treatment: prefer action with dir != 0
2786 if (sd1.dir == 0) {
2787 return sd2;
2788 } else if (sd2.dir == 0) {
2789 return sd1;
2790 } else {
2791 // prefer action that knows more about the desired direction
2792 // @note when deciding between right and left, right is always given as sd1
2793 assert(sd1.dir == -1);
2794 assert(sd2.dir == 1);
2795 if (sd1.latDist <= 0) {
2796 return sd1;
2797 } else if (sd2.latDist >= 0) {
2798 return sd2;
2799 }
2800 // when in doubt, prefer moving to the right
2801 return sd1.latDist <= sd2.latDist ? sd1 : sd2;
2802 }
2803 } else {
2804 if (can1) {
2805 if (can2) {
2806 // break strategic ties with tactial concerns
2807 if (reason1 == LCA_STRATEGIC) {
2808 if (sd1.latDist <= sd2.latDist) {
2810 } else {
2812 }
2813 } else {
2814 // finish the shorter maneuver (i.e. continue the current maneuver)
2815 return fabs(sd1.maneuverDist) < fabs(sd2.maneuverDist) ? sd1 : sd2;
2816 }
2817 } else {
2818 return sd1;
2819 }
2820 } else {
2821 return sd2;
2822 }
2823 }
2824 }
2825 } else {
2826 return sd1;
2827 }
2828 } else {
2829 return sd2;
2830 }
2831
2832}
2833
2834
2836MSLCM_SL2015::getLCA(int state, double latDist) {
2837 return ((latDist == 0 || (state & LCA_CHANGE_REASONS) == 0)
2838 ? LCA_NONE : (latDist < 0 ? LCA_RIGHT : LCA_LEFT));
2839}
2840
2841
2842int
2844 const MSLane& neighLane,
2845 int laneOffset,
2846 const MSLeaderDistanceInfo& leaders,
2847 const MSLeaderDistanceInfo& neighLeaders,
2848 const MSVehicle::LaneQ& curr,
2849 const MSVehicle::LaneQ& neigh,
2850 const MSVehicle::LaneQ& best,
2851 int bestLaneOffset,
2852 bool changeToBest,
2853 double& currentDist,
2854 double neighDist,
2855 double laDist,
2856 double roundaboutBonus,
2857 double latLaneDist,
2858 bool checkOpposite,
2859 double& latDist
2860 ) {
2861 const bool right = (laneOffset == -1);
2862 const bool left = (laneOffset == 1);
2863
2864 const double forwardPos = getForwardPos();
2865 if (laneOffset != 0) {
2866 myLeftSpace = currentDist - forwardPos;
2867 }
2868 const double usableDist = (currentDist - forwardPos - best.occupation * JAM_FACTOR);
2869 //- (best.lane->getVehicleNumber() * neighSpeed)); // VARIANT 9 jfSpeed
2870 const double maxJam = MAX2(neigh.occupation, curr.occupation);
2871 const double neighLeftPlace = MAX2(0., neighDist - forwardPos - maxJam);
2872 const double overlap = myVehicle.getLateralOverlap();
2873 // save the left space
2874
2875#ifdef DEBUG_STRATEGIC_CHANGE
2876 if (gDebugFlag2) {
2877 std::cout << SIMTIME
2878 << " veh=" << myVehicle.getID()
2879 << " forwardPos=" << forwardPos
2880 << " laSpeed=" << myLookAheadSpeed
2881 << " laDist=" << laDist
2882 << " currentDist=" << currentDist
2883 << " usableDist=" << usableDist
2884 << " bestLaneOffset=" << bestLaneOffset
2885 << " best.length=" << best.length
2886 << " maxJam=" << maxJam
2887 << " neighLeftPlace=" << neighLeftPlace
2888 << " myLeftSpace=" << myLeftSpace
2889 << " overlap=" << overlap
2890 << "\n";
2891 }
2892#endif
2893
2894 if (laneOffset == 0) {
2895 if (overlap > MAX2(POSITION_EPS, MSGlobals::gLateralResolution)
2896 && (getShadowLane() == nullptr || !getShadowLane()->allowsVehicleClass(myVehicle.getVClass()))
2897 && getWidth() < myVehicle.getLane()->getWidth()) {
2898 // @brief we urgently need to return to within lane bounds
2900 ret |= LCA_STRATEGIC | LCA_URGENT;
2901#ifdef DEBUG_STRATEGIC_CHANGE
2902 if (gDebugFlag2) {
2903 std::cout << SIMTIME << " returnToLaneBounds\n";
2904 }
2905#endif
2906 //std::cout << SIMTIME << " veh=" << myVehicle.getID() << " overlap=" << overlap << " returnToLaneBounds\n";
2907 } else if (myVehicle.getBestLanesContinuation().size() > 1 && myVehicle.getLane()->getWidth() > myVehicle.getBestLanesContinuation()[1]->getWidth()) {
2908 const MSLane* cur = myVehicle.getLane();
2909 const MSLane* next = myVehicle.getBestLanesContinuation()[1];
2910 const MSLink* link = cur->getLinkTo(next);
2911 const double distOnLane = cur->getLength() - myVehicle.getPositionOnLane();
2912 if (link != nullptr && getWidth() < next->getWidth() && distOnLane < 100) {
2913 double hwDiff = 0.5 * (cur->getWidth() - next->getWidth());
2914 double rightVehSide = myVehicle.getRightSideOnLane() + link->getLateralShift() - hwDiff;
2915 double leftVehSide = myVehicle.getLeftSideOnLane() + link->getLateralShift() - hwDiff;
2916 const double res = MSGlobals::gLateralResolution > 0 ? MSGlobals::gLateralResolution : next->getWidth();
2917 if (rightVehSide < -res && (next->getParallelLane(-1) == nullptr || !next->getParallelLane(-1)->allowsVehicleClass(myVehicle.getVClass()))) {
2918 latDist = -rightVehSide;
2919 myLeftSpace = distOnLane;
2920 ret |= LCA_STRATEGIC | LCA_URGENT;
2921#ifdef DEBUG_STRATEGIC_CHANGE
2922 if (gDebugFlag2) {
2923 std::cout << SIMTIME << " rightSublaneEnds rVSide=" << myVehicle.getRightSideOnLane()
2924 << " shift=" << link->getLateralShift() << " rVSide2=" << rightVehSide << " myLeftSpace=" << myLeftSpace << " \n";
2925 }
2926#endif
2927 } else if (leftVehSide > next->getWidth() + res && (next->getParallelLane(1) == nullptr || !next->getParallelLane(1)->allowsVehicleClass(myVehicle.getVClass()))) {
2928 latDist = -(leftVehSide - next->getWidth());
2929 myLeftSpace = distOnLane;
2930 ret |= LCA_STRATEGIC | LCA_URGENT;
2931#ifdef DEBUG_STRATEGIC_CHANGE
2932 if (gDebugFlag2) {
2933 std::cout << SIMTIME << " leftSublaneEnds lVSide=" << myVehicle.getLeftSideOnLane()
2934 << " shift=" << link->getLateralShift() << " lVSide2=" << leftVehSide << " myLeftSpace=" << myLeftSpace << "\n";
2935 }
2936#endif
2937 }
2938 }
2939 }
2940 } else if (laneOffset != 0 && changeToBest && bestLaneOffset == curr.bestLaneOffset
2941 && currentDistDisallows(usableDist, bestLaneOffset, laDist)) {
2943 if (!mustOvertakeStopped(false, neighLane, neighLeaders, leaders, forwardPos, neighDist, right, latLaneDist, currentDist, latDist)) {
2944 latDist = latLaneDist;
2945 ret |= LCA_STRATEGIC | LCA_URGENT;
2946#ifdef DEBUG_STRATEGIC_CHANGE
2947 if (gDebugFlag2) {
2948 std::cout << SIMTIME << " mustChangeToBest\n";
2949 }
2950#endif
2951 } else {
2952#ifdef DEBUG_STRATEGIC_CHANGE
2953 if (gDebugFlag2) {
2954 std::cout << " veh=" << myVehicle.getID() << " avoidStoppedNeigh\n";
2955 }
2956#endif
2957 }
2958 } else {
2959 // VARIANT_20 (noOvertakeRight)
2960 if (left && avoidOvertakeRight() && neighLeaders.hasVehicles()) {
2961 // check for slower leader on the left. we should not overtake but
2962 // rather move left ourselves (unless congested)
2963 // XXX only adapt as much as possible to get a lateral gap
2964 CLeaderDist cld = getSlowest(neighLeaders);
2965 const MSVehicle* nv = cld.first;
2966 if (nv->getSpeed() < myVehicle.getSpeed()) {
2967 const double vSafe = getCarFollowModel().followSpeed(
2968 &myVehicle, myVehicle.getSpeed(), cld.second, nv->getSpeed(), nv->getCarFollowModel().getMaxDecel());
2969 addLCSpeedAdvice(vSafe);
2970 if (vSafe < myVehicle.getSpeed()) {
2972 }
2973#ifdef DEBUG_STRATEGIC_CHANGE
2974 if (gDebugFlag2) {
2975 std::cout << SIMTIME
2976 << " avoid overtaking on the right nv=" << nv->getID()
2977 << " nvSpeed=" << nv->getSpeed()
2978 << " mySpeedGainProbabilityR=" << mySpeedGainProbabilityRight
2979 << " plannedSpeed=" << myVehicle.getSpeed() + ACCEL2SPEED(myLCAccelerationAdvices.back().first)
2980 << "\n";
2981 }
2982#endif
2983 }
2984 }
2985
2986 // handling reaction to stopped for opposite direction driving NYI
2987 const bool noOpposites = &myVehicle.getLane()->getEdge() == &neighLane.getEdge();
2988 if (laneOffset != 0 && myStrategicParam >= 0 && noOpposites && mustOvertakeStopped(true, neighLane, leaders, neighLeaders, forwardPos, neighDist, right, latLaneDist, currentDist, latDist)) {
2989#ifdef DEBUG_STRATEGIC_CHANGE
2990 if (gDebugFlag2) {
2991 std::cout << " veh=" << myVehicle.getID() << " mustOvertakeStopped\n";
2992 }
2993#endif
2994 if (latDist == 0) {
2995 ret |= LCA_STAY | LCA_STRATEGIC;
2996 } else {
2997 ret |= LCA_STRATEGIC | LCA_URGENT;
2998 }
2999
3000 } else if (!changeToBest && (currentDistDisallows(neighLeftPlace, abs(bestLaneOffset) + 2, laDist))) {
3001 // the opposite lane-changing direction should be done than the one examined herein
3002 // we'll check whether we assume we could change anyhow and get back in time...
3003 //
3004 // this rule prevents the vehicle from moving in opposite direction of the best lane
3005 // unless the way till the end where the vehicle has to be on the best lane
3006 // is long enough
3007#ifdef DEBUG_STRATEGIC_CHANGE
3008 if (gDebugFlag2) {
3009 std::cout << " veh=" << myVehicle.getID() << " could not change back and forth in time (1) neighLeftPlace=" << neighLeftPlace << "\n";
3010 }
3011#endif
3012 ret |= LCA_STAY | LCA_STRATEGIC;
3013 } else if (
3014 laneOffset != 0
3015 && bestLaneOffset == 0
3016 && !leaders.hasStoppedVehicle()
3017 && neigh.bestContinuations.back()->getLinkCont().size() != 0
3018 && roundaboutBonus == 0
3019 && !checkOpposite
3020 && neighDist < TURN_LANE_DIST
3021 && myStrategicParam >= 0) {
3022 // VARIANT_21 (stayOnBest)
3023 // we do not want to leave the best lane for a lane which leads elsewhere
3024 // unless our leader is stopped or we are approaching a roundabout
3025#ifdef DEBUG_STRATEGIC_CHANGE
3026 if (gDebugFlag2) {
3027 std::cout << " veh=" << myVehicle.getID() << " does not want to leave the bestLane (neighDist=" << neighDist << ")\n";
3028 }
3029#endif
3030 ret |= LCA_STAY | LCA_STRATEGIC;
3031 } else if (right
3032 && bestLaneOffset == 0
3033 && myVehicle.getLane()->getSpeedLimit() > 80. / 3.6
3035 ) {
3036 // let's also regard the case where the vehicle is driving on a highway...
3037 // in this case, we do not want to get to the dead-end of an on-ramp
3038#ifdef DEBUG_STRATEGIC_CHANGE
3039 if (gDebugFlag2) {
3040 std::cout << " veh=" << myVehicle.getID() << " does not want to get stranded on the on-ramp of a highway\n";
3041 }
3042#endif
3043 ret |= LCA_STAY | LCA_STRATEGIC;
3044 }
3045 }
3046 if (laneOffset != 0 && (ret & LCA_URGENT) == 0 && getShadowLane() != nullptr &&
3047 // ignore overlap if it goes in the correct direction
3048 bestLaneOffset * myVehicle.getLateralPositionOnLane() <= 0) {
3049 // no decision or decision to stay
3050 // make sure to stay within lane bounds in case the shadow lane ends
3051 //const double requiredDist = MAX2(2 * myVehicle.getLateralOverlap(), getSublaneWidth()) / SUMO_const_laneWidth * laDist;
3052 const double requiredDist = 2 * overlap / SUMO_const_laneWidth * laDist;
3053 double currentShadowDist = -myVehicle.getPositionOnLane();
3054 MSLane* shadowPrev = nullptr;
3055 for (std::vector<MSLane*>::const_iterator it = curr.bestContinuations.begin(); it != curr.bestContinuations.end(); ++it) {
3056 if (*it == nullptr) {
3057 continue;
3058 }
3059 MSLane* shadow = getShadowLane(*it);
3060 if (shadow == nullptr || currentShadowDist >= requiredDist) {
3061 break;
3062 }
3063 if (shadowPrev != nullptr) {
3064 currentShadowDist += shadowPrev->getEdge().getInternalFollowingLengthTo(&shadow->getEdge(), myVehicle.getVClass());
3065 }
3066 currentShadowDist += shadow->getLength();
3067 shadowPrev = shadow;
3068#ifdef DEBUG_STRATEGIC_CHANGE
3069 if (gDebugFlag2) {
3070 std::cout << " shadow=" << shadow->getID() << " currentShadowDist=" << currentShadowDist << "\n";
3071 }
3072#endif
3073 }
3074#ifdef DEBUG_STRATEGIC_CHANGE
3075 if (gDebugFlag2) {
3076 std::cout << " veh=" << myVehicle.getID() << " currentShadowDist=" << currentShadowDist << " requiredDist=" << requiredDist << " overlap=" << overlap << "\n";
3077 }
3078#endif
3079 if (currentShadowDist < requiredDist && currentShadowDist < usableDist) {
3080 myLeftSpace = currentShadowDist;
3082#ifdef DEBUG_STRATEGIC_CHANGE
3083 if (gDebugFlag2) {
3084 std::cout << " must change for shadowLane end latDist=" << latDist << " myLeftSpace=" << myLeftSpace << "\n";
3085 }
3086#endif
3087 ret |= LCA_STRATEGIC | LCA_URGENT | LCA_STAY ;
3088 }
3089 }
3090
3091 // check for overriding TraCI requests
3092#if defined(DEBUG_STRATEGIC_CHANGE) || defined(DEBUG_TRACI)
3093 if (gDebugFlag2) {
3094 std::cout << SIMTIME << " veh=" << myVehicle.getID() << " ret=" << ret;
3095 }
3096#endif
3097 // store state before canceling
3098 getCanceledState(laneOffset) |= ret;
3099 int retTraCI = myVehicle.influenceChangeDecision(ret);
3100 if ((retTraCI & LCA_TRACI) != 0) {
3101 if ((retTraCI & LCA_STAY) != 0) {
3102 ret = retTraCI;
3103 latDist = 0;
3104 } else if (((retTraCI & LCA_RIGHT) != 0 && laneOffset < 0)
3105 || ((retTraCI & LCA_LEFT) != 0 && laneOffset > 0)) {
3106 ret = retTraCI;
3107 latDist = latLaneDist;
3108 }
3109 }
3110#if defined(DEBUG_STRATEGIC_CHANGE) || defined(DEBUG_TRACI)
3111 if (gDebugFlag2) {
3112 std::cout << " reqAfterInfluence=" << toString((LaneChangeAction)retTraCI) << " ret=" << toString((LaneChangeAction)ret) << "\n";
3113 }
3114#endif
3115 return ret;
3116}
3117
3118
3119bool
3120MSLCM_SL2015::mustOvertakeStopped(bool checkCurrent, const MSLane& neighLane, const MSLeaderDistanceInfo& leaders, const MSLeaderDistanceInfo& neighLead,
3121 double posOnLane, double neighDist, bool right, double latLaneDist, double& currentDist, double& latDist) {
3122 bool mustOvertake = false;
3123 const bool checkOverTakeRight = avoidOvertakeRight();
3124 int rightmost;
3125 int leftmost;
3126 const bool curHasStopped = leaders.hasStoppedVehicle();
3127 const int dir = latLaneDist < 0 ? -1 : 1;
3128 const MSLane* neighBeyond = neighLane.getParallelLane(dir);
3129 const bool hasLaneBeyond = checkCurrent && neighBeyond != nullptr && neighBeyond->allowsVehicleClass(myVehicle.getVClass());
3130 UNUSED_PARAMETER(hasLaneBeyond);
3131 if (curHasStopped) {
3132 leaders.getSubLanes(&myVehicle, 0, rightmost, leftmost);
3133 for (int i = rightmost; i <= leftmost; i++) {
3134 const CLeaderDist& leader = leaders[i];
3135 if (leader.first != 0 && leader.first->isStopped() && leader.second < REACT_TO_STOPPED_DISTANCE) {
3136 const double overtakeDist = leader.second + myVehicle.getVehicleType().getLength() + leader.first->getVehicleType().getLengthWithGap();
3137 const double remaining = MIN2(neighDist, currentDist) - posOnLane;
3138#ifdef DEBUG_STRATEGIC_CHANGE
3139 if (DEBUG_COND) {
3140 std::cout << " overtakeDist=" << overtakeDist << " remaining=" << remaining
3141 << " minDistToStopped=" << neighLead.getMinDistToStopped()
3142 << " hasLaneBeyond=" << hasLaneBeyond
3143 << "\n";
3144 }
3145#endif
3146 if (// current destination leaves enough space to overtake the leader
3147 remaining > overtakeDist
3148 // maybe do not overtake on the right at high speed
3149 && (!checkCurrent || !checkOverTakeRight || !right)
3150 && (!neighLead.hasStoppedVehicle() || neighLead.getMinDistToStopped() > overtakeDist /*|| (hasLaneBeyond && hasFreeLaneBeyond(neighBeyond, dir))*/)
3151 //&& (neighLead.first == 0 || !neighLead.first->isStopped()
3152 // // neighboring stopped vehicle leaves enough space to overtake leader
3153 // || neighLead.second > overtakeDist))
3154 ) {
3155 // avoid becoming stuck behind a stopped leader
3156 currentDist = myVehicle.getPositionOnLane() + leader.second;
3157 myLeftSpace = currentDist - posOnLane;
3158 latDist = latLaneDist;
3159 mustOvertake = true;
3160#ifdef DEBUG_STRATEGIC_CHANGE
3161 if (DEBUG_COND) {
3162 std::cout << " veh=" << myVehicle.getID() << " overtake stopped leader=" << leader.first->getID()
3163 << " newCurrentDist=" << currentDist
3164 << " overtakeDist=" << overtakeDist
3165 << " remaining=" << remaining
3166 << "\n";
3167 }
3168#endif
3169 }
3170 }
3171
3172 }
3173 }
3174 if (!mustOvertake && !curHasStopped && neighLead.hasStoppedVehicle()) {
3175 // #todo fix this if the neigh lane has a different width
3176 const double offset = (latLaneDist < 0 ? -1 : 1) * myVehicle.getLane()->getWidth();
3177 neighLead.getSubLanes(&myVehicle, offset, rightmost, leftmost);
3178 for (int i = 0; i < leaders.numSublanes(); i++) {
3179 const CLeaderDist& leader = leaders[i];
3180 if (leader.first != 0 && leader.first->isStopped() && leader.second < REACT_TO_STOPPED_DISTANCE) {
3181 mustOvertake = true;
3182 if (i >= rightmost && i <= leftmost) {
3183 latDist = myVehicle.getLateralOverlap() * (latLaneDist > 0 ? -1 : 1);
3184 break;
3185 }
3186 }
3187 }
3188 }
3189 return mustOvertake;
3190}
3191
3192
3193double
3195 return (state & LCA_STRATEGIC) != 0 ? MAX2(0.0, (1.0 - myPushy * (1 + 0.5 * myImpatience))) : 1.0;
3196}
3197
3198
3199int
3201 const MSLeaderDistanceInfo& leaders,
3202 const MSLeaderDistanceInfo& followers,
3203 const MSLeaderDistanceInfo& blockers,
3204 const MSLeaderDistanceInfo& neighLeaders,
3205 const MSLeaderDistanceInfo& neighFollowers,
3206 const MSLeaderDistanceInfo& neighBlockers,
3207 const MSLane& neighLane,
3208 int laneOffset,
3209 double& latDist,
3210 double& maneuverDist,
3211 int& blocked) {
3212
3213 /* @notes
3214 * vehicles may need to compromise between fulfilling lane change objectives
3215 * (LCA_STRATEGIC, LCA_SPEED etc) and maintaining lateral gap. The minimum
3216 * acceptable lateral gap depends on
3217 * - the cultural context (China vs Europe)
3218 * - the driver agressiveness (willingness to encroach on other vehicles to force them to move laterally as well)
3219 * - see @note in checkBlocking
3220 * - the vehicle type (car vs motorcycle)
3221 * - the current speed
3222 * - the speed difference
3223 * - the importance / urgency of the desired maneuver
3224 *
3225 * the object of this method is to evaluate the above circumstances and
3226 * either:
3227 * - allow the current maneuver (state, latDist)
3228 * - to override the current maneuver with a distance-keeping maneuver
3229 *
3230 *
3231 * laneChangeModel/driver parameters
3232 * - bool pushy (willingness to encroach)
3233 * - float minGap at 100km/h (to be interpolated for lower speeds (assume 0 at speed 0)
3234 * - gapFactors (a factor for each of the change reasons
3235 *
3236 * further assumptions
3237 * - the maximum of egoSpeed and deltaSpeed can be used when interpolating minGap
3238 * - distance keeping to the edges of the road can be ignored (for now)
3239 *
3240 * currentMinGap = minGap * min(1.0, max(v, abs(v - vOther)) / 100) * gapFactor[lc_reason]
3241 *
3242 * */
3243
3245 double gapFactor = computeGapFactor(state);
3246 const double oldLatDist = latDist;
3247 const double oldManeuverDist = maneuverDist;
3249 const int traciState = myVehicle.influenceChangeDecision(state);
3250
3251 // compute gaps after maneuver
3252 const double halfWidth = getWidth() * 0.5;
3253 // if the current maneuver is blocked we will stay where we are
3254 const double oldCenter = myVehicle.getCenterOnEdge();
3255 // surplus gaps. these are used to collect various constraints
3256 // if they do not permit the desired maneuvre, should override it to better maintain distance
3257 // stay within the current edge
3258 double surplusGapRight = oldCenter - halfWidth;
3259 double surplusGapLeft = getLeftBorder(laneOffset != 0) - oldCenter - halfWidth;
3260 const bool stayInLane = (laneOffset == 0
3261 || ((traciState & LCA_STRATEGIC) != 0
3262 && (traciState & LCA_STAY) != 0
3263 // permit wide vehicles to stay on the road
3264 && (surplusGapLeft >= 0 && surplusGapRight >= 0)));
3265
3266 if (isOpposite()) {
3267 std::swap(surplusGapLeft, surplusGapRight);
3268 }
3269#ifdef DEBUG_KEEP_LATGAP
3270 if (gDebugFlag2) {
3271 std::cout << "\n " << SIMTIME << " keepLatGap() laneOffset=" << laneOffset
3272 << " latDist=" << latDist
3273 << " maneuverDist=" << maneuverDist
3274 << " state=" << toString((LaneChangeAction)state)
3275 << " traciState=" << toString((LaneChangeAction)traciState)
3276 << " blocked=" << toString((LaneChangeAction)blocked)
3277 << " gapFactor=" << gapFactor
3278 << " stayInLane=" << stayInLane << "\n"
3279 << " stayInEdge: surplusGapRight=" << surplusGapRight << " surplusGapLeft=" << surplusGapLeft << "\n";
3280 }
3281#endif
3282 // staying within the edge overrides all minGap considerations
3283 if (surplusGapLeft < 0 || surplusGapRight < 0) {
3284 gapFactor = 0;
3285 }
3286
3287 // maintain gaps to vehicles on the current lane
3288 // ignore vehicles that are too far behind
3289 const double netOverlap = -myVehicle.getVehicleType().getLength() * 0.5;
3290 updateGaps(leaders, myVehicle.getLane()->getRightSideOnEdge(), oldCenter, gapFactor, surplusGapRight, surplusGapLeft, true);
3291 updateGaps(followers, myVehicle.getLane()->getRightSideOnEdge(), oldCenter, gapFactor, surplusGapRight, surplusGapLeft, true, netOverlap);
3292
3293 if (laneOffset != 0) {
3294 // maintain gaps to vehicles on the target lane
3295 const double neighRight = getNeighRight(neighLane);
3296 updateGaps(neighLeaders, neighRight, oldCenter, gapFactor, surplusGapRight, surplusGapLeft, true);
3297 updateGaps(neighFollowers, neighRight, oldCenter, gapFactor, surplusGapRight, surplusGapLeft, true, netOverlap);
3298 }
3299#ifdef DEBUG_KEEP_LATGAP
3300 if (gDebugFlag2) {
3301 std::cout << " minGapLat: surplusGapRight=" << surplusGapRight << " surplusGapLeft=" << surplusGapLeft << "\n"
3302 << " lastGaps: right=" << myLastLateralGapRight << " left=" << myLastLateralGapLeft << "\n";
3303 }
3304#endif
3305 // we also need to track the physical gap, in addition to the psychological gap
3306 double physicalGapLeft = myLastLateralGapLeft == NO_NEIGHBOR ? surplusGapLeft : myLastLateralGapLeft;
3307 double physicalGapRight = myLastLateralGapRight == NO_NEIGHBOR ? surplusGapRight : myLastLateralGapRight;
3308
3309 const double halfLaneWidth = myVehicle.getLane()->getWidth() * 0.5;
3310 const double posLat = myVehicle.getLateralPositionOnLane() * (isOpposite() ? -1 : 1);
3311 if (stayInLane || laneOffset == 1) {
3312 // do not move past the right boundary of the current lane (traffic wasn't checked there)
3313 // but assume it's ok to be where we are in case we are already beyond
3314 surplusGapRight = MIN2(surplusGapRight, MAX2(0.0, halfLaneWidth + posLat - halfWidth));
3315 physicalGapRight = MIN2(physicalGapRight, MAX2(0.0, halfLaneWidth + posLat - halfWidth));
3316 }
3317 if (stayInLane || laneOffset == -1) {
3318 // do not move past the left boundary of the current lane (traffic wasn't checked there)
3319 // but assume it's ok to be where we are in case we are already beyond
3320 surplusGapLeft = MIN2(surplusGapLeft, MAX2(0.0, halfLaneWidth - posLat - halfWidth));
3321 physicalGapLeft = MIN2(physicalGapLeft, MAX2(0.0, halfLaneWidth - posLat - halfWidth));
3322 }
3323#ifdef DEBUG_KEEP_LATGAP
3324 if (gDebugFlag2) {
3325 std::cout << " stayInLane: surplusGapRight=" << surplusGapRight << " surplusGapLeft=" << surplusGapLeft << "\n";
3326 }
3327#endif
3328
3329 if (surplusGapRight + surplusGapLeft < 0) {
3330 // insufficient lateral space to fulfill all requirements. apportion space proportionally
3331 if ((state & LCA_CHANGE_REASONS) == 0) {
3332 state |= LCA_SUBLANE;
3333 }
3334 const double equalDeficit = 0.5 * (surplusGapLeft + surplusGapRight);
3335 if (surplusGapRight < surplusGapLeft) {
3336 // shift further to the left but no further than there is physical space
3337 const double delta = MIN2(equalDeficit - surplusGapRight, physicalGapLeft);
3338 latDist = delta;
3339 maneuverDist = delta;
3340#ifdef DEBUG_KEEP_LATGAP
3341 if (gDebugFlag2) {
3342 std::cout << " insufficient latSpace, move left: delta=" << delta << "\n";
3343 }
3344#endif
3345 } else {
3346 // shift further to the right but no further than there is physical space
3347 const double delta = MIN2(equalDeficit - surplusGapLeft, physicalGapRight);
3348 latDist = -delta;
3349 maneuverDist = -delta;
3350#ifdef DEBUG_KEEP_LATGAP
3351 if (gDebugFlag2) {
3352 std::cout << " insufficient latSpace, move right: delta=" << delta << "\n";
3353 }
3354#endif
3355 }
3356 } else {
3357 // sufficient space. move as far as the gaps permit
3358 latDist = MAX2(MIN2(latDist, surplusGapLeft), -surplusGapRight);
3359 maneuverDist = MAX2(MIN2(maneuverDist, surplusGapLeft), -surplusGapRight);
3360 if ((state & LCA_KEEPRIGHT) != 0 && maneuverDist != oldManeuverDist) {
3361 // don't start keepRight unless it can be completed
3362 latDist = oldLatDist;
3363 maneuverDist = oldManeuverDist;
3364 }
3365#ifdef DEBUG_KEEP_LATGAP
3366 if (gDebugFlag2) {
3367 std::cout << " adapted latDist=" << latDist << " maneuverDist=" << maneuverDist << " (old=" << oldLatDist << ")\n";
3368 }
3369#endif
3370 }
3371 // take into account overriding traci sublane-request
3373 // @note: the influence is reset in MSAbstractLaneChangeModel::setOwnState at the end of the lane-changing code for this vehicle
3374 latDist = myVehicle.getInfluencer().getLatDist();
3375 maneuverDist = myVehicle.getInfluencer().getLatDist();
3376 if (latDist < 0) {
3378 } else {
3380 }
3381 state |= LCA_TRACI;
3382#ifdef DEBUG_KEEP_LATGAP
3383 if (gDebugFlag2) {
3384 std::cout << " traci influenced latDist=" << latDist << "\n";
3385 }
3386#endif
3387 }
3388 // if we cannot move in the desired direction, consider the maneuver blocked anyway
3389 const bool nonSublaneChange = (state & (LCA_STRATEGIC | LCA_COOPERATIVE | LCA_SPEEDGAIN | LCA_KEEPRIGHT)) != 0;
3390 const bool traciChange = ((state | traciState) & LCA_TRACI) != 0;
3391 if (nonSublaneChange && !traciChange) {
3392 if ((latDist < NUMERICAL_EPS * myVehicle.getActionStepLengthSecs()) && (oldLatDist > 0)) {
3393#ifdef DEBUG_KEEP_LATGAP
3394 if (gDebugFlag2) {
3395 std::cout << " wanted changeToLeft oldLatDist=" << oldLatDist << ", blocked latGap changeToRight\n";
3396 }
3397#endif
3398 latDist = oldLatDist; // restore old request for usage in decideDirection()
3400 } else if ((latDist > -NUMERICAL_EPS * myVehicle.getActionStepLengthSecs()) && (oldLatDist < 0)) {
3401#ifdef DEBUG_KEEP_LATGAP
3402 if (gDebugFlag2) {
3403 std::cout << " wanted changeToRight oldLatDist=" << oldLatDist << ", blocked latGap changeToLeft\n";
3404 }
3405#endif
3406 latDist = oldLatDist; // restore old request for usage in decideDirection()
3408 }
3409 }
3410 // if we move, even though we wish to stay, update the change reason (except for TraCI)
3411 if (fabs(latDist) > NUMERICAL_EPS * myVehicle.getActionStepLengthSecs() && oldLatDist == 0) {
3412 state &= (~(LCA_CHANGE_REASONS | LCA_STAY) | LCA_TRACI);
3413 }
3414 // update blocked status
3415 if (fabs(latDist - oldLatDist) > NUMERICAL_EPS * myVehicle.getActionStepLengthSecs()) {
3416#ifdef DEBUG_KEEP_LATGAP
3417 if (gDebugFlag2) {
3418 std::cout << " latDistUpdated=" << latDist << " oldLatDist=" << oldLatDist << "\n";
3419 }
3420#endif
3421 blocked = checkBlocking(neighLane, latDist, maneuverDist, laneOffset, leaders, followers, blockers, neighLeaders, neighFollowers, neighBlockers, nullptr, nullptr, nonSublaneChange);
3422 }
3423 if (fabs(latDist) > NUMERICAL_EPS * myVehicle.getActionStepLengthSecs()) {
3424 state = (state & ~LCA_STAY);
3425 if ((state & LCA_CHANGE_REASONS) == 0) {
3426 state |= LCA_SUBLANE;
3427 }
3428 } else {
3429 if ((state & LCA_SUBLANE) != 0) {
3430 state |= LCA_STAY;
3431 }
3432 // avoid setting blinker due to numerical issues
3433 latDist = 0;
3434 }
3435#if defined(DEBUG_KEEP_LATGAP) || defined(DEBUG_STATE)
3436 if (gDebugFlag2) {
3437 std::cout << " latDist2=" << latDist
3438 << " state2=" << toString((LaneChangeAction)state)
3439 << " lastGapLeft=" << myLastLateralGapLeft
3440 << " lastGapRight=" << myLastLateralGapRight
3441 << " blockedAfter=" << toString((LaneChangeAction)blocked)
3442 << "\n";
3443 }
3444#endif
3445 return state;
3446}
3447
3448
3449void
3450MSLCM_SL2015::updateGaps(const MSLeaderDistanceInfo& others, double foeOffset, double oldCenter, double gapFactor,
3451 double& surplusGapRight, double& surplusGapLeft,
3452 bool saveMinGap, double netOverlap,
3453 double latDist,
3454 std::vector<CLeaderDist>* collectBlockers) {
3455 if (others.hasVehicles()) {
3456 const double halfWidth = getWidth() * 0.5 + NUMERICAL_EPS;
3457 const double baseMinGap = myMinGapLat;
3458 for (int i = 0; i < others.numSublanes(); ++i) {
3459 if (others[i].first != 0 && others[i].second <= 0
3460 && myCFRelated.count(others[i].first) == 0
3461 && (netOverlap == 0 || others[i].second + others[i].first->getVehicleType().getMinGap() < netOverlap)) {
3463 const MSVehicle* foe = others[i].first;
3464 const double res = MSGlobals::gLateralResolution > 0 ? MSGlobals::gLateralResolution : others[i].first->getLane()->getWidth();
3465 double foeRight, foeLeft;
3466 others.getSublaneBorders(i, foeOffset, foeRight, foeLeft);
3467 const double foeCenter = foeRight + 0.5 * res;
3468 const double gap = MIN2(fabs(foeRight - oldCenter), fabs(foeLeft - oldCenter)) - halfWidth;
3470 const double desiredMinGap = baseMinGap * deltaV / LATGAP_SPEED_THRESHOLD;
3471 const double currentMinGap = desiredMinGap * gapFactor; // pushy vehicles may accept a lower lateral gap temporarily
3472 /*
3473 if (netOverlap != 0) {
3474 // foe vehicle is follower with its front ahead of the ego midpoint
3475 // scale gap requirements so it gets lower for foe which are further behind ego
3476 //
3477 // relOverlap approaches 0 as the foe gets closer to the midpoint and it equals 1 if the foe is driving head-to-head
3478 const double relOverlap = 1 - (others[i].second + others[i].first->getVehicleType().getMinGap()) / netOverlap;
3479 currentMinGap *= currOverlap * relOverlap;
3480 }
3481 */
3482#if defined(DEBUG_BLOCKING) || defined(DEBUG_KEEP_LATGAP)
3483 if (debugVehicle()) {
3484 std::cout << " updateGaps"
3485 << " i=" << i
3486 << " foe=" << foe->getID()
3487 << " foeRight=" << foeRight
3488 << " foeLeft=" << foeLeft
3489 << " oldCenter=" << oldCenter
3490 << " gap=" << others[i].second
3491 << " latgap=" << gap
3492 << " currentMinGap=" << currentMinGap
3493 << " surplusGapRight=" << surplusGapRight
3494 << " surplusGapLeft=" << surplusGapLeft
3495 << "\n";
3496 }
3497#endif
3498
3499 // If foe is maneuvering towards ego, reserve some additional distance.
3500 // But don't expect the foe to come closer than currentMinGap if it isn't already there.
3501 // (XXX: How can the ego know the foe's maneuver dist?)
3502 if (foeCenter < oldCenter) { // && foe->getLaneChangeModel().getSpeedLat() > 0) {
3503 const double foeManeuverDist = MAX2(0., foe->getLaneChangeModel().getManeuverDist());
3504 surplusGapRight = MIN3(surplusGapRight, gap - currentMinGap, MAX2(currentMinGap, gap - foeManeuverDist));
3505 } else { //if (foeCenter > oldCenter && foe->getLaneChangeModel().getSpeedLat() < 0) {
3506 const double foeManeuverDist = -MIN2(0., foe->getLaneChangeModel().getManeuverDist());
3507 surplusGapLeft = MIN3(surplusGapLeft, gap - currentMinGap, MAX2(currentMinGap, gap - foeManeuverDist));
3508 }
3509 if (saveMinGap) {
3510 if (foeCenter < oldCenter) {
3511#if defined(DEBUG_BLOCKING) || defined(DEBUG_KEEP_LATGAP)
3512 if (gDebugFlag2 && gap < myLastLateralGapRight) {
3513 std::cout << " new minimum rightGap=" << gap << "\n";
3514 }
3515#endif
3517 } else {
3518#if defined(DEBUG_BLOCKING) || defined(DEBUG_KEEP_LATGAP)
3519 if (gDebugFlag2 && gap < myLastLateralGapLeft) {
3520 std::cout << " new minimum leftGap=" << gap << "\n";
3521 }
3522#endif
3524 }
3525 }
3526 if (collectBlockers != nullptr) {
3527 // check if the vehicle is blocking a desire lane change
3528 if ((foeCenter < oldCenter && latDist < 0 && gap < (desiredMinGap - latDist))
3529 || (foeCenter > oldCenter && latDist > 0 && gap < (desiredMinGap + latDist))) {
3530 collectBlockers->push_back(others[i]);
3531 }
3532 }
3533 }
3534 }
3535 }
3536}
3537
3538
3539double
3541 return myVehicle.getVehicleType().getWidth() + NUMERICAL_EPS;
3542}
3543
3544
3545double
3546MSLCM_SL2015::computeSpeedLat(double latDist, double& maneuverDist, bool urgent) const {
3547 int currentDirection = mySpeedLat >= 0 ? 1 : -1;
3548 int directionWish = latDist >= 0 ? 1 : -1;
3549 double maxSpeedLat = myVehicle.getVehicleType().getMaxSpeedLat();
3550 double accelLat = myAccelLat;
3551 if (!urgent && (myLeftSpace > POSITION_EPS || myMaxSpeedLatFactor < 0)) {
3552 const double speedBound = myMaxSpeedLatStanding + myMaxSpeedLatFactor * myVehicle.getSpeed();
3553 if (myMaxSpeedLatFactor >= 0) {
3554 // speedbound increases with speed and needs an upper bound
3555 maxSpeedLat = MIN2(maxSpeedLat, speedBound);
3556 } else {
3557 // speedbound decreases with speed and needs a lower bound
3558 // (only useful if myMaxSpeedLatStanding > maxSpeedLat)
3559 maxSpeedLat = MAX2(maxSpeedLat, speedBound);
3560 // increase (never decrease) lateral acceleration in proportion
3561 accelLat *= MAX2(1.0, speedBound / myVehicle.getVehicleType().getMaxSpeedLat());
3562 }
3563 }
3565 const double rightVehSide = myVehicle.getRightSideOnEdge();
3566 const double edgeOverlap = MAX2(-rightVehSide, rightVehSide + myVehicle.getVehicleType().getWidth() - myVehicle.getCurrentEdge()->getWidth());
3567 // if vehicle is outside edge bounds. Permit stronger lateral maneuvering
3568 accelLat = MAX2(accelLat, 2 * edgeOverlap);
3569 maxSpeedLat = MAX2(maxSpeedLat, edgeOverlap);
3570 }
3571
3572#ifdef DEBUG_MANEUVER
3573 if (debugVehicle()) {
3574 std::cout << SIMTIME
3575 << " veh=" << myVehicle.getID()
3576 << " computeSpeedLat()"
3577 << " latDist=" << latDist
3578 << " maneuverDist=" << maneuverDist
3579 << " urgent=" << urgent
3580 << " speedLat=" << mySpeedLat
3581 << " currentDirection=" << currentDirection
3582 << " directionWish=" << directionWish
3583 << " myLeftSpace=" << myLeftSpace
3584 << " maxSpeedLat=" << maxSpeedLat
3585 << std::endl;
3586 }
3587#endif
3588 // reduced lateral speed (in the desired direction). Don't change direction against desired.
3589 double speedDecel;
3590 if (directionWish == 1) {
3591 speedDecel = MAX2(mySpeedLat - ACCEL2SPEED(accelLat), 0.);
3592 } else {
3593 speedDecel = MIN2(mySpeedLat + ACCEL2SPEED(accelLat), 0.);
3594 }
3595 // increased lateral speed (in the desired direction)
3596 double speedAccel = MAX2(MIN2(mySpeedLat + directionWish * ACCEL2SPEED(accelLat), maxSpeedLat), -maxSpeedLat);
3597
3598 // can we reach the target distance in a single step? (XXX: assumes "Euler" update)
3599 double speedBound = DIST2SPEED(latDist);
3600 // for lat-gap keeping maneuvres myOrigLatDist may be 0
3601 const double fullLatDist = latDist > 0 ? MIN2(mySafeLatDistLeft, MAX2(maneuverDist, latDist)) : MAX2(-mySafeLatDistRight, MIN2(maneuverDist, latDist));
3602
3603 // update maneuverDist, if safety constraints apply in its direction
3604 if (maneuverDist * latDist > 0) {
3605 maneuverDist = fullLatDist;
3606 }
3607
3608#ifdef DEBUG_MANEUVER
3609 if (debugVehicle()) {
3610 std::cout << " mySafeLatDistRight=" << mySafeLatDistRight
3611 << " mySafeLatDistLeft=" << mySafeLatDistLeft
3612 << " fullLatDist=" << fullLatDist
3613 << " speedAccel=" << speedAccel
3614 << " speedDecel=" << speedDecel
3615 << " speedBound=" << speedBound
3616 << std::endl;
3617 }
3618#endif
3619 if (speedDecel * speedAccel <= 0 && (
3620 // speedAccel and speedDecel bracket speed 0. This means we can end the maneuver
3621 (latDist >= 0 && speedAccel >= speedBound && speedBound >= speedDecel)
3622 || (latDist <= 0 && speedAccel <= speedBound && speedBound <= speedDecel))) {
3623 // we can reach the desired value in this step
3624#ifdef DEBUG_MANEUVER
3625 if (debugVehicle()) {
3626 std::cout << " computeSpeedLat a)\n";
3627 }
3628#endif
3629 return speedBound;
3630 }
3631 // are we currently moving in the wrong direction?
3632 if (latDist * mySpeedLat < 0) {
3633#ifdef DEBUG_MANEUVER
3634 if (debugVehicle()) {
3635 std::cout << " computeSpeedLat b)\n";
3636 }
3637#endif
3638 return emergencySpeedLat(speedAccel);
3639 }
3640 // check if the remaining distance allows to accelerate laterally
3641 double minDistAccel = SPEED2DIST(speedAccel) + currentDirection * MSCFModel::brakeGapEuler(fabs(speedAccel), accelLat, 0); // most we can move in the target direction
3642 if ((fabs(minDistAccel) < fabs(fullLatDist)) || (fabs(minDistAccel - fullLatDist) < NUMERICAL_EPS)) {
3643#ifdef DEBUG_MANEUVER
3644 if (debugVehicle()) {
3645 std::cout << " computeSpeedLat c)\n";
3646 }
3647#endif
3648 return speedAccel;
3649 } else {
3650#ifdef DEBUG_MANEUVER
3651 if (debugVehicle()) {
3652 std::cout << " minDistAccel=" << minDistAccel << "\n";
3653 }
3654#endif
3655 // check if the remaining distance allows to maintain current lateral speed
3656 double minDistCurrent = SPEED2DIST(mySpeedLat) + currentDirection * MSCFModel::brakeGapEuler(fabs(mySpeedLat), accelLat, 0);
3657 if ((fabs(minDistCurrent) < fabs(fullLatDist)) || (fabs(minDistCurrent - fullLatDist) < NUMERICAL_EPS)) {
3658#ifdef DEBUG_MANEUVER
3659 if (debugVehicle()) {
3660 std::cout << " computeSpeedLat d)\n";
3661 }
3662#endif
3663 return mySpeedLat;
3664 }
3665 }
3666 // reduce lateral speed
3667#ifdef DEBUG_MANEUVER
3668 if (debugVehicle()) {
3669 std::cout << " computeSpeedLat e)\n";
3670 }
3671#endif
3672 return emergencySpeedLat(speedDecel);
3673}
3674
3675
3676double
3677MSLCM_SL2015::emergencySpeedLat(double speedLat) const {
3678 // reduce lateral speed for safety purposes
3679 if (speedLat < 0 && SPEED2DIST(-speedLat) > mySafeLatDistRight) {
3680 speedLat = -DIST2SPEED(mySafeLatDistRight);
3681#ifdef DEBUG_MANEUVER
3682 if (debugVehicle()) {
3683 std::cout << " rightDanger speedLat=" << speedLat << "\n";
3684 }
3685#endif
3686 } else if (speedLat > 0 && SPEED2DIST(speedLat) > mySafeLatDistLeft) {
3687 speedLat = DIST2SPEED(mySafeLatDistLeft);
3688#ifdef DEBUG_MANEUVER
3689 if (debugVehicle()) {
3690 std::cout << " leftDanger speedLat=" << speedLat << "\n";
3691 }
3692#endif
3693 }
3694 return speedLat;
3695}
3696
3697
3701 // Check whether the vehicle should adapt its alignment to an upcoming turn
3702 if (myTurnAlignmentDist > 0) {
3703 const std::pair<double, const MSLink*>& turnInfo = myVehicle.getNextTurn();
3704 const LinkDirection turnDir = turnInfo.second == nullptr ? LinkDirection::NODIR : turnInfo.second->getDirection();
3705 const bool indirect = turnInfo.second == nullptr ? false : turnInfo.second->isIndirect();
3706 if (turnInfo.first < myTurnAlignmentDist) {
3707 // Vehicle is close enough to the link to change its default alignment
3708 switch (turnDir) {
3712 if (myVehicle.getLane()->getBidiLane() == nullptr) {
3713 // no left alignment on bidi lane to avoid blocking oncoming traffic
3715 }
3716 break;
3721 break;
3724 default:
3725 break;
3726 }
3727 }
3728 }
3729 return align;
3730}
3731
3732
3733void
3734MSLCM_SL2015::commitManoeuvre(int blocked, int blockedFully,
3735 const MSLeaderDistanceInfo& leaders,
3736 const MSLeaderDistanceInfo& neighLeaders,
3737 const MSLane& neighLane,
3738 double maneuverDist) {
3739 if (!blocked && !blockedFully && !myCanChangeFully) {
3740 // round to full action steps
3741 double secondsToLeaveLane;
3743 secondsToLeaveLane = ceil(fabs(maneuverDist) / myVehicle.getVehicleType().getMaxSpeedLat() / myVehicle.getActionStepLengthSecs()) * myVehicle.getActionStepLengthSecs();
3744 // XXX myAccelLat must be taken into account (refs #3601, see ballistic case for solution)
3745
3746 // XXX This also causes probs: if the difference between the current speed and the committed is higher than the maximal decel,
3747 // the vehicle may pass myLeftSpace before completing the maneuver.
3748 myCommittedSpeed = MIN3(myLeftSpace / secondsToLeaveLane,
3751#if defined(DEBUG_MANEUVER) || defined(DEBUG_COMMITTED_SPEED)
3752 if (debugVehicle()) {
3753 std::cout << SIMTIME << " veh=" << myVehicle.getID() << " myCommittedSpeed=" << myCommittedSpeed << " leftSpace=" << myLeftSpace << " secondsToLeave=" << secondsToLeaveLane << "\n";
3754 }
3755#endif
3756 } else {
3757
3758 // Calculate seconds needed for leaving lane assuming start from lateral speed zero, and lat.accel == -lat.decel
3759 secondsToLeaveLane = MSCFModel::estimateArrivalTime(fabs(maneuverDist), 0., 0., myVehicle.getVehicleType().getMaxSpeedLat(), myAccelLat, myAccelLat);
3760 // round to full action steps
3761 secondsToLeaveLane = ceil(secondsToLeaveLane / myVehicle.getActionStepLengthSecs()) * myVehicle.getActionStepLengthSecs();
3762
3763 // committed speed will eventually be pushed into a drive item during the next planMove() step. This item
3764 // will not be read before the next action step at current time + actionStepLength-TS, so we need to schedule the corresponding speed.
3765 const double timeTillActionStep = myVehicle.getActionStepLengthSecs() - TS;
3766 const double nextActionStepSpeed = MAX2(0., myVehicle.getSpeed() + timeTillActionStep * myVehicle.getAcceleration());
3767 double nextLeftSpace;
3768 if (nextActionStepSpeed > 0.) {
3769 nextLeftSpace = myLeftSpace - timeTillActionStep * (myVehicle.getSpeed() + nextActionStepSpeed) * 0.5;
3770 } else if (myVehicle.getAcceleration() == 0) {
3771 nextLeftSpace = myLeftSpace;
3772 } else {
3773 assert(myVehicle.getAcceleration() < 0.);
3774 nextLeftSpace = myLeftSpace + (myVehicle.getSpeed() * myVehicle.getSpeed() / myVehicle.getAcceleration()) * 0.5;
3775 }
3776 const double avoidArrivalSpeed = nextActionStepSpeed + ACCEL2SPEED(MSCFModel::avoidArrivalAccel(
3777 nextLeftSpace, secondsToLeaveLane - timeTillActionStep, nextActionStepSpeed, myVehicle.getCarFollowModel().getEmergencyDecel()));
3778
3779 myCommittedSpeed = MIN3(avoidArrivalSpeed,
3782
3783#if defined(DEBUG_MANEUVER) || defined(DEBUG_COMMITTED_SPEED)
3784 if (gDebugFlag2) {
3785 std::cout << SIMTIME
3786 << " veh=" << myVehicle.getID()
3787 << " avoidArrivalSpeed=" << avoidArrivalSpeed
3788 << " currentSpeed=" << myVehicle.getSpeed()
3789 << " myLeftSpace=" << myLeftSpace
3790 << "\n nextLeftSpace=" << nextLeftSpace
3791 << " nextActionStepSpeed=" << nextActionStepSpeed
3792 << " nextActionStepRemainingSeconds=" << secondsToLeaveLane - timeTillActionStep
3793 << "\n";
3794 }
3795#endif
3796 }
3797 myCommittedSpeed = commitFollowSpeed(myCommittedSpeed, maneuverDist, secondsToLeaveLane, leaders, myVehicle.getLane()->getRightSideOnEdge());
3798 myCommittedSpeed = commitFollowSpeed(myCommittedSpeed, maneuverDist, secondsToLeaveLane, neighLeaders, neighLane.getRightSideOnEdge());
3800 myCommittedSpeed = 0;
3801 }
3802#if defined(DEBUG_MANEUVER) || defined(DEBUG_COMMITTED_SPEED)
3803 if (gDebugFlag2) {
3804 std::cout << SIMTIME
3805 << " veh=" << myVehicle.getID()
3806 << " secondsToLeave=" << secondsToLeaveLane
3808 << " committed=" << myCommittedSpeed
3809 << "\n";
3810 }
3811#endif
3812 }
3813}
3814
3815double
3816MSLCM_SL2015::commitFollowSpeed(double speed, double latDist, double secondsToLeaveLane, const MSLeaderDistanceInfo& leaders, double foeOffset) const {
3817 if (leaders.hasVehicles()) {
3818 // we distinguish 3 cases
3819 // - vehicles with lateral overlap at the end of the maneuver: try to follow safely
3820 // - vehicles with overlap at the start of the maneuver: avoid collision within secondsToLeaveLane
3821 // - vehicles without overlap: ignore
3822
3823 const double maxDecel = myVehicle.getCarFollowModel().getMaxDecel();
3824 // temporarily use another decel value
3825 MSCFModel& cfmodel = const_cast<MSCFModel&>(myVehicle.getCarFollowModel());
3826 cfmodel.setMaxDecel(maxDecel / getSafetyFactor());
3827
3828 const double vehWidth = getWidth();
3829 const double rightVehSide = myVehicle.getCenterOnEdge() - 0.5 * vehWidth;
3830 const double leftVehSide = rightVehSide + vehWidth;
3831 const double rightVehSideDest = rightVehSide + latDist;
3832 const double leftVehSideDest = leftVehSide + latDist;
3833#if defined(DEBUG_MANEUVER) || defined(DEBUG_COMMITTED_SPEED)
3834 if (gDebugFlag2) {
3835 std::cout << " commitFollowSpeed"
3836 << " latDist=" << latDist
3837 << " foeOffset=" << foeOffset
3838 << " vehRight=" << rightVehSide
3839 << " vehLeft=" << leftVehSide
3840 << " destRight=" << rightVehSideDest
3841 << " destLeft=" << leftVehSideDest
3842 << "\n";
3843 }
3844#endif
3845 for (int i = 0; i < leaders.numSublanes(); ++i) {
3846 CLeaderDist vehDist = leaders[i];
3847 if (vehDist.first != 0) {
3848 const MSVehicle* leader = vehDist.first;
3849 // only check the current stripe occuped by foe (transform into edge-coordinates)
3850 double foeRight, foeLeft;
3851 leaders.getSublaneBorders(i, foeOffset, foeRight, foeLeft);
3852#if defined(DEBUG_MANEUVER) || defined(DEBUG_COMMITTED_SPEED)
3853 if (gDebugFlag2) {
3854 std::cout << " foe=" << vehDist.first->getID()
3855 << " gap=" << vehDist.second
3856 << " secGap=" << myVehicle.getCarFollowModel().getSecureGap(&myVehicle, leader, myVehicle.getSpeed(), leader->getSpeed(), leader->getCarFollowModel().getMaxDecel())
3857 << " foeRight=" << foeRight
3858 << " foeLeft=" << foeLeft
3859 << " overlapBefore=" << overlap(rightVehSide, leftVehSide, foeRight, foeLeft)
3860 << " overlapDest=" << overlap(rightVehSideDest, leftVehSideDest, foeRight, foeLeft)
3861 << "\n";
3862 }
3863#endif
3864 if (overlap(rightVehSideDest, leftVehSideDest, foeRight, foeLeft)) {
3865 // case 1
3866 const double vSafe = myVehicle.getCarFollowModel().followSpeed(
3867 &myVehicle, speed, vehDist.second, leader->getSpeed(), leader->getCarFollowModel().getMaxDecel());
3868 speed = MIN2(speed, vSafe);
3869#if defined(DEBUG_MANEUVER) || defined(DEBUG_COMMITTED_SPEED)
3870 if (gDebugFlag2) {
3871 std::cout << " case1 vsafe=" << vSafe << " speed=" << speed << "\n";
3872 }
3873#endif
3874 } else if (overlap(rightVehSide, leftVehSide, foeRight, foeLeft)) {
3875 // case 2
3876 const double vSafe = myVehicle.getCarFollowModel().followSpeedTransient(
3877 secondsToLeaveLane,
3878 &myVehicle, speed, vehDist.second, leader->getSpeed(), leader->getCarFollowModel().getMaxDecel());
3879 speed = MIN2(speed, vSafe);
3880#if defined(DEBUG_MANEUVER) || defined(DEBUG_COMMITTED_SPEED)
3881 if (gDebugFlag2) {
3882 std::cout << " case2 vsafe=" << vSafe << " speed=" << speed << "\n";
3883 }
3884#endif
3885 }
3886 }
3887 }
3888 // restore original deceleration
3889 cfmodel.setMaxDecel(maxDecel);
3890
3891 }
3892 return speed;
3893}
3894
3895double
3897 return 1 / ((1 + 0.5 * myImpatience) * myAssertive);
3898}
3899
3900double
3902 return myOppositeParam <= 0 ? std::numeric_limits<double>::max() : 1 / myOppositeParam;
3903}
3904
3905
3906std::string
3907MSLCM_SL2015::getParameter(const std::string& key) const {
3909 return toString(myStrategicParam);
3910 } else if (key == toString(SUMO_ATTR_LCA_COOPERATIVE_PARAM)) {
3912 } else if (key == toString(SUMO_ATTR_LCA_SPEEDGAIN_PARAM)) {
3913 return toString(mySpeedGainParam);
3914 } else if (key == toString(SUMO_ATTR_LCA_KEEPRIGHT_PARAM)) {
3915 return toString(myKeepRightParam);
3916 } else if (key == toString(SUMO_ATTR_LCA_OPPOSITE_PARAM)) {
3917 return toString(myOppositeParam);
3918 } else if (key == toString(SUMO_ATTR_LCA_SUBLANE_PARAM)) {
3919 return toString(mySublaneParam);
3920 } else if (key == toString(SUMO_ATTR_MINGAP_LAT)) {
3921 return toString(myMinGapLat);
3922 } else if (key == toString(SUMO_ATTR_LCA_PUSHY)) {
3923 return toString(myPushy);
3924 } else if (key == toString(SUMO_ATTR_LCA_PUSHYGAP)) {
3925 return toString((myPushy - 1) * myMinGapLat);
3926 } else if (key == toString(SUMO_ATTR_LCA_ASSERTIVE)) {
3927 return toString(myAssertive);
3928 } else if (key == toString(SUMO_ATTR_LCA_IMPATIENCE)) {
3929 return toString(myImpatience);
3930 } else if (key == toString(SUMO_ATTR_LCA_TIME_TO_IMPATIENCE)) {
3932 } else if (key == toString(SUMO_ATTR_LCA_ACCEL_LAT)) {
3933 return toString(myAccelLat);
3934 } else if (key == toString(SUMO_ATTR_LCA_LOOKAHEADLEFT)) {
3935 return toString(myLookaheadLeft);
3936 } else if (key == toString(SUMO_ATTR_LCA_SPEEDGAINRIGHT)) {
3937 return toString(mySpeedGainRight);
3938 } else if (key == toString(SUMO_ATTR_LCA_LANE_DISCIPLINE)) {
3939 return toString(myLaneDiscipline);
3940 } else if (key == toString(SUMO_ATTR_LCA_SIGMA)) {
3941 return toString(mySigma);
3946 } else if (key == toString(SUMO_ATTR_LCA_SPEEDGAIN_LOOKAHEAD)) {
3948 } else if (key == toString(SUMO_ATTR_LCA_SPEEDGAIN_REMAIN_TIME)) {
3952 } else if (key == toString(SUMO_ATTR_LCA_COOPERATIVE_SPEED)) {
3954 } else if (key == toString(SUMO_ATTR_LCA_MAXSPEEDLATSTANDING)) {
3956 } else if (key == toString(SUMO_ATTR_LCA_MAXSPEEDLATFACTOR)) {
3958 } else if (key == toString(SUMO_ATTR_LCA_MAXDISTLATSTANDING)) {
3960 // access to internal state for debugging in sumo-gui (not documented since it may change at any time)
3961 } else if (key == "speedGainProbabilityRight") {
3963 } else if (key == "speedGainProbabilityLeft") {
3965 } else if (key == "keepRightProbability") {
3967 } else if (key == "lookAheadSpeed") {
3968 return toString(myLookAheadSpeed);
3969 } else if (key == "sigmaState") {
3970 return toString(mySigmaState);
3971 // motivation relative to threshold
3972 } else if (key == "speedGainRP") {
3974 } else if (key == "speedGainLP") {
3976 } else if (key == "keepRightP") {
3978 }
3979 throw InvalidArgument("Parameter '" + key + "' is not supported for laneChangeModel of type '" + toString(myModel) + "'");
3980}
3981
3982void
3983MSLCM_SL2015::setParameter(const std::string& key, const std::string& value) {
3984 double doubleValue;
3985 try {
3986 doubleValue = StringUtils::toDouble(value);
3987 } catch (NumberFormatException&) {
3988 throw InvalidArgument("Setting parameter '" + key + "' requires a number for laneChangeModel of type '" + toString(myModel) + "'");
3989 }
3991 myStrategicParam = doubleValue;
3992 } else if (key == toString(SUMO_ATTR_LCA_COOPERATIVE_PARAM)) {
3993 myCooperativeParam = doubleValue;
3994 } else if (key == toString(SUMO_ATTR_LCA_SPEEDGAIN_PARAM)) {
3995 mySpeedGainParam = doubleValue;
3996 } else if (key == toString(SUMO_ATTR_LCA_KEEPRIGHT_PARAM)) {
3997 myKeepRightParam = doubleValue;
3998 } else if (key == toString(SUMO_ATTR_LCA_OPPOSITE_PARAM)) {
3999 myOppositeParam = doubleValue;
4000 } else if (key == toString(SUMO_ATTR_LCA_SUBLANE_PARAM)) {
4001 mySublaneParam = doubleValue;
4002 } else if (key == toString(SUMO_ATTR_MINGAP_LAT)) {
4003 myMinGapLat = doubleValue;
4004 } else if (key == toString(SUMO_ATTR_LCA_PUSHY)) {
4005 myPushy = doubleValue;
4006 } else if (key == toString(SUMO_ATTR_LCA_PUSHYGAP)) {
4007 myPushy = 1 - doubleValue / myMinGapLat;
4008 } else if (key == toString(SUMO_ATTR_LCA_ASSERTIVE)) {
4009 myAssertive = doubleValue;
4010 } else if (key == toString(SUMO_ATTR_LCA_IMPATIENCE)) {
4011 myImpatience = doubleValue;
4012 myMinImpatience = doubleValue;
4013 } else if (key == toString(SUMO_ATTR_LCA_TIME_TO_IMPATIENCE)) {
4014 myTimeToImpatience = doubleValue;
4015 } else if (key == toString(SUMO_ATTR_LCA_ACCEL_LAT)) {
4016 myAccelLat = doubleValue;
4018 myTurnAlignmentDist = doubleValue;
4019 } else if (key == toString(SUMO_ATTR_LCA_LOOKAHEADLEFT)) {
4020 myLookaheadLeft = doubleValue;
4021 } else if (key == toString(SUMO_ATTR_LCA_SPEEDGAINRIGHT)) {
4022 mySpeedGainRight = doubleValue;
4023 } else if (key == toString(SUMO_ATTR_LCA_LANE_DISCIPLINE)) {
4024 myLaneDiscipline = doubleValue;
4025 } else if (key == toString(SUMO_ATTR_LCA_SIGMA)) {
4026 mySigma = doubleValue;
4028 myKeepRightAcceptanceTime = doubleValue;
4030 myOvertakeDeltaSpeedFactor = doubleValue;
4031 } else if (key == toString(SUMO_ATTR_LCA_SPEEDGAIN_LOOKAHEAD)) {
4032 mySpeedGainLookahead = doubleValue;
4033 } else if (key == toString(SUMO_ATTR_LCA_SPEEDGAIN_REMAIN_TIME)) {
4034 mySpeedGainRemainTime = doubleValue;
4036 myRoundaboutBonus = doubleValue;
4037 } else if (key == toString(SUMO_ATTR_LCA_COOPERATIVE_SPEED)) {
4038 myCooperativeSpeed = doubleValue;
4039 } else if (key == toString(SUMO_ATTR_LCA_MAXSPEEDLATSTANDING)) {
4040 myMaxSpeedLatStanding = doubleValue;
4041 } else if (key == toString(SUMO_ATTR_LCA_MAXSPEEDLATFACTOR)) {
4042 myMaxSpeedLatFactor = doubleValue;
4043 } else if (key == toString(SUMO_ATTR_LCA_MAXDISTLATSTANDING)) {
4044 myMaxDistLatStanding = doubleValue;
4045 // access to internal state
4046 } else if (key == "speedGainProbabilityRight") {
4047 mySpeedGainProbabilityRight = doubleValue;
4048 } else if (key == "speedGainProbabilityLeft") {
4049 mySpeedGainProbabilityLeft = doubleValue;
4050 } else if (key == "keepRightProbability") {
4051 myKeepRightProbability = doubleValue;
4052 } else if (key == "lookAheadSpeed") {
4053 myLookAheadSpeed = doubleValue;
4054 } else if (key == "sigmaState") {
4055 mySigmaState = doubleValue;
4056 } else {
4057 throw InvalidArgument("Setting parameter '" + key + "' is not supported for laneChangeModel of type '" + toString(myModel) + "'");
4058 }
4060}
4061
4062
4063int
4065 int laneOffset,
4067 int blocked,
4068 const std::pair<MSVehicle*, double>& leader,
4069 const std::pair<MSVehicle*, double>& follower,
4070 const std::pair<MSVehicle*, double>& neighLead,
4071 const std::pair<MSVehicle*, double>& neighFollow,
4072 const MSLane& neighLane,
4073 const std::vector<MSVehicle::LaneQ>& preb,
4074 MSVehicle** lastBlocked,
4075 MSVehicle** firstBlocked) {
4076
4077 const LaneChangeAction alternatives = LCA_NONE; // @todo pas this data
4078
4079#ifdef DEBUG_WANTSCHANGE
4080 if (DEBUG_COND) {
4081 std::cout << "\nWANTS_CHANGE\n" << SIMTIME
4082 //<< std::setprecision(10)
4083 << " veh=" << myVehicle.getID()
4084 << " lane=" << myVehicle.getLane()->getID()
4085 << " neigh=" << neighLane.getID()
4086 << " pos=" << myVehicle.getPositionOnLane()
4087 << " posLat=" << myVehicle.getLateralPositionOnLane()
4088 << " speed=" << myVehicle.getSpeed()
4089 << " considerChangeTo=" << (laneOffset == -1 ? "right" : "left")
4090 << "\n";
4091 }
4092#endif
4093
4094 double latDist = 0;
4095 const double laneWidth = myVehicle.getLane()->getWidth();
4096 MSLeaderDistanceInfo leaders(leader, laneWidth);
4097 MSLeaderDistanceInfo followers(follower, laneWidth);
4098 MSLeaderDistanceInfo blockers(std::make_pair((MSVehicle*)nullptr, -1), laneWidth);
4099 MSLeaderDistanceInfo neighLeaders(neighLead, laneWidth);
4100 MSLeaderDistanceInfo neighFollowers(neighFollow, laneWidth);
4101 MSLeaderDistanceInfo neighBlockers(std::make_pair((MSVehicle*)nullptr, -1), laneWidth);
4102
4103 double maneuverDist;
4104 int result = _wantsChangeSublane(laneOffset,
4105 alternatives,
4106 leaders, followers, blockers,
4107 neighLeaders, neighFollowers, neighBlockers,
4108 neighLane, preb,
4109 lastBlocked, firstBlocked, latDist, maneuverDist, blocked);
4110
4111 myCanChangeFully = true;
4112 // ignore sublane motivation
4113 result &= ~LCA_SUBLANE;
4114 result |= getLCA(result, latDist);
4115
4116#if defined(DEBUG_WANTSCHANGE) || defined(DEBUG_STATE)
4117 if (DEBUG_COND) {
4118 if (result & LCA_WANTS_LANECHANGE) {
4119 std::cout << SIMTIME
4120 << " veh=" << myVehicle.getID()
4121 << " wantsChangeTo=" << (laneOffset == -1 ? "right" : "left")
4122 << ((result & LCA_URGENT) ? " (urgent)" : "")
4123 << ((result & LCA_CHANGE_TO_HELP) ? " (toHelp)" : "")
4124 << ((result & LCA_STRATEGIC) ? " (strat)" : "")
4125 << ((result & LCA_COOPERATIVE) ? " (coop)" : "")
4126 << ((result & LCA_SPEEDGAIN) ? " (speed)" : "")
4127 << ((result & LCA_KEEPRIGHT) ? " (keepright)" : "")
4128 << ((result & LCA_TRACI) ? " (traci)" : "")
4129 << ((blocked & LCA_BLOCKED) ? " (blocked)" : "")
4130 << ((blocked & LCA_OVERLAPPING) ? " (overlap)" : "")
4131 << "\n\n\n";
4132 }
4133 }
4134#endif
4135
4136 return result;
4137}
4138
4139
4140double
4141MSLCM_SL2015::getLeftBorder(bool checkOpposite) const {
4142 return (myVehicle.getLane()->getEdge().getWidth()
4143 + ((myVehicle.getLane()->getParallelOpposite() != nullptr && checkOpposite) ? myVehicle.getLane()->getParallelOpposite()->getEdge().getWidth() : 0));
4144}
4145
4146double
4148 if (isOpposite()) {
4150 } else {
4151 return myVehicle.getCenterOnEdge();
4152 }
4153}
4154
4155double
4156MSLCM_SL2015::getNeighRight(const MSLane& neighLane) const {
4157 if (isOpposite()) {
4159 } else if ((&myVehicle.getLane()->getEdge() != &neighLane.getEdge())) {
4161 } else {
4162 // the normal case
4163 return neighLane.getRightSideOnEdge();
4164 }
4165}
4166
4167
4168bool
4169MSLCM_SL2015::preventSliding(double maneuverDist) const {
4170 // prevent wide maneuvers with unsufficient forward space
4171 if (fabs(maneuverDist) > myMaxDistLatStanding) {
4172 // emergency vehicles should not be restricted (TODO solve this with LCA_URGENT)
4174 return false;
4175 }
4176 const double brakeGap = myVehicle.getCarFollowModel().brakeGap(myVehicle.getSpeed());
4177 const bool isSlide = fabs(maneuverDist) > myMaxDistLatStanding + brakeGap * fabs(myMaxSpeedLatFactor);
4178#ifdef DEBUG_SLIDING
4179 if (gDebugFlag2) {
4180 std::cout << SIMTIME << " veh=" << myVehicle.getID() << " bgap=" << brakeGap << " maneuverDist=" << maneuverDist
4181 << " mds=" << myMaxDistLatStanding << " isSlide=" << isSlide << "\n";
4182 }
4183#endif
4184 return isSlide;
4185 }
4186 return false;
4187}
4188
4189bool
4190MSLCM_SL2015::wantsKeepRight(double keepRightProb) const {
4192}
4193
4194
4195bool
4196MSLCM_SL2015::saveBlockerLength(double length, double foeLeftSpace) {
4197 const bool canReserve = MSLCHelper::canSaveBlockerLength(myVehicle, length, myLeftSpace);
4198 if (!isOpposite() && (canReserve || myLeftSpace > foeLeftSpace)) {
4200 if (myLeftSpace == 0 && foeLeftSpace < 0) {
4201 // called from opposite overtaking, myLeftSpace must be initialized
4203 }
4204 return true;
4205 } else {
4206 return false;
4207 }
4208}
4209
4210
4211bool
4215/****************************************************************************/
long long int SUMOTime
Definition GUI.h:36
#define JAM_FACTOR
#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:27
bool gDebugFlag2
Definition StdDefs.cpp:44
const double SUMO_const_laneWidth
Definition StdDefs.h:52
T MIN3(T a, T b, T c)
Definition StdDefs.h:93
T MIN2(T a, T b)
Definition StdDefs.h:80
const double SUMO_const_haltingSpeed
the speed threshold at which vehicles are considered as halting
Definition StdDefs.h:62
T MAX2(T a, T b)
Definition StdDefs.h:86
T MAX3(T a, T b, T c)
Definition StdDefs.h:100
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:938
bool canChangeToOpposite() const
whether this edge allows changing to the opposite direction edge
Definition MSEdge.cpp:1346
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:664
const std::vector< double > getSubLaneSides() const
Returns the right side offsets of this edge's sublanes.
Definition MSEdge.h:669
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 sublaneEnds(int i, const MSLane *next, double shift)
check whether the sublane continues on the next lane
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:4574
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:2850
const MSLink * getLinkTo(const MSLane *const) const
returns the link to the given lane or nullptr, if it is not connected
Definition MSLane.cpp:2745
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:932
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:1202
bool hasPedestrians() const
whether the lane has pedestrians on it
Definition MSLane.cpp:4567
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:4383
MSLane * getBidiLane() const
retrieve bidirectional lane or nullptr
Definition MSLane.cpp:4679
MSLane * getParallelOpposite() const
return the opposite direction lane of this lanes edge or nullptr
Definition MSLane.cpp:4389
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:3241
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:1206
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:187
SUMOTime getCurrentTimeStep() const
Returns the current simulation step.
Definition MSNet.h:334
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 getLeftSideOnLane() const
Get the lateral position of the vehicles left side on the lane:
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 MSEdge * getCurrentEdge() const
Returns the edge the vehicle is currently at (possibly an internal edge or nullptr)
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 getRightSideOnLane() const
Get the lateral position of the vehicles right side on the lane:
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