1// Copyright (C) 2024 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
3
4#include "qquick3dxrspatialanchorlistmodel_p.h"
5#include "qquick3dxrspatialanchor_p.h"
6
7#if defined(Q_OS_VISIONOS)
8#include "visionos/qquick3dxranchormanager_visionos_p.h"
9#else
10#include "openxr/qquick3dxranchormanager_openxr_p.h"
11#endif
12
13QT_BEGIN_NAMESPACE
14
15/*!
16 \qmltype XrSpatialAnchorListModel
17 \inherits ListModel
18 \inqmlmodule QtQuick3D.Xr
19 \brief Provides a model containing spatial anchors.
20
21 This type provides a list of spatial anchors, which are points in
22 the physical world that can be tracked and associated with virtual content.
23
24 The list contains elements that have an \c anchor property with the type \l XrSpatialAnchor.
25
26 You can use it like this:
27
28 \qml
29 Repeater3D {
30 model: XrSpatialAnchorListModel {
31 }
32 delegate: Node {
33 required property XrSpatialAnchor anchor
34 position: anchor.position
35 rotation: anchor.rotation
36 // Further use of anchor properties...
37 }
38 }
39 \endqml
40*/
41
42QQuick3DXrSpatialAnchorListModel::QQuick3DXrSpatialAnchorListModel(QObject *parent)
43 : QAbstractListModel{parent}
44{
45 m_anchorManager = QQuick3DXrAnchorManager::instance();
46 if (m_anchorManager) {
47 connect(sender: m_anchorManager, signal: &QQuick3DXrAnchorManager::anchorAdded, context: this, slot: &QQuick3DXrSpatialAnchorListModel::handleAnchorAdded);
48 connect(sender: m_anchorManager, signal: &QQuick3DXrAnchorManager::anchorUpdated, context: this, slot: &QQuick3DXrSpatialAnchorListModel::handleAnchorUpdated);
49 connect(sender: m_anchorManager, signal: &QQuick3DXrAnchorManager::anchorRemoved, context: this, slot: &QQuick3DXrSpatialAnchorListModel::handleAnchorRemoved);
50 queryAnchors();
51 } else {
52 qWarning(msg: "SpatialAnchorModel: Failed to get anchor manager instance");
53 }
54}
55
56int QQuick3DXrSpatialAnchorListModel::rowCount(const QModelIndex &parent) const
57{
58 if (parent.isValid() || m_anchorManager == nullptr)
59 return 0;
60
61 return m_anchorManager->anchorCount();
62}
63
64QVariant QQuick3DXrSpatialAnchorListModel::data(const QModelIndex &index, int role) const
65{
66 if (!index.isValid() || m_anchorManager == nullptr)
67 return QVariant();
68
69 const auto &anchors = m_anchorManager->anchors();
70
71 // check bounds
72 if (index.row() < 0 || index.row() >= anchors.count())
73 return QVariant();
74
75 const auto &anchor = anchors.at(i: index.row());
76
77 if (role == Anchor)
78 return QVariant::fromValue(value: anchor);
79
80 // shouldn't be reachable under normal circumstances.
81 return QVariant();
82}
83
84QHash<int, QByteArray> QQuick3DXrSpatialAnchorListModel::roleNames() const
85{
86 QHash<int, QByteArray> roles;
87 roles[Anchor] = "anchor";
88 return roles;
89}
90
91void QQuick3DXrSpatialAnchorListModel::requestSceneCapture()
92{
93 if (m_anchorManager == nullptr)
94 return;
95
96 // not supported on the Simulator, this will be a no-op there
97 m_anchorManager->requestSceneCapture();
98}
99
100void QQuick3DXrSpatialAnchorListModel::queryAnchors()
101{
102 if (m_anchorManager == nullptr)
103 return;
104
105 m_anchorManager->queryAllAnchors();
106}
107
108void QQuick3DXrSpatialAnchorListModel::handleAnchorAdded(QQuick3DXrSpatialAnchor *anchor)
109{
110 Q_UNUSED(anchor)
111 // Brute Force :-p
112 beginResetModel();
113 endResetModel();
114}
115
116void QQuick3DXrSpatialAnchorListModel::handleAnchorRemoved(QUuid uuid)
117{
118 Q_UNUSED(uuid)
119 // Brute Force :-p
120 beginResetModel();
121 endResetModel();
122}
123
124void QQuick3DXrSpatialAnchorListModel::handleAnchorUpdated(QQuick3DXrSpatialAnchor *anchor)
125{
126 Q_UNUSED(anchor)
127 // Brute Force :-p
128 beginResetModel();
129 endResetModel();
130}
131
132// NOTE: filtering is not implemented yet, so the associated properties are left
133// undocumented in this version. They are not removed completely since filtering
134// will definitely be implemented in a future release.
135
136/*
137 \qmlproperty enumeration XrSpatialAnchorListModel::filterMode
138 \brief Specifies the filter mode for spatial anchors.
139 \internal
140
141 Holds the filter mode.
142 The filter mode can be one of the following:
143 \value All Show all spatial anchors.
144 \value Classification Show spatial anchors based on the provided classification filter flag.
145 \value Identifier Show spatial anchors based on matching the provided Identifiers.
146 */
147
148QQuick3DXrSpatialAnchorListModel::FilterMode QQuick3DXrSpatialAnchorListModel::filterMode() const
149{
150 return m_filterMode;
151}
152
153void QQuick3DXrSpatialAnchorListModel::setFilterMode(FilterMode newFilterMode)
154{
155 if (m_filterMode == newFilterMode)
156 return;
157 m_filterMode = newFilterMode;
158 emit filterModeChanged();
159}
160
161/*
162 \qmlproperty list<string> XrSpatialAnchorListModel::identifierFilter
163 \brief Holds the list of identifiers for filtering spatial anchors.
164 \internal
165 */
166
167QStringList QQuick3DXrSpatialAnchorListModel::identifierFilter() const
168{
169 return m_uuids;
170}
171
172void QQuick3DXrSpatialAnchorListModel::setIdentifierFilter(const QStringList &filter)
173{
174 if (m_uuids == filter)
175 return;
176 m_uuids = filter;
177 emit identifierFilterChanged();
178}
179
180/*
181 \qmlproperty enumeration XrSpatialAnchorListModel::classificationFilter
182 \brief Holds the classification flag used for filtering spatial anchors.
183 \internal
184
185 The ClassificationFlag filter is represented as a combination of flags:
186
187 \value Wall
188 \value Ceiling
189 \value Floor
190 \value Table
191 \value Seat
192 \value Window
193 \value Door
194 \value Other
195 */
196
197QQuick3DXrSpatialAnchorListModel::ClassificationFlags QQuick3DXrSpatialAnchorListModel::classificationFilter() const
198{
199 return m_classFilter;
200}
201
202void QQuick3DXrSpatialAnchorListModel::setClassificationFilter(ClassificationFlags newClassFilter)
203{
204 if (m_classFilter == newClassFilter)
205 return;
206 m_classFilter = newClassFilter;
207 emit classificationFilterChanged();
208}
209
210/*
211 \qmlproperty list<string> XrSpatialAnchorListModel::classificationStringFilter
212 \brief Holds the classification strings used for filtering spatial anchors.
213 \internal
214
215 If the \l FilterMode is set to \c Classification, this property can be used to provide a
216 list of additional classification string to filter on. These labels will then be matched against
217 the same value as reported by \l {XrSpatialAnchor::classificationString} property
218 of the spatial anchor.
219
220 \note Only \l {XrSpatialAnchor}{spatial anchors} that are classified as
221 \l {XrSpatialAnchor::Classification::Other}{Other}
222 will be checked against this filter.
223 */
224QStringList QQuick3DXrSpatialAnchorListModel::classificationStringFilter() const
225{
226 return m_classStringFilter.values();
227}
228
229void QQuick3DXrSpatialAnchorListModel::setClassificationStringFilter(const QStringList &newClassStringFilter)
230{
231 QSet<QString> newFilter { newClassStringFilter.cbegin(), newClassStringFilter.cend()};
232
233 if (m_classStringFilter == newFilter)
234 return;
235
236 m_classStringFilter = newFilter;
237 emit classificationStringFilterChanged();
238}
239
240QT_END_NAMESPACE
241

source code of qtquick3d/src/xr/quick3dxr/qquick3dxrspatialanchorlistmodel.cpp