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 | |
13 | QT_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 | |
42 | QQuick3DXrSpatialAnchorListModel::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 | |
56 | int 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 | |
64 | QVariant 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 | |
84 | QHash<int, QByteArray> QQuick3DXrSpatialAnchorListModel::roleNames() const |
85 | { |
86 | QHash<int, QByteArray> roles; |
87 | roles[Anchor] = "anchor" ; |
88 | return roles; |
89 | } |
90 | |
91 | void 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 | |
100 | void QQuick3DXrSpatialAnchorListModel::queryAnchors() |
101 | { |
102 | if (m_anchorManager == nullptr) |
103 | return; |
104 | |
105 | m_anchorManager->queryAllAnchors(); |
106 | } |
107 | |
108 | void QQuick3DXrSpatialAnchorListModel::handleAnchorAdded(QQuick3DXrSpatialAnchor *anchor) |
109 | { |
110 | Q_UNUSED(anchor) |
111 | // Brute Force :-p |
112 | beginResetModel(); |
113 | endResetModel(); |
114 | } |
115 | |
116 | void QQuick3DXrSpatialAnchorListModel::handleAnchorRemoved(QUuid uuid) |
117 | { |
118 | Q_UNUSED(uuid) |
119 | // Brute Force :-p |
120 | beginResetModel(); |
121 | endResetModel(); |
122 | } |
123 | |
124 | void 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 | |
148 | QQuick3DXrSpatialAnchorListModel::FilterMode QQuick3DXrSpatialAnchorListModel::filterMode() const |
149 | { |
150 | return m_filterMode; |
151 | } |
152 | |
153 | void 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 | |
167 | QStringList QQuick3DXrSpatialAnchorListModel::identifierFilter() const |
168 | { |
169 | return m_uuids; |
170 | } |
171 | |
172 | void 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 | |
197 | QQuick3DXrSpatialAnchorListModel::ClassificationFlags QQuick3DXrSpatialAnchorListModel::classificationFilter() const |
198 | { |
199 | return m_classFilter; |
200 | } |
201 | |
202 | void 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 | */ |
224 | QStringList QQuick3DXrSpatialAnchorListModel::classificationStringFilter() const |
225 | { |
226 | return m_classStringFilter.values(); |
227 | } |
228 | |
229 | void 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 | |
240 | QT_END_NAMESPACE |
241 | |