Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
eclipse
GitHub Repository: eclipse/sumo
Path: blob/main/src/foreign/rtree/SUMORTree.h
169678 views
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
const float extent0 = a_rect->m_max[0] - a_rect->m_min[0];
41
const float extent1 = a_rect->m_max[1] - a_rect->m_min[1];
42
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
newRect.m_min[0] = rtree_min(a_rectA->m_min[0], a_rectB->m_min[0]);
50
newRect.m_max[0] = rtree_max(a_rectA->m_max[0], a_rectB->m_max[0]);
51
newRect.m_min[1] = rtree_min(a_rectA->m_min[1], a_rectB->m_min[1]);
52
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
SUMORTree() :
70
GUI_RTREE_QUAL(&GUIGlObject::drawGL),
71
myLock(true) {
72
}
73
74
/// @brief Destructor
75
virtual ~SUMORTree() {
76
// check if lock is locked before insert objects
77
if (myLock.locked()) {
78
// cannot throw exception in destructor
79
WRITE_ERROR("Mutex of SUMORTree is locked during call of the destructor");
80
}
81
}
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
virtual void Insert(const float a_min[2], const float a_max[2], GUIGlObject* const & a_dataId) {
90
FXMutexLock locker(myLock);
91
GUI_RTREE_QUAL::Insert(a_min, a_max, a_dataId);
92
}
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
virtual void Remove(const float a_min[2], const float a_max[2], GUIGlObject* const & a_dataId) {
101
FXMutexLock locker(myLock);
102
GUI_RTREE_QUAL::Remove(a_min, a_max, a_dataId);
103
}
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
virtual int Search(const float a_min[2], const float a_max[2], const GUIVisualizationSettings& c) const {
115
FXMutexLock locker(myLock);
116
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
void addAdditionalGLObject(GUIGlObject *o, const double exaggeration = 1) {
123
// check if lock is locked before insert objects
124
if (myLock.locked()) {
125
throw ProcessError("Mutex of SUMORTree is locked before object insertion");
126
}
127
// lock mutex
128
FXMutexLock locker(myLock);
129
// obtain boundary of object
130
Boundary b = o->getCenteringBoundary();
131
// grow using exaggeration
132
if (exaggeration > 1) {
133
b.scale(exaggeration);
134
}
135
// show information in gui testing debug gl mode
136
if (MsgHandler::writeDebugGLMessages()) {
137
if (!b.isInitialised()) {
138
throw ProcessError(StringUtils::format("Boundary of GUIGlObject % is not initialised (insertion)", o->getMicrosimID()));
139
} else if ((b.getWidth() == 0) || (b.getHeight() == 0)) {
140
throw ProcessError(StringUtils::format("Boundary of GUIGlObject % has an invalid size (insertion)", o->getMicrosimID()));
141
} else if (myTreeDebug.count(o) > 0) {
142
throw ProcessError("GUIGlObject was already inserted");
143
} else {
144
myTreeDebug[o] = b;
145
}
146
}
147
// insert it in Tree
148
const float cmin[2] = {(float) b.xmin(), (float) b.ymin()};
149
const float cmax[2] = {(float) b.xmax(), (float) b.ymax()};
150
Insert(cmin, cmax, o);
151
// update tree size
152
myTreeSize++;
153
}
154
155
/** @brief Removes an additional object (detector/shape/trigger) from being visualised
156
* @param[in] o The object to remove
157
*/
158
void removeAdditionalGLObject(GUIGlObject *o, const double exaggeration = 1) {
159
// check if lock is locked remove insert objects
160
if (myLock.locked()) {
161
throw ProcessError("Mutex of SUMORTree is locked before object remove");
162
}
163
// lock mutex
164
FXMutexLock locker(myLock);
165
// obtain boundary of object
166
Boundary b = o->getCenteringBoundary();
167
// grow using exaggeration
168
if (exaggeration > 1) {
169
b.scale(exaggeration);
170
}
171
// show information in gui testing debug gl mode
172
if (MsgHandler::writeDebugGLMessages()) {
173
if (!b.isInitialised()) {
174
throw ProcessError(StringUtils::format("Boundary of GUIGlObject % is not initialised (deletion)", o->getMicrosimID()));
175
} else if ((b.getWidth() == 0) || (b.getHeight() == 0)) {
176
throw ProcessError(StringUtils::format("Boundary of GUIGlObject % has an invalid size (deletion)", o->getMicrosimID()));
177
} else if (myTreeDebug.count(o) == 0) {
178
throw ProcessError("GUIGlObject wasn't inserted");
179
} else if (toString(b) != toString(myTreeDebug.at(o))) {
180
// show information in console before throwing exception
181
std::cout << "Tree: " << toString(myTreeDebug.at(o)) << " original: " << toString(b) << std::endl;
182
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
const float cmin[2] = {(float) b.xmin(), (float) b.ymin()};
189
const float cmax[2] = {(float) b.xmax(), (float) b.ymax()};
190
Remove(cmin, cmax, o);
191
// update tree size
192
myTreeSize--;
193
}
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
};
245
246