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

201 lines
5.8 KiB

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