include/foundation/PxBounds3.h

File members: include/foundation/PxBounds3.h

// 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.
//  * Neither the name of NVIDIA CORPORATION nor the names of its
//    contributors may be used to endorse or promote products derived
//    from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''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 OWNER 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.
//
// Copyright (c) 2008-2024 NVIDIA Corporation. All rights reserved.
// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.

#ifndef PX_BOUNDS3_H
#define PX_BOUNDS3_H

#include "foundation/PxTransform.h"
#include "foundation/PxMat33.h"

#if !PX_DOXYGEN
namespace physx
{
#endif

// maximum extents defined such that floating point exceptions are avoided for standard use cases
#define PX_MAX_BOUNDS_EXTENTS (PX_MAX_REAL * 0.25f)

class PxBounds3
{
  public:
    PX_CUDA_CALLABLE PX_FORCE_INLINE PxBounds3()
    {
    }

    PX_CUDA_CALLABLE PX_FORCE_INLINE PxBounds3(const PxVec3& minimum, const PxVec3& maximum);

    PX_CUDA_CALLABLE PX_FORCE_INLINE void operator=(const PxBounds3& other)
    {
        minimum = other.minimum;
        maximum = other.maximum;
    }

    PX_CUDA_CALLABLE PX_FORCE_INLINE PxBounds3(const PxBounds3& other)
    {
        minimum = other.minimum;
        maximum = other.maximum;
    }

    static PX_CUDA_CALLABLE PX_FORCE_INLINE PxBounds3 empty();

    static PX_CUDA_CALLABLE PX_FORCE_INLINE PxBounds3 boundsOfPoints(const PxVec3& v0, const PxVec3& v1);

    static PX_CUDA_CALLABLE PX_FORCE_INLINE PxBounds3 centerExtents(const PxVec3& center, const PxVec3& extent);

    static PX_CUDA_CALLABLE PX_INLINE PxBounds3 basisExtent(const PxVec3& center, const PxMat33& basis, const PxVec3& extent);

    static PX_CUDA_CALLABLE PX_INLINE PxBounds3 poseExtent(const PxTransform& pose, const PxVec3& extent);

    static PX_CUDA_CALLABLE PX_INLINE PxBounds3 transformSafe(const PxMat33& matrix, const PxBounds3& bounds);

    static PX_CUDA_CALLABLE PX_INLINE PxBounds3 transformFast(const PxMat33& matrix, const PxBounds3& bounds);

    static PX_CUDA_CALLABLE PX_INLINE PxBounds3 transformSafe(const PxTransform& transform, const PxBounds3& bounds);

    static PX_CUDA_CALLABLE PX_INLINE PxBounds3 transformFast(const PxTransform& transform, const PxBounds3& bounds);

    PX_CUDA_CALLABLE PX_FORCE_INLINE void setEmpty();

    PX_CUDA_CALLABLE PX_FORCE_INLINE void setMaximal();

    PX_CUDA_CALLABLE PX_FORCE_INLINE void include(const PxVec3& v);

    PX_CUDA_CALLABLE PX_FORCE_INLINE void include(const PxBounds3& b);

    PX_CUDA_CALLABLE PX_FORCE_INLINE bool isEmpty() const;

    PX_CUDA_CALLABLE PX_FORCE_INLINE bool intersects(const PxBounds3& b) const;

    PX_CUDA_CALLABLE PX_FORCE_INLINE bool intersects1D(const PxBounds3& a, uint32_t axis) const;

    PX_CUDA_CALLABLE PX_FORCE_INLINE bool contains(const PxVec3& v) const;

    PX_CUDA_CALLABLE PX_FORCE_INLINE bool isInside(const PxBounds3& box) const;

    PX_CUDA_CALLABLE PX_FORCE_INLINE PxVec3 getCenter() const;

    PX_CUDA_CALLABLE PX_FORCE_INLINE float getCenter(uint32_t axis) const;

    PX_CUDA_CALLABLE PX_FORCE_INLINE float getExtents(uint32_t axis) const;

    PX_CUDA_CALLABLE PX_FORCE_INLINE PxVec3 getDimensions() const;

    PX_CUDA_CALLABLE PX_FORCE_INLINE PxVec3 getExtents() const;

    PX_CUDA_CALLABLE PX_FORCE_INLINE void scaleSafe(float scale);

    PX_CUDA_CALLABLE PX_FORCE_INLINE void scaleFast(float scale);

    PX_CUDA_CALLABLE PX_FORCE_INLINE void fattenSafe(float distance);

    PX_CUDA_CALLABLE PX_FORCE_INLINE void fattenFast(float distance);

    PX_CUDA_CALLABLE PX_FORCE_INLINE bool isFinite() const;

    PX_CUDA_CALLABLE PX_FORCE_INLINE bool isValid() const;

