LCOV - code coverage report
Current view: top level - src/microsim/trigger - MSTriggeredRerouter.cpp (source / functions) Hit Total Coverage
Test: lcov.info Lines: 503 552 91.1 %
Date: 2024-05-07 15:28:01 Functions: 22 24 91.7 %

          Line data    Source code
       1             : /****************************************************************************/
       2             : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
       3             : // Copyright (C) 2001-2024 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             : /// @date    Mon, 25 July 2005
      20             : ///
      21             : // Reroutes vehicles passing an edge
      22             : /****************************************************************************/
      23             : #include <config.h>
      24             : 
      25             : #include <string>
      26             : #include <algorithm>
      27             : #ifdef HAVE_FOX
      28             : #include <utils/common/ScopedLocker.h>
      29             : #endif
      30             : #include <utils/options/OptionsCont.h>
      31             : #include <utils/common/MsgHandler.h>
      32             : #include <utils/common/Command.h>
      33             : #include <utils/xml/SUMOXMLDefinitions.h>
      34             : #include <utils/common/UtilExceptions.h>
      35             : #include <utils/common/ToString.h>
      36             : #include <utils/common/StringUtils.h>
      37             : #include <utils/xml/SUMOSAXHandler.h>
      38             : #include <utils/router/DijkstraRouter.h>
      39             : #include <utils/common/RandHelper.h>
      40             : #include <utils/common/WrappingCommand.h>
      41             : #include <microsim/MSEdgeWeightsStorage.h>
      42             : #include <microsim/MSLane.h>
      43             : #include <microsim/MSVehicle.h>
      44             : #include <microsim/MSRoute.h>
      45             : #include <microsim/MSEdge.h>
      46             : #include <microsim/MSEventControl.h>
      47             : #include <microsim/MSNet.h>
      48             : #include <microsim/MSVehicleControl.h>
      49             : #include <microsim/MSGlobals.h>
      50             : #include <microsim/MSParkingArea.h>
      51             : #include <microsim/MSStop.h>
      52             : #include <microsim/transportables/MSPerson.h>
      53             : #include <microsim/devices/MSDevice_Routing.h>
      54             : #include <microsim/devices/MSRoutingEngine.h>
      55             : #include "MSTriggeredRerouter.h"
      56             : 
      57             : #include <mesosim/MELoop.h>
      58             : #include <mesosim/MESegment.h>
      59             : 
      60             : //#define DEBUG_REROUTER
      61             : //#define DEBUG_PARKING
      62             : #define DEBUGCOND (veh.isSelected())
      63             : //#define DEBUGCOND (true)
      64             : //#define DEBUGCOND (veh.getID() == "")
      65             : 
      66             : // ===========================================================================
      67             : // static member definition
      68             : // ===========================================================================
      69             : MSEdge MSTriggeredRerouter::mySpecialDest_keepDestination("MSTriggeredRerouter_keepDestination", -1, SumoXMLEdgeFunc::UNKNOWN, "", "", -1, 0);
      70             : MSEdge MSTriggeredRerouter::mySpecialDest_terminateRoute("MSTriggeredRerouter_terminateRoute", -1, SumoXMLEdgeFunc::UNKNOWN, "", "", -1, 0);
      71             : std::map<std::string, MSTriggeredRerouter*> MSTriggeredRerouter::myInstances;
      72             : 
      73             : 
      74             : // ===========================================================================
      75             : // method definitions
      76             : // ===========================================================================
      77        3296 : MSTriggeredRerouter::MSTriggeredRerouter(const std::string& id,
      78             :         const MSEdgeVector& edges, double prob, bool off, bool optional,
      79        3296 :         SUMOTime timeThreshold, const std::string& vTypes, const Position& pos) :
      80             :     Named(id),
      81             :     MSMoveReminder(id),
      82        3296 :     myEdges(edges),
      83        3296 :     myProbability(prob),
      84        3296 :     myUserProbability(prob),
      85        3296 :     myAmInUserMode(false),
      86        3296 :     myAmOptional(optional),
      87        3296 :     myPosition(pos),
      88        3296 :     myTimeThreshold(timeThreshold),
      89        6592 :     myHaveParkProbs(false) {
      90        3296 :     myInstances[id] = this;
      91             :     // build actors
      92        7687 :     for (const MSEdge* const e : edges) {
      93        4391 :         if (MSGlobals::gUseMesoSim) {
      94         291 :             MSGlobals::gMesoNet->getSegmentForEdge(*e)->addDetector(this);
      95             :         }
      96        9513 :         for (MSLane* const lane : e->getLanes()) {
      97        5122 :             lane->addMoveReminder(this);
      98             :         }
      99             :     }
     100        3296 :     if (off) {
     101           1 :         setUserMode(true);
     102           1 :         setUserUsageProbability(0);
     103             :     }
     104        6592 :     const std::vector<std::string> vt = StringTokenizer(vTypes).getVector();
     105             :     myVehicleTypes.insert(vt.begin(), vt.end());
     106        3296 : }
     107             : 
     108             : 
     109        5941 : MSTriggeredRerouter::~MSTriggeredRerouter() {
     110             :     myInstances.erase(getID());
     111       12529 : }
     112             : 
     113             : 
     114             : // ------------ loading begin
     115             : void
     116       17485 : MSTriggeredRerouter::myStartElement(int element,
     117             :                                     const SUMOSAXAttributes& attrs) {
     118       17485 :     if (element == SUMO_TAG_INTERVAL) {
     119        3279 :         bool ok = true;
     120        3279 :         myParsedRerouteInterval = RerouteInterval();
     121        3279 :         myParsedRerouteInterval.begin = attrs.getOptSUMOTimeReporting(SUMO_ATTR_BEGIN, nullptr, ok, -1);
     122        3279 :         myParsedRerouteInterval.end = attrs.getOptSUMOTimeReporting(SUMO_ATTR_END, nullptr, ok, SUMOTime_MAX);
     123             :     }
     124       17485 :     if (element == SUMO_TAG_DEST_PROB_REROUTE) {
     125             :         // by giving probabilities of new destinations
     126             :         // get the destination edge
     127         688 :         std::string dest = attrs.getStringSecure(SUMO_ATTR_ID, "");
     128         344 :         if (dest == "") {
     129           0 :             throw ProcessError(TLF("MSTriggeredRerouter %: No destination edge id given.", getID()));
     130             :         }
     131         344 :         MSEdge* to = MSEdge::dictionary(dest);
     132         344 :         if (to == nullptr) {
     133          69 :             if (dest == "keepDestination") {
     134             :                 to = &mySpecialDest_keepDestination;
     135          41 :             } else if (dest == "terminateRoute") {
     136             :                 to = &mySpecialDest_terminateRoute;
     137             :             } else {
     138           0 :                 throw ProcessError("MSTriggeredRerouter " + getID() + ": Destination edge '" + dest + "' is not known.");
     139             :             }
     140             :         }
     141             :         // get the probability to reroute
     142         344 :         bool ok = true;
     143         344 :         double prob = attrs.getOpt<double>(SUMO_ATTR_PROB, getID().c_str(), ok, 1.);
     144         344 :         if (!ok) {
     145           0 :             throw ProcessError();
     146             :         }
     147         344 :         if (prob < 0) {
     148           0 :             throw ProcessError("MSTriggeredRerouter " + getID() + ": Attribute 'probability' for destination '" + dest + "' is negative (must not).");
     149             :         }
     150             :         // add
     151         344 :         myParsedRerouteInterval.edgeProbs.add(to, prob);
     152             :     }
     153             : 
     154       17485 :     if (element == SUMO_TAG_CLOSING_REROUTE) {
     155             :         // by closing edge
     156         885 :         const std::string& closed_id = attrs.getStringSecure(SUMO_ATTR_ID, "");
     157         885 :         MSEdge* const closed = MSEdge::dictionary(closed_id);
     158         885 :         if (closed == nullptr) {
     159           0 :             throw ProcessError("MSTriggeredRerouter " + getID() + ": Edge '" + closed_id + "' to close is not known.");
     160             :         }
     161         885 :         myParsedRerouteInterval.closed.push_back(closed);
     162             :         bool ok;
     163         885 :         const std::string allow = attrs.getOpt<std::string>(SUMO_ATTR_ALLOW, getID().c_str(), ok, "", false);
     164         885 :         const std::string disallow = attrs.getOpt<std::string>(SUMO_ATTR_DISALLOW, getID().c_str(), ok, "");
     165         885 :         myParsedRerouteInterval.permissions = parseVehicleClasses(allow, disallow);
     166             :     }
     167             : 
     168       17485 :     if (element == SUMO_TAG_CLOSING_LANE_REROUTE) {
     169             :         // by closing lane
     170         159 :         std::string closed_id = attrs.getStringSecure(SUMO_ATTR_ID, "");
     171         159 :         MSLane* closed = MSLane::dictionary(closed_id);
     172         159 :         if (closed == nullptr) {
     173           0 :             throw ProcessError("MSTriggeredRerouter " + getID() + ": Lane '" + closed_id + "' to close is not known.");
     174             :         }
     175         159 :         myParsedRerouteInterval.closedLanes.push_back(closed);
     176             :         bool ok;
     177         159 :         if (attrs.hasAttribute(SUMO_ATTR_ALLOW) || attrs.hasAttribute(SUMO_ATTR_DISALLOW)) {
     178          83 :             const std::string allow = attrs.getOpt<std::string>(SUMO_ATTR_ALLOW, getID().c_str(), ok, "", false);
     179          83 :             const std::string disallow = attrs.getOpt<std::string>(SUMO_ATTR_DISALLOW, getID().c_str(), ok, "");
     180          83 :             myParsedRerouteInterval.permissions = parseVehicleClasses(allow, disallow);
     181             :         } else {
     182             :             // lane closing only makes sense if the lane really receives reduced permissions
     183          76 :             myParsedRerouteInterval.permissions = SVC_AUTHORITY;
     184             :         }
     185             :     }
     186             : 
     187       17485 :     if (element == SUMO_TAG_ROUTE_PROB_REROUTE) {
     188             :         // by explicit rerouting using routes
     189             :         // check if route exists
     190        1732 :         std::string routeStr = attrs.getStringSecure(SUMO_ATTR_ID, "");
     191         866 :         if (routeStr == "") {
     192           0 :             throw ProcessError(TLF("MSTriggeredRerouter %: No route id given.", getID()));
     193             :         }
     194         866 :         ConstMSRoutePtr route = MSRoute::dictionary(routeStr);
     195         866 :         if (route == nullptr) {
     196           0 :             throw ProcessError("MSTriggeredRerouter " + getID() + ": Route '" + routeStr + "' does not exist.");
     197             :         }
     198             : 
     199             :         // get the probability to reroute
     200         866 :         bool ok = true;
     201         866 :         double prob = attrs.getOpt<double>(SUMO_ATTR_PROB, getID().c_str(), ok, 1.);
     202         866 :         if (!ok) {
     203           0 :             throw ProcessError();
     204             :         }
     205         866 :         if (prob < 0) {
     206           0 :             throw ProcessError("MSTriggeredRerouter " + getID() + ": Attribute 'probability' for route '" + routeStr + "' is negative (must not).");
     207             :         }
     208             :         // add
     209        1732 :         myParsedRerouteInterval.routeProbs.add(route, prob);
     210             :     }
     211             : 
     212       17485 :     if (element == SUMO_TAG_PARKING_AREA_REROUTE) {
     213       23820 :         std::string parkingarea = attrs.getStringSecure(SUMO_ATTR_ID, "");
     214       11910 :         if (parkingarea == "") {
     215           0 :             throw ProcessError(TLF("MSTriggeredRerouter %: No parking area id given.", getID()));
     216             :         }
     217       11910 :         MSParkingArea* pa = static_cast<MSParkingArea*>(MSNet::getInstance()->getStoppingPlace(parkingarea, SUMO_TAG_PARKING_AREA));
     218       11910 :         if (pa == nullptr) {
     219           0 :             throw ProcessError("MSTriggeredRerouter " + getID() + ": Parking area '" + parkingarea + "' is not known.");
     220             :         }
     221             :         // get the probability to reroute
     222       11910 :         bool ok = true;
     223       11910 :         const double prob = attrs.getOpt<double>(SUMO_ATTR_PROB, getID().c_str(), ok, 1.);
     224       11910 :         if (!ok) {
     225           0 :             throw ProcessError();
     226             :         }
     227       11910 :         if (prob < 0) {
     228           0 :             throw ProcessError("MSTriggeredRerouter " + getID() + ": Attribute 'probability' for destination '" + parkingarea + "' is negative (must not).");
     229             :         }
     230       11910 :         const bool visible = attrs.getOpt<bool>(SUMO_ATTR_VISIBLE, getID().c_str(), ok, false);
     231             :         // add
     232       11910 :         myParsedRerouteInterval.parkProbs.add(std::make_pair(pa, visible), prob);
     233       11910 :         myHaveParkProbs = true;
     234             :     }
     235             : 
     236       17485 :     if (element == SUMO_TAG_VIA_PROB_REROUTE) {
     237             :         // by giving probabilities of vias
     238          74 :         std::string viaID  = attrs.getStringSecure(SUMO_ATTR_ID, "");
     239          37 :         if (viaID == "") {
     240           0 :             throw ProcessError(TLF("MSTriggeredRerouter %: No via edge id given.", getID()));
     241             :         }
     242          37 :         MSEdge* const via = MSEdge::dictionary(viaID);
     243          37 :         if (via == nullptr) {
     244           0 :             throw ProcessError("MSTriggeredRerouter " + getID() + ": Via edge '" + viaID + "' is not known.");
     245             :         }
     246             :         // get the probability to reroute
     247          37 :         bool ok = true;
     248          37 :         double prob = attrs.getOpt<double>(SUMO_ATTR_PROB, getID().c_str(), ok, 1.);
     249          37 :         if (!ok) {
     250           0 :             throw ProcessError();
     251             :         }
     252          37 :         if (prob < 0) {
     253           0 :             throw ProcessError("MSTriggeredRerouter " + getID() + ": Attribute 'probability' for via '" + viaID + "' is negative (must not).");
     254             :         }
     255             :         // add
     256          37 :         myParsedRerouteInterval.edgeProbs.add(via, prob);
     257          37 :         myParsedRerouteInterval.isVia = true;
     258             :     }
     259       17485 : }
     260             : 
     261             : 
     262             : void
     263       20781 : MSTriggeredRerouter::myEndElement(int element) {
     264       20781 :     if (element == SUMO_TAG_INTERVAL) {
     265       15186 :         for (auto paVi : myParsedRerouteInterval.parkProbs.getVals()) {
     266       11907 :             paVi.first->setNumAlternatives((int)myParsedRerouteInterval.parkProbs.getVals().size() - 1);
     267             :         }
     268        3279 :         if (myParsedRerouteInterval.closedLanes.size() > 0) {
     269             :             // collect edges that are affect by a closed lane
     270             :             std::set<MSEdge*> affected;
     271         275 :             for (const MSLane* const  l : myParsedRerouteInterval.closedLanes) {
     272         159 :                 affected.insert(&l->getEdge());
     273             :             }
     274         116 :             myParsedRerouteInterval.closedLanesAffected.insert(myParsedRerouteInterval.closedLanesAffected.begin(), affected.begin(), affected.end());
     275             :         }
     276        3279 :         const SUMOTime closingBegin = myParsedRerouteInterval.begin;
     277        6558 :         const SUMOTime simBegin = string2time(OptionsCont::getOptions().getString("begin"));
     278        3279 :         if (closingBegin < simBegin && myParsedRerouteInterval.end > simBegin) {
     279             :             // interval started before simulation begin but is still active at
     280             :             // the start of the simulation
     281         262 :             myParsedRerouteInterval.begin = simBegin;
     282             :         }
     283        3279 :         myIntervals.push_back(myParsedRerouteInterval);
     284        3279 :         myIntervals.back().id = (long long int)&myIntervals.back();
     285        3279 :         if (!(myParsedRerouteInterval.closed.empty() && myParsedRerouteInterval.closedLanes.empty()) && myParsedRerouteInterval.permissions != SVCAll) {
     286         832 :             MSNet::getInstance()->getBeginOfTimestepEvents()->addEvent(
     287         416 :                 new WrappingCommand<MSTriggeredRerouter>(this, &MSTriggeredRerouter::setPermissions), myParsedRerouteInterval.begin);
     288             :         }
     289             :     }
     290       20781 : }
     291             : 
     292             : 
     293             : // ------------ loading end
     294             : 
     295             : 
     296             : SUMOTime
     297         548 : MSTriggeredRerouter::setPermissions(const SUMOTime currentTime) {
     298             :     bool updateVehicles = false;
     299        1138 :     for (const RerouteInterval& i : myIntervals) {
     300         590 :         if (i.begin == currentTime && !(i.closed.empty() && i.closedLanes.empty()) && i.permissions != SVCAll) {
     301         896 :             for (MSEdge* const e : i.closed) {
     302         947 :                 for (MSLane* lane : e->getLanes()) {
     303             :                     //std::cout << SIMTIME << " closing: intervalID=" << i.id << " lane=" << (*l)->getID() << " prevPerm=" << getVehicleClassNames((*l)->getPermissions()) << " new=" << getVehicleClassNames(i.permissions) << "\n";
     304         481 :                     lane->setPermissions(i.permissions, i.id);
     305             :                 }
     306         466 :                 e->rebuildAllowedLanes();
     307             :                 updateVehicles = true;
     308             :             }
     309         571 :             for (MSLane* const lane : i.closedLanes) {
     310         141 :                 lane->setPermissions(i.permissions, i.id);
     311         141 :                 lane->getEdge().rebuildAllowedLanes();
     312             :                 updateVehicles = true;
     313             :             }
     314         860 :             MSNet::getInstance()->getBeginOfTimestepEvents()->addEvent(
     315         430 :                 new WrappingCommand<MSTriggeredRerouter>(this, &MSTriggeredRerouter::setPermissions), i.end);
     316             :         }
     317         590 :         if (i.end == currentTime && !(i.closed.empty() && i.closedLanes.empty()) && i.permissions != SVCAll) {
     318         274 :             for (MSEdge* const e : i.closed) {
     319         260 :                 for (MSLane* lane : e->getLanes()) {
     320         132 :                     lane->resetPermissions(i.id);
     321             :                     //std::cout << SIMTIME << " opening: intervalID=" << i.id << " lane=" << (*l)->getID() << " restore prevPerm=" << getVehicleClassNames((*l)->getPermissions()) << "\n";
     322             :                 }
     323         128 :                 e->rebuildAllowedLanes();
     324             :                 updateVehicles = true;
     325             :             }
     326         256 :             for (MSLane* lane : i.closedLanes) {
     327         110 :                 lane->resetPermissions(i.id);
     328         110 :                 lane->getEdge().rebuildAllowedLanes();
     329             :                 updateVehicles = true;
     330             :             }
     331             :         }
     332             :     }
     333         548 :     if (updateVehicles) {
     334             :         // only vehicles on the affected lanes had their bestlanes updated so far
     335        1107 :         for (MSEdge* e : myEdges) {
     336             :             // also updates vehicles
     337         559 :             e->rebuildAllowedTargets();
     338             :         }
     339             :     }
     340         548 :     return 0;
     341             : }
     342             : 
     343             : 
     344             : const MSTriggeredRerouter::RerouteInterval*
     345     1554297 : MSTriggeredRerouter::getCurrentReroute(SUMOTime time, SUMOTrafficObject& obj) const {
     346     2078426 :     for (const RerouteInterval& ri : myIntervals) {
     347     1219701 :         if (ri.begin <= time && ri.end > time) {
     348             :             if (
     349             :                 // destProbReroute
     350      626304 :                 ri.edgeProbs.getOverallProb() > 0 ||
     351             :                 // routeProbReroute
     352      826125 :                 ri.routeProbs.getOverallProb() > 0 ||
     353             :                 // parkingZoneReroute
     354             :                 ri.parkProbs.getOverallProb() > 0) {
     355      629138 :                 return &ri;
     356             :             }
     357       84412 :             if (!ri.closed.empty() || !ri.closedLanesAffected.empty()) {
     358       84412 :                 const std::set<SUMOTrafficObject::NumericalID>& edgeIndices = obj.getUpcomingEdgeIDs();
     359       84412 :                 if (affected(edgeIndices, ri.closed) || affected(edgeIndices, ri.closedLanesAffected)) {
     360             :                     return &ri;
     361             :                 }
     362             :             }
     363             :         }
     364             :     }
     365             :     return nullptr;
     366             : }
     367             : 
     368             : 
     369             : const MSTriggeredRerouter::RerouteInterval*
     370        4948 : MSTriggeredRerouter::getCurrentReroute(SUMOTime time) const {
     371        4962 :     for (const RerouteInterval& ri : myIntervals) {
     372        4948 :         if (ri.begin <= time && ri.end > time) {
     373        4934 :             if (ri.edgeProbs.getOverallProb() != 0 || ri.routeProbs.getOverallProb() != 0 || ri.parkProbs.getOverallProb() != 0
     374        4946 :                     || !ri.closed.empty() || !ri.closedLanesAffected.empty()) {
     375             :                 return &ri;
     376             :             }
     377             :         }
     378             :     }
     379             :     return nullptr;
     380             : }
     381             : 
     382             : 
     383             : bool
     384      656418 : MSTriggeredRerouter::notifyEnter(SUMOTrafficObject& tObject, MSMoveReminder::Notification reason, const MSLane* /* enteredLane */) {
     385      656418 :     if (myAmOptional) {
     386             :         return true;
     387             :     }
     388      655918 :     return triggerRouting(tObject, reason);
     389             : }
     390             : 
     391             : 
     392             : bool
     393      899099 : MSTriggeredRerouter::notifyMove(SUMOTrafficObject& veh, double /*oldPos*/,
     394             :                                 double /*newPos*/, double /*newSpeed*/) {
     395      899099 :     return triggerRouting(veh, NOTIFICATION_JUNCTION);
     396             : }
     397             : 
     398             : 
     399             : bool
     400      102379 : MSTriggeredRerouter::notifyLeave(SUMOTrafficObject& /*veh*/, double /*lastPos*/,
     401             :                                  MSMoveReminder::Notification reason, const MSLane* /* enteredLane */) {
     402      102379 :     return reason == NOTIFICATION_LANE_CHANGE;
     403             : }
     404             : 
     405             : 
     406             : bool
     407     1555087 : MSTriggeredRerouter::triggerRouting(SUMOTrafficObject& tObject, MSMoveReminder::Notification reason) {
     408     1555087 :     if (!applies(tObject)) {
     409             :         return false;
     410             :     }
     411             :     // check whether the vehicle shall be rerouted
     412     1554297 :     const SUMOTime now = MSNet::getInstance()->getCurrentTimeStep();
     413     1554297 :     const MSTriggeredRerouter::RerouteInterval* const rerouteDef = getCurrentReroute(now, tObject);
     414     1554297 :     if (rerouteDef == nullptr) {
     415             :         return true; // an active interval could appear later
     416             :     }
     417      695572 :     const double prob = myAmInUserMode ? myUserProbability : myProbability;
     418      695572 :     if (prob < 1 && RandHelper::rand(tObject.getRNG()) > prob) {
     419             :         return false; // XXX another interval could appear later but we would have to track whether the current interval was already tried
     420             :     }
     421      695283 :     if (myTimeThreshold > 0 && MAX2(tObject.getWaitingTime(), tObject.getWaitingTime(true)) < myTimeThreshold) {
     422             :         return true; // waiting time may be reached later
     423             :     }
     424      688889 :     if (reason == NOTIFICATION_LANE_CHANGE) {
     425             :         return false;
     426             :     }
     427             :     // if we have a closingLaneReroute, only vehicles with a rerouting device can profit from rerouting (otherwise, edge weights will not reflect local jamming)
     428      670628 :     const bool hasReroutingDevice = tObject.getDevice(typeid(MSDevice_Routing)) != nullptr;
     429      670628 :     if (rerouteDef->closedLanes.size() > 0 && !hasReroutingDevice) {
     430             :         return true; // an active interval could appear later
     431             :     }
     432      533851 :     const MSEdge* lastEdge = tObject.getRerouteDestination();
     433             : #ifdef DEBUG_REROUTER
     434             :     if (DEBUGCOND) {
     435             :         std::cout << SIMTIME << " veh=" << veh.getID() << " check rerouter " << getID() << " lane=" << Named::getIDSecure(veh.getLane()) << " edge=" << veh.getEdge()->getID() << " finalEdge=" << lastEdge->getID() << " arrivalPos=" << veh.getArrivalPos() << "\n";
     436             :     }
     437             : #endif
     438             : 
     439      533851 :     if (rerouteDef->parkProbs.getOverallProb() > 0) {
     440             : #ifdef HAVE_FOX
     441       22938 :         ScopedLocker<> lock(myNotificationMutex, MSGlobals::gNumSimThreads > 1);
     442             : #endif
     443       22938 :         if (!tObject.isVehicle()) {
     444             :             return false;
     445             :         }
     446             :         SUMOVehicle& veh = static_cast<SUMOVehicle&>(tObject);
     447       22883 :         bool newDestination = false;
     448             :         ConstMSEdgeVector newRoute;
     449       22883 :         MSParkingArea* newParkingArea = rerouteParkingArea(rerouteDef, veh, newDestination, newRoute);
     450       22883 :         if (newParkingArea != nullptr) {
     451             :             // adapt plans of any riders
     452       10972 :             for (MSTransportable* p : veh.getPersons()) {
     453          35 :                 p->rerouteParkingArea(veh.getNextParkingArea(), newParkingArea);
     454             :             }
     455             : 
     456       10937 :             if (newDestination) {
     457             :                 // update arrival parameters
     458         236 :                 SUMOVehicleParameter* newParameter = new SUMOVehicleParameter();
     459         236 :                 *newParameter = veh.getParameter();
     460         236 :                 newParameter->arrivalPosProcedure = ArrivalPosDefinition::GIVEN;
     461         236 :                 newParameter->arrivalPos = newParkingArea->getEndLanePosition();
     462         236 :                 veh.replaceParameter(newParameter);
     463             :             }
     464             : 
     465             :             SUMOAbstractRouter<MSEdge, SUMOVehicle>& router = hasReroutingDevice
     466       10772 :                     ? MSRoutingEngine::getRouterTT(veh.getRNGIndex(), veh.getVClass(), rerouteDef->closed)
     467       10937 :                     : MSNet::getInstance()->getRouterTT(veh.getRNGIndex(), rerouteDef->closed);
     468       10937 :             const double routeCost = router.recomputeCosts(newRoute, &veh, MSNet::getInstance()->getCurrentTimeStep());
     469       10937 :             ConstMSEdgeVector prevEdges(veh.getCurrentRouteEdge(), veh.getRoute().end());
     470       10937 :             const double previousCost = router.recomputeCosts(prevEdges, &veh, MSNet::getInstance()->getCurrentTimeStep());
     471       10937 :             const double savings = previousCost - routeCost;
     472             :             hasReroutingDevice
     473       21874 :             ? MSRoutingEngine::getRouterTT(veh.getRNGIndex(), veh.getVClass())
     474       11102 :             : MSNet::getInstance()->getRouterTT(veh.getRNGIndex()); // reset closed edges
     475             :             //if (getID() == "ego") std::cout << SIMTIME << " pCost=" << previousCost << " cost=" << routeCost
     476             :             //        << " prevEdges=" << toString(prevEdges)
     477             :             //        << " newEdges=" << toString(edges)
     478             :             //        << "\n";
     479             : 
     480             :             std::string errorMsg;
     481       10937 :             if (veh.replaceParkingArea(newParkingArea, errorMsg)) {
     482       32811 :                 veh.replaceRouteEdges(newRoute, routeCost, savings, getID() + ":" + toString(SUMO_TAG_PARKING_AREA_REROUTE), false, false, false);
     483             :             } else {
     484           0 :                 WRITE_WARNING("Vehicle '" + veh.getID() + "' at rerouter '" + getID()
     485             :                               + "' could not reroute to new parkingArea '" + newParkingArea->getID()
     486             :                               + "' reason=" + errorMsg + ", time=" + time2string(MSNet::getInstance()->getCurrentTimeStep()) + ".");
     487             :             }
     488             :         }
     489             :         return false;
     490             :     }
     491             : 
     492             :     // get rerouting params
     493      510913 :     ConstMSRoutePtr newRoute = rerouteDef->routeProbs.getOverallProb() > 0 ? rerouteDef->routeProbs.get() : nullptr;
     494             :     // we will use the route if given rather than calling our own dijsktra...
     495      510913 :     if (newRoute != nullptr) {
     496             : #ifdef DEBUG_REROUTER
     497             :         if (DEBUGCOND) {
     498             :             std::cout << "    replacedRoute from routeDist " << newRoute->getID() << "\n";
     499             :         }
     500             : #endif
     501      501508 :         tObject.replaceRoute(newRoute, getID());
     502      501508 :         return false; // XXX another interval could appear later but we would have to track whether the currenty interval was already used
     503             :     }
     504             :     const MSEdge* newEdge = lastEdge;
     505             :     // ok, try using a new destination
     506             :     double newArrivalPos = -1;
     507        9405 :     const bool destUnreachable = std::find(rerouteDef->closed.begin(), rerouteDef->closed.end(), lastEdge) != rerouteDef->closed.end();
     508             :     bool keepDestination = false;
     509             :     // if we have a closingReroute, only assign new destinations to vehicles which cannot reach their original destination
     510             :     // if we have a closingLaneReroute, no new destinations should be assigned
     511        9405 :     if (rerouteDef->closed.empty() || destUnreachable || rerouteDef->isVia) {
     512        6535 :         newEdge = rerouteDef->edgeProbs.getOverallProb() > 0 ? rerouteDef->edgeProbs.get() : lastEdge;
     513             :         assert(newEdge != nullptr);
     514        6535 :         if (newEdge == &mySpecialDest_terminateRoute) {
     515             :             keepDestination = true;
     516          55 :             newEdge = tObject.getEdge();
     517          55 :             newArrivalPos = tObject.getPositionOnLane(); // instant arrival
     518        6480 :         } else if (newEdge == &mySpecialDest_keepDestination || newEdge == lastEdge) {
     519        3588 :             if (destUnreachable && rerouteDef->permissions == SVCAll) {
     520             :                 // if permissions aren't set vehicles will simply drive through
     521             :                 // the closing unless terminated. If the permissions are specified, assume that the user wants
     522             :                 // vehicles to stand and wait until the closing ends
     523        2889 :                 WRITE_WARNINGF(TL("Cannot keep destination edge '%' for vehicle '%' due to closed edges. Terminating route."), lastEdge->getID(), tObject.getID());
     524         963 :                 newEdge = tObject.getEdge();
     525             :             } else {
     526             :                 newEdge = lastEdge;
     527             :             }
     528             :         }
     529             :     }
     530             :     ConstMSEdgeVector edges;
     531             :     std::vector<MSTransportableRouter::TripItem> items;
     532             :     // we have a new destination, let's replace the route (if it is affected)
     533       12275 :     if (rerouteDef->closed.empty() || destUnreachable || rerouteDef->isVia || affected(tObject.getUpcomingEdgeIDs(), rerouteDef->closed)) {
     534        8176 :         if (tObject.isVehicle()) {
     535             :             SUMOVehicle& veh = static_cast<SUMOVehicle&>(tObject);
     536             :             MSVehicleRouter& router = hasReroutingDevice
     537        6706 :                                       ? MSRoutingEngine::getRouterTT(veh.getRNGIndex(), veh.getVClass(), rerouteDef->closed)
     538        4147 :                                       : MSNet::getInstance()->getRouterTT(veh.getRNGIndex(), rerouteDef->closed);
     539        6706 :             router.compute(veh.getEdge(), newEdge, &veh, now, edges);
     540        6706 :             if (edges.size() == 0 && !keepDestination && rerouteDef->edgeProbs.getOverallProb() > 0) {
     541             :                 // destination unreachable due to closed intermediate edges. pick among alternative targets
     542          82 :                 RandomDistributor<MSEdge*> edgeProbs2 = rerouteDef->edgeProbs;
     543          82 :                 edgeProbs2.remove(const_cast<MSEdge*>(newEdge));
     544         152 :                 while (edges.size() == 0 && edgeProbs2.getVals().size() > 0) {
     545         110 :                     newEdge = edgeProbs2.get();
     546         110 :                     edgeProbs2.remove(const_cast<MSEdge*>(newEdge));
     547         110 :                     if (newEdge == &mySpecialDest_terminateRoute) {
     548          42 :                         newEdge = veh.getEdge();
     549          42 :                         newArrivalPos = veh.getPositionOnLane(); // instant arrival
     550             :                     }
     551         110 :                     if (newEdge == &mySpecialDest_keepDestination && rerouteDef->permissions != SVCAll) {
     552          40 :                         newEdge = lastEdge;
     553          40 :                         break;
     554             :                     }
     555          70 :                     router.compute(veh.getEdge(), newEdge, &veh, now, edges);
     556             :                 }
     557             : 
     558          82 :             }
     559        6706 :             if (!rerouteDef->isVia) {
     560        6706 :                 const double routeCost = router.recomputeCosts(edges, &veh, now);
     561             :                 hasReroutingDevice
     562        6706 :                 ? MSRoutingEngine::getRouterTT(veh.getRNGIndex(), veh.getVClass())
     563       10853 :                 : MSNet::getInstance()->getRouterTT(veh.getRNGIndex()); // reset closed edges
     564        6706 :                 const bool useNewRoute = veh.replaceRouteEdges(edges, routeCost, 0, getID());
     565             : #ifdef DEBUG_REROUTER
     566             :                 if (DEBUGCOND) std::cout << "   rerouting:  newDest=" << newEdge->getID()
     567             :                                              << " newEdges=" << toString(edges)
     568             :                                              << " useNewRoute=" << useNewRoute << " newArrivalPos=" << newArrivalPos << " numClosed=" << rerouteDef->closed.size()
     569             :                                              << " destUnreachable=" << destUnreachable << " containsClosed=" << veh.getRoute().containsAnyOf(rerouteDef->closed) << "\n";
     570             : #endif
     571        6706 :                 if (useNewRoute && newArrivalPos != -1) {
     572             :                     // must be called here because replaceRouteEdges may also set the arrivalPos
     573          91 :                     veh.setArrivalPos(newArrivalPos);
     574             :                 }
     575             : 
     576             :             }
     577             :         } else {
     578             :             // person rerouting here
     579             :             MSTransportableRouter& router = hasReroutingDevice
     580        1470 :                                             ? MSRoutingEngine::getIntermodalRouterTT(tObject.getRNGIndex(), rerouteDef->closed)
     581        1470 :                                             : MSNet::getInstance()->getIntermodalRouter(tObject.getRNGIndex(), 0, rerouteDef->closed);
     582        4410 :             const bool success = router.compute(tObject.getEdge(), newEdge, tObject.getPositionOnLane(), "",
     583        1470 :                                                 rerouteDef->isVia ? newEdge->getLength() / 2. : tObject.getParameter().arrivalPos, "",
     584        1470 :                                                 tObject.getMaxSpeed(), nullptr, 0, now, items);
     585        1470 :             if (!rerouteDef->isVia) {
     586         700 :                 if (success) {
     587        1400 :                     for (const MSTransportableRouter::TripItem& it : items) {
     588         700 :                         if (!it.edges.empty() && !edges.empty() && edges.back() == it.edges.front()) {
     589             :                             edges.pop_back();
     590             :                         }
     591         700 :                         edges.insert(edges.end(), std::make_move_iterator(it.edges.begin()), std::make_move_iterator(it.edges.end()));
     592         700 :                         if (!edges.empty()) {
     593         700 :                             static_cast<MSPerson&>(tObject).reroute(edges, tObject.getPositionOnLane(), 0, 1);
     594             :                         }
     595             :                     }
     596             :                 } else {
     597             :                     // maybe the pedestrian model still finds a way (JuPedSim)
     598           0 :                     static_cast<MSPerson&>(tObject).reroute({tObject.getEdge(), newEdge}, tObject.getPositionOnLane(), 0, 1);
     599             :                 }
     600             :             }
     601             :         }
     602             :     }
     603             :     // it was only a via so calculate the remaining part
     604        9405 :     if (rerouteDef->isVia) {
     605         770 :         if (tObject.isVehicle()) {
     606             :             SUMOVehicle& veh = static_cast<SUMOVehicle&>(tObject);
     607           0 :             if (!edges.empty()) {
     608             :                 edges.pop_back();
     609             :             }
     610             :             MSVehicleRouter& router = hasReroutingDevice
     611           0 :                                       ? MSRoutingEngine::getRouterTT(veh.getRNGIndex(), veh.getVClass(), rerouteDef->closed)
     612           0 :                                       : MSNet::getInstance()->getRouterTT(veh.getRNGIndex(), rerouteDef->closed);
     613           0 :             router.compute(newEdge, lastEdge, &veh, now, edges);
     614           0 :             const double routeCost = router.recomputeCosts(edges, &veh, now);
     615             :             hasReroutingDevice
     616           0 :             ? MSRoutingEngine::getRouterTT(veh.getRNGIndex(), veh.getVClass())
     617           0 :             : MSNet::getInstance()->getRouterTT(veh.getRNGIndex()); // reset closed edges
     618           0 :             const bool useNewRoute = veh.replaceRouteEdges(edges, routeCost, 0, getID());
     619             : #ifdef DEBUG_REROUTER
     620             :             if (DEBUGCOND) std::cout << "   rerouting:  newDest=" << newEdge->getID()
     621             :                                          << " newEdges=" << toString(edges)
     622             :                                          << " useNewRoute=" << useNewRoute << " newArrivalPos=" << newArrivalPos << " numClosed=" << rerouteDef->closed.size()
     623             :                                          << " destUnreachable=" << destUnreachable << " containsClosed=" << veh.getRoute().containsAnyOf(rerouteDef->closed) << "\n";
     624             : #endif
     625           0 :             if (useNewRoute && newArrivalPos != -1) {
     626             :                 // must be called here because replaceRouteEdges may also set the arrivalPos
     627           0 :                 veh.setArrivalPos(newArrivalPos);
     628             :             }
     629             :         } else {
     630             :             // person rerouting here
     631         770 :             bool success = !items.empty();
     632         770 :             if (success) {
     633             :                 MSTransportableRouter& router = hasReroutingDevice
     634         770 :                                                 ? MSRoutingEngine::getIntermodalRouterTT(tObject.getRNGIndex(), rerouteDef->closed)
     635         770 :                                                 : MSNet::getInstance()->getIntermodalRouter(tObject.getRNGIndex(), 0, rerouteDef->closed);
     636        2310 :                 success = router.compute(newEdge, lastEdge, newEdge->getLength() / 2., "",
     637         770 :                                          tObject.getParameter().arrivalPos, "",
     638         770 :                                          tObject.getMaxSpeed(), nullptr, 0, now, items);
     639             :             }
     640         770 :             if (success) {
     641        2310 :                 for (const MSTransportableRouter::TripItem& it : items) {
     642        1540 :                     if (!it.edges.empty() && !edges.empty() && edges.back() == it.edges.front()) {
     643             :                         edges.pop_back();
     644             :                     }
     645        1540 :                     edges.insert(edges.end(), std::make_move_iterator(it.edges.begin()), std::make_move_iterator(it.edges.end()));
     646             :                 }
     647         770 :                 if (!edges.empty()) {
     648         770 :                     static_cast<MSPerson&>(tObject).reroute(edges, tObject.getPositionOnLane(), 0, 1);
     649             :                 }
     650             :             } else {
     651             :                 // maybe the pedestrian model still finds a way (JuPedSim)
     652           0 :                 static_cast<MSPerson&>(tObject).reroute({tObject.getEdge(), newEdge, lastEdge}, tObject.getPositionOnLane(), 0, 1);
     653             :             }
     654             :         }
     655             :     }
     656             :     return false; // XXX another interval could appear later but we would have to track whether the currenty interval was already used
     657        9405 : }
     658             : 
     659             : 
     660             : void
     661           1 : MSTriggeredRerouter::setUserMode(bool val) {
     662           1 :     myAmInUserMode = val;
     663           1 : }
     664             : 
     665             : 
     666             : void
     667           1 : MSTriggeredRerouter::setUserUsageProbability(double prob) {
     668           1 :     myUserProbability = prob;
     669           1 : }
     670             : 
     671             : 
     672             : bool
     673           0 : MSTriggeredRerouter::inUserMode() const {
     674           0 :     return myAmInUserMode;
     675             : }
     676             : 
     677             : 
     678             : double
     679        1471 : MSTriggeredRerouter::getProbability() const {
     680        1471 :     return myAmInUserMode ? myUserProbability : myProbability;
     681             : }
     682             : 
     683             : 
     684             : double
     685           0 : MSTriggeredRerouter::getUserProbability() const {
     686           0 :     return myUserProbability;
     687             : }
     688             : 
     689             : 
     690             : double
     691      167394 : MSTriggeredRerouter::getWeight(SUMOVehicle& veh, const std::string param, const double defaultWeight) {
     692             :     // get custom vehicle parameter
     693      167394 :     if (veh.getParameter().hasParameter(param)) {
     694             :         try {
     695          40 :             return StringUtils::toDouble(veh.getParameter().getParameter(param, "-1"));
     696           0 :         } catch (...) {
     697           0 :             WRITE_WARNINGF(TL("Invalid value '%' for vehicle parameter '%'"), veh.getParameter().getParameter(param, "-1"), param);
     698           0 :         }
     699             :     } else {
     700             :         // get custom vType parameter
     701      167374 :         if (veh.getVehicleType().getParameter().hasParameter(param)) {
     702             :             try {
     703       20594 :                 return StringUtils::toDouble(veh.getVehicleType().getParameter().getParameter(param, "-1"));
     704           0 :             } catch (...) {
     705           0 :                 WRITE_WARNINGF(TL("Invalid value '%' for vType parameter '%'"), veh.getVehicleType().getParameter().getParameter(param, "-1"), param);
     706           0 :             }
     707             :         }
     708             :     }
     709             :     //WRITE_MESSAGE("Vehicle '" +veh.getID() + "' does not supply vehicle parameter '" + param + "'. Using default of " + toString(defaultWeight) + "\n";
     710             :     return defaultWeight;
     711             : }
     712             : 
     713             : 
     714             : MSParkingArea*
     715       22883 : MSTriggeredRerouter::rerouteParkingArea(const MSTriggeredRerouter::RerouteInterval* rerouteDef,
     716             :                                         SUMOVehicle& veh, bool& newDestination, ConstMSEdgeVector& newRoute) {
     717             :     // Reroute destination from initial parking area to an alternative parking area
     718             :     // if the following conditions are met:
     719             :     // - next stop target is a parking area
     720             :     // - target is included in the current alternative set
     721             :     // - target is visibly full
     722             :     // Any parking areas that are visibly full at the current location are
     723             :     // committed to parking memory
     724             : 
     725       22883 :     MSParkingArea* nearParkArea = nullptr;
     726       22883 :     std::vector<ParkingAreaVisible> parks = rerouteDef->parkProbs.getVals();
     727             : 
     728             :     // get vehicle params
     729       22883 :     MSParkingArea* destParkArea = veh.getNextParkingArea();
     730       22883 :     const MSRoute& route = veh.getRoute();
     731             : 
     732       22883 :     if (destParkArea == nullptr) {
     733             :         // not driving towards a parkingArea
     734             :         return nullptr;
     735             :     }
     736             :     // if the vehicle is on the destParkArea edge it is always visible
     737       19686 :     bool destVisible = (&destParkArea->getLane().getEdge() == veh.getEdge());
     738             : 
     739       61452 :     for (auto paVis : parks) {
     740       50607 :         if (paVis.first == destParkArea && paVis.second) {
     741             :             destVisible = true;
     742             :             break;
     743             :         }
     744             :     }
     745             : 
     746       19686 :     MSParkingArea* onTheWay = nullptr;
     747       19686 :     const int parkAnywhere = (int)getWeight(veh, "parking.anywhere", -1);
     748             : 
     749             :     // check whether we are ready to accept any free parkingArea along the
     750             :     // way to our destination
     751       19686 :     if (parkAnywhere < 0 || parkAnywhere > veh.getNumberParkingReroutes()) {
     752       19653 :         if (!destVisible) {
     753             :             // cannot determine destination occupancy, only register visibly full
     754       30607 :             for (const ParkingAreaVisible& pav : parks) {
     755       25914 :                 if (pav.second && pav.first->getLastStepOccupancy() == pav.first->getCapacity()) {
     756        3424 :                     veh.rememberBlockedParkingArea(pav.first, &pav.first->getLane().getEdge() == veh.getEdge());
     757             :                 }
     758             :             }
     759             : #ifdef DEBUG_PARKING
     760             :             if (DEBUGCOND) {
     761             :                 //std::cout << SIMTIME << " rerouter=" << getID() << " veh=" << veh.getID()
     762             :                 //    << " dest=" << destParkArea->getID() << " parkAnywhere=" << parkAnywhere << " parkingReroutes=" << veh.getNumberParkingReroutes() << " stay on original route\n";
     763             :             }
     764             : #endif
     765             :         }
     766             : 
     767             :     } else {
     768             :         double bestDist = std::numeric_limits<double>::max();
     769          33 :         const double brakeGap = veh.getBrakeGap(true);
     770         190 :         for (ParkingAreaVisible& item : parks) {
     771         157 :             if (item.second) {
     772          62 :                 MSParkingArea* pa = item.first;
     773          62 :                 if (&pa->getLane().getEdge() == veh.getEdge()
     774          62 :                         && pa->getLastStepOccupancy() < pa->getCapacity()) {
     775          24 :                     const double distToStart = pa->getBeginLanePosition() - veh.getPositionOnLane();
     776          24 :                     const double distToEnd = pa->getEndLanePosition() - veh.getPositionOnLane();
     777          24 :                     if (distToEnd > brakeGap) {
     778          38 :                         veh.rememberParkingAreaScore(pa, "dist=" + toString(distToStart));
     779          19 :                         if (distToStart < bestDist) {
     780             :                             bestDist = distToStart;
     781          19 :                             onTheWay = pa;
     782             :                         }
     783             :                     } else {
     784          10 :                         veh.rememberParkingAreaScore(pa, "tooClose");
     785             :                     }
     786             :                 }
     787             :             }
     788             :         }
     789             : #ifdef DEBUG_PARKING
     790             :         if (DEBUGCOND) {
     791             :             std::cout << SIMTIME << " rerouter=" << getID() << " veh=" << veh.getID()
     792             :                       << " dest=" << destParkArea->getID() << " parkAnywhere=" << parkAnywhere << " parkingReroutes=" << veh.getNumberParkingReroutes() << " alongTheWay=" << Named::getIDSecure(onTheWay) << "\n";
     793             :         }
     794             : #endif
     795             :     }
     796       19686 :     if (!destVisible && onTheWay == nullptr) {
     797             :         return nullptr;
     798             :     }
     799             : 
     800       14988 :     if (destParkArea->getLastStepOccupancy() == destParkArea->getCapacity() || onTheWay != nullptr) {
     801             : 
     802             :         // if the current route ends at the parking area, the new route will
     803             :         // also and at the new area
     804       22736 :         newDestination = (&destParkArea->getLane().getEdge() == route.getLastEdge()
     805        3151 :                           && veh.getArrivalPos() >= destParkArea->getBeginLanePosition()
     806       14519 :                           && veh.getArrivalPos() <= destParkArea->getEndLanePosition());
     807             : 
     808             : #ifdef DEBUG_PARKING
     809             :         if (DEBUGCOND) {
     810             :             std::cout << SIMTIME << " rerouter=" << getID() << " veh=" << veh.getID()
     811             :                       << " rerouteParkingArea dest=" << destParkArea->getID()
     812             :                       << " onDestEdge=" << (&(destParkArea->getLane().getEdge()) == veh.getEdge())
     813             :                       << " newDest=" << newDestination
     814             :                       << " onTheWay=" << Named::getIDSecure(onTheWay)
     815             :                       << "\n";
     816             :         }
     817             : #endif
     818             : 
     819             :         ParkingParamMap_t weights;
     820             :         std::map<MSParkingArea*, ConstMSEdgeVector> newRoutes;
     821             :         std::map<MSParkingArea*, ConstMSEdgeVector> parkApproaches;
     822             : 
     823             :         // The probability of choosing this area inside the zone
     824       11368 :         weights["probability"] = getWeight(veh, "parking.probability.weight", 0.0);
     825             : 
     826             :         // The capacity of this area
     827       11368 :         weights["capacity"] = getWeight(veh, "parking.capacity.weight", 0.0);
     828             : 
     829             :         // The absolute number of free spaces
     830       11368 :         weights["absfreespace"] = getWeight(veh, "parking.absfreespace.weight", 0.0);
     831             : 
     832             :         // The relative number of free spaces
     833       11368 :         weights["relfreespace"] = getWeight(veh, "parking.relfreespace.weight", 0.0);
     834             : 
     835             :         // The distance to the new parking area
     836       22736 :         weights["distanceto"] = getWeight(veh, "parking.distanceto.weight", getWeight(veh, "parking.distance.weight", 1.0));
     837             : 
     838             :         // The time to reach this area
     839       11368 :         weights["timeto"] = getWeight(veh, "parking.timeto.weight", 0.0);
     840             : 
     841             :         // The distance from the new parking area
     842       11368 :         weights["distancefrom"] = getWeight(veh, "parking.distancefrom.weight", 0.0);
     843             : 
     844             :         // The time to reach the end from this area
     845       22736 :         weights["timefrom"] = getWeight(veh, "parking.timefrom.weight", 0.0);
     846             : 
     847             :         // a map stores maximum values to normalize parking values
     848             :         ParkingParamMap_t maxValues;
     849             : 
     850       11368 :         maxValues["probability"] = 0.0;
     851       11368 :         maxValues["capacity"] = 0.0;
     852       11368 :         maxValues["absfreespace"] = 0.0;
     853       11368 :         maxValues["relfreespace"] = 0.0;
     854       11368 :         maxValues["distanceto"] = 0.0;
     855       11368 :         maxValues["timeto"] = 0.0;
     856       11368 :         maxValues["distancefrom"] = 0.0;
     857       11368 :         maxValues["timefrom"] = 0.0;
     858             : 
     859             :         // a map stores elegible parking areas
     860             :         MSParkingAreaMap_t parkAreas;
     861             : 
     862       11368 :         SUMOAbstractRouter<MSEdge, SUMOVehicle>& router = MSNet::getInstance()->getRouterTT(veh.getRNGIndex(), rerouteDef->closed);
     863             : 
     864             :         const std::vector<double>& probs = rerouteDef->parkProbs.getProbs();
     865             : 
     866       11368 :         const double brakeGap = veh.getBrakeGap(true);
     867             : 
     868       11368 :         if (onTheWay != nullptr) {
     869             :             // compute new route
     870          19 :             if (newDestination) {
     871           0 :                 newRoute.push_back(veh.getEdge());
     872             :             } else {
     873          19 :                 bool valid = addParkValues(veh, brakeGap, newDestination, onTheWay, onTheWay->getLastStepOccupancy(), 1, router, parkAreas, newRoutes, parkApproaches, maxValues);
     874          19 :                 if (!valid) {
     875           0 :                     WRITE_WARNINGF(TL("Parkingarea '%' along the way cannot be used by vehicle '%' for unknown reason"), onTheWay->getID(), veh.getID());
     876           0 :                     return nullptr;
     877             :                 }
     878          19 :                 newRoute = newRoutes[onTheWay];
     879             :             }
     880          19 :             return onTheWay;
     881             :         }
     882             : 
     883             :         int numAlternatives = 0;
     884             :         std::vector<std::tuple<SUMOTime, MSParkingArea*, int> > blockedTimes;
     885       11349 :         veh.resetParkingAreaScores();
     886       11349 :         veh.rememberParkingAreaScore(destParkArea, "occupied");
     887       11349 :         veh.rememberBlockedParkingArea(destParkArea, &destParkArea->getLane().getEdge() == veh.getEdge());
     888             : 
     889       11349 :         const SUMOTime parkingMemory = TIME2STEPS(getWeight(veh, "parking.memory", 600));
     890       11349 :         const double parkingFrustration = getWeight(veh, "parking.frustration", 100);
     891       11349 :         const double parkingKnowledge = getWeight(veh, "parking.knowledge", 0);
     892             : 
     893       60785 :         for (int i = 0; i < (int)parks.size(); ++i) {
     894       49436 :             MSParkingArea* pa = parks[i].first;
     895             :             // alternative occupancy is randomized (but never full) if invisible
     896             :             // current destination must be visible at this point
     897       49436 :             const bool visible = parks[i].second || (pa == destParkArea && destVisible);
     898       49436 :             double paOccupancy = pa->getOccupancy();
     899       49436 :             if (!visible && (parkingKnowledge == 0 || parkingKnowledge < RandHelper::rand(veh.getRNG()))) {
     900       35858 :                 const double minOccupancy = MIN2((double)pa->getCapacity() - NUMERICAL_EPS, (veh.getNumberParkingReroutes() * pa->getCapacity() / parkingFrustration));
     901       35858 :                 paOccupancy = RandHelper::rand(minOccupancy, (double)pa->getCapacity());
     902             :                 // previously visited?
     903       35858 :                 SUMOTime blockedTime = veh.sawBlockedParkingArea(pa, false);
     904       35858 :                 if (blockedTime >= 0 && SIMSTEP - blockedTime < parkingMemory) {
     905             :                     // assume it's still occupied
     906       18872 :                     paOccupancy = pa->getCapacity();
     907       18872 :                     blockedTimes.push_back(std::make_tuple(blockedTime, pa, i));
     908             : #ifdef DEBUG_PARKING
     909             :                     if (DEBUGCOND) {
     910             :                         std::cout << "    altPA=" << pa->getID() << " was blocked at " << time2string(blockedTime) << "\n";
     911             :                     }
     912             : #endif
     913             :                 }
     914             :             }
     915       49436 :             if (paOccupancy < pa->getCapacity()) {
     916       18091 :                 if (addParkValues(veh, brakeGap, newDestination, pa, paOccupancy, probs[i], router, parkAreas, newRoutes, parkApproaches, maxValues)) {
     917       17805 :                     numAlternatives++;
     918             :                 }
     919       31345 :             } else if (visible) {
     920             :                 // might only be visible now (i.e. because it's on the other
     921             :                 // side of the street), so we should remember this for later.
     922       12294 :                 veh.rememberBlockedParkingArea(pa, &pa->getLane().getEdge() == veh.getEdge());
     923             :             }
     924             :         }
     925       11349 :         if (numAlternatives == 0) {
     926             :             // use parkingArea with lowest blockedTime
     927        5099 :             std::sort(blockedTimes.begin(), blockedTimes.end(),
     928       13678 :             [](std::tuple<SUMOTime, MSParkingArea*, int> const & t1, std::tuple<SUMOTime, MSParkingArea*, int> const & t2) {
     929       13678 :                 if (std::get<0>(t1) < std::get<0>(t2)) {
     930             :                     return true;
     931             :                 }
     932        7710 :                 if (std::get<0>(t1) == std::get<0>(t2)) {
     933           4 :                     if (std::get<1>(t1)->getID() < std::get<1>(t2)->getID()) {
     934             :                         return true;
     935             :                     }
     936           0 :                     if (std::get<1>(t1)->getID() == std::get<1>(t2)->getID()) {
     937           0 :                         return std::get<2>(t1) < std::get<2>(t2);
     938             :                     }
     939             :                 }
     940             :                 return false;
     941             :             }
     942             :                      );
     943        5099 :             for (auto item : blockedTimes) {
     944             :                 MSParkingArea* pa = std::get<1>(item);
     945        4492 :                 double prob = probs[std::get<2>(item)];
     946             :                 // all parking areas are occupied. We have no good basis for
     947             :                 // prefering one or the other based on estimated occupancy
     948        4492 :                 double paOccupancy = RandHelper::rand((double)pa->getCapacity());
     949        4492 :                 if (addParkValues(veh, brakeGap, newDestination, pa, paOccupancy, prob, router, parkAreas, newRoutes, parkApproaches, maxValues)) {
     950             : #ifdef DEBUG_PARKING
     951             :                     if (DEBUGCOND) {
     952             :                         std::cout << "    altPA=" << pa->getID() << " targeting occupied pa based on blockTime " << STEPS2TIME(std::get<0>(item)) << " among " << blockedTimes.size() << " alternatives\n";
     953             :                     }
     954             : #endif
     955             :                     numAlternatives = 1;
     956             :                     break;
     957             :                 }
     958             :                 //std::cout << "  candidate=" << item.second->getID() << " observed=" << time2string(item.first) << "\n";
     959             :             }
     960        5099 :             if (numAlternatives == 0) {
     961             :                 // take any random target but prefer that that haven't been visited yet
     962             :                 std::vector<std::pair<SUMOTime, MSParkingArea*> > candidates;
     963        2397 :                 for (const ParkingAreaVisible& pav : parks) {
     964        1790 :                     if (pav.first == destParkArea) {
     965             :                         continue;
     966             :                     }
     967        1183 :                     SUMOTime dummy = veh.sawBlockedParkingArea(pav.first, true);
     968        1183 :                     if (dummy < 0) {
     969             :                         // randomize among the unvisited
     970         656 :                         dummy = -RandHelper::rand(1000000);
     971             :                     }
     972        1183 :                     candidates.push_back(std::make_pair(dummy, pav.first));
     973             :                 }
     974         607 :                 std::sort(candidates.begin(), candidates.end(),
     975             :                 [](std::tuple<SUMOTime, MSParkingArea*> const & t1, std::tuple<SUMOTime, MSParkingArea*> const & t2) {
     976        2008 :                     return std::get<0>(t1) < std::get<0>(t2) || (std::get<0>(t1) == std::get<0>(t2) && std::get<1>(t1)->getID() < std::get<1>(t2)->getID());
     977             :                 }
     978             :                          );
     979        1038 :                 for (auto item : candidates) {
     980             :                     MSParkingArea* pa = item.second;
     981         607 :                     if (addParkValues(veh, brakeGap, newDestination, pa, 0, 1, router, parkAreas, newRoutes, parkApproaches, maxValues)) {
     982             : #ifdef DEBUG_PARKING
     983             :                         if (DEBUGCOND) {
     984             :                             std::cout << "    altPA=" << pa->getID() << " targeting occupied pa (based on pure randomness) among " << candidates.size() << " alternatives\n";
     985             :                         }
     986             : #endif
     987             :                         numAlternatives = 1;
     988             :                         break;
     989             :                     }
     990             :                 }
     991             :             }
     992             :         }
     993             : 
     994       22698 :         MSNet::getInstance()->getRouterTT(veh.getRNGIndex()); // reset closed edges
     995             : 
     996             : #ifdef DEBUG_PARKING
     997             :         if (DEBUGCOND) {
     998             :             std::cout << "  maxValues=" << joinToString(maxValues, " ", ":") << "\n";
     999             :         }
    1000             : #endif
    1001             : 
    1002             :         // minimum cost to get the parking area
    1003             :         double minParkingCost = 0.0;
    1004             : 
    1005       33822 :         for (MSParkingAreaMap_t::iterator it = parkAreas.begin(); it != parkAreas.end(); ++it) {
    1006             :             // get the parking values
    1007             :             ParkingParamMap_t parkValues = it->second;
    1008             : 
    1009       32909 :             if (weights["probability"] > 0 && maxValues["probability"] > 0.0) {
    1010             :                 // random search should not drive past a usable parking area
    1011             :                 bool dominated = false;
    1012       10436 :                 double endPos = it->first->getEndLanePosition();
    1013       10436 :                 const ConstMSEdgeVector& to1 = parkApproaches[it->first];
    1014             :                 assert(to1.size() > 0);
    1015       33131 :                 for (auto altPa : parkAreas) {
    1016       24559 :                     if (altPa.first == it->first) {
    1017             :                         continue;
    1018             :                     }
    1019       15789 :                     const ConstMSEdgeVector& to2 = parkApproaches[altPa.first];
    1020             :                     assert(to2.size() > 0);
    1021       15789 :                     if (to1.size() > to2.size()) {
    1022        6289 :                         if (std::equal(to2.begin(), to2.end(), to1.begin())) {
    1023             :                             // other target lies on the route to the current candidate
    1024             :                             dominated = true;
    1025             :                             //std::cout << SIMTIME << " rrP veh=" << veh.getID() << " full=" << destParkArea->getID() << " cand=" << it->first->getID() << " onTheWay=" << altPa.first->getID() << "\n";
    1026             :                             break;
    1027             :                         }
    1028        9500 :                     } else if (to1 == to2 && endPos > altPa.first->getEndLanePosition()) {
    1029             :                         // other target is on the same edge but ahead of the current candidate
    1030             :                         dominated = true;
    1031             :                         //std::cout << SIMTIME << " rrP veh=" << veh.getID() << " full=" << destParkArea->getID() << " cand=" << it->first->getID() << " sameEdge=" << altPa.first->getID() << "\n";
    1032             :                         break;
    1033             :                     }
    1034             :                 }
    1035             :                 double prob = 0;
    1036             :                 if (!dominated) {
    1037        8572 :                     prob = RandHelper::rand(parkValues["probability"], veh.getRNG());
    1038        8572 :                     parkValues["probability"] = 1.0 - prob / maxValues["probability"];
    1039             :                 } else {
    1040             :                     // worst probability score
    1041        1864 :                     parkValues["probability"] = 1.0;
    1042             :                 }
    1043             :             } else {
    1044             :                 // value takes no effect due to weight=0
    1045       12037 :                 parkValues["probability"] = 0;
    1046             :             }
    1047             :             // normalizing with maximum values (we want to maximize some parameters then we reverse the value)
    1048       67419 :             parkValues["capacity"] = maxValues["capacity"] > 0.0 ? 1.0 - parkValues["capacity"] / maxValues["capacity"] : 0.0;
    1049       67419 :             parkValues["absfreespace"] = maxValues["absfreespace"] > 0.0 ? 1.0 - parkValues["absfreespace"] / maxValues["absfreespace"] : 0.0;
    1050       67419 :             parkValues["relfreespace"] = maxValues["relfreespace"] > 0.0 ? 1.0 - parkValues["relfreespace"] / maxValues["relfreespace"] : 0.0;
    1051             : 
    1052       67409 :             parkValues["distanceto"] = maxValues["distanceto"] > 0.0 ? parkValues["distanceto"] / maxValues["distanceto"] : 0.0;
    1053       67419 :             parkValues["timeto"] = maxValues["timeto"] > 0.0 ? parkValues["timeto"] / maxValues["timeto"] : 0.0;
    1054             : 
    1055       65097 :             parkValues["distancefrom"] = maxValues["distancefrom"] > 0.0 ? parkValues["distancefrom"] / maxValues["distancefrom"] : 0.0;
    1056       65097 :             parkValues["timefrom"] = maxValues["timefrom"] > 0.0 ? parkValues["timefrom"] / maxValues["timefrom"] : 0.0;
    1057             : 
    1058             :             // get the parking area cost
    1059       22473 :             double parkingCost = 0.0;
    1060             : 
    1061             :             // sum every index with its weight
    1062      202257 :             for (ParkingParamMap_t::iterator pc = parkValues.begin(); pc != parkValues.end(); ++pc) {
    1063      179784 :                 parkingCost += weights[pc->first] * pc->second;
    1064             :             }
    1065       22473 :             veh.rememberParkingAreaScore(it->first, toString(parkingCost)
    1066             :                                          //+ " rfs=" + toString(parkValues["relfreespace"])
    1067             :                                          //+ " dt=" + toString(parkValues["distanceto"])
    1068             :                                          //+ " p=" + toString(parkValues["probability"])
    1069             :                                         );
    1070             : 
    1071             :             // get the parking area with minimum cost
    1072       22473 :             if (nearParkArea == nullptr || parkingCost < minParkingCost) {
    1073       14370 :                 minParkingCost = parkingCost;
    1074       14370 :                 nearParkArea = it->first;
    1075       14370 :                 newRoute = newRoutes[nearParkArea];
    1076             :             }
    1077             : 
    1078             : #ifdef DEBUG_PARKING
    1079             :             if (DEBUGCOND) {
    1080             :                 std::cout << "    altPA=" << it->first->getID() << " score=" << parkingCost << " vals=" << joinToString(parkValues, " ", ":") << "\n";
    1081             :             }
    1082             : #endif
    1083             :         }
    1084       11349 :         veh.setNumberParkingReroutes(veh.getNumberParkingReroutes() + 1);
    1085             :     } else {
    1086             : #ifdef DEBUG_PARKING
    1087             :         if (DEBUGCOND) {
    1088             :             std::cout << SIMTIME << " rerouter=" << getID() << " veh=" << veh.getID() << " rerouteParkingArea dest=" << destParkArea->getID() << " sufficient space\n";
    1089             :         }
    1090             : #endif
    1091             :     }
    1092             : 
    1093             : #ifdef DEBUG_PARKING
    1094             :     if (DEBUGCOND) {
    1095             :         std::cout << "  parkingResult=" << Named::getIDSecure(nearParkArea) << "\n";
    1096             :     }
    1097             : #endif
    1098             : 
    1099       14969 :     return nearParkArea;
    1100             : }
    1101             : 
    1102             : 
    1103             : bool
    1104       23209 : MSTriggeredRerouter::addParkValues(SUMOVehicle& veh, double brakeGap, bool newDestination,
    1105             :                                    MSParkingArea* pa, double paOccupancy, double prob,
    1106             :                                    SUMOAbstractRouter<MSEdge, SUMOVehicle>& router,
    1107             :                                    MSParkingAreaMap_t& parkAreas,
    1108             :                                    std::map<MSParkingArea*, ConstMSEdgeVector>& newRoutes,
    1109             :                                    std::map<MSParkingArea*, ConstMSEdgeVector>& parkApproaches,
    1110             :                                    ParkingParamMap_t& maxValues) {
    1111             :     // a map stores the parking values
    1112             :     ParkingParamMap_t parkValues;
    1113             : 
    1114       23209 :     const MSRoute& route = veh.getRoute();
    1115       23209 :     const RGBColor& c = route.getColor();
    1116       23209 :     const MSEdge* parkEdge = &(pa->getLane().getEdge());
    1117             : 
    1118       23209 :     const bool includeInternalLengths = MSGlobals::gUsingInternalLanes && MSNet::getInstance()->hasInternalLinks();
    1119             : 
    1120             :     // Compute the route from the current edge to the parking area edge
    1121             :     ConstMSEdgeVector edgesToPark;
    1122       23209 :     const double parkPos = pa->getLastFreePos(veh);
    1123       23209 :     const MSEdge* rerouteOrigin = *veh.getRerouteOrigin();
    1124       23209 :     router.compute(rerouteOrigin, veh.getPositionOnLane(), parkEdge, parkPos, &veh, MSNet::getInstance()->getCurrentTimeStep(), edgesToPark, true);
    1125             : 
    1126             : #ifdef DEBUG_PARKING
    1127             :     if (DEBUGCOND) {
    1128             :         std::cout << "    altPA=" << pa->getID() << " vehEdge=" << veh.getEdge()->getID() << " parkEdge " << parkEdge->getID() << " edgesToPark=" << edgesToPark.size() << "\n";
    1129             :     }
    1130             : #endif
    1131             : 
    1132       23209 :     if (edgesToPark.size() > 0) {
    1133             :         // Compute the route from the parking area edge to the end of the route
    1134       22737 :         if (rerouteOrigin != veh.getEdge()) {
    1135           5 :             edgesToPark.insert(edgesToPark.begin(), veh.getEdge());
    1136             :         }
    1137             :         ConstMSEdgeVector edgesFromPark;
    1138       22737 :         parkApproaches[pa] = edgesToPark;
    1139             : 
    1140       22737 :         const MSEdge* nextDestination = route.getLastEdge();
    1141       22737 :         double nextPos = veh.getArrivalPos();
    1142       22737 :         int nextDestinationIndex = route.size() - 1;
    1143       22737 :         if (!newDestination) {
    1144       21576 :             std::vector<std::pair<int, double> > stopIndices = veh.getStopIndices();
    1145       21576 :             if (stopIndices.size() > 1) {
    1146          45 :                 nextDestinationIndex = stopIndices[1].first;
    1147          45 :                 nextDestination = route.getEdges()[nextDestinationIndex];
    1148          45 :                 nextPos = stopIndices[1].second;
    1149             : 
    1150             :             }
    1151       21576 :             router.compute(parkEdge, parkPos, nextDestination, nextPos,  &veh, MSNet::getInstance()->getCurrentTimeStep(), edgesFromPark, true);
    1152             :         }
    1153             : #ifdef DEBUG_PARKING
    1154             :         if (DEBUGCOND) {
    1155             :             //std::cout << "    altPA=" << pa->getID() << " parkEdge=" << parkEdge->getID() << " nextDest=" << nextDestination->getID() << " edgesFromPark=" << edgesFromPark.size() << "\n";
    1156             :         }
    1157             : #endif
    1158             : 
    1159       22737 :         if (edgesFromPark.size() > 0 || newDestination) {
    1160             : 
    1161       22737 :             parkValues["probability"] = prob;
    1162             : 
    1163       22737 :             if (parkValues["probability"] > maxValues["probability"]) {
    1164       11132 :                 maxValues["probability"] = parkValues["probability"];
    1165             :             }
    1166             : 
    1167       22737 :             parkValues["capacity"] = (double)(pa->getCapacity());
    1168       22737 :             parkValues["absfreespace"] = (double)(pa->getCapacity() - paOccupancy);
    1169             :             // if capacity = 0 then absfreespace and relfreespace are also 0
    1170       45474 :             parkValues["relfreespace"] = parkValues["absfreespace"] / MAX2(1.0, parkValues["capacity"]);
    1171             : 
    1172       22737 :             if (parkValues["capacity"] > maxValues["capacity"]) {
    1173       11132 :                 maxValues["capacity"] = parkValues["capacity"];
    1174             :             }
    1175             : 
    1176       22737 :             if (parkValues["absfreespace"] > maxValues["absfreespace"]) {
    1177       14970 :                 maxValues["absfreespace"] = parkValues["absfreespace"];
    1178             :             }
    1179             : 
    1180       22737 :             if (parkValues["relfreespace"] > maxValues["relfreespace"]) {
    1181       15160 :                 maxValues["relfreespace"] = parkValues["relfreespace"];
    1182             :             }
    1183             : 
    1184       22737 :             MSRoute routeToPark(route.getID() + "!topark#1", edgesToPark, false,
    1185       45474 :                                 &c == &RGBColor::DEFAULT_COLOR ? nullptr : new RGBColor(c), route.getStops());
    1186             : 
    1187             :             // The distance from the current edge to the new parking area
    1188       22737 :             double toPos = pa->getBeginLanePosition();
    1189       22737 :             if (&pa->getLane().getEdge() == veh.getEdge()) {
    1190         461 :                 toPos = MAX2(veh.getPositionOnLane(), toPos);
    1191             :             }
    1192       22737 :             parkValues["distanceto"] = routeToPark.getDistanceBetween(veh.getPositionOnLane(), toPos,
    1193       22737 :                                        routeToPark.begin(), routeToPark.end() - 1, includeInternalLengths);
    1194             : 
    1195       22737 :             if (parkValues["distanceto"] == std::numeric_limits<double>::max()) {
    1196           0 :                 WRITE_WARNINGF(TL("Invalid distance computation for vehicle '%' to parkingArea '%' at time=%."),
    1197             :                                veh.getID(), pa->getID(), time2string(SIMSTEP));
    1198             :             }
    1199       22737 :             const double endPos = pa->getOccupancy() == pa->getCapacity()
    1200       22737 :                                   ? pa->getLastFreePos(veh, veh.getPositionOnLane() + brakeGap)
    1201        8432 :                                   : pa->getEndLanePosition();
    1202       22737 :             const double distToEnd = parkValues["distanceto"] - toPos + endPos;
    1203             : #ifdef DEBUG_PARKING
    1204             :             if (DEBUGCOND) {
    1205             :                 std::cout << "      " << veh.getID() << " candidate=" << pa->getID()
    1206             :                           << " distanceTo=" << parkValues["distanceto"]
    1207             :                           << " brakeGap=" << brakeGap
    1208             :                           << " routeToPark=" << toString(edgesToPark)
    1209             :                           << " vehPos=" << veh.getPositionOnLane()
    1210             :                           << " begPos=" << pa->getBeginLanePosition()
    1211             :                           << " toPos=" << toPos
    1212             :                           << " endPos=" << pa->getEndLanePosition()
    1213             :                           << " distToEnd=" << distToEnd
    1214             :                           << "\n";
    1215             :             }
    1216             : #endif
    1217             : 
    1218       22737 :             if (distToEnd < brakeGap) {
    1219         245 :                 veh.rememberParkingAreaScore(pa, "tooClose");
    1220             : #ifdef DEBUG_PARKING
    1221             :                 if (DEBUGCOND) {
    1222             :                     std::cout << "    altPA=" << pa->getID() << " too close to brake (dist=" << distToEnd << " brakeGap=" << brakeGap << "\n";
    1223             :                 }
    1224             : #endif
    1225         245 :                 return false;
    1226             :             }
    1227             : 
    1228             :             // The time to reach the new parking area
    1229       22492 :             parkValues["timeto"] = router.recomputeCosts(edgesToPark, &veh, MSNet::getInstance()->getCurrentTimeStep());
    1230             : 
    1231       22492 :             if (parkValues["distanceto"] > maxValues["distanceto"]) {
    1232       17400 :                 maxValues["distanceto"] = parkValues["distanceto"];
    1233             :             }
    1234             : 
    1235       22492 :             if (parkValues["timeto"] > maxValues["timeto"]) {
    1236       17023 :                 maxValues["timeto"] = parkValues["timeto"];
    1237             :             }
    1238             : 
    1239       22492 :             ConstMSEdgeVector newEdges = edgesToPark;
    1240             : 
    1241       22492 :             if (newDestination) {
    1242        1161 :                 parkValues["distancefrom"] = 0;
    1243        1161 :                 parkValues["timefrom"] = 0;
    1244             :             } else {
    1245       21331 :                 MSRoute routeFromPark(route.getID() + "!frompark#1", edgesFromPark, false,
    1246       42662 :                                       &c == &RGBColor::DEFAULT_COLOR ? nullptr : new RGBColor(c), route.getStops());
    1247             :                 // The distance from the new parking area to the end of the route
    1248       21331 :                 parkValues["distancefrom"] = routeFromPark.getDistanceBetween(pa->getBeginLanePosition(), routeFromPark.getLastEdge()->getLength(),
    1249       21331 :                                              routeFromPark.begin(), routeFromPark.end() - 1, includeInternalLengths);
    1250       21331 :                 if (parkValues["distancefrom"] == std::numeric_limits<double>::max()) {
    1251           0 :                     WRITE_WARNINGF(TL("Invalid distance computation for vehicle '%' from parkingArea '%' at time=%."),
    1252             :                                    veh.getID(), pa->getID(), time2string(SIMSTEP));
    1253             :                 }
    1254             :                 // The time to reach this area
    1255       21331 :                 parkValues["timefrom"] = router.recomputeCosts(edgesFromPark, &veh, SIMSTEP);
    1256       21331 :                 newEdges.insert(newEdges.end(), edgesFromPark.begin() + 1, edgesFromPark.end());
    1257       21331 :                 newEdges.insert(newEdges.end(), route.begin() + nextDestinationIndex + 1, route.end());
    1258       21331 :             }
    1259             : 
    1260       22492 :             if (parkValues["distancefrom"] > maxValues["distancefrom"]) {
    1261       15900 :                 maxValues["distancefrom"] = parkValues["distancefrom"];
    1262             :             }
    1263             : 
    1264       22492 :             if (parkValues["timefrom"] > maxValues["timefrom"]) {
    1265       15656 :                 maxValues["timefrom"] = parkValues["timefrom"];
    1266             :             }
    1267             : 
    1268       22492 :             parkAreas[pa] = parkValues;
    1269       22492 :             newRoutes[pa] = newEdges;
    1270             : 
    1271             :             return true;
    1272       22737 :         } else {
    1273           0 :             veh.rememberParkingAreaScore(pa, "destUnreachable");
    1274             :         }
    1275             :     } else {
    1276         944 :         veh.rememberParkingAreaScore(pa, "unreachable");
    1277             :     }
    1278             : #ifdef DEBUG_PARKING
    1279             :     if (DEBUGCOND) {
    1280             :         std::cout << "    altPA=" << pa->getID() << " disconnected\n";
    1281             :     }
    1282             : #endif
    1283             :     // unreachable
    1284             :     return false;
    1285             : }
    1286             : 
    1287             : 
    1288             : bool
    1289     1555087 : MSTriggeredRerouter::applies(const SUMOTrafficObject& obj) const {
    1290     1555087 :     if (myVehicleTypes.empty() || myVehicleTypes.count(obj.getVehicleType().getOriginalID()) > 0) {
    1291     1554297 :         return true;
    1292             :     } else {
    1293        1580 :         std::set<std::string> vTypeDists = MSNet::getInstance()->getVehicleControl().getVTypeDistributionMembership(obj.getVehicleType().getOriginalID());
    1294         790 :         for (auto vTypeDist : vTypeDists) {
    1295             :             if (myVehicleTypes.count(vTypeDist) > 0) {
    1296             :                 return true;
    1297             :             }
    1298             :         }
    1299         790 :         return false;
    1300             :     }
    1301             : }
    1302             : 
    1303             : 
    1304             : bool
    1305      163864 : MSTriggeredRerouter::affected(const std::set<SUMOTrafficObject::NumericalID>& edgeIndices, const MSEdgeVector& closed) {
    1306      183179 :     for (const MSEdge* const e : closed) {
    1307       87390 :         if (edgeIndices.count(e->getNumericalID()) > 0) {
    1308             :             return true;
    1309             :         }
    1310             :     }
    1311             :     return false;
    1312             : }
    1313             : 
    1314             : 
    1315             : void
    1316       20385 : MSTriggeredRerouter::checkParkingRerouteConsistency() {
    1317             :     // if a parkingArea is a rerouting target, it should generally have a
    1318             :     // rerouter on its edge or vehicles will be stuck there once it's full.
    1319             :     // The user should receive a Warning in this case
    1320             :     std::set<MSEdge*> parkingRerouterEdges;
    1321             :     std::map<MSParkingArea*, std::string, ComparatorIdLess> targetedParkingArea; // paID -> targetingRerouter
    1322       23674 :     for (const auto& rr : myInstances) {
    1323             :         bool hasParkingReroute = false;
    1324        6561 :         for (const RerouteInterval& interval : rr.second->myIntervals) {
    1325        3272 :             if (interval.parkProbs.getOverallProb() > 0) {
    1326             :                 hasParkingReroute = true;
    1327       13593 :                 for (const ParkingAreaVisible& pav : interval.parkProbs.getVals()) {
    1328       11907 :                     targetedParkingArea[pav.first] = rr.first;
    1329             :                 }
    1330             :             }
    1331             :         }
    1332        3289 :         if (hasParkingReroute) {
    1333        1686 :             parkingRerouterEdges.insert(rr.second->myEdges.begin(), rr.second->myEdges.end());
    1334             :         }
    1335             :     }
    1336       22635 :     for (const auto& item : targetedParkingArea) {
    1337        2250 :         if (parkingRerouterEdges.count(&item.first->getLane().getEdge()) == 0) {
    1338        1065 :             WRITE_WARNINGF(TL("ParkingArea '%' is targeted by rerouter '%' but doesn't have its own rerouter. This may cause parking search to abort."),
    1339             :                            item.first->getID(), item.second);
    1340             :         }
    1341             :     }
    1342       20385 : }
    1343             : 
    1344             : 
    1345             : /****************************************************************************/

Generated by: LCOV version 1.14