💿🐜 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.

207 lines
5.8 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::sqr_length(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. T t0 = -b - h;
  114. T t1 = -b + h;
  115. if (t0 > t1)
  116. std::swap(t0, t1);
  117. if (t0 < T{0})
  118. return std::nullopt;
  119. return std::tuple<T, T>{t0, t1};
  120. }
  121. /**
  122. * Hyperrectangle-hyperrectangle intersection test.
  123. *
  124. * @param a First hyperrectangle.
  125. * @param b Second hyperrectangle.
  126. *
  127. * @return `true` if an intersection occurred, `false` otherwise.
  128. */
  129. template <class T, std::size_t N>
  130. constexpr inline bool intersection(const hyperrectangle<T, N>& a, const hyperrectangle<T, N>& b) noexcept
  131. {
  132. return a.intersects(b);
  133. }
  134. /**
  135. * Hyperrectangle-hypersphere intersection test.
  136. *
  137. * @param hyperrectangle Hyperrectangle.
  138. * @param hypersphere Hypersphere.
  139. *
  140. * @return `true` if an intersection occurred, `false` otherwise.
  141. */
  142. /// @{
  143. template <class T, std::size_t N>
  144. constexpr bool intersection(const hyperrectangle<T, N>& hyperrectangle, const hypersphere<T, N>& hypersphere) noexcept
  145. {
  146. T sqr_distance{0};
  147. for (std::size_t i = 0; i < N; ++i)
  148. {
  149. if (hypersphere.center[i] < hyperrectangle.min[i])
  150. {
  151. const T difference = hyperrectangle.min[i] - hypersphere.center[i];
  152. sqr_distance += difference * difference;
  153. }
  154. else if (hypersphere.center[i] > hyperrectangle.max[i])
  155. {
  156. const T difference = hypersphere.center[i] - hyperrectangle.max[i];
  157. sqr_distance += difference * difference;
  158. }
  159. }
  160. return sqr_distance <= hypersphere.radius * hypersphere.radius;
  161. }
  162. template <class T, std::size_t N>
  163. constexpr inline bool intersection(const hypersphere<T, N>& hypersphere, const hyperrectangle<T, N>& hyperrectangle) noexcept
  164. {
  165. return intersection<T, N>(hyperrectangle, hypersphere);
  166. }
  167. /// @}
  168. /**
  169. * Hypersphere-hypersphere intersection test.
  170. *
  171. * @param a First hypersphere.
  172. * @param b Second hypersphere.
  173. *
  174. * @return `true` if an intersection occurred, `false` otherwise.
  175. */
  176. template <class T, std::size_t N>
  177. constexpr inline bool intersection(const hypersphere<T, N>& a, const hypersphere<T, N>& b) noexcept
  178. {
  179. return a.intersects(b);
  180. }
  181. } // namespace primitive
  182. } // namespace geom
  183. #endif // ANTKEEPER_GEOM_PRIMITIVE_INTERSECTION_HPP