Loading [MathJax]/extensions/tex2jax.js

Open
Graph Drawing
Framework

 v. 2023.09 (Elderberry)
 

All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
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