QGIS API Documentation 3.43.0-Master (a93bf8b6462)
qgsrasterlayerrenderer.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgsrasterlayerrenderer.cpp
3 --------------------------------------
4 Date : December 2013
5 Copyright : (C) 2013 by Martin Dobias
6 Email : wonder dot sk at gmail dot com
7 ***************************************************************************
8 * *
9 * This program is free software; you can redistribute it and/or modify *
10 * it under the terms of the GNU General Public License as published by *
11 * the Free Software Foundation; either version 2 of the License, or *
12 * (at your option) any later version. *
13 * *
14 ***************************************************************************/
15
17#include "moc_qgsrasterlayerrenderer.cpp"
18
19#include "qgsmessagelog.h"
21#include "qgsrasterdrawer.h"
22#include "qgsrasteriterator.h"
23#include "qgsrasterlayer.h"
24#include "qgsrasterprojector.h"
25#include "qgsrendercontext.h"
26#include "qgsrasterrenderer.h"
27#include "qgsexception.h"
29#include "qgsmapclippingutils.h"
30#include "qgsrasterpipe.h"
31#include "qgselevationmap.h"
32#include "qgsgdalutils.h"
35#include "qgsruntimeprofiler.h"
36#include "qgsapplication.h"
38#include "qgsrasterlayerutils.h"
39#include "qgsinterval.h"
40#include "qgsunittypes.h"
41#include "qgsrasternuller.h"
43#include "qgsrasterlabeling.h"
44
45#include <QElapsedTimer>
46#include <QPointer>
47#include <QThread>
48
50
51QgsRasterLayerRendererFeedback::QgsRasterLayerRendererFeedback( QgsRasterLayerRenderer *r )
52 : mR( r )
53 , mMinimalPreviewInterval( 250 )
54{
56}
57
58void QgsRasterLayerRendererFeedback::onNewData()
59{
60 if ( !renderPartialOutput() )
61 return; // we were not asked for partial renders and we may not have a temporary image for overwriting...
62
63 // update only once upon a time
64 // (preview itself takes some time)
65 if ( mLastPreview.isValid() && mLastPreview.msecsTo( QTime::currentTime() ) < mMinimalPreviewInterval )
66 return;
67
68 // TODO: update only the area that got new data
69
70 QgsDebugMsgLevel( QStringLiteral( "new raster preview! %1" ).arg( mLastPreview.msecsTo( QTime::currentTime() ) ), 3 );
71 QElapsedTimer t;
72 t.start();
74 feedback.setPreviewOnly( true );
75 feedback.setRenderPartialOutput( true );
76 QgsRasterIterator iterator( mR->mPipe->last() );
77 QgsRasterDrawer drawer( &iterator );
78 drawer.draw( *( mR->renderContext() ), mR->mRasterViewPort, &feedback );
79 mR->mReadyToCompose = true;
80 QgsDebugMsgLevel( QStringLiteral( "total raster preview time: %1 ms" ).arg( t.elapsed() ), 3 );
81 mLastPreview = QTime::currentTime();
82}
83
87 : QgsMapLayerRenderer( layer->id(), &rendererContext )
88 , mLayerName( layer->name() )
89 , mLayerOpacity( layer->opacity() )
90 , mProviderCapabilities( layer->dataProvider()->providerCapabilities() )
91 , mInterfaceCapabilities( layer->dataProvider()->capabilities() )
92 , mFeedback( new QgsRasterLayerRendererFeedback( this ) )
93 , mEnableProfile( rendererContext.flags() & Qgis::RenderContextFlag::RecordProfile )
94{
95 mReadyToCompose = false;
96
97 QElapsedTimer timer;
98 timer.start();
99
100 QgsMapToPixel mapToPixel = rendererContext.mapToPixel();
101 if ( rendererContext.mapToPixel().mapRotation() )
102 {
103 // unset rotation for the sake of local computations.
104 // Rotation will be handled by QPainter later
105 // TODO: provide a method of QgsMapToPixel to fetch map center
106 // in geographical units
107 const QgsPointXY center = mapToPixel.toMapCoordinates(
108 static_cast<int>( mapToPixel.mapWidth() / 2.0 ),
109 static_cast<int>( mapToPixel.mapHeight() / 2.0 )
110 );
111 mapToPixel.setMapRotation( 0, center.x(), center.y() );
112 }
113
114 QgsRectangle viewExtentInMapCrs;
115 QgsRectangle layerExtentInMapCrs;
116
117 if ( rendererContext.coordinateTransform().isValid() )
118 {
119 QgsDebugMsgLevel( QStringLiteral( "coordinateTransform set -> project extents." ), 4 );
120 if ( rendererContext.extent().xMinimum() == std::numeric_limits<double>::lowest() &&
121 rendererContext.extent().yMinimum() == std::numeric_limits<double>::lowest() &&
122 rendererContext.extent().xMaximum() == std::numeric_limits<double>::max() &&
123 rendererContext.extent().yMaximum() == std::numeric_limits<double>::max() )
124 {
125 // We get in this situation if the view CRS is geographical and the
126 // extent goes beyond -180,-90,180,90. To avoid reprojection issues to the
127 // layer CRS, then this dummy extent is returned by QgsMapRendererJob::reprojectToLayerExtent()
128 // Don't try to reproject it now to view extent as this would return
129 // a null rectangle.
130 viewExtentInMapCrs = rendererContext.extent();
131 }
132 else
133 {
134 try
135 {
136 QgsCoordinateTransform ct = rendererContext.coordinateTransform();
138 viewExtentInMapCrs = rendererContext.mapExtent();
139 }
140 catch ( QgsCsException &cs )
141 {
142 QgsMessageLog::logMessage( QObject::tr( "Could not reproject view extent: %1" ).arg( cs.what() ), QObject::tr( "Raster" ) );
143 viewExtentInMapCrs.setNull();
144 }
145 }
146
147 try
148 {
149 QgsCoordinateTransform ct = rendererContext.coordinateTransform();
151 layerExtentInMapCrs = ct.transformBoundingBox( layer->extent() );
152 }
153 catch ( QgsCsException &cs )
154 {
155 QgsMessageLog::logMessage( QObject::tr( "Could not reproject layer extent: %1" ).arg( cs.what() ), QObject::tr( "Raster" ) );
156 layerExtentInMapCrs.setNull();
157 }
158 }
159 else
160 {
161 QgsDebugMsgLevel( QStringLiteral( "coordinateTransform not set" ), 4 );
162 viewExtentInMapCrs = rendererContext.extent();
163 layerExtentInMapCrs = layer->extent();
164 }
165
166 // clip raster extent to view extent
167 QgsRectangle visibleExtentOfRasterInMapCrs = layer->ignoreExtents() ? viewExtentInMapCrs : viewExtentInMapCrs.intersect( layerExtentInMapCrs );
168 if ( visibleExtentOfRasterInMapCrs.isEmpty() )
169 {
170 if ( rendererContext.coordinateTransform().isShortCircuited() )
171 {
172 // no point doing the fallback logic, we aren't using transforms
173
174 QgsDebugMsgLevel( QStringLiteral( "draw request outside view extent." ), 2 );
175 // nothing to do
176 return;
177 }
178
179 // fallback logic, try the inverse operation
180 // eg if we are trying to view a global layer in a small area local projection, then the transform of the
181 // map extent to the layer's local projection probably failed.
182 // So we'll try the opposite logic here, and see if we can first calculate the visible region in the
183 // layers extent, and then transform that small region back to the map's crs
184 try
185 {
186 QgsCoordinateTransform layerToMapTransform = rendererContext.coordinateTransform();
187 layerToMapTransform.setBallparkTransformsAreAppropriate( true );
188 const QgsRectangle viewExtentInLayerCrs = layerToMapTransform.transformBoundingBox( rendererContext.mapExtent(), Qgis::TransformDirection::Reverse );
189
190 const QgsRectangle visibleExtentInLayerCrs = layer->ignoreExtents() ? viewExtentInLayerCrs : viewExtentInLayerCrs.intersect( layer->extent() );
191 if ( visibleExtentInLayerCrs.isEmpty() )
192 {
193 QgsDebugMsgLevel( QStringLiteral( "draw request outside view extent." ), 2 );
194 // nothing to do
195 return;
196 }
197
198 visibleExtentOfRasterInMapCrs = layerToMapTransform.transformBoundingBox( visibleExtentInLayerCrs );
199 }
200 catch ( QgsCsException &cs )
201 {
202 QgsMessageLog::logMessage( QObject::tr( "Could not reproject layer extent: %1" ).arg( cs.what() ), QObject::tr( "Raster" ) );
203 return;
204 }
205 }
206
207 if ( visibleExtentOfRasterInMapCrs.isEmpty() )
208 {
209 QgsDebugMsgLevel( QStringLiteral( "draw request outside view extent." ), 2 );
210 // nothing to do
211 return;
212 }
213
214 QgsDebugMsgLevel( "map extent in layer crs is " + rendererContext.extent().toString(), 4 );
215 QgsDebugMsgLevel( "map extent in map crs is " + viewExtentInMapCrs.toString(), 4 );
216 QgsDebugMsgLevel( "layer extent in map crs is " + layerExtentInMapCrs.toString(), 4 );
217 QgsDebugMsgLevel( "visible extent of raster in map crs is " + visibleExtentOfRasterInMapCrs.toString(), 4 );
218
219 //
220 // The first thing we do is set up the QgsRasterViewPort. This struct stores all the settings
221 // relating to the size (in pixels and coordinate system units) of the raster part that is
222 // in view in the map window. It also stores the origin.
223 //
224 //this is not a class level member because every time the user pans or zooms
225 //the contents of the rasterViewPort will change
226 mRasterViewPort = new QgsRasterViewPort();
227
228 mRasterViewPort->mDrawnExtent = visibleExtentOfRasterInMapCrs;
229 if ( rendererContext.coordinateTransform().isValid() )
230 {
231 mRasterViewPort->mSrcCRS = layer->crs();
232 mRasterViewPort->mDestCRS = rendererContext.coordinateTransform().destinationCrs();
233 mRasterViewPort->mTransformContext = rendererContext.transformContext();
234 }
235 else
236 {
237 mRasterViewPort->mSrcCRS = QgsCoordinateReferenceSystem(); // will be invalid
238 mRasterViewPort->mDestCRS = QgsCoordinateReferenceSystem(); // will be invalid
239 }
240
241 // get dimensions of clipped raster image in device coordinate space (this is the size of the viewport)
242 mRasterViewPort->mTopLeftPoint = mapToPixel.transform( visibleExtentOfRasterInMapCrs.xMinimum(), visibleExtentOfRasterInMapCrs.yMaximum() );
243 mRasterViewPort->mBottomRightPoint = mapToPixel.transform( visibleExtentOfRasterInMapCrs.xMaximum(), visibleExtentOfRasterInMapCrs.yMinimum() );
244
245 // align to output device grid, i.e. std::floor/ceil to integers
246 // TODO: this should only be done if paint device is raster - screen, image
247 // for other devices (pdf) it can have floating point origin
248 // we could use floating point for raster devices as well, but respecting the
249 // output device grid should make it more effective as the resampling is done in
250 // the provider anyway
251 mRasterViewPort->mTopLeftPoint.setX( std::floor( mRasterViewPort->mTopLeftPoint.x() ) );
252 mRasterViewPort->mTopLeftPoint.setY( std::floor( mRasterViewPort->mTopLeftPoint.y() ) );
253 mRasterViewPort->mBottomRightPoint.setX( std::ceil( mRasterViewPort->mBottomRightPoint.x() ) );
254 mRasterViewPort->mBottomRightPoint.setY( std::ceil( mRasterViewPort->mBottomRightPoint.y() ) );
255 // recalc myRasterExtent to aligned values
256 visibleExtentOfRasterInMapCrs.set(
257 mapToPixel.toMapCoordinates( mRasterViewPort->mTopLeftPoint.x(),
258 mRasterViewPort->mBottomRightPoint.y() ),
259 mapToPixel.toMapCoordinates( mRasterViewPort->mBottomRightPoint.x(),
260 mRasterViewPort->mTopLeftPoint.y() )
261 );
262
263 //raster viewport top left / bottom right are already rounded to int
264 mRasterViewPort->mWidth = static_cast<qgssize>( std::abs( mRasterViewPort->mBottomRightPoint.x() - mRasterViewPort->mTopLeftPoint.x() ) );
265 mRasterViewPort->mHeight = static_cast<qgssize>( std::abs( mRasterViewPort->mBottomRightPoint.y() - mRasterViewPort->mTopLeftPoint.y() ) );
266
267 double dpi = 25.4 * rendererContext.scaleFactor();
268 if ( mProviderCapabilities & Qgis::RasterProviderCapability::DpiDependentData
269 && rendererContext.dpiTarget() >= 0.0 )
270 {
271 const double dpiScaleFactor = rendererContext.dpiTarget() / dpi;
272 mRasterViewPort->mWidth *= dpiScaleFactor;
273 mRasterViewPort->mHeight *= dpiScaleFactor;
274 dpi = rendererContext.dpiTarget();
275 }
276 else
277 {
278 rendererContext.setDpiTarget( -1.0 );
279 }
280
281 //the drawable area can start to get very very large when you get down displaying 2x2 or smaller, this is because
282 //mapToPixel.mapUnitsPerPixel() is less then 1,
283 //so we will just get the pixel data and then render these special cases differently in paintImageToCanvas()
284
285 QgsDebugMsgLevel( QStringLiteral( "mapUnitsPerPixel = %1" ).arg( mapToPixel.mapUnitsPerPixel() ), 3 );
286 QgsDebugMsgLevel( QStringLiteral( "mWidth = %1" ).arg( layer->width() ), 3 );
287 QgsDebugMsgLevel( QStringLiteral( "mHeight = %1" ).arg( layer->height() ), 3 );
288 QgsDebugMsgLevel( QStringLiteral( "visibleExtentOfRasterInMapCrs.xMinimum() = %1" ).arg( visibleExtentOfRasterInMapCrs.xMinimum() ), 3 );
289 QgsDebugMsgLevel( QStringLiteral( "visibleExtentOfRasterInMapCrs.xMaximum() = %1" ).arg( visibleExtentOfRasterInMapCrs.xMaximum() ), 3 );
290 QgsDebugMsgLevel( QStringLiteral( "visibleExtentOfRasterInMapCrs.yMinimum() = %1" ).arg( visibleExtentOfRasterInMapCrs.yMinimum() ), 3 );
291 QgsDebugMsgLevel( QStringLiteral( "visibleExtentOfRasterInMapCrs.yMaximum() = %1" ).arg( visibleExtentOfRasterInMapCrs.yMaximum() ), 3 );
292
293 QgsDebugMsgLevel( QStringLiteral( "mTopLeftPoint.x() = %1" ).arg( mRasterViewPort->mTopLeftPoint.x() ), 3 );
294 QgsDebugMsgLevel( QStringLiteral( "mBottomRightPoint.x() = %1" ).arg( mRasterViewPort->mBottomRightPoint.x() ), 3 );
295 QgsDebugMsgLevel( QStringLiteral( "mTopLeftPoint.y() = %1" ).arg( mRasterViewPort->mTopLeftPoint.y() ), 3 );
296 QgsDebugMsgLevel( QStringLiteral( "mBottomRightPoint.y() = %1" ).arg( mRasterViewPort->mBottomRightPoint.y() ), 3 );
297
298 QgsDebugMsgLevel( QStringLiteral( "mWidth = %1" ).arg( mRasterViewPort->mWidth ), 3 );
299 QgsDebugMsgLevel( QStringLiteral( "mHeight = %1" ).arg( mRasterViewPort->mHeight ), 3 );
300
301 // /\/\/\ - added to handle zoomed-in rasters
302
303 // TODO R->mLastViewPort = *mRasterViewPort;
304
305 // TODO: is it necessary? Probably WMS only?
306 layer->dataProvider()->setDpi( std::floor( dpi * rendererContext.devicePixelRatio() ) );
307
308 // copy the whole raster pipe!
309 mPipe.reset( new QgsRasterPipe( *layer->pipe() ) );
310
311 QObject::connect( mPipe->provider(), &QgsRasterDataProvider::statusChanged, layer, &QgsRasterLayer::statusChanged );
312 QgsRasterRenderer *rasterRenderer = mPipe->renderer();
313 if ( rasterRenderer
314 && !( rendererContext.flags() & Qgis::RenderContextFlag::RenderPreviewJob )
315 && !( rendererContext.flags() & Qgis::RenderContextFlag::Render3DMap ) )
316 {
317 if ( rasterRenderer->needsRefresh( rendererContext.extent() ) )
318 {
319 QList<double> minValues;
320 QList<double> maxValues;
321 const QgsRasterMinMaxOrigin &minMaxOrigin = rasterRenderer->minMaxOrigin();
322 for ( const int bandIdx : rasterRenderer->usesBands() )
323 {
324 double min;
325 double max;
326 layer->computeMinMax( bandIdx, minMaxOrigin, minMaxOrigin.limits(),
327 rendererContext.extent(), static_cast<int>( QgsRasterLayer::SAMPLE_SIZE ),
328 min, max );
329 minValues.append( min );
330 maxValues.append( max );
331 }
332
333 rasterRenderer->refresh( rendererContext.extent(), minValues, maxValues );
334 QgsRenderedLayerStatistics *layerStatistics = new QgsRenderedLayerStatistics( layer->id(), minValues, maxValues );
335 layerStatistics->setBoundingBox( rendererContext.extent() );
336 appendRenderedItemDetails( layerStatistics );
337 }
338 }
339
340 mPipe->evaluateDataDefinedProperties( rendererContext.expressionContext() );
341
342 const QgsRasterLayerTemporalProperties *temporalProperties = qobject_cast< const QgsRasterLayerTemporalProperties * >( layer->temporalProperties() );
343 const QgsRasterLayerElevationProperties *elevationProperties = qobject_cast<QgsRasterLayerElevationProperties *>( layer->elevationProperties() );
344
345 if ( ( temporalProperties->isActive() && renderContext()->isTemporal() )
346 || ( elevationProperties->hasElevation() && !renderContext()->zRange().isInfinite() ) )
347 {
348 // temporal and/or elevation band filtering may be applicable
349 bool matched = false;
351 layer,
352 rendererContext.temporalRange(),
353 rendererContext.zRange(),
354 matched
355 );
356 if ( matched && matchedBand > 0 )
357 {
358 mPipe->renderer()->setInputBand( matchedBand );
359 }
360 }
361
362 if ( temporalProperties->isActive() && renderContext()->isTemporal() )
363 {
364 switch ( temporalProperties->mode() )
365 {
370 break;
371
373 if ( mPipe->renderer()->usesBands().contains( temporalProperties->bandNumber() ) )
374 {
375 // if layer has elevation settings and we are only rendering a temporal range => we need to filter pixels by temporal values
376 std::unique_ptr< QgsRasterTransparency > transparency;
377 if ( const QgsRasterTransparency *rendererTransparency = mPipe->renderer()->rasterTransparency() )
378 transparency = std::make_unique< QgsRasterTransparency >( *rendererTransparency );
379 else
380 transparency = std::make_unique< QgsRasterTransparency >();
381
382 QVector<QgsRasterTransparency::TransparentSingleValuePixel> transparentPixels = transparency->transparentSingleValuePixelList();
383
384 const QDateTime &offset = temporalProperties->temporalRepresentationOffset();
385 const QgsInterval &scale = temporalProperties->temporalRepresentationScale();
386 const double adjustedLower = static_cast< double >( offset.msecsTo( rendererContext.temporalRange().begin() ) ) * QgsUnitTypes::fromUnitToUnitFactor( Qgis::TemporalUnit::Milliseconds, scale.originalUnit() ) / scale.originalDuration();
387 const double adjustedUpper = static_cast< double >( offset.msecsTo( rendererContext.temporalRange().end() ) ) * QgsUnitTypes::fromUnitToUnitFactor( Qgis::TemporalUnit::Milliseconds, scale.originalUnit() ) / scale.originalDuration();
388 transparentPixels.append( QgsRasterTransparency::TransparentSingleValuePixel( std::numeric_limits<double>::lowest(), adjustedLower, 0, true, !rendererContext.zRange().includeLower() ) );
389 transparentPixels.append( QgsRasterTransparency::TransparentSingleValuePixel( adjustedUpper, std::numeric_limits<double>::max(), 0, !rendererContext.zRange().includeUpper(), true ) );
390
391 transparency->setTransparentSingleValuePixelList( transparentPixels );
392 mPipe->renderer()->setRasterTransparency( transparency.release() );
393 }
394 break;
395
397 // in this mode we need to pass on the desired render temporal range to the data provider
398 if ( QgsRasterDataProviderTemporalCapabilities *temporalCapabilities = mPipe->provider()->temporalCapabilities() )
399 {
400 temporalCapabilities->setRequestedTemporalRange( rendererContext.temporalRange() );
401 temporalCapabilities->setIntervalHandlingMethod( temporalProperties->intervalHandlingMethod() );
402 }
403 break;
404 }
405 }
406 else if ( QgsRasterDataProviderTemporalCapabilities *temporalCapabilities = mPipe->provider()->temporalCapabilities() )
407 {
408 temporalCapabilities->setRequestedTemporalRange( QgsDateTimeRange() );
409 temporalCapabilities->setIntervalHandlingMethod( temporalProperties->intervalHandlingMethod() );
410 }
411
413
414 if ( elevationProperties && elevationProperties->hasElevation() )
415 {
416 mDrawElevationMap = true;
417 mElevationScale = elevationProperties->zScale();
418 mElevationOffset = elevationProperties->zOffset();
419 mElevationBand = elevationProperties->bandNumber();
420
421 if ( !rendererContext.zRange().isInfinite() )
422 {
423 // NOLINTBEGIN(bugprone-branch-clone)
424 switch ( elevationProperties->mode() )
425 {
427 // don't need to handle anything here -- the layer renderer will never be created if the
428 // render context range doesn't match the layer's fixed elevation range
429 break;
430
433 // temporal/elevation band based filtering was already handled earlier in this method
434 break;
435
437 {
438 if ( mPipe->renderer()->usesBands().contains( mElevationBand ) )
439 {
440 // if layer has elevation settings and we are only rendering a slice of z values => we need to filter pixels by elevation
441 if ( mPipe->renderer()->flags() & Qgis::RasterRendererFlag::UseNoDataForOutOfRangePixels )
442 {
443 std::unique_ptr< QgsRasterNuller> nuller;
444 if ( const QgsRasterNuller *existingNuller = mPipe->nuller() )
445 nuller.reset( existingNuller->clone() );
446 else
447 nuller = std::make_unique< QgsRasterNuller >();
448
449 // account for z offset/zscale by reversing these calculations, so that we get the z range in
450 // raw pixel values
451 QgsRasterRangeList nullRanges;
452 const double adjustedLower = ( rendererContext.zRange().lower() - mElevationOffset ) / mElevationScale;
453 const double adjustedUpper = ( rendererContext.zRange().upper() - mElevationOffset ) / mElevationScale;
454 nullRanges.append( QgsRasterRange( std::numeric_limits<double>::lowest(), adjustedLower, rendererContext.zRange().includeLower() ? QgsRasterRange::BoundsType::IncludeMin : QgsRasterRange::BoundsType::IncludeMinAndMax ) );
455 nullRanges.append( QgsRasterRange( adjustedUpper, std::numeric_limits<double>::max(), rendererContext.zRange().includeUpper() ? QgsRasterRange::BoundsType::IncludeMax : QgsRasterRange::BoundsType::IncludeMinAndMax ) );
456 nuller->setOutputNoDataValue( mElevationBand, static_cast< int >( adjustedLower - 1 ) );
457 nuller->setNoData( mElevationBand, nullRanges );
458
459 if ( !mPipe->insert( 1, nuller.release() ) )
460 {
461 QgsDebugError( QStringLiteral( "Cannot set pipe nuller" ) );
462 }
463 }
464 else
465 {
466 std::unique_ptr< QgsRasterTransparency > transparency;
467 if ( const QgsRasterTransparency *rendererTransparency = mPipe->renderer()->rasterTransparency() )
468 transparency = std::make_unique< QgsRasterTransparency >( *rendererTransparency );
469 else
470 transparency = std::make_unique< QgsRasterTransparency >();
471
472 QVector<QgsRasterTransparency::TransparentSingleValuePixel> transparentPixels = transparency->transparentSingleValuePixelList();
473
474 // account for z offset/zscale by reversing these calculations, so that we get the z range in
475 // raw pixel values
476 const double adjustedLower = ( rendererContext.zRange().lower() - mElevationOffset ) / mElevationScale;
477 const double adjustedUpper = ( rendererContext.zRange().upper() - mElevationOffset ) / mElevationScale;
478 transparentPixels.append( QgsRasterTransparency::TransparentSingleValuePixel( std::numeric_limits<double>::lowest(), adjustedLower, 0, true, !rendererContext.zRange().includeLower() ) );
479 transparentPixels.append( QgsRasterTransparency::TransparentSingleValuePixel( adjustedUpper, std::numeric_limits<double>::max(), 0, !rendererContext.zRange().includeUpper(), true ) );
480
481 transparency->setTransparentSingleValuePixelList( transparentPixels );
482 mPipe->renderer()->setRasterTransparency( transparency.release() );
483 }
484 }
485 break;
486 }
487 }
488 // NOLINTEND(bugprone-branch-clone)
489 }
490 }
491
492 prepareLabeling( layer );
493
494 mFeedback->setRenderContext( rendererContext );
495
496 mPipe->moveToThread( nullptr );
497
498 mPreparationTime = timer.elapsed();
499}
500
502{
503 delete mFeedback;
504
505 delete mRasterViewPort;
506}
507
509{
510 std::unique_ptr< QgsScopedRuntimeProfile > profile;
511 if ( mEnableProfile )
512 {
513 profile = std::make_unique< QgsScopedRuntimeProfile >( mLayerName, QStringLiteral( "rendering" ), layerId() );
514 if ( mPreparationTime > 0 )
515 QgsApplication::profiler()->record( QObject::tr( "Create renderer" ), mPreparationTime / 1000.0, QStringLiteral( "rendering" ) );
516 }
517
518 // Skip rendering of out of view tiles (xyz)
519 if ( !mRasterViewPort || ( renderContext()->testFlag( Qgis::RenderContextFlag::RenderPreviewJob ) &&
520 !( mInterfaceCapabilities &
522 return true;
523
524 mPipe->moveToThread( QThread::currentThread() );
525
526 QElapsedTimer time;
527 time.start();
528
529 std::unique_ptr< QgsScopedRuntimeProfile > preparingProfile;
530 if ( mEnableProfile )
531 {
532 preparingProfile = std::make_unique< QgsScopedRuntimeProfile >( QObject::tr( "Preparing render" ), QStringLiteral( "rendering" ) );
533 }
534
535 //
536 //
537 // The goal here is to make as many decisions as possible early on (outside of the rendering loop)
538 // so that we can maximise performance of the rendering process. So now we check which drawing
539 // procedure to use :
540 //
541
542 const QgsScopedQPainterState painterSate( renderContext()->painter() );
543 if ( !mClippingRegions.empty() )
544 {
545 bool needsPainterClipPath = false;
546 const QPainterPath path = QgsMapClippingUtils::calculatePainterClipRegion( mClippingRegions, *renderContext(), Qgis::LayerType::Raster, needsPainterClipPath );
547 if ( needsPainterClipPath )
548 renderContext()->painter()->setClipPath( path, Qt::IntersectClip );
549 }
550
551 QgsRasterProjector *projector = mPipe->projector();
552 bool restoreOldResamplingStage = false;
553 const Qgis::RasterResamplingStage oldResamplingState = mPipe->resamplingStage();
554
555 // TODO add a method to interface to get provider and get provider
556 // params in QgsRasterProjector
557 if ( projector )
558 {
559 // Force provider resampling if reprojection is needed
560 if ( ( mPipe->provider()->providerCapabilities() & Qgis::RasterProviderCapability::ProviderHintCanPerformProviderResampling ) &&
561 mRasterViewPort->mSrcCRS != mRasterViewPort->mDestCRS &&
562 oldResamplingState != Qgis::RasterResamplingStage::Provider )
563 {
564 restoreOldResamplingStage = true;
565 mPipe->setResamplingStage( Qgis::RasterResamplingStage::Provider );
566 }
567 projector->setCrs( mRasterViewPort->mSrcCRS, mRasterViewPort->mDestCRS, mRasterViewPort->mTransformContext );
568 }
569
570 // important -- disable SmoothPixmapTransform for raster layer renders. We want individual pixels to be clearly defined!
571 renderContext()->painter()->setRenderHint( QPainter::SmoothPixmapTransform, false );
572
573 preparingProfile.reset();
574 std::unique_ptr< QgsScopedRuntimeProfile > renderingProfile;
575 if ( mEnableProfile )
576 {
577 renderingProfile = std::make_unique< QgsScopedRuntimeProfile >( QObject::tr( "Rendering" ), QStringLiteral( "rendering" ) );
578 }
579
580 // Drawer to pipe?
581 QgsRasterIterator iterator( mPipe->last() );
582
583 // Get the maximum tile size from the provider and set it as the maximum tile size for the iterator
584 if ( QgsRasterDataProvider *provider = mPipe->provider() )
585 {
586 const QSize maxTileSize {provider->maximumTileSize()};
587 iterator.setMaximumTileWidth( maxTileSize.width() );
588 iterator.setMaximumTileHeight( maxTileSize.height() );
589 }
590
591 QgsRasterDrawer drawer( &iterator );
592 drawer.draw( *( renderContext() ), mRasterViewPort, mFeedback );
593
594 if ( mDrawElevationMap )
595 drawElevationMap();
596
597 renderingProfile.reset();
598
599 if ( mLabelProvider && !renderContext()->renderingStopped() )
600 {
601 std::unique_ptr< QgsScopedRuntimeProfile > labelingProfile;
602 if ( mEnableProfile )
603 {
604 labelingProfile = std::make_unique< QgsScopedRuntimeProfile >( QObject::tr( "Labeling" ), QStringLiteral( "rendering" ) );
605 }
606 drawLabeling();
607 }
608
609 if ( restoreOldResamplingStage )
610 {
611 mPipe->setResamplingStage( oldResamplingState );
612 }
613
614 const QStringList errors = mFeedback->errors();
615 for ( const QString &error : errors )
616 {
617 mErrors.append( error );
618 }
619
620 QgsDebugMsgLevel( QStringLiteral( "total raster draw time (ms): %1" ).arg( time.elapsed(), 5 ), 4 );
621 mReadyToCompose = true;
622
623 mPipe->moveToThread( nullptr );
624
625 return !mFeedback->isCanceled();
626}
627
629{
630 return mFeedback;
631}
632
634{
635 if ( !mRasterViewPort || !mPipe )
636 return false; // this layer is not going to get rendered
637
638 // preview of intermediate raster rendering results requires a temporary output image
640 return true;
641
642 if ( QgsRasterRenderer *renderer = mPipe->renderer() )
643 {
644 if ( !( renderer->flags() & Qgis::RasterRendererFlag::InternalLayerOpacityHandling ) )
645 {
646 switch ( renderContext()->rasterizedRenderingPolicy() )
647 {
650 break;
651
653 return false;
654 }
655
656 if ( !qgsDoubleNear( mLayerOpacity, 1.0 ) )
657 return true;
658 }
659 }
660
661 return false;
662}
663
664void QgsRasterLayerRenderer::prepareLabeling( QgsRasterLayer *layer )
665{
666 QgsRenderContext &context = *renderContext();
667
668 if ( QgsLabelingEngine *engine2 = context.labelingEngine() )
669 {
670 if ( QgsAbstractRasterLayerLabeling *labeling = layer->labeling() )
671 {
672 if ( layer->labelsEnabled() && labeling->isInScaleRange( context.rendererScale() ) )
673 {
674 std::unique_ptr< QgsRasterLayerLabelProvider > provider = labeling->provider( layer );
675 if ( provider )
676 {
677 // engine takes ownership
678 mLabelProvider = provider.release();
679 mLabelProvider->startRender( context );
680 engine2->addProvider( mLabelProvider );
681 }
682 }
683 }
684 }
685}
686
687void QgsRasterLayerRenderer::drawLabeling()
688{
689 if ( mLabelProvider )
690 mLabelProvider->generateLabels( *renderContext(), mPipe.get(), mRasterViewPort, mFeedback );
691}
692
693void QgsRasterLayerRenderer::drawElevationMap()
694{
695 QgsRasterDataProvider *dataProvider = mPipe->provider();
696 if ( renderContext()->elevationMap() && dataProvider )
697 {
698 double dpiScalefactor;
699
700 if ( renderContext()->dpiTarget() >= 0.0 )
701 dpiScalefactor = renderContext()->dpiTarget() / ( renderContext()->scaleFactor() * 25.4 );
702 else
703 dpiScalefactor = 1.0;
704
705 int outputWidth = static_cast<int>( static_cast<double>( mRasterViewPort->mWidth ) / dpiScalefactor * renderContext()->devicePixelRatio() );
706 int outputHeight = static_cast<int>( static_cast<double>( mRasterViewPort->mHeight ) / dpiScalefactor * renderContext()->devicePixelRatio() );
707
708 QSize viewSize = renderContext()->deviceOutputSize();
709 int viewWidth = static_cast<int>( viewSize.width() / dpiScalefactor );
710 int viewHeight = static_cast<int>( viewSize.height() / dpiScalefactor );
711
712 bool canRenderElevation = false;
713 std::unique_ptr<QgsRasterBlock> elevationBlock;
714 if ( mRasterViewPort->mSrcCRS == mRasterViewPort->mDestCRS )
715 {
716 elevationBlock.reset(
717 dataProvider->block(
718 mElevationBand,
719 mRasterViewPort->mDrawnExtent,
720 outputWidth,
721 outputHeight,
722 mFeedback ) );
723 canRenderElevation = true;
724 }
725 else
726 {
727 // Destinaton CRS is different from the source CRS.
728 // Using the raster projector lead to have big artifacts when rendering the elevation map.
729 // To get a smoother elevation map, we use GDAL resampling with coordinates transform
730 QgsRectangle viewExtentInLayerCoordinate = renderContext()->extent();
731
732 // If view extent is infinite, we use the data provider extent
733 if ( viewExtentInLayerCoordinate.xMinimum() == std::numeric_limits<double>::lowest() &&
734 viewExtentInLayerCoordinate.yMinimum() == std::numeric_limits<double>::lowest() &&
735 viewExtentInLayerCoordinate.xMaximum() == std::numeric_limits<double>::max() &&
736 viewExtentInLayerCoordinate.yMaximum() == std::numeric_limits<double>::max() )
737 {
738 viewExtentInLayerCoordinate = dataProvider->extent();
739 }
740
741 double xLayerResol = viewExtentInLayerCoordinate.width() / static_cast<double>( viewWidth );
742 double yLayerResol = viewExtentInLayerCoordinate.height() / static_cast<double>( viewHeight );
743
744 double overSampling = 1;
745 if ( mPipe->resampleFilter() )
746 overSampling = mPipe->resampleFilter()->maxOversampling();
747
749 {
750 // If the dataprovider has size capability, we calculate the requested resolution to provider
751 double providerXResol = dataProvider->extent().width() / dataProvider->xSize();
752 double providerYResol = dataProvider->extent().height() / dataProvider->ySize();
753 overSampling = ( xLayerResol / providerXResol + yLayerResol / providerYResol ) / 2;
754 }
755
756 GDALResampleAlg alg;
757 if ( overSampling > 1 )
759 else
761
762 Qgis::DataType dataType = dataProvider->dataType( mElevationBand );
763
764 if ( dataType != Qgis::DataType::UnknownDataType ) // resampling data by GDAL is not compatible with unknown data type
765 {
766 // we need extra pixels on border to avoid effect border with resampling (at least 2 pixels band for cubic alg)
767 int sourceWidth = viewWidth + 4;
768 int sourceHeight = viewHeight + 4;
769 viewExtentInLayerCoordinate = QgsRectangle(
770 viewExtentInLayerCoordinate.xMinimum() - xLayerResol * 2,
771 viewExtentInLayerCoordinate.yMinimum() - yLayerResol * 2,
772 viewExtentInLayerCoordinate.xMaximum() + xLayerResol * 2,
773 viewExtentInLayerCoordinate.yMaximum() + yLayerResol * 2 );
774
775 // Now we can do the resampling
776 std::unique_ptr<QgsRasterBlock> sourcedata( dataProvider->block( mElevationBand, viewExtentInLayerCoordinate, sourceWidth, sourceHeight, mFeedback ) );
777 gdal::dataset_unique_ptr gdalDsInput =
778 QgsGdalUtils::blockToSingleBandMemoryDataset( viewExtentInLayerCoordinate, sourcedata.get() );
779
780
781 elevationBlock.reset( new QgsRasterBlock( dataType,
782 outputWidth,
783 outputHeight ) );
784
785 elevationBlock->setNoDataValue( dataProvider->sourceNoDataValue( mElevationBand ) );
786
787 gdal::dataset_unique_ptr gdalDsOutput =
788 QgsGdalUtils::blockToSingleBandMemoryDataset( mRasterViewPort->mDrawnExtent, elevationBlock.get() );
789
790 // For coordinate transformation, we try to obtain a coordinate operation string from the transform context.
791 // Depending of the CRS, if we can't we use GDAL transformation directly from the source and destination CRS
792 QString coordinateOperation;
793 const QgsCoordinateTransformContext &transformContext = renderContext()->transformContext();
794 if ( transformContext.mustReverseCoordinateOperation( mRasterViewPort->mSrcCRS, mRasterViewPort->mDestCRS ) )
795 coordinateOperation = transformContext.calculateCoordinateOperation( mRasterViewPort->mDestCRS, mRasterViewPort->mSrcCRS );
796 else
797 coordinateOperation = transformContext.calculateCoordinateOperation( mRasterViewPort->mSrcCRS, mRasterViewPort->mDestCRS );
798
799 if ( coordinateOperation.isEmpty() )
800 canRenderElevation = QgsGdalUtils::resampleSingleBandRaster( gdalDsInput.get(), gdalDsOutput.get(), alg,
801 mRasterViewPort->mSrcCRS, mRasterViewPort->mDestCRS );
802 else
803 canRenderElevation = QgsGdalUtils::resampleSingleBandRaster( gdalDsInput.get(), gdalDsOutput.get(), alg,
804 coordinateOperation.toUtf8().constData() );
805 }
806 }
807
808 if ( canRenderElevation )
809 {
810 QPoint topLeft;
811 if ( renderContext()->mapToPixel().mapRotation() != 0 )
812 {
813 // Now rendering elevation on the elevation map, we need to take care of rotation:
814 // again a resampling but this time with a geotransform.
815 const QgsMapToPixel &mtp = renderContext()->mapToPixel();
817
818 int elevMapWidth = elevMap->rawElevationImage().width();
819 int elevMapHeight = elevMap->rawElevationImage().height();
820
821 int bottom = 0;
822 int top = elevMapHeight;
823 int left = elevMapWidth;
824 int right = 0;
825
826 QList<QgsPointXY> corners;
827 corners << QgsPointXY( mRasterViewPort->mDrawnExtent.xMinimum(), mRasterViewPort->mDrawnExtent.yMinimum() )
828 << QgsPointXY( mRasterViewPort->mDrawnExtent.xMaximum(), mRasterViewPort->mDrawnExtent.yMaximum() )
829 << QgsPointXY( mRasterViewPort->mDrawnExtent.xMinimum(), mRasterViewPort->mDrawnExtent.yMaximum() )
830 << QgsPointXY( mRasterViewPort->mDrawnExtent.xMaximum(), mRasterViewPort->mDrawnExtent.yMinimum() );
831
832 for ( const QgsPointXY &corner : std::as_const( corners ) )
833 {
834 const QgsPointXY dpt = mtp.transform( corner );
835 int x = static_cast<int>( std::round( dpt.x() ) );
836 int y = static_cast<int>( std::round( dpt.y() ) );
837
838 if ( x < left )
839 left = x;
840 if ( x > right )
841 right = x;
842 if ( y < top )
843 top = y;
844 if ( y > bottom )
845 bottom = y;
846 }
847
848 const QgsPointXY origin = mtp.toMapCoordinates( left, top );
849 double gridXSize = mtp.toMapCoordinates( right, top ).distance( origin );
850 double gridYSize = mtp.toMapCoordinates( left, bottom ).distance( origin );
851 double angleRad = renderContext()->mapToPixel().mapRotation() / 180 * M_PI;
852
853 gdal::dataset_unique_ptr gdalDsInput =
854 QgsGdalUtils::blockToSingleBandMemoryDataset( mRasterViewPort->mDrawnExtent, elevationBlock.get() );
855
856 std::unique_ptr<QgsRasterBlock> rotatedElevationBlock =
857 std::make_unique<QgsRasterBlock>( elevationBlock->dataType(),
858 ( right - left ) * renderContext()->devicePixelRatio() + 1,
859 ( bottom - top ) * renderContext()->devicePixelRatio() + 1 );
860
861 rotatedElevationBlock->setNoDataValue( elevationBlock->noDataValue() );
862
863 gdal::dataset_unique_ptr gdalDsOutput =
864 QgsGdalUtils::blockToSingleBandMemoryDataset( angleRad, origin, gridXSize, gridYSize, rotatedElevationBlock.get() );
865
867 gdalDsInput.get(),
868 gdalDsOutput.get(),
870 {
871 elevationBlock = std::move( rotatedElevationBlock );
872 }
873
874 topLeft = QPoint( left, top );
875 }
876 else
877 {
878 topLeft = mRasterViewPort->mTopLeftPoint.toQPointF().toPoint();
879 }
880
882 elevationBlock.get(),
883 topLeft.y() * renderContext()->devicePixelRatio(),
884 topLeft.x() * renderContext()->devicePixelRatio(),
885 mElevationScale,
886 mElevationOffset );
887 }
888 }
889}
Provides global constants and enumerations for use throughout the application.
Definition qgis.h:54
@ Default
Allow raster-based rendering in situations where it is required for correct rendering or where it wil...
@ PreferVector
Prefer vector-based rendering, when the result will still be visually near-identical to a raster-base...
@ ForceVector
Always force vector-based rendering, even when the result will be visually different to a raster-base...
RasterResamplingStage
Stage at which raster resampling occurs.
Definition qgis.h:1433
@ Provider
Resampling occurs in Provider.
@ ProviderHintCanPerformProviderResampling
Provider can perform resampling (to be opposed to post rendering resampling)
@ DpiDependentData
Provider's rendering is dependent on requested pixel size of the viewport.
@ InternalLayerOpacityHandling
The renderer internally handles the raster layer's opacity, so the default layer level opacity handli...
@ UseNoDataForOutOfRangePixels
Out of range pixels (eg those values outside of the rendered map's z range filter) should be set usin...
@ FixedRangePerBand
Layer has a fixed (manually specified) elevation range per band.
@ FixedElevationRange
Layer has a fixed elevation range.
@ RepresentsElevationSurface
Pixel values represent an elevation surface.
@ DynamicRangePerBand
Layer has a elevation range per band, calculated dynamically from an expression.
@ Milliseconds
Milliseconds.
@ RepresentsTemporalValues
Pixel values represent an datetime.
@ RedrawLayerOnly
Redraw the layer when temporal range changes, but don't apply any filtering. Useful when raster symbo...
@ FixedRangePerBand
Layer has a fixed temporal range per band.
@ TemporalRangeFromDataProvider
Mode when raster layer delegates temporal range handling to the dataprovider.
@ FixedTemporalRange
Mode when temporal properties have fixed start and end datetimes.
@ FixedDateTime
Layer has a fixed date time instant.
@ Prefetch
Allow prefetching of out-of-view images.
@ Size
Original data source size (and thus resolution) is known, it is not always available,...
DataType
Raster data types.
Definition qgis.h:351
@ UnknownDataType
Unknown or unspecified type.
@ Raster
Raster layer.
@ RenderPreviewJob
Render is a 'canvas preview' render, and shortcuts should be taken to ensure fast rendering.
@ RenderPartialOutput
Whether to make extra effort to update map image with partially rendered layers (better for interacti...
@ Render3DMap
Render is for a 3D map.
@ Reverse
Reverse/inverse transform (from destination to source)
Abstract base class for labeling settings for raster layers.
static QgsRuntimeProfiler * profiler()
Returns the application runtime profiler.
Represents a coordinate reference system (CRS).
Contains information about the context in which a coordinate transform is executed.
QString calculateCoordinateOperation(const QgsCoordinateReferenceSystem &source, const QgsCoordinateReferenceSystem &destination) const
Returns the Proj coordinate operation string to use when transforming from the specified source CRS t...
bool mustReverseCoordinateOperation(const QgsCoordinateReferenceSystem &source, const QgsCoordinateReferenceSystem &destination) const
Returns true if the coordinate operation returned by calculateCoordinateOperation() for the source to...
Handles coordinate transforms between two coordinate systems.
void setBallparkTransformsAreAppropriate(bool appropriate)
Sets whether approximate "ballpark" results are appropriate for this coordinate transform.
bool isShortCircuited() const
Returns true if the transform short circuits because the source and destination are equivalent.
QgsRectangle transformBoundingBox(const QgsRectangle &rectangle, Qgis::TransformDirection direction=Qgis::TransformDirection::Forward, bool handle180Crossover=false) const
Transforms a rectangle from the source CRS to the destination CRS.
bool isValid() const
Returns true if the coordinate transform is valid, ie both the source and destination CRS have been s...
QgsCoordinateReferenceSystem destinationCrs() const
Returns the destination coordinate reference system, which the transform will transform coordinates t...
Custom exception class for Coordinate Reference System related exceptions.
bool isInfinite() const
Returns true if the range consists of all possible values.
Definition qgsrange.h:287
Stores a digital elevation model in a raster image which may get updated as a part of the map layer r...
QImage rawElevationImage() const
Returns raw elevation image with elevations encoded as color values.
void fillWithRasterBlock(QgsRasterBlock *block, int top, int left, double zScale=1.0, double offset=0.0)
Fills the elevation map with values contains in a raster block starting from position defined by top ...
QString what() const
Base class for feedback objects to be used for cancellation of something running in a worker thread.
Definition qgsfeedback.h:44
static bool resampleSingleBandRaster(GDALDatasetH hSrcDS, GDALDatasetH hDstDS, GDALResampleAlg resampleAlg, const char *pszCoordinateOperation)
Resamples a single band raster to the destination dataset with different resolution (and possibly wit...
static GDALResampleAlg gdalResamplingAlgorithm(Qgis::RasterResamplingMethod method)
Returns the GDAL resampling method corresponding to the QGIS resampling method.
static gdal::dataset_unique_ptr blockToSingleBandMemoryDataset(int pixelWidth, int pixelHeight, const QgsRectangle &extent, void *block, GDALDataType dataType)
Converts a data block to a single band GDAL memory dataset.
A representation of the interval between two datetime values.
Definition qgsinterval.h:46
double originalDuration() const
Returns the original interval duration.
Qgis::TemporalUnit originalUnit() const
Returns the original interval temporal unit.
Provides map labeling functionality.
static QPainterPath calculatePainterClipRegion(const QList< QgsMapClippingRegion > &regions, const QgsRenderContext &context, Qgis::LayerType layerType, bool &shouldClip)
Returns a QPainterPath representing the intersection of clipping regions from context which should be...
static QList< QgsMapClippingRegion > collectClippingRegionsForLayer(const QgsRenderContext &context, const QgsMapLayer *layer)
Collects the list of map clipping regions from a context which apply to a map layer.
double zScale() const
Returns the z scale, which is a scaling factor which should be applied to z values from the layer.
double zOffset() const
Returns the z offset, which is a fixed offset amount which should be added to z values from the layer...
Base class for utility classes that encapsulate information necessary for rendering of map layers.
bool mReadyToCompose
The flag must be set to false in renderer's constructor if wants to use the smarter map redraws funct...
QString layerId() const
Gets access to the ID of the layer rendered by this class.
void appendRenderedItemDetails(QgsRenderedItemDetails *details)
Appends the details of a rendered item to the renderer.
QgsRenderContext * renderContext()
Returns the render context associated with the renderer.
QStringList errors() const
Returns list of errors (problems) that happened during the rendering.
virtual QgsRectangle extent() const
Returns the extent of the layer.
QgsCoordinateReferenceSystem crs
Definition qgsmaplayer.h:84
QString id
Definition qgsmaplayer.h:80
void statusChanged(const QString &status)
Emit a signal with status (e.g. to be caught by QgisApp and display a msg on status bar)
Perform transforms between map coordinates and device coordinates.
int mapHeight() const
Returns current map height in pixels.
void setMapRotation(double degrees, double cx, double cy)
Sets map rotation in degrees (clockwise).
double mapUnitsPerPixel() const
Returns the current map units per pixel.
QgsPointXY toMapCoordinates(int x, int y) const
Transforms device coordinates to map (world) coordinates.
int mapWidth() const
Returns the current map width in pixels.
QgsPointXY transform(const QgsPointXY &p) const
Transforms a point p from map (world) coordinates to device coordinates.
double mapRotation() const
Returns the current map rotation in degrees (clockwise).
static void logMessage(const QString &message, const QString &tag=QString(), Qgis::MessageLevel level=Qgis::MessageLevel::Warning, bool notifyUser=true, const char *file=__builtin_FILE(), const char *function=__builtin_FUNCTION(), int line=__builtin_LINE())
Adds a message to the log instance (and creates it if necessary).
Represents a 2D point.
Definition qgspointxy.h:60
double distance(double x, double y) const
Returns the distance between this point and a specified x, y coordinate.
Definition qgspointxy.h:206
void setY(double y)
Sets the y value of the point.
Definition qgspointxy.h:129
double y
Definition qgspointxy.h:64
double x
Definition qgspointxy.h:63
void setX(double x)
Sets the x value of the point.
Definition qgspointxy.h:119
QPointF toQPointF() const
Converts a point to a QPointF.
Definition qgspointxy.h:165
bool includeUpper() const
Returns true if the upper bound is inclusive, or false if the upper bound is exclusive.
Definition qgsrange.h:101
T lower() const
Returns the lower bound of the range.
Definition qgsrange.h:78
bool includeLower() const
Returns true if the lower bound is inclusive, or false if the lower bound is exclusive.
Definition qgsrange.h:93
T upper() const
Returns the upper bound of the range.
Definition qgsrange.h:85
Feedback object tailored for raster block reading.
void setPreviewOnly(bool preview)
set flag whether the block request is for preview purposes only
void setRenderPartialOutput(bool enable)
Set whether our painter is drawing to a temporary image used just by this layer.
Raster data container.
Implementation of data provider temporal properties for QgsRasterDataProviders.
Base class for raster data providers.
Qgis::RasterResamplingMethod zoomedInResamplingMethod() const
Returns resampling method for zoomed-in operations.
virtual double sourceNoDataValue(int bandNo) const
Value representing no data value.
void setDpi(int dpi)
Sets the output device resolution.
QgsRectangle extent() const override=0
Returns the extent of the layer.
Qgis::DataType dataType(int bandNo) const override=0
Returns data type for the band specified by number.
Qgis::RasterResamplingMethod zoomedOutResamplingMethod() const
Returns resampling method for zoomed-out operations.
QgsRasterBlock * block(int bandNo, const QgsRectangle &boundingBox, int width, int height, QgsRasterBlockFeedback *feedback=nullptr) override
Read block of data using given extent and size.
void statusChanged(const QString &) const
Emit a message to be displayed on status bar, usually used by network providers (WMS,...
The drawing pipe for raster layers.
void draw(QPainter *p, QgsRasterViewPort *viewPort, const QgsMapToPixel *qgsMapToPixel, QgsRasterBlockFeedback *feedback=nullptr)
Draws raster data.
virtual Qgis::RasterInterfaceCapabilities capabilities() const
Returns the capabilities supported by the interface.
virtual int xSize() const
Gets raster size.
virtual int ySize() const
Iterator for sequentially processing raster cells.
void setMaximumTileWidth(int w)
Sets the maximum tile width returned during iteration.
void setMaximumTileHeight(int h)
Sets the minimum tile height returned during iteration.
Raster layer specific subclass of QgsMapLayerElevationProperties.
Qgis::RasterElevationMode mode() const
Returns the elevation mode.
bool hasElevation() const override
Returns true if the layer has an elevation or z component.
int bandNumber() const
Returns the band number from which the elevation should be taken.
void generateLabels(QgsRenderContext &context, QgsRasterPipe *pipe, QgsRasterViewPort *rasterViewPort, QgsRasterLayerRendererFeedback *feedback)
Generates the labels, given a render context and input pipe.
void startRender(QgsRenderContext &context) final
To be called before rendering of labels begins.
Implementation of threaded rendering for raster layers.
bool render() override
Do the rendering (based on data stored in the class).
QgsRasterLayerRenderer(QgsRasterLayer *layer, QgsRenderContext &rendererContext)
bool forceRasterRender() const override
Returns true if the renderer must be rendered to a raster paint device (e.g.
QgsFeedback * feedback() const override
Access to feedback object of the layer renderer (may be nullptr)
Implementation of map layer temporal properties for raster layers.
QDateTime temporalRepresentationOffset() const
Returns the temporal offset, which is a fixed datetime which should be added to individual pixel valu...
Qgis::TemporalIntervalMatchMethod intervalHandlingMethod() const
Returns the desired method to use when resolving a temporal interval to matching layers or bands in t...
const QgsInterval & temporalRepresentationScale() const
Returns the scale, which is an interval factor which should be applied to individual pixel values fro...
Qgis::RasterTemporalMode mode() const
Returns the temporal properties mode.
int bandNumber() const
Returns the band number from which temporal values should be taken.
static int renderedBandForElevationAndTemporalRange(QgsRasterLayer *layer, const QgsDateTimeRange &temporalRange, const QgsDoubleRange &elevationRange, bool &matched)
Given a raster layer, returns the band which should be used for rendering the layer for a specified t...
Represents a raster layer.
const QgsAbstractRasterLayerLabeling * labeling() const
Access to const labeling configuration.
int height() const
Returns the height of the (unclipped) raster.
QgsMapLayerTemporalProperties * temporalProperties() override
Returns the layer's temporal properties.
QgsRasterPipe * pipe()
Returns the raster pipe.
bool ignoreExtents() const
If the ignoreExtent flag is set, the layer will also render outside the bounding box reported by the ...
void computeMinMax(int band, const QgsRasterMinMaxOrigin &mmo, Qgis::RasterRangeLimit limits, const QgsRectangle &extent, int sampleSize, double &min, double &max)
Compute the min max values along band according to MinMaxOrigin parameters mmo and extent.
bool labelsEnabled() const
Returns whether the layer contains labels which are enabled and should be drawn.
static const double SAMPLE_SIZE
Default sample size (number of pixels) for estimated statistics/histogram calculation.
QgsRasterDataProvider * dataProvider() override
Returns the source data provider.
int width() const
Returns the width of the (unclipped) raster.
QgsMapLayerElevationProperties * elevationProperties() override
Returns the layer's elevation properties.
Describes the origin of minimum and maximum values in a raster.
Qgis::RasterRangeLimit limits() const
Returns the raster limits.
Raster pipe that deals with null values.
Contains a pipeline of raster interfaces for sequential raster processing.
Implements approximate projection support for optimised raster transformation.
Q_DECL_DEPRECATED void setCrs(const QgsCoordinateReferenceSystem &srcCRS, const QgsCoordinateReferenceSystem &destCRS, int srcDatumTransform=-1, int destDatumTransform=-1)
Sets the source and destination CRS.
Represents a range of raster values between min and max, optionally including the min and max value.
@ IncludeMin
Include the min value, but not the max value, e.g. min <= value < max.
@ IncludeMinAndMax
Min and max values are inclusive.
@ IncludeMax
Include the max value, but not the min value, e.g. min < value <= max.
Raster renderer pipe that applies colors to a raster.
const QgsRasterMinMaxOrigin & minMaxOrigin() const
Returns const reference to origin of min/max values.
virtual bool refresh(const QgsRectangle &extent, const QList< double > &min, const QList< double > &max, bool forceRefresh=false)
Refreshes the renderer according to the min and max values associated with the extent.
virtual QList< int > usesBands() const
Returns a list of band numbers used by the renderer.
bool needsRefresh(const QgsRectangle &extent) const
Checks if the renderer needs to be refreshed according to extent.
Defines the list of pixel values to be considered as transparent or semi transparent when rendering r...
A rectangle specified with double values.
Q_INVOKABLE QString toString(int precision=16) const
Returns a string representation of form xmin,ymin : xmax,ymax Coordinates will be truncated to the sp...
double xMinimum
double yMinimum
double xMaximum
void set(const QgsPointXY &p1, const QgsPointXY &p2, bool normalize=true)
Sets the rectangle from two QgsPoints.
double yMaximum
void setNull()
Mark a rectangle as being null (holding no spatial information).
QgsRectangle intersect(const QgsRectangle &rect) const
Returns the intersection with the given rectangle.
Contains information about the context of a rendering operation.
double scaleFactor() const
Returns the scaling factor for the render to convert painter units to physical sizes.
QPainter * painter()
Returns the destination QPainter for the render operation.
double rendererScale() const
Returns the renderer map scale.
QgsExpressionContext & expressionContext()
Gets the expression context.
QgsCoordinateTransformContext transformContext() const
Returns the context's coordinate transform context, which stores various information regarding which ...
QgsElevationMap * elevationMap() const
Returns the destination elevation map for the render operation.
const QgsRectangle & extent() const
When rendering a map layer, calling this method returns the "clipping" extent for the layer (in the l...
bool testFlag(Qgis::RenderContextFlag flag) const
Check whether a particular flag is enabled.
void setDpiTarget(double dpi)
Sets the targeted dpi for rendering.
float devicePixelRatio() const
Returns the device pixel ratio.
QgsRectangle mapExtent() const
Returns the original extent of the map being rendered.
double dpiTarget() const
Returns the targeted DPI for rendering.
const QgsMapToPixel & mapToPixel() const
Returns the context's map to pixel transform, which transforms between map coordinates and device coo...
QgsDoubleRange zRange() const
Returns the range of z-values which should be rendered.
QSize deviceOutputSize() const
Returns the device output size of the render.
QgsLabelingEngine * labelingEngine() const
Gets access to new labeling engine (may be nullptr).
QgsCoordinateTransform coordinateTransform() const
Returns the current coordinate transform for the context.
Qgis::RenderContextFlags flags() const
Returns combination of flags used for rendering.
void setBoundingBox(const QgsRectangle &bounds)
Sets the bounding box of the item (in map units).
Contains computed statistics for a layer render.
void record(const QString &name, double time, const QString &group="startup", const QString &id=QString())
Manually adds a profile event with the given name and total time (in seconds).
Scoped object for saving and restoring a QPainter object's state.
bool isActive() const
Returns true if the temporal property is active.
const QgsDateTimeRange & temporalRange() const
Returns the datetime range for the object.
T begin() const
Returns the beginning of the range.
Definition qgsrange.h:446
T end() const
Returns the upper bound of the range.
Definition qgsrange.h:453
static Q_INVOKABLE double fromUnitToUnitFactor(Qgis::DistanceUnit fromUnit, Qgis::DistanceUnit toUnit)
Returns the conversion factor between the specified distance units.
std::unique_ptr< std::remove_pointer< GDALDatasetH >::type, GDALDatasetCloser > dataset_unique_ptr
Scoped GDAL dataset.
unsigned long long qgssize
Qgssize is used instead of size_t, because size_t is stdlib type, unknown by SIP, and it would be har...
Definition qgis.h:6891
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
Definition qgis.h:6367
#define QgsDebugMsgLevel(str, level)
Definition qgslogger.h:41
#define QgsDebugError(str)
Definition qgslogger.h:40
QgsTemporalRange< QDateTime > QgsDateTimeRange
QgsRange which stores a range of date times.
Definition qgsrange.h:761
QList< QgsRasterRange > QgsRasterRangeList
Defines the transparency for a range of single-band pixel values.
This class provides details of the viewable area that a raster will be rendered into.
qgssize mHeight
Height, number of rows to be rendered.
QgsCoordinateReferenceSystem mDestCRS
Target (map) coordinate system.
QgsPointXY mBottomRightPoint
Coordinate (in output device coordinate system) of bottom right corner of the part of the raster that...
QgsPointXY mTopLeftPoint
Coordinate (in output device coordinate system) of top left corner of the part of the raster that is ...
QgsCoordinateReferenceSystem mSrcCRS
Source (layer) coordinate system.
QgsRectangle mDrawnExtent
Intersection of current map extent and layer extent, in map (destination) CRS.
QgsCoordinateTransformContext mTransformContext
Coordinate transform context.
qgssize mWidth
Width, number of columns to be rendered.