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

Generated by: LCOV version 2.0-1