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