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 % 351 337
Test Date: 2026-10-12 15:53: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-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        43193 : MSDevice_Vehroutes::init() {
      67        43193 :     const OptionsCont& oc = OptionsCont::getOptions();
      68        86386 :     if (oc.isSet("vehroute-output")) {
      69        13418 :         OutputDevice::createDeviceByOption("vehroute-output", "routes", "routes_file.xsd");
      70        13400 :         OutputDevice& od = OutputDevice::getDeviceByOption("vehroute-output");
      71         6700 :         if (!od.isXML()) {
      72            4 :             WRITE_WARNING("Vehroute output does not fully support tabular formats. Sorting and stop output will not work.");
      73              :         }
      74         6700 :         mySaveExits = oc.getBool("vehroute-output.exit-times");
      75         6700 :         myLastRouteOnly = oc.getBool("vehroute-output.last-route");
      76         6700 :         myDUAStyle = oc.getBool("vehroute-output.dua");
      77         6700 :         myWriteCosts = oc.getBool("vehroute-output.cost");
      78         6700 :         mySorted = myDUAStyle || oc.getBool("vehroute-output.sorted");
      79         6700 :         myIntendedDepart = oc.getBool("vehroute-output.intended-depart");
      80         6700 :         myRouteLength = oc.getBool("vehroute-output.route-length");
      81         6700 :         mySkipPTLines = oc.getBool("vehroute-output.skip-ptlines");
      82         6700 :         myIncludeIncomplete = oc.getBool("vehroute-output.incomplete");
      83         6700 :         myWriteStopPriorEdges = oc.getBool("vehroute-output.stop-edges");
      84         6700 :         myWriteInternal = oc.getBool("vehroute-output.internal");
      85         6700 :         MSNet::getInstance()->addVehicleStateListener(&myStateListener);
      86         6700 :         myRouteInfos.routeOut = &od;
      87              :     }
      88        43187 : }
      89              : 
      90              : 
      91              : void
      92        46427 : MSDevice_Vehroutes::insertOptions(OptionsCont& oc) {
      93        46427 :     oc.addOptionSubTopic("Vehroutes Device");
      94        92854 :     insertDefaultAssignmentOptions("vehroute", "Vehroutes Device", oc);
      95        46427 : }
      96              : 
      97              : 
      98              : MSDevice_Vehroutes*
      99      6531592 : MSDevice_Vehroutes::buildVehicleDevices(SUMOVehicle& v, std::vector<MSVehicleDevice*>& into, int maxRoutes) {
     100      6531592 :     if (maxRoutes < std::numeric_limits<int>::max()) {
     101      2069926 :         return new MSDevice_Vehroutes(v, "vehroute_" + v.getID(), maxRoutes);
     102              :     }
     103      5496629 :     if (mySkipPTLines && v.getParameter().line != "") {
     104              :         return nullptr;
     105              :     }
     106      5495361 :     OptionsCont& oc = OptionsCont::getOptions();
     107     10990722 :     if (equippedByDefaultAssignmentOptions(oc, "vehroute", v, oc.isSet("vehroute-output"))) {
     108       146119 :         if (myLastRouteOnly) {
     109              :             maxRoutes = 0;
     110              :         }
     111       146119 :         myStateListener.myDevices[&v] = new MSDevice_Vehroutes(v, "vehroute_" + v.getID(), maxRoutes);
     112       146119 :         into.push_back(myStateListener.myDevices[&v]);
     113       146119 :         return myStateListener.myDevices[&v];
     114              :     }
     115              :     return nullptr;
     116              : }
     117              : 
     118              : 
     119              : // ---------------------------------------------------------------------------
     120              : // MSDevice_Vehroutes::StateListener-methods
     121              : // ---------------------------------------------------------------------------
     122              : void
     123       567798 : MSDevice_Vehroutes::StateListener::vehicleStateChanged(const SUMOVehicle* const vehicle, MSNet::VehicleState to, const std::string& info) {
     124       567798 :     if (to == MSNet::VehicleState::NEWROUTE) {
     125              :         const auto& deviceEntry = myDevices.find(vehicle);
     126       113081 :         if (deviceEntry != myDevices.end()) {
     127       111472 :             deviceEntry->second->addRoute(info);
     128              :         }
     129              :     }
     130       567798 : }
     131              : 
     132              : 
     133              : // ---------------------------------------------------------------------------
     134              : // MSDevice_Vehroutes-methods
     135              : // ---------------------------------------------------------------------------
     136      1181082 : MSDevice_Vehroutes::MSDevice_Vehroutes(SUMOVehicle& holder, const std::string& id, int maxRoutes) :
     137              :     MSVehicleDevice(holder, id),
     138      1181082 :     myCurrentRoute(holder.getRoutePtr()),
     139      1181082 :     myMaxRoutes(maxRoutes),
     140      1181082 :     myLastSavedAt(nullptr),
     141      1181082 :     myLastRouteIndex(-1),
     142      1181082 :     myDepartLane(-1),
     143      1181082 :     myDepartPos(-1),
     144      1181082 :     myDepartSpeed(-1),
     145      1181082 :     myDepartPosLat(0),
     146      1181082 :     myStopOut(2) {
     147              :         std::string dummyMsg;
     148      2362164 :         myCurrentValid = myHolder.hasValidRoute(dummyMsg, myCurrentRoute);
     149      1181082 : }
     150              : 
     151              : 
     152      2362020 : MSDevice_Vehroutes::~MSDevice_Vehroutes() {
     153      1181010 :     myStateListener.myDevices.erase(&myHolder);
     154      2362020 : }
     155              : 
     156              : 
     157              : bool
     158     14954920 : MSDevice_Vehroutes::notifyEnter(SUMOTrafficObject& veh, MSMoveReminder::Notification reason, const MSLane* enteredLane) {
     159     14954920 :     if (reason == MSMoveReminder::NOTIFICATION_DEPARTED) {
     160         5251 :         if (mySorted && myStateListener.myDevices.count(static_cast<SUMOVehicle*>(&veh)) != 0
     161       982976 :                 && myStateListener.myDevices[static_cast<SUMOVehicle*>(&veh)] == this) {
     162         4586 :             const SUMOTime departure = myIntendedDepart ? myHolder.getParameter().depart : MSNet::getInstance()->getCurrentTimeStep();
     163         4586 :             myRouteInfos.departureCounts[departure]++;
     164              :         }
     165       977725 :         if (!MSGlobals::gUseMesoSim) {
     166              :             const MSVehicle& vehicle = static_cast<MSVehicle&>(veh);
     167       597357 :             myDepartLane = vehicle.getLane()->getIndex();
     168       597357 :             myDepartPosLat = vehicle.getLateralPositionOnLane();
     169              :         }
     170       977725 :         myDepartSpeed = veh.getSpeed();
     171       977725 :         myDepartPos = veh.getPositionOnLane();
     172              :     }
     173     14954920 :     if (myWriteStopPriorEdges) {
     174           68 :         if (MSGlobals::gUseMesoSim) {
     175           48 :             const MSEdge* e = veh.getEdge();
     176           48 :             if (myPriorEdges.empty() || myPriorEdges.back() != e) {
     177           12 :                 myPriorEdges.push_back(e);
     178              :             }
     179              :         } else {
     180           20 :             myPriorEdges.push_back(&enteredLane->getEdge());
     181              :         }
     182              :     }
     183     14954920 :     myLastRouteIndex = myHolder.getRoutePosition();
     184     14954920 :     return true;
     185              : }
     186              : 
     187              : 
     188              : bool
     189     14917158 : MSDevice_Vehroutes::notifyLeave(SUMOTrafficObject& veh, double /*lastPos*/, MSMoveReminder::Notification reason, const MSLane* /* enteredLane */) {
     190     14917158 :     if (mySaveExits && reason != NOTIFICATION_LANE_CHANGE && reason != NOTIFICATION_PARKING && reason != NOTIFICATION_SEGMENT) {
     191       345036 :         const MSEdge* edge = myWriteInternal ? dynamic_cast<MSBaseVehicle&>(veh).getCurrentEdge() : veh.getEdge();
     192       345036 :         if (myLastSavedAt != edge) {
     193       173077 :             myExits.push_back(MSNet::getInstance()->getCurrentTimeStep());
     194       173077 :             myLastSavedAt = edge;
     195              :         }
     196              :     }
     197     14917158 :     return true;
     198              : }
     199              : 
     200              : 
     201              : void
     202        24375 : MSDevice_Vehroutes::notifyStopEnded() {
     203        24375 :     SUMOVehicleParameter::Stop stop = myHolder.getStops().front().pars;
     204        24375 :     const bool closeLater = myWriteStopPriorEdges || mySaveExits;
     205        24375 :     if (mySaveExits) {
     206              :         // prevent duplicate output
     207         1745 :         stop.parametersSet &=  ~(STOP_STARTED_SET | STOP_ENDED_SET);
     208              :     }
     209        24375 :     stop.write(myStopOut, !closeLater);
     210        24375 :     if (myWriteStopPriorEdges) {
     211              :         // calculate length
     212           16 :         double priorEdgesLength = 0;
     213           40 :         for (int i = 0; i < (int)myPriorEdges.size(); i++) {
     214           24 :             if (i == 0) {
     215           16 :                 priorEdgesLength += myPriorEdges.at(i)->getLength();
     216            8 :             } else if (myPriorEdges.at(i)->getID() != myPriorEdges.at(i - 1)->getID()) {
     217            8 :                 priorEdgesLength += myPriorEdges.at(i)->getLength();
     218              :             }
     219              :         }
     220           16 :         myStopOut.writeAttr("priorEdges", myPriorEdges);
     221              :         myPriorEdges.clear();
     222           16 :         myStopOut.writeAttr("priorEdgesLength", priorEdgesLength);
     223              :     }
     224        24375 :     if (mySaveExits) {
     225         1745 :         myStopOut.writeAttr(SUMO_ATTR_STARTED, time2string(stop.started));
     226         1745 :         myStopOut.writeAttr(SUMO_ATTR_ENDED, stop.ended < 0 ? "-1" : time2string(stop.ended));
     227              :     }
     228        24375 :     if (closeLater) {
     229         3522 :         myStopOut.closeTag();
     230              :     }
     231        24375 : }
     232              : 
     233              : 
     234              : void
     235       178641 : MSDevice_Vehroutes::writeXMLRoute(OutputDevice& os, int index) const {
     236        11333 :     if (index == 0 && !myIncludeIncomplete && myReplacedRoutes[index].route->size() == 2 &&
     237       182894 :             myReplacedRoutes[index].route->getEdges().front()->isTazConnector() &&
     238            0 :             myReplacedRoutes[index].route->getEdges().back()->isTazConnector()) {
     239              :         return;
     240              :     }
     241              :     // check if a previous route shall be written
     242              :     //std::cout << " writeXMLRoute index=" << index << " numReroutes=" << myHolder.getNumberReroutes() << "\n";
     243       178641 :     const int routesToSkip = myHolder.getParameter().wasSet(VEHPARS_FORCE_REROUTE) ? 1 : 0;
     244       178641 :     os.openTag(SUMO_TAG_ROUTE);
     245       178641 :     if (index >= 0) {
     246              :         assert((int)myReplacedRoutes.size() > index);
     247        44088 :         if (myDUAStyle || myWriteCosts) {
     248        17021 :             os.writeAttr(SUMO_ATTR_COST, myReplacedRoutes[index].route->getCosts());
     249              :         }
     250        44088 :         if (myWriteCosts) {
     251        17021 :             os.writeAttr(SUMO_ATTR_SAVINGS, myReplacedRoutes[index].route->getSavings());
     252              :         }
     253              :         // write edge on which the vehicle was when the route was valid
     254       130908 :         os.writeAttr("replacedOnEdge", (myReplacedRoutes[index].edge ?
     255              :                                         myReplacedRoutes[index].edge->getID() : ""));
     256        44088 :         if (myReplacedRoutes[index].lastRouteIndex > 0) {
     257              :             // do not write the default
     258        30189 :             os.writeAttr(SUMO_ATTR_REPLACED_ON_INDEX, myReplacedRoutes[index].lastRouteIndex);
     259              :         }
     260              :         // write the reason for replacement
     261        44088 :         os.writeAttr("reason", myReplacedRoutes[index].info);
     262              : 
     263              :         // write the time at which the route was replaced
     264        44088 :         os.writeAttr(SUMO_ATTR_REPLACED_AT_TIME, time2string(myReplacedRoutes[index].time));
     265        44088 :         os.writeAttr(SUMO_ATTR_PROB, "0");
     266        44088 :         OutputDevice_String edgesD;
     267              :         // always write the part that was actually driven and the rest of the current route that wasn't yet driven
     268              :         int start = 0;
     269       205546 :         for (int i = routesToSkip; i < index; i++) {
     270       161458 :             if (myReplacedRoutes[i].edge != nullptr) {
     271       160683 :                 int end = myReplacedRoutes[i].lastRouteIndex;
     272       160683 :                 myReplacedRoutes[i].route->writeEdgeIDs(edgesD, start, end, myWriteInternal, myHolder.getVClass());
     273              :             }
     274       161458 :             start = myReplacedRoutes[i].newRouteIndex;
     275              :         }
     276        44088 :         myReplacedRoutes[index].route->writeEdgeIDs(edgesD, start, -1, myWriteInternal, myHolder.getVClass());
     277        44088 :         std::string edgesS = edgesD.getString();
     278              :         edgesS.pop_back(); // remove last ' '
     279        44088 :         os.writeAttr(SUMO_ATTR_EDGES, edgesS);
     280        44088 :         if (myRouteLength) {
     281         8527 :             const bool includeInternalLengths = MSGlobals::gUsingInternalLanes && MSNet::getInstance()->hasInternalLinks();
     282              :             ConstMSRoutePtr route = myReplacedRoutes[index].route;
     283         8527 :             const double routeLength = route->getDistanceBetween(myHolder.getDepartPos(), route->getEdges().back()->getLength(),
     284         8527 :                                        route->begin(), route->end(), includeInternalLengths);
     285         8527 :             os.writeAttr("routeLength", routeLength);
     286              :         }
     287        44088 :     } else {
     288       134553 :         if (myDUAStyle || myWriteCosts) {
     289        37867 :             os.writeAttr(SUMO_ATTR_COST, myHolder.getRoute().getCosts());
     290              :         }
     291       134553 :         if (myWriteCosts) {
     292        37861 :             os.writeAttr(SUMO_ATTR_SAVINGS, myHolder.getRoute().getSavings());
     293              :         }
     294       134553 :         OutputDevice_String edgesD;
     295              :         int numWritten = 0;
     296              :         int start = 0;
     297       134553 :         if (myHolder.getNumberReroutes() > 0) {
     298              :             assert((int)myReplacedRoutes.size() <= myHolder.getNumberReroutes());
     299       108110 :             for (int i = routesToSkip; i < (int)myReplacedRoutes.size(); i++) {
     300        43299 :                 if (myReplacedRoutes[i].edge != nullptr) {
     301        42087 :                     int end = myReplacedRoutes[i].lastRouteIndex;
     302        42087 :                     numWritten += myReplacedRoutes[i].route->writeEdgeIDs(edgesD, start, end, myWriteInternal, myHolder.getVClass());
     303              :                 }
     304        43299 :                 start = myReplacedRoutes[i].newRouteIndex;
     305              :             }
     306              :         }
     307       134553 :         numWritten += myCurrentRoute->writeEdgeIDs(edgesD, start, -1, myWriteInternal, myHolder.getVClass());
     308       134553 :         std::string edgesS = edgesD.getString();
     309              :         edgesS.pop_back(); // remove last ' '
     310       134553 :         os.writeAttr(SUMO_ATTR_EDGES, edgesS);
     311              : 
     312       134553 :         if (mySaveExits) {
     313              :             std::vector<std::string> exits;
     314       152711 :             for (SUMOTime t : myExits) {
     315       282888 :                 exits.push_back(time2string(t));
     316              :             }
     317              :             assert(numWritten >= (int)myExits.size());
     318        22534 :             std::vector<std::string> missing(numWritten - (int)myExits.size(), "-1");
     319        11267 :             exits.insert(exits.end(), missing.begin(), missing.end());
     320        11267 :             os.writeAttr(SUMO_ATTR_EXITTIMES, exits);
     321        11267 :         }
     322       134553 :     }
     323       357282 :     os.closeTag();
     324              : }
     325              : 
     326              : 
     327              : void
     328       132952 : MSDevice_Vehroutes::generateOutput(OutputDevice* /*tripinfoOut*/) const {
     329       132952 :     writeOutput(true);
     330       132952 : }
     331              : 
     332              : 
     333              : void
     334       134559 : MSDevice_Vehroutes::writeOutput(const bool hasArrived) const {
     335       134559 :     const OptionsCont& oc = OptionsCont::getOptions();
     336       134559 :     OutputDevice& routeOut = OutputDevice::getDeviceByOption("vehroute-output");
     337       134559 :     OutputDevice_String stringOut(1);
     338       134559 :     OutputDevice& od = mySorted && routeOut.isXML() ? stringOut : routeOut;
     339       134559 :     SUMOVehicleParameter tmp = myHolder.getParameter();
     340       134559 :     tmp.depart = myIntendedDepart ? myHolder.getParameter().depart : myHolder.getDeparture();
     341       134559 :     if (!MSGlobals::gUseMesoSim) {
     342        98715 :         if (tmp.wasSet(VEHPARS_DEPARTLANE_SET)) {
     343        15434 :             tmp.departLaneProcedure = DepartLaneDefinition::GIVEN;
     344        15434 :             tmp.departLane = myDepartLane;
     345              :         }
     346        98715 :         if (tmp.wasSet(VEHPARS_DEPARTPOSLAT_SET)) {
     347            8 :             tmp.departPosLatProcedure = (tmp.departPosLatProcedure == DepartPosLatDefinition::RANDOM
     348            4 :                                          ? DepartPosLatDefinition::GIVEN_VEHROUTE
     349              :                                          : DepartPosLatDefinition::GIVEN);
     350            4 :             tmp.departPosLat = myDepartPosLat;
     351              :         }
     352              :     }
     353       134559 :     if (tmp.wasSet(VEHPARS_DEPARTPOS_SET)) {
     354        72210 :         tmp.departPosProcedure = ((tmp.departPosProcedure != DepartPosDefinition::GIVEN
     355        36105 :                                    && tmp.departPosProcedure != DepartPosDefinition::STOP)
     356        36105 :                                   ? DepartPosDefinition::GIVEN_VEHROUTE
     357              :                                   : DepartPosDefinition::GIVEN);
     358        36105 :         tmp.departPos = myDepartPos;
     359              :     }
     360       134559 :     if (tmp.wasSet(VEHPARS_DEPARTSPEED_SET)) {
     361        94688 :         tmp.departSpeedProcedure = ((tmp.departSpeedProcedure != DepartSpeedDefinition::GIVEN
     362        47344 :                                      && tmp.departSpeedProcedure != DepartSpeedDefinition::LIMIT)
     363        47344 :                                     ? DepartSpeedDefinition::GIVEN_VEHROUTE
     364              :                                     : DepartSpeedDefinition::GIVEN);
     365        47344 :         tmp.departSpeed = myDepartSpeed;
     366              :     }
     367       401671 :     if (oc.getBool("vehroute-output.speedfactor") ||
     368       484874 :             (oc.isDefault("vehroute-output.speedfactor") && tmp.wasSet(VEHPARS_DEPARTSPEED_SET))) {
     369        49344 :         tmp.parametersSet |= VEHPARS_SPEEDFACTOR_SET;
     370        49344 :         tmp.speedFactor = myHolder.getChosenSpeedFactor();
     371              :     }
     372              : 
     373       134559 :     const std::string typeID = myHolder.getVehicleType().getID() != DEFAULT_VTYPE_ID ? myHolder.getVehicleType().getID() : "";
     374       134559 :     tmp.write(od, oc, SUMO_TAG_VEHICLE, typeID);
     375       134559 :     if (hasArrived) {
     376       265904 :         od.writeAttr("arrival", time2string(MSNet::getInstance()->getCurrentTimeStep()));
     377              :     }
     378       134559 :     if (myRouteLength) {
     379         1134 :         const bool includeInternalLengths = MSGlobals::gUsingInternalLanes && MSNet::getInstance()->hasInternalLinks();
     380         1134 :         const double finalPos = hasArrived ? myHolder.getArrivalPos() : myHolder.getPositionOnLane();
     381         2268 :         const double routeLength = myHolder.getRoute().getDistanceBetween(myHolder.getDepartPos(), finalPos,
     382         1134 :                                    myHolder.getRoute().begin(), myHolder.getCurrentRouteEdge(), includeInternalLengths);
     383         1134 :         od.writeAttr("routeLength", routeLength);
     384              :     }
     385       134559 :     if (myDUAStyle) {
     386           12 :         const RandomDistributor<ConstMSRoutePtr>* const routeDist = MSRoute::distDictionary("!" + myHolder.getID());
     387           12 :         if (routeDist != nullptr) {
     388              :             const std::vector<ConstMSRoutePtr>& routes = routeDist->getVals();
     389            6 :             unsigned index = 0;
     390            6 :             while (index < routes.size() && routes[index] != myCurrentRoute) {
     391            0 :                 ++index;
     392              :             }
     393            6 :             od.openTag(SUMO_TAG_ROUTE_DISTRIBUTION).writeAttr(SUMO_ATTR_LAST, index);
     394              :             const std::vector<double>& probs = routeDist->getProbs();
     395           18 :             for (int i = 0; i < (int)routes.size(); ++i) {
     396           12 :                 od.setPrecision();
     397           12 :                 od.openTag(SUMO_TAG_ROUTE);
     398           12 :                 od.writeAttr(SUMO_ATTR_COST, routes[i]->getCosts());
     399           12 :                 if (myWriteCosts) {
     400            0 :                     od.writeAttr(SUMO_ATTR_SAVINGS, routes[i]->getSavings());
     401              :                 }
     402           12 :                 od.setPrecision(8);
     403           12 :                 od.writeAttr(SUMO_ATTR_PROB, probs[i]);
     404           12 :                 od.setPrecision();
     405           12 :                 OutputDevice_String edgesD;
     406           12 :                 routes[i]->writeEdgeIDs(edgesD, 0, -1, myWriteInternal, myHolder.getVClass());
     407           12 :                 std::string edgesS = edgesD.getString();
     408              :                 edgesS.pop_back(); // remove last ' '
     409           12 :                 od.writeAttr(SUMO_ATTR_EDGES, edgesS);
     410           24 :                 od.closeTag();
     411           12 :             }
     412           12 :             od.closeTag();
     413              :         } else {
     414            6 :             writeXMLRoute(od);
     415              :         }
     416              :     } else {
     417              :         std::string dummyMsg;
     418       134547 :         const int routesToSkip = (myHolder.getParameter().wasSet(VEHPARS_FORCE_REROUTE)
     419        55266 :                                   && !myIncludeIncomplete
     420        55146 :                                   && myReplacedRoutes.size() > 0
     421       188017 :                                   && !myReplacedRoutes[0].isValid ? 1 : 0);
     422       134547 :         if ((int)myReplacedRoutes.size() > routesToSkip) {
     423        25180 :             od.openTag(SUMO_TAG_ROUTE_DISTRIBUTION);
     424        69268 :             for (int i = routesToSkip; i < (int)myReplacedRoutes.size(); ++i) {
     425        44088 :                 writeXMLRoute(od, i);
     426              :             }
     427        25180 :             writeXMLRoute(od);
     428        50360 :             od.closeTag();
     429              :         } else {
     430       109367 :             writeXMLRoute(od);
     431              :         }
     432              :     }
     433       134559 :     if (routeOut.isXML()) {
     434       268418 :         od << myStopOut.getString();
     435              :     }
     436       134559 :     myHolder.getParameter().writeParams(od);
     437       134559 :     od.closeTag();
     438       134559 :     od.lf();
     439       134559 :     if (mySorted && routeOut.isXML()) {
     440              :         // numerical id reflects loading order
     441         8844 :         writeSortedOutput(&myRouteInfos, tmp.depart, myHolder.getNumericalID(), stringOut.getString());
     442              :     }
     443       134559 : }
     444              : 
     445              : 
     446              : ConstMSRoutePtr
     447            0 : MSDevice_Vehroutes::getRoute(int index) const {
     448            0 :     if (index < (int)myReplacedRoutes.size()) {
     449            0 :         return myReplacedRoutes[index].route;
     450              :     } else {
     451              :         return nullptr;
     452              :     }
     453              : }
     454              : 
     455              : 
     456              : void
     457       111472 : MSDevice_Vehroutes::addRoute(const std::string& info) {
     458       111472 :     if (myMaxRoutes > 0) {
     459              :         //std::cout << SIMTIME << " " << getID() << " departed=" << myHolder.hasDeparted() << " lastIndex=" << myLastRouteIndex << " start=" << myHolder.getRoutePosition() << "\n";
     460       496542 :         myReplacedRoutes.push_back(RouteReplaceInfo(
     461       147531 :                                        myHolder.hasDeparted() ?  myHolder.getEdge() : nullptr,
     462              :                                        MSNet::getInstance()->getCurrentTimeStep(), myCurrentRoute, info,
     463              :                                        myLastRouteIndex,
     464        46791 :                                        myHolder.hasDeparted() ? myHolder.getRoutePosition() : 0,
     465       100740 :                                        myCurrentValid));
     466       100740 :         if ((int)myReplacedRoutes.size() > myMaxRoutes) {
     467              :             myReplacedRoutes.erase(myReplacedRoutes.begin());
     468              :         }
     469              :     }
     470              :     std::string dummyMsg;
     471       111472 :     myCurrentRoute = myHolder.getRoutePtr();
     472       222944 :     myCurrentValid = myHolder.hasValidRoute(dummyMsg, myCurrentRoute);
     473       111472 : }
     474              : 
     475              : 
     476              : void
     477        41363 : MSDevice_Vehroutes::writePendingOutput(const bool includeUnfinished) {
     478        41363 :     MSNet* const net = MSNet::getInstance();
     479              : 
     480        41363 :     if (!includeUnfinished) {
     481        40867 :         if (mySorted) {
     482          118 :             for (const auto& routeInfo : myRouteInfos.routeXML) {
     483           36 :                 for (const auto& rouXML : routeInfo.second) {
     484           20 :                     (*myRouteInfos.routeOut) << rouXML.second;
     485              :                 }
     486              :             }
     487          102 :             if (net->hasPersons()) {
     488           23 :                 const SortedRouteInfo& personRouteInfos = net->getPersonControl().getRouteInfo();
     489           23 :                 if (personRouteInfos.routeOut != myRouteInfos.routeOut) {
     490            0 :                     for (const auto& routeInfo : personRouteInfos.routeXML) {
     491            0 :                         for (const auto& rouXML : routeInfo.second) {
     492            0 :                             (*personRouteInfos.routeOut) << rouXML.second;
     493              :                         }
     494              :                     }
     495              :                 }
     496              :             }
     497              :         }
     498        40867 :         return;
     499              :     }
     500         2103 :     for (const auto& it : myStateListener.myDevices) {
     501         1607 :         if (it.first->hasDeparted()) {
     502         1607 :             if (it.first->isStopped()) {
     503          869 :                 it.second->notifyStopEnded();
     504              :             }
     505         1607 :             it.second->writeOutput(false);
     506              :         }
     507              :     }
     508              :     // unfinished persons
     509          496 :     if (net->hasPersons()) {
     510          287 :         MSTransportableControl& pc = net->getPersonControl();
     511          393 :         while (pc.loadedBegin() != pc.loadedEnd()) {
     512          106 :             pc.erase(pc.loadedBegin()->second);
     513              :         }
     514              :     }
     515              :     // Flush any remaining sorted outputs that may still be buffered
     516          496 :     if (mySorted) {
     517            4 :         for (const auto& routeInfo : myRouteInfos.routeXML) {
     518            4 :             for (const auto& rouXML : routeInfo.second) {
     519            2 :                 (*myRouteInfos.routeOut) << rouXML.second;
     520              :             }
     521              :         }
     522            2 :         if (net->hasPersons()) {
     523            0 :             const SortedRouteInfo& personRouteInfos = net->getPersonControl().getRouteInfo();
     524            0 :             if (personRouteInfos.routeOut != myRouteInfos.routeOut) {
     525            0 :                 for (const auto& routeInfo : personRouteInfos.routeXML) {
     526            0 :                     for (const auto& rouXML : routeInfo.second) {
     527            0 :                         (*personRouteInfos.routeOut) << rouXML.second;
     528              :                     }
     529              :                 }
     530              :             }
     531              :         }
     532              :     }
     533              : }
     534              : 
     535              : 
     536              : void
     537          108 : MSDevice_Vehroutes::registerTransportableDepart(SUMOTime depart) {
     538          108 :     myRouteInfos.departureCounts[depart]++;
     539          108 : }
     540              : 
     541              : 
     542              : void
     543         4544 : MSDevice_Vehroutes::writeSortedOutput(MSDevice_Vehroutes::SortedRouteInfo* routeInfo, SUMOTime depart, const SUMOTrafficObject::NumericalID id, const std::string& xmlOutput) {
     544         4544 :     if (routeInfo->routeOut == myRouteInfos.routeOut) {
     545              :         routeInfo = &myRouteInfos;
     546              :     }
     547         4544 :     routeInfo->routeXML[depart][id] = xmlOutput;
     548         4544 :     routeInfo->departureCounts[depart]--;
     549              :     std::map<const SUMOTime, int>::iterator it = routeInfo->departureCounts.begin();
     550         7806 :     while (it != routeInfo->departureCounts.end() && it->second == 0) {
     551         7784 :         for (const auto& rouXML : routeInfo->routeXML[it->first]) {
     552         4522 :             (*routeInfo->routeOut) << rouXML.second;
     553              :         }
     554              :         routeInfo->routeXML.erase(it->first);
     555              :         it = routeInfo->departureCounts.erase(it);
     556              :     }
     557         4544 : }
     558              : 
     559              : 
     560              : void
     561         3168 : MSDevice_Vehroutes::saveState(OutputDevice& out) const {
     562         3168 :     out.openTag(SUMO_TAG_DEVICE);
     563         3168 :     out.writeAttr(SUMO_ATTR_ID, getID());
     564              :     std::vector<std::string> internals;
     565         3168 :     if (!MSGlobals::gUseMesoSim) {
     566         1847 :         internals.push_back(toString(myDepartLane));
     567         3694 :         internals.push_back(toString(myDepartPosLat));
     568              :     }
     569         3168 :     internals.push_back(toString(myDepartSpeed));
     570         3168 :     internals.push_back(toString(myDepartPos));
     571         3168 :     internals.push_back(toString(myReplacedRoutes.size()));
     572         6022 :     for (int i = 0; i < (int)myReplacedRoutes.size(); ++i) {
     573         2854 :         const std::string replacedOnEdge = myReplacedRoutes[i].edge == nullptr ? "!NULL" : myReplacedRoutes[i].edge->getID();
     574         2854 :         internals.push_back(replacedOnEdge);
     575         5708 :         internals.push_back(toString(myReplacedRoutes[i].time));
     576         2854 :         internals.push_back(myReplacedRoutes[i].route->getID());
     577         2854 :         internals.push_back(myReplacedRoutes[i].info);
     578         2854 :         internals.push_back(toString(myReplacedRoutes[i].lastRouteIndex));
     579         2854 :         internals.push_back(toString(myReplacedRoutes[i].newRouteIndex));
     580         5708 :         internals.push_back(toString(myReplacedRoutes[i].isValid));
     581              :     }
     582         3168 :     out.writeAttr(SUMO_ATTR_STATE, toString(internals));
     583         3168 :     if (mySaveExits && myExits.size() > 0) {
     584           11 :         out.writeAttr(SUMO_ATTR_EXITTIMES, myExits);
     585           11 :         out.writeAttr(SUMO_ATTR_EDGE, myLastSavedAt->getID());
     586              :     }
     587         3168 :     out.closeTag();
     588         3168 : }
     589              : 
     590              : 
     591              : void
     592         2264 : MSDevice_Vehroutes::loadState(const SUMOSAXAttributes& attrs) {
     593         2264 :     std::istringstream bis(attrs.getString(SUMO_ATTR_STATE));
     594         2264 :     if (!MSGlobals::gUseMesoSim) {
     595         1320 :         bis >> myDepartLane;
     596         1320 :         bis >> myDepartPosLat;
     597              :     }
     598         2264 :     bis >> myDepartSpeed;
     599         2264 :     bis >> myDepartPos;
     600              :     int size;
     601         2264 :     bis >> size;
     602         4095 :     for (int i = 0; i < size; ++i) {
     603              :         std::string edgeID;
     604              :         SUMOTime time;
     605              :         std::string routeID;
     606              :         std::string info;
     607              :         int lastIndex;
     608              :         int newIndex;
     609         1831 :         bis >> edgeID;
     610              :         bis >> time;
     611         1831 :         bis >> routeID;
     612         1831 :         bis >> info;
     613         1831 :         bis >> lastIndex;
     614         1831 :         bis >> newIndex;
     615         1831 :         bis >> myCurrentValid;
     616              : 
     617         1831 :         ConstMSRoutePtr route = MSRoute::dictionary(routeID);
     618         1831 :         if (route != nullptr) {
     619         2841 :             myReplacedRoutes.push_back(RouteReplaceInfo(MSEdge::dictionary(edgeID), time, route, info, lastIndex, newIndex, myCurrentValid));
     620              :         }
     621              :     }
     622         2264 :     if (mySaveExits && attrs.hasAttribute(SUMO_ATTR_EXITTIMES)) {
     623           11 :         bool ok = true;
     624           30 :         for (const std::string& t : attrs.get<std::vector<std::string> >(SUMO_ATTR_EXITTIMES, nullptr, ok)) {
     625           19 :             myExits.push_back(StringUtils::toLong(t));
     626           11 :         }
     627           11 :         if (attrs.hasAttribute(SUMO_ATTR_EDGE)) {
     628           11 :             myLastSavedAt = MSEdge::dictionary(attrs.getString(SUMO_ATTR_EDGE));
     629              :         }
     630              :     }
     631         2264 :     if (myHolder.hasDeparted()) {
     632          788 :         myLastRouteIndex = myHolder.getRoutePosition();
     633              :     }
     634         2264 : }
     635              : 
     636              : 
     637              : /****************************************************************************/
        

Generated by: LCOV version 2.0-1