Skip to content

Commit b83ae21

Browse files
author
rblazek
committed
GDALWarpOperation -> GDALRasterIO
git-svn-id: http://svn.osgeo.org/qgis/trunk/qgis@15418 c8812cc2-4d05-0410-92ff-de0c093fc19c
1 parent 1e9e753 commit b83ae21

File tree

3 files changed

+218
-1
lines changed

3 files changed

+218
-1
lines changed

src/core/qgsrasterdataprovider.cpp

+52
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222

2323
#include <QTime>
2424
#include <QMap>
25+
#include <QByteArray>
2526

2627
void QgsRasterDataProvider::readBlock( int bandNo, QgsRectangle const & viewExtent, int width, int height, QgsCoordinateReferenceSystem theSrcCRS, QgsCoordinateReferenceSystem theDestCRS, void *data )
2728
{
@@ -179,4 +180,55 @@ QString QgsRasterDataProvider::lastErrorFormat()
179180
return "text/plain";
180181
}
181182

183+
QByteArray QgsRasterDataProvider::noValueBytes( int theBandNo )
184+
{
185+
int type = dataType(theBandNo);
186+
int size = dataTypeSize(theBandNo) / 8;
187+
QByteArray ba;
188+
ba.resize(size);
189+
char * data = ba.data();
190+
double noval = mNoDataValue[theBandNo-1];
191+
unsigned char uc;
192+
unsigned short us;
193+
short s;
194+
unsigned int ui;
195+
int i;
196+
float f;
197+
double d;
198+
switch (type)
199+
{
200+
case QgsRasterDataProvider::Byte:
201+
uc = (unsigned char)noval;
202+
memcpy ( data, &uc, size);
203+
break;
204+
case QgsRasterDataProvider::UInt16:
205+
us = (unsigned short)noval;
206+
memcpy ( data, &us, size);
207+
break;
208+
case QgsRasterDataProvider::Int16:
209+
s = (short)noval;
210+
memcpy ( data, &s, size);
211+
break;
212+
case QgsRasterDataProvider::UInt32:
213+
ui = (unsigned int)noval;
214+
memcpy ( data, &ui, size);
215+
break;
216+
case QgsRasterDataProvider::Int32:
217+
i = (int)noval;
218+
memcpy ( data, &i, size);
219+
break;
220+
case QgsRasterDataProvider::Float32:
221+
f = (float)noval;
222+
memcpy ( data, &f, size);
223+
break;
224+
case QgsRasterDataProvider::Float64:
225+
d = (double)noval;
226+
memcpy ( data, &d, size);
227+
break;
228+
default:
229+
QgsLogger::warning( "GDAL data type is not supported" );
230+
}
231+
return ba;
232+
}
233+
182234
// ENDS

src/core/qgsrasterdataprovider.h

+3
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
class QImage;
3434
class QgsPoint;
3535
class QgsRasterBandStats;
36+
class QByteArray;
3637

3738
#define TINY_VALUE std::numeric_limits<double>::epsilon() * 20
3839

@@ -456,6 +457,8 @@ class CORE_EXPORT QgsRasterDataProvider : public QgsDataProvider
456457
static QString makeTableCell( QString const & value );
457458
static QString makeTableCells( QStringList const & values );
458459

460+
/** \brief Set null value in char */
461+
QByteArray noValueBytes(int theBandNo);
459462

