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 "MSFCDExport.h"
44 :
45 :
46 : // ===========================================================================
47 : // method definitions
48 : // ===========================================================================
49 : void
50 737908 : MSFCDExport::write(OutputDevice& of, SUMOTime timestep, bool elevation) {
51 737908 : const OptionsCont& oc = OptionsCont::getOptions();
52 1475816 : const SUMOTime period = string2time(oc.getString("device.fcd.period"));
53 1475816 : const SUMOTime begin = string2time(oc.getString("device.fcd.begin"));
54 737908 : if ((period > 0 && (timestep - begin) % period != 0) || timestep < begin) {
55 14108 : return;
56 : }
57 : const SumoXMLAttrMask mask = MSDevice_FCD::getWrittenAttributes();
58 723800 : const bool maskSet = oc.isSet("fcd-output.attributes");
59 723800 : const bool useGeo = oc.getBool("fcd-output.geo");
60 809211 : const bool signals = oc.getBool("fcd-output.signals") || (maskSet && of.useAttribute(SUMO_ATTR_SIGNALS, mask));
61 808381 : const bool writeAccel = oc.getBool("fcd-output.acceleration") || (maskSet && of.useAttribute(SUMO_ATTR_ACCELERATION, mask));
62 809379 : const bool writeDistance = oc.getBool("fcd-output.distance") || (maskSet && of.useAttribute(SUMO_ATTR_DISTANCE, mask));
63 723800 : const double maxLeaderDistance = oc.getFloat("fcd-output.max-leader-distance");
64 723800 : std::vector<std::string> params = oc.getStringVector("fcd-output.params");
65 723800 : MSNet* net = MSNet::getInstance();
66 : MSVehicleControl& vc = net->getVehicleControl();
67 1447600 : const double radius = oc.getFloat("device.fcd.radius");
68 723800 : const bool filter = MSDevice_FCD::getEdgeFilter().size() > 0;
69 : const bool shapeFilter = MSDevice_FCD::hasShapeFilter();
70 : std::set<const Named*> inRadius;
71 723800 : if (radius > 0) {
72 : // collect all vehicles in radius around equipped vehicles
73 4152 : for (MSVehicleControl::constVehIt it = vc.loadedVehBegin(); it != vc.loadedVehEnd(); ++it) {
74 2738 : const SUMOVehicle* veh = it->second;
75 2738 : if (isVisible(veh) && hasOwnOutput(veh, filter, shapeFilter)) {
76 1342 : PositionVector shape;
77 1342 : shape.push_back(veh->getPosition());
78 1342 : libsumo::Helper::collectObjectsInRange(libsumo::CMD_GET_VEHICLE_VARIABLE, shape, radius, inRadius);
79 1342 : libsumo::Helper::collectObjectsInRange(libsumo::CMD_GET_PERSON_VARIABLE, shape, radius, inRadius);
80 1342 : }
81 : }
82 : }
83 :
84 1447600 : of.openTag("timestep").writeAttr(SUMO_ATTR_TIME, time2string(timestep));
85 3084535 : for (MSVehicleControl::constVehIt it = vc.loadedVehBegin(); it != vc.loadedVehEnd(); ++it) {
86 2360735 : const SUMOVehicle* veh = it->second;
87 2360735 : const MSVehicle* microVeh = dynamic_cast<const MSVehicle*>(veh);
88 2360735 : const MSBaseVehicle* baseVeh = dynamic_cast<const MSBaseVehicle*>(veh);
89 2360735 : if (isVisible(veh)) {
90 1528479 : const bool hasOutput = hasOwnOutput(veh, filter, shapeFilter, (radius > 0 && inRadius.count(veh) > 0));
91 1525771 : if (hasOutput) {
92 963455 : Position pos = veh->getPosition();
93 963455 : if (useGeo) {
94 2696 : of.setPrecision(gPrecisionGeo);
95 2696 : GeoConvHelper::getFinal().cartesian2geo(pos);
96 : }
97 963455 : of.openTag(SUMO_TAG_VEHICLE);
98 : of.writeAttr(SUMO_ATTR_ID, veh->getID());
99 963455 : of.writeOptionalAttr(SUMO_ATTR_X, pos.x(), mask);
100 963455 : of.writeOptionalAttr(SUMO_ATTR_Y, pos.y(), mask);
101 963455 : of.setPrecision(gPrecision);
102 963455 : if (elevation) {
103 62077 : of.writeOptionalAttr(SUMO_ATTR_Z, pos.z(), mask);
104 : }
105 963455 : of.writeOptionalAttr(SUMO_ATTR_ANGLE, GeomHelper::naviDegree(veh->getAngle()), mask);
106 963455 : of.writeOptionalAttr(SUMO_ATTR_TYPE, veh->getVehicleType().getID(), mask);
107 963455 : of.writeOptionalAttr(SUMO_ATTR_SPEED, veh->getSpeed(), mask);
108 963455 : of.writeOptionalAttr(SUMO_ATTR_POSITION, veh->getPositionOnLane(), mask);
109 963455 : if (microVeh != nullptr) {
110 914041 : of.writeOptionalAttr(SUMO_ATTR_LANE, microVeh->getLane()->getID(), mask);
111 : } else {
112 49414 : of.writeOptionalAttr(SUMO_ATTR_EDGE, veh->getEdge()->getID(), mask);
113 : }
114 963455 : of.writeOptionalAttr(SUMO_ATTR_SLOPE, veh->getSlope(), mask);
115 963455 : if (microVeh != nullptr) {
116 914041 : if (signals) {
117 28864 : of.writeOptionalAttr(SUMO_ATTR_SIGNALS, toString(microVeh->getSignals()), mask);
118 : }
119 914041 : if (writeAccel) {
120 139303 : of.writeOptionalAttr(SUMO_ATTR_ACCELERATION, toString(microVeh->getAcceleration()), mask);
121 139303 : if (MSGlobals::gSublane) {
122 43154 : of.writeOptionalAttr(SUMO_ATTR_ACCELERATION_LAT, microVeh->getLaneChangeModel().getAccelerationLat(), mask);
123 : }
124 : }
125 : }
126 963455 : if (writeDistance) {
127 2134 : double lanePos = veh->getPositionOnLane();
128 2134 : if (microVeh != nullptr && microVeh->getLane()->isInternal()) {
129 4 : lanePos = microVeh->getRoute().getDistanceBetween(0., lanePos, microVeh->getEdge()->getLanes()[0], microVeh->getLane(),
130 2 : microVeh->getRoutePosition());
131 : }
132 2134 : of.writeOptionalAttr(SUMO_ATTR_DISTANCE, veh->getEdge()->getDistanceAt(lanePos), mask);
133 : }
134 963455 : of.writeOptionalAttr(SUMO_ATTR_ODOMETER, veh->getOdometer(), mask);
135 963455 : of.writeOptionalAttr(SUMO_ATTR_POSITION_LAT, veh->getLateralPositionOnLane(), mask);
136 963455 : if (microVeh != nullptr) {
137 914041 : of.writeOptionalAttr(SUMO_ATTR_SPEED_LAT, microVeh->getLaneChangeModel().getSpeedLat(), mask);
138 : }
139 963455 : if (maxLeaderDistance >= 0 && microVeh != nullptr) {
140 25434 : std::pair<const MSVehicle* const, double> leader = microVeh->getLeader(maxLeaderDistance);
141 25434 : if (leader.first != nullptr) {
142 18650 : of.writeOptionalAttr(SUMO_ATTR_LEADER_ID, toString(leader.first->getID()), mask);
143 18650 : of.writeOptionalAttr(SUMO_ATTR_LEADER_SPEED, toString(leader.first->getSpeed()), mask);
144 37300 : of.writeOptionalAttr(SUMO_ATTR_LEADER_GAP, toString(leader.second + microVeh->getVehicleType().getMinGap()), mask);
145 : } else {
146 6784 : of.writeOptionalAttr(SUMO_ATTR_LEADER_ID, "", mask);
147 6784 : of.writeOptionalAttr(SUMO_ATTR_LEADER_SPEED, -1, mask);
148 6784 : of.writeOptionalAttr(SUMO_ATTR_LEADER_GAP, -1, mask);
149 : }
150 : }
151 974700 : for (const std::string& key : params) {
152 : std::string error;
153 11245 : const std::string value = baseVeh->getPrefixedParameter(key, error);
154 11245 : if (value != "") {
155 12876 : of.writeAttr(StringUtils::escapeXML(key), StringUtils::escapeXML(value));
156 : }
157 : }
158 963455 : if (of.useAttribute(SUMO_ATTR_ARRIVALDELAY, mask)) {
159 5258 : double arrivalDelay = baseVeh->getStopArrivalDelay();
160 5258 : if (arrivalDelay == INVALID_DOUBLE) {
161 : // no upcoming stop also means that there is no delay
162 2378 : arrivalDelay = 0;
163 : }
164 5258 : of.writeOptionalAttr(SUMO_ATTR_ARRIVALDELAY, arrivalDelay, mask);
165 : }
166 1926910 : of.closeTag();
167 : }
168 : // write persons and containers
169 1525771 : const MSEdge* edge = microVeh == nullptr ? veh->getEdge() : &veh->getLane()->getEdge();
170 :
171 1525771 : const std::vector<MSTransportable*>& persons = veh->getPersons();
172 1567004 : for (MSTransportable* person : persons) {
173 82466 : writeTransportable(of, edge, person, veh, filter, shapeFilter, inRadius.count(person) > 0, SUMO_TAG_PERSON, useGeo, elevation, mask);
174 : }
175 1525771 : const std::vector<MSTransportable*>& containers = veh->getContainers();
176 1528341 : for (MSTransportable* container : containers) {
177 5140 : writeTransportable(of, edge, container, veh, filter, shapeFilter, inRadius.count(container) > 0, SUMO_TAG_CONTAINER, useGeo, elevation, mask);
178 : }
179 : }
180 : }
181 723800 : if (net->hasPersons() && net->getPersonControl().hasTransportables()) {
182 : // write persons
183 : MSEdgeControl& ec = net->getEdgeControl();
184 : const MSEdgeVector& edges = ec.getEdges();
185 2045880 : for (MSEdgeVector::const_iterator e = edges.begin(); e != edges.end(); ++e) {
186 1999204 : if (filter && MSDevice_FCD::getEdgeFilter().count(*e) == 0) {
187 104 : continue;
188 : }
189 1999100 : const std::vector<MSTransportable*>& persons = (*e)->getSortedPersons(timestep);
190 2201374 : for (MSTransportable* person : persons) {
191 404548 : writeTransportable(of, *e, person, nullptr, filter, shapeFilter, inRadius.count(person) > 0, SUMO_TAG_PERSON, useGeo, elevation, mask);
192 : }
193 : }
194 : }
195 723800 : if (net->hasContainers() && net->getContainerControl().hasTransportables()) {
196 : // write containers
197 : MSEdgeControl& ec = net->getEdgeControl();
198 : const std::vector<MSEdge*>& edges = ec.getEdges();
199 30800 : for (std::vector<MSEdge*>::const_iterator e = edges.begin(); e != edges.end(); ++e) {
200 28000 : if (filter && MSDevice_FCD::getEdgeFilter().count(*e) == 0) {
201 0 : continue;
202 : }
203 28000 : const std::vector<MSTransportable*>& containers = (*e)->getSortedContainers(timestep);
204 31416 : for (MSTransportable* container : containers) {
205 6832 : writeTransportable(of, *e, container, nullptr, filter, shapeFilter, inRadius.count(container) > 0, SUMO_TAG_CONTAINER, useGeo, elevation, mask);
206 : }
207 : }
208 : }
209 1447600 : of.closeTag();
210 723800 : }
211 :
212 : bool
213 2363473 : MSFCDExport::isVisible(const SUMOVehicle* veh) {
214 2363473 : return veh->isOnRoad() || veh->isParking() || veh->isRemoteControlled();
215 : }
216 :
217 : bool
218 1528479 : MSFCDExport::hasOwnOutput(const SUMOVehicle* veh, bool filter, bool shapeFilter, bool isInRadius) {
219 52 : return ((!filter || MSDevice_FCD::getEdgeFilter().count(veh->getEdge()) > 0)
220 1528455 : && (!shapeFilter || MSDevice_FCD::shapeFilter(veh))
221 3054748 : && ((veh->getDevice(typeid(MSDevice_FCD)) != nullptr) || isInRadius));
222 : }
223 :
224 : bool
225 249493 : MSFCDExport::hasOwnOutput(const MSTransportable* p, bool filter, bool shapeFilter, bool isInRadius) {
226 52 : return ((!filter || MSDevice_FCD::getEdgeFilter().count(p->getEdge()) > 0)
227 249465 : && (!shapeFilter || MSDevice_FCD::shapeFilter(p))
228 498958 : && ((p->getDevice(typeid(MSTransportableDevice_FCD)) != nullptr) || isInRadius));
229 : }
230 :
231 : void
232 249493 : MSFCDExport::writeTransportable(OutputDevice& of, const MSEdge* e, MSTransportable* p, const SUMOVehicle* v,
233 : bool filter, bool shapeFilter, bool inRadius,
234 : SumoXMLTag tag, bool useGeo, bool elevation, SumoXMLAttrMask mask) {
235 249493 : if (!hasOwnOutput(p, filter, shapeFilter, inRadius)) {
236 128 : return;
237 : }
238 249365 : Position pos = p->getPosition();
239 249365 : if (useGeo) {
240 0 : of.setPrecision(gPrecisionGeo);
241 0 : GeoConvHelper::getFinal().cartesian2geo(pos);
242 : }
243 249365 : of.openTag(tag);
244 : of.writeAttr(SUMO_ATTR_ID, p->getID());
245 249365 : of.writeOptionalAttr(SUMO_ATTR_X, pos.x(), mask);
246 249365 : of.writeOptionalAttr(SUMO_ATTR_Y, pos.y(), mask);
247 249365 : if (elevation) {
248 0 : of.writeOptionalAttr(SUMO_ATTR_Z, pos.z(), mask);
249 : }
250 249365 : of.writeOptionalAttr(SUMO_ATTR_ANGLE, GeomHelper::naviDegree(p->getAngle()), mask);
251 249365 : of.writeOptionalAttr(SUMO_ATTR_SPEED, p->getSpeed(), mask);
252 249365 : of.writeOptionalAttr(SUMO_ATTR_POSITION, p->getEdgePos(), mask);
253 249365 : of.writeOptionalAttr(SUMO_ATTR_EDGE, e->getID(), mask);
254 249365 : of.writeOptionalAttr(SUMO_ATTR_SLOPE, e->getLanes()[0]->getShape().slopeDegreeAtOffset(p->getEdgePos()), mask);
255 293124 : of.writeOptionalAttr(SUMO_ATTR_VEHICLE, v == nullptr ? "" : v->getID(), mask);
256 498730 : of.closeTag();
257 : }
258 :
259 :
260 : /****************************************************************************/
|