2024-03-19 17:45:12 +08:00

217 lines
8.8 KiB
C++

/**************************************************************************************/
/* */
/* Visualization Library */
/* http://visualizationlibrary.org */
/* */
/* Copyright (c) 2005-2020, Michele Bosi */
/* All rights reserved. */
/* */
/* Redistribution and use in source and binary forms, with or without modification, */
/* are permitted provided that the following conditions are met: */
/* */
/* - Redistributions of source code must retain the above copyright notice, this */
/* list of conditions and the following disclaimer. */
/* */
/* - Redistributions in binary form must reproduce the above copyright notice, this */
/* list of conditions and the following disclaimer in the documentation and/or */
/* other materials provided with the distribution. */
/* */
/* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND */
/* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED */
/* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE */
/* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR */
/* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES */
/* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; */
/* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON */
/* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT */
/* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS */
/* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
/* */
/**************************************************************************************/
#ifndef AABB_INCLUDE_ONCE
#define AABB_INCLUDE_ONCE
#include <vlCore/Vector3.hpp>
#include <vlCore/Matrix4.hpp>
namespace vl
{
//-----------------------------------------------------------------------------
// AABB
//-----------------------------------------------------------------------------
/** The AABB class implements an axis-aligned bounding box using vl::real precision. */
class VLCORE_EXPORT AABB
{
public:
/** Constructs a null AABB. */
AABB();
/** Constructs an AABB large enough to contain a sphere with the specified \p radius and \p center. */
AABB( const vec3& center, real radius );
/** Constructs an AABB large enough to contain the two specified points and enlarged by the amount specified by \p displace. */
AABB( const vec3& pt1, const vec3& pt2, real displace=0);
/** Sets ths AABB as null, that is, empty. */
void setNull() { mMin = 1; mMax = -1; }
/** Returns true if the AABB is null. */
bool isNull() const { return mMin.x() > mMax.x() || mMin.y() > mMax.y() || mMin.z() > mMax.z(); }
/** Returns true if the AABB contains a single point, that is, if the min and max corners of the AABB are equal. */
bool isPoint() const { return mMin == mMax; }
/** Enlarges the AABB in all directions by \p displace amount.
As a result every edge of the AABB will be \p displace*2 longer. */
void enlarge(real displace);
/** Returns true if an AABB intersects with the given AABB. */
bool intersects(const AABB & bb) const;
/** Clips the position of the given \p p point to be inside an AABB. */
vec3 clip(const vec3& p, bool clipx=true, bool clipy=true, bool clipz=true) const;
/** Returns true if the given point is inside the AABB.
This method allows you to restrict the test to any of the x, y, z axes. */
bool isInside(const vec3& p, bool clipx, bool clipy, bool clipz) const;
/** Returns true if the given point is inside the AABB. */
bool isInside(const vec3& p) const;
/** Returns the width of the AABB computed as max.x - min.x */
real width() const;
/** Returns the height of the AABB computed as max.y - min.y */
real height() const;
/** Returns the depth of the AABB computed as max.z - min.z */
real depth() const;
/** Returns true if two AABB are identical. */
bool operator==(const AABB& aabb) const
{
return mMin == aabb.mMin && mMax == aabb.mMax;
}
/** Returns true if two AABB are not identical. */
bool operator!=(const AABB& aabb) const
{
return !operator==(aabb);
}
/** Returns an AABB which contains the two source AABB. */
AABB operator+(const AABB& aabb) const;
/** Enlarges (if necessary) an AABB so that it contains the given AABB. */
AABB& operator+=(const AABB& other)
{
*this = *this + other;
return *this;
}
/** Returns an AABB which contains the source AABB and the given point. */
AABB operator+(const vec3& p)
{
AABB aabb = *this;
aabb += p;
return aabb;
}
/** Enlarges (if necessary) an AABB to contain the given point. */
const AABB& operator+=(const vec3& p)
{
addPoint(p);
return *this;
}
/** Returns the center of the AABB. */
vec3 center() const;
/** Returns the longest dimension of the AABB. */
real longestSideLength() const
{
real side = width();
if (height() > side)
side = height();
if (depth() > side)
side = depth();
return side;
}
/** Updates the AABB to contain the given point.
The point can represent a sphere if \p radius > 0. */
void addPoint(const vec3& p, real radius);
/** Updates the AABB to contain the given point. */
void addPoint(const vec3& p)
{
if (isNull())
{
mMax = p;
mMin = p;
return;
}
if ( mMax.x() < p.x() ) mMax.x() = p.x();
if ( mMax.y() < p.y() ) mMax.y() = p.y();
if ( mMax.z() < p.z() ) mMax.z() = p.z();
if ( mMin.x() > p.x() ) mMin.x() = p.x();
if ( mMin.y() > p.y() ) mMin.y() = p.y();
if ( mMin.z() > p.z() ) mMin.z() = p.z();
}
/** Transforms an AABB by the given matrix and returns it into the \p out parameter. */
void transformed(AABB& out, const mat4& mat) const
{
out.setNull();
if ( !isNull() )
{
out.addPoint( mat * vec3(minCorner().x(), minCorner().y(), minCorner().z()) );
out.addPoint( mat * vec3(minCorner().x(), maxCorner().y(), minCorner().z()) );
out.addPoint( mat * vec3(maxCorner().x(), maxCorner().y(), minCorner().z()) );
out.addPoint( mat * vec3(maxCorner().x(), minCorner().y(), minCorner().z()) );
out.addPoint( mat * vec3(minCorner().x(), minCorner().y(), maxCorner().z()) );
out.addPoint( mat * vec3(minCorner().x(), maxCorner().y(), maxCorner().z()) );
out.addPoint( mat * vec3(maxCorner().x(), maxCorner().y(), maxCorner().z()) );
out.addPoint( mat * vec3(maxCorner().x(), minCorner().y(), maxCorner().z()) );
}
}
/** Returns the AABB transformed by the given matrix. */
AABB transformed(const mat4& mat) const
{
AABB aabb;
transformed(aabb, mat);
return aabb;
}
/** Returns the corner of the AABB with the minimum x y z coordinates. */
const vec3& minCorner() const { return mMin; }
/** Returns the corner of the AABB with the maximum x y z coordinates. */
const vec3& maxCorner() const { return mMax; }
/** Sets the corner of the AABB with the minimum x y z coordinates. */
void setMinCorner(real x, real y, real z) { mMin.x() = x; mMin.y() = y; mMin.z() = z; }
/** Sets the corner of the AABB with the minimum x y z coordinates. */
void setMinCorner(const vec3& v) { mMin = v; }
/** Sets the corner of the AABB with the maximum x y z coordinates. */
void setMaxCorner(real x, real y, real z) { mMax.x() = x; mMax.y() = y; mMax.z() = z; }
/** Sets the corner of the AABB with the maximum x y z coordinates. */
void setMaxCorner(const vec3& v) { mMax = v; }
/** Returns the volume of the AABB. */
real volume() const { return width() * height() * depth(); }
protected:
vec3 mMin;
vec3 mMax;
};
}
#endif