32template <
typename T,
typename TxyFunc,
typename CoordT,
typename DistT>
54 if (this->free_list.empty()) {
55 this->nodes.emplace_back(element);
56 return this->nodes.size() - 1;
58 size_t newidx = this->free_list.back();
59 this->free_list.pop_back();
60 this->nodes[newidx] =
node{ element };
66 template <
typename It>
69 It mid = begin + (end - begin) / 2;
70 std::nth_element(begin, mid, end, [&](T a, T b) {
return TxyFunc()(a, level % 2) < TxyFunc()(b, level % 2); });
71 return TxyFunc()(*mid, level % 2);
75 template <
typename It>
78 ptrdiff_t count = end - begin;
82 }
else if (count == 1) {
84 }
else if (count > 1) {
86 It split = std::partition(begin, end, [&](T v) {
return TxyFunc()(v, level % 2) < split_coord; });
87 size_t newidx = this->
AddNode(*split);
88 this->nodes[newidx].left = this->
BuildSubtree(begin, split, level + 1);
89 this->nodes[newidx].right = this->
BuildSubtree(split + 1, end, level + 1);
97 bool Rebuild(
const T *include_element,
const T *exclude_element)
99 size_t initial_count = this->
Count();
102 T root_element = this->nodes[this->
root].element;
103 std::vector<T> elements = this->
FreeSubtree(this->root);
104 elements.push_back(root_element);
106 if (include_element !=
nullptr) {
107 elements.push_back(*include_element);
110 if (exclude_element !=
nullptr) {
111 typename std::vector<T>::iterator removed = std::remove(elements.begin(), elements.end(), *exclude_element);
112 elements.erase(removed, elements.end());
116 this->
Build(elements.begin(), elements.end());
117 assert(initial_count == this->
Count());
97 bool Rebuild(
const T *include_element,
const T *exclude_element) {
…}
127 node &n = this->nodes[node_idx];
130 CoordT nc = TxyFunc()(n.
element, dim);
132 CoordT ec = TxyFunc()(element, dim);
134 size_t &next = (ec < nc) ? n.
left : n.
right;
138 size_t newidx = this->
AddNode(element);
140 node &nn = this->nodes[node_idx];
141 if (ec < nc) nn.
left = newidx;
else nn.
right = newidx;
153 std::vector<T> subtree_elements;
154 node &n = this->nodes[node_idx];
157 size_t first_free = this->free_list.size();
164 for (
size_t i = first_free; i < this->free_list.size(); i++) {
165 node &fn = this->nodes[this->free_list[i]];
166 subtree_elements.push_back(fn.
element);
172 return subtree_elements;
185 node &n = this->nodes[node_idx];
189 this->free_list.push_back(node_idx);
195 std::vector<T> subtree_elements = this->
FreeSubtree(node_idx);
196 return this->
BuildSubtree(subtree_elements.begin(), subtree_elements.end(), level);;
203 CoordT nc = TxyFunc()(n.
element, dim);
205 CoordT ec = TxyFunc()(element, dim);
207 size_t next = (ec < nc) ? n.
left : n.
right;
211 if (new_branch != next) {
213 node &nn = this->nodes[node_idx];
214 if (ec < nc) nn.
left = new_branch;
else nn.
right = new_branch;
221 DistT ManhattanDistance(
const T &element, CoordT x, CoordT y)
const
223 return abs((DistT)TxyFunc()(element, 0) - (DistT)x) +
abs((DistT)TxyFunc()(element, 1) - (DistT)y);
231 if (a.second < b.second)
return a;
232 if (b.second < a.second)
return b;
233 if (a.first < b.first)
return a;
234 if (b.first < a.first)
return b;
243 const node &n = this->nodes[node_idx];
246 CoordT c = TxyFunc()(n.
element, dim);
248 DistT thisdist = this->ManhattanDistance(n.
element, xy[0], xy[1]);
253 size_t next = (xy[dim] < c) ? n.
left : n.
right;
259 limit = std::min(best.second, limit);
263 size_t opposite = (xy[dim] >= c) ? n.
left : n.
right;
272 template <
typename Outputter>
273 void FindContainedRecursive(CoordT p1[2], CoordT p2[2],
size_t node_idx,
int level,
const Outputter &outputter)
const
278 const node &n = this->nodes[node_idx];
281 CoordT ec = TxyFunc()(n.element, dim);
283 CoordT oc = TxyFunc()(n.element, 1 - dim);
286 if (ec >= p1[dim] && ec < p2[dim] && oc >= p1[1 - dim] && oc < p2[1 - dim]) outputter(n.element);
289 if (p1[dim] < ec && n.left !=
INVALID_NODE) this->FindContainedRecursive(p1, p2, n.left, level + 1, outputter);
292 if (p2[dim] > ec && n.right !=
INVALID_NODE) this->FindContainedRecursive(p1, p2, n.right, level + 1, outputter);
299 const node &n = this->nodes[node_idx];
303 void IncrementUnbalanced(
size_t amount = 1)
305 this->unbalanced += amount;
311 size_t count = this->
Count();
313 return this->unbalanced > count / 4;
317 void CheckInvariant(
size_t node_idx,
int level, CoordT min_x, CoordT max_x, CoordT min_y, CoordT max_y)
const
321 const node &n = this->nodes[node_idx];
322 CoordT cx = TxyFunc()(n.
element, 0);
323 CoordT cy = TxyFunc()(n.
element, 1);
330 if (level % 2 == 0) {
317 void CheckInvariant(
size_t node_idx,
int level, CoordT min_x, CoordT max_x, CoordT min_y, CoordT max_y)
const {
…}
345 this->
CheckInvariant(this->root, 0, std::numeric_limits<CoordT>::min(), std::numeric_limits<CoordT>::max(), std::numeric_limits<CoordT>::min(), std::numeric_limits<CoordT>::max());
359 template <
typename It>
363 this->free_list.clear();
364 this->unbalanced = 0;
365 if (begin == end)
return;
366 this->nodes.reserve(end - begin);
378 this->free_list.clear();
379 this->unbalanced = 0;
388 this->
Rebuild(
nullptr,
nullptr);
398 if (this->
Count() == 0) {
399 this->root = this->
AddNode(element);
403 this->IncrementUnbalanced();
417 size_t count = this->
Count();
418 if (count == 0)
return;
422 this->IncrementUnbalanced();
430 assert(this->free_list.size() <= this->nodes.size());
431 return this->nodes.size() - this->free_list.size();
441 assert(this->
Count() > 0);
443 CoordT xy[2] = { x, y };
456 template <
typename Outputter>
457 void FindContained(CoordT x1, CoordT y1, CoordT x2, CoordT y2,
const Outputter &outputter)
const
462 if (this->
Count() == 0)
return;
464 CoordT p1[2] = { x1, y1 };
465 CoordT p2[2] = { x2, y2 };
466 this->FindContainedRecursive(p1, p2, this->root, 0, outputter);
457 void FindContained(CoordT x1, CoordT y1, CoordT x2, CoordT y2,
const Outputter &outputter)
const {
…}
473 std::vector<T>
FindContained(CoordT x1, CoordT y1, CoordT x2, CoordT y2)
const
475 std::vector<T> result;
476 this->
FindContained(x1, y1, x2, y2, [&result](T e) {result.push_back(e); });
473 std::vector<T>
FindContained(CoordT x1, CoordT y1, CoordT x2, CoordT y2)
const {
…}
K-dimensional tree, specialised for 2-dimensional space.
static const size_t MIN_REBALANCE_THRESHOLD
Arbitrary value for "not worth rebalancing".
void Build(It begin, It end)
Clear and rebuild the tree from a new sequence of elements,.
size_t Count() const
Get number of elements stored in tree.
bool IsUnbalanced() const
Check if the entire tree is in need of rebuilding.
void FindContained(CoordT x1, CoordT y1, CoordT x2, CoordT y2, const Outputter &outputter) const
Find all items contained within the given rectangle.
bool Rebuild(const T *include_element, const T *exclude_element)
Rebuild the tree with all existing elements, optionally adding or removing one more.
std::vector< size_t > free_list
List of dead indices in the nodes vector.
node_distance FindNearestRecursive(CoordT xy[2], size_t node_idx, int level, DistT limit=std::numeric_limits< DistT >::max()) const
Search a sub-tree for the element nearest to a given point.
void InsertRecursive(const T &element, size_t node_idx, int level)
Insert one element in the tree somewhere below node_idx.
void Rebuild()
Reconstruct the tree with the same elements, letting it be fully balanced.
std::pair< T, DistT > node_distance
A data element and its distance to a searched-for point.
void Insert(const T &element)
Insert a single element in the tree.
Kdtree()
Construct a new Kdtree with the given xyfunc.
std::vector< node > nodes
Pool of all nodes in the tree.
std::vector< T > FindContained(CoordT x1, CoordT y1, CoordT x2, CoordT y2) const
Find all items contained within the given rectangle.
static node_distance SelectNearestNodeDistance(const node_distance &a, const node_distance &b)
Ordering function for node_distance objects, elements with equal distance are ordered by less-than co...
void CheckInvariant(size_t node_idx, int level, CoordT min_x, CoordT max_x, CoordT min_y, CoordT max_y) const
Verify that the invariant is true for a sub-tree, assert if not.
void Remove(const T &element)
Remove a single element from the tree, if it exists.
static const size_t INVALID_NODE
Index value indicating no-such-node.
size_t root
Index of root node.
size_t RemoveRecursive(const T &element, size_t node_idx, int level)
Find and remove one element from the tree.
size_t BuildSubtree(It begin, It end, int level)
Construct a subtree from elements between begin and end iterators, return index of root.
size_t AddNode(const T &element)
Create one new node in the tree, return its index in the pool.
void CheckInvariant() const
Verify the invariant for the entire tree, does nothing unless KDTREE_DEBUG is defined.
T FindNearest(CoordT x, CoordT y) const
Find the element closest to given coordinate, in Manhattan distance.
CoordT SelectSplitCoord(It begin, It end, int level)
Find a coordinate value to split a range of elements at.
std::vector< T > FreeSubtree(size_t node_idx)
Free all children of the given node.
void Clear()
Clear the tree.
size_t CountValue(const T &element, size_t node_idx) const
Debugging function, counts number of occurrences of an element regardless of its correct position in ...
size_t unbalanced
Number approximating how unbalanced the tree might be.
constexpr T abs(const T a)
Returns the absolute value of (scalar) variable.
Type of a node in the tree.
T element
Element stored at node.
size_t left
Index of node to the left, INVALID_NODE if none.
size_t right
Index of node to the right, INVALID_NODE if none.