Beispiel #1
0
void QgsZonalStatistics::statisticsFromMiddlePointTest( const QgsGeometry &poly, int pixelOffsetX,
    int pixelOffsetY, int nCellsX, int nCellsY, double cellSizeX, double cellSizeY, const QgsRectangle &rasterBBox, FeatureStats &stats )
{
  double cellCenterX, cellCenterY;

  cellCenterY = rasterBBox.yMaximum() - pixelOffsetY * cellSizeY - cellSizeY / 2;
  stats.reset();

  GEOSGeometry *polyGeos = poly.exportToGeos();
  if ( !polyGeos )
  {
    return;
  }

  GEOSContextHandle_t geosctxt = QgsGeometry::getGEOSHandler();
  const GEOSPreparedGeometry *polyGeosPrepared = GEOSPrepare_r( geosctxt, polyGeos );
  if ( !polyGeosPrepared )
  {
    GEOSGeom_destroy_r( geosctxt, polyGeos );
    return;
  }

  GEOSCoordSequence *cellCenterCoords = nullptr;
  GEOSGeometry *currentCellCenter = nullptr;

  QgsRectangle featureBBox = poly.boundingBox().intersect( &rasterBBox );
  QgsRectangle intersectBBox = rasterBBox.intersect( &featureBBox );

  QgsRasterBlock *block = mRasterProvider->block( mRasterBand, intersectBBox, nCellsX, nCellsY );
  for ( int i = 0; i < nCellsY; ++i )
  {
    cellCenterX = rasterBBox.xMinimum() + pixelOffsetX * cellSizeX + cellSizeX / 2;
    for ( int j = 0; j < nCellsX; ++j )
    {
      if ( validPixel( block->value( i, j ) ) )
      {
        GEOSGeom_destroy_r( geosctxt, currentCellCenter );
        cellCenterCoords = GEOSCoordSeq_create_r( geosctxt, 1, 2 );
        GEOSCoordSeq_setX_r( geosctxt, cellCenterCoords, 0, cellCenterX );
        GEOSCoordSeq_setY_r( geosctxt, cellCenterCoords, 0, cellCenterY );
        currentCellCenter = GEOSGeom_createPoint_r( geosctxt, cellCenterCoords );
        if ( GEOSPreparedContains_r( geosctxt, polyGeosPrepared, currentCellCenter ) )
        {
          stats.addValue( block->value( i, j ) );
        }
      }
      cellCenterX += cellSizeX;
    }
    cellCenterY -= cellSizeY;
  }

  GEOSGeom_destroy_r( geosctxt, currentCellCenter );
  GEOSPreparedGeom_destroy_r( geosctxt, polyGeosPrepared );
  GEOSGeom_destroy_r( geosctxt, polyGeos );
  delete block;
}
Beispiel #2
0
void QgsZonalStatistics::statisticsFromPreciseIntersection( const QgsGeometry &poly, int pixelOffsetX,
    int pixelOffsetY, int nCellsX, int nCellsY, double cellSizeX, double cellSizeY, const QgsRectangle &rasterBBox, FeatureStats &stats )
{
  stats.reset();

  double currentY = rasterBBox.yMaximum() - pixelOffsetY * cellSizeY - cellSizeY / 2;
  QgsGeometry pixelRectGeometry;

  double hCellSizeX = cellSizeX / 2.0;
  double hCellSizeY = cellSizeY / 2.0;
  double pixelArea = cellSizeX * cellSizeY;
  double weight = 0;

  QgsRectangle featureBBox = poly.boundingBox().intersect( &rasterBBox );
  QgsRectangle intersectBBox = rasterBBox.intersect( &featureBBox );

  QgsRasterBlock *block = mRasterProvider->block( mRasterBand, intersectBBox, nCellsX, nCellsY );
  for ( int i = 0; i < nCellsY; ++i )
  {
    double currentX = rasterBBox.xMinimum() + cellSizeX / 2.0 + pixelOffsetX * cellSizeX;
    for ( int j = 0; j < nCellsX; ++j )
    {
      if ( !validPixel( block->value( i, j ) ) )
      {
        continue;
      }

      pixelRectGeometry = QgsGeometry::fromRect( QgsRectangle( currentX - hCellSizeX, currentY - hCellSizeY, currentX + hCellSizeX, currentY + hCellSizeY ) );
      if ( !pixelRectGeometry.isNull() )
      {
        //intersection
        QgsGeometry intersectGeometry = pixelRectGeometry.intersection( poly );
        if ( !intersectGeometry.isNull() )
        {
          double intersectionArea = intersectGeometry.area();
          if ( intersectionArea >= 0.0 )
          {
            weight = intersectionArea / pixelArea;
            stats.addValue( block->value( i, j ), weight );
          }
        }
        pixelRectGeometry = QgsGeometry();
      }
      currentX += cellSizeX;
    }
    currentY -= cellSizeY;
  }
  delete block;
}
// Default implementation for values
QMap<int, QVariant> QgsRasterDataProvider::identify( const QgsPoint & thePoint, IdentifyFormat theFormat, const QgsRectangle &theExtent, int theWidth, int theHeight )
{
  QgsDebugMsg( "Entered" );
  QMap<int, QVariant> results;

  if ( theFormat != IdentifyFormatValue || !( capabilities() & IdentifyValue ) )
  {
    QgsDebugMsg( "Format not supported" );
    return results;
  }

  if ( !extent().contains( thePoint ) )
  {
    // Outside the raster
    for ( int bandNo = 1; bandNo <= bandCount(); bandNo++ )
    {
      results.insert( bandNo, noDataValue( bandNo ) );
    }
    return results;
  }

  QgsRectangle myExtent = theExtent;
  if ( myExtent.isEmpty() )  myExtent = extent();

  if ( theWidth == 0 )
  {
    theWidth = capabilities() & Size ? xSize() : 1000;
  }
  if ( theHeight == 0 )
  {
    theHeight = capabilities() & Size ? ySize() : 1000;
  }

  // Calculate the row / column where the point falls
  double xres = ( myExtent.width() ) / theWidth;
  double yres = ( myExtent.height() ) / theHeight;

  int col = ( int ) floor(( thePoint.x() - myExtent.xMinimum() ) / xres );
  int row = ( int ) floor(( myExtent.yMaximum() - thePoint.y() ) / yres );

  double xMin = myExtent.xMinimum() + col * xres;
  double xMax = xMin + xres;
  double yMax = myExtent.yMaximum() - row * yres;
  double yMin = yMax - yres;
  QgsRectangle pixelExtent( xMin, yMin, xMax, yMax );

  for ( int i = 1; i <= bandCount(); i++ )
  {
    QgsRasterBlock * myBlock = block( i, pixelExtent, 1, 1 );

    double value = noDataValue( i );
    if ( myBlock ) value = myBlock->value( 0 );

    results.insert( i, value );
  }
  return results;
}
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;
}
QgsRasterBlock* QgsSingleBandGrayRenderer::block( int bandNo, QgsRectangle  const & extent, int width, int height )
{
  Q_UNUSED( bandNo );
  QgsDebugMsg( QString( "width = %1 height = %2" ).arg( width ).arg( height ) );

  QgsRasterBlock *outputBlock = new QgsRasterBlock();
  if ( !mInput )
  {
    return outputBlock;
  }

  QgsRasterBlock *inputBlock = mInput->block( mGrayBand, extent, width, height );
  if ( !inputBlock || inputBlock->isEmpty() )
  {
    QgsDebugMsg( "No raster data!" );
    delete inputBlock;
    return outputBlock;
  }

  QgsRasterBlock *alphaBlock = 0;

  if ( mAlphaBand > 0 && mGrayBand != mAlphaBand )
  {
    alphaBlock = mInput->block( mAlphaBand, extent, width, height );
    if ( !alphaBlock || alphaBlock->isEmpty() )
    {
      // TODO: better to render without alpha
      delete inputBlock;
      delete alphaBlock;
      return outputBlock;
    }
  }
  else if ( mAlphaBand > 0 )
  {
    alphaBlock = inputBlock;
  }

  if ( !outputBlock->reset( QGis::ARGB32_Premultiplied, width, height ) )
  {
    delete inputBlock;
    delete alphaBlock;
    return outputBlock;
  }

  QRgb myDefaultColor = NODATA_COLOR;
  for ( qgssize i = 0; i < ( qgssize )width*height; i++ )
  {
    if ( inputBlock->isNoData( i ) )
    {
      outputBlock->setColor( i, myDefaultColor );
      continue;
    }
    double grayVal = inputBlock->value( i );

    double currentAlpha = mOpacity;
    if ( mRasterTransparency )
    {
      currentAlpha = mRasterTransparency->alphaValue( grayVal, mOpacity * 255 ) / 255.0;
    }
    if ( mAlphaBand > 0 )
    {
      currentAlpha *= alphaBlock->value( i ) / 255.0;
    }

    if ( mContrastEnhancement )
    {
      if ( !mContrastEnhancement->isValueInDisplayableRange( grayVal ) )
      {
        outputBlock->setColor( i, myDefaultColor );
        continue;
      }
      grayVal = mContrastEnhancement->enhanceContrast( grayVal );
    }

    if ( mGradient == WhiteToBlack )
    {
      grayVal = 255 - grayVal;
    }

    if ( qgsDoubleNear( currentAlpha, 1.0 ) )
    {
      outputBlock->setColor( i, qRgba( grayVal, grayVal, grayVal, 255 ) );
    }
    else
    {
      outputBlock->setColor( i, qRgba( currentAlpha * grayVal, currentAlpha * grayVal, currentAlpha * grayVal, currentAlpha * 255 ) );
    }
  }

  delete inputBlock;
  if ( mAlphaBand > 0 && mGrayBand != mAlphaBand )
  {
    delete alphaBlock;
  }

  return outputBlock;
}
QgsRasterBlock *QgsHillshadeRenderer::block( int bandNo, const QgsRectangle &extent, int width, int height, QgsRasterBlockFeedback* feedback )
{
    Q_UNUSED( bandNo );
    QgsRasterBlock *outputBlock = new QgsRasterBlock();
    if ( !mInput )
    {
        QgsDebugMsg( "No input raster!" );
        return outputBlock;
    }

    QgsRasterBlock *inputBlock = mInput->block( mBand, extent, width, height, feedback );

    if ( !inputBlock || inputBlock->isEmpty() )
    {
        QgsDebugMsg( "No raster data!" );
        delete inputBlock;
        return outputBlock;
    }

    QgsRasterBlock *alphaBlock = nullptr;

    if ( mAlphaBand > 0 && mBand != mAlphaBand )
    {

        alphaBlock = mInput->block( mAlphaBand, extent, width, height, feedback );
        if ( !alphaBlock || alphaBlock->isEmpty() )
        {
            // TODO: better to render without alpha
            delete inputBlock;
            delete alphaBlock;
            return outputBlock;
        }
    }
    else if ( mAlphaBand > 0 )
    {
        alphaBlock = inputBlock;
    }

    if ( !outputBlock->reset( Qgis::ARGB32_Premultiplied, width, height ) )
    {
        delete inputBlock;
        delete alphaBlock;
        return outputBlock;
    }



    double cellXSize = extent.width() / double( width );
    double cellYSize = extent.height() / double( height );
    double zenithRad = qMax( 0.0, 90 - mLightAngle ) * M_PI / 180.0;
    double azimuthRad = -1 * mLightAzimuth * M_PI / 180.0;
    double cosZenithRad = cos( zenithRad );
    double sinZenithRad = sin( zenithRad );

    // Multi direction hillshade: http://pubs.usgs.gov/of/1992/of92-422/of92-422.pdf
    double angle0Rad = ( -1 * mLightAzimuth - 45 - 45 * 0.5 ) * M_PI / 180.0;
    double angle1Rad = ( -1 * mLightAzimuth - 45 * 0.5 ) * M_PI / 180.0;
    double angle2Rad = ( -1 * mLightAzimuth + 45 * 0.5 ) * M_PI / 180.0;
    double angle3Rad = ( -1 * mLightAzimuth + 45 + 45 * 0.5 ) * M_PI / 180.0;

    QRgb myDefaultColor = NODATA_COLOR;

    for ( qgssize i = 0; i < ( qgssize )height; i++ )
    {

        for ( qgssize j = 0; j < ( qgssize )width; j++ )
        {

            if ( inputBlock->isNoData( i, j ) )
            {
                outputBlock->setColor( i, j, myDefaultColor );
                continue;
            }

            qgssize iUp, iDown, jLeft, jRight;
            if ( i == 0 )
            {
                iUp = i;
                iDown = i + 1;
            }
            else if ( i < ( qgssize )height - 1 )
            {
                iUp = i - 1;
                iDown = i + 1;
            }
            else
            {
                iUp = i - 1;
                iDown = i;
            }

            if ( j == 0 )
            {
                jLeft = j;
                jRight = j + 1;
            }
            else if ( j < ( qgssize )width - 1 )
            {
                jLeft = j - 1;
                jRight = j + 1;
            }
            else
            {
                jLeft = j - 1;
                jRight = j;
            }

            double x11;
            double x21;
            double x31;
            double x12;
            double x22; // Working cell
            double x32;
            double x13;
            double x23;
            double x33;

            // This is center cell. It is not nodata. Use this in place of nodata neighbors
            x22 = inputBlock->value( i, j );

            x11 = inputBlock->isNoData( iUp, jLeft )  ? x22 : inputBlock->value( iUp, jLeft );
            x21 = inputBlock->isNoData( i, jLeft )     ? x22 : inputBlock->value( i, jLeft );
            x31 = inputBlock->isNoData( iDown, jLeft ) ? x22 : inputBlock->value( iDown, jLeft );

            x12 = inputBlock->isNoData( iUp, j )       ? x22 : inputBlock->value( iUp, j );
            // x22
            x32 = inputBlock->isNoData( iDown, j )     ? x22 : inputBlock->value( iDown, j );

            x13 = inputBlock->isNoData( iUp, jRight )   ? x22 : inputBlock->value( iUp, jRight );
            x23 = inputBlock->isNoData( i, jRight )     ? x22 : inputBlock->value( i, jRight );
            x33 = inputBlock->isNoData( iDown, jRight ) ? x22 : inputBlock->value( iDown, jRight );

            double derX = calcFirstDerX( x11, x21, x31, x12, x22, x32, x13, x23, x33, cellXSize );
            double derY = calcFirstDerY( x11, x21, x31, x12, x22, x32, x13, x23, x33, cellYSize );

            double slopeRad = atan( mZFactor * sqrt( derX * derX + derY * derY ) );
            double aspectRad = atan2( derX, -derY );


            double grayValue;
            if ( !mMultiDirectional )
            {
                // Standard single direction hillshade
                grayValue = qBound( 0.0, 255.0 * ( cosZenithRad * cos( slopeRad )
                                                   + sinZenithRad * sin( slopeRad )
                                                   * cos( azimuthRad - aspectRad ) ) , 255.0 );
            }
            else
            {
                // Weighted multi direction as in http://pubs.usgs.gov/of/1992/of92-422/of92-422.pdf
                double weight0 = sin( aspectRad - angle0Rad );
                double weight1 = sin( aspectRad - angle1Rad );
                double weight2 = sin( aspectRad - angle2Rad );
                double weight3 = sin( aspectRad - angle3Rad );
                weight0 = weight0 * weight0;
                weight1 = weight1 * weight1;
                weight2 = weight2 * weight2;
                weight3 = weight3 * weight3;

                double cosSlope = cosZenithRad * cos( slopeRad );
                double sinSlope = sinZenithRad * sin( slopeRad );
                double color0 = cosSlope + sinSlope * cos( angle0Rad - aspectRad ) ;
                double color1 = cosSlope + sinSlope * cos( angle1Rad - aspectRad ) ;
                double color2 = cosSlope + sinSlope * cos( angle2Rad - aspectRad ) ;
                double color3 = cosSlope + sinSlope * cos( angle3Rad - aspectRad ) ;
                grayValue = qBound( 0.0, 255 * ( weight0 * color0 + weight1 * color1 + weight2 * color2 + weight3 * color3 ) * 0.5, 255.0 );
            }

            double currentAlpha = mOpacity;
            if ( mRasterTransparency )
            {
                currentAlpha = mRasterTransparency->alphaValue( x22, mOpacity * 255 ) / 255.0;
            }
            if ( mAlphaBand > 0 )
            {
                currentAlpha *= alphaBlock->value( i ) / 255.0;
            }

            if ( qgsDoubleNear( currentAlpha, 1.0 ) )
            {
                outputBlock->setColor( i, j, qRgba( grayValue, grayValue, grayValue, 255 ) );
            }
            else
            {
                outputBlock->setColor( i, j, qRgba( currentAlpha * grayValue, currentAlpha * grayValue, currentAlpha * grayValue, currentAlpha * 255 ) );
            }
        }
    }

    delete inputBlock;
    if ( mAlphaBand > 0 && mBand != mAlphaBand )
    {
        delete alphaBlock;
    }
    return outputBlock;
}
Beispiel #7
0
QgsRasterBlock* QgsSingleBandPseudoColorRenderer::block( int bandNo, QgsRectangle  const & extent, int width, int height, QgsRasterBlockFeedback* feedback )
{
  Q_UNUSED( bandNo );

  QgsRasterBlock *outputBlock = new QgsRasterBlock();
  if ( !mInput || !mShader )
  {
    return outputBlock;
  }


  QgsRasterBlock *inputBlock = mInput->block( mBand, extent, width, height, feedback );
  if ( !inputBlock || inputBlock->isEmpty() )
  {
    QgsDebugMsg( "No raster data!" );
    delete inputBlock;
    return outputBlock;
  }

  //rendering is faster without considering user-defined transparency
  bool hasTransparency = usesTransparency();

  QgsRasterBlock *alphaBlock = nullptr;
  if ( mAlphaBand > 0 && mAlphaBand != mBand )
  {
    alphaBlock = mInput->block( mAlphaBand, extent, width, height, feedback );
    if ( !alphaBlock || alphaBlock->isEmpty() )
    {
      delete inputBlock;
      delete alphaBlock;
      return outputBlock;
    }
  }
  else if ( mAlphaBand == mBand )
  {
    alphaBlock = inputBlock;
  }

  if ( !outputBlock->reset( Qgis::ARGB32_Premultiplied, width, height ) )
  {
    delete inputBlock;
    delete alphaBlock;
    return outputBlock;
  }

  QRgb myDefaultColor = NODATA_COLOR;

  for ( qgssize i = 0; i < ( qgssize )width*height; i++ )
  {
    if ( inputBlock->isNoData( i ) )
    {
      outputBlock->setColor( i, myDefaultColor );
      continue;
    }
    double val = inputBlock->value( i );
    int red, green, blue, alpha;
    if ( !mShader->shade( val, &red, &green, &blue, &alpha ) )
    {
      outputBlock->setColor( i, myDefaultColor );
      continue;
    }

    if ( alpha < 255 )
    {
      // Working with premultiplied colors, so multiply values by alpha
      red *= ( alpha / 255.0 );
      blue *= ( alpha / 255.0 );
      green *= ( alpha / 255.0 );
    }

    if ( !hasTransparency )
    {
      outputBlock->setColor( i, qRgba( red, green, blue, alpha ) );
    }
    else
    {
      //opacity
      double currentOpacity = mOpacity;
      if ( mRasterTransparency )
      {
        currentOpacity = mRasterTransparency->alphaValue( val, mOpacity * 255 ) / 255.0;
      }
      if ( mAlphaBand > 0 )
      {
        currentOpacity *= alphaBlock->value( i ) / 255.0;
      }

      outputBlock->setColor( i, qRgba( currentOpacity * red, currentOpacity * green, currentOpacity * blue, currentOpacity * alpha ) );
    }
  }

  delete inputBlock;
  if ( mAlphaBand > 0 && mBand != mAlphaBand )
  {
    delete alphaBlock;
  }

  return outputBlock;
}
Beispiel #8
0
QgsRasterHistogram QgsRasterInterface::histogram( int theBandNo,
    int theBinCount,
    double theMinimum, double theMaximum,
    const QgsRectangle & theExtent,
    int theSampleSize,
    bool theIncludeOutOfRange )
{
  QgsDebugMsg( QString( "theBandNo = %1 theBinCount = %2 theMinimum = %3 theMaximum = %4 theSampleSize = %5" ).arg( theBandNo ).arg( theBinCount ).arg( theMinimum ).arg( theMaximum ).arg( theSampleSize ) );

  QgsRasterHistogram myHistogram;
  initHistogram( myHistogram, theBandNo, theBinCount, theMinimum, theMaximum, theExtent, theSampleSize, theIncludeOutOfRange );

  // Find cached
  foreach ( QgsRasterHistogram histogram, mHistograms )
  {
    if ( histogram == myHistogram )
    {
      QgsDebugMsg( "Using cached histogram." );
      return histogram;
    }
  }

  int myBinCount = myHistogram.binCount;
  int myWidth = myHistogram.width;
  int myHeight = myHistogram.height;
  QgsRectangle myExtent = myHistogram.extent;
  myHistogram.histogramVector.resize( myBinCount );

  int myXBlockSize = xBlockSize();
  int myYBlockSize = yBlockSize();
  if ( myXBlockSize == 0 ) // should not happen, but happens
  {
    myXBlockSize = 500;
  }
  if ( myYBlockSize == 0 ) // should not happen, but happens
  {
    myYBlockSize = 500;
  }

  int myNXBlocks = ( myWidth + myXBlockSize - 1 ) / myXBlockSize;
  int myNYBlocks = ( myHeight + myYBlockSize - 1 ) / myYBlockSize;

  double myXRes = myExtent.width() / myWidth;
  double myYRes = myExtent.height() / myHeight;

  double myMinimum = myHistogram.minimum;
  double myMaximum = myHistogram.maximum;

  // To avoid rounding errors
  // TODO: check this
  double myerval = ( myMaximum - myMinimum ) / myHistogram.binCount;
  myMinimum -= 0.1 * myerval;
  myMaximum += 0.1 * myerval;

  QgsDebugMsg( QString( "binCount = %1 myMinimum = %2 myMaximum = %3" ).arg( myHistogram.binCount ).arg( myMinimum ).arg( myMaximum ) );

  double myBinSize = ( myMaximum - myMinimum ) / myBinCount;

  // TODO: progress signals
  for ( int myYBlock = 0; myYBlock < myNYBlocks; myYBlock++ )
  {
    for ( int myXBlock = 0; myXBlock < myNXBlocks; myXBlock++ )
    {
      int myBlockWidth = qMin( myXBlockSize, myWidth - myXBlock * myXBlockSize );
      int myBlockHeight = qMin( myYBlockSize, myHeight - myYBlock * myYBlockSize );

      double xmin = myExtent.xMinimum() + myXBlock * myXBlockSize * myXRes;
      double xmax = xmin + myBlockWidth * myXRes;
      double ymin = myExtent.yMaximum() - myYBlock * myYBlockSize * myYRes;
      double ymax = ymin - myBlockHeight * myYRes;

      QgsRectangle myPartExtent( xmin, ymin, xmax, ymax );

      QgsRasterBlock* blk = block( theBandNo, myPartExtent, myBlockWidth, myBlockHeight );

      // Collect the histogram counts.
      for ( qgssize i = 0; i < (( qgssize ) myBlockHeight ) * myBlockWidth; i++ )
      {
        if ( blk->isNoData( i ) )
        {
          continue; // NULL
        }
        double myValue = blk->value( i );

        int myBinIndex = static_cast <int>( qFloor(( myValue - myMinimum ) /  myBinSize ) ) ;

        if (( myBinIndex < 0 || myBinIndex > ( myBinCount - 1 ) ) && !theIncludeOutOfRange )
        {
          continue;
        }
        if ( myBinIndex < 0 ) myBinIndex = 0;
        if ( myBinIndex > ( myBinCount - 1 ) ) myBinIndex = myBinCount - 1;

        myHistogram.histogramVector[myBinIndex] += 1;
        myHistogram.nonNullCount++;
      }
      delete blk;
    }
  }

  myHistogram.valid = true;
  mHistograms.append( myHistogram );

#ifdef QGISDEBUG
  QString hist;
  for ( int i = 0; i < qMin( myHistogram.histogramVector.size(), 500 ); i++ )
  {
    hist += QString::number( myHistogram.histogramVector.value( i ) ) + " ";
  }
  QgsDebugMsg( "Histogram (max first 500 bins): " + hist );
#endif

  return myHistogram;
}
QgsRasterBlock * QgsPalettedRasterRenderer::block( int bandNo, QgsRectangle  const & extent, int width, int height )
{
    QgsRasterBlock *outputBlock = new QgsRasterBlock();
    if ( !mInput )
    {
        return outputBlock;
    }

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

    if ( !inputBlock || inputBlock->isEmpty() )
    {
        QgsDebugMsg( "No raster data!" );
        delete inputBlock;
        return outputBlock;
    }

    double currentOpacity = mOpacity;

    //rendering is faster without considering user-defined transparency
    bool hasTransparency = usesTransparency();
    QgsRasterBlock *alphaBlock = 0;

    if ( mAlphaBand > 0 && mAlphaBand != mBand )
    {
        alphaBlock = mInput->block( mAlphaBand, extent, width, height );
        if ( !alphaBlock || alphaBlock->isEmpty() )
        {
            delete inputBlock;
            delete alphaBlock;
            return outputBlock;
        }
    }
    else if ( mAlphaBand == mBand )
    {
        alphaBlock = inputBlock;
    }

    if ( !outputBlock->reset( QGis::ARGB32_Premultiplied, width, height ) )
    {
        delete inputBlock;
        delete alphaBlock;
        return outputBlock;
    }

    QRgb myDefaultColor = NODATA_COLOR;

    //use direct data access instead of QgsRasterBlock::setValue
    //because of performance
    unsigned int* outputData = ( unsigned int* )( outputBlock->bits() );

    qgssize rasterSize = ( qgssize )width * height;
    for ( qgssize i = 0; i < rasterSize; ++i )
    {
        if ( inputBlock->isNoData( i ) )
        {
            outputData[i] = myDefaultColor;
            continue;
        }
        int val = ( int ) inputBlock->value( i );
        if ( !hasTransparency )
        {
            outputData[i] = mColors[val];
        }
        else
        {
            currentOpacity = mOpacity;
            if ( mRasterTransparency )
            {
                currentOpacity = mRasterTransparency->alphaValue( val, mOpacity * 255 ) / 255.0;
            }
            if ( mAlphaBand > 0 )
            {
                currentOpacity *=  alphaBlock->value( i ) / 255.0;
            }
            QColor currentColor = QColor( mColors[val] );
            outputData[i] = qRgba( currentOpacity * currentColor.red(), currentOpacity * currentColor.green(), currentOpacity * currentColor.blue(), currentOpacity * 255 );
        }
    }

    delete inputBlock;
    if ( mAlphaBand > 0 && mBand != mAlphaBand )
    {
        delete alphaBlock;
    }

    return outputBlock;
}
QgsRasterBlock *QgsMultiBandColorRenderer::block( int bandNo, QgsRectangle  const &extent, int width, int height, QgsRasterBlockFeedback *feedback )
{
  Q_UNUSED( bandNo );
  std::unique_ptr< QgsRasterBlock > outputBlock( new QgsRasterBlock() );
  if ( !mInput )
  {
    return outputBlock.release();
  }

  //In some (common) cases, we can simplify the drawing loop considerably and save render time
  bool fastDraw = ( !usesTransparency()
                    && mRedBand > 0 && mGreenBand > 0 && mBlueBand > 0
                    && mAlphaBand < 1 );

  QSet<int> bands;
  if ( mRedBand > 0 )
  {
    bands << mRedBand;
  }
  if ( mGreenBand > 0 )
  {
    bands << mGreenBand;
  }
  if ( mBlueBand > 0 )
  {
    bands << mBlueBand;
  }
  if ( bands.empty() )
  {
    // no need to draw anything if no band is set
    // TODO:: we should probably return default color block
    return outputBlock.release();
  }

  if ( mAlphaBand > 0 )
  {
    bands << mAlphaBand;
  }

  QMap<int, QgsRasterBlock *> bandBlocks;
  QgsRasterBlock *defaultPointer = nullptr;
  QSet<int>::const_iterator bandIt = bands.constBegin();
  for ( ; bandIt != bands.constEnd(); ++bandIt )
  {
    bandBlocks.insert( *bandIt, defaultPointer );
  }

  QgsRasterBlock *redBlock = nullptr;
  QgsRasterBlock *greenBlock = nullptr;
  QgsRasterBlock *blueBlock = nullptr;
  QgsRasterBlock *alphaBlock = nullptr;

  bandIt = bands.constBegin();
  for ( ; bandIt != bands.constEnd(); ++bandIt )
  {
    bandBlocks[*bandIt] = mInput->block( *bandIt, extent, width, height, feedback );
    if ( !bandBlocks[*bandIt] )
    {
      // We should free the alloced mem from block().
      QgsDebugMsg( QStringLiteral( "No input band" ) );
      --bandIt;
      for ( ; bandIt != bands.constBegin(); --bandIt )
      {
        delete bandBlocks[*bandIt];
      }
      return outputBlock.release();
    }
  }

  if ( mRedBand > 0 )
  {
    redBlock = bandBlocks[mRedBand];
  }
  if ( mGreenBand > 0 )
  {
    greenBlock = bandBlocks[mGreenBand];
  }
  if ( mBlueBand > 0 )
  {
    blueBlock = bandBlocks[mBlueBand];
  }
  if ( mAlphaBand > 0 )
  {
    alphaBlock = bandBlocks[mAlphaBand];
  }

  if ( !outputBlock->reset( Qgis::ARGB32_Premultiplied, width, height ) )
  {
    for ( int i = 0; i < bandBlocks.size(); i++ )
    {
      delete bandBlocks.value( i );
    }
    return outputBlock.release();
  }

  QRgb *outputBlockColorData = outputBlock->colorData();

  // faster data access to data for the common case that input data are coming from RGB image with 8-bit bands
  bool hasByteRgb = ( redBlock && greenBlock && blueBlock && redBlock->dataType() == Qgis::Byte && greenBlock->dataType() == Qgis::Byte && blueBlock->dataType() == Qgis::Byte );
  const quint8 *redData = nullptr, *greenData = nullptr, *blueData = nullptr;
  if ( hasByteRgb )
  {
    redData = redBlock->byteData();
    greenData = greenBlock->byteData();
    blueData = blueBlock->byteData();
  }

  QRgb myDefaultColor = NODATA_COLOR;

  if ( fastDraw )
  {
    // By default RGB raster layers have contrast enhancement assigned and normally that requires us to take the slow
    // route that applies the enhancement. However if the algorithm type is "no enhancement" and all input bands are byte-sized,
    // no transform would be applied to the input values and we can take the fast route.
    bool hasEnhancement;
    if ( hasByteRgb )
    {
      hasEnhancement =
        ( mRedContrastEnhancement && mRedContrastEnhancement->contrastEnhancementAlgorithm() != QgsContrastEnhancement::NoEnhancement ) ||
        ( mGreenContrastEnhancement && mGreenContrastEnhancement->contrastEnhancementAlgorithm() != QgsContrastEnhancement::NoEnhancement ) ||
        ( mBlueContrastEnhancement && mBlueContrastEnhancement->contrastEnhancementAlgorithm() != QgsContrastEnhancement::NoEnhancement );
    }
    else
    {
      hasEnhancement = mRedContrastEnhancement || mGreenContrastEnhancement || mBlueContrastEnhancement;
    }
    if ( hasEnhancement )
      fastDraw = false;
  }

  qgssize count = ( qgssize )width * height;
  for ( qgssize i = 0; i < count; i++ )
  {
    if ( fastDraw ) //fast rendering if no transparency, stretching, color inversion, etc.
    {
      if ( redBlock->isNoData( i ) ||
           greenBlock->isNoData( i ) ||
           blueBlock->isNoData( i ) )
      {
        outputBlock->setColor( i, myDefaultColor );
      }
      else
      {
        if ( hasByteRgb )
        {
          outputBlockColorData[i] = qRgb( redData[i], greenData[i], blueData[i] );
        }
        else
        {
          int redVal = static_cast<int>( redBlock->value( i ) );
          int greenVal = static_cast<int>( greenBlock->value( i ) );
          int blueVal = static_cast<int>( blueBlock->value( i ) );
          outputBlockColorData[i] = qRgb( redVal, greenVal, blueVal );
        }
      }
      continue;
    }

    bool isNoData = false;
    double redVal = 0;
    double greenVal = 0;
    double blueVal = 0;
    if ( mRedBand > 0 )
    {
      redVal = redBlock->value( i );
      if ( redBlock->isNoData( i ) ) isNoData = true;
    }
    if ( !isNoData && mGreenBand > 0 )
    {
      greenVal = greenBlock->value( i );
      if ( greenBlock->isNoData( i ) ) isNoData = true;
    }
    if ( !isNoData && mBlueBand > 0 )
    {
      blueVal = blueBlock->value( i );
      if ( blueBlock->isNoData( i ) ) isNoData = true;
    }
    if ( isNoData )
    {
      outputBlock->setColor( i, myDefaultColor );
      continue;
    }

    //apply default color if red, green or blue not in displayable range
    if ( ( mRedContrastEnhancement && !mRedContrastEnhancement->isValueInDisplayableRange( redVal ) )
         || ( mGreenContrastEnhancement && !mGreenContrastEnhancement->isValueInDisplayableRange( redVal ) )
         || ( mBlueContrastEnhancement && !mBlueContrastEnhancement->isValueInDisplayableRange( redVal ) ) )
    {
      outputBlock->setColor( i, myDefaultColor );
      continue;
    }

    //stretch color values
    if ( mRedContrastEnhancement )
    {
      redVal = mRedContrastEnhancement->enhanceContrast( redVal );
    }
    if ( mGreenContrastEnhancement )
    {
      greenVal = mGreenContrastEnhancement->enhanceContrast( greenVal );
    }
    if ( mBlueContrastEnhancement )
    {
      blueVal = mBlueContrastEnhancement->enhanceContrast( blueVal );
    }

    //opacity
    double currentOpacity = mOpacity;
    if ( mRasterTransparency )
    {
      currentOpacity = mRasterTransparency->alphaValue( redVal, greenVal, blueVal, mOpacity * 255 ) / 255.0;
    }
    if ( mAlphaBand > 0 )
    {
      currentOpacity *= alphaBlock->value( i ) / 255.0;
    }

    if ( qgsDoubleNear( currentOpacity, 1.0 ) )
    {
      outputBlock->setColor( i, qRgba( redVal, greenVal, blueVal, 255 ) );
    }
    else
    {
      outputBlock->setColor( i, qRgba( currentOpacity * redVal, currentOpacity * greenVal, currentOpacity * blueVal, currentOpacity * 255 ) );
    }
  }

  //delete input blocks
  QMap<int, QgsRasterBlock *>::const_iterator bandDelIt = bandBlocks.constBegin();
  for ( ; bandDelIt != bandBlocks.constEnd(); ++bandDelIt )
  {
    delete bandDelIt.value();
  }

  return outputBlock.release();
}
Beispiel #11
0
QgsRasterBandStats QgsRasterInterface::bandStatistics( int theBandNo,
    int theStats,
    const QgsRectangle & theExtent,
    int theSampleSize )
{
  QgsDebugMsg( QString( "theBandNo = %1 theStats = %2 theSampleSize = %3" ).arg( theBandNo ).arg( theStats ).arg( theSampleSize ) );

  // TODO: null values set on raster layer!!!

  QgsRasterBandStats myRasterBandStats;
  initStatistics( myRasterBandStats, theBandNo, theStats, theExtent, theSampleSize );

  foreach ( QgsRasterBandStats stats, mStatistics )
  {
    if ( stats.contains( myRasterBandStats ) )
    {
      QgsDebugMsg( "Using cached statistics." );
      return stats;
    }
  }

  QgsRectangle myExtent = myRasterBandStats.extent;
  int myWidth = myRasterBandStats.width;
  int myHeight = myRasterBandStats.height;

  //int myDataType = dataType( theBandNo );

  int myXBlockSize = xBlockSize();
  int myYBlockSize = yBlockSize();
  if ( myXBlockSize == 0 ) // should not happen, but happens
  {
    myXBlockSize = 500;
  }
  if ( myYBlockSize == 0 ) // should not happen, but happens
  {
    myYBlockSize = 500;
  }

  int myNXBlocks = ( myWidth + myXBlockSize - 1 ) / myXBlockSize;
  int myNYBlocks = ( myHeight + myYBlockSize - 1 ) / myYBlockSize;

  double myXRes = myExtent.width() / myWidth;
  double myYRes = myExtent.height() / myHeight;
  // TODO: progress signals

  // used by single pass stdev
  double myMean = 0;
  double mySumOfSquares = 0;

  bool myFirstIterationFlag = true;
  for ( int myYBlock = 0; myYBlock < myNYBlocks; myYBlock++ )
  {
    for ( int myXBlock = 0; myXBlock < myNXBlocks; myXBlock++ )
    {
      QgsDebugMsg( QString( "myYBlock = %1 myXBlock = %2" ).arg( myYBlock ).arg( myXBlock ) );
      int myBlockWidth = qMin( myXBlockSize, myWidth - myXBlock * myXBlockSize );
      int myBlockHeight = qMin( myYBlockSize, myHeight - myYBlock * myYBlockSize );

      double xmin = myExtent.xMinimum() + myXBlock * myXBlockSize * myXRes;
      double xmax = xmin + myBlockWidth * myXRes;
      double ymin = myExtent.yMaximum() - myYBlock * myYBlockSize * myYRes;
      double ymax = ymin - myBlockHeight * myYRes;

      QgsRectangle myPartExtent( xmin, ymin, xmax, ymax );

      QgsRasterBlock* blk = block( theBandNo, myPartExtent, myBlockWidth, myBlockHeight );

      // Collect the histogram counts.
      for ( qgssize i = 0; i < (( qgssize ) myBlockHeight ) * myBlockWidth; i++ )
      {
        if ( blk->isNoData( i ) ) continue; // NULL

        double myValue = blk->value( i );

        myRasterBandStats.sum += myValue;
        myRasterBandStats.elementCount++;

        if ( myFirstIterationFlag )
        {
          myFirstIterationFlag = false;
          myRasterBandStats.minimumValue = myValue;
          myRasterBandStats.maximumValue = myValue;
        }
        else
        {
          if ( myValue < myRasterBandStats.minimumValue )
          {
            myRasterBandStats.minimumValue = myValue;
          }
          if ( myValue > myRasterBandStats.maximumValue )
          {
            myRasterBandStats.maximumValue = myValue;
          }
        }

        // Single pass stdev
        double myDelta = myValue - myMean;
        myMean += myDelta / myRasterBandStats.elementCount;
        mySumOfSquares += myDelta * ( myValue - myMean );
      }
      delete blk;
    }
  }

  myRasterBandStats.range = myRasterBandStats.maximumValue - myRasterBandStats.minimumValue;
  myRasterBandStats.mean = myRasterBandStats.sum / myRasterBandStats.elementCount;

  myRasterBandStats.sumOfSquares = mySumOfSquares; // OK with single pass?

  // stdDev may differ  from GDAL stats, because GDAL is using naive single pass
  // algorithm which is more error prone (because of rounding errors)
  // Divide result by sample size - 1 and get square root to get stdev
  myRasterBandStats.stdDev = sqrt( mySumOfSquares / ( myRasterBandStats.elementCount - 1 ) );

  QgsDebugMsg( "************ STATS **************" );
  QgsDebugMsg( QString( "MIN %1" ).arg( myRasterBandStats.minimumValue ) );
  QgsDebugMsg( QString( "MAX %1" ).arg( myRasterBandStats.maximumValue ) );
  QgsDebugMsg( QString( "RANGE %1" ).arg( myRasterBandStats.range ) );
  QgsDebugMsg( QString( "MEAN %1" ).arg( myRasterBandStats.mean ) );
  QgsDebugMsg( QString( "STDDEV %1" ).arg( myRasterBandStats.stdDev ) );

  myRasterBandStats.statsGathered = QgsRasterBandStats::All;
  mStatistics.append( myRasterBandStats );

  return myRasterBandStats;
}
Beispiel #12
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;
}
Beispiel #13
0
QgsRasterBlock *QgsHillshadeRenderer::block( int bandNo, const QgsRectangle &extent, int width, int height )
{
  Q_UNUSED( bandNo );
  QgsRasterBlock *outputBlock = new QgsRasterBlock();
  if ( !mInput )
  {
    QgsDebugMsg( "No input raster!" );
    return outputBlock;
  }

  QgsRasterBlock *inputBlock = mInput->block( mBand, extent, width, height );

  if ( !inputBlock || inputBlock->isEmpty() )
  {
    QgsDebugMsg( "No raster data!" );
    delete inputBlock;
    return outputBlock;
  }

  if ( !outputBlock->reset( QGis::ARGB32_Premultiplied, width, height ) )
  {
    delete inputBlock;
    return outputBlock;
  }

  double cellXSize = extent.width() / double( width );
  double cellYSize = extent.height() / double( height );
  double zenithRad = qMax( 0.0, 90 - mLightAngle ) * M_PI / 180.0;
  double azimuthRad = -1 * mLightAzimuth * M_PI / 180.0;
  double cosZenithRad = cos( zenithRad );
  double sinZenithRad = sin( zenithRad );

  QRgb myDefaultColor = NODATA_COLOR;

  for ( qgssize i = 0; i < ( qgssize )height; i++ )
  {

    for ( qgssize j = 0; j < ( qgssize )width; j++ )
    {

      if ( inputBlock->isNoData( i, j ) )
      {
        outputBlock->setColor( i, j, myDefaultColor );
        continue;
      }

      qgssize iUp, iDown, jLeft, jRight;
      if ( i == 0 )
      {
        iUp = i;
        iDown = i + 1;
      }
      else if ( i < ( qgssize )height - 1 )
      {
        iUp = i - 1;
        iDown = i + 1;
      }
      else
      {
        iUp = i - 1;
        iDown = i;
      }

      if ( j == 0 )
      {
        jLeft = j;
        jRight = j + 1;
      }
      else if ( j < ( qgssize )width - 1 )
      {
        jLeft = j - 1;
        jRight = j + 1;
      }
      else
      {
        jLeft = j - 1;
        jRight = j;
      }

      double x11;
      double x21;
      double x31;
      double x12;
      double x22; // Working cell
      double x32;
      double x13;
      double x23;
      double x33;

      // This is center cell. It is not nodata. Use this in place of nodata neighbors
      x22 = inputBlock->value( i, j );

      x11 = inputBlock->isNoData( iUp, jLeft )  ? x22 : inputBlock->value( iUp, jLeft );
      x21 = inputBlock->isNoData( i, jLeft )     ? x22 : inputBlock->value( i, jLeft );
      x31 = inputBlock->isNoData( iDown, jLeft ) ? x22 : inputBlock->value( iDown, jLeft );

      x12 = inputBlock->isNoData( iUp, j )       ? x22 : inputBlock->value( iUp, j );
      // x22
      x32 = inputBlock->isNoData( iDown, j )     ? x22 : inputBlock->value( iDown, j );

      x13 = inputBlock->isNoData( iUp, jRight )   ? x22 : inputBlock->value( iUp, jRight );
      x23 = inputBlock->isNoData( i, jRight )     ? x22 : inputBlock->value( i, jRight );
      x33 = inputBlock->isNoData( iDown, jRight ) ? x22 : inputBlock->value( iDown, jRight );

      double derX = calcFirstDerX( x11, x21, x31, x12, x22, x32, x13, x23, x33, cellXSize );
      double derY = calcFirstDerY( x11, x21, x31, x12, x22, x32, x13, x23, x33, cellYSize );

      double slope_rad = atan( mZFactor * sqrt( derX * derX + derY * derY ) );
      double aspectRad = atan2( derX, -derY );

      double colorvalue = qBound( 0.0, 255.0 * (( cosZenithRad * cos( slope_rad ) ) +
                                  ( sinZenithRad * sin( slope_rad ) *
                                    cos( azimuthRad - aspectRad ) ) ), 255.0 );

      outputBlock->setColor( i, j, qRgb( colorvalue, colorvalue, colorvalue ) );
    }
  }
  return outputBlock;
}
QgsRasterBlock *QgsMultiBandColorRenderer::block( int bandNo, QgsRectangle  const &extent, int width, int height, QgsRasterBlockFeedback *feedback )
{
  Q_UNUSED( bandNo );
  std::unique_ptr< QgsRasterBlock > outputBlock( new QgsRasterBlock() );
  if ( !mInput )
  {
    return outputBlock.release();
  }

  //In some (common) cases, we can simplify the drawing loop considerably and save render time
  bool fastDraw = ( !usesTransparency()
                    && mRedBand > 0 && mGreenBand > 0 && mBlueBand > 0
                    && mAlphaBand < 1 && !mRedContrastEnhancement && !mGreenContrastEnhancement && !mBlueContrastEnhancement );

  QSet<int> bands;
  if ( mRedBand > 0 )
  {
    bands << mRedBand;
  }
  if ( mGreenBand > 0 )
  {
    bands << mGreenBand;
  }
  if ( mBlueBand > 0 )
  {
    bands << mBlueBand;
  }
  if ( bands.size() < 1 )
  {
    // no need to draw anything if no band is set
    // TODO:: we should probably return default color block
    return outputBlock.release();
  }

  if ( mAlphaBand > 0 )
  {
    bands << mAlphaBand;
  }

  QMap<int, QgsRasterBlock *> bandBlocks;
  QgsRasterBlock *defaultPointer = nullptr;
  QSet<int>::const_iterator bandIt = bands.constBegin();
  for ( ; bandIt != bands.constEnd(); ++bandIt )
  {
    bandBlocks.insert( *bandIt, defaultPointer );
  }

  QgsRasterBlock *redBlock = nullptr;
  QgsRasterBlock *greenBlock = nullptr;
  QgsRasterBlock *blueBlock = nullptr;
  QgsRasterBlock *alphaBlock = nullptr;

  bandIt = bands.constBegin();
  for ( ; bandIt != bands.constEnd(); ++bandIt )
  {
    bandBlocks[*bandIt] =  mInput->block( *bandIt, extent, width, height, feedback );
    if ( !bandBlocks[*bandIt] )
    {
      // We should free the alloced mem from block().
      QgsDebugMsg( "No input band" );
      --bandIt;
      for ( ; bandIt != bands.constBegin(); --bandIt )
      {
        delete bandBlocks[*bandIt];
      }
      return outputBlock.release();
    }
  }

  if ( mRedBand > 0 )
  {
    redBlock = bandBlocks[mRedBand];
  }
  if ( mGreenBand > 0 )
  {
    greenBlock = bandBlocks[mGreenBand];
  }
  if ( mBlueBand > 0 )
  {
    blueBlock = bandBlocks[mBlueBand];
  }
  if ( mAlphaBand > 0 )
  {
    alphaBlock = bandBlocks[mAlphaBand];
  }

  if ( !outputBlock->reset( Qgis::ARGB32_Premultiplied, width, height ) )
  {
    for ( int i = 0; i < bandBlocks.size(); i++ )
    {
      delete bandBlocks.value( i );
    }
    return outputBlock.release();
  }

  QRgb myDefaultColor = NODATA_COLOR;

  for ( qgssize i = 0; i < ( qgssize )width * height; i++ )
  {
    if ( fastDraw ) //fast rendering if no transparency, stretching, color inversion, etc.
    {
      if ( redBlock->isNoData( i ) ||
           greenBlock->isNoData( i ) ||
           blueBlock->isNoData( i ) )
      {
        outputBlock->setColor( i, myDefaultColor );
      }
      else
      {
        int redVal = ( int )redBlock->value( i );
        int greenVal = ( int )greenBlock->value( i );
        int blueVal = ( int )blueBlock->value( i );
        outputBlock->setColor( i, qRgba( redVal, greenVal, blueVal, 255 ) );
      }
      continue;
    }

    bool isNoData = false;
    double redVal = 0;
    double greenVal = 0;
    double blueVal = 0;
    if ( mRedBand > 0 )
    {
      redVal = redBlock->value( i );
      if ( redBlock->isNoData( i ) ) isNoData = true;
    }
    if ( !isNoData && mGreenBand > 0 )
    {
      greenVal = greenBlock->value( i );
      if ( greenBlock->isNoData( i ) ) isNoData = true;
    }
    if ( !isNoData && mBlueBand > 0 )
    {
      blueVal = blueBlock->value( i );
      if ( blueBlock->isNoData( i ) ) isNoData = true;
    }
    if ( isNoData )
    {
      outputBlock->setColor( i, myDefaultColor );
      continue;
    }

    //apply default color if red, green or blue not in displayable range
    if ( ( mRedContrastEnhancement && !mRedContrastEnhancement->isValueInDisplayableRange( redVal ) )
         || ( mGreenContrastEnhancement && !mGreenContrastEnhancement->isValueInDisplayableRange( redVal ) )
         || ( mBlueContrastEnhancement && !mBlueContrastEnhancement->isValueInDisplayableRange( redVal ) ) )
    {
      outputBlock->setColor( i, myDefaultColor );
      continue;
    }

    //stretch color values
    if ( mRedContrastEnhancement )
    {
      redVal = mRedContrastEnhancement->enhanceContrast( redVal );
    }
    if ( mGreenContrastEnhancement )
    {
      greenVal = mGreenContrastEnhancement->enhanceContrast( greenVal );
    }
    if ( mBlueContrastEnhancement )
    {
      blueVal = mBlueContrastEnhancement->enhanceContrast( blueVal );
    }

    //opacity
    double currentOpacity = mOpacity;
    if ( mRasterTransparency )
    {
      currentOpacity = mRasterTransparency->alphaValue( redVal, greenVal, blueVal, mOpacity * 255 ) / 255.0;
    }
    if ( mAlphaBand > 0 )
    {
      currentOpacity *= alphaBlock->value( i ) / 255.0;
    }

    if ( qgsDoubleNear( currentOpacity, 1.0 ) )
    {
      outputBlock->setColor( i, qRgba( redVal, greenVal, blueVal, 255 ) );
    }
    else
    {
      outputBlock->setColor( i, qRgba( currentOpacity * redVal, currentOpacity * greenVal, currentOpacity * blueVal, currentOpacity * 255 ) );
    }
  }

  //delete input blocks
  QMap<int, QgsRasterBlock *>::const_iterator bandDelIt = bandBlocks.constBegin();
  for ( ; bandDelIt != bandBlocks.constEnd(); ++bandDelIt )
  {
    delete bandDelIt.value();
  }

  return outputBlock.release();
}
bool QgsRasterChecker::runTest( QString theVerifiedKey, QString theVerifiedUri,
                                QString theExpectedKey, QString theExpectedUri )
{
  bool ok = true;
  mReport += "\n\n";

  //QgsRasterDataProvider* verifiedProvider = QgsRasterLayer::loadProvider( theVerifiedKey, theVerifiedUri );
  QgsRasterDataProvider* verifiedProvider = ( QgsRasterDataProvider* ) QgsProviderRegistry::instance()->provider( theVerifiedKey, theVerifiedUri );
  if ( !verifiedProvider || !verifiedProvider->isValid() )
  {
    error( QString( "Cannot load provider %1 with URI: %2" ).arg( theVerifiedKey ).arg( theVerifiedUri ), mReport );
    ok = false;
  }

  //QgsRasterDataProvider* expectedProvider = QgsRasterLayer::loadProvider( theExpectedKey, theExpectedUri );
  QgsRasterDataProvider* expectedProvider = ( QgsRasterDataProvider* ) QgsProviderRegistry::instance()->provider( theExpectedKey, theExpectedUri );
  if ( !expectedProvider || !expectedProvider->isValid() )
  {
    error( QString( "Cannot load provider %1 with URI: %2" ).arg( theExpectedKey ).arg( theExpectedUri ), mReport );
    ok = false;
  }

  if ( !ok ) return false;

  mReport += QString( "Verified URI: %1<br>" ).arg( theVerifiedUri.replace( "&", "&amp;" ) );
  mReport += QString( "Expected URI: %1<br>" ).arg( theExpectedUri.replace( "&", "&amp;" ) );

  mReport += "<br>";
  mReport += QString( "<table style='%1'>\n" ).arg( mTabStyle );
  mReport += compareHead();

  compare( "Band count", verifiedProvider->bandCount(), expectedProvider->bandCount(), mReport, ok );

  compare( "Width", verifiedProvider->xSize(), expectedProvider->xSize(), mReport, ok );
  compare( "Height", verifiedProvider->ySize(), expectedProvider->ySize(), mReport, ok );

  compareRow( "Extent", verifiedProvider->extent().toString(), expectedProvider->extent().toString(), mReport, verifiedProvider->extent() == expectedProvider->extent() );

  if ( verifiedProvider->extent() != expectedProvider->extent() ) ok = false;


  mReport += "</table>\n";

  if ( !ok ) return false;

  bool allOk = true;
  for ( int band = 1; band <= expectedProvider->bandCount(); band++ )
  {
    bool bandOk = true;
    mReport += QString( "<h3>Band %1</h3>\n" ).arg( band );
    mReport += QString( "<table style='%1'>\n" ).arg( mTabStyle );
    mReport += compareHead();

    // Data types may differ (?)
    bool typesOk = true;
    compare( "Source data type", verifiedProvider->srcDataType( band ), expectedProvider->srcDataType( band ), mReport, typesOk );
    compare( "Data type", verifiedProvider->dataType( band ), expectedProvider->dataType( band ), mReport, typesOk ) ;

    // TODO: not yet sure if noDataValue() should exist at all
    //compare( "No data (NULL) value", verifiedProvider->noDataValue( band ), expectedProvider->noDataValue( band ), mReport, typesOk );

    bool statsOk = true;
    QgsRasterBandStats verifiedStats =  verifiedProvider->bandStatistics( band );
    QgsRasterBandStats expectedStats =  expectedProvider->bandStatistics( band );

    // Min/max may 'slightly' differ, for big numbers however, the difference may
    // be quite big, for example for Float32 with max -3.332e+38, the difference is 1.47338e+24
    double tol = tolerance( expectedStats.minimumValue );
    compare( "Minimum value", verifiedStats.minimumValue, expectedStats.minimumValue, mReport, statsOk, tol );
    tol = tolerance( expectedStats.maximumValue );
    compare( "Maximum value", verifiedStats.maximumValue, expectedStats.maximumValue, mReport, statsOk, tol );

    // TODO: enable once fixed (WCS excludes nulls but GDAL does not)
    //compare( "Cells count", verifiedStats.elementCount, expectedStats.elementCount, mReport, statsOk );

    tol = tolerance( expectedStats.mean );
    compare( "Mean", verifiedStats.mean, expectedStats.mean, mReport, statsOk, tol );

    // stdDev usually differ significantly
    tol = tolerance( expectedStats.stdDev, 1 );
    compare( "Standard deviation", verifiedStats.stdDev, expectedStats.stdDev, mReport, statsOk, tol );

    mReport += "</table>";
    mReport += "<br>";

    if ( !bandOk )
    {
      allOk = false;
      continue;
    }

    if ( !statsOk || !typesOk )
    {
      allOk = false;
      // create values table anyway so that values are available
    }

    mReport += "<table><tr>";
    mReport += "<td>Data comparison</td>";
    mReport += QString( "<td style='%1 %2 border: 1px solid'>correct&nbsp;value</td>" ).arg( mCellStyle ).arg( mOkStyle );
    mReport += "<td></td>";
    mReport += QString( "<td style='%1 %2 border: 1px solid'>wrong&nbsp;value<br>expected value</td></tr>" ).arg( mCellStyle ).arg( mErrStyle );
    mReport += "</tr></table>";
    mReport += "<br>";

    int width = expectedProvider->xSize();
    int height = expectedProvider->ySize();
    QgsRasterBlock *expectedBlock = expectedProvider->block( band, expectedProvider->extent(), width, height );
    QgsRasterBlock *verifiedBlock = verifiedProvider->block( band, expectedProvider->extent(), width, height );

    if ( !expectedBlock || !expectedBlock->isValid() ||
         !verifiedBlock || !verifiedBlock->isValid() )
    {
      allOk = false;
      mReport += "cannot read raster block";
      continue;
    }

    // compare data values
    QString htmlTable = QString( "<table style='%1'>" ).arg( mTabStyle );
    for ( int row = 0; row < height; row ++ )
    {
      htmlTable += "<tr>";
      for ( int col = 0; col < width; col ++ )
      {
        bool cellOk = true;
        double verifiedVal = verifiedBlock->value( row, col );
        double expectedVal = expectedBlock->value( row, col );

        QString valStr;
        if ( compare( verifiedVal, expectedVal, 0 ) )
        {
          valStr = QString( "%1" ).arg( verifiedVal );
        }
        else
        {
          cellOk = false;
          allOk = false;
          valStr = QString( "%1<br>%2" ).arg( verifiedVal ).arg( expectedVal );
        }
        htmlTable += QString( "<td style='%1 %2'>%3</td>" ).arg( mCellStyle ).arg( cellOk ? mOkStyle : mErrStyle ).arg( valStr );
      }
      htmlTable += "</tr>";
    }
    htmlTable += "</table>";

    mReport += htmlTable;

    delete expectedBlock;
    delete verifiedBlock;
  }
  delete verifiedProvider;
  delete expectedProvider;
  return allOk;
}
Beispiel #16
0
int QgsGrassGisLib::readRasterRow( int fd, void * buf, int row, RASTER_MAP_TYPE data_type, bool noDataAsZero )
{
    if ( row < 0 || row >= mRows )
    {
        QgsDebugMsg( QString( "row %1 out of range 0 - %2" ).arg( row ).arg( mRows ) );
        return 0;
    }

    // TODO: use cached block with more rows
    Raster raster = mRasters.value( fd );
    //if ( !raster.provider ) return -1;
    if ( !raster.input ) return -1;

    // Create extent for current row
    QgsRectangle blockRect = mExtent;
    double yRes = mExtent.height() / mRows;
    double yMax = mExtent.yMaximum() - yRes * row;
    //QgsDebugMsg( QString( "height = %1 mRows = %2" ).arg( mExtent.height() ).arg( mRows ) );
    //QgsDebugMsg( QString( "row = %1 yRes = %2 yRes * row = %3" ).arg( row ).arg( yRes ).arg( yRes * row ) );
    //QgsDebugMsg( QString( "mExtent.yMaximum() = %1 yMax = %2" ).arg( mExtent.yMaximum() ).arg( yMax ) );
    blockRect.setYMaximum( yMax );
    blockRect.setYMinimum( yMax - yRes );

    QgsRasterBlock *block = raster.input->block( raster.band, blockRect, mColumns, 1 );
    if ( !block ) return -1;

    QGis::DataType requestedType = qgisRasterType( data_type );

    //QgsDebugMsg( QString("data_type = %1").arg(data_type) );
    //QgsDebugMsg( QString("requestedType = %1").arg(requestedType) );
    //QgsDebugMsg( QString("requestedType size = %1").arg( QgsRasterBlock::typeSize( requestedType ) ) );
    //QgsDebugMsg( QString("block->dataType = %1").arg( block->dataType() ) );

    block->convert( requestedType );

    memcpy( buf, block->bits( 0 ), QgsRasterBlock::typeSize( requestedType ) * mColumns );

    for ( int i = 0; i < mColumns; i++ )
    {
        QgsDebugMsgLevel( QString( "row = %1 i = %2 val = %3 isNoData = %4" ).arg( row ).arg( i ).arg( block->value( i ) ).arg( block->isNoData( i ) ), 5 );
        //(( CELL * ) buf )[i] = i;
        if ( block->isNoData( 0, i ) )
        {
            if ( noDataAsZero )
            {
                switch ( data_type )
                {
                case CELL_TYPE:
                    G_zero(( char * ) &(( CELL * ) buf )[i], G_raster_size( data_type ) );
                    break;
                case FCELL_TYPE:
                    G_zero(( char * ) &(( FCELL * ) buf )[i], G_raster_size( data_type ) );
                    break;
                case DCELL_TYPE:
                    G_zero(( char * ) &(( DCELL * ) buf )[i], G_raster_size( data_type ) );
                    break;
                default:
                    break;
                }
            }
            else
            {
                switch ( data_type )
                {
                case CELL_TYPE:
                    G_set_c_null_value( &(( CELL * ) buf )[i], 1 );
                    break;
                case FCELL_TYPE:
                    G_set_f_null_value( &(( FCELL * ) buf )[i], 1 );
                    break;
                case DCELL_TYPE:
                    G_set_d_null_value( &(( DCELL * ) buf )[i], 1 );
                    break;
                default:
                    break;
                }
            }
        }
        //else
        //{
        //memcpy( &( buf[i] ), block->bits( 0, i ), 4 );
        //buf[i] = (int)  block->value( 0, i);
        //QgsDebugMsg( QString("buf[i] = %1").arg(buf[i]));
        //}
    }
    delete block;
    return 1;

}
Beispiel #17
0
// Default implementation for values
QgsRasterIdentifyResult QgsRasterDataProvider::identify( const QgsPointXY &point, QgsRaster::IdentifyFormat format, const QgsRectangle &boundingBox, int width, int height, int /*dpi*/ )
{
  QgsDebugMsgLevel( "Entered", 4 );
  QMap<int, QVariant> results;

  if ( format != QgsRaster::IdentifyFormatValue || !( capabilities() & IdentifyValue ) )
  {
    QgsDebugMsg( "Format not supported" );
    return QgsRasterIdentifyResult( ERR( tr( "Format not supported" ) ) );
  }

  if ( !extent().contains( point ) )
  {
    // Outside the raster
    for ( int bandNo = 1; bandNo <= bandCount(); bandNo++ )
    {
      results.insert( bandNo, QVariant() );
    }
    return QgsRasterIdentifyResult( QgsRaster::IdentifyFormatValue, results );
  }

  QgsRectangle finalExtent = boundingBox;
  if ( finalExtent.isEmpty() )
    finalExtent = extent();

  if ( width == 0 )
  {
    width = capabilities() & Size ? xSize() : 1000;
  }
  if ( height == 0 )
  {
    height = capabilities() & Size ? ySize() : 1000;
  }

  // Calculate the row / column where the point falls
  double xres = ( finalExtent.width() ) / width;
  double yres = ( finalExtent.height() ) / height;

  int col = static_cast< int >( std::floor( ( point.x() - finalExtent.xMinimum() ) / xres ) );
  int row = static_cast< int >( std::floor( ( finalExtent.yMaximum() - point.y() ) / yres ) );

  double xMin = finalExtent.xMinimum() + col * xres;
  double xMax = xMin + xres;
  double yMax = finalExtent.yMaximum() - row * yres;
  double yMin = yMax - yres;
  QgsRectangle pixelExtent( xMin, yMin, xMax, yMax );

  for ( int i = 1; i <= bandCount(); i++ )
  {
    QgsRasterBlock *myBlock = block( i, pixelExtent, 1, 1 );

    if ( myBlock )
    {
      double value = myBlock->value( 0 );

      results.insert( i, value );
      delete myBlock;
    }
    else
    {
      results.insert( i, QVariant() );
    }
  }
  return QgsRasterIdentifyResult( QgsRaster::IdentifyFormatValue, results );
}
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;
}