LCOV - code coverage report
Current view: top level - src/microsim - MSLink.cpp (source / functions) Coverage Total Hit
Test: lcov.info Lines: 91.7 % 920 844
Test Date: 2025-11-13 15:38:19 Functions: 96.7 % 61 59

            Line data    Source code
       1              : /****************************************************************************/
       2              : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
       3              : // Copyright (C) 2001-2025 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    MSLink.cpp
      15              : /// @author  Daniel Krajzewicz
      16              : /// @author  Jakob Erdmann
      17              : /// @author  Michael Behrisch
      18              : /// @author  Laura Bieker
      19              : /// @date    Sept 2002
      20              : ///
      21              : // A connection between lanes
      22              : /****************************************************************************/
      23              : #include <config.h>
      24              : 
      25              : #include <iostream>
      26              : #include <algorithm>
      27              : #include <limits>
      28              : #include <utils/iodevices/OutputDevice.h>
      29              : #include <utils/common/RandHelper.h>
      30              : #include <utils/common/StringTokenizer.h>
      31              : #include "MSNet.h"
      32              : #include "MSJunction.h"
      33              : #include "MSJunctionLogic.h"
      34              : #include "MSLink.h"
      35              : #include "MSLane.h"
      36              : #include <microsim/transportables/MSPerson.h>
      37              : #include <microsim/transportables/MSTransportableControl.h>
      38              : #include "MSEdge.h"
      39              : #include "MSGlobals.h"
      40              : #include "MSVehicle.h"
      41              : #include <microsim/lcmodels/MSAbstractLaneChangeModel.h>
      42              : #include <microsim/transportables/MSPModel.h>
      43              : 
      44              : //#define MSLink_DEBUG_CROSSING_POINTS
      45              : //#define MSLink_DEBUG_CROSSING_POINTS_DETAILS
      46              : //#define MSLink_DEBUG_OPENED
      47              : //#define DEBUG_APPROACHING
      48              : //#define DEBUG_ZIPPER
      49              : //#define DEBUG_WALKINGAREA
      50              : //#define DEBUG_COND (myLane->getID()=="43[0]_0" && myLaneBefore->getID()==":33_0_0")
      51              : //#define DEBUG_COND (myLane->getID()=="end_0")
      52              : //#define DEBUG_COND (true)
      53              : #define DEBUG_COND2(obj) (obj->isSelected())
      54              : //#define DEBUG_COND2(obj) (obj->getID() == "train2")
      55              : //#define DEBUG_COND2(obj) (true)
      56              : //#define DEBUG_COND_ZIPPER (gDebugFlag1)
      57              : //#define DEBUG_COND_ZIPPER (true)
      58              : #define DEBUG_COND_ZIPPER (ego->isSelected())
      59              : 
      60              : // ===========================================================================
      61              : // static member variables
      62              : // ===========================================================================
      63              : 
      64              : #define INVALID_TIME -1000
      65              : 
      66              : // the default safety gap when passing before oncoming pedestrians
      67              : #define JM_CROSSING_GAP_DEFAULT 10
      68              : 
      69              : // minimim width between sibling lanes to qualify as non-overlapping
      70              : #define DIVERGENCE_MIN_WIDTH 2.5
      71              : 
      72              : const SUMOTime MSLink::myLookaheadTime = TIME2STEPS(1);
      73              : // additional caution is needed when approaching a zipper link
      74              : const SUMOTime MSLink::myLookaheadTimeZipper = TIME2STEPS(16);
      75              : std::set<std::pair<MSLink*, MSLink*> > MSLink::myRecheck;
      76              : const double MSLink::NO_INTERSECTION(10000);
      77              : 
      78              : // ===========================================================================
      79              : // ConflictInfo member method definitions
      80              : // ===========================================================================
      81              : 
      82              : double
      83    398094156 : MSLink::ConflictInfo::getFoeLengthBehindCrossing(const MSLink* foeExitLink) const {
      84    398094156 :     if (flag == CONFLICT_DUMMY_MERGE) {
      85              :         return 0;
      86    390917440 :     } else if (foeConflictIndex >= 0) {
      87    373586284 :         return foeExitLink->myConflicts[foeConflictIndex].lengthBehindCrossing;
      88              :     } else {
      89              :         return -NO_INTERSECTION;
      90              :     }
      91              : }
      92              : 
      93              : double
      94    208954709 : MSLink::ConflictInfo::getFoeConflictSize(const MSLink* foeExitLink) const {
      95    208954709 :     if (foeConflictIndex >= 0) {
      96    191692704 :         return foeExitLink->myConflicts[foeConflictIndex].conflictSize;
      97              :     } else {
      98              :         return 0;
      99              :     }
     100              : }
     101              : 
     102              : double
     103    398226854 : MSLink::ConflictInfo::getLengthBehindCrossing(const MSLink* exitLink) const {
     104    398226854 :     if (flag == CONFLICT_STOP_AT_INTERNAL_JUNCTION) {
     105     16820842 :         return exitLink->getInternalLaneBefore()->getLength();
     106              :     } else {
     107    381406012 :         return lengthBehindCrossing;
     108              :     }
     109              : }
     110              : 
     111              : // ===========================================================================
     112              : // member method definitions
     113              : // ===========================================================================
     114      2505975 : MSLink::MSLink(MSLane* predLane, MSLane* succLane, MSLane* via, LinkDirection dir, LinkState state,
     115              :                double length, double foeVisibilityDistance, bool keepClear,
     116              :                MSTrafficLightLogic* logic, int tlIndex,
     117      2505975 :                bool indirect) :
     118      2505975 :     myLane(succLane),
     119      2505975 :     myLaneBefore(predLane),
     120      2505975 :     myApproachingPersons(nullptr),
     121      2505975 :     myIndex(-1),
     122      2505975 :     myTLIndex(tlIndex),
     123      2505975 :     myLogic(logic),
     124      2505975 :     myState(state),
     125      2505975 :     myLastGreenState(LINKSTATE_TL_GREEN_MINOR),
     126      2505975 :     myOffState(state),
     127      2505975 :     myLastStateChange(SUMOTime_MIN / 2), // a large negative value, but avoid overflows when subtracting
     128      2505975 :     myDirection(dir),
     129      2505975 :     myLength(length),
     130      2505975 :     myFoeVisibilityDistance(foeVisibilityDistance),
     131      2505975 :     myDistToFoePedCrossing(std::numeric_limits<double>::max()),
     132      2505975 :     myHasFoes(false),
     133      2505975 :     myAmCont(false),
     134      2505975 :     myAmContOff(false),
     135      2505975 :     myKeepClear(keepClear),
     136      2505975 :     myInternalLane(via),
     137      2505975 :     myInternalLaneBefore(nullptr),
     138      2505975 :     myMesoTLSPenalty(0),
     139      2505975 :     myGreenFraction(1),
     140      2505975 :     myLateralShift(0),
     141      2505975 :     myOffFoeLinks(nullptr),
     142      2505975 :     myWalkingAreaFoe(nullptr),
     143      2505975 :     myWalkingAreaFoeExit(nullptr),
     144      2505975 :     myHavePedestrianCrossingFoe(false),
     145      2505975 :     myParallelRight(nullptr),
     146      2505975 :     myParallelLeft(nullptr),
     147      2505975 :     myAmIndirect(indirect),
     148      2505975 :     myRadius(std::numeric_limits<double>::max()),
     149      2505975 :     myPermissions(myLaneBefore->getPermissions() & myLane->getPermissions() & (via == nullptr ? SVCAll : via->getPermissions())),
     150      2505975 :     myJunction(nullptr) {
     151              : 
     152      2505975 :     if (MSGlobals::gLateralResolution > 0) {
     153              :         // detect lateral shift from lane geometries
     154              :         //std::cout << "DEBUG link=" << myLaneBefore->getID() << "->" << getViaLaneOrLane()->getID() << " hasInternal=" << MSNet::getInstance()->hasInternalLinks() << " shapeBefore=" << myLaneBefore->getShape().back() << " shapeFront=" << getViaLaneOrLane()->getShape().front() << "\n";
     155       197499 :         if ((myInternalLane != nullptr || predLane->isInternal())
     156       490819 :                 && myLaneBefore->getShape().back() != getViaLaneOrLane()->getShape().front()) {
     157              :             PositionVector from = myLaneBefore->getShape();
     158              :             const PositionVector& to = getViaLaneOrLane()->getShape();
     159              :             const double dist = from.back().distanceTo2D(to.front());
     160              :             // figure out direction of shift
     161              :             try {
     162          642 :                 from.move2side(dist);
     163            0 :             } catch (InvalidArgument&) {
     164            0 :             }
     165          642 :             myLateralShift = (from.back().distanceTo2D(to.front()) < dist) ? dist : -dist;
     166          642 :             if (MSGlobals::gLefthand) {
     167           90 :                 myLateralShift *= -1;
     168              :             }
     169              :             //std::cout << " lateral shift link=" << myLaneBefore->getID() << "->" << getViaLaneOrLane()->getID() << " dist=" << dist << " shift=" << myLateralShift << "\n";
     170          642 :         }
     171              :     }
     172      2505975 : }
     173              : 
     174              : 
     175      2482123 : MSLink::~MSLink() {
     176      2482123 :     delete myOffFoeLinks;
     177      2483822 :     delete myApproachingPersons;
     178      2482123 : }
     179              : 
     180              : 
     181              : void
     182            4 : MSLink::addCustomConflict(const MSLane* from, const MSLane* to, double startPos, double endPos) {
     183            4 :     myCustomConflicts.push_back(CustomConflict(from, to, startPos, endPos));
     184            4 : }
     185              : 
     186              : const MSLink::CustomConflict*
     187      3026576 : MSLink::getCustomConflict(const MSLane* foeLane) const {
     188      3026576 :     if (myCustomConflicts.size() > 0) {
     189           16 :         const MSLane* foeFrom = foeLane->getNormalPredecessorLane();
     190           16 :         const MSLane* foeTo = foeLane->getNormalSuccessorLane();
     191           24 :         for (const CustomConflict& cc : myCustomConflicts) {
     192           16 :             if (cc.from == foeFrom && cc.to == foeTo) {
     193              :                 return &cc;
     194              :             }
     195              :         }
     196              : 
     197              :     }
     198              :     return nullptr;
     199              : }
     200              : 
     201              : void
     202      2289323 : MSLink::setRequestInformation(int index, bool hasFoes, bool isCont,
     203              :                               const std::vector<MSLink*>& foeLinks,
     204              :                               const std::vector<MSLane*>& foeLanes,
     205              :                               MSLane* internalLaneBefore) {
     206              : //#ifdef MSLink_DEBUG_CROSSING_POINTS
     207              : //    std::cout << " setRequestInformation() for junction " << getViaLaneOrLane()->getEdge().getFromJunction()->getID()
     208              : //            << "\nInternalLanes = " << toString(getViaLaneOrLane()->getEdge().getFromJunction()->getInternalLanes())
     209              : //            << std::endl;
     210              : //#endif
     211      2289323 :     myIndex = index;
     212      2289323 :     myHasFoes = hasFoes;
     213      2289323 :     myAmCont = isCont && MSGlobals::gUsingInternalLanes;
     214      2289323 :     myFoeLinks = foeLinks;
     215      7815102 :     for (MSLane* foeLane : foeLanes) {
     216              :         // cannot assign vector due to const-ness
     217      5525779 :         myFoeLanes.push_back(foeLane);
     218              :     }
     219      2289323 :     myJunction = const_cast<MSJunction*>(myLane->getEdge().getFromJunction()); // junctionGraph is initialized after the whole network is loaded
     220      2289323 :     myAmContOff = isCont && myLogic != nullptr && internalLaneBefore == nullptr && checkContOff();
     221      2289323 :     myInternalLaneBefore = internalLaneBefore;
     222              :     MSLane* lane = nullptr;
     223              :     if (internalLaneBefore != nullptr) {
     224              :         // this is an exit link. compute crossing points with all foeLanes
     225              :         lane = internalLaneBefore;
     226              :         //} else if (myLane->getEdge().isCrossing()) {
     227              :         //    // this is the link to a pedestrian crossing. compute crossing points with all foeLanes
     228              :         //    // @note not currently used by pedestrians
     229              :         //    lane = myLane;
     230              :     }
     231      2289323 :     const MSLink* entryLink = getCorrespondingEntryLink();
     232      2289323 :     if (entryLink->getOffState() == LinkState::LINKSTATE_ALLWAY_STOP && entryLink->getTLLogic() != nullptr) {
     233              :         // TLS has "normal" right of way rules but all conflicting links are foes when switching TLS off
     234              :         // (unless it's an internal junction link which should ignore all foes and should be ignored by all foes
     235         5179 :         myOffFoeLinks = new std::vector<MSLink*>();
     236         5179 :         if (isEntryLink()) {
     237        13936 :             for (MSLane* foeLane : foeLanes) {
     238              :                 assert(foeLane->isInternal() || foeLane->isCrossing());
     239        11660 :                 MSLink* viaLink = foeLane->getIncomingLanes().front().viaLink;
     240        11660 :                 if (viaLink->getLaneBefore()->isNormal()) {
     241         7050 :                     myOffFoeLinks->push_back(viaLink);
     242              :                 }
     243              :             }
     244              :         }
     245              :     }
     246              : #ifdef MSLink_DEBUG_CROSSING_POINTS
     247              :     std::cout << "link " << myIndex << " to " << getViaLaneOrLane()->getID() << " internalLaneBefore=" << (lane == 0 ? "NULL" : lane->getID()) << " has foes: " << toString(foeLanes) << "\n";
     248              : #endif
     249      2289323 :     if (lane != nullptr) {
     250       774876 :         const bool beforeInternalJunction = lane->getLinkCont()[0]->getViaLaneOrLane()->getEdge().isInternal();
     251       774876 :         if (lane->getIncomingLanes().size() != 1) {
     252            0 :             throw ProcessError(TLF("Internal lane '%' has % predecessors", lane->getID(), toString(lane->getIncomingLanes().size())));
     253              :         }
     254       774876 :         const MSLink* junctionEntryLink = lane->getEntryLink();
     255       774876 :         const bool isSecondPart = isExitLinkAfterInternalJunction();
     256              :         // compute crossing points
     257      3900737 :         for (const MSLane* foeLane : myFoeLanes) {
     258      3125861 :             const CustomConflict* cc = junctionEntryLink != nullptr ? junctionEntryLink->getCustomConflict(foeLane) : nullptr;
     259      3026568 :             if (cc != nullptr) {
     260              :                 // handle custom conflict definition
     261            8 :                 double startPos = cc->startPos;
     262            8 :                 const double conflictSize = cc->endPos - cc->startPos;
     263            8 :                 if (isSecondPart) {
     264            0 :                     startPos -= junctionEntryLink->getViaLane()->getLength();
     265              :                 }
     266              :                 // the foe connection may be split at an internal
     267              :                 // junction, we need to figure out whether the current
     268              :                 // foeLane is the intended target for the custom conflict
     269              :                 // There are two possibilities:
     270              :                 // a) We have no custom conflict for the reverse pair of connections
     271              :                 //    -> just check whether lane and foeLane intersect
     272              :                 // b) We have a "reverse" custom conflict
     273              :                 //    -> check whether it covers the foeLane
     274            8 :                 const CustomConflict* rcc = foeLane->getEntryLink()->getCustomConflict(lane);
     275              :                 bool haveIntersection = false;
     276            8 :                 if (rcc == nullptr) {
     277              :                     // a)
     278            8 :                     haveIntersection = lane->getShape().intersectsAtLengths2D(foeLane->getShape()).size() > 0;
     279              :                 } else {
     280              :                     // b)
     281            0 :                     const bool foeIsSecondPart = foeLane->getLogicalPredecessorLane()->isInternal();
     282            0 :                     double foeStartPos = rcc->startPos;
     283            0 :                     const double foeConflictSize = rcc->endPos - rcc->startPos;
     284            0 :                     if (foeIsSecondPart) {
     285            0 :                         foeStartPos -= foeLane->getLogicalPredecessorLane()->getLength();
     286              :                     }
     287            0 :                     const double foeEndPos = foeStartPos + foeConflictSize;
     288            0 :                     haveIntersection = ((foeStartPos > 0 && foeStartPos < foeLane->getLength())
     289            0 :                                         || (foeEndPos > 0 && foeEndPos < foeLane->getLength()));
     290              :                 }
     291            8 :                 if (haveIntersection) {
     292            4 :                     myConflicts.push_back(ConflictInfo(lane->getLength() - startPos, conflictSize));
     293              :                 } else {
     294            4 :                     myConflicts.push_back(ConflictInfo(-NO_INTERSECTION, 0));
     295              :                 }
     296              : #ifdef MSLink_DEBUG_CROSSING_POINTS
     297              :                 std::cout << " " << lane->getID() << " custom conflict with " << foeLane->getID() << " customReverse=" << (rcc != nullptr)
     298              :                           << " haveIntersection=" << haveIntersection
     299              :                           << " startPos=" << startPos << " conflictSize=" << conflictSize
     300              :                           << " lbc=" << myConflicts.back().lengthBehindCrossing
     301              :                           << "\n";
     302              : #endif
     303            8 :                 continue;
     304            8 :             }
     305      3125853 :             myHavePedestrianCrossingFoe = myHavePedestrianCrossingFoe || foeLane->getEdge().isCrossing();
     306      3125853 :             const bool sameTarget = myLane == foeLane->getLinkCont()[0]->getLane();
     307      3125853 :             if (sameTarget && !beforeInternalJunction && !contIntersect(lane, foeLane)) {
     308              :                 //if (myLane == foeLane->getLinkCont()[0]->getLane()) {
     309              :                 // this foeLane has the same target and merges at the end (lane exits the junction)
     310      1030435 :                 const double minDist = MIN2(DIVERGENCE_MIN_WIDTH, 0.5 * (lane->getWidth() + foeLane->getWidth()));
     311      1030435 :                 if (lane->getShape().back().distanceTo2D(foeLane->getShape().back()) >= minDist) {
     312              :                     // account for lateral shift by the entry links
     313        93826 :                     if (foeLane->getEntryLink()->isIndirect()) {
     314           29 :                         myConflicts.push_back(ConflictInfo(-NO_INTERSECTION, 0)); // dummy value, never used
     315              : #ifdef MSLink_DEBUG_CROSSING_POINTS
     316              :                         std::cout << " " << lane->getID() << " dummy merge with indirect" << foeLane->getID() << "\n";
     317              : #endif
     318              :                     } else {
     319        93797 :                         myConflicts.push_back(ConflictInfo(0, foeLane->getWidth(), CONFLICT_DUMMY_MERGE)); // dummy value, never used
     320              : #ifdef MSLink_DEBUG_CROSSING_POINTS
     321              :                         std::cout << " " << lane->getID() << " dummy merge with " << foeLane->getID() << "\n";
     322              : #endif
     323              :                     }
     324              :                 } else {
     325       936609 :                     const double distAfterDivergence = computeDistToDivergence(lane, foeLane, minDist, false);
     326              :                     const double lbcLane = lane->interpolateGeometryPosToLanePos(distAfterDivergence);
     327       936609 :                     myConflicts.push_back(ConflictInfo(lbcLane, foeLane->getWidth()));
     328              : #ifdef MSLink_DEBUG_CROSSING_POINTS
     329              :                     std::cout
     330              :                             << " " << lane->getID()
     331              :                             << " merges with " << foeLane->getID()
     332              :                             << " nextLane " << lane->getLinkCont()[0]->getViaLaneOrLane()->getID()
     333              :                             << " dist1=" << myConflicts.back().lengthBehindCrossing
     334              :                             << "\n";
     335              : #endif
     336              :                 }
     337              :             } else {
     338      2095418 :                 std::vector<double> intersections1 = lane->getShape().intersectsAtLengths2D(foeLane->getShape());
     339              : #ifdef MSLink_DEBUG_CROSSING_POINTS_DETAILS
     340              :                 std::cout << "    intersections1=" << toString(intersections1) << "\n";
     341              : #endif
     342              :                 bool haveIntersection = true;
     343      2095418 :                 if (intersections1.size() == 0) {
     344      1082267 :                     intersections1.push_back(-NO_INTERSECTION); // disregard this foe (using maxdouble leads to nasty problems down the line)
     345              :                     haveIntersection = false;
     346      1013151 :                 } else if (intersections1.size() > 1) {
     347         1293 :                     std::sort(intersections1.begin(), intersections1.end());
     348              :                 }
     349      2095418 :                 std::vector<double> intersections2 = foeLane->getShape().intersectsAtLengths2D(lane->getShape());
     350              : #ifdef MSLink_DEBUG_CROSSING_POINTS_DETAILS
     351              :                 std::cout << "    intersections2=" << toString(intersections2) << "\n";
     352              : #endif
     353      2095418 :                 if (intersections2.size() == 0) {
     354      1082267 :                     intersections2.push_back(0);
     355      1013151 :                 } else if (intersections2.size() > 1) {
     356         1293 :                     std::sort(intersections2.begin(), intersections2.end());
     357              :                 }
     358              : 
     359              :                 // check for near-intersection (internal junctions for a side road which are only relevant when they have stranded vehicles))
     360      2095418 :                 if (!haveIntersection && foeLane->getLinkCont()[0]->getViaLane() != nullptr) {
     361       173324 :                     const Position waitPos = foeLane->getShape().back();
     362       173324 :                     const double dist = lane->getShape().distance2D(waitPos, true);
     363       173324 :                     if (dist != GeomHelper::INVALID_OFFSET && dist < lane->getWidth() / 2) {
     364              :                         // risk of collision
     365              :                         intersections1.clear();
     366              :                         intersections2.clear();
     367        22012 :                         intersections1.push_back(lane->getShape().nearest_offset_to_point2D(waitPos));
     368        22012 :                         intersections2.push_back(foeLane->getShape().length());
     369              :                         haveIntersection = true;
     370              : #ifdef MSLink_DEBUG_CROSSING_POINTS_DETAILS
     371              :                         std::cout << "    link=" << myIndex << " " << getDescription() << " almostIntersection with foeLane " << foeLane->getID() << " offset=" << intersections1.back() << "\n";
     372              : #endif
     373              :                     }
     374              :                 }
     375              : 
     376              :                 double conflictSize = foeLane->getWidth();
     377              :                 ConflictFlag flag = CONFLICT_NO_INTERSECTION;
     378      2073406 :                 if (haveIntersection) {
     379              :                     flag = CONFLICT_DEFAULT;
     380      1035163 :                     const double angle1 = GeomHelper::naviDegree(lane->getShape().rotationAtOffset(intersections1.back()));
     381      1035163 :                     const double angle2 = GeomHelper::naviDegree(foeLane->getShape().rotationAtOffset(intersections2.back()));
     382      1035163 :                     const double angleDiff = GeomHelper::getMinAngleDiff(angle1, angle2);
     383              :                     //const double angleDiff = MIN2(GeomHelper::getMinAngleDiff(angle1, angle2),
     384              :                     //                              GeomHelper::getMinAngleDiff(angle1, angle2 + 180));
     385      1035163 :                     const double widthFactor = 1 / MAX2(sin(DEG2RAD(angleDiff)), 0.2) * 2 - 1;
     386              :                     //std::cout << "  intersection of " << lane->getID() << " with " << foeLane->getID() << " angle1=" << angle1 << " angle2=" << angle2 << " angleDiff=" << angleDiff << " widthFactor=" << widthFactor << "\n";
     387      1035163 :                     conflictSize *= widthFactor;
     388              :                     conflictSize = MIN2(conflictSize, lane->getLength());
     389              :                     // lane width affects the crossing point
     390      1035163 :                     intersections1.back() -= conflictSize / 2;
     391              :                     // ensure non-negative offset for weird geometries
     392      1035163 :                     intersections1.back() = MAX2(0.0, intersections1.back());
     393              : 
     394              :                     // also length/geometry factor. (XXX: Why subtract width/2 *before* converting geometric position to lane pos? refs #3031)
     395      1035163 :                     intersections1.back() = lane->interpolateGeometryPosToLanePos(intersections1.back());
     396              : 
     397      1035163 :                     if (internalLaneBefore->getLogicalPredecessorLane()->getEdge().isInternal() && !foeLane->getEdge().isCrossing())  {
     398              :                         flag = CONFLICT_STOP_AT_INTERNAL_JUNCTION;
     399              :                     }
     400              : 
     401      1035163 :                     if (foeLane->getEdge().isCrossing()) {
     402        93141 :                         const MSLink* before = myInternalLaneBefore->getCanonicalPredecessorLane()->getLinkTo(myInternalLaneBefore);
     403        93141 :                         const_cast<MSLink*>(before)->updateDistToFoePedCrossing(intersections1.back());
     404              :                     };
     405              :                 }
     406              : 
     407      2095418 :                 myConflicts.push_back(ConflictInfo(
     408      2095418 :                                           lane->getLength() - intersections1.back(),
     409              :                                           conflictSize, flag));
     410              : 
     411              : #ifdef MSLink_DEBUG_CROSSING_POINTS
     412              :                 std::cout
     413              :                         << "  intersection of " << lane->getID()
     414              :                         << " totalLength=" << lane->getLength()
     415              :                         << " with " << foeLane->getID()
     416              :                         << " totalLength=" << foeLane->getLength()
     417              :                         << " dist1=" << myConflicts.back().lengthBehindCrossing
     418              :                         << " widthFactor=" << myConflicts.back().conflictSize / foeLane->getWidth()
     419              :                         << "\n";
     420              : #endif
     421      2095418 :             }
     422              :         }
     423              :         // check for overlap with internal lanes from the same source lane
     424       774876 :         const MSLane* pred = lane->getLogicalPredecessorLane();
     425              :         // to avoid overlap with vehicles that came from pred (especially when pred has endOffset > 0)
     426              :         // we add all other internal lanes from pred as foeLanes
     427      2506919 :         for (const MSLink* const link : pred->getLinkCont()) {
     428      1732043 :             const MSLane* const sibling = link->getViaLane();
     429      1732043 :             if (sibling != lane && sibling != nullptr) {
     430       934296 :                 const double minDist = MIN2(DIVERGENCE_MIN_WIDTH, 0.5 * (lane->getWidth() + sibling->getWidth()));
     431       934296 :                 if (lane->getShape().front().distanceTo2D(sibling->getShape().front()) >= minDist) {
     432              :                     // account for lateral shift by the entry links
     433          620 :                     continue;
     434              :                 }
     435       933676 :                 const double distToDivergence = computeDistToDivergence(lane, sibling, minDist, true);
     436              :                 double lbcLane;
     437       933676 :                 if (lane->getLength() == sibling->getLength() && &lane->getEdge() == &sibling->getEdge()) {
     438              :                     // for parallel lanes, avoid inconsistency in distance estimation (#10988)
     439              :                     // between forward distance (getLeaderInfo)
     440              :                     // and backward distance used in lane-changing (getFollowersOnConsecutive)
     441        12168 :                     lbcLane = lane->getLength() - distToDivergence;
     442              :                 } else {
     443       921508 :                     lbcLane = MAX2(0.0, lane->getLength() - lane->interpolateGeometryPosToLanePos(distToDivergence));
     444              :                 }
     445              :                 ConflictInfo ci = ConflictInfo(lbcLane, sibling->getWidth());
     446       933676 :                 auto it = std::find(myFoeLanes.begin(), myFoeLanes.end(), sibling);
     447       933676 :                 if (it != myFoeLanes.end()) {
     448              :                     // avoid duplicate foeLane
     449           66 :                     const int replacedIndex = (int)(it - myFoeLanes.begin());
     450           66 :                     myConflicts[replacedIndex] = ci;
     451              :                 } else {
     452       933610 :                     myConflicts.push_back(ci);
     453       933610 :                     myFoeLanes.push_back(sibling);
     454              :                 }
     455              : #ifdef MSLink_DEBUG_CROSSING_POINTS
     456              :                 std::cout << " adding same-origin foe" << sibling->getID()
     457              :                           << " dist1=" << myConflicts.back().lengthBehindCrossing
     458              :                           << "\n";
     459              : #endif
     460       933676 :                 const MSLane* const siblingCont = sibling->getLinkCont().front()->getViaLaneOrLane();
     461       933676 :                 if (siblingCont->isInternal() && lane->getShape().distance2D(siblingCont->getShape().front()) < minDist) {
     462              :                     // there may still be overlap with siblingCont (when considering vehicle widths)
     463       210890 :                     const double distToDivergence2 = computeDistToDivergence(lane, siblingCont, minDist, true, sibling->getLength());
     464       210890 :                     double lbcLane2 = MAX2(0.0, lane->getLength() - lane->interpolateGeometryPosToLanePos(distToDivergence2));
     465              :                     ConflictInfo ci2 = ConflictInfo(lbcLane2, siblingCont->getWidth(), CONFLICT_SIBLING_CONTINUATION);
     466       210890 :                     myConflicts.push_back(ci2);
     467       210890 :                     myFoeLanes.push_back(siblingCont);
     468       210890 :                     myRecheck.insert({this, siblingCont->getLinkCont().front()});
     469              : 
     470              : #ifdef MSLink_DEBUG_CROSSING_POINTS
     471              :                     std::cout << " adding same-origin foeContinuation" << siblingCont->getID()
     472              :                               << " dist1=" << myConflicts.back().lengthBehindCrossing
     473              :                               << "\n";
     474              : #endif
     475              :                 }
     476              :             }
     477              :         }
     478              :         // init points for the symmetrical conflict
     479              :         // for each pair of conflicting lanes, the link that gets second, sets the pointers
     480      5045237 :         for (int i = 0; i < (int)myFoeLanes.size(); i++) {
     481      4270361 :             const MSLane* foeLane = myFoeLanes[i];
     482      4270361 :             MSLink* foeExitLink = foeLane->getLinkCont()[0];
     483              :             int foundIndex = -1;
     484     16255440 :             for (int i2 = 0; i2 < (int)foeExitLink->myFoeLanes.size(); i2++) {
     485     13805188 :                 if (foeExitLink->myFoeLanes[i2] == lane) {
     486      1820109 :                     myConflicts[i].foeConflictIndex = i2;
     487      1820109 :                     foeExitLink->myConflicts[i2].foeConflictIndex = i;
     488      1820109 :                     myRecheck.erase({foeExitLink, this});
     489              :                     foundIndex = i2;
     490      1820109 :                     break;
     491              :                 }
     492              :             }
     493              : #ifdef MSLink_DEBUG_CROSSING_POINTS
     494              :             std::cout << lane->getID() << " foeLane=" << foeLane->getID() << " index=" << i << " foundIndex=" << foundIndex << "\n";
     495              : #endif
     496      4270361 :             if (foundIndex < 0) {
     497      2450252 :                 if (myConflicts[i].flag != CONFLICT_NO_INTERSECTION) {
     498      1769383 :                     myRecheck.insert({this, foeExitLink});
     499              :                 }
     500              :             }
     501              :         }
     502              :     }
     503      2289323 :     if (MSGlobals::gLateralResolution > 0) {
     504              :         // check for links with the same origin lane and the same destination edge
     505       283988 :         const MSEdge* myTarget = &myLane->getEdge();
     506              :         // save foes for entry links
     507       900886 :         for (MSLink* const it : myLaneBefore->getLinkCont()) {
     508              :             const MSEdge* target = &(it->getLane()->getEdge());
     509       616898 :             if (it == this) {
     510       283988 :                 continue;
     511              :             }
     512       332910 :             if (target == myTarget) {
     513         6672 :                 mySublaneFoeLinks.push_back(it);
     514              : #ifdef MSLink_DEBUG_CROSSING_POINTS
     515              :                 std::cout << "  sublaneFoeLink (same target): " << it->getViaLaneOrLane()->getID() << "\n";
     516              : #endif
     517       326238 :             } else if (myDirection != LinkDirection::STRAIGHT && it->getDirection() == LinkDirection::STRAIGHT) {
     518              :                 // potential turn conflict
     519        79533 :                 mySublaneFoeLinks2.push_back(it);
     520              : #ifdef MSLink_DEBUG_CROSSING_POINTS
     521              :                 std::cout << "  sublaneFoeLink2 (other target: " << it->getViaLaneOrLane()->getID() << "\n";
     522              : #endif
     523              :             }
     524              :         }
     525              :         // save foes for exit links
     526       283988 :         if (fromInternalLane()) {
     527              :             //std::cout << " setRequestInformation link=" << getViaLaneOrLane()->getID() << " before=" << myLaneBefore->getID() << " before2=" << myLaneBefore->getIncomingLanes().front().lane->getID() << "\n";
     528       352178 :             for (const MSLink* const link : myLaneBefore->getIncomingLanes().front().lane->getLinkCont()) {
     529       247690 :                 if (link->getViaLane() != myInternalLaneBefore && &link->getLane()->getEdge() == myTarget) {
     530              :                     //std::cout << " add sublaneFoe=" << (*it)->getViaLane()->getID() << "\n";
     531         4222 :                     mySublaneFoeLanes.push_back(link->getViaLane());
     532              :                 }
     533              :             }
     534              :         }
     535              :     }
     536      2289323 :     if (myInternalLaneBefore != nullptr
     537       774876 :             && myDirection != LinkDirection::STRAIGHT
     538              :             // for right turns, the curvature helps rather than restricts the linkLeader check
     539       449076 :             && (
     540       449076 :                 (!MSGlobals::gLefthand && myDirection != LinkDirection::RIGHT)
     541       135046 :                 || (MSGlobals::gLefthand && myDirection != LinkDirection::LEFT))) {
     542       628890 :         const double angle = fabs(GeomHelper::angleDiff(
     543       314445 :                                       myLaneBefore->getNormalPredecessorLane()->getShape().angleAt2D(-2),
     544       314445 :                                       myLane->getShape().angleAt2D(0)));
     545       314445 :         if (angle > 0) {
     546       314445 :             double length = myInternalLaneBefore->getShape().length2D();
     547       628890 :             if (myInternalLaneBefore->getIncomingLanes().size() == 1 &&
     548       314445 :                     myInternalLaneBefore->getIncomingLanes()[0].lane->isInternal()) {
     549        86592 :                 length += myInternalLaneBefore->getIncomingLanes()[0].lane->getShape().length2D();
     550       227853 :             } else if (myInternalLane != nullptr) {
     551        86592 :                 length += myInternalLane->getShape().length2D();
     552              :             }
     553       314445 :             myRadius = length / angle;
     554              :             //std::cout << getDescription() << " a=" << RAD2DEG(angle) << " l=" << length << " r=" << myRadius << "\n";
     555              :         }
     556              :     }
     557      2289323 : }
     558              : 
     559              : 
     560              : void
     561        38582 : MSLink::recheckSetRequestInformation() {
     562       279275 :     for (auto item : myRecheck) {
     563              : #ifdef MSLink_DEBUG_CROSSING_POINTS
     564              :         std::cout << " recheck l1=" << item.first->getDescription() << " l2=" << item.second->getDescription() << "\n";
     565              : #endif
     566              :         MSLink* const link = item.first;
     567              :         MSLink* const foeExitLink = item.second;
     568              :         const MSLane* const lane = link->getInternalLaneBefore();
     569              :         const MSLane* const foeLane = foeExitLink->getInternalLaneBefore();
     570              :         int conflictIndex = -1;
     571      2108677 :         for (int i = 0; i < (int)link->myFoeLanes.size(); i++) {
     572      2108677 :             if (link->myFoeLanes[i] == foeLane) {
     573              :                 conflictIndex = i;
     574              :                 break;
     575              :             }
     576              :         }
     577       240693 :         if (conflictIndex == -1) {
     578            0 :             WRITE_WARNING("Could not recheck ConflictInfo for " + link->getDescription() + " and " + foeExitLink->getDescription() + "\n");
     579       211076 :             continue;
     580              :         }
     581       240693 :         ConflictInfo& ci = link->myConflicts[conflictIndex];
     582       240693 :         if (ci.flag & CONFLICT_SIBLING_CONTINUATION) {
     583       210886 :             const MSLane* const intLane = link->getInternalLaneBefore();
     584              :             const MSLane* const siblingCont = foeExitLink->getInternalLaneBefore();
     585       210886 :             const MSLane* const sibling = siblingCont->getLogicalPredecessorLane();
     586              :             // this is an approximation because intLane and sibling+siblingCont are still close to each other but may have different curvature
     587       210886 :             const double distToDivergence = intLane->getLength() - ci.lengthBehindCrossing;
     588       210886 :             double lbcSibCont = MIN2(siblingCont->getLength(), MAX2(0.0, sibling->getLength() + siblingCont->getLength() - distToDivergence));
     589              : #ifdef MSLink_DEBUG_CROSSING_POINTS
     590              :             std::cout << " siblingContinuation: distToDivergence=" << distToDivergence << " lbcSibCont=" << lbcSibCont << "\n";
     591              : #endif
     592              :             ConflictInfo ci2 = ConflictInfo(lbcSibCont, intLane->getWidth());
     593       210886 :             ci2.foeConflictIndex = conflictIndex;
     594       210886 :             ci.foeConflictIndex = (int)foeExitLink->myConflicts.size();
     595       210886 :             foeExitLink->myFoeLanes.push_back(intLane);
     596       210886 :             foeExitLink->myConflicts.push_back(ci2);
     597              :             continue;
     598       210886 :         }
     599              : 
     600        29807 :         std::vector<double> intersections1 = foeLane->getShape().intersectsAtLengths2D(lane->getShape());
     601        29807 :         if (intersections1.size() == 0) {
     602              : #ifdef MSLink_DEBUG_CROSSING_POINTS
     603              :             std::cout << "    no intersection\n";
     604              : #endif
     605              :             continue;
     606              :         }
     607        29617 :         const double widthFactor = ci.conflictSize / foeLane->getWidth();
     608        29617 :         const double conflictSize2 = lane->getWidth() * widthFactor;
     609        29617 :         std::sort(intersections1.begin(), intersections1.end());
     610        29617 :         intersections1.back() -= conflictSize2 / 2;
     611        29617 :         intersections1.back() = MAX2(0.0, intersections1.back());
     612        29617 :         ci.foeConflictIndex = (int)foeExitLink->myConflicts.size();
     613        29617 :         foeExitLink->myConflicts.push_back(ConflictInfo(foeLane->getLength() - intersections1.back(), conflictSize2));
     614              : #ifdef MSLink_DEBUG_CROSSING_POINTS
     615              :         std::cout << "    ci=" << conflictIndex << " wf=" << widthFactor << " flag=" << ci.flag << " flbc=" << foeExitLink->myConflicts.back().lengthBehindCrossing << "\n";
     616              : #endif
     617        29807 :     }
     618              :     myRecheck.clear();
     619        38582 : }
     620              : 
     621              : double
     622      2081175 : MSLink::computeDistToDivergence(const MSLane* lane, const MSLane* sibling, double minDist, bool sameSource, double siblingPredLength) const {
     623              :     double lbcSibling = 0;
     624              :     double lbcLane = 0;
     625              : 
     626              :     PositionVector l = lane->getShape();
     627              :     PositionVector s = sibling->getShape();
     628      2081175 :     double length = l.length2D();
     629      2081175 :     double sibLength = s.length2D();
     630      2081175 :     if (!sameSource) {
     631      1873218 :         l = l.reverse();
     632      1873218 :         s = s.reverse();
     633      1144566 :     } else if (sibling->getEntryLink()->myAmIndirect) {
     634              :         // ignore final waiting position since it may be quite close to the lane
     635              :         // shape but the waiting position is perpendicular (so the minDist
     636              :         // requirement is not necessary
     637           74 :         lbcSibling += s[-1].distanceTo2D(s[-2]);
     638              :         s.pop_back();
     639      1144492 :     } else if (lane->getEntryLink()->myAmIndirect) {
     640              :         // ignore final waiting position since it may be quite close to the lane
     641              :         // shape but the waiting position is perpendicular (so the minDist
     642              :         // requirement is not necessary
     643           74 :         lbcLane += l[-1].distanceTo2D(l[-2]);
     644              :         l.pop_back();
     645              :     }
     646              : 
     647              : #ifdef MSLink_DEBUG_CROSSING_POINTS_DETAILS
     648              :     std::cout << "   sameSource=" << sameSource << " minDist=" << minDist << " backDist=" << l.back().distanceTo2D(s.back()) << "\n";
     649              : #endif
     650      2081175 :     if (l.back().distanceTo2D(s.back()) > minDist) {
     651              :         // compute the final divergence point
     652              :         // this position serves two purposes:
     653              :         // 1) once the foe vehicle back (on sibling) has passed this point, we can safely ignore it
     654              :         // 2) both vehicles are put into a cf-relationship while before the point.
     655              :         //    Since the actual crossing point is at the start of the junction,
     656              :         //    we want to make sure that both vehicles have the same distance to the crossing point and thus follow each other naturally
     657      2028139 :         std::vector<double> distances = l.distances(s);
     658              : #ifdef MSLink_DEBUG_CROSSING_POINTS
     659              :         std::cout << "   distances=" << toString(distances) << "\n";
     660              : #endif
     661              :         assert(distances.size() == l.size() + s.size());
     662      2028139 :         if (distances.back() > minDist && distances[l.size() - 1] > minDist) {
     663              :             // do a pairwise check between lane and sibling to make because we do not know which of them bends more
     664      2028184 :             for (int j = (int)s.size() - 2; j >= 0; j--) {
     665      2028184 :                 const int i = j + (int)l.size();
     666      2028184 :                 const double segLength = s[j].distanceTo2D(s[j + 1]);
     667      2028184 :                 if (distances[i] > minDist) {
     668       767545 :                     lbcSibling += segLength;
     669              :                 } else {
     670              :                     // assume no sharp bends and just interpolate the last segment
     671      1260639 :                     lbcSibling += segLength - (minDist - distances[i]) * segLength / (distances[i + 1] - distances[i]);
     672      1260639 :                     break;
     673              :                 }
     674              :             }
     675      2076548 :             for (int i = (int)l.size() - 2; i >= 0; i--) {
     676      2025685 :                 const double segLength = l[i].distanceTo2D(l[i + 1]);
     677      2025685 :                 if (distances[i] > minDist) {
     678       815909 :                     lbcLane += segLength;
     679              :                 } else {
     680              :                     // assume no sharp bends and just interpolate the last segment
     681      1209776 :                     lbcLane += segLength - (minDist - distances[i]) * segLength / (distances[i + 1] - distances[i]);
     682      1209776 :                     break;
     683              :                 }
     684              :             }
     685              :         }
     686              :         assert(lbcSibling >= -NUMERICAL_EPS);
     687              :         assert(lbcLane >= -NUMERICAL_EPS);
     688      2028139 :     }
     689      2081175 :     const double distToDivergence1 = sibling->getLength() + siblingPredLength - lbcSibling;
     690      2081175 :     const double distToDivergence2 = lane->getLength() - lbcLane;
     691              :     const double distToDivergence = MIN3(
     692              :                                         MAX2(distToDivergence1, distToDivergence2),
     693              :                                         sibLength, length);
     694              : #ifdef MSLink_DEBUG_CROSSING_POINTS
     695              :     std::cout << "   distToDivergence=" << distToDivergence
     696              :               << " distTD1=" << distToDivergence1
     697              :               << " distTD2=" << distToDivergence2
     698              :               << " length=" << length
     699              :               << " sibLength=" << sibLength
     700              :               << "\n";
     701              : #endif
     702      2081175 :     return distToDivergence;
     703      2081175 : }
     704              : 
     705              : 
     706              : bool
     707      1030610 : MSLink::contIntersect(const MSLane* lane, const MSLane* foe) {
     708      1030610 :     if (foe->getLinkCont()[0]->getViaLane() != nullptr) {
     709        94240 :         std::vector<double> intersections = lane->getShape().intersectsAtLengths2D(foe->getShape());
     710        94240 :         return intersections.size() > 0;
     711        94240 :     }
     712              :     return false;
     713              : }
     714              : 
     715              : 
     716              : void
     717    814029195 : MSLink::setApproaching(const SUMOVehicle* approaching, const SUMOTime arrivalTime, const double arrivalSpeed, const double leaveSpeed,
     718              :                        const bool setRequest, const double arrivalSpeedBraking, const SUMOTime waitingTime, double dist, double latOffset) {
     719    814029195 :     const SUMOTime leaveTime = getLeaveTime(arrivalTime, arrivalSpeed, leaveSpeed, approaching->getVehicleType().getLength());
     720              : #ifdef DEBUG_APPROACHING
     721              :     if (DEBUG_COND2(approaching)) {
     722              :         std::cout << SIMTIME << " link=" << getDescription() << " setApproaching veh=" << approaching->getID();
     723              :         if (myApproachingVehicles.size() > 0) {
     724              :             std::cout << " curApproaching=";
     725              :             for (auto i = myApproachingVehicles.begin(); i != myApproachingVehicles.end(); ++i) {
     726              :                 std::cout << i->first->getID() << " ";
     727              :             }
     728              :         }
     729              :         std::cout << "\n";
     730              :     }
     731              : #endif
     732    814029195 :     myApproachingVehicles.emplace(approaching,
     733   1628058390 :                                   ApproachingVehicleInformation(arrivalTime, leaveTime, arrivalSpeed, leaveSpeed, setRequest,
     734    814029195 :                                           arrivalSpeedBraking, waitingTime, dist, approaching->getSpeed(), latOffset));
     735    814029195 : }
     736              : 
     737              : 
     738              : void
     739      1107374 : MSLink::setApproaching(const SUMOVehicle* approaching, ApproachingVehicleInformation ai) {
     740              : #ifdef DEBUG_APPROACHING
     741              :     if (DEBUG_COND2(approaching)) {
     742              :         std::cout << SIMTIME << " link=" << getDescription() << " setApproaching veh=" << approaching->getID();
     743              :         if (myApproachingVehicles.size() > 0) {
     744              :             std::cout << " curApproaching=";
     745              :             for (auto i = myApproachingVehicles.begin(); i != myApproachingVehicles.end(); ++i) {
     746              :                 std::cout << i->first->getID() << " ";
     747              :             }
     748              :         }
     749              :         std::cout << "\n";
     750              :     }
     751              : #endif
     752      1107374 :     myApproachingVehicles.emplace(approaching, ai);
     753      1107374 : }
     754              : 
     755              : void
     756       575759 : MSLink::setApproachingPerson(const MSPerson* approaching, const SUMOTime arrivalTime, const SUMOTime leaveTime) {
     757       575759 :     if (myApproachingPersons == nullptr) {
     758         1699 :         myApproachingPersons = new PersonApproachInfos();
     759              :     }
     760       575759 :     myApproachingPersons->emplace(approaching, ApproachingPersonInformation(arrivalTime, leaveTime));
     761       575759 : }
     762              : 
     763              : void
     764    810450095 : MSLink::removeApproaching(const SUMOVehicle* veh) {
     765              : #ifdef DEBUG_APPROACHING
     766              :     if (DEBUG_COND2(veh)) {
     767              :         std::cout << SIMTIME << " link=" << getDescription() << " removeApproaching veh=" << veh->getID();
     768              :         if (myApproachingVehicles.size() > 0) {
     769              :             std::cout << " curApproaching=";
     770              :             for (auto i = myApproachingVehicles.begin(); i != myApproachingVehicles.end(); ++i) {
     771              :                 std::cout << i->first->getID() << " ";
     772              :             }
     773              :         }
     774              :         std::cout << "\n";
     775              :     }
     776              : #endif
     777              :     myApproachingVehicles.erase(veh);
     778    810450095 : }
     779              : 
     780              : 
     781              : void
     782        36269 : MSLink::removeApproachingPerson(const MSPerson* person) {
     783        36269 :     if (myApproachingPersons == nullptr) {
     784           16 :         WRITE_WARNINGF("Person '%' entered crossing lane '%' without registering approach, time=%", person->getID(), myLane->getID(), time2string(SIMSTEP));
     785            4 :         return;
     786              :     }
     787              : #ifdef DEBUG_APPROACHING
     788              :     if (DEBUG_COND2(person)) {
     789              :         std::cout << SIMTIME << " Link '" << (myLaneBefore == 0 ? "NULL" : myLaneBefore->getID()) << "'->'" << (myLane == 0 ? "NULL" : myLane->getID()) << std::endl;
     790              :         std::cout << "' Removing approaching person '" << person->getID() << "'\nCurrently registered persons:" << std::endl;
     791              :         for (auto i = myApproachingPersons->begin(); i != myApproachingPersons->end(); ++i) {
     792              :             std::cout << "'" << i->first->getID() << "'" << std::endl;
     793              :         }
     794              :     }
     795              : #endif
     796              :     myApproachingPersons->erase(person);
     797              : }
     798              : 
     799              : 
     800              : MSLink::ApproachingVehicleInformation
     801     27876063 : MSLink::getApproaching(const SUMOVehicle* veh) const {
     802              :     auto i = myApproachingVehicles.find(veh);
     803     27876063 :     if (i != myApproachingVehicles.end()) {
     804     25202575 :         return i->second;
     805              :     } else {
     806              :         return ApproachingVehicleInformation(INVALID_TIME, INVALID_TIME, 0, 0, false, 0, 0, 0, 0, 0);
     807              :     }
     808              : }
     809              : 
     810              : 
     811              : const MSLink::ApproachingVehicleInformation*
     812      2346893 : MSLink::getApproachingPtr(const SUMOVehicle* veh) const {
     813              :     auto i = myApproachingVehicles.find(veh);
     814      2346893 :     if (i != myApproachingVehicles.end()) {
     815      2015950 :         return &i->second;
     816              :     } else {
     817              :         return nullptr;
     818              :     }
     819              : }
     820              : 
     821              : 
     822              : void
     823        13096 : MSLink::clearState() {
     824              :     myApproachingVehicles.clear();
     825        13096 : }
     826              : 
     827              : 
     828              : SUMOTime
     829   1447667954 : MSLink::getLeaveTime(const SUMOTime arrivalTime, const double arrivalSpeed,
     830              :                      const double leaveSpeed, const double vehicleLength) const {
     831   1477819781 :     return arrivalTime == SUMOTime_MAX ? SUMOTime_MAX : arrivalTime + TIME2STEPS((getLength() + vehicleLength) / MAX2(0.5 * (arrivalSpeed + leaveSpeed), NUMERICAL_EPS));
     832              : }
     833              : 
     834              : 
     835              : bool
     836    640913465 : MSLink::opened(SUMOTime arrivalTime, double arrivalSpeed, double leaveSpeed, double vehicleLength,
     837              :                double impatience, double decel, SUMOTime waitingTime, double posLat,
     838              :                BlockingFoes* collectFoes, bool ignoreRed, const SUMOTrafficObject* ego, double dist) const {
     839              : #ifdef MSLink_DEBUG_OPENED
     840              :     if (gDebugFlag1) {
     841              :         std::cout << SIMTIME << "  opened? link=" << getDescription() << " red=" << haveRed() << " cont=" << isCont() << " numFoeLinks=" << myFoeLinks.size() << " havePrio=" << havePriority() << " lastWasContMajorGreen=" << lastWasContState(LINKSTATE_TL_GREEN_MAJOR) << "\n";
     842              :     }
     843              : #endif
     844    640913465 :     if (haveRed() && !ignoreRed) {
     845              :         return false;
     846              :     }
     847    636755627 :     if (isCont() && MSGlobals::gUsingInternalLanes) {
     848              :         return true;
     849              :     }
     850    633238852 :     const SUMOTime leaveTime = getLeaveTime(arrivalTime, arrivalSpeed, leaveSpeed, vehicleLength);
     851    633238852 :     if (MSGlobals::gLateralResolution > 0) {
     852              :         // check for foes on the same lane with the same target edge
     853    135142990 :         for (const MSLink* foeLink : mySublaneFoeLinks) {
     854              :             assert(myLane != foeLink->getLane());
     855      9832461 :             for (const auto& it : foeLink->myApproachingVehicles) {
     856      6733617 :                 const SUMOVehicle* foe = it.first;
     857              :                 if (
     858              :                     // there only is a conflict if the paths cross
     859      7316275 :                     ((posLat < foe->getLateralPositionOnLane() + it.second.latOffset && myLane->getIndex() > foeLink->myLane->getIndex())
     860      6510235 :                      || (posLat > foe->getLateralPositionOnLane() + it.second.latOffset && myLane->getIndex() < foeLink->myLane->getIndex()))
     861              :                     // the vehicle that arrives later must yield
     862      7264296 :                     && (arrivalTime > it.second.arrivalTime
     863              :                         // if both vehicles arrive at the same time, the one
     864              :                         // to the left must yield
     865       342360 :                         || (arrivalTime == it.second.arrivalTime && posLat > foe->getLateralPositionOnLane()))) {
     866       188792 :                     if (blockedByFoe(foe, it.second, arrivalTime, leaveTime, arrivalSpeed, leaveSpeed, false,
     867              :                                      impatience, decel, waitingTime, ego)) {
     868              : #ifdef MSLink_DEBUG_OPENED
     869              :                         if (gDebugFlag1) {
     870              :                             std::cout << SIMTIME << " blocked by " << foe->getID() << " arrival=" << arrivalTime << " foeArrival=" << it.second.arrivalTime << "\n";
     871              :                         }
     872              : #endif
     873        40770 :                         if (collectFoes == nullptr) {
     874              : #ifdef MSLink_DEBUG_OPENED
     875              :                             if (gDebugFlag1) {
     876              :                                 std::cout << " link=" << getViaLaneOrLane()->getID() << " blocked by sublaneFoe=" << foe->getID() << " foeLink=" << foeLink->getViaLaneOrLane()->getID() << " posLat=" << posLat << "\n";
     877              :                             }
     878              : #endif
     879              :                             return false;
     880              :                         } else {
     881            0 :                             collectFoes->push_back(it.first);
     882              :                         }
     883              :                     }
     884              :                 }
     885              :             }
     886              :         }
     887              :         // check for foes on the same lane with a different target edge
     888              :         // (straight movers take precedence if the paths cross)
     889    132003376 :         const int lhSign = MSGlobals::gLefthand ? -1 : 1;
     890    133268316 :         for (const MSLink* foeLink : mySublaneFoeLinks2) {
     891              :             assert(myDirection != LinkDirection::STRAIGHT);
     892      5584921 :             for (const auto& it : foeLink->myApproachingVehicles) {
     893      4319981 :                 const SUMOVehicle* foe = it.first;
     894              :                 // there only is a conflict if the paths cross
     895              :                 // and if the vehicles are not currently in a car-following relationship
     896      4319981 :                 const double egoWidth = ego == nullptr ? 1.8 : ego->getVehicleType().getWidth();
     897      4319981 :                 if (!lateralOverlap(posLat, egoWidth, foe->getLateralPositionOnLane() + it.second.latOffset, foe->getVehicleType().getWidth())
     898      4319981 :                         && (((myDirection == LinkDirection::RIGHT || myDirection == LinkDirection::PARTRIGHT)
     899       473352 :                              && (posLat * lhSign > (foe->getLateralPositionOnLane() + it.second.latOffset) * lhSign))
     900       431987 :                             || ((myDirection == LinkDirection::LEFT || myDirection == LinkDirection::PARTLEFT)
     901        32795 :                                 && (posLat * lhSign < (foe->getLateralPositionOnLane() + it.second.latOffset) * lhSign)))) {
     902        75182 :                     if (blockedByFoe(foe, it.second, arrivalTime, leaveTime, arrivalSpeed, leaveSpeed, false,
     903              :                                      impatience, decel, waitingTime, ego)) {
     904              : #ifdef MSLink_DEBUG_OPENED
     905              :                         if (gDebugFlag1) {
     906              :                             std::cout << SIMTIME << " blocked by sublane foe " << foe->getID() << " arrival=" << arrivalTime << " foeArrival=" << it.second.arrivalTime << "\n";
     907              :                         }
     908              : #endif
     909         8576 :                         if (collectFoes == nullptr) {
     910              : #ifdef MSLink_DEBUG_OPENED
     911              :                             if (gDebugFlag1) {
     912              :                                 std::cout << " link=" << getViaLaneOrLane()->getID() << " blocked by sublaneFoe2=" << foe->getID() << " foeLink=" << foeLink->getViaLaneOrLane()->getID() << " posLat=" << posLat << "\n";
     913              :                             }
     914              : #endif
     915              :                             return false;
     916              :                         } else {
     917            0 :                             collectFoes->push_back(it.first);
     918              :                         }
     919              :                     }
     920              :                 }
     921              :             }
     922              :         }
     923              :     }
     924              : #ifdef MSLink_DEBUG_OPENED
     925              :     /*
     926              :     if (gDebugFlag1) {
     927              :         std::cout << SIMTIME << " isExitLinkAfterInternalJunction=" << isExitLinkAfterInternalJunction()
     928              :             << " entryLink=" << getCorrespondingEntryLink()->getDescription()
     929              :             << " entryState=" << getCorrespondingEntryLink()->getState()
     930              :             << "\n";
     931              :     }
     932              :     */
     933              : #endif
     934              :     if ((havePriority()
     935     26862376 :                 || lastWasContState(LINKSTATE_TL_GREEN_MAJOR)
     936     26561994 :                 || (isExitLinkAfterInternalJunction() && getCorrespondingEntryLink()->getState() == LINKSTATE_TL_GREEN_MAJOR))
     937    633601055 :             && myState != LINKSTATE_ZIPPER) {
     938              :         // priority usually means the link is open but there are exceptions:
     939              :         // zipper still needs to collect foes
     940              :         // sublane model could have detected a conflict
     941    605203151 :         return collectFoes == nullptr || collectFoes->size() == 0;
     942              :     }
     943     27986355 :     if (myState == LINKSTATE_ALLWAY_STOP && waitingTime < TIME2STEPS(ego == nullptr ? TS : ego->getVehicleType().getParameter().getJMParam(SUMO_ATTR_JM_ALLWAYSTOP_WAIT, TS))) {
     944              :         return false;
     945     27043895 :     } else if (myState == LINKSTATE_STOP && waitingTime < TIME2STEPS(ego == nullptr ? TS : ego->getVehicleType().getParameter().getJMParam(SUMO_ATTR_JM_STOPSIGN_WAIT, TS))) {
     946              :         return false;
     947              :     }
     948              : 
     949     27009129 :     const std::vector<MSLink*>& foeLinks = (myOffFoeLinks == nullptr || getCorrespondingEntryLink()->getState() != LINKSTATE_ALLWAY_STOP) ? myFoeLinks : *myOffFoeLinks;
     950              : #ifdef MSLink_DEBUG_OPENED
     951              :     if (gDebugFlag1) {
     952              :         std::cout << SIMTIME << " opened link=" << getViaLaneOrLane()->getID() << " foeLinks=" << foeLinks.size() << "\n";
     953              :     }
     954              : #endif
     955              : 
     956     27009129 :     if (MSGlobals::gUseMesoSim && impatience == 1 && !myLane->getEdge().isRoundabout()) {
     957              :         return true;
     958              :     }
     959     27008941 :     const bool lastWasContRed = lastWasContState(LINKSTATE_TL_RED);
     960     75312964 :     for (const MSLink* const link : foeLinks) {
     961     52713713 :         if (MSGlobals::gUseMesoSim) {
     962      1787117 :             if (link->haveRed()) {
     963        45724 :                 continue;
     964              :             }
     965              :         }
     966              : #ifdef MSLink_DEBUG_OPENED
     967              :         if (gDebugFlag1) {
     968              :             std::cout << SIMTIME << "   foeLink=" << link->getViaLaneOrLane()->getID() << " numApproaching=" << link->getApproaching().size() << "\n";
     969              :             if (link->getLane()->isCrossing()) {
     970              :                 std::cout << SIMTIME << "     approachingPersons=" << (link->myApproachingPersons == nullptr ? "NULL" : toString(link->myApproachingPersons->size())) << "\n";
     971              :             }
     972              :         }
     973              : #endif
     974     52667989 :         if (link->blockedAtTime(arrivalTime, leaveTime, arrivalSpeed, leaveSpeed, myLane == link->getLane(),
     975              :                                 impatience, decel, waitingTime, collectFoes, ego, lastWasContRed, dist)) {
     976              :             return false;
     977              :         }
     978              :     }
     979     22599251 :     if (collectFoes != nullptr && collectFoes->size() > 0) {
     980              :         return false;
     981              :     }
     982              :     return true;
     983              : }
     984              : 
     985              : 
     986              : bool
     987     52704771 : MSLink::blockedAtTime(SUMOTime arrivalTime, SUMOTime leaveTime, double arrivalSpeed, double leaveSpeed,
     988              :                       bool sameTargetLane, double impatience, double decel, SUMOTime waitingTime,
     989              :                       BlockingFoes* collectFoes, const SUMOTrafficObject* ego, bool lastWasContRed, double dist) const {
     990    199582768 :     for (const auto& it : myApproachingVehicles) {
     991              : #ifdef MSLink_DEBUG_OPENED
     992              :         if (gDebugFlag1) {
     993              :             if (ego != nullptr
     994              :                     && ego->getVehicleType().getParameter().getJMParam(SUMO_ATTR_JM_IGNORE_FOE_SPEED, 0) >= it.second.speed
     995              :                     && ego->getVehicleType().getParameter().getJMParam(SUMO_ATTR_JM_IGNORE_FOE_PROB, 0) > 0) {
     996              :                 std::stringstream stream; // to reduce output interleaving from different threads
     997              :                 stream << SIMTIME << " " << myApproachingVehicles.size() << "   foe link=" << getViaLaneOrLane()->getID()
     998              :                        << " foeVeh=" << it.first->getID() << " (below ignore speed)"
     999              :                        << " ignoreFoeProb=" << ego->getVehicleType().getParameter().getJMParam(SUMO_ATTR_JM_IGNORE_FOE_PROB, 0)
    1000              :                        << "\n";
    1001              :                 std::cout << stream.str();
    1002              :             }
    1003              :         }
    1004              : #endif
    1005    151195804 :         if (it.first != ego
    1006    151189036 :                 && (ego == nullptr
    1007    151152705 :                     || ego->getVehicleType().getParameter().getJMParam(SUMO_ATTR_JM_IGNORE_FOE_PROB, 0) == 0
    1008        22549 :                     || ego->getVehicleType().getParameter().getJMParam(SUMO_ATTR_JM_IGNORE_FOE_SPEED, 0) < it.second.speed
    1009         1701 :                     || ego->getVehicleType().getParameter().getJMParam(SUMO_ATTR_JM_IGNORE_FOE_PROB, 0) < RandHelper::rand(ego->getRNG()))
    1010    151187491 :                 && !ignoreFoe(ego, it.first)
    1011    151187249 :                 && (!lastWasContRed || it.first->getSpeed() > SUMO_const_haltingSpeed)
    1012    302367041 :                 && blockedByFoe(it.first, it.second, arrivalTime, leaveTime, arrivalSpeed, leaveSpeed, sameTargetLane,
    1013              :                                 impatience, decel, waitingTime, ego)) {
    1014     10526059 :             if (collectFoes == nullptr) {
    1015              :                 return true;
    1016              :             } else {
    1017      6208252 :                 collectFoes->push_back(it.first);
    1018              :             }
    1019              :         }
    1020              :     }
    1021     48386964 :     if (myApproachingPersons != nullptr && !haveRed()) {
    1022       887723 :         for (const auto& it : *myApproachingPersons) {
    1023              : //#ifdef MSLink_DEBUG_OPENED
    1024              : //            if (gDebugFlag1) {
    1025              : //                std::cout << SIMTIME << ": " << ego->getID() << " check person " << it.first->getID() << " aTime=" << arrivalTime << " foeATime=" << it.second.arrivalTime
    1026              : //                    << " lTime=" << leaveTime << " foeLTime=" << it.second.leavingTime
    1027              : //                    << " dist=" << dist << "\n";
    1028              : //            }
    1029              : //#endif
    1030              :             if ((ego == nullptr
    1031       195752 :                     || ego->getVehicleType().getParameter().getJMParam(SUMO_ATTR_JM_IGNORE_FOE_PROB, 0) == 0
    1032          600 :                     || ego->getVehicleType().getParameter().getJMParam(SUMO_ATTR_JM_IGNORE_FOE_SPEED, 0) < it.first->getSpeed()
    1033          600 :                     || ego->getVehicleType().getParameter().getJMParam(SUMO_ATTR_JM_IGNORE_FOE_PROB, 0) < RandHelper::rand(ego->getRNG()))
    1034       195373 :                     && !ignoreFoe(ego, it.first)
    1035       391266 :                     && !((arrivalTime > it.second.leavingTime) || (leaveTime < it.second.arrivalTime))) {
    1036       127149 :                 if (ego == nullptr) {
    1037              :                     // during insertion
    1038          146 :                     if (myJunction->getType() == SumoXMLNodeType::RAIL_CROSSING) {
    1039          146 :                         continue;
    1040              :                     } else {
    1041              :                         return true;
    1042              :                     }
    1043              :                 }
    1044              :                 // check whether braking is feasible (ego might have started to accelerate already)
    1045       127003 :                 const auto& cfm = ego->getVehicleType().getCarFollowModel();
    1046              : #ifdef MSLink_DEBUG_OPENED
    1047              :                 if (gDebugFlag1) {
    1048              :                     std::cout << SIMTIME << ": " << ego->getID() << " conflict with person " << it.first->getID() << " aTime=" << arrivalTime << " foeATime=" << it.second.arrivalTime << " dist=" << dist << " bGap=" << cfm.brakeGap(ego->getSpeed(), cfm.getMaxDecel(), 0) << "\n";
    1049              :                 }
    1050              : #endif
    1051       127003 :                 if (dist > cfm.brakeGap(ego->getSpeed(), cfm.getMaxDecel(), 0)) {
    1052              : #ifdef MSLink_DEBUG_OPENED
    1053              :                     if (gDebugFlag1) {
    1054              :                         std::cout << SIMTIME << ": " << ego->getID() << " blocked by person " << it.first->getID() << "\n";
    1055              :                     }
    1056              : #endif
    1057       116462 :                     if (collectFoes == nullptr) {
    1058              :                         return true;
    1059              :                     } else {
    1060            0 :                         collectFoes->push_back(it.first);
    1061              :                     }
    1062              :                 }
    1063              :             }
    1064              :         }
    1065              :     }
    1066              :     return false;
    1067              : }
    1068              : 
    1069              : 
    1070              : bool
    1071    151435211 : MSLink::blockedByFoe(const SUMOVehicle* veh, const ApproachingVehicleInformation& avi,
    1072              :                      SUMOTime arrivalTime, SUMOTime leaveTime, double arrivalSpeed, double leaveSpeed,
    1073              :                      bool sameTargetLane, double impatience, double decel, SUMOTime waitingTime,
    1074              :                      const SUMOTrafficObject* ego) const {
    1075              : #ifdef MSLink_DEBUG_OPENED
    1076              :     if (gDebugFlag1) {
    1077              :         std::stringstream stream; // to reduce output interleaving from different threads
    1078              :         stream << "    link=" << getDescription()
    1079              :                << " foeVeh=" << veh->getID()
    1080              :                << " req=" << avi.willPass
    1081              :                << " aT=" << avi.arrivalTime
    1082              :                << " lT=" << avi.leavingTime
    1083              :                << "\n";
    1084              :         std::cout << stream.str();
    1085              :     }
    1086              : #endif
    1087    151435211 :     if (!avi.willPass) {
    1088              :         return false;
    1089              :     }
    1090     51437426 :     if (myState == LINKSTATE_ALLWAY_STOP) {
    1091              :         assert(waitingTime > 0);
    1092              : #ifdef MSLink_DEBUG_OPENED
    1093              :         if (gDebugFlag1) {
    1094              :             std::stringstream stream; // to reduce output interleaving from different threads
    1095              :             stream << "    foeDist=" << avi.dist
    1096              :                    << " foeBGap=" << veh->getBrakeGap(false)
    1097              :                    << " foeWait=" << avi.waitingTime
    1098              :                    << " wait=" << waitingTime
    1099              :                    << "\n";
    1100              :             std::cout << stream.str();
    1101              :         }
    1102              : #endif
    1103              :         // when using actionSteps, the foe waiting time may be outdated
    1104      1323858 :         const SUMOTime actionDelta = SIMSTEP - veh->getLastActionTime();
    1105      1323858 :         if (waitingTime > avi.waitingTime + actionDelta) {
    1106              :             return false;
    1107              :         }
    1108       193867 :         if (waitingTime == (avi.waitingTime + actionDelta) && arrivalTime < avi.arrivalTime + actionDelta) {
    1109              :             return false;
    1110              :         }
    1111              :     }
    1112     50280053 :     SUMOTime foeArrivalTime = avi.arrivalTime;
    1113     50280053 :     double foeArrivalSpeedBraking = avi.arrivalSpeedBraking;
    1114     50280053 :     if (impatience > 0 && arrivalTime < avi.arrivalTime) {
    1115              : #ifdef MSLink_DEBUG_OPENED
    1116              :         gDebugFlag6 = ((ego == nullptr || ego->isSelected()) && (veh == nullptr || veh->isSelected()));
    1117              : #endif
    1118      2399252 :         const SUMOTime fatb = computeFoeArrivalTimeBraking(arrivalTime, veh, avi.arrivalTime, impatience, avi.dist, foeArrivalSpeedBraking);
    1119      2399252 :         foeArrivalTime = (SUMOTime)((1. - impatience) * (double)avi.arrivalTime + impatience * (double)fatb);
    1120              : #ifdef MSLink_DEBUG_OPENED
    1121              :         if (gDebugFlag6) {
    1122              :             std::cout << SIMTIME << " link=" << getDescription() << " ego=" << ego->getID() << " foe=" << veh->getID()
    1123              :                       << " at=" << STEPS2TIME(arrivalTime)
    1124              :                       << " fat=" << STEPS2TIME(avi.arrivalTime)
    1125              :                       << " fatb=" << STEPS2TIME(fatb)
    1126              :                       << " fat2=" << STEPS2TIME(foeArrivalTime)
    1127              :                       << "\n";
    1128              :         }
    1129              : #endif
    1130              :     }
    1131              : 
    1132              : 
    1133     50280053 :     const SUMOTime lookAhead = (myState == LINKSTATE_ZIPPER
    1134     50280053 :                                 ? myLookaheadTimeZipper
    1135              :                                 : (ego == nullptr
    1136     38967962 :                                    ? myLookaheadTime
    1137     38965211 :                                    : TIME2STEPS(ego->getVehicleType().getParameter().getJMParam(SUMO_ATTR_JM_TIMEGAP_MINOR, STEPS2TIME(myLookaheadTime)))));
    1138              :     //if (ego != 0) std::cout << SIMTIME << " ego=" << ego->getID() << " jmTimegapMinor=" << ego->getVehicleType().getParameter().getJMParam(SUMO_ATTR_JM_TIMEGAP_MINOR, -1) << " lookAhead=" << lookAhead << "\n";
    1139              : #ifdef MSLink_DEBUG_OPENED
    1140              :     if (gDebugFlag1 || gDebugFlag6) {
    1141              :         std::stringstream stream; // to reduce output interleaving from different threads
    1142              :         stream << "       imp=" << impatience << " fAT2=" << foeArrivalTime << " fASb=" << foeArrivalSpeedBraking << " lA=" << lookAhead << " egoAT=" << arrivalTime << " egoLT=" << leaveTime << " egoLS=" << leaveSpeed << "\n";
    1143              :         std::cout << stream.str();
    1144              :     }
    1145              : #endif
    1146     50280053 :     if (avi.leavingTime < arrivalTime) {
    1147              :         // ego wants to be follower
    1148     36093641 :         if (sameTargetLane && (arrivalTime - avi.leavingTime < lookAhead
    1149     16693921 :                                || unsafeMergeSpeeds(avi.leaveSpeed, arrivalSpeed,
    1150     16693921 :                                        veh->getVehicleType().getCarFollowModel().getMaxDecel(), decel))) {
    1151              : #ifdef MSLink_DEBUG_OPENED
    1152              :             if (gDebugFlag1 || gDebugFlag6) {
    1153              :                 std::cout << "      blocked (cannot follow)\n";
    1154              :             }
    1155              : #endif
    1156      3915108 :             return true;
    1157              :         }
    1158     14186412 :     } else if (foeArrivalTime > leaveTime + lookAhead) {
    1159              :         // ego wants to be leader.
    1160     12809897 :         if (sameTargetLane && unsafeMergeSpeeds(leaveSpeed, foeArrivalSpeedBraking,
    1161      5178451 :                                                 decel, veh->getVehicleType().getCarFollowModel().getMaxDecel())) {
    1162              : #ifdef MSLink_DEBUG_OPENED
    1163              :             if (gDebugFlag1 || gDebugFlag6) {
    1164              :                 std::cout << "      blocked (cannot lead)\n";
    1165              :             }
    1166              : #endif
    1167              :             return true;
    1168              :         }
    1169              :     } else {
    1170              :         // even without considering safeHeadwayTime there is already a conflict
    1171              : #ifdef MSLink_DEBUG_OPENED
    1172              :         if (gDebugFlag1 || gDebugFlag6) {
    1173              :             std::cout << "      blocked (hard conflict)\n";
    1174              :         }
    1175              : #endif
    1176              :         return true;
    1177              :     }
    1178              :     return false;
    1179              : }
    1180              : 
    1181              : 
    1182              : SUMOTime
    1183      2399252 : MSLink::computeFoeArrivalTimeBraking(SUMOTime arrivalTime, const SUMOVehicle* foe, SUMOTime foeArrivalTime, double impatience, double dist, double& fasb) {
    1184              :     // a: distance saved when foe brakes from arrivalTime to foeArrivalTime
    1185              :     // b: distance driven past foeArrivalTime
    1186              :     // m: permitted decceleration
    1187              :     // d: total deceleration until foeArrivalTime
    1188              :     // dist2: distance of foe at arrivalTime
    1189              :     // actual arrivalTime must fall on a simulation step
    1190      2399252 :     if (arrivalTime - arrivalTime % DELTA_T == foeArrivalTime - foeArrivalTime % DELTA_T) {
    1191              :         // foe enters the junction in the same step
    1192              : #ifdef MSLink_DEBUG_OPENED
    1193              :         if (gDebugFlag6) {
    1194              :             std::cout << "   foeAT before egoAT\n";
    1195              :         }
    1196              : #endif
    1197              :         return foeArrivalTime;
    1198              :     }
    1199      2064201 :     if (arrivalTime % DELTA_T > 0) {
    1200      2036360 :         arrivalTime = arrivalTime - (arrivalTime % DELTA_T) + DELTA_T;
    1201              :     }
    1202              :     //arrivalTime += DELTA_T - arrivalTime % DELTA_T;
    1203      2064201 :     const double m = foe->getVehicleType().getCarFollowModel().getMaxDecel() * impatience;
    1204      2064201 :     const double dt = STEPS2TIME(foeArrivalTime - arrivalTime);
    1205      2064201 :     const double d = dt * m;
    1206      2064201 :     const double a = dt * d / 2;
    1207      2064201 :     const double v = dist / STEPS2TIME(foeArrivalTime - SIMSTEP + DELTA_T);
    1208      2064201 :     const double dist2 = dist - v * STEPS2TIME(arrivalTime - SIMSTEP);
    1209              : #ifdef MSLink_DEBUG_OPENED
    1210              :     if (gDebugFlag6) {
    1211              :         std::cout << "   dist=" << dist << " dist2=" << dist2
    1212              :                   << " at=" << STEPS2TIME(arrivalTime)
    1213              :                   << " fat=" << STEPS2TIME(foeArrivalTime)
    1214              :                   << " dt=" << dt << " v=" << v << " m=" << m << " d=" << d << " a=" << a << "\n";
    1215              :     }
    1216              : #endif
    1217      2064201 :     if (0.5 * v * v / m <= dist2) {
    1218              : #ifdef MSLink_DEBUG_OPENED
    1219              :         if (gDebugFlag6) {
    1220              :             std::cout << "   canBrakeToStop\n";
    1221              :         }
    1222              : #endif
    1223       997563 :         fasb = 0;
    1224       997563 :         return foeArrivalTime + TIME2STEPS(30);
    1225              :     }
    1226              :     // a = b (foe reaches the original distance to the stop line)
    1227              :     // x: time driven past foeArrivalTime
    1228              :     // v: foe speed without braking
    1229              :     // v2: average foe speed after foeArrivalTime (braking continues for time x)
    1230              :     // v2 = (v - d - x * m / 2)
    1231              :     // b = v2 * x
    1232              :     // solving for x gives:
    1233      1066638 :     const double x = (sqrt(4 * (v - d) * (v - d) - 8 * m * a) * -0.5 - d + v) / m;
    1234              : 
    1235              : #ifdef MSLink_DEBUG_OPENED
    1236              :     const double x2 = (sqrt(4 * (v - d) * (v - d) - 8 * m * a) * 0.5 - d + v) / m;
    1237              :     if (gDebugFlag6 || std::isnan(x)) {
    1238              :         std::cout << SIMTIME << "   dist=" << dist << " dist2=" << dist2  << " at=" << STEPS2TIME(arrivalTime) << " m=" << m << " d=" << d << " v=" << v << " a=" << a << " x=" << x << " x2=" << x2 << "\n";
    1239              :     }
    1240              : #endif
    1241      1066638 :     fasb = v - (dt + x) * m;
    1242      1066638 :     return foeArrivalTime + TIME2STEPS(x);
    1243              : }
    1244              : 
    1245              : 
    1246              : bool
    1247       400055 : MSLink::hasApproachingFoe(SUMOTime arrivalTime, SUMOTime leaveTime, double speed, double decel) const {
    1248       412258 :     for (const MSLink* const link : myFoeLinks) {
    1249        36782 :         if (link->blockedAtTime(arrivalTime, leaveTime, speed, speed, myLane == link->getLane(), 0, decel, 0)) {
    1250              :             return true;
    1251              :         }
    1252              :     }
    1253       440654 :     for (const MSLane* const lane : myFoeLanes) {
    1254        70516 :         if (lane->getVehicleNumberWithPartials() > 0) {
    1255              :             return true;
    1256              :         }
    1257              :     }
    1258              :     return false;
    1259              : }
    1260              : 
    1261              : 
    1262              : std::pair<const SUMOVehicle*, const MSLink*>
    1263         5744 : MSLink::getFirstApproachingFoe(const MSLink* wrapAround) const {
    1264              :     double closetDist = std::numeric_limits<double>::max();
    1265              :     const SUMOVehicle* closest = nullptr;
    1266              :     const MSLink* foeLink = nullptr;
    1267        18715 :     for (MSLink* link : myFoeLinks) {
    1268        20108 :         for (const auto& it : link->myApproachingVehicles) {
    1269              :             //std::cout << " link=" << getDescription() << " foeLink_in=" << link->getLaneBefore()->getID() << " wrapAround=" << wrapAround->getDescription() << "\n";
    1270         7137 :             if (link->getLaneBefore() == wrapAround->getLaneBefore()) {
    1271          488 :                 return std::make_pair(nullptr, wrapAround);
    1272         6649 :             } else if (it.second.dist < closetDist) {
    1273              :                 closetDist = it.second.dist;
    1274         3497 :                 if (it.second.willPass) {
    1275         3221 :                     closest = it.first;
    1276              :                     foeLink = link;
    1277              :                 }
    1278              :             }
    1279              :         }
    1280              :     }
    1281              :     return std::make_pair(closest, foeLink);
    1282              : }
    1283              : 
    1284              : 
    1285              : void
    1286     49164029 : MSLink::setTLState(LinkState state, SUMOTime t) {
    1287     49164029 :     if (myState != state) {
    1288     16594353 :         myLastStateChange = t;
    1289              :     }
    1290     49164029 :     myState = state;
    1291     49164029 :     if (haveGreen()) {
    1292     11750669 :         myLastGreenState = myState;
    1293              :     }
    1294     49164029 : }
    1295              : 
    1296              : 
    1297              : void
    1298       150331 : MSLink::setTLLogic(const MSTrafficLightLogic* logic) {
    1299       150331 :     myLogic = logic;
    1300       150331 : }
    1301              : 
    1302              : 
    1303              : bool
    1304   1196577333 : MSLink::isCont() const {
    1305              :     // when a traffic light is switched off minor roads have their cont status revoked
    1306   1196577333 :     return (myState == LINKSTATE_TL_OFF_BLINKING || myState == LINKSTATE_ALLWAY_STOP || myState == LINKSTATE_STOP) ? myAmContOff : myAmCont;
    1307              : }
    1308              : 
    1309              : 
    1310              : bool
    1311     58612084 : MSLink::lastWasContMajor() const {
    1312     59113655 :     if (isExitLinkAfterInternalJunction()) {
    1313       501571 :         return myInternalLaneBefore->getIncomingLanes()[0].viaLink->lastWasContMajor();
    1314              :     }
    1315     58612084 :     if (myInternalLane == nullptr || myAmCont) {
    1316              :         return false;
    1317              :     } else {
    1318     44127160 :         MSLane* pred = myInternalLane->getLogicalPredecessorLane();
    1319     44127160 :         if (!pred->getEdge().isInternal()) {
    1320              :             return false;
    1321              :         } else {
    1322      9244807 :             const MSLane* const pred2 = pred->getLogicalPredecessorLane();
    1323              :             assert(pred2 != nullptr);
    1324      9244807 :             const MSLink* const predLink = pred2->getLinkTo(pred);
    1325              :             assert(predLink != nullptr);
    1326      9244807 :             if (predLink->havePriority()) {
    1327              :                 return true;
    1328              :             }
    1329      8654335 :             if (myHavePedestrianCrossingFoe) {
    1330       942131 :                 return predLink->getLastGreenState() == LINKSTATE_TL_GREEN_MAJOR;
    1331              :             } else {
    1332      7712204 :                 return predLink->haveYellow();
    1333              :             }
    1334              :         }
    1335              :     }
    1336              : }
    1337              : 
    1338              : 
    1339              : bool
    1340     53871317 : MSLink::lastWasContState(LinkState linkState) const {
    1341     53871317 :     if (myInternalLane == nullptr || myAmCont || myHavePedestrianCrossingFoe) {
    1342              :         return false;
    1343              :     } else {
    1344     46793391 :         MSLane* pred = myInternalLane->getLogicalPredecessorLane();
    1345     46793391 :         if (!pred->getEdge().isInternal()) {
    1346              :             return false;
    1347              :         } else {
    1348     12306356 :             const MSLane* const pred2 = pred->getLogicalPredecessorLane();
    1349              :             assert(pred2 != nullptr);
    1350     12306356 :             const MSLink* const predLink = pred2->getLinkTo(pred);
    1351              :             assert(predLink != nullptr);
    1352     12306356 :             return predLink->getState() == linkState;
    1353              :         }
    1354              :     }
    1355              : }
    1356              : 
    1357              : 
    1358              : void
    1359        81324 : MSLink::writeApproaching(OutputDevice& od, const std::string fromLaneID) const {
    1360        81324 :     if (myApproachingVehicles.size() > 0) {
    1361         9040 :         od.openTag("link");
    1362         9040 :         od.writeAttr(SUMO_ATTR_FROM, fromLaneID);
    1363         9040 :         const std::string via = getViaLane() == nullptr ? "" : getViaLane()->getID();
    1364         9040 :         od.writeAttr(SUMO_ATTR_VIA, via);
    1365        27120 :         od.writeAttr(SUMO_ATTR_TO, getLane() == nullptr ? "" : getLane()->getID());
    1366              :         std::vector<std::pair<SUMOTime, const SUMOVehicle*> > toSort; // stabilize output
    1367        19578 :         for (auto it : myApproachingVehicles) {
    1368        10538 :             toSort.push_back(std::make_pair(it.second.arrivalTime, it.first));
    1369              :         }
    1370         9040 :         std::sort(toSort.begin(), toSort.end());
    1371        19578 :         for (std::vector<std::pair<SUMOTime, const SUMOVehicle*> >::const_iterator it = toSort.begin(); it != toSort.end(); ++it) {
    1372        10538 :             od.openTag("approaching");
    1373        10538 :             const ApproachingVehicleInformation& avi = myApproachingVehicles.find(it->second)->second;
    1374        10538 :             od.writeAttr(SUMO_ATTR_ID, it->second->getID());
    1375        10538 :             od.writeAttr(SUMO_ATTR_IMPATIENCE, it->second->getImpatience());
    1376        21076 :             od.writeAttr("arrivalTime", time2string(avi.arrivalTime));
    1377        21076 :             od.writeAttr("leaveTime", time2string(avi.leavingTime));
    1378        21076 :             od.writeAttr("arrivalSpeed", toString(avi.arrivalSpeed));
    1379        21076 :             od.writeAttr("arrivalSpeedBraking", toString(avi.arrivalSpeedBraking));
    1380        21076 :             od.writeAttr("leaveSpeed", toString(avi.leaveSpeed));
    1381        21076 :             od.writeAttr("willPass", toString(avi.willPass));
    1382        21076 :             od.closeTag();
    1383              :         }
    1384         9040 :         od.closeTag();
    1385         9040 :     }
    1386        81324 : }
    1387              : 
    1388              : 
    1389              : double
    1390       921479 : MSLink::getInternalLengthsAfter() const {
    1391              :     double len = 0.;
    1392       921479 :     MSLane* lane = myInternalLane;
    1393              : 
    1394      1759070 :     while (lane != nullptr && lane->isInternal()) {
    1395       837591 :         len += lane->getLength();
    1396       837591 :         lane = lane->getLinkCont()[0]->getViaLane();
    1397              :     }
    1398       921479 :     return len;
    1399              : }
    1400              : 
    1401              : double
    1402            0 : MSLink::getInternalLengthsBefore() const {
    1403              :     double len = 0.;
    1404            0 :     const MSLane* lane = myInternalLane;
    1405              : 
    1406            0 :     while (lane != nullptr && lane->isInternal()) {
    1407            0 :         len += lane->getLength();
    1408            0 :         if (lane->getIncomingLanes().size() == 1) {
    1409            0 :             lane = lane->getIncomingLanes()[0].lane;
    1410              :         } else {
    1411              :             break;
    1412              :         }
    1413              :     }
    1414            0 :     return len;
    1415              : }
    1416              : 
    1417              : 
    1418              : double
    1419       132818 : MSLink::getLengthsBeforeCrossing(const MSLane* foeLane) const {
    1420       132818 :     MSLane* via = myInternalLane;
    1421              :     double totalDist = 0.;
    1422              :     bool foundCrossing = false;
    1423       135694 :     while (via != nullptr) {
    1424       134324 :         MSLink* link = via->getLinkCont()[0];
    1425       134324 :         double dist = link->getLengthBeforeCrossing(foeLane);
    1426       134324 :         if (dist != INVALID_DOUBLE) {
    1427              :             // found conflicting lane
    1428       131448 :             totalDist += dist;
    1429              :             foundCrossing = true;
    1430              :             break;
    1431              :         } else {
    1432         2876 :             totalDist += via->getLength();
    1433              :             via = link->getViaLane();
    1434              :         }
    1435              :     }
    1436              :     if (foundCrossing) {
    1437       131448 :         return totalDist;
    1438              :     } else {
    1439              :         return INVALID_DOUBLE;
    1440              :     }
    1441              : }
    1442              : 
    1443              : 
    1444              : double
    1445       134324 : MSLink::getLengthBeforeCrossing(const MSLane* foeLane) const {
    1446              :     int foe_ix;
    1447       805307 :     for (foe_ix = 0; foe_ix != (int)myFoeLanes.size(); ++foe_ix) {
    1448       803801 :         if (myFoeLanes[foe_ix] == foeLane) {
    1449              :             break;
    1450              :         }
    1451              :     }
    1452       134324 :     if (foe_ix == (int)myFoeLanes.size()) {
    1453              :         // no conflict with the given lane, indicate by returning -1
    1454              : #ifdef MSLink_DEBUG_CROSSING_POINTS
    1455              :         std::cout << "No crossing of lanes '" << foeLane->getID() << "' and '" << myInternalLaneBefore->getID() << "'" << std::endl;
    1456              : #endif
    1457              :         return INVALID_DOUBLE;
    1458              :     } else {
    1459              :         // found conflicting lane index
    1460       132818 :         double dist = myInternalLaneBefore->getLength() - myConflicts[foe_ix].getLengthBehindCrossing(this);
    1461       132818 :         if (dist == -10000.) {
    1462              :             // this is the value in myConflicts, if the relation allows intersection but none is present for the actual geometry.
    1463              :             return INVALID_DOUBLE;
    1464              :         }
    1465              : #ifdef MSLink_DEBUG_CROSSING_POINTS
    1466              :         std::cout << "Crossing of lanes '" << myInternalLaneBefore->getID() << "' and '" << foeLane->getID()
    1467              :                   << "' at distance " << dist << " (approach along '"
    1468              :                   <<  myInternalLaneBefore->getEntryLink()->getLaneBefore()->getID() << "')" << std::endl;
    1469              : #endif
    1470              :         return dist;
    1471              :     }
    1472              : }
    1473              : 
    1474              : 
    1475              : bool
    1476     35445602 : MSLink::isEntryLink() const {
    1477     35445602 :     if (MSGlobals::gUsingInternalLanes) {
    1478     57259720 :         return myInternalLane != nullptr && myInternalLaneBefore == nullptr;
    1479              :     } else {
    1480              :         return false;
    1481              :     }
    1482              : }
    1483              : 
    1484              : bool
    1485     17688465 : MSLink::isConflictEntryLink() const {
    1486              :     // either a non-cont entry link or the link after a cont-link
    1487     17688465 :     return !myAmCont && (isEntryLink() || (myInternalLaneBefore != nullptr && myInternalLane != nullptr));
    1488              : }
    1489              : 
    1490              : bool
    1491     87151191 : MSLink::isExitLink() const {
    1492     87151191 :     if (MSGlobals::gUsingInternalLanes) {
    1493    150387840 :         return myInternalLaneBefore != nullptr && myInternalLane == nullptr;
    1494              :     } else {
    1495              :         return false;
    1496              :     }
    1497              : }
    1498              : 
    1499              : bool
    1500    131839450 : MSLink::isExitLinkAfterInternalJunction() const {
    1501    131839450 :     if (MSGlobals::gUsingInternalLanes) {
    1502              :         return (getInternalLaneBefore() != nullptr
    1503     62935205 :                 && myInternalLaneBefore->getIncomingLanes().size() == 1
    1504    194144343 :                 && myInternalLaneBefore->getIncomingLanes().front().viaLink->isInternalJunctionLink());
    1505              :     } else {
    1506              :         return false;
    1507              :     }
    1508              : }
    1509              : 
    1510              : 
    1511              : const MSLink*
    1512       140284 : MSLink::getCorrespondingExitLink() const {
    1513       140284 :     MSLane* lane = myInternalLane;
    1514              :     const MSLink* link = this;
    1515       282298 :     while (lane != nullptr) {
    1516       142014 :         link = lane->getLinkCont()[0];
    1517              :         lane = link->getViaLane();
    1518              :     }
    1519       140284 :     return link;
    1520              : }
    1521              : 
    1522              : 
    1523              : const MSLink*
    1524    756171129 : MSLink::getCorrespondingEntryLink() const {
    1525              :     const MSLink* link = this;
    1526   1008599706 :     while (link->myLaneBefore->isInternal()) {
    1527              :         assert(myLaneBefore->getIncomingLanes().size() == 1);
    1528    252428577 :         link = link->myLaneBefore->getIncomingLanes().front().viaLink;
    1529              :     }
    1530    756171129 :     return link;
    1531              : }
    1532              : 
    1533              : 
    1534              : bool
    1535    357090834 : MSLink::isInternalJunctionLink() const {
    1536    357090834 :     return getInternalLaneBefore() != nullptr && myInternalLane != nullptr;
    1537              : }
    1538              : 
    1539              : 
    1540              : const MSLink::LinkLeaders
    1541    824815635 : MSLink::getLeaderInfo(const MSVehicle* ego, double dist, std::vector<const MSPerson*>* collectBlockers, bool isShadowLink) const {
    1542              :     LinkLeaders result;
    1543              :     // this link needs to start at an internal lane (either an exit link or between two internal lanes)
    1544              :     // or it must be queried by the pedestrian model (ego == 0)
    1545    824815635 :     if (ego != nullptr && (!fromInternalLane() || ego->getLaneChangeModel().isOpposite())) {
    1546              :         // ignore link leaders
    1547              :         return result;
    1548              :     }
    1549              :     //gDebugFlag1 = true;
    1550    273503937 :     if (gDebugFlag1) {
    1551            0 :         std::cout << SIMTIME << " getLeaderInfo link=" << getDescription() << " dist=" << dist << " isShadowLink=" << isShadowLink << "\n";
    1552              :     }
    1553    273503937 :     if (MSGlobals::gComputeLC && ego != nullptr && ego->getLane()->isNormal()) {
    1554     27122440 :         const MSLink* junctionEntry = getLaneBefore()->getEntryLink();
    1555      5958461 :         if (junctionEntry->haveRed() && !ego->ignoreRed(junctionEntry, true)
    1556              :                 // check oncoming on bidiLane during laneChanging
    1557     33076083 :                 && (!MSGlobals::gComputeLC || junctionEntry->getLaneBefore()->getBidiLane() == nullptr)) {
    1558      5916128 :             if (gDebugFlag1) {
    1559            0 :                 std::cout << "   ignore linkLeaders beyond red light\n";
    1560              :             }
    1561              :             return result;
    1562              :         }
    1563              :     }
    1564              :     // this is an exit link
    1565    267587809 :     const double extraGap = ego != nullptr ? ego->getVehicleType().getParameter().getJMParam(SUMO_ATTR_JM_EXTRA_GAP, 0) : 0;
    1566    662682388 :     for (int i = 0; i < (int)myFoeLanes.size(); ++i) {
    1567    395094582 :         const MSLane* foeLane = myFoeLanes[i];
    1568    395094582 :         const MSLink* foeExitLink = foeLane->getLinkCont()[0];
    1569              :         // distance from the querying vehicle to the crossing point with foeLane
    1570    395094582 :         double distToCrossing = dist - myConflicts[i].getLengthBehindCrossing(this);
    1571    395094582 :         const double foeDistToCrossing = foeLane->getLength() - myConflicts[i].getFoeLengthBehindCrossing(foeExitLink);
    1572    395094582 :         const bool sameTarget = (myLane == foeExitLink->getLane()) && !isInternalJunctionLink() && !foeExitLink->isInternalJunctionLink();
    1573    395094582 :         const bool sameSource = (myInternalLaneBefore != nullptr && myInternalLaneBefore->getNormalPredecessorLane() == foeLane->getNormalPredecessorLane());
    1574    395094582 :         const double crossingWidth = (sameTarget || sameSource) ? 0 : myConflicts[i].conflictSize;
    1575    395094582 :         const double foeCrossingWidth = (sameTarget || sameSource) ? 0 : myConflicts[i].getFoeConflictSize(foeExitLink);
    1576              :         // special treatment of contLane foe only applies if this lane is not a contLane or contLane follower itself
    1577    493467400 :         const bool contLane = (foeExitLink->getViaLaneOrLane()->getEdge().isInternal() && !(
    1578     98372818 :                                    isInternalJunctionLink() || isExitLinkAfterInternalJunction()));
    1579    395094582 :         if (gDebugFlag1) {
    1580              :             std::cout << " distToCrossing=" << distToCrossing << " foeLane=" << foeLane->getID() << " cWidth=" << crossingWidth
    1581            0 :                       << " ijl=" << isInternalJunctionLink() << " sT=" << sameTarget << " sS=" << sameSource
    1582            0 :                       << " lbc=" << myConflicts[i].getLengthBehindCrossing(this)
    1583            0 :                       << " flbc=" << myConflicts[i].getFoeLengthBehindCrossing(foeExitLink)
    1584              :                       << " cw=" << crossingWidth
    1585              :                       << " fcw=" << foeCrossingWidth
    1586              :                       << " contLane=" << contLane
    1587            0 :                       << " state=" << toString(myState)
    1588            0 :                       << " foeState=" << toString(foeExitLink->getState())
    1589            0 :                       << "\n";
    1590              :         }
    1591     90718792 :         if (distToCrossing + crossingWidth < 0 && !sameTarget
    1592    480660185 :                 && (ego == nullptr || !MSGlobals::gComputeLC || distToCrossing + crossingWidth + ego->getVehicleType().getLength() < 0)) {
    1593     81947574 :             if (gDebugFlag1) {
    1594            0 :                 std::cout << " ignore:egoBeyondCrossingPoint\n";
    1595              :             }
    1596     81947574 :             continue; // vehicle is behind the crossing point, continue with next foe lane
    1597              :         }
    1598              :         bool ignoreGreenCont = false;
    1599              :         bool foeIndirect = false;
    1600    313147008 :         if (contLane) {
    1601     30343534 :             const MSLink* entry = getLaneBefore()->getEntryLink();
    1602     30343534 :             const MSLink* foeEntry = foeLane->getEntryLink();
    1603     30343534 :             foeIndirect = foeEntry->myAmIndirect;
    1604     30327141 :             if (entry != nullptr && entry->haveGreen()
    1605     16880137 :                     && foeEntry != nullptr && foeEntry->haveGreen()
    1606     38237862 :                     && entry->myLaneBefore != foeEntry->myLaneBefore)  {
    1607              :                 // ignore vehicles before an internaljunction as long as they are still in green minor mode
    1608              :                 ignoreGreenCont = true;
    1609              :             }
    1610              :         }
    1611     30343534 :         if (foeIndirect && distToCrossing >= NO_INTERSECTION) {
    1612        28050 :             if (gDebugFlag1) {
    1613            0 :                 std::cout << " ignore:noIntersection\n";
    1614              :             }
    1615        28050 :             continue;
    1616              :         }
    1617              :         // it is not sufficient to return the last vehicle on the foeLane because ego might be its leader
    1618              :         // therefore we return all vehicles on the lane
    1619              :         //
    1620              :         // special care must be taken for continuation lanes. (next lane is also internal)
    1621              :         // vehicles on cont. lanes or on internal lanes with the same target as this link can not be ignored
    1622              :         // and should block (gap = -1) unless they are part of an indirect turn
    1623              :         MSLane::AnyVehicleIterator end = foeLane->anyVehiclesEnd();
    1624     26739233 :         for (MSLane::AnyVehicleIterator it_veh = foeLane->anyVehiclesBegin(); it_veh != end; ++it_veh) {
    1625     26739236 :             MSVehicle* leader = (MSVehicle*)*it_veh;
    1626     26739236 :             const double leaderBack = leader->getBackPositionOnLane(foeLane) - extraGap;
    1627     26739236 :             const double leaderBackDist = foeDistToCrossing - leaderBack;
    1628     26739236 :             const double l2 = ego != nullptr ? ego->getLength() + 2 : 0; // add some slack to account for further meeting-angle effects
    1629     26629930 :             const double sagitta = ego != nullptr && myRadius != std::numeric_limits<double>::max() ? myRadius - sqrt(myRadius * myRadius - 0.25 * l2 * l2) : 0;
    1630     26739236 :             const bool pastTheCrossingPoint = leaderBackDist + foeCrossingWidth + sagitta < 0;
    1631     26739236 :             const bool enteredTheCrossingPoint = leaderBackDist < leader->getVehicleType().getLength();
    1632     26739236 :             const bool foeIsBicycleTurn = (leader->getVehicleType().getVehicleClass() == SVC_BICYCLE
    1633     26739236 :                                            && foeLane->getIncomingLanes().front().viaLink->getDirection() == LinkDirection::LEFT);
    1634     26739236 :             const bool ignoreIndirectBicycleTurn = pastTheCrossingPoint && foeIsBicycleTurn;
    1635     26739236 :             const bool cannotIgnore = ((contLane && !ignoreIndirectBicycleTurn) || sameTarget || (sameSource && !MSGlobals::gComputeLC)) && ego != nullptr;
    1636     26739236 :             const bool inTheWay = ((((!pastTheCrossingPoint && distToCrossing > 0) || (sameTarget && distToCrossing > leaderBackDist - leader->getLength()))
    1637     21525139 :                                     && (enteredTheCrossingPoint || (sameSource && !enteredTheCrossingPoint && foeDistToCrossing < distToCrossing))
    1638     14005770 :                                     && (!foeExitLink->isInternalJunctionLink() || foeIsBicycleTurn || sameSource))
    1639     39700935 :                                    || foeExitLink->getLaneBefore()->getNormalPredecessorLane() == myLane->getBidiLane());
    1640     26739236 :             const bool isOpposite = leader->getLaneChangeModel().isOpposite();
    1641     26739236 :             const auto avi = foeExitLink->getApproaching(leader);
    1642              :             // if leader is not found, assume that it performed a lane change in the last step
    1643     26739236 :             const bool willPass = avi.willPass || (avi.arrivalTime == INVALID_TIME && sameTarget);
    1644     26739236 :             if (gDebugFlag1) {
    1645              :                 std::cout << " candidate leader=" << leader->getID()
    1646              :                           << " cannotIgnore=" << cannotIgnore
    1647              :                           << " fdtc=" << foeDistToCrossing
    1648              :                           << " lb=" << leaderBack
    1649              :                           << " lbd=" << leaderBackDist
    1650              :                           << " fcwidth=" << foeCrossingWidth
    1651            0 :                           << " r=" << myRadius
    1652              :                           << " sagitta=" << sagitta
    1653              :                           << " foePastCP=" << pastTheCrossingPoint
    1654              :                           << " foeEnteredCP=" << enteredTheCrossingPoint
    1655              :                           << " inTheWay=" << inTheWay
    1656              :                           << " willPass=" << willPass
    1657            0 :                           << " isFrontOnLane=" << leader->isFrontOnLane(foeLane)
    1658              :                           << " ignoreGreenCont=" << ignoreGreenCont
    1659              :                           << " foeIndirect=" << foeIndirect
    1660              :                           << " foeBikeTurn=" << foeIsBicycleTurn
    1661            0 :                           << " isOpposite=" << isOpposite << "\n";
    1662              :             }
    1663     26739236 :             if (leader == ego) {
    1664      6891696 :                 continue;
    1665              :             }
    1666              :             // ignore greenCont foe vehicles that are not in the way
    1667     26141822 :             if (!inTheWay && ignoreGreenCont) {
    1668         7594 :                 if (gDebugFlag1) {
    1669            0 :                     std::cout << "   ignoreGreenCont\n";
    1670              :                 }
    1671         7594 :                 continue;
    1672              :             }
    1673              :             // after entering the conflict area, ignore foe vehicles that are not in the way
    1674      3114484 :             if ((!MSGlobals::gComputeLC || (ego != nullptr && ego->getLane() == foeLane) || MSGlobals::gSublane)
    1675     24893850 :                     && distToCrossing < -POSITION_EPS && !inTheWay
    1676     26424252 :                     && (ego == nullptr || !MSGlobals::gComputeLC || distToCrossing < -ego->getVehicleType().getLength())) {
    1677       140114 :                 if (gDebugFlag1) {
    1678            0 :                     std::cout << "   ego entered conflict area\n";
    1679              :                 }
    1680       140114 :                 continue;
    1681              :             }
    1682     26070358 :             if (!MSGlobals::gComputeLC
    1683     22929350 :                     && sameSource
    1684      6866552 :                     && &ego->getLane()->getEdge() == &myInternalLaneBefore->getEdge()
    1685     26387859 :                     && leaderBack + leader->getLength() < ego->getPositionOnLane() - ego->getLength()) {
    1686              :                 // ego is already on the junction and clearly ahead of foe
    1687        76244 :                 if (gDebugFlag1) {
    1688            0 :                     std::cout << "   ego ahead of same-source foe\n";
    1689              :                 }
    1690        76244 :                 continue;
    1691              :             }
    1692              : 
    1693              :             // ignore foe vehicles that will not pass
    1694     17386830 :             if ((!cannotIgnore || leader->isStopped() || sameTarget)
    1695     17499951 :                     && !willPass
    1696      1171294 :                     && (avi.arrivalTime == INVALID_TIME || leader->getSpeed() < SUMO_const_haltingSpeed)
    1697      1171023 :                     && leader->isFrontOnLane(foeLane)
    1698              :                     && !isOpposite
    1699       602786 :                     && !inTheWay
    1700              :                     // willPass is false if the vehicle is already on the stopping edge
    1701     26362525 :                     && !leader->willStop()) {
    1702       443875 :                 if (gDebugFlag1) {
    1703            0 :                     std::cout << "   foe will not pass\n";
    1704              :                 }
    1705       443875 :                 continue;
    1706              :             }
    1707     25473995 :             if (leader->isBidiOn(foeLane)) {
    1708              :                 // conflict resolved via forward lane of the foe
    1709        46520 :                 continue;
    1710              :             }
    1711              :             // check whether foe is blocked and might need to change before leaving the junction
    1712     25427475 :             const bool foeStrategicBlocked = (leader->getLaneChangeModel().isStrategicBlocked() &&
    1713      1232254 :                                               leader->getCarFollowModel().brakeGap(leader->getSpeed()) <= foeLane->getLength() - leaderBack);
    1714     25427475 :             const bool sameInternalEdge = &myInternalLaneBefore->getEdge() == &foeExitLink->getInternalLaneBefore()->getEdge();
    1715              : 
    1716     25427475 :             const bool foeLaneIsBidi = myInternalLaneBefore->getBidiLane() == foeLane;
    1717     25427475 :             if (MSGlobals::gSublane && ego != nullptr && (sameSource || sameTarget || foeLaneIsBidi)
    1718      6738345 :                     && (!foeStrategicBlocked || sameInternalEdge)) {
    1719      6611676 :                 if (ego->getLane() == leader->getLane()) {
    1720       147008 :                     continue;
    1721              :                 }
    1722              :                 // ignore vehicles if not in conflict sublane-wise
    1723      6464668 :                 const double egoLatOffset = isShadowLink ? ego->getLatOffset(ego->getLaneChangeModel().getShadowLane()) : 0;
    1724      6464668 :                 const double posLat = ego->getLateralPositionOnLane() + egoLatOffset;
    1725      6464668 :                 double posLatLeader = leader->getLateralPositionOnLane() + leader->getLatOffset(foeLane);
    1726      6464668 :                 if (foeLaneIsBidi) {
    1727              :                     // leader is oncoming
    1728            0 :                     posLatLeader = foeLane->getWidth() - posLatLeader;
    1729              :                 }
    1730      6464668 :                 const double latGap = (fabs(posLat - posLatLeader)
    1731      6464668 :                                        - 0.5 * (ego->getVehicleType().getWidth() + leader->getVehicleType().getWidth()));
    1732      6464668 :                 const double maneuverDist = leader->getLaneChangeModel().getManeuverDist() * (posLat < posLatLeader ? -1 : 1);
    1733      6464668 :                 if (gDebugFlag1) {
    1734            0 :                     std::cout << " checkIgnore sublaneFoe lane=" << myInternalLaneBefore->getID()
    1735              :                               << " sameSource=" << sameSource
    1736              :                               << " sameTarget=" << sameTarget
    1737              :                               << " foeLaneIsBidi=" << foeLaneIsBidi
    1738              :                               << " foeLane=" << foeLane->getID()
    1739              :                               << " leader=" << leader->getID()
    1740            0 :                               << " egoLane=" << ego->getLane()->getID()
    1741            0 :                               << " leaderLane=" << leader->getLane()->getID()
    1742              :                               << " egoLat=" << posLat
    1743              :                               << " egoLatOffset=" << egoLatOffset
    1744              :                               << " leaderLat=" << posLatLeader
    1745            0 :                               << " leaderLatOffset=" << leader->getLatOffset(foeLane)
    1746              :                               << " latGap=" << latGap
    1747              :                               << " maneuverDist=" << maneuverDist
    1748            0 :                               << " computeLC=" << MSGlobals::gComputeLC
    1749            0 :                               << " egoMaxSpeedLat=" << ego->getVehicleType().getMaxSpeedLat()
    1750            0 :                               << "\n";
    1751              :                 }
    1752      1397869 :                 if (latGap > 0 && (latGap > maneuverDist || !sameTarget || !MSGlobals::gComputeLC)
    1753              :                         // do not perform sublane changes that interfere with the leader vehicle
    1754      7854487 :                         && (!MSGlobals::gComputeLC || latGap > ego->getVehicleType().getMaxSpeedLat())) {
    1755      1259990 :                     const MSLink* foeEntryLink = foeLane->getIncomingLanes().front().viaLink;
    1756      1259990 :                     if (sameSource) {
    1757              :                         // for lanes from the same edge, higer index implies a
    1758              :                         // connection further to the left
    1759       954602 :                         const bool leaderFromRight = (myIndex > foeEntryLink->getIndex());
    1760       954602 :                         if ((posLat > posLatLeader) == leaderFromRight) {
    1761              :                             // ignore speed since lanes diverge
    1762       509136 :                             if (gDebugFlag1) {
    1763            0 :                                 std::cout << "   ignored (same source) leaderFromRight=" << leaderFromRight << "\n";
    1764              :                             }
    1765       509136 :                             continue;
    1766              :                         }
    1767       305388 :                     } else if (sameTarget) {
    1768              :                         // for lanes from different edges we cannot rely on the
    1769              :                         // index due to wrap-around issues
    1770       305388 :                         if (myDirection != foeEntryLink->getDirection()) {
    1771       295206 :                             bool leaderFromRight = foeEntryLink->getDirection() < myDirection;
    1772              :                             // leader vehicle should not move towards ego
    1773       295206 :                             if (MSGlobals::gLefthand) {
    1774            0 :                                 leaderFromRight = !leaderFromRight;
    1775              :                             }
    1776       412897 :                             if ((posLat > posLatLeader) == leaderFromRight
    1777              :                                     // leader should keep lateral position or move away from ego
    1778       169974 :                                     && (leader->getLaneChangeModel().getSpeedLat() == 0
    1779        50843 :                                         || leaderFromRight == (leader->getLaneChangeModel().getSpeedLat() < latGap))
    1780       421536 :                                     && (ego->getLaneChangeModel().getSpeedLat() == 0
    1781        18058 :                                         || leaderFromRight == (ego->getLaneChangeModel().getSpeedLat() > latGap))) {
    1782       117691 :                                 if (gDebugFlag1) {
    1783            0 :                                     std::cout << "   ignored (different source) leaderFromRight=" << leaderFromRight << "\n";
    1784              :                                 }
    1785       117691 :                                 continue;
    1786              :                             }
    1787              :                         } else {
    1788              :                             // XXX figure out relative direction somehow
    1789              :                         }
    1790              :                     } else {
    1791            0 :                         if (gDebugFlag1) {
    1792            0 :                             std::cout << "   ignored oncoming bidi leader\n";
    1793              :                         }
    1794            0 :                         continue;
    1795              :                     }
    1796              :                 }
    1797              :             }
    1798     24653640 :             if (leader->getWaitingTime() < MSGlobals::gIgnoreJunctionBlocker) {
    1799              :                 // compute distance between vehicles on the superimposition of both lanes
    1800              :                 // where the crossing point is the common point
    1801              :                 double gap;
    1802              :                 bool fromLeft = true;
    1803     24219792 :                 if (ego == nullptr) {
    1804              :                     // request from pedestrian model. return distance between leaderBack and crossing point
    1805              :                     //std::cout << "   foeLane=" << foeLane->getID() << " leaderBack=" << leaderBack << " foeDistToCrossing=" << foeDistToCrossing << " foeLength=" << foeLane->getLength() << " foebehind=" << myConflicts[i].second << " dist=" << dist << " behind=" << myConflicts[i].first << "\n";
    1806       108914 :                     gap = leaderBackDist;
    1807              :                     // distToCrossing should not take into account the with of the foe lane
    1808              :                     // (which was subtracted in setRequestInformation)
    1809              :                     // Instead, the width of the foe vehicle is used directly by the caller.
    1810       108914 :                     distToCrossing += myConflicts[i].conflictSize / 2;
    1811       108914 :                     if (gap + foeCrossingWidth < 0) {
    1812              :                         // leader is completely past the crossing point
    1813              :                         // or there is no crossing point
    1814      4208686 :                         continue; // next vehicle
    1815              :                     }
    1816              :                     // we need to determine whether the vehicle passes the
    1817              :                     // crossing from the left or the right (heuristic)
    1818       107400 :                     fromLeft = foeDistToCrossing > 0.5 * foeLane->getLength();
    1819     24110878 :                 } else if ((contLane && !sameSource && !ignoreIndirectBicycleTurn) || isOpposite) {
    1820      1559849 :                     gap = -std::numeric_limits<double>::max(); // always break for vehicles which are on a continuation lane or for opposite-direction vehicles
    1821              :                 } else {
    1822     22551029 :                     if (pastTheCrossingPoint && !sameTarget) {
    1823              :                         // leader is completely past the crossing point
    1824              :                         // or there is no crossing point
    1825      4207093 :                         if (gDebugFlag1) {
    1826            0 :                             std::cout << " foePastCP ignored\n";
    1827              :                         }
    1828      4207093 :                         continue;
    1829              :                     }
    1830              :                     double leaderBackDist2 = leaderBackDist;
    1831     18343936 :                     if (sameTarget && leaderBackDist2 < 0) {
    1832      2999454 :                         const double mismatch = myConflicts[i].getFoeLengthBehindCrossing(foeExitLink) - myConflicts[i].getLengthBehindCrossing(this);
    1833      2999454 :                         if (mismatch > 0) {
    1834      1492061 :                             leaderBackDist2 += mismatch;
    1835              :                         }
    1836              :                     }
    1837     18343936 :                     if (gDebugFlag1) {
    1838              :                         std::cout << " distToCrossing=" << distToCrossing << " leaderBack=" << leaderBack
    1839              :                                   << " backDist=" << leaderBackDist
    1840              :                                   << " backDist2=" << leaderBackDist2
    1841            0 :                                   << " blockedStrategic=" << leader->getLaneChangeModel().isStrategicBlocked()
    1842            0 :                                   << "\n";
    1843              :                     }
    1844     18343936 :                     gap = distToCrossing - ego->getVehicleType().getMinGap() - leaderBackDist2 - foeCrossingWidth;
    1845              :                 }
    1846              :                 // if the foe is already moving off the intersection, we may
    1847              :                 // advance up to the crossing point unless we have the same target or same source
    1848              :                 // (for sameSource, the crossing point indicates the point of divergence)
    1849     23239317 :                 const bool stopAsap = ((leader->isFrontOnLane(foeLane) ? cannotIgnore : (sameTarget || sameSource))
    1850     20339828 :                                        || (ego != nullptr && ego->getVehicleType().getParameter().getJMParam(SUMO_ATTR_JM_ADVANCE, 1.0) == 0.0));
    1851     20011185 :                 if (gDebugFlag1) {
    1852            0 :                     std::cout << " leader=" << leader->getID() << " contLane=" << contLane << " cannotIgnore=" << cannotIgnore << " stopAsap=" << stopAsap << " gap=" << gap << "\n";
    1853              :                 }
    1854     20011185 :                 if (ignoreFoe(ego, leader)) {
    1855           79 :                     continue;
    1856              :                 }
    1857     20011106 :                 const int llFlags = ((fromLeft ? LL_FROM_LEFT : 0) |
    1858     20011106 :                                      (inTheWay ? LL_IN_THE_WAY : 0) |
    1859     20011106 :                                      (sameSource ? LL_SAME_SOURCE : 0) |
    1860     20011106 :                                      (sameTarget ? LL_SAME_TARGET : 0));
    1861     26045472 :                 result.emplace_back(leader, gap, stopAsap ? -1 : distToCrossing, llFlags, leader->getLatOffset(foeLane));
    1862              :             }
    1863              : 
    1864              :         }
    1865    313118955 :         if (ego != nullptr && MSNet::getInstance()->hasPersons()) {
    1866              :             // check for crossing pedestrians (keep driving if already on top of the crossing
    1867      6214467 :             const double distToPeds = distToCrossing - ego->getVehicleType().getParameter().getJMParam(SUMO_ATTR_JM_STOPLINE_CROSSING_GAP, MSPModel::SAFETY_GAP);
    1868      6214467 :             const double vehWidth = ego->getVehicleType().getWidth() + MSPModel::SAFETY_GAP; // + configurable safety gap
    1869              :             /// @todo consider lateral position (depending on whether the crossing is encountered on the way in or out)
    1870              :             // @check lefthand?!
    1871      6214467 :             const bool wayIn = myConflicts[i].lengthBehindCrossing < myLaneBefore->getLength() * 0.5;
    1872      6214467 :             const double vehCenter = (foeDistToCrossing + myLaneBefore->getWidth() * 0.5
    1873      6214467 :                                       + ego->getLateralPositionOnLane() * (wayIn ? -1 : 1));
    1874              :             // can access the movement model here since we already checked for existing persons above
    1875     11958332 :             if (distToPeds >= -MSPModel::SAFETY_GAP && MSNet::getInstance()->getPersonControl().getMovementModel()->blockedAtDist(ego, foeLane, vehCenter, vehWidth,
    1876      5743865 :                     ego->getVehicleType().getParameter().getJMParam(SUMO_ATTR_JM_CROSSING_GAP, JM_CROSSING_GAP_DEFAULT),
    1877              :                     collectBlockers)) {
    1878       495204 :                 result.emplace_back(nullptr, -1, distToPeds);
    1879      5719263 :             } else if (foeLane->isCrossing() && ego->getLane()->isInternal() && ego->getLane()->getEdge().getToJunction() == myJunction) {
    1880       138159 :                 const MSLink* crossingLink = foeLane->getIncomingLanes()[0].viaLink;
    1881       138159 :                 if (distToCrossing > 0 && crossingLink->havePriority() && crossingLink->myApproachingPersons != nullptr) {
    1882              :                     // a person might step on the crossing at any moment, since ego
    1883              :                     // is already on the junction, the opened() check is not done anymore
    1884        24367 :                     const double timeToEnterCrossing = distToCrossing / MAX2(ego->getSpeed(), 1.0);
    1885        29146 :                     for (const auto& item : (*crossingLink->myApproachingPersons)) {
    1886         5824 :                         if (!ignoreFoe(ego, item.first) && timeToEnterCrossing > STEPS2TIME(item.second.arrivalTime - SIMSTEP)) {
    1887         1045 :                             if (gDebugFlag1) {
    1888            0 :                                 std::cout << SIMTIME << ": " << ego->getID() << " breaking for approaching person " << item.first->getID()
    1889              :                                           //<< " dtc=" << distToCrossing << " ttc=" << distToCrossing / MAX2(ego->getSpeed(), 1.0) << " foeAT=" << item.second.arrivalTime << " foeTTC=" << STEPS2TIME(item.second.arrivalTime - SIMSTEP)
    1890            0 :                                           << "\n";
    1891              :                             }
    1892         1045 :                             result.emplace_back(nullptr, -1, distToPeds);
    1893         1045 :                             break;
    1894              :                             //} else {
    1895              :                             //    if (gDebugFlag1) {
    1896              :                             //        std::cout << SIMTIME << ": " << ego->getID() << " notBreaking for approaching person " << item.first->getID()
    1897              :                             //            << " dtc=" << distToCrossing << " ttc=" << distToCrossing / MAX2(ego->getSpeed(), 1.0) << " foeAT=" << item.second.arrivalTime << " foeTTC=" << STEPS2TIME(item.second.arrivalTime - SIMSTEP)
    1898              :                             //            << "\n";
    1899              :                             //    }
    1900              :                         }
    1901              :                     }
    1902              :                 }
    1903              :             }
    1904              :         }
    1905              :     }
    1906              : 
    1907              :     //std::cout << SIMTIME << " ego=" << Named::getIDSecure(ego) << " link=" << getViaLaneOrLane()->getID() << " myWalkingAreaFoe=" << Named::getIDSecure(myWalkingAreaFoe) << "\n";
    1908    267587806 :     if (ego != nullptr) {
    1909    266577782 :         checkWalkingAreaFoe(ego, myWalkingAreaFoe, collectBlockers, result);
    1910    266577782 :         checkWalkingAreaFoe(ego, myWalkingAreaFoeExit, collectBlockers, result);
    1911              :     }
    1912              : 
    1913    267587806 :     if (MSGlobals::gLateralResolution > 0 && ego != nullptr && !isShadowLink) {
    1914              :         // check for foes on the same edge
    1915     76584946 :         for (std::vector<MSLane*>::const_iterator it = mySublaneFoeLanes.begin(); it != mySublaneFoeLanes.end(); ++it) {
    1916     11965896 :             const MSLane* foeLane = *it;
    1917              :             MSLane::AnyVehicleIterator end = foeLane->anyVehiclesEnd();
    1918      3756431 :             for (MSLane::AnyVehicleIterator it_veh = foeLane->anyVehiclesBegin(); it_veh != end; ++it_veh) {
    1919      3756431 :                 MSVehicle* leader = (MSVehicle*)*it_veh;
    1920      3756431 :                 if (leader == ego) {
    1921      2212284 :                     continue;
    1922              :                 }
    1923      3225571 :                 if (leader->getLane()->isNormal()) {
    1924              :                     // leader is past the conflict point
    1925      1284185 :                     continue;
    1926              :                 }
    1927      1941386 :                 const double maxLength = MAX2(myInternalLaneBefore->getLength(), foeLane->getLength());
    1928      1941386 :                 const double gap = dist - maxLength - ego->getVehicleType().getMinGap() + leader->getBackPositionOnLane(foeLane) - extraGap;
    1929      1941386 :                 if (gap < -(ego->getVehicleType().getMinGap() + leader->getLength())) {
    1930              :                     // ego is ahead of leader
    1931       397239 :                     continue;
    1932              :                 }
    1933      1544147 :                 const double posLat = ego->getLateralPositionOnLane();
    1934      1544147 :                 const double posLatLeader = leader->getLateralPositionOnLane() + leader->getLatOffset(foeLane);
    1935      1544147 :                 if (gDebugFlag1) {
    1936            0 :                     std::cout << " sublaneFoe lane=" << myInternalLaneBefore->getID()
    1937              :                               << " foeLane=" << foeLane->getID()
    1938              :                               << " leader=" << leader->getID()
    1939            0 :                               << " egoLane=" << ego->getLane()->getID()
    1940            0 :                               << " leaderLane=" << leader->getLane()->getID()
    1941              :                               << " gap=" << gap
    1942              :                               << " egoLat=" << posLat
    1943              :                               << " leaderLat=" << posLatLeader
    1944            0 :                               << " leaderLatOffset=" << leader->getLatOffset(foeLane)
    1945            0 :                               << " egoIndex=" << myInternalLaneBefore->getIndex()
    1946            0 :                               << " foeIndex=" << foeLane->getIndex()
    1947            0 :                               << " dist=" << dist
    1948            0 :                               << " leaderBack=" << leader->getBackPositionOnLane(foeLane)
    1949            0 :                               << "\n";
    1950              :                 }
    1951              :                 // there only is a conflict if the paths cross
    1952       603675 :                 if ((posLat < posLatLeader && myInternalLaneBefore->getIndex() > foeLane->getIndex())
    1953      1891325 :                         || (posLat > posLatLeader && myInternalLaneBefore->getIndex() < foeLane->getIndex())) {
    1954       633505 :                     if (gDebugFlag1) {
    1955            0 :                         std::cout << SIMTIME << " blocked by " << leader->getID() << " (sublane split) foeLane=" << foeLane->getID() << "\n";
    1956              :                     }
    1957       633505 :                     if (ignoreFoe(ego, leader)) {
    1958            0 :                         continue;
    1959              :                     }
    1960       633505 :                     result.emplace_back(leader, gap, -1);
    1961              :                 }
    1962              :             }
    1963              :         }
    1964              :     }
    1965              :     return result;
    1966            3 : }
    1967              : 
    1968              : 
    1969              : void
    1970    533155564 : MSLink::checkWalkingAreaFoe(const MSVehicle* ego, const MSLane* foeLane, std::vector<const MSPerson*>* collectBlockers, LinkLeaders& result) const {
    1971    533155564 :     if (foeLane != nullptr && foeLane->getEdge().getPersons().size() > 0) {
    1972              :         // pedestrians may be on an arbitrary path across this
    1973              :         // walkingarea. make sure to keep enough distance.
    1974              :         // This is a simple but conservative solution that could be improved
    1975              :         // by ignoring pedestrians that are "obviously" not on a collision course
    1976       125256 :         double distToPeds = std::numeric_limits<double>::max();
    1977              :         assert(myInternalLaneBefore != nullptr);
    1978       125256 :         PositionVector egoPath = myInternalLaneBefore->getShape();
    1979       125256 :         if (ego->getLateralPositionOnLane() != 0) {
    1980       107046 :             egoPath.move2side((MSGlobals::gLefthand ? 1 : -1) * ego->getLateralPositionOnLane());
    1981              :         }
    1982       947785 :         for (MSTransportable* t : foeLane->getEdge().getPersons()) {
    1983       822529 :             MSPerson* p = static_cast<MSPerson*>(t);
    1984       822529 :             double dist = ego->getPosition().distanceTo2D(p->getPosition()) - p->getVehicleType().getLength();
    1985       822529 :             const bool inFront = isInFront(ego, egoPath, p->getPosition()) || isInFront(ego, egoPath, getFuturePosition(p));
    1986              :             if (inFront) {
    1987       302152 :                 dist -= MAX2(ego->getVehicleType().getMinGap(), MSPModel::SAFETY_GAP);
    1988              :             }
    1989              : #ifdef DEBUG_WALKINGAREA
    1990              :             if (ego->isSelected()) {
    1991              :                 std::cout << SIMTIME << " veh=" << ego->getID() << " ped=" << p->getID()
    1992              :                           << " pos=" << ego->getPosition() << " pedPos=" << p->getPosition()
    1993              :                           << " futurePedPos=" << getFuturePosition(p)
    1994              :                           << " rawDist=" << ego->getPosition().distanceTo2D(p->getPosition())
    1995              :                           << " inFront=" << inFront
    1996              :                           << " dist=" << dist << "\n";
    1997              :             }
    1998              : #endif
    1999       822529 :             if (dist < ego->getVehicleType().getWidth() / 2 || inFront) {
    2000       151367 :                 if (inFront) {
    2001       151076 :                     const double oncomingFactor = isOnComingPed(ego, p);
    2002       151076 :                     if (oncomingFactor > 0) {
    2003              :                         // account for pedestrian movement while closing in
    2004        53115 :                         const double timeToStop = sqrt(dist) / 2;
    2005        53115 :                         const double pedDist = p->getMaxSpeed() * MAX2(timeToStop, TS) * oncomingFactor;
    2006        53115 :                         dist = MAX2(0.0, dist - pedDist);
    2007              : #ifdef DEBUG_WALKINGAREA
    2008              :                         if (ego->isSelected()) {
    2009              :                             std::cout << "    timeToStop=" << timeToStop << " pedDist=" << pedDist << " factor=" << oncomingFactor << " dist2=" << dist << "\n";
    2010              :                         }
    2011              : #endif
    2012              :                     }
    2013              :                 }
    2014       151367 :                 if (ignoreFoe(ego, p)) {
    2015        25237 :                     continue;
    2016              :                 }
    2017       126130 :                 distToPeds = MIN2(distToPeds, dist);
    2018       126130 :                 if (collectBlockers != nullptr) {
    2019            0 :                     collectBlockers->push_back(p);
    2020              :                 }
    2021              :             }
    2022              :         }
    2023       125256 :         if (distToPeds != std::numeric_limits<double>::max()) {
    2024              :             // leave extra space in front
    2025        86654 :             result.emplace_back(nullptr, -1, distToPeds);
    2026              :         }
    2027       125256 :     }
    2028    533155564 : }
    2029              : 
    2030              : bool
    2031      1510112 : MSLink::isInFront(const MSVehicle* ego, const PositionVector& egoPath, const Position& pPos) const {
    2032      1510112 :     const double pedAngle = ego->getPosition().angleTo2D(pPos);
    2033      1510112 :     const double angleDiff = fabs(GeomHelper::angleDiff(ego->getAngle(), pedAngle));
    2034              : #ifdef DEBUG_WALKINGAREA
    2035              :     if (ego->isSelected()) {
    2036              :         std::cout << " angleDiff=" << RAD2DEG(angleDiff) << "\n";
    2037              :     }
    2038              : #endif
    2039      1510112 :     if (angleDiff < DEG2RAD(75)) {
    2040      1069647 :         return egoPath.distance2D(pPos) < ego->getVehicleType().getWidth() + MSPModel::SAFETY_GAP;
    2041              :     }
    2042              :     return false;
    2043              : }
    2044              : 
    2045              : 
    2046              : double
    2047       151076 : MSLink::isOnComingPed(const MSVehicle* ego, const MSPerson* p) const {
    2048       151076 :     const double pedToEgoAngle = p->getPosition().angleTo2D(ego->getPosition());
    2049       151076 :     const double angleDiff = fabs(GeomHelper::angleDiff(p->getAngle(), pedToEgoAngle));
    2050              : #ifdef DEBUG_WALKINGAREA
    2051              :     if (ego->isSelected()) {
    2052              :         std::cout << " ped-angleDiff=" << RAD2DEG(angleDiff) << " res=" << cos(angleDiff) << "\n";
    2053              :     }
    2054              : #endif
    2055       151076 :     if (angleDiff <= DEG2RAD(90)) {
    2056              :         ;
    2057        53115 :         return cos(angleDiff);
    2058              :     } else {
    2059              :         return 0;
    2060              :     }
    2061              : }
    2062              : 
    2063              : 
    2064              : Position
    2065       687583 : MSLink::getFuturePosition(const MSPerson* p, double timeHorizon) const {
    2066       687583 :     const double a = p->getAngle();
    2067       687583 :     const double dist = timeHorizon * p->getMaxSpeed();
    2068              : 
    2069       687583 :     const Position offset(cos(a) * dist, sin(a) * dist);
    2070       687583 :     return p->getPosition() + offset;
    2071              : }
    2072              : 
    2073              : 
    2074              : MSLink*
    2075      8908242 : MSLink::getParallelLink(int direction) const {
    2076      8908242 :     if (direction == -1) {
    2077      3550800 :         return myParallelRight;
    2078      5357442 :     } else if (direction == 1) {
    2079      5357442 :         return myParallelLeft;
    2080              :     } else {
    2081              :         assert(false || myLane->getOpposite() != nullptr);
    2082              :         return nullptr;
    2083              :     }
    2084              : }
    2085              : 
    2086              : MSLink*
    2087       169901 : MSLink::getOppositeDirectionLink() const {
    2088       169901 :     if (myLane->getOpposite() != nullptr && myLaneBefore->getOpposite() != nullptr) {
    2089        42607 :         for (MSLink* cand : myLane->getOpposite()->getLinkCont()) {
    2090        39435 :             if (cand->getLane() == myLaneBefore->getOpposite()) {
    2091              :                 return cand;
    2092              :             }
    2093              :         }
    2094              :     }
    2095              :     return nullptr;
    2096              : }
    2097              : 
    2098              : 
    2099              : MSLink*
    2100      4999558 : MSLink::computeParallelLink(int direction) {
    2101      4999558 :     const MSLane* const before = getLaneBefore()->getParallelLane(direction, false);
    2102      4999558 :     const MSLane* const after = getLane()->getParallelLane(direction, false);
    2103      4999558 :     if (before != nullptr && after != nullptr) {
    2104       848655 :         for (MSLink* const link : before->getLinkCont()) {
    2105       551294 :             if (link->getLane() == after) {
    2106              :                 return link;
    2107              :             }
    2108              :         }
    2109              :     }
    2110              :     return nullptr;
    2111              : }
    2112              : 
    2113              : 
    2114              : double
    2115      1194797 : MSLink::getZipperSpeed(const MSVehicle* ego, const double dist, double vSafe,
    2116              :                        SUMOTime arrivalTime,
    2117              :                        const BlockingFoes* foes) const {
    2118      1194797 :     if (myFoeLinks.size() == 0) {
    2119              :         // link should have LINKSTATE_MAJOR in this case
    2120              :         assert(false);
    2121              :         return vSafe;
    2122              :     }
    2123      1194797 :     const double brakeGap = ego->getCarFollowModel().brakeGap(vSafe, ego->getCarFollowModel().getMaxDecel(), TS);
    2124      1310617 :     if (dist > MAX2(myFoeVisibilityDistance, brakeGap)) {
    2125              : #ifdef DEBUG_ZIPPER
    2126              :         const SUMOTime now = MSNet::getInstance()->getCurrentTimeStep();
    2127              :         DEBUGOUT(DEBUG_COND_ZIPPER, SIMTIME << " getZipperSpeed ego=" << ego->getID()
    2128              :                  << " dist=" << dist << " bGap=" << brakeGap << " ignoring foes (arrival in " << STEPS2TIME(arrivalTime - now) << ")\n")
    2129              : #endif
    2130              :         return vSafe;
    2131              :     }
    2132              : #ifdef DEBUG_ZIPPER
    2133              :     DEBUGOUT(DEBUG_COND_ZIPPER, SIMTIME << " getZipperSpeed ego=" << ego->getID()
    2134              :              << " egoAT=" << arrivalTime
    2135              :              << " dist=" << dist
    2136              :              << " brakeGap=" << brakeGap
    2137              :              << " vSafe=" << vSafe
    2138              :              << " numFoes=" << foes->size()
    2139              :              << "\n")
    2140              : #endif
    2141              :     const bool uniqueFoeLink = myFoeLinks.size() == 1;
    2142       433506 :     MSLink* foeLink = myFoeLinks[0];
    2143      2449456 :     for (const auto& item : *foes) {
    2144      2015950 :         if (!item->isVehicle()) {
    2145            0 :             continue;
    2146              :         }
    2147      2015950 :         const MSVehicle* foe = dynamic_cast<const MSVehicle*>(item);
    2148              :         assert(foe != 0);
    2149              :         const ApproachingVehicleInformation* aviPtr = nullptr;
    2150      2015950 :         if (uniqueFoeLink) {
    2151      1357032 :             aviPtr = foeLink->getApproachingPtr(foe);
    2152              :         } else {
    2153              :             // figure out which link is approached by the current foe
    2154       989861 :             for (MSLink* fl : myFoeLinks) {
    2155       989861 :                 aviPtr = fl->getApproachingPtr(foe);
    2156       989861 :                 if (aviPtr != nullptr) {
    2157              :                     break;
    2158              :                 }
    2159              :             }
    2160              :         }
    2161      2015950 :         if (aviPtr == nullptr) {
    2162            0 :             continue;
    2163              :         }
    2164              :         const ApproachingVehicleInformation& avi = *aviPtr;
    2165      2015950 :         const double foeDist = (foe->isActive() ? avi.dist : MAX2(0.0, avi.dist -
    2166           36 :                                 STEPS2TIME(MSNet::getInstance()->getCurrentTimeStep() - foe->getLastActionTime()) * avi.speed));
    2167              : 
    2168      1365894 :         if (    // ignore vehicles that arrive after us (unless they are ahead and we could easily brake for them)
    2169      2117355 :             ((avi.arrivalTime > arrivalTime) && !couldBrakeForLeader(dist, foeDist, ego, foe)) ||
    2170              :             // also ignore vehicles that are behind us and are able to brake for us
    2171      2117355 :             couldBrakeForLeader(foeDist, dist, foe, ego) ||
    2172              :             // resolve ties by lane index
    2173       650060 :             (avi.arrivalTime == arrivalTime && foeDist == dist && ego->getLane()->getIndex() < foe->getLane()->getIndex())) {
    2174              : #ifdef DEBUG_ZIPPER
    2175              :             if (DEBUG_COND_ZIPPER) std::cout
    2176              :                         << "    ignoring foe=" << foe->getID()
    2177              :                         << " foeAT=" << avi.arrivalTime
    2178              :                         << " foeDist=" << avi.dist
    2179              :                         << " foeDist2=" << foeDist
    2180              :                         << " foeSpeed=" << avi.speed
    2181              :                         << " egoSpeed=" << ego->getSpeed()
    2182              :                         << " deltaDist=" << foeDist - dist
    2183              :                         << " delteSpeed=" << avi.speed - foe->getCarFollowModel().getMaxDecel() - ego->getSpeed()
    2184              :                         << " egoCouldBrake=" << couldBrakeForLeader(dist, foeDist, ego, foe)
    2185              :                         << " foeCouldBrake=" << couldBrakeForLeader(foeDist, dist, foe, ego)
    2186              :                         << "\n";
    2187              : #endif
    2188      1365894 :             continue;
    2189              :         }
    2190              :         // the idea behind speed adaption is three-fold:
    2191              :         // 1) ego needs to be in a car-following relationship with foe eventually
    2192              :         //    thus, the ego speed should be equal to the follow speed once the foe enters
    2193              :         //    the zipper junction
    2194              :         // 2) ego vehicle needs to put a certain distance beteen himself and foe (safeGap)
    2195              :         //    achieving this distance can be spread over time but computing
    2196              :         //    safeGap is subject to estimation errors of future speeds
    2197              :         // 3) deceleration can be spread out over the time until true
    2198              :         //    car-following happens, at the start of speed adaptions, smaller
    2199              :         //    decelerations should be sufficient
    2200              : 
    2201              :         // we cannot trust avi.arrivalSpeed if the foe has leader vehicles that are accelerating
    2202              :         // lets try to extrapolate
    2203       650056 :         const double uMax = foe->getLane()->getVehicleMaxSpeed(foe);
    2204       650056 :         const double uAccel = foe->getCarFollowModel().estimateSpeedAfterDistance(foeDist, avi.speed, foe->getCarFollowModel().getMaxAccel());
    2205              :         const double uEnd = MIN2(uMax, uAccel);
    2206       650056 :         const double uAvg = (avi.speed + uEnd) / 2;
    2207       650056 :         const double tf0 = foeDist / MAX2(NUMERICAL_EPS, uAvg);
    2208       650056 :         const double tf = MAX2(1.0, ceil((tf0) / TS) * TS);
    2209              : 
    2210       650056 :         const double vMax = ego->getLane()->getVehicleMaxSpeed(ego);
    2211       650056 :         const double vAccel = ego->getCarFollowModel().estimateSpeedAfterDistance(dist, ego->getSpeed(), ego->getCarFollowModel().getMaxAccel());
    2212       650056 :         const double vDecel = ego->getCarFollowModel().estimateSpeedAfterDistance(dist, ego->getSpeed(), -ego->getCarFollowModel().getMaxDecel());
    2213              :         const double vEnd = MIN3(vMax, vAccel, MAX2(uEnd, vDecel));
    2214       650056 :         const double vAvg = (ego->getSpeed() + vEnd) / 2;
    2215       650056 :         const double te0 = dist / MAX2(NUMERICAL_EPS, vAvg);
    2216       650056 :         const double te = MAX2(1.0, ceil((te0) / TS) * TS);
    2217              : 
    2218       650056 :         const double tTarget = tf + ego->getCarFollowModel().getHeadwayTime();
    2219       650056 :         const double a = ego->getCarFollowModel().avoidArrivalAccel(dist, tTarget, vSafe, ego->getCarFollowModel().getMaxDecel());
    2220              : 
    2221       650056 :         const double gap = dist - foe->getVehicleType().getLength() - ego->getVehicleType().getMinGap() - foeDist;
    2222       650056 :         const double vFollow = ego->getCarFollowModel().followSpeed(
    2223       650056 :                                    ego, ego->getSpeed(), gap, avi.speed, foe->getCarFollowModel().getMaxDecel(), foe);
    2224       650056 :         const double vSafeGap = MAX2(vFollow, ego->getSpeed() + ACCEL2SPEED(a));
    2225              : 
    2226              :         // scale behavior based on ego time to link (te)
    2227       650056 :         const double w = MIN2(1.0, te / 10);
    2228       650056 :         const double maxDecel = w * ego->getCarFollowModel().getMaxDecel() + (1 - w) * ego->getCarFollowModel().getEmergencyDecel();
    2229       650056 :         const double vZipper = MAX3(vFollow, ego->getSpeed() - ACCEL2SPEED(maxDecel), vSafeGap);
    2230              : 
    2231              :         vSafe = MIN2(vSafe, vZipper);
    2232              : #ifdef DEBUG_ZIPPER
    2233              :         if (DEBUG_COND_ZIPPER) std::cout << "    adapting to foe=" << foe->getID()
    2234              :                                              << " foeDist=" << foeDist
    2235              :                                              << " foeSpeed=" << avi.speed
    2236              :                                              << " foeAS=" << avi.arrivalSpeed
    2237              :                                              << " egoSpeed=" << ego->getSpeed()
    2238              :                                              << " uMax=" << uMax
    2239              :                                              << " uAccel=" << uAccel
    2240              :                                              << " uEnd=" << uEnd
    2241              :                                              << " uAvg=" << uAvg
    2242              :                                              << " gap=" << gap
    2243              :                                              << "\n      "
    2244              :                                              << " tf=" << tf
    2245              :                                              << " te=" << te
    2246              :                                              << " aSafeGap=" << a
    2247              :                                              << " vMax=" << vMax
    2248              :                                              << " vAccel=" << vAccel
    2249              :                                              << " vDecel=" << vDecel
    2250              :                                              << " vEnd=" << vEnd
    2251              :                                              << " vSafeGap=" << vSafeGap
    2252              :                                              << " vFollow=" << vFollow
    2253              :                                              << " w=" << w
    2254              :                                              << " maxDecel=" << maxDecel
    2255              :                                              << " vZipper=" << vZipper
    2256              :                                              << " vSafe=" << vSafe
    2257              :                                              << "\n";
    2258              : #endif
    2259              :     }
    2260              :     return vSafe;
    2261              : }
    2262              : 
    2263              : 
    2264              : bool
    2265      2117355 : MSLink::couldBrakeForLeader(double followDist, double leaderDist, const MSVehicle* follow, const MSVehicle* leader) {
    2266              :     return (// leader is ahead of follower
    2267      2117355 :                followDist > leaderDist &&
    2268              :                // and follower could brake for 1 s to stay behind leader
    2269       395601 :                followDist - leaderDist > follow->getSpeed() - follow->getCarFollowModel().getMaxDecel() - leader->getSpeed());
    2270              : }
    2271              : 
    2272              : 
    2273              : void
    2274      2499779 : MSLink::initParallelLinks() {
    2275      2499779 :     myParallelRight = computeParallelLink(-1);
    2276      2499779 :     myParallelLeft = computeParallelLink(1);
    2277      2499779 : }
    2278              : 
    2279              : bool
    2280        66595 : MSLink::checkContOff() const {
    2281              :     // check whether this link gets to keep its cont status switching the tls off
    2282              :     // @note: this could also be pre-computed in netconvert
    2283              :     // we check whether there is any major link from this edge
    2284       201530 :     for (const MSLane* cand : myLaneBefore->getEdge().getLanes()) {
    2285       399415 :         for (const MSLink* link : cand->getLinkCont()) {
    2286       264480 :             if (link->getOffState() == LINKSTATE_TL_OFF_NOSIGNAL) {
    2287              :                 return true;
    2288              :             }
    2289              :         }
    2290              :     }
    2291              :     return false;
    2292              : }
    2293              : 
    2294              : bool
    2295      4319981 : MSLink::lateralOverlap(double posLat, double width, double posLat2, double width2) {
    2296      4319981 :     return fabs(posLat2 - posLat) < (width + width2) / 2;
    2297              : }
    2298              : 
    2299              : std::string
    2300            0 : MSLink::getDescription() const {
    2301            0 :     return myLaneBefore->getID() + "->" + getViaLaneOrLane()->getID();
    2302              : }
    2303              : 
    2304              : 
    2305              : bool
    2306    172679979 : MSLink::ignoreFoe(const SUMOTrafficObject* ego, const SUMOTrafficObject* foe) {
    2307    172679979 :     if (ego == nullptr || !ego->getParameter().wasSet(VEHPARS_JUNCTIONMODEL_PARAMS_SET)) {
    2308    172647540 :         return false;
    2309              :     }
    2310        32439 :     const SUMOVehicleParameter& param = ego->getParameter();
    2311        71050 :     for (const std::string& typeID : StringTokenizer(param.getParameter(toString(SUMO_ATTR_JM_IGNORE_TYPES), "")).getVector()) {
    2312        31537 :         if (typeID == foe->getVehicleType().getID()) {
    2313              :             return true;
    2314              :         }
    2315        32439 :     }
    2316        16136 :     for (const std::string& id : StringTokenizer(param.getParameter(toString(SUMO_ATTR_JM_IGNORE_IDS), "")).getVector()) {
    2317         2291 :         if (id == foe->getID()) {
    2318              :             return true;
    2319              :         }
    2320         7074 :     }
    2321         6771 :     return false;
    2322              : }
    2323              : 
    2324              : 
    2325              : void
    2326        93141 : MSLink::updateDistToFoePedCrossing(double dist) {
    2327        93141 :     myDistToFoePedCrossing = MIN2(myDistToFoePedCrossing, dist);
    2328        93141 : }
    2329              : 
    2330              : 
    2331              : std::pair<const SUMOVehicle* const, const MSLink::ApproachingVehicleInformation>
    2332      3861740 : MSLink::getClosest() const {
    2333              :     assert(getApproaching().size() > 0);
    2334              :     double minDist = std::numeric_limits<double>::max();
    2335              :     auto closestIt = getApproaching().begin();
    2336      7724134 :     for (auto apprIt = getApproaching().begin(); apprIt != getApproaching().end(); apprIt++) {
    2337      3862394 :         if (apprIt->second.dist < minDist) {
    2338              :             minDist = apprIt->second.dist;
    2339              :             closestIt = apprIt;
    2340              :         }
    2341              :     }
    2342              :     // maybe a parallel link has a closer vehicle
    2343              :     /*
    2344              :     for (MSLink* link2 : link->getLaneBefore()->getLinkCont()) {
    2345              :         if (link2 != link) {
    2346              :             for (auto apprIt2 = link2->getApproaching().begin(); apprIt2 != link2->getApproaching().end(); apprIt2++) {
    2347              :                 if (apprIt2->second.dist < minDist) {
    2348              :                     minDist = apprIt2->second.dist;
    2349              :                     closestIt = apprIt2;
    2350              :                 }
    2351              :             }
    2352              :         }
    2353              :     }
    2354              :     */
    2355      3861740 :     return *closestIt;
    2356              : }
    2357              : 
    2358              : 
    2359              : bool
    2360       392287 : MSLink::railSignalWasPassed() const {
    2361       392287 :     if (myJunction != nullptr && myJunction->getType() == SumoXMLNodeType::RAIL_SIGNAL) {
    2362         1832 :         for (const auto& item : myApproachingVehicles) {
    2363            9 :             if (item.second.dist < SPEED2DIST(item.first->getSpeed())) {
    2364              :                 return true;
    2365              :             }
    2366              :         }
    2367              :     }
    2368              :     return false;
    2369              : }
    2370              : 
    2371              : /****************************************************************************/
        

Generated by: LCOV version 2.0-1