1 /****************************************************************************/
2 // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.org/sumo
3 // Copyright (C) 2002-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    ShapeContainer.cpp
11 /// @author  Daniel Krajzewicz
12 /// @author  Sascha Krieg
13 /// @author  Michael Behrisch
14 /// @author  Jakob Erdmann
15 /// @date    Sept 2002
16 /// @version $Id$
17 ///
18 // Storage for geometrical objects, sorted by the layers they are in
19 /****************************************************************************/
20 
21 
22 // ===========================================================================
23 // included modules
24 // ===========================================================================
25 #include <config.h>
26 
27 #include <fstream>
28 #include <stdlib.h>
29 #include <iostream>
30 #include <utility>
31 #include <string>
32 #include <cmath>
33 #include <utils/common/NamedObjectCont.h>
34 #include <utils/common/MsgHandler.h>
35 #include <utils/common/UtilExceptions.h>
36 #include <utils/common/ToString.h>
37 #include <utils/common/StdDefs.h>
38 #include <utils/common/ParametrisedWrappingCommand.h>
39 #include "PolygonDynamics.h"
40 #include "ShapeContainer.h"
41 
42 
43 // Debug defines
44 //#define DEBUG_DYNAMIC_SHAPES
45 
46 // ===========================================================================
47 // method definitions
48 // ===========================================================================
ShapeContainer()49 ShapeContainer::ShapeContainer() {}
50 
~ShapeContainer()51 ShapeContainer::~ShapeContainer() {
52     for (auto& p : myPolygonUpdateCommands) {
53         p.second->deschedule();
54     }
55     myPolygonUpdateCommands.clear();
56 
57     for (auto& p : myPolygonDynamics) {
58         delete p.second;
59     }
60     myPolygonDynamics.clear();
61 
62 }
63 
64 bool
addPolygon(const std::string & id,const std::string & type,const RGBColor & color,double layer,double angle,const std::string & imgFile,bool relativePath,const PositionVector & shape,bool geo,bool fill,double lineWidth,bool ignorePruning)65 ShapeContainer::addPolygon(const std::string& id, const std::string& type,
66                            const RGBColor& color, double layer,
67                            double angle, const std::string& imgFile, bool relativePath,
68                            const PositionVector& shape, bool geo, bool fill, double lineWidth, bool ignorePruning) {
69     return add(new SUMOPolygon(id, type, color, shape, geo, fill, lineWidth, layer, angle, imgFile, relativePath), ignorePruning);
70 }
71 
72 
73 PolygonDynamics*
addPolygonDynamics(double simtime,std::string polyID,SUMOTrafficObject * trackedObject,const std::vector<double> & timeSpan,const std::vector<double> & alphaSpan,bool looped,bool rotate)74 ShapeContainer::addPolygonDynamics(double simtime,
75                                    std::string polyID,
76                                    SUMOTrafficObject* trackedObject,
77                                    const std::vector<double>& timeSpan,
78                                    const std::vector<double>& alphaSpan,
79                                    bool looped,
80                                    bool rotate) {
81 
82 #ifdef DEBUG_DYNAMIC_SHAPES
83     std::cout << simtime << " ShapeContainer::addPolygonDynamics() called for polygon '" << polyID << "'" << std::endl;
84 #endif
85 
86     SUMOPolygon* p = myPolygons.get(polyID);
87     if (p == nullptr) {
88 #ifdef DEBUG_DYNAMIC_SHAPES
89         std::cout << "   polygon '" << polyID << "' doesn't exist!" << std::endl;
90 #endif
91         return nullptr;
92     }
93     // remove eventually existent previously assigne dynamics
94     removePolygonDynamics(polyID);
95 
96     // Add new dynamics
97     PolygonDynamics* pd = new PolygonDynamics(simtime, p, trackedObject, timeSpan, alphaSpan, looped, rotate);
98     myPolygonDynamics.insert(std::make_pair(polyID, pd));
99 
100     // Add tracking information
101     if (trackedObject != nullptr) {
102         auto i = myTrackingPolygons.find(pd->getTrackedObjectID());
103         if (i == myTrackingPolygons.end()) {
104             myTrackingPolygons.insert(std::make_pair(pd->getTrackedObjectID(), std::set<const SUMOPolygon*>({p})));
105         } else {
106             i->second.insert(p);
107         }
108     }
109     return pd;
110 }
111 
112 
113 bool
removePolygonDynamics(const std::string & polyID)114 ShapeContainer::removePolygonDynamics(const std::string& polyID) {
115     SUMOPolygon* p = myPolygons.get(polyID);
116     if (p == nullptr) {
117         return false;
118     }
119     auto d = myPolygonDynamics.find(polyID);
120     if (d != myPolygonDynamics.end()) {
121 #ifdef DEBUG_DYNAMIC_SHAPES
122         std::cout << "   Removing dynamics of polygon '" << polyID << "'" << std::endl;
123 #endif
124         const std::string& trackedObjID = d->second->getTrackedObjectID();
125         if (trackedObjID != "") {
126             // Remove tracking information
127             auto i = myTrackingPolygons.find(trackedObjID);
128             assert(i != myTrackingPolygons.end());
129             assert(i->second.find(p) != i->second.end());
130             i->second.erase(p);
131             // Remove highlighting information
132             clearHighlights(trackedObjID);
133         }
134         delete d->second;
135         myPolygonDynamics.erase(d);
136         // Clear existing polygon dynamics commands before adding new dynamics
137         cleanupPolygonDynamics(polyID);
138         return true;
139     } else {
140         return false;
141     }
142 }
143 
144 
145 bool
addPOI(const std::string & id,const std::string & type,const RGBColor & color,const Position & pos,bool geo,const std::string & lane,double posOverLane,double posLat,double layer,double angle,const std::string & imgFile,bool relativePath,double width,double height,bool ignorePruning)146 ShapeContainer::addPOI(const std::string& id, const std::string& type, const RGBColor& color, const Position& pos, bool geo,
147                        const std::string& lane, double posOverLane, double posLat, double layer, double angle,
148                        const std::string& imgFile, bool relativePath, double width, double height, bool ignorePruning) {
149     return add(new PointOfInterest(id, type, color, pos, geo, lane, posOverLane, posLat, layer, angle, imgFile, relativePath, width, height), ignorePruning);
150 }
151 
152 
153 bool
removePolygon(const std::string & id,bool)154 ShapeContainer::removePolygon(const std::string& id, bool /* useLock */) {
155 #ifdef DEBUG_DYNAMIC_SHAPES
156     std::cout << "ShapeContainer: Removing Polygon '" << id << "'" << std::endl;
157 #endif
158     removePolygonDynamics(id);
159     return myPolygons.remove(id);
160 }
161 
162 
163 bool
removePOI(const std::string & id)164 ShapeContainer::removePOI(const std::string& id) {
165     return myPOIs.remove(id);
166 }
167 
168 
169 void
movePOI(const std::string & id,const Position & pos)170 ShapeContainer::movePOI(const std::string& id, const Position& pos) {
171     PointOfInterest* p = myPOIs.get(id);
172     if (p != nullptr) {
173         static_cast<Position*>(p)->set(pos);
174     }
175 }
176 
177 
178 void
reshapePolygon(const std::string & id,const PositionVector & shape)179 ShapeContainer::reshapePolygon(const std::string& id, const PositionVector& shape) {
180     SUMOPolygon* p = myPolygons.get(id);
181     if (p != nullptr) {
182         p->setShape(shape);
183     }
184 }
185 
186 
187 bool
add(SUMOPolygon * poly,bool)188 ShapeContainer::add(SUMOPolygon* poly, bool /* ignorePruning */) {
189     if (!myPolygons.add(poly->getID(), poly)) {
190         delete poly;
191         return false;
192     }
193     return true;
194 }
195 
196 
197 bool
add(PointOfInterest * poi,bool)198 ShapeContainer::add(PointOfInterest* poi, bool /* ignorePruning */) {
199     if (!myPOIs.add(poi->getID(), poi)) {
200         delete poi;
201         return false;
202     }
203     return true;
204 }
205 
206 
207 void
cleanupPolygonDynamics(const std::string & id)208 ShapeContainer::cleanupPolygonDynamics(const std::string& id) {
209     auto j = myPolygonUpdateCommands.find(id);
210     if (j != myPolygonUpdateCommands.end()) {
211         j->second->deschedule();
212         myPolygonUpdateCommands.erase(j);
213     }
214 }
215 
216 
217 SUMOTime
polygonDynamicsUpdate(SUMOTime t,PolygonDynamics * pd)218 ShapeContainer::polygonDynamicsUpdate(SUMOTime t, PolygonDynamics* pd) {
219     SUMOTime next = pd->update(t);
220     if (next == 0) {
221         // Dynamics have expired => remove polygon
222         myPolygonUpdateCommands[pd->getPolygonID()]->deschedule();
223         // Don't aquire lock (in GUI case GUIShapeContainer::polygonDynamicsUpdate() does this)
224         removePolygon(pd->getPolygonID(), false);
225     }
226     return next;
227 }
228 
229 void
registerHighlight(const std::string & objectID,const int type,const std::string & polygonID)230 ShapeContainer::registerHighlight(const std::string& objectID, const int type, const std::string& polygonID) {
231     std::string toRemove = "";
232     clearHighlight(objectID, type, toRemove);
233     if (toRemove != "") {
234         removePolygon(toRemove);
235     }
236     auto i = myHighlightPolygons.find(objectID);
237     if (i == myHighlightPolygons.end()) {
238         myHighlightPolygons.insert(std::make_pair(objectID, std::map<int, std::string>({std::make_pair(type, polygonID)})));
239     } else {
240         i->second.insert(std::make_pair(type, polygonID));
241     }
242     myHighlightedObjects.insert(std::make_pair(polygonID, objectID));
243 }
244 
245 void
clearHighlight(const std::string & objectID,const int type,std::string & toRemove)246 ShapeContainer::clearHighlight(const std::string& objectID, const int type, std::string& toRemove) {
247     auto i = myHighlightPolygons.find(objectID);
248     if (i != myHighlightPolygons.end()) {
249         auto j = i->second.find(type);
250         if (j != i->second.end()) {
251             toRemove = j->second;
252             myHighlightedObjects.erase(toRemove);
253             i->second.erase(j);
254             if (i->second.empty()) {
255                 myHighlightPolygons.erase(i);
256             }
257         }
258     }
259 }
260 
261 void
clearHighlights(const std::string & objectID)262 ShapeContainer::clearHighlights(const std::string& objectID) {
263     auto i = myHighlightPolygons.find(objectID);
264     if (i != myHighlightPolygons.end()) {
265         myHighlightPolygons.erase(i);
266     }
267 }
268 
269 void
addPolygonUpdateCommand(std::string polyID,ParametrisedWrappingCommand<ShapeContainer,PolygonDynamics * > * cmd)270 ShapeContainer::addPolygonUpdateCommand(std::string polyID, ParametrisedWrappingCommand<ShapeContainer, PolygonDynamics*>* cmd) {
271     myPolygonUpdateCommands.insert(std::make_pair(polyID, cmd));
272 }
273 
274 
275 void
removeTrackers(std::string objectID)276 ShapeContainer::removeTrackers(std::string objectID) {
277     auto i = myTrackingPolygons.find(objectID);
278     if (i != myTrackingPolygons.end()) {
279 #ifdef DEBUG_DYNAMIC_SHAPES
280         std::cout << " Removing tracking polygons for object '" << objectID << "'" << std::endl;
281 #endif
282         for (const SUMOPolygon* p : i->second) {
283             removePolygon(p->getID());
284         }
285         myTrackingPolygons.erase(i);
286     }
287 }
288 
289 /****************************************************************************/
290 
291