LCOV - code coverage report
Current view: top level - src/microsim - MSLink.cpp (source / functions) Coverage Total Hit
Test: lcov.info Lines: 92.2 % 945 871
Test Date: 2026-06-15 15:46:12 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-2026 German Aerospace Center (DLR) and others.
       4              : // This program and the accompanying materials are made available under the
       5              : // terms of the Eclipse Public License 2.0 which is available at
       6              : // https://www.eclipse.org/legal/epl-2.0/
       7              : // This Source Code may also be made available under the following Secondary
       8              : // Licenses when the conditions for such availability set forth in the Eclipse
       9              : // Public License 2.0 are satisfied: GNU General Public License, version 2
      10              : // or later which is available at
      11              : // https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html
      12              : // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
      13              : /****************************************************************************/
      14              : /// @file    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    483299189 : MSLink::ConflictInfo::getFoeLengthBehindCrossing(const MSLink* foeExitLink) const {
      84    483299189 :     if (flag == CONFLICT_DUMMY_MERGE) {
      85              :         return 0;
      86    473413103 :     } else if (foeConflictIndex >= 0) {
      87    451494316 :         return foeExitLink->myConflicts[foeConflictIndex].lengthBehindCrossing;
      88              :     } else {
      89              :         return -NO_INTERSECTION;
      90              :     }
      91              : }
      92              : 
      93              : double
      94    249848650 : MSLink::ConflictInfo::getFoeConflictSize(const MSLink* foeExitLink) const {
      95    249848650 :     if (foeConflictIndex >= 0) {
      96    227999055 :         return foeExitLink->myConflicts[foeConflictIndex].conflictSize;
      97              :     } else {
      98              :         return 0;
      99              :     }
     100              : }
     101              : 
     102              : double
     103    483428595 : MSLink::ConflictInfo::getLengthBehindCrossing(const MSLink* exitLink) const {
     104    483428595 :     if (flag == CONFLICT_STOP_AT_INTERNAL_JUNCTION) {
     105     20160019 :         return exitLink->getInternalLaneBefore()->getLength();
     106              :     } else {
     107    463268576 :         return lengthBehindCrossing;
     108              :     }
     109              : }
     110              : 
     111              : // ===========================================================================
     112              : // member method definitions
     113              : // ===========================================================================
     114      2936198 : 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      2936198 :                bool indirect) :
     118      2936198 :     myLane(succLane),
     119      2936198 :     myLaneBefore(predLane),
     120      2936198 :     myApproachingPersons(nullptr),
     121      2936198 :     myIndex(-1),
     122      2936198 :     myTLIndex(tlIndex),
     123      2936198 :     myLogic(logic),
     124      2936198 :     myState(state),
     125      2936198 :     myLastGreenState(LINKSTATE_TL_GREEN_MINOR),
     126      2936198 :     myOffState(state),
     127      2936198 :     myLastStateChange(SUMOTime_MIN / 2), // a large negative value, but avoid overflows when subtracting
     128      2936198 :     myDirection(dir),
     129      2936198 :     myLength(length),
     130      2936198 :     myFoeVisibilityDistance(foeVisibilityDistance),
     131      2936198 :     myDistToFoePedCrossing(std::numeric_limits<double>::max()),
     132      2936198 :     myHasFoes(false),
     133      2936198 :     myAmCont(false),
     134      2936198 :     myAmContOff(false),
     135      2936198 :     myKeepClear(keepClear),
     136      2936198 :     myInternalLane(via),
     137      2936198 :     myInternalLaneBefore(nullptr),
     138      2936198 :     myMesoTLSPenalty(0),
     139      2936198 :     myGreenFraction(1),
     140      2936198 :     myLateralShift(0),
     141      2936198 :     myOffFoeLinks(nullptr),
     142      2936198 :     myWalkingAreaFoe(nullptr),
     143      2936198 :     myWalkingAreaFoeExit(nullptr),
     144      2936198 :     myHavePedestrianCrossingFoe(false),
     145      2936198 :     myParallelRight(nullptr),
     146      2936198 :     myParallelLeft(nullptr),
     147      2936198 :     myAmIndirect(indirect),
     148      2936198 :     myRadius(std::numeric_limits<double>::max()),
     149      2936198 :     myPermissions(myLaneBefore->getPermissions() & myLane->getPermissions() & (via == nullptr ? SVCAll : via->getPermissions())),
     150      2936198 :     myJunction(nullptr) {
     151              : 
     152      2936198 :     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       205427 :         if ((myInternalLane != nullptr || predLane->isInternal())
     156       512901 :                 && 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          652 :                 from.move2side(dist);
     163            0 :             } catch (InvalidArgument&) {
     164            0 :             }
     165          652 :             myLateralShift = (from.back().distanceTo2D(to.front()) < dist) ? dist : -dist;
     166          652 :             if (MSGlobals::gLefthand) {
     167           90 :                 myLateralShift *= -1;
     168              :             }
     169              :             //std::cout << " lateral shift link=" << myLaneBefore->getID() << "->" << getViaLaneOrLane()->getID() << " dist=" << dist << " shift=" << myLateralShift << "\n";
     170          652 :         }
     171              :     }
     172      2936198 : }
     173              : 
     174              : 
     175      2908923 : MSLink::~MSLink() {
     176      2908923 :     delete myOffFoeLinks;
     177      2910265 :     delete myApproachingPersons;
     178      2908923 : }
     179              : 
     180              : 
     181              : void
     182            6 : MSLink::addCustomConflict(const MSLane* from, const MSLane* to, double startPos, double endPos) {
     183            6 :     myCustomConflicts.push_back(CustomConflict(from, to, startPos, endPos));
     184            6 : }
     185              : 
     186              : const MSLink::CustomConflict*
     187      4070634 : MSLink::getCustomConflict(const MSLane* foeLane) const {
     188      4070634 :     if (myCustomConflicts.size() > 0) {
     189           24 :         const MSLane* foeFrom = foeLane->getNormalPredecessorLane();
     190           24 :         const MSLane* foeTo = foeLane->getNormalSuccessorLane();
     191           36 :         for (const CustomConflict& cc : myCustomConflicts) {
     192           24 :             if (cc.from == foeFrom && cc.to == foeTo) {
     193              :                 return &cc;
     194              :             }
     195              :         }
     196              : 
     197              :     }
     198              :     return nullptr;
     199              : }
     200              : 
     201              : void
     202      2656389 : 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      2656389 :     myIndex = index;
     212      2656389 :     myHasFoes = hasFoes;
     213      2656389 :     myAmCont = isCont && MSGlobals::gUsingInternalLanes;
     214      2656389 :     myFoeLinks = foeLinks;
     215     10148677 :     for (MSLane* foeLane : foeLanes) {
     216              :         // cannot assign vector due to const-ness
     217      7492288 :         myFoeLanes.push_back(foeLane);
     218              :     }
     219      2656389 :     myJunction = const_cast<MSJunction*>(myLane->getEdge().getFromJunction()); // junctionGraph is initialized after the whole network is loaded
     220      2656389 :     myAmContOff = isCont && myLogic != nullptr && internalLaneBefore == nullptr && checkContOff();
     221      2656389 :     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->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      2656389 :     const MSLink* entryLink = getCorrespondingEntryLink();
     232      2656389 :     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         5762 :         myOffFoeLinks = new std::vector<MSLink*>();
     236         5762 :         if (isEntryLink()) {
     237        15648 :             for (MSLane* foeLane : foeLanes) {
     238              :                 assert(foeLane->isInternal() || foeLane->isCrossing());
     239        13140 :                 MSLink* viaLink = foeLane->getIncomingLanes().front().viaLink;
     240        13140 :                 if (viaLink->getLaneBefore()->isNormal()) {
     241         7960 :                     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      2656389 :     if (lane != nullptr) {
     250      1035473 :         const bool beforeInternalJunction = lane->getLinkCont()[0]->getViaLaneOrLane()->getEdge().isInternal();
     251      1035473 :         if (lane->getIncomingLanes().size() != 1) {
     252            0 :             throw ProcessError(TLF("Internal lane '%' has % predecessors", lane->getID(), toString(lane->getIncomingLanes().size())));
     253              :         }
     254      1035473 :         const MSLink* junctionEntryLink = lane->getEntryLink();
     255      1035473 :         const bool isSecondPart = isExitLinkAfterInternalJunction();
     256              :         // compute crossing points
     257      5266220 :         for (const MSLane* foeLane : myFoeLanes) {
     258      4230747 :             const CustomConflict* cc = junctionEntryLink != nullptr ? junctionEntryLink->getCustomConflict(foeLane) : nullptr;
     259      4070622 :             if (cc != nullptr) {
     260              :                 // handle custom conflict definition
     261           12 :                 double startPos = cc->startPos;
     262           12 :                 const double conflictSize = cc->endPos - cc->startPos;
     263           12 :                 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           12 :                 const CustomConflict* rcc = foeLane->getEntryLink()->getCustomConflict(lane);
     275              :                 bool haveIntersection = false;
     276           12 :                 if (rcc == nullptr) {
     277              :                     // a)
     278           12 :                     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           12 :                 if (haveIntersection) {
     292            6 :                     myConflicts.push_back(ConflictInfo(lane->getLength() - startPos, conflictSize));
     293              :                 } else {
     294            6 :                     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           12 :                 continue;
     304           12 :             }
     305      4230735 :             myHavePedestrianCrossingFoe = myHavePedestrianCrossingFoe || foeLane->isCrossing();
     306      4230735 :             const bool sameTarget = myLane == foeLane->getLinkCont()[0]->getLane();
     307      4230735 :             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      1424631 :                 const double minDist = MIN2(DIVERGENCE_MIN_WIDTH, 0.5 * (lane->getWidth() + foeLane->getWidth()));
     311      1424631 :                 if (lane->getShape().back().distanceTo2D(foeLane->getShape().back()) >= minDist) {
     312              :                     // account for lateral shift by the entry links
     313       127623 :                     if (foeLane->getEntryLink()->isIndirect()) {
     314           39 :                         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       127584 :                         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      1297008 :                     const double distAfterDivergence = computeDistToDivergence(lane, foeLane, minDist, false);
     326              :                     const double lbcLane = lane->interpolateGeometryPosToLanePos(distAfterDivergence);
     327      1297008 :                     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      2806104 :                 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      2806104 :                 if (intersections1.size() == 0) {
     344      1453987 :                     intersections1.push_back(-NO_INTERSECTION); // disregard this foe (using maxdouble leads to nasty problems down the line)
     345              :                     haveIntersection = false;
     346      1352117 :                 } else if (intersections1.size() > 1) {
     347         1296 :                     std::sort(intersections1.begin(), intersections1.end());
     348              :                 }
     349      2806104 :                 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      2806104 :                 if (intersections2.size() == 0) {
     354      1453987 :                     intersections2.push_back(0);
     355      1352117 :                 } else if (intersections2.size() > 1) {
     356         1296 :                     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      2806104 :                 if (!haveIntersection && foeLane->getLinkCont()[0]->getViaLane() != nullptr) {
     361       256033 :                     const Position waitPos = foeLane->getShape().back();
     362       256033 :                     const double dist = lane->getShape().distance2D(waitPos, true);
     363       256033 :                     if (dist != GeomHelper::INVALID_OFFSET && dist < lane->getWidth() / 2) {
     364              :                         // risk of collision
     365              :                         intersections1.clear();
     366              :                         intersections2.clear();
     367        30039 :                         intersections1.push_back(lane->getShape().nearest_offset_to_point2D(waitPos));
     368        30039 :                         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      2776065 :                 if (haveIntersection) {
     379              :                     flag = CONFLICT_DEFAULT;
     380      1382156 :                     const double angle1 = GeomHelper::naviDegree(lane->getShape().rotationAtOffset(intersections1.back()));
     381      1382156 :                     const double angle2 = GeomHelper::naviDegree(foeLane->getShape().rotationAtOffset(intersections2.back()));
     382      1382156 :                     const double angleDiff = GeomHelper::getMinAngleDiff(angle1, angle2);
     383              :                     //const double angleDiff = MIN2(GeomHelper::getMinAngleDiff(angle1, angle2),
     384              :                     //                              GeomHelper::getMinAngleDiff(angle1, angle2 + 180));
     385      1382156 :                     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      1382156 :                     conflictSize *= widthFactor;
     388              :                     conflictSize = MIN2(conflictSize, lane->getLength());
     389              :                     // lane width affects the crossing point
     390      1382156 :                     intersections1.back() -= conflictSize / 2;
     391              :                     // ensure non-negative offset for weird geometries
     392      1382156 :                     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      1382156 :                     intersections1.back() = lane->interpolateGeometryPosToLanePos(intersections1.back());
     396              : 
     397      1382156 :                     if (internalLaneBefore->getLogicalPredecessorLane()->getEdge().isInternal() && !foeLane->isCrossing())  {
     398              :                         flag = CONFLICT_STOP_AT_INTERNAL_JUNCTION;
     399              :                     }
     400              : 
     401      1382156 :                     if (foeLane->isCrossing()) {
     402       112041 :                         const MSLink* before = myInternalLaneBefore->getCanonicalPredecessorLane()->getLinkTo(myInternalLaneBefore);
     403       112041 :                         const_cast<MSLink*>(before)->updateDistToFoePedCrossing(intersections1.back());
     404              :                     };
     405              :                 }
     406              : 
     407      2806104 :                 myConflicts.push_back(ConflictInfo(
     408      2806104 :                                           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      2806104 :             }
     422              :         }
     423              :         // check for overlap with internal lanes from the same source lane
     424      1035473 :         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      3386641 :         for (const MSLink* const link : pred->getLinkCont()) {
     428      2351168 :             const MSLane* const sibling = link->getViaLane();
     429      2351168 :             if (sibling != lane && sibling != nullptr) {
     430      1290764 :                 const double minDist = MIN2(DIVERGENCE_MIN_WIDTH, 0.5 * (lane->getWidth() + sibling->getWidth()));
     431      1290764 :                 if (lane->getShape().front().distanceTo2D(sibling->getShape().front()) >= minDist) {
     432              :                     // account for lateral shift by the entry links
     433          630 :                     continue;
     434              :                 }
     435      1290134 :                 const double distToDivergence = computeDistToDivergence(lane, sibling, minDist, true);
     436              :                 double lbcLane;
     437      1290134 :                 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        18190 :                     lbcLane = lane->getLength() - distToDivergence;
     442              :                 } else {
     443      1271944 :                     lbcLane = MAX2(0.0, lane->getLength() - lane->interpolateGeometryPosToLanePos(distToDivergence));
     444              :                 }
     445              :                 ConflictInfo ci = ConflictInfo(lbcLane, sibling->getWidth());
     446      1290134 :                 auto it = std::find(myFoeLanes.begin(), myFoeLanes.end(), sibling);
     447      1290134 :                 if (it != myFoeLanes.end()) {
     448              :                     // avoid duplicate foeLane
     449           86 :                     const int replacedIndex = (int)(it - myFoeLanes.begin());
     450           86 :                     myConflicts[replacedIndex] = ci;
     451              :                 } else {
     452      1290048 :                     myConflicts.push_back(ci);
     453      1290048 :                     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      1290134 :                 const MSLane* const siblingCont = sibling->getLinkCont().front()->getViaLaneOrLane();
     461      1290134 :                 if (siblingCont->isInternal() && lane->getShape().distance2D(siblingCont->getShape().front()) < minDist) {
     462              :                     // there may still be overlap with siblingCont (when considering vehicle widths)
     463       291808 :                     const double distToDivergence2 = computeDistToDivergence(lane, siblingCont, minDist, true, sibling->getLength());
     464       291808 :                     double lbcLane2 = MAX2(0.0, lane->getLength() - lane->interpolateGeometryPosToLanePos(distToDivergence2));
     465              :                     ConflictInfo ci2 = ConflictInfo(lbcLane2, siblingCont->getWidth(), CONFLICT_SIBLING_CONTINUATION);
     466       291808 :                     myConflicts.push_back(ci2);
     467       291808 :                     myFoeLanes.push_back(siblingCont);
     468       291808 :                     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      6848076 :         for (int i = 0; i < (int)myFoeLanes.size(); i++) {
     481      5812603 :             const MSLane* foeLane = myFoeLanes[i];
     482      5812603 :             MSLink* foeExitLink = foeLane->getLinkCont()[0];
     483              :             int foundIndex = -1;
     484     21764021 :             for (int i2 = 0; i2 < (int)foeExitLink->myFoeLanes.size(); i2++) {
     485     18453566 :                 if (foeExitLink->myFoeLanes[i2] == lane) {
     486      2502148 :                     myConflicts[i].foeConflictIndex = i2;
     487      2502148 :                     foeExitLink->myConflicts[i2].foeConflictIndex = i;
     488      2502148 :                     myRecheck.erase({foeExitLink, this});
     489              :                     foundIndex = i2;
     490      2502148 :                     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      5812603 :             if (foundIndex < 0) {
     497      3310455 :                 if (myConflicts[i].flag != CONFLICT_NO_INTERSECTION) {
     498      2411568 :                     myRecheck.insert({this, foeExitLink});
     499              :                 }
     500              :             }
     501              :         }
     502              :     }
     503      2656389 :     if (MSGlobals::gLateralResolution > 0) {
     504              :         // check for links with the same origin lane and the same destination edge
     505       295658 :         const MSEdge* myTarget = &myLane->getEdge();
     506              :         // save foes for entry links
     507       934420 :         for (MSLink* const it : myLaneBefore->getLinkCont()) {
     508              :             const MSEdge* target = &(it->getLane()->getEdge());
     509       638762 :             if (it == this) {
     510       295658 :                 continue;
     511              :             }
     512       343104 :             if (target == myTarget) {
     513         6788 :                 mySublaneFoeLinks.push_back(it);
     514              : #ifdef MSLink_DEBUG_CROSSING_POINTS
     515              :                 std::cout << "  sublaneFoeLink (same target): " << it->getViaLaneOrLane()->getID() << "\n";
     516              : #endif
     517       336316 :             } else if (myDirection != LinkDirection::STRAIGHT && it->getDirection() == LinkDirection::STRAIGHT) {
     518              :                 // potential turn conflict
     519        82278 :                 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       295658 :         if (fromInternalLane()) {
     527              :             //std::cout << " setRequestInformation link=" << getViaLaneOrLane()->getID() << " before=" << myLaneBefore->getID() << " before2=" << myLaneBefore->getIncomingLanes().front().lane->getID() << "\n";
     528       368776 :             for (const MSLink* const link : myLaneBefore->getIncomingLanes().front().lane->getLinkCont()) {
     529       259168 :                 if (link->getViaLane() != myInternalLaneBefore && &link->getLane()->getEdge() == myTarget) {
     530              :                     //std::cout << " add sublaneFoe=" << (*it)->getViaLane()->getID() << "\n";
     531         4344 :                     mySublaneFoeLanes.push_back(link->getViaLane());
     532              :                 }
     533              :             }
     534              :         }
     535              :     }
     536      2656389 :     if (myInternalLaneBefore != nullptr
     537      1035473 :             && myDirection != LinkDirection::STRAIGHT
     538              :             // for right turns, the curvature helps rather than restricts the linkLeader check
     539       603958 :             && (
     540       603958 :                 (!MSGlobals::gLefthand && myDirection != LinkDirection::RIGHT)
     541       177435 :                 || (MSGlobals::gLefthand && myDirection != LinkDirection::LEFT))) {
     542       853956 :         const double angle = fabs(GeomHelper::angleDiff(
     543       426978 :                                       myLaneBefore->getNormalPredecessorLane()->getShape().angleAt2D(-2),
     544       426978 :                                       myLane->getShape().angleAt2D(0)));
     545       426978 :         if (angle > 0) {
     546       426978 :             double length = myInternalLaneBefore->getShape().length2D();
     547       853956 :             if (myInternalLaneBefore->getIncomingLanes().size() == 1 &&
     548       426978 :                     myInternalLaneBefore->getIncomingLanes()[0].lane->isInternal()) {
     549       121331 :                 length += myInternalLaneBefore->getIncomingLanes()[0].lane->getShape().length2D();
     550       305647 :             } else if (myInternalLane != nullptr) {
     551       121331 :                 length += myInternalLane->getShape().length2D();
     552              :             }
     553       426978 :             myRadius = length / angle;
     554              :             //std::cout << getDescription() << " a=" << RAD2DEG(angle) << " l=" << length << " r=" << myRadius << "\n";
     555              :         }
     556              :     }
     557      2656389 : }
     558              : 
     559              : 
     560              : void
     561        42137 : MSLink::recheckSetRequestInformation() {
     562       355337 :     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      2712823 :         for (int i = 0; i < (int)link->myFoeLanes.size(); i++) {
     572      2712823 :             if (link->myFoeLanes[i] == foeLane) {
     573              :                 conflictIndex = i;
     574              :                 break;
     575              :             }
     576              :         }
     577       313200 :         if (conflictIndex == -1) {
     578            0 :             WRITE_WARNING("Could not recheck ConflictInfo for " + link->getDescription() + " and " + foeExitLink->getDescription() + "\n");
     579       292053 :             continue;
     580              :         }
     581       313200 :         ConflictInfo& ci = link->myConflicts[conflictIndex];
     582       313200 :         if (ci.flag & CONFLICT_SIBLING_CONTINUATION) {
     583       291803 :             const MSLane* const intLane = link->getInternalLaneBefore();
     584              :             const MSLane* const siblingCont = foeExitLink->getInternalLaneBefore();
     585       291803 :             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       291803 :             const double distToDivergence = intLane->getLength() - ci.lengthBehindCrossing;
     588       291803 :             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       291803 :             ci2.foeConflictIndex = conflictIndex;
     594       291803 :             ci.foeConflictIndex = (int)foeExitLink->myConflicts.size();
     595       291803 :             foeExitLink->myFoeLanes.push_back(intLane);
     596       291803 :             foeExitLink->myConflicts.push_back(ci2);
     597              :             continue;
     598       291803 :         }
     599              : 
     600        21397 :         std::vector<double> intersections1 = foeLane->getShape().intersectsAtLengths2D(lane->getShape());
     601        21397 :         if (intersections1.size() == 0) {
     602              : #ifdef MSLink_DEBUG_CROSSING_POINTS
     603              :             std::cout << "    no intersection\n";
     604              : #endif
     605              :             continue;
     606              :         }
     607        21147 :         const double widthFactor = ci.conflictSize / foeLane->getWidth();
     608        21147 :         const double conflictSize2 = lane->getWidth() * widthFactor;
     609        21147 :         std::sort(intersections1.begin(), intersections1.end());
     610        21147 :         intersections1.back() -= conflictSize2 / 2;
     611        21147 :         intersections1.back() = MAX2(0.0, intersections1.back());
     612        21147 :         ci.foeConflictIndex = (int)foeExitLink->myConflicts.size();
     613        21147 :         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        21397 :     }
     618              :     myRecheck.clear();
     619        42137 : }
     620              : 
     621              : double
     622      2878950 : 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      2878950 :     double length = l.length2D();
     629      2878950 :     double sibLength = s.length2D();
     630      2878950 :     if (!sameSource) {
     631      2594016 :         l = l.reverse();
     632      2594016 :         s = s.reverse();
     633      1581942 :     } 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           95 :         lbcSibling += s[-1].distanceTo2D(s[-2]);
     638              :         s.pop_back();
     639      1581847 :     } 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           94 :         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      2878950 :     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      2813531 :         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      2813531 :         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      2839932 :             for (int j = (int)s.size() - 2; j >= 0; j--) {
     665      2839932 :                 const int i = j + (int)l.size();
     666      2839932 :                 const double segLength = s[j].distanceTo2D(s[j + 1]);
     667      2839932 :                 if (distances[i] > minDist) {
     668      1085501 :                     lbcSibling += segLength;
     669              :                 } else {
     670              :                     // assume no sharp bends and just interpolate the last segment
     671      1754431 :                     lbcSibling += segLength - (minDist - distances[i]) * segLength / (distances[i + 1] - distances[i]);
     672      1754431 :                     break;
     673              :                 }
     674              :             }
     675      2908513 :             for (int i = (int)l.size() - 2; i >= 0; i--) {
     676      2839206 :                 const double segLength = l[i].distanceTo2D(l[i + 1]);
     677      2839206 :                 if (distances[i] > minDist) {
     678      1154082 :                     lbcLane += segLength;
     679              :                 } else {
     680              :                     // assume no sharp bends and just interpolate the last segment
     681      1685124 :                     lbcLane += segLength - (minDist - distances[i]) * segLength / (distances[i + 1] - distances[i]);
     682      1685124 :                     break;
     683              :                 }
     684              :             }
     685              :         }
     686              :         assert(lbcSibling >= -NUMERICAL_EPS);
     687              :         assert(lbcLane >= -NUMERICAL_EPS);
     688      2813531 :     }
     689      2878950 :     const double distToDivergence1 = sibling->getLength() + siblingPredLength - lbcSibling;
     690      2878950 :     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      2878950 :     return distToDivergence;
     703      2878950 : }
     704              : 
     705              : 
     706              : bool
     707      1424860 : MSLink::contIntersect(const MSLane* lane, const MSLane* foe) {
     708      1424860 :     if (foe->getLinkCont()[0]->getViaLane() != nullptr) {
     709       128130 :         std::vector<double> intersections = lane->getShape().intersectsAtLengths2D(foe->getShape());
     710       128130 :         return intersections.size() > 0;
     711       128130 :     }
     712              :     return false;
     713              : }
     714              : 
     715              : 
     716              : void
     717    878776963 : 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    878776963 :     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    878776963 :     myApproachingVehicles.emplace(approaching,
     733   1757553926 :                                   ApproachingVehicleInformation(arrivalTime, leaveTime, arrivalSpeed, leaveSpeed, setRequest,
     734    878776963 :                                           arrivalSpeedBraking, waitingTime, dist, approaching->getSpeed(), latOffset));
     735    878776963 : }
     736              : 
     737              : 
     738              : void
     739      1125641 : 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      1125641 :     myApproachingVehicles.emplace(approaching, ai);
     753      1125641 : }
     754              : 
     755              : void
     756       487792 : MSLink::setApproachingPerson(const MSPerson* approaching, const SUMOTime arrivalTime, const SUMOTime leaveTime) {
     757       487792 :     if (myApproachingPersons == nullptr) {
     758         1342 :         myApproachingPersons = new PersonApproachInfos();
     759              :     }
     760       487792 :     myApproachingPersons->emplace(approaching, ApproachingPersonInformation(arrivalTime, leaveTime));
     761       487792 : }
     762              : 
     763              : void
     764    869692447 : 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    869692447 : }
     779              : 
     780              : 
     781              : void
     782        31251 : MSLink::removeApproachingPerson(const MSPerson* person) {
     783        31251 :     if (myApproachingPersons == nullptr) {
     784           12 :         WRITE_WARNINGF("Person '%' entered crossing lane '%' without registering approach, time=%", person->getID(), myLane->getID(), time2string(SIMSTEP));
     785            3 :         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     31859212 : MSLink::getApproaching(const SUMOVehicle* veh) const {
     802              :     auto i = myApproachingVehicles.find(veh);
     803     31859212 :     if (i != myApproachingVehicles.end()) {
     804     27190162 :         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      2888450 : MSLink::getApproachingPtr(const SUMOVehicle* veh) const {
     813              :     auto i = myApproachingVehicles.find(veh);
     814      2888450 :     if (i != myApproachingVehicles.end()) {
     815      2526207 :         return &i->second;
     816              :     } else {
     817              :         return nullptr;
     818              :     }
     819              : }
     820              : 
     821              : 
     822              : void
     823        11296 : MSLink::clearState() {
     824              :     myApproachingVehicles.clear();
     825        11296 : }
     826              : 
     827              : 
     828              : SUMOTime
     829   1550377160 : MSLink::getLeaveTime(const SUMOTime arrivalTime, const double arrivalSpeed,
     830              :                      const double leaveSpeed, const double vehicleLength) const {
     831   1584034601 :     return arrivalTime == SUMOTime_MAX ? SUMOTime_MAX : arrivalTime + TIME2STEPS((getLength() + vehicleLength) / MAX2(0.5 * (arrivalSpeed + leaveSpeed), NUMERICAL_EPS));
     832              : }
     833              : 
     834              : 
     835              : bool
     836    684717712 : 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    684717712 :     if (haveRed() && !ignoreRed) {
     845              :         return false;
     846              :     }
     847    675620989 :     if (isCont() && MSGlobals::gUsingInternalLanes) {
     848              :         return true;
     849              :     }
     850    671162149 :     const SUMOTime leaveTime = getLeaveTime(arrivalTime, arrivalSpeed, leaveSpeed, vehicleLength);
     851    671162149 :     if (MSGlobals::gLateralResolution > 0) {
     852              :         // check for foes on the same lane with the same target edge
     853    138014254 :         for (const MSLink* foeLink : mySublaneFoeLinks) {
     854              :             assert(myLane != foeLink->getLane());
     855      9995558 :             for (const auto& it : foeLink->myApproachingVehicles) {
     856      6802859 :                 const SUMOVehicle* foe = it.first;
     857              :                 if (
     858              :                     // there only is a conflict if the paths cross
     859      7403055 :                     ((posLat < foe->getLateralPositionOnLane() + it.second.latOffset && myLane->getIndex() > foeLink->myLane->getIndex())
     860      6556242 :                      || (posLat > foe->getLateralPositionOnLane() + it.second.latOffset && myLane->getIndex() < foeLink->myLane->getIndex()))
     861              :                     // the vehicle that arrives later must yield
     862      7402666 :                     && (arrivalTime > it.second.arrivalTime
     863              :                         // if both vehicles arrive at the same time, the one
     864              :                         // to the left must yield
     865       387352 :                         || (arrivalTime == it.second.arrivalTime && posLat > foe->getLateralPositionOnLane()))) {
     866       213106 :                     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        42336 :                         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    134779219 :         const int lhSign = MSGlobals::gLefthand ? -1 : 1;
     890    136127253 :         for (const MSLink* foeLink : mySublaneFoeLinks2) {
     891              :             assert(myDirection != LinkDirection::STRAIGHT);
     892      5695189 :             for (const auto& it : foeLink->myApproachingVehicles) {
     893      4347155 :                 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      4347155 :                 const double egoWidth = ego == nullptr ? 1.8 : ego->getVehicleType().getWidth();
     897      4347155 :                 if (!lateralOverlap(posLat, egoWidth, foe->getLateralPositionOnLane() + it.second.latOffset, foe->getVehicleType().getWidth())
     898      4347155 :                         && (((myDirection == LinkDirection::RIGHT || myDirection == LinkDirection::PARTRIGHT)
     899       496186 :                              && (posLat * lhSign > (foe->getLateralPositionOnLane() + it.second.latOffset) * lhSign))
     900       449014 :                             || ((myDirection == LinkDirection::LEFT || myDirection == LinkDirection::PARTLEFT)
     901        33197 :                                 && (posLat * lhSign < (foe->getLateralPositionOnLane() + it.second.latOffset) * lhSign)))) {
     902        81295 :                     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         9067 :                         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     29838918 :             || lastWasContState(LINKSTATE_TL_GREEN_MAJOR)
     936     29427700 :             || (isExitLinkAfterInternalJunction() && getCorrespondingEntryLink()->getState() == LINKSTATE_TL_GREEN_MAJOR))
     937    671593182 :             && 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    640038759 :         return collectFoes == nullptr || collectFoes->size() == 0;
     942              :     }
     943     31071987 :     if (myState == LINKSTATE_ALLWAY_STOP && waitingTime < TIME2STEPS(ego == nullptr ? TS : ego->getVehicleType().getParameter().getJMParam(SUMO_ATTR_JM_ALLWAYSTOP_WAIT, TS))) {
     944              :         return false;
     945     30095825 :     } 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     30031791 :     const std::vector<MSLink*>& foeLinks = (myOffFoeLinks == nullptr || getCorrespondingEntryLink()->getState() != LINKSTATE_ALLWAY_STOP) ? myFoeLinks : *myOffFoeLinks;
     950              : 
     951     30031791 :     if (MSGlobals::gUseMesoSim && impatience == 1 && !myLane->getEdge().isRoundabout()) {
     952              :         return true;
     953              :     }
     954     30031663 :     if (myLane->getBidiLane() != nullptr) {
     955       131950 :         MSLane* bidi = myLane->getBidiLane();
     956       131950 :         if (bidi->getVehicleNumber() > 0) {
     957        20109 :             if (ego == nullptr) {
     958              :                 return false;
     959              :             }
     960              :             double maxOncomingWidth = 0;
     961        20109 :             const MSLane::VehCont& vehs = bidi->getVehiclesSecure();
     962       128598 :             for (MSVehicle* foe : vehs) {
     963       108489 :                 maxOncomingWidth = MAX2(maxOncomingWidth, foe->getVehicleType().getWidth());
     964              :             }
     965        20109 :             bidi->releaseVehicles();
     966        20109 :             if (MSGlobals::gLateralResolution > 0) {
     967        16779 :                 if (ego->getVehicleType().getWidth() + maxOncomingWidth + MSGlobals::gLateralResolution < myLane->getWidth()) {
     968              :                     return false;
     969              :                 }
     970         3330 :             } else if (maxOncomingWidth > 0) {
     971              :                 // do not enter a lane that has any oncoming vehicles
     972              :                 return false;
     973              :             }
     974              :         }
     975       266323 :         for (auto ili : bidi->getIncomingLanes()) {
     976       138285 :             if (ili.lane->getEdge().getPriority() > myLaneBefore->getEdge().getPriority()
     977       138285 :                     || (ili.lane->getEdge().getPriority() == myLaneBefore->getEdge().getPriority()
     978       107447 :                         && ili.lane->getID() > myLaneBefore->getID())) {
     979              :                 BlockingFoes bidiApproachFoes;
     980              :                 double maxOncomingWidth = 0;
     981        21198 :                 if (ili.viaLink->blockedAtTime(arrivalTime, leaveTime, arrivalSpeed, leaveSpeed, false, 0, decel, 0,
     982        42396 :                             MSGlobals::gLateralResolution ? &bidiApproachFoes : nullptr, ego) || bidiApproachFoes.size() > 0) {
     983          506 :                     if (MSGlobals::gLateralResolution > 0) {
     984          437 :                         for (const SUMOTrafficObject* foe : bidiApproachFoes) {
     985          226 :                             maxOncomingWidth = MAX2(maxOncomingWidth, foe->getVehicleType().getWidth());
     986              :                         }
     987          211 :                         if (ego->getVehicleType().getWidth() + maxOncomingWidth + MSGlobals::gLateralResolution < myLane->getWidth()) {
     988              :                             return false;
     989              :                         }
     990              :                     } else {
     991              :                         return false;
     992              :                     }
     993              :                 }
     994        21198 :             }
     995              :         }
     996              :     }
     997     30027751 :     const bool lastWasContRed = lastWasContState(LINKSTATE_TL_RED);
     998     83766369 :     for (const MSLink* const link : foeLinks) {
     999     58644093 :         if (MSGlobals::gUseMesoSim) {
    1000      1938961 :             if (link->haveRed()) {
    1001        46892 :                 continue;
    1002              :             }
    1003              :         }
    1004              : #ifdef MSLink_DEBUG_OPENED
    1005              :         if (gDebugFlag1) {
    1006              :             std::cout << SIMTIME << "   foeLink=" << link->getViaLaneOrLane()->getID() << " numApproaching=" << link->getApproaching().size() << "\n";
    1007              :             if (link->getLane()->isCrossing()) {
    1008              :                 std::cout << SIMTIME << "     approachingPersons=" << (link->myApproachingPersons == nullptr ? "NULL" : toString(link->myApproachingPersons->size())) << "\n";
    1009              :             }
    1010              :         }
    1011              : #endif
    1012     58597201 :         if (link->blockedAtTime(arrivalTime, leaveTime, arrivalSpeed, leaveSpeed, myLane == link->getLane(),
    1013              :                                 impatience, decel, waitingTime, collectFoes, ego, lastWasContRed, dist)) {
    1014              :             return false;
    1015              :         }
    1016              :     }
    1017     25122276 :     if (collectFoes != nullptr && collectFoes->size() > 0) {
    1018              :         return false;
    1019              :     }
    1020              :     return true;
    1021              : }
    1022              : 
    1023              : 
    1024              : bool
    1025     58676475 : MSLink::blockedAtTime(SUMOTime arrivalTime, SUMOTime leaveTime, double arrivalSpeed, double leaveSpeed,
    1026              :                       bool sameTargetLane, double impatience, double decel, SUMOTime waitingTime,
    1027              :                       BlockingFoes* collectFoes, const SUMOTrafficObject* ego, bool lastWasContRed, double dist) const {
    1028    218873751 :     for (const auto& it : myApproachingVehicles) {
    1029              : #ifdef MSLink_DEBUG_OPENED
    1030              :         if (gDebugFlag1) {
    1031              :             if (ego != nullptr
    1032              :                     && ego->getVehicleType().getParameter().getJMParam(SUMO_ATTR_JM_IGNORE_FOE_SPEED, 0) >= it.second.speed
    1033              :                     && ego->getVehicleType().getParameter().getJMParam(SUMO_ATTR_JM_IGNORE_FOE_PROB, 0) > 0) {
    1034              :                 std::stringstream stream; // to reduce output interleaving from different threads
    1035              :                 stream << SIMTIME << " " << myApproachingVehicles.size() << "   foe link=" << getViaLaneOrLane()->getID()
    1036              :                        << " foeVeh=" << it.first->getID() << " (below ignore speed)"
    1037              :                        << " ignoreFoeProb=" << ego->getVehicleType().getParameter().getJMParam(SUMO_ATTR_JM_IGNORE_FOE_PROB, 0)
    1038              :                        << "\n";
    1039              :                 std::cout << stream.str();
    1040              :             }
    1041              :         }
    1042              : #endif
    1043    165000523 :         if (it.first != ego
    1044    164991251 :                 && (ego == nullptr
    1045    164931461 :                     || ego->getVehicleType().getParameter().getJMParam(SUMO_ATTR_JM_IGNORE_FOE_PROB, 0) == 0
    1046        22492 :                     || ego->getVehicleType().getParameter().getJMParam(SUMO_ATTR_JM_IGNORE_FOE_SPEED, 0) < it.second.speed
    1047         1524 :                     || ego->getVehicleType().getParameter().getJMParam(SUMO_ATTR_JM_IGNORE_FOE_PROB, 0) < RandHelper::rand(ego->getRNG()))
    1048    164989883 :                 && !ignoreFoe(ego, it.first)
    1049    164989641 :                 && (!lastWasContRed || it.first->getSpeed() > SUMO_const_haltingSpeed)
    1050    329973791 :                 && blockedByFoe(it.first, it.second, arrivalTime, leaveTime, arrivalSpeed, leaveSpeed, sameTargetLane,
    1051              :                                 impatience, decel, waitingTime, ego)) {
    1052     11287919 :             if (collectFoes == nullptr) {
    1053              :                 return true;
    1054              :             } else {
    1055      6484672 :                 collectFoes->push_back(it.first);
    1056              :             }
    1057              :         }
    1058              :     }
    1059     53873228 :     if (myApproachingPersons != nullptr && !haveRed()) {
    1060              :         const SUMOTime lookAhead = (ego == nullptr
    1061       847594 :                                     ? myLookaheadTime
    1062       847422 :                                     : TIME2STEPS(ego->getVehicleType().getParameter().getJMParam(SUMO_ATTR_JM_TIMEGAP_MINOR, STEPS2TIME(myLookaheadTime))));
    1063       922437 :         for (const auto& it : *myApproachingPersons) {
    1064              : #ifdef MSLink_DEBUG_OPENED
    1065              :             if (gDebugFlag1) {
    1066              :                 std::cout << SIMTIME << ": " << ego->getID() << " check person " << it.first->getID() << " aTime=" << arrivalTime << " foeATime=" << it.second.arrivalTime
    1067              :                           << " lTime=" << leaveTime << " foeLTime=" << it.second.leavingTime
    1068              :                           << " dist=" << dist << "\n";
    1069              :             }
    1070              : #endif
    1071              :             if ((ego == nullptr
    1072       204470 :                     || ego->getVehicleType().getParameter().getJMParam(SUMO_ATTR_JM_IGNORE_FOE_PROB, 0) == 0
    1073          600 :                     || ego->getVehicleType().getParameter().getJMParam(SUMO_ATTR_JM_IGNORE_FOE_SPEED, 0) < it.first->getSpeed()
    1074          600 :                     || ego->getVehicleType().getParameter().getJMParam(SUMO_ATTR_JM_IGNORE_FOE_PROB, 0) < RandHelper::rand(ego->getRNG()))
    1075       204091 :                     && !ignoreFoe(ego, it.first)
    1076       408702 :                     && !((arrivalTime > it.second.leavingTime + lookAhead) || (leaveTime + lookAhead < it.second.arrivalTime))) {
    1077       143299 :                 if (ego == nullptr) {
    1078              :                     // during insertion
    1079          165 :                     if (myJunction->getType() == SumoXMLNodeType::RAIL_CROSSING) {
    1080          165 :                         continue;
    1081              :                     } else {
    1082              :                         return true;
    1083              :                     }
    1084              :                 }
    1085              :                 // check whether braking is feasible (ego might have started to accelerate already)
    1086       143134 :                 const auto& cfm = ego->getVehicleType().getCarFollowModel();
    1087              : #ifdef MSLink_DEBUG_OPENED
    1088              :                 if (gDebugFlag1) {
    1089              :                     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";
    1090              :                 }
    1091              : #endif
    1092       143134 :                 if (dist > cfm.brakeGap(ego->getSpeed(), cfm.getMaxDecel(), 0)) {
    1093              : #ifdef MSLink_DEBUG_OPENED
    1094              :                     if (gDebugFlag1) {
    1095              :                         std::cout << SIMTIME << ": " << ego->getID() << " blocked by person " << it.first->getID() << "\n";
    1096              :                     }
    1097              : #endif
    1098       129848 :                     if (collectFoes == nullptr) {
    1099              :                         return true;
    1100              :                     } else {
    1101            0 :                         collectFoes->push_back(it.first);
    1102              :                     }
    1103              :                 }
    1104              :             }
    1105              :         }
    1106              :     }
    1107              :     return false;
    1108              : }
    1109              : 
    1110              : 
    1111              : bool
    1112    165267669 : MSLink::blockedByFoe(const SUMOVehicle* veh, const ApproachingVehicleInformation& avi,
    1113              :                      SUMOTime arrivalTime, SUMOTime leaveTime, double arrivalSpeed, double leaveSpeed,
    1114              :                      bool sameTargetLane, double impatience, double decel, SUMOTime waitingTime,
    1115              :                      const SUMOTrafficObject* ego) const {
    1116              : #ifdef MSLink_DEBUG_OPENED
    1117              :     if (gDebugFlag1) {
    1118              :         std::stringstream stream; // to reduce output interleaving from different threads
    1119              :         stream << "    link=" << getDescription()
    1120              :                << " foeVeh=" << veh->getID()
    1121              :                << " req=" << avi.willPass
    1122              :                << " aT=" << avi.arrivalTime
    1123              :                << " lT=" << avi.leavingTime
    1124              :                << "\n";
    1125              :         std::cout << stream.str();
    1126              :     }
    1127              : #endif
    1128    165267669 :     if (!avi.willPass) {
    1129              :         return false;
    1130              :     }
    1131     60303894 :     if (myState == LINKSTATE_ALLWAY_STOP) {
    1132              :         assert(waitingTime > 0);
    1133              : #ifdef MSLink_DEBUG_OPENED
    1134              :         if (gDebugFlag1) {
    1135              :             std::stringstream stream; // to reduce output interleaving from different threads
    1136              :             stream << "    foeDist=" << avi.dist
    1137              :                    << " foeBGap=" << veh->getBrakeGap(false)
    1138              :                    << " foeWait=" << avi.waitingTime
    1139              :                    << " wait=" << waitingTime
    1140              :                    << "\n";
    1141              :             std::cout << stream.str();
    1142              :         }
    1143              : #endif
    1144              :         // when using actionSteps, the foe waiting time may be outdated
    1145      1566781 :         const SUMOTime actionDelta = SIMSTEP - veh->getLastActionTime();
    1146      1566781 :         if (waitingTime > avi.waitingTime + actionDelta) {
    1147              :             return false;
    1148              :         }
    1149       232841 :         if (waitingTime == (avi.waitingTime + actionDelta) && arrivalTime < avi.arrivalTime + actionDelta) {
    1150              :             return false;
    1151              :         }
    1152              :     }
    1153     58940380 :     SUMOTime foeArrivalTime = avi.arrivalTime;
    1154     58940380 :     double foeArrivalSpeedBraking = avi.arrivalSpeedBraking;
    1155     58940380 :     if (impatience > 0 && arrivalTime < avi.arrivalTime) {
    1156              : #ifdef MSLink_DEBUG_OPENED
    1157              :         gDebugFlag6 = ((ego == nullptr || ego->isSelected()) && (veh == nullptr || veh->isSelected()));
    1158              : #endif
    1159      2754504 :         const SUMOTime fatb = computeFoeArrivalTimeBraking(arrivalTime, veh, avi.arrivalTime, impatience, avi.dist, foeArrivalSpeedBraking);
    1160      2754504 :         foeArrivalTime = (SUMOTime)((1. - impatience) * (double)avi.arrivalTime + impatience * (double)fatb);
    1161              : #ifdef MSLink_DEBUG_OPENED
    1162              :         if (gDebugFlag6) {
    1163              :             std::cout << SIMTIME << " link=" << getDescription() << " ego=" << ego->getID() << " foe=" << veh->getID()
    1164              :                       << " at=" << STEPS2TIME(arrivalTime)
    1165              :                       << " fat=" << STEPS2TIME(avi.arrivalTime)
    1166              :                       << " fatb=" << STEPS2TIME(fatb)
    1167              :                       << " fat2=" << STEPS2TIME(foeArrivalTime)
    1168              :                       << "\n";
    1169              :         }
    1170              : #endif
    1171              :     }
    1172              : 
    1173              : 
    1174     58940380 :     const SUMOTime lookAhead = (myState == LINKSTATE_ZIPPER
    1175     58940380 :                                 ? myLookaheadTimeZipper
    1176              :                                 : (ego == nullptr
    1177     47219654 :                                    ? myLookaheadTime
    1178     47213594 :                                    : TIME2STEPS(ego->getVehicleType().getParameter().getJMParam(SUMO_ATTR_JM_TIMEGAP_MINOR, STEPS2TIME(myLookaheadTime)))));
    1179              :     //if (ego != 0) std::cout << SIMTIME << " ego=" << ego->getID() << " jmTimegapMinor=" << ego->getVehicleType().getParameter().getJMParam(SUMO_ATTR_JM_TIMEGAP_MINOR, -1) << " lookAhead=" << lookAhead << "\n";
    1180              : #ifdef MSLink_DEBUG_OPENED
    1181              :     if (gDebugFlag1 || gDebugFlag6) {
    1182              :         std::stringstream stream; // to reduce output interleaving from different threads
    1183              :         stream << "       imp=" << impatience << " fAT2=" << foeArrivalTime << " fASb=" << foeArrivalSpeedBraking << " lA=" << lookAhead << " egoAT=" << arrivalTime << " egoLT=" << leaveTime << " egoLS=" << leaveSpeed << "\n";
    1184              :         std::cout << stream.str();
    1185              :     }
    1186              : #endif
    1187     58940380 :     if (avi.leavingTime < arrivalTime) {
    1188              :         // ego wants to be follower
    1189     43110580 :         if (sameTargetLane && (arrivalTime - avi.leavingTime < lookAhead
    1190     18847534 :                                || unsafeMergeSpeeds(avi.leaveSpeed, arrivalSpeed,
    1191     18847534 :                                        veh->getVehicleType().getCarFollowModel().getMaxDecel(), decel))) {
    1192              : #ifdef MSLink_DEBUG_OPENED
    1193              :             if (gDebugFlag1 || gDebugFlag6) {
    1194              :                 std::cout << "      blocked (cannot follow)\n";
    1195              :             }
    1196              : #endif
    1197      4178006 :             return true;
    1198              :         }
    1199     15829800 :     } else if (foeArrivalTime > leaveTime + lookAhead) {
    1200              :         // ego wants to be leader.
    1201     14647254 :         if (sameTargetLane && unsafeMergeSpeeds(leaveSpeed, foeArrivalSpeedBraking,
    1202      5818323 :                                                 decel, veh->getVehicleType().getCarFollowModel().getMaxDecel())) {
    1203              : #ifdef MSLink_DEBUG_OPENED
    1204              :             if (gDebugFlag1 || gDebugFlag6) {
    1205              :                 std::cout << "      blocked (cannot lead)\n";
    1206              :             }
    1207              : #endif
    1208              :             return true;
    1209              :         }
    1210              :     } else {
    1211              :         // even without considering safeHeadwayTime there is already a conflict
    1212              : #ifdef MSLink_DEBUG_OPENED
    1213              :         if (gDebugFlag1 || gDebugFlag6) {
    1214              :             std::cout << "      blocked (hard conflict)\n";
    1215              :         }
    1216              : #endif
    1217              :         return true;
    1218              :     }
    1219              :     return false;
    1220              : }
    1221              : 
    1222              : 
    1223              : SUMOTime
    1224      2754504 : MSLink::computeFoeArrivalTimeBraking(SUMOTime arrivalTime, const SUMOVehicle* foe, SUMOTime foeArrivalTime, double impatience, double dist, double& fasb) {
    1225              :     // a: distance saved when foe brakes from arrivalTime to foeArrivalTime
    1226              :     // b: distance driven past foeArrivalTime
    1227              :     // m: permitted decceleration
    1228              :     // d: total deceleration until foeArrivalTime
    1229              :     // dist2: distance of foe at arrivalTime
    1230              :     // actual arrivalTime must fall on a simulation step
    1231      2754504 :     if (arrivalTime - arrivalTime % DELTA_T == foeArrivalTime - foeArrivalTime % DELTA_T) {
    1232              :         // foe enters the junction in the same step
    1233              : #ifdef MSLink_DEBUG_OPENED
    1234              :         if (gDebugFlag6) {
    1235              :             std::cout << "   foeAT before egoAT\n";
    1236              :         }
    1237              : #endif
    1238              :         return foeArrivalTime;
    1239              :     }
    1240      2422597 :     if (arrivalTime % DELTA_T > 0) {
    1241      2393058 :         arrivalTime = arrivalTime - (arrivalTime % DELTA_T) + DELTA_T;
    1242              :     }
    1243              :     //arrivalTime += DELTA_T - arrivalTime % DELTA_T;
    1244      2422597 :     const double m = foe->getVehicleType().getCarFollowModel().getMaxDecel() * impatience;
    1245      2422597 :     const double dt = STEPS2TIME(foeArrivalTime - arrivalTime);
    1246      2422597 :     const double d = dt * m;
    1247      2422597 :     const double a = dt * d / 2;
    1248      2422597 :     const double v = dist / STEPS2TIME(foeArrivalTime - SIMSTEP + DELTA_T);
    1249      2422597 :     const double dist2 = dist - v * STEPS2TIME(arrivalTime - SIMSTEP);
    1250              : #ifdef MSLink_DEBUG_OPENED
    1251              :     if (gDebugFlag6) {
    1252              :         std::cout << "   dist=" << dist << " dist2=" << dist2
    1253              :                   << " at=" << STEPS2TIME(arrivalTime)
    1254              :                   << " fat=" << STEPS2TIME(foeArrivalTime)
    1255              :                   << " dt=" << dt << " v=" << v << " m=" << m << " d=" << d << " a=" << a << "\n";
    1256              :     }
    1257              : #endif
    1258      2422597 :     if (0.5 * v * v / m <= dist2) {
    1259              : #ifdef MSLink_DEBUG_OPENED
    1260              :         if (gDebugFlag6) {
    1261              :             std::cout << "   canBrakeToStop\n";
    1262              :         }
    1263              : #endif
    1264      1212129 :         fasb = 0;
    1265      1212129 :         return foeArrivalTime + TIME2STEPS(30);
    1266              :     }
    1267              :     // a = b (foe reaches the original distance to the stop line)
    1268              :     // x: time driven past foeArrivalTime
    1269              :     // v: foe speed without braking
    1270              :     // v2: average foe speed after foeArrivalTime (braking continues for time x)
    1271              :     // v2 = (v - d - x * m / 2)
    1272              :     // b = v2 * x
    1273              :     // solving for x gives:
    1274      1210468 :     const double x = (sqrt(4 * (v - d) * (v - d) - 8 * m * a) * -0.5 - d + v) / m;
    1275              : 
    1276              : #ifdef MSLink_DEBUG_OPENED
    1277              :     const double x2 = (sqrt(4 * (v - d) * (v - d) - 8 * m * a) * 0.5 - d + v) / m;
    1278              :     if (gDebugFlag6 || std::isnan(x)) {
    1279              :         std::cout << SIMTIME << "   dist=" << dist << " dist2=" << dist2  << " at=" << STEPS2TIME(arrivalTime) << " m=" << m << " d=" << d << " v=" << v << " a=" << a << " x=" << x << " x2=" << x2 << "\n";
    1280              :     }
    1281              : #endif
    1282      1210468 :     fasb = v - (dt + x) * m;
    1283      1210468 :     return foeArrivalTime + TIME2STEPS(x);
    1284              : }
    1285              : 
    1286              : 
    1287              : bool
    1288       438196 : MSLink::hasApproachingFoe(SUMOTime arrivalTime, SUMOTime leaveTime, double speed, double decel) const {
    1289       468652 :     for (const MSLink* const link : myFoeLinks) {
    1290        58076 :         if (link->blockedAtTime(arrivalTime, leaveTime, speed, speed, myLane == link->getLane(), 0, decel, 0)) {
    1291              :             return true;
    1292              :         }
    1293              :     }
    1294       511126 :     for (const MSLane* const lane : myFoeLanes) {
    1295       107188 :         if (lane->getVehicleNumberWithPartials() > 0) {
    1296              :             return true;
    1297              :         }
    1298              :     }
    1299              :     return false;
    1300              : }
    1301              : 
    1302              : 
    1303              : std::pair<const SUMOVehicle*, const MSLink*>
    1304         5622 : MSLink::getFirstApproachingFoe(const MSLink* wrapAround) const {
    1305              :     double closetDist = std::numeric_limits<double>::max();
    1306              :     const SUMOVehicle* closest = nullptr;
    1307              :     const MSLink* foeLink = nullptr;
    1308        18308 :     for (MSLink* link : myFoeLinks) {
    1309        19750 :         for (const auto& it : link->myApproachingVehicles) {
    1310              :             //std::cout << " link=" << getDescription() << " foeLink_in=" << link->getLaneBefore()->getID() << " wrapAround=" << wrapAround->getDescription() << "\n";
    1311         7064 :             if (link->getLaneBefore() == wrapAround->getLaneBefore()) {
    1312          489 :                 return std::make_pair(nullptr, wrapAround);
    1313         6575 :             } else if (it.second.dist < closetDist) {
    1314              :                 closetDist = it.second.dist;
    1315         3423 :                 if (it.second.willPass) {
    1316         3162 :                     closest = it.first;
    1317              :                     foeLink = link;
    1318              :                 }
    1319              :             }
    1320              :         }
    1321              :     }
    1322              :     return std::make_pair(closest, foeLink);
    1323              : }
    1324              : 
    1325              : 
    1326              : void
    1327     71198791 : MSLink::setTLState(LinkState state, SUMOTime t) {
    1328     71198791 :     if (myState != state) {
    1329     16499810 :         myLastStateChange = t;
    1330              :     }
    1331     71198791 :     myState = state;
    1332     71198791 :     if (haveGreen()) {
    1333     12087453 :         myLastGreenState = myState;
    1334              :     }
    1335     71198791 : }
    1336              : 
    1337              : 
    1338              : void
    1339       176971 : MSLink::setTLLogic(const MSTrafficLightLogic* logic) {
    1340       176971 :     myLogic = logic;
    1341       176971 : }
    1342              : 
    1343              : 
    1344              : bool
    1345   1282125442 : MSLink::isCont() const {
    1346              :     // when a traffic light is switched off minor roads have their cont status revoked
    1347   1282125442 :     return (myState == LINKSTATE_TL_OFF_BLINKING || myState == LINKSTATE_ALLWAY_STOP || myState == LINKSTATE_STOP) ? myAmContOff : myAmCont;
    1348              : }
    1349              : 
    1350              : 
    1351              : bool
    1352     66780282 : MSLink::lastWasContMajor() const {
    1353     67459025 :     if (isExitLinkAfterInternalJunction()) {
    1354       678743 :         return myInternalLaneBefore->getIncomingLanes()[0].viaLink->lastWasContMajor();
    1355              :     }
    1356     66780282 :     if (myInternalLane == nullptr || myAmCont) {
    1357              :         return false;
    1358              :     } else {
    1359     48799633 :         MSLane* pred = myInternalLane->getLogicalPredecessorLane();
    1360     48799633 :         if (!pred->getEdge().isInternal()) {
    1361              :             return false;
    1362              :         } else {
    1363     11708413 :             const MSLane* const pred2 = pred->getLogicalPredecessorLane();
    1364              :             assert(pred2 != nullptr);
    1365     11708413 :             const MSLink* const predLink = pred2->getLinkTo(pred);
    1366              :             assert(predLink != nullptr);
    1367     11708413 :             if (predLink->havePriority()) {
    1368              :                 return true;
    1369              :             }
    1370     11074495 :             if (myHavePedestrianCrossingFoe) {
    1371      1437138 :                 return predLink->getLastGreenState() == LINKSTATE_TL_GREEN_MAJOR;
    1372              :             } else {
    1373      9637357 :                 return predLink->haveYellow();
    1374              :             }
    1375              :         }
    1376              :     }
    1377              : }
    1378              : 
    1379              : 
    1380              : bool
    1381     59866669 : MSLink::lastWasContState(LinkState linkState) const {
    1382     59866669 :     if (myInternalLane == nullptr || myAmCont || myHavePedestrianCrossingFoe) {
    1383              :         return false;
    1384              :     } else {
    1385     52569176 :         MSLane* pred = myInternalLane->getLogicalPredecessorLane();
    1386     52569176 :         if (!pred->getEdge().isInternal()) {
    1387              :             return false;
    1388              :         } else {
    1389     15363312 :             const MSLane* const pred2 = pred->getLogicalPredecessorLane();
    1390              :             assert(pred2 != nullptr);
    1391     15363312 :             const MSLink* const predLink = pred2->getLinkTo(pred);
    1392              :             assert(predLink != nullptr);
    1393     15363312 :             return predLink->getState() == linkState;
    1394              :         }
    1395              :     }
    1396              : }
    1397              : 
    1398              : 
    1399              : void
    1400       113904 : MSLink::writeApproaching(OutputDevice& od, const std::string fromLaneID) const {
    1401       113904 :     if (myApproachingVehicles.size() > 0) {
    1402         9765 :         od.openTag("link");
    1403         9765 :         od.writeAttr(SUMO_ATTR_FROM, fromLaneID);
    1404         9765 :         const std::string via = getViaLane() == nullptr ? "" : getViaLane()->getID();
    1405         9765 :         od.writeAttr(SUMO_ATTR_VIA, via);
    1406        19530 :         od.writeAttr(SUMO_ATTR_TO, getLane() == nullptr ? "" : getLane()->getID());
    1407              :         std::vector<std::pair<SUMOTime, const SUMOVehicle*> > toSort; // stabilize output
    1408        21325 :         for (auto it : myApproachingVehicles) {
    1409        11560 :             toSort.push_back(std::make_pair(it.second.arrivalTime, it.first));
    1410              :         }
    1411         9765 :         std::sort(toSort.begin(), toSort.end());
    1412        21325 :         for (std::vector<std::pair<SUMOTime, const SUMOVehicle*> >::const_iterator it = toSort.begin(); it != toSort.end(); ++it) {
    1413        11560 :             od.openTag("approaching");
    1414        11560 :             const ApproachingVehicleInformation& avi = myApproachingVehicles.find(it->second)->second;
    1415        11560 :             od.writeAttr(SUMO_ATTR_ID, it->second->getID());
    1416        11560 :             od.writeAttr(SUMO_ATTR_IMPATIENCE, it->second->getImpatience());
    1417        11560 :             od.writeAttr("arrivalTime", time2string(avi.arrivalTime));
    1418        11560 :             od.writeAttr("leaveTime", time2string(avi.leavingTime));
    1419        11560 :             od.writeAttr("arrivalSpeed", toString(avi.arrivalSpeed));
    1420        11560 :             od.writeAttr("arrivalSpeedBraking", toString(avi.arrivalSpeedBraking));
    1421        11560 :             od.writeAttr("leaveSpeed", toString(avi.leaveSpeed));
    1422        11560 :             od.writeAttr("willPass", toString(avi.willPass));
    1423        23120 :             od.closeTag();
    1424              :         }
    1425         9765 :         od.closeTag();
    1426         9765 :     }
    1427       113904 : }
    1428              : 
    1429              : 
    1430              : double
    1431       921909 : MSLink::getInternalLengthsAfter() const {
    1432              :     double len = 0.;
    1433       921909 :     MSLane* lane = myInternalLane;
    1434              : 
    1435      1760033 :     while (lane != nullptr && lane->isInternal()) {
    1436       838124 :         len += lane->getLength();
    1437       838124 :         lane = lane->getLinkCont()[0]->getViaLane();
    1438              :     }
    1439       921909 :     return len;
    1440              : }
    1441              : 
    1442              : double
    1443            0 : MSLink::getInternalLengthsBefore() const {
    1444              :     double len = 0.;
    1445            0 :     const MSLane* lane = myInternalLane;
    1446              : 
    1447            0 :     while (lane != nullptr && lane->isInternal()) {
    1448            0 :         len += lane->getLength();
    1449            0 :         if (lane->getIncomingLanes().size() == 1) {
    1450            0 :             lane = lane->getIncomingLanes()[0].lane;
    1451              :         } else {
    1452              :             break;
    1453              :         }
    1454              :     }
    1455            0 :     return len;
    1456              : }
    1457              : 
    1458              : 
    1459              : double
    1460       129526 : MSLink::getLengthsBeforeCrossing(const MSLane* foeLane) const {
    1461       129526 :     MSLane* via = myInternalLane;
    1462              :     double totalDist = 0.;
    1463              :     bool foundCrossing = false;
    1464       132382 :     while (via != nullptr) {
    1465       131022 :         MSLink* link = via->getLinkCont()[0];
    1466       131022 :         double dist = link->getLengthBeforeCrossing(foeLane);
    1467       131022 :         if (dist != INVALID_DOUBLE) {
    1468              :             // found conflicting lane
    1469       128166 :             totalDist += dist;
    1470              :             foundCrossing = true;
    1471              :             break;
    1472              :         } else {
    1473         2856 :             totalDist += via->getLength();
    1474              :             via = link->getViaLane();
    1475              :         }
    1476              :     }
    1477              :     if (foundCrossing) {
    1478       128166 :         return totalDist;
    1479              :     } else {
    1480              :         return INVALID_DOUBLE;
    1481              :     }
    1482              : }
    1483              : 
    1484              : 
    1485              : double
    1486       131022 : MSLink::getLengthBeforeCrossing(const MSLane* foeLane) const {
    1487              :     int foe_ix;
    1488       785495 :     for (foe_ix = 0; foe_ix != (int)myFoeLanes.size(); ++foe_ix) {
    1489       783999 :         if (myFoeLanes[foe_ix] == foeLane) {
    1490              :             break;
    1491              :         }
    1492              :     }
    1493       131022 :     if (foe_ix == (int)myFoeLanes.size()) {
    1494              :         // no conflict with the given lane, indicate by returning -1
    1495              : #ifdef MSLink_DEBUG_CROSSING_POINTS
    1496              :         std::cout << "No crossing of lanes '" << foeLane->getID() << "' and '" << myInternalLaneBefore->getID() << "'" << std::endl;
    1497              : #endif
    1498              :         return INVALID_DOUBLE;
    1499              :     } else {
    1500              :         // found conflicting lane index
    1501       129526 :         double dist = myInternalLaneBefore->getLength() - myConflicts[foe_ix].getLengthBehindCrossing(this);
    1502       129526 :         if (dist == -10000.) {
    1503              :             // this is the value in myConflicts, if the relation allows intersection but none is present for the actual geometry.
    1504              :             return INVALID_DOUBLE;
    1505              :         }
    1506              : #ifdef MSLink_DEBUG_CROSSING_POINTS
    1507              :         std::cout << "Crossing of lanes '" << myInternalLaneBefore->getID() << "' and '" << foeLane->getID()
    1508              :                   << "' at distance " << dist << " (approach along '"
    1509              :                   <<  myInternalLaneBefore->getEntryLink()->getLaneBefore()->getID() << "')" << std::endl;
    1510              : #endif
    1511              :         return dist;
    1512              :     }
    1513              : }
    1514              : 
    1515              : 
    1516              : bool
    1517     40135375 : MSLink::isEntryLink() const {
    1518     40135375 :     if (MSGlobals::gUsingInternalLanes) {
    1519     63822301 :         return myInternalLane != nullptr && myInternalLaneBefore == nullptr;
    1520              :     } else {
    1521              :         return false;
    1522              :     }
    1523              : }
    1524              : 
    1525              : bool
    1526     19493948 : MSLink::isConflictEntryLink() const {
    1527              :     // either a non-cont entry link or the link after a cont-link
    1528     19493948 :     return !myAmCont && (isEntryLink() || (myInternalLaneBefore != nullptr && myInternalLane != nullptr));
    1529              : }
    1530              : 
    1531              : bool
    1532     94821489 : MSLink::isExitLink() const {
    1533     94821489 :     if (MSGlobals::gUsingInternalLanes) {
    1534    162954969 :         return myInternalLaneBefore != nullptr && myInternalLane == nullptr;
    1535              :     } else {
    1536              :         return false;
    1537              :     }
    1538              : }
    1539              : 
    1540              : bool
    1541    156809857 : MSLink::isExitLinkAfterInternalJunction() const {
    1542    156809857 :     if (MSGlobals::gUsingInternalLanes) {
    1543              :         return (getInternalLaneBefore() != nullptr
    1544     81054409 :                 && myInternalLaneBefore->getIncomingLanes().size() == 1
    1545    237520746 :                 && myInternalLaneBefore->getIncomingLanes().front().viaLink->isInternalJunctionLink());
    1546              :     } else {
    1547              :         return false;
    1548              :     }
    1549              : }
    1550              : 
    1551              : 
    1552              : const MSLink*
    1553       140042 : MSLink::getCorrespondingExitLink() const {
    1554       140042 :     MSLane* lane = myInternalLane;
    1555              :     const MSLink* link = this;
    1556       284660 :     while (lane != nullptr) {
    1557       144618 :         link = lane->getLinkCont()[0];
    1558              :         lane = link->getViaLane();
    1559              :     }
    1560       140042 :     return link;
    1561              : }
    1562              : 
    1563              : 
    1564              : const MSLink*
    1565    809396661 : MSLink::getCorrespondingEntryLink() const {
    1566              :     const MSLink* link = this;
    1567   1088132707 :     while (link->myLaneBefore->isInternal()) {
    1568              :         assert(myLaneBefore->getIncomingLanes().size() == 1);
    1569    278736046 :         link = link->myLaneBefore->getIncomingLanes().front().viaLink;
    1570              :     }
    1571    809396661 :     return link;
    1572              : }
    1573              : 
    1574              : 
    1575              : bool
    1576    424401485 : MSLink::isInternalJunctionLink() const {
    1577    424401485 :     return getInternalLaneBefore() != nullptr && myInternalLane != nullptr;
    1578              : }
    1579              : 
    1580              : 
    1581              : const MSLink::LinkLeaders
    1582    879130379 : MSLink::getLeaderInfo(const MSVehicle* ego, double dist, std::vector<const MSPerson*>* collectBlockers, bool isShadowLink) const {
    1583              :     LinkLeaders result;
    1584              :     // this link needs to start at an internal lane (either an exit link or between two internal lanes)
    1585              :     // or it must be queried by the pedestrian model (ego == 0)
    1586    879130379 :     if (ego != nullptr && (!fromInternalLane() || ego->getLaneChangeModel().isOpposite())) {
    1587              :         // ignore link leaders
    1588              :         return result;
    1589              :     }
    1590              :     //gDebugFlag1 = true;
    1591    296654192 :     if (gDebugFlag1) {
    1592            0 :         std::cout << SIMTIME << " getLeaderInfo link=" << getDescription() << " dist=" << dist << " isShadowLink=" << isShadowLink << "\n";
    1593              :     }
    1594    296654192 :     if (MSGlobals::gComputeLC && ego != nullptr && ego->getLane()->isNormal()) {
    1595     25753169 :         const MSLink* junctionEntry = getLaneBefore()->getEntryLink();
    1596      6453515 :         if (junctionEntry->haveRed() && !ego->ignoreRed(junctionEntry, true)
    1597              :                 // check oncoming on bidiLane during laneChanging
    1598     32202001 :                 && (!MSGlobals::gComputeLC || junctionEntry->getLaneBefore()->getBidiLane() == nullptr)) {
    1599      6401573 :             if (gDebugFlag1) {
    1600            0 :                 std::cout << "   ignore linkLeaders beyond red light\n";
    1601              :             }
    1602              :             return result;
    1603              :         }
    1604              :     }
    1605              :     // this is an exit link
    1606    290252619 :     const double extraGap = ego != nullptr ? ego->getVehicleType().getParameter().getJMParam(SUMO_ATTR_JM_EXTRA_GAP, 0) : 0;
    1607    770480524 :     for (int i = 0; i < (int)myFoeLanes.size(); ++i) {
    1608    480227908 :         const MSLane* foeLane = myFoeLanes[i];
    1609    480227908 :         const MSLink* foeExitLink = foeLane->getLinkCont()[0];
    1610              :         // distance from the querying vehicle to the crossing point with foeLane
    1611    480227908 :         double distToCrossing = dist - myConflicts[i].getLengthBehindCrossing(this);
    1612    480227908 :         const double foeDistToCrossing = foeLane->getLength() - myConflicts[i].getFoeLengthBehindCrossing(foeExitLink);
    1613    480227908 :         const bool sameTarget = (myLane == foeExitLink->getLane()) && !isInternalJunctionLink() && !foeExitLink->isInternalJunctionLink();
    1614    480227908 :         const bool sameSource = (myInternalLaneBefore != nullptr && myInternalLaneBefore->getNormalPredecessorLane() == foeLane->getNormalPredecessorLane());
    1615    480227908 :         const double crossingWidth = (sameTarget || sameSource) ? 0 : myConflicts[i].conflictSize;
    1616    480227908 :         const double foeCrossingWidth = (sameTarget || sameSource) ? 0 : myConflicts[i].getFoeConflictSize(foeExitLink);
    1617              :         // special treatment of contLane foe only applies if this lane is not a contLane or contLane follower itself
    1618    607223610 :         const bool contLane = (foeExitLink->getViaLaneOrLane()->getEdge().isInternal() && !(
    1619    126995702 :                                    isInternalJunctionLink() || isExitLinkAfterInternalJunction()));
    1620    480227908 :         if (gDebugFlag1) {
    1621              :             std::cout << " distToCrossing=" << distToCrossing << " foeLane=" << foeLane->getID() << " cWidth=" << crossingWidth
    1622            0 :                       << " flag=" << myConflicts[i].flag
    1623            0 :                       << " ijl=" << isInternalJunctionLink() << " sT=" << sameTarget << " sS=" << sameSource
    1624            0 :                       << " lbc=" << myConflicts[i].getLengthBehindCrossing(this)
    1625            0 :                       << " flbc=" << myConflicts[i].getFoeLengthBehindCrossing(foeExitLink)
    1626              :                       << " cw=" << crossingWidth
    1627              :                       << " fcw=" << foeCrossingWidth
    1628              :                       << " contLane=" << contLane
    1629            0 :                       << " state=" << toString(myState)
    1630            0 :                       << " foeState=" << toString(foeExitLink->getState())
    1631            0 :                       << "\n";
    1632              :         }
    1633    106501316 :         if (distToCrossing + crossingWidth < 0 && !sameTarget
    1634    581055357 :                 && (ego == nullptr || !MSGlobals::gComputeLC || distToCrossing + crossingWidth + ego->getVehicleType().getLength() < 0)) {
    1635     96626177 :             if (gDebugFlag1) {
    1636            0 :                 std::cout << " ignore:egoBeyondCrossingPoint\n";
    1637              :             }
    1638     96626177 :             continue; // vehicle is behind the crossing point, continue with next foe lane
    1639              :         }
    1640              :         bool ignoreGreenCont = false;
    1641              :         bool foeIndirect = false;
    1642    383601731 :         if (contLane) {
    1643     41952162 :             const MSLink* entry = getLaneBefore()->getEntryLink();
    1644     41952162 :             const MSLink* foeEntry = foeLane->getEntryLink();
    1645     41952162 :             foeIndirect = foeEntry->myAmIndirect;
    1646     41671299 :             if (entry != nullptr && entry->haveGreen()
    1647     26453745 :                     && foeEntry != nullptr && foeEntry->haveGreen()
    1648     54339714 :                     && entry->myLaneBefore != foeEntry->myLaneBefore)  {
    1649              :                 // ignore vehicles before an internaljunction as long as they are still in green minor mode
    1650              :                 ignoreGreenCont = true;
    1651              :             }
    1652              :         }
    1653     41952162 :         if (foeIndirect && distToCrossing >= NO_INTERSECTION) {
    1654        28087 :             if (gDebugFlag1) {
    1655            0 :                 std::cout << " ignore:noIntersection\n";
    1656              :             }
    1657        28087 :             continue;
    1658              :         }
    1659              :         // it is not sufficient to return the last vehicle on the foeLane because ego might be its leader
    1660              :         // therefore we return all vehicles on the lane
    1661              :         //
    1662              :         // special care must be taken for continuation lanes. (next lane is also internal)
    1663              :         // vehicles on cont. lanes or on internal lanes with the same target as this link can not be ignored
    1664              :         // and should block (gap = -1) unless they are part of an indirect turn
    1665              :         MSLane::AnyVehicleIterator end = foeLane->anyVehiclesEnd();
    1666     30697035 :         for (MSLane::AnyVehicleIterator it_veh = foeLane->anyVehiclesBegin(); it_veh != end; ++it_veh) {
    1667     30697038 :             MSVehicle* leader = (MSVehicle*)*it_veh;
    1668     30697038 :             const double leaderBack = leader->getBackPositionOnLane(foeLane) - extraGap;
    1669     30697038 :             const double leaderBackDist = foeDistToCrossing - leaderBack;
    1670     30697038 :             const double l2 = ego != nullptr ? ego->getLength() + 2 : 0; // add some slack to account for further meeting-angle effects
    1671     30584699 :             const double sagitta = ego != nullptr && myRadius != std::numeric_limits<double>::max() ? myRadius - sqrt(myRadius * myRadius - 0.25 * l2 * l2) : 0;
    1672     30697038 :             const bool pastTheCrossingPoint = leaderBackDist + foeCrossingWidth + sagitta < 0;
    1673     30697038 :             const bool enteredTheCrossingPoint = leaderBackDist < leader->getVehicleType().getLength();
    1674     30697038 :             const bool foeIsBicycleTurn = (leader->getVehicleType().getVehicleClass() == SVC_BICYCLE
    1675     30697038 :                                            && foeLane->getIncomingLanes().front().viaLink->getDirection() == LinkDirection::LEFT);
    1676     30697038 :             const bool ignoreIndirectBicycleTurn = pastTheCrossingPoint && foeIsBicycleTurn;
    1677     30697038 :             const bool cannotIgnore = ((contLane && !ignoreIndirectBicycleTurn) || sameTarget || (sameSource && !MSGlobals::gComputeLC)) && ego != nullptr;
    1678     30697038 :             const bool inTheWay = ((((!pastTheCrossingPoint && distToCrossing > 0) || (sameTarget && distToCrossing > leaderBackDist - leader->getLength()))
    1679     24019763 :                                     && (enteredTheCrossingPoint || (sameSource && !enteredTheCrossingPoint && foeDistToCrossing < distToCrossing))
    1680     16125642 :                                     && (!(myConflicts[i].flag == CONFLICT_DUMMY_MERGE) || foeIsBicycleTurn || sameSource))
    1681     45303920 :                                    || foeExitLink->getLaneBefore()->getNormalPredecessorLane() == myLane->getBidiLane());
    1682     30697038 :             const bool isOpposite = leader->getLaneChangeModel().isOpposite();
    1683     30697038 :             const auto avi = foeExitLink->getApproaching(leader);
    1684              :             // if leader is not found, assume that it performed a lane change in the last step
    1685     30697038 :             const bool willPass = avi.willPass || (avi.arrivalTime == INVALID_TIME && sameTarget);
    1686     30697038 :             if (gDebugFlag1) {
    1687              :                 std::cout << " candidate leader=" << leader->getID()
    1688              :                           << " cannotIgnore=" << cannotIgnore
    1689              :                           << " fdtc=" << foeDistToCrossing
    1690              :                           << " lb=" << leaderBack
    1691              :                           << " lbd=" << leaderBackDist
    1692              :                           << " fcwidth=" << foeCrossingWidth
    1693            0 :                           << " r=" << myRadius
    1694              :                           << " sagitta=" << sagitta
    1695              :                           << " foePastCP=" << pastTheCrossingPoint
    1696              :                           << " foeEnteredCP=" << enteredTheCrossingPoint
    1697              :                           << " inTheWay=" << inTheWay
    1698              :                           << " willPass=" << willPass
    1699            0 :                           << " isFrontOnLane=" << leader->isFrontOnLane(foeLane)
    1700              :                           << " ignoreGreenCont=" << ignoreGreenCont
    1701              :                           << " foeIndirect=" << foeIndirect
    1702              :                           << " foeBikeTurn=" << foeIsBicycleTurn
    1703            0 :                           << " isOpposite=" << isOpposite << "\n";
    1704              :             }
    1705     30697038 :             if (leader == ego) {
    1706      9477964 :                 continue;
    1707              :             }
    1708              :             // ignore greenCont foe vehicles that are not in the way
    1709     29761824 :             if (!inTheWay && ignoreGreenCont) {
    1710         6890 :                 if (gDebugFlag1) {
    1711            0 :                     std::cout << "   ignoreGreenCont\n";
    1712              :                 }
    1713         6890 :                 continue;
    1714              :             }
    1715              :             // after entering the conflict area, ignore foe vehicles that are not in the way
    1716      3811009 :             if ((!MSGlobals::gComputeLC || (ego != nullptr && ego->getLane() == foeLane) || MSGlobals::gSublane)
    1717     28412440 :                     && distToCrossing < -POSITION_EPS && !inTheWay
    1718     30078368 :                     && (ego == nullptr || !MSGlobals::gComputeLC || distToCrossing < -ego->getVehicleType().getLength())) {
    1719       129569 :                 if (gDebugFlag1) {
    1720            0 :                     std::cout << "   ego entered conflict area\n";
    1721              :                 }
    1722       129569 :                 continue;
    1723              :             }
    1724     29709136 :             if (!MSGlobals::gComputeLC
    1725     25858210 :                     && sameSource
    1726      8109322 :                     && &ego->getLane()->getEdge() == &myInternalLaneBefore->getEdge()
    1727     30060594 :                     && leaderBack + leader->getLength() < ego->getPositionOnLane() - ego->getLength()) {
    1728              :                 // ego is already on the junction and clearly ahead of foe
    1729        83771 :                 if (gDebugFlag1) {
    1730            0 :                     std::cout << "   ego ahead of same-source foe\n";
    1731              :                 }
    1732        83771 :                 continue;
    1733              :             }
    1734              : 
    1735              :             // ignore foe vehicles that will not pass
    1736     18886952 :             if ((!cannotIgnore || leader->isStopped() || sameTarget)
    1737     19850367 :                     && !willPass
    1738      2370007 :                     && (avi.arrivalTime == INVALID_TIME || leader->getSpeed() < SUMO_const_haltingSpeed)
    1739      2369735 :                     && leader->isFrontOnLane(foeLane)
    1740              :                     && !isOpposite
    1741      1199414 :                     && !inTheWay
    1742              :                     // willPass is false if the vehicle is already on the stopping edge
    1743     30019703 :                     && !leader->willStop()) {
    1744       477320 :                 if (gDebugFlag1) {
    1745            0 :                     std::cout << "   foe will not pass\n";
    1746              :                 }
    1747       477320 :                 continue;
    1748              :             }
    1749     29064274 :             if (leader->isBidiOn(foeLane)) {
    1750              :                 // conflict resolved via forward lane of the foe
    1751      1277810 :                 continue;
    1752              :             }
    1753              :             // check whether foe is blocked and might need to change before leaving the junction
    1754     27786464 :             const bool foeStrategicBlocked = (leader->getLaneChangeModel().isStrategicBlocked() &&
    1755      1390592 :                                               leader->getCarFollowModel().brakeGap(leader->getSpeed()) <= foeLane->getLength() - leaderBack);
    1756     27786464 :             const bool sameInternalEdge = &myInternalLaneBefore->getEdge() == &foeExitLink->getInternalLaneBefore()->getEdge();
    1757              : 
    1758     27786464 :             const bool foeLaneIsBidi = myInternalLaneBefore->getBidiLane() == foeLane;
    1759     27786464 :             if (MSGlobals::gSublane && ego != nullptr && (sameSource || sameTarget || foeLaneIsBidi)
    1760      7349704 :                     && (!foeStrategicBlocked || sameInternalEdge)) {
    1761      7223154 :                 if (ego->getLane() == leader->getLane()) {
    1762       153330 :                     continue;
    1763              :                 }
    1764              :                 // ignore vehicles if not in conflict sublane-wise
    1765      7069824 :                 const double egoLatOffset = isShadowLink ? ego->getLatOffset(ego->getLaneChangeModel().getShadowLane()) : 0;
    1766      7069824 :                 const double posLat = ego->getLateralPositionOnLane() + egoLatOffset;
    1767      7069824 :                 double posLatLeader = leader->getLateralPositionOnLane() + leader->getLatOffset(foeLane);
    1768      7069824 :                 if (foeLaneIsBidi) {
    1769              :                     // leader is oncoming
    1770          431 :                     posLatLeader = foeLane->getWidth() - posLatLeader;
    1771              :                 }
    1772      7069824 :                 const double latGap = (fabs(posLat - posLatLeader)
    1773      7069824 :                                        - 0.5 * (ego->getVehicleType().getWidth() + leader->getVehicleType().getWidth()));
    1774      7069824 :                 const double maneuverDist = leader->getLaneChangeModel().getManeuverDist() * (posLat < posLatLeader ? -1 : 1);
    1775      7069824 :                 if (gDebugFlag1) {
    1776            0 :                     std::cout << " checkIgnore sublaneFoe lane=" << myInternalLaneBefore->getID()
    1777              :                               << " sameSource=" << sameSource
    1778              :                               << " sameTarget=" << sameTarget
    1779              :                               << " foeLaneIsBidi=" << foeLaneIsBidi
    1780              :                               << " foeLane=" << foeLane->getID()
    1781              :                               << " leader=" << leader->getID()
    1782            0 :                               << " egoLane=" << ego->getLane()->getID()
    1783            0 :                               << " leaderLane=" << leader->getLane()->getID()
    1784              :                               << " egoLat=" << posLat
    1785              :                               << " egoLatOffset=" << egoLatOffset
    1786              :                               << " leaderLat=" << posLatLeader
    1787            0 :                               << " leaderLatOffset=" << leader->getLatOffset(foeLane)
    1788              :                               << " latGap=" << latGap
    1789              :                               << " maneuverDist=" << maneuverDist
    1790            0 :                               << " computeLC=" << MSGlobals::gComputeLC
    1791            0 :                               << " egoMaxSpeedLat=" << ego->getVehicleType().getMaxSpeedLat()
    1792            0 :                               << "\n";
    1793              :                 }
    1794      1714659 :                 if (latGap > 0 && (latGap > maneuverDist || !sameTarget || !MSGlobals::gComputeLC)
    1795              :                         // do not perform sublane changes that interfere with the leader vehicle
    1796      8778222 :                         && (!MSGlobals::gComputeLC || latGap > ego->getVehicleType().getMaxSpeedLat())) {
    1797      1568700 :                     const MSLink* foeEntryLink = foeLane->getIncomingLanes().front().viaLink;
    1798      1568700 :                     if (sameSource) {
    1799              :                         // for lanes from the same edge, higer index implies a
    1800              :                         // connection further to the left
    1801      1269214 :                         const bool leaderFromRight = (myIndex > foeEntryLink->getIndex());
    1802      1269214 :                         if ((posLat > posLatLeader) == leaderFromRight) {
    1803              :                             // ignore speed since lanes diverge
    1804       691539 :                             if (gDebugFlag1) {
    1805            0 :                                 std::cout << "   ignored (same source) leaderFromRight=" << leaderFromRight << "\n";
    1806              :                             }
    1807       691539 :                             continue;
    1808              :                         }
    1809       299486 :                     } else if (sameTarget) {
    1810              :                         // for lanes from different edges we cannot rely on the
    1811              :                         // index due to wrap-around issues
    1812       299055 :                         if (myDirection != foeEntryLink->getDirection()) {
    1813       293274 :                             bool leaderFromRight = foeEntryLink->getDirection() < myDirection;
    1814              :                             // leader vehicle should not move towards ego
    1815       293274 :                             if (MSGlobals::gLefthand) {
    1816            0 :                                 leaderFromRight = !leaderFromRight;
    1817              :                             }
    1818       405493 :                             if ((posLat > posLatLeader) == leaderFromRight
    1819              :                                     // leader should keep lateral position or move away from ego
    1820       160268 :                                     && (leader->getLaneChangeModel().getSpeedLat() == 0
    1821        47748 :                                         || leaderFromRight == (leader->getLaneChangeModel().getSpeedLat() < latGap))
    1822       414639 :                                     && (ego->getLaneChangeModel().getSpeedLat() == 0
    1823        16386 :                                         || leaderFromRight == (ego->getLaneChangeModel().getSpeedLat() > -latGap))) {
    1824       112219 :                                 if (gDebugFlag1) {
    1825            0 :                                     std::cout << "   ignored (different source) leaderFromRight=" << leaderFromRight << "\n";
    1826              :                                 }
    1827       112219 :                                 continue;
    1828              :                             }
    1829              :                         } else {
    1830              :                             // XXX figure out relative direction somehow
    1831              :                         }
    1832              :                     } else {
    1833          431 :                         if (gDebugFlag1) {
    1834            0 :                             std::cout << "   ignored oncoming bidi leader\n";
    1835              :                         }
    1836          431 :                         continue;
    1837              :                     }
    1838              :                 }
    1839              :             }
    1840     26828945 :             if (leader->getWaitingTime() < MSGlobals::gIgnoreJunctionBlocker) {
    1841              :                 // compute distance between vehicles on the superimposition of both lanes
    1842              :                 // where the crossing point is the common point
    1843              :                 double gap;
    1844              :                 bool fromLeft = true;
    1845     26337713 :                 if (ego == nullptr) {
    1846              :                     // request from pedestrian model. return distance between leaderBack and crossing point
    1847              :                     //std::cout << "   foeLane=" << foeLane->getID() << " leaderBack=" << leaderBack << " foeDistToCrossing=" << foeDistToCrossing << " foeLength=" << foeLane->getLength() << " foebehind=" << myConflicts[i].second << " dist=" << dist << " behind=" << myConflicts[i].first << "\n";
    1848       111929 :                     gap = leaderBackDist;
    1849              :                     // distToCrossing should not take into account the with of the foe lane
    1850              :                     // (which was subtracted in setRequestInformation)
    1851              :                     // Instead, the width of the foe vehicle is used directly by the caller.
    1852       111929 :                     distToCrossing += myConflicts[i].conflictSize / 2;
    1853       111929 :                     if (gap + foeCrossingWidth < 0) {
    1854              :                         // leader is completely past the crossing point
    1855              :                         // or there is no crossing point
    1856      4674657 :                         continue; // next vehicle
    1857              :                     }
    1858              :                     // we need to determine whether the vehicle passes the
    1859              :                     // crossing from the left or the right (heuristic)
    1860       109788 :                     fromLeft = foeDistToCrossing > 0.5 * foeLane->getLength();
    1861     26225784 :                 } else if ((contLane && !sameSource && !ignoreIndirectBicycleTurn) || isOpposite) {
    1862      1589493 :                     gap = -std::numeric_limits<double>::max(); // always break for vehicles which are on a continuation lane or for opposite-direction vehicles
    1863              :                 } else {
    1864     24636291 :                     if (pastTheCrossingPoint && !sameTarget) {
    1865              :                         // leader is completely past the crossing point
    1866              :                         // or there is no crossing point
    1867      4672437 :                         if (gDebugFlag1) {
    1868            0 :                             std::cout << " foePastCP ignored\n";
    1869              :                         }
    1870      4672437 :                         continue;
    1871              :                     }
    1872              :                     double leaderBackDist2 = leaderBackDist;
    1873     19963854 :                     if (sameTarget && leaderBackDist2 < 0) {
    1874      3071161 :                         const double mismatch = myConflicts[i].getFoeLengthBehindCrossing(foeExitLink) - myConflicts[i].getLengthBehindCrossing(this);
    1875      3071161 :                         if (mismatch > 0) {
    1876      1541716 :                             leaderBackDist2 += mismatch;
    1877              :                         }
    1878              :                     }
    1879     19963854 :                     if (gDebugFlag1) {
    1880              :                         std::cout << " distToCrossing=" << distToCrossing << " leaderBack=" << leaderBack
    1881              :                                   << " backDist=" << leaderBackDist
    1882              :                                   << " backDist2=" << leaderBackDist2
    1883            0 :                                   << " blockedStrategic=" << leader->getLaneChangeModel().isStrategicBlocked()
    1884            0 :                                   << "\n";
    1885              :                     }
    1886     19963854 :                     gap = distToCrossing - ego->getVehicleType().getMinGap() - leaderBackDist2 - foeCrossingWidth;
    1887              :                 }
    1888              :                 // if the foe is already moving off the intersection, we may
    1889              :                 // advance up to the crossing point unless we have the same target or same source
    1890              :                 // (for sameSource, the crossing point indicates the point of divergence)
    1891     25329984 :                 const bool stopAsap = ((leader->isFrontOnLane(foeLane) ? cannotIgnore : (sameTarget || sameSource))
    1892     22214195 :                                        || (ego != nullptr && ego->getVehicleType().getParameter().getJMParam(SUMO_ATTR_JM_ADVANCE, 1.0) == 0.0));
    1893     21663135 :                 if (gDebugFlag1) {
    1894            0 :                     std::cout << " leader=" << leader->getID() << " contLane=" << contLane << " cannotIgnore=" << cannotIgnore << " stopAsap=" << stopAsap << " gap=" << gap << "\n";
    1895              :                 }
    1896     21663135 :                 if (ignoreFoe(ego, leader)) {
    1897           79 :                     continue;
    1898              :                 }
    1899     21663056 :                 const int llFlags = ((fromLeft ? LL_FROM_LEFT : 0) |
    1900     21663056 :                                      (inTheWay ? LL_IN_THE_WAY : 0) |
    1901     21663056 :                                      (sameSource ? LL_SAME_SOURCE : 0) |
    1902     21663056 :                                      (sameTarget ? LL_SAME_TARGET : 0));
    1903     28666690 :                 result.emplace_back(leader, gap, stopAsap ? -1 : distToCrossing, llFlags, leader->getLatOffset(foeLane));
    1904              :             }
    1905              : 
    1906              :         }
    1907    383573641 :         if (ego != nullptr && MSNet::getInstance()->hasPersons()) {
    1908              :             // check for crossing pedestrians (keep driving if already on top of the crossing
    1909      8727499 :             const double distToPeds = distToCrossing - ego->getVehicleType().getParameter().getJMParam(SUMO_ATTR_JM_STOPLINE_CROSSING_GAP, MSPModel::SAFETY_GAP);
    1910      8727499 :             const double vehWidth = ego->getVehicleType().getWidth() + MSPModel::SAFETY_GAP; // + configurable safety gap
    1911              :             /// @todo consider lateral position (depending on whether the crossing is encountered on the way in or out)
    1912              :             // @check lefthand?!
    1913      8727499 :             const bool wayIn = myConflicts[i].lengthBehindCrossing < myLaneBefore->getLength() * 0.5;
    1914      8727499 :             const double vehCenter = (foeDistToCrossing + myLaneBefore->getWidth() * 0.5
    1915      8727499 :                                       + ego->getLateralPositionOnLane() * (wayIn ? -1 : 1));
    1916              :             // can access the movement model here since we already checked for existing persons above
    1917     16971611 :             if (distToPeds >= -MSPModel::SAFETY_GAP && MSNet::getInstance()->getPersonControl().getMovementModel()->blockedAtDist(ego, foeLane, vehCenter, vehWidth,
    1918      8244112 :                     ego->getVehicleType().getParameter().getJMParam(SUMO_ATTR_JM_CROSSING_GAP, JM_CROSSING_GAP_DEFAULT),
    1919              :                     collectBlockers)) {
    1920       519407 :                 result.emplace_back(nullptr, -1, distToPeds);
    1921      8208092 :             } else if (foeLane->isCrossing() && ego->getLane()->isInternal() && ego->getLane()->getEdge().getToJunction() == myJunction) {
    1922       147025 :                 const MSLink* crossingLink = foeLane->getIncomingLanes()[0].viaLink;
    1923       147025 :                 if (distToCrossing > 0 && crossingLink->havePriority() && crossingLink->myApproachingPersons != nullptr) {
    1924              :                     // a person might step on the crossing at any moment, since ego
    1925              :                     // is already on the junction, the opened() check is not done anymore
    1926        26437 :                     const double timeToEnterCrossing = distToCrossing / MAX2(ego->getSpeed(), 1.0);
    1927        31748 :                     for (const auto& item : (*crossingLink->myApproachingPersons)) {
    1928         6875 :                         if (!ignoreFoe(ego, item.first) && timeToEnterCrossing > STEPS2TIME(item.second.arrivalTime - SIMSTEP)) {
    1929         1564 :                             if (gDebugFlag1) {
    1930            0 :                                 std::cout << SIMTIME << ": " << ego->getID() << " breaking for approaching person " << item.first->getID()
    1931              :                                           //<< " dtc=" << distToCrossing << " ttc=" << distToCrossing / MAX2(ego->getSpeed(), 1.0) << " foeAT=" << item.second.arrivalTime << " foeTTC=" << STEPS2TIME(item.second.arrivalTime - SIMSTEP)
    1932            0 :                                           << "\n";
    1933              :                             }
    1934         1564 :                             result.emplace_back(nullptr, -1, distToPeds);
    1935         1564 :                             break;
    1936              :                             //} else {
    1937              :                             //    if (gDebugFlag1) {
    1938              :                             //        std::cout << SIMTIME << ": " << ego->getID() << " notBreaking for approaching person " << item.first->getID()
    1939              :                             //            << " dtc=" << distToCrossing << " ttc=" << distToCrossing / MAX2(ego->getSpeed(), 1.0) << " foeAT=" << item.second.arrivalTime << " foeTTC=" << STEPS2TIME(item.second.arrivalTime - SIMSTEP)
    1940              :                             //            << "\n";
    1941              :                             //    }
    1942              :                         }
    1943              :                     }
    1944              :                 }
    1945              :             }
    1946              :         }
    1947              :     }
    1948              : 
    1949              :     //std::cout << SIMTIME << " ego=" << Named::getIDSecure(ego) << " link=" << getViaLaneOrLane()->getID() << " myWalkingAreaFoe=" << Named::getIDSecure(myWalkingAreaFoe) << "\n";
    1950    290252616 :     if (ego != nullptr) {
    1951    289311431 :         checkWalkingAreaFoe(ego, myWalkingAreaFoe, collectBlockers, result);
    1952    289311431 :         checkWalkingAreaFoe(ego, myWalkingAreaFoeExit, collectBlockers, result);
    1953              :     }
    1954              : 
    1955    290252616 :     if (MSGlobals::gLateralResolution > 0 && ego != nullptr && !isShadowLink) {
    1956              :         // check for foes on the same edge
    1957     71930219 :         for (std::vector<MSLane*>::const_iterator it = mySublaneFoeLanes.begin(); it != mySublaneFoeLanes.end(); ++it) {
    1958      5998977 :             const MSLane* foeLane = *it;
    1959              :             MSLane::AnyVehicleIterator end = foeLane->anyVehiclesEnd();
    1960      4172956 :             for (MSLane::AnyVehicleIterator it_veh = foeLane->anyVehiclesBegin(); it_veh != end; ++it_veh) {
    1961      4172956 :                 MSVehicle* leader = (MSVehicle*)*it_veh;
    1962      4172956 :                 if (leader == ego) {
    1963      2440217 :                     continue;
    1964              :                 }
    1965      3536146 :                 if (leader->getLane()->isNormal()) {
    1966              :                     // leader is past the conflict point
    1967      1352589 :                     continue;
    1968              :                 }
    1969      2183557 :                 const double maxLength = MAX2(myInternalLaneBefore->getLength(), foeLane->getLength());
    1970      2183557 :                 const double gap = dist - maxLength - ego->getVehicleType().getMinGap() + leader->getBackPositionOnLane(foeLane) - extraGap;
    1971      2183557 :                 if (gap < -(ego->getVehicleType().getMinGap() + leader->getLength())) {
    1972              :                     // ego is ahead of leader
    1973       450818 :                     continue;
    1974              :                 }
    1975      1732739 :                 const double posLat = ego->getLateralPositionOnLane();
    1976      1732739 :                 const double posLatLeader = leader->getLateralPositionOnLane() + leader->getLatOffset(foeLane);
    1977      1732739 :                 if (gDebugFlag1) {
    1978            0 :                     std::cout << " sublaneFoe lane=" << myInternalLaneBefore->getID()
    1979              :                               << " foeLane=" << foeLane->getID()
    1980              :                               << " leader=" << leader->getID()
    1981            0 :                               << " egoLane=" << ego->getLane()->getID()
    1982            0 :                               << " leaderLane=" << leader->getLane()->getID()
    1983              :                               << " gap=" << gap
    1984              :                               << " egoLat=" << posLat
    1985              :                               << " leaderLat=" << posLatLeader
    1986            0 :                               << " leaderLatOffset=" << leader->getLatOffset(foeLane)
    1987            0 :                               << " egoIndex=" << myInternalLaneBefore->getIndex()
    1988            0 :                               << " foeIndex=" << foeLane->getIndex()
    1989            0 :                               << " dist=" << dist
    1990            0 :                               << " leaderBack=" << leader->getBackPositionOnLane(foeLane)
    1991            0 :                               << "\n";
    1992              :                 }
    1993              :                 // there only is a conflict if the paths cross
    1994       695860 :                 if ((posLat < posLatLeader && myInternalLaneBefore->getIndex() > foeLane->getIndex())
    1995      2060630 :                         || (posLat > posLatLeader && myInternalLaneBefore->getIndex() < foeLane->getIndex())) {
    1996       796679 :                     if (gDebugFlag1) {
    1997            0 :                         std::cout << SIMTIME << " blocked by " << leader->getID() << " (sublane split) foeLane=" << foeLane->getID() << "\n";
    1998              :                     }
    1999       796679 :                     if (ignoreFoe(ego, leader)) {
    2000            0 :                         continue;
    2001              :                     }
    2002       796679 :                     result.emplace_back(leader, gap, -1);
    2003              :                 }
    2004              :             }
    2005              :         }
    2006              :     }
    2007              :     return result;
    2008            3 : }
    2009              : 
    2010              : 
    2011              : void
    2012    578622862 : MSLink::checkWalkingAreaFoe(const MSVehicle* ego, const MSLane* foeLane, std::vector<const MSPerson*>* collectBlockers, LinkLeaders& result) const {
    2013    578622862 :     if (foeLane != nullptr && foeLane->getEdge().getPersons().size() > 0) {
    2014              :         // pedestrians may be on an arbitrary path across this
    2015              :         // walkingarea. make sure to keep enough distance.
    2016              :         // This is a simple but conservative solution that could be improved
    2017              :         // by ignoring pedestrians that are "obviously" not on a collision course
    2018       125722 :         double distToPeds = std::numeric_limits<double>::max();
    2019              :         assert(myInternalLaneBefore != nullptr);
    2020       125722 :         PositionVector egoPath = myInternalLaneBefore->getShape();
    2021       125722 :         if (ego->getLateralPositionOnLane() != 0) {
    2022       107434 :             egoPath.move2side((MSGlobals::gLefthand ? 1 : -1) * ego->getLateralPositionOnLane());
    2023              :         }
    2024       959871 :         for (MSTransportable* t : foeLane->getEdge().getPersons()) {
    2025       834149 :             MSPerson* p = static_cast<MSPerson*>(t);
    2026       834149 :             double dist = ego->getPosition().distanceTo2D(p->getPosition()) - p->getVehicleType().getLength();
    2027       834149 :             const bool inFront = isInFront(ego, egoPath, p->getPosition()) || isInFront(ego, egoPath, getFuturePosition(p));
    2028              :             if (inFront) {
    2029       305944 :                 dist -= MAX2(ego->getVehicleType().getMinGap(), MSPModel::SAFETY_GAP);
    2030              :             }
    2031              : #ifdef DEBUG_WALKINGAREA
    2032              :             if (ego->isSelected()) {
    2033              :                 std::cout << SIMTIME << " veh=" << ego->getID() << " ped=" << p->getID()
    2034              :                           << " pos=" << ego->getPosition() << " pedPos=" << p->getPosition()
    2035              :                           << " futurePedPos=" << getFuturePosition(p)
    2036              :                           << " rawDist=" << ego->getPosition().distanceTo2D(p->getPosition())
    2037              :                           << " inFront=" << inFront
    2038              :                           << " dist=" << dist << "\n";
    2039              :             }
    2040              : #endif
    2041       834149 :             if (dist < ego->getVehicleType().getWidth() / 2 || inFront) {
    2042       153263 :                 if (inFront) {
    2043       152972 :                     const double oncomingFactor = isOnComingPed(ego, p);
    2044       152972 :                     if (oncomingFactor > 0) {
    2045              :                         // account for pedestrian movement while closing in
    2046        53953 :                         const double timeToStop = sqrt(dist) / 2;
    2047        53953 :                         const double pedDist = p->getMaxSpeed() * MAX2(timeToStop, TS) * oncomingFactor;
    2048        53953 :                         dist = MAX2(0.0, dist - pedDist);
    2049              : #ifdef DEBUG_WALKINGAREA
    2050              :                         if (ego->isSelected()) {
    2051              :                             std::cout << "    timeToStop=" << timeToStop << " pedDist=" << pedDist << " factor=" << oncomingFactor << " dist2=" << dist << "\n";
    2052              :                         }
    2053              : #endif
    2054              :                     }
    2055              :                 }
    2056       153263 :                 if (ignoreFoe(ego, p)) {
    2057        25237 :                     continue;
    2058              :                 }
    2059       128026 :                 distToPeds = MIN2(distToPeds, dist);
    2060       128026 :                 if (collectBlockers != nullptr) {
    2061            0 :                     collectBlockers->push_back(p);
    2062              :                 }
    2063              :             }
    2064              :         }
    2065       125722 :         if (distToPeds != std::numeric_limits<double>::max()) {
    2066              :             // leave extra space in front
    2067        87106 :             result.emplace_back(nullptr, -1, distToPeds);
    2068              :         }
    2069       125722 :     }
    2070    578622862 : }
    2071              : 
    2072              : bool
    2073      1531703 : MSLink::isInFront(const MSVehicle* ego, const PositionVector& egoPath, const Position& pPos) const {
    2074      1531703 :     const double pedAngle = ego->getPosition().angleTo2D(pPos);
    2075      1531703 :     const double angleDiff = fabs(GeomHelper::angleDiff(ego->getAngle(), pedAngle));
    2076              : #ifdef DEBUG_WALKINGAREA
    2077              :     if (ego->isSelected()) {
    2078              :         std::cout << " angleDiff=" << RAD2DEG(angleDiff) << "\n";
    2079              :     }
    2080              : #endif
    2081      1531703 :     if (angleDiff < DEG2RAD(75)) {
    2082      1082850 :         return egoPath.distance2D(pPos) < ego->getVehicleType().getWidth() + MSPModel::SAFETY_GAP;
    2083              :     }
    2084              :     return false;
    2085              : }
    2086              : 
    2087              : 
    2088              : double
    2089       152972 : MSLink::isOnComingPed(const MSVehicle* ego, const MSPerson* p) const {
    2090       152972 :     const double pedToEgoAngle = p->getPosition().angleTo2D(ego->getPosition());
    2091       152972 :     const double angleDiff = fabs(GeomHelper::angleDiff(p->getAngle(), pedToEgoAngle));
    2092              : #ifdef DEBUG_WALKINGAREA
    2093              :     if (ego->isSelected()) {
    2094              :         std::cout << " ped-angleDiff=" << RAD2DEG(angleDiff) << " res=" << cos(angleDiff) << "\n";
    2095              :     }
    2096              : #endif
    2097       152972 :     if (angleDiff <= DEG2RAD(90)) {
    2098              :         ;
    2099        53953 :         return cos(angleDiff);
    2100              :     } else {
    2101              :         return 0;
    2102              :     }
    2103              : }
    2104              : 
    2105              : 
    2106              : Position
    2107       697554 : MSLink::getFuturePosition(const MSPerson* p, double timeHorizon) const {
    2108       697554 :     const double a = p->getAngle();
    2109       697554 :     const double dist = timeHorizon * p->getMaxSpeed();
    2110              : 
    2111       697554 :     const Position offset(cos(a) * dist, sin(a) * dist);
    2112       697554 :     return p->getPosition() + offset;
    2113              : }
    2114              : 
    2115              : 
    2116              : MSLink*
    2117     10495238 : MSLink::getParallelLink(int direction) const {
    2118     10495238 :     if (direction == -1) {
    2119      4028692 :         return myParallelRight;
    2120      6466546 :     } else if (direction == 1) {
    2121      5784573 :         return myParallelLeft;
    2122              :     } else {
    2123              :         assert(false || myLane->getOpposite() != nullptr || MSGlobals::gComputeLC);
    2124              :         return nullptr;
    2125              :     }
    2126              : }
    2127              : 
    2128              : MSLink*
    2129       169638 : MSLink::getOppositeDirectionLink() const {
    2130       169638 :     if (myLane->getOpposite() != nullptr && myLaneBefore->getOpposite() != nullptr) {
    2131        42686 :         for (MSLink* cand : myLane->getOpposite()->getLinkCont()) {
    2132        39514 :             if (cand->getLane() == myLaneBefore->getOpposite()) {
    2133              :                 return cand;
    2134              :             }
    2135              :         }
    2136              :     }
    2137              :     return nullptr;
    2138              : }
    2139              : 
    2140              : 
    2141              : MSLink*
    2142      5859876 : MSLink::computeParallelLink(int direction) {
    2143      5859876 :     const MSLane* const before = getLaneBefore()->getParallelLane(direction, false);
    2144      5859876 :     const MSLane* const after = getLane()->getParallelLane(direction, false);
    2145      5859876 :     if (before != nullptr && after != nullptr) {
    2146       995139 :         for (MSLink* const link : before->getLinkCont()) {
    2147       657017 :             if (link->getLane() == after) {
    2148              :                 return link;
    2149              :             }
    2150              :         }
    2151              :     }
    2152              :     return nullptr;
    2153              : }
    2154              : 
    2155              : 
    2156              : double
    2157      1327198 : MSLink::getZipperSpeed(const MSVehicle* ego, const double dist, double vSafe,
    2158              :                        SUMOTime arrivalTime,
    2159              :                        const BlockingFoes* foes) const {
    2160      1327198 :     if (myFoeLinks.size() == 0) {
    2161              :         // link should have LINKSTATE_MAJOR in this case
    2162              :         assert(false);
    2163              :         return vSafe;
    2164              :     }
    2165      1327198 :     const double brakeGap = ego->getCarFollowModel().brakeGap(vSafe, ego->getCarFollowModel().getMaxDecel(), TS);
    2166      1442573 :     if (dist > MAX2(myFoeVisibilityDistance, brakeGap)) {
    2167              : #ifdef DEBUG_ZIPPER
    2168              :         const SUMOTime now = MSNet::getInstance()->getCurrentTimeStep();
    2169              :         DEBUGOUT(DEBUG_COND_ZIPPER, SIMTIME << " getZipperSpeed ego=" << ego->getID()
    2170              :                  << " dist=" << dist << " bGap=" << brakeGap << " ignoring foes (arrival in " << STEPS2TIME(arrivalTime - now) << ")\n")
    2171              : #endif
    2172              :         return vSafe;
    2173              :     }
    2174              : #ifdef DEBUG_ZIPPER
    2175              :     DEBUGOUT(DEBUG_COND_ZIPPER, SIMTIME << " getZipperSpeed ego=" << ego->getID()
    2176              :              << " egoAT=" << arrivalTime
    2177              :              << " dist=" << dist
    2178              :              << " brakeGap=" << brakeGap
    2179              :              << " vSafe=" << vSafe
    2180              :              << " numFoes=" << foes->size()
    2181              :              << "\n")
    2182              : #endif
    2183              :     const bool uniqueFoeLink = myFoeLinks.size() == 1;
    2184       496173 :     MSLink* foeLink = myFoeLinks[0];
    2185      2597487 :     for (const auto& item : *foes) {
    2186      2101314 :         if (!item->isVehicle()) {
    2187            0 :             continue;
    2188              :         }
    2189      2101314 :         const MSVehicle* foe = dynamic_cast<const MSVehicle*>(item);
    2190              :         assert(foe != 0);
    2191              :         const ApproachingVehicleInformation* aviPtr = nullptr;
    2192      2101314 :         if (uniqueFoeLink) {
    2193      1396081 :             aviPtr = foeLink->getApproachingPtr(foe);
    2194              :         } else {
    2195              :             // figure out which link is approached by the current foe
    2196      1067476 :             for (MSLink* fl : myFoeLinks) {
    2197      1067476 :                 aviPtr = fl->getApproachingPtr(foe);
    2198      1067476 :                 if (aviPtr != nullptr) {
    2199              :                     break;
    2200              :                 }
    2201              :             }
    2202              :         }
    2203      2101314 :         if (aviPtr == nullptr) {
    2204            0 :             continue;
    2205              :         }
    2206              :         const ApproachingVehicleInformation& avi = *aviPtr;
    2207      2101314 :         const double foeDist = (foe->isActive() ? avi.dist : MAX2(0.0, avi.dist -
    2208           36 :                                 STEPS2TIME(MSNet::getInstance()->getCurrentTimeStep() - foe->getLastActionTime()) * avi.speed));
    2209              : 
    2210      1428338 :         if (    // ignore vehicles that arrive after us (unless they are ahead and we could easily brake for them)
    2211      2202076 :             ((avi.arrivalTime > arrivalTime) && !couldBrakeForLeader(dist, foeDist, ego, foe)) ||
    2212              :             // also ignore vehicles that are behind us and are able to brake for us
    2213      2202076 :             couldBrakeForLeader(foeDist, dist, foe, ego) ||
    2214              :             // resolve ties by lane index
    2215       672984 :             (avi.arrivalTime == arrivalTime && foeDist == dist && ego->getLane()->getIndex() < foe->getLane()->getIndex())) {
    2216              : #ifdef DEBUG_ZIPPER
    2217              :             if (DEBUG_COND_ZIPPER) std::cout
    2218              :                         << "    ignoring foe=" << foe->getID()
    2219              :                         << " foeAT=" << avi.arrivalTime
    2220              :                         << " foeDist=" << avi.dist
    2221              :                         << " foeDist2=" << foeDist
    2222              :                         << " foeSpeed=" << avi.speed
    2223              :                         << " egoSpeed=" << ego->getSpeed()
    2224              :                         << " deltaDist=" << foeDist - dist
    2225              :                         << " delteSpeed=" << avi.speed - foe->getCarFollowModel().getMaxDecel() - ego->getSpeed()
    2226              :                         << " egoCouldBrake=" << couldBrakeForLeader(dist, foeDist, ego, foe)
    2227              :                         << " foeCouldBrake=" << couldBrakeForLeader(foeDist, dist, foe, ego)
    2228              :                         << "\n";
    2229              : #endif
    2230      1428338 :             continue;
    2231              :         }
    2232              :         // the idea behind speed adaption is three-fold:
    2233              :         // 1) ego needs to be in a car-following relationship with foe eventually
    2234              :         //    thus, the ego speed should be equal to the follow speed once the foe enters
    2235              :         //    the zipper junction
    2236              :         // 2) ego vehicle needs to put a certain distance beteen himself and foe (safeGap)
    2237              :         //    achieving this distance can be spread over time but computing
    2238              :         //    safeGap is subject to estimation errors of future speeds
    2239              :         // 3) deceleration can be spread out over the time until true
    2240              :         //    car-following happens, at the start of speed adaptions, smaller
    2241              :         //    decelerations should be sufficient
    2242              : 
    2243              :         // we cannot trust avi.arrivalSpeed if the foe has leader vehicles that are accelerating
    2244              :         // lets try to extrapolate
    2245       672976 :         const double uMax = foe->getLane()->getVehicleMaxSpeed(foe);
    2246       672976 :         const double uAccel = foe->getCarFollowModel().estimateSpeedAfterDistance(foeDist, avi.speed, foe->getCarFollowModel().getMaxAccel());
    2247              :         const double uEnd = MIN2(uMax, uAccel);
    2248       672976 :         const double uAvg = (avi.speed + uEnd) / 2;
    2249       672976 :         const double tf0 = foeDist / MAX2(NUMERICAL_EPS, uAvg);
    2250       672976 :         const double tf = MAX2(1.0, ceil((tf0) / TS) * TS);
    2251              : 
    2252       672976 :         const double vMax = ego->getLane()->getVehicleMaxSpeed(ego);
    2253       672976 :         const double vAccel = ego->getCarFollowModel().estimateSpeedAfterDistance(dist, ego->getSpeed(), ego->getCarFollowModel().getMaxAccel());
    2254       672976 :         const double vDecel = ego->getCarFollowModel().estimateSpeedAfterDistance(dist, ego->getSpeed(), -ego->getCarFollowModel().getMaxDecel());
    2255              :         const double vEnd = MIN3(vMax, vAccel, MAX2(uEnd, vDecel));
    2256       672976 :         const double vAvg = (ego->getSpeed() + vEnd) / 2;
    2257       672976 :         const double te0 = dist / MAX2(NUMERICAL_EPS, vAvg);
    2258       672976 :         const double te = MAX2(1.0, ceil((te0) / TS) * TS);
    2259              : 
    2260       672976 :         const double tTarget = tf + ego->getCarFollowModel().getHeadwayTime();
    2261       672976 :         const double a = ego->getCarFollowModel().avoidArrivalAccel(dist, tTarget, vSafe, ego->getCarFollowModel().getMaxDecel());
    2262              : 
    2263       672976 :         const double gap = dist - foe->getVehicleType().getLength() - ego->getVehicleType().getMinGap() - foeDist;
    2264       672976 :         const double vFollow = ego->getCarFollowModel().followSpeed(
    2265       672976 :                                    ego, ego->getSpeed(), gap, avi.speed, foe->getCarFollowModel().getMaxDecel(), foe);
    2266       672976 :         const double vSafeGap = MAX2(vFollow, ego->getSpeed() + ACCEL2SPEED(a));
    2267              : 
    2268              :         // scale behavior based on ego time to link (te)
    2269       672976 :         const double w = MIN2(1.0, te / 10);
    2270       672976 :         const double maxDecel = w * ego->getCarFollowModel().getMaxDecel() + (1 - w) * ego->getCarFollowModel().getEmergencyDecel();
    2271       672976 :         const double vZipper = MAX3(vFollow, ego->getSpeed() - ACCEL2SPEED(maxDecel), vSafeGap);
    2272              : 
    2273              :         vSafe = MIN2(vSafe, vZipper);
    2274              : #ifdef DEBUG_ZIPPER
    2275              :         if (DEBUG_COND_ZIPPER) std::cout << "    adapting to foe=" << foe->getID()
    2276              :                                              << " foeDist=" << foeDist
    2277              :                                              << " foeSpeed=" << avi.speed
    2278              :                                              << " foeAS=" << avi.arrivalSpeed
    2279              :                                              << " egoSpeed=" << ego->getSpeed()
    2280              :                                              << " uMax=" << uMax
    2281              :                                              << " uAccel=" << uAccel
    2282              :                                              << " uEnd=" << uEnd
    2283              :                                              << " uAvg=" << uAvg
    2284              :                                              << " gap=" << gap
    2285              :                                              << "\n      "
    2286              :                                              << " tf=" << tf
    2287              :                                              << " te=" << te
    2288              :                                              << " aSafeGap=" << a
    2289              :                                              << " vMax=" << vMax
    2290              :                                              << " vAccel=" << vAccel
    2291              :                                              << " vDecel=" << vDecel
    2292              :                                              << " vEnd=" << vEnd
    2293              :                                              << " vSafeGap=" << vSafeGap
    2294              :                                              << " vFollow=" << vFollow
    2295              :                                              << " w=" << w
    2296              :                                              << " maxDecel=" << maxDecel
    2297              :                                              << " vZipper=" << vZipper
    2298              :                                              << " vSafe=" << vSafe
    2299              :                                              << "\n";
    2300              : #endif
    2301              :     }
    2302              :     return vSafe;
    2303              : }
    2304              : 
    2305              : 
    2306              : bool
    2307      2202076 : MSLink::couldBrakeForLeader(double followDist, double leaderDist, const MSVehicle* follow, const MSVehicle* leader) {
    2308              :     return (// leader is ahead of follower
    2309      2202076 :                followDist > leaderDist &&
    2310              :                // and follower could brake for 1 s to stay behind leader
    2311       397310 :                followDist - leaderDist > follow->getSpeed() - follow->getCarFollowModel().getMaxDecel() - leader->getSpeed());
    2312              : }
    2313              : 
    2314              : 
    2315              : void
    2316      2929938 : MSLink::initParallelLinks() {
    2317      2929938 :     myParallelRight = computeParallelLink(-1);
    2318      2929938 :     myParallelLeft = computeParallelLink(1);
    2319      2929938 : }
    2320              : 
    2321              : bool
    2322        73418 : MSLink::checkContOff() const {
    2323              :     // check whether this link gets to keep its cont status switching the tls off
    2324              :     // @note: this could also be pre-computed in netconvert
    2325              :     // we check whether there is any major link from this edge
    2326       218884 :     for (const MSLane* cand : myLaneBefore->getEdge().getLanes()) {
    2327       433583 :         for (const MSLink* link : cand->getLinkCont()) {
    2328       288117 :             if (link->getOffState() == LINKSTATE_TL_OFF_NOSIGNAL) {
    2329              :                 return true;
    2330              :             }
    2331              :         }
    2332              :     }
    2333              :     return false;
    2334              : }
    2335              : 
    2336              : bool
    2337      4347155 : MSLink::lateralOverlap(double posLat, double width, double posLat2, double width2) {
    2338      4347155 :     return fabs(posLat2 - posLat) < (width + width2) / 2;
    2339              : }
    2340              : 
    2341              : std::string
    2342            0 : MSLink::getDescription() const {
    2343            0 :     return myLaneBefore->getID() + "->" + getViaLaneOrLane()->getID();
    2344              : }
    2345              : 
    2346              : 
    2347              : bool
    2348    188333363 : MSLink::ignoreFoe(const SUMOTrafficObject* ego, const SUMOTrafficObject* foe) {
    2349    188333363 :     if (ego == nullptr || !ego->getParameter().wasSet(VEHPARS_JUNCTIONMODEL_PARAMS_SET)) {
    2350    188300924 :         return false;
    2351              :     }
    2352        32439 :     const SUMOVehicleParameter& param = ego->getParameter();
    2353        71050 :     for (const std::string& typeID : StringTokenizer(param.getParameter(toString(SUMO_ATTR_JM_IGNORE_TYPES), "")).getVector()) {
    2354        31537 :         if (typeID == foe->getVehicleType().getID()) {
    2355              :             return true;
    2356              :         }
    2357        32439 :     }
    2358        16136 :     for (const std::string& id : StringTokenizer(param.getParameter(toString(SUMO_ATTR_JM_IGNORE_IDS), "")).getVector()) {
    2359         2291 :         if (id == foe->getID()) {
    2360              :             return true;
    2361              :         }
    2362         7074 :     }
    2363         6771 :     return false;
    2364              : }
    2365              : 
    2366              : 
    2367              : void
    2368       112041 : MSLink::updateDistToFoePedCrossing(double dist) {
    2369       112041 :     myDistToFoePedCrossing = MIN2(myDistToFoePedCrossing, dist);
    2370       112041 : }
    2371              : 
    2372              : 
    2373              : std::pair<const SUMOVehicle* const, const MSLink::ApproachingVehicleInformation>
    2374      8917927 : MSLink::getClosest() const {
    2375              :     assert(getApproaching().size() > 0);
    2376              :     double minDist = std::numeric_limits<double>::max();
    2377              :     auto closestIt = getApproaching().begin();
    2378     17836478 :     for (auto apprIt = getApproaching().begin(); apprIt != getApproaching().end(); apprIt++) {
    2379      8918551 :         if (apprIt->second.dist < minDist) {
    2380              :             minDist = apprIt->second.dist;
    2381              :             closestIt = apprIt;
    2382              :         }
    2383              :     }
    2384              :     // maybe a parallel link has a closer vehicle
    2385              :     /*
    2386              :     for (MSLink* link2 : link->getLaneBefore()->getLinkCont()) {
    2387              :         if (link2 != link) {
    2388              :             for (auto apprIt2 = link2->getApproaching().begin(); apprIt2 != link2->getApproaching().end(); apprIt2++) {
    2389              :                 if (apprIt2->second.dist < minDist) {
    2390              :                     minDist = apprIt2->second.dist;
    2391              :                     closestIt = apprIt2;
    2392              :                 }
    2393              :             }
    2394              :         }
    2395              :     }
    2396              :     */
    2397      8917927 :     return *closestIt;
    2398              : }
    2399              : 
    2400              : 
    2401              : bool
    2402       472333 : MSLink::railSignalWasPassed() const {
    2403       472333 :     if (myJunction != nullptr && myJunction->getType() == SumoXMLNodeType::RAIL_SIGNAL) {
    2404         2006 :         for (const auto& item : myApproachingVehicles) {
    2405            9 :             if (item.second.dist < SPEED2DIST(item.first->getSpeed())) {
    2406              :                 return true;
    2407              :             }
    2408              :         }
    2409              :     }
    2410              :     return false;
    2411              : }
    2412              : 
    2413              : /****************************************************************************/
        

Generated by: LCOV version 2.0-1