LCOV - code coverage report
Current view: top level - src/microsim/trigger - MSTriggeredRerouter.cpp (source / functions) Coverage Total Hit
Test: lcov.info Lines: 90.6 % 609 552
Test Date: 2026-09-20 15:45:03 Functions: 94.3 % 35 33

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

Generated by: LCOV version 2.0-1