Line data Source code
1 : #pragma once 2 : 3 : #include "elsaDefines.h" 4 : #include "BoundingBox.h" 5 : 6 : #include "spdlog/fmt/fmt.h" 7 : 8 : #include <Eigen/Geometry> 9 : #include <limits> 10 : #include <optional> 11 : #include <functional> 12 : 13 : namespace elsa 14 : { 15 : /** 16 : * @brief Helper struct for results of intersection tests 17 : */ 18 : struct IntersectionResult { 19 : /// the parameters for entry/exit points 20 : real_t _tmin, _tmax; 21 : 22 : /// default constructor 23 : IntersectionResult() 24 : : _tmin{std::numeric_limits<real_t>::infinity()}, 25 : _tmax{std::numeric_limits<real_t>::infinity()} 26 0 : { 27 0 : } 28 : 29 : /// simple constructor with values tmin, tmax 30 291026 : IntersectionResult(real_t tmin, real_t tmax) : _tmin{tmin}, _tmax{tmax} {} 31 : }; 32 : 33 : /** 34 : * @brief The intersection class computes intersections between rays and axis-aligned bounding 35 : * boxes (AABBs) 36 : * 37 : * @author Tobias Lasser - initial code, modernization 38 : * @author David Frank - various fixes 39 : * @author Maximilian Hornung - modularization 40 : * @author Nikola Dinev - various fixes 41 : */ 42 : class Intersection 43 : { 44 : public: 45 : /** 46 : * @brief Compute entry and exit point of ray in a volume (given as an AABB) 47 : * 48 : * @param[in] aabb the volume specified through an axis-aligned bounding box 49 : * @param[in] r the ray which we test for intersection with aabb 50 : 51 : * @returns nullopt if the volume is not hit, otherwise IntersectionResult 52 : * with entry/exit parameters tmin/tmax 53 : * 54 : * If the ray is running along a border of the bounding box, the lower bound will 55 : * be counted as in the bounding and the upper bound will be counted as outside. 56 : * 57 : * Method adapted from 58 : https://tavianator.com/fast-branchless-raybounding-box-intersections-part-2-nans/ 59 : */ 60 : static std::optional<IntersectionResult> withRay(const BoundingBox& aabb, 61 : const RealRay_t& r); 62 : 63 : static std::optional<IntersectionResult> xPlanesWithRay(BoundingBox aabb, 64 : const RealRay_t& r); 65 : }; 66 : 67 : /** 68 : * @brief min helper function which behaves like the IEEE standard suggests 69 : * 70 : * @param[in] x first value to find minimum of 71 : * @param[in] y second value to find minimum of 72 : * @returns the smaller value of x and y 73 : * 74 : * This function is used, because it tries to suppress NaN's. This behavior is 75 : * crucial for edge cases of the intersection algorithm. std::min(x,y) does 76 : * not provide this security and should be avoided in this case 77 : */ 78 : template <typename T1, typename T2> 79 : constexpr T1 minNum(T1 x, T2 y) 80 332156 : { 81 332156 : return std::not_equal_to<>()(y, y) ? x : (std::less<>()(x, y) ? x : y); 82 332156 : } 83 : 84 : /** 85 : * @brief max helper function which behaves like the IEEE standard suggests 86 : * 87 : * @param[in] x first value to find maximum of 88 : * @param[in] y second value to find maximum of 89 : * @returns the bigger value of x and y 90 : * 91 : * Same thing for NaN's as for the min function 92 : */ 93 : template <typename T1, typename T2> 94 : constexpr T1 maxNum(T1 x, T2 y) 95 637956 : { 96 637956 : return std::not_equal_to<>()(y, y) ? x : (std::greater<>()(x, y) ? x : y); 97 637956 : } 98 : 99 : } // namespace elsa 100 : 101 : template <> 102 : struct fmt::formatter<elsa::IntersectionResult> { 103 : template <typename ParseContext> 104 : constexpr auto parse(ParseContext& ctx) 105 0 : { 106 0 : return ctx.begin(); 107 0 : } 108 : 109 : template <typename FormatContext> 110 : auto format(const elsa::IntersectionResult& hit, FormatContext& ctx) 111 0 : { 112 0 : return fmt::format_to(ctx.out(), "{{ tmin: {}, tmax: {} }}", hit._tmin, hit._tmax); 113 0 : } 114 : };