LCOV - code coverage report
Current view: top level - src/microsim/devices - MSDevice_Vehroutes.cpp (source / functions) Coverage Total Hit
Test: lcov.info Lines: 95.9 % 341 327
Test Date: 2025-11-13 15:38:19 Functions: 95.0 % 20 19

            Line data    Source code
       1              : /****************************************************************************/
       2              : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
       3              : // Copyright (C) 2009-2025 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    MSDevice_Vehroutes.cpp
      15              : /// @author  Daniel Krajzewicz
      16              : /// @author  Laura Bieker
      17              : /// @author  Michael Behrisch
      18              : /// @author  Jakob Erdmann
      19              : /// @date    Fri, 30.01.2009
      20              : ///
      21              : // A device which collects info on the vehicle trip
      22              : /****************************************************************************/
      23              : #include <config.h>
      24              : 
      25              : #include <microsim/MSGlobals.h>
      26              : #include <microsim/MSNet.h>
      27              : #include <microsim/MSLane.h>
      28              : #include <microsim/MSEdge.h>
      29              : #include <microsim/MSRoute.h>
      30              : #include <microsim/MSStop.h>
      31              : #include <microsim/MSVehicle.h>
      32              : #include <microsim/MSVehicleType.h>
      33              : #include <microsim/transportables/MSTransportableControl.h>
      34              : #include <utils/vehicle/SUMOVehicle.h>
      35              : #include <utils/options/OptionsCont.h>
      36              : #include <utils/iodevices/OutputDevice_String.h>
      37              : #include <utils/xml/SUMOSAXAttributes.h>
      38              : #include "MSDevice_Vehroutes.h"
      39              : 
      40              : 
      41              : // ===========================================================================
      42              : // static member variables
      43              : // ===========================================================================
      44              : bool MSDevice_Vehroutes::mySaveExits = false;
      45              : bool MSDevice_Vehroutes::myLastRouteOnly = false;
      46              : bool MSDevice_Vehroutes::myDUAStyle = false;
      47              : bool MSDevice_Vehroutes::myWriteCosts = false;
      48              : bool MSDevice_Vehroutes::mySorted = false;
      49              : bool MSDevice_Vehroutes::myIntendedDepart = false;
      50              : bool MSDevice_Vehroutes::myRouteLength = false;
      51              : bool MSDevice_Vehroutes::mySkipPTLines = false;
      52              : bool MSDevice_Vehroutes::myIncludeIncomplete = false;
      53              : bool MSDevice_Vehroutes::myWriteStopPriorEdges = false;
      54              : bool MSDevice_Vehroutes::myWriteInternal = false;
      55              : MSDevice_Vehroutes::StateListener MSDevice_Vehroutes::myStateListener;
      56              : MSDevice_Vehroutes::SortedRouteInfo MSDevice_Vehroutes::myRouteInfos;
      57              : 
      58              : 
      59              : // ===========================================================================
      60              : // method definitions
      61              : // ===========================================================================
      62              : // ---------------------------------------------------------------------------
      63              : // static initialisation methods
      64              : // ---------------------------------------------------------------------------
      65              : void
      66        38602 : MSDevice_Vehroutes::init() {
      67        38602 :     const OptionsCont& oc = OptionsCont::getOptions();
      68        77204 :     if (oc.isSet("vehroute-output")) {
      69        11544 :         OutputDevice::createDeviceByOption("vehroute-output", "routes", "routes_file.xsd");
      70         5763 :         mySaveExits = oc.getBool("vehroute-output.exit-times");
      71         5763 :         myLastRouteOnly = oc.getBool("vehroute-output.last-route");
      72         5763 :         myDUAStyle = oc.getBool("vehroute-output.dua");
      73         5763 :         myWriteCosts = oc.getBool("vehroute-output.cost");
      74         5763 :         mySorted = myDUAStyle || oc.getBool("vehroute-output.sorted");
      75         5763 :         myIntendedDepart = oc.getBool("vehroute-output.intended-depart");
      76         5763 :         myRouteLength = oc.getBool("vehroute-output.route-length");
      77         5763 :         mySkipPTLines = oc.getBool("vehroute-output.skip-ptlines");
      78         5763 :         myIncludeIncomplete = oc.getBool("vehroute-output.incomplete");
      79         5763 :         myWriteStopPriorEdges = oc.getBool("vehroute-output.stop-edges");
      80         5763 :         myWriteInternal = oc.getBool("vehroute-output.internal");
      81         5763 :         MSNet::getInstance()->addVehicleStateListener(&myStateListener);
      82         5763 :         myRouteInfos.routeOut = &OutputDevice::getDeviceByOption("vehroute-output");
      83              :     }
      84        38596 : }
      85              : 
      86              : 
      87              : void
      88        39784 : MSDevice_Vehroutes::insertOptions(OptionsCont& oc) {
      89        39784 :     oc.addOptionSubTopic("Vehroutes Device");
      90        79568 :     insertDefaultAssignmentOptions("vehroute", "Vehroutes Device", oc);
      91        39784 : }
      92              : 
      93              : 
      94              : MSDevice_Vehroutes*
      95      6162231 : MSDevice_Vehroutes::buildVehicleDevices(SUMOVehicle& v, std::vector<MSVehicleDevice*>& into, int maxRoutes) {
      96      6162231 :     if (maxRoutes < std::numeric_limits<int>::max()) {
      97      1582302 :         return new MSDevice_Vehroutes(v, "vehroute_" + v.getID(), maxRoutes);
      98              :     }
      99      5371080 :     if (mySkipPTLines && v.getParameter().line != "") {
     100              :         return nullptr;
     101              :     }
     102      5369954 :     OptionsCont& oc = OptionsCont::getOptions();
     103     10739908 :     if (equippedByDefaultAssignmentOptions(oc, "vehroute", v, oc.isSet("vehroute-output"))) {
     104       136780 :         if (myLastRouteOnly) {
     105              :             maxRoutes = 0;
     106              :         }
     107       136780 :         myStateListener.myDevices[&v] = new MSDevice_Vehroutes(v, "vehroute_" + v.getID(), maxRoutes);
     108       136780 :         into.push_back(myStateListener.myDevices[&v]);
     109       136780 :         return myStateListener.myDevices[&v];
     110              :     }
     111              :     return nullptr;
     112              : }
     113              : 
     114              : 
     115              : // ---------------------------------------------------------------------------
     116              : // MSDevice_Vehroutes::StateListener-methods
     117              : // ---------------------------------------------------------------------------
     118              : void
     119       519555 : MSDevice_Vehroutes::StateListener::vehicleStateChanged(const SUMOVehicle* const vehicle, MSNet::VehicleState to, const std::string& info) {
     120       519555 :     if (to == MSNet::VehicleState::NEWROUTE) {
     121              :         const auto& deviceEntry = myDevices.find(vehicle);
     122        98387 :         if (deviceEntry != myDevices.end()) {
     123        97004 :             deviceEntry->second->addRoute(info);
     124              :         }
     125              :     }
     126       519555 : }
     127              : 
     128              : 
     129              : // ---------------------------------------------------------------------------
     130              : // MSDevice_Vehroutes-methods
     131              : // ---------------------------------------------------------------------------
     132       927931 : MSDevice_Vehroutes::MSDevice_Vehroutes(SUMOVehicle& holder, const std::string& id, int maxRoutes) :
     133              :     MSVehicleDevice(holder, id),
     134       927931 :     myCurrentRoute(holder.getRoutePtr()),
     135       927931 :     myMaxRoutes(maxRoutes),
     136       927931 :     myLastSavedAt(nullptr),
     137       927931 :     myLastRouteIndex(-1),
     138       927931 :     myDepartLane(-1),
     139       927931 :     myDepartPos(-1),
     140       927931 :     myDepartSpeed(-1),
     141       927931 :     myDepartPosLat(0),
     142       927931 :     myStopOut(2) {
     143       927931 : }
     144              : 
     145              : 
     146      1855754 : MSDevice_Vehroutes::~MSDevice_Vehroutes() {
     147       927877 :     myStateListener.myDevices.erase(&myHolder);
     148      1855754 : }
     149              : 
     150              : 
     151              : bool
     152     12824017 : MSDevice_Vehroutes::notifyEnter(SUMOTrafficObject& veh, MSMoveReminder::Notification reason, const MSLane* enteredLane) {
     153     12824017 :     if (reason == MSMoveReminder::NOTIFICATION_DEPARTED) {
     154       762748 :         if (mySorted && myStateListener.myDevices[static_cast<SUMOVehicle*>(&veh)] == this) {
     155         4586 :             const SUMOTime departure = myIntendedDepart ? myHolder.getParameter().depart : MSNet::getInstance()->getCurrentTimeStep();
     156         4586 :             myRouteInfos.departureCounts[departure]++;
     157              :         }
     158       762748 :         if (!MSGlobals::gUseMesoSim) {
     159              :             const MSVehicle& vehicle = static_cast<MSVehicle&>(veh);
     160       455213 :             myDepartLane = vehicle.getLane()->getIndex();
     161       455213 :             myDepartPosLat = vehicle.getLateralPositionOnLane();
     162              :         }
     163       762748 :         myDepartSpeed = veh.getSpeed();
     164       762748 :         myDepartPos = veh.getPositionOnLane();
     165              :     }
     166     12824017 :     if (myWriteStopPriorEdges) {
     167           68 :         if (MSGlobals::gUseMesoSim) {
     168           48 :             const MSEdge* e = veh.getEdge();
     169           48 :             if (myPriorEdges.empty() || myPriorEdges.back() != e) {
     170           12 :                 myPriorEdges.push_back(e);
     171              :             }
     172              :         } else {
     173           20 :             myPriorEdges.push_back(&enteredLane->getEdge());
     174              :         }
     175              :     }
     176     12824017 :     myLastRouteIndex = myHolder.getRoutePosition();
     177     12824017 :     return true;
     178              : }
     179              : 
     180              : 
     181              : bool
     182     12790167 : MSDevice_Vehroutes::notifyLeave(SUMOTrafficObject& veh, double /*lastPos*/, MSMoveReminder::Notification reason, const MSLane* /* enteredLane */) {
     183     12790167 :     if (mySaveExits && reason != NOTIFICATION_LANE_CHANGE && reason != NOTIFICATION_PARKING && reason != NOTIFICATION_SEGMENT) {
     184       275813 :         const MSEdge* edge = myWriteInternal ? dynamic_cast<MSBaseVehicle&>(veh).getCurrentEdge() : veh.getEdge();
     185       275813 :         if (myLastSavedAt != edge) {
     186       155598 :             myExits.push_back(MSNet::getInstance()->getCurrentTimeStep());
     187       155598 :             myLastSavedAt = edge;
     188              :         }
     189              :     }
     190     12790167 :     return true;
     191              : }
     192              : 
     193              : 
     194              : void
     195        20773 : MSDevice_Vehroutes::notifyStopEnded() {
     196        20773 :     SUMOVehicleParameter::Stop stop = myHolder.getStops().front().pars;
     197        20773 :     const bool closeLater = myWriteStopPriorEdges || mySaveExits;
     198        20773 :     if (mySaveExits) {
     199              :         // prevent duplicate output
     200         1567 :         stop.parametersSet &=  ~(STOP_STARTED_SET | STOP_ENDED_SET);
     201              :     }
     202        20773 :     stop.write(myStopOut, !closeLater);
     203        20773 :     if (myWriteStopPriorEdges) {
     204              :         // calculate length
     205           16 :         double priorEdgesLength = 0;
     206           40 :         for (int i = 0; i < (int)myPriorEdges.size(); i++) {
     207           24 :             if (i == 0) {
     208           16 :                 priorEdgesLength += myPriorEdges.at(i)->getLength();
     209            8 :             } else if (myPriorEdges.at(i)->getID() != myPriorEdges.at(i - 1)->getID()) {
     210            8 :                 priorEdgesLength += myPriorEdges.at(i)->getLength();
     211              :             }
     212              :         }
     213           32 :         myStopOut.writeAttr("priorEdges", myPriorEdges);
     214              :         myPriorEdges.clear();
     215           32 :         myStopOut.writeAttr("priorEdgesLength", priorEdgesLength);
     216              :     }
     217        20773 :     if (mySaveExits) {
     218         1567 :         myStopOut.writeAttr(SUMO_ATTR_STARTED, time2string(stop.started));
     219         3134 :         myStopOut.writeAttr(SUMO_ATTR_ENDED, stop.ended < 0 ? "-1" : time2string(stop.ended));
     220              :     }
     221        20773 :     if (closeLater) {
     222         3166 :         myStopOut.closeTag();
     223              :     }
     224        20773 : }
     225              : 
     226              : 
     227              : void
     228       163413 : MSDevice_Vehroutes::writeXMLRoute(OutputDevice& os, int index) const {
     229         9707 :     if (index == 0 && !myIncludeIncomplete && myReplacedRoutes[index].route->size() == 2 &&
     230       167050 :             myReplacedRoutes[index].route->getEdges().front()->isTazConnector() &&
     231            0 :             myReplacedRoutes[index].route->getEdges().back()->isTazConnector()) {
     232              :         return;
     233              :     }
     234              :     // check if a previous route shall be written
     235              :     //std::cout << " writeXMLRoute index=" << index << " numReroutes=" << myHolder.getNumberReroutes() << "\n";
     236       163413 :     const int routesToSkip = myHolder.getParameter().wasSet(VEHPARS_FORCE_REROUTE) ? 1 : 0;
     237       163413 :     os.openTag(SUMO_TAG_ROUTE);
     238       163413 :     if (index >= 0) {
     239              :         assert((int)myReplacedRoutes.size() > index);
     240        36933 :         if (myDUAStyle || myWriteCosts) {
     241        14532 :             os.writeAttr(SUMO_ATTR_COST, myReplacedRoutes[index].route->getCosts());
     242              :         }
     243        36933 :         if (myWriteCosts) {
     244        14532 :             os.writeAttr(SUMO_ATTR_SAVINGS, myReplacedRoutes[index].route->getSavings());
     245              :         }
     246              :         // write edge on which the vehicle was when the route was valid
     247       109454 :         os.writeAttr("replacedOnEdge", (myReplacedRoutes[index].edge ?
     248              :                                         myReplacedRoutes[index].edge->getID() : ""));
     249        36933 :         if (myReplacedRoutes[index].lastRouteIndex > 0) {
     250              :             // do not write the default
     251        25161 :             os.writeAttr(SUMO_ATTR_REPLACED_ON_INDEX, myReplacedRoutes[index].lastRouteIndex);
     252              :         }
     253              :         // write the reason for replacement
     254        73866 :         os.writeAttr("reason", myReplacedRoutes[index].info);
     255              : 
     256              :         // write the time at which the route was replaced
     257        36933 :         os.writeAttr(SUMO_ATTR_REPLACED_AT_TIME, time2string(myReplacedRoutes[index].time));
     258        36933 :         os.writeAttr(SUMO_ATTR_PROB, "0");
     259        36933 :         OutputDevice_String edgesD;
     260              :         // always write the part that was actually driven and the rest of the current route that wasn't yet driven
     261              :         int start = 0;
     262       157643 :         for (int i = routesToSkip; i < index; i++) {
     263       120710 :             if (myReplacedRoutes[i].edge != nullptr) {
     264       119902 :                 int end = myReplacedRoutes[i].lastRouteIndex;
     265       119902 :                 myReplacedRoutes[i].route->writeEdgeIDs(edgesD, start, end, myWriteInternal, myHolder.getVClass());
     266              :             }
     267       120710 :             start = myReplacedRoutes[i].newRouteIndex;
     268              :         }
     269        36933 :         myReplacedRoutes[index].route->writeEdgeIDs(edgesD, start, -1, myWriteInternal, myHolder.getVClass());
     270        36933 :         std::string edgesS = edgesD.getString();
     271              :         edgesS.pop_back(); // remove last ' '
     272        36933 :         os.writeAttr(SUMO_ATTR_EDGES, edgesS);
     273        36933 :         if (myRouteLength) {
     274         7133 :             const bool includeInternalLengths = MSGlobals::gUsingInternalLanes && MSNet::getInstance()->hasInternalLinks();
     275              :             ConstMSRoutePtr route = myReplacedRoutes[index].route;
     276         7133 :             const double routeLength = route->getDistanceBetween(myHolder.getDepartPos(), route->getEdges().back()->getLength(),
     277         7133 :                                        route->begin(), route->end(), includeInternalLengths);
     278        14266 :             os.writeAttr("routeLength", routeLength);
     279              :         }
     280        36933 :     } else {
     281       126480 :         if (myDUAStyle || myWriteCosts) {
     282        32889 :             os.writeAttr(SUMO_ATTR_COST, myHolder.getRoute().getCosts());
     283              :         }
     284       126480 :         if (myWriteCosts) {
     285        32883 :             os.writeAttr(SUMO_ATTR_SAVINGS, myHolder.getRoute().getSavings());
     286              :         }
     287       126480 :         OutputDevice_String edgesD;
     288              :         int numWritten = 0;
     289              :         int start = 0;
     290       126480 :         if (myHolder.getNumberReroutes() > 0) {
     291              :             assert((int)myReplacedRoutes.size() <= myHolder.getNumberReroutes());
     292        93703 :             for (int i = routesToSkip; i < (int)myReplacedRoutes.size(); i++) {
     293        36245 :                 if (myReplacedRoutes[i].edge != nullptr) {
     294        35125 :                     int end = myReplacedRoutes[i].lastRouteIndex;
     295        35125 :                     numWritten += myReplacedRoutes[i].route->writeEdgeIDs(edgesD, start, end, myWriteInternal, myHolder.getVClass());
     296              :                 }
     297        36245 :                 start = myReplacedRoutes[i].newRouteIndex;
     298              :             }
     299              :         }
     300       126480 :         numWritten += myCurrentRoute->writeEdgeIDs(edgesD, start, -1, myWriteInternal, myHolder.getVClass());
     301       126480 :         std::string edgesS = edgesD.getString();
     302              :         edgesS.pop_back(); // remove last ' '
     303       126480 :         os.writeAttr(SUMO_ATTR_EDGES, edgesS);
     304              : 
     305       126480 :         if (mySaveExits) {
     306              :             std::vector<std::string> exits;
     307       134096 :             for (SUMOTime t : myExits) {
     308       247884 :                 exits.push_back(time2string(t));
     309              :             }
     310              :             assert(numWritten >= (int)myExits.size());
     311        20308 :             std::vector<std::string> missing(numWritten - (int)myExits.size(), "-1");
     312        10154 :             exits.insert(exits.end(), missing.begin(), missing.end());
     313        10154 :             os.writeAttr(SUMO_ATTR_EXITTIMES, exits);
     314        10154 :         }
     315       126480 :     }
     316       326826 :     os.closeTag();
     317              : }
     318              : 
     319              : 
     320              : void
     321       125290 : MSDevice_Vehroutes::generateOutput(OutputDevice* /*tripinfoOut*/) const {
     322       125290 :     writeOutput(true);
     323       125290 : }
     324              : 
     325              : 
     326              : void
     327       126486 : MSDevice_Vehroutes::writeOutput(const bool hasArrived) const {
     328       126486 :     const OptionsCont& oc = OptionsCont::getOptions();
     329       126486 :     OutputDevice& routeOut = OutputDevice::getDeviceByOption("vehroute-output");
     330       126486 :     OutputDevice_String od(1);
     331       126486 :     SUMOVehicleParameter tmp = myHolder.getParameter();
     332       126486 :     tmp.depart = myIntendedDepart ? myHolder.getParameter().depart : myHolder.getDeparture();
     333       126486 :     if (!MSGlobals::gUseMesoSim) {
     334        90374 :         if (tmp.wasSet(VEHPARS_DEPARTLANE_SET)) {
     335        14297 :             tmp.departLaneProcedure = DepartLaneDefinition::GIVEN;
     336        14297 :             tmp.departLane = myDepartLane;
     337              :         }
     338        90374 :         if (tmp.wasSet(VEHPARS_DEPARTPOSLAT_SET)) {
     339            8 :             tmp.departPosLatProcedure = (tmp.departPosLatProcedure == DepartPosLatDefinition::RANDOM
     340            4 :                                          ? DepartPosLatDefinition::GIVEN_VEHROUTE
     341              :                                          : DepartPosLatDefinition::GIVEN);
     342            4 :             tmp.departPosLat = myDepartPosLat;
     343              :         }
     344              :     }
     345       126486 :     if (tmp.wasSet(VEHPARS_DEPARTPOS_SET)) {
     346        72950 :         tmp.departPosProcedure = ((tmp.departPosProcedure != DepartPosDefinition::GIVEN
     347        36475 :                                    && tmp.departPosProcedure != DepartPosDefinition::STOP)
     348        36475 :                                   ? DepartPosDefinition::GIVEN_VEHROUTE
     349              :                                   : DepartPosDefinition::GIVEN);
     350        36475 :         tmp.departPos = myDepartPos;
     351              :     }
     352       126486 :     if (tmp.wasSet(VEHPARS_DEPARTSPEED_SET)) {
     353        94066 :         tmp.departSpeedProcedure = ((tmp.departSpeedProcedure != DepartSpeedDefinition::GIVEN
     354        47033 :                                      && tmp.departSpeedProcedure != DepartSpeedDefinition::LIMIT)
     355        47033 :                                     ? DepartSpeedDefinition::GIVEN_VEHROUTE
     356              :                                     : DepartSpeedDefinition::GIVEN);
     357        47033 :         tmp.departSpeed = myDepartSpeed;
     358              :     }
     359       377452 :     if (oc.getBool("vehroute-output.speedfactor") ||
     360       452893 :             (oc.isDefault("vehroute-output.speedfactor") && tmp.wasSet(VEHPARS_DEPARTSPEED_SET))) {
     361        49033 :         tmp.parametersSet |= VEHPARS_SPEEDFACTOR_SET;
     362        49033 :         tmp.speedFactor = myHolder.getChosenSpeedFactor();
     363              :     }
     364              : 
     365       126486 :     const std::string typeID = myHolder.getVehicleType().getID() != DEFAULT_VTYPE_ID ? myHolder.getVehicleType().getID() : "";
     366       126486 :     tmp.write(od, oc, SUMO_TAG_VEHICLE, typeID);
     367       126486 :     if (hasArrived) {
     368       250580 :         od.writeAttr("arrival", time2string(MSNet::getInstance()->getCurrentTimeStep()));
     369              :     }
     370       126486 :     if (myRouteLength) {
     371          951 :         const bool includeInternalLengths = MSGlobals::gUsingInternalLanes && MSNet::getInstance()->hasInternalLinks();
     372          951 :         const double finalPos = hasArrived ? myHolder.getArrivalPos() : myHolder.getPositionOnLane();
     373         1902 :         const double routeLength = myHolder.getRoute().getDistanceBetween(myHolder.getDepartPos(), finalPos,
     374          951 :                                    myHolder.getRoute().begin(), myHolder.getCurrentRouteEdge(), includeInternalLengths);
     375         1902 :         od.writeAttr("routeLength", routeLength);
     376              :     }
     377       126486 :     if (myDUAStyle) {
     378           12 :         const RandomDistributor<ConstMSRoutePtr>* const routeDist = MSRoute::distDictionary("!" + myHolder.getID());
     379           12 :         if (routeDist != nullptr) {
     380              :             const std::vector<ConstMSRoutePtr>& routes = routeDist->getVals();
     381            6 :             unsigned index = 0;
     382            6 :             while (index < routes.size() && routes[index] != myCurrentRoute) {
     383            0 :                 ++index;
     384              :             }
     385            6 :             od.openTag(SUMO_TAG_ROUTE_DISTRIBUTION).writeAttr(SUMO_ATTR_LAST, index);
     386              :             const std::vector<double>& probs = routeDist->getProbs();
     387           18 :             for (int i = 0; i < (int)routes.size(); ++i) {
     388           12 :                 od.setPrecision();
     389           12 :                 od.openTag(SUMO_TAG_ROUTE);
     390           12 :                 od.writeAttr(SUMO_ATTR_COST, routes[i]->getCosts());
     391           12 :                 if (myWriteCosts) {
     392            0 :                     od.writeAttr(SUMO_ATTR_SAVINGS, routes[i]->getSavings());
     393              :                 }
     394           12 :                 od.setPrecision(8);
     395           12 :                 od.writeAttr(SUMO_ATTR_PROB, probs[i]);
     396           12 :                 od.setPrecision();
     397           12 :                 OutputDevice_String edgesD;
     398           12 :                 routes[i]->writeEdgeIDs(edgesD, 0, -1, myWriteInternal, myHolder.getVClass());
     399           12 :                 std::string edgesS = edgesD.getString();
     400              :                 edgesS.pop_back(); // remove last ' '
     401           12 :                 od.writeAttr(SUMO_ATTR_EDGES, edgesS);
     402           24 :                 od.closeTag();
     403           12 :             }
     404           12 :             od.closeTag();
     405              :         } else {
     406            6 :             writeXMLRoute(od);
     407              :         }
     408              :     } else {
     409              :         std::string dummyMsg;
     410       126474 :         const int routesToSkip = (myHolder.getParameter().wasSet(VEHPARS_FORCE_REROUTE)
     411        49383 :                                   && !myIncludeIncomplete
     412        49263 :                                   && myReplacedRoutes.size() > 0
     413       223501 :                                   && !myHolder.hasValidRoute(dummyMsg, myReplacedRoutes[0].route) ? 1 : 0);
     414       126474 :         if ((int)myReplacedRoutes.size() > routesToSkip) {
     415        22012 :             od.openTag(SUMO_TAG_ROUTE_DISTRIBUTION);
     416        58945 :             for (int i = routesToSkip; i < (int)myReplacedRoutes.size(); ++i) {
     417        36933 :                 writeXMLRoute(od, i);
     418              :             }
     419        22012 :             writeXMLRoute(od);
     420        44024 :             od.closeTag();
     421              :         } else {
     422       104462 :             writeXMLRoute(od);
     423              :         }
     424              :     }
     425       126486 :     od << myStopOut.getString();
     426       126486 :     myHolder.getParameter().writeParams(od);
     427       126486 :     od.closeTag();
     428       126486 :     od.lf();
     429       126486 :     if (mySorted) {
     430              :         // numerical id reflects loading order
     431         8844 :         writeSortedOutput(&myRouteInfos, tmp.depart, toString(myHolder.getNumericalID()), od.getString());
     432              :     } else {
     433       244128 :         routeOut << od.getString();
     434              :     }
     435       126486 : }
     436              : 
     437              : 
     438              : ConstMSRoutePtr
     439            0 : MSDevice_Vehroutes::getRoute(int index) const {
     440            0 :     if (index < (int)myReplacedRoutes.size()) {
     441            0 :         return myReplacedRoutes[index].route;
     442              :     } else {
     443              :         return nullptr;
     444              :     }
     445              : }
     446              : 
     447              : 
     448              : void
     449        97004 : MSDevice_Vehroutes::addRoute(const std::string& info) {
     450        97004 :     if (myMaxRoutes > 0) {
     451              :         //std::cout << SIMTIME << " " << getID() << " departed=" << myHolder.hasDeparted() << " lastIndex=" << myLastRouteIndex << " start=" << myHolder.getRoutePosition() << "\n";
     452       423118 :         myReplacedRoutes.push_back(RouteReplaceInfo(
     453       124961 :                                        myHolder.hasDeparted() ?  myHolder.getEdge() : nullptr,
     454              :                                        MSNet::getInstance()->getCurrentTimeStep(), myCurrentRoute, info,
     455              :                                        myLastRouteIndex,
     456       124961 :                                        myHolder.hasDeparted() ? myHolder.getRoutePosition() : 0));
     457        86598 :         if ((int)myReplacedRoutes.size() > myMaxRoutes) {
     458              :             myReplacedRoutes.erase(myReplacedRoutes.begin());
     459              :         }
     460              :     }
     461        97004 :     myCurrentRoute = myHolder.getRoutePtr();
     462        97004 : }
     463              : 
     464              : 
     465              : void
     466        36910 : MSDevice_Vehroutes::writePendingOutput(const bool includeUnfinished) {
     467        36910 :     MSNet* const net = MSNet::getInstance();
     468              : 
     469        36910 :     if (!includeUnfinished) {
     470        36565 :         if (mySorted) {
     471          117 :             for (const auto& routeInfo : myRouteInfos.routeXML) {
     472           36 :                 for (const auto& rouXML : routeInfo.second) {
     473           20 :                     (*myRouteInfos.routeOut) << rouXML.second;
     474              :                 }
     475              :             }
     476          101 :             if (net->hasPersons()) {
     477           22 :                 const SortedRouteInfo& personRouteInfos = net->getPersonControl().getRouteInfo();
     478           22 :                 if (personRouteInfos.routeOut != myRouteInfos.routeOut) {
     479            0 :                     for (const auto& routeInfo : personRouteInfos.routeXML) {
     480            0 :                         for (const auto& rouXML : routeInfo.second) {
     481            0 :                             (*personRouteInfos.routeOut) << rouXML.second;
     482              :                         }
     483              :                     }
     484              :                 }
     485              :             }
     486              :         }
     487        36565 :         return;
     488              :     }
     489         1541 :     for (const auto& it : myStateListener.myDevices) {
     490         1196 :         if (it.first->hasDeparted()) {
     491         1196 :             if (it.first->isStopped()) {
     492          593 :                 it.second->notifyStopEnded();
     493              :             }
     494         1196 :             it.second->writeOutput(false);
     495              :         }
     496              :     }
     497              :     // unfinished persons
     498          345 :     if (net->hasPersons()) {
     499          168 :         MSTransportableControl& pc = net->getPersonControl();
     500          190 :         while (pc.loadedBegin() != pc.loadedEnd()) {
     501           22 :             pc.erase(pc.loadedBegin()->second);
     502              :         }
     503              :     }
     504              :     // Flush any remaining sorted outputs that may still be buffered
     505          345 :     if (mySorted) {
     506            4 :         for (const auto& routeInfo : myRouteInfos.routeXML) {
     507            4 :             for (const auto& rouXML : routeInfo.second) {
     508            2 :                 (*myRouteInfos.routeOut) << rouXML.second;
     509              :             }
     510              :         }
     511            2 :         if (net->hasPersons()) {
     512            0 :             const SortedRouteInfo& personRouteInfos = net->getPersonControl().getRouteInfo();
     513            0 :             if (personRouteInfos.routeOut != myRouteInfos.routeOut) {
     514            0 :                 for (const auto& routeInfo : personRouteInfos.routeXML) {
     515            0 :                     for (const auto& rouXML : routeInfo.second) {
     516            0 :                         (*personRouteInfos.routeOut) << rouXML.second;
     517              :                     }
     518              :                 }
     519              :             }
     520              :         }
     521              :     }
     522              : }
     523              : 
     524              : 
     525              : void
     526          108 : MSDevice_Vehroutes::registerTransportableDepart(SUMOTime depart) {
     527          108 :     myRouteInfos.departureCounts[depart]++;
     528          108 : }
     529              : 
     530              : 
     531              : void
     532         4544 : MSDevice_Vehroutes::writeSortedOutput(MSDevice_Vehroutes::SortedRouteInfo* routeInfo, SUMOTime depart, const std::string& id, const std::string& xmlOutput) {
     533         4544 :     if (routeInfo->routeOut == myRouteInfos.routeOut) {
     534              :         routeInfo = &myRouteInfos;
     535              :     }
     536         4544 :     routeInfo->routeXML[depart][id] = xmlOutput;
     537         4544 :     routeInfo->departureCounts[depart]--;
     538              :     std::map<const SUMOTime, int>::iterator it = routeInfo->departureCounts.begin();
     539         7777 :     while (it != routeInfo->departureCounts.end() && it->second == 0) {
     540         7755 :         for (const auto& rouXML : routeInfo->routeXML[it->first]) {
     541         4522 :             (*routeInfo->routeOut) << rouXML.second;
     542              :         }
     543              :         routeInfo->routeXML.erase(it->first);
     544              :         it = routeInfo->departureCounts.erase(it);
     545              :     }
     546         4544 : }
     547              : 
     548              : 
     549              : void
     550         3127 : MSDevice_Vehroutes::saveState(OutputDevice& out) const {
     551         3127 :     out.openTag(SUMO_TAG_DEVICE);
     552         3127 :     out.writeAttr(SUMO_ATTR_ID, getID());
     553              :     std::vector<std::string> internals;
     554         3127 :     if (!MSGlobals::gUseMesoSim) {
     555         1838 :         internals.push_back(toString(myDepartLane));
     556         3676 :         internals.push_back(toString(myDepartPosLat));
     557              :     }
     558         3127 :     internals.push_back(toString(myDepartSpeed));
     559         3127 :     internals.push_back(toString(myDepartPos));
     560         3127 :     internals.push_back(toString(myReplacedRoutes.size()));
     561         5985 :     for (int i = 0; i < (int)myReplacedRoutes.size(); ++i) {
     562         2858 :         const std::string replacedOnEdge = myReplacedRoutes[i].edge == nullptr ? "!NULL" : myReplacedRoutes[i].edge->getID();
     563         2858 :         internals.push_back(replacedOnEdge);
     564         5716 :         internals.push_back(toString(myReplacedRoutes[i].time));
     565         2858 :         internals.push_back(myReplacedRoutes[i].route->getID());
     566         2858 :         internals.push_back(myReplacedRoutes[i].info);
     567         2858 :         internals.push_back(toString(myReplacedRoutes[i].lastRouteIndex));
     568         5716 :         internals.push_back(toString(myReplacedRoutes[i].newRouteIndex));
     569              :     }
     570         3127 :     out.writeAttr(SUMO_ATTR_STATE, toString(internals));
     571         3127 :     if (mySaveExits && myExits.size() > 0) {
     572            9 :         out.writeAttr(SUMO_ATTR_EXITTIMES, myExits);
     573            9 :         out.writeAttr(SUMO_ATTR_EDGE, myLastSavedAt->getID());
     574              :     }
     575         3127 :     out.closeTag();
     576         3127 : }
     577              : 
     578              : 
     579              : void
     580         2220 : MSDevice_Vehroutes::loadState(const SUMOSAXAttributes& attrs) {
     581         2220 :     std::istringstream bis(attrs.getString(SUMO_ATTR_STATE));
     582         2220 :     if (!MSGlobals::gUseMesoSim) {
     583         1307 :         bis >> myDepartLane;
     584         1307 :         bis >> myDepartPosLat;
     585              :     }
     586         2220 :     bis >> myDepartSpeed;
     587         2220 :     bis >> myDepartPos;
     588              :     int size;
     589         2220 :     bis >> size;
     590         4054 :     for (int i = 0; i < size; ++i) {
     591              :         std::string edgeID;
     592              :         SUMOTime time;
     593              :         std::string routeID;
     594              :         std::string info;
     595              :         int lastIndex;
     596              :         int newIndex;
     597         1834 :         bis >> edgeID;
     598              :         bis >> time;
     599         1834 :         bis >> routeID;
     600         1834 :         bis >> info;
     601         1834 :         bis >> lastIndex;
     602         1834 :         bis >> newIndex;
     603              : 
     604         1834 :         ConstMSRoutePtr route = MSRoute::dictionary(routeID);
     605         1834 :         if (route != nullptr) {
     606         2844 :             myReplacedRoutes.push_back(RouteReplaceInfo(MSEdge::dictionary(edgeID), time, route, info, lastIndex, newIndex));
     607              :         }
     608              :     }
     609         2220 :     if (mySaveExits && attrs.hasAttribute(SUMO_ATTR_EXITTIMES)) {
     610            9 :         bool ok = true;
     611           20 :         for (const std::string& t : attrs.get<std::vector<std::string> >(SUMO_ATTR_EXITTIMES, nullptr, ok)) {
     612           11 :             myExits.push_back(StringUtils::toLong(t));
     613            9 :         }
     614            9 :         if (attrs.hasAttribute(SUMO_ATTR_EDGE)) {
     615            9 :             myLastSavedAt = MSEdge::dictionary(attrs.getString(SUMO_ATTR_EDGE));
     616              :         }
     617              :     }
     618         2220 :     if (myHolder.hasDeparted()) {
     619          747 :         myLastRouteIndex = myHolder.getRoutePosition();
     620              :     }
     621         2220 : }
     622              : 
     623              : 
     624              : /****************************************************************************/
        

Generated by: LCOV version 2.0-1