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 : /****************************************************************************/
|