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 % 516 500
Test Date: 2026-03-02 16:00:03 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-2026 German Aerospace Center (DLR) and others.
       4              : // This program and the accompanying materials are made available under the
       5              : // terms of the Eclipse Public License 2.0 which is available at
       6              : // https://www.eclipse.org/legal/epl-2.0/
       7              : // This Source Code may also be made available under the following Secondary
       8              : // Licenses when the conditions for such availability set forth in the Eclipse
       9              : // Public License 2.0 are satisfied: GNU General Public License, version 2
      10              : // or later which is available at
      11              : // https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html
      12              : // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
      13              : /****************************************************************************/
      14              : /// @file    MSDevice_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        42243 : MSDevice_Tripinfo::insertOptions(OptionsCont& oc) {
      87        42243 :     oc.addOptionSubTopic("Tripinfo Device");
      88        84486 :     insertDefaultAssignmentOptions("tripinfo", "Tripinfo Device", oc);
      89        42243 : }
      90              : 
      91              : 
      92              : void
      93      5537930 : MSDevice_Tripinfo::buildVehicleDevices(SUMOVehicle& v, std::vector<MSVehicleDevice*>& into) {
      94      5537930 :     OptionsCont& oc = OptionsCont::getOptions();
      95     10809086 :     const bool enableByOutputOption = oc.isSet("tripinfo-output") || oc.getBool("duration-log.statistics");
      96     11075860 :     if (equippedByDefaultAssignmentOptions(oc, "tripinfo", v, enableByOutputOption)) {
      97      2299703 :         MSDevice_Tripinfo* device = new MSDevice_Tripinfo(v, "tripinfo_" + v.getID());
      98      2299703 :         into.push_back(device);
      99              :         myPendingOutput.insert(device);
     100              :     }
     101      5537930 : }
     102              : 
     103              : 
     104              : // ---------------------------------------------------------------------------
     105              : // MSDevice_Tripinfo-methods
     106              : // ---------------------------------------------------------------------------
     107      2299703 : MSDevice_Tripinfo::MSDevice_Tripinfo(SUMOVehicle& holder, const std::string& id) :
     108              :     MSVehicleDevice(holder, id),
     109            0 :     myDepartLane(""),
     110      2299703 :     myDepartSpeed(-1),
     111      2299703 :     myDepartPosLat(0),
     112      2299703 :     myWaitingTime(0),
     113      2299703 :     myAmWaiting(false),
     114      2299703 :     myWaitingCount(0),
     115      2299703 :     myStoppingTime(0),
     116      2299703 :     myParkingStarted(-1),
     117      2299703 :     myArrivalTime(NOT_ARRIVED),
     118      2299703 :     myArrivalLane(""),
     119      2299703 :     myArrivalPos(-1),
     120      2299703 :     myArrivalPosLat(0.),
     121      2299703 :     myArrivalSpeed(-1),
     122      2299703 :     myArrivalReason(MSMoveReminder::NOTIFICATION_ARRIVED),
     123      2299703 :     myMesoTimeLoss(0),
     124      2299703 :     myRouteLength(0.) {
     125      2299703 : }
     126              : 
     127              : 
     128      4599356 : MSDevice_Tripinfo::~MSDevice_Tripinfo() {
     129              :     // ensure clean up for vaporized vehicles which do not generate output
     130      2299678 :     myPendingOutput.erase(this);
     131      4599356 : }
     132              : 
     133              : void
     134        40907 : MSDevice_Tripinfo::cleanup() {
     135        40907 :     myVehicleCount = 0;
     136        40907 :     myTotalRouteLength = 0;
     137        40907 :     myTotalSpeed = 0;
     138        40907 :     myTotalDuration = 0;
     139        40907 :     myTotalWaitingTime = 0;
     140        40907 :     myTotalTimeLoss = 0;
     141        40907 :     myTotalDepartDelay = 0;
     142        40907 :     myWaitingDepartDelay = -1;
     143              : 
     144        40907 :     myBikeCount = 0;
     145        40907 :     myTotalBikeRouteLength = 0;
     146        40907 :     myTotalBikeSpeed = 0;
     147        40907 :     myTotalBikeDuration = 0;
     148        40907 :     myTotalBikeWaitingTime = 0;
     149        40907 :     myTotalBikeTimeLoss = 0;
     150        40907 :     myTotalBikeDepartDelay = 0;
     151              : 
     152        40907 :     myWalkCount = 0;
     153        40907 :     myTotalWalkRouteLength = 0;
     154        40907 :     myTotalWalkDuration = 0;
     155        40907 :     myTotalWalkTimeLoss = 0;
     156              : 
     157        40907 :     myRideCount = {0, 0};
     158        40907 :     myRideBusCount = {0, 0};
     159        40907 :     myRideRailCount = {0, 0};
     160        40907 :     myRideTaxiCount = {0, 0};
     161        40907 :     myRideBikeCount = {0, 0};
     162        40907 :     myRideAbortCount = {0, 0};
     163        40907 :     myTotalRideWaitingTime = {0, 0};
     164        40907 :     myTotalRideRouteLength = {0., 0.};
     165        40907 :     myTotalRideDuration = {0, 0};
     166        40907 : }
     167              : 
     168              : bool
     169         3919 : MSDevice_Tripinfo::notifyIdle(SUMOTrafficObject& veh) {
     170         3919 :     if (veh.isVehicle()) {
     171         3919 :         myWaitingTime += DELTA_T;
     172         3919 :         if (!myAmWaiting) {
     173          145 :             myWaitingCount++;
     174          145 :             myAmWaiting = true;
     175              :         }
     176              :     }
     177         3919 :     return true;
     178              : }
     179              : 
     180              : 
     181              : bool
     182    346422406 : MSDevice_Tripinfo::notifyMove(SUMOTrafficObject& veh, double /*oldPos*/,
     183              :                               double /*newPos*/, double newSpeed) {
     184    346422406 :     if (veh.isStopped()) {
     185      2242432 :         if (newSpeed <= SUMO_const_haltingSpeed) {
     186      2242245 :             myStoppingTime += DELTA_T;
     187              :         }
     188    344179974 :     } else if (newSpeed <= SUMO_const_haltingSpeed && lowAcceleration(veh)) {
     189     53684344 :         myWaitingTime += DELTA_T;
     190     53684344 :         if (!myAmWaiting) {
     191      2663698 :             myWaitingCount++;
     192      2663698 :             myAmWaiting = true;
     193              :         }
     194              :     } else {
     195    290495630 :         myAmWaiting = false;
     196              :     }
     197    346422406 :     return true;
     198              : }
     199              : 
     200              : 
     201              : bool
     202     53685203 : MSDevice_Tripinfo::lowAcceleration(const SUMOTrafficObject& veh) {
     203     53685203 :     if (MSGlobals::gUseMesoSim) {
     204              :         // acceleration is not modelled
     205              :         return false;
     206              :     } else {
     207     53685203 :         const MSVehicle& v = dynamic_cast<const MSVehicle&>(veh);
     208     53685203 :         return v.getAcceleration() <= v.accelThresholdForWaiting();
     209              :     }
     210              : }
     211              : 
     212              : 
     213              : void
     214     13355545 : 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     13355545 :     const double vmax = veh.getEdge()->getVehicleMaxSpeed(&veh);
     225     13355545 :     if (vmax > 0) {
     226     16308713 :         myMesoTimeLoss += TIME2STEPS(timeOnLane * (vmax - meanSpeedVehicleOnLane) / vmax);
     227              :     }
     228     13355545 :     myWaitingTime += veh.getWaitingTime();
     229     13355545 : }
     230              : 
     231              : 
     232              : void
     233      1742020 : MSDevice_Tripinfo::updateParkingStopTime() {
     234      1742020 :     if (myParkingStarted >= 0) {
     235         3881 :         myStoppingTime += (MSNet::getInstance()->getCurrentTimeStep() - myParkingStarted);
     236         3881 :         myParkingStarted = -1;
     237              :     }
     238      1742020 : }
     239              : 
     240              : bool
     241     27908795 : MSDevice_Tripinfo::notifyEnter(SUMOTrafficObject& veh, MSMoveReminder::Notification reason, const MSLane* /* enteredLane */) {
     242     27908795 :     if (reason == MSMoveReminder::NOTIFICATION_DEPARTED) {
     243      1772486 :         if (!MSGlobals::gUseMesoSim) {
     244      1392737 :             myDepartLane = static_cast<MSVehicle&>(veh).getLane()->getID();
     245      1392737 :             myDepartPosLat = static_cast<MSVehicle&>(veh).getLateralPositionOnLane();
     246              :         } else {
     247       379749 :             myDepartLane = veh.getEdge()->getFirstAllowed(veh.getVClass(), true)->getID();
     248              :         }
     249      1772486 :         myDepartSpeed = veh.getSpeed();
     250      1772486 :         myRouteLength = -veh.getPositionOnLane();
     251     26136309 :     } else if (reason == MSMoveReminder::NOTIFICATION_PARKING) {
     252              :         // notifyMove is not called while parking
     253              :         // @note insertion delay when resuming after parking is included
     254         3312 :         updateParkingStopTime();
     255              :     }
     256     27908795 :     return true;
     257              : }
     258              : 
     259              : 
     260              : bool
     261     27837178 : MSDevice_Tripinfo::notifyLeave(SUMOTrafficObject& veh, double /*lastPos*/,
     262              :                                MSMoveReminder::Notification reason, const MSLane* /* enteredLane */) {
     263     27837178 :     if (reason >= MSMoveReminder::NOTIFICATION_ARRIVED) {
     264      1705119 :         myArrivalTime = MSNet::getInstance()->getCurrentTimeStep();
     265      1705119 :         myArrivalReason = reason;
     266      1705119 :         if (!MSGlobals::gUseMesoSim) {
     267      1330639 :             myArrivalLane = static_cast<MSVehicle&>(veh).getLane()->getID();
     268      1330639 :             myArrivalPosLat = static_cast<MSVehicle&>(veh).getLateralPositionOnLane();
     269              :         } else {
     270       374480 :             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      1705119 :         if (reason > MSMoveReminder::NOTIFICATION_TELEPORT_ARRIVED) {
     276              :             // vaporized
     277          549 :             myArrivalPos = veh.getPositionOnLane();
     278              :         } else {
     279      1704570 :             myArrivalPos = myHolder.getArrivalPos();
     280              :         }
     281      1705119 :         myArrivalSpeed = veh.getSpeed();
     282      1705119 :         updateParkingStopTime();
     283     26132059 :     } else if (reason == MSMoveReminder::NOTIFICATION_PARKING) {
     284         4034 :         myParkingStarted = MSNet::getInstance()->getCurrentTimeStep();
     285     26128025 :     } else if (reason == NOTIFICATION_JUNCTION
     286     26128025 :                || reason == NOTIFICATION_TELEPORT
     287     12377373 :                || reason == NOTIFICATION_TELEPORT_CONTINUATION) {
     288     13755949 :         if (MSGlobals::gUseMesoSim) {
     289      1417424 :             myRouteLength += myHolder.getEdge()->getLength();
     290              :         } else {
     291     12338525 :             const MSLane* lane = static_cast<MSVehicle&>(veh).getLane();
     292     12338525 :             if (lane != nullptr) {
     293     12338501 :                 myRouteLength += lane->getLength();
     294              :             }
     295              :         }
     296              :     }
     297     27837178 :     return true;
     298              : }
     299              : 
     300              : 
     301              : void
     302      1738532 : MSDevice_Tripinfo::generateOutput(OutputDevice* tripinfoOut) const {
     303      1738532 :     const SUMOTime timeLoss = MSGlobals::gUseMesoSim ? myMesoTimeLoss : static_cast<MSVehicle&>(myHolder).getTimeLoss();
     304      1738532 :     const double routeLength = myRouteLength + (myArrivalTime == NOT_ARRIVED ? myHolder.getPositionOnLane() : myArrivalPos);
     305              :     SUMOTime duration = 0;
     306      1738532 :     if (myHolder.hasDeparted()) {
     307      1771671 :         duration = (myArrivalTime == NOT_ARRIVED ? SIMSTEP : myArrivalTime) - myHolder.getDeparture();
     308      1738288 :         if (myHolder.getVClass() == SVC_BICYCLE) {
     309        25193 :             myBikeCount++;
     310        25193 :             myTotalBikeRouteLength += routeLength;
     311        25193 :             myTotalBikeSpeed += routeLength / STEPS2TIME(duration);
     312        25193 :             myTotalBikeDuration += duration;
     313        25193 :             myTotalBikeWaitingTime += myWaitingTime;
     314        25193 :             myTotalBikeTimeLoss += timeLoss;
     315        25193 :             myTotalBikeDepartDelay += myHolder.getDepartDelay();
     316              :         } else {
     317      1713095 :             myVehicleCount++;
     318      1713095 :             myTotalRouteLength += routeLength;
     319      1713095 :             myTotalSpeed += routeLength / STEPS2TIME(duration);
     320      1713095 :             myTotalDuration += duration;
     321      1713095 :             myTotalWaitingTime += myWaitingTime;
     322      1713095 :             myTotalTimeLoss += timeLoss;
     323      1713095 :             myTotalDepartDelay += myHolder.getDepartDelay();
     324              :         }
     325              :     }
     326              : 
     327      1738532 :     myPendingOutput.erase(this);
     328      1738532 :     if (tripinfoOut == nullptr) {
     329      1500341 :         return;
     330              :     }
     331              :     // write
     332              :     OutputDevice& os = *tripinfoOut;
     333       476382 :     os.openTag("tripinfo").writeAttr("id", myHolder.getID());
     334       476382 :     os.writeAttr("depart", myHolder.hasDeparted() ? time2string(myHolder.getDeparture()) : "-1");
     335       238191 :     os.writeAttr("departLane", myDepartLane);
     336       238191 :     os.writeAttr("departPos", myHolder.getDepartPos());
     337       238191 :     if (MSGlobals::gLateralResolution > 0) {
     338        50958 :         os.writeAttr("departPosLat", myDepartPosLat);
     339              :     }
     340       238191 :     os.writeAttr("departSpeed", myDepartSpeed);
     341       238191 :     SUMOTime departDelay = myHolder.getDepartDelay();
     342       238191 :     const SUMOVehicleParameter& param = myHolder.getParameter();
     343       238191 :     if (!myHolder.hasDeparted()) {
     344              :         assert(param.depart <= SIMSTEP || param.departProcedure != DepartDefinition::GIVEN);
     345          244 :         departDelay = SIMSTEP - param.depart;
     346              :     }
     347       476382 :     os.writeAttr("departDelay", time2string(departDelay));
     348       476382 :     os.writeAttr("arrival", time2string(myArrivalTime));
     349       238191 :     os.writeAttr("arrivalLane", myArrivalLane);
     350       238191 :     os.writeAttr("arrivalPos", myArrivalPos);
     351       238191 :     if (MSGlobals::gLateralResolution > 0) {
     352        50958 :         os.writeAttr("arrivalPosLat", myArrivalPosLat);
     353              :     }
     354       238191 :     os.writeAttr("arrivalSpeed", myArrivalSpeed);
     355       476382 :     os.writeAttr("duration", time2string(duration));
     356       238191 :     os.writeAttr("routeLength", routeLength);
     357       238191 :     os.writeAttr(SUMO_ATTR_WAITINGTIME, time2string(myWaitingTime));
     358       238191 :     os.writeAttr(SUMO_ATTR_WAITINGCOUNT, myWaitingCount);
     359       238191 :     os.writeAttr(SUMO_ATTR_STOPTIME, time2string(myStoppingTime));
     360       238191 :     os.writeAttr(SUMO_ATTR_TIMELOSS, time2string(timeLoss));
     361       238191 :     os.writeAttr("rerouteNo", myHolder.getNumberReroutes());
     362       714573 :     os.writeAttr("devices", toString(myHolder.getDevices()));
     363       238191 :     os.writeAttr("vType", myHolder.getVehicleType().getID());
     364       476382 :     os.writeAttr("speedFactor", myHolder.getChosenSpeedFactor());
     365              :     std::string vaporized;
     366       238191 :     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       237808 :         default:
     386       237808 :             if (myHolder.getEdge() == myHolder.getRoute().getLastEdge() ||
     387         1566 :                     (param.arrivalEdge >= 0 && myHolder.getRoutePosition() >= param.arrivalEdge)) {
     388              :                 vaporized = "";
     389              :             } else {
     390              :                 vaporized = "end";
     391              :             }
     392              :             break;
     393              :     }
     394       476382 :     os.writeAttr("vaporized", vaporized);
     395              :     // cannot close tag because emission device output might follow
     396              : }
     397              : 
     398              : 
     399              : void
     400          953 : MSDevice_Tripinfo::generateOutputForUnfinished() {
     401          953 :     MSNet* net = MSNet::getInstance();
     402          953 :     OutputDevice* tripinfoOut = (OptionsCont::getOptions().isSet("tripinfo-output") ?
     403         1651 :                                  &OutputDevice::getDeviceByOption("tripinfo-output") : nullptr);
     404          953 :     myWaitingDepartDelay = 0;
     405          953 :     myUndepartedVehicleCount = 0;
     406         1906 :     const bool writeUndeparted = OptionsCont::getOptions().getBool("tripinfo-output.write-undeparted");
     407              :     const SUMOTime t = net->getCurrentTimeStep();
     408        66261 :     while (myPendingOutput.size() > 0) {
     409        65308 :         const MSDevice_Tripinfo* d = *myPendingOutput.begin();
     410        65308 :         const bool departed = d->myHolder.hasDeparted();
     411        65308 :         const bool departDelayed = d->myHolder.getParameter().depart <= t;
     412        65308 :         if (!departed && departDelayed) {
     413        31951 :             myUndepartedVehicleCount++;
     414        31951 :             myWaitingDepartDelay += (t - d->myHolder.getParameter().depart);
     415              :         }
     416        65308 :         if (departed || (writeUndeparted && departDelayed)) {
     417        33589 :             const_cast<MSDevice_Tripinfo*>(d)->updateParkingStopTime();
     418        33589 :             d->generateOutput(tripinfoOut);
     419        33589 :             if (tripinfoOut != nullptr) {
     420         7284 :                 for (MSVehicleDevice* const dev : d->myHolder.getDevices()) {
     421         5185 :                     if (typeid(*dev) == typeid(MSDevice_Tripinfo) || typeid(*dev) == typeid(MSDevice_Vehroutes)) {
     422              :                         // tripinfo is special and vehroute has its own write-unfinished option
     423         2661 :                         continue;
     424              :                     }
     425         2524 :                     dev->generateOutput(tripinfoOut);
     426              :                 }
     427         4198 :                 OutputDevice::getDeviceByOption("tripinfo-output").closeTag();
     428              :             }
     429              :         } else {
     430              :             myPendingOutput.erase(d);
     431              :         }
     432              :     }
     433              :     // unfinished persons
     434          953 :     if (net->hasPersons()) {
     435          591 :         net->getPersonControl().eraseAll();
     436              :     }
     437              : 
     438          953 : }
     439              : 
     440              : 
     441              : void
     442        55407 : MSDevice_Tripinfo::addPedestrianData(double walkLength, SUMOTime walkDuration, SUMOTime walkTimeLoss) {
     443        55407 :     myWalkCount++;
     444        55407 :     myTotalWalkRouteLength += walkLength;
     445        55407 :     myTotalWalkDuration += walkDuration;
     446        55407 :     myTotalWalkTimeLoss += walkTimeLoss;
     447        55407 : }
     448              : 
     449              : 
     450              : void
     451         7190 : MSDevice_Tripinfo::addRideTransportData(const bool isPerson, const double distance, const SUMOTime duration,
     452              :                                         const SUMOVehicleClass vClass, const std::string& line, const SUMOTime waitingTime) {
     453         7190 :     const int index = isPerson ? 0 : 1;
     454         7190 :     myRideCount[index]++;
     455         7190 :     if (duration > 0) {
     456         6871 :         myTotalRideWaitingTime[index] += waitingTime;
     457         6871 :         myTotalRideRouteLength[index] += distance;
     458         6871 :         myTotalRideDuration[index] += duration;
     459         6871 :         if (vClass == SVC_BICYCLE) {
     460           13 :             myRideBikeCount[index]++;
     461         6858 :         } else if (!line.empty()) {
     462         5649 :             if (isRailway(vClass)) {
     463          801 :                 myRideRailCount[index]++;
     464         4848 :             } else if (vClass == SVC_TAXI) {
     465         1600 :                 myRideTaxiCount[index]++;
     466              :             } else {
     467              :                 // some kind of road vehicle
     468         3248 :                 myRideBusCount[index]++;
     469              :             }
     470              :         }
     471              :     } else {
     472          319 :         myRideAbortCount[index]++;
     473              :     }
     474         7190 : }
     475              : 
     476              : 
     477              : std::string
     478         3098 : MSDevice_Tripinfo::printStatistics() {
     479         3098 :     std::ostringstream msg;
     480              :     msg.setf(msg.fixed);
     481         3098 :     msg.precision(gPrecision);
     482         3098 :     if (myBikeCount == 0 || myVehicleCount > 0) {
     483         3032 :         msg << "Statistics (avg of " << myVehicleCount << "):\n";
     484         3032 :         msg << " RouteLength: " << getAvgRouteLength() << "\n"
     485         3032 :             << " Speed: " << getAvgTripSpeed() << "\n"
     486         3032 :             << " Duration: " << getAvgDuration() << "\n"
     487         3032 :             << " WaitingTime: " << getAvgWaitingTime() << "\n"
     488         3032 :             << " TimeLoss: " << getAvgTimeLoss() << "\n"
     489         6064 :             << " DepartDelay: " << getAvgDepartDelay() << "\n";
     490              :     }
     491         3098 :     if (myBikeCount > 0) {
     492              :         msg << "Bike Statistics (avg of " << myBikeCount << "):\n"
     493          304 :             << " RouteLength: " << getAvgBikeRouteLength() << "\n"
     494          152 :             << " Speed: " << getAvgBikeTripSpeed() << "\n"
     495          152 :             << " Duration: " << getAvgBikeDuration() << "\n"
     496          152 :             << " WaitingTime: " << getAvgBikeWaitingTime() << "\n"
     497          152 :             << " TimeLoss: " << getAvgBikeTimeLoss() << "\n"
     498          304 :             << " DepartDelay: " << getAvgBikeDepartDelay() << "\n";
     499          152 :         if (myVehicleCount > 0 && myWaitingDepartDelay >= 0) {
     500           19 :             msg << "Statistics (avg of " << (myVehicleCount + myBikeCount) << "):\n";
     501              :         }
     502              :     }
     503         3098 :     if (myWaitingDepartDelay >= 0) {
     504          686 :         msg << " DepartDelayWaiting: " << getAvgDepartDelayWaiting() << "\n";
     505              :     }
     506         3098 :     if (myWalkCount > 0) {
     507              :         msg << "Pedestrian Statistics (avg of " << myWalkCount << " walks):\n"
     508          576 :             << " RouteLength: " << getAvgWalkRouteLength() << "\n"
     509          288 :             << " Duration: " << getAvgWalkDuration() << "\n"
     510          576 :             << " TimeLoss: " << getAvgWalkTimeLoss() << "\n";
     511              :     }
     512         6196 :     printRideStatistics(msg, "Ride", "rides", 0);
     513         6196 :     printRideStatistics(msg, "Transport", "transports", 1);
     514         3098 :     return msg.str();
     515         3098 : }
     516              : 
     517              : void
     518         6196 : MSDevice_Tripinfo::printRideStatistics(std::ostringstream& msg, const std::string& category, const std::string& modeName, const int index) {
     519         6196 :     if (myRideCount[index] > 0) {
     520          336 :         msg << category << " Statistics (avg of " << myRideCount[index] << " " << modeName << "):\n";
     521          112 :         msg << " WaitingTime: " << STEPS2TIME(myTotalRideWaitingTime[index] / myRideCount[index]) << "\n";
     522          112 :         msg << " RouteLength: " << myTotalRideRouteLength[index] / myRideCount[index] << "\n";
     523          112 :         msg << " Duration: " << STEPS2TIME(myTotalRideDuration[index] / myRideCount[index]) << "\n";
     524          112 :         if (myRideBusCount[index] > 0) {
     525           15 :             msg << " Bus: " << myRideBusCount[index] << "\n";
     526              :         }
     527          112 :         if (myRideRailCount[index] > 0) {
     528            9 :             msg << " Train: " << myRideRailCount[index] << "\n";
     529              :         }
     530          112 :         if (myRideTaxiCount[index] > 0) {
     531           66 :             msg << " Taxi: " << myRideTaxiCount[index] << "\n";
     532              :         }
     533          112 :         if (myRideBikeCount[index] > 0) {
     534           13 :             msg << " Bike: " << myRideBikeCount[index] << "\n";
     535              :         }
     536          112 :         if (myRideAbortCount[index] > 0) {
     537           11 :             msg << " Aborted: " << myRideAbortCount[index] << "\n";
     538              :         }
     539              :     }
     540              : 
     541         6196 : }
     542              : 
     543              : 
     544              : void
     545          264 : MSDevice_Tripinfo::writeStatistics(OutputDevice& od) {
     546          264 :     od.setPrecision(gPrecision);
     547          264 :     od.openTag("vehicleTripStatistics");
     548          264 :     od.writeAttr("count", myVehicleCount);
     549          264 :     od.writeAttr("routeLength", getAvgRouteLength());
     550          264 :     od.writeAttr("speed", getAvgTripSpeed());
     551          264 :     od.writeAttr("duration", getAvgDuration());
     552          264 :     od.writeAttr("waitingTime", getAvgWaitingTime());
     553          264 :     od.writeAttr("timeLoss", getAvgTimeLoss());
     554          264 :     od.writeAttr("departDelay", getAvgDepartDelay());
     555          264 :     od.writeAttr("departDelayWaiting", getAvgDepartDelayWaiting());
     556          528 :     od.writeAttr("totalTravelTime", time2string(myTotalDuration));
     557          528 :     od.writeAttr("totalDepartDelay", time2string(TIME2STEPS(getTotalDepartDelay() + getTotalBikeDepartDelay())));
     558          264 :     od.closeTag();
     559          264 :     if (myBikeCount > 0) {
     560            6 :         od.openTag("bikeTripStatistics");
     561            6 :         od.writeAttr("count", myBikeCount);
     562            6 :         od.writeAttr("routeLength", getAvgBikeRouteLength());
     563            6 :         od.writeAttr("speed", getAvgBikeTripSpeed());
     564            6 :         od.writeAttr("duration", getAvgBikeDuration());
     565            6 :         od.writeAttr("waitingTime", getAvgBikeWaitingTime());
     566            6 :         od.writeAttr("timeLoss", getAvgBikeTimeLoss());
     567            6 :         od.writeAttr("departDelay", getAvgBikeDepartDelay());
     568           12 :         od.writeAttr("totalTravelTime", time2string(myTotalBikeDuration));
     569           12 :         od.closeTag();
     570              :     }
     571          264 :     od.openTag("pedestrianStatistics");
     572          264 :     od.writeAttr("number", myWalkCount);
     573          264 :     od.writeAttr("routeLength", getAvgWalkRouteLength());
     574          264 :     od.writeAttr("duration", getAvgWalkDuration());
     575          264 :     od.writeAttr("timeLoss", getAvgWalkTimeLoss());
     576          264 :     od.closeTag();
     577          264 :     writeRideStatistics(od, "rideStatistics", 0);
     578          264 :     writeRideStatistics(od, "transportStatistics", 1);
     579          264 : }
     580              : 
     581              : void
     582          528 : MSDevice_Tripinfo::writeRideStatistics(OutputDevice& od, const std::string& category, const int index) {
     583          528 :     od.openTag(category);
     584         1056 :     od.writeAttr("number", myRideCount[index]);
     585          528 :     if (myRideCount[index] > 0) {
     586            4 :         od.writeAttr("waitingTime", STEPS2TIME(myTotalRideWaitingTime[index] / myRideCount[index]));
     587            4 :         od.writeAttr("routeLength", myTotalRideRouteLength[index] / myRideCount[index]);
     588            4 :         od.writeAttr("duration", STEPS2TIME(myTotalRideDuration[index] / myRideCount[index]));
     589            4 :         od.writeAttr("bus", myRideBusCount[index]);
     590            4 :         od.writeAttr("train", myRideRailCount[index]);
     591            4 :         od.writeAttr("taxi", myRideTaxiCount[index]);
     592            4 :         od.writeAttr("bike", myRideBikeCount[index]);
     593            4 :         od.writeAttr("aborted", myRideAbortCount[index]);
     594              :     }
     595          528 :     od.closeTag();
     596          528 : }
     597              : 
     598              : 
     599              : double
     600         3394 : MSDevice_Tripinfo::getAvgRouteLength() {
     601         3394 :     if (myVehicleCount > 0) {
     602         3158 :         return myTotalRouteLength / myVehicleCount;
     603              :     } else {
     604              :         return 0;
     605              :     }
     606              : }
     607              : 
     608              : double
     609         3394 : MSDevice_Tripinfo::getAvgTripSpeed() {
     610         3394 :     if (myVehicleCount > 0) {
     611         3158 :         return myTotalSpeed / myVehicleCount;
     612              :     } else {
     613              :         return 0;
     614              :     }
     615              : }
     616              : 
     617              : double
     618         3394 : MSDevice_Tripinfo::getAvgDuration() {
     619         3394 :     if (myVehicleCount > 0) {
     620         3158 :         return STEPS2TIME(myTotalDuration / myVehicleCount);
     621              :     } else {
     622              :         return 0;
     623              :     }
     624              : }
     625              : 
     626              : double
     627         3394 : MSDevice_Tripinfo::getAvgWaitingTime() {
     628         3394 :     if (myVehicleCount > 0) {
     629         3158 :         return STEPS2TIME(myTotalWaitingTime / myVehicleCount);
     630              :     } else {
     631              :         return 0;
     632              :     }
     633              : }
     634              : 
     635              : 
     636              : double
     637         3394 : MSDevice_Tripinfo::getAvgTimeLoss() {
     638         3394 :     if (myVehicleCount > 0) {
     639         3158 :         return STEPS2TIME(myTotalTimeLoss / myVehicleCount);
     640              :     } else {
     641              :         return 0;
     642              :     }
     643              : }
     644              : 
     645              : 
     646              : double
     647         3394 : MSDevice_Tripinfo::getAvgDepartDelay() {
     648         3394 :     if (myVehicleCount > 0) {
     649         3158 :         return STEPS2TIME(myTotalDepartDelay / myVehicleCount);
     650              :     } else {
     651              :         return 0;
     652              :     }
     653              : }
     654              : 
     655              : double
     656          705 : MSDevice_Tripinfo::getAvgDepartDelayWaiting() {
     657          705 :     if (myWaitingDepartDelay >= 0) {
     658          355 :         return STEPS2TIME(myWaitingDepartDelay / MAX2(1, myUndepartedVehicleCount));
     659              :     } else {
     660              :         return -1;
     661              :     }
     662              : }
     663              : 
     664              : 
     665              : double
     666          626 : MSDevice_Tripinfo::getTotalDepartDelay() {
     667          626 :     return STEPS2TIME(myTotalDepartDelay + MAX2((SUMOTime)0, myWaitingDepartDelay));
     668              : }
     669              : 
     670              : double
     671          207 : MSDevice_Tripinfo::getAvgBikeRouteLength() {
     672          207 :     if (myBikeCount > 0) {
     673          158 :         return myTotalBikeRouteLength / myBikeCount;
     674              :     } else {
     675              :         return 0;
     676              :     }
     677              : }
     678              : 
     679              : double
     680          207 : MSDevice_Tripinfo::getAvgBikeTripSpeed() {
     681          207 :     if (myBikeCount > 0) {
     682          158 :         return myTotalBikeSpeed / myBikeCount;
     683              :     } else {
     684              :         return 0;
     685              :     }
     686              : }
     687              : 
     688              : double
     689          207 : MSDevice_Tripinfo::getAvgBikeDuration() {
     690          207 :     if (myBikeCount > 0) {
     691          158 :         return STEPS2TIME(myTotalBikeDuration / myBikeCount);
     692              :     } else {
     693              :         return 0;
     694              :     }
     695              : }
     696              : 
     697              : double
     698          207 : MSDevice_Tripinfo::getAvgBikeWaitingTime() {
     699          207 :     if (myBikeCount > 0) {
     700          158 :         return STEPS2TIME(myTotalBikeWaitingTime / myBikeCount);
     701              :     } else {
     702              :         return 0;
     703              :     }
     704              : }
     705              : 
     706              : 
     707              : double
     708          207 : MSDevice_Tripinfo::getAvgBikeTimeLoss() {
     709          207 :     if (myBikeCount > 0) {
     710          158 :         return STEPS2TIME(myTotalBikeTimeLoss / myBikeCount);
     711              :     } else {
     712              :         return 0;
     713              :     }
     714              : }
     715              : 
     716              : double
     717          158 : MSDevice_Tripinfo::getAvgBikeDepartDelay() {
     718          158 :     if (myBikeCount > 0) {
     719          158 :         return STEPS2TIME(myTotalBikeDepartDelay / myBikeCount);
     720              :     } else {
     721              :         return 0;
     722              :     }
     723              : }
     724              : 
     725              : 
     726              : double
     727          528 : MSDevice_Tripinfo::getTotalBikeDepartDelay() {
     728          528 :     return STEPS2TIME(myTotalBikeDepartDelay);
     729              : }
     730              : 
     731              : double
     732          601 : MSDevice_Tripinfo::getAvgWalkRouteLength() {
     733          601 :     if (myWalkCount > 0) {
     734          294 :         return myTotalWalkRouteLength / myWalkCount;
     735              :     } else {
     736              :         return 0;
     737              :     }
     738              : }
     739              : 
     740              : double
     741          601 : MSDevice_Tripinfo::getAvgWalkDuration() {
     742          601 :     if (myWalkCount > 0) {
     743          294 :         return STEPS2TIME(myTotalWalkDuration / myWalkCount);
     744              :     } else {
     745              :         return 0;
     746              :     }
     747              : }
     748              : 
     749              : 
     750              : double
     751          601 : MSDevice_Tripinfo::getAvgWalkTimeLoss() {
     752          601 :     if (myWalkCount > 0) {
     753          294 :         return STEPS2TIME(myTotalWalkTimeLoss / myWalkCount);
     754              :     } else {
     755              :         return 0;
     756              :     }
     757              : }
     758              : 
     759              : 
     760              : double
     761            0 : MSDevice_Tripinfo::getAvgRideDuration() {
     762            0 :     if (myRideCount[0] > 0) {
     763            0 :         return STEPS2TIME(myTotalRideDuration[0] / myRideCount[0]);
     764              :     } else {
     765              :         return 0;
     766              :     }
     767              : }
     768              : 
     769              : double
     770            0 : MSDevice_Tripinfo::getAvgRideWaitingTime() {
     771            0 :     if (myRideCount[0] > 0) {
     772            0 :         return STEPS2TIME(myTotalRideWaitingTime[0] / myRideCount[0]);
     773              :     } else {
     774              :         return 0;
     775              :     }
     776              : }
     777              : 
     778              : double
     779            0 : MSDevice_Tripinfo::getAvgRideRouteLength() {
     780            0 :     if (myRideCount[0] > 0) {
     781            0 :         return myTotalRideRouteLength[0] / myRideCount[0];
     782              :     } else {
     783              :         return 0;
     784              :     }
     785              : }
     786              : 
     787              : 
     788              : std::string
     789          255 : MSDevice_Tripinfo::getParameter(const std::string& key) const {
     790          255 :     if (key == toString(SUMO_ATTR_WAITINGTIME)) {
     791           40 :         return toString(STEPS2TIME(myWaitingTime));
     792          215 :     } else if (key == toString(SUMO_ATTR_WAITINGCOUNT)) {
     793           40 :         return toString(myWaitingCount);
     794          175 :     } else if (key == toString(SUMO_ATTR_STOPTIME)) {
     795           40 :         return toString(STEPS2TIME(myStoppingTime));
     796          135 :     } else if (key == toString(SUMO_ATTR_ARRIVALTIME)) {
     797           27 :         return toString(STEPS2TIME(myArrivalTime));
     798          108 :     } else if (key == toString(SUMO_ATTR_ARRIVALLANE)) {
     799           27 :         return toString(myArrivalLane);
     800           81 :     } else if (key == toString(SUMO_ATTR_ARRIVALPOS)) {
     801           27 :         return toString(myArrivalPos);
     802           54 :     } else if (key == toString(SUMO_ATTR_ARRIVALPOS_LAT)) {
     803           27 :         return toString(myArrivalPosLat);
     804           27 :     } else if (key == toString(SUMO_ATTR_ARRIVALSPEED)) {
     805           27 :         return toString(myArrivalSpeed);
     806              :     }
     807            0 :     throw InvalidArgument("Parameter '" + key + "' is not supported for device of type '" + deviceName() + "'");
     808              : }
     809              : 
     810              : 
     811              : std::string
     812         2548 : MSDevice_Tripinfo::getGlobalParameter(const std::string& prefixedKey) {
     813              :     std::string key = prefixedKey; // by default, assume vehicleTripStatistics;
     814         2548 :     const std::string err = "Parameter '" + prefixedKey + "' is not supported for device of type 'tripinfo'";
     815         5096 :     if (StringUtils::startsWith(key, "vehicleTripStatistics.")) {
     816          980 :         key = prefixedKey.substr(22);
     817         4116 :     } else if (StringUtils::startsWith(key, "bikeTripStatistics.")) {
     818          343 :         key = prefixedKey.substr(19);
     819          343 :         if (key == toString(SUMO_ATTR_COUNT)) {
     820           49 :             return toString(myBikeCount);
     821          294 :         } else if (key == "routeLength") {
     822           49 :             return toString(getAvgBikeRouteLength());
     823          245 :         } else if (key == toString(SUMO_ATTR_SPEED)) {
     824           49 :             return toString(getAvgBikeTripSpeed());
     825          196 :         } else if (key == toString(SUMO_ATTR_DURATION)) {
     826           49 :             return toString(getAvgBikeDuration());
     827          147 :         } else if (key == toString(SUMO_ATTR_WAITINGTIME)) {
     828           49 :             return toString(getAvgBikeWaitingTime());
     829           98 :         } else if (key == toString(SUMO_ATTR_TIMELOSS)) {
     830           49 :             return toString(getAvgBikeTimeLoss());
     831           49 :         } else if (key == "departDelay") {
     832            0 :             return toString(getAvgBikeDepartDelay());
     833           49 :         } else if (key == "totalTravelTime") {
     834              :             // avoid human readable output
     835           49 :             return toString(STEPS2TIME((myTotalBikeDuration)));
     836              :         }
     837            0 :         throw InvalidArgument(err);
     838              : 
     839         3430 :     } else if (StringUtils::startsWith(key, "pedestrianStatistics.")) {
     840          245 :         key = prefixedKey.substr(21);
     841          441 :         if (key == toString(SUMO_ATTR_NUMBER) || key == toString(SUMO_ATTR_COUNT)) {
     842           98 :             return toString(myWalkCount);
     843          147 :         } else if (key == "routeLength") {
     844           49 :             return toString(getAvgWalkRouteLength());
     845           98 :         } else if (key == toString(SUMO_ATTR_DURATION)) {
     846           49 :             return toString(getAvgWalkDuration());
     847           49 :         } else if (key == toString(SUMO_ATTR_TIMELOSS)) {
     848           49 :             return toString(getAvgWalkTimeLoss());
     849              :         }
     850            0 :         throw InvalidArgument(err);
     851              : 
     852         2940 :     } else if (StringUtils::startsWith(key, "rideStatistics.") ||
     853         2450 :                StringUtils::startsWith(key, "transportStatistics.")) {
     854              :         int index = 0;
     855         1960 :         if (StringUtils::startsWith(key, "rideStatistics.")) {
     856          980 :             key = prefixedKey.substr(15);
     857              :         } else {
     858              :             index = 1;
     859          980 :             key = prefixedKey.substr(20);
     860              :         }
     861         1862 :         if (key == toString(SUMO_ATTR_NUMBER) || key == toString(SUMO_ATTR_COUNT)) {
     862          196 :             return toString(myRideCount[index]);
     863          784 :         } else if (key == toString(SUMO_ATTR_WAITINGTIME)) {
     864           98 :             return toString(STEPS2TIME(myTotalRideWaitingTime[index] / MAX2(1, myRideCount[index])));
     865          686 :         } else if (key == "routeLength") {
     866           98 :             return toString(myTotalRideRouteLength[index] / MAX2(1, myRideCount[index]));
     867          588 :         } else if (key == toString(SUMO_ATTR_DURATION)) {
     868           98 :             return toString(myTotalRideRouteLength[index] / MAX2(1, myRideCount[index]));
     869          490 :         } else if (key == "bus") {
     870           98 :             return toString(myRideBusCount[index]);
     871          392 :         } else if (key == "train") {
     872           98 :             return toString(myRideRailCount[index]);
     873          294 :         } else if (key == "taxi") {
     874           98 :             return toString(myRideTaxiCount[index]);
     875          196 :         } else if (key == "bike") {
     876           98 :             return toString(myRideBikeCount[index]);
     877           98 :         } else if (key == "aborted") {
     878           98 :             return toString(myRideAbortCount[index]);
     879              :         }
     880            0 :         throw InvalidArgument(err);
     881              :     }
     882              :     // vehicleTripStatistics
     883          980 :     if (key == toString(SUMO_ATTR_COUNT)) {
     884           98 :         return toString(myVehicleCount);
     885          882 :     } else if (key == "routeLength") {
     886           98 :         return toString(getAvgRouteLength());
     887          784 :     } else if (key == toString(SUMO_ATTR_SPEED)) {
     888           98 :         return toString(getAvgTripSpeed());
     889          686 :     } else if (key == toString(SUMO_ATTR_DURATION)) {
     890           98 :         return toString(getAvgDuration());
     891          588 :     } else if (key == toString(SUMO_ATTR_WAITINGTIME)) {
     892           98 :         return toString(getAvgWaitingTime());
     893          490 :     } else if (key == toString(SUMO_ATTR_TIMELOSS)) {
     894           98 :         return toString(getAvgTimeLoss());
     895          392 :     } else if (key == "departDelay") {
     896           98 :         return toString(getAvgDepartDelay());
     897          294 :     } else if (key == "departDelayWaiting") {
     898           98 :         return toString(getAvgDepartDelayWaiting());
     899          196 :     } else if (key == "totalTravelTime") {
     900              :         // avoid human readable output
     901           98 :         return toString(STEPS2TIME((myTotalDuration)));
     902           98 :     } else if (key == "totalDepartDelay") {
     903           98 :         return toString(getTotalDepartDelay());
     904              :     }
     905            0 :     throw InvalidArgument(err);
     906              : }
     907              : 
     908              : 
     909              : void
     910          202 : MSDevice_Tripinfo::saveState(OutputDevice& out) const {
     911              :     // always write device id to replicate stochastic assignment
     912          202 :     out.openTag(SUMO_TAG_DEVICE);
     913          202 :     out.writeAttr(SUMO_ATTR_ID, getID());
     914          202 :     if (myHolder.hasDeparted()) {
     915          124 :         std::ostringstream internals;
     916          124 :         internals << myDepartLane << " ";
     917          124 :         if (!MSGlobals::gUseMesoSim) {
     918           79 :             internals << myDepartPosLat << " ";
     919              :         }
     920          124 :         std::string state_arrivalLane = myArrivalLane == "" ? STATE_EMPTY_ARRIVALLANE : myArrivalLane;
     921          620 :         internals << myDepartSpeed << " " << myRouteLength << " " << myWaitingTime << " " << myAmWaiting << " " << myWaitingCount << " ";
     922          248 :         internals << myStoppingTime << " " << myParkingStarted << " ";
     923          496 :         internals << myArrivalTime << " " << state_arrivalLane << " " << myArrivalPos << " " << myArrivalPosLat << " " << myArrivalSpeed;
     924          248 :         out.writeAttr(SUMO_ATTR_STATE, internals.str());
     925          124 :     }
     926          202 :     out.closeTag();
     927          202 : }
     928              : 
     929              : 
     930              : void
     931          152 : MSDevice_Tripinfo::loadState(const SUMOSAXAttributes& attrs) {
     932          152 :     if (attrs.hasAttribute(SUMO_ATTR_STATE)) {
     933          104 :         std::istringstream bis(attrs.getString(SUMO_ATTR_STATE));
     934          104 :         bis >> myDepartLane;
     935          104 :         if (!MSGlobals::gUseMesoSim) {
     936           70 :             bis >> myDepartPosLat;
     937              :         }
     938          104 :         bis >> myDepartSpeed >> myRouteLength >> myWaitingTime >> myAmWaiting >> myWaitingCount;
     939          104 :         bis >> myStoppingTime >> myParkingStarted;
     940          104 :         bis >> myArrivalTime >> myArrivalLane >> myArrivalPos >> myArrivalPosLat >> myArrivalSpeed;
     941          104 :         if (myArrivalLane == STATE_EMPTY_ARRIVALLANE) {
     942              :             myArrivalLane = "";
     943              :         }
     944          104 :     }
     945          152 : }
     946              : 
     947              : 
     948              : /****************************************************************************/
        

Generated by: LCOV version 2.0-1