diff options
Diffstat (limited to 'src/Runtime/Source/foundation/Qt3DSBounds3.h')
-rw-r--r-- | src/Runtime/Source/foundation/Qt3DSBounds3.h | 443 |
1 files changed, 443 insertions, 0 deletions
diff --git a/src/Runtime/Source/foundation/Qt3DSBounds3.h b/src/Runtime/Source/foundation/Qt3DSBounds3.h new file mode 100644 index 00000000..fda4a6d4 --- /dev/null +++ b/src/Runtime/Source/foundation/Qt3DSBounds3.h @@ -0,0 +1,443 @@ +/**************************************************************************** +** +** Copyright (C) 2008-2012 NVIDIA Corporation. +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt 3D Studio. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QT3DS_FOUNDATION_QT3DS_BOUNDS3_H +#define QT3DS_FOUNDATION_QT3DS_BOUNDS3_H + +/** \addtogroup foundation +@{ +*/ + +#include "foundation/Qt3DSTransform.h" +#include "foundation/Qt3DSMat33.h" +#include "foundation/Qt3DSMat44.h" + +#ifndef QT3DS_DOXYGEN +namespace qt3ds { +#endif + +typedef QT3DSVec3 TNVBounds2BoxPoints[8]; + +/** +\brief Class representing 3D range or axis aligned bounding box. + +Stored as minimum and maximum extent corners. Alternate representation +would be center and dimensions. +May be empty or nonempty. If not empty, minimum <= maximum has to hold. +*/ +class NVBounds3 +{ +public: + /** + \brief Default constructor, not performing any initialization for performance reason. + \remark Use empty() function below to construct empty bounds. + */ + QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE NVBounds3() {} + + /** + \brief Construct from two bounding points + */ + QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE NVBounds3(const QT3DSVec3 &minimum, const QT3DSVec3 &maximum); + + /** + \brief Return empty bounds. + */ + static QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE NVBounds3 empty(); + + /** + \brief returns the AABB containing v0 and v1. + \param v0 first point included in the AABB. + \param v1 second point included in the AABB. + */ + static QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE NVBounds3 boundsOfPoints(const QT3DSVec3 &v0, + const QT3DSVec3 &v1); + + /** + \brief returns the AABB from center and extents vectors. + \param center Center vector + \param extent Extents vector + */ + static QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE NVBounds3 centerExtents(const QT3DSVec3 ¢er, + const QT3DSVec3 &extent); + + /** + \brief Construct from center, extent, and (not necessarily orthogonal) basis + */ + static QT3DS_CUDA_CALLABLE QT3DS_INLINE NVBounds3 basisExtent(const QT3DSVec3 ¢er, + const QT3DSMat33 &basis, + const QT3DSVec3 &extent); + + /** + \brief Construct from pose and extent + */ + static QT3DS_CUDA_CALLABLE QT3DS_INLINE NVBounds3 poseExtent(const NVTransform &pose, + const QT3DSVec3 &extent); + + /** + \brief gets the transformed bounds of the passed AABB (resulting in a bigger AABB). + \param[in] matrix Transform to apply, can contain scaling as well + \param[in] bounds The bounds to transform. + */ + static QT3DS_CUDA_CALLABLE QT3DS_INLINE NVBounds3 transform(const QT3DSMat33 &matrix, + const NVBounds3 &bounds); + + /** + \brief gets the transformed bounds of the passed AABB (resulting in a bigger AABB). + \param[in] transform Transform to apply, can contain scaling as well + \param[in] bounds The bounds to transform. + */ + static QT3DS_CUDA_CALLABLE QT3DS_INLINE NVBounds3 transform(const NVTransform &transform, + const NVBounds3 &bounds); + + /** + \brief Sets empty to true + */ + QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE void setEmpty(); + + /** + \brief Sets infinite bounds + */ + QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE void setInfinite(); + + /** + \brief expands the volume to include v + \param v Point to expand to. + */ + QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE void include(const QT3DSVec3 &v); + + /** + \brief expands the volume to include b. + \param b Bounds to perform union with. + */ + QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE void include(const NVBounds3 &b); + + QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE bool isEmpty() const; + + /** + \brief indicates whether the intersection of this and b is empty or not. + \param b Bounds to test for intersection. + */ + QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE bool intersects(const NVBounds3 &b) const; + + /** + \brief computes the 1D-intersection between two AABBs, on a given axis. + \param a the other AABB + \param axis the axis (0, 1, 2) + */ + QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE bool intersects1D(const NVBounds3 &a, QT3DSU32 axis) const; + + /** + \brief indicates if these bounds contain v. + \param v Point to test against bounds. + */ + QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE bool contains(const QT3DSVec3 &v) const; + + /** + \brief checks a box is inside another box. + \param box the other AABB + */ + QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE bool isInside(const NVBounds3 &box) const; + + /** + \brief returns the center of this axis aligned box. + */ + QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE QT3DSVec3 getCenter() const; + + /** + \brief get component of the box's center along a given axis + */ + QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE float getCenter(QT3DSU32 axis) const; + + /** + \brief get component of the box's extents along a given axis + */ + QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE float getExtents(QT3DSU32 axis) const; + + /** + \brief returns the dimensions (width/height/depth) of this axis aligned box. + */ + QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE QT3DSVec3 getDimensions() const; + + /** + \brief returns the extents, which are half of the width/height/depth. + */ + QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE QT3DSVec3 getExtents() const; + + /** + \brief scales the AABB. + \param scale Factor to scale AABB by. + */ + QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE void scale(QT3DSF32 scale); + + /** + fattens the AABB in all 3 dimensions by the given distance. + */ + QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE void fatten(NVReal distance); + + /** + checks that the AABB values are not NaN + */ + + QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE bool isFinite() const; + + QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE void expand(TNVBounds2BoxPoints &outPoints) const; + + QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE void transform(const QT3DSMat44 &inMatrix); + + QT3DSVec3 minimum, maximum; +}; + +QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE NVBounds3::NVBounds3(const QT3DSVec3 &minimum, const QT3DSVec3 &maximum) + : minimum(minimum) + , maximum(maximum) +{ +} + +QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE NVBounds3 NVBounds3::empty() +{ + return NVBounds3(QT3DSVec3(QT3DS_MAX_REAL), QT3DSVec3(-QT3DS_MAX_REAL)); +} + +QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE bool NVBounds3::isFinite() const +{ + return minimum.isFinite() && maximum.isFinite(); +} + +QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE NVBounds3 NVBounds3::boundsOfPoints(const QT3DSVec3 &v0, + const QT3DSVec3 &v1) +{ + return NVBounds3(v0.minimum(v1), v0.maximum(v1)); +} + +QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE NVBounds3 NVBounds3::centerExtents(const QT3DSVec3 ¢er, + const QT3DSVec3 &extent) +{ + return NVBounds3(center - extent, center + extent); +} + +QT3DS_CUDA_CALLABLE QT3DS_INLINE NVBounds3 NVBounds3::basisExtent(const QT3DSVec3 ¢er, + const QT3DSMat33 &basis, + const QT3DSVec3 &extent) +{ + // extended basis vectors + QT3DSVec3 c0 = basis.column0 * extent.x; + QT3DSVec3 c1 = basis.column1 * extent.y; + QT3DSVec3 c2 = basis.column2 * extent.z; + + QT3DSVec3 w; + // find combination of base vectors that produces max. distance for each component = sum of + // abs() + w.x = NVAbs(c0.x) + NVAbs(c1.x) + NVAbs(c2.x); + w.y = NVAbs(c0.y) + NVAbs(c1.y) + NVAbs(c2.y); + w.z = NVAbs(c0.z) + NVAbs(c1.z) + NVAbs(c2.z); + + return NVBounds3(center - w, center + w); +} + +QT3DS_CUDA_CALLABLE QT3DS_INLINE NVBounds3 NVBounds3::poseExtent(const NVTransform &pose, + const QT3DSVec3 &extent) +{ + return basisExtent(pose.p, QT3DSMat33(pose.q), extent); +} + +QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE void NVBounds3::setEmpty() +{ + minimum = QT3DSVec3(QT3DS_MAX_REAL); + maximum = QT3DSVec3(-QT3DS_MAX_REAL); +} + +QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE void NVBounds3::setInfinite() +{ + minimum = QT3DSVec3(-QT3DS_MAX_REAL); + maximum = QT3DSVec3(QT3DS_MAX_REAL); +} + +QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE void NVBounds3::include(const QT3DSVec3 &v) +{ + QT3DS_ASSERT(isFinite()); + minimum = minimum.minimum(v); + maximum = maximum.maximum(v); +} + +QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE void NVBounds3::include(const NVBounds3 &b) +{ + QT3DS_ASSERT(isFinite()); + minimum = minimum.minimum(b.minimum); + maximum = maximum.maximum(b.maximum); +} + +QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE bool NVBounds3::isEmpty() const +{ + QT3DS_ASSERT(isFinite()); + // Consistency condition for (Min, Max) boxes: minimum < maximum + return minimum.x > maximum.x || minimum.y > maximum.y || minimum.z > maximum.z; +} + +QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE bool NVBounds3::intersects(const NVBounds3 &b) const +{ + QT3DS_ASSERT(isFinite() && b.isFinite()); + 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); +} + +QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE bool NVBounds3::intersects1D(const NVBounds3 &a, QT3DSU32 axis) const +{ + QT3DS_ASSERT(isFinite() && a.isFinite()); + return maximum[axis] >= a.minimum[axis] && a.maximum[axis] >= minimum[axis]; +} + +QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE bool NVBounds3::contains(const QT3DSVec3 &v) const +{ + QT3DS_ASSERT(isFinite()); + + 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); +} + +QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE bool NVBounds3::isInside(const NVBounds3 &box) const +{ + QT3DS_ASSERT(isFinite() && box.isFinite()); + 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; +} + +QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE QT3DSVec3 NVBounds3::getCenter() const +{ + QT3DS_ASSERT(isFinite()); + return (minimum + maximum) * NVReal(0.5); +} + +QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE float NVBounds3::getCenter(QT3DSU32 axis) const +{ + QT3DS_ASSERT(isFinite()); + return (minimum[axis] + maximum[axis]) * NVReal(0.5); +} + +QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE float NVBounds3::getExtents(QT3DSU32 axis) const +{ + QT3DS_ASSERT(isFinite()); + return (maximum[axis] - minimum[axis]) * NVReal(0.5); +} + +QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE QT3DSVec3 NVBounds3::getDimensions() const +{ + QT3DS_ASSERT(isFinite()); + return maximum - minimum; +} + +QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE QT3DSVec3 NVBounds3::getExtents() const +{ + QT3DS_ASSERT(isFinite()); + return getDimensions() * NVReal(0.5); +} + +QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE void NVBounds3::scale(QT3DSF32 scale) +{ + QT3DS_ASSERT(isFinite()); + *this = centerExtents(getCenter(), getExtents() * scale); +} + +QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE void NVBounds3::fatten(NVReal distance) +{ + QT3DS_ASSERT(isFinite()); + minimum.x -= distance; + minimum.y -= distance; + minimum.z -= distance; + + maximum.x += distance; + maximum.y += distance; + maximum.z += distance; +} + +QT3DS_CUDA_CALLABLE QT3DS_INLINE NVBounds3 NVBounds3::transform(const QT3DSMat33 &matrix, + const NVBounds3 &bounds) +{ + QT3DS_ASSERT(bounds.isFinite()); + return bounds.isEmpty() ? bounds : NVBounds3::basisExtent(matrix * bounds.getCenter(), matrix, + bounds.getExtents()); +} + +QT3DS_CUDA_CALLABLE QT3DS_INLINE NVBounds3 NVBounds3::transform(const NVTransform &transform, + const NVBounds3 &bounds) +{ + QT3DS_ASSERT(bounds.isFinite()); + return bounds.isEmpty() ? bounds + : NVBounds3::basisExtent(transform.transform(bounds.getCenter()), + QT3DSMat33(transform.q), bounds.getExtents()); +} + +QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE void NVBounds3::expand(TNVBounds2BoxPoints &outPoints) const +{ + if (isEmpty()) { + for (QT3DSU32 idx = 0; idx < 8; ++idx) + outPoints[idx] = QT3DSVec3(0, 0, 0); + } else { + // Min corner of box + outPoints[0] = QT3DSVec3(minimum[0], minimum[1], minimum[2]); + outPoints[1] = QT3DSVec3(maximum[0], minimum[1], minimum[2]); + outPoints[2] = QT3DSVec3(minimum[0], maximum[1], minimum[2]); + outPoints[3] = QT3DSVec3(minimum[0], minimum[1], maximum[2]); + + // Max corner of box + outPoints[4] = QT3DSVec3(maximum[0], maximum[1], maximum[2]); + outPoints[5] = QT3DSVec3(minimum[0], maximum[1], maximum[2]); + outPoints[6] = QT3DSVec3(maximum[0], minimum[1], maximum[2]); + outPoints[7] = QT3DSVec3(maximum[0], maximum[1], minimum[2]); + } +} + +QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE void NVBounds3::transform(const QT3DSMat44 &inMatrix) +{ + if (!isEmpty()) { + TNVBounds2BoxPoints thePoints; + expand(thePoints); + setEmpty(); + for (QT3DSU32 idx = 0; idx < 8; ++idx) + include(inMatrix.transform(thePoints[idx])); + } +} + +#ifndef QT3DS_DOXYGEN +} // namespace qt3ds +#endif + +/** @} */ +#endif // QT3DS_FOUNDATION_QT3DS_BOUNDS3_H |