LCOV - code coverage report
Current view: top level - src/microsim - MSLink.cpp (source / functions) Coverage Total Hit
Test: lcov.info Lines: 92.0 % 952 876
Test Date: 2026-09-20 15:45:03 Functions: 96.8 % 62 60

            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    489375959 : MSLink::ConflictInfo::getFoeLengthBehindCrossing(const MSLink* foeExitLink) const {
      84    489375959 :     if (flag == CONFLICT_DUMMY_MERGE) {
      85              :         return 0;
      86    479354866 :     } else if (foeConflictIndex >= 0) {
      87    457319697 :         return foeExitLink->myConflicts[foeConflictIndex].lengthBehindCrossing;
      88              :     } else {
      89              :         return -NO_INTERSECTION;
      90              :     }
      91              : }
      92              : 
      93              : double
      94    252670039 : MSLink::ConflictInfo::getFoeConflictSize(const MSLink* foeExitLink) const {
      95    252670039 :     if (foeConflictIndex >= 0) {
      96    230703588 :         return foeExitLink->myConflicts[foeConflictIndex].conflictSize;
      97              :     } else {
      98              :         return 0;
      99              :     }
     100              : }
     101              : 
     102              : double
     103    489508037 : MSLink::ConflictInfo::getLengthBehindCrossing(const MSLink* exitLink) const {
     104    489508037 :     if (flag == CONFLICT_STOP_AT_INTERNAL_JUNCTION) {
     105     20503901 :         return exitLink->getInternalLaneBefore()->getLength();
     106              :     } else {
     107    469004136 :         return lengthBehindCrossing;
     108              :     }
     109              : }
     110              : 
     111              : // ===========================================================================
     112              : // member method definitions
     113              : // ===========================================================================
     114      2967056 : 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      2967056 :                bool indirect) :
     118      2967056 :     myLane(succLane),
     119      2967056 :     myLaneBefore(predLane),
     120      2967056 :     myApproachingPersons(nullptr),
     121      2967056 :     myIndex(-1),
     122      2967056 :     myTLIndex(tlIndex),
     123      2967056 :     myLogic(logic),
     124      2967056 :     myState(state),
     125      2967056 :     myLastGreenState(LINKSTATE_TL_GREEN_MINOR),
     126      2967056 :     myOffState(state),
     127      2967056 :     myLastStateChange(SUMOTime_MIN / 2), // a large negative value, but avoid overflows when subtracting
     128      2967056 :     myDirection(dir),
     129      2967056 :     myLength(length),
     130      2967056 :     myFoeVisibilityDistance(foeVisibilityDistance),
     131      2967056 :     myDistToFoePedCrossing(std::numeric_limits<double>::max()),
     132      2967056 :     myHasFoes(false),
     133      2967056 :     myAmCont(false),
     134      2967056 :     myAmContOff(false),
     135      2967056 :     myKeepClear(keepClear),
     136      2967056 :     myInternalLane(via),
     137      2967056 :     myInternalLaneBefore(nullptr),
     138      2967056 :     myMesoTLSPenalty(0),
     139      2967056 :     myGreenFraction(1),
     140      2967056 :     myLateralShift(0),
     141      2967056 :     myOffFoeLinks(nullptr),
     142      2967056 :     myWalkingAreaFoe(nullptr),
     143      2967056 :     myWalkingAreaFoeExit(nullptr),
     144      2967056 :     myHavePedestrianCrossingFoe(false),
     145      2967056 :     myParallelRight(nullptr),
     146      2967056 :     myParallelLeft(nullptr),
     147      2967056 :     myAmIndirect(indirect),
     148      2967056 :     myRadius(std::numeric_limits<double>::max()),
     149      2967056 :     myPermissions(0),
     150      2967056 :     myJunction(nullptr) 
     151              : {
     152      2967056 :     updatePermissions();
     153      2967056 :     if (MSGlobals::gLateralResolution > 0) {
     154              :         // detect lateral shift from lane geometries
     155              :         //std::cout << "DEBUG link=" << myLaneBefore->getID() << "->" << getViaLaneOrLane()->getID() << " hasInternal=" << MSNet::getInstance()->hasInternalLinks() << " shapeBefore=" << myLaneBefore->getShape().back() << " shapeFront=" << getViaLaneOrLane()->getShape().front() << "\n";
     156       207124 :         if ((myInternalLane != nullptr || predLane->isInternal())
     157       516998 :                 && myLaneBefore->getShape().back() != getViaLaneOrLane()->getShape().front()) {
     158              :             PositionVector from = myLaneBefore->getShape();
     159              :             const PositionVector& to = getViaLaneOrLane()->getShape();
     160              :             const double dist = from.back().distanceTo2D(to.front());
     161              :             // figure out direction of shift
     162              :             try {
     163          652 :                 from.move2side(dist);
     164            0 :             } catch (InvalidArgument&) {
     165            0 :             }
     166          652 :             myLateralShift = (from.back().distanceTo2D(to.front()) < dist) ? dist : -dist;
     167          652 :             if (MSGlobals::gLefthand) {
     168           90 :                 myLateralShift *= -1;
     169              :             }
     170              :             //std::cout << " lateral shift link=" << myLaneBefore->getID() << "->" << getViaLaneOrLane()->getID() << " dist=" << dist << " shift=" << myLateralShift << "\n";
     171          652 :         }
     172              :     }
     173      2967056 : }
     174              : 
     175              : 
     176      2940243 : MSLink::~MSLink() {
     177      2940243 :     delete myOffFoeLinks;
     178      2941574 :     delete myApproachingPersons;
     179      2940243 : }
     180              : 
     181              : 
     182              : void
     183      2970823 : MSLink::updatePermissions() {
     184              :     // we only ever increase permission because transient permission reductions lead to invalid bestLanes assignment otherwise
     185      2970823 :     myPermissions |= myLaneBefore->getPermissions() & myLane->getPermissions() & (myInternalLane == nullptr ? SVCAll : myInternalLane->getPermissions());
     186      2970823 : }
     187              : 
     188              : 
     189              : void
     190            6 : MSLink::addCustomConflict(const MSLane* from, const MSLane* to, double startPos, double endPos) {
     191            6 :     myCustomConflicts.push_back(CustomConflict(from, to, startPos, endPos));
     192            6 : }
     193              : 
     194              : const MSLink::CustomConflict*
     195      4153856 : MSLink::getCustomConflict(const MSLane* foeLane) const {
     196      4153856 :     if (myCustomConflicts.size() > 0) {
     197           24 :         const MSLane* foeFrom = foeLane->getNormalPredecessorLane();
     198           24 :         const MSLane* foeTo = foeLane->getNormalSuccessorLane();
     199           36 :         for (const CustomConflict& cc : myCustomConflicts) {
     200           24 :             if (cc.from == foeFrom && cc.to == foeTo) {
     201              :                 return &cc;
     202              :             }
     203              :         }
     204              : 
     205              :     }
     206              :     return nullptr;
     207              : }
     208              : 
     209              : void
     210      2685681 : MSLink::setRequestInformation(int index, bool hasFoes, bool isCont,
     211              :                               const std::vector<MSLink*>& foeLinks,
     212              :                               const std::vector<MSLane*>& foeLanes,
     213              :                               MSLane* internalLaneBefore) {
     214              : //#ifdef MSLink_DEBUG_CROSSING_POINTS
     215              : //    std::cout << " setRequestInformation() for junction " << getViaLaneOrLane()->getEdge().getFromJunction()->getID()
     216              : //            << "\nInternalLanes = " << toString(getViaLaneOrLane()->getEdge().getFromJunction()->getInternalLanes())
     217              : //            << std::endl;
     218              : //#endif
     219      2685681 :     myIndex = index;
     220      2685681 :     myHasFoes = hasFoes;
     221      2685681 :     myAmCont = isCont && MSGlobals::gUsingInternalLanes;
     222      2685681 :     myFoeLinks = foeLinks;
     223     10319917 :     for (MSLane* foeLane : foeLanes) {
     224              :         // cannot assign vector due to const-ness
     225      7634236 :         myFoeLanes.push_back(foeLane);
     226              :     }
     227      2685681 :     myJunction = const_cast<MSJunction*>(myLane->getEdge().getFromJunction()); // junctionGraph is initialized after the whole network is loaded
     228      2685681 :     myAmContOff = isCont && myLogic != nullptr && internalLaneBefore == nullptr && checkContOff();
     229      2685681 :     myInternalLaneBefore = internalLaneBefore;
     230              :     MSLane* lane = nullptr;
     231              :     if (internalLaneBefore != nullptr) {
     232              :         // this is an exit link. compute crossing points with all foeLanes
     233              :         lane = internalLaneBefore;
     234              :         //} else if (myLane->isCrossing()) {
     235              :         //    // this is the link to a pedestrian crossing. compute crossing points with all foeLanes
     236              :         //    // @note not currently used by pedestrians
     237              :         //    lane = myLane;
     238              :     }
     239      2685681 :     const MSLink* entryLink = getCorrespondingEntryLink();
     240      2685681 :     if (entryLink->getOffState() == LinkState::LINKSTATE_ALLWAY_STOP && entryLink->getTLLogic() != nullptr) {
     241              :         // TLS has "normal" right of way rules but all conflicting links are foes when switching TLS off
     242              :         // (unless it's an internal junction link which should ignore all foes and should be ignored by all foes
     243         5762 :         myOffFoeLinks = new std::vector<MSLink*>();
     244         5762 :         if (isEntryLink()) {
     245        15648 :             for (MSLane* foeLane : foeLanes) {
     246              :                 assert(foeLane->isInternal() || foeLane->isCrossing());
     247        13140 :                 MSLink* viaLink = foeLane->getIncomingLanes().front().viaLink;
     248        13140 :                 if (viaLink->getLaneBefore()->isNormal()) {
     249         7960 :                     myOffFoeLinks->push_back(viaLink);
     250              :                 }
     251              :             }
     252              :         }
     253              :     }
     254              : #ifdef MSLink_DEBUG_CROSSING_POINTS
     255              :     std::cout << "link " << myIndex << " to " << getViaLaneOrLane()->getID() << " internalLaneBefore=" << (lane == 0 ? "NULL" : lane->getID()) << " has foes: " << toString(foeLanes) << "\n";
     256              : #endif
     257      2685681 :     if (lane != nullptr) {
     258      1049641 :         const bool beforeInternalJunction = lane->getLinkCont()[0]->getViaLaneOrLane()->getEdge().isInternal();
     259      1049641 :         if (lane->getIncomingLanes().size() != 1) {
     260            0 :             throw ProcessError(TLF("Internal lane '%' has % predecessors", lane->getID(), toString(lane->getIncomingLanes().size())));
     261              :         }
     262      1049641 :         const MSLink* junctionEntryLink = lane->getEntryLink();
     263      1049641 :         const bool isSecondPart = isExitLinkAfterInternalJunction();
     264              :         // compute crossing points
     265      5364806 :         for (const MSLane* foeLane : myFoeLanes) {
     266      4315165 :             const CustomConflict* cc = junctionEntryLink != nullptr ? junctionEntryLink->getCustomConflict(foeLane) : nullptr;
     267      4153844 :             if (cc != nullptr) {
     268              :                 // handle custom conflict definition
     269           12 :                 double startPos = cc->startPos;
     270           12 :                 const double conflictSize = cc->endPos - cc->startPos;
     271           12 :                 if (isSecondPart) {
     272            0 :                     startPos -= junctionEntryLink->getViaLane()->getLength();
     273              :                 }
     274              :                 // the foe connection may be split at an internal
     275              :                 // junction, we need to figure out whether the current
     276              :                 // foeLane is the intended target for the custom conflict
     277              :                 // There are two possibilities:
     278              :                 // a) We have no custom conflict for the reverse pair of connections
     279              :                 //    -> just check whether lane and foeLane intersect
     280              :                 // b) We have a "reverse" custom conflict
     281              :                 //    -> check whether it covers the foeLane
     282           12 :                 const CustomConflict* rcc = foeLane->getEntryLink()->getCustomConflict(lane);
     283              :                 bool haveIntersection = false;
     284           12 :                 if (rcc == nullptr) {
     285              :                     // a)
     286           12 :                     haveIntersection = lane->getShape().intersectsAtLengths2D(foeLane->getShape()).size() > 0;
     287              :                 } else {
     288              :                     // b)
     289            0 :                     const bool foeIsSecondPart = foeLane->getLogicalPredecessorLane()->isInternal();
     290            0 :                     double foeStartPos = rcc->startPos;
     291            0 :                     const double foeConflictSize = rcc->endPos - rcc->startPos;
     292            0 :                     if (foeIsSecondPart) {
     293            0 :                         foeStartPos -= foeLane->getLogicalPredecessorLane()->getLength();
     294              :                     }
     295            0 :                     const double foeEndPos = foeStartPos + foeConflictSize;
     296            0 :                     haveIntersection = ((foeStartPos > 0 && foeStartPos < foeLane->getLength())
     297            0 :                                         || (foeEndPos > 0 && foeEndPos < foeLane->getLength()));
     298              :                 }
     299           12 :                 if (haveIntersection) {
     300            6 :                     myConflicts.push_back(ConflictInfo(lane->getLength() - startPos, conflictSize));
     301              :                 } else {
     302            6 :                     myConflicts.push_back(ConflictInfo(-NO_INTERSECTION, 0));
     303              :                 }
     304              : #ifdef MSLink_DEBUG_CROSSING_POINTS
     305              :                 std::cout << " " << lane->getID() << " custom conflict with " << foeLane->getID() << " customReverse=" << (rcc != nullptr)
     306              :                           << " haveIntersection=" << haveIntersection
     307              :                           << " startPos=" << startPos << " conflictSize=" << conflictSize
     308              :                           << " lbc=" << myConflicts.back().lengthBehindCrossing
     309              :                           << "\n";
     310              : #endif
     311           12 :                 continue;
     312           12 :             }
     313      4315153 :             myHavePedestrianCrossingFoe = myHavePedestrianCrossingFoe || foeLane->isCrossing();
     314      4315153 :             const bool sameTarget = myLane == foeLane->getLinkCont()[0]->getLane();
     315      4315153 :             if (sameTarget && !beforeInternalJunction && !contIntersect(lane, foeLane)) {
     316              :                 //if (myLane == foeLane->getLinkCont()[0]->getLane()) {
     317              :                 // this foeLane has the same target and merges at the end (lane exits the junction)
     318      1450393 :                 const double minDist = MIN2(DIVERGENCE_MIN_WIDTH, 0.5 * (lane->getWidth() + foeLane->getWidth()));
     319      1450393 :                 if (lane->getShape().back().distanceTo2D(foeLane->getShape().back()) >= minDist) {
     320              :                     // account for lateral shift by the entry links
     321       131237 :                     if (foeLane->getEntryLink()->isIndirect()) {
     322           41 :                         myConflicts.push_back(ConflictInfo(-NO_INTERSECTION, 0)); // dummy value, never used
     323              : #ifdef MSLink_DEBUG_CROSSING_POINTS
     324              :                         std::cout << " " << lane->getID() << " dummy merge with indirect" << foeLane->getID() << "\n";
     325              : #endif
     326              :                     } else {
     327       131196 :                         myConflicts.push_back(ConflictInfo(0, foeLane->getWidth(), CONFLICT_DUMMY_MERGE)); // dummy value, never used
     328              : #ifdef MSLink_DEBUG_CROSSING_POINTS
     329              :                         std::cout << " " << lane->getID() << " dummy merge with " << foeLane->getID() << "\n";
     330              : #endif
     331              :                     }
     332              :                 } else {
     333      1319156 :                     const double distAfterDivergence = computeDistToDivergence(lane, foeLane, minDist, false);
     334              :                     const double lbcLane = lane->interpolateGeometryPosToLanePos(distAfterDivergence);
     335      1319156 :                     myConflicts.push_back(ConflictInfo(lbcLane, foeLane->getWidth()));
     336              : #ifdef MSLink_DEBUG_CROSSING_POINTS
     337              :                     std::cout
     338              :                             << " " << lane->getID()
     339              :                             << " merges with " << foeLane->getID()
     340              :                             << " nextLane " << lane->getLinkCont()[0]->getViaLaneOrLane()->getID()
     341              :                             << " dist1=" << myConflicts.back().lengthBehindCrossing
     342              :                             << "\n";
     343              : #endif
     344              :                 }
     345              :             } else {
     346      2864760 :                 std::vector<double> intersections1 = lane->getShape().intersectsAtLengths2D(foeLane->getShape());
     347              : #ifdef MSLink_DEBUG_CROSSING_POINTS_DETAILS
     348              :                 std::cout << "    intersections1=" << toString(intersections1) << "\n";
     349              : #endif
     350              :                 bool haveIntersection = true;
     351      2864760 :                 if (intersections1.size() == 0) {
     352      1487251 :                     intersections1.push_back(-NO_INTERSECTION); // disregard this foe (using maxdouble leads to nasty problems down the line)
     353              :                     haveIntersection = false;
     354      1377509 :                 } else if (intersections1.size() > 1) {
     355         1306 :                     std::sort(intersections1.begin(), intersections1.end());
     356              :                 }
     357      2864760 :                 std::vector<double> intersections2 = foeLane->getShape().intersectsAtLengths2D(lane->getShape());
     358              : #ifdef MSLink_DEBUG_CROSSING_POINTS_DETAILS
     359              :                 std::cout << "    intersections2=" << toString(intersections2) << "\n";
     360              : #endif
     361      2864760 :                 if (intersections2.size() == 0) {
     362      1487251 :                     intersections2.push_back(0);
     363      1377509 :                 } else if (intersections2.size() > 1) {
     364         1306 :                     std::sort(intersections2.begin(), intersections2.end());
     365              :                 }
     366              : 
     367              :                 // check for near-intersection (internal junctions for a side road which are only relevant when they have stranded vehicles))
     368      2864760 :                 if (!haveIntersection && foeLane->getLinkCont()[0]->getViaLane() != nullptr) {
     369       266031 :                     const Position waitPos = foeLane->getShape().back();
     370       266031 :                     const double dist = lane->getShape().distance2D(waitPos, true);
     371       266031 :                     if (dist != GeomHelper::INVALID_OFFSET && dist < lane->getWidth() / 2) {
     372              :                         // risk of collision
     373              :                         intersections1.clear();
     374              :                         intersections2.clear();
     375        31012 :                         intersections1.push_back(lane->getShape().nearest_offset_to_point2D(waitPos));
     376        31012 :                         intersections2.push_back(foeLane->getShape().length());
     377              :                         haveIntersection = true;
     378              : #ifdef MSLink_DEBUG_CROSSING_POINTS_DETAILS
     379              :                         std::cout << "    link=" << myIndex << " " << getDescription() << " almostIntersection with foeLane " << foeLane->getID() << " offset=" << intersections1.back() << "\n";
     380              : #endif
     381              :                     }
     382              :                 }
     383              : 
     384              :                 double conflictSize = foeLane->getWidth();
     385              :                 ConflictFlag flag = CONFLICT_NO_INTERSECTION;
     386      2833748 :                 if (haveIntersection) {
     387              :                     flag = CONFLICT_DEFAULT;
     388      1408521 :                     const double angle1 = GeomHelper::naviDegree(lane->getShape().rotationAtOffset(intersections1.back()));
     389      1408521 :                     const double angle2 = GeomHelper::naviDegree(foeLane->getShape().rotationAtOffset(intersections2.back()));
     390      1408521 :                     const double angleDiff = GeomHelper::getMinAngleDiff(angle1, angle2);
     391              :                     //const double angleDiff = MIN2(GeomHelper::getMinAngleDiff(angle1, angle2),
     392              :                     //                              GeomHelper::getMinAngleDiff(angle1, angle2 + 180));
     393      1408521 :                     const double widthFactor = 1 / MAX2(sin(DEG2RAD(angleDiff)), 0.2) * 2 - 1;
     394              :                     //std::cout << "  intersection of " << lane->getID() << " with " << foeLane->getID() << " angle1=" << angle1 << " angle2=" << angle2 << " angleDiff=" << angleDiff << " widthFactor=" << widthFactor << "\n";
     395      1408521 :                     conflictSize *= widthFactor;
     396              :                     conflictSize = MIN2(conflictSize, lane->getLength());
     397              :                     // lane width affects the crossing point
     398      1408521 :                     intersections1.back() -= conflictSize / 2;
     399              :                     // ensure non-negative offset for weird geometries
     400      1408521 :                     intersections1.back() = MAX2(0.0, intersections1.back());
     401              : 
     402              :                     // also length/geometry factor. (XXX: Why subtract width/2 *before* converting geometric position to lane pos? refs #3031)
     403      1408521 :                     intersections1.back() = lane->interpolateGeometryPosToLanePos(intersections1.back());
     404              : 
     405      1408521 :                     if (internalLaneBefore->getLogicalPredecessorLane()->getEdge().isInternal() && !foeLane->isCrossing())  {
     406              :                         flag = CONFLICT_STOP_AT_INTERNAL_JUNCTION;
     407              :                     }
     408              : 
     409      1408521 :                     if (foeLane->isCrossing()) {
     410       112873 :                         const MSLink* before = myInternalLaneBefore->getCanonicalPredecessorLane()->getLinkTo(myInternalLaneBefore);
     411       112873 :                         const_cast<MSLink*>(before)->updateDistToFoePedCrossing(intersections1.back());
     412              :                     };
     413              :                 }
     414              : 
     415      2864760 :                 myConflicts.push_back(ConflictInfo(
     416      2864760 :                                           lane->getLength() - intersections1.back(),
     417              :                                           conflictSize, flag));
     418              : 
     419              : #ifdef MSLink_DEBUG_CROSSING_POINTS
     420              :                 std::cout
     421              :                         << "  intersection of " << lane->getID()
     422              :                         << " totalLength=" << lane->getLength()
     423              :                         << " with " << foeLane->getID()
     424              :                         << " totalLength=" << foeLane->getLength()
     425              :                         << " dist1=" << myConflicts.back().lengthBehindCrossing
     426              :                         << " widthFactor=" << myConflicts.back().conflictSize / foeLane->getWidth()
     427              :                         << "\n";
     428              : #endif
     429      2864760 :             }
     430              :         }
     431              :         // check for overlap with internal lanes from the same source lane
     432      1049641 :         const MSLane* pred = lane->getLogicalPredecessorLane();
     433              :         // to avoid overlap with vehicles that came from pred (especially when pred has endOffset > 0)
     434              :         // we add all other internal lanes from pred as foeLanes
     435      3436649 :         for (const MSLink* const link : pred->getLinkCont()) {
     436      2387008 :             const MSLane* const sibling = link->getViaLane();
     437      2387008 :             if (sibling != lane && sibling != nullptr) {
     438      1312416 :                 const double minDist = MIN2(DIVERGENCE_MIN_WIDTH, 0.5 * (lane->getWidth() + sibling->getWidth()));
     439      1312416 :                 if (lane->getShape().front().distanceTo2D(sibling->getShape().front()) >= minDist) {
     440              :                     // account for lateral shift by the entry links
     441          630 :                     continue;
     442              :                 }
     443      1311786 :                 const double distToDivergence = computeDistToDivergence(lane, sibling, minDist, true);
     444              :                 double lbcLane;
     445      1311786 :                 if (lane->getLength() == sibling->getLength() && &lane->getEdge() == &sibling->getEdge()) {
     446              :                     // for parallel lanes, avoid inconsistency in distance estimation (#10988)
     447              :                     // between forward distance (getLeaderInfo)
     448              :                     // and backward distance used in lane-changing (getFollowersOnConsecutive)
     449        18196 :                     lbcLane = lane->getLength() - distToDivergence;
     450              :                 } else {
     451      1293590 :                     lbcLane = MAX2(0.0, lane->getLength() - lane->interpolateGeometryPosToLanePos(distToDivergence));
     452              :                 }
     453              :                 ConflictInfo ci = ConflictInfo(lbcLane, sibling->getWidth());
     454      1311786 :                 auto it = std::find(myFoeLanes.begin(), myFoeLanes.end(), sibling);
     455      1311786 :                 if (it != myFoeLanes.end()) {
     456              :                     // avoid duplicate foeLane
     457           90 :                     const int replacedIndex = (int)(it - myFoeLanes.begin());
     458           90 :                     myConflicts[replacedIndex] = ci;
     459              :                 } else {
     460      1311696 :                     myConflicts.push_back(ci);
     461      1311696 :                     myFoeLanes.push_back(sibling);
     462              :                 }
     463              : #ifdef MSLink_DEBUG_CROSSING_POINTS
     464              :                 std::cout << " adding same-origin foe" << sibling->getID()
     465              :                           << " dist1=" << myConflicts.back().lengthBehindCrossing
     466              :                           << "\n";
     467              : #endif
     468      1311786 :                 const MSLane* const siblingCont = sibling->getLinkCont().front()->getViaLaneOrLane();
     469      1311786 :                 if (siblingCont->isInternal() && lane->getShape().distance2D(siblingCont->getShape().front()) < minDist) {
     470              :                     // there may still be overlap with siblingCont (when considering vehicle widths)
     471       298569 :                     const double maxCommonLength = MIN2(lane->getLength(), sibling->getLength() + siblingCont->getLength());
     472       298569 :                     const double lengthBehindDivergence = MAX2(0.0, lane->getLength() - maxCommonLength);
     473              :                     ConflictInfo ci2 = ConflictInfo(lengthBehindDivergence, siblingCont->getWidth(), CONFLICT_SIBLING_CONTINUATION);
     474       298569 :                     myConflicts.push_back(ci2);
     475       298569 :                     myFoeLanes.push_back(siblingCont);
     476       298569 :                     myRecheck.insert({this, siblingCont->getLinkCont().front()});
     477              : 
     478              : #ifdef MSLink_DEBUG_CROSSING_POINTS
     479              :                     std::cout << " adding same-origin foeContinuation" << siblingCont->getID()
     480              :                               << " dist1=" << myConflicts.back().lengthBehindCrossing
     481              :                               << "\n";
     482              : #endif
     483              :                 }
     484              :             }
     485              :         }
     486              :         // init points for the symmetrical conflict
     487              :         // for each pair of conflicting lanes, the link that gets second, sets the pointers
     488      6975071 :         for (int i = 0; i < (int)myFoeLanes.size(); i++) {
     489      5925430 :             const MSLane* foeLane = myFoeLanes[i];
     490      5925430 :             MSLink* foeExitLink = foeLane->getLinkCont()[0];
     491              :             int foundIndex = -1;
     492     22241712 :             for (int i2 = 0; i2 < (int)foeExitLink->myFoeLanes.size(); i2++) {
     493     18865568 :                 if (foeExitLink->myFoeLanes[i2] == lane) {
     494      2549286 :                     myConflicts[i].foeConflictIndex = i2;
     495      2549286 :                     foeExitLink->myConflicts[i2].foeConflictIndex = i;
     496      2549286 :                     myRecheck.erase({foeExitLink, this});
     497              :                     foundIndex = i2;
     498      2549286 :                     break;
     499              :                 }
     500              :             }
     501              : #ifdef MSLink_DEBUG_CROSSING_POINTS
     502              :             std::cout << lane->getID() << " foeLane=" << foeLane->getID() << " index=" << i << " foundIndex=" << foundIndex << "\n";
     503              : #endif
     504      5925430 :             if (foundIndex < 0) {
     505      3376144 :                 if (myConflicts[i].flag != CONFLICT_NO_INTERSECTION) {
     506      2456213 :                     myRecheck.insert({this, foeExitLink});
     507              :                 }
     508              :             }
     509              :         }
     510              :     }
     511      2685681 :     if (MSGlobals::gLateralResolution > 0) {
     512              :         // check for links with the same origin lane and the same destination edge
     513       297897 :         const MSEdge* myTarget = &myLane->getEdge();
     514              :         // save foes for entry links
     515       941174 :         for (MSLink* const it : myLaneBefore->getLinkCont()) {
     516              :             const MSEdge* target = &(it->getLane()->getEdge());
     517       643277 :             if (it == this) {
     518       297897 :                 continue;
     519              :             }
     520       345380 :             if (target == myTarget) {
     521         6804 :                 mySublaneFoeLinks.push_back(it);
     522              : #ifdef MSLink_DEBUG_CROSSING_POINTS
     523              :                 std::cout << "  sublaneFoeLink (same target): " << it->getViaLaneOrLane()->getID() << "\n";
     524              : #endif
     525       338576 :             } else if (myDirection != LinkDirection::STRAIGHT && it->getDirection() == LinkDirection::STRAIGHT) {
     526              :                 // potential turn conflict
     527        82850 :                 mySublaneFoeLinks2.push_back(it);
     528              : #ifdef MSLink_DEBUG_CROSSING_POINTS
     529              :                 std::cout << "  sublaneFoeLink2 (other target: " << it->getViaLaneOrLane()->getID() << "\n";
     530              : #endif
     531              :             }
     532              :         }
     533              :         // save foes for exit links
     534       297897 :         if (fromInternalLane()) {
     535              :             //std::cout << " setRequestInformation link=" << getViaLaneOrLane()->getID() << " before=" << myLaneBefore->getID() << " before2=" << myLaneBefore->getIncomingLanes().front().lane->getID() << "\n";
     536       371556 :             for (const MSLink* const link : myLaneBefore->getIncomingLanes().front().lane->getLinkCont()) {
     537       261070 :                 if (link->getViaLane() != myInternalLaneBefore && &link->getLane()->getEdge() == myTarget) {
     538              :                     //std::cout << " add sublaneFoe=" << (*it)->getViaLane()->getID() << "\n";
     539         4360 :                     mySublaneFoeLanes.push_back(link->getViaLane());
     540              :                 }
     541              :             }
     542              :         }
     543              :     }
     544      2685681 :     if (myInternalLaneBefore != nullptr
     545      1049641 :             && myDirection != LinkDirection::STRAIGHT
     546              :             // for right turns, the curvature helps rather than restricts the linkLeader check
     547       616005 :             && (
     548       616005 :                 (!MSGlobals::gLefthand && myDirection != LinkDirection::RIGHT)
     549       180097 :                 || (MSGlobals::gLefthand && myDirection != LinkDirection::LEFT))) {
     550       872726 :         const double angle = fabs(GeomHelper::angleDiff(
     551       436363 :                                       myLaneBefore->getNormalPredecessorLane()->getShape().angleAt2D(-2),
     552       436363 :                                       myLane->getShape().angleAt2D(0)));
     553       436363 :         if (angle > 0) {
     554       436363 :             double length = myInternalLaneBefore->getShape().length2D();
     555       872726 :             if (myInternalLaneBefore->getIncomingLanes().size() == 1 &&
     556       436363 :                     myInternalLaneBefore->getIncomingLanes()[0].lane->isInternal()) {
     557       125293 :                 length += myInternalLaneBefore->getIncomingLanes()[0].lane->getShape().length2D();
     558       311070 :             } else if (myInternalLane != nullptr) {
     559       125293 :                 length += myInternalLane->getShape().length2D();
     560              :             }
     561       436363 :             myRadius = length / angle;
     562              :             //std::cout << getDescription() << " a=" << RAD2DEG(angle) << " l=" << length << " r=" << myRadius << "\n";
     563              :         }
     564              :     }
     565      2685681 : }
     566              : 
     567              : 
     568              : void
     569        42584 : MSLink::recheckSetRequestInformation() {
     570       362648 :     for (auto item : myRecheck) {
     571              : #ifdef MSLink_DEBUG_CROSSING_POINTS
     572              :         std::cout << " recheck l1=" << item.first->getDescription() << " l2=" << item.second->getDescription() << "\n";
     573              : #endif
     574              :         MSLink* const link = item.first;
     575              :         MSLink* const foeExitLink = item.second;
     576              :         const MSLane* const lane = link->getInternalLaneBefore();
     577              :         const MSLane* const foeLane = foeExitLink->getInternalLaneBefore();
     578              :         int conflictIndex = -1;
     579      2790275 :         for (int i = 0; i < (int)link->myFoeLanes.size(); i++) {
     580      2790275 :             if (link->myFoeLanes[i] == foeLane) {
     581              :                 conflictIndex = i;
     582              :                 break;
     583              :             }
     584              :         }
     585       320064 :         if (conflictIndex == -1) {
     586            0 :             WRITE_WARNING("Could not recheck ConflictInfo for " + link->getDescription() + " and " + foeExitLink->getDescription() + "\n");
     587       298813 :             continue;
     588              :         }
     589       320064 :         ConflictInfo& ci = link->myConflicts[conflictIndex];
     590       320064 :         if (ci.flag & CONFLICT_SIBLING_CONTINUATION) {
     591       298563 :             const MSLane* const intLane = link->getInternalLaneBefore();
     592              :             const MSLane* const siblingCont = foeExitLink->getInternalLaneBefore();
     593       298563 :             const MSLane* const sibling = siblingCont->getLogicalPredecessorLane();
     594              :             // this is an approximation because intLane and sibling+siblingCont are still close to each other but may have different curvature
     595       298563 :             const double distToDivergence = intLane->getLength() - ci.lengthBehindCrossing;
     596       298563 :             double lbcSibCont = MIN2(siblingCont->getLength(), MAX2(0.0, sibling->getLength() + siblingCont->getLength() - distToDivergence));
     597              : #ifdef MSLink_DEBUG_CROSSING_POINTS
     598              :             std::cout << " siblingContinuation: distToDivergence=" << distToDivergence << " lbcSibCont=" << lbcSibCont << "\n";
     599              :             std::cout << " conflictIndex=" << conflictIndex << " foeLane=" << foeLane->getID() << " foeExitLink=" << foeExitLink->getDescription() << " intLane=" << intLane->getID() << "\n";
     600              : #endif
     601              :             ConflictInfo ci2 = ConflictInfo(lbcSibCont, intLane->getWidth());
     602       298563 :             ci2.foeConflictIndex = conflictIndex;
     603       298563 :             ci.foeConflictIndex = (int)foeExitLink->myConflicts.size();
     604       298563 :             foeExitLink->myFoeLanes.push_back(intLane);
     605       298563 :             foeExitLink->myConflicts.push_back(ci2);
     606              :             continue;
     607       298563 :         }
     608              : 
     609        21501 :         std::vector<double> intersections1 = foeLane->getShape().intersectsAtLengths2D(lane->getShape());
     610        21501 :         if (intersections1.size() == 0) {
     611              : #ifdef MSLink_DEBUG_CROSSING_POINTS
     612              :             std::cout << "    no intersection\n";
     613              : #endif
     614              :             continue;
     615              :         }
     616        21251 :         const double widthFactor = ci.conflictSize / foeLane->getWidth();
     617        21251 :         const double conflictSize2 = lane->getWidth() * widthFactor;
     618        21251 :         std::sort(intersections1.begin(), intersections1.end());
     619        21251 :         intersections1.back() -= conflictSize2 / 2;
     620        21251 :         intersections1.back() = MAX2(0.0, intersections1.back());
     621        21251 :         ci.foeConflictIndex = (int)foeExitLink->myConflicts.size();
     622        21251 :         foeExitLink->myConflicts.push_back(ConflictInfo(foeLane->getLength() - intersections1.back(), conflictSize2));
     623              : #ifdef MSLink_DEBUG_CROSSING_POINTS
     624              :         std::cout << "    ci=" << conflictIndex << " wf=" << widthFactor << " flag=" << ci.flag << " flbc=" << foeExitLink->myConflicts.back().lengthBehindCrossing << "\n";
     625              : #endif
     626        21501 :     }
     627              :     myRecheck.clear();
     628        42584 : }
     629              : 
     630              : double
     631      2630942 : MSLink::computeDistToDivergence(const MSLane* lane, const MSLane* sibling, double minDist, bool sameSource, double siblingPredLength) const {
     632              :     double lbcSibling = 0;
     633              :     double lbcLane = 0;
     634              : 
     635              :     PositionVector l = lane->getShape();
     636              :     PositionVector s = sibling->getShape();
     637      2630942 :     double length = l.length2D();
     638      2630942 :     double sibLength = s.length2D();
     639      2630942 :     if (!sameSource) {
     640      2638312 :         l = l.reverse();
     641      2638312 :         s = s.reverse();
     642      1311786 :     } else if (sibling->getEntryLink()->myAmIndirect) {
     643              :         // ignore final waiting position since it may be quite close to the lane
     644              :         // shape but the waiting position is perpendicular (so the minDist
     645              :         // requirement is not necessary
     646           94 :         lbcSibling += s[-1].distanceTo2D(s[-2]);
     647              :         s.pop_back();
     648      1311692 :     } else if (lane->getEntryLink()->myAmIndirect) {
     649              :         // ignore final waiting position since it may be quite close to the lane
     650              :         // shape but the waiting position is perpendicular (so the minDist
     651              :         // requirement is not necessary
     652           94 :         lbcLane += l[-1].distanceTo2D(l[-2]);
     653              :         l.pop_back();
     654              :     }
     655              : 
     656              : #ifdef MSLink_DEBUG_CROSSING_POINTS_DETAILS
     657              :     std::cout << "   sameSource=" << sameSource << " lane=" << lane->getID() << " sib=" << sibling->getID() << " minDist=" << minDist << " backDist=" << l.back().distanceTo2D(s.back()) << "\n";
     658              : #endif
     659      2630942 :     if (l.back().distanceTo2D(s.back()) > minDist) {
     660              :         // compute the final divergence point
     661              :         // this position serves two purposes:
     662              :         // 1) once the foe vehicle back (on sibling) has passed this point, we can safely ignore it
     663              :         // 2) both vehicles are put into a cf-relationship while before the point.
     664              :         //    Since the actual crossing point is at the start of the junction,
     665              :         //    we want to make sure that both vehicles have the same distance to the crossing point and thus follow each other naturally
     666      2573152 :         std::vector<double> distances = l.distances(s);
     667              : #ifdef MSLink_DEBUG_CROSSING_POINTS
     668              :         std::cout << "   distances=" << toString(distances) << "\n";
     669              : #endif
     670              :         assert(distances.size() == l.size() + s.size());
     671      2573152 :         if (distances.back() > minDist && distances[l.size() - 1] > minDist) {
     672              :             // do a pairwise check between lane and sibling to make because we do not know which of them bends more
     673      2446529 :             for (int j = (int)s.size() - 2; j >= 0; j--) {
     674      2446529 :                 const int i = j + (int)l.size();
     675      2446529 :                 const double segLength = s[j].distanceTo2D(s[j + 1]);
     676      2446529 :                 if (distances[i] > minDist) {
     677       948361 :                     lbcSibling += segLength;
     678              :                 } else {
     679              :                     // assume no sharp bends and just interpolate the last segment
     680      1498168 :                     lbcSibling += segLength - (minDist - distances[i]) * segLength / (distances[i + 1] - distances[i]);
     681      1498168 :                     break;
     682              :                 }
     683              :             }
     684      2447097 :             for (int i = (int)l.size() - 2; i >= 0; i--) {
     685      2447097 :                 const double segLength = l[i].distanceTo2D(l[i + 1]);
     686      2447097 :                 if (distances[i] > minDist) {
     687       948929 :                     lbcLane += segLength;
     688              :                 } else {
     689              :                     // assume no sharp bends and just interpolate the last segment
     690      1498168 :                     lbcLane += segLength - (minDist - distances[i]) * segLength / (distances[i + 1] - distances[i]);
     691      1498168 :                     break;
     692              :                 }
     693              :             }
     694              :         }
     695              :         assert(lbcSibling >= -NUMERICAL_EPS);
     696              :         assert(lbcLane >= -NUMERICAL_EPS);
     697      2573152 :     }
     698      2630942 :     const double distToDivergence1 = sibling->getLength() + siblingPredLength - lbcSibling;
     699      2630942 :     const double distToDivergence2 = lane->getLength() - lbcLane;
     700              :     const double distToDivergence = MIN3(
     701              :                                         MAX2(distToDivergence1, distToDivergence2),
     702              :                                         sibLength, length);
     703              : #ifdef MSLink_DEBUG_CROSSING_POINTS
     704              :     std::cout << "   distToDivergence=" << distToDivergence
     705              :               << " distTD1=" << distToDivergence1
     706              :               << " distTD2=" << distToDivergence2
     707              :               << " length=" << length
     708              :               << " sibLength=" << sibLength
     709              :               << "\n";
     710              : #endif
     711      2630942 :     return distToDivergence;
     712      2630942 : }
     713              : 
     714              : 
     715              : bool
     716      1450624 : MSLink::contIntersect(const MSLane* lane, const MSLane* foe) {
     717      1450624 :     if (foe->getLinkCont()[0]->getViaLane() != nullptr) {
     718       131782 :         std::vector<double> intersections = lane->getShape().intersectsAtLengths2D(foe->getShape());
     719       131782 :         return intersections.size() > 0;
     720       131782 :     }
     721              :     return false;
     722              : }
     723              : 
     724              : 
     725              : void
     726    897979161 : MSLink::setApproaching(const SUMOVehicle* approaching, const SUMOTime arrivalTime, const double arrivalSpeed, const double leaveSpeed,
     727              :                        const bool setRequest, const double arrivalSpeedBraking, const SUMOTime waitingTime, double dist, double latOffset) {
     728    897979161 :     const SUMOTime leaveTime = getLeaveTime(arrivalTime, arrivalSpeed, leaveSpeed, approaching->getVehicleType().getLength());
     729              : #ifdef DEBUG_APPROACHING
     730              :     if (DEBUG_COND2(approaching)) {
     731              :         std::cout << SIMTIME << " link=" << getDescription() << " setApproaching veh=" << approaching->getID();
     732              :         if (myApproachingVehicles.size() > 0) {
     733              :             std::cout << " curApproaching=";
     734              :             for (auto i = myApproachingVehicles.begin(); i != myApproachingVehicles.end(); ++i) {
     735              :                 std::cout << i->first->getID() << " ";
     736              :             }
     737              :         }
     738              :         std::cout << "\n";
     739              :     }
     740              : #endif
     741    897979161 :     if (MSGlobals::gUseMesoSim) {
     742              :         // - in meso, setApproaching may be called multiple times without intermediate removeApproaching (whenever a vehicle is blocked in MELoop::checkCar)
     743              :         // explicit erasure is necessary because emplace does nothing if the key already exists
     744              :         // - in micro, double registration only happens on looped routes. Here, we only wish to keep the first arrival and thus emplace has the correct behavior
     745              :         //   (on meso, only the next upcoming link is registered so nothing gets overwritten on looped routes)
     746              :         myApproachingVehicles.erase(approaching);
     747              :     }
     748    897979161 :     myApproachingVehicles.emplace(approaching,
     749   1795958322 :                                   ApproachingVehicleInformation(arrivalTime, leaveTime, arrivalSpeed, leaveSpeed, setRequest,
     750    897979161 :                                           arrivalSpeedBraking, waitingTime, dist, approaching->getSpeed(), latOffset));
     751    897979161 : }
     752              : 
     753              : 
     754              : void
     755      1121904 : MSLink::setApproaching(const SUMOVehicle* approaching, ApproachingVehicleInformation ai) {
     756              : #ifdef DEBUG_APPROACHING
     757              :     if (DEBUG_COND2(approaching)) {
     758              :         std::cout << SIMTIME << " link=" << getDescription() << " setApproaching veh=" << approaching->getID();
     759              :         if (myApproachingVehicles.size() > 0) {
     760              :             std::cout << " curApproaching=";
     761              :             for (auto i = myApproachingVehicles.begin(); i != myApproachingVehicles.end(); ++i) {
     762              :                 std::cout << i->first->getID() << " ";
     763              :             }
     764              :         }
     765              :         std::cout << "\n";
     766              :     }
     767              : #endif
     768      1121904 :     myApproachingVehicles.emplace(approaching, ai);
     769      1121904 : }
     770              : 
     771              : void
     772       487667 : MSLink::setApproachingPerson(const MSPerson* approaching, const SUMOTime arrivalTime, const SUMOTime leaveTime) {
     773       487667 :     if (myApproachingPersons == nullptr) {
     774         1331 :         myApproachingPersons = new PersonApproachInfos();
     775              :     }
     776       487667 :     myApproachingPersons->emplace(approaching, ApproachingPersonInformation(arrivalTime, leaveTime));
     777       487667 : }
     778              : 
     779              : void
     780    886909747 : MSLink::removeApproaching(const SUMOVehicle* veh) {
     781              : #ifdef DEBUG_APPROACHING
     782              :     if (DEBUG_COND2(veh)) {
     783              :         std::cout << SIMTIME << " link=" << getDescription() << " removeApproaching veh=" << veh->getID();
     784              :         if (myApproachingVehicles.size() > 0) {
     785              :             std::cout << " curApproaching=";
     786              :             for (auto i = myApproachingVehicles.begin(); i != myApproachingVehicles.end(); ++i) {
     787              :                 std::cout << i->first->getID() << " ";
     788              :             }
     789              :         }
     790              :         std::cout << "\n";
     791              :     }
     792              : #endif
     793              :     myApproachingVehicles.erase(veh);
     794    886909747 : }
     795              : 
     796              : 
     797              : void
     798        31239 : MSLink::removeApproachingPerson(const MSPerson* person) {
     799        31239 :     if (myApproachingPersons == nullptr) {
     800           12 :         WRITE_WARNINGF("Person '%' entered crossing lane '%' without registering approach, time=%", person->getID(), myLane->getID(), time2string(SIMSTEP));
     801            3 :         return;
     802              :     }
     803              : #ifdef DEBUG_APPROACHING
     804              :     if (DEBUG_COND2(person)) {
     805              :         std::cout << SIMTIME << " Link '" << (myLaneBefore == 0 ? "NULL" : myLaneBefore->getID()) << "'->'" << (myLane == 0 ? "NULL" : myLane->getID()) << std::endl;
     806              :         std::cout << "' Removing approaching person '" << person->getID() << "'\nCurrently registered persons:" << std::endl;
     807              :         for (auto i = myApproachingPersons->begin(); i != myApproachingPersons->end(); ++i) {
     808              :             std::cout << "'" << i->first->getID() << "'" << std::endl;
     809              :         }
     810              :     }
     811              : #endif
     812              :     myApproachingPersons->erase(person);
     813              : }
     814              : 
     815              : 
     816              : MSLink::ApproachingVehicleInformation
     817     30884543 : MSLink::getApproaching(const SUMOVehicle* veh) const {
     818              :     auto i = myApproachingVehicles.find(veh);
     819     30884543 :     if (i != myApproachingVehicles.end()) {
     820     27389453 :         return i->second;
     821              :     } else {
     822              :         return ApproachingVehicleInformation(INVALID_TIME, INVALID_TIME, 0, 0, false, 0, 0, 0, 0, 0);
     823              :     }
     824              : }
     825              : 
     826              : 
     827              : const MSLink::ApproachingVehicleInformation*
     828      2882530 : MSLink::getApproachingPtr(const SUMOVehicle* veh) const {
     829              :     auto i = myApproachingVehicles.find(veh);
     830      2882530 :     if (i != myApproachingVehicles.end()) {
     831      2520293 :         return &i->second;
     832              :     } else {
     833              :         return nullptr;
     834              :     }
     835              : }
     836              : 
     837              : 
     838              : void
     839        11184 : MSLink::clearState() {
     840              :     myApproachingVehicles.clear();
     841        11184 : }
     842              : 
     843              : 
     844              : SUMOTime
     845   1576652684 : MSLink::getLeaveTime(const SUMOTime arrivalTime, const double arrivalSpeed,
     846              :                      const double leaveSpeed, const double vehicleLength) const {
     847   1610437431 :     return arrivalTime == SUMOTime_MAX ? SUMOTime_MAX : arrivalTime + TIME2STEPS((getLength() + vehicleLength) / MAX2(0.5 * (arrivalSpeed + leaveSpeed), NUMERICAL_EPS));
     848              : }
     849              : 
     850              : 
     851              : bool
     852    693662205 : MSLink::opened(SUMOTime arrivalTime, double arrivalSpeed, double leaveSpeed, double vehicleLength,
     853              :                double impatience, double decel, SUMOTime waitingTime, double posLat,
     854              :                BlockingFoes* collectFoes, bool ignoreRed, const SUMOTrafficObject* ego, double dist) const {
     855              : #ifdef MSLink_DEBUG_OPENED
     856              :     if (gDebugFlag1) {
     857              :         std::cout << SIMTIME << "  opened? link=" << getDescription() << " red=" << haveRed() << " cont=" << isCont() << " numFoeLinks=" << myFoeLinks.size() << " havePrio=" << havePriority() << " lastWasContMajorGreen=" << lastWasContState(LINKSTATE_TL_GREEN_MAJOR) << "\n";
     858              :     }
     859              : #endif
     860    693662205 :     if (haveRed() && !ignoreRed) {
     861              :         return false;
     862              :     }
     863    682735194 :     if (isCont() && MSGlobals::gUsingInternalLanes) {
     864              :         return true;
     865              :     }
     866    678236469 :     const SUMOTime leaveTime = getLeaveTime(arrivalTime, arrivalSpeed, leaveSpeed, vehicleLength);
     867    678236469 :     if (MSGlobals::gLateralResolution > 0) {
     868              :         // check for foes on the same lane with the same target edge
     869    139704701 :         for (const MSLink* foeLink : mySublaneFoeLinks) {
     870              :             assert(myLane != foeLink->getLane());
     871     10080349 :             for (const auto& it : foeLink->myApproachingVehicles) {
     872      6867932 :                 const SUMOVehicle* foe = it.first;
     873              :                 if (
     874              :                     // there only is a conflict if the paths cross
     875      7474406 :                     ((posLat < foe->getLateralPositionOnLane() + it.second.latOffset && myLane->getIndex() > foeLink->myLane->getIndex())
     876      6620219 :                      || (posLat > foe->getLateralPositionOnLane() + it.second.latOffset && myLane->getIndex() < foeLink->myLane->getIndex()))
     877              :                     // the vehicle that arrives later must yield
     878      7458026 :                     && (arrivalTime > it.second.arrivalTime
     879              :                         // if both vehicles arrive at the same time, the one
     880              :                         // to the left must yield
     881       384324 :                         || (arrivalTime == it.second.arrivalTime && posLat > foe->getLateralPositionOnLane()))) {
     882       206527 :                     if (blockedByFoe(foe, it.second, arrivalTime, leaveTime, arrivalSpeed, leaveSpeed, false,
     883              :                                      impatience, decel, waitingTime, ego)) {
     884              : #ifdef MSLink_DEBUG_OPENED
     885              :                         if (gDebugFlag1) {
     886              :                             std::cout << SIMTIME << " blocked by " << foe->getID() << " arrival=" << arrivalTime << " foeArrival=" << it.second.arrivalTime << "\n";
     887              :                         }
     888              : #endif
     889        41338 :                         if (collectFoes == nullptr) {
     890              : #ifdef MSLink_DEBUG_OPENED
     891              :                             if (gDebugFlag1) {
     892              :                                 std::cout << " link=" << getViaLaneOrLane()->getID() << " blocked by sublaneFoe=" << foe->getID() << " foeLink=" << foeLink->getViaLaneOrLane()->getID() << " posLat=" << posLat << "\n";
     893              :                             }
     894              : #endif
     895              :                             return false;
     896              :                         } else {
     897            0 :                             collectFoes->push_back(it.first);
     898              :                         }
     899              :                     }
     900              :                 }
     901              :             }
     902              :         }
     903              :         // check for foes on the same lane with a different target edge
     904              :         // (straight movers take precedence if the paths cross)
     905    136450946 :         const int lhSign = MSGlobals::gLefthand ? -1 : 1;
     906    137797147 :         for (const MSLink* foeLink : mySublaneFoeLinks2) {
     907              :             assert(myDirection != LinkDirection::STRAIGHT);
     908      5711093 :             for (const auto& it : foeLink->myApproachingVehicles) {
     909      4364892 :                 const SUMOVehicle* foe = it.first;
     910              :                 // there only is a conflict if the paths cross
     911              :                 // and if the vehicles are not currently in a car-following relationship
     912      4364892 :                 const double egoWidth = ego == nullptr ? 1.8 : ego->getVehicleType().getWidth();
     913      4364892 :                 if (!lateralOverlap(posLat, egoWidth, foe->getLateralPositionOnLane() + it.second.latOffset, foe->getVehicleType().getWidth())
     914      4364892 :                         && (((myDirection == LinkDirection::RIGHT || myDirection == LinkDirection::PARTRIGHT)
     915       488504 :                              && (posLat * lhSign > (foe->getLateralPositionOnLane() + it.second.latOffset) * lhSign))
     916       435155 :                             || ((myDirection == LinkDirection::LEFT || myDirection == LinkDirection::PARTLEFT)
     917        32104 :                                 && (posLat * lhSign < (foe->getLateralPositionOnLane() + it.second.latOffset) * lhSign)))) {
     918        86912 :                     if (blockedByFoe(foe, it.second, arrivalTime, leaveTime, arrivalSpeed, leaveSpeed, false,
     919              :                                      impatience, decel, waitingTime, ego)) {
     920              : #ifdef MSLink_DEBUG_OPENED
     921              :                         if (gDebugFlag1) {
     922              :                             std::cout << SIMTIME << " blocked by sublane foe " << foe->getID() << " arrival=" << arrivalTime << " foeArrival=" << it.second.arrivalTime << "\n";
     923              :                         }
     924              : #endif
     925         9782 :                         if (collectFoes == nullptr) {
     926              : #ifdef MSLink_DEBUG_OPENED
     927              :                             if (gDebugFlag1) {
     928              :                                 std::cout << " link=" << getViaLaneOrLane()->getID() << " blocked by sublaneFoe2=" << foe->getID() << " foeLink=" << foeLink->getViaLaneOrLane()->getID() << " posLat=" << posLat << "\n";
     929              :                             }
     930              : #endif
     931              :                             return false;
     932              :                         } else {
     933            0 :                             collectFoes->push_back(it.first);
     934              :                         }
     935              :                     }
     936              :                 }
     937              :             }
     938              :         }
     939              :     }
     940              : #ifdef MSLink_DEBUG_OPENED
     941              :     /*
     942              :     if (gDebugFlag1) {
     943              :         std::cout << SIMTIME << " isExitLinkAfterInternalJunction=" << isExitLinkAfterInternalJunction()
     944              :             << " entryLink=" << getCorrespondingEntryLink()->getDescription()
     945              :             << " entryState=" << getCorrespondingEntryLink()->getState()
     946              :             << "\n";
     947              :     }
     948              :     */
     949              : #endif
     950              :     if ((havePriority()
     951     29924192 :             || lastWasContState(LINKSTATE_TL_GREEN_MAJOR)
     952     29487800 :             || (isExitLinkAfterInternalJunction() && getCorrespondingEntryLink()->getState() == LINKSTATE_TL_GREEN_MAJOR))
     953    678692929 :             && myState != LINKSTATE_ZIPPER) {
     954              :         // priority usually means the link is open but there are exceptions:
     955              :         // zipper still needs to collect foes
     956              :         // sublane model could have detected a conflict
     957    647056255 :         return collectFoes == nullptr || collectFoes->size() == 0;
     958              :     }
     959     31129094 :     if (myState == LINKSTATE_ALLWAY_STOP && waitingTime < TIME2STEPS(ego == nullptr ? TS : ego->getVehicleType().getParameter().getJMParam(SUMO_ATTR_JM_ALLWAYSTOP_WAIT, TS))) {
     960              :         return false;
     961     30151897 :     } else if (myState == LINKSTATE_STOP && waitingTime < TIME2STEPS(ego == nullptr ? TS : ego->getVehicleType().getParameter().getJMParam(SUMO_ATTR_JM_STOPSIGN_WAIT, TS))) {
     962              :         return false;
     963              :     }
     964              : 
     965     30087944 :     const std::vector<MSLink*>& foeLinks = (myOffFoeLinks == nullptr || getCorrespondingEntryLink()->getState() != LINKSTATE_ALLWAY_STOP) ? myFoeLinks : *myOffFoeLinks;
     966              : 
     967     30087944 :     if (MSGlobals::gUseMesoSim && impatience == 1 && !myLane->getEdge().isRoundabout()) {
     968              :         return true;
     969              :     }
     970     30087456 :     if (myLane->getBidiLane() != nullptr) {
     971       119521 :         MSLane* bidi = myLane->getBidiLane();
     972       119521 :         if (bidi->getVehicleNumber() > 0) {
     973         9531 :             if (ego == nullptr) {
     974              :                 return false;
     975              :             }
     976              :             double maxOncomingWidth = 0;
     977         9531 :             const MSLane::VehCont& vehs = bidi->getVehiclesSecure();
     978        46564 :             for (MSVehicle* foe : vehs) {
     979        37033 :                 maxOncomingWidth = MAX2(maxOncomingWidth, foe->getVehicleType().getWidth());
     980              :             }
     981         9531 :             bidi->releaseVehicles();
     982         9531 :             if (MSGlobals::gLateralResolution > 0) {
     983         6343 :                 if (ego->getVehicleType().getWidth() + maxOncomingWidth + MSGlobals::gLateralResolution < myLane->getWidth()) {
     984              :                     return false;
     985              :                 }
     986         3188 :             } else if (maxOncomingWidth > 0) {
     987              :                 // do not enter a lane that has any oncoming vehicles
     988              :                 return false;
     989              :             }
     990              :         }
     991       250031 :         for (auto ili : bidi->getIncomingLanes()) {
     992       134287 :             if (ili.lane->getEdge().getPriority() > myLaneBefore->getEdge().getPriority()
     993       134287 :                     || (ili.lane->getEdge().getPriority() == myLaneBefore->getEdge().getPriority()
     994       103290 :                         && ili.lane->getID() > myLaneBefore->getID())) {
     995              :                 BlockingFoes bidiApproachFoes;
     996              :                 double maxOncomingWidth = 0;
     997        18235 :                 if (ili.viaLink->blockedAtTime(arrivalTime, leaveTime, arrivalSpeed, leaveSpeed, false, 0, decel, 0,
     998        36470 :                             MSGlobals::gLateralResolution ? &bidiApproachFoes : nullptr, ego) || bidiApproachFoes.size() > 0) {
     999          530 :                     if (MSGlobals::gLateralResolution > 0) {
    1000          477 :                         for (const SUMOTrafficObject* foe : bidiApproachFoes) {
    1001          242 :                             maxOncomingWidth = MAX2(maxOncomingWidth, foe->getVehicleType().getWidth());
    1002              :                         }
    1003          235 :                         if (ego->getVehicleType().getWidth() + maxOncomingWidth + MSGlobals::gLateralResolution < myLane->getWidth()) {
    1004              :                             return false;
    1005              :                         }
    1006              :                     } else {
    1007              :                         return false;
    1008              :                     }
    1009              :                 }
    1010        18235 :             }
    1011              :         }
    1012              :     }
    1013     30083679 :     const bool lastWasContRed = lastWasContState(LINKSTATE_TL_RED);
    1014     83754359 :     for (const MSLink* const link : foeLinks) {
    1015     58664435 :         if (MSGlobals::gUseMesoSim) {
    1016      2112765 :             if (link->haveRed()) {
    1017        68120 :                 continue;
    1018              :             }
    1019              :         }
    1020              : #ifdef MSLink_DEBUG_OPENED
    1021              :         if (gDebugFlag1) {
    1022              :             std::cout << SIMTIME << "   foeLink=" << link->getViaLaneOrLane()->getID() << " numApproaching=" << link->getApproaching().size() << "\n";
    1023              :             if (link->getLane()->isCrossing()) {
    1024              :                 std::cout << SIMTIME << "     approachingPersons=" << (link->myApproachingPersons == nullptr ? "NULL" : toString(link->myApproachingPersons->size())) << "\n";
    1025              :             }
    1026              :         }
    1027              : #endif
    1028     58596315 :         if (link->blockedAtTime(arrivalTime, leaveTime, arrivalSpeed, leaveSpeed, myLane == link->getLane(),
    1029              :                                 impatience, decel, waitingTime, collectFoes, ego, lastWasContRed, dist)) {
    1030              :             return false;
    1031              :         }
    1032              :     }
    1033     25089924 :     if (collectFoes != nullptr && collectFoes->size() > 0) {
    1034              :         return false;
    1035              :     }
    1036              :     return true;
    1037              : }
    1038              : 
    1039              : 
    1040              : bool
    1041     58665871 : MSLink::blockedAtTime(SUMOTime arrivalTime, SUMOTime leaveTime, double arrivalSpeed, double leaveSpeed,
    1042              :                       bool sameTargetLane, double impatience, double decel, SUMOTime waitingTime,
    1043              :                       BlockingFoes* collectFoes, const SUMOTrafficObject* ego, bool lastWasContRed, double dist) const {
    1044    220396583 :     for (const auto& it : myApproachingVehicles) {
    1045              : #ifdef MSLink_DEBUG_OPENED
    1046              :         if (gDebugFlag1) {
    1047              :             if (ego != nullptr
    1048              :                     && ego->getVehicleType().getParameter().getJMParam(SUMO_ATTR_JM_IGNORE_FOE_SPEED, 0) >= it.second.speed
    1049              :                     && ego->getVehicleType().getParameter().getJMParam(SUMO_ATTR_JM_IGNORE_FOE_PROB, 0) > 0) {
    1050              :                 std::stringstream stream; // to reduce output interleaving from different threads
    1051              :                 stream << SIMTIME << " " << myApproachingVehicles.size() << "   foe link=" << getViaLaneOrLane()->getID()
    1052              :                        << " foeVeh=" << it.first->getID() << " (below ignore speed)"
    1053              :                        << " ignoreFoeProb=" << ego->getVehicleType().getParameter().getJMParam(SUMO_ATTR_JM_IGNORE_FOE_PROB, 0)
    1054              :                        << "\n";
    1055              :                 std::cout << stream.str();
    1056              :             }
    1057              :         }
    1058              : #endif
    1059    166621815 :         if (it.first != ego
    1060    166612541 :                 && (ego == nullptr
    1061    166564728 :                     || ego->getVehicleType().getParameter().getJMParam(SUMO_ATTR_JM_IGNORE_FOE_PROB, 0) == 0
    1062        23409 :                     || ego->getVehicleType().getParameter().getJMParam(SUMO_ATTR_JM_IGNORE_FOE_SPEED, 0) < it.second.speed
    1063         1757 :                     || ego->getVehicleType().getParameter().getJMParam(SUMO_ATTR_JM_IGNORE_FOE_PROB, 0) < RandHelper::rand(ego->getRNG()))
    1064    166610944 :                 && !ignoreFoe(ego, it.first)
    1065    166610702 :                 && (!lastWasContRed || it.first->getSpeed() > SUMO_const_haltingSpeed)
    1066    333225714 :                 && blockedByFoe(it.first, it.second, arrivalTime, leaveTime, arrivalSpeed, leaveSpeed, sameTargetLane,
    1067              :                                 impatience, decel, waitingTime, ego)) {
    1068     11376122 :             if (collectFoes == nullptr) {
    1069              :                 return true;
    1070              :             } else {
    1071      6485019 :                 collectFoes->push_back(it.first);
    1072              :             }
    1073              :         }
    1074              :     }
    1075     53774768 :     if (myApproachingPersons != nullptr && !haveRed()) {
    1076              :         const SUMOTime lookAhead = (ego == nullptr
    1077       847533 :                                     ? myLookaheadTime
    1078       847358 :                                     : TIME2STEPS(ego->getVehicleType().getParameter().getJMParam(SUMO_ATTR_JM_TIMEGAP_MINOR, STEPS2TIME(myLookaheadTime))));
    1079       922252 :         for (const auto& it : *myApproachingPersons) {
    1080              : #ifdef MSLink_DEBUG_OPENED
    1081              :             if (gDebugFlag1) {
    1082              :                 std::cout << SIMTIME << ": " << ego->getID() << " check person " << it.first->getID() << " aTime=" << arrivalTime << " foeATime=" << it.second.arrivalTime
    1083              :                           << " lTime=" << leaveTime << " foeLTime=" << it.second.leavingTime
    1084              :                           << " dist=" << dist << "\n";
    1085              :             }
    1086              : #endif
    1087              :             if ((ego == nullptr
    1088       204286 :                     || ego->getVehicleType().getParameter().getJMParam(SUMO_ATTR_JM_IGNORE_FOE_PROB, 0) == 0
    1089          600 :                     || ego->getVehicleType().getParameter().getJMParam(SUMO_ATTR_JM_IGNORE_FOE_SPEED, 0) < it.first->getSpeed()
    1090          600 :                     || ego->getVehicleType().getParameter().getJMParam(SUMO_ATTR_JM_IGNORE_FOE_PROB, 0) < RandHelper::rand(ego->getRNG()))
    1091       203917 :                     && !ignoreFoe(ego, it.first)
    1092       408354 :                     && !((arrivalTime > it.second.leavingTime + lookAhead) || (leaveTime + lookAhead < it.second.arrivalTime))) {
    1093       143196 :                 if (ego == nullptr) {
    1094              :                     // during insertion
    1095          174 :                     if (myJunction->getType() == SumoXMLNodeType::RAIL_CROSSING) {
    1096          174 :                         continue;
    1097              :                     } else {
    1098              :                         return true;
    1099              :                     }
    1100              :                 }
    1101              :                 // check whether braking is feasible (ego might have started to accelerate already)
    1102       143022 :                 const auto& cfm = ego->getVehicleType().getCarFollowModel();
    1103              : #ifdef MSLink_DEBUG_OPENED
    1104              :                 if (gDebugFlag1) {
    1105              :                     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";
    1106              :                 }
    1107              : #endif
    1108       143022 :                 if (dist > cfm.brakeGap(ego->getSpeed(), cfm.getMaxDecel(), 0)) {
    1109              : #ifdef MSLink_DEBUG_OPENED
    1110              :                     if (gDebugFlag1) {
    1111              :                         std::cout << SIMTIME << ": " << ego->getID() << " blocked by person " << it.first->getID() << "\n";
    1112              :                     }
    1113              : #endif
    1114       129798 :                     if (collectFoes == nullptr) {
    1115              :                         return true;
    1116              :                     } else {
    1117            0 :                         collectFoes->push_back(it.first);
    1118              :                     }
    1119              :                 }
    1120              :             }
    1121              :         }
    1122              :     }
    1123              :     return false;
    1124              : }
    1125              : 
    1126              : 
    1127              : bool
    1128    166897338 : MSLink::blockedByFoe(const SUMOVehicle* veh, const ApproachingVehicleInformation& avi,
    1129              :                      SUMOTime arrivalTime, SUMOTime leaveTime, double arrivalSpeed, double leaveSpeed,
    1130              :                      bool sameTargetLane, double impatience, double decel, SUMOTime waitingTime,
    1131              :                      const SUMOTrafficObject* ego) const {
    1132              : #ifdef MSLink_DEBUG_OPENED
    1133              :     if (gDebugFlag1) {
    1134              :         std::stringstream stream; // to reduce output interleaving from different threads
    1135              :         stream << "    link=" << getDescription()
    1136              :                << " foeVeh=" << veh->getID()
    1137              :                << " req=" << avi.willPass
    1138              :                << " aT=" << avi.arrivalTime
    1139              :                << " lT=" << avi.leavingTime
    1140              :                << "\n";
    1141              :         std::cout << stream.str();
    1142              :     }
    1143              : #endif
    1144    166897338 :     if (!avi.willPass) {
    1145              :         return false;
    1146              :     }
    1147     60571779 :     if (myState == LINKSTATE_ALLWAY_STOP) {
    1148              :         assert(waitingTime > 0);
    1149              : #ifdef MSLink_DEBUG_OPENED
    1150              :         if (gDebugFlag1) {
    1151              :             std::stringstream stream; // to reduce output interleaving from different threads
    1152              :             stream << "    foeDist=" << avi.dist
    1153              :                    << " foeBGap=" << veh->getBrakeGap(false)
    1154              :                    << " foeWait=" << avi.waitingTime
    1155              :                    << " wait=" << waitingTime
    1156              :                    << "\n";
    1157              :             std::cout << stream.str();
    1158              :         }
    1159              : #endif
    1160              :         // when using actionSteps, the foe waiting time may be outdated
    1161      1563239 :         const SUMOTime actionDelta = SIMSTEP - veh->getLastActionTime();
    1162      1563239 :         if (waitingTime > avi.waitingTime + actionDelta) {
    1163              :             return false;
    1164              :         }
    1165       234065 :         if (waitingTime == (avi.waitingTime + actionDelta) && arrivalTime < avi.arrivalTime + actionDelta) {
    1166              :             return false;
    1167              :         }
    1168              :     }
    1169     59212039 :     SUMOTime foeArrivalTime = avi.arrivalTime;
    1170     59212039 :     double foeArrivalSpeedBraking = avi.arrivalSpeedBraking;
    1171     59212039 :     if (impatience > 0 && arrivalTime < avi.arrivalTime) {
    1172              : #ifdef MSLink_DEBUG_OPENED
    1173              :         gDebugFlag6 = ((ego == nullptr || ego->isSelected()) && (veh == nullptr || veh->isSelected()));
    1174              : #endif
    1175      2823307 :         const SUMOTime fatb = computeFoeArrivalTimeBraking(arrivalTime, veh, avi.arrivalTime, impatience, avi.dist, foeArrivalSpeedBraking);
    1176      2823307 :         foeArrivalTime = (SUMOTime)((1. - impatience) * (double)avi.arrivalTime + impatience * (double)fatb);
    1177              : #ifdef MSLink_DEBUG_OPENED
    1178              :         if (gDebugFlag6) {
    1179              :             std::cout << SIMTIME << " link=" << getDescription() << " ego=" << ego->getID() << " foe=" << veh->getID()
    1180              :                       << " at=" << STEPS2TIME(arrivalTime)
    1181              :                       << " fat=" << STEPS2TIME(avi.arrivalTime)
    1182              :                       << " fatb=" << STEPS2TIME(fatb)
    1183              :                       << " fat2=" << STEPS2TIME(foeArrivalTime)
    1184              :                       << "\n";
    1185              :         }
    1186              : #endif
    1187              :     }
    1188              : 
    1189              : 
    1190     59212039 :     const SUMOTime lookAhead = (myState == LINKSTATE_ZIPPER
    1191     59212039 :                                 ? myLookaheadTimeZipper
    1192              :                                 : (ego == nullptr
    1193     47510532 :                                    ? myLookaheadTime
    1194     47505161 :                                    : TIME2STEPS(ego->getVehicleType().getParameter().getJMParam(SUMO_ATTR_JM_TIMEGAP_MINOR, STEPS2TIME(myLookaheadTime)))));
    1195              :     //if (ego != 0) std::cout << SIMTIME << " ego=" << ego->getID() << " jmTimegapMinor=" << ego->getVehicleType().getParameter().getJMParam(SUMO_ATTR_JM_TIMEGAP_MINOR, -1) << " lookAhead=" << lookAhead << "\n";
    1196              : #ifdef MSLink_DEBUG_OPENED
    1197              :     if (gDebugFlag1 || gDebugFlag6) {
    1198              :         std::stringstream stream; // to reduce output interleaving from different threads
    1199              :         stream << "       imp=" << impatience << " fAT2=" << foeArrivalTime << " fASb=" << foeArrivalSpeedBraking << " lA=" << lookAhead << " egoAT=" << arrivalTime << " egoLT=" << leaveTime << " egoLS=" << leaveSpeed << "\n";
    1200              :         std::cout << stream.str();
    1201              :     }
    1202              : #endif
    1203     59212039 :     if (avi.leavingTime < arrivalTime) {
    1204              :         // ego wants to be follower
    1205     43308111 :         if (sameTargetLane && (arrivalTime - avi.leavingTime < lookAhead
    1206     18936920 :                                || unsafeMergeSpeeds(avi.leaveSpeed, arrivalSpeed,
    1207     18936920 :                                        veh->getVehicleType().getCarFollowModel().getMaxDecel(), decel))) {
    1208              : #ifdef MSLink_DEBUG_OPENED
    1209              :             if (gDebugFlag1 || gDebugFlag6) {
    1210              :                 std::cout << "      blocked (cannot follow)\n";
    1211              :             }
    1212              : #endif
    1213      4177556 :             return true;
    1214              :         }
    1215     15903928 :     } else if (foeArrivalTime > leaveTime + lookAhead) {
    1216              :         // ego wants to be leader.
    1217     14618088 :         if (sameTargetLane && unsafeMergeSpeeds(leaveSpeed, foeArrivalSpeedBraking,
    1218      5804463 :                                                 decel, veh->getVehicleType().getCarFollowModel().getMaxDecel())) {
    1219              : #ifdef MSLink_DEBUG_OPENED
    1220              :             if (gDebugFlag1 || gDebugFlag6) {
    1221              :                 std::cout << "      blocked (cannot lead)\n";
    1222              :             }
    1223              : #endif
    1224              :             return true;
    1225              :         }
    1226              :     } else {
    1227              :         // even without considering safeHeadwayTime there is already a conflict
    1228              : #ifdef MSLink_DEBUG_OPENED
    1229              :         if (gDebugFlag1 || gDebugFlag6) {
    1230              :             std::cout << "      blocked (hard conflict)\n";
    1231              :         }
    1232              : #endif
    1233              :         return true;
    1234              :     }
    1235              :     return false;
    1236              : }
    1237              : 
    1238              : 
    1239              : SUMOTime
    1240      2823307 : MSLink::computeFoeArrivalTimeBraking(SUMOTime arrivalTime, const SUMOVehicle* foe, SUMOTime foeArrivalTime, double impatience, double dist, double& fasb) {
    1241              :     // a: distance saved when foe brakes from arrivalTime to foeArrivalTime
    1242              :     // b: distance driven past foeArrivalTime
    1243              :     // m: permitted decceleration
    1244              :     // d: total deceleration until foeArrivalTime
    1245              :     // dist2: distance of foe at arrivalTime
    1246              :     // actual arrivalTime must fall on a simulation step
    1247      2823307 :     if (arrivalTime - arrivalTime % DELTA_T == foeArrivalTime - foeArrivalTime % DELTA_T) {
    1248              :         // foe enters the junction in the same step
    1249              : #ifdef MSLink_DEBUG_OPENED
    1250              :         if (gDebugFlag6) {
    1251              :             std::cout << "   foeAT before egoAT\n";
    1252              :         }
    1253              : #endif
    1254              :         return foeArrivalTime;
    1255              :     }
    1256      2466060 :     if (arrivalTime % DELTA_T > 0) {
    1257      2436664 :         arrivalTime = arrivalTime - (arrivalTime % DELTA_T) + DELTA_T;
    1258              :     }
    1259              :     //arrivalTime += DELTA_T - arrivalTime % DELTA_T;
    1260      2466060 :     const double m = foe->getVehicleType().getCarFollowModel().getMaxDecel() * impatience;
    1261      2466060 :     const double dt = STEPS2TIME(foeArrivalTime - arrivalTime);
    1262      2466060 :     const double d = dt * m;
    1263      2466060 :     const double a = dt * d / 2;
    1264      2466060 :     const double v = dist / STEPS2TIME(foeArrivalTime - SIMSTEP + DELTA_T);
    1265      2466060 :     const double dist2 = dist - v * STEPS2TIME(arrivalTime - SIMSTEP);
    1266              : #ifdef MSLink_DEBUG_OPENED
    1267              :     if (gDebugFlag6) {
    1268              :         std::cout << "   dist=" << dist << " dist2=" << dist2
    1269              :                   << " at=" << STEPS2TIME(arrivalTime)
    1270              :                   << " fat=" << STEPS2TIME(foeArrivalTime)
    1271              :                   << " dt=" << dt << " v=" << v << " m=" << m << " d=" << d << " a=" << a << "\n";
    1272              :     }
    1273              : #endif
    1274      2466060 :     if (0.5 * v * v / m <= dist2) {
    1275              : #ifdef MSLink_DEBUG_OPENED
    1276              :         if (gDebugFlag6) {
    1277              :             std::cout << "   canBrakeToStop\n";
    1278              :         }
    1279              : #endif
    1280      1227365 :         fasb = 0;
    1281      1227365 :         return foeArrivalTime + TIME2STEPS(30);
    1282              :     }
    1283              :     // a = b (foe reaches the original distance to the stop line)
    1284              :     // x: time driven past foeArrivalTime
    1285              :     // v: foe speed without braking
    1286              :     // v2: average foe speed after foeArrivalTime (braking continues for time x)
    1287              :     // v2 = (v - d - x * m / 2)
    1288              :     // b = v2 * x
    1289              :     // solving for x gives:
    1290      1238695 :     const double x = (sqrt(4 * (v - d) * (v - d) - 8 * m * a) * -0.5 - d + v) / m;
    1291              : 
    1292              : #ifdef MSLink_DEBUG_OPENED
    1293              :     const double x2 = (sqrt(4 * (v - d) * (v - d) - 8 * m * a) * 0.5 - d + v) / m;
    1294              :     if (gDebugFlag6 || std::isnan(x)) {
    1295              :         std::cout << SIMTIME << "   dist=" << dist << " dist2=" << dist2  << " at=" << STEPS2TIME(arrivalTime) << " m=" << m << " d=" << d << " v=" << v << " a=" << a << " x=" << x << " x2=" << x2 << "\n";
    1296              :     }
    1297              : #endif
    1298      1238695 :     fasb = v - (dt + x) * m;
    1299      1238695 :     return foeArrivalTime + TIME2STEPS(x);
    1300              : }
    1301              : 
    1302              : 
    1303              : bool
    1304       437202 : MSLink::hasApproachingFoe(SUMOTime arrivalTime, SUMOTime leaveTime, double speed, double decel) const {
    1305       461377 :     for (const MSLink* const link : myFoeLinks) {
    1306        51321 :         if (link->blockedAtTime(arrivalTime, leaveTime, speed, speed, myLane == link->getLane(), 0, decel, 0)) {
    1307              :             return true;
    1308              :         }
    1309              :     }
    1310       504591 :     for (const MSLane* const lane : myFoeLanes) {
    1311       100963 :         if (lane->getVehicleNumberWithPartials() > 0) {
    1312              :             return true;
    1313              :         }
    1314              :     }
    1315              :     return false;
    1316              : }
    1317              : 
    1318              : 
    1319              : std::pair<const SUMOVehicle*, const MSLink*>
    1320         5817 : MSLink::getFirstApproachingFoe(const MSLink* wrapAround) const {
    1321              :     double closetDist = std::numeric_limits<double>::max();
    1322              :     const SUMOVehicle* closest = nullptr;
    1323              :     const MSLink* foeLink = nullptr;
    1324        18834 :     for (MSLink* link : myFoeLinks) {
    1325        20374 :         for (const auto& it : link->myApproachingVehicles) {
    1326              :             //std::cout << " link=" << getDescription() << " foeLink_in=" << link->getLaneBefore()->getID() << " wrapAround=" << wrapAround->getDescription() << "\n";
    1327         7357 :             if (link->getLaneBefore() == wrapAround->getLaneBefore()) {
    1328          520 :                 return std::make_pair(nullptr, wrapAround);
    1329         6837 :             } else if (it.second.dist < closetDist) {
    1330              :                 closetDist = it.second.dist;
    1331         3604 :                 if (it.second.willPass) {
    1332         3322 :                     closest = it.first;
    1333              :                     foeLink = link;
    1334              :                 }
    1335              :             }
    1336              :         }
    1337              :     }
    1338              :     return std::make_pair(closest, foeLink);
    1339              : }
    1340              : 
    1341              : 
    1342              : void
    1343     79852333 : MSLink::setTLState(LinkState state, SUMOTime t) {
    1344     79852333 :     if (myState != state) {
    1345     17730025 :         myLastStateChange = t;
    1346              :     }
    1347     79852333 :     myState = state;
    1348     79852333 :     if (haveGreen()) {
    1349     12637645 :         myLastGreenState = myState;
    1350              :     }
    1351     79852333 : }
    1352              : 
    1353              : 
    1354              : void
    1355       181243 : MSLink::setTLLogic(const MSTrafficLightLogic* logic) {
    1356       181243 :     myLogic = logic;
    1357       181243 : }
    1358              : 
    1359              : 
    1360              : bool
    1361   1300924468 : MSLink::isCont() const {
    1362              :     // when a traffic light is switched off minor roads have their cont status revoked
    1363   1300924468 :     return (myState == LINKSTATE_TL_OFF_BLINKING || myState == LINKSTATE_ALLWAY_STOP || myState == LINKSTATE_STOP) ? myAmContOff : myAmCont;
    1364              : }
    1365              : 
    1366              : 
    1367              : bool
    1368     65905093 : MSLink::lastWasContMajor() const {
    1369     66587088 :     if (isExitLinkAfterInternalJunction()) {
    1370       681995 :         return myInternalLaneBefore->getIncomingLanes()[0].viaLink->lastWasContMajor();
    1371              :     }
    1372     65905093 :     if (myInternalLane == nullptr || myAmCont) {
    1373              :         return false;
    1374              :     } else {
    1375     48379378 :         MSLane* pred = myInternalLane->getLogicalPredecessorLane();
    1376     48379378 :         if (!pred->getEdge().isInternal()) {
    1377              :             return false;
    1378              :         } else {
    1379     11634634 :             const MSLane* const pred2 = pred->getLogicalPredecessorLane();
    1380              :             assert(pred2 != nullptr);
    1381     11634634 :             const MSLink* const predLink = pred2->getLinkTo(pred);
    1382              :             assert(predLink != nullptr);
    1383     11634634 :             if (predLink->havePriority()) {
    1384              :                 return true;
    1385              :             }
    1386     10965029 :             if (myHavePedestrianCrossingFoe) {
    1387      1444475 :                 return predLink->getLastGreenState() == LINKSTATE_TL_GREEN_MAJOR;
    1388              :             } else {
    1389      9520554 :                 return predLink->haveYellow();
    1390              :             }
    1391              :         }
    1392              :     }
    1393              : }
    1394              : 
    1395              : 
    1396              : bool
    1397     60007871 : MSLink::lastWasContState(LinkState linkState) const {
    1398     60007871 :     if (myInternalLane == nullptr || myAmCont || myHavePedestrianCrossingFoe) {
    1399              :         return false;
    1400              :     } else {
    1401     52673155 :         MSLane* pred = myInternalLane->getLogicalPredecessorLane();
    1402     52673155 :         if (!pred->getEdge().isInternal()) {
    1403              :             return false;
    1404              :         } else {
    1405     15498344 :             const MSLane* const pred2 = pred->getLogicalPredecessorLane();
    1406              :             assert(pred2 != nullptr);
    1407     15498344 :             const MSLink* const predLink = pred2->getLinkTo(pred);
    1408              :             assert(predLink != nullptr);
    1409     15498344 :             return predLink->getState() == linkState;
    1410              :         }
    1411              :     }
    1412              : }
    1413              : 
    1414              : 
    1415              : void
    1416       113904 : MSLink::writeApproaching(OutputDevice& od, const std::string fromLaneID) const {
    1417       113904 :     if (myApproachingVehicles.size() > 0) {
    1418         9765 :         od.openTag("link");
    1419         9765 :         od.writeAttr(SUMO_ATTR_FROM, fromLaneID);
    1420         9765 :         const std::string via = getViaLane() == nullptr ? "" : getViaLane()->getID();
    1421         9765 :         od.writeAttr(SUMO_ATTR_VIA, via);
    1422        19530 :         od.writeAttr(SUMO_ATTR_TO, getLane() == nullptr ? "" : getLane()->getID());
    1423              :         std::vector<std::pair<SUMOTime, const SUMOVehicle*> > toSort; // stabilize output
    1424        21325 :         for (auto it : myApproachingVehicles) {
    1425        11560 :             toSort.push_back(std::make_pair(it.second.arrivalTime, it.first));
    1426              :         }
    1427         9765 :         std::sort(toSort.begin(), toSort.end());
    1428        21325 :         for (std::vector<std::pair<SUMOTime, const SUMOVehicle*> >::const_iterator it = toSort.begin(); it != toSort.end(); ++it) {
    1429        11560 :             od.openTag("approaching");
    1430        11560 :             const ApproachingVehicleInformation& avi = myApproachingVehicles.find(it->second)->second;
    1431        11560 :             od.writeAttr(SUMO_ATTR_ID, it->second->getID());
    1432        11560 :             od.writeAttr(SUMO_ATTR_IMPATIENCE, it->second->getImpatience());
    1433        11560 :             od.writeAttr("arrivalTime", time2string(avi.arrivalTime));
    1434        11560 :             od.writeAttr("leaveTime", time2string(avi.leavingTime));
    1435        11560 :             od.writeAttr("arrivalSpeed", toString(avi.arrivalSpeed));
    1436        11560 :             od.writeAttr("arrivalSpeedBraking", toString(avi.arrivalSpeedBraking));
    1437        11560 :             od.writeAttr("leaveSpeed", toString(avi.leaveSpeed));
    1438        11560 :             od.writeAttr("willPass", toString(avi.willPass));
    1439        23120 :             od.closeTag();
    1440              :         }
    1441         9765 :         od.closeTag();
    1442         9765 :     }
    1443       113904 : }
    1444              : 
    1445              : 
    1446              : double
    1447       921483 : MSLink::getInternalLengthsAfter() const {
    1448              :     double len = 0.;
    1449       921483 :     MSLane* lane = myInternalLane;
    1450              : 
    1451      1759209 :     while (lane != nullptr && lane->isInternal()) {
    1452       837726 :         len += lane->getLength();
    1453       837726 :         lane = lane->getLinkCont()[0]->getViaLane();
    1454              :     }
    1455       921483 :     return len;
    1456              : }
    1457              : 
    1458              : double
    1459            0 : MSLink::getInternalLengthsBefore() const {
    1460              :     double len = 0.;
    1461            0 :     const MSLane* lane = myInternalLane;
    1462              : 
    1463            0 :     while (lane != nullptr && lane->isInternal()) {
    1464            0 :         len += lane->getLength();
    1465            0 :         if (lane->getIncomingLanes().size() == 1) {
    1466            0 :             lane = lane->getIncomingLanes()[0].lane;
    1467              :         } else {
    1468              :             break;
    1469              :         }
    1470              :     }
    1471            0 :     return len;
    1472              : }
    1473              : 
    1474              : 
    1475              : double
    1476       132198 : MSLink::getLengthsBeforeCrossing(const MSLane* foeLane) const {
    1477       132198 :     MSLane* via = myInternalLane;
    1478              :     double totalDist = 0.;
    1479              :     bool foundCrossing = false;
    1480       135054 :     while (via != nullptr) {
    1481       133694 :         MSLink* link = via->getLinkCont()[0];
    1482       133694 :         double dist = link->getLengthBeforeCrossing(foeLane);
    1483       133694 :         if (dist != INVALID_DOUBLE) {
    1484              :             // found conflicting lane
    1485       130838 :             totalDist += dist;
    1486              :             foundCrossing = true;
    1487              :             break;
    1488              :         } else {
    1489         2856 :             totalDist += via->getLength();
    1490              :             via = link->getViaLane();
    1491              :         }
    1492              :     }
    1493              :     if (foundCrossing) {
    1494       130838 :         return totalDist;
    1495              :     } else {
    1496              :         return INVALID_DOUBLE;
    1497              :     }
    1498              : }
    1499              : 
    1500              : 
    1501              : double
    1502       133694 : MSLink::getLengthBeforeCrossing(const MSLane* foeLane) const {
    1503              :     int foe_ix;
    1504       801527 :     for (foe_ix = 0; foe_ix != (int)myFoeLanes.size(); ++foe_ix) {
    1505       800031 :         if (myFoeLanes[foe_ix] == foeLane) {
    1506              :             break;
    1507              :         }
    1508              :     }
    1509       133694 :     if (foe_ix == (int)myFoeLanes.size()) {
    1510              :         // no conflict with the given lane, indicate by returning -1
    1511              : #ifdef MSLink_DEBUG_CROSSING_POINTS
    1512              :         std::cout << "No crossing of lanes '" << foeLane->getID() << "' and '" << myInternalLaneBefore->getID() << "'" << std::endl;
    1513              : #endif
    1514              :         return INVALID_DOUBLE;
    1515              :     } else {
    1516              :         // found conflicting lane index
    1517       132198 :         double dist = myInternalLaneBefore->getLength() - myConflicts[foe_ix].getLengthBehindCrossing(this);
    1518       132198 :         if (dist == -10000.) {
    1519              :             // this is the value in myConflicts, if the relation allows intersection but none is present for the actual geometry.
    1520              :             return INVALID_DOUBLE;
    1521              :         }
    1522              : #ifdef MSLink_DEBUG_CROSSING_POINTS
    1523              :         std::cout << "Crossing of lanes '" << myInternalLaneBefore->getID() << "' and '" << foeLane->getID()
    1524              :                   << "' at distance " << dist << " (approach along '"
    1525              :                   <<  myInternalLaneBefore->getEntryLink()->getLaneBefore()->getID() << "')" << std::endl;
    1526              : #endif
    1527              :         return dist;
    1528              :     }
    1529              : }
    1530              : 
    1531              : 
    1532              : bool
    1533     40505728 : MSLink::isEntryLink() const {
    1534     40505728 :     if (MSGlobals::gUsingInternalLanes) {
    1535     64491430 :         return myInternalLane != nullptr && myInternalLaneBefore == nullptr;
    1536              :     } else {
    1537              :         return false;
    1538              :     }
    1539              : }
    1540              : 
    1541              : bool
    1542     19693092 : MSLink::isConflictEntryLink() const {
    1543              :     // either a non-cont entry link or the link after a cont-link
    1544     19693092 :     return !myAmCont && (isEntryLink() || (myInternalLaneBefore != nullptr && myInternalLane != nullptr));
    1545              : }
    1546              : 
    1547              : bool
    1548     94563306 : MSLink::isExitLink() const {
    1549     94563306 :     if (MSGlobals::gUsingInternalLanes) {
    1550    162449528 :         return myInternalLaneBefore != nullptr && myInternalLane == nullptr;
    1551              :     } else {
    1552              :         return false;
    1553              :     }
    1554              : }
    1555              : 
    1556              : bool
    1557    156964089 : MSLink::isExitLinkAfterInternalJunction() const {
    1558    156964089 :     if (MSGlobals::gUsingInternalLanes) {
    1559              :         return (getInternalLaneBefore() != nullptr
    1560     82005144 :                 && myInternalLaneBefore->getIncomingLanes().size() == 1
    1561    238604599 :                 && myInternalLaneBefore->getIncomingLanes().front().viaLink->isInternalJunctionLink());
    1562              :     } else {
    1563              :         return false;
    1564              :     }
    1565              : }
    1566              : 
    1567              : 
    1568              : const MSLink*
    1569       142714 : MSLink::getCorrespondingExitLink() const {
    1570       142714 :     MSLane* lane = myInternalLane;
    1571              :     const MSLink* link = this;
    1572       290004 :     while (lane != nullptr) {
    1573       147290 :         link = lane->getLinkCont()[0];
    1574              :         lane = link->getViaLane();
    1575              :     }
    1576       142714 :     return link;
    1577              : }
    1578              : 
    1579              : 
    1580              : const MSLink*
    1581    826250797 : MSLink::getCorrespondingEntryLink() const {
    1582              :     const MSLink* link = this;
    1583   1111080858 :     while (link->myLaneBefore->isInternal()) {
    1584              :         assert(myLaneBefore->getIncomingLanes().size() == 1);
    1585    284830061 :         link = link->myLaneBefore->getIncomingLanes().front().viaLink;
    1586              :     }
    1587    826250797 :     return link;
    1588              : }
    1589              : 
    1590              : 
    1591              : bool
    1592    433948378 : MSLink::isInternalJunctionLink() const {
    1593    433948378 :     return getInternalLaneBefore() != nullptr && myInternalLane != nullptr;
    1594              : }
    1595              : 
    1596              : 
    1597              : const MSLink::LinkLeaders
    1598    899142549 : MSLink::getLeaderInfo(const MSVehicle* ego, double dist, std::vector<const MSPerson*>* collectBlockers, bool isShadowLink) const {
    1599              :     LinkLeaders result;
    1600              :     // this link needs to start at an internal lane (either an exit link or between two internal lanes)
    1601              :     // or it must be queried by the pedestrian model (ego == 0)
    1602    899142549 :     if (ego != nullptr && (!fromInternalLane() || ego->getLaneChangeModel().isOpposite())) {
    1603              :         // ignore link leaders
    1604              :         return result;
    1605              :     }
    1606              :     //gDebugFlag1 = true;
    1607    304903526 :     if (gDebugFlag1) {
    1608            0 :         std::cout << SIMTIME << " getLeaderInfo link=" << getDescription() << " dist=" << dist << " isShadowLink=" << isShadowLink << "\n";
    1609              :     }
    1610    304903526 :     if (MSGlobals::gComputeLC && ego != nullptr && ego->getLane()->isNormal()) {
    1611     27269231 :         const MSLink* junctionEntry = getLaneBefore()->getEntryLink();
    1612      6563837 :         if (junctionEntry->haveRed() && !ego->ignoreRed(junctionEntry, true)
    1613              :                 // check oncoming on bidiLane during laneChanging
    1614     33827556 :                 && (!MSGlobals::gComputeLC || junctionEntry->getLaneBefore()->getBidiLane() == nullptr)) {
    1615      6513743 :             if (gDebugFlag1) {
    1616            0 :                 std::cout << "   ignore linkLeaders beyond red light\n";
    1617              :             }
    1618              :             return result;
    1619              :         }
    1620              :     }
    1621              :     // this is an exit link
    1622    298389783 :     const double extraGap = ego != nullptr ? ego->getVehicleType().getParameter().getJMParam(SUMO_ATTR_JM_EXTRA_GAP, 0) : 0;
    1623    784589430 :     for (int i = 0; i < (int)myFoeLanes.size(); ++i) {
    1624    486199647 :         const MSLane* foeLane = myFoeLanes[i];
    1625    486199647 :         const MSLink* foeExitLink = foeLane->getLinkCont()[0];
    1626              :         // distance from the querying vehicle to the crossing point with foeLane
    1627    486199647 :         double distToCrossing = dist - myConflicts[i].getLengthBehindCrossing(this);
    1628    486199647 :         const double foeDistToCrossing = foeLane->getLength() - myConflicts[i].getFoeLengthBehindCrossing(foeExitLink);
    1629    486199647 :         const bool sameTarget = (myLane == foeExitLink->getLane()) && !isInternalJunctionLink() && !foeExitLink->isInternalJunctionLink();
    1630    486199647 :         const bool sameSource = (myInternalLaneBefore != nullptr && myInternalLaneBefore->getNormalPredecessorLane() == foeLane->getNormalPredecessorLane());
    1631    486199647 :         const double crossingWidth = (sameTarget || sameSource) ? 0 : myConflicts[i].conflictSize;
    1632    486199647 :         const double foeCrossingWidth = (sameTarget || sameSource) ? 0 : myConflicts[i].getFoeConflictSize(foeExitLink);
    1633              :         // special treatment of contLane foe only applies if this lane is not a contLane or contLane follower itself
    1634    615442079 :         const bool contLane = (foeExitLink->getViaLaneOrLane()->getEdge().isInternal() && !(
    1635    129242432 :                                    isInternalJunctionLink() || isExitLinkAfterInternalJunction()));
    1636    486199647 :         if (gDebugFlag1) {
    1637              :             std::cout << " distToCrossing=" << distToCrossing << " foeLane=" << foeLane->getID() << " cWidth=" << crossingWidth
    1638            0 :                       << " flag=" << myConflicts[i].flag << " i=" << i << " fcIndex=" << myConflicts[i].foeConflictIndex
    1639            0 :                       << " ijl=" << isInternalJunctionLink() << " sT=" << sameTarget << " sS=" << sameSource
    1640            0 :                       << " lbc=" << myConflicts[i].getLengthBehindCrossing(this)
    1641            0 :                       << " flbc=" << myConflicts[i].getFoeLengthBehindCrossing(foeExitLink)
    1642              :                       << " cw=" << crossingWidth
    1643              :                       << " fcw=" << foeCrossingWidth
    1644              :                       << " contLane=" << contLane
    1645            0 :                       << " state=" << toString(myState)
    1646            0 :                       << " foeState=" << toString(foeExitLink->getState())
    1647            0 :                       << "\n";
    1648              :         }
    1649    107513816 :         if (distToCrossing + crossingWidth < 0 && !sameTarget
    1650    587974916 :                 && (ego == nullptr || !MSGlobals::gComputeLC || distToCrossing + crossingWidth + ego->getVehicleType().getLength() < 0)) {
    1651     97625361 :             if (gDebugFlag1) {
    1652            0 :                 std::cout << " ignore:egoBeyondCrossingPoint\n";
    1653              :             }
    1654     97625361 :             continue; // vehicle is behind the crossing point, continue with next foe lane
    1655              :         }
    1656              :         bool ignoreGreenCont = false;
    1657              :         bool foeIndirect = false;
    1658    388574286 :         if (contLane) {
    1659     42043617 :             const MSLink* entry = getLaneBefore()->getEntryLink();
    1660     42043617 :             const MSLink* foeEntry = foeLane->getEntryLink();
    1661     42043617 :             foeIndirect = foeEntry->myAmIndirect;
    1662     41763930 :             if (entry != nullptr && entry->haveGreen()
    1663     26753103 :                     && foeEntry != nullptr && foeEntry->haveGreen()
    1664     54504469 :                     && entry->myLaneBefore != foeEntry->myLaneBefore)  {
    1665              :                 // ignore vehicles before an internaljunction as long as they are still in green minor mode
    1666              :                 ignoreGreenCont = true;
    1667              :             }
    1668              :         }
    1669     42043617 :         if (foeIndirect && distToCrossing >= NO_INTERSECTION) {
    1670        29409 :             if (gDebugFlag1) {
    1671            0 :                 std::cout << " ignore:noIntersection\n";
    1672              :             }
    1673        29409 :             continue;
    1674              :         }
    1675              :         // it is not sufficient to return the last vehicle on the foeLane because ego might be its leader
    1676              :         // therefore we return all vehicles on the lane
    1677              :         //
    1678              :         // special care must be taken for continuation lanes. (next lane is also internal)
    1679              :         // vehicles on cont. lanes or on internal lanes with the same target as this link can not be ignored
    1680              :         // and should block (gap = -1) unless they are part of an indirect turn
    1681              :         MSLane::AnyVehicleIterator end = foeLane->anyVehiclesEnd();
    1682     29726203 :         for (MSLane::AnyVehicleIterator it_veh = foeLane->anyVehiclesBegin(); it_veh != end; ++it_veh) {
    1683     29726203 :             MSVehicle* leader = (MSVehicle*)*it_veh;
    1684     29726203 :             const double leaderBack = leader->getBackPositionOnLane(foeLane) - extraGap;
    1685     29726203 :             const double leaderBackDist = foeDistToCrossing - leaderBack;
    1686     29726203 :             const double l2 = ego != nullptr ? ego->getLength() + 2 : 0; // add some slack to account for further meeting-angle effects
    1687     29613715 :             const double sagitta = ego != nullptr && myRadius != std::numeric_limits<double>::max() ? myRadius - sqrt(myRadius * myRadius - 0.25 * l2 * l2) : 0;
    1688     29726203 :             const bool pastTheCrossingPoint = leaderBackDist + foeCrossingWidth + sagitta < 0;
    1689     29726203 :             const bool enteredTheCrossingPoint = leaderBackDist < leader->getVehicleType().getLength();
    1690     29726203 :             const bool foeIsBicycleTurn = (leader->getVehicleType().getVehicleClass() == SVC_BICYCLE
    1691     29726203 :                                            && foeLane->getIncomingLanes().front().viaLink->getDirection() == LinkDirection::LEFT);
    1692     29726203 :             const bool ignoreIndirectBicycleTurn = pastTheCrossingPoint && foeIsBicycleTurn;
    1693     29726203 :             const bool cannotIgnore = ((contLane && !ignoreIndirectBicycleTurn) || sameTarget || (sameSource && !MSGlobals::gComputeLC)) && ego != nullptr;
    1694     29726203 :             const bool inTheWay = ((((!pastTheCrossingPoint && distToCrossing > 0) || (sameTarget && distToCrossing > leaderBackDist - leader->getLength()))
    1695     23830066 :                                     && (enteredTheCrossingPoint || (sameSource && !enteredTheCrossingPoint && foeDistToCrossing < distToCrossing))
    1696     15794884 :                                     && (!(myConflicts[i].flag == CONFLICT_DUMMY_MERGE) || foeIsBicycleTurn || sameSource))
    1697     43701359 :                                    || foeExitLink->getLaneBefore()->getNormalPredecessorLane() == myLane->getBidiLane());
    1698     29726203 :             const bool isOpposite = leader->getLaneChangeModel().isOpposite();
    1699     29726203 :             const auto avi = foeExitLink->getApproaching(leader);
    1700              :             // if leader is not found, assume that it performed a lane change in the last step
    1701     29726203 :             const bool willPass = avi.willPass || (avi.arrivalTime == INVALID_TIME && sameTarget);
    1702     29726203 :             if (gDebugFlag1) {
    1703              :                 std::cout << " candidate leader=" << leader->getID()
    1704              :                           << " cannotIgnore=" << cannotIgnore
    1705              :                           << " fdtc=" << foeDistToCrossing
    1706              :                           << " lb=" << leaderBack
    1707              :                           << " lbd=" << leaderBackDist
    1708              :                           << " fcwidth=" << foeCrossingWidth
    1709            0 :                           << " r=" << myRadius
    1710              :                           << " sagitta=" << sagitta
    1711              :                           << " foePastCP=" << pastTheCrossingPoint
    1712              :                           << " foeEnteredCP=" << enteredTheCrossingPoint
    1713              :                           << " inTheWay=" << inTheWay
    1714              :                           << " willPass=" << willPass
    1715            0 :                           << " isFrontOnLane=" << leader->isFrontOnLane(foeLane)
    1716              :                           << " ignoreGreenCont=" << ignoreGreenCont
    1717              :                           << " foeIndirect=" << foeIndirect
    1718              :                           << " foeBikeTurn=" << foeIsBicycleTurn
    1719            0 :                           << " isOpposite=" << isOpposite << "\n";
    1720              :             }
    1721     29726203 :             if (leader == ego) {
    1722      7963783 :                 continue;
    1723              :             }
    1724              :             // ignore greenCont foe vehicles that are not in the way
    1725     28952822 :             if (!inTheWay && ignoreGreenCont) {
    1726         7088 :                 if (gDebugFlag1) {
    1727            0 :                     std::cout << "   ignoreGreenCont\n";
    1728              :                 }
    1729         7088 :                 continue;
    1730              :             }
    1731              :             // after entering the conflict area, ignore foe vehicles that are not in the way
    1732      4160863 :             if ((!MSGlobals::gComputeLC || (ego != nullptr && ego->getLane() == foeLane) || (MSGlobals::gSublane && !MSGlobals::gComputeLC))
    1733     24967103 :                     && distToCrossing < -POSITION_EPS && !inTheWay
    1734     29059997 :                     && (ego == nullptr || !MSGlobals::gComputeLC || distToCrossing < -ego->getVehicleType().getLength())) {
    1735        89961 :                 if (gDebugFlag1) {
    1736            0 :                     std::cout << "   ego entered conflict area\n";
    1737              :                 }
    1738        89961 :                 continue;
    1739              :             }
    1740     28930412 :             if (!MSGlobals::gComputeLC
    1741     24696650 :                     && sameSource
    1742      7529482 :                     && &ego->getLane()->getEdge() == &myInternalLaneBefore->getEdge()
    1743     29226211 :                     && leaderBack + leader->getLength() < ego->getPositionOnLane() - ego->getLength()) {
    1744              :                 // ego is already on the junction and clearly ahead of foe
    1745        74639 :                 if (gDebugFlag1) {
    1746            0 :                     std::cout << "   ego ahead of same-source foe\n";
    1747              :                 }
    1748        74639 :                 continue;
    1749              :             }
    1750              : 
    1751              :             // ignore foe vehicles that will not pass
    1752     18670817 :             if ((!cannotIgnore || leader->isStopped() || sameTarget)
    1753     19745218 :                     && !willPass
    1754      1590759 :                     && (avi.arrivalTime == INVALID_TIME || leader->getSpeed() < SUMO_const_haltingSpeed)
    1755      1590486 :                     && leader->isFrontOnLane(foeLane)
    1756              :                     && !isOpposite
    1757       768162 :                     && !inTheWay
    1758              :                     // willPass is false if the vehicle is already on the stopping edge
    1759     29207212 :                     && !leader->willStop()) {
    1760       425287 :                 if (gDebugFlag1) {
    1761            0 :                     std::cout << "   foe will not pass\n";
    1762              :                 }
    1763       425287 :                 continue;
    1764              :             }
    1765     28355847 :             if (leader->isBidiOn(foeLane)) {
    1766              :                 // conflict resolved via forward lane of the foe
    1767       325093 :                 continue;
    1768              :             }
    1769              :             // check whether foe is blocked and might need to change before leaving the junction
    1770     28030754 :             const bool foeStrategicBlocked = (leader->getLaneChangeModel().isStrategicBlocked() &&
    1771      1338494 :                                               leader->getCarFollowModel().brakeGap(leader->getSpeed()) <= foeLane->getLength() - leaderBack);
    1772     28030754 :             const bool sameInternalEdge = &myInternalLaneBefore->getEdge() == &foeExitLink->getInternalLaneBefore()->getEdge();
    1773              : 
    1774     28030754 :             const bool foeLaneIsBidi = myInternalLaneBefore->getBidiLane() == foeLane;
    1775     28030754 :             if (MSGlobals::gSublane && ego != nullptr && (sameSource || sameTarget || foeLaneIsBidi)
    1776      7622714 :                     && (!foeStrategicBlocked || sameInternalEdge)) {
    1777      7466867 :                 if (ego->getLane() == leader->getLane()) {
    1778       172258 :                     continue;
    1779              :                 }
    1780              :                 // ignore vehicles if not in conflict sublane-wise
    1781      7294609 :                 const double egoLatOffset = isShadowLink ? ego->getLatOffset(ego->getLaneChangeModel().getShadowLane()) : 0;
    1782      7294609 :                 const double posLat = ego->getLateralPositionOnLane() + egoLatOffset;
    1783      7294609 :                 double posLatLeader = leader->getLateralPositionOnLane() + leader->getLatOffset(foeLane);
    1784      7294609 :                 if (foeLaneIsBidi) {
    1785              :                     // leader is oncoming
    1786         1473 :                     posLatLeader = foeLane->getWidth() - posLatLeader;
    1787              :                 }
    1788      7294609 :                 const double latGap = (fabs(posLat - posLatLeader)
    1789      7294609 :                                        - 0.5 * (ego->getVehicleType().getWidth() + leader->getVehicleType().getWidth()));
    1790      7294609 :                 const double maneuverDist = leader->getLaneChangeModel().getManeuverDist() * (posLat < posLatLeader ? -1 : 1);
    1791      7294609 :                 if (gDebugFlag1) {
    1792            0 :                     std::cout << " checkIgnore sublaneFoe lane=" << myInternalLaneBefore->getID()
    1793              :                               << " sameSource=" << sameSource
    1794              :                               << " sameTarget=" << sameTarget
    1795              :                               << " foeLaneIsBidi=" << foeLaneIsBidi
    1796              :                               << " foeLane=" << foeLane->getID()
    1797              :                               << " leader=" << leader->getID()
    1798            0 :                               << " egoLane=" << ego->getLane()->getID()
    1799            0 :                               << " leaderLane=" << leader->getLane()->getID()
    1800              :                               << " egoLat=" << posLat
    1801              :                               << " egoLatOffset=" << egoLatOffset
    1802              :                               << " leaderLat=" << posLatLeader
    1803            0 :                               << " leaderLatOffset=" << leader->getLatOffset(foeLane)
    1804              :                               << " latGap=" << latGap
    1805              :                               << " maneuverDist=" << maneuverDist
    1806            0 :                               << " computeLC=" << MSGlobals::gComputeLC
    1807            0 :                               << " egoMaxSpeedLat=" << ego->getVehicleType().getMaxSpeedLat()
    1808            0 :                               << "\n";
    1809              :                 }
    1810      1581271 :                 if (latGap > 0 && (latGap > maneuverDist || !sameTarget || !MSGlobals::gComputeLC)
    1811              :                         // do not perform sublane changes that interfere with the leader vehicle
    1812      8869081 :                         && (!MSGlobals::gComputeLC || latGap > ego->getVehicleType().getMaxSpeedLat())) {
    1813      1399613 :                     const MSLink* foeEntryLink = foeLane->getIncomingLanes().front().viaLink;
    1814      1399613 :                     if (sameSource) {
    1815              :                         // for lanes from the same edge, higer index implies a
    1816              :                         // connection further to the left
    1817      1076842 :                         const bool leaderFromRight = (myIndex > foeEntryLink->getIndex());
    1818      1076842 :                         if ((posLat > posLatLeader) == leaderFromRight) {
    1819              :                             // ignore speed since lanes diverge
    1820       616741 :                             if (gDebugFlag1) {
    1821            0 :                                 std::cout << "   ignored (same source) leaderFromRight=" << leaderFromRight << "\n";
    1822              :                             }
    1823       616741 :                             continue;
    1824              :                         }
    1825       322771 :                     } else if (sameTarget) {
    1826              :                         // for lanes from different edges we cannot rely on the
    1827              :                         // index due to wrap-around issues
    1828       321298 :                         if (myDirection != foeEntryLink->getDirection()) {
    1829       313493 :                             bool leaderFromRight = foeEntryLink->getDirection() < myDirection;
    1830              :                             // leader vehicle should not move towards ego
    1831       313493 :                             if (MSGlobals::gLefthand) {
    1832            0 :                                 leaderFromRight = !leaderFromRight;
    1833              :                             }
    1834       313493 :                             if (gDebugFlag1) {
    1835            0 :                                 std::cout << "   leaderFromRight=" << leaderFromRight << "\n";
    1836              :                             }
    1837       457713 :                             if ((posLat > posLatLeader) == leaderFromRight
    1838              :                                     // leader should keep lateral position or move away from ego
    1839       173956 :                                     && (leader->getLaneChangeModel().getSpeedLat() == 0 || leader->getLaneChangeModel().getManeuverDist() == 0
    1840        30963 :                                         || leaderFromRight == (leader->getLaneChangeModel().getSpeedLat() < latGap))
    1841       462116 :                                     && (ego->getLaneChangeModel().getSpeedLat() == 0 || ego->getLaneChangeModel().getManeuverDist() == 0
    1842        10523 :                                         || leaderFromRight == (ego->getLaneChangeModel().getSpeedLat() > -latGap))) {
    1843       144220 :                                 if (gDebugFlag1) {
    1844            0 :                                     std::cout << "   ignored (different source) leaderFromRight=" << leaderFromRight << "\n";
    1845              :                                 }
    1846       144220 :                                 continue;
    1847              :                             }
    1848              :                         } else {
    1849              :                             // XXX figure out relative direction somehow
    1850              :                         }
    1851              :                     } else {
    1852         1473 :                         if (gDebugFlag1) {
    1853            0 :                             std::cout << "   ignored oncoming bidi leader\n";
    1854              :                         }
    1855         1473 :                         continue;
    1856              :                     }
    1857              :                 }
    1858              :             }
    1859     27096062 :             if (leader->getWaitingTime() < MSGlobals::gIgnoreJunctionBlocker) {
    1860              :                 // compute distance between vehicles on the superimposition of both lanes
    1861              :                 // where the crossing point is the common point
    1862              :                 double gap;
    1863              :                 bool fromLeft = true;
    1864     26593103 :                 if (ego == nullptr) {
    1865              :                     // request from pedestrian model. return distance between leaderBack and crossing point
    1866              :                     //std::cout << "   foeLane=" << foeLane->getID() << " leaderBack=" << leaderBack << " foeDistToCrossing=" << foeDistToCrossing << " foeLength=" << foeLane->getLength() << " foebehind=" << myConflicts[i].second << " dist=" << dist << " behind=" << myConflicts[i].first << "\n";
    1867       112078 :                     gap = leaderBackDist;
    1868              :                     // distToCrossing should not take into account the with of the foe lane
    1869              :                     // (which was subtracted in setRequestInformation)
    1870              :                     // Instead, the width of the foe vehicle is used directly by the caller.
    1871       112078 :                     distToCrossing += myConflicts[i].conflictSize / 2;
    1872       112078 :                     if (gap + foeCrossingWidth < 0) {
    1873              :                         // leader is completely past the crossing point
    1874              :                         // or there is no crossing point
    1875      4560261 :                         continue; // next vehicle
    1876              :                     }
    1877              :                     // we need to determine whether the vehicle passes the
    1878              :                     // crossing from the left or the right (heuristic)
    1879       109895 :                     fromLeft = foeDistToCrossing > 0.5 * foeLane->getLength();
    1880     26481025 :                 } else if ((contLane && !sameSource && !ignoreIndirectBicycleTurn) || isOpposite) {
    1881      1497712 :                     gap = -std::numeric_limits<double>::max(); // always break for vehicles which are on a continuation lane or for opposite-direction vehicles
    1882              :                 } else {
    1883     24983313 :                     if (pastTheCrossingPoint && !sameTarget) {
    1884              :                         // leader is completely past the crossing point
    1885              :                         // or there is no crossing point
    1886      4557997 :                         if (gDebugFlag1) {
    1887            0 :                             std::cout << " foePastCP ignored\n";
    1888              :                         }
    1889      4557997 :                         continue;
    1890              :                     }
    1891              :                     double leaderBackDist2 = leaderBackDist;
    1892     20425316 :                     if (sameTarget && leaderBackDist2 < 0) {
    1893      3176192 :                         const double mismatch = myConflicts[i].getFoeLengthBehindCrossing(foeExitLink) - myConflicts[i].getLengthBehindCrossing(this);
    1894      3176192 :                         if (mismatch > 0) {
    1895      1594878 :                             leaderBackDist2 += mismatch;
    1896              :                         }
    1897              :                     }
    1898     20425316 :                     if (gDebugFlag1) {
    1899              :                         std::cout << " distToCrossing=" << distToCrossing << " leaderBack=" << leaderBack
    1900              :                                   << " backDist=" << leaderBackDist
    1901              :                                   << " backDist2=" << leaderBackDist2
    1902            0 :                                   << " blockedStrategic=" << leader->getLaneChangeModel().isStrategicBlocked()
    1903            0 :                                   << "\n";
    1904              :                     }
    1905     20425316 :                     gap = distToCrossing - ego->getVehicleType().getMinGap() - leaderBackDist2 - foeCrossingWidth;
    1906              :                 }
    1907              :                 // if the foe is already moving off the intersection, we may
    1908              :                 // advance up to the crossing point unless we have the same target or same source
    1909              :                 // (for sameSource, the crossing point indicates the point of divergence)
    1910     25779213 :                 const bool stopAsap = ((leader->isFrontOnLane(foeLane) ? cannotIgnore : (sameTarget || sameSource))
    1911     22455030 :                                        || (ego != nullptr && ego->getVehicleType().getParameter().getJMParam(SUMO_ATTR_JM_ADVANCE, 1.0) == 0.0));
    1912     22032923 :                 if (gDebugFlag1) {
    1913            0 :                     std::cout << " leader=" << leader->getID() << " contLane=" << contLane << " cannotIgnore=" << cannotIgnore << " stopAsap=" << stopAsap << " gap=" << gap << "\n";
    1914              :                 }
    1915     22032923 :                 if (ignoreFoe(ego, leader)) {
    1916           81 :                     continue;
    1917              :                 }
    1918     22032842 :                 const int llFlags = ((fromLeft ? LL_FROM_LEFT : 0) |
    1919     22032842 :                                      (inTheWay ? LL_IN_THE_WAY : 0) |
    1920     22032842 :                                      (sameSource ? LL_SAME_SOURCE : 0) |
    1921     22032842 :                                      (sameTarget ? LL_SAME_TARGET : 0));
    1922     29090809 :                 result.emplace_back(leader, gap, stopAsap ? -1 : distToCrossing, llFlags, leader->getLatOffset(foeLane));
    1923              :             }
    1924              : 
    1925              :         }
    1926    388544877 :         if (ego != nullptr && MSNet::getInstance()->hasPersons()) {
    1927              :             // check for crossing pedestrians (keep driving if already on top of the crossing
    1928      8919373 :             const double distToPeds = distToCrossing - ego->getVehicleType().getParameter().getJMParam(SUMO_ATTR_JM_STOPLINE_CROSSING_GAP, MSPModel::SAFETY_GAP);
    1929      8919373 :             const double vehWidth = ego->getVehicleType().getWidth() + MSPModel::SAFETY_GAP; // + configurable safety gap
    1930              :             /// @todo consider lateral position (depending on whether the crossing is encountered on the way in or out)
    1931              :             // @check lefthand?!
    1932      8919373 :             const bool wayIn = myConflicts[i].lengthBehindCrossing < myLaneBefore->getLength() * 0.5;
    1933      8919373 :             const double vehCenter = (foeDistToCrossing + myLaneBefore->getWidth() * 0.5
    1934      8919373 :                                       + ego->getLateralPositionOnLane() * (wayIn ? -1 : 1));
    1935              :             // can access the movement model here since we already checked for existing persons above
    1936     17373737 :             if (distToPeds >= -MSPModel::SAFETY_GAP && MSNet::getInstance()->getPersonControl().getMovementModel()->blockedAtDist(ego, foeLane, vehCenter, vehWidth,
    1937      8454364 :                     ego->getVehicleType().getParameter().getJMParam(SUMO_ATTR_JM_CROSSING_GAP, JM_CROSSING_GAP_DEFAULT),
    1938              :                     collectBlockers)) {
    1939       519823 :                 result.emplace_back(nullptr, -1, distToPeds);
    1940      8399550 :             } else if (foeLane->isCrossing() && ego->getLane()->isInternal() && ego->getLane()->getEdge().getToJunction() == myJunction) {
    1941       150521 :                 const MSLink* crossingLink = foeLane->getIncomingLanes()[0].viaLink;
    1942       150521 :                 if (distToCrossing > 0 && crossingLink->havePriority() && crossingLink->myApproachingPersons != nullptr) {
    1943              :                     // a person might step on the crossing at any moment, since ego
    1944              :                     // is already on the junction, the opened() check is not done anymore
    1945        26562 :                     const double timeToEnterCrossing = distToCrossing / MAX2(ego->getSpeed(), 1.0);
    1946        31872 :                     for (const auto& item : (*crossingLink->myApproachingPersons)) {
    1947         6860 :                         if (!ignoreFoe(ego, item.first) && timeToEnterCrossing > STEPS2TIME(item.second.arrivalTime - SIMSTEP)) {
    1948         1550 :                             if (gDebugFlag1) {
    1949            0 :                                 std::cout << SIMTIME << ": " << ego->getID() << " breaking for approaching person " << item.first->getID()
    1950              :                                           //<< " dtc=" << distToCrossing << " ttc=" << distToCrossing / MAX2(ego->getSpeed(), 1.0) << " foeAT=" << item.second.arrivalTime << " foeTTC=" << STEPS2TIME(item.second.arrivalTime - SIMSTEP)
    1951            0 :                                           << "\n";
    1952              :                             }
    1953         1550 :                             result.emplace_back(nullptr, -1, distToPeds);
    1954         1550 :                             break;
    1955              :                             //} else {
    1956              :                             //    if (gDebugFlag1) {
    1957              :                             //        std::cout << SIMTIME << ": " << ego->getID() << " notBreaking for approaching person " << item.first->getID()
    1958              :                             //            << " dtc=" << distToCrossing << " ttc=" << distToCrossing / MAX2(ego->getSpeed(), 1.0) << " foeAT=" << item.second.arrivalTime << " foeTTC=" << STEPS2TIME(item.second.arrivalTime - SIMSTEP)
    1959              :                             //            << "\n";
    1960              :                             //    }
    1961              :                         }
    1962              :                     }
    1963              :                 }
    1964              :             }
    1965              :         }
    1966              :     }
    1967              : 
    1968              :     //std::cout << SIMTIME << " ego=" << Named::getIDSecure(ego) << " link=" << getViaLaneOrLane()->getID() << " myWalkingAreaFoe=" << Named::getIDSecure(myWalkingAreaFoe) << "\n";
    1969    298389783 :     if (ego != nullptr) {
    1970    297449397 :         checkWalkingAreaFoe(ego, myWalkingAreaFoe, collectBlockers, result);
    1971    297449397 :         checkWalkingAreaFoe(ego, myWalkingAreaFoeExit, collectBlockers, result);
    1972              :     }
    1973              : 
    1974    298389783 :     if (MSGlobals::gLateralResolution > 0 && ego != nullptr && !isShadowLink) {
    1975              :         // check for foes on the same edge
    1976     76330047 :         for (std::vector<MSLane*>::const_iterator it = mySublaneFoeLanes.begin(); it != mySublaneFoeLanes.end(); ++it) {
    1977      7303188 :             const MSLane* foeLane = *it;
    1978              :             MSLane::AnyVehicleIterator end = foeLane->anyVehiclesEnd();
    1979      4823300 :             for (MSLane::AnyVehicleIterator it_veh = foeLane->anyVehiclesBegin(); it_veh != end; ++it_veh) {
    1980      4823300 :                 MSVehicle* leader = (MSVehicle*)*it_veh;
    1981      4823300 :                 if (leader == ego) {
    1982      3031629 :                     continue;
    1983              :                 }
    1984      4146610 :                 if (leader->getLane()->isNormal()) {
    1985              :                     // leader is past the conflict point
    1986      1925859 :                     continue;
    1987              :                 }
    1988      2220751 :                 const double maxLength = MAX2(myInternalLaneBefore->getLength(), foeLane->getLength());
    1989      2220751 :                 const double gap = dist - maxLength - ego->getVehicleType().getMinGap() + leader->getBackPositionOnLane(foeLane) - extraGap;
    1990      2220751 :                 if (gap < -(ego->getVehicleType().getMinGap() + leader->getLength())) {
    1991              :                     // ego is ahead of leader
    1992       429080 :                     continue;
    1993              :                 }
    1994      1791671 :                 const double posLat = ego->getLateralPositionOnLane();
    1995      1791671 :                 const double posLatLeader = leader->getLateralPositionOnLane() + leader->getLatOffset(foeLane);
    1996      1791671 :                 if (gDebugFlag1) {
    1997            0 :                     std::cout << " sublaneFoe lane=" << myInternalLaneBefore->getID()
    1998              :                               << " foeLane=" << foeLane->getID()
    1999              :                               << " leader=" << leader->getID()
    2000            0 :                               << " egoLane=" << ego->getLane()->getID()
    2001            0 :                               << " leaderLane=" << leader->getLane()->getID()
    2002              :                               << " gap=" << gap
    2003              :                               << " egoLat=" << posLat
    2004              :                               << " leaderLat=" << posLatLeader
    2005            0 :                               << " leaderLatOffset=" << leader->getLatOffset(foeLane)
    2006            0 :                               << " egoIndex=" << myInternalLaneBefore->getIndex()
    2007            0 :                               << " foeIndex=" << foeLane->getIndex()
    2008            0 :                               << " dist=" << dist
    2009            0 :                               << " leaderBack=" << leader->getBackPositionOnLane(foeLane)
    2010            0 :                               << "\n";
    2011              :                 }
    2012              :                 // there only is a conflict if the paths cross
    2013       731777 :                 if ((posLat < posLatLeader && myInternalLaneBefore->getIndex() > foeLane->getIndex())
    2014      2131256 :                         || (posLat > posLatLeader && myInternalLaneBefore->getIndex() < foeLane->getIndex())) {
    2015       816344 :                     if (gDebugFlag1) {
    2016            0 :                         std::cout << SIMTIME << " blocked by " << leader->getID() << " (sublane split) foeLane=" << foeLane->getID() << "\n";
    2017              :                     }
    2018       816344 :                     if (ignoreFoe(ego, leader)) {
    2019            0 :                         continue;
    2020              :                     }
    2021       816344 :                     result.emplace_back(leader, gap, -1, LL_SAME_SOURCE);
    2022              :                 }
    2023              :             }
    2024              :         }
    2025              :     }
    2026              :     return result;
    2027            0 : }
    2028              : 
    2029              : 
    2030              : void
    2031    594898794 : MSLink::checkWalkingAreaFoe(const MSVehicle* ego, const MSLane* foeLane, std::vector<const MSPerson*>* collectBlockers, LinkLeaders& result) const {
    2032    594898794 :     if (foeLane != nullptr && foeLane->getEdge().getPersons().size() > 0) {
    2033              :         // pedestrians may be on an arbitrary path across this
    2034              :         // walkingarea. make sure to keep enough distance.
    2035              :         // This is a simple but conservative solution that could be improved
    2036              :         // by ignoring pedestrians that are "obviously" not on a collision course
    2037       124976 :         double distToPeds = std::numeric_limits<double>::max();
    2038              :         assert(myInternalLaneBefore != nullptr);
    2039       124976 :         PositionVector egoPath = myInternalLaneBefore->getShape();
    2040       124976 :         if (ego->getLateralPositionOnLane() != 0) {
    2041       110480 :             egoPath.move2side((MSGlobals::gLefthand ? 1 : -1) * ego->getLateralPositionOnLane());
    2042              :         }
    2043       937689 :         for (MSTransportable* t : foeLane->getEdge().getPersons()) {
    2044       812713 :             MSPerson* p = static_cast<MSPerson*>(t);
    2045       812713 :             double dist = ego->getPosition().distanceTo2D(p->getPosition()) - p->getVehicleType().getLength();
    2046       812713 :             const bool inFront = isInFront(ego, egoPath, p->getPosition()) || isInFront(ego, egoPath, getFuturePosition(p));
    2047              :             if (inFront) {
    2048       304424 :                 dist -= MAX2(ego->getVehicleType().getMinGap(), MSPModel::SAFETY_GAP);
    2049              :             }
    2050              : #ifdef DEBUG_WALKINGAREA
    2051              :             if (ego->isSelected()) {
    2052              :                 std::cout << SIMTIME << " veh=" << ego->getID() << " ped=" << p->getID()
    2053              :                           << " pos=" << ego->getPosition() << " pedPos=" << p->getPosition()
    2054              :                           << " futurePedPos=" << getFuturePosition(p)
    2055              :                           << " rawDist=" << ego->getPosition().distanceTo2D(p->getPosition())
    2056              :                           << " inFront=" << inFront
    2057              :                           << " dist=" << dist << "\n";
    2058              :             }
    2059              : #endif
    2060       812713 :             if (dist < ego->getVehicleType().getWidth() / 2 || inFront) {
    2061       152547 :                 if (inFront) {
    2062       152212 :                     const double oncomingFactor = isOnComingPed(ego, p);
    2063       152212 :                     if (oncomingFactor > 0) {
    2064              :                         // account for pedestrian movement while closing in
    2065        53382 :                         const double timeToStop = sqrt(dist) / 2;
    2066        53382 :                         const double pedDist = p->getMaxSpeed() * MAX2(timeToStop, TS) * oncomingFactor;
    2067        53382 :                         dist = MAX2(0.0, dist - pedDist);
    2068              : #ifdef DEBUG_WALKINGAREA
    2069              :                         if (ego->isSelected()) {
    2070              :                             std::cout << "    timeToStop=" << timeToStop << " pedDist=" << pedDist << " factor=" << oncomingFactor << " dist2=" << dist << "\n";
    2071              :                         }
    2072              : #endif
    2073              :                     }
    2074              :                 }
    2075       152547 :                 if (ignoreFoe(ego, p)) {
    2076        26165 :                     continue;
    2077              :                 }
    2078       126382 :                 distToPeds = MIN2(distToPeds, dist);
    2079       126382 :                 if (collectBlockers != nullptr) {
    2080            0 :                     collectBlockers->push_back(p);
    2081              :                 }
    2082              :             }
    2083              :         }
    2084       124976 :         if (distToPeds != std::numeric_limits<double>::max()) {
    2085              :             // leave extra space in front
    2086        85899 :             result.emplace_back(nullptr, -1, distToPeds);
    2087              :         }
    2088       124976 :     }
    2089    594898794 : }
    2090              : 
    2091              : bool
    2092      1489385 : MSLink::isInFront(const MSVehicle* ego, const PositionVector& egoPath, const Position& pPos) const {
    2093      1489385 :     const double pedAngle = ego->getPosition().angleTo2D(pPos);
    2094      1489385 :     const double angleDiff = fabs(GeomHelper::angleDiff(ego->getAngle(), pedAngle));
    2095              : #ifdef DEBUG_WALKINGAREA
    2096              :     if (ego->isSelected()) {
    2097              :         std::cout << " angleDiff=" << RAD2DEG(angleDiff) << "\n";
    2098              :     }
    2099              : #endif
    2100      1489385 :     if (angleDiff < DEG2RAD(75)) {
    2101      1057055 :         return egoPath.distance2D(pPos) < ego->getVehicleType().getWidth() + MSPModel::SAFETY_GAP;
    2102              :     }
    2103              :     return false;
    2104              : }
    2105              : 
    2106              : 
    2107              : double
    2108       152212 : MSLink::isOnComingPed(const MSVehicle* ego, const MSPerson* p) const {
    2109       152212 :     const double pedToEgoAngle = p->getPosition().angleTo2D(ego->getPosition());
    2110       152212 :     const double angleDiff = fabs(GeomHelper::angleDiff(p->getAngle(), pedToEgoAngle));
    2111              : #ifdef DEBUG_WALKINGAREA
    2112              :     if (ego->isSelected()) {
    2113              :         std::cout << " ped-angleDiff=" << RAD2DEG(angleDiff) << " res=" << cos(angleDiff) << "\n";
    2114              :     }
    2115              : #endif
    2116       152212 :     if (angleDiff <= DEG2RAD(90)) {
    2117              :         ;
    2118        53382 :         return cos(angleDiff);
    2119              :     } else {
    2120              :         return 0;
    2121              :     }
    2122              : }
    2123              : 
    2124              : 
    2125              : Position
    2126       676672 : MSLink::getFuturePosition(const MSPerson* p, double timeHorizon) const {
    2127       676672 :     const double a = p->getAngle();
    2128       676672 :     const double dist = timeHorizon * p->getMaxSpeed();
    2129              : 
    2130       676672 :     const Position offset(cos(a) * dist, sin(a) * dist);
    2131       676672 :     return p->getPosition() + offset;
    2132              : }
    2133              : 
    2134              : 
    2135              : MSLink*
    2136     10582734 : MSLink::getParallelLink(int direction) const {
    2137     10582734 :     if (direction == -1) {
    2138      4109596 :         return myParallelRight;
    2139      6473138 :     } else if (direction == 1) {
    2140      5812532 :         return myParallelLeft;
    2141              :     } else {
    2142              :         assert(false || myLane->getOpposite() != nullptr || MSGlobals::gComputeLC);
    2143              :         return nullptr;
    2144              :     }
    2145              : }
    2146              : 
    2147              : MSLink*
    2148       167103 : MSLink::getOppositeDirectionLink() const {
    2149       167103 :     if (myLane->getOpposite() != nullptr && myLaneBefore->getOpposite() != nullptr) {
    2150        42868 :         for (MSLink* cand : myLane->getOpposite()->getLinkCont()) {
    2151        39704 :             if (cand->getLane() == myLaneBefore->getOpposite()) {
    2152              :                 return cand;
    2153              :             }
    2154              :         }
    2155              :     }
    2156              :     return nullptr;
    2157              : }
    2158              : 
    2159              : 
    2160              : MSLink*
    2161      5921592 : MSLink::computeParallelLink(int direction) {
    2162      5921592 :     const MSLane* const before = getLaneBefore()->getParallelLane(direction, false);
    2163      5921592 :     const MSLane* const after = getLane()->getParallelLane(direction, false);
    2164      5921592 :     if (before != nullptr && after != nullptr) {
    2165      1003301 :         for (MSLink* const link : before->getLinkCont()) {
    2166       662258 :             if (link->getLane() == after) {
    2167              :                 return link;
    2168              :             }
    2169              :         }
    2170              :     }
    2171              :     return nullptr;
    2172              : }
    2173              : 
    2174              : 
    2175              : double
    2176      1326926 : MSLink::getZipperSpeed(const MSVehicle* ego, const double dist, double vSafe,
    2177              :                        SUMOTime arrivalTime,
    2178              :                        const BlockingFoes* foes) const {
    2179      1326926 :     if (myFoeLinks.size() == 0) {
    2180              :         // link should have LINKSTATE_MAJOR in this case
    2181              :         assert(false);
    2182              :         return vSafe;
    2183              :     }
    2184      1326926 :     const double brakeGap = ego->getCarFollowModel().brakeGap(vSafe, ego->getCarFollowModel().getMaxDecel(), TS);
    2185      1442377 :     if (dist > MAX2(myFoeVisibilityDistance, brakeGap)) {
    2186              : #ifdef DEBUG_ZIPPER
    2187              :         const SUMOTime now = MSNet::getInstance()->getCurrentTimeStep();
    2188              :         DEBUGOUT(DEBUG_COND_ZIPPER, SIMTIME << " getZipperSpeed ego=" << ego->getID()
    2189              :                  << " dist=" << dist << " bGap=" << brakeGap << " ignoring foes (arrival in " << STEPS2TIME(arrivalTime - now) << ")\n")
    2190              : #endif
    2191              :         return vSafe;
    2192              :     }
    2193              : #ifdef DEBUG_ZIPPER
    2194              :     DEBUGOUT(DEBUG_COND_ZIPPER, SIMTIME << " getZipperSpeed ego=" << ego->getID()
    2195              :              << " egoAT=" << arrivalTime
    2196              :              << " dist=" << dist
    2197              :              << " brakeGap=" << brakeGap
    2198              :              << " vSafe=" << vSafe
    2199              :              << " numFoes=" << foes->size()
    2200              :              << "\n")
    2201              : #endif
    2202              :     const bool uniqueFoeLink = myFoeLinks.size() == 1;
    2203       497258 :     MSLink* foeLink = myFoeLinks[0];
    2204      2594425 :     for (const auto& item : *foes) {
    2205      2097167 :         if (!item->isVehicle()) {
    2206            0 :             continue;
    2207              :         }
    2208      2097167 :         const MSVehicle* foe = dynamic_cast<const MSVehicle*>(item);
    2209              :         assert(foe != 0);
    2210              :         const ApproachingVehicleInformation* aviPtr = nullptr;
    2211      2097167 :         if (uniqueFoeLink) {
    2212      1391940 :             aviPtr = foeLink->getApproachingPtr(foe);
    2213              :         } else {
    2214              :             // figure out which link is approached by the current foe
    2215      1067464 :             for (MSLink* fl : myFoeLinks) {
    2216      1067464 :                 aviPtr = fl->getApproachingPtr(foe);
    2217      1067464 :                 if (aviPtr != nullptr) {
    2218              :                     break;
    2219              :                 }
    2220              :             }
    2221              :         }
    2222      2097167 :         if (aviPtr == nullptr) {
    2223            0 :             continue;
    2224              :         }
    2225              :         const ApproachingVehicleInformation& avi = *aviPtr;
    2226      2097167 :         const double foeDist = (foe->isActive() ? avi.dist : MAX2(0.0, avi.dist -
    2227           36 :                                 STEPS2TIME(MSNet::getInstance()->getCurrentTimeStep() - foe->getLastActionTime()) * avi.speed));
    2228              : 
    2229      1423763 :         if (    // ignore vehicles that arrive after us (unless they are ahead and we could easily brake for them)
    2230      2197819 :             ((avi.arrivalTime > arrivalTime) && !couldBrakeForLeader(dist, foeDist, ego, foe)) ||
    2231              :             // also ignore vehicles that are behind us and are able to brake for us
    2232      2197819 :             couldBrakeForLeader(foeDist, dist, foe, ego) ||
    2233              :             // resolve ties by lane index
    2234       673412 :             (avi.arrivalTime == arrivalTime && foeDist == dist && ego->getLane()->getIndex() < foe->getLane()->getIndex())) {
    2235              : #ifdef DEBUG_ZIPPER
    2236              :             if (DEBUG_COND_ZIPPER) std::cout
    2237              :                         << "    ignoring foe=" << foe->getID()
    2238              :                         << " foeAT=" << avi.arrivalTime
    2239              :                         << " foeDist=" << avi.dist
    2240              :                         << " foeDist2=" << foeDist
    2241              :                         << " foeSpeed=" << avi.speed
    2242              :                         << " egoSpeed=" << ego->getSpeed()
    2243              :                         << " deltaDist=" << foeDist - dist
    2244              :                         << " delteSpeed=" << avi.speed - foe->getCarFollowModel().getMaxDecel() - ego->getSpeed()
    2245              :                         << " egoCouldBrake=" << couldBrakeForLeader(dist, foeDist, ego, foe)
    2246              :                         << " foeCouldBrake=" << couldBrakeForLeader(foeDist, dist, foe, ego)
    2247              :                         << "\n";
    2248              : #endif
    2249      1423763 :             continue;
    2250              :         }
    2251              :         // the idea behind speed adaption is three-fold:
    2252              :         // 1) ego needs to be in a car-following relationship with foe eventually
    2253              :         //    thus, the ego speed should be equal to the follow speed once the foe enters
    2254              :         //    the zipper junction
    2255              :         // 2) ego vehicle needs to put a certain distance beteen himself and foe (safeGap)
    2256              :         //    achieving this distance can be spread over time but computing
    2257              :         //    safeGap is subject to estimation errors of future speeds
    2258              :         // 3) deceleration can be spread out over the time until true
    2259              :         //    car-following happens, at the start of speed adaptions, smaller
    2260              :         //    decelerations should be sufficient
    2261              : 
    2262              :         // we cannot trust avi.arrivalSpeed if the foe has leader vehicles that are accelerating
    2263              :         // lets try to extrapolate
    2264       673404 :         const double uMax = foe->getLane()->getVehicleMaxSpeed(foe);
    2265       673404 :         const double uAccel = foe->getCarFollowModel().estimateSpeedAfterDistance(foeDist, avi.speed, foe->getCarFollowModel().getMaxAccel());
    2266              :         const double uEnd = MIN2(uMax, uAccel);
    2267       673404 :         const double uAvg = (avi.speed + uEnd) / 2;
    2268       673404 :         const double tf0 = foeDist / MAX2(NUMERICAL_EPS, uAvg);
    2269       673404 :         const double tf = MAX2(1.0, ceil((tf0) / TS) * TS);
    2270              : 
    2271       673404 :         const double vMax = ego->getLane()->getVehicleMaxSpeed(ego);
    2272       673404 :         const double vAccel = ego->getCarFollowModel().estimateSpeedAfterDistance(dist, ego->getSpeed(), ego->getCarFollowModel().getMaxAccel());
    2273       673404 :         const double vDecel = ego->getCarFollowModel().estimateSpeedAfterDistance(dist, ego->getSpeed(), -ego->getCarFollowModel().getMaxDecel());
    2274              :         const double vEnd = MIN3(vMax, vAccel, MAX2(uEnd, vDecel));
    2275       673404 :         const double vAvg = (ego->getSpeed() + vEnd) / 2;
    2276       673404 :         const double te0 = dist / MAX2(NUMERICAL_EPS, vAvg);
    2277       673404 :         const double te = MAX2(1.0, ceil((te0) / TS) * TS);
    2278              : 
    2279       673404 :         const double tTarget = tf + ego->getCarFollowModel().getHeadwayTime();
    2280       673404 :         const double a = ego->getCarFollowModel().avoidArrivalAccel(dist, tTarget, vSafe, ego->getCarFollowModel().getMaxDecel());
    2281              : 
    2282       673404 :         const double gap = dist - foe->getVehicleType().getLength() - ego->getVehicleType().getMinGap() - foeDist;
    2283       673404 :         const double vFollow = ego->getCarFollowModel().followSpeed(
    2284       673404 :                                    ego, ego->getSpeed(), gap, avi.speed, foe->getCarFollowModel().getMaxDecel(), foe);
    2285       673404 :         const double vSafeGap = MAX2(vFollow, ego->getSpeed() + ACCEL2SPEED(a));
    2286              : 
    2287              :         // scale behavior based on ego time to link (te)
    2288       673404 :         const double w = MIN2(1.0, te / 10);
    2289       673404 :         const double maxDecel = w * ego->getCarFollowModel().getMaxDecel() + (1 - w) * ego->getCarFollowModel().getEmergencyDecel();
    2290       673404 :         const double vZipper = MAX3(vFollow, ego->getSpeed() - ACCEL2SPEED(maxDecel), vSafeGap);
    2291              : 
    2292              :         vSafe = MIN2(vSafe, vZipper);
    2293              : #ifdef DEBUG_ZIPPER
    2294              :         if (DEBUG_COND_ZIPPER) std::cout << "    adapting to foe=" << foe->getID()
    2295              :                                              << " foeDist=" << foeDist
    2296              :                                              << " foeSpeed=" << avi.speed
    2297              :                                              << " foeAS=" << avi.arrivalSpeed
    2298              :                                              << " egoSpeed=" << ego->getSpeed()
    2299              :                                              << " uMax=" << uMax
    2300              :                                              << " uAccel=" << uAccel
    2301              :                                              << " uEnd=" << uEnd
    2302              :                                              << " uAvg=" << uAvg
    2303              :                                              << " gap=" << gap
    2304              :                                              << "\n      "
    2305              :                                              << " tf=" << tf
    2306              :                                              << " te=" << te
    2307              :                                              << " aSafeGap=" << a
    2308              :                                              << " vMax=" << vMax
    2309              :                                              << " vAccel=" << vAccel
    2310              :                                              << " vDecel=" << vDecel
    2311              :                                              << " vEnd=" << vEnd
    2312              :                                              << " vSafeGap=" << vSafeGap
    2313              :                                              << " vFollow=" << vFollow
    2314              :                                              << " w=" << w
    2315              :                                              << " maxDecel=" << maxDecel
    2316              :                                              << " vZipper=" << vZipper
    2317              :                                              << " vSafe=" << vSafe
    2318              :                                              << "\n";
    2319              : #endif
    2320              :     }
    2321              :     return vSafe;
    2322              : }
    2323              : 
    2324              : 
    2325              : bool
    2326      2197819 : MSLink::couldBrakeForLeader(double followDist, double leaderDist, const MSVehicle* follow, const MSVehicle* leader) {
    2327              :     return (// leader is ahead of follower
    2328      2197819 :                followDist > leaderDist &&
    2329              :                // and follower could brake for 1 s to stay behind leader
    2330       393662 :                followDist - leaderDist > follow->getSpeed() - follow->getCarFollowModel().getMaxDecel() - leader->getSpeed());
    2331              : }
    2332              : 
    2333              : 
    2334              : void
    2335      2960796 : MSLink::initParallelLinks() {
    2336      2960796 :     myParallelRight = computeParallelLink(-1);
    2337      2960796 :     myParallelLeft = computeParallelLink(1);
    2338      2960796 : }
    2339              : 
    2340              : bool
    2341        77124 : MSLink::checkContOff() const {
    2342              :     // check whether this link gets to keep its cont status switching the tls off
    2343              :     // @note: this could also be pre-computed in netconvert
    2344              :     // we check whether there is any major link from this edge
    2345       226012 :     for (const MSLane* cand : myLaneBefore->getEdge().getLanes()) {
    2346       447515 :         for (const MSLink* link : cand->getLinkCont()) {
    2347       298627 :             if (link->getOffState() == LINKSTATE_TL_OFF_NOSIGNAL) {
    2348              :                 return true;
    2349              :             }
    2350              :         }
    2351              :     }
    2352              :     return false;
    2353              : }
    2354              : 
    2355              : bool
    2356      4364892 : MSLink::lateralOverlap(double posLat, double width, double posLat2, double width2) {
    2357      4364892 :     return fabs(posLat2 - posLat) < (width + width2) / 2;
    2358              : }
    2359              : 
    2360              : std::string
    2361            0 : MSLink::getDescription() const {
    2362            0 :     return myLaneBefore->getID() + "->" + getViaLaneOrLane()->getID();
    2363              : }
    2364              : 
    2365              : 
    2366              : bool
    2367    190343388 : MSLink::ignoreFoe(const SUMOTrafficObject* ego, const SUMOTrafficObject* foe) {
    2368    190343388 :     if (ego == nullptr || !ego->getParameter().wasSet(VEHPARS_JUNCTIONMODEL_PARAMS_SET)) {
    2369    190309835 :         return false;
    2370              :     }
    2371        33553 :     const SUMOVehicleParameter& param = ego->getParameter();
    2372        73462 :     for (const std::string& typeID : StringTokenizer(param.getParameter(toString(SUMO_ATTR_JM_IGNORE_TYPES), "")).getVector()) {
    2373        32650 :         if (typeID == foe->getVehicleType().getID()) {
    2374              :             return true;
    2375              :         }
    2376        33553 :     }
    2377        16507 :     for (const std::string& id : StringTokenizer(param.getParameter(toString(SUMO_ATTR_JM_IGNORE_IDS), "")).getVector()) {
    2378         2293 :         if (id == foe->getID()) {
    2379              :             return true;
    2380              :         }
    2381         7259 :     }
    2382         6955 :     return false;
    2383              : }
    2384              : 
    2385              : 
    2386              : void
    2387       112873 : MSLink::updateDistToFoePedCrossing(double dist) {
    2388       112873 :     myDistToFoePedCrossing = MIN2(myDistToFoePedCrossing, dist);
    2389       112873 : }
    2390              : 
    2391              : 
    2392              : std::pair<const SUMOVehicle* const, const MSLink::ApproachingVehicleInformation>
    2393     10499234 : MSLink::getClosest() const {
    2394              :     assert(getApproaching().size() > 0);
    2395              :     double minDist = std::numeric_limits<double>::max();
    2396              :     auto closestIt = getApproaching().begin();
    2397     20999197 :     for (auto apprIt = getApproaching().begin(); apprIt != getApproaching().end(); apprIt++) {
    2398     10499963 :         if (apprIt->second.dist < minDist) {
    2399              :             minDist = apprIt->second.dist;
    2400              :             closestIt = apprIt;
    2401              :         }
    2402              :     }
    2403              :     // maybe a parallel link has a closer vehicle
    2404              :     /*
    2405              :     for (MSLink* link2 : link->getLaneBefore()->getLinkCont()) {
    2406              :         if (link2 != link) {
    2407              :             for (auto apprIt2 = link2->getApproaching().begin(); apprIt2 != link2->getApproaching().end(); apprIt2++) {
    2408              :                 if (apprIt2->second.dist < minDist) {
    2409              :                     minDist = apprIt2->second.dist;
    2410              :                     closestIt = apprIt2;
    2411              :                 }
    2412              :             }
    2413              :         }
    2414              :     }
    2415              :     */
    2416     10499234 :     return *closestIt;
    2417              : }
    2418              : 
    2419              : 
    2420              : bool
    2421       472205 : MSLink::railSignalWasPassed() const {
    2422       472205 :     if (myJunction != nullptr && myJunction->getType() == SumoXMLNodeType::RAIL_SIGNAL) {
    2423         2015 :         for (const auto& item : myApproachingVehicles) {
    2424           12 :             if (item.second.dist < SPEED2DIST(item.first->getSpeed())) {
    2425              :                 return true;
    2426              :             }
    2427              :         }
    2428              :     }
    2429              :     return false;
    2430              : }
    2431              : 
    2432              : /****************************************************************************/
        

Generated by: LCOV version 2.0-1