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