Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
qquick3dxranchormanager_visionos.mm
Go to the documentation of this file.
1// Copyright (C) 2024 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
3
5
8
9#include <QtQuick3DUtils/private/qssgassert_p.h>
10#include <QtQuick3DUtils/private/qssgutils_p.h>
11
12
14
16{
18 return &instance;
19}
20
21QQuick3DXrAnchorManager::QQuick3DXrAnchorManager(QObject *parent)
22 : QObject(parent)
23{
24}
25
26QQuick3DXrAnchorManager::~QQuick3DXrAnchorManager()
27{
28
29}
30
31void QQuick3DXrAnchorManager::addAnchor(QQuick3DXrSpatialAnchor *anchor)
32{
33 anchor->moveToThread(qApp->thread());
34
35 m_anchorsByUuid.insert(anchor->uuid(), anchor);
36
37 Q_EMIT anchorAdded(anchor);
38}
39
41{
42 if (QQuick3DXrSpatialAnchor *anchor = m_anchorsByUuid.take(uuid))
43 anchor->deleteLater();
44 else
45 qWarning() << "Anchor not found for removal: " << uuid;
46
48}
49
51{
52 anchor->moveToThread(qApp->thread());
53
54 Q_EMIT anchorUpdated(anchor);
55}
56
58{
59 m_anchors = m_anchorsByUuid.values();
60}
61
63{
64 Unknown = 0,
67 Wall,
68 Ceiling,
69 Floor,
70 Table,
71 Seat,
72 Window,
73 Door,
74};
75
76static constexpr size_t anchorClassificationStart = size_t(AnchorClassifcation::Wall);
77
85 {ar_plane_classification_status_unknown, AnchorClassifcation::Unknown, QQuick3DXrSpatialAnchor::Classification::Unknown, "Unknown"},
86 {ar_plane_classification_status_not_available, AnchorClassifcation::NotAvailable, QQuick3DXrSpatialAnchor::Classification::Unknown, "Not Available"},
87 {ar_plane_classification_status_undetermined, AnchorClassifcation::Undetermined, QQuick3DXrSpatialAnchor::Classification::Unknown, "Undetermined"},
88 {ar_plane_classification_wall, AnchorClassifcation::Wall, QQuick3DXrSpatialAnchor::Classification::Wall, "Wall"},
89 {ar_plane_classification_ceiling, AnchorClassifcation::Ceiling, QQuick3DXrSpatialAnchor::Classification::Ceiling, "Ceiling"},
90 {ar_plane_classification_floor, AnchorClassifcation::Floor, QQuick3DXrSpatialAnchor::Classification::Floor, "Floor"},
91 {ar_plane_classification_table, AnchorClassifcation::Table, QQuick3DXrSpatialAnchor::Classification::Table, "Table"},
92 {ar_plane_classification_seat, AnchorClassifcation::Seat, QQuick3DXrSpatialAnchor::Classification::Seat, "Seat"},
93 {ar_plane_classification_window, AnchorClassifcation::Window, QQuick3DXrSpatialAnchor::Classification::Window, "Window"},
94 {ar_plane_classification_door, AnchorClassifcation::Door, QQuick3DXrSpatialAnchor::Classification::Door, "Door"},
95};
96
97static const AnchorClassificationMap &getAnchorClassificationName(ar_plane_classification_t classification, bool *identified = nullptr)
98{
99 size_t foundIndex = 0;
100 for (size_t i = 0, end = std::size(anchorClassificationMap); i != end; ++i) {
101 if (anchorClassificationMap[i].classification == classification) {
102 foundIndex = i;
103 break;
104 }
105 }
106
107 if (identified) // If the caller wants to know if the classification was found (I.e. not Unknown, Not Available, or Undetermined)
108 *identified = (foundIndex >= anchorClassificationStart);
109
110 return anchorClassificationMap[foundIndex];
111}
112
113static void updateAnchorProperties(QQuick3DXrSpatialAnchor &anchor, ar_plane_anchor_t planeAnchor)
114{
115 static const QQuaternion s_rot90X = QQuaternion::fromEulerAngles({-90.0f, 0.0f, 0.0f});
116
117 simd_float4x4 originFromAnchorTransform = ar_anchor_get_origin_from_anchor_transform(planeAnchor);
118 QMatrix4x4 transform{originFromAnchorTransform.columns[0].x, originFromAnchorTransform.columns[1].x, originFromAnchorTransform.columns[2].x, originFromAnchorTransform.columns[3].x,
119 originFromAnchorTransform.columns[0].y, originFromAnchorTransform.columns[1].y, originFromAnchorTransform.columns[2].y, originFromAnchorTransform.columns[3].y,
120 originFromAnchorTransform.columns[0].z, originFromAnchorTransform.columns[1].z, originFromAnchorTransform.columns[2].z, originFromAnchorTransform.columns[3].z,
121 0.0f, 0.0f, 0.0f, 1.0f};
122
123 ar_plane_classification_t classification = ar_plane_anchor_get_plane_classification(planeAnchor);
124 const auto &classificationEntry = getAnchorClassificationName(classification);
125
126 if (anchor.classification() != classificationEntry.label) {
127 anchor.setClassification(classificationEntry.label);
128 anchor.setClassificationString(QString::fromLatin1(classificationEntry.classificationName));
129 }
130
131 ar_plane_geometry_t planeGeometry = ar_plane_anchor_get_geometry(planeAnchor);
132 ar_plane_extent_t planeExtent = ar_plane_geometry_get_plane_extent(planeGeometry);
133
134 const float width = ar_plane_extent_get_width(planeExtent);
135 const float height = ar_plane_extent_get_height(planeExtent);
136
137 // position and rotation
140 QQuaternion rot;
142
143 // The y-axis of the plane anchor is the plane’s normal vector.
144 rot = rot * s_rot90X;
145
146 anchor.setPosition(pos * 100.0f);
147 anchor.setRotation(rot);
148
149 QVector2D offset2D{};
150 QVector2D extent2D(width, height);
151 anchor.setBounds2D(offset2D, extent2D);
152}
153
154void QQuick3DXrAnchorManager::planeUpdateHandler(void *context, ar_plane_anchors_t added_anchors, ar_plane_anchors_t updated_anchors, ar_plane_anchors_t removed_anchors)
155{
156 QSSG_ASSERT_X(context != nullptr, "Context is null!", return);
157
158 QQuick3DXrAnchorManager *that = reinterpret_cast<QQuick3DXrAnchorManager *>(context);
159 // Lock for writes to the anchors list (Might as well use a simple mutex, the data is only modified by this handler).
160 QWriteLocker locker(&that->m_anchorsLock);
161
162 // 1. Remove
163 if (removed_anchors) {
164 ar_plane_anchors_enumerate_anchors_f(removed_anchors, context, [](void *context, ar_plane_anchor_t planeAnchor) -> bool {
165 QSSG_ASSERT_X(QSSG_DEBUG_COND(context != nullptr), "Unexpected context!", return false);
166
167 QQuick3DXrAnchorManager *that = reinterpret_cast<QQuick3DXrAnchorManager *>(context);
168
169 unsigned char identifier[16] {};
170 ar_anchor_get_identifier(planeAnchor, identifier);
171
172 if (!QtQuick3DXr::isValidUuid(identifier)) {
173 qWarning() << "Invalid UUID for anchor";
174 return false;
175 }
176
177 QUuid uuid = QUuid::fromRfc4122(QByteArrayView(reinterpret_cast<const char *>(identifier), 16));
178 that->removeAnchor(uuid);
179
180 return true;
181 });
182 }
183
184 // 2. Add
185 if (added_anchors) {
186 ar_plane_anchors_enumerate_anchors_f(added_anchors, context, [](void *context, ar_plane_anchor_t planeAnchor) -> bool {
187 QSSG_ASSERT_X(QSSG_DEBUG_COND(context != nullptr), "Unexpected context!", return false);
188
189 QQuick3DXrAnchorManager *that = reinterpret_cast<QQuick3DXrAnchorManager *>(context);
190
191 // NOTE: The API documentation for this is severely lacking, but the swift docs have some more information
192 // saying the identifier follows RFC 4122 for UUIDs, meaning the identifier is a 128-bit value (Big Endian)
193 unsigned char identifier[16] {};
194 ar_anchor_get_identifier(planeAnchor, identifier);
195
196 if (!QtQuick3DXr::isValidUuid(identifier)) {
197 qWarning() << "Invalid UUID for anchor";
198 return false;
199 }
200
201 QUuid uuid = QUuid::fromRfc4122(QByteArrayView(reinterpret_cast<const char *>(identifier), 16));
202 const QtQuick3DXr::XrSpaceId space = that->getCurrentSpaceId();
203 QQuick3DXrSpatialAnchor *anchor = new QQuick3DXrSpatialAnchor(space, uuid);
204 updateAnchorProperties(*anchor, planeAnchor);
205 that->addAnchor(anchor);
206
207 return true;
208 });
209 }
210
211 // 3. Update
212 if (updated_anchors) {
213 ar_plane_anchors_enumerate_anchors_f(updated_anchors, context, [](void *context, ar_plane_anchor_t planeAnchor) -> bool {
214 QSSG_ASSERT_X(QSSG_DEBUG_COND(context != nullptr), "Unexpected context!", return false);
215
216 QQuick3DXrAnchorManager *that = reinterpret_cast<QQuick3DXrAnchorManager *>(context);
217
218 unsigned char identifier[16] {};
219 ar_anchor_get_identifier(planeAnchor, identifier);
220
221 if (!QtQuick3DXr::isValidUuid(identifier)) {
222 qWarning() << "Invalid UUID for anchor";
223 return false;
224 }
225
226 QUuid uuid = QUuid::fromRfc4122(QByteArrayView(reinterpret_cast<const char *>(identifier), 16));
227
228 QQuick3DXrSpatialAnchor *anchor = that->m_anchorsByUuid.value(uuid);
229 // This does occur in some cases, so we need to create a new anchor if it's not found
230 // NOTE: Ideally this should not happen, but it does, reason unknown atm.
231 if (!anchor) {
232 anchor = new QQuick3DXrSpatialAnchor(that->getCurrentSpaceId(), uuid);
233 updateAnchorProperties(*anchor, planeAnchor);
234 that->addAnchor(anchor);
235 } else {
236 updateAnchorProperties(*anchor, planeAnchor);
237 that->updateAnchor(anchor);
238 }
239
240 return true;
241 });
242 }
243
244 that->populateAnchorsList();
245}
246
247void QQuick3DXrAnchorManager::prepareAnchorManager(ar_data_providers_t dataProviders)
248{
249 QSSG_ASSERT_X(!m_isInitialized, "Anchor manager already initialized", return);
250
251 m_isPlaneDetectionSupported = (m_requestedAnchorType == AnchorType::Plane) && ar_plane_detection_provider_is_supported();
252 if (m_isPlaneDetectionSupported) {
253 ar_plane_detection_configuration_t planeDetectionConfiguration = ar_plane_detection_configuration_create();
254 m_planeDetectionProvider = ar_plane_detection_provider_create(planeDetectionConfiguration);
255 ar_plane_detection_provider_set_update_handler_f(m_planeDetectionProvider, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), this, &planeUpdateHandler);
256 ar_data_providers_add_data_provider(dataProviders, m_planeDetectionProvider);
257 } else {
258 qWarning("Plane detection is not supported on this platform.");
259 }
260}
261
262void QQuick3DXrAnchorManager::initAnchorManager()
263{
264 QSSG_ASSERT_X(!m_isInitialized, "Anchor manager already initialized", return);
265
266 m_isInitialized = m_isPlaneDetectionSupported;
267}
268
270{
272}
273
275{
276 return true;
277}
278
279QList<QQuick3DXrSpatialAnchor *> QQuick3DXrAnchorManager::anchors() const
280{
281 QReadLocker locker(&m_anchorsLock);
282 return m_anchors;
283}
284
286{
287 QReadLocker locker(&m_anchorsLock);
288 return m_anchors.size();
289}
290
QList< T > values() const
Returns a list containing all the values in the hash, in an arbitrary order.
Definition qhash.h:1099
T take(const Key &key)
Removes the item with the key from the hash and returns the value associated with it.
Definition qhash.h:986
iterator insert(const Key &key, const T &value)
Inserts a new item with the key and a value of value.
Definition qhash.h:1304
qsizetype size() const noexcept
Definition qlist.h:398
The QMatrix4x4 class represents a 4x4 transformation matrix in 3D space.
Definition qmatrix4x4.h:25
\inmodule QtCore
Definition qobject.h:103
bool moveToThread(QThread *thread QT6_DECL_NEW_OVERLOAD_TAIL)
Changes the thread affinity for this object and its children and returns true on success.
Definition qobject.cpp:1643
The QQuaternion class represents a quaternion consisting of a vector and scalar.
static QQuick3DXrAnchorManager * instance()
void updateAnchor(QQuick3DXrSpatialAnchor *anchor)
void anchorRemoved(QUuid uuid)
const QList< QQuick3DXrSpatialAnchor * > & anchors() const
void anchorAdded(QQuick3DXrSpatialAnchor *anchor)
void anchorUpdated(QQuick3DXrSpatialAnchor *anchor)
void setClassificationString(const QString &newClassificationString)
void setBounds2D(const QVector2D &offset, const QVector2D &extent)
void setRotation(const QQuaternion &newRotation)
void setClassification(Classification newClassification)
void setPosition(const QVector3D &newPosition)
\inmodule QtCore
static QString fromLatin1(QByteArrayView ba)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qstring.cpp:5881
\inmodule QtCore
Definition quuid.h:32
static QUuid fromRfc4122(QByteArrayView) noexcept
Creates a QUuid object from the binary representation of the UUID, as specified by RFC 4122 section 4...
Definition quuid.cpp:606
The QVector2D class represents a vector or vertex in 2D space.
Definition qvectornd.h:31
The QVector3D class represents a vector or vertex in 3D space.
Definition qvectornd.h:171
\inmodule QtCore
bool Q_QUICK3DUTILS_EXPORT decompose(const QMatrix4x4 &m, QVector3D &position, QVector3D &scale, QQuaternion &rotation)
Combined button and popup list for selecting options.
bool isValidUuid(const quint8(&uuid)[N])
#define qApp
#define qWarning
Definition qlogging.h:167
GLint GLsizei GLsizei height
GLuint GLuint end
GLint GLsizei width
GLuint GLenum GLenum transform
GLenum GLenum GLenum GLenum GLenum scale
static const AnchorClassificationMap & getAnchorClassificationName(ar_plane_classification_t classification, bool *identified=nullptr)
static constexpr size_t anchorClassificationStart
static void updateAnchorProperties(QQuick3DXrSpatialAnchor &anchor, ar_plane_anchor_t planeAnchor)
static const AnchorClassificationMap anchorClassificationMap[]
struct ar_data_providers_s * ar_data_providers_t
struct ar_plane_anchors_s * ar_plane_anchors_t
#define QSSG_DEBUG_COND(cond)
#define QSSG_ASSERT_X(cond, msg, action)
#define Q_EMIT
#define Q_UNIMPLEMENTED()
ptrdiff_t qsizetype
Definition qtypes.h:165
QQuick3DXrSpatialAnchor::Classification label