LCOV - code coverage report
Current view: top level - src/microsim/output - MSFCDExport.cpp (source / functions) Coverage Total Hit
Test: lcov.info Lines: 98.4 % 189 186
Test Date: 2026-06-15 15:46:12 Functions: 100.0 % 14 14

            Line data    Source code
       1              : /****************************************************************************/
       2              : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
       3              : // Copyright (C) 2012-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    MSFCDExport.cpp
      15              : /// @author  Daniel Krajzewicz
      16              : /// @author  Jakob Erdmann
      17              : /// @author  Mario Krumnow
      18              : /// @author  Michael Behrisch
      19              : /// @date    2012-04-26
      20              : ///
      21              : // Realises dumping Floating Car Data (FCD) Data
      22              : /****************************************************************************/
      23              : #include <config.h>
      24              : 
      25              : #include <utils/iodevices/OutputDevice.h>
      26              : #include <utils/options/OptionsCont.h>
      27              : #include <utils/geom/GeoConvHelper.h>
      28              : #include <utils/geom/GeomHelper.h>
      29              : #include <utils/shapes/SUMOPolygon.h>
      30              : #include <libsumo/Helper.h>
      31              : #include <microsim/devices/MSDevice_FCD.h>
      32              : #include <microsim/devices/MSTransportableDevice_FCD.h>
      33              : #include <microsim/MSEdgeControl.h>
      34              : #include <microsim/MSEdge.h>
      35              : #include <microsim/MSLane.h>
      36              : #include <microsim/MSGlobals.h>
      37              : #include <microsim/MSNet.h>
      38              : #include <microsim/MSVehicle.h>
      39              : #include <microsim/lcmodels/MSAbstractLaneChangeModel.h>
      40              : #include <microsim/transportables/MSPerson.h>
      41              : #include <microsim/transportables/MSTransportableControl.h>
      42              : #include <microsim/MSVehicleControl.h>
      43              : #include <mesosim/MEVehicle.h>
      44              : #include "MSEmissionExport.h"
      45              : #include "MSFCDExport.h"
      46              : 
      47              : 
      48              : // ===========================================================================
      49              : // method definitions
      50              : // ===========================================================================
      51              : void
      52      6691631 : MSFCDExport::write(OutputDevice& of, const SUMOTime timestep, const SumoXMLTag tag) {
      53      6691631 :     MSDevice_FCD::initOnce();
      54              :     const SUMOTime period = MSDevice_FCD::getPeriod();
      55              :     const SUMOTime begin = MSDevice_FCD::getBegin();
      56      6691631 :     if ((period > 0 && (timestep - begin) % period != 0) || timestep < begin) {
      57        57722 :         return;
      58              :     }
      59              :     const SumoXMLAttrMask& mask = MSDevice_FCD::getWrittenAttributes();
      60              :     const bool useGeo = MSDevice_FCD::useGeo();
      61              :     const bool useUTM = MSDevice_FCD::useUTM();
      62              :     const double maxLeaderDistance = MSDevice_FCD::getMaxLeaderDistance();
      63              :     const std::vector<std::string>& params = MSDevice_FCD::getParamsToWrite();
      64      6633909 :     MSNet* net = MSNet::getInstance();
      65              :     MSVehicleControl& vc = net->getVehicleControl();
      66              :     const double radius = MSDevice_FCD::getRadius();
      67      6633909 :     const bool filter = MSDevice_FCD::getEdgeFilter().size() > 0;
      68              :     const bool shapeFilter = MSDevice_FCD::hasShapeFilter();
      69              :     std::set<const Named*> inRadius;
      70      6633909 :     if (radius > 0) {
      71              :         // collect all vehicles in radius around equipped vehicles
      72         4152 :         for (MSVehicleControl::constVehIt it = vc.loadedVehBegin(); it != vc.loadedVehEnd(); ++it) {
      73         2738 :             const SUMOVehicle* veh = it->second;
      74         2738 :             if (isVisible(veh) && hasOwnOutput(veh, filter, shapeFilter)) {
      75         1342 :                 PositionVector shape;
      76         1342 :                 shape.push_back(veh->getPosition());
      77         1342 :                 libsumo::Helper::collectObjectsInRange(libsumo::CMD_GET_VEHICLE_VARIABLE, shape, radius, inRadius);
      78         1342 :                 libsumo::Helper::collectObjectsInRange(libsumo::CMD_GET_PERSON_VARIABLE, shape, radius, inRadius);
      79         1342 :             }
      80              :         }
      81              :     }
      82              : 
      83      6633909 :     bool wroteTimestep = false;
      84     16824023 :     auto openTimestep = [&]() {
      85     16824023 :         if (!wroteTimestep) {
      86      6632797 :             of.openTag("timestep").writeTime(SUMO_ATTR_TIME, timestep);
      87      6632797 :             wroteTimestep = true;
      88              :         }
      89     23457932 :     };
      90      6633909 :     if (!MSDevice_FCD::skipEmpty()) {
      91      6632507 :         openTimestep();
      92              :     }
      93     17100426 :     for (MSVehicleControl::constVehIt it = vc.loadedVehBegin(); it != vc.loadedVehEnd(); ++it) {
      94     10466517 :         const SUMOVehicle* const veh = it->second;
      95     10466517 :         if (isVisible(veh)) {
      96     17206378 :             const bool hasOutput = (tag == SUMO_TAG_NOTHING || tag == SUMO_TAG_VEHICLE) && hasOwnOutput(veh, filter, shapeFilter, (radius > 0 && inRadius.count(veh) > 0));
      97              :             if (hasOutput) {
      98      8026250 :                 openTimestep();
      99      8026250 :                 const MSVehicle* const microVeh = MSGlobals::gUseMesoSim ? nullptr : static_cast<const MSVehicle*>(veh);
     100      8026250 :                 Position pos = veh->getPosition();
     101      8026250 :                 if (useGeo) {
     102         2696 :                     of.setPrecision(gPrecisionGeo);
     103         2696 :                     GeoConvHelper::getFinal().cartesian2geo(pos);
     104      8023554 :                 } else if (useUTM) {
     105           90 :                     pos.sub(GeoConvHelper::getFinal().getOffset());
     106              :                 }
     107      8026250 :                 of.openTag(SUMO_TAG_VEHICLE);
     108      8026250 :                 of.writeAttr(SUMO_ATTR_ID, veh->getID());
     109      8026250 :                 of.writeOptionalAttr(SUMO_ATTR_X, pos.x(), mask);
     110      8026250 :                 of.writeOptionalAttr(SUMO_ATTR_Y, pos.y(), mask);
     111      8026250 :                 of.setPrecision(gPrecision);
     112      8026250 :                 of.writeOptionalAttr(SUMO_ATTR_Z, pos.z(), mask);
     113      8026250 :                 of.writeFuncAttr(SUMO_ATTR_ANGLE, [ = ]() {
     114      3835825 :                     return GeomHelper::naviDegree(veh->getAngle());
     115              :                 }, mask);
     116      8026250 :                 of.writeFuncAttr(SUMO_ATTR_TYPE, [ = ]() {
     117      7648029 :                     return veh->getVehicleType().getID();
     118              :                 }, mask);
     119      8026250 :                 of.writeFuncAttr(SUMO_ATTR_SPEED, [ = ]() {
     120      4101076 :                     return veh->getSpeed();
     121              :                 }, mask);
     122      8026250 :                 of.writeFuncAttr(SUMO_ATTR_SPEEDREL, [ = ]() {
     123          776 :                     const double speedLimit = veh->getEdge()->getSpeedLimit();
     124          776 :                     return speedLimit > 0 ? veh->getSpeed() / speedLimit : 0.;
     125              :                 }, mask);
     126      8026250 :                 of.writeFuncAttr(SUMO_ATTR_POSITION, [ = ]() {
     127      3969582 :                     return veh->getPositionOnLane();
     128              :                 }, mask);
     129      8026250 :                 of.writeFuncAttr(SUMO_ATTR_LANE, [ = ]() {
     130      3932389 :                     return MSGlobals::gUseMesoSim ? "" : microVeh->getLane()->getID();
     131              :                 }, mask, MSGlobals::gUseMesoSim);
     132     16123663 :                 of.writeFuncAttr(SUMO_ATTR_EDGE, [ = ]() {
     133        71163 :                     return veh->getCurrentEdge()->getID();
     134      8026250 :                 }, mask, !MSGlobals::gUseMesoSim);
     135      8026250 :                 of.writeFuncAttr(SUMO_ATTR_SLOPE, [ = ]() {
     136      3833163 :                     return veh->getSlope();
     137              :                 }, mask);
     138      8026250 :                 if (!MSGlobals::gUseMesoSim) {
     139      7951389 :                     of.writeFuncAttr(SUMO_ATTR_SIGNALS, [ = ]() {
     140        14762 :                         return microVeh->getSignals();
     141              :                     }, mask);
     142      7951389 :                     of.writeFuncAttr(SUMO_ATTR_ACCELERATION, [ = ]() {
     143       152606 :                         return microVeh->getAcceleration();
     144              :                     }, mask);
     145      7951389 :                     of.writeFuncAttr(SUMO_ATTR_ACCELERATION_LAT, [ = ]() {
     146        55481 :                         return microVeh->getLaneChangeModel().getAccelerationLat();
     147              :                     }, mask);
     148      7951389 :                     of.writeFuncAttr(SUMO_ATTR_SPEED_VEC, [ = ]() {
     149          844 :                         return GeomHelper::vectorize(microVeh->getSpeed(), microVeh->getAngle());
     150              :                     }, mask);
     151      7951389 :                     of.writeFuncAttr(SUMO_ATTR_ACCEL_VEC, [ = ]() {
     152          844 :                         return GeomHelper::vectorize(microVeh->getAcceleration(), microVeh->getAngle());
     153              :                     }, mask);
     154              :                 }
     155      8026250 :                 of.writeFuncAttr(SUMO_ATTR_DISTANCE, [ = ]() {
     156         2134 :                     double lanePos = veh->getPositionOnLane();
     157         2134 :                     if (!MSGlobals::gUseMesoSim && microVeh->getLane()->isInternal()) {
     158            4 :                         lanePos = microVeh->getRoute().getDistanceBetween(0., lanePos, microVeh->getEdge()->getLanes()[0], microVeh->getLane(),
     159            2 :                                   microVeh->getRoutePosition());
     160              :                     }
     161         2134 :                     return veh->getEdge()->getDistanceAt(lanePos);
     162              :                 }, mask);
     163      8026250 :                 of.writeFuncAttr(SUMO_ATTR_ODOMETER, [ = ]() {
     164          806 :                     return veh->getOdometer();
     165              :                 }, mask);
     166      8026250 :                 of.writeFuncAttr(SUMO_ATTR_POSITION_LAT, [ = ]() {
     167        63149 :                     return veh->getLateralPositionOnLane();
     168              :                 }, mask);
     169      8026250 :                 if (!MSGlobals::gUseMesoSim) {
     170      7951389 :                     of.writeFuncAttr(SUMO_ATTR_SPEED_LAT, [ = ]() {
     171        30477 :                         return microVeh->getLaneChangeModel().getSpeedLat();
     172              :                     }, mask);
     173              :                 }
     174      8026250 :                 if (maxLeaderDistance >= 0 && !MSGlobals::gUseMesoSim) {
     175        19203 :                     const std::pair<const MSVehicle* const, double> leader = microVeh->getLeader(maxLeaderDistance);
     176        19203 :                     if (leader.first != nullptr) {
     177        13988 :                         of.writeFuncAttr(SUMO_ATTR_LEADER_ID, [ = ]() {
     178        13388 :                             return leader.first->getID();
     179              :                         }, mask);
     180        13988 :                         of.writeFuncAttr(SUMO_ATTR_LEADER_SPEED, [ = ]() {
     181        13388 :                             return leader.first->getSpeed();
     182              :                         }, mask);
     183        13988 :                         of.writeFuncAttr(SUMO_ATTR_LEADER_GAP, [ = ]() {
     184        13988 :                             return leader.second + microVeh->getVehicleType().getMinGap();
     185              :                         }, mask);
     186              :                     } else {
     187         5215 :                         of.writeFuncAttr(SUMO_ATTR_LEADER_ID, [ = ]() {
     188              :                             return "";
     189              :                         }, mask);
     190         5215 :                         of.writeFuncAttr(SUMO_ATTR_LEADER_SPEED, [ = ]() {
     191              :                             return -1;
     192              :                         }, mask);
     193         5215 :                         of.writeFuncAttr(SUMO_ATTR_LEADER_GAP, [ = ]() {
     194              :                             return -1;
     195              :                         }, mask);
     196              :                     }
     197              :                 }
     198      8045263 :                 for (const std::string& key : params) {
     199              :                     std::string error;
     200        19013 :                     const std::string value = static_cast<const MSBaseVehicle*>(veh)->getPrefixedParameter(key, error);
     201        19013 :                     if (value != "") {
     202        28404 :                         of.writeAttr(StringUtils::escapeXML(key), StringUtils::escapeXML(value));
     203              :                     }
     204              :                 }
     205      8026250 :                 of.writeFuncAttr(SUMO_ATTR_ARRIVALDELAY, [ = ]() {
     206         5288 :                     const double arrivalDelay = static_cast<const MSBaseVehicle*>(veh)->getStopArrivalDelay();
     207         5288 :                     if (arrivalDelay == INVALID_DOUBLE) {
     208              :                         // no upcoming stop also means that there is no delay
     209         2388 :                         return 0.;
     210              :                     }
     211              :                     return arrivalDelay;
     212              :                 }, mask);
     213      8026250 :                 of.writeFuncAttr(SUMO_ATTR_DELAY, [ = ]() {
     214          806 :                     const double delay = static_cast<const MSBaseVehicle*>(veh)->getStopDelay();
     215          806 :                     if (delay < 0) {
     216              :                         // no upcoming stop also means that there is no delay
     217          656 :                         return 0.;
     218              :                     }
     219              :                     return delay;
     220              :                 }, mask);
     221      8026250 :                 if (MSGlobals::gUseMesoSim) {
     222              :                     const MEVehicle* mesoVeh = static_cast<const MEVehicle*>(veh);
     223        74861 :                     of.writeFuncAttr(SUMO_ATTR_SEGMENT, [ = ]() {
     224         5732 :                         return mesoVeh->getSegmentIndex();
     225              :                     }, mask);
     226        74861 :                     of.writeFuncAttr(SUMO_ATTR_QUEUE, [ = ]() {
     227         5732 :                         return mesoVeh->getQueIndex();
     228              :                     }, mask);
     229        74861 :                     of.writeFuncAttr(SUMO_ATTR_ENTRYTIME, [ = ]() {
     230         5732 :                         return mesoVeh->getLastEntryTimeSeconds();
     231              :                     }, mask);
     232        74861 :                     of.writeFuncAttr(SUMO_ATTR_EVENTTIME, [ = ]() {
     233         5732 :                         return mesoVeh->getEventTimeSeconds();
     234              :                     }, mask);
     235        74861 :                     of.writeFuncAttr(SUMO_ATTR_BLOCKTIME, [ = ]() {
     236         5732 :                         return mesoVeh->getBlockTime() == SUMOTime_MAX ? -1.0 : mesoVeh->getBlockTimeSeconds();
     237              :                     }, mask);
     238              :                 }
     239      8026250 :                 of.writeFuncAttr(SUMO_ATTR_TAG, [ = ]() {
     240           30 :                     return toString(SUMO_TAG_VEHICLE);
     241              :                 }, mask);
     242      8026250 :                 of.writeOptionalAttr(SUMO_ATTR_PERSON_NUMBER, veh->getPersonNumber(), mask);
     243      8026250 :                 of.writeOptionalAttr(SUMO_ATTR_CONTAINER_NUMBER, veh->getContainerNumber(), mask);
     244      8026250 :                 MSEmissionExport::writeEmissions(of, static_cast<const MSBaseVehicle*>(veh), false, mask);
     245     16052500 :                 of.closeTag();
     246              :             }
     247              :             // write persons and containers in the vehicle
     248      8603201 :             if (tag == SUMO_TAG_NOTHING || tag == SUMO_TAG_PERSON) {
     249      8603177 :                 const MSEdge* edge = MSGlobals::gUseMesoSim ? veh->getEdge() : &veh->getLane()->getEdge();
     250      8647462 :                 for (const MSTransportable* const person : veh->getPersons()) {
     251        44285 :                     if (hasOwnOutput(person, filter, shapeFilter, inRadius.count(person) > 0)) {
     252        43619 :                         openTimestep();
     253        43619 :                         writeTransportable(of, edge, person, veh, SUMO_TAG_PERSON, useGeo, mask);
     254              :                     }
     255              :                 }
     256      8606727 :                 for (const MSTransportable* const container : veh->getContainers()) {
     257         3550 :                     if (hasOwnOutput(container, filter, shapeFilter, inRadius.count(container) > 0)) {
     258         3246 :                         openTimestep();
     259         3246 :                         writeTransportable(of, edge, container, veh, SUMO_TAG_CONTAINER, useGeo, mask);
     260              :                     }
     261              :                 }
     262              :             }
     263              :         }
     264              :     }
     265      6633909 :     if (tag == SUMO_TAG_NOTHING || tag == SUMO_TAG_PERSON) {
     266      6633885 :         if (net->hasPersons() && net->getPersonControl().hasTransportables()) {
     267              :             // write persons who are not in a vehicle
     268    111532894 :             for (const MSEdge* const e : net->getEdgeControl().getEdges()) {
     269    109575450 :                 if (filter && MSDevice_FCD::getEdgeFilter().count(e) == 0) {
     270          108 :                     continue;
     271              :                 }
     272    111690838 :                 for (const MSTransportable* const person : e->getSortedPersons(timestep)) {
     273      2115496 :                     if (hasOwnOutput(person, filter, shapeFilter, inRadius.count(person) > 0)) {
     274      2114754 :                         openTimestep();
     275      2114754 :                         writeTransportable(of, e, person, nullptr, SUMO_TAG_PERSON, useGeo, mask);
     276              :                     }
     277    109575342 :                 }
     278              :             }
     279              :         }
     280      6633885 :         if (net->hasContainers() && net->getContainerControl().hasTransportables()) {
     281              :             // write containers which are not in a vehicle
     282     57638993 :             for (const MSEdge* const e : net->getEdgeControl().getEdges()) {
     283     53820680 :                 if (filter && MSDevice_FCD::getEdgeFilter().count(e) == 0) {
     284            0 :                     continue;
     285              :                 }
     286     53824431 :                 for (MSTransportable* container : e->getSortedContainers(timestep)) {
     287         3751 :                     if (hasOwnOutput(container, filter, shapeFilter, inRadius.count(container) > 0)) {
     288         3647 :                         openTimestep();
     289         3647 :                         writeTransportable(of, e, container, nullptr, SUMO_TAG_CONTAINER, useGeo, mask);
     290              :                     }
     291     53820680 :                 }
     292              :             }
     293              :         }
     294              :     }
     295      6633909 :     if (wroteTimestep) {
     296     13265594 :         of.closeTag();
     297              :     }
     298              : }
     299              : 
     300              : 
     301              : bool
     302     10469255 : MSFCDExport::isVisible(const SUMOVehicle* veh) {
     303     10469255 :     return veh->isOnRoad() || veh->isParking() || veh->isRemoteControlled();
     304              : }
     305              : 
     306              : 
     307              : bool
     308      8605885 : MSFCDExport::hasOwnOutput(const SUMOVehicle* veh, bool filter, bool shapeFilter, bool isInRadius) {
     309           54 :     return ((!filter || MSDevice_FCD::getEdgeFilter().count(veh->getEdge()) > 0)
     310      8605861 :             && (!shapeFilter || MSDevice_FCD::shapeFilter(veh))
     311     17207374 :             && ((veh->getDevice(typeid(MSDevice_FCD)) != nullptr) || isInRadius));
     312              : }
     313              : 
     314              : 
     315              : bool
     316      2167082 : MSFCDExport::hasOwnOutput(const MSTransportable* p, bool filter, bool shapeFilter, bool isInRadius) {
     317           54 :     return ((!filter || MSDevice_FCD::getEdgeFilter().count(p->getEdge()) > 0)
     318      2167054 :             && (!shapeFilter || MSDevice_FCD::shapeFilter(p))
     319      4334136 :             && ((p->getDevice(typeid(MSTransportableDevice_FCD)) != nullptr) || isInRadius));
     320              : }
     321              : 
     322              : 
     323              : void
     324      2165266 : MSFCDExport::writeTransportable(OutputDevice& of, const MSEdge* const e, const MSTransportable* const p, const SUMOVehicle* const v,
     325              :                                 const SumoXMLTag tag, const bool useGeo, const SumoXMLAttrMask mask) {
     326      2165266 :     Position pos = p->getPosition();
     327      2165266 :     if (useGeo) {
     328            0 :         of.setPrecision(gPrecisionGeo);
     329            0 :         GeoConvHelper::getFinal().cartesian2geo(pos);
     330              :     }
     331      2165266 :     of.openTag(tag);
     332      2165266 :     of.writeAttr(SUMO_ATTR_ID, p->getID());
     333      2165266 :     of.writeOptionalAttr(SUMO_ATTR_X, pos.x(), mask);
     334      2165266 :     of.writeOptionalAttr(SUMO_ATTR_Y, pos.y(), mask);
     335      2165266 :     of.setPrecision(gPrecision);
     336      2165266 :     of.writeOptionalAttr(SUMO_ATTR_Z, pos.z(), mask);
     337      2165266 :     of.writeOptionalAttr(SUMO_ATTR_ANGLE, GeomHelper::naviDegree(p->getAngle()), mask);
     338      2165266 :     of.writeOptionalAttr(SUMO_ATTR_TYPE, p->getVehicleType().getID(), mask);
     339      2165266 :     of.writeOptionalAttr(SUMO_ATTR_SPEED, p->getSpeed(), mask);
     340      2165266 :     of.writeOptionalAttr(SUMO_ATTR_SPEEDREL, e->getSpeedLimit() > 0 ? p->getSpeed() / e->getSpeedLimit() : 0., mask);
     341      2165266 :     of.writeOptionalAttr(SUMO_ATTR_POSITION, p->getEdgePos(), mask);
     342      2165266 :     of.writeOptionalAttr(SUMO_ATTR_LANE, "", mask, true);
     343      2165266 :     of.writeOptionalAttr(SUMO_ATTR_EDGE, e->getID(), mask);
     344      2165266 :     of.writeOptionalAttr(SUMO_ATTR_SLOPE, e->getLanes()[0]->getShape().slopeDegreeAtOffset(p->getEdgePos()), mask);
     345      4377397 :     of.writeOptionalAttr(SUMO_ATTR_VEHICLE, v == nullptr ? "" : v->getID(), mask);
     346      2165266 :     of.writeOptionalAttr(SUMO_ATTR_STAGE, p->getCurrentStageDescription(), mask);
     347      2165266 :     of.writeOptionalAttr(SUMO_ATTR_TAG, toString(tag), mask);
     348      2165266 :     of.closeTag();
     349      2165266 : }
     350              : 
     351              : 
     352              : /****************************************************************************/
        

Generated by: LCOV version 2.0-1