예제 #1
0
bool QgsRasterCalcNode::calculate( QMap<QString, QgsRasterMatrix*>& rasterData, QgsRasterMatrix& result ) const
{
  //deprecated method
  //convert QgsRasterMatrix to QgsRasterBlock and call replacement method
  QMap<QString, QgsRasterBlock* > rasterBlockData;
  QMap<QString, QgsRasterMatrix*>::const_iterator it = rasterData.constBegin();
  for ( ; it != rasterData.constEnd(); ++it )
  {
    QgsRasterBlock* block = new QgsRasterBlock( QGis::Float32, it.value()->nColumns(), it.value()->nRows(), it.value()->nodataValue() );
    for ( int row = 0; row < it.value()->nRows(); ++row )
    {
      for ( int col = 0; col < it.value()->nColumns(); ++col )
      {
        block->setValue( row, col, it.value()->data()[ row * it.value()->nColumns() + col ] );
      }
    }
    rasterBlockData.insert( it.key(), block );
  }

  return calculate( rasterBlockData, result );
}
예제 #2
0
QgsRasterBlock * QgsRasterNuller::block( int bandNo, QgsRectangle  const & extent, int width, int height )
{
  QgsDebugMsg( "Entered" );
  QgsRasterBlock *outputBlock = new QgsRasterBlock();
  if ( !mInput )
  {
    return outputBlock;
  }

  //void * rasterData = mInput->block( bandNo, extent, width, height );
  QgsRasterBlock *inputBlock = mInput->block( bandNo, extent, width, height );

  // Input may be without no data value
  //double noDataValue = mInput->noDataValue( bandNo );
  double noDataValue = mOutputNoData;

  for ( int i = 0; i < height; i++ )
  {
    for ( int j = 0; j < width; j++ )
    {
      //int index = i * width + j;

      //double value = readValue( rasterData, dataType, index );
      double value = inputBlock->value( i, j );

      foreach ( NoData noData, mNoData )
      {
        if (( value >= noData.min && value <= noData.max ) ||
            doubleNear( value, noData.min ) ||
            doubleNear( value, noData.max ) )
        {
          inputBlock->setValue( i, j, noDataValue );
        }
      }
    }
  }

  return inputBlock;
}
예제 #3
0
bool QgsGrassRasterImport::import()
{
  QgsDebugMsg( "entered" );
  if ( !mPipe )
  {
    setError( "Pipe is null." );
    return false;
  }

  QgsRasterDataProvider * provider = mPipe->provider();
  if ( !provider )
  {
    setError( "Pipe has no provider." );
    return false;
  }

  if ( !provider->isValid() )
  {
    setError( "Provider is not valid." );
    return false;
  }

  int redBand = 0;
  int greenBand = 0;
  int blueBand = 0;
  for ( int band = 1; band <= provider->bandCount(); band++ )
  {
    QgsDebugMsg( QString( "band = %1" ).arg( band ) );
    int colorInterpretation = provider->colorInterpretation( band );
    if ( colorInterpretation ==  QgsRaster::RedBand )
    {
      redBand = band;
    }
    else if ( colorInterpretation ==  QgsRaster::GreenBand )
    {
      greenBand = band;
    }
    else if ( colorInterpretation ==  QgsRaster::BlueBand )
    {
      blueBand = band;
    }

    QGis::DataType qgis_out_type = QGis::UnknownDataType;
    RASTER_MAP_TYPE data_type = -1;
    switch ( provider->dataType( band ) )
    {
      case QGis::Byte:
      case QGis::UInt16:
      case QGis::Int16:
      case QGis::UInt32:
      case QGis::Int32:
        qgis_out_type = QGis::Int32;
        break;
      case QGis::Float32:
        qgis_out_type = QGis::Float32;
        break;
      case QGis::Float64:
        qgis_out_type = QGis::Float64;
        break;
      case QGis::ARGB32:
      case QGis::ARGB32_Premultiplied:
        qgis_out_type = QGis::Int32;  // split to multiple bands?
        break;
      case QGis::CInt16:
      case QGis::CInt32:
      case QGis::CFloat32:
      case QGis::CFloat64:
      case QGis::UnknownDataType:
        setError( tr( "Data type %1 not supported" ).arg( provider->dataType( band ) ) );
        return false;
    }

    QgsDebugMsg( QString( "data_type = %1" ).arg( data_type ) );

    QString module = QgsGrass::qgisGrassModulePath() + "/qgis.r.in";
    QStringList arguments;
    QString name = mGrassObject.name();
    if ( provider->bandCount() > 1 )
    {
      // raster.<band> to keep in sync with r.in.gdal
      name += QString( ".%1" ).arg( band );
    }
    arguments.append( "output=" + name );    // get list of all output names
    QTemporaryFile gisrcFile;
    QProcess* process = 0;
    try
    {
      process = QgsGrass::startModule( mGrassObject.gisdbase(), mGrassObject.location(), mGrassObject.mapset(), module, arguments, gisrcFile );
    }
    catch ( QgsGrass::Exception &e )
    {
      setError( e.what() );
      return false;
    }

    QDataStream outStream( process );

    outStream << mExtent << ( qint32 )mXSize << ( qint32 )mYSize;
    outStream << ( qint32 )qgis_out_type;

    // calculate reasonable block size (5MB)
    int maximumTileHeight = 5000000 / mXSize;
    maximumTileHeight = std::max( 1, maximumTileHeight );
    // smaller if reprojecting so that it can be canceled quickly
    if ( mPipe->projector() )
    {
      maximumTileHeight = std::max( 1, 100000 / mXSize );
    }

    QgsRasterIterator iter( mPipe->last() );
    iter.setMaximumTileWidth( mXSize );
    iter.setMaximumTileHeight( maximumTileHeight );

    iter.startRasterRead( band, mXSize, mYSize, mExtent );

    int iterLeft = 0;
    int iterTop = 0;
    int iterCols = 0;
    int iterRows = 0;
    QgsRasterBlock* block = 0;
    process->setReadChannel( QProcess::StandardOutput );
    while ( iter.readNextRasterPart( band, iterCols, iterRows, &block, iterLeft, iterTop ) )
    {
      for ( int row = 0; row < iterRows; row++ )
      {
        if ( !block->convert( qgis_out_type ) )
        {
          setError( tr( "Cannot convert block (%1) to data type %2" ).arg( block->toString() ).arg( qgis_out_type ) );
          delete block;
          return false;
        }
        // prepare null values
        double noDataValue;
        if ( block->hasNoDataValue() )
        {
          noDataValue = block->noDataValue();
        }
        else
        {
          switch ( qgis_out_type )
          {
            case QGis::Int32:
              noDataValue = -2147483648.0;
              break;
            case QGis::Float32:
              noDataValue = std::numeric_limits<float>::max() * -1.0;
              break;
            case QGis::Float64:
              noDataValue = std::numeric_limits<double>::max() * -1.0;
              break;
            default: // should not happen
              noDataValue = std::numeric_limits<double>::max() * -1.0;
          }
          for ( qgssize i = 0; i < ( qgssize )block->width()*block->height(); i++ )
          {
            if ( block->isNoData( i ) )
            {
              block->setValue( i, noDataValue );
            }
          }
        }

        char * data = block->bits( row, 0 );
        int size = iterCols * block->dataTypeSize();
        QByteArray byteArray = QByteArray::fromRawData( data, size ); // does not copy data and does not take ownership
        if ( isCanceled() )
        {
          outStream << true; // cancel module
          break;
        }
        outStream << false; // not canceled
        outStream << noDataValue;

        outStream << byteArray;

        // Without waitForBytesWritten() it does not finish ok on Windows (process timeout)
        process->waitForBytesWritten( -1 );

#ifndef Q_OS_WIN
        // wait until the row is written to allow quick cancel (don't send data to buffer)
        process->waitForReadyRead();
        bool result;
        outStream >> result;
#endif
      }
      delete block;
      if ( isCanceled() )
      {
        outStream << true; // cancel module
        break;
      }
    }

    // TODO: send something back from module and read it here to close map correctly in module

    process->closeWriteChannel();
    // TODO: best timeout?
    process->waitForFinished( 30000 );

    QString stdoutString = process->readAllStandardOutput().data();
    QString stderrString = process->readAllStandardError().data();

    QString processResult = QString( "exitStatus=%1, exitCode=%2, error=%3, errorString=%4 stdout=%5, stderr=%6" )
                            .arg( process->exitStatus() ).arg( process->exitCode() )
                            .arg( process->error() ).arg( process->errorString() )
                            .arg( stdoutString.replace( "\n", ", " ) ).arg( stderrString.replace( "\n", ", " ) );
    QgsDebugMsg( "processResult: " + processResult );

    if ( process->exitStatus() != QProcess::NormalExit )
    {
      setError( process->errorString() );
      delete process;
      return false;
    }

    if ( process->exitCode() != 0 )
    {
      setError( stderrString );
      delete process;
      return false;
    }

    delete process;
  }
  QgsDebugMsg( QString( "redBand = %1 greenBand = %2 blueBand = %3" ).arg( redBand ).arg( greenBand ).arg( blueBand ) );
  if ( redBand > 0 && greenBand > 0 && blueBand > 0 )
  {
    // TODO: check if the group exists
    // I_find_group()
    QString name = mGrassObject.name();

    G_TRY
    {
      QgsGrass::setMapset( mGrassObject.gisdbase(), mGrassObject.location(), mGrassObject.mapset() );
      struct Ref ref;
      I_get_group_ref( name.toUtf8().data(), &ref );
      QString redName = name + QString( ".%1" ).arg( redBand );
      QString greenName = name + QString( ".%1" ).arg( greenBand );
      QString blueName = name + QString( ".%1" ).arg( blueBand );
      I_add_file_to_group_ref( redName.toUtf8().data(), mGrassObject.mapset().toUtf8().data(), &ref );
      I_add_file_to_group_ref( greenName.toUtf8().data(), mGrassObject.mapset().toUtf8().data(), &ref );
      I_add_file_to_group_ref( blueName.toUtf8().data(), mGrassObject.mapset().toUtf8().data(), &ref );
      I_put_group_ref( name.toUtf8().data(), &ref );
    }
    G_CATCH( QgsGrass::Exception &e )
    {
      QgsDebugMsg( QString( "Cannot create group: %1" ).arg( e.what() ) );
    }
예제 #4
0
QgsRasterBlock * QgsRasterNuller::block( int bandNo, QgsRectangle  const & extent, int width, int height )
{
  QgsDebugMsg( "Entered" );
  if ( !mInput )
  {
    return new QgsRasterBlock();
  }

  QgsRasterBlock *inputBlock = mInput->block( bandNo, extent, width, height );
  if ( !inputBlock )
  {
    return new QgsRasterBlock();
  }

  // We don't support nuller for color types
  if ( QgsRasterBlock::typeIsColor( inputBlock->dataType() ) )
  {
    return inputBlock;
  }

  QgsRasterBlock *outputBlock = 0;

  if ( mHasOutputNoData.value( bandNo - 1 ) || inputBlock->hasNoDataValue() )
  {
    double noDataValue;
    if ( mHasOutputNoData.value( bandNo - 1 ) )
    {
      noDataValue = mOutputNoData.value( bandNo - 1 );
    }
    else
    {
      noDataValue = inputBlock->noDataValue();
    }
    outputBlock = new QgsRasterBlock( inputBlock->dataType(), width, height, noDataValue );
  }
  else
  {
    outputBlock = new QgsRasterBlock( inputBlock->dataType(), width, height );
  }

  for ( int i = 0; i < height; i++ )
  {
    for ( int j = 0; j < width; j++ )
    {
      double value = inputBlock->value( i, j );

      bool isNoData = inputBlock->isNoData( i, j );
      if ( QgsRasterRange::contains( value, mNoData.value( bandNo - 1 ) ) )
      {
        isNoData = true;
      }
      outputBlock->setValue( i, j, inputBlock->value( i, j ) );
      if ( isNoData )
      {
        outputBlock->setIsNoData( i, j );
      }
      else
      {
        outputBlock->setValue( i, j, value );
      }
    }
  }
  delete inputBlock;

  return outputBlock;
}
QgsRasterBlock * QgsRasterDataProvider::block( int theBandNo, QgsRectangle  const & theExtent, int theWidth, int theHeight )
{
  QgsDebugMsg( QString( "theBandNo = %1 theWidth = %2 theHeight = %3" ).arg( theBandNo ).arg( theWidth ).arg( theHeight ) );
  QgsDebugMsg( QString( "theExtent = %1" ).arg( theExtent.toString() ) );

  QgsRasterBlock *block = new QgsRasterBlock( dataType( theBandNo ), theWidth, theHeight, noDataValue( theBandNo ) );

  if ( block->isEmpty() )
  {
    QgsDebugMsg( "Couldn't create raster block" );
    return block;
  }

  // Read necessary extent only
  QgsRectangle tmpExtent = extent().intersect( &theExtent );

  if ( tmpExtent.isEmpty() )
  {
    QgsDebugMsg( "Extent outside provider extent" );
    block->setIsNoData();
    return block;
  }

  double xRes = theExtent.width() / theWidth;
  double yRes = theExtent.height() / theHeight;
  double tmpXRes, tmpYRes;
  double providerXRes = 0;
  double providerYRes = 0;
  if ( capabilities() & ExactResolution )
  {
    providerXRes = extent().width() / xSize();
    providerYRes = extent().height() / ySize();
    tmpXRes = qMax( providerXRes, xRes );
    tmpYRes = qMax( providerYRes, yRes );
    if ( doubleNear( tmpXRes, xRes ) ) tmpXRes = xRes;
    if ( doubleNear( tmpYRes, yRes ) ) tmpYRes = yRes;
  }
  else
  {
    tmpXRes = xRes;
    tmpYRes = yRes;
  }

  if ( tmpExtent != theExtent ||
       tmpXRes > xRes || tmpYRes > yRes )
  {
    // Read smaller extent or lower resolution

    // Calculate row/col limits (before tmpExtent is aligned)
    int fromRow = qRound(( theExtent.yMaximum() - tmpExtent.yMaximum() ) / yRes );
    int toRow = qRound(( theExtent.yMaximum() - tmpExtent.yMinimum() ) / yRes ) - 1;
    int fromCol = qRound(( tmpExtent.xMinimum() - theExtent.xMinimum() ) / xRes ) ;
    int toCol = qRound(( tmpExtent.xMaximum() - theExtent.xMinimum() ) / xRes ) - 1;

    QgsDebugMsg( QString( "fromRow = %1 toRow = %2 fromCol = %3 toCol = %4" ).arg( fromRow ).arg( toRow ).arg( fromCol ).arg( toCol ) );

    if ( fromRow < 0 || fromRow >= theHeight || toRow < 0 || toRow >= theHeight ||
         fromCol < 0 || fromCol >= theWidth || toCol < 0 || toCol >= theWidth )
    {
      // Should not happen
      QgsDebugMsg( "Row or column limits out of range" );
      return block;
    }

    // If lower source resolution is used, the extent must beS aligned to original
    // resolution to avoid possible shift due to resampling
    if ( tmpXRes > xRes )
    {
      int col = floor(( tmpExtent.xMinimum() - extent().xMinimum() ) / providerXRes );
      tmpExtent.setXMinimum( extent().xMinimum() + col * providerXRes );
      col = ceil(( tmpExtent.xMaximum() - extent().xMinimum() ) / providerXRes );
      tmpExtent.setXMaximum( extent().xMinimum() + col * providerXRes );
    }
    if ( tmpYRes > yRes )
    {
      int row = floor(( extent().yMaximum() - tmpExtent.yMaximum() ) / providerYRes );
      tmpExtent.setYMaximum( extent().yMaximum() - row * providerYRes );
      row = ceil(( extent().yMaximum() - tmpExtent.yMinimum() ) / providerYRes );
      tmpExtent.setYMinimum( extent().yMaximum() - row * providerYRes );
    }
    int tmpWidth = qRound( tmpExtent.width() / tmpXRes );
    int tmpHeight = qRound( tmpExtent.height() / tmpYRes );
    tmpXRes = tmpExtent.width() / tmpWidth;
    tmpYRes = tmpExtent.height() / tmpHeight;

    QgsDebugMsg( QString( "Reading smaller block tmpWidth = %1 theHeight = %2" ).arg( tmpWidth ).arg( tmpHeight ) );
    QgsDebugMsg( QString( "tmpExtent = %1" ).arg( tmpExtent.toString() ) );

    block->setIsNoData();

    QgsRasterBlock *tmpBlock = new QgsRasterBlock( dataType( theBandNo ), tmpWidth, tmpHeight, noDataValue( theBandNo ) );

    readBlock( theBandNo, tmpExtent, tmpWidth, tmpHeight, tmpBlock->data() );

    int pixelSize = dataTypeSize( theBandNo );

    double xMin = theExtent.xMinimum();
    double yMax = theExtent.yMaximum();
    double tmpXMin = tmpExtent.xMinimum();
    double tmpYMax = tmpExtent.yMaximum();

    for ( int row = fromRow; row <= toRow; row++ )
    {
      double y = yMax - ( row + 0.5 ) * yRes;
      int tmpRow = floor(( tmpYMax - y ) / tmpYRes );

      for ( int col = fromCol; col <= toCol; col++ )
      {
        double x = xMin + ( col + 0.5 ) * xRes;
        int tmpCol = floor(( x - tmpXMin ) / tmpXRes );

        if ( tmpRow < 0 || tmpRow >= tmpHeight || tmpCol < 0 || tmpCol >= tmpWidth )
        {
          QgsDebugMsg( "Source row or column limits out of range" );
          block->setIsNoData(); // so that the problem becomes obvious and fixed
          delete tmpBlock;
          return block;
        }

        size_t tmpIndex = tmpRow * tmpWidth + tmpCol;
        size_t index = row * theWidth + col;

        char *tmpBits = tmpBlock->bits( tmpIndex );
        char *bits = block->bits( index );
        if ( !tmpBits )
        {
          QgsDebugMsg( QString( "Cannot get input block data tmpRow = %1 tmpCol = %2 tmpIndex = %3." ).arg( tmpRow ).arg( tmpCol ).arg( tmpIndex ) );
          continue;
        }
        if ( !bits )
        {
          QgsDebugMsg( "Cannot set output block data." );
          continue;
        }
        memcpy( bits, tmpBits, pixelSize );
      }
    }

    delete tmpBlock;
  }
  else
  {
    readBlock( theBandNo, theExtent, theWidth, theHeight, block->data() );
  }

  // apply user no data values
  // TODO: there are other readBlock methods where no data are not applied
  QList<QgsRasterBlock::Range> myNoDataRangeList = userNoDataValue( theBandNo );
  if ( !myNoDataRangeList.isEmpty() )
  {
    double myNoDataValue = noDataValue( theBandNo );
    size_t size = theWidth * theHeight;
    for ( size_t i = 0; i < size; i++ )
    {
      double value = block->value( i );

      if ( QgsRasterBlock::valueInRange( value, myNoDataRangeList ) )
      {
        block->setValue( i, myNoDataValue );
      }
    }
  }

  return block;
}