UFO 1.0.0
An Efficient Probabilistic 3D Mapping Framework That Embraces the Unknown
Loading...
Searching...
No Matches
map.hpp
1
42#ifndef UFO_MAP_COST_MAP_HPP
43#define UFO_MAP_COST_MAP_HPP
44
45// UFO
46#include <ufo/container/tree/container.hpp>
47#include <ufo/container/tree/tree.hpp>
48#include <ufo/map/cost/block.hpp>
49#include <ufo/map/cost/predicate.hpp>
50#include <ufo/map/cost/propagation_criteria.hpp>
51#include <ufo/map/map/map_block.hpp>
52#include <ufo/map/type.hpp>
53#include <ufo/numeric/transform3.hpp>
54#include <ufo/utility/bit_set.hpp>
55#include <ufo/utility/io/buffer.hpp>
56#include <ufo/utility/macros.hpp>
57#include <ufo/utility/type_traits.hpp>
58
59// STL
60#include <array>
61#include <iostream>
62#include <limits>
63#include <string_view>
64#include <type_traits>
65
66namespace ufo
67{
68template <class Derived, class Tree>
70{
71 private:
72 template <class Derived2, class Tree2>
73 friend class CostMap;
74
75 static constexpr auto const BF = Tree::branchingFactor();
76 static constexpr auto const Dim = Tree::dimensions();
77
78 public:
79 /**************************************************************************************
80 | |
81 | Tags |
82 | |
83 **************************************************************************************/
84
85 static constexpr MapType const Type = MapType::COST;
86
87 // Container
88 using Index = typename Tree::Index;
89 using Node = typename Tree::Node;
90 using Code = typename Tree::Code;
91 using Key = typename Tree::Key;
92 using Point = typename Tree::Point;
93 using Coord = typename Tree::Coord;
94 using coord_t = typename Tree::coord_t;
95 using depth_t = typename Tree::depth_t;
96 using offset_t = typename Tree::offset_t;
97 using length_t = typename Tree::length_t;
98 using pos_t = typename Tree::pos_t;
99
100 // Cost
101 using cost_t = typename CostBlock<BF>::cost_t;
102
103 public:
104 /**************************************************************************************
105 | |
106 | Access |
107 | |
108 **************************************************************************************/
109
110 template <class NodeType,
111 std::enable_if_t<Tree::template is_node_type_v<NodeType>, bool> = true>
112 [[nodiscard]] cost_t cost(NodeType node) const
113 {
114 Index n = derived().index(node);
115 return costBlock(n.pos)[n.offset].cost;
116 }
117
118 /**************************************************************************************
119 | |
120 | Modifiers |
121 | |
122 **************************************************************************************/
123
135 template <class NodeType,
136 std::enable_if_t<Tree::template is_node_type_v<NodeType>, bool> = true>
137 void costSet(NodeType node, cost_t value, bool propagate = true)
138 {
139 CostElement elem(value);
140
141 auto node_f = [this, elem](Index node) { costBlock(node.pos)[node.offset] = elem; };
142 auto block_f = [this, elem](pos_t pos) { costBlock(pos).fill(elem); };
143
144 if constexpr (std::is_same_v<Index, std::decay_t<NodeType>>) {
145 if (propagate) {
146 derived().recursParentFirst(node, node_f, block_f);
147 } else {
148 derived().recursLeaves(node, node_f, block_f);
149 }
150 } else {
151 if (propagate) {
152 auto propagate_f = [this](Index node, pos_t children) {
153 onPropagateChildren(node, children);
154 };
155
156 derived().recursLeaves(derived().code(node), node_f, block_f, propagate_f,
157 propagate);
158 } else {
159 derived().recursParentFirst(derived().code(node), node_f, block_f);
160 }
161 }
162 }
163
164 template <class NodeType,
165 std::enable_if_t<Tree::template is_node_type_v<NodeType>, bool> = true>
166 void costUpdate(NodeType node, cost_t change, bool propagate = true)
167 {
168 costUpdate(
169 node,
170 [this, change](Index node) {
171 return CostBlock(node.pos)[node.offset].cost + change;
172 },
173 propagate);
174 }
175
176 template <class NodeType, class UnaryOp,
177 std::enable_if_t<Tree::template is_node_type_v<NodeType>, bool> = true,
178 std::enable_if_t<std::is_invocable_r_v<cost_t, UnaryOp, Index>, bool> = true>
179 void costUpdate(NodeType node, UnaryOp unary_op, bool propagate = true)
180 {
181 auto node_f = [this, unary_op](Index node) {
182 cost_t value = unary_op(node);
183
184 auto& cb = CostBlock(node.pos)[node.offset];
185 cb.cost = value;
186 };
187
188 auto block_f = [this, node_f](pos_t pos) {
189 for (std::size_t i{}; BF > i; ++i) {
190 node_f(Index(pos, i));
191 }
192 };
193
194 auto propagate_f = [this](Index node, pos_t children) {
195 onPropagateChildren(node, children);
196 };
197
198 if constexpr (std::is_same_v<Index, std::decay_t<NodeType>>) {
199 if (propagate) {
200 derived().recursLeaves(node, node_f, block_f, propagate_f);
201 } else {
202 derived().recursLeaves(node, node_f, block_f);
203 }
204 } else {
205 derived().recursLeaves(derived().code(node), node_f, block_f, propagate_f,
206 propagate);
207 }
208 }
209
210 //
211 // Propagation criteria
212 //
213
214 [[nodiscard]] constexpr CostPropagationCriteria costPropagationCriteria() const noexcept
215 {
216 return prop_criteria_;
217 }
218
219 void costSetPropagationCriteria(CostPropagationCriteria prop_criteria,
220 bool propagate = true)
221 {
222 if (CostPropagationCriteria() == prop_criteria) {
223 return;
224 }
225
226 prop_criteria_ = prop_criteria;
227
228 // Set all inner nodes to modified
229 // FIXME: Possible to optimize this to only set the ones with children
230 derived().setModified();
231
232 if (propagate) {
233 derived().propagateModified();
234 }
235 }
236
237 protected:
238 /**************************************************************************************
239 | |
240 | Constructors |
241 | |
242 **************************************************************************************/
243
244 CostMap() { onInitRoot(); }
245
246 CostMap(CostMap const& other) = default;
247
248 CostMap(CostMap&& other) = default;
249
250 template <class Derived2, class Tree2>
251 CostMap(CostMap<Derived2, Tree2> const& other) : prop_criteria_(other.prop_criteria_)
252 {
253 }
254
255 template <class Derived2, class Tree2>
256 CostMap(CostMap<Derived2, Tree2>&& other)
257 : prop_criteria_(std::move(other.prop_criteria_))
258 {
259 }
260
261 /**************************************************************************************
262 | |
263 | Destructor |
264 | |
265 **************************************************************************************/
266
267 ~CostMap() = default;
268
269 /**************************************************************************************
270 | |
271 | Assignment operator |
272 | |
273 **************************************************************************************/
274
275 CostMap& operator=(CostMap const& rhs) = default;
276
277 CostMap& operator=(CostMap&& rhs) = default;
278
279 template <class Derived2, class Tree2>
280 CostMap& operator=(CostMap<Derived2, Tree2> const& rhs)
281 {
282 prop_criteria_ = rhs.prop_criteria_;
283 return *this;
284 }
285
286 template <class Derived2, class Tree2>
287 CostMap& operator=(CostMap<Derived2, Tree2>&& rhs)
288 {
289 prop_criteria_ = std::move(rhs.prop_criteria_);
290 return *this;
291 }
292
293 //
294 // Swap
295 //
296
297 void swap(CostMap& other) noexcept { std::swap(prop_criteria_, other.prop_criteria_); }
298
299 /**************************************************************************************
300 | |
301 | Derived |
302 | |
303 **************************************************************************************/
304
305 [[nodiscard]] constexpr Derived& derived() { return *static_cast<Derived*>(this); }
306
307 [[nodiscard]] constexpr Derived const& derived() const
308 {
309 return *static_cast<Derived const*>(this);
310 }
311
312 /**************************************************************************************
313 | |
314 | Block |
315 | |
316 **************************************************************************************/
317
318 [[nodiscard]] CostBlock<BF>& costBlock(pos_t pos)
319 {
320 return derived().template data<CostBlock<BF>>(pos);
321 }
322
323 [[nodiscard]] CostBlock<BF> const& costBlock(pos_t pos) const
324 {
325 return derived().template data<CostBlock<BF>>(pos);
326 }
327
328 /**************************************************************************************
329 | |
330 | Functions Derived expect |
331 | |
332 **************************************************************************************/
333
334 void onInitRoot()
335 {
336 auto& block = costBlock(0);
337
338 cost_t value{};
339 block[0].cost = value;
340 }
341
342 void onInitChildren(Index node, pos_t children)
343 {
344 costBlock(children).fill(costBlock(node.pos)[node.offset]);
345 }
346
347 void onPruneChildren(Index node, pos_t children)
348 {
349 auto& v = costBlock(node.pos)[node.offset];
350 }
351
352 void onPropagateChildren(Index node, pos_t children)
353 {
354 auto const& children_block = costBlock(children);
355
356 auto& cb = costBlock(node.pos)[node.offset];
357
358 cost_t value;
359 switch (prop_criteria_) {
360 case CostPropagationCriteria::MAX:
361 value = std::numeric_limits<cost_t>::lowest();
362 for (std::size_t i{}; BF > i; ++i) {
363 value = UFO_MAX(value, children_block[i].cost);
364 }
365 break;
366 case CostPropagationCriteria::MIN:
367 value = std::numeric_limits<cost_t>::max();
368 for (std::size_t i{}; BF > i; ++i) {
369 value = UFO_MIN(value, children_block[i].cost);
370 }
371 break;
372 case CostPropagationCriteria::MEAN: {
373 cost_t v = 0;
374 for (std::size_t i{}; BF > i; ++i) {
375 v += static_cast<int>(children_block[i].cost);
376 }
377 value = static_cast<cost_t>(v / static_cast<int>(BF));
378 break;
379 }
380 case CostPropagationCriteria::NONE: return;
381 }
382
383 cb.cost = value;
384 }
385
386 //
387 // Is prunable
388 //
389
390 [[nodiscard]] bool prunable(pos_t block) const
391 {
392 using std::begin;
393 using std::end;
394 return std::all_of(
395 begin(costBlock(block).data) + 1, end(costBlock(block).data),
396 [v = costBlock(block)[0].cost](auto const& e) { return v == e.cost; });
397 }
398
399 //
400 // Input/output (read/write)
401 //
402
403 [[nodiscard]] static constexpr std::size_t serializedSizeNode() noexcept
404 {
405 return sizeof(cost_t);
406 }
407
408 [[nodiscard]] constexpr std::size_t serializedSize(
409 std::vector<std::pair<pos_t, BitSet<BF>>> const& /* nodes */,
410 std::size_t num_nodes) const
411 {
412 return num_nodes * serializedSizeNode();
413 }
414
415 void onRead(ReadBuffer& in, std::vector<std::pair<pos_t, BitSet<BF>>> const& nodes)
416 {
417 for (auto [block, offset] : nodes) {
418 auto& cb = costBlock(block);
419
420 if (offset.all()) {
421 std::array<cost_t, BF> cost;
422 in.read(cost);
423 for (offset_t i{}; BF > i; ++i) {
424 cb[i] = CostElement(cost[i]);
425 }
426 } else {
427 for (offset_t i{}; BF > i; ++i) {
428 if (offset[i]) {
429 cost_t value;
430 in.read(value);
431 cb[i] = CostElement(value);
432 }
433 }
434 }
435 }
436 }
437
438 void onWrite(WriteBuffer& out, std::vector<std::pair<pos_t, BitSet<BF>>> const& nodes)
439 {
440 for (auto [block, offset] : nodes) {
441 auto const& cb = CostBlock(block);
442
443 if (offset.all()) {
444 std::array<cost_t, BF> cost;
445 for (offset_t i{}; BF > i; ++i) {
446 cost[i] = cb[i].cost;
447 }
448 out.write(cost);
449 } else {
450 for (offset_t i{}; BF > i; ++i) {
451 if (offset[i]) {
452 out.write(cb[i].cost);
453 }
454 }
455 }
456 }
457 }
458
459 //
460 // Dot file info
461 //
462
463 void onDotFileInfo(std::ostream& out, Index node) const
464 {
465 out << "Cost: " << cost(node);
466 }
467
468 private:
469 // Propagation criteria
470 CostPropagationCriteria prop_criteria_ = CostPropagationCriteria::MAX;
471};
472
473template <std::size_t Dim, std::size_t BF>
474struct map_block<CostMap, Dim, BF> {
475 using type = CostBlock<BF>;
476};
477} // namespace ufo
478
479#endif // UFO_MAP_COST_MAP_HPP
void costSet(NodeType node, cost_t value, bool propagate=true)
Definition map.hpp:137
static constexpr offset_type branchingFactor() noexcept
Returns the branching factor of the tree (i.e., 2 = binary tree, 4 = quadtree, 8 = octree,...
Definition tree.hpp:203
static constexpr std::size_t dimensions() noexcept
Returns the number of dimensions of the tree (i.e., 1 = binary tree, 2 = quadtree,...
Definition tree.hpp:211
STL namespace.
All vision-related classes and functions.
Definition cloud.hpp:49