LCOV - code coverage report
Current view: top level - src/microsim/trigger - MSTriggeredRerouter.cpp (source / functions) Coverage Total Hit
Test: lcov.info Lines: 90.6 % 606 549
Test Date: 2026-06-15 15:46:12 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         4072 : MSTriggeredRerouter::MSTriggeredRerouter(const std::string& id,
      88              :         const MSEdgeVector& edges, double prob, bool off, bool optional,
      89         4072 :         SUMOTime timeThreshold, const std::string& vTypes, const Position& pos, const double radius) :
      90              :     Named(id),
      91              :     MSMoveReminder(id),
      92              :     MSStoppingPlaceRerouter("parking"),
      93         4072 :     myEdges(edges),
      94         4072 :     myProbability(prob),
      95         4072 :     myUserProbability(prob),
      96         4072 :     myAmInUserMode(false),
      97         4072 :     myAmOptional(optional),
      98         4072 :     myPosition(pos),
      99         4072 :     myRadius(radius),
     100         4072 :     myTimeThreshold(timeThreshold),
     101        12216 :     myHaveParkProbs(false) {
     102         4072 :     myInstances[id] = this;
     103              :     // build actors
     104         9458 :     for (const MSEdge* const e : edges) {
     105         5386 :         if (MSGlobals::gUseMesoSim) {
     106          789 :             MSGlobals::gMesoNet->getSegmentForEdge(*e)->addDetector(this);
     107              :         }
     108        11439 :         for (MSLane* const lane : e->getLanes()) {
     109         6053 :             lane->addMoveReminder(this);
     110              :         }
     111              :     }
     112         4072 :     if (off) {
     113            1 :         setUserMode(true);
     114            1 :         setUserUsageProbability(0);
     115              :     }
     116         8144 :     const std::vector<std::string> vt = StringTokenizer(vTypes).getVector();
     117              :     myVehicleTypes.insert(vt.begin(), vt.end());
     118              :     if (myPosition == Position::INVALID) {
     119         3610 :         myPosition = edges.front()->getLanes()[0]->getShape()[0];
     120              :     }
     121         4072 : }
     122              : 
     123              : 
     124         7366 : MSTriggeredRerouter::~MSTriggeredRerouter() {
     125              :     myInstances.erase(getID());
     126        11434 : }
     127              : 
     128              : 
     129              : // ------------ loading begin
     130              : void
     131        18939 : MSTriggeredRerouter::myStartElement(int element,
     132              :                                     const SUMOSAXAttributes& attrs) {
     133        18939 :     if (element == SUMO_TAG_INTERVAL) {
     134         3929 :         bool ok = true;
     135         3929 :         myParsedRerouteInterval = RerouteInterval();
     136         3929 :         myParsedRerouteInterval.begin = attrs.getOptSUMOTimeReporting(SUMO_ATTR_BEGIN, nullptr, ok, -1);
     137         3929 :         myParsedRerouteInterval.end = attrs.getOptSUMOTimeReporting(SUMO_ATTR_END, nullptr, ok, SUMOTime_MAX);
     138         3929 :         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        18933 :     if (element == SUMO_TAG_DEST_PROB_REROUTE) {
     145              :         // by giving probabilities of new destinations
     146              :         // get the destination edge
     147          268 :         std::string dest = attrs.getStringSecure(SUMO_ATTR_ID, "");
     148          268 :         if (dest == "") {
     149            0 :             throw ProcessError(TLF("rerouter '%': destProbReroute has no destination edge id.", getID()));
     150              :         }
     151          268 :         MSEdge* to = MSEdge::dictionary(dest);
     152          268 :         if (to == nullptr) {
     153          111 :             if (dest == "keepDestination") {
     154              :                 to = &mySpecialDest_keepDestination;
     155           83 :             } 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          268 :         bool ok = true;
     163          268 :         double prob = attrs.getOpt<double>(SUMO_ATTR_PROB, getID().c_str(), ok, 1.);
     164          268 :         if (!ok) {
     165            0 :             throw ProcessError();
     166              :         }
     167          268 :         if (prob < 0) {
     168            0 :             throw ProcessError(TLF("rerouter '%': Attribute 'probability' for destination '%' is negative (must not).", getID(), dest));
     169              :         }
     170              :         // add
     171          268 :         myParsedRerouteInterval.edgeProbs.add(to, prob);
     172              :     }
     173              : 
     174        18933 :     if (element == SUMO_TAG_CLOSING_REROUTE) {
     175              :         // by closing edge
     176         1121 :         const std::string& closed_id = attrs.getStringSecure(SUMO_ATTR_ID, "");
     177         1121 :         MSEdge* const closedEdge = MSEdge::dictionary(closed_id);
     178         1121 :         if (closedEdge == nullptr) {
     179            0 :             throw ProcessError(TLF("rerouter '%': Edge '%' to close is not known.", getID(), closed_id));
     180              :         }
     181              :         bool ok;
     182         1121 :         const std::string allow = attrs.getOpt<std::string>(SUMO_ATTR_ALLOW, getID().c_str(), ok, "", false);
     183         1121 :         const std::string disallow = attrs.getOpt<std::string>(SUMO_ATTR_DISALLOW, getID().c_str(), ok, "");
     184         1121 :         const SUMOTime until = attrs.getOptSUMOTimeReporting(SUMO_ATTR_UNTIL, nullptr, ok, TIME2STEPS(-1));
     185         1121 :         SVCPermissions permissions = parseVehicleClasses(allow, disallow);
     186         1121 :         myParsedRerouteInterval.closed[closedEdge] = std::make_pair(permissions, STEPS2TIME(until));
     187              :     }
     188              : 
     189        18933 :     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        18933 :     if (element == SUMO_TAG_ROUTE_PROB_REROUTE) {
     207              :         // by explicit rerouting using routes
     208              :         // check if route exists
     209          766 :         std::string routeStr = attrs.getStringSecure(SUMO_ATTR_ID, "");
     210          766 :         if (routeStr == "") {
     211            0 :             throw ProcessError(TLF("rerouter '%': routeProbReroute has no alternative route id.", getID()));
     212              :         }
     213          766 :         ConstMSRoutePtr route = MSRoute::dictionary(routeStr);
     214          766 :         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          766 :         bool ok = true;
     220          766 :         double prob = attrs.getOpt<double>(SUMO_ATTR_PROB, getID().c_str(), ok, 1.);
     221          766 :         if (!ok) {
     222            0 :             throw ProcessError();
     223              :         }
     224          766 :         if (prob < 0) {
     225            0 :             throw ProcessError(TLF("rerouter '%': Attribute 'probability' for alternative route '%' is negative (must not).", getID(), routeStr));
     226              :         }
     227              :         // add
     228         1532 :         myParsedRerouteInterval.routeProbs.add(route, prob);
     229              :     }
     230              : 
     231        18933 :     if (element == SUMO_TAG_PARKING_AREA_REROUTE) {
     232        12528 :         std::string parkingarea = attrs.getStringSecure(SUMO_ATTR_ID, "");
     233        12528 :         if (parkingarea == "") {
     234            0 :             throw ProcessError(TLF("rerouter '%': parkingAreaReroute requires a parkingArea id.", getID()));
     235              :         }
     236        12528 :         MSParkingArea* pa = static_cast<MSParkingArea*>(MSNet::getInstance()->getStoppingPlace(parkingarea, SUMO_TAG_PARKING_AREA));
     237        12528 :         if (pa == nullptr) {
     238            0 :             throw ProcessError(TLF("rerouter '%': parkingArea '%' is not known.", getID(), parkingarea));
     239              :         }
     240              :         // get the probability to reroute
     241        12528 :         bool ok = true;
     242        12528 :         const double prob = attrs.getOpt<double>(SUMO_ATTR_PROB, getID().c_str(), ok, 1.);
     243        12528 :         if (!ok) {
     244            0 :             throw ProcessError();
     245              :         }
     246        12528 :         if (prob < 0) {
     247            0 :             throw ProcessError(TLF("rerouter '%': Attribute 'probability' for parkingArea '%' is negative (must not).", getID(), parkingarea));
     248              :         }
     249        12528 :         const bool visible = attrs.getOpt<bool>(SUMO_ATTR_VISIBLE, getID().c_str(), ok, false);
     250              :         // add
     251        12528 :         myParsedRerouteInterval.parkProbs.add(std::make_pair(pa, visible), prob);
     252        12528 :         myHaveParkProbs = true;
     253              :     }
     254              : 
     255        18933 :     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        18933 :     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        18933 :     if (element == SUMO_TAG_STATION_REROUTE) {
     314              :         // for letting a train switch it's stopping place in case of conflict
     315           45 :         const std::string stopID = attrs.getStringSecure(SUMO_ATTR_ID, "");
     316           45 :         if (stopID == "") {
     317            0 :             throw ProcessError(TLF("rerouter '%': stationReroute requires a stopping place id.", getID()));
     318              :         }
     319           45 :         MSStoppingPlace* stop = MSNet::getInstance()->getStoppingPlace(stopID);
     320           45 :         if (stop == nullptr) {
     321            0 :             throw ProcessError(TLF("rerouter '%': stopping place '%' is not known.", getID(), stopID));
     322              :         }
     323           45 :         myParsedRerouteInterval.stopAlternatives.push_back(std::make_pair(stop, true));
     324              :     }
     325        18933 : }
     326              : 
     327              : 
     328              : void
     329        22999 : MSTriggeredRerouter::myEndElement(int element) {
     330        22999 :     if (element == SUMO_TAG_INTERVAL) {
     331              :         // precompute permissionsAllowAll
     332              :         bool allowAll = true;
     333         4288 :         for (const auto& entry : myParsedRerouteInterval.closed) {
     334          929 :             allowAll = allowAll && entry.second.first == SVCAll;
     335              :             if (!allowAll) {
     336              :                 break;
     337              :             }
     338              :         }
     339         3923 :         myParsedRerouteInterval.permissionsAllowAll = allowAll;
     340              : 
     341        16448 :         for (auto paVi : myParsedRerouteInterval.parkProbs.getVals()) {
     342        12525 :             dynamic_cast<MSParkingArea*>(paVi.first)->setNumAlternatives((int)myParsedRerouteInterval.parkProbs.getVals().size() - 1);
     343              :         }
     344         3923 :         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         3923 :         const SUMOTime closingBegin = myParsedRerouteInterval.begin;
     353         3923 :         const SUMOTime simBegin = string2time(OptionsCont::getOptions().getString("begin"));
     354         3923 :         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         3923 :         myIntervals.push_back(myParsedRerouteInterval);
     360         3923 :         myIntervals.back().id = (long long int)&myIntervals.back();
     361         3923 :         if (!(myParsedRerouteInterval.closed.empty() && myParsedRerouteInterval.closedLanes.empty())) {
     362         1928 :             MSNet::getInstance()->getBeginOfTimestepEvents()->addEvent(
     363          964 :                 new WrappingCommand<MSTriggeredRerouter>(this, &MSTriggeredRerouter::setPermissions), myParsedRerouteInterval.begin);
     364              :         }
     365              :     }
     366        22999 : }
     367              : 
     368              : 
     369              : // ------------ loading end
     370              : 
     371              : 
     372              : SUMOTime
     373         1123 : MSTriggeredRerouter::setPermissions(const SUMOTime currentTime) {
     374              :     bool updateVehicles = false;
     375         2289 :     for (const RerouteInterval& i : myIntervals) {
     376         1166 :         if (i.begin == currentTime && !(i.closed.empty() && i.closedLanes.empty()) /*&& i.permissions != SVCAll*/) {
     377         2031 :             for (const auto& settings : i.closed) {
     378         2179 :                 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         1097 :                     lane->setPermissions(settings.second.first, i.id);
     381              :                 }
     382         1082 :                 settings.first->rebuildAllowedLanes();
     383              :                 updateVehicles = true;
     384              :             }
     385         1098 :             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         1898 :             MSNet::getInstance()->getBeginOfTimestepEvents()->addEvent(
     391          949 :                 new WrappingCommand<MSTriggeredRerouter>(this, &MSTriggeredRerouter::setPermissions), i.end);
     392              :         }
     393         1166 :         if (i.end == currentTime && !(i.closed.empty() && i.closedLanes.empty()) /*&& i.permissions != SVCAll*/) {
     394          396 :             for (auto settings : i.closed) {
     395          389 :                 for (MSLane* lane : settings.first->getLanes()) {
     396          195 :                     lane->resetPermissions(i.id);
     397              :                     //std::cout << SIMTIME << " opening: intervalID=" << i.id << " lane=" << lane->getID() << " restore prevPerm=" << getVehicleClassNames(lane->getPermissions()) << "\n";
     398              :                 }
     399          194 :                 settings.first->rebuildAllowedLanes();
     400              :                 updateVehicles = true;
     401              :             }
     402          315 :             for (std::pair<MSLane*, SVCPermissions> settings : i.closedLanes) {
     403          113 :                 settings.first->resetPermissions(i.id);
     404          113 :                 settings.first->getEdge().rebuildAllowedLanes();
     405              :                 updateVehicles = true;
     406              :             }
     407              :         }
     408              :     }
     409         1123 :     if (updateVehicles) {
     410              :         // only vehicles on the affected lanes had their bestlanes updated so far
     411         2259 :         for (MSEdge* e : myEdges) {
     412              :             // also updates vehicles
     413         1136 :             e->rebuildAllowedTargets();
     414              :         }
     415              :     }
     416         1123 :     return 0;
     417              : }
     418              : 
     419              : 
     420              : const MSTriggeredRerouter::RerouteInterval*
     421      1199977 : MSTriggeredRerouter::getCurrentReroute(SUMOTime time, SUMOTrafficObject& obj) const {
     422      1711986 :     for (const RerouteInterval& ri : myIntervals) {
     423      1214058 :         if (ri.begin <= time && ri.end > time) {
     424              :             if (
     425              :                 // destProbReroute
     426       716559 :                 ri.edgeProbs.getOverallProb() > 0 ||
     427              :                 // routeProbReroute
     428       177932 :                 ri.routeProbs.getOverallProb() > 0 ||
     429              :                 // parkingZoneReroute
     430       787648 :                 ri.parkProbs.getOverallProb() > 0 ||
     431              :                 // stationReroute
     432              :                 ri.stopAlternatives.size() > 0) {
     433       652097 :                 return &ri;
     434              :             }
     435        67768 :             if (!ri.closed.empty() || !ri.closedLanesAffected.empty() || !ri.overtakeLocations.empty()) {
     436        67768 :                 const std::set<SUMOTrafficObject::NumericalID>& edgeIndices = obj.getUpcomingEdgeIDs();
     437       135536 :                 if (affected(edgeIndices, ri.getClosedEdges())
     438        67768 :                         || affected(edgeIndices, ri.closedLanesAffected)) {
     439        49808 :                     return &ri;
     440              :                 }
     441        17960 :                 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       318188 : MSTriggeredRerouter::getCurrentReroute(SUMOTime time) const {
     456       318216 :     for (const RerouteInterval& ri : myIntervals) {
     457       318188 :         if (ri.begin <= time && ri.end > time) {
     458       318160 :             if (ri.edgeProbs.getOverallProb() != 0 || ri.routeProbs.getOverallProb() != 0 || ri.parkProbs.getOverallProb() != 0
     459       318175 :                     || !ri.closed.empty() || !ri.closedLanesAffected.empty() || !ri.overtakeLocations.empty()) {
     460              :                 return &ri;
     461              :             }
     462              :         }
     463              :     }
     464              :     return nullptr;
     465              : }
     466              : 
     467              : 
     468              : bool
     469       675034 : MSTriggeredRerouter::notifyEnter(SUMOTrafficObject& tObject, MSMoveReminder::Notification reason, const MSLane* /* enteredLane */) {
     470       675034 :     if (myAmOptional || myRadius != std::numeric_limits<double>::max()) {
     471              :         return true;
     472              :     }
     473       674894 :     return triggerRouting(tObject, reason);
     474              : }
     475              : 
     476              : 
     477              : bool
     478       524517 : MSTriggeredRerouter::notifyMove(SUMOTrafficObject& veh, double /*oldPos*/,
     479              :                                 double /*newPos*/, double /*newSpeed*/) {
     480       524517 :     return triggerRouting(veh, NOTIFICATION_JUNCTION);
     481              : }
     482              : 
     483              : 
     484              : bool
     485        19051 : MSTriggeredRerouter::notifyLeave(SUMOTrafficObject& /*veh*/, double /*lastPos*/,
     486              :                                  MSMoveReminder::Notification reason, const MSLane* /* enteredLane */) {
     487        19051 :     return reason == NOTIFICATION_LANE_CHANGE;
     488              : }
     489              : 
     490              : 
     491              : bool
     492      1200047 : MSTriggeredRerouter::triggerRouting(SUMOTrafficObject& tObject, MSMoveReminder::Notification reason) {
     493      1200047 :     if (!applies(tObject)) {
     494              :         return false;
     495              :     }
     496      1199977 :     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      1199977 :     const SUMOTime now = MSNet::getInstance()->getCurrentTimeStep();
     501      1199977 :     const MSTriggeredRerouter::RerouteInterval* const rerouteDef = getCurrentReroute(now, tObject);
     502      1199977 :     if (rerouteDef == nullptr) {
     503              :         return true; // an active interval could appear later
     504              :     }
     505       702049 :     const double prob = myAmInUserMode ? myUserProbability : myProbability;
     506       702049 :     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       701760 :     if (myTimeThreshold > 0 && MAX2(tObject.getWaitingTime(), tObject.getWaitingTime(true)) < myTimeThreshold) {
     510              :         return true; // waiting time may be reached later
     511              :     }
     512       695323 :     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       678084 :     const bool hasReroutingDevice = tObject.getDevice(typeid(MSDevice_Routing)) != nullptr;
     517       678084 :     if (rerouteDef->closedLanes.size() > 0 && !hasReroutingDevice) {
     518              :         return true; // an active interval could appear later
     519              :     }
     520       638073 :     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       638073 :     if (rerouteDef->parkProbs.getOverallProb() > 0) {
     528              : #ifdef HAVE_FOX
     529       104905 :         ScopedLocker<> lock(myNotificationMutex, MSGlobals::gNumSimThreads > 1);
     530              : #endif
     531       104905 :         if (!tObject.isVehicle()) {
     532              :             return false;
     533              :         }
     534              :         SUMOVehicle& veh = static_cast<SUMOVehicle&>(tObject);
     535       104840 :         bool newDestination = false;
     536              :         ConstMSEdgeVector newRoute;
     537       104840 :         MSParkingArea* oldParkingArea = veh.getNextParkingArea();
     538       104840 :         MSParkingArea* newParkingArea = rerouteParkingArea(rerouteDef, veh, newDestination, newRoute);
     539       104840 :         if (newParkingArea != nullptr) {
     540              :             // adapt plans of any riders
     541        28968 :             for (MSTransportable* p : veh.getPersons()) {
     542           40 :                 p->rerouteParkingArea(oldParkingArea, newParkingArea);
     543              :             }
     544              : 
     545        28928 :             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        12861 :                     ? MSRoutingEngine::getRouterTT(veh.getRNGIndex(), veh.getVClass(), rerouteDef->getClosed())
     556        57856 :                     : MSNet::getInstance()->getRouterTT(veh.getRNGIndex(), rerouteDef->getClosed());
     557        28928 :             const double routeCost = router.recomputeCosts(newRoute, &veh, MSNet::getInstance()->getCurrentTimeStep());
     558        28928 :             ConstMSEdgeVector prevEdges(veh.getCurrentRouteEdge(), veh.getRoute().end());
     559        28928 :             resetClosedEdges(hasReroutingDevice, veh);
     560        28928 :             const double previousCost = router.recomputeCosts(prevEdges, &veh, MSNet::getInstance()->getCurrentTimeStep());
     561        28928 :             const double savings = previousCost - routeCost;
     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        28928 :             if (veh.replaceParkingArea(newParkingArea, errorMsg)) {
     569        57856 :                 veh.replaceRouteEdges(newRoute, routeCost, savings, getID() + ":" + toString(SUMO_TAG_PARKING_AREA_REROUTE), false, false, false);
     570        28928 :                 if (oldParkingArea->isReservable()) {
     571           15 :                     oldParkingArea->removeSpaceReservation(&veh);
     572              :                 }
     573        28928 :                 if (newParkingArea->isReservable()) {
     574           15 :                     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        28928 :         } else {
     582        75912 :             if (oldParkingArea && oldParkingArea->isReservable()) {
     583           15 :                 oldParkingArea->addSpaceReservation(&veh);
     584              :             }
     585              :         }
     586              :         return false;
     587       104840 :     }
     588       533168 :     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       533024 :     if (rerouteDef->stopAlternatives.size() > 0) {
     658              :         // somewhat similar to parkProbs but taking into account public transport schedule
     659           15 :         if (!tObject.isVehicle()) {
     660              :             return false;
     661              :         }
     662           15 :         checkStopSwitch(static_cast<MSBaseVehicle&>(tObject), rerouteDef);
     663              :     }
     664              :     // get rerouting params
     665       533024 :     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       533024 :     if (newRoute != nullptr) {
     668              : #ifdef DEBUG_REROUTER
     669              :         if (DEBUGCOND(tObject)) {
     670              :             std::cout << "    replacedRoute from routeDist " << newRoute->getID() << "\n";
     671              :         }
     672              : #endif
     673       526981 :         tObject.replaceRoute(newRoute, getID());
     674       526981 :         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         6043 :     const MSEdgeVector closedEdges = rerouteDef->getClosedEdges();
     680         6043 :     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         6043 :     if (closedEdges.empty() || destUnreachable || rerouteDef->isVia) {
     685         4176 :         newEdge = rerouteDef->edgeProbs.getOverallProb() > 0 ? rerouteDef->edgeProbs.get() : lastEdge;
     686              :         assert(newEdge != nullptr);
     687         4176 :         if (newEdge == &mySpecialDest_terminateRoute) {
     688              :             keepDestination = true;
     689           55 :             newEdge = tObject.getEdge();
     690           55 :             newArrivalPos = tObject.getPositionOnLane(); // instant arrival
     691         4121 :         } else if (newEdge == &mySpecialDest_keepDestination || newEdge == lastEdge) {
     692         1577 :             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         6043 :     MSEdgeVector closed = rerouteDef->getClosedEdges();
     707         6043 :     Prohibitions prohibited = rerouteDef->getClosed();
     708         7910 :     if (rerouteDef->closed.empty() || destUnreachable || rerouteDef->isVia || affected(tObject.getUpcomingEdgeIDs(), closed)) {
     709         5966 :         if (tObject.isVehicle()) {
     710              :             SUMOVehicle& veh = static_cast<SUMOVehicle&>(tObject);
     711         4496 :             ConstMSEdgeVector prevEdges = veh.getRoute().getEdges();
     712         4496 :             const bool canChangeDest = rerouteDef->edgeProbs.getOverallProb() > 0;
     713              :             MSVehicleRouter& router = hasReroutingDevice
     714         4496 :                                       ? MSRoutingEngine::getRouterTT(veh.getRNGIndex(), veh.getVClass(), prohibited)
     715         1811 :                                       : MSNet::getInstance()->getRouterTT(veh.getRNGIndex(), prohibited);
     716              :             bool ok = false;
     717              :             try {
     718         4496 :                 ok = veh.reroute(now, getID(), router, false, false, canChangeDest, newEdge);
     719           17 :             } catch (ProcessError&) {}
     720         4496 :             if (!ok && !keepDestination && canChangeDest) {
     721              :                 // destination unreachable due to closed intermediate edges. pick among alternative targets
     722           96 :                 RandomDistributor<MSEdge*> edgeProbs2 = rerouteDef->edgeProbs;
     723           96 :                 edgeProbs2.remove(const_cast<MSEdge*>(newEdge));
     724          180 :                 while (!ok && edgeProbs2.getVals().size() > 0) {
     725          124 :                     newEdge = edgeProbs2.get();
     726          124 :                     edgeProbs2.remove(const_cast<MSEdge*>(newEdge));
     727          124 :                     if (newEdge == &mySpecialDest_terminateRoute) {
     728           56 :                         newEdge = veh.getEdge();
     729           56 :                         newArrivalPos = veh.getPositionOnLane(); // instant arrival
     730           70 :                         while (veh.hasStops()) {
     731           14 :                             veh.abortNextStop();
     732              :                         }
     733              :                     }
     734          124 :                     if (newEdge == &mySpecialDest_keepDestination && !rerouteDef->permissionsAllowAll) {
     735              :                         newEdge = lastEdge;
     736              :                         break;
     737              :                     }
     738              :                     try {
     739           84 :                         ok = veh.reroute(now, getID(), router, false, false, true, newEdge);
     740            0 :                     } catch (ProcessError&) {}
     741              :                 }
     742              :             }
     743         4496 :             resetClosedEdges(hasReroutingDevice, tObject);
     744         4496 :             if (ok) {
     745              :                 // since the old route was closed, savings would be infinite. This isn't useful
     746         4069 :                 const double previousCost = router.recomputeCosts(prevEdges, &veh, MSNet::getInstance()->getCurrentTimeStep());
     747         4069 :                 const double savings = previousCost - veh.getRoute().getCosts();
     748         4069 :                 const_cast<MSRoute&>(veh.getRoute()).setSavings(savings);
     749              :             }
     750         4496 :             if (!rerouteDef->isVia) {
     751              : #ifdef DEBUG_REROUTER
     752              :                 if (DEBUGCOND(tObject)) std::cout << "   rerouting:  newDest=" << newEdge->getID()
     753              :                                                       << " newEdges=" << toString(edges)
     754              :                                                       << " newArrivalPos=" << newArrivalPos << " numClosed=" << rerouteDef->closed.size()
     755              :                                                       << " destUnreachable=" << destUnreachable << " containsClosed=" << veh.getRoute().containsAnyOf(rerouteDef->getClosedEdges()) << "\n";
     756              : #endif
     757         4496 :                 if (ok && newArrivalPos != -1) {
     758              :                     // must be called here because replaceRouteEdges may also set the arrivalPos
     759          100 :                     veh.setArrivalPos(newArrivalPos);
     760              :                 }
     761              : 
     762              :             }
     763         4496 :         } else {
     764              :             // person rerouting here
     765              :             MSTransportableRouter& router = hasReroutingDevice
     766         1470 :                                             ? MSRoutingEngine::getIntermodalRouterTT(tObject.getRNGIndex(), prohibited)
     767         1470 :                                             : MSNet::getInstance()->getIntermodalRouter(tObject.getRNGIndex(), 0, prohibited);
     768         4410 :             const bool success = router.compute(tObject.getEdge(), newEdge, tObject.getPositionOnLane(), "",
     769         1470 :                                                 rerouteDef->isVia ? newEdge->getLength() / 2. : tObject.getParameter().arrivalPos, "",
     770         1470 :                                                 tObject.getMaxSpeed(), nullptr, tObject.getVTypeParameter(), 0, now, items);
     771         1470 :             if (!rerouteDef->isVia) {
     772          700 :                 if (success) {
     773         1400 :                     for (const MSTransportableRouter::TripItem& it : items) {
     774          700 :                         if (!it.edges.empty() && !edges.empty() && edges.back() == it.edges.front()) {
     775              :                             edges.pop_back();
     776              :                         }
     777          700 :                         edges.insert(edges.end(), std::make_move_iterator(it.edges.begin()), std::make_move_iterator(it.edges.end()));
     778          700 :                         if (!edges.empty()) {
     779          700 :                             static_cast<MSPerson&>(tObject).replaceWalk(edges, tObject.getPositionOnLane(), 0, 1);
     780              :                         }
     781              :                     }
     782              :                 } else {
     783              :                     // maybe the pedestrian model still finds a way (JuPedSim)
     784            0 :                     static_cast<MSPerson&>(tObject).replaceWalk({tObject.getEdge(), newEdge}, tObject.getPositionOnLane(), 0, 1);
     785              :                 }
     786              :             }
     787              :         }
     788         5966 :         if (!prohibited.empty()) {
     789         1875 :             resetClosedEdges(hasReroutingDevice, tObject);
     790              :         }
     791              :     }
     792              :     // it was only a via so calculate the remaining part
     793         6043 :     if (rerouteDef->isVia) {
     794          770 :         if (tObject.isVehicle()) {
     795              :             SUMOVehicle& veh = static_cast<SUMOVehicle&>(tObject);
     796            0 :             if (!edges.empty()) {
     797              :                 edges.pop_back();
     798              :             }
     799              :             MSVehicleRouter& router = hasReroutingDevice
     800            0 :                                       ? MSRoutingEngine::getRouterTT(veh.getRNGIndex(), veh.getVClass(), prohibited)
     801            0 :                                       : MSNet::getInstance()->getRouterTT(veh.getRNGIndex(), prohibited);
     802            0 :             router.compute(newEdge, lastEdge, &veh, now, edges);
     803            0 :             const double routeCost = router.recomputeCosts(edges, &veh, now);
     804              :             hasReroutingDevice
     805            0 :             ? MSRoutingEngine::getRouterTT(veh.getRNGIndex(), veh.getVClass())
     806            0 :             : MSNet::getInstance()->getRouterTT(veh.getRNGIndex()); // reset closed edges
     807            0 :             const bool useNewRoute = veh.replaceRouteEdges(edges, routeCost, 0, getID());
     808              : #ifdef DEBUG_REROUTER
     809              :             if (DEBUGCOND(tObject)) std::cout << "   rerouting:  newDest=" << newEdge->getID()
     810              :                                                   << " newEdges=" << toString(edges)
     811              :                                                   << " useNewRoute=" << useNewRoute << " newArrivalPos=" << newArrivalPos << " numClosed=" << rerouteDef->closed.size()
     812              :                                                   << " destUnreachable=" << destUnreachable << " containsClosed=" << veh.getRoute().containsAnyOf(rerouteDef->getClosedEdges()) << "\n";
     813              : #endif
     814            0 :             if (useNewRoute && newArrivalPos != -1) {
     815              :                 // must be called here because replaceRouteEdges may also set the arrivalPos
     816            0 :                 veh.setArrivalPos(newArrivalPos);
     817              :             }
     818              :         } else {
     819              :             // person rerouting here
     820          770 :             bool success = !items.empty();
     821          770 :             if (success) {
     822              :                 MSTransportableRouter& router = hasReroutingDevice
     823          770 :                                                 ? MSRoutingEngine::getIntermodalRouterTT(tObject.getRNGIndex(), prohibited)
     824          770 :                                                 : MSNet::getInstance()->getIntermodalRouter(tObject.getRNGIndex(), 0, prohibited);
     825         2310 :                 success = router.compute(newEdge, lastEdge, newEdge->getLength() / 2., "",
     826          770 :                                          tObject.getParameter().arrivalPos, "",
     827          770 :                                          tObject.getMaxSpeed(), nullptr, tObject.getVTypeParameter(), 0, now, items);
     828              :             }
     829          770 :             if (success) {
     830         2310 :                 for (const MSTransportableRouter::TripItem& it : items) {
     831         1540 :                     if (!it.edges.empty() && !edges.empty() && edges.back() == it.edges.front()) {
     832              :                         edges.pop_back();
     833              :                     }
     834         1540 :                     edges.insert(edges.end(), std::make_move_iterator(it.edges.begin()), std::make_move_iterator(it.edges.end()));
     835              :                 }
     836          770 :                 if (!edges.empty()) {
     837          770 :                     static_cast<MSPerson&>(tObject).replaceWalk(edges, tObject.getPositionOnLane(), 0, 1);
     838              :                 }
     839              :             } else {
     840              :                 // maybe the pedestrian model still finds a way (JuPedSim)
     841            0 :                 static_cast<MSPerson&>(tObject).replaceWalk({tObject.getEdge(), newEdge, lastEdge}, tObject.getPositionOnLane(), 0, 1);
     842              :             }
     843              :         }
     844          770 :         if (!prohibited.empty()) {
     845            0 :             resetClosedEdges(hasReroutingDevice, tObject);
     846              :         }
     847              :     }
     848              :     return false; // XXX another interval could appear later but we would have to track whether the currenty interval was already used
     849         6043 : }
     850              : 
     851              : 
     852              : void
     853            1 : MSTriggeredRerouter::setUserMode(bool val) {
     854            1 :     myAmInUserMode = val;
     855            1 : }
     856              : 
     857              : 
     858              : void
     859            1 : MSTriggeredRerouter::setUserUsageProbability(double prob) {
     860            1 :     myUserProbability = prob;
     861            1 : }
     862              : 
     863              : 
     864              : bool
     865            0 : MSTriggeredRerouter::inUserMode() const {
     866            0 :     return myAmInUserMode;
     867              : }
     868              : 
     869              : 
     870              : double
     871         5599 : MSTriggeredRerouter::getProbability() const {
     872         5599 :     return myAmInUserMode ? myUserProbability : myProbability;
     873              : }
     874              : 
     875              : 
     876              : double
     877            0 : MSTriggeredRerouter::getUserProbability() const {
     878            0 :     return myUserProbability;
     879              : }
     880              : 
     881              : 
     882              : double
     883        97064 : MSTriggeredRerouter::getStoppingPlaceOccupancy(MSStoppingPlace* sp, const SUMOVehicle* veh) {
     884              :     return (sp->getElement() == SUMO_TAG_PARKING_AREA
     885        97064 :                     ? (double)dynamic_cast<MSParkingArea*>(sp)->getOccupancyIncludingRemoteReservations(veh)
     886           42 :                     : (double)sp->getStoppedVehicles().size());
     887              : }
     888              : 
     889              : 
     890              : double
     891        94068 : MSTriggeredRerouter::getLastStepStoppingPlaceOccupancy(MSStoppingPlace* sp, const SUMOVehicle* veh) {
     892              :     return (sp->getElement() == SUMO_TAG_PARKING_AREA
     893        94068 :                     ? (double)dynamic_cast<MSParkingArea*>(sp)->getLastStepOccupancyIncludingRemoteReservations(veh)
     894           42 :                     : (double)sp->getStoppedVehicles().size());
     895              : }
     896              : 
     897              : 
     898              : double
     899       277486 : MSTriggeredRerouter::getStoppingPlaceCapacity(MSStoppingPlace* sp) {
     900              :     if (myBlockedStoppingPlaces.count(sp) == 0) {
     901              :         return (double)(sp->getElement() == SUMO_TAG_PARKING_AREA
     902       277470 :                         ? dynamic_cast<MSParkingArea*>(sp)->getCapacity()
     903              :                         // assume only one vehicle at a time (for stationReroute)
     904              :                         : 1.);
     905              :     } else {
     906              :         return 0.;
     907              :     }
     908              : }
     909              : 
     910              : 
     911              : void
     912        89505 : MSTriggeredRerouter::rememberBlockedStoppingPlace(SUMOVehicle& veh, const MSStoppingPlace* parkingArea, bool blocked) {
     913        89505 :     veh.rememberBlockedParkingArea(parkingArea, blocked);
     914        89505 : }
     915              : 
     916              : 
     917              : void
     918       132087 : MSTriggeredRerouter::rememberStoppingPlaceScore(SUMOVehicle& veh, MSStoppingPlace* parkingArea, const std::string& score) {
     919       132087 :     veh.rememberParkingAreaScore(parkingArea, score);
     920       132087 : }
     921              : 
     922              : 
     923              : void
     924        29729 : MSTriggeredRerouter::resetStoppingPlaceScores(SUMOVehicle& veh) {
     925        29729 :     veh.resetParkingAreaScores();
     926        29729 : }
     927              : 
     928              : 
     929              : SUMOTime
     930        71997 : MSTriggeredRerouter::sawBlockedStoppingPlace(SUMOVehicle& veh, MSStoppingPlace* parkingArea, bool local) {
     931        71997 :     return veh.sawBlockedParkingArea(parkingArea, local);
     932              : }
     933              : 
     934              : 
     935              : int
     936        69118 : MSTriggeredRerouter::getNumberStoppingPlaceReroutes(SUMOVehicle& veh) {
     937        69118 :     return veh.getNumberParkingReroutes();
     938              : }
     939              : 
     940              : 
     941              : void
     942        29729 : MSTriggeredRerouter::setNumberStoppingPlaceReroutes(SUMOVehicle& veh, int value) {
     943        29729 :     veh.setNumberParkingReroutes(value);
     944        29729 : }
     945              : 
     946              : 
     947              : MSParkingArea*
     948       104840 : MSTriggeredRerouter::rerouteParkingArea(const MSTriggeredRerouter::RerouteInterval* rerouteDef,
     949              :                                         SUMOVehicle& veh, bool& newDestination, ConstMSEdgeVector& newRoute) {
     950       104840 :     MSStoppingPlace* destStoppingPlace = veh.getNextParkingArea();
     951       104840 :     if (destStoppingPlace == nullptr) {
     952              :         // not driving towards the right type of stop
     953              :         return nullptr;
     954              :     }
     955              :     std::vector<StoppingPlaceVisible> parks;
     956       296400 :     for (auto cand : rerouteDef->parkProbs.getVals()) {
     957       202247 :         if (cand.first->accepts(&veh)) {
     958       201567 :             parks.push_back(cand);
     959              :         }
     960              :     }
     961              :     StoppingPlaceParamMap_t addInput = {};
     962       188306 :     return dynamic_cast<MSParkingArea*>(rerouteStoppingPlace(destStoppingPlace, parks, rerouteDef->parkProbs.getProbs(), veh, newDestination, newRoute, addInput, rerouteDef->getClosed()));
     963        94153 : }
     964              : 
     965              : 
     966              : std::pair<const SUMOVehicle*, MSRailSignal*>
     967          183 : MSTriggeredRerouter::overtakingTrain(const SUMOVehicle& veh,
     968              :                                      ConstMSEdgeVector::const_iterator mainStart,
     969              :                                      const OvertakeLocation& oloc,
     970              :                                      double& netSaving) {
     971          183 :     const ConstMSEdgeVector& route = veh.getRoute().getEdges();
     972              :     const MSEdgeVector& main = oloc.main;
     973          183 :     const double vMax = veh.getMaxSpeed();
     974          366 :     const double prio = veh.getFloatParam(toString(SUMO_TAG_OVERTAKING_REROUTE) + ".prio", false, DEFAULT_PRIO_OVERTAKEN, false);
     975          183 :     MSVehicleControl& c = MSNet::getInstance()->getVehicleControl();
     976          437 :     for (MSVehicleControl::constVehIt it_veh = c.loadedVehBegin(); it_veh != c.loadedVehEnd(); ++it_veh) {
     977          307 :         const MSBaseVehicle* veh2 = dynamic_cast<const MSBaseVehicle*>((*it_veh).second);
     978          307 :         if (veh2->isOnRoad() && veh2->getMaxSpeed() > vMax) {
     979           93 :             const double arrivalDelay = veh2->getStopArrivalDelay();
     980          182 :             const double delay = MAX2(veh2->getStopDelay(), arrivalDelay == INVALID_DOUBLE ? 0 : arrivalDelay);
     981          279 :             if (delay > veh2->getFloatParam(toString(SUMO_TAG_OVERTAKING_REROUTE) + ".maxDelay", false, DEFAULT_MAXDELAY, false)) {
     982              :                 continue;
     983              :             }
     984           89 :             const ConstMSEdgeVector& route2 = veh2->getRoute().getEdges();
     985              :             auto itOnMain2 = route2.end();
     986              :             int mainIndex = 0;
     987          110 :             for (const MSEdge* m : main) {
     988          105 :                 itOnMain2 = std::find(veh2->getCurrentRouteEdge(), route2.end(), m);
     989          105 :                 if (itOnMain2 != route2.end()) {
     990              :                     break;
     991              :                 }
     992           21 :                 mainIndex++;
     993              :             }
     994           89 :             if (itOnMain2 != route2.end() && itOnMain2 > veh2->getCurrentRouteEdge()) {
     995              :                 auto itOnMain = mainStart + mainIndex;
     996              :                 double timeToMain = 0;
     997          371 :                 for (auto it = veh.getCurrentRouteEdge(); it != itOnMain; it++) {
     998          290 :                     timeToMain += (*it)->getMinimumTravelTime(&veh);
     999              :                 }
    1000              :                 // veh2 may be anywhere on the current edge so we have to discount
    1001           81 :                 double timeToMain2 = -veh2->getEdge()->getMinimumTravelTime(veh2) * veh2->getPositionOnLane() / veh2->getEdge()->getLength();
    1002              :                 double timeToLastSignal2 = timeToMain2;
    1003          562 :                 for (auto it = veh2->getCurrentRouteEdge(); it != itOnMain2; it++) {
    1004          481 :                     timeToMain2 += (*it)->getMinimumTravelTime(veh2);
    1005          481 :                     auto signal = getRailSignal(*it);
    1006          481 :                     if (signal) {
    1007              :                         timeToLastSignal2 = timeToMain2;
    1008              : #ifdef DEBUG_OVERTAKING
    1009              :                         std::cout << "   lastBeforeMain2 " << signal->getID() << "\n";
    1010              : #endif
    1011              :                     }
    1012              :                 }
    1013              :                 double exitMainTime = timeToMain;
    1014              :                 double exitMainBlockTime2 = timeToMain2;
    1015              :                 double commonTime = 0;
    1016              :                 double commonTime2 = 0;
    1017              :                 int nCommon = 0;
    1018              :                 auto exitMain2 = itOnMain2;
    1019              :                 const MSRailSignal* firstAfterMain = nullptr;
    1020              :                 const MSEdge* common = nullptr;
    1021           81 :                 double vMinCommon = (*itOnMain)->getVehicleMaxSpeed(&veh);
    1022           81 :                 double vMinCommon2 = (*itOnMain2)->getVehicleMaxSpeed(veh2);
    1023              :                 while (itOnMain2 != route2.end()
    1024          794 :                         && itOnMain != route.end()
    1025         1657 :                         && *itOnMain == *itOnMain2) {
    1026              :                     common = *itOnMain;
    1027          785 :                     commonTime += common->getMinimumTravelTime(&veh);
    1028          785 :                     commonTime2 += common->getMinimumTravelTime(veh2);
    1029          785 :                     vMinCommon = MIN2(vMinCommon, common->getVehicleMaxSpeed(&veh));
    1030          785 :                     vMinCommon2 = MIN2(vMinCommon2, common->getVehicleMaxSpeed(veh2));
    1031          785 :                     const bool onMain = nCommon < (int)main.size() - mainIndex;
    1032          785 :                     if (onMain) {
    1033          240 :                         exitMainTime = timeToMain + commonTime;
    1034              :                     }
    1035          785 :                     if (firstAfterMain == nullptr) {
    1036          480 :                         exitMainBlockTime2 = timeToMain2 + commonTime2;
    1037              :                     }
    1038          785 :                     auto signal = getRailSignal(common);
    1039          785 :                     if (signal) {
    1040          318 :                         if (!onMain && firstAfterMain == nullptr) {
    1041              :                             firstAfterMain = signal;
    1042              : #ifdef DEBUG_OVERTAKING
    1043              :                             std::cout << "   firstAfterMain " << signal->getID() << "\n";
    1044              : #endif
    1045              :                         }
    1046              :                     }
    1047          785 :                     nCommon++;
    1048              :                     itOnMain++;
    1049              :                     itOnMain2++;
    1050              :                 }
    1051           81 :                 const double vMaxLast = common->getVehicleMaxSpeed(&veh);
    1052           81 :                 const double vMaxLast2 = common->getVehicleMaxSpeed(veh2);
    1053           81 :                 commonTime += veh.getLength() / vMaxLast;
    1054           81 :                 exitMainBlockTime2 += veh2->getLength() / vMaxLast2;
    1055           81 :                 exitMain2 += MIN2(nCommon, (int)main.size() - mainIndex);
    1056           81 :                 double timeLoss2 = MAX2(0.0, timeToMain + veh.getLength() / oloc.siding.front()->getVehicleMaxSpeed(&veh) - timeToLastSignal2);
    1057           81 :                 const double saving = timeToMain + commonTime - (timeToMain2 + commonTime2) - timeLoss2;
    1058           81 :                 const double loss = exitMainBlockTime2 - exitMainTime;
    1059          162 :                 const double prio2 = veh2->getFloatParam(toString(SUMO_TAG_OVERTAKING_REROUTE) + ".prio", false, DEFAULT_PRIO_OVERTAKER, false);
    1060              :                 // losses from acceleration after stopping at a signal
    1061           81 :                 const double accelTimeLoss = loss > 0 ? 0.5 * vMinCommon / veh.getVehicleType().getCarFollowModel().getMaxAccel() : 0;
    1062           81 :                 const double accelTimeLoss2 = timeLoss2 > 0 ? 0.5 * vMinCommon2 / veh2->getVehicleType().getCarFollowModel().getMaxAccel() : 0;
    1063           81 :                 netSaving = prio2 * (saving - accelTimeLoss2) - prio * (loss + accelTimeLoss);
    1064              : #ifdef DEBUG_OVERTAKING
    1065              :                 std::cout << SIMTIME << " veh=" << veh.getID() << " veh2=" << veh2->getID()
    1066              :                           << " sidingStart=" << oloc.siding.front()->getID()
    1067              :                           << " ttm=" << timeToMain << " ttm2=" << timeToMain2
    1068              :                           << " nCommon=" << nCommon << " cT=" << commonTime << " cT2=" << commonTime2
    1069              :                           << " em=" << exitMainTime << " emb2=" << exitMainBlockTime2
    1070              :                           << " ttls2=" << timeToLastSignal2
    1071              :                           << " saving=" << saving << " loss=" << loss
    1072              :                           << " atl=" << accelTimeLoss << " atl2=" << accelTimeLoss2 << " tl2=" << timeLoss2
    1073              :                           << " prio=" << prio << " prio2=" << prio2 << " netSaving=" << netSaving << "\n";
    1074              : #endif
    1075           81 :                 if (netSaving > oloc.minSaving) {
    1076           53 :                     MSRailSignal* s = findSignal(veh2->getCurrentRouteEdge(), exitMain2);
    1077           53 :                     if (s != nullptr) {
    1078           53 :                         return std::make_pair(veh2, s);
    1079              :                     }
    1080              :                 }
    1081              :             }
    1082              :         }
    1083              :     }
    1084          130 :     return std::make_pair(nullptr, nullptr);
    1085              : }
    1086              : 
    1087              : 
    1088              : void
    1089           15 : MSTriggeredRerouter::checkStopSwitch(MSBaseVehicle& ego, const MSTriggeredRerouter::RerouteInterval* def) {
    1090              :     myBlockedStoppingPlaces.clear();
    1091              : #ifdef DEBUG_REROUTER
    1092              :     std::cout << SIMTIME << " " << getID() << " ego=" << ego.getID() << "\n";
    1093              : #endif
    1094           15 :     if (!ego.hasStops()) {
    1095            1 :         return;
    1096              :     }
    1097           15 :     const MSStop& stop = ego.getNextStop();
    1098           15 :     if (stop.reached || stop.joinTriggered || (stop.pars.arrival < 0 && stop.pars.until < 0)) {
    1099              :         return;
    1100              :     }
    1101           15 :     MSStoppingPlace* cur = nullptr;
    1102           30 :     for (MSStoppingPlace* sp : stop.getPlaces()) {
    1103           15 :         for (auto item : def->stopAlternatives) {
    1104           15 :             if (sp == item.first) {
    1105           15 :                 cur = sp;
    1106           15 :                 break;
    1107              :             }
    1108              :         }
    1109           15 :     }
    1110           15 :     if (cur == nullptr) {
    1111              :         return;
    1112              :     }
    1113           15 :     std::vector<const SUMOVehicle*> stopped = cur->getStoppedVehicles();
    1114              : #ifdef DEBUG_REROUTER
    1115              :     std::cout << SIMTIME << " " << getID() << " ego=" << ego.getID() << " stopped=" << toString(stopped) << "\n";
    1116              : #endif
    1117              :     SUMOTime stoppedDuration = -1;
    1118           15 :     if (stopped.empty()) {
    1119              :         /// look upstream for vehicles that stop on this lane before ego arrives
    1120            9 :         const MSLane& stopLane = cur->getLane();
    1121            9 :         MSVehicleControl& c = MSNet::getInstance()->getVehicleControl();
    1122           28 :         for (MSVehicleControl::constVehIt it_veh = c.loadedVehBegin(); it_veh != c.loadedVehEnd(); ++it_veh) {
    1123           19 :             const MSBaseVehicle* veh = dynamic_cast<const MSBaseVehicle*>((*it_veh).second);
    1124           19 :             if (veh->isOnRoad() && veh->hasStops()) {
    1125           19 :                 const MSStop& vehStop = veh->getNextStop();
    1126           19 :                 if (vehStop.pars.lane == stopLane.getID()) {
    1127              :                     myBlockedStoppingPlaces.insert(cur);
    1128           12 :                     if (veh->isStopped()) {
    1129              :                         // stopped somewhere else on the same lane
    1130            3 :                         stoppedDuration = MAX3((SUMOTime)0, stoppedDuration, veh->getStopDuration());
    1131              :                     } else {
    1132            9 :                         std::pair<double, double> timeDist = veh->estimateTimeToNextStop();
    1133            9 :                         SUMOTime timeTo = TIME2STEPS(timeDist.first);
    1134            9 :                         stoppedDuration = MAX3((SUMOTime)0, stoppedDuration, timeTo + vehStop.getMinDuration(SIMSTEP + timeTo));
    1135              :                     }
    1136              :                 }
    1137              :             }
    1138              :         }
    1139              :     } else {
    1140              :         stoppedDuration = 0;
    1141           12 :         for (const SUMOVehicle* veh : cur->getStoppedVehicles()) {
    1142            6 :             stoppedDuration = MAX2(stoppedDuration, veh->getStopDuration());
    1143            6 :         }
    1144              :     }
    1145           15 :     if (stoppedDuration < 0) {
    1146              :         return;
    1147              :     }
    1148              :     /// @todo: consider time for conflict veh to leave the block
    1149           15 :     const SUMOTime stopFree = SIMSTEP + stoppedDuration;
    1150           15 :     const SUMOTime scheduledArrival = stop.pars.arrival >= 0 ? stop.pars.arrival : stop.pars.until - stop.pars.duration;
    1151              : #ifdef DEBUG_REROUTER
    1152              :     std::cout << SIMTIME << " " << getID() << " ego=" << ego.getID() << " stopFree=" << stopFree << " scheduledArrival=" << time2string(scheduledArrival) << "\n";
    1153              : #endif
    1154           15 :     if (stopFree < scheduledArrival) {
    1155              :         // no conflict according to the schedule
    1156              :         return;
    1157              :     }
    1158           14 :     const SUMOTime estimatedArrival = SIMSTEP + (stop.pars.arrival >= 0
    1159           14 :                                       ? TIME2STEPS(ego.getStopArrivalDelay())
    1160           16 :                                       : TIME2STEPS(ego.getStopDelay()) - stop.pars.duration);
    1161              : #ifdef DEBUG_REROUTER
    1162              :     std::cout << SIMTIME << " " << getID() << " ego=" << ego.getID() << " stopFree=" << stopFree << " estimatedArrival=" << time2string(estimatedArrival) << "\n";
    1163              : #endif
    1164           14 :     if (stopFree < estimatedArrival) {
    1165              :         // no conflict when considering current delay
    1166              :         return;
    1167              :     }
    1168           14 :     const std::vector<double> probs(def->stopAlternatives.size(), 1.);
    1169              :     StoppingPlaceParamMap_t scores = {};
    1170              :     bool newDestination;
    1171              :     ConstMSEdgeVector newRoute;
    1172              :     // @todo: consider future conflicts caused by rerouting
    1173              :     // @todo: reject alternatives with large detour
    1174           14 :     const MSStoppingPlace* alternative = rerouteStoppingPlace(nullptr, def->stopAlternatives, probs, ego, newDestination, newRoute, scores);
    1175              : #ifdef DEBUG_REROUTER
    1176              :     std::cout << SIMTIME << " " << getID() << " ego=" << ego.getID() << " alternative=" << Named::getIDSecure(alternative) << "\n";
    1177              : #endif
    1178           14 :     if (alternative != nullptr) {
    1179              :         // @todo adapt plans of any riders
    1180              :         //for (MSTransportable* p : ego.getPersons()) {
    1181              :         //    p->rerouteParkingArea(ego.getNextParkingArea(), newParkingArea);
    1182              :         //}
    1183              : 
    1184           14 :         if (newDestination && ego.getParameter().arrivalPosProcedure != ArrivalPosDefinition::DEFAULT) {
    1185              :             // update arrival parameters
    1186            0 :             SUMOVehicleParameter* newParameter = new SUMOVehicleParameter();
    1187            0 :             *newParameter = ego.getParameter();
    1188            0 :             newParameter->arrivalPosProcedure = ArrivalPosDefinition::GIVEN;
    1189            0 :             newParameter->arrivalPos = alternative->getEndLanePosition();
    1190            0 :             ego.replaceParameter(newParameter);
    1191              :         }
    1192              : 
    1193           14 :         SUMOVehicleParameter::Stop newStop = stop.pars;
    1194           14 :         newStop.lane = alternative->getLane().getID();
    1195           14 :         newStop.startPos = alternative->getBeginLanePosition();
    1196           14 :         newStop.endPos = alternative->getEndLanePosition();
    1197           14 :         switch (alternative->getElement()) {
    1198            0 :             case SUMO_TAG_PARKING_AREA:
    1199              :                 newStop.parkingarea = alternative->getID();
    1200              :                 break;
    1201            0 :             case SUMO_TAG_CONTAINER_STOP:
    1202              :                 newStop.containerstop = alternative->getID();
    1203              :                 break;
    1204            0 :             case SUMO_TAG_CHARGING_STATION:
    1205              :                 newStop.chargingStation = alternative->getID();
    1206              :                 break;
    1207            0 :             case SUMO_TAG_OVERHEAD_WIRE_SEGMENT:
    1208              :                 newStop.overheadWireSegment = alternative->getID();
    1209              :                 break;
    1210           14 :             case SUMO_TAG_BUS_STOP:
    1211              :             case SUMO_TAG_TRAIN_STOP:
    1212              :             default:
    1213              :                 newStop.busstop = alternative->getID();
    1214              :         }
    1215              :         std::string errorMsg;
    1216           28 :         if (!ego.replaceStop(0, newStop, getID() + ":" + toString(SUMO_TAG_STATION_REROUTE), false, errorMsg)) {
    1217            0 :             WRITE_WARNING("Vehicle '" + ego.getID() + "' at rerouter '" + getID()
    1218              :                           + "' could not perform stationReroute to '" + alternative->getID()
    1219              :                           + "' reason=" + errorMsg + ", time=" + time2string(MSNet::getInstance()->getCurrentTimeStep()) + ".");
    1220              :         }
    1221           14 :     }
    1222           29 : }
    1223              : 
    1224              : 
    1225              : MSRailSignal*
    1226          152 : MSTriggeredRerouter::findSignal(ConstMSEdgeVector::const_iterator begin, ConstMSEdgeVector::const_iterator end) {
    1227          152 :     auto it = end;
    1228              :     do {
    1229              :         it--;
    1230          304 :         auto signal = getRailSignal(*it);
    1231          304 :         if (signal != nullptr) {
    1232          152 :             return signal;
    1233              :         }
    1234          152 :     } while (it != begin);
    1235              :     return nullptr;
    1236              : }
    1237              : 
    1238              : 
    1239              : MSRailSignal*
    1240         1570 : MSTriggeredRerouter::getRailSignal(const MSEdge* edge) {
    1241         1570 :     if (edge->getToJunction()->getType() == SumoXMLNodeType::RAIL_SIGNAL) {
    1242          732 :         for (const MSLink* link : edge->getLanes().front()->getLinkCont()) {
    1243          732 :             if (link->getTLLogic() != nullptr) {
    1244          732 :                 return dynamic_cast<MSRailSignal*>(const_cast<MSTrafficLightLogic*>(link->getTLLogic()));
    1245              :             }
    1246              :         }
    1247              :     }
    1248              :     return nullptr;
    1249              : }
    1250              : 
    1251              : bool
    1252      1200047 : MSTriggeredRerouter::applies(const SUMOTrafficObject& obj) const {
    1253      1200047 :     if (myVehicleTypes.empty() || myVehicleTypes.count(obj.getVehicleType().getOriginalID()) > 0) {
    1254      1199977 :         return true;
    1255              :     } else {
    1256          140 :         std::set<std::string> vTypeDists = MSNet::getInstance()->getVehicleControl().getVTypeDistributionMembership(obj.getVehicleType().getOriginalID());
    1257           70 :         for (auto vTypeDist : vTypeDists) {
    1258              :             if (myVehicleTypes.count(vTypeDist) > 0) {
    1259              :                 return true;
    1260              :             }
    1261              :         }
    1262           70 :         return false;
    1263              :     }
    1264              : }
    1265              : 
    1266              : 
    1267              : bool
    1268       130869 : MSTriggeredRerouter::affected(const std::set<SUMOTrafficObject::NumericalID>& edgeIndices, const MSEdgeVector& closed) {
    1269       149015 :     for (const MSEdge* const e : closed) {
    1270        69888 :         if (edgeIndices.count(e->getNumericalID()) > 0) {
    1271              :             return true;
    1272              :         }
    1273              :     }
    1274              :     return false;
    1275              : }
    1276              : 
    1277              : 
    1278              : void
    1279        26206 : MSTriggeredRerouter::checkParkingRerouteConsistency() {
    1280              :     // if a parkingArea is a rerouting target, it should generally have a
    1281              :     // rerouter on its edge or vehicles will be stuck there once it's full.
    1282              :     // The user should receive a Warning in this case
    1283              :     std::set<MSEdge*> parkingRerouterEdges;
    1284              :     std::map<MSParkingArea*, std::string, ComparatorIdLess> targetedParkingArea; // paID -> targetingRerouter
    1285        30253 :     for (const auto& rr : myInstances) {
    1286              :         bool hasParkingReroute = false;
    1287         7951 :         for (const RerouteInterval& interval : rr.second->myIntervals) {
    1288         3904 :             if (interval.parkProbs.getOverallProb() > 0) {
    1289              :                 hasParkingReroute = true;
    1290        14682 :                 for (const StoppingPlaceVisible& pav : interval.parkProbs.getVals()) {
    1291        25050 :                     targetedParkingArea[dynamic_cast<MSParkingArea*>(pav.first)] = rr.first;
    1292              :                 }
    1293              :             }
    1294              :         }
    1295         4047 :         if (hasParkingReroute) {
    1296         2157 :             parkingRerouterEdges.insert(rr.second->myEdges.begin(), rr.second->myEdges.end());
    1297              :         }
    1298              :     }
    1299        29005 :     for (const auto& item : targetedParkingArea) {
    1300         2799 :         if (parkingRerouterEdges.count(&item.first->getLane().getEdge()) == 0) {
    1301         1312 :             WRITE_WARNINGF(TL("ParkingArea '%' is targeted by rerouter '%' but doesn't have its own rerouter. This may cause parking search to abort."),
    1302              :                            item.first->getID(), item.second);
    1303              :         }
    1304              :     }
    1305        26206 : }
    1306              : 
    1307              : 
    1308              : void
    1309        35335 : MSTriggeredRerouter::resetClosedEdges(bool hasReroutingDevice, const SUMOTrafficObject& o) {
    1310              :     // getRouterTT without prohibitions removes previous prohibitions
    1311        35335 :     if (o.isVehicle()) {
    1312              :         hasReroutingDevice
    1313        70670 :         ? MSRoutingEngine::getRouterTT(o.getRNGIndex(), o.getVClass())
    1314        54814 :         : MSNet::getInstance()->getRouterTT(o.getRNGIndex());
    1315              :     } else {
    1316              :         hasReroutingDevice
    1317            0 :         ? MSRoutingEngine::getIntermodalRouterTT(o.getRNGIndex())
    1318            0 :         : MSNet::getInstance()->getIntermodalRouter(o.getRNGIndex(), 0);
    1319              :     }
    1320        35335 : }
    1321              : 
    1322              : /****************************************************************************/
        

Generated by: LCOV version 2.0-1