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