LCOV - code coverage report
Current view: top level - src/microsim/trigger - MSTriggeredRerouter.cpp (source / functions) Coverage Total Hit
Test: lcov.info Lines: 90.6 % 597 541
Test Date: 2026-03-02 16:00:03 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-2026 German Aerospace Center (DLR) and others.
       4              : // This program and the accompanying materials are made available under the
       5              : // terms of the Eclipse Public License 2.0 which is available at
       6              : // https://www.eclipse.org/legal/epl-2.0/
       7              : // This Source Code may also be made available under the following Secondary
       8              : // Licenses when the conditions for such availability set forth in the Eclipse
       9              : // Public License 2.0 are satisfied: GNU General Public License, version 2
      10              : // or later which is available at
      11              : // https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html
      12              : // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
      13              : /****************************************************************************/
      14              : /// @file    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         4004 : MSTriggeredRerouter::MSTriggeredRerouter(const std::string& id,
      88              :         const MSEdgeVector& edges, double prob, bool off, bool optional,
      89         4004 :         SUMOTime timeThreshold, const std::string& vTypes, const Position& pos, const double radius) :
      90              :     Named(id),
      91              :     MSMoveReminder(id),
      92              :     MSStoppingPlaceRerouter("parking"),
      93         4004 :     myEdges(edges),
      94         4004 :     myProbability(prob),
      95         4004 :     myUserProbability(prob),
      96         4004 :     myAmInUserMode(false),
      97         4004 :     myAmOptional(optional),
      98         4004 :     myPosition(pos),
      99         4004 :     myRadius(radius),
     100         4004 :     myTimeThreshold(timeThreshold),
     101        12012 :     myHaveParkProbs(false) {
     102         4004 :     myInstances[id] = this;
     103              :     // build actors
     104         9322 :     for (const MSEdge* const e : edges) {
     105         5318 :         if (MSGlobals::gUseMesoSim) {
     106          717 :             MSGlobals::gMesoNet->getSegmentForEdge(*e)->addDetector(this);
     107              :         }
     108        11289 :         for (MSLane* const lane : e->getLanes()) {
     109         5971 :             lane->addMoveReminder(this);
     110              :         }
     111              :     }
     112         4004 :     if (off) {
     113            1 :         setUserMode(true);
     114            1 :         setUserUsageProbability(0);
     115              :     }
     116         8008 :     const std::vector<std::string> vt = StringTokenizer(vTypes).getVector();
     117              :     myVehicleTypes.insert(vt.begin(), vt.end());
     118              :     if (myPosition == Position::INVALID) {
     119         3626 :         myPosition = edges.front()->getLanes()[0]->getShape()[0];
     120              :     }
     121         4004 : }
     122              : 
     123              : 
     124         7272 : MSTriggeredRerouter::~MSTriggeredRerouter() {
     125              :     myInstances.erase(getID());
     126        11272 : }
     127              : 
     128              : 
     129              : // ------------ loading begin
     130              : void
     131        19694 : MSTriggeredRerouter::myStartElement(int element,
     132              :                                     const SUMOSAXAttributes& attrs) {
     133        19694 :     if (element == SUMO_TAG_INTERVAL) {
     134         3861 :         bool ok = true;
     135         3861 :         myParsedRerouteInterval = RerouteInterval();
     136         3861 :         myParsedRerouteInterval.begin = attrs.getOptSUMOTimeReporting(SUMO_ATTR_BEGIN, nullptr, ok, -1);
     137         3861 :         myParsedRerouteInterval.end = attrs.getOptSUMOTimeReporting(SUMO_ATTR_END, nullptr, ok, SUMOTime_MAX);
     138         3861 :         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        19688 :     if (element == SUMO_TAG_DEST_PROB_REROUTE) {
     145              :         // by giving probabilities of new destinations
     146              :         // get the destination edge
     147          226 :         std::string dest = attrs.getStringSecure(SUMO_ATTR_ID, "");
     148          226 :         if (dest == "") {
     149            0 :             throw ProcessError(TLF("rerouter '%': destProbReroute has no destination edge id.", getID()));
     150              :         }
     151          226 :         MSEdge* to = MSEdge::dictionary(dest);
     152          226 :         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          226 :         bool ok = true;
     163          226 :         double prob = attrs.getOpt<double>(SUMO_ATTR_PROB, getID().c_str(), ok, 1.);
     164          226 :         if (!ok) {
     165            0 :             throw ProcessError();
     166              :         }
     167          226 :         if (prob < 0) {
     168            0 :             throw ProcessError(TLF("rerouter '%': Attribute 'probability' for destination '%' is negative (must not).", getID(), dest));
     169              :         }
     170              :         // add
     171          226 :         myParsedRerouteInterval.edgeProbs.add(to, prob);
     172              :     }
     173              : 
     174        19688 :     if (element == SUMO_TAG_CLOSING_REROUTE) {
     175              :         // by closing edge
     176          960 :         const std::string& closed_id = attrs.getStringSecure(SUMO_ATTR_ID, "");
     177          960 :         MSEdge* const closedEdge = MSEdge::dictionary(closed_id);
     178          960 :         if (closedEdge == nullptr) {
     179            0 :             throw ProcessError(TLF("rerouter '%': Edge '%' to close is not known.", getID(), closed_id));
     180              :         }
     181              :         bool ok;
     182          960 :         const std::string allow = attrs.getOpt<std::string>(SUMO_ATTR_ALLOW, getID().c_str(), ok, "", false);
     183          960 :         const std::string disallow = attrs.getOpt<std::string>(SUMO_ATTR_DISALLOW, getID().c_str(), ok, "");
     184          960 :         const SUMOTime until = attrs.getOptSUMOTimeReporting(SUMO_ATTR_UNTIL, nullptr, ok, TIME2STEPS(-1));
     185          960 :         SVCPermissions permissions = parseVehicleClasses(allow, disallow);
     186          960 :         myParsedRerouteInterval.closed[closedEdge] = std::make_pair(permissions, STEPS2TIME(until));
     187              :     }
     188              : 
     189        19688 :     if (element == SUMO_TAG_CLOSING_LANE_REROUTE) {
     190              :         // by closing lane
     191          141 :         std::string closed_id = attrs.getStringSecure(SUMO_ATTR_ID, "");
     192          141 :         MSLane* closedLane = MSLane::dictionary(closed_id);
     193          141 :         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          141 :         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          141 :         myParsedRerouteInterval.closedLanes[closedLane] = permissions;
     204              :     }
     205              : 
     206        19688 :     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        19688 :     if (element == SUMO_TAG_PARKING_AREA_REROUTE) {
     232        13584 :         std::string parkingarea = attrs.getStringSecure(SUMO_ATTR_ID, "");
     233        13584 :         if (parkingarea == "") {
     234            0 :             throw ProcessError(TLF("rerouter '%': parkingAreaReroute requires a parkingArea id.", getID()));
     235              :         }
     236        13584 :         MSParkingArea* pa = static_cast<MSParkingArea*>(MSNet::getInstance()->getStoppingPlace(parkingarea, SUMO_TAG_PARKING_AREA));
     237        13584 :         if (pa == nullptr) {
     238            0 :             throw ProcessError(TLF("rerouter '%': parkingArea '%' is not known.", getID(), parkingarea));
     239              :         }
     240              :         // get the probability to reroute
     241        13584 :         bool ok = true;
     242        13584 :         const double prob = attrs.getOpt<double>(SUMO_ATTR_PROB, getID().c_str(), ok, 1.);
     243        13584 :         if (!ok) {
     244            0 :             throw ProcessError();
     245              :         }
     246        13584 :         if (prob < 0) {
     247            0 :             throw ProcessError(TLF("rerouter '%': Attribute 'probability' for parkingArea '%' is negative (must not).", getID(), parkingarea));
     248              :         }
     249        13584 :         const bool visible = attrs.getOpt<bool>(SUMO_ATTR_VISIBLE, getID().c_str(), ok, false);
     250              :         // add
     251        13584 :         myParsedRerouteInterval.parkProbs.add(std::make_pair(pa, visible), prob);
     252        13584 :         myHaveParkProbs = true;
     253              :     }
     254              : 
     255        19688 :     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        19688 :     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        19688 :     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        19688 : }
     326              : 
     327              : 
     328              : void
     329        23686 : MSTriggeredRerouter::myEndElement(int element) {
     330        23686 :     if (element == SUMO_TAG_INTERVAL) {
     331              :         // precompute permissionsAllowAll
     332              :         bool allowAll = true;
     333         4206 :         for (const auto& entry : myParsedRerouteInterval.closed) {
     334          789 :             allowAll = allowAll && entry.second.first == SVCAll;
     335              :             if (!allowAll) {
     336              :                 break;
     337              :             }
     338              :         }
     339         3855 :         myParsedRerouteInterval.permissionsAllowAll = allowAll;
     340              : 
     341        17436 :         for (auto paVi : myParsedRerouteInterval.parkProbs.getVals()) {
     342        13581 :             dynamic_cast<MSParkingArea*>(paVi.first)->setNumAlternatives((int)myParsedRerouteInterval.parkProbs.getVals().size() - 1);
     343              :         }
     344         3855 :         if (myParsedRerouteInterval.closedLanes.size() > 0) {
     345              :             // collect edges that are affect by a closed lane
     346              :             std::set<MSEdge*> affected;
     347          226 :             for (std::pair<MSLane*, SVCPermissions> settings : myParsedRerouteInterval.closedLanes) {
     348          135 :                 affected.insert(&settings.first->getEdge());
     349              :             }
     350           91 :             myParsedRerouteInterval.closedLanesAffected.insert(myParsedRerouteInterval.closedLanesAffected.begin(), affected.begin(), affected.end());
     351              :         }
     352         3855 :         const SUMOTime closingBegin = myParsedRerouteInterval.begin;
     353         3855 :         const SUMOTime simBegin = string2time(OptionsCont::getOptions().getString("begin"));
     354         3855 :         if (closingBegin < simBegin && myParsedRerouteInterval.end > simBegin) {
     355              :             // interval started before simulation begin but is still active at
     356              :             // the start of the simulation
     357          415 :             myParsedRerouteInterval.begin = simBegin;
     358              :         }
     359         3855 :         myIntervals.push_back(myParsedRerouteInterval);
     360         3855 :         myIntervals.back().id = (long long int)&myIntervals.back();
     361         3855 :         if (!(myParsedRerouteInterval.closed.empty() && myParsedRerouteInterval.closedLanes.empty())) {
     362         1648 :             MSNet::getInstance()->getBeginOfTimestepEvents()->addEvent(
     363          824 :                 new WrappingCommand<MSTriggeredRerouter>(this, &MSTriggeredRerouter::setPermissions), myParsedRerouteInterval.begin);
     364              :         }
     365              :     }
     366        23686 : }
     367              : 
     368              : 
     369              : // ------------ loading end
     370              : 
     371              : 
     372              : SUMOTime
     373          987 : MSTriggeredRerouter::setPermissions(const SUMOTime currentTime) {
     374              :     bool updateVehicles = false;
     375         2019 :     for (const RerouteInterval& i : myIntervals) {
     376         1032 :         if (i.begin == currentTime && !(i.closed.empty() && i.closedLanes.empty()) /*&& i.permissions != SVCAll*/) {
     377         1763 :             for (const auto& settings : i.closed) {
     378         1895 :                 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          956 :                     lane->setPermissions(settings.second.first, i.id);
     381              :                 }
     382          939 :                 settings.first->rebuildAllowedLanes();
     383              :                 updateVehicles = true;
     384              :             }
     385          973 :             for (std::pair<MSLane*, SVCPermissions> settings : i.closedLanes) {
     386          149 :                 settings.first->setPermissions(settings.second, i.id);
     387          149 :                 settings.first->getEdge().rebuildAllowedLanes();
     388              :                 updateVehicles = true;
     389              :             }
     390         1648 :             MSNet::getInstance()->getBeginOfTimestepEvents()->addEvent(
     391          824 :                 new WrappingCommand<MSTriggeredRerouter>(this, &MSTriggeredRerouter::setPermissions), i.end);
     392              :         }
     393         1032 :         if (i.end == currentTime && !(i.closed.empty() && i.closedLanes.empty()) /*&& i.permissions != SVCAll*/) {
     394          356 :             for (auto settings : i.closed) {
     395          335 :                 for (MSLane* lane : settings.first->getLanes()) {
     396          172 :                     lane->resetPermissions(i.id);
     397              :                     //std::cout << SIMTIME << " opening: intervalID=" << i.id << " lane=" << lane->getID() << " restore prevPerm=" << getVehicleClassNames(lane->getPermissions()) << "\n";
     398              :                 }
     399          163 :                 settings.first->rebuildAllowedLanes();
     400              :                 updateVehicles = true;
     401              :             }
     402          310 :             for (std::pair<MSLane*, SVCPermissions> settings : i.closedLanes) {
     403          117 :                 settings.first->resetPermissions(i.id);
     404          117 :                 settings.first->getEdge().rebuildAllowedLanes();
     405              :                 updateVehicles = true;
     406              :             }
     407              :         }
     408              :     }
     409          987 :     if (updateVehicles) {
     410              :         // only vehicles on the affected lanes had their bestlanes updated so far
     411         1999 :         for (MSEdge* e : myEdges) {
     412              :             // also updates vehicles
     413         1012 :             e->rebuildAllowedTargets();
     414              :         }
     415              :     }
     416          987 :     return 0;
     417              : }
     418              : 
     419              : 
     420              : const MSTriggeredRerouter::RerouteInterval*
     421      1193642 : MSTriggeredRerouter::getCurrentReroute(SUMOTime time, SUMOTrafficObject& obj) const {
     422      1703533 :     for (const RerouteInterval& ri : myIntervals) {
     423      1207723 :         if (ri.begin <= time && ri.end > time) {
     424              :             if (
     425              :                 // destProbReroute
     426       712513 :                 ri.edgeProbs.getOverallProb() > 0 ||
     427              :                 // routeProbReroute
     428       176856 :                 ri.routeProbs.getOverallProb() > 0 ||
     429              :                 // parkingZoneReroute
     430       783597 :                 ri.parkProbs.getOverallProb() > 0 ||
     431              :                 // stationReroute
     432              :                 ri.stopAlternatives.size() > 0) {
     433       648011 :                 return &ri;
     434              :             }
     435        67787 :             if (!ri.closed.empty() || !ri.closedLanesAffected.empty() || !ri.overtakeLocations.empty()) {
     436        67787 :                 const std::set<SUMOTrafficObject::NumericalID>& edgeIndices = obj.getUpcomingEdgeIDs();
     437       135574 :                 if (affected(edgeIndices, ri.getClosedEdges())
     438        67787 :                         || affected(edgeIndices, ri.closedLanesAffected)) {
     439        49677 :                     return &ri;
     440              :                 }
     441        18110 :                 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       318093 : MSTriggeredRerouter::getCurrentReroute(SUMOTime time) const {
     456       318120 :     for (const RerouteInterval& ri : myIntervals) {
     457       318093 :         if (ri.begin <= time && ri.end > time) {
     458       318066 :             if (ri.edgeProbs.getOverallProb() != 0 || ri.routeProbs.getOverallProb() != 0 || ri.parkProbs.getOverallProb() != 0
     459       318083 :                     || !ri.closed.empty() || !ri.closedLanesAffected.empty() || !ri.overtakeLocations.empty()) {
     460              :                 return &ri;
     461              :             }
     462              :         }
     463              :     }
     464              :     return nullptr;
     465              : }
     466              : 
     467              : 
     468              : bool
     469       670762 : MSTriggeredRerouter::notifyEnter(SUMOTrafficObject& tObject, MSMoveReminder::Notification reason, const MSLane* /* enteredLane */) {
     470       670762 :     if (myAmOptional || myRadius != std::numeric_limits<double>::max()) {
     471              :         return true;
     472              :     }
     473       670622 :     return triggerRouting(tObject, reason);
     474              : }
     475              : 
     476              : 
     477              : bool
     478       522448 : MSTriggeredRerouter::notifyMove(SUMOTrafficObject& veh, double /*oldPos*/,
     479              :                                 double /*newPos*/, double /*newSpeed*/) {
     480       522448 :     return triggerRouting(veh, NOTIFICATION_JUNCTION);
     481              : }
     482              : 
     483              : 
     484              : bool
     485        18946 : MSTriggeredRerouter::notifyLeave(SUMOTrafficObject& /*veh*/, double /*lastPos*/,
     486              :                                  MSMoveReminder::Notification reason, const MSLane* /* enteredLane */) {
     487        18946 :     return reason == NOTIFICATION_LANE_CHANGE;
     488              : }
     489              : 
     490              : 
     491              : bool
     492      1193712 : MSTriggeredRerouter::triggerRouting(SUMOTrafficObject& tObject, MSMoveReminder::Notification reason) {
     493      1193712 :     if (!applies(tObject)) {
     494              :         return false;
     495              :     }
     496      1193642 :     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      1193642 :     const SUMOTime now = MSNet::getInstance()->getCurrentTimeStep();
     501      1193642 :     const MSTriggeredRerouter::RerouteInterval* const rerouteDef = getCurrentReroute(now, tObject);
     502      1193642 :     if (rerouteDef == nullptr) {
     503              :         return true; // an active interval could appear later
     504              :     }
     505       697832 :     const double prob = myAmInUserMode ? myUserProbability : myProbability;
     506       697832 :     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       697543 :     if (myTimeThreshold > 0 && MAX2(tObject.getWaitingTime(), tObject.getWaitingTime(true)) < myTimeThreshold) {
     510              :         return true; // waiting time may be reached later
     511              :     }
     512       691096 :     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       672946 :     const bool hasReroutingDevice = tObject.getDevice(typeid(MSDevice_Routing)) != nullptr;
     517       672946 :     if (rerouteDef->closedLanes.size() > 0 && !hasReroutingDevice) {
     518              :         return true; // an active interval could appear later
     519              :     }
     520       633001 :     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       633001 :     if (rerouteDef->parkProbs.getOverallProb() > 0) {
     528              : #ifdef HAVE_FOX
     529       104000 :         ScopedLocker<> lock(myNotificationMutex, MSGlobals::gNumSimThreads > 1);
     530              : #endif
     531       104000 :         if (!tObject.isVehicle()) {
     532              :             return false;
     533              :         }
     534              :         SUMOVehicle& veh = static_cast<SUMOVehicle&>(tObject);
     535       103935 :         bool newDestination = false;
     536              :         ConstMSEdgeVector newRoute;
     537       103935 :         MSParkingArea* oldParkingArea = veh.getNextParkingArea();
     538       103935 :         MSParkingArea* newParkingArea = rerouteParkingArea(rerouteDef, veh, newDestination, newRoute);
     539       103935 :         if (newParkingArea != nullptr) {
     540              :             // adapt plans of any riders
     541        28829 :             for (MSTransportable* p : veh.getPersons()) {
     542           40 :                 p->rerouteParkingArea(oldParkingArea, newParkingArea);
     543              :             }
     544              : 
     545        28789 :             if (newDestination && veh.getParameter().arrivalPosProcedure != ArrivalPosDefinition::DEFAULT) {
     546              :                 // update arrival parameters
     547           50 :                 SUMOVehicleParameter* newParameter = new SUMOVehicleParameter();
     548           50 :                 *newParameter = veh.getParameter();
     549           50 :                 newParameter->arrivalPosProcedure = ArrivalPosDefinition::GIVEN;
     550           50 :                 newParameter->arrivalPos = newParkingArea->getEndLanePosition();
     551           50 :                 veh.replaceParameter(newParameter);
     552              :             }
     553              : 
     554              :             SUMOAbstractRouter<MSEdge, SUMOVehicle>& router = hasReroutingDevice
     555        12724 :                     ? MSRoutingEngine::getRouterTT(veh.getRNGIndex(), veh.getVClass(), rerouteDef->getClosed())
     556        57578 :                     : MSNet::getInstance()->getRouterTT(veh.getRNGIndex(), rerouteDef->getClosed());
     557        28789 :             const double routeCost = router.recomputeCosts(newRoute, &veh, MSNet::getInstance()->getCurrentTimeStep());
     558        28789 :             ConstMSEdgeVector prevEdges(veh.getCurrentRouteEdge(), veh.getRoute().end());
     559        28789 :             const double previousCost = router.recomputeCosts(prevEdges, &veh, MSNet::getInstance()->getCurrentTimeStep());
     560        28789 :             const double savings = previousCost - routeCost;
     561        28789 :             resetClosedEdges(hasReroutingDevice, veh);
     562              :             //if (getID() == "ego") std::cout << SIMTIME << " pCost=" << previousCost << " cost=" << routeCost
     563              :             //        << " prevEdges=" << toString(prevEdges)
     564              :             //        << " newEdges=" << toString(edges)
     565              :             //        << "\n";
     566              : 
     567              :             std::string errorMsg;
     568        28789 :             if (veh.replaceParkingArea(newParkingArea, errorMsg)) {
     569        57578 :                 veh.replaceRouteEdges(newRoute, routeCost, savings, getID() + ":" + toString(SUMO_TAG_PARKING_AREA_REROUTE), false, false, false);
     570        28789 :                 if (oldParkingArea->isReservable()) {
     571           20 :                     oldParkingArea->removeSpaceReservation(&veh);
     572              :                 }
     573        28789 :                 if (newParkingArea->isReservable()) {
     574           20 :                     newParkingArea->addSpaceReservation(&veh);
     575              :                 }
     576              :             } else {
     577            0 :                 WRITE_WARNING("Vehicle '" + veh.getID() + "' at rerouter '" + getID()
     578              :                               + "' could not reroute to new parkingArea '" + newParkingArea->getID()
     579              :                               + "' reason=" + errorMsg + ", time=" + time2string(MSNet::getInstance()->getCurrentTimeStep()) + ".");
     580              :             }
     581        28789 :         } else {
     582        75146 :             if (oldParkingArea && oldParkingArea->isReservable()) {
     583           10 :                 oldParkingArea->addSpaceReservation(&veh);
     584              :             }
     585              :         }
     586              :         return false;
     587       103935 :     }
     588       529001 :     if (rerouteDef->overtakeLocations.size() > 0) {
     589          144 :         if (!tObject.isVehicle()) {
     590              :             return false;
     591              :         }
     592              :         SUMOVehicle& veh = static_cast<SUMOVehicle&>(tObject);
     593          144 :         const ConstMSEdgeVector& oldEdges = veh.getRoute().getEdges();
     594              :         double bestSavings = -std::numeric_limits<double>::max();
     595              :         double netSaving;
     596              :         int bestIndex = -1;
     597              :         MSRouteIterator bestMainStart = oldEdges.end();
     598              :         std::pair<const SUMOVehicle*, MSRailSignal*> best_overtaker_signal(nullptr, nullptr);
     599              :         int index = -1;
     600              :         // sort locations by descending distance to vehicle
     601              :         std::vector<std::pair<int, int> > sortedLocs;
     602          330 :         for (const OvertakeLocation& oloc : rerouteDef->overtakeLocations) {
     603          186 :             index++;
     604          186 :             if (veh.getLength() > oloc.sidingLength) {
     605            3 :                 continue;
     606              :             }
     607          183 :             auto mainStart = std::find(veh.getCurrentRouteEdge(), oldEdges.end(), oloc.main.front());
     608          183 :             if (mainStart == oldEdges.end()
     609              :                     // exit main within
     610          366 :                     || ConstMSEdgeVector(mainStart, mainStart + oloc.main.size()) != oloc.cMain
     611              :                     // stop in main
     612          366 :                     || (veh.hasStops() && veh.getNextStop().edge < (mainStart + oloc.main.size()))) {
     613              :                 //std::cout << SIMTIME << " veh=" << veh.getID() << " wrong route or stop\n";
     614            0 :                 continue;
     615              :             }
     616              :             // negated iterator distance for descending order
     617          183 :             sortedLocs.push_back(std::make_pair(-(int)(mainStart - veh.getCurrentRouteEdge()), index));
     618              :         }
     619          144 :         std::sort(sortedLocs.begin(), sortedLocs.end());
     620          327 :         for (const auto& item : sortedLocs) {
     621          183 :             index = item.second;
     622          183 :             const OvertakeLocation& oloc = rerouteDef->overtakeLocations[index];
     623          183 :             auto mainStart = veh.getCurrentRouteEdge() - item.first;  // subtracting negative difference
     624          183 :             std::pair<const SUMOVehicle*, MSRailSignal*> overtaker_signal = overtakingTrain(veh, mainStart, oloc, netSaving);
     625          183 :             if (overtaker_signal.first != nullptr && netSaving > bestSavings) {
     626              :                 bestSavings = netSaving;
     627              :                 bestIndex = index;
     628              :                 best_overtaker_signal = overtaker_signal;
     629              :                 bestMainStart = mainStart;
     630              : #ifdef DEBUG_OVERTAKING
     631              :                 std::cout << "    newBest index=" << bestIndex << " saving=" << bestSavings << "\n";
     632              : #endif
     633              :             }
     634              :         }
     635          144 :         if (bestIndex >= 0) {
     636           41 :             const OvertakeLocation& oloc = rerouteDef->overtakeLocations[bestIndex];
     637           41 :             if (oloc.defer) {
     638            5 :                 return false;
     639              :             }
     640              :             SUMOAbstractRouter<MSEdge, SUMOVehicle>& router = hasReroutingDevice
     641            0 :                     ? MSRoutingEngine::getRouterTT(veh.getRNGIndex(), veh.getVClass(), rerouteDef->getClosed())
     642           72 :                     : MSNet::getInstance()->getRouterTT(veh.getRNGIndex(), rerouteDef->getClosed());
     643           36 :             ConstMSEdgeVector newEdges(veh.getCurrentRouteEdge(), bestMainStart);
     644           36 :             newEdges.insert(newEdges.end(), oloc.siding.begin(), oloc.siding.end());
     645           36 :             newEdges.insert(newEdges.end(), bestMainStart + oloc.main.size(), oldEdges.end());
     646           36 :             const double routeCost = router.recomputeCosts(newEdges, &veh, MSNet::getInstance()->getCurrentTimeStep());
     647           36 :             const double savings = (router.recomputeCosts(oloc.cMain, &veh, MSNet::getInstance()->getCurrentTimeStep())
     648           36 :                                     - router.recomputeCosts(oloc.cSiding, &veh, MSNet::getInstance()->getCurrentTimeStep()));
     649           72 :             const std::string info = getID() + ":" + toString(SUMO_TAG_OVERTAKING_REROUTE) + ":" + best_overtaker_signal.first->getID();
     650           36 :             veh.replaceRouteEdges(newEdges, routeCost, savings, info, false, false, false);
     651           36 :             oloc.sidingExit->addConstraint(veh.getID(), new MSRailSignalConstraint_Predecessor(
     652           36 :                                                MSRailSignalConstraint::PREDECESSOR, best_overtaker_signal.second, best_overtaker_signal.first->getID(), 100, true));
     653           36 :             resetClosedEdges(hasReroutingDevice, veh);
     654           36 :         }
     655          139 :         return false;
     656          144 :     }
     657       528857 :     if (rerouteDef->stopAlternatives.size() > 0) {
     658              :         // somewhat similar to parkProbs but taking into account public transport schedule
     659           12 :         if (!tObject.isVehicle()) {
     660              :             return false;
     661              :         }
     662           12 :         checkStopSwitch(static_cast<MSBaseVehicle&>(tObject), rerouteDef);
     663              :     }
     664              :     // get rerouting params
     665       528857 :     ConstMSRoutePtr newRoute = rerouteDef->routeProbs.getOverallProb() > 0 ? rerouteDef->routeProbs.get() : nullptr;
     666              :     // we will use the route if given rather than calling our own dijsktra...
     667       528857 :     if (newRoute != nullptr) {
     668              : #ifdef DEBUG_REROUTER
     669              :         if (DEBUGCOND(tObject)) {
     670              :             std::cout << "    replacedRoute from routeDist " << newRoute->getID() << "\n";
     671              :         }
     672              : #endif
     673       522921 :         tObject.replaceRoute(newRoute, getID());
     674       522918 :         return false; // XXX another interval could appear later but we would have to track whether the currenty interval was already used
     675              :     }
     676              :     const MSEdge* newEdge = lastEdge;
     677              :     // ok, try using a new destination
     678              :     double newArrivalPos = -1;
     679         5939 :     const MSEdgeVector closedEdges = rerouteDef->getClosedEdges();
     680         5939 :     const bool destUnreachable = std::find(closedEdges.begin(), closedEdges.end(), lastEdge) != closedEdges.end();
     681              :     bool keepDestination = false;
     682              :     // if we have a closingReroute, only assign new destinations to vehicles which cannot reach their original destination
     683              :     // if we have a closingLaneReroute, no new destinations should be assigned
     684         5939 :     if (closedEdges.empty() || destUnreachable || rerouteDef->isVia) {
     685         4177 :         newEdge = rerouteDef->edgeProbs.getOverallProb() > 0 ? rerouteDef->edgeProbs.get() : lastEdge;
     686              :         assert(newEdge != nullptr);
     687         4177 :         if (newEdge == &mySpecialDest_terminateRoute) {
     688              :             keepDestination = true;
     689           55 :             newEdge = tObject.getEdge();
     690           55 :             newArrivalPos = tObject.getPositionOnLane(); // instant arrival
     691         4122 :         } else if (newEdge == &mySpecialDest_keepDestination || newEdge == lastEdge) {
     692         1578 :             if (destUnreachable && rerouteDef->permissionsAllowAll) {
     693              :                 // if permissions aren't set vehicles will simply drive through
     694              :                 // the closing unless terminated. If the permissions are specified, assume that the user wants
     695              :                 // vehicles to stand and wait until the closing ends
     696           63 :                 WRITE_WARNINGF(TL("Cannot keep destination edge '%' for vehicle '%' due to closed edges. Terminating route."), lastEdge->getID(), tObject.getID());
     697           21 :                 newEdge = tObject.getEdge();
     698              :             } else {
     699              :                 newEdge = lastEdge;
     700              :             }
     701              :         }
     702              :     }
     703              :     ConstMSEdgeVector edges;
     704              :     std::vector<MSTransportableRouter::TripItem> items;
     705              :     // we have a new destination, let's replace the route (if it is affected)
     706         5939 :     MSEdgeVector closed = rerouteDef->getClosedEdges();
     707         5939 :     Prohibitions prohibited = rerouteDef->getClosed();
     708         7701 :     if (rerouteDef->closed.empty() || destUnreachable || rerouteDef->isVia || affected(tObject.getUpcomingEdgeIDs(), closed)) {
     709         5862 :         if (tObject.isVehicle()) {
     710              :             SUMOVehicle& veh = static_cast<SUMOVehicle&>(tObject);
     711         4392 :             const bool canChangeDest = rerouteDef->edgeProbs.getOverallProb() > 0;
     712              :             MSVehicleRouter& router = hasReroutingDevice
     713         4392 :                                       ? MSRoutingEngine::getRouterTT(veh.getRNGIndex(), veh.getVClass(), prohibited)
     714         1724 :                                       : MSNet::getInstance()->getRouterTT(veh.getRNGIndex(), prohibited);
     715         4392 :             bool ok = veh.reroute(now, getID(), router, false, false, canChangeDest, newEdge);
     716         4389 :             if (!ok && !keepDestination && canChangeDest) {
     717              :                 // destination unreachable due to closed intermediate edges. pick among alternative targets
     718           82 :                 RandomDistributor<MSEdge*> edgeProbs2 = rerouteDef->edgeProbs;
     719           82 :                 edgeProbs2.remove(const_cast<MSEdge*>(newEdge));
     720          152 :                 while (!ok && edgeProbs2.getVals().size() > 0) {
     721          110 :                     newEdge = edgeProbs2.get();
     722          110 :                     edgeProbs2.remove(const_cast<MSEdge*>(newEdge));
     723          110 :                     if (newEdge == &mySpecialDest_terminateRoute) {
     724           42 :                         newEdge = veh.getEdge();
     725           42 :                         newArrivalPos = veh.getPositionOnLane(); // instant arrival
     726              :                     }
     727          110 :                     if (newEdge == &mySpecialDest_keepDestination && !rerouteDef->permissionsAllowAll) {
     728              :                         newEdge = lastEdge;
     729              :                         break;
     730              :                     }
     731           70 :                     ok = veh.reroute(now, getID(), router, false, false, true, newEdge);
     732              :                 }
     733              : 
     734              :             }
     735         4389 :             if (!rerouteDef->isVia) {
     736              : #ifdef DEBUG_REROUTER
     737              :                 if (DEBUGCOND(tObject)) std::cout << "   rerouting:  newDest=" << newEdge->getID()
     738              :                                                       << " newEdges=" << toString(edges)
     739              :                                                       << " newArrivalPos=" << newArrivalPos << " numClosed=" << rerouteDef->closed.size()
     740              :                                                       << " destUnreachable=" << destUnreachable << " containsClosed=" << veh.getRoute().containsAnyOf(rerouteDef->getClosedEdges()) << "\n";
     741              : #endif
     742         4389 :                 if (ok && newArrivalPos != -1) {
     743              :                     // must be called here because replaceRouteEdges may also set the arrivalPos
     744           86 :                     veh.setArrivalPos(newArrivalPos);
     745              :                 }
     746              : 
     747              :             }
     748              :         } else {
     749              :             // person rerouting here
     750              :             MSTransportableRouter& router = hasReroutingDevice
     751         1470 :                                             ? MSRoutingEngine::getIntermodalRouterTT(tObject.getRNGIndex(), prohibited)
     752         1470 :                                             : MSNet::getInstance()->getIntermodalRouter(tObject.getRNGIndex(), 0, prohibited);
     753         4410 :             const bool success = router.compute(tObject.getEdge(), newEdge, tObject.getPositionOnLane(), "",
     754         1470 :                                                 rerouteDef->isVia ? newEdge->getLength() / 2. : tObject.getParameter().arrivalPos, "",
     755         1470 :                                                 tObject.getMaxSpeed(), nullptr, tObject.getVTypeParameter(), 0, now, items);
     756         1470 :             if (!rerouteDef->isVia) {
     757          700 :                 if (success) {
     758         1400 :                     for (const MSTransportableRouter::TripItem& it : items) {
     759          700 :                         if (!it.edges.empty() && !edges.empty() && edges.back() == it.edges.front()) {
     760              :                             edges.pop_back();
     761              :                         }
     762          700 :                         edges.insert(edges.end(), std::make_move_iterator(it.edges.begin()), std::make_move_iterator(it.edges.end()));
     763          700 :                         if (!edges.empty()) {
     764          700 :                             static_cast<MSPerson&>(tObject).replaceWalk(edges, tObject.getPositionOnLane(), 0, 1);
     765              :                         }
     766              :                     }
     767              :                 } else {
     768              :                     // maybe the pedestrian model still finds a way (JuPedSim)
     769            0 :                     static_cast<MSPerson&>(tObject).replaceWalk({tObject.getEdge(), newEdge}, tObject.getPositionOnLane(), 0, 1);
     770              :                 }
     771              :             }
     772              :         }
     773         5859 :         if (!prohibited.empty()) {
     774         1767 :             resetClosedEdges(hasReroutingDevice, tObject);
     775              :         }
     776              :     }
     777              :     // it was only a via so calculate the remaining part
     778         5936 :     if (rerouteDef->isVia) {
     779          770 :         if (tObject.isVehicle()) {
     780              :             SUMOVehicle& veh = static_cast<SUMOVehicle&>(tObject);
     781            0 :             if (!edges.empty()) {
     782              :                 edges.pop_back();
     783              :             }
     784              :             MSVehicleRouter& router = hasReroutingDevice
     785            0 :                                       ? MSRoutingEngine::getRouterTT(veh.getRNGIndex(), veh.getVClass(), prohibited)
     786            0 :                                       : MSNet::getInstance()->getRouterTT(veh.getRNGIndex(), prohibited);
     787            0 :             router.compute(newEdge, lastEdge, &veh, now, edges);
     788            0 :             const double routeCost = router.recomputeCosts(edges, &veh, now);
     789              :             hasReroutingDevice
     790            0 :             ? MSRoutingEngine::getRouterTT(veh.getRNGIndex(), veh.getVClass())
     791            0 :             : MSNet::getInstance()->getRouterTT(veh.getRNGIndex()); // reset closed edges
     792            0 :             const bool useNewRoute = veh.replaceRouteEdges(edges, routeCost, 0, getID());
     793              : #ifdef DEBUG_REROUTER
     794              :             if (DEBUGCOND(tObject)) std::cout << "   rerouting:  newDest=" << newEdge->getID()
     795              :                                                   << " newEdges=" << toString(edges)
     796              :                                                   << " useNewRoute=" << useNewRoute << " newArrivalPos=" << newArrivalPos << " numClosed=" << rerouteDef->closed.size()
     797              :                                                   << " destUnreachable=" << destUnreachable << " containsClosed=" << veh.getRoute().containsAnyOf(rerouteDef->getClosedEdges()) << "\n";
     798              : #endif
     799            0 :             if (useNewRoute && newArrivalPos != -1) {
     800              :                 // must be called here because replaceRouteEdges may also set the arrivalPos
     801            0 :                 veh.setArrivalPos(newArrivalPos);
     802              :             }
     803              :         } else {
     804              :             // person rerouting here
     805          770 :             bool success = !items.empty();
     806          770 :             if (success) {
     807              :                 MSTransportableRouter& router = hasReroutingDevice
     808          770 :                                                 ? MSRoutingEngine::getIntermodalRouterTT(tObject.getRNGIndex(), prohibited)
     809          770 :                                                 : MSNet::getInstance()->getIntermodalRouter(tObject.getRNGIndex(), 0, prohibited);
     810         2310 :                 success = router.compute(newEdge, lastEdge, newEdge->getLength() / 2., "",
     811          770 :                                          tObject.getParameter().arrivalPos, "",
     812          770 :                                          tObject.getMaxSpeed(), nullptr, tObject.getVTypeParameter(), 0, now, items);
     813              :             }
     814          770 :             if (success) {
     815         2310 :                 for (const MSTransportableRouter::TripItem& it : items) {
     816         1540 :                     if (!it.edges.empty() && !edges.empty() && edges.back() == it.edges.front()) {
     817              :                         edges.pop_back();
     818              :                     }
     819         1540 :                     edges.insert(edges.end(), std::make_move_iterator(it.edges.begin()), std::make_move_iterator(it.edges.end()));
     820              :                 }
     821          770 :                 if (!edges.empty()) {
     822          770 :                     static_cast<MSPerson&>(tObject).replaceWalk(edges, tObject.getPositionOnLane(), 0, 1);
     823              :                 }
     824              :             } else {
     825              :                 // maybe the pedestrian model still finds a way (JuPedSim)
     826            3 :                 static_cast<MSPerson&>(tObject).replaceWalk({tObject.getEdge(), newEdge, lastEdge}, tObject.getPositionOnLane(), 0, 1);
     827              :             }
     828              :         }
     829          770 :         if (!prohibited.empty()) {
     830            0 :             resetClosedEdges(hasReroutingDevice, tObject);
     831              :         }
     832              :     }
     833              :     return false; // XXX another interval could appear later but we would have to track whether the currenty interval was already used
     834         5948 : }
     835              : 
     836              : 
     837              : void
     838            1 : MSTriggeredRerouter::setUserMode(bool val) {
     839            1 :     myAmInUserMode = val;
     840            1 : }
     841              : 
     842              : 
     843              : void
     844            1 : MSTriggeredRerouter::setUserUsageProbability(double prob) {
     845            1 :     myUserProbability = prob;
     846            1 : }
     847              : 
     848              : 
     849              : bool
     850            0 : MSTriggeredRerouter::inUserMode() const {
     851            0 :     return myAmInUserMode;
     852              : }
     853              : 
     854              : 
     855              : double
     856         5964 : MSTriggeredRerouter::getProbability() const {
     857         5964 :     return myAmInUserMode ? myUserProbability : myProbability;
     858              : }
     859              : 
     860              : 
     861              : double
     862            0 : MSTriggeredRerouter::getUserProbability() const {
     863            0 :     return myUserProbability;
     864              : }
     865              : 
     866              : 
     867              : double
     868        96484 : MSTriggeredRerouter::getStoppingPlaceOccupancy(MSStoppingPlace* sp, const SUMOVehicle* veh) {
     869        96484 :     return (double)(sp->getElement() == SUMO_TAG_PARKING_AREA
     870        96448 :                     ? dynamic_cast<MSParkingArea*>(sp)->getOccupancyIncludingRemoteReservations(veh)
     871           36 :                     : sp->getStoppedVehicles().size());
     872              : }
     873              : 
     874              : 
     875              : double
     876        93757 : MSTriggeredRerouter::getLastStepStoppingPlaceOccupancy(MSStoppingPlace* sp, const SUMOVehicle* veh) {
     877        93757 :     return (double)(sp->getElement() == SUMO_TAG_PARKING_AREA
     878        93721 :                     ? dynamic_cast<MSParkingArea*>(sp)->getLastStepOccupancyIncludingRemoteReservations(veh)
     879           36 :                     : sp->getStoppedVehicles().size());
     880              : }
     881              : 
     882              : 
     883              : double
     884       275916 : MSTriggeredRerouter::getStoppingPlaceCapacity(MSStoppingPlace* sp) {
     885              :     if (myBlockedStoppingPlaces.count(sp) == 0) {
     886              :         return (double)(sp->getElement() == SUMO_TAG_PARKING_AREA
     887       275900 :                         ? dynamic_cast<MSParkingArea*>(sp)->getCapacity()
     888              :                         // assume only one vehicle at a time (for stationReroute)
     889              :                         : 1.);
     890              :     } else {
     891              :         return 0.;
     892              :     }
     893              : }
     894              : 
     895              : 
     896              : void
     897        89206 : MSTriggeredRerouter::rememberBlockedStoppingPlace(SUMOVehicle& veh, const MSStoppingPlace* parkingArea, bool blocked) {
     898        89206 :     veh.rememberBlockedParkingArea(parkingArea, blocked);
     899        89206 : }
     900              : 
     901              : 
     902              : void
     903       131724 : MSTriggeredRerouter::rememberStoppingPlaceScore(SUMOVehicle& veh, MSStoppingPlace* parkingArea, const std::string& score) {
     904       131724 :     veh.rememberParkingAreaScore(parkingArea, score);
     905       131724 : }
     906              : 
     907              : 
     908              : void
     909        29564 : MSTriggeredRerouter::resetStoppingPlaceScores(SUMOVehicle& veh) {
     910        29564 :     veh.resetParkingAreaScores();
     911        29564 : }
     912              : 
     913              : 
     914              : SUMOTime
     915        71557 : MSTriggeredRerouter::sawBlockedStoppingPlace(SUMOVehicle& veh, MSStoppingPlace* parkingArea, bool local) {
     916        71557 :     return veh.sawBlockedParkingArea(parkingArea, local);
     917              : }
     918              : 
     919              : 
     920              : int
     921        68516 : MSTriggeredRerouter::getNumberStoppingPlaceReroutes(SUMOVehicle& veh) {
     922        68516 :     return veh.getNumberParkingReroutes();
     923              : }
     924              : 
     925              : 
     926              : void
     927        29564 : MSTriggeredRerouter::setNumberStoppingPlaceReroutes(SUMOVehicle& veh, int value) {
     928        29564 :     veh.setNumberParkingReroutes(value);
     929        29564 : }
     930              : 
     931              : 
     932              : MSParkingArea*
     933       103935 : MSTriggeredRerouter::rerouteParkingArea(const MSTriggeredRerouter::RerouteInterval* rerouteDef,
     934              :                                         SUMOVehicle& veh, bool& newDestination, ConstMSEdgeVector& newRoute) {
     935       103935 :     MSStoppingPlace* destStoppingPlace = veh.getNextParkingArea();
     936       103935 :     if (destStoppingPlace == nullptr) {
     937              :         // not driving towards the right type of stop
     938              :         return nullptr;
     939              :     }
     940              :     std::vector<StoppingPlaceVisible> parks;
     941       295075 :     for (auto cand : rerouteDef->parkProbs.getVals()) {
     942       201230 :         if (cand.first->accepts(&veh)) {
     943       200550 :             parks.push_back(cand);
     944              :         }
     945              :     }
     946              :     StoppingPlaceParamMap_t addInput = {};
     947       187690 :     return dynamic_cast<MSParkingArea*>(rerouteStoppingPlace(destStoppingPlace, parks, rerouteDef->parkProbs.getProbs(), veh, newDestination, newRoute, addInput, rerouteDef->getClosed()));
     948        93845 : }
     949              : 
     950              : 
     951              : std::pair<const SUMOVehicle*, MSRailSignal*>
     952          183 : MSTriggeredRerouter::overtakingTrain(const SUMOVehicle& veh,
     953              :                                      ConstMSEdgeVector::const_iterator mainStart,
     954              :                                      const OvertakeLocation& oloc,
     955              :                                      double& netSaving) {
     956          183 :     const ConstMSEdgeVector& route = veh.getRoute().getEdges();
     957              :     const MSEdgeVector& main = oloc.main;
     958          183 :     const double vMax = veh.getMaxSpeed();
     959          366 :     const double prio = veh.getFloatParam(toString(SUMO_TAG_OVERTAKING_REROUTE) + ".prio", false, DEFAULT_PRIO_OVERTAKEN, false);
     960          183 :     MSVehicleControl& c = MSNet::getInstance()->getVehicleControl();
     961          437 :     for (MSVehicleControl::constVehIt it_veh = c.loadedVehBegin(); it_veh != c.loadedVehEnd(); ++it_veh) {
     962          307 :         const MSBaseVehicle* veh2 = dynamic_cast<const MSBaseVehicle*>((*it_veh).second);
     963          307 :         if (veh2->isOnRoad() && veh2->getMaxSpeed() > vMax) {
     964           93 :             const double arrivalDelay = veh2->getStopArrivalDelay();
     965          182 :             const double delay = MAX2(veh2->getStopDelay(), arrivalDelay == INVALID_DOUBLE ? 0 : arrivalDelay);
     966          279 :             if (delay > veh2->getFloatParam(toString(SUMO_TAG_OVERTAKING_REROUTE) + ".maxDelay", false, DEFAULT_MAXDELAY, false)) {
     967              :                 continue;
     968              :             }
     969           89 :             const ConstMSEdgeVector& route2 = veh2->getRoute().getEdges();
     970              :             auto itOnMain2 = route2.end();
     971              :             int mainIndex = 0;
     972          110 :             for (const MSEdge* m : main) {
     973          105 :                 itOnMain2 = std::find(veh2->getCurrentRouteEdge(), route2.end(), m);
     974          105 :                 if (itOnMain2 != route2.end()) {
     975              :                     break;
     976              :                 }
     977           21 :                 mainIndex++;
     978              :             }
     979           89 :             if (itOnMain2 != route2.end() && itOnMain2 > veh2->getCurrentRouteEdge()) {
     980              :                 auto itOnMain = mainStart + mainIndex;
     981              :                 double timeToMain = 0;
     982          371 :                 for (auto it = veh.getCurrentRouteEdge(); it != itOnMain; it++) {
     983          290 :                     timeToMain += (*it)->getMinimumTravelTime(&veh);
     984              :                 }
     985              :                 // veh2 may be anywhere on the current edge so we have to discount
     986           81 :                 double timeToMain2 = -veh2->getEdge()->getMinimumTravelTime(veh2) * veh2->getPositionOnLane() / veh2->getEdge()->getLength();
     987              :                 double timeToLastSignal2 = timeToMain2;
     988          562 :                 for (auto it = veh2->getCurrentRouteEdge(); it != itOnMain2; it++) {
     989          481 :                     timeToMain2 += (*it)->getMinimumTravelTime(veh2);
     990          481 :                     auto signal = getRailSignal(*it);
     991          481 :                     if (signal) {
     992              :                         timeToLastSignal2 = timeToMain2;
     993              : #ifdef DEBUG_OVERTAKING
     994              :                         std::cout << "   lastBeforeMain2 " << signal->getID() << "\n";
     995              : #endif
     996              :                     }
     997              :                 }
     998              :                 double exitMainTime = timeToMain;
     999              :                 double exitMainBlockTime2 = timeToMain2;
    1000              :                 double commonTime = 0;
    1001              :                 double commonTime2 = 0;
    1002              :                 int nCommon = 0;
    1003              :                 auto exitMain2 = itOnMain2;
    1004              :                 const MSRailSignal* firstAfterMain = nullptr;
    1005              :                 const MSEdge* common = nullptr;
    1006           81 :                 double vMinCommon = (*itOnMain)->getVehicleMaxSpeed(&veh);
    1007           81 :                 double vMinCommon2 = (*itOnMain2)->getVehicleMaxSpeed(veh2);
    1008              :                 while (itOnMain2 != route2.end()
    1009          794 :                         && itOnMain != route.end()
    1010         1657 :                         && *itOnMain == *itOnMain2) {
    1011              :                     common = *itOnMain;
    1012          785 :                     commonTime += common->getMinimumTravelTime(&veh);
    1013          785 :                     commonTime2 += common->getMinimumTravelTime(veh2);
    1014          785 :                     vMinCommon = MIN2(vMinCommon, common->getVehicleMaxSpeed(&veh));
    1015          785 :                     vMinCommon2 = MIN2(vMinCommon2, common->getVehicleMaxSpeed(veh2));
    1016          785 :                     const bool onMain = nCommon < (int)main.size() - mainIndex;
    1017          785 :                     if (onMain) {
    1018          240 :                         exitMainTime = timeToMain + commonTime;
    1019              :                     }
    1020          785 :                     if (firstAfterMain == nullptr) {
    1021          480 :                         exitMainBlockTime2 = timeToMain2 + commonTime2;
    1022              :                     }
    1023          785 :                     auto signal = getRailSignal(common);
    1024          785 :                     if (signal) {
    1025          318 :                         if (!onMain && firstAfterMain == nullptr) {
    1026              :                             firstAfterMain = signal;
    1027              : #ifdef DEBUG_OVERTAKING
    1028              :                             std::cout << "   firstAfterMain " << signal->getID() << "\n";
    1029              : #endif
    1030              :                         }
    1031              :                     }
    1032          785 :                     nCommon++;
    1033              :                     itOnMain++;
    1034              :                     itOnMain2++;
    1035              :                 }
    1036           81 :                 const double vMaxLast = common->getVehicleMaxSpeed(&veh);
    1037           81 :                 const double vMaxLast2 = common->getVehicleMaxSpeed(veh2);
    1038           81 :                 commonTime += veh.getLength() / vMaxLast;
    1039           81 :                 exitMainBlockTime2 += veh2->getLength() / vMaxLast2;
    1040           81 :                 exitMain2 += MIN2(nCommon, (int)main.size() - mainIndex);
    1041           81 :                 double timeLoss2 = MAX2(0.0, timeToMain + veh.getLength() / oloc.siding.front()->getVehicleMaxSpeed(&veh) - timeToLastSignal2);
    1042           81 :                 const double saving = timeToMain + commonTime - (timeToMain2 + commonTime2) - timeLoss2;
    1043           81 :                 const double loss = exitMainBlockTime2 - exitMainTime;
    1044          162 :                 const double prio2 = veh2->getFloatParam(toString(SUMO_TAG_OVERTAKING_REROUTE) + ".prio", false, DEFAULT_PRIO_OVERTAKER, false);
    1045              :                 // losses from acceleration after stopping at a signal
    1046           81 :                 const double accelTimeLoss = loss > 0 ? 0.5 * vMinCommon / veh.getVehicleType().getCarFollowModel().getMaxAccel() : 0;
    1047           81 :                 const double accelTimeLoss2 = timeLoss2 > 0 ? 0.5 * vMinCommon2 / veh2->getVehicleType().getCarFollowModel().getMaxAccel() : 0;
    1048           81 :                 netSaving = prio2 * (saving - accelTimeLoss2) - prio * (loss + accelTimeLoss);
    1049              : #ifdef DEBUG_OVERTAKING
    1050              :                 std::cout << SIMTIME << " veh=" << veh.getID() << " veh2=" << veh2->getID()
    1051              :                           << " sidingStart=" << oloc.siding.front()->getID()
    1052              :                           << " ttm=" << timeToMain << " ttm2=" << timeToMain2
    1053              :                           << " nCommon=" << nCommon << " cT=" << commonTime << " cT2=" << commonTime2
    1054              :                           << " em=" << exitMainTime << " emb2=" << exitMainBlockTime2
    1055              :                           << " ttls2=" << timeToLastSignal2
    1056              :                           << " saving=" << saving << " loss=" << loss
    1057              :                           << " atl=" << accelTimeLoss << " atl2=" << accelTimeLoss2 << " tl2=" << timeLoss2
    1058              :                           << " prio=" << prio << " prio2=" << prio2 << " netSaving=" << netSaving << "\n";
    1059              : #endif
    1060           81 :                 if (netSaving > oloc.minSaving) {
    1061           53 :                     MSRailSignal* s = findSignal(veh2->getCurrentRouteEdge(), exitMain2);
    1062           53 :                     if (s != nullptr) {
    1063           53 :                         return std::make_pair(veh2, s);
    1064              :                     }
    1065              :                 }
    1066              :             }
    1067              :         }
    1068              :     }
    1069          130 :     return std::make_pair(nullptr, nullptr);
    1070              : }
    1071              : 
    1072              : 
    1073              : void
    1074           12 : MSTriggeredRerouter::checkStopSwitch(MSBaseVehicle& ego, const MSTriggeredRerouter::RerouteInterval* def) {
    1075              :     myBlockedStoppingPlaces.clear();
    1076              : #ifdef DEBUG_REROUTER
    1077              :     std::cout << SIMTIME << " " << getID() << " ego=" << ego.getID() << "\n";
    1078              : #endif
    1079           12 :     if (!ego.hasStops()) {
    1080            0 :         return;
    1081              :     }
    1082           12 :     const MSStop& stop = ego.getNextStop();
    1083           12 :     if (stop.reached || stop.joinTriggered || (stop.pars.arrival < 0 && stop.pars.until < 0)) {
    1084              :         return;
    1085              :     }
    1086           12 :     MSStoppingPlace* cur = nullptr;
    1087           24 :     for (MSStoppingPlace* sp : stop.getPlaces()) {
    1088           12 :         for (auto item : def->stopAlternatives) {
    1089           12 :             if (sp == item.first) {
    1090           12 :                 cur = sp;
    1091           12 :                 break;
    1092              :             }
    1093              :         }
    1094           12 :     }
    1095           12 :     if (cur == nullptr) {
    1096              :         return;
    1097              :     }
    1098           12 :     std::vector<const SUMOVehicle*> stopped = cur->getStoppedVehicles();
    1099              : #ifdef DEBUG_REROUTER
    1100              :     std::cout << SIMTIME << " " << getID() << " ego=" << ego.getID() << " stopped=" << toString(stopped) << "\n";
    1101              : #endif
    1102              :     SUMOTime stoppedDuration = -1;
    1103           12 :     if (stopped.empty()) {
    1104              :         /// look upstream for vehicles that stop on this lane before ego arrives
    1105            8 :         const MSLane& stopLane = cur->getLane();
    1106            8 :         MSVehicleControl& c = MSNet::getInstance()->getVehicleControl();
    1107           25 :         for (MSVehicleControl::constVehIt it_veh = c.loadedVehBegin(); it_veh != c.loadedVehEnd(); ++it_veh) {
    1108           17 :             const MSBaseVehicle* veh = dynamic_cast<const MSBaseVehicle*>((*it_veh).second);
    1109           17 :             if (veh->isOnRoad() && veh->hasStops()) {
    1110           17 :                 const MSStop& vehStop = veh->getNextStop();
    1111           17 :                 if (vehStop.pars.lane == stopLane.getID()) {
    1112              :                     myBlockedStoppingPlaces.insert(cur);
    1113           10 :                     if (veh->isStopped()) {
    1114              :                         // stopped somewhere else on the same lane
    1115            2 :                         stoppedDuration = MAX3((SUMOTime)0, stoppedDuration, veh->getStopDuration());
    1116              :                     } else {
    1117            8 :                         std::pair<double, double> timeDist = veh->estimateTimeToNextStop();
    1118            8 :                         SUMOTime timeTo = TIME2STEPS(timeDist.first);
    1119            8 :                         stoppedDuration = MAX3((SUMOTime)0, stoppedDuration, timeTo + vehStop.getMinDuration(SIMSTEP + timeTo));
    1120              :                     }
    1121              :                 }
    1122              :             }
    1123              :         }
    1124              :     } else {
    1125              :         stoppedDuration = 0;
    1126            8 :         for (const SUMOVehicle* veh : cur->getStoppedVehicles()) {
    1127            4 :             stoppedDuration = MAX2(stoppedDuration, veh->getStopDuration());
    1128            4 :         }
    1129              :     }
    1130           12 :     if (stoppedDuration < 0) {
    1131              :         return;
    1132              :     }
    1133              :     /// @todo: consider time for conflict veh to leave the block
    1134           12 :     const SUMOTime stopFree = SIMSTEP + stoppedDuration;
    1135           12 :     const SUMOTime scheduledArrival = stop.pars.arrival >= 0 ? stop.pars.arrival : stop.pars.until - stop.pars.duration;
    1136              : #ifdef DEBUG_REROUTER
    1137              :     std::cout << SIMTIME << " " << getID() << " ego=" << ego.getID() << " stopFree=" << stopFree << " scheduledArrival=" << time2string(scheduledArrival) << "\n";
    1138              : #endif
    1139           12 :     if (stopFree < scheduledArrival) {
    1140              :         // no conflict according to the schedule
    1141              :         return;
    1142              :     }
    1143           12 :     const SUMOTime estimatedArrival = SIMSTEP + (stop.pars.arrival >= 0
    1144           12 :                                       ? TIME2STEPS(ego.getStopArrivalDelay())
    1145           16 :                                       : TIME2STEPS(ego.getStopDelay()) - stop.pars.duration);
    1146              : #ifdef DEBUG_REROUTER
    1147              :     std::cout << SIMTIME << " " << getID() << " ego=" << ego.getID() << " stopFree=" << stopFree << " estimatedArrival=" << time2string(estimatedArrival) << "\n";
    1148              : #endif
    1149           12 :     if (stopFree < estimatedArrival) {
    1150              :         // no conflict when considering current delay
    1151              :         return;
    1152              :     }
    1153           12 :     const std::vector<double> probs(def->stopAlternatives.size(), 1.);
    1154              :     StoppingPlaceParamMap_t scores = {};
    1155              :     bool newDestination;
    1156              :     ConstMSEdgeVector newRoute;
    1157              :     // @todo: consider future conflicts caused by rerouting
    1158              :     // @todo: reject alternatives with large detour
    1159           12 :     const MSStoppingPlace* alternative = rerouteStoppingPlace(nullptr, def->stopAlternatives, probs, ego, newDestination, newRoute, scores);
    1160              : #ifdef DEBUG_REROUTER
    1161              :     std::cout << SIMTIME << " " << getID() << " ego=" << ego.getID() << " alternative=" << Named::getIDSecure(alternative) << "\n";
    1162              : #endif
    1163           12 :     if (alternative != nullptr) {
    1164              :         // @todo adapt plans of any riders
    1165              :         //for (MSTransportable* p : ego.getPersons()) {
    1166              :         //    p->rerouteParkingArea(ego.getNextParkingArea(), newParkingArea);
    1167              :         //}
    1168              : 
    1169           12 :         if (newDestination && ego.getParameter().arrivalPosProcedure != ArrivalPosDefinition::DEFAULT) {
    1170              :             // update arrival parameters
    1171            0 :             SUMOVehicleParameter* newParameter = new SUMOVehicleParameter();
    1172            0 :             *newParameter = ego.getParameter();
    1173            0 :             newParameter->arrivalPosProcedure = ArrivalPosDefinition::GIVEN;
    1174            0 :             newParameter->arrivalPos = alternative->getEndLanePosition();
    1175            0 :             ego.replaceParameter(newParameter);
    1176              :         }
    1177              : 
    1178           12 :         SUMOVehicleParameter::Stop newStop = stop.pars;
    1179           12 :         newStop.lane = alternative->getLane().getID();
    1180           12 :         newStop.startPos = alternative->getBeginLanePosition();
    1181           12 :         newStop.endPos = alternative->getEndLanePosition();
    1182           12 :         switch (alternative->getElement()) {
    1183            0 :             case SUMO_TAG_PARKING_AREA:
    1184              :                 newStop.parkingarea = alternative->getID();
    1185              :                 break;
    1186            0 :             case SUMO_TAG_CONTAINER_STOP:
    1187              :                 newStop.containerstop = alternative->getID();
    1188              :                 break;
    1189            0 :             case SUMO_TAG_CHARGING_STATION:
    1190              :                 newStop.chargingStation = alternative->getID();
    1191              :                 break;
    1192            0 :             case SUMO_TAG_OVERHEAD_WIRE_SEGMENT:
    1193              :                 newStop.overheadWireSegment = alternative->getID();
    1194              :                 break;
    1195           12 :             case SUMO_TAG_BUS_STOP:
    1196              :             case SUMO_TAG_TRAIN_STOP:
    1197              :             default:
    1198              :                 newStop.busstop = alternative->getID();
    1199              :         }
    1200              :         std::string errorMsg;
    1201           24 :         if (!ego.replaceStop(0, newStop, getID() + ":" + toString(SUMO_TAG_STATION_REROUTE), false, errorMsg)) {
    1202            0 :             WRITE_WARNING("Vehicle '" + ego.getID() + "' at rerouter '" + getID()
    1203              :                           + "' could not perform stationReroute to '" + alternative->getID()
    1204              :                           + "' reason=" + errorMsg + ", time=" + time2string(MSNet::getInstance()->getCurrentTimeStep()) + ".");
    1205              :         }
    1206           12 :     }
    1207           24 : }
    1208              : 
    1209              : 
    1210              : MSRailSignal*
    1211          152 : MSTriggeredRerouter::findSignal(ConstMSEdgeVector::const_iterator begin, ConstMSEdgeVector::const_iterator end) {
    1212          152 :     auto it = end;
    1213              :     do {
    1214              :         it--;
    1215          304 :         auto signal = getRailSignal(*it);
    1216          304 :         if (signal != nullptr) {
    1217          152 :             return signal;
    1218              :         }
    1219          152 :     } while (it != begin);
    1220              :     return nullptr;
    1221              : }
    1222              : 
    1223              : 
    1224              : MSRailSignal*
    1225         1570 : MSTriggeredRerouter::getRailSignal(const MSEdge* edge) {
    1226         1570 :     if (edge->getToJunction()->getType() == SumoXMLNodeType::RAIL_SIGNAL) {
    1227          732 :         for (const MSLink* link : edge->getLanes().front()->getLinkCont()) {
    1228          732 :             if (link->getTLLogic() != nullptr) {
    1229          732 :                 return dynamic_cast<MSRailSignal*>(const_cast<MSTrafficLightLogic*>(link->getTLLogic()));
    1230              :             }
    1231              :         }
    1232              :     }
    1233              :     return nullptr;
    1234              : }
    1235              : 
    1236              : bool
    1237      1193712 : MSTriggeredRerouter::applies(const SUMOTrafficObject& obj) const {
    1238      1193712 :     if (myVehicleTypes.empty() || myVehicleTypes.count(obj.getVehicleType().getOriginalID()) > 0) {
    1239      1193642 :         return true;
    1240              :     } else {
    1241          140 :         std::set<std::string> vTypeDists = MSNet::getInstance()->getVehicleControl().getVTypeDistributionMembership(obj.getVehicleType().getOriginalID());
    1242           70 :         for (auto vTypeDist : vTypeDists) {
    1243              :             if (myVehicleTypes.count(vTypeDist) > 0) {
    1244              :                 return true;
    1245              :             }
    1246              :         }
    1247           70 :         return false;
    1248              :     }
    1249              : }
    1250              : 
    1251              : 
    1252              : bool
    1253       130876 : MSTriggeredRerouter::affected(const std::set<SUMOTrafficObject::NumericalID>& edgeIndices, const MSEdgeVector& closed) {
    1254       149177 :     for (const MSEdge* const e : closed) {
    1255        69807 :         if (edgeIndices.count(e->getNumericalID()) > 0) {
    1256              :             return true;
    1257              :         }
    1258              :     }
    1259              :     return false;
    1260              : }
    1261              : 
    1262              : 
    1263              : void
    1264        25459 : MSTriggeredRerouter::checkParkingRerouteConsistency() {
    1265              :     // if a parkingArea is a rerouting target, it should generally have a
    1266              :     // rerouter on its edge or vehicles will be stuck there once it's full.
    1267              :     // The user should receive a Warning in this case
    1268              :     std::set<MSEdge*> parkingRerouterEdges;
    1269              :     std::map<MSParkingArea*, std::string, ComparatorIdLess> targetedParkingArea; // paID -> targetingRerouter
    1270        29450 :     for (const auto& rr : myInstances) {
    1271              :         bool hasParkingReroute = false;
    1272         7839 :         for (const RerouteInterval& interval : rr.second->myIntervals) {
    1273         3848 :             if (interval.parkProbs.getOverallProb() > 0) {
    1274              :                 hasParkingReroute = true;
    1275        15834 :                 for (const StoppingPlaceVisible& pav : interval.parkProbs.getVals()) {
    1276        27162 :                     targetedParkingArea[dynamic_cast<MSParkingArea*>(pav.first)] = rr.first;
    1277              :                 }
    1278              :             }
    1279              :         }
    1280         3991 :         if (hasParkingReroute) {
    1281         2253 :             parkingRerouterEdges.insert(rr.second->myEdges.begin(), rr.second->myEdges.end());
    1282              :         }
    1283              :     }
    1284        28354 :     for (const auto& item : targetedParkingArea) {
    1285         2895 :         if (parkingRerouterEdges.count(&item.first->getLane().getEdge()) == 0) {
    1286         1312 :             WRITE_WARNINGF(TL("ParkingArea '%' is targeted by rerouter '%' but doesn't have its own rerouter. This may cause parking search to abort."),
    1287              :                            item.first->getID(), item.second);
    1288              :         }
    1289              :     }
    1290        25459 : }
    1291              : 
    1292              : 
    1293              : void
    1294        30592 : MSTriggeredRerouter::resetClosedEdges(bool hasReroutingDevice, const SUMOTrafficObject& o) {
    1295              :     // getRouterTT without prohibitions removes previous prohibitions
    1296        30592 :     if (o.isVehicle()) {
    1297              :         hasReroutingDevice
    1298        61184 :         ? MSRoutingEngine::getRouterTT(o.getRNGIndex(), o.getVClass())
    1299        48171 :         : MSNet::getInstance()->getRouterTT(o.getRNGIndex());
    1300              :     } else {
    1301              :         hasReroutingDevice
    1302            0 :         ? MSRoutingEngine::getIntermodalRouterTT(o.getRNGIndex())
    1303            0 :         : MSNet::getInstance()->getIntermodalRouter(o.getRNGIndex(), 0);
    1304              :     }
    1305        30592 : }
    1306              : 
    1307              : /****************************************************************************/
        

Generated by: LCOV version 2.0-1