LCOV - code coverage report
Current view: top level - src/foreign/rtree - SUMORTree.h (source / functions) Coverage Total Hit
Test: lcov.info Lines: 69.8 % 63 44
Test Date: 2025-11-13 15:38:19 Functions: 100.0 % 8 8

            Line data    Source code
       1              : /****************************************************************************/
       2              : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
       3              : // Copyright (C) 2001-2025 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    SUMORTree.h
      15              : /// @author  Daniel Krajzewicz
      16              : /// @date    27.10.2008
      17              : ///
      18              : // A RT-tree for efficient storing of SUMO's GL-objects
      19              : /****************************************************************************/
      20              : #pragma once
      21              : #include <config.h>
      22              : 
      23              : #include <utils/foxtools/fxheader.h>
      24              : #include <utils/common/MsgHandler.h>
      25              : #include <utils/geom/Boundary.h>
      26              : #include <utils/gui/globjects/GUIGlObject.h>
      27              : #include <utils/gui/settings/GUIVisualizationSettings.h>
      28              : #include <utils/gui/div/GUIIOGlobals.h>
      29              : 
      30              : #include "RTree.h"
      31              : 
      32              : 
      33              : #define GUI_RTREE_QUAL RTree<GUIGlObject*, GUIGlObject, float, 2, GUIVisualizationSettings>
      34              : 
      35              : // specialized implementation for speedup and avoiding warnings
      36              : 
      37              : template<>
      38              : inline float GUI_RTREE_QUAL::RectSphericalVolume(Rect* a_rect) {
      39              :   ASSERT(a_rect);
      40     11327421 :   const float extent0 = a_rect->m_max[0] - a_rect->m_min[0];
      41     11327421 :   const float extent1 = a_rect->m_max[1] - a_rect->m_min[1];
      42      7784423 :   return .78539816f * (extent0 * extent0 + extent1 * extent1);
      43              : }
      44              : 
      45              : template<>
      46              : inline GUI_RTREE_QUAL::Rect GUI_RTREE_QUAL::CombineRect(Rect* a_rectA, Rect* a_rectB) {
      47              :     ASSERT(a_rectA && a_rectB);
      48              :     Rect newRect;
      49     10986705 :     newRect.m_min[0] = rtree_min(a_rectA->m_min[0], a_rectB->m_min[0]);
      50     10986705 :     newRect.m_max[0] = rtree_max(a_rectA->m_max[0], a_rectB->m_max[0]);
      51     10986705 :     newRect.m_min[1] = rtree_min(a_rectA->m_min[1], a_rectB->m_min[1]);
      52     10986705 :     newRect.m_max[1] = rtree_max(a_rectA->m_max[1], a_rectB->m_max[1]);
      53              :     return newRect;
      54              : }
      55              : 
      56              : 
      57              : // ===========================================================================
      58              : // class definitions
      59              : // ===========================================================================
      60              : /** @class SUMORTree
      61              :  * @brief A RT-tree for efficient storing of SUMO's GL-objects
      62              :  *
      63              :  * This class specialises the used RT-tree implementation from "rttree.h" and
      64              :  *  extends it by a mutex for avoiding parallel change and traversal of the tree.
      65              :  */
      66              : class SUMORTree : private GUI_RTREE_QUAL, public Boundary {
      67              : public:
      68              :     /// @brief Constructor
      69        31884 :     SUMORTree() :
      70              :         GUI_RTREE_QUAL(&GUIGlObject::drawGL),
      71        31884 :         myLock(true) {
      72        31884 :     }
      73              : 
      74              :     /// @brief Destructor
      75        47730 :     virtual ~SUMORTree() {
      76              :         // check if lock is locked before insert objects
      77        31820 :         if (myLock.locked()) {
      78              :             // cannot throw exception in destructor
      79            0 :             WRITE_ERROR("Mutex of SUMORTree is locked during call of the destructor");
      80              :         }
      81        47730 :     }
      82              : 
      83              :     /** @brief Insert entry
      84              :      * @param a_min Min of bounding rect
      85              :      * @param a_max Max of bounding rect
      86              :      * @param a_dataId Positive Id of data.  Maybe zero, but negative numbers not allowed.
      87              :      * @see RTree::Insert
      88              :      */
      89       444916 :     virtual void Insert(const float a_min[2], const float a_max[2], GUIGlObject* const & a_dataId) {
      90       444916 :         FXMutexLock locker(myLock);
      91       444916 :         GUI_RTREE_QUAL::Insert(a_min, a_max, a_dataId);
      92       444916 :     }
      93              : 
      94              :     /** @brief Remove entry
      95              :      * @param a_min Min of bounding rect
      96              :      * @param a_max Max of bounding rect
      97              :      * @param a_dataId Positive Id of data.  Maybe zero, but negative numbers not allowed.
      98              :      * @see RTree::Remove
      99              :      */
     100         2387 :     virtual void Remove(const float a_min[2], const float a_max[2], GUIGlObject* const & a_dataId) {
     101         2387 :         FXMutexLock locker(myLock);
     102         2387 :         GUI_RTREE_QUAL::Remove(a_min, a_max, a_dataId);
     103         2387 :     }
     104              : 
     105              :     /** @brief Find all within search rectangle
     106              :      * @param a_min Min of search bounding rect
     107              :      * @param a_max Max of search bounding rect
     108              :      * @param a_searchResult Search result array.  Caller should set grow size. Function will reset, not append to array.
     109              :      * @param a_resultCallback Callback function to return result.  Callback should return 'true' to continue searching
     110              :      * @param a_context User context to pass as parameter to a_resultCallback
     111              :      * @return Returns the number of entries found
     112              :      * @see RTree::Search
     113              :      */
     114      1294149 :     virtual int Search(const float a_min[2], const float a_max[2], const GUIVisualizationSettings& c) const {
     115      1294149 :         FXMutexLock locker(myLock);
     116      2588297 :         return GUI_RTREE_QUAL::Search(a_min, a_max, c);
     117              :     }
     118              : 
     119              :     /** @brief Adds an additional object (detector/shape/trigger) for visualisation
     120              :      * @param[in] o The object to add
     121              :      */
     122        28843 :     void addAdditionalGLObject(GUIGlObject *o, const double exaggeration = 1) {
     123              :         // check if lock is locked before insert objects
     124        28843 :         if (myLock.locked()) {
     125            0 :             throw ProcessError("Mutex of SUMORTree is locked before object insertion");
     126              :         }
     127              :         // lock mutex
     128              :         FXMutexLock locker(myLock);
     129              :         // obtain boundary of object
     130        28843 :         Boundary b = o->getCenteringBoundary();
     131              :         // grow using exaggeration
     132        28843 :         if (exaggeration > 1) {
     133            0 :             b.scale(exaggeration);
     134              :         }
     135              :         // show information in gui testing debug gl mode
     136        28843 :         if (MsgHandler::writeDebugGLMessages()) {
     137            0 :             if (!b.isInitialised()) {
     138            0 :                 throw ProcessError(StringUtils::format("Boundary of GUIGlObject % is not initialised (insertion)", o->getMicrosimID()));
     139            0 :             } else if ((b.getWidth() == 0) || (b.getHeight() == 0)) {
     140            0 :                 throw ProcessError(StringUtils::format("Boundary of GUIGlObject % has an invalid size (insertion)", o->getMicrosimID()));
     141              :             } else if (myTreeDebug.count(o) > 0) {
     142            0 :                 throw ProcessError("GUIGlObject was already inserted");
     143              :             } else {
     144            0 :                 myTreeDebug[o] = b;
     145              :             }
     146              :         }
     147              :         // insert it in Tree
     148        28843 :         const float cmin[2] = {(float) b.xmin(), (float) b.ymin()};
     149        28843 :         const float cmax[2] = {(float) b.xmax(), (float) b.ymax()};
     150        28843 :         Insert(cmin, cmax, o);
     151              :         // update tree size
     152        28843 :         myTreeSize++;
     153        28843 :     }
     154              : 
     155              :     /** @brief Removes an additional object (detector/shape/trigger) from being visualised
     156              :      * @param[in] o The object to remove
     157              :      */
     158         2387 :     void removeAdditionalGLObject(GUIGlObject *o, const double exaggeration = 1) {
     159              :         // check if lock is locked remove insert objects
     160         2387 :         if (myLock.locked()) {
     161            0 :             throw ProcessError("Mutex of SUMORTree is locked before object remove");
     162              :         }
     163              :         // lock mutex
     164              :         FXMutexLock locker(myLock);
     165              :         // obtain boundary of object
     166         2387 :         Boundary b = o->getCenteringBoundary();
     167              :         // grow using exaggeration
     168         2387 :         if (exaggeration > 1) {
     169            0 :             b.scale(exaggeration);
     170              :         }
     171              :         // show information in gui testing debug gl mode
     172         2387 :         if (MsgHandler::writeDebugGLMessages()) {
     173            0 :             if (!b.isInitialised()) {
     174            0 :                 throw ProcessError(StringUtils::format("Boundary of GUIGlObject % is not initialised (deletion)", o->getMicrosimID()));
     175            0 :             } else if ((b.getWidth() == 0) || (b.getHeight() == 0)) {
     176            0 :                 throw ProcessError(StringUtils::format("Boundary of GUIGlObject % has an invalid size (deletion)", o->getMicrosimID()));
     177              :             } else if (myTreeDebug.count(o) == 0) {
     178            0 :                 throw ProcessError("GUIGlObject wasn't inserted");
     179            0 :             } else if (toString(b) != toString(myTreeDebug.at(o))) {
     180              :                 // show information in console before throwing exception
     181            0 :                 std::cout << "Tree: " << toString(myTreeDebug.at(o)) << " original: " << toString(b) << std::endl;
     182            0 :                 throw ProcessError("add boundary of GUIGlObject " + o->getMicrosimID() + " is different of removed boundary (" + toString(b) + " != " + toString(myTreeDebug.at(o)) + ")");
     183              :             } else {
     184              :                 myTreeDebug.erase(o);
     185              :             }
     186              :         }
     187              :         // remove it from Tree
     188         2387 :         const float cmin[2] = {(float) b.xmin(), (float) b.ymin()};
     189         2387 :         const float cmax[2] = {(float) b.xmax(), (float) b.ymax()};
     190         2387 :         Remove(cmin, cmax, o);
     191              :         // update tree size
     192         2387 :         myTreeSize--;
     193         2387 :     }
     194              : 
     195              :     /// @brief update boundaries
     196              :     void updateBoundaries(GUIGlObjectType type) {
     197              :         // declare vector with glObjects to update
     198              :         std::vector<GUIGlObject*> glObjects;
     199              :         glObjects.reserve(myTreeSize);
     200              :         // declare iterator
     201              :         GUI_RTREE_QUAL::Iterator it;
     202              :         GetFirst(it);
     203              :         // iterate over entire tree and keep glObject in glObjects
     204              :         while (!IsNull(it)) {
     205              :             const auto glType = (*it)->getType();
     206              :             if ((glType == type) ||
     207              :                 ((glType > GLO_ADDITIONALELEMENT) && (glType < GLO_SHAPE)) ||   // Additionals
     208              :                 ((glType >= GLO_TAZ) && (glType < GLO_LOCKICON))) {             // TAZ Elements
     209              :                 glObjects.push_back(*it);
     210              :             }
     211              :             GetNext(it);
     212              :         }
     213              :         // remove and insert all elements again with the new boundary
     214              :         for (const auto &glObject : glObjects) {
     215              :             removeAdditionalGLObject(glObject);
     216              :             removeObjectFromTreeDebug(glObject);
     217              :             addAdditionalGLObject(glObject);
     218              :         }
     219              :     }
     220              : 
     221              : protected:
     222              :     /// @brief A mutex avoiding parallel change and traversal of the tree
     223              :     mutable FXMutex myLock;
     224              : 
     225              :     /// @brief number of inserted elements
     226              :     int myTreeSize = 0;
     227              : 
     228              : private:
     229              :     /**@brief Map only used for check that SUMORTree works as expected, only is used if option "gui-testing-debug-gl" is enabled.
     230              :      * @note Warning: DO NOT USE in release mode and use it in debug mode carefully, due it produces a slowdown.
     231              :      */
     232              :     std::map<GUIGlObject*, Boundary> myTreeDebug;
     233              : 
     234              :     /// @brief remove object from TreeDebug
     235              :     bool removeObjectFromTreeDebug(const GUIGlObject* obj) {
     236              :         for (auto it = myTreeDebug.begin(); it != myTreeDebug.end(); it++) {
     237              :             if (it->first == obj) {
     238              :                 myTreeDebug.erase(it);
     239              :                 return true;
     240              :             }
     241              :         }
     242              :         return false;
     243              :     }
     244              : };
        

Generated by: LCOV version 2.0-1