46 mPointIndex =
nullptr;
53 const std::size_t size =
results.size();
55 for ( std::size_t i = 0; i < size; ++i, ++pointData )
60 #if GEOS_VERSION_MAJOR>3 || GEOS_VERSION_MINOR>=8
63 GEOSCoordSequence *seq = GEOSCoordSeq_create_r( geosctxt, 1, 2 );
64 GEOSCoordSeq_setX_r( geosctxt, seq, 0, point.distanceAlongCurve );
65 GEOSCoordSeq_setY_r( geosctxt, seq, 0, point.z );
69 GEOSSTRtree_insert_r( geosctxt, mPointIndex, geosPoint.get(), pointData );
71 #if GEOS_VERSION_MAJOR<4 && GEOS_VERSION_MINOR<9
72 mSTRTreeItems.emplace_back( std::move( geosPoint ) );
79 return QStringLiteral(
"pointcloud" );
85 QMap< double, double > res;
88 res.insert( point.distanceAlongCurve, point.z );
100 res.append(
QgsPoint( point.x, point.y, point.z ) );
108 QVector< QgsGeometry > res;
130 painter->setBrush( Qt::NoBrush );
131 painter->setPen( Qt::NoPen );
149 const QRectF visibleRegion( minDistance,
minZ, maxDistance - minDistance,
maxZ -
minZ );
150 QPainterPath clipPath;
151 clipPath.addPolygon( context.
worldTransform().map( visibleRegion ) );
152 painter->setClipPath( clipPath, Qt::ClipOperation::IntersectClip );
158 QPointF p = context.
worldTransform().map( QPointF( point.distanceAlongCurve, point.z ) );
161 color.setAlphaF( color.alphaF() * ( 1.0 - std::pow( point.distanceFromCurve /
tolerance, 0.5 ) ) );
166 painter->fillRect( QRectF( p.x() - penWidth * 0.5,
167 p.y() - penWidth * 0.5,
168 penWidth, penWidth ), color );
172 painter->setBrush( QBrush( color ) );
173 painter->setPen( Qt::NoPen );
174 painter->drawEllipse( QRectF( p.x() - penWidth * 0.5,
175 p.y() - penWidth * 0.5,
176 penWidth, penWidth ) );
184 QList< const QgsPointCloudLayerProfileResults::PointResult * > *
list;
202 GEOSCoordSequence *coord = GEOSCoordSeq_create_r( geosctxt, 2, 2 );
203 #if GEOS_VERSION_MAJOR<4 && GEOS_VERSION_MINOR<9
204 GEOSCoordSeq_setXY_r( geosctxt, coord, 0, minDistance, minElevation );
205 GEOSCoordSeq_setXY_r( geosctxt, coord, 1, maxDistance, maxElevation );
207 GEOSCoordSeq_setX_r( geosctxt, coord, 0, minDistance );
208 GEOSCoordSeq_setY_r( geosctxt, coord, 0, minElevation );
209 GEOSCoordSeq_setX_r( geosctxt, coord, 1, maxDistance );
210 GEOSCoordSeq_setY_r( geosctxt, coord, 1, maxElevation );
212 geos::unique_ptr searchDiagonal( GEOSGeom_createLineString_r( geosctxt, coord ) );
214 QList<const PointResult *> items;
216 callbackData.
list = &items;
217 GEOSSTRtree_query_r( geosctxt, mPointIndex, searchDiagonal.get(),
_GEOSQueryCallback, &callbackData );
221 double bestMatchDistance = std::numeric_limits< double >::max();
223 for (
const PointResult *candidate : std::as_const( items ) )
225 const double distance = std::sqrt( std::pow( candidate->distanceAlongCurve - point.
distance(), 2 )
227 if ( distance < bestMatchDistance )
229 bestMatchDistance = distance;
230 bestMatch = candidate;
251 std::unique_ptr< QgsCurve > substring( mProfileCurve->curveSubstring( distanceRange.
lower(), distanceRange.
upper() ) );
252 QgsGeos substringGeos( substring.get() );
253 std::unique_ptr< QgsAbstractGeometry > searchGeometry( substringGeos.
buffer( mTolerance, 8, Qgis::EndCapStyle::Flat, Qgis::JoinStyle::Round, 2 ) );
254 if ( !searchGeometry )
260 searchGeometry->transform( curveToLayerTransform );
268 const QgsDoubleRange providerElevationRange( ( elevationRange.
lower() - mZOffset ) / mZScale, ( elevationRange.
upper() - mZOffset ) / mZScale );
270 const QgsGeometry pointCloudSearchGeometry( std::move( searchGeometry ) );
271 const QVector<QVariantMap> pointAttributes = mLayer->dataProvider()->identify( mMaxErrorInLayerCoordinates, pointCloudSearchGeometry, providerElevationRange );
272 if ( pointAttributes.empty() )
289 mLayer = pcGenerator->mLayer;
290 mCurveCrs = pcGenerator->mTargetCrs;
291 mProfileCurve.reset( pcGenerator->mProfileCurve->clone() );
292 mTolerance = pcGenerator->mTolerance;
294 mZOffset = pcGenerator->mZOffset;
295 mZScale = pcGenerator->mZScale;
304 , mLayerAttributes( layer->attributes() )
305 , mRenderer( qgis::down_cast<
QgsPointCloudLayerElevationProperties* >( layer->elevationProperties() )->respectLayerColors() && mLayer->renderer() ? mLayer->renderer()->clone() : nullptr )
315 , mProfileCurve( request.profileCurve() ? request.profileCurve()->clone() : nullptr )
316 , mTolerance( request.tolerance() )
317 , mSourceCrs( layer->
crs() )
318 , mTargetCrs( request.
crs() )
319 , mTransformContext( request.transformContext() )
320 , mZOffset( layer->elevationProperties()->zOffset() )
321 , mZScale( layer->elevationProperties()->zScale() )
322 , mStepDistance( request.stepDistance() )
324 if ( mLayer->dataProvider()->index() )
326 mScale = mLayer->dataProvider()->index()->scale();
327 mOffset = mLayer->dataProvider()->index()->offset();
345 mGatheredPoints.clear();
346 if ( !mLayer || !mProfileCurve || mFeedback->isCanceled() )
361 std::unique_ptr< QgsCurve > trimmedCurve;
363 if ( startDistanceOffset > 0 || endDistance < mProfileCurve->length() )
365 trimmedCurve.reset( mProfileCurve->curveSubstring( startDistanceOffset, endDistance ) );
366 sourceCurve = trimmedCurve.get();
370 sourceCurve = mProfileCurve.get();
374 QgsGeos originalCurveGeos( sourceCurve );
376 mSearchGeometryInLayerCrs.reset( originalCurveGeos.
buffer( mTolerance, 8, Qgis::EndCapStyle::Flat, Qgis::JoinStyle::Round, 2 ) );
381 mSearchGeometryInLayerCrs->transform( mLayerToTargetTransform, Qgis::TransformDirection::Reverse );
385 QgsDebugMsg( QStringLiteral(
"Error transforming profile line to layer CRS" ) );
389 if ( mFeedback->isCanceled() )
392 mSearchGeometryInLayerCrsGeometryEngine = std::make_unique< QgsGeos >( mSearchGeometryInLayerCrs.get() );
393 mSearchGeometryInLayerCrsGeometryEngine->prepareGeometry();
394 mMaxSearchExtentInLayerCrs = mSearchGeometryInLayerCrs->boundingBox();
404 if ( toleranceInPixels / 4 < maximumErrorPixels )
405 maximumErrorPixels = toleranceInPixels / 4;
417 QgsDebugMsg( QStringLiteral(
"Could not transform node extent to curve CRS" ) );
418 rootNodeExtentInCurveCrs = rootNodeExtentLayerCoords;
421 const double rootErrorInMapCoordinates = rootNodeExtentInCurveCrs.
width() / pc->
span();
424 if ( ( rootErrorInMapCoordinates < 0.0 ) || ( mapUnitsPerPixel < 0.0 ) || ( maximumErrorPixels < 0.0 ) )
426 QgsDebugMsg( QStringLiteral(
"invalid screen error" ) );
429 double rootErrorPixels = rootErrorInMapCoordinates / mapUnitsPerPixel;
430 const QVector<IndexedPointCloudNode> nodes = traverseTree( pc, pc->
root(), maximumErrorPixels, rootErrorPixels, context.
elevationRange() );
432 const double rootErrorInLayerCoordinates = rootNodeExtentLayerCoords.
width() / pc->
span();
433 const double maxErrorInMapCoordinates = maximumErrorPixels * mapUnitsPerPixel;
435 mResults = std::make_unique< QgsPointCloudLayerProfileResults >();
436 mResults->copyPropertiesFromGenerator(
this );
437 mResults->mMaxErrorInLayerCoordinates = maxErrorInMapCoordinates * rootErrorInLayerCoordinates / rootErrorInMapCoordinates;
447 mPreparedRendererData = mRenderer->prepare();
448 if ( mPreparedRendererData )
450 const QSet< QString > rendererAttributes = mPreparedRendererData->usedAttributes();
451 for (
const QString &attribute : std::as_const( rendererAttributes ) )
453 if ( attributes.
indexOf( attribute ) >= 0 )
456 const int layerIndex = mLayerAttributes.
indexOf( attribute );
457 if ( layerIndex < 0 )
459 QgsMessageLog::logMessage( QObject::tr(
"Required attribute %1 not found in layer" ).arg( attribute ), QObject::tr(
"Point Cloud" ) );
463 attributes.
push_back( mLayerAttributes.
at( layerIndex ) );
469 mPreparedRendererData.reset();
476 case QgsPointCloudIndex::AccessType::Local:
481 case QgsPointCloudIndex::AccessType::Remote:
488 if ( mFeedback->isCanceled() )
495 const int size = mGatheredPoints.size();
496 mResults->results.resize( size );
498 for (
int i = 0; i < size; ++i, ++pointData, ++destData )
500 if ( mFeedback->isCanceled() )
503 *destData = *pointData;
505 if ( mOpacityByDistanceEffect )
508 mResults->minZ = std::min( destData->
z, mResults->minZ );
509 mResults->maxZ = std::max( destData->
z, mResults->maxZ );
511 mResults->finalize( mFeedback.get() );
518 return mResults.release();
523 return mFeedback.get();
528 QVector<IndexedPointCloudNode> nodes;
530 if ( mFeedback->isCanceled() )
541 if ( !mMaxSearchExtentInLayerCrs.
intersects( nodeMapExtent ) )
545 if ( !mSearchGeometryInLayerCrsGeometryEngine->intersects( nodeMapGeometry.
constGet() ) )
550 double childrenErrorPixels = nodeErrorPixels / 2.0;
551 if ( childrenErrorPixels < maxErrorPixels )
554 const QList<IndexedPointCloudNode> children = pc->
nodeChildren( n );
557 nodes += traverseTree( pc, nn, maxErrorPixels, childrenErrorPixels, zRange );
568 if ( mFeedback->isCanceled() )
571 std::unique_ptr<QgsPointCloudBlock> block( pc->
nodeData( n, request ) );
576 visitBlock( block.get(), zRange );
590 QVector<QgsPointCloudBlockRequest *> blockRequests;
594 for (
int i = 0; i < nodes.size(); ++i )
599 blockRequests.append( blockRequest );
601 [
this, &nodesDrawn, &loop, &blockRequests, &zRange, nStr, blockRequest ]()
603 blockRequests.removeOne( blockRequest );
606 if ( blockRequests.isEmpty() )
609 std::unique_ptr<QgsPointCloudBlock> block( blockRequest->
block() );
611 blockRequest->deleteLater();
613 if ( mFeedback->isCanceled() )
620 QgsDebugMsg( QStringLiteral(
"Unable to load node %1, error: %2" ).arg( nStr, blockRequest->
errorStr() ) );
624 visitBlock( block.get(), zRange );
636 delete blockRequest->
block();
637 blockRequest->deleteLater();
645 const char *ptr = block->
data();
653 int xOffset = 0, yOffset = 0, zOffset = 0;
658 bool useRenderer =
false;
659 if ( mPreparedRendererData )
661 useRenderer = mPreparedRendererData->prepareBlock( block );
666 for (
int i = 0; i < count; ++i )
668 if ( mFeedback->isCanceled() )
674 QgsPointCloudAttribute::getPointXYZ( ptr, i, recordSize, xOffset, xType, yOffset, yType, zOffset, zType, block->
scale(), block->
offset(), res.
x, res.
y, res.
z );
676 res.
z = res.
z * mZScale + mZOffset;
682 color = mPreparedRendererData->pointColor( block, i, res.
z );
683 if ( !color.isValid() )
686 res.
color = color.rgba();
690 res.
color = mPointColor.rgba();
693 if ( mSearchGeometryInLayerCrsGeometryEngine->contains( res.
x, res.
y ) )
707 mGatheredPoints.append( res );