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