UFO 1.0.0
An Efficient Probabilistic 3D Mapping Framework That Embraces the Unknown
Loading...
Searching...
No Matches
code.hpp
1
42#ifndef UFO_CONTAINER_TREE_CODE_HPP
43#define UFO_CONTAINER_TREE_CODE_HPP
44
45// UFO
46#include <ufo/container/tree/key.hpp>
47#include <ufo/morton/morton.hpp>
48#include <ufo/numeric/math.hpp>
49
50// STL
51#include <cstddef>
52#include <cstdint>
53#include <functional>
54
55namespace ufo
56{
57template <std::size_t Dim>
59{
60 private:
61 //
62 // Friends
63 //
64
65 friend class std::hash<TreeCode>;
66
67 public:
68 using code_type = std::uint32_t;
69 using key_type = typename TreeKey<Dim>::key_type;
70 using depth_type = std::uint32_t;
71 using size_type = std::size_t;
72
73 private:
74 static constexpr code_type const DEPTHS_PER_IDX = Morton<Dim>::LEVELS_32;
75 static constexpr code_type const OFFSET_MASK = ~((~code_type(0)) << Dim);
76
77 static constexpr std::array<bool, 3> const ACTIVE{
78 true, std::numeric_limits<key_type>::digits > DEPTHS_PER_IDX,
79 std::numeric_limits<key_type>::digits > 2 * DEPTHS_PER_IDX};
80
81 public:
82 /**************************************************************************************
83 | |
84 | Constructors |
85 | |
86 **************************************************************************************/
87
88 constexpr TreeCode() noexcept = default;
89 constexpr TreeCode(TreeCode const&) noexcept = default;
90
91 constexpr TreeCode(std::array<code_type, 3> const& code, depth_type const& depth)
92 : code_(code), depth_(depth)
93 {
94 assert(valid());
95 }
96
97 constexpr explicit TreeCode(std::array<code_type, 3> const& code) : TreeCode(code, 0) {}
98
99 constexpr explicit TreeCode(TreeKey<Dim> const& key) : depth_(key.depth())
100 {
101 auto k = key << key.depth();
102
103 code_[0] = Morton<Dim>::encode32(k);
104 if constexpr (ACTIVE[1]) {
105 code_[1] = Morton<Dim>::encode32(k >> DEPTHS_PER_IDX);
106 }
107 if constexpr (ACTIVE[2]) {
108 code_[2] = Morton<Dim>::encode32(k >> (2 * DEPTHS_PER_IDX));
109 }
110 }
111
112 [[nodiscard]] static constexpr TreeCode invalid() noexcept
113 {
114 TreeCode code;
115 code.invalidate();
116 return code;
117 }
118
119 /**************************************************************************************
120 | |
121 | Assignment operator |
122 | |
123 **************************************************************************************/
124
125 constexpr TreeCode& operator=(TreeCode const&) noexcept = default;
126
127 /**************************************************************************************
128 | |
129 | Conversion operator |
130 | |
131 **************************************************************************************/
132
133 [[nodiscard]] constexpr explicit operator TreeKey<Dim>() const noexcept
134 {
135 typename TreeKey<Dim>::Key key = Morton<Dim>::decode32(code_[0]);
136
137 if constexpr (ACTIVE[1]) {
138 auto k = Morton<Dim>::decode32(code_[1]) << DEPTHS_PER_IDX;
139 for (std::size_t j{}; Dim > j; ++j) {
140 key[j] |= k[j];
141 }
142 }
143 if constexpr (ACTIVE[2]) {
144 auto k = Morton<Dim>::decode32(code_[2]) << (2 * DEPTHS_PER_IDX);
145 for (std::size_t j{}; Dim > j; ++j) {
146 key[j] |= k[j];
147 }
148 }
149
150 return TreeKey<Dim>(key >> depth_, depth_);
151 }
152
153 /**************************************************************************************
154 | |
155 | Element access |
156 | |
157 **************************************************************************************/
158
159 [[nodiscard]] constexpr key_type operator[](size_type pos) const noexcept
160 {
161 assert(size() > pos);
162
163 key_type k = Morton<Dim>::decode32(code_[0], pos);
164
165 if constexpr (ACTIVE[1]) {
166 k |= Morton<Dim>::decode32(code_[1], pos) << DEPTHS_PER_IDX;
167 }
168 if constexpr (ACTIVE[2]) {
169 k |= Morton<Dim>::decode32(code_[2], pos) << (2 * DEPTHS_PER_IDX);
170 }
171
172 return k >> depth_;
173 }
174
175 /**************************************************************************************
176 | |
177 | Capacity |
178 | |
179 **************************************************************************************/
180
181 [[nodiscard]] static constexpr size_type size() noexcept { return Dim; }
182
183 /**************************************************************************************
184 | |
185 | Operations |
186 | |
187 **************************************************************************************/
188
189 [[nodiscard]] constexpr bool valid() const noexcept
190 {
191 bool a = maxDepth() >= depth();
192 // TODO: Implement
193 // // Check if unused upper bits are set to zero
194 // bool b = 0 == (code() >> (Dim * maxDepth()));
195 // // Check if unused lower bits are set to zero
196 // bool c = code() == ((code() >> (Dim * depth())) << (Dim * depth()));
197
198 // return a && b && c;
199 return a;
200 }
201
202 constexpr void invalidate() noexcept { depth_ = maxDepth() + 1; }
203
204 [[nodiscard]] static constexpr std::size_t branchingFactor() noexcept
205 {
206 return ipow(std::size_t(2), static_cast<int>(Dim));
207 }
208
209 // [[nodiscard]] constexpr code_type code() const noexcept { return code_; }
210
211 [[nodiscard]] static constexpr depth_type maxDepth() noexcept
212 {
213 depth_type max_depth = DEPTHS_PER_IDX;
214 if constexpr (ACTIVE[1]) {
215 max_depth += DEPTHS_PER_IDX;
216 }
217 if constexpr (ACTIVE[2]) {
218 max_depth += DEPTHS_PER_IDX;
219 }
220 return max_depth;
221 }
222
223 [[nodiscard]] constexpr depth_type depth() const noexcept { return depth_; }
224
225 [[nodiscard]] static constexpr bool sameAncestorAtDepth(TreeCode const& lhs,
226 TreeCode const& rhs,
227 depth_type depth) noexcept
228 {
229 assert(maxDepth() >= depth);
230 assert(lhs.valid() && rhs.valid());
231
232 auto i = depth / DEPTHS_PER_IDX;
233 auto d = depth % DEPTHS_PER_IDX;
234
235 std::array<code_type, 3> m{0 >= i ? ~code_type(0) : code_type(0),
236 1 >= i ? ~code_type(0) : code_type(0),
237 2 >= i ? ~code_type(0) : code_type(0)};
238
239 m[i] <<= Dim * d;
240
241 return (lhs.code_[0] & m[0]) == (rhs.code_[0] & m[0]) &&
242 (lhs.code_[1] & m[1]) == (rhs.code_[1] & m[1]) &&
243 (lhs.code_[2] & m[2]) == (rhs.code_[2] & m[2]);
244 }
245
246 [[nodiscard]] constexpr bool isAncestorOf(TreeCode const& other) const noexcept
247 {
248 return depth() >= other.depth() && sameAncestorAtDepth(*this, other, depth());
249 }
250
251 [[nodiscard]] constexpr bool isDescendantOf(TreeCode const& other) const noexcept
252 {
253 return other.isAncestorOf(*this);
254 }
255
256 [[nodiscard]] constexpr bool isSiblingOf(TreeCode const& other) const noexcept
257 {
258 return depth() == other.depth() && sameAncestorAtDepth(*this, other, depth() + 1);
259 }
260
261 [[nodiscard]] static constexpr depth_type lowestCommonAncestor(
262 TreeCode const& lhs, TreeCode const& rhs) noexcept
263 {
264 assert(lhs.valid() && rhs.valid());
265
266 auto depth =
267 lhs.code_[2] != rhs.code_[2]
268 ? 2 * DEPTHS_PER_IDX
269 : static_cast<depth_type>(lhs.code_[1] != rhs.code_[1]) * DEPTHS_PER_IDX;
270 depth = std::max(depth, std::max(lhs.depth(), rhs.depth()));
271
272 auto i = depth / DEPTHS_PER_IDX;
273 auto d = depth % DEPTHS_PER_IDX;
274 code_type c = (lhs.code_[i] ^ rhs.code_[i]) >> (Dim * d);
275 for (; c; c >>= Dim, ++depth) {
276 }
277
278 return depth;
279 }
280
281 [[nodiscard]] constexpr TreeCode toDepth(depth_type depth) const
282 {
283 assert(maxDepth() >= depth);
284
285 TreeCode ret = *this;
286 ret.setDepth(depth);
287 return ret;
288 }
289
290 constexpr void setDepth(depth_type depth)
291 {
292 assert(maxDepth() >= depth);
293
294 auto i = depth / DEPTHS_PER_IDX;
295 auto d = depth % DEPTHS_PER_IDX;
296
297 std::array<code_type, 3> m{0 >= i ? ~code_type(0) : code_type(0),
298 1 >= i ? ~code_type(0) : code_type(0),
299 2 >= i ? ~code_type(0) : code_type(0)};
300
301 m[i] <<= Dim * d;
302
303 code_[0] &= m[0];
304 code_[1] &= m[1];
305 code_[2] &= m[2];
306 depth_ = depth;
307 }
308
314 [[nodiscard]] constexpr code_type offset() const { return offset(depth_); }
315
322 [[nodiscard]] constexpr code_type offset(depth_type depth) const
323 {
324 assert(maxDepth() >= depth && depth_ <= depth);
325
326 auto i = depth / DEPTHS_PER_IDX;
327 auto d = depth % DEPTHS_PER_IDX;
328 return (code_[i] >> (Dim * d)) & OFFSET_MASK;
329 }
330
331 constexpr void setOffset(code_type offset) { setOffset(depth_, offset); }
332
333 constexpr void setOffset(depth_type depth, code_type offset)
334 {
335 assert(maxDepth() >= depth && depth_ <= depth && branchingFactor() > offset);
336
337 auto i = depth / DEPTHS_PER_IDX;
338 auto d = depth % DEPTHS_PER_IDX;
339
340 // NOTE: Two shifts to prevent shifting by more bits than code_type contains
341 code_[i] &= ((~code_type(0)) << Dim) << (Dim * d);
342 code_[i] |= static_cast<code_type>(offset) << (Dim * d);
343 }
344
345 [[nodiscard]] constexpr TreeCode parent() const { return toDepth(depth_ + 1); }
346
353 [[nodiscard]] constexpr TreeCode child(std::size_t idx) const
354 {
355 assert(0 < depth_);
356 assert(branchingFactor() > idx);
357
358 return firstborn().firstbornSibling(idx);
359 }
360
366 [[nodiscard]] constexpr TreeCode firstborn() const
367 {
368 assert(0 < depth_);
369 return TreeCode(code_, depth_ - 1);
370 }
371
378 [[nodiscard]] constexpr TreeCode sibling(std::size_t idx) const
379 {
380 TreeCode ret = *this;
381 ret.setOffset(depth_, idx);
382 return ret;
383 }
384
385 [[nodiscard]] constexpr TreeCode nextSibling() const
386 {
387 assert(branchingFactor() > offset() + 1);
388
389 auto i = depth_ / DEPTHS_PER_IDX;
390 auto d = depth_ % DEPTHS_PER_IDX;
391
392 TreeCode ret = *this;
393 ret.code_[i] += code_type(1) << (Dim * d);
394 return ret;
395 }
396
397 [[nodiscard]] constexpr TreeCode prevSibling() const
398 {
399 assert(0 < offset());
400
401 auto i = depth_ / DEPTHS_PER_IDX;
402 auto d = depth_ % DEPTHS_PER_IDX;
403
404 TreeCode ret = *this;
405 ret.code_[i] -= code_type(1) << (Dim * d);
406 return ret;
407 }
408
418 [[nodiscard]] constexpr TreeCode firstbornSibling(std::size_t idx) const
419 {
420 assert(0 == offset(depth_));
421 assert(branchingFactor() > idx);
422
423 auto i = depth_ / DEPTHS_PER_IDX;
424 auto d = depth_ % DEPTHS_PER_IDX;
425
426 TreeCode ret = *this;
427 ret.code_[i] |= static_cast<code_type>(idx) << (Dim * d);
428 return ret;
429 }
430
431 // void append(code_type code, depth_type num_depths)
432 // {
433 // // TODO: Fix asserts
434 // assert(depth() >= num_depths);
435
436 // // TODO: Implement
437 // }
438
439 // code_type remove(depth_type num_depths)
440 // {
441 // // TODO: Fix asserts
442 // assert(maxDepth() - depth() >= num_depths);
443 // assert(DEPTHS_PER_IDX >= num_depths);
444
445 // // TODO: Implement
446 // }
447
448 // [[nodiscard]] code_type lowestOffsets(depth_type num_depths) const
449 // {
450 // // // TODO: Fix asserts
451 // // assert(maxDepth() - depth() >= num_depths);
452 // // assert(DEPTHS_PER_IDX >= num_depths);
453
454 // // // TODO: Implement
455 // // return 0;
456
457 // assert(DEPTHS_PER_IDX >= num_depths);
458
459 // return code_[0] &
460 // (~code_type(0) >> (std::numeric_limits<code_type>::digits - Dim *
461 // num_depths));
462 // }
463
464 // void lowestOffsets(depth_type num_depths, code_type lowest_offsets)
465 // {
466 // // // TODO: Fix asserts
467 // // assert(maxDepth() - depth() >= num_depths);
468 // // assert(DEPTHS_PER_IDX >= num_depths);
469
470 // // // TODO: Implement
471 // // return 0;
472
473 // assert(DEPTHS_PER_IDX >= num_depths);
474
475 // // TODO: Fix
476 // code_[0] |= lowest_offsets;
477
478 // // return code_[0] &
479 // // (~code_type(0) >> (std::numeric_limits<code_type>::digits - Dim *
480 // num_depths));
481 // }
482
483 [[nodiscard]] code_type lowestOffsets() const { return code_[0]; }
484
485 void lowestOffsets(code_type lowest_offsets, depth_type depth = 0)
486 {
487 code_[0] = lowest_offsets;
488 depth_ = depth;
489 }
490
491 /**************************************************************************************
492 | |
493 | Compare |
494 | |
495 **************************************************************************************/
496
497 friend constexpr bool operator==(TreeCode const& lhs, TreeCode const& rhs) noexcept
498 {
499 return lhs.code_ == rhs.code_ && lhs.depth_ == rhs.depth_;
500 }
501
502 friend constexpr bool operator!=(TreeCode const& lhs, TreeCode const& rhs) noexcept
503 {
504 return !(lhs == rhs);
505 }
506
507 friend constexpr bool operator<(TreeCode const& lhs, TreeCode const& rhs) noexcept
508 {
509 return lhs.code_ < rhs.code_;
510 }
511
512 friend constexpr bool operator<=(TreeCode const& lhs, TreeCode const& rhs) noexcept
513 {
514 return lhs.code_ <= rhs.code_;
515 }
516
517 friend constexpr bool operator>(TreeCode const& lhs, TreeCode const& rhs) noexcept
518 {
519 return lhs.code_ > rhs.code_;
520 }
521
522 friend constexpr bool operator>=(TreeCode const& lhs, TreeCode const& rhs) noexcept
523 {
524 return lhs.code_ >= rhs.code_;
525 }
526
527 friend std::ostream& operator<<(std::ostream& os, TreeCode const& code)
528 {
529 os << "code: " << code.code_[0] << " ";
530 if constexpr (ACTIVE[1]) {
531 os << code.code_[1] << " ";
532 }
533 if constexpr (ACTIVE[2]) {
534 os << code.code_[2] << " ";
535 }
536 return os << "depth: " << code.depth();
537 }
538
539 private:
540 std::array<code_type, 3> code_{};
541 depth_type depth_ = maxDepth() + 1;
542};
543
544using BinaryCode = TreeCode<1>;
545using QuadCode = TreeCode<2>;
546using OctCode = TreeCode<3>;
547using HexCode = TreeCode<4>;
548
549} // namespace ufo
550
551namespace std
552{
553template <std::size_t Dim>
554struct hash<ufo::TreeCode<Dim>> {
555 std::size_t operator()(ufo::TreeCode<Dim> code) const
556 {
557 // Code size
558 static constexpr std::size_t const CS =
559 std::numeric_limits<typename ufo::TreeCode<Dim>::code_type>::digits;
560 // Hash size
561 static constexpr std::size_t const HS = std::numeric_limits<std::size_t>::digits;
562
563 std::size_t h = static_cast<std::size_t>(code.code_[0]);
564 if constexpr (ufo::TreeCode<Dim>::ACTIVE[1] && HS > CS) {
565 h |= static_cast<std::size_t>(code.code_[1]) << CS;
566 }
567 if constexpr (ufo::TreeCode<Dim>::ACTIVE[2] && HS > 2 * CS) {
568 h |= static_cast<std::size_t>(code.code_[2]) << (2 * CS);
569 }
570 return h;
571 }
572};
573} // namespace std
574
575#endif // UFO_CONTAINER_TREE_CODE_HPP
constexpr TreeCode firstbornSibling(std::size_t idx) const
Get the code of a specific sibling of this firstborn code.
Definition code.hpp:418
constexpr TreeCode sibling(std::size_t idx) const
Get the code of a specific sibling of this code.
Definition code.hpp:378
constexpr TreeCode child(std::size_t idx) const
Get the code of a specific child of this code.
Definition code.hpp:353
constexpr TreeCode firstborn() const
Get the code of the firstborn child of this code (same as child(0)).
Definition code.hpp:366
constexpr code_type offset() const
Get the offset at the current depth (same as c.offset(c.depth())).
Definition code.hpp:314
constexpr code_type offset(depth_type depth) const
Get the offset at a specific depth for this code.
Definition code.hpp:322
constexpr T ipow(T base, int exp) noexcept
Computes integer power of a base.
Definition math.hpp:112
STL namespace.
All vision-related classes and functions.
Definition cloud.hpp:49
constexpr T a(Lab< T, Flags > color) noexcept
Returns the un-weighted green–red axis value.
Definition lab.hpp:310
A fixed-size arithmetic vector of up to 4 dimensions.
Definition vec.hpp:76