blob: ad5053fc45c609c1cc8245fd0c7b08b13cba2cee [file] [log] [blame]
// Copyright 2017 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef LIB_ESCHER_GEOMETRY_BOUNDING_BOX_H_
#define LIB_ESCHER_GEOMETRY_BOUNDING_BOX_H_
#include "lib/escher/geometry/types.h"
namespace escher {
class BoundingBox {
public:
// Non-empty box. No error-checking; it is up to the caller to ensure that
// all components of max are >= the corresponding component of min.
BoundingBox(vec3 min, vec3 max);
// Empty box.
constexpr BoundingBox() : min_{1, 1, 1}, max_{0, 0, 0} {}
// Return an empty box if max < min along any of the coordinate axes,
// or if max == min along more than |max_degenerate_dimensions| of the
// coordinate axes. Otherwise return a non-empty box.
static BoundingBox NewChecked(vec3 min, vec3 max,
uint32_t max_degenerate_dimensions = 0);
const vec3& min() const { return min_; }
const vec3& max() const { return max_; }
bool operator==(const BoundingBox& box) const {
return min_ == box.min_ && max_ == box.max_;
}
bool operator!=(const BoundingBox& box) const { return !(*this == box); }
// Expand this bounding box to encompass the other. Return this box.
BoundingBox& Join(const BoundingBox& box);
// Shrink this box to be the intersection of this with the other. If the
// boxes do not intersect, this box becomes empty. Return this box.
BoundingBox& Intersect(const BoundingBox& box);
float width() const { return max_.x - min_.x; }
float height() const { return max_.y - min_.y; }
float depth() const { return max_.z - min_.z; }
// Return true if the other box is completely contained by this one.
bool Contains(const BoundingBox& box) const {
// We don't need to check if this box is empty, because the way we define
// an empty box guarantees that the subsequent tests can't pass.
return glm::all(glm::lessThanEqual(min_, box.min_)) &&
glm::all(glm::greaterThanEqual(max_, box.max_)) && !box.is_empty();
}
bool is_empty() const { return *this == BoundingBox(); }
// Return the number of bounding box corners that are clipped by the
// specified plane (between 0 and 8). Since this is a 2D plane, the z
// coordinate is ignored, and only 4 corners need to be tested.
uint32_t NumClippedCorners(const plane2& plane) const;
// Return the number of bounding box corners that are clipped by the
// specified plane (between 0 and 8).
uint32_t NumClippedCorners(const plane3& plane) const;
private:
vec3 min_;
vec3 max_;
};
// Return a new BoundingBox that encloses the 8 corners of this box, after
// they are transformed by the matrix. Note: this can cause the box to grow,
// e.g. if you rotate it by 45 degrees.
BoundingBox operator*(const mat4& matrix, const BoundingBox& box);
// Return a new Bounding box by translating the input box.
inline BoundingBox operator+(const vec3& translation, const BoundingBox& box) {
return box.is_empty()
? BoundingBox()
: BoundingBox(box.min() + translation, box.max() + translation);
}
// Return a new Bounding box by translating the input box.
inline BoundingBox operator+(const BoundingBox& box, const vec3& translation) {
return translation + box;
}
// Debugging.
ESCHER_DEBUG_PRINTABLE(BoundingBox);
} // namespace escher
#endif // LIB_ESCHER_GEOMETRY_BOUNDING_BOX_H_