Files
watrbx-game-engine/App/util/Extents.h
T
2025-10-28 14:05:46 -04:00

240 lines
5.8 KiB
C++

#pragma once
#include "Util/NormalId.h"
#include "Util/G3DCore.h"
#include "rbx/Debug.h"
#include "Util/Math.h"
namespace RBX {
class Extents {
private:
Vector3 low;
Vector3 high;
public:
Extents() // initialize to negativeInfiniteExtents;
: low(Vector3::maxFinite())
, high(-Vector3::maxFinite())
{}
Extents(const Vector3& _min, const Vector3& _max)
: low(_min)
, high(_max)
{
RBXASSERT_SLOW(low == low.min(high));
RBXASSERT_SLOW(high == high.max(low));
}
bool isNanInf() const
{
return (Math::isNanInfVector3(low) || Math::isNanInfVector3(high));
}
static Extents fromCenterCorner(const Vector3& center, const Vector3& corner) {
return Extents(center-corner, center+corner);
}
static Extents fromCenterRadius(const Vector3& center, float radius) {
return fromCenterCorner(center, Vector3(radius, radius, radius));
}
bool operator==(const Extents& other) const {
return ((low == other.low) && (high == other.high));
}
bool operator!=(const Extents& other) const {
return !(*this == other);
}
static Extents vv(const Vector3& v0, const Vector3& v1) {
Extents e;
e.low = v0.min(v1);
e.high = v0.max(v1);
return e;
}
const Vector3& min() const {return low;}
const Vector3& max() const {return high;}
Vector3int16 getCornerIndex(int i) const;
Vector3 getCorner(int i) const;
Vector3 size() const {
return high - low;
}
Vector3 center() const {
return 0.5 * (low + high);
}
Vector3 bottomCenter() const {
Vector3 answer = center();
answer.y = low.y;
return answer;
}
Vector3 topCenter() const {
Vector3 answer = center();
answer.y = high.y;
return answer;
}
float longestSide() const {
Vector3 s = size();
return G3D::max(G3D::max(s.x, s.y), s.z);
}
float volume() const {
Vector3 s = size();
return s.x * s.y * s.z;
}
float areaXZ() const {
Vector3 s = size();
return s.x * s.z;
}
bool isNull() const {
return low.x > high.x || low.y > high.y || low.z > high.z;
}
Extents toWorldSpace(const CoordinateFrame& offset) const;
Extents express(const CoordinateFrame& myFrame, const CoordinateFrame& expressInFrame) const;
// faceId's are in order of x, y, z, -x, -y, -z
Vector3 faceCenter(NormalId faceId) const;
/**
Returns the four corners of a face (0 <= f < 6).
The corners are returned to form a counter clockwise quad facing outwards.
*/
void getFaceCorners(
NormalId faceId,
Vector3& v0,
Vector3& v1,
Vector3& v2,
Vector3& v3) const;
Plane getPlane(NormalId normalId) const;
// clip the vector to be inside the Extents
Vector3 clip(const Vector3& clipVector) const {
return clipVector.clamp(low, high);
}
float computeClosestSqDistanceToPoint(const Vector3& point) const;
// minimum amount to move innerExtents and keep them within Extents
Vector3 clamp(const Extents& innerExtents) const;
NormalId closestFace(const Vector3& point);
void unionWith(const Extents& other) { // Extents& operator&= (const Extents& other) {
low = low.min(other.low);
high = high.max(other.high);
}
Extents clampInsideOf(const Extents& other) const; // Extents& operator&= (const Extents& other) {
void shift(const Vector3& shiftVector) {// Extents& operator+= (const Vector3& shiftVector) {
low += shiftVector;
high += shiftVector;
}
void scale(float x) { // Extents& operator*= (float x) {
low *= x;
high *= x;
}
void expand(float x) {
low -= Vector3(x,x,x);
high += Vector3(x,x,x);
}
void expand(const Vector3& p) {
low -= p;
high += p;
}
void expandToContain(const Vector3& p) {
low = low.min(p);
high = high.max(p);
}
void expandToContain(const Extents& e) {
low = low.min(e.low);
high = high.max(e.high);
}
bool contains(const Vector3& point) const {
return ( (point.x >= low.x)
&& (point.y >= low.y)
&& (point.z >= low.z)
&& (point.x <= high.x)
&& (point.y <= high.y)
&& (point.z <= high.z) );
}
bool fuzzyContains(const Vector3& point, float slop) const {
return ( (point.x >= (low.x - slop))
&& (point.y >= (low.y - slop))
&& (point.z >= (low.z - slop))
&& (point.x <= (high.x + slop))
&& (point.y <= (high.y + slop))
&& (point.z <= (high.z + slop)) );
}
bool overlapsOrTouches(const Extents& other) const { // true if sides are exactly equal (touching)
return ( (this->low.x > other.high.x)
|| (this->low.y > other.high.y)
|| (this->low.z > other.high.z)
|| (this->high.y < other.low.y)
|| (this->high.x < other.low.x)
|| (this->high.z < other.low.z)) ? false : true;
}
static bool overlapsOrTouches(const Extents& e0, const Extents& e1) {return e0.overlapsOrTouches(e1);}
bool clampToOverlap(const Extents& other) {
if ( (this->low.x >= other.high.x)
|| (this->low.y >= other.high.y)
|| (this->low.z >= other.high.z)
|| (this->high.y <= other.low.y)
|| (this->high.x <= other.low.x)
|| (this->high.z <= other.low.z))
return false; // not overlap
low = low.clamp(other.low, other.high);
high = high.clamp(other.low, other.high);
return true;
}
bool separatedByMoreThan(const Extents& other, float distance) const;
static const Extents& zero() {
static Extents e(Vector3::zero(), Vector3::zero());
return e;
}
static const Extents& unit() {
static Extents e(Vector3(-1,-1,-1), Vector3(1,1,1));
return e;
}
static const Extents& negativeMaxExtents() {
static Extents e; // default constructor builds this;
return e;
}
static const Extents& maxExtents() {
static Extents e(-Vector3::maxFinite(), Vector3::maxFinite());
return e;
}
};
} // namespace