ACTS
Experiment-independent tracking
Loading...
Searching...
No Matches
bounding_volume.hpp
1// This file is part of the ACTS project.
2//
3// Copyright (C) 2016 CERN for the benefit of the ACTS project
4//
5// This Source Code Form is subject to the terms of the Mozilla Public
6// License, v. 2.0. If a copy of the MPL was not distributed with this
7// file, You can obtain one at https://mozilla.org/MPL/2.0/.
8
9#pragma once
10
11// Project include(s).
12#include "detray/definitions/algebra.hpp"
13#include "detray/definitions/detail/qualifiers.hpp"
14#include "detray/definitions/units.hpp"
15#include "detray/geometry/mask.hpp"
16#include "detray/geometry/shapes/cuboid3D.hpp"
17#include "detray/geometry/shapes/cylinder3D.hpp"
18#include "detray/navigation/intersection/bounding_box/cuboid_intersector.hpp"
19#include "detray/navigation/intersection/intersection.hpp"
20#include "detray/tracks/ray.hpp"
21
22// System include(s)
23#include <cassert>
24#include <limits>
25#include <type_traits>
26#include <vector>
27
28namespace detray {
29
31template <typename shape_t, concepts::algebra algebra_t>
33 public:
39 using shape = shape_t;
41 using boundaries = typename shape_t::boundaries;
43 template <typename A>
44 using local_frame = typename shape_t::template local_frame_type<A>;
45
47 static constexpr std::size_t dim{shape_t::dim};
49
51 constexpr axis_aligned_bounding_volume() = default;
52
56 template <typename... Args>
57 DETRAY_HOST_DEVICE explicit constexpr axis_aligned_bounding_volume(
58 std::size_t box_id, Args&&... args)
59 : m_mask(box_id, std::forward<Args>(args)...) {}
60
65 template <typename mask_t, typename S = shape_t>
66 requires std::is_same_v<S, cuboid3D>
67 DETRAY_HOST_DEVICE constexpr axis_aligned_bounding_volume(
68 const mask_t& mask, std::size_t box_id, const scalar_t envelope)
69 : m_mask{mask.local_min_bounds(envelope).values(), box_id} {
70 // Make sure the box is actually 'bounding'
71 assert(envelope >= std::numeric_limits<scalar_t>::epsilon());
72 }
73
77 DETRAY_HOST axis_aligned_bounding_volume(const std::vector<scalar_t>& values,
78 std::size_t box_id)
79 : m_mask(values, box_id) {
80 assert(values.size() == shape::boundaries::e_size &&
81 " Given number of boundaries does not match mask shape.");
82 }
83
89 template <typename other_shape_t>
90 requires std::is_same_v<
91 typename shape::template local_frame_type<algebra_t>,
92 typename other_shape_t::template local_frame_type<algebra_t>>
93 DETRAY_HOST constexpr axis_aligned_bounding_volume(
95 aabbs,
96 std::size_t box_id, const scalar_t env) {
97 using loc_point_t = darray<scalar_t, other_shape_t::dim>;
98
99 // Find min/max extent of the local aabb in local coordinates
100 constexpr scalar_t inv{detail::invalid_value<scalar_t>()};
101 scalar_t min_x{inv};
102 scalar_t min_y{inv};
103 scalar_t min_z{inv};
104 scalar_t max_x{-inv};
105 scalar_t max_y{-inv};
106 scalar_t max_z{-inv};
107 for (const auto& vol : aabbs) {
108 const auto min_point = vol.template loc_min<loc_point_t>();
109 const auto max_point = vol.template loc_max<loc_point_t>();
110
111 // Check every coordinate of the points
112 min_x = min_point[0] < min_x ? min_point[0] : min_x;
113 min_y = min_point[1] < min_y ? min_point[1] : min_y;
114
115 max_x = max_point[0] > max_x ? max_point[0] : max_x;
116 max_y = max_point[1] > max_y ? max_point[1] : max_y;
117
118 if constexpr (min_point.size() > 2) {
119 min_z = min_point[2] < min_z ? min_point[2] : min_z;
120 max_z = max_point[2] > max_z ? max_point[2] : max_z;
121 }
122 }
124 box_id, min_x - env, min_y - env, min_z - env,
125 max_x + env, max_y + env, max_z + env};
126 }
127
131 DETRAY_HOST_DEVICE
132 constexpr auto operator[](const std::size_t i) const -> scalar_t {
133 return m_mask[i];
134 }
135
138 DETRAY_HOST_DEVICE
139 constexpr auto id() const -> std::size_t { return m_mask.volume_link(); }
140
143 DETRAY_HOST_DEVICE
144 constexpr auto bounds() const -> const mask<shape, algebra_t, std::size_t>& {
145 return m_mask;
146 }
147
149 template <typename point_t>
150 DETRAY_HOST_DEVICE constexpr auto loc_min() const -> point_t {
151 if constexpr (std::is_same_v<shape, cuboid3D>) {
152 return {m_mask[cuboid3D::e_min_x], m_mask[cuboid3D::e_min_y],
153 m_mask[cuboid3D::e_min_z]};
154 } else if constexpr (std::is_same_v<shape, cylinder3D>) {
155 return {-m_mask[cylinder3D::e_max_r], m_mask[cylinder3D::e_min_phi],
156 m_mask[cylinder3D::e_min_z]};
157 }
158
159 // If the volume shape is not supported, return universal minimum
160 assert(false);
161 constexpr scalar_t inv{detail::invalid_value<scalar_t>()};
162 return point_t{-inv, -inv, -inv};
163 }
164
166 template <typename point_t>
167 DETRAY_HOST_DEVICE constexpr auto loc_max() const -> point_t {
168 if constexpr (std::is_same_v<shape, cuboid3D>) {
169 return {m_mask[cuboid3D::e_max_x], m_mask[cuboid3D::e_max_y],
170 m_mask[cuboid3D::e_max_z]};
171 } else if constexpr (std::is_same_v<shape, cylinder3D>) {
172 return {m_mask[cylinder3D::e_max_r], m_mask[cylinder3D::e_max_phi],
173 m_mask[cylinder3D::e_max_z]};
174 }
175
176 // If the volume shape is not supported, return universal minimum
177 // (or compilation error for 2D point)
178 assert(false);
179 constexpr scalar_t inv{detail::invalid_value<scalar_t>()};
180 return point_t{inv, inv, inv};
181 }
182
186 template <concepts::transform3D transform3_t>
187 DETRAY_HOST_DEVICE constexpr auto glob_min(const transform3_t& trf) const ->
188 typename transform3_t::point3 {
189 using point3_t = typename transform3_t::point3;
190
191 if constexpr (std::is_same_v<shape, cuboid3D>) {
192 return trf.point_to_global(loc_min<point3_t>());
193 } else if constexpr (std::is_same_v<shape, cylinder3D>) {
194 return cylindrical3D<transform3_t>{}.local_to_global(trf, m_mask,
196 }
197
198 // If the volume shape is not supported, return universal minimum
199 // (or compilation error for 2D point)
200 assert(false);
201 constexpr scalar_t inv{detail::invalid_value<scalar_t>()};
202 return point3_t{-inv, -inv, -inv};
203 }
204
209 template <concepts::transform3D transform3_t>
210 DETRAY_HOST_DEVICE constexpr auto glob_max(const transform3_t& trf) const ->
211 typename transform3_t::point3 {
212 using point3_t = typename transform3_t::point3;
213
214 if constexpr (std::is_same_v<shape, cuboid3D>) {
215 return trf.point_to_global(loc_max<point3_t>());
216 } else if constexpr (std::is_same_v<shape, cylinder3D>) {
217 return cylindrical3D<transform3_t>{}.local_to_global(trf, m_mask,
219 }
220
221 // If the volume shape is not supported, return universal minimum
222 assert(false);
223 constexpr scalar_t inv{detail::invalid_value<scalar_t>()};
224 return point3_t{inv, inv, inv};
225 }
226
228 template <concepts::point3D point3_t>
229 DETRAY_HOST_DEVICE constexpr auto center() const -> point3_t {
230 const scalar_t center_x{
231 0.5f * (m_mask[cuboid3D::e_max_x] + m_mask[cuboid3D::e_min_x])};
232 const scalar_t center_y{
233 0.5f * (m_mask[cuboid3D::e_max_y] + m_mask[cuboid3D::e_min_y])};
234 const scalar_t center_z{
235 0.5f * (m_mask[cuboid3D::e_max_z] + m_mask[cuboid3D::e_min_z])};
236
237 return {detail::is_invalid_value(center_x) ? 0.f : center_x,
238 detail::is_invalid_value(center_y) ? 0.f : center_y,
239 detail::is_invalid_value(center_z) ? 0.f : center_z};
240 }
241
251 template <concepts::transform3D transform3_t, typename S = shape_t>
252 requires std::is_same_v<S, cuboid3D>
253 DETRAY_HOST_DEVICE auto transform(const transform3_t& trf) const
255 using point3_t = typename transform3_t::point3;
256
257 const scalar_t scalor_x{
258 (m_mask[cuboid3D::e_max_x] - m_mask[cuboid3D::e_min_x])};
259 const scalar_t scalor_y{
260 (m_mask[cuboid3D::e_max_y] - m_mask[cuboid3D::e_min_y])};
261 const scalar_t scalor_z{
262 (m_mask[cuboid3D::e_max_z] - m_mask[cuboid3D::e_min_z])};
263
264 // Cannot handle 'inv' propagation through the calculation for now
265 if (detail::is_invalid_value(scalor_x) ||
266 detail::is_invalid_value(scalor_y) ||
267 detail::is_invalid_value(scalor_z)) {
268 // If the box was infinite to begin with, it stays that way
269 assert(detail::is_invalid_value(scalor_x) &&
270 detail::is_invalid_value(scalor_y) &&
271 detail::is_invalid_value(scalor_z));
272
273 return *this;
274 }
275
276 // The new axis vectors, scaled to the aabb dimensions
277 // (e.g. max_x - min_x)
278 const point3_t new_box_x = scalor_x * trf.x();
279 const point3_t new_box_y = scalor_y * trf.y();
280 const point3_t new_box_z = scalor_z * trf.z();
281
282 // Transform the old min and max points to the global frame and
283 // construct all corner points of the local aabb in global coordinates
284 darray<point3_t, 8> glob_c_points;
285 glob_c_points[0] = glob_min(trf);
286 glob_c_points[1] = glob_max(trf);
287 glob_c_points[2] = glob_c_points[0] + new_box_x;
288 glob_c_points[3] = glob_c_points[0] + new_box_y;
289 glob_c_points[4] = glob_c_points[0] + new_box_z;
290 glob_c_points[5] = glob_c_points[1] - new_box_x;
291 glob_c_points[6] = glob_c_points[1] - new_box_y;
292 glob_c_points[7] = glob_c_points[1] - new_box_z;
293
294 // Find min/max extent of the local aabb in global coordinates
295 constexpr scalar_t inv{detail::invalid_value<scalar_t>()};
296 scalar_t min_x{inv};
297 scalar_t min_y{inv};
298 scalar_t min_z{inv};
299 scalar_t max_x{-inv};
300 scalar_t max_y{-inv};
301 scalar_t max_z{-inv};
302 for (const point3_t& p : glob_c_points) {
303 // Check every coordinate of the point
304 min_x = p[0] < min_x ? p[0] : min_x;
305 max_x = p[0] > max_x ? p[0] : max_x;
306 min_y = p[1] < min_y ? p[1] : min_y;
307 max_y = p[1] > max_y ? p[1] : max_y;
308 min_z = p[2] < min_z ? p[2] : min_z;
309 max_z = p[2] > max_z ? p[2] : max_z;
310 }
311
312 // Construct the transformed aabb
314 m_mask.volume_link(), min_x, min_y, min_z, max_x, max_y, max_z};
315 }
316
322 template <concepts::point point_t>
323 DETRAY_HOST_DEVICE constexpr bool is_inside(
324 const point_t& loc_p,
325 const scalar_t t = std::numeric_limits<scalar_t>::epsilon()) const {
326 return m_mask.is_inside(loc_p, t);
327 }
328
333 DETRAY_HOST_DEVICE
334 constexpr bool intersect(
335 const detail::ray<algebra_t>& ray,
336 const scalar_t t = std::numeric_limits<scalar_t>::epsilon()) const {
337 static_assert(std::is_same_v<shape, cuboid3D>,
338 "aabbs are only implemented in cuboid shape for now");
339 return cuboid_intersector{}(ray, m_mask, t);
340 }
341
342 private:
344 DETRAY_HOST friend std::ostream& operator<<(
345 std::ostream& os, const axis_aligned_bounding_volume& aabb) {
346 return os << aabb.bounds().to_string();
347 }
348
350};
351
352} // namespace detray
constexpr bool is_inside(const point_t &loc_p, const scalar_t t=std::numeric_limits< scalar_t >::epsilon()) const
Checks whether a point lies inside the box.
Definition bounding_volume.hpp:323
typename cuboid3D::boundaries boundaries
Definition bounding_volume.hpp:41
constexpr axis_aligned_bounding_volume(const std::vector< axis_aligned_bounding_volume< other_shape_t, algebra_t > > &aabbs, std::size_t box_id, const scalar_t env)
Construct a bounding box around a set of boxes.
Definition bounding_volume.hpp:93
constexpr auto id() const -> std::size_t
Return the volume identifier.
Definition bounding_volume.hpp:139
constexpr auto bounds() const -> const mask< shape, algebra_t, std::size_t > &
Return the shape mask storing this volume's bounds.
Definition bounding_volume.hpp:144
constexpr auto glob_max(const transform3_t &trf) const -> typename transform3_t::point3
Transform the local maximum bounds into global Cartesian coordinates.
Definition bounding_volume.hpp:210
constexpr auto loc_min() const -> point_t
Definition bounding_volume.hpp:150
constexpr auto glob_min(const transform3_t &trf) const -> typename transform3_t::point3
Transform the local minimum bounds into global Cartesian coordinates.
Definition bounding_volume.hpp:187
dscalar< algebra_t > scalar_t
Definition bounding_volume.hpp:37
typename cuboid3D::template local_frame_type< A > local_frame
Definition bounding_volume.hpp:44
constexpr bool intersect(const detail::ray< algebra_t > &ray, const scalar_t t=std::numeric_limits< scalar_t >::epsilon()) const
Intersect the box with a ray.
Definition bounding_volume.hpp:334
constexpr axis_aligned_bounding_volume(std::size_t box_id, Args &&... args)
Constructor from mask boundary values.
Definition bounding_volume.hpp:57
constexpr auto loc_max() const -> point_t
Definition bounding_volume.hpp:167
friend std::ostream & operator<<(std::ostream &os, const axis_aligned_bounding_volume &aabb)
Print the bounding volume.
Definition bounding_volume.hpp:344
constexpr axis_aligned_bounding_volume(const mask_t &mask, std::size_t box_id, const scalar_t envelope)
Construct around an arbitrary surface mask.
Definition bounding_volume.hpp:67
constexpr auto center() const -> point3_t
Definition bounding_volume.hpp:229
static constexpr std::size_t dim
Definition bounding_volume.hpp:47
cuboid3D shape
Definition bounding_volume.hpp:39
axis_aligned_bounding_volume(const std::vector< scalar_t > &values, std::size_t box_id)
Construct from mask boundary vector.
Definition bounding_volume.hpp:77
constexpr axis_aligned_bounding_volume()=default
Default constructor builds an infinite box.
auto transform(const transform3_t &trf) const -> axis_aligned_bounding_volume
Lower and upper point for minimum axis aligned bounding box of cuboid shape.
Definition bounding_volume.hpp:253
constexpr auto operator[](const std::size_t i) const -> scalar_t
Access one boundary value by its shape-specific index.
Definition bounding_volume.hpp:132
describes a straight-line trajectory
Definition ray.hpp:22
Mask a region on a surface and link it to a volume.
Definition mask.hpp:46
Detray include(s).
Definition array_operators.hpp:18
get_scalar_t< A, T > dscalar
Scalar type for algebra A and value type T.
Definition algebra.hpp:64
std::array< value_t, kDIM > darray
Fixed-size array container.
Definition containers.hpp:30
Checks if a cuboid bonuding box is intersected by a ray.
Definition cuboid_intersector.hpp:27
Projection into a 3D cylindrical coordinate frame.
Definition cylindrical3D.hpp:20
static point3_type local_to_global(const transform3_type &trf, const point3_type &p)
This method transforms from a local 3D cylindrical point to a point in the global cartesian 3D frame.
Definition cylindrical3D.hpp:70