diff --git a/src/3d/qgspointcloudlayerchunkloader_p.cpp b/src/3d/qgspointcloudlayerchunkloader_p.cpp index b3ab8ba1e2734..e94aa6909e7c8 100644 --- a/src/3d/qgspointcloudlayerchunkloader_p.cpp +++ b/src/3d/qgspointcloudlayerchunkloader_p.cpp @@ -17,6 +17,7 @@ #include "moc_qgspointcloudlayerchunkloader_p.cpp" #include "qgs3dutils.h" +#include "qgsbox3d.h" #include "qgspointcloudlayer3drenderer.h" #include "qgschunknode.h" #include "qgslogger.h" @@ -57,7 +58,7 @@ QgsPointCloudLayerChunkLoader::QgsPointCloudLayerChunkLoader( const QgsPointClou mContext.setAttributes( pc->attributes() ); const QgsChunkNodeId nodeId = node->tileId(); - const IndexedPointCloudNode pcNode( nodeId.d, nodeId.x, nodeId.y, nodeId.z ); + const QgsPointCloudNodeId pcNode( nodeId.d, nodeId.x, nodeId.y, nodeId.z ); Q_ASSERT( pc->hasNode( pcNode ) ); @@ -128,7 +129,7 @@ Qt3DCore::QEntity *QgsPointCloudLayerChunkLoader::createEntity( Qt3DCore::QEntit { QgsPointCloudIndex *pc = mFactory->mPointCloudIndex; const QgsChunkNodeId nodeId = mNode->tileId(); - const IndexedPointCloudNode pcNode( nodeId.d, nodeId.x, nodeId.y, nodeId.z ); + const QgsPointCloudNodeId pcNode( nodeId.d, nodeId.x, nodeId.y, nodeId.z ); Q_ASSERT( pc->hasNode( pcNode ) ); Qt3DCore::QEntity *entity = new Qt3DCore::QEntity( parent ); @@ -165,7 +166,7 @@ QgsChunkLoader *QgsPointCloudLayerChunkLoaderFactory::createChunkLoader( QgsChun { const QgsChunkNodeId id = node->tileId(); - Q_ASSERT( mPointCloudIndex->hasNode( IndexedPointCloudNode( 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< QgsPointCloud3DSymbol * >( mSymbol->clone() ); return new QgsPointCloudLayerChunkLoader( this, node, std::unique_ptr< QgsPointCloud3DSymbol >( symbol ), mCoordinateTransform, mZValueScale, mZValueOffset ); } @@ -173,20 +174,20 @@ QgsChunkLoader *QgsPointCloudLayerChunkLoaderFactory::createChunkLoader( QgsChun int QgsPointCloudLayerChunkLoaderFactory::primitivesCount( QgsChunkNode *node ) const { const QgsChunkNodeId id = node->tileId(); - const IndexedPointCloudNode n( id.d, id.x, id.y, id.z ); + const QgsPointCloudNodeId n( id.d, id.x, id.y, id.z ); Q_ASSERT( mPointCloudIndex->hasNode( n ) ); - return mPointCloudIndex->nodePointCount( n ); + return mPointCloudIndex->getNode( n ).pointCount(); } -QgsBox3D nodeBoundsToBox3D( QgsPointCloudDataBounds nodeBounds, QgsVector3D offset, QgsVector3D scale, const QgsCoordinateTransform &coordinateTransform, double zValueOffset, double zValueScale ) +static QgsBox3D nodeBoundsToBox3D( QgsBox3D nodeBounds, const QgsCoordinateTransform &coordinateTransform, double zValueOffset, double zValueScale ) { - QgsVector3D extentMin3D( static_cast( nodeBounds.xMin() ) * scale.x() + offset.x(), - static_cast( nodeBounds.yMin() ) * scale.y() + offset.y(), - ( static_cast( nodeBounds.zMin() ) * scale.z() + offset.z() ) * zValueScale + zValueOffset ); - QgsVector3D extentMax3D( static_cast( nodeBounds.xMax() ) * scale.x() + offset.x(), - static_cast( nodeBounds.yMax() ) * scale.y() + offset.y(), - ( static_cast( nodeBounds.zMax() ) * scale.z() + offset.z() ) * zValueScale + zValueOffset ); + QgsVector3D extentMin3D( static_cast( nodeBounds.xMinimum() ), + static_cast( nodeBounds.yMinimum() ), + static_cast( nodeBounds.zMinimum() ) * zValueScale + zValueOffset ); + QgsVector3D extentMax3D( static_cast( nodeBounds.xMaximum() ), + static_cast( nodeBounds.yMaximum() ), + static_cast( nodeBounds.zMaximum() ) * zValueScale + zValueOffset ); QgsCoordinateTransform extentTransform = coordinateTransform; extentTransform.setBallparkTransformsAreAppropriate( true ); try @@ -205,10 +206,11 @@ QgsBox3D nodeBoundsToBox3D( QgsPointCloudDataBounds nodeBounds, QgsVector3D offs QgsChunkNode *QgsPointCloudLayerChunkLoaderFactory::createRootNode() const { - const QgsPointCloudDataBounds rootNodeBounds = mPointCloudIndex->nodeBounds( IndexedPointCloudNode( 0, 0, 0, 0 ) ); - QgsBox3D rootNodeBox3D = nodeBoundsToBox3D( rootNodeBounds, mPointCloudIndex->offset(), mPointCloudIndex->scale(), mCoordinateTransform, mZValueOffset, mZValueScale ); + const QgsPointCloudNode pcNode = mPointCloudIndex->getNode( mPointCloudIndex->root() ); + const QgsBox3D rootNodeBounds = pcNode.bounds(); + QgsBox3D rootNodeBox3D = nodeBoundsToBox3D( rootNodeBounds, mCoordinateTransform, mZValueOffset, mZValueScale ); - const float error = mPointCloudIndex->nodeError( IndexedPointCloudNode( 0, 0, 0, 0 ) ); + const float error = pcNode.error(); QgsChunkNode *node = new QgsChunkNode( QgsChunkNodeId( 0, 0, 0, 0 ), rootNodeBox3D, error ); node->setRefinementProcess( mSymbol->renderAsTriangles() ? Qgis::TileRefinementProcess::Replacement : Qgis::TileRefinementProcess::Additive ); return node; @@ -224,15 +226,16 @@ 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 ); - - if ( !mPointCloudIndex->hasNode( IndexedPointCloudNode( childId.d, childId.x, childId.y, childId.z ) ) ) + const QgsPointCloudNodeId childPcId( childId.d, childId.x, childId.y, childId.z ); + if ( !mPointCloudIndex->hasNode( childPcId ) ) continue; + const QgsPointCloudNode childNode = mPointCloudIndex->getNode( childPcId ); + const QgsBox3D childBounds = childNode.bounds(); if ( !mExtent.isEmpty() && - !mPointCloudIndex->nodeMapExtent( IndexedPointCloudNode( childId.d, childId.x, childId.y, childId.z ) ).intersects( mExtent ) ) + !childBounds.intersects( mExtent ) ) continue; - const QgsPointCloudDataBounds childBounds = mPointCloudIndex->nodeBounds( IndexedPointCloudNode( childId.d, childId.x, childId.y, childId.z ) ); - QgsBox3D childBox3D = nodeBoundsToBox3D( childBounds, mPointCloudIndex->offset(), mPointCloudIndex->scale(), mCoordinateTransform, mZValueOffset, mZValueScale ); + QgsBox3D childBox3D = nodeBoundsToBox3D( childBounds, mCoordinateTransform, mZValueOffset, mZValueScale ); QgsChunkNode *child = new QgsChunkNode( childId, childBox3D, childError, node ); child->setRefinementProcess( mSymbol->renderAsTriangles() ? Qgis::TileRefinementProcess::Replacement : Qgis::TileRefinementProcess::Additive ); @@ -302,7 +305,7 @@ QVector QgsPointCloudLayerChunkedEntity::rayIntersec for ( QgsChunkNode *node : activeNodes ) { const QgsChunkNodeId id = node->tileId(); - const IndexedPointCloudNode n( id.d, id.x, id.y, id.z ); + const QgsPointCloudNodeId n( id.d, id.x, id.y, id.z ); if ( !index->hasNode( n ) ) continue; diff --git a/src/3d/symbols/qgspointcloud3dsymbol_p.cpp b/src/3d/symbols/qgspointcloud3dsymbol_p.cpp index 80b9b4f8a0b79..6a920c8510164 100644 --- a/src/3d/symbols/qgspointcloud3dsymbol_p.cpp +++ b/src/3d/symbols/qgspointcloud3dsymbol_p.cpp @@ -56,15 +56,15 @@ 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 IndexedPointCloudNode &n, const QgsPointCloud3DRenderContext &context, const QgsPointCloudBlock *block ) +static QgsVector3D originFromNodeBounds( QgsPointCloudIndex *pc, const QgsPointCloudNodeId &n, const QgsPointCloud3DRenderContext &context, const QgsPointCloudBlock *block ) { const QgsVector3D blockScale = block->scale(); const QgsVector3D blockOffset = block->offset(); - QgsPointCloudDataBounds bounds = pc->nodeBounds( n ); - double nodeOriginX = bounds.xMin() * blockScale.x() + blockOffset.x(); - double nodeOriginY = bounds.yMin() * blockScale.y() + blockOffset.y(); - double nodeOriginZ = ( bounds.zMin() * blockScale.z() + blockOffset.z() ) * context.zValueScale() + context.zValueFixedOffset(); + QgsBox3D bounds = pc->getNode( n ).bounds(); + double nodeOriginX = bounds.xMinimum() * blockScale.x() + blockOffset.x(); + double nodeOriginY = bounds.yMinimum() * blockScale.y() + blockOffset.y(); + double nodeOriginZ = ( bounds.zMinimum() * blockScale.z() + blockOffset.z() ) * context.zValueScale() + context.zValueFixedOffset(); try { context.coordinateTransform().transformInPlace( nodeOriginX, nodeOriginY, nodeOriginZ ); @@ -359,7 +359,7 @@ void QgsPointCloud3DSymbolHandler::makeEntity( Qt3DCore::QEntity *parent, const } -std::vector QgsPointCloud3DSymbolHandler::getVertices( QgsPointCloudIndex *pc, const IndexedPointCloudNode &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(); @@ -376,7 +376,7 @@ std::vector QgsPointCloud3DSymbolHandler::getVertices( QgsPointCloudInde } // next, we also need all points of all parents nodes to make the triangulation (also external points) - IndexedPointCloudNode parentNode = n.parentNode(); + QgsPointCloudNodeId parentNode = n.parentNode(); double span = pc->span(); //factor to take account of the density of the point to calculate extension of the bounding box @@ -520,7 +520,7 @@ void QgsPointCloud3DSymbolHandler::filterTriangles( const std::vector &t } } -void QgsPointCloud3DSymbolHandler::triangulate( QgsPointCloudIndex *pc, const IndexedPointCloudNode &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; @@ -547,7 +547,7 @@ void QgsPointCloud3DSymbolHandler::triangulate( QgsPointCloudIndex *pc, const In filterTriangles( triangleIndexes, context, box3D ); } -std::unique_ptr QgsPointCloud3DSymbolHandler::pointCloudBlock( QgsPointCloudIndex *pc, const IndexedPointCloudNode &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 ) @@ -556,7 +556,8 @@ std::unique_ptr QgsPointCloud3DSymbolHandler::pointCloudBloc } else if ( pc->accessType() == QgsPointCloudIndex::AccessType::Remote ) { - if ( pc->nodePointCount( n ) < 1 ) + QgsPointCloudNode node = pc->getNode( n ); + if ( node.pointCount() < 1 ) return block; bool loopAborted = false; @@ -590,7 +591,7 @@ bool QgsSingleColorPointCloud3DSymbolHandler::prepare( const QgsPointCloud3DRend return true; } -void QgsSingleColorPointCloud3DSymbolHandler::processNode( QgsPointCloudIndex *pc, const IndexedPointCloudNode &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 ) ); @@ -670,7 +671,7 @@ bool QgsColorRampPointCloud3DSymbolHandler::prepare( const QgsPointCloud3DRender return true; } -void QgsColorRampPointCloud3DSymbolHandler::processNode( QgsPointCloudIndex *pc, const IndexedPointCloudNode &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; @@ -808,7 +809,7 @@ bool QgsRGBPointCloud3DSymbolHandler::prepare( const QgsPointCloud3DRenderContex return true; } -void QgsRGBPointCloud3DSymbolHandler::processNode( QgsPointCloudIndex *pc, const IndexedPointCloudNode &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 ) ); @@ -953,7 +954,7 @@ bool QgsClassificationPointCloud3DSymbolHandler::prepare( const QgsPointCloud3DR return true; } -void QgsClassificationPointCloud3DSymbolHandler::processNode( QgsPointCloudIndex *pc, const IndexedPointCloudNode &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 acda5656ecfcd..579d2a3ca5b86 100644 --- a/src/3d/symbols/qgspointcloud3dsymbol_p.h +++ b/src/3d/symbols/qgspointcloud3dsymbol_p.h @@ -32,7 +32,7 @@ #define SIP_NO_FILE -class IndexedPointCloudNode; +class QgsPointCloudNodeId; class QgsAABB; class QgsPointCloud3DSymbolHandler @@ -45,10 +45,10 @@ class QgsPointCloud3DSymbolHandler struct PointData; virtual bool prepare( const QgsPointCloud3DRenderContext &context ) = 0;// override; - virtual void processNode( QgsPointCloudIndex *pc, const IndexedPointCloudNode &n, const QgsPointCloud3DRenderContext &context, PointData *output = nullptr ) = 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 IndexedPointCloudNode &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 IndexedPointCloudNode &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 IndexedPointCloudNode &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 IndexedPointCloudNode &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 IndexedPointCloudNode &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 IndexedPointCloudNode &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 IndexedPointCloudNode &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/qgscachedpointcloudblockrequest.cpp b/src/core/pointcloud/qgscachedpointcloudblockrequest.cpp index 1acd1df58792c..aed6418d9db9e 100644 --- a/src/core/pointcloud/qgscachedpointcloudblockrequest.cpp +++ b/src/core/pointcloud/qgscachedpointcloudblockrequest.cpp @@ -20,7 +20,7 @@ ///@cond PRIVATE -QgsCachedPointCloudBlockRequest::QgsCachedPointCloudBlockRequest( QgsPointCloudBlock *block, const IndexedPointCloudNode &node, const QString &uri, +QgsCachedPointCloudBlockRequest::QgsCachedPointCloudBlockRequest( QgsPointCloudBlock *block, const QgsPointCloudNodeId &node, const QString &uri, const QgsPointCloudAttributeCollection &attributes, const QgsPointCloudAttributeCollection &requestedAttributes, const QgsVector3D &scale, const QgsVector3D &offset, const QgsPointCloudExpression &filterExpression, const QgsRectangle &filterRect ) : QgsPointCloudBlockRequest( node, uri, attributes, requestedAttributes, scale, offset, filterExpression, filterRect ) diff --git a/src/core/pointcloud/qgscachedpointcloudblockrequest.h b/src/core/pointcloud/qgscachedpointcloudblockrequest.h index 324292701f0c0..b500f60852a78 100644 --- a/src/core/pointcloud/qgscachedpointcloudblockrequest.h +++ b/src/core/pointcloud/qgscachedpointcloudblockrequest.h @@ -44,7 +44,7 @@ class CORE_EXPORT QgsCachedPointCloudBlockRequest : public QgsPointCloudBlockReq * QgsCachedPointCloudBlockRequest constructor using an existing \a block * Note: Ownership of \a block is transferred */ - QgsCachedPointCloudBlockRequest( QgsPointCloudBlock *block, const IndexedPointCloudNode &node, const QString &uri, + QgsCachedPointCloudBlockRequest( QgsPointCloudBlock *block, const QgsPointCloudNodeId &node, const QString &uri, const QgsPointCloudAttributeCollection &attributes, const QgsPointCloudAttributeCollection &requestedAttributes, const QgsVector3D &scale, const QgsVector3D &offset, const QgsPointCloudExpression &filterExpression, const QgsRectangle &filterRect ); diff --git a/src/core/pointcloud/qgscopcpointcloudblockrequest.cpp b/src/core/pointcloud/qgscopcpointcloudblockrequest.cpp index 148fc3ee15453..8a93ea33c8779 100644 --- a/src/core/pointcloud/qgscopcpointcloudblockrequest.cpp +++ b/src/core/pointcloud/qgscopcpointcloudblockrequest.cpp @@ -30,7 +30,7 @@ ///@cond PRIVATE -QgsCopcPointCloudBlockRequest::QgsCopcPointCloudBlockRequest( const IndexedPointCloudNode &node, const QString &uri, +QgsCopcPointCloudBlockRequest::QgsCopcPointCloudBlockRequest( const QgsPointCloudNodeId &node, const QString &uri, const QgsPointCloudAttributeCollection &attributes, const QgsPointCloudAttributeCollection &requestedAttributes, const QgsVector3D &scale, const QgsVector3D &offset, const QgsPointCloudExpression &filterExpression, const QgsRectangle &filterRect, uint64_t blockOffset, int32_t blockSize, int pointCount, const QgsLazInfo &lazInfo ) diff --git a/src/core/pointcloud/qgscopcpointcloudblockrequest.h b/src/core/pointcloud/qgscopcpointcloudblockrequest.h index 8c68ec61fafeb..32cc9aa2685d7 100644 --- a/src/core/pointcloud/qgscopcpointcloudblockrequest.h +++ b/src/core/pointcloud/qgscopcpointcloudblockrequest.h @@ -46,7 +46,7 @@ class CORE_EXPORT QgsCopcPointCloudBlockRequest : public QgsPointCloudBlockReque * Requests the block data of size \a blockSize at offset blockOffset * Note: It is the responsablitiy of the caller to delete the block if it was loaded correctly */ - QgsCopcPointCloudBlockRequest( const IndexedPointCloudNode &node, const QString &Uri, + QgsCopcPointCloudBlockRequest( const QgsPointCloudNodeId &node, const QString &Uri, const QgsPointCloudAttributeCollection &attributes, const QgsPointCloudAttributeCollection &requestedAttributes, const QgsVector3D &scale, const QgsVector3D &offset, const QgsPointCloudExpression &filterExpression, const QgsRectangle &filterRect, uint64_t blockOffset, int32_t blockSize, int pointCount, const QgsLazInfo &lazInfo ); diff --git a/src/core/pointcloud/qgscopcpointcloudindex.cpp b/src/core/pointcloud/qgscopcpointcloudindex.cpp index 2c876afb81ae8..2c1ad603a2cd7 100644 --- a/src/core/pointcloud/qgscopcpointcloudindex.cpp +++ b/src/core/pointcloud/qgscopcpointcloudindex.cpp @@ -27,6 +27,7 @@ #include #include "qgsapplication.h" +#include "qgsbox3d.h" #include "qgscachedpointcloudblockrequest.h" #include "qgscopcpointcloudblockrequest.h" #include "qgseptdecoder.h" @@ -71,7 +72,7 @@ void QgsCopcPointCloudIndex::load( const QString &urlString ) mCopcFile.open( QgsLazDecoder::toNativePath( urlString ), std::ios::binary ); if ( mCopcFile.fail() ) { - mError = tr( "Unable to open %1 for reading" ).arg( urlString ); + mError = QObject::tr( "Unable to open %1 for reading" ).arg( urlString ); mIsValid = false; return; } @@ -93,7 +94,7 @@ void QgsCopcPointCloudIndex::load( const QString &urlString ) } if ( !mIsValid ) { - mError = tr( "Unable to recognize %1 as a LAZ file: \"%2\"" ).arg( urlString, mLazInfo->error() ); + mError = QObject::tr( "Unable to recognize %1 as a LAZ file: \"%2\"" ).arg( urlString, mLazInfo->error() ); } } @@ -102,7 +103,7 @@ bool QgsCopcPointCloudIndex::loadSchema( QgsLazInfo &lazInfo ) QByteArray copcInfoVlrData = lazInfo.vlrData( QStringLiteral( "copc" ), 1 ); if ( copcInfoVlrData.isEmpty() ) { - mError = tr( "Invalid COPC file" ); + mError = QObject::tr( "Invalid COPC file" ); return false; } mCopcInfoVlr.fill( copcInfoVlrData.data(), copcInfoVlrData.size() ); @@ -127,17 +128,10 @@ bool QgsCopcPointCloudIndex::loadSchema( QgsLazInfo &lazInfo ) const double ymax = mCopcInfoVlr.center_y + mCopcInfoVlr.halfsize; const double zmax = mCopcInfoVlr.center_z + mCopcInfoVlr.halfsize; - mRootBounds = QgsPointCloudDataBounds( - ( xmin - mOffset.x() ) / mScale.x(), - ( ymin - mOffset.y() ) / mScale.y(), - ( zmin - mOffset.z() ) / mScale.z(), - ( xmax - mOffset.x() ) / mScale.x(), - ( ymax - mOffset.y() ) / mScale.y(), - ( zmax - mOffset.z() ) / mScale.z() - ); + mRootBounds = QgsBox3D( xmin, ymin, zmin, xmax, ymax, zmax ); - double calculatedSpan = nodeMapExtent( root() ).width() / mCopcInfoVlr.spacing; - mSpan = calculatedSpan; + // TODO: Rounding? + mSpan = mRootBounds.width() / mCopcInfoVlr.spacing; #ifdef QGIS_DEBUG double dx = xmax - xmin, dy = ymax - ymin, dz = zmax - zmin; @@ -150,7 +144,7 @@ bool QgsCopcPointCloudIndex::loadSchema( QgsLazInfo &lazInfo ) return true; } -std::unique_ptr QgsCopcPointCloudIndex::nodeData( const IndexedPointCloudNode &n, const QgsPointCloudRequest &request ) +std::unique_ptr QgsCopcPointCloudIndex::nodeData( const QgsPointCloudNodeId &n, const QgsPointCloudRequest &request ) { if ( QgsPointCloudBlock *cached = getNodeDataFromCache( n, request ) ) { @@ -196,7 +190,7 @@ std::unique_ptr QgsCopcPointCloudIndex::nodeData( const Inde return nullptr; QEventLoop loop; - connect( blockRequest.get(), &QgsPointCloudBlockRequest::finished, &loop, &QEventLoop::quit ); + QObject::connect( blockRequest.get(), &QgsPointCloudBlockRequest::finished, &loop, &QEventLoop::quit ); loop.exec(); block = blockRequest->takeBlock(); @@ -209,7 +203,7 @@ std::unique_ptr QgsCopcPointCloudIndex::nodeData( const Inde return block; } -QgsPointCloudBlockRequest *QgsCopcPointCloudIndex::asyncNodeData( const IndexedPointCloudNode &n, const QgsPointCloudRequest &request ) +QgsPointCloudBlockRequest *QgsCopcPointCloudIndex::asyncNodeData( const QgsPointCloudNodeId &n, const QgsPointCloudRequest &request ) { if ( mAccessType == Local ) return nullptr; // TODO @@ -257,21 +251,21 @@ bool QgsCopcPointCloudIndex::writeStatistics( QgsPointCloudStatistics &stats ) { if ( mAccessType == Remote ) { - QgsMessageLog::logMessage( tr( "Can't write statistics to remote file \"%1\"" ).arg( mUri ) ); + QgsMessageLog::logMessage( QObject::tr( "Can't write statistics to remote file \"%1\"" ).arg( mUri ) ); return false; } if ( mLazInfo->version() != qMakePair( 1, 4 ) ) { // EVLR isn't supported in the first place - QgsMessageLog::logMessage( tr( "Can't write statistics to \"%1\": laz version != 1.4" ).arg( mUri ) ); + QgsMessageLog::logMessage( QObject::tr( "Can't write statistics to \"%1\": laz version != 1.4" ).arg( mUri ) ); return false; } QByteArray statisticsEvlrData = fetchCopcStatisticsEvlrData(); if ( !statisticsEvlrData.isEmpty() ) { - QgsMessageLog::logMessage( tr( "Can't write statistics to \"%1\": file already contains COPC statistics!" ).arg( mUri ) ); + QgsMessageLog::logMessage( QObject::tr( "Can't write statistics to \"%1\": file already contains COPC statistics!" ).arg( mUri ) ); return false; } @@ -302,7 +296,7 @@ bool QgsCopcPointCloudIndex::writeStatistics( QgsPointCloudStatistics &stats ) } else { - QgsMessageLog::logMessage( tr( "Couldn't open COPC file \"%1\" to write statistics" ).arg( mUri ) ); + QgsMessageLog::logMessage( QObject::tr( "Couldn't open COPC file \"%1\" to write statistics" ).arg( mUri ) ); return false; } copcFile.close(); @@ -329,19 +323,19 @@ bool QgsCopcPointCloudIndex::isValid() const return mIsValid; } -bool QgsCopcPointCloudIndex::fetchNodeHierarchy( const IndexedPointCloudNode &n ) const +bool QgsCopcPointCloudIndex::fetchNodeHierarchy( const QgsPointCloudNodeId &n ) const { QMutexLocker locker( &mHierarchyMutex ); - QVector ancestors; - IndexedPointCloudNode foundRoot = n; + QVector ancestors; + QgsPointCloudNodeId foundRoot = n; while ( !mHierarchy.contains( foundRoot ) ) { ancestors.push_front( foundRoot ); foundRoot = foundRoot.parentNode(); } ancestors.push_front( foundRoot ); - for ( IndexedPointCloudNode n : ancestors ) + for ( QgsPointCloudNodeId n : ancestors ) { auto hierarchyIt = mHierarchy.constFind( n ); if ( hierarchyIt == mHierarchy.constEnd() ) @@ -385,7 +379,7 @@ void QgsCopcPointCloudIndex::fetchHierarchyPage( uint64_t offset, uint64_t byteS std::unique_ptr reply( QgsApplication::tileDownloadManager()->get( nr ) ); QEventLoop loop; - connect( reply.get(), &QgsTileDownloadManagerReply::finished, &loop, &QEventLoop::quit ); + QObject::connect( reply.get(), &QgsTileDownloadManagerReply::finished, &loop, &QEventLoop::quit ); loop.exec(); if ( reply->error() != QNetworkReply::NoError ) @@ -425,41 +419,48 @@ void QgsCopcPointCloudIndex::populateHierarchy( const char *hierarchyPageData, u for ( uint64_t i = 0; i < byteSize; i += sizeof( CopcEntry ) ) { const CopcEntry *entry = reinterpret_cast( hierarchyPageData + i ); - const IndexedPointCloudNode nodeId( entry->key.level, entry->key.x, entry->key.y, entry->key.z ); + const QgsPointCloudNodeId nodeId( entry->key.level, entry->key.x, entry->key.y, entry->key.z ); mHierarchy[nodeId] = entry->pointCount; mHierarchyNodePos.insert( nodeId, QPair( entry->offset, entry->byteSize ) ); } } -bool QgsCopcPointCloudIndex::hasNode( const IndexedPointCloudNode &n ) const +bool QgsCopcPointCloudIndex::hasNode( const QgsPointCloudNodeId &n ) const { return fetchNodeHierarchy( n ); } -QList QgsCopcPointCloudIndex::nodeChildren( const IndexedPointCloudNode &n ) const +QgsPointCloudNode QgsCopcPointCloudIndex::getNode( const QgsPointCloudNodeId &id ) const { - fetchNodeHierarchy( n ); + fetchNodeHierarchy( id ); - mHierarchyMutex.lock(); + qint64 pointCount; - auto hierarchyIt = mHierarchy.constFind( n ); - Q_ASSERT( hierarchyIt != mHierarchy.constEnd() ); - QList lst; - lst.reserve( 8 ); - const int d = n.d() + 1; - const int x = n.x() * 2; - const int y = n.y() * 2; - const int z = n.z() * 2; - mHierarchyMutex.unlock(); - - for ( int i = 0; i < 8; ++i ) + QList children; { - int dx = i & 1, dy = !!( i & 2 ), dz = !!( i & 4 ); - const IndexedPointCloudNode n2( d, x + dx, y + dy, z + dz ); - if ( fetchNodeHierarchy( n2 ) && mHierarchy[n] >= 0 ) - lst.append( n2 ); + QMutexLocker locker( &mHierarchyMutex ); + + pointCount = mHierarchy.value( id, -1 ); + + auto hierarchyIt = mHierarchy.constFind( id ); + Q_ASSERT( hierarchyIt != mHierarchy.constEnd() ); + children.reserve( 8 ); + const int d = id.d() + 1; + const int x = id.x() * 2; + const int y = id.y() * 2; + const int z = id.z() * 2; + mHierarchyMutex.unlock(); + + for ( int i = 0; i < 8; ++i ) + { + int dx = i & 1, dy = !!( i & 2 ), dz = !!( i & 4 ); + const QgsPointCloudNodeId n2( d, x + dx, y + dy, z + dz ); + if ( fetchNodeHierarchy( n2 ) && mHierarchy[id] >= 0 ) + children.append( n2 ); + } } - return lst; + + return QgsPointCloudNode( *this, id, pointCount, children ); } void QgsCopcPointCloudIndex::copyCommonProperties( QgsCopcPointCloudIndex *destination ) const diff --git a/src/core/pointcloud/qgscopcpointcloudindex.h b/src/core/pointcloud/qgscopcpointcloudindex.h index 32e0f52fab502..b54bf474f61f2 100644 --- a/src/core/pointcloud/qgscopcpointcloudindex.h +++ b/src/core/pointcloud/qgscopcpointcloudindex.h @@ -42,7 +42,6 @@ class QgsCoordinateReferenceSystem; class CORE_EXPORT QgsCopcPointCloudIndex: public QgsPointCloudIndex { - Q_OBJECT public: explicit QgsCopcPointCloudIndex(); @@ -52,11 +51,11 @@ class CORE_EXPORT QgsCopcPointCloudIndex: public QgsPointCloudIndex void load( const QString &fileName ) override; - bool hasNode( const IndexedPointCloudNode &n ) const override; - QList nodeChildren( const IndexedPointCloudNode &n ) const override; + bool hasNode( const QgsPointCloudNodeId &n ) const override; + virtual QgsPointCloudNode getNode( const QgsPointCloudNodeId &id ) const override; - std::unique_ptr< QgsPointCloudBlock> nodeData( const IndexedPointCloudNode &n, const QgsPointCloudRequest &request ) override; - QgsPointCloudBlockRequest *asyncNodeData( const IndexedPointCloudNode &n, const QgsPointCloudRequest &request ) override; + std::unique_ptr< QgsPointCloudBlock> nodeData( const QgsPointCloudNodeId &n, const QgsPointCloudRequest &request ) override; + QgsPointCloudBlockRequest *asyncNodeData( const QgsPointCloudNodeId &n, const QgsPointCloudRequest &request ) override; QgsCoordinateReferenceSystem crs() const override; qint64 pointCount() const override; @@ -97,7 +96,7 @@ class CORE_EXPORT QgsCopcPointCloudIndex: public QgsPointCloudIndex bool loadHierarchy(); //! Fetches all nodes leading to node \a node into memory - bool fetchNodeHierarchy( const IndexedPointCloudNode &n ) const; + bool fetchNodeHierarchy( const QgsPointCloudNodeId &n ) const; /** * Fetches the COPC hierarchy page at offset \a offset and of size \a byteSize into memory @@ -112,7 +111,7 @@ class CORE_EXPORT QgsCopcPointCloudIndex: public QgsPointCloudIndex QgsPointCloudIndex::AccessType mAccessType = Local; mutable std::ifstream mCopcFile; mutable lazperf::copc_info_vlr mCopcInfoVlr; - mutable QHash> mHierarchyNodePos; //!< Additional data hierarchy for COPC + mutable QHash> mHierarchyNodePos; //!< Additional data hierarchy for COPC QVariantMap mOriginalMetadata; mutable std::optional mStatistics; diff --git a/src/core/pointcloud/qgseptpointcloudblockrequest.cpp b/src/core/pointcloud/qgseptpointcloudblockrequest.cpp index 6cb0d62631658..18029e72e7b0e 100644 --- a/src/core/pointcloud/qgseptpointcloudblockrequest.cpp +++ b/src/core/pointcloud/qgseptpointcloudblockrequest.cpp @@ -31,7 +31,7 @@ ///@cond PRIVATE -QgsEptPointCloudBlockRequest::QgsEptPointCloudBlockRequest( const IndexedPointCloudNode &node, const QString &uri, const QString &dataType, +QgsEptPointCloudBlockRequest::QgsEptPointCloudBlockRequest( const QgsPointCloudNodeId &node, const QString &uri, const QString &dataType, const QgsPointCloudAttributeCollection &attributes, const QgsPointCloudAttributeCollection &requestedAttributes, const QgsVector3D &scale, const QgsVector3D &offset, const QgsPointCloudExpression &filterExpression, const QgsRectangle &filterRect ) : QgsPointCloudBlockRequest( node, uri, attributes, requestedAttributes, scale, offset, filterExpression, filterRect ), diff --git a/src/core/pointcloud/qgseptpointcloudblockrequest.h b/src/core/pointcloud/qgseptpointcloudblockrequest.h index 38321ab854340..64afbfc1a3b65 100644 --- a/src/core/pointcloud/qgseptpointcloudblockrequest.h +++ b/src/core/pointcloud/qgseptpointcloudblockrequest.h @@ -45,7 +45,7 @@ class CORE_EXPORT QgsEptPointCloudBlockRequest : public QgsPointCloudBlockReques * Requests the block data of size \a blockSize at offset blockOffset * Note: It is the responsablitiy of the caller to delete the block if it was loaded correctly */ - QgsEptPointCloudBlockRequest( const IndexedPointCloudNode &node, const QString &Uri, const QString &dataType, + QgsEptPointCloudBlockRequest( const QgsPointCloudNodeId &node, const QString &Uri, const QString &dataType, const QgsPointCloudAttributeCollection &attributes, const QgsPointCloudAttributeCollection &requestedAttributes, const QgsVector3D &scale, const QgsVector3D &offset, const QgsPointCloudExpression &filterExpression, const QgsRectangle &filterRect ); diff --git a/src/core/pointcloud/qgseptpointcloudindex.cpp b/src/core/pointcloud/qgseptpointcloudindex.cpp index 27da4cbf57351..4542279cf7b93 100644 --- a/src/core/pointcloud/qgseptpointcloudindex.cpp +++ b/src/core/pointcloud/qgseptpointcloudindex.cpp @@ -50,7 +50,7 @@ QgsEptPointCloudIndex::QgsEptPointCloudIndex() { - mHierarchyNodes.insert( IndexedPointCloudNode( 0, 0, 0, 0 ) ); + mHierarchyNodes.insert( QgsPointCloudNodeId( 0, 0, 0, 0 ) ); } QgsEptPointCloudIndex::~QgsEptPointCloudIndex() = default; @@ -98,7 +98,7 @@ void QgsEptPointCloudIndex::load( const QString &urlString ) QFile f( mUri ); if ( !f.open( QIODevice::ReadOnly ) ) { - mError = tr( "Unable to open %1 for reading" ).arg( mUri ); + mError = QObject::tr( "Unable to open %1 for reading" ).arg( mUri ); mIsValid = false; return; } @@ -132,7 +132,7 @@ void QgsEptPointCloudIndex::load( const QString &urlString ) loadManifest( manifestJson ); } - if ( !loadNodeHierarchy( IndexedPointCloudNode( 0, 0, 0, 0 ) ) ) + if ( !loadNodeHierarchy( QgsPointCloudNodeId( 0, 0, 0, 0 ) ) ) { QgsDebugError( QStringLiteral( "Failed to load root EPT node" ) ); success = false; @@ -356,15 +356,7 @@ bool QgsEptPointCloudIndex::loadSchema( const QByteArray &dataJson ) const double ymax = bounds[4].toDouble(); const double zmax = bounds[5].toDouble(); - mRootBounds = QgsPointCloudDataBounds( - ( xmin - mOffset.x() ) / mScale.x(), - ( ymin - mOffset.y() ) / mScale.y(), - ( zmin - mOffset.z() ) / mScale.z(), - ( xmax - mOffset.x() ) / mScale.x(), - ( ymax - mOffset.y() ) / mScale.y(), - ( zmax - mOffset.z() ) / mScale.z() - ); - + mRootBounds = QgsBox3D( xmin, ymin, zmin, xmax, ymax, zmax ); #ifdef QGIS_DEBUG double dx = xmax - xmin, dy = ymax - ymin, dz = zmax - zmin; @@ -377,7 +369,7 @@ bool QgsEptPointCloudIndex::loadSchema( const QByteArray &dataJson ) return true; } -std::unique_ptr QgsEptPointCloudIndex::nodeData( const IndexedPointCloudNode &n, const QgsPointCloudRequest &request ) +std::unique_ptr QgsEptPointCloudIndex::nodeData( const QgsPointCloudNodeId &n, const QgsPointCloudRequest &request ) { if ( QgsPointCloudBlock *cached = getNodeDataFromCache( n, request ) ) { @@ -392,7 +384,7 @@ std::unique_ptr QgsEptPointCloudIndex::nodeData( const Index return nullptr; QEventLoop loop; - connect( blockRequest.get(), &QgsPointCloudBlockRequest::finished, &loop, &QEventLoop::quit ); + QObject::connect( blockRequest.get(), &QgsPointCloudBlockRequest::finished, &loop, &QEventLoop::quit ); loop.exec(); block = blockRequest->takeBlock(); @@ -432,7 +424,7 @@ std::unique_ptr QgsEptPointCloudIndex::nodeData( const Index return block; } -QgsPointCloudBlockRequest *QgsEptPointCloudIndex::asyncNodeData( const IndexedPointCloudNode &n, const QgsPointCloudRequest &request ) +QgsPointCloudBlockRequest *QgsEptPointCloudIndex::asyncNodeData( const QgsPointCloudNodeId &n, const QgsPointCloudRequest &request ) { if ( QgsPointCloudBlock *cached = getNodeDataFromCache( n, request ) ) { @@ -473,7 +465,7 @@ QgsPointCloudBlockRequest *QgsEptPointCloudIndex::asyncNodeData( const IndexedPo return new QgsEptPointCloudBlockRequest( n, fileUrl, mDataType, attributes(), requestAttributes, scale(), offset(), filterExpression, request.filterRect() ); } -bool QgsEptPointCloudIndex::hasNode( const IndexedPointCloudNode &n ) const +bool QgsEptPointCloudIndex::hasNode( const QgsPointCloudNodeId &n ) const { return loadNodeHierarchy( n ); } @@ -488,30 +480,29 @@ qint64 QgsEptPointCloudIndex::pointCount() const return mPointCount; } -qint64 QgsEptPointCloudIndex::nodePointCount( const IndexedPointCloudNode &nodeId ) const +QgsPointCloudNode QgsEptPointCloudIndex::getNode( const QgsPointCloudNodeId &id ) const { - // First try loading our cached value - { - QMutexLocker locker( &mHierarchyMutex ); - qint64 pointCount = mHierarchy.value( nodeId, -1 ); - if ( pointCount != -1 ) - return pointCount; - } + QgsPointCloudNode node = QgsPointCloudIndex::getNode( id ); + + // First try cached value + if ( node.pointCount() != -1 ) + return node; // Try loading all nodes' hierarchy files on the path from root and stop when // one contains the point count for nodeId - QVector pathToRoot = nodePathToRoot( nodeId ); + QVector pathToRoot = nodePathToRoot( id ); for ( int i = pathToRoot.size() - 1; i >= 0; --i ) { loadSingleNodeHierarchy( pathToRoot[i] ); QMutexLocker locker( &mHierarchyMutex ); - qint64 pointCount = mHierarchy.value( nodeId, -1 ); + qint64 pointCount = mHierarchy.value( id, -1 ); if ( pointCount != -1 ) - return pointCount; + return QgsPointCloudNode( *this, id, pointCount, node.children() ); } - return -1; + // If we fail, return with pointCount = -1 anyway + return node; } QgsPointCloudStatistics QgsEptPointCloudIndex::metadataStatistics() const @@ -537,7 +528,7 @@ QgsPointCloudStatistics QgsEptPointCloudIndex::metadataStatistics() const return QgsPointCloudStatistics( pointCount(), statsMap ); } -bool QgsEptPointCloudIndex::loadSingleNodeHierarchy( const IndexedPointCloudNode &nodeId ) const +bool QgsEptPointCloudIndex::loadSingleNodeHierarchy( const QgsPointCloudNodeId &nodeId ) const { mHierarchyMutex.lock(); const bool foundInHierarchy = mHierarchy.contains( nodeId ); @@ -563,7 +554,7 @@ bool QgsEptPointCloudIndex::loadSingleNodeHierarchy( const IndexedPointCloudNode std::unique_ptr reply( QgsApplication::tileDownloadManager()->get( nr ) ); QEventLoop loop; - connect( reply.get(), &QgsTileDownloadManagerReply::finished, &loop, &QEventLoop::quit ); + QObject::connect( reply.get(), &QgsTileDownloadManagerReply::finished, &loop, &QEventLoop::quit ); loop.exec(); if ( reply->error() != QNetworkReply::NoError ) @@ -599,7 +590,7 @@ bool QgsEptPointCloudIndex::loadSingleNodeHierarchy( const IndexedPointCloudNode { const QString nodeIdStr = it.key(); const int nodePointCount = it.value().toInt(); - const IndexedPointCloudNode nodeId = IndexedPointCloudNode::fromString( nodeIdStr ); + const QgsPointCloudNodeId nodeId = QgsPointCloudNodeId::fromString( nodeIdStr ); if ( nodePointCount >= 0 ) mHierarchy[nodeId] = nodePointCount; else if ( nodePointCount == -1 ) @@ -609,10 +600,10 @@ bool QgsEptPointCloudIndex::loadSingleNodeHierarchy( const IndexedPointCloudNode return true; } -QVector QgsEptPointCloudIndex::nodePathToRoot( const IndexedPointCloudNode &nodeId ) const +QVector QgsEptPointCloudIndex::nodePathToRoot( const QgsPointCloudNodeId &nodeId ) const { - QVector path; - IndexedPointCloudNode currentNode = nodeId; + QVector path; + QgsPointCloudNodeId currentNode = nodeId; do { path.push_back( currentNode ); @@ -623,25 +614,28 @@ QVector QgsEptPointCloudIndex::nodePathToRoot( const Inde return path; } -bool QgsEptPointCloudIndex::loadNodeHierarchy( const IndexedPointCloudNode &nodeId ) const +bool QgsEptPointCloudIndex::loadNodeHierarchy( const QgsPointCloudNodeId &nodeId ) const { - mHierarchyMutex.lock(); - bool found = mHierarchy.contains( nodeId ); - mHierarchyMutex.unlock(); + bool found; + { + QMutexLocker lock( &mHierarchyMutex ); + found = mHierarchy.contains( nodeId ); + } if ( found ) return true; - QVector pathToRoot = nodePathToRoot( nodeId ); + QVector pathToRoot = nodePathToRoot( nodeId ); for ( int i = pathToRoot.size() - 1; i >= 0 && !mHierarchy.contains( nodeId ); --i ) { - const IndexedPointCloudNode node = pathToRoot[i]; + const QgsPointCloudNodeId node = pathToRoot[i]; if ( !loadSingleNodeHierarchy( node ) ) return false; } - mHierarchyMutex.lock(); - found = mHierarchy.contains( nodeId ); - mHierarchyMutex.unlock(); + { + QMutexLocker lock( &mHierarchyMutex ); + found = mHierarchy.contains( nodeId ); + } return found; } diff --git a/src/core/pointcloud/qgseptpointcloudindex.h b/src/core/pointcloud/qgseptpointcloudindex.h index 097894b6caab6..382e269cb843f 100644 --- a/src/core/pointcloud/qgseptpointcloudindex.h +++ b/src/core/pointcloud/qgseptpointcloudindex.h @@ -28,6 +28,7 @@ #include "qgspointcloudindex.h" #include "qgis_sip.h" +#include "qgsvector3d.h" ///@cond PRIVATE #define SIP_NO_FILE @@ -36,7 +37,6 @@ class QgsCoordinateReferenceSystem; class CORE_EXPORT QgsEptPointCloudIndex: public QgsPointCloudIndex { - Q_OBJECT public: explicit QgsEptPointCloudIndex(); @@ -46,13 +46,13 @@ class CORE_EXPORT QgsEptPointCloudIndex: public QgsPointCloudIndex void load( const QString &fileName ) override; - std::unique_ptr nodeData( const IndexedPointCloudNode &n, const QgsPointCloudRequest &request ) override; - QgsPointCloudBlockRequest *asyncNodeData( const IndexedPointCloudNode &n, const QgsPointCloudRequest &request ) override; - bool hasNode( const IndexedPointCloudNode &n ) const override; + std::unique_ptr nodeData( const QgsPointCloudNodeId &n, const QgsPointCloudRequest &request ) override; + QgsPointCloudBlockRequest *asyncNodeData( const QgsPointCloudNodeId &n, const QgsPointCloudRequest &request ) override; + bool hasNode( const QgsPointCloudNodeId &n ) const override; QgsCoordinateReferenceSystem crs() const override; qint64 pointCount() const override; - virtual qint64 nodePointCount( const IndexedPointCloudNode &n ) const override; + virtual QgsPointCloudNode getNode( const QgsPointCloudNodeId &id ) const override; QVariantMap originalMetadata() const override { return mOriginalMetadata; } virtual QgsPointCloudStatistics metadataStatistics() const override; @@ -69,9 +69,9 @@ class CORE_EXPORT QgsEptPointCloudIndex: public QgsPointCloudIndex bool loadSchema( const QByteArray &dataJson ); void loadManifest( const QByteArray &manifestJson ); bool loadSchema( QFile &f ); - bool loadSingleNodeHierarchy( const IndexedPointCloudNode &nodeId ) const; - QVector nodePathToRoot( const IndexedPointCloudNode &nodeId ) const; - bool loadNodeHierarchy( const IndexedPointCloudNode &nodeId ) const; + bool loadSingleNodeHierarchy( const QgsPointCloudNodeId &nodeId ) const; + QVector nodePathToRoot( const QgsPointCloudNodeId &nodeId ) const; + bool loadNodeHierarchy( const QgsPointCloudNodeId &nodeId ) const; bool mIsValid = false; QgsPointCloudIndex::AccessType mAccessType = Local; @@ -81,7 +81,7 @@ class CORE_EXPORT QgsEptPointCloudIndex: public QgsPointCloudIndex QString mUrlDirectoryPart; //! Contains the nodes that will have */ept-hierarchy/d-x-y-z.json file - mutable QSet mHierarchyNodes; + mutable QSet mHierarchyNodes; qint64 mPointCount = 0; diff --git a/src/core/pointcloud/qgspointcloudblockrequest.cpp b/src/core/pointcloud/qgspointcloudblockrequest.cpp index 9cb8a3b0185ca..c898ecff6490e 100644 --- a/src/core/pointcloud/qgspointcloudblockrequest.cpp +++ b/src/core/pointcloud/qgspointcloudblockrequest.cpp @@ -24,7 +24,7 @@ ///@cond PRIVATE -QgsPointCloudBlockRequest::QgsPointCloudBlockRequest( const IndexedPointCloudNode &node, const QString &uri, +QgsPointCloudBlockRequest::QgsPointCloudBlockRequest( const QgsPointCloudNodeId &node, const QString &uri, const QgsPointCloudAttributeCollection &attributes, const QgsPointCloudAttributeCollection &requestedAttributes, const QgsVector3D &scale, const QgsVector3D &offset, const QgsPointCloudExpression &filterExpression, const QgsRectangle &filterRect ) : mNode( node ) diff --git a/src/core/pointcloud/qgspointcloudblockrequest.h b/src/core/pointcloud/qgspointcloudblockrequest.h index ce6e438e360b9..1e0ebb555d3bd 100644 --- a/src/core/pointcloud/qgspointcloudblockrequest.h +++ b/src/core/pointcloud/qgspointcloudblockrequest.h @@ -42,7 +42,7 @@ class CORE_EXPORT QgsPointCloudBlockRequest : public QObject * QgsPointCloudBlockRequest constructor * Note: It is the responsablitiy of the caller to delete the block if it was loaded correctly */ - QgsPointCloudBlockRequest( const IndexedPointCloudNode &node, const QString &Uri, + QgsPointCloudBlockRequest( const QgsPointCloudNodeId &node, const QString &Uri, const QgsPointCloudAttributeCollection &attributes, const QgsPointCloudAttributeCollection &requestedAttributes, const QgsVector3D &scale, const QgsVector3D &offset, const QgsPointCloudExpression &filterExpression, const QgsRectangle &filterRect ); @@ -62,7 +62,7 @@ class CORE_EXPORT QgsPointCloudBlockRequest : public QObject void finished(); protected: - IndexedPointCloudNode mNode; + QgsPointCloudNodeId mNode; QString mUri; QgsPointCloudAttributeCollection mAttributes; QgsPointCloudAttributeCollection mRequestedAttributes; diff --git a/src/core/pointcloud/qgspointclouddataprovider.cpp b/src/core/pointcloud/qgspointclouddataprovider.cpp index f4ed0d6b27625..916c7f0d80c0c 100644 --- a/src/core/pointcloud/qgspointclouddataprovider.cpp +++ b/src/core/pointcloud/qgspointclouddataprovider.cpp @@ -221,7 +221,7 @@ struct MapIndexedPointCloudNode : mRequest( request ), mIndexScale( indexScale ), mIndexOffset( indexOffset ), mExtentGeometry( extentGeometry ), mZRange( zRange ), mIndex( index ), mPointsLimit( pointsLimit ) { } - QVector operator()( IndexedPointCloudNode n ) + QVector operator()( QgsPointCloudNodeId n ) { QVector acceptedPoints; std::unique_ptr block( mIndex->nodeData( n, mRequest ) ); @@ -325,12 +325,8 @@ QVector QgsPointCloudDataProvider::identify( if ( !index || !index->isValid() ) return acceptedPoints; - const IndexedPointCloudNode root = index->root(); - - const QgsRectangle rootNodeExtent = index->nodeMapExtent( root ); - const double rootError = rootNodeExtent.width() / index->span(); - - const QVector nodes = traverseTree( index, root, maxError, rootError, extentGeometry, extentZRange ); + const QgsPointCloudNode root = index->getNode( index->root() ); + const QVector nodes = traverseTree( index, root, maxError, root.error(), extentGeometry, extentZRange ); const QgsPointCloudAttributeCollection attributeCollection = index->attributes(); QgsPointCloudRequest request; @@ -344,9 +340,9 @@ QVector QgsPointCloudDataProvider::identify( return acceptedPoints; } -QVector QgsPointCloudDataProvider::traverseTree( +QVector QgsPointCloudDataProvider::traverseTree( const QgsPointCloudIndex *pc, - IndexedPointCloudNode n, + QgsPointCloudNode node, double maxError, double nodeError, const QgsGeometry &extentGeometry, @@ -354,26 +350,27 @@ QVector QgsPointCloudDataProvider::traverseTree( { QGIS_PROTECT_QOBJECT_THREAD_ACCESS - QVector nodes; + QVector nodes; - const QgsDoubleRange nodeZRange = pc->nodeZRange( n ); + const QgsBox3D nodeBounds = node.bounds(); + const QgsDoubleRange nodeZRange( nodeBounds.zMinimum(), nodeBounds.zMaximum() ); if ( !extentZRange.overlaps( nodeZRange ) ) return nodes; - if ( !extentGeometry.intersects( pc->nodeMapExtent( n ) ) ) + if ( !extentGeometry.intersects( nodeBounds.toRectangle() ) ) return nodes; - nodes.append( n ); + nodes.append( node.id() ); const double childrenError = nodeError / 2.0; if ( childrenError < maxError ) return nodes; - const QList children = pc->nodeChildren( n ); - for ( const IndexedPointCloudNode &nn : children ) + for ( const QgsPointCloudNodeId &nn : node.children() ) { - if ( extentGeometry.intersects( pc->nodeMapExtent( nn ) ) ) - nodes += traverseTree( pc, nn, maxError, childrenError, extentGeometry, extentZRange ); + const QgsPointCloudNode childNode = pc->getNode( nn ); + if ( extentGeometry.intersects( childNode.bounds().toRectangle() ) ) + nodes += traverseTree( pc, childNode, maxError, childrenError, extentGeometry, extentZRange ); } return nodes; diff --git a/src/core/pointcloud/qgspointclouddataprovider.h b/src/core/pointcloud/qgspointclouddataprovider.h index 58a7507303501..0df928b8267b8 100644 --- a/src/core/pointcloud/qgspointclouddataprovider.h +++ b/src/core/pointcloud/qgspointclouddataprovider.h @@ -24,8 +24,6 @@ #include "qgspointcloudindex.h" #include "qgspointcloudsubindex.h" -class IndexedPointCloudNode; -class QgsPointCloudIndex; class QgsPointCloudRenderer; class QgsGeometry; class QgsPointCloudStatistics; @@ -284,7 +282,7 @@ class CORE_EXPORT QgsPointCloudDataProvider: public QgsDataProvider QVector identify( QgsPointCloudIndex *index, double maxError, const QgsGeometry &extentGeometry, const QgsDoubleRange &extentZRange, int pointsLimit ) SIP_SKIP ; private: - QVector traverseTree( const QgsPointCloudIndex *pc, IndexedPointCloudNode n, 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 e4e72833277f4..58e2916bbfc2f 100644 --- a/src/core/pointcloud/qgspointcloudindex.cpp +++ b/src/core/pointcloud/qgspointcloudindex.cpp @@ -25,64 +25,66 @@ #include #include #include +#include +#include "qgsbox3d.h" #include "qgstiledownloadmanager.h" #include "qgspointcloudstatistics.h" #include "qgslogger.h" -IndexedPointCloudNode::IndexedPointCloudNode(): +QgsPointCloudNodeId::QgsPointCloudNodeId(): mD( -1 ), mX( 0 ), mY( 0 ), mZ( 0 ) {} -IndexedPointCloudNode::IndexedPointCloudNode( int _d, int _x, int _y, int _z ): +QgsPointCloudNodeId::QgsPointCloudNodeId( int _d, int _x, int _y, int _z ): mD( _d ), mX( _x ), mY( _y ), mZ( _z ) {} -IndexedPointCloudNode IndexedPointCloudNode::parentNode() const +QgsPointCloudNodeId QgsPointCloudNodeId::parentNode() const { - return IndexedPointCloudNode( mD - 1, mX / 2, mY / 2, mZ / 2 ); + return QgsPointCloudNodeId( mD - 1, mX / 2, mY / 2, mZ / 2 ); } -IndexedPointCloudNode IndexedPointCloudNode::fromString( const QString &str ) +QgsPointCloudNodeId QgsPointCloudNodeId::fromString( const QString &str ) { QStringList lst = str.split( '-' ); if ( lst.count() != 4 ) - return IndexedPointCloudNode(); - return IndexedPointCloudNode( lst[0].toInt(), lst[1].toInt(), lst[2].toInt(), lst[3].toInt() ); + return QgsPointCloudNodeId(); + return QgsPointCloudNodeId( lst[0].toInt(), lst[1].toInt(), lst[2].toInt(), lst[3].toInt() ); } -QString IndexedPointCloudNode::toString() const +QString QgsPointCloudNodeId::toString() const { return QStringLiteral( "%1-%2-%3-%4" ).arg( mD ).arg( mX ).arg( mY ).arg( mZ ); } -int IndexedPointCloudNode::d() const +int QgsPointCloudNodeId::d() const { return mD; } -int IndexedPointCloudNode::x() const +int QgsPointCloudNodeId::x() const { return mX; } -int IndexedPointCloudNode::y() const +int QgsPointCloudNodeId::y() const { return mY; } -int IndexedPointCloudNode::z() const +int QgsPointCloudNodeId::z() const { return mZ; } -uint qHash( IndexedPointCloudNode id ) +uint qHash( QgsPointCloudNodeId id ) { return id.d() + id.x() + id.y() + id.z(); } @@ -93,7 +95,7 @@ uint qHash( IndexedPointCloudNode id ) // QgsPointCloudCacheKey // -QgsPointCloudCacheKey::QgsPointCloudCacheKey( const IndexedPointCloudNode &n, const QgsPointCloudRequest &request, const QgsPointCloudExpression &expression, const QString &uri ) +QgsPointCloudCacheKey::QgsPointCloudCacheKey( const QgsPointCloudNodeId &n, const QgsPointCloudRequest &request, const QgsPointCloudExpression &expression, const QString &uri ) : mNode( n ) , mUri( uri ) , mRequest( request ) @@ -115,63 +117,28 @@ uint qHash( const QgsPointCloudCacheKey &key ) } // -// QgsPointCloudDataBounds +// QgsPointCloudNode // -QgsPointCloudDataBounds::QgsPointCloudDataBounds() = default; - -QgsPointCloudDataBounds::QgsPointCloudDataBounds( qint64 xmin, qint64 ymin, qint64 zmin, qint64 xmax, qint64 ymax, qint64 zmax ) - : mXMin( xmin ) - , mYMin( ymin ) - , mZMin( zmin ) - , mXMax( xmax ) - , mYMax( ymax ) - , mZMax( zmax ) -{ - -} - -qint64 QgsPointCloudDataBounds::xMin() const -{ - return mXMin; -} - -qint64 QgsPointCloudDataBounds::yMin() const -{ - return mYMin; -} - -qint64 QgsPointCloudDataBounds::xMax() const +QgsBox3D QgsPointCloudNode::bounds() const { - return mXMax; -} + const QgsBox3D rootBounds = mIndex.rootNodeBounds(); + const double d = rootBounds.xMaximum() - rootBounds.xMinimum(); + const double dLevel = ( double )d / pow( 2, mId.d() ); -qint64 QgsPointCloudDataBounds::yMax() const -{ - return mYMax; -} + const double xMin = rootBounds.xMinimum() + dLevel * mId.x(); + const double xMax = rootBounds.xMinimum() + dLevel * ( mId.x() + 1 ); + const double yMin = rootBounds.yMinimum() + dLevel * mId.y(); + const double yMax = rootBounds.yMinimum() + dLevel * ( mId.y() + 1 ); + const double zMin = rootBounds.zMinimum() + dLevel * mId.z(); + const double zMax = rootBounds.zMinimum() + dLevel * ( mId.z() + 1 ); -qint64 QgsPointCloudDataBounds::zMin() const -{ - return mZMin; + return QgsBox3D( xMin, yMin, zMin, xMax, yMax, zMax ); } -qint64 QgsPointCloudDataBounds::zMax() const +float QgsPointCloudNode::error() const { - return mZMax; -} - -QgsRectangle QgsPointCloudDataBounds::mapExtent( const QgsVector3D &offset, const QgsVector3D &scale ) const -{ - return QgsRectangle( - mXMin * scale.x() + offset.x(), mYMin * scale.y() + offset.y(), - mXMax * scale.x() + offset.x(), mYMax * scale.y() + offset.y() - ); -} - -QgsDoubleRange QgsPointCloudDataBounds::zRange( const QgsVector3D &offset, const QgsVector3D &scale ) const -{ - return QgsDoubleRange( mZMin * scale.z() + offset.z(), mZMax * scale.z() + offset.z() ); + return bounds().width() / mIndex.span(); } ///@endcond @@ -187,74 +154,44 @@ QgsPointCloudIndex::QgsPointCloudIndex() = default; QgsPointCloudIndex::~QgsPointCloudIndex() = default; -bool QgsPointCloudIndex::hasNode( const IndexedPointCloudNode &n ) const +bool QgsPointCloudIndex::hasNode( const QgsPointCloudNodeId &n ) const { QMutexLocker locker( &mHierarchyMutex ); return mHierarchy.contains( n ); } -qint64 QgsPointCloudIndex::nodePointCount( const IndexedPointCloudNode &n ) const +QgsPointCloudNode QgsPointCloudIndex::getNode( const QgsPointCloudNodeId &id ) const { - QMutexLocker locker( &mHierarchyMutex ); - return mHierarchy.value( n, -1 ); -} + Q_ASSERT( hasNode( id ) ); -QList QgsPointCloudIndex::nodeChildren( const IndexedPointCloudNode &n ) const -{ - Q_ASSERT( hasNode( n ) ); - QList lst; - const int d = n.d() + 1; - const int x = n.x() * 2; - const int y = n.y() * 2; - const int z = n.z() * 2; - - for ( int i = 0; i < 8; ++i ) + qint64 pointCount; { - int dx = i & 1, dy = !!( i & 2 ), dz = !!( i & 4 ); - const IndexedPointCloudNode n2( d, x + dx, y + dy, z + dz ); - if ( hasNode( n2 ) ) - lst.append( n2 ); + QMutexLocker locker( &mHierarchyMutex ); + pointCount = mHierarchy.value( id, -1 ); } - return lst; -} - -QgsPointCloudAttributeCollection QgsPointCloudIndex::attributes() const -{ - return mAttributes; -} - -QgsPointCloudDataBounds QgsPointCloudIndex::nodeBounds( const IndexedPointCloudNode &n ) const -{ - qint64 xMin, yMin, zMin, xMax, yMax, zMax; - - const qint64 d = mRootBounds.xMax() - mRootBounds.xMin(); - const double dLevel = ( double )d / pow( 2, n.d() ); - xMin = round( mRootBounds.xMin() + dLevel * n.x() ); - xMax = round( mRootBounds.xMin() + dLevel * ( n.x() + 1 ) ); - yMin = round( mRootBounds.yMin() + dLevel * n.y() ); - yMax = round( mRootBounds.yMin() + dLevel * ( n.y() + 1 ) ); - zMin = round( mRootBounds.zMin() + dLevel * n.z() ); - zMax = round( mRootBounds.zMin() + dLevel * ( n.z() + 1 ) ); - - QgsPointCloudDataBounds db( xMin, yMin, zMin, xMax, yMax, zMax ); - return db; -} + QList children; + { + const int d = id.d() + 1; + const int x = id.x() * 2; + const int y = id.y() * 2; + const int z = id.z() * 2; -QgsRectangle QgsPointCloudIndex::nodeMapExtent( const IndexedPointCloudNode &node ) const -{ - return nodeBounds( node ).mapExtent( mOffset, mScale ); -} + for ( int i = 0; i < 8; ++i ) + { + int dx = i & 1, dy = !!( i & 2 ), dz = !!( i & 4 ); + const QgsPointCloudNodeId n2( d, x + dx, y + dy, z + dz ); + if ( hasNode( n2 ) ) + children.append( n2 ); + } + } -QgsDoubleRange QgsPointCloudIndex::nodeZRange( const IndexedPointCloudNode &node ) const -{ - return nodeBounds( node ).zRange( mOffset, mScale ); + return QgsPointCloudNode( *this, id, pointCount, children ); } -float QgsPointCloudIndex::nodeError( const IndexedPointCloudNode &n ) const +QgsPointCloudAttributeCollection QgsPointCloudIndex::attributes() const { - const double w = nodeMapExtent( n ).width(); - return w / mSpan; + return mAttributes; } QgsVector3D QgsPointCloudIndex::scale() const @@ -327,15 +264,13 @@ void QgsPointCloudIndex::copyCommonProperties( QgsPointCloudIndex *destination ) destination->mZMin = mZMin; destination->mZMax = mZMax; destination->mHierarchy = mHierarchy; - destination->mScale = mScale; - destination->mOffset = mOffset; destination->mRootBounds = mRootBounds; destination->mAttributes = mAttributes; destination->mSpan = mSpan; destination->mFilterExpression = mFilterExpression; } -QgsPointCloudBlock *QgsPointCloudIndex::getNodeDataFromCache( const IndexedPointCloudNode &node, const QgsPointCloudRequest &request ) +QgsPointCloudBlock *QgsPointCloudIndex::getNodeDataFromCache( const QgsPointCloudNodeId &node, const QgsPointCloudRequest &request ) { QgsPointCloudCacheKey key( node, request, mFilterExpression, mUri ); @@ -344,12 +279,12 @@ QgsPointCloudBlock *QgsPointCloudIndex::getNodeDataFromCache( const IndexedPoint return cached ? cached->clone() : nullptr; } -void QgsPointCloudIndex::storeNodeDataToCache( QgsPointCloudBlock *data, const IndexedPointCloudNode &node, const QgsPointCloudRequest &request ) +void QgsPointCloudIndex::storeNodeDataToCache( QgsPointCloudBlock *data, const QgsPointCloudNodeId &node, const QgsPointCloudRequest &request ) { storeNodeDataToCacheStatic( data, node, request, mFilterExpression, mUri ); } -void QgsPointCloudIndex::storeNodeDataToCacheStatic( QgsPointCloudBlock *data, const IndexedPointCloudNode &node, const QgsPointCloudRequest &request, const QgsPointCloudExpression &expression, const QString &uri ) +void QgsPointCloudIndex::storeNodeDataToCacheStatic( QgsPointCloudBlock *data, const QgsPointCloudNodeId &node, const QgsPointCloudRequest &request, const QgsPointCloudExpression &expression, const QString &uri ) { if ( !data ) return; diff --git a/src/core/pointcloud/qgspointcloudindex.h b/src/core/pointcloud/qgspointcloudindex.h index 4887795a3d8e1..858728d6fb308 100644 --- a/src/core/pointcloud/qgspointcloudindex.h +++ b/src/core/pointcloud/qgspointcloudindex.h @@ -30,10 +30,9 @@ #include "qgis_core.h" #include "qgspointcloudstatistics.h" #include "qgsrectangle.h" -#include "qgsvector3d.h" +#include "qgsbox3d.h" #include "qgis_sip.h" #include "qgspointcloudblock.h" -#include "qgsrange.h" #include "qgspointcloudattribute.h" #include "qgspointcloudexpression.h" #include "qgspointcloudrequest.h" @@ -51,26 +50,26 @@ class QgsPointCloudIndex; /** * \ingroup core * - * \brief Represents a indexed point cloud node in octree + * \brief Represents a indexed point cloud node's position in octree * * \note The API is considered EXPERIMENTAL and can be changed without a notice * * \since QGIS 3.18 */ -class CORE_EXPORT IndexedPointCloudNode +class CORE_EXPORT QgsPointCloudNodeId { public: //! Constructs invalid node - IndexedPointCloudNode(); + QgsPointCloudNodeId(); //! Constructs valid node - IndexedPointCloudNode( int _d, int _x, int _y, int _z ); + QgsPointCloudNodeId( int _d, int _x, int _y, int _z ); //! Returns whether node is valid bool isValid() const { return mD >= 0; } // TODO c++20 - replace with = default - bool operator==( IndexedPointCloudNode other ) const + bool operator==( QgsPointCloudNodeId other ) const { return mD == other.d() && mX == other.x() && mY == other.y() && mZ == other.z(); } @@ -79,10 +78,10 @@ class CORE_EXPORT IndexedPointCloudNode * Returns the parent of the node * \since QGIS 3.20 */ - IndexedPointCloudNode parentNode() const; + QgsPointCloudNodeId parentNode() const; //! Creates node from string - static IndexedPointCloudNode fromString( const QString &str ); + static QgsPointCloudNodeId fromString( const QString &str ); //! Encode node to string QString toString() const; @@ -103,10 +102,10 @@ class CORE_EXPORT IndexedPointCloudNode int mD = -1, mX = -1, mY = -1, mZ = -1; }; -Q_DECLARE_TYPEINFO( IndexedPointCloudNode, Q_PRIMITIVE_TYPE ); +Q_DECLARE_TYPEINFO( QgsPointCloudNodeId, Q_PRIMITIVE_TYPE ); //! Hash function for indexed nodes -CORE_EXPORT uint qHash( IndexedPointCloudNode id ); +CORE_EXPORT uint qHash( QgsPointCloudNodeId id ); /** * \ingroup core @@ -121,12 +120,12 @@ class CORE_EXPORT QgsPointCloudCacheKey { public: //! Ctor - QgsPointCloudCacheKey( const IndexedPointCloudNode &n, const QgsPointCloudRequest &request, const QgsPointCloudExpression &expression, const QString &uri ); + QgsPointCloudCacheKey( const QgsPointCloudNodeId &n, const QgsPointCloudRequest &request, const QgsPointCloudExpression &expression, const QString &uri ); bool operator==( const QgsPointCloudCacheKey &other ) const; - //! Returns the key's IndexedPointCloudNode - IndexedPointCloudNode node() const { return mNode; } + //! Returns the key's QgsPointCloudNodeId + QgsPointCloudNodeId node() const { return mNode; } //! Returns the key's uri QString uri() const { return mUri; } @@ -138,7 +137,7 @@ class CORE_EXPORT QgsPointCloudCacheKey QgsPointCloudExpression filterExpression() const { return mFilterExpression; } private: - IndexedPointCloudNode mNode; + QgsPointCloudNodeId mNode; QString mUri; QgsPointCloudRequest mRequest; QgsPointCloudExpression mFilterExpression; @@ -150,51 +149,33 @@ uint qHash( const QgsPointCloudCacheKey &key ); /** * \ingroup core * - * \brief Represents packaged data bounds + * \brief Keeps metadata for indexed point cloud node * * \note The API is considered EXPERIMENTAL and can be changed without a notice * - * \since QGIS 3.18 + * \since QGIS 3.42 */ -class CORE_EXPORT QgsPointCloudDataBounds +class CORE_EXPORT QgsPointCloudNode { public: - //! Constructs invalid bounds - QgsPointCloudDataBounds(); - //! Constructs bounds - QgsPointCloudDataBounds( qint64 xmin, qint64 ymin, qint64 zmin, qint64 xmax, qint64 ymax, qint64 zmax ); - - //! Returns x min - qint64 xMin() const; - - //! Returns y min - qint64 yMin() const; - - //! Returns z min - qint64 zMin() const; - - //! Returns x max - qint64 xMax() const; - - //! Returns y max - qint64 yMax() const; - - //! Returns z max - qint64 zMax() const; - - //! Returns 2D rectangle in map coordinates - QgsRectangle mapExtent( const QgsVector3D &offset, const QgsVector3D &scale ) const; - - //! Returns the z range, applying the specified \a offset and \a scale. - QgsDoubleRange zRange( const QgsVector3D &offset, const QgsVector3D &scale ) const; + QgsPointCloudNode( const QgsPointCloudIndex &index, QgsPointCloudNodeId id, qint64 pointCount, + QList childIds ) + : mIndex( index ), mId( id ), mPointCount( pointCount ), mChildIds( childIds ) + { + } + QgsPointCloudNodeId id() const { return mId; } + qint64 pointCount() const { return mPointCount; } + QList children() const { return mChildIds; } + //! Returns node's error in map units (used to determine in whether the node has enough detail for the current view) + float error() const; + QgsBox3D bounds() const; private: - qint64 mXMin = 0; - qint64 mYMin = 0; - qint64 mZMin = 0; - qint64 mXMax = 0; - qint64 mYMax = 0; - qint64 mZMax = 0; + const QgsPointCloudIndex &mIndex; + // Specific node metadata: + QgsPointCloudNodeId mId; + qint64 mPointCount; + QList mChildIds; }; /** @@ -206,9 +187,8 @@ class CORE_EXPORT QgsPointCloudDataBounds * * \since QGIS 3.18 */ -class CORE_EXPORT QgsPointCloudIndex: public QObject +class CORE_EXPORT QgsPointCloudIndex { - Q_OBJECT public: //! The access type of the data, local is for local files and remote for remote files (over HTTP) enum AccessType @@ -219,7 +199,7 @@ class CORE_EXPORT QgsPointCloudIndex: public QObject //! Constructs index explicit QgsPointCloudIndex(); - ~QgsPointCloudIndex(); + virtual ~QgsPointCloudIndex(); /** * Returns a clone of the current point cloud index object @@ -262,16 +242,12 @@ class CORE_EXPORT QgsPointCloudIndex: public QObject virtual QgsPointCloudStatistics metadataStatistics() const; //! Returns root node of the index - IndexedPointCloudNode root() { return IndexedPointCloudNode( 0, 0, 0, 0 ); } + QgsPointCloudNodeId root() { return QgsPointCloudNodeId( 0, 0, 0, 0 ); } //! Returns whether the octree contain given node - virtual bool hasNode( const IndexedPointCloudNode &n ) const; - - //! Returns the number of points of a given node \a n - virtual qint64 nodePointCount( const IndexedPointCloudNode &n ) const; + virtual bool hasNode( const QgsPointCloudNodeId &n ) const; - //! Returns all children of node - virtual QList nodeChildren( const IndexedPointCloudNode &n ) const; + virtual QgsPointCloudNode getNode( const QgsPointCloudNodeId &id ) const; //! Returns all attributes that are stored in the file QgsPointCloudAttributeCollection attributes() const; @@ -284,7 +260,7 @@ class CORE_EXPORT QgsPointCloudIndex: public QObject * * May return nullptr in case the node is not present or any other problem with loading */ - virtual std::unique_ptr< QgsPointCloudBlock > nodeData( const IndexedPointCloudNode &n, const QgsPointCloudRequest &request ) = 0; + virtual std::unique_ptr< QgsPointCloudBlock > nodeData( const QgsPointCloudNodeId &n, const QgsPointCloudRequest &request ) = 0; /** * Returns a handle responsible for loading a node data block @@ -296,7 +272,7 @@ class CORE_EXPORT QgsPointCloudIndex: public QObject * * May return nullptr in case the node is not present or any other problem with loading */ - virtual QgsPointCloudBlockRequest *asyncNodeData( const IndexedPointCloudNode &n, const QgsPointCloudRequest &request ) = 0; + virtual QgsPointCloudBlockRequest *asyncNodeData( const QgsPointCloudNodeId &n, const QgsPointCloudRequest &request ) = 0; //! Returns extent of the data QgsRectangle extent() const { return mExtent; } @@ -306,30 +282,13 @@ class CORE_EXPORT QgsPointCloudIndex: public QObject //! Returns z max double zMax() const { return mZMax; } - //! Returns bounds of particular \a node - QgsPointCloudDataBounds nodeBounds( const IndexedPointCloudNode &node ) const; - - /** - * Returns the extent of a \a node in map coordinates. - * - * \see nodeZRange() - */ - QgsRectangle nodeMapExtent( const IndexedPointCloudNode &node ) const; - - /** - * Returns the z range of a \a node. - * - * \see nodeMapExtent() - */ - QgsDoubleRange nodeZRange( const IndexedPointCloudNode &node ) const; - - //! Returns node's error in map units (used to determine in whether the node has enough detail for the current view) - float nodeError( const IndexedPointCloudNode &n ) const; + //! Returns bounding box of root node in CRS coords + QgsBox3D rootNodeBounds() const { return mRootBounds; } - //! Returns scale + //! Returns scale of data relative to CRS QgsVector3D scale() const; - //! Returns offset + //! Returns offset of data from CRS QgsVector3D offset() const; /** @@ -364,17 +323,17 @@ class CORE_EXPORT QgsPointCloudIndex: public QObject * If not found in the cache, nullptr is returned. * Caller takes ownership of the returned object. */ - QgsPointCloudBlock *getNodeDataFromCache( const IndexedPointCloudNode &node, const QgsPointCloudRequest &request ); + QgsPointCloudBlock *getNodeDataFromCache( const QgsPointCloudNodeId &node, const QgsPointCloudRequest &request ); /** * 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. */ - void storeNodeDataToCache( QgsPointCloudBlock *data, const IndexedPointCloudNode &node, const QgsPointCloudRequest &request ); + void storeNodeDataToCache( QgsPointCloudBlock *data, const QgsPointCloudNodeId &node, const QgsPointCloudRequest &request ); /** * Stores existing \a data to the cache for the specified \a node, \a request, \a expression and \a uri. Ownership is not transferred, block gets cloned in the cache. */ - static void storeNodeDataToCacheStatic( QgsPointCloudBlock *data, const IndexedPointCloudNode &node, const QgsPointCloudRequest &request, + static void storeNodeDataToCacheStatic( QgsPointCloudBlock *data, const QgsPointCloudNodeId &node, const QgsPointCloudRequest &request, const QgsPointCloudExpression &expression, const QString &uri ); protected: //TODO private @@ -385,10 +344,10 @@ class CORE_EXPORT QgsPointCloudIndex: public QObject double mZMin = 0, mZMax = 0; //!< Vertical extent of data mutable QMutex mHierarchyMutex; - mutable QHash mHierarchy; //!< Data hierarchy + mutable QHash mHierarchy; //!< Data hierarchy QgsVector3D mScale; //!< Scale of our int32 coordinates compared to CRS coords QgsVector3D mOffset; //!< Offset of our int32 coordinates compared to CRS coords - QgsPointCloudDataBounds mRootBounds; //!< Bounds of the root node's cube (in int32 coordinates) + QgsBox3D mRootBounds; //!< Bounds of the root node's cube (in int32 coordinates) QgsPointCloudAttributeCollection mAttributes; //! All native attributes stored in the file int mSpan = 0; //!< Number of points in one direction in a single node QgsPointCloudExpression mFilterExpression; //!< The filter expression to be evaluated when fetching node data diff --git a/src/core/pointcloud/qgspointcloudlayer.cpp b/src/core/pointcloud/qgspointcloudlayer.cpp index 9a807d0b80258..058006a834ec2 100644 --- a/src/core/pointcloud/qgspointcloudlayer.cpp +++ b/src/core/pointcloud/qgspointcloudlayer.cpp @@ -905,7 +905,7 @@ void QgsPointCloudLayer::calculateStatistics() #ifdef HAVE_COPC if ( mDataProvider && mDataProvider->index() && mDataProvider->index()->isValid() && mDataProvider->name() == QLatin1String( "pdal" ) && mStatistics.sampledPointsCount() != 0 ) { - if ( QgsCopcPointCloudIndex *index = qobject_cast( mDataProvider->index() ) ) + if ( QgsCopcPointCloudIndex *index = dynamic_cast( mDataProvider->index() ) ) { index->writeStatistics( mStatistics ); } diff --git a/src/core/pointcloud/qgspointcloudlayerexporter.cpp b/src/core/pointcloud/qgspointcloudlayerexporter.cpp index b3c13f2f41c45..e97a42ae935a1 100644 --- a/src/core/pointcloud/qgspointcloudlayerexporter.cpp +++ b/src/core/pointcloud/qgspointcloudlayerexporter.cpp @@ -24,6 +24,7 @@ #include "moc_qgspointcloudlayerexporter.cpp" #include "qgsmemoryproviderutils.h" #include "qgspointcloudrequest.h" +#include "qgsrectangle.h" #include "qgsvectorfilewriter.h" #include "qgsgeos.h" @@ -329,23 +330,23 @@ void QgsPointCloudLayerExporter::ExporterBase::run() geometryFilterRectangle = envelope->boundingBox(); } - QVector nodes; + QVector nodes; qint64 pointCount = 0; - QQueue queue; + QQueue queue; queue.push_back( mParent->mIndex->root() ); while ( !queue.empty() ) { - IndexedPointCloudNode node = queue.front(); + QgsPointCloudNode node = mParent->mIndex->getNode( queue.front() ); queue.pop_front(); - const QgsRectangle nodeExtent = mParent->mIndex->nodeMapExtent( node ); - if ( mParent->mExtent.intersects( nodeExtent ) && - mParent->mZRange.overlaps( mParent->mIndex->nodeZRange( node ) ) && - geometryFilterRectangle.intersects( nodeExtent ) ) + const QgsBox3D nodeBounds = node.bounds(); + if ( mParent->mExtent.intersects( nodeBounds.toRectangle() ) && + mParent->mZRange.overlaps( { nodeBounds.zMinimum(), nodeBounds.zMaximum() } ) && + geometryFilterRectangle.intersects( nodeBounds.toRectangle() ) ) { - pointCount += mParent->mIndex->nodePointCount( node ); - nodes.push_back( node ); + pointCount += node.pointCount(); + nodes.push_back( node.id() ); } - for ( const IndexedPointCloudNode &child : mParent->mIndex->nodeChildren( node ) ) + for ( const QgsPointCloudNodeId &child : node.children() ) { queue.push_back( child ); } @@ -356,7 +357,7 @@ void QgsPointCloudLayerExporter::ExporterBase::run() request.setAttributes( mParent->requestedAttributeCollection() ); std::unique_ptr block = nullptr; qint64 pointsExported = 0; - for ( const IndexedPointCloudNode &node : nodes ) + for ( const QgsPointCloudNodeId &node : nodes ) { block = mParent->mIndex->nodeData( node, request ); const QgsPointCloudAttributeCollection attributesCollection = block->attributes(); diff --git a/src/core/pointcloud/qgspointcloudlayerprofilegenerator.cpp b/src/core/pointcloud/qgspointcloudlayerprofilegenerator.cpp index 9982c4f1d3257..a8d706b0e14e7 100644 --- a/src/core/pointcloud/qgspointcloudlayerprofilegenerator.cpp +++ b/src/core/pointcloud/qgspointcloudlayerprofilegenerator.cpp @@ -510,8 +510,8 @@ bool QgsPointCloudLayerProfileGenerator::generateProfile( const QgsProfileGenera for ( QgsPointCloudIndex *pc : std::as_const( indexes ) ) { - const IndexedPointCloudNode root = pc->root(); - const QgsRectangle rootNodeExtentLayerCoords = pc->nodeMapExtent( root ); + const QgsPointCloudNode root = pc->getNode( pc->root() ); + const QgsRectangle rootNodeExtentLayerCoords = root.bounds().toRectangle(); QgsRectangle rootNodeExtentInCurveCrs; try { @@ -531,7 +531,7 @@ 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 maxErrorInMapCoordinates = maximumErrorPixels * mapUnitsPerPixel; @@ -599,37 +599,36 @@ QgsFeedback *QgsPointCloudLayerProfileGenerator::feedback() const return mFeedback.get(); } -QVector QgsPointCloudLayerProfileGenerator::traverseTree( const QgsPointCloudIndex *pc, IndexedPointCloudNode 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; + QVector nodes; if ( mFeedback->isCanceled() ) { return nodes; } - const QgsDoubleRange nodeZRange = pc->nodeZRange( n ); - const QgsDoubleRange adjustedNodeZRange = QgsDoubleRange( nodeZRange.lower() * mZScale + mZOffset, nodeZRange.upper() * mZScale + mZOffset ); - if ( !zRange.isInfinite() && !zRange.overlaps( adjustedNodeZRange ) ) + QgsPointCloudNode node = pc->getNode( n ); + QgsBox3D nodeBounds = node.bounds(); + const QgsDoubleRange nodeZRange( nodeBounds.zMinimum(), nodeBounds.zMaximum() ); + if ( !zRange.isInfinite() && !zRange.overlaps( nodeZRange ) ) return nodes; - const QgsRectangle nodeMapExtent = pc->nodeMapExtent( n ); - if ( !mMaxSearchExtentInLayerCrs.intersects( nodeMapExtent ) ) + if ( !mMaxSearchExtentInLayerCrs.intersects( nodeBounds.toRectangle() ) ) return nodes; - const QgsGeometry nodeMapGeometry = QgsGeometry::fromRect( nodeMapExtent ); + const QgsGeometry nodeMapGeometry = QgsGeometry::fromRect( nodeBounds.toRectangle() ); if ( !mSearchGeometryInLayerCrsGeometryEngine->intersects( nodeMapGeometry.constGet() ) ) return nodes; - if ( pc->nodePointCount( n ) > 0 ) + if ( node.pointCount() > 0 ) nodes.append( n ); double childrenErrorPixels = nodeErrorPixels / 2.0; if ( childrenErrorPixels < maxErrorPixels ) return nodes; - const QList children = pc->nodeChildren( n ); - for ( const IndexedPointCloudNode &nn : children ) + for ( const QgsPointCloudNodeId &nn : node.children() ) { nodes += traverseTree( pc, nn, maxErrorPixels, childrenErrorPixels, zRange ); } @@ -637,10 +636,10 @@ QVector QgsPointCloudLayerProfileGenerator::traverseTree( 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 IndexedPointCloudNode &n : nodes ) + for ( const QgsPointCloudNodeId &n : nodes ) { if ( mFeedback->isCanceled() ) break; @@ -657,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; @@ -670,7 +669,7 @@ int QgsPointCloudLayerProfileGenerator::visitNodesAsync( const QVectorasyncNodeData( n, request ); blockRequests.append( blockRequest ); diff --git a/src/core/pointcloud/qgspointcloudlayerprofilegenerator.h b/src/core/pointcloud/qgspointcloudlayerprofilegenerator.h index 6b082cc23b941..370b786c4362d 100644 --- a/src/core/pointcloud/qgspointcloudlayerprofilegenerator.h +++ b/src/core/pointcloud/qgspointcloudlayerprofilegenerator.h @@ -37,7 +37,7 @@ class QgsPointCloudLayer; class QgsAbstractTerrainProvider; class QgsProfileSnapContext; class QgsPointCloudRenderer; -class IndexedPointCloudNode; +class QgsPointCloudNodeId; class QgsPointCloudIndex; class QgsPointCloudRequest; class QgsPointCloudBlock; @@ -144,9 +144,9 @@ class CORE_EXPORT QgsPointCloudLayerProfileGenerator : public QgsAbstractProfile QgsFeedback *feedback() const override; private: - QVector traverseTree( const QgsPointCloudIndex *pc, IndexedPointCloudNode 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 f127228aaa278..d4baafe8083c5 100644 --- a/src/core/pointcloud/qgspointcloudlayerrenderer.cpp +++ b/src/core/pointcloud/qgspointcloudlayerrenderer.cpp @@ -240,11 +240,12 @@ bool QgsPointCloudLayerRenderer::renderIndex( QgsPointCloudIndex *pc ) t.start(); #endif - const IndexedPointCloudNode root = pc->root(); + const QgsPointCloudNodeId root = pc->root(); const double maximumError = context.renderContext().convertToPainterUnits( mRenderer->maximumScreenError(), mRenderer->maximumScreenErrorUnit() );// in pixels - const QgsRectangle rootNodeExtentLayerCoords = pc->nodeMapExtent( root ); + const QgsPointCloudNode rootNode = pc->getNode( root ); + const QgsRectangle rootNodeExtentLayerCoords = pc->extent(); QgsRectangle rootNodeExtentMapCoords; if ( !context.renderContext().coordinateTransform().isShortCircuited() ) { @@ -274,7 +275,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 ); @@ -328,7 +329,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() ) @@ -339,7 +340,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; @@ -409,7 +410,7 @@ int QgsPointCloudLayerRenderer::renderNodesAsync( const QVectorasyncNodeData( n, request ); blockRequests.append( blockRequest ); @@ -486,7 +487,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; @@ -501,7 +502,7 @@ int QgsPointCloudLayerRenderer::renderNodesSorted( const QVector> allPairs; - for ( const IndexedPointCloudNode &n : nodes ) + for ( const QgsPointCloudNodeId &n : nodes ) { if ( context.renderContext().renderingStopped() ) { @@ -758,13 +759,13 @@ void QgsPointCloudLayerRenderer::setLayerRenderingTimeHint( int time ) mRenderTimeHint = time; } -QVector QgsPointCloudLayerRenderer::traverseTree( const QgsPointCloudIndex *pc, +QVector QgsPointCloudLayerRenderer::traverseTree( const QgsPointCloudIndex *pc, const QgsRenderContext &context, - IndexedPointCloudNode n, + QgsPointCloudNodeId n, double maxErrorPixels, double nodeErrorPixels ) { - QVector nodes; + QVector nodes; if ( context.renderingStopped() ) { @@ -772,23 +773,25 @@ QVector QgsPointCloudLayerRenderer::traverseTree( const Q return nodes; } - if ( !context.extent().intersects( pc->nodeMapExtent( n ) ) ) + QgsPointCloudNode node = pc->getNode( n ); + QgsBox3D nodeExtent = node.bounds(); + + if ( !context.extent().intersects( nodeExtent.toRectangle() ) ) return nodes; - const QgsDoubleRange nodeZRange = pc->nodeZRange( n ); + const QgsDoubleRange nodeZRange( nodeExtent.zMinimum(), nodeExtent.zMaximum() ); const QgsDoubleRange adjustedNodeZRange = QgsDoubleRange( nodeZRange.lower() + mZOffset, nodeZRange.upper() + mZOffset ); if ( !context.zRange().isInfinite() && !context.zRange().overlaps( adjustedNodeZRange ) ) return nodes; - if ( pc->nodePointCount( n ) > 0 ) + if ( node.pointCount() > 0 ) nodes.append( n ); double childrenErrorPixels = nodeErrorPixels / 2.0; if ( childrenErrorPixels < maxErrorPixels ) return nodes; - const QList children = pc->nodeChildren( n ); - for ( const IndexedPointCloudNode &nn : children ) + for ( const QgsPointCloudNodeId &nn : node.children() ) { nodes += traverseTree( pc, context, nn, maxErrorPixels, childrenErrorPixels ); } diff --git a/src/core/pointcloud/qgspointcloudlayerrenderer.h b/src/core/pointcloud/qgspointcloudlayerrenderer.h index 1fe90fadf93cf..23be4090291d5 100644 --- a/src/core/pointcloud/qgspointcloudlayerrenderer.h +++ b/src/core/pointcloud/qgspointcloudlayerrenderer.h @@ -72,10 +72,10 @@ class CORE_EXPORT QgsPointCloudLayerRenderer: public QgsMapLayerRenderer QgsFeedback *feedback() const override { return mFeedback.get(); } private: - QVector traverseTree( const QgsPointCloudIndex *pc, const QgsRenderContext &context, IndexedPointCloudNode 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 ); diff --git a/src/core/pointcloud/qgspointcloudstatistics.h b/src/core/pointcloud/qgspointcloudstatistics.h index 299bccea226f2..6da262cba6b4a 100644 --- a/src/core/pointcloud/qgspointcloudstatistics.h +++ b/src/core/pointcloud/qgspointcloudstatistics.h @@ -26,7 +26,7 @@ #include class QgsPointCloudAttribute; -class IndexedPointCloudNode; +class QgsPointCloudNodeId; /** * \ingroup core diff --git a/src/core/pointcloud/qgspointcloudstatscalculator.cpp b/src/core/pointcloud/qgspointcloudstatscalculator.cpp index 4cdf9388b1f0a..5748dd2412a59 100644 --- a/src/core/pointcloud/qgspointcloudstatscalculator.cpp +++ b/src/core/pointcloud/qgspointcloudstatscalculator.cpp @@ -57,22 +57,23 @@ struct StatsProcessor return *this; } - QgsPointCloudStatistics operator()( IndexedPointCloudNode node ) + QgsPointCloudStatistics operator()( QgsPointCloudNodeId nodeId ) { - if ( mIndex->nodePointCount( node ) < 1 ) + QgsPointCloudNode node = mIndex->getNode( nodeId ); + if ( node.pointCount() < 1 ) return QgsPointCloudStatistics(); std::unique_ptr block = nullptr; if ( mIndex->accessType() == QgsPointCloudIndex::Local ) { - block = mIndex->nodeData( node, mRequest ); + block = mIndex->nodeData( nodeId, mRequest ); } else { - QgsPointCloudBlockRequest *request = mIndex->asyncNodeData( node, mRequest ); + QgsPointCloudBlockRequest *request = mIndex->asyncNodeData( nodeId, mRequest ); if ( request == nullptr ) { - QgsDebugError( QStringLiteral( "Unable to calculate statistics for node %1: Got nullptr async request" ).arg( node.toString() ) ); + QgsDebugError( QStringLiteral( "Unable to calculate statistics for node %1: Got nullptr async request" ).arg( nodeId.toString() ) ); return QgsPointCloudStatistics(); } QEventLoop loop; @@ -84,7 +85,7 @@ struct StatsProcessor block = request->takeBlock(); if ( !block ) { - QgsMessageLog::logMessage( QObject::tr( "Unable to calculate statistics for node %1, error: \"%2\"" ).arg( node.toString(), request->errorStr() ) ); + QgsMessageLog::logMessage( QObject::tr( "Unable to calculate statistics for node %1, error: \"%2\"" ).arg( nodeId.toString(), request->errorStr() ) ); } } } @@ -198,23 +199,23 @@ bool QgsPointCloudStatsCalculator::calculateStats( QgsFeedback *feedback, const mRequest.setAttributes( attributes ); qint64 pointCount = 0; - QVector nodes; - QQueue queue; + QVector nodes; + QQueue queue; queue.push_back( mIndex->root() ); while ( !queue.empty() ) { - IndexedPointCloudNode node = queue.front(); + QgsPointCloudNode node = mIndex->getNode( queue.front() ); queue.pop_front(); - if ( !mProcessedNodes.contains( node ) ) - pointCount += mIndex->nodePointCount( node ); + if ( !mProcessedNodes.contains( node.id() ) ) + pointCount += node.pointCount(); if ( pointsLimit != -1 && pointCount > pointsLimit ) break; - if ( !mProcessedNodes.contains( node ) ) + if ( !mProcessedNodes.contains( node.id() ) ) { - nodes.push_back( node ); - mProcessedNodes.insert( node ); + nodes.push_back( node.id() ); + mProcessedNodes.insert( node.id() ); } - for ( const IndexedPointCloudNode &child : mIndex->nodeChildren( node ) ) + for ( const QgsPointCloudNodeId &child : node.children() ) { queue.push_back( child ); } diff --git a/src/core/pointcloud/qgspointcloudstatscalculator.h b/src/core/pointcloud/qgspointcloudstatscalculator.h index a9ec7e755f013..d7fff2a6953ab 100644 --- a/src/core/pointcloud/qgspointcloudstatscalculator.h +++ b/src/core/pointcloud/qgspointcloudstatscalculator.h @@ -27,7 +27,6 @@ #include #include "qgspointcloudrequest.h" -#include "qgsstatisticalsummary.h" #include "qgspointcloudstatistics.h" #define SIP_NO_FILE @@ -35,7 +34,7 @@ class QgsPointCloudIndex; class QgsPointCloudBlock; class QgsPointCloudAttribute; -class IndexedPointCloudNode; +class QgsPointCloudNodeId; class QgsFeedback; /** @@ -66,7 +65,7 @@ class CORE_EXPORT QgsPointCloudStatsCalculator : public QObject std::unique_ptr mIndex; QgsPointCloudStatistics mStats; - QSet mProcessedNodes; + QSet mProcessedNodes; QgsPointCloudRequest mRequest; }; diff --git a/tests/src/providers/testqgscopcprovider.cpp b/tests/src/providers/testqgscopcprovider.cpp index 347f4522173f3..d4d3628c7d30a 100644 --- a/tests/src/providers/testqgscopcprovider.cpp +++ b/tests/src/providers/testqgscopcprovider.cpp @@ -267,8 +267,8 @@ void TestQgsCopcProvider::validLayer() QVERIFY( layer->dataProvider()->index() ); // all hierarchy is stored in a single node - QVERIFY( layer->dataProvider()->index()->hasNode( IndexedPointCloudNode::fromString( "0-0-0-0" ) ) ); - QVERIFY( !layer->dataProvider()->index()->hasNode( IndexedPointCloudNode::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() @@ -285,8 +285,8 @@ void TestQgsCopcProvider::validLayerWithCopcHierarchy() QVERIFY( layer->dataProvider()->index() ); // all hierarchy is stored in multiple nodes - QVERIFY( layer->dataProvider()->index()->hasNode( IndexedPointCloudNode::fromString( "1-1-1-0" ) ) ); - QVERIFY( layer->dataProvider()->index()->hasNode( IndexedPointCloudNode::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() @@ -831,10 +831,10 @@ void TestQgsCopcProvider::testPointCloudIndex() QgsPointCloudIndex *index = layer->dataProvider()->index(); QVERIFY( index->isValid() ); - QCOMPARE( index->nodePointCount( IndexedPointCloudNode::fromString( QStringLiteral( "0-0-0-0" ) ) ), 56721 ); - QCOMPARE( index->nodePointCount( IndexedPointCloudNode::fromString( QStringLiteral( "1-1-1-1" ) ) ), -1 ); - QCOMPARE( index->nodePointCount( IndexedPointCloudNode::fromString( QStringLiteral( "2-3-3-1" ) ) ), 446 ); - QCOMPARE( index->nodePointCount( IndexedPointCloudNode::fromString( QStringLiteral( "9-9-9-9" ) ) ), -1 ); + QCOMPARE( index->getNode( QgsPointCloudNodeId::fromString( QStringLiteral( "0-0-0-0" ) ) ).pointCount(), 56721 ); + QCOMPARE( index->getNode( QgsPointCloudNodeId::fromString( QStringLiteral( "1-1-1-1" ) ) ).pointCount(), -1 ); + QCOMPARE( index->getNode( QgsPointCloudNodeId::fromString( QStringLiteral( "2-3-3-1" ) ) ).pointCount(), 446 ); + QCOMPARE( index->getNode( QgsPointCloudNodeId::fromString( QStringLiteral( "9-9-9-9" ) ) ).pointCount(), -1 ); QCOMPARE( index->pointCount(), 518862 ); QCOMPARE( index->zMin(), 2322.89625 ); @@ -843,38 +843,38 @@ void TestQgsCopcProvider::testPointCloudIndex() QCOMPARE( index->offset().toVector3D(), QVector3D( 515385, 4918361, 2330.5 ) ); QCOMPARE( index->span(), 128 ); - QCOMPARE( index->nodeError( IndexedPointCloudNode::fromString( QStringLiteral( "0-0-0-0" ) ) ), 0.328125 ); - QCOMPARE( index->nodeError( IndexedPointCloudNode::fromString( QStringLiteral( "1-1-1-1" ) ) ), 0.1640625 ); - QCOMPARE( index->nodeError( IndexedPointCloudNode::fromString( QStringLiteral( "2-3-3-1" ) ) ), 0.08203125 ); + QCOMPARE( index->getNode( QgsPointCloudNodeId::fromString( QStringLiteral( "0-0-0-0" ) ) ).error(), 0.328125 ); + QCOMPARE( index->getNode( QgsPointCloudNodeId::fromString( QStringLiteral( "1-1-1-1" ) ) ).error(), 0.1640625 ); + QCOMPARE( index->getNode( QgsPointCloudNodeId::fromString( QStringLiteral( "2-3-3-1" ) ) ).error(), 0.08203125 ); { - QgsPointCloudDataBounds bounds = index->nodeBounds( IndexedPointCloudNode::fromString( QStringLiteral( "0-0-0-0" ) ) ); - QCOMPARE( bounds.xMin(), -170000 ); - QCOMPARE( bounds.yMin(), -210000 ); - QCOMPARE( bounds.zMin(), -85000 ); - QCOMPARE( bounds.xMax(), 250000 ); - QCOMPARE( bounds.yMax(), 210000 ); - QCOMPARE( bounds.zMax(), 335000 ); + QgsBox3D bounds = index->getNode( QgsPointCloudNodeId::fromString( QStringLiteral( "0-0-0-0" ) ) ).bounds(); + QCOMPARE( bounds.xMinimum(), 515368 ); + QCOMPARE( bounds.yMinimum(), 4918340 ); + QCOMPARE( bounds.zMinimum(), 2322 ); + QCOMPARE( bounds.xMaximum(), 515410 ); + QCOMPARE( bounds.yMaximum(), 4918382 ); + QCOMPARE( bounds.zMaximum(), 2364 ); } { - QgsPointCloudDataBounds bounds = index->nodeBounds( IndexedPointCloudNode::fromString( QStringLiteral( "1-1-1-1" ) ) ); - QCOMPARE( bounds.xMin(), 40000 ); - QCOMPARE( bounds.yMin(), 0 ); - QCOMPARE( bounds.zMin(), 125000 ); - QCOMPARE( bounds.xMax(), 250000 ); - QCOMPARE( bounds.yMax(), 210000 ); - QCOMPARE( bounds.zMax(), 335000 ); + QgsBox3D bounds = index->getNode( QgsPointCloudNodeId::fromString( QStringLiteral( "1-1-1-1" ) ) ).bounds(); + QCOMPARE( bounds.xMinimum(), 515389 ); + QCOMPARE( bounds.yMinimum(), 4918361 ); + QCOMPARE( bounds.zMinimum(), 2343 ); + QCOMPARE( bounds.xMaximum(), 515410 ); + QCOMPARE( bounds.yMaximum(), 4918382 ); + QCOMPARE( bounds.zMaximum(), 2364 ); } { - QgsPointCloudDataBounds bounds = index->nodeBounds( IndexedPointCloudNode::fromString( QStringLiteral( "2-3-3-1" ) ) ); - QCOMPARE( bounds.xMin(), 145000 ); - QCOMPARE( bounds.yMin(), 105000 ); - QCOMPARE( bounds.zMin(), 20000 ); - QCOMPARE( bounds.xMax(), 250000 ); - QCOMPARE( bounds.yMax(), 210000 ); - QCOMPARE( bounds.zMax(), 125000 ); + 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 ); + QCOMPARE( bounds.xMaximum(), 515410 ); + QCOMPARE( bounds.yMaximum(), 4918382 ); + QCOMPARE( bounds.zMaximum(), 2343 ); } } @@ -1136,7 +1136,7 @@ void TestQgsCopcProvider::testSaveLoadStats() QVERIFY( layer->isValid() ); QVERIFY( layer->dataProvider() && layer->dataProvider()->isValid() && layer->dataProvider()->index() ); - QgsCopcPointCloudIndex *index = qobject_cast( layer->dataProvider()->index() ); + QgsCopcPointCloudIndex *index = dynamic_cast( layer->dataProvider()->index() ); calculatedStats = layer->statistics(); index->writeStatistics( calculatedStats ); @@ -1148,7 +1148,7 @@ void TestQgsCopcProvider::testSaveLoadStats() QVERIFY( layer->dataProvider() && layer->dataProvider()->isValid() && layer->dataProvider()->index() ); - QgsCopcPointCloudIndex *index = qobject_cast( layer->dataProvider()->index() ); + QgsCopcPointCloudIndex *index = dynamic_cast( layer->dataProvider()->index() ); readStats = index->metadataStatistics(); } @@ -1166,16 +1166,16 @@ void TestQgsCopcProvider::testPointCloudRequest() QgsPointCloudIndex *index = layer->dataProvider()->index(); QVERIFY( index->isValid() ); - QVector nodes; - QQueue queue; + QVector nodes; + QQueue queue; queue.push_back( index->root() ); while ( !queue.empty() ) { - IndexedPointCloudNode node = queue.front(); + QgsPointCloudNodeId node = queue.front(); queue.pop_front(); nodes.push_back( node ); - for ( const IndexedPointCloudNode &child : index->nodeChildren( node ) ) + for ( const QgsPointCloudNodeId &child : index->getNode( node ).children() ) { queue.push_back( child ); } @@ -1185,7 +1185,7 @@ void TestQgsCopcProvider::testPointCloudRequest() request.setAttributes( layer->attributes() ); // If request.setFilterRect() is not called, no filter should be applied int count = 0; - for ( IndexedPointCloudNode node : nodes ) + for ( QgsPointCloudNodeId node : nodes ) { auto block = index->nodeData( node, request ); count += block->pointCount(); @@ -1196,7 +1196,7 @@ void TestQgsCopcProvider::testPointCloudRequest() QgsRectangle extent( 515390, 4918360, 515400, 4918370 ); request.setFilterRect( extent ); count = 0; - for ( IndexedPointCloudNode node : nodes ) + for ( QgsPointCloudNodeId node : nodes ) { auto block = index->nodeData( node, request ); count += block->pointCount(); @@ -1207,7 +1207,7 @@ void TestQgsCopcProvider::testPointCloudRequest() extent = QgsRectangle( 0, 0, 1, 1 ); request.setFilterRect( extent ); count = 0; - for ( IndexedPointCloudNode node : nodes ) + for ( QgsPointCloudNodeId node : nodes ) { auto block = index->nodeData( node, request ); count += block->pointCount(); @@ -1218,7 +1218,7 @@ void TestQgsCopcProvider::testPointCloudRequest() count = 0; extent = QgsRectangle(); request.setFilterRect( extent ); - for ( IndexedPointCloudNode node : nodes ) + for ( QgsPointCloudNodeId node : nodes ) { auto block = index->nodeData( node, request ); count += block->pointCount(); diff --git a/tests/src/providers/testqgseptprovider.cpp b/tests/src/providers/testqgseptprovider.cpp index de72ad9150d3c..751ad5626a312 100644 --- a/tests/src/providers/testqgseptprovider.cpp +++ b/tests/src/providers/testqgseptprovider.cpp @@ -264,8 +264,8 @@ void TestQgsEptProvider::validLayer() QVERIFY( layer->dataProvider()->index() ); // all hierarchy is stored in a single node - QVERIFY( layer->dataProvider()->index()->hasNode( IndexedPointCloudNode::fromString( "0-0-0-0" ) ) ); - QVERIFY( !layer->dataProvider()->index()->hasNode( IndexedPointCloudNode::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() @@ -282,8 +282,8 @@ void TestQgsEptProvider::validLayerWithEptHierarchy() QVERIFY( layer->dataProvider()->index() ); // all hierarchy is stored in multiple nodes - QVERIFY( layer->dataProvider()->index()->hasNode( IndexedPointCloudNode::fromString( "1-1-1-1" ) ) ); - QVERIFY( layer->dataProvider()->index()->hasNode( IndexedPointCloudNode::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() @@ -629,10 +629,10 @@ void TestQgsEptProvider::testPointCloudIndex() QgsPointCloudIndex *index = layer->dataProvider()->index(); QVERIFY( index->isValid() ); - QCOMPARE( index->nodePointCount( IndexedPointCloudNode::fromString( QStringLiteral( "0-0-0-0" ) ) ), 41998 ); - QCOMPARE( index->nodePointCount( IndexedPointCloudNode::fromString( QStringLiteral( "1-1-1-1" ) ) ), 48879 ); - QCOMPARE( index->nodePointCount( IndexedPointCloudNode::fromString( QStringLiteral( "2-3-3-1" ) ) ), 41734 ); - QCOMPARE( index->nodePointCount( IndexedPointCloudNode::fromString( QStringLiteral( "9-9-9-9" ) ) ), -1 ); + 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 ); + QCOMPARE( index->getNode( QgsPointCloudNodeId::fromString( QStringLiteral( "9-9-9-9" ) ) ).pointCount(), -1 ); QCOMPARE( index->pointCount(), 518862 ); QCOMPARE( index->zMin(), 2322 ); @@ -641,38 +641,38 @@ void TestQgsEptProvider::testPointCloudIndex() QCOMPARE( index->offset().toVector3D(), QVector3D( 515385, 4918361, 2331 ) ); QCOMPARE( index->span(), 128 ); - QCOMPARE( index->nodeError( IndexedPointCloudNode::fromString( QStringLiteral( "0-0-0-0" ) ) ), 0.34375 ); - QCOMPARE( index->nodeError( IndexedPointCloudNode::fromString( QStringLiteral( "1-1-1-1" ) ) ), 0.171875 ); - QCOMPARE( index->nodeError( IndexedPointCloudNode::fromString( QStringLiteral( "2-3-3-1" ) ) ), 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 ); { - QgsPointCloudDataBounds bounds = index->nodeBounds( IndexedPointCloudNode::fromString( QStringLiteral( "0-0-0-0" ) ) ); - QCOMPARE( bounds.xMin(), -88000 ); - QCOMPARE( bounds.yMin(), -88000 ); - QCOMPARE( bounds.zMin(), -88000 ); - QCOMPARE( bounds.xMax(), 88000 ); - QCOMPARE( bounds.yMax(), 88000 ); - QCOMPARE( bounds.zMax(), 88000 ); + QgsBox3D bounds = index->getNode( QgsPointCloudNodeId::fromString( QStringLiteral( "0-0-0-0" ) ) ).bounds(); + QCOMPARE( bounds.xMinimum(), 515363 ); + QCOMPARE( bounds.yMinimum(), 4918339 ); + QCOMPARE( bounds.zMinimum(), 2309 ); + QCOMPARE( bounds.xMaximum(), 515407 ); + QCOMPARE( bounds.yMaximum(), 4918383 ); + QCOMPARE( bounds.zMaximum(), 2353 ); } { - QgsPointCloudDataBounds bounds = index->nodeBounds( IndexedPointCloudNode::fromString( QStringLiteral( "1-1-1-1" ) ) ); - QCOMPARE( bounds.xMin(), 0 ); - QCOMPARE( bounds.yMin(), 0 ); - QCOMPARE( bounds.zMin(), 0 ); - QCOMPARE( bounds.xMax(), 88000 ); - QCOMPARE( bounds.yMax(), 88000 ); - QCOMPARE( bounds.zMax(), 88000 ); + QgsBox3D bounds = index->getNode( QgsPointCloudNodeId::fromString( QStringLiteral( "1-1-1-1" ) ) ).bounds(); + QCOMPARE( bounds.xMinimum(), 515385 ); + QCOMPARE( bounds.yMinimum(), 4918361 ); + QCOMPARE( bounds.zMinimum(), 2331 ); + QCOMPARE( bounds.xMaximum(), 515407 ); + QCOMPARE( bounds.yMaximum(), 4918383 ); + QCOMPARE( bounds.zMaximum(), 2353 ); } { - QgsPointCloudDataBounds bounds = index->nodeBounds( IndexedPointCloudNode::fromString( QStringLiteral( "2-3-3-1" ) ) ); - QCOMPARE( bounds.xMin(), 44000 ); - QCOMPARE( bounds.yMin(), 44000 ); - QCOMPARE( bounds.zMin(), -44000 ); - QCOMPARE( bounds.xMax(), 88000 ); - QCOMPARE( bounds.yMax(), 88000 ); - QCOMPARE( bounds.zMax(), 0 ); + QgsBox3D bounds = index->getNode( QgsPointCloudNodeId::fromString( QStringLiteral( "2-3-3-1" ) ) ).bounds(); + QCOMPARE( bounds.xMinimum(), 515396 ); + QCOMPARE( bounds.yMinimum(), 4918372 ); + QCOMPARE( bounds.zMinimum(), 2320 ); + QCOMPARE( bounds.xMaximum(), 515407 ); + QCOMPARE( bounds.yMaximum(), 4918383 ); + QCOMPARE( bounds.zMaximum(), 2331 ); } } @@ -686,16 +686,16 @@ void TestQgsEptProvider::testPointCloudRequest() QgsPointCloudIndex *index = layer->dataProvider()->index(); QVERIFY( index->isValid() ); - QVector nodes; - QQueue queue; + QVector nodes; + QQueue queue; queue.push_back( index->root() ); while ( !queue.empty() ) { - IndexedPointCloudNode node = queue.front(); + QgsPointCloudNodeId node = queue.front(); queue.pop_front(); nodes.push_back( node ); - for ( const IndexedPointCloudNode &child : index->nodeChildren( node ) ) + for ( const QgsPointCloudNodeId &child : index->getNode( node ).children() ) { queue.push_back( child ); } @@ -705,7 +705,7 @@ void TestQgsEptProvider::testPointCloudRequest() request.setAttributes( layer->attributes() ); // If request.setFilterRect() is not called, no filter should be applied int count = 0; - for ( IndexedPointCloudNode node : nodes ) + for ( QgsPointCloudNodeId node : nodes ) { std::unique_ptr< QgsPointCloudBlock> block( index->nodeData( node, request ) ); count += block->pointCount(); @@ -716,7 +716,7 @@ void TestQgsEptProvider::testPointCloudRequest() QgsRectangle extent( 515390, 4918360, 515400, 4918370 ); request.setFilterRect( extent ); count = 0; - for ( IndexedPointCloudNode node : nodes ) + for ( QgsPointCloudNodeId node : nodes ) { std::unique_ptr< QgsPointCloudBlock> block( index->nodeData( node, request ) ); count += block->pointCount(); @@ -727,7 +727,7 @@ void TestQgsEptProvider::testPointCloudRequest() extent = QgsRectangle( 0, 0, 1, 1 ); request.setFilterRect( extent ); count = 0; - for ( IndexedPointCloudNode node : nodes ) + for ( QgsPointCloudNodeId node : nodes ) { std::unique_ptr< QgsPointCloudBlock> block( index->nodeData( node, request ) ); count += block->pointCount(); @@ -738,7 +738,7 @@ void TestQgsEptProvider::testPointCloudRequest() count = 0; extent = QgsRectangle(); request.setFilterRect( extent ); - for ( IndexedPointCloudNode node : nodes ) + for ( QgsPointCloudNodeId node : nodes ) { std::unique_ptr< QgsPointCloudBlock> block( index->nodeData( node, request ) ); count += block->pointCount();