LCOV - code coverage report
Current view: top level - src/microsim - MSEdge.cpp (source / functions) Coverage Total Hit
Test: lcov.info Lines: 95.6 % 780 746
Test Date: 2026-01-01 15:49:29 Functions: 95.5 % 89 85

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

Generated by: LCOV version 2.0-1