460463
protected:
461464
/**Dots per intch. Extended WMS (e.g. QGIS mapserver) support DPI dependent output and therefore

src/providers/gdal/qgsgdalprovider.cpp

+163-1
Original file line numberDiff line numberDiff line change
@@ -510,6 +510,9 @@ QImage* QgsGdalProvider::draw( QgsRectangle const & viewExtent, int pixelWidth,
510510

511511
void QgsGdalProvider::readBlock( int theBandNo, int xBlock, int yBlock, void *block )
512512
{
513+
// TODO!!!: Check data alignment!!! May it happen that nearest value which
514+
// is not nearest is assigned to an output cell???
515+
513516
QgsDebugMsg( "Entered" );
514517

515518
QgsDebugMsg( "yBlock = " + QString::number( yBlock ) );
@@ -528,7 +531,165 @@ void QgsGdalProvider::readBlock( int theBandNo, QgsRectangle const & theExtent,
528531
QgsDebugMsg( "thePixelWidth = " + QString::number( thePixelWidth ) );
529532
QgsDebugMsg( "thePixelHeight = " + QString::number( thePixelHeight ) );
530533
QgsDebugMsg( "theExtent: " + theExtent.toString() );
531-
QgsDebugMsg( "crs(): " + crs().toWkt() );
534+
535+
// TODO: fill block with no data values
536+
537+
QgsRectangle myRasterExtent = theExtent.intersect( &mExtent );
538+
if ( myRasterExtent.isEmpty() )
539+
{
540+
QgsDebugMsg( "draw request outside view extent." );
541+
return;
542+
}
543+
QgsDebugMsg( "myRasterExtent: " + myRasterExtent.toString() );
544+
545+
double xRes = theExtent.width()/thePixelWidth;
546+
double yRes = theExtent.height()/thePixelHeight;
547+
548+
// Find top, bottom rows and left, right column the raster extent covers
549+
// These are limits in target grid space
550+
int top = 0;
551+
int bottom = thePixelHeight-1;
552+
int left = 0;
553+
int right = thePixelWidth-1;
554+
555+
if ( myRasterExtent.yMaximum() < theExtent.yMaximum() )
556+
{
557+
top = static_cast<int> ( round( ( theExtent.yMaximum() - myRasterExtent.yMaximum() ) / yRes ) );
558+
}
559+
if ( myRasterExtent.yMinimum() > theExtent.yMinimum() )
560+
{
561+
bottom = static_cast<int> ( round( ( theExtent.yMaximum() - myRasterExtent.yMinimum() ) / yRes ) - 1 );
562+
}
563+
564+
if ( myRasterExtent.xMinimum() > theExtent.xMinimum() )
565+
{
566+
left = static_cast<int> ( round( ( myRasterExtent.xMinimum() - theExtent.xMinimum() ) / xRes ) );
567+
}
568+
if ( myRasterExtent.xMaximum() < theExtent.xMaximum() )
569+
{
570+
right = static_cast<int> ( round( ( myRasterExtent.xMaximum() - theExtent.xMinimum() ) / xRes ) - 1 );
571+
}
572+
QgsDebugMsg( QString("top = %1 bottom = %2 left = %3 right = %4").arg(top).arg(bottom).arg(left).arg(right) );
573+
574+
// We want to avoid another resampling, so we read data approximately with
575+
// the same resolution as requested and exactly the width/height we need.
576+
577+
// Calculate rows/cols limits in raster grid space
578+
579+
// IMHO, we cannot align target grid to raster grid using target grid edges
580+
// and finding the nearest raster grid because it could lead to cell center
581+
// getting outside the right cell when doing resampling, example
582+
// Raster width is 30m and it has 3 columns and we want to read xrange 5.1-30
583+
// to 3 columns, the nearest edge for beginning in raster grid is 10.0
584+
// reading cols 1-2, we get raster[1] value in target[0], but the center of
585+
// target[0] is 5.1 + ((30-5.1)/3)/2 = 9.25 so it falls to raster[0]. Is it right?
586+
// => We are looking for such alignment with which the center of first/last cell
587+
// alls to the right raster cell
588+
589+
double center, centerRaster;
590+
int rasterTop, rasterBottom, rasterLeft, rasterRight;
591+
592+
// top
593+
center = myRasterExtent.yMaximum() - yRes/2;
594+
// center in raster space
595+
// GDAL states that mGeoTransform[3] is top, but probably it can be also bottom
596+
// if mGeoTransform[5] is negative
597+
if ( mGeoTransform[5] > 0 )
598+
{
599+
centerRaster = ( mGeoTransform[3] - center ) / mGeoTransform[5];
600+
}
601+
else
602+
{
603+
centerRaster = ( center - mGeoTransform[3] ) / mGeoTransform[5];
604+
}
605+
rasterTop = static_cast<int> ( floor ( centerRaster ) );
606+
607+
// bottom
608+
center = myRasterExtent.yMinimum() + yRes/2;
609+
if ( mGeoTransform[5] > 0 )
610+
{
611+
centerRaster = ( mGeoTransform[3] - center ) / mGeoTransform[5];
612+
}
613+
else
614+
{
615+
centerRaster = ( center - mGeoTransform[3] ) / mGeoTransform[5];
616+
}
617+
rasterBottom = static_cast<int> ( floor ( centerRaster ) );
618+
619+
// left
620+
center = myRasterExtent.xMinimum() + xRes/2;
621+
centerRaster = ( center - mGeoTransform[0] ) / mGeoTransform[1];
622+
rasterLeft = static_cast<int> ( floor ( centerRaster ) );
623+
624+
// right
625+
center = myRasterExtent.xMaximum() - xRes/2;
626+
centerRaster = ( center - mGeoTransform[0] ) / mGeoTransform[1];
627+
rasterRight = static_cast<int> ( floor ( centerRaster ) );
628+
629+
QgsDebugMsg( QString("rasterTop = %1 rasterBottom = %2 rasterLeft = %3 rasterRight = %4").arg(rasterTop).arg(rasterBottom).arg(rasterLeft).arg(rasterRight) );
630+
631+
// Allocate temporary block
632+
int width = right - left + 1;
633+
int height = bottom - top + 1;
634+
635+
int rasterWidth = rasterRight - rasterLeft + 1;
636+
int rasterHeight = rasterBottom - rasterTop + 1;
637+
638+
QgsDebugMsg( QString("width = %1 height = %2 rasterWidth = %3 rasterHeight = %4").arg(width).arg(height).arg(rasterWidth).arg(rasterHeight) );
639+
640+
int size = dataTypeSize(theBandNo) / 8;
641+
642+
// fill with null values
643+
QByteArray ba = noValueBytes(theBandNo);
644+
char *nodata = ba.data();
645+
char *block = (char *) theBlock;
646+
for ( int i = 0; i < thePixelWidth * thePixelHeight; i++ )
647+
{
648+
memcpy ( block, nodata, size );
649+
block += size;
650+
}
651+
652+
GDALRasterBandH gdalBand = GDALGetRasterBand( mGdalDataset, theBandNo );
653+
654+
// Calc beginnig of data if raster does not start at top
655+
block = (char *) theBlock;
656+
if ( top != 0 )
657+
{
658+
block += size * thePixelWidth * top;
659+
}
660+
661+
// Cal nLineSpace if raster does not cover whole extent
662+
int nLineSpace = size * thePixelWidth;
663+
if ( left != 0 ) {
664+
block += size * left;
665+
}
666+
667+
GDALDataType type = ( GDALDataType )mGdalDataType[theBandNo-1];
668+
669+
CPLErrorReset();
670+
CPLErr err = GDALRasterIO( gdalBand, GF_Read,
671+
rasterLeft, rasterTop, rasterWidth, rasterHeight,
672+
(void *)block,
673+
width, height, type,
674+
0, nLineSpace );
675+
676+
if ( err != CPLE_None )
677+
{
678+
QgsLogger::warning( "RasterIO error: " + QString::fromUtf8( CPLGetLastErrorMsg() ) );
679+
QgsDebugMsg ( "RasterIO error: " + QString::fromUtf8( CPLGetLastErrorMsg() ) );
680+
}
681+
682+
683+
}
684+
685+
// this is old version which was using GDALWarpOperation, unfortunately
686+
// it may be very slow on large datasets
687+
#if 0
688+
void QgsGdalProvider::readBlock( int theBandNo, QgsRectangle const & theExtent, int thePixelWidth, int thePixelHeight, void *theBlock )
689+
{
690+
QgsDebugMsg( "thePixelWidth = " + QString::number( thePixelWidth ) );
691+
QgsDebugMsg( "thePixelHeight = " + QString::number( thePixelHeight ) );
692+
QgsDebugMsg( "theExtent: " + theExtent.toString() );
532693

533694
QString myMemDsn;
534695
myMemDsn.sprintf( "DATAPOINTER = %p", theBlock );
@@ -672,6 +833,7 @@ void QgsGdalProvider::readBlock( int theBandNo, QgsRectangle const & theExtent,
672833
GDALClose( myGdalMemDataset );
673834

674835
}
836+
#endif
675837

676838
double QgsGdalProvider::noDataValue() const
677839
{

0 commit comments

Comments
 (0)