1 | // Copyright (C) 2024 The Qt Company Ltd. |
2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only |
3 | |
4 | #include "qquick3dxrspatialanchor_p.h" |
5 | |
6 | #if defined(Q_OS_VISIONOS) |
7 | #include "visionos/qquick3dxranchormanager_visionos_p.h" |
8 | #else |
9 | #include "openxr/qquick3dxranchormanager_openxr_p.h" |
10 | #endif |
11 | |
12 | QT_BEGIN_NAMESPACE |
13 | |
14 | /*! |
15 | \qmltype XrSpatialAnchor |
16 | \inherits QtObject |
17 | \inqmlmodule QtQuick3D.Xr |
18 | \brief Tracks a specific location or object in real space. |
19 | |
20 | This type represents a spatial anchor that tracks |
21 | a specific location or object in real space. It provides information about |
22 | the anchor's position, rotation, classification, and bounds. |
23 | |
24 | Spatial anchors are accessed through an \l XrSpatialAnchorListModel. |
25 | |
26 | \note Anchor objects are provided by the system. They cannot be created in QML. |
27 | |
28 | See the \l{Qt Quick 3D - XR Spatial Anchors Example} for how to use this type. |
29 | */ |
30 | |
31 | /*! |
32 | \qmlproperty enumeration XrSpatialAnchor::Classification |
33 | \ingroup xr-anchors |
34 | \brief The classification of the spatial anchor. |
35 | \readonly |
36 | |
37 | The Classification enum provides a set of predefined category types that describe |
38 | the purpose or context of a spatial anchor. |
39 | |
40 | \value Classification.Unknown The label has not been set or identified. |
41 | \value Classification.Wall The anchor represents a wall. |
42 | \value Classification.Ceiling The anchor represents a ceiling. |
43 | \value Classification.Floor The anchor represents a floor. |
44 | \value Classification.Table The anchor represents a table. |
45 | \value Classification.Seat The anchor represents a seat. |
46 | \value Classification.Window The anchor represents a window. |
47 | \value Classification.Door The anchor represents a door. |
48 | \value Classification.Other The anchor was not identified as any of the above types. See: \l classificationString |
49 | |
50 | The following table shows the mapping between the classification type in \qxr, |
51 | OpenXR, and VisionOS. If the classification type from the system falls outside of the defined types, |
52 | then the \e Type is set to \c Other, and the system type is provided by the \l classificationString property. |
53 | |
54 | \note The classification string can also be \c{Other}. |
55 | |
56 | \table |
57 | \header |
58 | \li Type |
59 | \li OpenXR |
60 | \li VisionOS |
61 | \li Description |
62 | \row |
63 | \li Unknown |
64 | \li - |
65 | \li - |
66 | \li The label has not been set or identified. |
67 | \row |
68 | \li Wall |
69 | \li WALL_FACE |
70 | \li Wall |
71 | \li The anchor represents a wall. |
72 | \row |
73 | \li Ceiling |
74 | \li CEILING |
75 | \li Ceiling |
76 | \li The anchor represents a ceiling. |
77 | \row |
78 | \li Floor |
79 | \li FLOOR |
80 | \li Floor |
81 | \li The anchor represents a floor. |
82 | \row |
83 | \li Table |
84 | \li TABLE |
85 | \li Table |
86 | \li The anchor represents a table. |
87 | \row |
88 | \li Seat |
89 | \li COUCH |
90 | \li Seat |
91 | \li The anchor represents a seat. |
92 | \row |
93 | \li Window |
94 | \li WINDOW_FRAME |
95 | \li Window |
96 | \li The anchor represents a window. |
97 | \row |
98 | \li Door |
99 | \li DOOR_FRAME |
100 | \li Door |
101 | \li The anchor represents a door. |
102 | \row |
103 | \li Other |
104 | \li - |
105 | \li - |
106 | \li The anchor represents something else. See: \l classificationString |
107 | \endtable |
108 | */ |
109 | |
110 | QQuick3DXrSpatialAnchor::QQuick3DXrSpatialAnchor(QtQuick3DXr::XrSpaceId space, QUuid &uuid, QObject *parent) |
111 | : QObject(parent) |
112 | , m_space(space) |
113 | , m_uuid(uuid) |
114 | { |
115 | } |
116 | |
117 | QQuick3DXrSpatialAnchor::~QQuick3DXrSpatialAnchor() |
118 | { |
119 | } |
120 | |
121 | /*! |
122 | \qmlproperty vector3d XrSpatialAnchor::offset3D |
123 | \brief The 3D offset of the spatial anchor. |
124 | \readonly |
125 | |
126 | This property provides the 3D offset of the anchor's bounds (in meters) from the anchor's \l position. |
127 | |
128 | \sa offset3D, has3DBounds |
129 | */ |
130 | |
131 | QVector3D QQuick3DXrSpatialAnchor::offset3D() const |
132 | { |
133 | return m_offset3D; |
134 | } |
135 | |
136 | void QQuick3DXrSpatialAnchor::setOffset3D(const QVector3D &newOffset) |
137 | { |
138 | if (m_offset3D == newOffset) |
139 | return; |
140 | m_offset3D = newOffset; |
141 | emit offset3DChanged(); |
142 | } |
143 | |
144 | /*! |
145 | \qmlproperty vector3d XrSpatialAnchor::extent3D |
146 | \brief The 3D extent of the spatial anchor. |
147 | \readonly |
148 | |
149 | This property specifies the spatial anchor's volume in three dimensions (width, height, and depth). |
150 | It is valid when \l has3DBounds is \c true. |
151 | |
152 | \sa offset3D, has3DBounds |
153 | */ |
154 | |
155 | QVector3D QQuick3DXrSpatialAnchor::extent3D() const |
156 | { |
157 | return m_extent3D; |
158 | } |
159 | |
160 | void QQuick3DXrSpatialAnchor::setExtent3D(const QVector3D &newExtent) |
161 | { |
162 | if (m_extent3D == newExtent) |
163 | return; |
164 | m_extent3D = newExtent; |
165 | emit extent3DChanged(); |
166 | } |
167 | |
168 | /*! |
169 | \qmlproperty vector3d XrSpatialAnchor::position |
170 | \brief The position of the spatial anchor. |
171 | |
172 | \readonly |
173 | This property returns the 3D position (in meters) of the spatial anchor's origin within the |
174 | session's coordinate system. |
175 | */ |
176 | |
177 | QVector3D QQuick3DXrSpatialAnchor::position() const |
178 | { |
179 | return m_position; |
180 | } |
181 | |
182 | void QQuick3DXrSpatialAnchor::setPosition(const QVector3D &newPosition) |
183 | { |
184 | if (m_position == newPosition) |
185 | return; |
186 | m_position = newPosition; |
187 | emit positionChanged(); |
188 | } |
189 | |
190 | /*! |
191 | \qmlproperty quaternion XrSpatialAnchor::rotation |
192 | \brief The orientation of the spatial anchor. |
193 | \readonly |
194 | |
195 | This property provides the spatial anchor's rotation (as a quaternion). |
196 | */ |
197 | |
198 | QQuaternion QQuick3DXrSpatialAnchor::rotation() const |
199 | { |
200 | return m_rotation; |
201 | } |
202 | |
203 | void QQuick3DXrSpatialAnchor::setRotation(const QQuaternion &newRotation) |
204 | { |
205 | if (m_rotation == newRotation) |
206 | return; |
207 | m_rotation = newRotation; |
208 | emit rotationChanged(); |
209 | } |
210 | |
211 | /*! |
212 | \qmlproperty enumeration XrSpatialAnchor::classification |
213 | \brief The classification type of the spatial anchor. |
214 | \readonly |
215 | |
216 | This property returns the \l {XrSpatialAnchor::Classification}{classification type} for this anchor |
217 | (for example,\c Table or \c Floor) describing the anchor's purpose or context. |
218 | |
219 | \note The classification type coming from the system might not be in the set of labels |
220 | defined by the \l Classification enum, in which case the type will be set to \c Other |
221 | and the \l classificationString property will contain the original label. |
222 | |
223 | \sa classificationString |
224 | */ |
225 | |
226 | QQuick3DXrSpatialAnchor::Classification QQuick3DXrSpatialAnchor::classification() const |
227 | { |
228 | return m_classification; |
229 | } |
230 | |
231 | void QQuick3DXrSpatialAnchor::setClassification(Classification newClassification) |
232 | { |
233 | if (m_classification == newClassification) |
234 | return; |
235 | m_classification = newClassification; |
236 | emit classificationChanged(); |
237 | } |
238 | |
239 | /*! |
240 | \qmlproperty string XrSpatialAnchor::classificationString |
241 | \brief The classification type of the spatial anchor as a string. |
242 | \readonly |
243 | |
244 | This property returns the classification type as a string if one exists. |
245 | If the classification type is not in the set of types defined by the \l Classification enums, the |
246 | label is set to \c Other, and this property can be used to access the type as it was reported by |
247 | the system. |
248 | |
249 | \note This string can be empty or change, depending on the system and how the anchor gets classified. |
250 | |
251 | \sa classification |
252 | */ |
253 | |
254 | QString QQuick3DXrSpatialAnchor::classificationString() const |
255 | { |
256 | return m_classificationString; |
257 | } |
258 | |
259 | void QQuick3DXrSpatialAnchor::setClassificationString(const QString &newClassificationString) |
260 | { |
261 | if (m_classificationString == newClassificationString) |
262 | return; |
263 | m_classificationString = newClassificationString; |
264 | emit classificationStringChanged(); |
265 | } |
266 | |
267 | /*! |
268 | \qmlproperty bool XrSpatialAnchor::has2DBounds |
269 | \brief Indicates whether the spatial anchor has 2D bounds. |
270 | \readonly |
271 | |
272 | This property holds \c true if the spatial anchor has 2D bounds, |
273 | described by \l offset2D and \l extent2D, indicating that it |
274 | represents a flat surface (for example, a floor or wall). |
275 | |
276 | Otherwise, it returns false. |
277 | \sa offset2D, extent2D, has3DBounds |
278 | */ |
279 | |
280 | bool QQuick3DXrSpatialAnchor::has2DBounds() const |
281 | { |
282 | return m_has2DBounds; |
283 | } |
284 | |
285 | void QQuick3DXrSpatialAnchor::setBounds2D(const QVector2D &offset, const QVector2D &extent) |
286 | { |
287 | if (qFuzzyCompare(v1: m_offset2D, v2: offset) && qFuzzyCompare(v1: m_extent2D, v2: extent)) |
288 | return; |
289 | |
290 | m_offset2D = offset; |
291 | m_extent2D = extent; |
292 | |
293 | // FIXME: verify |
294 | m_has2DBounds = true; |
295 | |
296 | emit has2DBoundsChanged(); |
297 | } |
298 | |
299 | /*! |
300 | \qmlproperty bool XrSpatialAnchor::has3DBounds |
301 | \brief Indicates whether the spatial anchor has 3D bounds. |
302 | \readonly |
303 | |
304 | This property returns \c true if the spatial anchor has 3D bounds, indicating |
305 | that it represents a volume (for example, a table or a cupboard). |
306 | The bounds are described by \l offset3D and \l extent3D. |
307 | |
308 | Otherwise, it returns \c false. |
309 | \sa offset3D, extent3D, has2DBounds |
310 | */ |
311 | |
312 | |
313 | bool QQuick3DXrSpatialAnchor::has3DBounds() const |
314 | { |
315 | return m_has3DBounds; |
316 | } |
317 | |
318 | void QQuick3DXrSpatialAnchor::setBounds3D(const QVector3D &offset, const QVector3D &extent) |
319 | { |
320 | if (qFuzzyCompare(v1: m_offset3D, v2: offset) && qFuzzyCompare(v1: m_extent3D, v2: extent)) |
321 | return; |
322 | |
323 | m_offset3D = offset; |
324 | m_extent3D = extent; |
325 | |
326 | // FIXME: Store the 3D bounds and verify |
327 | m_has3DBounds = true; |
328 | |
329 | emit has3DBoundsChanged(); |
330 | } |
331 | |
332 | /*! |
333 | \qmlproperty vector2d XrSpatialAnchor::offset2D |
334 | \brief The 2D offset of the spatial anchor. |
335 | |
336 | \readonly |
337 | This property holds the offset of the anchor's bounds within |
338 | the X/Z plane. It is valid when \l has2DBounds is \c true. |
339 | |
340 | \sa has2DBounds, extent2D |
341 | */ |
342 | |
343 | QVector2D QQuick3DXrSpatialAnchor::offset2D() const |
344 | { |
345 | return m_offset2D; |
346 | } |
347 | |
348 | /*! |
349 | \qmlproperty vector2d XrSpatialAnchor::extent2D |
350 | \brief The 2D extent of the spatial anchor. |
351 | \readonly |
352 | |
353 | This property holds the spatial anchor's size in two dimensions (width and height) within |
354 | the X/Z plane. It is valid when \l has2DBounds is \c true. |
355 | |
356 | \sa has2DBounds, offset2D |
357 | */ |
358 | |
359 | QVector2D QQuick3DXrSpatialAnchor::extent2D() const |
360 | { |
361 | return m_extent2D; |
362 | } |
363 | |
364 | /*! |
365 | \qmlproperty string XrSpatialAnchor::identifier |
366 | \brief A unique identifier for this spatial anchor. |
367 | \readonly |
368 | |
369 | This property holds a unique identifier associated with the |
370 | spatial anchor. This is the same identifier referenced by a \l XrSpatialAnchorListModel. |
371 | */ |
372 | |
373 | QString QQuick3DXrSpatialAnchor::identifier() const |
374 | { |
375 | return QString::fromLatin1(ba: m_uuid.toRfc4122()); |
376 | } |
377 | |
378 | QSet<QUuid> QQuick3DXrSpatialAnchor::roomLayoutUuids() const |
379 | { |
380 | return m_roomLayoutUuids; |
381 | } |
382 | |
383 | void QQuick3DXrSpatialAnchor::setRoomLayoutUuids(const QSet<QUuid> &newRoomLayoutUuids) |
384 | { |
385 | m_roomLayoutUuids = newRoomLayoutUuids; |
386 | } |
387 | |
388 | QSet<QUuid> QQuick3DXrSpatialAnchor::spaceContainerUuids() const |
389 | { |
390 | return m_spaceContainerUuids; |
391 | } |
392 | |
393 | void QQuick3DXrSpatialAnchor::setSpaceContainerUuids(const QSet<QUuid> &newSpaceContainerUuids) |
394 | { |
395 | m_spaceContainerUuids = newSpaceContainerUuids; |
396 | } |
397 | |
398 | QT_END_NAMESPACE |
399 | |