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