/* * Copyright (C) 2021 Christopher J. Howard * * This file is part of Antkeeper source code. * * Antkeeper source code is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Antkeeper source code is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Antkeeper source code. If not, see . */ #ifndef ANTKEEPER_GEOM_AABB_HPP #define ANTKEEPER_GEOM_AABB_HPP #include "bounding-volume.hpp" #include "sphere.hpp" #include "math/math.hpp" #include namespace geom { /** * Axis-aligned bounding box. */ template struct aabb: public bounding_volume { typedef math::vector vector_type; typedef math::matrix matrix_type; typedef math::transform transform_type; vector_type min_point; vector_type max_point; /** * Transforms an AABB. * * @param a AABB to be transformed. * @param t Transform by which the AABB should be transformed. * @return Transformed AABB. */ static aabb transform(const aabb& a, const transform_type& t); /** * Transforms an AABB. * * @param a AABB to be transformed. * @param m Matrix by which the AABB should be transformed. * @return Transformed AABB. */ static aabb transform(const aabb& a, const matrix_type& m); aabb(const vector_type& min_point, const vector_type& max_point); aabb(); virtual bounding_volume_type get_bounding_volume_type() const; virtual bool intersects(const sphere& sphere) const; virtual bool intersects(const aabb& aabb) const; virtual bool contains(const sphere& sphere) const; virtual bool contains(const aabb& aabb) const; virtual bool contains(const vector_type& point) const; /** * Returns the position of the specified corner. * * @param index Index of a corner. * @return Position of the specified corner. */ vector_type corner(int index) const noexcept; }; template aabb aabb::transform(const aabb& a, const transform_type& t) { vector_type min_point = {std::numeric_limits::infinity(), std::numeric_limits::infinity(), std::numeric_limits::infinity()}; vector_type max_point = {-std::numeric_limits::infinity(), -std::numeric_limits::infinity(), -std::numeric_limits::infinity()}; for (std::size_t i = 0; i < 8; ++i) { vector_type transformed_corner = math::mul(t, a.corner(i)); for (std::size_t j = 0; j < 3; ++j) { min_point[j] = std::min(min_point[j], transformed_corner[j]); max_point[j] = std::max(max_point[j], transformed_corner[j]); } } return {min_point, max_point}; } template aabb aabb::transform(const aabb& a, const matrix_type& m) { vector_type min_point = {std::numeric_limits::infinity(), std::numeric_limits::infinity(), std::numeric_limits::infinity()}; vector_type max_point = {-std::numeric_limits::infinity(), -std::numeric_limits::infinity(), -std::numeric_limits::infinity()}; for (std::size_t i = 0; i < 8; ++i) { vector_type corner = a.corner(i); math::vector transformed_corner = math::mul(m, math::vector{corner.x, corner.y, corner.z, T(1)}); for (std::size_t j = 0; j < 3; ++j) { min_point[j] = std::min(min_point[j], transformed_corner[j]); max_point[j] = std::max(max_point[j], transformed_corner[j]); } } return {min_point, max_point}; } template aabb::aabb(const vector_type& min_point, const vector_type& max_point): min_point(min_point), max_point(max_point) {} template aabb::aabb() {} template inline bounding_volume_type aabb::get_bounding_volume_type() const { return bounding_volume_type::aabb; } template bool aabb::intersects(const sphere& sphere) const { const vector_type radius_vector = {sphere.radius, sphere.radius, sphere.radius}; return aabb(min_point - radius_vector, max_point + radius_vector).contains(sphere.center); } template bool aabb::intersects(const aabb& aabb) const { if (max_point.x < aabb.min_point.x || min_point.x > aabb.max_point.x) return false; if (max_point.y < aabb.min_point.y || min_point.y > aabb.max_point.y) return false; if (max_point.z < aabb.min_point.z || min_point.z > aabb.max_point.z) return false; return true; } template bool aabb::contains(const sphere& sphere) const { if (sphere.center.x - sphere.radius < min_point.x || sphere.center.x + sphere.radius > max_point.x) return false; if (sphere.center.y - sphere.radius < min_point.y || sphere.center.y + sphere.radius > max_point.y) return false; if (sphere.center.z - sphere.radius < min_point.z || sphere.center.z + sphere.radius > max_point.z) return false; return true; } template bool aabb::contains(const aabb& aabb) const { if (aabb.min_point.x < min_point.x || aabb.max_point.x > max_point.x) return false; if (aabb.min_point.y < min_point.y || aabb.max_point.y > max_point.y) return false; if (aabb.min_point.z < min_point.z || aabb.max_point.z > max_point.z) return false; return true; } template bool aabb::contains(const vector_type& point) const { if (point.x < min_point.x || point.x > max_point.x) return false; if (point.y < min_point.y || point.y > max_point.y) return false; if (point.z < min_point.z || point.z > max_point.z) return false; return true; } template typename aabb::vector_type aabb::corner(int index) const noexcept { return { ((index >> 2) & 1) ? max_point[0] : min_point[0], ((index >> 1) & 1) ? max_point[1] : min_point[1], ((index >> 0) & 1) ? max_point[2] : min_point[2] }; } } // namespace geom #endif // ANTKEEPER_GEOM_AABB_HPP