UFO 1.0.0
An Efficient Probabilistic 3D Mapping Framework That Embraces the Unknown
Loading...
Searching...
No Matches
morton.hpp
1
50#ifndef UFO_MORTON_HPP
51#define UFO_MORTON_HPP
52
53// UFO
54#include <ufo/numeric/vec.hpp>
55
56// STL
57#include <cassert>
58#include <concepts>
59#include <cstddef>
60#include <cstdint>
61#include <limits>
62#include <tuple>
63#include <utility>
64
65#if defined(UFO_BMI2)
66#include <immintrin.h>
67#endif
68
69namespace ufo
70{
71namespace detail
72{
73template <std::size_t Dim, std::unsigned_integral T, std::size_t Offset>
74constexpr inline T MortonMask = [] {
75 T mask{};
76 std::size_t bits = std::numeric_limits<T>::digits;
77 for (std::size_t i = 0; i < bits / Dim; ++i) {
78 mask |= T(1) << (i * Dim + Offset);
79 }
80 return mask;
81}();
82
83template <std::size_t Dim, std::unsigned_integral T, std::size_t Offset = 0>
84 requires(Dim >= 1 && Offset < Dim)
85[[nodiscard]] constexpr T spread(T x)
86{
87 if constexpr (1 == Dim) {
88 return x;
89 } else {
90#if defined(UFO_BMI2)
91 if !consteval {
92 if constexpr (sizeof(T) == 4) {
93 return _pdep_u32(static_cast<std::uint32_t>(x),
94 MortonMask<Dim, std::uint32_t, Offset>);
95 } else if constexpr (sizeof(T) == 8) {
96 return _pdep_u64(static_cast<std::uint64_t>(x),
97 MortonMask<Dim, std::uint64_t, Offset>);
98 }
99 }
100#endif
101 if constexpr (0 != Offset) {
102 return spread<Dim, T, 0>(x) << Offset;
103 } else if constexpr (2 == Dim) {
104 T m(x);
105 if constexpr (sizeof(T) == 8) {
106 m &= 0x00000000FFFFFFFF;
107 m = (m | (m << 16)) & 0x0000FFFF0000FFFF;
108 m = (m | (m << 8)) & 0x00FF00FF00FF00FF;
109 m = (m | (m << 4)) & 0x0F0F0F0F0F0F0F0F;
110 m = (m | (m << 2)) & 0x3333333333333333;
111 m = (m | (m << 1)) & 0x5555555555555555;
112 } else {
113 m &= 0x0000FFFF;
114 m = (m | (m << 8)) & 0x00FF00FF;
115 m = (m | (m << 4)) & 0x0F0F0F0F;
116 m = (m | (m << 2)) & 0x33333333;
117 m = (m | (m << 1)) & 0x55555555;
118 }
119 return m;
120 } else if constexpr (3 == Dim) {
121 T m(x);
122 if constexpr (sizeof(T) == 8) {
123 m &= 0x1FFFFF;
124 m = (m | m << 32) & 0x1F00000000FFFF;
125 m = (m | m << 16) & 0x1F0000FF0000FF;
126 m = (m | m << 8) & 0x100F00F00F00F00F;
127 m = (m | m << 4) & 0x10C30C30C30C30C3;
128 m = (m | m << 2) & 0x1249249249249249;
129 } else {
130 m &= 0x3FF;
131 m = (m | m << 16) & 0x30000FF;
132 m = (m | m << 8) & 0x300F00F;
133 m = (m | m << 4) & 0x30C30C3;
134 m = (m | m << 2) & 0x9249249;
135 }
136 return m;
137 } else {
138 T res{};
139 std::size_t bits = std::numeric_limits<T>::digits / Dim;
140 for (std::size_t i = 0; i < bits; ++i) {
141 res |= (x & (T(1) << i)) << (i * (Dim - 1));
142 }
143 return res;
144 }
145 }
146}
147
148template <std::size_t Dim, std::unsigned_integral T, std::size_t Offset = 0>
149 requires(Dim >= 1 && Offset < Dim)
150[[nodiscard]] constexpr T compact(T m)
151{
152 if constexpr (1 == Dim) {
153 return m;
154 } else {
155#if defined(UFO_BMI2)
156 if !consteval {
157 if constexpr (sizeof(T) == 4) {
158 return _pext_u32(static_cast<std::uint32_t>(m),
159 MortonMask<Dim, std::uint32_t, Offset>);
160 } else if constexpr (sizeof(T) == 8) {
161 return _pext_u64(static_cast<std::uint64_t>(m),
162 MortonMask<Dim, std::uint64_t, Offset>);
163 }
164 }
165#endif
166 if constexpr (0 != Offset) {
167 return compact<Dim, T, 0>(m >> Offset);
168 } else if constexpr (2 == Dim) {
169 T x(m & MortonMask<Dim, T, 0>);
170 if constexpr (sizeof(T) == 8) {
171 x = (x ^ (x >> 1)) & 0x3333333333333333;
172 x = (x ^ (x >> 2)) & 0x0F0F0F0F0F0F0F0F;
173 x = (x ^ (x >> 4)) & 0x00FF00FF00FF00FF;
174 x = (x ^ (x >> 8)) & 0x0000FFFF0000FFFF;
175 x = (x ^ (x >> 16)) & 0x00000000FFFFFFFF;
176 } else {
177 x = (x ^ (x >> 1)) & 0x33333333;
178 x = (x ^ (x >> 2)) & 0x0F0F0F0F;
179 x = (x ^ (x >> 4)) & 0x00FF00FF;
180 x = (x ^ (x >> 8)) & 0x0000FFFF;
181 }
182 return x;
183 } else if constexpr (3 == Dim) {
184 T x(m & MortonMask<Dim, T, 0>);
185 if constexpr (sizeof(T) == 8) {
186 x = (x ^ (x >> 2)) & 0x10C30C30C30C30C3;
187 x = (x ^ (x >> 4)) & 0x100F00F00F00F00F;
188 x = (x ^ (x >> 8)) & 0x1F0000FF0000FF;
189 x = (x ^ (x >> 16)) & 0x1F00000000FFFF;
190 x = (x ^ (x >> 32)) & 0x1FFFFF;
191 } else {
192 x = (x ^ (x >> 2)) & 0x30C30C3;
193 x = (x ^ (x >> 4)) & 0x300F00F;
194 x = (x ^ (x >> 8)) & 0x30000FF;
195 x = (x ^ (x >> 16)) & 0x3FF;
196 }
197 return x;
198 } else {
199 T res{};
200 std::size_t bits = std::numeric_limits<T>::digits / Dim;
201 for (std::size_t i = 0; i < bits; ++i) {
202 res |= (m & (T(1) << (i * Dim))) >> (i * (Dim - 1));
203 }
204 return res;
205 }
206 }
207}
208
209} // namespace detail
210
211template <std::size_t Dim>
212struct Morton {
213 static constexpr std::uint32_t X_M_32 = detail::MortonMask<Dim, std::uint32_t, 0>;
214 static constexpr std::uint64_t X_M_64 = detail::MortonMask<Dim, std::uint64_t, 0>;
215
216 static constexpr std::size_t LEVELS_32 = 32 / Dim;
217 static constexpr std::size_t LEVELS_64 = 64 / Dim;
218
219 template <std::convertible_to<std::uint32_t>... Args>
220 requires(sizeof...(Args) == Dim)
221 [[nodiscard]] static constexpr std::uint32_t encode32(Args... args)
222 {
223 return encode_impl<std::uint32_t>(std::make_index_sequence<Dim>{},
224 static_cast<std::uint32_t>(args)...);
225 }
226
227 [[nodiscard]] static constexpr std::uint32_t encode32(Vec<Dim, std::uint32_t> const& v)
228 {
229 return std::apply([](auto... args) { return encode32(args...); }, v.fields);
230 }
231
232 template <std::convertible_to<std::uint32_t>... Args>
233 requires(sizeof...(Args) == Dim)
234 [[nodiscard]] static constexpr std::uint64_t encode64(Args... args)
235 {
236 return encode_impl<std::uint64_t>(std::make_index_sequence<Dim>{},
237 static_cast<std::uint32_t>(args)...);
238 }
239
240 [[nodiscard]] static constexpr std::uint64_t encode64(Vec<Dim, std::uint32_t> const& v)
241 {
242 return std::apply([](auto... args) { return encode64(args...); }, v.fields);
243 }
244
245 [[nodiscard]] static constexpr Vec<Dim, std::uint32_t> decode32(std::uint32_t m)
246 {
247 return decode_impl<std::uint32_t>(m, std::make_index_sequence<Dim>{});
248 }
249
250 [[nodiscard]] static constexpr std::uint32_t decode32(std::uint32_t m, std::size_t pos)
251 {
252 assert(Dim > pos);
253 return decode_pos_impl<std::uint32_t>(m, pos, std::make_index_sequence<Dim>{});
254 }
255
256 [[nodiscard]] static constexpr Vec<Dim, std::uint32_t> decode64(std::uint64_t m)
257 {
258 return decode_impl<std::uint64_t>(m, std::make_index_sequence<Dim>{});
259 }
260
261 [[nodiscard]] static constexpr std::uint32_t decode64(std::uint64_t m, std::size_t pos)
262 {
263 assert(Dim > pos);
264 return decode_pos_impl<std::uint64_t>(m, pos, std::make_index_sequence<Dim>{});
265 }
266
267 [[nodiscard]] static constexpr std::uint32_t spread32(std::uint32_t x)
268 {
269 return detail::spread<Dim, std::uint32_t, 0>(x);
270 }
271
272 [[nodiscard]] static constexpr std::uint64_t spread64(std::uint32_t x)
273 {
274 return detail::spread<Dim, std::uint64_t, 0>(static_cast<std::uint64_t>(x));
275 }
276
277 [[nodiscard]] static constexpr std::uint32_t compact32(std::uint32_t m)
278 {
279 return detail::compact<Dim, std::uint32_t, 0>(m);
280 }
281
282 [[nodiscard]] static constexpr std::uint32_t compact64(std::uint64_t m)
283 {
284 return static_cast<std::uint32_t>(detail::compact<Dim, std::uint64_t, 0>(m));
285 }
286
287 private:
288 template <std::unsigned_integral T, std::size_t... Is, std::convertible_to<T>... Args>
289 [[nodiscard]] static constexpr T encode_impl(std::index_sequence<Is...>, Args... args)
290 {
291 return (detail::spread<Dim, T, Is>(static_cast<T>(args)) | ...);
292 }
293
294 template <std::unsigned_integral T, std::size_t... Is>
295 [[nodiscard]] static constexpr Vec<Dim, std::uint32_t> decode_impl(
296 T m, std::index_sequence<Is...>)
297 {
299 static_cast<std::uint32_t>(detail::compact<Dim, T, Is>(m))...);
300 }
301
302 template <std::unsigned_integral T, std::size_t... Is>
303 [[nodiscard]] static constexpr std::uint32_t decode_pos_impl(T m, std::size_t pos,
304 std::index_sequence<Is...>)
305 {
306 std::uint32_t res{};
307 ((Is == pos ? res = static_cast<std::uint32_t>(detail::compact<Dim, T, Is>(m)) : 0),
308 ...);
309 return res;
310 }
311};
312
313} // namespace ufo
314
315#endif // UFO_MORTON_HPP
316
All vision-related classes and functions.
Definition cloud.hpp:49
A fixed-size arithmetic vector of up to 4 dimensions.
Definition vec.hpp:76