QGIS API Documentation 4.3.0-Master (35968c35f7e)
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"
27#include "qgspainting.h"
29#include "qgsrasterdrawer.h"
30#include "qgsrasteriterator.h"
31#include "qgsrasterlabeling.h"
32#include "qgsrasterlayer.h"
35#include "qgsrasterlayerutils.h"
36#include "qgsrasternuller.h"
37#include "qgsrasterpipe.h"
38#include "qgsrasterprojector.h"
39#include "qgsrasterrenderer.h"
42#include "qgsrendercontext.h"
44#include "qgsruntimeprofiler.h"
45#include "qgsthreadingutils.h"
46#include "qgsunittypes.h"
47
48#include <QElapsedTimer>
49#include <QPointer>
50#include <QString>
51#include <QThread>
52
53#include "moc_qgsrasterlayerrenderer.cpp"
54
55using namespace Qt::StringLiterals;
56
58
59QgsRasterLayerRendererFeedback::QgsRasterLayerRendererFeedback( QgsRasterLayerRenderer *r )
60 : mR( r )
61{
63}
64
65void QgsRasterLayerRendererFeedback::onNewData()
66{
67 if ( !renderPartialOutput() )
68 return; // we were not asked for partial renders and we may not have a temporary image for overwriting...
69
70 // update only once upon a time
71 // (preview itself takes some time)
72 if ( mLastPreview.isValid() && mLastPreview.msecsTo( QTime::currentTime() ) < mMinimalPreviewInterval )
73 return;
74
75 // TODO: update only the area that got new data
76
77 QgsDebugMsgLevel( u"new raster preview! %1"_s.arg( mLastPreview.msecsTo( QTime::currentTime() ) ), 3 );
78 QElapsedTimer t;
79 t.start();
81 feedback.setPreviewOnly( true );
82 feedback.setRenderPartialOutput( true );
83 QgsRasterIterator iterator( mR->mPipe->last() );
84 QgsRasterDrawer drawer( &iterator );
85 drawer.draw( *( mR->renderContext() ), mR->mRasterViewPort.get(), &feedback );
86 mR->mReadyToCompose = true;
87 QgsDebugMsgLevel( u"total raster preview time: %1 ms"_s.arg( t.elapsed() ), 3 );
88 mLastPreview = QTime::currentTime();
89}
90
94 : QgsMapLayerRenderer( layer->id(), &rendererContext )
95 , mLayerName( layer->name() )
96 , mLayerOpacity( layer->opacity() )
97 , mProviderCapabilities( layer->dataProvider()->providerCapabilities() )
98 , mInterfaceCapabilities( layer->dataProvider()->capabilities() )
99 , mFeedback( std::make_unique<QgsRasterLayerRendererFeedback>( this ) )
100 , mEnableProfile( rendererContext.flags() & Qgis::RenderContextFlag::RecordProfile )
101{
102 mReadyToCompose = false;
103
104 QElapsedTimer timer;
105 timer.start();
106
107 QgsMapToPixel mapToPixel = rendererContext.mapToPixel();
108 if ( rendererContext.mapToPixel().mapRotation() )
109 {
110 // unset rotation for the sake of local computations.
111 // Rotation will be handled by QPainter later
112 // TODO: provide a method of QgsMapToPixel to fetch map center
113 // in geographical units
114 const QgsPointXY center = mapToPixel.toMapCoordinates( static_cast<int>( mapToPixel.mapWidth() / 2.0 ), static_cast<int>( mapToPixel.mapHeight() / 2.0 ) );
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( u"coordinateTransform set -> project extents."_s, 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( u"coordinateTransform not set"_s, 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( u"draw request outside view extent."_s, 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( u"draw request outside view extent."_s, 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( u"draw request outside view extent."_s, 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 = std::make_unique<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(), mRasterViewPort->mBottomRightPoint.y() ),
262 mapToPixel.toMapCoordinates( mRasterViewPort->mBottomRightPoint.x(), mRasterViewPort->mTopLeftPoint.y() )
263 );
264
265 //raster viewport top left / bottom right are already rounded to int
266 mRasterViewPort->mWidth = static_cast<qgssize>( std::abs( mRasterViewPort->mBottomRightPoint.x() - mRasterViewPort->mTopLeftPoint.x() ) );
267 mRasterViewPort->mHeight = static_cast<qgssize>( std::abs( mRasterViewPort->mBottomRightPoint.y() - mRasterViewPort->mTopLeftPoint.y() ) );
268
269 double dpi = 25.4 * rendererContext.scaleFactor();
270 if ( mProviderCapabilities & Qgis::RasterProviderCapability::DpiDependentData && rendererContext.dpiTarget() >= 0.0 )
271 {
272 const double dpiScaleFactor = rendererContext.dpiTarget() / dpi;
273 mRasterViewPort->mWidth *= dpiScaleFactor;
274 mRasterViewPort->mHeight *= dpiScaleFactor;
275 dpi = rendererContext.dpiTarget();
276 }
277 else
278 {
279 rendererContext.setDpiTarget( -1.0 );
280 }
281
282 //the drawable area can start to get very very large when you get down displaying 2x2 or smaller, this is because
283 //mapToPixel.mapUnitsPerPixel() is less then 1,
284 //so we will just get the pixel data and then render these special cases differently in paintImageToCanvas()
285
286 QgsDebugMsgLevel( u"mapUnitsPerPixel = %1"_s.arg( mapToPixel.mapUnitsPerPixel() ), 3 );
287 QgsDebugMsgLevel( u"mWidth = %1"_s.arg( layer->width() ), 3 );
288 QgsDebugMsgLevel( u"mHeight = %1"_s.arg( layer->height() ), 3 );
289 QgsDebugMsgLevel( u"visibleExtentOfRasterInMapCrs.xMinimum() = %1"_s.arg( visibleExtentOfRasterInMapCrs.xMinimum() ), 3 );
290 QgsDebugMsgLevel( u"visibleExtentOfRasterInMapCrs.xMaximum() = %1"_s.arg( visibleExtentOfRasterInMapCrs.xMaximum() ), 3 );
291 QgsDebugMsgLevel( u"visibleExtentOfRasterInMapCrs.yMinimum() = %1"_s.arg( visibleExtentOfRasterInMapCrs.yMinimum() ), 3 );
292 QgsDebugMsgLevel( u"visibleExtentOfRasterInMapCrs.yMaximum() = %1"_s.arg( visibleExtentOfRasterInMapCrs.yMaximum() ), 3 );
293
294 QgsDebugMsgLevel( u"mTopLeftPoint.x() = %1"_s.arg( mRasterViewPort->mTopLeftPoint.x() ), 3 );
295 QgsDebugMsgLevel( u"mBottomRightPoint.x() = %1"_s.arg( mRasterViewPort->mBottomRightPoint.x() ), 3 );
296 QgsDebugMsgLevel( u"mTopLeftPoint.y() = %1"_s.arg( mRasterViewPort->mTopLeftPoint.y() ), 3 );
297 QgsDebugMsgLevel( u"mBottomRightPoint.y() = %1"_s.arg( mRasterViewPort->mBottomRightPoint.y() ), 3 );
298
299 QgsDebugMsgLevel( u"mWidth = %1"_s.arg( mRasterViewPort->mWidth ), 3 );
300 QgsDebugMsgLevel( u"mHeight = %1"_s.arg( mRasterViewPort->mHeight ), 3 );
301
302 // /\/\/\ - added to handle zoomed-in rasters
303
304 // TODO R->mLastViewPort = *mRasterViewPort;
305
306 // TODO: is it necessary? Probably WMS only?
307 layer->dataProvider()->setDpi( std::floor( dpi * rendererContext.devicePixelRatio() ) );
308
309 // copy the whole raster pipe!
310 mPipe = std::make_unique<QgsRasterPipe>( *layer->pipe() );
311
312 QObject::connect( mPipe->provider(), &QgsRasterDataProvider::statusChanged, layer, &QgsRasterLayer::statusChanged );
313 QgsRasterRenderer *rasterRenderer = mPipe->renderer();
314 if ( rasterRenderer && !( rendererContext.flags() & Qgis::RenderContextFlag::RenderPreviewJob ) && !( rendererContext.flags() & Qgis::RenderContextFlag::Render3DMap ) )
315 {
316 if ( rasterRenderer->needsRefresh( rendererContext.extent() ) )
317 {
318 QList<double> minValues;
319 QList<double> maxValues;
320 const QgsRasterMinMaxOrigin &minMaxOrigin = rasterRenderer->minMaxOrigin();
321 for ( const int bandIdx : rasterRenderer->usesBands() )
322 {
323 double min;
324 double max;
325 layer->computeMinMax( bandIdx, minMaxOrigin, minMaxOrigin.limits(), rendererContext.extent(), static_cast<int>( QgsRasterLayer::SAMPLE_SIZE ), min, max );
326 minValues.append( min );
327 maxValues.append( max );
328 }
329
330 rasterRenderer->refresh( rendererContext.extent(), minValues, maxValues );
331 QgsRenderedLayerStatistics *layerStatistics = new QgsRenderedLayerStatistics( layer->id(), minValues, maxValues );
332 layerStatistics->setBoundingBox( rendererContext.extent() );
333 appendRenderedItemDetails( layerStatistics );
334 }
335 }
336
337 mPipe->evaluateDataDefinedProperties( rendererContext.expressionContext() );
338
339 const QgsRasterLayerTemporalProperties *temporalProperties = qobject_cast< const QgsRasterLayerTemporalProperties * >( layer->temporalProperties() );
340 const QgsRasterLayerElevationProperties *elevationProperties = qobject_cast<QgsRasterLayerElevationProperties *>( layer->elevationProperties() );
341
342 if ( ( temporalProperties->isActive() && renderContext()->isTemporal() ) || ( elevationProperties->hasElevation() && !renderContext()->zRange().isInfinite() ) )
343 {
344 // temporal and/or elevation band filtering may be applicable
345 bool matched = false;
346 const int matchedBand = QgsRasterLayerUtils::renderedBandForElevationAndTemporalRange( layer, rendererContext.temporalRange(), rendererContext.zRange(), matched );
347 if ( matched && matchedBand > 0 )
348 {
349 mPipe->renderer()->setInputBand( matchedBand );
350 }
351 }
352
353 if ( temporalProperties->isActive() && renderContext()->isTemporal() )
354 {
355 switch ( temporalProperties->mode() )
356 {
361 break;
362
364 if ( mPipe->renderer()->usesBands().contains( temporalProperties->bandNumber() ) )
365 {
366 // if layer has elevation settings and we are only rendering a temporal range => we need to filter pixels by temporal values
367 std::unique_ptr< QgsRasterTransparency > transparency;
368 if ( const QgsRasterTransparency *rendererTransparency = mPipe->renderer()->rasterTransparency() )
369 transparency = std::make_unique< QgsRasterTransparency >( *rendererTransparency );
370 else
371 transparency = std::make_unique< QgsRasterTransparency >();
372
373 QVector<QgsRasterTransparency::TransparentSingleValuePixel> transparentPixels = transparency->transparentSingleValuePixelList();
374
375 const QDateTime &offset = temporalProperties->temporalRepresentationOffset();
376 const QgsInterval &scale = temporalProperties->temporalRepresentationScale();
377 const double adjustedLower = static_cast< double >( offset.msecsTo( rendererContext.temporalRange().begin() ) )
379 / scale.originalDuration();
380 const double adjustedUpper = static_cast< double >( offset.msecsTo( rendererContext.temporalRange().end() ) )
382 / scale.originalDuration();
383 if ( !temporalProperties->accumulatePixels() )
384 {
385 transparentPixels.append( QgsRasterTransparency::TransparentSingleValuePixel( std::numeric_limits<double>::lowest(), adjustedLower, 0, true, !rendererContext.zRange().includeLower() ) );
386 }
387 transparentPixels.append( QgsRasterTransparency::TransparentSingleValuePixel( adjustedUpper, std::numeric_limits<double>::max(), 0, !rendererContext.zRange().includeUpper(), true ) );
388
389 transparency->setTransparentSingleValuePixelList( transparentPixels );
390 mPipe->renderer()->setRasterTransparency( transparency.release() );
391 }
392 break;
393
395 // in this mode we need to pass on the desired render temporal range to the data provider
396 if ( QgsRasterDataProviderTemporalCapabilities *temporalCapabilities = mPipe->provider()->temporalCapabilities() )
397 {
398 temporalCapabilities->setRequestedTemporalRange( rendererContext.temporalRange() );
399 temporalCapabilities->setIntervalHandlingMethod( temporalProperties->intervalHandlingMethod() );
400 }
401 break;
402 }
403 }
404 else if ( QgsRasterDataProviderTemporalCapabilities *temporalCapabilities = mPipe->provider()->temporalCapabilities() )
405 {
406 temporalCapabilities->setRequestedTemporalRange( QgsDateTimeRange() );
407 temporalCapabilities->setIntervalHandlingMethod( temporalProperties->intervalHandlingMethod() );
408 }
409
410 mClippingRegions = QgsMapClippingUtils::collectClippingRegionsForLayer( *renderContext(), layer );
411
412 if ( elevationProperties && elevationProperties->hasElevation() )
413 {
414 mDrawElevationMap = true;
415 mElevationScale = elevationProperties->zScale();
416 mElevationOffset = elevationProperties->zOffset();
417 mElevationBand = elevationProperties->bandNumber();
418
419 if ( !rendererContext.zRange().isInfinite() )
420 {
421 // NOLINTBEGIN(bugprone-branch-clone)
422 switch ( elevationProperties->mode() )
423 {
424 case Qgis::RasterElevationMode::FixedElevationRange:
425 // don't need to handle anything here -- the layer renderer will never be created if the
426 // render context range doesn't match the layer's fixed elevation range
427 break;
428
429 case Qgis::RasterElevationMode::FixedRangePerBand:
430 case Qgis::RasterElevationMode::DynamicRangePerBand:
431 // temporal/elevation band based filtering was already handled earlier in this method
432 break;
433
434 case Qgis::RasterElevationMode::RepresentsElevationSurface:
435 {
436 if ( mPipe->renderer()->usesBands().contains( mElevationBand ) )
437 {
438 // if layer has elevation settings and we are only rendering a slice of z values => we need to filter pixels by elevation
439 if ( mPipe->renderer()->flags() & Qgis::RasterRendererFlag::UseNoDataForOutOfRangePixels )
440 {
441 std::unique_ptr< QgsRasterNuller> nuller;
442 if ( const QgsRasterNuller *existingNuller = mPipe->nuller() )
443 nuller.reset( existingNuller->clone() );
444 else
445 nuller = std::make_unique< QgsRasterNuller >();
446
447 // account for z offset/zscale by reversing these calculations, so that we get the z range in
448 // raw pixel values
449 QgsRasterRangeList nullRanges;
450 const double adjustedLower = ( rendererContext.zRange().lower() - mElevationOffset ) / mElevationScale;
451 const double adjustedUpper = ( rendererContext.zRange().upper() - mElevationOffset ) / mElevationScale;
452 nullRanges.append(
453 QgsRasterRange( std::numeric_limits<double>::lowest(), adjustedLower, rendererContext.zRange().includeLower() ? QgsRasterRange::BoundsType::IncludeMin : QgsRasterRange::BoundsType::IncludeMinAndMax )
454 );
455 nullRanges.append(
456 QgsRasterRange( adjustedUpper, std::numeric_limits<double>::max(), rendererContext.zRange().includeUpper() ? QgsRasterRange::BoundsType::IncludeMax : QgsRasterRange::BoundsType::IncludeMinAndMax )
457 );
458 nuller->setOutputNoDataValue( mElevationBand, static_cast< int >( adjustedLower - 1 ) );
459 nuller->setNoData( mElevationBand, nullRanges );
460
461 if ( !mPipe->insert( 1, nuller.release() ) )
462 {
463 QgsDebugError( u"Cannot set pipe nuller"_s );
464 }
465 }
466 else
467 {
468 std::unique_ptr< QgsRasterTransparency > transparency;
469 if ( const QgsRasterTransparency *rendererTransparency = mPipe->renderer()->rasterTransparency() )
470 transparency = std::make_unique< QgsRasterTransparency >( *rendererTransparency );
471 else
472 transparency = std::make_unique< QgsRasterTransparency >();
473
474 QVector<QgsRasterTransparency::TransparentSingleValuePixel> transparentPixels = transparency->transparentSingleValuePixelList();
475
476 // account for z offset/zscale by reversing these calculations, so that we get the z range in
477 // raw pixel values
478 const double adjustedLower = ( rendererContext.zRange().lower() - mElevationOffset ) / mElevationScale;
479 const double adjustedUpper = ( rendererContext.zRange().upper() - mElevationOffset ) / mElevationScale;
480 transparentPixels.append( QgsRasterTransparency::TransparentSingleValuePixel( std::numeric_limits<double>::lowest(), adjustedLower, 0, true, !rendererContext.zRange().includeLower() ) );
481 transparentPixels.append( QgsRasterTransparency::TransparentSingleValuePixel( adjustedUpper, std::numeric_limits<double>::max(), 0, !rendererContext.zRange().includeUpper(), true ) );
482
483 transparency->setTransparentSingleValuePixelList( transparentPixels );
484 mPipe->renderer()->setRasterTransparency( transparency.release() );
485 }
486 }
487 break;
488 }
489 }
490 // NOLINTEND(bugprone-branch-clone)
491 }
492 }
493
494 prepareLabeling( layer );
495
496 mFeedback->setRenderContext( rendererContext );
497
498 mPipe->moveToThread( nullptr );
499
500 mPreparationTime = timer.elapsed();
501}
502
505
507{
508 QgsScopedThreadName threadName( u"render:%1"_s.arg( mLayerName ) );
509
510 std::unique_ptr< QgsScopedRuntimeProfile > profile;
511 if ( mEnableProfile )
512 {
513 profile = std::make_unique< QgsScopedRuntimeProfile >( mLayerName, u"rendering"_s, layerId() );
514 if ( mPreparationTime > 0 )
515 QgsApplication::profiler()->record( QObject::tr( "Create renderer" ), mPreparationTime / 1000.0, u"rendering"_s );
516 }
517
518 // Skip rendering of out of view tiles (xyz)
519 if ( !mRasterViewPort || ( renderContext()->testFlag( Qgis::RenderContextFlag::RenderPreviewJob ) && !( mInterfaceCapabilities & Qgis::RasterInterfaceCapability::Prefetch ) ) )
520 return true;
521
522 mPipe->moveToThread( QThread::currentThread() );
523
524 QElapsedTimer time;
525 time.start();
526
527 std::unique_ptr< QgsScopedRuntimeProfile > preparingProfile;
528 if ( mEnableProfile )
529 {
530 preparingProfile = std::make_unique< QgsScopedRuntimeProfile >( QObject::tr( "Preparing render" ), u"rendering"_s );
531 }
532
533 //
534 //
535 // The goal here is to make as many decisions as possible early on (outside of the rendering loop)
536 // so that we can maximise performance of the rendering process. So now we check which drawing
537 // procedure to use :
538 //
539
540 const QgsScopedQPainterState painterSate( renderContext()->painter() );
541
542 // important -- disable SmoothPixmapTransform and Antialiasing for raster layer renders. We want individual pixels to be clearly defined!
543 renderContext()->painter()->setRenderHint( QPainter::SmoothPixmapTransform, false );
544 bool antialiasEnabled = false;
545 if ( !mClippingRegions.empty() )
546 {
547 bool needsPainterClipPath = false;
548 const QPainterPath path = QgsMapClippingUtils::calculatePainterClipRegion( mClippingRegions, *renderContext(), Qgis::LayerType::Raster, needsPainterClipPath );
549 if ( needsPainterClipPath )
550 {
551 renderContext()->painter()->setClipPath( path, Qt::IntersectClip );
552 // this is an exception to the earlier flag disabling antialiasing!
553 // If we are rendering with clip paths, we WANT the boundaries of the raster to be
554 // rendered using antialiasing along the clip path, or things are very ugly! And since we can't
555 // selectively antialias JUST the clip path boundary, we fallback to antialiasing the
556 // whole raster render
557 antialiasEnabled = true;
558 }
559 }
560 renderContext()->painter()->setRenderHint( QPainter::Antialiasing, antialiasEnabled );
561
562 QgsRasterProjector *projector = mPipe->projector();
563 bool restoreOldResamplingStage = false;
564 const Qgis::RasterResamplingStage oldResamplingState = mPipe->resamplingStage();
565
566 // TODO add a method to interface to get provider and get provider
567 // params in QgsRasterProjector
568 if ( projector )
569 {
570 // Force provider resampling if reprojection is needed
571 if ( ( mPipe->provider()->providerCapabilities() & Qgis::RasterProviderCapability::ProviderHintCanPerformProviderResampling )
572 && mRasterViewPort->mSrcCRS != mRasterViewPort->mDestCRS
573 && oldResamplingState != Qgis::RasterResamplingStage::Provider )
574 {
575 restoreOldResamplingStage = true;
576 mPipe->setResamplingStage( Qgis::RasterResamplingStage::Provider );
577 }
578 projector->setCrs( mRasterViewPort->mSrcCRS, mRasterViewPort->mDestCRS, mRasterViewPort->mTransformContext );
579 }
580
581 preparingProfile.reset();
582 std::unique_ptr< QgsScopedRuntimeProfile > renderingProfile;
583 if ( mEnableProfile )
584 {
585 renderingProfile = std::make_unique< QgsScopedRuntimeProfile >( QObject::tr( "Rendering" ), u"rendering"_s );
586 }
587
588 // Drawer to pipe?
589 QgsRasterIterator iterator( mPipe->last() );
590
591 // Get the maximum tile size from the provider and set it as the maximum tile size for the iterator
592 if ( QgsRasterDataProvider *provider = mPipe->provider() )
593 {
594 const QSize maxTileSize { provider->maximumTileSize() };
595 iterator.setMaximumTileWidth( maxTileSize.width() );
596 iterator.setMaximumTileHeight( maxTileSize.height() );
597 }
598
599 QgsRasterDrawer drawer( &iterator );
600 drawer.draw( *( renderContext() ), mRasterViewPort.get(), mFeedback.get() );
601
602 if ( mDrawElevationMap )
603 drawElevationMap();
604
605 renderingProfile.reset();
606
607 if ( mLabelProvider && !renderContext()->renderingStopped() )
608 {
609 std::unique_ptr< QgsScopedRuntimeProfile > labelingProfile;
610 if ( mEnableProfile )
611 {
612 labelingProfile = std::make_unique< QgsScopedRuntimeProfile >( QObject::tr( "Labeling" ), u"rendering"_s );
613 }
614 drawLabeling();
615 }
616
617 if ( restoreOldResamplingStage )
618 {
619 mPipe->setResamplingStage( oldResamplingState );
620 }
621
622 const QStringList errors = mFeedback->errors();
623 for ( const QString &error : errors )
624 {
625 mErrors.append( error );
626 }
627
628 QgsDebugMsgLevel( u"total raster draw time (ms): %1"_s.arg( time.elapsed(), 5 ), 4 );
629 mReadyToCompose = true;
630
631 mPipe->moveToThread( nullptr );
632
633 return !mFeedback->isCanceled();
634}
635
637{
638 return mFeedback.get();
639}
640
642{
643 if ( !mRasterViewPort || !mPipe )
644 return false; // this layer is not going to get rendered
645
646 // preview of intermediate raster rendering results requires a temporary output image
648 return true;
649
650 if ( QgsRasterRenderer *renderer = mPipe->renderer() )
651 {
652 if ( !( renderer->flags() & Qgis::RasterRendererFlag::InternalLayerOpacityHandling ) )
653 {
654 switch ( renderContext()->rasterizedRenderingPolicy() )
655 {
658 break;
659
661 return false;
662 }
663
664 if ( !qgsDoubleNear( mLayerOpacity, 1.0 ) )
665 return true;
666 }
667 }
668
669 return false;
670}
671
672void QgsRasterLayerRenderer::prepareLabeling( QgsRasterLayer *layer )
673{
674 QgsRenderContext &context = *renderContext();
675
676 if ( QgsLabelingEngine *engine2 = context.labelingEngine() )
677 {
678 if ( QgsAbstractRasterLayerLabeling *labeling = layer->labeling() )
679 {
680 if ( layer->labelsEnabled() && labeling->isInScaleRange( context.rendererScale() ) )
681 {
682 std::unique_ptr< QgsRasterLayerLabelProvider > provider = labeling->provider( layer );
683 if ( provider )
684 {
685 // engine takes ownership
686 mLabelProvider = provider.release();
687 mLabelProvider->startRender( context );
688 engine2->addProvider( mLabelProvider );
689 }
690 }
691 }
692 }
693}
694
695void QgsRasterLayerRenderer::drawLabeling()
696{
697 if ( mLabelProvider )
698 mLabelProvider->generateLabels( *renderContext(), mPipe.get(), mRasterViewPort.get(), mFeedback.get() );
699}
700
701void QgsRasterLayerRenderer::drawElevationMap()
702{
703 QgsRasterDataProvider *dataProvider = mPipe->provider();
704 if ( renderContext()->elevationMap() && dataProvider )
705 {
706 double dpiScalefactor;
707
708 if ( renderContext()->dpiTarget() >= 0.0 )
709 dpiScalefactor = renderContext()->dpiTarget() / ( renderContext()->scaleFactor() * 25.4 );
710 else
711 dpiScalefactor = 1.0;
712
713 int outputWidth = static_cast<int>( static_cast<double>( mRasterViewPort->mWidth ) / dpiScalefactor * renderContext()->devicePixelRatio() );
714 int outputHeight = static_cast<int>( static_cast<double>( mRasterViewPort->mHeight ) / dpiScalefactor * renderContext()->devicePixelRatio() );
715
716 QSize viewSize = renderContext()->deviceOutputSize();
717 int viewWidth = static_cast<int>( viewSize.width() / dpiScalefactor );
718 int viewHeight = static_cast<int>( viewSize.height() / dpiScalefactor );
719
720 bool canRenderElevation = false;
721 std::unique_ptr<QgsRasterBlock> elevationBlock;
722 if ( mRasterViewPort->mSrcCRS == mRasterViewPort->mDestCRS )
723 {
724 elevationBlock.reset( dataProvider->block( mElevationBand, mRasterViewPort->mDrawnExtent, outputWidth, outputHeight, mFeedback.get() ) );
725 canRenderElevation = true;
726 }
727 else
728 {
729 // Destinaton CRS is different from the source CRS.
730 // Using the raster projector lead to have big artifacts when rendering the elevation map.
731 // To get a smoother elevation map, we use GDAL resampling with coordinates transform
732 QgsRectangle viewExtentInLayerCoordinate = renderContext()->extent();
733
734 // If view extent is infinite, we use the data provider extent
735 if ( viewExtentInLayerCoordinate.xMinimum() == std::numeric_limits<double>::lowest()
736 && viewExtentInLayerCoordinate.yMinimum() == std::numeric_limits<double>::lowest()
737 && viewExtentInLayerCoordinate.xMaximum() == std::numeric_limits<double>::max()
738 && viewExtentInLayerCoordinate.yMaximum() == std::numeric_limits<double>::max() )
739 {
740 viewExtentInLayerCoordinate = dataProvider->extent();
741 }
742
743 double xLayerResol = viewExtentInLayerCoordinate.width() / static_cast<double>( viewWidth );
744 double yLayerResol = viewExtentInLayerCoordinate.height() / static_cast<double>( viewHeight );
745
746 double overSampling = 1;
747 if ( mPipe->resampleFilter() )
748 overSampling = mPipe->resampleFilter()->maxOversampling();
749
751 {
752 // If the dataprovider has size capability, we calculate the requested resolution to provider
753 double providerXResol = dataProvider->extent().width() / dataProvider->xSize();
754 double providerYResol = dataProvider->extent().height() / dataProvider->ySize();
755 overSampling = ( xLayerResol / providerXResol + yLayerResol / providerYResol ) / 2;
756 }
757
758 GDALResampleAlg alg;
759 if ( overSampling > 1 )
761 else
763
764 Qgis::DataType dataType = dataProvider->dataType( mElevationBand );
765
766 if ( dataType != Qgis::DataType::UnknownDataType ) // resampling data by GDAL is not compatible with unknown data type
767 {
768 // we need extra pixels on border to avoid effect border with resampling (at least 2 pixels band for cubic alg)
769 int sourceWidth = viewWidth + 4;
770 int sourceHeight = viewHeight + 4;
771 viewExtentInLayerCoordinate = QgsRectangle(
772 viewExtentInLayerCoordinate.xMinimum() - xLayerResol * 2,
773 viewExtentInLayerCoordinate.yMinimum() - yLayerResol * 2,
774 viewExtentInLayerCoordinate.xMaximum() + xLayerResol * 2,
775 viewExtentInLayerCoordinate.yMaximum() + yLayerResol * 2
776 );
777
778 // Now we can do the resampling
779 std::unique_ptr<QgsRasterBlock> sourcedata( dataProvider->block( mElevationBand, viewExtentInLayerCoordinate, sourceWidth, sourceHeight, mFeedback.get() ) );
780 gdal::dataset_unique_ptr gdalDsInput = QgsGdalUtils::blockToSingleBandMemoryDataset( viewExtentInLayerCoordinate, sourcedata.get() );
781
782
783 elevationBlock = std::make_unique<QgsRasterBlock>( dataType, outputWidth, outputHeight );
784
785 elevationBlock->setNoDataValue( dataProvider->sourceNoDataValue( mElevationBand ) );
786
787 gdal::dataset_unique_ptr gdalDsOutput = QgsGdalUtils::blockToSingleBandMemoryDataset( mRasterViewPort->mDrawnExtent, elevationBlock.get() );
788
789 // For coordinate transformation, we try to obtain a coordinate operation string from the transform context.
790 // Depending of the CRS, if we can't we use GDAL transformation directly from the source and destination CRS
791 QString coordinateOperation;
792 const QgsCoordinateTransformContext &transformContext = renderContext()->transformContext();
793 if ( transformContext.mustReverseCoordinateOperation( mRasterViewPort->mSrcCRS, mRasterViewPort->mDestCRS ) )
794 coordinateOperation = transformContext.calculateCoordinateOperation( mRasterViewPort->mDestCRS, mRasterViewPort->mSrcCRS );
795 else
796 coordinateOperation = transformContext.calculateCoordinateOperation( mRasterViewPort->mSrcCRS, mRasterViewPort->mDestCRS );
797
798 if ( coordinateOperation.isEmpty() )
799 canRenderElevation = QgsGdalUtils::resampleSingleBandRaster( gdalDsInput.get(), gdalDsOutput.get(), alg, mRasterViewPort->mSrcCRS, mRasterViewPort->mDestCRS );
800 else
801 canRenderElevation = QgsGdalUtils::resampleSingleBandRaster( gdalDsInput.get(), gdalDsOutput.get(), alg, coordinateOperation.toUtf8().constData() );
802 }
803 }
804
805 if ( canRenderElevation )
806 {
807 QPoint topLeft;
808 if ( renderContext()->mapToPixel().mapRotation() != 0 )
809 {
810 // Now rendering elevation on the elevation map, we need to take care of rotation:
811 // again a resampling but this time with a geotransform.
812 const QgsMapToPixel &mtp = renderContext()->mapToPixel();
813 QgsElevationMap *elevMap = renderContext()->elevationMap();
814
815 int elevMapWidth = elevMap->rawElevationImage().width();
816 int elevMapHeight = elevMap->rawElevationImage().height();
817
818 int bottom = 0;
819 int top = elevMapHeight;
820 int left = elevMapWidth;
821 int right = 0;
822
823 QList<QgsPointXY> corners;
824 corners
825 << QgsPointXY( mRasterViewPort->mDrawnExtent.xMinimum(), mRasterViewPort->mDrawnExtent.yMinimum() )
826 << QgsPointXY( mRasterViewPort->mDrawnExtent.xMaximum(), mRasterViewPort->mDrawnExtent.yMaximum() )
827 << QgsPointXY( mRasterViewPort->mDrawnExtent.xMinimum(), mRasterViewPort->mDrawnExtent.yMaximum() )
828 << QgsPointXY( mRasterViewPort->mDrawnExtent.xMaximum(), mRasterViewPort->mDrawnExtent.yMinimum() );
829
830 for ( const QgsPointXY &corner : std::as_const( corners ) )
831 {
832 const QgsPointXY dpt = mtp.transform( corner );
833 int x = static_cast<int>( std::round( dpt.x() ) );
834 int y = static_cast<int>( std::round( dpt.y() ) );
835
836 if ( x < left )
837 left = x;
838 if ( x > right )
839 right = x;
840 if ( y < top )
841 top = y;
842 if ( y > bottom )
843 bottom = y;
844 }
845
846 const QgsPointXY origin = mtp.toMapCoordinates( left, top );
847 double gridXSize = mtp.toMapCoordinates( right, top ).distance( origin );
848 double gridYSize = mtp.toMapCoordinates( left, bottom ).distance( origin );
849 double angleRad = renderContext()->mapToPixel().mapRotation() / 180 * M_PI;
850
851 gdal::dataset_unique_ptr gdalDsInput = QgsGdalUtils::blockToSingleBandMemoryDataset( mRasterViewPort->mDrawnExtent, elevationBlock.get() );
852
853 std::unique_ptr<QgsRasterBlock> rotatedElevationBlock
854 = std::make_unique<QgsRasterBlock>( elevationBlock->dataType(), ( right - left ) * renderContext()->devicePixelRatio() + 1, ( bottom - top ) * renderContext()->devicePixelRatio() + 1 );
855
856 rotatedElevationBlock->setNoDataValue( elevationBlock->noDataValue() );
857
858 gdal::dataset_unique_ptr gdalDsOutput = QgsGdalUtils::blockToSingleBandMemoryDataset( angleRad, origin, gridXSize, gridYSize, rotatedElevationBlock.get() );
859
860 if ( QgsGdalUtils::resampleSingleBandRaster( gdalDsInput.get(), gdalDsOutput.get(), QgsGdalUtils::gdalResamplingAlgorithm( dataProvider->zoomedInResamplingMethod() ), nullptr ) )
861 {
862 elevationBlock = std::move( rotatedElevationBlock );
863 }
864
865 topLeft = QPoint( left, top );
866 }
867 else
868 {
869 topLeft = mRasterViewPort->mTopLeftPoint.toQPointF().toPoint();
870 }
871
872 renderContext()->elevationMap()->fillWithRasterBlock( elevationBlock.get(), topLeft.y() * renderContext()->devicePixelRatio(), topLeft.x() * renderContext()->devicePixelRatio(), mElevationScale, mElevationOffset );
873 }
874 }
875}
Provides global constants and enumerations for use throughout the application.
Definition qgis.h:62
@ Default
Allow raster-based rendering in situations where it is required for correct rendering or where it wil...
Definition qgis.h:2917
@ PreferVector
Prefer vector-based rendering, when the result will still be visually near-identical to a raster-base...
Definition qgis.h:2918
@ ForceVector
Always force vector-based rendering, even when the result will be visually different to a raster-base...
Definition qgis.h:2919
RasterResamplingStage
Stage at which raster resampling occurs.
Definition qgis.h:1639
@ Provider
Resampling occurs in Provider.
Definition qgis.h:1641
@ ProviderHintCanPerformProviderResampling
Provider can perform resampling (to be opposed to post rendering resampling).
Definition qgis.h:5446
@ DpiDependentData
Provider's rendering is dependent on requested pixel size of the viewport.
Definition qgis.h:5448
@ InternalLayerOpacityHandling
The renderer internally handles the raster layer's opacity, so the default layer level opacity handli...
Definition qgis.h:1672
@ Milliseconds
Milliseconds.
Definition qgis.h:5735
@ RepresentsTemporalValues
Pixel values represent an datetime.
Definition qgis.h:2836
@ RedrawLayerOnly
Redraw the layer when temporal range changes, but don't apply any filtering. Useful when raster symbo...
Definition qgis.h:2833
@ FixedRangePerBand
Layer has a fixed temporal range per band.
Definition qgis.h:2835
@ TemporalRangeFromDataProvider
Mode when raster layer delegates temporal range handling to the dataprovider.
Definition qgis.h:2832
@ FixedTemporalRange
Mode when temporal properties have fixed start and end datetimes.
Definition qgis.h:2831
@ FixedDateTime
Layer has a fixed date time instant.
Definition qgis.h:2837
@ Prefetch
Allow prefetching of out-of-view images.
Definition qgis.h:5419
@ Size
Original data source size (and thus resolution) is known, it is not always available,...
Definition qgis.h:5410
DataType
Raster data types.
Definition qgis.h:413
@ UnknownDataType
Unknown or unspecified type.
Definition qgis.h:414
@ Raster
Raster layer.
Definition qgis.h:208
@ RenderPreviewJob
Render is a 'canvas preview' render, and shortcuts should be taken to ensure fast rendering.
Definition qgis.h:2974
@ RenderPartialOutput
Whether to make extra effort to update map image with partially rendered layers (better for interacti...
Definition qgis.h:2973
@ Render3DMap
Render is for a 3D map.
Definition qgis.h:2979
Abstract base class for labeling settings for raster layers.
static QgsRuntimeProfiler * profiler()
Returns the application runtime profiler.
QString calculateCoordinateOperation(const QgsCoordinateReferenceSystem &source, const QgsCoordinateReferenceSystem &destination) const
Returns the Proj coordinate operation string to use when transforming from the specified source CRS t...
bool mustReverseCoordinateOperation(const QgsCoordinateReferenceSystem &source, const QgsCoordinateReferenceSystem &destination) const
Returns true if the coordinate operation returned by calculateCoordinateOperation() for the source to...
Handles coordinate transforms between two coordinate systems.
void setBallparkTransformsAreAppropriate(bool appropriate)
Sets whether approximate "ballpark" results are appropriate for this coordinate transform.
QgsRectangle transformBoundingBox(const QgsRectangle &rectangle, Qgis::TransformDirection direction=Qgis::TransformDirection::Forward, bool handle180Crossover=false) const
Transforms a rectangle from the source CRS to the destination CRS.
bool isValid() const
Returns true if the coordinate transform is valid, ie both the source and destination CRS have been s...
Custom exception class for Coordinate Reference System related exceptions.
QImage rawElevationImage() const
Returns raw elevation image with elevations encoded as color values.
void fillWithRasterBlock(QgsRasterBlock *block, int top, int left, double zScale=1.0, double offset=0.0)
Fills the elevation map with values contains in a raster block starting from position defined by top ...
QString what() const
Base class for feedback objects to be used for cancellation of something running in a worker thread.
Definition qgsfeedback.h:44
static bool resampleSingleBandRaster(GDALDatasetH hSrcDS, GDALDatasetH hDstDS, GDALResampleAlg resampleAlg, const char *pszCoordinateOperation)
Resamples a single band raster to the destination dataset with different resolution (and possibly wit...
static GDALResampleAlg gdalResamplingAlgorithm(Qgis::RasterResamplingMethod method)
Returns the GDAL resampling method corresponding to the QGIS resampling method.
static gdal::dataset_unique_ptr blockToSingleBandMemoryDataset(int pixelWidth, int pixelHeight, const QgsRectangle &extent, void *block, GDALDataType dataType)
Converts a data block to a single band GDAL memory dataset.
A representation of the interval between two datetime values.
Definition qgsinterval.h:52
double originalDuration() const
Returns the original interval duration.
Qgis::TemporalUnit originalUnit() const
Returns the original interval temporal unit.
Provides map labeling functionality.
static QPainterPath calculatePainterClipRegion(const QList< QgsMapClippingRegion > &regions, const QgsRenderContext &context, Qgis::LayerType layerType, bool &shouldClip)
Returns a QPainterPath representing the intersection of clipping regions from context which should be...
static QList< QgsMapClippingRegion > collectClippingRegionsForLayer(const QgsRenderContext &context, const QgsMapLayer *layer)
Collects the list of map clipping regions from a context which apply to a map layer.
bool mReadyToCompose
The flag must be set to false in renderer's constructor if wants to use the smarter map redraws funct...
QString layerId() const
Gets access to the ID of the layer rendered by this class.
virtual Qgis::MapLayerRendererFlags flags() const
Returns flags which control how the map layer rendering behaves.
QgsRenderContext * renderContext()
Returns the render context associated with the renderer.
QStringList errors() const
Returns list of errors (problems) that happened during the rendering.
QgsMapLayerRenderer(const QString &layerID, QgsRenderContext *context=nullptr)
Constructor for QgsMapLayerRenderer, with the associated layerID and render context.
void statusChanged(const QString &status)
Emit a signal with status (e.g. to be caught by QgisApp and display a msg on status bar).
Perform transforms between map coordinates and device coordinates.
QgsPointXY toMapCoordinates(int x, int y) const
Transforms device coordinates to map (world) coordinates.
QgsPointXY transform(const QgsPointXY &p) const
Transforms a point p from map (world) coordinates to device coordinates.
double mapRotation() const
Returns the current map rotation in degrees (clockwise).
static void logMessage(const QString &message, const QString &tag=QString(), Qgis::MessageLevel level=Qgis::MessageLevel::Warning, bool notifyUser=true, const char *file=__builtin_FILE(), const char *function=__builtin_FUNCTION(), int line=__builtin_LINE(), Qgis::StringFormat format=Qgis::StringFormat::PlainText)
Adds a message to the log instance (and creates it if necessary).
double distance(double x, double y) const
Returns the distance between this point and a specified x, y coordinate.
Definition qgspointxy.h:209
double y
Definition qgspointxy.h:66
double x
Definition qgspointxy.h:65
Feedback object tailored for raster block reading.
void setPreviewOnly(bool preview)
set flag whether the block request is for preview purposes only
void setRenderPartialOutput(bool enable)
Set whether our painter is drawing to a temporary image used just by this layer.
Implementation of data provider temporal properties for QgsRasterDataProviders.
Base class for raster data providers.
Qgis::RasterResamplingMethod zoomedInResamplingMethod() const
Returns resampling method for zoomed-in operations.
virtual double sourceNoDataValue(int bandNo) const
Value representing no data value.
QgsRectangle extent() const override=0
Returns the extent of the layer.
Qgis::DataType dataType(int bandNo) const override=0
Returns data type for the band specified by number.
Qgis::RasterResamplingMethod zoomedOutResamplingMethod() const
Returns resampling method for zoomed-out operations.
QgsRasterBlock * block(int bandNo, const QgsRectangle &boundingBox, int width, int height, QgsRasterBlockFeedback *feedback=nullptr) override
Read block of data using given extent and size.
void statusChanged(const QString &) const
Emit a message to be displayed on status bar, usually used by network providers (WMS,...
The drawing pipe for raster layers.
void draw(QPainter *p, QgsRasterViewPort *viewPort, const QgsMapToPixel *qgsMapToPixel, QgsRasterBlockFeedback *feedback=nullptr)
Draws raster data.
virtual Qgis::RasterInterfaceCapabilities capabilities() const
Returns the capabilities supported by the interface.
virtual int xSize() const
Gets raster size.
virtual int ySize() const
Iterator for sequentially processing raster cells.
void setMaximumTileWidth(int w)
Sets the maximum tile width returned during iteration.
void setMaximumTileHeight(int h)
Sets the minimum tile height returned during iteration.
Raster layer specific subclass of QgsMapLayerElevationProperties.
void startRender(QgsRenderContext &context) final
To be called before rendering of labels begins.
Implementation of threaded rendering for raster layers.
bool render() override
Do the rendering (based on data stored in the class).
QgsRasterLayerRenderer(QgsRasterLayer *layer, QgsRenderContext &rendererContext)
bool forceRasterRender() const override
Returns true if the renderer must be rendered to a raster paint device (e.g.
QgsFeedback * feedback() const override
Access to feedback object of the layer renderer (may be nullptr).
Implementation of map layer temporal properties for raster layers.
static int renderedBandForElevationAndTemporalRange(QgsRasterLayer *layer, const QgsDateTimeRange &temporalRange, const QgsDoubleRange &elevationRange, bool &matched)
Given a raster layer, returns the band which should be used for rendering the layer for a specified t...
Represents a raster layer.
const QgsAbstractRasterLayerLabeling * labeling() const
Access to const labeling configuration.
bool labelsEnabled() const
Returns whether the layer contains labels which are enabled and should be drawn.
Implements approximate projection support for optimised raster transformation.
Q_DECL_DEPRECATED void setCrs(const QgsCoordinateReferenceSystem &srcCRS, const QgsCoordinateReferenceSystem &destCRS, int srcDatumTransform=-1, int destDatumTransform=-1)
Sets the source and destination CRS.
Raster renderer pipe that applies colors to a raster.
Defines the list of pixel values to be considered as transparent or semi transparent when rendering r...
A rectangle specified with double values.
Q_INVOKABLE QString toString(int precision=16) const
Returns a string representation of form xmin,ymin : xmax,ymax Coordinates will be rounded to the spec...
double xMinimum
double yMinimum
double xMaximum
void set(const QgsPointXY &p1, const QgsPointXY &p2, bool normalize=true)
Sets the rectangle from two QgsPoints.
double yMaximum
QgsRectangle intersect(const QgsRectangle &rect) const
Returns the intersection with the given rectangle.
Contains information about the context of a rendering operation.
double scaleFactor() const
Returns the scaling factor for the render to convert painter units to physical sizes.
QPainter * painter()
Returns the destination QPainter for the render operation.
double rendererScale() const
Returns the renderer map scale.
QgsCoordinateTransformContext transformContext() const
Returns the context's coordinate transform context, which stores various information regarding which ...
QgsElevationMap * elevationMap() const
Returns the destination elevation map for the render operation.
const QgsRectangle & extent() const
When rendering a map layer, calling this method returns the "clipping" extent for the layer (in the l...
bool testFlag(Qgis::RenderContextFlag flag) const
Check whether a particular flag is enabled.
float devicePixelRatio() const
Returns the device pixel ratio.
double dpiTarget() const
Returns the targeted DPI for rendering.
const QgsMapToPixel & mapToPixel() const
Returns the context's map to pixel transform, which transforms between map coordinates and device coo...
QSize deviceOutputSize() const
Returns the device output size of the render.
QgsLabelingEngine * labelingEngine() const
Gets access to new labeling engine (may be nullptr).
QgsCoordinateTransform coordinateTransform() const
Returns the current coordinate transform for the context.
void record(const QString &name, double time, const QString &group="startup", const QString &id=QString())
Manually adds a profile event with the given name and total time (in seconds).
Scoped object for saving and restoring a QPainter object's state.
Scoped object for setting the current thread name.
static Q_INVOKABLE double fromUnitToUnitFactor(Qgis::DistanceUnit fromUnit, Qgis::DistanceUnit toUnit)
Returns the conversion factor between the specified distance units.
std::unique_ptr< std::remove_pointer< GDALDatasetH >::type, GDALDatasetCloser > dataset_unique_ptr
Scoped GDAL dataset.
unsigned long long qgssize
Qgssize is used instead of size_t, because size_t is stdlib type, unknown by SIP, and it would be har...
Definition qgis.h:8342
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference).
Definition qgis.h:7725
#define QgsDebugMsgLevel(str, level)
Definition qgslogger.h:80
Defines the transparency for a range of single-band pixel values.