UFO 1.0.0
An Efficient Probabilistic 3D Mapping Framework That Embraces the Unknown
Loading...
Searching...
No Matches
count_map.hpp
1
42#ifndef UFO_MAP_COUNT_MAP_HPP
43#define UFO_MAP_COUNT_MAP_HPP
44
45// UFO
46#include <ufo/map/types.hpp>
47#include <ufo/utility/io/buffer.hpp>
48
49// STL
50#include <algorithm>
51#include <array>
52#include <cstdint>
53#include <type_traits>
54#include <utility>
55#include <vector>
56
57namespace ufo
58{
59template <class Derived, offset_t N, class Index, class Node, class Code, class Key,
60 class Coord>
62{
63 public:
64 using CountBlock = DataBlock<count_t, N>;
65
66 //
67 // Count block
68 //
69
70 [[nodiscard]] CountBlock& countBlock(pos_t block) { return count_[block]; }
71
72 [[nodiscard]] CountBlock const& countBlock(pos_t block) const { return count_[block]; }
73
74 //
75 // Get count
76 //
77
78 [[nodiscard]] count_t count(Index node) const { return count_[node.pos][node.offset]; }
79
80 [[nodiscard]] count_t count(Node node) const { return count(derived().index(node)); }
81
82 [[nodiscard]] count_t count(Code code) const { return count(derived().index(code)); }
83
84 [[nodiscard]] count_t count(Key key) const { return count(derived().index(key)); }
85
86 [[nodiscard]] count_t count(Coord coord, depth_t depth = 0) const
87 {
88 return count(derived().index(coord, depth));
89 }
90
91 //
92 // Set count
93 //
94
95 void setCount(Index node, count_t count)
96 {
97 return derived().apply(
98 node, [this, count](Index node) { count_[node.pos][node.offset] = count; },
99 [this, count](pos_t pos) { count_[pos].fill(count); });
100 }
101
102 Node setCount(Node node, count_t count, bool propagate = true)
103 {
104 return derived().apply(
105 node, [this, count](Index node) { count_[node.pos][node.offset] = count; },
106 [this, count](pos_t pos) { count_[pos].fill(count); }, propagate);
107 }
108
109 Node setCount(Code code, count_t count, bool propagate = true)
110 {
111 return derived().apply(
112 code, [this, count](Index node) { count_[node.pos][node.offset] = count; },
113 [this, count](pos_t pos) { count_[pos].fill(count); }, propagate);
114 }
115
116 Node setCount(Key key, count_t count, bool propagate = true)
117 {
118 return setCount(derived().toCode(key), count, propagate);
119 }
120
121 Node setCount(Coord coord, count_t count, bool propagate = true, depth_t depth = 0)
122 {
123 return setCount(derived().toCode(coord, depth), count, propagate);
124 }
125
126 //
127 // Update count
128 //
129
130 void updateCount(Index node, int change)
131 {
132 derived().apply(
133 node, [this, change](Index node) { count_[node.pos][node.offset] += change; },
134 [this, change](pos_t pos) {
135 for (auto& e : count_[pos]) {
136 e += change;
137 }
138 });
139 }
140
141 template <class UnaryOp,
142 std::enable_if_t<std::is_invocable_v<UnaryOp, count_t>, bool> = true>
143 void updateCount(Index node, UnaryOp unary_op)
144 {
145 derived().apply(
146 node,
147 [this, unary_op](Index node) {
148 count_[node.pos][node.offset] = unary_op(count_[node.pos][node.offset]);
149 },
150 [this, unary_op](pos_t pos) {
151 for (auto& e : count_[pos]) {
152 e = unary_op(e);
153 }
154 });
155 }
156
157 template <class BinaryOp,
158 std::enable_if_t<std::is_invocable_v<BinaryOp, Index, count_t>, bool> = true>
159 void updateCount(Index node, BinaryOp binary_op)
160 {
161 derived().apply(
162 node,
163 [this, binary_op](Index node) {
164 count_[node.pos][node.offset] = binary_op(node, count_[node.pos][node.offset]);
165 },
166 [this, binary_op](pos_t pos) {
167 offset_t i{};
168 for (auto& e : count_[pos]) {
169 e = binary_op(Index(pos, i++), e);
170 }
171 });
172 }
173
174 Node updateCount(Node node, int change, bool propagate = true)
175 {
176 return derived().apply(
177 node, [this, change](Index node) { count_[node.pos][node.offset] += change; },
178 [this, change](pos_t pos) {
179 for (auto& e : count_[pos]) {
180 e += change;
181 }
182 },
183 propagate);
184 }
185
186 template <class UnaryOp,
187 std::enable_if_t<std::is_invocable_v<UnaryOp, count_t>, bool> = true>
188 Node updateCount(Node node, UnaryOp unary_op, bool propagate = true)
189 {
190 return derived().apply(
191 node,
192 [this, unary_op](Index node) {
193 count_[node.pos][node.offset] = unary_op(count_[node.pos][node.offset]);
194 },
195 [this, unary_op](pos_t pos) {
196 for (auto& e : count_[pos]) {
197 e = unary_op(e);
198 }
199 },
200 propagate);
201 }
202
203 template <class BinaryOp,
204 std::enable_if_t<std::is_invocable_v<BinaryOp, Index, count_t>, bool> = true>
205 Node updateCount(Node node, BinaryOp binary_op, bool propagate = true)
206 {
207 return derived().apply(
208 node,
209 [this, binary_op](Index node) {
210 count_[node.pos][node.offset] = binary_op(node, count_[node.pos][node.offset]);
211 },
212 [this, binary_op](pos_t pos) {
213 offset_t i{};
214 for (auto& e : count_[pos]) {
215 e = binary_op(Index(pos, i++), e);
216 }
217 },
218 propagate);
219 }
220
221 Node updateCount(Code code, int change, bool propagate = true)
222 {
223 return derived().apply(
224 code, [this, change](Index node) { count_[node.pos][node.offset] += change; },
225 [this, change](pos_t pos) {
226 for (auto& e : count_[pos]) {
227 e += change;
228 }
229 },
230 propagate);
231 }
232
233 template <class UnaryOp,
234 std::enable_if_t<std::is_invocable_v<UnaryOp, count_t>, bool> = true>
235 Node updateCount(Code code, UnaryOp unary_op, bool propagate = true)
236 {
237 return derived().apply(
238 code,
239 [this, unary_op](Index node) {
240 count_[node.pos][node.offset] = unary_op(count_[node.pos][node.offset]);
241 },
242 [this, unary_op](pos_t pos) {
243 for (auto& e : count_[pos]) {
244 e = unary_op(e);
245 }
246 },
247 propagate);
248 }
249
250 template <class BinaryOp,
251 std::enable_if_t<std::is_invocable_v<BinaryOp, Index, count_t>, bool> = true>
252 Node updateCount(Code code, BinaryOp binary_op, bool propagate = true)
253 {
254 return derived().apply(
255 code,
256 [this, binary_op](Index node) {
257 count_[node.pos][node.offset] = binary_op(node, count_[node.pos][node.offset]);
258 },
259 [this, binary_op](pos_t pos) {
260 offset_t i{};
261 for (auto& e : count_[pos]) {
262 e = binary_op(Index(pos, i++), e);
263 }
264 },
265 propagate);
266 }
267
268 Node updateCount(Key key, int change, bool propagate = true)
269 {
270 return updateCount(derived().toCode(key), change, propagate);
271 }
272
273 template <class UnaryOp,
274 std::enable_if_t<std::is_invocable_v<UnaryOp, count_t>, bool> = true>
275 Node updateCount(Key key, UnaryOp unary_op, bool propagate = true)
276 {
277 return updateCount(derived().toCode(key), unary_op, propagate);
278 }
279
280 template <class BinaryOp,
281 std::enable_if_t<std::is_invocable_v<BinaryOp, Index, count_t>, bool> = true>
282 Node updateCount(Key key, BinaryOp binary_op, bool propagate = true)
283 {
284 return updateCount(derived().toCode(key), binary_op, propagate);
285 }
286
287 Node updateCount(Coord coord, int change, bool propagate = true, depth_t depth = 0)
288 {
289 return updateCount(derived().toCode(coord, depth), change, propagate);
290 }
291
292 template <class UnaryOp,
293 std::enable_if_t<std::is_invocable_v<UnaryOp, count_t>, bool> = true>
294 Node updateCount(Coord coord, UnaryOp unary_op, bool propagate = true,
295 depth_t depth = 0)
296 {
297 return updateCount(derived().toCode(coord, depth), unary_op, propagate);
298 }
299
300 template <class BinaryOp,
301 std::enable_if_t<std::is_invocable_v<BinaryOp, Index, count_t>, bool> = true>
302 Node updateCount(Coord coord, BinaryOp binary_op, bool propagate = true,
303 depth_t depth = 0)
304 {
305 return updateCount(derived().toCode(coord, depth), binary_op, propagate);
306 }
307
308 //
309 // Propagation criteria
310 //
311
312 [[nodiscard]] constexpr PropagationCriteria countPropagationCriteria() const noexcept
313 {
314 return prop_criteria_;
315 }
316
317 void setCountPropagationCriteria(PropagationCriteria prop_criteria,
318 bool propagate = true)
319 {
320 if (prop_criteria_ == prop_criteria) {
321 return;
322 }
323
324 prop_criteria_ = prop_criteria;
325
326 derived().setModified();
327
328 if (propagate) {
329 derived().propagateModified();
330 }
331 }
332
333 protected:
334 //
335 // Constructors
336 //
337
338 CountMap() { count_.emplace_back(); }
339
340 CountMap(CountMap const&) = default;
341
342 CountMap(CountMap&&) = default;
343
344 template <class Derived2>
346 : count_(other.count_), prop_criteria_(other.prop_criteria_)
347 {
348 }
349
350 template <class Derived2>
352 : count_(std::move(other.count_)), prop_criteria_(std::move(other.prop_criteria_))
353 {
354 }
355
356 //
357 // Destructor
358 //
359
360 ~CountMap() = default;
361
362 //
363 // Assignment operator
364 //
365
366 CountMap& operator=(CountMap const&) = default;
367
368 CountMap& operator=(CountMap&&) = default;
369
370 template <class Derived2>
372 {
373 count_ = rhs.count_;
374 prop_criteria_ = rhs.prop_criteria_;
375 return *this;
376 }
377
378 template <class Derived2>
380 {
381 count_ = std::move(rhs.count_);
382 prop_criteria_ = std::move(rhs.prop_criteria_);
383 return *this;
384 }
385
386 //
387 // Swap
388 //
389
390 void swap(CountMap& other) noexcept
391 {
392 std::swap(count_, other.count_);
393 std::swap(prop_criteria_, other.prop_criteria_);
394 }
395
396 //
397 // Derived
398 //
399
400 [[nodiscard]] constexpr Derived& derived() { return *static_cast<Derived*>(this); }
401
402 [[nodiscard]] constexpr Derived const& derived() const
403 {
404 return *static_cast<Derived const*>(this);
405 }
406
407 //
408 // Create node block
409 //
410
411 void createBlock(Index node)
412 {
413 count_.emplace_back();
414 count_.back().fill(count_[node.pos][node.offset]);
415 }
416
417 //
418 // Resize
419 //
420
421 void resize(std::size_t count)
422 {
423 // TODO: Implement
424 count_.resize(count);
425 }
426
427 //
428 // Reserve
429 //
430
431 void reserveImpl(std::size_t new_cap) { count_.reserve(new_cap); }
432
433 //
434 // Initialize root
435 //
436
437 void initRoot()
438 {
439 auto node = derived().rootIndex();
440 count_[node.pos][node.offset] = 0;
441 }
442
443 //
444 // Fill
445 //
446
447 void fill(Index node, pos_t children)
448 {
449 count_[children].fill(count_[node.pos][node.offset]);
450 }
451
452 //
453 // Clear
454 //
455
456 void clearImpl() { count_.resize(1); }
457
458 void clearImpl(pos_t) {}
459
460 //
461 // Update node
462 //
463
464 void updateBlock(pos_t block, std::array<bool, N> modified_parent)
465 {
466 for (offset_t i{}; N != i; ++i) {
467 if (modified_parent[i]) {
468 Index node(block, i);
469 updateNode(node, derived().children(node));
470 }
471 }
472 }
473
474 void updateNode(Index node, pos_t children)
475 {
476 switch (countPropagationCriteria()) {
477 case PropagationCriteria::MIN:
478 count_[node.pos][node.offset] = min(children);
479 return;
480 case PropagationCriteria::MAX:
481 count_[node.pos][node.offset] = max(children);
482 return;
483 case PropagationCriteria::MEAN:
484 count_[node.pos][node.offset] = mean(children);
485 return;
486 case PropagationCriteria::NONE: return;
487 }
488 }
489
490 [[nodiscard]] constexpr count_t min(pos_t block) const
491 {
492 count_t ret = count_[block][0];
493 for (auto e : count_[block]) {
494 ret = std::min(ret, e);
495 }
496 return ret;
497 }
498
499 [[nodiscard]] constexpr count_t max(pos_t block) const
500 {
501 count_t ret = count_[block][0];
502 for (auto e : count_[block]) {
503 ret = std::max(ret, e);
504 }
505 return ret;
506 }
507
508 [[nodiscard]] constexpr count_t mean(pos_t block) const
509 {
510 // FIXME: What happens if count_t is not unsigned integer?
511 if constexpr (std::is_unsigned_v<count_t>) {
512 return std::accumulate(std::cbegin(count_[block]), std::cend(count_[block]),
513 std::uint64_t(0)) /
514 N;
515 } else {
516 return std::accumulate(std::cbegin(count_[block]), std::cend(count_[block]), 0.0) /
517 N;
518 }
519 }
520
521 //
522 // Is prunable
523 //
524
525 [[nodiscard]] bool isPrunable(pos_t block) const
526 {
527 return std::all_of(std::cbegin(count_[block]) + 1, std::cend(count_[block]),
528 [a = count_[block].front()](auto b) { return a == b; });
529 }
530
531 //
532 // Memory
533 //
534
535 [[nodiscard]] static constexpr std::size_t sizeofNodeTimesN(Index) noexcept
536 {
537 return sizeofBlockLowerBound();
538 }
539
540 [[nodiscard]] static constexpr std::size_t sizeofBlock(pos_t) noexcept
541 {
542 return sizeofBlockLowerBound();
543 }
544
545 [[nodiscard]] static constexpr std::size_t sizeofBlockLowerBound() noexcept
546 {
547 return sizeof(typename decltype(count_)::value_type);
548 }
549
550 [[nodiscard]] static constexpr std::size_t sizeofMap() noexcept
551 {
552 return sizeof(count_) + sizeof(prop_criteria_);
553 }
554
555 //
556 // Input/output (read/write)
557 //
558
559 [[nodiscard]] static constexpr MapType mapType() noexcept { return MapType::COUNT; }
560
561 [[nodiscard]] static constexpr std::size_t serializedSizeBlock() noexcept
562 {
563 return sizeof(typename decltype(count_)::value_type);
564 }
565
566 template <class Container>
567 std::size_t serializedSize(Container const& c) const
568 {
569 return c.size() * serializedSizeBlock();
570 }
571
572 template <class Container>
573 void readNodes(ReadBuffer& in, Container const& c)
574 {
575 for (auto const [pos, offsets] : c) {
576 if (offsets.all()) {
577 in.read(count_[pos].data(), serializedSizeBlock());
578 } else {
579 CountBlock count;
580 in.read(count.data(), serializedSizeBlock());
581 for (offset_t i{}; N != i; ++i) {
582 count_[pos][i] = offsets[i] ? count[i] : count_[pos][i];
583 }
584 }
585 }
586 }
587
588 template <class BlockRange>
589 void writeBlocks(WriteBuffer& out, BlockRange const& blocks) const
590 {
591 for (auto block : blocks) {
592 out.write(count_[block].data(), serializedSizeBlock());
593 }
594 }
595
596 protected:
597 // Data
598 Container<CountBlock> count_;
599
600 // Propagation criteria
601 PropagationCriteria prop_criteria_ = PropagationCriteria::MAX;
602
603 template <class Derived2, offset_t N2, class Index2, class Node2, class Code2,
604 class Key2, class Coord2>
605 friend class CountMap;
606};
607} // namespace ufo
608
609#endif // UFO_MAP_COUNT_MAP_HPP
All vision-related classes and functions.
Definition cloud.hpp:49
constexpr T b(Lab< T, Flags > color) noexcept
Returns the un-weighted blue–yellow axis value.
Definition lab.hpp:326
constexpr T a(Lab< T, Flags > color) noexcept
Returns the un-weighted green–red axis value.
Definition lab.hpp:310