42#ifndef UFO_MAP_RAY_CASTER_HPP
43#define UFO_MAP_RAY_CASTER_HPP
46#include <ufo/map/integration/integration_grid.hpp>
47#include <ufo/map/octree/octree_code.hpp>
48#include <ufo/map/octree/octree_key.hpp>
49#include <ufo/map/quadtree/quadtree_code.hpp>
50#include <ufo/map/quadtree/quadtree_key.hpp>
51#include <ufo/map/types.hpp>
52#include <ufo/numeric/util.hpp>
53#include <ufo/numeric/vec2.hpp>
54#include <ufo/numeric/vec3.hpp>
61#include <unordered_map>
66inline void computeRay(std::unordered_map<OctCode, IntegrationGrid<OctCode>>& misses,
67 Vec3f origin, Vec3f goal, OctCode c_origin, Vec3f voxel_border,
68 float grid_size,
float max_distance,
unsigned inflate_unknown)
70 static constexpr auto max = std::numeric_limits<float>::max();
71 depth_t depth = c_origin.depth();
73 auto dir = goal - origin;
79 std::array<int, 3>
sign{sgn(dir.x), sgn(dir.y), sgn(dir.z)};
85 std::array<void (OctCode ::*)(code_t), 3> step_f{
86 0 <=
sign[0] ? (void (OctCode ::*)(code_t))(&OctCode::incX)
87 : (void (OctCode ::*)(code_t))(&OctCode::decX),
88 0 <=
sign[1] ? (void (OctCode ::*)(code_t))(&OctCode::incY)
89 : (void (OctCode ::*)(code_t))(&OctCode::decY),
90 0 <=
sign[2] ? (void (OctCode ::*)(code_t))(&OctCode::incZ)
91 : (void (OctCode ::*)(code_t))(&OctCode::decZ)};
92 std::array<code_t, 3> step_v{c_origin.xStep(), c_origin.yStep(), c_origin.zStep()};
94 Vec3f t_max(
sign[0] ? (voxel_border.x +
sign[0] * grid_size / 2.0f) / dir.x :
max,
95 sign[1] ? (voxel_border.y +
sign[1] * grid_size / 2.0f) / dir.y :
max,
96 sign[2] ? (voxel_border.z +
sign[2] * grid_size / 2.0f) / dir.z :
max);
98 Vec3f t_delta(
sign[0] ? grid_size / std::abs(dir.x) :
max,
103 unsigned steps = (
sign[0] ? std::ceil((
distance - t_max[0]) / t_delta[0]) : 0) +
107 OctCode prev_at_depth = c_origin.toDepth(IntegrationGrid<OctCode>::depth() + depth);
108 IntegrationGrid<OctCode>* misses_grid = &misses[prev_at_depth];
109 misses_grid->set(c_origin);
112 auto const advance_dim = t_max.minElementIndex();
113 (c_origin.*step_f[advance_dim])(step_v[advance_dim]);
114 t_max[advance_dim] += t_delta[advance_dim];
116 if (!OctCode::equalAtDepth(prev_at_depth, c_origin,
117 IntegrationGrid<OctCode>::depth() + depth)) {
118 prev_at_depth = c_origin.toDepth(IntegrationGrid<OctCode>::depth() + depth);
119 misses_grid = &misses[prev_at_depth];
121 misses_grid->set(c_origin);
126 unsigned advance_dim{};
127 std::array<unsigned, 3> s{};
128 while (s[advance_dim] != inflate_unknown) {
129 advance_dim = t_max.minElementIndex();
130 (c_origin.*step_f[advance_dim])(step_v[advance_dim]);
131 t_max[advance_dim] += t_delta[advance_dim];
134 if (!OctCode::equalAtDepth(prev_at_depth, c_origin,
135 IntegrationGrid<OctCode>::depth() + depth)) {
136 prev_at_depth = c_origin.toDepth(IntegrationGrid<OctCode>::depth() + depth);
137 misses_grid = &misses[prev_at_depth];
139 misses_grid->set(c_origin);
143inline void computeRay(std::unordered_map<OctCode, IntegrationGrid<OctCode>>& misses,
144 std::unordered_map<OctCode, IntegrationGrid<OctCode>>
const& hits,
145 Vec3f origin, Vec3f goal, OctCode c_origin, Vec3f voxel_border,
146 float grid_size,
float max_distance,
unsigned inflate_unknown,
147 bool ray_passthrough_hits)
149 static constexpr auto max = std::numeric_limits<float>::max();
150 depth_t depth = c_origin.depth();
152 auto dir = goal - origin;
158 std::array<int, 3>
sign{sgn(dir.x), sgn(dir.y), sgn(dir.z)};
164 std::array<void (OctCode ::*)(code_t), 3> step_f{
165 0 <=
sign[0] ? (void (OctCode ::*)(code_t))(&OctCode::incX)
166 : (void (OctCode ::*)(code_t))(&OctCode::decX),
167 0 <=
sign[1] ? (void (OctCode ::*)(code_t))(&OctCode::incY)
168 : (void (OctCode ::*)(code_t))(&OctCode::decY),
169 0 <=
sign[2] ? (void (OctCode ::*)(code_t))(&OctCode::incZ)
170 : (void (OctCode ::*)(code_t))(&OctCode::decZ)};
171 std::array<code_t, 3> step_v{c_origin.xStep(), c_origin.yStep(), c_origin.zStep()};
173 Vec3f t_max(
sign[0] ? (voxel_border.x +
sign[0] * grid_size / 2.0f) / dir.x :
max,
174 sign[1] ? (voxel_border.y +
sign[1] * grid_size / 2.0f) / dir.y :
max,
175 sign[2] ? (voxel_border.z +
sign[2] * grid_size / 2.0f) / dir.z :
max);
177 Vec3f t_delta(
sign[0] ? grid_size / std::abs(dir.x) :
max,
182 unsigned steps = (
sign[0] ? std::ceil((
distance - t_max[0]) / t_delta[0]) : 0) +
186 OctCode prev_at_depth = c_origin.toDepth(IntegrationGrid<OctCode>::depth() + depth);
187 IntegrationGrid<OctCode>* misses_grid = &misses[prev_at_depth];
188 misses_grid->set(c_origin);
190 if (ray_passthrough_hits) {
192 auto const advance_dim = t_max.minElementIndex();
193 (c_origin.*step_f[advance_dim])(step_v[advance_dim]);
194 t_max[advance_dim] += t_delta[advance_dim];
196 if (!OctCode::equalAtDepth(prev_at_depth, c_origin,
197 IntegrationGrid<OctCode>::depth() + depth)) {
198 prev_at_depth = c_origin.toDepth(IntegrationGrid<OctCode>::depth() + depth);
199 misses_grid = &misses[prev_at_depth];
201 misses_grid->set(c_origin);
204 auto hit_grid = hits.find(prev_at_depth);
205 auto const hit_grid_end = std::cend(hits);
207 while (steps-- && (hit_grid_end == hit_grid || !hit_grid->second.test(c_origin))) {
208 auto const advance_dim = t_max.minElementIndex();
209 (c_origin.*step_f[advance_dim])(step_v[advance_dim]);
210 t_max[advance_dim] += t_delta[advance_dim];
212 if (!OctCode::equalAtDepth(prev_at_depth, c_origin,
213 IntegrationGrid<OctCode>::depth() + depth)) {
214 prev_at_depth = c_origin.toDepth(IntegrationGrid<OctCode>::depth() + depth);
215 misses_grid = &misses[prev_at_depth];
216 hit_grid = hits.find(prev_at_depth);
218 misses_grid->set(c_origin);
224 unsigned advance_dim{};
225 std::array<unsigned, 3> s{};
226 while (s[advance_dim] != inflate_unknown) {
227 advance_dim = t_max.minElementIndex();
228 (c_origin.*step_f[advance_dim])(step_v[advance_dim]);
229 t_max[advance_dim] += t_delta[advance_dim];
232 if (!OctCode::equalAtDepth(prev_at_depth, c_origin,
233 IntegrationGrid<OctCode>::depth() + depth)) {
234 prev_at_depth = c_origin.toDepth(IntegrationGrid<OctCode>::depth() + depth);
235 misses_grid = &misses[prev_at_depth];
237 misses_grid->set(c_origin);
242void computeRaySimple(
Map const& map, std::unordered_map<OctCode, Grid>& grids,
243 Vec3f origin, Vec3f goal, depth_t depth,
float step_size,
244 float max_distance = std::numeric_limits<float>::max(),
245 float early_stop_distance = 0.0f)
247 Vec3f dir = goal - origin;
253 std::size_t num_steps =
static_cast<std::size_t
>(
distance / step_size);
254 Vec3f step = dir * step_size;
256 OctCode prev_at_depth = map.toCode(origin, Grid::depth() + depth);
257 Grid* grid = &grids[prev_at_depth];
258 grid->set(map.toCode(origin, depth));
259 for (std::size_t i{}; i != num_steps; ++i, origin += step) {
260 OctCode cur = map.toCode(origin, depth);
262 if (OctCode::equalAtDepth(prev_at_depth, cur, Grid::depth() + depth)) {
263 grid = &grids[cur.toDepth(Grid::depth() + depth)];
264 prev_at_depth = cur.toDepth(Grid::depth() + depth);
270[[nodiscard]]
inline std::vector<OctCode> computeRay(
271 OctKey origin, OctKey goal,
float max_distance = std::numeric_limits<float>::max(),
272 std::size_t early_stop = 0,
float early_stop_distance = 0.0f)
274 assert(origin.depth() == goal.depth());
276 int const size =
static_cast<int>(origin.step());
278 Vec3f o(
static_cast<float>(origin.x),
static_cast<float>(origin.y),
279 static_cast<float>(origin.z));
280 Vec3f g(
static_cast<float>(goal.x),
static_cast<float>(goal.y),
281 static_cast<float>(goal.z));
289 Vec3i step(sgn(dir.x) * size, sgn(dir.y) * size, sgn(dir.z) * size);
293 constexpr auto max = std::numeric_limits<float>::max();
294 float f_size =
static_cast<float>(size);
296 Vec3f t_delta(step.x ? f_size / dir.x :
max, step.y ? f_size / dir.y :
max,
297 step.z ? f_size / dir.z :
max);
299 Vec3f t_max = t_delta / 2.0f;
303 std::vector<OctCode> ray;
304 ray.emplace_back(origin);
306 while (origin != goal && t_max.min() <=
distance) {
307 auto advance_dim = t_max.minElementIndex();
309 origin[advance_dim] +=
static_cast<key_t
>(step[advance_dim]);
310 t_max[advance_dim] += t_delta[advance_dim];
311 ray.emplace_back(origin);
313 for (; 0 != early_stop && !ray.empty(); --early_stop) {
319[[nodiscard]]
inline std::vector<OctCode> computeRaySimple(
320 OctKey origin, OctKey goal,
float step_size_factor = 1.0f,
321 float max_distance = std::numeric_limits<float>::max(), std::size_t early_stop = 0,
322 float early_stop_distance = 0.0f)
324 auto const depth = origin.depth;
326 assert(goal.depth() == depth);
328 Vec3f current(
static_cast<float>(origin.x),
static_cast<float>(origin.y),
329 static_cast<float>(origin.z));
330 Vec3f last(
static_cast<float>(goal.x),
static_cast<float>(goal.y),
331 static_cast<float>(goal.z));
333 Vec3f dir = last - current;
339 auto step_size =
static_cast<float>(1U << depth) * step_size_factor;
341 std::size_t num_steps =
static_cast<std::size_t
>(
343 Vec3f step = dir * step_size;
345 num_steps = num_steps - std::min(num_steps, early_stop);
347 if (0 == num_steps) {
352 std::vector<OctCode> ray;
353 ray.reserve(num_steps);
354 for (std::size_t i{}; i != num_steps; ++i, current += step) {
355 ray.emplace_back(OctKey(
static_cast<key_t
>(current.x),
static_cast<key_t
>(current.y),
356 static_cast<key_t
>(current.z), depth));
361[[nodiscard]]
inline std::vector<QuadCode> computeRaySimple(
362 QuadKey origin, QuadKey goal,
float step_size_factor = 1.0f,
363 float max_distance = std::numeric_limits<float>::max(), std::size_t early_step = 0,
364 float early_stop_distance = 0.0f)
369[[nodiscard]]
inline std::vector<Vec3f> computeRaySimple(
370 Vec3f origin, Vec3f goal,
float step_size,
371 float max_distance = std::numeric_limits<float>::max(), std::size_t early_stop = 0,
372 float early_stop_distance = 0.0f)
374 Vec3f dir = goal - origin;
382 std::size_t num_steps =
static_cast<std::size_t
>(
distance / step_size);
383 num_steps -= std::min(num_steps, early_stop);
384 Vec3f step = dir * step_size;
387 std::vector<Vec3f> ray;
388 ray.reserve(num_steps);
389 for (std::size_t i{}; i != num_steps; ++i, origin += step) {
390 ray.push_back(origin);
395[[nodiscard]]
inline std::vector<Vec2f> computeRaySimple(
396 Vec2f origin, Vec2f goal,
float step_size,
397 float max_distance = std::numeric_limits<float>::max(), std::size_t early_stop = 0,
398 float early_stop_distance = 0.0f)
400 Vec2f dir = goal - origin;
408 std::size_t num_steps =
static_cast<std::size_t
>(
distance / step_size);
409 num_steps -= std::min(num_steps, early_stop);
410 Vec2f step = dir * step_size;
413 std::vector<Vec2f> ray;
414 ray.reserve(num_steps);
415 for (std::size_t i{}; i != num_steps; ++i, origin += step) {
416 ray.push_back(origin);
constexpr int sign(T val) noexcept
Returns the sign of a value.
All vision-related classes and functions.
constexpr Vec< Dim, T > ceil(Vec< Dim, T > v) noexcept
Returns the component-wise ceiling of a floating-point vector.
constexpr Vec< Geometry::dimension(), typename Geometry::value_type > max(Geometry const &g)
Returns the maximum coordinate of the minimum spanning axis-aligned bounding box of a geometry.
constexpr Vec< Dim, T > abs(Vec< Dim, T > v) noexcept
Returns the component-wise absolute value of a vector.
constexpr auto distance(A const &a, B const &b)
Computes the minimum distance between two shapes.