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