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 L\"ammel
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 540 : Polygon::getIDList() {
49 : std::vector<std::string> ids;
50 540 : MSNet::getInstance()->getShapeContainer().getPolygons().insertIDs(ids);
51 538 : return ids;
52 2 : }
53 :
54 :
55 : int
56 169 : Polygon::getIDCount() {
57 169 : return (int)getIDList().size();
58 : }
59 :
60 :
61 : std::string
62 124 : Polygon::getType(const std::string& polygonID) {
63 124 : return getPolygon(polygonID)->getShapeType();
64 : }
65 :
66 :
67 : TraCIPositionVector
68 10142 : Polygon::getShape(const std::string& polygonID) {
69 10142 : SUMOPolygon* p = getPolygon(polygonID);
70 10142 : return Helper::makeTraCIPositionVector(p->getShape());
71 : }
72 :
73 :
74 : bool
75 124 : Polygon::getFilled(const std::string& polygonID) {
76 124 : return getPolygon(polygonID)->getFill();
77 : }
78 :
79 : double
80 13 : Polygon::getLineWidth(const std::string& polygonID) {
81 13 : return getPolygon(polygonID)->getLineWidth();
82 : }
83 :
84 : TraCIColor
85 133 : Polygon::getColor(const std::string& polygonID) {
86 133 : SUMOPolygon* p = getPolygon(polygonID);
87 131 : return Helper::makeTraCIColor(p->getShapeColor());
88 : }
89 :
90 :
91 : std::string
92 14 : Polygon::getParameter(const std::string& polygonID, const std::string& key) {
93 28 : return getPolygon(polygonID)->getParameter(key, "");
94 : }
95 :
96 :
97 0 : LIBSUMO_GET_PARAMETER_WITH_KEY_IMPLEMENTATION(Polygon)
98 :
99 :
100 : void
101 8 : Polygon::setType(const std::string& polygonID, const std::string& polygonType) {
102 8 : getPolygon(polygonID)->setShapeType(polygonType);
103 7 : }
104 :
105 :
106 : void
107 9 : Polygon::setShape(const std::string& polygonID, const TraCIPositionVector& shape) {
108 9 : PositionVector positionVector = Helper::makePositionVector(shape);
109 9 : getPolygon(polygonID); // just to check whether it exists
110 8 : ShapeContainer& shapeCont = MSNet::getInstance()->getShapeContainer();
111 8 : shapeCont.reshapePolygon(polygonID, positionVector);
112 9 : }
113 :
114 :
115 : void
116 14 : Polygon::setColor(const std::string& polygonID, const TraCIColor& c) {
117 14 : getPolygon(polygonID)->setShapeColor(Helper::makeRGBColor(c));
118 13 : }
119 :
120 :
121 : void
122 269 : Polygon::add(const std::string& polygonID, const TraCIPositionVector& shape, const TraCIColor& color, bool fill, const std::string& polygonType, int layer, double lineWidth) {
123 269 : ShapeContainer& shapeCont = MSNet::getInstance()->getShapeContainer();
124 269 : PositionVector pShape = Helper::makePositionVector(shape);
125 267 : RGBColor col = Helper::makeRGBColor(color);
126 267 : 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 267 : if (myTree != nullptr) {
130 : SUMOPolygon* p = shapeCont.getPolygons().get(polygonID);
131 6 : Boundary b = p->getShape().getBoxBoundary();
132 6 : const float cmin[2] = {(float) b.xmin(), (float) b.ymin()};
133 6 : const float cmax[2] = {(float) b.xmax(), (float) b.ymax()};
134 6 : myTree->Insert(cmin, cmax, p);
135 6 : }
136 267 : }
137 :
138 :
139 : void
140 86 : 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 86 : add(polygonID, shape, color, fill, polygonType, layer, lineWidth);
142 86 : MSNet::getInstance()->getShapeContainer().registerHighlight(objectID, type, polygonID);
143 86 : }
144 :
145 :
146 : void
147 256 : 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 256 : if (timeSpan.empty()) {
149 80 : if (trackedObjectID == "") {
150 20 : 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 70 : if (looped) {
153 20 : throw TraCIException("Could not add polygon dynamics for polygon '" + polygonID + "': looped==true requires time line of positive length.");
154 : }
155 : }
156 236 : if (timeSpan.size() == 1) {
157 20 : throw TraCIException("Could not add polygon dynamics for polygon '" + polygonID + "': time span cannot have length one.");
158 226 : } else if (timeSpan.size() > 0 && timeSpan[0] != 0.0) {
159 20 : throw TraCIException("Could not add polygon dynamics for polygon '" + polygonID + "': first element of time span must be zero.");
160 : }
161 216 : if (timeSpan.size() != alphaSpan.size() && alphaSpan.size() != 0) {
162 20 : throw TraCIException("Could not add polygon dynamics for polygon '" + polygonID + "': alpha span must have length zero or equal to time span length.");
163 : }
164 206 : if (timeSpan.size() >= 2) {
165 764 : for (unsigned int i = 1; i < timeSpan.size(); ++i) {
166 628 : if (timeSpan[i - 1] > timeSpan[i]) {
167 20 : throw TraCIException("Could not add polygon dynamics for polygon '" + polygonID + "': entries of time span must be ordered ascendingly.");
168 : }
169 : }
170 : }
171 :
172 196 : SUMOTrafficObject* obj = getTrafficObject(trackedObjectID);
173 196 : ShapeContainer& shapeCont = MSNet::getInstance()->getShapeContainer();
174 196 : PolygonDynamics* pd = shapeCont.addPolygonDynamics(SIMTIME, polygonID, obj, timeSpan, alphaSpan, looped, rotate);
175 196 : 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 196 : if (MSNet::getInstance()->getDynamicShapeUpdater() == nullptr) {
180 30 : MSNet::VehicleStateListener* listener = dynamic_cast<MSNet::VehicleStateListener*>(MSNet::getInstance()->makeDynamicShapeUpdater());
181 30 : MSNet::getInstance()->addVehicleStateListener(listener);
182 : }
183 :
184 : // Schedule the regular polygon update
185 196 : auto cmd = new ParametrisedWrappingCommand<ShapeContainer, PolygonDynamics*>(&shapeCont, pd, &ShapeContainer::polygonDynamicsUpdate);
186 196 : shapeCont.addPolygonUpdateCommand(pd->getPolygonID(), cmd);
187 196 : MSNet::getInstance()->getEndOfTimestepEvents()->addEvent(cmd, SIMSTEP);
188 196 : }
189 :
190 :
191 : void
192 34 : Polygon::remove(const std::string& polygonID, int /* layer */) {
193 : // !!! layer not used yet (shouldn't the id be enough?)
194 34 : ShapeContainer& shapeCont = MSNet::getInstance()->getShapeContainer();
195 34 : if (myTree != nullptr) {
196 : SUMOPolygon* p = shapeCont.getPolygons().get(polygonID);
197 6 : if (p != nullptr) {
198 6 : Boundary b = p->getShape().getBoxBoundary();
199 6 : const float cmin[2] = {(float) b.xmin(), (float) b.ymin()};
200 6 : const float cmax[2] = {(float) b.xmax(), (float) b.ymax()};
201 6 : myTree->Remove(cmin, cmax, p);
202 6 : }
203 : }
204 34 : if (!shapeCont.removePolygon(polygonID)) {
205 2 : throw TraCIException("Could not remove polygon '" + polygonID + "'");
206 : }
207 33 : }
208 :
209 :
210 : void
211 8 : Polygon::setFilled(std::string polygonID, bool filled) {
212 8 : SUMOPolygon* p = getPolygon(polygonID);
213 7 : p->setFill(filled);
214 7 : }
215 :
216 : void
217 7 : Polygon::setLineWidth(std::string polygonID, double lineWidth) {
218 7 : SUMOPolygon* p = getPolygon(polygonID);
219 7 : p->setLineWidth(lineWidth);
220 7 : }
221 :
222 :
223 : SUMOPolygon*
224 30860 : Polygon::getPolygon(const std::string& id) {
225 30860 : SUMOPolygon* p = MSNet::getInstance()->getShapeContainer().getPolygons().get(id);
226 30854 : if (p == nullptr) {
227 12 : throw TraCIException("Polygon '" + id + "' is not known");
228 : }
229 30854 : return p;
230 : }
231 :
232 :
233 : SUMOTrafficObject*
234 196 : Polygon::getTrafficObject(const std::string& id) {
235 196 : if (id == "") {
236 : return nullptr;
237 : }
238 140 : MSNet* net = MSNet::getInstance();
239 : // First try to find a vehicle with the given id
240 140 : SUMOVehicle* sumoVehicle = net->getVehicleControl().getVehicle(id);
241 140 : 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 7 : Polygon::setParameter(const std::string& polygonID, const std::string& key, const std::string& value) {
255 7 : SUMOPolygon* p = getPolygon(polygonID);
256 7 : p->setParameter(key, value);
257 7 : }
258 :
259 :
260 8206 : LIBSUMO_SUBSCRIPTION_IMPLEMENTATION(Polygon, POLYGON)
261 :
262 :
263 : NamedRTree*
264 236 : Polygon::getTree() {
265 236 : if (myTree == nullptr) {
266 16 : myTree = new NamedRTree();
267 16 : ShapeContainer& shapeCont = MSNet::getInstance()->getShapeContainer();
268 52 : for (const auto& i : shapeCont.getPolygons()) {
269 36 : Boundary b = i.second->getShape().getBoxBoundary();
270 36 : const float cmin[2] = {(float) b.xmin(), (float) b.ymin()};
271 36 : const float cmax[2] = {(float) b.xmax(), (float) b.ymax()};
272 36 : myTree->Insert(cmin, cmax, i.second);
273 36 : }
274 : }
275 236 : return myTree;
276 : }
277 :
278 : void
279 35156 : Polygon::cleanup() {
280 35156 : delete myTree;
281 35156 : myTree = nullptr;
282 35156 : }
283 :
284 : void
285 20257 : Polygon::storeShape(const std::string& id, PositionVector& shape) {
286 20257 : shape = getPolygon(id)->getShape();
287 20257 : }
288 :
289 :
290 : std::shared_ptr<VariableWrapper>
291 267 : Polygon::makeWrapper() {
292 267 : return std::make_shared<Helper::SubscriptionWrapper>(handleVariable, mySubscriptionResults, myContextSubscriptionResults);
293 : }
294 :
295 :
296 : bool
297 6850 : Polygon::handleVariable(const std::string& objID, const int variable, VariableWrapper* wrapper, tcpip::Storage* paramData) {
298 6850 : switch (variable) {
299 275 : case TRACI_ID_LIST:
300 275 : return wrapper->wrapStringList(objID, variable, getIDList());
301 135 : case ID_COUNT:
302 135 : return wrapper->wrapInt(objID, variable, getIDCount());
303 98 : case VAR_TYPE:
304 196 : return wrapper->wrapString(objID, variable, getType(objID));
305 105 : case VAR_COLOR:
306 105 : return wrapper->wrapColor(objID, variable, getColor(objID));
307 98 : case VAR_FILL:
308 98 : return wrapper->wrapInt(objID, variable, getFilled(objID));
309 9 : case VAR_WIDTH:
310 9 : return wrapper->wrapDouble(objID, variable, getLineWidth(objID));
311 6110 : case VAR_SHAPE:
312 12220 : return wrapper->wrapPositionVector(objID, variable, getShape(objID));
313 10 : case libsumo::VAR_PARAMETER:
314 10 : paramData->readUnsignedByte();
315 20 : 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 106 : Polygon::exists(std::string polyID) {
327 106 : SUMOPolygon* p = MSNet::getInstance()->getShapeContainer().getPolygons().get(polyID);
328 106 : return p != nullptr;
329 : }
330 : }
331 :
332 :
333 : /****************************************************************************/
|