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