UFO 1.0.0
An Efficient Probabilistic 3D Mapping Framework That Embraces the Unknown
Loading...
Searching...
No Matches
render.hpp
1
42#ifndef UFO_CONTAINER_TREE_RENDER_HPP
43#define UFO_CONTAINER_TREE_RENDER_HPP
44
45// UFO
46#include <ufo/container/tree/node.hpp>
47#include <ufo/container/tree/predicate.hpp>
48#include <ufo/container/tree/trace_result.hpp>
49#include <ufo/utility/type_traits.hpp>
50#include <ufo/vision/camera.hpp>
51
52// STL
53#include <utility>
54
55namespace ufo
56{
57//
58// New
59//
60
61template <class Tree, class Predicate,
62 std::enable_if_t<pred::is_pred_v<Predicate>, bool> = true>
63[[nodiscard]] Image<TraceResult<Tree::dimensions()>> render(Tree const& tree,
64 Camera const& camera,
65 Predicate const& pred)
66{
67 return render(tree.index(), tree, camera, pred);
68}
69
70template <class Tree, class NodeType, class Predicate,
71 std::enable_if_t<Tree::template is_node_type_v<NodeType>, bool> = true,
72 std::enable_if_t<pred::is_pred_v<Predicate>, bool> = true>
73[[nodiscard]] Image<TraceResult<Tree::dimensions()>> render(Tree const& tree,
74 NodeType const& node,
75 Camera const& camera,
76 Predicate const& pred)
77{
78 if constexpr (2 == Tree::dimensions()) {
79 // TODO: Implement
80 } else if constexpr (3 == Tree::dimensions()) {
81 // TODO: fix this
82 return tree.trace(node, camera.rays(), pred);
83 } else if constexpr (4 == Tree::dimensions()) {
84 // TODO: Implement
85 } else {
86 static_assert(dependent_false_v<Tree>, "Does not support dimensions");
87 }
88}
89
90template <
91 class ExecutionPolicy, class Tree, class Predicate,
92 std::enable_if_t<pred::is_pred_v<Predicate>, bool> = true,
93 std::enable_if_t<execution::is_execution_policy_v<ExecutionPolicy>, bool> = true>
94[[nodiscard]] Image<TraceResult<Tree::dimensions()>> render(ExecutionPolicy&& policy,
95 Tree const& tree,
96 Camera const& camera,
97 Predicate const& pred)
98{
99 return render(std::forward<ExecutionPolicy>(policy), tree, tree.index(), camera, pred);
100}
101
102template <
103 class ExecutionPolicy, class Tree, class NodeType, class Predicate,
104 std::enable_if_t<Tree::template is_node_type_v<NodeType>, bool> = true,
105 std::enable_if_t<pred::is_pred_v<Predicate>, bool> = true,
106 std::enable_if_t<execution::is_execution_policy_v<ExecutionPolicy>, bool> = true>
107[[nodiscard]] Image<TraceResult<Tree::dimensions()>> render(ExecutionPolicy&& policy,
108 Tree const& tree,
109 NodeType const& node,
110 Camera const& camera,
111 Predicate const& pred)
112{
113 if constexpr (2 == Tree::dimensions()) {
114 // TODO: Implement
115 } else if constexpr (3 == Tree::dimensions()) {
116 Image<TraceResult<Tree::dimensions()>> image(camera.rows, camera.cols);
117 auto rays = camera.rays();
118 tree.trace(std::forward<ExecutionPolicy>(policy), node, rays.begin(), rays.end(),
119 image.begin(), pred, camera.near_clip, camera.far_clip);
120 return image;
121 } else if constexpr (4 == Tree::dimensions()) {
122 // TODO: Implement
123 } else {
124 static_assert(dependent_false_v<Tree>, "Does not support dimensions");
125 }
126}
127
128template <class Map, class Predicate = pred::True,
129 std::enable_if_t<pred::is_pred_v<Predicate, Map>, bool> = true>
130[[nodiscard]] std::pair<Image<typename Map::Node>, Image<float>> renderGPU(
131 Map const& map, Camera const& camera, Predicate const& pred = pred::True{},
132 bool only_exists = true)
133{
134 return renderGPU(map.code(), map, camera, pred, only_exists);
135}
136
137template <class NodeType, class Map, class Predicate = pred::True,
138 std::enable_if_t<Map::template is_node_type_v<NodeType>, bool> = true,
139 std::enable_if_t<pred::is_pred_v<Predicate, Map>, bool> = true>
140[[nodiscard]] std::pair<Image<typename Map::Node>, Image<float>> renderGPU(
141 NodeType const& node, Map const& map, Camera const& camera,
142 Predicate pred = pred::True{}, bool only_exists = true)
143{
144 using Filter = pred::Filter<Predicate>;
145
146 Filter::init(pred, map);
147
148 // TODO: Init GPU
149
150 // TODO: Add shader to some list
151
152 // TODO: Call
153
154 std::pair<Image<typename Map::Node>, Image<float>> ret;
155
156 auto& nodes = ret.first;
157 auto& depths = ret.second;
158
159 nodes.resize(camera.cols, camera.rows);
160 depths.resize(camera.cols, camera.rows);
161
162 // TODO: Implement
163
164 return ret;
165}
166
167#if 0
168//
169// Quadtree
170//
171
172template <class InnerFun, class HitFun, class T>
173void render(Camera const& camera, Image<T>& image, InnerFun inner_f, HitFun hit_f,
174 T const& miss)
175{
176 render(Base::index(), camera, image, inner_f, hit_f, miss);
177}
178
179template <class InnerFun, class HitFun, class T>
180[[nodiscard]] Image<T> render(Camera const& camera, std::size_t rows, std::size_t cols,
181 InnerFun inner_f, HitFun hit_f, T const& miss)
182{
183 return render(Base::index(), camera, rows, cols, inner_f, hit_f, miss);
184}
185
186template <class NodeType, class InnerFun, class HitFun, class T,
187 std::enable_if_t<Base::template is_node_type_v<NodeType>, bool> = true>
188void render(NodeType node, Camera const& camera, Image<T>& image, InnerFun inner_f,
189 HitFun hit_f, T const& miss)
190{
191 Image<Ray3> rays = camera.rays(image.rows(), image.cols());
192 trace3D(node, rays.begin(), rays.end(), image.begin(), inner_f, hit_f, miss);
193}
194
195template <class NodeType, class InnerFun, class HitFun, class T,
196 std::enable_if_t<Base::template is_node_type_v<NodeType>, bool> = true>
197[[nodiscard]] Image<T> render(NodeType node, Camera const& camera, std::size_t rows,
198 std::size_t cols, InnerFun inner_f, HitFun hit_f,
199 T const& miss)
200{
201 Image<T> image(rows, cols);
202 render(node, camera, image, inner_f, hit_f, miss);
203 return image;
204}
205
206template <
207 class ExecutionPolicy, class InnerFun, class HitFun, class T,
208 std::enable_if_t<execution::is_execution_policy_v<ExecutionPolicy>, bool> = true>
209void render(ExecutionPolicy&& policy, Camera const& camera, Image<T>& image,
210 InnerFun inner_f, HitFun hit_f, T const& miss)
211{
212 render(std::forward<ExecutionPolicy>(policy), Base::index(), camera, image, inner_f,
213 hit_f, miss);
214}
215
216template <
217 class ExecutionPolicy, class InnerFun, class HitFun, class T,
218 std::enable_if_t<execution::is_execution_policy_v<ExecutionPolicy>, bool> = true>
219[[nodiscard]] Image<T> render(ExecutionPolicy&& policy, Camera const& camera,
220 std::size_t rows, std::size_t cols, InnerFun inner_f,
221 HitFun hit_f, T const& miss)
222{
223 return render(std::forward<ExecutionPolicy>(policy), Base::index(), camera, rows, cols,
224 inner_f, hit_f, miss);
225}
226
227template <class ExecutionPolicy, class NodeType, class InnerFun, class HitFun, class T>
228void render(ExecutionPolicy&& policy, NodeType node, Camera const& camera,
229 Image<T>& image, InnerFun inner_f, HitFun hit_f, T const& miss)
230{
231 auto rows = image.rows();
232 auto cols = image.cols();
233
234 Image<Ray3> rays = camera.rays(policy, rows, cols);
235
236 trace3D(std::forward<ExecutionPolicy>(policy), node, rays.begin(), rays.end(),
237 image.begin(), inner_f, hit_f, miss);
238}
239
240template <class ExecutionPolicy, class NodeType, class InnerFun, class HitFun, class T>
241[[nodiscard]] Image<T> render(ExecutionPolicy&& policy, NodeType node,
242 Camera const& camera, std::size_t rows, std::size_t cols,
243 InnerFun inner_f, HitFun hit_f, T const& miss)
244{
245 Image<T> image(rows, cols);
246 render(policy, node, camera, image, inner_f, hit_f, miss);
247 return image;
248}
249
250template <class NodeType, class InputIt, class OutputIt, class InnerFun, class HitFun,
251 class T, std::enable_if_t<Base::template is_node_type_v<NodeType>, bool> = true>
252OutputIt trace3D(NodeType node, InputIt first, InputIt last, OutputIt d_first,
253 InnerFun inner_f, HitFun hit_f, T const& miss)
254{
255 if constexpr (!std::is_same_v<Index, std::decay_t<NodeType>>) {
256 // Unless NodeType is Index, we need to check that the node actually exists
257 if (!Base::exists(node)) {
258 return miss;
259 }
260 }
261
262 Index n = Base::index(node);
263
264 auto center = Base::center(n);
265 auto half_length = Base::halfLength(n);
266
267 return std::transform(first, last, d_first, [&](auto const& ray) {
268 return trace3D(n, center, half_length, ray, inner_f, hit_f, miss);
269 });
270}
271
272template <class ExecutionPolicy, class NodeType, class RandomIt1, class RandomIt2,
273 class InnerFun, class HitFun, class T>
274RandomIt2 trace3D(ExecutionPolicy&& policy, NodeType node, RandomIt1 first,
275 RandomIt1 last, RandomIt2 d_first, InnerFun inner_f, HitFun hit_f,
276 T const& miss)
277{
278 if constexpr (std::is_same_v<execution::sequenced_policy,
279 std::decay_t<ExecutionPolicy>>) {
280 return trace3D(node, first, last, d_first, inner_f, hit_f, miss);
281 }
282
283#if !defined(UFO_TBB) && !defined(UFO_OMP)
284 return trace3D(node, first, last, d_first, inner_f, hit_f, miss);
285#endif
286
287 if constexpr (!std::is_same_v<Index, std::decay_t<NodeType>>) {
288 // Unless NodeType is Index, we need to check that the node actually exists
289 if (!Base::exists(node)) {
290 return miss;
291 }
292 }
293
294 Index n = Base::index(node);
295
296 auto center = Base::center(n);
297 auto half_length = Base::halfLength(n);
298
299#if defined(UFO_TBB)
300 return std::transform(
301 std::forward<ExecutionPolicy>(policy), first, last, d_first, [&](auto const& ray) {
302 return trace3D(n, center, half_length, ray, inner_f, hit_f, miss);
303 });
304#elif defined(UFO_OMP)
305 std::size_t size = std::distance(first, last);
306
307#pragma omp parallel for
308 for (std::size_t i = 0; i != size; ++i) {
309 auto const& ray = first[i];
310 d_first[i] = trace3D(n, center, half_length, ray, inner_f, hit_f, miss);
311 }
312
313 return std::next(d_first, size);
314#endif
315}
316
317template <class InnerFun, class HitFun, class T>
318[[nodiscard]] T trace3D(Index node, Vec2f const& center, float half_length,
319 Ray3 const& ray, InnerFun inner_f, HitFun hit_f,
320 T const& miss)
321{
322 auto wrapped_inner_f = [&ray, inner_f](Index node, float distance) {
323 return inner_f(node, ray, distance);
324 };
325
326 auto wrapped_hit_f = [&ray, hit_f](Index node, float distance) {
327 return hit_f(node, ray, distance);
328 };
329
330 if (0.0f == ray.origin.z && 0.0f == ray.direction.z) {
331 // 2D case
332 Ray2 ray2(Vec2f(ray.origin), Vec2f(ray.direction));
333 auto params = Base::traceInit(ray2, center, half_length);
334 return Base::trace(node, params, wrapped_inner_f, wrapped_hit_f, miss);
335 } else if (0.0f == ray.direction.z || sign(ray.origin.z) == sign(ray.direction.z)) {
336 // Ray never intersects the 2D XY plane at Z=0
337 return miss;
338 }
339
340 // Check where 3D ray intersects with 2D XY plane at z=0
341 float t = -ray.origin.z / ray.direction.z;
342 Vec2f v = Vec2f(ray.origin) + t * Vec2f(ray.direction);
343 auto code = Base::code(v);
344
345 if (Base::code(node) != code.toDepth(Base::depth(node))) {
346 // Different part of the tree, so return miss
347 return miss;
348 }
349
350 for (int depth = Base::depth(node); 0 < depth; --depth) {
351 if (auto [hit, value] = wrapped_hit_f(node, t); hit) {
352 return value;
353 } else if (Base::isLeaf(node) || !wrapped_inner_f(node, t)) {
354 return miss;
355 }
356
357 node = Base::child(node, code.offset(depth - 1));
358 }
359
360 if (auto [hit, value] = wrapped_hit_f(node, t); hit) {
361 return value;
362 }
363
364 return miss;
365}
366
367//
368// Octree
369//
370
371template <class InnerFun, class HitFun, class T>
372void render(Camera const& camera, Image<T>& image, InnerFun inner_f, HitFun hit_f,
373 T const& miss)
374{
375 render(Base::index(), camera, image, inner_f, hit_f, miss);
376}
377
378template <class InnerFun, class HitFun, class T>
379[[nodiscard]] Image<T> render(Camera const& camera, std::size_t rows, std::size_t cols,
380 InnerFun inner_f, HitFun hit_f, T const& miss)
381{
382 return render(Base::index(), camera, rows, cols, inner_f, hit_f, miss);
383}
384
385template <class NodeType, class InnerFun, class HitFun, class T,
386 std::enable_if_t<Base::template is_node_type_v<NodeType>, bool> = true>
387void render(NodeType node, Camera const& camera, Image<T>& image, InnerFun inner_f,
388 HitFun hit_f, T const& miss)
389{
390 Image<Ray3> rays = camera.rays(image.rows(), image.cols());
391 Base::trace(node, rays.begin(), rays.end(), image.begin(), inner_f, hit_f, miss);
392}
393
394template <class NodeType, class InnerFun, class HitFun, class T,
395 std::enable_if_t<Base::template is_node_type_v<NodeType>, bool> = true>
396[[nodiscard]] Image<T> render(NodeType node, Camera const& camera, std::size_t rows,
397 std::size_t cols, InnerFun inner_f, HitFun hit_f,
398 T const& miss)
399{
400 Image<T> image(rows, cols);
401 render(node, camera, image, inner_f, hit_f, miss);
402 return image;
403}
404
405template <
406 class ExecutionPolicy, class InnerFun, class HitFun, class T,
407 std::enable_if_t<execution::is_execution_policy_v<ExecutionPolicy>, bool> = true>
408void render(ExecutionPolicy&& policy, Camera const& camera, Image<T>& image,
409 InnerFun inner_f, HitFun hit_f, T const& miss)
410{
411 render(std::forward<ExecutionPolicy>(policy), Base::index(), camera, image, inner_f,
412 hit_f, miss);
413}
414
415template <
416 class ExecutionPolicy, class InnerFun, class HitFun, class T,
417 std::enable_if_t<execution::is_execution_policy_v<ExecutionPolicy>, bool> = true>
418[[nodiscard]] Image<T> render(ExecutionPolicy&& policy, Camera const& camera,
419 std::size_t rows, std::size_t cols, InnerFun inner_f,
420 HitFun hit_f, T const& miss)
421{
422 return render(std::forward<ExecutionPolicy>(policy), Base::index(), camera, rows, cols,
423 inner_f, hit_f, miss);
424}
425
426template <class ExecutionPolicy, class NodeType, class InnerFun, class HitFun, class T>
427void render(ExecutionPolicy&& policy, NodeType node, Camera const& camera,
428 Image<T>& image, InnerFun inner_f, HitFun hit_f, T const& miss)
429{
430 auto rows = image.rows();
431 auto cols = image.cols();
432
433 Image<Ray3> rays = camera.rays(policy, rows, cols);
434
435 constexpr std::size_t const step_size = 1;
436
437 if constexpr (1 == step_size) {
438 Base::trace(std::forward<ExecutionPolicy>(policy), node, rays.begin(), rays.end(),
439 image.begin(), inner_f, hit_f, miss);
440 } else {
441 // Image<std::pair<TreeIndex, float>> iter_image(
442 // rows, cols, std::make_pair(TreeIndex{}, std::numeric_limits<float>::max()));
443
444 Index n = Base::index(node);
445
446 auto center = Base::center(n);
447 auto half_length = Base::halfLength(n);
448
449 std::vector<std::size_t> row_idx(rows);
450 std::iota(row_idx.begin(), row_idx.end(), 0);
451
452 // std::vector<std::size_t> row_idx_samples()
453
454 // std::generate(row_idx.begin(), row_idx.end(), [n = 0]() mutable {
455 // auto v = n;
456 // n += 2;
457 // return v;
458 // });
459
460 // struct IterElement {
461 // Index node;
462 // float distance;
463 // T value;
464
465 // IterElement() = default;
466
467 // IterElement(Index node, float distance, T value)
468 // : node(node), distance(distance), value(value)
469 // {
470 // }
471 // };
472
473 // auto tmp_miss = IterElement(TreeIndex{}, std::numeric_limits<float>::max(),
474 // miss);
475
476 // std::sample(rays.begin(), rays.end(), std::back_inserter(out), 4,
477 // std::mt19937{std::random_device{}()});
478
479 // std::transform(
480 // policy, rays.begin(), rays.end(), image.begin(), [&, this](auto const& ray) {
481 // auto wrapped_inner_f = [inner_f, &ray](auto node, auto distance) {
482 // return inner_f(node, ray, distance);
483 // };
484
485 // auto wrapped_hit_f = [hit_f, &ray](auto node, auto distance) {
486 // return hit_f(node, ray, distance);
487 // // auto [hit, value] = hit_f(node, ray, distance);
488 // // return std::make_pair(hit, IterElement(node, distance, value));
489 // };
490
491 // auto params = Base::traceInit(ray, center, half_length);
492 // return Base::trace(n, params, wrapped_inner_f, wrapped_hit_f, miss);
493 // });
494
495 static std::size_t s{};
496 ++s;
497
498 std::for_each(policy, row_idx.begin(), row_idx.end(), [&](std::size_t row) {
499 std::size_t offset = (row + s) % step_size;
500
501 for (std::size_t col = offset; cols > col; col += step_size) {
502 auto const& ray = rays(row, col);
503
504 auto wrapped_inner_f = [inner_f, &ray](auto node, auto distance) {
505 return inner_f(node, ray, distance);
506 };
507
508 auto wrapped_hit_f = [hit_f, &ray](auto node, auto distance) {
509 return hit_f(node, ray, distance);
510 // auto [hit, value] = hit_f(node, ray, distance);
511 // return std::make_pair(hit, IterElement(node, distance, value));
512 };
513
514 auto params = Base::traceInit(ray, center, half_length);
515 image(row, col) = Base::trace(n, params, wrapped_inner_f, wrapped_hit_f, miss);
516 // auto ie = Base::trace(n, params, wrapped_inner_f, wrapped_hit_f,
517 // tmp_miss); image(row, col) = ie.value; iter_image(row, col) = {ie.node,
518 // ie.distance};
519 }
520 });
521
522 if constexpr (2 == step_size) {
523 // std::for_each(
524 // policy, row_idx.begin() + 1, row_idx.end() - 1, [&](std::size_t row) {
525 // std::size_t const offset = 1 - (row % step_size);
526
527 // for (std::size_t col = step_size - offset; cols - 1 > col;
528 // col += step_size) {
529 // auto idx = minIndex(Vec4f(
530 // iter_image(row - 1, col).second, iter_image(row + 1, col).second,
531 // iter_image(row, col - 1).second, iter_image(row, col + 1).second));
532
533 // std::size_t min_row = 0 == idx ? row - 1 : (1 == idx ? row + 1 : row);
534 // std::size_t min_col = 2 == idx ? col - 1 : (3 == idx ? col + 1 : col);
535
536 // auto const& [node, distance] = iter_image(min_row, min_col);
537 // if (Base::valid(node)) {
538 // auto ray = rays(row, col);
539 // // float dist = distance(ray.origin, min(bounds));
540 // if (auto [hit, value] = hit_f(node, ray, distance); hit) {
541 // image(row, col) = value;
542 // } else {
543 // image(row, col) = miss;
544 // }
545 // } else {
546 // image(row, col) = miss;
547 // }
548 // }
549 // });
550 } else {
551 // std::for_each(
552 // policy, row_idx.begin() + 1, row_idx.end() - 1, [&](std::size_t row) {
553 // std::size_t const offset = row % step_size;
554
555 // for (std::size_t col = 1; cols - 1 > col; ++col) {
556 // if (offset == (col % step_size)) {
557 // continue;
558 // }
559
560 // auto idx = minIndex(Vec4f(
561 // iter_image(row - 1, col).second, iter_image(row + 1, col).second,
562 // iter_image(row, col - 1).second, iter_image(row, col + 1).second));
563
564 // std::size_t min_row = 0 == idx ? row - 1 : (1 == idx ? row + 1 : row);
565 // std::size_t min_col = 2 == idx ? col - 1 : (3 == idx ? col + 1 : col);
566
567 // auto const& [node, distance] = iter_image(min_row, min_col);
568 // if (Base::valid(node)) {
569 // auto ray = rays(row, col);
570 // // float dist = distance(ray.origin, min(bounds));
571 // if (auto [hit, value] = hit_f(node, ray, distance); hit) {
572 // image(row, col) = value;
573 // } else {
574 // image(row, col) = miss;
575 // }
576 // } else {
577 // image(row, col) = miss;
578 // }
579 // }
580 // });
581 }
582 }
583}
584
585template <class ExecutionPolicy, class NodeType, class InnerFun, class HitFun, class T>
586[[nodiscard]] Image<T> render(ExecutionPolicy&& policy, NodeType node,
587 Camera const& camera, std::size_t rows, std::size_t cols,
588 InnerFun inner_f, HitFun hit_f, T const& miss)
589{
590 Image<T> image(rows, cols);
591 render(policy, node, camera, image, inner_f, hit_f, miss);
592 return image;
593}
594
595//
596// Hextree
597//
598
599template <class InnerFun, class HitFun, class T>
600void render(float w, Camera const& camera, Image<T>& image, InnerFun inner_f,
601 HitFun hit_f, T const& miss)
602{
603 render(w, Base::index(), camera, image, inner_f, hit_f, miss);
604}
605
606template <class InnerFun, class HitFun, class T>
607[[nodiscard]] Image<T> render(float w, Camera const& camera, std::size_t rows,
608 std::size_t cols, InnerFun inner_f, HitFun hit_f,
609 T const& miss)
610{
611 return render(Base::index(), w, camera, rows, cols, inner_f, hit_f, miss);
612}
613
614template <class NodeType, class InnerFun, class HitFun, class T,
615 std::enable_if_t<Base::template is_node_type_v<NodeType>, bool> = true>
616void render(NodeType node, float w, Camera const& camera, Image<T>& image,
617 InnerFun inner_f, HitFun hit_f, T const& miss)
618{
619 Image<Ray3> rays = camera.rays(image.rows(), image.cols());
620 Image<Ray4> rays4d(image.rows(), image.cols());
621 for (std::size_t row{}; image.rows() > row; ++row) {
622 for (std::size_t col{}; image.cols() > col; ++col) {
623 rays4d(row, col) =
624 Ray4(Vec4f(rays(row, col).origin, w), Vec4f(rays(row, col).direction, 0));
625 }
626 }
627 Base::trace(node, rays4d.begin(), rays4d.end(), image.begin(), inner_f, hit_f, miss);
628}
629
630template <class NodeType, class InnerFun, class HitFun, class T,
631 std::enable_if_t<Base::template is_node_type_v<NodeType>, bool> = true>
632[[nodiscard]] Image<T> render(NodeType node, float w, Camera const& camera,
633 std::size_t rows, std::size_t cols, InnerFun inner_f,
634 HitFun hit_f, T const& miss)
635{
636 Image<T> image(rows, cols);
637 render(node, w, camera, image, inner_f, hit_f, miss);
638 return image;
639}
640
641template <
642 class ExecutionPolicy, class InnerFun, class HitFun, class T,
643 std::enable_if_t<execution::is_execution_policy_v<ExecutionPolicy>, bool> = true>
644void render(ExecutionPolicy&& policy, float w, Camera const& camera, Image<T>& image,
645 InnerFun inner_f, HitFun hit_f, T const& miss)
646{
647 render(std::forward<ExecutionPolicy>(policy), Base::index(), w, camera, image, inner_f,
648 hit_f, miss);
649}
650
651template <
652 class ExecutionPolicy, class InnerFun, class HitFun, class T,
653 std::enable_if_t<execution::is_execution_policy_v<ExecutionPolicy>, bool> = true>
654[[nodiscard]] Image<T> render(ExecutionPolicy&& policy, float w, Camera const& camera,
655 std::size_t rows, std::size_t cols, InnerFun inner_f,
656 HitFun hit_f, T const& miss)
657{
658 return render(std::forward<ExecutionPolicy>(policy), Base::index(), w, camera, rows,
659 cols, inner_f, hit_f, miss);
660}
661
662template <class ExecutionPolicy, class NodeType, class InnerFun, class HitFun, class T>
663void render(ExecutionPolicy&& policy, NodeType node, float w, Camera const& camera,
664 Image<T>& image, InnerFun inner_f, HitFun hit_f, T const& miss)
665{
666 auto rows = image.rows();
667 auto cols = image.cols();
668
669 Image<Ray3> rays = camera.rays(policy, rows, cols);
670 Image<Ray4> rays4d(image.rows(), image.cols());
671 for (std::size_t row{}; image.rows() > row; ++row) {
672 for (std::size_t col{}; image.cols() > col; ++col) {
673 rays4d(row, col) =
674 Ray4(Vec4f(rays(row, col).origin, w), Vec4f(rays(row, col).direction, 0));
675 }
676 }
677
678 Base::trace(std::forward<ExecutionPolicy>(policy), node, rays4d.begin(), rays4d.end(),
679 image.begin(), inner_f, hit_f, miss);
680}
681
682template <class ExecutionPolicy, class NodeType, class InnerFun, class HitFun, class T>
683[[nodiscard]] Image<T> render(ExecutionPolicy&& policy, NodeType node, float w,
684 Camera const& camera, std::size_t rows, std::size_t cols,
685 InnerFun inner_f, HitFun hit_f, T const& miss)
686{
687 Image<T> image(rows, cols);
688 render(policy, node, w, camera, image, inner_f, hit_f, miss);
689 return image;
690}
691#endif
692} // namespace ufo
693
694#endif // UFO_CONTAINER_TREE_RENDER_HPP
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
constexpr int sign(T val) noexcept
Returns the sign of a value.
Definition math.hpp:70
All vision-related classes and functions.
Definition cloud.hpp:49
constexpr auto distance(A const &a, B const &b)
Computes the minimum distance between two shapes.
Definition distance.hpp:61