QGIS API Documentation 3.99.0-Master (2fe06baccd8)
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{
59}
60
61void QgsRasterLayerRendererFeedback::onNewData()
62{
63 if ( !renderPartialOutput() )
64 return; // we were not asked for partial renders and we may not have a temporary image for overwriting...
65
66 // update only once upon a time
67 // (preview itself takes some time)
68 if ( mLastPreview.isValid() && mLastPreview.msecsTo( QTime::currentTime() ) < mMinimalPreviewInterval )
69 return;
70
71 // TODO: update only the area that got new data
72
73 QgsDebugMsgLevel( QStringLiteral( "new raster preview! %1" ).arg( mLastPreview.msecsTo( QTime::currentTime() ) ), 3 );
74 QElapsedTimer t;
75 t.start();
77 feedback.setPreviewOnly( true );
78 feedback.setRenderPartialOutput( true );
79 QgsRasterIterator iterator( mR->mPipe->last() );
80 QgsRasterDrawer drawer( &iterator );
81 drawer.draw( *( mR->renderContext() ), mR->mRasterViewPort, &feedback );
82 mR->mReadyToCompose = true;
83 QgsDebugMsgLevel( QStringLiteral( "total raster preview time: %1 ms" ).arg( t.elapsed() ), 3 );
84 mLastPreview = QTime::currentTime();
85}
86
90 : QgsMapLayerRenderer( layer->id(), &rendererContext )
91 , mLayerName( layer->name() )
92 , mLayerOpacity( layer->opacity() )
93 , mProviderCapabilities( layer->dataProvider()->providerCapabilities() )
94 , mInterfaceCapabilities( layer->dataProvider()->capabilities() )
95 , mFeedback( new QgsRasterLayerRendererFeedback( this ) )
96 , mEnableProfile( rendererContext.flags() & Qgis::RenderContextFlag::RecordProfile )
97{
98 mReadyToCompose = false;
99
100 QElapsedTimer timer;
101 timer.start();
102
103 QgsMapToPixel mapToPixel = rendererContext.mapToPixel();
104 if ( rendererContext.mapToPixel().mapRotation() )
105 {
106 // unset rotation for the sake of local computations.
107 // Rotation will be handled by QPainter later
108 // TODO: provide a method of QgsMapToPixel to fetch map center
109 // in geographical units
110 const QgsPointXY center = mapToPixel.toMapCoordinates(
111 static_cast<int>( mapToPixel.mapWidth() / 2.0 ),
112 static_cast<int>( mapToPixel.mapHeight() / 2.0 )
113 );
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( QStringLiteral( "coordinateTransform set -> project extents." ), 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( QStringLiteral( "coordinateTransform not set" ), 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( QStringLiteral( "draw request outside view extent." ), 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( QStringLiteral( "draw request outside view extent." ), 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( QStringLiteral( "draw request outside view extent." ), 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(),
261 mRasterViewPort->mBottomRightPoint.y() ),
262 mapToPixel.toMapCoordinates( mRasterViewPort->mBottomRightPoint.x(),
263 mRasterViewPort->mTopLeftPoint.y() )
264 );
265
266 //raster viewport top left / bottom right are already rounded to int
267 mRasterViewPort->mWidth = static_cast<qgssize>( std::abs( mRasterViewPort->mBottomRightPoint.x() - mRasterViewPort->mTopLeftPoint.x() ) );
268 mRasterViewPort->mHeight = static_cast<qgssize>( std::abs( mRasterViewPort->mBottomRightPoint.y() - mRasterViewPort->mTopLeftPoint.y() ) );
269
270 double dpi = 25.4 * rendererContext.scaleFactor();
271 if ( mProviderCapabilities & Qgis::RasterProviderCapability::DpiDependentData
272 && rendererContext.dpiTarget() >= 0.0 )
273 {
274 const double dpiScaleFactor = rendererContext.dpiTarget() / dpi;
275 mRasterViewPort->mWidth *= dpiScaleFactor;
276 mRasterViewPort->mHeight *= dpiScaleFactor;
277 dpi = rendererContext.dpiTarget();
278 }
279 else
280 {
281 rendererContext.setDpiTarget( -1.0 );
282 }
283
284 //the drawable area can start to get very very large when you get down displaying 2x2 or smaller, this is because
285 //mapToPixel.mapUnitsPerPixel() is less then 1,
286 //so we will just get the pixel data and then render these special cases differently in paintImageToCanvas()
287
288 QgsDebugMsgLevel( QStringLiteral( "mapUnitsPerPixel = %1" ).arg( mapToPixel.mapUnitsPerPixel() ), 3 );
289 QgsDebugMsgLevel( QStringLiteral( "mWidth = %1" ).arg( layer->width() ), 3 );
290 QgsDebugMsgLevel( QStringLiteral( "mHeight = %1" ).arg( layer->height() ), 3 );
291 QgsDebugMsgLevel( QStringLiteral( "visibleExtentOfRasterInMapCrs.xMinimum() = %1" ).arg( visibleExtentOfRasterInMapCrs.xMinimum() ), 3 );
292 QgsDebugMsgLevel( QStringLiteral( "visibleExtentOfRasterInMapCrs.xMaximum() = %1" ).arg( visibleExtentOfRasterInMapCrs.xMaximum() ), 3 );
293 QgsDebugMsgLevel( QStringLiteral( "visibleExtentOfRasterInMapCrs.yMinimum() = %1" ).arg( visibleExtentOfRasterInMapCrs.yMinimum() ), 3 );
294 QgsDebugMsgLevel( QStringLiteral( "visibleExtentOfRasterInMapCrs.yMaximum() = %1" ).arg( visibleExtentOfRasterInMapCrs.yMaximum() ), 3 );
295
296 QgsDebugMsgLevel( QStringLiteral( "mTopLeftPoint.x() = %1" ).arg( mRasterViewPort->mTopLeftPoint.x() ), 3 );
297 QgsDebugMsgLevel( QStringLiteral( "mBottomRightPoint.x() = %1" ).arg( mRasterViewPort->mBottomRightPoint.x() ), 3 );
298 QgsDebugMsgLevel( QStringLiteral( "mTopLeftPoint.y() = %1" ).arg( mRasterViewPort->mTopLeftPoint.y() ), 3 );
299 QgsDebugMsgLevel( QStringLiteral( "mBottomRightPoint.y() = %1" ).arg( mRasterViewPort->mBottomRightPoint.y() ), 3 );
300
301 QgsDebugMsgLevel( QStringLiteral( "mWidth = %1" ).arg( mRasterViewPort->mWidth ), 3 );
302 QgsDebugMsgLevel( QStringLiteral( "mHeight = %1" ).arg( mRasterViewPort->mHeight ), 3 );
303
304 // /\/\/\ - added to handle zoomed-in rasters
305
306 // TODO R->mLastViewPort = *mRasterViewPort;
307
308 // TODO: is it necessary? Probably WMS only?
309 layer->dataProvider()->setDpi( std::floor( dpi * rendererContext.devicePixelRatio() ) );
310
311 // copy the whole raster pipe!
312 mPipe = std::make_unique<QgsRasterPipe>( *layer->pipe() );
313
314 QObject::connect( mPipe->provider(), &QgsRasterDataProvider::statusChanged, layer, &QgsRasterLayer::statusChanged );
315 QgsRasterRenderer *rasterRenderer = mPipe->renderer();
316 if ( rasterRenderer
317 && !( rendererContext.flags() & Qgis::RenderContextFlag::RenderPreviewJob )
318 && !( rendererContext.flags() & Qgis::RenderContextFlag::Render3DMap ) )
319 {
320 if ( rasterRenderer->needsRefresh( rendererContext.extent() ) )
321 {
322 QList<double> minValues;
323 QList<double> maxValues;
324 const QgsRasterMinMaxOrigin &minMaxOrigin = rasterRenderer->minMaxOrigin();
325 for ( const int bandIdx : rasterRenderer->usesBands() )
326 {
327 double min;
328 double max;
329 layer->computeMinMax( bandIdx, minMaxOrigin, minMaxOrigin.limits(),
330 rendererContext.extent(), static_cast<int>( QgsRasterLayer::SAMPLE_SIZE ),
331 min, max );
332 minValues.append( min );
333 maxValues.append( max );
334 }
335
336 rasterRenderer->refresh( rendererContext.extent(), minValues, maxValues );
337 QgsRenderedLayerStatistics *layerStatistics = new QgsRenderedLayerStatistics( layer->id(), minValues, maxValues );
338 layerStatistics->setBoundingBox( rendererContext.extent() );
339 appendRenderedItemDetails( layerStatistics );
340 }
341 }
342
343 mPipe->evaluateDataDefinedProperties( rendererContext.expressionContext() );
344
345 const QgsRasterLayerTemporalProperties *temporalProperties = qobject_cast< const QgsRasterLayerTemporalProperties * >( layer->temporalProperties() );
346 const QgsRasterLayerElevationProperties *elevationProperties = qobject_cast<QgsRasterLayerElevationProperties *>( layer->elevationProperties() );
347
348 if ( ( temporalProperties->isActive() && renderContext()->isTemporal() )
349 || ( elevationProperties->hasElevation() && !renderContext()->zRange().isInfinite() ) )
350 {
351 // temporal and/or elevation band filtering may be applicable
352 bool matched = false;
354 layer,
355 rendererContext.temporalRange(),
356 rendererContext.zRange(),
357 matched
358 );
359 if ( matched && matchedBand > 0 )
360 {
361 mPipe->renderer()->setInputBand( matchedBand );
362 }
363 }
364
365 if ( temporalProperties->isActive() && renderContext()->isTemporal() )
366 {
367 switch ( temporalProperties->mode() )
368 {
373 break;
374
376 if ( mPipe->renderer()->usesBands().contains( temporalProperties->bandNumber() ) )
377 {
378 // if layer has elevation settings and we are only rendering a temporal range => we need to filter pixels by temporal values
379 std::unique_ptr< QgsRasterTransparency > transparency;
380 if ( const QgsRasterTransparency *rendererTransparency = mPipe->renderer()->rasterTransparency() )
381 transparency = std::make_unique< QgsRasterTransparency >( *rendererTransparency );
382 else
383 transparency = std::make_unique< QgsRasterTransparency >();
384
385 QVector<QgsRasterTransparency::TransparentSingleValuePixel> transparentPixels = transparency->transparentSingleValuePixelList();
386
387 const QDateTime &offset = temporalProperties->temporalRepresentationOffset();
388 const QgsInterval &scale = temporalProperties->temporalRepresentationScale();
389 const double adjustedLower = static_cast< double >( offset.msecsTo( rendererContext.temporalRange().begin() ) ) * QgsUnitTypes::fromUnitToUnitFactor( Qgis::TemporalUnit::Milliseconds, scale.originalUnit() ) / scale.originalDuration();
390 const double adjustedUpper = static_cast< double >( offset.msecsTo( rendererContext.temporalRange().end() ) ) * QgsUnitTypes::fromUnitToUnitFactor( Qgis::TemporalUnit::Milliseconds, scale.originalUnit() ) / scale.originalDuration();
391 if ( !temporalProperties->accumulatePixels() )
392 {
393 transparentPixels.append( QgsRasterTransparency::TransparentSingleValuePixel( std::numeric_limits<double>::lowest(), adjustedLower, 0, true, !rendererContext.zRange().includeLower() ) );
394 }
395 transparentPixels.append( QgsRasterTransparency::TransparentSingleValuePixel( adjustedUpper, std::numeric_limits<double>::max(), 0, !rendererContext.zRange().includeUpper(), true ) );
396
397 transparency->setTransparentSingleValuePixelList( transparentPixels );
398 mPipe->renderer()->setRasterTransparency( transparency.release() );
399 }
400 break;
401
403 // in this mode we need to pass on the desired render temporal range to the data provider
404 if ( QgsRasterDataProviderTemporalCapabilities *temporalCapabilities = mPipe->provider()->temporalCapabilities() )
405 {
406 temporalCapabilities->setRequestedTemporalRange( rendererContext.temporalRange() );
407 temporalCapabilities->setIntervalHandlingMethod( temporalProperties->intervalHandlingMethod() );
408 }
409 break;
410 }
411 }
412 else if ( QgsRasterDataProviderTemporalCapabilities *temporalCapabilities = mPipe->provider()->temporalCapabilities() )
413 {
414 temporalCapabilities->setRequestedTemporalRange( QgsDateTimeRange() );
415 temporalCapabilities->setIntervalHandlingMethod( temporalProperties->intervalHandlingMethod() );
416 }
417
418 mClippingRegions = QgsMapClippingUtils::collectClippingRegionsForLayer( *renderContext(), layer );
419
420 if ( elevationProperties && elevationProperties->hasElevation() )
421 {
422 mDrawElevationMap = true;
423 mElevationScale = elevationProperties->zScale();
424 mElevationOffset = elevationProperties->zOffset();
425 mElevationBand = elevationProperties->bandNumber();
426
427 if ( !rendererContext.zRange().isInfinite() )
428 {
429 // NOLINTBEGIN(bugprone-branch-clone)
430 switch ( elevationProperties->mode() )
431 {
432 case Qgis::RasterElevationMode::FixedElevationRange:
433 // don't need to handle anything here -- the layer renderer will never be created if the
434 // render context range doesn't match the layer's fixed elevation range
435 break;
436
437 case Qgis::RasterElevationMode::FixedRangePerBand:
438 case Qgis::RasterElevationMode::DynamicRangePerBand:
439 // temporal/elevation band based filtering was already handled earlier in this method
440 break;
441
442 case Qgis::RasterElevationMode::RepresentsElevationSurface:
443 {
444 if ( mPipe->renderer()->usesBands().contains( mElevationBand ) )
445 {
446 // if layer has elevation settings and we are only rendering a slice of z values => we need to filter pixels by elevation
447 if ( mPipe->renderer()->flags() & Qgis::RasterRendererFlag::UseNoDataForOutOfRangePixels )
448 {
449 std::unique_ptr< QgsRasterNuller> nuller;
450 if ( const QgsRasterNuller *existingNuller = mPipe->nuller() )
451 nuller.reset( existingNuller->clone() );
452 else
453 nuller = std::make_unique< QgsRasterNuller >();
454
455 // account for z offset/zscale by reversing these calculations, so that we get the z range in
456 // raw pixel values
457 QgsRasterRangeList nullRanges;
458 const double adjustedLower = ( rendererContext.zRange().lower() - mElevationOffset ) / mElevationScale;
459 const double adjustedUpper = ( rendererContext.zRange().upper() - mElevationOffset ) / mElevationScale;
460 nullRanges.append( QgsRasterRange( std::numeric_limits<double>::lowest(), adjustedLower, rendererContext.zRange().includeLower() ? QgsRasterRange::BoundsType::IncludeMin : QgsRasterRange::BoundsType::IncludeMinAndMax ) );
461 nullRanges.append( QgsRasterRange( adjustedUpper, std::numeric_limits<double>::max(), rendererContext.zRange().includeUpper() ? QgsRasterRange::BoundsType::IncludeMax : QgsRasterRange::BoundsType::IncludeMinAndMax ) );
462 nuller->setOutputNoDataValue( mElevationBand, static_cast< int >( adjustedLower - 1 ) );
463 nuller->setNoData( mElevationBand, nullRanges );
464
465 if ( !mPipe->insert( 1, nuller.release() ) )
466 {
467 QgsDebugError( QStringLiteral( "Cannot set pipe nuller" ) );
468 }
469 }
470 else
471 {
472 std::unique_ptr< QgsRasterTransparency > transparency;
473 if ( const QgsRasterTransparency *rendererTransparency = mPipe->renderer()->rasterTransparency() )
474 transparency = std::make_unique< QgsRasterTransparency >( *rendererTransparency );
475 else
476 transparency = std::make_unique< QgsRasterTransparency >();
477
478 QVector<QgsRasterTransparency::TransparentSingleValuePixel> transparentPixels = transparency->transparentSingleValuePixelList();
479
480 // account for z offset/zscale by reversing these calculations, so that we get the z range in
481 // raw pixel values
482 const double adjustedLower = ( rendererContext.zRange().lower() - mElevationOffset ) / mElevationScale;
483 const double adjustedUpper = ( rendererContext.zRange().upper() - mElevationOffset ) / mElevationScale;
484 transparentPixels.append( QgsRasterTransparency::TransparentSingleValuePixel( std::numeric_limits<double>::lowest(), adjustedLower, 0, true, !rendererContext.zRange().includeLower() ) );
485 transparentPixels.append( QgsRasterTransparency::TransparentSingleValuePixel( adjustedUpper, std::numeric_limits<double>::max(), 0, !rendererContext.zRange().includeUpper(), true ) );
486
487 transparency->setTransparentSingleValuePixelList( transparentPixels );
488 mPipe->renderer()->setRasterTransparency( transparency.release() );
489 }
490 }
491 break;
492 }
493 }
494 // NOLINTEND(bugprone-branch-clone)
495 }
496 }
497
498 prepareLabeling( layer );
499
500 mFeedback->setRenderContext( rendererContext );
501
502 mPipe->moveToThread( nullptr );
503
504 mPreparationTime = timer.elapsed();
505}
506
508{
509 delete mFeedback;
510
511 delete mRasterViewPort;
512}
513
515{
516 QgsScopedThreadName threadName( QStringLiteral( "render:%1" ).arg( mLayerName ) );
517
518 std::unique_ptr< QgsScopedRuntimeProfile > profile;
519 if ( mEnableProfile )
520 {
521 profile = std::make_unique< QgsScopedRuntimeProfile >( mLayerName, QStringLiteral( "rendering" ), layerId() );
522 if ( mPreparationTime > 0 )
523 QgsApplication::profiler()->record( QObject::tr( "Create renderer" ), mPreparationTime / 1000.0, QStringLiteral( "rendering" ) );
524 }
525
526 // Skip rendering of out of view tiles (xyz)
527 if ( !mRasterViewPort || ( renderContext()->testFlag( Qgis::RenderContextFlag::RenderPreviewJob ) &&
528 !( mInterfaceCapabilities &
530 return true;
531
532 mPipe->moveToThread( QThread::currentThread() );
533
534 QElapsedTimer time;
535 time.start();
536
537 std::unique_ptr< QgsScopedRuntimeProfile > preparingProfile;
538 if ( mEnableProfile )
539 {
540 preparingProfile = std::make_unique< QgsScopedRuntimeProfile >( QObject::tr( "Preparing render" ), QStringLiteral( "rendering" ) );
541 }
542
543 //
544 //
545 // The goal here is to make as many decisions as possible early on (outside of the rendering loop)
546 // so that we can maximise performance of the rendering process. So now we check which drawing
547 // procedure to use :
548 //
549
550 const QgsScopedQPainterState painterSate( renderContext()->painter() );
551
552 // important -- disable SmoothPixmapTransform and Antialiasing for raster layer renders. We want individual pixels to be clearly defined!
553 renderContext()->painter()->setRenderHint( QPainter::SmoothPixmapTransform, false );
554 bool antialiasEnabled = false;
555 if ( !mClippingRegions.empty() )
556 {
557 bool needsPainterClipPath = false;
558 const QPainterPath path = QgsMapClippingUtils::calculatePainterClipRegion( mClippingRegions, *renderContext(), Qgis::LayerType::Raster, needsPainterClipPath );
559 if ( needsPainterClipPath )
560 {
561 renderContext()->painter()->setClipPath( path, Qt::IntersectClip );
562 // this is an exception to the earlier flag disabling antialiasing!
563 // If we are rendering with clip paths, we WANT the boundaries of the raster to be
564 // rendered using antialiasing along the clip path, or things are very ugly! And since we can't
565 // selectively antialias JUST the clip path boundary, we fallback to antialiasing the
566 // whole raster render
567 antialiasEnabled = true;
568 }
569 }
570 renderContext()->painter()->setRenderHint( QPainter::Antialiasing, antialiasEnabled );
571
572 QgsRasterProjector *projector = mPipe->projector();
573 bool restoreOldResamplingStage = false;
574 const Qgis::RasterResamplingStage oldResamplingState = mPipe->resamplingStage();
575
576 // TODO add a method to interface to get provider and get provider
577 // params in QgsRasterProjector
578 if ( projector )
579 {
580 // Force provider resampling if reprojection is needed
581 if ( ( mPipe->provider()->providerCapabilities() & Qgis::RasterProviderCapability::ProviderHintCanPerformProviderResampling ) &&
582 mRasterViewPort->mSrcCRS != mRasterViewPort->mDestCRS &&
583 oldResamplingState != Qgis::RasterResamplingStage::Provider )
584 {
585 restoreOldResamplingStage = true;
586 mPipe->setResamplingStage( Qgis::RasterResamplingStage::Provider );
587 }
588 projector->setCrs( mRasterViewPort->mSrcCRS, mRasterViewPort->mDestCRS, mRasterViewPort->mTransformContext );
589 }
590
591 preparingProfile.reset();
592 std::unique_ptr< QgsScopedRuntimeProfile > renderingProfile;
593 if ( mEnableProfile )
594 {
595 renderingProfile = std::make_unique< QgsScopedRuntimeProfile >( QObject::tr( "Rendering" ), QStringLiteral( "rendering" ) );
596 }
597
598 // Drawer to pipe?
599 QgsRasterIterator iterator( mPipe->last() );
600
601 // Get the maximum tile size from the provider and set it as the maximum tile size for the iterator
602 if ( QgsRasterDataProvider *provider = mPipe->provider() )
603 {
604 const QSize maxTileSize {provider->maximumTileSize()};
605 iterator.setMaximumTileWidth( maxTileSize.width() );
606 iterator.setMaximumTileHeight( maxTileSize.height() );
607 }
608
609 QgsRasterDrawer drawer( &iterator );
610 drawer.draw( *( renderContext() ), mRasterViewPort, mFeedback );
611
612 if ( mDrawElevationMap )
613 drawElevationMap();
614
615 renderingProfile.reset();
616
617 if ( mLabelProvider && !renderContext()->renderingStopped() )
618 {
619 std::unique_ptr< QgsScopedRuntimeProfile > labelingProfile;
620 if ( mEnableProfile )
621 {
622 labelingProfile = std::make_unique< QgsScopedRuntimeProfile >( QObject::tr( "Labeling" ), QStringLiteral( "rendering" ) );
623 }
624 drawLabeling();
625 }
626
627 if ( restoreOldResamplingStage )
628 {
629 mPipe->setResamplingStage( oldResamplingState );
630 }
631
632 const QStringList errors = mFeedback->errors();
633 for ( const QString &error : errors )
634 {
635 mErrors.append( error );
636 }
637
638 QgsDebugMsgLevel( QStringLiteral( "total raster draw time (ms): %1" ).arg( time.elapsed(), 5 ), 4 );
639 mReadyToCompose = true;
640
641 mPipe->moveToThread( nullptr );
642
643 return !mFeedback->isCanceled();
644}
645
647{
648 return mFeedback;
649}
650
652{
653 if ( !mRasterViewPort || !mPipe )
654 return false; // this layer is not going to get rendered
655
656 // preview of intermediate raster rendering results requires a temporary output image
658 return true;
659
660 if ( QgsRasterRenderer *renderer = mPipe->renderer() )
661 {
662 if ( !( renderer->flags() & Qgis::RasterRendererFlag::InternalLayerOpacityHandling ) )
663 {
664 switch ( renderContext()->rasterizedRenderingPolicy() )
665 {
668 break;
669
671 return false;
672 }
673
674 if ( !qgsDoubleNear( mLayerOpacity, 1.0 ) )
675 return true;
676 }
677 }
678
679 return false;
680}
681
682void QgsRasterLayerRenderer::prepareLabeling( QgsRasterLayer *layer )
683{
684 QgsRenderContext &context = *renderContext();
685
686 if ( QgsLabelingEngine *engine2 = context.labelingEngine() )
687 {
688 if ( QgsAbstractRasterLayerLabeling *labeling = layer->labeling() )
689 {
690 if ( layer->labelsEnabled() && labeling->isInScaleRange( context.rendererScale() ) )
691 {
692 std::unique_ptr< QgsRasterLayerLabelProvider > provider = labeling->provider( layer );
693 if ( provider )
694 {
695 // engine takes ownership
696 mLabelProvider = provider.release();
697 mLabelProvider->startRender( context );
698 engine2->addProvider( mLabelProvider );
699 }
700 }
701 }
702 }
703}
704
705void QgsRasterLayerRenderer::drawLabeling()
706{
707 if ( mLabelProvider )
708 mLabelProvider->generateLabels( *renderContext(), mPipe.get(), mRasterViewPort, mFeedback );
709}
710
711void QgsRasterLayerRenderer::drawElevationMap()
712{
713 QgsRasterDataProvider *dataProvider = mPipe->provider();
714 if ( renderContext()->elevationMap() && dataProvider )
715 {
716 double dpiScalefactor;
717
718 if ( renderContext()->dpiTarget() >= 0.0 )
719 dpiScalefactor = renderContext()->dpiTarget() / ( renderContext()->scaleFactor() * 25.4 );
720 else
721 dpiScalefactor = 1.0;
722
723 int outputWidth = static_cast<int>( static_cast<double>( mRasterViewPort->mWidth ) / dpiScalefactor * renderContext()->devicePixelRatio() );
724 int outputHeight = static_cast<int>( static_cast<double>( mRasterViewPort->mHeight ) / dpiScalefactor * renderContext()->devicePixelRatio() );
725
726 QSize viewSize = renderContext()->deviceOutputSize();
727 int viewWidth = static_cast<int>( viewSize.width() / dpiScalefactor );
728 int viewHeight = static_cast<int>( viewSize.height() / dpiScalefactor );
729
730 bool canRenderElevation = false;
731 std::unique_ptr<QgsRasterBlock> elevationBlock;
732 if ( mRasterViewPort->mSrcCRS == mRasterViewPort->mDestCRS )
733 {
734 elevationBlock.reset(
735 dataProvider->block(
736 mElevationBand,
737 mRasterViewPort->mDrawnExtent,
738 outputWidth,
739 outputHeight,
740 mFeedback ) );
741 canRenderElevation = true;
742 }
743 else
744 {
745 // Destinaton CRS is different from the source CRS.
746 // Using the raster projector lead to have big artifacts when rendering the elevation map.
747 // To get a smoother elevation map, we use GDAL resampling with coordinates transform
748 QgsRectangle viewExtentInLayerCoordinate = renderContext()->extent();
749
750 // If view extent is infinite, we use the data provider extent
751 if ( viewExtentInLayerCoordinate.xMinimum() == std::numeric_limits<double>::lowest() &&
752 viewExtentInLayerCoordinate.yMinimum() == std::numeric_limits<double>::lowest() &&
753 viewExtentInLayerCoordinate.xMaximum() == std::numeric_limits<double>::max() &&
754 viewExtentInLayerCoordinate.yMaximum() == std::numeric_limits<double>::max() )
755 {
756 viewExtentInLayerCoordinate = dataProvider->extent();
757 }
758
759 double xLayerResol = viewExtentInLayerCoordinate.width() / static_cast<double>( viewWidth );
760 double yLayerResol = viewExtentInLayerCoordinate.height() / static_cast<double>( viewHeight );
761
762 double overSampling = 1;
763 if ( mPipe->resampleFilter() )
764 overSampling = mPipe->resampleFilter()->maxOversampling();
765
767 {
768 // If the dataprovider has size capability, we calculate the requested resolution to provider
769 double providerXResol = dataProvider->extent().width() / dataProvider->xSize();
770 double providerYResol = dataProvider->extent().height() / dataProvider->ySize();
771 overSampling = ( xLayerResol / providerXResol + yLayerResol / providerYResol ) / 2;
772 }
773
774 GDALResampleAlg alg;
775 if ( overSampling > 1 )
777 else
779
780 Qgis::DataType dataType = dataProvider->dataType( mElevationBand );
781
782 if ( dataType != Qgis::DataType::UnknownDataType ) // resampling data by GDAL is not compatible with unknown data type
783 {
784 // we need extra pixels on border to avoid effect border with resampling (at least 2 pixels band for cubic alg)
785 int sourceWidth = viewWidth + 4;
786 int sourceHeight = viewHeight + 4;
787 viewExtentInLayerCoordinate = QgsRectangle(
788 viewExtentInLayerCoordinate.xMinimum() - xLayerResol * 2,
789 viewExtentInLayerCoordinate.yMinimum() - yLayerResol * 2,
790 viewExtentInLayerCoordinate.xMaximum() + xLayerResol * 2,
791 viewExtentInLayerCoordinate.yMaximum() + yLayerResol * 2 );
792
793 // Now we can do the resampling
794 std::unique_ptr<QgsRasterBlock> sourcedata( dataProvider->block( mElevationBand, viewExtentInLayerCoordinate, sourceWidth, sourceHeight, mFeedback ) );
795 gdal::dataset_unique_ptr gdalDsInput =
796 QgsGdalUtils::blockToSingleBandMemoryDataset( viewExtentInLayerCoordinate, sourcedata.get() );
797
798
799 elevationBlock = std::make_unique<QgsRasterBlock>( dataType,
800 outputWidth,
801 outputHeight );
802
803 elevationBlock->setNoDataValue( dataProvider->sourceNoDataValue( mElevationBand ) );
804
805 gdal::dataset_unique_ptr gdalDsOutput =
806 QgsGdalUtils::blockToSingleBandMemoryDataset( mRasterViewPort->mDrawnExtent, elevationBlock.get() );
807
808 // For coordinate transformation, we try to obtain a coordinate operation string from the transform context.
809 // Depending of the CRS, if we can't we use GDAL transformation directly from the source and destination CRS
810 QString coordinateOperation;
811 const QgsCoordinateTransformContext &transformContext = renderContext()->transformContext();
812 if ( transformContext.mustReverseCoordinateOperation( mRasterViewPort->mSrcCRS, mRasterViewPort->mDestCRS ) )
813 coordinateOperation = transformContext.calculateCoordinateOperation( mRasterViewPort->mDestCRS, mRasterViewPort->mSrcCRS );
814 else
815 coordinateOperation = transformContext.calculateCoordinateOperation( mRasterViewPort->mSrcCRS, mRasterViewPort->mDestCRS );
816
817 if ( coordinateOperation.isEmpty() )
818 canRenderElevation = QgsGdalUtils::resampleSingleBandRaster( gdalDsInput.get(), gdalDsOutput.get(), alg,
819 mRasterViewPort->mSrcCRS, mRasterViewPort->mDestCRS );
820 else
821 canRenderElevation = QgsGdalUtils::resampleSingleBandRaster( gdalDsInput.get(), gdalDsOutput.get(), alg,
822 coordinateOperation.toUtf8().constData() );
823 }
824 }
825
826 if ( canRenderElevation )
827 {
828 QPoint topLeft;
829 if ( renderContext()->mapToPixel().mapRotation() != 0 )
830 {
831 // Now rendering elevation on the elevation map, we need to take care of rotation:
832 // again a resampling but this time with a geotransform.
833 const QgsMapToPixel &mtp = renderContext()->mapToPixel();
834 QgsElevationMap *elevMap = renderContext()->elevationMap();
835
836 int elevMapWidth = elevMap->rawElevationImage().width();
837 int elevMapHeight = elevMap->rawElevationImage().height();
838
839 int bottom = 0;
840 int top = elevMapHeight;
841 int left = elevMapWidth;
842 int right = 0;
843
844 QList<QgsPointXY> corners;
845 corners << QgsPointXY( mRasterViewPort->mDrawnExtent.xMinimum(), mRasterViewPort->mDrawnExtent.yMinimum() )
846 << QgsPointXY( mRasterViewPort->mDrawnExtent.xMaximum(), mRasterViewPort->mDrawnExtent.yMaximum() )
847 << QgsPointXY( mRasterViewPort->mDrawnExtent.xMinimum(), mRasterViewPort->mDrawnExtent.yMaximum() )
848 << QgsPointXY( mRasterViewPort->mDrawnExtent.xMaximum(), mRasterViewPort->mDrawnExtent.yMinimum() );
849
850 for ( const QgsPointXY &corner : std::as_const( corners ) )
851 {
852 const QgsPointXY dpt = mtp.transform( corner );
853 int x = static_cast<int>( std::round( dpt.x() ) );
854 int y = static_cast<int>( std::round( dpt.y() ) );
855
856 if ( x < left )
857 left = x;
858 if ( x > right )
859 right = x;
860 if ( y < top )
861 top = y;
862 if ( y > bottom )
863 bottom = y;
864 }
865
866 const QgsPointXY origin = mtp.toMapCoordinates( left, top );
867 double gridXSize = mtp.toMapCoordinates( right, top ).distance( origin );
868 double gridYSize = mtp.toMapCoordinates( left, bottom ).distance( origin );
869 double angleRad = renderContext()->mapToPixel().mapRotation() / 180 * M_PI;
870
871 gdal::dataset_unique_ptr gdalDsInput =
872 QgsGdalUtils::blockToSingleBandMemoryDataset( mRasterViewPort->mDrawnExtent, elevationBlock.get() );
873
874 std::unique_ptr<QgsRasterBlock> rotatedElevationBlock =
875 std::make_unique<QgsRasterBlock>( elevationBlock->dataType(),
876 ( right - left ) * renderContext()->devicePixelRatio() + 1,
877 ( bottom - top ) * renderContext()->devicePixelRatio() + 1 );
878
879 rotatedElevationBlock->setNoDataValue( elevationBlock->noDataValue() );
880
881 gdal::dataset_unique_ptr gdalDsOutput =
882 QgsGdalUtils::blockToSingleBandMemoryDataset( angleRad, origin, gridXSize, gridYSize, rotatedElevationBlock.get() );
883
885 gdalDsInput.get(),
886 gdalDsOutput.get(),
888 {
889 elevationBlock = std::move( rotatedElevationBlock );
890 }
891
892 topLeft = QPoint( left, top );
893 }
894 else
895 {
896 topLeft = mRasterViewPort->mTopLeftPoint.toQPointF().toPoint();
897 }
898
900 elevationBlock.get(),
901 topLeft.y() * renderContext()->devicePixelRatio(),
902 topLeft.x() * renderContext()->devicePixelRatio(),
903 mElevationScale,
904 mElevationOffset );
905 }
906 }
907}
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.