Fix elevation profile on virtual point cloud (#59073)

* Fix elevation profile on virtual point cloud

(fix #54728)

* Update src/core/pointcloud/qgspointcloudlayerprofilegenerator.cpp

---------

Co-authored-by: Nyall Dawson <nyall.dawson@gmail.com>
This commit is contained in:
David Koňařík 2024-10-24 10:05:15 +02:00 committed by GitHub
parent 400cf13bb0
commit de9377a4bb
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

View File

@ -389,12 +389,23 @@ bool QgsPointCloudLayerProfileGenerator::generateProfile( const QgsProfileGenera
// this is not AT ALL thread safe, but it's what QgsPointCloudLayerRenderer does !
// TODO: fix when QgsPointCloudLayerRenderer is made thread safe to use same approach
QgsPointCloudIndex *pc = mLayer->dataProvider()->index();
if ( !pc || !pc->isValid() )
QVector<QgsPointCloudIndex *> indexes;
QgsPointCloudIndex *mainIndex = mLayer->dataProvider()->index();
if ( mainIndex && mainIndex->isValid() )
indexes.append( mainIndex );
// Gather all relevant sub-indexes
const QgsRectangle profileCurveBbox = mProfileCurve->boundingBox();
for ( const QgsPointCloudSubIndex &subidx : mLayer->dataProvider()->subIndexes() )
{
return false;
QgsPointCloudIndex *index = subidx.index();
if ( index && index->isValid() && subidx.polygonBounds().intersects( profileCurveBbox ) )
indexes.append( subidx.index() );
}
if ( indexes.empty() )
return false;
const double startDistanceOffset = std::max( !context.distanceRange().isInfinite() ? context.distanceRange().lower() : 0, 0.0 );
const double endDistance = context.distanceRange().upper();
@ -433,9 +444,13 @@ bool QgsPointCloudLayerProfileGenerator::generateProfile( const QgsProfileGenera
mSearchGeometryInLayerCrsGeometryEngine->prepareGeometry();
mMaxSearchExtentInLayerCrs = mSearchGeometryInLayerCrs->boundingBox();
const IndexedPointCloudNode root = pc->root();
double maximumErrorPixels = context.convertDistanceToPixels( mMaximumScreenError, mMaximumScreenErrorUnit );
if ( maximumErrorPixels < 0.0 )
{
QgsDebugError( QStringLiteral( "Invalid maximum error in pixels" ) );
return false;
}
const double toleranceInPixels = context.convertDistanceToPixels( mTolerance, Qgis::RenderUnit::MapUnits );
// ensure that the maximum error is compatible with the tolerance size -- otherwise if the tolerance size
// is much smaller than the maximum error, we don't dig deep enough into the point cloud nodes to find
@ -444,42 +459,6 @@ bool QgsPointCloudLayerProfileGenerator::generateProfile( const QgsProfileGenera
if ( toleranceInPixels / 4 < maximumErrorPixels )
maximumErrorPixels = toleranceInPixels / 4;
const QgsRectangle rootNodeExtentLayerCoords = pc->nodeMapExtent( root );
QgsRectangle rootNodeExtentInCurveCrs;
try
{
QgsCoordinateTransform extentTransform = mLayerToTargetTransform;
extentTransform.setBallparkTransformsAreAppropriate( true );
rootNodeExtentInCurveCrs = extentTransform.transformBoundingBox( rootNodeExtentLayerCoords );
}
catch ( QgsCsException & )
{
QgsDebugError( QStringLiteral( "Could not transform node extent to curve CRS" ) );
rootNodeExtentInCurveCrs = rootNodeExtentLayerCoords;
}
const double rootErrorInMapCoordinates = rootNodeExtentInCurveCrs.width() / pc->span(); // in curve coords
const double mapUnitsPerPixel = context.mapUnitsPerDistancePixel();
if ( ( rootErrorInMapCoordinates < 0.0 ) || ( mapUnitsPerPixel < 0.0 ) || ( maximumErrorPixels < 0.0 ) )
{
QgsDebugError( QStringLiteral( "invalid screen error" ) );
return false;
}
double rootErrorPixels = rootErrorInMapCoordinates / mapUnitsPerPixel; // in pixels
const QVector<IndexedPointCloudNode> nodes = traverseTree( pc, pc->root(), maximumErrorPixels, rootErrorPixels, context.elevationRange() );
if ( nodes.empty() )
{
return false;
}
const double rootErrorInLayerCoordinates = rootNodeExtentLayerCoords.width() / pc->span();
const double maxErrorInMapCoordinates = maximumErrorPixels * mapUnitsPerPixel;
mResults = std::make_unique< QgsPointCloudLayerProfileResults >();
mResults->copyPropertiesFromGenerator( this );
mResults->mMaxErrorInLayerCoordinates = maxErrorInMapCoordinates * rootErrorInLayerCoordinates / rootErrorInMapCoordinates;
QgsPointCloudRequest request;
QgsPointCloudAttributeCollection attributes;
attributes.push_back( QgsPointCloudAttribute( QStringLiteral( "X" ), QgsPointCloudAttribute::Int32 ) );
@ -515,22 +494,75 @@ bool QgsPointCloudLayerProfileGenerator::generateProfile( const QgsProfileGenera
request.setAttributes( attributes );
switch ( pc->accessType() )
mResults = std::make_unique< QgsPointCloudLayerProfileResults >();
mResults->copyPropertiesFromGenerator( this );
mResults->mMaxErrorInLayerCoordinates = 0;
QgsCoordinateTransform extentTransform = mLayerToTargetTransform;
extentTransform.setBallparkTransformsAreAppropriate( true );
const double mapUnitsPerPixel = context.mapUnitsPerDistancePixel();
if ( mapUnitsPerPixel < 0.0 )
{
case QgsPointCloudIndex::AccessType::Local:
{
visitNodesSync( nodes, pc, request, context.elevationRange() );
break;
}
case QgsPointCloudIndex::AccessType::Remote:
{
visitNodesAsync( nodes, pc, request, context.elevationRange() );
break;
}
QgsDebugError( QStringLiteral( "Invalid map units per pixel ratio" ) );
return false;
}
if ( mFeedback->isCanceled() )
for ( QgsPointCloudIndex *pc : std::as_const( indexes ) )
{
const IndexedPointCloudNode root = pc->root();
const QgsRectangle rootNodeExtentLayerCoords = pc->nodeMapExtent( root );
QgsRectangle rootNodeExtentInCurveCrs;
try
{
rootNodeExtentInCurveCrs = extentTransform.transformBoundingBox( rootNodeExtentLayerCoords );
}
catch ( QgsCsException & )
{
QgsDebugError( QStringLiteral( "Could not transform node extent to curve CRS" ) );
rootNodeExtentInCurveCrs = rootNodeExtentLayerCoords;
}
const double rootErrorInMapCoordinates = rootNodeExtentInCurveCrs.width() / pc->span(); // in curve coords
if ( rootErrorInMapCoordinates < 0.0 )
{
QgsDebugError( QStringLiteral( "Invalid root node error" ) );
return false;
}
double rootErrorPixels = rootErrorInMapCoordinates / mapUnitsPerPixel; // in pixels
const QVector<IndexedPointCloudNode> nodes = traverseTree( pc, pc->root(), maximumErrorPixels, rootErrorPixels, context.elevationRange() );
const double rootErrorInLayerCoordinates = rootNodeExtentLayerCoords.width() / pc->span();
const double maxErrorInMapCoordinates = maximumErrorPixels * mapUnitsPerPixel;
mResults->mMaxErrorInLayerCoordinates = std::max(
mResults->mMaxErrorInLayerCoordinates,
maxErrorInMapCoordinates * rootErrorInLayerCoordinates / rootErrorInMapCoordinates );
switch ( pc->accessType() )
{
case QgsPointCloudIndex::AccessType::Local:
{
visitNodesSync( nodes, pc, request, context.elevationRange() );
break;
}
case QgsPointCloudIndex::AccessType::Remote:
{
visitNodesAsync( nodes, pc, request, context.elevationRange() );
break;
}
}
if ( mFeedback->isCanceled() )
return false;
}
if ( mGatheredPoints.empty() )
{
mResults = nullptr;
return false;
}
// convert x/y values back to distance/height values