1 /***************************************************************************
2 qgspointcloudrgbrendererwidget.cpp
3 ---------------------
4 begin : November 2020
5 copyright : (C) 2020 by Nyall Dawson
6 email : nyall dot dawson 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
18 #include "qgspointcloudrgbrendererwidget.h"
19 #include "qgscontrastenhancement.h"
20 #include "qgspointcloudlayer.h"
21 #include "qgspointcloudrgbrenderer.h"
22 #include "qgsdoublevalidator.h"
23
24 ///@cond PRIVATE
25
QgsPointCloudRgbRendererWidget(QgsPointCloudLayer * layer,QgsStyle * style)26 QgsPointCloudRgbRendererWidget::QgsPointCloudRgbRendererWidget( QgsPointCloudLayer *layer, QgsStyle *style )
27 : QgsPointCloudRendererWidget( layer, style )
28 {
29 setupUi( this );
30 connect( mRedMinLineEdit, &QLineEdit::textChanged, this, &QgsPointCloudRgbRendererWidget::mRedMinLineEdit_textChanged );
31 connect( mRedMaxLineEdit, &QLineEdit::textChanged, this, &QgsPointCloudRgbRendererWidget::mRedMaxLineEdit_textChanged );
32 connect( mGreenMinLineEdit, &QLineEdit::textChanged, this, &QgsPointCloudRgbRendererWidget::mGreenMinLineEdit_textChanged );
33 connect( mGreenMaxLineEdit, &QLineEdit::textChanged, this, &QgsPointCloudRgbRendererWidget::mGreenMaxLineEdit_textChanged );
34 connect( mBlueMinLineEdit, &QLineEdit::textChanged, this, &QgsPointCloudRgbRendererWidget::mBlueMinLineEdit_textChanged );
35 connect( mBlueMaxLineEdit, &QLineEdit::textChanged, this, &QgsPointCloudRgbRendererWidget::mBlueMaxLineEdit_textChanged );
36 createValidators();
37
38 mRedAttributeComboBox->setAllowEmptyAttributeName( true );
39 mGreenAttributeComboBox->setAllowEmptyAttributeName( true );
40 mBlueAttributeComboBox->setAllowEmptyAttributeName( true );
41
42 //contrast enhancement algorithms
43 mContrastEnhancementAlgorithmComboBox->addItem( tr( "No Enhancement" ), QgsContrastEnhancement::NoEnhancement );
44 mContrastEnhancementAlgorithmComboBox->addItem( tr( "Stretch to MinMax" ), QgsContrastEnhancement::StretchToMinimumMaximum );
45 mContrastEnhancementAlgorithmComboBox->addItem( tr( "Stretch and Clip to MinMax" ), QgsContrastEnhancement::StretchAndClipToMinimumMaximum );
46 mContrastEnhancementAlgorithmComboBox->addItem( tr( "Clip to MinMax" ), QgsContrastEnhancement::ClipToMinimumMaximum );
47
48 if ( layer )
49 {
50 mRedAttributeComboBox->setLayer( layer );
51 mGreenAttributeComboBox->setLayer( layer );
52 mBlueAttributeComboBox->setLayer( layer );
53
54 setFromRenderer( layer->renderer() );
55 }
56
57 connect( mRedAttributeComboBox, &QgsPointCloudAttributeComboBox::attributeChanged,
58 this, &QgsPointCloudRgbRendererWidget::redAttributeChanged );
59 connect( mGreenAttributeComboBox, &QgsPointCloudAttributeComboBox::attributeChanged,
60 this, &QgsPointCloudRgbRendererWidget::greenAttributeChanged );
61 connect( mBlueAttributeComboBox, &QgsPointCloudAttributeComboBox::attributeChanged,
62 this, &QgsPointCloudRgbRendererWidget::blueAttributeChanged );
63 connect( mContrastEnhancementAlgorithmComboBox, static_cast<void ( QComboBox::* )( int )>( &QComboBox::currentIndexChanged ), this, &QgsPointCloudRgbRendererWidget::emitWidgetChanged );
64
65 if ( layer )
66 {
67 // set nice initial values
68 redAttributeChanged();
69 greenAttributeChanged();
70 blueAttributeChanged();
71 }
72 }
73
create(QgsPointCloudLayer * layer,QgsStyle * style,QgsPointCloudRenderer *)74 QgsPointCloudRendererWidget *QgsPointCloudRgbRendererWidget::create( QgsPointCloudLayer *layer, QgsStyle *style, QgsPointCloudRenderer * )
75 {
76 return new QgsPointCloudRgbRendererWidget( layer, style );
77 }
78
renderer()79 QgsPointCloudRenderer *QgsPointCloudRgbRendererWidget::renderer()
80 {
81 if ( !mLayer )
82 {
83 return nullptr;
84 }
85
86 std::unique_ptr< QgsPointCloudRgbRenderer > renderer = std::make_unique< QgsPointCloudRgbRenderer >();
87 renderer->setRedAttribute( mRedAttributeComboBox->currentAttribute() );
88 renderer->setGreenAttribute( mGreenAttributeComboBox->currentAttribute() );
89 renderer->setBlueAttribute( mBlueAttributeComboBox->currentAttribute() );
90
91 setCustomMinMaxValues( renderer.get() );
92 return renderer.release();
93 }
94
createValidators()95 void QgsPointCloudRgbRendererWidget::createValidators()
96 {
97 mRedMinLineEdit->setValidator( new QgsDoubleValidator( mRedMinLineEdit ) );
98 mRedMaxLineEdit->setValidator( new QgsDoubleValidator( mRedMinLineEdit ) );
99 mGreenMinLineEdit->setValidator( new QgsDoubleValidator( mGreenMinLineEdit ) );
100 mGreenMaxLineEdit->setValidator( new QgsDoubleValidator( mGreenMinLineEdit ) );
101 mBlueMinLineEdit->setValidator( new QgsDoubleValidator( mBlueMinLineEdit ) );
102 mBlueMaxLineEdit->setValidator( new QgsDoubleValidator( mBlueMinLineEdit ) );
103 }
104
setCustomMinMaxValues(QgsPointCloudRgbRenderer * r)105 void QgsPointCloudRgbRendererWidget::setCustomMinMaxValues( QgsPointCloudRgbRenderer *r )
106 {
107 if ( !r )
108 {
109 return;
110 }
111
112 if ( mContrastEnhancementAlgorithmComboBox->currentData().toInt() ==
113 QgsContrastEnhancement::NoEnhancement )
114 {
115 r->setRedContrastEnhancement( nullptr );
116 r->setGreenContrastEnhancement( nullptr );
117 r->setBlueContrastEnhancement( nullptr );
118 return;
119 }
120
121 QgsContrastEnhancement *redEnhancement = nullptr;
122 QgsContrastEnhancement *greenEnhancement = nullptr;
123 QgsContrastEnhancement *blueEnhancement = nullptr;
124
125 bool redMinOk, redMaxOk;
126 const double redMin = QgsDoubleValidator::toDouble( mRedMinLineEdit->text(), &redMinOk );
127 const double redMax = QgsDoubleValidator::toDouble( mRedMaxLineEdit->text(), &redMaxOk );
128 if ( redMinOk && redMaxOk && !mRedAttributeComboBox->currentAttribute().isEmpty() )
129 {
130 redEnhancement = new QgsContrastEnhancement( Qgis::DataType::UnknownDataType );
131 redEnhancement->setMinimumValue( redMin );
132 redEnhancement->setMaximumValue( redMax );
133 }
134
135 bool greenMinOk, greenMaxOk;
136 const double greenMin = QgsDoubleValidator::toDouble( mGreenMinLineEdit->text(), &greenMinOk );
137 const double greenMax = QgsDoubleValidator::toDouble( mGreenMaxLineEdit->text(), &greenMaxOk );
138 if ( greenMinOk && greenMaxOk && !mGreenAttributeComboBox->currentAttribute().isEmpty() )
139 {
140 greenEnhancement = new QgsContrastEnhancement( Qgis::DataType::UnknownDataType );
141 greenEnhancement->setMinimumValue( greenMin );
142 greenEnhancement->setMaximumValue( greenMax );
143 }
144
145 bool blueMinOk, blueMaxOk;
146 const double blueMin = QgsDoubleValidator::toDouble( mBlueMinLineEdit->text(), &blueMinOk );
147 const double blueMax = QgsDoubleValidator::toDouble( mBlueMaxLineEdit->text(), &blueMaxOk );
148 if ( blueMinOk && blueMaxOk && !mBlueAttributeComboBox->currentAttribute().isEmpty() )
149 {
150 blueEnhancement = new QgsContrastEnhancement( Qgis::DataType::UnknownDataType );
151 blueEnhancement->setMinimumValue( blueMin );
152 blueEnhancement->setMaximumValue( blueMax );
153 }
154
155 if ( redEnhancement )
156 {
157 redEnhancement->setContrastEnhancementAlgorithm( static_cast< QgsContrastEnhancement::ContrastEnhancementAlgorithm >(
158 ( mContrastEnhancementAlgorithmComboBox->currentData().toInt() ) ) );
159 }
160 if ( greenEnhancement )
161 {
162 greenEnhancement->setContrastEnhancementAlgorithm( static_cast< QgsContrastEnhancement::ContrastEnhancementAlgorithm >(
163 ( mContrastEnhancementAlgorithmComboBox->currentData().toInt() ) ) );
164 }
165 if ( blueEnhancement )
166 {
167 blueEnhancement->setContrastEnhancementAlgorithm( static_cast< QgsContrastEnhancement::ContrastEnhancementAlgorithm >(
168 ( mContrastEnhancementAlgorithmComboBox->currentData().toInt() ) ) );
169 }
170 r->setRedContrastEnhancement( redEnhancement );
171 r->setGreenContrastEnhancement( greenEnhancement );
172 r->setBlueContrastEnhancement( blueEnhancement );
173 }
174
mRedMinLineEdit_textChanged(const QString &)175 void QgsPointCloudRgbRendererWidget::mRedMinLineEdit_textChanged( const QString & )
176 {
177 minMaxModified();
178 }
179
mRedMaxLineEdit_textChanged(const QString &)180 void QgsPointCloudRgbRendererWidget::mRedMaxLineEdit_textChanged( const QString & )
181 {
182 minMaxModified();
183 }
184
mGreenMinLineEdit_textChanged(const QString &)185 void QgsPointCloudRgbRendererWidget::mGreenMinLineEdit_textChanged( const QString & )
186 {
187 minMaxModified();
188 }
189
mGreenMaxLineEdit_textChanged(const QString &)190 void QgsPointCloudRgbRendererWidget::mGreenMaxLineEdit_textChanged( const QString & )
191 {
192 minMaxModified();
193 }
194
mBlueMinLineEdit_textChanged(const QString &)195 void QgsPointCloudRgbRendererWidget::mBlueMinLineEdit_textChanged( const QString & )
196 {
197 minMaxModified();
198 }
199
mBlueMaxLineEdit_textChanged(const QString &)200 void QgsPointCloudRgbRendererWidget::mBlueMaxLineEdit_textChanged( const QString & )
201 {
202 minMaxModified();
203 }
204
emitWidgetChanged()205 void QgsPointCloudRgbRendererWidget::emitWidgetChanged()
206 {
207 if ( !mBlockChangedSignal )
208 emit widgetChanged();
209 }
210
redAttributeChanged()211 void QgsPointCloudRgbRendererWidget::redAttributeChanged()
212 {
213 if ( mLayer && mLayer->dataProvider() )
214 {
215 const QVariant max = mLayer->dataProvider()->metadataStatistic( mRedAttributeComboBox->currentAttribute(), QgsStatisticalSummary::Max );
216 if ( max.isValid() )
217 {
218 const int maxValue = max.toInt();
219 mDisableMinMaxWidgetRefresh++;
220 mRedMinLineEdit->setText( QLocale().toString( 0 ) );
221
222 // try and guess suitable range from input max values -- we don't just take the provider max value directly here, but rather see if it's
223 // likely to be 8 bit or 16 bit color values
224 mRedMaxLineEdit->setText( QLocale().toString( maxValue > 255 ? 65535 : 255 ) );
225 mDisableMinMaxWidgetRefresh--;
226 emitWidgetChanged();
227 }
228 }
229 }
230
greenAttributeChanged()231 void QgsPointCloudRgbRendererWidget::greenAttributeChanged()
232 {
233 if ( mLayer && mLayer->dataProvider() )
234 {
235 const QVariant max = mLayer->dataProvider()->metadataStatistic( mGreenAttributeComboBox->currentAttribute(), QgsStatisticalSummary::Max );
236 if ( max.isValid() )
237 {
238 const int maxValue = max.toInt();
239 mDisableMinMaxWidgetRefresh++;
240 mGreenMinLineEdit->setText( QLocale().toString( 0 ) );
241
242 // try and guess suitable range from input max values -- we don't just take the provider max value directly here, but rather see if it's
243 // likely to be 8 bit or 16 bit color values
244 mGreenMaxLineEdit->setText( QLocale().toString( maxValue > 255 ? 65535 : 255 ) );
245 mDisableMinMaxWidgetRefresh--;
246 emitWidgetChanged();
247 }
248 }
249 }
250
blueAttributeChanged()251 void QgsPointCloudRgbRendererWidget::blueAttributeChanged()
252 {
253 if ( mLayer && mLayer->dataProvider() )
254 {
255 const QVariant max = mLayer->dataProvider()->metadataStatistic( mBlueAttributeComboBox->currentAttribute(), QgsStatisticalSummary::Max );
256 if ( max.isValid() )
257 {
258 const int maxValue = max.toInt();
259 mDisableMinMaxWidgetRefresh++;
260 mBlueMinLineEdit->setText( QLocale().toString( 0 ) );
261
262 // try and guess suitable range from input max values -- we don't just take the provider max value directly here, but rather see if it's
263 // likely to be 8 bit or 16 bit color values
264 mBlueMaxLineEdit->setText( QLocale().toString( maxValue > 255 ? 65535 : 255 ) );
265 mDisableMinMaxWidgetRefresh--;
266 emitWidgetChanged();
267 }
268 }
269 }
270
minMaxModified()271 void QgsPointCloudRgbRendererWidget::minMaxModified()
272 {
273 if ( !mDisableMinMaxWidgetRefresh )
274 {
275 if ( ( QgsContrastEnhancement::ContrastEnhancementAlgorithm )( mContrastEnhancementAlgorithmComboBox->currentData().toInt() ) == QgsContrastEnhancement::NoEnhancement )
276 {
277 mContrastEnhancementAlgorithmComboBox->setCurrentIndex(
278 mContrastEnhancementAlgorithmComboBox->findData( ( int ) QgsContrastEnhancement::StretchToMinimumMaximum ) );
279 }
280 emitWidgetChanged();
281 }
282 }
283
setMinMaxValue(const QgsContrastEnhancement * ce,QLineEdit * minEdit,QLineEdit * maxEdit)284 void QgsPointCloudRgbRendererWidget::setMinMaxValue( const QgsContrastEnhancement *ce, QLineEdit *minEdit, QLineEdit *maxEdit )
285 {
286 if ( !minEdit || !maxEdit )
287 {
288 return;
289 }
290
291 if ( !ce )
292 {
293 minEdit->clear();
294 maxEdit->clear();
295 return;
296 }
297
298 minEdit->setText( QLocale().toString( ce->minimumValue() ) );
299 maxEdit->setText( QLocale().toString( ce->maximumValue() ) );
300
301 // QgsMultiBandColorRenderer is using individual contrast enhancements for each
302 // band, but this widget GUI has one for all
303 mContrastEnhancementAlgorithmComboBox->setCurrentIndex( mContrastEnhancementAlgorithmComboBox->findData(
304 static_cast< int >( ce->contrastEnhancementAlgorithm() ) ) );
305 }
306
setFromRenderer(const QgsPointCloudRenderer * r)307 void QgsPointCloudRgbRendererWidget::setFromRenderer( const QgsPointCloudRenderer *r )
308 {
309 mBlockChangedSignal = true;
310 const QgsPointCloudRgbRenderer *mbcr = dynamic_cast<const QgsPointCloudRgbRenderer *>( r );
311 if ( mbcr )
312 {
313 mRedAttributeComboBox->setAttribute( mbcr->redAttribute() );
314 mGreenAttributeComboBox->setAttribute( mbcr->greenAttribute() );
315 mBlueAttributeComboBox->setAttribute( mbcr->blueAttribute() );
316
317 mDisableMinMaxWidgetRefresh++;
318 setMinMaxValue( mbcr->redContrastEnhancement(), mRedMinLineEdit, mRedMaxLineEdit );
319 setMinMaxValue( mbcr->greenContrastEnhancement(), mGreenMinLineEdit, mGreenMaxLineEdit );
320 setMinMaxValue( mbcr->blueContrastEnhancement(), mBlueMinLineEdit, mBlueMaxLineEdit );
321 mDisableMinMaxWidgetRefresh--;
322 }
323 else
324 {
325 if ( mRedAttributeComboBox->findText( QStringLiteral( "Red" ) ) > -1 && mRedAttributeComboBox->findText( QStringLiteral( "Green" ) ) > -1 &&
326 mRedAttributeComboBox->findText( QStringLiteral( "Blue" ) ) > -1 )
327 {
328 mRedAttributeComboBox->setAttribute( QStringLiteral( "Red" ) );
329 mGreenAttributeComboBox->setAttribute( QStringLiteral( "Green" ) );
330 mBlueAttributeComboBox->setAttribute( QStringLiteral( "Blue" ) );
331 }
332 else
333 {
334 mRedAttributeComboBox->setCurrentIndex( mRedAttributeComboBox->count() > 1 ? 1 : 0 );
335 mGreenAttributeComboBox->setCurrentIndex( mGreenAttributeComboBox->count() > 2 ? 2 : 0 );
336 mBlueAttributeComboBox->setCurrentIndex( mBlueAttributeComboBox->count() > 3 ? 3 : 0 );
337 }
338 }
339 mBlockChangedSignal = false;
340 }
341
342 ///@endcond
343