    PX_CUDA_CALLABLE PX_FORCE_INLINE PxVec3 closestPoint(const PxVec3& p) const;

    PxVec3 minimum, maximum;
};

PX_CUDA_CALLABLE PX_FORCE_INLINE PxBounds3::PxBounds3(const PxVec3& minimum_, const PxVec3& maximum_)
: minimum(minimum_), maximum(maximum_)
{
}

PX_CUDA_CALLABLE PX_FORCE_INLINE PxBounds3 PxBounds3::empty()
{
    return PxBounds3(PxVec3(PX_MAX_BOUNDS_EXTENTS), PxVec3(-PX_MAX_BOUNDS_EXTENTS));
}

PX_CUDA_CALLABLE PX_FORCE_INLINE bool PxBounds3::isFinite() const
{
    return minimum.isFinite() && maximum.isFinite();
}

PX_CUDA_CALLABLE PX_FORCE_INLINE PxBounds3 PxBounds3::boundsOfPoints(const PxVec3& v0, const PxVec3& v1)
{
    return PxBounds3(v0.minimum(v1), v0.maximum(v1));
}

PX_CUDA_CALLABLE PX_FORCE_INLINE PxBounds3 PxBounds3::centerExtents(const PxVec3& center, const PxVec3& extent)
{
    return PxBounds3(center - extent, center + extent);
}

PX_CUDA_CALLABLE PX_INLINE PxBounds3
PxBounds3::basisExtent(const PxVec3& center, const PxMat33& basis, const PxVec3& extent)
{
    // extended basis vectors
    const PxVec3 c0 = basis.column0 * extent.x;
    const PxVec3 c1 = basis.column1 * extent.y;
    const PxVec3 c2 = basis.column2 * extent.z;

    // find combination of base vectors that produces max. distance for each component = sum of abs()
    const PxVec3 w( PxAbs(c0.x) + PxAbs(c1.x) + PxAbs(c2.x),
                    PxAbs(c0.y) + PxAbs(c1.y) + PxAbs(c2.y),
                    PxAbs(c0.z) + PxAbs(c1.z) + PxAbs(c2.z));

    return PxBounds3(center - w, center + w);
}

PX_CUDA_CALLABLE PX_INLINE PxBounds3 PxBounds3::poseExtent(const PxTransform& pose, const PxVec3& extent)
{
    return basisExtent(pose.p, PxMat33(pose.q), extent);
}

PX_CUDA_CALLABLE PX_FORCE_INLINE void PxBounds3::setEmpty()
{
    minimum = PxVec3(PX_MAX_BOUNDS_EXTENTS);
    maximum = PxVec3(-PX_MAX_BOUNDS_EXTENTS);
}

PX_CUDA_CALLABLE PX_FORCE_INLINE void PxBounds3::setMaximal()
{
    minimum = PxVec3(-PX_MAX_BOUNDS_EXTENTS);
    maximum = PxVec3(PX_MAX_BOUNDS_EXTENTS);
}

PX_CUDA_CALLABLE PX_FORCE_INLINE void PxBounds3::include(const PxVec3& v)
{
    PX_ASSERT(isValid());
    minimum = minimum.minimum(v);
    maximum = maximum.maximum(v);
}

PX_CUDA_CALLABLE PX_FORCE_INLINE void PxBounds3::include(const PxBounds3& b)
{
    PX_ASSERT(isValid());
    minimum = minimum.minimum(b.minimum);
    maximum = maximum.maximum(b.maximum);
}

PX_CUDA_CALLABLE PX_FORCE_INLINE bool PxBounds3::isEmpty() const
{
    PX_ASSERT(isValid());
    return minimum.x > maximum.x;
}

PX_CUDA_CALLABLE PX_FORCE_INLINE bool PxBounds3::intersects(const PxBounds3& b) const
{
    PX_ASSERT(isValid() && b.isValid());
    return !(b.minimum.x > maximum.x || minimum.x > b.maximum.x || b.minimum.y > maximum.y || minimum.y > b.maximum.y ||
             b.minimum.z > maximum.z || minimum.z > b.maximum.z);
}

PX_CUDA_CALLABLE PX_FORCE_INLINE bool PxBounds3::intersects1D(const PxBounds3& a, uint32_t axis) const
{
    PX_ASSERT(isValid() && a.isValid());
    return maximum[axis] >= a.minimum[axis] && a.maximum[axis] >= minimum[axis];
}

PX_CUDA_CALLABLE PX_FORCE_INLINE bool PxBounds3::contains(const PxVec3& v) const
{
    PX_ASSERT(isValid());

    return !(v.x < minimum.x || v.x > maximum.x || v.y < minimum.y || v.y > maximum.y || v.z < minimum.z ||
             v.z > maximum.z);
}

PX_CUDA_CALLABLE PX_FORCE_INLINE bool PxBounds3::isInside(const PxBounds3& box) const
{
    PX_ASSERT(isValid() && box.isValid());
    if(box.minimum.x > minimum.x)
        return false;
    if(box.minimum.y > minimum.y)
        return false;
    if(box.minimum.z > minimum.z)
        return false;
    if(box.maximum.x < maximum.x)
        return false;
    if(box.maximum.y < maximum.y)
        return false;
    if(box.maximum.z < maximum.z)
        return false;
    return true;
}

PX_CUDA_CALLABLE PX_FORCE_INLINE PxVec3 PxBounds3::getCenter() const
{
    PX_ASSERT(isValid());
    return (minimum + maximum) * 0.5f;
}

PX_CUDA_CALLABLE PX_FORCE_INLINE float PxBounds3::getCenter(uint32_t axis) const
{
    PX_ASSERT(isValid());
    return (minimum[axis] + maximum[axis]) * 0.5f;
}

PX_CUDA_CALLABLE PX_FORCE_INLINE float PxBounds3::getExtents(uint32_t axis) const
{
    PX_ASSERT(isValid());
    return (maximum[axis] - minimum[axis]) * 0.5f;
}

PX_CUDA_CALLABLE PX_FORCE_INLINE PxVec3 PxBounds3::getDimensions() const
{
    PX_ASSERT(isValid());
    return maximum - minimum;
}

PX_CUDA_CALLABLE PX_FORCE_INLINE PxVec3 PxBounds3::getExtents() const
{
    PX_ASSERT(isValid());
    return getDimensions() * 0.5f;
}

PX_CUDA_CALLABLE PX_FORCE_INLINE void PxBounds3::scaleSafe(float scale)
{
    PX_ASSERT(isValid());
    if(!isEmpty())
        scaleFast(scale);
}

PX_CUDA_CALLABLE PX_FORCE_INLINE void PxBounds3::scaleFast(float scale)
{
    PX_ASSERT(isValid());
    *this = centerExtents(getCenter(), getExtents() * scale);
}

PX_CUDA_CALLABLE PX_FORCE_INLINE void PxBounds3::fattenSafe(float distance)
{
    PX_ASSERT(isValid());
    if(!isEmpty())
        fattenFast(distance);
}

PX_CUDA_CALLABLE PX_FORCE_INLINE void PxBounds3::fattenFast(float distance)
{
    PX_ASSERT(isValid());
    minimum.x -= distance;
    minimum.y -= distance;
    minimum.z -= distance;

    maximum.x += distance;
    maximum.y += distance;
    maximum.z += distance;
}

PX_CUDA_CALLABLE PX_INLINE PxBounds3 PxBounds3::transformSafe(const PxMat33& matrix, const PxBounds3& bounds)
{
    PX_ASSERT(bounds.isValid());
    return !bounds.isEmpty() ? transformFast(matrix, bounds) : bounds;
}

PX_CUDA_CALLABLE PX_INLINE PxBounds3 PxBounds3::transformFast(const PxMat33& matrix, const PxBounds3& bounds)
{
    PX_ASSERT(bounds.isValid());
    return PxBounds3::basisExtent(matrix * bounds.getCenter(), matrix, bounds.getExtents());
}

PX_CUDA_CALLABLE PX_INLINE PxBounds3 PxBounds3::transformSafe(const PxTransform& transform, const PxBounds3& bounds)
{
    PX_ASSERT(bounds.isValid());
    return !bounds.isEmpty() ? transformFast(transform, bounds) : bounds;
}

PX_CUDA_CALLABLE PX_INLINE PxBounds3 PxBounds3::transformFast(const PxTransform& transform, const PxBounds3& bounds)
{
    PX_ASSERT(bounds.isValid());
    return PxBounds3::basisExtent(transform.transform(bounds.getCenter()), PxMat33(transform.q), bounds.getExtents());
}

PX_CUDA_CALLABLE PX_FORCE_INLINE bool PxBounds3::isValid() const
{
    return (isFinite() && (((minimum.x <= maximum.x) && (minimum.y <= maximum.y) && (minimum.z <= maximum.z)) ||
                           ((minimum.x == PX_MAX_BOUNDS_EXTENTS) && (minimum.y == PX_MAX_BOUNDS_EXTENTS) &&
                            (minimum.z == PX_MAX_BOUNDS_EXTENTS) && (maximum.x == -PX_MAX_BOUNDS_EXTENTS) &&
                            (maximum.y == -PX_MAX_BOUNDS_EXTENTS) && (maximum.z == -PX_MAX_BOUNDS_EXTENTS))));
}

PX_CUDA_CALLABLE PX_FORCE_INLINE PxVec3 PxBounds3::closestPoint(const PxVec3& p) const
{
    return minimum.maximum(maximum.minimum(p));
}

#if !PX_DOXYGEN
} // namespace physx
#endif

#endif