Line data Source code
1 : /****************************************************************************/
2 : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3 : // Copyright (C) 2012-2024 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 "MSFCDExport.h"
45 :
46 :
47 : // ===========================================================================
48 : // method definitions
49 : // ===========================================================================
50 : void
51 769585 : MSFCDExport::write(OutputDevice& of, SUMOTime timestep, bool elevation) {
52 769585 : const OptionsCont& oc = OptionsCont::getOptions();
53 769585 : const SUMOTime period = string2time(oc.getString("device.fcd.period"));
54 769585 : const SUMOTime begin = string2time(oc.getString("device.fcd.begin"));
55 769585 : if ((period > 0 && (timestep - begin) % period != 0) || timestep < begin) {
56 56260 : return;
57 : }
58 : const SumoXMLAttrMask mask = MSDevice_FCD::getWrittenAttributes();
59 713325 : const bool maskSet = oc.isSet("fcd-output.attributes");
60 713325 : const bool useGeo = oc.getBool("fcd-output.geo");
61 799604 : const bool signals = oc.getBool("fcd-output.signals") || (maskSet && of.useAttribute(SUMO_ATTR_SIGNALS, mask));
62 798774 : const bool writeAccel = oc.getBool("fcd-output.acceleration") || (maskSet && of.useAttribute(SUMO_ATTR_ACCELERATION, mask));
63 799772 : const bool writeDistance = oc.getBool("fcd-output.distance") || (maskSet && of.useAttribute(SUMO_ATTR_DISTANCE, mask));
64 713325 : const double maxLeaderDistance = oc.getFloat("fcd-output.max-leader-distance");
65 713325 : std::vector<std::string> params = oc.getStringVector("fcd-output.params");
66 713325 : MSNet* net = MSNet::getInstance();
67 : MSVehicleControl& vc = net->getVehicleControl();
68 1426650 : const double radius = oc.getFloat("device.fcd.radius");
69 713325 : const bool filter = MSDevice_FCD::getEdgeFilter().size() > 0;
70 : const bool shapeFilter = MSDevice_FCD::hasShapeFilter();
71 : std::set<const Named*> inRadius;
72 713325 : if (radius > 0) {
73 : // collect all vehicles in radius around equipped vehicles
74 4152 : for (MSVehicleControl::constVehIt it = vc.loadedVehBegin(); it != vc.loadedVehEnd(); ++it) {
75 2738 : const SUMOVehicle* veh = it->second;
76 2738 : if (isVisible(veh) && hasOwnOutput(veh, filter, shapeFilter)) {
77 1342 : PositionVector shape;
78 1342 : shape.push_back(veh->getPosition());
79 1342 : libsumo::Helper::collectObjectsInRange(libsumo::CMD_GET_VEHICLE_VARIABLE, shape, radius, inRadius);
80 1342 : libsumo::Helper::collectObjectsInRange(libsumo::CMD_GET_PERSON_VARIABLE, shape, radius, inRadius);
81 1342 : }
82 : }
83 : }
84 :
85 1426650 : of.openTag("timestep").writeAttr(SUMO_ATTR_TIME, time2string(timestep));
86 3069577 : for (MSVehicleControl::constVehIt it = vc.loadedVehBegin(); it != vc.loadedVehEnd(); ++it) {
87 2356252 : const SUMOVehicle* veh = it->second;
88 2356252 : const MSVehicle* microVeh = dynamic_cast<const MSVehicle*>(veh);
89 2356252 : const MSBaseVehicle* baseVeh = dynamic_cast<const MSBaseVehicle*>(veh);
90 2356252 : if (isVisible(veh)) {
91 3043272 : const bool hasOutput = hasOwnOutput(veh, filter, shapeFilter, (radius > 0 && inRadius.count(veh) > 0));
92 1521636 : if (hasOutput) {
93 955610 : Position pos = veh->getPosition();
94 955610 : if (useGeo) {
95 2696 : of.setPrecision(gPrecisionGeo);
96 2696 : GeoConvHelper::getFinal().cartesian2geo(pos);
97 : }
98 955610 : of.openTag(SUMO_TAG_VEHICLE);
99 : of.writeAttr(SUMO_ATTR_ID, veh->getID());
100 955610 : of.writeOptionalAttr(SUMO_ATTR_X, pos.x(), mask);
101 955610 : of.writeOptionalAttr(SUMO_ATTR_Y, pos.y(), mask);
102 955610 : of.setPrecision(gPrecision);
103 955610 : if (elevation) {
104 62507 : of.writeOptionalAttr(SUMO_ATTR_Z, pos.z(), mask);
105 : }
106 955610 : of.writeOptionalAttr(SUMO_ATTR_ANGLE, GeomHelper::naviDegree(veh->getAngle()), mask);
107 955610 : of.writeOptionalAttr(SUMO_ATTR_TYPE, veh->getVehicleType().getID(), mask);
108 955610 : of.writeOptionalAttr(SUMO_ATTR_SPEED, veh->getSpeed(), mask);
109 955610 : of.writeOptionalAttr(SUMO_ATTR_POSITION, veh->getPositionOnLane(), mask);
110 955610 : if (microVeh != nullptr) {
111 899770 : of.writeOptionalAttr(SUMO_ATTR_LANE, microVeh->getLane()->getID(), mask);
112 : } else {
113 55840 : of.writeOptionalAttr(SUMO_ATTR_EDGE, veh->getEdge()->getID(), mask);
114 : }
115 955610 : of.writeOptionalAttr(SUMO_ATTR_SLOPE, veh->getSlope(), mask);
116 955610 : if (microVeh != nullptr) {
117 899770 : if (signals) {
118 29614 : of.writeOptionalAttr(SUMO_ATTR_SIGNALS, toString(microVeh->getSignals()), mask);
119 : }
120 899770 : if (writeAccel) {
121 137902 : of.writeOptionalAttr(SUMO_ATTR_ACCELERATION, toString(microVeh->getAcceleration()), mask);
122 137902 : if (MSGlobals::gSublane) {
123 43201 : of.writeOptionalAttr(SUMO_ATTR_ACCELERATION_LAT, microVeh->getLaneChangeModel().getAccelerationLat(), mask);
124 : }
125 : }
126 : }
127 955610 : if (writeDistance) {
128 2134 : double lanePos = veh->getPositionOnLane();
129 2134 : if (microVeh != nullptr && microVeh->getLane()->isInternal()) {
130 4 : lanePos = microVeh->getRoute().getDistanceBetween(0., lanePos, microVeh->getEdge()->getLanes()[0], microVeh->getLane(),
131 2 : microVeh->getRoutePosition());
132 : }
133 2134 : of.writeOptionalAttr(SUMO_ATTR_DISTANCE, veh->getEdge()->getDistanceAt(lanePos), mask);
134 : }
135 955610 : of.writeOptionalAttr(SUMO_ATTR_ODOMETER, veh->getOdometer(), mask);
136 955610 : of.writeOptionalAttr(SUMO_ATTR_POSITION_LAT, veh->getLateralPositionOnLane(), mask);
137 955610 : if (microVeh != nullptr) {
138 899770 : of.writeOptionalAttr(SUMO_ATTR_SPEED_LAT, microVeh->getLaneChangeModel().getSpeedLat(), mask);
139 : }
140 955610 : if (maxLeaderDistance >= 0 && microVeh != nullptr) {
141 19203 : std::pair<const MSVehicle* const, double> leader = microVeh->getLeader(maxLeaderDistance);
142 19203 : if (leader.first != nullptr) {
143 13988 : of.writeOptionalAttr(SUMO_ATTR_LEADER_ID, toString(leader.first->getID()), mask);
144 13988 : of.writeOptionalAttr(SUMO_ATTR_LEADER_SPEED, toString(leader.first->getSpeed()), mask);
145 27976 : of.writeOptionalAttr(SUMO_ATTR_LEADER_GAP, toString(leader.second + microVeh->getVehicleType().getMinGap()), mask);
146 : } else {
147 5215 : of.writeOptionalAttr(SUMO_ATTR_LEADER_ID, "", mask);
148 5215 : of.writeOptionalAttr(SUMO_ATTR_LEADER_SPEED, -1, mask);
149 5215 : of.writeOptionalAttr(SUMO_ATTR_LEADER_GAP, -1, mask);
150 : }
151 : }
152 974749 : for (const std::string& key : params) {
153 : std::string error;
154 19139 : const std::string value = baseVeh->getPrefixedParameter(key, error);
155 19139 : if (value != "") {
156 28656 : of.writeAttr(StringUtils::escapeXML(key), StringUtils::escapeXML(value));
157 : }
158 : }
159 955610 : if (of.useAttribute(SUMO_ATTR_ARRIVALDELAY, mask)) {
160 5258 : double arrivalDelay = baseVeh->getStopArrivalDelay();
161 5258 : if (arrivalDelay == INVALID_DOUBLE) {
162 : // no upcoming stop also means that there is no delay
163 2378 : arrivalDelay = 0;
164 : }
165 5258 : of.writeOptionalAttr(SUMO_ATTR_ARRIVALDELAY, arrivalDelay, mask);
166 : }
167 955610 : if (MSGlobals::gUseMesoSim) {
168 55840 : const MEVehicle* mesoVeh = dynamic_cast<const MEVehicle*>(veh);
169 55840 : of.writeOptionalAttr(SUMO_ATTR_SEGMENT, mesoVeh->getSegmentIndex(), mask);
170 55840 : of.writeOptionalAttr(SUMO_ATTR_QUEUE, mesoVeh->getQueIndex(), mask);
171 55840 : of.writeOptionalAttr(SUMO_ATTR_ENTRYTIME, mesoVeh->getLastEntryTimeSeconds(), mask);
172 55840 : of.writeOptionalAttr(SUMO_ATTR_EVENTTIME, mesoVeh->getEventTimeSeconds(), mask);
173 58564 : of.writeOptionalAttr(SUMO_ATTR_BLOCKTIME, mesoVeh->getBlockTime() == SUMOTime_MAX ? -1.0 : mesoVeh->getBlockTimeSeconds(), mask);
174 : }
175 1911220 : of.closeTag();
176 : }
177 : // write persons and containers
178 1521636 : const MSEdge* edge = microVeh == nullptr ? veh->getEdge() : &veh->getLane()->getEdge();
179 :
180 1521636 : const std::vector<MSTransportable*>& persons = veh->getPersons();
181 1566273 : for (MSTransportable* person : persons) {
182 89274 : writeTransportable(of, edge, person, veh, filter, shapeFilter, inRadius.count(person) > 0, SUMO_TAG_PERSON, useGeo, elevation, mask);
183 : }
184 1521636 : const std::vector<MSTransportable*>& containers = veh->getContainers();
185 1524206 : for (MSTransportable* container : containers) {
186 5140 : writeTransportable(of, edge, container, veh, filter, shapeFilter, inRadius.count(container) > 0, SUMO_TAG_CONTAINER, useGeo, elevation, mask);
187 : }
188 : }
189 : }
190 713325 : if (net->hasPersons() && net->getPersonControl().hasTransportables()) {
191 : // write persons
192 : MSEdgeControl& ec = net->getEdgeControl();
193 : const MSEdgeVector& edges = ec.getEdges();
194 2225058 : for (MSEdgeVector::const_iterator e = edges.begin(); e != edges.end(); ++e) {
195 2178037 : if (filter && MSDevice_FCD::getEdgeFilter().count(*e) == 0) {
196 104 : continue;
197 : }
198 2177933 : const std::vector<MSTransportable*>& persons = (*e)->getSortedPersons(timestep);
199 2377198 : for (MSTransportable* person : persons) {
200 398530 : writeTransportable(of, *e, person, nullptr, filter, shapeFilter, inRadius.count(person) > 0, SUMO_TAG_PERSON, useGeo, elevation, mask);
201 : }
202 2177933 : }
203 : }
204 713325 : if (net->hasContainers() && net->getContainerControl().hasTransportables()) {
205 : // write containers
206 : MSEdgeControl& ec = net->getEdgeControl();
207 : const std::vector<MSEdge*>& edges = ec.getEdges();
208 30800 : for (std::vector<MSEdge*>::const_iterator e = edges.begin(); e != edges.end(); ++e) {
209 28000 : if (filter && MSDevice_FCD::getEdgeFilter().count(*e) == 0) {
210 0 : continue;
211 : }
212 28000 : const std::vector<MSTransportable*>& containers = (*e)->getSortedContainers(timestep);
213 31416 : for (MSTransportable* container : containers) {
214 6832 : writeTransportable(of, *e, container, nullptr, filter, shapeFilter, inRadius.count(container) > 0, SUMO_TAG_CONTAINER, useGeo, elevation, mask);
215 : }
216 28000 : }
217 : }
218 1426650 : of.closeTag();
219 713325 : }
220 :
221 : bool
222 2358990 : MSFCDExport::isVisible(const SUMOVehicle* veh) {
223 2358990 : return veh->isOnRoad() || veh->isParking() || veh->isRemoteControlled();
224 : }
225 :
226 : bool
227 1524344 : MSFCDExport::hasOwnOutput(const SUMOVehicle* veh, bool filter, bool shapeFilter, bool isInRadius) {
228 52 : return ((!filter || MSDevice_FCD::getEdgeFilter().count(veh->getEdge()) > 0)
229 1524320 : && (!shapeFilter || MSDevice_FCD::shapeFilter(veh))
230 3046478 : && ((veh->getDevice(typeid(MSDevice_FCD)) != nullptr) || isInRadius));
231 : }
232 :
233 : bool
234 249888 : MSFCDExport::hasOwnOutput(const MSTransportable* p, bool filter, bool shapeFilter, bool isInRadius) {
235 52 : return ((!filter || MSDevice_FCD::getEdgeFilter().count(p->getEdge()) > 0)
236 249860 : && (!shapeFilter || MSDevice_FCD::shapeFilter(p))
237 499748 : && ((p->getDevice(typeid(MSTransportableDevice_FCD)) != nullptr) || isInRadius));
238 : }
239 :
240 : void
241 249888 : MSFCDExport::writeTransportable(OutputDevice& of, const MSEdge* e, MSTransportable* p, const SUMOVehicle* v,
242 : bool filter, bool shapeFilter, bool inRadius,
243 : SumoXMLTag tag, bool useGeo, bool elevation, SumoXMLAttrMask mask) {
244 249888 : if (!hasOwnOutput(p, filter, shapeFilter, inRadius)) {
245 1134 : return;
246 : }
247 248754 : Position pos = p->getPosition();
248 248754 : if (useGeo) {
249 0 : of.setPrecision(gPrecisionGeo);
250 0 : GeoConvHelper::getFinal().cartesian2geo(pos);
251 : }
252 248754 : of.openTag(tag);
253 : of.writeAttr(SUMO_ATTR_ID, p->getID());
254 248754 : of.writeOptionalAttr(SUMO_ATTR_X, pos.x(), mask);
255 248754 : of.writeOptionalAttr(SUMO_ATTR_Y, pos.y(), mask);
256 248754 : if (elevation) {
257 0 : of.writeOptionalAttr(SUMO_ATTR_Z, pos.z(), mask);
258 : }
259 248754 : of.writeOptionalAttr(SUMO_ATTR_ANGLE, GeomHelper::naviDegree(p->getAngle()), mask);
260 248754 : of.writeOptionalAttr(SUMO_ATTR_SPEED, p->getSpeed(), mask);
261 248754 : of.writeOptionalAttr(SUMO_ATTR_POSITION, p->getEdgePos(), mask);
262 248754 : of.writeOptionalAttr(SUMO_ATTR_EDGE, e->getID(), mask);
263 248754 : of.writeOptionalAttr(SUMO_ATTR_SLOPE, e->getLanes()[0]->getShape().slopeDegreeAtOffset(p->getEdgePos()), mask);
264 295399 : of.writeOptionalAttr(SUMO_ATTR_VEHICLE, v == nullptr ? "" : v->getID(), mask);
265 248754 : of.writeOptionalAttr(SUMO_ATTR_TYPE, p->getVehicleType().getID(), mask);
266 497508 : of.closeTag();
267 : }
268 :
269 :
270 : /****************************************************************************/
|