Line data Source code
1 : /****************************************************************************/ 2 : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo 3 : // Copyright (C) 2013-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 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 : std::set<const MSEdge*> MSDevice_FCD::myEdgeFilter; 42 : std::vector<PositionVector> MSDevice_FCD::myShape4Filters; 43 : bool MSDevice_FCD::myEdgeFilterInitialized(false); 44 : bool MSDevice_FCD::myShapeFilterInitialized(false); 45 : bool MSDevice_FCD::myShapeFilterDesired(false); 46 : SumoXMLAttrMask MSDevice_FCD::myWrittenAttributes(getDefaultMask()); 47 : 48 : // =========================================================================== 49 : // method definitions 50 : // =========================================================================== 51 : // --------------------------------------------------------------------------- 52 : // static initialisation methods 53 : // --------------------------------------------------------------------------- 54 : void 55 36322 : MSDevice_FCD::insertOptions(OptionsCont& oc) { 56 36322 : oc.addOptionSubTopic("FCD Device"); 57 72644 : insertDefaultAssignmentOptions("fcd", "FCD Device", oc); 58 : 59 72644 : oc.doRegister("device.fcd.begin", new Option_String("-1")); 60 72644 : oc.addDescription("device.fcd.begin", "FCD Device", TL("Recording begin time for FCD-data")); 61 : 62 72644 : oc.doRegister("device.fcd.period", new Option_String("0")); 63 72644 : oc.addDescription("device.fcd.period", "FCD Device", TL("Recording period for FCD-data")); 64 : 65 36322 : oc.doRegister("device.fcd.radius", new Option_Float(0)); 66 72644 : oc.addDescription("device.fcd.radius", "FCD Device", TL("Record objects in a radius around equipped vehicles")); 67 36322 : } 68 : 69 : 70 : void 71 4655769 : MSDevice_FCD::buildVehicleDevices(SUMOVehicle& v, std::vector<MSVehicleDevice*>& into) { 72 4655769 : OptionsCont& oc = OptionsCont::getOptions(); 73 9311538 : if (equippedByDefaultAssignmentOptions(oc, "fcd", v, oc.isSet("fcd-output"))) { 74 19509 : MSDevice_FCD* device = new MSDevice_FCD(v, "fcd_" + v.getID()); 75 19509 : into.push_back(device); 76 19509 : initOnce(); 77 : } 78 4655769 : } 79 : 80 : 81 : // --------------------------------------------------------------------------- 82 : // MSDevice_FCD-methods 83 : // --------------------------------------------------------------------------- 84 19509 : MSDevice_FCD::MSDevice_FCD(SUMOVehicle& holder, const std::string& id) : 85 19509 : MSVehicleDevice(holder, id) { 86 19509 : } 87 : 88 : 89 39008 : MSDevice_FCD::~MSDevice_FCD() { 90 39008 : } 91 : 92 : 93 : SumoXMLAttrMask 94 71437 : MSDevice_FCD::getDefaultMask() { 95 71437 : SumoXMLAttrMask mask; 96 : // set all bits to 1 97 : mask.set(); 98 : // some attributes are not written by default and must be enabled via option fcd-output.attributes 99 : // (or with an explicit attribute list) 100 : mask.reset(SUMO_ATTR_VEHICLE); 101 : mask.reset(SUMO_ATTR_ODOMETER); 102 : mask.reset(SUMO_ATTR_SPEED_LAT); 103 : mask.reset(SUMO_ATTR_POSITION_LAT); 104 : mask.reset(SUMO_ATTR_ARRIVALDELAY); 105 71437 : return mask; 106 : } 107 : 108 : 109 : bool 110 2696 : MSDevice_FCD::shapeFilter(const SUMOTrafficObject* veh) { 111 : // lazily build the shape filter in the case where route file is loaded as an additional file 112 2696 : if (!myShapeFilterInitialized) { 113 6 : buildShapeFilter(); 114 : } 115 2696 : const MSVehicle* msVeh = dynamic_cast<const MSVehicle*>(veh); 116 4882 : for (auto shape : myShape4Filters) { 117 2700 : if (shape.around(veh->getPosition()) || ((msVeh != nullptr) && shape.around(msVeh->getBackPosition()))) { 118 : return true; 119 : } 120 2696 : } 121 2186 : return false; 122 : } 123 : 124 : 125 : void 126 12 : MSDevice_FCD::buildShapeFilter(void) { 127 12 : const OptionsCont& oc = OptionsCont::getOptions(); 128 24 : if (oc.isSet("fcd-output.filter-shapes")) { 129 12 : const ShapeContainer& loadedShapes = MSNet::getInstance()->getShapeContainer(); 130 12 : if (loadedShapes.getPolygons().size() > 0) { 131 18 : for (std::string attrName : oc.getStringVector("fcd-output.filter-shapes")) { 132 6 : if (loadedShapes.getPolygons().get(attrName) == 0) { 133 0 : WRITE_ERRORF(TL("Specified shape '%' for filtering fcd-output could not be found."), attrName); 134 : } else { 135 : // store the PositionVector, not reference, as traci can manipulate / detete the polygons 136 6 : myShape4Filters.push_back(loadedShapes.getPolygons().get(attrName)->getShape()); 137 : } 138 : } 139 6 : myShapeFilterInitialized = true; 140 : } 141 : } else { 142 0 : myShapeFilterInitialized = true; 143 : } 144 12 : } 145 : 146 : 147 : void 148 21469 : MSDevice_FCD::initOnce() { 149 21469 : if (myEdgeFilterInitialized) { 150 : return; 151 : } 152 2680 : myEdgeFilterInitialized = true; 153 2680 : const OptionsCont& oc = OptionsCont::getOptions(); 154 5360 : if (oc.isSet("fcd-output.filter-edges.input-file")) { 155 12 : const std::string file = oc.getString("fcd-output.filter-edges.input-file"); 156 6 : std::ifstream strm(file.c_str()); 157 6 : if (!strm.good()) { 158 0 : throw ProcessError(TLF("Could not load names of edges for filtering fcd-output from '%'.", file)); 159 : } 160 12 : while (strm.good()) { 161 : std::string name; 162 6 : strm >> name; 163 : // maybe we're loading an edge-selection 164 12 : if (StringUtils::startsWith(name, "edge:")) { 165 12 : name = name.substr(5); 166 : } 167 6 : myEdgeFilter.insert(MSEdge::dictionary(name)); 168 : } 169 6 : } 170 5360 : if (oc.isSet("fcd-output.attributes")) { 171 : myWrittenAttributes.reset(); 172 1023 : for (std::string attrName : oc.getStringVector("fcd-output.attributes")) { 173 510 : if (!SUMOXMLDefinitions::Attrs.hasString(attrName)) { 174 25 : if (attrName == "all") { 175 : myWrittenAttributes.set(); 176 : } else { 177 0 : WRITE_ERRORF(TL("Unknown attribute '%' to write in fcd output."), attrName); 178 : } 179 : continue; 180 : } 181 460 : int attr = SUMOXMLDefinitions::Attrs.get(attrName); 182 460 : myWrittenAttributes.set(attr); 183 : } 184 : } 185 : 186 5360 : if (oc.isSet("fcd-output.filter-shapes")) { 187 : // build the shape filter if it is desired 188 6 : myShapeFilterDesired = true; 189 6 : buildShapeFilter(); 190 : } 191 : //std::cout << "mask=" << myWrittenAttributes << " binary=" << std::bitset<64>(myWrittenAttributes) << "\n"; 192 : } 193 : 194 : 195 : void 196 35160 : MSDevice_FCD::cleanup() { 197 : myEdgeFilter.clear(); 198 : myShape4Filters.clear(); 199 35160 : myEdgeFilterInitialized = false; 200 35160 : myShapeFilterInitialized = false; 201 35160 : myShapeFilterDesired = false; 202 35160 : myWrittenAttributes = getDefaultMask(); 203 35160 : } 204 : 205 : 206 : /****************************************************************************/