Stride Reference Manual  - generated for commit 9643b11
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
KdTree_def.h
Go to the documentation of this file.
1 /*
2  * This is free software: you can redistribute it and/or modify it
3  * under the terms of the GNU General Public License as published by
4  * the Free Software Foundation, either version 3 of the License, or
5  * any later version.
6  * The software is distributed in the hope that it will be useful,
7  * but WITHOUT ANY WARRANTY; without even the implied warranty of
8  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9  * GNU General Public License for more details.
10  * You should have received a copy of the GNU General Public License
11  * along with the software. If not, see <http://www.gnu.org/licenses/>.
12  *
13  * Copyright 2018, 2019, Jan Broeckhove and Bistromatics group.
14  */
15 
16 #pragma once
17 
18 #include "KdTree.h"
19 
20 #include "AABBox.h"
21 #include "KdNode.h"
22 #include "Median.h"
23 
24 #include <algorithm>
25 #include <cstddef>
26 #include <functional>
27 #include <memory>
28 #include <queue>
29 #include <utility>
30 #include <vector>
31 
32 namespace geopop {
33 
34 template <typename P>
35 KdTree<P>::KdTree() : m_size(0), m_root(nullptr)
36 {
37 }
38 
39 template <typename P>
40 KdTree<P> KdTree<P>::Build(const std::vector<P>& points)
41 {
42  KdTree result;
43  result.m_size = points.size();
44  result.m_root = Construct<0>(points);
45  return result;
46 }
47 
48 template <typename P>
49 void KdTree<P>::Apply(std::function<bool(const P&)> f) const
50 {
51  if (m_root == nullptr)
52  return;
53 
54  std::queue<kd::BaseNode<P>*> todo;
55  todo.push(m_root.get());
56 
57  while (!todo.empty()) {
58  kd::BaseNode<P>* current = todo.front();
59  todo.pop();
60 
61  if (!f(current->GetPoint())) {
62  break;
63  }
64 
65  kd::BaseNode<P>* left = current->BorrowLeft();
66  if (left != nullptr)
67  todo.push(left);
68 
69  kd::BaseNode<P>* right = current->BorrowRight();
70  if (right != nullptr)
71  todo.push(right);
72  }
73 }
74 
75 template <typename P>
76 void KdTree<P>::Apply(std::function<bool(const P&)> f, const AABBox<P>& box) const
77 {
78  std::queue<kd::BaseNode<P>*> q;
79  q.push(m_root.get());
80  while (!q.empty()) {
81  kd::BaseNode<P>* current = q.front();
82  q.pop();
83  if (current == nullptr)
84  continue;
85 
86  if (current->GetPoint().InBox(box)) {
87  if (!f(current->GetPoint())) {
88  break;
89  }
90  }
91  kd::BaseNode<P>* a = current->BorrowSplitChild(box.lower);
92  kd::BaseNode<P>* b = current->BorrowSplitChild(box.upper);
93  q.push(a);
94  if (a != b)
95  q.push(b);
96  }
97 }
98 
99 template <typename P>
100 bool KdTree<P>::Contains(const P& point) const
101 {
102  bool result = false;
103  Apply([&result, &point](const P& pt) -> bool {
104  if (pt == point) {
105  result = true;
106  return false;
107  }
108  return true;
109  });
110  return result;
111 }
112 
113 template <typename P>
114 bool KdTree<P>::Empty() const
115 {
116  return Size() == 0;
117 }
118 
119 template <typename P>
120 std::size_t KdTree<P>::GetHeight() const
121 {
122  int h = 0;
123  std::queue<std::pair<int, kd::BaseNode<P>*>> q;
124  q.emplace(1, m_root.get());
125  while (!q.empty()) {
126  auto tmp = q.front();
127  q.pop();
128  kd::BaseNode<P>* n = tmp.second;
129  if (!n)
130  continue;
131  h = tmp.first;
132  q.emplace(h + 1, n->BorrowLeft());
133  q.emplace(h + 1, n->BorrowRight());
134  }
135  return static_cast<size_t>(h);
136 }
137 
138 template <typename P>
139 void KdTree<P>::Insert(P point)
140 {
141  m_size++;
142  if (!m_root) {
143  m_root = std::make_unique<kd::Node<P, 0>>(point);
144  return;
145  }
146  kd::BaseNode<P>* current = m_root.get();
147  while (true) {
148  kd::BaseNode<P>* next = current->BorrowSplitChild(point);
149  if (!next) {
150  current->AddChild(point);
151  return;
152  }
153  current = next;
154  }
155 }
156 
157 template <typename P>
158 std::vector<P> KdTree<P>::Query(const AABBox<P>& box) const
159 {
160  std::vector<P> result;
161  Apply(
162  [&result](const P& pt) -> bool {
163  result.push_back(pt);
164  return true;
165  },
166  box);
167  return result;
168 }
169 
170 template <typename P>
171 std::size_t KdTree<P>::Size() const
172 {
173  return m_size;
174 }
175 
176 template <typename P>
177 template <std::size_t D>
178 std::unique_ptr<kd::Node<P, D>> KdTree<P>::Construct(const std::vector<P>& points)
179 {
180  if (points.empty())
181  return nullptr;
182 
183  std::size_t med = kd::Median<P, D>(points);
184  auto median_val = points[med].template Get<D>();
185  P root_pt = P();
186 
187  std::vector<P> left, right;
188  for (std::size_t i = 0; i < points.size(); i++) {
189  const auto& p = points[i];
190  if (i == med) {
191  root_pt = p;
192  } else if (p.template Get<D>() <= median_val) {
193  left.push_back(p);
194  } else {
195  right.push_back(p);
196  }
197  }
198 
199  auto root = std::make_unique<kd::Node<P, D>>(root_pt);
200  root->m_left = Construct<(D + 1) % P::dim>(left);
201  root->m_right = Construct<(D + 1) % P::dim>(right);
202 
203  return root;
204 }
205 
206 } // namespace geopop
A k-d tree: a k-dimensional generalization of binary search trees This data structure allows for effi...
Definition: KdNode.h:25
AxisAlignedBoundingBox (hyperrectangle defined by lower and upper bound for every dimension)...
Definition: AABBox.h:24
bool Empty() const
Is the tree empty.
Definition: KdTree_def.h:114
static std::unique_ptr< kd::Node< P, D > > Construct(const std::vector< P > &points)
Definition: KdTree_def.h:178
std::size_t Size() const
Get the size of the tree.
Definition: KdTree_def.h:171
std::size_t m_size
The number of points in the tree.
Definition: KdTree.h:108
virtual BaseNode< P > * BorrowRight() const =0
Get a non-owning pointer to the right child (nullptr if no such child).
void Insert(P point)
Insert a new point into the tree, using this often may result in an unbalanced tree.
Definition: KdTree_def.h:139
virtual BaseNode< P > * BorrowSplitChild(const P &point) const =0
Get a non-owning pointer to the child corresponding to the correct split for point.
std::size_t GetHeight() const
Get the height of the tree (mostly for testing purposes).
Definition: KdTree_def.h:120
KdTree()
Constructor: builds an empty tree.
Definition: KdTree_def.h:35
Namespace for the geographic and demograhic classes.
Definition: Coordinate.h:21
virtual P GetPoint() const =0
Gets the point for this node.
P lower
The lower bound for every dimension.
Definition: AABBox.h:27
P upper
The upper bound for every dimension.
Definition: AABBox.h:29
virtual void AddChild(P point)=0
Add a new child in the right place, according to split.
std::unique_ptr< kd::Node< P, 0 > > m_root
The root node of the tree.
Definition: KdTree.h:109
std::vector< P > Query(const AABBox< P > &box) const
Get all points in the tree that lie within box.
Definition: KdTree_def.h:158
static KdTree Build(const std::vector< P > &points)
Build a balanced tree from the given set of points efficiently.
Definition: KdTree_def.h:40
virtual BaseNode< P > * BorrowLeft() const =0
Get a non-owning pointer to the left child (nullptr if no such child).
bool Contains(const P &point) const
Test wether a point is contained in the tree.
Definition: KdTree_def.h:100
void Apply(std::function< bool(const P &)> f) const
Calls a function with each of the points in the tree.
Definition: KdTree_def.h:49
A base class for all instantiations of a Node with D.
Definition: KdNode.h:33