38 return QStringLiteral(
"raster" );
46 QVector<QgsProfileIdentifyResults> res;
47 res.reserve( noLayerResults.size() );
64 , mProfileCurve( request.profileCurve() ? request.profileCurve()->clone() : nullptr )
65 , mSourceCrs( layer->
crs() )
66 , mTargetCrs( request.
crs() )
67 , mTransformContext( request.transformContext() )
68 , mOffset( layer->elevationProperties()->zOffset() )
69 , mScale( layer->elevationProperties()->zScale() )
72 , mRasterUnitsPerPixelX( layer->rasterUnitsPerPixelX() )
73 , mRasterUnitsPerPixelY( layer->rasterUnitsPerPixelY() )
74 , mStepDistance( request.stepDistance() )
97 if ( !mProfileCurve || mFeedback->isCanceled() )
103 std::unique_ptr< QgsCurve > trimmedCurve;
105 if ( startDistanceOffset > 0 || endDistance < mProfileCurve->length() )
107 trimmedCurve.reset( mProfileCurve->curveSubstring( startDistanceOffset, endDistance ) );
108 sourceCurve = trimmedCurve.get();
112 sourceCurve = mProfileCurve.get();
116 std::unique_ptr< QgsCurve > transformedCurve( sourceCurve->
clone() );
120 transformedCurve->transform( rasterToTargetTransform, Qgis::TransformDirection::Reverse );
124 QgsDebugMsg( QStringLiteral(
"Error transforming profile line to raster CRS" ) );
128 if ( mFeedback->isCanceled() )
131 const QgsRectangle profileCurveBoundingBox = transformedCurve->boundingBox();
132 if ( !profileCurveBoundingBox.
intersects( mRasterProvider->extent() ) )
135 if ( mFeedback->isCanceled() )
138 mResults = std::make_unique< QgsRasterLayerProfileResults >();
139 mResults->mLayer = mLayer;
140 mResults->copyPropertiesFromGenerator(
this );
143 curveEngine->prepareGeometry();
145 if ( mFeedback->isCanceled() )
148 double stepDistance = mStepDistance;
159 QSet< QgsPointXY > profilePoints;
160 if ( !std::isnan( stepDistance ) )
165 densifiedCurve.
transform( rasterToTargetTransform, Qgis::TransformDirection::Reverse );
169 profilePoints.insert( *it );
173 if ( mFeedback->isCanceled() )
177 int subRegionWidth = 0;
178 int subRegionHeight = 0;
179 int subRegionLeft = 0;
180 int subRegionTop = 0;
181 const QgsRectangle rasterSubRegion = mRasterProvider->xSize() > 0 && mRasterProvider->ySize() > 0 ?
183 mRasterProvider->extent(),
184 mRasterProvider->xSize(),
185 mRasterProvider->ySize(),
186 transformedCurve->boundingBox(),
190 subRegionTop ) : transformedCurve->boundingBox();
192 if ( mRasterProvider->xSize() == 0 || mRasterProvider->ySize() == 0 )
197 const double conversionFactor = curveLengthInPixels / transformedCurve->length();
198 subRegionWidth = 2 * conversionFactor * rasterSubRegion.
width();
199 subRegionHeight = 2 * conversionFactor * rasterSubRegion.
height();
210 it.
startRasterRead( mBand, subRegionWidth, subRegionHeight, rasterSubRegion );
212 const double halfPixelSizeX = mRasterUnitsPerPixelX / 2.0;
213 const double halfPixelSizeY = mRasterUnitsPerPixelY / 2.0;
214 int blockColumns = 0;
216 int blockTopLeftColumn = 0;
217 int blockTopLeftRow = 0;
220 while ( it.
next( mBand, blockColumns, blockRows, blockTopLeftColumn, blockTopLeftRow, blockExtent ) )
222 if ( mFeedback->isCanceled() )
226 if ( !curveEngine->intersects( blockExtentGeom.
constGet() ) )
229 std::unique_ptr< QgsRasterBlock > block( mRasterProvider->block( mBand, blockExtent, blockColumns, blockRows, mFeedback.get() ) );
230 if ( mFeedback->isCanceled() )
236 bool isNoData =
false;
240 if ( !std::isnan( stepDistance ) )
242 auto it = profilePoints.begin();
243 while ( it != profilePoints.end() )
245 if ( mFeedback->isCanceled() )
251 const int row = std::clamp(
static_cast< int >( std::round( ( blockExtent.
yMaximum() - it->y() ) / mRasterUnitsPerPixelY ) ), 0, blockRows - 1 );
252 const int col = std::clamp(
static_cast< int >( std::round( ( it->x() - blockExtent.
xMinimum() ) / mRasterUnitsPerPixelX ) ), 0, blockColumns - 1 );
253 double val = block->valueAndNoData( row, col, isNoData );
256 val = val * mScale + mOffset;
260 val = std::numeric_limits<double>::quiet_NaN();
263 QgsPoint pixel( it->x(), it->y(), val );
266 pixel.
transform( rasterToTargetTransform );
272 mResults->mRawPoints.append( pixel );
274 it = profilePoints.erase( it );
282 if ( profilePoints.isEmpty() )
287 double currentY = blockExtent.
yMaximum() - 0.5 * mRasterUnitsPerPixelY;
288 for (
int row = 0; row < blockRows; ++row )
290 if ( mFeedback->isCanceled() )
293 double currentX = blockExtent.
xMinimum() + 0.5 * mRasterUnitsPerPixelX;
294 for (
int col = 0; col < blockColumns; ++col, currentX += mRasterUnitsPerPixelX )
296 const double val = block->valueAndNoData( row, col, isNoData );
300 currentY - halfPixelSizeY,
301 currentX + halfPixelSizeX,
302 currentY + halfPixelSizeY ) );
303 if ( !curveEngine->intersects( pixelRectGeometry.
constGet() ) )
306 QgsPoint pixel( currentX, currentY, isNoData ? std::numeric_limits<double>::quiet_NaN() : val * mScale + mOffset );
309 pixel.
transform( rasterToTargetTransform );
315 mResults->mRawPoints.append( pixel );
317 currentY -= mRasterUnitsPerPixelY;
322 if ( mFeedback->isCanceled() )
326 QgsGeos originalCurveGeos( sourceCurve );
329 for (
const QgsPoint &pixel : std::as_const( mResults->mRawPoints ) )
331 if ( mFeedback->isCanceled() )
334 const double distance = originalCurveGeos.
lineLocatePoint( pixel, &lastError ) + startDistanceOffset;
336 if ( !std::isnan( pixel.z() ) )
338 mResults->minZ = std::min( pixel.z(), mResults->minZ );
339 mResults->maxZ = std::max( pixel.z(), mResults->maxZ );
341 mResults->mDistanceToHeightMap.insert( distance, pixel.z() );
349 return mResults.release();
354 return mFeedback.get();