Skip to content

Commit de9377a

Browse files
dvdkonnyalldawson
andauthored
Fix elevation profile on virtual point cloud (qgis#59073)
* Fix elevation profile on virtual point cloud (fix qgis#54728) * Update src/core/pointcloud/qgspointcloudlayerprofilegenerator.cpp --------- Co-authored-by: Nyall Dawson <[email protected]>
1 parent 400cf13 commit de9377a

File tree

1 file changed

+81
-49
lines changed

1 file changed

+81
-49
lines changed

src/core/pointcloud/qgspointcloudlayerprofilegenerator.cpp

+81-49
Original file line numberDiff line numberDiff line change
@@ -389,12 +389,23 @@ bool QgsPointCloudLayerProfileGenerator::generateProfile( const QgsProfileGenera
389389
// this is not AT ALL thread safe, but it's what QgsPointCloudLayerRenderer does !
390390
// TODO: fix when QgsPointCloudLayerRenderer is made thread safe to use same approach
391391

392-
QgsPointCloudIndex *pc = mLayer->dataProvider()->index();
393-
if ( !pc || !pc->isValid() )
392+
QVector<QgsPointCloudIndex *> indexes;
393+
QgsPointCloudIndex *mainIndex = mLayer->dataProvider()->index();
394+
if ( mainIndex && mainIndex->isValid() )
395+
indexes.append( mainIndex );
396+
397+
// Gather all relevant sub-indexes
398+
const QgsRectangle profileCurveBbox = mProfileCurve->boundingBox();
399+
for ( const QgsPointCloudSubIndex &subidx : mLayer->dataProvider()->subIndexes() )
394400
{
395-
return false;
401+
QgsPointCloudIndex *index = subidx.index();
402+
if ( index && index->isValid() && subidx.polygonBounds().intersects( profileCurveBbox ) )
403+
indexes.append( subidx.index() );
396404
}
397405

406+
if ( indexes.empty() )
407+
return false;
408+
398409
const double startDistanceOffset = std::max( !context.distanceRange().isInfinite() ? context.distanceRange().lower() : 0, 0.0 );
399410
const double endDistance = context.distanceRange().upper();
400411

@@ -433,9 +444,13 @@ bool QgsPointCloudLayerProfileGenerator::generateProfile( const QgsProfileGenera
433444
mSearchGeometryInLayerCrsGeometryEngine->prepareGeometry();
434445
mMaxSearchExtentInLayerCrs = mSearchGeometryInLayerCrs->boundingBox();
435446

436-
const IndexedPointCloudNode root = pc->root();
437-
438447
double maximumErrorPixels = context.convertDistanceToPixels( mMaximumScreenError, mMaximumScreenErrorUnit );
448+
if ( maximumErrorPixels < 0.0 )
449+
{
450+
QgsDebugError( QStringLiteral( "Invalid maximum error in pixels" ) );
451+
return false;
452+
}
453+
439454
const double toleranceInPixels = context.convertDistanceToPixels( mTolerance, Qgis::RenderUnit::MapUnits );
440455
// ensure that the maximum error is compatible with the tolerance size -- otherwise if the tolerance size
441456
// 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
444459
if ( toleranceInPixels / 4 < maximumErrorPixels )
445460
maximumErrorPixels = toleranceInPixels / 4;
446461

447-
const QgsRectangle rootNodeExtentLayerCoords = pc->nodeMapExtent( root );
448-
QgsRectangle rootNodeExtentInCurveCrs;
449-
try
450-
{
451-
QgsCoordinateTransform extentTransform = mLayerToTargetTransform;
452-
extentTransform.setBallparkTransformsAreAppropriate( true );
453-
rootNodeExtentInCurveCrs = extentTransform.transformBoundingBox( rootNodeExtentLayerCoords );
454-
}
455-
catch ( QgsCsException & )
456-
{
457-
QgsDebugError( QStringLiteral( "Could not transform node extent to curve CRS" ) );
458-
rootNodeExtentInCurveCrs = rootNodeExtentLayerCoords;
459-
}
460-
461-
const double rootErrorInMapCoordinates = rootNodeExtentInCurveCrs.width() / pc->span(); // in curve coords
462-
463-
const double mapUnitsPerPixel = context.mapUnitsPerDistancePixel();
464-
if ( ( rootErrorInMapCoordinates < 0.0 ) || ( mapUnitsPerPixel < 0.0 ) || ( maximumErrorPixels < 0.0 ) )
465-
{
466-
QgsDebugError( QStringLiteral( "invalid screen error" ) );
467-
return false;
468-
}
469-
double rootErrorPixels = rootErrorInMapCoordinates / mapUnitsPerPixel; // in pixels
470-
const QVector<IndexedPointCloudNode> nodes = traverseTree( pc, pc->root(), maximumErrorPixels, rootErrorPixels, context.elevationRange() );
471-
if ( nodes.empty() )
472-
{
473-
return false;
474-
}
475-
476-
const double rootErrorInLayerCoordinates = rootNodeExtentLayerCoords.width() / pc->span();
477-
const double maxErrorInMapCoordinates = maximumErrorPixels * mapUnitsPerPixel;
478-
479-
mResults = std::make_unique< QgsPointCloudLayerProfileResults >();
480-
mResults->copyPropertiesFromGenerator( this );
481-
mResults->mMaxErrorInLayerCoordinates = maxErrorInMapCoordinates * rootErrorInLayerCoordinates / rootErrorInMapCoordinates;
482-
483462
QgsPointCloudRequest request;
484463
QgsPointCloudAttributeCollection attributes;
485464
attributes.push_back( QgsPointCloudAttribute( QStringLiteral( "X" ), QgsPointCloudAttribute::Int32 ) );
@@ -515,22 +494,75 @@ bool QgsPointCloudLayerProfileGenerator::generateProfile( const QgsProfileGenera
515494

516495
request.setAttributes( attributes );
517496

518-
switch ( pc->accessType() )
497+
mResults = std::make_unique< QgsPointCloudLayerProfileResults >();
498+
mResults->copyPropertiesFromGenerator( this );
499+
mResults->mMaxErrorInLayerCoordinates = 0;
500+
501+
QgsCoordinateTransform extentTransform = mLayerToTargetTransform;
502+
extentTransform.setBallparkTransformsAreAppropriate( true );
503+
504+
const double mapUnitsPerPixel = context.mapUnitsPerDistancePixel();
505+
if ( mapUnitsPerPixel < 0.0 )
506+
{
507+
QgsDebugError( QStringLiteral( "Invalid map units per pixel ratio" ) );
508+
return false;
509+
}
510+
511+
for ( QgsPointCloudIndex *pc : std::as_const( indexes ) )
519512
{
520-
case QgsPointCloudIndex::AccessType::Local:
513+
const IndexedPointCloudNode root = pc->root();
514+
const QgsRectangle rootNodeExtentLayerCoords = pc->nodeMapExtent( root );
515+
QgsRectangle rootNodeExtentInCurveCrs;
516+
try
521517
{
522-
visitNodesSync( nodes, pc, request, context.elevationRange() );
523-
break;
518+
rootNodeExtentInCurveCrs = extentTransform.transformBoundingBox( rootNodeExtentLayerCoords );
524519
}
525-
case QgsPointCloudIndex::AccessType::Remote:
520+
catch ( QgsCsException & )
526521
{
527-
visitNodesAsync( nodes, pc, request, context.elevationRange() );
528-
break;
522+
QgsDebugError( QStringLiteral( "Could not transform node extent to curve CRS" ) );
523+
rootNodeExtentInCurveCrs = rootNodeExtentLayerCoords;
524+
}
525+
526+
const double rootErrorInMapCoordinates = rootNodeExtentInCurveCrs.width() / pc->span(); // in curve coords
527+
if ( rootErrorInMapCoordinates < 0.0 )
528+
{
529+
QgsDebugError( QStringLiteral( "Invalid root node error" ) );
530+
return false;
531+
}
532+
533+
double rootErrorPixels = rootErrorInMapCoordinates / mapUnitsPerPixel; // in pixels
534+
const QVector<IndexedPointCloudNode> nodes = traverseTree( pc, pc->root(), maximumErrorPixels, rootErrorPixels, context.elevationRange() );
535+
536+
const double rootErrorInLayerCoordinates = rootNodeExtentLayerCoords.width() / pc->span();
537+
const double maxErrorInMapCoordinates = maximumErrorPixels * mapUnitsPerPixel;
538+
539+
mResults->mMaxErrorInLayerCoordinates = std::max(
540+
mResults->mMaxErrorInLayerCoordinates,
541+
maxErrorInMapCoordinates * rootErrorInLayerCoordinates / rootErrorInMapCoordinates );
542+
543+
switch ( pc->accessType() )
544+
{
545+
case QgsPointCloudIndex::AccessType::Local:
546+
{
547+
visitNodesSync( nodes, pc, request, context.elevationRange() );
548+
break;
549+
}
550+
case QgsPointCloudIndex::AccessType::Remote:
551+
{
552+
visitNodesAsync( nodes, pc, request, context.elevationRange() );
553+
break;
554+
}
529555
}
556+
557+
if ( mFeedback->isCanceled() )
558+
return false;
530559
}
531560

532-
if ( mFeedback->isCanceled() )
561+
if ( mGatheredPoints.empty() )
562+
{
563+
mResults = nullptr;
533564
return false;
565+
}
534566

535567
// convert x/y values back to distance/height values
536568

0 commit comments

Comments
 (0)