QGIS API Documentation 4.3.0-Master (52aa6503bed)
Loading...
Searching...
No Matches
qgsrastervectorfieldrendererwidget.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgsrastervectorfieldrendererwidget.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 "qgsrasterbandstats.h"
25#include "qgsrasterlayer.h"
27
28#include "moc_qgsrastervectorfieldrendererwidget.cpp"
29
31 : QgsRasterRendererWidget( layer, extent )
32{
33 setupUi( this );
34
35 mXBandComboBox->setLayer( mRasterLayer );
36 mYBandComboBox->setLayer( mRasterLayer );
37 mDirectionBandComboBox->setLayer( mRasterLayer );
38
39 mSourceModeComboBox->addItem( tr( "Component Bands" ), QVariant::fromValue( Qgis::RasterVectorFieldSourceMode::CartesianComponents ) );
40 mSourceModeComboBox->addItem( tr( "Encoded Direction" ), QVariant::fromValue( Qgis::RasterVectorFieldSourceMode::EncodedDirection ) );
41
42 mDirectionEncodingComboBox->addItem( tr( "Esri (1 = E, 2 = SE, 4 = S, 8 = SW, 16 = W, 32 = NW, 64 = N, 128 = NE)" ), QVariant::fromValue( Qgis::RasterDirectionEncoding::Esri ) );
43 mDirectionEncodingComboBox->addItem( tr( "GRASS (1 = NE, 2 = N, 3 = NW, 4 = W, 5 = SW, 6 = S, 7 = SE, 8 = E)" ), QVariant::fromValue( Qgis::RasterDirectionEncoding::Grass ) );
44 mDirectionEncodingComboBox->addItem( tr( "SAGA (0 = N, 1 = NE, 2 = E, 3 = SE, 4 = S, 5 = SW, 6 = W, 7 = NW)" ), QVariant::fromValue( Qgis::RasterDirectionEncoding::Saga ) );
45 mDirectionEncodingComboBox->addItem( tr( "PCRaster LDD (1 = SW, 2 = S, 3 = SE, 4 = W, 6 = E, 7 = NW, 8 = N, 9 = NE)" ), QVariant::fromValue( Qgis::RasterDirectionEncoding::PcRaster ) );
46
47 const int bandCount = mRasterLayer && mRasterLayer->dataProvider() ? mRasterLayer->dataProvider()->bandCount() : 0;
48
49 // a renderer which was never set up starts on the defaults of a freshly created one
50 const QgsRasterVectorFieldRenderer defaultRenderer( nullptr );
51 QgsVectorFieldSettings settings = defaultRenderer.settings();
52 Qgis::RasterVectorFieldSourceMode sourceMode = defaultRenderer.sourceMode();
53 Qgis::RasterDirectionEncoding encoding = defaultRenderer.directionEncoding();
54 int xBand = 1;
55 int yBand = std::min( 2, std::max( 1, bandCount ) );
56 int directionBand = 1;
57
58 if ( const QgsRasterVectorFieldRenderer *renderer = dynamic_cast<const QgsRasterVectorFieldRenderer *>( mRasterLayer ? mRasterLayer->renderer() : nullptr ) )
59 {
60 sourceMode = renderer->sourceMode();
61 xBand = renderer->xBand();
62 yBand = renderer->yBand();
63 directionBand = renderer->directionBand();
64 encoding = renderer->directionEncoding();
65 settings = renderer->settings();
66 }
67
68 whileBlocking( mXBandComboBox )->setBand( xBand );
69 whileBlocking( mYBandComboBox )->setBand( yBand );
70 whileBlocking( mDirectionBandComboBox )->setBand( directionBand );
71 whileBlocking( mSourceModeComboBox )->setCurrentIndex( mSourceModeComboBox->findData( QVariant::fromValue( sourceMode ) ) );
72 whileBlocking( mDirectionEncodingComboBox )->setCurrentIndex( mDirectionEncodingComboBox->findData( QVariant::fromValue( encoding ) ) );
73
74 // the magnitude support and range must both be known before the settings are pushed in, so that
75 // the widget hides what the data cannot carry and classifies the color ramp against the data
76 updateSourceMode();
77 mVectorFieldSettingsWidget->setSettings( settings );
78
79 connect( mXBandComboBox, &QgsRasterBandComboBox::bandChanged, this, &QgsRasterVectorFieldRendererWidget::onBandChanged );
80 connect( mYBandComboBox, &QgsRasterBandComboBox::bandChanged, this, &QgsRasterVectorFieldRendererWidget::onBandChanged );
81 connect( mDirectionBandComboBox, &QgsRasterBandComboBox::bandChanged, this, &QgsRasterVectorFieldRendererWidget::onBandChanged );
82 connect( mDirectionEncodingComboBox, qOverload<int>( &QComboBox::currentIndexChanged ), this, &QgsRasterVectorFieldRendererWidget::widgetChanged );
83 connect( mSourceModeComboBox, qOverload<int>( &QComboBox::currentIndexChanged ), this, &QgsRasterVectorFieldRendererWidget::onSourceModeChanged );
85}
86
87Qgis::RasterVectorFieldSourceMode QgsRasterVectorFieldRendererWidget::currentSourceMode() const
88{
89 return mSourceModeComboBox->currentData().value<Qgis::RasterVectorFieldSourceMode>();
90}
91
92void QgsRasterVectorFieldRendererWidget::onSourceModeChanged()
93{
94 // the symbology widget keeps its settings across the switch, but the ones which depend on a
95 // magnitude have to be pushed back through it so they are hidden or forced
96 const QgsVectorFieldSettings settings = mVectorFieldSettingsWidget->settings();
97 updateSourceMode();
98 mVectorFieldSettingsWidget->setSettings( settings );
99
100 emit widgetChanged();
101}
102
103void QgsRasterVectorFieldRendererWidget::updateSourceMode()
104{
105 const bool encoded = currentSourceMode() == Qgis::RasterVectorFieldSourceMode::EncodedDirection;
106 mBandsStackedWidget->setCurrentWidget( encoded ? mDirectionBandPage : mComponentBandsPage );
107 mVectorFieldSettingsWidget->setHasMagnitude( !encoded );
108
109 updateMagnitudeRange();
110}
111
112void QgsRasterVectorFieldRendererWidget::onBandChanged()
113{
114 updateMagnitudeRange();
115 emit widgetChanged();
116}
117
118void QgsRasterVectorFieldRendererWidget::updateMagnitudeRange()
119{
120 mMinimumMagnitude = std::numeric_limits<double>::quiet_NaN();
121 mMaximumMagnitude = std::numeric_limits<double>::quiet_NaN();
122
123 if ( currentSourceMode() == Qgis::RasterVectorFieldSourceMode::EncodedDirection )
124 {
125 // the encodings carry a direction only, every vector has a magnitude of one. Reading the
126 // statistics of the band would only measure the codes themselves
127 mMinimumMagnitude = 0;
128 mMaximumMagnitude = 1;
129 mVectorFieldSettingsWidget->setMagnitudeRange( mMinimumMagnitude, mMaximumMagnitude );
130 return;
131 }
132
133 QgsRasterDataProvider *provider = mRasterLayer ? mRasterLayer->dataProvider() : nullptr;
134 const int xBand = mXBandComboBox->currentBand();
135 const int yBand = mYBandComboBox->currentBand();
136 if ( !provider || xBand <= 0 || yBand <= 0 )
137 return;
138
140 const QgsRasterBandStats xStats = provider->bandStatistics( xBand, wanted, mExtent );
141 const QgsRasterBandStats yStats = provider->bandStatistics( yBand, wanted, mExtent );
142
143 // the components are unrelated, so the largest magnitude they can combine into is the one where
144 // both are at their extreme, and the smallest one is a vector of zero length
145 const double largestX = std::max( std::fabs( xStats.minimumValue ), std::fabs( xStats.maximumValue ) );
146 const double largestY = std::max( std::fabs( yStats.minimumValue ), std::fabs( yStats.maximumValue ) );
147 if ( std::isnan( largestX ) || std::isnan( largestY ) )
148 return;
149
150 mMinimumMagnitude = 0;
151 mMaximumMagnitude = std::hypot( largestX, largestY );
152
153 mVectorFieldSettingsWidget->setMagnitudeRange( mMinimumMagnitude, mMaximumMagnitude );
154}
155
157{
158 QgsRasterDataProvider *provider = mRasterLayer ? mRasterLayer->dataProvider() : nullptr;
159 if ( !provider )
160 return nullptr;
161
162 auto renderer = std::make_unique<QgsRasterVectorFieldRenderer>( provider );
163 renderer->setSourceMode( currentSourceMode() );
164 renderer->setXBand( mXBandComboBox->currentBand() );
165 renderer->setYBand( mYBandComboBox->currentBand() );
166 renderer->setDirectionBand( mDirectionBandComboBox->currentBand() );
167 renderer->setDirectionEncoding( mDirectionEncodingComboBox->currentData().value<Qgis::RasterDirectionEncoding>() );
168 renderer->setSettings( mVectorFieldSettingsWidget->settings() );
169 renderer->setMinimumMagnitude( mMinimumMagnitude );
170 renderer->setMaximumMagnitude( mMaximumMagnitude );
171 return renderer.release();
172}
RasterVectorFieldSourceMode
Defines how a raster vector field renderer reads the vectors from the raster bands.
Definition qgis.h:7262
@ 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
QFlags< RasterBandStatistic > RasterBandStatistics
Statistics to be calculated for raster bands.
Definition qgis.h:6779
RasterDirectionEncoding
Schemes used to encode a compass direction as an integer raster value.
Definition qgis.h:7276
@ PcRaster
PCRaster: 1=SW, 2=S, 3=SE, 4=W, 6=E, 7=NW, 8=N, 9=NE.
Definition qgis.h:7280
@ Esri
Esri: 1=E, 2=SE, 4=S, 8=SW, 16=W, 32=NW, 64=N, 128=NE.
Definition qgis.h:7277
@ Saga
SAGA: 0=N, 1=NE, 2=E, 3=SE, 4=S, 5=SW, 6=W, 7=NW.
Definition qgis.h:7279
@ Grass
GRASS: 1=NE, 2=N, 3=NW, 4=W, 5=SW, 6=S, 7=SE, 8=E.
Definition qgis.h:7278
void bandChanged(int band)
Emitted when the currently selected band changes.
double minimumValue
The minimum cell value in the raster band.
double maximumValue
The maximum cell value in the raster band.
Base class for raster data providers.
Q_DECL_DEPRECATED QgsRasterBandStats bandStatistics(int bandNo, int stats, const QgsRectangle &extent=QgsRectangle(), int sampleSize=0, QgsRasterBlockFeedback *feedback=nullptr)
Returns the band statistics.
Represents a raster layer.
QgsRectangle mExtent
Current extent.
QgsRasterRendererWidget(QgsRasterLayer *layer, const QgsRectangle &extent)
Constructor for QgsRasterRendererWidget.
void widgetChanged()
Emitted when something on the widget has changed.
Raster renderer pipe that applies colors to a raster.
QgsRasterRenderer * renderer() override
Creates a new renderer, using the properties defined in the widget.
QgsRasterVectorFieldRendererWidget(QgsRasterLayer *layer, const QgsRectangle &extent=QgsRectangle())
Constructor for QgsRasterVectorFieldRendererWidget.
Raster renderer which draws a vector field stored in raster bands.
QgsVectorFieldSettings settings() const
Returns the settings used to render the vector field.
Qgis::RasterDirectionEncoding directionEncoding() const
Returns the scheme the directionBand() is coded with.
Qgis::RasterVectorFieldSourceMode sourceMode() const
Returns the way the vectors are stored in the raster bands.
A rectangle specified with double values.
void widgetChanged()
Vector field symbology settings changed.
Represents a renderer settings for vector datasets.
QgsSignalBlocker< Object > whileBlocking(Object *object)
Temporarily blocks signals from a QObject while calling a single method from the object.
Definition qgis.h:7665