/* This file is part of NSEssentials. Use of this source code is granted via a BSD-style license, which can be found in License.txt in the repository root. @author Nico Schertler */ #pragma once #include namespace nse { namespace math { //Represents an n-dimensional axis-aligned bounding box. The lower limits are inclusive, //whereas the upper limits are exclusive. template struct BoundingBox { Eigen::Matrix min, max; //Initializes the bounding box with an empty area. BoundingBox() { reset(); } BoundingBox(const Eigen::Matrix& min, const Eigen::Matrix& max) : min(min), max(max) { } //Resets the bounding box to an empty area. void reset() { min.setConstant(std::numeric_limits::max()); max.setConstant(std::numeric_limits::lowest()); } //Computes the intersection of two axis-aligned bounding boxes and returns if there is an intersection. static bool intersect(const BoundingBox& bb1, const BoundingBox& bb2, BoundingBox& out) { for (int i = 0; i < DIM; ++i) { out.min[i] = std::max(bb1.min[i], bb2.min[i]); if (out.min[i] > bb1.max[i] || out.min[i] > bb2.max[i]) return false; out.max[i] = std::min(bb1.max[i], bb2.max[i]); if (out.max[i] < bb1.min[i] || out.max[i] < bb2.min[i]) return false; } return true; } //Computes the union of two axis-aligned bounding boxes. static void unite(const BoundingBox& bb1, const BoundingBox& bb2, BoundingBox& out) { for (int i = 0; i < DIM; ++i) { out.min[i] = std::min(bb1.min[i], bb2.min[i]); out.max[i] = std::max(bb1.max[i], bb2.max[i]); } } //expands the bounding box to contain every point in V void expand(const Eigen::Matrix& V) { for (int v = 0; v < V.cols(); ++v) { for (int i = 0; i < DIM; ++i) { if (V(i, v) < min(i)) min(i) = V(i, v); if (V(i, v) >= max(i)) max(i) = nextafter(V(i, v), std::numeric_limits::max()); } } } //Returns if the bounding box contains the given point. bool containsPoint(const Eigen::Matrix& v) const { for (int i = 0; i < DIM; ++i) { if (v(i) < min(i) || v(i) >= max(i)) return false; } return true; } //Returns the box's diagonal Eigen::Matrix diagonal() const { return max - min; } //Returns the box's center Eigen::Matrix center() const { return 0.5f * (min + max); } //Transforms the bounding box with a given affine transform and returns the axis-aligned bounding box //of the transformed box. BoundingBox transform(const Eigen::Transform& t) const { //http://dev.theomader.com/transform-bounding-boxes/ Eigen::Matrix tMin = t.translation(); Eigen::Matrix tMax = t.translation(); for (int i = 0; i < DIM; ++i) { Eigen::Matrix a = t.linear().col(i) * min(i); Eigen::Matrix b = t.linear().col(i) * max(i); tMin += a.cwiseMin(b); tMax += a.cwiseMax(b); } return BoundingBox(tMin, tMax); } }; } }