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

206 lines
6.0 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_AABB_HPP
  20. #define ANTKEEPER_GEOM_AABB_HPP
  21. #include "bounding-volume.hpp"
  22. #include "sphere.hpp"
  23. #include "math/math.hpp"
  24. #include <limits>
  25. namespace geom {
  26. /**
  27. * Axis-aligned bounding box.
  28. */
  29. template <class T>
  30. struct aabb: public bounding_volume<T>
  31. {
  32. typedef math::vector<T, 3> vector_type;
  33. typedef math::matrix<T, 4, 4> matrix_type;
  34. typedef math::transform<T> transform_type;
  35. vector_type min_point;
  36. vector_type max_point;
  37. /**
  38. * Transforms an AABB.
  39. *
  40. * @param a AABB to be transformed.
  41. * @param t Transform by which the AABB should be transformed.
  42. * @return Transformed AABB.
  43. */
  44. static aabb transform(const aabb& a, const transform_type& t);
  45. /**
  46. * Transforms an AABB.
  47. *
  48. * @param a AABB to be transformed.
  49. * @param m Matrix by which the AABB should be transformed.
  50. * @return Transformed AABB.
  51. */
  52. static aabb transform(const aabb& a, const matrix_type& m);
  53. aabb(const vector_type& min_point, const vector_type& max_point);
  54. aabb();
  55. virtual bounding_volume_type get_bounding_volume_type() const;
  56. virtual bool intersects(const sphere<T>& sphere) const;
  57. virtual bool intersects(const aabb<T>& aabb) const;
  58. virtual bool contains(const sphere<T>& sphere) const;
  59. virtual bool contains(const aabb<T>& aabb) const;
  60. virtual bool contains(const vector_type& point) const;
  61. /**
  62. * Returns the position of the specified corner.
  63. *
  64. * @param index Index of a corner.
  65. * @return Position of the specified corner.
  66. */
  67. vector_type corner(int index) const noexcept;
  68. };
  69. template <class T>
  70. aabb<T> aabb<T>::transform(const aabb& a, const transform_type& t)
  71. {
  72. vector_type min_point = {std::numeric_limits<T>::infinity(), std::numeric_limits<T>::infinity(), std::numeric_limits<T>::infinity()};
  73. vector_type max_point = {-std::numeric_limits<T>::infinity(), -std::numeric_limits<T>::infinity(), -std::numeric_limits<T>::infinity()};
  74. for (std::size_t i = 0; i < 8; ++i)
  75. {
  76. vector_type transformed_corner = math::mul(t, a.corner(i));
  77. for (std::size_t j = 0; j < 3; ++j)
  78. {
  79. min_point[j] = std::min<T>(min_point[j], transformed_corner[j]);
  80. max_point[j] = std::max<T>(max_point[j], transformed_corner[j]);
  81. }
  82. }
  83. return {min_point, max_point};
  84. }
  85. template <class T>
  86. aabb<T> aabb<T>::transform(const aabb& a, const matrix_type& m)
  87. {
  88. vector_type min_point = {std::numeric_limits<T>::infinity(), std::numeric_limits<T>::infinity(), std::numeric_limits<T>::infinity()};
  89. vector_type max_point = {-std::numeric_limits<T>::infinity(), -std::numeric_limits<T>::infinity(), -std::numeric_limits<T>::infinity()};
  90. for (std::size_t i = 0; i < 8; ++i)
  91. {
  92. vector_type corner = a.corner(i);
  93. math::vector<T, 4> transformed_corner = math::mul(m, math::vector<T, 4>{corner.x, corner.y, corner.z, T(1)});
  94. for (std::size_t j = 0; j < 3; ++j)
  95. {
  96. min_point[j] = std::min<T>(min_point[j], transformed_corner[j]);
  97. max_point[j] = std::max<T>(max_point[j], transformed_corner[j]);
  98. }
  99. }
  100. return {min_point, max_point};
  101. }
  102. template <class T>
  103. aabb<T>::aabb(const vector_type& min_point, const vector_type& max_point):
  104. min_point(min_point),
  105. max_point(max_point)
  106. {}
  107. template <class T>
  108. aabb<T>::aabb()
  109. {}
  110. template <class T>
  111. inline bounding_volume_type aabb<T>::get_bounding_volume_type() const
  112. {
  113. return bounding_volume_type::aabb;
  114. }
  115. template <class T>
  116. bool aabb<T>::intersects(const sphere<T>& sphere) const
  117. {
  118. const vector_type radius_vector = {sphere.radius, sphere.radius, sphere.radius};
  119. return aabb<T>(min_point - radius_vector, max_point + radius_vector).contains(sphere.center);
  120. }
  121. template <class T>
  122. bool aabb<T>::intersects(const aabb<T>& aabb) const
  123. {
  124. if (max_point.x < aabb.min_point.x || min_point.x > aabb.max_point.x)
  125. return false;
  126. if (max_point.y < aabb.min_point.y || min_point.y > aabb.max_point.y)
  127. return false;
  128. if (max_point.z < aabb.min_point.z || min_point.z > aabb.max_point.z)
  129. return false;
  130. return true;
  131. }
  132. template <class T>
  133. bool aabb<T>::contains(const sphere<T>& sphere) const
  134. {
  135. if (sphere.center.x - sphere.radius < min_point.x || sphere.center.x + sphere.radius > max_point.x)
  136. return false;
  137. if (sphere.center.y - sphere.radius < min_point.y || sphere.center.y + sphere.radius > max_point.y)
  138. return false;
  139. if (sphere.center.z - sphere.radius < min_point.z || sphere.center.z + sphere.radius > max_point.z)
  140. return false;
  141. return true;
  142. }
  143. template <class T>
  144. bool aabb<T>::contains(const aabb<T>& aabb) const
  145. {
  146. if (aabb.min_point.x < min_point.x || aabb.max_point.x > max_point.x)
  147. return false;
  148. if (aabb.min_point.y < min_point.y || aabb.max_point.y > max_point.y)
  149. return false;
  150. if (aabb.min_point.z < min_point.z || aabb.max_point.z > max_point.z)
  151. return false;
  152. return true;
  153. }
  154. template <class T>
  155. bool aabb<T>::contains(const vector_type& point) const
  156. {
  157. if (point.x < min_point.x || point.x > max_point.x)
  158. return false;
  159. if (point.y < min_point.y || point.y > max_point.y)
  160. return false;
  161. if (point.z < min_point.z || point.z > max_point.z)
  162. return false;
  163. return true;
  164. }
  165. template <class T>
  166. typename aabb<T>::vector_type aabb<T>::corner(int index) const noexcept
  167. {
  168. return
  169. {
  170. ((index >> 2) & 1) ? max_point[0] : min_point[0],
  171. ((index >> 1) & 1) ? max_point[1] : min_point[1],
  172. ((index >> 0) & 1) ? max_point[2] : min_point[2]
  173. };
  174. }
  175. } // namespace geom
  176. #endif // ANTKEEPER_GEOM_AABB_HPP