Open
Graph Drawing
Framework

 v. 2023.09 (Elderberry)
 

Loading...
Searching...
No Matches
DTree.h
Go to the documentation of this file.
1
29#pragma once
30
32
33#include <algorithm>
34
35namespace ogdf {
36namespace energybased {
37namespace dtree {
38
40template<typename IntType, int Dim>
41class DTree {
42public:
44 static constexpr int MaxNumChildrenPerNode = (1 << Dim);
45
47 explicit DTree(int numPoints)
48 : m_maxLevel((sizeof(IntType) << 3) + 1), m_numPoints(0), m_rootIndex(-1) {
50 }
51
54
56 struct Point {
57 IntType x[Dim];
58 };
59
61 struct MortonEntry {
62 IntType mortonNr[Dim];
63 int ref;
64
66 bool operator<(const MortonEntry& other) const {
68 }
69
71 bool operator==(const MortonEntry& other) const {
73 }
74 };
75
77 struct Node {
78 // quadtree related stuff
79 int level;
80 int next;
85 };
86
88 inline const Node& node(int i) const { return m_nodes[i]; };
89
91 inline Node& node(int i) { return m_nodes[i]; };
92
94 inline int numChilds(int i) const { return m_nodes[i].numChilds; };
95
97 inline int child(int i, int j) const { return m_nodes[i].child[j]; };
98
100 inline int numPoints(int i) const { return m_nodes[i].numPoints; };
101
103 inline int point(int i, int j) const { return m_mortonOrder[m_nodes[i].firstPoint + j].ref; };
104
106 void setPoint(int i, int d, IntType value);
107
109 inline int numPoints() const { return m_numPoints; };
110
112 inline int maxNumNodes() const { return m_numPoints * 2; };
113
115 const Point& point(int i) const { return m_points[i]; }
116
118 void prepareMortonOrder();
119
121 void sortMortonNumbers();
122
124 void prepareNodeLayer();
125
127 inline void mergeWithNext(int curr);
128
130 inline void adjustPointInfo(int curr);
131
133 int linkNodes(int curr, int maxLevel);
134
136 void linkNodes();
137
139 void build();
140
142 int countPoints(int curr) const;
143
145 int countPoints() const { return countPoints(m_rootIndex); };
146
148 int rootIndex() const { return m_rootIndex; };
149
150private:
152 void allocate(int n);
153
155 void deallocate();
156
158 Point* m_points = nullptr;
161 Node* m_nodes = nullptr;
163};
164
166template<typename IntType, int Dim>
168 m_numPoints = n;
169 m_points = new Point[m_numPoints];
170 m_mortonOrder = new MortonEntry[m_numPoints];
171 m_nodes = new Node[m_numPoints * 2];
172};
173
175template<typename IntType, int Dim>
177 delete[] m_points;
178 delete[] m_mortonOrder;
179 delete[] m_nodes;
180};
181
182template<typename IntType, int Dim>
183void DTree<IntType, Dim>::setPoint(int i, int d, IntType value) {
184 // set i-th point d coord to value
185 m_points[i].x[d] = value;
186}
187
189template<typename IntType, int Dim>
191 // loop over the point order
192 for (int i = 0; i < m_numPoints; i++) {
193 // set i's ref to i
194 m_mortonOrder[i].ref = i;
195
196 // generate the morton number by interleaving the bits
197 interleaveBits<IntType, Dim>(m_points[i].x, m_mortonOrder[i].mortonNr);
198 }
199}
200
202template<typename IntType, int Dim>
204 // just sort them
205 std::sort(m_mortonOrder, m_mortonOrder + m_numPoints);
206}
207
209template<typename IntType, int Dim>
211 Node* leafLayer = m_nodes;
212 Node* innerLayer = m_nodes + m_numPoints;
213
214#if 0
215 int last = 0;
216#endif
217 for (int i = 0; i < m_numPoints;) {
218 Node& leaf = leafLayer[i];
220 // i represents the current node on both layers
221 int j = i + 1;
222
223 // find the next morton number that differs or stop when j is equal to m_numPoints
224 while ((j < m_numPoints) && (m_mortonOrder[i] == m_mortonOrder[j])) {
225 j++;
226 }
227 // j is the index of the next cell (node)
228
229 // init the node on the leaf layer
230 leaf.firstPoint = i; //< node sits above the first point of the cell
231 leaf.numPoints =
232 j - i; //< number of points with equal morton numbers (number of points in grid cell)
233 leaf.numChilds = 0; //< it's a leaf
234 leaf.level = 0; //< it's a leaf
235 leaf.next = j; //< this leaf hasnt been created yet but we use indices so its ok
236
237 if (j < m_numPoints) {
238 // Note: the n-th inner node is not needed because we only need n-1 inner nodes to cover n leaves
239 // if we reach the n-1-th inner node, the variable last is set for the last time
240#if 0
241 last = i;
242#endif
243 // init the node on the inner node layer
244 innerNode.child[0] = i; //< node sits above the first leaf
245 innerNode.child[1] = j; //< this leaf hasnt been created yet but we use indices so its ok
246 innerNode.numChilds = 2; //< every inner node covers two leaves in the beginning
247 innerNode.level = lowestCommonAncestorLevel<IntType, Dim>(m_mortonOrder[i].mortonNr,
248 m_mortonOrder[j].mortonNr);
249 innerNode.next = m_numPoints + j; // the inner node layer is shifted by n
250 } else {
251 // no next for the last
252 innerLayer[i].next = 0;
253 // this is important to make the recursion stop
254 innerLayer[i].level = m_maxLevel + 1;
255 }
256
257 // advance to the next cell
258 i = j;
259 };
260 // here we set the successor of the n-1-th inner node to zero to avoid dealing with the n-th inner node
261#if 0
262 innerLayer[last].next = 0;
263#endif
264};
265
267template<typename IntType, int Dim>
269 int next = node(curr).next;
270 // Cool: since we never touched node(next) before
271 // it is still linked to only two leaves,
272 node(curr).child[node(curr).numChilds++] = node(next).child[1];
273
274 // thus we don't need this ugly loop:
275 // for (int i=1; i<node(next).numChilds; i++)
276 // node(curr).child[node(curr).numChilds++] = node(next).child[i];
277 node(curr).next = node(next).next;
278};
279
280template<typename IntType, int Dim>
282 // adjust the first such that it matched the first child
283 node(curr).firstPoint = node(node(curr).child[0]).firstPoint;
284
285 // index of the last child
286 const int lastChild = node(curr).child[node(curr).numChilds - 1];
287
288 // numPoints is lastPoint + 1 - firstPoint
289 node(curr).numPoints =
290 node(lastChild).firstPoint + node(lastChild).numPoints - node(curr).firstPoint;
291}
292
294template<typename IntType, int Dim>
295int DTree<IntType, Dim>::linkNodes(int curr, int maxLevel) {
296 // while the subtree is smaller than maxLevel
297 while (node(curr).next && node(node(curr).next).level < maxLevel) {
298 // get next node in the chain
299 int next = node(curr).next;
300 // First case: same level => merge, discard next
301 if (node(curr).level == node(next).level) {
302 mergeWithNext(curr);
303 } else if (node(curr).level < node(next).level) {
304 // Second case: next is higher => become first child
305 // set the first child of next to the current node
306 node(next).child[0] = curr;
307
308 // adjust the point info of the curr
309 adjustPointInfo(curr);
310
311 // this is the only case where we advance curr
312 curr = next;
313 } else { // Third case: next is smaller => construct a maximal subtree starting with next
314 int r = linkNodes(next, node(curr).level);
315 node(curr).child[node(curr).numChilds - 1] = r;
316 node(curr).next = node(r).next;
317 };
318 };
319 // adjust the point info of the curr
320 adjustPointInfo(curr);
321
322 // we are done with this subtree, return the root
323 return curr;
324};
325
327template<typename IntType, int Dim>
329 m_rootIndex = linkNodes(m_numPoints, m_maxLevel);
330};
331
333template<typename IntType, int Dim>
335 if (m_nodes[curr].numChilds) {
336 int sum = 0;
337 for (int i = 0; i < m_nodes[curr].numChilds; i++) {
338 sum += countPoints(m_nodes[curr].child[i]);
339 };
340
341 return sum;
342 } else {
343 return m_nodes[curr].numPoints;
344 }
345};
346
348template<typename IntType, int Dim>
350 // prepare the array with the morton numbers
351 prepareMortonOrder();
352
353 // sort the morton numbers
354 sortMortonNumbers();
355
356 // prepare the node layer
357 prepareNodeLayer();
358
360 linkNodes();
361};
362
363}
364}
365}
Implentation of the reduced quadtree for Dim dimensions.
Definition DTree.h:41
const Point & point(int i) const
returns the ith point in the input sequence
Definition DTree.h:115
int point(int i, int j) const
returns the index of the jth point covered by i's subtree.
Definition DTree.h:103
void sortMortonNumbers()
Sorts the points by morton number.
Definition DTree.h:203
int m_rootIndex
The index of the root node.
Definition DTree.h:162
int countPoints() const
Just for fun: traverse the tree and count the points in the leaves.
Definition DTree.h:145
void adjustPointInfo(int curr)
used to update the first and numPoints of inner nodes by linkNodes
Definition DTree.h:281
Point * m_points
The input set.
Definition DTree.h:158
static constexpr int MaxNumChildrenPerNode
the maximum number of children per node = 2^d
Definition DTree.h:44
void prepareNodeLayer()
Prepares both the leaf and inner node layer.
Definition DTree.h:210
int maxNumNodes() const
returns the maximum number of nodes (and the max index of a node)
Definition DTree.h:112
Node * m_nodes
Memory for all nodes.
Definition DTree.h:161
void deallocate()
Releases memory.
Definition DTree.h:176
void mergeWithNext(int curr)
Merges curr with next node in the chain (used by linkNodes)
Definition DTree.h:268
int numChilds(int i) const
returns the number of children of node i
Definition DTree.h:94
int numPoints() const
returns the number of points the quadtree contains
Definition DTree.h:109
int numPoints(int i) const
returns the number of points covered by this subtree
Definition DTree.h:100
int m_numPoints
Total number of points.
Definition DTree.h:159
int child(int i, int j) const
returns the index of the j th child of node i
Definition DTree.h:97
void allocate(int n)
Allocates memory for n points.
Definition DTree.h:167
void setPoint(int i, int d, IntType value)
sets the point to the given grid coords
Definition DTree.h:183
const Node & node(int i) const
Just to access the nodes a little bit easier.
Definition DTree.h:88
DTree(int numPoints)
constructor
Definition DTree.h:47
void prepareMortonOrder()
Prepares the morton numbers for sorting.
Definition DTree.h:190
void build()
Does all required steps except the allocate, deallocate, randomPoints.
Definition DTree.h:349
Node & node(int i)
Just to access the nodes a little bit easier.
Definition DTree.h:91
MortonEntry * m_mortonOrder
The order to be sorted.
Definition DTree.h:160
void linkNodes()
The Recursive Bottom-Up Construction (recursion start)
Definition DTree.h:328
int rootIndex() const
returns the index of the root node
Definition DTree.h:148
NodeElement * node
The type of nodes.
Definition Graph_d.h:64
int r[]
static MultilevelBuilder * getDoubleFactoredZeroAdjustedMerger()
The namespace for all OGDF objects.
The entry in the sorted order for a point.
Definition DTree.h:61
int ref
index in the original point order
Definition DTree.h:63
IntType mortonNr[Dim]
the morton number of the point
Definition DTree.h:62
bool operator<(const MortonEntry &other) const
less comparator for sort
Definition DTree.h:66
bool operator==(const MortonEntry &other) const
equal comparer for the construction algorithm
Definition DTree.h:71
int numChilds
number of children
Definition DTree.h:82
int next
the next node on the same layer (leaf or inner node layer)
Definition DTree.h:80
int firstPoint
the first point in the sorted order covered by this subtree
Definition DTree.h:83
int child[MaxNumChildrenPerNode]
index of the children
Definition DTree.h:81
int level
the level of the node in a complete quadtree
Definition DTree.h:79
int numPoints
the number of points covered by this subtree
Definition DTree.h:84
The point class with integer coords.
Definition DTree.h:56