LCOV - code coverage report
Current view: top level - src/microsim/lcmodels - MSLCM_SL2015.cpp (source / functions) Coverage Total Hit
Test: lcov.info Lines: 92.0 % 1408 1296
Test Date: 2026-09-20 15:45:03 Functions: 100.0 % 63 63

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

Generated by: LCOV version 2.0-1