Example #1
0
void QgsRendererRasterPropertiesWidget::setRendererWidget( const QString &rendererName )
{
    QgsDebugMsg( "rendererName = " + rendererName );
    QgsRasterRendererWidget* oldWidget = mRendererWidget;

    QgsRasterRendererRegistryEntry rendererEntry;
    if ( QgsRasterRendererRegistry::instance()->rendererData( rendererName, rendererEntry ) )
    {
        if ( rendererEntry.widgetCreateFunction ) //single band color data renderer e.g. has no widget
        {
            QgsDebugMsg( "renderer has widgetCreateFunction" );
            // Current canvas extent (used to calc min/max) in layer CRS
            QgsRectangle myExtent = mMapCanvas->mapSettings().outputExtentToLayerExtent( mRasterLayer, mMapCanvas->extent() );
            mRendererWidget = rendererEntry.widgetCreateFunction( mRasterLayer, myExtent );
            mRendererWidget->setMapCanvas( mMapCanvas );
            connect( mRendererWidget, SIGNAL( widgetChanged() ), this, SIGNAL( widgetChanged() ) );
            stackedWidget->addWidget( mRendererWidget );
            stackedWidget->setCurrentWidget( mRendererWidget );
            if ( oldWidget )
            {
                //compare used bands in new and old renderer and reset transparency dialog if different
                QgsRasterRenderer* oldRenderer = oldWidget->renderer();
                QgsRasterRenderer* newRenderer = mRendererWidget->renderer();
                QList<int> oldBands = oldRenderer->usesBands();
                QList<int> newBands = newRenderer->usesBands();
//        if ( oldBands != newBands )
//        {
//          populateTransparencyTable( newRenderer );
//        }
                delete oldRenderer;
                delete newRenderer;
            }
        }
    }

    if ( mRendererWidget != oldWidget )
        delete oldWidget;

    int widgetIndex = cboRenderers->findData( rendererName );
    if ( widgetIndex != -1 )
    {
        whileBlocking( cboRenderers )->setCurrentIndex( widgetIndex );
    }

}
void QgsRasterTransparencyWidget::setTransparencyCell( int row, int column, double value )
{
  QgsDebugMsg( QStringLiteral( "value = %1" ).arg( value, 0, 'g', 17 ) );
  QgsRasterDataProvider *provider = mRasterLayer->dataProvider();
  if ( !provider ) return;

  QgsRasterRenderer *renderer = mRasterLayer->renderer();
  if ( !renderer ) return;
  int nBands = renderer->usesBands().size();

  QLineEdit *lineEdit = new QLineEdit();
  lineEdit->setFrame( false ); // frame looks bad in table
  // Without margins row selection is not displayed (important for delete row)
  lineEdit->setContentsMargins( 1, 1, 1, 1 );

  if ( column == tableTransparency->columnCount() - 1 )
  {
    // transparency
    // Who needs transparency as floating point?
    lineEdit->setValidator( new QIntValidator( nullptr ) );
    lineEdit->setText( QString::number( static_cast<int>( value ) ) );
  }
  else
  {
    // value
    QString valueString;
    switch ( provider->sourceDataType( 1 ) )
    {
      case Qgis::Float32:
      case Qgis::Float64:
        lineEdit->setValidator( new QDoubleValidator( nullptr ) );
        if ( !std::isnan( value ) )
        {
          valueString = QgsRasterBlock::printValue( value );
        }
        break;
      default:
        lineEdit->setValidator( new QIntValidator( nullptr ) );
        if ( !std::isnan( value ) )
        {
          valueString = QString::number( static_cast<int>( value ) );
        }
        break;
    }
    lineEdit->setText( valueString );
    connect( lineEdit, &QLineEdit::textEdited, this, &QgsPanelWidget::widgetChanged );
  }
  tableTransparency->setCellWidget( row, column, lineEdit );
  adjustTransparencyCellWidth( row, column );

  if ( nBands == 1 && ( column == 0 || column == 1 ) )
  {
    connect( lineEdit, &QLineEdit::textEdited, this, &QgsRasterTransparencyWidget::transparencyCellTextEdited );
  }
  tableTransparency->resizeColumnsToContents();
  emit widgetChanged();
}
void QgsRasterTransparencyWidget::pixelSelected( const QgsPointXY &canvasPoint )
{
  QgsRasterRenderer *renderer = mRasterLayer->renderer();
  if ( !renderer )
  {
    return;
  }

  //Get the pixel values and add a new entry to the transparency table
  if ( mMapCanvas && mPixelSelectorTool )
  {
    mMapCanvas->unsetMapTool( mPixelSelectorTool );

    const QgsMapSettings &ms = mMapCanvas->mapSettings();
    QgsPointXY myPoint = ms.mapToLayerCoordinates( mRasterLayer, canvasPoint );

    QgsRectangle myExtent = ms.mapToLayerCoordinates( mRasterLayer, mMapCanvas->extent() );
    double mapUnitsPerPixel = mMapCanvas->mapUnitsPerPixel();
    int myWidth = mMapCanvas->extent().width() / mapUnitsPerPixel;
    int myHeight = mMapCanvas->extent().height() / mapUnitsPerPixel;

    QMap<int, QVariant> myPixelMap = mRasterLayer->dataProvider()->identify( myPoint, QgsRaster::IdentifyFormatValue, myExtent, myWidth, myHeight ).results();

    QList<int> bands = renderer->usesBands();

    QList<double> values;
    for ( int i = 0; i < bands.size(); ++i )
    {
      int bandNo = bands.value( i );
      if ( myPixelMap.count( bandNo ) == 1 )
      {
        if ( myPixelMap.value( bandNo ).isNull() )
        {
          return; // Don't add nodata, transparent anyway
        }
        double value = myPixelMap.value( bandNo ).toDouble();
        QgsDebugMsg( QStringLiteral( "value = %1" ).arg( value, 0, 'g', 17 ) );
        values.append( value );
      }
    }
    if ( bands.size() == 1 )
    {
      // Set 'to'
      values.insert( 1, values.value( 0 ) );
    }
    tableTransparency->insertRow( tableTransparency->rowCount() );
    for ( int i = 0; i < values.size(); i++ )
    {
      setTransparencyCell( tableTransparency->rowCount() - 1, i, values.value( i ) );
    }
    setTransparencyCell( tableTransparency->rowCount() - 1, tableTransparency->columnCount() - 1, 100 );
  }

  tableTransparency->resizeColumnsToContents();
  tableTransparency->resizeRowsToContents();
}
void QgsRasterTransparencyWidget::transparencyCellTextEdited( const QString &text )
{
  Q_UNUSED( text )
  QgsDebugMsg( QStringLiteral( "text = %1" ).arg( text ) );
  QgsRasterRenderer *renderer = mRasterLayer->renderer();
  if ( !renderer )
  {
    return;
  }
  int nBands = renderer->usesBands().size();
  if ( nBands == 1 )
  {
    QLineEdit *lineEdit = dynamic_cast<QLineEdit *>( sender() );
    if ( !lineEdit ) return;
    int row = -1;
    int column = -1;
    for ( int r = 0; r < tableTransparency->rowCount(); r++ )
    {
      for ( int c = 0; c < tableTransparency->columnCount(); c++ )
      {
        if ( tableTransparency->cellWidget( r, c ) == sender() )
        {
          row = r;
          column = c;
          break;
        }
      }
      if ( row != -1 ) break;
    }
    QgsDebugMsg( QStringLiteral( "row = %1 column =%2" ).arg( row ).arg( column ) );

    if ( column == 0 )
    {
      QLineEdit *toLineEdit = dynamic_cast<QLineEdit *>( tableTransparency->cellWidget( row, 1 ) );
      if ( !toLineEdit ) return;
      bool toChanged = mTransparencyToEdited.value( row );
      QgsDebugMsg( QStringLiteral( "toChanged = %1" ).arg( toChanged ) );
      if ( !toChanged )
      {
        toLineEdit->setText( lineEdit->text() );
      }
    }
    else if ( column == 1 )
    {
      setTransparencyToEdited( row );
    }
  }
  emit widgetChanged();
}
void QgsRasterTransparencyWidget::pbnDefaultValues_clicked()
{
  QgsRasterRenderer *r = mRasterLayer->renderer();
  if ( !r )
  {
    return;
  }

  int nBands = r->usesBands().size();

  setupTransparencyTable( nBands );

  tableTransparency->resizeColumnsToContents(); // works only with values
  tableTransparency->resizeRowsToContents();

}
void QgsRasterTransparencyWidget::pbnAddValuesManually_clicked()
{
  QgsRasterRenderer *renderer = mRasterLayer->renderer();
  if ( !renderer )
  {
    return;
  }

  tableTransparency->insertRow( tableTransparency->rowCount() );

  int n = renderer->usesBands().size();
  if ( n == 1 ) n++;

  for ( int i = 0; i < n; i++ )
  {
    setTransparencyCell( tableTransparency->rowCount() - 1, i, std::numeric_limits<double>::quiet_NaN() );
  }

  setTransparencyCell( tableTransparency->rowCount() - 1, n, 100 );

  tableTransparency->resizeColumnsToContents();
  tableTransparency->resizeRowsToContents();
}
QgsRasterRenderer* QgsRasterRendererRegistry::defaultRendererForDrawingStyle( QgsRaster::DrawingStyle theDrawingStyle, QgsRasterDataProvider* provider ) const
{
    if ( !provider || provider->bandCount() < 1 )
    {
        return nullptr;
    }


    QgsRasterRenderer* renderer = nullptr;
    switch ( theDrawingStyle )
    {
    case QgsRaster::PalettedColor:
    {
        int grayBand = 1; //reasonable default
        QList<QgsColorRampShader::ColorRampItem> colorEntries = provider->colorTable( grayBand );

        //go through list and take maximum value (it could be that entries don't start at 0 or indices are not contiguous)
        int colorArraySize = 0;
        QList<QgsColorRampShader::ColorRampItem>::const_iterator colorIt = colorEntries.constBegin();
        for ( ; colorIt != colorEntries.constEnd(); ++colorIt )
        {
            if ( colorIt->value > colorArraySize )
            {
                colorArraySize = ( int )( colorIt->value );
            }
        }

        colorArraySize += 1; //usually starts at 0
        QColor* colorArray = new QColor[ colorArraySize ];
        colorIt = colorEntries.constBegin();
        QVector<QString> labels;
        for ( ; colorIt != colorEntries.constEnd(); ++colorIt )
        {
            int idx = ( int )( colorIt->value );
            colorArray[idx] = colorIt->color;
            if ( !colorIt->label.isEmpty() )
            {
                if ( labels.size() <= idx ) labels.resize( idx + 1 );
                labels[idx] = colorIt->label;
            }
        }

        renderer = new QgsPalettedRasterRenderer( provider,
                grayBand,
                colorArray,
                colorArraySize,
                labels );
    }
    break;
    case QgsRaster::MultiBandSingleBandGray:
    case QgsRaster::SingleBandGray:
    {
        int grayBand = 1;
        renderer = new QgsSingleBandGrayRenderer( provider, grayBand );

        QgsContrastEnhancement* ce = new QgsContrastEnhancement(( QGis::DataType )(
                    provider->dataType( grayBand ) ) );

// Default contrast enhancement is set from QgsRasterLayer, it has already setContrastEnhancementAlgorithm(). Default enhancement must only be set if default style was not loaded (to avoid stats calculation).
        (( QgsSingleBandGrayRenderer* )renderer )->setContrastEnhancement( ce );
        break;
    }
    case QgsRaster::SingleBandPseudoColor:
    {
        int bandNo = 1;
        double minValue = 0;
        double maxValue = 0;
        // TODO: avoid calculating statistics if not necessary (default style loaded)
        minMaxValuesForBand( bandNo, provider, minValue, maxValue );
        QgsRasterShader* shader = new QgsRasterShader( minValue, maxValue );
        renderer = new QgsSingleBandPseudoColorRenderer( provider, bandNo, shader );
        break;
    }
    case QgsRaster::MultiBandColor:
    {
        QSettings s;

        int redBand = s.value( "/Raster/defaultRedBand", 1 ).toInt();
        if ( redBand < 0 || redBand > provider->bandCount() )
        {
            redBand = -1;
        }
        int greenBand = s.value( "/Raster/defaultGreenBand", 2 ).toInt();
        if ( greenBand < 0 || greenBand > provider->bandCount() )
        {
            greenBand = -1;
        }
        int blueBand = s.value( "/Raster/defaultBlueBand", 3 ).toInt();
        if ( blueBand < 0 || blueBand > provider->bandCount() )
        {
            blueBand = -1;
        }

        renderer = new QgsMultiBandColorRenderer( provider, redBand, greenBand, blueBand );
        break;
    }
    case QgsRaster::SingleBandColorDataStyle:
    {
        renderer = new QgsSingleBandColorDataRenderer( provider, 1 );
        break;
    }
    default:
        return nullptr;
    }

    QgsRasterTransparency* tr = new QgsRasterTransparency(); //renderer takes ownership
    int bandCount = renderer->usesBands().size();
    if ( bandCount == 1 )
    {
        QList<QgsRasterTransparency::TransparentSingleValuePixel> transparentSingleList;
        tr->setTransparentSingleValuePixelList( transparentSingleList );
    }
    else if ( bandCount == 3 )
    {
        QList<QgsRasterTransparency::TransparentThreeValuePixel> transparentThreeValueList;
        tr->setTransparentThreeValuePixelList( transparentThreeValueList );
    }
    renderer->setRasterTransparency( tr );
    return renderer;
}
void QgsRendererRasterPropertiesWidget::setRendererWidget( const QString &rendererName )
{
  QgsDebugMsg( "rendererName = " + rendererName );
  QgsRasterRendererWidget *oldWidget = mRendererWidget;
  QgsRasterRenderer *oldRenderer = mRasterLayer->renderer();

  int alphaBand = -1;
  double opacity = 1;
  if ( oldRenderer )
  {
    // Retain alpha band and opacity when switching renderer
    alphaBand = oldRenderer->alphaBand();
    opacity = oldRenderer->opacity();
  }

  QgsRasterRendererRegistryEntry rendererEntry;
  if ( QgsApplication::rasterRendererRegistry()->rendererData( rendererName, rendererEntry ) )
  {
    if ( rendererEntry.widgetCreateFunction ) // Single band color data renderer e.g. has no widget
    {
      QgsDebugMsg( QStringLiteral( "renderer has widgetCreateFunction" ) );
      // Current canvas extent (used to calc min/max) in layer CRS
      QgsRectangle myExtent = mMapCanvas->mapSettings().outputExtentToLayerExtent( mRasterLayer, mMapCanvas->extent() );
      if ( oldWidget )
      {
        if ( rendererName == QLatin1String( "singlebandgray" ) )
        {
          whileBlocking( mRasterLayer )->setRenderer( QgsApplication::rasterRendererRegistry()->defaultRendererForDrawingStyle( QgsRaster::SingleBandGray, mRasterLayer->dataProvider() ) );
          whileBlocking( mRasterLayer )->setDefaultContrastEnhancement();
        }
        else if ( rendererName == QLatin1String( "multibandcolor" ) )
        {
          whileBlocking( mRasterLayer )->setRenderer( QgsApplication::rasterRendererRegistry()->defaultRendererForDrawingStyle( QgsRaster::MultiBandColor, mRasterLayer->dataProvider() ) );
          whileBlocking( mRasterLayer )->setDefaultContrastEnhancement();
        }
      }
      mRasterLayer->renderer()->setAlphaBand( alphaBand );
      mRasterLayer->renderer()->setOpacity( opacity );
      mRendererWidget = rendererEntry.widgetCreateFunction( mRasterLayer, myExtent );
      mRendererWidget->setMapCanvas( mMapCanvas );
      connect( mRendererWidget, &QgsRasterRendererWidget::widgetChanged, this, &QgsPanelWidget::widgetChanged );
      stackedWidget->addWidget( mRendererWidget );
      stackedWidget->setCurrentWidget( mRendererWidget );
      if ( oldWidget )
      {
        // Compare used bands in new and old renderer and reset transparency dialog if different
        QgsRasterRenderer *oldRenderer = oldWidget->renderer();
        QgsRasterRenderer *newRenderer = mRendererWidget->renderer();
#if 0
        QList<int> oldBands = oldRenderer->usesBands();
        QList<int> newBands = newRenderer->usesBands();

        if ( oldBands != newBands )
        {
          populateTransparencyTable( newRenderer );
        }
#endif

        delete oldRenderer;
        delete newRenderer;
      }
    }
  }

  if ( mRendererWidget != oldWidget )
    delete oldWidget;

  int widgetIndex = cboRenderers->findData( rendererName );
  if ( widgetIndex != -1 )
  {
    whileBlocking( cboRenderers )->setCurrentIndex( widgetIndex );
  }

}
QgsRasterRenderer *QgsRasterRendererRegistry::defaultRendererForDrawingStyle( QgsRaster::DrawingStyle drawingStyle, QgsRasterDataProvider *provider ) const
{
  if ( !provider || provider->bandCount() < 1 )
  {
    return nullptr;
  }


  QgsRasterRenderer *renderer = nullptr;
  switch ( drawingStyle )
  {
    case QgsRaster::PalettedColor:
    {
      int grayBand = 1; //reasonable default
      QgsPalettedRasterRenderer::ClassData classes = QgsPalettedRasterRenderer::colorTableToClassData( provider->colorTable( grayBand ) );
      renderer = new QgsPalettedRasterRenderer( provider,
          grayBand,
          classes );
    }
    break;
    case QgsRaster::MultiBandSingleBandGray:
    case QgsRaster::SingleBandGray:
    {
      int grayBand = 1;
      renderer = new QgsSingleBandGrayRenderer( provider, grayBand );

      QgsContrastEnhancement *ce = new QgsContrastEnhancement( ( Qgis::DataType )(
            provider->dataType( grayBand ) ) );

// Default contrast enhancement is set from QgsRasterLayer, it has already setContrastEnhancementAlgorithm(). Default enhancement must only be set if default style was not loaded (to avoid stats calculation).
      ( ( QgsSingleBandGrayRenderer * )renderer )->setContrastEnhancement( ce );
      break;
    }
    case QgsRaster::SingleBandPseudoColor:
    {
      int bandNo = 1;
      double minValue = 0;
      double maxValue = 0;
      // TODO: avoid calculating statistics if not necessary (default style loaded)
      minMaxValuesForBand( bandNo, provider, minValue, maxValue );
      QgsRasterShader *shader = new QgsRasterShader( minValue, maxValue );
      renderer = new QgsSingleBandPseudoColorRenderer( provider, bandNo, shader );
      break;
    }
    case QgsRaster::MultiBandColor:
    {
      QgsSettings s;

      int redBand = s.value( QStringLiteral( "/Raster/defaultRedBand" ), 1 ).toInt();
      if ( redBand < 0 || redBand > provider->bandCount() )
      {
        redBand = -1;
      }
      int greenBand = s.value( QStringLiteral( "/Raster/defaultGreenBand" ), 2 ).toInt();
      if ( greenBand < 0 || greenBand > provider->bandCount() )
      {
        greenBand = -1;
      }
      int blueBand = s.value( QStringLiteral( "/Raster/defaultBlueBand" ), 3 ).toInt();
      if ( blueBand < 0 || blueBand > provider->bandCount() )
      {
        blueBand = -1;
      }

      renderer = new QgsMultiBandColorRenderer( provider, redBand, greenBand, blueBand );
      break;
    }
    case QgsRaster::SingleBandColorDataStyle:
    {
      renderer = new QgsSingleBandColorDataRenderer( provider, 1 );
      break;
    }
    default:
      return nullptr;
  }

  QgsRasterTransparency *tr = new QgsRasterTransparency(); //renderer takes ownership
  int bandCount = renderer->usesBands().size();
  if ( bandCount == 1 )
  {
    QList<QgsRasterTransparency::TransparentSingleValuePixel> transparentSingleList;
    tr->setTransparentSingleValuePixelList( transparentSingleList );
  }
  else if ( bandCount == 3 )
  {
    QList<QgsRasterTransparency::TransparentThreeValuePixel> transparentThreeValueList;
    tr->setTransparentThreeValuePixelList( transparentThreeValueList );
  }
  renderer->setRasterTransparency( tr );
  return renderer;
}