LCOV - code coverage report
Current view: top level - src/microsim/output - MSFCDExport.cpp (source / functions) Coverage Total Hit
Test: lcov.info Lines: 98.3 % 173 170
Test Date: 2026-04-16 16:39:47 Functions: 100.0 % 13 13

            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      5044583 : MSFCDExport::write(OutputDevice& of, const SUMOTime timestep, const SumoXMLTag tag) {
      53      5044583 :     MSDevice_FCD::initOnce();
      54              :     const SUMOTime period = MSDevice_FCD::getPeriod();
      55              :     const SUMOTime begin = MSDevice_FCD::getBegin();
      56      5044583 :     if ((period > 0 && (timestep - begin) % period != 0) || timestep < begin) {
      57        57702 :         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      4986881 :     MSNet* net = MSNet::getInstance();
      65              :     MSVehicleControl& vc = net->getVehicleControl();
      66              :     const double radius = MSDevice_FCD::getRadius();
      67      4986881 :     const bool filter = MSDevice_FCD::getEdgeFilter().size() > 0;
      68              :     const bool shapeFilter = MSDevice_FCD::hasShapeFilter();
      69              :     std::set<const Named*> inRadius;
      70      4986881 :     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      9973762 :     of.openTag("timestep").writeTime(SUMO_ATTR_TIME, timestep);
      84     13781445 :     for (MSVehicleControl::constVehIt it = vc.loadedVehBegin(); it != vc.loadedVehEnd(); ++it) {
      85      8794564 :         const SUMOVehicle* const veh = it->second;
      86      8794564 :         if (isVisible(veh)) {
      87     13863168 :             const bool hasOutput = (tag == SUMO_TAG_NOTHING || tag == SUMO_TAG_VEHICLE) && hasOwnOutput(veh, filter, shapeFilter, (radius > 0 && inRadius.count(veh) > 0));
      88              :             if (hasOutput) {
      89      6354731 :                 const MSVehicle* const microVeh = MSGlobals::gUseMesoSim ? nullptr : static_cast<const MSVehicle*>(veh);
      90      6354731 :                 Position pos = veh->getPosition();
      91      6354731 :                 if (useGeo) {
      92         2696 :                     of.setPrecision(gPrecisionGeo);
      93         2696 :                     GeoConvHelper::getFinal().cartesian2geo(pos);
      94      6352035 :                 } else if (useUTM) {
      95           90 :                     pos.sub(GeoConvHelper::getFinal().getOffset());
      96              :                 }
      97      6354731 :                 of.openTag(SUMO_TAG_VEHICLE);
      98      6354731 :                 of.writeAttr(SUMO_ATTR_ID, veh->getID());
      99      6354731 :                 of.writeOptionalAttr(SUMO_ATTR_X, pos.x(), mask);
     100      6354731 :                 of.writeOptionalAttr(SUMO_ATTR_Y, pos.y(), mask);
     101      6354731 :                 of.setPrecision(gPrecision);
     102      6354731 :                 of.writeOptionalAttr(SUMO_ATTR_Z, pos.z(), mask);
     103      6354731 :                 of.writeFuncAttr(SUMO_ATTR_ANGLE, [ = ]() {
     104      3837882 :                     return GeomHelper::naviDegree(veh->getAngle());
     105              :                 }, mask);
     106      6354731 :                 of.writeFuncAttr(SUMO_ATTR_TYPE, [ = ]() {
     107      5977034 :                     return veh->getVehicleType().getID();
     108              :                 }, mask);
     109      6354731 :                 of.writeFuncAttr(SUMO_ATTR_SPEED, [ = ]() {
     110      4102609 :                     return veh->getSpeed();
     111              :                 }, mask);
     112      6354731 :                 of.writeFuncAttr(SUMO_ATTR_SPEEDREL, [ = ]() {
     113          776 :                     const double speedLimit = veh->getEdge()->getSpeedLimit();
     114          776 :                     return speedLimit > 0 ? veh->getSpeed() / speedLimit : 0.;
     115              :                 }, mask);
     116      6354731 :                 of.writeFuncAttr(SUMO_ATTR_POSITION, [ = ]() {
     117      3971639 :                     return veh->getPositionOnLane();
     118              :                 }, mask);
     119      6354731 :                 of.writeFuncAttr(SUMO_ATTR_LANE, [ = ]() {
     120      3934524 :                     return MSGlobals::gUseMesoSim ? "" : microVeh->getLane()->getID();
     121              :                 }, mask, MSGlobals::gUseMesoSim);
     122     12780023 :                 of.writeFuncAttr(SUMO_ATTR_EDGE, [ = ]() {
     123        70561 :                     return veh->getCurrentEdge()->getID();
     124      6354731 :                 }, mask, !MSGlobals::gUseMesoSim);
     125      6354731 :                 of.writeFuncAttr(SUMO_ATTR_SLOPE, [ = ]() {
     126      3835220 :                     return veh->getSlope();
     127              :                 }, mask);
     128      6354731 :                 if (!MSGlobals::gUseMesoSim) {
     129      6280472 :                     of.writeFuncAttr(SUMO_ATTR_SIGNALS, [ = ]() {
     130        14762 :                         return microVeh->getSignals();
     131              :                     }, mask);
     132      6280472 :                     of.writeFuncAttr(SUMO_ATTR_ACCELERATION, [ = ]() {
     133       152144 :                         return microVeh->getAcceleration();
     134              :                     }, mask);
     135      6280472 :                     of.writeFuncAttr(SUMO_ATTR_ACCELERATION_LAT, [ = ]() {
     136        55365 :                         return microVeh->getLaneChangeModel().getAccelerationLat();
     137              :                     }, mask);
     138      6280472 :                     of.writeFuncAttr(SUMO_ATTR_SPEED_VEC, [ = ]() {
     139          844 :                         return GeomHelper::vectorize(microVeh->getSpeed(), microVeh->getAngle());
     140              :                     }, mask);
     141      6280472 :                     of.writeFuncAttr(SUMO_ATTR_ACCEL_VEC, [ = ]() {
     142          844 :                         return GeomHelper::vectorize(microVeh->getAcceleration(), microVeh->getAngle());
     143              :                     }, mask);
     144              :                 }
     145      6354731 :                 of.writeFuncAttr(SUMO_ATTR_DISTANCE, [ = ]() {
     146         2134 :                     double lanePos = veh->getPositionOnLane();
     147         2134 :                     if (!MSGlobals::gUseMesoSim && microVeh->getLane()->isInternal()) {
     148            4 :                         lanePos = microVeh->getRoute().getDistanceBetween(0., lanePos, microVeh->getEdge()->getLanes()[0], microVeh->getLane(),
     149            2 :                                   microVeh->getRoutePosition());
     150              :                     }
     151         2134 :                     return veh->getEdge()->getDistanceAt(lanePos);
     152              :                 }, mask);
     153      6354731 :                 of.writeFuncAttr(SUMO_ATTR_ODOMETER, [ = ]() {
     154          806 :                     return veh->getOdometer();
     155              :                 }, mask);
     156      6354731 :                 of.writeFuncAttr(SUMO_ATTR_POSITION_LAT, [ = ]() {
     157        63149 :                     return veh->getLateralPositionOnLane();
     158              :                 }, mask);
     159      6354731 :                 if (!MSGlobals::gUseMesoSim) {
     160      6280472 :                     of.writeFuncAttr(SUMO_ATTR_SPEED_LAT, [ = ]() {
     161        30477 :                         return microVeh->getLaneChangeModel().getSpeedLat();
     162              :                     }, mask);
     163              :                 }
     164      6354731 :                 if (maxLeaderDistance >= 0 && !MSGlobals::gUseMesoSim) {
     165        18071 :                     const std::pair<const MSVehicle* const, double> leader = microVeh->getLeader(maxLeaderDistance);
     166        18071 :                     if (leader.first != nullptr) {
     167        13157 :                         of.writeFuncAttr(SUMO_ATTR_LEADER_ID, [ = ]() {
     168        12557 :                             return leader.first->getID();
     169              :                         }, mask);
     170        13157 :                         of.writeFuncAttr(SUMO_ATTR_LEADER_SPEED, [ = ]() {
     171        12557 :                             return leader.first->getSpeed();
     172              :                         }, mask);
     173        13157 :                         of.writeFuncAttr(SUMO_ATTR_LEADER_GAP, [ = ]() {
     174        13157 :                             return leader.second + microVeh->getVehicleType().getMinGap();
     175              :                         }, mask);
     176              :                     } else {
     177         4914 :                         of.writeFuncAttr(SUMO_ATTR_LEADER_ID, [ = ]() {
     178              :                             return "";
     179              :                         }, mask);
     180         4914 :                         of.writeFuncAttr(SUMO_ATTR_LEADER_SPEED, [ = ]() {
     181              :                             return -1;
     182              :                         }, mask);
     183         4914 :                         of.writeFuncAttr(SUMO_ATTR_LEADER_GAP, [ = ]() {
     184              :                             return -1;
     185              :                         }, mask);
     186              :                     }
     187              :                 }
     188      6373880 :                 for (const std::string& key : params) {
     189              :                     std::string error;
     190        19149 :                     const std::string value = static_cast<const MSBaseVehicle*>(veh)->getPrefixedParameter(key, error);
     191        19149 :                     if (value != "") {
     192        28676 :                         of.writeAttr(StringUtils::escapeXML(key), StringUtils::escapeXML(value));
     193              :                     }
     194              :                 }
     195      6354731 :                 of.writeFuncAttr(SUMO_ATTR_ARRIVALDELAY, [ = ]() {
     196         5288 :                     const double arrivalDelay = static_cast<const MSBaseVehicle*>(veh)->getStopArrivalDelay();
     197         5288 :                     if (arrivalDelay == INVALID_DOUBLE) {
     198              :                         // no upcoming stop also means that there is no delay
     199         2388 :                         return 0.;
     200              :                     }
     201              :                     return arrivalDelay;
     202              :                 }, mask);
     203      6354731 :                 of.writeFuncAttr(SUMO_ATTR_DELAY, [ = ]() {
     204          806 :                     const double delay = static_cast<const MSBaseVehicle*>(veh)->getStopDelay();
     205          806 :                     if (delay < 0) {
     206              :                         // no upcoming stop also means that there is no delay
     207          656 :                         return 0.;
     208              :                     }
     209              :                     return delay;
     210              :                 }, mask);
     211      6354731 :                 if (MSGlobals::gUseMesoSim) {
     212              :                     const MEVehicle* mesoVeh = static_cast<const MEVehicle*>(veh);
     213        74259 :                     of.writeFuncAttr(SUMO_ATTR_SEGMENT, [ = ]() {
     214         5732 :                         return mesoVeh->getSegmentIndex();
     215              :                     }, mask);
     216        74259 :                     of.writeFuncAttr(SUMO_ATTR_QUEUE, [ = ]() {
     217         5732 :                         return mesoVeh->getQueIndex();
     218              :                     }, mask);
     219        74259 :                     of.writeFuncAttr(SUMO_ATTR_ENTRYTIME, [ = ]() {
     220         5732 :                         return mesoVeh->getLastEntryTimeSeconds();
     221              :                     }, mask);
     222        74259 :                     of.writeFuncAttr(SUMO_ATTR_EVENTTIME, [ = ]() {
     223         5732 :                         return mesoVeh->getEventTimeSeconds();
     224              :                     }, mask);
     225        74259 :                     of.writeFuncAttr(SUMO_ATTR_BLOCKTIME, [ = ]() {
     226         5732 :                         return mesoVeh->getBlockTime() == SUMOTime_MAX ? -1.0 : mesoVeh->getBlockTimeSeconds();
     227              :                     }, mask);
     228              :                 }
     229      6354731 :                 of.writeFuncAttr(SUMO_ATTR_TAG, [ = ]() {
     230           30 :                     return toString(SUMO_TAG_VEHICLE);
     231              :                 }, mask);
     232      6354731 :                 of.writeOptionalAttr(SUMO_ATTR_PERSON_NUMBER, veh->getPersonNumber(), mask);
     233      6354731 :                 of.writeOptionalAttr(SUMO_ATTR_CONTAINER_NUMBER, veh->getContainerNumber(), mask);
     234      6354731 :                 MSEmissionExport::writeEmissions(of, static_cast<const MSBaseVehicle*>(veh), false, mask);
     235     12709462 :                 of.closeTag();
     236              :             }
     237              :             // write persons and containers in the vehicle
     238      6931596 :             if (tag == SUMO_TAG_NOTHING || tag == SUMO_TAG_PERSON) {
     239      6931572 :                 const MSEdge* edge = MSGlobals::gUseMesoSim ? veh->getEdge() : &veh->getLane()->getEdge();
     240      6974682 :                 for (const MSTransportable* const person : veh->getPersons()) {
     241        86220 :                     writeTransportable(of, edge, person, veh, filter, shapeFilter, inRadius.count(person) > 0, SUMO_TAG_PERSON, useGeo, mask);
     242              :                 }
     243      6935122 :                 for (const MSTransportable* const container : veh->getContainers()) {
     244         7100 :                     writeTransportable(of, edge, container, veh, filter, shapeFilter, inRadius.count(container) > 0, SUMO_TAG_CONTAINER, useGeo, mask);
     245              :                 }
     246              :             }
     247              :         }
     248              :     }
     249      4986881 :     if (tag == SUMO_TAG_NOTHING || tag == SUMO_TAG_PERSON) {
     250      4986857 :         if (net->hasPersons() && net->getPersonControl().hasTransportables()) {
     251              :             // write persons who are not in a vehicle
     252    113059080 :             for (const MSEdge* const e : net->getEdgeControl().getEdges()) {
     253    111074858 :                 if (filter && MSDevice_FCD::getEdgeFilter().count(e) == 0) {
     254          108 :                     continue;
     255              :                 }
     256    113199369 :                 for (const MSTransportable* const person : e->getSortedPersons(timestep)) {
     257      4249238 :                     writeTransportable(of, e, person, nullptr, filter, shapeFilter, inRadius.count(person) > 0, SUMO_TAG_PERSON, useGeo, mask);
     258    111074750 :                 }
     259              :             }
     260              :         }
     261      4986857 :         if (net->hasContainers() && net->getContainerControl().hasTransportables()) {
     262              :             // write containers which are not in a vehicle
     263     32543213 :             for (const MSEdge* const e : net->getEdgeControl().getEdges()) {
     264     30397952 :                 if (filter && MSDevice_FCD::getEdgeFilter().count(e) == 0) {
     265            0 :                     continue;
     266              :                 }
     267     30401703 :                 for (MSTransportable* container : e->getSortedContainers(timestep)) {
     268         7502 :                     writeTransportable(of, e, container, nullptr, filter, shapeFilter, inRadius.count(container) > 0, SUMO_TAG_CONTAINER, useGeo, mask);
     269     30397952 :                 }
     270              :             }
     271              :         }
     272              :     }
     273      9973762 :     of.closeTag();
     274              : }
     275              : 
     276              : 
     277              : bool
     278      8797302 : MSFCDExport::isVisible(const SUMOVehicle* veh) {
     279      8797302 :     return veh->isOnRoad() || veh->isParking() || veh->isRemoteControlled();
     280              : }
     281              : 
     282              : 
     283              : bool
     284      6934280 : MSFCDExport::hasOwnOutput(const SUMOVehicle* veh, bool filter, bool shapeFilter, bool isInRadius) {
     285           54 :     return ((!filter || MSDevice_FCD::getEdgeFilter().count(veh->getEdge()) > 0)
     286      6934256 :             && (!shapeFilter || MSDevice_FCD::shapeFilter(veh))
     287     13866350 :             && ((veh->getDevice(typeid(MSDevice_FCD)) != nullptr) || isInRadius));
     288              : }
     289              : 
     290              : 
     291              : bool
     292      2175030 : MSFCDExport::hasOwnOutput(const MSTransportable* p, bool filter, bool shapeFilter, bool isInRadius) {
     293           54 :     return ((!filter || MSDevice_FCD::getEdgeFilter().count(p->getEdge()) > 0)
     294      2175002 :             && (!shapeFilter || MSDevice_FCD::shapeFilter(p))
     295      4350032 :             && ((p->getDevice(typeid(MSTransportableDevice_FCD)) != nullptr) || isInRadius));
     296              : }
     297              : 
     298              : 
     299              : void
     300      2175030 : MSFCDExport::writeTransportable(OutputDevice& of, const MSEdge* const e, const MSTransportable* const p, const SUMOVehicle* const v,
     301              :                                 const bool filter, const bool shapeFilter, const bool inRadius,
     302              :                                 const SumoXMLTag tag, const bool useGeo, const SumoXMLAttrMask mask) {
     303      2175030 :     if (!hasOwnOutput(p, filter, shapeFilter, inRadius)) {
     304         1816 :         return;
     305              :     }
     306      2173214 :     Position pos = p->getPosition();
     307      2173214 :     if (useGeo) {
     308            0 :         of.setPrecision(gPrecisionGeo);
     309            0 :         GeoConvHelper::getFinal().cartesian2geo(pos);
     310              :     }
     311      2173214 :     of.openTag(tag);
     312      2173214 :     of.writeAttr(SUMO_ATTR_ID, p->getID());
     313      2173214 :     of.writeOptionalAttr(SUMO_ATTR_X, pos.x(), mask);
     314      2173214 :     of.writeOptionalAttr(SUMO_ATTR_Y, pos.y(), mask);
     315      2173214 :     of.setPrecision(gPrecision);
     316      2173214 :     of.writeOptionalAttr(SUMO_ATTR_Z, pos.z(), mask);
     317      2173214 :     of.writeOptionalAttr(SUMO_ATTR_ANGLE, GeomHelper::naviDegree(p->getAngle()), mask);
     318      2173214 :     of.writeOptionalAttr(SUMO_ATTR_TYPE, p->getVehicleType().getID(), mask);
     319      2173214 :     of.writeOptionalAttr(SUMO_ATTR_SPEED, p->getSpeed(), mask);
     320      2173214 :     of.writeOptionalAttr(SUMO_ATTR_SPEEDREL, e->getSpeedLimit() > 0 ? p->getSpeed() / e->getSpeedLimit() : 0., mask);
     321      2173214 :     of.writeOptionalAttr(SUMO_ATTR_POSITION, p->getEdgePos(), mask);
     322      2173214 :     of.writeOptionalAttr(SUMO_ATTR_LANE, "", mask, true);
     323      2173214 :     of.writeOptionalAttr(SUMO_ATTR_EDGE, e->getID(), mask);
     324      2173214 :     of.writeOptionalAttr(SUMO_ATTR_SLOPE, e->getLanes()[0]->getShape().slopeDegreeAtOffset(p->getEdgePos()), mask);
     325      4392118 :     of.writeOptionalAttr(SUMO_ATTR_VEHICLE, v == nullptr ? "" : v->getID(), mask);
     326      2173214 :     of.writeOptionalAttr(SUMO_ATTR_STAGE, p->getCurrentStageDescription(), mask);
     327      2173214 :     of.writeOptionalAttr(SUMO_ATTR_TAG, toString(tag), mask);
     328      4346428 :     of.closeTag();
     329              : }
     330              : 
     331              : 
     332              : /****************************************************************************/
        

Generated by: LCOV version 2.0-1