// Copyright (C) 2024 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only #include "qquick3dxrspatialanchor_p.h" #if defined(Q_OS_VISIONOS) #include "visionos/qquick3dxranchormanager_visionos_p.h" #else #include "openxr/qquick3dxranchormanager_openxr_p.h" #endif QT_BEGIN_NAMESPACE /*! \qmltype XrSpatialAnchor \inherits QtObject \inqmlmodule QtQuick3D.Xr \brief Tracks a specific location or object in real space. This type represents a spatial anchor that tracks a specific location or object in real space. It provides information about the anchor's position, rotation, classification, and bounds. Spatial anchors are accessed through an \l XrSpatialAnchorListModel. \note The system provides Anchor objects. They cannot be created in QML. See the \l{Qt Quick 3D - XR Spatial Anchors Example} for how to use this type. \section1 Platform notes \section2 Meta Quest Devices This API makes use of the Meta Quest Scene and Spatial Anchor APIs. You need to add the following permissions to your app's \c AndroidManifest.xml file: \badcode \endcode \note You need to manually set up a Space before running an app, or anchors will not be available. */ /*! \qmlproperty enumeration XrSpatialAnchor::Classification \ingroup xr-anchors \brief The classification of the spatial anchor. \readonly The Classification enum provides a set of predefined category types that describe the purpose or context of a spatial anchor. \value Classification.Unknown The label has not been set or identified. \value Classification.Wall The anchor represents a wall. \value Classification.Ceiling The anchor represents a ceiling. \value Classification.Floor The anchor represents a floor. \value Classification.Table The anchor represents a table. \value Classification.Seat The anchor represents a seat. \value Classification.Window The anchor represents a window. \value Classification.Door The anchor represents a door. \value Classification.Other The anchor was not identified as any of the above types. See: \l classificationString The following table shows the mapping between the classification type in \qxr, OpenXR, and VisionOS. If the classification type from the system falls outside of the defined types, then the \e Type is set to \c Other, and the system type is provided by the \l classificationString property. \note The classification string can also be \c{Other}. \table \header \li Type \li OpenXR \li VisionOS \li Description \row \li Unknown \li - \li - \li The label has not been set or identified. \row \li Wall \li WALL_FACE \li Wall \li The anchor represents a wall. \row \li Ceiling \li CEILING \li Ceiling \li The anchor represents a ceiling. \row \li Floor \li FLOOR \li Floor \li The anchor represents a floor. \row \li Table \li TABLE \li Table \li The anchor represents a table. \row \li Seat \li COUCH \li Seat \li The anchor represents a seat. \row \li Window \li WINDOW_FRAME \li Window \li The anchor represents a window. \row \li Door \li DOOR_FRAME \li Door \li The anchor represents a door. \row \li Other \li - \li - \li The anchor represents something else. See: \l classificationString \endtable */ QQuick3DXrSpatialAnchor::QQuick3DXrSpatialAnchor(QtQuick3DXr::XrSpaceId space, QUuid &uuid, QObject *parent) : QObject(parent) , m_space(space) , m_uuid(uuid) { } QQuick3DXrSpatialAnchor::~QQuick3DXrSpatialAnchor() { } /*! \qmlproperty vector3d XrSpatialAnchor::offset3D \brief The 3D offset of the spatial anchor. \readonly This property provides the 3D offset of the anchor's bounds (in meters) from the anchor's \l position. \sa offset3D, has3DBounds */ QVector3D QQuick3DXrSpatialAnchor::offset3D() const { return m_offset3D; } void QQuick3DXrSpatialAnchor::setOffset3D(const QVector3D &newOffset) { if (m_offset3D == newOffset) return; m_offset3D = newOffset; emit offset3DChanged(); } /*! \qmlproperty vector3d XrSpatialAnchor::extent3D \brief The 3D extent of the spatial anchor. \readonly This property specifies the spatial anchor's volume in three dimensions (width, height, and depth). It is valid when \l has3DBounds is \c true. \sa offset3D, has3DBounds */ QVector3D QQuick3DXrSpatialAnchor::extent3D() const { return m_extent3D; } void QQuick3DXrSpatialAnchor::setExtent3D(const QVector3D &newExtent) { if (m_extent3D == newExtent) return; m_extent3D = newExtent; emit extent3DChanged(); } /*! \qmlproperty vector3d XrSpatialAnchor::position \brief The position of the spatial anchor. \readonly This property returns the 3D position (in meters) of the spatial anchor's origin within the session's coordinate system. */ QVector3D QQuick3DXrSpatialAnchor::position() const { return m_position; } void QQuick3DXrSpatialAnchor::setPosition(const QVector3D &newPosition) { if (m_position == newPosition) return; m_position = newPosition; emit positionChanged(); } /*! \qmlproperty quaternion XrSpatialAnchor::rotation \brief The orientation of the spatial anchor. \readonly This property provides the spatial anchor's rotation (as a quaternion). */ QQuaternion QQuick3DXrSpatialAnchor::rotation() const { return m_rotation; } void QQuick3DXrSpatialAnchor::setRotation(const QQuaternion &newRotation) { if (m_rotation == newRotation) return; m_rotation = newRotation; emit rotationChanged(); } /*! \qmlproperty enumeration XrSpatialAnchor::classification \brief The classification type of the spatial anchor. \readonly This property returns the \l {XrSpatialAnchor::Classification}{classification type} for this anchor (for example,\c Table or \c Floor) describing the anchor's purpose or context. \note The classification type coming from the system might not be in the set of labels defined by the \l Classification enum, in which case the type will be set to \c Other and the \l classificationString property will contain the original label. \sa classificationString */ QQuick3DXrSpatialAnchor::Classification QQuick3DXrSpatialAnchor::classification() const { return m_classification; } void QQuick3DXrSpatialAnchor::setClassification(Classification newClassification) { if (m_classification == newClassification) return; m_classification = newClassification; emit classificationChanged(); } /*! \qmlproperty string XrSpatialAnchor::classificationString \brief The classification type of the spatial anchor as a string. \readonly This property returns the classification type as a string if one exists. If the classification type is not in the set of types defined by the \l Classification enums, the label is set to \c Other, and this property can be used to access the type as it was reported by the system. \note This string can be empty or change, depending on the system and how the anchor gets classified. \sa classification */ QString QQuick3DXrSpatialAnchor::classificationString() const { return m_classificationString; } void QQuick3DXrSpatialAnchor::setClassificationString(const QString &newClassificationString) { if (m_classificationString == newClassificationString) return; m_classificationString = newClassificationString; emit classificationStringChanged(); } /*! \qmlproperty bool XrSpatialAnchor::has2DBounds \brief Indicates whether the spatial anchor has 2D bounds. \readonly This property holds \c true if the spatial anchor has 2D bounds, described by \l offset2D and \l extent2D, indicating that it represents a flat surface (for example, a floor or wall). Otherwise, it returns false. \sa offset2D, extent2D, has3DBounds */ bool QQuick3DXrSpatialAnchor::has2DBounds() const { return m_has2DBounds; } void QQuick3DXrSpatialAnchor::setBounds2D(const QVector2D &offset, const QVector2D &extent) { if (qFuzzyCompare(m_offset2D, offset) && qFuzzyCompare(m_extent2D, extent)) return; m_offset2D = offset; m_extent2D = extent; // FIXME: verify m_has2DBounds = true; emit has2DBoundsChanged(); } /*! \qmlproperty bool XrSpatialAnchor::has3DBounds \brief Indicates whether the spatial anchor has 3D bounds. \readonly This property returns \c true if the spatial anchor has 3D bounds, indicating that it represents a volume (for example, a table or a cupboard). The bounds are described by \l offset3D and \l extent3D. Otherwise, it returns \c false. \sa offset3D, extent3D, has2DBounds */ bool QQuick3DXrSpatialAnchor::has3DBounds() const { return m_has3DBounds; } void QQuick3DXrSpatialAnchor::setBounds3D(const QVector3D &offset, const QVector3D &extent) { if (qFuzzyCompare(m_offset3D, offset) && qFuzzyCompare(m_extent3D, extent)) return; m_offset3D = offset; m_extent3D = extent; // FIXME: Store the 3D bounds and verify m_has3DBounds = true; emit has3DBoundsChanged(); } /*! \qmlproperty vector2d XrSpatialAnchor::offset2D \brief The 2D offset of the spatial anchor. \readonly This property holds the offset of the anchor's bounds within the X/Z plane. It is valid when \l has2DBounds is \c true. \sa has2DBounds, extent2D */ QVector2D QQuick3DXrSpatialAnchor::offset2D() const { return m_offset2D; } /*! \qmlproperty vector2d XrSpatialAnchor::extent2D \brief The 2D extent of the spatial anchor. \readonly This property holds the spatial anchor's size in two dimensions (width and height) within the X/Z plane. It is valid when \l has2DBounds is \c true. \sa has2DBounds, offset2D */ QVector2D QQuick3DXrSpatialAnchor::extent2D() const { return m_extent2D; } /*! \qmlproperty string XrSpatialAnchor::identifier \brief A unique identifier for this spatial anchor. \readonly This property holds a unique identifier associated with the spatial anchor. This is the same identifier referenced by a \l XrSpatialAnchorListModel. */ QString QQuick3DXrSpatialAnchor::identifier() const { return QString::fromLatin1(m_uuid.toRfc4122()); } QSet QQuick3DXrSpatialAnchor::roomLayoutUuids() const { return m_roomLayoutUuids; } void QQuick3DXrSpatialAnchor::setRoomLayoutUuids(const QSet &newRoomLayoutUuids) { m_roomLayoutUuids = newRoomLayoutUuids; } QSet QQuick3DXrSpatialAnchor::spaceContainerUuids() const { return m_spaceContainerUuids; } void QQuick3DXrSpatialAnchor::setSpaceContainerUuids(const QSet &newSpaceContainerUuids) { m_spaceContainerUuids = newSpaceContainerUuids; } QT_END_NAMESPACE