Open
Graph Drawing
Framework

 v. 2023.09 (Elderberry)
 

DTreeWSPD.h
Go to the documentation of this file.
1 
29 #pragma once
30 
31 #include <ogdf/basic/basic.h>
33 
34 namespace ogdf {
35 namespace energybased {
36 namespace dtree {
37 
38 class IWSPD {
39 public:
41  virtual void onWellSeparatedPair(int aIndex, int bIndex) = 0;
42 };
43 
44 template<int Dim>
45 class DTreeWSPD {
46 public:
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
93  void computeWSPD(IWSPD* m_pIWSPD);
94 
96  double separationFactor() const { return m_wspdSeparationFactor; };
97 
100 
101 protected:
102  IWSPD* m_pIWSPD = nullptr;
103 
105  NodeData& node(int i) { return m_nodeData[i]; };
106 
108  void updateBoundingBox();
109 
111  void updateTreeGridPoints();
112 
114  void updateTreeNodeGeometry();
115 
117  void updateTreeNodeGeometry(int curr);
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 
147  NodeData* m_nodeData = nullptr;
148 
150  PointData* m_pointData = nullptr;
151 
153  double m_bboxMin[Dim];
154 
156  double m_bboxMax[Dim];
157 };
158 
160 template<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 
175 template<int Dim>
177  // free the mem
178  deallocate();
179 }
180 
181 template<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 
188 template<int Dim>
190  delete m_pTree;
191  delete[] m_nodeData;
192  delete[] m_pointData;
193 }
194 
195 template<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 
210 template<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
225 template<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 
246 template<int Dim>
247 void DTreeWSPD<Dim>::wspdRecursive(int a, int b) {
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 
271 template<int Dim>
272 bool 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 
303 template<>
304 bool 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 
317 template<>
318 bool 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 
333 template<int Dim>
334 void DTreeWSPD<Dim>::setPoint(int i, int d, double coord) {
335  m_pointData[i].x[d] = coord;
336 }
337 
338 template<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
359 template<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 
393 template<int Dim>
395  updateTreeNodeGeometry(m_pTree->rootIndex());
396 }
397 
398 // updates the geometry of the quadtree nodes
399 template<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 }
ogdf
The namespace for all OGDF objects.
Definition: AugmentationModule.h:36
ogdf::energybased::dtree::DTreeWSPD::NodeData::min_x
double min_x[Dim]
bounding box min coord
Definition: DTreeWSPD.h:62
DTree.h
ogdf::energybased::dtree::DTreeWSPD::m_nodeData
NodeData * m_nodeData
geometry for the quadtree nodes
Definition: DTreeWSPD.h:147
ogdf::energybased::dtree::DTreeWSPD::tree
const Tree & tree() const
returns the corresponding Dtree
Definition: DTreeWSPD.h:81
ogdf::energybased::dtree::IWSPD::onWellSeparatedPair
virtual void onWellSeparatedPair(int aIndex, int bIndex)=0
called by the WSPD for a pair that is well separated
ogdf::energybased::dtree::DTreeWSPD::deallocate
void deallocate()
free mem
Definition: DTreeWSPD.h:189
ogdf::energybased::dtree::DTreeWSPD::NodeData::x
double x[Dim]
center of cell circle
Definition: DTreeWSPD.h:59
ogdf::energybased::dtree::DTreeWSPD::m_pointData
PointData * m_pointData
point data
Definition: DTreeWSPD.h:150
ogdf::energybased::dtree::DTreeWSPD::~DTreeWSPD
~DTreeWSPD()
destructor
Definition: DTreeWSPD.h:176
ogdf::energybased::dtree::DTreeWSPD::setSeparationFactor
void setSeparationFactor(double s)
sets the parameter s of the WSPD (default is 1.0)
Definition: DTreeWSPD.h:99
ogdf::energybased::dtree::DTreeWSPD::NodeData::max_x
double max_x[Dim]
bounding box min coord
Definition: DTreeWSPD.h:65
ogdf::energybased::dtree::DTreeWSPD::update
void update()
call this when the point set has been updated.
Definition: DTreeWSPD.h:196
ogdf::energybased::dtree::DTreeWSPD::updateBoundingBox
void updateBoundingBox()
updates the bounding box by iterating over all points
Definition: DTreeWSPD.h:339
ogdf::energybased::dtree::DTreeWSPD::node
const NodeData & node(int i) const
returns the data for a quadtree
Definition: DTreeWSPD.h:84
ogdf::energybased::dtree::DTreeWSPD::m_numPoints
int m_numPoints
number of points
Definition: DTreeWSPD.h:135
ogdf::energybased::dtree::DTreeWSPD::NodeData::radius_sq
double radius_sq
radius of the cell
Definition: DTreeWSPD.h:68
ogdf::energybased::dtree::DTreeWSPD::NodeData
geometry for the quadtree nodes
Definition: DTreeWSPD.h:57
ogdf::energybased::dtree::DTreeWSPD::updateTreeNodeGeometry
void updateTreeNodeGeometry()
updates the geometry of the quadtree nodes
Definition: DTreeWSPD.h:394
ogdf::energybased::dtree::DTreeWSPD::PointData
world coordinates of the points
Definition: DTreeWSPD.h:72
ogdf::energybased::dtree::DTreeWSPD::node
NodeData & node(int i)
returns the data for a quadtree
Definition: DTreeWSPD.h:105
ogdf::energybased::dtree::DTreeWSPD::wspdRecursive
void wspdRecursive(int a)
the unary recursive function generating the binary calls
Definition: DTreeWSPD.h:226
ogdf::energybased::dtree::DTreeWSPD::separationFactor
double separationFactor() const
returns the parameter s of the WSPD (default is 1.0)
Definition: DTreeWSPD.h:96
ogdf::energybased::dtree::DTreeWSPD::m_bboxMin
double m_bboxMin[Dim]
the bounding box min coord of the point set
Definition: DTreeWSPD.h:153
ogdf::energybased::dtree::IWSPD
Definition: DTreeWSPD.h:38
ogdf::energybased::dtree::DTreeWSPD::computeWSPD
void computeWSPD(IWSPD *m_pIWSPD)
Definition: DTreeWSPD.h:211
ogdf::node
NodeElement * node
The type of nodes.
Definition: Graph_d.h:63
ogdf::energybased::dtree::DTreeWSPD::IntType
unsigned int IntType
Definition: DTreeWSPD.h:47
ogdf::energybased::dtree::DTreeWSPD::m_wspdSeparationFactorPlus2Squared_cached
double m_wspdSeparationFactorPlus2Squared_cached
a cached value for the ws test
Definition: DTreeWSPD.h:141
ogdf::energybased::dtree::DTreeWSPD::m_bboxMax
double m_bboxMax[Dim]
the bounding box max coord of the point set
Definition: DTreeWSPD.h:156
ogdf::EdgeStandardType::tree
@ tree
for every hyperedge e a minimal subcubic tree connecting all hypernodes incident with e together is a...
ogdf::energybased::dtree::DTreeWSPD::m_pIWSPD
IWSPD * m_pIWSPD
Definition: DTreeWSPD.h:102
basic.h
Basic declarations, included by all source files.
ogdf::energybased::dtree::DTreeWSPD::PointData::x
double x[Dim]
coords of the point
Definition: DTreeWSPD.h:74
ogdf::energybased::dtree::DTreeWSPD
Definition: DTreeWSPD.h:45
ogdf::energybased::dtree::DTreeWSPD::point
const PointData & point(int i) const
return ith point
Definition: DTreeWSPD.h:90
ogdf::energybased::dtree::DTreeWSPD::m_wspdSeparationFactor
double m_wspdSeparationFactor
the separation factor for the ws predicate
Definition: DTreeWSPD.h:138
ogdf::energybased::dtree::DTreeWSPD::DTreeWSPD
DTreeWSPD(int numPoints)
constructs a new WSPD for numPoints
Definition: DTreeWSPD.h:161
ogdf::energybased::dtree::DTreeWSPD::setPoint
void setPoint(int i, int d, double coord)
sets the point to the given coords
Definition: DTreeWSPD.h:334
ogdf::energybased::dtree::DTreeWSPD::allocate
void allocate()
allocate mem
Definition: DTreeWSPD.h:182
ogdf::energybased::dtree::DTree
Implentation of the reduced quadtree for Dim dimensions.
Definition: DTree.h:41
ogdf::energybased::dtree::DTreeWSPD::updateTreeGridPoints
void updateTreeGridPoints()
updates the integer grid points in the quadtree
Definition: DTreeWSPD.h:360
ogdf::energybased::dtree::DTreeWSPD::areWellSeparated
bool areWellSeparated(int a, int b) const
predicate for determining if cells are well-separated
Definition: DTreeWSPD.h:272
ogdf::randomDouble
double randomDouble(double low, double high)
Returns a random double value from the interval [low, high).
ogdf::energybased::dtree::DTreeWSPD::m_pTree
Tree * m_pTree
the quadtree this wspd is working on
Definition: DTreeWSPD.h:144