Line data Source code
1 : /****************************************************************************/
2 : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3 : // Copyright (C) 2013-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 MSDevice_FCD.cpp
15 : /// @author Daniel Krajzewicz
16 : /// @author Michael Behrisch
17 : /// @author Jakob Erdmann
18 : /// @date 11.06.2013
19 : ///
20 : // A device which stands as an implementation FCD and which outputs movereminder calls
21 : /****************************************************************************/
22 : #include <config.h>
23 :
24 : #include <bitset>
25 : #include <utils/common/StringUtils.h>
26 : #include <utils/options/OptionsCont.h>
27 : #include <utils/iodevices/OutputDevice.h>
28 : #include <utils/vehicle/SUMOVehicle.h>
29 : #include <utils/shapes/ShapeContainer.h>
30 : #include <utils/shapes/SUMOPolygon.h>
31 : #include <microsim/MSNet.h>
32 : #include <microsim/MSLane.h>
33 : #include <microsim/MSEdge.h>
34 : #include <microsim/MSVehicle.h>
35 : #include "MSDevice_FCD.h"
36 :
37 :
38 : // ===========================================================================
39 : // static members
40 : // ===========================================================================
41 : SUMOTime MSDevice_FCD::myBegin = SUMOTime_MAX;
42 : SUMOTime MSDevice_FCD::myPeriod = 0;
43 : bool MSDevice_FCD::myUseGeo;
44 : bool MSDevice_FCD::myUseUTM;
45 : double MSDevice_FCD::myMaxLeaderDistance;
46 : std::vector<std::string> MSDevice_FCD::myParamsToWrite;
47 : double MSDevice_FCD::myRadius;
48 : std::set<const MSEdge*> MSDevice_FCD::myEdgeFilter;
49 : std::vector<PositionVector> MSDevice_FCD::myShape4Filters;
50 : bool MSDevice_FCD::myEdgeFilterInitialized(false);
51 : bool MSDevice_FCD::myShapeFilterInitialized(false);
52 : bool MSDevice_FCD::myShapeFilterDesired(false);
53 : SumoXMLAttrMask MSDevice_FCD::myWrittenAttributes;
54 :
55 :
56 : // ===========================================================================
57 : // method definitions
58 : // ===========================================================================
59 : // ---------------------------------------------------------------------------
60 : // static initialisation methods
61 : // ---------------------------------------------------------------------------
62 : void
63 44603 : MSDevice_FCD::insertOptions(OptionsCont& oc) {
64 44603 : oc.addOptionSubTopic("FCD Device");
65 89206 : insertDefaultAssignmentOptions("fcd", "FCD Device", oc);
66 :
67 89206 : oc.doRegister("device.fcd.begin", new Option_String("-1"));
68 89206 : oc.addDescription("device.fcd.begin", "FCD Device", TL("Recording begin time for FCD-data"));
69 :
70 89206 : oc.doRegister("device.fcd.period", new Option_String("0"));
71 89206 : oc.addDescription("device.fcd.period", "FCD Device", TL("Recording period for FCD-data"));
72 :
73 44603 : oc.doRegister("device.fcd.radius", new Option_Float(0));
74 89206 : oc.addDescription("device.fcd.radius", "FCD Device", TL("Record objects in a radius around equipped vehicles"));
75 44603 : }
76 :
77 :
78 : void
79 5255340 : MSDevice_FCD::buildVehicleDevices(SUMOVehicle& v, std::vector<MSVehicleDevice*>& into) {
80 5255340 : OptionsCont& oc = OptionsCont::getOptions();
81 10510680 : if (equippedByDefaultAssignmentOptions(oc, "fcd", v, oc.isSet("fcd-output"))) {
82 22463 : MSDevice_FCD* device = new MSDevice_FCD(v, "fcd_" + v.getID());
83 22463 : into.push_back(device);
84 : }
85 5255340 : }
86 :
87 :
88 : // ---------------------------------------------------------------------------
89 : // MSDevice_FCD-methods
90 : // ---------------------------------------------------------------------------
91 22463 : MSDevice_FCD::MSDevice_FCD(SUMOVehicle& holder, const std::string& id) :
92 22463 : MSVehicleDevice(holder, id) {
93 22463 : }
94 :
95 :
96 44918 : MSDevice_FCD::~MSDevice_FCD() {
97 44918 : }
98 :
99 :
100 : SumoXMLAttrMask
101 6753 : MSDevice_FCD::getDefaultMask() {
102 : SumoXMLAttrMask mask;
103 : mask.set(SUMO_ATTR_X);
104 : mask.set(SUMO_ATTR_Y);
105 6753 : if (MSNet::getInstance()->hasElevation()) {
106 : mask.set(SUMO_ATTR_Z);
107 : }
108 : mask.set(SUMO_ATTR_ANGLE);
109 : mask.set(SUMO_ATTR_TYPE);
110 : mask.set(SUMO_ATTR_SPEED);
111 : mask.set(SUMO_ATTR_POSITION);
112 : mask.set(SUMO_ATTR_LANE); // for micro vehicles only
113 : mask.set(SUMO_ATTR_EDGE); // for persons and meso vehicles
114 : mask.set(SUMO_ATTR_SLOPE);
115 18175 : if (!MSGlobals::gUseMesoSim && OptionsCont::getOptions().getFloat("fcd-output.max-leader-distance") > 0.) {
116 : mask.set(SUMO_ATTR_LEADER_ID);
117 : mask.set(SUMO_ATTR_LEADER_SPEED);
118 : mask.set(SUMO_ATTR_LEADER_GAP);
119 : }
120 6753 : return mask;
121 : }
122 :
123 :
124 : bool
125 2696 : MSDevice_FCD::shapeFilter(const SUMOTrafficObject* veh) {
126 : // lazily build the shape filter in the case where route file is loaded as an additional file
127 2696 : if (!myShapeFilterInitialized) {
128 0 : buildShapeFilter();
129 : }
130 2696 : const MSVehicle* msVeh = dynamic_cast<const MSVehicle*>(veh);
131 4882 : for (auto shape : myShape4Filters) {
132 2696 : if (shape.around(veh->getPosition()) || ((msVeh != nullptr) && shape.around(msVeh->getBackPosition()))) {
133 : return true;
134 : }
135 2696 : }
136 2186 : return false;
137 : }
138 :
139 :
140 : void
141 6 : MSDevice_FCD::buildShapeFilter(void) {
142 6 : const OptionsCont& oc = OptionsCont::getOptions();
143 12 : if (oc.isSet("fcd-output.filter-shapes")) {
144 6 : const ShapeContainer& loadedShapes = MSNet::getInstance()->getShapeContainer();
145 6 : if (loadedShapes.getPolygons().size() > 0) {
146 18 : for (std::string attrName : oc.getStringVector("fcd-output.filter-shapes")) {
147 6 : if (loadedShapes.getPolygons().get(attrName) == 0) {
148 0 : WRITE_ERRORF(TL("Specified shape '%' for filtering fcd-output could not be found."), attrName);
149 : } else {
150 : // store the PositionVector, not reference, as traci can manipulate / detete the polygons
151 6 : myShape4Filters.push_back(loadedShapes.getPolygons().get(attrName)->getShape());
152 : }
153 : }
154 6 : myShapeFilterInitialized = true;
155 : }
156 : } else {
157 0 : myShapeFilterInitialized = true;
158 : }
159 6 : }
160 :
161 :
162 : void
163 5044583 : MSDevice_FCD::initOnce() {
164 5044583 : if (myEdgeFilterInitialized) {
165 5040310 : return;
166 : }
167 4273 : myEdgeFilterInitialized = true;
168 4273 : const OptionsCont& oc = OptionsCont::getOptions();
169 4273 : myPeriod = string2time(oc.getString("device.fcd.period"));
170 4273 : myBegin = string2time(oc.getString("device.fcd.begin"));
171 4273 : myUseGeo = oc.getBool("fcd-output.geo");
172 4273 : myUseUTM = oc.getBool("fcd-output.utm");
173 4273 : myMaxLeaderDistance = oc.getFloat("fcd-output.max-leader-distance");
174 4273 : myParamsToWrite = oc.getStringVector("fcd-output.params");
175 4273 : myRadius = oc.getFloat("device.fcd.radius");
176 8546 : if (oc.isSet("fcd-output.filter-edges.input-file")) {
177 12 : const std::string file = oc.getString("fcd-output.filter-edges.input-file");
178 6 : std::ifstream strm(file.c_str());
179 6 : if (!strm.good()) {
180 0 : throw ProcessError(TLF("Could not load names of edges for filtering fcd-output from '%'.", file));
181 : }
182 12 : while (strm.good()) {
183 : std::string name;
184 6 : strm >> name;
185 : // maybe we're loading an edge-selection
186 12 : if (StringUtils::startsWith(name, "edge:")) {
187 12 : name = name.substr(5);
188 : }
189 6 : myEdgeFilter.insert(MSEdge::dictionary(name));
190 : }
191 6 : }
192 : SumoXMLAttrMask emissions;
193 : emissions.set(SUMO_ATTR_ECLASS);
194 : emissions.set(SUMO_ATTR_CO2);
195 : emissions.set(SUMO_ATTR_CO);
196 : emissions.set(SUMO_ATTR_HC);
197 : emissions.set(SUMO_ATTR_NOX);
198 : emissions.set(SUMO_ATTR_PMX);
199 : emissions.set(SUMO_ATTR_FUEL);
200 : emissions.set(SUMO_ATTR_ELECTRICITY);
201 : emissions.set(SUMO_ATTR_NOISE);
202 : SumoXMLAttrMask misc;
203 : misc.set(SUMO_ATTR_SIGNALS);
204 : misc.set(SUMO_ATTR_ACCELERATION);
205 : misc.set(SUMO_ATTR_ACCELERATION_LAT);
206 : misc.set(SUMO_ATTR_SPEED_VEC);
207 : misc.set(SUMO_ATTR_ACCEL_VEC);
208 : misc.set(SUMO_ATTR_DISTANCE);
209 : misc.set(SUMO_ATTR_ODOMETER);
210 : misc.set(SUMO_ATTR_POSITION_LAT);
211 : misc.set(SUMO_ATTR_SPEED_LAT);
212 : misc.set(SUMO_ATTR_SPEEDREL);
213 : misc.set(SUMO_ATTR_LEADER_ID);
214 : misc.set(SUMO_ATTR_LEADER_SPEED);
215 : misc.set(SUMO_ATTR_ARRIVALDELAY);
216 : misc.set(SUMO_ATTR_DELAY);
217 : misc.set(SUMO_ATTR_SEGMENT);
218 : misc.set(SUMO_ATTR_QUEUE);
219 : misc.set(SUMO_ATTR_ENTRYTIME);
220 : misc.set(SUMO_ATTR_EVENTTIME);
221 : misc.set(SUMO_ATTR_BLOCKTIME);
222 21365 : const std::map<std::string, SumoXMLAttrMask> special = {{"location", getDefaultMask()}, {"emissions", emissions}, {"misc", misc}};
223 8546 : if (oc.isSet("fcd-output.attributes")) {
224 3586 : myWrittenAttributes = OutputDevice::parseWrittenAttributes(oc.getStringVector("fcd-output.attributes"), "fcd output", special);
225 : } else {
226 2480 : myWrittenAttributes = getDefaultMask();
227 : }
228 : // need to store this because some attributes are reset later
229 : const bool all = myWrittenAttributes.all();
230 : myWrittenAttributes.set(SUMO_ATTR_ID);
231 4273 : if (!MSNet::getInstance()->hasElevation()) {
232 : myWrittenAttributes.reset(SUMO_ATTR_Z);
233 : }
234 8546 : if (oc.getBool("fcd-output.signals")) {
235 : myWrittenAttributes.set(SUMO_ATTR_SIGNALS);
236 : }
237 8546 : if (oc.getBool("fcd-output.acceleration")) {
238 : myWrittenAttributes.set(SUMO_ATTR_ACCELERATION);
239 : }
240 4273 : myWrittenAttributes.set(SUMO_ATTR_ACCELERATION_LAT, myWrittenAttributes.test(SUMO_ATTR_ACCELERATION) && MSGlobals::gSublane);
241 8546 : if (oc.getBool("fcd-output.distance")) {
242 : myWrittenAttributes.set(SUMO_ATTR_DISTANCE);
243 : }
244 8546 : if (oc.getBool("fcd-output.speed-relative")) {
245 : myWrittenAttributes.set(SUMO_ATTR_SPEEDREL);
246 : }
247 :
248 8546 : if (oc.isSet("fcd-output.filter-shapes")) {
249 : // build the shape filter if it is desired
250 6 : myShapeFilterDesired = true;
251 6 : buildShapeFilter();
252 : }
253 8546 : OutputDevice::getDeviceByOption("fcd-output").setExpectedAttributes(all ? 0 : myWrittenAttributes);
254 0 : }
255 :
256 :
257 : void
258 41448 : MSDevice_FCD::cleanup() {
259 : myEdgeFilter.clear();
260 : myShape4Filters.clear();
261 41448 : myEdgeFilterInitialized = false;
262 41448 : myShapeFilterInitialized = false;
263 41448 : myShapeFilterDesired = false;
264 : myWrittenAttributes.reset();
265 41448 : }
266 :
267 :
268 : /****************************************************************************/
|