LCOV - code coverage report
Current view: top level - src/utils/shapes - ShapeContainer.cpp (source / functions) Coverage Total Hit
Test: lcov.info Lines: 91.7 % 109 100
Test Date: 2026-03-02 16:00:03 Functions: 100.0 % 21 21

            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              : /****************************************************************************/
        

Generated by: LCOV version 2.0-1