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