QGIS API Documentation 3.39.0-Master (d85f3c2a281)
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 "qgsmessagelog.h"
20#include "qgsrasterdrawer.h"
21#include "qgsrasteriterator.h"
22#include "qgsrasterlayer.h"
23#include "qgsrasterprojector.h"
24#include "qgsrendercontext.h"
25#include "qgsrasterrenderer.h"
26#include "qgsexception.h"
28#include "qgsmapclippingutils.h"
29#include "qgsrasterpipe.h"
30#include "qgselevationmap.h"
31#include "qgsgdalutils.h"
34#include "qgsruntimeprofiler.h"
35#include "qgsapplication.h"
37#include "qgsrasterlayerutils.h"
38#include "qgsinterval.h"
39#include "qgsunittypes.h"
40#include "qgsrasternuller.h"
41
42#include <QElapsedTimer>
43#include <QPointer>
44#include <QThread>
45
47
48QgsRasterLayerRendererFeedback::QgsRasterLayerRendererFeedback( QgsRasterLayerRenderer *r )
49 : mR( r )
50 , mMinimalPreviewInterval( 250 )
51{
53}
54
55void QgsRasterLayerRendererFeedback::onNewData()
56{
57 if ( !renderPartialOutput() )
58 return; // we were not asked for partial renders and we may not have a temporary image for overwriting...
59
60 // update only once upon a time
61 // (preview itself takes some time)
62 if ( mLastPreview.isValid() && mLastPreview.msecsTo( QTime::currentTime() ) < mMinimalPreviewInterval )
63 return;
64
65 // TODO: update only the area that got new data
66
67 QgsDebugMsgLevel( QStringLiteral( "new raster preview! %1" ).arg( mLastPreview.msecsTo( QTime::currentTime() ) ), 3 );
68 QElapsedTimer t;
69 t.start();
71 feedback.setPreviewOnly( true );
72 feedback.setRenderPartialOutput( true );
73 QgsRasterIterator iterator( mR->mPipe->last() );
74 QgsRasterDrawer drawer( &iterator );
75 drawer.draw( *( mR->renderContext() ), mR->mRasterViewPort, &feedback );
76 mR->mReadyToCompose = true;
77 QgsDebugMsgLevel( QStringLiteral( "total raster preview time: %1 ms" ).arg( t.elapsed() ), 3 );
78 mLastPreview = QTime::currentTime();
79}
80
84 : QgsMapLayerRenderer( layer->id(), &rendererContext )
85 , mLayerName( layer->name() )
86 , mLayerOpacity( layer->opacity() )
87 , mProviderCapabilities( layer->dataProvider()->providerCapabilities() )
88 , mInterfaceCapabilities( layer->dataProvider()->capabilities() )
89 , mFeedback( new QgsRasterLayerRendererFeedback( this ) )
90 , mEnableProfile( rendererContext.flags() & Qgis::RenderContextFlag::RecordProfile )
91{
92 mReadyToCompose = false;
93
94 QElapsedTimer timer;
95 timer.start();
96
97 QgsMapToPixel mapToPixel = rendererContext.mapToPixel();
98 if ( rendererContext.mapToPixel().mapRotation() )
99 {
100 // unset rotation for the sake of local computations.
101 // Rotation will be handled by QPainter later
102 // TODO: provide a method of QgsMapToPixel to fetch map center
103 // in geographical units
104 const QgsPointXY center = mapToPixel.toMapCoordinates(
105 static_cast<int>( mapToPixel.mapWidth() / 2.0 ),
106 static_cast<int>( mapToPixel.mapHeight() / 2.0 )
107 );
108 mapToPixel.setMapRotation( 0, center.x(), center.y() );
109 }
110
111 QgsRectangle myProjectedViewExtent;
112 QgsRectangle myProjectedLayerExtent;
113
114 if ( rendererContext.coordinateTransform().isValid() )
115 {
116 QgsDebugMsgLevel( QStringLiteral( "coordinateTransform set -> project extents." ), 4 );
117 if ( rendererContext.extent().xMinimum() == std::numeric_limits<double>::lowest() &&
118 rendererContext.extent().yMinimum() == std::numeric_limits<double>::lowest() &&
119 rendererContext.extent().xMaximum() == std::numeric_limits<double>::max() &&
120 rendererContext.extent().yMaximum() == std::numeric_limits<double>::max() )
121 {
122 // We get in this situation if the view CRS is geographical and the
123 // extent goes beyond -180,-90,180,90. To avoid reprojection issues to the
124 // layer CRS, then this dummy extent is returned by QgsMapRendererJob::reprojectToLayerExtent()
125 // Don't try to reproject it now to view extent as this would return
126 // a null rectangle.
127 myProjectedViewExtent = rendererContext.extent();
128 }
129 else
130 {
131 try
132 {
133 QgsCoordinateTransform ct = rendererContext.coordinateTransform();
135 myProjectedViewExtent = ct.transformBoundingBox( rendererContext.extent() );
136 }
137 catch ( QgsCsException &cs )
138 {
139 QgsMessageLog::logMessage( QObject::tr( "Could not reproject view extent: %1" ).arg( cs.what() ), QObject::tr( "Raster" ) );
140 myProjectedViewExtent.setNull();
141 }
142 }
143
144 try
145 {
146 QgsCoordinateTransform ct = rendererContext.coordinateTransform();
148 myProjectedLayerExtent = ct.transformBoundingBox( layer->extent() );
149 }
150 catch ( QgsCsException &cs )
151 {
152 QgsMessageLog::logMessage( QObject::tr( "Could not reproject layer extent: %1" ).arg( cs.what() ), QObject::tr( "Raster" ) );
153 myProjectedLayerExtent.setNull();
154 }
155 }
156 else
157 {
158 QgsDebugMsgLevel( QStringLiteral( "coordinateTransform not set" ), 4 );
159 myProjectedViewExtent = rendererContext.extent();
160 myProjectedLayerExtent = layer->extent();
161 }
162
163 // clip raster extent to view extent
164 QgsRectangle myRasterExtent = layer->ignoreExtents() ? myProjectedViewExtent : myProjectedViewExtent.intersect( myProjectedLayerExtent );
165 if ( myRasterExtent.isEmpty() )
166 {
167 QgsDebugMsgLevel( QStringLiteral( "draw request outside view extent." ), 2 );
168 // nothing to do
169 return;
170 }
171
172 QgsDebugMsgLevel( "theViewExtent is " + rendererContext.extent().toString(), 4 );
173 QgsDebugMsgLevel( "myProjectedViewExtent is " + myProjectedViewExtent.toString(), 4 );
174 QgsDebugMsgLevel( "myProjectedLayerExtent is " + myProjectedLayerExtent.toString(), 4 );
175 QgsDebugMsgLevel( "myRasterExtent is " + myRasterExtent.toString(), 4 );
176
177 //
178 // The first thing we do is set up the QgsRasterViewPort. This struct stores all the settings
179 // relating to the size (in pixels and coordinate system units) of the raster part that is
180 // in view in the map window. It also stores the origin.
181 //
182 //this is not a class level member because every time the user pans or zooms
183 //the contents of the rasterViewPort will change
184 mRasterViewPort = new QgsRasterViewPort();
185
186 mRasterViewPort->mDrawnExtent = myRasterExtent;
187 if ( rendererContext.coordinateTransform().isValid() )
188 {
189 mRasterViewPort->mSrcCRS = layer->crs();
190 mRasterViewPort->mDestCRS = rendererContext.coordinateTransform().destinationCrs();
191 mRasterViewPort->mTransformContext = rendererContext.transformContext();
192 }
193 else
194 {
195 mRasterViewPort->mSrcCRS = QgsCoordinateReferenceSystem(); // will be invalid
196 mRasterViewPort->mDestCRS = QgsCoordinateReferenceSystem(); // will be invalid
197 }
198
199 // get dimensions of clipped raster image in device coordinate space (this is the size of the viewport)
200 mRasterViewPort->mTopLeftPoint = mapToPixel.transform( myRasterExtent.xMinimum(), myRasterExtent.yMaximum() );
201 mRasterViewPort->mBottomRightPoint = mapToPixel.transform( myRasterExtent.xMaximum(), myRasterExtent.yMinimum() );
202
203 // align to output device grid, i.e. std::floor/ceil to integers
204 // TODO: this should only be done if paint device is raster - screen, image
205 // for other devices (pdf) it can have floating point origin
206 // we could use floating point for raster devices as well, but respecting the
207 // output device grid should make it more effective as the resampling is done in
208 // the provider anyway
209 mRasterViewPort->mTopLeftPoint.setX( std::floor( mRasterViewPort->mTopLeftPoint.x() ) );
210 mRasterViewPort->mTopLeftPoint.setY( std::floor( mRasterViewPort->mTopLeftPoint.y() ) );
211 mRasterViewPort->mBottomRightPoint.setX( std::ceil( mRasterViewPort->mBottomRightPoint.x() ) );
212 mRasterViewPort->mBottomRightPoint.setY( std::ceil( mRasterViewPort->mBottomRightPoint.y() ) );
213 // recalc myRasterExtent to aligned values
214 myRasterExtent.set(
215 mapToPixel.toMapCoordinates( mRasterViewPort->mTopLeftPoint.x(),
216 mRasterViewPort->mBottomRightPoint.y() ),
217 mapToPixel.toMapCoordinates( mRasterViewPort->mBottomRightPoint.x(),
218 mRasterViewPort->mTopLeftPoint.y() )
219 );
220
221 //raster viewport top left / bottom right are already rounded to int
222 mRasterViewPort->mWidth = static_cast<qgssize>( std::abs( mRasterViewPort->mBottomRightPoint.x() - mRasterViewPort->mTopLeftPoint.x() ) );
223 mRasterViewPort->mHeight = static_cast<qgssize>( std::abs( mRasterViewPort->mBottomRightPoint.y() - mRasterViewPort->mTopLeftPoint.y() ) );
224
225 double dpi = 25.4 * rendererContext.scaleFactor();
226 if ( mProviderCapabilities & Qgis::RasterProviderCapability::DpiDependentData
227 && rendererContext.dpiTarget() >= 0.0 )
228 {
229 const double dpiScaleFactor = rendererContext.dpiTarget() / dpi;
230 mRasterViewPort->mWidth *= dpiScaleFactor;
231 mRasterViewPort->mHeight *= dpiScaleFactor;
232 dpi = rendererContext.dpiTarget();
233 }
234 else
235 {
236 rendererContext.setDpiTarget( -1.0 );
237 }
238
239 //the drawable area can start to get very very large when you get down displaying 2x2 or smaller, this is because
240 //mapToPixel.mapUnitsPerPixel() is less then 1,
241 //so we will just get the pixel data and then render these special cases differently in paintImageToCanvas()
242
243 QgsDebugMsgLevel( QStringLiteral( "mapUnitsPerPixel = %1" ).arg( mapToPixel.mapUnitsPerPixel() ), 3 );
244 QgsDebugMsgLevel( QStringLiteral( "mWidth = %1" ).arg( layer->width() ), 3 );
245 QgsDebugMsgLevel( QStringLiteral( "mHeight = %1" ).arg( layer->height() ), 3 );
246 QgsDebugMsgLevel( QStringLiteral( "myRasterExtent.xMinimum() = %1" ).arg( myRasterExtent.xMinimum() ), 3 );
247 QgsDebugMsgLevel( QStringLiteral( "myRasterExtent.xMaximum() = %1" ).arg( myRasterExtent.xMaximum() ), 3 );
248 QgsDebugMsgLevel( QStringLiteral( "myRasterExtent.yMinimum() = %1" ).arg( myRasterExtent.yMinimum() ), 3 );
249 QgsDebugMsgLevel( QStringLiteral( "myRasterExtent.yMaximum() = %1" ).arg( myRasterExtent.yMaximum() ), 3 );
250
251 QgsDebugMsgLevel( QStringLiteral( "mTopLeftPoint.x() = %1" ).arg( mRasterViewPort->mTopLeftPoint.x() ), 3 );
252 QgsDebugMsgLevel( QStringLiteral( "mBottomRightPoint.x() = %1" ).arg( mRasterViewPort->mBottomRightPoint.x() ), 3 );
253 QgsDebugMsgLevel( QStringLiteral( "mTopLeftPoint.y() = %1" ).arg( mRasterViewPort->mTopLeftPoint.y() ), 3 );
254 QgsDebugMsgLevel( QStringLiteral( "mBottomRightPoint.y() = %1" ).arg( mRasterViewPort->mBottomRightPoint.y() ), 3 );
255
256 QgsDebugMsgLevel( QStringLiteral( "mWidth = %1" ).arg( mRasterViewPort->mWidth ), 3 );
257 QgsDebugMsgLevel( QStringLiteral( "mHeight = %1" ).arg( mRasterViewPort->mHeight ), 3 );
258
259 // /\/\/\ - added to handle zoomed-in rasters
260
261 // TODO R->mLastViewPort = *mRasterViewPort;
262
263 // TODO: is it necessary? Probably WMS only?
264 layer->dataProvider()->setDpi( std::floor( dpi * rendererContext.devicePixelRatio() ) );
265
266 // copy the whole raster pipe!
267 mPipe.reset( new QgsRasterPipe( *layer->pipe() ) );
268
269 QObject::connect( mPipe->provider(), &QgsRasterDataProvider::statusChanged, layer, &QgsRasterLayer::statusChanged );
270 QgsRasterRenderer *rasterRenderer = mPipe->renderer();
271 if ( rasterRenderer
272 && !( rendererContext.flags() & Qgis::RenderContextFlag::RenderPreviewJob )
273 && !( rendererContext.flags() & Qgis::RenderContextFlag::Render3DMap ) )
274 {
275 layer->refreshRendererIfNeeded( rasterRenderer, rendererContext.extent() );
276 }
277
278 mPipe->evaluateDataDefinedProperties( rendererContext.expressionContext() );
279
280 const QgsRasterLayerTemporalProperties *temporalProperties = qobject_cast< const QgsRasterLayerTemporalProperties * >( layer->temporalProperties() );
281 const QgsRasterLayerElevationProperties *elevationProperties = qobject_cast<QgsRasterLayerElevationProperties *>( layer->elevationProperties() );
282
283 if ( ( temporalProperties->isActive() && renderContext()->isTemporal() )
284 || ( elevationProperties->hasElevation() && !renderContext()->zRange().isInfinite() ) )
285 {
286 // temporal and/or elevation band filtering may be applicable
287 bool matched = false;
289 layer,
290 rendererContext.temporalRange(),
291 rendererContext.zRange(),
292 matched
293 );
294 if ( matched && matchedBand > 0 )
295 {
296 mPipe->renderer()->setInputBand( matchedBand );
297 }
298 }
299
300 if ( temporalProperties->isActive() && renderContext()->isTemporal() )
301 {
302 switch ( temporalProperties->mode() )
303 {
307 break;
308
310 if ( mPipe->renderer()->usesBands().contains( temporalProperties->bandNumber() ) )
311 {
312 // if layer has elevation settings and we are only rendering a temporal range => we need to filter pixels by temporal values
313 std::unique_ptr< QgsRasterTransparency > transparency;
314 if ( const QgsRasterTransparency *rendererTransparency = mPipe->renderer()->rasterTransparency() )
315 transparency = std::make_unique< QgsRasterTransparency >( *rendererTransparency );
316 else
317 transparency = std::make_unique< QgsRasterTransparency >();
318
319 QVector<QgsRasterTransparency::TransparentSingleValuePixel> transparentPixels = transparency->transparentSingleValuePixelList();
320
321 const QDateTime &offset = temporalProperties->temporalRepresentationOffset();
322 const QgsInterval &scale = temporalProperties->temporalRepresentationScale();
323 const double adjustedLower = static_cast< double >( offset.msecsTo( rendererContext.temporalRange().begin() ) ) * QgsUnitTypes::fromUnitToUnitFactor( Qgis::TemporalUnit::Milliseconds, scale.originalUnit() ) / scale.originalDuration();
324 const double adjustedUpper = static_cast< double >( offset.msecsTo( rendererContext.temporalRange().end() ) ) * QgsUnitTypes::fromUnitToUnitFactor( Qgis::TemporalUnit::Milliseconds, scale.originalUnit() ) / scale.originalDuration();
325 transparentPixels.append( QgsRasterTransparency::TransparentSingleValuePixel( std::numeric_limits<double>::lowest(), adjustedLower, 0, true, !rendererContext.zRange().includeLower() ) );
326 transparentPixels.append( QgsRasterTransparency::TransparentSingleValuePixel( adjustedUpper, std::numeric_limits<double>::max(), 0, !rendererContext.zRange().includeUpper(), true ) );
327
328 transparency->setTransparentSingleValuePixelList( transparentPixels );
329 mPipe->renderer()->setRasterTransparency( transparency.release() );
330 }
331 break;
332
334 // in this mode we need to pass on the desired render temporal range to the data provider
335 if ( QgsRasterDataProviderTemporalCapabilities *temporalCapabilities = mPipe->provider()->temporalCapabilities() )
336 {
337 temporalCapabilities->setRequestedTemporalRange( rendererContext.temporalRange() );
338 temporalCapabilities->setIntervalHandlingMethod( temporalProperties->intervalHandlingMethod() );
339 }
340 break;
341 }
342 }
343 else if ( QgsRasterDataProviderTemporalCapabilities *temporalCapabilities = mPipe->provider()->temporalCapabilities() )
344 {
345 temporalCapabilities->setRequestedTemporalRange( QgsDateTimeRange() );
346 temporalCapabilities->setIntervalHandlingMethod( temporalProperties->intervalHandlingMethod() );
347 }
348
350
351 if ( elevationProperties && elevationProperties->hasElevation() )
352 {
353 mDrawElevationMap = true;
354 mElevationScale = elevationProperties->zScale();
355 mElevationOffset = elevationProperties->zOffset();
356 mElevationBand = elevationProperties->bandNumber();
357
358 if ( !rendererContext.zRange().isInfinite() )
359 {
360 // NOLINTBEGIN(bugprone-branch-clone)
361 switch ( elevationProperties->mode() )
362 {
364 // don't need to handle anything here -- the layer renderer will never be created if the
365 // render context range doesn't match the layer's fixed elevation range
366 break;
367
370 // temporal/elevation band based filtering was already handled earlier in this method
371 break;
372
374 {
375 if ( mPipe->renderer()->usesBands().contains( mElevationBand ) )
376 {
377 // if layer has elevation settings and we are only rendering a slice of z values => we need to filter pixels by elevation
378 if ( mPipe->renderer()->flags() & Qgis::RasterRendererFlag::UseNoDataForOutOfRangePixels )
379 {
380 std::unique_ptr< QgsRasterNuller> nuller;
381 if ( const QgsRasterNuller *existingNuller = mPipe->nuller() )
382 nuller.reset( existingNuller->clone() );
383 else
384 nuller = std::make_unique< QgsRasterNuller >();
385
386 // account for z offset/zscale by reversing these calculations, so that we get the z range in
387 // raw pixel values
388 QgsRasterRangeList nullRanges;
389 const double adjustedLower = ( rendererContext.zRange().lower() - mElevationOffset ) / mElevationScale;
390 const double adjustedUpper = ( rendererContext.zRange().upper() - mElevationOffset ) / mElevationScale;
391 nullRanges.append( QgsRasterRange( std::numeric_limits<double>::lowest(), adjustedLower, rendererContext.zRange().includeLower() ? QgsRasterRange::BoundsType::IncludeMin : QgsRasterRange::BoundsType::IncludeMinAndMax ) );
392 nullRanges.append( QgsRasterRange( adjustedUpper, std::numeric_limits<double>::max(), rendererContext.zRange().includeUpper() ? QgsRasterRange::BoundsType::IncludeMax : QgsRasterRange::BoundsType::IncludeMinAndMax ) );
393 nuller->setOutputNoDataValue( mElevationBand, static_cast< int >( adjustedLower - 1 ) );
394 nuller->setNoData( mElevationBand, nullRanges );
395
396 if ( !mPipe->insert( 1, nuller.release() ) )
397 {
398 QgsDebugError( QStringLiteral( "Cannot set pipe nuller" ) );
399 }
400 }
401 else
402 {
403 std::unique_ptr< QgsRasterTransparency > transparency;
404 if ( const QgsRasterTransparency *rendererTransparency = mPipe->renderer()->rasterTransparency() )
405 transparency = std::make_unique< QgsRasterTransparency >( *rendererTransparency );
406 else
407 transparency = std::make_unique< QgsRasterTransparency >();
408
409 QVector<QgsRasterTransparency::TransparentSingleValuePixel> transparentPixels = transparency->transparentSingleValuePixelList();
410
411 // account for z offset/zscale by reversing these calculations, so that we get the z range in
412 // raw pixel values
413 const double adjustedLower = ( rendererContext.zRange().lower() - mElevationOffset ) / mElevationScale;
414 const double adjustedUpper = ( rendererContext.zRange().upper() - mElevationOffset ) / mElevationScale;
415 transparentPixels.append( QgsRasterTransparency::TransparentSingleValuePixel( std::numeric_limits<double>::lowest(), adjustedLower, 0, true, !rendererContext.zRange().includeLower() ) );
416 transparentPixels.append( QgsRasterTransparency::TransparentSingleValuePixel( adjustedUpper, std::numeric_limits<double>::max(), 0, !rendererContext.zRange().includeUpper(), true ) );
417
418 transparency->setTransparentSingleValuePixelList( transparentPixels );
419 mPipe->renderer()->setRasterTransparency( transparency.release() );
420 }
421 }
422 break;
423 }
424 }
425 // NOLINTEND(bugprone-branch-clone)
426 }
427 }
428
429 mFeedback->setRenderContext( rendererContext );
430
431 mPipe->moveToThread( nullptr );
432
433 mPreparationTime = timer.elapsed();
434}
435
437{
438 delete mFeedback;
439
440 delete mRasterViewPort;
441}
442
444{
445 std::unique_ptr< QgsScopedRuntimeProfile > profile;
446 if ( mEnableProfile )
447 {
448 profile = std::make_unique< QgsScopedRuntimeProfile >( mLayerName, QStringLiteral( "rendering" ), layerId() );
449 if ( mPreparationTime > 0 )
450 QgsApplication::profiler()->record( QObject::tr( "Create renderer" ), mPreparationTime / 1000.0, QStringLiteral( "rendering" ) );
451 }
452
453 // Skip rendering of out of view tiles (xyz)
454 if ( !mRasterViewPort || ( renderContext()->testFlag( Qgis::RenderContextFlag::RenderPreviewJob ) &&
455 !( mInterfaceCapabilities &
457 return true;
458
459 mPipe->moveToThread( QThread::currentThread() );
460
461 QElapsedTimer time;
462 time.start();
463
464 std::unique_ptr< QgsScopedRuntimeProfile > preparingProfile;
465 if ( mEnableProfile )
466 {
467 preparingProfile = std::make_unique< QgsScopedRuntimeProfile >( QObject::tr( "Preparing render" ), QStringLiteral( "rendering" ) );
468 }
469
470 //
471 //
472 // The goal here is to make as many decisions as possible early on (outside of the rendering loop)
473 // so that we can maximise performance of the rendering process. So now we check which drawing
474 // procedure to use :
475 //
476
477 const QgsScopedQPainterState painterSate( renderContext()->painter() );
478 if ( !mClippingRegions.empty() )
479 {
480 bool needsPainterClipPath = false;
481 const QPainterPath path = QgsMapClippingUtils::calculatePainterClipRegion( mClippingRegions, *renderContext(), Qgis::LayerType::Raster, needsPainterClipPath );
482 if ( needsPainterClipPath )
483 renderContext()->painter()->setClipPath( path, Qt::IntersectClip );
484 }
485
486 QgsRasterProjector *projector = mPipe->projector();
487 bool restoreOldResamplingStage = false;
488 const Qgis::RasterResamplingStage oldResamplingState = mPipe->resamplingStage();
489
490 // TODO add a method to interface to get provider and get provider
491 // params in QgsRasterProjector
492 if ( projector )
493 {
494 // Force provider resampling if reprojection is needed
495 if ( ( mPipe->provider()->providerCapabilities() & Qgis::RasterProviderCapability::ProviderHintCanPerformProviderResampling ) &&
496 mRasterViewPort->mSrcCRS != mRasterViewPort->mDestCRS &&
497 oldResamplingState != Qgis::RasterResamplingStage::Provider )
498 {
499 restoreOldResamplingStage = true;
500 mPipe->setResamplingStage( Qgis::RasterResamplingStage::Provider );
501 }
502 projector->setCrs( mRasterViewPort->mSrcCRS, mRasterViewPort->mDestCRS, mRasterViewPort->mTransformContext );
503 }
504
505 // important -- disable SmoothPixmapTransform for raster layer renders. We want individual pixels to be clearly defined!
506 renderContext()->painter()->setRenderHint( QPainter::SmoothPixmapTransform, false );
507
508 preparingProfile.reset();
509 std::unique_ptr< QgsScopedRuntimeProfile > renderingProfile;
510 if ( mEnableProfile )
511 {
512 renderingProfile = std::make_unique< QgsScopedRuntimeProfile >( QObject::tr( "Rendering" ), QStringLiteral( "rendering" ) );
513 }
514
515 // Drawer to pipe?
516 QgsRasterIterator iterator( mPipe->last() );
517 QgsRasterDrawer drawer( &iterator );
518 drawer.draw( *( renderContext() ), mRasterViewPort, mFeedback );
519
520 if ( mDrawElevationMap )
521 drawElevationMap();
522
523 if ( restoreOldResamplingStage )
524 {
525 mPipe->setResamplingStage( oldResamplingState );
526 }
527
528 const QStringList errors = mFeedback->errors();
529 for ( const QString &error : errors )
530 {
531 mErrors.append( error );
532 }
533
534 QgsDebugMsgLevel( QStringLiteral( "total raster draw time (ms): %1" ).arg( time.elapsed(), 5 ), 4 );
535 mReadyToCompose = true;
536
537 mPipe->moveToThread( nullptr );
538
539 return !mFeedback->isCanceled();
540}
541
543{
544 return mFeedback;
545}
546
548{
549 if ( !mRasterViewPort || !mPipe )
550 return false; // this layer is not going to get rendered
551
552 // preview of intermediate raster rendering results requires a temporary output image
554 return true;
555
556 if ( QgsRasterRenderer *renderer = mPipe->renderer() )
557 {
559 && renderContext()->testFlag( Qgis::RenderContextFlag::UseAdvancedEffects ) && ( !qgsDoubleNear( mLayerOpacity, 1.0 ) ) )
560 return true;
561 }
562
563 return false;
564}
565
566void QgsRasterLayerRenderer::drawElevationMap()
567{
568 QgsRasterDataProvider *dataProvider = mPipe->provider();
569 if ( renderContext()->elevationMap() && dataProvider )
570 {
571 double dpiScalefactor;
572
573 if ( renderContext()->dpiTarget() >= 0.0 )
574 dpiScalefactor = renderContext()->dpiTarget() / ( renderContext()->scaleFactor() * 25.4 );
575 else
576 dpiScalefactor = 1.0;
577
578 int outputWidth = static_cast<int>( static_cast<double>( mRasterViewPort->mWidth ) / dpiScalefactor * renderContext()->devicePixelRatio() );
579 int outputHeight = static_cast<int>( static_cast<double>( mRasterViewPort->mHeight ) / dpiScalefactor * renderContext()->devicePixelRatio() );
580
581 QSize viewSize = renderContext()->deviceOutputSize();
582 int viewWidth = static_cast<int>( viewSize.width() / dpiScalefactor );
583 int viewHeight = static_cast<int>( viewSize.height() / dpiScalefactor );
584
585 bool canRenderElevation = false;
586 std::unique_ptr<QgsRasterBlock> elevationBlock;
587 if ( mRasterViewPort->mSrcCRS == mRasterViewPort->mDestCRS )
588 {
589 elevationBlock.reset(
590 dataProvider->block(
591 mElevationBand,
592 mRasterViewPort->mDrawnExtent,
593 outputWidth,
594 outputHeight,
595 mFeedback ) );
596 canRenderElevation = true;
597 }
598 else
599 {
600 // Destinaton CRS is different from the source CRS.
601 // Using the raster projector lead to have big artifacts when rendering the elevation map.
602 // To get a smoother elevation map, we use GDAL resampling with coordinates transform
603 QgsRectangle viewExtentInLayerCoordinate = renderContext()->extent();
604
605 // If view extent is infinite, we use the data provider extent
606 if ( viewExtentInLayerCoordinate.xMinimum() == std::numeric_limits<double>::lowest() &&
607 viewExtentInLayerCoordinate.yMinimum() == std::numeric_limits<double>::lowest() &&
608 viewExtentInLayerCoordinate.xMaximum() == std::numeric_limits<double>::max() &&
609 viewExtentInLayerCoordinate.yMaximum() == std::numeric_limits<double>::max() )
610 {
611 viewExtentInLayerCoordinate = dataProvider->extent();
612 }
613
614 double xLayerResol = viewExtentInLayerCoordinate.width() / static_cast<double>( viewWidth );
615 double yLayerResol = viewExtentInLayerCoordinate.height() / static_cast<double>( viewHeight );
616
617 double overSampling = 1;
618 if ( mPipe->resampleFilter() )
619 overSampling = mPipe->resampleFilter()->maxOversampling();
620
622 {
623 // If the dataprovider has size capability, we calculate the requested resolution to provider
624 double providerXResol = dataProvider->extent().width() / dataProvider->xSize();
625 double providerYResol = dataProvider->extent().height() / dataProvider->ySize();
626 overSampling = ( xLayerResol / providerXResol + yLayerResol / providerYResol ) / 2;
627 }
628
629 GDALResampleAlg alg;
630 if ( overSampling > 1 )
632 else
634
635 Qgis::DataType dataType = dataProvider->dataType( mElevationBand );
636
637 if ( dataType != Qgis::DataType::UnknownDataType ) // resampling data by GDAL is not compatible with unknown data type
638 {
639 // we need extra pixels on border to avoid effect border with resampling (at least 2 pixels band for cubic alg)
640 int sourceWidth = viewWidth + 4;
641 int sourceHeight = viewHeight + 4;
642 viewExtentInLayerCoordinate = QgsRectangle(
643 viewExtentInLayerCoordinate.xMinimum() - xLayerResol * 2,
644 viewExtentInLayerCoordinate.yMinimum() - yLayerResol * 2,
645 viewExtentInLayerCoordinate.xMaximum() + xLayerResol * 2,
646 viewExtentInLayerCoordinate.yMaximum() + yLayerResol * 2 );
647
648 // Now we can do the resampling
649 std::unique_ptr<QgsRasterBlock> sourcedata( dataProvider->block( mElevationBand, viewExtentInLayerCoordinate, sourceWidth, sourceHeight, mFeedback ) );
650 gdal::dataset_unique_ptr gdalDsInput =
651 QgsGdalUtils::blockToSingleBandMemoryDataset( viewExtentInLayerCoordinate, sourcedata.get() );
652
653
654 elevationBlock.reset( new QgsRasterBlock( dataType,
655 outputWidth,
656 outputHeight ) );
657
658 elevationBlock->setNoDataValue( dataProvider->sourceNoDataValue( mElevationBand ) );
659
660 gdal::dataset_unique_ptr gdalDsOutput =
661 QgsGdalUtils::blockToSingleBandMemoryDataset( mRasterViewPort->mDrawnExtent, elevationBlock.get() );
662
663 // For coordinate transformation, we try to obtain a coordinate operation string from the transform context.
664 // Depending of the CRS, if we can't we use GDAL transformation directly from the source and destination CRS
665 QString coordinateOperation;
666 const QgsCoordinateTransformContext &transformContext = renderContext()->transformContext();
667 if ( transformContext.mustReverseCoordinateOperation( mRasterViewPort->mSrcCRS, mRasterViewPort->mDestCRS ) )
668 coordinateOperation = transformContext.calculateCoordinateOperation( mRasterViewPort->mDestCRS, mRasterViewPort->mSrcCRS );
669 else
670 coordinateOperation = transformContext.calculateCoordinateOperation( mRasterViewPort->mSrcCRS, mRasterViewPort->mDestCRS );
671
672 if ( coordinateOperation.isEmpty() )
673 canRenderElevation = QgsGdalUtils::resampleSingleBandRaster( gdalDsInput.get(), gdalDsOutput.get(), alg,
674 mRasterViewPort->mSrcCRS, mRasterViewPort->mDestCRS );
675 else
676 canRenderElevation = QgsGdalUtils::resampleSingleBandRaster( gdalDsInput.get(), gdalDsOutput.get(), alg,
677 coordinateOperation.toUtf8().constData() );
678 }
679 }
680
681 if ( canRenderElevation )
682 {
683 QPoint topLeft;
684 if ( renderContext()->mapToPixel().mapRotation() != 0 )
685 {
686 // Now rendering elevation on the elevation map, we need to take care of rotation:
687 // again a resampling but this time with a geotransform.
688 const QgsMapToPixel &mtp = renderContext()->mapToPixel();
690
691 int elevMapWidth = elevMap->rawElevationImage().width();
692 int elevMapHeight = elevMap->rawElevationImage().height();
693
694 int bottom = 0;
695 int top = elevMapHeight;
696 int left = elevMapWidth;
697 int right = 0;
698
699 QList<QgsPointXY> corners;
700 corners << QgsPointXY( mRasterViewPort->mDrawnExtent.xMinimum(), mRasterViewPort->mDrawnExtent.yMinimum() )
701 << QgsPointXY( mRasterViewPort->mDrawnExtent.xMaximum(), mRasterViewPort->mDrawnExtent.yMaximum() )
702 << QgsPointXY( mRasterViewPort->mDrawnExtent.xMinimum(), mRasterViewPort->mDrawnExtent.yMaximum() )
703 << QgsPointXY( mRasterViewPort->mDrawnExtent.xMaximum(), mRasterViewPort->mDrawnExtent.yMinimum() );
704
705 for ( const QgsPointXY &corner : std::as_const( corners ) )
706 {
707 const QgsPointXY dpt = mtp.transform( corner );
708 int x = static_cast<int>( std::round( dpt.x() ) );
709 int y = static_cast<int>( std::round( dpt.y() ) );
710
711 if ( x < left )
712 left = x;
713 if ( x > right )
714 right = x;
715 if ( y < top )
716 top = y;
717 if ( y > bottom )
718 bottom = y;
719 }
720
721 const QgsPointXY origin = mtp.toMapCoordinates( left, top );
722 double gridXSize = mtp.toMapCoordinates( right, top ).distance( origin );
723 double gridYSize = mtp.toMapCoordinates( left, bottom ).distance( origin );
724 double angleRad = renderContext()->mapToPixel().mapRotation() / 180 * M_PI;
725
726 gdal::dataset_unique_ptr gdalDsInput =
727 QgsGdalUtils::blockToSingleBandMemoryDataset( mRasterViewPort->mDrawnExtent, elevationBlock.get() );
728
729 std::unique_ptr<QgsRasterBlock> rotatedElevationBlock =
730 std::make_unique<QgsRasterBlock>( elevationBlock->dataType(),
731 ( right - left ) * renderContext()->devicePixelRatio() + 1,
732 ( bottom - top ) * renderContext()->devicePixelRatio() + 1 );
733
734 rotatedElevationBlock->setNoDataValue( elevationBlock->noDataValue() );
735
736 gdal::dataset_unique_ptr gdalDsOutput =
737 QgsGdalUtils::blockToSingleBandMemoryDataset( angleRad, origin, gridXSize, gridYSize, rotatedElevationBlock.get() );
738
740 gdalDsInput.get(),
741 gdalDsOutput.get(),
743 {
744 elevationBlock.reset( rotatedElevationBlock.release() );
745 }
746
747 topLeft = QPoint( left, top );
748 }
749 else
750 {
751 topLeft = mRasterViewPort->mTopLeftPoint.toQPointF().toPoint();
752 }
753
755 elevationBlock.get(),
756 topLeft.y() * renderContext()->devicePixelRatio(),
757 topLeft.x() * renderContext()->devicePixelRatio(),
758 mElevationScale,
759 mElevationOffset );
760 }
761 }
762}
The Qgis class provides global constants for use throughout the application.
Definition qgis.h:54
RasterResamplingStage
Stage at which raster resampling occurs.
Definition qgis.h:1380
@ Provider
Resampling occurs in Provider.
@ ProviderHintCanPerformProviderResampling
Provider can perform resampling (to be opposed to post rendering resampling)
@ DpiDependentData
Provider's rendering is dependent on requested pixel size of the viewport.
@ InternalLayerOpacityHandling
The renderer internally handles the raster layer's opacity, so the default layer level opacity handli...
@ UseNoDataForOutOfRangePixels
Out of range pixels (eg those values outside of the rendered map's z range filter) should be set usin...
@ FixedRangePerBand
Layer has a fixed (manually specified) elevation range per band.
@ FixedElevationRange
Layer has a fixed elevation range.
@ RepresentsElevationSurface
Pixel values represent an elevation surface.
@ DynamicRangePerBand
Layer has a elevation range per band, calculated dynamically from an expression.
@ Milliseconds
Milliseconds.
@ RepresentsTemporalValues
Pixel values represent an datetime.
@ RedrawLayerOnly
Redraw the layer when temporal range changes, but don't apply any filtering. Useful when raster symbo...
@ FixedRangePerBand
Layer has a fixed temporal range per band.
@ TemporalRangeFromDataProvider
Mode when raster layer delegates temporal range handling to the dataprovider.
@ FixedTemporalRange
Mode when temporal properties have fixed start and end datetimes.
@ Prefetch
Allow prefetching of out-of-view images.
@ Size
Original data source size (and thus resolution) is known, it is not always available,...
DataType
Raster data types.
Definition qgis.h:351
@ UnknownDataType
Unknown or unspecified type.
@ Raster
Raster layer.
@ RenderPreviewJob
Render is a 'canvas preview' render, and shortcuts should be taken to ensure fast rendering.
@ RenderPartialOutput
Whether to make extra effort to update map image with partially rendered layers (better for interacti...
@ Render3DMap
Render is for a 3D map.
@ UseAdvancedEffects
Enable layer opacity and blending effects.
static QgsRuntimeProfiler * profiler()
Returns the application runtime profiler.
This class represents a coordinate reference system (CRS).
Contains information about the context in which a coordinate transform is executed.
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...
Class for doing transforms between two map 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...
QgsCoordinateReferenceSystem destinationCrs() const
Returns the destination coordinate reference system, which the transform will transform coordinates t...
Custom exception class for Coordinate Reference System related exceptions.
bool isInfinite() const
Returns true if the range consists of all possible values.
Definition qgsrange.h:285
Stores digital elevation model in a raster image which may get updated as a part of map layer renderi...
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 GDALResampleAlg gdalResamplingAlgorithm(QgsRasterDataProvider::ResamplingMethod method)
Returns the GDAL resampling method corresponding to the QGIS resampling method.
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 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:46
double originalDuration() const
Returns the original interval duration.
Qgis::TemporalUnit originalUnit() const
Returns the original interval temporal unit.
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.
double zScale() const
Returns the z scale, which is a scaling factor which should be applied to z values from the layer.
double zOffset() const
Returns the z offset, which is a fixed offset amount which should be added to z values from the layer...
Base class for utility classes that encapsulate information necessary for rendering of map layers.
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.
QgsRenderContext * renderContext()
Returns the render context associated with the renderer.
QStringList errors() const
Returns list of errors (problems) that happened during the rendering.
virtual QgsRectangle extent() const
Returns the extent of the layer.
QgsCoordinateReferenceSystem crs
Definition qgsmaplayer.h:83
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.
int mapHeight() const
Returns current map height in pixels.
void setMapRotation(double degrees, double cx, double cy)
Sets map rotation in degrees (clockwise).
double mapUnitsPerPixel() const
Returns the current map units per pixel.
QgsPointXY toMapCoordinates(int x, int y) const
Transforms device coordinates to map (world) coordinates.
int mapWidth() const
Returns the current map width in pixels.
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)
Adds a message to the log instance (and creates it if necessary).
A class to represent a 2D point.
Definition qgspointxy.h:60
double distance(double x, double y) const
Returns the distance between this point and a specified x, y coordinate.
Definition qgspointxy.h:206
void setY(double y)
Sets the y value of the point.
Definition qgspointxy.h:129
double y
Definition qgspointxy.h:64
double x
Definition qgspointxy.h:63
void setX(double x)
Sets the x value of the point.
Definition qgspointxy.h:119
QPointF toQPointF() const
Converts a point to a QPointF.
Definition qgspointxy.h:165
bool includeUpper() const
Returns true if the upper bound is inclusive, or false if the upper bound is exclusive.
Definition qgsrange.h:101
T lower() const
Returns the lower bound of the range.
Definition qgsrange.h:78
bool includeLower() const
Returns true if the lower bound is inclusive, or false if the lower bound is exclusive.
Definition qgsrange.h:93
T upper() const
Returns the upper bound of the range.
Definition qgsrange.h:85
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.
Raster data container.
Implementation of data provider temporal properties for QgsRasterDataProviders.
Base class for raster data providers.
virtual double sourceNoDataValue(int bandNo) const
Value representing no data value.
ResamplingMethod zoomedOutResamplingMethod() const
Returns resampling method for zoomed-out operations.
void setDpi(int dpi)
Sets the output device resolution.
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.
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,...
ResamplingMethod zoomedInResamplingMethod() const
Returns resampling method for zoomed-in operations.
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.
Raster layer specific subclass of QgsMapLayerElevationProperties.
Qgis::RasterElevationMode mode() const
Returns the elevation mode.
bool hasElevation() const override
Returns true if the layer has an elevation or z component.
int bandNumber() const
Returns the band number from which the elevation should be taken.
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.
QDateTime temporalRepresentationOffset() const
Returns the temporal offset, which is a fixed datetime which should be added to individual pixel valu...
Qgis::TemporalIntervalMatchMethod intervalHandlingMethod() const
Returns the desired method to use when resolving a temporal interval to matching layers or bands in t...
const QgsInterval & temporalRepresentationScale() const
Returns the scale, which is an interval factor which should be applied to individual pixel values fro...
Qgis::RasterTemporalMode mode() const
Returns the temporal properties mode.
int bandNumber() const
Returns the band number from which temporal values should be taken.
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.
int height() const
Returns the height of the (unclipped) raster.
void refreshRendererIfNeeded(QgsRasterRenderer *rasterRenderer, const QgsRectangle &extent)
Refresh renderer with new extent, if needed.
QgsMapLayerTemporalProperties * temporalProperties() override
Returns the layer's temporal properties.
QgsRasterPipe * pipe()
Returns the raster pipe.
bool ignoreExtents() const
If the ignoreExtent flag is set, the layer will also render outside the bounding box reported by the ...
QgsRasterDataProvider * dataProvider() override
Returns the source data provider.
int width() const
Returns the width of the (unclipped) raster.
QgsMapLayerElevationProperties * elevationProperties() override
Returns the layer's elevation properties.
Raster pipe that deals with null values.
Contains a pipeline of raster interfaces for sequential raster processing.
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 values range container.
@ IncludeMin
Include the min value, but not the max value, e.g. min <= value < max.
@ IncludeMinAndMax
Min and max values are inclusive.
@ IncludeMax
Include the max value, but not the min value, e.g. min < value <= max.
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.
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() const
Returns the x minimum value (left side of rectangle).
double yMinimum() const
Returns the y minimum value (bottom side of rectangle).
double width() const
Returns the width of the rectangle.
double xMaximum() const
Returns the x maximum value (right side of rectangle).
double yMaximum() const
Returns the y maximum value (top side of rectangle).
void set(const QgsPointXY &p1, const QgsPointXY &p2, bool normalize=true)
Sets the rectangle from two QgsPoints.
bool isEmpty() const
Returns true if the rectangle has no area.
double height() const
Returns the height of the rectangle.
void setNull()
Mark a rectangle as being null (holding no spatial information).
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.
QgsExpressionContext & expressionContext()
Gets the expression context.
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.
void setDpiTarget(double dpi)
Sets the targeted dpi for rendering.
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...
QgsDoubleRange zRange() const
Returns the range of z-values which should be rendered.
QSize deviceOutputSize() const
Returns the device output size of the render.
QgsCoordinateTransform coordinateTransform() const
Returns the current coordinate transform for the context.
Qgis::RenderContextFlags flags() const
Returns combination of flags used for rendering.
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.
bool isActive() const
Returns true if the temporal property is active.
const QgsDateTimeRange & temporalRange() const
Returns the datetime range for the object.
T begin() const
Returns the beginning of the range.
Definition qgsrange.h:444
T end() const
Returns the upper bound of the range.
Definition qgsrange.h:451
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:6405
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
Definition qgis.h:5857
#define QgsDebugMsgLevel(str, level)
Definition qgslogger.h:39
#define QgsDebugError(str)
Definition qgslogger.h:38
QgsTemporalRange< QDateTime > QgsDateTimeRange
QgsRange which stores a range of date times.
Definition qgsrange.h:742
QList< QgsRasterRange > QgsRasterRangeList
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.
qgssize mHeight
Height, number of rows to be rendered.
QgsCoordinateReferenceSystem mDestCRS
Target coordinate system.
QgsPointXY mBottomRightPoint
Coordinate (in output device coordinate system) of bottom right corner of the part of the raster that...
QgsPointXY mTopLeftPoint
Coordinate (in output device coordinate system) of top left corner of the part of the raster that is ...
QgsCoordinateReferenceSystem mSrcCRS
Source coordinate system.
QgsRectangle mDrawnExtent
Intersection of current map extent and layer extent.
QgsCoordinateTransformContext mTransformContext
Coordinate transform context.
qgssize mWidth
Width, number of columns to be rendered.