LCOV - code coverage report
Current view: top level - src/microsim - MSEdge.cpp (source / functions) Coverage Total Hit
Test: lcov.info Lines: 94.9 % 758 719
Test Date: 2024-11-22 15:46:21 Functions: 94.1 % 85 80

            Line data    Source code
       1              : /****************************************************************************/
       2              : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
       3              : // Copyright (C) 2001-2024 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              : 
      63              : 
      64              : // ===========================================================================
      65              : // member method definitions
      66              : // ===========================================================================
      67      2069186 : MSEdge::MSEdge(const std::string& id, int numericalID,
      68              :                const SumoXMLEdgeFunc function,
      69              :                const std::string& streetName,
      70              :                const std::string& edgeType,
      71              :                int priority,
      72      2069186 :                double distance) :
      73      2069186 :     Named(id), myNumericalID(numericalID), myLanes(nullptr),
      74      2069186 :     myLaneChanger(nullptr), myFunction(function), myVaporizationRequests(0),
      75      2069186 :     myLastFailedInsertionTime(-1),
      76      2069186 :     myFromJunction(nullptr), myToJunction(nullptr),
      77      2069186 :     myHaveTransientPermissions(false),
      78      2069186 :     myOtherTazConnector(nullptr),
      79      2069186 :     myStreetName(streetName),
      80      2069186 :     myEdgeType(edgeType),
      81      2069186 :     myPriority(priority),
      82      2069186 :     myDistance(distance),
      83      2069186 :     myWidth(0.),
      84      2069186 :     myLength(0.),
      85      2069186 :     myEmptyTraveltime(0.),
      86      2069186 :     myTimePenalty(0.),
      87      2069186 :     myAmDelayed(false),
      88      2069186 :     myAmRoundabout(false),
      89      2069186 :     myAmFringe(true),
      90      4138372 :     myBidiEdge(nullptr)
      91      2069186 : { }
      92              : 
      93              : 
      94      3451658 : MSEdge::~MSEdge() {
      95      1943669 :     delete myLaneChanger;
      96      1943669 :     delete myReversedRoutingEdge;
      97      1943669 :     delete myRailwayRoutingEdge;
      98     11226334 : }
      99              : 
     100              : 
     101              : void
     102      1938242 : MSEdge::initialize(const std::vector<MSLane*>* lanes) {
     103              :     assert(lanes != 0);
     104      1938242 :     myLanes = std::shared_ptr<const std::vector<MSLane*> >(lanes);
     105      1938242 :     if (myFunction == SumoXMLEdgeFunc::CONNECTOR) {
     106       200472 :         myCombinedPermissions = SVCAll;
     107              :     }
     108      4098226 :     for (MSLane* const lane : *lanes) {
     109      2159984 :         lane->setRightSideOnEdge(myWidth, (int)mySublaneSides.size());
     110      2159984 :         MSLeaderInfo ahead(lane->getWidth());
     111      4951056 :         for (int j = 0; j < ahead.numSublanes(); ++j) {
     112      2791072 :             mySublaneSides.push_back(myWidth + j * MSGlobals::gLateralResolution);
     113              :         }
     114      2159984 :         myWidth += lane->getWidth();
     115      2159984 :     }
     116      1938242 : }
     117              : 
     118              : 
     119      1816325 : void MSEdge::recalcCache() {
     120      1816325 :     if (myLanes->empty()) {
     121              :         return;
     122              :     }
     123      1816325 :     myLength = myLanes->front()->getLength();
     124      3632650 :     myEmptyTraveltime = myLength / MAX2(getSpeedLimit(), NUMERICAL_EPS);
     125      1816325 :     if (isNormal() && (MSGlobals::gUseMesoSim || MSGlobals::gTLSPenalty > 0)) {
     126              :         SUMOTime minorPenalty = 0;
     127       160272 :         bool haveTLSPenalty = MSGlobals::gTLSPenalty > 0;
     128       160272 :         if (MSGlobals::gUseMesoSim) {
     129       160157 :             const MESegment::MesoEdgeType& edgeType = MSNet::getInstance()->getMesoType(getEdgeType());
     130       160157 :             minorPenalty = edgeType.minorPenalty;
     131       160157 :             haveTLSPenalty = edgeType.tlsPenalty > 0;
     132              :         }
     133       160272 :         if (haveTLSPenalty || minorPenalty > 0) {
     134              :             // add tls penalties to the minimum travel time
     135              :             SUMOTime minPenalty = -1;
     136         1931 :             for (const MSLane* const l : *myLanes) {
     137         3025 :                 for (const MSLink* const link : l->getLinkCont()) {
     138         1721 :                     if (link->getLane()->isWalkingArea() && link->getLaneBefore()->isNormal()) {
     139           60 :                         continue;
     140              :                     }
     141         1661 :                     SUMOTime linkPenalty = link->isTLSControlled() ? link->getMesoTLSPenalty() : (link->havePriority() ? 0 : minorPenalty);
     142         1661 :                     if (minPenalty == -1) {
     143              :                         minPenalty = linkPenalty;
     144              :                     } else {
     145              :                         minPenalty = MIN2(minPenalty, linkPenalty);
     146              :                     }
     147              :                 }
     148              :             }
     149          627 :             if (minPenalty > 0) {
     150          197 :                 myEmptyTraveltime += STEPS2TIME(minPenalty);
     151          197 :                 myTimePenalty = STEPS2TIME(minPenalty);
     152              :             }
     153              :         }
     154      1656053 :     } else if (isCrossing() && MSGlobals::gTLSPenalty > 0) {
     155              :         // penalties are recorded for the entering link
     156           80 :         for (const auto& ili : myLanes->front()->getIncomingLanes()) {
     157           40 :             double penalty = STEPS2TIME(ili.viaLink->getMesoTLSPenalty());
     158           40 :             if (!ili.viaLink->haveOffPriority()) {
     159            0 :                 penalty = MAX2(penalty, MSGlobals::gMinorPenalty);
     160              :             }
     161           40 :             if (penalty > 0) {
     162           20 :                 myEmptyTraveltime += penalty;
     163           20 :                 myTimePenalty = penalty;
     164              :             }
     165              :         }
     166      1656013 :     } else if (isInternal() && MSGlobals::gUsingInternalLanes) {
     167       809389 :         const MSLink* link = myLanes->front()->getIncomingLanes()[0].viaLink;
     168       809389 :         if (!link->isTLSControlled() && !link->havePriority()) {
     169       408174 :             if (link->isTurnaround()) {
     170       139613 :                 myEmptyTraveltime += MSGlobals::gTurnaroundPenalty;
     171       139613 :                 myTimePenalty = MSGlobals::gTurnaroundPenalty;
     172              :             } else {
     173       268561 :                 myEmptyTraveltime += MSGlobals::gMinorPenalty;
     174       268561 :                 myTimePenalty = MSGlobals::gMinorPenalty;
     175              :             }
     176              :         }
     177              :     }
     178              : }
     179              : 
     180              : 
     181              : void
     182           42 : MSEdge::resetTAZ(MSJunction* junction) {
     183              :     mySuccessors.clear();
     184              :     myPredecessors.clear();
     185          728 :     for (const MSEdge* edge : junction->getIncoming()) {
     186          686 :         if (!edge->isInternal()) {
     187          126 :             MSEdgeVector& succ = const_cast<MSEdgeVector&>(edge->mySuccessors);
     188              :             MSConstEdgePairVector& succVia = const_cast<MSConstEdgePairVector&>(edge->myViaSuccessors);
     189          126 :             MSEdgeVector& pred = const_cast<MSEdgeVector&>(edge->myPredecessors);
     190          126 :             auto it = std::find(succ.begin(), succ.end(), this);
     191          126 :             auto it2 = std::find(succVia.begin(), succVia.end(), std::make_pair(const_cast<const MSEdge*>(this), (const MSEdge*)nullptr));
     192          126 :             auto it3 = std::find(pred.begin(), pred.end(), this);
     193          126 :             if (it != succ.end()) {
     194              :                 succ.erase(it);
     195              :                 succVia.erase(it2);
     196              :             }
     197          126 :             if (it3 != pred.end()) {
     198              :                 pred.erase(it3);
     199              :             }
     200              :         }
     201              :     }
     202           42 : }
     203              : 
     204              : void
     205      1735146 : MSEdge::closeBuilding() {
     206      3892055 :     for (MSLane* const lane : *myLanes) {
     207      4910147 :         for (MSLink* const link : lane->getLinkCont()) {
     208      2753238 :             link->initParallelLinks();
     209              :             MSLane* const toL = link->getLane();
     210              :             MSLane* const viaL = link->getViaLane();
     211      2753238 :             if (toL != nullptr) {
     212              :                 MSEdge& to = toL->getEdge();
     213      2753238 :                 if (std::find(mySuccessors.begin(), mySuccessors.end(), &to) == mySuccessors.end()) {
     214      2493154 :                     mySuccessors.push_back(&to);
     215      4986308 :                     myViaSuccessors.push_back(std::make_pair(&to, (viaL == nullptr ? nullptr : &viaL->getEdge())));
     216              :                 }
     217      2753238 :                 if (std::find(to.myPredecessors.begin(), to.myPredecessors.end(), this) == to.myPredecessors.end()) {
     218      2493154 :                     to.myPredecessors.push_back(this);
     219              :                 }
     220      2753238 :                 if (link->getDirection() != LinkDirection::TURN) {
     221      2176327 :                     myAmFringe = false;
     222              :                 }
     223              :             }
     224      2753238 :             if (viaL != nullptr) {
     225              :                 MSEdge& to = viaL->getEdge();
     226       919164 :                 if (std::find(to.myPredecessors.begin(), to.myPredecessors.end(), this) == to.myPredecessors.end()) {
     227       809206 :                     to.myPredecessors.push_back(this);
     228              :                 }
     229              :             }
     230              :         }
     231      2156909 :         lane->checkBufferType();
     232              :     }
     233      1735146 :     std::sort(mySuccessors.begin(), mySuccessors.end(), by_id_sorter());
     234      1735146 :     rebuildAllowedLanes(true);
     235      1735146 :     recalcCache();
     236              : 
     237              :     // extend lookup table for sublane model after all edges are read
     238      1735146 :     if (myLanes->back()->getOpposite() != nullptr) {
     239         7360 :         MSLane* opposite = myLanes->back()->getOpposite();
     240         7360 :         MSLeaderInfo ahead(opposite->getWidth());
     241        20762 :         for (int j = 0; j < ahead.numSublanes(); ++j) {
     242        13402 :             mySublaneSides.push_back(myWidth + j * MSGlobals::gLateralResolution);
     243              :         }
     244         7360 :     }
     245      1735146 : }
     246              : 
     247              : 
     248              : void
     249          160 : MSEdge::updateMesoType() {
     250              :     assert(MSGlobals::gUseMesoSim);
     251          160 :     if (!myLanes->empty()) {
     252          160 :         MSGlobals::gMesoNet->updateSegmentsForEdge(*this);
     253              :     }
     254          160 : }
     255              : 
     256              : 
     257              : void
     258      1735146 : MSEdge::buildLaneChanger() {
     259      1735146 :     if (!myLanes->empty()) {
     260      1735146 :         const bool allowChanging = allowsLaneChanging();
     261      1735146 :         if (MSGlobals::gLateralResolution > 0) {
     262              :             // may always initiate sublane-change
     263       159902 :             if (!isInternal() || MSGlobals::gUsingInternalLanes) {
     264       159726 :                 myLaneChanger = new MSLaneChangerSublane(myLanes.get(), allowChanging);
     265              :             }
     266              :         } else {
     267      1575244 :             if (MSGlobals::gLaneChangeDuration > 0) {
     268         3717 :                 myLaneChanger = new MSLaneChanger(myLanes.get(), allowChanging);
     269      1571527 :             } else if (myLanes->size() > 1 || canChangeToOpposite()) {
     270       282105 :                 myLaneChanger = new MSLaneChanger(myLanes.get(), allowChanging);
     271              :             }
     272              :         }
     273              :     }
     274      1735146 : }
     275              : 
     276              : 
     277              : bool
     278      1735146 : MSEdge::allowsLaneChanging() const {
     279      1735146 :     if (isInternal() && MSGlobals::gUsingInternalLanes) {
     280              :         // allow changing only if all links leading to this internal lane have priority
     281              :         // or they are controlled by a traffic light
     282      1317319 :         for (const MSLane* const lane : *myLanes) {
     283       916455 :             const MSLink* const link = lane->getLogicalPredecessorLane()->getLinkTo(lane);
     284              :             assert(link != nullptr);
     285              :             const LinkState state = link->getState();
     286       398921 :             if ((state == LINKSTATE_MINOR && lane->getBidiLane() == nullptr)
     287       517740 :                     || state == LINKSTATE_EQUAL
     288       517740 :                     || state == LINKSTATE_STOP
     289              :                     || state == LINKSTATE_ALLWAY_STOP
     290       916455 :                     || state == LINKSTATE_DEADEND) {
     291              :                 return false;
     292              :             }
     293              :         }
     294              :     }
     295              :     return true;
     296              : }
     297              : 
     298              : 
     299              : void
     300     17837712 : MSEdge::addToAllowed(const SVCPermissions permissions, std::shared_ptr<const std::vector<MSLane*> > allowedLanes, AllowedLanesCont& laneCont) const {
     301     17837712 :     if (!allowedLanes->empty()) {
     302              :         // recheck whether we had this list to save memory
     303     17970374 :         for (auto& allowed : laneCont) {
     304     17056792 :             if (*allowed.second == *allowedLanes) {
     305     13622619 :                 allowed.first |= permissions;
     306              :                 return;
     307              :             }
     308              :         }
     309       913582 :         laneCont.push_back(std::make_pair(permissions, allowedLanes));
     310              :     }
     311              : }
     312              : 
     313              : 
     314              : SVCPermissions
     315      2818511 : MSEdge::getMesoPermissions(SVCPermissions p, SVCPermissions ignoreIgnored) {
     316      2818511 :     SVCPermissions ignored = myMesoIgnoredVClasses & ~ignoreIgnored;
     317      2818511 :     return (p | ignored) == ignored ? 0 : p;
     318              : }
     319              : 
     320              : 
     321              : void
     322      1736024 : MSEdge::rebuildAllowedLanes(const bool onInit) {
     323              :     // rebuild myMinimumPermissions and myCombinedPermissions
     324      1736024 :     myMinimumPermissions = SVCAll;
     325      1736024 :     myCombinedPermissions = 0;
     326              :     bool lanesChangedPermission = false;
     327      3894236 :     for (MSLane* const lane : *myLanes) {
     328              :         // same dedicated lanes are ignored in meso to avoid capacity errors.
     329              :         // Here we have to make sure that vehicles which are set to depart on
     330              :         // such lanes trigger an error.
     331      2158212 :         SVCPermissions allow = getMesoPermissions(lane->getPermissions(), SVC_PEDESTRIAN);
     332      2158212 :         myMinimumPermissions &= allow;
     333      2158212 :         myCombinedPermissions |= allow;
     334      2158212 :         lanesChangedPermission |= lane->hadPermissionChanges();
     335              :     }
     336      1736024 :     if (!onInit && !myHaveTransientPermissions && lanesChangedPermission) {
     337          506 :         myHaveTransientPermissions = true;
     338              :         // backup original structures when first needed
     339          506 :         myOrigAllowed = myAllowed;
     340              :         myOrigAllowedTargets = myAllowedTargets;
     341              :         myOrigClassesViaSuccessorMap = myClassesViaSuccessorMap;
     342              :     }
     343              :     // rebuild myAllowed
     344              :     myAllowed.clear();
     345      1736024 :     if (myCombinedPermissions != myMinimumPermissions) {
     346       134135 :         myAllowed.push_back(std::make_pair(SVC_IGNORING, myLanes));
     347      4560590 :         for (SVCPermissions vclass = SVC_PRIVATE; vclass <= SUMOVehicleClass_MAX; vclass *= 2) {
     348      4426455 :             if ((myCombinedPermissions & vclass) == vclass) {
     349              :                 std::shared_ptr<std::vector<MSLane*> > allowedLanes = std::make_shared<std::vector<MSLane*> >();
     350      9393769 :                 for (MSLane* const lane : *myLanes) {
     351      6382308 :                     if (lane->allowsVehicleClass((SUMOVehicleClass)vclass)) {
     352      3216416 :                         allowedLanes->push_back(lane);
     353              :                     }
     354              :                 }
     355      6022922 :                 addToAllowed(vclass, allowedLanes, myAllowed);
     356              :             }
     357              :         }
     358              :     }
     359      1736024 :     if (onInit) {
     360      1735146 :         myOriginalMinimumPermissions = myMinimumPermissions;
     361      1735146 :         myOriginalCombinedPermissions = myCombinedPermissions;
     362              :     } else {
     363          878 :         rebuildAllowedTargets(false);
     364         2373 :         for (MSEdge* pred : myPredecessors) {
     365         1495 :             if (myHaveTransientPermissions && !pred->myHaveTransientPermissions) {
     366          758 :                 pred->myOrigAllowed = pred->myAllowed;
     367              :                 pred->myOrigAllowedTargets = pred->myAllowedTargets;
     368              :                 pred->myOrigClassesViaSuccessorMap = pred->myClassesViaSuccessorMap;
     369          758 :                 pred->myHaveTransientPermissions = true;
     370              :             }
     371         1495 :             pred->rebuildAllowedTargets(false);
     372              :         }
     373          878 :         if (MSGlobals::gUseMesoSim) {
     374         1354 :             for (MESegment* s = MSGlobals::gMesoNet->getSegmentForEdge(*this); s != nullptr; s = s->getNextSegment()) {
     375         1128 :                 s->updatePermissions();
     376              :             }
     377              :         }
     378              :     }
     379      1736024 : }
     380              : 
     381              : 
     382              : void
     383      1738060 : MSEdge::rebuildAllowedTargets(const bool updateVehicles) {
     384              :     myAllowedTargets.clear();
     385      4235437 :     for (const MSEdge* target : mySuccessors) {
     386              :         bool universalMap = true; // whether the mapping for SVC_IGNORING is also valid for all vehicle classes
     387              :         std::shared_ptr<std::vector<MSLane*> > allLanes = std::make_shared<std::vector<MSLane*> >();
     388              :         // compute the mapping for SVC_IGNORING
     389      5869461 :         for (MSLane* const lane : *myLanes) {
     390              :             SVCPermissions combinedTargetPermissions = 0;
     391      9451223 :             for (const MSLink* const link : lane->getLinkCont()) {
     392      6079139 :                 if (&link->getLane()->getEdge() == target) {
     393      2758267 :                     allLanes->push_back(lane);
     394      2758267 :                     combinedTargetPermissions |= link->getLane()->getPermissions();
     395      2758267 :                     if (link->getViaLane() != nullptr &&
     396       920633 :                             ((lane->getPermissions() & link->getLane()->getPermissions()) != link->getViaLane()->getPermissions())) {
     397              :                         // custom connection permissions
     398              :                         universalMap = false;
     399              :                     }
     400              :                 }
     401              :             }
     402      3372084 :             if (combinedTargetPermissions == 0 || (lane->getPermissions() & combinedTargetPermissions) != lane->getPermissions()) {
     403              :                 universalMap = false;
     404              :             }
     405              :         }
     406      2497377 :         if (universalMap) {
     407      2001491 :             if (myAllowed.empty()) {
     408              :                 // we have no lane specific permissions
     409      3949782 :                 myAllowedTargets[target].push_back(std::make_pair(myMinimumPermissions, myLanes));
     410              :             } else {
     411       104722 :                 for (const auto& i : myAllowed) {
     412       234366 :                     addToAllowed(i.first, i.second, myAllowedTargets[target]);
     413              :                 }
     414              :             }
     415              :         } else {
     416       991772 :             addToAllowed(SVC_IGNORING, allLanes, myAllowedTargets[target]);
     417              :             // compute the vclass specific mapping
     418     16860124 :             for (SVCPermissions vclass = SVC_PRIVATE; vclass <= SUMOVehicleClass_MAX; vclass *= 2) {
     419     16364238 :                 if ((myCombinedPermissions & vclass) == vclass) {
     420              :                     std::shared_ptr<std::vector<MSLane*> > allowedLanes = std::make_shared<std::vector<MSLane*> >();
     421     47287806 :                     for (MSLane* const lane : *myLanes) {
     422     33035563 :                         if (lane->allowsVehicleClass((SUMOVehicleClass)vclass)) {
     423     67279125 :                             for (const MSLink* const link : lane->getLinkCont()) {
     424     42026878 :                                 if (link->getLane()->allowsVehicleClass((SUMOVehicleClass)vclass) && &link->getLane()->getEdge() == target && (link->getViaLane() == nullptr || link->getViaLane()->allowsVehicleClass((SUMOVehicleClass)vclass))) {
     425     11285412 :                                     allowedLanes->push_back(lane);
     426              :                                 }
     427              :                             }
     428              :                         }
     429              :                     }
     430     42756729 :                     addToAllowed(vclass, allowedLanes, myAllowedTargets[target]);
     431              :                 }
     432              :             }
     433              :         }
     434              :     }
     435      1738060 :     if (updateVehicles) {
     436         1299 :         for (const MSLane* const lane : *myLanes) {
     437          758 :             const MSLane::VehCont& vehs = lane->getVehiclesSecure();
     438         2120 :             for (MSVehicle* veh : vehs) {
     439         1362 :                 veh->updateBestLanes(true);
     440              :             }
     441          758 :             lane->releaseVehicles();
     442              :         }
     443              :     }
     444              :     myClassesSuccessorMap.clear();
     445      1738060 : }
     446              : 
     447              : 
     448              : // ------------ Access to the edge's lanes
     449              : MSLane*
     450          870 : MSEdge::leftLane(const MSLane* const lane) const {
     451          870 :     return parallelLane(lane, 1);
     452              : }
     453              : 
     454              : 
     455              : MSLane*
     456          448 : MSEdge::rightLane(const MSLane* const lane) const {
     457          448 :     return parallelLane(lane, -1);
     458              : }
     459              : 
     460              : 
     461              : MSLane*
     462     64783979 : MSEdge::parallelLane(const MSLane* const lane, int offset, bool includeOpposite) const {
     463     64783979 :     const int resultIndex = lane->getIndex() + offset;
     464     64783979 :     if (resultIndex >= getNumLanes() && includeOpposite) {
     465     16264635 :         const MSEdge* opposite = getOppositeEdge();
     466     16264635 :         if (opposite != nullptr && resultIndex < getNumLanes() + opposite->getNumLanes()) {
     467      1357792 :             return opposite->getLanes()[opposite->getNumLanes() + getNumLanes() - resultIndex - 1];
     468              :         }
     469              :         return nullptr;
     470     48519344 :     } else if (resultIndex >= (int)myLanes->size() || resultIndex < 0) {
     471              :         return nullptr;
     472              :     } else {
     473     28111091 :         return (*myLanes)[resultIndex];
     474              :     }
     475              : }
     476              : 
     477              : 
     478              : const std::vector<MSLane*>*
     479     72005791 : MSEdge::allowedLanes(const MSEdge& destination, SUMOVehicleClass vclass, bool ignoreTransientPermissions) const {
     480     72005791 :     const auto& targets = ignoreTransientPermissions && myHaveTransientPermissions ? myOrigAllowedTargets : myAllowedTargets;
     481              :     AllowedLanesByTarget::const_iterator i = targets.find(&destination);
     482     72005791 :     if (i != targets.end()) {
     483     72012086 :         for (const auto& allowed : i->second) {
     484     71917552 :             if ((allowed.first & vclass) == vclass) {
     485              :                 return allowed.second.get();
     486              :             }
     487              :         }
     488              :     }
     489              :     return nullptr;
     490              : }
     491              : 
     492              : 
     493              : const std::vector<MSLane*>*
     494   2377206749 : MSEdge::allowedLanes(SUMOVehicleClass vclass) const {
     495   2377206749 :     if ((myMinimumPermissions & vclass) == vclass) {
     496    647110697 :         return myLanes.get();
     497              :     } else {
     498   1730096052 :         if ((myCombinedPermissions & vclass) == vclass) {
     499   3465910403 :             for (const auto& allowed : myAllowed) {
     500   3465910403 :                 if ((allowed.first & vclass) == vclass) {
     501              :                     return allowed.second.get();
     502              :                 }
     503              :             }
     504              :         }
     505         2004 :         return nullptr;
     506              :     }
     507              : }
     508              : 
     509              : 
     510              : // ------------
     511              : SUMOTime
     512          409 : MSEdge::incVaporization(SUMOTime) {
     513          409 :     ++myVaporizationRequests;
     514          409 :     return 0;
     515              : }
     516              : 
     517              : 
     518              : SUMOTime
     519           43 : MSEdge::decVaporization(SUMOTime) {
     520           43 :     --myVaporizationRequests;
     521           43 :     return 0;
     522              : }
     523              : 
     524              : 
     525              : MSLane*
     526    105609882 : MSEdge::getFreeLane(const std::vector<MSLane*>* allowed, const SUMOVehicleClass vclass, double departPos) const {
     527    105609882 :     if (allowed == nullptr) {
     528     72334571 :         allowed = allowedLanes(vclass);
     529              :     }
     530              :     MSLane* res = nullptr;
     531     72334571 :     if (allowed != nullptr) {
     532              :         double largestGap = 0;
     533              :         MSLane* resByGap = nullptr;
     534              :         double leastOccupancy = std::numeric_limits<double>::max();
     535    237193589 :         for (std::vector<MSLane*>::const_iterator i = allowed->begin(); i != allowed->end(); ++i) {
     536    131585630 :             const double occupancy = (*i)->getBruttoOccupancy();
     537    131585630 :             if (occupancy < leastOccupancy) {
     538    115185926 :                 res = (*i);
     539              :                 leastOccupancy = occupancy;
     540              :             }
     541    131585630 :             const MSVehicle* last = (*i)->getLastFullVehicle();
     542    131585630 :             const double lastGap = (last != nullptr ? last->getPositionOnLane() : myLength) - departPos;
     543    131585630 :             if (lastGap > largestGap) {
     544              :                 largestGap = lastGap;
     545     59685441 :                 resByGap = (*i);
     546              :             }
     547              :         }
     548    105607959 :         if (resByGap != nullptr) {
     549              :             //if (res != resByGap) std::cout << SIMTIME << " edge=" << getID() << " departPos=" << departPos << " res=" << Named::getIDSecure(res) << " resByGap=" << Named::getIDSecure(resByGap) << " largestGap=" << largestGap << "\n";
     550              :             res = resByGap;
     551              :         }
     552              :     }
     553    105609882 :     return res;
     554              : }
     555              : 
     556              : 
     557              : MSLane*
     558      2333752 : MSEdge::getProbableLane(const std::vector<MSLane*>* allowed, const SUMOVehicleClass vclass, double departPos, double maxSpeed) const {
     559      2333752 :     if (allowed == nullptr) {
     560            0 :         allowed = allowedLanes(vclass);
     561              :     }
     562              :     MSLane* res = nullptr;
     563            0 :     if (allowed != nullptr) {
     564              :         double largestGap = 0;
     565              :         double largestSpeed = 0;
     566              :         MSLane* resByGap = nullptr;
     567              :         double leastOccupancy = std::numeric_limits<double>::max();
     568              :         int aIndex = 0;
     569      8123261 :         for (std::vector<MSLane*>::const_iterator i = allowed->begin(); i != allowed->end(); ++i, aIndex++) {
     570      5789509 :             const double occupancy = (*i)->getBruttoOccupancy();
     571      5789509 :             if (occupancy < leastOccupancy) {
     572      5315384 :                 res = (*i);
     573              :                 leastOccupancy = occupancy;
     574              :             }
     575      5789509 :             const MSVehicle* last = (*i)->getLastFullVehicle();
     576      5789509 :             double lastGap = (last != nullptr ? last->getPositionOnLane() : myLength) - departPos;
     577              :             // never insert to the left of a vehicle with a larger speedFactor
     578      5789509 :             if (lastGap > largestGap && maxSpeed >= largestSpeed) {
     579              :                 largestGap = lastGap;
     580      3180460 :                 resByGap = (*i);
     581              :             }
     582      5789509 :             if (last != nullptr) {
     583      5788816 :                 largestSpeed = MAX2(largestSpeed, getVehicleMaxSpeed(last));
     584              :             }
     585              :         }
     586      2333752 :         if (resByGap != nullptr) {
     587              :             //if (res != resByGap) std::cout << SIMTIME << " edge=" << getID() << " departPos=" << departPos << " res=" << Named::getIDSecure(res) << " resByGap=" << Named::getIDSecure(resByGap) << " largestGap=" << largestGap << "\n";
     588              :             res = resByGap;
     589              :         }
     590              :     }
     591      2333752 :     return res;
     592              : }
     593              : 
     594              : 
     595              : double
     596    108024827 : MSEdge::getDepartPosBound(const MSVehicle& veh, bool upper) const {
     597    108024827 :     const SUMOVehicleParameter& pars = veh.getParameter();
     598              :     double pos = getLength();
     599              :     // determine the position
     600    108024827 :     switch (pars.departPosProcedure) {
     601      3077253 :         case DepartPosDefinition::GIVEN:
     602      3077253 :             pos = pars.departPos;
     603      3077253 :             if (pos < 0.) {
     604      2981267 :                 pos += myLength;
     605              :             }
     606              :             break;
     607              :         case DepartPosDefinition::RANDOM:
     608              :             // could be any position on the edge
     609              :             break;
     610              :         case DepartPosDefinition::RANDOM_FREE:
     611              :             // could be any position on the edge due to multiple random attempts
     612              :             break;
     613              :         case DepartPosDefinition::FREE:
     614              :             // many candidate positions, upper bound could be computed exactly
     615              :             // with much effort
     616              :             break;
     617       311844 :         case DepartPosDefinition::LAST:
     618       311844 :             if (upper) {
     619       464966 :                 for (std::vector<MSLane*>::const_iterator i = myLanes->begin(); i != myLanes->end(); ++i) {
     620       315522 :                     MSVehicle* last = (*i)->getLastFullVehicle();
     621       315522 :                     if (last != nullptr) {
     622       274490 :                         pos = MIN2(pos, last->getPositionOnLane());
     623              :                     }
     624              :                 }
     625              :             } else {
     626              :                 pos = 0;
     627              :             }
     628              :             break;
     629     50601890 :         case DepartPosDefinition::BASE:
     630              :         case DepartPosDefinition::DEFAULT:
     631     50601890 :             if (!upper) {
     632              :                 pos = 0;
     633              :             }
     634              :             break;
     635            8 :         default:
     636            8 :             pos = MIN2(pos, veh.getVehicleType().getLength());
     637              :             break;
     638              :     }
     639    108024827 :     return pos;
     640              : }
     641              : 
     642              : MSLane*
     643           39 : MSEdge::getDepartLaneMeso(SUMOVehicle& veh) const {
     644           39 :     if (veh.getParameter().departLaneProcedure == DepartLaneDefinition::GIVEN) {
     645            2 :         if ((int) myLanes->size() <= veh.getParameter().departLane || !(*myLanes)[veh.getParameter().departLane]->allowsVehicleClass(veh.getVehicleType().getVehicleClass())) {
     646            0 :             return nullptr;
     647              :         }
     648            2 :         return (*myLanes)[veh.getParameter().departLane];
     649              :     }
     650           37 :     return (*myLanes)[0];
     651              : }
     652              : 
     653              : MSLane*
     654   2245449083 : MSEdge::getDepartLane(MSVehicle& veh) const {
     655   2245449083 :     switch (veh.getParameter().departLaneProcedure) {
     656    100211081 :         case DepartLaneDefinition::GIVEN:
     657    100211081 :             if ((int) myLanes->size() <= veh.getParameter().departLane || !(*myLanes)[veh.getParameter().departLane]->allowsVehicleClass(veh.getVehicleType().getVehicleClass())) {
     658           62 :                 return nullptr;
     659              :             }
     660    100211019 :             return (*myLanes)[veh.getParameter().departLane];
     661     80108508 :         case DepartLaneDefinition::RANDOM:
     662    160217016 :             return RandHelper::getRandomFrom(*allowedLanes(veh.getVehicleType().getVehicleClass()));
     663     72236958 :         case DepartLaneDefinition::FREE:
     664     72236958 :             return getFreeLane(nullptr, veh.getVehicleType().getVehicleClass(), getDepartPosBound(veh, false));
     665      5489916 :         case DepartLaneDefinition::ALLOWED_FREE:
     666      5489916 :             if (veh.getRoute().size() == 1) {
     667         5906 :                 return getFreeLane(nullptr, veh.getVehicleType().getVehicleClass(), getDepartPosBound(veh, false));
     668              :             } else {
     669      5484010 :                 return getFreeLane(allowedLanes(**(veh.getRoute().begin() + 1), veh.getVehicleType().getVehicleClass()), veh.getVehicleType().getVehicleClass(), getDepartPosBound(veh, false));
     670              :             }
     671     29935328 :         case DepartLaneDefinition::BEST_FREE:
     672              :         case DepartLaneDefinition::BEST_PROB: {
     673     29935328 :             veh.updateBestLanes(false, myLanes->front());
     674     29935328 :             const std::vector<MSVehicle::LaneQ>& bl = veh.getBestLanes();
     675              :             double bestLength = -1;
     676     94265471 :             for (std::vector<MSVehicle::LaneQ>::const_iterator i = bl.begin(); i != bl.end(); ++i) {
     677     64330143 :                 if ((*i).length > bestLength) {
     678              :                     bestLength = (*i).length;
     679              :                 }
     680              :             }
     681              :             // beyond a certain length, all lanes are suitable
     682              :             // however, we still need to check departPos to avoid unsuitable insertion
     683              :             // (this is only possible in some cases)
     684              :             double departPos = 0;
     685     29935328 :             if (bestLength > BEST_LANE_LOOKAHEAD) {
     686       362625 :                 departPos = getDepartPosBound(veh);
     687       362625 :                 bestLength = MIN2(bestLength - departPos, BEST_LANE_LOOKAHEAD);
     688              :             }
     689     29935328 :             std::vector<MSLane*>* bestLanes = new std::vector<MSLane*>();
     690     94265471 :             for (std::vector<MSVehicle::LaneQ>::const_iterator i = bl.begin(); i != bl.end(); ++i) {
     691     64330143 :                 if (((*i).length - departPos) >= bestLength) {
     692     36306682 :                     if (isInternal()) {
     693           32 :                         for (MSLane* lane : *myLanes) {
     694           20 :                             if (lane->getNormalSuccessorLane() == (*i).lane) {
     695           12 :                                 bestLanes->push_back(lane);
     696              :                             }
     697              :                         }
     698              :                     } else {
     699     36306670 :                         bestLanes->push_back((*i).lane);
     700              :                     }
     701              :                 }
     702              :             }
     703              :             MSLane* ret = nullptr;
     704     29935328 :             if (veh.getParameter().departLaneProcedure == DepartLaneDefinition::BEST_FREE) {
     705     27601576 :                 ret = getFreeLane(bestLanes, veh.getVehicleType().getVehicleClass(), getDepartPosBound(veh, false));
     706              :             } else {
     707      2333752 :                 ret = getProbableLane(bestLanes, veh.getVehicleType().getVehicleClass(), getDepartPosBound(veh, false), getVehicleMaxSpeed(&veh));
     708              :             }
     709     29935328 :             delete bestLanes;
     710     29935328 :             return ret;
     711              :         }
     712   1957467292 :         case DepartLaneDefinition::DEFAULT:
     713              :         case DepartLaneDefinition::FIRST_ALLOWED:
     714   1957467292 :             return getFirstAllowed(veh.getVehicleType().getVehicleClass());
     715              :         default:
     716              :             break;
     717              :     }
     718            0 :     if (!(*myLanes)[0]->allowsVehicleClass(veh.getVehicleType().getVehicleClass())) {
     719              :         return nullptr;
     720              :     }
     721            0 :     return (*myLanes)[0];
     722              : }
     723              : 
     724              : 
     725              : MSLane*
     726   1958162648 : MSEdge::getFirstAllowed(SUMOVehicleClass vClass, bool defaultFirst) const {
     727   3409076560 :     for (std::vector<MSLane*>::const_iterator i = myLanes->begin(); i != myLanes->end(); ++i) {
     728   3409076560 :         if ((*i)->allowsVehicleClass(vClass)) {
     729              :             return *i;
     730              :         }
     731              :     }
     732            0 :     return defaultFirst && !myLanes->empty() ? myLanes->front() : nullptr;
     733              : }
     734              : 
     735              : 
     736              : bool
     737   2779719940 : MSEdge::validateDepartSpeed(SUMOVehicle& v) const {
     738   2779719940 :     const SUMOVehicleParameter& pars = v.getParameter();
     739   2779719940 :     const MSVehicleType& type = v.getVehicleType();
     740   2779719940 :     if (pars.departSpeedProcedure == DepartSpeedDefinition::GIVEN) {
     741              :         // departSpeed could have been rounded down in the output
     742    118024764 :         double vMax = getVehicleMaxSpeed(&v) + SPEED_EPS;
     743    118024764 :         if (pars.departSpeed > vMax) {
     744              :             // check departLane (getVehicleMaxSpeed checks lane 0)
     745        22578 :             MSLane* departLane = MSGlobals::gMesoNet ? getDepartLaneMeso(v) : getDepartLane(dynamic_cast<MSVehicle&>(v));
     746        22578 :             if (departLane != nullptr) {
     747        22578 :                 vMax = departLane->getVehicleMaxSpeed(&v);
     748        22578 :                 if (pars.wasSet(VEHPARS_SPEEDFACTOR_SET)) {
     749              :                     // speedFactor could have been rounded down in the output
     750            7 :                     vMax *= (1 + SPEED_EPS);
     751              :                 }
     752              :                 // additive term must come after multiplication!
     753        22578 :                 vMax += SPEED_EPS;
     754        22578 :                 if (pars.departSpeed > vMax) {
     755        22564 :                     const std::vector<double>& speedFactorParams = type.getSpeedFactor().getParameter();
     756        22564 :                     if (speedFactorParams[1] > 0.) {
     757        45090 :                         v.setChosenSpeedFactor(type.computeChosenSpeedDeviation(nullptr, pars.departSpeed / MIN2(getSpeedLimit(), type.getDesiredMaxSpeed() - SPEED_EPS)));
     758        22545 :                         if (v.getChosenSpeedFactor() > speedFactorParams[0] + 2 * speedFactorParams[1]) {
     759              :                             // only warn for significant deviation
     760        37140 :                             WRITE_WARNINGF(TL("Choosing new speed factor % for vehicle '%' to match departure speed % (max %)."),
     761              :                                            toString(v.getChosenSpeedFactor()), pars.id, pars.departSpeed, vMax);
     762              :                         }
     763              :                     } else {
     764              :                         return false;
     765              :                     }
     766              :                 }
     767              :             }
     768              :         }
     769              :     }
     770              :     return true;
     771              : }
     772              : 
     773              : 
     774              : bool
     775   2780281869 : MSEdge::insertVehicle(SUMOVehicle& v, SUMOTime time, const bool checkOnly, const bool forceCheck) const {
     776              :     // when vaporizing, no vehicles are inserted, but checking needs to be successful to trigger removal
     777   2780262807 :     if (isVaporizing() || isTazConnector()
     778   5559979166 :             || v.getRouteValidity(true, checkOnly) != MSBaseVehicle::ROUTE_VALID) {
     779       584639 :         return checkOnly;
     780              :     }
     781   2779697053 :     const SUMOVehicleParameter& pars = v.getParameter();
     782   2779697053 :     if (!validateDepartSpeed(v)) {
     783           14 :         const std::string errorMsg = "Departure speed for vehicle '" + pars.id + "' is too high for the departure edge '" + getID() + "'.";
     784           14 :         if (MSGlobals::gCheckRoutes) {
     785           14 :             throw ProcessError(errorMsg);
     786              :         } else {
     787           28 :             WRITE_WARNING(errorMsg);
     788              :         }
     789              :     }
     790   2779697046 :     if (MSGlobals::gUseMesoSim) {
     791    506323307 :         if (!forceCheck && myLastFailedInsertionTime == time) {
     792              :             return false;
     793              :         }
     794     27403852 :         double pos = 0.0;
     795     27403852 :         switch (pars.departPosProcedure) {
     796       571437 :             case DepartPosDefinition::GIVEN:
     797       571437 :                 if (pars.departPos >= 0.) {
     798       565767 :                     pos = pars.departPos;
     799              :                 } else {
     800         5670 :                     pos = pars.departPos + getLength();
     801              :                 }
     802       571437 :                 if (pos < 0 || pos > getLength()) {
     803            6 :                     WRITE_WARNING("Invalid departPos " + toString(pos) + " given for vehicle '" +
     804              :                                   v.getID() + "'. Inserting at lane end instead.");
     805            2 :                     pos = getLength();
     806              :                 }
     807              :                 break;
     808              :             case DepartPosDefinition::RANDOM:
     809              :             case DepartPosDefinition::RANDOM_FREE:
     810         6812 :                 pos = RandHelper::rand(getLength());
     811         6812 :                 break;
     812              :             default:
     813              :                 break;
     814              :         }
     815              :         bool result = false;
     816     27403852 :         MESegment* segment = MSGlobals::gMesoNet->getSegmentForEdge(*this, pos);
     817              :         MEVehicle* veh = static_cast<MEVehicle*>(&v);
     818              :         int qIdx;
     819     27403852 :         if (pars.departPosProcedure == DepartPosDefinition::FREE) {
     820       486320 :             while (segment != nullptr && !result) {
     821       447862 :                 if (checkOnly) {
     822            6 :                     result = segment->hasSpaceFor(veh, time, qIdx, true) == time;
     823              :                 } else {
     824       447856 :                     result = segment->initialise(veh, time);
     825              :                 }
     826              :                 segment = segment->getNextSegment();
     827              :             }
     828              :         } else {
     829     27365394 :             if (checkOnly) {
     830     25860869 :                 result = segment->hasSpaceFor(veh, time, qIdx, true) == time;
     831              :             } else {
     832      1504525 :                 result = segment->initialise(veh, time);
     833              :             }
     834              :         }
     835     27403850 :         return result;
     836              :     }
     837   2273373739 :     if (checkOnly) {
     838    692433553 :         switch (v.getParameter().departLaneProcedure) {
     839    614369188 :             case DepartLaneDefinition::GIVEN:
     840              :             case DepartLaneDefinition::DEFAULT:
     841              :             case DepartLaneDefinition::FIRST_ALLOWED: {
     842    614369188 :                 MSLane* insertionLane = getDepartLane(static_cast<MSVehicle&>(v));
     843    614369188 :                 if (insertionLane == nullptr) {
     844            0 :                     WRITE_WARNING("could not insert vehicle '" + v.getID() + "' on any lane of edge '" + getID() + "', time=" + time2string(MSNet::getInstance()->getCurrentTimeStep()));
     845            0 :                     return false;
     846              :                 }
     847    614369188 :                 const double occupancy = insertionLane->getBruttoOccupancy();
     848    614369188 :                 return (occupancy == 0 || occupancy * myLength + v.getVehicleType().getLengthWithGap() <= myLength ||
     849     12198715 :                         v.getParameter().departProcedure == DepartDefinition::SPLIT);
     850              :             }
     851     78064365 :             default:
     852     86238941 :                 for (std::vector<MSLane*>::const_iterator i = myLanes->begin(); i != myLanes->end(); ++i) {
     853     82391862 :                     const double occupancy = (*i)->getBruttoOccupancy();
     854     82391862 :                     if (occupancy == 0 || occupancy * myLength + v.getVehicleType().getLengthWithGap() <= myLength ||
     855      8174576 :                             v.getParameter().departProcedure == DepartDefinition::SPLIT) {
     856              :                         return true;
     857              :                     }
     858              :                 }
     859              :         }
     860              :         return false;
     861              :     }
     862   1580940186 :     MSLane* insertionLane = getDepartLane(static_cast<MSVehicle&>(v));
     863   1580940186 :     if (insertionLane == nullptr) {
     864              :         return false;
     865              :     }
     866              : 
     867   1580940186 :     if (!forceCheck) {
     868   1580940009 :         if (myLastFailedInsertionTime == time) {
     869              :             if (myFailedInsertionMemory.count(insertionLane->getIndex())) {
     870              :                 // A vehicle was already rejected for the proposed insertionLane in this timestep
     871              :                 return false;
     872              :             }
     873              :         } else {
     874              :             // last rejection occurred in a previous timestep, clear cache
     875              :             myFailedInsertionMemory.clear();
     876              :         }
     877              :     }
     878              : 
     879     11198931 :     bool success = insertionLane->insertVehicle(static_cast<MSVehicle&>(v));
     880              : 
     881     11198930 :     if (!success) {
     882              :         // constraints may enforce explicit re-ordering so we need to try other vehicles after failure
     883     16648340 :         if (!insertionLane->hasParameter("insertionOrder" + v.getID())) {
     884      8324023 :             myFailedInsertionMemory.insert(insertionLane->getIndex());
     885              :         }
     886              :     }
     887              :     return success;
     888              : }
     889              : 
     890              : 
     891              : void
     892     35839107 : MSEdge::changeLanes(SUMOTime t) const {
     893     35839107 :     if (myLaneChanger != nullptr) {
     894     35839107 :         myLaneChanger->laneChange(t);
     895              :     }
     896     35839107 : }
     897              : 
     898              : 
     899              : const MSEdge*
     900      2175380 : MSEdge::getInternalFollowingEdge(const MSEdge* followerAfterInternal, SUMOVehicleClass vClass) const {
     901              :     //@todo to be optimized
     902      2613063 :     for (const MSLane* const l : *myLanes) {
     903      3139667 :         for (const MSLink* const link : l->getLinkCont()) {
     904      2701984 :             if (&link->getLane()->getEdge() == followerAfterInternal) {
     905      1890449 :                 if (link->getViaLane() != nullptr) {
     906       989368 :                     if (link->getViaLane()->allowsVehicleClass(vClass)) {
     907       986956 :                         return &link->getViaLane()->getEdge();
     908              :                     } else {
     909         2412 :                         continue;
     910              :                     }
     911              :                 } else {
     912              :                     return nullptr; // network without internal links
     913              :                 }
     914              :             }
     915              :         }
     916              :     }
     917              :     return nullptr;
     918              : }
     919              : 
     920              : 
     921              : double
     922      1110309 : MSEdge::getInternalFollowingLengthTo(const MSEdge* followerAfterInternal, SUMOVehicleClass vClass) const {
     923              :     assert(followerAfterInternal != 0);
     924              :     assert(!followerAfterInternal->isInternal());
     925              :     double dist = 0.;
     926      1110309 :     const MSEdge* edge = getInternalFollowingEdge(followerAfterInternal, vClass);
     927              :     // Take into account non-internal lengths until next non-internal edge
     928      2035435 :     while (edge != nullptr && edge->isInternal()) {
     929       925126 :         dist += edge->getLength();
     930       925126 :         edge = edge->getInternalFollowingEdge(followerAfterInternal, vClass);
     931              :     }
     932      1110309 :     return dist;
     933              : }
     934              : 
     935              : 
     936              : const MSEdge*
     937       133554 : MSEdge::getNormalBefore() const {
     938              :     const MSEdge* result = this;
     939       141498 :     while (result->isInternal() && MSGlobals::gUsingInternalLanes) {
     940              :         assert(result->getPredecessors().size() == 1);
     941         7944 :         result = result->getPredecessors().front();
     942              :     }
     943       133554 :     return result;
     944              : }
     945              : 
     946              : const MSEdge*
     947      4788475 : MSEdge::getNormalSuccessor() const {
     948              :     const MSEdge* result = this;
     949      8942122 :     while (result->isInternal()) {
     950              :         assert(result->getSuccessors().size() == 1);
     951      4153647 :         result = result->getSuccessors().front();
     952              :     }
     953      4788475 :     return result;
     954              : }
     955              : 
     956              : double
     957    123208473 : MSEdge::getMeanSpeed() const {
     958              :     double v = 0;
     959              :     double totalNumVehs = 0;
     960    123208473 :     if (MSGlobals::gUseMesoSim) {
     961    144894353 :         for (MESegment* segment = MSGlobals::gMesoNet->getSegmentForEdge(*this); segment != nullptr; segment = segment->getNextSegment()) {
     962              :             const int numVehs = segment->getCarNumber();
     963    125734255 :             if (numVehs > 0) {
     964     23333243 :                 v += numVehs * segment->getMeanSpeed();
     965     23333243 :                 totalNumVehs += numVehs;
     966              :             }
     967              :         }
     968     19160098 :         if (totalNumVehs == 0) {
     969     11688694 :             return getLength() / myEmptyTraveltime; // may include tls-penalty
     970              :         }
     971              :     } else {
     972    249929603 :         for (const MSLane* const lane : *myLanes) {
     973              :             int numVehs = lane->getVehicleNumber();
     974    145881228 :             if (numVehs == 0) {
     975              :                 // take speed limit but with lowest possible weight
     976              :                 numVehs = 1;
     977              :             }
     978    145881228 :             v += numVehs * lane->getMeanSpeed();
     979    145881228 :             totalNumVehs += numVehs;
     980              :         }
     981    104048375 :         if (myBidiEdge != nullptr) {
     982      8067132 :             for (const MSLane* const lane : myBidiEdge->getLanes()) {
     983      4147626 :                 if (lane->getVehicleNumber() > 0) {
     984              :                     // do not route across edges which are already occupied in reverse direction
     985              :                     return 0;
     986              :                 }
     987              :             }
     988              :         }
     989    103820399 :         if (totalNumVehs == 0) {
     990            0 :             return getSpeedLimit();
     991              :         }
     992              :     }
     993    111291803 :     return v / totalNumVehs;
     994              : }
     995              : 
     996              : 
     997              : double
     998            0 : MSEdge::getMeanFriction() const {
     999              :     double f = 0.;
    1000            0 :     for (const MSLane* const lane : *myLanes) {
    1001            0 :         f += lane->getFrictionCoefficient();
    1002              :     }
    1003            0 :     if (!myLanes->empty()) {
    1004            0 :         return f / (double)myLanes->size();
    1005              :     }
    1006              :     return 1.;
    1007              : }
    1008              : 
    1009              : 
    1010              : double
    1011         1090 : MSEdge::getMeanSpeedBike() const {
    1012         1090 :     if (MSGlobals::gUseMesoSim) {
    1013              :         // no separate bicycle speeds in meso
    1014          362 :         return getMeanSpeed();
    1015              :     }
    1016              :     double v = 0;
    1017              :     double totalNumVehs = 0;
    1018         2404 :     for (const MSLane* const lane : *myLanes) {
    1019              :         const int numVehs = lane->getVehicleNumber();
    1020         1676 :         v += numVehs * lane->getMeanSpeedBike();
    1021         1676 :         totalNumVehs += numVehs;
    1022              :     }
    1023          728 :     if (totalNumVehs == 0) {
    1024          364 :         return getSpeedLimit();
    1025              :     }
    1026          364 :     return v / totalNumVehs;
    1027              : }
    1028              : 
    1029              : 
    1030              : double
    1031        52374 : MSEdge::getCurrentTravelTime(double minSpeed) const {
    1032              :     assert(minSpeed > 0);
    1033        52374 :     if (!myAmDelayed) {
    1034        34496 :         return myEmptyTraveltime;
    1035              :     }
    1036        35756 :     return getLength() / MAX2(minSpeed, getMeanSpeed());
    1037              : }
    1038              : 
    1039              : 
    1040              : double
    1041            0 : MSEdge::getRoutingSpeed() const {
    1042            0 :     return MSRoutingEngine::getAssumedSpeed(this, nullptr);
    1043              : }
    1044              : 
    1045              : 
    1046              : bool
    1047      1938240 : MSEdge::dictionary(const std::string& id, MSEdge* ptr) {
    1048              :     const DictType::iterator it = myDict.lower_bound(id);
    1049      1938240 :     if (it == myDict.end() || it->first != id) {
    1050              :         // id not in myDict
    1051      1938240 :         myDict.emplace_hint(it, id, ptr);
    1052      3876516 :         while (ptr->getNumericalID() >= (int)myEdges.size()) {
    1053      1938276 :             myEdges.push_back(nullptr);
    1054              :         }
    1055      1938240 :         myEdges[ptr->getNumericalID()] = ptr;
    1056      1938240 :         return true;
    1057              :     }
    1058              :     return false;
    1059              : }
    1060              : 
    1061              : 
    1062              : MSEdge*
    1063      8386004 : MSEdge::dictionary(const std::string& id) {
    1064              :     const DictType::iterator it = myDict.find(id);
    1065      8386004 :     if (it == myDict.end()) {
    1066              :         return nullptr;
    1067              :     }
    1068      6446535 :     return it->second;
    1069              : }
    1070              : 
    1071              : 
    1072              : MSEdge*
    1073      2759824 : MSEdge::dictionaryHint(const std::string& id, const int startIdx) {
    1074              :     // this method is mainly useful when parsing connections from the net.xml which are sorted by "from" id
    1075      2759824 :     if (myEdges[startIdx] != nullptr && myEdges[startIdx]->getID() == id) {
    1076              :         return myEdges[startIdx];
    1077              :     }
    1078      1635641 :     if (startIdx + 1 < (int)myEdges.size() && myEdges[startIdx + 1] != nullptr && myEdges[startIdx + 1]->getID() == id) {
    1079              :         return myEdges[startIdx + 1];
    1080              :     }
    1081       485335 :     return dictionary(id);
    1082              : }
    1083              : 
    1084              : 
    1085              : const MSEdgeVector&
    1086       821736 : MSEdge::getAllEdges() {
    1087       821736 :     return myEdges;
    1088              : }
    1089              : 
    1090              : 
    1091              : void
    1092        40327 : MSEdge::clear() {
    1093      1853184 :     for (DictType::iterator i = myDict.begin(); i != myDict.end(); ++i) {
    1094      1812857 :         delete (*i).second;
    1095              :     }
    1096              :     myDict.clear();
    1097              :     myEdges.clear();
    1098        40327 : }
    1099              : 
    1100              : 
    1101              : void
    1102          269 : MSEdge::insertIDs(std::vector<std::string>& into) {
    1103        15600 :     for (DictType::iterator i = myDict.begin(); i != myDict.end(); ++i) {
    1104        15331 :         into.push_back((*i).first);
    1105              :     }
    1106          269 : }
    1107              : 
    1108              : 
    1109              : void
    1110       371327 : MSEdge::parseEdgesList(const std::string& desc, ConstMSEdgeVector& into,
    1111              :                        const std::string& rid) {
    1112       371327 :     StringTokenizer st(desc);
    1113       371327 :     parseEdgesList(st.getVector(), into, rid);
    1114       371327 : }
    1115              : 
    1116              : 
    1117              : void
    1118       371595 : MSEdge::parseEdgesList(const std::vector<std::string>& desc, ConstMSEdgeVector& into,
    1119              :                        const std::string& rid) {
    1120      1491158 :     for (std::vector<std::string>::const_iterator i = desc.begin(); i != desc.end(); ++i) {
    1121      1119630 :         const MSEdge* edge = MSEdge::dictionary(*i);
    1122              :         // check whether the edge exists
    1123      1119630 :         if (edge == nullptr) {
    1124           67 :             throw ProcessError("The edge '" + *i + "' within the route " + rid + " is not known."
    1125          134 :                                + "\n The route can not be build.");
    1126              :         }
    1127      1119563 :         into.push_back(edge);
    1128              :     }
    1129       371528 : }
    1130              : 
    1131              : 
    1132              : double
    1133      1307823 : MSEdge::getDistanceTo(const MSEdge* other, const bool doBoundaryEstimate) const {
    1134              :     assert(this != other);
    1135      1307823 :     if (doBoundaryEstimate) {
    1136        18677 :         return myBoundary.distanceTo2D(other->myBoundary);
    1137              :     }
    1138      1289146 :     if (isTazConnector()) {
    1139          449 :         if (other->isTazConnector()) {
    1140          437 :             return myBoundary.distanceTo2D(other->myBoundary);
    1141              :         }
    1142           12 :         return myBoundary.distanceTo2D(other->getLanes()[0]->getShape()[0]);
    1143              :     }
    1144      1288697 :     if (other->isTazConnector()) {
    1145         5255 :         return other->myBoundary.distanceTo2D(getLanes()[0]->getShape()[-1]);
    1146              :     }
    1147      1283442 :     return getLanes()[0]->getShape()[-1].distanceTo2D(other->getLanes()[0]->getShape()[0]);
    1148              : }
    1149              : 
    1150              : 
    1151              : const Position
    1152         1519 : MSEdge::getStopPosition(const SUMOVehicleParameter::Stop& stop) {
    1153         1519 :     return MSLane::dictionary(stop.lane)->geometryPositionAtOffset((stop.endPos + stop.startPos) / 2.);
    1154              : }
    1155              : 
    1156              : 
    1157              : double
    1158     88518598 : MSEdge::getSpeedLimit() const {
    1159              :     // @note lanes might have different maximum speeds in theory
    1160     88518598 :     return myLanes->empty() ? 1 : getLanes()[0]->getSpeedLimit();
    1161              : }
    1162              : 
    1163              : 
    1164              : double
    1165      1857312 : MSEdge::getLengthGeometryFactor() const {
    1166      1857312 :     return myLanes->empty() ? 1 : getLanes()[0]->getLengthGeometryFactor();
    1167              : }
    1168              : 
    1169              : double
    1170    245616081 : MSEdge::getVehicleMaxSpeed(const SUMOTrafficObject* const veh) const {
    1171              :     // @note lanes might have different maximum speeds in theory
    1172    245616081 :     return myLanes->empty() ? 1 : getLanes()[0]->getVehicleMaxSpeed(veh);
    1173              : }
    1174              : 
    1175              : 
    1176              : void
    1177          189 : MSEdge::setMaxSpeed(double val, double jamThreshold) {
    1178              :     assert(val >= 0);
    1179          189 :     if (myLanes != nullptr) {
    1180          532 :         for (std::vector<MSLane*>::const_iterator i = myLanes->begin(); i != myLanes->end(); ++i) {
    1181          343 :             (*i)->setMaxSpeed(val, false, false, jamThreshold);
    1182              :         }
    1183              :     }
    1184          189 : }
    1185              : 
    1186              : 
    1187              : void
    1188      1219284 : MSEdge::addTransportable(MSTransportable* t) const {
    1189      1219284 :     if (t->isPerson()) {
    1190              :         myPersons.insert(t);
    1191              :     } else {
    1192              :         myContainers.insert(t);
    1193              :     }
    1194      1219284 : }
    1195              : 
    1196              : void
    1197      2129848 : MSEdge::removeTransportable(MSTransportable* t) const {
    1198      2129848 :     std::set<MSTransportable*, ComparatorNumericalIdLess>& tc = t->isPerson() ? myPersons : myContainers;
    1199              :     auto it = tc.find(t);
    1200      2129848 :     if (it != tc.end()) {
    1201              :         tc.erase(it);
    1202              :     }
    1203      2129848 : }
    1204              : 
    1205              : std::vector<MSTransportable*>
    1206      7178265 : MSEdge::getSortedPersons(SUMOTime timestep, bool includeRiding) const {
    1207      7178265 :     std::vector<MSTransportable*> result(myPersons.begin(), myPersons.end());
    1208      7178265 :     if (includeRiding) {
    1209      2347915 :         for (std::vector<MSLane*>::const_iterator i = myLanes->begin(); i != myLanes->end(); ++i) {
    1210      1656344 :             const MSLane::VehCont& vehs = (*i)->getVehiclesSecure();
    1211      2879978 :             for (MSLane::VehCont::const_iterator j = vehs.begin(); j != vehs.end(); ++j) {
    1212      1223634 :                 const std::vector<MSTransportable*>& persons = (*j)->getPersons();
    1213      1223634 :                 result.insert(result.end(), persons.begin(), persons.end());
    1214              :             }
    1215      1656344 :             (*i)->releaseVehicles();
    1216              :         }
    1217              :     }
    1218      7178265 :     sort(result.begin(), result.end(), transportable_by_position_sorter(timestep));
    1219      7178265 :     return result;
    1220            0 : }
    1221              : 
    1222              : 
    1223              : std::vector<MSTransportable*>
    1224      4235804 : MSEdge::getSortedContainers(SUMOTime timestep, bool /* includeRiding */) const {
    1225      4235804 :     std::vector<MSTransportable*> result(myContainers.begin(), myContainers.end());
    1226      4235804 :     sort(result.begin(), result.end(), transportable_by_position_sorter(timestep));
    1227      4235804 :     return result;
    1228            0 : }
    1229              : 
    1230              : 
    1231              : int
    1232      5073950 : MSEdge::transportable_by_position_sorter::operator()(const MSTransportable* const c1, const MSTransportable* const c2) const {
    1233      5073950 :     const double pos1 = c1->getCurrentStage()->getEdgePos(myTime);
    1234      5073950 :     const double pos2 = c2->getCurrentStage()->getEdgePos(myTime);
    1235      5073950 :     if (pos1 != pos2) {
    1236      4918366 :         return pos1 < pos2;
    1237              :     }
    1238       155584 :     return c1->getID() < c2->getID();
    1239              : }
    1240              : 
    1241              : 
    1242              : void
    1243       425435 : MSEdge::addSuccessor(MSEdge* edge, const MSEdge* via) {
    1244       425435 :     mySuccessors.push_back(edge);
    1245       425435 :     myViaSuccessors.push_back(std::make_pair(edge, via));
    1246       425435 :     if (isTazConnector() && edge->getFromJunction() != nullptr) {
    1247       212714 :         myBoundary.add(edge->getFromJunction()->getPosition());
    1248              :     }
    1249              : 
    1250       425435 :     edge->myPredecessors.push_back(this);
    1251       425435 :     if (edge->isTazConnector() && getToJunction() != nullptr) {
    1252       212721 :         edge->myBoundary.add(getToJunction()->getPosition());
    1253              :     }
    1254       425435 : }
    1255              : 
    1256              : 
    1257              : const MSEdgeVector&
    1258      7040972 : MSEdge::getSuccessors(SUMOVehicleClass vClass) const {
    1259      7040972 :     if (vClass == SVC_IGNORING || !MSNet::getInstance()->hasPermissions() || myFunction == SumoXMLEdgeFunc::CONNECTOR) {
    1260      7035008 :         return mySuccessors;
    1261              :     }
    1262              : #ifdef HAVE_FOX
    1263         5964 :     ScopedLocker<> lock(mySuccessorMutex, MSGlobals::gNumThreads > 1);
    1264              : #endif
    1265              :     std::map<SUMOVehicleClass, MSEdgeVector>::iterator i = myClassesSuccessorMap.find(vClass);
    1266         5964 :     if (i == myClassesSuccessorMap.end()) {
    1267              :         // instantiate vector
    1268         1320 :         myClassesSuccessorMap[vClass];
    1269              :         i = myClassesSuccessorMap.find(vClass);
    1270              :         // this vClass is requested for the first time. rebuild all successors
    1271         6371 :         for (MSEdgeVector::const_iterator it = mySuccessors.begin(); it != mySuccessors.end(); ++it) {
    1272         5051 :             if ((*it)->isTazConnector()) {
    1273          239 :                 i->second.push_back(*it);
    1274              :             } else {
    1275         4812 :                 const std::vector<MSLane*>* allowed = allowedLanes(**it, vClass);
    1276         4812 :                 if (allowed != nullptr && allowed->size() > 0) {
    1277         3998 :                     i->second.push_back(*it);
    1278              :                 }
    1279              :             }
    1280              :         }
    1281              :     }
    1282              :     // can use cached value
    1283         5964 :     return i->second;
    1284              : }
    1285              : 
    1286              : 
    1287              : const MSConstEdgePairVector&
    1288    100246016 : MSEdge::getViaSuccessors(SUMOVehicleClass vClass, bool ignoreTransientPermissions) const {
    1289    100246016 :     if (vClass == SVC_IGNORING || !MSNet::getInstance()->hasPermissions() || myFunction == SumoXMLEdgeFunc::CONNECTOR) {
    1290     94986146 :         return myViaSuccessors;
    1291              :     }
    1292              : #ifdef HAVE_FOX
    1293      5259870 :     ScopedLocker<> lock(mySuccessorMutex, MSGlobals::gNumThreads > 1);
    1294              : #endif
    1295      5259870 :     auto& viaMap = ignoreTransientPermissions && myHaveTransientPermissions ? myOrigClassesViaSuccessorMap : myClassesViaSuccessorMap;
    1296              :     auto i = viaMap.find(vClass);
    1297      5259870 :     if (i != viaMap.end()) {
    1298              :         // can use cached value
    1299      5215767 :         return i->second;
    1300              :     }
    1301              :     // instantiate vector
    1302        44103 :     MSConstEdgePairVector& result = viaMap[vClass];
    1303              :     // this vClass is requested for the first time. rebuild all successors
    1304       183439 :     for (const auto& viaPair : myViaSuccessors) {
    1305       139336 :         if (viaPair.first->isTazConnector()) {
    1306        10271 :             result.push_back(viaPair);
    1307              :         } else {
    1308       129065 :             const std::vector<MSLane*>* allowed = allowedLanes(*viaPair.first, vClass, ignoreTransientPermissions);
    1309       129065 :             if (allowed != nullptr && allowed->size() > 0) {
    1310       102157 :                 result.push_back(viaPair);
    1311              :             }
    1312              :         }
    1313              :     }
    1314              :     return result;
    1315              : }
    1316              : 
    1317              : 
    1318              : void
    1319      1737559 : MSEdge::setJunctions(MSJunction* from, MSJunction* to) {
    1320      1737559 :     myFromJunction = from;
    1321      1737559 :     myToJunction = to;
    1322      1737559 :     if (!isTazConnector()) {
    1323      1737559 :         myBoundary.add(from->getPosition());
    1324      1737559 :         myBoundary.add(to->getPosition());
    1325              :     }
    1326      1737559 : }
    1327              : 
    1328              : 
    1329              : bool
    1330      2773340 : MSEdge::canChangeToOpposite() const {
    1331      2773340 :     return (!myLanes->empty() && myLanes->back()->getOpposite() != nullptr &&
    1332              :             // do not change on curved internal lanes
    1333              :             (!isInternal()
    1334         5481 :              || (MSGlobals::gUsingInternalLanes
    1335         5477 :                  && myLanes->back()->getIncomingLanes()[0].viaLink->getDirection() == LinkDirection::STRAIGHT)));
    1336              : }
    1337              : 
    1338              : 
    1339              : const MSEdge*
    1340     18013107 : MSEdge::getOppositeEdge() const {
    1341     18013107 :     if (!myLanes->empty() && myLanes->back()->getOpposite() != nullptr) {
    1342      2970902 :         return &(myLanes->back()->getOpposite()->getEdge());
    1343              :     } else {
    1344     15042205 :         return nullptr;
    1345              :     }
    1346              : }
    1347              : 
    1348              : 
    1349              : bool
    1350          178 : MSEdge::hasMinorLink() const {
    1351          370 :     for (const MSLane* const l : *myLanes) {
    1352          290 :         for (const MSLink* const link : l->getLinkCont()) {
    1353           98 :             if (!link->havePriority()) {
    1354              :                 return true;
    1355              :             }
    1356              :         }
    1357              :     }
    1358              :     return false;
    1359              : }
    1360              : 
    1361              : bool
    1362      1036763 : MSEdge::hasChangeProhibitions(SUMOVehicleClass svc, int index) const {
    1363      1036763 :     if (myLanes->size() == 1) {
    1364              :         return false;
    1365              :     }
    1366      2385562 :     for (const MSLane* const l : *myLanes) {
    1367      1596894 :         if (l->getIndex() <= index && !l->allowsChangingRight(svc) && l->getIndex() > 0) {
    1368              :             return true;
    1369      1596806 :         } else if (l->getIndex() >= index && !l->allowsChangingLeft(svc) && l->getIndex() < (int)(myLanes->size() - 1)) {
    1370              :             return true;
    1371              :         }
    1372              :     }
    1373              :     return false;
    1374              : }
    1375              : 
    1376              : void
    1377      1075769 : MSEdge::checkAndRegisterBiDirEdge(const std::string& bidiID) {
    1378      1075769 :     if (bidiID != "") {
    1379        24894 :         myBidiEdge = dictionary(bidiID);
    1380        24894 :         if (myBidiEdge == nullptr) {
    1381            0 :             WRITE_ERRORF(TL("Bidi-edge '%' does not exist"), bidiID);
    1382              :         }
    1383        24894 :         setBidiLanes();
    1384       638924 :         return;
    1385              :     }
    1386      1050875 :     if (getFunction() != SumoXMLEdgeFunc::NORMAL) {
    1387              :         return;
    1388              :     }
    1389              :     // legacy networks (no bidi attribute)
    1390       436845 :     ConstMSEdgeVector candidates = myToJunction->getOutgoing();
    1391      3584739 :     for (ConstMSEdgeVector::const_iterator it = candidates.begin(); it != candidates.end(); it++) {
    1392      3147894 :         if ((*it)->getToJunction() == myFromJunction) { //reverse edge
    1393       292008 :             if (myBidiEdge != nullptr && isSuperposable(*it)) {
    1394            0 :                 WRITE_WARNINGF(TL("Ambiguous superposable edges between junction '%' and '%'."), myToJunction->getID(), myFromJunction->getID());
    1395            0 :                 break;
    1396              :             }
    1397       292008 :             if (isSuperposable(*it)) {
    1398           26 :                 myBidiEdge = *it;
    1399           26 :                 setBidiLanes();
    1400              :             }
    1401              :         }
    1402              :     }
    1403       436845 : }
    1404              : 
    1405              : 
    1406              : void
    1407        24920 : MSEdge::setBidiLanes() {
    1408              :     assert(myBidiEdge != nullptr);
    1409        24920 :     if (getNumLanes() == 1 && myBidiEdge->getNumLanes() == 1) {
    1410              :         // the other way round is set when this method runs for the bidiEdge
    1411        24382 :         getLanes()[0]->setBidiLane(myBidiEdge->getLanes()[0]);
    1412              :     } else {
    1413              :         // find lanes with matching reversed shapes
    1414              :         int numBidiLanes = 0;
    1415         1680 :         for (MSLane* l1 : *myLanes) {
    1416         3630 :             for (MSLane* l2 : *myBidiEdge->myLanes) {
    1417         2488 :                 if (l1->getShape().reverse().almostSame(l2->getShape(), POSITION_EPS * 2)) {
    1418          592 :                     l1->setBidiLane(l2);
    1419          592 :                     numBidiLanes++;
    1420              :                 }
    1421              :             }
    1422              :         }
    1423              :         // warn only once for each pair
    1424          538 :         if (numBidiLanes == 0 && getNumericalID() < myBidiEdge->getNumericalID()) {
    1425           15 :             WRITE_WARNINGF(TL("Edge '%s' and bidi edge '%s' have no matching bidi lanes"), getID(), myBidiEdge->getID());
    1426              :         }
    1427              :     }
    1428        24920 : }
    1429              : 
    1430              : 
    1431              : bool
    1432       292008 : MSEdge::isSuperposable(const MSEdge* other) {
    1433       292008 :     if (other == nullptr || other->getLanes().size() != myLanes->size()) {
    1434              :         return false;
    1435              :     }
    1436              :     std::vector<MSLane*>::const_iterator it1 = myLanes->begin();
    1437              :     std::vector<MSLane*>::const_reverse_iterator it2 = other->getLanes().rbegin();
    1438              :     do {
    1439       287766 :         if ((*it1)->getShape().reverse() != (*it2)->getShape()) {
    1440              :             return false;
    1441              :         }
    1442              :         it1++;
    1443              :         it2++;
    1444           26 :     } while (it1 != myLanes->end());
    1445              : 
    1446              :     return true;
    1447              : }
    1448              : 
    1449              : 
    1450              : void
    1451        64987 : MSEdge::addWaiting(SUMOVehicle* vehicle) const {
    1452              : #ifdef HAVE_FOX
    1453        64987 :     ScopedLocker<> lock(myWaitingMutex, MSGlobals::gNumSimThreads > 1);
    1454              : #endif
    1455        64987 :     myWaiting.push_back(vehicle);
    1456        64987 : }
    1457              : 
    1458              : 
    1459              : void
    1460        57426 : MSEdge::removeWaiting(const SUMOVehicle* vehicle) const {
    1461              : #ifdef HAVE_FOX
    1462        57426 :     ScopedLocker<> lock(myWaitingMutex, MSGlobals::gNumSimThreads > 1);
    1463              : #endif
    1464        57426 :     std::vector<SUMOVehicle*>::iterator it = std::find(myWaiting.begin(), myWaiting.end(), vehicle);
    1465        57426 :     if (it != myWaiting.end()) {
    1466        57009 :         myWaiting.erase(it);
    1467              :     }
    1468        57426 : }
    1469              : 
    1470              : 
    1471              : SUMOVehicle*
    1472        75834 : MSEdge::getWaitingVehicle(MSTransportable* transportable, const double position) const {
    1473              : #ifdef HAVE_FOX
    1474        75834 :     ScopedLocker<> lock(myWaitingMutex, MSGlobals::gNumSimThreads > 1);
    1475              : #endif
    1476        76149 :     for (SUMOVehicle* const vehicle : myWaiting) {
    1477         5097 :         if (transportable->isWaitingFor(vehicle)) {
    1478         7192 :             if (vehicle->isStoppedInRange(position, MSGlobals::gStopTolerance) ||
    1479         2208 :                     (!vehicle->hasDeparted() &&
    1480         2010 :                      (vehicle->getParameter().departProcedure == DepartDefinition::TRIGGERED ||
    1481           83 :                       vehicle->getParameter().departProcedure == DepartDefinition::CONTAINER_TRIGGERED))) {
    1482              :                 return vehicle;
    1483              :             }
    1484          202 :             if (!vehicle->isLineStop(position) && vehicle->allowsBoarding(transportable)) {
    1485          228 :                 WRITE_WARNING((transportable->isPerson() ? "Person '" : "Container '")
    1486              :                               + transportable->getID() + "' at edge '" + getID() + "' position " + toString(position) + " cannot use waiting vehicle '"
    1487              :                               + vehicle->getID() + "' at position " + toString(vehicle->getPositionOnLane()) + " because it is too far away.");
    1488              :             }
    1489              :         }
    1490              :     }
    1491              :     return nullptr;
    1492              : }
    1493              : 
    1494              : std::vector<const SUMOVehicle*>
    1495       106231 : MSEdge::getVehicles() const {
    1496              :     std::vector<const SUMOVehicle*> result;
    1497       106231 :     if (MSGlobals::gUseMesoSim) {
    1498          140 :         for (MESegment* segment = MSGlobals::gMesoNet->getSegmentForEdge(*this); segment != nullptr; segment = segment->getNextSegment()) {
    1499           80 :             std::vector<const MEVehicle*> segmentVehs = segment->getVehicles();
    1500           80 :             result.insert(result.end(), segmentVehs.begin(), segmentVehs.end());
    1501           80 :         }
    1502              :     } else {
    1503       285770 :         for (MSLane* lane : getLanes()) {
    1504       655373 :             for (auto veh : lane->getVehiclesSecure()) {
    1505       475804 :                 result.push_back(veh);
    1506              :             }
    1507       179569 :             lane->releaseVehicles();
    1508              :         }
    1509              :     }
    1510       106231 :     return result;
    1511            0 : }
    1512              : 
    1513              : int
    1514       453919 : MSEdge::getNumDrivingLanes() const {
    1515              :     int result = 0;
    1516       453919 :     SVCPermissions filter = SVCAll;
    1517       453919 :     if ((myCombinedPermissions & ~(SVC_PEDESTRIAN | SVC_WHEELCHAIR)) != 0) {
    1518              :         filter = ~(SVC_PEDESTRIAN | SVC_WHEELCHAIR);
    1519           96 :     } else if ((myCombinedPermissions & (SVC_PEDESTRIAN | SVC_WHEELCHAIR)) != 0) {
    1520              :         // filter out green verge
    1521              :         filter = (SVC_PEDESTRIAN | SVC_WHEELCHAIR);
    1522              :     }
    1523       958112 :     for (const MSLane* const l : *myLanes) {
    1524       504193 :         if ((l->getPermissions() & filter) != 0) {
    1525       502582 :             result++;
    1526              :         }
    1527              :     }
    1528       453919 :     return result;
    1529              : }
    1530              : 
    1531              : int
    1532          653 : MSEdge::getVehicleNumber() const {
    1533          653 :     return (int)getVehicles().size();
    1534              : }
    1535              : 
    1536              : 
    1537              : bool
    1538            0 : MSEdge::isEmpty() const {
    1539              :     /// more efficient than retrieving vehicle number
    1540            0 :     if (MSGlobals::gUseMesoSim) {
    1541            0 :         for (MESegment* segment = MSGlobals::gMesoNet->getSegmentForEdge(*this); segment != nullptr; segment = segment->getNextSegment()) {
    1542            0 :             if (segment->getCarNumber() > 0) {
    1543              :                 return false;
    1544              :             }
    1545              :         }
    1546              :     } else {
    1547            0 :         for (MSLane* lane : getLanes()) {
    1548            0 :             if (lane->getVehicleNumber() > 0) {
    1549              :                 return false;
    1550              :             }
    1551              :         }
    1552              :     }
    1553              :     return true;
    1554              : }
    1555              : 
    1556              : 
    1557              : double
    1558            6 : MSEdge::getWaitingSeconds() const {
    1559              :     double wtime = 0;
    1560            6 :     if (MSGlobals::gUseMesoSim) {
    1561            4 :         for (MESegment* segment = MSGlobals::gMesoNet->getSegmentForEdge(*this); segment != nullptr; segment = segment->getNextSegment()) {
    1562            3 :             wtime += segment->getWaitingSeconds();
    1563              :         }
    1564              :     } else {
    1565           10 :         for (MSLane* lane : getLanes()) {
    1566            5 :             wtime += lane->getWaitingSeconds();
    1567              :         }
    1568              :     }
    1569            6 :     return wtime;
    1570              : }
    1571              : 
    1572              : 
    1573              : double
    1574           14 : MSEdge::getOccupancy() const {
    1575           14 :     if (myLanes->size() == 0) {
    1576              :         return 0;
    1577              :     }
    1578           14 :     if (MSGlobals::gUseMesoSim) {
    1579              :         /// @note MESegment only tracks brutto occupancy so we compute this from sratch
    1580              :         double sum = 0;
    1581            4 :         for (const SUMOVehicle* veh : getVehicles()) {
    1582            2 :             sum += dynamic_cast<const MEVehicle*>(veh)->getVehicleType().getLength();
    1583            2 :         }
    1584            2 :         return sum / (myLength * (double)myLanes->size());
    1585              :     } else {
    1586              :         double sum = 0;
    1587           24 :         for (auto lane : getLanes()) {
    1588           12 :             sum += lane->getNettoOccupancy();
    1589              :         }
    1590           12 :         return sum / (double)myLanes->size();
    1591              :     }
    1592              : }
    1593              : 
    1594              : 
    1595              : double
    1596            0 : MSEdge::getFlow() const {
    1597            0 :     if (myLanes->size() == 0) {
    1598              :         return 0;
    1599              :     }
    1600              :     double flow = 0;
    1601            0 :     for (MESegment* segment = MSGlobals::gMesoNet->getSegmentForEdge(*this); segment != nullptr; segment = segment->getNextSegment()) {
    1602            0 :         flow += (double) segment->getCarNumber() * segment->getMeanSpeed();
    1603              :     }
    1604            0 :     return 3600 * flow / (*myLanes)[0]->getLength();
    1605              : }
    1606              : 
    1607              : 
    1608              : double
    1609            0 : MSEdge::getBruttoOccupancy() const {
    1610            0 :     if (myLanes->size() == 0) {
    1611              :         return 0;
    1612              :     }
    1613              :     double occ = 0;
    1614            0 :     for (MESegment* segment = MSGlobals::gMesoNet->getSegmentForEdge(*this); segment != nullptr; segment = segment->getNextSegment()) {
    1615            0 :         occ += segment->getBruttoOccupancy();
    1616              :     }
    1617            0 :     return occ / (*myLanes)[0]->getLength() / (double)(myLanes->size());
    1618              : }
    1619              : 
    1620              : double
    1621         4240 : MSEdge::getTravelTimeAggregated(const MSEdge* const edge, const SUMOVehicle* const veh, double /*time*/) {
    1622         4240 :     return edge->getLength() / MIN2(MSRoutingEngine::getAssumedSpeed(edge, veh), veh->getMaxSpeed());
    1623              : }
    1624              : 
    1625              : 
    1626              : void
    1627         2098 : MSEdge::inferEdgeType() {
    1628              :     // @note must be called after closeBuilding() to ensure successors and
    1629              :     // predecessors are set
    1630         2098 :     if (isInternal() && myEdgeType == "") {
    1631         1274 :         const std::string typeBefore = getNormalBefore()->getEdgeType();
    1632         1274 :         if (typeBefore != "") {
    1633          622 :             const std::string typeAfter = getNormalSuccessor()->getEdgeType();
    1634          622 :             if (typeBefore == typeAfter) {
    1635              :                 myEdgeType = typeBefore;
    1636          244 :             } else if (typeAfter != "") {
    1637           60 :                 MSNet* net = MSNet::getInstance();
    1638           60 :                 auto resBefore = net->getRestrictions(typeBefore);
    1639           60 :                 auto resAfter = net->getRestrictions(typeAfter);
    1640           60 :                 if (resBefore != nullptr && resAfter != nullptr) {
    1641              :                     // create new restrictions for this type-combination
    1642           80 :                     myEdgeType = typeBefore + "|" + typeAfter;
    1643           40 :                     if (net->getRestrictions(myEdgeType) == nullptr) {
    1644           40 :                         for (const auto& item : *resBefore) {
    1645           20 :                             const SUMOVehicleClass svc = item.first;
    1646           20 :                             const double speed = item.second;
    1647              :                             const auto it = (*resAfter).find(svc);
    1648           20 :                             if (it != (*resAfter).end()) {
    1649           20 :                                 const double speed2 = it->second;
    1650           20 :                                 const double newSpeed = (MSNet::getInstance()->hasJunctionHigherSpeeds()
    1651           20 :                                                          ? MAX2(speed, speed2) : (speed + speed2) / 2);
    1652           20 :                                 net->addRestriction(myEdgeType, svc, newSpeed);
    1653              :                             }
    1654              :                         }
    1655              :                     }
    1656              :                 }
    1657              :             }
    1658              :         }
    1659              :     }
    1660         2098 : }
    1661              : 
    1662              : 
    1663              : double
    1664         2134 : MSEdge::getDistanceAt(double pos) const {
    1665              :     // negative values of myDistances indicate descending kilometrage
    1666         2134 :     return fabs(myDistance + pos);
    1667              : }
    1668              : 
    1669              : 
    1670              : bool
    1671          101 : MSEdge::hasTransientPermissions() const {
    1672          101 :     return myHaveTransientPermissions;
    1673              : }
    1674              : 
    1675              : 
    1676              : void
    1677         7833 : MSEdge::clearState() {
    1678              :     myPersons.clear();
    1679              :     myContainers.clear();
    1680              :     myWaiting.clear();
    1681         7833 : }
    1682              : 
    1683              : /****************************************************************************/
        

Generated by: LCOV version 2.0-1