QGIS API Documentation  3.26.3-Buenos Aires (65e4edfdad)
qgsrastertransparencywidget.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsrastertransparencywidget.cpp
3  ---------------------
4  begin : May 2016
5  copyright : (C) 2016 by Nathan Woodrow
6  email : woodrow dot nathan 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 #include <QWidget>
16 #include <QIntValidator>
17 #include <QFile>
18 #include <QTextStream>
19 #include <QMessageBox>
20 #include <QFileDialog>
21 #include <QRegularExpression>
22 
23 #include "qgssettings.h"
25 #include "qgsrasterlayer.h"
26 #include "qgsraster.h"
27 #include "qgsrasterlayerrenderer.h"
28 #include "qgsrasterdataprovider.h"
29 #include "qgsrastertransparency.h"
30 #include "qgsmaptoolemitpoint.h"
31 #include "qgsmapsettings.h"
32 #include "qgsrectangle.h"
33 #include "qgsmapcanvas.h"
36 #include "qgsdoublevalidator.h"
38 #include "qgstemporalcontroller.h"
39 
41  : QgsMapLayerConfigWidget( layer, canvas, parent )
42  , TRSTRING_NOT_SET( tr( "Not Set" ) )
43  , mRasterLayer( layer )
44  , mMapCanvas( canvas )
45 {
46  setupUi( this );
47  connect( pbnAddValuesFromDisplay, &QToolButton::clicked, this, &QgsRasterTransparencyWidget::pbnAddValuesFromDisplay_clicked );
48  connect( pbnAddValuesManually, &QToolButton::clicked, this, &QgsRasterTransparencyWidget::pbnAddValuesManually_clicked );
49  connect( pbnDefaultValues, &QToolButton::clicked, this, &QgsRasterTransparencyWidget::pbnDefaultValues_clicked );
50  connect( pbnExportTransparentPixelValues, &QToolButton::clicked, this, &QgsRasterTransparencyWidget::pbnExportTransparentPixelValues_clicked );
51  connect( pbnImportTransparentPixelValues, &QToolButton::clicked, this, &QgsRasterTransparencyWidget::pbnImportTransparentPixelValues_clicked );
52  connect( pbnRemoveSelectedRow, &QToolButton::clicked, this, &QgsRasterTransparencyWidget::pbnRemoveSelectedRow_clicked );
53 
54  mNodataColorButton->setShowNoColor( true );
55  mNodataColorButton->setColorDialogTitle( tr( "Select No Data Color" ) );
56  syncToLayer();
57 
58  connect( mOpacityWidget, &QgsOpacityWidget::opacityChanged, this, &QgsPanelWidget::widgetChanged );
59  connect( cboxTransparencyBand, &QgsRasterBandComboBox::bandChanged, this, &QgsPanelWidget::widgetChanged );
60  connect( mSrcNoDataValueCheckBox, &QCheckBox::stateChanged, this, &QgsPanelWidget::widgetChanged );
61  connect( leNoDataValue, &QLineEdit::textEdited, this, &QgsPanelWidget::widgetChanged );
62  leNoDataValue->setValidator( new QgsDoubleValidator( std::numeric_limits<double>::lowest(), std::numeric_limits<double>::max(), this ) );
63  connect( mNodataColorButton, &QgsColorButton::colorChanged, this, &QgsPanelWidget::widgetChanged );
64 
65  mPixelSelectorTool = nullptr;
66  if ( mMapCanvas )
67  {
68  mPixelSelectorTool = new QgsMapToolEmitPoint( mMapCanvas );
69  connect( mPixelSelectorTool, &QgsMapToolEmitPoint::canvasClicked, this, &QgsRasterTransparencyWidget::pixelSelected );
70  }
71  else
72  {
73  pbnAddValuesFromDisplay->setEnabled( false );
74  }
75 
77 }
78 
80 {
81  mContext = context;
82 }
83 
85 {
86  QgsExpressionContext expContext;
90 
91  if ( QgsMapCanvas *canvas = mContext.mapCanvas() )
92  {
93  expContext << QgsExpressionContextUtils::mapSettingsScope( canvas->mapSettings() )
94  << new QgsExpressionContextScope( canvas->expressionContextScope() );
95  if ( const QgsExpressionContextScopeGenerator *generator = dynamic_cast< const QgsExpressionContextScopeGenerator * >( canvas->temporalController() ) )
96  {
97  expContext << generator->createExpressionContextScope();
98  }
99  }
100  else
101  {
103  }
104 
105  if ( mRasterLayer )
106  expContext << QgsExpressionContextUtils::layerScope( mRasterLayer );
107 
108  // additional scopes
109  const auto constAdditionalExpressionContextScopes = mContext.additionalExpressionContextScopes();
110  for ( const QgsExpressionContextScope &scope : constAdditionalExpressionContextScopes )
111  {
112  expContext.appendScope( new QgsExpressionContextScope( scope ) );
113  }
114 
115  return expContext;
116 }
117 
119 {
120  QgsRasterDataProvider *provider = mRasterLayer->dataProvider();
121  QgsRasterRenderer *renderer = mRasterLayer->renderer();
122  if ( provider )
123  {
124  if ( provider->dataType( 1 ) == Qgis::DataType::ARGB32
125  || provider->dataType( 1 ) == Qgis::DataType::ARGB32_Premultiplied )
126  {
127  gboxNoDataValue->setEnabled( false );
128  gboxCustomTransparency->setEnabled( false );
129  }
130 
131  cboxTransparencyBand->setShowNotSetOption( true, tr( "None" ) );
132  cboxTransparencyBand->setLayer( mRasterLayer );
133  }
134 
135  if ( mRasterLayer->dataProvider()->sourceHasNoDataValue( 1 ) )
136  {
137  lblSrcNoDataValue->setText( QgsRasterBlock::printValue( mRasterLayer->dataProvider()->sourceNoDataValue( 1 ) ) );
138  }
139  else
140  {
141  lblSrcNoDataValue->setText( tr( "not defined" ) );
142  }
143 
144  mSrcNoDataValueCheckBox->setChecked( mRasterLayer->dataProvider()->useSourceNoDataValue( 1 ) );
145 
146  const bool enableSrcNoData = mRasterLayer->dataProvider()->sourceHasNoDataValue( 1 ) && !std::isnan( mRasterLayer->dataProvider()->sourceNoDataValue( 1 ) );
147 
148  mSrcNoDataValueCheckBox->setEnabled( enableSrcNoData );
149  lblSrcNoDataValue->setEnabled( enableSrcNoData );
150 
151  if ( renderer )
152  {
153  if ( renderer->nodataColor().isValid() )
154  mNodataColorButton->setColor( renderer->nodataColor() );
155  else
156  mNodataColorButton->setToNull();
157 
158  mOpacityWidget->setOpacity( renderer->opacity() );
159 
160  cboxTransparencyBand->setBand( renderer->alphaBand() );
161  }
162 
163  const QgsRasterRangeList noDataRangeList = mRasterLayer->dataProvider()->userNoDataValues( 1 );
164  QgsDebugMsg( QStringLiteral( "noDataRangeList.size = %1" ).arg( noDataRangeList.size() ) );
165  if ( !noDataRangeList.isEmpty() )
166  {
167  const double v = QgsRasterBlock::printValue( noDataRangeList.value( 0 ).min() ).toDouble();
168  leNoDataValue->setText( QLocale().toString( v ) );
169  }
170  else
171  {
172  leNoDataValue->setText( QString() );
173  }
174 
175  mPropertyCollection = mRasterLayer->pipe()->dataDefinedProperties();
176  updateDataDefinedButtons();
177 
178  populateTransparencyTable( mRasterLayer->renderer() );
179 }
180 
181 void QgsRasterTransparencyWidget::transparencyCellTextEdited( const QString &text )
182 {
183  Q_UNUSED( text )
184  QgsDebugMsg( QStringLiteral( "text = %1" ).arg( text ) );
185  QgsRasterRenderer *renderer = mRasterLayer->renderer();
186  if ( !renderer )
187  {
188  return;
189  }
190  const int nBands = renderer->usesBands().size();
191  if ( nBands == 1 )
192  {
193  QLineEdit *lineEdit = qobject_cast<QLineEdit *>( sender() );
194  if ( !lineEdit ) return;
195  int row = -1;
196  int column = -1;
197  for ( int r = 0; r < tableTransparency->rowCount(); r++ )
198  {
199  for ( int c = 0; c < tableTransparency->columnCount(); c++ )
200  {
201  if ( tableTransparency->cellWidget( r, c ) == sender() )
202  {
203  row = r;
204  column = c;
205  break;
206  }
207  }
208  if ( row != -1 ) break;
209  }
210  QgsDebugMsg( QStringLiteral( "row = %1 column =%2" ).arg( row ).arg( column ) );
211 
212  if ( column == 0 )
213  {
214  QLineEdit *toLineEdit = dynamic_cast<QLineEdit *>( tableTransparency->cellWidget( row, 1 ) );
215  if ( !toLineEdit ) return;
216  const bool toChanged = mTransparencyToEdited.value( row );
217  QgsDebugMsg( QStringLiteral( "toChanged = %1" ).arg( toChanged ) );
218  if ( !toChanged )
219  {
220  toLineEdit->setText( lineEdit->text() );
221  }
222  }
223  else if ( column == 1 )
224  {
225  setTransparencyToEdited( row );
226  }
227  }
228  emit widgetChanged();
229 }
230 
231 void QgsRasterTransparencyWidget::pbnAddValuesFromDisplay_clicked()
232 {
233  if ( mMapCanvas && mPixelSelectorTool )
234  {
235  mMapCanvas->setMapTool( mPixelSelectorTool );
236  }
237 }
238 
239 void QgsRasterTransparencyWidget::pbnAddValuesManually_clicked()
240 {
241  QgsRasterRenderer *renderer = mRasterLayer->renderer();
242  if ( !renderer )
243  {
244  return;
245  }
246 
247  tableTransparency->insertRow( tableTransparency->rowCount() );
248 
249  int n = renderer->usesBands().size();
250  if ( n == 1 ) n++;
251 
252  for ( int i = 0; i < n; i++ )
253  {
254  setTransparencyCell( tableTransparency->rowCount() - 1, i, std::numeric_limits<double>::quiet_NaN() );
255  }
256 
257  setTransparencyCell( tableTransparency->rowCount() - 1, n, 100 );
258 
259  //tableTransparency->resizeColumnsToContents();
260  //tableTransparency->resizeRowsToContents();
261 }
262 
263 void QgsRasterTransparencyWidget::pbnDefaultValues_clicked()
264 {
265  QgsRasterRenderer *r = mRasterLayer->renderer();
266  if ( !r )
267  {
268  return;
269  }
270 
271  const int nBands = r->usesBands().size();
272 
273  setupTransparencyTable( nBands );
274 
275  //tableTransparency->resizeColumnsToContents(); // works only with values
276  //tableTransparency->resizeRowsToContents();
277 
278 }
279 
280 void QgsRasterTransparencyWidget::pbnExportTransparentPixelValues_clicked()
281 {
282  const QgsSettings myQSettings;
283  const QString myLastDir = myQSettings.value( QStringLiteral( "lastRasterFileFilterDir" ), QDir::homePath() ).toString();
284  QString myFileName = QFileDialog::getSaveFileName( this, tr( "Save Pixel Values as File" ), myLastDir, tr( "Textfile" ) + " (*.txt)" );
285  if ( !myFileName.isEmpty() )
286  {
287  if ( !myFileName.endsWith( QLatin1String( ".txt" ), Qt::CaseInsensitive ) )
288  {
289  myFileName = myFileName + ".txt";
290  }
291 
292  QFile myOutputFile( myFileName );
293  if ( myOutputFile.open( QFile::WriteOnly | QIODevice::Truncate ) )
294  {
295  QTextStream myOutputStream( &myOutputFile );
296  myOutputStream << "# " << tr( "QGIS Generated Transparent Pixel Value Export File" ) << '\n';
297  if ( rasterIsMultiBandColor() )
298  {
299  myOutputStream << "#\n#\n# " << tr( "Red" ) << "\t" << tr( "Green" ) << "\t" << tr( "Blue" ) << "\t" << tr( "Percent Transparent" );
300  for ( int myTableRunner = 0; myTableRunner < tableTransparency->rowCount(); myTableRunner++ )
301  {
302  myOutputStream << '\n' << QString::number( transparencyCellValue( myTableRunner, 0 ) ) << "\t"
303  << QString::number( transparencyCellValue( myTableRunner, 1 ) ) << "\t"
304  << QString::number( transparencyCellValue( myTableRunner, 2 ) ) << "\t"
305  << QString::number( transparencyCellValue( myTableRunner, 3 ) );
306  }
307  }
308  else
309  {
310  myOutputStream << "#\n#\n# " << tr( "Value" ) << "\t" << tr( "Percent Transparent" );
311 
312  for ( int myTableRunner = 0; myTableRunner < tableTransparency->rowCount(); myTableRunner++ )
313  {
314  myOutputStream << '\n' << QString::number( transparencyCellValue( myTableRunner, 0 ) ) << "\t"
315  << QString::number( transparencyCellValue( myTableRunner, 1 ) ) << "\t"
316  << QString::number( transparencyCellValue( myTableRunner, 2 ) );
317  }
318  }
319  }
320  else
321  {
322  QMessageBox::warning( this, tr( "Save Pixel Values as File" ), tr( "Write access denied. Adjust the file permissions and try again.\n\n" ) );
323  }
324  }
325 }
326 
327 void QgsRasterTransparencyWidget::pbnImportTransparentPixelValues_clicked()
328 {
329  int myLineCounter = 0;
330  bool myImportError = false;
331  QString myBadLines;
332  const QgsSettings myQSettings;
333  const QString myLastDir = myQSettings.value( QStringLiteral( "lastRasterFileFilterDir" ), QDir::homePath() ).toString();
334  const QString myFileName = QFileDialog::getOpenFileName( this, tr( "Load Pixel Values from File" ), myLastDir, tr( "Textfile" ) + " (*.txt)" );
335  QFile myInputFile( myFileName );
336  if ( myInputFile.open( QFile::ReadOnly ) )
337  {
338  QTextStream myInputStream( &myInputFile );
339  QString myInputLine;
340  if ( rasterIsMultiBandColor() )
341  {
342  for ( int myTableRunner = tableTransparency->rowCount() - 1; myTableRunner >= 0; myTableRunner-- )
343  {
344  tableTransparency->removeRow( myTableRunner );
345  }
346 
347  while ( !myInputStream.atEnd() )
348  {
349  myLineCounter++;
350  myInputLine = myInputStream.readLine();
351  if ( !myInputLine.isEmpty() )
352  {
353  if ( !myInputLine.simplified().startsWith( '#' ) )
354  {
355 #if QT_VERSION < QT_VERSION_CHECK(5, 15, 0)
356  QStringList myTokens = myInputLine.split( QRegExp( "\\s+" ), QString::SkipEmptyParts );
357 #else
358  QStringList myTokens = myInputLine.split( QRegularExpression( "\\s+" ), Qt::SkipEmptyParts );
359 #endif
360  if ( myTokens.count() != 4 )
361  {
362  myImportError = true;
363  myBadLines = myBadLines + QString::number( myLineCounter ) + ":\t[" + myInputLine + "]\n";
364  }
365  else
366  {
367  tableTransparency->insertRow( tableTransparency->rowCount() );
368  for ( int col = 0; col < 4; col++ )
369  {
370  setTransparencyCell( tableTransparency->rowCount() - 1, col, myTokens[col].toDouble() );
371  }
372  }
373  }
374  }
375  }
376  }
377  else
378  {
379  for ( int myTableRunner = tableTransparency->rowCount() - 1; myTableRunner >= 0; myTableRunner-- )
380  {
381  tableTransparency->removeRow( myTableRunner );
382  }
383 
384  while ( !myInputStream.atEnd() )
385  {
386  myLineCounter++;
387  myInputLine = myInputStream.readLine();
388  if ( !myInputLine.isEmpty() )
389  {
390  if ( !myInputLine.simplified().startsWith( '#' ) )
391  {
392 #if QT_VERSION < QT_VERSION_CHECK(5, 15, 0)
393  QStringList myTokens = myInputLine.split( QRegExp( "\\s+" ), QString::SkipEmptyParts );
394 #else
395  QStringList myTokens = myInputLine.split( QRegularExpression( "\\s+" ), Qt::SkipEmptyParts );
396 #endif
397  if ( myTokens.count() != 3 && myTokens.count() != 2 ) // 2 for QGIS < 1.9 compatibility
398  {
399  myImportError = true;
400  myBadLines = myBadLines + QString::number( myLineCounter ) + ":\t[" + myInputLine + "]\n";
401  }
402  else
403  {
404  if ( myTokens.count() == 2 )
405  {
406  myTokens.insert( 1, myTokens[0] ); // add 'to' value, QGIS < 1.9 compatibility
407  }
408  tableTransparency->insertRow( tableTransparency->rowCount() );
409  for ( int col = 0; col < 3; col++ )
410  {
411  setTransparencyCell( tableTransparency->rowCount() - 1, col, myTokens[col].toDouble() );
412  }
413  }
414  }
415  }
416  }
417  }
418 
419  if ( myImportError )
420  {
421  QMessageBox::warning( this, tr( "Load Pixel Values from File" ), tr( "The following lines contained errors\n\n%1" ).arg( myBadLines ) );
422  }
423  }
424  else if ( !myFileName.isEmpty() )
425  {
426  QMessageBox::warning( this, tr( "Load Pixel Values from File" ), tr( "Read access denied. Adjust the file permissions and try again.\n\n" ) );
427  }
428  //tableTransparency->resizeColumnsToContents();
429  //tableTransparency->resizeRowsToContents();
430  emit widgetChanged();
431 }
432 
433 void QgsRasterTransparencyWidget::pbnRemoveSelectedRow_clicked()
434 {
435  if ( 0 < tableTransparency->rowCount() )
436  {
437  tableTransparency->removeRow( tableTransparency->currentRow() );
438  }
439  emit widgetChanged();
440 }
441 
442 bool QgsRasterTransparencyWidget::rasterIsMultiBandColor()
443 {
444  return mRasterLayer && nullptr != dynamic_cast<QgsMultiBandColorRenderer *>( mRasterLayer->renderer() );
445 }
446 
448 {
449  //set NoDataValue
450  QgsRasterRangeList myNoDataRangeList;
451  if ( "" != leNoDataValue->text() )
452  {
453  bool myDoubleOk = false;
454  const double myNoDataValue = QgsDoubleValidator::toDouble( leNoDataValue->text(), &myDoubleOk );
455  if ( myDoubleOk )
456  {
457  const QgsRasterRange myNoDataRange( myNoDataValue, myNoDataValue );
458  myNoDataRangeList << myNoDataRange;
459  }
460  }
461  for ( int bandNo = 1; bandNo <= mRasterLayer->dataProvider()->bandCount(); bandNo++ )
462  {
463  mRasterLayer->dataProvider()->setUserNoDataValue( bandNo, myNoDataRangeList );
464  mRasterLayer->dataProvider()->setUseSourceNoDataValue( bandNo, mSrcNoDataValueCheckBox->isChecked() );
465  }
466 
467  //transparency settings
468  QgsRasterRenderer *rasterRenderer = mRasterLayer->renderer();
469  if ( rasterRenderer )
470  {
471  rasterRenderer->setAlphaBand( cboxTransparencyBand->currentBand() );
472  rasterRenderer->setNodataColor( mNodataColorButton->color() );
473 
474  //Walk through each row in table and test value. If not valid set to 0.0 and continue building transparency list
475  QgsRasterTransparency *rasterTransparency = new QgsRasterTransparency();
476  if ( tableTransparency->columnCount() == 4 )
477  {
479  QList<QgsRasterTransparency::TransparentThreeValuePixel> myTransparentThreeValuePixelList;
480  myTransparentThreeValuePixelList.reserve( tableTransparency->rowCount() );
481  for ( int myListRunner = 0; myListRunner < tableTransparency->rowCount(); myListRunner++ )
482  {
483  myTransparentPixel.red = transparencyCellValue( myListRunner, 0 );
484  myTransparentPixel.green = transparencyCellValue( myListRunner, 1 );
485  myTransparentPixel.blue = transparencyCellValue( myListRunner, 2 );
486  myTransparentPixel.percentTransparent = transparencyCellValue( myListRunner, 3 );
487  myTransparentThreeValuePixelList.append( myTransparentPixel );
488  }
489  rasterTransparency->setTransparentThreeValuePixelList( myTransparentThreeValuePixelList );
490  }
491  else if ( tableTransparency->columnCount() == 3 )
492  {
494  QList<QgsRasterTransparency::TransparentSingleValuePixel> myTransparentSingleValuePixelList;
495  myTransparentSingleValuePixelList.reserve( tableTransparency->rowCount() );
496  for ( int myListRunner = 0; myListRunner < tableTransparency->rowCount(); myListRunner++ )
497  {
498  myTransparentPixel.min = transparencyCellValue( myListRunner, 0 );
499  myTransparentPixel.max = transparencyCellValue( myListRunner, 1 );
500  myTransparentPixel.percentTransparent = transparencyCellValue( myListRunner, 2 );
501 
502  myTransparentSingleValuePixelList.append( myTransparentPixel );
503  }
504  rasterTransparency->setTransparentSingleValuePixelList( myTransparentSingleValuePixelList );
505  }
506 
507  rasterRenderer->setRasterTransparency( rasterTransparency );
508 
509  //set global transparency
510  rasterRenderer->setOpacity( mOpacityWidget->opacity() );
511  }
512 
513  mRasterLayer->pipe()->setDataDefinedProperties( mPropertyCollection );
514 }
515 
517 {
518  button->blockSignals( true );
519  button->init( key, mPropertyCollection, QgsRasterPipe::propertyDefinitions(), nullptr );
520  connect( button, &QgsPropertyOverrideButton::changed, this, &QgsRasterTransparencyWidget::updateProperty );
521  button->registerExpressionContextGenerator( this );
522  button->blockSignals( false );
523 }
524 
526 {
527  const auto propertyOverrideButtons { findChildren< QgsPropertyOverrideButton * >() };
528  for ( QgsPropertyOverrideButton *button : propertyOverrideButtons )
529  {
530  updateDataDefinedButton( button );
531  }
532 }
533 
535 {
536  if ( !button )
537  return;
538 
539  if ( button->propertyKey() < 0 )
540  return;
541 
542  const QgsRasterPipe::Property key = static_cast< QgsRasterPipe::Property >( button->propertyKey() );
543  whileBlocking( button )->setToProperty( mPropertyCollection.property( key ) );
544 }
545 
546 void QgsRasterTransparencyWidget::updateProperty()
547 {
548  QgsPropertyOverrideButton *button = qobject_cast<QgsPropertyOverrideButton *>( sender() );
549  const QgsRasterPipe::Property key = static_cast< QgsRasterPipe::Property >( button->propertyKey() );
550  mPropertyCollection.setProperty( key, button->toProperty() );
551  emit widgetChanged();
552 }
553 
554 void QgsRasterTransparencyWidget::pixelSelected( const QgsPointXY &canvasPoint )
555 {
556  QgsRasterRenderer *renderer = mRasterLayer->renderer();
557  if ( !renderer )
558  {
559  return;
560  }
561 
562  //Get the pixel values and add a new entry to the transparency table
563  if ( mMapCanvas && mPixelSelectorTool )
564  {
565  mMapCanvas->unsetMapTool( mPixelSelectorTool );
566 
567  const QgsMapSettings &ms = mMapCanvas->mapSettings();
568  const QgsPointXY myPoint = ms.mapToLayerCoordinates( mRasterLayer, canvasPoint );
569 
570  const QgsRectangle myExtent = ms.mapToLayerCoordinates( mRasterLayer, mMapCanvas->extent() );
571  const double mapUnitsPerPixel = mMapCanvas->mapUnitsPerPixel();
572  const int myWidth = mMapCanvas->extent().width() / mapUnitsPerPixel;
573  const int myHeight = mMapCanvas->extent().height() / mapUnitsPerPixel;
574 
575  const QMap<int, QVariant> myPixelMap = mRasterLayer->dataProvider()->identify( myPoint, QgsRaster::IdentifyFormatValue, myExtent, myWidth, myHeight ).results();
576 
577  const QList<int> bands = renderer->usesBands();
578 
579  QList<double> values;
580  for ( int i = 0; i < bands.size(); ++i )
581  {
582  const int bandNo = bands.value( i );
583  if ( myPixelMap.count( bandNo ) == 1 )
584  {
585  if ( myPixelMap.value( bandNo ).isNull() )
586  {
587  return; // Don't add nodata, transparent anyway
588  }
589  const double value = myPixelMap.value( bandNo ).toDouble();
590  QgsDebugMsg( QStringLiteral( "value = %1" ).arg( value, 0, 'g', 17 ) );
591  values.append( value );
592  }
593  }
594  if ( bands.size() == 1 )
595  {
596  // Set 'to'
597  values.insert( 1, values.value( 0 ) );
598  }
599  tableTransparency->insertRow( tableTransparency->rowCount() );
600  for ( int i = 0; i < values.size(); i++ )
601  {
602  setTransparencyCell( tableTransparency->rowCount() - 1, i, values.value( i ) );
603  }
604  setTransparencyCell( tableTransparency->rowCount() - 1, tableTransparency->columnCount() - 1, 100 );
605  }
606 
607  //tableTransparency->resizeColumnsToContents();
608  //tableTransparency->resizeRowsToContents();
609 }
610 
611 void QgsRasterTransparencyWidget::populateTransparencyTable( QgsRasterRenderer *renderer )
612 {
613  if ( !mRasterLayer )
614  {
615  return;
616  }
617 
618  if ( !renderer )
619  {
620  return;
621  }
622 
623  const int nBands = renderer->usesBands().size();
624  setupTransparencyTable( nBands );
625 
626  const QgsRasterTransparency *rasterTransparency = renderer->rasterTransparency();
627  if ( !rasterTransparency )
628  {
629  return;
630  }
631 
632  if ( nBands == 1 )
633  {
634  QList<QgsRasterTransparency::TransparentSingleValuePixel> pixelList = rasterTransparency->transparentSingleValuePixelList();
635  for ( int i = 0; i < pixelList.size(); ++i )
636  {
637  tableTransparency->insertRow( i );
638  setTransparencyCell( i, 0, pixelList[i].min );
639  setTransparencyCell( i, 1, pixelList[i].max );
640  setTransparencyCell( i, 2, pixelList[i].percentTransparent );
641  // break synchronization only if values differ
642  if ( pixelList[i].min != pixelList[i].max )
643  {
644  setTransparencyToEdited( i );
645  }
646  }
647  }
648  else if ( nBands == 3 )
649  {
650  QList<QgsRasterTransparency::TransparentThreeValuePixel> pixelList = rasterTransparency->transparentThreeValuePixelList();
651  for ( int i = 0; i < pixelList.size(); ++i )
652  {
653  tableTransparency->insertRow( i );
654  setTransparencyCell( i, 0, pixelList[i].red );
655  setTransparencyCell( i, 1, pixelList[i].green );
656  setTransparencyCell( i, 2, pixelList[i].blue );
657  setTransparencyCell( i, 3, pixelList[i].percentTransparent );
658  }
659  }
660 
661  tableTransparency->resizeColumnsToContents();
662  tableTransparency->resizeRowsToContents();
663 
664 }
665 
666 void QgsRasterTransparencyWidget::setupTransparencyTable( int nBands )
667 {
668  tableTransparency->clear();
669  tableTransparency->setColumnCount( 0 );
670  tableTransparency->setRowCount( 0 );
671  mTransparencyToEdited.clear();
672 
673  if ( nBands == 3 )
674  {
675  tableTransparency->setColumnCount( 4 );
676  tableTransparency->setHorizontalHeaderItem( 0, new QTableWidgetItem( tr( "Red" ) ) );
677  tableTransparency->setHorizontalHeaderItem( 1, new QTableWidgetItem( tr( "Green" ) ) );
678  tableTransparency->setHorizontalHeaderItem( 2, new QTableWidgetItem( tr( "Blue" ) ) );
679  tableTransparency->setHorizontalHeaderItem( 3, new QTableWidgetItem( tr( "Percent Transparent" ) ) );
680  }
681  else //1 band
682  {
683  tableTransparency->setColumnCount( 3 );
684 // Is it important to distinguish the header? It becomes difficult with range.
685 #if 0
686  if ( QgsRasterLayer::PalettedColor != mRasterLayer->drawingStyle() &&
687  QgsRasterLayer::PalettedSingleBandGray != mRasterLayer->drawingStyle() &&
688  QgsRasterLayer::PalettedSingleBandPseudoColor != mRasterLayer->drawingStyle() &&
689  QgsRasterLayer::PalettedMultiBandColor != mRasterLayer->drawingStyle() )
690  {
691  tableTransparency->setHorizontalHeaderItem( 0, new QTableWidgetItem( tr( "Gray" ) ) );
692  }
693  else
694  {
695  tableTransparency->setHorizontalHeaderItem( 0, new QTableWidgetItem( tr( "Indexed Value" ) ) );
696  }
697 #endif
698  tableTransparency->setHorizontalHeaderItem( 0, new QTableWidgetItem( tr( "From" ) ) );
699  tableTransparency->setHorizontalHeaderItem( 1, new QTableWidgetItem( tr( "To" ) ) );
700  tableTransparency->setHorizontalHeaderItem( 2, new QTableWidgetItem( tr( "Percent Transparent" ) ) );
701  }
702 }
703 
704 void QgsRasterTransparencyWidget::setTransparencyCell( int row, int column, double value )
705 {
706  QgsDebugMsg( QStringLiteral( "value = %1" ).arg( value, 0, 'g', 17 ) );
707  QgsRasterDataProvider *provider = mRasterLayer->dataProvider();
708  if ( !provider ) return;
709 
710  QgsRasterRenderer *renderer = mRasterLayer->renderer();
711  if ( !renderer ) return;
712  const int nBands = renderer->usesBands().size();
713 
714  QLineEdit *lineEdit = new QLineEdit();
715  lineEdit->setFrame( false ); // frame looks bad in table
716  // Without margins row selection is not displayed (important for delete row)
717  lineEdit->setContentsMargins( 1, 1, 1, 1 );
718 
719  if ( column == tableTransparency->columnCount() - 1 )
720  {
721  // transparency
722  // Who needs transparency as floating point?
723  lineEdit->setValidator( new QIntValidator( nullptr ) );
724  lineEdit->setText( QString::number( static_cast<int>( value ) ) );
725  }
726  else
727  {
728  // value
729  QString valueString;
730  switch ( provider->sourceDataType( 1 ) )
731  {
734  lineEdit->setValidator( new QgsDoubleValidator( nullptr ) );
735  if ( !std::isnan( value ) )
736  {
737  const double v = QgsRasterBlock::printValue( value ).toDouble();
738  valueString = QLocale().toString( v );
739  }
740  break;
741  default:
742  lineEdit->setValidator( new QIntValidator( nullptr ) );
743  if ( !std::isnan( value ) )
744  {
745  valueString = QString::number( static_cast<int>( value ) );
746  }
747  break;
748  }
749  lineEdit->setText( valueString );
750  connect( lineEdit, &QLineEdit::textEdited, this, &QgsPanelWidget::widgetChanged );
751  }
752  tableTransparency->setCellWidget( row, column, lineEdit );
753  adjustTransparencyCellWidth( row, column );
754 
755  if ( nBands == 1 && ( column == 0 || column == 1 ) )
756  {
757  connect( lineEdit, &QLineEdit::textEdited, this, &QgsRasterTransparencyWidget::transparencyCellTextEdited );
758  }
759  //tableTransparency->resizeColumnsToContents();
760  emit widgetChanged();
761 }
762 
763 void QgsRasterTransparencyWidget::adjustTransparencyCellWidth( int row, int column )
764 {
765  QLineEdit *lineEdit = dynamic_cast<QLineEdit *>( tableTransparency->cellWidget( row, column ) );
766  if ( !lineEdit ) return;
767 
768  int width = std::max( lineEdit->fontMetrics().boundingRect( lineEdit->text() ).width() + 10, 100 );
769  width = std::max( width, tableTransparency->columnWidth( column ) );
770 
771  lineEdit->setFixedWidth( width );
772 }
773 
774 void QgsRasterTransparencyWidget::setTransparencyToEdited( int row )
775 {
776  if ( row >= mTransparencyToEdited.size() )
777  {
778  mTransparencyToEdited.resize( row + 1 );
779  }
780  mTransparencyToEdited[row] = true;
781 }
782 
783 double QgsRasterTransparencyWidget::transparencyCellValue( int row, int column )
784 {
785  QLineEdit *lineEdit = dynamic_cast<QLineEdit *>( tableTransparency->cellWidget( row, column ) );
786  if ( !lineEdit || lineEdit->text().isEmpty() )
787  {
788  return std::numeric_limits<double>::quiet_NaN();
789  }
790  return QgsDoubleValidator::toDouble( lineEdit->text() );
791 
792 }
793 
795 {
796  return mPixelSelectorTool;
797 }
QgsExpressionContext
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
Definition: qgsexpressioncontext.h:406
QgsOpacityWidget::opacityChanged
void opacityChanged(double opacity)
Emitted when the opacity is changed in the widget, where opacity ranges from 0.0 (transparent) to 1....
QgsRasterTransparency::setTransparentThreeValuePixelList
void setTransparentThreeValuePixelList(const QList< QgsRasterTransparency::TransparentThreeValuePixel > &newList)
Sets the transparent three value pixel list, replacing the whole existing list.
Definition: qgsrastertransparency.cpp:69
QgsRasterBandComboBox::bandChanged
void bandChanged(int band)
Emitted when the currently selected band changes.
qgsexpressioncontextutils.h
QgsRasterBlock::printValue
static QString printValue(double value)
Print double value with all necessary significant digits.
Definition: qgsrasterblock.cpp:618
QgsMapSettings::mapToLayerCoordinates
QgsPointXY mapToLayerCoordinates(const QgsMapLayer *layer, QgsPointXY point) const
transform point coordinates from output CRS to layer's CRS
Definition: qgsmapsettings.cpp:633
qgsrasterlayer.h
QgsRasterRenderer::setRasterTransparency
void setRasterTransparency(QgsRasterTransparency *t)
Definition: qgsrasterrenderer.cpp:99
QgsRasterDataProvider::dataType
Qgis::DataType dataType(int bandNo) const override=0
Returns data type for the band specified by number.
QgsSettings::value
QVariant value(const QString &key, const QVariant &defaultValue=QVariant(), Section section=NoSection) const
Returns the value for setting key.
Definition: qgssettings.cpp:161
QgsExpressionContextUtils::globalScope
static QgsExpressionContextScope * globalScope()
Creates a new scope which contains variables and functions relating to the global QGIS context.
Definition: qgsexpressioncontextutils.cpp:40
qgsrectangle.h
qgsmapcanvas.h
QgsRasterTransparencyWidget::initializeDataDefinedButton
void initializeDataDefinedButton(QgsPropertyOverrideButton *button, QgsRasterPipe::Property key)
Registers a property override button, setting up its initial value, connections and description.
Definition: qgsrastertransparencywidget.cpp:516
QgsPropertyOverrideButton::changed
void changed()
Emitted when property definition changes.
QgsRasterTransparency::transparentSingleValuePixelList
QList< QgsRasterTransparency::TransparentSingleValuePixel > transparentSingleValuePixelList() const
Returns the transparent single value pixel list.
Definition: qgsrastertransparency.cpp:27
qgsrasteridentifyresult.h
QgsRasterTransparency::transparentThreeValuePixelList
QList< QgsRasterTransparency::TransparentThreeValuePixel > transparentThreeValuePixelList() const
Returns the transparent three value pixel list.
Definition: qgsrastertransparency.cpp:32
QgsRasterTransparency::TransparentSingleValuePixel::min
double min
Definition: qgsrastertransparency.h:55
QgsRasterRenderer::nodataColor
QColor nodataColor() const
Returns the color to use for shading nodata pixels.
Definition: qgsrasterrenderer.h:102
QgsExpressionContextUtils::layerScope
static QgsExpressionContextScope * layerScope(const QgsMapLayer *layer)
Creates a new scope which contains variables and functions relating to a QgsMapLayer.
Definition: qgsexpressioncontextutils.cpp:334
QgsSymbolWidgetContext
Contains settings which reflect the context in which a symbol (or renderer) widget is shown,...
Definition: qgssymbolwidgetcontext.h:35
QgsMapCanvas
Map canvas is a class for displaying all GIS data types on a canvas.
Definition: qgsmapcanvas.h:89
QgsExpressionContextUtils::mapSettingsScope
static QgsExpressionContextScope * mapSettingsScope(const QgsMapSettings &mapSettings)
Creates a new scope which contains variables and functions relating to a QgsMapSettings object.
Definition: qgsexpressioncontextutils.cpp:427
QgsProject::instance
static QgsProject * instance()
Returns the QgsProject singleton instance.
Definition: qgsproject.cpp:480
QgsRasterTransparency::TransparentThreeValuePixel::percentTransparent
double percentTransparent
Definition: qgsrastertransparency.h:50
QgsPropertyOverrideButton::propertyKey
int propertyKey() const
Returns the property key linked to the button.
Definition: qgspropertyoverridebutton.h:123
QgsSettings
This class is a composition of two QSettings instances:
Definition: qgssettings.h:61
QgsExpressionContextScopeGenerator
Abstract interface for generating an expression context scope.
Definition: qgsexpressioncontextscopegenerator.h:28
QgsMapToolEmitPoint::canvasClicked
void canvasClicked(const QgsPointXY &point, Qt::MouseButton button)
signal emitted on canvas click
QgsDebugMsg
#define QgsDebugMsg(str)
Definition: qgslogger.h:38
qgsmapsettings.h
QgsRasterRenderer::usesBands
virtual QList< int > usesBands() const
Returns a list of band numbers used by the renderer.
Definition: qgsrasterrenderer.h:151
QgsRectangle
A rectangle specified with double values.
Definition: qgsrectangle.h:41
QgsMapLayerConfigWidget
A panel widget that can be shown in the map style dock.
Definition: qgsmaplayerconfigwidget.h:115
QgsPropertyOverrideButton
A button for controlling property overrides which may apply to a widget.
Definition: qgspropertyoverridebutton.h:50
QgsColorButton::colorChanged
void colorChanged(const QColor &color)
Emitted whenever a new color is set for the button.
QgsRasterTransparency::TransparentSingleValuePixel::percentTransparent
double percentTransparent
Definition: qgsrastertransparency.h:57
qgstemporalcontroller.h
QgsRasterTransparency::TransparentThreeValuePixel::blue
double blue
Definition: qgsrastertransparency.h:49
QgsExpressionContextUtils::projectScope
static QgsExpressionContextScope * projectScope(const QgsProject *project)
Creates a new scope which contains variables and functions relating to a QGIS project.
Definition: qgsexpressioncontextutils.cpp:291
qgsraster.h
QgsRaster::IdentifyFormatValue
@ IdentifyFormatValue
Definition: qgsraster.h:73
QgsRasterTransparencyWidget::setContext
void setContext(const QgsSymbolWidgetContext &context)
Sets the context in which the dialog is shown, e.g., the associated map canvas and expression context...
Definition: qgsrastertransparencywidget.cpp:79
whileBlocking
QgsSignalBlocker< Object > whileBlocking(Object *object)
Temporarily blocks signals from a QObject while calling a single method from the object.
Definition: qgis.h:2191
QgsRasterRenderer
Raster renderer pipe that applies colors to a raster.
Definition: qgsrasterrenderer.h:40
QgsRasterRenderer::rasterTransparency
const QgsRasterTransparency * rasterTransparency() const
Definition: qgsrasterrenderer.h:116
QgsRasterTransparencyWidget::syncToLayer
void syncToLayer()
Sync the widget state to the layer set for the widget.
Definition: qgsrastertransparencywidget.cpp:118
qgsrastertransparencywidget.h
QgsRasterTransparencyWidget::pixelSelectorTool
QgsMapToolEmitPoint * pixelSelectorTool() const
Returns the (possibly nullptr) map pixel selector tool.
Definition: qgsrastertransparencywidget.cpp:794
QgsRasterPipe::RendererOpacity
@ RendererOpacity
Raster renderer global opacity.
Definition: qgsrasterpipe.h:59
QgsRasterRenderer::setAlphaBand
void setAlphaBand(int band)
Definition: qgsrasterrenderer.h:118
QgsDoubleValidator
QgsDoubleValidator is a QLineEdit Validator that combines QDoubleValidator and QRegularExpressionVali...
Definition: qgsdoublevalidator.h:40
QgsRasterTransparencyWidget::updateDataDefinedButton
void updateDataDefinedButton(QgsPropertyOverrideButton *button)
Updates a specific property override button to reflect the widgets's current properties.
Definition: qgsrastertransparencywidget.cpp:534
QgsRasterTransparencyWidget::apply
void apply() override
Apply any changes on the widget to the set layer.
Definition: qgsrastertransparencywidget.cpp:447
Qgis::DataType::Float64
@ Float64
Sixty four bit floating point (double)
QgsPanelWidget::widgetChanged
void widgetChanged()
Emitted when the widget state changes.
QgsPropertyOverrideButton::toProperty
QgsProperty toProperty() const
Returns a QgsProperty object encapsulating the current state of the widget.
Definition: qgspropertyoverridebutton.cpp:192
QgsRasterTransparency::TransparentSingleValuePixel::max
double max
Definition: qgsrastertransparency.h:56
QgsRasterRangeList
QList< QgsRasterRange > QgsRasterRangeList
Definition: qgsrasterrange.h:26
QgsRasterTransparency::setTransparentSingleValuePixelList
void setTransparentSingleValuePixelList(const QList< QgsRasterTransparency::TransparentSingleValuePixel > &newList)
Sets the transparent single value pixel list, replacing the whole existing list.
Definition: qgsrastertransparency.cpp:64
QgsRasterTransparency::TransparentSingleValuePixel
Definition: qgsrastertransparency.h:53
Qgis::DataType::ARGB32_Premultiplied
@ ARGB32_Premultiplied
Color, alpha, red, green, blue, 4 bytes the same as QImage::Format_ARGB32_Premultiplied.
QgsMultiBandColorRenderer
Renderer for multiband images with the color components.
Definition: qgsmultibandcolorrenderer.h:32
QgsRasterLayer
Represents a raster layer.
Definition: qgsrasterlayer.h:76
QgsRasterTransparency
Defines the list of pixel values to be considered as transparent or semi transparent when rendering r...
Definition: qgsrastertransparency.h:32
qgsrastertransparency.h
QgsPropertyOverrideButton::init
void init(int propertyKey, const QgsProperty &property, const QgsPropertiesDefinition &definitions, const QgsVectorLayer *layer=nullptr, bool auxiliaryStorageEnabled=false)
Initialize a newly constructed property button (useful if button was included in a UI layout).
Definition: qgspropertyoverridebutton.cpp:96
QgsRasterPipe::propertyDefinitions
static QgsPropertiesDefinition propertyDefinitions()
Returns the definitions for data defined properties available for use in raster pipes.
Definition: qgsrasterpipe.cpp:444
qgsrasterlayerrenderer.h
Qgis::DataType::ARGB32
@ ARGB32
Color, alpha, red, green, blue, 4 bytes the same as QImage::Format_ARGB32.
QgsExpressionContextScope
Single scope for storing variables and functions for use within a QgsExpressionContext....
Definition: qgsexpressioncontext.h:113
QgsExpressionContext::appendScope
void appendScope(QgsExpressionContextScope *scope)
Appends a scope to the end of the context.
Definition: qgsexpressioncontext.cpp:494
QgsPointXY
A class to represent a 2D point.
Definition: qgspointxy.h:58
QgsRasterTransparencyWidget::updateDataDefinedButtons
void updateDataDefinedButtons()
Updates all property override buttons to reflect the widgets's current properties.
Definition: qgsrastertransparencywidget.cpp:525
QgsMapToolEmitPoint
A map tool that simply emits a point when clicking on the map. Connecting a slot to its canvasClicked...
Definition: qgsmaptoolemitpoint.h:30
QgsRasterDataProvider::sourceDataType
Qgis::DataType sourceDataType(int bandNo) const override=0
Returns source data type for the band specified by number, source data type may be shorter than dataT...
Qgis::DataType::Float32
@ Float32
Thirty two bit floating point (float)
c
As part of the API refactoring and improvements which landed in the Processing API was substantially reworked from the x version This was done in order to allow much of the underlying Processing framework to be ported into c
Definition: porting_processing.dox:1
QgsPropertyOverrideButton::registerExpressionContextGenerator
void registerExpressionContextGenerator(QgsExpressionContextGenerator *generator)
Register an expression context generator class that will be used to retrieve an expression context fo...
Definition: qgspropertyoverridebutton.cpp:945
QgsRasterRenderer::alphaBand
int alphaBand() const
Definition: qgsrasterrenderer.h:119
qgsmultibandcolorrenderer.h
QgsDoubleValidator::toDouble
static double toDouble(const QString &input, bool *ok)
Converts input string to double value.
Definition: qgsdoublevalidator.cpp:134
qgssettings.h
QgsRasterTransparencyWidget::QgsRasterTransparencyWidget
QgsRasterTransparencyWidget(QgsRasterLayer *layer, QgsMapCanvas *canvas, QWidget *parent=nullptr)
Widget to control a layers transparency and related options.
Definition: qgsrastertransparencywidget.cpp:40
QgsRasterTransparency::TransparentThreeValuePixel
Definition: qgsrastertransparency.h:45
QgsRasterRange
Raster values range container. Represents range of values between min and max including min and max v...
Definition: qgsrasterrange.h:35
QgsExpressionContextUtils::atlasScope
static QgsExpressionContextScope * atlasScope(const QgsLayoutAtlas *atlas)
Creates a new scope which contains variables and functions relating to a QgsLayoutAtlas.
Definition: qgsexpressioncontextutils.cpp:660
QgsRasterPipe::Property
Property
Data definable properties.
Definition: qgsrasterpipe.h:57
QgsRasterRenderer::setNodataColor
void setNodataColor(const QColor &color)
Sets the color to use for shading nodata pixels.
Definition: qgsrasterrenderer.h:113
QgsRasterTransparency::TransparentThreeValuePixel::red
double red
Definition: qgsrastertransparency.h:47
qgsdoublevalidator.h
QgsMapSettings
The QgsMapSettings class contains configuration for rendering of the map. The rendering itself is don...
Definition: qgsmapsettings.h:88
QgsRasterTransparency::TransparentThreeValuePixel::green
double green
Definition: qgsrastertransparency.h:48
QgsRasterRenderer::setOpacity
void setOpacity(double opacity)
Sets the opacity for the renderer, where opacity is a value between 0 (totally transparent) and 1....
Definition: qgsrasterrenderer.h:83
QgsRasterDataProvider
Base class for raster data providers.
Definition: qgsrasterdataprovider.h:88
qgsmaptoolemitpoint.h
qgsrasterdataprovider.h
QgsRasterRenderer::opacity
double opacity() const
Returns the opacity for the renderer, where opacity is a value between 0 (totally transparent) and 1....
Definition: qgsrasterrenderer.h:90
QgsRasterTransparencyWidget::createExpressionContext
QgsExpressionContext createExpressionContext() const override
This method needs to be reimplemented in all classes which implement this interface and return an exp...
Definition: qgsrastertransparencywidget.cpp:84