@@ -389,12 +389,23 @@ bool QgsPointCloudLayerProfileGenerator::generateProfile( const QgsProfileGenera
389
389
// this is not AT ALL thread safe, but it's what QgsPointCloudLayerRenderer does !
390
390
// TODO: fix when QgsPointCloudLayerRenderer is made thread safe to use same approach
391
391
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 () )
394
400
{
395
- return false ;
401
+ QgsPointCloudIndex *index = subidx.index ();
402
+ if ( index && index ->isValid () && subidx.polygonBounds ().intersects ( profileCurveBbox ) )
403
+ indexes.append ( subidx.index () );
396
404
}
397
405
406
+ if ( indexes.empty () )
407
+ return false ;
408
+
398
409
const double startDistanceOffset = std::max ( !context.distanceRange ().isInfinite () ? context.distanceRange ().lower () : 0 , 0.0 );
399
410
const double endDistance = context.distanceRange ().upper ();
400
411
@@ -433,9 +444,13 @@ bool QgsPointCloudLayerProfileGenerator::generateProfile( const QgsProfileGenera
433
444
mSearchGeometryInLayerCrsGeometryEngine ->prepareGeometry ();
434
445
mMaxSearchExtentInLayerCrs = mSearchGeometryInLayerCrs ->boundingBox ();
435
446
436
- const IndexedPointCloudNode root = pc->root ();
437
-
438
447
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
+
439
454
const double toleranceInPixels = context.convertDistanceToPixels ( mTolerance , Qgis::RenderUnit::MapUnits );
440
455
// ensure that the maximum error is compatible with the tolerance size -- otherwise if the tolerance size
441
456
// 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
444
459
if ( toleranceInPixels / 4 < maximumErrorPixels )
445
460
maximumErrorPixels = toleranceInPixels / 4 ;
446
461
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
-
483
462
QgsPointCloudRequest request;
484
463
QgsPointCloudAttributeCollection attributes;
485
464
attributes.push_back ( QgsPointCloudAttribute ( QStringLiteral ( " X" ), QgsPointCloudAttribute::Int32 ) );
@@ -515,22 +494,75 @@ bool QgsPointCloudLayerProfileGenerator::generateProfile( const QgsProfileGenera
515
494
516
495
request.setAttributes ( attributes );
517
496
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 ) )
519
512
{
520
- case QgsPointCloudIndex::AccessType::Local:
513
+ const IndexedPointCloudNode root = pc->root ();
514
+ const QgsRectangle rootNodeExtentLayerCoords = pc->nodeMapExtent ( root );
515
+ QgsRectangle rootNodeExtentInCurveCrs;
516
+ try
521
517
{
522
- visitNodesSync ( nodes, pc, request, context.elevationRange () );
523
- break ;
518
+ rootNodeExtentInCurveCrs = extentTransform.transformBoundingBox ( rootNodeExtentLayerCoords );
524
519
}
525
- case QgsPointCloudIndex::AccessType::Remote:
520
+ catch ( QgsCsException & )
526
521
{
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
+ }
529
555
}
556
+
557
+ if ( mFeedback ->isCanceled () )
558
+ return false ;
530
559
}
531
560
532
- if ( mFeedback ->isCanceled () )
561
+ if ( mGatheredPoints .empty () )
562
+ {
563
+ mResults = nullptr ;
533
564
return false ;
565
+ }
534
566
535
567
// convert x/y values back to distance/height values
536
568
0 commit comments