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