LCOV - code coverage report
Current view: top level - src/microsim/output - MSFCDExport.cpp (source / functions) Coverage Total Hit
Test: lcov.info Lines: 98.2 % 163 160
Test Date: 2026-03-26 16:31:35 Functions: 100.0 % 10 10

            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      3895061 : MSFCDExport::write(OutputDevice& of, const SUMOTime timestep, const SumoXMLTag tag) {
      53      3895061 :     MSDevice_FCD::initOnce();
      54              :     const SUMOTime period = MSDevice_FCD::getPeriod();
      55              :     const SUMOTime begin = MSDevice_FCD::getBegin();
      56      3895061 :     if ((period > 0 && (timestep - begin) % period != 0) || timestep < begin) {
      57        57700 :         return;
      58              :     }
      59              :     const SumoXMLAttrMask& mask = MSDevice_FCD::getWrittenAttributes();
      60              :     const bool useGeo = MSDevice_FCD::useGeo();
      61              :     const double maxLeaderDistance = MSDevice_FCD::getMaxLeaderDistance();
      62              :     const std::vector<std::string>& params = MSDevice_FCD::getParamsToWrite();
      63      3837361 :     MSNet* net = MSNet::getInstance();
      64              :     MSVehicleControl& vc = net->getVehicleControl();
      65              :     const double radius = MSDevice_FCD::getRadius();
      66      3837361 :     const bool filter = MSDevice_FCD::getEdgeFilter().size() > 0;
      67              :     const bool shapeFilter = MSDevice_FCD::hasShapeFilter();
      68              :     std::set<const Named*> inRadius;
      69      3837361 :     if (radius > 0) {
      70              :         // collect all vehicles in radius around equipped vehicles
      71         4152 :         for (MSVehicleControl::constVehIt it = vc.loadedVehBegin(); it != vc.loadedVehEnd(); ++it) {
      72         2738 :             const SUMOVehicle* veh = it->second;
      73         2738 :             if (isVisible(veh) && hasOwnOutput(veh, filter, shapeFilter)) {
      74         1342 :                 PositionVector shape;
      75         1342 :                 shape.push_back(veh->getPosition());
      76         1342 :                 libsumo::Helper::collectObjectsInRange(libsumo::CMD_GET_VEHICLE_VARIABLE, shape, radius, inRadius);
      77         1342 :                 libsumo::Helper::collectObjectsInRange(libsumo::CMD_GET_PERSON_VARIABLE, shape, radius, inRadius);
      78         1342 :             }
      79              :         }
      80              :     }
      81              : 
      82      7674722 :     of.openTag("timestep").writeTime(SUMO_ATTR_TIME, timestep);
      83     13398906 :     for (MSVehicleControl::constVehIt it = vc.loadedVehBegin(); it != vc.loadedVehEnd(); ++it) {
      84      9561545 :         const SUMOVehicle* const veh = it->second;
      85      9561545 :         if (isVisible(veh)) {
      86     17433912 :             const bool hasOutput = (tag == SUMO_TAG_NOTHING || tag == SUMO_TAG_VEHICLE) && hasOwnOutput(veh, filter, shapeFilter, (radius > 0 && inRadius.count(veh) > 0));
      87              :             if (hasOutput) {
      88      8142175 :                 const MSVehicle* const microVeh = MSGlobals::gUseMesoSim ? nullptr : static_cast<const MSVehicle*>(veh);
      89      8142175 :                 Position pos = veh->getPosition();
      90      8142175 :                 if (useGeo) {
      91         2696 :                     of.setPrecision(gPrecisionGeo);
      92         2696 :                     GeoConvHelper::getFinal().cartesian2geo(pos);
      93              :                 }
      94      8142175 :                 of.openTag(SUMO_TAG_VEHICLE);
      95      8142175 :                 of.writeAttr(SUMO_ATTR_ID, veh->getID());
      96      8142175 :                 of.writeOptionalAttr(SUMO_ATTR_X, pos.x(), mask);
      97      8142175 :                 of.writeOptionalAttr(SUMO_ATTR_Y, pos.y(), mask);
      98      8142175 :                 of.setPrecision(gPrecision);
      99      8142175 :                 of.writeOptionalAttr(SUMO_ATTR_Z, pos.z(), mask);
     100      8142175 :                 of.writeFuncAttr(SUMO_ATTR_ANGLE, [ = ]() {
     101      4855742 :                     return GeomHelper::naviDegree(veh->getAngle());
     102              :                 }, mask);
     103      8142175 :                 of.writeFuncAttr(SUMO_ATTR_TYPE, [ = ]() {
     104      7764844 :                     return veh->getVehicleType().getID();
     105              :                 }, mask);
     106      8142175 :                 of.writeFuncAttr(SUMO_ATTR_SPEED, [ = ]() {
     107      5120301 :                     return veh->getSpeed();
     108              :                 }, mask);
     109      8142175 :                 of.writeFuncAttr(SUMO_ATTR_POSITION, [ = ]() {
     110      4989433 :                     return veh->getPositionOnLane();
     111              :                 }, mask);
     112      8142175 :                 of.writeFuncAttr(SUMO_ATTR_LANE, [ = ]() {
     113      4952704 :                     return MSGlobals::gUseMesoSim ? "" : microVeh->getLane()->getID();
     114              :                 }, mask, MSGlobals::gUseMesoSim);
     115     16354459 :                 of.writeFuncAttr(SUMO_ATTR_EDGE, [ = ]() {
     116        70109 :                     return veh->getEdge()->getID();
     117      8142175 :                 }, mask, !MSGlobals::gUseMesoSim);
     118      8142175 :                 of.writeFuncAttr(SUMO_ATTR_SLOPE, [ = ]() {
     119      4853088 :                     return veh->getSlope();
     120              :                 }, mask);
     121      8142175 :                 if (!MSGlobals::gUseMesoSim) {
     122      8068514 :                     of.writeFuncAttr(SUMO_ATTR_SIGNALS, [ = ]() {
     123        14762 :                         return microVeh->getSignals();
     124              :                     }, mask);
     125      8068514 :                     of.writeFuncAttr(SUMO_ATTR_ACCELERATION, [ = ]() {
     126       152031 :                         return microVeh->getAcceleration();
     127              :                     }, mask);
     128      8068514 :                     of.writeFuncAttr(SUMO_ATTR_ACCELERATION_LAT, [ = ]() {
     129        55365 :                         return microVeh->getLaneChangeModel().getAccelerationLat();
     130              :                     }, mask);
     131              :                 }
     132      8142175 :                 of.writeFuncAttr(SUMO_ATTR_DISTANCE, [ = ]() {
     133         2134 :                     double lanePos = veh->getPositionOnLane();
     134         2134 :                     if (!MSGlobals::gUseMesoSim && microVeh->getLane()->isInternal()) {
     135            4 :                         lanePos = microVeh->getRoute().getDistanceBetween(0., lanePos, microVeh->getEdge()->getLanes()[0], microVeh->getLane(),
     136            2 :                                   microVeh->getRoutePosition());
     137              :                     }
     138         2134 :                     return veh->getEdge()->getDistanceAt(lanePos);
     139              :                 }, mask);
     140      8142175 :                 of.writeFuncAttr(SUMO_ATTR_ODOMETER, [ = ]() {
     141          806 :                     return veh->getOdometer();
     142              :                 }, mask);
     143      8142175 :                 of.writeFuncAttr(SUMO_ATTR_POSITION_LAT, [ = ]() {
     144        63149 :                     return veh->getLateralPositionOnLane();
     145              :                 }, mask);
     146      8142175 :                 if (!MSGlobals::gUseMesoSim) {
     147      8068514 :                     of.writeFuncAttr(SUMO_ATTR_SPEED_LAT, [ = ]() {
     148        30477 :                         return microVeh->getLaneChangeModel().getSpeedLat();
     149              :                     }, mask);
     150              :                 }
     151      8142175 :                 if (maxLeaderDistance >= 0 && !MSGlobals::gUseMesoSim) {
     152        18071 :                     const std::pair<const MSVehicle* const, double> leader = microVeh->getLeader(maxLeaderDistance);
     153        18071 :                     if (leader.first != nullptr) {
     154        13157 :                         of.writeFuncAttr(SUMO_ATTR_LEADER_ID, [ = ]() {
     155        12557 :                             return leader.first->getID();
     156              :                         }, mask);
     157        13157 :                         of.writeFuncAttr(SUMO_ATTR_LEADER_SPEED, [ = ]() {
     158        12557 :                             return leader.first->getSpeed();
     159              :                         }, mask);
     160        13157 :                         of.writeFuncAttr(SUMO_ATTR_LEADER_GAP, [ = ]() {
     161        13157 :                             return leader.second + microVeh->getVehicleType().getMinGap();
     162              :                         }, mask);
     163              :                     } else {
     164         4914 :                         of.writeFuncAttr(SUMO_ATTR_LEADER_ID, [ = ]() {
     165              :                             return "";
     166              :                         }, mask);
     167         4914 :                         of.writeFuncAttr(SUMO_ATTR_LEADER_SPEED, [ = ]() {
     168              :                             return -1;
     169              :                         }, mask);
     170         4914 :                         of.writeFuncAttr(SUMO_ATTR_LEADER_GAP, [ = ]() {
     171              :                             return -1;
     172              :                         }, mask);
     173              :                     }
     174              :                 }
     175      8161314 :                 for (const std::string& key : params) {
     176              :                     std::string error;
     177        19139 :                     const std::string value = static_cast<const MSBaseVehicle*>(veh)->getPrefixedParameter(key, error);
     178        19139 :                     if (value != "") {
     179        28656 :                         of.writeAttr(StringUtils::escapeXML(key), StringUtils::escapeXML(value));
     180              :                     }
     181              :                 }
     182      8142175 :                 of.writeFuncAttr(SUMO_ATTR_ARRIVALDELAY, [ = ]() {
     183         5288 :                     const double arrivalDelay = static_cast<const MSBaseVehicle*>(veh)->getStopArrivalDelay();
     184         5288 :                     if (arrivalDelay == INVALID_DOUBLE) {
     185              :                         // no upcoming stop also means that there is no delay
     186         2388 :                         return 0.;
     187              :                     }
     188              :                     return arrivalDelay;
     189              :                 }, mask);
     190      8142175 :                 of.writeFuncAttr(SUMO_ATTR_DELAY, [ = ]() {
     191          806 :                     const double delay = static_cast<const MSBaseVehicle*>(veh)->getStopDelay();
     192          806 :                     if (delay < 0) {
     193              :                         // no upcoming stop also means that there is no delay
     194          656 :                         return 0.;
     195              :                     }
     196              :                     return delay;
     197              :                 }, mask);
     198      8142175 :                 if (MSGlobals::gUseMesoSim) {
     199              :                     const MEVehicle* mesoVeh = static_cast<const MEVehicle*>(veh);
     200        73661 :                     of.writeFuncAttr(SUMO_ATTR_SEGMENT, [ = ]() {
     201         5732 :                         return mesoVeh->getSegmentIndex();
     202              :                     }, mask);
     203        73661 :                     of.writeFuncAttr(SUMO_ATTR_QUEUE, [ = ]() {
     204         5732 :                         return mesoVeh->getQueIndex();
     205              :                     }, mask);
     206        73661 :                     of.writeFuncAttr(SUMO_ATTR_ENTRYTIME, [ = ]() {
     207         5732 :                         return mesoVeh->getLastEntryTimeSeconds();
     208              :                     }, mask);
     209        73661 :                     of.writeFuncAttr(SUMO_ATTR_EVENTTIME, [ = ]() {
     210         5732 :                         return mesoVeh->getEventTimeSeconds();
     211              :                     }, mask);
     212        73661 :                     of.writeFuncAttr(SUMO_ATTR_BLOCKTIME, [ = ]() {
     213         5732 :                         return mesoVeh->getBlockTime() == SUMOTime_MAX ? -1.0 : mesoVeh->getBlockTimeSeconds();
     214              :                     }, mask);
     215              :                 }
     216      8142175 :                 of.writeFuncAttr(SUMO_ATTR_TAG, [ = ]() {
     217           30 :                     return toString(SUMO_TAG_VEHICLE);
     218              :                 }, mask);
     219      8142175 :                 of.writeOptionalAttr(SUMO_ATTR_PERSON_NUMBER, veh->getPersonNumber(), mask);
     220      8142175 :                 of.writeOptionalAttr(SUMO_ATTR_CONTAINER_NUMBER, veh->getContainerNumber(), mask);
     221      8142175 :                 MSEmissionExport::writeEmissions(of, static_cast<const MSBaseVehicle*>(veh), false, mask);
     222     16284350 :                 of.closeTag();
     223              :             }
     224              :             // write persons and containers in the vehicle
     225      8716968 :             if (tag == SUMO_TAG_NOTHING || tag == SUMO_TAG_PERSON) {
     226      8716944 :                 const MSEdge* edge = MSGlobals::gUseMesoSim ? veh->getEdge() : &veh->getLane()->getEdge();
     227      8762091 :                 for (const MSTransportable* const person : veh->getPersons()) {
     228        90294 :                     writeTransportable(of, edge, person, veh, filter, shapeFilter, inRadius.count(person) > 0, SUMO_TAG_PERSON, useGeo, mask);
     229              :                 }
     230      8720492 :                 for (const MSTransportable* const container : veh->getContainers()) {
     231         7096 :                     writeTransportable(of, edge, container, veh, filter, shapeFilter, inRadius.count(container) > 0, SUMO_TAG_CONTAINER, useGeo, mask);
     232              :                 }
     233              :             }
     234              :         }
     235              :     }
     236      3837361 :     if (tag == SUMO_TAG_NOTHING || tag == SUMO_TAG_PERSON) {
     237      3837337 :         if (net->hasPersons() && net->getPersonControl().hasTransportables()) {
     238              :             // write persons who are not in a vehicle
     239      3585615 :             for (const MSEdge* const e : net->getEdgeControl().getEdges()) {
     240      3520222 :                 if (filter && MSDevice_FCD::getEdgeFilter().count(e) == 0) {
     241          104 :                     continue;
     242              :                 }
     243      3743850 :                 for (const MSTransportable* const person : e->getSortedPersons(timestep)) {
     244       447464 :                     writeTransportable(of, e, person, nullptr, filter, shapeFilter, inRadius.count(person) > 0, SUMO_TAG_PERSON, useGeo, mask);
     245      3520118 :                 }
     246              :             }
     247              :         }
     248      3837337 :         if (net->hasContainers() && net->getContainerControl().hasTransportables()) {
     249              :             // write containers which are not in a vehicle
     250     44091485 :             for (const MSEdge* const e : net->getEdgeControl().getEdges()) {
     251     41176284 :                 if (filter && MSDevice_FCD::getEdgeFilter().count(e) == 0) {
     252            0 :                     continue;
     253              :                 }
     254     41180035 :                 for (MSTransportable* container : e->getSortedContainers(timestep)) {
     255         7502 :                     writeTransportable(of, e, container, nullptr, filter, shapeFilter, inRadius.count(container) > 0, SUMO_TAG_CONTAINER, useGeo, mask);
     256     41176284 :                 }
     257              :             }
     258              :         }
     259              :     }
     260      7674722 :     of.closeTag();
     261              : }
     262              : 
     263              : 
     264              : bool
     265      9564283 : MSFCDExport::isVisible(const SUMOVehicle* veh) {
     266      9564283 :     return veh->isOnRoad() || veh->isParking() || veh->isRemoteControlled();
     267              : }
     268              : 
     269              : 
     270              : bool
     271      8719652 : MSFCDExport::hasOwnOutput(const SUMOVehicle* veh, bool filter, bool shapeFilter, bool isInRadius) {
     272           52 :     return ((!filter || MSDevice_FCD::getEdgeFilter().count(veh->getEdge()) > 0)
     273      8719628 :             && (!shapeFilter || MSDevice_FCD::shapeFilter(veh))
     274     17437094 :             && ((veh->getDevice(typeid(MSDevice_FCD)) != nullptr) || isInRadius));
     275              : }
     276              : 
     277              : 
     278              : bool
     279       276178 : MSFCDExport::hasOwnOutput(const MSTransportable* p, bool filter, bool shapeFilter, bool isInRadius) {
     280           52 :     return ((!filter || MSDevice_FCD::getEdgeFilter().count(p->getEdge()) > 0)
     281       276150 :             && (!shapeFilter || MSDevice_FCD::shapeFilter(p))
     282       552328 :             && ((p->getDevice(typeid(MSTransportableDevice_FCD)) != nullptr) || isInRadius));
     283              : }
     284              : 
     285              : 
     286              : void
     287       276178 : MSFCDExport::writeTransportable(OutputDevice& of, const MSEdge* const e, const MSTransportable* const p, const SUMOVehicle* const v,
     288              :                                 const bool filter, const bool shapeFilter, const bool inRadius,
     289              :                                 const SumoXMLTag tag, const bool useGeo, const SumoXMLAttrMask mask) {
     290       276178 :     if (!hasOwnOutput(p, filter, shapeFilter, inRadius)) {
     291         1812 :         return;
     292              :     }
     293       274366 :     Position pos = p->getPosition();
     294       274366 :     if (useGeo) {
     295            0 :         of.setPrecision(gPrecisionGeo);
     296            0 :         GeoConvHelper::getFinal().cartesian2geo(pos);
     297              :     }
     298       274366 :     of.openTag(tag);
     299       274366 :     of.writeAttr(SUMO_ATTR_ID, p->getID());
     300       274366 :     of.writeOptionalAttr(SUMO_ATTR_X, pos.x(), mask);
     301       274366 :     of.writeOptionalAttr(SUMO_ATTR_Y, pos.y(), mask);
     302       274366 :     of.setPrecision(gPrecision);
     303       274366 :     of.writeOptionalAttr(SUMO_ATTR_Z, pos.z(), mask);
     304       274366 :     of.writeOptionalAttr(SUMO_ATTR_ANGLE, GeomHelper::naviDegree(p->getAngle()), mask);
     305       274366 :     of.writeOptionalAttr(SUMO_ATTR_TYPE, p->getVehicleType().getID(), mask);
     306       274366 :     of.writeOptionalAttr(SUMO_ATTR_SPEED, p->getSpeed(), mask);
     307       274366 :     of.writeOptionalAttr(SUMO_ATTR_POSITION, p->getEdgePos(), mask);
     308       274366 :     of.writeOptionalAttr(SUMO_ATTR_LANE, "", mask, true);
     309       274366 :     of.writeOptionalAttr(SUMO_ATTR_EDGE, e->getID(), mask);
     310       274366 :     of.writeOptionalAttr(SUMO_ATTR_SLOPE, e->getLanes()[0]->getShape().slopeDegreeAtOffset(p->getEdgePos()), mask);
     311       596461 :     of.writeOptionalAttr(SUMO_ATTR_VEHICLE, v == nullptr ? "" : v->getID(), mask);
     312       274366 :     of.writeOptionalAttr(SUMO_ATTR_STAGE, p->getCurrentStageDescription(), mask);
     313       274366 :     of.writeOptionalAttr(SUMO_ATTR_TAG, toString(tag), mask);
     314       548732 :     of.closeTag();
     315              : }
     316              : 
     317              : 
     318              : /****************************************************************************/
        

Generated by: LCOV version 2.0-1