1 /** Aesalon, a tool to visualize program behaviour in real time.
2 Copyright (C) 2009-2011, Aesalon development team.
4 Aesalon is distributed under the terms of the GNU GPLv3. See
5 the included file LICENSE for more information.
7 @file include/storage/RTree.h
10 #ifndef AesalonStorage_RTree_H
11 #define AesalonStorage_RTree_H
16 #include "util/MessageSystem.h"
21 /** An n-dimensional R-tree.
23 - Key must support a basic assignment specifier and also the element zero, plus all the usual arithmetic operators.
24 Using an elementary type is a very good idea.
25 - Value must be either a basic type or a pointer.
26 - Minimum <= Maximum/2. (Logic in code assumes this.)
27 - Maximum <= some reasonable number. Many linear searches through lists of this size take place.
28 A reasonable size is sixteen.
29 - Dimensions should be as small as possible; many linear operations take place on this number.
30 Six is a reasonable upper bound.
31 - FloatKey should be a version of Key that supports floating-point arithmetic (or at least non-integer division).
32 Unless otherwise noted, all algorithms are from
33 A Guttman, R-Trees: A Dynamic Index Structure for Spatial Searching, 1984.
35 @todo Improve condenseTree's handling of non-leaf nodes.
38 #define RTreeTemplate \
39 template< RTreeTemplateItems >
40 #define RTreeTemplateItems \
41 typename Key, typename Value, int Dimensions, int Maximum, int Minimum, typename FloatKey
43 RTree<Key, Value, Dimensions, Maximum, Minimum, FloatKey>
45 template<typename Key
, typename Value
, int Dimensions
, int Maximum
, int Minimum
, typename FloatKey
=Key
>
50 Key m_bounds
[Dimensions
][2];
53 for(int i
= 1; i
< Dimensions
; i
++) {
54 m_bounds
[i
][0] = m_bounds
[i
][1] = 0.0;
57 Bound(Key d1_start
, Key d1_end
, ...) {
61 m_bounds
[0][0] = d1_start
, m_bounds
[0][1] = d1_end
;
63 for(int i
= 1; i
< Dimensions
; i
++) {
64 m_bounds
[i
][0] = va_arg(ap
, Key
);
65 m_bounds
[i
][1] = va_arg(ap
, Key
);
71 Key
start(int dimension
) const { return m_bounds
[dimension
][0]; }
72 Key
end(int dimension
) const { return m_bounds
[dimension
][1]; }
74 bool overlaps(const Bound
&other
) const {
75 for(int i
= 0; i
< Dimensions
; i
++) {
76 if(m_bounds
[i
][0] > other
.m_bounds
[i
][1] ||
77 m_bounds
[i
][1] < other
.m_bounds
[i
][0]) return false;
82 Key
toCover(const Bound
&other
) {
84 Key bounds
[Dimensions
][2];
85 Key sizes
[Dimensions
];
87 for(int i
= 0; i
< Dimensions
; i
++) {
88 bounds
[i
][0] = m_bounds
[i
][0];
89 bounds
[i
][1] = m_bounds
[i
][1];
90 sizes
[i
] = m_bounds
[i
][1] - m_bounds
[i
][0];
93 for(int i
= 0; i
< Dimensions
; i
++) {
95 if(other
.m_bounds
[i
][0] < bounds
[i
][0]) delta
+= bounds
[i
][0] - other
.m_bounds
[i
][0];
96 if(other
.m_bounds
[i
][1] > bounds
[i
][1]) delta
+= other
.m_bounds
[i
][1] - bounds
[i
][1];
99 for(int i
= 0; i
< Dimensions
; i
++) {
100 volume
+= delta
*sizes
[i
];
105 void cover(const Bound
&other
) {
106 for(int i
= 0; i
< Dimensions
; i
++) {
107 m_bounds
[i
][0] = std::min(m_bounds
[i
][0], other
.m_bounds
[i
][0]);
108 m_bounds
[i
][1] = std::max(m_bounds
[i
][1], other
.m_bounds
[i
][1]);
115 virtual ~Callback() {}
117 /** Handle a search result.
118 @return True if the search should continue.
120 virtual bool handle(const Bound
&bound
, Value
&value
) = 0;
134 Branch m_branch
[Maximum
];
136 Node(int depth
) : m_depth(depth
) {}
138 Bound
&bound() { return m_bound
; }
139 const Bound
&bound() const { return m_bound
; }
141 int depth() const { return m_depth
; }
142 bool isLeaf() const { return m_depth
== 0; }
144 bool isFull() const { return m_branches
== Maximum
; }
145 int branches() const { return m_branches
; }
147 void addBranch(const Bound
&bound
, Value value
) {
148 m_branch
[m_branches
].item
.bound
= bound
;
149 m_branch
[m_branches
++].item
.value
= value
;
151 void addBranch(Node
*child
) {
155 Node
*parent() const { return m_parent
; }
156 void setParent(Node
*parent
) { m_parent
= parent
; }
164 void search(const Bound
&bound
, Callback
*callback
);
165 void insert(const Bound
&bound
, const Value
&value
);
167 bool search(Node
*node
, const Bound
&bound
, Callback
*callback
);
168 Node
*split(Node
*node
, Node
*toInsert
);
172 RTreeScope::RTree() {
177 RTreeScope::~RTree() {
182 void RTreeScope::search(const RTreeScope::Bound
&bound
, RTreeScope::Callback
*callback
) {
183 search(m_root
, bound
, callback
);
187 void RTreeScope::insert(const RTreeScope::Bound
&bound
, const Value
&value
) {
189 AesalonPoolAlloc(Node
, toInsert
, Node(bound
, value
, NULL
));
195 bool RTreeScope::search(RTreeScope::Node
*node
, const RTreeScope::Bound
&bound
, RTreeScope::Callback
*callback
) {
196 if(node
== NULL
) return;
198 Message(Debug
, "**** Beginning search.");
202 Message(Debug
, "Searching node . . .");
203 if(bound
.overlaps(n
->bound())) {
204 Message(Debug
, "\tBound overlaps!");
206 if(!callback
->handle(n
->bound(), n
->value())) return false;
209 if(!search(n
, bound
, callback
)) return false;
218 typename
RTreeScope::Node
*RTreeScope::split(RTreeScope::Node
*node
, RTreeScope::Node
*toInsert
) {
220 AesalonPoolAlloc(Node
, s
, Node(node
->depth(), NULL
));
223 Message(Fatal
, "Splitting NYI.");
230 } // namespace Storage