1// Copyright (C) 2008-2012 NVIDIA Corporation.
2// Copyright (C) 2019 The Qt Company Ltd.
3// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
4
5#ifndef QSSGBOUNDS3_H
6#define QSSGBOUNDS3_H
7
8//
9// W A R N I N G
10// -------------
11//
12// This file is not part of the Qt API. It exists purely as an
13// implementation detail. This header file may change from version to
14// version without notice, or even be removed.
15//
16// We mean it.
17//
18
19#include "qssgutils_p.h"
20#include <QtQuick3DUtils/private/qtquick3dutilsglobal_p.h>
21
22#include <QVector3D>
23#include <QMatrix3x3>
24#include <QMatrix4x4>
25
26#include <limits>
27#include <qnumeric.h>
28
29QT_BEGIN_NAMESPACE
30
31using QSSGBoxPoints = std::array<QVector3D, 8>;
32
33/**
34\brief Class representing 3D range or axis aligned bounding box.
35
36Stored as minimum and maximum extent corners. Alternate representation
37would be center and dimensions.
38May be empty or nonempty. If not empty, minimum <= maximum has to hold.
39*/
40class Q_QUICK3DUTILS_EXPORT QSSGBounds3
41{
42public:
43 /**
44 \brief Default constructor, using empty bounds.
45 */
46 Q_DECL_CONSTEXPR Q_ALWAYS_INLINE QSSGBounds3();
47
48 /**
49 \brief Construct uninitialized.
50 */
51 Q_ALWAYS_INLINE QSSGBounds3(Qt::Initialization);
52
53 /**
54 \brief Construct from two bounding points
55 */
56 Q_DECL_CONSTEXPR Q_ALWAYS_INLINE QSSGBounds3(const QVector3D &minimum, const QVector3D &maximum);
57
58 /**
59 \brief returns the AABB containing v0 and v1.
60 \param v0 first point included in the AABB.
61 \param v1 second point included in the AABB.
62 */
63 static Q_ALWAYS_INLINE QSSGBounds3 boundsOfPoints(const QVector3D &v0, const QVector3D &v1);
64
65 /**
66 \brief returns the AABB from center and extents vectors.
67 \param center Center vector
68 \param extent Extents vector
69 */
70 static Q_ALWAYS_INLINE QSSGBounds3 centerExtents(const QVector3D &center, const QVector3D &extent);
71
72 /**
73 \brief Construct from center, extent, and (not necessarily orthogonal) basis
74 */
75 static Q_ALWAYS_INLINE QSSGBounds3 basisExtent(const QVector3D &center, const QMatrix3x3 &basis, const QVector3D &extent);
76
77 /**
78 \brief gets the transformed bounds of the passed AABB (resulting in a bigger AABB).
79 \param[in] matrix Transform to apply, can contain scaling as well
80 \param[in] bounds The bounds to transform.
81 */
82 static QSSGBounds3 transform(const QMatrix3x3 &matrix, const QSSGBounds3 &bounds);
83
84 /**
85 \brief Sets empty to true
86 */
87 Q_ALWAYS_INLINE void setEmpty();
88
89 /**
90 \brief Sets infinite bounds
91 */
92 Q_ALWAYS_INLINE void setInfinite();
93
94 /**
95 \brief expands the volume to include v
96 \param v Point to expand to.
97 */
98 void include(const QVector3D &v);
99
100 /**
101 \brief expands the volume to include b.
102 \param b Bounds to perform union with.
103 */
104 void include(const QSSGBounds3 &b);
105
106 Q_ALWAYS_INLINE bool isEmpty() const;
107
108 /**
109 \brief indicates whether the intersection of this and b is empty or not.
110 \param b Bounds to test for intersection.
111 */
112 Q_ALWAYS_INLINE bool intersects(const QSSGBounds3 &b) const;
113
114 /**
115 \brief computes the 1D-intersection between two AABBs, on a given axis.
116 \param a the other AABB
117 \param axis the axis (0, 1, 2)
118 */
119 Q_ALWAYS_INLINE bool intersects1D(const QSSGBounds3 &a, quint32 axis) const;
120
121 /**
122 \brief indicates if these bounds contain v.
123 \param v Point to test against bounds.
124 */
125 Q_ALWAYS_INLINE bool contains(const QVector3D &v) const;
126
127 /**
128 \brief checks a box is inside another box.
129 \param box the other AABB
130 */
131 Q_ALWAYS_INLINE bool isInside(const QSSGBounds3 &box) const;
132
133 /**
134 \brief returns the center of this axis aligned box.
135 */
136 Q_ALWAYS_INLINE QVector3D center() const;
137
138 /**
139 \brief get component of the box's center along a given axis
140 */
141 Q_ALWAYS_INLINE float center(quint32 axis) const;
142
143 /**
144 \brief get component of the box's extents along a given axis
145 */
146 Q_ALWAYS_INLINE float extents(quint32 axis) const;
147
148 /**
149 \brief returns the dimensions (width/height/depth) of this axis aligned box.
150 */
151 Q_ALWAYS_INLINE QVector3D dimensions() const;
152
153 /**
154 \brief returns the extents, which are half of the width/height/depth.
155 */
156 Q_ALWAYS_INLINE QVector3D extents() const;
157
158 /**
159 \brief scales the AABB.
160 \param scale Factor to scale AABB by.
161 */
162 Q_ALWAYS_INLINE void scale(float scale);
163
164 /**
165 fattens the AABB in all 3 dimensions by the given distance.
166 */
167 Q_ALWAYS_INLINE void fatten(double distance);
168
169 /**
170 checks that the AABB values are not NaN
171 */
172
173 bool isFinite() const;
174
175 /**
176 Use when the bounds is already verified to be non-empty!!!
177 */
178 Q_ALWAYS_INLINE QSSGBoxPoints toQSSGBoxPointsNoEmptyCheck() const;
179 /**
180 Verifies that the bounds is non-empty.
181 */
182 Q_ALWAYS_INLINE QSSGBoxPoints toQSSGBoxPoints() const;
183
184 void transform(const QMatrix4x4 &inMatrix);
185
186 /**
187 Returns the support point in a given direction
188 */
189 QVector3D getSupport(const QVector3D &direction) const;
190
191 QVector3D minimum;
192 QVector3D maximum;
193};
194
195Q_DECL_CONSTEXPR Q_ALWAYS_INLINE QSSGBounds3::QSSGBounds3()
196 : minimum(QVector3D(std::numeric_limits<float>::max(), std::numeric_limits<float>::max(), std::numeric_limits<float>::max()))
197 , maximum(-std::numeric_limits<float>::max(), -std::numeric_limits<float>::max(), -std::numeric_limits<float>::max())
198{
199}
200
201Q_ALWAYS_INLINE QSSGBounds3::QSSGBounds3(Qt::Initialization)
202 : minimum(Qt::Uninitialized), maximum(Qt::Uninitialized) { }
203
204Q_DECL_CONSTEXPR Q_ALWAYS_INLINE QSSGBounds3::QSSGBounds3(const QVector3D &_minimum, const QVector3D &_maximum)
205 : minimum(_minimum), maximum(_maximum)
206{
207}
208
209Q_ALWAYS_INLINE QSSGBounds3 QSSGBounds3::centerExtents(const QVector3D &center, const QVector3D &extent)
210{
211 return QSSGBounds3(center - extent, center + extent);
212}
213
214Q_ALWAYS_INLINE void QSSGBounds3::setEmpty()
215{
216 constexpr float maxFloat = std::numeric_limits<float>::max();
217 minimum = QVector3D(maxFloat, maxFloat, maxFloat);
218 maximum = QVector3D(-maxFloat, -maxFloat, -maxFloat);
219}
220
221Q_ALWAYS_INLINE void QSSGBounds3::setInfinite()
222{
223 constexpr float maxFloat = std::numeric_limits<float>::max();
224 minimum = QVector3D(-maxFloat, -maxFloat, -maxFloat);
225 maximum = QVector3D(maxFloat, maxFloat, maxFloat);
226}
227
228Q_ALWAYS_INLINE bool QSSGBounds3::isEmpty() const
229{
230 Q_ASSERT(isFinite());
231 // Consistency condition for (Min, Max) boxes: minimum < maximum
232 return minimum.x() > maximum.x() || minimum.y() > maximum.y() || minimum.z() > maximum.z();
233}
234
235Q_ALWAYS_INLINE bool QSSGBounds3::intersects(const QSSGBounds3 &b) const
236{
237 Q_ASSERT(isFinite() && b.isFinite());
238 return !(b.minimum.x() > maximum.x() || minimum.x() > b.maximum.x() || b.minimum.y() > maximum.y()
239 || minimum.y() > b.maximum.y() || b.minimum.z() > maximum.z() || minimum.z() > b.maximum.z());
240}
241
242Q_ALWAYS_INLINE bool QSSGBounds3::intersects1D(const QSSGBounds3 &a, quint32 axis) const
243{
244 Q_ASSERT(isFinite() && a.isFinite());
245 return maximum[int(axis)] >= a.minimum[axis] && a.maximum[axis] >= minimum[axis];
246}
247
248Q_ALWAYS_INLINE bool QSSGBounds3::contains(const QVector3D &v) const
249{
250 Q_ASSERT(isFinite());
251
252 return !(v.x() < minimum.x() || v.x() > maximum.x() || v.y() < minimum.y() || v.y() > maximum.y()
253 || v.z() < minimum.z() || v.z() > maximum.z());
254}
255
256Q_ALWAYS_INLINE bool QSSGBounds3::isInside(const QSSGBounds3 &box) const
257{
258 Q_ASSERT(isFinite() && box.isFinite());
259 if (box.minimum.x() > minimum.x())
260 return false;
261 if (box.minimum.y() > minimum.y())
262 return false;
263 if (box.minimum.z() > minimum.z())
264 return false;
265 if (box.maximum.x() < maximum.x())
266 return false;
267 if (box.maximum.y() < maximum.y())
268 return false;
269 if (box.maximum.z() < maximum.z())
270 return false;
271 return true;
272}
273
274Q_ALWAYS_INLINE QVector3D QSSGBounds3::center() const
275{
276 Q_ASSERT(isFinite());
277 return (minimum + maximum) * double(0.5);
278}
279
280Q_ALWAYS_INLINE float QSSGBounds3::center(quint32 axis) const
281{
282 Q_ASSERT(isFinite());
283 return (minimum[int(axis)] + maximum[int(axis)]) * 0.5f;
284}
285
286Q_ALWAYS_INLINE float QSSGBounds3::extents(quint32 axis) const
287{
288 Q_ASSERT(isFinite());
289 return (maximum[int(axis)] - minimum[int(axis)]) * 0.5f;
290}
291
292Q_ALWAYS_INLINE QVector3D QSSGBounds3::dimensions() const
293{
294 Q_ASSERT(isFinite());
295 return maximum - minimum;
296}
297
298Q_ALWAYS_INLINE QVector3D QSSGBounds3::extents() const
299{
300 Q_ASSERT(isFinite());
301 return dimensions() * double(0.5);
302}
303
304Q_ALWAYS_INLINE void QSSGBounds3::scale(float scale)
305{
306 Q_ASSERT(isFinite());
307 *this = centerExtents(center: center(), extent: extents() * scale);
308}
309
310Q_ALWAYS_INLINE void QSSGBounds3::fatten(double distance)
311{
312 Q_ASSERT(isFinite());
313 minimum -= QVector3D(float(distance), float(distance), float(distance));
314 maximum += QVector3D(float(distance), float(distance), float(distance));
315}
316
317Q_ALWAYS_INLINE QSSGBoxPoints QSSGBounds3::toQSSGBoxPointsNoEmptyCheck() const
318{
319 return { // Min corner of box
320 QVector3D(minimum[0], minimum[1], minimum[2]),
321 QVector3D(maximum[0], minimum[1], minimum[2]),
322 QVector3D(minimum[0], maximum[1], minimum[2]),
323 QVector3D(minimum[0], minimum[1], maximum[2]),
324 // Max corner of box
325 QVector3D(maximum[0], maximum[1], maximum[2]),
326 QVector3D(minimum[0], maximum[1], maximum[2]),
327 QVector3D(maximum[0], minimum[1], maximum[2]),
328 QVector3D(maximum[0], maximum[1], minimum[2])
329 };
330}
331
332Q_ALWAYS_INLINE QSSGBoxPoints QSSGBounds3::toQSSGBoxPoints() const
333{
334 if (isEmpty())
335 return { QVector3D(0, 0, 0), QVector3D(0, 0, 0), QVector3D(0, 0, 0), QVector3D(0, 0, 0),
336 QVector3D(0, 0, 0), QVector3D(0, 0, 0), QVector3D(0, 0, 0), QVector3D(0, 0, 0) };
337 return toQSSGBoxPointsNoEmptyCheck();
338}
339
340QT_END_NAMESPACE
341
342#endif // QSSGBOUNDS3_H
343

source code of qtquick3d/src/utils/qssgbounds3_p.h