QGIS API Documentation 3.41.0-Master (cea29feecf2)
Loading...
Searching...
No Matches
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
44#include <QElapsedTimer>
45#include <QPointer>
46#include <QThread>
47
49
50QgsRasterLayerRendererFeedback::QgsRasterLayerRendererFeedback( QgsRasterLayerRenderer *r )
51 : mR( r )
52 , mMinimalPreviewInterval( 250 )
53{
55}
56
57void QgsRasterLayerRendererFeedback::onNewData()
58{
59 if ( !renderPartialOutput() )
60 return; // we were not asked for partial renders and we may not have a temporary image for overwriting...
61
62 // update only once upon a time
63 // (preview itself takes some time)
64 if ( mLastPreview.isValid() && mLastPreview.msecsTo( QTime::currentTime() ) < mMinimalPreviewInterval )
65 return;
66
67 // TODO: update only the area that got new data
68
69 QgsDebugMsgLevel( QStringLiteral( "new raster preview! %1" ).arg( mLastPreview.msecsTo( QTime::currentTime() ) ), 3 );
70 QElapsedTimer t;
71 t.start();
73 feedback.setPreviewOnly( true );
74 feedback.setRenderPartialOutput( true );
75 QgsRasterIterator iterator( mR->mPipe->last() );
76 QgsRasterDrawer drawer( &iterator );
77 drawer.draw( *( mR->renderContext() ), mR->mRasterViewPort, &feedback );
78 mR->mReadyToCompose = true;
79 QgsDebugMsgLevel( QStringLiteral( "total raster preview time: %1 ms" ).arg( t.elapsed() ), 3 );
80 mLastPreview = QTime::currentTime();
81}
82
86 : QgsMapLayerRenderer( layer->id(), &rendererContext )
87 , mLayerName( layer->name() )
88 , mLayerOpacity( layer->opacity() )
89 , mProviderCapabilities( layer->dataProvider()->providerCapabilities() )
90 , mInterfaceCapabilities( layer->dataProvider()->capabilities() )
91 , mFeedback( new QgsRasterLayerRendererFeedback( this ) )
92 , mEnableProfile( rendererContext.flags() & Qgis::RenderContextFlag::RecordProfile )
93{
94 mReadyToCompose = false;
95
96 QElapsedTimer timer;
97 timer.start();
98
99 QgsMapToPixel mapToPixel = rendererContext.mapToPixel();
100 if ( rendererContext.mapToPixel().mapRotation() )
101 {
102 // unset rotation for the sake of local computations.
103 // Rotation will be handled by QPainter later
104 // TODO: provide a method of QgsMapToPixel to fetch map center
105 // in geographical units
106 const QgsPointXY center = mapToPixel.toMapCoordinates(
107 static_cast<int>( mapToPixel.mapWidth() / 2.0 ),
108 static_cast<int>( mapToPixel.mapHeight() / 2.0 )
109 );
110 mapToPixel.setMapRotation( 0, center.x(), center.y() );
111 }
112
113 QgsRectangle myProjectedViewExtent;
114 QgsRectangle myProjectedLayerExtent;
115
116 if ( rendererContext.coordinateTransform().isValid() )
117 {
118 QgsDebugMsgLevel( QStringLiteral( "coordinateTransform set -> project extents." ), 4 );
119 if ( rendererContext.extent().xMinimum() == std::numeric_limits<double>::lowest() &&
120 rendererContext.extent().yMinimum() == std::numeric_limits<double>::lowest() &&
121 rendererContext.extent().xMaximum() == std::numeric_limits<double>::max() &&
122 rendererContext.extent().yMaximum() == std::numeric_limits<double>::max() )
123 {
124 // We get in this situation if the view CRS is geographical and the
125 // extent goes beyond -180,-90,180,90. To avoid reprojection issues to the
126 // layer CRS, then this dummy extent is returned by QgsMapRendererJob::reprojectToLayerExtent()
127 // Don't try to reproject it now to view extent as this would return
128 // a null rectangle.
129 myProjectedViewExtent = rendererContext.extent();
130 }
131 else
132 {
133 try
134 {
135 QgsCoordinateTransform ct = rendererContext.coordinateTransform();
137 myProjectedViewExtent = ct.transformBoundingBox( rendererContext.extent() );
138 }
139 catch ( QgsCsException &cs )
140 {
141 QgsMessageLog::logMessage( QObject::tr( "Could not reproject view extent: %1" ).arg( cs.what() ), QObject::tr( "Raster" ) );
142 myProjectedViewExtent.setNull();
143 }
144 }
145
146 try
147 {
148 QgsCoordinateTransform ct = rendererContext.coordinateTransform();
150 myProjectedLayerExtent = ct.transformBoundingBox( layer->extent() );
151 }
152 catch ( QgsCsException &cs )
153 {
154 QgsMessageLog::logMessage( QObject::tr( "Could not reproject layer extent: %1" ).arg( cs.what() ), QObject::tr( "Raster" ) );
155 myProjectedLayerExtent.setNull();
156 }
157 }
158 else
159 {
160 QgsDebugMsgLevel( QStringLiteral( "coordinateTransform not set" ), 4 );
161 myProjectedViewExtent = rendererContext.extent();
162 myProjectedLayerExtent = layer->extent();
163 }
164
165 // clip raster extent to view extent
166 QgsRectangle myRasterExtent = layer->ignoreExtents() ? myProjectedViewExtent : myProjectedViewExtent.intersect( myProjectedLayerExtent );
167 if ( myRasterExtent.isEmpty() )
168 {
169 QgsDebugMsgLevel( QStringLiteral( "draw request outside view extent." ), 2 );
170 // nothing to do
171 return;
172 }
173
174 QgsDebugMsgLevel( "theViewExtent is " + rendererContext.extent().toString(), 4 );
175 QgsDebugMsgLevel( "myProjectedViewExtent is " + myProjectedViewExtent.toString(), 4 );
176 QgsDebugMsgLevel( "myProjectedLayerExtent is " + myProjectedLayerExtent.toString(), 4 );
177 QgsDebugMsgLevel( "myRasterExtent is " + myRasterExtent.toString(), 4 );
178
179 //
180 // The first thing we do is set up the QgsRasterViewPort. This struct stores all the settings
181 // relating to the size (in pixels and coordinate system units) of the raster part that is
182 // in view in the map window. It also stores the origin.
183 //
184 //this is not a class level member because every time the user pans or zooms
185 //the contents of the rasterViewPort will change
186 mRasterViewPort = new QgsRasterViewPort();
187
188 mRasterViewPort->mDrawnExtent = myRasterExtent;
189 if ( rendererContext.coordinateTransform().isValid() )
190 {
191 mRasterViewPort->mSrcCRS = layer->crs();
192 mRasterViewPort->mDestCRS = rendererContext.coordinateTransform().destinationCrs();
193 mRasterViewPort->mTransformContext = rendererContext.transformContext();
194 }
195 else
196 {
197 mRasterViewPort->mSrcCRS = QgsCoordinateReferenceSystem(); // will be invalid
198 mRasterViewPort->mDestCRS = QgsCoordinateReferenceSystem(); // will be invalid
199 }
200
201 // get dimensions of clipped raster image in device coordinate space (this is the size of the viewport)
202 mRasterViewPort->mTopLeftPoint = mapToPixel.transform( myRasterExtent.xMinimum(), myRasterExtent.yMaximum() );
203 mRasterViewPort->mBottomRightPoint = mapToPixel.transform( myRasterExtent.xMaximum(), myRasterExtent.yMinimum() );
204
205 // align to output device grid, i.e. std::floor/ceil to integers
206 // TODO: this should only be done if paint device is raster - screen, image
207 // for other devices (pdf) it can have floating point origin
208 // we could use floating point for raster devices as well, but respecting the
209 // output device grid should make it more effective as the resampling is done in
210 // the provider anyway
211 mRasterViewPort->mTopLeftPoint.setX( std::floor( mRasterViewPort->mTopLeftPoint.x() ) );
212 mRasterViewPort->mTopLeftPoint.setY( std::floor( mRasterViewPort->mTopLeftPoint.y() ) );
213 mRasterViewPort->mBottomRightPoint.setX( std::ceil( mRasterViewPort->mBottomRightPoint.x() ) );
214 mRasterViewPort->mBottomRightPoint.setY( std::ceil( mRasterViewPort->mBottomRightPoint.y() ) );
215 // recalc myRasterExtent to aligned values
216 myRasterExtent.set(
217 mapToPixel.toMapCoordinates( mRasterViewPort->mTopLeftPoint.x(),
218 mRasterViewPort->mBottomRightPoint.y() ),
219 mapToPixel.toMapCoordinates( mRasterViewPort->mBottomRightPoint.x(),
220 mRasterViewPort->mTopLeftPoint.y() )
221 );
222
223 //raster viewport top left / bottom right are already rounded to int
224 mRasterViewPort->mWidth = static_cast<qgssize>( std::abs( mRasterViewPort->mBottomRightPoint.x() - mRasterViewPort->mTopLeftPoint.x() ) );
225 mRasterViewPort->mHeight = static_cast<qgssize>( std::abs( mRasterViewPort->mBottomRightPoint.y() - mRasterViewPort->mTopLeftPoint.y() ) );
226
227 double dpi = 25.4 * rendererContext.scaleFactor();
228 if ( mProviderCapabilities & Qgis::RasterProviderCapability::DpiDependentData
229 && rendererContext.dpiTarget() >= 0.0 )
230 {
231 const double dpiScaleFactor = rendererContext.dpiTarget() / dpi;
232 mRasterViewPort->mWidth *= dpiScaleFactor;
233 mRasterViewPort->mHeight *= dpiScaleFactor;
234 dpi = rendererContext.dpiTarget();
235 }
236 else
237 {
238 rendererContext.setDpiTarget( -1.0 );
239 }
240
241 //the drawable area can start to get very very large when you get down displaying 2x2 or smaller, this is because
242 //mapToPixel.mapUnitsPerPixel() is less then 1,
243 //so we will just get the pixel data and then render these special cases differently in paintImageToCanvas()
244
245 QgsDebugMsgLevel( QStringLiteral( "mapUnitsPerPixel = %1" ).arg( mapToPixel.mapUnitsPerPixel() ), 3 );
246 QgsDebugMsgLevel( QStringLiteral( "mWidth = %1" ).arg( layer->width() ), 3 );
247 QgsDebugMsgLevel( QStringLiteral( "mHeight = %1" ).arg( layer->height() ), 3 );
248 QgsDebugMsgLevel( QStringLiteral( "myRasterExtent.xMinimum() = %1" ).arg( myRasterExtent.xMinimum() ), 3 );
249 QgsDebugMsgLevel( QStringLiteral( "myRasterExtent.xMaximum() = %1" ).arg( myRasterExtent.xMaximum() ), 3 );
250 QgsDebugMsgLevel( QStringLiteral( "myRasterExtent.yMinimum() = %1" ).arg( myRasterExtent.yMinimum() ), 3 );
251 QgsDebugMsgLevel( QStringLiteral( "myRasterExtent.yMaximum() = %1" ).arg( myRasterExtent.yMaximum() ), 3 );
252
253 QgsDebugMsgLevel( QStringLiteral( "mTopLeftPoint.x() = %1" ).arg( mRasterViewPort->mTopLeftPoint.x() ), 3 );
254 QgsDebugMsgLevel( QStringLiteral( "mBottomRightPoint.x() = %1" ).arg( mRasterViewPort->mBottomRightPoint.x() ), 3 );
255 QgsDebugMsgLevel( QStringLiteral( "mTopLeftPoint.y() = %1" ).arg( mRasterViewPort->mTopLeftPoint.y() ), 3 );
256 QgsDebugMsgLevel( QStringLiteral( "mBottomRightPoint.y() = %1" ).arg( mRasterViewPort->mBottomRightPoint.y() ), 3 );
257
258 QgsDebugMsgLevel( QStringLiteral( "mWidth = %1" ).arg( mRasterViewPort->mWidth ), 3 );
259 QgsDebugMsgLevel( QStringLiteral( "mHeight = %1" ).arg( mRasterViewPort->mHeight ), 3 );
260
261 // /\/\/\ - added to handle zoomed-in rasters
262
263 // TODO R->mLastViewPort = *mRasterViewPort;
264
265 // TODO: is it necessary? Probably WMS only?
266 layer->dataProvider()->setDpi( std::floor( dpi * rendererContext.devicePixelRatio() ) );
267
268 // copy the whole raster pipe!
269 mPipe.reset( new QgsRasterPipe( *layer->pipe() ) );
270
271 QObject::connect( mPipe->provider(), &QgsRasterDataProvider::statusChanged, layer, &QgsRasterLayer::statusChanged );
272 QgsRasterRenderer *rasterRenderer = mPipe->renderer();
273 if ( rasterRenderer
274 && !( rendererContext.flags() & Qgis::RenderContextFlag::RenderPreviewJob )
275 && !( rendererContext.flags() & Qgis::RenderContextFlag::Render3DMap ) )
276 {
277 if ( rasterRenderer->needsRefresh( rendererContext.extent() ) )
278 {
279 QList<double> minValues;
280 QList<double> maxValues;
281 const QgsRasterMinMaxOrigin &minMaxOrigin = rasterRenderer->minMaxOrigin();
282 for ( const int bandIdx : rasterRenderer->usesBands() )
283 {
284 double min;
285 double max;
286 layer->computeMinMax( bandIdx, minMaxOrigin, minMaxOrigin.limits(),
287 rendererContext.extent(), static_cast<int>( QgsRasterLayer::SAMPLE_SIZE ),
288 min, max );
289 minValues.append( min );
290 maxValues.append( max );
291 }
292
293 rasterRenderer->refresh( rendererContext.extent(), minValues, maxValues );
294 QgsRenderedLayerStatistics *layerStatistics = new QgsRenderedLayerStatistics( layer->id(), minValues, maxValues );
295 layerStatistics->setBoundingBox( rendererContext.extent() );
296 appendRenderedItemDetails( layerStatistics );
297 }
298 }
299
300 mPipe->evaluateDataDefinedProperties( rendererContext.expressionContext() );
301
302 const QgsRasterLayerTemporalProperties *temporalProperties = qobject_cast< const QgsRasterLayerTemporalProperties * >( layer->temporalProperties() );
303 const QgsRasterLayerElevationProperties *elevationProperties = qobject_cast<QgsRasterLayerElevationProperties *>( layer->elevationProperties() );
304
305 if ( ( temporalProperties->isActive() && renderContext()->isTemporal() )
306 || ( elevationProperties->hasElevation() && !renderContext()->zRange().isInfinite() ) )
307 {
308 // temporal and/or elevation band filtering may be applicable
309 bool matched = false;
311 layer,
312 rendererContext.temporalRange(),
313 rendererContext.zRange(),
314 matched
315 );
316 if ( matched && matchedBand > 0 )
317 {
318 mPipe->renderer()->setInputBand( matchedBand );
319 }
320 }
321
322 if ( temporalProperties->isActive() && renderContext()->isTemporal() )
323 {
324 switch ( temporalProperties->mode() )
325 {
329 break;
330
332 if ( mPipe->renderer()->usesBands().contains( temporalProperties->bandNumber() ) )
333 {
334 // if layer has elevation settings and we are only rendering a temporal range => we need to filter pixels by temporal values
335 std::unique_ptr< QgsRasterTransparency > transparency;
336 if ( const QgsRasterTransparency *rendererTransparency = mPipe->renderer()->rasterTransparency() )
337 transparency = std::make_unique< QgsRasterTransparency >( *rendererTransparency );
338 else
339 transparency = std::make_unique< QgsRasterTransparency >();
340
341 QVector<QgsRasterTransparency::TransparentSingleValuePixel> transparentPixels = transparency->transparentSingleValuePixelList();
342
343 const QDateTime &offset = temporalProperties->temporalRepresentationOffset();
344 const QgsInterval &scale = temporalProperties->temporalRepresentationScale();
345 const double adjustedLower = static_cast< double >( offset.msecsTo( rendererContext.temporalRange().begin() ) ) * QgsUnitTypes::fromUnitToUnitFactor( Qgis::TemporalUnit::Milliseconds, scale.originalUnit() ) / scale.originalDuration();
346 const double adjustedUpper = static_cast< double >( offset.msecsTo( rendererContext.temporalRange().end() ) ) * QgsUnitTypes::fromUnitToUnitFactor( Qgis::TemporalUnit::Milliseconds, scale.originalUnit() ) / scale.originalDuration();
347 transparentPixels.append( QgsRasterTransparency::TransparentSingleValuePixel( std::numeric_limits<double>::lowest(), adjustedLower, 0, true, !rendererContext.zRange().includeLower() ) );
348 transparentPixels.append( QgsRasterTransparency::TransparentSingleValuePixel( adjustedUpper, std::numeric_limits<double>::max(), 0, !rendererContext.zRange().includeUpper(), true ) );
349
350 transparency->setTransparentSingleValuePixelList( transparentPixels );
351 mPipe->renderer()->setRasterTransparency( transparency.release() );
352 }
353 break;
354
356 // in this mode we need to pass on the desired render temporal range to the data provider
357 if ( QgsRasterDataProviderTemporalCapabilities *temporalCapabilities = mPipe->provider()->temporalCapabilities() )
358 {
359 temporalCapabilities->setRequestedTemporalRange( rendererContext.temporalRange() );
360 temporalCapabilities->setIntervalHandlingMethod( temporalProperties->intervalHandlingMethod() );
361 }
362 break;
363 }
364 }
365 else if ( QgsRasterDataProviderTemporalCapabilities *temporalCapabilities = mPipe->provider()->temporalCapabilities() )
366 {
367 temporalCapabilities->setRequestedTemporalRange( QgsDateTimeRange() );
368 temporalCapabilities->setIntervalHandlingMethod( temporalProperties->intervalHandlingMethod() );
369 }
370
372
373 if ( elevationProperties && elevationProperties->hasElevation() )
374 {
375 mDrawElevationMap = true;
376 mElevationScale = elevationProperties->zScale();
377 mElevationOffset = elevationProperties->zOffset();
378 mElevationBand = elevationProperties->bandNumber();
379
380 if ( !rendererContext.zRange().isInfinite() )
381 {
382 // NOLINTBEGIN(bugprone-branch-clone)
383 switch ( elevationProperties->mode() )
384 {
386 // don't need to handle anything here -- the layer renderer will never be created if the
387 // render context range doesn't match the layer's fixed elevation range
388 break;
389
392 // temporal/elevation band based filtering was already handled earlier in this method
393 break;
394
396 {
397 if ( mPipe->renderer()->usesBands().contains( mElevationBand ) )
398 {
399 // if layer has elevation settings and we are only rendering a slice of z values => we need to filter pixels by elevation
400 if ( mPipe->renderer()->flags() & Qgis::RasterRendererFlag::UseNoDataForOutOfRangePixels )
401 {
402 std::unique_ptr< QgsRasterNuller> nuller;
403 if ( const QgsRasterNuller *existingNuller = mPipe->nuller() )
404 nuller.reset( existingNuller->clone() );
405 else
406 nuller = std::make_unique< QgsRasterNuller >();
407
408 // account for z offset/zscale by reversing these calculations, so that we get the z range in
409 // raw pixel values
410 QgsRasterRangeList nullRanges;
411 const double adjustedLower = ( rendererContext.zRange().lower() - mElevationOffset ) / mElevationScale;
412 const double adjustedUpper = ( rendererContext.zRange().upper() - mElevationOffset ) / mElevationScale;
413 nullRanges.append( QgsRasterRange( std::numeric_limits<double>::lowest(), adjustedLower, rendererContext.zRange().includeLower() ? QgsRasterRange::BoundsType::IncludeMin : QgsRasterRange::BoundsType::IncludeMinAndMax ) );
414 nullRanges.append( QgsRasterRange( adjustedUpper, std::numeric_limits<double>::max(), rendererContext.zRange().includeUpper() ? QgsRasterRange::BoundsType::IncludeMax : QgsRasterRange::BoundsType::IncludeMinAndMax ) );
415 nuller->setOutputNoDataValue( mElevationBand, static_cast< int >( adjustedLower - 1 ) );
416 nuller->setNoData( mElevationBand, nullRanges );
417
418 if ( !mPipe->insert( 1, nuller.release() ) )
419 {
420 QgsDebugError( QStringLiteral( "Cannot set pipe nuller" ) );
421 }
422 }
423 else
424 {
425 std::unique_ptr< QgsRasterTransparency > transparency;
426 if ( const QgsRasterTransparency *rendererTransparency = mPipe->renderer()->rasterTransparency() )
427 transparency = std::make_unique< QgsRasterTransparency >( *rendererTransparency );
428 else
429 transparency = std::make_unique< QgsRasterTransparency >();
430
431 QVector<QgsRasterTransparency::TransparentSingleValuePixel> transparentPixels = transparency->transparentSingleValuePixelList();
432
433 // account for z offset/zscale by reversing these calculations, so that we get the z range in
434 // raw pixel values
435 const double adjustedLower = ( rendererContext.zRange().lower() - mElevationOffset ) / mElevationScale;
436 const double adjustedUpper = ( rendererContext.zRange().upper() - mElevationOffset ) / mElevationScale;
437 transparentPixels.append( QgsRasterTransparency::TransparentSingleValuePixel( std::numeric_limits<double>::lowest(), adjustedLower, 0, true, !rendererContext.zRange().includeLower() ) );
438 transparentPixels.append( QgsRasterTransparency::TransparentSingleValuePixel( adjustedUpper, std::numeric_limits<double>::max(), 0, !rendererContext.zRange().includeUpper(), true ) );
439
440 transparency->setTransparentSingleValuePixelList( transparentPixels );
441 mPipe->renderer()->setRasterTransparency( transparency.release() );
442 }
443 }
444 break;
445 }
446 }
447 // NOLINTEND(bugprone-branch-clone)
448 }
449 }
450
451 mFeedback->setRenderContext( rendererContext );
452
453 mPipe->moveToThread( nullptr );
454
455 mPreparationTime = timer.elapsed();
456}
457
459{
460 delete mFeedback;
461
462 delete mRasterViewPort;
463}
464
466{
467 std::unique_ptr< QgsScopedRuntimeProfile > profile;
468 if ( mEnableProfile )
469 {
470 profile = std::make_unique< QgsScopedRuntimeProfile >( mLayerName, QStringLiteral( "rendering" ), layerId() );
471 if ( mPreparationTime > 0 )
472 QgsApplication::profiler()->record( QObject::tr( "Create renderer" ), mPreparationTime / 1000.0, QStringLiteral( "rendering" ) );
473 }
474
475 // Skip rendering of out of view tiles (xyz)
476 if ( !mRasterViewPort || ( renderContext()->testFlag( Qgis::RenderContextFlag::RenderPreviewJob ) &&
477 !( mInterfaceCapabilities &
479 return true;
480
481 mPipe->moveToThread( QThread::currentThread() );
482
483 QElapsedTimer time;
484 time.start();
485
486 std::unique_ptr< QgsScopedRuntimeProfile > preparingProfile;
487 if ( mEnableProfile )
488 {
489 preparingProfile = std::make_unique< QgsScopedRuntimeProfile >( QObject::tr( "Preparing render" ), QStringLiteral( "rendering" ) );
490 }
491
492 //
493 //
494 // The goal here is to make as many decisions as possible early on (outside of the rendering loop)
495 // so that we can maximise performance of the rendering process. So now we check which drawing
496 // procedure to use :
497 //
498
499 const QgsScopedQPainterState painterSate( renderContext()->painter() );
500 if ( !mClippingRegions.empty() )
501 {
502 bool needsPainterClipPath = false;
503 const QPainterPath path = QgsMapClippingUtils::calculatePainterClipRegion( mClippingRegions, *renderContext(), Qgis::LayerType::Raster, needsPainterClipPath );
504 if ( needsPainterClipPath )
505 renderContext()->painter()->setClipPath( path, Qt::IntersectClip );
506 }
507
508 QgsRasterProjector *projector = mPipe->projector();
509 bool restoreOldResamplingStage = false;
510 const Qgis::RasterResamplingStage oldResamplingState = mPipe->resamplingStage();
511
512 // TODO add a method to interface to get provider and get provider
513 // params in QgsRasterProjector
514 if ( projector )
515 {
516 // Force provider resampling if reprojection is needed
517 if ( ( mPipe->provider()->providerCapabilities() & Qgis::RasterProviderCapability::ProviderHintCanPerformProviderResampling ) &&
518 mRasterViewPort->mSrcCRS != mRasterViewPort->mDestCRS &&
519 oldResamplingState != Qgis::RasterResamplingStage::Provider )
520 {
521 restoreOldResamplingStage = true;
522 mPipe->setResamplingStage( Qgis::RasterResamplingStage::Provider );
523 }
524 projector->setCrs( mRasterViewPort->mSrcCRS, mRasterViewPort->mDestCRS, mRasterViewPort->mTransformContext );
525 }
526
527 // important -- disable SmoothPixmapTransform for raster layer renders. We want individual pixels to be clearly defined!
528 renderContext()->painter()->setRenderHint( QPainter::SmoothPixmapTransform, false );
529
530 preparingProfile.reset();
531 std::unique_ptr< QgsScopedRuntimeProfile > renderingProfile;
532 if ( mEnableProfile )
533 {
534 renderingProfile = std::make_unique< QgsScopedRuntimeProfile >( QObject::tr( "Rendering" ), QStringLiteral( "rendering" ) );
535 }
536
537 // Drawer to pipe?
538 QgsRasterIterator iterator( mPipe->last() );
539
540 // Get the maximum tile size from the provider and set it as the maximum tile size for the iterator
541 if ( QgsRasterDataProvider *provider = mPipe->provider() )
542 {
543 const QSize maxTileSize {provider->maximumTileSize()};
544 iterator.setMaximumTileWidth( maxTileSize.width() );
545 iterator.setMaximumTileHeight( maxTileSize.height() );
546 }
547
548 QgsRasterDrawer drawer( &iterator );
549 drawer.draw( *( renderContext() ), mRasterViewPort, mFeedback );
550
551 if ( mDrawElevationMap )
552 drawElevationMap();
553
554 if ( restoreOldResamplingStage )
555 {
556 mPipe->setResamplingStage( oldResamplingState );
557 }
558
559 const QStringList errors = mFeedback->errors();
560 for ( const QString &error : errors )
561 {
562 mErrors.append( error );
563 }
564
565 QgsDebugMsgLevel( QStringLiteral( "total raster draw time (ms): %1" ).arg( time.elapsed(), 5 ), 4 );
566 mReadyToCompose = true;
567
568 mPipe->moveToThread( nullptr );
569
570 return !mFeedback->isCanceled();
571}
572
574{
575 return mFeedback;
576}
577
579{
580 if ( !mRasterViewPort || !mPipe )
581 return false; // this layer is not going to get rendered
582
583 // preview of intermediate raster rendering results requires a temporary output image
585 return true;
586
587 if ( QgsRasterRenderer *renderer = mPipe->renderer() )
588 {
590 && renderContext()->testFlag( Qgis::RenderContextFlag::UseAdvancedEffects ) && ( !qgsDoubleNear( mLayerOpacity, 1.0 ) ) )
591 return true;
592 }
593
594 return false;
595}
596
597void QgsRasterLayerRenderer::drawElevationMap()
598{
599 QgsRasterDataProvider *dataProvider = mPipe->provider();
600 if ( renderContext()->elevationMap() && dataProvider )
601 {
602 double dpiScalefactor;
603
604 if ( renderContext()->dpiTarget() >= 0.0 )
605 dpiScalefactor = renderContext()->dpiTarget() / ( renderContext()->scaleFactor() * 25.4 );
606 else
607 dpiScalefactor = 1.0;
608
609 int outputWidth = static_cast<int>( static_cast<double>( mRasterViewPort->mWidth ) / dpiScalefactor * renderContext()->devicePixelRatio() );
610 int outputHeight = static_cast<int>( static_cast<double>( mRasterViewPort->mHeight ) / dpiScalefactor * renderContext()->devicePixelRatio() );
611
612 QSize viewSize = renderContext()->deviceOutputSize();
613 int viewWidth = static_cast<int>( viewSize.width() / dpiScalefactor );
614 int viewHeight = static_cast<int>( viewSize.height() / dpiScalefactor );
615
616 bool canRenderElevation = false;
617 std::unique_ptr<QgsRasterBlock> elevationBlock;
618 if ( mRasterViewPort->mSrcCRS == mRasterViewPort->mDestCRS )
619 {
620 elevationBlock.reset(
621 dataProvider->block(
622 mElevationBand,
623 mRasterViewPort->mDrawnExtent,
624 outputWidth,
625 outputHeight,
626 mFeedback ) );
627 canRenderElevation = true;
628 }
629 else
630 {
631 // Destinaton CRS is different from the source CRS.
632 // Using the raster projector lead to have big artifacts when rendering the elevation map.
633 // To get a smoother elevation map, we use GDAL resampling with coordinates transform
634 QgsRectangle viewExtentInLayerCoordinate = renderContext()->extent();
635
636 // If view extent is infinite, we use the data provider extent
637 if ( viewExtentInLayerCoordinate.xMinimum() == std::numeric_limits<double>::lowest() &&
638 viewExtentInLayerCoordinate.yMinimum() == std::numeric_limits<double>::lowest() &&
639 viewExtentInLayerCoordinate.xMaximum() == std::numeric_limits<double>::max() &&
640 viewExtentInLayerCoordinate.yMaximum() == std::numeric_limits<double>::max() )
641 {
642 viewExtentInLayerCoordinate = dataProvider->extent();
643 }
644
645 double xLayerResol = viewExtentInLayerCoordinate.width() / static_cast<double>( viewWidth );
646 double yLayerResol = viewExtentInLayerCoordinate.height() / static_cast<double>( viewHeight );
647
648 double overSampling = 1;
649 if ( mPipe->resampleFilter() )
650 overSampling = mPipe->resampleFilter()->maxOversampling();
651
653 {
654 // If the dataprovider has size capability, we calculate the requested resolution to provider
655 double providerXResol = dataProvider->extent().width() / dataProvider->xSize();
656 double providerYResol = dataProvider->extent().height() / dataProvider->ySize();
657 overSampling = ( xLayerResol / providerXResol + yLayerResol / providerYResol ) / 2;
658 }
659
660 GDALResampleAlg alg;
661 if ( overSampling > 1 )
663 else
665
666 Qgis::DataType dataType = dataProvider->dataType( mElevationBand );
667
668 if ( dataType != Qgis::DataType::UnknownDataType ) // resampling data by GDAL is not compatible with unknown data type
669 {
670 // we need extra pixels on border to avoid effect border with resampling (at least 2 pixels band for cubic alg)
671 int sourceWidth = viewWidth + 4;
672 int sourceHeight = viewHeight + 4;
673 viewExtentInLayerCoordinate = QgsRectangle(
674 viewExtentInLayerCoordinate.xMinimum() - xLayerResol * 2,
675 viewExtentInLayerCoordinate.yMinimum() - yLayerResol * 2,
676 viewExtentInLayerCoordinate.xMaximum() + xLayerResol * 2,
677 viewExtentInLayerCoordinate.yMaximum() + yLayerResol * 2 );
678
679 // Now we can do the resampling
680 std::unique_ptr<QgsRasterBlock> sourcedata( dataProvider->block( mElevationBand, viewExtentInLayerCoordinate, sourceWidth, sourceHeight, mFeedback ) );
681 gdal::dataset_unique_ptr gdalDsInput =
682 QgsGdalUtils::blockToSingleBandMemoryDataset( viewExtentInLayerCoordinate, sourcedata.get() );
683
684
685 elevationBlock.reset( new QgsRasterBlock( dataType,
686 outputWidth,
687 outputHeight ) );
688
689 elevationBlock->setNoDataValue( dataProvider->sourceNoDataValue( mElevationBand ) );
690
691 gdal::dataset_unique_ptr gdalDsOutput =
692 QgsGdalUtils::blockToSingleBandMemoryDataset( mRasterViewPort->mDrawnExtent, elevationBlock.get() );
693
694 // For coordinate transformation, we try to obtain a coordinate operation string from the transform context.
695 // Depending of the CRS, if we can't we use GDAL transformation directly from the source and destination CRS
696 QString coordinateOperation;
697 const QgsCoordinateTransformContext &transformContext = renderContext()->transformContext();
698 if ( transformContext.mustReverseCoordinateOperation( mRasterViewPort->mSrcCRS, mRasterViewPort->mDestCRS ) )
699 coordinateOperation = transformContext.calculateCoordinateOperation( mRasterViewPort->mDestCRS, mRasterViewPort->mSrcCRS );
700 else
701 coordinateOperation = transformContext.calculateCoordinateOperation( mRasterViewPort->mSrcCRS, mRasterViewPort->mDestCRS );
702
703 if ( coordinateOperation.isEmpty() )
704 canRenderElevation = QgsGdalUtils::resampleSingleBandRaster( gdalDsInput.get(), gdalDsOutput.get(), alg,
705 mRasterViewPort->mSrcCRS, mRasterViewPort->mDestCRS );
706 else
707 canRenderElevation = QgsGdalUtils::resampleSingleBandRaster( gdalDsInput.get(), gdalDsOutput.get(), alg,
708 coordinateOperation.toUtf8().constData() );
709 }
710 }
711
712 if ( canRenderElevation )
713 {
714 QPoint topLeft;
715 if ( renderContext()->mapToPixel().mapRotation() != 0 )
716 {
717 // Now rendering elevation on the elevation map, we need to take care of rotation:
718 // again a resampling but this time with a geotransform.
719 const QgsMapToPixel &mtp = renderContext()->mapToPixel();
721
722 int elevMapWidth = elevMap->rawElevationImage().width();
723 int elevMapHeight = elevMap->rawElevationImage().height();
724
725 int bottom = 0;
726 int top = elevMapHeight;
727 int left = elevMapWidth;
728 int right = 0;
729
730 QList<QgsPointXY> corners;
731 corners << QgsPointXY( mRasterViewPort->mDrawnExtent.xMinimum(), mRasterViewPort->mDrawnExtent.yMinimum() )
732 << QgsPointXY( mRasterViewPort->mDrawnExtent.xMaximum(), mRasterViewPort->mDrawnExtent.yMaximum() )
733 << QgsPointXY( mRasterViewPort->mDrawnExtent.xMinimum(), mRasterViewPort->mDrawnExtent.yMaximum() )
734 << QgsPointXY( mRasterViewPort->mDrawnExtent.xMaximum(), mRasterViewPort->mDrawnExtent.yMinimum() );
735
736 for ( const QgsPointXY &corner : std::as_const( corners ) )
737 {
738 const QgsPointXY dpt = mtp.transform( corner );
739 int x = static_cast<int>( std::round( dpt.x() ) );
740 int y = static_cast<int>( std::round( dpt.y() ) );
741
742 if ( x < left )
743 left = x;
744 if ( x > right )
745 right = x;
746 if ( y < top )
747 top = y;
748 if ( y > bottom )
749 bottom = y;
750 }
751
752 const QgsPointXY origin = mtp.toMapCoordinates( left, top );
753 double gridXSize = mtp.toMapCoordinates( right, top ).distance( origin );
754 double gridYSize = mtp.toMapCoordinates( left, bottom ).distance( origin );
755 double angleRad = renderContext()->mapToPixel().mapRotation() / 180 * M_PI;
756
757 gdal::dataset_unique_ptr gdalDsInput =
758 QgsGdalUtils::blockToSingleBandMemoryDataset( mRasterViewPort->mDrawnExtent, elevationBlock.get() );
759
760 std::unique_ptr<QgsRasterBlock> rotatedElevationBlock =
761 std::make_unique<QgsRasterBlock>( elevationBlock->dataType(),
762 ( right - left ) * renderContext()->devicePixelRatio() + 1,
763 ( bottom - top ) * renderContext()->devicePixelRatio() + 1 );
764
765 rotatedElevationBlock->setNoDataValue( elevationBlock->noDataValue() );
766
767 gdal::dataset_unique_ptr gdalDsOutput =
768 QgsGdalUtils::blockToSingleBandMemoryDataset( angleRad, origin, gridXSize, gridYSize, rotatedElevationBlock.get() );
769
771 gdalDsInput.get(),
772 gdalDsOutput.get(),
774 {
775 elevationBlock.reset( rotatedElevationBlock.release() );
776 }
777
778 topLeft = QPoint( left, top );
779 }
780 else
781 {
782 topLeft = mRasterViewPort->mTopLeftPoint.toQPointF().toPoint();
783 }
784
786 elevationBlock.get(),
787 topLeft.y() * renderContext()->devicePixelRatio(),
788 topLeft.x() * renderContext()->devicePixelRatio(),
789 mElevationScale,
790 mElevationOffset );
791 }
792 }
793}
The Qgis class provides global constants for use throughout the application.
Definition qgis.h:54
RasterResamplingStage
Stage at which raster resampling occurs.
Definition qgis.h:1380
@ 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.
@ 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.
@ UseAdvancedEffects
Enable layer opacity and blending effects.
static QgsRuntimeProfiler * profiler()
Returns the application runtime profiler.
This class 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...
Class for doing transforms between two map coordinate systems.
void setBallparkTransformsAreAppropriate(bool appropriate)
Sets whether approximate "ballpark" results are appropriate for this coordinate transform.
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:285
Stores digital elevation model in a raster image which may get updated as a part of map layer renderi...
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 GDALResampleAlg gdalResamplingAlgorithm(QgsRasterDataProvider::ResamplingMethod method)
Returns the GDAL resampling method corresponding to the QGIS resampling method.
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 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.
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:83
QString id
Definition qgsmaplayer.h:79
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)
Adds a message to the log instance (and creates it if necessary).
A class to represent 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.
virtual double sourceNoDataValue(int bandNo) const
Value representing no data value.
ResamplingMethod zoomedOutResamplingMethod() const
Returns resampling method for zoomed-out operations.
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.
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,...
ResamplingMethod zoomedInResamplingMethod() const
Returns resampling method for zoomed-in operations.
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.
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.
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.
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.
This class describes the origin of min/max values.
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.
Raster values range container.
@ 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.
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.
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.
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:444
T end() const
Returns the upper bound of the range.
Definition qgsrange.h:451
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:6572
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
Definition qgis.h:6024
#define QgsDebugMsgLevel(str, level)
Definition qgslogger.h:39
#define QgsDebugError(str)
Definition qgslogger.h:38
QgsTemporalRange< QDateTime > QgsDateTimeRange
QgsRange which stores a range of date times.
Definition qgsrange.h:742
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 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 coordinate system.
QgsRectangle mDrawnExtent
Intersection of current map extent and layer extent.
QgsCoordinateTransformContext mTransformContext
Coordinate transform context.
qgssize mWidth
Width, number of columns to be rendered.