LCOV - code coverage report
Current view: top level - src/microsim/trigger - MSTriggeredRerouter.cpp (source / functions) Coverage Total Hit
Test: lcov.info Lines: 90.5 % 590 534
Test Date: 2025-12-06 15:35:27 Functions: 94.3 % 35 33

            Line data    Source code
       1              : /****************************************************************************/
       2              : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
       3              : // Copyright (C) 2001-2025 German Aerospace Center (DLR) and others.
       4              : // This program and the accompanying materials are made available under the
       5              : // terms of the Eclipse Public License 2.0 which is available at
       6              : // https://www.eclipse.org/legal/epl-2.0/
       7              : // This Source Code may also be made available under the following Secondary
       8              : // Licenses when the conditions for such availability set forth in the Eclipse
       9              : // Public License 2.0 are satisfied: GNU General Public License, version 2
      10              : // or later which is available at
      11              : // https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html
      12              : // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
      13              : /****************************************************************************/
      14              : /// @file    MSTriggeredRerouter.cpp
      15              : /// @author  Daniel Krajzewicz
      16              : /// @author  Jakob Erdmann
      17              : /// @author  Michael Behrisch
      18              : /// @author  Mirco Sturari
      19              : /// @author  Mirko Barthauer
      20              : /// @date    Mon, 25 July 2005
      21              : ///
      22              : // Reroutes vehicles passing an edge
      23              : /****************************************************************************/
      24              : #include <config.h>
      25              : 
      26              : #include <string>
      27              : #include <algorithm>
      28              : #ifdef HAVE_FOX
      29              : #include <utils/common/ScopedLocker.h>
      30              : #endif
      31              : #include <utils/options/OptionsCont.h>
      32              : #include <utils/common/MsgHandler.h>
      33              : #include <utils/common/Command.h>
      34              : #include <utils/xml/SUMOXMLDefinitions.h>
      35              : #include <utils/common/UtilExceptions.h>
      36              : #include <utils/common/ToString.h>
      37              : #include <utils/common/StringUtils.h>
      38              : #include <utils/xml/SUMOSAXHandler.h>
      39              : #include <utils/router/DijkstraRouter.h>
      40              : #include <utils/common/RandHelper.h>
      41              : #include <utils/common/WrappingCommand.h>
      42              : #include <microsim/MSEdgeWeightsStorage.h>
      43              : #include <microsim/MSLane.h>
      44              : #include <microsim/MSLink.h>
      45              : #include <microsim/MSVehicle.h>
      46              : #include <microsim/MSBaseVehicle.h>
      47              : #include <microsim/MSRoute.h>
      48              : #include <microsim/MSEdge.h>
      49              : #include <microsim/MSEventControl.h>
      50              : #include <microsim/MSNet.h>
      51              : #include <microsim/MSVehicleControl.h>
      52              : #include <microsim/MSGlobals.h>
      53              : #include <microsim/MSParkingArea.h>
      54              : #include <microsim/MSStop.h>
      55              : #include <microsim/traffic_lights/MSRailSignal.h>
      56              : #include <microsim/traffic_lights/MSRailSignalConstraint.h>
      57              : #include <microsim/transportables/MSPerson.h>
      58              : #include <microsim/devices/MSDevice_Routing.h>
      59              : #include <microsim/devices/MSRoutingEngine.h>
      60              : #include "MSTriggeredRerouter.h"
      61              : 
      62              : #include <mesosim/MELoop.h>
      63              : #include <mesosim/MESegment.h>
      64              : 
      65              : //#define DEBUG_REROUTER
      66              : //#define DEBUG_OVERTAKING
      67              : #define DEBUGCOND(veh) (veh.isSelected())
      68              : //#define DEBUGCOND(veh) (true)
      69              : //#define DEBUGCOND(veh) (veh.getID() == "")
      70              : 
      71              : /// assume that a faster train has more priority and a slower train doesn't matter
      72              : #define DEFAULT_PRIO_OVERTAKER 1
      73              : #define DEFAULT_PRIO_OVERTAKEN 0.001
      74              : 
      75              : // ===========================================================================
      76              : // static member definition
      77              : // ===========================================================================
      78              : MSEdge MSTriggeredRerouter::mySpecialDest_keepDestination("MSTriggeredRerouter_keepDestination", -1, SumoXMLEdgeFunc::UNKNOWN, "", "", "", -1, 0);
      79              : MSEdge MSTriggeredRerouter::mySpecialDest_terminateRoute("MSTriggeredRerouter_terminateRoute", -1, SumoXMLEdgeFunc::UNKNOWN, "", "", "", -1, 0);
      80              : const double MSTriggeredRerouter::DEFAULT_MAXDELAY(7200);
      81              : std::map<std::string, MSTriggeredRerouter*> MSTriggeredRerouter::myInstances;
      82              : 
      83              : 
      84              : // ===========================================================================
      85              : // method definitions
      86              : // ===========================================================================
      87         3998 : MSTriggeredRerouter::MSTriggeredRerouter(const std::string& id,
      88              :         const MSEdgeVector& edges, double prob, bool off, bool optional,
      89         3998 :         SUMOTime timeThreshold, const std::string& vTypes, const Position& pos, const double radius) :
      90              :     Named(id),
      91              :     MSMoveReminder(id),
      92              :     MSStoppingPlaceRerouter("parking"),
      93         3998 :     myEdges(edges),
      94         3998 :     myProbability(prob),
      95         3998 :     myUserProbability(prob),
      96         3998 :     myAmInUserMode(false),
      97         3998 :     myAmOptional(optional),
      98         3998 :     myPosition(pos),
      99         3998 :     myRadius(radius),
     100         3998 :     myTimeThreshold(timeThreshold),
     101        11994 :     myHaveParkProbs(false) {
     102         3998 :     myInstances[id] = this;
     103              :     // build actors
     104         9298 :     for (const MSEdge* const e : edges) {
     105         5300 :         if (MSGlobals::gUseMesoSim) {
     106          696 :             MSGlobals::gMesoNet->getSegmentForEdge(*e)->addDetector(this);
     107              :         }
     108        11303 :         for (MSLane* const lane : e->getLanes()) {
     109         6003 :             lane->addMoveReminder(this);
     110              :         }
     111              :     }
     112         3998 :     if (off) {
     113            1 :         setUserMode(true);
     114            1 :         setUserUsageProbability(0);
     115              :     }
     116         7996 :     const std::vector<std::string> vt = StringTokenizer(vTypes).getVector();
     117              :     myVehicleTypes.insert(vt.begin(), vt.end());
     118              :     if (myPosition == Position::INVALID) {
     119         3581 :         myPosition = edges.front()->getLanes()[0]->getShape()[0];
     120              :     }
     121         3998 : }
     122              : 
     123              : 
     124         7279 : MSTriggeredRerouter::~MSTriggeredRerouter() {
     125              :     myInstances.erase(getID());
     126        11273 : }
     127              : 
     128              : 
     129              : // ------------ loading begin
     130              : void
     131        19510 : MSTriggeredRerouter::myStartElement(int element,
     132              :                                     const SUMOSAXAttributes& attrs) {
     133        19510 :     if (element == SUMO_TAG_INTERVAL) {
     134         3791 :         bool ok = true;
     135         3791 :         myParsedRerouteInterval = RerouteInterval();
     136         3791 :         myParsedRerouteInterval.begin = attrs.getOptSUMOTimeReporting(SUMO_ATTR_BEGIN, nullptr, ok, -1);
     137         3791 :         myParsedRerouteInterval.end = attrs.getOptSUMOTimeReporting(SUMO_ATTR_END, nullptr, ok, SUMOTime_MAX);
     138         3791 :         if (myParsedRerouteInterval.begin >= myParsedRerouteInterval.end) {
     139           18 :             throw ProcessError(TLF("rerouter '%': interval end % is not after begin %.", getID(),
     140              :                                    time2string(myParsedRerouteInterval.end),
     141           18 :                                    time2string(myParsedRerouteInterval.begin)));
     142              :         }
     143              :     }
     144        19504 :     if (element == SUMO_TAG_DEST_PROB_REROUTE) {
     145              :         // by giving probabilities of new destinations
     146              :         // get the destination edge
     147          214 :         std::string dest = attrs.getStringSecure(SUMO_ATTR_ID, "");
     148          214 :         if (dest == "") {
     149            0 :             throw ProcessError(TLF("rerouter '%': destProbReroute has no destination edge id.", getID()));
     150              :         }
     151          214 :         MSEdge* to = MSEdge::dictionary(dest);
     152          214 :         if (to == nullptr) {
     153           69 :             if (dest == "keepDestination") {
     154              :                 to = &mySpecialDest_keepDestination;
     155           41 :             } else if (dest == "terminateRoute") {
     156              :                 to = &mySpecialDest_terminateRoute;
     157              :             } else {
     158            0 :                 throw ProcessError(TLF("rerouter '%': Destination edge '%' is not known.", getID(), dest));
     159              :             }
     160              :         }
     161              :         // get the probability to reroute
     162          214 :         bool ok = true;
     163          214 :         double prob = attrs.getOpt<double>(SUMO_ATTR_PROB, getID().c_str(), ok, 1.);
     164          214 :         if (!ok) {
     165            0 :             throw ProcessError();
     166              :         }
     167          214 :         if (prob < 0) {
     168            0 :             throw ProcessError(TLF("rerouter '%': Attribute 'probability' for destination '%' is negative (must not).", getID(), dest));
     169              :         }
     170              :         // add
     171          214 :         myParsedRerouteInterval.edgeProbs.add(to, prob);
     172              :     }
     173              : 
     174        19504 :     if (element == SUMO_TAG_CLOSING_REROUTE) {
     175              :         // by closing edge
     176          926 :         const std::string& closed_id = attrs.getStringSecure(SUMO_ATTR_ID, "");
     177          926 :         MSEdge* const closedEdge = MSEdge::dictionary(closed_id);
     178          926 :         if (closedEdge == nullptr) {
     179            0 :             throw ProcessError(TLF("rerouter '%': Edge '%' to close is not known.", getID(), closed_id));
     180              :         }
     181              :         bool ok;
     182          926 :         const std::string allow = attrs.getOpt<std::string>(SUMO_ATTR_ALLOW, getID().c_str(), ok, "", false);
     183          926 :         const std::string disallow = attrs.getOpt<std::string>(SUMO_ATTR_DISALLOW, getID().c_str(), ok, "");
     184          926 :         const SUMOTime until = attrs.getOptSUMOTimeReporting(SUMO_ATTR_UNTIL, nullptr, ok, -1);
     185          926 :         SVCPermissions permissions = parseVehicleClasses(allow, disallow);
     186          926 :         myParsedRerouteInterval.closed[closedEdge] = std::make_pair(permissions, STEPS2TIME(until));
     187              :     }
     188              : 
     189        19504 :     if (element == SUMO_TAG_CLOSING_LANE_REROUTE) {
     190              :         // by closing lane
     191          139 :         std::string closed_id = attrs.getStringSecure(SUMO_ATTR_ID, "");
     192          139 :         MSLane* closedLane = MSLane::dictionary(closed_id);
     193          139 :         if (closedLane == nullptr) {
     194            0 :             throw ProcessError(TLF("rerouter '%': Lane '%' to close is not known.", getID(), closed_id));
     195              :         }
     196              :         bool ok;
     197              :         SVCPermissions permissions = SVC_AUTHORITY;
     198          139 :         if (attrs.hasAttribute(SUMO_ATTR_ALLOW) || attrs.hasAttribute(SUMO_ATTR_DISALLOW)) {
     199           68 :             const std::string allow = attrs.getOpt<std::string>(SUMO_ATTR_ALLOW, getID().c_str(), ok, "", false);
     200           68 :             const std::string disallow = attrs.getOpt<std::string>(SUMO_ATTR_DISALLOW, getID().c_str(), ok, "");
     201           68 :             permissions = parseVehicleClasses(allow, disallow);
     202              :         }
     203          139 :         myParsedRerouteInterval.closedLanes[closedLane] = permissions;
     204              :     }
     205              : 
     206        19504 :     if (element == SUMO_TAG_ROUTE_PROB_REROUTE) {
     207              :         // by explicit rerouting using routes
     208              :         // check if route exists
     209          745 :         std::string routeStr = attrs.getStringSecure(SUMO_ATTR_ID, "");
     210          745 :         if (routeStr == "") {
     211            0 :             throw ProcessError(TLF("rerouter '%': routeProbReroute has no alternative route id.", getID()));
     212              :         }
     213          745 :         ConstMSRoutePtr route = MSRoute::dictionary(routeStr);
     214          745 :         if (route == nullptr) {
     215            0 :             throw ProcessError(TLF("rerouter '%': Alternative route '%' does not exist.", getID(), routeStr));
     216              :         }
     217              : 
     218              :         // get the probability to reroute
     219          745 :         bool ok = true;
     220          745 :         double prob = attrs.getOpt<double>(SUMO_ATTR_PROB, getID().c_str(), ok, 1.);
     221          745 :         if (!ok) {
     222            0 :             throw ProcessError();
     223              :         }
     224          745 :         if (prob < 0) {
     225            0 :             throw ProcessError(TLF("rerouter '%': Attribute 'probability' for alternative route '%' is negative (must not).", getID(), routeStr));
     226              :         }
     227              :         // add
     228         1490 :         myParsedRerouteInterval.routeProbs.add(route, prob);
     229              :     }
     230              : 
     231        19504 :     if (element == SUMO_TAG_PARKING_AREA_REROUTE) {
     232        13518 :         std::string parkingarea = attrs.getStringSecure(SUMO_ATTR_ID, "");
     233        13518 :         if (parkingarea == "") {
     234            0 :             throw ProcessError(TLF("rerouter '%': parkingAreaReroute requires a parkingArea id.", getID()));
     235              :         }
     236        13518 :         MSParkingArea* pa = static_cast<MSParkingArea*>(MSNet::getInstance()->getStoppingPlace(parkingarea, SUMO_TAG_PARKING_AREA));
     237        13518 :         if (pa == nullptr) {
     238            0 :             throw ProcessError(TLF("rerouter '%': parkingArea '%' is not known.", getID(), parkingarea));
     239              :         }
     240              :         // get the probability to reroute
     241        13518 :         bool ok = true;
     242        13518 :         const double prob = attrs.getOpt<double>(SUMO_ATTR_PROB, getID().c_str(), ok, 1.);
     243        13518 :         if (!ok) {
     244            0 :             throw ProcessError();
     245              :         }
     246        13518 :         if (prob < 0) {
     247            0 :             throw ProcessError(TLF("rerouter '%': Attribute 'probability' for parkingArea '%' is negative (must not).", getID(), parkingarea));
     248              :         }
     249        13518 :         const bool visible = attrs.getOpt<bool>(SUMO_ATTR_VISIBLE, getID().c_str(), ok, false);
     250              :         // add
     251        13518 :         myParsedRerouteInterval.parkProbs.add(std::make_pair(pa, visible), prob);
     252        13518 :         myHaveParkProbs = true;
     253              :     }
     254              : 
     255        19504 :     if (element == SUMO_TAG_VIA_PROB_REROUTE) {
     256              :         // by giving probabilities of vias
     257           37 :         std::string viaID  = attrs.getStringSecure(SUMO_ATTR_ID, "");
     258           37 :         if (viaID == "") {
     259            0 :             throw ProcessError(TLF("rerouter '%': No via edge id given.", getID()));
     260              :         }
     261           37 :         MSEdge* const via = MSEdge::dictionary(viaID);
     262           37 :         if (via == nullptr) {
     263            0 :             throw ProcessError(TLF("rerouter '%': Via Edge '%' is not known.", getID(), viaID));
     264              :         }
     265              :         // get the probability to reroute
     266           37 :         bool ok = true;
     267           37 :         double prob = attrs.getOpt<double>(SUMO_ATTR_PROB, getID().c_str(), ok, 1.);
     268           37 :         if (!ok) {
     269            0 :             throw ProcessError();
     270              :         }
     271           37 :         if (prob < 0) {
     272            0 :             throw ProcessError(TLF("rerouter '%': Attribute 'probability' for via '%' is negative (must not).", getID(), viaID));
     273              :         }
     274              :         // add
     275           37 :         myParsedRerouteInterval.edgeProbs.add(via, prob);
     276           37 :         myParsedRerouteInterval.isVia = true;
     277              :     }
     278        19504 :     if (element == SUMO_TAG_OVERTAKING_REROUTE) {
     279              :         // for letting a slow train use a siding to be overtaken by a fast train
     280              :         OvertakeLocation oloc;
     281           99 :         bool ok = true;
     282          396 :         for (const std::string& edgeID : attrs.get<std::vector<std::string> >(SUMO_ATTR_MAIN, getID().c_str(), ok)) {
     283          297 :             MSEdge* edge = MSEdge::dictionary(edgeID);
     284          297 :             if (edge == nullptr) {
     285            0 :                 throw InvalidArgument(TLF("The main edge '%' to use within rerouter '%' is not known.", edgeID, getID()));
     286              :             }
     287          297 :             oloc.main.push_back(edge);
     288          297 :             oloc.cMain.push_back(edge);
     289           99 :         }
     290          396 :         for (const std::string& edgeID : attrs.get<std::vector<std::string> >(SUMO_ATTR_SIDING, getID().c_str(), ok)) {
     291          297 :             MSEdge* edge = MSEdge::dictionary(edgeID);
     292          297 :             if (edge == nullptr) {
     293            0 :                 throw InvalidArgument(TLF("The siding edge '%' to use within rerouter '%' is not known.", edgeID, getID()));
     294              :             }
     295          297 :             oloc.siding.push_back(edge);
     296          297 :             oloc.cSiding.push_back(edge);
     297           99 :         }
     298           99 :         oloc.sidingExit = findSignal(oloc.cSiding.begin(), oloc.cSiding.end());
     299           99 :         if (oloc.sidingExit == nullptr) {
     300            0 :             throw InvalidArgument(TLF("The siding within rerouter '%' does not have a rail signal.", getID()));
     301              :         }
     302          198 :         for (auto it = oloc.cSiding.begin(); it != oloc.cSiding.end(); it++) {
     303          198 :             oloc.sidingLength += (*it)->getLength();
     304          198 :             if ((*it)->getToJunction()->getID() == oloc.sidingExit->getID()) {
     305              :                 break;
     306              :             }
     307              :         }
     308           99 :         oloc.minSaving = attrs.getOpt<double>(SUMO_ATTR_MINSAVING, getID().c_str(), ok, 300);
     309           99 :         const bool hasAlternatives = myParsedRerouteInterval.overtakeLocations.size() > 0;
     310           99 :         oloc.defer = attrs.getOpt<bool>(SUMO_ATTR_DEFER, getID().c_str(), ok, hasAlternatives);
     311           99 :         myParsedRerouteInterval.overtakeLocations.push_back(oloc);
     312           99 :     }
     313        19504 :     if (element == SUMO_TAG_STATION_REROUTE) {
     314              :         // for letting a train switch it's stopping place in case of conflict
     315           36 :         const std::string stopID = attrs.getStringSecure(SUMO_ATTR_ID, "");
     316           36 :         if (stopID == "") {
     317            0 :             throw ProcessError(TLF("rerouter '%': stationReroute requires a stopping place id.", getID()));
     318              :         }
     319           36 :         MSStoppingPlace* stop = MSNet::getInstance()->getStoppingPlace(stopID);
     320           36 :         if (stop == nullptr) {
     321            0 :             throw ProcessError(TLF("rerouter '%': stopping place '%' is not known.", getID(), stopID));
     322              :         }
     323           36 :         myParsedRerouteInterval.stopAlternatives.push_back(std::make_pair(stop, true));
     324              :     }
     325        19504 : }
     326              : 
     327              : 
     328              : void
     329        23496 : MSTriggeredRerouter::myEndElement(int element) {
     330        23496 :     if (element == SUMO_TAG_INTERVAL) {
     331              :         // precompute permissionsAllowAll
     332              :         bool allowAll = true;
     333         4136 :         for (const auto& entry : myParsedRerouteInterval.closed) {
     334          765 :             allowAll = allowAll && entry.second.first == SVCAll;
     335              :             if (!allowAll) {
     336              :                 break;
     337              :             }
     338              :         }
     339         3785 :         myParsedRerouteInterval.permissionsAllowAll = allowAll;
     340              : 
     341        17300 :         for (auto paVi : myParsedRerouteInterval.parkProbs.getVals()) {
     342        13515 :             dynamic_cast<MSParkingArea*>(paVi.first)->setNumAlternatives((int)myParsedRerouteInterval.parkProbs.getVals().size() - 1);
     343              :         }
     344         3785 :         if (myParsedRerouteInterval.closedLanes.size() > 0) {
     345              :             // collect edges that are affect by a closed lane
     346              :             std::set<MSEdge*> affected;
     347          223 :             for (std::pair<MSLane*, SVCPermissions> settings : myParsedRerouteInterval.closedLanes) {
     348          133 :                 affected.insert(&settings.first->getEdge());
     349              :             }
     350           90 :             myParsedRerouteInterval.closedLanesAffected.insert(myParsedRerouteInterval.closedLanesAffected.begin(), affected.begin(), affected.end());
     351              :         }
     352         3785 :         const SUMOTime closingBegin = myParsedRerouteInterval.begin;
     353         3785 :         const SUMOTime simBegin = string2time(OptionsCont::getOptions().getString("begin"));
     354         3785 :         if (closingBegin < simBegin && myParsedRerouteInterval.end > simBegin) {
     355              :             // interval started before simulation begin but is still active at
     356              :             // the start of the simulation
     357          403 :             myParsedRerouteInterval.begin = simBegin;
     358              :         }
     359         3785 :         myIntervals.push_back(myParsedRerouteInterval);
     360         3785 :         myIntervals.back().id = (long long int)&myIntervals.back();
     361         3785 :         if (!(myParsedRerouteInterval.closed.empty() && myParsedRerouteInterval.closedLanes.empty())) {
     362         1598 :             MSNet::getInstance()->getBeginOfTimestepEvents()->addEvent(
     363          799 :                 new WrappingCommand<MSTriggeredRerouter>(this, &MSTriggeredRerouter::setPermissions), myParsedRerouteInterval.begin);
     364              :         }
     365              :     }
     366        23496 : }
     367              : 
     368              : 
     369              : // ------------ loading end
     370              : 
     371              : 
     372              : SUMOTime
     373          944 : MSTriggeredRerouter::setPermissions(const SUMOTime currentTime) {
     374              :     bool updateVehicles = false;
     375         1931 :     for (const RerouteInterval& i : myIntervals) {
     376          987 :         if (i.begin == currentTime && !(i.closed.empty() && i.closedLanes.empty()) /*&& i.permissions != SVCAll*/) {
     377         1700 :             for (const auto& settings : i.closed) {
     378         1821 :                 for (MSLane* lane : settings.first->getLanes()) {
     379              :                     //std::cout << SIMTIME << " closing: intervalID=" << i.id << " lane=" << lane->getID() << " prevPerm=" << getVehicleClassNames(lane->getPermissions()) << " new=" << getVehicleClassNames(i.permissions) << "\n";
     380          918 :                     lane->setPermissions(settings.second.first, i.id);
     381              :                 }
     382          903 :                 settings.first->rebuildAllowedLanes();
     383              :                 updateVehicles = true;
     384              :             }
     385          944 :             for (std::pair<MSLane*, SVCPermissions> settings : i.closedLanes) {
     386          147 :                 settings.first->setPermissions(settings.second, i.id);
     387          147 :                 settings.first->getEdge().rebuildAllowedLanes();
     388              :                 updateVehicles = true;
     389              :             }
     390         1594 :             MSNet::getInstance()->getBeginOfTimestepEvents()->addEvent(
     391          797 :                 new WrappingCommand<MSTriggeredRerouter>(this, &MSTriggeredRerouter::setPermissions), i.end);
     392              :         }
     393          987 :         if (i.end == currentTime && !(i.closed.empty() && i.closedLanes.empty()) /*&& i.permissions != SVCAll*/) {
     394          325 :             for (auto settings : i.closed) {
     395          301 :                 for (MSLane* lane : settings.first->getLanes()) {
     396          151 :                     lane->resetPermissions(i.id);
     397              :                     //std::cout << SIMTIME << " opening: intervalID=" << i.id << " lane=" << lane->getID() << " restore prevPerm=" << getVehicleClassNames(lane->getPermissions()) << "\n";
     398              :                 }
     399          150 :                 settings.first->rebuildAllowedLanes();
     400              :                 updateVehicles = true;
     401              :             }
     402          286 :             for (std::pair<MSLane*, SVCPermissions> settings : i.closedLanes) {
     403          111 :                 settings.first->resetPermissions(i.id);
     404          111 :                 settings.first->getEdge().rebuildAllowedLanes();
     405              :                 updateVehicles = true;
     406              :             }
     407              :         }
     408              :     }
     409          944 :     if (updateVehicles) {
     410              :         // only vehicles on the affected lanes had their bestlanes updated so far
     411         1901 :         for (MSEdge* e : myEdges) {
     412              :             // also updates vehicles
     413          957 :             e->rebuildAllowedTargets();
     414              :         }
     415              :     }
     416          944 :     return 0;
     417              : }
     418              : 
     419              : 
     420              : const MSTriggeredRerouter::RerouteInterval*
     421      1176493 : MSTriggeredRerouter::getCurrentReroute(SUMOTime time, SUMOTrafficObject& obj) const {
     422      1684551 :     for (const RerouteInterval& ri : myIntervals) {
     423      1190574 :         if (ri.begin <= time && ri.end > time) {
     424              :             if (
     425              :                 // destProbReroute
     426       696636 :                 ri.edgeProbs.getOverallProb() > 0 ||
     427              :                 // routeProbReroute
     428       161040 :                 ri.routeProbs.getOverallProb() > 0 ||
     429              :                 // parkingZoneReroute
     430       763780 :                 ri.parkProbs.getOverallProb() > 0 ||
     431              :                 // stationReroute
     432              :                 ri.stopAlternatives.size() > 0) {
     433       635458 :                 return &ri;
     434              :             }
     435        64155 :             if (!ri.closed.empty() || !ri.closedLanesAffected.empty() || !ri.overtakeLocations.empty()) {
     436        64155 :                 const std::set<SUMOTrafficObject::NumericalID>& edgeIndices = obj.getUpcomingEdgeIDs();
     437       128310 :                 if (affected(edgeIndices, ri.getClosedEdges())
     438        64155 :                         || affected(edgeIndices, ri.closedLanesAffected)) {
     439        46914 :                     return &ri;
     440              :                 }
     441        17241 :                 for (const OvertakeLocation& oloc : ri.overtakeLocations) {
     442          144 :                     if (affected(edgeIndices, oloc.main)) {
     443              :                         return &ri;
     444              :                     }
     445              :                 }
     446              : 
     447              :             }
     448              :         }
     449              :     }
     450              :     return nullptr;
     451              : }
     452              : 
     453              : 
     454              : const MSTriggeredRerouter::RerouteInterval*
     455         7915 : MSTriggeredRerouter::getCurrentReroute(SUMOTime time) const {
     456         7932 :     for (const RerouteInterval& ri : myIntervals) {
     457         7915 :         if (ri.begin <= time && ri.end > time) {
     458         7898 :             if (ri.edgeProbs.getOverallProb() != 0 || ri.routeProbs.getOverallProb() != 0 || ri.parkProbs.getOverallProb() != 0
     459         7913 :                     || !ri.closed.empty() || !ri.closedLanesAffected.empty() || !ri.overtakeLocations.empty()) {
     460              :                 return &ri;
     461              :             }
     462              :         }
     463              :     }
     464              :     return nullptr;
     465              : }
     466              : 
     467              : 
     468              : bool
     469       658100 : MSTriggeredRerouter::notifyEnter(SUMOTrafficObject& tObject, MSMoveReminder::Notification reason, const MSLane* /* enteredLane */) {
     470       658100 :     if (myAmOptional || myRadius != std::numeric_limits<double>::max()) {
     471              :         return true;
     472              :     }
     473       657960 :     return triggerRouting(tObject, reason);
     474              : }
     475              : 
     476              : 
     477              : bool
     478       518377 : MSTriggeredRerouter::notifyMove(SUMOTrafficObject& veh, double /*oldPos*/,
     479              :                                 double /*newPos*/, double /*newSpeed*/) {
     480       518377 :     return triggerRouting(veh, NOTIFICATION_JUNCTION);
     481              : }
     482              : 
     483              : 
     484              : bool
     485        18806 : MSTriggeredRerouter::notifyLeave(SUMOTrafficObject& /*veh*/, double /*lastPos*/,
     486              :                                  MSMoveReminder::Notification reason, const MSLane* /* enteredLane */) {
     487        18806 :     return reason == NOTIFICATION_LANE_CHANGE;
     488              : }
     489              : 
     490              : 
     491              : bool
     492      1176563 : MSTriggeredRerouter::triggerRouting(SUMOTrafficObject& tObject, MSMoveReminder::Notification reason) {
     493      1176563 :     if (!applies(tObject)) {
     494              :         return false;
     495              :     }
     496      1176493 :     if (myRadius != std::numeric_limits<double>::max() && tObject.getPosition().distanceTo(myPosition) > myRadius) {
     497            0 :         return true;
     498              :     }
     499              :     // check whether the vehicle shall be rerouted
     500      1176493 :     const SUMOTime now = MSNet::getInstance()->getCurrentTimeStep();
     501      1176493 :     const MSTriggeredRerouter::RerouteInterval* const rerouteDef = getCurrentReroute(now, tObject);
     502      1176493 :     if (rerouteDef == nullptr) {
     503              :         return true; // an active interval could appear later
     504              :     }
     505       682516 :     const double prob = myAmInUserMode ? myUserProbability : myProbability;
     506       682516 :     if (prob < 1 && RandHelper::rand(tObject.getRNG()) > prob) {
     507              :         return false; // XXX another interval could appear later but we would have to track whether the current interval was already tried
     508              :     }
     509       682227 :     if (myTimeThreshold > 0 && MAX2(tObject.getWaitingTime(), tObject.getWaitingTime(true)) < myTimeThreshold) {
     510              :         return true; // waiting time may be reached later
     511              :     }
     512       675553 :     if (reason == NOTIFICATION_LANE_CHANGE) {
     513              :         return false;
     514              :     }
     515              :     // if we have a closingLaneReroute, only vehicles with a rerouting device can profit from rerouting (otherwise, edge weights will not reflect local jamming)
     516       657682 :     const bool hasReroutingDevice = tObject.getDevice(typeid(MSDevice_Routing)) != nullptr;
     517       657682 :     if (rerouteDef->closedLanes.size() > 0 && !hasReroutingDevice) {
     518              :         return true; // an active interval could appear later
     519              :     }
     520       620232 :     const MSEdge* lastEdge = tObject.getRerouteDestination();
     521              : #ifdef DEBUG_REROUTER
     522              :     if (DEBUGCOND(tObject)) {
     523              :         std::cout << SIMTIME << " veh=" << tObject.getID() << " check rerouter " << getID() << " lane=" << Named::getIDSecure(tObject.getLane()) << " edge=" << tObject.getEdge()->getID() << " finalEdge=" << lastEdge->getID() /*<< " arrivalPos=" << tObject.getArrivalPos()*/ << "\n";
     524              :     }
     525              : #endif
     526              : 
     527       620232 :     if (rerouteDef->parkProbs.getOverallProb() > 0) {
     528              : #ifdef HAVE_FOX
     529        91656 :         ScopedLocker<> lock(myNotificationMutex, MSGlobals::gNumSimThreads > 1);
     530              : #endif
     531        91656 :         if (!tObject.isVehicle()) {
     532              :             return false;
     533              :         }
     534              :         SUMOVehicle& veh = static_cast<SUMOVehicle&>(tObject);
     535        91591 :         bool newDestination = false;
     536              :         ConstMSEdgeVector newRoute;
     537        91591 :         MSParkingArea* newParkingArea = rerouteParkingArea(rerouteDef, veh, newDestination, newRoute);
     538        91591 :         if (newParkingArea != nullptr) {
     539              :             // adapt plans of any riders
     540        18300 :             for (MSTransportable* p : veh.getPersons()) {
     541           40 :                 p->rerouteParkingArea(veh.getNextParkingArea(), newParkingArea);
     542              :             }
     543              : 
     544        18260 :             if (newDestination) {
     545              :                 // update arrival parameters
     546          601 :                 SUMOVehicleParameter* newParameter = new SUMOVehicleParameter();
     547          601 :                 *newParameter = veh.getParameter();
     548          601 :                 newParameter->arrivalPosProcedure = ArrivalPosDefinition::GIVEN;
     549          601 :                 newParameter->arrivalPos = newParkingArea->getEndLanePosition();
     550          601 :                 veh.replaceParameter(newParameter);
     551              :             }
     552              : 
     553              :             SUMOAbstractRouter<MSEdge, SUMOVehicle>& router = hasReroutingDevice
     554        12195 :                     ? MSRoutingEngine::getRouterTT(veh.getRNGIndex(), veh.getVClass(), rerouteDef->getClosed())
     555        36520 :                     : MSNet::getInstance()->getRouterTT(veh.getRNGIndex(), rerouteDef->getClosed());
     556        18260 :             const double routeCost = router.recomputeCosts(newRoute, &veh, MSNet::getInstance()->getCurrentTimeStep());
     557        18260 :             ConstMSEdgeVector prevEdges(veh.getCurrentRouteEdge(), veh.getRoute().end());
     558        18260 :             const double previousCost = router.recomputeCosts(prevEdges, &veh, MSNet::getInstance()->getCurrentTimeStep());
     559        18260 :             const double savings = previousCost - routeCost;
     560        18260 :             resetClosedEdges(hasReroutingDevice, veh);
     561              :             //if (getID() == "ego") std::cout << SIMTIME << " pCost=" << previousCost << " cost=" << routeCost
     562              :             //        << " prevEdges=" << toString(prevEdges)
     563              :             //        << " newEdges=" << toString(edges)
     564              :             //        << "\n";
     565              : 
     566              :             std::string errorMsg;
     567        18260 :             if (veh.replaceParkingArea(newParkingArea, errorMsg)) {
     568        36520 :                 veh.replaceRouteEdges(newRoute, routeCost, savings, getID() + ":" + toString(SUMO_TAG_PARKING_AREA_REROUTE), false, false, false);
     569              :             } else {
     570            0 :                 WRITE_WARNING("Vehicle '" + veh.getID() + "' at rerouter '" + getID()
     571              :                               + "' could not reroute to new parkingArea '" + newParkingArea->getID()
     572              :                               + "' reason=" + errorMsg + ", time=" + time2string(MSNet::getInstance()->getCurrentTimeStep()) + ".");
     573              :             }
     574        18260 :         }
     575              :         return false;
     576        91591 :     }
     577       528576 :     if (rerouteDef->overtakeLocations.size() > 0) {
     578          144 :         if (!tObject.isVehicle()) {
     579              :             return false;
     580              :         }
     581              :         SUMOVehicle& veh = static_cast<SUMOVehicle&>(tObject);
     582          144 :         const ConstMSEdgeVector& oldEdges = veh.getRoute().getEdges();
     583              :         double bestSavings = -std::numeric_limits<double>::max();
     584              :         double netSaving;
     585              :         int bestIndex = -1;
     586              :         MSRouteIterator bestMainStart = oldEdges.end();
     587              :         std::pair<const SUMOVehicle*, MSRailSignal*> best_overtaker_signal(nullptr, nullptr);
     588              :         int index = -1;
     589              :         // sort locations by descending distance to vehicle
     590              :         std::vector<std::pair<int, int> > sortedLocs;
     591          330 :         for (const OvertakeLocation& oloc : rerouteDef->overtakeLocations) {
     592          186 :             index++;
     593          186 :             if (veh.getLength() > oloc.sidingLength) {
     594            3 :                 continue;
     595              :             }
     596          183 :             auto mainStart = std::find(veh.getCurrentRouteEdge(), oldEdges.end(), oloc.main.front());
     597          183 :             if (mainStart == oldEdges.end()
     598              :                     // exit main within
     599          366 :                     || ConstMSEdgeVector(mainStart, mainStart + oloc.main.size()) != oloc.cMain
     600              :                     // stop in main
     601          366 :                     || (veh.hasStops() && veh.getNextStop().edge < (mainStart + oloc.main.size()))) {
     602              :                 //std::cout << SIMTIME << " veh=" << veh.getID() << " wrong route or stop\n";
     603            0 :                 continue;
     604              :             }
     605              :             // negated iterator distance for descending order
     606          183 :             sortedLocs.push_back(std::make_pair(-(int)(mainStart - veh.getCurrentRouteEdge()), index));
     607              :         }
     608          144 :         std::sort(sortedLocs.begin(), sortedLocs.end());
     609          327 :         for (const auto& item : sortedLocs) {
     610          183 :             index = item.second;
     611          183 :             const OvertakeLocation& oloc = rerouteDef->overtakeLocations[index];
     612          183 :             auto mainStart = veh.getCurrentRouteEdge() - item.first;  // subtracting negative difference
     613          183 :             std::pair<const SUMOVehicle*, MSRailSignal*> overtaker_signal = overtakingTrain(veh, mainStart, oloc, netSaving);
     614          183 :             if (overtaker_signal.first != nullptr && netSaving > bestSavings) {
     615              :                 bestSavings = netSaving;
     616              :                 bestIndex = index;
     617              :                 best_overtaker_signal = overtaker_signal;
     618              :                 bestMainStart = mainStart;
     619              : #ifdef DEBUG_OVERTAKING
     620              :                 std::cout << "    newBest index=" << bestIndex << " saving=" << bestSavings << "\n";
     621              : #endif
     622              :             }
     623              :         }
     624          144 :         if (bestIndex >= 0) {
     625           41 :             const OvertakeLocation& oloc = rerouteDef->overtakeLocations[bestIndex];
     626           41 :             if (oloc.defer) {
     627            5 :                 return false;
     628              :             }
     629              :             SUMOAbstractRouter<MSEdge, SUMOVehicle>& router = hasReroutingDevice
     630            0 :                     ? MSRoutingEngine::getRouterTT(veh.getRNGIndex(), veh.getVClass(), rerouteDef->getClosed())
     631           72 :                     : MSNet::getInstance()->getRouterTT(veh.getRNGIndex(), rerouteDef->getClosed());
     632           36 :             ConstMSEdgeVector newEdges(veh.getCurrentRouteEdge(), bestMainStart);
     633           36 :             newEdges.insert(newEdges.end(), oloc.siding.begin(), oloc.siding.end());
     634           36 :             newEdges.insert(newEdges.end(), bestMainStart + oloc.main.size(), oldEdges.end());
     635           36 :             const double routeCost = router.recomputeCosts(newEdges, &veh, MSNet::getInstance()->getCurrentTimeStep());
     636           36 :             const double savings = (router.recomputeCosts(oloc.cMain, &veh, MSNet::getInstance()->getCurrentTimeStep())
     637           36 :                                     - router.recomputeCosts(oloc.cSiding, &veh, MSNet::getInstance()->getCurrentTimeStep()));
     638           72 :             const std::string info = getID() + ":" + toString(SUMO_TAG_OVERTAKING_REROUTE) + ":" + best_overtaker_signal.first->getID();
     639           36 :             veh.replaceRouteEdges(newEdges, routeCost, savings, info, false, false, false);
     640           36 :             oloc.sidingExit->addConstraint(veh.getID(), new MSRailSignalConstraint_Predecessor(
     641           36 :                                                MSRailSignalConstraint::PREDECESSOR, best_overtaker_signal.second, best_overtaker_signal.first->getID(), 100, true));
     642           36 :             resetClosedEdges(hasReroutingDevice, veh);
     643           36 :         }
     644          139 :         return false;
     645          144 :     }
     646       528432 :     if (rerouteDef->stopAlternatives.size() > 0) {
     647              :         // somewhat similar to parkProbs but taking into account public transport schedule
     648           12 :         if (!tObject.isVehicle()) {
     649              :             return false;
     650              :         }
     651           12 :         checkStopSwitch(static_cast<MSBaseVehicle&>(tObject), rerouteDef);
     652              :     }
     653              :     // get rerouting params
     654       528432 :     ConstMSRoutePtr newRoute = rerouteDef->routeProbs.getOverallProb() > 0 ? rerouteDef->routeProbs.get() : nullptr;
     655              :     // we will use the route if given rather than calling our own dijsktra...
     656       528432 :     if (newRoute != nullptr) {
     657              : #ifdef DEBUG_REROUTER
     658              :         if (DEBUGCOND(tObject)) {
     659              :             std::cout << "    replacedRoute from routeDist " << newRoute->getID() << "\n";
     660              :         }
     661              : #endif
     662       522885 :         tObject.replaceRoute(newRoute, getID());
     663       522882 :         return false; // XXX another interval could appear later but we would have to track whether the currenty interval was already used
     664              :     }
     665              :     const MSEdge* newEdge = lastEdge;
     666              :     // ok, try using a new destination
     667              :     double newArrivalPos = -1;
     668         5550 :     const MSEdgeVector closedEdges = rerouteDef->getClosedEdges();
     669         5550 :     const bool destUnreachable = std::find(closedEdges.begin(), closedEdges.end(), lastEdge) != closedEdges.end();
     670              :     bool keepDestination = false;
     671              :     // if we have a closingReroute, only assign new destinations to vehicles which cannot reach their original destination
     672              :     // if we have a closingLaneReroute, no new destinations should be assigned
     673         5550 :     if (closedEdges.empty() || destUnreachable || rerouteDef->isVia) {
     674         3823 :         newEdge = rerouteDef->edgeProbs.getOverallProb() > 0 ? rerouteDef->edgeProbs.get() : lastEdge;
     675              :         assert(newEdge != nullptr);
     676         3823 :         if (newEdge == &mySpecialDest_terminateRoute) {
     677              :             keepDestination = true;
     678           55 :             newEdge = tObject.getEdge();
     679           55 :             newArrivalPos = tObject.getPositionOnLane(); // instant arrival
     680         3768 :         } else if (newEdge == &mySpecialDest_keepDestination || newEdge == lastEdge) {
     681         1532 :             if (destUnreachable && rerouteDef->permissionsAllowAll) {
     682              :                 // if permissions aren't set vehicles will simply drive through
     683              :                 // the closing unless terminated. If the permissions are specified, assume that the user wants
     684              :                 // vehicles to stand and wait until the closing ends
     685           63 :                 WRITE_WARNINGF(TL("Cannot keep destination edge '%' for vehicle '%' due to closed edges. Terminating route."), lastEdge->getID(), tObject.getID());
     686           21 :                 newEdge = tObject.getEdge();
     687              :             } else {
     688              :                 newEdge = lastEdge;
     689              :             }
     690              :         }
     691              :     }
     692              :     ConstMSEdgeVector edges;
     693              :     std::vector<MSTransportableRouter::TripItem> items;
     694              :     // we have a new destination, let's replace the route (if it is affected)
     695         5550 :     MSEdgeVector closed = rerouteDef->getClosedEdges();
     696         5550 :     Prohibitions prohibited = rerouteDef->getClosed();
     697         7277 :     if (rerouteDef->closed.empty() || destUnreachable || rerouteDef->isVia || affected(tObject.getUpcomingEdgeIDs(), closed)) {
     698         5473 :         if (tObject.isVehicle()) {
     699              :             SUMOVehicle& veh = static_cast<SUMOVehicle&>(tObject);
     700         4003 :             const bool canChangeDest = rerouteDef->edgeProbs.getOverallProb() > 0;
     701              :             MSVehicleRouter& router = hasReroutingDevice
     702         4003 :                                       ? MSRoutingEngine::getRouterTT(veh.getRNGIndex(), veh.getVClass(), prohibited)
     703         1693 :                                       : MSNet::getInstance()->getRouterTT(veh.getRNGIndex(), prohibited);
     704         4003 :             bool ok = veh.reroute(now, getID(), router, false, false, canChangeDest, newEdge);
     705         4000 :             if (!ok && !keepDestination && canChangeDest) {
     706              :                 // destination unreachable due to closed intermediate edges. pick among alternative targets
     707           82 :                 RandomDistributor<MSEdge*> edgeProbs2 = rerouteDef->edgeProbs;
     708           82 :                 edgeProbs2.remove(const_cast<MSEdge*>(newEdge));
     709          152 :                 while (!ok && edgeProbs2.getVals().size() > 0) {
     710          110 :                     newEdge = edgeProbs2.get();
     711          110 :                     edgeProbs2.remove(const_cast<MSEdge*>(newEdge));
     712          110 :                     if (newEdge == &mySpecialDest_terminateRoute) {
     713           42 :                         newEdge = veh.getEdge();
     714           42 :                         newArrivalPos = veh.getPositionOnLane(); // instant arrival
     715              :                     }
     716          110 :                     if (newEdge == &mySpecialDest_keepDestination && !rerouteDef->permissionsAllowAll) {
     717              :                         newEdge = lastEdge;
     718              :                         break;
     719              :                     }
     720           70 :                     ok = veh.reroute(now, getID(), router, false, false, true, newEdge);
     721              :                 }
     722              : 
     723              :             }
     724         4000 :             if (!rerouteDef->isVia) {
     725              : #ifdef DEBUG_REROUTER
     726              :                 if (DEBUGCOND(tObject)) std::cout << "   rerouting:  newDest=" << newEdge->getID()
     727              :                                                       << " newEdges=" << toString(edges)
     728              :                                                       << " newArrivalPos=" << newArrivalPos << " numClosed=" << rerouteDef->closed.size()
     729              :                                                       << " destUnreachable=" << destUnreachable << " containsClosed=" << veh.getRoute().containsAnyOf(rerouteDef->getClosedEdges()) << "\n";
     730              : #endif
     731         4000 :                 if (ok && newArrivalPos != -1) {
     732              :                     // must be called here because replaceRouteEdges may also set the arrivalPos
     733           86 :                     veh.setArrivalPos(newArrivalPos);
     734              :                 }
     735              : 
     736              :             }
     737              :         } else {
     738              :             // person rerouting here
     739              :             MSTransportableRouter& router = hasReroutingDevice
     740         1470 :                                             ? MSRoutingEngine::getIntermodalRouterTT(tObject.getRNGIndex(), prohibited)
     741         1470 :                                             : MSNet::getInstance()->getIntermodalRouter(tObject.getRNGIndex(), 0, prohibited);
     742         4410 :             const bool success = router.compute(tObject.getEdge(), newEdge, tObject.getPositionOnLane(), "",
     743         1470 :                                                 rerouteDef->isVia ? newEdge->getLength() / 2. : tObject.getParameter().arrivalPos, "",
     744         1470 :                                                 tObject.getMaxSpeed(), nullptr, tObject.getVTypeParameter(), 0, now, items);
     745         1470 :             if (!rerouteDef->isVia) {
     746          700 :                 if (success) {
     747         1400 :                     for (const MSTransportableRouter::TripItem& it : items) {
     748          700 :                         if (!it.edges.empty() && !edges.empty() && edges.back() == it.edges.front()) {
     749              :                             edges.pop_back();
     750              :                         }
     751          700 :                         edges.insert(edges.end(), std::make_move_iterator(it.edges.begin()), std::make_move_iterator(it.edges.end()));
     752          700 :                         if (!edges.empty()) {
     753          700 :                             static_cast<MSPerson&>(tObject).replaceWalk(edges, tObject.getPositionOnLane(), 0, 1);
     754              :                         }
     755              :                     }
     756              :                 } else {
     757              :                     // maybe the pedestrian model still finds a way (JuPedSim)
     758            0 :                     static_cast<MSPerson&>(tObject).replaceWalk({tObject.getEdge(), newEdge}, tObject.getPositionOnLane(), 0, 1);
     759              :                 }
     760              :             }
     761              :         }
     762         5470 :         if (!prohibited.empty()) {
     763         1729 :             resetClosedEdges(hasReroutingDevice, tObject);
     764              :         }
     765              :     }
     766              :     // it was only a via so calculate the remaining part
     767         5547 :     if (rerouteDef->isVia) {
     768          770 :         if (tObject.isVehicle()) {
     769              :             SUMOVehicle& veh = static_cast<SUMOVehicle&>(tObject);
     770            0 :             if (!edges.empty()) {
     771              :                 edges.pop_back();
     772              :             }
     773              :             MSVehicleRouter& router = hasReroutingDevice
     774            0 :                                       ? MSRoutingEngine::getRouterTT(veh.getRNGIndex(), veh.getVClass(), prohibited)
     775            0 :                                       : MSNet::getInstance()->getRouterTT(veh.getRNGIndex(), prohibited);
     776            0 :             router.compute(newEdge, lastEdge, &veh, now, edges);
     777            0 :             const double routeCost = router.recomputeCosts(edges, &veh, now);
     778              :             hasReroutingDevice
     779            0 :             ? MSRoutingEngine::getRouterTT(veh.getRNGIndex(), veh.getVClass())
     780            0 :             : MSNet::getInstance()->getRouterTT(veh.getRNGIndex()); // reset closed edges
     781            0 :             const bool useNewRoute = veh.replaceRouteEdges(edges, routeCost, 0, getID());
     782              : #ifdef DEBUG_REROUTER
     783              :             if (DEBUGCOND(tObject)) std::cout << "   rerouting:  newDest=" << newEdge->getID()
     784              :                                                   << " newEdges=" << toString(edges)
     785              :                                                   << " useNewRoute=" << useNewRoute << " newArrivalPos=" << newArrivalPos << " numClosed=" << rerouteDef->closed.size()
     786              :                                                   << " destUnreachable=" << destUnreachable << " containsClosed=" << veh.getRoute().containsAnyOf(rerouteDef->getClosedEdges()) << "\n";
     787              : #endif
     788            0 :             if (useNewRoute && newArrivalPos != -1) {
     789              :                 // must be called here because replaceRouteEdges may also set the arrivalPos
     790            0 :                 veh.setArrivalPos(newArrivalPos);
     791              :             }
     792              :         } else {
     793              :             // person rerouting here
     794          770 :             bool success = !items.empty();
     795          770 :             if (success) {
     796              :                 MSTransportableRouter& router = hasReroutingDevice
     797          770 :                                                 ? MSRoutingEngine::getIntermodalRouterTT(tObject.getRNGIndex(), prohibited)
     798          770 :                                                 : MSNet::getInstance()->getIntermodalRouter(tObject.getRNGIndex(), 0, prohibited);
     799         2310 :                 success = router.compute(newEdge, lastEdge, newEdge->getLength() / 2., "",
     800          770 :                                          tObject.getParameter().arrivalPos, "",
     801          770 :                                          tObject.getMaxSpeed(), nullptr, tObject.getVTypeParameter(), 0, now, items);
     802              :             }
     803          770 :             if (success) {
     804         2310 :                 for (const MSTransportableRouter::TripItem& it : items) {
     805         1540 :                     if (!it.edges.empty() && !edges.empty() && edges.back() == it.edges.front()) {
     806              :                         edges.pop_back();
     807              :                     }
     808         1540 :                     edges.insert(edges.end(), std::make_move_iterator(it.edges.begin()), std::make_move_iterator(it.edges.end()));
     809              :                 }
     810          770 :                 if (!edges.empty()) {
     811          770 :                     static_cast<MSPerson&>(tObject).replaceWalk(edges, tObject.getPositionOnLane(), 0, 1);
     812              :                 }
     813              :             } else {
     814              :                 // maybe the pedestrian model still finds a way (JuPedSim)
     815            3 :                 static_cast<MSPerson&>(tObject).replaceWalk({tObject.getEdge(), newEdge, lastEdge}, tObject.getPositionOnLane(), 0, 1);
     816              :             }
     817              :         }
     818          770 :         if (!prohibited.empty()) {
     819            0 :             resetClosedEdges(hasReroutingDevice, tObject);
     820              :         }
     821              :     }
     822              :     return false; // XXX another interval could appear later but we would have to track whether the currenty interval was already used
     823         5559 : }
     824              : 
     825              : 
     826              : void
     827            1 : MSTriggeredRerouter::setUserMode(bool val) {
     828            1 :     myAmInUserMode = val;
     829            1 : }
     830              : 
     831              : 
     832              : void
     833            1 : MSTriggeredRerouter::setUserUsageProbability(double prob) {
     834            1 :     myUserProbability = prob;
     835            1 : }
     836              : 
     837              : 
     838              : bool
     839            0 : MSTriggeredRerouter::inUserMode() const {
     840            0 :     return myAmInUserMode;
     841              : }
     842              : 
     843              : 
     844              : double
     845         5644 : MSTriggeredRerouter::getProbability() const {
     846         5644 :     return myAmInUserMode ? myUserProbability : myProbability;
     847              : }
     848              : 
     849              : 
     850              : double
     851            0 : MSTriggeredRerouter::getUserProbability() const {
     852            0 :     return myUserProbability;
     853              : }
     854              : 
     855              : 
     856              : double
     857       101736 : MSTriggeredRerouter::getStoppingPlaceOccupancy(MSStoppingPlace* sp) {
     858       101736 :     return (double)(sp->getElement() == SUMO_TAG_PARKING_AREA
     859       101678 :                     ? dynamic_cast<MSParkingArea*>(sp)->getOccupancy()
     860           58 :                     : sp->getStoppedVehicles().size());
     861              : }
     862              : 
     863              : 
     864              : double
     865        81871 : MSTriggeredRerouter::getLastStepStoppingPlaceOccupancy(MSStoppingPlace* sp) {
     866        81871 :     return (double)(sp->getElement() == SUMO_TAG_PARKING_AREA
     867        81835 :                     ? dynamic_cast<MSParkingArea*>(sp)->getLastStepOccupancy()
     868           36 :                     : sp->getStoppedVehicles().size());
     869              : }
     870              : 
     871              : 
     872              : double
     873       259094 : MSTriggeredRerouter::getStoppingPlaceCapacity(MSStoppingPlace* sp) {
     874              :     if (myBlockedStoppingPlaces.count(sp) == 0) {
     875              :         return (double)(sp->getElement() == SUMO_TAG_PARKING_AREA
     876       259078 :                         ? dynamic_cast<MSParkingArea*>(sp)->getCapacity()
     877              :                         // assume only one vehicle at a time (for stationReroute)
     878              :                         : 1.);
     879              :     } else {
     880              :         return 0.;
     881              :     }
     882              : }
     883              : 
     884              : 
     885              : void
     886        54344 : MSTriggeredRerouter::rememberBlockedStoppingPlace(SUMOVehicle& veh, const MSStoppingPlace* parkingArea, bool blocked) {
     887        54344 :     veh.rememberBlockedParkingArea(parkingArea, blocked);
     888        54344 : }
     889              : 
     890              : 
     891              : void
     892        86339 : MSTriggeredRerouter::rememberStoppingPlaceScore(SUMOVehicle& veh, MSStoppingPlace* parkingArea, const std::string& score) {
     893        86339 :     veh.rememberParkingAreaScore(parkingArea, score);
     894        86339 : }
     895              : 
     896              : 
     897              : void
     898        19077 : MSTriggeredRerouter::resetStoppingPlaceScores(SUMOVehicle& veh) {
     899        19077 :     veh.resetParkingAreaScores();
     900        19077 : }
     901              : 
     902              : 
     903              : SUMOTime
     904        51792 : MSTriggeredRerouter::sawBlockedStoppingPlace(SUMOVehicle& veh, MSStoppingPlace* parkingArea, bool local) {
     905        51792 :     return veh.sawBlockedParkingArea(parkingArea, local);
     906              : }
     907              : 
     908              : 
     909              : int
     910        58330 : MSTriggeredRerouter::getNumberStoppingPlaceReroutes(SUMOVehicle& veh) {
     911        58330 :     return veh.getNumberParkingReroutes();
     912              : }
     913              : 
     914              : 
     915              : void
     916        19077 : MSTriggeredRerouter::setNumberStoppingPlaceReroutes(SUMOVehicle& veh, int value) {
     917        19077 :     veh.setNumberParkingReroutes(value);
     918        19077 : }
     919              : 
     920              : 
     921              : MSParkingArea*
     922        91591 : MSTriggeredRerouter::rerouteParkingArea(const MSTriggeredRerouter::RerouteInterval* rerouteDef,
     923              :                                         SUMOVehicle& veh, bool& newDestination, ConstMSEdgeVector& newRoute) {
     924        91591 :     MSStoppingPlace* destStoppingPlace = veh.getNextParkingArea();
     925        91591 :     if (destStoppingPlace == nullptr) {
     926              :         // not driving towards the right type of stop
     927              :         return nullptr;
     928              :     }
     929              :     std::vector<StoppingPlaceVisible> parks;
     930       255067 :     for (auto cand : rerouteDef->parkProbs.getVals()) {
     931       173140 :         if (cand.first->accepts(&veh)) {
     932       172460 :             parks.push_back(cand);
     933              :         }
     934              :     }
     935              :     StoppingPlaceParamMap_t addInput = {};
     936       163854 :     return dynamic_cast<MSParkingArea*>(rerouteStoppingPlace(destStoppingPlace, parks, rerouteDef->parkProbs.getProbs(), veh, newDestination, newRoute, addInput, rerouteDef->getClosed()));
     937        81927 : }
     938              : 
     939              : 
     940              : std::pair<const SUMOVehicle*, MSRailSignal*>
     941          183 : MSTriggeredRerouter::overtakingTrain(const SUMOVehicle& veh,
     942              :                                      ConstMSEdgeVector::const_iterator mainStart,
     943              :                                      const OvertakeLocation& oloc,
     944              :                                      double& netSaving) {
     945          183 :     const ConstMSEdgeVector& route = veh.getRoute().getEdges();
     946              :     const MSEdgeVector& main = oloc.main;
     947          183 :     const double vMax = veh.getMaxSpeed();
     948          366 :     const double prio = veh.getFloatParam(toString(SUMO_TAG_OVERTAKING_REROUTE) + ".prio", false, DEFAULT_PRIO_OVERTAKEN, false);
     949          183 :     MSVehicleControl& c = MSNet::getInstance()->getVehicleControl();
     950          437 :     for (MSVehicleControl::constVehIt it_veh = c.loadedVehBegin(); it_veh != c.loadedVehEnd(); ++it_veh) {
     951          307 :         const MSBaseVehicle* veh2 = dynamic_cast<const MSBaseVehicle*>((*it_veh).second);
     952          307 :         if (veh2->isOnRoad() && veh2->getMaxSpeed() > vMax) {
     953           93 :             const double arrivalDelay = veh2->getStopArrivalDelay();
     954          182 :             const double delay = MAX2(veh2->getStopDelay(), arrivalDelay == INVALID_DOUBLE ? 0 : arrivalDelay);
     955          279 :             if (delay > veh2->getFloatParam(toString(SUMO_TAG_OVERTAKING_REROUTE) + ".maxDelay", false, DEFAULT_MAXDELAY, false)) {
     956              :                 continue;
     957              :             }
     958           89 :             const ConstMSEdgeVector& route2 = veh2->getRoute().getEdges();
     959              :             auto itOnMain2 = route2.end();
     960              :             int mainIndex = 0;
     961          110 :             for (const MSEdge* m : main) {
     962          105 :                 itOnMain2 = std::find(veh2->getCurrentRouteEdge(), route2.end(), m);
     963          105 :                 if (itOnMain2 != route2.end()) {
     964              :                     break;
     965              :                 }
     966           21 :                 mainIndex++;
     967              :             }
     968           89 :             if (itOnMain2 != route2.end() && itOnMain2 > veh2->getCurrentRouteEdge()) {
     969              :                 auto itOnMain = mainStart + mainIndex;
     970              :                 double timeToMain = 0;
     971          371 :                 for (auto it = veh.getCurrentRouteEdge(); it != itOnMain; it++) {
     972          290 :                     timeToMain += (*it)->getMinimumTravelTime(&veh);
     973              :                 }
     974              :                 // veh2 may be anywhere on the current edge so we have to discount
     975           81 :                 double timeToMain2 = -veh2->getEdge()->getMinimumTravelTime(veh2) * veh2->getPositionOnLane() / veh2->getEdge()->getLength();
     976              :                 double timeToLastSignal2 = timeToMain2;
     977          562 :                 for (auto it = veh2->getCurrentRouteEdge(); it != itOnMain2; it++) {
     978          481 :                     timeToMain2 += (*it)->getMinimumTravelTime(veh2);
     979          481 :                     auto signal = getRailSignal(*it);
     980          481 :                     if (signal) {
     981              :                         timeToLastSignal2 = timeToMain2;
     982              : #ifdef DEBUG_OVERTAKING
     983              :                         std::cout << "   lastBeforeMain2 " << signal->getID() << "\n";
     984              : #endif
     985              :                     }
     986              :                 }
     987              :                 double exitMainTime = timeToMain;
     988              :                 double exitMainBlockTime2 = timeToMain2;
     989              :                 double commonTime = 0;
     990              :                 double commonTime2 = 0;
     991              :                 int nCommon = 0;
     992              :                 auto exitMain2 = itOnMain2;
     993              :                 const MSRailSignal* firstAfterMain = nullptr;
     994              :                 const MSEdge* common = nullptr;
     995           81 :                 double vMinCommon = (*itOnMain)->getVehicleMaxSpeed(&veh);
     996           81 :                 double vMinCommon2 = (*itOnMain2)->getVehicleMaxSpeed(veh2);
     997              :                 while (itOnMain2 != route2.end()
     998          794 :                         && itOnMain != route.end()
     999         1657 :                         && *itOnMain == *itOnMain2) {
    1000              :                     common = *itOnMain;
    1001          785 :                     commonTime += common->getMinimumTravelTime(&veh);
    1002          785 :                     commonTime2 += common->getMinimumTravelTime(veh2);
    1003          785 :                     vMinCommon = MIN2(vMinCommon, common->getVehicleMaxSpeed(&veh));
    1004          785 :                     vMinCommon2 = MIN2(vMinCommon2, common->getVehicleMaxSpeed(veh2));
    1005          785 :                     const bool onMain = nCommon < (int)main.size() - mainIndex;
    1006          785 :                     if (onMain) {
    1007          240 :                         exitMainTime = timeToMain + commonTime;
    1008              :                     }
    1009          785 :                     if (firstAfterMain == nullptr) {
    1010          480 :                         exitMainBlockTime2 = timeToMain2 + commonTime2;
    1011              :                     }
    1012          785 :                     auto signal = getRailSignal(common);
    1013          785 :                     if (signal) {
    1014          318 :                         if (!onMain && firstAfterMain == nullptr) {
    1015              :                             firstAfterMain = signal;
    1016              : #ifdef DEBUG_OVERTAKING
    1017              :                             std::cout << "   firstAfterMain " << signal->getID() << "\n";
    1018              : #endif
    1019              :                         }
    1020              :                     }
    1021          785 :                     nCommon++;
    1022              :                     itOnMain++;
    1023              :                     itOnMain2++;
    1024              :                 }
    1025           81 :                 const double vMaxLast = common->getVehicleMaxSpeed(&veh);
    1026           81 :                 const double vMaxLast2 = common->getVehicleMaxSpeed(veh2);
    1027           81 :                 commonTime += veh.getLength() / vMaxLast;
    1028           81 :                 exitMainBlockTime2 += veh2->getLength() / vMaxLast2;
    1029           81 :                 exitMain2 += MIN2(nCommon, (int)main.size() - mainIndex);
    1030           81 :                 double timeLoss2 = MAX2(0.0, timeToMain + veh.getLength() / oloc.siding.front()->getVehicleMaxSpeed(&veh) - timeToLastSignal2);
    1031           81 :                 const double saving = timeToMain + commonTime - (timeToMain2 + commonTime2) - timeLoss2;
    1032           81 :                 const double loss = exitMainBlockTime2 - exitMainTime;
    1033          162 :                 const double prio2 = veh2->getFloatParam(toString(SUMO_TAG_OVERTAKING_REROUTE) + ".prio", false, DEFAULT_PRIO_OVERTAKER, false);
    1034              :                 // losses from acceleration after stopping at a signal
    1035           81 :                 const double accelTimeLoss = loss > 0 ? 0.5 * vMinCommon / veh.getVehicleType().getCarFollowModel().getMaxAccel() : 0;
    1036           81 :                 const double accelTimeLoss2 = timeLoss2 > 0 ? 0.5 * vMinCommon2 / veh2->getVehicleType().getCarFollowModel().getMaxAccel() : 0;
    1037           81 :                 netSaving = prio2 * (saving - accelTimeLoss2) - prio * (loss + accelTimeLoss);
    1038              : #ifdef DEBUG_OVERTAKING
    1039              :                 std::cout << SIMTIME << " veh=" << veh.getID() << " veh2=" << veh2->getID()
    1040              :                           << " sidingStart=" << oloc.siding.front()->getID()
    1041              :                           << " ttm=" << timeToMain << " ttm2=" << timeToMain2
    1042              :                           << " nCommon=" << nCommon << " cT=" << commonTime << " cT2=" << commonTime2
    1043              :                           << " em=" << exitMainTime << " emb2=" << exitMainBlockTime2
    1044              :                           << " ttls2=" << timeToLastSignal2
    1045              :                           << " saving=" << saving << " loss=" << loss
    1046              :                           << " atl=" << accelTimeLoss << " atl2=" << accelTimeLoss2 << " tl2=" << timeLoss2
    1047              :                           << " prio=" << prio << " prio2=" << prio2 << " netSaving=" << netSaving << "\n";
    1048              : #endif
    1049           81 :                 if (netSaving > oloc.minSaving) {
    1050           53 :                     MSRailSignal* s = findSignal(veh2->getCurrentRouteEdge(), exitMain2);
    1051           53 :                     if (s != nullptr) {
    1052           53 :                         return std::make_pair(veh2, s);
    1053              :                     }
    1054              :                 }
    1055              :             }
    1056              :         }
    1057              :     }
    1058          130 :     return std::make_pair(nullptr, nullptr);
    1059              : }
    1060              : 
    1061              : 
    1062              : void
    1063           12 : MSTriggeredRerouter::checkStopSwitch(MSBaseVehicle& ego, const MSTriggeredRerouter::RerouteInterval* def) {
    1064              :     myBlockedStoppingPlaces.clear();
    1065              : #ifdef DEBUG_REROUTER
    1066              :     std::cout << SIMTIME << " " << getID() << " ego=" << ego.getID() << "\n";
    1067              : #endif
    1068           12 :     if (!ego.hasStops()) {
    1069            0 :         return;
    1070              :     }
    1071           12 :     const MSStop& stop = ego.getNextStop();
    1072           12 :     if (stop.reached || stop.joinTriggered || (stop.pars.arrival < 0 && stop.pars.until < 0)) {
    1073              :         return;
    1074              :     }
    1075           12 :     MSStoppingPlace* cur = nullptr;
    1076           24 :     for (MSStoppingPlace* sp : stop.getPlaces()) {
    1077           12 :         for (auto item : def->stopAlternatives) {
    1078           12 :             if (sp == item.first) {
    1079           12 :                 cur = sp;
    1080           12 :                 break;
    1081              :             }
    1082              :         }
    1083           12 :     }
    1084           12 :     if (cur == nullptr) {
    1085              :         return;
    1086              :     }
    1087           12 :     std::vector<const SUMOVehicle*> stopped = cur->getStoppedVehicles();
    1088              : #ifdef DEBUG_REROUTER
    1089              :     std::cout << SIMTIME << " " << getID() << " ego=" << ego.getID() << " stopped=" << toString(stopped) << "\n";
    1090              : #endif
    1091              :     SUMOTime stoppedDuration = -1;
    1092           12 :     if (stopped.empty()) {
    1093              :         /// look upstream for vehicles that stop on this lane before ego arrives
    1094            8 :         const MSLane& stopLane = cur->getLane();
    1095            8 :         MSVehicleControl& c = MSNet::getInstance()->getVehicleControl();
    1096           25 :         for (MSVehicleControl::constVehIt it_veh = c.loadedVehBegin(); it_veh != c.loadedVehEnd(); ++it_veh) {
    1097           17 :             const MSBaseVehicle* veh = dynamic_cast<const MSBaseVehicle*>((*it_veh).second);
    1098           17 :             if (veh->isOnRoad() && veh->hasStops()) {
    1099           17 :                 const MSStop& vehStop = veh->getNextStop();
    1100           17 :                 if (vehStop.pars.lane == stopLane.getID()) {
    1101              :                     myBlockedStoppingPlaces.insert(cur);
    1102           10 :                     if (veh->isStopped()) {
    1103              :                         // stopped somewhere else on the same lane
    1104            2 :                         stoppedDuration = MAX3((SUMOTime)0, stoppedDuration, veh->getStopDuration());
    1105              :                     } else {
    1106            8 :                         std::pair<double, double> timeDist = veh->estimateTimeToNextStop();
    1107            8 :                         SUMOTime timeTo = TIME2STEPS(timeDist.first);
    1108            8 :                         stoppedDuration = MAX3((SUMOTime)0, stoppedDuration, timeTo + vehStop.getMinDuration(SIMSTEP + timeTo));
    1109              :                     }
    1110              :                 }
    1111              :             }
    1112              :         }
    1113              :     } else {
    1114              :         stoppedDuration = 0;
    1115            8 :         for (const SUMOVehicle* veh : cur->getStoppedVehicles()) {
    1116            4 :             stoppedDuration = MAX2(stoppedDuration, veh->getStopDuration());
    1117            4 :         }
    1118              :     }
    1119           12 :     if (stoppedDuration < 0) {
    1120              :         return;
    1121              :     }
    1122              :     /// @todo: consider time for conflict veh to leave the block
    1123           12 :     const SUMOTime stopFree = SIMSTEP + stoppedDuration;
    1124           12 :     const SUMOTime scheduledArrival = stop.pars.arrival >= 0 ? stop.pars.arrival : stop.pars.until - stop.pars.duration;
    1125              : #ifdef DEBUG_REROUTER
    1126              :     std::cout << SIMTIME << " " << getID() << " ego=" << ego.getID() << " stopFree=" << stopFree << " scheduledArrival=" << time2string(scheduledArrival) << "\n";
    1127              : #endif
    1128           12 :     if (stopFree < scheduledArrival) {
    1129              :         // no conflict according to the schedule
    1130              :         return;
    1131              :     }
    1132           12 :     const SUMOTime estimatedArrival = SIMSTEP + (stop.pars.arrival >= 0
    1133           12 :                                       ? TIME2STEPS(ego.getStopArrivalDelay())
    1134           16 :                                       : TIME2STEPS(ego.getStopDelay()) - stop.pars.duration);
    1135              : #ifdef DEBUG_REROUTER
    1136              :     std::cout << SIMTIME << " " << getID() << " ego=" << ego.getID() << " stopFree=" << stopFree << " estimatedArrival=" << time2string(estimatedArrival) << "\n";
    1137              : #endif
    1138           12 :     if (stopFree < estimatedArrival) {
    1139              :         // no conflict when considering current delay
    1140              :         return;
    1141              :     }
    1142           12 :     const std::vector<double> probs(def->stopAlternatives.size(), 1.);
    1143              :     StoppingPlaceParamMap_t scores = {};
    1144              :     bool newDestination;
    1145              :     ConstMSEdgeVector newRoute;
    1146              :     // @todo: consider future conflicts caused by rerouting
    1147              :     // @todo: reject alternatives with large detour
    1148           12 :     const MSStoppingPlace* alternative = rerouteStoppingPlace(nullptr, def->stopAlternatives, probs, ego, newDestination, newRoute, scores);
    1149              : #ifdef DEBUG_REROUTER
    1150              :     std::cout << SIMTIME << " " << getID() << " ego=" << ego.getID() << " alternative=" << Named::getIDSecure(alternative) << "\n";
    1151              : #endif
    1152           12 :     if (alternative != nullptr) {
    1153              :         // @todo adapt plans of any riders
    1154              :         //for (MSTransportable* p : ego.getPersons()) {
    1155              :         //    p->rerouteParkingArea(ego.getNextParkingArea(), newParkingArea);
    1156              :         //}
    1157              : 
    1158           12 :         if (newDestination) {
    1159              :             // update arrival parameters
    1160            0 :             SUMOVehicleParameter* newParameter = new SUMOVehicleParameter();
    1161            0 :             *newParameter = ego.getParameter();
    1162            0 :             newParameter->arrivalPosProcedure = ArrivalPosDefinition::GIVEN;
    1163            0 :             newParameter->arrivalPos = alternative->getEndLanePosition();
    1164            0 :             ego.replaceParameter(newParameter);
    1165              :         }
    1166              : 
    1167           12 :         SUMOVehicleParameter::Stop newStop = stop.pars;
    1168           12 :         newStop.lane = alternative->getLane().getID();
    1169           12 :         newStop.startPos = alternative->getBeginLanePosition();
    1170           12 :         newStop.endPos = alternative->getEndLanePosition();
    1171           12 :         switch (alternative->getElement()) {
    1172            0 :             case SUMO_TAG_PARKING_AREA:
    1173              :                 newStop.parkingarea = alternative->getID();
    1174              :                 break;
    1175            0 :             case SUMO_TAG_CONTAINER_STOP:
    1176              :                 newStop.containerstop = alternative->getID();
    1177              :                 break;
    1178            0 :             case SUMO_TAG_CHARGING_STATION:
    1179              :                 newStop.chargingStation = alternative->getID();
    1180              :                 break;
    1181            0 :             case SUMO_TAG_OVERHEAD_WIRE_SEGMENT:
    1182              :                 newStop.overheadWireSegment = alternative->getID();
    1183              :                 break;
    1184           12 :             case SUMO_TAG_BUS_STOP:
    1185              :             case SUMO_TAG_TRAIN_STOP:
    1186              :             default:
    1187              :                 newStop.busstop = alternative->getID();
    1188              :         }
    1189              :         std::string errorMsg;
    1190           24 :         if (!ego.replaceStop(0, newStop, getID() + ":" + toString(SUMO_TAG_STATION_REROUTE), false, errorMsg)) {
    1191            0 :             WRITE_WARNING("Vehicle '" + ego.getID() + "' at rerouter '" + getID()
    1192              :                           + "' could not perform stationReroute to '" + alternative->getID()
    1193              :                           + "' reason=" + errorMsg + ", time=" + time2string(MSNet::getInstance()->getCurrentTimeStep()) + ".");
    1194              :         }
    1195           12 :     }
    1196           24 : }
    1197              : 
    1198              : 
    1199              : MSRailSignal*
    1200          152 : MSTriggeredRerouter::findSignal(ConstMSEdgeVector::const_iterator begin, ConstMSEdgeVector::const_iterator end) {
    1201          152 :     auto it = end;
    1202              :     do {
    1203              :         it--;
    1204          304 :         auto signal = getRailSignal(*it);
    1205          304 :         if (signal != nullptr) {
    1206          152 :             return signal;
    1207              :         }
    1208          152 :     } while (it != begin);
    1209              :     return nullptr;
    1210              : }
    1211              : 
    1212              : 
    1213              : MSRailSignal*
    1214         1570 : MSTriggeredRerouter::getRailSignal(const MSEdge* edge) {
    1215         1570 :     if (edge->getToJunction()->getType() == SumoXMLNodeType::RAIL_SIGNAL) {
    1216          732 :         for (const MSLink* link : edge->getLanes().front()->getLinkCont()) {
    1217          732 :             if (link->getTLLogic() != nullptr) {
    1218          732 :                 return dynamic_cast<MSRailSignal*>(const_cast<MSTrafficLightLogic*>(link->getTLLogic()));
    1219              :             }
    1220              :         }
    1221              :     }
    1222              :     return nullptr;
    1223              : }
    1224              : 
    1225              : bool
    1226      1176563 : MSTriggeredRerouter::applies(const SUMOTrafficObject& obj) const {
    1227      1176563 :     if (myVehicleTypes.empty() || myVehicleTypes.count(obj.getVehicleType().getOriginalID()) > 0) {
    1228      1176493 :         return true;
    1229              :     } else {
    1230          140 :         std::set<std::string> vTypeDists = MSNet::getInstance()->getVehicleControl().getVTypeDistributionMembership(obj.getVehicleType().getOriginalID());
    1231           70 :         for (auto vTypeDist : vTypeDists) {
    1232              :             if (myVehicleTypes.count(vTypeDist) > 0) {
    1233              :                 return true;
    1234              :             }
    1235              :         }
    1236           70 :         return false;
    1237              :     }
    1238              : }
    1239              : 
    1240              : 
    1241              : bool
    1242       123608 : MSTriggeredRerouter::affected(const std::set<SUMOTrafficObject::NumericalID>& edgeIndices, const MSEdgeVector& closed) {
    1243       141040 :     for (const MSEdge* const e : closed) {
    1244        66140 :         if (edgeIndices.count(e->getNumericalID()) > 0) {
    1245              :             return true;
    1246              :         }
    1247              :     }
    1248              :     return false;
    1249              : }
    1250              : 
    1251              : 
    1252              : void
    1253        23532 : MSTriggeredRerouter::checkParkingRerouteConsistency() {
    1254              :     // if a parkingArea is a rerouting target, it should generally have a
    1255              :     // rerouter on its edge or vehicles will be stuck there once it's full.
    1256              :     // The user should receive a Warning in this case
    1257              :     std::set<MSEdge*> parkingRerouterEdges;
    1258              :     std::map<MSParkingArea*, std::string, ComparatorIdLess> targetedParkingArea; // paID -> targetingRerouter
    1259        27517 :     for (const auto& rr : myInstances) {
    1260              :         bool hasParkingReroute = false;
    1261         7763 :         for (const RerouteInterval& interval : rr.second->myIntervals) {
    1262         3778 :             if (interval.parkProbs.getOverallProb() > 0) {
    1263              :                 hasParkingReroute = true;
    1264        15735 :                 for (const StoppingPlaceVisible& pav : interval.parkProbs.getVals()) {
    1265        27030 :                     targetedParkingArea[dynamic_cast<MSParkingArea*>(pav.first)] = rr.first;
    1266              :                 }
    1267              :             }
    1268              :         }
    1269         3985 :         if (hasParkingReroute) {
    1270         2220 :             parkingRerouterEdges.insert(rr.second->myEdges.begin(), rr.second->myEdges.end());
    1271              :         }
    1272              :     }
    1273        26361 :     for (const auto& item : targetedParkingArea) {
    1274         2829 :         if (parkingRerouterEdges.count(&item.first->getLane().getEdge()) == 0) {
    1275         1168 :             WRITE_WARNINGF(TL("ParkingArea '%' is targeted by rerouter '%' but doesn't have its own rerouter. This may cause parking search to abort."),
    1276              :                            item.first->getID(), item.second);
    1277              :         }
    1278              :     }
    1279        23532 : }
    1280              : 
    1281              : 
    1282              : void
    1283        20025 : MSTriggeredRerouter::resetClosedEdges(bool hasReroutingDevice, const SUMOTrafficObject& o) {
    1284              :     // getRouterTT without prohibitions removes previous prohibitions
    1285        20025 :     if (o.isVehicle()) {
    1286              :         hasReroutingDevice
    1287        40050 :         ? MSRoutingEngine::getRouterTT(o.getRNGIndex(), o.getVClass())
    1288        27573 :         : MSNet::getInstance()->getRouterTT(o.getRNGIndex());
    1289              :     } else {
    1290              :         hasReroutingDevice
    1291            0 :         ? MSRoutingEngine::getIntermodalRouterTT(o.getRNGIndex())
    1292            0 :         : MSNet::getInstance()->getIntermodalRouter(o.getRNGIndex(), 0);
    1293              :     }
    1294        20025 : }
    1295              : 
    1296              : /****************************************************************************/
        

Generated by: LCOV version 2.0-1