QgsRasterBlock* QgsSingleBandColorDataRenderer::block( int bandNo, QgsRectangle const & extent, int width, int height, QgsRasterBlockFeedback* feedback ) { Q_UNUSED( bandNo ); QgsRasterBlock *outputBlock = new QgsRasterBlock(); if ( !mInput ) { return outputBlock; } QgsRasterBlock *inputBlock = mInput->block( mBand, extent, width, height, feedback ); if ( !inputBlock || inputBlock->isEmpty() ) { QgsDebugMsg( "No raster data!" ); delete inputBlock; return outputBlock; } bool hasTransparency = usesTransparency(); if ( !hasTransparency ) { // Nothing to do, just retype if necessary inputBlock->convert( Qgis::ARGB32_Premultiplied ); delete outputBlock; return inputBlock; } if ( !outputBlock->reset( Qgis::ARGB32_Premultiplied, width, height ) ) { delete inputBlock; return outputBlock; } // make sure input is also premultiplied! inputBlock->convert( Qgis::ARGB32_Premultiplied ); QRgb* inputBits = ( QRgb* )inputBlock->bits(); QRgb* outputBits = ( QRgb* )outputBlock->bits(); for ( qgssize i = 0; i < ( qgssize )width*height; i++ ) { QRgb c = inputBits[i]; outputBits[i] = qRgba( mOpacity * qRed( c ), mOpacity * qGreen( c ), mOpacity * qBlue( c ), mOpacity * qAlpha( c ) ); } delete inputBlock; return outputBlock; }
QgsRasterBlock *QgsRasterDataProvider::block( int bandNo, QgsRectangle const &boundingBox, int width, int height, QgsRasterBlockFeedback *feedback ) { QgsDebugMsgLevel( QString( "bandNo = %1 width = %2 height = %3" ).arg( bandNo ).arg( width ).arg( height ), 4 ); QgsDebugMsgLevel( QString( "boundingBox = %1" ).arg( boundingBox.toString() ), 4 ); QgsRasterBlock *block = new QgsRasterBlock( dataType( bandNo ), width, height ); if ( sourceHasNoDataValue( bandNo ) && useSourceNoDataValue( bandNo ) ) { block->setNoDataValue( sourceNoDataValue( bandNo ) ); } if ( block->isEmpty() ) { QgsDebugMsg( "Couldn't create raster block" ); return block; } // Read necessary extent only QgsRectangle tmpExtent = extent().intersect( &boundingBox ); if ( tmpExtent.isEmpty() ) { QgsDebugMsg( "Extent outside provider extent" ); block->setIsNoData(); return block; } double xRes = boundingBox.width() / width; double yRes = boundingBox.height() / height; double tmpXRes, tmpYRes; double providerXRes = 0; double providerYRes = 0; if ( capabilities() & Size ) { providerXRes = extent().width() / xSize(); providerYRes = extent().height() / ySize(); tmpXRes = std::max( providerXRes, xRes ); tmpYRes = std::max( providerYRes, yRes ); if ( qgsDoubleNear( tmpXRes, xRes ) ) tmpXRes = xRes; if ( qgsDoubleNear( tmpYRes, yRes ) ) tmpYRes = yRes; } else { tmpXRes = xRes; tmpYRes = yRes; } if ( tmpExtent != boundingBox || tmpXRes > xRes || tmpYRes > yRes ) { // Read smaller extent or lower resolution if ( !extent().contains( boundingBox ) ) { QRect subRect = QgsRasterBlock::subRect( boundingBox, width, height, extent() ); block->setIsNoDataExcept( subRect ); } // Calculate row/col limits (before tmpExtent is aligned) int fromRow = std::round( ( boundingBox.yMaximum() - tmpExtent.yMaximum() ) / yRes ); int toRow = std::round( ( boundingBox.yMaximum() - tmpExtent.yMinimum() ) / yRes ) - 1; int fromCol = std::round( ( tmpExtent.xMinimum() - boundingBox.xMinimum() ) / xRes ); int toCol = std::round( ( tmpExtent.xMaximum() - boundingBox.xMinimum() ) / xRes ) - 1; QgsDebugMsgLevel( QString( "fromRow = %1 toRow = %2 fromCol = %3 toCol = %4" ).arg( fromRow ).arg( toRow ).arg( fromCol ).arg( toCol ), 4 ); if ( fromRow < 0 || fromRow >= height || toRow < 0 || toRow >= height || fromCol < 0 || fromCol >= width || toCol < 0 || toCol >= width ) { // 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 = std::floor( ( tmpExtent.xMinimum() - extent().xMinimum() ) / providerXRes ); tmpExtent.setXMinimum( extent().xMinimum() + col * providerXRes ); col = std::ceil( ( tmpExtent.xMaximum() - extent().xMinimum() ) / providerXRes ); tmpExtent.setXMaximum( extent().xMinimum() + col * providerXRes ); } if ( tmpYRes > yRes ) { int row = std::floor( ( extent().yMaximum() - tmpExtent.yMaximum() ) / providerYRes ); tmpExtent.setYMaximum( extent().yMaximum() - row * providerYRes ); row = std::ceil( ( extent().yMaximum() - tmpExtent.yMinimum() ) / providerYRes ); tmpExtent.setYMinimum( extent().yMaximum() - row * providerYRes ); } int tmpWidth = std::round( tmpExtent.width() / tmpXRes ); int tmpHeight = std::round( tmpExtent.height() / tmpYRes ); tmpXRes = tmpExtent.width() / tmpWidth; tmpYRes = tmpExtent.height() / tmpHeight; QgsDebugMsgLevel( QString( "Reading smaller block tmpWidth = %1 height = %2" ).arg( tmpWidth ).arg( tmpHeight ), 4 ); QgsDebugMsgLevel( QString( "tmpExtent = %1" ).arg( tmpExtent.toString() ), 4 ); QgsRasterBlock *tmpBlock = new QgsRasterBlock( dataType( bandNo ), tmpWidth, tmpHeight ); if ( sourceHasNoDataValue( bandNo ) && useSourceNoDataValue( bandNo ) ) { tmpBlock->setNoDataValue( sourceNoDataValue( bandNo ) ); } readBlock( bandNo, tmpExtent, tmpWidth, tmpHeight, tmpBlock->bits(), feedback ); int pixelSize = dataTypeSize( bandNo ); double xMin = boundingBox.xMinimum(); double yMax = boundingBox.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 = std::floor( ( tmpYMax - y ) / tmpYRes ); for ( int col = fromCol; col <= toCol; col++ ) { double x = xMin + ( col + 0.5 ) * xRes; int tmpCol = std::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; } qgssize tmpIndex = static_cast< qgssize >( tmpRow ) * static_cast< qgssize >( tmpWidth ) + tmpCol; qgssize index = row * static_cast< qgssize >( width ) + 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( bandNo, boundingBox, width, height, block->bits(), feedback ); } // apply scale and offset block->applyScaleOffset( bandScale( bandNo ), bandOffset( bandNo ) ); // apply user no data values block->applyNoDataValues( userNoDataValues( bandNo ) ); return block; }
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; }
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 * QgsRasterProjector::block( int bandNo, QgsRectangle const & extent, int width, int height ) { QgsDebugMsg( QString( "extent:\n%1" ).arg( extent.toString() ) ); QgsDebugMsg( QString( "width = %1 height = %2" ).arg( width ).arg( height ) ); if ( !mInput ) { QgsDebugMsg( "Input not set" ); return new QgsRasterBlock(); } if ( ! mSrcCRS.isValid() || ! mDestCRS.isValid() || mSrcCRS == mDestCRS ) { QgsDebugMsg( "No projection necessary" ); return mInput->block( bandNo, extent, width, height ); } mDestExtent = extent; mDestRows = height; mDestCols = width; calc(); QgsDebugMsg( QString( "srcExtent:\n%1" ).arg( srcExtent().toString() ) ); QgsDebugMsg( QString( "srcCols = %1 srcRows = %2" ).arg( srcCols() ).arg( srcRows() ) ); // If we zoom out too much, projector srcRows / srcCols maybe 0, which can cause problems in providers if ( srcRows() <= 0 || srcCols() <= 0 ) { QgsDebugMsg( "Zero srcRows or srcCols" ); return new QgsRasterBlock(); } QgsRasterBlock *inputBlock = mInput->block( bandNo, srcExtent(), srcCols(), srcRows() ); if ( !inputBlock || inputBlock->isEmpty() ) { QgsDebugMsg( "No raster data!" ); delete inputBlock; return new QgsRasterBlock(); } qgssize pixelSize = QgsRasterBlock::typeSize( mInput->dataType( bandNo ) ); QgsRasterBlock *outputBlock; if ( inputBlock->hasNoDataValue() ) { outputBlock = new QgsRasterBlock( inputBlock->dataType(), width, height, inputBlock->noDataValue() ); } else { outputBlock = new QgsRasterBlock( inputBlock->dataType(), width, height ); } if ( !outputBlock->isValid() ) { QgsDebugMsg( "Cannot create block" ); delete inputBlock; return outputBlock; } // set output to no data, it should be fast outputBlock->setIsNoData(); // No data: because isNoData()/setIsNoData() is slow with respect to simple memcpy, // we use if only if necessary: // 1) no data value exists (numerical) -> memcpy, not necessary isNoData()/setIsNoData() // 2) no data value does not exist but it may contain no data (numerical no data bitmap) // -> must use isNoData()/setIsNoData() // 3) no data are not used (no no data value, no no data bitmap) -> simple memcpy // 4) image - simple memcpy // To copy no data values stored in bitmaps we have to use isNoData()/setIsNoData(), // we cannot fill output block with no data because we use memcpy for data, not setValue(). bool doNoData = !QgsRasterBlock::typeIsNumeric( inputBlock->dataType() ) && inputBlock->hasNoData() && !inputBlock->hasNoDataValue(); const QgsCoordinateTransform* inverseCt = nullptr; if ( !mApproximate ) { inverseCt = QgsCoordinateTransformCache::instance()->transform( mDestCRS.authid(), mSrcCRS.authid(), mDestDatumTransform, mSrcDatumTransform ); } outputBlock->setIsNoData(); int srcRow, srcCol; for ( int i = 0; i < height; ++i ) { for ( int j = 0; j < width; ++j ) { bool inside = srcRowCol( i, j, &srcRow, &srcCol, inverseCt ); if ( !inside ) continue; // we have everything set to no data qgssize srcIndex = ( qgssize )srcRow * mSrcCols + srcCol; QgsDebugMsgLevel( QString( "row = %1 col = %2 srcRow = %3 srcCol = %4" ).arg( i ).arg( j ).arg( srcRow ).arg( srcCol ), 5 ); // isNoData() may be slow so we check doNoData first if ( doNoData && inputBlock->isNoData( srcRow, srcCol ) ) { outputBlock->setIsNoData( i, j ); continue; } qgssize destIndex = ( qgssize )i * width + j; char *srcBits = inputBlock->bits( srcIndex ); char *destBits = outputBlock->bits( destIndex ); if ( !srcBits ) { QgsDebugMsg( QString( "Cannot get input block data: row = %1 col = %2" ).arg( i ).arg( j ) ); continue; } if ( !destBits ) { QgsDebugMsg( QString( "Cannot set output block data: srcRow = %1 srcCol = %2" ).arg( srcRow ).arg( srcCol ) ); continue; } memcpy( destBits, srcBits, pixelSize ); outputBlock->setIsData( i, j ); } } delete inputBlock; return outputBlock; }
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() ) ); }
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 block->applyNodataValues( userNoDataValue( theBandNo ) ); return block; }