Line data Source code
1 : /****************************************************************************/
2 : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3 : // Copyright (C) 2002-2026 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 :
38 : #include "PolygonDynamics.h"
39 : #include "ShapeContainer.h"
40 :
41 : // Debug defines
42 : //#define DEBUG_DYNAMIC_SHAPES
43 :
44 : // ===========================================================================
45 : // method definitions
46 : // ===========================================================================
47 :
48 43429 : ShapeContainer::ShapeContainer() {}
49 :
50 :
51 75038 : ShapeContainer::~ShapeContainer() {
52 42823 : for (auto& p : myPolygonUpdateCommands) {
53 5 : p.second->deschedule();
54 : }
55 : myPolygonUpdateCommands.clear();
56 :
57 42823 : for (auto& p : myPolygonDynamics) {
58 5 : delete p.second;
59 : }
60 : myPolygonDynamics.clear();
61 :
62 160674 : }
63 :
64 :
65 : bool
66 17032 : ShapeContainer::addPolygon(const std::string& id, const std::string& type, const RGBColor& color,
67 : double layer, double angle, const std::string& imgFile, const PositionVector& shape,
68 : bool geo, bool fill, double lineWidth, bool ignorePruning, const std::string& name) {
69 17032 : return add(new SUMOPolygon(id, type, color, shape, geo, fill, lineWidth, layer, angle, imgFile, name), ignorePruning);
70 : }
71 :
72 :
73 : PolygonDynamics*
74 158 : 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 158 : SUMOPolygon* p = myPolygons.get(polyID);
87 158 : 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
94 158 : removePolygonDynamics(polyID);
95 :
96 : // Add new dynamics
97 158 : PolygonDynamics* pd = new PolygonDynamics(simtime, p, trackedObject, timeSpan, alphaSpan, looped, rotate);
98 158 : myPolygonDynamics.insert(std::make_pair(polyID, pd));
99 :
100 : // Add tracking information
101 158 : if (trackedObject != nullptr) {
102 : auto i = myTrackingPolygons.find(pd->getTrackedObjectID());
103 113 : if (i == myTrackingPolygons.end()) {
104 120 : 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
114 299 : ShapeContainer::removePolygonDynamics(const std::string& polyID) {
115 299 : SUMOPolygon* p = myPolygons.get(polyID);
116 299 : if (p == nullptr) {
117 : return false;
118 : }
119 : auto d = myPolygonDynamics.find(polyID);
120 298 : if (d != myPolygonDynamics.end()) {
121 : #ifdef DEBUG_DYNAMIC_SHAPES
122 : std::cout << " Removing dynamics of polygon '" << polyID << "'" << std::endl;
123 : #endif
124 153 : const std::string& trackedObjID = d->second->getTrackedObjectID();
125 153 : 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 113 : clearHighlights(trackedObjID, p);
133 : }
134 153 : delete d->second;
135 : myPolygonDynamics.erase(d);
136 : // Clear existing polygon dynamics commands before adding new dynamics
137 153 : cleanupPolygonDynamics(polyID);
138 153 : return true;
139 : } else {
140 : return false;
141 : }
142 : }
143 :
144 :
145 : bool
146 8077 : 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, bool friendlyPos, double posLat, const std::string& icon, double layer,
148 : double angle, const std::string& imgFile, double width, double height, bool ignorePruning) {
149 8077 : return add(new PointOfInterest(id, type, color, pos, geo, lane, posOverLane, friendlyPos, posLat, icon, layer, angle, imgFile, width, height), ignorePruning);
150 : }
151 :
152 :
153 : bool
154 141 : 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 141 : removePolygonDynamics(id);
159 : SUMOPolygon* p = myPolygons.get(id);
160 140 : if (p != nullptr) {
161 140 : for (ShapeListener* listener : myListeners) {
162 0 : listener->polygonChanged(p, false, true);
163 : }
164 : }
165 141 : return myPolygons.remove(id);
166 : }
167 :
168 :
169 : bool
170 10 : ShapeContainer::removePOI(const std::string& id) {
171 : PointOfInterest* p = myPOIs.get(id);
172 9 : if (p != nullptr) {
173 9 : for (ShapeListener* listener : myListeners) {
174 0 : listener->poiChanged(p, false, true);
175 : }
176 : }
177 10 : return myPOIs.remove(id);
178 : }
179 :
180 :
181 : void
182 5 : ShapeContainer::movePOI(const std::string& id, const Position& pos) {
183 : PointOfInterest* p = myPOIs.get(id);
184 5 : if (p != nullptr) {
185 5 : static_cast<Position*>(p)->set(pos);
186 5 : for (ShapeListener* listener : myListeners) {
187 0 : listener->poiChanged(p, false, false);
188 : }
189 : }
190 5 : }
191 :
192 :
193 : void
194 6 : ShapeContainer::reshapePolygon(const std::string& id, const PositionVector& shape) {
195 : SUMOPolygon* p = myPolygons.get(id);
196 6 : if (p != nullptr) {
197 6 : p->setShape(shape);
198 6 : for (ShapeListener* listener : myListeners) {
199 0 : listener->polygonChanged(p, false, false);
200 : }
201 : }
202 6 : }
203 :
204 :
205 : bool
206 20787 : ShapeContainer::add(SUMOPolygon* poly, bool /* ignorePruning */) {
207 20787 : if (!myPolygons.add(poly->getID(), poly)) {
208 0 : delete poly;
209 0 : return false;
210 : }
211 20787 : for (ShapeListener* listener : myListeners) {
212 0 : listener->polygonChanged(poly, true, false);
213 : }
214 : return true;
215 : }
216 :
217 :
218 : bool
219 10863 : ShapeContainer::add(PointOfInterest* poi, bool /* ignorePruning */) {
220 10863 : if (!myPOIs.add(poi->getID(), poi)) {
221 1 : delete poi;
222 1 : return false;
223 : }
224 10862 : for (ShapeListener* listener : myListeners) {
225 0 : listener->poiChanged(poi, true, false);
226 : }
227 : return true;
228 : }
229 :
230 : void
231 186 : ShapeContainer::clearState() {
232 186 : for (auto& item : myPolygonUpdateCommands) {
233 0 : item.second->deschedule();
234 : }
235 : myPolygonUpdateCommands.clear();
236 186 : }
237 :
238 : void
239 153 : ShapeContainer::cleanupPolygonDynamics(const std::string& id) {
240 : auto j = myPolygonUpdateCommands.find(id);
241 153 : if (j != myPolygonUpdateCommands.end()) {
242 153 : j->second->deschedule();
243 : myPolygonUpdateCommands.erase(j);
244 : }
245 153 : }
246 :
247 :
248 : SUMOTime
249 3438 : ShapeContainer::polygonDynamicsUpdate(SUMOTime t, PolygonDynamics* pd) {
250 3438 : SUMOTime next = pd->update(t);
251 3438 : if (next == 0) {
252 : // Dynamics have expired => remove polygon
253 87 : myPolygonUpdateCommands[pd->getPolygonID()]->deschedule();
254 : // Don't aquire lock (in GUI case GUIShapeContainer::polygonDynamicsUpdate() does this)
255 87 : removePolygon(pd->getPolygonID(), false);
256 : }
257 3438 : return next;
258 : }
259 :
260 : void
261 71 : ShapeContainer::registerHighlight(const std::string& objectID, const int type, const std::string& polygonID) {
262 71 : std::string toRemove = "";
263 71 : clearHighlight(objectID, type, toRemove);
264 71 : if (toRemove != "") {
265 11 : removePolygon(toRemove);
266 : }
267 : auto i = myHighlightPolygons.find(objectID);
268 71 : if (i == myHighlightPolygons.end()) {
269 396 : myHighlightPolygons.insert(std::make_pair(objectID, std::map<int, std::string>({std::make_pair(type, polygonID)})));
270 : } else {
271 15 : i->second.insert(std::make_pair(type, polygonID));
272 : }
273 142 : myHighlightedObjects.insert(std::make_pair(polygonID, objectID));
274 71 : }
275 :
276 : void
277 71 : ShapeContainer::clearHighlight(const std::string& objectID, const int type, std::string& toRemove) {
278 : auto i = myHighlightPolygons.find(objectID);
279 71 : if (i != myHighlightPolygons.end()) {
280 : auto j = i->second.find(type);
281 16 : if (j != i->second.end()) {
282 11 : toRemove = j->second;
283 : myHighlightedObjects.erase(toRemove);
284 : i->second.erase(j);
285 11 : if (i->second.empty()) {
286 : myHighlightPolygons.erase(i);
287 : }
288 : }
289 : }
290 71 : }
291 :
292 : void
293 113 : ShapeContainer::clearHighlights(const std::string& objectID, SUMOPolygon* p) {
294 : auto i = myHighlightPolygons.find(objectID);
295 113 : if (i != myHighlightPolygons.end()) {
296 : auto j = i->second.begin();
297 74 : while (j != i->second.end()) {
298 54 : if (j->second == p->getID()) {
299 : i->second.erase(j);
300 : break;
301 : } else {
302 : ++j;
303 : }
304 : }
305 54 : if (i->second.empty()) {
306 : myHighlightPolygons.erase(i);
307 : }
308 : }
309 113 : }
310 :
311 : void
312 158 : ShapeContainer::addPolygonUpdateCommand(std::string polyID, ParametrisedWrappingCommand<ShapeContainer, PolygonDynamics*>* cmd) {
313 158 : myPolygonUpdateCommands.insert(std::make_pair(polyID, cmd));
314 158 : }
315 :
316 :
317 : void
318 32 : ShapeContainer::removeTrackers(std::string objectID) {
319 : auto i = myTrackingPolygons.find(objectID);
320 32 : if (i != myTrackingPolygons.end()) {
321 : #ifdef DEBUG_DYNAMIC_SHAPES
322 : std::cout << " Removing tracking polygons for object '" << objectID << "'" << std::endl;
323 : #endif
324 48 : while (!i->second.empty()) {
325 16 : removePolygon((*i->second.begin())->getID());
326 : }
327 : myTrackingPolygons.erase(i);
328 : }
329 32 : }
330 :
331 :
332 : /****************************************************************************/
|