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