Ponca  aa50bfdf187919869239c5b44b748842569114c1
Point Cloud Analysis library
Loading...
Searching...
No Matches
kdTree.hpp
1/*
2 This Source Code Form is subject to the terms of the Mozilla Public
3 License, v. 2.0. If a copy of the MPL was not distributed with this
4 file, You can obtain one at http://mozilla.org/MPL/2.0/.
5*/
6
7// KdTree ----------------------------------------------------------------------
8
9template<typename Traits>
10template<typename PointUserContainer, typename Converter>
11inline void KdTreeBase<Traits>::build(PointUserContainer&& points, Converter c)
12{
13 IndexContainer ids(points.size());
14 std::iota(ids.begin(), ids.end(), 0);
15 this->buildWithSampling(std::forward<PointUserContainer>(points), std::move(ids), std::move(c));
16}
17
18template<typename Traits>
20{
21 m_points.clear();
22 m_nodes.clear();
23 m_indices.clear();
24 m_leaf_count = 0;
25}
26
27template<typename Traits>
29{
30 if (m_points.empty())
31 return m_nodes.empty() && m_indices.empty();
32
33 if(m_nodes.empty() || m_indices.empty())
34 {
35 return false;
36 }
37
38 std::vector<bool> b(point_count(), false);
39 for(IndexType idx : m_indices)
40 {
41 if(idx < 0 || point_count() <= idx || b[idx])
42 {
43 return false;
44 }
45 b[idx] = true;
46 }
47
48 for(NodeIndexType n=0;n<node_count();++n)
49 {
50 const NodeType& node = m_nodes[n];
51 if(node.is_leaf())
52 {
53 if(sample_count() <= node.leaf_start() || node.leaf_start()+node.leaf_size() > sample_count())
54 {
55 return false;
56 }
57 }
58 else
59 {
60 if(node.inner_split_dim() < 0 || DataPoint::Dim-1 < node.inner_split_dim())
61 {
62 return false;
63 }
64 if(node_count() <= node.inner_first_child_id() || node_count() <= node.inner_first_child_id()+1)
65 {
66 return false;
67 }
68 }
69 }
70
71 return true;
72}
73
74template<typename Traits>
75void KdTreeBase<Traits>::print(std::ostream& os, bool verbose) const
76{
77 os << "KdTree:";
78 os << "\n MaxNodes: " << MAX_NODE_COUNT;
79 os << "\n MaxPoints: " << MAX_POINT_COUNT;
80 os << "\n MaxDepth: " << MAX_DEPTH;
81 os << "\n PointCount: " << point_count();
82 os << "\n SampleCount: " << sample_count();
83 os << "\n NodeCount: " << node_count();
84
85 if (!verbose)
86 {
87 return;
88 }
89
90 os << "\n Samples: [";
91 static constexpr IndexType SAMPLES_PER_LINE = 10;
92 for (IndexType i = 0; i < sample_count(); ++i)
93 {
94 os << (i == 0 ? "" : ",");
95 os << (i % SAMPLES_PER_LINE == 0 ? "\n " : " ");
96 os << m_indices[i];
97 }
98
99 os << "]\n Nodes:";
100 for (NodeIndexType n = 0; n < node_count(); ++n)
101 {
102 const NodeType& node = m_nodes[n];
103 if (node.is_leaf())
104 {
105 os << "\n - Type: Leaf";
106 os << "\n Start: " << node.leaf_start();
107 os << "\n Size: " << node.leaf_size();
108 }
109 else
110 {
111 os << "\n - Type: Inner";
112 os << "\n SplitDim: " << node.inner_split_dim();
113 os << "\n SplitValue: " << node.inner_split_value();
114 os << "\n FirstChild: " << node.inner_first_child_id();
115 }
116 }
117}
118
119template<typename Traits>
120template<typename PointUserContainer, typename IndexUserContainer, typename Converter>
121inline void KdTreeBase<Traits>::buildWithSampling(PointUserContainer&& points,
122 IndexUserContainer sampling,
123 Converter c)
124{
125 PONCA_DEBUG_ASSERT(points.size() <= MAX_POINT_COUNT);
126 this->clear();
127
128 // Move, copy or convert input samples
129 c(std::forward<PointUserContainer>(points), m_points);
130
131 m_nodes = NodeContainer();
132 m_nodes.reserve(4 * point_count() / m_min_cell_size);
133 m_nodes.emplace_back();
134
135 m_indices = std::move(sampling);
136
137 this->build_rec(0, 0, sample_count(), 1);
138
139 PONCA_DEBUG_ASSERT(this->valid());
140}
141
142template<typename Traits>
143void KdTreeBase<Traits>::build_rec(NodeIndexType node_id, IndexType start, IndexType end, int level)
144{
145 NodeType& node = m_nodes[node_id];
146 AabbType aabb;
147 for(IndexType i=start; i<end; ++i)
148 aabb.extend(m_points[m_indices[i]].pos());
149
150 node.set_is_leaf(
151 end-start <= m_min_cell_size ||
152 level >= Traits::MAX_DEPTH ||
153 // Since we add 2 nodes per inner node we need to stop if we can't add
154 // them both
155 (NodeIndexType)m_nodes.size() > MAX_NODE_COUNT - 2);
156
157 node.configure_range(start, end-start, aabb);
158 if (node.is_leaf())
159 {
160 ++m_leaf_count;
161 }
162 else
163 {
164 int split_dim = 0;
165 (Scalar(0.5) * aabb.diagonal()).maxCoeff(&split_dim);
166 node.configure_inner(aabb.center()[split_dim], m_nodes.size(), split_dim);
167 m_nodes.emplace_back();
168 m_nodes.emplace_back();
169
170 IndexType mid_id = this->partition(start, end, split_dim, node.inner_split_value());
171 build_rec(node.inner_first_child_id(), start, mid_id, level+1);
172 build_rec(node.inner_first_child_id()+1, mid_id, end, level+1);
173 }
174}
176template<typename Traits>
177auto KdTreeBase<Traits>::partition(IndexType start, IndexType end, int dim, Scalar value)
178 -> IndexType
179{
180 const auto& points = m_points;
181 auto& indices = m_indices;
182
183 auto it = std::partition(indices.begin()+start, indices.begin()+end, [&](IndexType i)
184 {
185 return points[i].pos()[dim] < value;
186 });
187
188 auto distance = std::distance(m_indices.begin(), it);
189
190 return static_cast<IndexType>(distance);
191}
[KdTreeSparse type definition]
Definition: kdTree.h:104
typename DataPoint::Scalar Scalar
Scalar given by user via DataPoint.
Definition: kdTree.h:115
typename Traits::IndexType IndexType
Type used to index points into the PointContainer.
Definition: kdTree.h:107
void clear()
Clear tree data.
Definition: kdTree.hpp:19