LCOV - code coverage report
Current view: top level - src/microsim/devices - MSDevice_Vehroutes.cpp (source / functions) Coverage Total Hit
Test: lcov.info Lines: 96.0 % 346 332
Test Date: 2026-05-24 16:29:35 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-2026 German Aerospace Center (DLR) and others.
       4              : // This program and the accompanying materials are made available under the
       5              : // terms of the Eclipse Public License 2.0 which is available at
       6              : // https://www.eclipse.org/legal/epl-2.0/
       7              : // This Source Code may also be made available under the following Secondary
       8              : // Licenses when the conditions for such availability set forth in the Eclipse
       9              : // Public License 2.0 are satisfied: GNU General Public License, version 2
      10              : // or later which is available at
      11              : // https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html
      12              : // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
      13              : /****************************************************************************/
      14              : /// @file    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        42028 : MSDevice_Vehroutes::init() {
      67        42028 :     const OptionsCont& oc = OptionsCont::getOptions();
      68        84056 :     if (oc.isSet("vehroute-output")) {
      69        12410 :         OutputDevice::createDeviceByOption("vehroute-output", "routes", "routes_file.xsd");
      70        12392 :         OutputDevice& od = OutputDevice::getDeviceByOption("vehroute-output");
      71         6196 :         if (!od.isXML()) {
      72            4 :             WRITE_WARNING("Vehroute output does not fully support tabular formats. Sorting and stop output will not work.");
      73              :         }
      74         6196 :         mySaveExits = oc.getBool("vehroute-output.exit-times");
      75         6196 :         myLastRouteOnly = oc.getBool("vehroute-output.last-route");
      76         6196 :         myDUAStyle = oc.getBool("vehroute-output.dua");
      77         6196 :         myWriteCosts = oc.getBool("vehroute-output.cost");
      78         6196 :         mySorted = myDUAStyle || oc.getBool("vehroute-output.sorted");
      79         6196 :         myIntendedDepart = oc.getBool("vehroute-output.intended-depart");
      80         6196 :         myRouteLength = oc.getBool("vehroute-output.route-length");
      81         6196 :         mySkipPTLines = oc.getBool("vehroute-output.skip-ptlines");
      82         6196 :         myIncludeIncomplete = oc.getBool("vehroute-output.incomplete");
      83         6196 :         myWriteStopPriorEdges = oc.getBool("vehroute-output.stop-edges");
      84         6196 :         myWriteInternal = oc.getBool("vehroute-output.internal");
      85         6196 :         MSNet::getInstance()->addVehicleStateListener(&myStateListener);
      86         6196 :         myRouteInfos.routeOut = &od;
      87              :     }
      88        42022 : }
      89              : 
      90              : 
      91              : void
      92        45156 : MSDevice_Vehroutes::insertOptions(OptionsCont& oc) {
      93        45156 :     oc.addOptionSubTopic("Vehroutes Device");
      94        90312 :     insertDefaultAssignmentOptions("vehroute", "Vehroutes Device", oc);
      95        45156 : }
      96              : 
      97              : 
      98              : MSDevice_Vehroutes*
      99      6196164 : MSDevice_Vehroutes::buildVehicleDevices(SUMOVehicle& v, std::vector<MSVehicleDevice*>& into, int maxRoutes) {
     100      6196164 :     if (maxRoutes < std::numeric_limits<int>::max()) {
     101      1868924 :         return new MSDevice_Vehroutes(v, "vehroute_" + v.getID(), maxRoutes);
     102              :     }
     103      5261702 :     if (mySkipPTLines && v.getParameter().line != "") {
     104              :         return nullptr;
     105              :     }
     106      5260576 :     OptionsCont& oc = OptionsCont::getOptions();
     107     10521152 :     if (equippedByDefaultAssignmentOptions(oc, "vehroute", v, oc.isSet("vehroute-output"))) {
     108       138937 :         if (myLastRouteOnly) {
     109              :             maxRoutes = 0;
     110              :         }
     111       138937 :         myStateListener.myDevices[&v] = new MSDevice_Vehroutes(v, "vehroute_" + v.getID(), maxRoutes);
     112       138937 :         into.push_back(myStateListener.myDevices[&v]);
     113       138937 :         return myStateListener.myDevices[&v];
     114              :     }
     115              :     return nullptr;
     116              : }
     117              : 
     118              : 
     119              : // ---------------------------------------------------------------------------
     120              : // MSDevice_Vehroutes::StateListener-methods
     121              : // ---------------------------------------------------------------------------
     122              : void
     123       534565 : MSDevice_Vehroutes::StateListener::vehicleStateChanged(const SUMOVehicle* const vehicle, MSNet::VehicleState to, const std::string& info) {
     124       534565 :     if (to == MSNet::VehicleState::NEWROUTE) {
     125              :         const auto& deviceEntry = myDevices.find(vehicle);
     126       102895 :         if (deviceEntry != myDevices.end()) {
     127       101482 :             deviceEntry->second->addRoute(info);
     128              :         }
     129              :     }
     130       534565 : }
     131              : 
     132              : 
     133              : // ---------------------------------------------------------------------------
     134              : // MSDevice_Vehroutes-methods
     135              : // ---------------------------------------------------------------------------
     136      1073399 : MSDevice_Vehroutes::MSDevice_Vehroutes(SUMOVehicle& holder, const std::string& id, int maxRoutes) :
     137              :     MSVehicleDevice(holder, id),
     138      1073399 :     myCurrentRoute(holder.getRoutePtr()),
     139      1073399 :     myMaxRoutes(maxRoutes),
     140      1073399 :     myLastSavedAt(nullptr),
     141      1073399 :     myLastRouteIndex(-1),
     142      1073399 :     myDepartLane(-1),
     143      1073399 :     myDepartPos(-1),
     144      1073399 :     myDepartSpeed(-1),
     145      1073399 :     myDepartPosLat(0),
     146      1073399 :     myStopOut(2) {
     147      1073399 : }
     148              : 
     149              : 
     150      2146662 : MSDevice_Vehroutes::~MSDevice_Vehroutes() {
     151      1073331 :     myStateListener.myDevices.erase(&myHolder);
     152      2146662 : }
     153              : 
     154              : 
     155              : bool
     156     14275728 : MSDevice_Vehroutes::notifyEnter(SUMOTrafficObject& veh, MSMoveReminder::Notification reason, const MSLane* enteredLane) {
     157     14275728 :     if (reason == MSMoveReminder::NOTIFICATION_DEPARTED) {
     158         5251 :         if (mySorted && myStateListener.myDevices.count(static_cast<SUMOVehicle*>(&veh)) != 0
     159       889731 :                 && myStateListener.myDevices[static_cast<SUMOVehicle*>(&veh)] == this) {
     160         4586 :             const SUMOTime departure = myIntendedDepart ? myHolder.getParameter().depart : MSNet::getInstance()->getCurrentTimeStep();
     161         4586 :             myRouteInfos.departureCounts[departure]++;
     162              :         }
     163       884480 :         if (!MSGlobals::gUseMesoSim) {
     164              :             const MSVehicle& vehicle = static_cast<MSVehicle&>(veh);
     165       578219 :             myDepartLane = vehicle.getLane()->getIndex();
     166       578219 :             myDepartPosLat = vehicle.getLateralPositionOnLane();
     167              :         }
     168       884480 :         myDepartSpeed = veh.getSpeed();
     169       884480 :         myDepartPos = veh.getPositionOnLane();
     170              :     }
     171     14275728 :     if (myWriteStopPriorEdges) {
     172           68 :         if (MSGlobals::gUseMesoSim) {
     173           48 :             const MSEdge* e = veh.getEdge();
     174           48 :             if (myPriorEdges.empty() || myPriorEdges.back() != e) {
     175           12 :                 myPriorEdges.push_back(e);
     176              :             }
     177              :         } else {
     178           20 :             myPriorEdges.push_back(&enteredLane->getEdge());
     179              :         }
     180              :     }
     181     14275728 :     myLastRouteIndex = myHolder.getRoutePosition();
     182     14275728 :     return true;
     183              : }
     184              : 
     185              : 
     186              : bool
     187     14238854 : MSDevice_Vehroutes::notifyLeave(SUMOTrafficObject& veh, double /*lastPos*/, MSMoveReminder::Notification reason, const MSLane* /* enteredLane */) {
     188     14238854 :     if (mySaveExits && reason != NOTIFICATION_LANE_CHANGE && reason != NOTIFICATION_PARKING && reason != NOTIFICATION_SEGMENT) {
     189       308845 :         const MSEdge* edge = myWriteInternal ? dynamic_cast<MSBaseVehicle&>(veh).getCurrentEdge() : veh.getEdge();
     190       308845 :         if (myLastSavedAt != edge) {
     191       155723 :             myExits.push_back(MSNet::getInstance()->getCurrentTimeStep());
     192       155723 :             myLastSavedAt = edge;
     193              :         }
     194              :     }
     195     14238854 :     return true;
     196              : }
     197              : 
     198              : 
     199              : void
     200        23796 : MSDevice_Vehroutes::notifyStopEnded() {
     201        23796 :     SUMOVehicleParameter::Stop stop = myHolder.getStops().front().pars;
     202        23796 :     const bool closeLater = myWriteStopPriorEdges || mySaveExits;
     203        23796 :     if (mySaveExits) {
     204              :         // prevent duplicate output
     205         1658 :         stop.parametersSet &=  ~(STOP_STARTED_SET | STOP_ENDED_SET);
     206              :     }
     207        23796 :     stop.write(myStopOut, !closeLater);
     208        23796 :     if (myWriteStopPriorEdges) {
     209              :         // calculate length
     210           16 :         double priorEdgesLength = 0;
     211           40 :         for (int i = 0; i < (int)myPriorEdges.size(); i++) {
     212           24 :             if (i == 0) {
     213           16 :                 priorEdgesLength += myPriorEdges.at(i)->getLength();
     214            8 :             } else if (myPriorEdges.at(i)->getID() != myPriorEdges.at(i - 1)->getID()) {
     215            8 :                 priorEdgesLength += myPriorEdges.at(i)->getLength();
     216              :             }
     217              :         }
     218           16 :         myStopOut.writeAttr("priorEdges", myPriorEdges);
     219              :         myPriorEdges.clear();
     220           16 :         myStopOut.writeAttr("priorEdgesLength", priorEdgesLength);
     221              :     }
     222        23796 :     if (mySaveExits) {
     223         1658 :         myStopOut.writeAttr(SUMO_ATTR_STARTED, time2string(stop.started));
     224         1658 :         myStopOut.writeAttr(SUMO_ATTR_ENDED, stop.ended < 0 ? "-1" : time2string(stop.ended));
     225              :     }
     226        23796 :     if (closeLater) {
     227         3348 :         myStopOut.closeTag();
     228              :     }
     229        23796 : }
     230              : 
     231              : 
     232              : void
     233       167670 : MSDevice_Vehroutes::writeXMLRoute(OutputDevice& os, int index) const {
     234        10058 :     if (index == 0 && !myIncludeIncomplete && myReplacedRoutes[index].route->size() == 2 &&
     235       171428 :             myReplacedRoutes[index].route->getEdges().front()->isTazConnector() &&
     236            0 :             myReplacedRoutes[index].route->getEdges().back()->isTazConnector()) {
     237              :         return;
     238              :     }
     239              :     // check if a previous route shall be written
     240              :     //std::cout << " writeXMLRoute index=" << index << " numReroutes=" << myHolder.getNumberReroutes() << "\n";
     241       167670 :     const int routesToSkip = myHolder.getParameter().wasSet(VEHPARS_FORCE_REROUTE) ? 1 : 0;
     242       167670 :     os.openTag(SUMO_TAG_ROUTE);
     243       167670 :     if (index >= 0) {
     244              :         assert((int)myReplacedRoutes.size() > index);
     245        39695 :         if (myDUAStyle || myWriteCosts) {
     246        14410 :             os.writeAttr(SUMO_ATTR_COST, myReplacedRoutes[index].route->getCosts());
     247              :         }
     248        39695 :         if (myWriteCosts) {
     249        14410 :             os.writeAttr(SUMO_ATTR_SAVINGS, myReplacedRoutes[index].route->getSavings());
     250              :         }
     251              :         // write edge on which the vehicle was when the route was valid
     252       117701 :         os.writeAttr("replacedOnEdge", (myReplacedRoutes[index].edge ?
     253              :                                         myReplacedRoutes[index].edge->getID() : ""));
     254        39695 :         if (myReplacedRoutes[index].lastRouteIndex > 0) {
     255              :             // do not write the default
     256        27398 :             os.writeAttr(SUMO_ATTR_REPLACED_ON_INDEX, myReplacedRoutes[index].lastRouteIndex);
     257              :         }
     258              :         // write the reason for replacement
     259        39695 :         os.writeAttr("reason", myReplacedRoutes[index].info);
     260              : 
     261              :         // write the time at which the route was replaced
     262        39695 :         os.writeAttr(SUMO_ATTR_REPLACED_AT_TIME, time2string(myReplacedRoutes[index].time));
     263        39695 :         os.writeAttr(SUMO_ATTR_PROB, "0");
     264        39695 :         OutputDevice_String edgesD;
     265              :         // always write the part that was actually driven and the rest of the current route that wasn't yet driven
     266              :         int start = 0;
     267       191469 :         for (int i = routesToSkip; i < index; i++) {
     268       151774 :             if (myReplacedRoutes[i].edge != nullptr) {
     269       150948 :                 int end = myReplacedRoutes[i].lastRouteIndex;
     270       150948 :                 myReplacedRoutes[i].route->writeEdgeIDs(edgesD, start, end, myWriteInternal, myHolder.getVClass());
     271              :             }
     272       151774 :             start = myReplacedRoutes[i].newRouteIndex;
     273              :         }
     274        39695 :         myReplacedRoutes[index].route->writeEdgeIDs(edgesD, start, -1, myWriteInternal, myHolder.getVClass());
     275        39695 :         std::string edgesS = edgesD.getString();
     276              :         edgesS.pop_back(); // remove last ' '
     277        39695 :         os.writeAttr(SUMO_ATTR_EDGES, edgesS);
     278        39695 :         if (myRouteLength) {
     279         7174 :             const bool includeInternalLengths = MSGlobals::gUsingInternalLanes && MSNet::getInstance()->hasInternalLinks();
     280              :             ConstMSRoutePtr route = myReplacedRoutes[index].route;
     281         7174 :             const double routeLength = route->getDistanceBetween(myHolder.getDepartPos(), route->getEdges().back()->getLength(),
     282         7174 :                                        route->begin(), route->end(), includeInternalLengths);
     283         7174 :             os.writeAttr("routeLength", routeLength);
     284              :         }
     285        39695 :     } else {
     286       127975 :         if (myDUAStyle || myWriteCosts) {
     287        33096 :             os.writeAttr(SUMO_ATTR_COST, myHolder.getRoute().getCosts());
     288              :         }
     289       127975 :         if (myWriteCosts) {
     290        33090 :             os.writeAttr(SUMO_ATTR_SAVINGS, myHolder.getRoute().getSavings());
     291              :         }
     292       127975 :         OutputDevice_String edgesD;
     293              :         int numWritten = 0;
     294              :         int start = 0;
     295       127975 :         if (myHolder.getNumberReroutes() > 0) {
     296              :             assert((int)myReplacedRoutes.size() <= myHolder.getNumberReroutes());
     297        96784 :             for (int i = routesToSkip; i < (int)myReplacedRoutes.size(); i++) {
     298        38826 :                 if (myReplacedRoutes[i].edge != nullptr) {
     299        37685 :                     int end = myReplacedRoutes[i].lastRouteIndex;
     300        37685 :                     numWritten += myReplacedRoutes[i].route->writeEdgeIDs(edgesD, start, end, myWriteInternal, myHolder.getVClass());
     301              :                 }
     302        38826 :                 start = myReplacedRoutes[i].newRouteIndex;
     303              :             }
     304              :         }
     305       127975 :         numWritten += myCurrentRoute->writeEdgeIDs(edgesD, start, -1, myWriteInternal, myHolder.getVClass());
     306       127975 :         std::string edgesS = edgesD.getString();
     307              :         edgesS.pop_back(); // remove last ' '
     308       127975 :         os.writeAttr(SUMO_ATTR_EDGES, edgesS);
     309              : 
     310       127975 :         if (mySaveExits) {
     311              :             std::vector<std::string> exits;
     312       134278 :             for (SUMOTime t : myExits) {
     313       248188 :                 exits.push_back(time2string(t));
     314              :             }
     315              :             assert(numWritten >= (int)myExits.size());
     316        20368 :             std::vector<std::string> missing(numWritten - (int)myExits.size(), "-1");
     317        10184 :             exits.insert(exits.end(), missing.begin(), missing.end());
     318        10184 :             os.writeAttr(SUMO_ATTR_EXITTIMES, exits);
     319        10184 :         }
     320       127975 :     }
     321       335340 :     os.closeTag();
     322              : }
     323              : 
     324              : 
     325              : void
     326       126579 : MSDevice_Vehroutes::generateOutput(OutputDevice* /*tripinfoOut*/) const {
     327       126579 :     writeOutput(true);
     328       126579 : }
     329              : 
     330              : 
     331              : void
     332       127981 : MSDevice_Vehroutes::writeOutput(const bool hasArrived) const {
     333       127981 :     const OptionsCont& oc = OptionsCont::getOptions();
     334       127981 :     OutputDevice& routeOut = OutputDevice::getDeviceByOption("vehroute-output");
     335       127981 :     OutputDevice_String stringOut(1);
     336       127981 :     OutputDevice& od = mySorted && routeOut.isXML() ? stringOut : routeOut;
     337       127981 :     SUMOVehicleParameter tmp = myHolder.getParameter();
     338       127981 :     tmp.depart = myIntendedDepart ? myHolder.getParameter().depart : myHolder.getDeparture();
     339       127981 :     if (!MSGlobals::gUseMesoSim) {
     340        91648 :         if (tmp.wasSet(VEHPARS_DEPARTLANE_SET)) {
     341        14577 :             tmp.departLaneProcedure = DepartLaneDefinition::GIVEN;
     342        14577 :             tmp.departLane = myDepartLane;
     343              :         }
     344        91648 :         if (tmp.wasSet(VEHPARS_DEPARTPOSLAT_SET)) {
     345            8 :             tmp.departPosLatProcedure = (tmp.departPosLatProcedure == DepartPosLatDefinition::RANDOM
     346            4 :                                          ? DepartPosLatDefinition::GIVEN_VEHROUTE
     347              :                                          : DepartPosLatDefinition::GIVEN);
     348            4 :             tmp.departPosLat = myDepartPosLat;
     349              :         }
     350              :     }
     351       127981 :     if (tmp.wasSet(VEHPARS_DEPARTPOS_SET)) {
     352        73222 :         tmp.departPosProcedure = ((tmp.departPosProcedure != DepartPosDefinition::GIVEN
     353        36611 :                                    && tmp.departPosProcedure != DepartPosDefinition::STOP)
     354        36611 :                                   ? DepartPosDefinition::GIVEN_VEHROUTE
     355              :                                   : DepartPosDefinition::GIVEN);
     356        36611 :         tmp.departPos = myDepartPos;
     357              :     }
     358       127981 :     if (tmp.wasSet(VEHPARS_DEPARTSPEED_SET)) {
     359        94740 :         tmp.departSpeedProcedure = ((tmp.departSpeedProcedure != DepartSpeedDefinition::GIVEN
     360        47370 :                                      && tmp.departSpeedProcedure != DepartSpeedDefinition::LIMIT)
     361        47370 :                                     ? DepartSpeedDefinition::GIVEN_VEHROUTE
     362              :                                     : DepartSpeedDefinition::GIVEN);
     363        47370 :         tmp.departSpeed = myDepartSpeed;
     364              :     }
     365       381937 :     if (oc.getBool("vehroute-output.speedfactor") ||
     366       458536 :             (oc.isDefault("vehroute-output.speedfactor") && tmp.wasSet(VEHPARS_DEPARTSPEED_SET))) {
     367        49370 :         tmp.parametersSet |= VEHPARS_SPEEDFACTOR_SET;
     368        49370 :         tmp.speedFactor = myHolder.getChosenSpeedFactor();
     369              :     }
     370              : 
     371       127981 :     const std::string typeID = myHolder.getVehicleType().getID() != DEFAULT_VTYPE_ID ? myHolder.getVehicleType().getID() : "";
     372       127981 :     tmp.write(od, oc, SUMO_TAG_VEHICLE, typeID);
     373       127981 :     if (hasArrived) {
     374       253158 :         od.writeAttr("arrival", time2string(MSNet::getInstance()->getCurrentTimeStep()));
     375              :     }
     376       127981 :     if (myRouteLength) {
     377          951 :         const bool includeInternalLengths = MSGlobals::gUsingInternalLanes && MSNet::getInstance()->hasInternalLinks();
     378          951 :         const double finalPos = hasArrived ? myHolder.getArrivalPos() : myHolder.getPositionOnLane();
     379         1902 :         const double routeLength = myHolder.getRoute().getDistanceBetween(myHolder.getDepartPos(), finalPos,
     380          951 :                                    myHolder.getRoute().begin(), myHolder.getCurrentRouteEdge(), includeInternalLengths);
     381          951 :         od.writeAttr("routeLength", routeLength);
     382              :     }
     383       127981 :     if (myDUAStyle) {
     384           12 :         const RandomDistributor<ConstMSRoutePtr>* const routeDist = MSRoute::distDictionary("!" + myHolder.getID());
     385           12 :         if (routeDist != nullptr) {
     386              :             const std::vector<ConstMSRoutePtr>& routes = routeDist->getVals();
     387            6 :             unsigned index = 0;
     388            6 :             while (index < routes.size() && routes[index] != myCurrentRoute) {
     389            0 :                 ++index;
     390              :             }
     391            6 :             od.openTag(SUMO_TAG_ROUTE_DISTRIBUTION).writeAttr(SUMO_ATTR_LAST, index);
     392              :             const std::vector<double>& probs = routeDist->getProbs();
     393           18 :             for (int i = 0; i < (int)routes.size(); ++i) {
     394           12 :                 od.setPrecision();
     395           12 :                 od.openTag(SUMO_TAG_ROUTE);
     396           12 :                 od.writeAttr(SUMO_ATTR_COST, routes[i]->getCosts());
     397           12 :                 if (myWriteCosts) {
     398            0 :                     od.writeAttr(SUMO_ATTR_SAVINGS, routes[i]->getSavings());
     399              :                 }
     400           12 :                 od.setPrecision(8);
     401           12 :                 od.writeAttr(SUMO_ATTR_PROB, probs[i]);
     402           12 :                 od.setPrecision();
     403           12 :                 OutputDevice_String edgesD;
     404           12 :                 routes[i]->writeEdgeIDs(edgesD, 0, -1, myWriteInternal, myHolder.getVClass());
     405           12 :                 std::string edgesS = edgesD.getString();
     406              :                 edgesS.pop_back(); // remove last ' '
     407           12 :                 od.writeAttr(SUMO_ATTR_EDGES, edgesS);
     408           24 :                 od.closeTag();
     409           12 :             }
     410           12 :             od.closeTag();
     411              :         } else {
     412            6 :             writeXMLRoute(od);
     413              :         }
     414              :     } else {
     415              :         std::string dummyMsg;
     416       127969 :         const int routesToSkip = (myHolder.getParameter().wasSet(VEHPARS_FORCE_REROUTE)
     417        49749 :                                   && !myIncludeIncomplete
     418        49629 :                                   && myReplacedRoutes.size() > 0
     419       225696 :                                   && !myHolder.hasValidRoute(dummyMsg, myReplacedRoutes[0].route) ? 1 : 0);
     420       127969 :         if ((int)myReplacedRoutes.size() > routesToSkip) {
     421        22231 :             od.openTag(SUMO_TAG_ROUTE_DISTRIBUTION);
     422        61926 :             for (int i = routesToSkip; i < (int)myReplacedRoutes.size(); ++i) {
     423        39695 :                 writeXMLRoute(od, i);
     424              :             }
     425        22231 :             writeXMLRoute(od);
     426        44462 :             od.closeTag();
     427              :         } else {
     428       105738 :             writeXMLRoute(od);
     429              :         }
     430              :     }
     431       127981 :     if (routeOut.isXML()) {
     432       255262 :         od << myStopOut.getString();
     433              :     }
     434       127981 :     myHolder.getParameter().writeParams(od);
     435       127981 :     od.closeTag();
     436       127981 :     od.lf();
     437       127981 :     if (mySorted && routeOut.isXML()) {
     438              :         // numerical id reflects loading order
     439         8844 :         writeSortedOutput(&myRouteInfos, tmp.depart, myHolder.getNumericalID(), stringOut.getString());
     440              :     }
     441       127981 : }
     442              : 
     443              : 
     444              : ConstMSRoutePtr
     445            0 : MSDevice_Vehroutes::getRoute(int index) const {
     446            0 :     if (index < (int)myReplacedRoutes.size()) {
     447            0 :         return myReplacedRoutes[index].route;
     448              :     } else {
     449              :         return nullptr;
     450              :     }
     451              : }
     452              : 
     453              : 
     454              : void
     455       101482 : MSDevice_Vehroutes::addRoute(const std::string& info) {
     456       101482 :     if (myMaxRoutes > 0) {
     457              :         //std::cout << SIMTIME << " " << getID() << " departed=" << myHolder.hasDeparted() << " lastIndex=" << myLastRouteIndex << " start=" << myHolder.getRoutePosition() << "\n";
     458       447684 :         myReplacedRoutes.push_back(RouteReplaceInfo(
     459       133082 :                                        myHolder.hasDeparted() ?  myHolder.getEdge() : nullptr,
     460              :                                        MSNet::getInstance()->getCurrentTimeStep(), myCurrentRoute, info,
     461              :                                        myLastRouteIndex,
     462       133082 :                                        myHolder.hasDeparted() ? myHolder.getRoutePosition() : 0));
     463        90760 :         if ((int)myReplacedRoutes.size() > myMaxRoutes) {
     464              :             myReplacedRoutes.erase(myReplacedRoutes.begin());
     465              :         }
     466              :     }
     467       101482 :     myCurrentRoute = myHolder.getRoutePtr();
     468       101482 : }
     469              : 
     470              : 
     471              : void
     472        40234 : MSDevice_Vehroutes::writePendingOutput(const bool includeUnfinished) {
     473        40234 :     MSNet* const net = MSNet::getInstance();
     474              : 
     475        40234 :     if (!includeUnfinished) {
     476        39792 :         if (mySorted) {
     477          118 :             for (const auto& routeInfo : myRouteInfos.routeXML) {
     478           36 :                 for (const auto& rouXML : routeInfo.second) {
     479           20 :                     (*myRouteInfos.routeOut) << rouXML.second;
     480              :                 }
     481              :             }
     482          102 :             if (net->hasPersons()) {
     483           23 :                 const SortedRouteInfo& personRouteInfos = net->getPersonControl().getRouteInfo();
     484           23 :                 if (personRouteInfos.routeOut != myRouteInfos.routeOut) {
     485            0 :                     for (const auto& routeInfo : personRouteInfos.routeXML) {
     486            0 :                         for (const auto& rouXML : routeInfo.second) {
     487            0 :                             (*personRouteInfos.routeOut) << rouXML.second;
     488              :                         }
     489              :                     }
     490              :                 }
     491              :             }
     492              :         }
     493        39792 :         return;
     494              :     }
     495         1844 :     for (const auto& it : myStateListener.myDevices) {
     496         1402 :         if (it.first->hasDeparted()) {
     497         1402 :             if (it.first->isStopped()) {
     498          764 :                 it.second->notifyStopEnded();
     499              :             }
     500         1402 :             it.second->writeOutput(false);
     501              :         }
     502              :     }
     503              :     // unfinished persons
     504          442 :     if (net->hasPersons()) {
     505          264 :         MSTransportableControl& pc = net->getPersonControl();
     506          370 :         while (pc.loadedBegin() != pc.loadedEnd()) {
     507          106 :             pc.erase(pc.loadedBegin()->second);
     508              :         }
     509              :     }
     510              :     // Flush any remaining sorted outputs that may still be buffered
     511          442 :     if (mySorted) {
     512            4 :         for (const auto& routeInfo : myRouteInfos.routeXML) {
     513            4 :             for (const auto& rouXML : routeInfo.second) {
     514            2 :                 (*myRouteInfos.routeOut) << rouXML.second;
     515              :             }
     516              :         }
     517            2 :         if (net->hasPersons()) {
     518            0 :             const SortedRouteInfo& personRouteInfos = net->getPersonControl().getRouteInfo();
     519            0 :             if (personRouteInfos.routeOut != myRouteInfos.routeOut) {
     520            0 :                 for (const auto& routeInfo : personRouteInfos.routeXML) {
     521            0 :                     for (const auto& rouXML : routeInfo.second) {
     522            0 :                         (*personRouteInfos.routeOut) << rouXML.second;
     523              :                     }
     524              :                 }
     525              :             }
     526              :         }
     527              :     }
     528              : }
     529              : 
     530              : 
     531              : void
     532          108 : MSDevice_Vehroutes::registerTransportableDepart(SUMOTime depart) {
     533          108 :     myRouteInfos.departureCounts[depart]++;
     534          108 : }
     535              : 
     536              : 
     537              : void
     538         4544 : MSDevice_Vehroutes::writeSortedOutput(MSDevice_Vehroutes::SortedRouteInfo* routeInfo, SUMOTime depart, const SUMOTrafficObject::NumericalID id, const std::string& xmlOutput) {
     539         4544 :     if (routeInfo->routeOut == myRouteInfos.routeOut) {
     540              :         routeInfo = &myRouteInfos;
     541              :     }
     542         4544 :     routeInfo->routeXML[depart][id] = xmlOutput;
     543         4544 :     routeInfo->departureCounts[depart]--;
     544              :     std::map<const SUMOTime, int>::iterator it = routeInfo->departureCounts.begin();
     545         7771 :     while (it != routeInfo->departureCounts.end() && it->second == 0) {
     546         7749 :         for (const auto& rouXML : routeInfo->routeXML[it->first]) {
     547         4522 :             (*routeInfo->routeOut) << rouXML.second;
     548              :         }
     549              :         routeInfo->routeXML.erase(it->first);
     550              :         it = routeInfo->departureCounts.erase(it);
     551              :     }
     552         4544 : }
     553              : 
     554              : 
     555              : void
     556         3160 : MSDevice_Vehroutes::saveState(OutputDevice& out) const {
     557         3160 :     out.openTag(SUMO_TAG_DEVICE);
     558         3160 :     out.writeAttr(SUMO_ATTR_ID, getID());
     559              :     std::vector<std::string> internals;
     560         3160 :     if (!MSGlobals::gUseMesoSim) {
     561         1842 :         internals.push_back(toString(myDepartLane));
     562         3684 :         internals.push_back(toString(myDepartPosLat));
     563              :     }
     564         3160 :     internals.push_back(toString(myDepartSpeed));
     565         3160 :     internals.push_back(toString(myDepartPos));
     566         3160 :     internals.push_back(toString(myReplacedRoutes.size()));
     567         6013 :     for (int i = 0; i < (int)myReplacedRoutes.size(); ++i) {
     568         2853 :         const std::string replacedOnEdge = myReplacedRoutes[i].edge == nullptr ? "!NULL" : myReplacedRoutes[i].edge->getID();
     569         2853 :         internals.push_back(replacedOnEdge);
     570         5706 :         internals.push_back(toString(myReplacedRoutes[i].time));
     571         2853 :         internals.push_back(myReplacedRoutes[i].route->getID());
     572         2853 :         internals.push_back(myReplacedRoutes[i].info);
     573         2853 :         internals.push_back(toString(myReplacedRoutes[i].lastRouteIndex));
     574         5706 :         internals.push_back(toString(myReplacedRoutes[i].newRouteIndex));
     575              :     }
     576         3160 :     out.writeAttr(SUMO_ATTR_STATE, toString(internals));
     577         3160 :     if (mySaveExits && myExits.size() > 0) {
     578           11 :         out.writeAttr(SUMO_ATTR_EXITTIMES, myExits);
     579           11 :         out.writeAttr(SUMO_ATTR_EDGE, myLastSavedAt->getID());
     580              :     }
     581         3160 :     out.closeTag();
     582         3160 : }
     583              : 
     584              : 
     585              : void
     586         2253 : MSDevice_Vehroutes::loadState(const SUMOSAXAttributes& attrs) {
     587         2253 :     std::istringstream bis(attrs.getString(SUMO_ATTR_STATE));
     588         2253 :     if (!MSGlobals::gUseMesoSim) {
     589         1312 :         bis >> myDepartLane;
     590         1312 :         bis >> myDepartPosLat;
     591              :     }
     592         2253 :     bis >> myDepartSpeed;
     593         2253 :     bis >> myDepartPos;
     594              :     int size;
     595         2253 :     bis >> size;
     596         4083 :     for (int i = 0; i < size; ++i) {
     597              :         std::string edgeID;
     598              :         SUMOTime time;
     599              :         std::string routeID;
     600              :         std::string info;
     601              :         int lastIndex;
     602              :         int newIndex;
     603         1830 :         bis >> edgeID;
     604              :         bis >> time;
     605         1830 :         bis >> routeID;
     606         1830 :         bis >> info;
     607         1830 :         bis >> lastIndex;
     608         1830 :         bis >> newIndex;
     609              : 
     610         1830 :         ConstMSRoutePtr route = MSRoute::dictionary(routeID);
     611         1830 :         if (route != nullptr) {
     612         2841 :             myReplacedRoutes.push_back(RouteReplaceInfo(MSEdge::dictionary(edgeID), time, route, info, lastIndex, newIndex));
     613              :         }
     614              :     }
     615         2253 :     if (mySaveExits && attrs.hasAttribute(SUMO_ATTR_EXITTIMES)) {
     616           11 :         bool ok = true;
     617           30 :         for (const std::string& t : attrs.get<std::vector<std::string> >(SUMO_ATTR_EXITTIMES, nullptr, ok)) {
     618           19 :             myExits.push_back(StringUtils::toLong(t));
     619           11 :         }
     620           11 :         if (attrs.hasAttribute(SUMO_ATTR_EDGE)) {
     621           11 :             myLastSavedAt = MSEdge::dictionary(attrs.getString(SUMO_ATTR_EDGE));
     622              :         }
     623              :     }
     624         2253 :     if (myHolder.hasDeparted()) {
     625          779 :         myLastRouteIndex = myHolder.getRoutePosition();
     626              :     }
     627         2253 : }
     628              : 
     629              : 
     630              : /****************************************************************************/
        

Generated by: LCOV version 2.0-1