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-2026 German Aerospace Center (DLR) and others.
4// This program and the accompanying materials are made available under the
5// terms of the Eclipse Public License 2.0 which is available at
6// https://www.eclipse.org/legal/epl-2.0/
7// This Source Code may also be made available under the following Secondary
8// Licenses when the conditions for such availability set forth in the Eclipse
9// Public License 2.0 are satisfied: GNU General Public License, version 2
10// or later which is available at
11// https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html
12// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
13/****************************************************************************/
18// 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 const double targetSpeed = getCarFollowModel().followSpeed(
2084 &myVehicle, myVehicle.getSpeed(), (gap - POSITION_EPS),
2085 (*blocked)->getSpeed(), (*blocked)->getCarFollowModel().getMaxDecel());
2086#ifdef DEBUG_INFORM
2087 if (gDebugFlag2) {
2088 std::cout << " slowing down for blocked " << Named::getIDSecure(*blocked) << " targetSpeed=" << targetSpeed << "\n";
2089 }
2090#endif
2091 addLCSpeedAdvice(targetSpeed, false);
2092 //(*blocked) = 0; // VARIANT_14 (furtherBlock)
2093 }
2094 }
2095 }
2096 return state;
2097}
2098
2099
2100bool
2101MSLCM_SL2015::isBidi(const MSLane* lane) const {
2102 if (!MSNet::getInstance()->hasBidiEdges()) {
2103 return false;
2104 }
2105 if (lane == myVehicle.getLane()->getBidiLane()) {
2106 return true;
2107 }
2108 for (const MSLane* cand : myVehicle.getBestLanesContinuation()) {
2109 if (cand != nullptr && cand->getBidiLane() == lane) {
2110 return true;
2111 }
2112 }
2113 return false;
2114}
2115
2116void
2117MSLCM_SL2015::updateExpectedSublaneSpeeds(const MSLeaderDistanceInfo& ahead, int sublaneOffset, int laneIndex) {
2118 const std::vector<MSLane*>& lanes = myVehicle.getLane()->getEdge().getLanes();
2119 const std::vector<MSVehicle::LaneQ>& preb = myVehicle.getBestLanes();
2120 const MSLane* lane = isOpposite() ? myVehicle.getLane()->getParallelOpposite() : lanes[laneIndex];
2121 const MSLane* next = myVehicle.getBestLanesContinuation().size() > 1 ? myVehicle.getBestLanesContinuation()[1] : nullptr;
2122 const MSLink* link = next != nullptr ? lane->getLinkTo(next) : nullptr;
2123 const double shift = link != nullptr ? link->getLateralShift() + 0.5 * (lane->getWidth() - next->getWidth()) : 0;
2124 const MSLane* bidi = myVehicle.getLane()->getBidiLane();
2125 const double vMax = lane->getVehicleMaxSpeed(&myVehicle);
2126 assert(preb.size() == lanes.size() || isOpposite());
2127#ifdef DEBUG_EXPECTED_SLSPEED
2128 if (DEBUG_COND) {
2129 std::cout << SIMTIME << " veh=" << myVehicle.getID() << " updateExpectedSublaneSpeeds opposite=" << isOpposite()
2130 << " sublaneOffset=" << sublaneOffset << " laneIndex=" << laneIndex << " lane=" << lane->getID() << " ahead=" << ahead.toString() << "\n";
2131 }
2132#endif
2133
2134 for (int sublane = 0; sublane < (int)ahead.numSublanes(); ++sublane) {
2135 const int edgeSublane = sublane + sublaneOffset;
2136 if (edgeSublane >= (int)myExpectedSublaneSpeeds.size()) {
2137 // this may happen if a sibling lane is wider than the changer lane
2138 continue;
2139 }
2140 if (link != nullptr && lane->getWidth() > next->getWidth() + NUMERICAL_EPS && MSGlobals::gLateralResolution > 0 && sublaneEnds(sublane, next, shift)) {
2141 // sublane does not continue, discourage from use
2142 myExpectedSublaneSpeeds[edgeSublane] = 0;
2143#ifdef DEBUG_EXPECTED_SLSPEED
2144 if (DEBUG_COND) {
2145 std::cout << " updateExpectedSublaneSpeeds sublane=" << sublane << " doesNotContinue\n";
2146 }
2147#endif
2148 continue;
2150 // lane allowed, find potential leaders and compute safe speeds
2151 // XXX anticipate future braking if leader has a lower speed than myVehicle
2152 const MSVehicle* leader = ahead[sublane].first;
2153 const double gap = ahead[sublane].second;
2154 double vSafe;
2155 if (leader == nullptr) {
2156 if (hasBlueLight()) {
2157 // can continue from any lane if necessary
2158 vSafe = vMax;
2159 } else {
2160 const int prebIndex = isOpposite() ? (int)preb.size() - 1 : laneIndex;
2161 const double dist = preb[prebIndex].length - myVehicle.getPositionOnLane();
2162 vSafe = getCarFollowModel().followSpeed(&myVehicle, vMax, dist, 0, 0);
2163 }
2164 } else if (bidi != nullptr && leader->getLane()->getBidiLane() != nullptr && isBidi(leader->getLane())) {
2165 // oncoming
2166 if (gap < (1 + mySpeedGainLookahead * 2) * (vMax + leader->getSpeed())) {
2167 vSafe = 0;
2168 } else {
2169 vSafe = vMax;
2170 }
2171#ifdef DEBUG_EXPECTED_SLSPEED
2172 if (DEBUG_COND) {
2173 std::cout << SIMTIME << " updateExpectedSublaneSpeeds sublane=" << sublane << " leader=" << leader->getID() << " bidi=" << bidi->getID() << " gap=" << gap << " vSafe=" << vSafe << "\n";
2174 }
2175#endif
2176 } else {
2177 if (leader->getAcceleration() > 0.5 * leader->getCarFollowModel().getMaxAccel()) {
2178 // assume that the leader will continue accelerating to its maximum speed
2179 vSafe = leader->getLane()->getVehicleMaxSpeed(leader);
2180 } else {
2182 &myVehicle, vMax, gap, leader->getSpeed(), leader->getCarFollowModel().getMaxDecel());
2183#ifdef DEBUG_EXPECTED_SLSPEED
2184 if (DEBUG_COND) {
2185 std::cout << " updateExpectedSublaneSpeeds edgeSublane=" << edgeSublane << " leader=" << leader->getID() << " gap=" << gap << " vSafe=" << vSafe << "\n";
2186 }
2187#endif
2188 vSafe = forecastAverageSpeed(vSafe, vMax, gap, leader->getSpeed());
2189 }
2190 }
2191 // take pedestrians into account
2192 if (lane->getEdge().getPersons().size() > 0 && lane->hasPedestrians()) {
2194 double foeRight, foeLeft;
2195 ahead.getSublaneBorders(sublane, 0, foeRight, foeLeft);
2196 // get all leaders ahead or overlapping
2197 const PersonDist pedLeader = lane->nextBlocking(myVehicle.getPositionOnLane() - myVehicle.getVehicleType().getLength(), foeRight, foeLeft);
2198 if (pedLeader.first != 0) {
2199 const double pedGap = pedLeader.second - myVehicle.getVehicleType().getMinGap() - myVehicle.getVehicleType().getLength();
2200 // we do not know the walking direction here so we take the pedestrian speed as 0
2201 vSafe = MIN2(getCarFollowModel().stopSpeed(&myVehicle, vMax, pedGap),
2202 forecastAverageSpeed(vSafe, vMax, pedGap, 0));
2203#ifdef DEBUG_EXPECTED_SLSPEED
2204 if (DEBUG_COND) {
2205 std::cout << " updateExpectedSublaneSpeeds edgeSublane=" << edgeSublane << " pedLeader=" << pedLeader.first->getID() << " gap=" << pedGap << " vSafe=" << vSafe << "\n";
2206 }
2207#endif
2208 }
2209 }
2210 // take bidi pedestrians into account
2211 if (bidi != nullptr && bidi->getEdge().getPersons().size() > 0 && bidi->hasPedestrians()) {
2213 double foeRight, foeLeft;
2214 ahead.getSublaneBorders(sublane, 0, foeRight, foeLeft);
2215 const double foeRightBidi = bidi->getWidth() - foeLeft;
2216 const double foeLeftBidi = bidi->getWidth() - foeRight;
2217 // get all leaders ahead or overlapping
2218 const double relativeBackPos = myVehicle.getLane()->getLength() - myVehicle.getPositionOnLane() + myVehicle.getLength();
2219 const double stopTime = ceil(myVehicle.getSpeed() / myVehicle.getCarFollowModel().getMaxDecel());
2220 PersonDist pedLeader = bidi->nextBlocking(relativeBackPos, foeRightBidi, foeLeftBidi, stopTime, true);
2221 if (pedLeader.first != 0) {
2222 const double pedGap = pedLeader.second - myVehicle.getVehicleType().getMinGap() - myVehicle.getVehicleType().getLength();
2223 // we do not know the walking direction here so we take the pedestrian speed as 0
2224 vSafe = MIN2(getCarFollowModel().stopSpeed(&myVehicle, vMax, pedGap),
2225 forecastAverageSpeed(vSafe, vMax, pedGap, 0));
2226#ifdef DEBUG_EXPECTED_SLSPEED
2227 if (DEBUG_COND) {
2228 std::cout << " updateExpectedSublaneSpeeds edgeSublane=" << edgeSublane << " pedLeader=" << pedLeader.first->getID() << " (bidi) gap=" << pedGap << " vSafe=" << vSafe << "\n";
2229 }
2230#endif
2231 }
2232 }
2233 vSafe = MIN2(vMax, vSafe);
2234 // forget old data when on the opposite side
2235 const double memoryFactor = isOpposite() ? 0 : pow(SPEEDGAIN_MEMORY_FACTOR, myVehicle.getActionStepLengthSecs());
2236 myExpectedSublaneSpeeds[edgeSublane] = memoryFactor * myExpectedSublaneSpeeds[edgeSublane] + (1 - memoryFactor) * vSafe;
2237 } else {
2238 // lane forbidden
2239 myExpectedSublaneSpeeds[edgeSublane] = -1;
2240#ifdef DEBUG_EXPECTED_SLSPEED
2241 if (DEBUG_COND) {
2242 std::cout << " updateExpectedSublaneSpeeds edgeSublane=" << edgeSublane << " lane " << lane->getID() << " forbidden\n";
2243 }
2244#endif
2245 }
2246 }
2247 // XXX deal with leaders on subsequent lanes based on preb
2248}
2249
2250
2251bool
2252MSLCM_SL2015::sublaneEnds(int i, const MSLane* next, double shift) {
2253 const double side = i * MSGlobals::gLateralResolution + shift;
2254 return ((side < -NUMERICAL_EPS
2255 && (next->getParallelLane(-1) == nullptr || !next->getParallelLane(-1)->allowsVehicleClass(myVehicle.getVClass())))
2256 || (side + MSGlobals::gLateralResolution > next->getWidth()
2257 && (next->getParallelLane(1) == nullptr || !next->getParallelLane(1)->allowsVehicleClass(myVehicle.getVClass()))));
2258}
2259
2260
2261double
2262MSLCM_SL2015::forecastAverageSpeed(double vSafe, double vMax, double gap, double vLeader) const {
2263 const double deltaV = vMax - vLeader;
2264 if (deltaV > 0 && gap / deltaV < mySpeedGainLookahead && mySpeedGainLookahead > 0) {
2265 // anticipate future braking by computing the average
2266 // speed over the next few seconds
2267 const double foreCastTime = mySpeedGainLookahead * 2;
2268 const double gapClosingTime = MAX2(0.0, gap / deltaV);
2269 const double vSafe2 = (gapClosingTime * vSafe + (foreCastTime - gapClosingTime) * vLeader) / foreCastTime;
2270#ifdef DEBUG_EXPECTED_SLSPEED
2271 if (DEBUG_COND && vSafe2 != vSafe) {
2272 std::cout << " foreCastTime=" << foreCastTime << " gapClosingTime=" << gapClosingTime << " extrapolated vSafe=" << vSafe2 << "\n";
2273 }
2274#endif
2275 vSafe = vSafe2;
2276 }
2277 return vSafe;
2278}
2279
2280
2281double
2282MSLCM_SL2015::computeSpeedGain(double latDistSublane, double defaultNextSpeed) const {
2283 double result = std::numeric_limits<double>::max();
2284 const std::vector<double>& sublaneSides = myVehicle.getLane()->getEdge().getSubLaneSides();
2285 const double vehWidth = getWidth();
2286 const double rightVehSide = myVehicle.getCenterOnEdge() - vehWidth * 0.5 + latDistSublane;
2287 const double leftVehSide = rightVehSide + vehWidth;
2288 for (int i = 0; i < (int)sublaneSides.size(); ++i) {
2289 const double leftSide = i + 1 < (int)sublaneSides.size() ? sublaneSides[i + 1] : MAX2(myVehicle.getLane()->getEdge().getWidth(), sublaneSides[i] + POSITION_EPS);
2290 if (overlap(rightVehSide, leftVehSide, sublaneSides[i], leftSide)) {
2291 result = MIN2(result, myExpectedSublaneSpeeds[i]);
2292 }
2293 //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";
2294 }
2295 return result - defaultNextSpeed;
2296}
2297
2298
2301 int iMax = -1;
2302 double maxLength = -1;
2303 for (int i = 0; i < ldi.numSublanes(); ++i) {
2304 const MSVehicle* veh = ldi[i].first;
2305 if (veh) {
2306 const double length = veh->getVehicleType().getLength();
2307 if (length > maxLength && tieBrakeLeader(veh)) {
2308 maxLength = length;
2309 iMax = i;
2310 }
2311 }
2312 }
2313 return iMax >= 0 ? ldi[iMax] : std::make_pair(nullptr, -1);
2314}
2315
2316
2317bool
2319 // tie braker if the leader is at the same lane position
2320 return veh != nullptr && (veh->getPositionOnLane() != myVehicle.getPositionOnLane()
2321 || veh->getSpeed() < myVehicle.getSpeed()
2322 || &veh->getLane()->getEdge() != &myVehicle.getLane()->getEdge()
2323 || veh->getLane()->getIndex() > myVehicle.getLane()->getIndex());
2324}
2325
2326
2329 int iMax = 0;
2330 double minSpeed = std::numeric_limits<double>::max();
2331 for (int i = 0; i < ldi.numSublanes(); ++i) {
2332 if (ldi[i].first != 0) {
2333 const double speed = ldi[i].first->getSpeed();
2334 if (speed < minSpeed) {
2335 minSpeed = speed;
2336 iMax = i;
2337 }
2338 }
2339 }
2340 return ldi[iMax];
2341}
2342
2343
2344int
2345MSLCM_SL2015::checkBlocking(const MSLane& neighLane, double& latDist, double maneuverDist, int laneOffset,
2346 const MSLeaderDistanceInfo& leaders,
2347 const MSLeaderDistanceInfo& followers,
2348 const MSLeaderDistanceInfo& /*blockers */,
2349 const MSLeaderDistanceInfo& neighLeaders,
2350 const MSLeaderDistanceInfo& neighFollowers,
2351 const MSLeaderDistanceInfo& /* neighBlockers */,
2352 std::vector<CLeaderDist>* collectLeadBlockers,
2353 std::vector<CLeaderDist>* collectFollowBlockers,
2354 bool keepLatGapManeuver,
2355 double gapFactor,
2356 int* retBlockedFully) {
2357 // truncate latDist according to maxSpeedLat
2358 const double maxDist = SPEED2DIST(getMaxSpeedLat2());
2359 latDist = MAX2(MIN2(latDist, maxDist), -maxDist);
2361 return 0;
2362 }
2363
2364 const double neighRight = getNeighRight(neighLane);
2365 if (!myCFRelatedReady) {
2366 updateCFRelated(followers, myVehicle.getLane()->getRightSideOnEdge(), false);
2368 if (laneOffset != 0) {
2369 updateCFRelated(neighFollowers, neighRight, false);
2370 updateCFRelated(neighLeaders, neighRight, true);
2371 }
2372 myCFRelatedReady = true;
2373 }
2374
2375 // reduce latDist to avoid blockage with overlapping vehicles (no minGapLat constraints)
2376 const double center = myVehicle.getCenterOnEdge();
2377 updateGaps(leaders, myVehicle.getLane()->getRightSideOnEdge(), center, gapFactor, mySafeLatDistRight, mySafeLatDistLeft, false, 0, latDist, collectLeadBlockers);
2378 updateGaps(followers, myVehicle.getLane()->getRightSideOnEdge(), center, gapFactor, mySafeLatDistRight, mySafeLatDistLeft, false, 0, latDist, collectFollowBlockers);
2379 if (laneOffset != 0) {
2380 updateGaps(neighLeaders, neighRight, center, gapFactor, mySafeLatDistRight, mySafeLatDistLeft, false, 0, latDist, collectLeadBlockers);
2381 updateGaps(neighFollowers, neighRight, center, gapFactor, mySafeLatDistRight, mySafeLatDistLeft, false, 0, latDist, collectFollowBlockers);
2382 }
2383#ifdef DEBUG_BLOCKING
2384 if (gDebugFlag2) {
2385 std::cout << " checkBlocking latDist=" << latDist << " mySafeLatDistRight=" << mySafeLatDistRight << " mySafeLatDistLeft=" << mySafeLatDistLeft << "\n";
2386 }
2387#endif
2388 // if we can move at least a little bit in the desired direction, do so (rather than block)
2389 const bool forcedTraCIChange = (myVehicle.hasInfluencer()
2392 if (latDist < 0) {
2393 if (mySafeLatDistRight <= NUMERICAL_EPS) {
2395 } else if (!forcedTraCIChange) {
2396 latDist = MAX2(latDist, -mySafeLatDistRight);
2397 }
2398 } else {
2399 if (mySafeLatDistLeft <= NUMERICAL_EPS) {
2401 } else if (!forcedTraCIChange) {
2402 latDist = MIN2(latDist, mySafeLatDistLeft);
2403 }
2404 }
2405
2406 myCanChangeFully = (maneuverDist == 0 || latDist == maneuverDist);
2407#ifdef DEBUG_BLOCKING
2408 if (gDebugFlag2) {
2409 std::cout << " checkBlocking latDist=" << latDist << " maneuverDist=" << maneuverDist << "\n";
2410 }
2411#endif
2412 // destination sublanes must be safe
2413 // intermediate sublanes must not be blocked by overlapping vehicles
2414
2415 // XXX avoid checking the same leader multiple times
2416 // XXX ensure that only changes within the same lane are undertaken if laneOffset = 0
2417
2418 int blocked = 0;
2419 blocked |= checkBlockingVehicles(&myVehicle, leaders, laneOffset, latDist, myVehicle.getLane()->getRightSideOnEdge(), true,
2420 mySafeLatDistRight, mySafeLatDistLeft, collectLeadBlockers);
2421 blocked |= checkBlockingVehicles(&myVehicle, followers, laneOffset, latDist, myVehicle.getLane()->getRightSideOnEdge(), false,
2422 mySafeLatDistRight, mySafeLatDistLeft, collectFollowBlockers);
2423 if (laneOffset != 0) {
2424 blocked |= checkBlockingVehicles(&myVehicle, neighLeaders, laneOffset, latDist, neighRight, true,
2425 mySafeLatDistRight, mySafeLatDistLeft, collectLeadBlockers);
2426 blocked |= checkBlockingVehicles(&myVehicle, neighFollowers, laneOffset, latDist, neighRight, false,
2427 mySafeLatDistRight, mySafeLatDistLeft, collectFollowBlockers);
2428 }
2429
2430 int blockedFully = 0;
2431 blockedFully |= checkBlockingVehicles(&myVehicle, leaders, laneOffset, maneuverDist, myVehicle.getLane()->getRightSideOnEdge(), true,
2432 mySafeLatDistRight, mySafeLatDistLeft, collectLeadBlockers);
2433 blockedFully |= checkBlockingVehicles(&myVehicle, followers, laneOffset, maneuverDist, myVehicle.getLane()->getRightSideOnEdge(), false,
2434 mySafeLatDistRight, mySafeLatDistLeft, collectFollowBlockers);
2435 if (laneOffset != 0) {
2436 blockedFully |= checkBlockingVehicles(&myVehicle, neighLeaders, laneOffset, maneuverDist, neighRight, true,
2437 mySafeLatDistRight, mySafeLatDistLeft, collectLeadBlockers);
2438 blockedFully |= checkBlockingVehicles(&myVehicle, neighFollowers, laneOffset, maneuverDist, neighRight, false,
2439 mySafeLatDistRight, mySafeLatDistLeft, collectFollowBlockers);
2440 }
2441 if (retBlockedFully != nullptr) {
2442 *retBlockedFully = blockedFully;
2443 }
2444#ifdef DEBUG_BLOCKING
2445 if (gDebugFlag2) {
2446 std::cout << " blocked=" << blocked << " (" << toString((LaneChangeAction)blocked) << ") blockedFully=" << toString((LaneChangeAction)blockedFully)
2447 << " canChangeFully=" << myCanChangeFully << " keepLatGapManeuver=" << keepLatGapManeuver << "\n";
2448 }
2449#endif
2450 if (blocked == 0 && !myCanChangeFully && myPushy == 0 && !keepLatGapManeuver) {
2451 // aggressive drivers immediately start moving towards potential
2452 // blockers and only check that the start of their maneuver (latDist) is safe. In
2453 // contrast, cautious drivers need to check latDist and origLatDist to
2454 // ensure that the maneuver can be finished without encroaching on other vehicles.
2455 blocked |= blockedFully;
2456 } else {
2457 // XXX: in case of action step length > simulation step length, pushing may lead to collisions,
2458 // because maneuver is continued until maneuverDist is reached (perhaps set maneuverDist=latDist)
2459 }
2460#ifdef DEBUG_BLOCKING
2461 if (gDebugFlag2) {
2462 std::cout << " blocked2=" << blocked << " (" << toString((LaneChangeAction)blocked) << ")\n";
2463 }
2464#endif
2465 if (collectFollowBlockers != nullptr && collectLeadBlockers != nullptr) {
2466 // prevent vehicles from being classified as leader and follower simultaneously
2467 for (std::vector<CLeaderDist>::const_iterator it2 = collectLeadBlockers->begin(); it2 != collectLeadBlockers->end(); ++it2) {
2468 for (std::vector<CLeaderDist>::iterator it = collectFollowBlockers->begin(); it != collectFollowBlockers->end();) {
2469 if ((*it2).first == (*it).first) {
2470#ifdef DEBUG_BLOCKING
2471 if (gDebugFlag2) {
2472 std::cout << " removed follower " << (*it).first->getID() << " because it is already a leader\n";
2473 }
2474#endif
2475 it = collectFollowBlockers->erase(it);
2476 } else {
2477 ++it;
2478 }
2479 }
2480 }
2481 }
2482 return blocked;
2483}
2484
2485
2486int
2488 const MSVehicle* ego, const MSLeaderDistanceInfo& vehicles,
2489 int laneOffset, double latDist, double foeOffset, bool leaders,
2490 double& safeLatGapRight, double& safeLatGapLeft,
2491 std::vector<CLeaderDist>* collectBlockers) const {
2492 // determine borders where safety/no-overlap conditions must hold
2493 const LaneChangeAction blockType = (laneOffset == 0
2495 : (laneOffset > 0
2498 const double vehWidth = getWidth();
2499 const double rightVehSide = ego->getRightSideOnEdge();
2500 const double leftVehSide = rightVehSide + vehWidth;
2501 const double rightVehSideDest = rightVehSide + latDist;
2502 const double leftVehSideDest = leftVehSide + latDist;
2503 const double rightNoOverlap = MIN2(rightVehSideDest, rightVehSide);
2504 const double leftNoOverlap = MAX2(leftVehSideDest, leftVehSide);
2505#ifdef DEBUG_BLOCKING
2506 if (gDebugFlag2) {
2507 std::cout << " checkBlockingVehicles"
2508 << " laneOffset=" << laneOffset
2509 << " latDist=" << latDist
2510 << " foeOffset=" << foeOffset
2511 << " vehRight=" << rightVehSide
2512 << " vehLeft=" << leftVehSide
2513 << " rightNoOverlap=" << rightNoOverlap
2514 << " leftNoOverlap=" << leftNoOverlap
2515 << " destRight=" << rightVehSideDest
2516 << " destLeft=" << leftVehSideDest
2517 << " leaders=" << leaders
2518 << " blockType=" << toString((LaneChangeAction) blockType)
2519 << "\n";
2520 }
2521#endif
2522 int result = 0;
2523 for (int i = 0; i < vehicles.numSublanes(); ++i) {
2524 CLeaderDist vehDist = vehicles[i];
2525 if (vehDist.first != 0 && myCFRelated.count(vehDist.first) == 0) {
2526 const MSVehicle* leader = vehDist.first;
2527 const MSVehicle* follower = ego;
2528 if (!leaders) {
2529 std::swap(leader, follower);
2530 }
2531 // only check the current stripe occupied by foe (transform into edge-coordinates)
2532 double foeRight, foeLeft;
2533 vehicles.getSublaneBorders(i, foeOffset, foeRight, foeLeft);
2534 const bool overlapBefore = overlap(rightVehSide, leftVehSide, foeRight, foeLeft);
2535 const bool overlapDest = overlap(rightVehSideDest, leftVehSideDest, foeRight, foeLeft);
2536 const bool overlapAny = overlap(rightNoOverlap, leftNoOverlap, foeRight, foeLeft);
2537#ifdef DEBUG_BLOCKING
2538 if (gDebugFlag2) {
2539 std::cout << " foe=" << vehDist.first->getID()
2540 << " gap=" << vehDist.second
2541 << " secGap=" << follower->getCarFollowModel().getSecureGap(follower, leader, follower->getSpeed(), leader->getSpeed(), leader->getCarFollowModel().getMaxDecel())
2542 << " foeRight=" << foeRight
2543 << " foeLeft=" << foeLeft
2544 << " overlapBefore=" << overlapBefore
2545 << " overlap=" << overlapAny
2546 << " overlapDest=" << overlapDest
2547 << "\n";
2548 }
2549#endif
2550 if (overlapAny) {
2551 if (vehDist.second < 0) {
2552 if (overlapBefore && !overlapDest && !outsideEdge()) {
2553#ifdef DEBUG_BLOCKING
2554 if (gDebugFlag2) {
2555 std::cout << " ignoring current overlap to come clear\n";
2556 }
2557#endif
2558 } else {
2559#ifdef DEBUG_BLOCKING
2560 if (gDebugFlag2) {
2561 std::cout << " overlap (" << toString((LaneChangeAction)blockType) << ")\n";
2562 }
2563#endif
2564 result |= (blockType | LCA_OVERLAPPING);
2565 if (collectBlockers == nullptr) {
2566 return result;
2567 } else {
2568 collectBlockers->push_back(vehDist);
2569 }
2570 }
2571 } else if (overlapDest || !myCanChangeFully) {
2572 // Estimate state after actionstep (follower may be accelerating!)
2573 // A comparison between secure gap depending on the expected speeds and the extrapolated gap
2574 // determines whether the s is blocking the lane change.
2575 // (Note that the longitudinal state update has already taken effect before LC dynamics (thus "-TS" below), would be affected by #3665)
2576
2577 // Use conservative estimate for time until next action step
2578 // (XXX: how can the ego know the foe's action step length?)
2579 const double timeTillAction = MAX2(follower->getActionStepLengthSecs(), leader->getActionStepLengthSecs()) - TS;
2580 // Ignore decel for follower
2581 const double followerAccel = MAX2(0., follower->getAcceleration());
2582 const double leaderAccel = leader->getAcceleration();
2583 // Expected gap after next actionsteps
2584 const double expectedGap = MSCFModel::gapExtrapolation(timeTillAction, vehDist.second, leader->getSpeed(), follower->getSpeed(), leaderAccel, followerAccel, std::numeric_limits<double>::max(), std::numeric_limits<double>::max());
2585
2586 // Determine expected speeds and corresponding secure gap at the extrapolated timepoint
2587 const double followerExpectedSpeed = follower->getSpeed() + timeTillAction * followerAccel;
2588 const double leaderExpectedSpeed = MAX2(0., leader->getSpeed() + timeTillAction * leaderAccel);
2589 const double expectedSecureGap = follower->getCarFollowModel().getSecureGap(follower, leader, followerExpectedSpeed, leaderExpectedSpeed, leader->getCarFollowModel().getMaxDecel());
2590
2591#if defined(DEBUG_ACTIONSTEPS) && defined(DEBUG_BLOCKING)
2592 if (gDebugFlag2) {
2593 std::cout << " timeTillAction=" << timeTillAction
2594 << " followerAccel=" << followerAccel
2595 << " followerExpectedSpeed=" << followerExpectedSpeed
2596 << " leaderAccel=" << leaderAccel
2597 << " leaderExpectedSpeed=" << leaderExpectedSpeed
2598 << "\n gap=" << vehDist.second
2599 << " gapChange=" << (expectedGap - vehDist.second)
2600 << " expectedGap=" << expectedGap
2601 << " expectedSecureGap=" << expectedSecureGap
2602 << " safeLatGapLeft=" << safeLatGapLeft
2603 << " safeLatGapRight=" << safeLatGapRight
2604 << std::endl;
2605 }
2606#endif
2607
2608 // @note for euler-update, a different value for secureGap2 may be obtained when applying safetyFactor to followerDecel rather than secureGap
2609 const double secureGap2 = expectedSecureGap * getSafetyFactor();
2610 if (expectedGap < secureGap2) {
2611 // Foe is a blocker. Update lateral safe gaps accordingly.
2612 if (foeRight > leftVehSide) {
2613 safeLatGapLeft = MIN2(safeLatGapLeft, foeRight - leftVehSide);
2614 } else if (foeLeft < rightVehSide) {
2615 safeLatGapRight = MIN2(safeLatGapRight, rightVehSide - foeLeft);
2616 }
2617
2618#ifdef DEBUG_BLOCKING
2619 if (gDebugFlag2) {
2620 std::cout << " blocked by " << vehDist.first->getID() << " gap=" << vehDist.second << " expectedGap=" << expectedGap
2621 << " expectedSecureGap=" << expectedSecureGap << " secGap2=" << secureGap2 << " safetyFactor=" << getSafetyFactor()
2622 << " safeLatGapLeft=" << safeLatGapLeft << " safeLatGapRight=" << safeLatGapRight
2623 << "\n";
2624 }
2625#endif
2626 result |= blockType;
2627 if (collectBlockers == nullptr) {
2628 return result;
2629 }
2630#ifdef DEBUG_BLOCKING
2631 } else if (gDebugFlag2 && expectedGap < expectedSecureGap) {
2632 std::cout << " ignore blocker " << vehDist.first->getID() << " gap=" << vehDist.second << " expectedGap=" << expectedGap
2633 << " expectedSecureGap=" << expectedSecureGap << " secGap2=" << secureGap2 << " safetyFactor=" << getSafetyFactor() << "\n";
2634#endif
2635 }
2636 if (collectBlockers != nullptr) {
2637 // collect non-blocking followers as well to make sure
2638 // they remain non-blocking
2639 collectBlockers->push_back(vehDist);
2640 }
2641 }
2642 }
2643 }
2644 }
2645 return result;
2646
2647}
2648
2649
2650void
2651MSLCM_SL2015::updateCFRelated(const MSLeaderDistanceInfo& vehicles, double foeOffset, bool leaders) {
2652 // to ensure that we do not ignore the wrong vehicles due to numerical
2653 // instability we slightly reduce the width
2654 const double vehWidth = myVehicle.getVehicleType().getWidth() - NUMERICAL_EPS;
2655 const double rightVehSide = myVehicle.getCenterOnEdge() - 0.5 * vehWidth;
2656 const double leftVehSide = rightVehSide + vehWidth;
2657#ifdef DEBUG_BLOCKING
2658 if (gDebugFlag2) {
2659 std::cout << " updateCFRelated foeOffset=" << foeOffset << " vehicles=" << vehicles.toString() << "\n";
2660 }
2661#endif
2662 for (int i = 0; i < vehicles.numSublanes(); ++i) {
2663 CLeaderDist vehDist = vehicles[i];
2664 if (vehDist.first != 0 && (myCFRelated.count(vehDist.first) == 0 || vehDist.second < 0)) {
2665 double foeRight, foeLeft;
2666 vehicles.getSublaneBorders(i, foeOffset, foeRight, foeLeft);
2667#ifdef DEBUG_BLOCKING
2668 if (gDebugFlag2) {
2669 std::cout << " foe=" << vehDist.first->getID() << " gap=" << vehDist.second
2670 << " sublane=" << i
2671 << " foeOffset=" << foeOffset
2672 << " egoR=" << rightVehSide << " egoL=" << leftVehSide
2673 << " iR=" << foeRight << " iL=" << foeLeft
2674 << " egoV=" << myVehicle.getSpeed() << " foeV=" << vehDist.first->getSpeed()
2675 << " egoE=" << myVehicle.getLane()->getEdge().getID() << " foeE=" << vehDist.first->getLane()->getEdge().getID()
2676 << "\n";
2677 }
2678#endif
2679 if (overlap(rightVehSide, leftVehSide, foeRight, foeLeft) && !outsideEdge() && (vehDist.second >= 0
2680 // avoid deadlock due to #3729
2681 || (!leaders
2684 && vehDist.first->getSpeed() < SUMO_const_haltingSpeed
2685 && -vehDist.second < vehDist.first->getVehicleType().getMinGap()
2686 && &(myVehicle.getLane()->getEdge()) != &(vehDist.first->getLane()->getEdge()))
2687 )) {
2688#ifdef DEBUG_BLOCKING
2689 if (gDebugFlag2) {
2690 std::cout << " ignoring cfrelated foe=" << vehDist.first->getID() << "\n";
2691 }
2692#endif
2693 myCFRelated.insert(vehDist.first);
2694 } else {
2695 const int erased = (int)myCFRelated.erase(vehDist.first);
2696#ifdef DEBUG_BLOCKING
2697 if (gDebugFlag2 && erased > 0) {
2698 std::cout << " restoring cfrelated foe=" << vehDist.first->getID() << "\n";
2699 }
2700#else
2701 UNUSED_PARAMETER(erased);
2702#endif
2703 }
2704 }
2705 }
2706}
2707
2708
2709bool
2710MSLCM_SL2015::overlap(double right, double left, double right2, double left2) {
2711 assert(right <= left);
2712 assert(right2 <= left2);
2713 return left2 >= right + NUMERICAL_EPS && left >= right2 + NUMERICAL_EPS;
2714}
2715
2716
2717int
2718MSLCM_SL2015::lowest_bit(int changeReason) {
2719 if ((changeReason & LCA_STRATEGIC) != 0) {
2720 return LCA_STRATEGIC;
2721 }
2722 if ((changeReason & LCA_COOPERATIVE) != 0) {
2723 return LCA_COOPERATIVE;
2724 }
2725 if ((changeReason & LCA_SPEEDGAIN) != 0) {
2726 return LCA_SPEEDGAIN;
2727 }
2728 if ((changeReason & LCA_KEEPRIGHT) != 0) {
2729 return LCA_KEEPRIGHT;
2730 }
2731 if ((changeReason & LCA_TRACI) != 0) {
2732 return LCA_TRACI;
2733 }
2734 return changeReason;
2735}
2736
2737
2740 // ignore dummy decisions (returned if mayChange() failes)
2741 if (sd1.state == 0) {
2742 return sd2;
2743 } else if (sd2.state == 0) {
2744 return sd1;
2745 }
2746 // LCA_SUBLANE is special because LCA_STAY|LCA_SUBLANE may override another LCA_SUBLANE command
2747 const bool want1 = ((sd1.state & LCA_WANTS_LANECHANGE) != 0) || ((sd1.state & LCA_SUBLANE) != 0 && (sd1.state & LCA_STAY) != 0);
2748 const bool want2 = ((sd2.state & LCA_WANTS_LANECHANGE) != 0) || ((sd2.state & LCA_SUBLANE) != 0 && (sd2.state & LCA_STAY) != 0);
2749 const bool can1 = ((sd1.state & LCA_BLOCKED) == 0);
2750 const bool can2 = ((sd2.state & LCA_BLOCKED) == 0);
2751 int reason1 = lowest_bit(sd1.state & LCA_CHANGE_REASONS);
2752 int reason2 = lowest_bit(sd2.state & LCA_CHANGE_REASONS);
2753#ifdef DEBUG_DECISION
2754 if (DEBUG_COND) std::cout << SIMTIME
2755 << " veh=" << myVehicle.getID()
2756 << " state1=" << toString((LaneChangeAction)sd1.state)
2757 << " want1=" << (sd1.state & LCA_WANTS_LANECHANGE)
2758 << " dist1=" << sd1.latDist
2759 << " dir1=" << sd1.dir
2760 << " state2=" << toString((LaneChangeAction)sd2.state)
2761 << " want2=" << (sd2.state & LCA_WANTS_LANECHANGE)
2762 << " dist2=" << sd2.latDist
2763 << " dir2=" << sd2.dir
2764 << " reason1=" << toString((LaneChangeAction)reason1)
2765 << " reason2=" << toString((LaneChangeAction)reason2)
2766 << "\n";
2767#endif
2768 if (want1) {
2769 if (want2) {
2770 if ((sd1.state & LCA_TRACI) != 0 && (sd2.state & LCA_TRACI) != 0) {
2771 // influencer may assign LCA_WANTS_LANECHANGE despite latDist = 0
2772 if (sd1.latDist == 0 && sd2.latDist != 0) {
2773 return sd2;
2774 } else if (sd2.latDist == 0 && sd1.latDist != 0) {
2775 return sd1;
2776 }
2777 }
2778 // decide whether right or left has higher priority (lower value in enum LaneChangeAction)
2779 if (reason1 < reason2) {
2780 //if (DEBUG_COND) std::cout << " " << (sd1.state & LCA_CHANGE_REASONS) << " < " << (sd2.state & LCA_CHANGE_REASONS) << "\n";
2781 return (!can1 && can2 && sd1.sameDirection(sd2)) ? sd2 : sd1;
2782 //return sd1;
2783 } else if (reason1 > reason2) {
2784 //if (DEBUG_COND) std::cout << " " << (sd1.state & LCA_CHANGE_REASONS) << " > " << (sd2.state & LCA_CHANGE_REASONS) << "\n";
2785 return (!can2 && can1 && sd1.sameDirection(sd2)) ? sd1 : sd2;
2786 //return sd2;
2787 } else {
2788 // same priority.
2789 if ((sd1.state & LCA_SUBLANE) != 0) {
2790 // special treatment: prefer action with dir != 0
2791 if (sd1.dir == 0) {
2792 return sd2;
2793 } else if (sd2.dir == 0) {
2794 return sd1;
2795 } else {
2796 // prefer action that knows more about the desired direction
2797 // @note when deciding between right and left, right is always given as sd1
2798 assert(sd1.dir == -1);
2799 assert(sd2.dir == 1);
2800 if (sd1.latDist <= 0) {
2801 return sd1;
2802 } else if (sd2.latDist >= 0) {
2803 return sd2;
2804 }
2805 // when in doubt, prefer moving to the right
2806 return sd1.latDist <= sd2.latDist ? sd1 : sd2;
2807 }
2808 } else {
2809 if (can1) {
2810 if (can2) {
2811 // break strategic ties with tactial concerns
2812 if (reason1 == LCA_STRATEGIC) {
2813 if (sd1.latDist <= sd2.latDist) {
2815 } else {
2817 }
2818 } else {
2819 // finish the shorter maneuver (i.e. continue the current maneuver)
2820 return fabs(sd1.maneuverDist) < fabs(sd2.maneuverDist) ? sd1 : sd2;
2821 }
2822 } else {
2823 return sd1;
2824 }
2825 } else {
2826 return sd2;
2827 }
2828 }
2829 }
2830 } else {
2831 return sd1;
2832 }
2833 } else {
2834 return sd2;
2835 }
2836
2837}
2838
2839
2841MSLCM_SL2015::getLCA(int state, double latDist) {
2842 return ((latDist == 0 || (state & LCA_CHANGE_REASONS) == 0)
2843 ? LCA_NONE : (latDist < 0 ? LCA_RIGHT : LCA_LEFT));
2844}
2845
2846
2847int
2849 const MSLane& neighLane,
2850 int laneOffset,
2851 const MSLeaderDistanceInfo& leaders,
2852 const MSLeaderDistanceInfo& neighLeaders,
2853 const MSVehicle::LaneQ& curr,
2854 const MSVehicle::LaneQ& neigh,
2855 const MSVehicle::LaneQ& best,
2856 int bestLaneOffset,
2857 bool changeToBest,
2858 double& currentDist,
2859 double neighDist,
2860 double laDist,
2861 double roundaboutBonus,
2862 double latLaneDist,
2863 bool checkOpposite,
2864 double& latDist
2865 ) {
2866 const bool right = (laneOffset == -1);
2867 const bool left = (laneOffset == 1);
2868
2869 const double forwardPos = getForwardPos();
2870 if (laneOffset != 0) {
2871 myLeftSpace = currentDist - forwardPos;
2872 }
2873 const double usableDist = (currentDist - forwardPos - best.occupation * JAM_FACTOR);
2874 //- (best.lane->getVehicleNumber() * neighSpeed)); // VARIANT 9 jfSpeed
2875 const double maxJam = MAX2(neigh.occupation, curr.occupation);
2876 const double neighLeftPlace = MAX2(0., neighDist - forwardPos - maxJam);
2877 const double overlap = myVehicle.getLateralOverlap();
2878 // save the left space
2879
2880#ifdef DEBUG_STRATEGIC_CHANGE
2881 if (gDebugFlag2) {
2882 std::cout << SIMTIME
2883 << " veh=" << myVehicle.getID()
2884 << " forwardPos=" << forwardPos
2885 << " laSpeed=" << myLookAheadSpeed
2886 << " laDist=" << laDist
2887 << " currentDist=" << currentDist
2888 << " usableDist=" << usableDist
2889 << " bestLaneOffset=" << bestLaneOffset
2890 << " best.length=" << best.length
2891 << " maxJam=" << maxJam
2892 << " neighLeftPlace=" << neighLeftPlace
2893 << " myLeftSpace=" << myLeftSpace
2894 << " overlap=" << overlap
2895 << "\n";
2896 }
2897#endif
2898
2899 if (laneOffset == 0) {
2900 if (overlap > MAX2(POSITION_EPS, MSGlobals::gLateralResolution)
2901 && (getShadowLane() == nullptr || !getShadowLane()->allowsVehicleClass(myVehicle.getVClass()))
2902 && getWidth() < myVehicle.getLane()->getWidth()) {
2903 // @brief we urgently need to return to within lane bounds
2905 ret |= LCA_STRATEGIC | LCA_URGENT;
2906#ifdef DEBUG_STRATEGIC_CHANGE
2907 if (gDebugFlag2) {
2908 std::cout << SIMTIME << " returnToLaneBounds\n";
2909 }
2910#endif
2911 //std::cout << SIMTIME << " veh=" << myVehicle.getID() << " overlap=" << overlap << " returnToLaneBounds\n";
2912 } else if (myVehicle.getBestLanesContinuation().size() > 1 && myVehicle.getLane()->getWidth() > myVehicle.getBestLanesContinuation()[1]->getWidth()) {
2913 const MSLane* cur = myVehicle.getLane();
2914 const MSLane* next = myVehicle.getBestLanesContinuation()[1];
2915 const MSLink* link = cur->getLinkTo(next);
2916 const double distOnLane = cur->getLength() - myVehicle.getPositionOnLane();
2917 if (link != nullptr && getWidth() < next->getWidth() && distOnLane < 100) {
2918 double hwDiff = 0.5 * (cur->getWidth() - next->getWidth());
2919 double rightVehSide = myVehicle.getRightSideOnLane() + link->getLateralShift() - hwDiff;
2920 double leftVehSide = myVehicle.getLeftSideOnLane() + link->getLateralShift() - hwDiff;
2921 const double res = MSGlobals::gLateralResolution > 0 ? MSGlobals::gLateralResolution : next->getWidth();
2922 if (rightVehSide < -res && (next->getParallelLane(-1) == nullptr || !next->getParallelLane(-1)->allowsVehicleClass(myVehicle.getVClass()))) {
2923 latDist = -rightVehSide;
2924 myLeftSpace = distOnLane;
2925 ret |= LCA_STRATEGIC | LCA_URGENT;
2926#ifdef DEBUG_STRATEGIC_CHANGE
2927 if (gDebugFlag2) {
2928 std::cout << SIMTIME << " rightSublaneEnds rVSide=" << myVehicle.getRightSideOnLane()
2929 << " shift=" << link->getLateralShift() << " rVSide2=" << rightVehSide << " myLeftSpace=" << myLeftSpace << " \n";
2930 }
2931#endif
2932 } else if (leftVehSide > next->getWidth() + res && (next->getParallelLane(1) == nullptr || !next->getParallelLane(1)->allowsVehicleClass(myVehicle.getVClass()))) {
2933 latDist = -(leftVehSide - next->getWidth());
2934 myLeftSpace = distOnLane;
2935 ret |= LCA_STRATEGIC | LCA_URGENT;
2936#ifdef DEBUG_STRATEGIC_CHANGE
2937 if (gDebugFlag2) {
2938 std::cout << SIMTIME << " leftSublaneEnds lVSide=" << myVehicle.getLeftSideOnLane()
2939 << " shift=" << link->getLateralShift() << " lVSide2=" << leftVehSide << " myLeftSpace=" << myLeftSpace << "\n";
2940 }
2941#endif
2942 }
2943 }
2944 }
2945 } else if (laneOffset != 0 && changeToBest && bestLaneOffset == curr.bestLaneOffset
2946 && currentDistDisallows(usableDist, bestLaneOffset, laDist)) {
2948 if (!mustOvertakeStopped(false, neighLane, neighLeaders, leaders, forwardPos, neighDist, right, latLaneDist, currentDist, latDist)) {
2949 latDist = latLaneDist;
2950 ret |= LCA_STRATEGIC | LCA_URGENT;
2951#ifdef DEBUG_STRATEGIC_CHANGE
2952 if (gDebugFlag2) {
2953 std::cout << SIMTIME << " mustChangeToBest\n";
2954 }
2955#endif
2956 } else {
2957#ifdef DEBUG_STRATEGIC_CHANGE
2958 if (gDebugFlag2) {
2959 std::cout << " veh=" << myVehicle.getID() << " avoidStoppedNeigh\n";
2960 }
2961#endif
2962 }
2963 } else {
2964 // VARIANT_20 (noOvertakeRight)
2965 if (left && avoidOvertakeRight() && neighLeaders.hasVehicles()) {
2966 // check for slower leader on the left. we should not overtake but
2967 // rather move left ourselves (unless congested)
2968 // XXX only adapt as much as possible to get a lateral gap
2969 CLeaderDist cld = getSlowest(neighLeaders);
2970 const MSVehicle* nv = cld.first;
2971 if (nv->getSpeed() < myVehicle.getSpeed()) {
2972 const double vSafe = getCarFollowModel().followSpeed(
2973 &myVehicle, myVehicle.getSpeed(), cld.second, nv->getSpeed(), nv->getCarFollowModel().getMaxDecel());
2974 addLCSpeedAdvice(vSafe);
2975 if (vSafe < myVehicle.getSpeed()) {
2977 }
2978#ifdef DEBUG_STRATEGIC_CHANGE
2979 if (gDebugFlag2) {
2980 std::cout << SIMTIME
2981 << " avoid overtaking on the right nv=" << nv->getID()
2982 << " nvSpeed=" << nv->getSpeed()
2983 << " mySpeedGainProbabilityR=" << mySpeedGainProbabilityRight
2984 << " plannedSpeed=" << myVehicle.getSpeed() + ACCEL2SPEED(myLCAccelerationAdvices.back().first)
2985 << "\n";
2986 }
2987#endif
2988 }
2989 }
2990
2991 // handling reaction to stopped for opposite direction driving NYI
2992 const bool noOpposites = &myVehicle.getLane()->getEdge() == &neighLane.getEdge();
2993 if (laneOffset != 0 && myStrategicParam >= 0 && noOpposites && mustOvertakeStopped(true, neighLane, leaders, neighLeaders, forwardPos, neighDist, right, latLaneDist, currentDist, latDist)) {
2994#ifdef DEBUG_STRATEGIC_CHANGE
2995 if (gDebugFlag2) {
2996 std::cout << " veh=" << myVehicle.getID() << " mustOvertakeStopped\n";
2997 }
2998#endif
2999 if (latDist == 0) {
3000 ret |= LCA_STAY | LCA_STRATEGIC;
3001 } else {
3002 ret |= LCA_STRATEGIC | LCA_URGENT;
3003 }
3004
3005 } else if (!changeToBest && (currentDistDisallows(neighLeftPlace, abs(bestLaneOffset) + 2, laDist))) {
3006 // the opposite lane-changing direction should be done than the one examined herein
3007 // we'll check whether we assume we could change anyhow and get back in time...
3008 //
3009 // this rule prevents the vehicle from moving in opposite direction of the best lane
3010 // unless the way till the end where the vehicle has to be on the best lane
3011 // is long enough
3012#ifdef DEBUG_STRATEGIC_CHANGE
3013 if (gDebugFlag2) {
3014 std::cout << " veh=" << myVehicle.getID() << " could not change back and forth in time (1) neighLeftPlace=" << neighLeftPlace << "\n";
3015 }
3016#endif
3017 ret |= LCA_STAY | LCA_STRATEGIC;
3018 } else if (
3019 laneOffset != 0
3020 && bestLaneOffset == 0
3021 && !leaders.hasStoppedVehicle()
3022 && neigh.bestContinuations.back()->getLinkCont().size() != 0
3023 && roundaboutBonus == 0
3024 && !checkOpposite
3025 && neighDist < TURN_LANE_DIST
3026 && myStrategicParam >= 0) {
3027 // VARIANT_21 (stayOnBest)
3028 // we do not want to leave the best lane for a lane which leads elsewhere
3029 // unless our leader is stopped or we are approaching a roundabout
3030#ifdef DEBUG_STRATEGIC_CHANGE
3031 if (gDebugFlag2) {
3032 std::cout << " veh=" << myVehicle.getID() << " does not want to leave the bestLane (neighDist=" << neighDist << ")\n";
3033 }
3034#endif
3035 ret |= LCA_STAY | LCA_STRATEGIC;
3036 } else if (right
3037 && bestLaneOffset == 0
3038 && myVehicle.getLane()->getSpeedLimit() > 80. / 3.6
3040 ) {
3041 // let's also regard the case where the vehicle is driving on a highway...
3042 // in this case, we do not want to get to the dead-end of an on-ramp
3043#ifdef DEBUG_STRATEGIC_CHANGE
3044 if (gDebugFlag2) {
3045 std::cout << " veh=" << myVehicle.getID() << " does not want to get stranded on the on-ramp of a highway\n";
3046 }
3047#endif
3048 ret |= LCA_STAY | LCA_STRATEGIC;
3049 }
3050 }
3051 if (laneOffset != 0 && (ret & LCA_URGENT) == 0 && getShadowLane() != nullptr &&
3052 // ignore overlap if it goes in the correct direction
3053 bestLaneOffset * myVehicle.getLateralPositionOnLane() <= 0) {
3054 // no decision or decision to stay
3055 // make sure to stay within lane bounds in case the shadow lane ends
3056 //const double requiredDist = MAX2(2 * myVehicle.getLateralOverlap(), getSublaneWidth()) / SUMO_const_laneWidth * laDist;
3057 const double requiredDist = 2 * overlap / SUMO_const_laneWidth * laDist;
3058 double currentShadowDist = -myVehicle.getPositionOnLane();
3059 MSLane* shadowPrev = nullptr;
3060 for (std::vector<MSLane*>::const_iterator it = curr.bestContinuations.begin(); it != curr.bestContinuations.end(); ++it) {
3061 if (*it == nullptr) {
3062 continue;
3063 }
3064 MSLane* shadow = getShadowLane(*it);
3065 if (shadow == nullptr || currentShadowDist >= requiredDist) {
3066 break;
3067 }
3068 if (shadowPrev != nullptr) {
3069 currentShadowDist += shadowPrev->getEdge().getInternalFollowingLengthTo(&shadow->getEdge(), myVehicle.getVClass());
3070 }
3071 currentShadowDist += shadow->getLength();
3072 shadowPrev = shadow;
3073#ifdef DEBUG_STRATEGIC_CHANGE
3074 if (gDebugFlag2) {
3075 std::cout << " shadow=" << shadow->getID() << " currentShadowDist=" << currentShadowDist << "\n";
3076 }
3077#endif
3078 }
3079#ifdef DEBUG_STRATEGIC_CHANGE
3080 if (gDebugFlag2) {
3081 std::cout << " veh=" << myVehicle.getID() << " currentShadowDist=" << currentShadowDist << " requiredDist=" << requiredDist << " overlap=" << overlap << "\n";
3082 }
3083#endif
3084 if (currentShadowDist < requiredDist && currentShadowDist < usableDist) {
3085 myLeftSpace = currentShadowDist;
3087#ifdef DEBUG_STRATEGIC_CHANGE
3088 if (gDebugFlag2) {
3089 std::cout << " must change for shadowLane end latDist=" << latDist << " myLeftSpace=" << myLeftSpace << "\n";
3090 }
3091#endif
3092 ret |= LCA_STRATEGIC | LCA_URGENT | LCA_STAY ;
3093 }
3094 }
3095
3096 // check for overriding TraCI requests
3097#if defined(DEBUG_STRATEGIC_CHANGE) || defined(DEBUG_TRACI)
3098 if (gDebugFlag2) {
3099 std::cout << SIMTIME << " veh=" << myVehicle.getID() << " ret=" << ret;
3100 }
3101#endif
3102 // store state before canceling
3103 getCanceledState(laneOffset) |= ret;
3104 int retTraCI = myVehicle.influenceChangeDecision(ret);
3105 if ((retTraCI & LCA_TRACI) != 0) {
3106 if ((retTraCI & LCA_STAY) != 0) {
3107 ret = retTraCI;
3108 latDist = 0;
3109 } else if (((retTraCI & LCA_RIGHT) != 0 && laneOffset < 0)
3110 || ((retTraCI & LCA_LEFT) != 0 && laneOffset > 0)) {
3111 ret = retTraCI;
3112 latDist = latLaneDist;
3113 }
3114 }
3115#if defined(DEBUG_STRATEGIC_CHANGE) || defined(DEBUG_TRACI)
3116 if (gDebugFlag2) {
3117 std::cout << " reqAfterInfluence=" << toString((LaneChangeAction)retTraCI) << " ret=" << toString((LaneChangeAction)ret) << "\n";
3118 }
3119#endif
3120 return ret;
3121}
3122
3123
3124bool
3125MSLCM_SL2015::mustOvertakeStopped(bool checkCurrent, const MSLane& neighLane, const MSLeaderDistanceInfo& leaders, const MSLeaderDistanceInfo& neighLead,
3126 double posOnLane, double neighDist, bool right, double latLaneDist, double& currentDist, double& latDist) {
3127 bool mustOvertake = false;
3128 const bool checkOverTakeRight = avoidOvertakeRight();
3129 int rightmost;
3130 int leftmost;
3131 const bool curHasStopped = leaders.hasStoppedVehicle();
3132 const int dir = latLaneDist < 0 ? -1 : 1;
3133 const MSLane* neighBeyond = neighLane.getParallelLane(dir);
3134 const bool hasLaneBeyond = checkCurrent && neighBeyond != nullptr && neighBeyond->allowsVehicleClass(myVehicle.getVClass());
3135 UNUSED_PARAMETER(hasLaneBeyond);
3136 if (curHasStopped) {
3137 leaders.getSubLanes(&myVehicle, 0, rightmost, leftmost);
3138 for (int i = rightmost; i <= leftmost; i++) {
3139 const CLeaderDist& leader = leaders[i];
3140 if (leader.first != 0 && leader.first->isStopped() && leader.second < REACT_TO_STOPPED_DISTANCE) {
3141 const double overtakeDist = leader.second + myVehicle.getVehicleType().getLength() + leader.first->getVehicleType().getLengthWithGap();
3142 const double remaining = MIN2(neighDist, currentDist) - posOnLane;
3143#ifdef DEBUG_STRATEGIC_CHANGE
3144 if (DEBUG_COND) {
3145 std::cout << " overtakeDist=" << overtakeDist << " remaining=" << remaining
3146 << " minDistToStopped=" << neighLead.getMinDistToStopped()
3147 << " hasLaneBeyond=" << hasLaneBeyond
3148 << "\n";
3149 }
3150#endif
3151 if (// current destination leaves enough space to overtake the leader
3152 remaining > overtakeDist
3153 // maybe do not overtake on the right at high speed
3154 && (!checkCurrent || !checkOverTakeRight || !right)
3155 && (!neighLead.hasStoppedVehicle() || neighLead.getMinDistToStopped() > overtakeDist /*|| (hasLaneBeyond && hasFreeLaneBeyond(neighBeyond, dir))*/)
3156 //&& (neighLead.first == 0 || !neighLead.first->isStopped()
3157 // // neighboring stopped vehicle leaves enough space to overtake leader
3158 // || neighLead.second > overtakeDist))
3159 ) {
3160 // avoid becoming stuck behind a stopped leader
3161 currentDist = myVehicle.getPositionOnLane() + leader.second;
3162 myLeftSpace = currentDist - posOnLane;
3163 latDist = latLaneDist;
3164 mustOvertake = true;
3165#ifdef DEBUG_STRATEGIC_CHANGE
3166 if (DEBUG_COND) {
3167 std::cout << " veh=" << myVehicle.getID() << " overtake stopped leader=" << leader.first->getID()
3168 << " newCurrentDist=" << currentDist
3169 << " overtakeDist=" << overtakeDist
3170 << " remaining=" << remaining
3171 << "\n";
3172 }
3173#endif
3174 }
3175 }
3176
3177 }
3178 }
3179 if (!mustOvertake && !curHasStopped && neighLead.hasStoppedVehicle()) {
3180 // #todo fix this if the neigh lane has a different width
3181 const double offset = (latLaneDist < 0 ? -1 : 1) * myVehicle.getLane()->getWidth();
3182 neighLead.getSubLanes(&myVehicle, offset, rightmost, leftmost);
3183 for (int i = 0; i < leaders.numSublanes(); i++) {
3184 const CLeaderDist& leader = leaders[i];
3185 if (leader.first != 0 && leader.first->isStopped() && leader.second < REACT_TO_STOPPED_DISTANCE) {
3186 mustOvertake = true;
3187 if (i >= rightmost && i <= leftmost) {
3188 latDist = myVehicle.getLateralOverlap() * (latLaneDist > 0 ? -1 : 1);
3189 break;
3190 }
3191 }
3192 }
3193 }
3194 return mustOvertake;
3195}
3196
3197
3198double
3200 return (state & LCA_STRATEGIC) != 0 ? MAX2(0.0, (1.0 - myPushy * (1 + 0.5 * myImpatience))) : 1.0;
3201}
3202
3203
3204int
3206 const MSLeaderDistanceInfo& leaders,
3207 const MSLeaderDistanceInfo& followers,
3208 const MSLeaderDistanceInfo& blockers,
3209 const MSLeaderDistanceInfo& neighLeaders,
3210 const MSLeaderDistanceInfo& neighFollowers,
3211 const MSLeaderDistanceInfo& neighBlockers,
3212 const MSLane& neighLane,
3213 int laneOffset,
3214 double& latDist,
3215 double& maneuverDist,
3216 int& blocked) {
3217
3218 /* @notes
3219 * vehicles may need to compromise between fulfilling lane change objectives
3220 * (LCA_STRATEGIC, LCA_SPEED etc) and maintaining lateral gap. The minimum
3221 * acceptable lateral gap depends on
3222 * - the cultural context (China vs Europe)
3223 * - the driver agressiveness (willingness to encroach on other vehicles to force them to move laterally as well)
3224 * - see @note in checkBlocking
3225 * - the vehicle type (car vs motorcycle)
3226 * - the current speed
3227 * - the speed difference
3228 * - the importance / urgency of the desired maneuver
3229 *
3230 * the object of this method is to evaluate the above circumstances and
3231 * either:
3232 * - allow the current maneuver (state, latDist)
3233 * - to override the current maneuver with a distance-keeping maneuver
3234 *
3235 *
3236 * laneChangeModel/driver parameters
3237 * - bool pushy (willingness to encroach)
3238 * - float minGap at 100km/h (to be interpolated for lower speeds (assume 0 at speed 0)
3239 * - gapFactors (a factor for each of the change reasons
3240 *
3241 * further assumptions
3242 * - the maximum of egoSpeed and deltaSpeed can be used when interpolating minGap
3243 * - distance keeping to the edges of the road can be ignored (for now)
3244 *
3245 * currentMinGap = minGap * min(1.0, max(v, abs(v - vOther)) / 100) * gapFactor[lc_reason]
3246 *
3247 * */
3248
3250 double gapFactor = computeGapFactor(state);
3251 const double oldLatDist = latDist;
3252 const double oldManeuverDist = maneuverDist;
3254 const int traciState = myVehicle.influenceChangeDecision(state);
3255
3256 // compute gaps after maneuver
3257 const double halfWidth = getWidth() * 0.5;
3258 // if the current maneuver is blocked we will stay where we are
3259 const double oldCenter = myVehicle.getCenterOnEdge();
3260 // surplus gaps. these are used to collect various constraints
3261 // if they do not permit the desired maneuvre, should override it to better maintain distance
3262 // stay within the current edge
3263 double surplusGapRight = oldCenter - halfWidth;
3264 double surplusGapLeft = getLeftBorder(laneOffset != 0) - oldCenter - halfWidth;
3265 const bool stayInLane = (laneOffset == 0
3266 || ((traciState & LCA_STRATEGIC) != 0
3267 && (traciState & LCA_STAY) != 0
3268 // permit wide vehicles to stay on the road
3269 && (surplusGapLeft >= 0 && surplusGapRight >= 0)));
3270
3271 if (isOpposite()) {
3272 std::swap(surplusGapLeft, surplusGapRight);
3273 }
3274#ifdef DEBUG_KEEP_LATGAP
3275 if (gDebugFlag2) {
3276 std::cout << "\n " << SIMTIME << " keepLatGap() laneOffset=" << laneOffset
3277 << " latDist=" << latDist
3278 << " maneuverDist=" << maneuverDist
3279 << " state=" << toString((LaneChangeAction)state)
3280 << " traciState=" << toString((LaneChangeAction)traciState)
3281 << " blocked=" << toString((LaneChangeAction)blocked)
3282 << " gapFactor=" << gapFactor
3283 << " stayInLane=" << stayInLane << "\n"
3284 << " stayInEdge: surplusGapRight=" << surplusGapRight << " surplusGapLeft=" << surplusGapLeft << "\n";
3285 }
3286#endif
3287 // staying within the edge overrides all minGap considerations
3288 if (surplusGapLeft < 0 || surplusGapRight < 0) {
3289 gapFactor = 0;
3290 }
3291
3292 // maintain gaps to vehicles on the current lane
3293 // ignore vehicles that are too far behind
3294 const double netOverlap = -myVehicle.getVehicleType().getLength() * 0.5;
3295 updateGaps(leaders, myVehicle.getLane()->getRightSideOnEdge(), oldCenter, gapFactor, surplusGapRight, surplusGapLeft, true);
3296 updateGaps(followers, myVehicle.getLane()->getRightSideOnEdge(), oldCenter, gapFactor, surplusGapRight, surplusGapLeft, true, netOverlap);
3297
3298 if (laneOffset != 0) {
3299 // maintain gaps to vehicles on the target lane
3300 const double neighRight = getNeighRight(neighLane);
3301 updateGaps(neighLeaders, neighRight, oldCenter, gapFactor, surplusGapRight, surplusGapLeft, true);
3302 updateGaps(neighFollowers, neighRight, oldCenter, gapFactor, surplusGapRight, surplusGapLeft, true, netOverlap);
3303 }
3304#ifdef DEBUG_KEEP_LATGAP
3305 if (gDebugFlag2) {
3306 std::cout << " minGapLat: surplusGapRight=" << surplusGapRight << " surplusGapLeft=" << surplusGapLeft << "\n"
3307 << " lastGaps: right=" << myLastLateralGapRight << " left=" << myLastLateralGapLeft << "\n";
3308 }
3309#endif
3310 // we also need to track the physical gap, in addition to the psychological gap
3311 double physicalGapLeft = myLastLateralGapLeft == NO_NEIGHBOR ? surplusGapLeft : myLastLateralGapLeft;
3312 double physicalGapRight = myLastLateralGapRight == NO_NEIGHBOR ? surplusGapRight : myLastLateralGapRight;
3313
3314 const double halfLaneWidth = myVehicle.getLane()->getWidth() * 0.5;
3315 const double posLat = myVehicle.getLateralPositionOnLane() * (isOpposite() ? -1 : 1);
3316 if (stayInLane || laneOffset == 1) {
3317 // do not move past the right boundary of the current lane (traffic wasn't checked there)
3318 // but assume it's ok to be where we are in case we are already beyond
3319 surplusGapRight = MIN2(surplusGapRight, MAX2(0.0, halfLaneWidth + posLat - halfWidth));
3320 physicalGapRight = MIN2(physicalGapRight, MAX2(0.0, halfLaneWidth + posLat - halfWidth));
3321 }
3322 if (stayInLane || laneOffset == -1) {
3323 // do not move past the left boundary of the current lane (traffic wasn't checked there)
3324 // but assume it's ok to be where we are in case we are already beyond
3325 surplusGapLeft = MIN2(surplusGapLeft, MAX2(0.0, halfLaneWidth - posLat - halfWidth));
3326 physicalGapLeft = MIN2(physicalGapLeft, MAX2(0.0, halfLaneWidth - posLat - halfWidth));
3327 }
3328#ifdef DEBUG_KEEP_LATGAP
3329 if (gDebugFlag2) {
3330 std::cout << " stayInLane: surplusGapRight=" << surplusGapRight << " surplusGapLeft=" << surplusGapLeft << "\n";
3331 }
3332#endif
3333
3334 if (surplusGapRight + surplusGapLeft < 0) {
3335 // insufficient lateral space to fulfill all requirements. apportion space proportionally
3336 if ((state & LCA_CHANGE_REASONS) == 0) {
3337 state |= LCA_SUBLANE;
3338 }
3339 const double equalDeficit = 0.5 * (surplusGapLeft + surplusGapRight);
3340 if (surplusGapRight < surplusGapLeft) {
3341 // shift further to the left but no further than there is physical space
3342 const double delta = MIN2(equalDeficit - surplusGapRight, physicalGapLeft);
3343 latDist = delta;
3344 maneuverDist = delta;
3345#ifdef DEBUG_KEEP_LATGAP
3346 if (gDebugFlag2) {
3347 std::cout << " insufficient latSpace, move left: delta=" << delta << "\n";
3348 }
3349#endif
3350 } else {
3351 // shift further to the right but no further than there is physical space
3352 const double delta = MIN2(equalDeficit - surplusGapLeft, physicalGapRight);
3353 latDist = -delta;
3354 maneuverDist = -delta;
3355#ifdef DEBUG_KEEP_LATGAP
3356 if (gDebugFlag2) {
3357 std::cout << " insufficient latSpace, move right: delta=" << delta << "\n";
3358 }
3359#endif
3360 }
3361 } else {
3362 // sufficient space. move as far as the gaps permit
3363 latDist = MAX2(MIN2(latDist, surplusGapLeft), -surplusGapRight);
3364 maneuverDist = MAX2(MIN2(maneuverDist, surplusGapLeft), -surplusGapRight);
3365 if ((state & LCA_KEEPRIGHT) != 0 && maneuverDist != oldManeuverDist) {
3366 // don't start keepRight unless it can be completed
3367 latDist = oldLatDist;
3368 maneuverDist = oldManeuverDist;
3369 }
3370#ifdef DEBUG_KEEP_LATGAP
3371 if (gDebugFlag2) {
3372 std::cout << " adapted latDist=" << latDist << " maneuverDist=" << maneuverDist << " (old=" << oldLatDist << ")\n";
3373 }
3374#endif
3375 }
3376 // take into account overriding traci sublane-request
3378 // @note: the influence is reset in MSAbstractLaneChangeModel::setOwnState at the end of the lane-changing code for this vehicle
3379 latDist = myVehicle.getInfluencer().getLatDist();
3380 maneuverDist = myVehicle.getInfluencer().getLatDist();
3381 if (latDist < 0) {
3383 } else {
3385 }
3386 state |= LCA_TRACI;
3387#ifdef DEBUG_KEEP_LATGAP
3388 if (gDebugFlag2) {
3389 std::cout << " traci influenced latDist=" << latDist << "\n";
3390 }
3391#endif
3392 }
3393 // if we cannot move in the desired direction, consider the maneuver blocked anyway
3394 const bool nonSublaneChange = (state & (LCA_STRATEGIC | LCA_COOPERATIVE | LCA_SPEEDGAIN | LCA_KEEPRIGHT)) != 0;
3395 const bool traciChange = ((state | traciState) & LCA_TRACI) != 0;
3396 if (nonSublaneChange && !traciChange) {
3397 if ((latDist < NUMERICAL_EPS * myVehicle.getActionStepLengthSecs()) && (oldLatDist > 0)) {
3398#ifdef DEBUG_KEEP_LATGAP
3399 if (gDebugFlag2) {
3400 std::cout << " wanted changeToLeft oldLatDist=" << oldLatDist << ", blocked latGap changeToRight\n";
3401 }
3402#endif
3403 latDist = oldLatDist; // restore old request for usage in decideDirection()
3405 } else if ((latDist > -NUMERICAL_EPS * myVehicle.getActionStepLengthSecs()) && (oldLatDist < 0)) {
3406#ifdef DEBUG_KEEP_LATGAP
3407 if (gDebugFlag2) {
3408 std::cout << " wanted changeToRight oldLatDist=" << oldLatDist << ", blocked latGap changeToLeft\n";
3409 }
3410#endif
3411 latDist = oldLatDist; // restore old request for usage in decideDirection()
3413 }
3414 }
3415 // if we move, even though we wish to stay, update the change reason (except for TraCI)
3416 if (fabs(latDist) > NUMERICAL_EPS * myVehicle.getActionStepLengthSecs() && oldLatDist == 0) {
3417 state &= (~(LCA_CHANGE_REASONS | LCA_STAY) | LCA_TRACI);
3418 }
3419 // update blocked status
3420 if (fabs(latDist - oldLatDist) > NUMERICAL_EPS * myVehicle.getActionStepLengthSecs()) {
3421#ifdef DEBUG_KEEP_LATGAP
3422 if (gDebugFlag2) {
3423 std::cout << " latDistUpdated=" << latDist << " oldLatDist=" << oldLatDist << "\n";
3424 }
3425#endif
3426 blocked = checkBlocking(neighLane, latDist, maneuverDist, laneOffset, leaders, followers, blockers, neighLeaders, neighFollowers, neighBlockers, nullptr, nullptr, nonSublaneChange);
3427 }
3428 if (fabs(latDist) > NUMERICAL_EPS * myVehicle.getActionStepLengthSecs()) {
3429 state = (state & ~LCA_STAY);
3430 if ((state & LCA_CHANGE_REASONS) == 0) {
3431 state |= LCA_SUBLANE;
3432 }
3433 } else {
3434 if ((state & LCA_SUBLANE) != 0) {
3435 state |= LCA_STAY;
3436 }
3437 // avoid setting blinker due to numerical issues
3438 latDist = 0;
3439 }
3440#if defined(DEBUG_KEEP_LATGAP) || defined(DEBUG_STATE)
3441 if (gDebugFlag2) {
3442 std::cout << " latDist2=" << latDist
3443 << " state2=" << toString((LaneChangeAction)state)
3444 << " lastGapLeft=" << myLastLateralGapLeft
3445 << " lastGapRight=" << myLastLateralGapRight
3446 << " blockedAfter=" << toString((LaneChangeAction)blocked)
3447 << "\n";
3448 }
3449#endif
3450 return state;
3451}
3452
3453
3454void
3455MSLCM_SL2015::updateGaps(const MSLeaderDistanceInfo& others, double foeOffset, double oldCenter, double gapFactor,
3456 double& surplusGapRight, double& surplusGapLeft,
3457 bool saveMinGap, double netOverlap,
3458 double latDist,
3459 std::vector<CLeaderDist>* collectBlockers) {
3460 if (others.hasVehicles()) {
3461 const double halfWidth = getWidth() * 0.5 + NUMERICAL_EPS;
3462 const double baseMinGap = myMinGapLat;
3463 for (int i = 0; i < others.numSublanes(); ++i) {
3464 if (others[i].first != 0 && others[i].second <= 0
3465 && myCFRelated.count(others[i].first) == 0
3466 && (netOverlap == 0 || others[i].second + others[i].first->getVehicleType().getMinGap() < netOverlap)) {
3468 const MSVehicle* foe = others[i].first;
3469 const double res = MSGlobals::gLateralResolution > 0 ? MSGlobals::gLateralResolution : others[i].first->getLane()->getWidth();
3470 double foeRight, foeLeft;
3471 others.getSublaneBorders(i, foeOffset, foeRight, foeLeft);
3472 const double foeCenter = foeRight + 0.5 * res;
3473 const double gap = MIN2(fabs(foeRight - oldCenter), fabs(foeLeft - oldCenter)) - halfWidth;
3475 const double desiredMinGap = baseMinGap * deltaV / LATGAP_SPEED_THRESHOLD;
3476 const double currentMinGap = desiredMinGap * gapFactor; // pushy vehicles may accept a lower lateral gap temporarily
3477 /*
3478 if (netOverlap != 0) {
3479 // foe vehicle is follower with its front ahead of the ego midpoint
3480 // scale gap requirements so it gets lower for foe which are further behind ego
3481 //
3482 // relOverlap approaches 0 as the foe gets closer to the midpoint and it equals 1 if the foe is driving head-to-head
3483 const double relOverlap = 1 - (others[i].second + others[i].first->getVehicleType().getMinGap()) / netOverlap;
3484 currentMinGap *= currOverlap * relOverlap;
3485 }
3486 */
3487#if defined(DEBUG_BLOCKING) || defined(DEBUG_KEEP_LATGAP)
3488 if (debugVehicle()) {
3489 std::cout << " updateGaps"
3490 << " i=" << i
3491 << " foe=" << foe->getID()
3492 << " foeRight=" << foeRight
3493 << " foeLeft=" << foeLeft
3494 << " oldCenter=" << oldCenter
3495 << " gap=" << others[i].second
3496 << " latgap=" << gap
3497 << " currentMinGap=" << currentMinGap
3498 << " surplusGapRight=" << surplusGapRight
3499 << " surplusGapLeft=" << surplusGapLeft
3500 << "\n";
3501 }
3502#endif
3503
3504 // If foe is maneuvering towards ego, reserve some additional distance.
3505 // But don't expect the foe to come closer than currentMinGap if it isn't already there.
3506 // (XXX: How can the ego know the foe's maneuver dist?)
3507 if (foeCenter < oldCenter) { // && foe->getLaneChangeModel().getSpeedLat() > 0) {
3508 const double foeManeuverDist = MAX2(0., foe->getLaneChangeModel().getManeuverDist());
3509 surplusGapRight = MIN3(surplusGapRight, gap - currentMinGap, MAX2(currentMinGap, gap - foeManeuverDist));
3510 } else { //if (foeCenter > oldCenter && foe->getLaneChangeModel().getSpeedLat() < 0) {
3511 const double foeManeuverDist = -MIN2(0., foe->getLaneChangeModel().getManeuverDist());
3512 surplusGapLeft = MIN3(surplusGapLeft, gap - currentMinGap, MAX2(currentMinGap, gap - foeManeuverDist));
3513 }
3514 if (saveMinGap) {
3515 if (foeCenter < oldCenter) {
3516#if defined(DEBUG_BLOCKING) || defined(DEBUG_KEEP_LATGAP)
3517 if (gDebugFlag2 && gap < myLastLateralGapRight) {
3518 std::cout << " new minimum rightGap=" << gap << "\n";
3519 }
3520#endif
3522 } else {
3523#if defined(DEBUG_BLOCKING) || defined(DEBUG_KEEP_LATGAP)
3524 if (gDebugFlag2 && gap < myLastLateralGapLeft) {
3525 std::cout << " new minimum leftGap=" << gap << "\n";
3526 }
3527#endif
3529 }
3530 }
3531 if (collectBlockers != nullptr) {
3532 // check if the vehicle is blocking a desire lane change
3533 if ((foeCenter < oldCenter && latDist < 0 && gap < (desiredMinGap - latDist))
3534 || (foeCenter > oldCenter && latDist > 0 && gap < (desiredMinGap + latDist))) {
3535 collectBlockers->push_back(others[i]);
3536 }
3537 }
3538 }
3539 }
3540 }
3541}
3542
3543
3544double
3546 return myVehicle.getVehicleType().getWidth() + NUMERICAL_EPS;
3547}
3548
3549
3550double
3551MSLCM_SL2015::computeSpeedLat(double latDist, double& maneuverDist, bool urgent) const {
3552 int currentDirection = mySpeedLat >= 0 ? 1 : -1;
3553 int directionWish = latDist >= 0 ? 1 : -1;
3554 double maxSpeedLat = myVehicle.getVehicleType().getMaxSpeedLat();
3555 double accelLat = myAccelLat;
3556 if (!urgent && (myLeftSpace > POSITION_EPS || myMaxSpeedLatFactor < 0)) {
3557 const double speedBound = myMaxSpeedLatStanding + myMaxSpeedLatFactor * myVehicle.getSpeed();
3558 if (myMaxSpeedLatFactor >= 0) {
3559 // speedbound increases with speed and needs an upper bound
3560 maxSpeedLat = MIN2(maxSpeedLat, speedBound);
3561 } else {
3562 // speedbound decreases with speed and needs a lower bound
3563 // (only useful if myMaxSpeedLatStanding > maxSpeedLat)
3564 maxSpeedLat = MAX2(maxSpeedLat, speedBound);
3565 // increase (never decrease) lateral acceleration in proportion
3566 accelLat *= MAX2(1.0, speedBound / myVehicle.getVehicleType().getMaxSpeedLat());
3567 }
3568 }
3570 const double rightVehSide = myVehicle.getRightSideOnEdge();
3571 const double edgeOverlap = MAX2(-rightVehSide, rightVehSide + myVehicle.getVehicleType().getWidth() - myVehicle.getCurrentEdge()->getWidth());
3572 // if vehicle is outside edge bounds. Permit stronger lateral maneuvering
3573 accelLat = MAX2(accelLat, 2 * edgeOverlap);
3574 maxSpeedLat = MAX2(maxSpeedLat, edgeOverlap);
3575 }
3576
3577#ifdef DEBUG_MANEUVER
3578 if (debugVehicle()) {
3579 std::cout << SIMTIME
3580 << " veh=" << myVehicle.getID()
3581 << " computeSpeedLat()"
3582 << " latDist=" << latDist
3583 << " maneuverDist=" << maneuverDist
3584 << " urgent=" << urgent
3585 << " speedLat=" << mySpeedLat
3586 << " currentDirection=" << currentDirection
3587 << " directionWish=" << directionWish
3588 << " myLeftSpace=" << myLeftSpace
3589 << " maxSpeedLat=" << maxSpeedLat
3590 << std::endl;
3591 }
3592#endif
3593 // reduced lateral speed (in the desired direction). Don't change direction against desired.
3594 double speedDecel;
3595 if (directionWish == 1) {
3596 speedDecel = MAX2(mySpeedLat - ACCEL2SPEED(accelLat), 0.);
3597 } else {
3598 speedDecel = MIN2(mySpeedLat + ACCEL2SPEED(accelLat), 0.);
3599 }
3600 // increased lateral speed (in the desired direction)
3601 double speedAccel = MAX2(MIN2(mySpeedLat + directionWish * ACCEL2SPEED(accelLat), maxSpeedLat), -maxSpeedLat);
3602
3603 // can we reach the target distance in a single step? (XXX: assumes "Euler" update)
3604 double speedBound = DIST2SPEED(latDist);
3605 // for lat-gap keeping maneuvres myOrigLatDist may be 0
3606 const double fullLatDist = latDist > 0 ? MIN2(mySafeLatDistLeft, MAX2(maneuverDist, latDist)) : MAX2(-mySafeLatDistRight, MIN2(maneuverDist, latDist));
3607
3608 // update maneuverDist, if safety constraints apply in its direction
3609 if (maneuverDist * latDist > 0) {
3610 maneuverDist = fullLatDist;
3611 }
3612
3613#ifdef DEBUG_MANEUVER
3614 if (debugVehicle()) {
3615 std::cout << " mySafeLatDistRight=" << mySafeLatDistRight
3616 << " mySafeLatDistLeft=" << mySafeLatDistLeft
3617 << " fullLatDist=" << fullLatDist
3618 << " speedAccel=" << speedAccel
3619 << " speedDecel=" << speedDecel
3620 << " speedBound=" << speedBound
3621 << std::endl;
3622 }
3623#endif
3624 if (speedDecel * speedAccel <= 0 && (
3625 // speedAccel and speedDecel bracket speed 0. This means we can end the maneuver
3626 (latDist >= 0 && speedAccel >= speedBound && speedBound >= speedDecel)
3627 || (latDist <= 0 && speedAccel <= speedBound && speedBound <= speedDecel))) {
3628 // we can reach the desired value in this step
3629#ifdef DEBUG_MANEUVER
3630 if (debugVehicle()) {
3631 std::cout << " computeSpeedLat a)\n";
3632 }
3633#endif
3634 return speedBound;
3635 }
3636 // are we currently moving in the wrong direction?
3637 if (latDist * mySpeedLat < 0) {
3638#ifdef DEBUG_MANEUVER
3639 if (debugVehicle()) {
3640 std::cout << " computeSpeedLat b)\n";
3641 }
3642#endif
3643 return emergencySpeedLat(speedAccel);
3644 }
3645 // check if the remaining distance allows to accelerate laterally
3646 double minDistAccel = SPEED2DIST(speedAccel) + currentDirection * MSCFModel::brakeGapEuler(fabs(speedAccel), accelLat, 0); // most we can move in the target direction
3647 if ((fabs(minDistAccel) < fabs(fullLatDist)) || (fabs(minDistAccel - fullLatDist) < NUMERICAL_EPS)) {
3648#ifdef DEBUG_MANEUVER
3649 if (debugVehicle()) {
3650 std::cout << " computeSpeedLat c)\n";
3651 }
3652#endif
3653 return speedAccel;
3654 } else {
3655#ifdef DEBUG_MANEUVER
3656 if (debugVehicle()) {
3657 std::cout << " minDistAccel=" << minDistAccel << "\n";
3658 }
3659#endif
3660 // check if the remaining distance allows to maintain current lateral speed
3661 double minDistCurrent = SPEED2DIST(mySpeedLat) + currentDirection * MSCFModel::brakeGapEuler(fabs(mySpeedLat), accelLat, 0);
3662 if ((fabs(minDistCurrent) < fabs(fullLatDist)) || (fabs(minDistCurrent - fullLatDist) < NUMERICAL_EPS)) {
3663#ifdef DEBUG_MANEUVER
3664 if (debugVehicle()) {
3665 std::cout << " computeSpeedLat d)\n";
3666 }
3667#endif
3668 return mySpeedLat;
3669 }
3670 }
3671 // reduce lateral speed
3672#ifdef DEBUG_MANEUVER
3673 if (debugVehicle()) {
3674 std::cout << " computeSpeedLat e)\n";
3675 }
3676#endif
3677 return emergencySpeedLat(speedDecel);
3678}
3679
3680
3681double
3682MSLCM_SL2015::emergencySpeedLat(double speedLat) const {
3683 // reduce lateral speed for safety purposes
3684 if (speedLat < 0 && SPEED2DIST(-speedLat) > mySafeLatDistRight) {
3685 speedLat = -DIST2SPEED(mySafeLatDistRight);
3686#ifdef DEBUG_MANEUVER
3687 if (debugVehicle()) {
3688 std::cout << " rightDanger speedLat=" << speedLat << "\n";
3689 }
3690#endif
3691 } else if (speedLat > 0 && SPEED2DIST(speedLat) > mySafeLatDistLeft) {
3692 speedLat = DIST2SPEED(mySafeLatDistLeft);
3693#ifdef DEBUG_MANEUVER
3694 if (debugVehicle()) {
3695 std::cout << " leftDanger speedLat=" << speedLat << "\n";
3696 }
3697#endif
3698 }
3699 return speedLat;
3700}
3701
3702
3706 // Check whether the vehicle should adapt its alignment to an upcoming turn
3707 if (myTurnAlignmentDist > 0) {
3708 const std::pair<double, const MSLink*>& turnInfo = myVehicle.getNextTurn();
3709 const LinkDirection turnDir = turnInfo.second == nullptr ? LinkDirection::NODIR : turnInfo.second->getDirection();
3710 const bool indirect = turnInfo.second == nullptr ? false : turnInfo.second->isIndirect();
3711 if (turnInfo.first < myTurnAlignmentDist) {
3712 // Vehicle is close enough to the link to change its default alignment
3713 switch (turnDir) {
3717 if (myVehicle.getLane()->getBidiLane() == nullptr) {
3718 // no left alignment on bidi lane to avoid blocking oncoming traffic
3720 }
3721 break;
3726 break;
3729 default:
3730 break;
3731 }
3732 }
3733 }
3734 return align;
3735}
3736
3737
3738void
3739MSLCM_SL2015::commitManoeuvre(int blocked, int blockedFully,
3740 const MSLeaderDistanceInfo& leaders,
3741 const MSLeaderDistanceInfo& neighLeaders,
3742 const MSLane& neighLane,
3743 double maneuverDist) {
3744 if (!blocked && !blockedFully && !myCanChangeFully) {
3745 // round to full action steps
3746 double secondsToLeaveLane;
3748 secondsToLeaveLane = ceil(fabs(maneuverDist) / myVehicle.getVehicleType().getMaxSpeedLat() / myVehicle.getActionStepLengthSecs()) * myVehicle.getActionStepLengthSecs();
3749 // XXX myAccelLat must be taken into account (refs #3601, see ballistic case for solution)
3750
3751 // XXX This also causes probs: if the difference between the current speed and the committed is higher than the maximal decel,
3752 // the vehicle may pass myLeftSpace before completing the maneuver.
3753 myCommittedSpeed = MIN3(myLeftSpace / secondsToLeaveLane,
3756#if defined(DEBUG_MANEUVER) || defined(DEBUG_COMMITTED_SPEED)
3757 if (debugVehicle()) {
3758 std::cout << SIMTIME << " veh=" << myVehicle.getID() << " myCommittedSpeed=" << myCommittedSpeed << " leftSpace=" << myLeftSpace << " secondsToLeave=" << secondsToLeaveLane << "\n";
3759 }
3760#endif
3761 } else {
3762
3763 // Calculate seconds needed for leaving lane assuming start from lateral speed zero, and lat.accel == -lat.decel
3764 secondsToLeaveLane = MSCFModel::estimateArrivalTime(fabs(maneuverDist), 0., 0., myVehicle.getVehicleType().getMaxSpeedLat(), myAccelLat, myAccelLat);
3765 // round to full action steps
3766 secondsToLeaveLane = ceil(secondsToLeaveLane / myVehicle.getActionStepLengthSecs()) * myVehicle.getActionStepLengthSecs();
3767
3768 // committed speed will eventually be pushed into a drive item during the next planMove() step. This item
3769 // will not be read before the next action step at current time + actionStepLength-TS, so we need to schedule the corresponding speed.
3770 const double timeTillActionStep = myVehicle.getActionStepLengthSecs() - TS;
3771 const double nextActionStepSpeed = MAX2(0., myVehicle.getSpeed() + timeTillActionStep * myVehicle.getAcceleration());
3772 double nextLeftSpace;
3773 if (nextActionStepSpeed > 0.) {
3774 nextLeftSpace = myLeftSpace - timeTillActionStep * (myVehicle.getSpeed() + nextActionStepSpeed) * 0.5;
3775 } else if (myVehicle.getAcceleration() == 0) {
3776 nextLeftSpace = myLeftSpace;
3777 } else {
3778 assert(myVehicle.getAcceleration() < 0.);
3779 nextLeftSpace = myLeftSpace + (myVehicle.getSpeed() * myVehicle.getSpeed() / myVehicle.getAcceleration()) * 0.5;
3780 }
3781 const double avoidArrivalSpeed = nextActionStepSpeed + ACCEL2SPEED(MSCFModel::avoidArrivalAccel(
3782 nextLeftSpace, secondsToLeaveLane - timeTillActionStep, nextActionStepSpeed, myVehicle.getCarFollowModel().getEmergencyDecel()));
3783
3784 myCommittedSpeed = MIN3(avoidArrivalSpeed,
3787
3788#if defined(DEBUG_MANEUVER) || defined(DEBUG_COMMITTED_SPEED)
3789 if (gDebugFlag2) {
3790 std::cout << SIMTIME
3791 << " veh=" << myVehicle.getID()
3792 << " avoidArrivalSpeed=" << avoidArrivalSpeed
3793 << " currentSpeed=" << myVehicle.getSpeed()
3794 << " myLeftSpace=" << myLeftSpace
3795 << "\n nextLeftSpace=" << nextLeftSpace
3796 << " nextActionStepSpeed=" << nextActionStepSpeed
3797 << " nextActionStepRemainingSeconds=" << secondsToLeaveLane - timeTillActionStep
3798 << "\n";
3799 }
3800#endif
3801 }
3802 myCommittedSpeed = commitFollowSpeed(myCommittedSpeed, maneuverDist, secondsToLeaveLane, leaders, myVehicle.getLane()->getRightSideOnEdge());
3803 myCommittedSpeed = commitFollowSpeed(myCommittedSpeed, maneuverDist, secondsToLeaveLane, neighLeaders, neighLane.getRightSideOnEdge());
3805 myCommittedSpeed = 0;
3806 }
3807#if defined(DEBUG_MANEUVER) || defined(DEBUG_COMMITTED_SPEED)
3808 if (gDebugFlag2) {
3809 std::cout << SIMTIME
3810 << " veh=" << myVehicle.getID()
3811 << " secondsToLeave=" << secondsToLeaveLane
3813 << " committed=" << myCommittedSpeed
3814 << "\n";
3815 }
3816#endif
3817 }
3818}
3819
3820double
3821MSLCM_SL2015::commitFollowSpeed(double speed, double latDist, double secondsToLeaveLane, const MSLeaderDistanceInfo& leaders, double foeOffset) const {
3822 if (leaders.hasVehicles()) {
3823 // we distinguish 3 cases
3824 // - vehicles with lateral overlap at the end of the maneuver: try to follow safely
3825 // - vehicles with overlap at the start of the maneuver: avoid collision within secondsToLeaveLane
3826 // - vehicles without overlap: ignore
3827
3828 const double maxDecel = myVehicle.getCarFollowModel().getMaxDecel();
3829 // temporarily use another decel value
3830 MSCFModel& cfmodel = const_cast<MSCFModel&>(myVehicle.getCarFollowModel());
3831 cfmodel.setMaxDecel(maxDecel / getSafetyFactor());
3832
3833 const double vehWidth = getWidth();
3834 const double rightVehSide = myVehicle.getCenterOnEdge() - 0.5 * vehWidth;
3835 const double leftVehSide = rightVehSide + vehWidth;
3836 const double rightVehSideDest = rightVehSide + latDist;
3837 const double leftVehSideDest = leftVehSide + latDist;
3838#if defined(DEBUG_MANEUVER) || defined(DEBUG_COMMITTED_SPEED)
3839 if (gDebugFlag2) {
3840 std::cout << " commitFollowSpeed"
3841 << " latDist=" << latDist
3842 << " foeOffset=" << foeOffset
3843 << " vehRight=" << rightVehSide
3844 << " vehLeft=" << leftVehSide
3845 << " destRight=" << rightVehSideDest
3846 << " destLeft=" << leftVehSideDest
3847 << "\n";
3848 }
3849#endif
3850 for (int i = 0; i < leaders.numSublanes(); ++i) {
3851 CLeaderDist vehDist = leaders[i];
3852 if (vehDist.first != 0) {
3853 const MSVehicle* leader = vehDist.first;
3854 // only check the current stripe occuped by foe (transform into edge-coordinates)
3855 double foeRight, foeLeft;
3856 leaders.getSublaneBorders(i, foeOffset, foeRight, foeLeft);
3857#if defined(DEBUG_MANEUVER) || defined(DEBUG_COMMITTED_SPEED)
3858 if (gDebugFlag2) {
3859 std::cout << " foe=" << vehDist.first->getID()
3860 << " gap=" << vehDist.second
3861 << " secGap=" << myVehicle.getCarFollowModel().getSecureGap(&myVehicle, leader, myVehicle.getSpeed(), leader->getSpeed(), leader->getCarFollowModel().getMaxDecel())
3862 << " foeRight=" << foeRight
3863 << " foeLeft=" << foeLeft
3864 << " overlapBefore=" << overlap(rightVehSide, leftVehSide, foeRight, foeLeft)
3865 << " overlapDest=" << overlap(rightVehSideDest, leftVehSideDest, foeRight, foeLeft)
3866 << "\n";
3867 }
3868#endif
3869 if (overlap(rightVehSideDest, leftVehSideDest, foeRight, foeLeft)) {
3870 // case 1
3871 const double vSafe = myVehicle.getCarFollowModel().followSpeed(
3872 &myVehicle, speed, vehDist.second, leader->getSpeed(), leader->getCarFollowModel().getMaxDecel());
3873 speed = MIN2(speed, vSafe);
3874#if defined(DEBUG_MANEUVER) || defined(DEBUG_COMMITTED_SPEED)
3875 if (gDebugFlag2) {
3876 std::cout << " case1 vsafe=" << vSafe << " speed=" << speed << "\n";
3877 }
3878#endif
3879 } else if (overlap(rightVehSide, leftVehSide, foeRight, foeLeft)) {
3880 // case 2
3881 const double vSafe = myVehicle.getCarFollowModel().followSpeedTransient(
3882 secondsToLeaveLane,
3883 &myVehicle, speed, vehDist.second, leader->getSpeed(), leader->getCarFollowModel().getMaxDecel());
3884 speed = MIN2(speed, vSafe);
3885#if defined(DEBUG_MANEUVER) || defined(DEBUG_COMMITTED_SPEED)
3886 if (gDebugFlag2) {
3887 std::cout << " case2 vsafe=" << vSafe << " speed=" << speed << "\n";
3888 }
3889#endif
3890 }
3891 }
3892 }
3893 // restore original deceleration
3894 cfmodel.setMaxDecel(maxDecel);
3895
3896 }
3897 return speed;
3898}
3899
3900double
3902 return 1 / ((1 + 0.5 * myImpatience) * myAssertive);
3903}
3904
3905double
3907 return myOppositeParam <= 0 ? std::numeric_limits<double>::max() : 1 / myOppositeParam;
3908}
3909
3910
3911std::string
3912MSLCM_SL2015::getParameter(const std::string& key) const {
3914 return toString(myStrategicParam);
3915 } else if (key == toString(SUMO_ATTR_LCA_COOPERATIVE_PARAM)) {
3917 } else if (key == toString(SUMO_ATTR_LCA_SPEEDGAIN_PARAM)) {
3918 return toString(mySpeedGainParam);
3919 } else if (key == toString(SUMO_ATTR_LCA_KEEPRIGHT_PARAM)) {
3920 return toString(myKeepRightParam);
3921 } else if (key == toString(SUMO_ATTR_LCA_OPPOSITE_PARAM)) {
3922 return toString(myOppositeParam);
3923 } else if (key == toString(SUMO_ATTR_LCA_SUBLANE_PARAM)) {
3924 return toString(mySublaneParam);
3925 } else if (key == toString(SUMO_ATTR_MINGAP_LAT)) {
3926 return toString(myMinGapLat);
3927 } else if (key == toString(SUMO_ATTR_LCA_PUSHY)) {
3928 return toString(myPushy);
3929 } else if (key == toString(SUMO_ATTR_LCA_PUSHYGAP)) {
3930 return toString((myPushy - 1) * myMinGapLat);
3931 } else if (key == toString(SUMO_ATTR_LCA_ASSERTIVE)) {
3932 return toString(myAssertive);
3933 } else if (key == toString(SUMO_ATTR_LCA_IMPATIENCE)) {
3934 return toString(myImpatience);
3935 } else if (key == toString(SUMO_ATTR_LCA_TIME_TO_IMPATIENCE)) {
3937 } else if (key == toString(SUMO_ATTR_LCA_ACCEL_LAT)) {
3938 return toString(myAccelLat);
3939 } else if (key == toString(SUMO_ATTR_LCA_LOOKAHEADLEFT)) {
3940 return toString(myLookaheadLeft);
3941 } else if (key == toString(SUMO_ATTR_LCA_SPEEDGAINRIGHT)) {
3942 return toString(mySpeedGainRight);
3943 } else if (key == toString(SUMO_ATTR_LCA_LANE_DISCIPLINE)) {
3944 return toString(myLaneDiscipline);
3945 } else if (key == toString(SUMO_ATTR_LCA_SIGMA)) {
3946 return toString(mySigma);
3951 } else if (key == toString(SUMO_ATTR_LCA_SPEEDGAIN_LOOKAHEAD)) {
3953 } else if (key == toString(SUMO_ATTR_LCA_SPEEDGAIN_REMAIN_TIME)) {
3957 } else if (key == toString(SUMO_ATTR_LCA_COOPERATIVE_SPEED)) {
3959 } else if (key == toString(SUMO_ATTR_LCA_MAXSPEEDLATSTANDING)) {
3961 } else if (key == toString(SUMO_ATTR_LCA_MAXSPEEDLATFACTOR)) {
3963 } else if (key == toString(SUMO_ATTR_LCA_MAXDISTLATSTANDING)) {
3965 // access to internal state for debugging in sumo-gui (not documented since it may change at any time)
3966 } else if (key == "speedGainProbabilityRight") {
3968 } else if (key == "speedGainProbabilityLeft") {
3970 } else if (key == "keepRightProbability") {
3972 } else if (key == "lookAheadSpeed") {
3973 return toString(myLookAheadSpeed);
3974 } else if (key == "sigmaState") {
3975 return toString(mySigmaState);
3976 // motivation relative to threshold
3977 } else if (key == "speedGainRP") {
3979 } else if (key == "speedGainLP") {
3981 } else if (key == "keepRightP") {
3983 }
3984 throw InvalidArgument("Parameter '" + key + "' is not supported for laneChangeModel of type '" + toString(myModel) + "'");
3985}
3986
3987void
3988MSLCM_SL2015::setParameter(const std::string& key, const std::string& value) {
3989 double doubleValue;
3990 try {
3991 doubleValue = StringUtils::toDouble(value);
3992 } catch (NumberFormatException&) {
3993 throw InvalidArgument("Setting parameter '" + key + "' requires a number for laneChangeModel of type '" + toString(myModel) + "'");
3994 }
3996 myStrategicParam = doubleValue;
3997 } else if (key == toString(SUMO_ATTR_LCA_COOPERATIVE_PARAM)) {
3998 myCooperativeParam = doubleValue;
3999 } else if (key == toString(SUMO_ATTR_LCA_SPEEDGAIN_PARAM)) {
4000 mySpeedGainParam = doubleValue;
4001 } else if (key == toString(SUMO_ATTR_LCA_KEEPRIGHT_PARAM)) {
4002 myKeepRightParam = doubleValue;
4003 } else if (key == toString(SUMO_ATTR_LCA_OPPOSITE_PARAM)) {
4004 myOppositeParam = doubleValue;
4005 } else if (key == toString(SUMO_ATTR_LCA_SUBLANE_PARAM)) {
4006 mySublaneParam = doubleValue;
4007 } else if (key == toString(SUMO_ATTR_MINGAP_LAT)) {
4008 myMinGapLat = doubleValue;
4009 } else if (key == toString(SUMO_ATTR_LCA_PUSHY)) {
4010 myPushy = doubleValue;
4011 } else if (key == toString(SUMO_ATTR_LCA_PUSHYGAP)) {
4012 myPushy = 1 - doubleValue / myMinGapLat;
4013 } else if (key == toString(SUMO_ATTR_LCA_ASSERTIVE)) {
4014 myAssertive = doubleValue;
4015 } else if (key == toString(SUMO_ATTR_LCA_IMPATIENCE)) {
4016 myImpatience = doubleValue;
4017 myMinImpatience = doubleValue;
4018 } else if (key == toString(SUMO_ATTR_LCA_TIME_TO_IMPATIENCE)) {
4019 myTimeToImpatience = doubleValue;
4020 } else if (key == toString(SUMO_ATTR_LCA_ACCEL_LAT)) {
4021 myAccelLat = doubleValue;
4023 myTurnAlignmentDist = doubleValue;
4024 } else if (key == toString(SUMO_ATTR_LCA_LOOKAHEADLEFT)) {
4025 myLookaheadLeft = doubleValue;
4026 } else if (key == toString(SUMO_ATTR_LCA_SPEEDGAINRIGHT)) {
4027 mySpeedGainRight = doubleValue;
4028 } else if (key == toString(SUMO_ATTR_LCA_LANE_DISCIPLINE)) {
4029 myLaneDiscipline = doubleValue;
4030 } else if (key == toString(SUMO_ATTR_LCA_SIGMA)) {
4031 mySigma = doubleValue;
4033 myKeepRightAcceptanceTime = doubleValue;
4035 myOvertakeDeltaSpeedFactor = doubleValue;
4036 } else if (key == toString(SUMO_ATTR_LCA_SPEEDGAIN_LOOKAHEAD)) {
4037 mySpeedGainLookahead = doubleValue;
4038 } else if (key == toString(SUMO_ATTR_LCA_SPEEDGAIN_REMAIN_TIME)) {
4039 mySpeedGainRemainTime = doubleValue;
4041 myRoundaboutBonus = doubleValue;
4042 } else if (key == toString(SUMO_ATTR_LCA_COOPERATIVE_SPEED)) {
4043 myCooperativeSpeed = doubleValue;
4044 } else if (key == toString(SUMO_ATTR_LCA_MAXSPEEDLATSTANDING)) {
4045 myMaxSpeedLatStanding = doubleValue;
4046 } else if (key == toString(SUMO_ATTR_LCA_MAXSPEEDLATFACTOR)) {
4047 myMaxSpeedLatFactor = doubleValue;
4048 } else if (key == toString(SUMO_ATTR_LCA_MAXDISTLATSTANDING)) {
4049 myMaxDistLatStanding = doubleValue;
4050 // access to internal state
4051 } else if (key == "speedGainProbabilityRight") {
4052 mySpeedGainProbabilityRight = doubleValue;
4053 } else if (key == "speedGainProbabilityLeft") {
4054 mySpeedGainProbabilityLeft = doubleValue;
4055 } else if (key == "keepRightProbability") {
4056 myKeepRightProbability = doubleValue;
4057 } else if (key == "lookAheadSpeed") {
4058 myLookAheadSpeed = doubleValue;
4059 } else if (key == "sigmaState") {
4060 mySigmaState = doubleValue;
4061 } else {
4062 throw InvalidArgument("Setting parameter '" + key + "' is not supported for laneChangeModel of type '" + toString(myModel) + "'");
4063 }
4065}
4066
4067
4068int
4070 int laneOffset,
4072 int blocked,
4073 const std::pair<MSVehicle*, double>& leader,
4074 const std::pair<MSVehicle*, double>& follower,
4075 const std::pair<MSVehicle*, double>& neighLead,
4076 const std::pair<MSVehicle*, double>& neighFollow,
4077 const MSLane& neighLane,
4078 const std::vector<MSVehicle::LaneQ>& preb,
4079 MSVehicle** lastBlocked,
4080 MSVehicle** firstBlocked) {
4081
4082 const LaneChangeAction alternatives = LCA_NONE; // @todo pas this data
4083
4084#ifdef DEBUG_WANTSCHANGE
4085 if (DEBUG_COND) {
4086 std::cout << "\nWANTS_CHANGE\n" << SIMTIME
4087 //<< std::setprecision(10)
4088 << " veh=" << myVehicle.getID()
4089 << " lane=" << myVehicle.getLane()->getID()
4090 << " neigh=" << neighLane.getID()
4091 << " pos=" << myVehicle.getPositionOnLane()
4092 << " posLat=" << myVehicle.getLateralPositionOnLane()
4093 << " speed=" << myVehicle.getSpeed()
4094 << " considerChangeTo=" << (laneOffset == -1 ? "right" : "left")
4095 << "\n";
4096 }
4097#endif
4098
4099 double latDist = 0;
4100 const double laneWidth = myVehicle.getLane()->getWidth();
4101 MSLeaderDistanceInfo leaders(leader, laneWidth);
4102 MSLeaderDistanceInfo followers(follower, laneWidth);
4103 MSLeaderDistanceInfo blockers(std::make_pair((MSVehicle*)nullptr, -1), laneWidth);
4104 MSLeaderDistanceInfo neighLeaders(neighLead, laneWidth);
4105 MSLeaderDistanceInfo neighFollowers(neighFollow, laneWidth);
4106 MSLeaderDistanceInfo neighBlockers(std::make_pair((MSVehicle*)nullptr, -1), laneWidth);
4107
4108 double maneuverDist;
4109 int result = _wantsChangeSublane(laneOffset,
4110 alternatives,
4111 leaders, followers, blockers,
4112 neighLeaders, neighFollowers, neighBlockers,
4113 neighLane, preb,
4114 lastBlocked, firstBlocked, latDist, maneuverDist, blocked);
4115
4116 myCanChangeFully = true;
4117 // ignore sublane motivation
4118 result &= ~LCA_SUBLANE;
4119 result |= getLCA(result, latDist);
4120
4121#if defined(DEBUG_WANTSCHANGE) || defined(DEBUG_STATE)
4122 if (DEBUG_COND) {
4123 if (result & LCA_WANTS_LANECHANGE) {
4124 std::cout << SIMTIME
4125 << " veh=" << myVehicle.getID()
4126 << " wantsChangeTo=" << (laneOffset == -1 ? "right" : "left")
4127 << ((result & LCA_URGENT) ? " (urgent)" : "")
4128 << ((result & LCA_CHANGE_TO_HELP) ? " (toHelp)" : "")
4129 << ((result & LCA_STRATEGIC) ? " (strat)" : "")
4130 << ((result & LCA_COOPERATIVE) ? " (coop)" : "")
4131 << ((result & LCA_SPEEDGAIN) ? " (speed)" : "")
4132 << ((result & LCA_KEEPRIGHT) ? " (keepright)" : "")
4133 << ((result & LCA_TRACI) ? " (traci)" : "")
4134 << ((blocked & LCA_BLOCKED) ? " (blocked)" : "")
4135 << ((blocked & LCA_OVERLAPPING) ? " (overlap)" : "")
4136 << "\n\n\n";
4137 }
4138 }
4139#endif
4140
4141 return result;
4142}
4143
4144
4145double
4146MSLCM_SL2015::getLeftBorder(bool checkOpposite) const {
4147 return (myVehicle.getLane()->getEdge().getWidth()
4148 + ((myVehicle.getLane()->getParallelOpposite() != nullptr && checkOpposite) ? myVehicle.getLane()->getParallelOpposite()->getEdge().getWidth() : 0));
4149}
4150
4151double
4153 if (isOpposite()) {
4155 } else {
4156 return myVehicle.getCenterOnEdge();
4157 }
4158}
4159
4160double
4161MSLCM_SL2015::getNeighRight(const MSLane& neighLane) const {
4162 if (isOpposite()) {
4164 } else if ((&myVehicle.getLane()->getEdge() != &neighLane.getEdge())) {
4166 } else {
4167 // the normal case
4168 return neighLane.getRightSideOnEdge();
4169 }
4170}
4171
4172
4173bool
4174MSLCM_SL2015::preventSliding(double maneuverDist) const {
4175 // prevent wide maneuvers with unsufficient forward space
4176 if (fabs(maneuverDist) > myMaxDistLatStanding) {
4177 // emergency vehicles should not be restricted (TODO solve this with LCA_URGENT)
4179 return false;
4180 }
4181 const double brakeGap = myVehicle.getCarFollowModel().brakeGap(myVehicle.getSpeed());
4182 const bool isSlide = fabs(maneuverDist) > myMaxDistLatStanding + brakeGap * fabs(myMaxSpeedLatFactor);
4183#ifdef DEBUG_SLIDING
4184 if (gDebugFlag2) {
4185 std::cout << SIMTIME << " veh=" << myVehicle.getID() << " bgap=" << brakeGap << " maneuverDist=" << maneuverDist
4186 << " mds=" << myMaxDistLatStanding << " isSlide=" << isSlide << "\n";
4187 }
4188#endif
4189 return isSlide;
4190 }
4191 return false;
4192}
4193
4194bool
4195MSLCM_SL2015::wantsKeepRight(double keepRightProb) const {
4197}
4198
4199
4200bool
4201MSLCM_SL2015::saveBlockerLength(double length, double foeLeftSpace) {
4202 const bool canReserve = MSLCHelper::canSaveBlockerLength(myVehicle, length, myLeftSpace);
4203 if (!isOpposite() && (canReserve || myLeftSpace > foeLeftSpace)) {
4205 if (myLeftSpace == 0 && foeLeftSpace < 0) {
4206 // called from opposite overtaking, myLeftSpace must be initialized
4208 }
4209 return true;
4210 } else {
4211 return false;
4212 }
4213}
4214
4215
4216bool
4220/****************************************************************************/
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:958
bool canChangeToOpposite() const
whether this edge allows changing to the opposite direction edge
Definition MSEdge.cpp:1366
bool isInternal() const
return whether this edge is an internal edge
Definition MSEdge.h:269
double getWidth() const
Returns the edges's width (sum over all lanes)
Definition MSEdge.h:665
const std::vector< double > getSubLaneSides() const
Returns the right side offsets of this edge's sublanes.
Definition MSEdge.h:670
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:4581
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:2857
const MSLink * getLinkTo(const MSLane *const) const
returns the link to the given lane or nullptr, if it is not connected
Definition MSLane.cpp:2752
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:935
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:1205
bool hasPedestrians() const
whether the lane has pedestrians on it
Definition MSLane.cpp:4574
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:4390
MSLane * getBidiLane() const
retrieve bidirectional lane or nullptr
Definition MSLane.cpp:4686
MSLane * getParallelOpposite() const
return the opposite direction lane of this lanes edge or nullptr
Definition MSLane.cpp:4396
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:3248
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:1209
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:1603
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:1611
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:1038
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:1702
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