From 5903cc995c701b38002a639482ee7ffb0e3cee8a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Ko=C5=88a=C5=99=C3=ADk?= Date: Tue, 17 Dec 2024 20:54:04 +0100 Subject: [PATCH] Split point cloud index into implementation & wrapper --- .../core/auto_additions/qgspointcloudindex.py | 24 ++ .../pointcloud/qgspointcloudindex.sip.in | 366 ++++++++++++++++++ python/PyQt6/core/core_auto.sip | 1 + .../core/auto_additions/qgspointcloudindex.py | 24 ++ .../pointcloud/qgspointcloudindex.sip.in | 366 ++++++++++++++++++ python/core/core_auto.sip | 1 + src/3d/qgspointcloudlayerchunkloader_p.cpp | 34 +- src/3d/qgspointcloudlayerchunkloader_p.h | 6 +- src/3d/qgsvirtualpointcloudentity_p.h | 1 - src/3d/symbols/qgspointcloud3dsymbol_p.cpp | 30 +- src/3d/symbols/qgspointcloud3dsymbol_p.h | 20 +- .../qgscopcpointcloudblockrequest.cpp | 3 +- .../pointcloud/qgscopcpointcloudindex.cpp | 36 +- src/core/pointcloud/qgscopcpointcloudindex.h | 16 +- .../qgseptpointcloudblockrequest.cpp | 2 +- src/core/pointcloud/qgseptpointcloudindex.cpp | 27 +- src/core/pointcloud/qgseptpointcloudindex.h | 8 +- .../pointcloud/qgspointclouddataprovider.cpp | 42 +- .../pointcloud/qgspointclouddataprovider.h | 6 +- src/core/pointcloud/qgspointcloudindex.cpp | 229 ++++++++++- src/core/pointcloud/qgspointcloudindex.h | 300 +++++++++++++- src/core/pointcloud/qgspointcloudlayer.cpp | 7 +- .../pointcloud/qgspointcloudlayerexporter.cpp | 20 +- .../pointcloud/qgspointcloudlayerexporter.h | 2 +- .../qgspointcloudlayerprofilegenerator.cpp | 42 +- .../qgspointcloudlayerprofilegenerator.h | 6 +- .../pointcloud/qgspointcloudlayerrenderer.cpp | 55 ++- .../pointcloud/qgspointcloudlayerrenderer.h | 10 +- .../qgspointcloudstatscalculationtask.cpp | 2 +- .../qgspointcloudstatscalculationtask.h | 2 +- .../qgspointcloudstatscalculator.cpp | 30 +- .../pointcloud/qgspointcloudstatscalculator.h | 6 +- src/core/pointcloud/qgspointcloudsubindex.h | 8 +- src/core/providers/copc/qgscopcprovider.cpp | 32 +- src/core/providers/copc/qgscopcprovider.h | 4 +- src/core/providers/ept/qgseptprovider.cpp | 28 +- src/core/providers/ept/qgseptprovider.h | 4 +- .../vpc/qgsvirtualpointcloudprovider.cpp | 12 +- .../vpc/qgsvirtualpointcloudprovider.h | 3 +- src/providers/pdal/qgspdalprovider.cpp | 26 +- src/providers/pdal/qgspdalprovider.h | 4 +- tests/src/providers/testqgscopcprovider.cpp | 68 ++-- tests/src/providers/testqgseptprovider.cpp | 62 +-- .../testqgsvirtualpointcloudprovider.cpp | 6 +- 44 files changed, 1602 insertions(+), 379 deletions(-) create mode 100644 python/PyQt6/core/auto_additions/qgspointcloudindex.py create mode 100644 python/PyQt6/core/auto_generated/pointcloud/qgspointcloudindex.sip.in create mode 100644 python/core/auto_additions/qgspointcloudindex.py create mode 100644 python/core/auto_generated/pointcloud/qgspointcloudindex.sip.in diff --git a/python/PyQt6/core/auto_additions/qgspointcloudindex.py b/python/PyQt6/core/auto_additions/qgspointcloudindex.py new file mode 100644 index 0000000000000..0066303eb8510 --- /dev/null +++ b/python/PyQt6/core/auto_additions/qgspointcloudindex.py @@ -0,0 +1,24 @@ +# The following has been generated automatically from src/core/pointcloud/qgspointcloudindex.h +# monkey patching scoped based enum +QgsPointCloudAccessType.Local.__doc__ = "Local means the source is a local file on the machine" +QgsPointCloudAccessType.Remote.__doc__ = "Remote means it's loaded through a protocol like HTTP" +QgsPointCloudAccessType.__doc__ = """The access type of the data, local is for local files and remote for remote files (over HTTP) + +* ``Local``: Local means the source is a local file on the machine +* ``Remote``: Remote means it's loaded through a protocol like HTTP + +""" +# -- +try: + QgsPointCloudNodeId.fromString = staticmethod(QgsPointCloudNodeId.fromString) + QgsPointCloudNodeId.__group__ = ['pointcloud'] +except (NameError, AttributeError): + pass +try: + QgsPointCloudNode.__group__ = ['pointcloud'] +except (NameError, AttributeError): + pass +try: + QgsPointCloudIndex.__group__ = ['pointcloud'] +except (NameError, AttributeError): + pass diff --git a/python/PyQt6/core/auto_generated/pointcloud/qgspointcloudindex.sip.in b/python/PyQt6/core/auto_generated/pointcloud/qgspointcloudindex.sip.in new file mode 100644 index 0000000000000..d7fb1ae04b7a6 --- /dev/null +++ b/python/PyQt6/core/auto_generated/pointcloud/qgspointcloudindex.sip.in @@ -0,0 +1,366 @@ +/************************************************************************ + * This file has been generated automatically from * + * * + * src/core/pointcloud/qgspointcloudindex.h * + * * + * Do not edit manually ! Edit header and run scripts/sipify.py again * + ************************************************************************/ + + + + + + + +class QgsPointCloudNodeId +{ +%Docstring(signature="appended") + +Represents a indexed point cloud node's position in octree + +.. note:: + + The API is considered EXPERIMENTAL and can be changed without a notice + +.. versionadded:: 3.18 +%End + +%TypeHeaderCode +#include "qgspointcloudindex.h" +%End + public: + QgsPointCloudNodeId(); +%Docstring +Constructs invalid node +%End + QgsPointCloudNodeId( int _d, int _x, int _y, int _z ); +%Docstring +Constructs valid node +%End + + bool isValid() const; +%Docstring +Returns whether node is valid +%End + + + bool operator==( QgsPointCloudNodeId other ) const; + + QgsPointCloudNodeId parentNode() const; +%Docstring +Returns the parent of the node + +.. versionadded:: 3.20 +%End + + static QgsPointCloudNodeId fromString( const QString &str ); +%Docstring +Creates node from string +%End + + QString toString() const; +%Docstring +Encode node to string +%End + + int d() const; +%Docstring +Returns d +%End + + int x() const; +%Docstring +Returns x +%End + + int y() const; +%Docstring +Returns y +%End + + int z() const; +%Docstring +Returns z +%End + +}; + + +uint qHash( QgsPointCloudNodeId id ); +%Docstring +Hash function for indexed nodes +%End + + +class QgsPointCloudNode +{ +%Docstring(signature="appended") + +Keeps metadata for indexed point cloud node + +.. note:: + + The API is considered EXPERIMENTAL and can be changed without a notice + +.. versionadded:: 3.42 +%End + +%TypeHeaderCode +#include "qgspointcloudindex.h" +%End + public: + + QgsPointCloudNode( const QgsPointCloudNodeId &id, + qint64 pointCount, + const QList &childIds, + float error, + const QgsBox3D &bounds ); +%Docstring +Constructs new node object. Should only be called by :py:func:`QgsAbstractPointCloudIndex.getNode()`. +Bounds should always be computed by :py:func:`QgsPointCloudNode.bounds()`. +%End + QgsPointCloudNodeId id() const; +%Docstring +Returns node's ID (unique in index) +%End + qint64 pointCount() const; +%Docstring +Returns number of points contained in node data +%End + QList children() const; +%Docstring +Returns IDs of child nodes +%End + float error() const; +%Docstring +Returns node's error in map units (used to determine in whether the node has enough detail for the current view) +%End + QgsBox3D bounds() const; +%Docstring +Returns node's bounding cube in CRS coords +%End + + static QgsBox3D bounds( QgsBox3D rootBounds, QgsPointCloudNodeId id ); +%Docstring +Returns bounding box of specific node +%End + +}; + +enum class QgsPointCloudAccessType +{ + Local, + Remote +}; + + + + +class QgsPointCloudIndex /NoDefaultCtors/ +{ +%Docstring(signature="appended") +Smart pointer for :py:class:`QgsAbstractPointCloudIndex` + +This is a wrapper for :py:class:`QgsAbstractPointCloudIndex`, an index for point cloud +layers. It contains a shared_pointer, ensuring that concurrent access to the +index is memory safe. + +.. versionadded:: 3.42 +%End + +%TypeHeaderCode +#include "qgspointcloudindex.h" +%End + public: + + operator bool() const; + + void load( const QString &fileName ); +%Docstring +Loads the index from the file + +.. seealso:: :py:func:`QgsAbstractPointCloudIndex.load` +%End + + bool isValid() const; +%Docstring +Returns whether index is loaded and valid + +.. seealso:: :py:func:`QgsAbstractPointCloudIndex.isValid` +%End + + QString error() const; +%Docstring +Returns the error that occurred during the loading of the index. + +.. seealso:: :py:func:`QgsAbstractPointCloudIndex.error` +%End + + QgsPointCloudAccessType accessType() const; +%Docstring +Returns the access type of the data +If the access type is Remote, data will be fetched from an HTTP server either synchronously or asynchronously +If the access type is local, the data is stored locally as a file and will only be fetch synchronously ( blocking request with nodeData only ) + +.. note:: + + Always make sure to check before trying to use asyncNodeData since it is not supported in the case of local access type + +.. seealso:: :py:func:`QgsAbstractPointCloudIndex.accessType` +%End + + QgsCoordinateReferenceSystem crs() const; +%Docstring +Returns the coordinate reference system of the point cloud index + +.. seealso:: :py:func:`QgsAbstractPointCloudIndex.crs` +%End + + qint64 pointCount() const; +%Docstring +Returns the number of points in the point cloud + +.. seealso:: :py:func:`QgsAbstractPointCloudIndex.pointCount` +%End + + QVariantMap originalMetadata() const; +%Docstring +Returns the original metadata map + +.. seealso:: :py:func:`QgsAbstractPointCloudIndex.originalMetadata` +%End + + QgsPointCloudStatistics metadataStatistics() const; +%Docstring +Returns the object containing the statistics metadata extracted from the dataset + +.. seealso:: :py:func:`QgsAbstractPointCloudIndex.metadataStatistics` +%End + + bool writeStatistics( QgsPointCloudStatistics &stats ); +%Docstring +Writes the statistics object ``stats`` into the backing file, if possible. +Returns true if the data was written successfully. + +.. seealso:: :py:func:`QgsAbstractPointCloudIndex.writeStatistics` +%End + + QgsPointCloudNodeId root() const; +%Docstring +Returns root node of the index + +.. seealso:: :py:func:`QgsAbstractPointCloudIndex.root` +%End + + bool hasNode( const QgsPointCloudNodeId &id ) const; +%Docstring +Returns whether the octree contain given node + +.. seealso:: :py:func:`QgsAbstractPointCloudIndex.hasNode` +%End + + QgsPointCloudNode getNode( const QgsPointCloudNodeId &id ) const; +%Docstring +Returns object for a given node + +.. seealso:: :py:func:`QgsAbstractPointCloudIndex.getNode` +%End + + QgsPointCloudAttributeCollection attributes() const; +%Docstring +Returns all attributes that are stored in the file + +.. seealso:: :py:func:`QgsAbstractPointCloudIndex.attributes` +%End + + + + QgsRectangle extent() const; +%Docstring +Returns extent of the data + +.. seealso:: :py:func:`QgsAbstractPointCloudIndex.extent` +%End + + double zMin() const; +%Docstring +Returns z min + +.. seealso:: :py:func:`QgsAbstractPointCloudIndex.zMin` +%End + + double zMax() const; +%Docstring +Returns z max + +.. seealso:: :py:func:`QgsAbstractPointCloudIndex.zMax` +%End + + QgsBox3D rootNodeBounds() const; +%Docstring +Returns bounding box of root node in CRS coords + +.. seealso:: :py:func:`QgsAbstractPointCloudIndex.rootNodeBounds` +%End + + QgsVector3D scale() const; +%Docstring +Returns scale of data relative to CRS + +.. seealso:: :py:func:`QgsAbstractPointCloudIndex.scale` +%End + + QgsVector3D offset() const; +%Docstring +Returns offset of data from CRS + +.. seealso:: :py:func:`QgsAbstractPointCloudIndex.offset` +%End + + int span() const; +%Docstring +Returns the number of points in one direction in a single node. + +.. seealso:: :py:func:`QgsAbstractPointCloudIndex.span` +%End + + bool setSubsetString( const QString &subset ); +%Docstring +Sets the string used to define a subset of the point cloud. + +:param subset: The subset string to be used in a ``:py:class:`QgsPointCloudExpression``` + +:return: true if the expression is parsed with no errors, false otherwise + +.. seealso:: :py:func:`QgsAbstractPointCloudIndex.setSubsetString` +%End + + QString subsetString() const; +%Docstring +Returns the string used to define a subset of the point cloud. + +:return: The subset string or null QString if not implemented by the provider + +.. seealso:: :py:func:`QgsAbstractPointCloudIndex.subsetString` +%End + + + + QVariantMap extraMetadata() const; +%Docstring +Returns extra metadata that's not accessible through the other methods +in an implementation-specific dynamic structure. + +.. seealso:: :py:func:`QgsAbstractPointCloudIndex.extraMetadata` +%End + +}; + + +/************************************************************************ + * This file has been generated automatically from * + * * + * src/core/pointcloud/qgspointcloudindex.h * + * * + * Do not edit manually ! Edit header and run scripts/sipify.py again * + ************************************************************************/ diff --git a/python/PyQt6/core/core_auto.sip b/python/PyQt6/core/core_auto.sip index cf68113b49dca..6e2e4f37d7b79 100644 --- a/python/PyQt6/core/core_auto.sip +++ b/python/PyQt6/core/core_auto.sip @@ -515,6 +515,7 @@ %Include auto_generated/pointcloud/qgspointcloudblock.sip %Include auto_generated/pointcloud/qgspointcloudlayer.sip %Include auto_generated/pointcloud/qgspointcloudlayerelevationproperties.sip +%Include auto_generated/pointcloud/qgspointcloudindex.sip %Include auto_generated/pointcloud/qgspointclouddataprovider.sip %Include auto_generated/pointcloud/qgspointcloudrenderer.sip %Include auto_generated/pointcloud/qgspointcloudrendererregistry.sip diff --git a/python/core/auto_additions/qgspointcloudindex.py b/python/core/auto_additions/qgspointcloudindex.py new file mode 100644 index 0000000000000..0066303eb8510 --- /dev/null +++ b/python/core/auto_additions/qgspointcloudindex.py @@ -0,0 +1,24 @@ +# The following has been generated automatically from src/core/pointcloud/qgspointcloudindex.h +# monkey patching scoped based enum +QgsPointCloudAccessType.Local.__doc__ = "Local means the source is a local file on the machine" +QgsPointCloudAccessType.Remote.__doc__ = "Remote means it's loaded through a protocol like HTTP" +QgsPointCloudAccessType.__doc__ = """The access type of the data, local is for local files and remote for remote files (over HTTP) + +* ``Local``: Local means the source is a local file on the machine +* ``Remote``: Remote means it's loaded through a protocol like HTTP + +""" +# -- +try: + QgsPointCloudNodeId.fromString = staticmethod(QgsPointCloudNodeId.fromString) + QgsPointCloudNodeId.__group__ = ['pointcloud'] +except (NameError, AttributeError): + pass +try: + QgsPointCloudNode.__group__ = ['pointcloud'] +except (NameError, AttributeError): + pass +try: + QgsPointCloudIndex.__group__ = ['pointcloud'] +except (NameError, AttributeError): + pass diff --git a/python/core/auto_generated/pointcloud/qgspointcloudindex.sip.in b/python/core/auto_generated/pointcloud/qgspointcloudindex.sip.in new file mode 100644 index 0000000000000..d7fb1ae04b7a6 --- /dev/null +++ b/python/core/auto_generated/pointcloud/qgspointcloudindex.sip.in @@ -0,0 +1,366 @@ +/************************************************************************ + * This file has been generated automatically from * + * * + * src/core/pointcloud/qgspointcloudindex.h * + * * + * Do not edit manually ! Edit header and run scripts/sipify.py again * + ************************************************************************/ + + + + + + + +class QgsPointCloudNodeId +{ +%Docstring(signature="appended") + +Represents a indexed point cloud node's position in octree + +.. note:: + + The API is considered EXPERIMENTAL and can be changed without a notice + +.. versionadded:: 3.18 +%End + +%TypeHeaderCode +#include "qgspointcloudindex.h" +%End + public: + QgsPointCloudNodeId(); +%Docstring +Constructs invalid node +%End + QgsPointCloudNodeId( int _d, int _x, int _y, int _z ); +%Docstring +Constructs valid node +%End + + bool isValid() const; +%Docstring +Returns whether node is valid +%End + + + bool operator==( QgsPointCloudNodeId other ) const; + + QgsPointCloudNodeId parentNode() const; +%Docstring +Returns the parent of the node + +.. versionadded:: 3.20 +%End + + static QgsPointCloudNodeId fromString( const QString &str ); +%Docstring +Creates node from string +%End + + QString toString() const; +%Docstring +Encode node to string +%End + + int d() const; +%Docstring +Returns d +%End + + int x() const; +%Docstring +Returns x +%End + + int y() const; +%Docstring +Returns y +%End + + int z() const; +%Docstring +Returns z +%End + +}; + + +uint qHash( QgsPointCloudNodeId id ); +%Docstring +Hash function for indexed nodes +%End + + +class QgsPointCloudNode +{ +%Docstring(signature="appended") + +Keeps metadata for indexed point cloud node + +.. note:: + + The API is considered EXPERIMENTAL and can be changed without a notice + +.. versionadded:: 3.42 +%End + +%TypeHeaderCode +#include "qgspointcloudindex.h" +%End + public: + + QgsPointCloudNode( const QgsPointCloudNodeId &id, + qint64 pointCount, + const QList &childIds, + float error, + const QgsBox3D &bounds ); +%Docstring +Constructs new node object. Should only be called by :py:func:`QgsAbstractPointCloudIndex.getNode()`. +Bounds should always be computed by :py:func:`QgsPointCloudNode.bounds()`. +%End + QgsPointCloudNodeId id() const; +%Docstring +Returns node's ID (unique in index) +%End + qint64 pointCount() const; +%Docstring +Returns number of points contained in node data +%End + QList children() const; +%Docstring +Returns IDs of child nodes +%End + float error() const; +%Docstring +Returns node's error in map units (used to determine in whether the node has enough detail for the current view) +%End + QgsBox3D bounds() const; +%Docstring +Returns node's bounding cube in CRS coords +%End + + static QgsBox3D bounds( QgsBox3D rootBounds, QgsPointCloudNodeId id ); +%Docstring +Returns bounding box of specific node +%End + +}; + +enum class QgsPointCloudAccessType +{ + Local, + Remote +}; + + + + +class QgsPointCloudIndex /NoDefaultCtors/ +{ +%Docstring(signature="appended") +Smart pointer for :py:class:`QgsAbstractPointCloudIndex` + +This is a wrapper for :py:class:`QgsAbstractPointCloudIndex`, an index for point cloud +layers. It contains a shared_pointer, ensuring that concurrent access to the +index is memory safe. + +.. versionadded:: 3.42 +%End + +%TypeHeaderCode +#include "qgspointcloudindex.h" +%End + public: + + operator bool() const; + + void load( const QString &fileName ); +%Docstring +Loads the index from the file + +.. seealso:: :py:func:`QgsAbstractPointCloudIndex.load` +%End + + bool isValid() const; +%Docstring +Returns whether index is loaded and valid + +.. seealso:: :py:func:`QgsAbstractPointCloudIndex.isValid` +%End + + QString error() const; +%Docstring +Returns the error that occurred during the loading of the index. + +.. seealso:: :py:func:`QgsAbstractPointCloudIndex.error` +%End + + QgsPointCloudAccessType accessType() const; +%Docstring +Returns the access type of the data +If the access type is Remote, data will be fetched from an HTTP server either synchronously or asynchronously +If the access type is local, the data is stored locally as a file and will only be fetch synchronously ( blocking request with nodeData only ) + +.. note:: + + Always make sure to check before trying to use asyncNodeData since it is not supported in the case of local access type + +.. seealso:: :py:func:`QgsAbstractPointCloudIndex.accessType` +%End + + QgsCoordinateReferenceSystem crs() const; +%Docstring +Returns the coordinate reference system of the point cloud index + +.. seealso:: :py:func:`QgsAbstractPointCloudIndex.crs` +%End + + qint64 pointCount() const; +%Docstring +Returns the number of points in the point cloud + +.. seealso:: :py:func:`QgsAbstractPointCloudIndex.pointCount` +%End + + QVariantMap originalMetadata() const; +%Docstring +Returns the original metadata map + +.. seealso:: :py:func:`QgsAbstractPointCloudIndex.originalMetadata` +%End + + QgsPointCloudStatistics metadataStatistics() const; +%Docstring +Returns the object containing the statistics metadata extracted from the dataset + +.. seealso:: :py:func:`QgsAbstractPointCloudIndex.metadataStatistics` +%End + + bool writeStatistics( QgsPointCloudStatistics &stats ); +%Docstring +Writes the statistics object ``stats`` into the backing file, if possible. +Returns true if the data was written successfully. + +.. seealso:: :py:func:`QgsAbstractPointCloudIndex.writeStatistics` +%End + + QgsPointCloudNodeId root() const; +%Docstring +Returns root node of the index + +.. seealso:: :py:func:`QgsAbstractPointCloudIndex.root` +%End + + bool hasNode( const QgsPointCloudNodeId &id ) const; +%Docstring +Returns whether the octree contain given node + +.. seealso:: :py:func:`QgsAbstractPointCloudIndex.hasNode` +%End + + QgsPointCloudNode getNode( const QgsPointCloudNodeId &id ) const; +%Docstring +Returns object for a given node + +.. seealso:: :py:func:`QgsAbstractPointCloudIndex.getNode` +%End + + QgsPointCloudAttributeCollection attributes() const; +%Docstring +Returns all attributes that are stored in the file + +.. seealso:: :py:func:`QgsAbstractPointCloudIndex.attributes` +%End + + + + QgsRectangle extent() const; +%Docstring +Returns extent of the data + +.. seealso:: :py:func:`QgsAbstractPointCloudIndex.extent` +%End + + double zMin() const; +%Docstring +Returns z min + +.. seealso:: :py:func:`QgsAbstractPointCloudIndex.zMin` +%End + + double zMax() const; +%Docstring +Returns z max + +.. seealso:: :py:func:`QgsAbstractPointCloudIndex.zMax` +%End + + QgsBox3D rootNodeBounds() const; +%Docstring +Returns bounding box of root node in CRS coords + +.. seealso:: :py:func:`QgsAbstractPointCloudIndex.rootNodeBounds` +%End + + QgsVector3D scale() const; +%Docstring +Returns scale of data relative to CRS + +.. seealso:: :py:func:`QgsAbstractPointCloudIndex.scale` +%End + + QgsVector3D offset() const; +%Docstring +Returns offset of data from CRS + +.. seealso:: :py:func:`QgsAbstractPointCloudIndex.offset` +%End + + int span() const; +%Docstring +Returns the number of points in one direction in a single node. + +.. seealso:: :py:func:`QgsAbstractPointCloudIndex.span` +%End + + bool setSubsetString( const QString &subset ); +%Docstring +Sets the string used to define a subset of the point cloud. + +:param subset: The subset string to be used in a ``:py:class:`QgsPointCloudExpression``` + +:return: true if the expression is parsed with no errors, false otherwise + +.. seealso:: :py:func:`QgsAbstractPointCloudIndex.setSubsetString` +%End + + QString subsetString() const; +%Docstring +Returns the string used to define a subset of the point cloud. + +:return: The subset string or null QString if not implemented by the provider + +.. seealso:: :py:func:`QgsAbstractPointCloudIndex.subsetString` +%End + + + + QVariantMap extraMetadata() const; +%Docstring +Returns extra metadata that's not accessible through the other methods +in an implementation-specific dynamic structure. + +.. seealso:: :py:func:`QgsAbstractPointCloudIndex.extraMetadata` +%End + +}; + + +/************************************************************************ + * This file has been generated automatically from * + * * + * src/core/pointcloud/qgspointcloudindex.h * + * * + * Do not edit manually ! Edit header and run scripts/sipify.py again * + ************************************************************************/ diff --git a/python/core/core_auto.sip b/python/core/core_auto.sip index cf68113b49dca..6e2e4f37d7b79 100644 --- a/python/core/core_auto.sip +++ b/python/core/core_auto.sip @@ -515,6 +515,7 @@ %Include auto_generated/pointcloud/qgspointcloudblock.sip %Include auto_generated/pointcloud/qgspointcloudlayer.sip %Include auto_generated/pointcloud/qgspointcloudlayerelevationproperties.sip +%Include auto_generated/pointcloud/qgspointcloudindex.sip %Include auto_generated/pointcloud/qgspointclouddataprovider.sip %Include auto_generated/pointcloud/qgspointcloudrenderer.sip %Include auto_generated/pointcloud/qgspointcloudrendererregistry.sip diff --git a/src/3d/qgspointcloudlayerchunkloader_p.cpp b/src/3d/qgspointcloudlayerchunkloader_p.cpp index d1da768719e66..994f72df985e7 100644 --- a/src/3d/qgspointcloudlayerchunkloader_p.cpp +++ b/src/3d/qgspointcloudlayerchunkloader_p.cpp @@ -52,13 +52,13 @@ QgsPointCloudLayerChunkLoader::QgsPointCloudLayerChunkLoader( const QgsPointClou , mFactory( factory ) , mContext( factory->mRenderContext, coordinateTransform, std::move( symbol ), zValueScale, zValueOffset ) { - QgsPointCloudIndex *pc = mFactory->mPointCloudIndex; - mContext.setAttributes( pc->attributes() ); + QgsPointCloudIndex pc = mFactory->mPointCloudIndex; + mContext.setAttributes( pc.attributes() ); const QgsChunkNodeId nodeId = node->tileId(); const QgsPointCloudNodeId pcNode( nodeId.d, nodeId.x, nodeId.y, nodeId.z ); - Q_ASSERT( pc->hasNode( pcNode ) ); + Q_ASSERT( pc.hasNode( pcNode ) ); QgsDebugMsgLevel( QStringLiteral( "loading entity %1" ).arg( node->tileId().text() ), 2 ); @@ -124,10 +124,10 @@ void QgsPointCloudLayerChunkLoader::cancel() Qt3DCore::QEntity *QgsPointCloudLayerChunkLoader::createEntity( Qt3DCore::QEntity *parent ) { - QgsPointCloudIndex *pc = mFactory->mPointCloudIndex; + QgsPointCloudIndex pc = mFactory->mPointCloudIndex; const QgsChunkNodeId nodeId = mNode->tileId(); const QgsPointCloudNodeId pcNode( nodeId.d, nodeId.x, nodeId.y, nodeId.z ); - Q_ASSERT( pc->hasNode( pcNode ) ); + Q_ASSERT( pc.hasNode( pcNode ) ); Qt3DCore::QEntity *entity = new Qt3DCore::QEntity( parent ); mHandler->finalize( entity, mContext ); @@ -137,7 +137,7 @@ Qt3DCore::QEntity *QgsPointCloudLayerChunkLoader::createEntity( Qt3DCore::QEntit /////////////// -QgsPointCloudLayerChunkLoaderFactory::QgsPointCloudLayerChunkLoaderFactory( const Qgs3DRenderContext &context, const QgsCoordinateTransform &coordinateTransform, QgsPointCloudIndex *pc, QgsPointCloud3DSymbol *symbol, double zValueScale, double zValueOffset, int pointBudget ) +QgsPointCloudLayerChunkLoaderFactory::QgsPointCloudLayerChunkLoaderFactory( const Qgs3DRenderContext &context, const QgsCoordinateTransform &coordinateTransform, QgsPointCloudIndex pc, QgsPointCloud3DSymbol *symbol, double zValueScale, double zValueOffset, int pointBudget ) : mRenderContext( context ) , mCoordinateTransform( coordinateTransform ) , mPointCloudIndex( pc ) @@ -162,7 +162,7 @@ QgsChunkLoader *QgsPointCloudLayerChunkLoaderFactory::createChunkLoader( QgsChun { const QgsChunkNodeId id = node->tileId(); - Q_ASSERT( mPointCloudIndex->hasNode( QgsPointCloudNodeId( id.d, id.x, id.y, id.z ) ) ); + Q_ASSERT( mPointCloudIndex.hasNode( QgsPointCloudNodeId( id.d, id.x, id.y, id.z ) ) ); QgsPointCloud3DSymbol *symbol = static_cast( mSymbol->clone() ); return new QgsPointCloudLayerChunkLoader( this, node, std::unique_ptr( symbol ), mCoordinateTransform, mZValueScale, mZValueOffset ); } @@ -171,8 +171,8 @@ int QgsPointCloudLayerChunkLoaderFactory::primitivesCount( QgsChunkNode *node ) { const QgsChunkNodeId id = node->tileId(); const QgsPointCloudNodeId n( id.d, id.x, id.y, id.z ); - Q_ASSERT( mPointCloudIndex->hasNode( n ) ); - return mPointCloudIndex->getNode( n ).pointCount(); + Q_ASSERT( mPointCloudIndex.hasNode( n ) ); + return mPointCloudIndex.getNode( n ).pointCount(); } @@ -197,7 +197,7 @@ static QgsBox3D nodeBoundsToBox3D( QgsBox3D nodeBounds, const QgsCoordinateTrans QgsChunkNode *QgsPointCloudLayerChunkLoaderFactory::createRootNode() const { - const QgsPointCloudNode pcNode = mPointCloudIndex->getNode( mPointCloudIndex->root() ); + const QgsPointCloudNode pcNode = mPointCloudIndex.getNode( mPointCloudIndex.root() ); const QgsBox3D rootNodeBounds = pcNode.bounds(); QgsBox3D rootNodeBox3D = nodeBoundsToBox3D( rootNodeBounds, mCoordinateTransform, mZValueOffset, mZValueScale ); @@ -218,9 +218,9 @@ QVector QgsPointCloudLayerChunkLoaderFactory::createChildren( Qg int dx = i & 1, dy = !!( i & 2 ), dz = !!( i & 4 ); const QgsChunkNodeId childId( nodeId.d + 1, nodeId.x * 2 + dx, nodeId.y * 2 + dy, nodeId.z * 2 + dz ); const QgsPointCloudNodeId childPcId( childId.d, childId.x, childId.y, childId.z ); - if ( !mPointCloudIndex->hasNode( childPcId ) ) + if ( !mPointCloudIndex.hasNode( childPcId ) ) continue; - const QgsPointCloudNode childNode = mPointCloudIndex->getNode( childPcId ); + const QgsPointCloudNode childNode = mPointCloudIndex.getNode( childPcId ); const QgsBox3D childBounds = childNode.bounds(); if ( !mExtent.isEmpty() && !childBounds.intersects( mExtent ) ) continue; @@ -237,7 +237,7 @@ QVector QgsPointCloudLayerChunkLoaderFactory::createChildren( Qg /////////////// -QgsPointCloudLayerChunkedEntity::QgsPointCloudLayerChunkedEntity( Qgs3DMapSettings *map, QgsPointCloudIndex *pc, const QgsCoordinateTransform &coordinateTransform, QgsPointCloud3DSymbol *symbol, float maximumScreenSpaceError, bool showBoundingBoxes, double zValueScale, double zValueOffset, int pointBudget ) +QgsPointCloudLayerChunkedEntity::QgsPointCloudLayerChunkedEntity( Qgs3DMapSettings *map, QgsPointCloudIndex pc, const QgsCoordinateTransform &coordinateTransform, QgsPointCloud3DSymbol *symbol, float maximumScreenSpaceError, bool showBoundingBoxes, double zValueScale, double zValueOffset, int pointBudget ) : QgsChunkedEntity( map, maximumScreenSpaceError, new QgsPointCloudLayerChunkLoaderFactory( Qgs3DRenderContext::fromMapSettings( map ), coordinateTransform, pc, symbol, zValueScale, zValueOffset, pointBudget ), true, pointBudget ) { setShowBoundingBoxes( showBoundingBoxes ); @@ -278,9 +278,9 @@ QVector QgsPointCloudLayerChunkedEntity::rayIntersec QgsVector3D adjustedRayDirection = QgsVector3D( rayDirectionMapCoords.x(), rayDirectionMapCoords.y(), rayDirectionMapCoords.z() / factory->mZValueScale ); adjustedRayDirection.normalize(); - QgsPointCloudIndex *index = factory->mPointCloudIndex; + QgsPointCloudIndex index = factory->mPointCloudIndex; - const QgsPointCloudAttributeCollection attributeCollection = index->attributes(); + const QgsPointCloudAttributeCollection attributeCollection = index.attributes(); QgsPointCloudRequest request; request.setAttributes( attributeCollection ); @@ -291,14 +291,14 @@ QVector QgsPointCloudLayerChunkedEntity::rayIntersec const QgsChunkNodeId id = node->tileId(); const QgsPointCloudNodeId n( id.d, id.x, id.y, id.z ); - if ( !index->hasNode( n ) ) + if ( !index.hasNode( n ) ) continue; const QgsAABB nodeBbox = Qgs3DUtils::mapToWorldExtent( node->box3D(), mMapSettings->origin() ); if ( !QgsRayCastingUtils::rayBoxIntersection( ray, nodeBbox ) ) continue; - std::unique_ptr block( index->nodeData( n, request ) ); + std::unique_ptr block( index.nodeData( n, request ) ); if ( !block ) continue; diff --git a/src/3d/qgspointcloudlayerchunkloader_p.h b/src/3d/qgspointcloudlayerchunkloader_p.h index 59c37cfc3fdd0..c575a2fc41c2c 100644 --- a/src/3d/qgspointcloudlayerchunkloader_p.h +++ b/src/3d/qgspointcloudlayerchunkloader_p.h @@ -63,7 +63,7 @@ class QgsPointCloudLayerChunkLoaderFactory : public QgsChunkLoaderFactory * Constructs the factory * The factory takes ownership over the passed \a symbol */ - QgsPointCloudLayerChunkLoaderFactory( const Qgs3DRenderContext &context, const QgsCoordinateTransform &coordinateTransform, QgsPointCloudIndex *pc, QgsPointCloud3DSymbol *symbol, double zValueScale, double zValueOffset, int pointBudget ); + QgsPointCloudLayerChunkLoaderFactory( const Qgs3DRenderContext &context, const QgsCoordinateTransform &coordinateTransform, QgsPointCloudIndex pc, QgsPointCloud3DSymbol *symbol, double zValueScale, double zValueOffset, int pointBudget ); //! Creates loader for the given chunk node. Ownership of the returned is passed to the caller. virtual QgsChunkLoader *createChunkLoader( QgsChunkNode *node ) const override; @@ -72,7 +72,7 @@ class QgsPointCloudLayerChunkLoaderFactory : public QgsChunkLoaderFactory virtual int primitivesCount( QgsChunkNode *node ) const override; Qgs3DRenderContext mRenderContext; QgsCoordinateTransform mCoordinateTransform; - QgsPointCloudIndex *mPointCloudIndex; + QgsPointCloudIndex mPointCloudIndex; std::unique_ptr mSymbol; double mZValueScale = 1.0; double mZValueOffset = 0; @@ -127,7 +127,7 @@ class QgsPointCloudLayerChunkedEntity : public QgsChunkedEntity { Q_OBJECT public: - explicit QgsPointCloudLayerChunkedEntity( Qgs3DMapSettings *map, QgsPointCloudIndex *pc, const QgsCoordinateTransform &coordinateTransform, QgsPointCloud3DSymbol *symbol, float maxScreenError, bool showBoundingBoxes, double zValueScale, double zValueOffset, int pointBudget ); + explicit QgsPointCloudLayerChunkedEntity( Qgs3DMapSettings *map, QgsPointCloudIndex pc, const QgsCoordinateTransform &coordinateTransform, QgsPointCloud3DSymbol *symbol, float maxScreenError, bool showBoundingBoxes, double zValueScale, double zValueOffset, int pointBudget ); QVector rayIntersection( const QgsRayCastingUtils::Ray3D &ray, const QgsRayCastingUtils::RayCastContext &context ) const override; diff --git a/src/3d/qgsvirtualpointcloudentity_p.h b/src/3d/qgsvirtualpointcloudentity_p.h index a28a0fd26b07b..6416f8ba2f75e 100644 --- a/src/3d/qgsvirtualpointcloudentity_p.h +++ b/src/3d/qgsvirtualpointcloudentity_p.h @@ -36,7 +36,6 @@ class QgsAABB; class QgsChunkBoundsEntity; class QgsPointCloudLayer; -class QgsPointCloudIndex; class QgsVirtualPointCloudProvider; class QgsPointCloud3DSymbol; class Qgs3DMapSettings; diff --git a/src/3d/symbols/qgspointcloud3dsymbol_p.cpp b/src/3d/symbols/qgspointcloud3dsymbol_p.cpp index 4c494714565de..0a8316b4c5198 100644 --- a/src/3d/symbols/qgspointcloud3dsymbol_p.cpp +++ b/src/3d/symbols/qgspointcloud3dsymbol_p.cpp @@ -57,9 +57,9 @@ typedef Qt3DCore::QGeometry Qt3DQGeometry; #include // pick a point that we'll use as origin for coordinates for this node's points -static QgsVector3D originFromNodeBounds( QgsPointCloudIndex *pc, const QgsPointCloudNodeId &n, const QgsPointCloud3DRenderContext &context ) +static QgsVector3D originFromNodeBounds( QgsPointCloudIndex pc, const QgsPointCloudNodeId &n, const QgsPointCloud3DRenderContext &context ) { - QgsBox3D bounds = pc->getNode( n ).bounds(); + QgsBox3D bounds = pc.getNode( n ).bounds(); double nodeOriginX = bounds.xMinimum(); double nodeOriginY = bounds.yMinimum(); double nodeOriginZ = bounds.zMinimum() * context.zValueScale() + context.zValueFixedOffset(); @@ -356,7 +356,7 @@ void QgsPointCloud3DSymbolHandler::makeEntity( Qt3DCore::QEntity *parent, const } -std::vector QgsPointCloud3DSymbolHandler::getVertices( QgsPointCloudIndex *pc, const QgsPointCloudNodeId &n, const QgsPointCloud3DRenderContext &context, const QgsBox3D &box3D ) +std::vector QgsPointCloud3DSymbolHandler::getVertices( QgsPointCloudIndex pc, const QgsPointCloudNodeId &n, const QgsPointCloud3DRenderContext &context, const QgsBox3D &box3D ) { bool hasColorData = !outNormal.colors.empty(); bool hasParameterData = !outNormal.parameter.empty(); @@ -374,7 +374,7 @@ std::vector QgsPointCloud3DSymbolHandler::getVertices( QgsPointCloudInde // next, we also need all points of all parents nodes to make the triangulation (also external points) QgsPointCloudNodeId parentNode = n.parentNode(); - double span = pc->span(); + double span = pc.span(); //factor to take account of the density of the point to calculate extension of the bounding box // with a usual value span = 128, bounding box is extended by 12.5 % on each side. double extraBoxFactor = 16 / span; @@ -516,7 +516,7 @@ void QgsPointCloud3DSymbolHandler::filterTriangles( const std::vector &t } } -void QgsPointCloud3DSymbolHandler::triangulate( QgsPointCloudIndex *pc, const QgsPointCloudNodeId &n, const QgsPointCloud3DRenderContext &context, const QgsBox3D &box3D ) +void QgsPointCloud3DSymbolHandler::triangulate( QgsPointCloudIndex pc, const QgsPointCloudNodeId &n, const QgsPointCloud3DRenderContext &context, const QgsBox3D &box3D ) { if ( outNormal.positions.isEmpty() ) return; @@ -543,22 +543,22 @@ void QgsPointCloud3DSymbolHandler::triangulate( QgsPointCloudIndex *pc, const Qg filterTriangles( triangleIndexes, context, box3D ); } -std::unique_ptr QgsPointCloud3DSymbolHandler::pointCloudBlock( QgsPointCloudIndex *pc, const QgsPointCloudNodeId &n, const QgsPointCloudRequest &request, const QgsPointCloud3DRenderContext &context ) +std::unique_ptr QgsPointCloud3DSymbolHandler::pointCloudBlock( QgsPointCloudIndex pc, const QgsPointCloudNodeId &n, const QgsPointCloudRequest &request, const QgsPointCloud3DRenderContext &context ) { std::unique_ptr block; - if ( pc->accessType() == QgsPointCloudIndex::AccessType::Local ) + if ( pc.accessType() == QgsPointCloudAccessType::Local ) { - block = pc->nodeData( n, request ); + block = pc.nodeData( n, request ); } - else if ( pc->accessType() == QgsPointCloudIndex::AccessType::Remote ) + else if ( pc.accessType() == QgsPointCloudAccessType::Remote ) { - QgsPointCloudNode node = pc->getNode( n ); + QgsPointCloudNode node = pc.getNode( n ); if ( node.pointCount() < 1 ) return block; bool loopAborted = false; QEventLoop loop; - QgsPointCloudBlockRequest *req = pc->asyncNodeData( n, request ); + QgsPointCloudBlockRequest *req = pc.asyncNodeData( n, request ); QObject::connect( req, &QgsPointCloudBlockRequest::finished, &loop, &QEventLoop::quit ); QObject::connect( context.feedback(), &QgsFeedback::canceled, &loop, [&]() { loopAborted = true; @@ -585,7 +585,7 @@ bool QgsSingleColorPointCloud3DSymbolHandler::prepare( const QgsPointCloud3DRend return true; } -void QgsSingleColorPointCloud3DSymbolHandler::processNode( QgsPointCloudIndex *pc, const QgsPointCloudNodeId &n, const QgsPointCloud3DRenderContext &context, PointData *output ) +void QgsSingleColorPointCloud3DSymbolHandler::processNode( QgsPointCloudIndex pc, const QgsPointCloudNodeId &n, const QgsPointCloud3DRenderContext &context, PointData *output ) { QgsPointCloudAttributeCollection attributes; attributes.push_back( QgsPointCloudAttribute( QStringLiteral( "X" ), QgsPointCloudAttribute::Int32 ) ); @@ -664,7 +664,7 @@ bool QgsColorRampPointCloud3DSymbolHandler::prepare( const QgsPointCloud3DRender return true; } -void QgsColorRampPointCloud3DSymbolHandler::processNode( QgsPointCloudIndex *pc, const QgsPointCloudNodeId &n, const QgsPointCloud3DRenderContext &context, PointData *output ) +void QgsColorRampPointCloud3DSymbolHandler::processNode( QgsPointCloudIndex pc, const QgsPointCloudNodeId &n, const QgsPointCloud3DRenderContext &context, PointData *output ) { QgsPointCloudAttributeCollection attributes; const int xOffset = 0; @@ -801,7 +801,7 @@ bool QgsRGBPointCloud3DSymbolHandler::prepare( const QgsPointCloud3DRenderContex return true; } -void QgsRGBPointCloud3DSymbolHandler::processNode( QgsPointCloudIndex *pc, const QgsPointCloudNodeId &n, const QgsPointCloud3DRenderContext &context, PointData *output ) +void QgsRGBPointCloud3DSymbolHandler::processNode( QgsPointCloudIndex pc, const QgsPointCloudNodeId &n, const QgsPointCloud3DRenderContext &context, PointData *output ) { QgsPointCloudAttributeCollection attributes; attributes.push_back( QgsPointCloudAttribute( QStringLiteral( "X" ), QgsPointCloudAttribute::Int32 ) ); @@ -945,7 +945,7 @@ bool QgsClassificationPointCloud3DSymbolHandler::prepare( const QgsPointCloud3DR return true; } -void QgsClassificationPointCloud3DSymbolHandler::processNode( QgsPointCloudIndex *pc, const QgsPointCloudNodeId &n, const QgsPointCloud3DRenderContext &context, PointData *output ) +void QgsClassificationPointCloud3DSymbolHandler::processNode( QgsPointCloudIndex pc, const QgsPointCloudNodeId &n, const QgsPointCloud3DRenderContext &context, PointData *output ) { QgsPointCloudAttributeCollection attributes; const int xOffset = 0; diff --git a/src/3d/symbols/qgspointcloud3dsymbol_p.h b/src/3d/symbols/qgspointcloud3dsymbol_p.h index 47b17d8ebbfd6..0b8bb01ea4329 100644 --- a/src/3d/symbols/qgspointcloud3dsymbol_p.h +++ b/src/3d/symbols/qgspointcloud3dsymbol_p.h @@ -44,11 +44,11 @@ class QgsPointCloud3DSymbolHandler struct PointData; - virtual bool prepare( const QgsPointCloud3DRenderContext &context ) = 0; // override; - virtual void processNode( QgsPointCloudIndex *pc, const QgsPointCloudNodeId &n, const QgsPointCloud3DRenderContext &context, PointData *output = nullptr ) = 0; // override; - virtual void finalize( Qt3DCore::QEntity *parent, const QgsPointCloud3DRenderContext &context ) = 0; // override; + virtual bool prepare( const QgsPointCloud3DRenderContext &context ) = 0; // override; + virtual void processNode( QgsPointCloudIndex pc, const QgsPointCloudNodeId &n, const QgsPointCloud3DRenderContext &context, PointData *output = nullptr ) = 0; // override; + virtual void finalize( Qt3DCore::QEntity *parent, const QgsPointCloud3DRenderContext &context ) = 0; // override; - void triangulate( QgsPointCloudIndex *pc, const QgsPointCloudNodeId &n, const QgsPointCloud3DRenderContext &context, const QgsBox3D &box3D ); + void triangulate( QgsPointCloudIndex pc, const QgsPointCloudNodeId &n, const QgsPointCloud3DRenderContext &context, const QgsBox3D &box3D ); float zMinimum() const { return mZMin; } float zMaximum() const { return mZMax; } @@ -76,14 +76,14 @@ class QgsPointCloud3DSymbolHandler #else virtual Qt3DCore::QGeometry *makeGeometry( Qt3DCore::QNode *parent, const QgsPointCloud3DSymbolHandler::PointData &data, unsigned int byteStride ) = 0; #endif - std::unique_ptr pointCloudBlock( QgsPointCloudIndex *pc, const QgsPointCloudNodeId &node, const QgsPointCloudRequest &request, const QgsPointCloud3DRenderContext &context ); + std::unique_ptr pointCloudBlock( QgsPointCloudIndex pc, const QgsPointCloudNodeId &node, const QgsPointCloudRequest &request, const QgsPointCloud3DRenderContext &context ); // outputs PointData outNormal; //!< Features that are not selected private: //! Returns all vertices of the node \a n, and of its parents contained in \a bbox and in an extension of this box depending of the density of the points - std::vector getVertices( QgsPointCloudIndex *pc, const QgsPointCloudNodeId &n, const QgsPointCloud3DRenderContext &context, const QgsBox3D &box3D ); + std::vector getVertices( QgsPointCloudIndex pc, const QgsPointCloudNodeId &n, const QgsPointCloud3DRenderContext &context, const QgsBox3D &box3D ); //! Calculates the normals of triangles dedined by index contained in \a triangles. Must be used only in the method triangulate(). void calculateNormals( const std::vector &triangles ); @@ -105,7 +105,7 @@ class QgsSingleColorPointCloud3DSymbolHandler : public QgsPointCloud3DSymbolHand QgsSingleColorPointCloud3DSymbolHandler(); bool prepare( const QgsPointCloud3DRenderContext &context ) override; - void processNode( QgsPointCloudIndex *pc, const QgsPointCloudNodeId &n, const QgsPointCloud3DRenderContext &context, PointData *output = nullptr ) override; + void processNode( QgsPointCloudIndex pc, const QgsPointCloudNodeId &n, const QgsPointCloud3DRenderContext &context, PointData *output = nullptr ) override; void finalize( Qt3DCore::QEntity *parent, const QgsPointCloud3DRenderContext &context ) override; private: @@ -122,7 +122,7 @@ class QgsColorRampPointCloud3DSymbolHandler : public QgsPointCloud3DSymbolHandle QgsColorRampPointCloud3DSymbolHandler(); bool prepare( const QgsPointCloud3DRenderContext &context ) override; - void processNode( QgsPointCloudIndex *pc, const QgsPointCloudNodeId &n, const QgsPointCloud3DRenderContext &context, PointData *output = nullptr ) override; + void processNode( QgsPointCloudIndex pc, const QgsPointCloudNodeId &n, const QgsPointCloud3DRenderContext &context, PointData *output = nullptr ) override; void finalize( Qt3DCore::QEntity *parent, const QgsPointCloud3DRenderContext &context ) override; private: @@ -139,7 +139,7 @@ class QgsRGBPointCloud3DSymbolHandler : public QgsPointCloud3DSymbolHandler QgsRGBPointCloud3DSymbolHandler(); bool prepare( const QgsPointCloud3DRenderContext &context ) override; - void processNode( QgsPointCloudIndex *pc, const QgsPointCloudNodeId &n, const QgsPointCloud3DRenderContext &context, PointData *output = nullptr ) override; + void processNode( QgsPointCloudIndex pc, const QgsPointCloudNodeId &n, const QgsPointCloud3DRenderContext &context, PointData *output = nullptr ) override; void finalize( Qt3DCore::QEntity *parent, const QgsPointCloud3DRenderContext &context ) override; private: @@ -156,7 +156,7 @@ class QgsClassificationPointCloud3DSymbolHandler : public QgsPointCloud3DSymbolH QgsClassificationPointCloud3DSymbolHandler(); bool prepare( const QgsPointCloud3DRenderContext &context ) override; - void processNode( QgsPointCloudIndex *pc, const QgsPointCloudNodeId &n, const QgsPointCloud3DRenderContext &context, PointData *output = nullptr ) override; + void processNode( QgsPointCloudIndex pc, const QgsPointCloudNodeId &n, const QgsPointCloud3DRenderContext &context, PointData *output = nullptr ) override; void finalize( Qt3DCore::QEntity *parent, const QgsPointCloud3DRenderContext &context ) override; private: diff --git a/src/core/pointcloud/qgscopcpointcloudblockrequest.cpp b/src/core/pointcloud/qgscopcpointcloudblockrequest.cpp index 8a93ea33c8779..f50ab95960b91 100644 --- a/src/core/pointcloud/qgscopcpointcloudblockrequest.cpp +++ b/src/core/pointcloud/qgscopcpointcloudblockrequest.cpp @@ -18,6 +18,7 @@ #include "qgscopcpointcloudblockrequest.h" #include "moc_qgscopcpointcloudblockrequest.cpp" +#include "qgspointcloudindex.h" #include "qgstiledownloadmanager.h" #include "qgslazdecoder.h" #include "qgsapplication.h" @@ -71,7 +72,7 @@ void QgsCopcPointCloudBlockRequest::blockFinishedLoading() QgsPointCloudRequest req; req.setAttributes( mRequestedAttributes ); req.setFilterRect( mFilterRect ); - QgsPointCloudIndex::storeNodeDataToCacheStatic( mBlock.get(), mNode, req, mFilterExpression, mUri ); + QgsAbstractPointCloudIndex::storeNodeDataToCacheStatic( mBlock.get(), mNode, req, mFilterExpression, mUri ); } catch ( std::exception &e ) { diff --git a/src/core/pointcloud/qgscopcpointcloudindex.cpp b/src/core/pointcloud/qgscopcpointcloudindex.cpp index c8a66af57992d..4ef2dd498282f 100644 --- a/src/core/pointcloud/qgscopcpointcloudindex.cpp +++ b/src/core/pointcloud/qgscopcpointcloudindex.cpp @@ -33,6 +33,7 @@ #include "qgslazdecoder.h" #include "qgscoordinatereferencesystem.h" #include "qgspointcloudblockrequest.h" +#include "qgspointcloudindex.h" #include "qgspointcloudrequest.h" #include "qgspointcloudattribute.h" #include "qgslogger.h" @@ -51,12 +52,12 @@ QgsCopcPointCloudIndex::QgsCopcPointCloudIndex() = default; QgsCopcPointCloudIndex::~QgsCopcPointCloudIndex() = default; -std::unique_ptr QgsCopcPointCloudIndex::clone() const +std::unique_ptr QgsCopcPointCloudIndex::clone() const { QgsCopcPointCloudIndex *clone = new QgsCopcPointCloudIndex; QMutexLocker locker( &mHierarchyMutex ); copyCommonProperties( clone ); - return std::unique_ptr( clone ); + return std::unique_ptr( clone ); } void QgsCopcPointCloudIndex::load( const QString &urlString ) @@ -64,10 +65,10 @@ void QgsCopcPointCloudIndex::load( const QString &urlString ) QUrl url = urlString; // Treat non-URLs as local files if ( url.isValid() && ( url.scheme() == "http" || url.scheme() == "https" ) ) - mAccessType = Remote; + mAccessType = QgsPointCloudAccessType::Remote; else { - mAccessType = Local; + mAccessType = QgsPointCloudAccessType::Local; mCopcFile.open( QgsLazDecoder::toNativePath( urlString ), std::ios::binary ); if ( mCopcFile.fail() ) { @@ -78,7 +79,7 @@ void QgsCopcPointCloudIndex::load( const QString &urlString ) } mUri = urlString; - if ( mAccessType == Remote ) + if ( mAccessType == QgsPointCloudAccessType::Remote ) mLazInfo.reset( new QgsLazInfo( QgsLazInfo::fromUrl( url ) ) ); else mLazInfo.reset( new QgsLazInfo( QgsLazInfo::fromFile( mCopcFile ) ) ); @@ -151,7 +152,7 @@ std::unique_ptr QgsCopcPointCloudIndex::nodeData( const QgsP } std::unique_ptr block; - if ( mAccessType == Local ) + if ( mAccessType == QgsPointCloudAccessType::Local ) { const bool found = fetchNodeHierarchy( n ); if ( !found ) @@ -204,7 +205,7 @@ std::unique_ptr QgsCopcPointCloudIndex::nodeData( const QgsP QgsPointCloudBlockRequest *QgsCopcPointCloudIndex::asyncNodeData( const QgsPointCloudNodeId &n, const QgsPointCloudRequest &request ) { - if ( mAccessType == Local ) + if ( mAccessType == QgsPointCloudAccessType::Local ) return nullptr; // TODO if ( QgsPointCloudBlock *cached = getNodeDataFromCache( n, request ) ) { @@ -248,7 +249,7 @@ bool QgsCopcPointCloudIndex::loadHierarchy() const bool QgsCopcPointCloudIndex::writeStatistics( QgsPointCloudStatistics &stats ) { - if ( mAccessType == Remote ) + if ( mAccessType == QgsPointCloudAccessType::Remote ) { QgsMessageLog::logMessage( QObject::tr( "Can't write statistics to remote file \"%1\"" ).arg( mUri ) ); return false; @@ -309,7 +310,7 @@ QgsPointCloudStatistics QgsCopcPointCloudIndex::metadataStatistics() const { const QByteArray statisticsEvlrData = fetchCopcStatisticsEvlrData(); if ( statisticsEvlrData.isEmpty() ) - mStatistics = QgsPointCloudIndex::metadataStatistics(); + mStatistics = QgsAbstractPointCloudIndex::metadataStatistics(); else mStatistics = QgsPointCloudStatistics::fromStatisticsJson( statisticsEvlrData ); } @@ -357,7 +358,7 @@ void QgsCopcPointCloudIndex::fetchHierarchyPage( uint64_t offset, uint64_t byteS switch ( mAccessType ) { - case Local: + case QgsPointCloudAccessType::Local: { mCopcFile.seekg( offset ); std::unique_ptr data( new char[ byteSize ] ); @@ -366,7 +367,7 @@ void QgsCopcPointCloudIndex::fetchHierarchyPage( uint64_t offset, uint64_t byteS populateHierarchy( data.get(), byteSize ); return; } - case Remote: + case QgsPointCloudAccessType::Remote: { QNetworkRequest nr = QNetworkRequest( QUrl( mUri ) ); QgsSetRequestInitiatorClass( nr, QStringLiteral( "QgsCopcPointCloudIndex" ) ); @@ -465,13 +466,13 @@ QgsPointCloudNode QgsCopcPointCloudIndex::getNode( const QgsPointCloudNodeId &id void QgsCopcPointCloudIndex::copyCommonProperties( QgsCopcPointCloudIndex *destination ) const { - QgsPointCloudIndex::copyCommonProperties( destination ); + QgsAbstractPointCloudIndex::copyCommonProperties( destination ); // QgsCopcPointCloudIndex specific fields destination->mIsValid = mIsValid; destination->mAccessType = mAccessType; destination->mUri = mUri; - if ( mAccessType == Local ) + if ( mAccessType == QgsPointCloudAccessType::Local ) destination->mCopcFile.open( QgsLazDecoder::toNativePath( mUri ), std::ios::binary ); destination->mCopcInfoVlr = mCopcInfoVlr; destination->mHierarchyNodePos = mHierarchyNodePos; @@ -481,7 +482,7 @@ void QgsCopcPointCloudIndex::copyCommonProperties( QgsCopcPointCloudIndex *desti QByteArray QgsCopcPointCloudIndex::fetchCopcStatisticsEvlrData() const { - Q_ASSERT( mAccessType == Local ); // TODO: Remote + Q_ASSERT( mAccessType == QgsPointCloudAccessType::Local ); // TODO: Remote uint64_t offset = mLazInfo->firstEvlrOffset(); uint32_t evlrCount = mLazInfo->evlrCount(); @@ -509,9 +510,12 @@ QByteArray QgsCopcPointCloudIndex::fetchCopcStatisticsEvlrData() const return statisticsEvlrData; } -bool QgsCopcPointCloudIndex::gpsTimeFlag() const +QVariantMap QgsCopcPointCloudIndex::extraMetadata() const { - return mLazInfo.get()->header().global_encoding & 1; + return + { + { QStringLiteral( "CopcGpsTimeFlag" ), mLazInfo.get()->header().global_encoding & 1 }, + }; } ///@endcond diff --git a/src/core/pointcloud/qgscopcpointcloudindex.h b/src/core/pointcloud/qgscopcpointcloudindex.h index 0eb3e715d07a1..9352c99e2e380 100644 --- a/src/core/pointcloud/qgscopcpointcloudindex.h +++ b/src/core/pointcloud/qgscopcpointcloudindex.h @@ -39,14 +39,14 @@ class QgsCoordinateReferenceSystem; -class CORE_EXPORT QgsCopcPointCloudIndex: public QgsPointCloudIndex +class CORE_EXPORT QgsCopcPointCloudIndex: public QgsAbstractPointCloudIndex { public: explicit QgsCopcPointCloudIndex(); ~QgsCopcPointCloudIndex(); - std::unique_ptr clone() const override; + std::unique_ptr clone() const override; void load( const QString &fileName ) override; @@ -61,14 +61,14 @@ class CORE_EXPORT QgsCopcPointCloudIndex: public QgsPointCloudIndex QVariantMap originalMetadata() const override { return mOriginalMetadata; } bool isValid() const override; - QgsPointCloudIndex::AccessType accessType() const override { return mAccessType; }; + QgsPointCloudAccessType accessType() const override { return mAccessType; }; /** * Writes the statistics object \a stats into the COPC dataset as an Extended Variable Length Record (EVLR). * Returns true if the data was written successfully. * \since QGIS 3.26 */ - bool writeStatistics( QgsPointCloudStatistics &stats ); + bool writeStatistics( QgsPointCloudStatistics &stats ) override; /** * Returns the statistics object contained in the COPC dataset. @@ -84,11 +84,11 @@ class CORE_EXPORT QgsCopcPointCloudIndex: public QgsPointCloudIndex void copyCommonProperties( QgsCopcPointCloudIndex *destination ) const; /** - * Returns the gps time flag from global_encoding field in LAS header, 0 indicates GPS week time (seconds passed since the beginning of the week) + * Returns one datapoint, "CopcGpsTimeFlag": The gps time flag from global_encoding field in LAS header, + * 0 indicates GPS week time (seconds passed since the beginning of the week) * 1 indicates GPS adjusted time, which is seconds passed since the GPS base time minus 1e9 - * \since QGIS 3.42 */ - bool gpsTimeFlag() const; + QVariantMap extraMetadata() const override; protected: bool loadSchema( QgsLazInfo &lazInfo ); @@ -107,7 +107,7 @@ class CORE_EXPORT QgsCopcPointCloudIndex: public QgsPointCloudIndex QByteArray fetchCopcStatisticsEvlrData() const; bool mIsValid = false; - QgsPointCloudIndex::AccessType mAccessType = Local; + QgsPointCloudAccessType mAccessType = QgsPointCloudAccessType::Local; mutable std::ifstream mCopcFile; mutable lazperf::copc_info_vlr mCopcInfoVlr; mutable QHash> mHierarchyNodePos; //!< Additional data hierarchy for COPC diff --git a/src/core/pointcloud/qgseptpointcloudblockrequest.cpp b/src/core/pointcloud/qgseptpointcloudblockrequest.cpp index 18029e72e7b0e..9578d6ee61e51 100644 --- a/src/core/pointcloud/qgseptpointcloudblockrequest.cpp +++ b/src/core/pointcloud/qgseptpointcloudblockrequest.cpp @@ -76,7 +76,7 @@ void QgsEptPointCloudBlockRequest::blockFinishedLoading() QgsPointCloudRequest req; req.setAttributes( mRequestedAttributes ); req.setFilterRect( mFilterRect ); - QgsPointCloudIndex::storeNodeDataToCacheStatic( mBlock.get(), mNode, req, mFilterExpression, mUri ); + QgsAbstractPointCloudIndex::storeNodeDataToCacheStatic( mBlock.get(), mNode, req, mFilterExpression, mUri ); } } catch ( std::exception &e ) diff --git a/src/core/pointcloud/qgseptpointcloudindex.cpp b/src/core/pointcloud/qgseptpointcloudindex.cpp index 4b7d8f68eedf1..c5139d4cd7a5b 100644 --- a/src/core/pointcloud/qgseptpointcloudindex.cpp +++ b/src/core/pointcloud/qgseptpointcloudindex.cpp @@ -35,6 +35,7 @@ #include "qgslazdecoder.h" #include "qgscoordinatereferencesystem.h" #include "qgspointcloudblockrequest.h" +#include "qgspointcloudindex.h" #include "qgspointcloudrequest.h" #include "qgspointcloudattribute.h" #include "qgslogger.h" @@ -54,12 +55,12 @@ QgsEptPointCloudIndex::QgsEptPointCloudIndex() QgsEptPointCloudIndex::~QgsEptPointCloudIndex() = default; -std::unique_ptr QgsEptPointCloudIndex::clone() const +std::unique_ptr QgsEptPointCloudIndex::clone() const { QgsEptPointCloudIndex *clone = new QgsEptPointCloudIndex; QMutexLocker locker( &mHierarchyMutex ); copyCommonProperties( clone ); - return std::unique_ptr( clone ); + return std::unique_ptr( clone ); } void QgsEptPointCloudIndex::load( const QString &urlString ) @@ -67,9 +68,9 @@ void QgsEptPointCloudIndex::load( const QString &urlString ) QUrl url = urlString; // Treat non-URLs as local files if ( url.isValid() && ( url.scheme() == "http" || url.scheme() == "https" ) ) - mAccessType = Remote; + mAccessType = QgsPointCloudAccessType::Remote; else - mAccessType = Local; + mAccessType = QgsPointCloudAccessType::Local; mUri = urlString; QStringList splitUrl = mUri.split( '/' ); @@ -77,7 +78,7 @@ void QgsEptPointCloudIndex::load( const QString &urlString ) mUrlDirectoryPart = splitUrl.join( '/' ); QByteArray content; - if ( mAccessType == Remote ) + if ( mAccessType == QgsPointCloudAccessType::Remote ) { QNetworkRequest nr = QNetworkRequest( QUrl( mUri ) ); QgsSetRequestInitiatorClass( nr, QStringLiteral( "QgsEptPointCloudIndex" ) ); @@ -110,7 +111,7 @@ void QgsEptPointCloudIndex::load( const QString &urlString ) // try to import the metadata too! const QString manifestPath = mUrlDirectoryPart + QStringLiteral( "/ept-sources/manifest.json" ); QByteArray manifestJson; - if ( mAccessType == Remote ) + if ( mAccessType == QgsPointCloudAccessType::Remote ) { QUrl manifestUrl( manifestPath ); @@ -158,7 +159,7 @@ void QgsEptPointCloudIndex::loadManifest( const QByteArray &manifestJson ) const QString fullMetadataPath = mUrlDirectoryPart + QStringLiteral( "/ept-sources/" ) + metadataPath; QByteArray metadataJson; - if ( mAccessType == Remote ) + if ( mAccessType == QgsPointCloudAccessType::Remote ) { QUrl metadataUrl( fullMetadataPath ); QNetworkRequest nr = QNetworkRequest( QUrl( metadataUrl ) ); @@ -376,7 +377,7 @@ std::unique_ptr QgsEptPointCloudIndex::nodeData( const QgsPo } std::unique_ptr block; - if ( mAccessType == Remote ) + if ( mAccessType == QgsPointCloudAccessType::Remote ) { std::unique_ptr blockRequest( asyncNodeData( n, request ) ); if ( !blockRequest ) @@ -431,7 +432,7 @@ QgsPointCloudBlockRequest *QgsEptPointCloudIndex::asyncNodeData( const QgsPointC scale(), offset(), mFilterExpression, request.filterRect() ); } - if ( mAccessType != Remote ) + if ( mAccessType != QgsPointCloudAccessType::Remote ) return nullptr; if ( !loadNodeHierarchy( n ) ) @@ -481,7 +482,7 @@ qint64 QgsEptPointCloudIndex::pointCount() const QgsPointCloudNode QgsEptPointCloudIndex::getNode( const QgsPointCloudNodeId &id ) const { - QgsPointCloudNode node = QgsPointCloudIndex::getNode( id ); + QgsPointCloudNode node = QgsAbstractPointCloudIndex::getNode( id ); // First try cached value if ( node.pointCount() != -1 ) @@ -543,7 +544,7 @@ bool QgsEptPointCloudIndex::loadSingleNodeHierarchy( const QgsPointCloudNodeId & const QString filePath = QStringLiteral( "%1/ept-hierarchy/%2.json" ).arg( mUrlDirectoryPart, nodeId.toString() ); QByteArray dataJsonH; - if ( mAccessType == Remote ) + if ( mAccessType == QgsPointCloudAccessType::Remote ) { QNetworkRequest nr( filePath ); QgsSetRequestInitiatorClass( nr, QStringLiteral( "QgsEptPointCloudIndex" ) ); @@ -645,14 +646,14 @@ bool QgsEptPointCloudIndex::isValid() const return mIsValid; } -QgsPointCloudIndex::AccessType QgsEptPointCloudIndex::accessType() const +QgsPointCloudAccessType QgsEptPointCloudIndex::accessType() const { return mAccessType; } void QgsEptPointCloudIndex::copyCommonProperties( QgsEptPointCloudIndex *destination ) const { - QgsPointCloudIndex::copyCommonProperties( destination ); + QgsAbstractPointCloudIndex::copyCommonProperties( destination ); // QgsEptPointCloudIndex specific fields destination->mIsValid = mIsValid; diff --git a/src/core/pointcloud/qgseptpointcloudindex.h b/src/core/pointcloud/qgseptpointcloudindex.h index 7b5f8733ae359..32d9a540ebbbe 100644 --- a/src/core/pointcloud/qgseptpointcloudindex.h +++ b/src/core/pointcloud/qgseptpointcloudindex.h @@ -34,14 +34,14 @@ class QgsCoordinateReferenceSystem; -class CORE_EXPORT QgsEptPointCloudIndex: public QgsPointCloudIndex +class CORE_EXPORT QgsEptPointCloudIndex: public QgsAbstractPointCloudIndex { public: explicit QgsEptPointCloudIndex(); ~QgsEptPointCloudIndex(); - std::unique_ptr clone() const override; + std::unique_ptr clone() const override; void load( const QString &fileName ) override; @@ -56,7 +56,7 @@ class CORE_EXPORT QgsEptPointCloudIndex: public QgsPointCloudIndex QgsPointCloudStatistics metadataStatistics() const override; bool isValid() const override; - QgsPointCloudIndex::AccessType accessType() const override; + QgsPointCloudAccessType accessType() const override; /** * Copies common properties to the \a destination index @@ -73,7 +73,7 @@ class CORE_EXPORT QgsEptPointCloudIndex: public QgsPointCloudIndex bool loadNodeHierarchy( const QgsPointCloudNodeId &nodeId ) const; bool mIsValid = false; - QgsPointCloudIndex::AccessType mAccessType = Local; + QgsPointCloudAccessType mAccessType = QgsPointCloudAccessType::Local; QString mDataType; QString mWkt; diff --git a/src/core/pointcloud/qgspointclouddataprovider.cpp b/src/core/pointcloud/qgspointclouddataprovider.cpp index 916c7f0d80c0c..03f6549bb8ebc 100644 --- a/src/core/pointcloud/qgspointclouddataprovider.cpp +++ b/src/core/pointcloud/qgspointclouddataprovider.cpp @@ -53,8 +53,8 @@ bool QgsPointCloudDataProvider::hasValidIndex() const { QGIS_PROTECT_QOBJECT_THREAD_ACCESS - QgsPointCloudIndex *lIndex = index(); - return lIndex && lIndex->isValid(); + QgsPointCloudIndex lIndex = index(); + return lIndex.isValid(); } QgsGeometry QgsPointCloudDataProvider::polygonBounds() const @@ -188,10 +188,10 @@ QgsPointCloudStatistics QgsPointCloudDataProvider::metadataStatistics() { QGIS_PROTECT_QOBJECT_THREAD_ACCESS - QgsPointCloudIndex *pcIndex = index(); + QgsPointCloudIndex pcIndex = index(); if ( pcIndex ) { - return pcIndex->metadataStatistics(); + return pcIndex.metadataStatistics(); } return QgsPointCloudStatistics(); } @@ -217,14 +217,14 @@ struct MapIndexedPointCloudNode typedef QVector> result_type; MapIndexedPointCloudNode( QgsPointCloudRequest &request, const QgsVector3D &indexScale, const QgsVector3D &indexOffset, - const QgsGeometry &extentGeometry, const QgsDoubleRange &zRange, QgsPointCloudIndex *index, int pointsLimit ) + const QgsGeometry &extentGeometry, const QgsDoubleRange &zRange, QgsPointCloudIndex index, int pointsLimit ) : mRequest( request ), mIndexScale( indexScale ), mIndexOffset( indexOffset ), mExtentGeometry( extentGeometry ), mZRange( zRange ), mIndex( index ), mPointsLimit( pointsLimit ) { } QVector operator()( QgsPointCloudNodeId n ) { QVector acceptedPoints; - std::unique_ptr block( mIndex->nodeData( n, mRequest ) ); + std::unique_ptr block( mIndex.nodeData( n, mRequest ) ); if ( !block || pointsCount == mPointsLimit ) return acceptedPoints; @@ -238,6 +238,12 @@ struct MapIndexedPointCloudNode const QgsPointCloudAttribute::DataType zType = blockAttributes.find( QStringLiteral( "Z" ), zOffset )->type(); std::unique_ptr< QgsGeos > extentEngine = std::make_unique< QgsGeos >( mExtentGeometry.constGet() ); extentEngine->prepareGeometry(); + + std::optional copcTimeFlag = std::nullopt; + QVariantMap extraMetadata = mIndex.extraMetadata(); + if ( extraMetadata.contains( QStringLiteral( "CopcGpsTimeFlag" ) ) ) + copcTimeFlag = extraMetadata[ QStringLiteral( "CopcGpsTimeFlag" ) ].toBool(); + for ( int i = 0; i < block->pointCount() && pointsCount < mPointsLimit; ++i ) { double x, y, z; @@ -251,14 +257,14 @@ struct MapIndexedPointCloudNode pointAttr[ QStringLiteral( "Z" ) ] = z; - if ( const QgsCopcPointCloudIndex *copcIndex = dynamic_cast( mIndex ) ) + if ( copcTimeFlag.has_value() ) { const QDateTime gpsBaseTime = QDateTime::fromSecsSinceEpoch( 315964809, Qt::UTC ); constexpr int numberOfSecsInWeek = 3600 * 24 * 7; // here we check the flag set in header to determine if we need to // parse the time as GPS week time or GPS adjusted standard time // however often times the flag is set wrong, so we determine if the value is bigger than the maximum amount of seconds in week then it has to be adjusted standard time - if ( copcIndex->gpsTimeFlag() || pointAttr[QStringLiteral( "GpsTime" )].toDouble() > numberOfSecsInWeek ) + if ( copcTimeFlag.value() || pointAttr[QStringLiteral( "GpsTime" )].toDouble() > numberOfSecsInWeek ) { const QString utcTime = gpsBaseTime.addSecs( static_cast( pointAttr[QStringLiteral( "GpsTime" )].toDouble() + 1e9 ) ).toString( Qt::ISODate ); pointAttr[ QStringLiteral( "GpsTime (raw)" )] = pointAttr[QStringLiteral( "GpsTime" )]; @@ -283,7 +289,7 @@ struct MapIndexedPointCloudNode QgsVector3D mIndexOffset; const QgsGeometry &mExtentGeometry; const QgsDoubleRange &mZRange; - QgsPointCloudIndex *mIndex = nullptr; + QgsPointCloudIndex mIndex; int mPointsLimit; int pointsCount = 0; }; @@ -314,7 +320,7 @@ QVector QgsPointCloudDataProvider::identify( } QVector QgsPointCloudDataProvider::identify( - QgsPointCloudIndex *index, double maxError, + QgsPointCloudIndex index, double maxError, const QgsGeometry &extentGeometry, const QgsDoubleRange &extentZRange, int pointsLimit ) { @@ -322,18 +328,18 @@ QVector QgsPointCloudDataProvider::identify( QVector acceptedPoints; - if ( !index || !index->isValid() ) + if ( !index.isValid() ) return acceptedPoints; - const QgsPointCloudNode root = index->getNode( index->root() ); + const QgsPointCloudNode root = index.getNode( index.root() ); const QVector nodes = traverseTree( index, root, maxError, root.error(), extentGeometry, extentZRange ); - const QgsPointCloudAttributeCollection attributeCollection = index->attributes(); + const QgsPointCloudAttributeCollection attributeCollection = index.attributes(); QgsPointCloudRequest request; request.setAttributes( attributeCollection ); acceptedPoints = QtConcurrent::blockingMappedReduced( nodes, - MapIndexedPointCloudNode( request, index->scale(), index->offset(), extentGeometry, extentZRange, index, pointsLimit ), + MapIndexedPointCloudNode( request, index.scale(), index.offset(), extentGeometry, extentZRange, index, pointsLimit ), qOverload>&>( &QVector>::append ), QtConcurrent::UnorderedReduce ); @@ -341,7 +347,7 @@ QVector QgsPointCloudDataProvider::identify( } QVector QgsPointCloudDataProvider::traverseTree( - const QgsPointCloudIndex *pc, + const QgsPointCloudIndex pc, QgsPointCloudNode node, double maxError, double nodeError, @@ -368,7 +374,7 @@ QVector QgsPointCloudDataProvider::traverseTree( for ( const QgsPointCloudNodeId &nn : node.children() ) { - const QgsPointCloudNode childNode = pc->getNode( nn ); + const QgsPointCloudNode childNode = pc.getNode( nn ); if ( extentGeometry.intersects( childNode.bounds().toRectangle() ) ) nodes += traverseTree( pc, childNode, maxError, childrenError, extentGeometry, extentZRange ); } @@ -381,11 +387,11 @@ bool QgsPointCloudDataProvider::setSubsetString( const QString &subset, bool upd QGIS_PROTECT_QOBJECT_THREAD_ACCESS Q_UNUSED( updateFeatureCount ) - const auto i = index(); + auto i = index(); if ( !i ) return false; - if ( !i->setSubsetString( subset ) ) + if ( !i.setSubsetString( subset ) ) return false; mSubsetString = subset; emit dataChanged(); diff --git a/src/core/pointcloud/qgspointclouddataprovider.h b/src/core/pointcloud/qgspointclouddataprovider.h index 0df928b8267b8..4fb3bb60d5405 100644 --- a/src/core/pointcloud/qgspointclouddataprovider.h +++ b/src/core/pointcloud/qgspointclouddataprovider.h @@ -157,7 +157,7 @@ class CORE_EXPORT QgsPointCloudDataProvider: public QgsDataProvider * * \note Not available in Python bindings */ - virtual QgsPointCloudIndex *index() const SIP_SKIP {return nullptr;} + virtual QgsPointCloudIndex index() const SIP_SKIP {return nullptr;} /** * Returns a list of sub indexes available if the provider supports multiple indexes, empty list otherwise. @@ -279,10 +279,10 @@ class CORE_EXPORT QgsPointCloudDataProvider: public QgsDataProvider QString mSubsetString; //! Identify in a specific index (used for sub-indexes) - QVector identify( QgsPointCloudIndex *index, double maxError, const QgsGeometry &extentGeometry, const QgsDoubleRange &extentZRange, int pointsLimit ) SIP_SKIP ; + QVector identify( QgsPointCloudIndex index, double maxError, const QgsGeometry &extentGeometry, const QgsDoubleRange &extentZRange, int pointsLimit ) SIP_SKIP ; private: - QVector traverseTree( const QgsPointCloudIndex *pc, QgsPointCloudNode node, double maxError, double nodeError, const QgsGeometry &extentGeometry, const QgsDoubleRange &extentZRange ); + QVector traverseTree( const QgsPointCloudIndex pc, QgsPointCloudNode node, double maxError, double nodeError, const QgsGeometry &extentGeometry, const QgsDoubleRange &extentZRange ); }; diff --git a/src/core/pointcloud/qgspointcloudindex.cpp b/src/core/pointcloud/qgspointcloudindex.cpp index dc12a79f74e0f..843c1b9a8ac4a 100644 --- a/src/core/pointcloud/qgspointcloudindex.cpp +++ b/src/core/pointcloud/qgspointcloudindex.cpp @@ -15,6 +15,7 @@ * * ***************************************************************************/ +#include "qgscoordinatereferencesystem.h" #include "qgspointcloudindex.h" #include #include @@ -25,6 +26,7 @@ #include #include #include +#include #include "qgsbox3d.h" #include "qgstiledownloadmanager.h" @@ -147,23 +149,23 @@ float QgsPointCloudNode::error() const ///@endcond // -// QgsPointCloudIndex +// QgsAbstractPointCloudIndex // -QMutex QgsPointCloudIndex::sBlockCacheMutex; -QCache QgsPointCloudIndex::sBlockCache( 200'000'000 ); // 200MB of cached points +QMutex QgsAbstractPointCloudIndex::sBlockCacheMutex; +QCache QgsAbstractPointCloudIndex::sBlockCache( 200'000'000 ); // 200MB of cached points -QgsPointCloudIndex::QgsPointCloudIndex() = default; +QgsAbstractPointCloudIndex::QgsAbstractPointCloudIndex() = default; -QgsPointCloudIndex::~QgsPointCloudIndex() = default; +QgsAbstractPointCloudIndex::~QgsAbstractPointCloudIndex() = default; -bool QgsPointCloudIndex::hasNode( const QgsPointCloudNodeId &n ) const +bool QgsAbstractPointCloudIndex::hasNode( const QgsPointCloudNodeId &n ) const { QMutexLocker locker( &mHierarchyMutex ); return mHierarchy.contains( n ); } -QgsPointCloudNode QgsPointCloudIndex::getNode( const QgsPointCloudNodeId &id ) const +QgsPointCloudNode QgsAbstractPointCloudIndex::getNode( const QgsPointCloudNodeId &id ) const { Q_ASSERT( hasNode( id ) ); @@ -193,32 +195,32 @@ QgsPointCloudNode QgsPointCloudIndex::getNode( const QgsPointCloudNodeId &id ) c return QgsPointCloudNode( id, pointCount, children, bounds.width() / mSpan, bounds ); } -QgsPointCloudAttributeCollection QgsPointCloudIndex::attributes() const +QgsPointCloudAttributeCollection QgsAbstractPointCloudIndex::attributes() const { return mAttributes; } -QgsVector3D QgsPointCloudIndex::scale() const +QgsVector3D QgsAbstractPointCloudIndex::scale() const { return mScale; } -QgsVector3D QgsPointCloudIndex::offset() const +QgsVector3D QgsAbstractPointCloudIndex::offset() const { return mOffset; } -void QgsPointCloudIndex::setAttributes( const QgsPointCloudAttributeCollection &attributes ) +void QgsAbstractPointCloudIndex::setAttributes( const QgsPointCloudAttributeCollection &attributes ) { mAttributes = attributes; } -int QgsPointCloudIndex::span() const +int QgsAbstractPointCloudIndex::span() const { return mSpan; } -bool QgsPointCloudIndex::setSubsetString( const QString &subset ) +bool QgsAbstractPointCloudIndex::setSubsetString( const QString &subset ) { const QString lastExpression = mFilterExpression; mFilterExpression.setExpression( subset ); @@ -242,12 +244,12 @@ bool QgsPointCloudIndex::setSubsetString( const QString &subset ) return true; } -QString QgsPointCloudIndex::subsetString() const +QString QgsAbstractPointCloudIndex::subsetString() const { return mFilterExpression; } -QgsPointCloudStatistics QgsPointCloudIndex::metadataStatistics() const +QgsPointCloudStatistics QgsAbstractPointCloudIndex::metadataStatistics() const { QMap statsMap; statsMap[ "X" ].minimum = mExtent.xMinimum(); @@ -260,9 +262,15 @@ QgsPointCloudStatistics QgsPointCloudIndex::metadataStatistics() const return QgsPointCloudStatistics( pointCount(), statsMap ); } -void QgsPointCloudIndex::copyCommonProperties( QgsPointCloudIndex *destination ) const +bool QgsAbstractPointCloudIndex::writeStatistics( QgsPointCloudStatistics &stats ) +{ + Q_UNUSED( stats ); + return false; +} + +void QgsAbstractPointCloudIndex::copyCommonProperties( QgsAbstractPointCloudIndex *destination ) const { - // Base QgsPointCloudIndex fields + // Base QgsAbstractPointCloudIndex fields destination->mUri = mUri; destination->mExtent = mExtent; destination->mZMin = mZMin; @@ -276,7 +284,7 @@ void QgsPointCloudIndex::copyCommonProperties( QgsPointCloudIndex *destination ) destination->mFilterExpression = mFilterExpression; } -QgsPointCloudBlock *QgsPointCloudIndex::getNodeDataFromCache( const QgsPointCloudNodeId &node, const QgsPointCloudRequest &request ) +QgsPointCloudBlock *QgsAbstractPointCloudIndex::getNodeDataFromCache( const QgsPointCloudNodeId &node, const QgsPointCloudRequest &request ) { QgsPointCloudCacheKey key( node, request, mFilterExpression, mUri ); @@ -285,12 +293,12 @@ QgsPointCloudBlock *QgsPointCloudIndex::getNodeDataFromCache( const QgsPointClou return cached ? cached->clone() : nullptr; } -void QgsPointCloudIndex::storeNodeDataToCache( QgsPointCloudBlock *data, const QgsPointCloudNodeId &node, const QgsPointCloudRequest &request ) const +void QgsAbstractPointCloudIndex::storeNodeDataToCache( QgsPointCloudBlock *data, const QgsPointCloudNodeId &node, const QgsPointCloudRequest &request ) const { storeNodeDataToCacheStatic( data, node, request, mFilterExpression, mUri ); } -void QgsPointCloudIndex::storeNodeDataToCacheStatic( QgsPointCloudBlock *data, const QgsPointCloudNodeId &node, const QgsPointCloudRequest &request, const QgsPointCloudExpression &expression, const QString &uri ) +void QgsAbstractPointCloudIndex::storeNodeDataToCacheStatic( QgsPointCloudBlock *data, const QgsPointCloudNodeId &node, const QgsPointCloudRequest &request, const QgsPointCloudExpression &expression, const QString &uri ) { if ( !data ) return; @@ -303,3 +311,184 @@ void QgsPointCloudIndex::storeNodeDataToCacheStatic( QgsPointCloudBlock *data, c QgsDebugMsgLevel( QStringLiteral( "(%1/%2): Caching node %3 of %4" ).arg( sBlockCache.totalCost() ).arg( sBlockCache.maxCost() ).arg( key.node().toString() ).arg( key.uri() ), 4 ); sBlockCache.insert( key, data->clone(), cost ); } + +QVariantMap QgsAbstractPointCloudIndex::extraMetadata() const +{ + return {}; +} + +// +// QgsPointCloudIndex +// +// + +QgsPointCloudIndex::QgsPointCloudIndex( QgsAbstractPointCloudIndex *index ) +{ + mIndex.reset( index ); +} + +QgsPointCloudIndex::operator bool() const +{ + return mIndex != nullptr; +} + +void QgsPointCloudIndex::load( const QString &fileName ) +{ + Q_ASSERT( mIndex ); + mIndex->load( fileName ); +} + +bool QgsPointCloudIndex::isValid() const +{ + return mIndex && mIndex->isValid(); +} + +QString QgsPointCloudIndex::error() const +{ + return mIndex ? mIndex->error() : QStringLiteral( "Index is NULL" ); +} + +QgsPointCloudAccessType QgsPointCloudIndex::accessType() const +{ + Q_ASSERT( mIndex ); + return mIndex->accessType(); +} + +QgsCoordinateReferenceSystem QgsPointCloudIndex::crs() const +{ + Q_ASSERT( mIndex ); + return mIndex->crs(); +} + +qint64 QgsPointCloudIndex::pointCount() const +{ + Q_ASSERT( mIndex ); + return mIndex->pointCount(); +} + +QVariantMap QgsPointCloudIndex::originalMetadata() const +{ + Q_ASSERT( mIndex ); + return mIndex->originalMetadata(); +} + +QgsPointCloudStatistics QgsPointCloudIndex::metadataStatistics() const +{ + Q_ASSERT( mIndex ); + return mIndex->metadataStatistics(); +} + +bool QgsPointCloudIndex::writeStatistics( QgsPointCloudStatistics &stats ) +{ + Q_ASSERT( mIndex ); + return mIndex->writeStatistics( stats ); +} + +QgsPointCloudNodeId QgsPointCloudIndex::root() const +{ + Q_ASSERT( mIndex ); + return mIndex->root(); +} + +bool QgsPointCloudIndex::hasNode( const QgsPointCloudNodeId &id ) const +{ + Q_ASSERT( mIndex ); + return mIndex->hasNode( id ); +} + +QgsPointCloudNode QgsPointCloudIndex::getNode( const QgsPointCloudNodeId &id ) const +{ + Q_ASSERT( mIndex ); + return mIndex->getNode( id ); +} + +QgsPointCloudAttributeCollection QgsPointCloudIndex::attributes() const +{ + Q_ASSERT( mIndex ); + return mIndex->attributes(); +} + +std::unique_ptr QgsPointCloudIndex::nodeData( const QgsPointCloudNodeId &n, const QgsPointCloudRequest &request ) +{ + Q_ASSERT( mIndex ); + return mIndex->nodeData( n, request ); +} + +QgsPointCloudBlockRequest *QgsPointCloudIndex::asyncNodeData( const QgsPointCloudNodeId &n, const QgsPointCloudRequest &request ) +{ + Q_ASSERT( mIndex ); + return mIndex->asyncNodeData( n, request ); +} + +QgsRectangle QgsPointCloudIndex::extent() const +{ + Q_ASSERT( mIndex ); + return mIndex->extent(); +} + +double QgsPointCloudIndex::zMin() const +{ + Q_ASSERT( mIndex ); + return mIndex->zMin(); +} +double QgsPointCloudIndex::zMax() const +{ + Q_ASSERT( mIndex ); + return mIndex->zMax(); +} + +QgsBox3D QgsPointCloudIndex::rootNodeBounds() const +{ + Q_ASSERT( mIndex ); + return mIndex->rootNodeBounds(); +} + +QgsVector3D QgsPointCloudIndex::scale() const +{ + Q_ASSERT( mIndex ); + return mIndex->scale(); +} + +QgsVector3D QgsPointCloudIndex::offset() const +{ + Q_ASSERT( mIndex ); + return mIndex->offset(); +} + +int QgsPointCloudIndex::span() const +{ + Q_ASSERT( mIndex ); + return mIndex->span(); +} + + +bool QgsPointCloudIndex::setSubsetString( const QString &subset ) +{ + Q_ASSERT( mIndex ); + return mIndex->setSubsetString( subset ); +} + +QString QgsPointCloudIndex::subsetString() const +{ + Q_ASSERT( mIndex ); + return mIndex->subsetString(); +} + +QgsPointCloudBlock *QgsPointCloudIndex::getNodeDataFromCache( const QgsPointCloudNodeId &node, const QgsPointCloudRequest &request ) +{ + Q_ASSERT( mIndex ); + return mIndex->getNodeDataFromCache( node, request ); +} + +void QgsPointCloudIndex::storeNodeDataToCache( QgsPointCloudBlock *data, const QgsPointCloudNodeId &node, const QgsPointCloudRequest &request ) +{ + Q_ASSERT( mIndex ); + mIndex->storeNodeDataToCache( data, node, request ); +} + +QVariantMap QgsPointCloudIndex::extraMetadata() const +{ + Q_ASSERT( mIndex ); + return mIndex->extraMetadata(); +} + diff --git a/src/core/pointcloud/qgspointcloudindex.h b/src/core/pointcloud/qgspointcloudindex.h index 2c038a5fe4412..442391e891486 100644 --- a/src/core/pointcloud/qgspointcloudindex.h +++ b/src/core/pointcloud/qgspointcloudindex.h @@ -37,14 +37,11 @@ #include "qgspointcloudrequest.h" -#define SIP_NO_FILE - -class QgsPointCloudRequest; class QgsPointCloudAttributeCollection; class QgsCoordinateReferenceSystem; class QgsPointCloudBlockRequest; class QgsPointCloudStatistics; -class QgsPointCloudIndex; +class QgsAbstractPointCloudIndex; /** * \ingroup core @@ -106,6 +103,8 @@ Q_DECLARE_TYPEINFO( QgsPointCloudNodeId, Q_PRIMITIVE_TYPE ); //! Hash function for indexed nodes CORE_EXPORT uint qHash( QgsPointCloudNodeId id ); +#ifndef SIP_RUN + /** * \ingroup core * @@ -145,6 +144,8 @@ class CORE_EXPORT QgsPointCloudCacheKey //! Hash function for QgsPointCloudCacheKey uint qHash( const QgsPointCloudCacheKey &key ); +#endif // !SIP_RUN + /** * \ingroup core * @@ -159,7 +160,7 @@ class CORE_EXPORT QgsPointCloudNode public: /** - * Constructs new node object. Should only be called by QgsPointCloudIndex::getNode(). + * Constructs new node object. Should only be called by QgsAbstractPointCloudIndex::getNode(). * Bounds should always be computed by QgsPointCloudNode::bounds(). */ QgsPointCloudNode( const QgsPointCloudNodeId &id, @@ -197,6 +198,16 @@ class CORE_EXPORT QgsPointCloudNode QgsBox3D mBounds; }; +//! The access type of the data, local is for local files and remote for remote files (over HTTP) +enum class QgsPointCloudAccessType +{ + Local, //!< Local means the source is a local file on the machine + Remote //!< Remote means it's loaded through a protocol like HTTP +}; + + +#ifndef SIP_RUN + /** * \ingroup core * @@ -204,28 +215,21 @@ class CORE_EXPORT QgsPointCloudNode * * \note The API is considered EXPERIMENTAL and can be changed without a notice * - * \since QGIS 3.18 + * \since QGIS 3.42 */ -class CORE_EXPORT QgsPointCloudIndex +class CORE_EXPORT QgsAbstractPointCloudIndex { public: - //! The access type of the data, local is for local files and remote for remote files (over HTTP) - enum AccessType - { - Local, //!< Local means the source is a local file on the machine - Remote //!< Remote means it's loaded through a protocol like HTTP - }; - //! Constructs index - explicit QgsPointCloudIndex(); - virtual ~QgsPointCloudIndex(); + explicit QgsAbstractPointCloudIndex(); + virtual ~QgsAbstractPointCloudIndex(); /** * Returns a clone of the current point cloud index object * \note It is the responsibility of the caller to handle the ownership and delete the object. * \since QGIS 3.26 */ - virtual std::unique_ptr clone() const = 0; + virtual std::unique_ptr clone() const = 0; //! Loads the index from the file virtual void load( const QString &fileName ) = 0; @@ -245,7 +249,7 @@ class CORE_EXPORT QgsPointCloudIndex * If the access type is local, the data is stored locally as a file and will only be fetch synchronously ( blocking request with nodeData only ) * \note Always make sure to check before trying to use asyncNodeData since it is not supported in the case of local access type */ - virtual AccessType accessType() const = 0; + virtual QgsPointCloudAccessType accessType() const = 0; //! Returns the coordinate reference system of the point cloud index virtual QgsCoordinateReferenceSystem crs() const = 0; @@ -256,12 +260,19 @@ class CORE_EXPORT QgsPointCloudIndex /** * Returns the object containing the statistics metadata extracted from the dataset - * \since QGIS 3.26 + * \since QGIS 3.42 */ virtual QgsPointCloudStatistics metadataStatistics() const; + /** + * Writes the statistics object \a stats into the backing file, if possible. + * Returns true if the data was written successfully. + * \since QGIS 3.26 + */ + virtual bool writeStatistics( QgsPointCloudStatistics &stats ); + //! Returns root node of the index - QgsPointCloudNodeId root() { return QgsPointCloudNodeId( 0, 0, 0, 0 ); } + QgsPointCloudNodeId root() const { return QgsPointCloudNodeId( 0, 0, 0, 0 ); } //! Returns whether the octree contain given node virtual bool hasNode( const QgsPointCloudNodeId &n ) const; @@ -336,7 +347,7 @@ class CORE_EXPORT QgsPointCloudIndex * Copies common properties to the \a destination index * \since QGIS 3.26 */ - void copyCommonProperties( QgsPointCloudIndex *destination ) const; + void copyCommonProperties( QgsAbstractPointCloudIndex *destination ) const; /** * Fetches the requested node data from the cache for the specified \a node and \a request. @@ -356,6 +367,14 @@ class CORE_EXPORT QgsPointCloudIndex static void storeNodeDataToCacheStatic( QgsPointCloudBlock *data, const QgsPointCloudNodeId &node, const QgsPointCloudRequest &request, const QgsPointCloudExpression &expression, const QString &uri ); + /** + * Returns extra metadata that's not accessible through the other methods + * in an implementation-specific dynamic structure. + * + * \since QGIS 3.42 + */ + virtual QVariantMap extraMetadata() const; + protected: //TODO private //! Sets native attributes of the data void setAttributes( const QgsPointCloudAttributeCollection &attributes ); @@ -378,4 +397,243 @@ class CORE_EXPORT QgsPointCloudIndex static QCache sBlockCache; }; +#endif // !SIP_RUN + + +/** + * \ingroup core + * \brief Smart pointer for QgsAbstractPointCloudIndex + * + * This is a wrapper for QgsAbstractPointCloudIndex, an index for point cloud + * layers. It contains a shared_pointer, ensuring that concurrent access to the + * index is memory safe. + * + * \since QGIS 3.42 + */ +class CORE_EXPORT QgsPointCloudIndex SIP_NODEFAULTCTORS +{ + public: + //! Construct wrapper, takes ownership of index + QgsPointCloudIndex( QgsAbstractPointCloudIndex *index ) SIP_SKIP; + + //! Checks if index is non-null + operator bool() const; + + /** + * Loads the index from the file + * + * \see QgsAbstractPointCloudIndex::load + */ + void load( const QString &fileName ); + + /** + * Returns whether index is loaded and valid + * + * \see QgsAbstractPointCloudIndex::isValid + */ + bool isValid() const; + + /** + * Returns the error that occurred during the loading of the index. + * + * \see QgsAbstractPointCloudIndex::error + */ + QString error() const; + + /** + * Returns the access type of the data + * If the access type is Remote, data will be fetched from an HTTP server either synchronously or asynchronously + * If the access type is local, the data is stored locally as a file and will only be fetch synchronously ( blocking request with nodeData only ) + * \note Always make sure to check before trying to use asyncNodeData since it is not supported in the case of local access type + * + * \see QgsAbstractPointCloudIndex::accessType + */ + QgsPointCloudAccessType accessType() const; + + /** + * Returns the coordinate reference system of the point cloud index + * + * \see QgsAbstractPointCloudIndex::crs + */ + QgsCoordinateReferenceSystem crs() const; + + /** + * Returns the number of points in the point cloud + * + * \see QgsAbstractPointCloudIndex::pointCount + */ + qint64 pointCount() const; + + /** + * Returns the original metadata map + * + * \see QgsAbstractPointCloudIndex::originalMetadata + */ + QVariantMap originalMetadata() const; + + /** + * Returns the object containing the statistics metadata extracted from the dataset + * + * \see QgsAbstractPointCloudIndex::metadataStatistics + */ + QgsPointCloudStatistics metadataStatistics() const; + + /** + * Writes the statistics object \a stats into the backing file, if possible. + * Returns true if the data was written successfully. + * + * \see QgsAbstractPointCloudIndex::writeStatistics + */ + bool writeStatistics( QgsPointCloudStatistics &stats ); + + /** + * Returns root node of the index + * + * \see QgsAbstractPointCloudIndex::root + */ + QgsPointCloudNodeId root() const; + + /** + * Returns whether the octree contain given node + * + * \see QgsAbstractPointCloudIndex::hasNode + */ + bool hasNode( const QgsPointCloudNodeId &id ) const; + + /** + * Returns object for a given node + * + * \see QgsAbstractPointCloudIndex::getNode + */ + QgsPointCloudNode getNode( const QgsPointCloudNodeId &id ) const; + + /** + * Returns all attributes that are stored in the file + * + * \see QgsAbstractPointCloudIndex::attributes + */ + QgsPointCloudAttributeCollection attributes() const; + + /** + * Returns node data block. + * + * e.g. positions (needs to be scaled and offset applied to get coordinates) or + * classification, intensity or custom attributes. + * + * May return nullptr in case the node is not present or any other problem with loading + * + * \see QgsAbstractPointCloudIndex::nodeData + */ + std::unique_ptr< QgsPointCloudBlock > nodeData( const QgsPointCloudNodeId &n, const QgsPointCloudRequest &request ) SIP_SKIP; + + /** + * Returns a handle responsible for loading a node data block + * + * e.g. positions (needs to be scaled and offset applied to get coordinates) or + * classification, intensity or custom attributes + * + * It is caller responsibility to free the handle and the block issued by the handle if the loading succeeds. + * + * May return nullptr in case the node is not present or any other problem with loading + * + * \see QgsAbstractPointCloudIndex::asyncNodeData + */ + QgsPointCloudBlockRequest *asyncNodeData( const QgsPointCloudNodeId &n, const QgsPointCloudRequest &request ) SIP_SKIP; + + /** + * Returns extent of the data + * + * \see QgsAbstractPointCloudIndex::extent + */ + QgsRectangle extent() const; + + /** + * Returns z min + * + * \see QgsAbstractPointCloudIndex::zMin + */ + double zMin() const; + + /** + * Returns z max + * + * \see QgsAbstractPointCloudIndex::zMax + */ + double zMax() const; + + /** + * Returns bounding box of root node in CRS coords + * + * \see QgsAbstractPointCloudIndex::rootNodeBounds + */ + QgsBox3D rootNodeBounds() const; + + /** + * Returns scale of data relative to CRS + * + * \see QgsAbstractPointCloudIndex::scale + */ + QgsVector3D scale() const; + + /** + * Returns offset of data from CRS + * + * \see QgsAbstractPointCloudIndex::offset + */ + QgsVector3D offset() const; + + /** + * Returns the number of points in one direction in a single node. + * + * \see QgsAbstractPointCloudIndex::span + */ + int span() const; + + /** + * Sets the string used to define a subset of the point cloud. + * \param subset The subset string to be used in a \a QgsPointCloudExpression + * \returns true if the expression is parsed with no errors, false otherwise + * + * \see QgsAbstractPointCloudIndex::setSubsetString + */ + bool setSubsetString( const QString &subset ); + + /** + * Returns the string used to define a subset of the point cloud. + * \returns The subset string or null QString if not implemented by the provider + * + * + * \see QgsAbstractPointCloudIndex::subsetString + */ + QString subsetString() const; + + /** + * Fetches the requested node data from the cache for the specified \a node and \a request. + * If not found in the cache, nullptr is returned. + * Caller takes ownership of the returned object. + * + * \see QgsAbstractPointCloudIndex::getNodeDataFromCache + */ + QgsPointCloudBlock *getNodeDataFromCache( const QgsPointCloudNodeId &node, const QgsPointCloudRequest &request ) SIP_SKIP; + + /** + * Stores existing \a data to the cache for the specified \a node and \a request. Ownership is not transferred, block gets cloned in the cache. + * + * \see QgsAbstractPointCloudIndex::storeNodeDataToCache + */ + void storeNodeDataToCache( QgsPointCloudBlock *data, const QgsPointCloudNodeId &node, const QgsPointCloudRequest &request ) SIP_SKIP; + + /** + * Returns extra metadata that's not accessible through the other methods + * in an implementation-specific dynamic structure. + * + * \see QgsAbstractPointCloudIndex::extraMetadata + */ + QVariantMap extraMetadata() const; + + private: + std::shared_ptr mIndex; +}; + + #endif // QGSPOINTCLOUDINDEX_H diff --git a/src/core/pointcloud/qgspointcloudlayer.cpp b/src/core/pointcloud/qgspointcloudlayer.cpp index e2288ad901d87..2cae354826743 100644 --- a/src/core/pointcloud/qgspointcloudlayer.cpp +++ b/src/core/pointcloud/qgspointcloudlayer.cpp @@ -900,12 +900,9 @@ void QgsPointCloudLayer::calculateStatistics() resetRenderer(); mStatsCalculationTask = 0; #ifdef HAVE_COPC - if ( mDataProvider && mDataProvider->index() && mDataProvider->index()->isValid() && mDataProvider->name() == QLatin1String( "pdal" ) && mStatistics.sampledPointsCount() != 0 ) + if ( mDataProvider && mDataProvider->index() && mDataProvider->index().isValid() && mDataProvider->name() == QLatin1String( "pdal" ) && mStatistics.sampledPointsCount() != 0 ) { - if ( QgsCopcPointCloudIndex *index = dynamic_cast( mDataProvider->index() ) ) - { - index->writeStatistics( mStatistics ); - } + mDataProvider->index().writeStatistics( mStatistics ); } #endif } ); diff --git a/src/core/pointcloud/qgspointcloudlayerexporter.cpp b/src/core/pointcloud/qgspointcloudlayerexporter.cpp index ba5896c58d173..c876d7e7861cf 100644 --- a/src/core/pointcloud/qgspointcloudlayerexporter.cpp +++ b/src/core/pointcloud/qgspointcloudlayerexporter.cpp @@ -55,7 +55,7 @@ QString QgsPointCloudLayerExporter::getOgrDriverName( ExportFormat format ) QgsPointCloudLayerExporter::QgsPointCloudLayerExporter( QgsPointCloudLayer *layer ) : mLayerAttributeCollection( layer->attributes() ) - , mIndex( layer->dataProvider()->index()->clone() ) + , mIndex( layer->dataProvider()->index() ) , mSourceCrs( QgsCoordinateReferenceSystem( layer->crs() ) ) , mTargetCrs( QgsCoordinateReferenceSystem( layer->crs() ) ) { @@ -337,10 +337,10 @@ void QgsPointCloudLayerExporter::ExporterBase::run() QVector nodes; qint64 pointCount = 0; QQueue queue; - queue.push_back( mParent->mIndex->root() ); + queue.push_back( mParent->mIndex.root() ); while ( !queue.empty() ) { - QgsPointCloudNode node = mParent->mIndex->getNode( queue.front() ); + QgsPointCloudNode node = mParent->mIndex.getNode( queue.front() ); queue.pop_front(); const QgsBox3D nodeBounds = node.bounds(); if ( mParent->mExtent.intersects( nodeBounds.toRectangle() ) && @@ -363,7 +363,7 @@ void QgsPointCloudLayerExporter::ExporterBase::run() qint64 pointsExported = 0; for ( const QgsPointCloudNodeId &node : nodes ) { - block = mParent->mIndex->nodeData( node, request ); + block = mParent->mIndex.nodeData( node, request ); const QgsPointCloudAttributeCollection attributesCollection = block->attributes(); const char *ptr = block->data(); int count = block->pointCount(); @@ -532,12 +532,12 @@ QgsPointCloudLayerExporter::ExporterPdal::ExporterPdal( QgsPointCloudLayerExport mOptions.add( "format", QString::number( mPointFormat ).toStdString() ); if ( mParent->mTransform->isShortCircuited() ) { - mOptions.add( "offset_x", QString::number( mParent->mIndex->offset().x() ).toStdString() ); - mOptions.add( "offset_y", QString::number( mParent->mIndex->offset().y() ).toStdString() ); - mOptions.add( "offset_z", QString::number( mParent->mIndex->offset().z() ).toStdString() ); - mOptions.add( "scale_x", QString::number( mParent->mIndex->scale().x() ).toStdString() ); - mOptions.add( "scale_y", QString::number( mParent->mIndex->scale().y() ).toStdString() ); - mOptions.add( "scale_z", QString::number( mParent->mIndex->scale().z() ).toStdString() ); + mOptions.add( "offset_x", QString::number( mParent->mIndex.offset().x() ).toStdString() ); + mOptions.add( "offset_y", QString::number( mParent->mIndex.offset().y() ).toStdString() ); + mOptions.add( "offset_z", QString::number( mParent->mIndex.offset().z() ).toStdString() ); + mOptions.add( "scale_x", QString::number( mParent->mIndex.scale().x() ).toStdString() ); + mOptions.add( "scale_y", QString::number( mParent->mIndex.scale().y() ).toStdString() ); + mOptions.add( "scale_z", QString::number( mParent->mIndex.scale().z() ).toStdString() ); } mTable.layout()->registerDim( pdal::Dimension::Id::X ); diff --git a/src/core/pointcloud/qgspointcloudlayerexporter.h b/src/core/pointcloud/qgspointcloudlayerexporter.h index fbca3aa606c8e..c349caee4b166 100644 --- a/src/core/pointcloud/qgspointcloudlayerexporter.h +++ b/src/core/pointcloud/qgspointcloudlayerexporter.h @@ -256,7 +256,7 @@ class CORE_EXPORT QgsPointCloudLayerExporter SIP_NODEFAULTCTORS const QgsPointCloudAttributeCollection mLayerAttributeCollection; - std::unique_ptr< QgsPointCloudIndex > mIndex; + QgsPointCloudIndex mIndex = nullptr; QString mName = QObject::tr( "Exported" ); ExportFormat mFormat = ExportFormat::Memory; QString mFilename; diff --git a/src/core/pointcloud/qgspointcloudlayerprofilegenerator.cpp b/src/core/pointcloud/qgspointcloudlayerprofilegenerator.cpp index a8d706b0e14e7..dc58b4aa0abb6 100644 --- a/src/core/pointcloud/qgspointcloudlayerprofilegenerator.cpp +++ b/src/core/pointcloud/qgspointcloudlayerprofilegenerator.cpp @@ -363,8 +363,8 @@ QgsPointCloudLayerProfileGenerator::QgsPointCloudLayerProfileGenerator( QgsPoint { if ( mLayer->dataProvider()->index() ) { - mScale = mLayer->dataProvider()->index()->scale(); - mOffset = mLayer->dataProvider()->index()->offset(); + mScale = mLayer->dataProvider()->index().scale(); + mOffset = mLayer->dataProvider()->index().offset(); } } @@ -389,17 +389,17 @@ bool QgsPointCloudLayerProfileGenerator::generateProfile( const QgsProfileGenera // this is not AT ALL thread safe, but it's what QgsPointCloudLayerRenderer does ! // TODO: fix when QgsPointCloudLayerRenderer is made thread safe to use same approach - QVector indexes; - QgsPointCloudIndex *mainIndex = mLayer->dataProvider()->index(); - if ( mainIndex && mainIndex->isValid() ) + QVector indexes; + QgsPointCloudIndex mainIndex = mLayer->dataProvider()->index(); + if ( mainIndex && mainIndex.isValid() ) indexes.append( mainIndex ); // Gather all relevant sub-indexes const QgsRectangle profileCurveBbox = mProfileCurve->boundingBox(); for ( const QgsPointCloudSubIndex &subidx : mLayer->dataProvider()->subIndexes() ) { - QgsPointCloudIndex *index = subidx.index(); - if ( index && index->isValid() && subidx.polygonBounds().intersects( profileCurveBbox ) ) + QgsPointCloudIndex index = subidx.index(); + if ( index && index.isValid() && subidx.polygonBounds().intersects( profileCurveBbox ) ) indexes.append( subidx.index() ); } @@ -508,9 +508,9 @@ bool QgsPointCloudLayerProfileGenerator::generateProfile( const QgsProfileGenera return false; } - for ( QgsPointCloudIndex *pc : std::as_const( indexes ) ) + for ( QgsPointCloudIndex pc : std::as_const( indexes ) ) { - const QgsPointCloudNode root = pc->getNode( pc->root() ); + const QgsPointCloudNode root = pc.getNode( pc.root() ); const QgsRectangle rootNodeExtentLayerCoords = root.bounds().toRectangle(); QgsRectangle rootNodeExtentInCurveCrs; try @@ -523,7 +523,7 @@ bool QgsPointCloudLayerProfileGenerator::generateProfile( const QgsProfileGenera rootNodeExtentInCurveCrs = rootNodeExtentLayerCoords; } - const double rootErrorInMapCoordinates = rootNodeExtentInCurveCrs.width() / pc->span(); // in curve coords + const double rootErrorInMapCoordinates = rootNodeExtentInCurveCrs.width() / pc.span(); // in curve coords if ( rootErrorInMapCoordinates < 0.0 ) { QgsDebugError( QStringLiteral( "Invalid root node error" ) ); @@ -531,23 +531,23 @@ bool QgsPointCloudLayerProfileGenerator::generateProfile( const QgsProfileGenera } double rootErrorPixels = rootErrorInMapCoordinates / mapUnitsPerPixel; // in pixels - const QVector nodes = traverseTree( pc, pc->root(), maximumErrorPixels, rootErrorPixels, context.elevationRange() ); + const QVector nodes = traverseTree( pc, pc.root(), maximumErrorPixels, rootErrorPixels, context.elevationRange() ); - const double rootErrorInLayerCoordinates = rootNodeExtentLayerCoords.width() / pc->span(); + const double rootErrorInLayerCoordinates = rootNodeExtentLayerCoords.width() / pc.span(); const double maxErrorInMapCoordinates = maximumErrorPixels * mapUnitsPerPixel; mResults->mMaxErrorInLayerCoordinates = std::max( mResults->mMaxErrorInLayerCoordinates, maxErrorInMapCoordinates * rootErrorInLayerCoordinates / rootErrorInMapCoordinates ); - switch ( pc->accessType() ) + switch ( pc.accessType() ) { - case QgsPointCloudIndex::AccessType::Local: + case QgsPointCloudAccessType::Local: { visitNodesSync( nodes, pc, request, context.elevationRange() ); break; } - case QgsPointCloudIndex::AccessType::Remote: + case QgsPointCloudAccessType::Remote: { visitNodesAsync( nodes, pc, request, context.elevationRange() ); break; @@ -599,7 +599,7 @@ QgsFeedback *QgsPointCloudLayerProfileGenerator::feedback() const return mFeedback.get(); } -QVector QgsPointCloudLayerProfileGenerator::traverseTree( const QgsPointCloudIndex *pc, QgsPointCloudNodeId n, double maxErrorPixels, double nodeErrorPixels, const QgsDoubleRange &zRange ) +QVector QgsPointCloudLayerProfileGenerator::traverseTree( const QgsPointCloudIndex pc, QgsPointCloudNodeId n, double maxErrorPixels, double nodeErrorPixels, const QgsDoubleRange &zRange ) { QVector nodes; @@ -608,7 +608,7 @@ QVector QgsPointCloudLayerProfileGenerator::traverseTree( c return nodes; } - QgsPointCloudNode node = pc->getNode( n ); + QgsPointCloudNode node = pc.getNode( n ); QgsBox3D nodeBounds = node.bounds(); const QgsDoubleRange nodeZRange( nodeBounds.zMinimum(), nodeBounds.zMaximum() ); if ( !zRange.isInfinite() && !zRange.overlaps( nodeZRange ) ) @@ -636,7 +636,7 @@ QVector QgsPointCloudLayerProfileGenerator::traverseTree( c return nodes; } -int QgsPointCloudLayerProfileGenerator::visitNodesSync( const QVector &nodes, QgsPointCloudIndex *pc, QgsPointCloudRequest &request, const QgsDoubleRange &zRange ) +int QgsPointCloudLayerProfileGenerator::visitNodesSync( const QVector &nodes, QgsPointCloudIndex pc, QgsPointCloudRequest &request, const QgsDoubleRange &zRange ) { int nodesDrawn = 0; for ( const QgsPointCloudNodeId &n : nodes ) @@ -644,7 +644,7 @@ int QgsPointCloudLayerProfileGenerator::visitNodesSync( const QVectorisCanceled() ) break; - std::unique_ptr block( pc->nodeData( n, request ) ); + std::unique_ptr block( pc.nodeData( n, request ) ); if ( !block ) continue; @@ -656,7 +656,7 @@ int QgsPointCloudLayerProfileGenerator::visitNodesSync( const QVector &nodes, QgsPointCloudIndex *pc, QgsPointCloudRequest &request, const QgsDoubleRange &zRange ) +int QgsPointCloudLayerProfileGenerator::visitNodesAsync( const QVector &nodes, QgsPointCloudIndex pc, QgsPointCloudRequest &request, const QgsDoubleRange &zRange ) { int nodesDrawn = 0; @@ -671,7 +671,7 @@ int QgsPointCloudLayerProfileGenerator::visitNodesAsync( const QVectorasyncNodeData( n, request ); + QgsPointCloudBlockRequest *blockRequest = pc.asyncNodeData( n, request ); blockRequests.append( blockRequest ); QObject::connect( blockRequest, &QgsPointCloudBlockRequest::finished, &loop, [ this, &nodesDrawn, &loop, &blockRequests, &zRange, nStr, blockRequest ]() diff --git a/src/core/pointcloud/qgspointcloudlayerprofilegenerator.h b/src/core/pointcloud/qgspointcloudlayerprofilegenerator.h index 370b786c4362d..60026ef2bfb3b 100644 --- a/src/core/pointcloud/qgspointcloudlayerprofilegenerator.h +++ b/src/core/pointcloud/qgspointcloudlayerprofilegenerator.h @@ -144,9 +144,9 @@ class CORE_EXPORT QgsPointCloudLayerProfileGenerator : public QgsAbstractProfile QgsFeedback *feedback() const override; private: - QVector traverseTree( const QgsPointCloudIndex *pc, QgsPointCloudNodeId n, double maxErrorPixels, double nodeErrorPixels, const QgsDoubleRange &zRange ); - int visitNodesSync( const QVector &nodes, QgsPointCloudIndex *pc, QgsPointCloudRequest &request, const QgsDoubleRange &zRange ); - int visitNodesAsync( const QVector &nodes, QgsPointCloudIndex *pc, QgsPointCloudRequest &request, const QgsDoubleRange &zRange ); + QVector traverseTree( const QgsPointCloudIndex pc, QgsPointCloudNodeId n, double maxErrorPixels, double nodeErrorPixels, const QgsDoubleRange &zRange ); + int visitNodesSync( const QVector &nodes, QgsPointCloudIndex pc, QgsPointCloudRequest &request, const QgsDoubleRange &zRange ); + int visitNodesAsync( const QVector &nodes, QgsPointCloudIndex pc, QgsPointCloudRequest &request, const QgsDoubleRange &zRange ); void visitBlock( const QgsPointCloudBlock *block, const QgsDoubleRange &zRange ); QPointer< QgsPointCloudLayer > mLayer; diff --git a/src/core/pointcloud/qgspointcloudlayerrenderer.cpp b/src/core/pointcloud/qgspointcloudlayerrenderer.cpp index 71a2043f82a33..9b8fdc6fc1430 100644 --- a/src/core/pointcloud/qgspointcloudlayerrenderer.cpp +++ b/src/core/pointcloud/qgspointcloudlayerrenderer.cpp @@ -67,8 +67,8 @@ QgsPointCloudLayerRenderer::QgsPointCloudLayerRenderer( QgsPointCloudLayer *laye if ( mLayer->dataProvider()->index() ) { - mScale = mLayer->dataProvider()->index()->scale(); - mOffset = mLayer->dataProvider()->index()->offset(); + mScale = mLayer->dataProvider()->index().scale(); + mOffset = mLayer->dataProvider()->index().offset(); } if ( const QgsPointCloudLayerElevationProperties *elevationProps = qobject_cast< const QgsPointCloudLayerElevationProperties * >( mLayer->elevationProperties() ) ) @@ -129,9 +129,8 @@ bool QgsPointCloudLayerRenderer::render() } // TODO cache!? - QgsPointCloudIndex *pc = mLayer->dataProvider()->index(); - if ( mSubIndexes.isEmpty() && - ( !pc || !pc->isValid() ) ) + QgsPointCloudIndex pc = mLayer->dataProvider()->index(); + if ( mSubIndexes.isEmpty() && ( !pc || !pc.isValid() ) ) { mReadyToCompose = true; return false; @@ -205,12 +204,12 @@ bool QgsPointCloudLayerRenderer::render() if ( canceled ) break; - QgsPointCloudIndex *pc = si.index(); + QgsPointCloudIndex pc = si.index(); if ( !renderExtent.intersects( si.extent() ) ) continue; - if ( !pc || !pc->isValid() || renderExtent.width() > si.extent().width() ) + if ( !pc || !pc.isValid() || renderExtent.width() > si.extent().width() ) { // when dealing with virtual point clouds, we want to render the individual extents when zoomed out // and only use the selected renderer when zoomed in @@ -237,11 +236,11 @@ bool QgsPointCloudLayerRenderer::render() return !canceled; } -bool QgsPointCloudLayerRenderer::renderIndex( QgsPointCloudIndex *pc ) +bool QgsPointCloudLayerRenderer::renderIndex( QgsPointCloudIndex pc ) { QgsPointCloudRenderContext context( *renderContext(), - pc->scale(), - pc->offset(), + pc.scale(), + pc.offset(), mZScale, mZOffset, mFeedback.get() ); @@ -252,12 +251,12 @@ bool QgsPointCloudLayerRenderer::renderIndex( QgsPointCloudIndex *pc ) t.start(); #endif - const QgsPointCloudNodeId root = pc->root(); + const QgsPointCloudNodeId root = pc.root(); const double maximumError = context.renderContext().convertToPainterUnits( mRenderer->maximumScreenError(), mRenderer->maximumScreenErrorUnit() );// in pixels - const QgsPointCloudNode rootNode = pc->getNode( root ); - const QgsRectangle rootNodeExtentLayerCoords = pc->extent(); + const QgsPointCloudNode rootNode = pc.getNode( root ); + const QgsRectangle rootNodeExtentLayerCoords = pc.extent(); QgsRectangle rootNodeExtentMapCoords; if ( !context.renderContext().coordinateTransform().isShortCircuited() ) { @@ -278,7 +277,7 @@ bool QgsPointCloudLayerRenderer::renderIndex( QgsPointCloudIndex *pc ) rootNodeExtentMapCoords = rootNodeExtentLayerCoords; } - const double rootErrorInMapCoordinates = rootNodeExtentMapCoords.width() / pc->span(); // in map coords + const double rootErrorInMapCoordinates = rootNodeExtentMapCoords.width() / pc.span(); // in map coords double mapUnitsPerPixel = context.renderContext().mapToPixel().mapUnitsPerPixel(); if ( ( rootErrorInMapCoordinates < 0.0 ) || ( mapUnitsPerPixel < 0.0 ) || ( maximumError < 0.0 ) ) @@ -287,7 +286,7 @@ bool QgsPointCloudLayerRenderer::renderIndex( QgsPointCloudIndex *pc ) return false; } double rootErrorPixels = rootErrorInMapCoordinates / mapUnitsPerPixel; // in pixels - const QVector nodes = traverseTree( pc, context.renderContext(), pc->root(), maximumError, rootErrorPixels ); + const QVector nodes = traverseTree( pc, context.renderContext(), pc.root(), maximumError, rootErrorPixels ); QgsPointCloudRequest request; request.setAttributes( mAttributes ); @@ -314,14 +313,14 @@ bool QgsPointCloudLayerRenderer::renderIndex( QgsPointCloudIndex *pc ) } case Qgis::PointCloudDrawOrder::Default: { - switch ( pc->accessType() ) + switch ( pc.accessType() ) { - case QgsPointCloudIndex::AccessType::Local: + case QgsPointCloudAccessType::Local: { nodesDrawn += renderNodesSync( nodes, pc, context, request, canceled ); break; } - case QgsPointCloudIndex::AccessType::Remote: + case QgsPointCloudAccessType::Remote: { nodesDrawn += renderNodesAsync( nodes, pc, context, request, canceled ); break; @@ -341,7 +340,7 @@ bool QgsPointCloudLayerRenderer::renderIndex( QgsPointCloudIndex *pc ) return !canceled; } -int QgsPointCloudLayerRenderer::renderNodesSync( const QVector &nodes, QgsPointCloudIndex *pc, QgsPointCloudRenderContext &context, QgsPointCloudRequest &request, bool &canceled ) +int QgsPointCloudLayerRenderer::renderNodesSync( const QVector &nodes, QgsPointCloudIndex pc, QgsPointCloudRenderContext &context, QgsPointCloudRequest &request, bool &canceled ) { QPainter *finalPainter = context.renderContext().painter(); if ( mRenderer->renderAsTriangles() && context.renderContext().previewRenderPainter() ) @@ -360,7 +359,7 @@ int QgsPointCloudLayerRenderer::renderNodesSync( const QVector block( pc->nodeData( n, request ) ); + std::unique_ptr block( pc.nodeData( n, request ) ); if ( !block ) continue; @@ -399,7 +398,7 @@ int QgsPointCloudLayerRenderer::renderNodesSync( const QVector &nodes, QgsPointCloudIndex *pc, QgsPointCloudRenderContext &context, QgsPointCloudRequest &request, bool &canceled ) +int QgsPointCloudLayerRenderer::renderNodesAsync( const QVector &nodes, QgsPointCloudIndex pc, QgsPointCloudRenderContext &context, QgsPointCloudRequest &request, bool &canceled ) { if ( context.feedback() && context.feedback()->isCanceled() ) return 0; @@ -424,7 +423,7 @@ int QgsPointCloudLayerRenderer::renderNodesAsync( const QVectorasyncNodeData( n, request ); + QgsPointCloudBlockRequest *blockRequest = pc.asyncNodeData( n, request ); blockRequests.append( blockRequest ); QObject::connect( blockRequest, &QgsPointCloudBlockRequest::finished, &loop, [ this, &canceled, &nodesDrawn, &loop, &blockRequests, &context, nStr, blockRequest ]() @@ -499,7 +498,7 @@ int QgsPointCloudLayerRenderer::renderNodesAsync( const QVector &nodes, QgsPointCloudIndex *pc, QgsPointCloudRenderContext &context, QgsPointCloudRequest &request, bool &canceled, Qgis::PointCloudDrawOrder order ) +int QgsPointCloudLayerRenderer::renderNodesSorted( const QVector &nodes, QgsPointCloudIndex pc, QgsPointCloudRenderContext &context, QgsPointCloudRequest &request, bool &canceled, Qgis::PointCloudDrawOrder order ) { int blockCount = 0; int pointCount = 0; @@ -522,7 +521,7 @@ int QgsPointCloudLayerRenderer::renderNodesSorted( const QVector block( pc->nodeData( n, request ) ); + std::unique_ptr block( pc.nodeData( n, request ) ); if ( !block ) continue; @@ -771,11 +770,7 @@ void QgsPointCloudLayerRenderer::setLayerRenderingTimeHint( int time ) mRenderTimeHint = time; } -QVector QgsPointCloudLayerRenderer::traverseTree( const QgsPointCloudIndex *pc, - const QgsRenderContext &context, - QgsPointCloudNodeId n, - double maxErrorPixels, - double nodeErrorPixels ) +QVector QgsPointCloudLayerRenderer::traverseTree( const QgsPointCloudIndex pc, const QgsRenderContext &context, QgsPointCloudNodeId n, double maxErrorPixels, double nodeErrorPixels ) { QVector nodes; @@ -785,7 +780,7 @@ QVector QgsPointCloudLayerRenderer::traverseTree( const Qgs return nodes; } - QgsPointCloudNode node = pc->getNode( n ); + QgsPointCloudNode node = pc.getNode( n ); QgsBox3D nodeExtent = node.bounds(); if ( !context.extent().intersects( nodeExtent.toRectangle() ) ) diff --git a/src/core/pointcloud/qgspointcloudlayerrenderer.h b/src/core/pointcloud/qgspointcloudlayerrenderer.h index 23be4090291d5..9e301128786b9 100644 --- a/src/core/pointcloud/qgspointcloudlayerrenderer.h +++ b/src/core/pointcloud/qgspointcloudlayerrenderer.h @@ -72,12 +72,12 @@ class CORE_EXPORT QgsPointCloudLayerRenderer: public QgsMapLayerRenderer QgsFeedback *feedback() const override { return mFeedback.get(); } private: - QVector traverseTree( const QgsPointCloudIndex *pc, const QgsRenderContext &context, QgsPointCloudNodeId n, double maxErrorPixels, double nodeErrorPixels ); - int renderNodesSync( const QVector &nodes, QgsPointCloudIndex *pc, QgsPointCloudRenderContext &context, QgsPointCloudRequest &request, bool &canceled ); - int renderNodesAsync( const QVector &nodes, QgsPointCloudIndex *pc, QgsPointCloudRenderContext &context, QgsPointCloudRequest &request, bool &canceled ); - int renderNodesSorted( const QVector &nodes, QgsPointCloudIndex *pc, QgsPointCloudRenderContext &context, QgsPointCloudRequest &request, bool &canceled, Qgis::PointCloudDrawOrder order ); + QVector traverseTree( const QgsPointCloudIndex pc, const QgsRenderContext &context, QgsPointCloudNodeId n, double maxErrorPixels, double nodeErrorPixels ); + int renderNodesSync( const QVector &nodes, QgsPointCloudIndex pc, QgsPointCloudRenderContext &context, QgsPointCloudRequest &request, bool &canceled ); + int renderNodesAsync( const QVector &nodes, QgsPointCloudIndex pc, QgsPointCloudRenderContext &context, QgsPointCloudRequest &request, bool &canceled ); + int renderNodesSorted( const QVector &nodes, QgsPointCloudIndex pc, QgsPointCloudRenderContext &context, QgsPointCloudRequest &request, bool &canceled, Qgis::PointCloudDrawOrder order ); void renderTriangulatedSurface( QgsPointCloudRenderContext &context ); - bool renderIndex( QgsPointCloudIndex *pc ); + bool renderIndex( QgsPointCloudIndex pc ); QgsPointCloudLayer *mLayer = nullptr; QString mLayerName; diff --git a/src/core/pointcloud/qgspointcloudstatscalculationtask.cpp b/src/core/pointcloud/qgspointcloudstatscalculationtask.cpp index 6205dbe9025fd..62ecad009e079 100644 --- a/src/core/pointcloud/qgspointcloudstatscalculationtask.cpp +++ b/src/core/pointcloud/qgspointcloudstatscalculationtask.cpp @@ -25,7 +25,7 @@ ///@cond PRIVATE -QgsPointCloudStatsCalculationTask::QgsPointCloudStatsCalculationTask( QgsPointCloudIndex *index, const QVector &attributes, qint64 pointLimit ) +QgsPointCloudStatsCalculationTask::QgsPointCloudStatsCalculationTask( QgsPointCloudIndex index, const QVector &attributes, qint64 pointLimit ) : QgsTask( tr( "Generating attributes statistics" ) ) , mCalculator( index ) , mAttributes( attributes ) diff --git a/src/core/pointcloud/qgspointcloudstatscalculationtask.h b/src/core/pointcloud/qgspointcloudstatscalculationtask.h index ce581002c9f13..588c9050085ee 100644 --- a/src/core/pointcloud/qgspointcloudstatscalculationtask.h +++ b/src/core/pointcloud/qgspointcloudstatscalculationtask.h @@ -43,7 +43,7 @@ class QgsPointCloudStatsCalculationTask : public QgsTask Q_OBJECT public: - QgsPointCloudStatsCalculationTask( QgsPointCloudIndex *index, const QVector &attributes, qint64 pointLimit ); + QgsPointCloudStatsCalculationTask( QgsPointCloudIndex index, const QVector &attributes, qint64 pointLimit ); bool run() override; diff --git a/src/core/pointcloud/qgspointcloudstatscalculator.cpp b/src/core/pointcloud/qgspointcloudstatscalculator.cpp index 61bb760edcbbb..0111c6386d02d 100644 --- a/src/core/pointcloud/qgspointcloudstatscalculator.cpp +++ b/src/core/pointcloud/qgspointcloudstatscalculator.cpp @@ -38,19 +38,19 @@ struct StatsProcessor typedef QgsPointCloudStatistics result_type; static QMutex sStatsProcessorFeedbackMutex; - StatsProcessor( QgsPointCloudIndex *index, QgsPointCloudRequest request, QgsFeedback *feedback, double progressValue ) - : mIndex( index->clone().release() ), mRequest( request ), mFeedback( feedback ), mProgressValue( progressValue ) + StatsProcessor( QgsPointCloudIndex index, QgsPointCloudRequest request, QgsFeedback *feedback, double progressValue ) + : mIndex( index ), mRequest( request ), mFeedback( feedback ), mProgressValue( progressValue ) { } StatsProcessor( const StatsProcessor &processor ) - : mIndex( processor.mIndex->clone().release() ), mRequest( processor.mRequest ), mFeedback( processor.mFeedback ), mProgressValue( processor.mProgressValue ) + : mIndex( processor.mIndex ), mRequest( processor.mRequest ), mFeedback( processor.mFeedback ), mProgressValue( processor.mProgressValue ) { } StatsProcessor &operator =( const StatsProcessor &rhs ) { - mIndex.reset( rhs.mIndex->clone().release() ); + mIndex = rhs.mIndex; mRequest = rhs.mRequest; mFeedback = rhs.mFeedback; mProgressValue = rhs.mProgressValue; @@ -59,18 +59,18 @@ struct StatsProcessor QgsPointCloudStatistics operator()( QgsPointCloudNodeId nodeId ) { - QgsPointCloudNode node = mIndex->getNode( nodeId ); + QgsPointCloudNode node = mIndex.getNode( nodeId ); if ( node.pointCount() < 1 ) return QgsPointCloudStatistics(); std::unique_ptr block = nullptr; - if ( mIndex->accessType() == QgsPointCloudIndex::Local ) + if ( mIndex.accessType() == QgsPointCloudAccessType::Local ) { - block = mIndex->nodeData( nodeId, mRequest ); + block = mIndex.nodeData( nodeId, mRequest ); } else { - QgsPointCloudBlockRequest *request = mIndex->asyncNodeData( nodeId, mRequest ); + QgsPointCloudBlockRequest *request = mIndex.asyncNodeData( nodeId, mRequest ); if ( request == nullptr ) { QgsDebugError( QStringLiteral( "Unable to calculate statistics for node %1: Got nullptr async request" ).arg( nodeId.toString() ) ); @@ -169,7 +169,7 @@ struct StatsProcessor return QgsPointCloudStatistics( count, statsMap ); } private: - std::unique_ptr mIndex = nullptr; + QgsPointCloudIndex mIndex; QgsPointCloudRequest mRequest; QgsFeedback *mFeedback = nullptr; double mProgressValue = 0.0; @@ -183,15 +183,15 @@ struct StatsProcessor QMutex StatsProcessor::sStatsProcessorFeedbackMutex; -QgsPointCloudStatsCalculator::QgsPointCloudStatsCalculator( QgsPointCloudIndex *index ) - : mIndex( index->clone() ) +QgsPointCloudStatsCalculator::QgsPointCloudStatsCalculator( QgsPointCloudIndex index ) + : mIndex( index ) { } bool QgsPointCloudStatsCalculator::calculateStats( QgsFeedback *feedback, const QVector &attributes, qint64 pointsLimit ) { - if ( !mIndex->isValid() ) + if ( !mIndex.isValid() ) { QgsMessageLog::logMessage( QObject::tr( "Unable to calculate statistics of an invalid index" ) ); return false; @@ -201,10 +201,10 @@ bool QgsPointCloudStatsCalculator::calculateStats( QgsFeedback *feedback, const qint64 pointCount = 0; QVector nodes; QQueue queue; - queue.push_back( mIndex->root() ); + queue.push_back( mIndex.root() ); while ( !queue.empty() ) { - QgsPointCloudNode node = mIndex->getNode( queue.front() ); + QgsPointCloudNode node = mIndex.getNode( queue.front() ); queue.pop_front(); if ( !mProcessedNodes.contains( node.id() ) ) pointCount += node.pointCount(); @@ -223,7 +223,7 @@ bool QgsPointCloudStatsCalculator::calculateStats( QgsFeedback *feedback, const feedback->setProgress( 0 ); - QVector list = QtConcurrent::blockingMapped( nodes, StatsProcessor( mIndex.get(), mRequest, feedback, 100.0 / ( double )nodes.size() ) ); + QVector list = QtConcurrent::blockingMapped( nodes, StatsProcessor( mIndex, mRequest, feedback, 100.0 / ( double )nodes.size() ) ); for ( QgsPointCloudStatistics &s : list ) { diff --git a/src/core/pointcloud/qgspointcloudstatscalculator.h b/src/core/pointcloud/qgspointcloudstatscalculator.h index d7fff2a6953ab..a4398bbb2080d 100644 --- a/src/core/pointcloud/qgspointcloudstatscalculator.h +++ b/src/core/pointcloud/qgspointcloudstatscalculator.h @@ -26,12 +26,12 @@ #include #include +#include "qgspointcloudindex.h" #include "qgspointcloudrequest.h" #include "qgspointcloudstatistics.h" #define SIP_NO_FILE -class QgsPointCloudIndex; class QgsPointCloudBlock; class QgsPointCloudAttribute; class QgsPointCloudNodeId; @@ -50,7 +50,7 @@ class CORE_EXPORT QgsPointCloudStatsCalculator : public QObject Q_OBJECT public: //! Constructor - QgsPointCloudStatsCalculator( QgsPointCloudIndex *index ); + QgsPointCloudStatsCalculator( QgsPointCloudIndex index ); /** * Calculates the statistics of given attributes \a attributes up to new \a pointsLimit points @@ -62,7 +62,7 @@ class CORE_EXPORT QgsPointCloudStatsCalculator : public QObject QgsPointCloudStatistics statistics() const { return mStats; } private: - std::unique_ptr mIndex; + QgsPointCloudIndex mIndex; QgsPointCloudStatistics mStats; QSet mProcessedNodes; diff --git a/src/core/pointcloud/qgspointcloudsubindex.h b/src/core/pointcloud/qgspointcloudsubindex.h index b85c733a1510e..627c775524b00 100644 --- a/src/core/pointcloud/qgspointcloudsubindex.h +++ b/src/core/pointcloud/qgspointcloudsubindex.h @@ -49,11 +49,11 @@ class QgsPointCloudSubIndex { } - //! Returns a pointer to the point cloud index. May be NULLPTR if not loaded. - QgsPointCloudIndex *index() const { return mIndex.get(); } + //! Returns the point cloud index. May be NULLPTR if not loaded. + QgsPointCloudIndex index() const { return mIndex; } //! Sets the point cloud index to \a index. - void setIndex( QgsPointCloudIndex *index ) { mIndex.reset( index ); } + void setIndex( QgsPointCloudIndex index ) { mIndex = index; } //! Returns the uri for this sub index QString uri() const { return mUri; } @@ -74,7 +74,7 @@ class QgsPointCloudSubIndex qint64 pointCount() const { return mPointCount; } private: - std::shared_ptr mIndex; + QgsPointCloudIndex mIndex = nullptr; QString mUri; QgsRectangle mExtent; QgsGeometry mGeometry; diff --git a/src/core/providers/copc/qgscopcprovider.cpp b/src/core/providers/copc/qgscopcprovider.cpp index b033c7850246d..bcc1a3406c964 100644 --- a/src/core/providers/copc/qgscopcprovider.cpp +++ b/src/core/providers/copc/qgscopcprovider.cpp @@ -36,18 +36,16 @@ QgsCopcProvider::QgsCopcProvider( const QString &uri, const QgsDataProvider::ProviderOptions &options, Qgis::DataProviderReadFlags flags ) - : QgsPointCloudDataProvider( uri, options, flags ) + : QgsPointCloudDataProvider( uri, options, flags ), mIndex( new QgsCopcPointCloudIndex ) { - mIndex.reset( new QgsCopcPointCloudIndex ); - std::unique_ptr< QgsScopedRuntimeProfile > profile; if ( QgsApplication::profiler()->groupIsActive( QStringLiteral( "projectload" ) ) ) profile = std::make_unique< QgsScopedRuntimeProfile >( tr( "Open data source" ), QStringLiteral( "projectload" ) ); loadIndex( ); - if ( mIndex && !mIndex->isValid() ) + if ( !mIndex.isValid() ) { - appendError( mIndex->error() ); + appendError( mIndex.error() ); } } @@ -57,7 +55,7 @@ QgsCoordinateReferenceSystem QgsCopcProvider::crs() const { QGIS_PROTECT_QOBJECT_THREAD_ACCESS - return mIndex->crs(); + return mIndex.crs(); } Qgis::DataProviderFlags QgsCopcProvider::flags() const @@ -69,25 +67,21 @@ QgsRectangle QgsCopcProvider::extent() const { QGIS_PROTECT_QOBJECT_THREAD_ACCESS - return mIndex->extent(); + return mIndex.extent(); } QgsPointCloudAttributeCollection QgsCopcProvider::attributes() const { QGIS_PROTECT_QOBJECT_THREAD_ACCESS - return mIndex->attributes(); + return mIndex.attributes(); } bool QgsCopcProvider::isValid() const { QGIS_PROTECT_QOBJECT_THREAD_ACCESS - if ( !mIndex.get() ) - { - return false; - } - return mIndex->isValid(); + return mIndex.isValid(); } QString QgsCopcProvider::name() const @@ -104,19 +98,19 @@ QString QgsCopcProvider::description() const return QStringLiteral( "Point Clouds COPC" ); } -QgsPointCloudIndex *QgsCopcProvider::index() const +QgsPointCloudIndex QgsCopcProvider::index() const { // non fatal for now -- 2d rendering of point clouds is not thread safe and calls this QGIS_PROTECT_QOBJECT_THREAD_ACCESS_NON_FATAL - return mIndex.get(); + return mIndex; } qint64 QgsCopcProvider::pointCount() const { QGIS_PROTECT_QOBJECT_THREAD_ACCESS - return mIndex->pointCount(); + return mIndex.pointCount(); } void QgsCopcProvider::loadIndex( ) @@ -124,16 +118,16 @@ void QgsCopcProvider::loadIndex( ) QGIS_PROTECT_QOBJECT_THREAD_ACCESS // Index already loaded -> no need to load - if ( mIndex->isValid() ) + if ( mIndex.isValid() ) return; - mIndex->load( dataSourceUri() ); + mIndex.load( dataSourceUri() ); } QVariantMap QgsCopcProvider::originalMetadata() const { QGIS_PROTECT_QOBJECT_THREAD_ACCESS - return mIndex->originalMetadata(); + return mIndex.originalMetadata(); } void QgsCopcProvider::generateIndex() diff --git a/src/core/providers/copc/qgscopcprovider.h b/src/core/providers/copc/qgscopcprovider.h index 1eb7308d16a9a..e1486c7c8fd59 100644 --- a/src/core/providers/copc/qgscopcprovider.h +++ b/src/core/providers/copc/qgscopcprovider.h @@ -46,7 +46,7 @@ class QgsCopcProvider: public QgsPointCloudDataProvider bool isValid() const override; QString name() const override; QString description() const override; - QgsPointCloudIndex *index() const override; + QgsPointCloudIndex index() const override; qint64 pointCount() const override; QVariantMap originalMetadata() const override; void loadIndex( ) override; @@ -54,7 +54,7 @@ class QgsCopcProvider: public QgsPointCloudDataProvider PointCloudIndexGenerationState indexingState( ) override { return PointCloudIndexGenerationState::Indexed; } private: - std::unique_ptr mIndex; + QgsPointCloudIndex mIndex; QgsRectangle mExtent; QgsCoordinateReferenceSystem mCrs; diff --git a/src/core/providers/ept/qgseptprovider.cpp b/src/core/providers/ept/qgseptprovider.cpp index e5eb904624dfd..d4c9b8fcffa7a 100644 --- a/src/core/providers/ept/qgseptprovider.cpp +++ b/src/core/providers/ept/qgseptprovider.cpp @@ -37,18 +37,16 @@ QgsEptProvider::QgsEptProvider( const QString &uri, const QgsDataProvider::ProviderOptions &options, Qgis::DataProviderReadFlags flags ) - : QgsPointCloudDataProvider( uri, options, flags ) + : QgsPointCloudDataProvider( uri, options, flags ), mIndex( new QgsEptPointCloudIndex ) { - mIndex.reset( new QgsEptPointCloudIndex ); - std::unique_ptr< QgsScopedRuntimeProfile > profile; if ( QgsApplication::profiler()->groupIsActive( QStringLiteral( "projectload" ) ) ) profile = std::make_unique< QgsScopedRuntimeProfile >( tr( "Open data source" ), QStringLiteral( "projectload" ) ); loadIndex( ); - if ( mIndex && !mIndex->isValid() ) + if ( mIndex && !mIndex.isValid() ) { - appendError( mIndex->error() ); + appendError( mIndex.error() ); } } @@ -63,28 +61,28 @@ QgsCoordinateReferenceSystem QgsEptProvider::crs() const { QGIS_PROTECT_QOBJECT_THREAD_ACCESS - return mIndex->crs(); + return mIndex.crs(); } QgsRectangle QgsEptProvider::extent() const { QGIS_PROTECT_QOBJECT_THREAD_ACCESS - return mIndex->extent(); + return mIndex.extent(); } QgsPointCloudAttributeCollection QgsEptProvider::attributes() const { QGIS_PROTECT_QOBJECT_THREAD_ACCESS - return mIndex->attributes(); + return mIndex.attributes(); } bool QgsEptProvider::isValid() const { QGIS_PROTECT_QOBJECT_THREAD_ACCESS - return mIndex->isValid(); + return mIndex.isValid(); } QString QgsEptProvider::name() const @@ -101,36 +99,36 @@ QString QgsEptProvider::description() const return QStringLiteral( "Point Clouds EPT" ); } -QgsPointCloudIndex *QgsEptProvider::index() const +QgsPointCloudIndex QgsEptProvider::index() const { // BAD! 2D rendering of point clouds is NOT thread safe QGIS_PROTECT_QOBJECT_THREAD_ACCESS_NON_FATAL - return mIndex.get(); + return mIndex; } qint64 QgsEptProvider::pointCount() const { QGIS_PROTECT_QOBJECT_THREAD_ACCESS - return mIndex->pointCount(); + return mIndex.pointCount(); } void QgsEptProvider::loadIndex( ) { QGIS_PROTECT_QOBJECT_THREAD_ACCESS - if ( mIndex->isValid() ) + if ( mIndex.isValid() ) return; - mIndex->load( dataSourceUri() ); + mIndex.load( dataSourceUri() ); } QVariantMap QgsEptProvider::originalMetadata() const { QGIS_PROTECT_QOBJECT_THREAD_ACCESS - return mIndex->originalMetadata(); + return mIndex.originalMetadata(); } void QgsEptProvider::generateIndex() diff --git a/src/core/providers/ept/qgseptprovider.h b/src/core/providers/ept/qgseptprovider.h index 527666c7d9142..2360b4b7b7820 100644 --- a/src/core/providers/ept/qgseptprovider.h +++ b/src/core/providers/ept/qgseptprovider.h @@ -45,7 +45,7 @@ class QgsEptProvider: public QgsPointCloudDataProvider bool isValid() const override; QString name() const override; QString description() const override; - QgsPointCloudIndex *index() const override; + QgsPointCloudIndex index() const override; qint64 pointCount() const override; QVariantMap originalMetadata() const override; void loadIndex( ) override; @@ -53,7 +53,7 @@ class QgsEptProvider: public QgsPointCloudDataProvider PointCloudIndexGenerationState indexingState( ) override { return PointCloudIndexGenerationState::Indexed; } private: - std::unique_ptr mIndex; + QgsPointCloudIndex mIndex; }; class QgsEptProviderMetadata : public QgsProviderMetadata diff --git a/src/core/providers/vpc/qgsvirtualpointcloudprovider.cpp b/src/core/providers/vpc/qgsvirtualpointcloudprovider.cpp index d3ac19d5d2e51..43c5f86294c6a 100644 --- a/src/core/providers/vpc/qgsvirtualpointcloudprovider.cpp +++ b/src/core/providers/vpc/qgsvirtualpointcloudprovider.cpp @@ -114,7 +114,7 @@ QString QgsVirtualPointCloudProvider::description() const return PROVIDER_DESCRIPTION; } -QgsPointCloudIndex *QgsVirtualPointCloudProvider::index() const +QgsPointCloudIndex QgsVirtualPointCloudProvider::index() const { // non fatal for now -- 2d rendering of point clouds is not thread safe and calls this QGIS_PROTECT_QOBJECT_THREAD_ACCESS_NON_FATAL @@ -398,11 +398,11 @@ void QgsVirtualPointCloudProvider::loadSubIndex( int i ) if ( !sl.index() ) return; - sl.index()->load( sl.uri() ); + sl.index().load( sl.uri() ); // if expression is broken or index is missing a required field, set to "false" so it returns no points - if ( !mSubsetString.isEmpty() && !sl.index()->setSubsetString( mSubsetString ) ) - sl.index()->setSubsetString( QStringLiteral( "false" ) ); + if ( !mSubsetString.isEmpty() && !sl.index().setSubsetString( mSubsetString ) ) + sl.index().setSubsetString( QStringLiteral( "false" ) ); emit subIndexLoaded( i ); } @@ -494,8 +494,8 @@ bool QgsVirtualPointCloudProvider::setSubsetString( const QString &subset, bool continue; // if expression is broken or index is missing a required field, set to "false" so it returns no points - if ( !i.index()->setSubsetString( subset ) ) - i.index()->setSubsetString( QStringLiteral( "false" ) ); + if ( !i.index().setSubsetString( subset ) ) + i.index().setSubsetString( QStringLiteral( "false" ) ); } mSubsetString = subset; diff --git a/src/core/providers/vpc/qgsvirtualpointcloudprovider.h b/src/core/providers/vpc/qgsvirtualpointcloudprovider.h index aa5d9ac126d9a..d6be5dba8434e 100644 --- a/src/core/providers/vpc/qgsvirtualpointcloudprovider.h +++ b/src/core/providers/vpc/qgsvirtualpointcloudprovider.h @@ -48,7 +48,7 @@ class CORE_EXPORT QgsVirtualPointCloudProvider: public QgsPointCloudDataProvider bool isValid() const override; QString name() const override; QString description() const override; - QgsPointCloudIndex *index() const override; + QgsPointCloudIndex index() const override; qint64 pointCount() const override; QVariantMap originalMetadata() const override; void loadIndex( ) override; @@ -69,7 +69,6 @@ class CORE_EXPORT QgsVirtualPointCloudProvider: public QgsPointCloudDataProvider void populateAttributeCollection( QSet names ); QVector mSubLayers; std::unique_ptr mPolygonBounds; - std::unique_ptr mIndex; QgsPointCloudAttributeCollection mAttributes; QStringList mUriList; diff --git a/src/providers/pdal/qgspdalprovider.cpp b/src/providers/pdal/qgspdalprovider.cpp index bbaa347445774..879ada1488ba5 100644 --- a/src/providers/pdal/qgspdalprovider.cpp +++ b/src/providers/pdal/qgspdalprovider.cpp @@ -87,7 +87,7 @@ QgsPointCloudAttributeCollection QgsPdalProvider::attributes() const if ( mIndex ) { - return mIndex->attributes(); + return mIndex.attributes(); } if ( mDummyAttributes.count() > 0 ) @@ -118,7 +118,7 @@ void QgsPdalProvider::generateIndex() { QGIS_PROTECT_QOBJECT_THREAD_ACCESS - if ( mRunningIndexingTask || ( mIndex && mIndex->isValid() ) ) + if ( mRunningIndexingTask || ( mIndex && mIndex.isValid() ) ) return; if ( anyIndexingTaskExists() ) @@ -144,7 +144,7 @@ QgsPointCloudDataProvider::PointCloudIndexGenerationState QgsPdalProvider::index { QGIS_PROTECT_QOBJECT_THREAD_ACCESS - if ( mIndex && mIndex->isValid() ) + if ( mIndex && mIndex.isValid() ) return PointCloudIndexGenerationState::Indexed; else if ( mRunningIndexingTask ) return PointCloudIndexGenerationState::Indexing; @@ -156,32 +156,32 @@ void QgsPdalProvider::loadIndex() { QGIS_PROTECT_QOBJECT_THREAD_ACCESS - if ( mIndex && mIndex->isValid() ) + if ( mIndex && mIndex.isValid() ) return; // Try to load copc index - if ( !mIndex || !mIndex->isValid() ) + if ( !mIndex || !mIndex.isValid() ) { const QString outputFile = _outCopcFile( dataSourceUri() ); const QFileInfo fi( outputFile ); if ( fi.isFile() ) { - mIndex.reset( new QgsCopcPointCloudIndex ); - mIndex->load( outputFile ); + mIndex = new QgsCopcPointCloudIndex; + mIndex.load( outputFile ); } } // Try to load ept index - if ( !mIndex || !mIndex->isValid() ) + if ( !mIndex || !mIndex.isValid() ) { const QString outputDir = _outEptDir( dataSourceUri() ); const QString outEptJson = QStringLiteral( "%1/ept.json" ).arg( outputDir ); const QFileInfo fi( outEptJson ); if ( fi.isFile() ) { - mIndex.reset( new QgsEptPointCloudIndex ); - mIndex->load( outEptJson ); + mIndex = new QgsEptPointCloudIndex; + mIndex.load( outEptJson ); } } - if ( !mIndex || !mIndex->isValid() ) + if ( !mIndex || !mIndex.isValid() ) { QgsDebugMsgLevel( QStringLiteral( "pdalprovider: neither copc or ept index for dataset %1 is not correctly loaded" ).arg( dataSourceUri() ), 2 ); } @@ -273,11 +273,11 @@ QString QgsPdalProvider::description() const return QStringLiteral( "Point Clouds PDAL" ); } -QgsPointCloudIndex *QgsPdalProvider::index() const +QgsPointCloudIndex QgsPdalProvider::index() const { QGIS_PROTECT_QOBJECT_THREAD_ACCESS - return mIndex.get(); + return mIndex; } bool QgsPdalProvider::load( const QString &uri ) diff --git a/src/providers/pdal/qgspdalprovider.h b/src/providers/pdal/qgspdalprovider.h index 4d23b7bb3cae2..fc08a0b30515a 100644 --- a/src/providers/pdal/qgspdalprovider.h +++ b/src/providers/pdal/qgspdalprovider.h @@ -40,7 +40,7 @@ class QgsPdalProvider : public QgsPointCloudDataProvider bool isValid() const override; QString name() const override; QString description() const override; - QgsPointCloudIndex *index() const override; + QgsPointCloudIndex index() const override; void loadIndex() override; void generateIndex() override; PointCloudIndexGenerationState indexingState() override; @@ -60,7 +60,7 @@ class QgsPdalProvider : public QgsPointCloudDataProvider QVariantMap mOriginalMetadata; // will be used when layer was not indexed, e.g. when loaded by Processing algorithm QgsPointCloudAttributeCollection mDummyAttributes; - std::unique_ptr mIndex; + QgsPointCloudIndex mIndex; QgsPdalIndexingTask *mRunningIndexingTask = nullptr; static QQueue sIndexingQueue; }; diff --git a/tests/src/providers/testqgscopcprovider.cpp b/tests/src/providers/testqgscopcprovider.cpp index 48d273b1c8be5..a8499f95104c8 100644 --- a/tests/src/providers/testqgscopcprovider.cpp +++ b/tests/src/providers/testqgscopcprovider.cpp @@ -265,8 +265,8 @@ void TestQgsCopcProvider::validLayer() QVERIFY( layer->dataProvider()->index() ); // all hierarchy is stored in a single node - QVERIFY( layer->dataProvider()->index()->hasNode( QgsPointCloudNodeId::fromString( "0-0-0-0" ) ) ); - QVERIFY( !layer->dataProvider()->index()->hasNode( QgsPointCloudNodeId::fromString( "1-0-0-0" ) ) ); + QVERIFY( layer->dataProvider()->index().hasNode( QgsPointCloudNodeId::fromString( "0-0-0-0" ) ) ); + QVERIFY( !layer->dataProvider()->index().hasNode( QgsPointCloudNodeId::fromString( "1-0-0-0" ) ) ); } void TestQgsCopcProvider::validLayerWithCopcHierarchy() @@ -283,8 +283,8 @@ void TestQgsCopcProvider::validLayerWithCopcHierarchy() QVERIFY( layer->dataProvider()->index() ); // all hierarchy is stored in multiple nodes - QVERIFY( layer->dataProvider()->index()->hasNode( QgsPointCloudNodeId::fromString( "1-1-1-0" ) ) ); - QVERIFY( layer->dataProvider()->index()->hasNode( QgsPointCloudNodeId::fromString( "2-3-3-1" ) ) ); + QVERIFY( layer->dataProvider()->index().hasNode( QgsPointCloudNodeId::fromString( "1-1-1-0" ) ) ); + QVERIFY( layer->dataProvider()->index().hasNode( QgsPointCloudNodeId::fromString( "2-3-3-1" ) ) ); } void TestQgsCopcProvider::attributes() @@ -824,26 +824,26 @@ void TestQgsCopcProvider::testPointCloudIndex() std::unique_ptr layer = std::make_unique( dataPath, QStringLiteral( "layer" ), QStringLiteral( "copc" ) ); QVERIFY( layer->isValid() ); - QgsPointCloudIndex *index = layer->dataProvider()->index(); - QVERIFY( index->isValid() ); + QgsPointCloudIndex index = layer->dataProvider()->index(); + QVERIFY( index.isValid() ); - QCOMPARE( index->getNode( QgsPointCloudNodeId::fromString( QStringLiteral( "0-0-0-0" ) ) ).pointCount(), 56721 ); - QVERIFY( !index->hasNode( QgsPointCloudNodeId::fromString( QStringLiteral( "1-1-1-1" ) ) ) ); - QCOMPARE( index->getNode( QgsPointCloudNodeId::fromString( QStringLiteral( "2-3-3-1" ) ) ).pointCount(), 446 ); - QVERIFY( !index->hasNode( QgsPointCloudNodeId::fromString( QStringLiteral( "9-9-9-9" ) ) ) ); + QCOMPARE( index.getNode( QgsPointCloudNodeId::fromString( QStringLiteral( "0-0-0-0" ) ) ).pointCount(), 56721 ); + QVERIFY( !index.hasNode( QgsPointCloudNodeId::fromString( QStringLiteral( "1-1-1-1" ) ) ) ); + QCOMPARE( index.getNode( QgsPointCloudNodeId::fromString( QStringLiteral( "2-3-3-1" ) ) ).pointCount(), 446 ); + QVERIFY( !index.hasNode( QgsPointCloudNodeId::fromString( QStringLiteral( "9-9-9-9" ) ) ) ); - QCOMPARE( index->pointCount(), 518862 ); - QCOMPARE( index->zMin(), 2322.89625 ); - QCOMPARE( index->zMax(), 2338.5755 ); - QCOMPARE( index->scale().toVector3D(), QVector3D( 0.0001f, 0.0001f, 0.0001f ) ); - QCOMPARE( index->offset().toVector3D(), QVector3D( 515385, 4918361, 2330.5 ) ); - QCOMPARE( index->span(), 128 ); + QCOMPARE( index.pointCount(), 518862 ); + QCOMPARE( index.zMin(), 2322.89625 ); + QCOMPARE( index.zMax(), 2338.5755 ); + QCOMPARE( index.scale().toVector3D(), QVector3D( 0.0001f, 0.0001f, 0.0001f ) ); + QCOMPARE( index.offset().toVector3D(), QVector3D( 515385, 4918361, 2330.5 ) ); + QCOMPARE( index.span(), 128 ); - QCOMPARE( index->getNode( QgsPointCloudNodeId::fromString( QStringLiteral( "0-0-0-0" ) ) ).error(), 0.328125 ); - QCOMPARE( index->getNode( QgsPointCloudNodeId::fromString( QStringLiteral( "2-3-3-1" ) ) ).error(), 0.08203125 ); + QCOMPARE( index.getNode( QgsPointCloudNodeId::fromString( QStringLiteral( "0-0-0-0" ) ) ).error(), 0.328125 ); + QCOMPARE( index.getNode( QgsPointCloudNodeId::fromString( QStringLiteral( "2-3-3-1" ) ) ).error(), 0.08203125 ); { - QgsBox3D bounds = index->getNode( QgsPointCloudNodeId::fromString( QStringLiteral( "0-0-0-0" ) ) ).bounds(); + QgsBox3D bounds = index.getNode( QgsPointCloudNodeId::fromString( QStringLiteral( "0-0-0-0" ) ) ).bounds(); QCOMPARE( bounds.xMinimum(), 515368 ); QCOMPARE( bounds.yMinimum(), 4918340 ); QCOMPARE( bounds.zMinimum(), 2322 ); @@ -853,7 +853,7 @@ void TestQgsCopcProvider::testPointCloudIndex() } { - QgsBox3D bounds = QgsPointCloudNode::bounds( index->rootNodeBounds(), QgsPointCloudNodeId::fromString( QStringLiteral( "1-1-1-1" ) ) ); + QgsBox3D bounds = QgsPointCloudNode::bounds( index.rootNodeBounds(), QgsPointCloudNodeId::fromString( QStringLiteral( "1-1-1-1" ) ) ); QCOMPARE( bounds.xMinimum(), 515389 ); QCOMPARE( bounds.yMinimum(), 4918361 ); QCOMPARE( bounds.zMinimum(), 2343 ); @@ -863,7 +863,7 @@ void TestQgsCopcProvider::testPointCloudIndex() } { - QgsBox3D bounds = index->getNode( QgsPointCloudNodeId::fromString( QStringLiteral( "2-3-3-1" ) ) ).bounds(); + QgsBox3D bounds = index.getNode( QgsPointCloudNodeId::fromString( QStringLiteral( "2-3-3-1" ) ) ).bounds(); QCOMPARE( bounds.xMinimum(), 515399.5 ); QCOMPARE( bounds.yMinimum(), 4918371.5 ); QCOMPARE( bounds.zMinimum(), 2332.5 ); @@ -878,7 +878,7 @@ void TestQgsCopcProvider::testStatsCalculator() const QString dataPath = copyTestData( QStringLiteral( "/point_clouds/copc/extrabytes-dataset.copc.laz" ) ); std::unique_ptr layer = std::make_unique( dataPath, QStringLiteral( "layer" ), QStringLiteral( "copc" ) ); - QgsPointCloudIndex *index = layer->dataProvider()->index(); + QgsPointCloudIndex index = layer->dataProvider()->index(); QgsPointCloudStatsCalculator calculator( index ); QVector attributes; @@ -1130,10 +1130,10 @@ void TestQgsCopcProvider::testSaveLoadStats() QVERIFY( layer->isValid() ); QVERIFY( layer->dataProvider() && layer->dataProvider()->isValid() && layer->dataProvider()->index() ); - QgsCopcPointCloudIndex *index = dynamic_cast( layer->dataProvider()->index() ); + QgsPointCloudIndex index = layer->dataProvider()->index(); calculatedStats = layer->statistics(); - index->writeStatistics( calculatedStats ); + index.writeStatistics( calculatedStats ); } { @@ -1142,8 +1142,8 @@ void TestQgsCopcProvider::testSaveLoadStats() QVERIFY( layer->dataProvider() && layer->dataProvider()->isValid() && layer->dataProvider()->index() ); - QgsCopcPointCloudIndex *index = dynamic_cast( layer->dataProvider()->index() ); - readStats = index->metadataStatistics(); + QgsPointCloudIndex index = layer->dataProvider()->index(); + readStats = index.metadataStatistics(); } QVERIFY( calculatedStats.sampledPointsCount() == readStats.sampledPointsCount() ); @@ -1157,19 +1157,19 @@ void TestQgsCopcProvider::testPointCloudRequest() std::unique_ptr layer = std::make_unique( dataPath, QStringLiteral( "layer" ), QStringLiteral( "copc" ) ); QVERIFY( layer->isValid() ); - QgsPointCloudIndex *index = layer->dataProvider()->index(); - QVERIFY( index->isValid() ); + QgsPointCloudIndex index = layer->dataProvider()->index(); + QVERIFY( index.isValid() ); QVector nodes; QQueue queue; - queue.push_back( index->root() ); + queue.push_back( index.root() ); while ( !queue.empty() ) { QgsPointCloudNodeId node = queue.front(); queue.pop_front(); nodes.push_back( node ); - for ( const QgsPointCloudNodeId &child : index->getNode( node ).children() ) + for ( const QgsPointCloudNodeId &child : index.getNode( node ).children() ) { queue.push_back( child ); } @@ -1181,7 +1181,7 @@ void TestQgsCopcProvider::testPointCloudRequest() int count = 0; for ( QgsPointCloudNodeId node : nodes ) { - auto block = index->nodeData( node, request ); + auto block = index.nodeData( node, request ); count += block->pointCount(); } QCOMPARE( count, layer->pointCount() ); @@ -1192,7 +1192,7 @@ void TestQgsCopcProvider::testPointCloudRequest() count = 0; for ( QgsPointCloudNodeId node : nodes ) { - auto block = index->nodeData( node, request ); + auto block = index.nodeData( node, request ); count += block->pointCount(); } QCOMPARE( count, 217600 ); @@ -1203,7 +1203,7 @@ void TestQgsCopcProvider::testPointCloudRequest() count = 0; for ( QgsPointCloudNodeId node : nodes ) { - auto block = index->nodeData( node, request ); + auto block = index.nodeData( node, request ); count += block->pointCount(); } QCOMPARE( count, 0 ); @@ -1214,7 +1214,7 @@ void TestQgsCopcProvider::testPointCloudRequest() request.setFilterRect( extent ); for ( QgsPointCloudNodeId node : nodes ) { - auto block = index->nodeData( node, request ); + auto block = index.nodeData( node, request ); count += block->pointCount(); } QCOMPARE( count, layer->pointCount() ); diff --git a/tests/src/providers/testqgseptprovider.cpp b/tests/src/providers/testqgseptprovider.cpp index 2797ab7e65049..2a63f256da49f 100644 --- a/tests/src/providers/testqgseptprovider.cpp +++ b/tests/src/providers/testqgseptprovider.cpp @@ -265,8 +265,8 @@ void TestQgsEptProvider::validLayer() QVERIFY( layer->dataProvider()->index() ); // all hierarchy is stored in a single node - QVERIFY( layer->dataProvider()->index()->hasNode( QgsPointCloudNodeId::fromString( "0-0-0-0" ) ) ); - QVERIFY( !layer->dataProvider()->index()->hasNode( QgsPointCloudNodeId::fromString( "1-0-0-0" ) ) ); + QVERIFY( layer->dataProvider()->index().hasNode( QgsPointCloudNodeId::fromString( "0-0-0-0" ) ) ); + QVERIFY( !layer->dataProvider()->index().hasNode( QgsPointCloudNodeId::fromString( "1-0-0-0" ) ) ); } void TestQgsEptProvider::validLayerWithEptHierarchy() @@ -283,8 +283,8 @@ void TestQgsEptProvider::validLayerWithEptHierarchy() QVERIFY( layer->dataProvider()->index() ); // all hierarchy is stored in multiple nodes - QVERIFY( layer->dataProvider()->index()->hasNode( QgsPointCloudNodeId::fromString( "1-1-1-1" ) ) ); - QVERIFY( layer->dataProvider()->index()->hasNode( QgsPointCloudNodeId::fromString( "2-3-3-1" ) ) ); + QVERIFY( layer->dataProvider()->index().hasNode( QgsPointCloudNodeId::fromString( "1-1-1-1" ) ) ); + QVERIFY( layer->dataProvider()->index().hasNode( QgsPointCloudNodeId::fromString( "2-3-3-1" ) ) ); } void TestQgsEptProvider::attributes() @@ -627,27 +627,27 @@ void TestQgsEptProvider::testPointCloudIndex() std::unique_ptr layer = std::make_unique( path + QStringLiteral( "/ept.json" ), QStringLiteral( "layer" ), QStringLiteral( "ept" ) ); QVERIFY( layer->isValid() ); - QgsPointCloudIndex *index = layer->dataProvider()->index(); - QVERIFY( index->isValid() ); + QgsPointCloudIndex index = layer->dataProvider()->index(); + QVERIFY( index.isValid() ); - QCOMPARE( index->getNode( QgsPointCloudNodeId::fromString( QStringLiteral( "0-0-0-0" ) ) ).pointCount(), 41998 ); - QCOMPARE( index->getNode( QgsPointCloudNodeId::fromString( QStringLiteral( "1-1-1-1" ) ) ).pointCount(), 48879 ); - QCOMPARE( index->getNode( QgsPointCloudNodeId::fromString( QStringLiteral( "2-3-3-1" ) ) ).pointCount(), 41734 ); - QVERIFY( !index->hasNode( QgsPointCloudNodeId::fromString( QStringLiteral( "9-9-9-9" ) ) ) ); + QCOMPARE( index.getNode( QgsPointCloudNodeId::fromString( QStringLiteral( "0-0-0-0" ) ) ).pointCount(), 41998 ); + QCOMPARE( index.getNode( QgsPointCloudNodeId::fromString( QStringLiteral( "1-1-1-1" ) ) ).pointCount(), 48879 ); + QCOMPARE( index.getNode( QgsPointCloudNodeId::fromString( QStringLiteral( "2-3-3-1" ) ) ).pointCount(), 41734 ); + QVERIFY( !index.hasNode( QgsPointCloudNodeId::fromString( QStringLiteral( "9-9-9-9" ) ) ) ); - QCOMPARE( index->pointCount(), 518862 ); - QCOMPARE( index->zMin(), 2322 ); - QCOMPARE( index->zMax(), 2339 ); - QCOMPARE( index->scale().toVector3D(), QVector3D( 0.00025f, 0.00025f, 0.00025f ) ); - QCOMPARE( index->offset().toVector3D(), QVector3D( 515385, 4918361, 2331 ) ); - QCOMPARE( index->span(), 128 ); + QCOMPARE( index.pointCount(), 518862 ); + QCOMPARE( index.zMin(), 2322 ); + QCOMPARE( index.zMax(), 2339 ); + QCOMPARE( index.scale().toVector3D(), QVector3D( 0.00025f, 0.00025f, 0.00025f ) ); + QCOMPARE( index.offset().toVector3D(), QVector3D( 515385, 4918361, 2331 ) ); + QCOMPARE( index.span(), 128 ); - QCOMPARE( index->getNode( QgsPointCloudNodeId::fromString( QStringLiteral( "0-0-0-0" ) ) ).error(), 0.34375 ); - QCOMPARE( index->getNode( QgsPointCloudNodeId::fromString( QStringLiteral( "1-1-1-1" ) ) ).error(), 0.171875 ); - QCOMPARE( index->getNode( QgsPointCloudNodeId::fromString( QStringLiteral( "2-3-3-1" ) ) ).error(), 0.0859375 ); + QCOMPARE( index.getNode( QgsPointCloudNodeId::fromString( QStringLiteral( "0-0-0-0" ) ) ).error(), 0.34375 ); + QCOMPARE( index.getNode( QgsPointCloudNodeId::fromString( QStringLiteral( "1-1-1-1" ) ) ).error(), 0.171875 ); + QCOMPARE( index.getNode( QgsPointCloudNodeId::fromString( QStringLiteral( "2-3-3-1" ) ) ).error(), 0.0859375 ); { - QgsBox3D bounds = index->getNode( QgsPointCloudNodeId::fromString( QStringLiteral( "0-0-0-0" ) ) ).bounds(); + QgsBox3D bounds = index.getNode( QgsPointCloudNodeId::fromString( QStringLiteral( "0-0-0-0" ) ) ).bounds(); QCOMPARE( bounds.xMinimum(), 515363 ); QCOMPARE( bounds.yMinimum(), 4918339 ); QCOMPARE( bounds.zMinimum(), 2309 ); @@ -657,7 +657,7 @@ void TestQgsEptProvider::testPointCloudIndex() } { - QgsBox3D bounds = index->getNode( QgsPointCloudNodeId::fromString( QStringLiteral( "1-1-1-1" ) ) ).bounds(); + QgsBox3D bounds = index.getNode( QgsPointCloudNodeId::fromString( QStringLiteral( "1-1-1-1" ) ) ).bounds(); QCOMPARE( bounds.xMinimum(), 515385 ); QCOMPARE( bounds.yMinimum(), 4918361 ); QCOMPARE( bounds.zMinimum(), 2331 ); @@ -667,7 +667,7 @@ void TestQgsEptProvider::testPointCloudIndex() } { - QgsBox3D bounds = index->getNode( QgsPointCloudNodeId::fromString( QStringLiteral( "2-3-3-1" ) ) ).bounds(); + QgsBox3D bounds = index.getNode( QgsPointCloudNodeId::fromString( QStringLiteral( "2-3-3-1" ) ) ).bounds(); QCOMPARE( bounds.xMinimum(), 515396 ); QCOMPARE( bounds.yMinimum(), 4918372 ); QCOMPARE( bounds.zMinimum(), 2320 ); @@ -684,19 +684,19 @@ void TestQgsEptProvider::testPointCloudRequest() std::unique_ptr layer = std::make_unique( path + QStringLiteral( "/ept.json" ), QStringLiteral( "layer" ), QStringLiteral( "ept" ) ); QVERIFY( layer->isValid() ); - QgsPointCloudIndex *index = layer->dataProvider()->index(); - QVERIFY( index->isValid() ); + QgsPointCloudIndex index = layer->dataProvider()->index(); + QVERIFY( index.isValid() ); QVector nodes; QQueue queue; - queue.push_back( index->root() ); + queue.push_back( index.root() ); while ( !queue.empty() ) { QgsPointCloudNodeId node = queue.front(); queue.pop_front(); nodes.push_back( node ); - for ( const QgsPointCloudNodeId &child : index->getNode( node ).children() ) + for ( const QgsPointCloudNodeId &child : index.getNode( node ).children() ) { queue.push_back( child ); } @@ -708,7 +708,7 @@ void TestQgsEptProvider::testPointCloudRequest() int count = 0; for ( QgsPointCloudNodeId node : nodes ) { - std::unique_ptr block( index->nodeData( node, request ) ); + std::unique_ptr block( index.nodeData( node, request ) ); count += block->pointCount(); } QCOMPARE( count, layer->pointCount() ); @@ -719,7 +719,7 @@ void TestQgsEptProvider::testPointCloudRequest() count = 0; for ( QgsPointCloudNodeId node : nodes ) { - std::unique_ptr block( index->nodeData( node, request ) ); + std::unique_ptr block( index.nodeData( node, request ) ); count += block->pointCount(); } QCOMPARE( count, 217600 ); @@ -730,7 +730,7 @@ void TestQgsEptProvider::testPointCloudRequest() count = 0; for ( QgsPointCloudNodeId node : nodes ) { - std::unique_ptr block( index->nodeData( node, request ) ); + std::unique_ptr block( index.nodeData( node, request ) ); count += block->pointCount(); } QCOMPARE( count, 0 ); @@ -741,7 +741,7 @@ void TestQgsEptProvider::testPointCloudRequest() request.setFilterRect( extent ); for ( QgsPointCloudNodeId node : nodes ) { - std::unique_ptr block( index->nodeData( node, request ) ); + std::unique_ptr block( index.nodeData( node, request ) ); count += block->pointCount(); } QCOMPARE( count, layer->pointCount() ); @@ -752,7 +752,7 @@ void TestQgsEptProvider::testStatsCalculator() const QString path = copyTestDataDirectory( QStringLiteral( "point_clouds/ept/extrabytes-dataset" ) ); std::unique_ptr layer = std::make_unique( path + QStringLiteral( "/ept.json" ), QStringLiteral( "layer" ), QStringLiteral( "ept" ) ); - QgsPointCloudIndex *index = layer->dataProvider()->index(); + QgsPointCloudIndex index = layer->dataProvider()->index(); QgsPointCloudStatsCalculator calculator( index ); QVector attributes; diff --git a/tests/src/providers/testqgsvirtualpointcloudprovider.cpp b/tests/src/providers/testqgsvirtualpointcloudprovider.cpp index 61fac3d1f866c..1d49725bd3103 100644 --- a/tests/src/providers/testqgsvirtualpointcloudprovider.cpp +++ b/tests/src/providers/testqgsvirtualpointcloudprovider.cpp @@ -223,7 +223,7 @@ void TestQgsVirtualPointCloudProvider::validLayer() QCOMPARE( layer->dataProvider()->pointCount(), 3365334 ); QCOMPARE( layer->pointCount(), 3365334 ); - QCOMPARE( layer->dataProvider()->index(), nullptr ); + QVERIFY( !layer->dataProvider()->index() ); } void TestQgsVirtualPointCloudProvider::attributes() @@ -272,8 +272,8 @@ void TestQgsVirtualPointCloudProvider::testLazyLoading() std::unique_ptr layer = std::make_unique( mTestDataDir + QStringLiteral( "point_clouds/virtual/tiles.vpc" ), QStringLiteral( "layer" ), QStringLiteral( "vpc" ) ); QVERIFY( layer->isValid() ); - QgsPointCloudIndex *index = layer->dataProvider()->index(); - QCOMPARE( index, nullptr ); + QgsPointCloudIndex index = layer->dataProvider()->index(); + QVERIFY( !index ); QVector subIndexes = layer->dataProvider()->subIndexes();