LCOV - code coverage report
Current view: top level - src/microsim - MSEdge.cpp (source / functions) Coverage Total Hit
Test: lcov.info Lines: 95.6 % 779 745
Test Date: 2026-04-16 16:39:47 Functions: 95.5 % 88 84

            Line data    Source code
       1              : /****************************************************************************/
       2              : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
       3              : // Copyright (C) 2001-2026 German Aerospace Center (DLR) and others.
       4              : // This program and the accompanying materials are made available under the
       5              : // terms of the Eclipse Public License 2.0 which is available at
       6              : // https://www.eclipse.org/legal/epl-2.0/
       7              : // This Source Code may also be made available under the following Secondary
       8              : // Licenses when the conditions for such availability set forth in the Eclipse
       9              : // Public License 2.0 are satisfied: GNU General Public License, version 2
      10              : // or later which is available at
      11              : // https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html
      12              : // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
      13              : /****************************************************************************/
      14              : /// @file    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      1953335 : 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      1953335 :                double distance) :
      75      1953335 :     Named(id), myNumericalID(numericalID), myLanes(nullptr),
      76      1953335 :     myLaneChanger(nullptr), myFunction(function), myVaporizationRequests(0),
      77      1953335 :     myLastFailedInsertionTime(-1),
      78      1953335 :     myFromJunction(nullptr), myToJunction(nullptr),
      79      1953335 :     myHaveTransientPermissions(false),
      80      1953335 :     myOtherTazConnector(nullptr),
      81      1953335 :     myStreetName(streetName),
      82      1953335 :     myEdgeType(edgeType),
      83      1953335 :     myRoutingType(routingType),
      84      1953335 :     myPriority(priority),
      85      1953335 :     myDistance(distance),
      86      1953335 :     myWidth(0.),
      87      1953335 :     myLength(0.),
      88      1953335 :     myEmptyTraveltime(0.),
      89      1953335 :     myTimePenalty(0.),
      90      1953335 :     myAmDelayed(false),
      91      1953335 :     myAmRoundabout(false),
      92      1953335 :     myAmFringe(true),
      93      3906670 :     myBidiEdge(nullptr)
      94      1953335 : { }
      95              : 
      96              : 
      97      3370581 : MSEdge::~MSEdge() {
      98      1938423 :     delete myLaneChanger;
      99      1938423 :     delete myReversedRoutingEdge;
     100      1938423 :     delete myRailwayRoutingEdge;
     101     11124273 : }
     102              : 
     103              : 
     104              : void
     105      1819512 : MSEdge::initialize(const std::vector<MSLane*>* lanes) {
     106              :     assert(lanes != 0);
     107      1819512 :     myLanes = std::shared_ptr<const std::vector<MSLane*> >(lanes);
     108      1819512 :     if (myFunction == SumoXMLEdgeFunc::CONNECTOR) {
     109        70010 :         myCombinedPermissions = SVCAll;
     110              :     }
     111      3923267 :     for (MSLane* const lane : *lanes) {
     112      2103755 :         lane->setRightSideOnEdge(myWidth, (int)mySublaneSides.size());
     113      2103755 :         MSLeaderInfo ahead(lane->getWidth());
     114      4910093 :         for (int j = 0; j < ahead.numSublanes(); ++j) {
     115      2806338 :             mySublaneSides.push_back(myWidth + j * MSGlobals::gLateralResolution);
     116              :         }
     117      2103755 :         myWidth += lane->getWidth();
     118      2103755 :     }
     119      1819512 : }
     120              : 
     121              : 
     122      1837947 : void MSEdge::recalcCache() {
     123      1837947 :     if (myLanes->empty()) {
     124              :         return;
     125              :     }
     126      1837947 :     myLength = myLanes->front()->getLength();
     127      3675894 :     myEmptyTraveltime = myLength / MAX2(getSpeedLimit(), NUMERICAL_EPS);
     128      1837947 :     if (isNormal() && (MSGlobals::gUseMesoSim || MSGlobals::gTLSPenalty > 0)) {
     129              :         SUMOTime minorPenalty = 0;
     130       179322 :         bool haveTLSPenalty = MSGlobals::gTLSPenalty > 0;
     131       179322 :         if (MSGlobals::gUseMesoSim) {
     132       179207 :             const MESegment::MesoEdgeType& edgeType = MSNet::getInstance()->getMesoType(getEdgeType());
     133       179207 :             minorPenalty = edgeType.minorPenalty;
     134       179207 :             haveTLSPenalty = edgeType.tlsPenalty > 0;
     135              :         }
     136       179322 :         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      1658625 :     } else if (isCrossing() && MSGlobals::gTLSPenalty > 0) {
     158              :         // penalties are recorded for the entering link
     159          112 :         for (const auto& ili : myLanes->front()->getIncomingLanes()) {
     160           56 :             double penalty = STEPS2TIME(ili.viaLink->getMesoTLSPenalty());
     161           56 :             if (!ili.viaLink->haveOffPriority()) {
     162            0 :                 penalty = MAX2(penalty, MSGlobals::gMinorPenalty);
     163              :             }
     164           56 :             if (penalty > 0) {
     165           20 :                 myEmptyTraveltime += penalty;
     166           20 :                 myTimePenalty = penalty;
     167              :             }
     168              :         }
     169      1658569 :     } else if (isInternal() && MSGlobals::gUsingInternalLanes) {
     170       963388 :         const MSLink* link = myLanes->front()->getIncomingLanes()[0].viaLink;
     171       963388 :         if (!link->isTLSControlled() && !link->havePriority()) {
     172       478099 :             if (link->isTurnaround()) {
     173       181350 :                 myEmptyTraveltime += MSGlobals::gTurnaroundPenalty;
     174       181350 :                 myTimePenalty = MSGlobals::gTurnaroundPenalty;
     175              :             } else {
     176       296749 :                 myEmptyTraveltime += MSGlobals::gMinorPenalty;
     177       296749 :                 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      1746984 : MSEdge::closeBuilding() {
     209      3847798 :     for (MSLane* const lane : *myLanes) {
     210      4990240 :         for (MSLink* const link : lane->getLinkCont()) {
     211      2889426 :             link->initParallelLinks();
     212              :             MSLane* const toL = link->getLane();
     213              :             MSLane* const viaL = link->getViaLane();
     214      2889426 :             if (toL != nullptr) {
     215              :                 MSEdge& to = toL->getEdge();
     216      2889426 :                 if (std::find(mySuccessors.begin(), mySuccessors.end(), &to) == mySuccessors.end()) {
     217      2693029 :                     mySuccessors.push_back(&to);
     218      5386058 :                     myViaSuccessors.push_back(std::make_pair(&to, (viaL == nullptr ? nullptr : &viaL->getEdge())));
     219              :                 }
     220      2889426 :                 if (std::find(to.myPredecessors.begin(), to.myPredecessors.end(), this) == to.myPredecessors.end()) {
     221      2693029 :                     to.myPredecessors.push_back(this);
     222              :                 }
     223      2889426 :                 if (link->getDirection() != LinkDirection::TURN) {
     224      2254504 :                     myAmFringe = false;
     225              :                 }
     226              :             }
     227      2889426 :             if (viaL != nullptr) {
     228              :                 MSEdge& to = viaL->getEdge();
     229      1009822 :                 if (std::find(to.myPredecessors.begin(), to.myPredecessors.end(), this) == to.myPredecessors.end()) {
     230       929861 :                     to.myPredecessors.push_back(this);
     231              :                 }
     232              :             }
     233              :         }
     234      2100814 :         lane->checkBufferType();
     235              :     }
     236      1746984 :     std::sort(mySuccessors.begin(), mySuccessors.end(), by_id_sorter());
     237      1746984 :     rebuildAllowedLanes(true);
     238      1746984 :     recalcCache();
     239              : 
     240              :     // extend lookup table for sublane model after all edges are read
     241      1746984 :     if (myLanes->back()->getOpposite() != nullptr) {
     242         8256 :         MSLane* opposite = myLanes->back()->getOpposite();
     243         8256 :         MSLeaderInfo ahead(opposite->getWidth());
     244        22578 :         for (int j = 0; j < ahead.numSublanes(); ++j) {
     245        14322 :             mySublaneSides.push_back(myWidth + j * MSGlobals::gLateralResolution);
     246              :         }
     247         8256 :     }
     248      1746984 : }
     249              : 
     250              : 
     251              : void
     252      1746976 : MSEdge::postLoadInitLaneChanger() {
     253      1746976 :     if (myLaneChanger != nullptr) {
     254       434848 :         myLaneChanger->postloadInitLC();
     255              :     }
     256      1746976 : }
     257              : 
     258              : void
     259      1746984 : MSEdge::buildLaneChanger() {
     260      1746984 :     if (!myLanes->empty()) {
     261      1746984 :         const bool allowChanging = allowsLaneChanging();
     262      1746984 :         if (MSGlobals::gLateralResolution > 0) {
     263              :             // may always initiate sublane-change
     264       180632 :             if (!isInternal() || MSGlobals::gUsingInternalLanes) {
     265       180441 :                 myLaneChanger = new MSLaneChangerSublane(myLanes.get(), allowChanging);
     266              :             }
     267              :         } else {
     268      1566352 :             if (MSGlobals::gLaneChangeDuration > 0) {
     269         3717 :                 myLaneChanger = new MSLaneChanger(myLanes.get(), allowChanging);
     270      1562635 :             } else if (myLanes->size() > 1 || canChangeToOpposite()) {
     271       250698 :                 myLaneChanger = new MSLaneChanger(myLanes.get(), allowChanging);
     272              :             }
     273              :         }
     274              :     }
     275      1746984 : }
     276              : 
     277              : 
     278              : bool
     279      1746984 : MSEdge::allowsLaneChanging() const {
     280      1746984 :     if (isInternal() && MSGlobals::gUsingInternalLanes) {
     281              :         // allow changing only if all links leading to this internal lane have priority
     282              :         // or they are controlled by a traffic light
     283      1468544 :         for (const MSLane* const lane : *myLanes) {
     284      1006432 :             const MSLink* const link = lane->getLogicalPredecessorLane()->getLinkTo(lane);
     285              :             assert(link != nullptr);
     286              :             const LinkState state = link->getState();
     287       456892 :             if ((state == LINKSTATE_MINOR && lane->getBidiLane() == nullptr)
     288       549774 :                     || state == LINKSTATE_EQUAL
     289       549774 :                     || state == LINKSTATE_STOP
     290              :                     || state == LINKSTATE_ALLWAY_STOP
     291      1006432 :                     || state == LINKSTATE_DEADEND) {
     292              :                 return false;
     293              :             }
     294              :         }
     295              :     }
     296              :     return true;
     297              : }
     298              : 
     299              : 
     300              : void
     301     18282842 : MSEdge::addToAllowed(const SVCPermissions permissions, std::shared_ptr<const std::vector<MSLane*> > allowedLanes, AllowedLanesCont& laneCont) const {
     302     18282842 :     if (!allowedLanes->empty()) {
     303              :         // recheck whether we had this list to save memory
     304     18020813 :         for (auto& allowed : laneCont) {
     305     17001797 :             if (*allowed.second == *allowedLanes) {
     306     12740445 :                 allowed.first |= permissions;
     307              :                 return;
     308              :             }
     309              :         }
     310      1019016 :         laneCont.push_back(std::make_pair(permissions, allowedLanes));
     311              :     }
     312              : }
     313              : 
     314              : 
     315              : SVCPermissions
     316      2901477 : MSEdge::getMesoPermissions(SVCPermissions p, SVCPermissions ignoreIgnored) {
     317      2901477 :     SVCPermissions ignored = myMesoIgnoredVClasses & ~ignoreIgnored;
     318      2901477 :     return (p | ignored) == ignored ? 0 : p;
     319              : }
     320              : 
     321              : 
     322              : void
     323      1748493 : MSEdge::rebuildAllowedLanes(const bool onInit, bool updateVehicles) {
     324              :     // rebuild myMinimumPermissions and myCombinedPermissions
     325      1748493 :     myMinimumPermissions = SVCAll;
     326      1748493 :     myCombinedPermissions = 0;
     327              :     bool lanesChangedPermission = false;
     328      3851328 :     for (MSLane* const lane : *myLanes) {
     329              :         // same dedicated lanes are ignored in meso to avoid capacity errors.
     330              :         // Here we have to make sure that vehicles which are set to depart on
     331              :         // such lanes trigger an error.
     332      2102835 :         SVCPermissions allow = getMesoPermissions(lane->getPermissions(), SVC_PEDESTRIAN);
     333      2102835 :         myMinimumPermissions &= allow;
     334      2102835 :         myCombinedPermissions |= allow;
     335      2102835 :         lanesChangedPermission |= lane->hadPermissionChanges();
     336              :     }
     337      1748493 :     if (!onInit && !myHaveTransientPermissions && lanesChangedPermission) {
     338         1080 :         myHaveTransientPermissions = true;
     339              :         // backup original structures when first needed
     340         1080 :         myOrigAllowed = myAllowed;
     341              :         myOrigAllowedTargets = myAllowedTargets;
     342              :         myOrigClassesViaSuccessorMap = myClassesViaSuccessorMap;
     343              :     }
     344              :     // rebuild myAllowed
     345              :     myAllowed.clear();
     346      1748493 :     if (myCombinedPermissions != myMinimumPermissions) {
     347       166901 :         myAllowed.push_back(std::make_pair(SVC_IGNORING, myLanes));
     348      5674634 :         for (SVCPermissions vclass = SVC_PRIVATE; vclass <= SUMOVehicleClass_MAX; vclass *= 2) {
     349      5507733 :             if ((myCombinedPermissions & vclass) == vclass) {
     350              :                 std::shared_ptr<std::vector<MSLane*> > allowedLanes = std::make_shared<std::vector<MSLane*> >();
     351     11626101 :                 for (MSLane* const lane : *myLanes) {
     352      7873047 :                     if (lane->allowsVehicleClass((SUMOVehicleClass)vclass)) {
     353      3965097 :                         allowedLanes->push_back(lane);
     354              :                     }
     355              :                 }
     356      7506108 :                 addToAllowed(vclass, allowedLanes, myAllowed);
     357              :             }
     358              :         }
     359              :     }
     360      1748493 :     if (onInit) {
     361      1746984 :         myOriginalMinimumPermissions = myMinimumPermissions;
     362      1746984 :         myOriginalCombinedPermissions = myCombinedPermissions;
     363              :     } else {
     364         1509 :         rebuildAllowedTargets(updateVehicles);
     365         3825 :         for (MSEdge* pred : myPredecessors) {
     366         2316 :             if (myHaveTransientPermissions && !pred->myHaveTransientPermissions) {
     367         1509 :                 pred->myOrigAllowed = pred->myAllowed;
     368              :                 pred->myOrigAllowedTargets = pred->myAllowedTargets;
     369              :                 pred->myOrigClassesViaSuccessorMap = pred->myClassesViaSuccessorMap;
     370         1509 :                 pred->myHaveTransientPermissions = true;
     371              :             }
     372         2316 :             pred->rebuildAllowedTargets(updateVehicles);
     373              :         }
     374         1509 :         if (MSGlobals::gUseMesoSim) {
     375         2625 :             for (MESegment* s = MSGlobals::gMesoNet->getSegmentForEdge(*this); s != nullptr; s = s->getNextSegment()) {
     376         2226 :                 s->updatePermissions();
     377              :             }
     378              :         }
     379              :     }
     380      1748493 : }
     381              : 
     382              : 
     383              : void
     384      1751877 : MSEdge::rebuildAllowedTargets(const bool updateVehicles) {
     385              :     myAllowedTargets.clear();
     386      4452204 :     for (const MSEdge* target : mySuccessors) {
     387              :         bool universalMap = true; // whether the mapping for SVC_IGNORING is also valid for all vehicle classes
     388              :         std::shared_ptr<std::vector<MSLane*> > allLanes = std::make_shared<std::vector<MSLane*> >();
     389              :         // compute the mapping for SVC_IGNORING
     390      6147556 :         for (MSLane* const lane : *myLanes) {
     391              :             SVCPermissions combinedTargetPermissions = 0;
     392      9797705 :             for (const MSLink* const link : lane->getLinkCont()) {
     393      6350476 :                 if (&link->getLane()->getEdge() == target) {
     394      2897779 :                     allLanes->push_back(lane);
     395      2897779 :                     combinedTargetPermissions |= link->getLane()->getPermissions();
     396      2897779 :                     if (link->getViaLane() != nullptr &&
     397      1012281 :                             ((lane->getPermissions() & link->getLane()->getPermissions()) != link->getViaLane()->getPermissions())) {
     398              :                         // custom connection permissions
     399              :                         universalMap = false;
     400              :                     }
     401              :                 }
     402              :             }
     403      3447229 :             if (combinedTargetPermissions == 0 || (lane->getPermissions() & combinedTargetPermissions) != lane->getPermissions()) {
     404              :                 universalMap = false;
     405              :             }
     406              :         }
     407      2700327 :         if (universalMap) {
     408      2201949 :             if (myAllowed.empty()) {
     409              :                 // we have no lane specific permissions
     410      4336086 :                 myAllowedTargets[target].push_back(std::make_pair(myMinimumPermissions, myLanes));
     411              :             } else {
     412       133683 :                 for (const auto& i : myAllowed) {
     413       299331 :                     addToAllowed(i.first, i.second, myAllowedTargets[target]);
     414              :                 }
     415              :             }
     416              :         } else {
     417       996756 :             addToAllowed(SVC_IGNORING, allLanes, myAllowedTargets[target]);
     418              :             // compute the vclass specific mapping
     419     16944852 :             for (SVCPermissions vclass = SVC_PRIVATE; vclass <= SUMOVehicleClass_MAX; vclass *= 2) {
     420     16446474 :                 if ((myCombinedPermissions & vclass) == vclass) {
     421              :                     std::shared_ptr<std::vector<MSLane*> > allowedLanes = std::make_shared<std::vector<MSLane*> >();
     422     43221066 :                     for (MSLane* const lane : *myLanes) {
     423     29289433 :                         if (lane->allowsVehicleClass((SUMOVehicleClass)vclass)) {
     424     55788133 :                             for (const MSLink* const link : lane->getLinkCont()) {
     425     36456758 :                                 if (link->getLane()->allowsVehicleClass((SUMOVehicleClass)vclass) && &link->getLane()->getEdge() == target && (link->getViaLane() == nullptr || link->getViaLane()->allowsVehicleClass((SUMOVehicleClass)vclass))) {
     426      9762825 :                                     allowedLanes->push_back(lane);
     427              :                                 }
     428              :                             }
     429              :                         }
     430              :                     }
     431     41794899 :                     addToAllowed(vclass, allowedLanes, myAllowedTargets[target]);
     432              :                 }
     433              :             }
     434              :         }
     435              :     }
     436      1751877 :     if (updateVehicles) {
     437         3145 :         for (const MSLane* const lane : *myLanes) {
     438         1834 :             const MSLane::VehCont& vehs = lane->getVehiclesSecure();
     439         4224 :             for (MSVehicle* veh : vehs) {
     440         2390 :                 veh->updateBestLanes(true);
     441              :             }
     442         1834 :             lane->releaseVehicles();
     443              :         }
     444              :     }
     445              :     myClassesSuccessorMap.clear();
     446      1751877 : }
     447              : 
     448              : 
     449              : // ------------ Access to the edge's lanes
     450              : MSLane*
     451          774 : MSEdge::leftLane(const MSLane* const lane) const {
     452          774 :     return parallelLane(lane, 1);
     453              : }
     454              : 
     455              : 
     456              : MSLane*
     457          400 : MSEdge::rightLane(const MSLane* const lane) const {
     458          400 :     return parallelLane(lane, -1);
     459              : }
     460              : 
     461              : 
     462              : MSLane*
     463     82660691 : MSEdge::parallelLane(const MSLane* const lane, int offset, bool includeOpposite) const {
     464     82660691 :     const int resultIndex = lane->getIndex() + offset;
     465     82660691 :     if (resultIndex >= getNumLanes() && includeOpposite) {
     466     20218488 :         const MSEdge* opposite = getOppositeEdge();
     467     20218488 :         if (opposite != nullptr && resultIndex < getNumLanes() + opposite->getNumLanes()) {
     468      1383998 :             return opposite->getLanes()[opposite->getNumLanes() + getNumLanes() - resultIndex - 1];
     469              :         }
     470              :         return nullptr;
     471     62442203 :     } else if (resultIndex >= (int)myLanes->size() || resultIndex < 0) {
     472              :         return nullptr;
     473              :     } else {
     474     38456860 :         return (*myLanes)[resultIndex];
     475              :     }
     476              : }
     477              : 
     478              : 
     479              : const std::vector<MSLane*>*
     480     76026205 : MSEdge::allowedLanes(const MSEdge& destination, SUMOVehicleClass vclass, bool ignoreTransientPermissions) const {
     481     76026205 :     const auto& targets = ignoreTransientPermissions && myHaveTransientPermissions ? myOrigAllowedTargets : myAllowedTargets;
     482              :     AllowedLanesByTarget::const_iterator i = targets.find(&destination);
     483     76026205 :     if (i != targets.end()) {
     484     75994277 :         for (const auto& allowed : i->second) {
     485     75874215 :             if ((allowed.first & vclass) == vclass) {
     486              :                 return allowed.second.get();
     487              :             }
     488              :         }
     489              :     }
     490              :     return nullptr;
     491              : }
     492              : 
     493              : 
     494              : const std::vector<MSLane*>*
     495    274657757 : MSEdge::allowedLanes(SUMOVehicleClass vclass) const {
     496    274657757 :     if ((myMinimumPermissions & vclass) == vclass) {
     497     43708959 :         return myLanes.get();
     498              :     } else {
     499    230948798 :         if ((myCombinedPermissions & vclass) == vclass) {
     500    461894273 :             for (const auto& allowed : myAllowed) {
     501    461894273 :                 if ((allowed.first & vclass) == vclass) {
     502              :                     return allowed.second.get();
     503              :                 }
     504              :             }
     505              :         }
     506         1989 :         return nullptr;
     507              :     }
     508              : }
     509              : 
     510              : 
     511              : const std::vector<MSLane*>*
     512   2172158975 : MSEdge::allowedLanes(SUMOVehicleClass vclass, bool ignoreTransientPermissions) const {
     513   2172158975 :     const SVCPermissions& minP = ignoreTransientPermissions ? myOriginalMinimumPermissions : myMinimumPermissions;
     514   2172158975 :     if ((minP & vclass) == vclass) {
     515    634821912 :         return myLanes.get();
     516              :     } else {
     517   1537337063 :         const SVCPermissions comP = ignoreTransientPermissions ? myOriginalCombinedPermissions : myCombinedPermissions;
     518   1537337063 :         if ((comP & vclass) == vclass) {
     519   1537336991 :             const AllowedLanesCont& allowedCont = ignoreTransientPermissions ? myOrigAllowed : myAllowed;
     520   3080372408 :             for (const auto& allowed : allowedCont) {
     521   3080372408 :                 if ((allowed.first & vclass) == vclass) {
     522              :                     return allowed.second.get();
     523              :                 }
     524              :             }
     525              :         }
     526           72 :         return nullptr;
     527              :     }
     528              : }
     529              : 
     530              : 
     531              : // ------------
     532              : SUMOTime
     533          433 : MSEdge::incVaporization(SUMOTime) {
     534          433 :     ++myVaporizationRequests;
     535          433 :     return 0;
     536              : }
     537              : 
     538              : 
     539              : SUMOTime
     540          279 : MSEdge::decVaporization(SUMOTime) {
     541          279 :     --myVaporizationRequests;
     542          279 :     return 0;
     543              : }
     544              : 
     545              : 
     546              : MSLane*
     547    216935099 : MSEdge::getFreeLane(const std::vector<MSLane*>* allowed, const SUMOVehicleClass vclass, double departPos) const {
     548    216935099 :     if (allowed == nullptr) {
     549    183717656 :         allowed = allowedLanes(vclass);
     550              :     }
     551              :     MSLane* res = nullptr;
     552    183717656 :     if (allowed != nullptr) {
     553              :         double largestGap = 0;
     554              :         MSLane* resByGap = nullptr;
     555              :         double leastOccupancy = std::numeric_limits<double>::max();
     556    458667418 :         for (std::vector<MSLane*>::const_iterator i = allowed->begin(); i != allowed->end(); ++i) {
     557    241734300 :             const double occupancy = (*i)->getBruttoOccupancy();
     558    241734300 :             if (occupancy < leastOccupancy) {
     559    224822565 :                 res = (*i);
     560              :                 leastOccupancy = occupancy;
     561              :             }
     562    241734300 :             const MSVehicle* last = (*i)->getLastFullVehicle();
     563    241734300 :             const double lastGap = (last != nullptr ? last->getPositionOnLane() : myLength) - departPos;
     564    241734300 :             if (lastGap > largestGap) {
     565              :                 largestGap = lastGap;
     566     57637875 :                 resByGap = (*i);
     567              :             }
     568              :         }
     569    216933118 :         if (resByGap != nullptr) {
     570              :             //if (res != resByGap) std::cout << SIMTIME << " edge=" << getID() << " departPos=" << departPos << " res=" << Named::getIDSecure(res) << " resByGap=" << Named::getIDSecure(resByGap) << " largestGap=" << largestGap << "\n";
     571              :             res = resByGap;
     572              :         }
     573              :     }
     574    216935099 :     return res;
     575              : }
     576              : 
     577              : 
     578              : MSLane*
     579    839494875 : MSEdge::getProbableLane(const std::vector<MSLane*>* allowed, const SUMOVehicleClass vclass, double departPos, double maxSpeed) const {
     580    839494875 :     if (allowed == nullptr) {
     581            0 :         allowed = allowedLanes(vclass);
     582              :     }
     583              :     MSLane* res = nullptr;
     584            0 :     if (allowed != nullptr) {
     585              :         double largestGap = 0;
     586              :         double largestSpeed = 0;
     587              :         MSLane* resByGap = nullptr;
     588              :         double leastOccupancy = std::numeric_limits<double>::max();
     589              :         int aIndex = 0;
     590   1685050251 :         for (std::vector<MSLane*>::const_iterator i = allowed->begin(); i != allowed->end(); ++i, aIndex++) {
     591    845555376 :             const double occupancy = (*i)->getBruttoOccupancy();
     592    845555376 :             if (occupancy < leastOccupancy) {
     593    844830387 :                 res = (*i);
     594              :                 leastOccupancy = occupancy;
     595              :             }
     596    845555376 :             const MSVehicle* last = (*i)->getLastFullVehicle();
     597    845555376 :             double lastGap = (last != nullptr ? last->getPositionOnLane() : myLength) - departPos;
     598              :             // never insert to the left of a vehicle with a larger speedFactor
     599    845555376 :             if (lastGap > largestGap && maxSpeed >= largestSpeed) {
     600              :                 largestGap = lastGap;
     601    800350511 :                 resByGap = (*i);
     602              :             }
     603    845555376 :             if (last != nullptr) {
     604    843309975 :                 largestSpeed = MAX2(largestSpeed, getVehicleMaxSpeed(last));
     605              :             }
     606              :         }
     607    839494875 :         if (resByGap != nullptr) {
     608              :             //if (res != resByGap) std::cout << SIMTIME << " edge=" << getID() << " departPos=" << departPos << " res=" << Named::getIDSecure(res) << " resByGap=" << Named::getIDSecure(resByGap) << " largestGap=" << largestGap << "\n";
     609              :             res = resByGap;
     610              :         }
     611              :     }
     612    839494875 :     return res;
     613              : }
     614              : 
     615              : 
     616              : double
     617   1057546545 : MSEdge::getDepartPosBound(const MSVehicle& veh, bool upper) const {
     618   1057546545 :     const SUMOVehicleParameter& pars = veh.getParameter();
     619              :     double pos = getLength();
     620              :     // determine the position
     621   1057546545 :     switch (pars.departPosProcedure) {
     622      9426226 :         case DepartPosDefinition::GIVEN:
     623      9426226 :             pos = pars.departPos;
     624      9426226 :             if (pos < 0.) {
     625      2250044 :                 pos += myLength;
     626              :             }
     627              :             break;
     628              :         case DepartPosDefinition::RANDOM:
     629              :             // could be any position on the edge
     630              :             break;
     631              :         case DepartPosDefinition::RANDOM_FREE:
     632              :             // could be any position on the edge due to multiple random attempts
     633              :             break;
     634              :         case DepartPosDefinition::FREE:
     635              :             // many candidate positions, upper bound could be computed exactly
     636              :             // with much effort
     637              :             break;
     638     11726394 :         case DepartPosDefinition::LAST:
     639     11726394 :             if (upper) {
     640       468068 :                 for (std::vector<MSLane*>::const_iterator i = myLanes->begin(); i != myLanes->end(); ++i) {
     641       317844 :                     MSVehicle* last = (*i)->getLastFullVehicle();
     642       317844 :                     if (last != nullptr) {
     643       276034 :                         pos = MIN2(pos, last->getPositionOnLane());
     644              :                     }
     645              :                 }
     646              :             } else {
     647              :                 pos = 0;
     648              :             }
     649              :             break;
     650    831085367 :         case DepartPosDefinition::BASE:
     651              :         case DepartPosDefinition::DEFAULT:
     652    831085367 :             if (!upper) {
     653              :                 pos = 0;
     654              :             }
     655              :             break;
     656           28 :         default:
     657           28 :             pos = MIN2(pos, veh.getVehicleType().getLength());
     658              :             break;
     659              :     }
     660   1057546545 :     return pos;
     661              : }
     662              : 
     663              : MSLane*
     664           46 : MSEdge::getDepartLaneMeso(SUMOVehicle& veh) const {
     665           46 :     if (veh.getParameter().departLaneProcedure == DepartLaneDefinition::GIVEN) {
     666            3 :         if ((int) myLanes->size() <= veh.getParameter().departLane || !(*myLanes)[veh.getParameter().departLane]->allowsVehicleClass(veh.getVehicleType().getVehicleClass())) {
     667            0 :             return nullptr;
     668              :         }
     669            3 :         return (*myLanes)[veh.getParameter().departLane];
     670              :     }
     671           43 :     return (*myLanes)[0];
     672              : }
     673              : 
     674              : MSLane*
     675   1735723046 : MSEdge::getDepartLane(MSVehicle& veh) const {
     676   1735723046 :     DepartLaneDefinition dld = veh.getParameter().departLaneProcedure;
     677   1735723046 :     int departLane = veh.getParameter().departLane;
     678   1735723046 :     if (dld == DepartLaneDefinition::DEFAULT) {
     679   1319944800 :         dld = myDefaultDepartLaneDefinition;
     680   1319944800 :         departLane = myDefaultDepartLane;
     681              :     }
     682   1735723046 :     switch (dld) {
     683    100838409 :         case DepartLaneDefinition::GIVEN:
     684    100838409 :             if ((int) myLanes->size() <= departLane || !(*myLanes)[departLane]->allowsVehicleClass(veh.getVehicleType().getVehicleClass())) {
     685           66 :                 return nullptr;
     686              :             }
     687    100838343 :             return (*myLanes)[departLane];
     688     90910283 :         case DepartLaneDefinition::RANDOM:
     689    181820566 :             return RandHelper::getRandomFrom(*allowedLanes(veh.getVehicleType().getVehicleClass()));
     690    183616536 :         case DepartLaneDefinition::FREE:
     691    183616536 :             return getFreeLane(nullptr, veh.getVehicleType().getVehicleClass(), getDepartPosBound(veh, false));
     692      4971244 :         case DepartLaneDefinition::ALLOWED_FREE:
     693      4971244 :             if (veh.getRoute().size() == 1) {
     694         5960 :                 return getFreeLane(nullptr, veh.getVehicleType().getVehicleClass(), getDepartPosBound(veh, false));
     695              :             } else {
     696      4965284 :                 return getFreeLane(allowedLanes(**(veh.getRoute().begin() + 1), veh.getVehicleType().getVehicleClass()), veh.getVehicleType().getVehicleClass(), getDepartPosBound(veh, false));
     697              :             }
     698    867551334 :         case DepartLaneDefinition::BEST_FREE:
     699              :         case DepartLaneDefinition::BEST_PROB: {
     700    867551334 :             veh.updateBestLanes(false, myLanes->front());
     701    867551334 :             const std::vector<MSVehicle::LaneQ>& bl = veh.getBestLanes();
     702              :             double bestLength = -1;
     703   2561799349 :             for (std::vector<MSVehicle::LaneQ>::const_iterator i = bl.begin(); i != bl.end(); ++i) {
     704   1694248015 :                 if ((*i).length > bestLength) {
     705              :                     bestLength = (*i).length;
     706              :                 }
     707              :             }
     708              :             // beyond a certain length, all lanes are suitable
     709              :             // however, we still need to check departPos to avoid unsuitable insertion
     710              :             // (this is only possible in some cases)
     711              :             double departPos = 0;
     712    867551334 :             if (bestLength > BEST_LANE_LOOKAHEAD) {
     713      1407431 :                 departPos = getDepartPosBound(veh);
     714      1407431 :                 bestLength = MIN2(bestLength - departPos, BEST_LANE_LOOKAHEAD);
     715              :             }
     716    867551334 :             std::vector<MSLane*>* bestLanes = new std::vector<MSLane*>();
     717   2561799349 :             for (std::vector<MSVehicle::LaneQ>::const_iterator i = bl.begin(); i != bl.end(); ++i) {
     718   1694248015 :                 if (((*i).length - departPos) >= bestLength) {
     719    876256978 :                     if (isInternal()) {
     720           32 :                         for (MSLane* lane : *myLanes) {
     721           20 :                             if (lane->getNormalSuccessorLane() == (*i).lane) {
     722           12 :                                 bestLanes->push_back(lane);
     723              :                             }
     724              :                         }
     725              :                     } else {
     726    876256966 :                         bestLanes->push_back((*i).lane);
     727              :                     }
     728              :                 }
     729              :             }
     730              :             MSLane* ret = nullptr;
     731    867551334 :             if (veh.getParameter().departLaneProcedure == DepartLaneDefinition::BEST_FREE) {
     732     28056459 :                 ret = getFreeLane(bestLanes, veh.getVehicleType().getVehicleClass(), getDepartPosBound(veh, false));
     733              :             } else {
     734    839494875 :                 ret = getProbableLane(bestLanes, veh.getVehicleType().getVehicleClass(), getDepartPosBound(veh, false), getVehicleMaxSpeed(&veh));
     735              :             }
     736    867551334 :             delete bestLanes;
     737    867551334 :             return ret;
     738              :         }
     739    487835240 :         case DepartLaneDefinition::DEFAULT:
     740              :         case DepartLaneDefinition::FIRST_ALLOWED:
     741    487835240 :             return getFirstAllowed(veh.getVehicleType().getVehicleClass());
     742              :         default:
     743              :             break;
     744              :     }
     745            0 :     if (!(*myLanes)[0]->allowsVehicleClass(veh.getVehicleType().getVehicleClass())) {
     746              :         return nullptr;
     747              :     }
     748            0 :     return (*myLanes)[0];
     749              : }
     750              : 
     751              : 
     752              : MSLane*
     753    488604235 : MSEdge::getFirstAllowed(SUMOVehicleClass vClass, bool defaultFirst, int routingMode) const {
     754    494915402 :     for (std::vector<MSLane*>::const_iterator i = myLanes->begin(); i != myLanes->end(); ++i) {
     755    494910402 :         if ((*i)->allowsVehicleClass(vClass, routingMode)) {
     756    488599235 :             return *i;
     757              :         }
     758              :     }
     759         5000 :     return defaultFirst && !myLanes->empty() ? myLanes->front() : nullptr;
     760              : }
     761              : 
     762              : 
     763              : bool
     764   2794498525 : MSEdge::validateDepartSpeed(SUMOVehicle& v) const {
     765   2794498525 :     const SUMOVehicleParameter& pars = v.getParameter();
     766   2794498525 :     const MSVehicleType& type = v.getVehicleType();
     767   2794498525 :     if (pars.departSpeedProcedure == DepartSpeedDefinition::GIVEN) {
     768              :         // departSpeed could have been rounded down in the output
     769    150738705 :         double vMax = getVehicleMaxSpeed(&v) + SPEED_EPS;
     770    150738705 :         if (pars.departSpeed > vMax) {
     771              :             // check departLane (getVehicleMaxSpeed checks lane 0)
     772        19610 :             MSLane* departLane = MSGlobals::gMesoNet ? getDepartLaneMeso(v) : getDepartLane(dynamic_cast<MSVehicle&>(v));
     773        19610 :             if (departLane != nullptr) {
     774        19610 :                 vMax = departLane->getVehicleMaxSpeed(&v);
     775        19610 :                 if (pars.wasSet(VEHPARS_SPEEDFACTOR_SET)) {
     776              :                     // speedFactor could have been rounded down in the output
     777            7 :                     vMax *= (1 + SPEED_EPS);
     778              :                 }
     779              :                 // additive term must come after multiplication!
     780        19610 :                 vMax += SPEED_EPS;
     781        19610 :                 if (pars.departSpeed > vMax) {
     782        19596 :                     if (type.getSpeedFactor().getParameter(1) > 0.) {
     783        39154 :                         v.setChosenSpeedFactor(type.computeChosenSpeedDeviation(nullptr, pars.departSpeed / MIN2(getSpeedLimit(), type.getDesiredMaxSpeed() - SPEED_EPS)));
     784        19577 :                         if (v.getChosenSpeedFactor() > type.getSpeedFactor().getParameter(0) + 2 * type.getSpeedFactor().getParameter(1)) {
     785              :                             // only warn for significant deviation
     786        33536 :                             WRITE_WARNINGF(TL("Choosing new speed factor % for vehicle '%' to match departure speed % (max %)."),
     787              :                                            toString(v.getChosenSpeedFactor()), pars.id, pars.departSpeed, vMax);
     788              :                         }
     789              :                     } else {
     790              :                         return false;
     791              :                     }
     792              :                 }
     793              :             }
     794              :         }
     795              :     }
     796              :     return true;
     797              : }
     798              : 
     799              : 
     800              : bool
     801   2794959912 : MSEdge::insertVehicle(SUMOVehicle& v, SUMOTime time, const bool checkOnly, const bool forceCheck) const {
     802              :     // when vaporizing, no vehicles are inserted, but checking needs to be successful to trigger removal
     803   2794941126 :     if (isVaporizing() || isTazConnector()
     804   5589435739 :             || v.getRouteValidity(true, checkOnly) != MSBaseVehicle::ROUTE_VALID) {
     805       484152 :         return checkOnly;
     806              :     }
     807   2794475581 :     const SUMOVehicleParameter& pars = v.getParameter();
     808   2794475581 :     if (!validateDepartSpeed(v)) {
     809           14 :         if (MSGlobals::gCheckRoutes) {
     810           21 :             throw ProcessError(TLF("Departure speed for vehicle '%' is too high for the departure edge '%', time=%.",
     811           21 :                                    pars.id, getID(), time2string(time)));
     812              :         } else {
     813           21 :             WRITE_WARNINGF(TL("Departure speed for vehicle '%' is too high for the departure edge '%', time=%."),
     814              :                            pars.id, getID(), time2string(time));
     815              :         }
     816              :     }
     817   2794475574 :     if (MSGlobals::gUseMesoSim) {
     818    573246004 :         if (!forceCheck && myLastFailedInsertionTime == time) {
     819              :             return false;
     820              :         }
     821              :         double pos = 0.0;
     822     97183751 :         switch (pars.departPosProcedure) {
     823       514486 :             case DepartPosDefinition::GIVEN:
     824       514486 :                 if (pars.departPos >= 0.) {
     825              :                     pos = pars.departPos;
     826              :                 } else {
     827         8389 :                     pos = pars.departPos + getLength();
     828              :                 }
     829       514486 :                 if (pos < 0 || pos > getLength()) {
     830            6 :                     WRITE_WARNINGF(TL("Invalid departPos % given for vehicle '%', time=%. Inserting at lane end instead."),
     831              :                                    pos, v.getID(), time2string(time));
     832              :                     pos = getLength();
     833              :                 }
     834              :                 break;
     835              :             case DepartPosDefinition::RANDOM:
     836              :             case DepartPosDefinition::RANDOM_FREE:
     837              :                 pos = RandHelper::rand(getLength());
     838        44178 :                 break;
     839              :             default:
     840              :                 break;
     841              :         }
     842              :         bool result = false;
     843     97183751 :         MESegment* segment = MSGlobals::gMesoNet->getSegmentForEdge(*this, pos);
     844              :         MEVehicle* veh = static_cast<MEVehicle*>(&v);
     845              :         int qIdx;
     846     97183751 :         if (pars.departPosProcedure == DepartPosDefinition::FREE) {
     847       486990 :             while (segment != nullptr && !result) {
     848       448198 :                 if (checkOnly) {
     849            6 :                     result = segment->hasSpaceFor(veh, time, qIdx, true) == time;
     850              :                 } else {
     851       448192 :                     result = segment->initialise(veh, time);
     852              :                 }
     853              :                 segment = segment->getNextSegment();
     854              :             }
     855              :         } else {
     856     97144959 :             if (checkOnly) {
     857     95588007 :                 result = segment->hasSpaceFor(veh, time, qIdx, true) == time;
     858              :             } else {
     859      1556952 :                 result = segment->initialise(veh, time);
     860              :             }
     861              :         }
     862     97183748 :         return result;
     863              :     }
     864   2221229570 :     if (checkOnly) {
     865    616066165 :         DepartLaneDefinition dld = v.getParameter().departLaneProcedure;
     866    616066165 :         if (dld == DepartLaneDefinition::DEFAULT) {
     867    561257033 :             dld = myDefaultDepartLaneDefinition;
     868              :         }
     869    616066165 :         switch (dld) {
     870     80109233 :             case DepartLaneDefinition::GIVEN:
     871              :             case DepartLaneDefinition::DEFAULT:
     872              :             case DepartLaneDefinition::FIRST_ALLOWED: {
     873     80109233 :                 MSLane* insertionLane = getDepartLane(static_cast<MSVehicle&>(v));
     874     80109233 :                 if (insertionLane == nullptr) {
     875            0 :                     WRITE_WARNINGF(TL("Could not insert vehicle '%' on any lane of edge '%', time=%."),
     876              :                                    v.getID(), getID(), time2string(time));
     877            0 :                     return false;
     878              :                 }
     879     80109233 :                 const double occupancy = insertionLane->getBruttoOccupancy();
     880     80109233 :                 return (occupancy == 0 || occupancy * myLength + v.getVehicleType().getLengthWithGap() <= myLength ||
     881      5553063 :                         v.getParameter().departProcedure == DepartDefinition::SPLIT);
     882              :             }
     883    535956932 :             default:
     884    553553078 :                 for (std::vector<MSLane*>::const_iterator i = myLanes->begin(); i != myLanes->end(); ++i) {
     885    545337120 :                     const double occupancy = (*i)->getBruttoOccupancy();
     886    545337120 :                     if (occupancy == 0 || occupancy * myLength + v.getVehicleType().getLengthWithGap() <= myLength ||
     887     17596146 :                             v.getParameter().departProcedure == DepartDefinition::SPLIT) {
     888              :                         return true;
     889              :                     }
     890              :                 }
     891              :         }
     892              :         return false;
     893              :     }
     894   1605163405 :     MSLane* insertionLane = getDepartLane(static_cast<MSVehicle&>(v));
     895   1605163405 :     if (insertionLane == nullptr) {
     896              :         return false;
     897              :     }
     898              : 
     899   1605158405 :     if (!forceCheck) {
     900   1605158228 :         if (myLastFailedInsertionTime == time) {
     901              :             if (myFailedInsertionMemory.count(insertionLane->getIndex())) {
     902              :                 // A vehicle was already rejected for the proposed insertionLane in this timestep
     903              :                 return false;
     904              :             }
     905              :         } else {
     906              :             // last rejection occurred in a previous timestep, clear cache
     907              :             myFailedInsertionMemory.clear();
     908              :         }
     909              :     }
     910              : 
     911     13386880 :     bool success = insertionLane->insertVehicle(static_cast<MSVehicle&>(v));
     912              : 
     913     13386877 :     if (!success) {
     914              :         // constraints may enforce explicit re-ordering so we need to try other vehicles after failure
     915     19881856 :         if (!insertionLane->hasParameter("insertionOrder" + v.getID())) {
     916      9940781 :             myFailedInsertionMemory.insert(insertionLane->getIndex());
     917              :         }
     918              :     }
     919              :     return success;
     920              : }
     921              : 
     922              : 
     923              : void
     924     42064392 : MSEdge::changeLanes(SUMOTime t) const {
     925     42064392 :     if (myLaneChanger != nullptr) {
     926     42064392 :         myLaneChanger->laneChange(t);
     927              :     }
     928     42064392 : }
     929              : 
     930              : 
     931              : const MSEdge*
     932      5303884 : MSEdge::getInternalFollowingEdge(const MSEdge* followerAfterInternal, SUMOVehicleClass vClass) const {
     933              :     //@todo to be optimized
     934      6067481 :     for (const MSLane* const l : *myLanes) {
     935      8680862 :         for (const MSLink* const link : l->getLinkCont()) {
     936      7917265 :             if (&link->getLane()->getEdge() == followerAfterInternal) {
     937      5037970 :                 if (link->getViaLane() != nullptr) {
     938      4016575 :                     if (link->getViaLane()->allowsVehicleClass(vClass)) {
     939      3977857 :                         return &link->getViaLane()->getEdge();
     940              :                     } else {
     941        38718 :                         continue;
     942              :                     }
     943              :                 } else {
     944              :                     return nullptr; // network without internal links
     945              :                 }
     946              :             }
     947              :         }
     948              :     }
     949              :     return nullptr;
     950              : }
     951              : 
     952              : 
     953              : double
     954      1234517 : MSEdge::getInternalFollowingLengthTo(const MSEdge* followerAfterInternal, SUMOVehicleClass vClass) const {
     955              :     assert(followerAfterInternal != 0);
     956              :     assert(!followerAfterInternal->isInternal());
     957              :     double dist = 0.;
     958      1234517 :     const MSEdge* edge = getInternalFollowingEdge(followerAfterInternal, vClass);
     959              :     // Take into account non-internal lengths until next non-internal edge
     960      2275125 :     while (edge != nullptr && edge->isInternal()) {
     961      1040608 :         dist += edge->getLength();
     962      1040608 :         edge = edge->getInternalFollowingEdge(followerAfterInternal, vClass);
     963              :     }
     964      1234517 :     return dist;
     965              : }
     966              : 
     967              : 
     968              : const MSEdge*
     969       149397 : MSEdge::getNormalBefore() const {
     970              :     const MSEdge* result = this;
     971       158428 :     while (result->isInternal() && MSGlobals::gUsingInternalLanes) {
     972              :         assert(result->getPredecessors().size() == 1);
     973         9031 :         result = result->getPredecessors().front();
     974              :     }
     975       149397 :     return result;
     976              : }
     977              : 
     978              : const MSEdge*
     979      5970523 : MSEdge::getNormalSuccessor() const {
     980              :     const MSEdge* result = this;
     981     11297645 :     while (result->isInternal()) {
     982              :         assert(result->getSuccessors().size() == 1);
     983      5327122 :         result = result->getSuccessors().front();
     984              :     }
     985      5970523 :     return result;
     986              : }
     987              : 
     988              : double
     989    184167475 : MSEdge::getMeanSpeed() const {
     990              :     double v = 0;
     991              :     double totalNumVehs = 0;
     992    184167475 :     if (MSGlobals::gUseMesoSim) {
     993    240513751 :         for (MESegment* segment = MSGlobals::gMesoNet->getSegmentForEdge(*this); segment != nullptr; segment = segment->getNextSegment()) {
     994              :             const int numVehs = segment->getCarNumber();
     995    178277995 :             if (numVehs > 0) {
     996     25290826 :                 v += numVehs * segment->getMeanSpeed();
     997     25290826 :                 totalNumVehs += numVehs;
     998              :             }
     999              :         }
    1000     62235756 :         if (totalNumVehs == 0) {
    1001     53038403 :             return getLength() / myEmptyTraveltime; // may include tls-penalty
    1002              :         }
    1003              :     } else {
    1004    280758149 :         for (const MSLane* const lane : *myLanes) {
    1005              :             int numVehs = lane->getVehicleNumber();
    1006    158826430 :             if (numVehs == 0) {
    1007              :                 // take speed limit but with lowest possible weight
    1008              :                 numVehs = 1;
    1009              :             }
    1010    158826430 :             v += numVehs * lane->getMeanSpeed();
    1011    158826430 :             totalNumVehs += numVehs;
    1012              :         }
    1013    121931719 :         if (myBidiEdge != nullptr) {
    1014      8758073 :             for (const MSLane* const lane : myBidiEdge->getLanes()) {
    1015      4536666 :                 if (lane->getVehicleNumber() > 0) {
    1016              :                     // do not route across edges which are already occupied in reverse direction
    1017              :                     return 0;
    1018              :                 }
    1019              :             }
    1020              :         }
    1021    121616604 :         if (totalNumVehs == 0) {
    1022            0 :             return getSpeedLimit();
    1023              :         }
    1024              :     }
    1025    130813957 :     return v / totalNumVehs;
    1026              : }
    1027              : 
    1028              : 
    1029              : double
    1030            8 : MSEdge::getMeanFriction() const {
    1031              :     double f = 0.;
    1032           32 :     for (const MSLane* const lane : *myLanes) {
    1033           24 :         f += lane->getFrictionCoefficient();
    1034              :     }
    1035            8 :     if (!myLanes->empty()) {
    1036            8 :         return f / (double)myLanes->size();
    1037              :     }
    1038              :     return 1.;
    1039              : }
    1040              : 
    1041              : 
    1042              : double
    1043         1272 : MSEdge::getMeanSpeedBike() const {
    1044         1272 :     if (MSGlobals::gUseMesoSim) {
    1045              :         // no separate bicycle speeds in meso
    1046          362 :         return getMeanSpeed();
    1047              :     }
    1048              :     double v = 0;
    1049              :     double totalNumVehs = 0;
    1050         3005 :     for (const MSLane* const lane : *myLanes) {
    1051              :         const int numVehs = lane->getVehicleNumber();
    1052         2095 :         v += numVehs * lane->getMeanSpeedBike();
    1053         2095 :         totalNumVehs += numVehs;
    1054              :     }
    1055          910 :     if (totalNumVehs == 0) {
    1056          455 :         return getSpeedLimit();
    1057              :     }
    1058          455 :     return v / totalNumVehs;
    1059              : }
    1060              : 
    1061              : 
    1062              : double
    1063        63248 : MSEdge::getCurrentTravelTime(double minSpeed) const {
    1064              :     assert(minSpeed > 0);
    1065        63248 :     if (!myAmDelayed) {
    1066        44794 :         return myEmptyTraveltime;
    1067              :     }
    1068        36908 :     return getLength() / MAX2(minSpeed, getMeanSpeed());
    1069              : }
    1070              : 
    1071              : 
    1072              : double
    1073            0 : MSEdge::getRoutingSpeed() const {
    1074            0 :     return MSRoutingEngine::getAssumedSpeed(this, nullptr);
    1075              : }
    1076              : 
    1077              : 
    1078              : bool
    1079      1819510 : MSEdge::dictionary(const std::string& id, MSEdge* ptr) {
    1080              :     const DictType::iterator it = myDict.lower_bound(id);
    1081      1819510 :     if (it == myDict.end() || it->first != id) {
    1082              :         // id not in myDict
    1083      1819510 :         myDict.emplace_hint(it, id, ptr);
    1084      3639054 :         while (ptr->getNumericalID() >= (int)myEdges.size()) {
    1085      1819544 :             myEdges.push_back(nullptr);
    1086              :         }
    1087      1819510 :         myEdges[ptr->getNumericalID()] = ptr;
    1088      1819510 :         return true;
    1089              :     }
    1090              :     return false;
    1091              : }
    1092              : 
    1093              : 
    1094              : MSEdge*
    1095      8597819 : MSEdge::dictionary(const std::string& id) {
    1096              :     const DictType::iterator it = myDict.find(id);
    1097      8597819 :     if (it == myDict.end()) {
    1098              :         return nullptr;
    1099              :     }
    1100      6776279 :     return it->second;
    1101              : }
    1102              : 
    1103              : 
    1104              : MSEdge*
    1105      2895920 : MSEdge::dictionaryHint(const std::string& id, const int startIdx) {
    1106              :     // this method is mainly useful when parsing connections from the net.xml which are sorted by "from" id
    1107      2895920 :     if (myEdges[startIdx] != nullptr && myEdges[startIdx]->getID() == id) {
    1108              :         return myEdges[startIdx];
    1109              :     }
    1110      1829438 :     if (startIdx + 1 < (int)myEdges.size() && myEdges[startIdx + 1] != nullptr && myEdges[startIdx + 1]->getID() == id) {
    1111              :         return myEdges[startIdx + 1];
    1112              :     }
    1113       601787 :     return dictionary(id);
    1114              : }
    1115              : 
    1116              : 
    1117              : const MSEdgeVector&
    1118       892240 : MSEdge::getAllEdges() {
    1119       892240 :     return myEdges;
    1120              : }
    1121              : 
    1122              : 
    1123              : void
    1124        41625 : MSEdge::clear() {
    1125      1846225 :     for (DictType::iterator i = myDict.begin(); i != myDict.end(); ++i) {
    1126      1804600 :         delete (*i).second;
    1127              :     }
    1128              :     myDict.clear();
    1129              :     myEdges.clear();
    1130        41625 : }
    1131              : 
    1132              : 
    1133              : void
    1134          285 : MSEdge::insertIDs(std::vector<std::string>& into) {
    1135        16016 :     for (DictType::iterator i = myDict.begin(); i != myDict.end(); ++i) {
    1136        15731 :         into.push_back((*i).first);
    1137              :     }
    1138          285 : }
    1139              : 
    1140              : 
    1141              : void
    1142       412206 : MSEdge::parseEdgesList(const std::string& desc, ConstMSEdgeVector& into,
    1143              :                        const std::string& rid) {
    1144       412206 :     StringTokenizer st(desc);
    1145       412206 :     parseEdgesList(st.getVector(), into, rid);
    1146       412206 : }
    1147              : 
    1148              : 
    1149              : void
    1150       412486 : MSEdge::parseEdgesList(const std::vector<std::string>& desc, ConstMSEdgeVector& into,
    1151              :                        const std::string& rid) {
    1152      1562625 :     for (std::vector<std::string>::const_iterator i = desc.begin(); i != desc.end(); ++i) {
    1153      1150188 :         const MSEdge* edge = MSEdge::dictionary(*i);
    1154              :         // check whether the edge exists
    1155      1150188 :         if (edge == nullptr) {
    1156           49 :             throw ProcessError("The edge '" + *i + "' within the route " + rid + " is not known."
    1157          147 :                                + "\n The route can not be build.");
    1158              :         }
    1159      1150139 :         into.push_back(edge);
    1160              :     }
    1161       412437 : }
    1162              : 
    1163              : 
    1164              : double
    1165      1893362 : MSEdge::getDistanceTo(const MSEdge* other, const bool doBoundaryEstimate) const {
    1166              :     assert(this != other);
    1167      1893362 :     if (doBoundaryEstimate) {
    1168        19288 :         return myBoundary.distanceTo2D(other->myBoundary);
    1169              :     }
    1170      1874074 :     if (isTazConnector()) {
    1171          564 :         if (other->isTazConnector()) {
    1172          448 :             return myBoundary.distanceTo2D(other->myBoundary);
    1173              :         }
    1174          116 :         return myBoundary.distanceTo2D(other->getLanes()[0]->getShape()[0]);
    1175              :     }
    1176      1873510 :     if (other->isTazConnector()) {
    1177         5405 :         return other->myBoundary.distanceTo2D(getLanes()[0]->getShape()[-1]);
    1178              :     }
    1179      1868105 :     return getLanes()[0]->getShape()[-1].distanceTo2D(other->getLanes()[0]->getShape()[0]);
    1180              : }
    1181              : 
    1182              : 
    1183              : const Position
    1184         2424 : MSEdge::getStopPosition(const SUMOVehicleParameter::Stop& stop) {
    1185         2424 :     return MSLane::dictionary(stop.lane)->geometryPositionAtOffset((stop.endPos + stop.startPos) / 2.);
    1186              : }
    1187              : 
    1188              : 
    1189              : double
    1190     93978394 : MSEdge::getSpeedLimit() const {
    1191              :     // @note lanes might have different maximum speeds in theory
    1192     93978394 :     return myLanes->empty() ? 1 : getLanes()[0]->getSpeedLimit();
    1193              : }
    1194              : 
    1195              : 
    1196              : double
    1197      1910472 : MSEdge::getLengthGeometryFactor() const {
    1198      1910472 :     return myLanes->empty() ? 1 : getLanes()[0]->getLengthGeometryFactor();
    1199              : }
    1200              : 
    1201              : double
    1202   2071136244 : MSEdge::getVehicleMaxSpeed(const SUMOTrafficObject* const veh) const {
    1203              :     // @note lanes might have different maximum speeds in theory
    1204   2071136244 :     return myLanes->empty() ? 1 : getLanes()[0]->getVehicleMaxSpeed(veh);
    1205              : }
    1206              : 
    1207              : 
    1208              : void
    1209          203 : MSEdge::setMaxSpeed(const double val, const bool modified, const double jamThreshold) {
    1210              :     assert(val >= 0);
    1211          203 :     if (myLanes != nullptr) {
    1212          560 :         for (MSLane* const lane : *myLanes) {
    1213          357 :             lane->setMaxSpeed(val, modified, jamThreshold);
    1214              :         }
    1215              :     }
    1216          203 : }
    1217              : 
    1218              : 
    1219              : void
    1220      3135475 : MSEdge::addTransportable(MSTransportable* t) const {
    1221      3135475 :     if (t->isPerson()) {
    1222              :         myPersons.insert(t);
    1223              :     } else {
    1224              :         myContainers.insert(t);
    1225              :     }
    1226      3135475 : }
    1227              : 
    1228              : void
    1229      6256056 : MSEdge::removeTransportable(MSTransportable* t) const {
    1230      6256056 :     std::set<MSTransportable*, ComparatorNumericalIdLess>& tc = t->isPerson() ? myPersons : myContainers;
    1231              :     auto it = tc.find(t);
    1232      6256056 :     if (it != tc.end()) {
    1233              :         tc.erase(it);
    1234              :     }
    1235      6256056 : }
    1236              : 
    1237              : std::vector<MSTransportable*>
    1238    112257407 : MSEdge::getSortedPersons(SUMOTime timestep, bool includeRiding) const {
    1239    112257407 :     std::vector<MSTransportable*> result(myPersons.begin(), myPersons.end());
    1240    112257407 :     if (includeRiding) {
    1241      2896155 :         for (std::vector<MSLane*>::const_iterator i = myLanes->begin(); i != myLanes->end(); ++i) {
    1242      2042878 :             const MSLane::VehCont& vehs = (*i)->getVehiclesSecure();
    1243      3266518 :             for (MSLane::VehCont::const_iterator j = vehs.begin(); j != vehs.end(); ++j) {
    1244      1223640 :                 const std::vector<MSTransportable*>& persons = (*j)->getPersons();
    1245      1223640 :                 result.insert(result.end(), persons.begin(), persons.end());
    1246              :             }
    1247      2042878 :             (*i)->releaseVehicles();
    1248              :         }
    1249              :     }
    1250    112257407 :     sort(result.begin(), result.end(), transportable_by_position_sorter(timestep));
    1251    112257407 :     return result;
    1252            0 : }
    1253              : 
    1254              : 
    1255              : std::vector<MSTransportable*>
    1256     30615008 : MSEdge::getSortedContainers(SUMOTime timestep, bool /* includeRiding */) const {
    1257     30615008 :     std::vector<MSTransportable*> result(myContainers.begin(), myContainers.end());
    1258     30615008 :     sort(result.begin(), result.end(), transportable_by_position_sorter(timestep));
    1259     30615008 :     return result;
    1260            0 : }
    1261              : 
    1262              : 
    1263              : int
    1264      5227135 : MSEdge::transportable_by_position_sorter::operator()(const MSTransportable* const c1, const MSTransportable* const c2) const {
    1265      5227135 :     const double pos1 = c1->getCurrentStage()->getEdgePos(myTime);
    1266      5227135 :     const double pos2 = c2->getCurrentStage()->getEdgePos(myTime);
    1267      5227135 :     if (pos1 != pos2) {
    1268      5075766 :         return pos1 < pos2;
    1269              :     }
    1270       151369 :     return c1->getID() < c2->getID();
    1271              : }
    1272              : 
    1273              : 
    1274              : void
    1275       125237 : MSEdge::addSuccessor(MSEdge* edge, const MSEdge* via) {
    1276       125237 :     mySuccessors.push_back(edge);
    1277       125237 :     myViaSuccessors.push_back(std::make_pair(edge, via));
    1278       125237 :     if (isTazConnector() && edge->getFromJunction() != nullptr) {
    1279        62615 :         myBoundary.add(edge->getFromJunction()->getPosition());
    1280              :     }
    1281              : 
    1282       125237 :     edge->myPredecessors.push_back(this);
    1283       125237 :     if (edge->isTazConnector() && getToJunction() != nullptr) {
    1284        62622 :         edge->myBoundary.add(getToJunction()->getPosition());
    1285              :     }
    1286       125237 : }
    1287              : 
    1288              : 
    1289              : const MSEdgeVector&
    1290     79765077 : MSEdge::getSuccessors(SUMOVehicleClass vClass) const {
    1291     79765077 :     if (vClass == SVC_IGNORING || !MSNet::getInstance()->hasPermissions() || myFunction == SumoXMLEdgeFunc::CONNECTOR) {
    1292     79750315 :         return mySuccessors;
    1293              :     }
    1294              : #ifdef HAVE_FOX
    1295        14762 :     ScopedLocker<> lock(mySuccessorMutex, MSGlobals::gNumThreads > 1);
    1296              : #endif
    1297              :     std::map<SUMOVehicleClass, MSEdgeVector>::iterator i = myClassesSuccessorMap.find(vClass);
    1298        14762 :     if (i == myClassesSuccessorMap.end()) {
    1299              :         // instantiate vector
    1300         1856 :         myClassesSuccessorMap[vClass];
    1301              :         i = myClassesSuccessorMap.find(vClass);
    1302              :         // this vClass is requested for the first time. rebuild all successors
    1303         9567 :         for (MSEdgeVector::const_iterator it = mySuccessors.begin(); it != mySuccessors.end(); ++it) {
    1304         7711 :             if ((*it)->isTazConnector()) {
    1305          239 :                 i->second.push_back(*it);
    1306              :             } else {
    1307         7472 :                 const std::vector<MSLane*>* allowed = allowedLanes(**it, vClass);
    1308         7472 :                 if (allowed != nullptr && allowed->size() > 0) {
    1309         5620 :                     i->second.push_back(*it);
    1310              :                 }
    1311              :             }
    1312              :         }
    1313              :     }
    1314              :     // can use cached value
    1315        14762 :     return i->second;
    1316              : }
    1317              : 
    1318              : 
    1319              : const MSConstEdgePairVector&
    1320    199061513 : MSEdge::getViaSuccessors(SUMOVehicleClass vClass, bool ignoreTransientPermissions) const {
    1321    199061513 :     if (vClass == SVC_IGNORING || !MSNet::getInstance()->hasPermissions() || myFunction == SumoXMLEdgeFunc::CONNECTOR) {
    1322    193231522 :         return myViaSuccessors;
    1323              :     }
    1324              : #ifdef HAVE_FOX
    1325      5829991 :     ScopedLocker<> lock(mySuccessorMutex, MSGlobals::gNumThreads > 1);
    1326              : #endif
    1327      5829991 :     auto& viaMap = ignoreTransientPermissions && myHaveTransientPermissions ? myOrigClassesViaSuccessorMap : myClassesViaSuccessorMap;
    1328              :     auto i = viaMap.find(vClass);
    1329      5829991 :     if (i != viaMap.end()) {
    1330              :         // can use cached value
    1331      5776637 :         return i->second;
    1332              :     }
    1333              :     // instantiate vector
    1334        53354 :     MSConstEdgePairVector& result = viaMap[vClass];
    1335              :     // this vClass is requested for the first time. rebuild all successors
    1336       226075 :     for (const auto& viaPair : myViaSuccessors) {
    1337       172721 :         if (viaPair.first->isTazConnector()) {
    1338         6322 :             result.push_back(viaPair);
    1339              :         } else {
    1340       166399 :             const std::vector<MSLane*>* allowed = allowedLanes(*viaPair.first, vClass, ignoreTransientPermissions);
    1341       166399 :             if (allowed != nullptr && allowed->size() > 0) {
    1342       125005 :                 result.push_back(viaPair);
    1343              :             }
    1344              :         }
    1345              :     }
    1346              :     return result;
    1347              : }
    1348              : 
    1349              : 
    1350              : void
    1351      1749291 : MSEdge::setJunctions(MSJunction* from, MSJunction* to) {
    1352      1749291 :     myFromJunction = from;
    1353      1749291 :     myToJunction = to;
    1354      1749291 :     if (!isTazConnector()) {
    1355      1749291 :         myBoundary.add(from->getPosition());
    1356      1749291 :         myBoundary.add(to->getPosition());
    1357              :     }
    1358      1749291 : }
    1359              : 
    1360              : 
    1361              : bool
    1362      2876138 : MSEdge::canChangeToOpposite() const {
    1363      2876138 :     return (!myLanes->empty() && myLanes->back()->getOpposite() != nullptr &&
    1364              :             // do not change on curved internal lanes
    1365              :             (!isInternal()
    1366         5865 :              || (MSGlobals::gUsingInternalLanes
    1367         5865 :                  && myLanes->back()->getIncomingLanes()[0].viaLink->getDirection() == LinkDirection::STRAIGHT)));
    1368              : }
    1369              : 
    1370              : 
    1371              : const MSEdge*
    1372     21976313 : MSEdge::getOppositeEdge() const {
    1373     21976313 :     if (!myLanes->empty() && myLanes->back()->getOpposite() != nullptr) {
    1374      2991214 :         return &(myLanes->back()->getOpposite()->getEdge());
    1375              :     } else {
    1376     18985099 :         return nullptr;
    1377              :     }
    1378              : }
    1379              : 
    1380              : 
    1381              : bool
    1382          178 : MSEdge::hasMinorLink() const {
    1383          354 :     for (const MSLane* const l : *myLanes) {
    1384          386 :         for (const MSLink* const link : l->getLinkCont()) {
    1385          210 :             if (!link->havePriority()) {
    1386              :                 return true;
    1387              :             }
    1388              :         }
    1389              :     }
    1390              :     return false;
    1391              : }
    1392              : 
    1393              : bool
    1394       212754 : MSEdge::hasChangeProhibitions(SUMOVehicleClass svc, int index) const {
    1395       212754 :     if (myLanes->size() == 1) {
    1396              :         return false;
    1397              :     }
    1398       295050 :     for (const MSLane* const l : *myLanes) {
    1399       200211 :         if (l->getIndex() <= index && !l->allowsChangingRight(svc) && l->getIndex() > 0) {
    1400              :             return true;
    1401       200167 :         } else if (l->getIndex() >= index && !l->allowsChangingLeft(svc) && l->getIndex() < (int)(myLanes->size() - 1)) {
    1402              :             return true;
    1403              :         }
    1404              :     }
    1405              :     return false;
    1406              : }
    1407              : 
    1408              : void
    1409       913128 : MSEdge::checkAndRegisterBiDirEdge(const std::string& bidiID) {
    1410       913128 :     if (bidiID != "") {
    1411        31750 :         myBidiEdge = dictionary(bidiID);
    1412        31750 :         if (myBidiEdge == nullptr) {
    1413            0 :             WRITE_ERRORF(TL("Bidi-edge '%' does not exist"), bidiID);
    1414              :         }
    1415        31750 :         setBidiLanes();
    1416       525962 :         return;
    1417              :     }
    1418       881378 :     if (getFunction() != SumoXMLEdgeFunc::NORMAL) {
    1419              :         return;
    1420              :     }
    1421              :     // legacy networks (no bidi attribute)
    1422       387166 :     ConstMSEdgeVector candidates = myToJunction->getOutgoing();
    1423      3084865 :     for (ConstMSEdgeVector::const_iterator it = candidates.begin(); it != candidates.end(); it++) {
    1424      2697699 :         if ((*it)->getToJunction() == myFromJunction) { //reverse edge
    1425       309052 :             if (myBidiEdge != nullptr && isSuperposable(*it)) {
    1426            0 :                 WRITE_WARNINGF(TL("Ambiguous superposable edges between junction '%' and '%'."), myToJunction->getID(), myFromJunction->getID());
    1427            0 :                 break;
    1428              :             }
    1429       309052 :             if (isSuperposable(*it)) {
    1430           26 :                 myBidiEdge = *it;
    1431           26 :                 setBidiLanes();
    1432              :             }
    1433              :         }
    1434              :     }
    1435       387166 : }
    1436              : 
    1437              : 
    1438              : void
    1439        31776 : MSEdge::setBidiLanes() {
    1440              :     assert(myBidiEdge != nullptr);
    1441        31776 :     if (getNumLanes() == 1 && myBidiEdge->getNumLanes() == 1) {
    1442              :         // the other way round is set when this method runs for the bidiEdge
    1443        31238 :         getLanes()[0]->setBidiLane(myBidiEdge->getLanes()[0]);
    1444              :     } else {
    1445              :         // find lanes with matching reversed shapes
    1446              :         int numBidiLanes = 0;
    1447         1680 :         for (MSLane* l1 : *myLanes) {
    1448         3630 :             for (MSLane* l2 : *myBidiEdge->myLanes) {
    1449         2488 :                 if (l1->getShape().reverse().almostSame(l2->getShape(), POSITION_EPS * 2)) {
    1450          592 :                     l1->setBidiLane(l2);
    1451          592 :                     numBidiLanes++;
    1452              :                 }
    1453              :             }
    1454              :         }
    1455              :         // warn only once for each pair
    1456          538 :         if (numBidiLanes == 0 && getNumericalID() < myBidiEdge->getNumericalID()) {
    1457           15 :             WRITE_WARNINGF(TL("Edge '%' and bidi edge '%' have no matching bidi lanes"), getID(), myBidiEdge->getID());
    1458              :         }
    1459              :     }
    1460        31776 : }
    1461              : 
    1462              : 
    1463              : bool
    1464       309052 : MSEdge::isSuperposable(const MSEdge* other) {
    1465       309052 :     if (other == nullptr || other->getLanes().size() != myLanes->size()) {
    1466              :         return false;
    1467              :     }
    1468              :     std::vector<MSLane*>::const_iterator it1 = myLanes->begin();
    1469              :     std::vector<MSLane*>::const_reverse_iterator it2 = other->getLanes().rbegin();
    1470              :     do {
    1471       304470 :         if ((*it1)->getShape().reverse() != (*it2)->getShape()) {
    1472              :             return false;
    1473              :         }
    1474              :         it1++;
    1475              :         it2++;
    1476           26 :     } while (it1 != myLanes->end());
    1477              : 
    1478              :     return true;
    1479              : }
    1480              : 
    1481              : 
    1482              : void
    1483        72503 : MSEdge::addWaiting(SUMOVehicle* vehicle) const {
    1484              : #ifdef HAVE_FOX
    1485        72503 :     ScopedLocker<> lock(myWaitingMutex, MSGlobals::gNumSimThreads > 1);
    1486              : #endif
    1487        72503 :     myWaiting.push_back(vehicle);
    1488        72503 : }
    1489              : 
    1490              : 
    1491              : void
    1492        64150 : MSEdge::removeWaiting(const SUMOVehicle* vehicle) const {
    1493              : #ifdef HAVE_FOX
    1494        64150 :     ScopedLocker<> lock(myWaitingMutex, MSGlobals::gNumSimThreads > 1);
    1495              : #endif
    1496        64150 :     std::vector<SUMOVehicle*>::iterator it = std::find(myWaiting.begin(), myWaiting.end(), vehicle);
    1497        64150 :     if (it != myWaiting.end()) {
    1498        63540 :         myWaiting.erase(it);
    1499              :     }
    1500        64150 : }
    1501              : 
    1502              : 
    1503              : SUMOVehicle*
    1504        77335 : MSEdge::getWaitingVehicle(MSTransportable* transportable, const double position) const {
    1505              : #ifdef HAVE_FOX
    1506        77335 :     ScopedLocker<> lock(myWaitingMutex, MSGlobals::gNumSimThreads > 1);
    1507              : #endif
    1508        77637 :     for (SUMOVehicle* const vehicle : myWaiting) {
    1509         5153 :         if (transportable->isWaitingFor(vehicle)) {
    1510         7305 :             if (vehicle->isStoppedInRange(position, MSGlobals::gStopTolerance) ||
    1511         2244 :                     (!vehicle->hasDeparted() &&
    1512         2038 :                      (vehicle->getParameter().departProcedure == DepartDefinition::TRIGGERED ||
    1513           83 :                       vehicle->getParameter().departProcedure == DepartDefinition::CONTAINER_TRIGGERED))) {
    1514              :                 return vehicle;
    1515              :             }
    1516          210 :             if (!vehicle->isLineStop(position) && vehicle->allowsBoarding(transportable)) {
    1517          228 :                 WRITE_WARNING((transportable->isPerson() ? "Person '" : "Container '")
    1518              :                               + transportable->getID() + "' at edge '" + getID() + "' position " + toString(position) + " cannot use waiting vehicle '"
    1519              :                               + vehicle->getID() + "' at position " + toString(vehicle->getPositionOnLane()) + " because it is too far away.");
    1520              :             }
    1521              :         }
    1522              :     }
    1523              :     return nullptr;
    1524              : }
    1525              : 
    1526              : std::vector<const SUMOVehicle*>
    1527       144417 : MSEdge::getVehicles() const {
    1528              :     std::vector<const SUMOVehicle*> result;
    1529       144417 :     if (MSGlobals::gUseMesoSim) {
    1530          220 :         for (MESegment* segment = MSGlobals::gMesoNet->getSegmentForEdge(*this); segment != nullptr; segment = segment->getNextSegment()) {
    1531          122 :             std::vector<const MEVehicle*> segmentVehs = segment->getVehicles();
    1532          122 :             result.insert(result.end(), segmentVehs.begin(), segmentVehs.end());
    1533          122 :         }
    1534              :     } else {
    1535       386591 :         for (MSLane* lane : getLanes()) {
    1536       830458 :             for (auto veh : lane->getVehiclesSecure()) {
    1537       588235 :                 result.push_back(veh);
    1538              :             }
    1539       242223 :             lane->releaseVehicles();
    1540              :         }
    1541              :     }
    1542       144417 :     return result;
    1543            0 : }
    1544              : 
    1545              : int
    1546       622582 : MSEdge::getNumDrivingLanes() const {
    1547              :     int result = 0;
    1548       622582 :     SVCPermissions filter = SVCAll;
    1549       622582 :     if ((myCombinedPermissions & ~(SVC_PEDESTRIAN | SVC_WHEELCHAIR)) != 0) {
    1550              :         filter = ~(SVC_PEDESTRIAN | SVC_WHEELCHAIR);
    1551         2050 :     } else if ((myCombinedPermissions & (SVC_PEDESTRIAN | SVC_WHEELCHAIR)) != 0) {
    1552              :         // filter out green verge
    1553              :         filter = (SVC_PEDESTRIAN | SVC_WHEELCHAIR);
    1554              :     }
    1555      1402542 :     for (const MSLane* const l : *myLanes) {
    1556       779960 :         if ((l->getPermissions() & filter) != 0) {
    1557       690586 :             result++;
    1558              :         }
    1559              :     }
    1560       622582 :     return result;
    1561              : }
    1562              : 
    1563              : int
    1564          399 : MSEdge::getVehicleNumber() const {
    1565          399 :     return (int)getVehicles().size();
    1566              : }
    1567              : 
    1568              : 
    1569              : bool
    1570            0 : MSEdge::isEmpty() const {
    1571              :     /// more efficient than retrieving vehicle number
    1572            0 :     if (MSGlobals::gUseMesoSim) {
    1573            0 :         for (MESegment* segment = MSGlobals::gMesoNet->getSegmentForEdge(*this); segment != nullptr; segment = segment->getNextSegment()) {
    1574            0 :             if (segment->getCarNumber() > 0) {
    1575              :                 return false;
    1576              :             }
    1577              :         }
    1578              :     } else {
    1579            0 :         for (MSLane* lane : getLanes()) {
    1580            0 :             if (lane->getVehicleNumber() > 0) {
    1581              :                 return false;
    1582              :             }
    1583              :         }
    1584              :     }
    1585              :     return true;
    1586              : }
    1587              : 
    1588              : 
    1589              : double
    1590           14 : MSEdge::getWaitingSeconds() const {
    1591              :     double wtime = 0;
    1592           14 :     if (MSGlobals::gUseMesoSim) {
    1593           12 :         for (MESegment* segment = MSGlobals::gMesoNet->getSegmentForEdge(*this); segment != nullptr; segment = segment->getNextSegment()) {
    1594            9 :             wtime += segment->getWaitingSeconds();
    1595              :         }
    1596              :     } else {
    1597           34 :         for (MSLane* lane : getLanes()) {
    1598           23 :             wtime += lane->getWaitingSeconds();
    1599              :         }
    1600              :     }
    1601           14 :     return wtime;
    1602              : }
    1603              : 
    1604              : 
    1605              : double
    1606           22 : MSEdge::getOccupancy() const {
    1607           22 :     if (myLanes->size() == 0) {
    1608              :         return 0;
    1609              :     }
    1610           22 :     if (MSGlobals::gUseMesoSim) {
    1611              :         /// @note MESegment only tracks brutto occupancy so we compute this from sratch
    1612              :         double sum = 0;
    1613            8 :         for (const SUMOVehicle* veh : getVehicles()) {
    1614            4 :             sum += dynamic_cast<const MEVehicle*>(veh)->getVehicleType().getLength();
    1615            4 :         }
    1616            4 :         return sum / (myLength * (double)myLanes->size());
    1617              :     } else {
    1618              :         double sum = 0;
    1619           48 :         for (auto lane : getLanes()) {
    1620           30 :             sum += lane->getNettoOccupancy();
    1621              :         }
    1622           18 :         return sum / (double)myLanes->size();
    1623              :     }
    1624              : }
    1625              : 
    1626              : 
    1627              : double
    1628            0 : MSEdge::getFlow() const {
    1629            0 :     if (myLanes->size() == 0) {
    1630              :         return 0;
    1631              :     }
    1632              :     double flow = 0;
    1633            0 :     for (MESegment* segment = MSGlobals::gMesoNet->getSegmentForEdge(*this); segment != nullptr; segment = segment->getNextSegment()) {
    1634            0 :         flow += (double) segment->getCarNumber() * segment->getMeanSpeed();
    1635              :     }
    1636            0 :     return 3600 * flow / (*myLanes)[0]->getLength();
    1637              : }
    1638              : 
    1639              : 
    1640              : double
    1641            0 : MSEdge::getBruttoOccupancy() const {
    1642            0 :     if (myLanes->size() == 0) {
    1643              :         return 0;
    1644              :     }
    1645              :     double occ = 0;
    1646            0 :     for (MESegment* segment = MSGlobals::gMesoNet->getSegmentForEdge(*this); segment != nullptr; segment = segment->getNextSegment()) {
    1647            0 :         occ += segment->getBruttoOccupancy();
    1648              :     }
    1649            0 :     return occ / (*myLanes)[0]->getLength() / (double)(myLanes->size());
    1650              : }
    1651              : 
    1652              : double
    1653         4240 : MSEdge::getTravelTimeAggregated(const MSEdge* const edge, const SUMOVehicle* const veh, double /*time*/) {
    1654         4240 :     return edge->getLength() / MIN2(MSRoutingEngine::getAssumedSpeed(edge, veh), veh->getMaxSpeed());
    1655              : }
    1656              : 
    1657              : 
    1658              : void
    1659         2098 : MSEdge::inferEdgeType() {
    1660              :     // @note must be called after closeBuilding() to ensure successors and
    1661              :     // predecessors are set
    1662         2098 :     if (isInternal() && myEdgeType == "") {
    1663         1274 :         const std::string typeBefore = getNormalBefore()->getEdgeType();
    1664         1274 :         if (typeBefore != "") {
    1665          694 :             const std::string typeAfter = getNormalSuccessor()->getEdgeType();
    1666          694 :             if (typeBefore == typeAfter) {
    1667              :                 myEdgeType = typeBefore;
    1668          314 :             } else if (typeAfter != "") {
    1669           68 :                 MSNet* net = MSNet::getInstance();
    1670           68 :                 auto resBefore = net->getRestrictions(typeBefore);
    1671           68 :                 auto resAfter = net->getRestrictions(typeAfter);
    1672           68 :                 if (resBefore != nullptr && resAfter != nullptr) {
    1673              :                     // create new restrictions for this type-combination
    1674           96 :                     myEdgeType = typeBefore + "|" + typeAfter;
    1675           48 :                     if (net->getRestrictions(myEdgeType) == nullptr) {
    1676           48 :                         for (const auto& item : *resBefore) {
    1677           24 :                             const SUMOVehicleClass svc = item.first;
    1678           24 :                             const double speed = item.second;
    1679              :                             const auto it = (*resAfter).find(svc);
    1680           24 :                             if (it != (*resAfter).end()) {
    1681           24 :                                 const double speed2 = it->second;
    1682           24 :                                 const double newSpeed = (MSNet::getInstance()->hasJunctionHigherSpeeds()
    1683           24 :                                                          ? MAX2(speed, speed2) : (speed + speed2) / 2);
    1684           24 :                                 net->addRestriction(myEdgeType, svc, newSpeed);
    1685              :                             }
    1686              :                         }
    1687              :                     }
    1688              :                 }
    1689              :             }
    1690              :         }
    1691              :     }
    1692         2098 : }
    1693              : 
    1694              : 
    1695              : double
    1696         2178 : MSEdge::getDistanceAt(double pos) const {
    1697              :     // negative values of myDistances indicate descending kilometrage
    1698         2178 :     return fabs(myDistance + pos);
    1699              : }
    1700              : 
    1701              : 
    1702              : bool
    1703         1329 : MSEdge::hasTransientPermissions() const {
    1704         1329 :     return myHaveTransientPermissions;
    1705              : }
    1706              : 
    1707              : 
    1708              : std::pair<double, SUMOTime>
    1709    587192766 : MSEdge::getLastBlocked(int index) const {
    1710    587192766 :     if (myLaneChanger != nullptr) {
    1711    587192766 :         return myLaneChanger->getLastBlocked(index);
    1712              :     }
    1713            0 :     return std::make_pair(-1, -1);
    1714              : }
    1715              : 
    1716              : 
    1717              : double
    1718         1631 : MSEdge::getPreference(const SUMOVTypeParameter& pars) const {
    1719         3262 :     return MSNet::getInstance()->getPreference(getRoutingType(), pars);
    1720              : }
    1721              : 
    1722              : void
    1723         7032 : MSEdge::clearState() {
    1724              :     myPersons.clear();
    1725              :     myContainers.clear();
    1726              :     myWaiting.clear();
    1727         7032 : }
    1728              : 
    1729              : /****************************************************************************/
        

Generated by: LCOV version 2.0-1