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

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