Skip to content

Commit

Permalink
Refactor QgsPointCloudIndex
Browse files Browse the repository at this point in the history
- Rename IndexedPointCloudNode to QgsPointCloudNodeId.
- Introduce QgsPointCloudNode and move methods to it from
  QgsPointCloudIndex.
- Report point cloud node bounds directly in CRS coordinates, without
  extra scaling and offset.
  • Loading branch information
dvdkon committed Nov 22, 2024
1 parent 6c8c546 commit 4bac513
Show file tree
Hide file tree
Showing 30 changed files with 435 additions and 545 deletions.
45 changes: 24 additions & 21 deletions src/3d/qgspointcloudlayerchunkloader_p.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#include "moc_qgspointcloudlayerchunkloader_p.cpp"

#include "qgs3dutils.h"
#include "qgsbox3d.h"
#include "qgspointcloudlayer3drenderer.h"
#include "qgschunknode.h"
#include "qgslogger.h"
Expand Down Expand Up @@ -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 ) );

Expand Down Expand Up @@ -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 );
Expand Down Expand Up @@ -165,28 +166,28 @@ 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 );
}

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<double>( nodeBounds.xMin() ) * scale.x() + offset.x(),
static_cast<double>( nodeBounds.yMin() ) * scale.y() + offset.y(),
( static_cast<double>( nodeBounds.zMin() ) * scale.z() + offset.z() ) * zValueScale + zValueOffset );
QgsVector3D extentMax3D( static_cast<double>( nodeBounds.xMax() ) * scale.x() + offset.x(),
static_cast<double>( nodeBounds.yMax() ) * scale.y() + offset.y(),
( static_cast<double>( nodeBounds.zMax() ) * scale.z() + offset.z() ) * zValueScale + zValueOffset );
QgsVector3D extentMin3D( static_cast<double>( nodeBounds.xMinimum() ),
static_cast<double>( nodeBounds.yMinimum() ),
static_cast<double>( nodeBounds.zMinimum() ) * zValueScale + zValueOffset );
QgsVector3D extentMax3D( static_cast<double>( nodeBounds.xMaximum() ),
static_cast<double>( nodeBounds.yMaximum() ),
static_cast<double>( nodeBounds.zMaximum() ) * zValueScale + zValueOffset );
QgsCoordinateTransform extentTransform = coordinateTransform;
extentTransform.setBallparkTransformsAreAppropriate( true );
try
Expand All @@ -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;
Expand All @@ -224,15 +226,16 @@ QVector<QgsChunkNode *> 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 );
Expand Down Expand Up @@ -302,7 +305,7 @@ QVector<QgsRayCastingUtils::RayHit> 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;
Expand Down
29 changes: 15 additions & 14 deletions src/3d/symbols/qgspointcloud3dsymbol_p.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -56,15 +56,15 @@ typedef Qt3DCore::QGeometry Qt3DQGeometry;
#include <delaunator.hpp>

// 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 );
Expand Down Expand Up @@ -359,7 +359,7 @@ void QgsPointCloud3DSymbolHandler::makeEntity( Qt3DCore::QEntity *parent, const
}


std::vector<double> QgsPointCloud3DSymbolHandler::getVertices( QgsPointCloudIndex *pc, const IndexedPointCloudNode &n, const QgsPointCloud3DRenderContext &context, const QgsBox3D &box3D )
std::vector<double> QgsPointCloud3DSymbolHandler::getVertices( QgsPointCloudIndex *pc, const QgsPointCloudNodeId &n, const QgsPointCloud3DRenderContext &context, const QgsBox3D &box3D )
{

bool hasColorData = !outNormal.colors.empty();
Expand All @@ -376,7 +376,7 @@ std::vector<double> 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
Expand Down Expand Up @@ -520,7 +520,7 @@ void QgsPointCloud3DSymbolHandler::filterTriangles( const std::vector<size_t> &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;
Expand All @@ -547,7 +547,7 @@ void QgsPointCloud3DSymbolHandler::triangulate( QgsPointCloudIndex *pc, const In
filterTriangles( triangleIndexes, context, box3D );
}

std::unique_ptr<QgsPointCloudBlock> QgsPointCloud3DSymbolHandler::pointCloudBlock( QgsPointCloudIndex *pc, const IndexedPointCloudNode &n, const QgsPointCloudRequest &request, const QgsPointCloud3DRenderContext &context )
std::unique_ptr<QgsPointCloudBlock> QgsPointCloud3DSymbolHandler::pointCloudBlock( QgsPointCloudIndex *pc, const QgsPointCloudNodeId &n, const QgsPointCloudRequest &request, const QgsPointCloud3DRenderContext &context )
{
std::unique_ptr<QgsPointCloudBlock> block;
if ( pc->accessType() == QgsPointCloudIndex::AccessType::Local )
Expand All @@ -556,7 +556,8 @@ std::unique_ptr<QgsPointCloudBlock> 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;
Expand Down Expand Up @@ -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 ) );
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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 ) );
Expand Down Expand Up @@ -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;
Expand Down
18 changes: 9 additions & 9 deletions src/3d/symbols/qgspointcloud3dsymbol_p.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@

#define SIP_NO_FILE

class IndexedPointCloudNode;
class QgsPointCloudNodeId;
class QgsAABB;

class QgsPointCloud3DSymbolHandler
Expand All @@ -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; }
Expand Down Expand Up @@ -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<QgsPointCloudBlock> pointCloudBlock( QgsPointCloudIndex *pc, const IndexedPointCloudNode &node, const QgsPointCloudRequest &request, const QgsPointCloud3DRenderContext &context );
std::unique_ptr<QgsPointCloudBlock> 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<double> getVertices( QgsPointCloudIndex *pc, const IndexedPointCloudNode &n, const QgsPointCloud3DRenderContext &context, const QgsBox3D &box3D );
std::vector<double> 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<size_t> &triangles );
Expand All @@ -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:
Expand All @@ -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:
Expand All @@ -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:
Expand All @@ -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:
Expand Down
2 changes: 1 addition & 1 deletion src/core/pointcloud/qgscachedpointcloudblockrequest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 )
Expand Down
2 changes: 1 addition & 1 deletion src/core/pointcloud/qgscachedpointcloudblockrequest.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 );

Expand Down
Loading

0 comments on commit 4bac513

Please sign in to comment.