27 int theSrcDatumTransform,
28 int theDestDatumTransform,
30 int theDestRows,
int theDestCols,
31 double theMaxSrcXRes,
double theMaxSrcYRes,
34 , mSrcCRS( theSrcCRS )
35 , mDestCRS( theDestCRS )
36 , mSrcDatumTransform( theSrcDatumTransform )
37 , mDestDatumTransform( theDestDatumTransform )
38 , mDestExtent( theDestExtent )
39 , mExtent( theExtent )
40 , mDestRows( theDestRows ), mDestCols( theDestCols )
41 , pHelperTop( 0 ), pHelperBottom( 0 )
42 , mMaxSrcXRes( theMaxSrcXRes ), mMaxSrcYRes( theMaxSrcYRes )
54 int theDestRows,
int theDestCols,
55 double theMaxSrcXRes,
double theMaxSrcYRes,
58 , mSrcCRS( theSrcCRS )
59 , mDestCRS( theDestCRS )
60 , mSrcDatumTransform( -1 )
61 , mDestDatumTransform( -1 )
62 , mDestExtent( theDestExtent )
63 , mExtent( theExtent )
64 , mDestRows( theDestRows ), mDestCols( theDestCols )
65 , pHelperTop( 0 ), pHelperBottom( 0 )
66 , mMaxSrcXRes( theMaxSrcXRes ), mMaxSrcYRes( theMaxSrcYRes )
77 double theMaxSrcXRes,
double theMaxSrcYRes,
80 , mSrcCRS( theSrcCRS )
81 , mDestCRS( theDestCRS )
82 , mSrcDatumTransform( -1 )
83 , mDestDatumTransform( -1 )
84 , mExtent( theExtent )
93 , mDestRowsPerMatrixRow( 0.0 )
94 , mDestColsPerMatrixCol( 0.0 )
95 , pHelperTop( 0 ), pHelperBottom( 0 )
99 , mSqrTolerance( 0.0 )
100 , mMaxSrcXRes( theMaxSrcXRes )
101 , mMaxSrcYRes( theMaxSrcYRes )
102 , mApproximate( false )
109 , mSrcDatumTransform( -1 )
110 , mDestDatumTransform( -1 )
119 , mDestRowsPerMatrixRow( 0.0 )
120 , mDestColsPerMatrixCol( 0.0 )
126 , mSqrTolerance( 0.0 )
129 , mApproximate( false )
137 , pHelperBottom( NULL )
142 , mApproximate( false )
144 mSrcCRS = projector.mSrcCRS;
145 mDestCRS = projector.mDestCRS;
146 mSrcDatumTransform = projector.mSrcDatumTransform;
147 mDestDatumTransform = projector.mDestDatumTransform;
148 mMaxSrcXRes = projector.mMaxSrcXRes;
149 mMaxSrcYRes = projector.mMaxSrcYRes;
150 mExtent = projector.mExtent;
151 mDestRows = projector.mDestRows;
152 mDestCols = projector.mDestCols;
153 mDestXRes = projector.mDestXRes;
154 mDestYRes = projector.mDestYRes;
155 mSrcRows = projector.mSrcRows;
156 mSrcCols = projector.mSrcCols;
157 mSrcXRes = projector.mSrcXRes;
158 mSrcYRes = projector.mSrcYRes;
159 mDestRowsPerMatrixRow = projector.mDestRowsPerMatrixRow;
160 mDestColsPerMatrixCol = projector.mDestColsPerMatrixCol;
166 if ( &projector !=
this )
168 mSrcCRS = projector.mSrcCRS;
169 mDestCRS = projector.mDestCRS;
170 mSrcDatumTransform = projector.mSrcDatumTransform;
171 mDestDatumTransform = projector.mDestDatumTransform;
172 mMaxSrcXRes = projector.mMaxSrcXRes;
173 mMaxSrcYRes = projector.mMaxSrcYRes;
174 mExtent = projector.mExtent;
183 projector->mSrcDatumTransform = mSrcDatumTransform;
184 projector->mDestDatumTransform = mDestDatumTransform;
191 delete[] pHelperBottom;
211 mDestCRS = theDestCRS;
212 mSrcDatumTransform = srcDatumTransform;
213 mDestDatumTransform = destDatumTransform;
216 void QgsRasterProjector::calc()
220 mCPLegalMatrix.clear();
223 delete[] pHelperBottom;
242 mExtent = provider->
extent();
247 mDestXRes = mDestExtent.
width() / ( mDestCols );
248 mDestYRes = mDestExtent.
height() / ( mDestRows );
254 double myDestRes = mDestXRes < mDestYRes ? mDestXRes : mDestYRes;
255 mSqrTolerance = myDestRes * myDestRes;
260 mCPCols = mCPRows = 3;
261 for (
int i = 0; i < mCPRows; i++ )
263 QList<QgsPoint> myRow;
267 mCPMatrix.insert( i, myRow );
269 QList<bool> myLegalRow;
270 myLegalRow.append(
bool(
false ) );
271 myLegalRow.append(
bool(
false ) );
272 myLegalRow.append(
bool(
false ) );
273 mCPLegalMatrix.insert( i, myLegalRow );
275 for (
int i = 0; i < mCPRows; i++ )
277 calcRow( i, inverseCt );
282 bool myColsOK = checkCols( inverseCt );
285 insertRows( inverseCt );
287 bool myRowsOK = checkRows( inverseCt );
290 insertCols( inverseCt );
292 if ( myColsOK && myRowsOK )
300 if ( mCPRows * mCPCols > 0.25 * mDestRows * mDestCols )
303 mApproximate =
false;
307 QgsDebugMsg( QString(
"CPMatrix size: mCPRows = %1 mCPCols = %2" ).arg( mCPRows ).arg( mCPCols ) );
308 mDestRowsPerMatrixRow = ( float )mDestRows / ( mCPRows - 1 );
309 mDestColsPerMatrixCol = ( float )mDestCols / ( mCPCols - 1 );
317 mSrcYRes = mSrcExtent.
height() / mSrcRows;
318 mSrcXRes = mSrcExtent.
width() / mSrcCols;
321 pHelperTop =
new QgsPoint[mDestCols];
322 pHelperBottom =
new QgsPoint[mDestCols];
323 calcHelper( 0, pHelperTop );
324 calcHelper( 1, pHelperBottom );
328 void QgsRasterProjector::calcSrcExtent()
337 mSrcExtent =
QgsRectangle( myPoint.
x(), myPoint.
y(), myPoint.
x(), myPoint.
y() );
338 for (
int i = 0; i < mCPRows; i++ )
340 for (
int j = 0; j < mCPCols ; j++ )
342 myPoint = mCPMatrix[i][j];
343 if ( mCPLegalMatrix[i][j] )
352 mSrcExtent = mSrcExtent.
intersect( &mExtent );
365 if ( mMaxSrcXRes > 0 )
368 double col = floor(( mSrcExtent.
xMinimum() - mExtent.
xMinimum() ) / mMaxSrcXRes );
369 double x = mExtent.
xMinimum() + col * mMaxSrcXRes;
373 x = mExtent.
xMinimum() + col * mMaxSrcXRes;
376 if ( mMaxSrcYRes > 0 )
378 double row = floor(( mExtent.
yMaximum() - mSrcExtent.
yMaximum() ) / mMaxSrcYRes );
379 double y = mExtent.
yMaximum() - row * mMaxSrcYRes;
383 y = mExtent.
yMaximum() - row * mMaxSrcYRes;
390 QString QgsRasterProjector::cpToString()
393 for (
int i = 0; i < mCPRows; i++ )
397 for (
int j = 0; j < mCPCols; j++ )
402 if ( mCPLegalMatrix[i][j] )
415 void QgsRasterProjector::calcSrcRowsCols()
424 double myDestColsPerMatrixCell = ( double )mDestCols / mCPCols;
425 double myDestRowsPerMatrixCell = ( double )mDestRows / mCPRows;
426 QgsDebugMsg( QString(
"myDestColsPerMatrixCell = %1 myDestRowsPerMatrixCell = %2" ).arg( myDestColsPerMatrixCell ).arg( myDestRowsPerMatrixCell ) );
428 double myMinSize = DBL_MAX;
430 for (
int i = 0; i < mCPRows - 1; i++ )
432 for (
int j = 0; j < mCPCols - 1; j++ )
434 QgsPoint myPointA = mCPMatrix[i][j];
435 QgsPoint myPointB = mCPMatrix[i][j+1];
436 QgsPoint myPointC = mCPMatrix[i+1][j];
437 if ( mCPLegalMatrix[i][j] && mCPLegalMatrix[i][j+1] && mCPLegalMatrix[i+1][j] )
439 double mySize = sqrt( myPointA.
sqrDist( myPointB ) ) / myDestColsPerMatrixCell;
440 if ( mySize < myMinSize )
443 mySize = sqrt( myPointA.
sqrDist( myPointC ) ) / myDestRowsPerMatrixCell;
444 if ( mySize < myMinSize )
455 QgsDebugMsg( QString(
"mMaxSrcXRes = %1 mMaxSrcYRes = %2" ).arg( mMaxSrcXRes ).arg( mMaxSrcYRes ) );
457 double myMinXSize = mMaxSrcXRes > myMinSize ? mMaxSrcXRes : myMinSize;
458 double myMinYSize = mMaxSrcYRes > myMinSize ? mMaxSrcYRes : myMinSize;
459 QgsDebugMsg( QString(
"myMinXSize = %1 myMinYSize = %2" ).arg( myMinXSize ).arg( myMinYSize ) );
460 QgsDebugMsg( QString(
"mSrcExtent.width = %1 mSrcExtent.height = %2" ).arg( mSrcExtent.
width() ).arg( mSrcExtent.
height() ) );
463 mSrcRows = ( int ) qRound( mSrcExtent.
height() / myMinYSize );
464 mSrcCols = ( int ) qRound( mSrcExtent.
width() / myMinXSize );
466 QgsDebugMsg( QString(
"mSrcRows = %1 mSrcCols = %2" ).arg( mSrcRows ).arg( mSrcCols ) );
470 inline void QgsRasterProjector::destPointOnCPMatrix(
int theRow,
int theCol,
double *theX,
double *theY )
472 *theX = mDestExtent.
xMinimum() + theCol * mDestExtent.
width() / ( mCPCols - 1 );
473 *theY = mDestExtent.
yMaximum() - theRow * mDestExtent.
height() / ( mCPRows - 1 );
476 inline int QgsRasterProjector::matrixRow(
int theDestRow )
478 return (
int )( floor(( theDestRow + 0.5 ) / mDestRowsPerMatrixRow ) );
480 inline int QgsRasterProjector::matrixCol(
int theDestCol )
482 return (
int )( floor(( theDestCol + 0.5 ) / mDestColsPerMatrixCol ) );
485 QgsPoint QgsRasterProjector::srcPoint(
int theDestRow,
int theCol )
487 Q_UNUSED( theDestRow );
492 void QgsRasterProjector::calcHelper(
int theMatrixRow,
QgsPoint *thePoints )
495 for (
int myDestCol = 0; myDestCol < mDestCols; myDestCol++ )
497 double myDestX = mDestExtent.
xMinimum() + ( myDestCol + 0.5 ) * mDestXRes;
499 int myMatrixCol = matrixCol( myDestCol );
501 double myDestXMin, myDestYMin, myDestXMax, myDestYMax;
503 destPointOnCPMatrix( theMatrixRow, myMatrixCol, &myDestXMin, &myDestYMin );
504 destPointOnCPMatrix( theMatrixRow, myMatrixCol + 1, &myDestXMax, &myDestYMax );
506 double xfrac = ( myDestX - myDestXMin ) / ( myDestXMax - myDestXMin );
508 QgsPoint &mySrcPoint0 = mCPMatrix[theMatrixRow][myMatrixCol];
509 QgsPoint &mySrcPoint1 = mCPMatrix[theMatrixRow][myMatrixCol+1];
510 double s = mySrcPoint0.
x() + ( mySrcPoint1.
x() - mySrcPoint0.
x() ) * xfrac;
511 double t = mySrcPoint0.
y() + ( mySrcPoint1.
y() - mySrcPoint0.
y() ) * xfrac;
513 thePoints[myDestCol].
setX( s );
514 thePoints[myDestCol].
setY( t );
517 void QgsRasterProjector::nextHelper()
522 pHelperTop = pHelperBottom;
524 calcHelper( mHelperTopRow + 2, pHelperBottom );
528 bool QgsRasterProjector::srcRowCol(
int theDestRow,
int theDestCol,
int *theSrcRow,
int *theSrcCol,
const QgsCoordinateTransform* ct )
532 return approximateSrcRowCol( theDestRow, theDestCol, theSrcRow, theSrcCol );
536 return preciseSrcRowCol( theDestRow, theDestCol, theSrcRow, theSrcCol, ct );
540 bool QgsRasterProjector::preciseSrcRowCol(
int theDestRow,
int theDestCol,
int *theSrcRow,
int *theSrcCol,
const QgsCoordinateTransform* ct )
544 QgsDebugMsgLevel( QString(
"theDestRow = %1 mDestExtent.yMaximum() = %2 mDestYRes = %3" ).arg( theDestRow ).arg( mDestExtent.
yMaximum() ).arg( mDestYRes ), 5 );
548 double x = mDestExtent.
xMinimum() + ( theDestCol + 0.5 ) * mDestXRes;
549 double y = mDestExtent.
yMaximum() - ( theDestRow + 0.5 ) * mDestYRes;
570 *theSrcRow = ( int ) floor(( mSrcExtent.
yMaximum() - y ) / mSrcYRes );
571 *theSrcCol = ( int ) floor(( x - mSrcExtent.
xMinimum() ) / mSrcXRes );
573 QgsDebugMsgLevel( QString(
"mSrcExtent.yMinimum() = %1 mSrcExtent.yMaximum() = %2 mSrcYRes = %3" ).arg( mSrcExtent.
yMinimum() ).arg( mSrcExtent.
yMaximum() ).arg( mSrcYRes ), 5 );
574 QgsDebugMsgLevel( QString(
"theSrcRow = %1 theSrcCol = %2" ).arg( *theSrcRow ).arg( *theSrcCol ), 5 );
581 if ( *theSrcRow >= mSrcRows )
return false;
582 if ( *theSrcRow < 0 )
return false;
583 if ( *theSrcCol >= mSrcCols )
return false;
584 if ( *theSrcCol < 0 )
return false;
589 bool QgsRasterProjector::approximateSrcRowCol(
int theDestRow,
int theDestCol,
int *theSrcRow,
int *theSrcCol )
591 int myMatrixRow = matrixRow( theDestRow );
592 int myMatrixCol = matrixCol( theDestCol );
594 if ( myMatrixRow > mHelperTopRow )
600 double myDestY = mDestExtent.
yMaximum() - ( theDestRow + 0.5 ) * mDestYRes;
604 double myDestXMin, myDestYMin, myDestXMax, myDestYMax;
606 destPointOnCPMatrix( myMatrixRow + 1, myMatrixCol, &myDestXMin, &myDestYMin );
607 destPointOnCPMatrix( myMatrixRow, myMatrixCol + 1, &myDestXMax, &myDestYMax );
609 double yfrac = ( myDestY - myDestYMin ) / ( myDestYMax - myDestYMin );
611 QgsPoint &myTop = pHelperTop[theDestCol];
612 QgsPoint &myBot = pHelperBottom[theDestCol];
618 double tx = myTop.
x();
619 double ty = myTop.
y();
620 double bx = myBot.
x();
621 double by = myBot.
y();
622 double mySrcX = bx + ( tx - bx ) * yfrac;
623 double mySrcY = by + ( ty - by ) * yfrac;
632 *theSrcRow = ( int ) floor(( mSrcExtent.
yMaximum() - mySrcY ) / mSrcYRes );
633 *theSrcCol = ( int ) floor(( mySrcX - mSrcExtent.
xMinimum() ) / mSrcXRes );
638 if ( *theSrcRow >= mSrcRows )
return false;
639 if ( *theSrcRow < 0 )
return false;
640 if ( *theSrcCol >= mSrcCols )
return false;
641 if ( *theSrcCol < 0 )
return false;
648 for (
int r = 0; r < mCPRows - 1; r++ )
650 QList<QgsPoint> myRow;
651 QList<bool> myLegalRow;
652 for (
int c = 0; c < mCPCols; c++ )
655 myLegalRow.append(
false );
658 mCPMatrix.insert( 1 + r*2, myRow );
659 mCPLegalMatrix.insert( 1 + r*2, myLegalRow );
661 mCPRows += mCPRows - 1;
662 for (
int r = 1; r < mCPRows - 1; r += 2 )
670 for (
int r = 0; r < mCPRows; r++ )
672 QList<QgsPoint> myRow;
673 QList<bool> myLegalRow;
674 for (
int c = 0; c < mCPCols - 1; c++ )
676 mCPMatrix[r].insert( 1 + c*2,
QgsPoint() );
677 mCPLegalMatrix[r].insert( 1 + c*2,
false );
680 mCPCols += mCPCols - 1;
681 for (
int c = 1; c < mCPCols - 1; c += 2 )
690 double myDestX, myDestY;
691 destPointOnCPMatrix( theRow, theCol, &myDestX, &myDestY );
692 QgsPoint myDestPoint( myDestX, myDestY );
697 mCPMatrix[theRow][theCol] = ct->
transform( myDestPoint );
698 mCPLegalMatrix[theRow][theCol] =
true;
702 mCPLegalMatrix[theRow][theCol] =
false;
709 mCPLegalMatrix[theRow][theCol] =
false;
716 for (
int i = 0; i < mCPCols; i++ )
718 calcCP( theRow, i, ct );
727 for (
int i = 0; i < mCPRows; i++ )
729 calcCP( i, theCol, ct );
742 for (
int c = 0; c < mCPCols; c++ )
744 for (
int r = 1; r < mCPRows - 1; r += 2 )
746 double myDestX, myDestY;
747 destPointOnCPMatrix( r, c, &myDestX, &myDestY );
748 QgsPoint myDestPoint( myDestX, myDestY );
750 QgsPoint mySrcPoint1 = mCPMatrix[r-1][c];
751 QgsPoint mySrcPoint2 = mCPMatrix[r][c];
752 QgsPoint mySrcPoint3 = mCPMatrix[r+1][c];
754 QgsPoint mySrcApprox(( mySrcPoint1.
x() + mySrcPoint3.
x() ) / 2, ( mySrcPoint1.
y() + mySrcPoint3.
y() ) / 2 );
755 if ( !mCPLegalMatrix[r-1][c] || !mCPLegalMatrix[r][c] || !mCPLegalMatrix[r+1][c] )
763 double mySqrDist = myDestApprox.
sqrDist( myDestPoint );
764 if ( mySqrDist > mSqrTolerance )
787 for (
int r = 0; r < mCPRows; r++ )
789 for (
int c = 1; c < mCPCols - 1; c += 2 )
791 double myDestX, myDestY;
792 destPointOnCPMatrix( r, c, &myDestX, &myDestY );
794 QgsPoint myDestPoint( myDestX, myDestY );
795 QgsPoint mySrcPoint1 = mCPMatrix[r][c-1];
796 QgsPoint mySrcPoint2 = mCPMatrix[r][c];
797 QgsPoint mySrcPoint3 = mCPMatrix[r][c+1];
799 QgsPoint mySrcApprox(( mySrcPoint1.
x() + mySrcPoint3.
x() ) / 2, ( mySrcPoint1.
y() + mySrcPoint3.
y() ) / 2 );
800 if ( !mCPLegalMatrix[r][c-1] || !mCPLegalMatrix[r][c] || !mCPLegalMatrix[r][c+1] )
808 double mySqrDist = myDestApprox.
sqrDist( myDestPoint );
809 if ( mySqrDist > mSqrTolerance )
828 QgsDebugMsg( QString(
"width = %1 height = %2" ).arg( width ).arg( height ) );
835 if ( ! mSrcCRS.
isValid() || ! mDestCRS.
isValid() || mSrcCRS == mDestCRS )
838 return mInput->
block( bandNo, extent, width, height );
846 QgsDebugMsg( QString(
"srcExtent:\n%1" ).arg( srcExtent().toString() ) );
847 QgsDebugMsg( QString(
"srcCols = %1 srcRows = %2" ).arg( srcCols() ).arg( srcRows() ) );
850 if ( srcRows() <= 0 || srcCols() <= 0 )
857 if ( !inputBlock || inputBlock->
isEmpty() )
875 if ( !outputBlock->isValid() )
903 outputBlock->setIsNoData();
906 for (
int i = 0; i < height; ++i )
908 for (
int j = 0; j < width; ++j )
910 bool inside = srcRowCol( i, j, &srcRow, &srcCol, inverseCt );
911 if ( !inside )
continue;
914 QgsDebugMsgLevel( QString(
"row = %1 col = %2 srcRow = %3 srcCol = %4" ).arg( i ).arg( j ).arg( srcRow ).arg( srcCol ), 5 );
917 if ( doNoData && inputBlock->
isNoData( srcRow, srcCol ) )
919 outputBlock->setIsNoData( i, j );
924 char *srcBits = inputBlock->
bits( srcIndex );
925 char *destBits = outputBlock->bits( destIndex );
928 QgsDebugMsg( QString(
"Cannot get input block data: row = %1 col = %2" ).arg( i ).arg( j ) );
933 QgsDebugMsg( QString(
"Cannot set output block data: srcRow = %1 srcCol = %2" ).arg( srcRow ).arg( srcCol ) );
936 memcpy( destBits, srcBits, pixelSize );
937 outputBlock->setIsData( i, j );
virtual int bandCount() const =0
Get number of bands.
A rectangle specified with double values.
bool isEmpty() const
test if rectangle is empty.
void setCRS(const QgsCoordinateReferenceSystem &theSrcCRS, const QgsCoordinateReferenceSystem &theDestCRS, int srcDatumTransform=-1, int destDatumTransform=-1)
set source and destination CRS
void setXMaximum(double x)
Set the maximum x value.
double yMaximum() const
Get the y maximum value (top side of rectangle)
static bool typeIsNumeric(QGis::DataType type)
Returns true if data type is numeric.
bool contains(const QgsRectangle &rect) const
return true when rectangle contains other rectangle
virtual const QgsRasterInterface * srcInput() const
Get source / raw input, the first in pipe, usually provider.
static QgsCoordinateTransformCache * instance()
double noDataValue() const
Return no data value.
QGis::DataType dataType() const
Returns data type.
double sqrDist(double x, double y) const
Returns the squared distance between this point and x,y.
bool isNoData(int row, int column)
Check if value at position is no data.
virtual int ySize() const
bool setIsNoData(int row, int column)
Set no data on pixel.
void combineExtentWith(QgsRectangle *rect)
expand the rectangle so that covers both the original rectangle and the given rectangle ...
~QgsRasterProjector()
The destructor.
bool hasNoData() const
Returns true if the block may contain no data.
double yMinimum() const
Get the y minimum value (bottom side of rectangle)
QgsRasterBlock * block(int bandNo, const QgsRectangle &extent, int width, int height) override
Read block of data using given extent and size.
double xMaximum() const
Get the x maximum value (right side of rectangle)
#define QgsDebugMsgLevel(str, level)
void setYMinimum(double y)
Set the minimum y value.
QString toString() const
String representation of the point (x,y)
static int typeSize(int dataType)
virtual QGis::DataType dataType(int bandNo) const =0
Returns data type for the band specified by number.
QgsRasterInterface * clone() const override
Clone itself, create deep copy.
Base class for processing filters like renderers, reprojector, resampler etc.
A class to represent a point.
unsigned long long qgssize
qgssize is used instead of size_t, because size_t is stdlib type, unknown by SIP, and it would be har...
virtual int capabilities() const
Returns a bitmask containing the supported capabilities.
virtual QgsRectangle extent() override=0
Get the extent of the data source.
virtual QgsRectangle extent()
Get the extent of the interface.
bool hasNoDataValue() const
True if the block has no data value.
char * bits(int row, int column)
Get pointer to data.
virtual int xSize() const
Get raster size.
void setYMaximum(double y)
Set the maximum y value.
QgsRectangle intersect(const QgsRectangle *rect) const
return the intersection with the given rectangle
Class for storing a coordinate reference system (CRS)
DataType
Raster data types.
virtual QgsRasterBlock * block(int bandNo, const QgsRectangle &extent, int width, int height)=0
Read block of data using given extent and size.
Custom exception class for Coordinate Reference System related exceptions.
QGis::DataType dataType(int bandNo) const override
Returns data type for the band specified by number.
double width() const
Width of the rectangle.
QgsRasterInterface * mInput
QgsRasterProjector & operator=(const QgsRasterProjector &projector)
QString toString(bool automaticPrecision=false) const
returns string representation of form xmin,ymin xmax,ymax
double xMinimum() const
Get the x minimum value (left side of rectangle)
void setXMinimum(double x)
Set the minimum x value.
double height() const
Height of the rectangle.
bool isEmpty() const
Returns true if block is empty, i.e.
int bandCount() const override
Get number of bands.
Base class for raster data providers.