Open
Graph Drawing
Framework

 v. 2023.09 (Elderberry)
 

Loading...
Searching...
No Matches
DTreeWSPD.h
Go to the documentation of this file.
1
29#pragma once
30
31#include <ogdf/basic/basic.h>
33
34#include <algorithm>
35#include <utility>
36
37namespace ogdf {
38namespace energybased {
39namespace dtree {
40
41class IWSPD {
42public:
44 virtual void onWellSeparatedPair(int aIndex, int bIndex) = 0;
45};
46
47template<int Dim>
48class DTreeWSPD {
49public:
50 using IntType = unsigned int;
52
54 explicit DTreeWSPD(int numPoints);
55
57 ~DTreeWSPD();
58
60 struct NodeData {
62 double x[Dim];
63
65 double min_x[Dim];
66
68 double max_x[Dim];
69
71 double radius_sq;
72 };
73
75 struct PointData {
77 double x[Dim];
78 };
79
81 void update();
82
84 const Tree& tree() const { return *m_pTree; };
85
87 const NodeData& node(int i) const { return m_nodeData[i]; };
88
90 void setPoint(int i, int d, double coord);
91
93 const PointData& point(int i) const { return m_pointData[i]; };
94
95 // temp function for
97
99 double separationFactor() const { return m_wspdSeparationFactor; };
100
103
104protected:
105 IWSPD* m_pIWSPD = nullptr;
106
108 NodeData& node(int i) { return m_nodeData[i]; };
109
111 void updateBoundingBox();
112
115
118
120 void updateTreeNodeGeometry(int curr);
121
123 void wspdRecursive(int a);
124
126 void wspdRecursive(int a, int b);
127
129 bool areWellSeparated(int a, int b) const;
130
132 void allocate();
133
135 void deallocate();
136
139
142
145
147 Tree* m_pTree = nullptr;
148
151
154
156 double m_bboxMin[Dim];
157
159 double m_bboxMax[Dim];
160};
161
163template<int Dim>
165 : m_numPoints(numPoints)
166 , m_wspdSeparationFactor(1.0)
167 , m_wspdSeparationFactorPlus2Squared_cached(9.0) {
168 // get the memory
169 allocate();
170
171 // init arrays
172 for (int i = 0; i < Dim; i++) {
173 m_bboxMin[i] = m_bboxMax[i] = 0.0;
174 }
175}
176
178template<int Dim>
180 // free the mem
181 deallocate();
182}
183
184template<int Dim>
186 m_pTree = new Tree(m_numPoints);
187 m_nodeData = new NodeData[m_pTree->maxNumNodes()];
188 m_pointData = new PointData[m_numPoints];
189}
190
191template<int Dim>
193 delete m_pTree;
194 delete[] m_nodeData;
195 delete[] m_pointData;
196}
197
198template<int Dim>
200 // update the bounding box of the point set
201 updateBoundingBox();
202
203 // update grid points inside the quadtree
204 updateTreeGridPoints();
205
206 // rebuild the tree
207 m_pTree->build();
208
209 // compute center, radius and bbox for each node
210 updateTreeNodeGeometry();
211}
212
213template<int Dim>
215 m_pIWSPD = pIWSPD;
216
217 // update this cached value for the well-sep test
218 const double s = (m_wspdSeparationFactor + 2.0);
219
220 // precompute this
221 m_wspdSeparationFactorPlus2Squared_cached = s * s;
222
223 // go ahead with the decomposition
224 wspdRecursive(m_pTree->rootIndex());
225}
226
227// the unary recursive function generating the binary calls
228template<int Dim>
230 // iterate over all ordered pairs of children
231 for (int i = 0; i < m_pTree->numChilds(curr); i++) {
232 // the first child index
233 const int first_child = m_pTree->child(curr, i);
234
235 // the second loop for the pair
236 for (int j = i + 1; j < m_pTree->numChilds(curr); j++) {
237 // the second child index
238 const int second_child = m_pTree->child(curr, j);
239
240 // call for each ordered pair the binary function
241 wspdRecursive(first_child, second_child);
242 }
243
244 // now do all this for every child
245 wspdRecursive(first_child);
246 }
247}
248
249template<int Dim>
251 if (areWellSeparated(a, b)) {
252 // far enough away => approx
253 if (m_pIWSPD) {
254 m_pIWSPD->onWellSeparatedPair(a, b);
255 }
256 } else {
257 // two cells are too close
258 int small_node = a;
259 int large_node = b;
260
261 // make sure the small one is not the bigger one
262 if (node(small_node).radius_sq > node(large_node).radius_sq) {
263 std::swap(small_node, large_node);
264 }
265
266 // split the bigger one
267 for (int i = 0; i < tree().numChilds(large_node); ++i) {
268 // recurse on the child
269 wspdRecursive(small_node, tree().child(large_node, i));
270 }
271 }
272}
273
274template<int Dim>
275bool DTreeWSPD<Dim>::areWellSeparated(int a, int b) const {
276 // take the bigger radius
277 double r_max_sq = std::max(node(a).radius_sq, node(b).radius_sq);
278
279 // compute the square distance
280 double dist_sq = 0.0;
281
282 // the d^2 loop
283 for (int d = 0; d < Dim; d++) {
284 double dx = node(a).x[d] - node(b).x[d];
285 dist_sq += dx * dx;
286 }
287
288 // two circles are well separated iff d - 2r > sr
289 // where d is the distance between the two centers
290 // (not the distance of circles!)
291 // this ws <=> d > (s + 2)r
292 // more efficient: d^2 > (s + 2)^2 r^2
293 // d_sq > (s^2 + 4s + 4) * r_max
294#if 0
295# if 0
296 const double s = (m_wspdSeparationFactor + 2.0);
297 return dist_sq > (m_wspdSeparationFactor * m_wspdSeparationFactor + 4.0 * m_wspdSeparationFactor + 4) * r_max * r_max;
298# else
299 return dist_sq > s * s * r_max_sq;
300# endif
301#else
302 return dist_sq > m_wspdSeparationFactorPlus2Squared_cached * r_max_sq;
303#endif
304}
305
306template<>
307bool DTreeWSPD<2>::areWellSeparated(int a, int b) const {
308 // take the bigger radius
309 double r_max_sq = std::max(node(a).radius_sq, node(b).radius_sq);
310
311 // compute the square distance
312 double dx_0 = node(a).x[0] - node(b).x[0];
313 double dx_1 = node(a).x[1] - node(b).x[1];
314 double dist_sq = dx_0 * dx_0 + dx_1 * dx_1;
315
316 // compare the sq distance
317 return dist_sq > m_wspdSeparationFactorPlus2Squared_cached * r_max_sq;
318}
319
320template<>
321bool DTreeWSPD<3>::areWellSeparated(int a, int b) const {
322 // take the bigger radius
323 double r_max_sq = std::max(node(a).radius_sq, node(b).radius_sq);
324
325 // compute the square distance
326 double dx_0 = node(a).x[0] - node(b).x[0];
327 double dx_1 = node(a).x[1] - node(b).x[1];
328 double dx_2 = node(a).x[2] - node(b).x[2];
329 double dist_sq = dx_0 * dx_0 + dx_1 * dx_1 + dx_2 * dx_2;
330
331 // compare the sq distance
332 return dist_sq > m_wspdSeparationFactorPlus2Squared_cached * r_max_sq;
333}
334
336template<int Dim>
337void DTreeWSPD<Dim>::setPoint(int i, int d, double coord) {
338 m_pointData[i].x[d] = coord;
339}
340
341template<int Dim>
343 if (!m_numPoints) {
344 return;
345 }
346
347 // initial values
348 for (int d = 0; d < Dim; d++) {
349 m_bboxMin[d] = m_bboxMax[d] = point(0).x[d];
350 }
351
352 // no magic here
353 for (int i = 1; i < m_numPoints; i++) {
354 for (int d = 0; d < Dim; d++) {
355 m_bboxMin[d] = std::min(m_bboxMin[d], point(i).x[d]);
356 m_bboxMax[d] = std::max(m_bboxMax[d], point(i).x[d]);
357 }
358 }
359}
360
361// updates the integer grid points in the quadtree
362template<int Dim>
364 for (int d = 0; d < Dim; d++) {
365 double noise_max = (m_bboxMax[d] - m_bboxMin[d]) * 0.25;
366 m_bboxMax[d] += randomDouble(0.0, noise_max);
367 m_bboxMin[d] -= randomDouble(0.0, noise_max);
368 }
369 // lets assume the bbox is updated. find the longest side
370 double quad_size = m_bboxMax[0] - m_bboxMin[0];
371 for (int d = 1; d < Dim; d++) {
372 quad_size = std::max(quad_size, m_bboxMax[d] - m_bboxMin[d]);
373 }
374
375 const double factor = (double)(0xffffffff);
376
377 double scale = factor / quad_size;
378 // iterate over all points
379 for (int i = 0; i < m_numPoints; i++) {
380 for (int d = 0; d < Dim; d++) {
381 // put it in the bounding square
382#if 0
383 double nx = ((point(i).x[d] - m_bboxMin[d] + 0.01) / quad_size + 0.02);
384#endif
385 double nx = ((point(i).x[d] - m_bboxMin[d]) * scale);
386
387 // dirty put on grid here
388 unsigned int ix = static_cast<unsigned int>(nx); //nx * (double)(unsigned int)(0x1fffffff);
389
390 // set the point coord
391 m_pTree->setPoint(i, d, ix);
392 }
393 }
394}
395
396template<int Dim>
398 updateTreeNodeGeometry(m_pTree->rootIndex());
399}
400
401// updates the geometry of the quadtree nodes
402template<int Dim>
404 // if this is an inner node
405 if (m_pTree->numChilds(curr)) {
406 // init with the bbox of the first child
407
408 // iterate over the rest of the children
409 for (int i = 0; i < m_pTree->numChilds(curr); i++) {
410 // the child index
411 const int child = m_pTree->child(curr, i);
412
413 // compute the size of the subtree
414 updateTreeNodeGeometry(child);
415
416 // lazy set the first
417 if (!i) {
418 for (int d = 0; d < Dim; d++) {
419 node(curr).min_x[d] = node(child).min_x[d];
420 node(curr).max_x[d] = node(child).max_x[d];
421 }
422 } else {
423 for (int d = 0; d < Dim; d++) {
424 node(curr).min_x[d] = std::min(node(curr).min_x[d], node(child).min_x[d]);
425 node(curr).max_x[d] = std::max(node(curr).max_x[d], node(child).max_x[d]);
426 }
427 }
428 };
429 } else { // else it is a leaf
430 // init from first point
431 for (int d = 0; d < Dim; d++) {
432 node(curr).min_x[d] = node(curr).max_x[d] = point(tree().point(curr, 0)).x[d];
433 }
434
435 // and the remaining points
436 for (int i = 1; i < tree().numPoints(curr); ++i) {
437 for (int d = 0; d < Dim; d++) {
438 node(curr).min_x[d] =
439 std::min(node(curr).min_x[d], point(tree().point(curr, i)).x[d]);
440 node(curr).max_x[d] =
441 std::max(node(curr).max_x[d], point(tree().point(curr, i)).x[d]);
442 }
443 }
444 }
445
446 // init the radius
447 node(curr).radius_sq = 0.0;
448
449 // compute the center and radius of the rect
450 for (int d = 0; d < Dim; d++) {
451 node(curr).x[d] = (node(curr).min_x[d] + node(curr).max_x[d]) * 0.5;
452 double s_x = (node(curr).max_x[d] - node(curr).min_x[d]);
453 node(curr).radius_sq += s_x * s_x;
454 }
455
456 // and the smallest enclosing circle radius squared
457 node(curr).radius_sq *= 0.25; // sqrt(node(curr).radius) * 0.5 squared;
458}
459
460}
461}
462}
Basic declarations, included by all source files.
Implentation of the reduced quadtree for Dim dimensions.
Definition DTree.h:41
Tree * m_pTree
the quadtree this wspd is working on
Definition DTreeWSPD.h:147
const NodeData & node(int i) const
returns the data for a quadtree
Definition DTreeWSPD.h:87
const Tree & tree() const
returns the corresponding Dtree
Definition DTreeWSPD.h:84
const PointData & point(int i) const
return ith point
Definition DTreeWSPD.h:93
double m_bboxMax[Dim]
the bounding box max coord of the point set
Definition DTreeWSPD.h:159
double m_bboxMin[Dim]
the bounding box min coord of the point set
Definition DTreeWSPD.h:156
NodeData * m_nodeData
geometry for the quadtree nodes
Definition DTreeWSPD.h:150
void computeWSPD(IWSPD *m_pIWSPD)
Definition DTreeWSPD.h:214
PointData * m_pointData
point data
Definition DTreeWSPD.h:153
void updateTreeNodeGeometry()
updates the geometry of the quadtree nodes
Definition DTreeWSPD.h:397
void updateBoundingBox()
updates the bounding box by iterating over all points
Definition DTreeWSPD.h:342
double separationFactor() const
returns the parameter s of the WSPD (default is 1.0)
Definition DTreeWSPD.h:99
void wspdRecursive(int a)
the unary recursive function generating the binary calls
Definition DTreeWSPD.h:229
double m_wspdSeparationFactorPlus2Squared_cached
a cached value for the ws test
Definition DTreeWSPD.h:144
void update()
call this when the point set has been updated.
Definition DTreeWSPD.h:199
double m_wspdSeparationFactor
the separation factor for the ws predicate
Definition DTreeWSPD.h:141
DTreeWSPD(int numPoints)
constructs a new WSPD for numPoints
Definition DTreeWSPD.h:164
bool areWellSeparated(int a, int b) const
predicate for determining if cells are well-separated
Definition DTreeWSPD.h:275
int m_numPoints
number of points
Definition DTreeWSPD.h:138
void setSeparationFactor(double s)
sets the parameter s of the WSPD (default is 1.0)
Definition DTreeWSPD.h:102
void updateTreeGridPoints()
updates the integer grid points in the quadtree
Definition DTreeWSPD.h:363
void setPoint(int i, int d, double coord)
sets the point to the given coords
Definition DTreeWSPD.h:337
NodeData & node(int i)
returns the data for a quadtree
Definition DTreeWSPD.h:108
virtual void onWellSeparatedPair(int aIndex, int bIndex)=0
called by the WSPD for a pair that is well separated
NodeElement * node
The type of nodes.
Definition Graph_d.h:71
double randomDouble(double low, double high)
Returns a random double value from the interval [low, high).
The namespace for all OGDF objects.
@ tree
for every hyperedge e a minimal subcubic tree connecting all hypernodes incident with e together is a...
geometry for the quadtree nodes
Definition DTreeWSPD.h:60
double min_x[Dim]
bounding box min coord
Definition DTreeWSPD.h:65
double max_x[Dim]
bounding box min coord
Definition DTreeWSPD.h:68
double x[Dim]
center of cell circle
Definition DTreeWSPD.h:62
world coordinates of the points
Definition DTreeWSPD.h:75
double x[Dim]
coords of the point
Definition DTreeWSPD.h:77