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-07-05 15:55:58 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    483527455 : MSLink::ConflictInfo::getFoeLengthBehindCrossing(const MSLink* foeExitLink) const {
      84    483527455 :     if (flag == CONFLICT_DUMMY_MERGE) {
      85              :         return 0;
      86    473641527 :     } else if (foeConflictIndex >= 0) {
      87    451526807 :         return foeExitLink->myConflicts[foeConflictIndex].lengthBehindCrossing;
      88              :     } else {
      89              :         return -NO_INTERSECTION;
      90              :     }
      91              : }
      92              : 
      93              : double
      94    250500214 : MSLink::ConflictInfo::getFoeConflictSize(const MSLink* foeExitLink) const {
      95    250500214 :     if (foeConflictIndex >= 0) {
      96    228454686 :         return foeExitLink->myConflicts[foeConflictIndex].conflictSize;
      97              :     } else {
      98              :         return 0;
      99              :     }
     100              : }
     101              : 
     102              : double
     103    483658469 : MSLink::ConflictInfo::getLengthBehindCrossing(const MSLink* exitLink) const {
     104    483658469 :     if (flag == CONFLICT_STOP_AT_INTERNAL_JUNCTION) {
     105     20032987 :         return exitLink->getInternalLaneBefore()->getLength();
     106              :     } else {
     107    463625482 :         return lengthBehindCrossing;
     108              :     }
     109              : }
     110              : 
     111              : // ===========================================================================
     112              : // member method definitions
     113              : // ===========================================================================
     114      2920605 : 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      2920605 :                bool indirect) :
     118      2920605 :     myLane(succLane),
     119      2920605 :     myLaneBefore(predLane),
     120      2920605 :     myApproachingPersons(nullptr),
     121      2920605 :     myIndex(-1),
     122      2920605 :     myTLIndex(tlIndex),
     123      2920605 :     myLogic(logic),
     124      2920605 :     myState(state),
     125      2920605 :     myLastGreenState(LINKSTATE_TL_GREEN_MINOR),
     126      2920605 :     myOffState(state),
     127      2920605 :     myLastStateChange(SUMOTime_MIN / 2), // a large negative value, but avoid overflows when subtracting
     128      2920605 :     myDirection(dir),
     129      2920605 :     myLength(length),
     130      2920605 :     myFoeVisibilityDistance(foeVisibilityDistance),
     131      2920605 :     myDistToFoePedCrossing(std::numeric_limits<double>::max()),
     132      2920605 :     myHasFoes(false),
     133      2920605 :     myAmCont(false),
     134      2920605 :     myAmContOff(false),
     135      2920605 :     myKeepClear(keepClear),
     136      2920605 :     myInternalLane(via),
     137      2920605 :     myInternalLaneBefore(nullptr),
     138      2920605 :     myMesoTLSPenalty(0),
     139      2920605 :     myGreenFraction(1),
     140      2920605 :     myLateralShift(0),
     141      2920605 :     myOffFoeLinks(nullptr),
     142      2920605 :     myWalkingAreaFoe(nullptr),
     143      2920605 :     myWalkingAreaFoeExit(nullptr),
     144      2920605 :     myHavePedestrianCrossingFoe(false),
     145      2920605 :     myParallelRight(nullptr),
     146      2920605 :     myParallelLeft(nullptr),
     147      2920605 :     myAmIndirect(indirect),
     148      2920605 :     myRadius(std::numeric_limits<double>::max()),
     149      2920605 :     myPermissions(myLaneBefore->getPermissions() & myLane->getPermissions() & (via == nullptr ? SVCAll : via->getPermissions())),
     150      2920605 :     myJunction(nullptr) {
     151              : 
     152      2920605 :     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       206049 :         if ((myInternalLane != nullptr || predLane->isInternal())
     156       514865 :                 && 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      2920605 : }
     173              : 
     174              : 
     175      2892886 : MSLink::~MSLink() {
     176      2892886 :     delete myOffFoeLinks;
     177      2894220 :     delete myApproachingPersons;
     178      2892886 : }
     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      3977340 : MSLink::getCustomConflict(const MSLane* foeLane) const {
     188      3977340 :     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      2640370 : 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      2640370 :     myIndex = index;
     212      2640370 :     myHasFoes = hasFoes;
     213      2640370 :     myAmCont = isCont && MSGlobals::gUsingInternalLanes;
     214      2640370 :     myFoeLinks = foeLinks;
     215      9954182 :     for (MSLane* foeLane : foeLanes) {
     216              :         // cannot assign vector due to const-ness
     217      7313812 :         myFoeLanes.push_back(foeLane);
     218              :     }
     219      2640370 :     myJunction = const_cast<MSJunction*>(myLane->getEdge().getFromJunction()); // junctionGraph is initialized after the whole network is loaded
     220      2640370 :     myAmContOff = isCont && myLogic != nullptr && internalLaneBefore == nullptr && checkContOff();
     221      2640370 :     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      2640370 :     const MSLink* entryLink = getCorrespondingEntryLink();
     232      2640370 :     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      2640370 :     if (lane != nullptr) {
     250      1009259 :         const bool beforeInternalJunction = lane->getLinkCont()[0]->getViaLaneOrLane()->getEdge().isInternal();
     251      1009259 :         if (lane->getIncomingLanes().size() != 1) {
     252            0 :             throw ProcessError(TLF("Internal lane '%' has % predecessors", lane->getID(), toString(lane->getIncomingLanes().size())));
     253              :         }
     254      1009259 :         const MSLink* junctionEntryLink = lane->getEntryLink();
     255      1009259 :         const bool isSecondPart = isExitLinkAfterInternalJunction();
     256              :         // compute crossing points
     257      5144936 :         for (const MSLane* foeLane : myFoeLanes) {
     258      4135677 :             const CustomConflict* cc = junctionEntryLink != nullptr ? junctionEntryLink->getCustomConflict(foeLane) : nullptr;
     259      3977328 :             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      4135665 :             myHavePedestrianCrossingFoe = myHavePedestrianCrossingFoe || foeLane->isCrossing();
     306      4135665 :             const bool sameTarget = myLane == foeLane->getLinkCont()[0]->getLane();
     307      4135665 :             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      1378943 :                 const double minDist = MIN2(DIVERGENCE_MIN_WIDTH, 0.5 * (lane->getWidth() + foeLane->getWidth()));
     311      1378943 :                 if (lane->getShape().back().distanceTo2D(foeLane->getShape().back()) >= minDist) {
     312              :                     // account for lateral shift by the entry links
     313       125769 :                     if (foeLane->getEntryLink()->isIndirect()) {
     314           41 :                         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       125728 :                         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      1253174 :                     const double distAfterDivergence = computeDistToDivergence(lane, foeLane, minDist, false);
     326              :                     const double lbcLane = lane->interpolateGeometryPosToLanePos(distAfterDivergence);
     327      1253174 :                     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      2756722 :                 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      2756722 :                 if (intersections1.size() == 0) {
     344      1429561 :                     intersections1.push_back(-NO_INTERSECTION); // disregard this foe (using maxdouble leads to nasty problems down the line)
     345              :                     haveIntersection = false;
     346      1327161 :                 } else if (intersections1.size() > 1) {
     347         1306 :                     std::sort(intersections1.begin(), intersections1.end());
     348              :                 }
     349      2756722 :                 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      2756722 :                 if (intersections2.size() == 0) {
     354      1429561 :                     intersections2.push_back(0);
     355      1327161 :                 } else if (intersections2.size() > 1) {
     356         1306 :                     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      2756722 :                 if (!haveIntersection && foeLane->getLinkCont()[0]->getViaLane() != nullptr) {
     361       257575 :                     const Position waitPos = foeLane->getShape().back();
     362       257575 :                     const double dist = lane->getShape().distance2D(waitPos, true);
     363       257575 :                     if (dist != GeomHelper::INVALID_OFFSET && dist < lane->getWidth() / 2) {
     364              :                         // risk of collision
     365              :                         intersections1.clear();
     366              :                         intersections2.clear();
     367        29540 :                         intersections1.push_back(lane->getShape().nearest_offset_to_point2D(waitPos));
     368        29540 :                         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      2727182 :                 if (haveIntersection) {
     379              :                     flag = CONFLICT_DEFAULT;
     380      1356701 :                     const double angle1 = GeomHelper::naviDegree(lane->getShape().rotationAtOffset(intersections1.back()));
     381      1356701 :                     const double angle2 = GeomHelper::naviDegree(foeLane->getShape().rotationAtOffset(intersections2.back()));
     382      1356701 :                     const double angleDiff = GeomHelper::getMinAngleDiff(angle1, angle2);
     383              :                     //const double angleDiff = MIN2(GeomHelper::getMinAngleDiff(angle1, angle2),
     384              :                     //                              GeomHelper::getMinAngleDiff(angle1, angle2 + 180));
     385      1356701 :                     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      1356701 :                     conflictSize *= widthFactor;
     388              :                     conflictSize = MIN2(conflictSize, lane->getLength());
     389              :                     // lane width affects the crossing point
     390      1356701 :                     intersections1.back() -= conflictSize / 2;
     391              :                     // ensure non-negative offset for weird geometries
     392      1356701 :                     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      1356701 :                     intersections1.back() = lane->interpolateGeometryPosToLanePos(intersections1.back());
     396              : 
     397      1356701 :                     if (internalLaneBefore->getLogicalPredecessorLane()->getEdge().isInternal() && !foeLane->isCrossing())  {
     398              :                         flag = CONFLICT_STOP_AT_INTERNAL_JUNCTION;
     399              :                     }
     400              : 
     401      1356701 :                     if (foeLane->isCrossing()) {
     402       110858 :                         const MSLink* before = myInternalLaneBefore->getCanonicalPredecessorLane()->getLinkTo(myInternalLaneBefore);
     403       110858 :                         const_cast<MSLink*>(before)->updateDistToFoePedCrossing(intersections1.back());
     404              :                     };
     405              :                 }
     406              : 
     407      2756722 :                 myConflicts.push_back(ConflictInfo(
     408      2756722 :                                           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      2756722 :             }
     422              :         }
     423              :         // check for overlap with internal lanes from the same source lane
     424      1009259 :         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      3290090 :         for (const MSLink* const link : pred->getLinkCont()) {
     428      2280831 :             const MSLane* const sibling = link->getViaLane();
     429      2280831 :             if (sibling != lane && sibling != nullptr) {
     430      1246784 :                 const double minDist = MIN2(DIVERGENCE_MIN_WIDTH, 0.5 * (lane->getWidth() + sibling->getWidth()));
     431      1246784 :                 if (lane->getShape().front().distanceTo2D(sibling->getShape().front()) >= minDist) {
     432              :                     // account for lateral shift by the entry links
     433          630 :                     continue;
     434              :                 }
     435      1246154 :                 const double distToDivergence = computeDistToDivergence(lane, sibling, minDist, true);
     436              :                 double lbcLane;
     437      1246154 :                 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        18150 :                     lbcLane = lane->getLength() - distToDivergence;
     442              :                 } else {
     443      1228004 :                     lbcLane = MAX2(0.0, lane->getLength() - lane->interpolateGeometryPosToLanePos(distToDivergence));
     444              :                 }
     445              :                 ConflictInfo ci = ConflictInfo(lbcLane, sibling->getWidth());
     446      1246154 :                 auto it = std::find(myFoeLanes.begin(), myFoeLanes.end(), sibling);
     447      1246154 :                 if (it != myFoeLanes.end()) {
     448              :                     // avoid duplicate foeLane
     449           90 :                     const int replacedIndex = (int)(it - myFoeLanes.begin());
     450           90 :                     myConflicts[replacedIndex] = ci;
     451              :                 } else {
     452      1246064 :                     myConflicts.push_back(ci);
     453      1246064 :                     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      1246154 :                 const MSLane* const siblingCont = sibling->getLinkCont().front()->getViaLaneOrLane();
     461      1246154 :                 if (siblingCont->isInternal() && lane->getShape().distance2D(siblingCont->getShape().front()) < minDist) {
     462              :                     // there may still be overlap with siblingCont (when considering vehicle widths)
     463       283041 :                     const double maxCommonLength = MIN2(lane->getLength(), sibling->getLength() + siblingCont->getLength());
     464       283041 :                     const double lengthBehindDivergence = MAX2(0.0, lane->getLength() - maxCommonLength);
     465              :                     ConflictInfo ci2 = ConflictInfo(lengthBehindDivergence, siblingCont->getWidth(), CONFLICT_SIBLING_CONTINUATION);
     466       283041 :                     myConflicts.push_back(ci2);
     467       283041 :                     myFoeLanes.push_back(siblingCont);
     468       283041 :                     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      6674041 :         for (int i = 0; i < (int)myFoeLanes.size(); i++) {
     481      5664782 :             const MSLane* foeLane = myFoeLanes[i];
     482      5664782 :             MSLink* foeExitLink = foeLane->getLinkCont()[0];
     483              :             int foundIndex = -1;
     484     21315327 :             for (int i2 = 0; i2 < (int)foeExitLink->myFoeLanes.size(); i2++) {
     485     18088894 :                 if (foeExitLink->myFoeLanes[i2] == lane) {
     486      2438349 :                     myConflicts[i].foeConflictIndex = i2;
     487      2438349 :                     foeExitLink->myConflicts[i2].foeConflictIndex = i;
     488      2438349 :                     myRecheck.erase({foeExitLink, this});
     489              :                     foundIndex = i2;
     490      2438349 :                     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      5664782 :             if (foundIndex < 0) {
     497      3226433 :                 if (myConflicts[i].flag != CONFLICT_NO_INTERSECTION) {
     498      2342808 :                     myRecheck.insert({this, foeExitLink});
     499              :                 }
     500              :             }
     501              :         }
     502              :     }
     503      2640370 :     if (MSGlobals::gLateralResolution > 0) {
     504              :         // check for links with the same origin lane and the same destination edge
     505       296545 :         const MSEdge* myTarget = &myLane->getEdge();
     506              :         // save foes for entry links
     507       936988 :         for (MSLink* const it : myLaneBefore->getLinkCont()) {
     508              :             const MSEdge* target = &(it->getLane()->getEdge());
     509       640443 :             if (it == this) {
     510       296545 :                 continue;
     511              :             }
     512       343898 :             if (target == myTarget) {
     513         6800 :                 mySublaneFoeLinks.push_back(it);
     514              : #ifdef MSLink_DEBUG_CROSSING_POINTS
     515              :                 std::cout << "  sublaneFoeLink (same target): " << it->getViaLaneOrLane()->getID() << "\n";
     516              : #endif
     517       337098 :             } else if (myDirection != LinkDirection::STRAIGHT && it->getDirection() == LinkDirection::STRAIGHT) {
     518              :                 // potential turn conflict
     519        82471 :                 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       296545 :         if (fromInternalLane()) {
     527              :             //std::cout << " setRequestInformation link=" << getViaLaneOrLane()->getID() << " before=" << myLaneBefore->getID() << " before2=" << myLaneBefore->getIncomingLanes().front().lane->getID() << "\n";
     528       370520 :             for (const MSLink* const link : myLaneBefore->getIncomingLanes().front().lane->getLinkCont()) {
     529       260431 :                 if (link->getViaLane() != myInternalLaneBefore && &link->getLane()->getEdge() == myTarget) {
     530              :                     //std::cout << " add sublaneFoe=" << (*it)->getViaLane()->getID() << "\n";
     531         4356 :                     mySublaneFoeLanes.push_back(link->getViaLane());
     532              :                 }
     533              :             }
     534              :         }
     535              :     }
     536      2640370 :     if (myInternalLaneBefore != nullptr
     537      1009259 :             && myDirection != LinkDirection::STRAIGHT
     538              :             // for right turns, the curvature helps rather than restricts the linkLeader check
     539       583171 :             && (
     540       583171 :                 (!MSGlobals::gLefthand && myDirection != LinkDirection::RIGHT)
     541       172383 :                 || (MSGlobals::gLefthand && myDirection != LinkDirection::LEFT))) {
     542       822486 :         const double angle = fabs(GeomHelper::angleDiff(
     543       411243 :                                       myLaneBefore->getNormalPredecessorLane()->getShape().angleAt2D(-2),
     544       411243 :                                       myLane->getShape().angleAt2D(0)));
     545       411243 :         if (angle > 0) {
     546       411243 :             double length = myInternalLaneBefore->getShape().length2D();
     547       822486 :             if (myInternalLaneBefore->getIncomingLanes().size() == 1 &&
     548       411243 :                     myInternalLaneBefore->getIncomingLanes()[0].lane->isInternal()) {
     549       116270 :                 length += myInternalLaneBefore->getIncomingLanes()[0].lane->getShape().length2D();
     550       294973 :             } else if (myInternalLane != nullptr) {
     551       116270 :                 length += myInternalLane->getShape().length2D();
     552              :             }
     553       411243 :             myRadius = length / angle;
     554              :             //std::cout << getDescription() << " a=" << RAD2DEG(angle) << " l=" << length << " r=" << myRadius << "\n";
     555              :         }
     556              :     }
     557      2640370 : }
     558              : 
     559              : 
     560              : void
     561        42364 : MSLink::recheckSetRequestInformation() {
     562       346290 :     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      2660301 :         for (int i = 0; i < (int)link->myFoeLanes.size(); i++) {
     572      2660301 :             if (link->myFoeLanes[i] == foeLane) {
     573              :                 conflictIndex = i;
     574              :                 break;
     575              :             }
     576              :         }
     577       303926 :         if (conflictIndex == -1) {
     578            0 :             WRITE_WARNING("Could not recheck ConflictInfo for " + link->getDescription() + " and " + foeExitLink->getDescription() + "\n");
     579       283285 :             continue;
     580              :         }
     581       303926 :         ConflictInfo& ci = link->myConflicts[conflictIndex];
     582       303926 :         if (ci.flag & CONFLICT_SIBLING_CONTINUATION) {
     583       283035 :             const MSLane* const intLane = link->getInternalLaneBefore();
     584              :             const MSLane* const siblingCont = foeExitLink->getInternalLaneBefore();
     585       283035 :             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       283035 :             const double distToDivergence = intLane->getLength() - ci.lengthBehindCrossing;
     588       283035 :             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              :             std::cout << " conflictIndex=" << conflictIndex << " foeLane=" << foeLane->getID() << " foeExitLink=" << foeExitLink->getDescription() << " intLane=" << intLane->getID() << "\n";
     592              : #endif
     593              :             ConflictInfo ci2 = ConflictInfo(lbcSibCont, intLane->getWidth());
     594       283035 :             ci2.foeConflictIndex = conflictIndex;
     595       283035 :             ci.foeConflictIndex = (int)foeExitLink->myConflicts.size();
     596       283035 :             foeExitLink->myFoeLanes.push_back(intLane);
     597       283035 :             foeExitLink->myConflicts.push_back(ci2);
     598              :             continue;
     599       283035 :         }
     600              : 
     601        20891 :         std::vector<double> intersections1 = foeLane->getShape().intersectsAtLengths2D(lane->getShape());
     602        20891 :         if (intersections1.size() == 0) {
     603              : #ifdef MSLink_DEBUG_CROSSING_POINTS
     604              :             std::cout << "    no intersection\n";
     605              : #endif
     606              :             continue;
     607              :         }
     608        20641 :         const double widthFactor = ci.conflictSize / foeLane->getWidth();
     609        20641 :         const double conflictSize2 = lane->getWidth() * widthFactor;
     610        20641 :         std::sort(intersections1.begin(), intersections1.end());
     611        20641 :         intersections1.back() -= conflictSize2 / 2;
     612        20641 :         intersections1.back() = MAX2(0.0, intersections1.back());
     613        20641 :         ci.foeConflictIndex = (int)foeExitLink->myConflicts.size();
     614        20641 :         foeExitLink->myConflicts.push_back(ConflictInfo(foeLane->getLength() - intersections1.back(), conflictSize2));
     615              : #ifdef MSLink_DEBUG_CROSSING_POINTS
     616              :         std::cout << "    ci=" << conflictIndex << " wf=" << widthFactor << " flag=" << ci.flag << " flbc=" << foeExitLink->myConflicts.back().lengthBehindCrossing << "\n";
     617              : #endif
     618        20891 :     }
     619              :     myRecheck.clear();
     620        42364 : }
     621              : 
     622              : double
     623      2499328 : MSLink::computeDistToDivergence(const MSLane* lane, const MSLane* sibling, double minDist, bool sameSource, double siblingPredLength) const {
     624              :     double lbcSibling = 0;
     625              :     double lbcLane = 0;
     626              : 
     627              :     PositionVector l = lane->getShape();
     628              :     PositionVector s = sibling->getShape();
     629      2499328 :     double length = l.length2D();
     630      2499328 :     double sibLength = s.length2D();
     631      2499328 :     if (!sameSource) {
     632      2506348 :         l = l.reverse();
     633      2506348 :         s = s.reverse();
     634      1246154 :     } else if (sibling->getEntryLink()->myAmIndirect) {
     635              :         // ignore final waiting position since it may be quite close to the lane
     636              :         // shape but the waiting position is perpendicular (so the minDist
     637              :         // requirement is not necessary
     638           94 :         lbcSibling += s[-1].distanceTo2D(s[-2]);
     639              :         s.pop_back();
     640      1246060 :     } else if (lane->getEntryLink()->myAmIndirect) {
     641              :         // ignore final waiting position since it may be quite close to the lane
     642              :         // shape but the waiting position is perpendicular (so the minDist
     643              :         // requirement is not necessary
     644           94 :         lbcLane += l[-1].distanceTo2D(l[-2]);
     645              :         l.pop_back();
     646              :     }
     647              : 
     648              : #ifdef MSLink_DEBUG_CROSSING_POINTS_DETAILS
     649              :     std::cout << "   sameSource=" << sameSource << " lane=" << lane->getID() << " sib=" << sibling->getID() << " minDist=" << minDist << " backDist=" << l.back().distanceTo2D(s.back()) << "\n";
     650              : #endif
     651      2499328 :     if (l.back().distanceTo2D(s.back()) > minDist) {
     652              :         // compute the final divergence point
     653              :         // this position serves two purposes:
     654              :         // 1) once the foe vehicle back (on sibling) has passed this point, we can safely ignore it
     655              :         // 2) both vehicles are put into a cf-relationship while before the point.
     656              :         //    Since the actual crossing point is at the start of the junction,
     657              :         //    we want to make sure that both vehicles have the same distance to the crossing point and thus follow each other naturally
     658      2441470 :         std::vector<double> distances = l.distances(s);
     659              : #ifdef MSLink_DEBUG_CROSSING_POINTS
     660              :         std::cout << "   distances=" << toString(distances) << "\n";
     661              : #endif
     662              :         assert(distances.size() == l.size() + s.size());
     663      2441470 :         if (distances.back() > minDist && distances[l.size() - 1] > minDist) {
     664              :             // do a pairwise check between lane and sibling to make because we do not know which of them bends more
     665      2323041 :             for (int j = (int)s.size() - 2; j >= 0; j--) {
     666      2323041 :                 const int i = j + (int)l.size();
     667      2323041 :                 const double segLength = s[j].distanceTo2D(s[j + 1]);
     668      2323041 :                 if (distances[i] > minDist) {
     669       903171 :                     lbcSibling += segLength;
     670              :                 } else {
     671              :                     // assume no sharp bends and just interpolate the last segment
     672      1419870 :                     lbcSibling += segLength - (minDist - distances[i]) * segLength / (distances[i + 1] - distances[i]);
     673      1419870 :                     break;
     674              :                 }
     675              :             }
     676      2323537 :             for (int i = (int)l.size() - 2; i >= 0; i--) {
     677      2323537 :                 const double segLength = l[i].distanceTo2D(l[i + 1]);
     678      2323537 :                 if (distances[i] > minDist) {
     679       903667 :                     lbcLane += segLength;
     680              :                 } else {
     681              :                     // assume no sharp bends and just interpolate the last segment
     682      1419870 :                     lbcLane += segLength - (minDist - distances[i]) * segLength / (distances[i + 1] - distances[i]);
     683      1419870 :                     break;
     684              :                 }
     685              :             }
     686              :         }
     687              :         assert(lbcSibling >= -NUMERICAL_EPS);
     688              :         assert(lbcLane >= -NUMERICAL_EPS);
     689      2441470 :     }
     690      2499328 :     const double distToDivergence1 = sibling->getLength() + siblingPredLength - lbcSibling;
     691      2499328 :     const double distToDivergence2 = lane->getLength() - lbcLane;
     692              :     const double distToDivergence = MIN3(
     693              :                                         MAX2(distToDivergence1, distToDivergence2),
     694              :                                         sibLength, length);
     695              : #ifdef MSLink_DEBUG_CROSSING_POINTS
     696              :     std::cout << "   distToDivergence=" << distToDivergence
     697              :               << " distTD1=" << distToDivergence1
     698              :               << " distTD2=" << distToDivergence2
     699              :               << " length=" << length
     700              :               << " sibLength=" << sibLength
     701              :               << "\n";
     702              : #endif
     703      2499328 :     return distToDivergence;
     704      2499328 : }
     705              : 
     706              : 
     707              : bool
     708      1379174 : MSLink::contIntersect(const MSLane* lane, const MSLane* foe) {
     709      1379174 :     if (foe->getLinkCont()[0]->getViaLane() != nullptr) {
     710       126278 :         std::vector<double> intersections = lane->getShape().intersectsAtLengths2D(foe->getShape());
     711       126278 :         return intersections.size() > 0;
     712       126278 :     }
     713              :     return false;
     714              : }
     715              : 
     716              : 
     717              : void
     718    879395042 : MSLink::setApproaching(const SUMOVehicle* approaching, const SUMOTime arrivalTime, const double arrivalSpeed, const double leaveSpeed,
     719              :                        const bool setRequest, const double arrivalSpeedBraking, const SUMOTime waitingTime, double dist, double latOffset) {
     720    879395042 :     const SUMOTime leaveTime = getLeaveTime(arrivalTime, arrivalSpeed, leaveSpeed, approaching->getVehicleType().getLength());
     721              : #ifdef DEBUG_APPROACHING
     722              :     if (DEBUG_COND2(approaching)) {
     723              :         std::cout << SIMTIME << " link=" << getDescription() << " setApproaching veh=" << approaching->getID();
     724              :         if (myApproachingVehicles.size() > 0) {
     725              :             std::cout << " curApproaching=";
     726              :             for (auto i = myApproachingVehicles.begin(); i != myApproachingVehicles.end(); ++i) {
     727              :                 std::cout << i->first->getID() << " ";
     728              :             }
     729              :         }
     730              :         std::cout << "\n";
     731              :     }
     732              : #endif
     733    879395042 :     myApproachingVehicles.emplace(approaching,
     734   1758790084 :                                   ApproachingVehicleInformation(arrivalTime, leaveTime, arrivalSpeed, leaveSpeed, setRequest,
     735    879395042 :                                           arrivalSpeedBraking, waitingTime, dist, approaching->getSpeed(), latOffset));
     736    879395042 : }
     737              : 
     738              : 
     739              : void
     740      1127882 : MSLink::setApproaching(const SUMOVehicle* approaching, ApproachingVehicleInformation ai) {
     741              : #ifdef DEBUG_APPROACHING
     742              :     if (DEBUG_COND2(approaching)) {
     743              :         std::cout << SIMTIME << " link=" << getDescription() << " setApproaching veh=" << approaching->getID();
     744              :         if (myApproachingVehicles.size() > 0) {
     745              :             std::cout << " curApproaching=";
     746              :             for (auto i = myApproachingVehicles.begin(); i != myApproachingVehicles.end(); ++i) {
     747              :                 std::cout << i->first->getID() << " ";
     748              :             }
     749              :         }
     750              :         std::cout << "\n";
     751              :     }
     752              : #endif
     753      1127882 :     myApproachingVehicles.emplace(approaching, ai);
     754      1127882 : }
     755              : 
     756              : void
     757       487881 : MSLink::setApproachingPerson(const MSPerson* approaching, const SUMOTime arrivalTime, const SUMOTime leaveTime) {
     758       487881 :     if (myApproachingPersons == nullptr) {
     759         1334 :         myApproachingPersons = new PersonApproachInfos();
     760              :     }
     761       487881 :     myApproachingPersons->emplace(approaching, ApproachingPersonInformation(arrivalTime, leaveTime));
     762       487881 : }
     763              : 
     764              : void
     765    870076619 : MSLink::removeApproaching(const SUMOVehicle* veh) {
     766              : #ifdef DEBUG_APPROACHING
     767              :     if (DEBUG_COND2(veh)) {
     768              :         std::cout << SIMTIME << " link=" << getDescription() << " removeApproaching veh=" << veh->getID();
     769              :         if (myApproachingVehicles.size() > 0) {
     770              :             std::cout << " curApproaching=";
     771              :             for (auto i = myApproachingVehicles.begin(); i != myApproachingVehicles.end(); ++i) {
     772              :                 std::cout << i->first->getID() << " ";
     773              :             }
     774              :         }
     775              :         std::cout << "\n";
     776              :     }
     777              : #endif
     778              :     myApproachingVehicles.erase(veh);
     779    870076619 : }
     780              : 
     781              : 
     782              : void
     783        31244 : MSLink::removeApproachingPerson(const MSPerson* person) {
     784        31244 :     if (myApproachingPersons == nullptr) {
     785           12 :         WRITE_WARNINGF("Person '%' entered crossing lane '%' without registering approach, time=%", person->getID(), myLane->getID(), time2string(SIMSTEP));
     786            3 :         return;
     787              :     }
     788              : #ifdef DEBUG_APPROACHING
     789              :     if (DEBUG_COND2(person)) {
     790              :         std::cout << SIMTIME << " Link '" << (myLaneBefore == 0 ? "NULL" : myLaneBefore->getID()) << "'->'" << (myLane == 0 ? "NULL" : myLane->getID()) << std::endl;
     791              :         std::cout << "' Removing approaching person '" << person->getID() << "'\nCurrently registered persons:" << std::endl;
     792              :         for (auto i = myApproachingPersons->begin(); i != myApproachingPersons->end(); ++i) {
     793              :             std::cout << "'" << i->first->getID() << "'" << std::endl;
     794              :         }
     795              :     }
     796              : #endif
     797              :     myApproachingPersons->erase(person);
     798              : }
     799              : 
     800              : 
     801              : MSLink::ApproachingVehicleInformation
     802     31752398 : MSLink::getApproaching(const SUMOVehicle* veh) const {
     803              :     auto i = myApproachingVehicles.find(veh);
     804     31752398 :     if (i != myApproachingVehicles.end()) {
     805     26994610 :         return i->second;
     806              :     } else {
     807              :         return ApproachingVehicleInformation(INVALID_TIME, INVALID_TIME, 0, 0, false, 0, 0, 0, 0, 0);
     808              :     }
     809              : }
     810              : 
     811              : 
     812              : const MSLink::ApproachingVehicleInformation*
     813      2889587 : MSLink::getApproachingPtr(const SUMOVehicle* veh) const {
     814              :     auto i = myApproachingVehicles.find(veh);
     815      2889587 :     if (i != myApproachingVehicles.end()) {
     816      2527343 :         return &i->second;
     817              :     } else {
     818              :         return nullptr;
     819              :     }
     820              : }
     821              : 
     822              : 
     823              : void
     824        11288 : MSLink::clearState() {
     825              :     myApproachingVehicles.clear();
     826        11288 : }
     827              : 
     828              : 
     829              : SUMOTime
     830   1551416049 : MSLink::getLeaveTime(const SUMOTime arrivalTime, const double arrivalSpeed,
     831              :                      const double leaveSpeed, const double vehicleLength) const {
     832   1585218282 :     return arrivalTime == SUMOTime_MAX ? SUMOTime_MAX : arrivalTime + TIME2STEPS((getLength() + vehicleLength) / MAX2(0.5 * (arrivalSpeed + leaveSpeed), NUMERICAL_EPS));
     833              : }
     834              : 
     835              : 
     836              : bool
     837    685228283 : MSLink::opened(SUMOTime arrivalTime, double arrivalSpeed, double leaveSpeed, double vehicleLength,
     838              :                double impatience, double decel, SUMOTime waitingTime, double posLat,
     839              :                BlockingFoes* collectFoes, bool ignoreRed, const SUMOTrafficObject* ego, double dist) const {
     840              : #ifdef MSLink_DEBUG_OPENED
     841              :     if (gDebugFlag1) {
     842              :         std::cout << SIMTIME << "  opened? link=" << getDescription() << " red=" << haveRed() << " cont=" << isCont() << " numFoeLinks=" << myFoeLinks.size() << " havePrio=" << havePriority() << " lastWasContMajorGreen=" << lastWasContState(LINKSTATE_TL_GREEN_MAJOR) << "\n";
     843              :     }
     844              : #endif
     845    685228283 :     if (haveRed() && !ignoreRed) {
     846              :         return false;
     847              :     }
     848    676049234 :     if (isCont() && MSGlobals::gUsingInternalLanes) {
     849              :         return true;
     850              :     }
     851    671583208 :     const SUMOTime leaveTime = getLeaveTime(arrivalTime, arrivalSpeed, leaveSpeed, vehicleLength);
     852    671583208 :     if (MSGlobals::gLateralResolution > 0) {
     853              :         // check for foes on the same lane with the same target edge
     854    137907051 :         for (const MSLink* foeLink : mySublaneFoeLinks) {
     855              :             assert(myLane != foeLink->getLane());
     856      9993865 :             for (const auto& it : foeLink->myApproachingVehicles) {
     857      6799308 :                 const SUMOVehicle* foe = it.first;
     858              :                 if (
     859              :                     // there only is a conflict if the paths cross
     860      7399754 :                     ((posLat < foe->getLateralPositionOnLane() + it.second.latOffset && myLane->getIndex() > foeLink->myLane->getIndex())
     861      6553388 :                      || (posLat > foe->getLateralPositionOnLane() + it.second.latOffset && myLane->getIndex() < foeLink->myLane->getIndex()))
     862              :                     // the vehicle that arrives later must yield
     863      7397315 :                     && (arrivalTime > it.second.arrivalTime
     864              :                         // if both vehicles arrive at the same time, the one
     865              :                         // to the left must yield
     866       386486 :                         || (arrivalTime == it.second.arrivalTime && posLat > foe->getLateralPositionOnLane()))) {
     867       212166 :                     if (blockedByFoe(foe, it.second, arrivalTime, leaveTime, arrivalSpeed, leaveSpeed, false,
     868              :                                      impatience, decel, waitingTime, ego)) {
     869              : #ifdef MSLink_DEBUG_OPENED
     870              :                         if (gDebugFlag1) {
     871              :                             std::cout << SIMTIME << " blocked by " << foe->getID() << " arrival=" << arrivalTime << " foeArrival=" << it.second.arrivalTime << "\n";
     872              :                         }
     873              : #endif
     874        42189 :                         if (collectFoes == nullptr) {
     875              : #ifdef MSLink_DEBUG_OPENED
     876              :                             if (gDebugFlag1) {
     877              :                                 std::cout << " link=" << getViaLaneOrLane()->getID() << " blocked by sublaneFoe=" << foe->getID() << " foeLink=" << foeLink->getViaLaneOrLane()->getID() << " posLat=" << posLat << "\n";
     878              :                             }
     879              : #endif
     880              :                             return false;
     881              :                         } else {
     882            0 :                             collectFoes->push_back(it.first);
     883              :                         }
     884              :                     }
     885              :                 }
     886              :             }
     887              :         }
     888              :         // check for foes on the same lane with a different target edge
     889              :         // (straight movers take precedence if the paths cross)
     890    134670305 :         const int lhSign = MSGlobals::gLefthand ? -1 : 1;
     891    136015972 :         for (const MSLink* foeLink : mySublaneFoeLinks2) {
     892              :             assert(myDirection != LinkDirection::STRAIGHT);
     893      5706618 :             for (const auto& it : foeLink->myApproachingVehicles) {
     894      4360951 :                 const SUMOVehicle* foe = it.first;
     895              :                 // there only is a conflict if the paths cross
     896              :                 // and if the vehicles are not currently in a car-following relationship
     897      4360951 :                 const double egoWidth = ego == nullptr ? 1.8 : ego->getVehicleType().getWidth();
     898      4360951 :                 if (!lateralOverlap(posLat, egoWidth, foe->getLateralPositionOnLane() + it.second.latOffset, foe->getVehicleType().getWidth())
     899      4360951 :                         && (((myDirection == LinkDirection::RIGHT || myDirection == LinkDirection::PARTRIGHT)
     900       494691 :                              && (posLat * lhSign > (foe->getLateralPositionOnLane() + it.second.latOffset) * lhSign))
     901       447039 :                             || ((myDirection == LinkDirection::LEFT || myDirection == LinkDirection::PARTLEFT)
     902        33197 :                                 && (posLat * lhSign < (foe->getLateralPositionOnLane() + it.second.latOffset) * lhSign)))) {
     903        81775 :                     if (blockedByFoe(foe, it.second, arrivalTime, leaveTime, arrivalSpeed, leaveSpeed, false,
     904              :                                      impatience, decel, waitingTime, ego)) {
     905              : #ifdef MSLink_DEBUG_OPENED
     906              :                         if (gDebugFlag1) {
     907              :                             std::cout << SIMTIME << " blocked by sublane foe " << foe->getID() << " arrival=" << arrivalTime << " foeArrival=" << it.second.arrivalTime << "\n";
     908              :                         }
     909              : #endif
     910         8944 :                         if (collectFoes == nullptr) {
     911              : #ifdef MSLink_DEBUG_OPENED
     912              :                             if (gDebugFlag1) {
     913              :                                 std::cout << " link=" << getViaLaneOrLane()->getID() << " blocked by sublaneFoe2=" << foe->getID() << " foeLink=" << foeLink->getViaLaneOrLane()->getID() << " posLat=" << posLat << "\n";
     914              :                             }
     915              : #endif
     916              :                             return false;
     917              :                         } else {
     918            0 :                             collectFoes->push_back(it.first);
     919              :                         }
     920              :                     }
     921              :                 }
     922              :             }
     923              :         }
     924              :     }
     925              : #ifdef MSLink_DEBUG_OPENED
     926              :     /*
     927              :     if (gDebugFlag1) {
     928              :         std::cout << SIMTIME << " isExitLinkAfterInternalJunction=" << isExitLinkAfterInternalJunction()
     929              :             << " entryLink=" << getCorrespondingEntryLink()->getDescription()
     930              :             << " entryState=" << getCorrespondingEntryLink()->getState()
     931              :             << "\n";
     932              :     }
     933              :     */
     934              : #endif
     935              :     if ((havePriority()
     936     29903813 :             || lastWasContState(LINKSTATE_TL_GREEN_MAJOR)
     937     29461435 :             || (isExitLinkAfterInternalJunction() && getCorrespondingEntryLink()->getState() == LINKSTATE_TL_GREEN_MAJOR))
     938    672045641 :             && myState != LINKSTATE_ZIPPER) {
     939              :         // priority usually means the link is open but there are exceptions:
     940              :         // zipper still needs to collect foes
     941              :         // sublane model could have detected a conflict
     942    640426185 :         return collectFoes == nullptr || collectFoes->size() == 0;
     943              :     }
     944     31105890 :     if (myState == LINKSTATE_ALLWAY_STOP && waitingTime < TIME2STEPS(ego == nullptr ? TS : ego->getVehicleType().getParameter().getJMParam(SUMO_ATTR_JM_ALLWAYSTOP_WAIT, TS))) {
     945              :         return false;
     946     30129728 :     } else if (myState == LINKSTATE_STOP && waitingTime < TIME2STEPS(ego == nullptr ? TS : ego->getVehicleType().getParameter().getJMParam(SUMO_ATTR_JM_STOPSIGN_WAIT, TS))) {
     947              :         return false;
     948              :     }
     949              : 
     950     30065694 :     const std::vector<MSLink*>& foeLinks = (myOffFoeLinks == nullptr || getCorrespondingEntryLink()->getState() != LINKSTATE_ALLWAY_STOP) ? myFoeLinks : *myOffFoeLinks;
     951              : 
     952     30065694 :     if (MSGlobals::gUseMesoSim && impatience == 1 && !myLane->getEdge().isRoundabout()) {
     953              :         return true;
     954              :     }
     955     30065560 :     if (myLane->getBidiLane() != nullptr) {
     956       131896 :         MSLane* bidi = myLane->getBidiLane();
     957       131896 :         if (bidi->getVehicleNumber() > 0) {
     958        19955 :             if (ego == nullptr) {
     959              :                 return false;
     960              :             }
     961              :             double maxOncomingWidth = 0;
     962        19955 :             const MSLane::VehCont& vehs = bidi->getVehiclesSecure();
     963       127733 :             for (MSVehicle* foe : vehs) {
     964       107778 :                 maxOncomingWidth = MAX2(maxOncomingWidth, foe->getVehicleType().getWidth());
     965              :             }
     966        19955 :             bidi->releaseVehicles();
     967        19955 :             if (MSGlobals::gLateralResolution > 0) {
     968        16779 :                 if (ego->getVehicleType().getWidth() + maxOncomingWidth + MSGlobals::gLateralResolution < myLane->getWidth()) {
     969              :                     return false;
     970              :                 }
     971         3176 :             } else if (maxOncomingWidth > 0) {
     972              :                 // do not enter a lane that has any oncoming vehicles
     973              :                 return false;
     974              :             }
     975              :         }
     976       266583 :         for (auto ili : bidi->getIncomingLanes()) {
     977       138445 :             if (ili.lane->getEdge().getPriority() > myLaneBefore->getEdge().getPriority()
     978       138445 :                     || (ili.lane->getEdge().getPriority() == myLaneBefore->getEdge().getPriority()
     979       107448 :                         && ili.lane->getID() > myLaneBefore->getID())) {
     980              :                 BlockingFoes bidiApproachFoes;
     981              :                 double maxOncomingWidth = 0;
     982        21199 :                 if (ili.viaLink->blockedAtTime(arrivalTime, leaveTime, arrivalSpeed, leaveSpeed, false, 0, decel, 0,
     983        42398 :                             MSGlobals::gLateralResolution ? &bidiApproachFoes : nullptr, ego) || bidiApproachFoes.size() > 0) {
     984          506 :                     if (MSGlobals::gLateralResolution > 0) {
     985          437 :                         for (const SUMOTrafficObject* foe : bidiApproachFoes) {
     986          226 :                             maxOncomingWidth = MAX2(maxOncomingWidth, foe->getVehicleType().getWidth());
     987              :                         }
     988          211 :                         if (ego->getVehicleType().getWidth() + maxOncomingWidth + MSGlobals::gLateralResolution < myLane->getWidth()) {
     989              :                             return false;
     990              :                         }
     991              :                     } else {
     992              :                         return false;
     993              :                     }
     994              :                 }
     995        21199 :             }
     996              :         }
     997              :     }
     998     30061802 :     const bool lastWasContRed = lastWasContState(LINKSTATE_TL_RED);
     999     83564730 :     for (const MSLink* const link : foeLinks) {
    1000     58437899 :         if (MSGlobals::gUseMesoSim) {
    1001      1829960 :             if (link->haveRed()) {
    1002        70073 :                 continue;
    1003              :             }
    1004              :         }
    1005              : #ifdef MSLink_DEBUG_OPENED
    1006              :         if (gDebugFlag1) {
    1007              :             std::cout << SIMTIME << "   foeLink=" << link->getViaLaneOrLane()->getID() << " numApproaching=" << link->getApproaching().size() << "\n";
    1008              :             if (link->getLane()->isCrossing()) {
    1009              :                 std::cout << SIMTIME << "     approachingPersons=" << (link->myApproachingPersons == nullptr ? "NULL" : toString(link->myApproachingPersons->size())) << "\n";
    1010              :             }
    1011              :         }
    1012              : #endif
    1013     58367826 :         if (link->blockedAtTime(arrivalTime, leaveTime, arrivalSpeed, leaveSpeed, myLane == link->getLane(),
    1014              :                                 impatience, decel, waitingTime, collectFoes, ego, lastWasContRed, dist)) {
    1015              :             return false;
    1016              :         }
    1017              :     }
    1018     25126831 :     if (collectFoes != nullptr && collectFoes->size() > 0) {
    1019              :         return false;
    1020              :     }
    1021              :     return true;
    1022              : }
    1023              : 
    1024              : 
    1025              : bool
    1026     58440326 : MSLink::blockedAtTime(SUMOTime arrivalTime, SUMOTime leaveTime, double arrivalSpeed, double leaveSpeed,
    1027              :                       bool sameTargetLane, double impatience, double decel, SUMOTime waitingTime,
    1028              :                       BlockingFoes* collectFoes, const SUMOTrafficObject* ego, bool lastWasContRed, double dist) const {
    1029    219422093 :     for (const auto& it : myApproachingVehicles) {
    1030              : #ifdef MSLink_DEBUG_OPENED
    1031              :         if (gDebugFlag1) {
    1032              :             if (ego != nullptr
    1033              :                     && ego->getVehicleType().getParameter().getJMParam(SUMO_ATTR_JM_IGNORE_FOE_SPEED, 0) >= it.second.speed
    1034              :                     && ego->getVehicleType().getParameter().getJMParam(SUMO_ATTR_JM_IGNORE_FOE_PROB, 0) > 0) {
    1035              :                 std::stringstream stream; // to reduce output interleaving from different threads
    1036              :                 stream << SIMTIME << " " << myApproachingVehicles.size() << "   foe link=" << getViaLaneOrLane()->getID()
    1037              :                        << " foeVeh=" << it.first->getID() << " (below ignore speed)"
    1038              :                        << " ignoreFoeProb=" << ego->getVehicleType().getParameter().getJMParam(SUMO_ATTR_JM_IGNORE_FOE_PROB, 0)
    1039              :                        << "\n";
    1040              :                 std::cout << stream.str();
    1041              :             }
    1042              :         }
    1043              : #endif
    1044    165814090 :         if (it.first != ego
    1045    165804817 :                 && (ego == nullptr
    1046    165756610 :                     || ego->getVehicleType().getParameter().getJMParam(SUMO_ATTR_JM_IGNORE_FOE_PROB, 0) == 0
    1047        23251 :                     || ego->getVehicleType().getParameter().getJMParam(SUMO_ATTR_JM_IGNORE_FOE_SPEED, 0) < it.second.speed
    1048         1746 :                     || ego->getVehicleType().getParameter().getJMParam(SUMO_ATTR_JM_IGNORE_FOE_PROB, 0) < RandHelper::rand(ego->getRNG()))
    1049    165803227 :                 && !ignoreFoe(ego, it.first)
    1050    165802985 :                 && (!lastWasContRed || it.first->getSpeed() > SUMO_const_haltingSpeed)
    1051    331600960 :                 && blockedByFoe(it.first, it.second, arrivalTime, leaveTime, arrivalSpeed, leaveSpeed, sameTargetLane,
    1052              :                                 impatience, decel, waitingTime, ego)) {
    1053     11317848 :             if (collectFoes == nullptr) {
    1054              :                 return true;
    1055              :             } else {
    1056      6485525 :                 collectFoes->push_back(it.first);
    1057              :             }
    1058              :         }
    1059              :     }
    1060     53608003 :     if (myApproachingPersons != nullptr && !haveRed()) {
    1061              :         const SUMOTime lookAhead = (ego == nullptr
    1062       847530 :                                     ? myLookaheadTime
    1063       847358 :                                     : TIME2STEPS(ego->getVehicleType().getParameter().getJMParam(SUMO_ATTR_JM_TIMEGAP_MINOR, STEPS2TIME(myLookaheadTime))));
    1064       922244 :         for (const auto& it : *myApproachingPersons) {
    1065              : #ifdef MSLink_DEBUG_OPENED
    1066              :             if (gDebugFlag1) {
    1067              :                 std::cout << SIMTIME << ": " << ego->getID() << " check person " << it.first->getID() << " aTime=" << arrivalTime << " foeATime=" << it.second.arrivalTime
    1068              :                           << " lTime=" << leaveTime << " foeLTime=" << it.second.leavingTime
    1069              :                           << " dist=" << dist << "\n";
    1070              :             }
    1071              : #endif
    1072              :             if ((ego == nullptr
    1073       204291 :                     || ego->getVehicleType().getParameter().getJMParam(SUMO_ATTR_JM_IGNORE_FOE_PROB, 0) == 0
    1074          600 :                     || ego->getVehicleType().getParameter().getJMParam(SUMO_ATTR_JM_IGNORE_FOE_SPEED, 0) < it.first->getSpeed()
    1075          600 :                     || ego->getVehicleType().getParameter().getJMParam(SUMO_ATTR_JM_IGNORE_FOE_PROB, 0) < RandHelper::rand(ego->getRNG()))
    1076       203912 :                     && !ignoreFoe(ego, it.first)
    1077       408344 :                     && !((arrivalTime > it.second.leavingTime + lookAhead) || (leaveTime + lookAhead < it.second.arrivalTime))) {
    1078       143187 :                 if (ego == nullptr) {
    1079              :                     // during insertion
    1080          165 :                     if (myJunction->getType() == SumoXMLNodeType::RAIL_CROSSING) {
    1081          165 :                         continue;
    1082              :                     } else {
    1083              :                         return true;
    1084              :                     }
    1085              :                 }
    1086              :                 // check whether braking is feasible (ego might have started to accelerate already)
    1087       143022 :                 const auto& cfm = ego->getVehicleType().getCarFollowModel();
    1088              : #ifdef MSLink_DEBUG_OPENED
    1089              :                 if (gDebugFlag1) {
    1090              :                     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";
    1091              :                 }
    1092              : #endif
    1093       143022 :                 if (dist > cfm.brakeGap(ego->getSpeed(), cfm.getMaxDecel(), 0)) {
    1094              : #ifdef MSLink_DEBUG_OPENED
    1095              :                     if (gDebugFlag1) {
    1096              :                         std::cout << SIMTIME << ": " << ego->getID() << " blocked by person " << it.first->getID() << "\n";
    1097              :                     }
    1098              : #endif
    1099       129798 :                     if (collectFoes == nullptr) {
    1100              :                         return true;
    1101              :                     } else {
    1102            0 :                         collectFoes->push_back(it.first);
    1103              :                     }
    1104              :                 }
    1105              :             }
    1106              :         }
    1107              :     }
    1108              :     return false;
    1109              : }
    1110              : 
    1111              : 
    1112              : bool
    1113    166080811 : MSLink::blockedByFoe(const SUMOVehicle* veh, const ApproachingVehicleInformation& avi,
    1114              :                      SUMOTime arrivalTime, SUMOTime leaveTime, double arrivalSpeed, double leaveSpeed,
    1115              :                      bool sameTargetLane, double impatience, double decel, SUMOTime waitingTime,
    1116              :                      const SUMOTrafficObject* ego) const {
    1117              : #ifdef MSLink_DEBUG_OPENED
    1118              :     if (gDebugFlag1) {
    1119              :         std::stringstream stream; // to reduce output interleaving from different threads
    1120              :         stream << "    link=" << getDescription()
    1121              :                << " foeVeh=" << veh->getID()
    1122              :                << " req=" << avi.willPass
    1123              :                << " aT=" << avi.arrivalTime
    1124              :                << " lT=" << avi.leavingTime
    1125              :                << "\n";
    1126              :         std::cout << stream.str();
    1127              :     }
    1128              : #endif
    1129    166080811 :     if (!avi.willPass) {
    1130              :         return false;
    1131              :     }
    1132     60564704 :     if (myState == LINKSTATE_ALLWAY_STOP) {
    1133              :         assert(waitingTime > 0);
    1134              : #ifdef MSLink_DEBUG_OPENED
    1135              :         if (gDebugFlag1) {
    1136              :             std::stringstream stream; // to reduce output interleaving from different threads
    1137              :             stream << "    foeDist=" << avi.dist
    1138              :                    << " foeBGap=" << veh->getBrakeGap(false)
    1139              :                    << " foeWait=" << avi.waitingTime
    1140              :                    << " wait=" << waitingTime
    1141              :                    << "\n";
    1142              :             std::cout << stream.str();
    1143              :         }
    1144              : #endif
    1145              :         // when using actionSteps, the foe waiting time may be outdated
    1146      1566781 :         const SUMOTime actionDelta = SIMSTEP - veh->getLastActionTime();
    1147      1566781 :         if (waitingTime > avi.waitingTime + actionDelta) {
    1148              :             return false;
    1149              :         }
    1150       232841 :         if (waitingTime == (avi.waitingTime + actionDelta) && arrivalTime < avi.arrivalTime + actionDelta) {
    1151              :             return false;
    1152              :         }
    1153              :     }
    1154     59201190 :     SUMOTime foeArrivalTime = avi.arrivalTime;
    1155     59201190 :     double foeArrivalSpeedBraking = avi.arrivalSpeedBraking;
    1156     59201190 :     if (impatience > 0 && arrivalTime < avi.arrivalTime) {
    1157              : #ifdef MSLink_DEBUG_OPENED
    1158              :         gDebugFlag6 = ((ego == nullptr || ego->isSelected()) && (veh == nullptr || veh->isSelected()));
    1159              : #endif
    1160      2771089 :         const SUMOTime fatb = computeFoeArrivalTimeBraking(arrivalTime, veh, avi.arrivalTime, impatience, avi.dist, foeArrivalSpeedBraking);
    1161      2771089 :         foeArrivalTime = (SUMOTime)((1. - impatience) * (double)avi.arrivalTime + impatience * (double)fatb);
    1162              : #ifdef MSLink_DEBUG_OPENED
    1163              :         if (gDebugFlag6) {
    1164              :             std::cout << SIMTIME << " link=" << getDescription() << " ego=" << ego->getID() << " foe=" << veh->getID()
    1165              :                       << " at=" << STEPS2TIME(arrivalTime)
    1166              :                       << " fat=" << STEPS2TIME(avi.arrivalTime)
    1167              :                       << " fatb=" << STEPS2TIME(fatb)
    1168              :                       << " fat2=" << STEPS2TIME(foeArrivalTime)
    1169              :                       << "\n";
    1170              :         }
    1171              : #endif
    1172              :     }
    1173              : 
    1174              : 
    1175     59201190 :     const SUMOTime lookAhead = (myState == LINKSTATE_ZIPPER
    1176     59201190 :                                 ? myLookaheadTimeZipper
    1177              :                                 : (ego == nullptr
    1178     47479586 :                                    ? myLookaheadTime
    1179     47474198 :                                    : TIME2STEPS(ego->getVehicleType().getParameter().getJMParam(SUMO_ATTR_JM_TIMEGAP_MINOR, STEPS2TIME(myLookaheadTime)))));
    1180              :     //if (ego != 0) std::cout << SIMTIME << " ego=" << ego->getID() << " jmTimegapMinor=" << ego->getVehicleType().getParameter().getJMParam(SUMO_ATTR_JM_TIMEGAP_MINOR, -1) << " lookAhead=" << lookAhead << "\n";
    1181              : #ifdef MSLink_DEBUG_OPENED
    1182              :     if (gDebugFlag1 || gDebugFlag6) {
    1183              :         std::stringstream stream; // to reduce output interleaving from different threads
    1184              :         stream << "       imp=" << impatience << " fAT2=" << foeArrivalTime << " fASb=" << foeArrivalSpeedBraking << " lA=" << lookAhead << " egoAT=" << arrivalTime << " egoLT=" << leaveTime << " egoLS=" << leaveSpeed << "\n";
    1185              :         std::cout << stream.str();
    1186              :     }
    1187              : #endif
    1188     59201190 :     if (avi.leavingTime < arrivalTime) {
    1189              :         // ego wants to be follower
    1190     43351277 :         if (sameTargetLane && (arrivalTime - avi.leavingTime < lookAhead
    1191     18982644 :                                || unsafeMergeSpeeds(avi.leaveSpeed, arrivalSpeed,
    1192     18982644 :                                        veh->getVehicleType().getCarFollowModel().getMaxDecel(), decel))) {
    1193              : #ifdef MSLink_DEBUG_OPENED
    1194              :             if (gDebugFlag1 || gDebugFlag6) {
    1195              :                 std::cout << "      blocked (cannot follow)\n";
    1196              :             }
    1197              : #endif
    1198      4175524 :             return true;
    1199              :         }
    1200     15849913 :     } else if (foeArrivalTime > leaveTime + lookAhead) {
    1201              :         // ego wants to be leader.
    1202     14617938 :         if (sameTargetLane && unsafeMergeSpeeds(leaveSpeed, foeArrivalSpeedBraking,
    1203      5804240 :                                                 decel, veh->getVehicleType().getCarFollowModel().getMaxDecel())) {
    1204              : #ifdef MSLink_DEBUG_OPENED
    1205              :             if (gDebugFlag1 || gDebugFlag6) {
    1206              :                 std::cout << "      blocked (cannot lead)\n";
    1207              :             }
    1208              : #endif
    1209              :             return true;
    1210              :         }
    1211              :     } else {
    1212              :         // even without considering safeHeadwayTime there is already a conflict
    1213              : #ifdef MSLink_DEBUG_OPENED
    1214              :         if (gDebugFlag1 || gDebugFlag6) {
    1215              :             std::cout << "      blocked (hard conflict)\n";
    1216              :         }
    1217              : #endif
    1218              :         return true;
    1219              :     }
    1220              :     return false;
    1221              : }
    1222              : 
    1223              : 
    1224              : SUMOTime
    1225      2771089 : MSLink::computeFoeArrivalTimeBraking(SUMOTime arrivalTime, const SUMOVehicle* foe, SUMOTime foeArrivalTime, double impatience, double dist, double& fasb) {
    1226              :     // a: distance saved when foe brakes from arrivalTime to foeArrivalTime
    1227              :     // b: distance driven past foeArrivalTime
    1228              :     // m: permitted decceleration
    1229              :     // d: total deceleration until foeArrivalTime
    1230              :     // dist2: distance of foe at arrivalTime
    1231              :     // actual arrivalTime must fall on a simulation step
    1232      2771089 :     if (arrivalTime - arrivalTime % DELTA_T == foeArrivalTime - foeArrivalTime % DELTA_T) {
    1233              :         // foe enters the junction in the same step
    1234              : #ifdef MSLink_DEBUG_OPENED
    1235              :         if (gDebugFlag6) {
    1236              :             std::cout << "   foeAT before egoAT\n";
    1237              :         }
    1238              : #endif
    1239              :         return foeArrivalTime;
    1240              :     }
    1241      2416054 :     if (arrivalTime % DELTA_T > 0) {
    1242      2386304 :         arrivalTime = arrivalTime - (arrivalTime % DELTA_T) + DELTA_T;
    1243              :     }
    1244              :     //arrivalTime += DELTA_T - arrivalTime % DELTA_T;
    1245      2416054 :     const double m = foe->getVehicleType().getCarFollowModel().getMaxDecel() * impatience;
    1246      2416054 :     const double dt = STEPS2TIME(foeArrivalTime - arrivalTime);
    1247      2416054 :     const double d = dt * m;
    1248      2416054 :     const double a = dt * d / 2;
    1249      2416054 :     const double v = dist / STEPS2TIME(foeArrivalTime - SIMSTEP + DELTA_T);
    1250      2416054 :     const double dist2 = dist - v * STEPS2TIME(arrivalTime - SIMSTEP);
    1251              : #ifdef MSLink_DEBUG_OPENED
    1252              :     if (gDebugFlag6) {
    1253              :         std::cout << "   dist=" << dist << " dist2=" << dist2
    1254              :                   << " at=" << STEPS2TIME(arrivalTime)
    1255              :                   << " fat=" << STEPS2TIME(foeArrivalTime)
    1256              :                   << " dt=" << dt << " v=" << v << " m=" << m << " d=" << d << " a=" << a << "\n";
    1257              :     }
    1258              : #endif
    1259      2416054 :     if (0.5 * v * v / m <= dist2) {
    1260              : #ifdef MSLink_DEBUG_OPENED
    1261              :         if (gDebugFlag6) {
    1262              :             std::cout << "   canBrakeToStop\n";
    1263              :         }
    1264              : #endif
    1265      1216959 :         fasb = 0;
    1266      1216959 :         return foeArrivalTime + TIME2STEPS(30);
    1267              :     }
    1268              :     // a = b (foe reaches the original distance to the stop line)
    1269              :     // x: time driven past foeArrivalTime
    1270              :     // v: foe speed without braking
    1271              :     // v2: average foe speed after foeArrivalTime (braking continues for time x)
    1272              :     // v2 = (v - d - x * m / 2)
    1273              :     // b = v2 * x
    1274              :     // solving for x gives:
    1275      1199095 :     const double x = (sqrt(4 * (v - d) * (v - d) - 8 * m * a) * -0.5 - d + v) / m;
    1276              : 
    1277              : #ifdef MSLink_DEBUG_OPENED
    1278              :     const double x2 = (sqrt(4 * (v - d) * (v - d) - 8 * m * a) * 0.5 - d + v) / m;
    1279              :     if (gDebugFlag6 || std::isnan(x)) {
    1280              :         std::cout << SIMTIME << "   dist=" << dist << " dist2=" << dist2  << " at=" << STEPS2TIME(arrivalTime) << " m=" << m << " d=" << d << " v=" << v << " a=" << a << " x=" << x << " x2=" << x2 << "\n";
    1281              :     }
    1282              : #endif
    1283      1199095 :     fasb = v - (dt + x) * m;
    1284      1199095 :     return foeArrivalTime + TIME2STEPS(x);
    1285              : }
    1286              : 
    1287              : 
    1288              : bool
    1289       437945 : MSLink::hasApproachingFoe(SUMOTime arrivalTime, SUMOTime leaveTime, double speed, double decel) const {
    1290       462096 :     for (const MSLink* const link : myFoeLinks) {
    1291        51301 :         if (link->blockedAtTime(arrivalTime, leaveTime, speed, speed, myLane == link->getLane(), 0, decel, 0)) {
    1292              :             return true;
    1293              :         }
    1294              :     }
    1295       508294 :     for (const MSLane* const lane : myFoeLanes) {
    1296       104355 :         if (lane->getVehicleNumberWithPartials() > 0) {
    1297              :             return true;
    1298              :         }
    1299              :     }
    1300              :     return false;
    1301              : }
    1302              : 
    1303              : 
    1304              : std::pair<const SUMOVehicle*, const MSLink*>
    1305         5622 : MSLink::getFirstApproachingFoe(const MSLink* wrapAround) const {
    1306              :     double closetDist = std::numeric_limits<double>::max();
    1307              :     const SUMOVehicle* closest = nullptr;
    1308              :     const MSLink* foeLink = nullptr;
    1309        18308 :     for (MSLink* link : myFoeLinks) {
    1310        19750 :         for (const auto& it : link->myApproachingVehicles) {
    1311              :             //std::cout << " link=" << getDescription() << " foeLink_in=" << link->getLaneBefore()->getID() << " wrapAround=" << wrapAround->getDescription() << "\n";
    1312         7064 :             if (link->getLaneBefore() == wrapAround->getLaneBefore()) {
    1313          489 :                 return std::make_pair(nullptr, wrapAround);
    1314         6575 :             } else if (it.second.dist < closetDist) {
    1315              :                 closetDist = it.second.dist;
    1316         3423 :                 if (it.second.willPass) {
    1317         3162 :                     closest = it.first;
    1318              :                     foeLink = link;
    1319              :                 }
    1320              :             }
    1321              :         }
    1322              :     }
    1323              :     return std::make_pair(closest, foeLink);
    1324              : }
    1325              : 
    1326              : 
    1327              : void
    1328     65816548 : MSLink::setTLState(LinkState state, SUMOTime t) {
    1329     65816548 :     if (myState != state) {
    1330     15560606 :         myLastStateChange = t;
    1331              :     }
    1332     65816548 :     myState = state;
    1333     65816548 :     if (haveGreen()) {
    1334     11106416 :         myLastGreenState = myState;
    1335              :     }
    1336     65816548 : }
    1337              : 
    1338              : 
    1339              : void
    1340       179943 : MSLink::setTLLogic(const MSTrafficLightLogic* logic) {
    1341       179943 :     myLogic = logic;
    1342       179943 : }
    1343              : 
    1344              : 
    1345              : bool
    1346   1282938078 : MSLink::isCont() const {
    1347              :     // when a traffic light is switched off minor roads have their cont status revoked
    1348   1282938078 :     return (myState == LINKSTATE_TL_OFF_BLINKING || myState == LINKSTATE_ALLWAY_STOP || myState == LINKSTATE_STOP) ? myAmContOff : myAmCont;
    1349              : }
    1350              : 
    1351              : 
    1352              : bool
    1353     66704402 : MSLink::lastWasContMajor() const {
    1354     67381527 :     if (isExitLinkAfterInternalJunction()) {
    1355       677125 :         return myInternalLaneBefore->getIncomingLanes()[0].viaLink->lastWasContMajor();
    1356              :     }
    1357     66704402 :     if (myInternalLane == nullptr || myAmCont) {
    1358              :         return false;
    1359              :     } else {
    1360     48711184 :         MSLane* pred = myInternalLane->getLogicalPredecessorLane();
    1361     48711184 :         if (!pred->getEdge().isInternal()) {
    1362              :             return false;
    1363              :         } else {
    1364     11735728 :             const MSLane* const pred2 = pred->getLogicalPredecessorLane();
    1365              :             assert(pred2 != nullptr);
    1366     11735728 :             const MSLink* const predLink = pred2->getLinkTo(pred);
    1367              :             assert(predLink != nullptr);
    1368     11735728 :             if (predLink->havePriority()) {
    1369              :                 return true;
    1370              :             }
    1371     11063796 :             if (myHavePedestrianCrossingFoe) {
    1372      1433421 :                 return predLink->getLastGreenState() == LINKSTATE_TL_GREEN_MAJOR;
    1373              :             } else {
    1374      9630375 :                 return predLink->haveYellow();
    1375              :             }
    1376              :         }
    1377              :     }
    1378              : }
    1379              : 
    1380              : 
    1381              : bool
    1382     59965615 : MSLink::lastWasContState(LinkState linkState) const {
    1383     59965615 :     if (myInternalLane == nullptr || myAmCont || myHavePedestrianCrossingFoe) {
    1384              :         return false;
    1385              :     } else {
    1386     52339572 :         MSLane* pred = myInternalLane->getLogicalPredecessorLane();
    1387     52339572 :         if (!pred->getEdge().isInternal()) {
    1388              :             return false;
    1389              :         } else {
    1390     15391642 :             const MSLane* const pred2 = pred->getLogicalPredecessorLane();
    1391              :             assert(pred2 != nullptr);
    1392     15391642 :             const MSLink* const predLink = pred2->getLinkTo(pred);
    1393              :             assert(predLink != nullptr);
    1394     15391642 :             return predLink->getState() == linkState;
    1395              :         }
    1396              :     }
    1397              : }
    1398              : 
    1399              : 
    1400              : void
    1401       113904 : MSLink::writeApproaching(OutputDevice& od, const std::string fromLaneID) const {
    1402       113904 :     if (myApproachingVehicles.size() > 0) {
    1403         9765 :         od.openTag("link");
    1404         9765 :         od.writeAttr(SUMO_ATTR_FROM, fromLaneID);
    1405         9765 :         const std::string via = getViaLane() == nullptr ? "" : getViaLane()->getID();
    1406         9765 :         od.writeAttr(SUMO_ATTR_VIA, via);
    1407        19530 :         od.writeAttr(SUMO_ATTR_TO, getLane() == nullptr ? "" : getLane()->getID());
    1408              :         std::vector<std::pair<SUMOTime, const SUMOVehicle*> > toSort; // stabilize output
    1409        21325 :         for (auto it : myApproachingVehicles) {
    1410        11560 :             toSort.push_back(std::make_pair(it.second.arrivalTime, it.first));
    1411              :         }
    1412         9765 :         std::sort(toSort.begin(), toSort.end());
    1413        21325 :         for (std::vector<std::pair<SUMOTime, const SUMOVehicle*> >::const_iterator it = toSort.begin(); it != toSort.end(); ++it) {
    1414        11560 :             od.openTag("approaching");
    1415        11560 :             const ApproachingVehicleInformation& avi = myApproachingVehicles.find(it->second)->second;
    1416        11560 :             od.writeAttr(SUMO_ATTR_ID, it->second->getID());
    1417        11560 :             od.writeAttr(SUMO_ATTR_IMPATIENCE, it->second->getImpatience());
    1418        11560 :             od.writeAttr("arrivalTime", time2string(avi.arrivalTime));
    1419        11560 :             od.writeAttr("leaveTime", time2string(avi.leavingTime));
    1420        11560 :             od.writeAttr("arrivalSpeed", toString(avi.arrivalSpeed));
    1421        11560 :             od.writeAttr("arrivalSpeedBraking", toString(avi.arrivalSpeedBraking));
    1422        11560 :             od.writeAttr("leaveSpeed", toString(avi.leaveSpeed));
    1423        11560 :             od.writeAttr("willPass", toString(avi.willPass));
    1424        23120 :             od.closeTag();
    1425              :         }
    1426         9765 :         od.closeTag();
    1427         9765 :     }
    1428       113904 : }
    1429              : 
    1430              : 
    1431              : double
    1432       922014 : MSLink::getInternalLengthsAfter() const {
    1433              :     double len = 0.;
    1434       922014 :     MSLane* lane = myInternalLane;
    1435              : 
    1436      1760241 :     while (lane != nullptr && lane->isInternal()) {
    1437       838227 :         len += lane->getLength();
    1438       838227 :         lane = lane->getLinkCont()[0]->getViaLane();
    1439              :     }
    1440       922014 :     return len;
    1441              : }
    1442              : 
    1443              : double
    1444            0 : MSLink::getInternalLengthsBefore() const {
    1445              :     double len = 0.;
    1446            0 :     const MSLane* lane = myInternalLane;
    1447              : 
    1448            0 :     while (lane != nullptr && lane->isInternal()) {
    1449            0 :         len += lane->getLength();
    1450            0 :         if (lane->getIncomingLanes().size() == 1) {
    1451            0 :             lane = lane->getIncomingLanes()[0].lane;
    1452              :         } else {
    1453              :             break;
    1454              :         }
    1455              :     }
    1456            0 :     return len;
    1457              : }
    1458              : 
    1459              : 
    1460              : double
    1461       131134 : MSLink::getLengthsBeforeCrossing(const MSLane* foeLane) const {
    1462       131134 :     MSLane* via = myInternalLane;
    1463              :     double totalDist = 0.;
    1464              :     bool foundCrossing = false;
    1465       133990 :     while (via != nullptr) {
    1466       132630 :         MSLink* link = via->getLinkCont()[0];
    1467       132630 :         double dist = link->getLengthBeforeCrossing(foeLane);
    1468       132630 :         if (dist != INVALID_DOUBLE) {
    1469              :             // found conflicting lane
    1470       129774 :             totalDist += dist;
    1471              :             foundCrossing = true;
    1472              :             break;
    1473              :         } else {
    1474         2856 :             totalDist += via->getLength();
    1475              :             via = link->getViaLane();
    1476              :         }
    1477              :     }
    1478              :     if (foundCrossing) {
    1479       129774 :         return totalDist;
    1480              :     } else {
    1481              :         return INVALID_DOUBLE;
    1482              :     }
    1483              : }
    1484              : 
    1485              : 
    1486              : double
    1487       132630 : MSLink::getLengthBeforeCrossing(const MSLane* foeLane) const {
    1488              :     int foe_ix;
    1489       795143 :     for (foe_ix = 0; foe_ix != (int)myFoeLanes.size(); ++foe_ix) {
    1490       793647 :         if (myFoeLanes[foe_ix] == foeLane) {
    1491              :             break;
    1492              :         }
    1493              :     }
    1494       132630 :     if (foe_ix == (int)myFoeLanes.size()) {
    1495              :         // no conflict with the given lane, indicate by returning -1
    1496              : #ifdef MSLink_DEBUG_CROSSING_POINTS
    1497              :         std::cout << "No crossing of lanes '" << foeLane->getID() << "' and '" << myInternalLaneBefore->getID() << "'" << std::endl;
    1498              : #endif
    1499              :         return INVALID_DOUBLE;
    1500              :     } else {
    1501              :         // found conflicting lane index
    1502       131134 :         double dist = myInternalLaneBefore->getLength() - myConflicts[foe_ix].getLengthBehindCrossing(this);
    1503       131134 :         if (dist == -10000.) {
    1504              :             // this is the value in myConflicts, if the relation allows intersection but none is present for the actual geometry.
    1505              :             return INVALID_DOUBLE;
    1506              :         }
    1507              : #ifdef MSLink_DEBUG_CROSSING_POINTS
    1508              :         std::cout << "Crossing of lanes '" << myInternalLaneBefore->getID() << "' and '" << foeLane->getID()
    1509              :                   << "' at distance " << dist << " (approach along '"
    1510              :                   <<  myInternalLaneBefore->getEntryLink()->getLaneBefore()->getID() << "')" << std::endl;
    1511              : #endif
    1512              :         return dist;
    1513              :     }
    1514              : }
    1515              : 
    1516              : 
    1517              : bool
    1518     40189439 : MSLink::isEntryLink() const {
    1519     40189439 :     if (MSGlobals::gUsingInternalLanes) {
    1520     63900129 :         return myInternalLane != nullptr && myInternalLaneBefore == nullptr;
    1521              :     } else {
    1522              :         return false;
    1523              :     }
    1524              : }
    1525              : 
    1526              : bool
    1527     19516409 : MSLink::isConflictEntryLink() const {
    1528              :     // either a non-cont entry link or the link after a cont-link
    1529     19516409 :     return !myAmCont && (isEntryLink() || (myInternalLaneBefore != nullptr && myInternalLane != nullptr));
    1530              : }
    1531              : 
    1532              : bool
    1533     94889297 : MSLink::isExitLink() const {
    1534     94889297 :     if (MSGlobals::gUsingInternalLanes) {
    1535    163055798 :         return myInternalLaneBefore != nullptr && myInternalLane == nullptr;
    1536              :     } else {
    1537              :         return false;
    1538              :     }
    1539              : }
    1540              : 
    1541              : bool
    1542    156855446 : MSLink::isExitLinkAfterInternalJunction() const {
    1543    156855446 :     if (MSGlobals::gUsingInternalLanes) {
    1544              :         return (getInternalLaneBefore() != nullptr
    1545     81164503 :                 && myInternalLaneBefore->getIncomingLanes().size() == 1
    1546    237507040 :                 && myInternalLaneBefore->getIncomingLanes().front().viaLink->isInternalJunctionLink());
    1547              :     } else {
    1548              :         return false;
    1549              :     }
    1550              : }
    1551              : 
    1552              : 
    1553              : const MSLink*
    1554       141642 : MSLink::getCorrespondingExitLink() const {
    1555       141642 :     MSLane* lane = myInternalLane;
    1556              :     const MSLink* link = this;
    1557       287732 :     while (lane != nullptr) {
    1558       146090 :         link = lane->getLinkCont()[0];
    1559              :         lane = link->getViaLane();
    1560              :     }
    1561       141642 :     return link;
    1562              : }
    1563              : 
    1564              : 
    1565              : const MSLink*
    1566    809500741 : MSLink::getCorrespondingEntryLink() const {
    1567              :     const MSLink* link = this;
    1568   1088467719 :     while (link->myLaneBefore->isInternal()) {
    1569              :         assert(myLaneBefore->getIncomingLanes().size() == 1);
    1570    278966978 :         link = link->myLaneBefore->getIncomingLanes().front().viaLink;
    1571              :     }
    1572    809500741 :     return link;
    1573              : }
    1574              : 
    1575              : 
    1576              : bool
    1577    424452773 : MSLink::isInternalJunctionLink() const {
    1578    424452773 :     return getInternalLaneBefore() != nullptr && myInternalLane != nullptr;
    1579              : }
    1580              : 
    1581              : 
    1582              : const MSLink::LinkLeaders
    1583    879401438 : MSLink::getLeaderInfo(const MSVehicle* ego, double dist, std::vector<const MSPerson*>* collectBlockers, bool isShadowLink) const {
    1584              :     LinkLeaders result;
    1585              :     // this link needs to start at an internal lane (either an exit link or between two internal lanes)
    1586              :     // or it must be queried by the pedestrian model (ego == 0)
    1587    879401438 :     if (ego != nullptr && (!fromInternalLane() || ego->getLaneChangeModel().isOpposite())) {
    1588              :         // ignore link leaders
    1589              :         return result;
    1590              :     }
    1591              :     //gDebugFlag1 = true;
    1592    297028948 :     if (gDebugFlag1) {
    1593            0 :         std::cout << SIMTIME << " getLeaderInfo link=" << getDescription() << " dist=" << dist << " isShadowLink=" << isShadowLink << "\n";
    1594              :     }
    1595    297028948 :     if (MSGlobals::gComputeLC && ego != nullptr && ego->getLane()->isNormal()) {
    1596     25814476 :         const MSLink* junctionEntry = getLaneBefore()->getEntryLink();
    1597      6475182 :         if (junctionEntry->haveRed() && !ego->ignoreRed(junctionEntry, true)
    1598              :                 // check oncoming on bidiLane during laneChanging
    1599     32284972 :                 && (!MSGlobals::gComputeLC || junctionEntry->getLaneBefore()->getBidiLane() == nullptr)) {
    1600      6421179 :             if (gDebugFlag1) {
    1601            0 :                 std::cout << "   ignore linkLeaders beyond red light\n";
    1602              :             }
    1603              :             return result;
    1604              :         }
    1605              :     }
    1606              :     // this is an exit link
    1607    290607769 :     const double extraGap = ego != nullptr ? ego->getVehicleType().getParameter().getJMParam(SUMO_ATTR_JM_EXTRA_GAP, 0) : 0;
    1608    771019665 :     for (int i = 0; i < (int)myFoeLanes.size(); ++i) {
    1609    480411897 :         const MSLane* foeLane = myFoeLanes[i];
    1610    480411897 :         const MSLink* foeExitLink = foeLane->getLinkCont()[0];
    1611              :         // distance from the querying vehicle to the crossing point with foeLane
    1612    480411897 :         double distToCrossing = dist - myConflicts[i].getLengthBehindCrossing(this);
    1613    480411897 :         const double foeDistToCrossing = foeLane->getLength() - myConflicts[i].getFoeLengthBehindCrossing(foeExitLink);
    1614    480411897 :         const bool sameTarget = (myLane == foeExitLink->getLane()) && !isInternalJunctionLink() && !foeExitLink->isInternalJunctionLink();
    1615    480411897 :         const bool sameSource = (myInternalLaneBefore != nullptr && myInternalLaneBefore->getNormalPredecessorLane() == foeLane->getNormalPredecessorLane());
    1616    480411897 :         const double crossingWidth = (sameTarget || sameSource) ? 0 : myConflicts[i].conflictSize;
    1617    480411897 :         const double foeCrossingWidth = (sameTarget || sameSource) ? 0 : myConflicts[i].getFoeConflictSize(foeExitLink);
    1618              :         // special treatment of contLane foe only applies if this lane is not a contLane or contLane follower itself
    1619    607823523 :         const bool contLane = (foeExitLink->getViaLaneOrLane()->getEdge().isInternal() && !(
    1620    127411626 :                                    isInternalJunctionLink() || isExitLinkAfterInternalJunction()));
    1621    480411897 :         if (gDebugFlag1) {
    1622              :             std::cout << " distToCrossing=" << distToCrossing << " foeLane=" << foeLane->getID() << " cWidth=" << crossingWidth
    1623            0 :                       << " flag=" << myConflicts[i].flag << " i=" << i << " fcIndex=" << myConflicts[i].foeConflictIndex
    1624            0 :                       << " ijl=" << isInternalJunctionLink() << " sT=" << sameTarget << " sS=" << sameSource
    1625            0 :                       << " lbc=" << myConflicts[i].getLengthBehindCrossing(this)
    1626            0 :                       << " flbc=" << myConflicts[i].getFoeLengthBehindCrossing(foeExitLink)
    1627              :                       << " cw=" << crossingWidth
    1628              :                       << " fcw=" << foeCrossingWidth
    1629              :                       << " contLane=" << contLane
    1630            0 :                       << " state=" << toString(myState)
    1631            0 :                       << " foeState=" << toString(foeExitLink->getState())
    1632            0 :                       << "\n";
    1633              :         }
    1634    106068008 :         if (distToCrossing + crossingWidth < 0 && !sameTarget
    1635    580763211 :                 && (ego == nullptr || !MSGlobals::gComputeLC || distToCrossing + crossingWidth + ego->getVehicleType().getLength() < 0)) {
    1636     96266289 :             if (gDebugFlag1) {
    1637            0 :                 std::cout << " ignore:egoBeyondCrossingPoint\n";
    1638              :             }
    1639     96266289 :             continue; // vehicle is behind the crossing point, continue with next foe lane
    1640              :         }
    1641              :         bool ignoreGreenCont = false;
    1642              :         bool foeIndirect = false;
    1643    384145608 :         if (contLane) {
    1644     41878649 :             const MSLink* entry = getLaneBefore()->getEntryLink();
    1645     41878649 :             const MSLink* foeEntry = foeLane->getEntryLink();
    1646     41878649 :             foeIndirect = foeEntry->myAmIndirect;
    1647     41598344 :             if (entry != nullptr && entry->haveGreen()
    1648     26548394 :                     && foeEntry != nullptr && foeEntry->haveGreen()
    1649     54266236 :                     && entry->myLaneBefore != foeEntry->myLaneBefore)  {
    1650              :                 // ignore vehicles before an internaljunction as long as they are still in green minor mode
    1651              :                 ignoreGreenCont = true;
    1652              :             }
    1653              :         }
    1654     41878649 :         if (foeIndirect && distToCrossing >= NO_INTERSECTION) {
    1655        31466 :             if (gDebugFlag1) {
    1656            0 :                 std::cout << " ignore:noIntersection\n";
    1657              :             }
    1658        31466 :             continue;
    1659              :         }
    1660              :         // it is not sufficient to return the last vehicle on the foeLane because ego might be its leader
    1661              :         // therefore we return all vehicles on the lane
    1662              :         //
    1663              :         // special care must be taken for continuation lanes. (next lane is also internal)
    1664              :         // vehicles on cont. lanes or on internal lanes with the same target as this link can not be ignored
    1665              :         // and should block (gap = -1) unless they are part of an indirect turn
    1666              :         MSLane::AnyVehicleIterator end = foeLane->anyVehiclesEnd();
    1667     30587909 :         for (MSLane::AnyVehicleIterator it_veh = foeLane->anyVehiclesBegin(); it_veh != end; ++it_veh) {
    1668     30587910 :             MSVehicle* leader = (MSVehicle*)*it_veh;
    1669     30587910 :             const double leaderBack = leader->getBackPositionOnLane(foeLane) - extraGap;
    1670     30587910 :             const double leaderBackDist = foeDistToCrossing - leaderBack;
    1671     30587910 :             const double l2 = ego != nullptr ? ego->getLength() + 2 : 0; // add some slack to account for further meeting-angle effects
    1672     30475418 :             const double sagitta = ego != nullptr && myRadius != std::numeric_limits<double>::max() ? myRadius - sqrt(myRadius * myRadius - 0.25 * l2 * l2) : 0;
    1673     30587910 :             const bool pastTheCrossingPoint = leaderBackDist + foeCrossingWidth + sagitta < 0;
    1674     30587910 :             const bool enteredTheCrossingPoint = leaderBackDist < leader->getVehicleType().getLength();
    1675     30587910 :             const bool foeIsBicycleTurn = (leader->getVehicleType().getVehicleClass() == SVC_BICYCLE
    1676     30587910 :                                            && foeLane->getIncomingLanes().front().viaLink->getDirection() == LinkDirection::LEFT);
    1677     30587910 :             const bool ignoreIndirectBicycleTurn = pastTheCrossingPoint && foeIsBicycleTurn;
    1678     30587910 :             const bool cannotIgnore = ((contLane && !ignoreIndirectBicycleTurn) || sameTarget || (sameSource && !MSGlobals::gComputeLC)) && ego != nullptr;
    1679     30587910 :             const bool inTheWay = ((((!pastTheCrossingPoint && distToCrossing > 0) || (sameTarget && distToCrossing > leaderBackDist - leader->getLength()))
    1680     24191855 :                                     && (enteredTheCrossingPoint || (sameSource && !enteredTheCrossingPoint && foeDistToCrossing < distToCrossing))
    1681     16305319 :                                     && (!(myConflicts[i].flag == CONFLICT_DUMMY_MERGE) || foeIsBicycleTurn || sameSource))
    1682     44912159 :                                    || foeExitLink->getLaneBefore()->getNormalPredecessorLane() == myLane->getBidiLane());
    1683     30587910 :             const bool isOpposite = leader->getLaneChangeModel().isOpposite();
    1684     30587910 :             const auto avi = foeExitLink->getApproaching(leader);
    1685              :             // if leader is not found, assume that it performed a lane change in the last step
    1686     30587910 :             const bool willPass = avi.willPass || (avi.arrivalTime == INVALID_TIME && sameTarget);
    1687     30587910 :             if (gDebugFlag1) {
    1688              :                 std::cout << " candidate leader=" << leader->getID()
    1689              :                           << " cannotIgnore=" << cannotIgnore
    1690              :                           << " fdtc=" << foeDistToCrossing
    1691              :                           << " lb=" << leaderBack
    1692              :                           << " lbd=" << leaderBackDist
    1693              :                           << " fcwidth=" << foeCrossingWidth
    1694            0 :                           << " r=" << myRadius
    1695              :                           << " sagitta=" << sagitta
    1696              :                           << " foePastCP=" << pastTheCrossingPoint
    1697              :                           << " foeEnteredCP=" << enteredTheCrossingPoint
    1698              :                           << " inTheWay=" << inTheWay
    1699              :                           << " willPass=" << willPass
    1700            0 :                           << " isFrontOnLane=" << leader->isFrontOnLane(foeLane)
    1701              :                           << " ignoreGreenCont=" << ignoreGreenCont
    1702              :                           << " foeIndirect=" << foeIndirect
    1703              :                           << " foeBikeTurn=" << foeIsBicycleTurn
    1704            0 :                           << " isOpposite=" << isOpposite << "\n";
    1705              :             }
    1706     30587910 :             if (leader == ego) {
    1707      9243953 :                 continue;
    1708              :             }
    1709              :             // ignore greenCont foe vehicles that are not in the way
    1710     29645122 :             if (!inTheWay && ignoreGreenCont) {
    1711         6890 :                 if (gDebugFlag1) {
    1712            0 :                     std::cout << "   ignoreGreenCont\n";
    1713              :                 }
    1714         6890 :                 continue;
    1715              :             }
    1716              :             // after entering the conflict area, ignore foe vehicles that are not in the way
    1717      3816666 :             if ((!MSGlobals::gComputeLC || (ego != nullptr && ego->getLane() == foeLane) || MSGlobals::gSublane)
    1718     28248911 :                     && distToCrossing < -POSITION_EPS && !inTheWay
    1719     29967294 :                     && (ego == nullptr || !MSGlobals::gComputeLC || distToCrossing < -ego->getVehicleType().getLength())) {
    1720       132386 :                 if (gDebugFlag1) {
    1721            0 :                     std::cout << "   ego entered conflict area\n";
    1722              :                 }
    1723       132386 :                 continue;
    1724              :             }
    1725     29605655 :             if (!MSGlobals::gComputeLC
    1726     25733043 :                     && sameSource
    1727      8047624 :                     && &ego->getLane()->getEdge() == &myInternalLaneBefore->getEdge()
    1728     29973684 :                     && leaderBack + leader->getLength() < ego->getPositionOnLane() - ego->getLength()) {
    1729              :                 // ego is already on the junction and clearly ahead of foe
    1730        99809 :                 if (gDebugFlag1) {
    1731            0 :                     std::cout << "   ego ahead of same-source foe\n";
    1732              :                 }
    1733        99809 :                 continue;
    1734              :             }
    1735              : 
    1736              :             // ignore foe vehicles that will not pass
    1737     18721863 :             if ((!cannotIgnore || leader->isStopped() || sameTarget)
    1738     20029951 :                     && !willPass
    1739      2332106 :                     && (avi.arrivalTime == INVALID_TIME || leader->getSpeed() < SUMO_const_haltingSpeed)
    1740      2331834 :                     && leader->isFrontOnLane(foeLane)
    1741              :                     && !isOpposite
    1742      1172855 :                     && !inTheWay
    1743              :                     // willPass is false if the vehicle is already on the stopping edge
    1744     29857476 :                     && !leader->willStop()) {
    1745       450650 :                 if (gDebugFlag1) {
    1746            0 :                     std::cout << "   foe will not pass\n";
    1747              :                 }
    1748       450650 :                 continue;
    1749              :             }
    1750     28955387 :             if (leader->isBidiOn(foeLane)) {
    1751              :                 // conflict resolved via forward lane of the foe
    1752      1277058 :                 continue;
    1753              :             }
    1754              :             // check whether foe is blocked and might need to change before leaving the junction
    1755     27678329 :             const bool foeStrategicBlocked = (leader->getLaneChangeModel().isStrategicBlocked() &&
    1756      1422028 :                                               leader->getCarFollowModel().brakeGap(leader->getSpeed()) <= foeLane->getLength() - leaderBack);
    1757     27678329 :             const bool sameInternalEdge = &myInternalLaneBefore->getEdge() == &foeExitLink->getInternalLaneBefore()->getEdge();
    1758              : 
    1759     27678329 :             const bool foeLaneIsBidi = myInternalLaneBefore->getBidiLane() == foeLane;
    1760     27678329 :             if (MSGlobals::gSublane && ego != nullptr && (sameSource || sameTarget || foeLaneIsBidi)
    1761      7144805 :                     && (!foeStrategicBlocked || sameInternalEdge)) {
    1762      7006090 :                 if (ego->getLane() == leader->getLane()) {
    1763       160016 :                     continue;
    1764              :                 }
    1765              :                 // ignore vehicles if not in conflict sublane-wise
    1766      6846074 :                 const double egoLatOffset = isShadowLink ? ego->getLatOffset(ego->getLaneChangeModel().getShadowLane()) : 0;
    1767      6846074 :                 const double posLat = ego->getLateralPositionOnLane() + egoLatOffset;
    1768      6846074 :                 double posLatLeader = leader->getLateralPositionOnLane() + leader->getLatOffset(foeLane);
    1769      6846074 :                 if (foeLaneIsBidi) {
    1770              :                     // leader is oncoming
    1771          431 :                     posLatLeader = foeLane->getWidth() - posLatLeader;
    1772              :                 }
    1773      6846074 :                 const double latGap = (fabs(posLat - posLatLeader)
    1774      6846074 :                                        - 0.5 * (ego->getVehicleType().getWidth() + leader->getVehicleType().getWidth()));
    1775      6846074 :                 const double maneuverDist = leader->getLaneChangeModel().getManeuverDist() * (posLat < posLatLeader ? -1 : 1);
    1776      6846074 :                 if (gDebugFlag1) {
    1777            0 :                     std::cout << " checkIgnore sublaneFoe lane=" << myInternalLaneBefore->getID()
    1778              :                               << " sameSource=" << sameSource
    1779              :                               << " sameTarget=" << sameTarget
    1780              :                               << " foeLaneIsBidi=" << foeLaneIsBidi
    1781              :                               << " foeLane=" << foeLane->getID()
    1782              :                               << " leader=" << leader->getID()
    1783            0 :                               << " egoLane=" << ego->getLane()->getID()
    1784            0 :                               << " leaderLane=" << leader->getLane()->getID()
    1785              :                               << " egoLat=" << posLat
    1786              :                               << " egoLatOffset=" << egoLatOffset
    1787              :                               << " leaderLat=" << posLatLeader
    1788            0 :                               << " leaderLatOffset=" << leader->getLatOffset(foeLane)
    1789              :                               << " latGap=" << latGap
    1790              :                               << " maneuverDist=" << maneuverDist
    1791            0 :                               << " computeLC=" << MSGlobals::gComputeLC
    1792            0 :                               << " egoMaxSpeedLat=" << ego->getVehicleType().getMaxSpeedLat()
    1793            0 :                               << "\n";
    1794              :                 }
    1795      1483356 :                 if (latGap > 0 && (latGap > maneuverDist || !sameTarget || !MSGlobals::gComputeLC)
    1796              :                         // do not perform sublane changes that interfere with the leader vehicle
    1797      8322893 :                         && (!MSGlobals::gComputeLC || latGap > ego->getVehicleType().getMaxSpeedLat())) {
    1798      1342454 :                     const MSLink* foeEntryLink = foeLane->getIncomingLanes().front().viaLink;
    1799      1342454 :                     if (sameSource) {
    1800              :                         // for lanes from the same edge, higer index implies a
    1801              :                         // connection further to the left
    1802      1033556 :                         const bool leaderFromRight = (myIndex > foeEntryLink->getIndex());
    1803      1033556 :                         if ((posLat > posLatLeader) == leaderFromRight) {
    1804              :                             // ignore speed since lanes diverge
    1805       594651 :                             if (gDebugFlag1) {
    1806            0 :                                 std::cout << "   ignored (same source) leaderFromRight=" << leaderFromRight << "\n";
    1807              :                             }
    1808       594651 :                             continue;
    1809              :                         }
    1810       308898 :                     } else if (sameTarget) {
    1811              :                         // for lanes from different edges we cannot rely on the
    1812              :                         // index due to wrap-around issues
    1813       308467 :                         if (myDirection != foeEntryLink->getDirection()) {
    1814       301655 :                             bool leaderFromRight = foeEntryLink->getDirection() < myDirection;
    1815              :                             // leader vehicle should not move towards ego
    1816       301655 :                             if (MSGlobals::gLefthand) {
    1817            0 :                                 leaderFromRight = !leaderFromRight;
    1818              :                             }
    1819       419892 :                             if ((posLat > posLatLeader) == leaderFromRight
    1820              :                                     // leader should keep lateral position or move away from ego
    1821       166877 :                                     && (leader->getLaneChangeModel().getSpeedLat() == 0
    1822        49284 :                                         || leaderFromRight == (leader->getLaneChangeModel().getSpeedLat() < latGap))
    1823       429001 :                                     && (ego->getLaneChangeModel().getSpeedLat() == 0
    1824        16492 :                                         || leaderFromRight == (ego->getLaneChangeModel().getSpeedLat() > -latGap))) {
    1825       118237 :                                 if (gDebugFlag1) {
    1826            0 :                                     std::cout << "   ignored (different source) leaderFromRight=" << leaderFromRight << "\n";
    1827              :                                 }
    1828       118237 :                                 continue;
    1829              :                             }
    1830              :                         } else {
    1831              :                             // XXX figure out relative direction somehow
    1832              :                         }
    1833              :                     } else {
    1834          431 :                         if (gDebugFlag1) {
    1835            0 :                             std::cout << "   ignored oncoming bidi leader\n";
    1836              :                         }
    1837          431 :                         continue;
    1838              :                     }
    1839              :                 }
    1840              :             }
    1841     26804994 :             if (leader->getWaitingTime() < MSGlobals::gIgnoreJunctionBlocker) {
    1842              :                 // compute distance between vehicles on the superimposition of both lanes
    1843              :                 // where the crossing point is the common point
    1844              :                 double gap;
    1845              :                 bool fromLeft = true;
    1846     26313762 :                 if (ego == nullptr) {
    1847              :                     // request from pedestrian model. return distance between leaderBack and crossing point
    1848              :                     //std::cout << "   foeLane=" << foeLane->getID() << " leaderBack=" << leaderBack << " foeDistToCrossing=" << foeDistToCrossing << " foeLength=" << foeLane->getLength() << " foebehind=" << myConflicts[i].second << " dist=" << dist << " behind=" << myConflicts[i].first << "\n";
    1849       112082 :                     gap = leaderBackDist;
    1850              :                     // distToCrossing should not take into account the with of the foe lane
    1851              :                     // (which was subtracted in setRequestInformation)
    1852              :                     // Instead, the width of the foe vehicle is used directly by the caller.
    1853       112082 :                     distToCrossing += myConflicts[i].conflictSize / 2;
    1854       112082 :                     if (gap + foeCrossingWidth < 0) {
    1855              :                         // leader is completely past the crossing point
    1856              :                         // or there is no crossing point
    1857      4518249 :                         continue; // next vehicle
    1858              :                     }
    1859              :                     // we need to determine whether the vehicle passes the
    1860              :                     // crossing from the left or the right (heuristic)
    1861       109899 :                     fromLeft = foeDistToCrossing > 0.5 * foeLane->getLength();
    1862     26201680 :                 } else if ((contLane && !sameSource && !ignoreIndirectBicycleTurn) || isOpposite) {
    1863      1355488 :                     gap = -std::numeric_limits<double>::max(); // always break for vehicles which are on a continuation lane or for opposite-direction vehicles
    1864              :                 } else {
    1865     24846192 :                     if (pastTheCrossingPoint && !sameTarget) {
    1866              :                         // leader is completely past the crossing point
    1867              :                         // or there is no crossing point
    1868      4515987 :                         if (gDebugFlag1) {
    1869            0 :                             std::cout << " foePastCP ignored\n";
    1870              :                         }
    1871      4515987 :                         continue;
    1872              :                     }
    1873              :                     double leaderBackDist2 = leaderBackDist;
    1874     20330205 :                     if (sameTarget && leaderBackDist2 < 0) {
    1875      3115438 :                         const double mismatch = myConflicts[i].getFoeLengthBehindCrossing(foeExitLink) - myConflicts[i].getLengthBehindCrossing(this);
    1876      3115438 :                         if (mismatch > 0) {
    1877      1562835 :                             leaderBackDist2 += mismatch;
    1878              :                         }
    1879              :                     }
    1880     20330205 :                     if (gDebugFlag1) {
    1881              :                         std::cout << " distToCrossing=" << distToCrossing << " leaderBack=" << leaderBack
    1882              :                                   << " backDist=" << leaderBackDist
    1883              :                                   << " backDist2=" << leaderBackDist2
    1884            0 :                                   << " blockedStrategic=" << leader->getLaneChangeModel().isStrategicBlocked()
    1885            0 :                                   << "\n";
    1886              :                     }
    1887     20330205 :                     gap = distToCrossing - ego->getVehicleType().getMinGap() - leaderBackDist2 - foeCrossingWidth;
    1888              :                 }
    1889              :                 // if the foe is already moving off the intersection, we may
    1890              :                 // advance up to the crossing point unless we have the same target or same source
    1891              :                 // (for sameSource, the crossing point indicates the point of divergence)
    1892     25577265 :                 const bool stopAsap = ((leader->isFrontOnLane(foeLane) ? cannotIgnore : (sameTarget || sameSource))
    1893     22351551 :                                        || (ego != nullptr && ego->getVehicleType().getParameter().getJMParam(SUMO_ATTR_JM_ADVANCE, 1.0) == 0.0));
    1894     21795592 :                 if (gDebugFlag1) {
    1895            0 :                     std::cout << " leader=" << leader->getID() << " contLane=" << contLane << " cannotIgnore=" << cannotIgnore << " stopAsap=" << stopAsap << " gap=" << gap << "\n";
    1896              :                 }
    1897     21795592 :                 if (ignoreFoe(ego, leader)) {
    1898           79 :                     continue;
    1899              :                 }
    1900     21795513 :                 const int llFlags = ((fromLeft ? LL_FROM_LEFT : 0) |
    1901     21795513 :                                      (inTheWay ? LL_IN_THE_WAY : 0) |
    1902     21795513 :                                      (sameSource ? LL_SAME_SOURCE : 0) |
    1903     21795513 :                                      (sameTarget ? LL_SAME_TARGET : 0));
    1904     28890849 :                 result.emplace_back(leader, gap, stopAsap ? -1 : distToCrossing, llFlags, leader->getLatOffset(foeLane));
    1905              :             }
    1906              : 
    1907              :         }
    1908    384114141 :         if (ego != nullptr && MSNet::getInstance()->hasPersons()) {
    1909              :             // check for crossing pedestrians (keep driving if already on top of the crossing
    1910      8797165 :             const double distToPeds = distToCrossing - ego->getVehicleType().getParameter().getJMParam(SUMO_ATTR_JM_STOPLINE_CROSSING_GAP, MSPModel::SAFETY_GAP);
    1911      8797165 :             const double vehWidth = ego->getVehicleType().getWidth() + MSPModel::SAFETY_GAP; // + configurable safety gap
    1912              :             /// @todo consider lateral position (depending on whether the crossing is encountered on the way in or out)
    1913              :             // @check lefthand?!
    1914      8797165 :             const bool wayIn = myConflicts[i].lengthBehindCrossing < myLaneBefore->getLength() * 0.5;
    1915      8797165 :             const double vehCenter = (foeDistToCrossing + myLaneBefore->getWidth() * 0.5
    1916      8797165 :                                       + ego->getLateralPositionOnLane() * (wayIn ? -1 : 1));
    1917              :             // can access the movement model here since we already checked for existing persons above
    1918     17138774 :             if (distToPeds >= -MSPModel::SAFETY_GAP && MSNet::getInstance()->getPersonControl().getMovementModel()->blockedAtDist(ego, foeLane, vehCenter, vehWidth,
    1919      8341609 :                     ego->getVehicleType().getParameter().getJMParam(SUMO_ATTR_JM_CROSSING_GAP, JM_CROSSING_GAP_DEFAULT),
    1920              :                     collectBlockers)) {
    1921       519427 :                 result.emplace_back(nullptr, -1, distToPeds);
    1922      8277738 :             } else if (foeLane->isCrossing() && ego->getLane()->isInternal() && ego->getLane()->getEdge().getToJunction() == myJunction) {
    1923       146928 :                 const MSLink* crossingLink = foeLane->getIncomingLanes()[0].viaLink;
    1924       146928 :                 if (distToCrossing > 0 && crossingLink->havePriority() && crossingLink->myApproachingPersons != nullptr) {
    1925              :                     // a person might step on the crossing at any moment, since ego
    1926              :                     // is already on the junction, the opened() check is not done anymore
    1927        26500 :                     const double timeToEnterCrossing = distToCrossing / MAX2(ego->getSpeed(), 1.0);
    1928        31806 :                     for (const auto& item : (*crossingLink->myApproachingPersons)) {
    1929         6853 :                         if (!ignoreFoe(ego, item.first) && timeToEnterCrossing > STEPS2TIME(item.second.arrivalTime - SIMSTEP)) {
    1930         1547 :                             if (gDebugFlag1) {
    1931            0 :                                 std::cout << SIMTIME << ": " << ego->getID() << " breaking for approaching person " << item.first->getID()
    1932              :                                           //<< " dtc=" << distToCrossing << " ttc=" << distToCrossing / MAX2(ego->getSpeed(), 1.0) << " foeAT=" << item.second.arrivalTime << " foeTTC=" << STEPS2TIME(item.second.arrivalTime - SIMSTEP)
    1933            0 :                                           << "\n";
    1934              :                             }
    1935         1547 :                             result.emplace_back(nullptr, -1, distToPeds);
    1936         1547 :                             break;
    1937              :                             //} else {
    1938              :                             //    if (gDebugFlag1) {
    1939              :                             //        std::cout << SIMTIME << ": " << ego->getID() << " notBreaking for approaching person " << item.first->getID()
    1940              :                             //            << " dtc=" << distToCrossing << " ttc=" << distToCrossing / MAX2(ego->getSpeed(), 1.0) << " foeAT=" << item.second.arrivalTime << " foeTTC=" << STEPS2TIME(item.second.arrivalTime - SIMSTEP)
    1941              :                             //            << "\n";
    1942              :                             //    }
    1943              :                         }
    1944              :                     }
    1945              :                 }
    1946              :             }
    1947              :         }
    1948              :     }
    1949              : 
    1950              :     //std::cout << SIMTIME << " ego=" << Named::getIDSecure(ego) << " link=" << getViaLaneOrLane()->getID() << " myWalkingAreaFoe=" << Named::getIDSecure(myWalkingAreaFoe) << "\n";
    1951    290607768 :     if (ego != nullptr) {
    1952    289667121 :         checkWalkingAreaFoe(ego, myWalkingAreaFoe, collectBlockers, result);
    1953    289667121 :         checkWalkingAreaFoe(ego, myWalkingAreaFoeExit, collectBlockers, result);
    1954              :     }
    1955              : 
    1956    290607768 :     if (MSGlobals::gLateralResolution > 0 && ego != nullptr && !isShadowLink) {
    1957              :         // check for foes on the same edge
    1958     71909208 :         for (std::vector<MSLane*>::const_iterator it = mySublaneFoeLanes.begin(); it != mySublaneFoeLanes.end(); ++it) {
    1959      6026256 :             const MSLane* foeLane = *it;
    1960              :             MSLane::AnyVehicleIterator end = foeLane->anyVehiclesEnd();
    1961      4209228 :             for (MSLane::AnyVehicleIterator it_veh = foeLane->anyVehiclesBegin(); it_veh != end; ++it_veh) {
    1962      4209228 :                 MSVehicle* leader = (MSVehicle*)*it_veh;
    1963      4209228 :                 if (leader == ego) {
    1964      2456863 :                     continue;
    1965              :                 }
    1966      3572685 :                 if (leader->getLane()->isNormal()) {
    1967              :                     // leader is past the conflict point
    1968      1361320 :                     continue;
    1969              :                 }
    1970      2211365 :                 const double maxLength = MAX2(myInternalLaneBefore->getLength(), foeLane->getLength());
    1971      2211365 :                 const double gap = dist - maxLength - ego->getVehicleType().getMinGap() + leader->getBackPositionOnLane(foeLane) - extraGap;
    1972      2211365 :                 if (gap < -(ego->getVehicleType().getMinGap() + leader->getLength())) {
    1973              :                     // ego is ahead of leader
    1974       459000 :                     continue;
    1975              :                 }
    1976      1752365 :                 const double posLat = ego->getLateralPositionOnLane();
    1977      1752365 :                 const double posLatLeader = leader->getLateralPositionOnLane() + leader->getLatOffset(foeLane);
    1978      1752365 :                 if (gDebugFlag1) {
    1979            0 :                     std::cout << " sublaneFoe lane=" << myInternalLaneBefore->getID()
    1980              :                               << " foeLane=" << foeLane->getID()
    1981              :                               << " leader=" << leader->getID()
    1982            0 :                               << " egoLane=" << ego->getLane()->getID()
    1983            0 :                               << " leaderLane=" << leader->getLane()->getID()
    1984              :                               << " gap=" << gap
    1985              :                               << " egoLat=" << posLat
    1986              :                               << " leaderLat=" << posLatLeader
    1987            0 :                               << " leaderLatOffset=" << leader->getLatOffset(foeLane)
    1988            0 :                               << " egoIndex=" << myInternalLaneBefore->getIndex()
    1989            0 :                               << " foeIndex=" << foeLane->getIndex()
    1990            0 :                               << " dist=" << dist
    1991            0 :                               << " leaderBack=" << leader->getBackPositionOnLane(foeLane)
    1992            0 :                               << "\n";
    1993              :                 }
    1994              :                 // there only is a conflict if the paths cross
    1995       695109 :                 if ((posLat < posLatLeader && myInternalLaneBefore->getIndex() > foeLane->getIndex())
    1996      2079807 :                         || (posLat > posLatLeader && myInternalLaneBefore->getIndex() < foeLane->getIndex())) {
    1997       796171 :                     if (gDebugFlag1) {
    1998            0 :                         std::cout << SIMTIME << " blocked by " << leader->getID() << " (sublane split) foeLane=" << foeLane->getID() << "\n";
    1999              :                     }
    2000       796171 :                     if (ignoreFoe(ego, leader)) {
    2001            0 :                         continue;
    2002              :                     }
    2003       796171 :                     result.emplace_back(leader, gap, -1);
    2004              :                 }
    2005              :             }
    2006              :         }
    2007              :     }
    2008              :     return result;
    2009            1 : }
    2010              : 
    2011              : 
    2012              : void
    2013    579334242 : MSLink::checkWalkingAreaFoe(const MSVehicle* ego, const MSLane* foeLane, std::vector<const MSPerson*>* collectBlockers, LinkLeaders& result) const {
    2014    579334242 :     if (foeLane != nullptr && foeLane->getEdge().getPersons().size() > 0) {
    2015              :         // pedestrians may be on an arbitrary path across this
    2016              :         // walkingarea. make sure to keep enough distance.
    2017              :         // This is a simple but conservative solution that could be improved
    2018              :         // by ignoring pedestrians that are "obviously" not on a collision course
    2019       125665 :         double distToPeds = std::numeric_limits<double>::max();
    2020              :         assert(myInternalLaneBefore != nullptr);
    2021       125665 :         PositionVector egoPath = myInternalLaneBefore->getShape();
    2022       125665 :         if (ego->getLateralPositionOnLane() != 0) {
    2023       107434 :             egoPath.move2side((MSGlobals::gLefthand ? 1 : -1) * ego->getLateralPositionOnLane());
    2024              :         }
    2025       959753 :         for (MSTransportable* t : foeLane->getEdge().getPersons()) {
    2026       834088 :             MSPerson* p = static_cast<MSPerson*>(t);
    2027       834088 :             double dist = ego->getPosition().distanceTo2D(p->getPosition()) - p->getVehicleType().getLength();
    2028       834088 :             const bool inFront = isInFront(ego, egoPath, p->getPosition()) || isInFront(ego, egoPath, getFuturePosition(p));
    2029              :             if (inFront) {
    2030       305886 :                 dist -= MAX2(ego->getVehicleType().getMinGap(), MSPModel::SAFETY_GAP);
    2031              :             }
    2032              : #ifdef DEBUG_WALKINGAREA
    2033              :             if (ego->isSelected()) {
    2034              :                 std::cout << SIMTIME << " veh=" << ego->getID() << " ped=" << p->getID()
    2035              :                           << " pos=" << ego->getPosition() << " pedPos=" << p->getPosition()
    2036              :                           << " futurePedPos=" << getFuturePosition(p)
    2037              :                           << " rawDist=" << ego->getPosition().distanceTo2D(p->getPosition())
    2038              :                           << " inFront=" << inFront
    2039              :                           << " dist=" << dist << "\n";
    2040              :             }
    2041              : #endif
    2042       834088 :             if (dist < ego->getVehicleType().getWidth() / 2 || inFront) {
    2043       153234 :                 if (inFront) {
    2044       152943 :                     const double oncomingFactor = isOnComingPed(ego, p);
    2045       152943 :                     if (oncomingFactor > 0) {
    2046              :                         // account for pedestrian movement while closing in
    2047        53949 :                         const double timeToStop = sqrt(dist) / 2;
    2048        53949 :                         const double pedDist = p->getMaxSpeed() * MAX2(timeToStop, TS) * oncomingFactor;
    2049        53949 :                         dist = MAX2(0.0, dist - pedDist);
    2050              : #ifdef DEBUG_WALKINGAREA
    2051              :                         if (ego->isSelected()) {
    2052              :                             std::cout << "    timeToStop=" << timeToStop << " pedDist=" << pedDist << " factor=" << oncomingFactor << " dist2=" << dist << "\n";
    2053              :                         }
    2054              : #endif
    2055              :                     }
    2056              :                 }
    2057       153234 :                 if (ignoreFoe(ego, p)) {
    2058        25237 :                     continue;
    2059              :                 }
    2060       127997 :                 distToPeds = MIN2(distToPeds, dist);
    2061       127997 :                 if (collectBlockers != nullptr) {
    2062            0 :                     collectBlockers->push_back(p);
    2063              :                 }
    2064              :             }
    2065              :         }
    2066       125665 :         if (distToPeds != std::numeric_limits<double>::max()) {
    2067              :             // leave extra space in front
    2068        87077 :             result.emplace_back(nullptr, -1, distToPeds);
    2069              :         }
    2070       125665 :     }
    2071    579334242 : }
    2072              : 
    2073              : bool
    2074      1531611 : MSLink::isInFront(const MSVehicle* ego, const PositionVector& egoPath, const Position& pPos) const {
    2075      1531611 :     const double pedAngle = ego->getPosition().angleTo2D(pPos);
    2076      1531611 :     const double angleDiff = fabs(GeomHelper::angleDiff(ego->getAngle(), pedAngle));
    2077              : #ifdef DEBUG_WALKINGAREA
    2078              :     if (ego->isSelected()) {
    2079              :         std::cout << " angleDiff=" << RAD2DEG(angleDiff) << "\n";
    2080              :     }
    2081              : #endif
    2082      1531611 :     if (angleDiff < DEG2RAD(75)) {
    2083      1082758 :         return egoPath.distance2D(pPos) < ego->getVehicleType().getWidth() + MSPModel::SAFETY_GAP;
    2084              :     }
    2085              :     return false;
    2086              : }
    2087              : 
    2088              : 
    2089              : double
    2090       152943 : MSLink::isOnComingPed(const MSVehicle* ego, const MSPerson* p) const {
    2091       152943 :     const double pedToEgoAngle = p->getPosition().angleTo2D(ego->getPosition());
    2092       152943 :     const double angleDiff = fabs(GeomHelper::angleDiff(p->getAngle(), pedToEgoAngle));
    2093              : #ifdef DEBUG_WALKINGAREA
    2094              :     if (ego->isSelected()) {
    2095              :         std::cout << " ped-angleDiff=" << RAD2DEG(angleDiff) << " res=" << cos(angleDiff) << "\n";
    2096              :     }
    2097              : #endif
    2098       152943 :     if (angleDiff <= DEG2RAD(90)) {
    2099              :         ;
    2100        53949 :         return cos(angleDiff);
    2101              :     } else {
    2102              :         return 0;
    2103              :     }
    2104              : }
    2105              : 
    2106              : 
    2107              : Position
    2108       697523 : MSLink::getFuturePosition(const MSPerson* p, double timeHorizon) const {
    2109       697523 :     const double a = p->getAngle();
    2110       697523 :     const double dist = timeHorizon * p->getMaxSpeed();
    2111              : 
    2112       697523 :     const Position offset(cos(a) * dist, sin(a) * dist);
    2113       697523 :     return p->getPosition() + offset;
    2114              : }
    2115              : 
    2116              : 
    2117              : MSLink*
    2118     10503301 : MSLink::getParallelLink(int direction) const {
    2119     10503301 :     if (direction == -1) {
    2120      4027845 :         return myParallelRight;
    2121      6475456 :     } else if (direction == 1) {
    2122      5783239 :         return myParallelLeft;
    2123              :     } else {
    2124              :         assert(false || myLane->getOpposite() != nullptr || MSGlobals::gComputeLC);
    2125              :         return nullptr;
    2126              :     }
    2127              : }
    2128              : 
    2129              : MSLink*
    2130       169746 : MSLink::getOppositeDirectionLink() const {
    2131       169746 :     if (myLane->getOpposite() != nullptr && myLaneBefore->getOpposite() != nullptr) {
    2132        42821 :         for (MSLink* cand : myLane->getOpposite()->getLinkCont()) {
    2133        39649 :             if (cand->getLane() == myLaneBefore->getOpposite()) {
    2134              :                 return cand;
    2135              :             }
    2136              :         }
    2137              :     }
    2138              :     return nullptr;
    2139              : }
    2140              : 
    2141              : 
    2142              : MSLink*
    2143      5828690 : MSLink::computeParallelLink(int direction) {
    2144      5828690 :     const MSLane* const before = getLaneBefore()->getParallelLane(direction, false);
    2145      5828690 :     const MSLane* const after = getLane()->getParallelLane(direction, false);
    2146      5828690 :     if (before != nullptr && after != nullptr) {
    2147       997630 :         for (MSLink* const link : before->getLinkCont()) {
    2148       657711 :             if (link->getLane() == after) {
    2149              :                 return link;
    2150              :             }
    2151              :         }
    2152              :     }
    2153              :     return nullptr;
    2154              : }
    2155              : 
    2156              : 
    2157              : double
    2158      1327404 : MSLink::getZipperSpeed(const MSVehicle* ego, const double dist, double vSafe,
    2159              :                        SUMOTime arrivalTime,
    2160              :                        const BlockingFoes* foes) const {
    2161      1327404 :     if (myFoeLinks.size() == 0) {
    2162              :         // link should have LINKSTATE_MAJOR in this case
    2163              :         assert(false);
    2164              :         return vSafe;
    2165              :     }
    2166      1327404 :     const double brakeGap = ego->getCarFollowModel().brakeGap(vSafe, ego->getCarFollowModel().getMaxDecel(), TS);
    2167      1442784 :     if (dist > MAX2(myFoeVisibilityDistance, brakeGap)) {
    2168              : #ifdef DEBUG_ZIPPER
    2169              :         const SUMOTime now = MSNet::getInstance()->getCurrentTimeStep();
    2170              :         DEBUGOUT(DEBUG_COND_ZIPPER, SIMTIME << " getZipperSpeed ego=" << ego->getID()
    2171              :                  << " dist=" << dist << " bGap=" << brakeGap << " ignoring foes (arrival in " << STEPS2TIME(arrivalTime - now) << ")\n")
    2172              : #endif
    2173              :         return vSafe;
    2174              :     }
    2175              : #ifdef DEBUG_ZIPPER
    2176              :     DEBUGOUT(DEBUG_COND_ZIPPER, SIMTIME << " getZipperSpeed ego=" << ego->getID()
    2177              :              << " egoAT=" << arrivalTime
    2178              :              << " dist=" << dist
    2179              :              << " brakeGap=" << brakeGap
    2180              :              << " vSafe=" << vSafe
    2181              :              << " numFoes=" << foes->size()
    2182              :              << "\n")
    2183              : #endif
    2184              :     const bool uniqueFoeLink = myFoeLinks.size() == 1;
    2185       496377 :     MSLink* foeLink = myFoeLinks[0];
    2186      2598432 :     for (const auto& item : *foes) {
    2187      2102055 :         if (!item->isVehicle()) {
    2188            0 :             continue;
    2189              :         }
    2190      2102055 :         const MSVehicle* foe = dynamic_cast<const MSVehicle*>(item);
    2191              :         assert(foe != 0);
    2192              :         const ApproachingVehicleInformation* aviPtr = nullptr;
    2193      2102055 :         if (uniqueFoeLink) {
    2194      1396823 :             aviPtr = foeLink->getApproachingPtr(foe);
    2195              :         } else {
    2196              :             // figure out which link is approached by the current foe
    2197      1067476 :             for (MSLink* fl : myFoeLinks) {
    2198      1067476 :                 aviPtr = fl->getApproachingPtr(foe);
    2199      1067476 :                 if (aviPtr != nullptr) {
    2200              :                     break;
    2201              :                 }
    2202              :             }
    2203              :         }
    2204      2102055 :         if (aviPtr == nullptr) {
    2205            0 :             continue;
    2206              :         }
    2207              :         const ApproachingVehicleInformation& avi = *aviPtr;
    2208      2102055 :         const double foeDist = (foe->isActive() ? avi.dist : MAX2(0.0, avi.dist -
    2209           36 :                                 STEPS2TIME(MSNet::getInstance()->getCurrentTimeStep() - foe->getLastActionTime()) * avi.speed));
    2210              : 
    2211      1428779 :         if (    // ignore vehicles that arrive after us (unless they are ahead and we could easily brake for them)
    2212      2202786 :             ((avi.arrivalTime > arrivalTime) && !couldBrakeForLeader(dist, foeDist, ego, foe)) ||
    2213              :             // also ignore vehicles that are behind us and are able to brake for us
    2214      2202786 :             couldBrakeForLeader(foeDist, dist, foe, ego) ||
    2215              :             // resolve ties by lane index
    2216       673284 :             (avi.arrivalTime == arrivalTime && foeDist == dist && ego->getLane()->getIndex() < foe->getLane()->getIndex())) {
    2217              : #ifdef DEBUG_ZIPPER
    2218              :             if (DEBUG_COND_ZIPPER) std::cout
    2219              :                         << "    ignoring foe=" << foe->getID()
    2220              :                         << " foeAT=" << avi.arrivalTime
    2221              :                         << " foeDist=" << avi.dist
    2222              :                         << " foeDist2=" << foeDist
    2223              :                         << " foeSpeed=" << avi.speed
    2224              :                         << " egoSpeed=" << ego->getSpeed()
    2225              :                         << " deltaDist=" << foeDist - dist
    2226              :                         << " delteSpeed=" << avi.speed - foe->getCarFollowModel().getMaxDecel() - ego->getSpeed()
    2227              :                         << " egoCouldBrake=" << couldBrakeForLeader(dist, foeDist, ego, foe)
    2228              :                         << " foeCouldBrake=" << couldBrakeForLeader(foeDist, dist, foe, ego)
    2229              :                         << "\n";
    2230              : #endif
    2231      1428779 :             continue;
    2232              :         }
    2233              :         // the idea behind speed adaption is three-fold:
    2234              :         // 1) ego needs to be in a car-following relationship with foe eventually
    2235              :         //    thus, the ego speed should be equal to the follow speed once the foe enters
    2236              :         //    the zipper junction
    2237              :         // 2) ego vehicle needs to put a certain distance beteen himself and foe (safeGap)
    2238              :         //    achieving this distance can be spread over time but computing
    2239              :         //    safeGap is subject to estimation errors of future speeds
    2240              :         // 3) deceleration can be spread out over the time until true
    2241              :         //    car-following happens, at the start of speed adaptions, smaller
    2242              :         //    decelerations should be sufficient
    2243              : 
    2244              :         // we cannot trust avi.arrivalSpeed if the foe has leader vehicles that are accelerating
    2245              :         // lets try to extrapolate
    2246       673276 :         const double uMax = foe->getLane()->getVehicleMaxSpeed(foe);
    2247       673276 :         const double uAccel = foe->getCarFollowModel().estimateSpeedAfterDistance(foeDist, avi.speed, foe->getCarFollowModel().getMaxAccel());
    2248              :         const double uEnd = MIN2(uMax, uAccel);
    2249       673276 :         const double uAvg = (avi.speed + uEnd) / 2;
    2250       673276 :         const double tf0 = foeDist / MAX2(NUMERICAL_EPS, uAvg);
    2251       673276 :         const double tf = MAX2(1.0, ceil((tf0) / TS) * TS);
    2252              : 
    2253       673276 :         const double vMax = ego->getLane()->getVehicleMaxSpeed(ego);
    2254       673276 :         const double vAccel = ego->getCarFollowModel().estimateSpeedAfterDistance(dist, ego->getSpeed(), ego->getCarFollowModel().getMaxAccel());
    2255       673276 :         const double vDecel = ego->getCarFollowModel().estimateSpeedAfterDistance(dist, ego->getSpeed(), -ego->getCarFollowModel().getMaxDecel());
    2256              :         const double vEnd = MIN3(vMax, vAccel, MAX2(uEnd, vDecel));
    2257       673276 :         const double vAvg = (ego->getSpeed() + vEnd) / 2;
    2258       673276 :         const double te0 = dist / MAX2(NUMERICAL_EPS, vAvg);
    2259       673276 :         const double te = MAX2(1.0, ceil((te0) / TS) * TS);
    2260              : 
    2261       673276 :         const double tTarget = tf + ego->getCarFollowModel().getHeadwayTime();
    2262       673276 :         const double a = ego->getCarFollowModel().avoidArrivalAccel(dist, tTarget, vSafe, ego->getCarFollowModel().getMaxDecel());
    2263              : 
    2264       673276 :         const double gap = dist - foe->getVehicleType().getLength() - ego->getVehicleType().getMinGap() - foeDist;
    2265       673276 :         const double vFollow = ego->getCarFollowModel().followSpeed(
    2266       673276 :                                    ego, ego->getSpeed(), gap, avi.speed, foe->getCarFollowModel().getMaxDecel(), foe);
    2267       673276 :         const double vSafeGap = MAX2(vFollow, ego->getSpeed() + ACCEL2SPEED(a));
    2268              : 
    2269              :         // scale behavior based on ego time to link (te)
    2270       673276 :         const double w = MIN2(1.0, te / 10);
    2271       673276 :         const double maxDecel = w * ego->getCarFollowModel().getMaxDecel() + (1 - w) * ego->getCarFollowModel().getEmergencyDecel();
    2272       673276 :         const double vZipper = MAX3(vFollow, ego->getSpeed() - ACCEL2SPEED(maxDecel), vSafeGap);
    2273              : 
    2274              :         vSafe = MIN2(vSafe, vZipper);
    2275              : #ifdef DEBUG_ZIPPER
    2276              :         if (DEBUG_COND_ZIPPER) std::cout << "    adapting to foe=" << foe->getID()
    2277              :                                              << " foeDist=" << foeDist
    2278              :                                              << " foeSpeed=" << avi.speed
    2279              :                                              << " foeAS=" << avi.arrivalSpeed
    2280              :                                              << " egoSpeed=" << ego->getSpeed()
    2281              :                                              << " uMax=" << uMax
    2282              :                                              << " uAccel=" << uAccel
    2283              :                                              << " uEnd=" << uEnd
    2284              :                                              << " uAvg=" << uAvg
    2285              :                                              << " gap=" << gap
    2286              :                                              << "\n      "
    2287              :                                              << " tf=" << tf
    2288              :                                              << " te=" << te
    2289              :                                              << " aSafeGap=" << a
    2290              :                                              << " vMax=" << vMax
    2291              :                                              << " vAccel=" << vAccel
    2292              :                                              << " vDecel=" << vDecel
    2293              :                                              << " vEnd=" << vEnd
    2294              :                                              << " vSafeGap=" << vSafeGap
    2295              :                                              << " vFollow=" << vFollow
    2296              :                                              << " w=" << w
    2297              :                                              << " maxDecel=" << maxDecel
    2298              :                                              << " vZipper=" << vZipper
    2299              :                                              << " vSafe=" << vSafe
    2300              :                                              << "\n";
    2301              : #endif
    2302              :     }
    2303              :     return vSafe;
    2304              : }
    2305              : 
    2306              : 
    2307              : bool
    2308      2202786 : MSLink::couldBrakeForLeader(double followDist, double leaderDist, const MSVehicle* follow, const MSVehicle* leader) {
    2309              :     return (// leader is ahead of follower
    2310      2202786 :                followDist > leaderDist &&
    2311              :                // and follower could brake for 1 s to stay behind leader
    2312       397274 :                followDist - leaderDist > follow->getSpeed() - follow->getCarFollowModel().getMaxDecel() - leader->getSpeed());
    2313              : }
    2314              : 
    2315              : 
    2316              : void
    2317      2914345 : MSLink::initParallelLinks() {
    2318      2914345 :     myParallelRight = computeParallelLink(-1);
    2319      2914345 :     myParallelLeft = computeParallelLink(1);
    2320      2914345 : }
    2321              : 
    2322              : bool
    2323        76702 : MSLink::checkContOff() const {
    2324              :     // check whether this link gets to keep its cont status switching the tls off
    2325              :     // @note: this could also be pre-computed in netconvert
    2326              :     // we check whether there is any major link from this edge
    2327       223898 :     for (const MSLane* cand : myLaneBefore->getEdge().getLanes()) {
    2328       443157 :         for (const MSLink* link : cand->getLinkCont()) {
    2329       295961 :             if (link->getOffState() == LINKSTATE_TL_OFF_NOSIGNAL) {
    2330              :                 return true;
    2331              :             }
    2332              :         }
    2333              :     }
    2334              :     return false;
    2335              : }
    2336              : 
    2337              : bool
    2338      4360951 : MSLink::lateralOverlap(double posLat, double width, double posLat2, double width2) {
    2339      4360951 :     return fabs(posLat2 - posLat) < (width + width2) / 2;
    2340              : }
    2341              : 
    2342              : std::string
    2343            0 : MSLink::getDescription() const {
    2344            0 :     return myLaneBefore->getID() + "->" + getViaLaneOrLane()->getID();
    2345              : }
    2346              : 
    2347              : 
    2348              : bool
    2349    189278446 : MSLink::ignoreFoe(const SUMOTrafficObject* ego, const SUMOTrafficObject* foe) {
    2350    189278446 :     if (ego == nullptr || !ego->getParameter().wasSet(VEHPARS_JUNCTIONMODEL_PARAMS_SET)) {
    2351    189246007 :         return false;
    2352              :     }
    2353        32439 :     const SUMOVehicleParameter& param = ego->getParameter();
    2354        71050 :     for (const std::string& typeID : StringTokenizer(param.getParameter(toString(SUMO_ATTR_JM_IGNORE_TYPES), "")).getVector()) {
    2355        31537 :         if (typeID == foe->getVehicleType().getID()) {
    2356              :             return true;
    2357              :         }
    2358        32439 :     }
    2359        16136 :     for (const std::string& id : StringTokenizer(param.getParameter(toString(SUMO_ATTR_JM_IGNORE_IDS), "")).getVector()) {
    2360         2291 :         if (id == foe->getID()) {
    2361              :             return true;
    2362              :         }
    2363         7074 :     }
    2364         6771 :     return false;
    2365              : }
    2366              : 
    2367              : 
    2368              : void
    2369       110858 : MSLink::updateDistToFoePedCrossing(double dist) {
    2370       110858 :     myDistToFoePedCrossing = MIN2(myDistToFoePedCrossing, dist);
    2371       110858 : }
    2372              : 
    2373              : 
    2374              : std::pair<const SUMOVehicle* const, const MSLink::ApproachingVehicleInformation>
    2375      8766799 : MSLink::getClosest() const {
    2376              :     assert(getApproaching().size() > 0);
    2377              :     double minDist = std::numeric_limits<double>::max();
    2378              :     auto closestIt = getApproaching().begin();
    2379     17534327 :     for (auto apprIt = getApproaching().begin(); apprIt != getApproaching().end(); apprIt++) {
    2380      8767528 :         if (apprIt->second.dist < minDist) {
    2381              :             minDist = apprIt->second.dist;
    2382              :             closestIt = apprIt;
    2383              :         }
    2384              :     }
    2385              :     // maybe a parallel link has a closer vehicle
    2386              :     /*
    2387              :     for (MSLink* link2 : link->getLaneBefore()->getLinkCont()) {
    2388              :         if (link2 != link) {
    2389              :             for (auto apprIt2 = link2->getApproaching().begin(); apprIt2 != link2->getApproaching().end(); apprIt2++) {
    2390              :                 if (apprIt2->second.dist < minDist) {
    2391              :                     minDist = apprIt2->second.dist;
    2392              :                     closestIt = apprIt2;
    2393              :                 }
    2394              :             }
    2395              :         }
    2396              :     }
    2397              :     */
    2398      8766799 :     return *closestIt;
    2399              : }
    2400              : 
    2401              : 
    2402              : bool
    2403       473250 : MSLink::railSignalWasPassed() const {
    2404       473250 :     if (myJunction != nullptr && myJunction->getType() == SumoXMLNodeType::RAIL_SIGNAL) {
    2405         2009 :         for (const auto& item : myApproachingVehicles) {
    2406           12 :             if (item.second.dist < SPEED2DIST(item.first->getSpeed())) {
    2407              :                 return true;
    2408              :             }
    2409              :         }
    2410              :     }
    2411              :     return false;
    2412              : }
    2413              : 
    2414              : /****************************************************************************/
        

Generated by: LCOV version 2.0-1