Line data Source code
1 : /****************************************************************************/
2 : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3 : // Copyright (C) 2017-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 Polygon.cpp
15 : /// @author Gregor Laemmel
16 : /// @date 15.03.2017
17 : ///
18 : // C++ TraCI client API implementation
19 : /****************************************************************************/
20 : #include <microsim/MSNet.h>
21 : #include <microsim/MSEventControl.h>
22 : #include <microsim/MSVehicleControl.h>
23 : #include <microsim/transportables/MSTransportableControl.h>
24 : #include <microsim/MSDynamicShapeUpdater.h>
25 : #include <libsumo/TraCIConstants.h>
26 : #include <utils/shapes/SUMOPolygon.h>
27 : #include <utils/shapes/PolygonDynamics.h>
28 : #include <utils/shapes/ShapeContainer.h>
29 : #include <utils/common/ParametrisedWrappingCommand.h>
30 :
31 : #include "Polygon.h"
32 : #include "Helper.h"
33 :
34 :
35 : namespace libsumo {
36 : // ===========================================================================
37 : // static member initializations
38 : // ===========================================================================
39 : SubscriptionResults Polygon::mySubscriptionResults;
40 : ContextSubscriptionResults Polygon::myContextSubscriptionResults;
41 : NamedRTree* Polygon::myTree(nullptr);
42 :
43 :
44 : // ===========================================================================
45 : // static member definitions
46 : // ===========================================================================
47 : std::vector<std::string>
48 533 : Polygon::getIDList() {
49 : std::vector<std::string> ids;
50 533 : MSNet::getInstance()->getShapeContainer().getPolygons().insertIDs(ids);
51 531 : return ids;
52 2 : }
53 :
54 :
55 : int
56 136 : Polygon::getIDCount() {
57 136 : return (int)getIDList().size();
58 : }
59 :
60 :
61 : std::string
62 101 : Polygon::getType(const std::string& polygonID) {
63 101 : return getPolygon(polygonID)->getShapeType();
64 : }
65 :
66 :
67 : TraCIPositionVector
68 8116 : Polygon::getShape(const std::string& polygonID) {
69 8116 : SUMOPolygon* p = getPolygon(polygonID);
70 8116 : return Helper::makeTraCIPositionVector(p->getShape());
71 : }
72 :
73 :
74 : bool
75 101 : Polygon::getFilled(const std::string& polygonID) {
76 101 : return getPolygon(polygonID)->getFill();
77 : }
78 :
79 : double
80 11 : Polygon::getLineWidth(const std::string& polygonID) {
81 11 : return getPolygon(polygonID)->getLineWidth();
82 : }
83 :
84 : TraCIColor
85 109 : Polygon::getColor(const std::string& polygonID) {
86 109 : SUMOPolygon* p = getPolygon(polygonID);
87 107 : return Helper::makeTraCIColor(p->getShapeColor());
88 : }
89 :
90 :
91 : std::string
92 12 : Polygon::getParameter(const std::string& polygonID, const std::string& key) {
93 24 : return getPolygon(polygonID)->getParameter(key, "");
94 : }
95 :
96 :
97 0 : LIBSUMO_GET_PARAMETER_WITH_KEY_IMPLEMENTATION(Polygon)
98 :
99 :
100 : void
101 7 : Polygon::setType(const std::string& polygonID, const std::string& polygonType) {
102 7 : getPolygon(polygonID)->setShapeType(polygonType);
103 6 : }
104 :
105 :
106 : void
107 8 : Polygon::setShape(const std::string& polygonID, const TraCIPositionVector& shape) {
108 8 : PositionVector positionVector = Helper::makePositionVector(shape);
109 8 : getPolygon(polygonID); // just to check whether it exists
110 7 : ShapeContainer& shapeCont = MSNet::getInstance()->getShapeContainer();
111 7 : shapeCont.reshapePolygon(polygonID, positionVector);
112 8 : }
113 :
114 :
115 : void
116 12 : Polygon::setColor(const std::string& polygonID, const TraCIColor& c) {
117 12 : getPolygon(polygonID)->setShapeColor(Helper::makeRGBColor(c));
118 11 : }
119 :
120 :
121 : void
122 216 : Polygon::add(const std::string& polygonID, const TraCIPositionVector& shape, const TraCIColor& color, bool fill, const std::string& polygonType, int layer, double lineWidth) {
123 216 : ShapeContainer& shapeCont = MSNet::getInstance()->getShapeContainer();
124 216 : PositionVector pShape = Helper::makePositionVector(shape);
125 214 : RGBColor col = Helper::makeRGBColor(color);
126 214 : if (!shapeCont.addPolygon(polygonID, polygonType, col, (double)layer, Shape::DEFAULT_ANGLE, Shape::DEFAULT_IMG_FILE, Shape::DEFAULT_RELATIVEPATH, pShape, false, fill, lineWidth)) {
127 0 : throw TraCIException("Could not add polygon '" + polygonID + "'");
128 : }
129 214 : if (myTree != nullptr) {
130 : SUMOPolygon* p = shapeCont.getPolygons().get(polygonID);
131 5 : Boundary b = p->getShape().getBoxBoundary();
132 5 : const float cmin[2] = {(float) b.xmin(), (float) b.ymin()};
133 5 : const float cmax[2] = {(float) b.xmax(), (float) b.ymax()};
134 5 : myTree->Insert(cmin, cmax, p);
135 5 : }
136 214 : }
137 :
138 :
139 : void
140 69 : Polygon::addHighlightPolygon(const std::string& objectID, const int type, const std::string& polygonID, const TraCIPositionVector& shape, const TraCIColor& color, bool fill, const std::string& polygonType, int layer, double lineWidth) {
141 69 : add(polygonID, shape, color, fill, polygonType, layer, lineWidth);
142 69 : MSNet::getInstance()->getShapeContainer().registerHighlight(objectID, type, polygonID);
143 69 : }
144 :
145 :
146 : void
147 204 : Polygon::addDynamics(const std::string& polygonID, const std::string& trackedObjectID, const std::vector<double>& timeSpan, const std::vector<double>& alphaSpan, bool looped, bool rotate) {
148 204 : if (timeSpan.empty()) {
149 63 : if (trackedObjectID == "") {
150 16 : throw TraCIException("Could not add polygon dynamics for polygon '" + polygonID + "': dynamics underspecified (either a tracked object ID or a time span have to be provided).");
151 : }
152 55 : if (looped) {
153 16 : throw TraCIException("Could not add polygon dynamics for polygon '" + polygonID + "': looped==true requires time line of positive length.");
154 : }
155 : }
156 188 : if (timeSpan.size() == 1) {
157 16 : throw TraCIException("Could not add polygon dynamics for polygon '" + polygonID + "': time span cannot have length one.");
158 180 : } else if (timeSpan.size() > 0 && timeSpan[0] != 0.0) {
159 16 : throw TraCIException("Could not add polygon dynamics for polygon '" + polygonID + "': first element of time span must be zero.");
160 : }
161 172 : if (timeSpan.size() != alphaSpan.size() && alphaSpan.size() != 0) {
162 16 : throw TraCIException("Could not add polygon dynamics for polygon '" + polygonID + "': alpha span must have length zero or equal to time span length.");
163 : }
164 164 : if (timeSpan.size() >= 2) {
165 612 : for (unsigned int i = 1; i < timeSpan.size(); ++i) {
166 503 : if (timeSpan[i - 1] > timeSpan[i]) {
167 16 : throw TraCIException("Could not add polygon dynamics for polygon '" + polygonID + "': entries of time span must be ordered ascendingly.");
168 : }
169 : }
170 : }
171 :
172 156 : SUMOTrafficObject* obj = getTrafficObject(trackedObjectID);
173 156 : ShapeContainer& shapeCont = MSNet::getInstance()->getShapeContainer();
174 312 : PolygonDynamics* pd = shapeCont.addPolygonDynamics(SIMTIME, polygonID, obj, timeSpan, alphaSpan, looped, rotate);
175 156 : if (pd == nullptr) {
176 0 : throw TraCIException("Could not add polygon dynamics for polygon '" + polygonID + "': polygon doesn't exist.");
177 : }
178 : // Ensure existence of a DynamicShapeUpdater
179 156 : if (MSNet::getInstance()->getDynamicShapeUpdater() == nullptr) {
180 24 : MSNet::VehicleStateListener* listener = dynamic_cast<MSNet::VehicleStateListener*>(MSNet::getInstance()->makeDynamicShapeUpdater());
181 24 : MSNet::getInstance()->addVehicleStateListener(listener);
182 : }
183 :
184 : // Schedule the regular polygon update
185 156 : auto cmd = new ParametrisedWrappingCommand<ShapeContainer, PolygonDynamics*>(&shapeCont, pd, &ShapeContainer::polygonDynamicsUpdate);
186 312 : shapeCont.addPolygonUpdateCommand(pd->getPolygonID(), cmd);
187 156 : MSNet::getInstance()->getEndOfTimestepEvents()->addEvent(cmd, SIMSTEP);
188 156 : }
189 :
190 :
191 : void
192 27 : Polygon::remove(const std::string& polygonID, int /* layer */) {
193 : // !!! layer not used yet (shouldn't the id be enough?)
194 27 : ShapeContainer& shapeCont = MSNet::getInstance()->getShapeContainer();
195 27 : if (myTree != nullptr) {
196 : SUMOPolygon* p = shapeCont.getPolygons().get(polygonID);
197 5 : if (p != nullptr) {
198 5 : Boundary b = p->getShape().getBoxBoundary();
199 5 : const float cmin[2] = {(float) b.xmin(), (float) b.ymin()};
200 5 : const float cmax[2] = {(float) b.xmax(), (float) b.ymax()};
201 5 : myTree->Remove(cmin, cmax, p);
202 5 : }
203 : }
204 27 : if (!shapeCont.removePolygon(polygonID)) {
205 2 : throw TraCIException("Could not remove polygon '" + polygonID + "'");
206 : }
207 26 : }
208 :
209 :
210 : void
211 7 : Polygon::setFilled(std::string polygonID, bool filled) {
212 7 : SUMOPolygon* p = getPolygon(polygonID);
213 6 : p->setFill(filled);
214 6 : }
215 :
216 : void
217 6 : Polygon::setLineWidth(std::string polygonID, double lineWidth) {
218 6 : SUMOPolygon* p = getPolygon(polygonID);
219 6 : p->setLineWidth(lineWidth);
220 6 : }
221 :
222 :
223 : SUMOPolygon*
224 24851 : Polygon::getPolygon(const std::string& id) {
225 24851 : SUMOPolygon* p = MSNet::getInstance()->getShapeContainer().getPolygons().get(id);
226 24845 : if (p == nullptr) {
227 12 : throw TraCIException("Polygon '" + id + "' is not known");
228 : }
229 24845 : return p;
230 : }
231 :
232 :
233 : SUMOTrafficObject*
234 156 : Polygon::getTrafficObject(const std::string& id) {
235 156 : if (id == "") {
236 : return nullptr;
237 : }
238 111 : MSNet* net = MSNet::getInstance();
239 : // First try to find a vehicle with the given id
240 111 : SUMOVehicle* sumoVehicle = net->getVehicleControl().getVehicle(id);
241 111 : if (sumoVehicle != nullptr) {
242 : return static_cast<SUMOTrafficObject*>(sumoVehicle);
243 : }
244 0 : MSTransportable* transportable = net->getPersonControl().get(id);
245 0 : if (transportable != nullptr) {
246 : return static_cast<SUMOTrafficObject*>(transportable);
247 : } else {
248 0 : throw TraCIException("Traffic object '" + id + "' is not known");
249 : }
250 : }
251 :
252 :
253 : void
254 6 : Polygon::setParameter(const std::string& polygonID, const std::string& key, const std::string& value) {
255 6 : SUMOPolygon* p = getPolygon(polygonID);
256 6 : p->setParameter(key, value);
257 6 : }
258 :
259 :
260 8298 : LIBSUMO_SUBSCRIPTION_IMPLEMENTATION(Polygon, POLYGON)
261 :
262 :
263 : NamedRTree*
264 352 : Polygon::getTree() {
265 352 : if (myTree == nullptr) {
266 17 : myTree = new NamedRTree();
267 17 : ShapeContainer& shapeCont = MSNet::getInstance()->getShapeContainer();
268 58 : for (const auto& i : shapeCont.getPolygons()) {
269 41 : Boundary b = i.second->getShape().getBoxBoundary();
270 41 : const float cmin[2] = {(float) b.xmin(), (float) b.ymin()};
271 41 : const float cmax[2] = {(float) b.xmax(), (float) b.ymax()};
272 41 : myTree->Insert(cmin, cmax, i.second);
273 41 : }
274 : }
275 352 : return myTree;
276 : }
277 :
278 : void
279 40219 : Polygon::cleanup() {
280 40219 : delete myTree;
281 40219 : myTree = nullptr;
282 40219 : }
283 :
284 : void
285 16355 : Polygon::storeShape(const std::string& id, PositionVector& shape) {
286 16355 : shape = getPolygon(id)->getShape();
287 16355 : }
288 :
289 :
290 : std::shared_ptr<VariableWrapper>
291 266 : Polygon::makeWrapper() {
292 266 : return std::make_shared<Helper::SubscriptionWrapper>(handleVariable, mySubscriptionResults, myContextSubscriptionResults);
293 : }
294 :
295 :
296 : bool
297 4695 : Polygon::handleVariable(const std::string& objID, const int variable, VariableWrapper* wrapper, tcpip::Storage* paramData) {
298 4695 : switch (variable) {
299 253 : case TRACI_ID_LIST:
300 253 : return wrapper->wrapStringList(objID, variable, getIDList());
301 102 : case ID_COUNT:
302 102 : return wrapper->wrapInt(objID, variable, getIDCount());
303 75 : case VAR_TYPE:
304 150 : return wrapper->wrapString(objID, variable, getType(objID));
305 81 : case VAR_COLOR:
306 81 : return wrapper->wrapColor(objID, variable, getColor(objID));
307 75 : case VAR_FILL:
308 75 : return wrapper->wrapInt(objID, variable, getFilled(objID));
309 7 : case VAR_WIDTH:
310 7 : return wrapper->wrapDouble(objID, variable, getLineWidth(objID));
311 4084 : case VAR_SHAPE:
312 8168 : return wrapper->wrapPositionVector(objID, variable, getShape(objID));
313 8 : case libsumo::VAR_PARAMETER:
314 8 : paramData->readUnsignedByte();
315 16 : return wrapper->wrapString(objID, variable, getParameter(objID, paramData->readString()));
316 0 : case libsumo::VAR_PARAMETER_WITH_KEY:
317 0 : paramData->readUnsignedByte();
318 0 : return wrapper->wrapStringPair(objID, variable, getParameterWithKey(objID, paramData->readString()));
319 : default:
320 : return false;
321 : }
322 : }
323 :
324 :
325 : bool
326 85 : Polygon::exists(std::string polyID) {
327 85 : SUMOPolygon* p = MSNet::getInstance()->getShapeContainer().getPolygons().get(polyID);
328 85 : return p != nullptr;
329 : }
330 : }
331 :
332 :
333 : /****************************************************************************/
|