1 /****************************************************************************/
2 // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.org/sumo
3 // Copyright (C) 2017-2019 German Aerospace Center (DLR) and others.
4 // This program and the accompanying materials
5 // are made available under the terms of the Eclipse Public License v2.0
6 // which accompanies this distribution, and is available at
7 // http://www.eclipse.org/legal/epl-v20.html
8 // SPDX-License-Identifier: EPL-2.0
9 /****************************************************************************/
10 /// @file Polygon.cpp
11 /// @author Gregor L\"ammel
12 /// @date 15.03.2017
13 /// @version $Id$
14 ///
15 // C++ TraCI client API implementation
16 /****************************************************************************/
17
18
19 // ===========================================================================
20 // included modules
21 // ===========================================================================
22 #include <microsim/MSNet.h>
23 #include <microsim/MSEventControl.h>
24 #include <microsim/MSVehicleControl.h>
25 #include <microsim/MSTransportableControl.h>
26 #include <microsim/MSDynamicShapeUpdater.h>
27 #include <libsumo/TraCIConstants.h>
28 #include <utils/shapes/SUMOPolygon.h>
29 #include <utils/shapes/PolygonDynamics.h>
30 #include <utils/shapes/ShapeContainer.h>
31 #include <utils/common/ParametrisedWrappingCommand.h>
32
33 #include "Polygon.h"
34 #include "Helper.h"
35
36
37 namespace libsumo {
38 // ===========================================================================
39 // static member initializations
40 // ===========================================================================
41 SubscriptionResults Polygon::mySubscriptionResults;
42 ContextSubscriptionResults Polygon::myContextSubscriptionResults;
43
44
45 // ===========================================================================
46 // static member definitions
47 // ===========================================================================
48 std::vector<std::string>
getIDList()49 Polygon::getIDList() {
50 std::vector<std::string> ids;
51 ShapeContainer& shapeCont = MSNet::getInstance()->getShapeContainer();
52 shapeCont.getPolygons().insertIDs(ids);
53 return ids;
54 }
55
56
57 int
getIDCount()58 Polygon::getIDCount() {
59 return (int)getIDList().size();
60 }
61
62
63 std::string
getType(const std::string & polygonID)64 Polygon::getType(const std::string& polygonID) {
65 return getPolygon(polygonID)->getShapeType();
66 }
67
68
69 TraCIPositionVector
getShape(const std::string & polygonID)70 Polygon::getShape(const std::string& polygonID) {
71 SUMOPolygon* p = getPolygon(polygonID);
72 return Helper::makeTraCIPositionVector(p->getShape());
73 }
74
75
76 bool
getFilled(const std::string & polygonID)77 Polygon::getFilled(const std::string& polygonID) {
78 return getPolygon(polygonID)->getFill();
79 }
80
81 double
getLineWidth(const std::string & polygonID)82 Polygon::getLineWidth(const std::string& polygonID) {
83 return getPolygon(polygonID)->getLineWidth();
84 }
85
86 TraCIColor
getColor(const std::string & polygonID)87 Polygon::getColor(const std::string& polygonID) {
88 SUMOPolygon* p = getPolygon(polygonID);
89 return Helper::makeTraCIColor(p->getShapeColor());
90 }
91
92
93 std::string
getParameter(const std::string & polygonID,const std::string & key)94 Polygon::getParameter(const std::string& polygonID, const std::string& key) {
95 return getPolygon(polygonID)->getParameter(key, "");
96 }
97
98
99 void
setType(const std::string & polygonID,const std::string & setType)100 Polygon::setType(const std::string& polygonID, const std::string& setType) {
101 SUMOPolygon* p = getPolygon(polygonID);
102 p->setShapeType(setType);
103 }
104
105
106 void
setShape(const std::string & polygonID,const TraCIPositionVector & shape)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
setColor(const std::string & polygonID,const TraCIColor & c)116 Polygon::setColor(const std::string& polygonID, const TraCIColor& c) {
117 getPolygon(polygonID)->setShapeColor(Helper::makeRGBColor(c));
118 }
119
120
121 void
add(const std::string & polygonID,const TraCIPositionVector & shape,const TraCIColor & color,bool fill,double lineWidth,const std::string & polygonType,int layer)122 Polygon::add(const std::string& polygonID, const TraCIPositionVector& shape, const TraCIColor& color, bool fill, double lineWidth, const std::string& polygonType, int layer) {
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, Shape::DEFAULT_RELATIVEPATH, pShape, false, fill, lineWidth)) {
127 throw TraCIException("Could not add polygon '" + polygonID + "'");
128 }
129 }
130
131 void
addHighlightPolygon(const std::string & objectID,const int type,const std::string & polygonID,const TraCIPositionVector & shape,const TraCIColor & color,bool fill,double lineWidth,const std::string & polygonType,int layer)132 Polygon::addHighlightPolygon(const std::string& objectID, const int type, const std::string& polygonID, const TraCIPositionVector& shape, const TraCIColor& color, bool fill, double lineWidth, const std::string& polygonType, int layer) {
133 MSNet::getInstance()->getShapeContainer().registerHighlight(objectID, type, polygonID);
134 add(polygonID, shape, color, fill, lineWidth, polygonType, layer);
135 }
136
137 void
addDynamics(const std::string & polygonID,const std::string & trackedID,const std::vector<double> & timeSpan,const std::vector<double> & alphaSpan,bool looped,bool rotate)138 Polygon::addDynamics(const std::string& polygonID, const std::string& trackedID, const std::vector<double>& timeSpan, const std::vector<double>& alphaSpan, bool looped, bool rotate) {
139 if (timeSpan.empty()) {
140 if (trackedID == "") {
141 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).");
142 }
143 if (looped) {
144 throw TraCIException("Could not add polygon dynamics for polygon '" + polygonID + "': looped==true requires time line of positive length.");
145 }
146 }
147 if (timeSpan.size() == 1) {
148 throw TraCIException("Could not add polygon dynamics for polygon '" + polygonID + "': time span cannot have length one.");
149 } else if (timeSpan.size() > 0 && timeSpan[0] != 0.0) {
150 throw TraCIException("Could not add polygon dynamics for polygon '" + polygonID + "': first element of time span must be zero.");
151 }
152 if (timeSpan.size() != alphaSpan.size() && alphaSpan.size() != 0) {
153 throw TraCIException("Could not add polygon dynamics for polygon '" + polygonID + "': alpha span must have length zero or equal to time span length.");
154 }
155 if (timeSpan.size() >= 2) {
156 for (unsigned int i = 1; i < timeSpan.size(); ++i) {
157 if (timeSpan[i - 1] > timeSpan[i]) {
158 throw TraCIException("Could not add polygon dynamics for polygon '" + polygonID + "': entries of time span must be ordered ascendingly.");
159 }
160 }
161 }
162
163 SUMOTrafficObject* obj = getTrafficObject(trackedID);
164 ShapeContainer& shapeCont = MSNet::getInstance()->getShapeContainer();
165 PolygonDynamics* pd = shapeCont.addPolygonDynamics(SIMTIME, polygonID, obj, timeSpan, alphaSpan, looped, rotate);
166 if (pd == nullptr) {
167 throw TraCIException("Could not add polygon dynamics for polygon '" + polygonID + "': polygon doesn't exist.");
168 }
169 // Ensure existence of a DynamicShapeUpdater
170 if (MSNet::getInstance()->getDynamicShapeUpdater() == nullptr) {
171 MSNet::VehicleStateListener* listener = dynamic_cast<MSNet::VehicleStateListener*>(MSNet::getInstance()->makeDynamicShapeUpdater());
172 MSNet::getInstance()->addVehicleStateListener(listener);
173 }
174
175 // Schedule the regular polygon update
176 auto cmd = new ParametrisedWrappingCommand<ShapeContainer, PolygonDynamics*>(&shapeCont, pd, &ShapeContainer::polygonDynamicsUpdate);
177 shapeCont.addPolygonUpdateCommand(pd->getPolygonID(), cmd);
178 MSNet::getInstance()->getEndOfTimestepEvents()->addEvent(cmd, SIMSTEP + DELTA_T);
179 }
180
181
182 void
remove(const std::string & polygonID,int)183 Polygon::remove(const std::string& polygonID, int /* layer */) {
184 // !!! layer not used yet (shouldn't the id be enough?)
185 ShapeContainer& shapeCont = MSNet::getInstance()->getShapeContainer();
186 if (!shapeCont.removePolygon(polygonID)) {
187 throw TraCIException("Could not remove polygon '" + polygonID + "'");
188 }
189 }
190
191
192 void
setFilled(std::string polygonID,bool filled)193 Polygon::setFilled(std::string polygonID, bool filled) {
194 SUMOPolygon* p = getPolygon(polygonID);
195 p->setFill(filled);
196 }
197
198 void
setLineWidth(std::string polygonID,double lineWidth)199 Polygon::setLineWidth(std::string polygonID, double lineWidth) {
200 SUMOPolygon* p = getPolygon(polygonID);
201 p->setLineWidth(lineWidth);
202 }
203
204
205 SUMOPolygon*
getPolygon(const std::string & id)206 Polygon::getPolygon(const std::string& id) {
207 SUMOPolygon* p = MSNet::getInstance()->getShapeContainer().getPolygons().get(id);
208 if (p == nullptr) {
209 throw TraCIException("Polygon '" + id + "' is not known");
210 }
211 return p;
212 }
213
214
215 SUMOTrafficObject*
getTrafficObject(const std::string & id)216 Polygon::getTrafficObject(const std::string& id) {
217 if (id == "") {
218 return nullptr;
219 }
220 MSNet* net = MSNet::getInstance();
221 // First try to find a vehicle with the given id
222 SUMOVehicle* sumoVehicle = net->getVehicleControl().getVehicle(id);
223 if (sumoVehicle != nullptr) {
224 return static_cast<SUMOTrafficObject*>(sumoVehicle);
225 }
226 MSTransportable* transportable = net->getPersonControl().get(id);
227 if (transportable != nullptr) {
228 return static_cast<SUMOTrafficObject*>(transportable);
229 } else {
230 throw TraCIException("Traffic object '" + id + "' is not known");
231 }
232 }
233
234
235 void
setParameter(const std::string & polygonID,const std::string & key,const std::string & value)236 Polygon::setParameter(const std::string& polygonID, const std::string& key, const std::string& value) {
237 SUMOPolygon* p = getPolygon(polygonID);
238 p->setParameter(key, value);
239 }
240
241
LIBSUMO_SUBSCRIPTION_IMPLEMENTATION(Polygon,POLYGON)242 LIBSUMO_SUBSCRIPTION_IMPLEMENTATION(Polygon, POLYGON)
243
244
245 NamedRTree*
246 Polygon::getTree() {
247 NamedRTree* t = new NamedRTree();
248 ShapeContainer& shapeCont = MSNet::getInstance()->getShapeContainer();
249 for (const auto& i : shapeCont.getPolygons()) {
250 Boundary b = i.second->getShape().getBoxBoundary();
251 const float cmin[2] = {(float) b.xmin(), (float) b.ymin()};
252 const float cmax[2] = {(float) b.xmax(), (float) b.ymax()};
253 t->Insert(cmin, cmax, i.second);
254 }
255 return t;
256 }
257
258
259 void
storeShape(const std::string & id,PositionVector & shape)260 Polygon::storeShape(const std::string& id, PositionVector& shape) {
261 shape = getPolygon(id)->getShape();
262 }
263
264
265 std::shared_ptr<VariableWrapper>
makeWrapper()266 Polygon::makeWrapper() {
267 return std::make_shared<Helper::SubscriptionWrapper>(handleVariable, mySubscriptionResults, myContextSubscriptionResults);
268 }
269
270
271 bool
handleVariable(const std::string & objID,const int variable,VariableWrapper * wrapper)272 Polygon::handleVariable(const std::string& objID, const int variable, VariableWrapper* wrapper) {
273 switch (variable) {
274 case TRACI_ID_LIST:
275 return wrapper->wrapStringList(objID, variable, getIDList());
276 case ID_COUNT:
277 return wrapper->wrapInt(objID, variable, getIDCount());
278 case VAR_TYPE:
279 return wrapper->wrapString(objID, variable, getType(objID));
280 case VAR_COLOR:
281 return wrapper->wrapColor(objID, variable, getColor(objID));
282 case VAR_FILL:
283 return wrapper->wrapInt(objID, variable, getFilled(objID));
284 case VAR_WIDTH:
285 return wrapper->wrapDouble(objID, variable, getLineWidth(objID));
286 default:
287 return false;
288 }
289 }
290
291
292 bool
exists(std::string polyID)293 Polygon::exists(std::string polyID) {
294 SUMOPolygon* p = MSNet::getInstance()->getShapeContainer().getPolygons().get(polyID);
295 return p != nullptr;
296 }
297
298 }
299
300
301 /****************************************************************************/
302