small_gicp
kdtree_tbb.hpp
Go to the documentation of this file.
1 // SPDX-FileCopyrightText: Copyright 2024 Kenji Koide
2 // SPDX-License-Identifier: MIT
3 #pragma once
4 
5 #include <atomic>
6 #include <tbb/tbb.h>
8 
9 namespace small_gicp {
10 
13 public:
15  template <typename KdTree, typename PointCloud>
16  void build_tree(KdTree& kdtree, const PointCloud& points) const {
17  kdtree.indices.resize(traits::size(points));
18  std::iota(kdtree.indices.begin(), kdtree.indices.end(), 0);
19 
20  std::atomic_uint64_t node_count = 0;
21  kdtree.nodes.resize(traits::size(points));
22  kdtree.root = create_node(kdtree, node_count, points, kdtree.indices.begin(), kdtree.indices.begin(), kdtree.indices.end());
23  kdtree.nodes.resize(node_count);
24  }
25 
31  template <typename PointCloud, typename KdTree, typename IndexConstIterator>
33  KdTree& kdtree,
34  std::atomic_uint64_t& node_count,
35  const PointCloud& points,
36  IndexConstIterator global_first,
37  IndexConstIterator first,
38  IndexConstIterator last) const {
39  const size_t N = std::distance(first, last);
40  const NodeIndexType node_index = node_count++;
41  auto& node = kdtree.nodes[node_index];
42 
43  // Create a leaf node.
44  if (N <= max_leaf_size) {
45  // std::sort(first, last);
46  node.node_type.lr.first = std::distance(global_first, first);
47  node.node_type.lr.last = std::distance(global_first, last);
48 
49  return node_index;
50  }
51 
52  // Find the best axis to split the input points.
53  using Projection = typename KdTree::Projection;
54  const auto proj = Projection::find_axis(points, first, last, projection_setting);
55  const auto median_itr = first + N / 2;
56  std::nth_element(first, median_itr, last, [&](size_t i, size_t j) { return proj(traits::point(points, i)) < proj(traits::point(points, j)); });
57 
58  // Create a non-leaf node.
59  node.node_type.sub.proj = proj;
60  node.node_type.sub.thresh = proj(traits::point(points, *median_itr));
61 
62  // Create left and right child nodes.
63  if (N > 512) {
64  tbb::parallel_invoke(
65  [&] { node.left = create_node(kdtree, node_count, points, global_first, first, median_itr); },
66  [&] { node.right = create_node(kdtree, node_count, points, global_first, median_itr, last); });
67  } else {
68  node.left = create_node(kdtree, node_count, points, global_first, first, median_itr);
69  node.right = create_node(kdtree, node_count, points, global_first, median_itr, last);
70  }
71 
72  return node_index;
73  }
74 
75 public:
76  int max_leaf_size = 20;
78 };
79 
80 } // namespace small_gicp
size_t size(const T &points)
Get the number of points.
Definition: traits.hpp:16
auto point(const T &points, size_t i)
Get i-th point. 4D vector is used to take advantage of SIMD intrinsics. The last element must be fill...
Definition: traits.hpp:40
Definition: flat_container.hpp:12
std::uint32_t NodeIndexType
Definition: kdtree.hpp:52
Kd-tree builder with TBB.
Definition: kdtree_tbb.hpp:12
void build_tree(KdTree &kdtree, const PointCloud &points) const
Build KdTree.
Definition: kdtree_tbb.hpp:16
int max_leaf_size
Maximum number of points in a leaf node.
Definition: kdtree_tbb.hpp:76
ProjectionSetting projection_setting
Projection setting.
Definition: kdtree_tbb.hpp:77
NodeIndexType create_node(KdTree &kdtree, std::atomic_uint64_t &node_count, const PointCloud &points, IndexConstIterator global_first, IndexConstIterator first, IndexConstIterator last) const
Create a Kd-tree node from the given point indices.
Definition: kdtree_tbb.hpp:32
"Safe" KdTree that holds the ownership of the input points.
Definition: kdtree.hpp:245
Point cloud.
Definition: point_cloud.hpp:15
Parameters to control the projection axis search.
Definition: projection.hpp:12