1// Copyright (C) 2020 Klaralvdalens Datakonsult AB (KDAB).
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include "qboundingvolume.h"
5#include "qboundingvolume_p.h"
6#include <Qt3DCore/private/corelogging_p.h>
7#include <Qt3DCore/private/calcboundingvolumejob_p.h>
8
9QT_BEGIN_NAMESPACE
10
11namespace Qt3DCore {
12
13bool operator<(const QVector3D &a, const QVector3D &b) {
14 return a.x() < b.x() && a.y() < b.y() && a.z() < b.z();
15}
16
17QBoundingVolumePrivate::QBoundingVolumePrivate()
18 : QComponentPrivate()
19 , m_view(nullptr)
20 , m_implicitRadius(0.0f)
21 , m_implicitPointsValid(false)
22 , m_explicitPointsValid(false)
23 , m_primaryProvider(true)
24{
25}
26
27void QBoundingVolumePrivate::setImplicitBounds(const QVector3D &minPoint, const QVector3D &maxPoint,
28 const QVector3D &center, float radius)
29{
30 Q_Q(QBoundingVolume);
31
32 if (!minPoint.isNull() && !maxPoint.isNull() && minPoint < maxPoint) {
33 if (m_implicitMinPoint != minPoint) {
34 m_implicitMinPoint = minPoint;
35 emit q->implicitMinPointChanged(implicitMinPoint: m_implicitMinPoint);
36 }
37 if (m_implicitMaxPoint != maxPoint) {
38 m_implicitMaxPoint = maxPoint;
39 emit q->implicitMaxPointChanged(implicitMaxPoint: m_implicitMaxPoint);
40 }
41 m_implicitCenter = center;
42 m_implicitRadius = radius;
43 if (!m_implicitPointsValid) {
44 m_implicitPointsValid = true;
45 emit q->implicitPointsValidChanged(implicitPointsValid: m_implicitPointsValid);
46 }
47 } else {
48 if (m_implicitPointsValid) {
49 m_implicitPointsValid = false;
50 emit q->implicitPointsValidChanged(implicitPointsValid: m_implicitPointsValid);
51 }
52 }
53}
54
55void QBoundingVolumePrivate::setView(QGeometryView *view)
56{
57 Q_Q(QBoundingVolume);
58
59 if (m_view == view)
60 return;
61
62 if (m_view)
63 unregisterDestructionHelper(node: m_view);
64
65 if (view && !view->parent())
66 view->setParent(q);
67
68 m_view = view;
69
70 // Ensures proper bookkeeping
71 if (m_view)
72 registerDestructionHelper(node: m_view, func: &QBoundingVolume::setView, m_view);
73
74 emit q->viewChanged(view);
75}
76
77QBoundingVolumePrivate *QBoundingVolumePrivate::get(QBoundingVolume *q)
78{
79 return q->d_func();
80}
81
82/*!
83 * \qmltype BoundingVolume
84 * \instantiates Qt3DCore::QBoundingVolume
85 * \inqmlmodule Qt3D.Core
86 * \since 2.16
87 *
88 * \brief can be used to override an entity's bounding volume.
89 *
90 * An entity's bounding volume is used for many operations such as
91 * picking or view frustum culling. It is normally computed by
92 * traversing the rendered geometry.
93 *
94 * BoundingVolume can be used when the extent of the geometry is
95 * known to the application so that Qt 3D does not have to
96 * compute it.
97 *
98 * A bounding volume can be provided either as minimum and maximum
99 * extent coordinates, or a separate, usually simpler, geometry
100 * that approximates the rendered mesh.
101 *
102 * When using minimum and maximum extents, these are considered
103 * to be the opposite corners of an axis aligned bounding box,
104 * in the geometry's local coordinate system.
105 *
106 * BoundingVolume can also be used to query the computed bounding
107 * volume of a GeometryView. The implicitMinPoint and implicitMaxPoint
108 * properties will be updated if the geometry changes. Note that this
109 * is done asynchronously on a background thread so you should check
110 * the value of implicitPointsValid before reading them.
111 *
112 * You can force the implicit extents to be updated by calling
113 * updateImplicitBounds. This will block on the calling thread until
114 * the results are available.
115 *
116 * \note GeometryRenderer inherits BoundingVolume and thus supports
117 * reading implicit bounds or setting explicit bounds also.
118 */
119
120/*!
121 \class Qt3DCore::QBoundingVolume
122 \inheaderfile Qt3DCore/QBoundingVolume
123 \inmodule Qt3DCore
124 \inherits Qt3DCore::QComponent
125 \since 6.0
126 \brief can be used to override the bounding volume of an entity.
127
128 An entity's bounding volume is used for many operations such as
129 picking or view frustum culling. It is normally computed by
130 traversing the rendered geometry.
131
132 QBoundingVolume can be used when the extent of the geometry is
133 known to the application so that Qt 3D does not have to
134 compute it.
135
136 A bounding volume can be provided either as minimum and maximum
137 extent coordinates, or a separate, usually simpler, geometry
138 that approximates the rendered mesh.
139
140 When using minimum and maximum extents, these are considered
141 to be the opposite corners of an axis aligned bounding box,
142 in the geometry's local coordinate system.
143
144 QBoundingVolume can also be used to query the computed bounding
145 volume of a GeometryView. The implicitMinPoint and implicitMaxPoint
146 properties will be updated if the geometry changes. Note that this
147 is done asynchronously on a background thread so you should check
148 the value of implicitPointsValid before reading them.
149
150 You can force the implicit extents to be updated by calling
151 updateImplicitBounds. This will block on the calling thread until
152 the results are available.
153
154 \note GeometryRenderer inherits BoundingVolume and thus supports
155 reading implicit bounds or setting explicit bounds also.
156*/
157
158/*!
159 * Constructs a new QBoundingVolume with \a parent.
160 */
161QBoundingVolume::QBoundingVolume(QNode *parent)
162 : QComponent(*new QBoundingVolumePrivate(), parent)
163{
164}
165
166/*!
167 * \internal
168 */
169QBoundingVolume::QBoundingVolume(QBoundingVolumePrivate &dd, QNode *parent)
170 : QComponent(dd, parent)
171{
172}
173
174/*!
175 * \internal
176 */
177QBoundingVolume::~QBoundingVolume()
178{
179}
180
181/*!
182* \qmlproperty GeometryView BoundingVolume::view
183*
184* Holds a pointer to the instance of QGeometryView which will be used, if set,
185* to compute the bounding volume.
186*/
187/*!
188* \property QBoundingVolume::view
189*
190* Holds a pointer to the instance of QGeometryView which will be used, if set,
191* to compute the bounding volume.
192*/
193QGeometryView *QBoundingVolume::view() const
194{
195 Q_D(const QBoundingVolume);
196 return d->m_view;
197}
198
199/*!
200* \qmlproperty vector3d BoundingVolume::implicitMinPoint
201*
202* Holds minimum extent of the bounding volume computed from the specified view.
203*/
204/*!
205* \property QBoundingVolume::implicitMinPoint
206*
207* Holds minimum extent of the bounding volume computed from the specified view.
208*/
209QVector3D QBoundingVolume::implicitMinPoint() const
210{
211 Q_D(const QBoundingVolume);
212 return d->m_implicitMinPoint;
213}
214
215/*!
216* \qmlproperty vector3d BoundingVolume::implicitMaxPoint
217*
218* Holds maximum extent of the bounding volume computed from the specified view.
219*/
220/*!
221* \property QBoundingVolume::implicitMaxPoint
222*
223* Holds maximum extent of the bounding volume computed from the specified view.
224*/
225QVector3D QBoundingVolume::implicitMaxPoint() const
226{
227 Q_D(const QBoundingVolume);
228 return d->m_implicitMaxPoint;
229}
230
231/*!
232* \qmlproperty bool BoundingVolume::implicitPointsValid
233*
234* True if a view has been assigned and the implicit extent properties are up to date.
235*
236* \sa updateImplicitBounds
237*/
238/*!
239* \property QBoundingVolume::implicitPointsValid
240*
241* True if a view has been assigned and the implicit extent properties are up to date.
242*
243* \sa updateImplicitBounds
244*/
245bool QBoundingVolume::areImplicitPointsValid() const
246{
247 Q_D(const QBoundingVolume);
248 return d->m_implicitPointsValid;
249}
250
251/*!
252* \qmlproperty vector3d BoundingVolume::minPoint
253*
254* User specified minimum extent of the bounding volume. When set (along with maximum
255* extent), this will be used internally to avoid computing the volume from the
256* geometry.
257*/
258/*!
259* \property QBoundingVolume::minPoint
260*
261* User specified minimum extent of the bounding volume. When set (along with maximum
262* extent), this will be used internally to avoid computing the volume from the
263* geometry.
264*/
265QVector3D QBoundingVolume::minPoint() const
266{
267 Q_D(const QBoundingVolume);
268 return d->m_minPoint;
269}
270
271/*!
272* \qmlproperty vector3d BoundingVolume::maxPoint
273*
274* User specified maximum extent of the bounding volume. When set (along with minimum
275* extent), this will be used internally to avoid computing the volume from the
276* geometry.
277*/
278/*!
279* \property QBoundingVolume::maxPoint
280*
281* User specified maximum extent of the bounding volume. When set (along with minimum
282* extent), this will be used internally to avoid computing the volume from the
283* geometry.
284*/
285QVector3D QBoundingVolume::maxPoint() const
286{
287 Q_D(const QBoundingVolume);
288 return d->m_maxPoint;
289}
290
291void QBoundingVolume::setView(QGeometryView *view)
292{
293 Q_D(QBoundingVolume);
294 d->setView(view);
295}
296
297void QBoundingVolume::setMinPoint(const QVector3D &minPoint)
298{
299 Q_D(QBoundingVolume);
300 if (d->m_minPoint != minPoint) {
301 d->m_minPoint = minPoint;
302 d->m_explicitPointsValid = true;
303 d->markDirty(changes: QScene::GeometryDirty);
304 emit minPointChanged(minPoint: d->m_minPoint);
305 }
306}
307
308void QBoundingVolume::setMaxPoint(const QVector3D &maxPoint)
309{
310 Q_D(QBoundingVolume);
311 if (d->m_maxPoint != maxPoint) {
312 d->m_maxPoint = maxPoint;
313 d->m_explicitPointsValid = true;
314 d->markDirty(changes: QScene::GeometryDirty);
315 emit maxPointChanged(maxPoint: d->m_maxPoint);
316 }
317}
318
319/*!
320* \qmlmethod bool BoundingVolume::updateImplicitBounds()
321*
322* Updates the implicit bounds of the specified view. Returns
323* \c true if the computation succeeded and false otherwise.
324*
325* \note The calculations are done in the call thread, this
326* could take significant time for large meshes.
327*/
328
329/*!
330* Updates the implicit bounds of the specified view. Returns
331* \c true if the computation succeeded and false otherwise.
332*
333* \note The calculations are done in the call thread, this
334* could take significant time for large meshes.
335*/
336bool QBoundingVolume::updateImplicitBounds()
337{
338 Q_D(QBoundingVolume);
339 if (!d->m_view)
340 return false;
341
342 auto data = BoundingVolumeComputeData::fromView(view: d->m_view);
343 if (!data.valid())
344 return false;
345
346 auto res = data.compute();
347 if (!res.valid())
348 return false;
349
350 d->setImplicitBounds(minPoint: res.m_min, maxPoint: res.m_max, center: res.m_center, radius: res.m_radius);
351 return true;
352}
353
354} // namespace Qt3DCore
355
356QT_END_NAMESPACE
357
358#include "moc_qboundingvolume.cpp"
359

source code of qt3d/src/core/geometry/qboundingvolume.cpp