Quadtree-Impl.h
Go to the documentation of this file.
1 /*************************************************************************
2 > File Name: Quadtree-Impl.h
3 > Project Name: CubbyFlow
4 > Author: Chan-Ho Chris Ohk
5 > Purpose: Generic quadtree data structure.
6 > Created Time: 2017/10/15
7 > Copyright (c) 2018, Chan-Ho Chris Ohk
8 *************************************************************************/
9 #ifndef CUBBYFLOW_QUADTREE_IMPL_H
10 #define CUBBYFLOW_QUADTREE_IMPL_H
11 
12 #include <numeric>
13 #include <stack>
14 
15 namespace CubbyFlow
16 {
17  template <typename T>
18  bool Quadtree<T>::Node::IsLeaf() const
19  {
20  return firstChild == std::numeric_limits<size_t>::max();
21  }
22 
23  template <typename T>
25  {
26  // Do nothing
27  }
28 
29  template <typename T>
30  void Quadtree<T>::Build(const std::vector<T>& items, const BoundingBox2D& bound,
31  const BoxIntersectionTestFunc2<T>& testFunc, size_t maxDepth)
32  {
33  // Reset items
34  m_maxDepth = maxDepth;
35  m_items = items;
36  m_nodes.clear();
37 
38  // Normalize bounding box
39  m_bbox = bound;
40  double maxEdgeLen = std::max(m_bbox.GetWidth(), m_bbox.GetHeight());
41  m_bbox.upperCorner = m_bbox.lowerCorner + Vector2D(maxEdgeLen, maxEdgeLen);
42 
43  // Build
44  m_nodes.resize(1);
45  m_nodes[0].items.resize(m_items.size());
46  std::iota(m_nodes[0].items.begin(), m_nodes[0].items.end(), ZERO_SIZE);
47 
48  Build(0, 1, m_bbox, testFunc);
49  }
50 
51  template <typename T>
53  {
54  m_maxDepth = 1;
55  m_items.clear();
56  m_nodes.cloear();
57  m_bbox = BoundingBox2D();
58  }
59 
60  template <typename T>
62  const Vector2D& pt,
63  const NearestNeighborDistanceFunc2<T>& distanceFunc) const
64  {
66  best.distance = std::numeric_limits<double>::max();
67  best.item = nullptr;
68 
69  // Prepare to traverse quadtree
70  std::stack<std::pair<const Node*, BoundingBox2D>> todo;
71 
72  // Traverse quadtree nodes
73  const Node* node = m_nodes.data();
74  BoundingBox2D bound = m_bbox;
75  while (node != nullptr)
76  {
77  if (node->IsLeaf())
78  {
79  for (size_t itemIdx : node->items)
80  {
81  double d = distanceFunc(m_items[itemIdx], pt);
82  if (d < best.distance)
83  {
84  best.distance = d;
85  best.item = &m_items[itemIdx];
86  }
87  }
88 
89  // Grab next node to process from todo stack
90  if (todo.empty())
91  {
92  break;
93  }
94 
95  node = todo.top().first;
96  bound = todo.top().second;
97  todo.pop();
98  }
99  else
100  {
101  const double bestDistSqr = best.distance * best.distance;
102 
103  typedef std::tuple<const Node*, double, BoundingBox2D> NodeDistBox;
104  std::array<NodeDistBox, 4> childDistSqrPairs;
105  const auto MidPoint = bound.MidPoint();
106  for (int i = 0; i < 4; ++i)
107  {
108  const Node* child = &m_nodes[node->firstChild + i];
109  const auto childBound = BoundingBox2D(bound.Corner(i), MidPoint);
110  Vector2D cp = childBound.Clamp(pt);
111  double distMinSqr = cp.DistanceSquaredTo(pt);
112 
113  childDistSqrPairs[i] = std::make_tuple(child, distMinSqr, childBound);
114  }
115  std::sort(childDistSqrPairs.begin(), childDistSqrPairs.end(),
116  [](const NodeDistBox& a, const NodeDistBox& b)
117  {
118  return std::get<1>(a) > std::get<1>(b);
119  });
120 
121  for (int i = 0; i < 4; ++i)
122  {
123  const auto& childPair = childDistSqrPairs[i];
124  if (std::get<1>(childPair) < bestDistSqr)
125  {
126  todo.emplace(std::get<0>(childPair), std::get<2>(childPair));
127  }
128  }
129 
130  if (todo.empty())
131  {
132  break;
133  }
134 
135  node = todo.top().first;
136  bound = todo.top().second;
137  todo.pop();
138  }
139  }
140 
141  return best;
142  }
143 
144  template <typename T>
146  const BoundingBox2D& box,
147  const BoxIntersectionTestFunc2<T>& testFunc) const
148  {
149  return IsIntersects(box, testFunc, 0, m_bbox);
150  }
151 
152  template <typename T>
154  const Ray2D& ray, const RayIntersectionTestFunc2<T>& testFunc) const
155  {
156  return IsIntersects(ray, testFunc, 0, m_bbox);
157  }
158 
159  template <typename T>
161  const BoundingBox2D& box, const BoxIntersectionTestFunc2<T>& testFunc,
162  const IntersectionVisitorFunc2<T>& visitorFunc) const
163  {
164  ForEachIntersectingItem(box, testFunc, visitorFunc, 0, m_bbox);
165  }
166 
167  template <typename T>
169  const Ray2D& ray, const RayIntersectionTestFunc2<T>& testFunc,
170  const IntersectionVisitorFunc2<T>& visitorFunc) const
171  {
172  ForEachIntersectingItem(ray, testFunc, visitorFunc, 0, m_bbox);
173  }
174 
175  template <typename T>
177  const Ray2D& ray, const GetRayIntersectionFunc2<T>& testFunc) const
178  {
180  best.distance = std::numeric_limits<double>::max();
181  best.item = nullptr;
182 
183  return GetClosestIntersection(ray, testFunc, 0, m_bbox, best);
184  }
185 
186  template <typename T>
188  {
189  return m_items.begin();
190  }
191 
192  template <typename T>
194  {
195  return m_items.end();
196  }
197 
198  template <typename T>
200  {
201  return m_items.begin();
202  }
203 
204  template <typename T>
206  {
207  return m_items.end();
208  }
209 
210  template <typename T>
212  {
213  return m_items.size();
214  }
215 
216  template <typename T>
217  const T& Quadtree<T>::GetItem(size_t i) const
218  {
219  return m_items[i];
220  }
221 
222  template <typename T>
224  {
225  return m_nodes.size();
226  }
227 
228  template <typename T>
229  const std::vector<size_t>& Quadtree<T>::GetItemsAtNode(size_t nodeIdx) const
230  {
231  return m_nodes[nodeIdx].items;
232  }
233 
234  template <typename T>
235  size_t Quadtree<T>::GetChildIndex(size_t nodeIdx, size_t childIdx) const
236  {
237  return m_nodes[nodeIdx].firstChild + childIdx;
238  }
239 
240  template <typename T>
242  {
243  return m_bbox;
244  }
245 
246  template <typename T>
248  {
249  return m_maxDepth;
250  }
251 
252  template <typename T>
253  void Quadtree<T>::Build(size_t nodeIdx, size_t depth,
254  const BoundingBox2D& bound,
255  const BoxIntersectionTestFunc2<T>& testFunc)
256  {
257  if (depth < m_maxDepth && !m_nodes[nodeIdx].items.empty())
258  {
259  size_t firstChild = m_nodes[nodeIdx].firstChild = m_nodes.size();
260  m_nodes.resize(m_nodes[nodeIdx].firstChild + 4);
261 
262  BoundingBox2D bboxPerNode[4];
263 
264  for (int i = 0; i < 4; ++i)
265  {
266  bboxPerNode[i] = BoundingBox2D(bound.Corner(i), bound.MidPoint());
267  }
268 
269  auto& currentItems = m_nodes[nodeIdx].items;
270  for (size_t i = 0; i < currentItems.size(); ++i)
271  {
272  size_t currentItem = currentItems[i];
273  for (int j = 0; j < 4; ++j)
274  {
275  if (testFunc(m_items[currentItem], bboxPerNode[j]))
276  {
277  m_nodes[firstChild + j].items.push_back(currentItem);
278  }
279  }
280  }
281 
282  // Remove non-leaf data
283  currentItems.clear();
284 
285  // Refine
286  for (int i = 0; i < 4; ++i)
287  {
288  Build(firstChild + i, depth + 1, bboxPerNode[i], testFunc);
289  }
290  }
291  }
292 
293  template <typename T>
295  const BoxIntersectionTestFunc2<T>& testFunc,
296  size_t nodeIdx, const BoundingBox2D& bound) const
297  {
298  if (!box.Overlaps(bound))
299  {
300  return false;
301  }
302 
303  const Node& node = m_nodes[nodeIdx];
304 
305  if (node.items.size() > 0)
306  {
307  for (size_t itemIdx : node.items)
308  {
309  if (testFunc(m_items[itemIdx], box))
310  {
311  return true;
312  }
313  }
314  }
315 
316  if (node.firstChild != std::numeric_limits<size_t>::max())
317  {
318  for (int i = 0; i < 4; ++i)
319  {
320  if (IsIntersects(box, testFunc, node.firstChild + i, BoundingBox2D(bound.Corner(i), bound.MidPoint())))
321  {
322  return true;
323  }
324  }
325  }
326 
327  return false;
328  }
329 
330  template <typename T>
331  bool Quadtree<T>::IsIntersects(const Ray2D& ray,
332  const RayIntersectionTestFunc2<T>& testFunc,
333  size_t nodeIdx, const BoundingBox2D& bound) const
334  {
335  if (!bound.Intersects(ray))
336  {
337  return false;
338  }
339 
340  const Node& node = m_nodes[nodeIdx];
341 
342  if (node.items.size() > 0)
343  {
344  for (size_t itemIdx : node.items)
345  {
346  if (testFunc(m_items[itemIdx], ray))
347  {
348  return true;
349  }
350  }
351  }
352 
353  if (node.firstChild != std::numeric_limits<size_t>::max())
354  {
355  for (int i = 0; i < 4; ++i)
356  {
357  if (IsIntersects(ray, testFunc, node.firstChild + i, BoundingBox2D(bound.Corner(i), bound.MidPoint())))
358  {
359  return true;
360  }
361  }
362  }
363 
364  return false;
365  }
366 
367  template <typename T>
369  const BoundingBox2D& box, const BoxIntersectionTestFunc2<T>& testFunc,
370  const IntersectionVisitorFunc2<T>& visitorFunc, size_t nodeIdx,
371  const BoundingBox2D& bound) const
372  {
373  if (!box.Overlaps(bound))
374  {
375  return;
376  }
377 
378  const Node& node = m_nodes[nodeIdx];
379 
380  if (node.items.size() > 0)
381  {
382  for (size_t itemIdx : node.items)
383  {
384  if (testFunc(m_items[itemIdx], box))\
385  {
386  visitorFunc(m_items[itemIdx]);
387  }
388  }
389  }
390 
391  if (node.firstChild != std::numeric_limits<size_t>::max())
392  {
393  for (int i = 0; i < 4; ++i)
394  {
395  ForEachIntersectingItem(
396  box, testFunc, visitorFunc, node.firstChild + i,
397  BoundingBox2D(bound.Corner(i), bound.MidPoint()));
398  }
399  }
400  }
401 
402  template <typename T>
404  const Ray2D& ray, const RayIntersectionTestFunc2<T>& testFunc,
405  const IntersectionVisitorFunc2<T>& visitorFunc, size_t nodeIdx,
406  const BoundingBox2D& bound) const
407  {
408  if (!bound.Intersects(ray))
409  {
410  return;
411  }
412 
413  const Node& node = m_nodes[nodeIdx];
414 
415  if (node.items.size() > 0)
416  {
417  for (size_t itemIdx : node.items)
418  {
419  if (testFunc(m_items[itemIdx], ray))
420  {
421  visitorFunc(m_items[itemIdx]);
422  }
423  }
424  }
425 
426  if (node.firstChild != std::numeric_limits<size_t>::max())
427  {
428  for (int i = 0; i < 4; ++i)
429  {
430  ForEachIntersectingItem(
431  ray, testFunc, visitorFunc, node.firstChild + i,
432  BoundingBox2D(bound.Corner(i), bound.MidPoint()));
433  }
434  }
435  }
436 
437  template <typename T>
438  ClosestIntersectionQueryResult2<T> Quadtree<T>::GetClosestIntersection(
439  const Ray2D& ray, const GetRayIntersectionFunc2<T>& testFunc,
440  size_t nodeIdx, const BoundingBox2D& bound,
441  ClosestIntersectionQueryResult2<T> best) const
442  {
443  if (!bound.Intersects(ray))
444  {
445  return best;
446  }
447 
448  const Node& node = m_nodes[nodeIdx];
449 
450  if (node.items.size() > 0)
451  {
452  for (size_t itemIdx : node.items)
453  {
454  double dist = testFunc(m_items[itemIdx], ray);
455  if (dist < best.distance)
456  {
457  best.distance = dist;
458  best.item = &m_items[itemIdx];
459  }
460  }
461  }
462 
463  if (node.firstChild != std::numeric_limits<size_t>::max())
464  {
465  for (int i = 0; i < 4; ++i)
466  {
467  best = GetClosestIntersection(
468  ray, testFunc, node.firstChild + i,
469  BoundingBox2D(bound.Corner(i), bound.MidPoint()), best);
470  }
471  }
472 
473  return best;
474  }
475 }
476 
477 #endif
NearestNeighborQueryResult2< T > GetNearestNeighbor(const Vector2D &pt, const NearestNeighborDistanceFunc2< T > &distanceFunc) const override
Definition: Quadtree-Impl.h:61
Quadtree()
Default constructor.
Definition: Quadtree-Impl.h:24
double distance
Definition: NearestNeighborQueryEngine2.h:21
Vector2< T > MidPoint() const
Returns the mid-point of this box.
Definition: BoundingBox2-Impl.h:163
Ray2< double > Ray2D
Double-type 2-D ray.
Definition: Ray2.h:54
Closest intersection query result.
Definition: IntersectionQueryEngine2.h:19
Class for 2-D ray.
Definition: Ray2.h:23
size_t GetNumberOfNodes() const
Returns the number of quadtree nodes.
Definition: Quadtree-Impl.h:223
size_t GetMaxDepth() const
Returns the maximum depth of the tree.
Definition: Quadtree-Impl.h:247
const T * item
Definition: IntersectionQueryEngine2.h:21
BoundingBox2< double > BoundingBox2D
Double-type 2-D BoundingBox.
Definition: BoundingBox2.h:126
std::function< bool(const T &, const BoundingBox2D &)> BoxIntersectionTestFunc2
Box-item intersection test function.
Definition: IntersectionQueryEngine2.h:31
size_t GetChildIndex(size_t nodeIdx, size_t childIdx) const
Returns a child&#39;s index for given node.
Definition: Quadtree-Impl.h:235
Nearest neighbor query result.
Definition: NearestNeighborQueryEngine2.h:18
Vector2< T > upperCorner
Upper corner of the bounding box.
Definition: BoundingBox2.h:51
T DistanceSquaredTo(const Vector &other) const
Returns the squared distance to the other vector.
Definition: Vector2-Impl.h:308
void Build(const std::vector< T > &items, const BoundingBox2D &bound, const BoxIntersectionTestFunc2< T > &testFunc, size_t maxDepth)
Definition: Quadtree-Impl.h:30
const std::vector< size_t > & GetItemsAtNode(size_t nodeIdx) const
Returns the list of the items for given noide index.
Definition: Quadtree-Impl.h:229
bool IsIntersects(const BoundingBox2D &box, const BoxIntersectionTestFunc2< T > &testFunc) const override
Returns true if given box intersects with any of the stored items.
Definition: Quadtree-Impl.h:145
const T * item
Definition: NearestNeighborQueryEngine2.h:20
void Clear()
Clears all the contents of this instance.
Definition: Quadtree-Impl.h:52
2-D axis-aligned bounding box class.
Definition: BoundingBox2.h:44
Definition: pybind11Utils.h:24
Vector2< double > Vector2D
Double-type 2D vector.
Definition: Vector2.h:341
void ForEachIntersectingItem(const BoundingBox2D &box, const BoxIntersectionTestFunc2< T > &testFunc, const IntersectionVisitorFunc2< T > &visitorFunc) const override
Invokes visitorFunc for every intersecting items.
Definition: Quadtree-Impl.h:160
std::function< void(const T &)> IntersectionVisitorFunc2
Visitor function which is invoked for each intersecting item.
Definition: IntersectionQueryEngine2.h:43
double distance
Definition: IntersectionQueryEngine2.h:22
Iterator begin()
Returns the begin iterator of the item.
Definition: Quadtree-Impl.h:187
size_t GetNumberOfItems() const
Returns the number of items.
Definition: Quadtree-Impl.h:211
ClosestIntersectionQueryResult2< T > GetClosestIntersection(const Ray2D &ray, const GetRayIntersectionFunc2< T > &testFunc) const override
Returns the closest intersection for given ray.
Definition: Quadtree-Impl.h:176
Iterator end()
Returns the end iterator of the item.
Definition: Quadtree-Impl.h:193
constexpr size_t ZERO_SIZE
Zero size_t.
Definition: Constants.h:18
const BoundingBox2D & GetBoundingBox() const
Returns the bounding box of this quadtree.
Definition: Quadtree-Impl.h:241
Vector2< T > Corner(size_t idx) const
Returns corner position. Index starts from x-first order.
Definition: BoundingBox2-Impl.h:215
2-D vector class.
Definition: Vector2.h:26
const T & GetItem(size_t i) const
Returns the item at i.
Definition: Quadtree-Impl.h:217
std::function< double(const T &, const Ray2D &)> GetRayIntersectionFunc2
Ray-item closest intersection evaluation function.
Definition: IntersectionQueryEngine2.h:39
typename ContainerType::const_iterator ConstIterator
Definition: Quadtree.h:32
std::function< bool(const T &, const Ray2D &)> RayIntersectionTestFunc2
Ray-item intersection test function.
Definition: IntersectionQueryEngine2.h:35
std::function< double(const T &, const Vector2D &)> NearestNeighborDistanceFunc2
Nearest neighbor distance measure function.
Definition: NearestNeighborQueryEngine2.h:26
typename ContainerType::iterator Iterator
Definition: Quadtree.h:31