💿🐜 Antkeeper source code https://antkeeper.com
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

199 lines
5.7 KiB

  1. /*
  2. * Copyright (C) 2021 Christopher J. Howard
  3. *
  4. * This file is part of Antkeeper source code.
  5. *
  6. * Antkeeper source code is free software: you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation, either version 3 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * Antkeeper source code is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>.
  18. */
  19. #ifndef ANTKEEPER_GEOM_PRIMITIVE_INTERSECTION_HPP
  20. #define ANTKEEPER_GEOM_PRIMITIVE_INTERSECTION_HPP
  21. #include "geom/primitive/hyperplane.hpp"
  22. #include "geom/primitive/hyperrectangle.hpp"
  23. #include "geom/primitive/hypersphere.hpp"
  24. #include "geom/primitive/ray.hpp"
  25. #include <algorithm>
  26. #include <optional>
  27. namespace geom {
  28. namespace primitive {
  29. /**
  30. * Ray-hyperplane intersection test.
  31. *
  32. * @param ray Ray.
  33. * @param hyperplane Hyperplane.
  34. *
  35. * @return Distance along the ray to the point of intersection, or `std::nullopt` if no intersection occurred.
  36. */
  37. /// @{
  38. template <class T, std::size_t N>
  39. constexpr std::optional<T> intersection(const ray<T, N>& ray, const hyperplane<T, N>& hyperplane) noexcept
  40. {
  41. const T cos_theta = math::dot(ray.direction, hyperplane.normal);
  42. if (cos_theta != T{0})
  43. {
  44. const T t = -hyperplane.distance(ray.origin) / cos_theta;
  45. if (t >= T{0})
  46. return t;
  47. }
  48. return std::nullopt;
  49. }
  50. template <class T, std::size_t N>
  51. constexpr inline std::optional<T> intersection(const hyperplane<T, N>& hyperplane, const ray<T, N>& ray) noexcept
  52. {
  53. return intersection<T, N>(ray, hyperplane);
  54. }
  55. /// @}
  56. /**
  57. * Ray-hyperrectangle intersection test.
  58. *
  59. * @param ray Ray.
  60. * @param hyperrectangle Hyperrectangle.
  61. *
  62. * @return Tuple containing the distances along the ray to the first and second points of intersection, or `std::nullopt` if no intersection occurred.
  63. */
  64. /// @{
  65. template <class T, std::size_t N>
  66. constexpr std::optional<std::tuple<T, T>> intersection(const ray<T, N>& ray, const hyperrectangle<T, N>& hyperrectangle) noexcept
  67. {
  68. T t0 = -std::numeric_limits<T>::infinity();
  69. T t1 = std::numeric_limits<T>::infinity();
  70. for (std::size_t i = 0; i < N; ++i)
  71. {
  72. if (!ray.direction[i])
  73. {
  74. if (ray.origin[i] < hyperrectangle.min[i] || ray.origin[i] > hyperrectangle.max[i])
  75. return std::nullopt;
  76. }
  77. else
  78. {
  79. T min = (hyperrectangle.min[i] - ray.origin[i]) / ray.direction[i];
  80. T max = (hyperrectangle.max[i] - ray.origin[i]) / ray.direction[i];
  81. t0 = std::max(t0, std::min(min, max));
  82. t1 = std::min(t1, std::max(min, max));
  83. }
  84. }
  85. if (t0 > t1 || t1 < T{0})
  86. return std::nullopt;
  87. return {t0, t1};
  88. }
  89. template <class T, std::size_t N>
  90. constexpr inline std::optional<std::tuple<T, T>> intersection(const hyperrectangle<T, N>& hyperrectangle, const ray<T, N>& ray) noexcept
  91. {
  92. return intersection<T, N>(ray, hyperrectangle);
  93. }
  94. /// @}
  95. /**
  96. * Ray-hypersphere intersection test.
  97. *
  98. * @param ray Ray.
  99. * @param hypersphere Hypersphere.
  100. *
  101. * @return Tuple containing the distances along the ray to the first and second points of intersection, or `std::nullopt` if no intersection occurred.
  102. */
  103. template <class T, std::size_t N>
  104. std::optional<std::tuple<T, T>> intersection(const ray<T, N>& ray, const hypersphere<T, N>& hypersphere) noexcept
  105. {
  106. const math::vector<T, N> displacement = ray.origin - hypersphere.center;
  107. const T b = math::dot(displacement, ray.direction);
  108. const T c = math::length_squared(displacement) - hypersphere.radius * hypersphere.radius;
  109. T h = b * b - c;
  110. if (h < T{0})
  111. return std::nullopt;
  112. h = std::sqrt(h);
  113. return std::tuple<float, float>{-b - h, -b + h};
  114. }
  115. /**
  116. * Hyperrectangle-hyperrectangle intersection test.
  117. *
  118. * @param a First hyperrectangle.
  119. * @param b Second hyperrectangle.
  120. *
  121. * @return `true` if an intersection occurred, `false` otherwise.
  122. */
  123. template <class T, std::size_t N>
  124. constexpr inline bool intersection(const hyperrectangle<T, N>& a, const hyperrectangle<T, N>& b) noexcept
  125. {
  126. return a.intersects(b);
  127. }
  128. /**
  129. * Hyperrectangle-hypersphere intersection test.
  130. *
  131. * @param hyperrectangle Hyperrectangle.
  132. * @param hypersphere Hypersphere.
  133. *
  134. * @return `true` if an intersection occurred, `false` otherwise.
  135. */
  136. /// @{
  137. template <class T, std::size_t N>
  138. constexpr bool intersection(const hyperrectangle<T, N>& hyperrectangle, const hypersphere<T, N>& hypersphere) noexcept
  139. {
  140. T sqr_distance{0};
  141. for (std::size_t i = 0; i < N; ++i)
  142. {
  143. if (hypersphere.center[i] < hyperrectangle.min[i])
  144. {
  145. const T difference = hyperrectangle.min[i] - hypersphere.center[i];
  146. sqr_distance += difference * difference;
  147. }
  148. else if (hypersphere.center[i] > hyperrectangle.max[i])
  149. {
  150. const T difference = hypersphere.center[i] - hyperrectangle.max[i];
  151. sqr_distance += difference * difference;
  152. }
  153. }
  154. return sqr_distance <= hypersphere.radius * hypersphere.radius;
  155. }
  156. template <class T, std::size_t N>
  157. constexpr inline bool intersection(const hypersphere<T, N>& hypersphere, const hyperrectangle<T, N>& hyperrectangle) noexcept
  158. {
  159. return intersection<T, N>(hyperrectangle, hypersphere);
  160. }
  161. /// @}
  162. /**
  163. * Hypersphere-hypersphere intersection test.
  164. *
  165. * @param a First hypersphere.
  166. * @param b Second hypersphere.
  167. *
  168. * @return `true` if an intersection occurred, `false` otherwise.
  169. */
  170. template <class T, std::size_t N>
  171. constexpr inline bool intersection(const hypersphere<T, N>& a, const hypersphere<T, N>& b) noexcept
  172. {
  173. return a.intersects(b);
  174. }
  175. } // namespace primitive
  176. } // namespace geom
  177. #endif // ANTKEEPER_GEOM_PRIMITIVE_INTERSECTION_HPP