Ponca  40f245e28b920cbb763a1c6282156c87c626f24c
Point Cloud Analysis library
Loading...
Searching...
No Matches
kdTreeTraits.h
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
8#pragma once
9
10#include "../../Common/Macro.h"
11
12#include <cstddef>
13
14#include <Eigen/Geometry>
15
16namespace Ponca {
17#ifndef PARSED_WITH_DOXYGEN
18namespace internal
19{
20 constexpr int clz(unsigned int value)
21 {
22#if PONCA_HAS_BUILTIN_CLZ
23 return __builtin_clz(value);
24#else
25 if (value == 0)
26 {
27 return 0;
28 }
29
30 unsigned int msb_mask = 1 << (sizeof(unsigned int)*8 - 1);
31 int count = 0;
32 for (; (value & msb_mask) == 0; value <<= 1, ++count)
33 {
34 }
35 return count;
36#endif
37 }
38}
39#endif
40
41template <typename NodeIndex, typename Scalar, int DIM>
43{
44private:
45 enum
46 {
47 // The minimum bit width required to store the split dimension.
48 //
49 // Equal to the index of DIM's most significant bit (starting at 1), e.g.:
50 // With DIM = 4,
51 // -------------
52 // DIM = 0b | 1 | 0 | 0 |
53 // -------------
54 // Bit index = #3 #2 #1
55 //
56 // The MSB has an index of 3, so we store the dimension on 3 bits.
57 DIM_BITS = sizeof(unsigned int)*8 - internal::clz((unsigned int)DIM),
58 };
59
60 // The node stores bitfields as unsigned indices.
61 using UIndex = typename std::make_unsigned<NodeIndex>::type;
62
63public:
64 enum
65 {
69 INDEX_BITS = sizeof(UIndex)*8 - DIM_BITS,
70 };
71
72 Scalar split_value{0};
73 UIndex first_child_id : INDEX_BITS;
74 UIndex split_dim : DIM_BITS;
75};
76
77template <typename Index, typename Size>
79{
80 Index start{0};
81 Size size{0};
82};
83
105template <typename Index, typename NodeIndex, typename DataPoint,
106 typename LeafSize = Index,
108 typename _LeafNodeType = KdTreeDefaultLeafNode<Index, LeafSize>>
110{
111private:
112 using Scalar = typename DataPoint::Scalar;
113 using InnerType = _InnerNodeType;
114 using LeafType = _LeafNodeType;
115
116public:
117 enum : std::size_t
118 {
123 MAX_COUNT = std::size_t(2) << InnerType::INDEX_BITS,
124 };
125
132 using AabbType = Eigen::AlignedBox<Scalar, DataPoint::Dim>;
133
134 KdTreeCustomizableNode() = default;
135
137 : m_is_leaf(n.m_is_leaf)
138 {
139 if (m_is_leaf)
140 {
141 data.m_leaf = n.data.m_leaf;
142 }
143 else
144 {
145 data.m_inner = n.data.m_inner;
146 }
147 }
148
149 constexpr KdTreeCustomizableNode& operator=(KdTreeCustomizableNode&& n)
150 {
151 if (&n != this)
152 {
153 m_is_leaf = n.m_is_leaf;
154 if (m_is_leaf)
155 {
156 data.m_leaf = n.data.m_leaf;
157 }
158 else
159 {
160 data.m_inner = n.data.m_inner;
161 }
162 }
163
164 return *this;
165 }
166
167 constexpr KdTreeCustomizableNode(const KdTreeCustomizableNode& n)
168 : m_is_leaf(n.m_is_leaf)
169 {
170 if (n.m_is_leaf)
171 {
172 data.m_leaf = n.data.m_leaf;
173 }
174 else
175 {
176 data.m_inner = n.data.m_inner;
177 }
178 }
179
180 constexpr KdTreeCustomizableNode& operator=(const KdTreeCustomizableNode& n)
181 {
182 if (&n != this)
183 {
184 m_is_leaf = n.m_is_leaf;
185 if (n.m_is_leaf)
186 {
187 data.m_leaf = n.data.m_leaf;
188 }
189 else
190 {
191 data.m_inner = n.data.m_inner;
192 }
193 }
194
195 return *this;
196 }
197
198 ~KdTreeCustomizableNode() {}
199
200 [[nodiscard]] bool is_leaf() const { return m_is_leaf; }
201 void set_is_leaf(bool is_leaf) { m_is_leaf = is_leaf; }
202
215 void configure_range(Index start, Index size, const AabbType &aabb)
216 {
217 if (m_is_leaf)
218 {
219 data.m_leaf.start = start;
220 data.m_leaf.size = (LeafSize)size;
221 }
222 }
223
233 void configure_inner(Scalar split_value, Index first_child_id, Index split_dim)
234 {
235 if (!m_is_leaf)
236 {
237 data.m_inner.split_value = split_value;
238 data.m_inner.first_child_id = first_child_id;
239 data.m_inner.split_dim = split_dim;
240 }
241 }
242
247 [[nodiscard]] Index leaf_start() const { return data.m_leaf.start; }
248
252 [[nodiscard]] LeafSize leaf_size() const { return data.m_leaf.size; }
253
257 [[nodiscard]] Scalar inner_split_value() const { return data.m_inner.split_value; }
258
262 [[nodiscard]] int inner_split_dim() const { return (int)data.m_inner.split_dim; }
263
271 [[nodiscard]] Index inner_first_child_id() const { return (Index)data.m_inner.first_child_id; }
272
273protected:
274 [[nodiscard]] inline LeafType& getAsLeaf() { return data.m_leaf; }
275 [[nodiscard]] inline InnerType& getAsInner() { return data.m_inner; }
276 [[nodiscard]] inline const LeafType& getAsLeaf() const { return data.m_leaf; }
277 [[nodiscard]] inline const InnerType& getAsInner() const { return data.m_inner; }
278
279private:
280 bool m_is_leaf{true};
281 union Data
282 {
283 // We need an explicit constructor here, see https://stackoverflow.com/a/70428826
284 constexpr Data() : m_leaf() {}
285
286 ~Data() {}
287 LeafType m_leaf;
288 InnerType m_inner;
289 };
290 Data data;
291};
292
293template <typename Index, typename NodeIndex, typename DataPoint,
294 typename LeafSize = Index>
295struct KdTreeDefaultNode : public KdTreeCustomizableNode<Index, NodeIndex, DataPoint, LeafSize,
296 KdTreeDefaultInnerNode<NodeIndex, typename DataPoint::Scalar, DataPoint::Dim>,
297 KdTreeDefaultLeafNode<Index, LeafSize>> {
298 using Base = KdTreeCustomizableNode<Index, NodeIndex, DataPoint, LeafSize,
301};
302
310template <typename _DataPoint,
311 template <typename /*Index*/,
312 typename /*NodeIndex*/,
313 typename /*DataPoint*/,
314 typename /*LeafSize*/> typename _NodeType = KdTreeDefaultNode>
316{
317 enum
318 {
323 };
324
334 using DataPoint = _DataPoint;
335 using IndexType = int;
336 using LeafSizeType = unsigned short;
337
338 // Containers
339 using PointContainer = std::vector<DataPoint>;
340 using IndexContainer = std::vector<IndexType>;
341
342 // Nodes
343 using NodeIndexType = std::size_t;
344 using NodeType = _NodeType<IndexType, NodeIndexType, DataPoint, LeafSizeType>;
345 using NodeContainer = std::vector<NodeType>;
346};
347} // namespace Ponca
The node type used by default by the kd-tree.
Scalar inner_split_value() const
The position of the AABB split of the inner node.
Index leaf_start() const
The start index of the range of the leaf node in the sample index array.
Eigen::AlignedBox< Scalar, DataPoint::Dim > AabbType
The type used to store node bounding boxes.
void configure_range(Index start, Index size, const AabbType &aabb)
Configures the range of the node in the sample index array of the kd-tree.
void configure_inner(Scalar split_value, Index first_child_id, Index split_dim)
Configures the inner node information.
int inner_split_dim() const
Which axis the split of the AABB of the inner node was done on.
@ MAX_COUNT
The maximum number of nodes that a kd-tree can have when using this node type.
LeafSize leaf_size() const
The size of the range of the leaf node in the sample index array.
Index inner_first_child_id() const
The index of the first child of the node in the node array of the kd-tree.
This Source Code Form is subject to the terms of the Mozilla Public License, v.
@ INDEX_BITS
The bit width used to store the first child index.
The default traits type used by the kd-tree.
@ MAX_DEPTH
A compile-time constant specifying the maximum depth of the kd-tree.
_DataPoint DataPoint
The type used to store point data.