QGIS API Documentation  2.7.0-Master
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
qgsrasterdataprovider.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsrasterdataprovider.cpp - DataProvider Interface for raster layers
3  --------------------------------------
4  Date : Mar 11, 2005
5  Copyright : (C) 2005 by Brendan Morley
6  email : morb at ozemail dot com dot au
7  ***************************************************************************/
8 
9 /***************************************************************************
10  * *
11  * This program is free software; you can redistribute it and/or modify *
12  * it under the terms of the GNU General Public License as published by *
13  * the Free Software Foundation; either version 2 of the License, or *
14  * (at your option) any later version. *
15  * *
16  ***************************************************************************/
17 
18 #include "qgsproviderregistry.h"
19 #include "qgsrasterdataprovider.h"
21 #include "qgsrasterprojector.h"
22 #include "qgslogger.h"
23 
24 #include <QTime>
25 #include <QMap>
26 #include <QByteArray>
27 #include <QVariant>
28 
29 #include <qmath.h>
30 
31 #define ERRMSG(message) QGS_ERROR_MESSAGE(message, "Raster provider")
32 #define ERR(message) QgsError(message, "Raster provider")
33 
34 void QgsRasterDataProvider::setUseSrcNoDataValue( int bandNo, bool use )
35 {
36  if ( mUseSrcNoDataValue.size() < bandNo )
37  {
38  for ( int i = mUseSrcNoDataValue.size(); i < bandNo; i++ )
39  {
40  mUseSrcNoDataValue.append( false );
41  }
42  }
43  mUseSrcNoDataValue[bandNo-1] = use;
44 }
45 
46 QgsRasterBlock * QgsRasterDataProvider::block( int theBandNo, QgsRectangle const & theExtent, int theWidth, int theHeight )
47 {
48  QgsDebugMsg( QString( "theBandNo = %1 theWidth = %2 theHeight = %3" ).arg( theBandNo ).arg( theWidth ).arg( theHeight ) );
49  QgsDebugMsg( QString( "theExtent = %1" ).arg( theExtent.toString() ) );
50 
52  if ( srcHasNoDataValue( theBandNo ) && useSrcNoDataValue( theBandNo ) )
53  {
54  block = new QgsRasterBlock( dataType( theBandNo ), theWidth, theHeight, srcNoDataValue( theBandNo ) );
55  }
56  else
57  {
58  block = new QgsRasterBlock( dataType( theBandNo ), theWidth, theHeight );
59  }
60 
61  if ( block->isEmpty() )
62  {
63  QgsDebugMsg( "Couldn't create raster block" );
64  return block;
65  }
66 
67  // Read necessary extent only
68  QgsRectangle tmpExtent = extent().intersect( &theExtent );
69 
70  if ( tmpExtent.isEmpty() )
71  {
72  QgsDebugMsg( "Extent outside provider extent" );
73  block->setIsNoData();
74  return block;
75  }
76 
77  double xRes = theExtent.width() / theWidth;
78  double yRes = theExtent.height() / theHeight;
79  double tmpXRes, tmpYRes;
80  double providerXRes = 0;
81  double providerYRes = 0;
82  if ( capabilities() & Size )
83  {
84  providerXRes = extent().width() / xSize();
85  providerYRes = extent().height() / ySize();
86  tmpXRes = qMax( providerXRes, xRes );
87  tmpYRes = qMax( providerYRes, yRes );
88  if ( qgsDoubleNear( tmpXRes, xRes ) ) tmpXRes = xRes;
89  if ( qgsDoubleNear( tmpYRes, yRes ) ) tmpYRes = yRes;
90  }
91  else
92  {
93  tmpXRes = xRes;
94  tmpYRes = yRes;
95  }
96 
97  if ( tmpExtent != theExtent ||
98  tmpXRes > xRes || tmpYRes > yRes )
99  {
100  // Read smaller extent or lower resolution
101 
102  if ( !extent().contains( theExtent ) )
103  {
104  QRect subRect = QgsRasterBlock::subRect( theExtent, theWidth, theHeight, extent() );
105  block->setIsNoDataExcept( subRect );
106  }
107 
108  // Calculate row/col limits (before tmpExtent is aligned)
109  int fromRow = qRound(( theExtent.yMaximum() - tmpExtent.yMaximum() ) / yRes );
110  int toRow = qRound(( theExtent.yMaximum() - tmpExtent.yMinimum() ) / yRes ) - 1;
111  int fromCol = qRound(( tmpExtent.xMinimum() - theExtent.xMinimum() ) / xRes );
112  int toCol = qRound(( tmpExtent.xMaximum() - theExtent.xMinimum() ) / xRes ) - 1;
113 
114  QgsDebugMsg( QString( "fromRow = %1 toRow = %2 fromCol = %3 toCol = %4" ).arg( fromRow ).arg( toRow ).arg( fromCol ).arg( toCol ) );
115 
116  if ( fromRow < 0 || fromRow >= theHeight || toRow < 0 || toRow >= theHeight ||
117  fromCol < 0 || fromCol >= theWidth || toCol < 0 || toCol >= theWidth )
118  {
119  // Should not happen
120  QgsDebugMsg( "Row or column limits out of range" );
121  return block;
122  }
123 
124  // If lower source resolution is used, the extent must beS aligned to original
125  // resolution to avoid possible shift due to resampling
126  if ( tmpXRes > xRes )
127  {
128  int col = floor(( tmpExtent.xMinimum() - extent().xMinimum() ) / providerXRes );
129  tmpExtent.setXMinimum( extent().xMinimum() + col * providerXRes );
130  col = ceil(( tmpExtent.xMaximum() - extent().xMinimum() ) / providerXRes );
131  tmpExtent.setXMaximum( extent().xMinimum() + col * providerXRes );
132  }
133  if ( tmpYRes > yRes )
134  {
135  int row = floor(( extent().yMaximum() - tmpExtent.yMaximum() ) / providerYRes );
136  tmpExtent.setYMaximum( extent().yMaximum() - row * providerYRes );
137  row = ceil(( extent().yMaximum() - tmpExtent.yMinimum() ) / providerYRes );
138  tmpExtent.setYMinimum( extent().yMaximum() - row * providerYRes );
139  }
140  int tmpWidth = qRound( tmpExtent.width() / tmpXRes );
141  int tmpHeight = qRound( tmpExtent.height() / tmpYRes );
142  tmpXRes = tmpExtent.width() / tmpWidth;
143  tmpYRes = tmpExtent.height() / tmpHeight;
144 
145  QgsDebugMsg( QString( "Reading smaller block tmpWidth = %1 theHeight = %2" ).arg( tmpWidth ).arg( tmpHeight ) );
146  QgsDebugMsg( QString( "tmpExtent = %1" ).arg( tmpExtent.toString() ) );
147 
148  QgsRasterBlock *tmpBlock;
149  if ( srcHasNoDataValue( theBandNo ) && useSrcNoDataValue( theBandNo ) )
150  {
151  tmpBlock = new QgsRasterBlock( dataType( theBandNo ), tmpWidth, tmpHeight, srcNoDataValue( theBandNo ) );
152  }
153  else
154  {
155  tmpBlock = new QgsRasterBlock( dataType( theBandNo ), tmpWidth, tmpHeight );
156  }
157 
158  readBlock( theBandNo, tmpExtent, tmpWidth, tmpHeight, tmpBlock->bits() );
159 
160  int pixelSize = dataTypeSize( theBandNo );
161 
162  double xMin = theExtent.xMinimum();
163  double yMax = theExtent.yMaximum();
164  double tmpXMin = tmpExtent.xMinimum();
165  double tmpYMax = tmpExtent.yMaximum();
166 
167  for ( int row = fromRow; row <= toRow; row++ )
168  {
169  double y = yMax - ( row + 0.5 ) * yRes;
170  int tmpRow = floor(( tmpYMax - y ) / tmpYRes );
171 
172  for ( int col = fromCol; col <= toCol; col++ )
173  {
174  double x = xMin + ( col + 0.5 ) * xRes;
175  int tmpCol = floor(( x - tmpXMin ) / tmpXRes );
176 
177  if ( tmpRow < 0 || tmpRow >= tmpHeight || tmpCol < 0 || tmpCol >= tmpWidth )
178  {
179  QgsDebugMsg( "Source row or column limits out of range" );
180  block->setIsNoData(); // so that the problem becomes obvious and fixed
181  delete tmpBlock;
182  return block;
183  }
184 
185  qgssize tmpIndex = tmpRow * tmpWidth + tmpCol;
186  qgssize index = row * theWidth + col;
187 
188  char *tmpBits = tmpBlock->bits( tmpIndex );
189  char *bits = block->bits( index );
190  if ( !tmpBits )
191  {
192  QgsDebugMsg( QString( "Cannot get input block data tmpRow = %1 tmpCol = %2 tmpIndex = %3." ).arg( tmpRow ).arg( tmpCol ).arg( tmpIndex ) );
193  continue;
194  }
195  if ( !bits )
196  {
197  QgsDebugMsg( "Cannot set output block data." );
198  continue;
199  }
200  memcpy( bits, tmpBits, pixelSize );
201  }
202  }
203 
204  delete tmpBlock;
205  }
206  else
207  {
208  readBlock( theBandNo, theExtent, theWidth, theHeight, block->bits() );
209  }
210 
211  // apply scale and offset
212  block->applyScaleOffset( bandScale( theBandNo ), bandOffset( theBandNo ) );
213  // apply user no data values
214  block->applyNoDataValues( userNoDataValues( theBandNo ) );
215  return block;
216 }
217 
219  : QgsRasterInterface( 0 )
220  , mDpi( -1 )
221 {
222 }
223 
225  : QgsDataProvider( uri )
226  , QgsRasterInterface( 0 )
227  , mDpi( -1 )
228 {
229 }
230 
231 //
232 //Random Static convenience function
233 //
235 // convenience function for building metadata() HTML table cells
236 // convenience function for creating a string list from a C style string list
237 QStringList QgsRasterDataProvider::cStringList2Q_( char ** stringList )
238 {
239  QStringList strings;
240 
241  // presume null terminated string list
242  for ( qgssize i = 0; stringList[i]; ++i )
243  {
244  strings.append( stringList[i] );
245  }
246 
247  return strings;
248 
249 } // cStringList2Q_
250 
251 QString QgsRasterDataProvider::makeTableCell( QString const & value )
252 {
253  return "<p>\n" + value + "</p>\n";
254 } // makeTableCell_
255 
256 // convenience function for building metadata() HTML table cells
257 QString QgsRasterDataProvider::makeTableCells( QStringList const & values )
258 {
259  QString s( "<tr>" );
260 
261  for ( QStringList::const_iterator i = values.begin();
262  i != values.end();
263  ++i )
264  {
266  }
267 
268  s += "</tr>";
269 
270  return s;
271 } // makeTableCell_
272 
274 {
275  QString s;
276  return s;
277 }
278 
279 // Default implementation for values
280 QgsRasterIdentifyResult QgsRasterDataProvider::identify( const QgsPoint & thePoint, QgsRaster::IdentifyFormat theFormat, const QgsRectangle &theExtent, int theWidth, int theHeight )
281 {
282  QgsDebugMsg( "Entered" );
283  QMap<int, QVariant> results;
284 
285  if ( theFormat != QgsRaster::IdentifyFormatValue || !( capabilities() & IdentifyValue ) )
286  {
287  QgsDebugMsg( "Format not supported" );
288  return QgsRasterIdentifyResult( ERR( tr( "Format not supported" ) ) );
289  }
290 
291  if ( !extent().contains( thePoint ) )
292  {
293  // Outside the raster
294  for ( int bandNo = 1; bandNo <= bandCount(); bandNo++ )
295  {
296  results.insert( bandNo, QVariant() );
297  }
299  }
300 
301  QgsRectangle myExtent = theExtent;
302  if ( myExtent.isEmpty() ) myExtent = extent();
303 
304  if ( theWidth == 0 )
305  {
306  theWidth = capabilities() & Size ? xSize() : 1000;
307  }
308  if ( theHeight == 0 )
309  {
310  theHeight = capabilities() & Size ? ySize() : 1000;
311  }
312 
313  // Calculate the row / column where the point falls
314  double xres = ( myExtent.width() ) / theWidth;
315  double yres = ( myExtent.height() ) / theHeight;
316 
317  int col = ( int ) floor(( thePoint.x() - myExtent.xMinimum() ) / xres );
318  int row = ( int ) floor(( myExtent.yMaximum() - thePoint.y() ) / yres );
319 
320  double xMin = myExtent.xMinimum() + col * xres;
321  double xMax = xMin + xres;
322  double yMax = myExtent.yMaximum() - row * yres;
323  double yMin = yMax - yres;
324  QgsRectangle pixelExtent( xMin, yMin, xMax, yMax );
325 
326  for ( int i = 1; i <= bandCount(); i++ )
327  {
328  QgsRasterBlock * myBlock = block( i, pixelExtent, 1, 1 );
329 
330  if ( myBlock )
331  {
332  double value = myBlock->value( 0 );
333 
334  results.insert( i, value );
335  delete myBlock;
336  }
337  else
338  {
339  results.insert( i, QVariant() );
340  }
341  }
343 }
344 
346 {
347  return "text/plain";
348 }
349 
350 typedef QList<QPair<QString, QString> > *pyramidResamplingMethods_t();
351 QList<QPair<QString, QString> > QgsRasterDataProvider::pyramidResamplingMethods( QString providerKey )
352 {
353  pyramidResamplingMethods_t *pPyramidResamplingMethods = ( pyramidResamplingMethods_t * ) cast_to_fptr( QgsProviderRegistry::instance()->function( providerKey, "pyramidResamplingMethods" ) );
354  if ( pPyramidResamplingMethods )
355  {
356  QList<QPair<QString, QString> > *methods = pPyramidResamplingMethods();
357  if ( !methods )
358  {
359  QgsDebugMsg( "provider pyramidResamplingMethods returned no methods" );
360  }
361  else
362  {
363  return *methods;
364  }
365  }
366  else
367  {
368  QgsDebugMsg( "Could not resolve pyramidResamplingMethods provider library" );
369  }
370  return QList<QPair<QString, QString> >();
371 }
372 
374 {
375  QList<QgsRasterPyramid> myPyramidList = buildPyramidList();
376 
377  if ( myPyramidList.isEmpty() )
378  return false;
379 
380  QList<QgsRasterPyramid>::iterator myRasterPyramidIterator;
381  for ( myRasterPyramidIterator = myPyramidList.begin();
382  myRasterPyramidIterator != myPyramidList.end();
383  ++myRasterPyramidIterator )
384  {
385  if ( myRasterPyramidIterator->exists )
386  {
387  return true;
388  }
389  }
390  return false;
391 }
392 
394 {
395  if ( bandNo >= mUserNoDataValue.size() )
396  {
397  for ( int i = mUserNoDataValue.size(); i < bandNo; i++ )
398  {
400  }
401  }
402  QgsDebugMsg( QString( "set %1 band %1 no data ranges" ).arg( noData.size() ) );
403 
404  if ( mUserNoDataValue[bandNo-1] != noData )
405  {
406  // Clear statistics
407  int i = 0;
408  while ( i < mStatistics.size() )
409  {
410  if ( mStatistics.value( i ).bandNumber == bandNo )
411  {
412  mStatistics.removeAt( i );
413  mHistograms.removeAt( i );
414  }
415  else
416  {
417  i++;
418  }
419  }
420  mUserNoDataValue[bandNo-1] = noData;
421  }
422 }
423 
424 typedef QgsRasterDataProvider * createFunction_t( const QString&,
425  const QString&, int,
427  int, int, double*,
429  QStringList );
430 
432  const QString &uri,
433  const QString& format, int nBands,
434  QGis::DataType type,
435  int width, int height, double* geoTransform,
436  const QgsCoordinateReferenceSystem& crs,
437  QStringList createOptions )
438 {
439  createFunction_t *createFn = ( createFunction_t* ) cast_to_fptr( QgsProviderRegistry::instance()->function( providerKey, "create" ) );
440  if ( !createFn )
441  {
442  QgsDebugMsg( "Cannot resolve 'create' function in " + providerKey + " provider" );
443  // TODO: it would be good to return invalid QgsRasterDataProvider
444  // with QgsError set, but QgsRasterDataProvider has pure virtual methods
445  return 0;
446  }
447  return createFn( uri, format, nBands, type, width, height, geoTransform, crs, createOptions );
448 }
449 
451 {
452  switch ( format )
453  {
455  return "Value";
457  return "Text";
459  return "Html";
461  return "Feature";
462  default:
463  return "Undefined";
464  }
465 }
466 
468 {
469  switch ( format )
470  {
472  return tr( "Value" );
474  return tr( "Text" );
476  return tr( "Html" );
478  return tr( "Feature" );
479  default:
480  return "Undefined";
481  }
482 }
483 
485 {
486  if ( formatName == "Value" ) return QgsRaster::IdentifyFormatValue;
487  if ( formatName == "Text" ) return QgsRaster::IdentifyFormatText;
488  if ( formatName == "Html" ) return QgsRaster::IdentifyFormatHtml;
489  if ( formatName == "Feature" ) return QgsRaster::IdentifyFormatFeature;
491 }
492 
494 {
495  switch ( format )
496  {
498  return IdentifyValue;
500  return IdentifyText;
502  return IdentifyHtml;
504  return IdentifyFeature;
505  default:
506  return NoCapabilities;
507  }
508 }
509 
510 bool QgsRasterDataProvider::userNoDataValuesContains( int bandNo, double value ) const
511 {
512  QgsRasterRangeList rangeList = mUserNoDataValue.value( bandNo - 1 );
513  return QgsRasterRange::contains( value, rangeList );
514 }
515 
517 {
518  mDpi = other.mDpi;
523  mExtent = other.mExtent;
524 }
525 
526 // ENDS
bool hasPyramids()
Returns true if raster has at least one populated histogram.
virtual int bandCount() const =0
Get number of bands.
virtual void readBlock(int bandNo, int xBlock, int yBlock, void *data)
Read block of data.
static unsigned index
A rectangle specified with double values.
Definition: qgsrectangle.h:35
bool isEmpty() const
test if rectangle is empty.
void copyBaseSettings(const QgsRasterDataProvider &other)
Copy member variables from other raster data provider.
virtual QgsRasterBlock * block(int theBandNo, const QgsRectangle &theExtent, int theWidth, int theHeight)
Read block of data using given extent and size.
static bool contains(double value, const QgsRasterRangeList &rangeList)
Test if value is within the list of ranges.
void setXMaximum(double x)
Set the maximum x value.
Definition: qgsrectangle.h:163
static QgsProviderRegistry * instance(QString pluginPath=QString::null)
means of accessing canonical single instance
double yMaximum() const
Get the y maximum value (top side of rectangle)
Definition: qgsrectangle.h:188
#define QgsDebugMsg(str)
Definition: qgslogger.h:33
void applyNoDataValues(const QgsRasterRangeList &rangeList)
virtual double bandOffset(int bandNo) const
Read band offset for raster value @note added in 2.3.
virtual void setUseSrcNoDataValue(int bandNo, bool use)
Set source nodata value usage.
virtual double srcNoDataValue(int bandNo) const
Value representing no data value.
static QString makeTableCell(const QString &value)
static Capability identifyFormatToCapability(QgsRaster::IdentifyFormat format)
virtual QgsRasterRangeList userNoDataValues(int bandNo) const
Get list of user no data value ranges.
static QgsRasterDataProvider * create(const QString &providerKey, const QString &uri, const QString &format, int nBands, QGis::DataType type, int width, int height, double *geoTransform, const QgsCoordinateReferenceSystem &crs, QStringList createOptions=QStringList())
Creates a new dataset with mDataSourceURI.
Abstract base class for spatial data provider implementations.
bool qgsDoubleNear(double a, double b, double epsilon=4 *DBL_EPSILON)
Definition: qgis.h:325
double x() const
Definition: qgspoint.h:126
virtual int ySize() const
static QString identifyFormatName(QgsRaster::IdentifyFormat format)
bool setIsNoData(int row, int column)
Set no data on pixel.
virtual bool useSrcNoDataValue(int bandNo) const
Get source nodata value usage.
virtual QString lastErrorFormat()
Returns the format of the error text for the last error in this provider.
Raster identify results container.
virtual QgsRasterIdentifyResult identify(const QgsPoint &thePoint, QgsRaster::IdentifyFormat theFormat, const QgsRectangle &theExtent=QgsRectangle(), int theWidth=0, int theHeight=0)
Identify raster value(s) found on the point position.
bool setIsNoDataExcept(const QRect &theExceptRect)
Set the whole block to no data except specified rectangle.
Raster data container.
double yMinimum() const
Get the y minimum value (bottom side of rectangle)
Definition: qgsrectangle.h:193
virtual void setUserNoDataValue(int bandNo, QgsRasterRangeList noData)
double xMaximum() const
Get the x maximum value (right side of rectangle)
Definition: qgsrectangle.h:178
virtual QList< QgsRasterPyramid > buildPyramidList(QList< int > overviewList=QList< int >())
Accessor for ths raster layers pyramid list.
double value(int row, int column) const
Read a single value if type of block is numeric.
virtual QgsRectangle extent()=0
Get the extent of the data source.
void setYMinimum(double y)
Set the minimum y value.
Definition: qgsrectangle.h:168
QList< QgsRasterHistogram > mHistograms
List of cached histograms, all bands mixed.
QList< bool > mSrcHasNoDataValue
Source no data value exists.
virtual QGis::DataType dataType(int bandNo) const =0
Returns data type for the band specified by number.
IdentifyFormat
Definition: qgsraster.h:54
DataType
Raster data types.
Definition: qgis.h:204
Base class for processing filters like renderers, reprojector, resampler etc.
A class to represent a point.
Definition: qgspoint.h:63
QgsRasterDataProvider * createFunction_t(const QString &, const QString &, int, QGis::DataType, int, int, double *, const QgsCoordinateReferenceSystem &, QStringList)
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...
Definition: qgis.h:424
bool userNoDataValuesContains(int bandNo, double value) const
Returns true if user no data contains value.
QList< double > mSrcNoDataValue
Source no data value is available and is set to be used or internal no data is available.
virtual int capabilities() const
Returns a bitmask containing the supported capabilities.
virtual double bandScale(int bandNo) const
Read band scale for raster value @note added in 2.3.
QList< QPair< QString, QString > > * pyramidResamplingMethods_t()
char * bits(int row, int column)
Get pointer to data.
QList< QgsRasterRange > QgsRasterRangeList
virtual int xSize() const
Get raster size.
Capability
If you add to this, please also add to capabilitiesString()
void applyScaleOffset(double scale, double offset)
apply band scale and offset to raster block values @note added in 2.3
void setYMaximum(double y)
Set the maximum y value.
Definition: qgsrectangle.h:173
virtual QString metadata()=0
Get metadata in a format suitable for feeding directly into a subset of the GUI raster properties "Me...
QgsRectangle intersect(const QgsRectangle *rect) const
return the intersection with the given rectangle
static QString makeTableCells(const QStringList &values)
Class for storing a coordinate reference system (CRS)
int dataTypeSize(int bandNo)
double y() const
Definition: qgspoint.h:134
void * function(const QString &providerKey, const QString &functionName)
Get pointer to provider function.
static QStringList cStringList2Q_(char **stringList)
static QgsRaster::IdentifyFormat identifyFormatFromName(QString formatName)
void(*)() cast_to_fptr(void *p)
Definition: qgis.h:301
static QList< QPair< QString, QString > > pyramidResamplingMethods(QString providerKey)
Returns a list of pyramid resampling method name and label pairs for given provider.
virtual bool srcHasNoDataValue(int bandNo) const
QList< QgsRasterBandStats > mStatistics
List of cached statistics, all bands mixed.
static QRect subRect(const QgsRectangle &theExtent, int theWidth, int theHeight, const QgsRectangle &theSubExtent)
For theExtent and theWidht, theHeight find rectangle covered by subextent.
double width() const
Width of the rectangle.
Definition: qgsrectangle.h:198
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)
Definition: qgsrectangle.h:183
static QString identifyFormatLabel(QgsRaster::IdentifyFormat format)
#define ERR(message)
void setXMinimum(double x)
Set the minimum x value.
Definition: qgsrectangle.h:158
double height() const
Height of the rectangle.
Definition: qgsrectangle.h:203
bool isEmpty() const
Returns true if block is empty, i.e.
Base class for raster data providers.
QList< QgsRasterRangeList > mUserNoDataValue
List of lists of user defined additional no data values for each band, indexed from 0...
QList< bool > mUseSrcNoDataValue
Use source nodata value.
#define tr(sourceText)