32template <
typename T,
typename TxyFunc,
typename CoordT,
typename DistT>
58 if (this->free_list.empty()) {
59 this->nodes.emplace_back(element);
60 return this->nodes.size() - 1;
62 size_t newidx = this->free_list.back();
63 this->free_list.pop_back();
64 this->nodes[newidx] = node{ element };
76 template <
typename It>
79 It mid = begin + (end - begin) / 2;
80 std::nth_element(begin, mid, end, [&](T a, T b) {
return TxyFunc()(a, level % 2) < TxyFunc()(b, level % 2); });
81 return TxyFunc()(*mid, level % 2);
91 template <
typename It>
94 ptrdiff_t count = end - begin;
98 }
else if (count == 1) {
100 }
else if (count > 1) {
102 It split = std::partition(begin, end, [&](T v) {
return TxyFunc()(v, level % 2) < split_coord; });
103 size_t newidx = this->
AddNode(*split);
104 this->nodes[newidx].left = this->
BuildSubtree(begin, split, level + 1);
105 this->nodes[newidx].right = this->
BuildSubtree(split + 1, end, level + 1);
118 bool Rebuild(
const T *include_element,
const T *exclude_element)
120 size_t initial_count = this->
Count();
123 T root_element = this->nodes[this->root].element;
124 std::vector<T> elements = this->
FreeSubtree(this->root);
125 elements.push_back(root_element);
127 if (include_element !=
nullptr) {
128 elements.push_back(*include_element);
131 if (exclude_element !=
nullptr) {
132 typename std::vector<T>::iterator removed = std::remove(elements.begin(), elements.end(), *exclude_element);
133 elements.erase(removed, elements.end());
137 this->
Build(elements.begin(), elements.end());
138 assert(initial_count == this->
Count());
153 node &n = this->nodes[node_idx];
156 CoordT nc = TxyFunc()(n.element, dim);
158 CoordT ec = TxyFunc()(element, dim);
160 size_t &next = (ec < nc) ? n.left : n.right;
164 size_t newidx = this->
AddNode(element);
166 node &nn = this->nodes[node_idx];
167 if (ec < nc) nn.left = newidx;
else nn.right = newidx;
180 std::vector<T> subtree_elements;
181 node &n = this->nodes[node_idx];
184 size_t first_free = this->free_list.size();
186 if (n.left !=
INVALID_NODE) this->free_list.push_back(n.left);
187 if (n.right !=
INVALID_NODE) this->free_list.push_back(n.right);
191 for (
size_t i = first_free; i < this->free_list.size(); i++) {
192 node &fn = this->nodes[this->free_list[i]];
193 subtree_elements.push_back(fn.element);
194 if (fn.left !=
INVALID_NODE) this->free_list.push_back(fn.left);
195 if (fn.right !=
INVALID_NODE) this->free_list.push_back(fn.right);
199 return subtree_elements;
212 node &n = this->nodes[node_idx];
214 if (n.element == element) {
216 this->free_list.push_back(node_idx);
222 std::vector<T> subtree_elements = this->
FreeSubtree(node_idx);
223 return this->
BuildSubtree(subtree_elements.begin(), subtree_elements.end(), level);;
230 CoordT nc = TxyFunc()(n.element, dim);
232 CoordT ec = TxyFunc()(element, dim);
234 size_t next = (ec < nc) ? n.left : n.right;
238 if (new_branch != next) {
240 node &nn = this->nodes[node_idx];
241 if (ec < nc) nn.left = new_branch;
else nn.right = new_branch;
248 DistT ManhattanDistance(
const T &element, CoordT x, CoordT y)
const
250 return abs((DistT)TxyFunc()(element, 0) - (DistT)x) +
abs((DistT)TxyFunc()(element, 1) - (DistT)y);
263 if (a.second < b.second)
return a;
264 if (b.second < a.second)
return b;
265 if (a.first < b.first)
return a;
266 if (b.first < a.first)
return b;
282 const node &n = this->nodes[node_idx];
285 CoordT c = TxyFunc()(n.element, dim);
287 DistT thisdist = this->ManhattanDistance(n.element, xy[0], xy[1]);
292 size_t next = (xy[dim] < c) ? n.left : n.right;
298 limit = std::min(best.second, limit);
302 size_t opposite = (xy[dim] >= c) ? n.left : n.right;
311 template <
typename Outputter>
312 void FindContainedRecursive(CoordT p1[2], CoordT p2[2],
size_t node_idx,
int level,
const Outputter &outputter)
const
317 const node &n = this->nodes[node_idx];
320 CoordT ec = TxyFunc()(n.element, dim);
322 CoordT oc = TxyFunc()(n.element, 1 - dim);
325 if (ec >= p1[dim] && ec < p2[dim] && oc >= p1[1 - dim] && oc < p2[1 - dim]) outputter(n.element);
328 if (p1[dim] < ec && n.left != INVALID_NODE) this->FindContainedRecursive(p1, p2, n.left, level + 1, outputter);
331 if (p2[dim] > ec && n.right != INVALID_NODE) this->FindContainedRecursive(p1, p2, n.right, level + 1, outputter);
343 const node &n = this->nodes[node_idx];
344 return this->
CountValue(element, n.left) + this->
CountValue(element, n.right) + ((n.element == element) ? 1 : 0);
347 void IncrementUnbalanced(
size_t amount = 1)
349 this->unbalanced += amount;
358 size_t count = this->
Count();
360 return this->unbalanced > count / 4;
372 void CheckInvariant(
size_t node_idx,
int level, CoordT min_x, CoordT max_x, CoordT min_y, CoordT max_y)
const
376 const node &n = this->nodes[node_idx];
377 CoordT cx = TxyFunc()(n.element, 0);
378 CoordT cy = TxyFunc()(n.element, 1);
385 if (level % 2 == 0) {
388 this->
CheckInvariant(n.right, level + 1, cx, max_x, min_y, max_y);
392 this->
CheckInvariant(n.right, level + 1, min_x, max_x, cy, max_y);
400 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());
414 template <
typename It>
418 this->free_list.clear();
419 this->unbalanced = 0;
420 if (begin == end)
return;
421 this->nodes.reserve(end - begin);
433 this->free_list.clear();
434 this->unbalanced = 0;
443 this->
Rebuild(
nullptr,
nullptr);
454 if (this->
Count() == 0) {
455 this->root = this->
AddNode(element);
459 this->IncrementUnbalanced();
474 size_t count = this->
Count();
475 if (count == 0)
return;
479 this->IncrementUnbalanced();
490 assert(this->free_list.size() <= this->nodes.size());
491 return this->nodes.size() - this->free_list.size();
504 assert(this->
Count() > 0);
506 CoordT xy[2] = { x, y };
519 template <
typename Outputter>
520 void FindContained(CoordT x1, CoordT y1, CoordT x2, CoordT y2,
const Outputter &outputter)
const
525 if (this->
Count() == 0)
return;
527 CoordT p1[2] = { x1, y1 };
528 CoordT p2[2] = { x2, y2 };
529 this->FindContainedRecursive(p1, p2, this->root, 0, outputter);
541 std::vector<T>
FindContained(CoordT x1, CoordT y1, CoordT x2, CoordT y2)
const
543 std::vector<T> result;
544 this->
FindContained(x1, y1, x2, y2, [&result](T e) {result.push_back(e); });
static const size_t MIN_REBALANCE_THRESHOLD
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
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
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 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.
size_t AddNode(const T &element)
Create one new node in the tree.
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 ...
constexpr T abs(const T a)
Returns the absolute value of (scalar) variable.
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.