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