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