QGIS API Documentation 4.3.0-Master (4ecdf0f3f59)
Loading...
Searching...
No Matches
qgsrastervectorfieldrenderer.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgsrastervectorfieldrenderer.cpp
3 --------------------------------
4 begin : September 2026
5 copyright : (C) 2026 by Stefanos Natsis
6 email : uclaros at gmail dot com
7 ***************************************************************************/
8
9/***************************************************************************
10 * *
11 * This program is free software; you can redistribute it and/or modify *
12 * it under the terms of the GNU General Public License as published by *
13 * the Free Software Foundation; either version 2 of the License, or *
14 * (at your option) any later version. *
15 * *
16 ***************************************************************************/
17
19
20#include <algorithm>
21#include <cmath>
22
23#include "qgscolorrampshader.h"
25#include "qgsdistancearea.h"
26#include "qgslogger.h"
27#include "qgsmaptopixel.h"
28#include "qgsrasterblock.h"
31#include "qgsreadwritecontext.h"
32#include "qgsrendercontext.h"
34
35#include <QImage>
36#include <QPainter>
37#include <QSizeF>
38#include <QString>
39
40using namespace Qt::StringLiterals;
41
43constexpr qint64 VECTOR_FIELD_MAXIMUM_SAMPLES = 4'000'000;
44
48
50
52{
54 renderer->copyCommonProperties( this );
55 renderer->mSourceMode = mSourceMode;
56 renderer->mXBand = mXBand;
57 renderer->mYBand = mYBand;
58 renderer->mDirectionBand = mDirectionBand;
59 renderer->mDirectionEncoding = mDirectionEncoding;
60 renderer->mSettings = mSettings;
61 renderer->mMinimumMagnitude = mMinimumMagnitude;
62 renderer->mMaximumMagnitude = mMaximumMagnitude;
63 return renderer;
64}
65
70
71std::unique_ptr<QgsRasterRenderer> QgsRasterVectorFieldRenderer::create( const QDomElement &elem, QgsRasterInterface *input )
72{
73 if ( elem.isNull() )
74 return nullptr;
75
76 auto renderer = std::make_unique<QgsRasterVectorFieldRenderer>( input );
77 renderer->readXml( elem );
78
79 renderer->setSourceMode( qgsEnumKeyToValue( elem.attribute( u"source-mode"_s ), Qgis::RasterVectorFieldSourceMode::CartesianComponents ) );
80 renderer->setXBand( elem.attribute( u"x-band"_s, u"-1"_s ).toInt() );
81 renderer->setYBand( elem.attribute( u"y-band"_s, u"-1"_s ).toInt() );
82 renderer->setDirectionBand( elem.attribute( u"direction-band"_s, u"-1"_s ).toInt() );
83 renderer->setDirectionEncoding( qgsEnumKeyToValue( elem.attribute( u"direction-encoding"_s ), Qgis::RasterDirectionEncoding::Esri ) );
84
85 if ( elem.hasAttribute( u"minimum-magnitude"_s ) )
86 renderer->setMinimumMagnitude( elem.attribute( u"minimum-magnitude"_s ).toDouble() );
87 if ( elem.hasAttribute( u"maximum-magnitude"_s ) )
88 renderer->setMaximumMagnitude( elem.attribute( u"maximum-magnitude"_s ).toDouble() );
89
90 const QDomElement settingsElem = elem.firstChildElement( u"vector-settings"_s );
91 if ( !settingsElem.isNull() )
92 {
94 settings.readXml( settingsElem, QgsReadWriteContext() );
95 renderer->setSettings( settings );
96 }
97
98 return renderer;
99}
100
101void QgsRasterVectorFieldRenderer::writeXml( QDomDocument &doc, QDomElement &parentElem ) const
102{
103 if ( parentElem.isNull() )
104 return;
105
106 QDomElement rasterRendererElem = doc.createElement( u"rasterrenderer"_s );
107 _writeXml( doc, rasterRendererElem );
108
109 rasterRendererElem.setAttribute( u"source-mode"_s, qgsEnumValueToKey( mSourceMode ) );
110 rasterRendererElem.setAttribute( u"x-band"_s, mXBand );
111 rasterRendererElem.setAttribute( u"y-band"_s, mYBand );
112 rasterRendererElem.setAttribute( u"direction-band"_s, mDirectionBand );
113 rasterRendererElem.setAttribute( u"direction-encoding"_s, qgsEnumValueToKey( mDirectionEncoding ) );
114 if ( !std::isnan( mMinimumMagnitude ) )
115 rasterRendererElem.setAttribute( u"minimum-magnitude"_s, qgsDoubleToString( mMinimumMagnitude ) );
116 if ( !std::isnan( mMaximumMagnitude ) )
117 rasterRendererElem.setAttribute( u"maximum-magnitude"_s, qgsDoubleToString( mMaximumMagnitude ) );
118 rasterRendererElem.appendChild( mSettings.writeXml( doc, QgsReadWriteContext() ) );
119
120 parentElem.appendChild( rasterRendererElem );
121}
122
123bool QgsRasterVectorFieldRenderer::shouldAcceptBand( int band ) const
124{
125 // without an input the band cannot be validated yet, which happens while cloning or reading a project
126 return band > 0 && ( !mInput || band <= mInput->bandCount() );
127}
128
130{
131 if ( !shouldAcceptBand( band ) )
132 return false;
133
134 mXBand = band;
135 return true;
136}
137
139{
140 if ( !shouldAcceptBand( band ) )
141 return false;
142
143 mYBand = band;
144 return true;
145}
146
148{
149 if ( !shouldAcceptBand( band ) )
150 return false;
151
152 mDirectionBand = band;
153 return true;
154}
155
157{
158 QList<int> bands;
159 switch ( mSourceMode )
160 {
162 if ( mXBand > 0 )
163 bands << mXBand;
164 if ( mYBand > 0 )
165 bands << mYBand;
166 break;
167
169 if ( mDirectionBand > 0 )
170 bands << mDirectionBand;
171 break;
172 }
173 return bands;
174}
175
176QList<QPair<QString, QColor>> QgsRasterVectorFieldRenderer::legendSymbologyItems() const
177{
178 QList<QPair<QString, QColor>> items;
179
180 switch ( mSettings.coloringMethod() )
181 {
183 items << qMakePair( QString(), mSettings.color() );
184 break;
185
187 {
188 const QList<QgsColorRampShader::ColorRampItem> rampItems = mSettings.colorRampShader().colorRampItemList();
189 items.reserve( rampItems.size() );
190 for ( const QgsColorRampShader::ColorRampItem &rampItem : rampItems )
191 items << qMakePair( rampItem.label, rampItem.color );
192 break;
193 }
194 }
195
196 return items;
197}
198
199
207
212static QgsRasterVectorFieldSampleGrid calculateSampleGrid( QgsRasterInterface *input, const QgsRectangle &extent, int width, int height )
213{
215 grid.extent = extent;
216 grid.columns = width;
217 grid.rows = height;
218
219 const QgsRectangle sourceExtent = input->extent();
220 const int sourceWidth = input->xSize();
221 const int sourceHeight = input->ySize();
222 if ( sourceWidth <= 0 || sourceHeight <= 0 || sourceExtent.isEmpty() )
223 return grid; // the source resolution is unknown, sample at the resolution of the block
224
225 const double xResolution = sourceExtent.width() / sourceWidth;
226 const double yResolution = sourceExtent.height() / sourceHeight;
227
228 // the range of source pixels covering the block
229 const double firstColumn = std::floor( ( extent.xMinimum() - sourceExtent.xMinimum() ) / xResolution );
230 const double lastColumn = std::ceil( ( extent.xMaximum() - sourceExtent.xMinimum() ) / xResolution );
231 const double firstRow = std::floor( ( sourceExtent.yMaximum() - extent.yMaximum() ) / yResolution );
232 const double lastRow = std::ceil( ( sourceExtent.yMaximum() - extent.yMinimum() ) / yResolution );
233
234 const qint64 columns = std::max<qint64>( 1, static_cast<qint64>( lastColumn - firstColumn ) );
235 const qint64 rows = std::max<qint64>( 1, static_cast<qint64>( lastRow - firstRow ) );
236
237 // sampling much finer than the block is drawn is wasted, and a whole fine raster does not fit in memory
238 qint64 step = 1;
239 step = std::max( step, ( columns + 2 * width - 1 ) / ( 2 * width ) );
240 step = std::max( step, ( rows + 2 * height - 1 ) / ( 2 * height ) );
241 while ( ( ( columns + step - 1 ) / step ) * ( ( rows + step - 1 ) / step ) > VECTOR_FIELD_MAXIMUM_SAMPLES )
242 ++step;
243
244 grid.columns = static_cast<int>( ( columns + step - 1 ) / step );
245 grid.rows = static_cast<int>( ( rows + step - 1 ) / step );
246 grid.extent = QgsRectangle(
247 sourceExtent.xMinimum() + firstColumn * xResolution,
248 sourceExtent.yMaximum() - ( firstRow + static_cast<double>( grid.rows ) * step ) * yResolution,
249 sourceExtent.xMinimum() + ( firstColumn + static_cast<double>( grid.columns ) * step ) * xResolution,
250 sourceExtent.yMaximum() - firstRow * yResolution
251 );
252
253 return grid;
254}
255
266static QSizeF calculateBlockPixelsPerMapPixel( const QgsRenderContext &context, const QgsRectangle &extent, int width, int height )
267{
268 if ( !context.mapToPixel().isValid() || width <= 0 || height <= 0 )
269 return QSizeF( 1.0, 1.0 );
270
271 const double mapUnitsPerPixel = context.mapToPixel().mapUnitsPerPixel();
272 if ( mapUnitsPerPixel <= 0 )
273 return QSizeF( 1.0, 1.0 );
274
275 QgsPointXY center = extent.center();
276 QgsPointXY nextColumn( center.x() + extent.width() / width, center.y() );
277 QgsPointXY nextRow( center.x(), center.y() - extent.height() / height );
278 try
279 {
280 QgsCoordinateTransform transform = context.coordinateTransform();
281 if ( transform.isValid() )
282 {
283 transform.setBallparkTransformsAreAppropriate( true );
284 center = transform.transform( center );
285 nextColumn = transform.transform( nextColumn );
286 nextRow = transform.transform( nextRow );
287 }
288 }
289 catch ( QgsCsException & )
290 {
291 QgsDebugError( u"Could not transform the block extent to the map CRS"_s );
292 return QSizeF( 1.0, 1.0 );
293 }
294
295 const auto ratio = [mapUnitsPerPixel]( double blockPixelSizeInMapUnits ) {
296 if ( !std::isfinite( blockPixelSizeInMapUnits ) || blockPixelSizeInMapUnits <= 0 )
297 return 1.0;
298 return std::clamp( mapUnitsPerPixel / blockPixelSizeInMapUnits, 0.05, 20.0 );
299 };
300
301 return QSizeF( ratio( center.distance( nextColumn ) ), ratio( center.distance( nextRow ) ) );
302}
303
308static bool calculateMagnitudeRange( const QgsRasterBlock *xValues, const QgsRasterBlock *yValues, double &minimum, double &maximum )
309{
310 minimum = std::numeric_limits<double>::max();
311 maximum = std::numeric_limits<double>::lowest();
312 bool found = false;
313
314 const int rows = std::min( xValues->height(), yValues->height() );
315 const int columns = std::min( xValues->width(), yValues->width() );
316 for ( int row = 0; row < rows; ++row )
317 {
318 for ( int column = 0; column < columns; ++column )
319 {
320 bool isNoData = false;
321 const double x = xValues->valueAndNoData( row, column, isNoData );
322 if ( isNoData || std::isnan( x ) )
323 continue;
324
325 const double y = yValues->valueAndNoData( row, column, isNoData );
326 if ( isNoData || std::isnan( y ) )
327 continue;
328
329 const double magnitude = std::hypot( x, y );
330 minimum = std::min( minimum, magnitude );
331 maximum = std::max( maximum, magnitude );
332 found = true;
333 }
334 }
335
336 return found;
337}
338
340{
341 Q_UNUSED( bandNo )
342
343 auto outputBlock = std::make_unique<QgsRasterBlock>();
344 if ( !mInput || width <= 0 || height <= 0 || extent.isEmpty() )
345 return outputBlock.release();
346
347 // each source mode requires different bands
348 switch ( mSourceMode )
349 {
351 if ( mXBand <= 0 || mYBand <= 0 )
352 return outputBlock.release();
353 break;
354
356 if ( mDirectionBand <= 0 )
357 return outputBlock.release();
358 break;
359 }
360
361 QgsRasterDataProvider *provider = dynamic_cast<QgsRasterDataProvider *>( mInput->sourceInput() );
362 const QgsCoordinateReferenceSystem layerCrs = provider ? provider->crs() : QgsCoordinateReferenceSystem();
363 const QgsRectangle layerExtent = provider ? provider->extent() : mInput->extent();
364
365 const QgsRasterVectorFieldSampleGrid grid = calculateSampleGrid( mInput, extent, width, height );
366
367 std::shared_ptr<const QgsRasterBlock> xValues;
368 std::shared_ptr<const QgsRasterBlock> yValues;
369 std::shared_ptr<const QgsRasterBlock> directionValues;
370
371 double minimumMagnitude = mMinimumMagnitude;
372 double maximumMagnitude = mMaximumMagnitude;
373
374 switch ( mSourceMode )
375 {
377 {
378 xValues.reset( mInput->block( mXBand, grid.extent, grid.columns, grid.rows, feedback ) );
379 yValues.reset( mInput->block( mYBand, grid.extent, grid.columns, grid.rows, feedback ) );
380 if ( !xValues || !yValues || xValues->isEmpty() || yValues->isEmpty() )
381 {
382 QgsDebugError( u"No raster data!"_s );
383 return outputBlock.release();
384 }
385
386 if ( std::isnan( minimumMagnitude ) || std::isnan( maximumMagnitude ) )
387 {
388 double dataMinimum = 0;
389 double dataMaximum = 0;
390 if ( !calculateMagnitudeRange( xValues.get(), yValues.get(), dataMinimum, dataMaximum ) )
391 return outputBlock.release(); // the whole block holds no data
392
393 if ( std::isnan( minimumMagnitude ) )
394 minimumMagnitude = dataMinimum;
395 if ( std::isnan( maximumMagnitude ) )
396 maximumMagnitude = dataMaximum;
397 }
398 break;
399 }
400
402 {
403 // We don't want resampling, the pixels hold direction coded values
404 const bool resamplingWasEnabled = provider && provider->isProviderResamplingEnabled();
405 if ( resamplingWasEnabled )
406 provider->enableProviderResampling( false );
407
408 directionValues.reset( mInput->block( mDirectionBand, grid.extent, grid.columns, grid.rows, feedback ) );
409
410 if ( resamplingWasEnabled )
411 provider->enableProviderResampling( true );
412
413 if ( !directionValues || directionValues->isEmpty() )
414 {
415 QgsDebugError( u"No raster data!"_s );
416 return outputBlock.release();
417 }
418
419 // the encodings carry a direction only, every vector has a magnitude of one
422 break;
423 }
424 }
425
426 QImage image( width, height, QImage::Format_ARGB32_Premultiplied );
427 if ( image.isNull() )
428 return outputBlock.release();
429 image.fill( Qt::transparent );
430
431 // scoped so that the painter has ended before the block takes the image, and the engine, which
432 // restores the painter state when it goes, is destroyed before the painter
433 {
434 QPainter painter( &image );
435 painter.setRenderHint( QPainter::Antialiasing, true );
436
437 // the copy taken from the feedback has no feedback of its own, and the streamline field only
438 // iterates while it has one to check for cancellation
439 QgsRasterBlockFeedback localFeedback;
440 QgsRasterBlockFeedback *effectiveFeedback = feedback ? feedback : &localFeedback;
441
442 // the feedback carries a copy of the map render context, which is where the scale factor, the
443 // reference scale and the render flags come from. It is missing when the renderer is used
444 // outside of a map render, by the file writer or by the layer preview.
445 const QgsRenderContext mapContext = feedback ? feedback->renderContext() : QgsRenderContext();
446 const bool hasMapContext = mapContext.mapToPixel().isValid();
447
448 const QSizeF blockPixelsPerMapPixel = hasMapContext ? calculateBlockPixelsPerMapPixel( mapContext, extent, width, height ) : QSizeF( 1.0, 1.0 );
449
450 // the context is built from the block painter instead of being copied from the map context, so that
451 // nothing describing the map render can leak into a block which is drawn in the coordinates of the
452 // raster. Only the values taken over here are shared with the map render
454 if ( hasMapContext )
455 {
456 context.setFlags( mapContext.flags() );
458 // the block may be drawn at a different resolution than the map painter, so everything which sizes the
459 // symbology in physical units has to be scaled along with it. The two axes are averaged to provide a single scale
460 context.setScaleFactor( mapContext.scaleFactor() * std::sqrt( blockPixelsPerMapPixel.width() * blockPixelsPerMapPixel.height() ) );
462 context.setRendererScale( mapContext.rendererScale() );
463 context.setTransformContext( mapContext.transformContext() );
464 }
465
466 // the block image is axis aligned, the drawer rotates it once it is complete
467 context.setMapToPixel( QgsMapToPixel( extent.width() / width, extent.center().x(), extent.center().y(), width, height, 0 ) );
468 context.setMapExtent( extent );
469 context.setExtent( extent );
470
471 // the symbology is drawn in the coordinates of the raster itself, and reprojected afterwards
472 // along with the image, so the context must not transform anything.
474
475 // the distance area declares which CRS the block is drawn in: the wind barbs use it to tell which
476 // hemisphere they are in, and meters-at-scale sizes are measured against it
477 if ( layerCrs.isValid() )
478 {
480 da.setSourceCrs( layerCrs, context.transformContext() );
481 da.setEllipsoid( layerCrs.ellipsoidAcronym() );
482 context.setDistanceArea( da );
483 }
484
485 context.setFeedback( effectiveFeedback );
486
487 // the grid cell size is expressed in canvas pixels, which the block pixels only match at a
488 // device pixel ratio of one
490 settings.setUserGridCellWidth( std::max( 1, static_cast<int>( std::round( settings.userGridCellWidth() * blockPixelsPerMapPixel.width() ) ) ) );
491 settings.setUserGridCellHeight( std::max( 1, static_cast<int>( std::round( settings.userGridCellHeight() * blockPixelsPerMapPixel.height() ) ) ) );
492
493 const QgsRectangle dataExtent = extent.intersect( layerExtent );
494
495 std::unique_ptr<QgsVectorFieldValueSource> source;
496 switch ( mSourceMode )
497 {
499 source = std::make_unique<QgsRasterVectorFieldValueSource>( xValues, yValues, grid.extent, dataExtent, maximumMagnitude );
500 break;
501
503 source = std::make_unique<QgsRasterVectorFieldEncodedDirectionValueSource>( directionValues, mDirectionEncoding, grid.extent, dataExtent );
504 break;
505 }
506
507 QgsVectorFieldEngine engine( maximumMagnitude, minimumMagnitude, settings, context, QSize( width, height ) );
508
509 switch ( settings.symbology() )
510 {
513 // the glyphs are laid out from the corner of the layer, a point which does not depend on
514 // how the render is split into blocks, so that the pattern continues across block boundaries
515 engine.drawGlyphs( std::move( source ), QgsPointXY( layerExtent.xMinimum(), layerExtent.yMaximum() ), effectiveFeedback );
516 break;
517
519 engine.drawStreamlines( std::move( source ), effectiveFeedback );
520 break;
521
523 engine.drawTraces( std::move( source ) );
524 break;
525 }
526 }
527
528 outputBlock->setImage( &image );
529 return outputBlock.release();
530}
@ WindBarbs
Displaying vector dataset with wind barbs.
Definition qgis.h:7238
@ Arrows
Displaying vector dataset with arrows.
Definition qgis.h:7235
@ Traces
Displaying vector dataset with particle traces.
Definition qgis.h:7237
@ Streamlines
Displaying vector dataset with streamlines.
Definition qgis.h:7236
QFlags< RasterRendererFlag > RasterRendererFlags
Flags which control behavior of raster renderers.
Definition qgis.h:1682
@ CartesianComponents
Two bands holding the x and y components of the vectors.
Definition qgis.h:7263
@ EncodedDirection
A single band holding integer coded compass directions, see Qgis::RasterDirectionEncoding.
Definition qgis.h:7264
@ UseNoDataForOutOfRangePixels
Out of range pixels (eg those values outside of the rendered map's z range filter) should be set usin...
Definition qgis.h:1673
@ Antialiasing
Use antialiasing while drawing.
Definition qgis.h:2972
@ Esri
Esri: 1=E, 2=SE, 4=S, 8=SW, 16=W, 32=NW, 64=N, 128=NE.
Definition qgis.h:7277
Represents a coordinate reference system (CRS).
bool isValid() const
Returns whether this CRS is correctly initialized and usable.
QString ellipsoidAcronym() const
Returns the ellipsoid acronym for the ellipsoid used by the CRS.
Handles coordinate transforms between two coordinate systems.
void setBallparkTransformsAreAppropriate(bool appropriate)
Sets whether approximate "ballpark" results are appropriate for this coordinate transform.
QgsPointXY transform(const QgsPointXY &point, Qgis::TransformDirection direction=Qgis::TransformDirection::Forward) const
Transform the point 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.
virtual QgsCoordinateReferenceSystem crs() const =0
Returns the coordinate system for the data source.
A general purpose distance and area calculator, capable of performing ellipsoid based calculations.
void setSourceCrs(const QgsCoordinateReferenceSystem &crs, const QgsCoordinateTransformContext &context)
Sets source spatial reference system crs.
bool setEllipsoid(const QString &ellipsoid)
Sets the ellipsoid by its acronym.
@ ColorRamp
Render with a color ramp.
@ SingleColor
Render with a single color.
Perform transforms between map coordinates and device coordinates.
bool isValid() const
Returns true if the object is valid (i.e.
double mapUnitsPerPixel() const
Returns the current map units per pixel.
Represents a 2D point.
Definition qgspointxy.h:62
double distance(double x, double y) const
Returns the distance between this point and a specified x, y coordinate.
Definition qgspointxy.h:209
double y
Definition qgspointxy.h:66
double x
Definition qgspointxy.h:65
Feedback object tailored for raster block reading.
QgsRenderContext renderContext() const
Returns the render context of the associated block reading.
Raster data container.
int height() const
Returns the height (number of rows) of the raster block.
double valueAndNoData(int row, int column, bool &isNoData) const
Reads a single value from the pixel at row and column, if type of block is numeric.
int width() const
Returns the width (number of columns) of the raster block.
Base class for raster data providers.
bool isProviderResamplingEnabled() const
Returns whether provider-level resampling is enabled.
virtual bool enableProviderResampling(bool enable)
Enable or disable provider-level resampling.
QgsRectangle extent() const override=0
Returns the extent of the layer.
Base class for processing filters like renderers, reprojector, resampler etc.
virtual int xSize() const
Gets raster size.
QgsRasterInterface(QgsRasterInterface *input=nullptr)
virtual int bandCount() const =0
Gets number of bands.
QgsRasterInterface * mInput
virtual int ySize() const
virtual QgsRectangle extent() const
Gets the extent of the interface.
virtual QgsRasterInterface * input() const
Current input.
QgsRasterRenderer(QgsRasterInterface *input=nullptr, const QString &type=QString())
Constructor for QgsRasterRenderer.
void _writeXml(QDomDocument &doc, QDomElement &rasterRendererElem) const
Write upper class info into rasterrenderer element (called by writeXml method of subclasses).
void copyCommonProperties(const QgsRasterRenderer *other, bool copyMinMaxOrigin=true)
Copies common properties like opacity / transparency data from other renderer.
bool setXBand(int band)
Attempts to set the band which holds the x component of the vectors.
QgsRasterBlock * block(int bandNo, const QgsRectangle &extent, int width, int height, QgsRasterBlockFeedback *feedback=nullptr) override
Read block of data using given extent and size.
Qgis::RasterRendererFlags flags() const override
Returns flags which dictate renderer behavior.
QgsRasterVectorFieldRenderer(QgsRasterInterface *input)
Creates a vector field renderer.
bool setDirectionBand(int band)
Attempts to set the band which holds the coded compass directions.
bool setYBand(int band)
Attempts to set the band which holds the y component of the vectors.
QList< int > usesBands() const override
Returns a list of band numbers used by the renderer.
QList< QPair< QString, QColor > > legendSymbologyItems() const override
Returns symbology items if provided by renderer.
double maximumMagnitude() const
Returns the magnitude the symbology treats as the largest one of the raster.
QgsRasterVectorFieldRenderer * clone() const override
Clone itself, create deep copy.
~QgsRasterVectorFieldRenderer() override
void writeXml(QDomDocument &doc, QDomElement &parentElem) const override
Write base class members to xml.
static std::unique_ptr< QgsRasterRenderer > create(const QDomElement &elem, QgsRasterInterface *input)
Creates an instance of the renderer based on definition from XML (used by renderer registry).
double minimumMagnitude() const
Returns the magnitude the symbology treats as the smallest one of the raster.
QgsVectorFieldSettings settings() const
Returns the settings used to render the vector field.
A container for the context for various read/write operations on objects.
A rectangle specified with double values.
double xMinimum
double yMinimum
double xMaximum
double yMaximum
QgsPointXY center
Contains information about the context of a rendering operation.
void setMapExtent(const QgsRectangle &extent)
Sets the original extent of the map being rendered.
double scaleFactor() const
Returns the scaling factor for the render to convert painter units to physical sizes.
void setCoordinateTransform(const QgsCoordinateTransform &t)
Sets the current coordinate transform for the context.
void setDistanceArea(const QgsDistanceArea &distanceArea)
A general purpose distance and area calculator, capable of performing ellipsoid based calculations.
void setScaleFactor(double factor)
Sets the scaling factor for the render to convert painter units to physical sizes.
double symbologyReferenceScale() const
Returns the symbology reference scale.
double rendererScale() const
Returns the renderer map scale.
QgsCoordinateTransformContext transformContext() const
Returns the context's coordinate transform context, which stores various information regarding which ...
void setFeedback(QgsFeedback *feedback)
Attach a feedback object that can be queried regularly during rendering to check if rendering should ...
void setFlag(Qgis::RenderContextFlag flag, bool on=true)
Enable or disable a particular flag (other flags are not affected).
void setSymbologyReferenceScale(double scale)
Sets the symbology reference scale.
const QgsMapToPixel & mapToPixel() const
Returns the context's map to pixel transform, which transforms between map coordinates and device coo...
void setTransformContext(const QgsCoordinateTransformContext &context)
Sets the context's coordinate transform context, which stores various information regarding which dat...
void setFlags(Qgis::RenderContextFlags flags)
Set combination of flags that will be used for rendering.
void setExtent(const QgsRectangle &extent)
When rendering a map layer, calling this method sets the "clipping" extent for the layer (in the laye...
void setMapToPixel(const QgsMapToPixel &mtp)
Sets the context's map to pixel transform, which transforms between map coordinates and device coordi...
static QgsRenderContext fromQPainter(QPainter *painter)
Creates a default render context given a pixel based QPainter destination.
void setRendererScale(double scale)
Sets the renderer map scale.
QgsCoordinateTransform coordinateTransform() const
Returns the current coordinate transform for the context.
Qgis::RenderContextFlags flags() const
Returns combination of flags used for rendering.
Responsible for rendering vector field data.
void drawStreamlines(std::unique_ptr< QgsVectorFieldValueSource > source, QgsRasterBlockFeedback *feedback=nullptr)
Integrates and draws streamlines over the whole rendered extent, sampling the vector field from sourc...
void drawGlyphs(std::unique_ptr< QgsVectorFieldValueSource > source, const QgsPointXY &anchor, QgsFeedback *feedback=nullptr)
Draws one glyph per position of the placement grid described by the settings the engine was construct...
void drawTraces(std::unique_ptr< QgsVectorFieldValueSource > source)
Seeds particles over the whole rendered extent, moves them one time step and draws their traces,...
Represents a renderer settings for vector datasets.
T qgsEnumKeyToValue(const QString &key, const T &defaultValue, bool tryValueAsKey=true, bool *returnOk=nullptr)
Returns the value corresponding to the given key of an enum.
Definition qgis.h:8064
QString qgsDoubleToString(double a, int precision=17)
Returns a string representation of a double.
Definition qgis.h:7678
QString qgsEnumValueToKey(const T &value, bool *returnOk=nullptr)
Returns the value for the given key of an enum.
Definition qgis.h:8045
#define QgsDebugError(str)
Definition qgslogger.h:71
constexpr qint64 VECTOR_FIELD_MAXIMUM_SAMPLES
Upper bound on the number of vector values read from the two bands for a single block.
The extent and size at which the two component bands are read for one block.