LCOV - code coverage report
Current view: top level - src/microsim/devices - MSDevice_Tripinfo.cpp (source / functions) Coverage Total Hit
Test: lcov.info Lines: 96.9 % 518 502
Test Date: 2025-11-13 15:38:19 Functions: 93.5 % 46 43

            Line data    Source code
       1              : /****************************************************************************/
       2              : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
       3              : // Copyright (C) 2009-2025 German Aerospace Center (DLR) and others.
       4              : // This program and the accompanying materials are made available under the
       5              : // terms of the Eclipse Public License 2.0 which is available at
       6              : // https://www.eclipse.org/legal/epl-2.0/
       7              : // This Source Code may also be made available under the following Secondary
       8              : // Licenses when the conditions for such availability set forth in the Eclipse
       9              : // Public License 2.0 are satisfied: GNU General Public License, version 2
      10              : // or later which is available at
      11              : // https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html
      12              : // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
      13              : /****************************************************************************/
      14              : /// @file    MSDevice_Tripinfo.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/MSVehicle.h>
      30              : #include <microsim/transportables/MSTransportableControl.h>
      31              : #include <mesosim/MEVehicle.h>
      32              : #include <utils/options/OptionsCont.h>
      33              : #include <utils/iodevices/OutputDevice.h>
      34              : #include <utils/xml/SUMOSAXAttributes.h>
      35              : #include "MSDevice_Vehroutes.h"
      36              : #include "MSDevice_Tripinfo.h"
      37              : 
      38              : #define NOT_ARRIVED TIME2STEPS(-1)
      39              : #define STATE_EMPTY_ARRIVALLANE "NONE"
      40              : 
      41              : 
      42              : // ===========================================================================
      43              : // static members
      44              : // ===========================================================================
      45              : std::set<const MSDevice_Tripinfo*, ComparatorNumericalIdLess> MSDevice_Tripinfo::myPendingOutput;
      46              : 
      47              : int MSDevice_Tripinfo::myVehicleCount(0);
      48              : int MSDevice_Tripinfo::myUndepartedVehicleCount(0);
      49              : double MSDevice_Tripinfo::myTotalRouteLength(0);
      50              : double MSDevice_Tripinfo::myTotalSpeed(0);
      51              : SUMOTime MSDevice_Tripinfo::myTotalDuration(0);
      52              : SUMOTime MSDevice_Tripinfo::myTotalWaitingTime(0);
      53              : SUMOTime MSDevice_Tripinfo::myTotalTimeLoss(0);
      54              : SUMOTime MSDevice_Tripinfo::myTotalDepartDelay(0);
      55              : SUMOTime MSDevice_Tripinfo::myWaitingDepartDelay(-1);
      56              : 
      57              : int MSDevice_Tripinfo::myBikeCount(0);
      58              : double MSDevice_Tripinfo::myTotalBikeRouteLength(0);
      59              : double MSDevice_Tripinfo::myTotalBikeSpeed(0);
      60              : SUMOTime MSDevice_Tripinfo::myTotalBikeDuration(0);
      61              : SUMOTime MSDevice_Tripinfo::myTotalBikeWaitingTime(0);
      62              : SUMOTime MSDevice_Tripinfo::myTotalBikeTimeLoss(0);
      63              : SUMOTime MSDevice_Tripinfo::myTotalBikeDepartDelay(0);
      64              : 
      65              : int MSDevice_Tripinfo::myWalkCount(0);
      66              : double MSDevice_Tripinfo::myTotalWalkRouteLength(0);
      67              : SUMOTime MSDevice_Tripinfo::myTotalWalkDuration(0);
      68              : SUMOTime MSDevice_Tripinfo::myTotalWalkTimeLoss(0);
      69              : std::vector<int> MSDevice_Tripinfo::myRideCount({0, 0});
      70              : std::vector<int> MSDevice_Tripinfo::myRideBusCount({0, 0});
      71              : std::vector<int> MSDevice_Tripinfo::myRideRailCount({0, 0});
      72              : std::vector<int> MSDevice_Tripinfo::myRideTaxiCount({0, 0});
      73              : std::vector<int> MSDevice_Tripinfo::myRideBikeCount({0, 0});
      74              : std::vector<int> MSDevice_Tripinfo::myRideAbortCount({0, 0});
      75              : std::vector<SUMOTime> MSDevice_Tripinfo::myTotalRideWaitingTime({0, 0});
      76              : std::vector<double> MSDevice_Tripinfo::myTotalRideRouteLength({0., 0.});
      77              : std::vector<SUMOTime> MSDevice_Tripinfo::myTotalRideDuration({0, 0});
      78              : 
      79              : // ===========================================================================
      80              : // method definitions
      81              : // ===========================================================================
      82              : // ---------------------------------------------------------------------------
      83              : // static initialisation methods
      84              : // ---------------------------------------------------------------------------
      85              : void
      86        39784 : MSDevice_Tripinfo::insertOptions(OptionsCont& oc) {
      87        39784 :     oc.addOptionSubTopic("Tripinfo Device");
      88        79568 :     insertDefaultAssignmentOptions("tripinfo", "Tripinfo Device", oc);
      89        39784 : }
      90              : 
      91              : 
      92              : void
      93      5371080 : MSDevice_Tripinfo::buildVehicleDevices(SUMOVehicle& v, std::vector<MSVehicleDevice*>& into) {
      94      5371080 :     OptionsCont& oc = OptionsCont::getOptions();
      95     10480349 :     const bool enableByOutputOption = oc.isSet("tripinfo-output") || oc.getBool("duration-log.statistics");
      96     10742160 :     if (equippedByDefaultAssignmentOptions(oc, "tripinfo", v, enableByOutputOption)) {
      97      2123702 :         MSDevice_Tripinfo* device = new MSDevice_Tripinfo(v, "tripinfo_" + v.getID());
      98      2123702 :         into.push_back(device);
      99              :         myPendingOutput.insert(device);
     100              :     }
     101      5371080 : }
     102              : 
     103              : 
     104              : // ---------------------------------------------------------------------------
     105              : // MSDevice_Tripinfo-methods
     106              : // ---------------------------------------------------------------------------
     107      2123702 : MSDevice_Tripinfo::MSDevice_Tripinfo(SUMOVehicle& holder, const std::string& id) :
     108              :     MSVehicleDevice(holder, id),
     109            0 :     myDepartLane(""),
     110      2123702 :     myDepartSpeed(-1),
     111      2123702 :     myDepartPosLat(0),
     112      2123702 :     myWaitingTime(0),
     113      2123702 :     myAmWaiting(false),
     114      2123702 :     myWaitingCount(0),
     115      2123702 :     myStoppingTime(0),
     116      2123702 :     myParkingStarted(-1),
     117      2123702 :     myArrivalTime(NOT_ARRIVED),
     118      2123702 :     myArrivalLane(""),
     119      2123702 :     myArrivalPos(-1),
     120      2123702 :     myArrivalPosLat(0.),
     121      2123702 :     myArrivalSpeed(-1),
     122      2123702 :     myArrivalReason(MSMoveReminder::NOTIFICATION_ARRIVED),
     123      2123702 :     myMesoTimeLoss(0),
     124      2123702 :     myRouteLength(0.) {
     125      2123702 : }
     126              : 
     127              : 
     128      4247354 : MSDevice_Tripinfo::~MSDevice_Tripinfo() {
     129              :     // ensure clean up for vaporized vehicles which do not generate output
     130      2123677 :     myPendingOutput.erase(this);
     131      4247354 : }
     132              : 
     133              : void
     134        38670 : MSDevice_Tripinfo::cleanup() {
     135        38670 :     myVehicleCount = 0;
     136        38670 :     myTotalRouteLength = 0;
     137        38670 :     myTotalSpeed = 0;
     138        38670 :     myTotalDuration = 0;
     139        38670 :     myTotalWaitingTime = 0;
     140        38670 :     myTotalTimeLoss = 0;
     141        38670 :     myTotalDepartDelay = 0;
     142        38670 :     myWaitingDepartDelay = -1;
     143              : 
     144        38670 :     myBikeCount = 0;
     145        38670 :     myTotalBikeRouteLength = 0;
     146        38670 :     myTotalBikeSpeed = 0;
     147        38670 :     myTotalBikeDuration = 0;
     148        38670 :     myTotalBikeWaitingTime = 0;
     149        38670 :     myTotalBikeTimeLoss = 0;
     150        38670 :     myTotalBikeDepartDelay = 0;
     151              : 
     152        38670 :     myWalkCount = 0;
     153        38670 :     myTotalWalkRouteLength = 0;
     154        38670 :     myTotalWalkDuration = 0;
     155        38670 :     myTotalWalkTimeLoss = 0;
     156              : 
     157        38670 :     myRideCount = {0, 0};
     158        38670 :     myRideBusCount = {0, 0};
     159        38670 :     myRideRailCount = {0, 0};
     160        38670 :     myRideTaxiCount = {0, 0};
     161        38670 :     myRideBikeCount = {0, 0};
     162        38670 :     myRideAbortCount = {0, 0};
     163        38670 :     myTotalRideWaitingTime = {0, 0};
     164        38670 :     myTotalRideRouteLength = {0., 0.};
     165        38670 :     myTotalRideDuration = {0, 0};
     166        38670 : }
     167              : 
     168              : bool
     169         3518 : MSDevice_Tripinfo::notifyIdle(SUMOTrafficObject& veh) {
     170         3518 :     if (veh.isVehicle()) {
     171         3518 :         myWaitingTime += DELTA_T;
     172         3518 :         if (!myAmWaiting) {
     173          130 :             myWaitingCount++;
     174          130 :             myAmWaiting = true;
     175              :         }
     176              :     }
     177         3518 :     return true;
     178              : }
     179              : 
     180              : 
     181              : bool
     182    336642236 : MSDevice_Tripinfo::notifyMove(SUMOTrafficObject& veh, double /*oldPos*/,
     183              :                               double /*newPos*/, double newSpeed) {
     184    336642236 :     if (veh.isStopped()) {
     185      1931365 :         if (newSpeed <= SUMO_const_haltingSpeed) {
     186      1931181 :             myStoppingTime += DELTA_T;
     187              :         }
     188    334710871 :     } else if (newSpeed <= SUMO_const_haltingSpeed && lowAcceleration(veh)) {
     189     50316363 :         myWaitingTime += DELTA_T;
     190     50316363 :         if (!myAmWaiting) {
     191      2516933 :             myWaitingCount++;
     192      2516933 :             myAmWaiting = true;
     193              :         }
     194              :     } else {
     195    284394508 :         myAmWaiting = false;
     196              :     }
     197    336642236 :     return true;
     198              : }
     199              : 
     200              : 
     201              : bool
     202     50317220 : MSDevice_Tripinfo::lowAcceleration(const SUMOTrafficObject& veh) {
     203     50317220 :     if (MSGlobals::gUseMesoSim) {
     204              :         // acceleration is not modelled
     205              :         return false;
     206              :     } else {
     207     50317220 :         const MSVehicle& v = dynamic_cast<const MSVehicle&>(veh);
     208     50317220 :         return v.getAcceleration() <= v.accelThresholdForWaiting();
     209              :     }
     210              : }
     211              : 
     212              : 
     213              : void
     214     13247778 : MSDevice_Tripinfo::notifyMoveInternal(const SUMOTrafficObject& veh,
     215              :                                       const double /* frontOnLane */,
     216              :                                       const double timeOnLane,
     217              :                                       const double /* meanSpeedFrontOnLane */,
     218              :                                       const double meanSpeedVehicleOnLane,
     219              :                                       const double /* travelledDistanceFrontOnLane */,
     220              :                                       const double /* travelledDistanceVehicleOnLane */,
     221              :                                       const double /* meanLengthOnLane */) {
     222              : 
     223              :     // called by meso
     224     13247778 :     const double vmax = veh.getEdge()->getVehicleMaxSpeed(&veh);
     225     13247778 :     if (vmax > 0) {
     226     16141221 :         myMesoTimeLoss += TIME2STEPS(timeOnLane * (vmax - meanSpeedVehicleOnLane) / vmax);
     227              :     }
     228     13247778 :     myWaitingTime += veh.getWaitingTime();
     229     13247778 : }
     230              : 
     231              : 
     232              : void
     233      1594678 : MSDevice_Tripinfo::updateParkingStopTime() {
     234      1594678 :     if (myParkingStarted >= 0) {
     235         3843 :         myStoppingTime += (MSNet::getInstance()->getCurrentTimeStep() - myParkingStarted);
     236         3843 :         myParkingStarted = -1;
     237              :     }
     238      1594678 : }
     239              : 
     240              : bool
     241     27155168 : MSDevice_Tripinfo::notifyEnter(SUMOTrafficObject& veh, MSMoveReminder::Notification reason, const MSLane* /* enteredLane */) {
     242     27155168 :     if (reason == MSMoveReminder::NOTIFICATION_DEPARTED) {
     243      1624168 :         if (!MSGlobals::gUseMesoSim) {
     244      1262873 :             myDepartLane = static_cast<MSVehicle&>(veh).getLane()->getID();
     245      1262873 :             myDepartPosLat = static_cast<MSVehicle&>(veh).getLateralPositionOnLane();
     246              :         } else {
     247       361295 :             myDepartLane = veh.getEdge()->getFirstAllowed(veh.getVClass(), true)->getID();
     248              :         }
     249      1624168 :         myDepartSpeed = veh.getSpeed();
     250      1624168 :         myRouteLength = -veh.getPositionOnLane();
     251     25531000 :     } else if (reason == MSMoveReminder::NOTIFICATION_PARKING) {
     252              :         // notifyMove is not called while parking
     253              :         // @note insertion delay when resuming after parking is included
     254         3288 :         updateParkingStopTime();
     255              :     }
     256     27155168 :     return true;
     257              : }
     258              : 
     259              : 
     260              : bool
     261     27084689 : MSDevice_Tripinfo::notifyLeave(SUMOTrafficObject& veh, double /*lastPos*/,
     262              :                                MSMoveReminder::Notification reason, const MSLane* /* enteredLane */) {
     263     27084689 :     if (reason >= MSMoveReminder::NOTIFICATION_ARRIVED) {
     264      1557931 :         myArrivalTime = MSNet::getInstance()->getCurrentTimeStep();
     265      1557931 :         myArrivalReason = reason;
     266      1557931 :         if (!MSGlobals::gUseMesoSim) {
     267      1201867 :             myArrivalLane = static_cast<MSVehicle&>(veh).getLane()->getID();
     268      1201867 :             myArrivalPosLat = static_cast<MSVehicle&>(veh).getLateralPositionOnLane();
     269              :         } else {
     270       356064 :             myArrivalLane = veh.getEdge()->getFirstAllowed(veh.getVClass(), true)->getID();
     271              :         }
     272              :         // @note vehicle may have moved past its arrivalPos during the last step
     273              :         // due to non-zero arrivalspeed but we consider it as arrived at the desired position
     274              :         // However, vaporization may happen anywhere (via TraCI)
     275      1557931 :         if (reason > MSMoveReminder::NOTIFICATION_TELEPORT_ARRIVED) {
     276              :             // vaporized
     277          546 :             myArrivalPos = veh.getPositionOnLane();
     278              :         } else {
     279      1557385 :             myArrivalPos = myHolder.getArrivalPos();
     280              :         }
     281      1557931 :         myArrivalSpeed = veh.getSpeed();
     282      1557931 :         updateParkingStopTime();
     283     25526758 :     } else if (reason == MSMoveReminder::NOTIFICATION_PARKING) {
     284         3996 :         myParkingStarted = MSNet::getInstance()->getCurrentTimeStep();
     285     25522762 :     } else if (reason == NOTIFICATION_JUNCTION
     286     25522762 :                || reason == NOTIFICATION_TELEPORT
     287     12344779 :                || reason == NOTIFICATION_TELEPORT_CONTINUATION) {
     288     13183289 :         if (MSGlobals::gUseMesoSim) {
     289      1346644 :             myRouteLength += myHolder.getEdge()->getLength();
     290              :         } else {
     291     11836645 :             const MSLane* lane = static_cast<MSVehicle&>(veh).getLane();
     292     11836645 :             if (lane != nullptr) {
     293     11836621 :                 myRouteLength += lane->getLength();
     294              :             }
     295              :         }
     296              :     }
     297     27084689 :     return true;
     298              : }
     299              : 
     300              : 
     301              : void
     302      1591214 : MSDevice_Tripinfo::generateOutput(OutputDevice* tripinfoOut) const {
     303      1591214 :     const SUMOTime timeLoss = MSGlobals::gUseMesoSim ? myMesoTimeLoss : static_cast<MSVehicle&>(myHolder).getTimeLoss();
     304      1591214 :     const double routeLength = myRouteLength + (myArrivalTime == NOT_ARRIVED ? myHolder.getPositionOnLane() : myArrivalPos);
     305              :     SUMOTime duration = 0;
     306      1591214 :     if (myHolder.hasDeparted()) {
     307      1624223 :         duration = (myArrivalTime == NOT_ARRIVED ? SIMSTEP : myArrivalTime) - myHolder.getDeparture();
     308      1590970 :         if (myHolder.getVClass() == SVC_BICYCLE) {
     309        25127 :             myBikeCount++;
     310        25127 :             myTotalBikeRouteLength += routeLength;
     311        25127 :             myTotalBikeSpeed += routeLength / STEPS2TIME(duration);
     312        25127 :             myTotalBikeDuration += duration;
     313        25127 :             myTotalBikeWaitingTime += myWaitingTime;
     314        25127 :             myTotalBikeTimeLoss += timeLoss;
     315        25127 :             myTotalBikeDepartDelay += myHolder.getDepartDelay();
     316              :         } else {
     317      1565843 :             myVehicleCount++;
     318      1565843 :             myTotalRouteLength += routeLength;
     319      1565843 :             myTotalSpeed += routeLength / STEPS2TIME(duration);
     320      1565843 :             myTotalDuration += duration;
     321      1565843 :             myTotalWaitingTime += myWaitingTime;
     322      1565843 :             myTotalTimeLoss += timeLoss;
     323      1565843 :             myTotalDepartDelay += myHolder.getDepartDelay();
     324              :         }
     325              :     }
     326              : 
     327      1591214 :     myPendingOutput.erase(this);
     328      1591214 :     if (tripinfoOut == nullptr) {
     329      1356592 :         return;
     330              :     }
     331              :     // write
     332              :     OutputDevice& os = *tripinfoOut;
     333       469244 :     os.openTag("tripinfo").writeAttr("id", myHolder.getID());
     334       469244 :     os.writeAttr("depart", myHolder.hasDeparted() ? time2string(myHolder.getDeparture()) : "-1");
     335       234622 :     os.writeAttr("departLane", myDepartLane);
     336       234622 :     os.writeAttr("departPos", myHolder.getDepartPos());
     337       234622 :     if (MSGlobals::gLateralResolution > 0) {
     338        49992 :         os.writeAttr("departPosLat", myDepartPosLat);
     339              :     }
     340       234622 :     os.writeAttr("departSpeed", myDepartSpeed);
     341       234622 :     SUMOTime departDelay = myHolder.getDepartDelay();
     342       234622 :     const SUMOVehicleParameter& param = myHolder.getParameter();
     343       234622 :     if (!myHolder.hasDeparted()) {
     344              :         assert(param.depart <= SIMSTEP || param.departProcedure != DepartDefinition::GIVEN);
     345          244 :         departDelay = SIMSTEP - param.depart;
     346              :     }
     347       469244 :     os.writeAttr("departDelay", time2string(departDelay));
     348       469244 :     os.writeAttr("arrival", time2string(myArrivalTime));
     349       234622 :     os.writeAttr("arrivalLane", myArrivalLane);
     350       234622 :     os.writeAttr("arrivalPos", myArrivalPos);
     351       234622 :     if (MSGlobals::gLateralResolution > 0) {
     352        49992 :         os.writeAttr("arrivalPosLat", myArrivalPosLat);
     353              :     }
     354       234622 :     os.writeAttr("arrivalSpeed", myArrivalSpeed);
     355       469244 :     os.writeAttr("duration", time2string(duration));
     356       234622 :     os.writeAttr("routeLength", routeLength);
     357       234622 :     os.writeAttr(SUMO_ATTR_WAITINGTIME, time2string(myWaitingTime));
     358       234622 :     os.writeAttr(SUMO_ATTR_WAITINGCOUNT, myWaitingCount);
     359       234622 :     os.writeAttr(SUMO_ATTR_STOPTIME, time2string(myStoppingTime));
     360       234622 :     os.writeAttr(SUMO_ATTR_TIMELOSS, time2string(timeLoss));
     361       234622 :     os.writeAttr("rerouteNo", myHolder.getNumberReroutes());
     362       703866 :     os.writeAttr("devices", toString(myHolder.getDevices()));
     363       234622 :     os.writeAttr("vType", myHolder.getVehicleType().getID());
     364       469244 :     os.writeAttr("speedFactor", myHolder.getChosenSpeedFactor());
     365              :     std::string vaporized;
     366       234622 :     switch (myArrivalReason) {
     367              :         case MSMoveReminder::NOTIFICATION_VAPORIZED_CALIBRATOR:
     368              :             vaporized = "calibrator";
     369              :             break;
     370              :         case MSMoveReminder::NOTIFICATION_VAPORIZED_GUI:
     371              :             vaporized = "gui";
     372              :             break;
     373              :         case MSMoveReminder::NOTIFICATION_VAPORIZED_COLLISION:
     374              :             vaporized = "collision";
     375              :             break;
     376              :         case MSMoveReminder::NOTIFICATION_VAPORIZED_VAPORIZER:
     377              :             vaporized = "vaporizer";
     378              :             break;
     379              :         case MSMoveReminder::NOTIFICATION_VAPORIZED_TRACI:
     380              :             vaporized = "traci";
     381              :             break;
     382              :         case MSMoveReminder::NOTIFICATION_TELEPORT_ARRIVED:
     383              :             vaporized = "teleport";
     384              :             break;
     385       234239 :         default:
     386       234239 :             if (myHolder.getEdge() == myHolder.getRoute().getLastEdge() ||
     387         1499 :                     (param.arrivalEdge >= 0 && myHolder.getRoutePosition() >= param.arrivalEdge)) {
     388              :                 vaporized = "";
     389              :             } else {
     390              :                 vaporized = "end";
     391              :             }
     392              :             break;
     393              :     }
     394       469244 :     os.writeAttr("vaporized", vaporized);
     395              :     // cannot close tag because emission device output might follow
     396              : }
     397              : 
     398              : 
     399              : void
     400          911 : MSDevice_Tripinfo::generateOutputForUnfinished() {
     401          911 :     MSNet* net = MSNet::getInstance();
     402          911 :     OutputDevice* tripinfoOut = (OptionsCont::getOptions().isSet("tripinfo-output") ?
     403         1567 :                                  &OutputDevice::getDeviceByOption("tripinfo-output") : nullptr);
     404          911 :     myWaitingDepartDelay = 0;
     405          911 :     myUndepartedVehicleCount = 0;
     406         1822 :     const bool writeUndeparted = OptionsCont::getOptions().getBool("tripinfo-output.write-undeparted");
     407              :     const SUMOTime t = net->getCurrentTimeStep();
     408        66089 :     while (myPendingOutput.size() > 0) {
     409        65178 :         const MSDevice_Tripinfo* d = *myPendingOutput.begin();
     410        65178 :         const bool departed = d->myHolder.hasDeparted();
     411        65178 :         const bool departDelayed = d->myHolder.getParameter().depart <= t;
     412        65178 :         if (!departed && departDelayed) {
     413        31951 :             myUndepartedVehicleCount++;
     414        31951 :             myWaitingDepartDelay += (t - d->myHolder.getParameter().depart);
     415              :         }
     416        65178 :         if (departed || (writeUndeparted && departDelayed)) {
     417        33459 :             const_cast<MSDevice_Tripinfo*>(d)->updateParkingStopTime();
     418        33459 :             d->generateOutput(tripinfoOut);
     419        33459 :             if (tripinfoOut != nullptr) {
     420         6568 :                 for (MSVehicleDevice* const dev : d->myHolder.getDevices()) {
     421         4599 :                     if (typeid(*dev) == typeid(MSDevice_Tripinfo) || typeid(*dev) == typeid(MSDevice_Vehroutes)) {
     422              :                         // tripinfo is special and vehroute has its own write-unfinished option
     423         2423 :                         continue;
     424              :                     }
     425         2176 :                     dev->generateOutput(tripinfoOut);
     426              :                 }
     427         3938 :                 OutputDevice::getDeviceByOption("tripinfo-output").closeTag();
     428              :             }
     429              :         } else {
     430              :             myPendingOutput.erase(d);
     431              :         }
     432              :     }
     433              :     // unfinished persons
     434          911 :     if (net->hasPersons()) {
     435          551 :         MSTransportableControl& pc = net->getPersonControl();
     436          767 :         while (pc.loadedBegin() != pc.loadedEnd()) {
     437          216 :             pc.erase(pc.loadedBegin()->second);
     438              :         }
     439              :     }
     440              : 
     441          911 : }
     442              : 
     443              : 
     444              : void
     445        55168 : MSDevice_Tripinfo::addPedestrianData(double walkLength, SUMOTime walkDuration, SUMOTime walkTimeLoss) {
     446        55168 :     myWalkCount++;
     447        55168 :     myTotalWalkRouteLength += walkLength;
     448        55168 :     myTotalWalkDuration += walkDuration;
     449        55168 :     myTotalWalkTimeLoss += walkTimeLoss;
     450        55168 : }
     451              : 
     452              : 
     453              : void
     454         6928 : MSDevice_Tripinfo::addRideTransportData(const bool isPerson, const double distance, const SUMOTime duration,
     455              :                                         const SUMOVehicleClass vClass, const std::string& line, const SUMOTime waitingTime) {
     456         6928 :     const int index = isPerson ? 0 : 1;
     457         6928 :     myRideCount[index]++;
     458         6928 :     if (duration > 0) {
     459         6663 :         myTotalRideWaitingTime[index] += waitingTime;
     460         6663 :         myTotalRideRouteLength[index] += distance;
     461         6663 :         myTotalRideDuration[index] += duration;
     462         6663 :         if (vClass == SVC_BICYCLE) {
     463           13 :             myRideBikeCount[index]++;
     464         6650 :         } else if (!line.empty()) {
     465         5441 :             if (isRailway(vClass)) {
     466          817 :                 myRideRailCount[index]++;
     467         4624 :             } else if (vClass == SVC_TAXI) {
     468         1444 :                 myRideTaxiCount[index]++;
     469              :             } else {
     470              :                 // some kind of road vehicle
     471         3180 :                 myRideBusCount[index]++;
     472              :             }
     473              :         }
     474              :     } else {
     475          265 :         myRideAbortCount[index]++;
     476              :     }
     477         6928 : }
     478              : 
     479              : 
     480              : std::string
     481         2911 : MSDevice_Tripinfo::printStatistics() {
     482         2911 :     std::ostringstream msg;
     483              :     msg.setf(msg.fixed);
     484         2911 :     msg.precision(gPrecision);
     485         2911 :     if (myBikeCount == 0 || myVehicleCount > 0) {
     486         2845 :         msg << "Statistics (avg of " << myVehicleCount << "):\n";
     487         2845 :         msg << " RouteLength: " << getAvgRouteLength() << "\n"
     488         2845 :             << " Speed: " << getAvgTripSpeed() << "\n"
     489         2845 :             << " Duration: " << getAvgDuration() << "\n"
     490         2845 :             << " WaitingTime: " << getAvgWaitingTime() << "\n"
     491         2845 :             << " TimeLoss: " << getAvgTimeLoss() << "\n"
     492         5690 :             << " DepartDelay: " << getAvgDepartDelay() << "\n";
     493              :     }
     494         2911 :     if (myBikeCount > 0) {
     495              :         msg << "Bike Statistics (avg of " << myBikeCount << "):\n"
     496          302 :             << " RouteLength: " << getAvgBikeRouteLength() << "\n"
     497          151 :             << " Speed: " << getAvgBikeTripSpeed() << "\n"
     498          151 :             << " Duration: " << getAvgBikeDuration() << "\n"
     499          151 :             << " WaitingTime: " << getAvgBikeWaitingTime() << "\n"
     500          151 :             << " TimeLoss: " << getAvgBikeTimeLoss() << "\n"
     501          302 :             << " DepartDelay: " << getAvgBikeDepartDelay() << "\n";
     502          151 :         if (myVehicleCount > 0 && myWaitingDepartDelay >= 0) {
     503           19 :             msg << "Statistics (avg of " << (myVehicleCount + myBikeCount) << "):\n";
     504              :         }
     505              :     }
     506         2911 :     if (myWaitingDepartDelay >= 0) {
     507          686 :         msg << " DepartDelayWaiting: " << getAvgDepartDelayWaiting() << "\n";
     508              :     }
     509         2911 :     if (myWalkCount > 0) {
     510              :         msg << "Pedestrian Statistics (avg of " << myWalkCount << " walks):\n"
     511          566 :             << " RouteLength: " << getAvgWalkRouteLength() << "\n"
     512          283 :             << " Duration: " << getAvgWalkDuration() << "\n"
     513          566 :             << " TimeLoss: " << getAvgWalkTimeLoss() << "\n";
     514              :     }
     515         5822 :     printRideStatistics(msg, "Ride", "rides", 0);
     516         5822 :     printRideStatistics(msg, "Transport", "transports", 1);
     517         2911 :     return msg.str();
     518         2911 : }
     519              : 
     520              : void
     521         5822 : MSDevice_Tripinfo::printRideStatistics(std::ostringstream& msg, const std::string& category, const std::string& modeName, const int index) {
     522         5822 :     if (myRideCount[index] > 0) {
     523          336 :         msg << category << " Statistics (avg of " << myRideCount[index] << " " << modeName << "):\n";
     524          112 :         msg << " WaitingTime: " << STEPS2TIME(myTotalRideWaitingTime[index] / myRideCount[index]) << "\n";
     525          112 :         msg << " RouteLength: " << myTotalRideRouteLength[index] / myRideCount[index] << "\n";
     526          112 :         msg << " Duration: " << STEPS2TIME(myTotalRideDuration[index] / myRideCount[index]) << "\n";
     527          112 :         if (myRideBusCount[index] > 0) {
     528           15 :             msg << " Bus: " << myRideBusCount[index] << "\n";
     529              :         }
     530          112 :         if (myRideRailCount[index] > 0) {
     531            9 :             msg << " Train: " << myRideRailCount[index] << "\n";
     532              :         }
     533          112 :         if (myRideTaxiCount[index] > 0) {
     534           66 :             msg << " Taxi: " << myRideTaxiCount[index] << "\n";
     535              :         }
     536          112 :         if (myRideBikeCount[index] > 0) {
     537           13 :             msg << " Bike: " << myRideBikeCount[index] << "\n";
     538              :         }
     539          112 :         if (myRideAbortCount[index] > 0) {
     540           11 :             msg << " Aborted: " << myRideAbortCount[index] << "\n";
     541              :         }
     542              :     }
     543              : 
     544         5822 : }
     545              : 
     546              : 
     547              : void
     548          264 : MSDevice_Tripinfo::writeStatistics(OutputDevice& od) {
     549          264 :     od.setPrecision(gPrecision);
     550          264 :     od.openTag("vehicleTripStatistics");
     551          264 :     od.writeAttr("count", myVehicleCount);
     552          264 :     od.writeAttr("routeLength", getAvgRouteLength());
     553          264 :     od.writeAttr("speed", getAvgTripSpeed());
     554          264 :     od.writeAttr("duration", getAvgDuration());
     555          264 :     od.writeAttr("waitingTime", getAvgWaitingTime());
     556          264 :     od.writeAttr("timeLoss", getAvgTimeLoss());
     557          264 :     od.writeAttr("departDelay", getAvgDepartDelay());
     558          264 :     od.writeAttr("departDelayWaiting", getAvgDepartDelayWaiting());
     559          528 :     od.writeAttr("totalTravelTime", time2string(myTotalDuration));
     560          528 :     od.writeAttr("totalDepartDelay", time2string(TIME2STEPS(getTotalDepartDelay() + getTotalBikeDepartDelay())));
     561          264 :     od.closeTag();
     562          264 :     if (myBikeCount > 0) {
     563            6 :         od.openTag("bikeTripStatistics");
     564            6 :         od.writeAttr("count", myBikeCount);
     565            6 :         od.writeAttr("routeLength", getAvgBikeRouteLength());
     566            6 :         od.writeAttr("speed", getAvgBikeTripSpeed());
     567            6 :         od.writeAttr("duration", getAvgBikeDuration());
     568            6 :         od.writeAttr("waitingTime", getAvgBikeWaitingTime());
     569            6 :         od.writeAttr("timeLoss", getAvgBikeTimeLoss());
     570            6 :         od.writeAttr("departDelay", getAvgBikeDepartDelay());
     571           12 :         od.writeAttr("totalTravelTime", time2string(myTotalBikeDuration));
     572           12 :         od.closeTag();
     573              :     }
     574          264 :     od.openTag("pedestrianStatistics");
     575          264 :     od.writeAttr("number", myWalkCount);
     576          264 :     od.writeAttr("routeLength", getAvgWalkRouteLength());
     577          264 :     od.writeAttr("duration", getAvgWalkDuration());
     578          264 :     od.writeAttr("timeLoss", getAvgWalkTimeLoss());
     579          264 :     od.closeTag();
     580          264 :     writeRideStatistics(od, "rideStatistics", 0);
     581          264 :     writeRideStatistics(od, "transportStatistics", 1);
     582          264 : }
     583              : 
     584              : void
     585          528 : MSDevice_Tripinfo::writeRideStatistics(OutputDevice& od, const std::string& category, const int index) {
     586          528 :     od.openTag(category);
     587         1056 :     od.writeAttr("number", myRideCount[index]);
     588          528 :     if (myRideCount[index] > 0) {
     589            4 :         od.writeAttr("waitingTime", STEPS2TIME(myTotalRideWaitingTime[index] / myRideCount[index]));
     590            4 :         od.writeAttr("routeLength", myTotalRideRouteLength[index] / myRideCount[index]);
     591            4 :         od.writeAttr("duration", STEPS2TIME(myTotalRideDuration[index] / myRideCount[index]));
     592            4 :         od.writeAttr("bus", myRideBusCount[index]);
     593            4 :         od.writeAttr("train", myRideRailCount[index]);
     594            4 :         od.writeAttr("taxi", myRideTaxiCount[index]);
     595            4 :         od.writeAttr("bike", myRideBikeCount[index]);
     596            4 :         od.writeAttr("aborted", myRideAbortCount[index]);
     597              :     }
     598          528 :     od.closeTag();
     599          528 : }
     600              : 
     601              : 
     602              : double
     603         3233 : MSDevice_Tripinfo::getAvgRouteLength() {
     604         3233 :     if (myVehicleCount > 0) {
     605         3003 :         return myTotalRouteLength / myVehicleCount;
     606              :     } else {
     607              :         return 0;
     608              :     }
     609              : }
     610              : 
     611              : double
     612         3233 : MSDevice_Tripinfo::getAvgTripSpeed() {
     613         3233 :     if (myVehicleCount > 0) {
     614         3003 :         return myTotalSpeed / myVehicleCount;
     615              :     } else {
     616              :         return 0;
     617              :     }
     618              : }
     619              : 
     620              : double
     621         3233 : MSDevice_Tripinfo::getAvgDuration() {
     622         3233 :     if (myVehicleCount > 0) {
     623         3003 :         return STEPS2TIME(myTotalDuration / myVehicleCount);
     624              :     } else {
     625              :         return 0;
     626              :     }
     627              : }
     628              : 
     629              : double
     630         3233 : MSDevice_Tripinfo::getAvgWaitingTime() {
     631         3233 :     if (myVehicleCount > 0) {
     632         3003 :         return STEPS2TIME(myTotalWaitingTime / myVehicleCount);
     633              :     } else {
     634              :         return 0;
     635              :     }
     636              : }
     637              : 
     638              : 
     639              : double
     640         3233 : MSDevice_Tripinfo::getAvgTimeLoss() {
     641         3233 :     if (myVehicleCount > 0) {
     642         3003 :         return STEPS2TIME(myTotalTimeLoss / myVehicleCount);
     643              :     } else {
     644              :         return 0;
     645              :     }
     646              : }
     647              : 
     648              : 
     649              : double
     650         3233 : MSDevice_Tripinfo::getAvgDepartDelay() {
     651         3233 :     if (myVehicleCount > 0) {
     652         3003 :         return STEPS2TIME(myTotalDepartDelay / myVehicleCount);
     653              :     } else {
     654              :         return 0;
     655              :     }
     656              : }
     657              : 
     658              : double
     659          731 : MSDevice_Tripinfo::getAvgDepartDelayWaiting() {
     660          731 :     if (myWaitingDepartDelay >= 0) {
     661          355 :         return STEPS2TIME(myWaitingDepartDelay / MAX2(1, myUndepartedVehicleCount));
     662              :     } else {
     663              :         return -1;
     664              :     }
     665              : }
     666              : 
     667              : 
     668              : double
     669          652 : MSDevice_Tripinfo::getTotalDepartDelay() {
     670          652 :     return STEPS2TIME(myTotalDepartDelay + MAX2((SUMOTime)0, myWaitingDepartDelay));
     671              : }
     672              : 
     673              : double
     674          219 : MSDevice_Tripinfo::getAvgBikeRouteLength() {
     675          219 :     if (myBikeCount > 0) {
     676          157 :         return myTotalBikeRouteLength / myBikeCount;
     677              :     } else {
     678              :         return 0;
     679              :     }
     680              : }
     681              : 
     682              : double
     683          219 : MSDevice_Tripinfo::getAvgBikeTripSpeed() {
     684          219 :     if (myBikeCount > 0) {
     685          157 :         return myTotalBikeSpeed / myBikeCount;
     686              :     } else {
     687              :         return 0;
     688              :     }
     689              : }
     690              : 
     691              : double
     692          219 : MSDevice_Tripinfo::getAvgBikeDuration() {
     693          219 :     if (myBikeCount > 0) {
     694          157 :         return STEPS2TIME(myTotalBikeDuration / myBikeCount);
     695              :     } else {
     696              :         return 0;
     697              :     }
     698              : }
     699              : 
     700              : double
     701          219 : MSDevice_Tripinfo::getAvgBikeWaitingTime() {
     702          219 :     if (myBikeCount > 0) {
     703          157 :         return STEPS2TIME(myTotalBikeWaitingTime / myBikeCount);
     704              :     } else {
     705              :         return 0;
     706              :     }
     707              : }
     708              : 
     709              : 
     710              : double
     711          219 : MSDevice_Tripinfo::getAvgBikeTimeLoss() {
     712          219 :     if (myBikeCount > 0) {
     713          157 :         return STEPS2TIME(myTotalBikeTimeLoss / myBikeCount);
     714              :     } else {
     715              :         return 0;
     716              :     }
     717              : }
     718              : 
     719              : double
     720          157 : MSDevice_Tripinfo::getAvgBikeDepartDelay() {
     721          157 :     if (myBikeCount > 0) {
     722          157 :         return STEPS2TIME(myTotalBikeDepartDelay / myBikeCount);
     723              :     } else {
     724              :         return 0;
     725              :     }
     726              : }
     727              : 
     728              : 
     729              : double
     730          528 : MSDevice_Tripinfo::getTotalBikeDepartDelay() {
     731          528 :     return STEPS2TIME(myTotalBikeDepartDelay);
     732              : }
     733              : 
     734              : double
     735          609 : MSDevice_Tripinfo::getAvgWalkRouteLength() {
     736          609 :     if (myWalkCount > 0) {
     737          289 :         return myTotalWalkRouteLength / myWalkCount;
     738              :     } else {
     739              :         return 0;
     740              :     }
     741              : }
     742              : 
     743              : double
     744          609 : MSDevice_Tripinfo::getAvgWalkDuration() {
     745          609 :     if (myWalkCount > 0) {
     746          289 :         return STEPS2TIME(myTotalWalkDuration / myWalkCount);
     747              :     } else {
     748              :         return 0;
     749              :     }
     750              : }
     751              : 
     752              : 
     753              : double
     754          609 : MSDevice_Tripinfo::getAvgWalkTimeLoss() {
     755          609 :     if (myWalkCount > 0) {
     756          289 :         return STEPS2TIME(myTotalWalkTimeLoss / myWalkCount);
     757              :     } else {
     758              :         return 0;
     759              :     }
     760              : }
     761              : 
     762              : 
     763              : double
     764            0 : MSDevice_Tripinfo::getAvgRideDuration() {
     765            0 :     if (myRideCount[0] > 0) {
     766            0 :         return STEPS2TIME(myTotalRideDuration[0] / myRideCount[0]);
     767              :     } else {
     768              :         return 0;
     769              :     }
     770              : }
     771              : 
     772              : double
     773            0 : MSDevice_Tripinfo::getAvgRideWaitingTime() {
     774            0 :     if (myRideCount[0] > 0) {
     775            0 :         return STEPS2TIME(myTotalRideWaitingTime[0] / myRideCount[0]);
     776              :     } else {
     777              :         return 0;
     778              :     }
     779              : }
     780              : 
     781              : double
     782            0 : MSDevice_Tripinfo::getAvgRideRouteLength() {
     783            0 :     if (myRideCount[0] > 0) {
     784            0 :         return myTotalRideRouteLength[0] / myRideCount[0];
     785              :     } else {
     786              :         return 0;
     787              :     }
     788              : }
     789              : 
     790              : 
     791              : std::string
     792          266 : MSDevice_Tripinfo::getParameter(const std::string& key) const {
     793          266 :     if (key == toString(SUMO_ATTR_WAITINGTIME)) {
     794           52 :         return toString(STEPS2TIME(myWaitingTime));
     795          214 :     } else if (key == toString(SUMO_ATTR_WAITINGCOUNT)) {
     796           52 :         return toString(myWaitingCount);
     797          162 :     } else if (key == toString(SUMO_ATTR_STOPTIME)) {
     798           52 :         return toString(STEPS2TIME(myStoppingTime));
     799          110 :     } else if (key == toString(SUMO_ATTR_ARRIVALTIME)) {
     800           22 :         return toString(STEPS2TIME(myArrivalTime));
     801           88 :     } else if (key == toString(SUMO_ATTR_ARRIVALLANE)) {
     802           22 :         return toString(myArrivalLane);
     803           66 :     } else if (key == toString(SUMO_ATTR_ARRIVALPOS)) {
     804           22 :         return toString(myArrivalPos);
     805           44 :     } else if (key == toString(SUMO_ATTR_ARRIVALPOS_LAT)) {
     806           22 :         return toString(myArrivalPosLat);
     807           22 :     } else if (key == toString(SUMO_ATTR_ARRIVALSPEED)) {
     808           22 :         return toString(myArrivalSpeed);
     809              :     }
     810            0 :     throw InvalidArgument("Parameter '" + key + "' is not supported for device of type '" + deviceName() + "'");
     811              : }
     812              : 
     813              : 
     814              : std::string
     815         3224 : MSDevice_Tripinfo::getGlobalParameter(const std::string& prefixedKey) {
     816              :     std::string key = prefixedKey; // by default, assume vehicleTripStatistics;
     817         3224 :     const std::string err = "Parameter '" + prefixedKey + "' is not supported for device of type 'tripinfo'";
     818         6448 :     if (StringUtils::startsWith(key, "vehicleTripStatistics.")) {
     819         1240 :         key = prefixedKey.substr(22);
     820         5208 :     } else if (StringUtils::startsWith(key, "bikeTripStatistics.")) {
     821          434 :         key = prefixedKey.substr(19);
     822          434 :         if (key == toString(SUMO_ATTR_COUNT)) {
     823           62 :             return toString(myBikeCount);
     824          372 :         } else if (key == "routeLength") {
     825           62 :             return toString(getAvgBikeRouteLength());
     826          310 :         } else if (key == toString(SUMO_ATTR_SPEED)) {
     827           62 :             return toString(getAvgBikeTripSpeed());
     828          248 :         } else if (key == toString(SUMO_ATTR_DURATION)) {
     829           62 :             return toString(getAvgBikeDuration());
     830          186 :         } else if (key == toString(SUMO_ATTR_WAITINGTIME)) {
     831           62 :             return toString(getAvgBikeWaitingTime());
     832          124 :         } else if (key == toString(SUMO_ATTR_TIMELOSS)) {
     833           62 :             return toString(getAvgBikeTimeLoss());
     834           62 :         } else if (key == "departDelay") {
     835            0 :             return toString(getAvgBikeDepartDelay());
     836           62 :         } else if (key == "totalTravelTime") {
     837              :             // avoid human readable output
     838           62 :             return toString(STEPS2TIME((myTotalBikeDuration)));
     839              :         }
     840            0 :         throw InvalidArgument(err);
     841              : 
     842         4340 :     } else if (StringUtils::startsWith(key, "pedestrianStatistics.")) {
     843          310 :         key = prefixedKey.substr(21);
     844          558 :         if (key == toString(SUMO_ATTR_NUMBER) || key == toString(SUMO_ATTR_COUNT)) {
     845          124 :             return toString(myWalkCount);
     846          186 :         } else if (key == "routeLength") {
     847           62 :             return toString(getAvgWalkRouteLength());
     848          124 :         } else if (key == toString(SUMO_ATTR_DURATION)) {
     849           62 :             return toString(getAvgWalkDuration());
     850           62 :         } else if (key == toString(SUMO_ATTR_TIMELOSS)) {
     851           62 :             return toString(getAvgWalkTimeLoss());
     852              :         }
     853            0 :         throw InvalidArgument(err);
     854              : 
     855         3720 :     } else if (StringUtils::startsWith(key, "rideStatistics.") ||
     856         3100 :                StringUtils::startsWith(key, "transportStatistics.")) {
     857              :         int index = 0;
     858         2480 :         if (StringUtils::startsWith(key, "rideStatistics.")) {
     859         1240 :             key = prefixedKey.substr(15);
     860              :         } else {
     861              :             index = 1;
     862         1240 :             key = prefixedKey.substr(20);
     863              :         }
     864         2356 :         if (key == toString(SUMO_ATTR_NUMBER) || key == toString(SUMO_ATTR_COUNT)) {
     865          248 :             return toString(myRideCount[index]);
     866          992 :         } else if (key == toString(SUMO_ATTR_WAITINGTIME)) {
     867          124 :             return toString(STEPS2TIME(myTotalRideWaitingTime[index] / MAX2(1, myRideCount[index])));
     868          868 :         } else if (key == "routeLength") {
     869          124 :             return toString(myTotalRideRouteLength[index] / MAX2(1, myRideCount[index]));
     870          744 :         } else if (key == toString(SUMO_ATTR_DURATION)) {
     871          124 :             return toString(myTotalRideRouteLength[index] / MAX2(1, myRideCount[index]));
     872          620 :         } else if (key == "bus") {
     873          124 :             return toString(myRideBusCount[index]);
     874          496 :         } else if (key == "train") {
     875          124 :             return toString(myRideRailCount[index]);
     876          372 :         } else if (key == "taxi") {
     877          124 :             return toString(myRideTaxiCount[index]);
     878          248 :         } else if (key == "bike") {
     879          124 :             return toString(myRideBikeCount[index]);
     880          124 :         } else if (key == "aborted") {
     881          124 :             return toString(myRideAbortCount[index]);
     882              :         }
     883            0 :         throw InvalidArgument(err);
     884              :     }
     885              :     // vehicleTripStatistics
     886         1240 :     if (key == toString(SUMO_ATTR_COUNT)) {
     887          124 :         return toString(myVehicleCount);
     888         1116 :     } else if (key == "routeLength") {
     889          124 :         return toString(getAvgRouteLength());
     890          992 :     } else if (key == toString(SUMO_ATTR_SPEED)) {
     891          124 :         return toString(getAvgTripSpeed());
     892          868 :     } else if (key == toString(SUMO_ATTR_DURATION)) {
     893          124 :         return toString(getAvgDuration());
     894          744 :     } else if (key == toString(SUMO_ATTR_WAITINGTIME)) {
     895          124 :         return toString(getAvgWaitingTime());
     896          620 :     } else if (key == toString(SUMO_ATTR_TIMELOSS)) {
     897          124 :         return toString(getAvgTimeLoss());
     898          496 :     } else if (key == "departDelay") {
     899          124 :         return toString(getAvgDepartDelay());
     900          372 :     } else if (key == "departDelayWaiting") {
     901          124 :         return toString(getAvgDepartDelayWaiting());
     902          248 :     } else if (key == "totalTravelTime") {
     903              :         // avoid human readable output
     904          124 :         return toString(STEPS2TIME((myTotalDuration)));
     905          124 :     } else if (key == "totalDepartDelay") {
     906          124 :         return toString(getTotalDepartDelay());
     907              :     }
     908            0 :     throw InvalidArgument(err);
     909              : }
     910              : 
     911              : 
     912              : void
     913          198 : MSDevice_Tripinfo::saveState(OutputDevice& out) const {
     914              :     // always write device id to replicate stochastic assignment
     915          198 :     out.openTag(SUMO_TAG_DEVICE);
     916          198 :     out.writeAttr(SUMO_ATTR_ID, getID());
     917          198 :     if (myHolder.hasDeparted()) {
     918          123 :         std::ostringstream internals;
     919          123 :         internals << myDepartLane << " ";
     920          123 :         if (!MSGlobals::gUseMesoSim) {
     921           78 :             internals << myDepartPosLat << " ";
     922              :         }
     923          123 :         std::string state_arrivalLane = myArrivalLane == "" ? STATE_EMPTY_ARRIVALLANE : myArrivalLane;
     924          615 :         internals << myDepartSpeed << " " << myRouteLength << " " << myWaitingTime << " " << myAmWaiting << " " << myWaitingCount << " ";
     925          246 :         internals << myStoppingTime << " " << myParkingStarted << " ";
     926          492 :         internals << myArrivalTime << " " << state_arrivalLane << " " << myArrivalPos << " " << myArrivalPosLat << " " << myArrivalSpeed;
     927          246 :         out.writeAttr(SUMO_ATTR_STATE, internals.str());
     928          123 :     }
     929          198 :     out.closeTag();
     930          198 : }
     931              : 
     932              : 
     933              : void
     934          148 : MSDevice_Tripinfo::loadState(const SUMOSAXAttributes& attrs) {
     935          148 :     if (attrs.hasAttribute(SUMO_ATTR_STATE)) {
     936          103 :         std::istringstream bis(attrs.getString(SUMO_ATTR_STATE));
     937          103 :         bis >> myDepartLane;
     938          103 :         if (!MSGlobals::gUseMesoSim) {
     939           69 :             bis >> myDepartPosLat;
     940              :         }
     941          103 :         bis >> myDepartSpeed >> myRouteLength >> myWaitingTime >> myAmWaiting >> myWaitingCount;
     942          103 :         bis >> myStoppingTime >> myParkingStarted;
     943          103 :         bis >> myArrivalTime >> myArrivalLane >> myArrivalPos >> myArrivalPosLat >> myArrivalSpeed;
     944          103 :         if (myArrivalLane == STATE_EMPTY_ARRIVALLANE) {
     945              :             myArrivalLane = "";
     946              :         }
     947          103 :     }
     948          148 : }
     949              : 
     950              : 
     951              : /****************************************************************************/
        

Generated by: LCOV version 2.0-1