LCOV - code coverage report
Current view: top level - src/microsim - MSEdge.cpp (source / functions) Coverage Total Hit
Test: lcov.info Lines: 95.4 % 766 731
Test Date: 2025-12-06 15:35:27 Functions: 95.4 % 87 83

            Line data    Source code
       1              : /****************************************************************************/
       2              : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
       3              : // Copyright (C) 2001-2025 German Aerospace Center (DLR) and others.
       4              : // This program and the accompanying materials are made available under the
       5              : // terms of the Eclipse Public License 2.0 which is available at
       6              : // https://www.eclipse.org/legal/epl-2.0/
       7              : // This Source Code may also be made available under the following Secondary
       8              : // Licenses when the conditions for such availability set forth in the Eclipse
       9              : // Public License 2.0 are satisfied: GNU General Public License, version 2
      10              : // or later which is available at
      11              : // https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html
      12              : // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
      13              : /****************************************************************************/
      14              : /// @file    MSEdge.cpp
      15              : /// @author  Christian Roessel
      16              : /// @author  Jakob Erdmann
      17              : /// @author  Christoph Sommer
      18              : /// @author  Daniel Krajzewicz
      19              : /// @author  Laura Bieker
      20              : /// @author  Michael Behrisch
      21              : /// @author  Sascha Krieg
      22              : /// @date    Tue, 06 Mar 2001
      23              : ///
      24              : // A road/street connecting two junctions
      25              : /****************************************************************************/
      26              : #include <config.h>
      27              : 
      28              : #include <algorithm>
      29              : #include <iostream>
      30              : #include <cassert>
      31              : #ifdef HAVE_FOX
      32              : #include <utils/common/ScopedLocker.h>
      33              : #endif
      34              : #include <utils/common/StringTokenizer.h>
      35              : #include <utils/options/OptionsCont.h>
      36              : #include <microsim/devices/MSRoutingEngine.h>
      37              : #include <mesosim/MELoop.h>
      38              : #include <mesosim/MESegment.h>
      39              : #include <mesosim/MEVehicle.h>
      40              : #include "MSInsertionControl.h"
      41              : #include "MSJunction.h"
      42              : #include "MSLane.h"
      43              : #include "MSLaneChanger.h"
      44              : #include "MSLaneChangerSublane.h"
      45              : #include "MSLink.h"
      46              : #include "MSGlobals.h"
      47              : #include "MSNet.h"
      48              : #include "MSVehicle.h"
      49              : #include "MSLeaderInfo.h"
      50              : #include <microsim/transportables/MSTransportable.h>
      51              : #include "MSEdgeWeightsStorage.h"
      52              : #include "MSEdge.h"
      53              : 
      54              : #define BEST_LANE_LOOKAHEAD 3000.0
      55              : 
      56              : // ===========================================================================
      57              : // static member definitions
      58              : // ===========================================================================
      59              : MSEdge::DictType MSEdge::myDict;
      60              : MSEdgeVector MSEdge::myEdges;
      61              : SVCPermissions MSEdge::myMesoIgnoredVClasses(0);
      62              : DepartLaneDefinition MSEdge::myDefaultDepartLaneDefinition(DepartLaneDefinition::DEFAULT);
      63              : int MSEdge::myDefaultDepartLane(0);
      64              : 
      65              : // ===========================================================================
      66              : // member method definitions
      67              : // ===========================================================================
      68      1929848 : MSEdge::MSEdge(const std::string& id, int numericalID,
      69              :                const SumoXMLEdgeFunc function,
      70              :                const std::string& streetName,
      71              :                const std::string& edgeType,
      72              :                const std::string& routingType,
      73              :                int priority,
      74      1929848 :                double distance) :
      75      1929848 :     Named(id), myNumericalID(numericalID), myLanes(nullptr),
      76      1929848 :     myLaneChanger(nullptr), myFunction(function), myVaporizationRequests(0),
      77      1929848 :     myLastFailedInsertionTime(-1),
      78      1929848 :     myFromJunction(nullptr), myToJunction(nullptr),
      79      1929848 :     myHaveTransientPermissions(false),
      80      1929848 :     myOtherTazConnector(nullptr),
      81      1929848 :     myStreetName(streetName),
      82      1929848 :     myEdgeType(edgeType),
      83      1929848 :     myRoutingType(routingType),
      84      1929848 :     myPriority(priority),
      85      1929848 :     myDistance(distance),
      86      1929848 :     myWidth(0.),
      87      1929848 :     myLength(0.),
      88      1929848 :     myEmptyTraveltime(0.),
      89      1929848 :     myTimePenalty(0.),
      90      1929848 :     myAmDelayed(false),
      91      1929848 :     myAmRoundabout(false),
      92      1929848 :     myAmFringe(true),
      93      3859696 :     myBidiEdge(nullptr)
      94      1929848 : { }
      95              : 
      96              : 
      97      3372603 : MSEdge::~MSEdge() {
      98      1914492 :     delete myLaneChanger;
      99      1914492 :     delete myReversedRoutingEdge;
     100      1914492 :     delete myRailwayRoutingEdge;
     101     11030571 : }
     102              : 
     103              : 
     104              : void
     105      1810130 : MSEdge::initialize(const std::vector<MSLane*>* lanes) {
     106              :     assert(lanes != 0);
     107      1810130 :     myLanes = std::shared_ptr<const std::vector<MSLane*> >(lanes);
     108      1810130 :     if (myFunction == SumoXMLEdgeFunc::CONNECTOR) {
     109       182804 :         myCombinedPermissions = SVCAll;
     110              :     }
     111      3760394 :     for (MSLane* const lane : *lanes) {
     112      1950264 :         lane->setRightSideOnEdge(myWidth, (int)mySublaneSides.size());
     113      1950264 :         MSLeaderInfo ahead(lane->getWidth());
     114      4590386 :         for (int j = 0; j < ahead.numSublanes(); ++j) {
     115      2640122 :             mySublaneSides.push_back(myWidth + j * MSGlobals::gLateralResolution);
     116              :         }
     117      1950264 :         myWidth += lane->getWidth();
     118      1950264 :     }
     119      1810130 : }
     120              : 
     121              : 
     122      1709780 : void MSEdge::recalcCache() {
     123      1709780 :     if (myLanes->empty()) {
     124              :         return;
     125              :     }
     126      1709780 :     myLength = myLanes->front()->getLength();
     127      3419560 :     myEmptyTraveltime = myLength / MAX2(getSpeedLimit(), NUMERICAL_EPS);
     128      1709780 :     if (isNormal() && (MSGlobals::gUseMesoSim || MSGlobals::gTLSPenalty > 0)) {
     129              :         SUMOTime minorPenalty = 0;
     130       169171 :         bool haveTLSPenalty = MSGlobals::gTLSPenalty > 0;
     131       169171 :         if (MSGlobals::gUseMesoSim) {
     132       169056 :             const MESegment::MesoEdgeType& edgeType = MSNet::getInstance()->getMesoType(getEdgeType());
     133       169056 :             minorPenalty = edgeType.minorPenalty;
     134       169056 :             haveTLSPenalty = edgeType.tlsPenalty > 0;
     135              :         }
     136       169171 :         if (haveTLSPenalty || minorPenalty > 0) {
     137              :             // add tls penalties to the minimum travel time
     138              :             SUMOTime minPenalty = -1;
     139         2555 :             for (const MSLane* const l : *myLanes) {
     140         4099 :                 for (const MSLink* const link : l->getLinkCont()) {
     141         2387 :                     if (link->getLane()->isWalkingArea() && link->getLaneBefore()->isNormal()) {
     142           60 :                         continue;
     143              :                     }
     144         2327 :                     SUMOTime linkPenalty = link->isTLSControlled() ? link->getMesoTLSPenalty() : (link->havePriority() ? 0 : minorPenalty);
     145         2327 :                     if (minPenalty == -1) {
     146              :                         minPenalty = linkPenalty;
     147              :                     } else {
     148              :                         minPenalty = MIN2(minPenalty, linkPenalty);
     149              :                     }
     150              :                 }
     151              :             }
     152          843 :             if (minPenalty > 0) {
     153          285 :                 myEmptyTraveltime += STEPS2TIME(minPenalty);
     154          285 :                 myTimePenalty = STEPS2TIME(minPenalty);
     155              :             }
     156              :         }
     157      1540609 :     } else if (isCrossing() && MSGlobals::gTLSPenalty > 0) {
     158              :         // penalties are recorded for the entering link
     159           80 :         for (const auto& ili : myLanes->front()->getIncomingLanes()) {
     160           40 :             double penalty = STEPS2TIME(ili.viaLink->getMesoTLSPenalty());
     161           40 :             if (!ili.viaLink->haveOffPriority()) {
     162            0 :                 penalty = MAX2(penalty, MSGlobals::gMinorPenalty);
     163              :             }
     164           40 :             if (penalty > 0) {
     165           20 :                 myEmptyTraveltime += penalty;
     166           20 :                 myTimePenalty = penalty;
     167              :             }
     168              :         }
     169      1540569 :     } else if (isInternal() && MSGlobals::gUsingInternalLanes) {
     170       703155 :         const MSLink* link = myLanes->front()->getIncomingLanes()[0].viaLink;
     171       703155 :         if (!link->isTLSControlled() && !link->havePriority()) {
     172       343837 :             if (link->isTurnaround()) {
     173       128961 :                 myEmptyTraveltime += MSGlobals::gTurnaroundPenalty;
     174       128961 :                 myTimePenalty = MSGlobals::gTurnaroundPenalty;
     175              :             } else {
     176       214876 :                 myEmptyTraveltime += MSGlobals::gMinorPenalty;
     177       214876 :                 myTimePenalty = MSGlobals::gMinorPenalty;
     178              :             }
     179              :         }
     180              :     }
     181              : }
     182              : 
     183              : 
     184              : void
     185           42 : MSEdge::resetTAZ(MSJunction* junction) {
     186              :     mySuccessors.clear();
     187              :     myPredecessors.clear();
     188          728 :     for (const MSEdge* edge : junction->getIncoming()) {
     189          686 :         if (!edge->isInternal()) {
     190          126 :             MSEdgeVector& succ = const_cast<MSEdgeVector&>(edge->mySuccessors);
     191              :             MSConstEdgePairVector& succVia = const_cast<MSConstEdgePairVector&>(edge->myViaSuccessors);
     192          126 :             MSEdgeVector& pred = const_cast<MSEdgeVector&>(edge->myPredecessors);
     193          126 :             auto it = std::find(succ.begin(), succ.end(), this);
     194          126 :             auto it2 = std::find(succVia.begin(), succVia.end(), std::make_pair(const_cast<const MSEdge*>(this), (const MSEdge*)nullptr));
     195          126 :             auto it3 = std::find(pred.begin(), pred.end(), this);
     196          126 :             if (it != succ.end()) {
     197              :                 succ.erase(it);
     198              :                 succVia.erase(it2);
     199              :             }
     200          126 :             if (it3 != pred.end()) {
     201              :                 pred.erase(it3);
     202              :             }
     203              :         }
     204              :     }
     205           42 : }
     206              : 
     207              : void
     208      1624808 : MSEdge::closeBuilding() {
     209      3572131 :     for (MSLane* const lane : *myLanes) {
     210      4463799 :         for (MSLink* const link : lane->getLinkCont()) {
     211      2516476 :             link->initParallelLinks();
     212              :             MSLane* const toL = link->getLane();
     213              :             MSLane* const viaL = link->getViaLane();
     214      2516476 :             if (toL != nullptr) {
     215              :                 MSEdge& to = toL->getEdge();
     216      2516476 :                 if (std::find(mySuccessors.begin(), mySuccessors.end(), &to) == mySuccessors.end()) {
     217      2344382 :                     mySuccessors.push_back(&to);
     218      4688764 :                     myViaSuccessors.push_back(std::make_pair(&to, (viaL == nullptr ? nullptr : &viaL->getEdge())));
     219              :                 }
     220      2516476 :                 if (std::find(to.myPredecessors.begin(), to.myPredecessors.end(), this) == to.myPredecessors.end()) {
     221      2344382 :                     to.myPredecessors.push_back(this);
     222              :                 }
     223      2516476 :                 if (link->getDirection() != LinkDirection::TURN) {
     224      1952835 :                     myAmFringe = false;
     225              :                 }
     226              :             }
     227      2516476 :             if (viaL != nullptr) {
     228              :                 MSEdge& to = viaL->getEdge();
     229       767979 :                 if (std::find(to.myPredecessors.begin(), to.myPredecessors.end(), this) == to.myPredecessors.end()) {
     230       702972 :                     to.myPredecessors.push_back(this);
     231              :                 }
     232              :             }
     233              :         }
     234      1947323 :         lane->checkBufferType();
     235              :     }
     236      1624808 :     std::sort(mySuccessors.begin(), mySuccessors.end(), by_id_sorter());
     237      1624808 :     rebuildAllowedLanes(true);
     238      1624808 :     recalcCache();
     239              : 
     240              :     // extend lookup table for sublane model after all edges are read
     241      1624808 :     if (myLanes->back()->getOpposite() != nullptr) {
     242         7556 :         MSLane* opposite = myLanes->back()->getOpposite();
     243         7556 :         MSLeaderInfo ahead(opposite->getWidth());
     244        21280 :         for (int j = 0; j < ahead.numSublanes(); ++j) {
     245        13724 :             mySublaneSides.push_back(myWidth + j * MSGlobals::gLateralResolution);
     246              :         }
     247         7556 :     }
     248      1624808 : }
     249              : 
     250              : 
     251              : void
     252          613 : MSEdge::updateMesoType() {
     253              :     assert(MSGlobals::gUseMesoSim);
     254          613 :     if (!myLanes->empty()) {
     255          613 :         MSGlobals::gMesoNet->updateSegmentsForEdge(*this);
     256              :     }
     257          613 : }
     258              : 
     259              : 
     260              : void
     261      1624808 : MSEdge::buildLaneChanger() {
     262      1624808 :     if (!myLanes->empty()) {
     263      1624808 :         const bool allowChanging = allowsLaneChanging();
     264      1624808 :         if (MSGlobals::gLateralResolution > 0) {
     265              :             // may always initiate sublane-change
     266       176353 :             if (!isInternal() || MSGlobals::gUsingInternalLanes) {
     267       176162 :                 myLaneChanger = new MSLaneChangerSublane(myLanes.get(), allowChanging);
     268              :             }
     269              :         } else {
     270      1448455 :             if (MSGlobals::gLaneChangeDuration > 0) {
     271         3717 :                 myLaneChanger = new MSLaneChanger(myLanes.get(), allowChanging);
     272      1444738 :             } else if (myLanes->size() > 1 || canChangeToOpposite()) {
     273       223808 :                 myLaneChanger = new MSLaneChanger(myLanes.get(), allowChanging);
     274              :             }
     275              :         }
     276              :     }
     277      1624808 : }
     278              : 
     279              : 
     280              : bool
     281      1624808 : MSEdge::allowsLaneChanging() const {
     282      1624808 :     if (isInternal() && MSGlobals::gUsingInternalLanes) {
     283              :         // allow changing only if all links leading to this internal lane have priority
     284              :         // or they are controlled by a traffic light
     285      1123924 :         for (const MSLane* const lane : *myLanes) {
     286       765050 :             const MSLink* const link = lane->getLogicalPredecessorLane()->getLinkTo(lane);
     287              :             assert(link != nullptr);
     288              :             const LinkState state = link->getState();
     289       334607 :             if ((state == LINKSTATE_MINOR && lane->getBidiLane() == nullptr)
     290       430679 :                     || state == LINKSTATE_EQUAL
     291       430679 :                     || state == LINKSTATE_STOP
     292              :                     || state == LINKSTATE_ALLWAY_STOP
     293       765050 :                     || state == LINKSTATE_DEADEND) {
     294              :                 return false;
     295              :             }
     296              :         }
     297              :     }
     298              :     return true;
     299              : }
     300              : 
     301              : 
     302              : void
     303     15858994 : MSEdge::addToAllowed(const SVCPermissions permissions, std::shared_ptr<const std::vector<MSLane*> > allowedLanes, AllowedLanesCont& laneCont) const {
     304     15858994 :     if (!allowedLanes->empty()) {
     305              :         // recheck whether we had this list to save memory
     306     16054367 :         for (auto& allowed : laneCont) {
     307     15178643 :             if (*allowed.second == *allowedLanes) {
     308     11474524 :                 allowed.first |= permissions;
     309              :                 return;
     310              :             }
     311              :         }
     312       875724 :         laneCont.push_back(std::make_pair(permissions, allowedLanes));
     313              :     }
     314              : }
     315              : 
     316              : 
     317              : SVCPermissions
     318      2688097 : MSEdge::getMesoPermissions(SVCPermissions p, SVCPermissions ignoreIgnored) {
     319      2688097 :     SVCPermissions ignored = myMesoIgnoredVClasses & ~ignoreIgnored;
     320      2688097 :     return (p | ignored) == ignored ? 0 : p;
     321              : }
     322              : 
     323              : 
     324              : void
     325      1626204 : MSEdge::rebuildAllowedLanes(const bool onInit, bool updateVehicles) {
     326              :     // rebuild myMinimumPermissions and myCombinedPermissions
     327      1626204 :     myMinimumPermissions = SVCAll;
     328      1626204 :     myCombinedPermissions = 0;
     329              :     bool lanesChangedPermission = false;
     330      3575439 :     for (MSLane* const lane : *myLanes) {
     331              :         // same dedicated lanes are ignored in meso to avoid capacity errors.
     332              :         // Here we have to make sure that vehicles which are set to depart on
     333              :         // such lanes trigger an error.
     334      1949235 :         SVCPermissions allow = getMesoPermissions(lane->getPermissions(), SVC_PEDESTRIAN);
     335      1949235 :         myMinimumPermissions &= allow;
     336      1949235 :         myCombinedPermissions |= allow;
     337      1949235 :         lanesChangedPermission |= lane->hadPermissionChanges();
     338              :     }
     339      1626204 :     if (!onInit && !myHaveTransientPermissions && lanesChangedPermission) {
     340          965 :         myHaveTransientPermissions = true;
     341              :         // backup original structures when first needed
     342          965 :         myOrigAllowed = myAllowed;
     343              :         myOrigAllowedTargets = myAllowedTargets;
     344              :         myOrigClassesViaSuccessorMap = myClassesViaSuccessorMap;
     345              :     }
     346              :     // rebuild myAllowed
     347              :     myAllowed.clear();
     348      1626204 :     if (myCombinedPermissions != myMinimumPermissions) {
     349       143388 :         myAllowed.push_back(std::make_pair(SVC_IGNORING, myLanes));
     350      4875192 :         for (SVCPermissions vclass = SVC_PRIVATE; vclass <= SUMOVehicleClass_MAX; vclass *= 2) {
     351      4731804 :             if ((myCombinedPermissions & vclass) == vclass) {
     352              :                 std::shared_ptr<std::vector<MSLane*> > allowedLanes = std::make_shared<std::vector<MSLane*> >();
     353     10163717 :                 for (MSLane* const lane : *myLanes) {
     354      6904666 :                     if (lane->allowsVehicleClass((SUMOVehicleClass)vclass)) {
     355      3482458 :                         allowedLanes->push_back(lane);
     356              :                     }
     357              :                 }
     358      6518102 :                 addToAllowed(vclass, allowedLanes, myAllowed);
     359              :             }
     360              :         }
     361              :     }
     362      1626204 :     if (onInit) {
     363      1624808 :         myOriginalMinimumPermissions = myMinimumPermissions;
     364      1624808 :         myOriginalCombinedPermissions = myCombinedPermissions;
     365              :     } else {
     366         1396 :         rebuildAllowedTargets(updateVehicles);
     367         3558 :         for (MSEdge* pred : myPredecessors) {
     368         2162 :             if (myHaveTransientPermissions && !pred->myHaveTransientPermissions) {
     369         1349 :                 pred->myOrigAllowed = pred->myAllowed;
     370              :                 pred->myOrigAllowedTargets = pred->myAllowedTargets;
     371              :                 pred->myOrigClassesViaSuccessorMap = pred->myClassesViaSuccessorMap;
     372         1349 :                 pred->myHaveTransientPermissions = true;
     373              :             }
     374         2162 :             pred->rebuildAllowedTargets(updateVehicles);
     375              :         }
     376         1396 :         if (MSGlobals::gUseMesoSim) {
     377         2182 :             for (MESegment* s = MSGlobals::gMesoNet->getSegmentForEdge(*this); s != nullptr; s = s->getNextSegment()) {
     378         1824 :                 s->updatePermissions();
     379              :             }
     380              :         }
     381              :     }
     382      1626204 : }
     383              : 
     384              : 
     385              : void
     386      1629323 : MSEdge::rebuildAllowedTargets(const bool updateVehicles) {
     387              :     myAllowedTargets.clear();
     388      3980414 :     for (const MSEdge* target : mySuccessors) {
     389              :         bool universalMap = true; // whether the mapping for SVC_IGNORING is also valid for all vehicle classes
     390              :         std::shared_ptr<std::vector<MSLane*> > allLanes = std::make_shared<std::vector<MSLane*> >();
     391              :         // compute the mapping for SVC_IGNORING
     392      5357972 :         for (MSLane* const lane : *myLanes) {
     393              :             SVCPermissions combinedTargetPermissions = 0;
     394      8772500 :             for (const MSLink* const link : lane->getLinkCont()) {
     395      5765619 :                 if (&link->getLane()->getEdge() == target) {
     396      2524134 :                     allLanes->push_back(lane);
     397      2524134 :                     combinedTargetPermissions |= link->getLane()->getPermissions();
     398      2524134 :                     if (link->getViaLane() != nullptr &&
     399       770146 :                             ((lane->getPermissions() & link->getLane()->getPermissions()) != link->getViaLane()->getPermissions())) {
     400              :                         // custom connection permissions
     401              :                         universalMap = false;
     402              :                     }
     403              :                 }
     404              :             }
     405      3006881 :             if (combinedTargetPermissions == 0 || (lane->getPermissions() & combinedTargetPermissions) != lane->getPermissions()) {
     406              :                 universalMap = false;
     407              :             }
     408              :         }
     409      2351091 :         if (universalMap) {
     410      1917632 :             if (myAllowed.empty()) {
     411              :                 // we have no lane specific permissions
     412      3779722 :                 myAllowedTargets[target].push_back(std::make_pair(myMinimumPermissions, myLanes));
     413              :             } else {
     414       109085 :                 for (const auto& i : myAllowed) {
     415       243942 :                     addToAllowed(i.first, i.second, myAllowedTargets[target]);
     416              :                 }
     417              :             }
     418              :         } else {
     419       866918 :             addToAllowed(SVC_IGNORING, allLanes, myAllowedTargets[target]);
     420              :             // compute the vclass specific mapping
     421     14737606 :             for (SVCPermissions vclass = SVC_PRIVATE; vclass <= SUMOVehicleClass_MAX; vclass *= 2) {
     422     14304147 :                 if ((myCombinedPermissions & vclass) == vclass) {
     423              :                     std::shared_ptr<std::vector<MSLane*> > allowedLanes = std::make_shared<std::vector<MSLane*> >();
     424     37662458 :                     for (MSLane* const lane : *myLanes) {
     425     25577288 :                         if (lane->allowsVehicleClass((SUMOVehicleClass)vclass)) {
     426     49432829 :                             for (const MSLink* const link : lane->getLinkCont()) {
     427     32352031 :                                 if (link->getLane()->allowsVehicleClass((SUMOVehicleClass)vclass) && &link->getLane()->getEdge() == target && (link->getViaLane() == nullptr || link->getViaLane()->allowsVehicleClass((SUMOVehicleClass)vclass))) {
     428      8935310 :                                     allowedLanes->push_back(lane);
     429              :                                 }
     430              :                             }
     431              :                         }
     432              :                     }
     433     36255510 :                     addToAllowed(vclass, allowedLanes, myAllowedTargets[target]);
     434              :                 }
     435              :             }
     436              :         }
     437              :     }
     438      1629323 :     if (updateVehicles) {
     439         2935 :         for (const MSLane* const lane : *myLanes) {
     440         1731 :             const MSLane::VehCont& vehs = lane->getVehiclesSecure();
     441         4391 :             for (MSVehicle* veh : vehs) {
     442         2660 :                 veh->updateBestLanes(true);
     443              :             }
     444         1731 :             lane->releaseVehicles();
     445              :         }
     446              :     }
     447              :     myClassesSuccessorMap.clear();
     448      1629323 : }
     449              : 
     450              : 
     451              : // ------------ Access to the edge's lanes
     452              : MSLane*
     453          870 : MSEdge::leftLane(const MSLane* const lane) const {
     454          870 :     return parallelLane(lane, 1);
     455              : }
     456              : 
     457              : 
     458              : MSLane*
     459          448 : MSEdge::rightLane(const MSLane* const lane) const {
     460          448 :     return parallelLane(lane, -1);
     461              : }
     462              : 
     463              : 
     464              : MSLane*
     465     85491855 : MSEdge::parallelLane(const MSLane* const lane, int offset, bool includeOpposite) const {
     466     85491855 :     const int resultIndex = lane->getIndex() + offset;
     467     85491855 :     if (resultIndex >= getNumLanes() && includeOpposite) {
     468     20211099 :         const MSEdge* opposite = getOppositeEdge();
     469     20211099 :         if (opposite != nullptr && resultIndex < getNumLanes() + opposite->getNumLanes()) {
     470      1391308 :             return opposite->getLanes()[opposite->getNumLanes() + getNumLanes() - resultIndex - 1];
     471              :         }
     472              :         return nullptr;
     473     65280756 :     } else if (resultIndex >= (int)myLanes->size() || resultIndex < 0) {
     474              :         return nullptr;
     475              :     } else {
     476     43169471 :         return (*myLanes)[resultIndex];
     477              :     }
     478              : }
     479              : 
     480              : 
     481              : const std::vector<MSLane*>*
     482     75869162 : MSEdge::allowedLanes(const MSEdge& destination, SUMOVehicleClass vclass, bool ignoreTransientPermissions) const {
     483     75869162 :     const auto& targets = ignoreTransientPermissions && myHaveTransientPermissions ? myOrigAllowedTargets : myAllowedTargets;
     484              :     AllowedLanesByTarget::const_iterator i = targets.find(&destination);
     485     75869162 :     if (i != targets.end()) {
     486     75879699 :         for (const auto& allowed : i->second) {
     487     75772282 :             if ((allowed.first & vclass) == vclass) {
     488              :                 return allowed.second.get();
     489              :             }
     490              :         }
     491              :     }
     492              :     return nullptr;
     493              : }
     494              : 
     495              : 
     496              : const std::vector<MSLane*>*
     497   2510015478 : MSEdge::allowedLanes(SUMOVehicleClass vclass) const {
     498   2510015478 :     if ((myMinimumPermissions & vclass) == vclass) {
     499    665170041 :         return myLanes.get();
     500              :     } else {
     501   1844845437 :         if ((myCombinedPermissions & vclass) == vclass) {
     502   3695385523 :             for (const auto& allowed : myAllowed) {
     503   3695385523 :                 if ((allowed.first & vclass) == vclass) {
     504              :                     return allowed.second.get();
     505              :                 }
     506              :             }
     507              :         }
     508         2067 :         return nullptr;
     509              :     }
     510              : }
     511              : 
     512              : 
     513              : // ------------
     514              : SUMOTime
     515          595 : MSEdge::incVaporization(SUMOTime) {
     516          595 :     ++myVaporizationRequests;
     517          595 :     return 0;
     518              : }
     519              : 
     520              : 
     521              : SUMOTime
     522           43 : MSEdge::decVaporization(SUMOTime) {
     523           43 :     --myVaporizationRequests;
     524           43 :     return 0;
     525              : }
     526              : 
     527              : 
     528              : MSLane*
     529    105882361 : MSEdge::getFreeLane(const std::vector<MSLane*>* allowed, const SUMOVehicleClass vclass, double departPos) const {
     530    105882361 :     if (allowed == nullptr) {
     531     71666610 :         allowed = allowedLanes(vclass);
     532              :     }
     533              :     MSLane* res = nullptr;
     534     71666610 :     if (allowed != nullptr) {
     535              :         double largestGap = 0;
     536              :         MSLane* resByGap = nullptr;
     537              :         double leastOccupancy = std::numeric_limits<double>::max();
     538    237679589 :         for (std::vector<MSLane*>::const_iterator i = allowed->begin(); i != allowed->end(); ++i) {
     539    131799209 :             const double occupancy = (*i)->getBruttoOccupancy();
     540    131799209 :             if (occupancy < leastOccupancy) {
     541    115423355 :                 res = (*i);
     542              :                 leastOccupancy = occupancy;
     543              :             }
     544    131799209 :             const MSVehicle* last = (*i)->getLastFullVehicle();
     545    131799209 :             const double lastGap = (last != nullptr ? last->getPositionOnLane() : myLength) - departPos;
     546    131799209 :             if (lastGap > largestGap) {
     547              :                 largestGap = lastGap;
     548     59817669 :                 resByGap = (*i);
     549              :             }
     550              :         }
     551    105880380 :         if (resByGap != nullptr) {
     552              :             //if (res != resByGap) std::cout << SIMTIME << " edge=" << getID() << " departPos=" << departPos << " res=" << Named::getIDSecure(res) << " resByGap=" << Named::getIDSecure(resByGap) << " largestGap=" << largestGap << "\n";
     553              :             res = resByGap;
     554              :         }
     555              :     }
     556    105882361 :     return res;
     557              : }
     558              : 
     559              : 
     560              : MSLane*
     561      3267458 : MSEdge::getProbableLane(const std::vector<MSLane*>* allowed, const SUMOVehicleClass vclass, double departPos, double maxSpeed) const {
     562      3267458 :     if (allowed == nullptr) {
     563            0 :         allowed = allowedLanes(vclass);
     564              :     }
     565              :     MSLane* res = nullptr;
     566            0 :     if (allowed != nullptr) {
     567              :         double largestGap = 0;
     568              :         double largestSpeed = 0;
     569              :         MSLane* resByGap = nullptr;
     570              :         double leastOccupancy = std::numeric_limits<double>::max();
     571              :         int aIndex = 0;
     572     11511999 :         for (std::vector<MSLane*>::const_iterator i = allowed->begin(); i != allowed->end(); ++i, aIndex++) {
     573      8244541 :             const double occupancy = (*i)->getBruttoOccupancy();
     574      8244541 :             if (occupancy < leastOccupancy) {
     575      7552371 :                 res = (*i);
     576              :                 leastOccupancy = occupancy;
     577              :             }
     578      8244541 :             const MSVehicle* last = (*i)->getLastFullVehicle();
     579      8244541 :             double lastGap = (last != nullptr ? last->getPositionOnLane() : myLength) - departPos;
     580              :             // never insert to the left of a vehicle with a larger speedFactor
     581      8244541 :             if (lastGap > largestGap && maxSpeed >= largestSpeed) {
     582              :                 largestGap = lastGap;
     583      4450922 :                 resByGap = (*i);
     584              :             }
     585      8244541 :             if (last != nullptr) {
     586      8243633 :                 largestSpeed = MAX2(largestSpeed, getVehicleMaxSpeed(last));
     587              :             }
     588              :         }
     589      3267458 :         if (resByGap != nullptr) {
     590              :             //if (res != resByGap) std::cout << SIMTIME << " edge=" << getID() << " departPos=" << departPos << " res=" << Named::getIDSecure(res) << " resByGap=" << Named::getIDSecure(resByGap) << " largestGap=" << largestGap << "\n";
     591              :             res = resByGap;
     592              :         }
     593              :     }
     594      3267458 :     return res;
     595              : }
     596              : 
     597              : 
     598              : double
     599    109227479 : MSEdge::getDepartPosBound(const MSVehicle& veh, bool upper) const {
     600    109227479 :     const SUMOVehicleParameter& pars = veh.getParameter();
     601              :     double pos = getLength();
     602              :     // determine the position
     603    109227479 :     switch (pars.departPosProcedure) {
     604      1784659 :         case DepartPosDefinition::GIVEN:
     605      1784659 :             pos = pars.departPos;
     606      1784659 :             if (pos < 0.) {
     607      1705997 :                 pos += myLength;
     608              :             }
     609              :             break;
     610              :         case DepartPosDefinition::RANDOM:
     611              :             // could be any position on the edge
     612              :             break;
     613              :         case DepartPosDefinition::RANDOM_FREE:
     614              :             // could be any position on the edge due to multiple random attempts
     615              :             break;
     616              :         case DepartPosDefinition::FREE:
     617              :             // many candidate positions, upper bound could be computed exactly
     618              :             // with much effort
     619              :             break;
     620       315848 :         case DepartPosDefinition::LAST:
     621       315848 :             if (upper) {
     622       472974 :                 for (std::vector<MSLane*>::const_iterator i = myLanes->begin(); i != myLanes->end(); ++i) {
     623       321528 :                     MSVehicle* last = (*i)->getLastFullVehicle();
     624       321528 :                     if (last != nullptr) {
     625       278494 :                         pos = MIN2(pos, last->getPositionOnLane());
     626              :                     }
     627              :                 }
     628              :             } else {
     629              :                 pos = 0;
     630              :             }
     631              :             break;
     632     53209351 :         case DepartPosDefinition::BASE:
     633              :         case DepartPosDefinition::DEFAULT:
     634     53209351 :             if (!upper) {
     635              :                 pos = 0;
     636              :             }
     637              :             break;
     638           20 :         default:
     639           20 :             pos = MIN2(pos, veh.getVehicleType().getLength());
     640              :             break;
     641              :     }
     642    109227479 :     return pos;
     643              : }
     644              : 
     645              : MSLane*
     646           42 : MSEdge::getDepartLaneMeso(SUMOVehicle& veh) const {
     647           42 :     if (veh.getParameter().departLaneProcedure == DepartLaneDefinition::GIVEN) {
     648            2 :         if ((int) myLanes->size() <= veh.getParameter().departLane || !(*myLanes)[veh.getParameter().departLane]->allowsVehicleClass(veh.getVehicleType().getVehicleClass())) {
     649            0 :             return nullptr;
     650              :         }
     651            2 :         return (*myLanes)[veh.getParameter().departLane];
     652              :     }
     653           40 :     return (*myLanes)[0];
     654              : }
     655              : 
     656              : MSLane*
     657   2372827589 : MSEdge::getDepartLane(MSVehicle& veh) const {
     658   2372827589 :     DepartLaneDefinition dld = veh.getParameter().departLaneProcedure;
     659   2372827589 :     int departLane = veh.getParameter().departLane;
     660   2372827589 :     if (dld == DepartLaneDefinition::DEFAULT) {
     661   2077255826 :         dld = myDefaultDepartLaneDefinition;
     662   2077255826 :         departLane = myDefaultDepartLane;
     663              :     }
     664   2372827589 :     switch (dld) {
     665    100920319 :         case DepartLaneDefinition::GIVEN:
     666    100920319 :             if ((int) myLanes->size() <= departLane || !(*myLanes)[departLane]->allowsVehicleClass(veh.getVehicleType().getVehicleClass())) {
     667           61 :                 return nullptr;
     668              :             }
     669    100920258 :             return (*myLanes)[departLane];
     670     81664132 :         case DepartLaneDefinition::RANDOM:
     671    163328264 :             return RandHelper::getRandomFrom(*allowedLanes(veh.getVehicleType().getVehicleClass()));
     672     71569532 :         case DepartLaneDefinition::FREE:
     673     71569532 :             return getFreeLane(nullptr, veh.getVehicleType().getVehicleClass(), getDepartPosBound(veh, false));
     674      5484616 :         case DepartLaneDefinition::ALLOWED_FREE:
     675      5484616 :             if (veh.getRoute().size() == 1) {
     676         5494 :                 return getFreeLane(nullptr, veh.getVehicleType().getVehicleClass(), getDepartPosBound(veh, false));
     677              :             } else {
     678      5479122 :                 return getFreeLane(allowedLanes(**(veh.getRoute().begin() + 1), veh.getVehicleType().getVehicleClass()), veh.getVehicleType().getVehicleClass(), getDepartPosBound(veh, false));
     679              :             }
     680     31809373 :         case DepartLaneDefinition::BEST_FREE:
     681              :         case DepartLaneDefinition::BEST_PROB: {
     682     31809373 :             veh.updateBestLanes(false, myLanes->front());
     683     31809373 :             const std::vector<MSVehicle::LaneQ>& bl = veh.getBestLanes();
     684              :             double bestLength = -1;
     685    100720314 :             for (std::vector<MSVehicle::LaneQ>::const_iterator i = bl.begin(); i != bl.end(); ++i) {
     686     68910941 :                 if ((*i).length > bestLength) {
     687              :                     bestLength = (*i).length;
     688              :                 }
     689              :             }
     690              :             // beyond a certain length, all lanes are suitable
     691              :             // however, we still need to check departPos to avoid unsuitable insertion
     692              :             // (this is only possible in some cases)
     693              :             double departPos = 0;
     694     31809373 :             if (bestLength > BEST_LANE_LOOKAHEAD) {
     695       363958 :                 departPos = getDepartPosBound(veh);
     696       363958 :                 bestLength = MIN2(bestLength - departPos, BEST_LANE_LOOKAHEAD);
     697              :             }
     698     31809373 :             std::vector<MSLane*>* bestLanes = new std::vector<MSLane*>();
     699    100720314 :             for (std::vector<MSVehicle::LaneQ>::const_iterator i = bl.begin(); i != bl.end(); ++i) {
     700     68910941 :                 if (((*i).length - departPos) >= bestLength) {
     701     39425658 :                     if (isInternal()) {
     702           32 :                         for (MSLane* lane : *myLanes) {
     703           20 :                             if (lane->getNormalSuccessorLane() == (*i).lane) {
     704           12 :                                 bestLanes->push_back(lane);
     705              :                             }
     706              :                         }
     707              :                     } else {
     708     39425646 :                         bestLanes->push_back((*i).lane);
     709              :                     }
     710              :                 }
     711              :             }
     712              :             MSLane* ret = nullptr;
     713     31809373 :             if (veh.getParameter().departLaneProcedure == DepartLaneDefinition::BEST_FREE) {
     714     28541915 :                 ret = getFreeLane(bestLanes, veh.getVehicleType().getVehicleClass(), getDepartPosBound(veh, false));
     715              :             } else {
     716      3267458 :                 ret = getProbableLane(bestLanes, veh.getVehicleType().getVehicleClass(), getDepartPosBound(veh, false), getVehicleMaxSpeed(&veh));
     717              :             }
     718     31809373 :             delete bestLanes;
     719     31809373 :             return ret;
     720              :         }
     721   2081379617 :         case DepartLaneDefinition::DEFAULT:
     722              :         case DepartLaneDefinition::FIRST_ALLOWED:
     723   2081379617 :             return getFirstAllowed(veh.getVehicleType().getVehicleClass());
     724              :         default:
     725              :             break;
     726              :     }
     727            0 :     if (!(*myLanes)[0]->allowsVehicleClass(veh.getVehicleType().getVehicleClass())) {
     728              :         return nullptr;
     729              :     }
     730            0 :     return (*myLanes)[0];
     731              : }
     732              : 
     733              : 
     734              : MSLane*
     735   2082105608 : MSEdge::getFirstAllowed(SUMOVehicleClass vClass, bool defaultFirst, int routingMode) const {
     736   3647653242 :     for (std::vector<MSLane*>::const_iterator i = myLanes->begin(); i != myLanes->end(); ++i) {
     737   3647653242 :         if ((*i)->allowsVehicleClass(vClass, routingMode)) {
     738   2082105608 :             return *i;
     739              :         }
     740              :     }
     741            0 :     return defaultFirst && !myLanes->empty() ? myLanes->front() : nullptr;
     742              : }
     743              : 
     744              : 
     745              : bool
     746   2909083847 : MSEdge::validateDepartSpeed(SUMOVehicle& v) const {
     747   2909083847 :     const SUMOVehicleParameter& pars = v.getParameter();
     748   2909083847 :     const MSVehicleType& type = v.getVehicleType();
     749   2909083847 :     if (pars.departSpeedProcedure == DepartSpeedDefinition::GIVEN) {
     750              :         // departSpeed could have been rounded down in the output
     751    118356741 :         double vMax = getVehicleMaxSpeed(&v) + SPEED_EPS;
     752    118356741 :         if (pars.departSpeed > vMax) {
     753              :             // check departLane (getVehicleMaxSpeed checks lane 0)
     754        22599 :             MSLane* departLane = MSGlobals::gMesoNet ? getDepartLaneMeso(v) : getDepartLane(dynamic_cast<MSVehicle&>(v));
     755        22599 :             if (departLane != nullptr) {
     756        22599 :                 vMax = departLane->getVehicleMaxSpeed(&v);
     757        22599 :                 if (pars.wasSet(VEHPARS_SPEEDFACTOR_SET)) {
     758              :                     // speedFactor could have been rounded down in the output
     759            7 :                     vMax *= (1 + SPEED_EPS);
     760              :                 }
     761              :                 // additive term must come after multiplication!
     762        22599 :                 vMax += SPEED_EPS;
     763        22599 :                 if (pars.departSpeed > vMax) {
     764        22585 :                     if (type.getSpeedFactor().getParameter(1) > 0.) {
     765        45132 :                         v.setChosenSpeedFactor(type.computeChosenSpeedDeviation(nullptr, pars.departSpeed / MIN2(getSpeedLimit(), type.getDesiredMaxSpeed() - SPEED_EPS)));
     766        22566 :                         if (v.getChosenSpeedFactor() > type.getSpeedFactor().getParameter(0) + 2 * type.getSpeedFactor().getParameter(1)) {
     767              :                             // only warn for significant deviation
     768        37156 :                             WRITE_WARNINGF(TL("Choosing new speed factor % for vehicle '%' to match departure speed % (max %)."),
     769              :                                            toString(v.getChosenSpeedFactor()), pars.id, pars.departSpeed, vMax);
     770              :                         }
     771              :                     } else {
     772              :                         return false;
     773              :                     }
     774              :                 }
     775              :             }
     776              :         }
     777              :     }
     778              :     return true;
     779              : }
     780              : 
     781              : 
     782              : bool
     783   2909674361 : MSEdge::insertVehicle(SUMOVehicle& v, SUMOTime time, const bool checkOnly, const bool forceCheck) const {
     784              :     // when vaporizing, no vehicles are inserted, but checking needs to be successful to trigger removal
     785   2909644358 :     if (isVaporizing() || isTazConnector()
     786   5818735550 :             || v.getRouteValidity(true, checkOnly) != MSBaseVehicle::ROUTE_VALID) {
     787       613239 :         return checkOnly;
     788              :     }
     789   2909060937 :     const SUMOVehicleParameter& pars = v.getParameter();
     790   2909060937 :     if (!validateDepartSpeed(v)) {
     791           14 :         if (MSGlobals::gCheckRoutes) {
     792           21 :             throw ProcessError(TLF("Departure speed for vehicle '%' is too high for the departure edge '%', time=%.",
     793           21 :                                    pars.id, getID(), time2string(time)));
     794              :         } else {
     795           21 :             WRITE_WARNINGF(TL("Departure speed for vehicle '%' is too high for the departure edge '%', time=%."),
     796              :                            pars.id, getID(), time2string(time));
     797              :         }
     798              :     }
     799   2909060930 :     if (MSGlobals::gUseMesoSim) {
     800    503469344 :         if (!forceCheck && myLastFailedInsertionTime == time) {
     801              :             return false;
     802              :         }
     803              :         double pos = 0.0;
     804     27974724 :         switch (pars.departPosProcedure) {
     805       573844 :             case DepartPosDefinition::GIVEN:
     806       573844 :                 if (pars.departPos >= 0.) {
     807              :                     pos = pars.departPos;
     808              :                 } else {
     809         7315 :                     pos = pars.departPos + getLength();
     810              :                 }
     811       573844 :                 if (pos < 0 || pos > getLength()) {
     812            6 :                     WRITE_WARNINGF(TL("Invalid departPos % given for vehicle '%', time=%. Inserting at lane end instead."),
     813              :                                    pos, v.getID(), time2string(time));
     814              :                     pos = getLength();
     815              :                 }
     816              :                 break;
     817              :             case DepartPosDefinition::RANDOM:
     818              :             case DepartPosDefinition::RANDOM_FREE:
     819              :                 pos = RandHelper::rand(getLength());
     820         6874 :                 break;
     821              :             default:
     822              :                 break;
     823              :         }
     824              :         bool result = false;
     825     27974724 :         MESegment* segment = MSGlobals::gMesoNet->getSegmentForEdge(*this, pos);
     826              :         MEVehicle* veh = static_cast<MEVehicle*>(&v);
     827              :         int qIdx;
     828     27974724 :         if (pars.departPosProcedure == DepartPosDefinition::FREE) {
     829       486418 :             while (segment != nullptr && !result) {
     830       447912 :                 if (checkOnly) {
     831            6 :                     result = segment->hasSpaceFor(veh, time, qIdx, true) == time;
     832              :                 } else {
     833       447906 :                     result = segment->initialise(veh, time);
     834              :                 }
     835              :                 segment = segment->getNextSegment();
     836              :             }
     837              :         } else {
     838     27936218 :             if (checkOnly) {
     839     26409865 :                 result = segment->hasSpaceFor(veh, time, qIdx, true) == time;
     840              :             } else {
     841      1526353 :                 result = segment->initialise(veh, time);
     842              :             }
     843              :         }
     844     27974721 :         return result;
     845              :     }
     846   2405591586 :     if (checkOnly) {
     847    742389491 :         switch (v.getParameter().departLaneProcedure) {
     848    659131138 :             case DepartLaneDefinition::GIVEN:
     849              :             case DepartLaneDefinition::DEFAULT:
     850              :             case DepartLaneDefinition::FIRST_ALLOWED: {
     851    659131138 :                 MSLane* insertionLane = getDepartLane(static_cast<MSVehicle&>(v));
     852    659131138 :                 if (insertionLane == nullptr) {
     853            0 :                     WRITE_WARNINGF(TL("Could not insert vehicle '%' on any lane of edge '%', time=%."),
     854              :                                    v.getID(), getID(), time2string(time));
     855            0 :                     return false;
     856              :                 }
     857    659131138 :                 const double occupancy = insertionLane->getBruttoOccupancy();
     858    659131138 :                 return (occupancy == 0 || occupancy * myLength + v.getVehicleType().getLengthWithGap() <= myLength ||
     859     12407160 :                         v.getParameter().departProcedure == DepartDefinition::SPLIT);
     860              :             }
     861     83258353 :             default:
     862    100847101 :                 for (std::vector<MSLane*>::const_iterator i = myLanes->begin(); i != myLanes->end(); ++i) {
     863     92611657 :                     const double occupancy = (*i)->getBruttoOccupancy();
     864     92611657 :                     if (occupancy == 0 || occupancy * myLength + v.getVehicleType().getLengthWithGap() <= myLength ||
     865     17588748 :                             v.getParameter().departProcedure == DepartDefinition::SPLIT) {
     866              :                         return true;
     867              :                     }
     868              :                 }
     869              :         }
     870              :         return false;
     871              :     }
     872   1663202095 :     MSLane* insertionLane = getDepartLane(static_cast<MSVehicle&>(v));
     873   1663202095 :     if (insertionLane == nullptr) {
     874              :         return false;
     875              :     }
     876              : 
     877   1663202095 :     if (!forceCheck) {
     878   1663201918 :         if (myLastFailedInsertionTime == time) {
     879              :             if (myFailedInsertionMemory.count(insertionLane->getIndex())) {
     880              :                 // A vehicle was already rejected for the proposed insertionLane in this timestep
     881              :                 return false;
     882              :             }
     883              :         } else {
     884              :             // last rejection occurred in a previous timestep, clear cache
     885              :             myFailedInsertionMemory.clear();
     886              :         }
     887              :     }
     888              : 
     889     11994034 :     bool success = insertionLane->insertVehicle(static_cast<MSVehicle&>(v));
     890              : 
     891     11994031 :     if (!success) {
     892              :         // constraints may enforce explicit re-ordering so we need to try other vehicles after failure
     893     17889202 :         if (!insertionLane->hasParameter("insertionOrder" + v.getID())) {
     894      8944454 :             myFailedInsertionMemory.insert(insertionLane->getIndex());
     895              :         }
     896              :     }
     897              :     return success;
     898              : }
     899              : 
     900              : 
     901              : void
     902     40721162 : MSEdge::changeLanes(SUMOTime t) const {
     903     40721162 :     if (myLaneChanger != nullptr) {
     904     40721162 :         myLaneChanger->laneChange(t);
     905              :     }
     906     40721162 : }
     907              : 
     908              : 
     909              : const MSEdge*
     910      2386574 : MSEdge::getInternalFollowingEdge(const MSEdge* followerAfterInternal, SUMOVehicleClass vClass) const {
     911              :     //@todo to be optimized
     912      2902301 :     for (const MSLane* const l : *myLanes) {
     913      3496880 :         for (const MSLink* const link : l->getLinkCont()) {
     914      2981153 :             if (&link->getLane()->getEdge() == followerAfterInternal) {
     915      2088881 :                 if (link->getViaLane() != nullptr) {
     916      1086202 :                     if (link->getViaLane()->allowsVehicleClass(vClass)) {
     917      1083385 :                         return &link->getViaLane()->getEdge();
     918              :                     } else {
     919         2817 :                         continue;
     920              :                     }
     921              :                 } else {
     922              :                     return nullptr; // network without internal links
     923              :                 }
     924              :             }
     925              :         }
     926              :     }
     927              :     return nullptr;
     928              : }
     929              : 
     930              : 
     931              : double
     932      1215440 : MSEdge::getInternalFollowingLengthTo(const MSEdge* followerAfterInternal, SUMOVehicleClass vClass) const {
     933              :     assert(followerAfterInternal != 0);
     934              :     assert(!followerAfterInternal->isInternal());
     935              :     double dist = 0.;
     936      1215440 :     const MSEdge* edge = getInternalFollowingEdge(followerAfterInternal, vClass);
     937              :     // Take into account non-internal lengths until next non-internal edge
     938      2237584 :     while (edge != nullptr && edge->isInternal()) {
     939      1022144 :         dist += edge->getLength();
     940      1022144 :         edge = edge->getInternalFollowingEdge(followerAfterInternal, vClass);
     941              :     }
     942      1215440 :     return dist;
     943              : }
     944              : 
     945              : 
     946              : const MSEdge*
     947       144815 : MSEdge::getNormalBefore() const {
     948              :     const MSEdge* result = this;
     949       153239 :     while (result->isInternal() && MSGlobals::gUsingInternalLanes) {
     950              :         assert(result->getPredecessors().size() == 1);
     951         8424 :         result = result->getPredecessors().front();
     952              :     }
     953       144815 :     return result;
     954              : }
     955              : 
     956              : const MSEdge*
     957      5141173 : MSEdge::getNormalSuccessor() const {
     958              :     const MSEdge* result = this;
     959      9645323 :     while (result->isInternal()) {
     960              :         assert(result->getSuccessors().size() == 1);
     961      4504150 :         result = result->getSuccessors().front();
     962              :     }
     963      5141173 :     return result;
     964              : }
     965              : 
     966              : double
     967    174035353 : MSEdge::getMeanSpeed() const {
     968              :     double v = 0;
     969              :     double totalNumVehs = 0;
     970    174035353 :     if (MSGlobals::gUseMesoSim) {
     971    161973248 :         for (MESegment* segment = MSGlobals::gMesoNet->getSegmentForEdge(*this); segment != nullptr; segment = segment->getNextSegment()) {
     972              :             const int numVehs = segment->getCarNumber();
     973    137521454 :             if (numVehs > 0) {
     974     23896118 :                 v += numVehs * segment->getMeanSpeed();
     975     23896118 :                 totalNumVehs += numVehs;
     976              :             }
     977              :         }
     978     24451794 :         if (totalNumVehs == 0) {
     979     16500691 :             return getLength() / myEmptyTraveltime; // may include tls-penalty
     980              :         }
     981              :     } else {
     982    350392068 :         for (const MSLane* const lane : *myLanes) {
     983              :             int numVehs = lane->getVehicleNumber();
     984    200808509 :             if (numVehs == 0) {
     985              :                 // take speed limit but with lowest possible weight
     986              :                 numVehs = 1;
     987              :             }
     988    200808509 :             v += numVehs * lane->getMeanSpeed();
     989    200808509 :             totalNumVehs += numVehs;
     990              :         }
     991    149583559 :         if (myBidiEdge != nullptr) {
     992      8335556 :             for (const MSLane* const lane : myBidiEdge->getLanes()) {
     993      4318606 :                 if (lane->getVehicleNumber() > 0) {
     994              :                     // do not route across edges which are already occupied in reverse direction
     995              :                     return 0;
     996              :                 }
     997              :             }
     998              :         }
     999    149282047 :         if (totalNumVehs == 0) {
    1000            0 :             return getSpeedLimit();
    1001              :         }
    1002              :     }
    1003    157233150 :     return v / totalNumVehs;
    1004              : }
    1005              : 
    1006              : 
    1007              : double
    1008            8 : MSEdge::getMeanFriction() const {
    1009              :     double f = 0.;
    1010           32 :     for (const MSLane* const lane : *myLanes) {
    1011           24 :         f += lane->getFrictionCoefficient();
    1012              :     }
    1013            8 :     if (!myLanes->empty()) {
    1014            8 :         return f / (double)myLanes->size();
    1015              :     }
    1016              :     return 1.;
    1017              : }
    1018              : 
    1019              : 
    1020              : double
    1021         1272 : MSEdge::getMeanSpeedBike() const {
    1022         1272 :     if (MSGlobals::gUseMesoSim) {
    1023              :         // no separate bicycle speeds in meso
    1024          362 :         return getMeanSpeed();
    1025              :     }
    1026              :     double v = 0;
    1027              :     double totalNumVehs = 0;
    1028         3005 :     for (const MSLane* const lane : *myLanes) {
    1029              :         const int numVehs = lane->getVehicleNumber();
    1030         2095 :         v += numVehs * lane->getMeanSpeedBike();
    1031         2095 :         totalNumVehs += numVehs;
    1032              :     }
    1033          910 :     if (totalNumVehs == 0) {
    1034          455 :         return getSpeedLimit();
    1035              :     }
    1036          455 :     return v / totalNumVehs;
    1037              : }
    1038              : 
    1039              : 
    1040              : double
    1041        55102 : MSEdge::getCurrentTravelTime(double minSpeed) const {
    1042              :     assert(minSpeed > 0);
    1043        55102 :     if (!myAmDelayed) {
    1044        36852 :         return myEmptyTraveltime;
    1045              :     }
    1046        36500 :     return getLength() / MAX2(minSpeed, getMeanSpeed());
    1047              : }
    1048              : 
    1049              : 
    1050              : double
    1051            0 : MSEdge::getRoutingSpeed() const {
    1052            0 :     return MSRoutingEngine::getAssumedSpeed(this, nullptr);
    1053              : }
    1054              : 
    1055              : 
    1056              : bool
    1057      1810128 : MSEdge::dictionary(const std::string& id, MSEdge* ptr) {
    1058              :     const DictType::iterator it = myDict.lower_bound(id);
    1059      1810128 :     if (it == myDict.end() || it->first != id) {
    1060              :         // id not in myDict
    1061      1810128 :         myDict.emplace_hint(it, id, ptr);
    1062      3620292 :         while (ptr->getNumericalID() >= (int)myEdges.size()) {
    1063      1810164 :             myEdges.push_back(nullptr);
    1064              :         }
    1065      1810128 :         myEdges[ptr->getNumericalID()] = ptr;
    1066      1810128 :         return true;
    1067              :     }
    1068              :     return false;
    1069              : }
    1070              : 
    1071              : 
    1072              : MSEdge*
    1073      7902864 : MSEdge::dictionary(const std::string& id) {
    1074              :     const DictType::iterator it = myDict.find(id);
    1075      7902864 :     if (it == myDict.end()) {
    1076              :         return nullptr;
    1077              :     }
    1078      6090834 :     return it->second;
    1079              : }
    1080              : 
    1081              : 
    1082              : MSEdge*
    1083      2522906 : MSEdge::dictionaryHint(const std::string& id, const int startIdx) {
    1084              :     // this method is mainly useful when parsing connections from the net.xml which are sorted by "from" id
    1085      2522906 :     if (myEdges[startIdx] != nullptr && myEdges[startIdx]->getID() == id) {
    1086              :         return myEdges[startIdx];
    1087              :     }
    1088      1506927 :     if (startIdx + 1 < (int)myEdges.size() && myEdges[startIdx + 1] != nullptr && myEdges[startIdx + 1]->getID() == id) {
    1089              :         return myEdges[startIdx + 1];
    1090              :     }
    1091       468739 :     return dictionary(id);
    1092              : }
    1093              : 
    1094              : 
    1095              : const MSEdgeVector&
    1096       885230 : MSEdge::getAllEdges() {
    1097       885230 :     return myEdges;
    1098              : }
    1099              : 
    1100              : 
    1101              : void
    1102        38964 : MSEdge::clear() {
    1103      1833870 :     for (DictType::iterator i = myDict.begin(); i != myDict.end(); ++i) {
    1104      1794906 :         delete (*i).second;
    1105              :     }
    1106              :     myDict.clear();
    1107              :     myEdges.clear();
    1108        38964 : }
    1109              : 
    1110              : 
    1111              : void
    1112          309 : MSEdge::insertIDs(std::vector<std::string>& into) {
    1113        16328 :     for (DictType::iterator i = myDict.begin(); i != myDict.end(); ++i) {
    1114        16019 :         into.push_back((*i).first);
    1115              :     }
    1116          309 : }
    1117              : 
    1118              : 
    1119              : void
    1120       405730 : MSEdge::parseEdgesList(const std::string& desc, ConstMSEdgeVector& into,
    1121              :                        const std::string& rid) {
    1122       405730 :     StringTokenizer st(desc);
    1123       405730 :     parseEdgesList(st.getVector(), into, rid);
    1124       405730 : }
    1125              : 
    1126              : 
    1127              : void
    1128       406010 : MSEdge::parseEdgesList(const std::vector<std::string>& desc, ConstMSEdgeVector& into,
    1129              :                        const std::string& rid) {
    1130      1544760 :     for (std::vector<std::string>::const_iterator i = desc.begin(); i != desc.end(); ++i) {
    1131      1138801 :         const MSEdge* edge = MSEdge::dictionary(*i);
    1132              :         // check whether the edge exists
    1133      1138801 :         if (edge == nullptr) {
    1134           51 :             throw ProcessError("The edge '" + *i + "' within the route " + rid + " is not known."
    1135          153 :                                + "\n The route can not be build.");
    1136              :         }
    1137      1138750 :         into.push_back(edge);
    1138              :     }
    1139       405959 : }
    1140              : 
    1141              : 
    1142              : double
    1143      2090329 : MSEdge::getDistanceTo(const MSEdge* other, const bool doBoundaryEstimate) const {
    1144              :     assert(this != other);
    1145      2090329 :     if (doBoundaryEstimate) {
    1146        19288 :         return myBoundary.distanceTo2D(other->myBoundary);
    1147              :     }
    1148      2071041 :     if (isTazConnector()) {
    1149          453 :         if (other->isTazConnector()) {
    1150          441 :             return myBoundary.distanceTo2D(other->myBoundary);
    1151              :         }
    1152           12 :         return myBoundary.distanceTo2D(other->getLanes()[0]->getShape()[0]);
    1153              :     }
    1154      2070588 :     if (other->isTazConnector()) {
    1155         5264 :         return other->myBoundary.distanceTo2D(getLanes()[0]->getShape()[-1]);
    1156              :     }
    1157      2065324 :     return getLanes()[0]->getShape()[-1].distanceTo2D(other->getLanes()[0]->getShape()[0]);
    1158              : }
    1159              : 
    1160              : 
    1161              : const Position
    1162         2429 : MSEdge::getStopPosition(const SUMOVehicleParameter::Stop& stop) {
    1163         2429 :     return MSLane::dictionary(stop.lane)->geometryPositionAtOffset((stop.endPos + stop.startPos) / 2.);
    1164              : }
    1165              : 
    1166              : 
    1167              : double
    1168     88723561 : MSEdge::getSpeedLimit() const {
    1169              :     // @note lanes might have different maximum speeds in theory
    1170     88723561 :     return myLanes->empty() ? 1 : getLanes()[0]->getSpeedLimit();
    1171              : }
    1172              : 
    1173              : 
    1174              : double
    1175      1817872 : MSEdge::getLengthGeometryFactor() const {
    1176      1817872 :     return myLanes->empty() ? 1 : getLanes()[0]->getLengthGeometryFactor();
    1177              : }
    1178              : 
    1179              : double
    1180    321966997 : MSEdge::getVehicleMaxSpeed(const SUMOTrafficObject* const veh) const {
    1181              :     // @note lanes might have different maximum speeds in theory
    1182    321966997 :     return myLanes->empty() ? 1 : getLanes()[0]->getVehicleMaxSpeed(veh);
    1183              : }
    1184              : 
    1185              : 
    1186              : void
    1187          205 : MSEdge::setMaxSpeed(double val, double jamThreshold) {
    1188              :     assert(val >= 0);
    1189          205 :     if (myLanes != nullptr) {
    1190          564 :         for (std::vector<MSLane*>::const_iterator i = myLanes->begin(); i != myLanes->end(); ++i) {
    1191          359 :             (*i)->setMaxSpeed(val, false, false, jamThreshold);
    1192              :         }
    1193              :     }
    1194          205 : }
    1195              : 
    1196              : 
    1197              : void
    1198      1307316 : MSEdge::addTransportable(MSTransportable* t) const {
    1199      1307316 :     if (t->isPerson()) {
    1200              :         myPersons.insert(t);
    1201              :     } else {
    1202              :         myContainers.insert(t);
    1203              :     }
    1204      1307316 : }
    1205              : 
    1206              : void
    1207      6573177 : MSEdge::removeTransportable(MSTransportable* t) const {
    1208      6573177 :     std::set<MSTransportable*, ComparatorNumericalIdLess>& tc = t->isPerson() ? myPersons : myContainers;
    1209              :     auto it = tc.find(t);
    1210      6573177 :     if (it != tc.end()) {
    1211              :         tc.erase(it);
    1212              :     }
    1213      6573177 : }
    1214              : 
    1215              : std::vector<MSTransportable*>
    1216      7350228 : MSEdge::getSortedPersons(SUMOTime timestep, bool includeRiding) const {
    1217      7350228 :     std::vector<MSTransportable*> result(myPersons.begin(), myPersons.end());
    1218      7350228 :     if (includeRiding) {
    1219      2338921 :         for (std::vector<MSLane*>::const_iterator i = myLanes->begin(); i != myLanes->end(); ++i) {
    1220      1651510 :             const MSLane::VehCont& vehs = (*i)->getVehiclesSecure();
    1221      2875351 :             for (MSLane::VehCont::const_iterator j = vehs.begin(); j != vehs.end(); ++j) {
    1222      1223841 :                 const std::vector<MSTransportable*>& persons = (*j)->getPersons();
    1223      1223841 :                 result.insert(result.end(), persons.begin(), persons.end());
    1224              :             }
    1225      1651510 :             (*i)->releaseVehicles();
    1226              :         }
    1227              :     }
    1228      7350228 :     sort(result.begin(), result.end(), transportable_by_position_sorter(timestep));
    1229      7350228 :     return result;
    1230            0 : }
    1231              : 
    1232              : 
    1233              : std::vector<MSTransportable*>
    1234     64210904 : MSEdge::getSortedContainers(SUMOTime timestep, bool /* includeRiding */) const {
    1235     64210904 :     std::vector<MSTransportable*> result(myContainers.begin(), myContainers.end());
    1236     64210904 :     sort(result.begin(), result.end(), transportable_by_position_sorter(timestep));
    1237     64210904 :     return result;
    1238            0 : }
    1239              : 
    1240              : 
    1241              : int
    1242      5097662 : MSEdge::transportable_by_position_sorter::operator()(const MSTransportable* const c1, const MSTransportable* const c2) const {
    1243      5097662 :     const double pos1 = c1->getCurrentStage()->getEdgePos(myTime);
    1244      5097662 :     const double pos2 = c2->getCurrentStage()->getEdgePos(myTime);
    1245      5097662 :     if (pos1 != pos2) {
    1246      4942606 :         return pos1 < pos2;
    1247              :     }
    1248       155056 :     return c1->getID() < c2->getID();
    1249              : }
    1250              : 
    1251              : 
    1252              : void
    1253       404171 : MSEdge::addSuccessor(MSEdge* edge, const MSEdge* via) {
    1254       404171 :     mySuccessors.push_back(edge);
    1255       404171 :     myViaSuccessors.push_back(std::make_pair(edge, via));
    1256       404171 :     if (isTazConnector() && edge->getFromJunction() != nullptr) {
    1257       202082 :         myBoundary.add(edge->getFromJunction()->getPosition());
    1258              :     }
    1259              : 
    1260       404171 :     edge->myPredecessors.push_back(this);
    1261       404171 :     if (edge->isTazConnector() && getToJunction() != nullptr) {
    1262       202089 :         edge->myBoundary.add(getToJunction()->getPosition());
    1263              :     }
    1264       404171 : }
    1265              : 
    1266              : 
    1267              : const MSEdgeVector&
    1268      7734429 : MSEdge::getSuccessors(SUMOVehicleClass vClass) const {
    1269      7734429 :     if (vClass == SVC_IGNORING || !MSNet::getInstance()->hasPermissions() || myFunction == SumoXMLEdgeFunc::CONNECTOR) {
    1270      7718141 :         return mySuccessors;
    1271              :     }
    1272              : #ifdef HAVE_FOX
    1273        16288 :     ScopedLocker<> lock(mySuccessorMutex, MSGlobals::gNumThreads > 1);
    1274              : #endif
    1275              :     std::map<SUMOVehicleClass, MSEdgeVector>::iterator i = myClassesSuccessorMap.find(vClass);
    1276        16288 :     if (i == myClassesSuccessorMap.end()) {
    1277              :         // instantiate vector
    1278         1644 :         myClassesSuccessorMap[vClass];
    1279              :         i = myClassesSuccessorMap.find(vClass);
    1280              :         // this vClass is requested for the first time. rebuild all successors
    1281         7883 :         for (MSEdgeVector::const_iterator it = mySuccessors.begin(); it != mySuccessors.end(); ++it) {
    1282         6239 :             if ((*it)->isTazConnector()) {
    1283          239 :                 i->second.push_back(*it);
    1284              :             } else {
    1285         6000 :                 const std::vector<MSLane*>* allowed = allowedLanes(**it, vClass);
    1286         6000 :                 if (allowed != nullptr && allowed->size() > 0) {
    1287         4970 :                     i->second.push_back(*it);
    1288              :                 }
    1289              :             }
    1290              :         }
    1291              :     }
    1292              :     // can use cached value
    1293        16288 :     return i->second;
    1294              : }
    1295              : 
    1296              : 
    1297              : const MSConstEdgePairVector&
    1298    160500234 : MSEdge::getViaSuccessors(SUMOVehicleClass vClass, bool ignoreTransientPermissions) const {
    1299    160500234 :     if (vClass == SVC_IGNORING || !MSNet::getInstance()->hasPermissions() || myFunction == SumoXMLEdgeFunc::CONNECTOR) {
    1300    154847742 :         return myViaSuccessors;
    1301              :     }
    1302              : #ifdef HAVE_FOX
    1303      5652492 :     ScopedLocker<> lock(mySuccessorMutex, MSGlobals::gNumThreads > 1);
    1304              : #endif
    1305      5652492 :     auto& viaMap = ignoreTransientPermissions && myHaveTransientPermissions ? myOrigClassesViaSuccessorMap : myClassesViaSuccessorMap;
    1306              :     auto i = viaMap.find(vClass);
    1307      5652492 :     if (i != viaMap.end()) {
    1308              :         // can use cached value
    1309      5602125 :         return i->second;
    1310              :     }
    1311              :     // instantiate vector
    1312        50367 :     MSConstEdgePairVector& result = viaMap[vClass];
    1313              :     // this vClass is requested for the first time. rebuild all successors
    1314       207535 :     for (const auto& viaPair : myViaSuccessors) {
    1315       157168 :         if (viaPair.first->isTazConnector()) {
    1316        11333 :             result.push_back(viaPair);
    1317              :         } else {
    1318       145835 :             const std::vector<MSLane*>* allowed = allowedLanes(*viaPair.first, vClass, ignoreTransientPermissions);
    1319       145835 :             if (allowed != nullptr && allowed->size() > 0) {
    1320       116223 :                 result.push_back(viaPair);
    1321              :             }
    1322              :         }
    1323              :     }
    1324              :     return result;
    1325              : }
    1326              : 
    1327              : 
    1328              : void
    1329      1627115 : MSEdge::setJunctions(MSJunction* from, MSJunction* to) {
    1330      1627115 :     myFromJunction = from;
    1331      1627115 :     myToJunction = to;
    1332      1627115 :     if (!isTazConnector()) {
    1333      1627115 :         myBoundary.add(from->getPosition());
    1334      1627115 :         myBoundary.add(to->getPosition());
    1335              :     }
    1336      1627115 : }
    1337              : 
    1338              : 
    1339              : bool
    1340      2737747 : MSEdge::canChangeToOpposite() const {
    1341      2737747 :     return (!myLanes->empty() && myLanes->back()->getOpposite() != nullptr &&
    1342              :             // do not change on curved internal lanes
    1343              :             (!isInternal()
    1344         5453 :              || (MSGlobals::gUsingInternalLanes
    1345         5449 :                  && myLanes->back()->getIncomingLanes()[0].viaLink->getDirection() == LinkDirection::STRAIGHT)));
    1346              : }
    1347              : 
    1348              : 
    1349              : const MSEdge*
    1350     21977347 : MSEdge::getOppositeEdge() const {
    1351     21977347 :     if (!myLanes->empty() && myLanes->back()->getOpposite() != nullptr) {
    1352      3011183 :         return &(myLanes->back()->getOpposite()->getEdge());
    1353              :     } else {
    1354     18966164 :         return nullptr;
    1355              :     }
    1356              : }
    1357              : 
    1358              : 
    1359              : bool
    1360          178 : MSEdge::hasMinorLink() const {
    1361          370 :     for (const MSLane* const l : *myLanes) {
    1362          290 :         for (const MSLink* const link : l->getLinkCont()) {
    1363           98 :             if (!link->havePriority()) {
    1364              :                 return true;
    1365              :             }
    1366              :         }
    1367              :     }
    1368              :     return false;
    1369              : }
    1370              : 
    1371              : bool
    1372       623113 : MSEdge::hasChangeProhibitions(SUMOVehicleClass svc, int index) const {
    1373       623113 :     if (myLanes->size() == 1) {
    1374              :         return false;
    1375              :     }
    1376      1367302 :     for (const MSLane* const l : *myLanes) {
    1377       916560 :         if (l->getIndex() <= index && !l->allowsChangingRight(svc) && l->getIndex() > 0) {
    1378              :             return true;
    1379       916516 :         } else if (l->getIndex() >= index && !l->allowsChangingLeft(svc) && l->getIndex() < (int)(myLanes->size() - 1)) {
    1380              :             return true;
    1381              :         }
    1382              :     }
    1383              :     return false;
    1384              : }
    1385              : 
    1386              : void
    1387       878956 : MSEdge::checkAndRegisterBiDirEdge(const std::string& bidiID) {
    1388       878956 :     if (bidiID != "") {
    1389        28306 :         myBidiEdge = dictionary(bidiID);
    1390        28306 :         if (myBidiEdge == nullptr) {
    1391            0 :             WRITE_ERRORF(TL("Bidi-edge '%' does not exist"), bidiID);
    1392              :         }
    1393        28306 :         setBidiLanes();
    1394       501816 :         return;
    1395              :     }
    1396       850650 :     if (getFunction() != SumoXMLEdgeFunc::NORMAL) {
    1397              :         return;
    1398              :     }
    1399              :     // legacy networks (no bidi attribute)
    1400       377140 :     ConstMSEdgeVector candidates = myToJunction->getOutgoing();
    1401      2983052 :     for (ConstMSEdgeVector::const_iterator it = candidates.begin(); it != candidates.end(); it++) {
    1402      2605912 :         if ((*it)->getToJunction() == myFromJunction) { //reverse edge
    1403       303712 :             if (myBidiEdge != nullptr && isSuperposable(*it)) {
    1404            0 :                 WRITE_WARNINGF(TL("Ambiguous superposable edges between junction '%' and '%'."), myToJunction->getID(), myFromJunction->getID());
    1405            0 :                 break;
    1406              :             }
    1407       303712 :             if (isSuperposable(*it)) {
    1408           26 :                 myBidiEdge = *it;
    1409           26 :                 setBidiLanes();
    1410              :             }
    1411              :         }
    1412              :     }
    1413       377140 : }
    1414              : 
    1415              : 
    1416              : void
    1417        28332 : MSEdge::setBidiLanes() {
    1418              :     assert(myBidiEdge != nullptr);
    1419        28332 :     if (getNumLanes() == 1 && myBidiEdge->getNumLanes() == 1) {
    1420              :         // the other way round is set when this method runs for the bidiEdge
    1421        27794 :         getLanes()[0]->setBidiLane(myBidiEdge->getLanes()[0]);
    1422              :     } else {
    1423              :         // find lanes with matching reversed shapes
    1424              :         int numBidiLanes = 0;
    1425         1680 :         for (MSLane* l1 : *myLanes) {
    1426         3630 :             for (MSLane* l2 : *myBidiEdge->myLanes) {
    1427         2488 :                 if (l1->getShape().reverse().almostSame(l2->getShape(), POSITION_EPS * 2)) {
    1428          592 :                     l1->setBidiLane(l2);
    1429          592 :                     numBidiLanes++;
    1430              :                 }
    1431              :             }
    1432              :         }
    1433              :         // warn only once for each pair
    1434          538 :         if (numBidiLanes == 0 && getNumericalID() < myBidiEdge->getNumericalID()) {
    1435           15 :             WRITE_WARNINGF(TL("Edge '%' and bidi edge '%' have no matching bidi lanes"), getID(), myBidiEdge->getID());
    1436              :         }
    1437              :     }
    1438        28332 : }
    1439              : 
    1440              : 
    1441              : bool
    1442       303712 : MSEdge::isSuperposable(const MSEdge* other) {
    1443       303712 :     if (other == nullptr || other->getLanes().size() != myLanes->size()) {
    1444              :         return false;
    1445              :     }
    1446              :     std::vector<MSLane*>::const_iterator it1 = myLanes->begin();
    1447              :     std::vector<MSLane*>::const_reverse_iterator it2 = other->getLanes().rbegin();
    1448              :     do {
    1449       299138 :         if ((*it1)->getShape().reverse() != (*it2)->getShape()) {
    1450              :             return false;
    1451              :         }
    1452              :         it1++;
    1453              :         it2++;
    1454           26 :     } while (it1 != myLanes->end());
    1455              : 
    1456              :     return true;
    1457              : }
    1458              : 
    1459              : 
    1460              : void
    1461        69687 : MSEdge::addWaiting(SUMOVehicle* vehicle) const {
    1462              : #ifdef HAVE_FOX
    1463        69687 :     ScopedLocker<> lock(myWaitingMutex, MSGlobals::gNumSimThreads > 1);
    1464              : #endif
    1465        69687 :     myWaiting.push_back(vehicle);
    1466        69687 : }
    1467              : 
    1468              : 
    1469              : void
    1470        61600 : MSEdge::removeWaiting(const SUMOVehicle* vehicle) const {
    1471              : #ifdef HAVE_FOX
    1472        61600 :     ScopedLocker<> lock(myWaitingMutex, MSGlobals::gNumSimThreads > 1);
    1473              : #endif
    1474        61600 :     std::vector<SUMOVehicle*>::iterator it = std::find(myWaiting.begin(), myWaiting.end(), vehicle);
    1475        61600 :     if (it != myWaiting.end()) {
    1476        61283 :         myWaiting.erase(it);
    1477              :     }
    1478        61600 : }
    1479              : 
    1480              : 
    1481              : SUMOVehicle*
    1482        79033 : MSEdge::getWaitingVehicle(MSTransportable* transportable, const double position) const {
    1483              : #ifdef HAVE_FOX
    1484        79033 :     ScopedLocker<> lock(myWaitingMutex, MSGlobals::gNumSimThreads > 1);
    1485              : #endif
    1486        79336 :     for (SUMOVehicle* const vehicle : myWaiting) {
    1487         5171 :         if (transportable->isWaitingFor(vehicle)) {
    1488         7316 :             if (vehicle->isStoppedInRange(position, MSGlobals::gStopTolerance) ||
    1489         2245 :                     (!vehicle->hasDeparted() &&
    1490         2046 :                      (vehicle->getParameter().departProcedure == DepartDefinition::TRIGGERED ||
    1491           83 :                       vehicle->getParameter().departProcedure == DepartDefinition::CONTAINER_TRIGGERED))) {
    1492              :                 return vehicle;
    1493              :             }
    1494          203 :             if (!vehicle->isLineStop(position) && vehicle->allowsBoarding(transportable)) {
    1495          228 :                 WRITE_WARNING((transportable->isPerson() ? "Person '" : "Container '")
    1496              :                               + transportable->getID() + "' at edge '" + getID() + "' position " + toString(position) + " cannot use waiting vehicle '"
    1497              :                               + vehicle->getID() + "' at position " + toString(vehicle->getPositionOnLane()) + " because it is too far away.");
    1498              :             }
    1499              :         }
    1500              :     }
    1501              :     return nullptr;
    1502              : }
    1503              : 
    1504              : std::vector<const SUMOVehicle*>
    1505       144692 : MSEdge::getVehicles() const {
    1506              :     std::vector<const SUMOVehicle*> result;
    1507       144692 :     if (MSGlobals::gUseMesoSim) {
    1508          164 :         for (MESegment* segment = MSGlobals::gMesoNet->getSegmentForEdge(*this); segment != nullptr; segment = segment->getNextSegment()) {
    1509           88 :             std::vector<const MEVehicle*> segmentVehs = segment->getVehicles();
    1510           88 :             result.insert(result.end(), segmentVehs.begin(), segmentVehs.end());
    1511           88 :         }
    1512              :     } else {
    1513       387783 :         for (MSLane* lane : getLanes()) {
    1514       831869 :             for (auto veh : lane->getVehiclesSecure()) {
    1515       588740 :                 result.push_back(veh);
    1516              :             }
    1517       243129 :             lane->releaseVehicles();
    1518              :         }
    1519              :     }
    1520       144692 :     return result;
    1521            0 : }
    1522              : 
    1523              : int
    1524       601794 : MSEdge::getNumDrivingLanes() const {
    1525              :     int result = 0;
    1526       601794 :     SVCPermissions filter = SVCAll;
    1527       601794 :     if ((myCombinedPermissions & ~(SVC_PEDESTRIAN | SVC_WHEELCHAIR)) != 0) {
    1528              :         filter = ~(SVC_PEDESTRIAN | SVC_WHEELCHAIR);
    1529         2050 :     } else if ((myCombinedPermissions & (SVC_PEDESTRIAN | SVC_WHEELCHAIR)) != 0) {
    1530              :         // filter out green verge
    1531              :         filter = (SVC_PEDESTRIAN | SVC_WHEELCHAIR);
    1532              :     }
    1533      1341899 :     for (const MSLane* const l : *myLanes) {
    1534       740105 :         if ((l->getPermissions() & filter) != 0) {
    1535       666553 :             result++;
    1536              :         }
    1537              :     }
    1538       601794 :     return result;
    1539              : }
    1540              : 
    1541              : int
    1542          661 : MSEdge::getVehicleNumber() const {
    1543          661 :     return (int)getVehicles().size();
    1544              : }
    1545              : 
    1546              : 
    1547              : bool
    1548            0 : MSEdge::isEmpty() const {
    1549              :     /// more efficient than retrieving vehicle number
    1550            0 :     if (MSGlobals::gUseMesoSim) {
    1551            0 :         for (MESegment* segment = MSGlobals::gMesoNet->getSegmentForEdge(*this); segment != nullptr; segment = segment->getNextSegment()) {
    1552            0 :             if (segment->getCarNumber() > 0) {
    1553              :                 return false;
    1554              :             }
    1555              :         }
    1556              :     } else {
    1557            0 :         for (MSLane* lane : getLanes()) {
    1558            0 :             if (lane->getVehicleNumber() > 0) {
    1559              :                 return false;
    1560              :             }
    1561              :         }
    1562              :     }
    1563              :     return true;
    1564              : }
    1565              : 
    1566              : 
    1567              : double
    1568           14 : MSEdge::getWaitingSeconds() const {
    1569              :     double wtime = 0;
    1570           14 :     if (MSGlobals::gUseMesoSim) {
    1571            4 :         for (MESegment* segment = MSGlobals::gMesoNet->getSegmentForEdge(*this); segment != nullptr; segment = segment->getNextSegment()) {
    1572            3 :             wtime += segment->getWaitingSeconds();
    1573              :         }
    1574              :     } else {
    1575           42 :         for (MSLane* lane : getLanes()) {
    1576           29 :             wtime += lane->getWaitingSeconds();
    1577              :         }
    1578              :     }
    1579           14 :     return wtime;
    1580              : }
    1581              : 
    1582              : 
    1583              : double
    1584           22 : MSEdge::getOccupancy() const {
    1585           22 :     if (myLanes->size() == 0) {
    1586              :         return 0;
    1587              :     }
    1588           22 :     if (MSGlobals::gUseMesoSim) {
    1589              :         /// @note MESegment only tracks brutto occupancy so we compute this from sratch
    1590              :         double sum = 0;
    1591            4 :         for (const SUMOVehicle* veh : getVehicles()) {
    1592            2 :             sum += dynamic_cast<const MEVehicle*>(veh)->getVehicleType().getLength();
    1593            2 :         }
    1594            2 :         return sum / (myLength * (double)myLanes->size());
    1595              :     } else {
    1596              :         double sum = 0;
    1597           56 :         for (auto lane : getLanes()) {
    1598           36 :             sum += lane->getNettoOccupancy();
    1599              :         }
    1600           20 :         return sum / (double)myLanes->size();
    1601              :     }
    1602              : }
    1603              : 
    1604              : 
    1605              : double
    1606            0 : MSEdge::getFlow() const {
    1607            0 :     if (myLanes->size() == 0) {
    1608              :         return 0;
    1609              :     }
    1610              :     double flow = 0;
    1611            0 :     for (MESegment* segment = MSGlobals::gMesoNet->getSegmentForEdge(*this); segment != nullptr; segment = segment->getNextSegment()) {
    1612            0 :         flow += (double) segment->getCarNumber() * segment->getMeanSpeed();
    1613              :     }
    1614            0 :     return 3600 * flow / (*myLanes)[0]->getLength();
    1615              : }
    1616              : 
    1617              : 
    1618              : double
    1619            0 : MSEdge::getBruttoOccupancy() const {
    1620            0 :     if (myLanes->size() == 0) {
    1621              :         return 0;
    1622              :     }
    1623              :     double occ = 0;
    1624            0 :     for (MESegment* segment = MSGlobals::gMesoNet->getSegmentForEdge(*this); segment != nullptr; segment = segment->getNextSegment()) {
    1625            0 :         occ += segment->getBruttoOccupancy();
    1626              :     }
    1627            0 :     return occ / (*myLanes)[0]->getLength() / (double)(myLanes->size());
    1628              : }
    1629              : 
    1630              : double
    1631         4240 : MSEdge::getTravelTimeAggregated(const MSEdge* const edge, const SUMOVehicle* const veh, double /*time*/) {
    1632         4240 :     return edge->getLength() / MIN2(MSRoutingEngine::getAssumedSpeed(edge, veh), veh->getMaxSpeed());
    1633              : }
    1634              : 
    1635              : 
    1636              : void
    1637         2098 : MSEdge::inferEdgeType() {
    1638              :     // @note must be called after closeBuilding() to ensure successors and
    1639              :     // predecessors are set
    1640         2098 :     if (isInternal() && myEdgeType == "") {
    1641         1274 :         const std::string typeBefore = getNormalBefore()->getEdgeType();
    1642         1274 :         if (typeBefore != "") {
    1643          622 :             const std::string typeAfter = getNormalSuccessor()->getEdgeType();
    1644          622 :             if (typeBefore == typeAfter) {
    1645              :                 myEdgeType = typeBefore;
    1646          244 :             } else if (typeAfter != "") {
    1647           60 :                 MSNet* net = MSNet::getInstance();
    1648           60 :                 auto resBefore = net->getRestrictions(typeBefore);
    1649           60 :                 auto resAfter = net->getRestrictions(typeAfter);
    1650           60 :                 if (resBefore != nullptr && resAfter != nullptr) {
    1651              :                     // create new restrictions for this type-combination
    1652           80 :                     myEdgeType = typeBefore + "|" + typeAfter;
    1653           40 :                     if (net->getRestrictions(myEdgeType) == nullptr) {
    1654           40 :                         for (const auto& item : *resBefore) {
    1655           20 :                             const SUMOVehicleClass svc = item.first;
    1656           20 :                             const double speed = item.second;
    1657              :                             const auto it = (*resAfter).find(svc);
    1658           20 :                             if (it != (*resAfter).end()) {
    1659           20 :                                 const double speed2 = it->second;
    1660           20 :                                 const double newSpeed = (MSNet::getInstance()->hasJunctionHigherSpeeds()
    1661           20 :                                                          ? MAX2(speed, speed2) : (speed + speed2) / 2);
    1662           20 :                                 net->addRestriction(myEdgeType, svc, newSpeed);
    1663              :                             }
    1664              :                         }
    1665              :                     }
    1666              :                 }
    1667              :             }
    1668              :         }
    1669              :     }
    1670         2098 : }
    1671              : 
    1672              : 
    1673              : double
    1674         2134 : MSEdge::getDistanceAt(double pos) const {
    1675              :     // negative values of myDistances indicate descending kilometrage
    1676         2134 :     return fabs(myDistance + pos);
    1677              : }
    1678              : 
    1679              : 
    1680              : bool
    1681         1006 : MSEdge::hasTransientPermissions() const {
    1682         1006 :     return myHaveTransientPermissions;
    1683              : }
    1684              : 
    1685              : 
    1686              : std::pair<double, SUMOTime>
    1687    563727533 : MSEdge::getLastBlocked(int index) const {
    1688    563727533 :     if (myLaneChanger != nullptr) {
    1689    563727533 :         return myLaneChanger->getLastBlocked(index);
    1690              :     }
    1691            0 :     return std::make_pair(-1, -1);
    1692              : }
    1693              : 
    1694              : 
    1695              : double
    1696         1631 : MSEdge::getPreference(const SUMOVTypeParameter& pars) const {
    1697         3262 :     return MSNet::getInstance()->getPreference(getRoutingType(), pars);
    1698              : }
    1699              : 
    1700              : void
    1701         8184 : MSEdge::clearState() {
    1702              :     myPersons.clear();
    1703              :     myContainers.clear();
    1704              :     myWaiting.clear();
    1705         8184 : }
    1706              : 
    1707              : /****************************************************************************/
        

Generated by: LCOV version 2.0-1