LCOV - code coverage report
Current view: top level - src/microsim/devices - MSDevice_Vehroutes.cpp (source / functions) Hit Total Coverage
Test: lcov.info Lines: 311 320 97.2 %
Date: 2024-04-30 15:40:33 Functions: 19 20 95.0 %

          Line data    Source code
       1             : /****************************************************************************/
       2             : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
       3             : // Copyright (C) 2009-2024 German Aerospace Center (DLR) and others.
       4             : // This program and the accompanying materials are made available under the
       5             : // terms of the Eclipse Public License 2.0 which is available at
       6             : // https://www.eclipse.org/legal/epl-2.0/
       7             : // This Source Code may also be made available under the following Secondary
       8             : // Licenses when the conditions for such availability set forth in the Eclipse
       9             : // Public License 2.0 are satisfied: GNU General Public License, version 2
      10             : // or later which is available at
      11             : // https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html
      12             : // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
      13             : /****************************************************************************/
      14             : /// @file    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       34656 : MSDevice_Vehroutes::init() {
      67       34656 :     const OptionsCont& oc = OptionsCont::getOptions();
      68       69312 :     if (oc.isSet("vehroute-output")) {
      69       10708 :         OutputDevice::createDeviceByOption("vehroute-output", "routes", "routes_file.xsd");
      70        5345 :         mySaveExits = oc.getBool("vehroute-output.exit-times");
      71        5345 :         myLastRouteOnly = oc.getBool("vehroute-output.last-route");
      72        5345 :         myDUAStyle = oc.getBool("vehroute-output.dua");
      73        5345 :         myWriteCosts = oc.getBool("vehroute-output.cost");
      74        5432 :         mySorted = myDUAStyle || oc.getBool("vehroute-output.sorted");
      75        5345 :         myIntendedDepart = oc.getBool("vehroute-output.intended-depart");
      76        5345 :         myRouteLength = oc.getBool("vehroute-output.route-length");
      77        5345 :         mySkipPTLines = oc.getBool("vehroute-output.skip-ptlines");
      78        5345 :         myIncludeIncomplete = oc.getBool("vehroute-output.incomplete");
      79        5345 :         myWriteStopPriorEdges = oc.getBool("vehroute-output.stop-edges");
      80        5345 :         myWriteInternal = oc.getBool("vehroute-output.internal");
      81        5345 :         MSNet::getInstance()->addVehicleStateListener(&myStateListener);
      82        5345 :         myRouteInfos.routeOut = &OutputDevice::getDeviceByOption("vehroute-output");
      83             :     }
      84       34650 : }
      85             : 
      86             : 
      87             : void
      88       36322 : MSDevice_Vehroutes::insertOptions(OptionsCont& oc) {
      89       36322 :     oc.addOptionSubTopic("Vehroutes Device");
      90       72644 :     insertDefaultAssignmentOptions("vehroute", "Vehroutes Device", oc);
      91       36322 : }
      92             : 
      93             : 
      94             : MSDevice_Vehroutes*
      95     5338584 : MSDevice_Vehroutes::buildVehicleDevices(SUMOVehicle& v, std::vector<MSVehicleDevice*>& into, int maxRoutes) {
      96     5338584 :     if (maxRoutes < std::numeric_limits<int>::max()) {
      97     1365602 :         return new MSDevice_Vehroutes(v, "vehroute_" + v.getID(), maxRoutes);
      98             :     }
      99     4655783 :     if (mySkipPTLines && v.getParameter().line != "") {
     100             :         return nullptr;
     101             :     }
     102     4654741 :     OptionsCont& oc = OptionsCont::getOptions();
     103     9309482 :     if (equippedByDefaultAssignmentOptions(oc, "vehroute", v, oc.isSet("vehroute-output"))) {
     104      126084 :         if (myLastRouteOnly) {
     105             :             maxRoutes = 0;
     106             :         }
     107      126084 :         myStateListener.myDevices[&v] = new MSDevice_Vehroutes(v, "vehroute_" + v.getID(), maxRoutes);
     108      126084 :         into.push_back(myStateListener.myDevices[&v]);
     109      126084 :         return myStateListener.myDevices[&v];
     110             :     }
     111             :     return nullptr;
     112             : }
     113             : 
     114             : 
     115             : // ---------------------------------------------------------------------------
     116             : // MSDevice_Vehroutes::StateListener-methods
     117             : // ---------------------------------------------------------------------------
     118             : void
     119      462153 : MSDevice_Vehroutes::StateListener::vehicleStateChanged(const SUMOVehicle* const vehicle, MSNet::VehicleState to, const std::string& info) {
     120      462153 :     if (to == MSNet::VehicleState::NEWROUTE) {
     121             :         const auto& deviceEntry = myDevices.find(vehicle);
     122       75662 :         if (deviceEntry != myDevices.end()) {
     123       74333 :             deviceEntry->second->addRoute(info);
     124             :         }
     125             :     }
     126      462153 : }
     127             : 
     128             : 
     129             : // ---------------------------------------------------------------------------
     130             : // MSDevice_Vehroutes-methods
     131             : // ---------------------------------------------------------------------------
     132      808885 : MSDevice_Vehroutes::MSDevice_Vehroutes(SUMOVehicle& holder, const std::string& id, int maxRoutes) :
     133             :     MSVehicleDevice(holder, id),
     134      808885 :     myCurrentRoute(holder.getRoutePtr()),
     135      808885 :     myMaxRoutes(maxRoutes),
     136      808885 :     myLastSavedAt(nullptr),
     137      808885 :     myLastRouteIndex(-1),
     138      808885 :     myDepartLane(-1),
     139      808885 :     myDepartPos(-1),
     140      808885 :     myDepartSpeed(-1),
     141      808885 :     myDepartPosLat(0),
     142      808885 :     myStopOut(2) {
     143      808885 : }
     144             : 
     145             : 
     146     1617644 : MSDevice_Vehroutes::~MSDevice_Vehroutes() {
     147      808822 :     myStateListener.myDevices.erase(&myHolder);
     148     3235288 : }
     149             : 
     150             : 
     151             : bool
     152    11761394 : MSDevice_Vehroutes::notifyEnter(SUMOTrafficObject& veh, MSMoveReminder::Notification reason, const MSLane* enteredLane) {
     153    11761394 :     if (reason == MSMoveReminder::NOTIFICATION_DEPARTED) {
     154      693517 :         if (mySorted && myStateListener.myDevices[static_cast<SUMOVehicle*>(&veh)] == this) {
     155        7416 :             const SUMOTime departure = myIntendedDepart ? myHolder.getParameter().depart : MSNet::getInstance()->getCurrentTimeStep();
     156        7416 :             myRouteInfos.departureCounts[departure]++;
     157             :         }
     158      693517 :         if (!MSGlobals::gUseMesoSim) {
     159             :             const MSVehicle& vehicle = static_cast<MSVehicle&>(veh);
     160      410252 :             myDepartLane = vehicle.getLane()->getIndex();
     161      410252 :             myDepartPosLat = vehicle.getLateralPositionOnLane();
     162             :         }
     163      693517 :         myDepartSpeed = veh.getSpeed();
     164      693517 :         myDepartPos = veh.getPositionOnLane();
     165             :     }
     166    11761394 :     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    11761394 :     myLastRouteIndex = myHolder.getRoutePosition();
     177    11761394 :     return true;
     178             : }
     179             : 
     180             : 
     181             : bool
     182    11729676 : MSDevice_Vehroutes::notifyLeave(SUMOTrafficObject& veh, double /*lastPos*/, MSMoveReminder::Notification reason, const MSLane* /* enteredLane */) {
     183    11729676 :     if (mySaveExits && reason != NOTIFICATION_LANE_CHANGE && reason != NOTIFICATION_PARKING && reason != NOTIFICATION_SEGMENT) {
     184      281261 :         const MSEdge* edge = myWriteInternal ? dynamic_cast<MSBaseVehicle&>(veh).getCurrentEdge() : veh.getEdge();
     185      281261 :         if (myLastSavedAt != edge) {
     186      159028 :             myExits.push_back(MSNet::getInstance()->getCurrentTimeStep());
     187      159028 :             myLastSavedAt = edge;
     188             :         }
     189             :     }
     190    11729676 :     return true;
     191             : }
     192             : 
     193             : 
     194             : void
     195       17425 : MSDevice_Vehroutes::notifyStopEnded() {
     196       17425 :     const SUMOVehicleParameter::Stop& stop = myHolder.getStops().front().pars;
     197       17425 :     const bool closeLater = myWriteStopPriorEdges || mySaveExits;
     198       17425 :     stop.write(myStopOut, !closeLater);
     199       17425 :     if (myWriteStopPriorEdges) {
     200             :         // calculate length
     201          16 :         double priorEdgesLength = 0;
     202          40 :         for (int i = 0; i < (int)myPriorEdges.size(); i++) {
     203          24 :             if (i == 0) {
     204          16 :                 priorEdgesLength += myPriorEdges.at(i)->getLength();
     205           8 :             } else if (myPriorEdges.at(i)->getID() != myPriorEdges.at(i - 1)->getID()) {
     206           8 :                 priorEdgesLength += myPriorEdges.at(i)->getLength();
     207             :             }
     208             :         }
     209          32 :         myStopOut.writeAttr("priorEdges", myPriorEdges);
     210             :         myPriorEdges.clear();
     211          32 :         myStopOut.writeAttr("priorEdgesLength", priorEdgesLength);
     212             :     }
     213       17425 :     if (mySaveExits) {
     214        1437 :         myStopOut.writeAttr(SUMO_ATTR_STARTED, time2string(stop.started));
     215        2874 :         myStopOut.writeAttr(SUMO_ATTR_ENDED, stop.ended < 0 ? "-1" : time2string(stop.ended));
     216             :     }
     217       17425 :     if (closeLater) {
     218        2906 :         myStopOut.closeTag();
     219             :     }
     220       17425 : }
     221             : 
     222             : 
     223             : void
     224      151405 : MSDevice_Vehroutes::writeXMLRoute(OutputDevice& os, int index) const {
     225        9968 :     if (index == 0 && !myIncludeIncomplete && myReplacedRoutes[index].route->size() == 2 &&
     226      155017 :             myReplacedRoutes[index].route->getEdges().front()->isTazConnector() &&
     227           0 :             myReplacedRoutes[index].route->getEdges().back()->isTazConnector()) {
     228             :         return;
     229             :     }
     230             :     // check if a previous route shall be written
     231             :     //std::cout << " writeXMLRoute index=" << index << " numReroutes=" << myHolder.getNumberReroutes() << "\n";
     232      151405 :     const int routesToSkip = myHolder.getParameter().wasSet(VEHPARS_FORCE_REROUTE) ? 1 : 0;
     233      151405 :     os.openTag(SUMO_TAG_ROUTE);
     234      151405 :     if (index >= 0) {
     235             :         assert((int)myReplacedRoutes.size() > index);
     236       35455 :         if (myDUAStyle || myWriteCosts) {
     237       26164 :             os.writeAttr(SUMO_ATTR_COST, myReplacedRoutes[index].route->getCosts());
     238             :         }
     239       35455 :         if (myWriteCosts) {
     240       26164 :             os.writeAttr(SUMO_ATTR_SAVINGS, myReplacedRoutes[index].route->getSavings());
     241             :         }
     242             :         // write edge on which the vehicle was when the route was valid
     243      105226 :         os.writeAttr("replacedOnEdge", (myReplacedRoutes[index].edge ?
     244             :                                         myReplacedRoutes[index].edge->getID() : ""));
     245       35455 :         if (myReplacedRoutes[index].lastRouteIndex > 0) {
     246             :             // do not write the default
     247       24891 :             os.writeAttr(SUMO_ATTR_REPLACED_ON_INDEX, myReplacedRoutes[index].lastRouteIndex);
     248             :         }
     249             :         // write the reason for replacement
     250       70910 :         os.writeAttr("reason", myReplacedRoutes[index].info);
     251             : 
     252             :         // write the time at which the route was replaced
     253       70910 :         os.writeAttr(SUMO_ATTR_REPLACED_AT_TIME, time2string(myReplacedRoutes[index].time));
     254             :         os.writeAttr(SUMO_ATTR_PROB, "0");
     255       35455 :         OutputDevice_String edgesD;
     256             :         // always write the part that was actually driven and the rest of the current route that wasn't yet driven
     257             :         int start = 0;
     258      144715 :         for (int i = routesToSkip; i < index; i++) {
     259      109260 :             if (myReplacedRoutes[i].edge != nullptr) {
     260      109020 :                 int end = myReplacedRoutes[i].lastRouteIndex;
     261      109020 :                 myReplacedRoutes[i].route->writeEdgeIDs(edgesD, start, end, myWriteInternal, myHolder.getVClass());
     262             :             }
     263      109260 :             start = myReplacedRoutes[i].newRouteIndex;
     264             :         }
     265       35455 :         myReplacedRoutes[index].route->writeEdgeIDs(edgesD, start, -1, myWriteInternal, myHolder.getVClass());
     266       35455 :         std::string edgesS = edgesD.getString();
     267             :         edgesS.pop_back(); // remove last ' '
     268             :         os.writeAttr(SUMO_ATTR_EDGES, edgesS);
     269       35455 :         if (myRouteLength) {
     270        6220 :             const bool includeInternalLengths = MSGlobals::gUsingInternalLanes && MSNet::getInstance()->hasInternalLinks();
     271             :             ConstMSRoutePtr route = myReplacedRoutes[index].route;
     272        6220 :             const double routeLength = route->getDistanceBetween(myHolder.getDepartPos(), route->getEdges().back()->getLength(),
     273        6220 :                                        route->begin(), route->end(), includeInternalLengths);
     274       12440 :             os.writeAttr("routeLength", routeLength);
     275             :         }
     276       35455 :     } else {
     277      115950 :         if (myDUAStyle || myWriteCosts) {
     278       40326 :             os.writeAttr(SUMO_ATTR_COST, myHolder.getRoute().getCosts());
     279             :         }
     280      115950 :         if (myWriteCosts) {
     281       40314 :             os.writeAttr(SUMO_ATTR_SAVINGS, myHolder.getRoute().getSavings());
     282             :         }
     283      115950 :         OutputDevice_String edgesD;
     284             :         int numWritten = 0;
     285             :         int start = 0;
     286      115950 :         if (myHolder.getNumberReroutes() > 0) {
     287             :             assert((int)myReplacedRoutes.size() <= myHolder.getNumberReroutes());
     288       80763 :             for (int i = routesToSkip; i < (int)myReplacedRoutes.size(); i++) {
     289       34696 :                 if (myReplacedRoutes[i].edge != nullptr) {
     290       33995 :                     int end = myReplacedRoutes[i].lastRouteIndex;
     291       33995 :                     numWritten += myReplacedRoutes[i].route->writeEdgeIDs(edgesD, start, end, myWriteInternal, myHolder.getVClass());
     292             :                 }
     293       34696 :                 start = myReplacedRoutes[i].newRouteIndex;
     294             :             }
     295             :         }
     296      115950 :         numWritten += myCurrentRoute->writeEdgeIDs(edgesD, start, -1, myWriteInternal, myHolder.getVClass());
     297      115950 :         std::string edgesS = edgesD.getString();
     298             :         edgesS.pop_back(); // remove last ' '
     299             :         os.writeAttr(SUMO_ATTR_EDGES, edgesS);
     300             : 
     301      115950 :         if (mySaveExits) {
     302             :             std::vector<std::string> exits;
     303      139046 :             for (SUMOTime t : myExits) {
     304      255742 :                 exits.push_back(time2string(t));
     305             :             }
     306             :             assert(numWritten >= (int)myExits.size());
     307       22350 :             std::vector<std::string> missing(numWritten - (int)myExits.size(), "-1");
     308       11175 :             exits.insert(exits.end(), missing.begin(), missing.end());
     309             :             os.writeAttr(SUMO_ATTR_EXITTIMES, exits);
     310       11175 :         }
     311      115950 :     }
     312      302810 :     os.closeTag();
     313             : }
     314             : 
     315             : 
     316             : void
     317      114932 : MSDevice_Vehroutes::generateOutput(OutputDevice* /*tripinfoOut*/) const {
     318      114932 :     writeOutput(true);
     319      114932 : }
     320             : 
     321             : 
     322             : void
     323      115956 : MSDevice_Vehroutes::writeOutput(const bool hasArrived) const {
     324      115956 :     const OptionsCont& oc = OptionsCont::getOptions();
     325      115956 :     OutputDevice& routeOut = OutputDevice::getDeviceByOption("vehroute-output");
     326      115956 :     OutputDevice_String od(1);
     327      115956 :     SUMOVehicleParameter tmp = myHolder.getParameter();
     328      115956 :     tmp.depart = myIntendedDepart ? myHolder.getParameter().depart : myHolder.getDeparture();
     329      115956 :     if (!MSGlobals::gUseMesoSim) {
     330       85465 :         if (tmp.wasSet(VEHPARS_DEPARTLANE_SET)) {
     331       15594 :             tmp.departLaneProcedure = DepartLaneDefinition::GIVEN;
     332       15594 :             tmp.departLane = myDepartLane;
     333             :         }
     334       85465 :         if (tmp.wasSet(VEHPARS_DEPARTPOSLAT_SET)) {
     335           8 :             tmp.departPosLatProcedure = (tmp.departPosLatProcedure == DepartPosLatDefinition::RANDOM
     336           4 :                                          ? DepartPosLatDefinition::GIVEN_VEHROUTE
     337             :                                          : DepartPosLatDefinition::GIVEN);
     338           4 :             tmp.departPosLat = myDepartPosLat;
     339             :         }
     340             :     }
     341      115956 :     if (tmp.wasSet(VEHPARS_DEPARTPOS_SET)) {
     342       77536 :         tmp.departPosProcedure = ((tmp.departPosProcedure != DepartPosDefinition::GIVEN
     343       38768 :                                    && tmp.departPosProcedure != DepartPosDefinition::STOP)
     344       38768 :                                   ? DepartPosDefinition::GIVEN_VEHROUTE
     345             :                                   : DepartPosDefinition::GIVEN);
     346       38768 :         tmp.departPos = myDepartPos;
     347             :     }
     348      115956 :     if (tmp.wasSet(VEHPARS_DEPARTSPEED_SET)) {
     349       90700 :         tmp.departSpeedProcedure = ((tmp.departSpeedProcedure != DepartSpeedDefinition::GIVEN
     350       45350 :                                      && tmp.departSpeedProcedure != DepartSpeedDefinition::LIMIT)
     351       45350 :                                     ? DepartSpeedDefinition::GIVEN_VEHROUTE
     352             :                                     : DepartSpeedDefinition::GIVEN);
     353       45350 :         tmp.departSpeed = myDepartSpeed;
     354             :     }
     355      343862 :     if (oc.getBool("vehroute-output.speedfactor") ||
     356      385200 :             (oc.isDefault("vehroute-output.speedfactor") && tmp.wasSet(VEHPARS_DEPARTSPEED_SET))) {
     357       49350 :         tmp.parametersSet |= VEHPARS_SPEEDFACTOR_SET;
     358       49350 :         tmp.speedFactor = myHolder.getChosenSpeedFactor();
     359             :     }
     360             : 
     361      115956 :     const std::string typeID = myHolder.getVehicleType().getID() != DEFAULT_VTYPE_ID ? myHolder.getVehicleType().getID() : "";
     362      115956 :     tmp.write(od, oc, SUMO_TAG_VEHICLE, typeID);
     363      115956 :     if (hasArrived) {
     364      229864 :         od.writeAttr("arrival", time2string(MSNet::getInstance()->getCurrentTimeStep()));
     365             :     }
     366      115956 :     if (myRouteLength) {
     367         851 :         const bool includeInternalLengths = MSGlobals::gUsingInternalLanes && MSNet::getInstance()->hasInternalLinks();
     368         851 :         const double finalPos = hasArrived ? myHolder.getArrivalPos() : myHolder.getPositionOnLane();
     369        1702 :         const double routeLength = myHolder.getRoute().getDistanceBetween(myHolder.getDepartPos(), finalPos,
     370         851 :                                    myHolder.getRoute().begin(), myHolder.getCurrentRouteEdge(), includeInternalLengths);
     371        1702 :         od.writeAttr("routeLength", routeLength);
     372             :     }
     373      115956 :     if (myDUAStyle) {
     374          12 :         const RandomDistributor<ConstMSRoutePtr>* const routeDist = MSRoute::distDictionary("!" + myHolder.getID());
     375          12 :         if (routeDist != nullptr) {
     376             :             const std::vector<ConstMSRoutePtr>& routes = routeDist->getVals();
     377           6 :             unsigned index = 0;
     378           6 :             while (index < routes.size() && routes[index] != myCurrentRoute) {
     379           0 :                 ++index;
     380             :             }
     381           6 :             od.openTag(SUMO_TAG_ROUTE_DISTRIBUTION).writeAttr(SUMO_ATTR_LAST, index);
     382             :             const std::vector<double>& probs = routeDist->getProbs();
     383          18 :             for (int i = 0; i < (int)routes.size(); ++i) {
     384          12 :                 od.setPrecision();
     385          12 :                 od.openTag(SUMO_TAG_ROUTE);
     386          12 :                 od.writeAttr(SUMO_ATTR_COST, routes[i]->getCosts());
     387          12 :                 if (myWriteCosts) {
     388           0 :                     od.writeAttr(SUMO_ATTR_SAVINGS, routes[i]->getSavings());
     389             :                 }
     390          12 :                 od.setPrecision(8);
     391             :                 od.writeAttr(SUMO_ATTR_PROB, probs[i]);
     392          12 :                 od.setPrecision();
     393          12 :                 OutputDevice_String edgesD;
     394          12 :                 routes[i]->writeEdgeIDs(edgesD, 0, -1, myWriteInternal, myHolder.getVClass());
     395          12 :                 std::string edgesS = edgesD.getString();
     396             :                 edgesS.pop_back(); // remove last ' '
     397             :                 od.writeAttr(SUMO_ATTR_EDGES, edgesS);
     398          24 :                 od.closeTag();
     399          12 :             }
     400          12 :             od.closeTag();
     401             :         } else {
     402           6 :             writeXMLRoute(od);
     403             :         }
     404             :     } else {
     405             :         std::string dummyMsg;
     406      115944 :         const int routesToSkip = (myHolder.getParameter().wasSet(VEHPARS_FORCE_REROUTE)
     407       37853 :                                   && !myIncludeIncomplete
     408       37733 :                                   && myReplacedRoutes.size() > 0
     409      189764 :                                   && !myHolder.hasValidRoute(dummyMsg, myReplacedRoutes[0].route) ? 1 : 0);
     410      115944 :         if ((int)myReplacedRoutes.size() > routesToSkip) {
     411       21248 :             od.openTag(SUMO_TAG_ROUTE_DISTRIBUTION);
     412       56703 :             for (int i = routesToSkip; i < (int)myReplacedRoutes.size(); ++i) {
     413       35455 :                 writeXMLRoute(od, i);
     414             :             }
     415       21248 :             writeXMLRoute(od);
     416       42496 :             od.closeTag();
     417             :         } else {
     418       94696 :             writeXMLRoute(od);
     419             :         }
     420             :     }
     421      115956 :     od << myStopOut.getString();
     422      115956 :     myHolder.getParameter().writeParams(od);
     423      115956 :     od.closeTag();
     424      115956 :     od.lf();
     425      115956 :     if (mySorted) {
     426             :         // numerical id reflects loading order
     427       21750 :         writeSortedOutput(&myRouteInfos, tmp.depart, toString(myHolder.getNumericalID()), od.getString());
     428             :     } else {
     429      217412 :         routeOut << od.getString();
     430             :     }
     431      115956 : }
     432             : 
     433             : 
     434             : ConstMSRoutePtr
     435           0 : MSDevice_Vehroutes::getRoute(int index) const {
     436           0 :     if (index < (int)myReplacedRoutes.size()) {
     437           0 :         return myReplacedRoutes[index].route;
     438             :     } else {
     439             :         return nullptr;
     440             :     }
     441             : }
     442             : 
     443             : 
     444             : void
     445       74333 : MSDevice_Vehroutes::addRoute(const std::string& info) {
     446       74333 :     if (myMaxRoutes > 0) {
     447             :         //std::cout << SIMTIME << " " << getID() << " departed=" << myHolder.hasDeparted() << " lastIndex=" << myLastRouteIndex << " start=" << myHolder.getRoutePosition() << "\n";
     448      371598 :         myReplacedRoutes.push_back(RouteReplaceInfo(
     449      111536 :                                        myHolder.hasDeparted() ?  myHolder.getEdge() : nullptr,
     450             :                                        MSNet::getInstance()->getCurrentTimeStep(), myCurrentRoute, info,
     451             :                                        myLastRouteIndex,
     452      111536 :                                        myHolder.hasDeparted() ? myHolder.getRoutePosition() : 0));
     453       74263 :         if ((int)myReplacedRoutes.size() > myMaxRoutes) {
     454             :             myReplacedRoutes.erase(myReplacedRoutes.begin());
     455             :         }
     456             :     }
     457       74333 :     myCurrentRoute = myHolder.getRoutePtr();
     458       74333 : }
     459             : 
     460             : 
     461             : void
     462       33156 : MSDevice_Vehroutes::writePendingOutput(const bool includeUnfinished) {
     463       33156 :     MSNet* const net = MSNet::getInstance();
     464             : 
     465       33156 :     if (!includeUnfinished) {
     466       32885 :         if (mySorted) {
     467         115 :             for (const auto& routeInfo : myRouteInfos.routeXML) {
     468          36 :                 for (const auto& rouXML : routeInfo.second) {
     469          20 :                     (*myRouteInfos.routeOut) << rouXML.second;
     470             :                 }
     471             :             }
     472          99 :             if (net->hasPersons()) {
     473          18 :                 const SortedRouteInfo& personRouteInfos = net->getPersonControl().getRouteInfo();
     474          18 :                 if (personRouteInfos.routeOut != myRouteInfos.routeOut) {
     475           0 :                     for (const auto& routeInfo : personRouteInfos.routeXML) {
     476           0 :                         for (const auto& rouXML : routeInfo.second) {
     477           0 :                             (*personRouteInfos.routeOut) << rouXML.second;
     478             :                         }
     479             :                     }
     480             :                 }
     481             :             }
     482             :         }
     483       32885 :         return;
     484             :     }
     485        1295 :     for (const auto& it : myStateListener.myDevices) {
     486        1024 :         if (it.first->hasDeparted()) {
     487        1024 :             if (it.first->isStopped()) {
     488         445 :                 it.second->notifyStopEnded();
     489             :             }
     490        1024 :             it.second->writeOutput(false);
     491             :         }
     492             :     }
     493             :     // unfinished persons
     494         271 :     if (net->hasPersons()) {
     495         104 :         MSTransportableControl& pc = net->getPersonControl();
     496         128 :         while (pc.loadedBegin() != pc.loadedEnd()) {
     497          24 :             pc.erase(pc.loadedBegin()->second);
     498             :         }
     499             :     }
     500             : }
     501             : 
     502             : 
     503             : void
     504         108 : MSDevice_Vehroutes::registerTransportableDepart(SUMOTime depart) {
     505         108 :     myRouteInfos.departureCounts[depart]++;
     506         108 : }
     507             : 
     508             : 
     509             : void
     510        7372 : MSDevice_Vehroutes::writeSortedOutput(MSDevice_Vehroutes::SortedRouteInfo* routeInfo, SUMOTime depart, const std::string& id, const std::string& xmlOutput) {
     511        7372 :     if (routeInfo->routeOut == myRouteInfos.routeOut) {
     512             :         routeInfo = &myRouteInfos;
     513             :     }
     514        7372 :     routeInfo->routeXML[depart][id] = xmlOutput;
     515        7372 :     routeInfo->departureCounts[depart]--;
     516             :     std::map<const SUMOTime, int>::iterator it = routeInfo->departureCounts.begin();
     517       12198 :     while (it != routeInfo->departureCounts.end() && it->second == 0) {
     518       12178 :         for (const auto& rouXML : routeInfo->routeXML[it->first]) {
     519        7352 :             (*routeInfo->routeOut) << rouXML.second;
     520             :         }
     521             :         routeInfo->routeXML.erase(it->first);
     522             :         it = routeInfo->departureCounts.erase(it);
     523             :     }
     524        7372 : }
     525             : 
     526             : 
     527             : void
     528        1831 : MSDevice_Vehroutes::saveState(OutputDevice& out) const {
     529        1831 :     out.openTag(SUMO_TAG_DEVICE);
     530             :     out.writeAttr(SUMO_ATTR_ID, getID());
     531             :     std::vector<std::string> internals;
     532        1831 :     if (!MSGlobals::gUseMesoSim) {
     533        1352 :         internals.push_back(toString(myDepartLane));
     534        2704 :         internals.push_back(toString(myDepartPosLat));
     535             :     }
     536        1831 :     internals.push_back(toString(myDepartSpeed));
     537        1831 :     internals.push_back(toString(myDepartPos));
     538        1831 :     internals.push_back(toString(myReplacedRoutes.size()));
     539        2884 :     for (int i = 0; i < (int)myReplacedRoutes.size(); ++i) {
     540        1053 :         const std::string replacedOnEdge = myReplacedRoutes[i].edge == nullptr ? "!NULL" : myReplacedRoutes[i].edge->getID();
     541        1053 :         internals.push_back(replacedOnEdge);
     542        2106 :         internals.push_back(toString(myReplacedRoutes[i].time));
     543        1053 :         internals.push_back(myReplacedRoutes[i].route->getID());
     544        1053 :         internals.push_back(myReplacedRoutes[i].info);
     545        1053 :         internals.push_back(toString(myReplacedRoutes[i].lastRouteIndex));
     546        2106 :         internals.push_back(toString(myReplacedRoutes[i].newRouteIndex));
     547             :     }
     548        1831 :     out.writeAttr(SUMO_ATTR_STATE, toString(internals));
     549        1831 :     if (mySaveExits && myExits.size() > 0) {
     550          11 :         out.writeAttr(SUMO_ATTR_EXITTIMES, myExits);
     551          11 :         out.writeAttr(SUMO_ATTR_EDGE, myLastSavedAt->getID());
     552             :     }
     553        1831 :     out.closeTag();
     554        1831 : }
     555             : 
     556             : 
     557             : void
     558        1597 : MSDevice_Vehroutes::loadState(const SUMOSAXAttributes& attrs) {
     559        1597 :     std::istringstream bis(attrs.getString(SUMO_ATTR_STATE));
     560        1597 :     if (!MSGlobals::gUseMesoSim) {
     561        1196 :         bis >> myDepartLane;
     562        1196 :         bis >> myDepartPosLat;
     563             :     }
     564        1597 :     bis >> myDepartSpeed;
     565        1597 :     bis >> myDepartPos;
     566             :     int size;
     567        1597 :     bis >> size;
     568        2650 :     for (int i = 0; i < size; ++i) {
     569             :         std::string edgeID;
     570             :         SUMOTime time;
     571             :         std::string routeID;
     572             :         std::string info;
     573             :         int lastIndex;
     574             :         int newIndex;
     575        1053 :         bis >> edgeID;
     576             :         bis >> time;
     577        1053 :         bis >> routeID;
     578        1053 :         bis >> info;
     579        1053 :         bis >> lastIndex;
     580        1053 :         bis >> newIndex;
     581             : 
     582        1053 :         ConstMSRoutePtr route = MSRoute::dictionary(routeID);
     583        1053 :         if (route != nullptr) {
     584          75 :             myReplacedRoutes.push_back(RouteReplaceInfo(MSEdge::dictionary(edgeID), time, route, info, lastIndex, newIndex));
     585             :         }
     586             :     }
     587        1597 :     if (mySaveExits && attrs.hasAttribute(SUMO_ATTR_EXITTIMES)) {
     588          11 :         bool ok = true;
     589          24 :         for (const std::string& t : attrs.get<std::vector<std::string> >(SUMO_ATTR_EXITTIMES, nullptr, ok)) {
     590          13 :             myExits.push_back(StringUtils::toLong(t));
     591          11 :         }
     592          11 :         if (attrs.hasAttribute(SUMO_ATTR_EDGE)) {
     593          11 :             myLastSavedAt = MSEdge::dictionary(attrs.getString(SUMO_ATTR_EDGE));
     594             :         }
     595             :     }
     596        1597 : }
     597             : 
     598             : 
     599             : /****************************************************************************/

Generated by: LCOV version 1.14