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