Example #1
0
void QgsRasterCalcDialog::insertAvailableRasterBands()
{
  const QMap<QString, QgsMapLayer*>& layers = QgsMapLayerRegistry::instance()->mapLayers();
  QMap<QString, QgsMapLayer*>::const_iterator layerIt = layers.constBegin();

  bool firstLayer = true;
  for ( ; layerIt != layers.constEnd(); ++layerIt )
  {
    QgsRasterLayer* rlayer = dynamic_cast<QgsRasterLayer*>( layerIt.value() );
    if ( rlayer && rlayer->dataProvider() && rlayer->dataProvider()->name() == "gdal" )
    {
      if ( firstLayer ) //set bounding box / resolution of output to the values of the first possible input layer
      {
        mNColumnsSpinBox->setValue( rlayer->width() );
        mNRowsSpinBox->setValue( rlayer->height() );
        QgsRectangle bbox = rlayer->extent();
        mXMinSpinBox->setValue( bbox.xMinimum() );
        mXMaxSpinBox->setValue( bbox.xMaximum() );
        mYMinSpinBox->setValue( bbox.yMinimum() );
        mYMaxSpinBox->setValue( bbox.yMaximum() );
        firstLayer = false;
      }
      //get number of bands
      for ( int i = 0; i < rlayer->bandCount(); ++i )
      {
        QgsRasterCalculatorEntry entry;
        entry.raster = rlayer;
        entry.bandNumber = i + 1;
        entry.ref = rlayer->name() + '@' + QString::number( i + 1 );
        mAvailableRasterBands.push_back( entry );
        mRasterBandsListWidget->addItem( entry.ref );
      }
    }
  }
}
Example #2
0
void QgsTileScaleWidget::layerChanged( QgsMapLayer *layer )
{
  mSlider->setDisabled( true );

  QgsRasterLayer *rl = qobject_cast<QgsRasterLayer *>( layer );
  if ( !rl || rl->providerType() != QLatin1String( "wms" ) || !rl->dataProvider() )
    return;

  QVariant res = rl->dataProvider()->property( "resolutions" );

  mResolutions.clear();
  Q_FOREACH ( const QVariant &r, res.toList() )
  {
    QgsDebugMsg( QString( "found resolution: %1" ).arg( r.toDouble() ) );
    mResolutions << r.toDouble();
  }

  if ( mResolutions.isEmpty() )
    return;

  mSlider->setRange( 0, mResolutions.size() - 1 );
  mSlider->setTickInterval( 1 );
  mSlider->setInvertedAppearance( true );
  mSlider->setPageStep( 1 );
  mSlider->setTracking( false );

  scaleChanged( mMapCanvas->scale() );

  mSlider->setEnabled( true );
  show();
}
void QgsRasterCalcDialog::insertAvailableRasterBands()
{
  const QMap<QString, QgsMapLayer *> &layers = QgsProject::instance()->mapLayers();
  QMap<QString, QgsMapLayer *>::const_iterator layerIt = layers.constBegin();

  for ( ; layerIt != layers.constEnd(); ++layerIt )
  {
    QgsRasterLayer *rlayer = dynamic_cast<QgsRasterLayer *>( layerIt.value() );
    if ( rlayer && rlayer->dataProvider() && rlayer->dataProvider()->name() == QLatin1String( "gdal" ) )
    {
      if ( !mExtentSizeSet ) //set bounding box / resolution of output to the values of the first possible input layer
      {
        setExtentSize( rlayer->width(), rlayer->height(), rlayer->extent() );
        mCrsSelector->setCrs( rlayer->crs() );
      }
      //get number of bands
      for ( int i = 0; i < rlayer->bandCount(); ++i )
      {
        QgsRasterCalculatorEntry entry;
        entry.raster = rlayer;
        entry.bandNumber = i + 1;
        entry.ref = rlayer->name() + '@' + QString::number( i + 1 );
        mAvailableRasterBands.push_back( entry );
        mRasterBandsListWidget->addItem( entry.ref );
      }
    }
  }
}
Example #4
0
QVector<QgsRasterCalculatorEntry> QgsRasterCalculatorEntry::rasterEntries()
{
  QVector<QgsRasterCalculatorEntry> availableEntries;
  const QMap<QString, QgsMapLayer *> &layers = QgsProject::instance()->mapLayers();

  auto uniqueRasterBandIdentifier = [ & ]( QgsRasterCalculatorEntry & entry ) -> bool
  {
    unsigned int i( 1 );
    entry.ref = QStringLiteral( "%1@%2" ).arg( entry.raster->name() ).arg( entry.bandNumber );
    while ( true )
    {
      bool unique( true );
      for ( const auto &ref : qgis::as_const( availableEntries ) )
      {
        // Safety belt
        if ( !( entry.raster && ref.raster ) )
          continue;
        // Check if a layer with the same data source was already added to the list
        if ( ref.raster->publicSource() == entry.raster->publicSource() )
          return false;
        // If same name but different source
        if ( ref.ref == entry.ref )
        {
          unique = false;
          entry.ref = QStringLiteral( "%1_%2@%3" ).arg( entry.raster->name() ).arg( i++ ).arg( entry.bandNumber );
        }
      }
      if ( unique )
        return true;
    }
  };

  QMap<QString, QgsMapLayer *>::const_iterator layerIt = layers.constBegin();
  for ( ; layerIt != layers.constEnd(); ++layerIt )
  {
    QgsRasterLayer *rlayer = qobject_cast<QgsRasterLayer *>( layerIt.value() );
    if ( rlayer && rlayer->dataProvider() && rlayer->dataProvider()->name() == QLatin1String( "gdal" ) )
    {
      //get number of bands
      for ( int i = 0; i < rlayer->bandCount(); ++i )
      {
        QgsRasterCalculatorEntry entry;
        entry.raster = rlayer;
        entry.bandNumber = i + 1;
        if ( ! uniqueRasterBandIdentifier( entry ) )
          continue;
        availableEntries.push_back( entry );
      }
    }
  }
  return availableEntries;
}
const QImage& QgsWMSLegendNode::getLegendGraphic() const
{
    if ( ! mValid && ! mFetcher )
    {
        // or maybe in presence of a downloader we should just delete it
        // and start a new one ?

        QgsRasterLayer* layer = qobject_cast<QgsRasterLayer*>( mLayerNode->layer() );
        const QgsLayerTreeModel* mod = model();
        if ( ! mod ) return mImage;
        const QgsMapSettings* ms = mod->legendFilterByMap();

        QgsRasterDataProvider* prov = layer->dataProvider();

        Q_ASSERT( ! mFetcher );
        mFetcher.reset( prov->getLegendGraphicFetcher( ms ) );
        if ( mFetcher )
        {
            connect( mFetcher.data(), SIGNAL( finish( const QImage& ) ), this, SLOT( getLegendGraphicFinished( const QImage& ) ) );
            connect( mFetcher.data(), SIGNAL( error( const QString& ) ), this, SLOT( getLegendGraphicErrored( const QString& ) ) );
            connect( mFetcher.data(), SIGNAL( progress( qint64, qint64 ) ), this, SLOT( getLegendGraphicProgress( qint64, qint64 ) ) );
            mFetcher->start();
        } // else QgsDebugMsg("XXX No legend supported ?");

    }
QImage QgsWmsLegendNode::getLegendGraphic() const
{
  if ( ! mValid && ! mFetcher )
  {
    // or maybe in presence of a downloader we should just delete it
    // and start a new one ?

    QgsRasterLayer *layer = qobject_cast<QgsRasterLayer *>( mLayerNode->layer() );
    const QgsLayerTreeModel *mod = model();
    if ( ! mod )
      return mImage;
    const QgsMapSettings *ms = mod->legendFilterMapSettings();

    QgsRasterDataProvider *prov = layer->dataProvider();
    if ( ! prov )
      return mImage;

    Q_ASSERT( ! mFetcher );
    mFetcher.reset( prov->getLegendGraphicFetcher( ms ) );
    if ( mFetcher )
    {
      connect( mFetcher.get(), &QgsImageFetcher::finish, this, &QgsWmsLegendNode::getLegendGraphicFinished );
      connect( mFetcher.get(), &QgsImageFetcher::error, this, &QgsWmsLegendNode::getLegendGraphicErrored );
      connect( mFetcher.get(), &QgsImageFetcher::progress, this, &QgsWmsLegendNode::getLegendGraphicProgress );
      mFetcher->start();
    } // else QgsDebugMsg("XXX No legend supported?");

  }

  return mImage;
}
void QgsZonalStatisticsDialog::insertAvailableLayers()
{
  //insert available raster layers
  //enter available layers into the combo box
  QMap<QString, QgsMapLayer*> mapLayers = QgsMapLayerRegistry::instance()->mapLayers();
  QMap<QString, QgsMapLayer*>::iterator layer_it = mapLayers.begin();

  for ( ; layer_it != mapLayers.end(); ++layer_it )
  {
    QgsRasterLayer* rl = dynamic_cast<QgsRasterLayer*>( layer_it.value() );
    if ( rl )
    {
      QgsRasterDataProvider* rp = rl->dataProvider();
      if ( rp && rp->name() == "gdal" )
      {
        mRasterLayerComboBox->addItem( rl->name(), QVariant( rl->id() ) );
      }
    }
    else
    {
      QgsVectorLayer* vl = dynamic_cast<QgsVectorLayer*>( layer_it.value() );
      if ( vl && vl->geometryType() == QGis::Polygon )
      {
        QgsVectorDataProvider* provider  = vl->dataProvider();
        if ( provider->capabilities() & QgsVectorDataProvider::AddAttributes )
        {
          mPolygonLayerComboBox->addItem( vl->name(), QVariant( vl->id() ) );
        }
      }
    }
  }
}
Example #8
0
void SWGISBrowser::updateCurrentTab()
{
    Tab currentTab = this->activeTab();
    if(currentTab == Metadata && this->m_DirtyMetadata)
    {
        if(this->m_Layer && this->m_Layer->isValid())
        {
            QString myStyle = QgsApplication::reportStyleSheet();
            ui->metaTextBrowser->document()->setDefaultStyleSheet(myStyle);
            ui->metaTextBrowser->setHtml(this->m_Layer->metadata());
        }
        else
            ui->metaTextBrowser->setHtml(QString());

        this->m_DirtyMetadata = false;
    }

    if(currentTab == Preview && this->m_DirtyPreview)
    {
        if (this->m_Layer && this->m_Layer->isValid())
        {
            // Create preview: add to map canvas
            QList<QgsMapCanvasLayer> layers;
            layers << QgsMapCanvasLayer( this->m_Layer );
            ui->mapCanvas->setLayerSet( layers );
            QgsRectangle fullExtent = this->m_Layer->extent();
            fullExtent.scale( 1.05 ); // add some border
            ui->mapCanvas->setExtent( fullExtent );
            ui->mapCanvas->refresh();

            QgsRasterLayer *rlayer = qobject_cast<QgsRasterLayer *>(this->m_Layer);
            if (rlayer)
            {
                connect(rlayer->dataProvider(), SIGNAL(dataChanged()), rlayer, SLOT(triggerRepaint()));
                connect(rlayer->dataProvider(), SIGNAL(dataChanged()), ui->mapCanvas, SLOT(refresh()));
            }
        }
        this->m_DirtyPreview = false;
    }

    if (currentTab == Attributes && this->m_DirtyAttributes)
    {
        if (this->m_Layer  && this->m_Layer->isValid() && this->m_Layer->type() == QgsMapLayer::VectorLayer)
        {
            QgsVectorLayer* vlayer = qobject_cast<QgsVectorLayer*>(this->m_Layer);
            QApplication::setOverrideCursor(Qt::WaitCursor);
            this->setLayer(vlayer);
            QApplication::restoreOverrideCursor();
        }
        else
        {
            this->setLayer(nullptr);
        }
        this->m_DirtyAttributes = false;
    }
}
bool QgsZonalHistogramAlgorithm::prepareAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback * )
{
  QgsRasterLayer *layer = parameterAsRasterLayer( parameters, QStringLiteral( "INPUT_RASTER" ), context );
  if ( !layer )
    throw QgsProcessingException( invalidRasterError( parameters, QStringLiteral( "INPUT_RASTER" ) ) );

  mRasterBand = parameterAsInt( parameters, QStringLiteral( "RASTER_BAND" ), context );
  mHasNoDataValue = layer->dataProvider()->sourceHasNoDataValue( mRasterBand );
  mNodataValue = layer->dataProvider()->sourceNoDataValue( mRasterBand );
  mRasterInterface.reset( layer->dataProvider()->clone() );
  mRasterExtent = layer->extent();
  mCrs = layer->crs();
  mCellSizeX = std::abs( layer->rasterUnitsPerPixelX() );
  mCellSizeY = std::abs( layer->rasterUnitsPerPixelX() );
  mNbCellsXProvider = mRasterInterface->xSize();
  mNbCellsYProvider = mRasterInterface->ySize();

  return true;
}
Example #10
0
void QgsRasterCalcDialog::insertAvailableRasterBands()
{
  mAvailableRasterBands = QgsRasterCalculatorEntry::rasterEntries().toList();
  mRasterBandsListWidget->clear();
  for ( const auto &entry : qgis::as_const( mAvailableRasterBands ) )
  {
    QgsRasterLayer *rlayer = entry.raster;
    if ( rlayer && rlayer->dataProvider() && rlayer->dataProvider()->name() == QLatin1String( "gdal" ) )
    {
      if ( !mExtentSizeSet ) //set bounding box / resolution of output to the values of the first possible input layer
      {
        setExtentSize( rlayer->width(), rlayer->height(), rlayer->extent() );
        mCrsSelector->setCrs( rlayer->crs() );
      }
      QListWidgetItem *item = new QListWidgetItem( entry.ref, mRasterBandsListWidget );
      item->setData( Qt::ToolTipRole, rlayer->publicSource() );
      mRasterBandsListWidget->addItem( item );
    }
  }
}
bool QgsReclassifyAlgorithmBase::prepareAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
{
  mDataType = QgsRasterAnalysisUtils::rasterTypeChoiceToDataType( parameterAsEnum( parameters, QStringLiteral( "DATA_TYPE" ), context ) );
  QgsRasterLayer *layer = parameterAsRasterLayer( parameters, QStringLiteral( "INPUT_RASTER" ), context );

  if ( !layer )
    throw QgsProcessingException( invalidRasterError( parameters, QStringLiteral( "INPUT_RASTER" ) ) );

  mBand = parameterAsInt( parameters, QStringLiteral( "RASTER_BAND" ), context );
  if ( mBand < 1 || mBand > layer->bandCount() )
    throw QgsProcessingException( QObject::tr( "Invalid band number for RASTER_BAND (%1): Valid values for input raster are 1 to %2" ).arg( mBand )
                                  .arg( layer->bandCount() ) );

  mInterface.reset( layer->dataProvider()->clone() );
  mExtent = layer->extent();
  mCrs = layer->crs();
  mRasterUnitsPerPixelX = std::abs( layer->rasterUnitsPerPixelX() );
  mRasterUnitsPerPixelY = std::abs( layer->rasterUnitsPerPixelY() );
  mNbCellsXProvider = mInterface->xSize();
  mNbCellsYProvider = mInterface->ySize();

  mNoDataValue = parameterAsDouble( parameters, QStringLiteral( "NO_DATA" ), context );
  mUseNoDataForMissingValues = parameterAsBool( parameters, QStringLiteral( "NODATA_FOR_MISSING" ), context );

  int boundsType = parameterAsEnum( parameters, QStringLiteral( "RANGE_BOUNDARIES" ), context );
  switch ( boundsType )
  {
    case 0:
      mBoundsType = QgsReclassifyUtils::RasterClass::IncludeMax;
      break;

    case 1:
      mBoundsType = QgsReclassifyUtils::RasterClass::IncludeMin;
      break;

    case 2:
      mBoundsType = QgsReclassifyUtils::RasterClass::IncludeMinAndMax;
      break;

    case 3:
      mBoundsType = QgsReclassifyUtils::RasterClass::Exclusive;
      break;
  }

  return _prepareAlgorithm( parameters, context, feedback );
}
void QgsLayerStylingWidget::updateCurrentWidgetLayer()
{
  if ( !mCurrentLayer )
    return;  // non-spatial are ignored in setLayer()

  mBlockAutoApply = true;

  whileBlocking( mLayerCombo )->setLayer( mCurrentLayer );

  int row = mOptionsListWidget->currentIndex().row();

  mStackedWidget->setCurrentIndex( mLayerPage );

  QgsPanelWidget *current = mWidgetStack->takeMainPanel();
  if ( current )
  {
    if ( QgsLabelingWidget *widget = qobject_cast<QgsLabelingWidget *>( current ) )
    {
      mLabelingWidget = widget;
    }
    else if ( QgsUndoWidget *widget = qobject_cast<QgsUndoWidget *>( current ) )
    {
      mUndoWidget = widget;
    }
    else if ( QgsRendererRasterPropertiesWidget *widget = qobject_cast<QgsRendererRasterPropertiesWidget *>( current ) )
    {
      mRasterStyleWidget = widget;
    }
#ifdef HAVE_3D
    else if ( QgsVectorLayer3DRendererWidget *widget = qobject_cast<QgsVectorLayer3DRendererWidget *>( current ) )
    {
      mVector3DWidget = widget;
    }
#endif

  }

  mWidgetStack->clear();
  // Create the user page widget if we are on one of those pages
  // TODO Make all widgets use this method.
  if ( mUserPages.contains( row ) )
  {
    QgsMapLayerConfigWidget *panel = mUserPages[row]->createWidget( mCurrentLayer, mMapCanvas, true, mWidgetStack );
    if ( panel )
    {
      connect( panel, &QgsPanelWidget::widgetChanged, this, &QgsLayerStylingWidget::autoApply );
      mWidgetStack->setMainPanel( panel );
    }
  }

  // The last widget is always the undo stack.
  if ( row == mOptionsListWidget->count() - 1 )
  {
    mWidgetStack->setMainPanel( mUndoWidget );
  }
  else if ( mCurrentLayer->type() == QgsMapLayer::VectorLayer )
  {
    QgsVectorLayer *vlayer = qobject_cast<QgsVectorLayer *>( mCurrentLayer );

    switch ( row )
    {
      case 0: // Style
      {
        QgsRendererPropertiesDialog *styleWidget = new QgsRendererPropertiesDialog( vlayer, QgsStyle::defaultStyle(), true, mStackedWidget );
        styleWidget->setMapCanvas( mMapCanvas );
        styleWidget->setDockMode( true );
        connect( styleWidget, &QgsRendererPropertiesDialog::widgetChanged, this, &QgsLayerStylingWidget::autoApply );
        QgsPanelWidgetWrapper *wrapper = new QgsPanelWidgetWrapper( styleWidget, mStackedWidget );
        wrapper->setDockMode( true );
        connect( styleWidget, &QgsRendererPropertiesDialog::showPanel, wrapper, &QgsPanelWidget::openPanel );
        mWidgetStack->setMainPanel( wrapper );
        break;
      }
      case 1: // Labels
      {
        if ( !mLabelingWidget )
        {
          mLabelingWidget = new QgsLabelingWidget( nullptr, mMapCanvas, mWidgetStack );
          mLabelingWidget->setDockMode( true );
          connect( mLabelingWidget, &QgsLabelingWidget::widgetChanged, this, &QgsLayerStylingWidget::autoApply );
        }
        mLabelingWidget->setLayer( vlayer );
        mWidgetStack->setMainPanel( mLabelingWidget );
        break;
      }
#ifdef HAVE_3D
      case 2:  // 3D View
      {
        if ( !mVector3DWidget )
        {
          mVector3DWidget = new QgsVectorLayer3DRendererWidget( nullptr, mMapCanvas, mWidgetStack );
          mVector3DWidget->setDockMode( true );
          connect( mVector3DWidget, &QgsVectorLayer3DRendererWidget::widgetChanged, this, &QgsLayerStylingWidget::autoApply );
        }
        mVector3DWidget->setLayer( vlayer );
        mWidgetStack->setMainPanel( mVector3DWidget );
        break;
      }
#endif
      default:
        break;
    }
  }
  else if ( mCurrentLayer->type() == QgsMapLayer::RasterLayer )
  {
    QgsRasterLayer *rlayer = qobject_cast<QgsRasterLayer *>( mCurrentLayer );
    bool hasMinMaxCollapsedState = false;
    bool minMaxCollapsed = false;

    switch ( row )
    {
      case 0: // Style
      {
        // Backup collapsed state of min/max group so as to restore it
        // on the new widget.
        if ( mRasterStyleWidget )
        {
          QgsRasterRendererWidget *currentRenderWidget = mRasterStyleWidget->currentRenderWidget();
          if ( currentRenderWidget )
          {
            QgsRasterMinMaxWidget *mmWidget = currentRenderWidget->minMaxWidget();
            if ( mmWidget )
            {
              hasMinMaxCollapsedState = true;
              minMaxCollapsed = mmWidget->isCollapsed();
            }
          }
        }
        mRasterStyleWidget = new QgsRendererRasterPropertiesWidget( rlayer, mMapCanvas, mWidgetStack );
        if ( hasMinMaxCollapsedState )
        {
          QgsRasterRendererWidget *currentRenderWidget = mRasterStyleWidget->currentRenderWidget();
          if ( currentRenderWidget )
          {
            QgsRasterMinMaxWidget *mmWidget = currentRenderWidget->minMaxWidget();
            if ( mmWidget )
            {
              mmWidget->setCollapsed( minMaxCollapsed );
            }
          }
        }
        mRasterStyleWidget->setDockMode( true );
        connect( mRasterStyleWidget, &QgsPanelWidget::widgetChanged, this, &QgsLayerStylingWidget::autoApply );
        mWidgetStack->setMainPanel( mRasterStyleWidget );
        break;
      }

      case 1: // Transparency
      {
        QgsRasterTransparencyWidget *transwidget = new QgsRasterTransparencyWidget( rlayer, mMapCanvas, mWidgetStack );
        transwidget->setDockMode( true );
        connect( transwidget, &QgsPanelWidget::widgetChanged, this, &QgsLayerStylingWidget::autoApply );
        mWidgetStack->setMainPanel( transwidget );
        break;
      }
      case 2: // Histogram
      {
        if ( rlayer->dataProvider()->capabilities() & QgsRasterDataProvider::Size )
        {
          if ( !mRasterStyleWidget )
          {
            mRasterStyleWidget = new QgsRendererRasterPropertiesWidget( rlayer, mMapCanvas, mWidgetStack );
            mRasterStyleWidget->syncToLayer( rlayer );
          }
          connect( mRasterStyleWidget, &QgsPanelWidget::widgetChanged, this, &QgsLayerStylingWidget::autoApply );

          QgsRasterHistogramWidget *widget = new QgsRasterHistogramWidget( rlayer, mWidgetStack );
          connect( widget, &QgsPanelWidget::widgetChanged, this, &QgsLayerStylingWidget::autoApply );
          QString name = mRasterStyleWidget->currentRenderWidget()->renderer()->type();
          widget->setRendererWidget( name, mRasterStyleWidget->currentRenderWidget() );
          widget->setDockMode( true );

          mWidgetStack->setMainPanel( widget );
        }
        break;
      }
      default:
        break;
    }
  }
  else
  {
    mStackedWidget->setCurrentIndex( mNotSupportedPage );
  }

  mBlockAutoApply = false;
}
Example #13
0
QByteArray* QgsWCSServer::getCoverage()
{
  QStringList wcsLayersId = mConfigParser->wcsLayers();

  QList<QgsMapLayer*> layerList;

  QStringList mErrors = QStringList();

  //defining coverage name
  QString coveName = "";
  //read COVERAGE
  QMap<QString, QString>::const_iterator cove_name_it = mParameters.find( "COVERAGE" );
  if ( cove_name_it != mParameters.end() )
  {
    coveName = cove_name_it.value();
  }
  if ( coveName == "" )
  {
    QMap<QString, QString>::const_iterator cove_name_it = mParameters.find( "IDENTIFIER" );
    if ( cove_name_it != mParameters.end() )
    {
      coveName = cove_name_it.value();
    }
  }

  if ( coveName == "" )
  {
    mErrors << QString( "COVERAGE is mandatory" );
  }

  layerList = mConfigParser->mapLayerFromCoverage( coveName );
  if ( layerList.size() < 1 )
  {
    mErrors << QString( "The layer for the COVERAGE '%1' is not found" ).arg( coveName );
  }

  bool conversionSuccess;
  // BBOX
  bool bboxOk = false;
  double minx = 0.0, miny = 0.0, maxx = 0.0, maxy = 0.0;
  // WIDTh and HEIGHT
  int width = 0, height = 0;
  // CRS
  QString crs = "";

  // read BBOX
  QMap<QString, QString>::const_iterator bbIt = mParameters.find( "BBOX" );
  if ( bbIt == mParameters.end() )
  {
    minx = 0; miny = 0; maxx = 0; maxy = 0;
  }
  else
  {
    bboxOk = true;
    QString bbString = bbIt.value();
    minx = bbString.section( ",", 0, 0 ).toDouble( &conversionSuccess );
    if ( !conversionSuccess ) {bboxOk = false;}
    miny = bbString.section( ",", 1, 1 ).toDouble( &conversionSuccess );
    if ( !conversionSuccess ) {bboxOk = false;}
    maxx = bbString.section( ",", 2, 2 ).toDouble( &conversionSuccess );
    if ( !conversionSuccess ) {bboxOk = false;}
    maxy = bbString.section( ",", 3, 3 ).toDouble( &conversionSuccess );
    if ( !conversionSuccess ) {bboxOk = false;}
  }
  if ( !bboxOk )
  {
    mErrors << QString( "The BBOX is mandatory and has to be xx.xxx,yy.yyy,xx.xxx,yy.yyy" );
  }

  // read WIDTH
  width = mParameters.value( "WIDTH", "0" ).toInt( &conversionSuccess );
  if ( !conversionSuccess )
    width = 0;
  // read HEIGHT
  height = mParameters.value( "HEIGHT", "0" ).toInt( &conversionSuccess );
  if ( !conversionSuccess )
  {
    height = 0;
  }

  if ( width < 0 || height < 0 )
  {
    mErrors << QString( "The WIDTH and HEIGHT are mandatory and have to be integer" );
  }

  crs = mParameters.value( "CRS", "" );
  if ( crs == "" )
  {
    mErrors << QString( "The CRS is mandatory" );
  }

  if ( mErrors.count() != 0 )
  {
    throw QgsMapServiceException( "RequestNotWellFormed", mErrors.join( ". " ) );
  }

  QgsCoordinateReferenceSystem requestCRS = QgsCRSCache::instance()->crsByAuthId( crs );
  if ( !requestCRS.isValid() )
  {
    mErrors << QString( "Could not create request CRS" );
    throw QgsMapServiceException( "RequestNotWellFormed", mErrors.join( ". " ) );
  }

  QgsRectangle rect( minx, miny, maxx, maxy );

  QgsMapLayer* layer = layerList.at( 0 );
  QgsRasterLayer* rLayer = dynamic_cast<QgsRasterLayer*>( layer );
  if ( rLayer && wcsLayersId.contains( rLayer->id() ) )
  {
    // RESPONSE_CRS
    QgsCoordinateReferenceSystem responseCRS = rLayer->crs();
    crs = mParameters.value( "RESPONSE_CRS", "" );
    if ( crs != "" )
    {
      responseCRS = QgsCRSCache::instance()->crsByAuthId( crs );
      if ( !responseCRS.isValid() )
      {
        responseCRS = rLayer->crs();
      }
    }

    // transform rect
    if ( requestCRS != rLayer->crs() )
    {
      QgsCoordinateTransform t( requestCRS, rLayer->crs() );
      rect = t.transformBoundingBox( rect );
    }

    QTemporaryFile tempFile;
    tempFile.open();
    QgsRasterFileWriter fileWriter( tempFile.fileName() );

    // clone pipe/provider
    QgsRasterPipe* pipe = new QgsRasterPipe();
    if ( !pipe->set( rLayer->dataProvider()->clone() ) )
    {
      mErrors << QString( "Cannot set pipe provider" );
      throw QgsMapServiceException( "RequestNotWellFormed", mErrors.join( ". " ) );
    }

    // add projector if necessary
    if ( responseCRS != rLayer->crs() )
    {
      QgsRasterProjector * projector = new QgsRasterProjector;
      projector->setCRS( rLayer->crs(), responseCRS );
      if ( !pipe->insert( 2, projector ) )
      {
        mErrors << QString( "Cannot set pipe projector" );
        throw QgsMapServiceException( "RequestNotWellFormed", mErrors.join( ". " ) );
      }
    }

    QgsRasterFileWriter::WriterError err = fileWriter.writeRaster( pipe, width, height, rect, responseCRS );
    if ( err != QgsRasterFileWriter::NoError )
    {
      mErrors << QString( "Cannot write raster error code: %1" ).arg( err );
      throw QgsMapServiceException( "RequestNotWellFormed", mErrors.join( ". " ) );
    }
    delete pipe;
    QByteArray* ba = 0;
    ba = new QByteArray();
    *ba = tempFile.readAll();

    return ba;
  }
  return 0;
}
void TestQgsWcsPublicServers::test( )
{
  QStringList versions;
  // It may happen that server supports 1.1.1, but does not accept 1.1 (http://zeus.pin.unifi.it/gi-wcs/http)
  versions << "" << "1.0.0" << "1.1.0"; // empty for default
  QStringList servers;
  // Some (first) coverages do not advertize any supportedCRS and sever gives
  // error both with native CRS (EPSG::561005) and EPSG:4326
  // MOD* coverages work OK
  servers << "http://argon.geogr.uni-jena.de:8080/geoserver/ows";
  servers << "http://demo.geonode.org/geoserver/wcs";
  servers << "http://demo.mapserver.org/cgi-bin/wcs";
  servers << "http://demo.opengeo.org/geoserver/wcs";
  // geobrain.laits.gmu.edu servers are quite slow
  servers << "http://geobrain.laits.gmu.edu/cgi-bin/gbwcs-dem";
  servers << "http://geobrain.laits.gmu.edu/cgi-bin/ows8/wcseo";
  servers << "http://geobrain.laits.gmu.edu/cgi-bin/wcs110";
  servers << "http://geobrain.laits.gmu.edu/cgi-bin/wcs-all";
  servers << "http://iceds.ge.ucl.ac.uk/cgi-bin/icedswcs";
  servers << "http://motherlode.ucar.edu:8080/thredds/wcs/fmrc/NCEP/DGEX/Alaska_12km/NCEP-DGEX-Alaska_12km_best.ncd";
  servers << "http://navigator.state.or.us/ArcGIS/services/Framework/Imagery_Mosaic2009/ImageServer/WCSServer";
  servers << "http://nsidc.org/cgi-bin/atlas_north";
  servers << "http://sedac.ciesin.columbia.edu/geoserver/wcs";
  // Big and slow
  //servers << "http://webmap.ornl.gov/ogcbroker/wcs";
  servers << "http://ws.csiss.gmu.edu/cgi-bin/wcs-t";
  // Big and slow
  //servers << "http://ws.laits.gmu.edu/cgi-bin/wcs-all";
  // Currently very slow or down
  //servers << "http://www.sogeo.ch/geoserver/wcs";
  // Slow and erroneous
  //servers << "http://zeus.pin.unifi.it/gi-wcs/http";

  foreach ( QString server, servers )
  {
    QStringList myServerLog;
    myServerLog << "server:" + server;
    QString myServerDirName = server;
    myServerDirName.replace( QRegExp( "[:/]+" ), "." );
    myServerDirName.replace( QRegExp( "\\.$" ), "" );
    QgsDebugMsg( "myServerDirName = " + myServerDirName );

    QDir myServerDir( mCacheDir.absolutePath() + QDir::separator() + myServerDirName );
    QString myServerLogPath = myServerDir.absolutePath() + QDir::separator() + "server.log";
    if ( QFileInfo( myServerLogPath ).exists() )
    {
      QgsDebugMsg( "cache exists " + myServerDir.absolutePath() );
      continue;
    }

    if ( !myServerDir.exists() )
    {
      mCacheDir.mkdir( myServerDirName );
    }

    foreach ( QString version, versions )
    {
      QgsDebugMsg( "server: " + server + " version: " + version );

      QgsDataSourceURI myServerUri;

      myServerUri.setParam( "url", server );
      if ( !version.isEmpty() )
      {
        myServerUri.setParam( "version", version );
      }

      QgsWcsCapabilities myCapabilities;
      myCapabilities.setUri( myServerUri );

      if ( !myCapabilities.lastError().isEmpty() )
      {
        QgsDebugMsg( myCapabilities.lastError() );
        myServerLog << "error: (version: " + version + ") " +  myCapabilities.lastError().replace( "\n", " " );
        continue;
      }

      QVector<QgsWcsCoverageSummary> myCoverages;
      if ( !myCapabilities.supportedCoverages( myCoverages ) )
      {
        QgsDebugMsg( "Cannot get list of coverages" );
        myServerLog << "error: (version: " + version + ") Cannot get list of coverages";
        continue;
      }

      int myCoverageCount = 0;
      int myStep = myCoverages.size() / mMaxCoverages;
      int myStepCount = -1;
      foreach ( QgsWcsCoverageSummary myCoverage, myCoverages )
      {
        QgsDebugMsg( "coverage: " + myCoverage.identifier );
        // Go in steps to get more success/errors
        if ( myStepCount == -1 || myStepCount > myStep )
        {
          myStepCount = 0;
        }
        else
        {
          myStepCount++;
          continue;
        }

        myCoverageCount++;
        if ( myCoverageCount > mMaxCoverages ) break;

        QString myPath = myServerDir.absolutePath() + QDir::separator() + myCoverage.identifier;

        if ( !version.isEmpty() )
        {
          myPath += "-" + version;
        }
        QString myLogPath = myPath + ".log";

        if ( QFileInfo( myLogPath ).exists() )
        {
          QMap<QString, QString> log = readLog( myLogPath );
          if ( !log.value( "identifier" ).isEmpty() && log.value( "error" ).isEmpty() ) continue;
        }

        QStringList myLog;
        myLog << "identifier:" + myCoverage.identifier;
        myCapabilities.describeCoverage( myCoverage.identifier );
        myCoverage = myCapabilities.coverage( myCoverage.identifier ); // get described
        QgsDataSourceURI myUri = myServerUri;
        myUri.setParam( "identifier", myCoverage.identifier );
        if ( myCoverage.times.size() > 0 )
        {
          myUri.setParam( "time", myCoverage.times.value( 0 ) );
        }
        myLog << "version:" + version;
        myLog << "uri:" + myUri.encodedUri();

        int myWidth = 100;
        int myHeight = 100;
        if ( myCoverage.hasSize )
        {
          myHeight = static_cast<int>( qRound( 1.0 * myWidth * myCoverage.height / myCoverage.width ) );
        }
        myLog << QString( "hasSize:%1" ).arg( myCoverage.hasSize );

        QgsRasterLayer * myLayer = new QgsRasterLayer( myUri.encodedUri(), myCoverage.identifier, "wcs", true );
        if ( myLayer->isValid() )
        {
          int myBandCount = myLayer->dataProvider()->bandCount();
          myLog << "bandCount:" + QString::number( myBandCount );
          if ( myBandCount > 0 )
          {
            myLog << "srcType:" + QString::number( myLayer->dataProvider()->srcDataType( 1 ) );

            QgsRasterBandStats myStats = myLayer->dataProvider()->bandStatistics( 1, QgsRasterBandStats::All, QgsRectangle(), myWidth * myHeight );
            myLog << "min:" + QString::number( myStats.minimumValue );
            myLog << "max:" + QString::number( myStats.maximumValue );
          }

          QgsMapRenderer myMapRenderer;
          QList<QgsMapLayer *> myLayersList;

          myLayersList.append( myLayer );
          QgsMapLayerRegistry::instance()->addMapLayers( myLayersList, false );

          QMap<QString, QgsMapLayer*> myLayersMap = QgsMapLayerRegistry::instance()->mapLayers();

          myMapRenderer.setLayerSet( myLayersMap.keys() );

          myMapRenderer.setExtent( myLayer->extent() );

          QImage myImage( myWidth, myHeight, QImage::Format_ARGB32_Premultiplied );
          myImage.fill( 0 );

          myMapRenderer.setOutputSize( QSize( myWidth, myHeight ), myImage.logicalDpiX() );

          QPainter myPainter( &myImage );
          myMapRenderer.render( &myPainter );

          // Save rendered image
          QString myPngPath = myPath + ".png";
          QgsDebugMsg( "myPngPath = " + myPngPath );
          myImage.save( myPngPath );

          // Verify data
          QSet<QString> myValues; // cannot be QSet<double>
          void *myData = myLayer->dataProvider()->readBlock( 1, myLayer->extent(), myWidth, myHeight );
          if ( myData )
          {
            int myType = myLayer->dataProvider()->dataType( 1 );
            for ( int row = 0; row < myHeight; row++ )
            {
              for ( int col = 0; col < myWidth; col++ )
              {
                double value = myLayer->dataProvider()->readValue( myData, myType, row * myWidth + col );
                QString valueStr = QString::number( value );
                if ( !myValues.contains( valueStr ) ) myValues.insert( valueStr );
              }
            }
            free( myData );
          }
          QgsDebugMsg( QString( "%1 values" ).arg( myValues.size() ) );
          myLog << QString( "valuesCount:%1" ).arg( myValues.size() );

          // Verify image colors
          QSet<QRgb> myColors;
          for ( int row = 0; row < myHeight; row++ )
          {
            for ( int col = 0; col < myWidth; col++ )
            {
              QRgb color = myImage.pixel( col, row );
              if ( !myColors.contains( color ) ) myColors.insert( color );
            }
          }
          QgsDebugMsg( QString( "%1 colors" ).arg( myColors.size() ) );
          myLog << QString( "colorsCount:%1" ).arg( myColors.size() );
        }
        else
        {
          QgsDebugMsg( "Layer is not valid" );
          myLog << "error:Layer is not valid";
        }

        QFile myLogFile( myLogPath );
        myLogFile.open( QIODevice::WriteOnly | QIODevice::Text );
        QTextStream myStream( &myLogFile );
        myStream << myLog.join( "\n" );

        myLogFile.close();
        QgsMapLayerRegistry::instance()->removeAllMapLayers();
      }