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