QGIS API Documentation 4.0.0-Norrköping (1ddcee3d0e4)
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
18#include <memory>
19
20#include "qgsapplication.h"
21#include "qgselevationmap.h"
22#include "qgsexception.h"
23#include "qgsgdalutils.h"
24#include "qgsinterval.h"
25#include "qgsmapclippingutils.h"
26#include "qgsmessagelog.h"
28#include "qgsrasterdrawer.h"
29#include "qgsrasteriterator.h"
30#include "qgsrasterlabeling.h"
31#include "qgsrasterlayer.h"
34#include "qgsrasterlayerutils.h"
35#include "qgsrasternuller.h"
36#include "qgsrasterpipe.h"
37#include "qgsrasterprojector.h"
38#include "qgsrasterrenderer.h"
41#include "qgsrendercontext.h"
43#include "qgsruntimeprofiler.h"
44#include "qgsthreadingutils.h"
45#include "qgsunittypes.h"
46
47#include <QElapsedTimer>
48#include <QPointer>
49#include <QString>
50#include <QThread>
51
52#include "moc_qgsrasterlayerrenderer.cpp"
53
54using namespace Qt::StringLiterals;
55
57
58QgsRasterLayerRendererFeedback::QgsRasterLayerRendererFeedback( QgsRasterLayerRenderer *r )
59 : mR( r )
60{
62}
63
64void QgsRasterLayerRendererFeedback::onNewData()
65{
66 if ( !renderPartialOutput() )
67 return; // we were not asked for partial renders and we may not have a temporary image for overwriting...
68
69 // update only once upon a time
70 // (preview itself takes some time)
71 if ( mLastPreview.isValid() && mLastPreview.msecsTo( QTime::currentTime() ) < mMinimalPreviewInterval )
72 return;
73
74 // TODO: update only the area that got new data
75
76 QgsDebugMsgLevel( u"new raster preview! %1"_s.arg( mLastPreview.msecsTo( QTime::currentTime() ) ), 3 );
77 QElapsedTimer t;
78 t.start();
80 feedback.setPreviewOnly( true );
81 feedback.setRenderPartialOutput( true );
82 QgsRasterIterator iterator( mR->mPipe->last() );
83 QgsRasterDrawer drawer( &iterator );
84 drawer.draw( *( mR->renderContext() ), mR->mRasterViewPort, &feedback );
85 mR->mReadyToCompose = true;
86 QgsDebugMsgLevel( u"total raster preview time: %1 ms"_s.arg( t.elapsed() ), 3 );
87 mLastPreview = QTime::currentTime();
88}
89
93 : QgsMapLayerRenderer( layer->id(), &rendererContext )
94 , mLayerName( layer->name() )
95 , mLayerOpacity( layer->opacity() )
96 , mProviderCapabilities( layer->dataProvider()->providerCapabilities() )
97 , mInterfaceCapabilities( layer->dataProvider()->capabilities() )
98 , mFeedback( new QgsRasterLayerRendererFeedback( this ) )
99 , mEnableProfile( rendererContext.flags() & Qgis::RenderContextFlag::RecordProfile )
100{
101 mReadyToCompose = false;
102
103 QElapsedTimer timer;
104 timer.start();
105
106 QgsMapToPixel mapToPixel = rendererContext.mapToPixel();
107 if ( rendererContext.mapToPixel().mapRotation() )
108 {
109 // unset rotation for the sake of local computations.
110 // Rotation will be handled by QPainter later
111 // TODO: provide a method of QgsMapToPixel to fetch map center
112 // in geographical units
113 const QgsPointXY center = mapToPixel.toMapCoordinates( static_cast<int>( mapToPixel.mapWidth() / 2.0 ), static_cast<int>( mapToPixel.mapHeight() / 2.0 ) );
114 mapToPixel.setMapRotation( 0, center.x(), center.y() );
115 }
116
117 QgsRectangle viewExtentInMapCrs;
118 QgsRectangle layerExtentInMapCrs;
119
120 if ( rendererContext.coordinateTransform().isValid() )
121 {
122 QgsDebugMsgLevel( u"coordinateTransform set -> project extents."_s, 4 );
123 if ( rendererContext.extent().xMinimum() == std::numeric_limits<double>::lowest()
124 && rendererContext.extent().yMinimum() == std::numeric_limits<double>::lowest()
125 && rendererContext.extent().xMaximum() == std::numeric_limits<double>::max()
126 && rendererContext.extent().yMaximum() == std::numeric_limits<double>::max() )
127 {
128 // We get in this situation if the view CRS is geographical and the
129 // extent goes beyond -180,-90,180,90. To avoid reprojection issues to the
130 // layer CRS, then this dummy extent is returned by QgsMapRendererJob::reprojectToLayerExtent()
131 // Don't try to reproject it now to view extent as this would return
132 // a null rectangle.
133 viewExtentInMapCrs = rendererContext.extent();
134 }
135 else
136 {
137 try
138 {
139 QgsCoordinateTransform ct = rendererContext.coordinateTransform();
140 ct.setBallparkTransformsAreAppropriate( true );
141 viewExtentInMapCrs = rendererContext.mapExtent();
142 }
143 catch ( QgsCsException &cs )
144 {
145 QgsMessageLog::logMessage( QObject::tr( "Could not reproject view extent: %1" ).arg( cs.what() ), QObject::tr( "Raster" ) );
146 viewExtentInMapCrs.setNull();
147 }
148 }
149
150 try
151 {
152 QgsCoordinateTransform ct = rendererContext.coordinateTransform();
154 layerExtentInMapCrs = ct.transformBoundingBox( layer->extent() );
155 }
156 catch ( QgsCsException &cs )
157 {
158 QgsMessageLog::logMessage( QObject::tr( "Could not reproject layer extent: %1" ).arg( cs.what() ), QObject::tr( "Raster" ) );
159 layerExtentInMapCrs.setNull();
160 }
161 }
162 else
163 {
164 QgsDebugMsgLevel( u"coordinateTransform not set"_s, 4 );
165 viewExtentInMapCrs = rendererContext.extent();
166 layerExtentInMapCrs = layer->extent();
167 }
168
169 // clip raster extent to view extent
170 QgsRectangle visibleExtentOfRasterInMapCrs = layer->ignoreExtents() ? viewExtentInMapCrs : viewExtentInMapCrs.intersect( layerExtentInMapCrs );
171 if ( visibleExtentOfRasterInMapCrs.isEmpty() )
172 {
173 if ( rendererContext.coordinateTransform().isShortCircuited() )
174 {
175 // no point doing the fallback logic, we aren't using transforms
176
177 QgsDebugMsgLevel( u"draw request outside view extent."_s, 2 );
178 // nothing to do
179 return;
180 }
181
182 // fallback logic, try the inverse operation
183 // eg if we are trying to view a global layer in a small area local projection, then the transform of the
184 // map extent to the layer's local projection probably failed.
185 // So we'll try the opposite logic here, and see if we can first calculate the visible region in the
186 // layers extent, and then transform that small region back to the map's crs
187 try
188 {
189 QgsCoordinateTransform layerToMapTransform = rendererContext.coordinateTransform();
190 layerToMapTransform.setBallparkTransformsAreAppropriate( true );
191 const QgsRectangle viewExtentInLayerCrs = layerToMapTransform.transformBoundingBox( rendererContext.mapExtent(), Qgis::TransformDirection::Reverse );
192
193 const QgsRectangle visibleExtentInLayerCrs = layer->ignoreExtents() ? viewExtentInLayerCrs : viewExtentInLayerCrs.intersect( layer->extent() );
194 if ( visibleExtentInLayerCrs.isEmpty() )
195 {
196 QgsDebugMsgLevel( u"draw request outside view extent."_s, 2 );
197 // nothing to do
198 return;
199 }
200
201 visibleExtentOfRasterInMapCrs = layerToMapTransform.transformBoundingBox( visibleExtentInLayerCrs );
202 }
203 catch ( QgsCsException &cs )
204 {
205 QgsMessageLog::logMessage( QObject::tr( "Could not reproject layer extent: %1" ).arg( cs.what() ), QObject::tr( "Raster" ) );
206 return;
207 }
208 }
209
210 if ( visibleExtentOfRasterInMapCrs.isEmpty() )
211 {
212 QgsDebugMsgLevel( u"draw request outside view extent."_s, 2 );
213 // nothing to do
214 return;
215 }
216
217 QgsDebugMsgLevel( "map extent in layer crs is " + rendererContext.extent().toString(), 4 );
218 QgsDebugMsgLevel( "map extent in map crs is " + viewExtentInMapCrs.toString(), 4 );
219 QgsDebugMsgLevel( "layer extent in map crs is " + layerExtentInMapCrs.toString(), 4 );
220 QgsDebugMsgLevel( "visible extent of raster in map crs is " + visibleExtentOfRasterInMapCrs.toString(), 4 );
221
222 //
223 // The first thing we do is set up the QgsRasterViewPort. This struct stores all the settings
224 // relating to the size (in pixels and coordinate system units) of the raster part that is
225 // in view in the map window. It also stores the origin.
226 //
227 //this is not a class level member because every time the user pans or zooms
228 //the contents of the rasterViewPort will change
229 mRasterViewPort = new QgsRasterViewPort();
230
231 mRasterViewPort->mDrawnExtent = visibleExtentOfRasterInMapCrs;
232 if ( rendererContext.coordinateTransform().isValid() )
233 {
234 mRasterViewPort->mSrcCRS = layer->crs();
235 mRasterViewPort->mDestCRS = rendererContext.coordinateTransform().destinationCrs();
236 mRasterViewPort->mTransformContext = rendererContext.transformContext();
237 }
238 else
239 {
240 mRasterViewPort->mSrcCRS = QgsCoordinateReferenceSystem(); // will be invalid
241 mRasterViewPort->mDestCRS = QgsCoordinateReferenceSystem(); // will be invalid
242 }
243
244 // get dimensions of clipped raster image in device coordinate space (this is the size of the viewport)
245 mRasterViewPort->mTopLeftPoint = mapToPixel.transform( visibleExtentOfRasterInMapCrs.xMinimum(), visibleExtentOfRasterInMapCrs.yMaximum() );
246 mRasterViewPort->mBottomRightPoint = mapToPixel.transform( visibleExtentOfRasterInMapCrs.xMaximum(), visibleExtentOfRasterInMapCrs.yMinimum() );
247
248 // align to output device grid, i.e. std::floor/ceil to integers
249 // TODO: this should only be done if paint device is raster - screen, image
250 // for other devices (pdf) it can have floating point origin
251 // we could use floating point for raster devices as well, but respecting the
252 // output device grid should make it more effective as the resampling is done in
253 // the provider anyway
254 mRasterViewPort->mTopLeftPoint.setX( std::floor( mRasterViewPort->mTopLeftPoint.x() ) );
255 mRasterViewPort->mTopLeftPoint.setY( std::floor( mRasterViewPort->mTopLeftPoint.y() ) );
256 mRasterViewPort->mBottomRightPoint.setX( std::ceil( mRasterViewPort->mBottomRightPoint.x() ) );
257 mRasterViewPort->mBottomRightPoint.setY( std::ceil( mRasterViewPort->mBottomRightPoint.y() ) );
258 // recalc myRasterExtent to aligned values
259 visibleExtentOfRasterInMapCrs.set(
260 mapToPixel.toMapCoordinates( mRasterViewPort->mTopLeftPoint.x(), mRasterViewPort->mBottomRightPoint.y() ),
261 mapToPixel.toMapCoordinates( mRasterViewPort->mBottomRightPoint.x(), mRasterViewPort->mTopLeftPoint.y() )
262 );
263
264 //raster viewport top left / bottom right are already rounded to int
265 mRasterViewPort->mWidth = static_cast<qgssize>( std::abs( mRasterViewPort->mBottomRightPoint.x() - mRasterViewPort->mTopLeftPoint.x() ) );
266 mRasterViewPort->mHeight = static_cast<qgssize>( std::abs( mRasterViewPort->mBottomRightPoint.y() - mRasterViewPort->mTopLeftPoint.y() ) );
267
268 double dpi = 25.4 * rendererContext.scaleFactor();
269 if ( mProviderCapabilities & Qgis::RasterProviderCapability::DpiDependentData && 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( u"mapUnitsPerPixel = %1"_s.arg( mapToPixel.mapUnitsPerPixel() ), 3 );
286 QgsDebugMsgLevel( u"mWidth = %1"_s.arg( layer->width() ), 3 );
287 QgsDebugMsgLevel( u"mHeight = %1"_s.arg( layer->height() ), 3 );
288 QgsDebugMsgLevel( u"visibleExtentOfRasterInMapCrs.xMinimum() = %1"_s.arg( visibleExtentOfRasterInMapCrs.xMinimum() ), 3 );
289 QgsDebugMsgLevel( u"visibleExtentOfRasterInMapCrs.xMaximum() = %1"_s.arg( visibleExtentOfRasterInMapCrs.xMaximum() ), 3 );
290 QgsDebugMsgLevel( u"visibleExtentOfRasterInMapCrs.yMinimum() = %1"_s.arg( visibleExtentOfRasterInMapCrs.yMinimum() ), 3 );
291 QgsDebugMsgLevel( u"visibleExtentOfRasterInMapCrs.yMaximum() = %1"_s.arg( visibleExtentOfRasterInMapCrs.yMaximum() ), 3 );
292
293 QgsDebugMsgLevel( u"mTopLeftPoint.x() = %1"_s.arg( mRasterViewPort->mTopLeftPoint.x() ), 3 );
294 QgsDebugMsgLevel( u"mBottomRightPoint.x() = %1"_s.arg( mRasterViewPort->mBottomRightPoint.x() ), 3 );
295 QgsDebugMsgLevel( u"mTopLeftPoint.y() = %1"_s.arg( mRasterViewPort->mTopLeftPoint.y() ), 3 );
296 QgsDebugMsgLevel( u"mBottomRightPoint.y() = %1"_s.arg( mRasterViewPort->mBottomRightPoint.y() ), 3 );
297
298 QgsDebugMsgLevel( u"mWidth = %1"_s.arg( mRasterViewPort->mWidth ), 3 );
299 QgsDebugMsgLevel( u"mHeight = %1"_s.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 = std::make_unique<QgsRasterPipe>( *layer->pipe() );
310
311 QObject::connect( mPipe->provider(), &QgsRasterDataProvider::statusChanged, layer, &QgsRasterLayer::statusChanged );
312 QgsRasterRenderer *rasterRenderer = mPipe->renderer();
313 if ( rasterRenderer && !( rendererContext.flags() & Qgis::RenderContextFlag::RenderPreviewJob ) && !( rendererContext.flags() & Qgis::RenderContextFlag::Render3DMap ) )
314 {
315 if ( rasterRenderer->needsRefresh( rendererContext.extent() ) )
316 {
317 QList<double> minValues;
318 QList<double> maxValues;
319 const QgsRasterMinMaxOrigin &minMaxOrigin = rasterRenderer->minMaxOrigin();
320 for ( const int bandIdx : rasterRenderer->usesBands() )
321 {
322 double min;
323 double max;
324 layer->computeMinMax( bandIdx, minMaxOrigin, minMaxOrigin.limits(), rendererContext.extent(), static_cast<int>( QgsRasterLayer::SAMPLE_SIZE ), min, max );
325 minValues.append( min );
326 maxValues.append( max );
327 }
328
329 rasterRenderer->refresh( rendererContext.extent(), minValues, maxValues );
330 QgsRenderedLayerStatistics *layerStatistics = new QgsRenderedLayerStatistics( layer->id(), minValues, maxValues );
331 layerStatistics->setBoundingBox( rendererContext.extent() );
332 appendRenderedItemDetails( layerStatistics );
333 }
334 }
335
336 mPipe->evaluateDataDefinedProperties( rendererContext.expressionContext() );
337
338 const QgsRasterLayerTemporalProperties *temporalProperties = qobject_cast< const QgsRasterLayerTemporalProperties * >( layer->temporalProperties() );
339 const QgsRasterLayerElevationProperties *elevationProperties = qobject_cast<QgsRasterLayerElevationProperties *>( layer->elevationProperties() );
340
341 if ( ( temporalProperties->isActive() && renderContext()->isTemporal() ) || ( elevationProperties->hasElevation() && !renderContext()->zRange().isInfinite() ) )
342 {
343 // temporal and/or elevation band filtering may be applicable
344 bool matched = false;
345 const int matchedBand = QgsRasterLayerUtils::renderedBandForElevationAndTemporalRange( layer, rendererContext.temporalRange(), rendererContext.zRange(), matched );
346 if ( matched && matchedBand > 0 )
347 {
348 mPipe->renderer()->setInputBand( matchedBand );
349 }
350 }
351
352 if ( temporalProperties->isActive() && renderContext()->isTemporal() )
353 {
354 switch ( temporalProperties->mode() )
355 {
360 break;
361
363 if ( mPipe->renderer()->usesBands().contains( temporalProperties->bandNumber() ) )
364 {
365 // if layer has elevation settings and we are only rendering a temporal range => we need to filter pixels by temporal values
366 std::unique_ptr< QgsRasterTransparency > transparency;
367 if ( const QgsRasterTransparency *rendererTransparency = mPipe->renderer()->rasterTransparency() )
368 transparency = std::make_unique< QgsRasterTransparency >( *rendererTransparency );
369 else
370 transparency = std::make_unique< QgsRasterTransparency >();
371
372 QVector<QgsRasterTransparency::TransparentSingleValuePixel> transparentPixels = transparency->transparentSingleValuePixelList();
373
374 const QDateTime &offset = temporalProperties->temporalRepresentationOffset();
375 const QgsInterval &scale = temporalProperties->temporalRepresentationScale();
376 const double adjustedLower = static_cast< double >( offset.msecsTo( rendererContext.temporalRange().begin() ) )
378 / scale.originalDuration();
379 const double adjustedUpper = static_cast< double >( offset.msecsTo( rendererContext.temporalRange().end() ) )
381 / scale.originalDuration();
382 if ( !temporalProperties->accumulatePixels() )
383 {
384 transparentPixels.append( QgsRasterTransparency::TransparentSingleValuePixel( std::numeric_limits<double>::lowest(), adjustedLower, 0, true, !rendererContext.zRange().includeLower() ) );
385 }
386 transparentPixels.append( QgsRasterTransparency::TransparentSingleValuePixel( adjustedUpper, std::numeric_limits<double>::max(), 0, !rendererContext.zRange().includeUpper(), true ) );
387
388 transparency->setTransparentSingleValuePixelList( transparentPixels );
389 mPipe->renderer()->setRasterTransparency( transparency.release() );
390 }
391 break;
392
394 // in this mode we need to pass on the desired render temporal range to the data provider
395 if ( QgsRasterDataProviderTemporalCapabilities *temporalCapabilities = mPipe->provider()->temporalCapabilities() )
396 {
397 temporalCapabilities->setRequestedTemporalRange( rendererContext.temporalRange() );
398 temporalCapabilities->setIntervalHandlingMethod( temporalProperties->intervalHandlingMethod() );
399 }
400 break;
401 }
402 }
403 else if ( QgsRasterDataProviderTemporalCapabilities *temporalCapabilities = mPipe->provider()->temporalCapabilities() )
404 {
405 temporalCapabilities->setRequestedTemporalRange( QgsDateTimeRange() );
406 temporalCapabilities->setIntervalHandlingMethod( temporalProperties->intervalHandlingMethod() );
407 }
408
409 mClippingRegions = QgsMapClippingUtils::collectClippingRegionsForLayer( *renderContext(), layer );
410
411 if ( elevationProperties && elevationProperties->hasElevation() )
412 {
413 mDrawElevationMap = true;
414 mElevationScale = elevationProperties->zScale();
415 mElevationOffset = elevationProperties->zOffset();
416 mElevationBand = elevationProperties->bandNumber();
417
418 if ( !rendererContext.zRange().isInfinite() )
419 {
420 // NOLINTBEGIN(bugprone-branch-clone)
421 switch ( elevationProperties->mode() )
422 {
423 case Qgis::RasterElevationMode::FixedElevationRange:
424 // don't need to handle anything here -- the layer renderer will never be created if the
425 // render context range doesn't match the layer's fixed elevation range
426 break;
427
428 case Qgis::RasterElevationMode::FixedRangePerBand:
429 case Qgis::RasterElevationMode::DynamicRangePerBand:
430 // temporal/elevation band based filtering was already handled earlier in this method
431 break;
432
433 case Qgis::RasterElevationMode::RepresentsElevationSurface:
434 {
435 if ( mPipe->renderer()->usesBands().contains( mElevationBand ) )
436 {
437 // if layer has elevation settings and we are only rendering a slice of z values => we need to filter pixels by elevation
438 if ( mPipe->renderer()->flags() & Qgis::RasterRendererFlag::UseNoDataForOutOfRangePixels )
439 {
440 std::unique_ptr< QgsRasterNuller> nuller;
441 if ( const QgsRasterNuller *existingNuller = mPipe->nuller() )
442 nuller.reset( existingNuller->clone() );
443 else
444 nuller = std::make_unique< QgsRasterNuller >();
445
446 // account for z offset/zscale by reversing these calculations, so that we get the z range in
447 // raw pixel values
448 QgsRasterRangeList nullRanges;
449 const double adjustedLower = ( rendererContext.zRange().lower() - mElevationOffset ) / mElevationScale;
450 const double adjustedUpper = ( rendererContext.zRange().upper() - mElevationOffset ) / mElevationScale;
451 nullRanges.append(
452 QgsRasterRange( std::numeric_limits<double>::lowest(), adjustedLower, rendererContext.zRange().includeLower() ? QgsRasterRange::BoundsType::IncludeMin : QgsRasterRange::BoundsType::IncludeMinAndMax )
453 );
454 nullRanges.append(
455 QgsRasterRange( adjustedUpper, std::numeric_limits<double>::max(), rendererContext.zRange().includeUpper() ? QgsRasterRange::BoundsType::IncludeMax : QgsRasterRange::BoundsType::IncludeMinAndMax )
456 );
457 nuller->setOutputNoDataValue( mElevationBand, static_cast< int >( adjustedLower - 1 ) );
458 nuller->setNoData( mElevationBand, nullRanges );
459
460 if ( !mPipe->insert( 1, nuller.release() ) )
461 {
462 QgsDebugError( u"Cannot set pipe nuller"_s );
463 }
464 }
465 else
466 {
467 std::unique_ptr< QgsRasterTransparency > transparency;
468 if ( const QgsRasterTransparency *rendererTransparency = mPipe->renderer()->rasterTransparency() )
469 transparency = std::make_unique< QgsRasterTransparency >( *rendererTransparency );
470 else
471 transparency = std::make_unique< QgsRasterTransparency >();
472
473 QVector<QgsRasterTransparency::TransparentSingleValuePixel> transparentPixels = transparency->transparentSingleValuePixelList();
474
475 // account for z offset/zscale by reversing these calculations, so that we get the z range in
476 // raw pixel values
477 const double adjustedLower = ( rendererContext.zRange().lower() - mElevationOffset ) / mElevationScale;
478 const double adjustedUpper = ( rendererContext.zRange().upper() - mElevationOffset ) / mElevationScale;
479 transparentPixels.append( QgsRasterTransparency::TransparentSingleValuePixel( std::numeric_limits<double>::lowest(), adjustedLower, 0, true, !rendererContext.zRange().includeLower() ) );
480 transparentPixels.append( QgsRasterTransparency::TransparentSingleValuePixel( adjustedUpper, std::numeric_limits<double>::max(), 0, !rendererContext.zRange().includeUpper(), true ) );
481
482 transparency->setTransparentSingleValuePixelList( transparentPixels );
483 mPipe->renderer()->setRasterTransparency( transparency.release() );
484 }
485 }
486 break;
487 }
488 }
489 // NOLINTEND(bugprone-branch-clone)
490 }
491 }
492
493 prepareLabeling( layer );
494
495 mFeedback->setRenderContext( rendererContext );
496
497 mPipe->moveToThread( nullptr );
498
499 mPreparationTime = timer.elapsed();
500}
501
503{
504 delete mFeedback;
505
506 delete mRasterViewPort;
507}
508
510{
511 QgsScopedThreadName threadName( u"render:%1"_s.arg( mLayerName ) );
512
513 std::unique_ptr< QgsScopedRuntimeProfile > profile;
514 if ( mEnableProfile )
515 {
516 profile = std::make_unique< QgsScopedRuntimeProfile >( mLayerName, u"rendering"_s, layerId() );
517 if ( mPreparationTime > 0 )
518 QgsApplication::profiler()->record( QObject::tr( "Create renderer" ), mPreparationTime / 1000.0, u"rendering"_s );
519 }
520
521 // Skip rendering of out of view tiles (xyz)
522 if ( !mRasterViewPort || ( renderContext()->testFlag( Qgis::RenderContextFlag::RenderPreviewJob ) && !( mInterfaceCapabilities & Qgis::RasterInterfaceCapability::Prefetch ) ) )
523 return true;
524
525 mPipe->moveToThread( QThread::currentThread() );
526
527 QElapsedTimer time;
528 time.start();
529
530 std::unique_ptr< QgsScopedRuntimeProfile > preparingProfile;
531 if ( mEnableProfile )
532 {
533 preparingProfile = std::make_unique< QgsScopedRuntimeProfile >( QObject::tr( "Preparing render" ), u"rendering"_s );
534 }
535
536 //
537 //
538 // The goal here is to make as many decisions as possible early on (outside of the rendering loop)
539 // so that we can maximise performance of the rendering process. So now we check which drawing
540 // procedure to use :
541 //
542
543 const QgsScopedQPainterState painterSate( renderContext()->painter() );
544
545 // important -- disable SmoothPixmapTransform and Antialiasing for raster layer renders. We want individual pixels to be clearly defined!
546 renderContext()->painter()->setRenderHint( QPainter::SmoothPixmapTransform, false );
547 bool antialiasEnabled = false;
548 if ( !mClippingRegions.empty() )
549 {
550 bool needsPainterClipPath = false;
551 const QPainterPath path = QgsMapClippingUtils::calculatePainterClipRegion( mClippingRegions, *renderContext(), Qgis::LayerType::Raster, needsPainterClipPath );
552 if ( needsPainterClipPath )
553 {
554 renderContext()->painter()->setClipPath( path, Qt::IntersectClip );
555 // this is an exception to the earlier flag disabling antialiasing!
556 // If we are rendering with clip paths, we WANT the boundaries of the raster to be
557 // rendered using antialiasing along the clip path, or things are very ugly! And since we can't
558 // selectively antialias JUST the clip path boundary, we fallback to antialiasing the
559 // whole raster render
560 antialiasEnabled = true;
561 }
562 }
563 renderContext()->painter()->setRenderHint( QPainter::Antialiasing, antialiasEnabled );
564
565 QgsRasterProjector *projector = mPipe->projector();
566 bool restoreOldResamplingStage = false;
567 const Qgis::RasterResamplingStage oldResamplingState = mPipe->resamplingStage();
568
569 // TODO add a method to interface to get provider and get provider
570 // params in QgsRasterProjector
571 if ( projector )
572 {
573 // Force provider resampling if reprojection is needed
574 if ( ( mPipe->provider()->providerCapabilities() & Qgis::RasterProviderCapability::ProviderHintCanPerformProviderResampling )
575 && mRasterViewPort->mSrcCRS != mRasterViewPort->mDestCRS
576 && oldResamplingState != Qgis::RasterResamplingStage::Provider )
577 {
578 restoreOldResamplingStage = true;
579 mPipe->setResamplingStage( Qgis::RasterResamplingStage::Provider );
580 }
581 projector->setCrs( mRasterViewPort->mSrcCRS, mRasterViewPort->mDestCRS, mRasterViewPort->mTransformContext );
582 }
583
584 preparingProfile.reset();
585 std::unique_ptr< QgsScopedRuntimeProfile > renderingProfile;
586 if ( mEnableProfile )
587 {
588 renderingProfile = std::make_unique< QgsScopedRuntimeProfile >( QObject::tr( "Rendering" ), u"rendering"_s );
589 }
590
591 // Drawer to pipe?
592 QgsRasterIterator iterator( mPipe->last() );
593
594 // Get the maximum tile size from the provider and set it as the maximum tile size for the iterator
595 if ( QgsRasterDataProvider *provider = mPipe->provider() )
596 {
597 const QSize maxTileSize { provider->maximumTileSize() };
598 iterator.setMaximumTileWidth( maxTileSize.width() );
599 iterator.setMaximumTileHeight( maxTileSize.height() );
600 }
601
602 QgsRasterDrawer drawer( &iterator );
603 drawer.draw( *( renderContext() ), mRasterViewPort, mFeedback );
604
605 if ( mDrawElevationMap )
606 drawElevationMap();
607
608 renderingProfile.reset();
609
610 if ( mLabelProvider && !renderContext()->renderingStopped() )
611 {
612 std::unique_ptr< QgsScopedRuntimeProfile > labelingProfile;
613 if ( mEnableProfile )
614 {
615 labelingProfile = std::make_unique< QgsScopedRuntimeProfile >( QObject::tr( "Labeling" ), u"rendering"_s );
616 }
617 drawLabeling();
618 }
619
620 if ( restoreOldResamplingStage )
621 {
622 mPipe->setResamplingStage( oldResamplingState );
623 }
624
625 const QStringList errors = mFeedback->errors();
626 for ( const QString &error : errors )
627 {
628 mErrors.append( error );
629 }
630
631 QgsDebugMsgLevel( u"total raster draw time (ms): %1"_s.arg( time.elapsed(), 5 ), 4 );
632 mReadyToCompose = true;
633
634 mPipe->moveToThread( nullptr );
635
636 return !mFeedback->isCanceled();
637}
638
640{
641 return mFeedback;
642}
643
645{
646 if ( !mRasterViewPort || !mPipe )
647 return false; // this layer is not going to get rendered
648
649 // preview of intermediate raster rendering results requires a temporary output image
651 return true;
652
653 if ( QgsRasterRenderer *renderer = mPipe->renderer() )
654 {
655 if ( !( renderer->flags() & Qgis::RasterRendererFlag::InternalLayerOpacityHandling ) )
656 {
657 switch ( renderContext()->rasterizedRenderingPolicy() )
658 {
661 break;
662
664 return false;
665 }
666
667 if ( !qgsDoubleNear( mLayerOpacity, 1.0 ) )
668 return true;
669 }
670 }
671
672 return false;
673}
674
675void QgsRasterLayerRenderer::prepareLabeling( QgsRasterLayer *layer )
676{
677 QgsRenderContext &context = *renderContext();
678
679 if ( QgsLabelingEngine *engine2 = context.labelingEngine() )
680 {
681 if ( QgsAbstractRasterLayerLabeling *labeling = layer->labeling() )
682 {
683 if ( layer->labelsEnabled() && labeling->isInScaleRange( context.rendererScale() ) )
684 {
685 std::unique_ptr< QgsRasterLayerLabelProvider > provider = labeling->provider( layer );
686 if ( provider )
687 {
688 // engine takes ownership
689 mLabelProvider = provider.release();
690 mLabelProvider->startRender( context );
691 engine2->addProvider( mLabelProvider );
692 }
693 }
694 }
695 }
696}
697
698void QgsRasterLayerRenderer::drawLabeling()
699{
700 if ( mLabelProvider )
701 mLabelProvider->generateLabels( *renderContext(), mPipe.get(), mRasterViewPort, mFeedback );
702}
703
704void QgsRasterLayerRenderer::drawElevationMap()
705{
706 QgsRasterDataProvider *dataProvider = mPipe->provider();
707 if ( renderContext()->elevationMap() && dataProvider )
708 {
709 double dpiScalefactor;
710
711 if ( renderContext()->dpiTarget() >= 0.0 )
712 dpiScalefactor = renderContext()->dpiTarget() / ( renderContext()->scaleFactor() * 25.4 );
713 else
714 dpiScalefactor = 1.0;
715
716 int outputWidth = static_cast<int>( static_cast<double>( mRasterViewPort->mWidth ) / dpiScalefactor * renderContext()->devicePixelRatio() );
717 int outputHeight = static_cast<int>( static_cast<double>( mRasterViewPort->mHeight ) / dpiScalefactor * renderContext()->devicePixelRatio() );
718
719 QSize viewSize = renderContext()->deviceOutputSize();
720 int viewWidth = static_cast<int>( viewSize.width() / dpiScalefactor );
721 int viewHeight = static_cast<int>( viewSize.height() / dpiScalefactor );
722
723 bool canRenderElevation = false;
724 std::unique_ptr<QgsRasterBlock> elevationBlock;
725 if ( mRasterViewPort->mSrcCRS == mRasterViewPort->mDestCRS )
726 {
727 elevationBlock.reset( dataProvider->block( mElevationBand, mRasterViewPort->mDrawnExtent, outputWidth, outputHeight, mFeedback ) );
728 canRenderElevation = true;
729 }
730 else
731 {
732 // Destinaton CRS is different from the source CRS.
733 // Using the raster projector lead to have big artifacts when rendering the elevation map.
734 // To get a smoother elevation map, we use GDAL resampling with coordinates transform
735 QgsRectangle viewExtentInLayerCoordinate = renderContext()->extent();
736
737 // If view extent is infinite, we use the data provider extent
738 if ( viewExtentInLayerCoordinate.xMinimum() == std::numeric_limits<double>::lowest()
739 && viewExtentInLayerCoordinate.yMinimum() == std::numeric_limits<double>::lowest()
740 && viewExtentInLayerCoordinate.xMaximum() == std::numeric_limits<double>::max()
741 && viewExtentInLayerCoordinate.yMaximum() == std::numeric_limits<double>::max() )
742 {
743 viewExtentInLayerCoordinate = dataProvider->extent();
744 }
745
746 double xLayerResol = viewExtentInLayerCoordinate.width() / static_cast<double>( viewWidth );
747 double yLayerResol = viewExtentInLayerCoordinate.height() / static_cast<double>( viewHeight );
748
749 double overSampling = 1;
750 if ( mPipe->resampleFilter() )
751 overSampling = mPipe->resampleFilter()->maxOversampling();
752
754 {
755 // If the dataprovider has size capability, we calculate the requested resolution to provider
756 double providerXResol = dataProvider->extent().width() / dataProvider->xSize();
757 double providerYResol = dataProvider->extent().height() / dataProvider->ySize();
758 overSampling = ( xLayerResol / providerXResol + yLayerResol / providerYResol ) / 2;
759 }
760
761 GDALResampleAlg alg;
762 if ( overSampling > 1 )
764 else
766
767 Qgis::DataType dataType = dataProvider->dataType( mElevationBand );
768
769 if ( dataType != Qgis::DataType::UnknownDataType ) // resampling data by GDAL is not compatible with unknown data type
770 {
771 // we need extra pixels on border to avoid effect border with resampling (at least 2 pixels band for cubic alg)
772 int sourceWidth = viewWidth + 4;
773 int sourceHeight = viewHeight + 4;
774 viewExtentInLayerCoordinate = QgsRectangle(
775 viewExtentInLayerCoordinate.xMinimum() - xLayerResol * 2,
776 viewExtentInLayerCoordinate.yMinimum() - yLayerResol * 2,
777 viewExtentInLayerCoordinate.xMaximum() + xLayerResol * 2,
778 viewExtentInLayerCoordinate.yMaximum() + yLayerResol * 2
779 );
780
781 // Now we can do the resampling
782 std::unique_ptr<QgsRasterBlock> sourcedata( dataProvider->block( mElevationBand, viewExtentInLayerCoordinate, sourceWidth, sourceHeight, mFeedback ) );
783 gdal::dataset_unique_ptr gdalDsInput = QgsGdalUtils::blockToSingleBandMemoryDataset( viewExtentInLayerCoordinate, sourcedata.get() );
784
785
786 elevationBlock = std::make_unique<QgsRasterBlock>( dataType, outputWidth, outputHeight );
787
788 elevationBlock->setNoDataValue( dataProvider->sourceNoDataValue( mElevationBand ) );
789
790 gdal::dataset_unique_ptr gdalDsOutput = QgsGdalUtils::blockToSingleBandMemoryDataset( mRasterViewPort->mDrawnExtent, elevationBlock.get() );
791
792 // For coordinate transformation, we try to obtain a coordinate operation string from the transform context.
793 // Depending of the CRS, if we can't we use GDAL transformation directly from the source and destination CRS
794 QString coordinateOperation;
795 const QgsCoordinateTransformContext &transformContext = renderContext()->transformContext();
796 if ( transformContext.mustReverseCoordinateOperation( mRasterViewPort->mSrcCRS, mRasterViewPort->mDestCRS ) )
797 coordinateOperation = transformContext.calculateCoordinateOperation( mRasterViewPort->mDestCRS, mRasterViewPort->mSrcCRS );
798 else
799 coordinateOperation = transformContext.calculateCoordinateOperation( mRasterViewPort->mSrcCRS, mRasterViewPort->mDestCRS );
800
801 if ( coordinateOperation.isEmpty() )
802 canRenderElevation = QgsGdalUtils::resampleSingleBandRaster( gdalDsInput.get(), gdalDsOutput.get(), alg, mRasterViewPort->mSrcCRS, mRasterViewPort->mDestCRS );
803 else
804 canRenderElevation = QgsGdalUtils::resampleSingleBandRaster( gdalDsInput.get(), gdalDsOutput.get(), alg, 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();
816 QgsElevationMap *elevMap = renderContext()->elevationMap();
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
828 << QgsPointXY( mRasterViewPort->mDrawnExtent.xMinimum(), mRasterViewPort->mDrawnExtent.yMinimum() )
829 << QgsPointXY( mRasterViewPort->mDrawnExtent.xMaximum(), mRasterViewPort->mDrawnExtent.yMaximum() )
830 << QgsPointXY( mRasterViewPort->mDrawnExtent.xMinimum(), mRasterViewPort->mDrawnExtent.yMaximum() )
831 << QgsPointXY( mRasterViewPort->mDrawnExtent.xMaximum(), mRasterViewPort->mDrawnExtent.yMinimum() );
832
833 for ( const QgsPointXY &corner : std::as_const( corners ) )
834 {
835 const QgsPointXY dpt = mtp.transform( corner );
836 int x = static_cast<int>( std::round( dpt.x() ) );
837 int y = static_cast<int>( std::round( dpt.y() ) );
838
839 if ( x < left )
840 left = x;
841 if ( x > right )
842 right = x;
843 if ( y < top )
844 top = y;
845 if ( y > bottom )
846 bottom = y;
847 }
848
849 const QgsPointXY origin = mtp.toMapCoordinates( left, top );
850 double gridXSize = mtp.toMapCoordinates( right, top ).distance( origin );
851 double gridYSize = mtp.toMapCoordinates( left, bottom ).distance( origin );
852 double angleRad = renderContext()->mapToPixel().mapRotation() / 180 * M_PI;
853
854 gdal::dataset_unique_ptr gdalDsInput = QgsGdalUtils::blockToSingleBandMemoryDataset( mRasterViewPort->mDrawnExtent, elevationBlock.get() );
855
856 std::unique_ptr<QgsRasterBlock> rotatedElevationBlock
857 = std::make_unique<QgsRasterBlock>( elevationBlock->dataType(), ( right - left ) * renderContext()->devicePixelRatio() + 1, ( bottom - top ) * renderContext()->devicePixelRatio() + 1 );
858
859 rotatedElevationBlock->setNoDataValue( elevationBlock->noDataValue() );
860
861 gdal::dataset_unique_ptr gdalDsOutput = QgsGdalUtils::blockToSingleBandMemoryDataset( angleRad, origin, gridXSize, gridYSize, rotatedElevationBlock.get() );
862
863 if ( QgsGdalUtils::resampleSingleBandRaster( gdalDsInput.get(), gdalDsOutput.get(), QgsGdalUtils::gdalResamplingAlgorithm( dataProvider->zoomedInResamplingMethod() ), nullptr ) )
864 {
865 elevationBlock = std::move( rotatedElevationBlock );
866 }
867
868 topLeft = QPoint( left, top );
869 }
870 else
871 {
872 topLeft = mRasterViewPort->mTopLeftPoint.toQPointF().toPoint();
873 }
874
875 renderContext()->elevationMap()->fillWithRasterBlock( elevationBlock.get(), topLeft.y() * renderContext()->devicePixelRatio(), topLeft.x() * renderContext()->devicePixelRatio(), mElevationScale, mElevationOffset );
876 }
877 }
878}
Provides global constants and enumerations for use throughout the application.
Definition qgis.h:62
@ Default
Allow raster-based rendering in situations where it is required for correct rendering or where it wil...
Definition qgis.h:2799
@ PreferVector
Prefer vector-based rendering, when the result will still be visually near-identical to a raster-base...
Definition qgis.h:2800
@ ForceVector
Always force vector-based rendering, even when the result will be visually different to a raster-base...
Definition qgis.h:2801
RasterResamplingStage
Stage at which raster resampling occurs.
Definition qgis.h:1548
@ Provider
Resampling occurs in Provider.
Definition qgis.h:1550
@ ProviderHintCanPerformProviderResampling
Provider can perform resampling (to be opposed to post rendering resampling).
Definition qgis.h:5048
@ DpiDependentData
Provider's rendering is dependent on requested pixel size of the viewport.
Definition qgis.h:5050
@ InternalLayerOpacityHandling
The renderer internally handles the raster layer's opacity, so the default layer level opacity handli...
Definition qgis.h:1581
@ Milliseconds
Milliseconds.
Definition qgis.h:5317
@ RepresentsTemporalValues
Pixel values represent an datetime.
Definition qgis.h:2718
@ RedrawLayerOnly
Redraw the layer when temporal range changes, but don't apply any filtering. Useful when raster symbo...
Definition qgis.h:2715
@ FixedRangePerBand
Layer has a fixed temporal range per band.
Definition qgis.h:2717
@ TemporalRangeFromDataProvider
Mode when raster layer delegates temporal range handling to the dataprovider.
Definition qgis.h:2714
@ FixedTemporalRange
Mode when temporal properties have fixed start and end datetimes.
Definition qgis.h:2713
@ FixedDateTime
Layer has a fixed date time instant.
Definition qgis.h:2719
@ Prefetch
Allow prefetching of out-of-view images.
Definition qgis.h:5021
@ Size
Original data source size (and thus resolution) is known, it is not always available,...
Definition qgis.h:5012
DataType
Raster data types.
Definition qgis.h:393
@ UnknownDataType
Unknown or unspecified type.
Definition qgis.h:394
@ Raster
Raster layer.
Definition qgis.h:208
@ RenderPreviewJob
Render is a 'canvas preview' render, and shortcuts should be taken to ensure fast rendering.
Definition qgis.h:2855
@ RenderPartialOutput
Whether to make extra effort to update map image with partially rendered layers (better for interacti...
Definition qgis.h:2854
@ Render3DMap
Render is for a 3D map.
Definition qgis.h:2860
Abstract base class for labeling settings for raster layers.
static QgsRuntimeProfiler * profiler()
Returns the application runtime profiler.
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.
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...
Custom exception class for Coordinate Reference System related exceptions.
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:52
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.
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.
virtual Qgis::MapLayerRendererFlags flags() const
Returns flags which control how the map layer rendering behaves.
QgsRenderContext * renderContext()
Returns the render context associated with the renderer.
QStringList errors() const
Returns list of errors (problems) that happened during the rendering.
QgsMapLayerRenderer(const QString &layerID, QgsRenderContext *context=nullptr)
Constructor for QgsMapLayerRenderer, with the associated layerID and render context.
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.
QgsPointXY toMapCoordinates(int x, int y) const
Transforms device coordinates to map (world) coordinates.
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(), Qgis::StringFormat format=Qgis::StringFormat::PlainText)
Adds a message to the log instance (and creates it if necessary).
double distance(double x, double y) const
Returns the distance between this point and a specified x, y coordinate.
Definition qgspointxy.h:209
double y
Definition qgspointxy.h:66
double x
Definition qgspointxy.h:65
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.
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.
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.
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.
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.
bool labelsEnabled() const
Returns whether the layer contains labels which are enabled and should be drawn.
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 renderer pipe that applies colors to a raster.
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 rounded to the spec...
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
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.
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.
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...
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.
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.
Scoped object for setting the current thread name.
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:7485
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference).
Definition qgis.h:6975
#define QgsDebugMsgLevel(str, level)
Definition qgslogger.h:63
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.
QgsRectangle mDrawnExtent
Intersection of current map extent and layer extent, in map (destination) CRS.