mirror of
https://github.com/qgis/QGIS.git
synced 2025-04-14 00:07:35 -04:00
Merge branch 'master' of github.com:qgis/Quantum-GIS
This commit is contained in:
commit
ad78d7b5d6
@ -82,7 +82,7 @@ class QgsRasterInterface
|
||||
|
||||
virtual int bandCount() const;
|
||||
|
||||
virtual double noDataValue() const;
|
||||
virtual double noDataValue( int bandNo ) const;
|
||||
|
||||
virtual void * block( int bandNo, const QgsRectangle & extent, int width, int height );
|
||||
|
||||
|
@ -172,7 +172,7 @@ public:
|
||||
int height();
|
||||
|
||||
/** \brief Is the NoDataValue Valid */
|
||||
bool isNoDataValueValid() const;
|
||||
//bool isNoDataValueValid() const;
|
||||
|
||||
/** \brief Accessor for mGrayMinimumMaximumEstimated */
|
||||
//bool isGrayMinimumMaximumEstimated() const; //removed with raster redesign
|
||||
@ -181,7 +181,7 @@ public:
|
||||
//bool isRGBMinimumMaximumEstimated() const; //removed with raster redesign
|
||||
|
||||
/** \brief Accessor that returns the NO_DATA entry for this raster */
|
||||
double noDataValue( bool* isValid = 0 );
|
||||
//double noDataValue( bool* isValid = 0 );
|
||||
|
||||
/** \brief Returns a pointer to the transparency object */
|
||||
//QgsRasterTransparency* rasterTransparency(); //removed with raster redesign
|
||||
@ -385,7 +385,7 @@ public:
|
||||
//bool readColorTable( int theBandNumber, QList<QgsColorRampShader::ColorRampItem>* theList );
|
||||
|
||||
/** \brief Simple reset function that set the noDataValue back to the value stored in the first raster band */
|
||||
void resetNoDataValue();
|
||||
//void resetNoDataValue();
|
||||
|
||||
/** \brief Mutator for blue band name mapping */
|
||||
void setBlueBandName( const QString & theBandName );
|
||||
@ -431,7 +431,7 @@ public:
|
||||
void setMinimumValue( QString theBand, double theValue, bool theGenerateLookupTableFlag = true );
|
||||
|
||||
/** \brief Mutator that allows the NO_DATA entry for this raster to be overridden */
|
||||
void setNoDataValue( double theNoData );
|
||||
//void setNoDataValue( double theNoData );
|
||||
|
||||
/** \brief Set the raster shader function to a user defined function
|
||||
\note ownership of the shader function is transfered to raster shader */
|
||||
|
@ -546,13 +546,20 @@ void QgsRasterLayerProperties::sync()
|
||||
// TODO: no data ranges
|
||||
if ( mRasterLayer->dataProvider()->srcHasNoDataValue( 1 ) )
|
||||
{
|
||||
lblSrcNoDataValue->setText( QgsRasterInterface::printValue( mRasterLayer->dataProvider()->noDataValue( 1 ) ) );
|
||||
lblSrcNoDataValue->setText( QgsRasterInterface::printValue( mRasterLayer->dataProvider()->srcNoDataValue( 1 ) ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
lblSrcNoDataValue->setText( tr( "not defined" ) );
|
||||
}
|
||||
|
||||
mSrcNoDataValueCheckBox->setChecked( mRasterLayer->dataProvider()->useSrcNoDataValue( 1 ) );
|
||||
|
||||
bool enableSrcNoData = mRasterLayer->dataProvider()->srcHasNoDataValue( 1 ) && !qIsNaN( mRasterLayer->dataProvider()->srcNoDataValue( 1 ) );
|
||||
|
||||
mSrcNoDataValueCheckBox->setEnabled( enableSrcNoData );
|
||||
lblSrcNoDataValue->setEnabled( enableSrcNoData );
|
||||
|
||||
QList<QgsRasterInterface::Range> noDataRangeList = mRasterLayer->dataProvider()->userNoDataValue( 1 );
|
||||
QgsDebugMsg( QString( "noDataRangeList.size = %1" ).arg( noDataRangeList.size() ) );
|
||||
if ( noDataRangeList.size() > 0 )
|
||||
@ -600,13 +607,14 @@ void QgsRasterLayerProperties::sync()
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( mRasterLayer->isNoDataValueValid() )
|
||||
// TODO: all bands
|
||||
if ( mRasterLayer->dataProvider()->srcHasNoDataValue( 1 ) )
|
||||
{
|
||||
lblNoData->setText( tr( "No-Data Value: %1" ).arg( mRasterLayer->noDataValue() ) );
|
||||
lblNoData->setText( tr( "No-Data Value: %1" ).arg( mRasterLayer->dataProvider()->noDataValue( 1 ) ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
lblNoData->setText( tr( "No-Data Value: Not Set" ) );
|
||||
lblNoData->setText( tr( "No-Data Value: " ) + tr( "n/a" ) );
|
||||
}
|
||||
}
|
||||
|
||||
@ -678,6 +686,7 @@ void QgsRasterLayerProperties::apply()
|
||||
for ( int bandNo = 1; bandNo <= mRasterLayer->dataProvider()->bandCount(); bandNo++ )
|
||||
{
|
||||
mRasterLayer->dataProvider()->setUserNoDataValue( bandNo, myNoDataRangeList );
|
||||
mRasterLayer->dataProvider()->setUseSrcNoDataValue( bandNo, mSrcNoDataValueCheckBox->isChecked() );
|
||||
}
|
||||
|
||||
//set renderer from widget
|
||||
@ -992,32 +1001,30 @@ void QgsRasterLayerProperties::on_pbnDefaultValues_clicked()
|
||||
|
||||
setupTransparencyTable( nBands );
|
||||
|
||||
// I don't think that noDataValue should be added to transparency list
|
||||
#if 0
|
||||
if ( nBands == 3 )
|
||||
{
|
||||
if ( mRasterLayer->isNoDataValueValid() )
|
||||
{
|
||||
// I don't think that noDataValue should be added to transparency list
|
||||
#if 0
|
||||
tableTransparency->insertRow( tableTransparency->rowCount() );
|
||||
setTransparencyCell( 0, 0, mRasterLayer->noDataValue() );
|
||||
setTransparencyCell( 0, 1, mRasterLayer->noDataValue() );
|
||||
setTransparencyCell( 0, 2, mRasterLayer->noDataValue() );
|
||||
setTransparencyCell( 0, 1, 100 );
|
||||
#endif
|
||||
}
|
||||
}
|
||||
else //1 band
|
||||
{
|
||||
if ( mRasterLayer->isNoDataValueValid() )
|
||||
{
|
||||
#if 0
|
||||
tableTransparency->insertRow( tableTransparency->rowCount() );
|
||||
setTransparencyCell( 0, 0, mRasterLayer->noDataValue() );
|
||||
setTransparencyCell( 0, 1, mRasterLayer->noDataValue() );
|
||||
setTransparencyCell( 0, 1, 100 );
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
tableTransparency->resizeColumnsToContents(); // works only with values
|
||||
tableTransparency->resizeRowsToContents();
|
||||
|
@ -25,6 +25,27 @@
|
||||
|
||||
#include <qmath.h>
|
||||
|
||||
void QgsRasterDataProvider::setUseSrcNoDataValue( int bandNo, bool use )
|
||||
{
|
||||
if ( mUseSrcNoDataValue.size() < bandNo )
|
||||
{
|
||||
for ( int i = mUseSrcNoDataValue.size(); i < bandNo; i++ )
|
||||
{
|
||||
mUseSrcNoDataValue.append( false );
|
||||
}
|
||||
}
|
||||
mUseSrcNoDataValue[bandNo-1] = use;
|
||||
}
|
||||
|
||||
double QgsRasterDataProvider::noDataValue( int bandNo ) const
|
||||
{
|
||||
if ( mSrcHasNoDataValue.value( bandNo - 1 ) && mUseSrcNoDataValue.value( bandNo - 1 ) )
|
||||
{
|
||||
return mSrcNoDataValue.value( bandNo -1 );
|
||||
}
|
||||
return mInternalNoDataValue.value( bandNo -1 );
|
||||
}
|
||||
|
||||
void QgsRasterDataProvider::readBlock( int bandNo, QgsRectangle
|
||||
const & viewExtent, int width,
|
||||
int height,
|
||||
@ -289,7 +310,7 @@ QByteArray QgsRasterDataProvider::noValueBytes( int theBandNo )
|
||||
QByteArray ba;
|
||||
ba.resize(( int )size );
|
||||
char * data = ba.data();
|
||||
double noval = mNoDataValue[theBandNo-1];
|
||||
double noval = noDataValue( theBandNo - 1 );
|
||||
unsigned char uc;
|
||||
unsigned short us;
|
||||
short s;
|
||||
@ -616,7 +637,6 @@ QgsRasterBandStats QgsRasterDataProvider::bandStatistics( int theBandNo,
|
||||
int myWidth = myRasterBandStats.width;
|
||||
int myHeight = myRasterBandStats.height;
|
||||
|
||||
double myNoDataValue = noDataValue();
|
||||
int myDataType = dataType( theBandNo );
|
||||
|
||||
int myXBlockSize = xBlockSize();
|
||||
@ -669,7 +689,8 @@ QgsRasterBandStats QgsRasterDataProvider::bandStatistics( int theBandNo,
|
||||
double myValue = readValue( myData, myDataType, myX + ( myY * myBlockWidth ) );
|
||||
//QgsDebugMsg ( QString ( "%1 %2 value %3" ).arg (myX).arg(myY).arg( myValue ) );
|
||||
|
||||
if ( mValidNoDataValue && ( qAbs( myValue - myNoDataValue ) <= TINY_VALUE ) )
|
||||
// TODO: user nodata
|
||||
if ( isNoDataValue( theBandNo, myValue ) )
|
||||
{
|
||||
continue; // NULL
|
||||
}
|
||||
@ -718,7 +739,6 @@ QgsRasterBandStats QgsRasterDataProvider::bandStatistics( int theBandNo,
|
||||
myRasterBandStats.stdDev = sqrt( mySumOfSquares / ( myRasterBandStats.elementCount - 1 ) );
|
||||
|
||||
QgsDebugMsg( "************ STATS **************" );
|
||||
QgsDebugMsg( QString( "VALID NODATA %1" ).arg( mValidNoDataValue ) );
|
||||
QgsDebugMsg( QString( "MIN %1" ).arg( myRasterBandStats.minimumValue ) );
|
||||
QgsDebugMsg( QString( "MAX %1" ).arg( myRasterBandStats.maximumValue ) );
|
||||
QgsDebugMsg( QString( "RANGE %1" ).arg( myRasterBandStats.range ) );
|
||||
@ -893,7 +913,6 @@ QgsRasterHistogram QgsRasterDataProvider::histogram( int theBandNo,
|
||||
QgsRectangle myExtent = myHistogram.extent;
|
||||
myHistogram.histogramVector.resize( myBinCount );
|
||||
|
||||
double myNoDataValue = noDataValue();
|
||||
int myDataType = dataType( theBandNo );
|
||||
|
||||
int myXBlockSize = xBlockSize();
|
||||
@ -953,7 +972,8 @@ QgsRasterHistogram QgsRasterDataProvider::histogram( int theBandNo,
|
||||
double myValue = readValue( myData, myDataType, myX + ( myY * myBlockWidth ) );
|
||||
//QgsDebugMsg ( QString ( "%1 %2 value %3" ).arg (myX).arg(myY).arg( myValue ) );
|
||||
|
||||
if ( mValidNoDataValue && ( qAbs( myValue - myNoDataValue ) <= TINY_VALUE ) )
|
||||
// TODO: user defined nodata values
|
||||
if ( isNoDataValue( theBandNo, myValue ) )
|
||||
{
|
||||
continue; // NULL
|
||||
}
|
||||
@ -1034,7 +1054,7 @@ void QgsRasterDataProvider::cumulativeCut( int theBandNo,
|
||||
double QgsRasterDataProvider::readValue( void *data, int type, int index )
|
||||
{
|
||||
if ( !data )
|
||||
return mValidNoDataValue ? noDataValue() : 0.0;
|
||||
return std::numeric_limits<double>::quiet_NaN();
|
||||
|
||||
switch ( type )
|
||||
{
|
||||
@ -1063,7 +1083,7 @@ double QgsRasterDataProvider::readValue( void *data, int type, int index )
|
||||
QgsLogger::warning( "GDAL data type is not supported" );
|
||||
}
|
||||
|
||||
return mValidNoDataValue ? noDataValue() : 0.0;
|
||||
return std::numeric_limits<double>::quiet_NaN();
|
||||
}
|
||||
|
||||
void QgsRasterDataProvider::setUserNoDataValue( int bandNo, QList<QgsRasterInterface::Range> noData )
|
||||
|
@ -295,17 +295,24 @@ class CORE_EXPORT QgsRasterDataProvider : public QgsDataProvider, public QgsRast
|
||||
virtual double readValue( void *data, int type, int index );
|
||||
|
||||
/* Return true if source band has no data value */
|
||||
virtual bool srcHasNoDataValue( int bandNo ) const { Q_UNUSED( bandNo ); return false; }
|
||||
virtual bool srcHasNoDataValue( int bandNo ) const { return mSrcHasNoDataValue.value( bandNo -1 ); }
|
||||
|
||||
/** \brief Get source nodata value usage */
|
||||
virtual bool useSrcNoDataValue( int bandNo ) const { return mUseSrcNoDataValue.value( bandNo -1 ); }
|
||||
|
||||
/** \brief Set source nodata value usage */
|
||||
virtual void setUseSrcNoDataValue( int bandNo, bool use );
|
||||
|
||||
/** value representing null data */
|
||||
virtual double noDataValue() const { return 0; }
|
||||
//virtual double noDataValue() const { return 0; }
|
||||
|
||||
/** Value representing original source no data. This value my differ from
|
||||
* if it was overwritten by user */
|
||||
virtual double noDataValue( int bandNo ) const { return mNoDataValue.value( bandNo -1 ); }
|
||||
/** Value representing currentno data.
|
||||
* WARNING: this value returned by this method is not constant. It may change
|
||||
* for example if user disable use of source no data value. */
|
||||
virtual double noDataValue( int bandNo ) const;
|
||||
|
||||
/** Value representing no data value. */
|
||||
//virtual double srcNoDataValue( int bandNo ) const { return mSrcNoDataValue.value(bandNo-1); }
|
||||
virtual double srcNoDataValue( int bandNo ) const { return mSrcNoDataValue.value( bandNo -1 ); }
|
||||
|
||||
virtual void setUserNoDataValue( int bandNo, QList<QgsRasterInterface::Range> noData );
|
||||
|
||||
@ -523,7 +530,7 @@ class CORE_EXPORT QgsRasterDataProvider : public QgsDataProvider, public QgsRast
|
||||
void setDpi( int dpi ) {mDpi = dpi;}
|
||||
|
||||
/** \brief Is the NoDataValue Valid */
|
||||
bool isNoDataValueValid() const { return mValidNoDataValue; }
|
||||
//bool isNoDataValueValid() const { return mValidNoDataValue; }
|
||||
|
||||
static QStringList cStringList2Q_( char ** stringList );
|
||||
|
||||
@ -603,19 +610,27 @@ class CORE_EXPORT QgsRasterDataProvider : public QgsDataProvider, public QgsRast
|
||||
int mDpi;
|
||||
|
||||
/** \brief Cell value representing original source no data. e.g. -9999, indexed from 0 */
|
||||
//QList<double> mSrcNoDataValue;
|
||||
QList<double> mSrcNoDataValue;
|
||||
|
||||
/** \brief Cell value representing no data. e.g. -9999, indexed from 0.
|
||||
* Currently the values is the same as in mSrcNoDataValue, but a possibility
|
||||
* to overwrite/disable original no data value could be added (?), in that
|
||||
* case this value would be different. But original source no data value
|
||||
* cannot be disabled without add additional user nodata (there would not be
|
||||
* any guaranteed free nodata value available (to represent nodata in
|
||||
* reprojection for example) */
|
||||
QList<double> mNoDataValue;
|
||||
/** \brief Source nodata value exist */
|
||||
QList<bool> mSrcHasNoDataValue;
|
||||
|
||||
/** \brief Use source nodata value. User can disable usage of source nodata
|
||||
* value as nodata. It may happen that a value is wrongly given by GDAL
|
||||
* as nodata (e.g. 0) and it has to be treated as regular value. */
|
||||
QList<bool> mUseSrcNoDataValue;
|
||||
|
||||
/** \brief Internal value representing nodata. Indexed from 0.
|
||||
* This values is used to represent nodata if no source nodata is available
|
||||
* or if the source nodata use was disabled.
|
||||
* It would be also possible to use wider type only if nodata is really necessary
|
||||
* in following interfaces, but that could make difficult to subclass
|
||||
* QgsRasterInterface.
|
||||
*/
|
||||
QList<double> mInternalNoDataValue;
|
||||
|
||||
/** \brief Flag indicating if the nodatavalue is valid*/
|
||||
bool mValidNoDataValue;
|
||||
//bool mValidNoDataValue;
|
||||
|
||||
/** \brief List of lists of user defined additional no data values
|
||||
* for each band, indexed from 0 */
|
||||
|
@ -75,7 +75,6 @@ bool QgsRasterChecker::runTest( QString theVerifiedKey, QString theVerifiedUri,
|
||||
|
||||
if ( verifiedProvider->extent() != expectedProvider->extent() ) ok = false;
|
||||
|
||||
compare( "No data (NULL) value", verifiedProvider->noDataValue(), expectedProvider->noDataValue(), mReport, ok );
|
||||
|
||||
mReport += "</table>\n";
|
||||
|
||||
@ -94,6 +93,8 @@ bool QgsRasterChecker::runTest( QString theVerifiedKey, QString theVerifiedUri,
|
||||
compare( "Source data type", verifiedProvider->srcDataType( band ), expectedProvider->srcDataType( band ), mReport, typesOk );
|
||||
compare( "Data type", verifiedProvider->dataType( band ), expectedProvider->dataType( band ), mReport, typesOk ) ;
|
||||
|
||||
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 );
|
||||
|
@ -167,14 +167,15 @@ QgsRasterFileWriter::WriterError QgsRasterFileWriter::writeDataRaster( const Qgs
|
||||
bool srcHasNoDataValue = srcProvider->srcHasNoDataValue( bandNo );
|
||||
bool destHasNoDataValue = false;
|
||||
double destNoDataValue;
|
||||
//QgsRasterInterface::DataType destDataType = srcProvider->srcDataType( bandNo );
|
||||
QgsRasterInterface::DataType destDataType = srcProvider->dataType( bandNo );
|
||||
QgsRasterInterface::DataType destDataType = srcProvider->srcDataType( bandNo );
|
||||
//QgsRasterInterface::DataType destDataType = srcProvider->dataType( bandNo );
|
||||
// TODO: verify what happens/should happen if srcNoDataValue is disabled by setUseSrcNoDataValue
|
||||
QgsDebugMsg( QString( "srcHasNoDataValue = %1 srcNoDataValue = %2" ).arg( srcHasNoDataValue ).arg( srcProvider->srcNoDataValue( bandNo ) ) );
|
||||
if ( srcHasNoDataValue )
|
||||
{
|
||||
|
||||
// If source has no data value, it is used by provider
|
||||
// TODO: this is not realy source no data, we would need srcNoDataValue() but it
|
||||
// can be safely used I think
|
||||
destNoDataValue = srcProvider->noDataValue();
|
||||
destNoDataValue = srcProvider->srcNoDataValue( bandNo );
|
||||
destHasNoDataValue = true;
|
||||
}
|
||||
else if ( nuller && nuller->noData().size() > 0 )
|
||||
@ -255,6 +256,7 @@ QgsRasterFileWriter::WriterError QgsRasterFileWriter::writeDataRaster( const Qgs
|
||||
destDataTypeList.replace( i, destDataType );
|
||||
destNoDataValueList.replace( i, destNoDataValue );
|
||||
}
|
||||
destDataType = destDataTypeList.value( 0 );
|
||||
|
||||
// Try again
|
||||
destProvider = initOutput( nCols, nRows, crs, geoTransform, nBands, destDataType );
|
||||
@ -367,7 +369,7 @@ QgsRasterFileWriter::WriterError QgsRasterFileWriter::writeDataRaster(
|
||||
else
|
||||
{
|
||||
// TODO: this conversion should go to QgsRasterDataProvider::write with additional input data type param
|
||||
void *destData = QgsRasterInterface::convert( dataList[i-1], srcProvider->srcDataType( i ), destDataType, iterCols * iterRows );
|
||||
void *destData = QgsRasterInterface::convert( dataList[i-1], srcProvider->dataType( i ), destDataType, iterCols * iterRows );
|
||||
destDataList.push_back( destData );
|
||||
CPLFree( dataList[i-1] );
|
||||
}
|
||||
|
@ -259,6 +259,8 @@ void * QgsRasterInterface::convert( void *srcData, QgsRasterInterface::DataType
|
||||
{
|
||||
double value = readValue( srcData, srcDataType, i );
|
||||
writeValue( destData, destDataType, i, value );
|
||||
//double newValue = readValue( destData, destDataType, i );
|
||||
//QgsDebugMsg( QString("convert type %1 to %2: %3 -> %4").arg(srcDataType).arg(destDataType).arg( value ).arg( newValue ) );
|
||||
}
|
||||
return destData;
|
||||
}
|
||||
|
@ -142,14 +142,14 @@ class CORE_EXPORT QgsRasterInterface
|
||||
|
||||
/** Retruns value representing 'no data' (NULL) */
|
||||
// TODO: Q_DECL_DEPRECATED
|
||||
virtual double noDataValue() const { return 0; }
|
||||
//virtual double noDataValue() const { return 0; }
|
||||
|
||||
/** Return no data value for specific band. Each band/provider must have
|
||||
* no data value, if there is no one set in original data, provider decides one
|
||||
* possibly using wider data type.
|
||||
* @param bandNo band number
|
||||
* @return No data value */
|
||||
virtual double noDataValue( int bandNo ) const { Q_UNUSED( bandNo ); return noDataValue(); }
|
||||
virtual double noDataValue( int bandNo ) const { Q_UNUSED( bandNo ); return std::numeric_limits<double>::quiet_NaN(); }
|
||||
|
||||
/** Test if value is nodata for specific band
|
||||
* @param bandNo band number
|
||||
@ -216,6 +216,10 @@ class CORE_EXPORT QgsRasterInterface
|
||||
* returned. */
|
||||
double time( bool cumulative = false );
|
||||
|
||||
inline static double readValue( void *data, QgsRasterInterface::DataType type, int index );
|
||||
|
||||
inline static void writeValue( void *data, QgsRasterInterface::DataType type, int index, double value );
|
||||
|
||||
/** \brief Print double value with all necessary significant digits.
|
||||
* It is ensured that conversion back to double gives the same number.
|
||||
* @param value the value to be printed
|
||||
@ -238,8 +242,6 @@ class CORE_EXPORT QgsRasterInterface
|
||||
// On/off state, if off, it does not do anything, replicates input
|
||||
bool mOn;
|
||||
|
||||
inline static double readValue( void *data, QgsRasterInterface::DataType type, int index );
|
||||
inline static void writeValue( void *data, QgsRasterInterface::DataType type, int index, double value );
|
||||
|
||||
/** \brief Test if value is within the list of ranges
|
||||
* @param value value
|
||||
|
@ -500,7 +500,7 @@ void QgsRasterLayer::computeMinimumMaximumFromLastExtent( int theBand, double* t
|
||||
if ( !theMinMax )
|
||||
return;
|
||||
|
||||
int myDataType = mDataProvider->dataType( theBand );
|
||||
QgsRasterInterface::DataType myDataType = mDataProvider->dataType( theBand );
|
||||
void* myScanData = readData( theBand, &mLastViewPort );
|
||||
|
||||
/* Check for out of memory error */
|
||||
@ -521,8 +521,8 @@ void QgsRasterLayer::computeMinimumMaximumFromLastExtent( int theBand, double* t
|
||||
{
|
||||
for ( int myColumn = 0; myColumn < mLastViewPort.drawableAreaXDim; ++myColumn )
|
||||
{
|
||||
myValue = readValue( myScanData, myDataType, myRow * mLastViewPort.drawableAreaXDim + myColumn );
|
||||
if ( mValidNoDataValue && ( qAbs( myValue - mNoDataValue ) <= TINY_VALUE || myValue != myValue ) )
|
||||
myValue = QgsRasterInterface::readValue( myScanData, myDataType, myRow * mLastViewPort.drawableAreaXDim + myColumn );
|
||||
if ( mDataProvider->isNoDataValue( theBand, myValue ) )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
@ -1234,9 +1234,10 @@ QString QgsRasterLayer::metadata()
|
||||
myMetadata += tr( "No Data Value" );
|
||||
myMetadata += "</p>\n";
|
||||
myMetadata += "<p>";
|
||||
if ( mValidNoDataValue )
|
||||
// TODO: all bands
|
||||
if ( mDataProvider->srcHasNoDataValue( 1 ) )
|
||||
{
|
||||
myMetadata += QString::number( mNoDataValue );
|
||||
myMetadata += QString::number( mDataProvider->srcNoDataValue( 1 ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -1545,7 +1546,7 @@ double QgsRasterLayer::rasterUnitsPerPixel()
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
#if 0
|
||||
void QgsRasterLayer::resetNoDataValue()
|
||||
{
|
||||
mNoDataValue = std::numeric_limits<int>::max();
|
||||
@ -1573,7 +1574,7 @@ void QgsRasterLayer::resetNoDataValue()
|
||||
mValidNoDataValue = mDataProvider->isNoDataValueValid();
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void QgsRasterLayer::setBlueBandName( QString const & theBandName )
|
||||
{
|
||||
@ -1596,8 +1597,8 @@ void QgsRasterLayer::init()
|
||||
setDrawingStyle( QgsRasterLayer::UndefinedDrawingStyle );
|
||||
|
||||
mBandCount = 0;
|
||||
mNoDataValue = -9999.0;
|
||||
mValidNoDataValue = false;
|
||||
//mNoDataValue = -9999.0;
|
||||
//mValidNoDataValue = false;
|
||||
|
||||
//Initialize the last view port structure, should really be a class
|
||||
mLastViewPort.drawableAreaXDim = 0;
|
||||
@ -1719,7 +1720,7 @@ void QgsRasterLayer::setDataProvider( QString const & provider )
|
||||
mDataSource = mDataProvider->dataSourceUri();
|
||||
}
|
||||
|
||||
setNoDataValue( mDataProvider->noDataValue() );
|
||||
//setNoDataValue( mDataProvider->noDataValue() );
|
||||
|
||||
// get the extent
|
||||
QgsRectangle mbr = mDataProvider->extent();
|
||||
@ -1737,7 +1738,7 @@ void QgsRasterLayer::setDataProvider( QString const & provider )
|
||||
// upper case the first letter of the layer name
|
||||
QgsDebugMsg( "mLayerName: " + name() );
|
||||
|
||||
mValidNoDataValue = mDataProvider->isNoDataValueValid();
|
||||
//mValidNoDataValue = mDataProvider->isNoDataValueValid();
|
||||
|
||||
// set up the raster drawing style
|
||||
// Do not set any 'sensible' style here, the style is set later
|
||||
@ -2228,6 +2229,7 @@ void QgsRasterLayer::setMinimumValue( QString, double, bool )
|
||||
//legacy method
|
||||
}
|
||||
|
||||
#if 0
|
||||
void QgsRasterLayer::setNoDataValue( double theNoDataValue )
|
||||
{
|
||||
if ( theNoDataValue != mNoDataValue )
|
||||
@ -2246,6 +2248,7 @@ void QgsRasterLayer::setNoDataValue( double theNoDataValue )
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void QgsRasterLayer::setRasterShaderFunction( QgsRasterShaderFunction* )
|
||||
{
|
||||
@ -2596,7 +2599,7 @@ bool QgsRasterLayer::readXml( const QDomNode& layer_node )
|
||||
// Load user no data value
|
||||
QDomElement noDataElement = layer_node.firstChildElement( "noData" );
|
||||
|
||||
QDomNodeList noDataBandList = noDataElement.elementsByTagName( "noDataRangeList" );
|
||||
QDomNodeList noDataBandList = noDataElement.elementsByTagName( "noDataList" );
|
||||
|
||||
for ( int i = 0; i < noDataBandList.size(); ++i )
|
||||
{
|
||||
@ -2606,6 +2609,7 @@ bool QgsRasterLayer::readXml( const QDomNode& layer_node )
|
||||
QgsDebugMsg( QString( "bandNo = %1" ).arg( bandNo ) );
|
||||
if ( ok && ( bandNo > 0 ) && ( bandNo <= mDataProvider->bandCount() ) )
|
||||
{
|
||||
mDataProvider->setUseSrcNoDataValue( bandNo, bandElement.attribute( "useSrcNoData" ).toInt() );
|
||||
QList<QgsRasterInterface::Range> myNoDataRangeList;
|
||||
|
||||
QDomNodeList rangeList = bandElement.elementsByTagName( "noDataRange" );
|
||||
@ -2686,8 +2690,9 @@ bool QgsRasterLayer::writeXml( QDomNode & layer_node,
|
||||
{
|
||||
if ( mDataProvider->userNoDataValue( bandNo ).isEmpty() ) continue;
|
||||
|
||||
QDomElement noDataRangeList = document.createElement( "noDataRangeList" );
|
||||
QDomElement noDataRangeList = document.createElement( "noDataList" );
|
||||
noDataRangeList.setAttribute( "bandNo", bandNo );
|
||||
noDataRangeList.setAttribute( "useSrcNoData", mDataProvider->useSrcNoDataValue( bandNo ) );
|
||||
|
||||
foreach ( QgsRasterInterface::Range range, mDataProvider->userNoDataValue( bandNo ) )
|
||||
{
|
||||
@ -2816,6 +2821,7 @@ bool QgsRasterLayer::readFile( QString const &theFilename )
|
||||
/*
|
||||
* @param index index in memory block
|
||||
*/
|
||||
#if 0
|
||||
double QgsRasterLayer::readValue( void *data, int type, int index )
|
||||
{
|
||||
if ( !data )
|
||||
@ -2851,6 +2857,7 @@ double QgsRasterLayer::readValue( void *data, int type, int index )
|
||||
|
||||
return mValidNoDataValue ? mNoDataValue : 0.0;
|
||||
}
|
||||
#endif
|
||||
|
||||
bool QgsRasterLayer::update()
|
||||
{
|
||||
|
@ -342,10 +342,10 @@ class CORE_EXPORT QgsRasterLayer : public QgsMapLayer
|
||||
int height() { return mHeight; }
|
||||
|
||||
/** \brief Is the NoDataValue Valid */
|
||||
bool isNoDataValueValid() const { return mValidNoDataValue; }
|
||||
//bool isNoDataValueValid() const { return mValidNoDataValue; }
|
||||
|
||||
/** \brief Accessor that returns the NO_DATA entry for this raster */
|
||||
double noDataValue( bool* isValid = 0 ) { if ( isValid ) { *isValid = mValidNoDataValue;} return mNoDataValue; }
|
||||
//double noDataValue( bool* isValid = 0 ) { if ( isValid ) { *isValid = mValidNoDataValue;} return mNoDataValue; }
|
||||
|
||||
/** \brief Accessor for raster layer type (which is a read only property) */
|
||||
LayerType rasterType() { return mRasterType; }
|
||||
@ -553,7 +553,7 @@ class CORE_EXPORT QgsRasterLayer : public QgsMapLayer
|
||||
bool readColorTable( int theBandNumber, QList<QgsColorRampShader::ColorRampItem>* theList );
|
||||
|
||||
/** \brief Simple reset function that set the noDataValue back to the value stored in the first raster band */
|
||||
void resetNoDataValue();
|
||||
//void resetNoDataValue();
|
||||
|
||||
/** \brief Mutator for blue band name mapping */
|
||||
void setBlueBandName( const QString & theBandName );
|
||||
@ -626,7 +626,7 @@ class CORE_EXPORT QgsRasterLayer : public QgsMapLayer
|
||||
Q_DECL_DEPRECATED void setMinimumValue( QString theBand, double theValue, bool theGenerateLookupTableFlag = true );
|
||||
|
||||
/** \brief Mutator that allows the NO_DATA entry for this raster to be overridden */
|
||||
void setNoDataValue( double theNoData );
|
||||
//void setNoDataValue( double theNoData );
|
||||
|
||||
/** \brief Set the raster shader function to a user defined function
|
||||
\note ownership of the shader function is transfered to raster shader */
|
||||
@ -795,7 +795,7 @@ class CORE_EXPORT QgsRasterLayer : public QgsMapLayer
|
||||
|
||||
/** \brief Read a raster value given position from memory block created by readData() */
|
||||
//inline double readValue( void *data, GDALDataType type, int index );
|
||||
inline double readValue( void *data, int type, int index );
|
||||
//inline double readValue( void *data, int type, int index );
|
||||
|
||||
/** \brief Update the layer if it is outdated */
|
||||
bool update();
|
||||
@ -869,7 +869,7 @@ class CORE_EXPORT QgsRasterLayer : public QgsMapLayer
|
||||
bool mModified;
|
||||
|
||||
/** \brief Cell value representing no data. e.g. -9999 */
|
||||
double mNoDataValue;
|
||||
//double mNoDataValue;
|
||||
|
||||
/** [ data provider interface ] Data provider key */
|
||||
QString mProviderKey;
|
||||
@ -889,7 +889,7 @@ class CORE_EXPORT QgsRasterLayer : public QgsMapLayer
|
||||
bool mUserDefinedRGBMinimumMaximum;
|
||||
|
||||
/** \brief Flag indicating if the nodatavalue is valid*/
|
||||
bool mValidNoDataValue;
|
||||
//bool mValidNoDataValue;
|
||||
|
||||
//QgsRasterRenderer* mRenderer;
|
||||
//QgsRasterResampleFilter *mResampleFilter;
|
||||
|
@ -91,7 +91,8 @@ bool QgsRasterRenderer::usesTransparency( ) const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return ( mAlphaBand > 0 || ( mRasterTransparency && !mRasterTransparency->isEmpty( mInput->noDataValue() ) ) || !doubleNear( mOpacity, 1.0 ) );
|
||||
// TODO: nodata per band
|
||||
return ( mAlphaBand > 0 || ( mRasterTransparency && !mRasterTransparency->isEmpty( mInput->noDataValue( 1 ) ) ) || !doubleNear( mOpacity, 1.0 ) );
|
||||
}
|
||||
|
||||
void QgsRasterRenderer::setRasterTransparency( QgsRasterTransparency* t )
|
||||
|
@ -80,7 +80,6 @@ class CORE_EXPORT QgsRasterRenderer : public QgsRasterInterface
|
||||
virtual QList<int> usesBands() const { return QList<int>(); }
|
||||
|
||||
protected:
|
||||
inline double readValue( void *data, QgsRasterInterface::DataType type, int index );
|
||||
|
||||
/**Write upper class info into rasterrenderer element (called by writeXML method of subclasses)*/
|
||||
void _writeXML( QDomDocument& doc, QDomElement& rasterRendererElem ) const;
|
||||
@ -101,47 +100,4 @@ class CORE_EXPORT QgsRasterRenderer : public QgsRasterInterface
|
||||
double mMaxOversampling;
|
||||
};
|
||||
|
||||
inline double QgsRasterRenderer::readValue( void *data, QgsRasterInterface::DataType type, int index )
|
||||
{
|
||||
if ( !mInput )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ( !data )
|
||||
{
|
||||
return mInput->noDataValue();
|
||||
}
|
||||
|
||||
switch ( type )
|
||||
{
|
||||
case QgsRasterInterface::Byte:
|
||||
return ( double )(( GByte * )data )[index];
|
||||
break;
|
||||
case QgsRasterInterface::UInt16:
|
||||
return ( double )(( GUInt16 * )data )[index];
|
||||
break;
|
||||
case QgsRasterInterface::Int16:
|
||||
return ( double )(( GInt16 * )data )[index];
|
||||
break;
|
||||
case QgsRasterInterface::UInt32:
|
||||
return ( double )(( GUInt32 * )data )[index];
|
||||
break;
|
||||
case QgsRasterInterface::Int32:
|
||||
return ( double )(( GInt32 * )data )[index];
|
||||
break;
|
||||
case QgsRasterInterface::Float32:
|
||||
return ( double )(( float * )data )[index];
|
||||
break;
|
||||
case QgsRasterInterface::Float64:
|
||||
return ( double )(( double * )data )[index];
|
||||
break;
|
||||
default:
|
||||
//QgsMessageLog::logMessage( tr( "GDAL data type %1 is not supported" ).arg( type ), tr( "Raster" ) );
|
||||
break;
|
||||
}
|
||||
|
||||
return mInput->noDataValue();
|
||||
}
|
||||
|
||||
#endif // QGSRASTERRENDERER_H
|
||||
|
@ -177,6 +177,7 @@ int QgsRasterTransparency::alphaValue( double theRedValue, double theGreenValue,
|
||||
return theGlobalTransparency;
|
||||
}
|
||||
|
||||
// TODO: nodata per band
|
||||
bool QgsRasterTransparency::isEmpty( double nodataValue ) const
|
||||
{
|
||||
return (
|
||||
|
@ -731,6 +731,7 @@ void QgsGdalProvider::readBlock( int theBandNo, QgsRectangle const & theExtent,
|
||||
}
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
bool QgsGdalProvider::srcHasNoDataValue( int bandNo ) const
|
||||
{
|
||||
if ( mGdalDataset )
|
||||
@ -754,6 +755,7 @@ double QgsGdalProvider::noDataValue() const
|
||||
}
|
||||
return std::numeric_limits<int>::max(); // should not happen or be used
|
||||
}
|
||||
#endif
|
||||
|
||||
void QgsGdalProvider::computeMinMax( int theBandNo )
|
||||
{
|
||||
@ -834,7 +836,7 @@ QMap<int, void *> QgsGdalProvider::identify( const QgsPoint & point )
|
||||
for ( int i = 1; i <= GDALGetRasterCount( mGdalDataset ); i++ )
|
||||
{
|
||||
void * data = VSIMalloc( dataTypeSize( i ) / 8 );
|
||||
writeValue( data, dataType( i ), 0, noDataValue() );
|
||||
writeValue( data, dataType( i ), 0, noDataValue( i ) );
|
||||
results.insert( i, data );
|
||||
}
|
||||
}
|
||||
@ -2127,7 +2129,6 @@ QgsRasterBandStats QgsGdalProvider::bandStatistics( int theBandNo, int theStats,
|
||||
|
||||
#ifdef QGISDEBUG
|
||||
QgsDebugMsg( "************ STATS **************" );
|
||||
QgsDebugMsg( QString( "VALID NODATA %1" ).arg( mValidNoDataValue ) );
|
||||
QgsDebugMsg( QString( "MIN %1" ).arg( myRasterBandStats.minimumValue ) );
|
||||
QgsDebugMsg( QString( "MAX %1" ).arg( myRasterBandStats.maximumValue ) );
|
||||
QgsDebugMsg( QString( "RANGE %1" ).arg( myRasterBandStats.range ) );
|
||||
@ -2273,57 +2274,64 @@ void QgsGdalProvider::initBaseDataset()
|
||||
//
|
||||
// Determine the nodata value and data type
|
||||
//
|
||||
mValidNoDataValue = true;
|
||||
//mValidNoDataValue = true;
|
||||
for ( int i = 1; i <= GDALGetRasterCount( mGdalBaseDataset ); i++ )
|
||||
{
|
||||
computeMinMax( i );
|
||||
GDALRasterBandH myGdalBand = GDALGetRasterBand( mGdalDataset, i );
|
||||
GDALDataType myGdalDataType = GDALGetRasterDataType( myGdalBand );
|
||||
|
||||
int isValid = false;
|
||||
double myNoDataValue = GDALGetRasterNoDataValue( GDALGetRasterBand( mGdalDataset, i ), &isValid );
|
||||
double myNoDataValue = GDALGetRasterNoDataValue( myGdalBand, &isValid );
|
||||
if ( isValid )
|
||||
{
|
||||
QgsDebugMsg( QString( "GDALGetRasterNoDataValue = %1" ).arg( myNoDataValue ) ) ;
|
||||
mGdalDataType.append( myGdalDataType );
|
||||
mSrcNoDataValue.append( myNoDataValue );
|
||||
mSrcHasNoDataValue.append( true );
|
||||
mUseSrcNoDataValue.append( true );
|
||||
}
|
||||
else
|
||||
{
|
||||
// But we need a null value in case of reprojection and BTW also for
|
||||
// aligned margines
|
||||
|
||||
switch ( srcDataType( i ) )
|
||||
{
|
||||
case QgsRasterDataProvider::Byte:
|
||||
// Use longer data type to avoid conflict with real data
|
||||
myNoDataValue = -32768.0;
|
||||
mGdalDataType.append( GDT_Int16 );
|
||||
break;
|
||||
case QgsRasterDataProvider::Int16:
|
||||
myNoDataValue = -2147483648.0;
|
||||
mGdalDataType.append( GDT_Int32 );
|
||||
break;
|
||||
case QgsRasterDataProvider::UInt16:
|
||||
myNoDataValue = -2147483648.0;
|
||||
mGdalDataType.append( GDT_Int32 );
|
||||
break;
|
||||
case QgsRasterDataProvider::Int32:
|
||||
myNoDataValue = -2147483648.0;
|
||||
mGdalDataType.append( myGdalDataType );
|
||||
break;
|
||||
case QgsRasterDataProvider::UInt32:
|
||||
myNoDataValue = 4294967295.0;
|
||||
mGdalDataType.append( myGdalDataType );
|
||||
break;
|
||||
default:
|
||||
myNoDataValue = std::numeric_limits<int>::max();
|
||||
// Would NaN work well?
|
||||
//myNoDataValue = std::numeric_limits<double>::quiet_NaN();
|
||||
mGdalDataType.append( myGdalDataType );
|
||||
}
|
||||
mSrcNoDataValue.append( std::numeric_limits<double>::quiet_NaN() );
|
||||
mSrcHasNoDataValue.append( false );
|
||||
mUseSrcNoDataValue.append( false );
|
||||
}
|
||||
//mSrcNoDataValue.append( myNoDataValue );
|
||||
mNoDataValue.append( myNoDataValue );
|
||||
QgsDebugMsg( QString( "mNoDataValue[%1] = %2" ).arg( i - 1 ).arg( mNoDataValue[i-1] ) );
|
||||
// It may happen that nodata value given by GDAL is wrong and it has to be
|
||||
// disabled by user, in that case we need another value to be used for nodata
|
||||
// (for reprojection for example) -> always internaly represent as wider type
|
||||
// with mInternalNoDataValue in reserve.
|
||||
int myInternalGdalDataType = myGdalDataType;
|
||||
double myInternalNoDataValue = 123;
|
||||
switch ( srcDataType( i ) )
|
||||
{
|
||||
case QgsRasterDataProvider::Byte:
|
||||
myInternalNoDataValue = -32768.0;
|
||||
myInternalGdalDataType = GDT_Int16;
|
||||
break;
|
||||
case QgsRasterDataProvider::Int16:
|
||||
myInternalNoDataValue = -2147483648.0;
|
||||
myInternalGdalDataType = GDT_Int32;
|
||||
break;
|
||||
case QgsRasterDataProvider::UInt16:
|
||||
myInternalNoDataValue = -2147483648.0;
|
||||
myInternalGdalDataType = GDT_Int32;
|
||||
break;
|
||||
case QgsRasterDataProvider::Int32:
|
||||
// We believe that such values is no used in real data
|
||||
myInternalNoDataValue = -2147483648.0;
|
||||
break;
|
||||
case QgsRasterDataProvider::UInt32:
|
||||
// We believe that such values is no used in real data
|
||||
myInternalNoDataValue = 4294967295.0;
|
||||
break;
|
||||
default: // Float32, Float64
|
||||
//myNoDataValue = std::numeric_limits<int>::max();
|
||||
// NaN should work well
|
||||
myInternalNoDataValue = std::numeric_limits<double>::quiet_NaN();
|
||||
}
|
||||
mGdalDataType.append( myInternalGdalDataType );
|
||||
mInternalNoDataValue.append( myInternalNoDataValue );
|
||||
QgsDebugMsg( QString( "mInternalNoDataValue[%1] = %2" ).arg( i - 1 ).arg( mInternalNoDataValue[i-1] ) );
|
||||
}
|
||||
|
||||
mValid = true;
|
||||
|
@ -198,8 +198,8 @@ class QgsGdalProvider : public QgsRasterDataProvider, QgsGdalProviderBase
|
||||
|
||||
//void * readBlock( int bandNo, QgsRectangle const & extent, int width, int height );
|
||||
|
||||
bool srcHasNoDataValue( int bandNo ) const;
|
||||
double noDataValue() const;
|
||||
//bool srcHasNoDataValue( int bandNo ) const;
|
||||
//double noDataValue() const;
|
||||
void computeMinMax( int bandNo );
|
||||
double minimumValue( int bandNo ) const;
|
||||
double maximumValue( int bandNo ) const;
|
||||
|
@ -27,6 +27,7 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
#ifdef WIN32
|
||||
#include <fcntl.h>
|
||||
#include <io.h>
|
||||
@ -140,6 +141,15 @@ static int cell_draw( char *name,
|
||||
long one = 1;
|
||||
FILE *fo;
|
||||
int raster_size;
|
||||
#ifdef NAN
|
||||
double dnul = NAN;
|
||||
float fnul = NAN;
|
||||
#else
|
||||
double dnul = strtod( "NAN", 0 );
|
||||
float fnul = strtof( "NAN", 0 );
|
||||
// another possibility would be nan()/nanf() - C99
|
||||
// and 0./0. if all fails
|
||||
#endif
|
||||
|
||||
big_endian = !( *(( char * )( &one ) ) );
|
||||
|
||||
@ -213,18 +223,19 @@ static int cell_draw( char *name,
|
||||
// see comments in QgsGrassRasterProvider::noDataValue()
|
||||
if ( data_type == CELL_TYPE )
|
||||
{
|
||||
int nul = -2000000000;
|
||||
//int nul = -2000000000;
|
||||
int nul = -2147483648;
|
||||
fwrite( &nul , 4, 1, fo );
|
||||
}
|
||||
else if ( data_type == DCELL_TYPE )
|
||||
{
|
||||
double nul = -1e+300;
|
||||
fwrite( &nul , 8, 1, fo );
|
||||
//double nul = -1e+300;
|
||||
fwrite( &dnul , 8, 1, fo );
|
||||
}
|
||||
else if ( data_type == FCELL_TYPE )
|
||||
{
|
||||
double nul = -1e+30;
|
||||
fwrite( &nul , 4, 1, fo );
|
||||
//double nul = -1e+30;
|
||||
fwrite( &fnul , 4, 1, fo );
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -15,7 +15,7 @@
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
#include <limits>
|
||||
|
||||
#include "qgslogger.h"
|
||||
#include "qgsgrass.h"
|
||||
@ -76,7 +76,7 @@ QgsGrassRasterProvider::QgsGrassRasterProvider( QString const & uri )
|
||||
mTimestamp = dataTimestamp();
|
||||
|
||||
mRasterValue.start( mGisdbase, mLocation, mMapset, mMapName );
|
||||
mValidNoDataValue = true;
|
||||
//mValidNoDataValue = true;
|
||||
|
||||
mCrs = QgsGrass::crs( mGisdbase, mLocation );
|
||||
QgsDebugMsg( "mCrs: " + mCrs.toWkt() );
|
||||
@ -92,10 +92,11 @@ QgsGrassRasterProvider::QgsGrassRasterProvider( QString const & uri )
|
||||
|
||||
// TODO: avoid showing these strange numbers in GUI
|
||||
// TODO: don't save no data values in project file, add a flag if value was defined by user
|
||||
|
||||
double myInternalNoDataValue;
|
||||
if ( mGrassDataType == CELL_TYPE )
|
||||
{
|
||||
//limit: -2147483647;
|
||||
mNoDataValue = -2000000000;
|
||||
myInternalNoDataValue = -2147483648;
|
||||
}
|
||||
else if ( mGrassDataType == DCELL_TYPE )
|
||||
{
|
||||
@ -105,7 +106,8 @@ QgsGrassRasterProvider::QgsGrassRasterProvider( QString const & uri )
|
||||
// No data value is shown in GUI, use some nice number.
|
||||
// Choose values with small representation error.
|
||||
// limit: 1.7976931348623157e+308
|
||||
mNoDataValue = -1e+300;
|
||||
//myInternalNoDataValue = -1e+300;
|
||||
myInternalNoDataValue = std::numeric_limits<double>::quiet_NaN();
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -115,9 +117,11 @@ QgsGrassRasterProvider::QgsGrassRasterProvider( QString const & uri )
|
||||
}
|
||||
|
||||
// limit: 3.40282347e+38
|
||||
mNoDataValue = -1e+30;
|
||||
//myInternalNoDataValue = -1e+30;
|
||||
myInternalNoDataValue = std::numeric_limits<float>::quiet_NaN();
|
||||
}
|
||||
QgsDebugMsg( QString( "mNoDataValue = %1" ).arg( mNoDataValue ) );
|
||||
mInternalNoDataValue.append( myInternalNoDataValue );
|
||||
QgsDebugMsg( QString( "myInternalNoDataValue = %1" ).arg( myInternalNoDataValue ) );
|
||||
|
||||
// TODO: refresh mRows and mCols if raster was rewritten
|
||||
// We have to decide some reasonable block size, not to big to occupate too much
|
||||
@ -285,11 +289,6 @@ void QgsGrassRasterProvider::readBlock( int bandNo, QgsRectangle const & viewEx
|
||||
memcpy( block, data.data(), size );
|
||||
}
|
||||
|
||||
double QgsGrassRasterProvider::noDataValue() const
|
||||
{
|
||||
return mNoDataValue;
|
||||
}
|
||||
|
||||
double QgsGrassRasterProvider::minimumValue( int bandNo ) const
|
||||
{
|
||||
Q_UNUSED( bandNo );
|
||||
@ -428,7 +427,7 @@ QMap<int, void *> QgsGrassRasterProvider::identify( const QgsPoint & thePoint )
|
||||
QString strValue = mRasterValue.value( thePoint.x(), thePoint.y() );
|
||||
// attention, value tool does his own tricks with grass identify() so it stops to refresh values outside extent or null values e.g.
|
||||
|
||||
double value = noDataValue();
|
||||
double value = noDataValue( 1 );
|
||||
|
||||
if ( strValue != "out" && strValue != "null" )
|
||||
{
|
||||
|
@ -209,7 +209,7 @@ class QgsGrassRasterProvider : public QgsRasterDataProvider
|
||||
void readBlock( int bandNo, int xBlock, int yBlock, void *data );
|
||||
void readBlock( int bandNo, QgsRectangle const & viewExtent, int width, int height, void *data );
|
||||
|
||||
double noDataValue() const;
|
||||
//double noDataValue() const;
|
||||
double minimumValue( int bandNo )const;
|
||||
double maximumValue( int bandNo )const;
|
||||
|
||||
@ -263,7 +263,7 @@ class QgsGrassRasterProvider : public QgsRasterDataProvider
|
||||
|
||||
QgsGrassRasterValue mRasterValue;
|
||||
|
||||
double mNoDataValue;
|
||||
//double mNoDataValue;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -187,6 +187,32 @@ void QgsWcsCapabilities::clear()
|
||||
mCapabilities = c;
|
||||
}
|
||||
|
||||
QString QgsWcsCapabilities::getCapabilitiesUrl( const QString version ) const
|
||||
{
|
||||
QString url = prepareUri( mUri.param( "url" ) ) + "SERVICE=WCS&REQUEST=GetCapabilities";
|
||||
|
||||
if ( !version.isEmpty() )
|
||||
{
|
||||
// 1.0.0 - VERSION
|
||||
// 1.1.0 - AcceptVersions (not supported by UMN Mapserver 6.0.3 - defaults to latest 1.1
|
||||
if ( version.startsWith( "1.0" ) )
|
||||
{
|
||||
url += "&VERSION=" + version;
|
||||
}
|
||||
else if ( version.startsWith( "1.1" ) )
|
||||
{
|
||||
// Ignored by UMN Mapserver 6.0.3, see below
|
||||
url += "&AcceptVersions=" + version;
|
||||
}
|
||||
}
|
||||
return url;
|
||||
}
|
||||
|
||||
QString QgsWcsCapabilities::getCapabilitiesUrl( ) const
|
||||
{
|
||||
return getCapabilitiesUrl( mVersion );
|
||||
}
|
||||
|
||||
bool QgsWcsCapabilities::retrieveServerCapabilities( )
|
||||
{
|
||||
clear();
|
||||
@ -196,21 +222,10 @@ bool QgsWcsCapabilities::retrieveServerCapabilities( )
|
||||
|
||||
if ( !preferredVersion.isEmpty() )
|
||||
{
|
||||
// This is not
|
||||
if ( preferredVersion.startsWith( "1.0" ) )
|
||||
{
|
||||
versions << "VERSION=" + preferredVersion;
|
||||
}
|
||||
else if ( preferredVersion.startsWith( "1.1" ) )
|
||||
{
|
||||
// Ignored by UMN Mapserver 6.0.3, see below
|
||||
versions << "AcceptVersions=" + preferredVersion;
|
||||
}
|
||||
versions << preferredVersion;
|
||||
}
|
||||
else
|
||||
{
|
||||
// 1.0.0 - VERSION
|
||||
// 1.1.0 - AcceptVersions (not supported by UMN Mapserver 6.0.3 - defaults to latest 1.1
|
||||
// We prefer 1.0 because 1.1 has many issues, each server implements it in defferent
|
||||
// way with various particularities
|
||||
// It may happen that server supports 1.1.0 but gives error for 1.1
|
||||
@ -232,12 +247,7 @@ bool QgsWcsCapabilities::retrieveServerCapabilities( QString preferredVersion )
|
||||
{
|
||||
clear();
|
||||
|
||||
QString url = prepareUri( mUri.param( "url" ) ) + "SERVICE=WCS&REQUEST=GetCapabilities";
|
||||
|
||||
if ( !preferredVersion.isEmpty() )
|
||||
{
|
||||
url += "&" + preferredVersion;
|
||||
}
|
||||
QString url = getCapabilitiesUrl( preferredVersion );
|
||||
|
||||
if ( ! sendRequest( url ) ) { return false; }
|
||||
|
||||
@ -261,6 +271,23 @@ bool QgsWcsCapabilities::retrieveServerCapabilities( QString preferredVersion )
|
||||
return true;
|
||||
}
|
||||
|
||||
QString QgsWcsCapabilities::getDescribeCoverageUrl( QString const &identifier ) const
|
||||
{
|
||||
QString url = prepareUri( mUri.param( "url" ) ) + "SERVICE=WCS&REQUEST=DescribeCoverage&VERSION=" + mVersion;
|
||||
|
||||
if ( mVersion.startsWith( "1.0" ) )
|
||||
{
|
||||
url += "&COVERAGE=" + identifier;
|
||||
}
|
||||
else if ( mVersion.startsWith( "1.1" ) )
|
||||
{
|
||||
// in 1.1.0, 1.1.1, 1.1.2 the name of param is 'identifier'
|
||||
// but in KVP 'identifiers'
|
||||
url += "&IDENTIFIERS=" + identifier;
|
||||
}
|
||||
return url;
|
||||
}
|
||||
|
||||
bool QgsWcsCapabilities::describeCoverage( QString const &identifier, bool forceRefresh )
|
||||
{
|
||||
QgsDebugMsg( " identifier = " + identifier );
|
||||
@ -274,18 +301,7 @@ bool QgsWcsCapabilities::describeCoverage( QString const &identifier, bool force
|
||||
|
||||
if ( coverage->described && ! forceRefresh ) return true;
|
||||
|
||||
QString url = prepareUri( mUri.param( "url" ) ) + "SERVICE=WCS&REQUEST=DescribeCoverage&VERSION=" + mVersion;
|
||||
|
||||
if ( mVersion.startsWith( "1.0" ) )
|
||||
{
|
||||
url += "&COVERAGE=" + coverage->identifier;
|
||||
}
|
||||
else if ( mVersion.startsWith( "1.1" ) )
|
||||
{
|
||||
// in 1.1.0, 1.1.1, 1.1.2 the name of param is 'identifier'
|
||||
// but in KVP 'identifiers'
|
||||
url += "&IDENTIFIERS=" + coverage->identifier;
|
||||
}
|
||||
QString url = getDescribeCoverageUrl( coverage->identifier );
|
||||
|
||||
if ( ! sendRequest( url ) ) { return false; }
|
||||
|
||||
|
@ -125,8 +125,17 @@ class QgsWcsCapabilities : public QObject
|
||||
*/
|
||||
static QString prepareUri( QString uri );
|
||||
|
||||
/**Returns the GetCoverage url
|
||||
*/
|
||||
/** \brief Returns the GetCoverage full url
|
||||
* \param version optional version, e.g. 1.0.0 or 1.1.0 */
|
||||
QString getCapabilitiesUrl( const QString version ) const;
|
||||
|
||||
/** \brief Returns the GetCoverage full url using current version */
|
||||
QString getCapabilitiesUrl() const;
|
||||
|
||||
/** \brief Returns the GetCoverage full full url using current version */
|
||||
QString getDescribeCoverageUrl( QString const &identifier ) const;
|
||||
|
||||
/** Returns the GetCoverage base url */
|
||||
QString getCoverageUrl() const;
|
||||
|
||||
//! Send request to server
|
||||
@ -225,7 +234,7 @@ class QgsWcsCapabilities : public QObject
|
||||
/**
|
||||
* \brief Retrieve and parse the (cached) Capabilities document from the server
|
||||
*
|
||||
* \param preferredVersion - optional version KVP
|
||||
* \param preferredVersion - optional version, e.g. 1.0.0, 1.1.0
|
||||
*
|
||||
* \retval false if the capabilities document could not be retrieved or parsed -
|
||||
* see lastError() for more info
|
||||
|
@ -280,56 +280,62 @@ QgsWcsProvider::QgsWcsProvider( QString const &uri )
|
||||
|
||||
QgsDebugMsg( QString( "myGdalDataType[%1] = %2" ).arg( i - 1 ).arg( myGdalDataType ) );
|
||||
mSrcGdalDataType.append( myGdalDataType );
|
||||
// TODO: This could be shared with GDAL provider
|
||||
int isValid = false;
|
||||
|
||||
// UMN Mapserver does not automaticaly set null value, METADATA wcs_rangeset_nullvalue must be used
|
||||
// http://lists.osgeo.org/pipermail/mapserver-users/2010-April/065328.html
|
||||
|
||||
// TODO:
|
||||
|
||||
// TODO: This could be shared with GDAL provider
|
||||
int isValid = false;
|
||||
double myNoDataValue = GDALGetRasterNoDataValue( gdalBand, &isValid );
|
||||
if ( isValid )
|
||||
{
|
||||
QgsDebugMsg( QString( "GDALGetRasterNoDataValue = %1" ).arg( myNoDataValue ) ) ;
|
||||
mGdalDataType.append( myGdalDataType );
|
||||
mSrcNoDataValue.append( myNoDataValue );
|
||||
mSrcHasNoDataValue.append( true );
|
||||
mUseSrcNoDataValue.append( true );
|
||||
}
|
||||
else
|
||||
{
|
||||
// But we need a null value in case of reprojection and BTW also for
|
||||
// aligned margines
|
||||
switch ( dataTypeFromGdal( myGdalDataType ) )
|
||||
{
|
||||
|
||||
case QgsRasterDataProvider::Byte:
|
||||
// Use longer data type to avoid conflict with real data
|
||||
myNoDataValue = -32768.0;
|
||||
mGdalDataType.append( GDT_Int16 );
|
||||
break;
|
||||
case QgsRasterDataProvider::Int16:
|
||||
myNoDataValue = -2147483648.0;
|
||||
mGdalDataType.append( GDT_Int32 );
|
||||
break;
|
||||
case QgsRasterDataProvider::UInt16:
|
||||
myNoDataValue = -2147483648.0;
|
||||
mGdalDataType.append( GDT_Int32 );
|
||||
break;
|
||||
case QgsRasterDataProvider::Int32:
|
||||
myNoDataValue = -2147483648.0;
|
||||
mGdalDataType.append( myGdalDataType );
|
||||
break;
|
||||
case QgsRasterDataProvider::UInt32:
|
||||
myNoDataValue = 4294967295.0;
|
||||
mGdalDataType.append( myGdalDataType );
|
||||
break;
|
||||
default:
|
||||
myNoDataValue = std::numeric_limits<int>::max();
|
||||
// Would NaN work well?
|
||||
//myNoDataValue = std::numeric_limits<double>::quiet_NaN();
|
||||
mGdalDataType.append( myGdalDataType );
|
||||
}
|
||||
mSrcNoDataValue.append( std::numeric_limits<double>::quiet_NaN() );
|
||||
mSrcHasNoDataValue.append( false );
|
||||
mUseSrcNoDataValue.append( false );
|
||||
}
|
||||
mNoDataValue.append( myNoDataValue );
|
||||
// It may happen that nodata value given by GDAL is wrong and it has to be
|
||||
// disabled by user, in that case we need another value to be used for nodata
|
||||
// (for reprojection for example) -> always internaly represent as wider type
|
||||
// with mInternalNoDataValue in reserve.
|
||||
int myInternalGdalDataType = myGdalDataType;
|
||||
double myInternalNoDataValue;
|
||||
switch ( srcDataType( i ) )
|
||||
{
|
||||
case QgsRasterDataProvider::Byte:
|
||||
myInternalNoDataValue = -32768.0;
|
||||
myInternalGdalDataType = GDT_Int16;
|
||||
break;
|
||||
case QgsRasterDataProvider::Int16:
|
||||
myInternalNoDataValue = -2147483648.0;
|
||||
myInternalGdalDataType = GDT_Int32;
|
||||
break;
|
||||
case QgsRasterDataProvider::UInt16:
|
||||
myInternalNoDataValue = -2147483648.0;
|
||||
myInternalGdalDataType = GDT_Int32;
|
||||
break;
|
||||
case QgsRasterDataProvider::Int32:
|
||||
// We believe that such values is no used in real data
|
||||
myInternalNoDataValue = -2147483648.0;
|
||||
break;
|
||||
case QgsRasterDataProvider::UInt32:
|
||||
// We believe that such values is no used in real data
|
||||
myInternalNoDataValue = 4294967295.0;
|
||||
break;
|
||||
default: // Float32, Float64
|
||||
//myNoDataValue = std::numeric_limits<int>::max();
|
||||
// NaN should work well
|
||||
myInternalNoDataValue = std::numeric_limits<double>::quiet_NaN();
|
||||
}
|
||||
mGdalDataType.append( myInternalGdalDataType );
|
||||
mInternalNoDataValue.append( myInternalNoDataValue );
|
||||
QgsDebugMsg( QString( "mInternalNoDataValue[%1] = %2" ).arg( i - 1 ).arg( mInternalNoDataValue[i-1] ) );
|
||||
|
||||
// TODO: what to do if null values from DescribeCoverage differ?
|
||||
if ( !mCoverageSummary.nullValues.contains( myNoDataValue ) )
|
||||
@ -337,11 +343,9 @@ QgsWcsProvider::QgsWcsProvider( QString const &uri )
|
||||
QgsDebugMsg( QString( "noDataValue %1 is missing in nullValues from CoverageDescription" ).arg( myNoDataValue ) );
|
||||
}
|
||||
|
||||
mValidNoDataValue = true;
|
||||
|
||||
QgsDebugMsg( QString( "mSrcGdalDataType[%1] = %2" ).arg( i - 1 ).arg( mSrcGdalDataType[i-1] ) );
|
||||
QgsDebugMsg( QString( "mGdalDataType[%1] = %2" ).arg( i - 1 ).arg( mGdalDataType[i-1] ) );
|
||||
QgsDebugMsg( QString( "mNoDataValue[%1] = %2" ).arg( i - 1 ).arg( mNoDataValue[i-1] ) );
|
||||
QgsDebugMsg( QString( "mSrcNoDataValue[%1] = %2" ).arg( i - 1 ).arg( mSrcNoDataValue[i-1] ) );
|
||||
|
||||
// Create and store color table
|
||||
// TODO: never tested because mapserver (6.0.3) does not support color tables
|
||||
@ -1074,15 +1078,6 @@ int QgsWcsProvider::bandCount() const
|
||||
return mBandCount;
|
||||
}
|
||||
|
||||
double QgsWcsProvider::noDataValue() const
|
||||
{
|
||||
if ( mNoDataValue.size() > 0 )
|
||||
{
|
||||
return mNoDataValue[0];
|
||||
}
|
||||
return std::numeric_limits<int>::max(); // should not happen or be used
|
||||
}
|
||||
|
||||
// this is only called once when statistics are calculated
|
||||
// TODO
|
||||
int QgsWcsProvider::xBlockSize() const
|
||||
@ -1525,7 +1520,7 @@ QMap<int, void *> QgsWcsProvider::identify( const QgsPoint & thePoint )
|
||||
for ( int i = 1; i <= bandCount(); i++ )
|
||||
{
|
||||
void * data = VSIMalloc( dataTypeSize( i ) / 8 );
|
||||
writeValue( data, dataType( i ), 0, noDataValue() );
|
||||
writeValue( data, dataType( i ), 0, noDataValue( i ) );
|
||||
results.insert( i, data );
|
||||
}
|
||||
return results;
|
||||
|
@ -147,7 +147,7 @@ class QgsWcsProvider : public QgsRasterDataProvider, QgsGdalProviderBase
|
||||
QgsRasterInterface::DataType dataType( int bandNo ) const;
|
||||
QgsRasterInterface::DataType srcDataType( int bandNo ) const;
|
||||
int bandCount() const;
|
||||
double noDataValue() const;
|
||||
//double noDataValue() const;
|
||||
int xBlockSize() const;
|
||||
int yBlockSize() const;
|
||||
int xSize() const;
|
||||
@ -303,7 +303,7 @@ class QgsWcsProvider : public QgsRasterDataProvider, QgsGdalProviderBase
|
||||
QList<int>mSrcGdalDataType;
|
||||
|
||||
/** \brief Cell value representing no data. e.g. -9999, indexed from 0 */
|
||||
QList<double> mNoDataValue;
|
||||
//QList<double> mNoDataValue;
|
||||
|
||||
/** Color tables indexed from 0 */
|
||||
QList< QList<QgsColorRampShader::ColorRampItem> > mColorTables;
|
||||
|
@ -439,9 +439,12 @@
|
||||
<number>1</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLabel" name="lblSrcNoDataValueLabel">
|
||||
<widget class="QCheckBox" name="mSrcNoDataValueCheckBox">
|
||||
<property name="toolTip">
|
||||
<string>Use original source no data value.</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Source no data value:</string>
|
||||
<string>No data value:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
@ -166,7 +166,7 @@ bool TestQgsRasterFileWriter::writeTest( QString theRasterName )
|
||||
// All OK, we can delete the file
|
||||
tmpFile.setAutoRemove( ok );
|
||||
|
||||
return true;
|
||||
return ok;
|
||||
}
|
||||
|
||||
void TestQgsRasterFileWriter::log( QString msg )
|
||||
|
@ -96,6 +96,7 @@ IF(UNIX AND NOT ANDROID AND CMAKE_BUILD_TYPE MATCHES Debug)
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../../../src/core
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../../../src/core/raster
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../../../src/providers/wcs
|
||||
${QT_QTSCRIPT_INCLUDE_DIR}
|
||||
)
|
||||
|
||||
TARGET_LINK_LIBRARIES(qgis_wcstest
|
||||
@ -105,6 +106,7 @@ IF(UNIX AND NOT ANDROID AND CMAKE_BUILD_TYPE MATCHES Debug)
|
||||
${QT_QTXML_LIBRARY}
|
||||
${QT_QTWEBKIT_LIBRARY}
|
||||
${QT_QTMAIN_LIBRARY}
|
||||
${QT_QTSCRIPT_LIBRARY}
|
||||
qgis_core
|
||||
)
|
||||
|
||||
@ -112,5 +114,6 @@ IF(UNIX AND NOT ANDROID AND CMAKE_BUILD_TYPE MATCHES Debug)
|
||||
BUNDLE DESTINATION ${QGIS_BIN_DIR}
|
||||
RUNTIME DESTINATION ${QGIS_BIN_DIR}
|
||||
)
|
||||
INSTALL(FILES wcs-servers.json DESTINATION ${QGIS_DATA_DIR}/resources)
|
||||
|
||||
ENDIF(UNIX AND NOT ANDROID AND CMAKE_BUILD_TYPE MATCHES Debug)
|
||||
|
@ -21,6 +21,9 @@
|
||||
#include <QString>
|
||||
#include <QStringList>
|
||||
#include <QTextStream>
|
||||
#include <QScriptEngine>
|
||||
#include <QScriptValue>
|
||||
#include <QScriptValueIterator>
|
||||
|
||||
#include <qgsapplication.h>
|
||||
#include <qgsdatasourceuri.h>
|
||||
@ -46,11 +49,12 @@ int _fmode = _O_BINARY;
|
||||
#include <getopt.h>
|
||||
#endif
|
||||
|
||||
TestQgsWcsPublicServers::TestQgsWcsPublicServers( const QString & cacheDirPath, int maxCoverages, const QString & server, const QString & coverage, bool force ):
|
||||
TestQgsWcsPublicServers::TestQgsWcsPublicServers( const QString & cacheDirPath, int maxCoverages, const QString & server, const QString & coverage, const QString &version, bool force ):
|
||||
mCacheDirPath( cacheDirPath )
|
||||
, mMaxCoverages( maxCoverages )
|
||||
, mServer( server )
|
||||
, mCoverage( coverage )
|
||||
, mVersion( version )
|
||||
, mForce( force )
|
||||
{
|
||||
|
||||
@ -83,56 +87,123 @@ void TestQgsWcsPublicServers::init()
|
||||
mHead << "Values";
|
||||
mHead << "Colors";
|
||||
mHead << "Has size";
|
||||
|
||||
// read servers + issues list
|
||||
QString path = QgsApplication::pkgDataPath() + "/resources/wcs-servers.json";
|
||||
QFile file( path );
|
||||
if ( file.open( QIODevice::ReadOnly | QIODevice::Text ) )
|
||||
{
|
||||
QString data = file.readAll();
|
||||
//QgsDebugMsg("servers: \n" + str );
|
||||
file.close();
|
||||
QScriptEngine engine;
|
||||
QScriptValue result = engine.evaluate( data );
|
||||
|
||||
QScriptValueIterator serverIt( result );
|
||||
while ( serverIt.hasNext() )
|
||||
{
|
||||
serverIt.next();
|
||||
QScriptValue serverValue = serverIt.value();
|
||||
|
||||
QString serverUrl = serverValue.property( "url" ).toString();
|
||||
QgsDebugMsg( "serverUrl: " + serverUrl );
|
||||
|
||||
Server server( serverUrl );
|
||||
|
||||
QScriptValue issuesValue = serverValue.property( "issues" );
|
||||
|
||||
QScriptValueIterator issuesIt( issuesValue );
|
||||
while ( issuesIt.hasNext() )
|
||||
{
|
||||
issuesIt.next();
|
||||
QScriptValue issueValue = issuesIt.value();
|
||||
|
||||
QString description = issueValue.property( "description" ).toString();
|
||||
QgsDebugMsg( "description: " + description );
|
||||
Issue issue( description );
|
||||
|
||||
QScriptValue coveragesValue = issueValue.property( "coverages" );
|
||||
QScriptValueIterator coveragesIt( coveragesValue );
|
||||
while ( coveragesIt.hasNext() )
|
||||
{
|
||||
coveragesIt.next();
|
||||
issue.coverages << coveragesIt.value().toString();
|
||||
}
|
||||
|
||||
QScriptValue versionsValue = issueValue.property( "versions" );
|
||||
QScriptValueIterator versionsIt( versionsValue );
|
||||
while ( versionsIt.hasNext() )
|
||||
{
|
||||
versionsIt.next();
|
||||
issue.versions << versionsIt.value().toString();
|
||||
}
|
||||
|
||||
server.issues << issue;
|
||||
}
|
||||
|
||||
mServers << server;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
QgsDebugMsg( "Cannot open " + path );
|
||||
}
|
||||
}
|
||||
|
||||
QStringList TestQgsWcsPublicServers::issueDescriptions( const QString & url, const QString & coverage, const QString &version )
|
||||
{
|
||||
QStringList descriptions;
|
||||
foreach ( Server server, mServers )
|
||||
{
|
||||
if ( server.url == url )
|
||||
{
|
||||
foreach ( Issue issue, server.issues )
|
||||
{
|
||||
if (( issue.coverages.size() == 0 || issue.coverages.contains( coverage ) ) &&
|
||||
( issue.versions.size() == 0 || issue.versions.contains( version ) ) )
|
||||
{
|
||||
descriptions << issue.description;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return descriptions;
|
||||
}
|
||||
|
||||
void TestQgsWcsPublicServers::test( )
|
||||
{
|
||||
QStringList versions;
|
||||
// It may happen that server supports 1.1.1, but does not accept 1.1 (http://zeus.pin.unifi.it/gi-wcs/http)
|
||||
versions << "" << "1.0.0" << "1.1.0"; // empty for default
|
||||
QStringList serverUrls;
|
||||
|
||||
if ( !mServer.isEmpty() )
|
||||
// It may happen that server supports 1.1.1, but does not accept 1.1 (http://zeus.pin.unifi.it/gi-wcs/http)
|
||||
|
||||
if ( !mVersion.isEmpty() )
|
||||
{
|
||||
Server server( mServer );
|
||||
mServers << server;
|
||||
versions << mVersion;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Some (first) coverages do not advertize any supportedCRS and sever gives
|
||||
// error both with native CRS (EPSG::561005) and EPSG:4326
|
||||
// MOD* coverages work OK
|
||||
mServers << Server( "http://argon.geogr.uni-jena.de:8080/geoserver/ows" );
|
||||
mServers << Server( "http://demo.geonode.org/geoserver/wcs" );
|
||||
mServers << Server( "http://demo.mapserver.org/cgi-bin/wcs" );
|
||||
mServers << Server( "http://demo.opengeo.org/geoserver/wcs" );
|
||||
// geobrain.laits.gmu.edu servers are quite slow
|
||||
mServers << Server( "http://geobrain.laits.gmu.edu/cgi-bin/gbwcs-dem" );
|
||||
//mServers << Server ( "http://geobrain.laits.gmu.edu/cgi-bin/ows8/wcseo" );
|
||||
//mServers << Server ( "http://geobrain.laits.gmu.edu/cgi-bin/wcs110" );
|
||||
//mServers << Server ( "http://geobrain.laits.gmu.edu/cgi-bin/wcs-all" );
|
||||
//mServers << Server ( "http://ws.csiss.gmu.edu/cgi-bin/wcs-t" );
|
||||
// Big and slow
|
||||
//mServers << Server ( "http://ws.laits.gmu.edu/cgi-bin/wcs-all" );
|
||||
// Slow
|
||||
//mServers << Server ( "http://iceds.ge.ucl.ac.uk/cgi-bin/icedswcs" );
|
||||
mServers << Server( "http://motherlode.ucar.edu:8080/thredds/wcs/fmrc/NCEP/DGEX/Alaska_12km/NCEP-DGEX-Alaska_12km_best.ncd" );
|
||||
mServers << Server( "http://navigator.state.or.us/ArcGIS/services/Framework/Imagery_Mosaic2009/ImageServer/WCSServer" );
|
||||
mServers << Server( "http://nsidc.org/cgi-bin/atlas_north" );
|
||||
// Slow
|
||||
//mServers << Server ( "http://sedac.ciesin.columbia.edu/geoserver/wcs" );
|
||||
// Big and slow
|
||||
//mServers << Server ( "http://webmap.ornl.gov/ogcbroker/wcs" );
|
||||
// Currently very slow or down
|
||||
//mServers << Server ( "http://www.sogeo.ch/geoserver/wcs" );
|
||||
// Slow and erroneous
|
||||
//mServers << Server ( "http://zeus.pin.unifi.it/gi-wcs/http" );
|
||||
versions << "" << "1.0.0" << "1.1.0"; // empty for default
|
||||
}
|
||||
|
||||
foreach ( Server server, mServers )
|
||||
|
||||
if ( !mServer.isEmpty() )
|
||||
{
|
||||
serverUrls << mServer;
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach ( Server server, mServers )
|
||||
{
|
||||
serverUrls << server.url;
|
||||
}
|
||||
}
|
||||
|
||||
foreach ( QString serverUrl, serverUrls )
|
||||
{
|
||||
QStringList myServerLog;
|
||||
myServerLog << "server:" + server.url;
|
||||
QString myServerDirName = server.url;
|
||||
myServerLog << "server:" + serverUrl;
|
||||
QString myServerDirName = serverUrl;
|
||||
myServerDirName.replace( QRegExp( "[:/]+" ), "." );
|
||||
myServerDirName.replace( QRegExp( "\\.$" ), "" );
|
||||
QgsDebugMsg( "myServerDirName = " + myServerDirName );
|
||||
@ -148,7 +219,7 @@ void TestQgsWcsPublicServers::test( )
|
||||
|
||||
foreach ( QString version, versions )
|
||||
{
|
||||
QgsDebugMsg( "server: " + server.url + " version: " + version );
|
||||
QgsDebugMsg( "server: " + serverUrl + " version: " + version );
|
||||
QStringList myVersionLog;
|
||||
myVersionLog << "version:" + version;
|
||||
|
||||
@ -165,7 +236,7 @@ void TestQgsWcsPublicServers::test( )
|
||||
|
||||
QgsDataSourceURI myServerUri;
|
||||
|
||||
myServerUri.setParam( "url", server.url );
|
||||
myServerUri.setParam( "url", serverUrl );
|
||||
if ( !version.isEmpty() )
|
||||
{
|
||||
myServerUri.setParam( "version", version );
|
||||
@ -174,6 +245,7 @@ void TestQgsWcsPublicServers::test( )
|
||||
QgsWcsCapabilities myCapabilities;
|
||||
myCapabilities.setUri( myServerUri );
|
||||
|
||||
|
||||
if ( !myCapabilities.lastError().isEmpty() )
|
||||
{
|
||||
QgsDebugMsg( myCapabilities.lastError() );
|
||||
@ -181,6 +253,8 @@ void TestQgsWcsPublicServers::test( )
|
||||
continue;
|
||||
}
|
||||
|
||||
myVersionLog << "getCapabilitiesUrl:" + myCapabilities.getCapabilitiesUrl();
|
||||
|
||||
QVector<QgsWcsCoverageSummary> myCoverages;
|
||||
if ( !myCapabilities.supportedCoverages( myCoverages ) )
|
||||
{
|
||||
@ -238,7 +312,7 @@ void TestQgsWcsPublicServers::test( )
|
||||
myUri.setParam( "time", myCoverage.times.value( 0 ) );
|
||||
}
|
||||
myLog << "version:" + version;
|
||||
myLog << "uri:" + myUri.encodedUri();
|
||||
myLog << "describeCoverageUrl:" + myCapabilities.getDescribeCoverageUrl( myCoverage.identifier );
|
||||
// Test time
|
||||
//myLog << "date:" + QString( "%1").arg( QDateTime::currentDateTime().toTime_t() );
|
||||
myLog << "date:" + QString( "%1" ).arg( QDateTime::currentDateTime().toString() );
|
||||
@ -405,7 +479,7 @@ void TestQgsWcsPublicServers::report()
|
||||
QDir myVersionDir( myVersionDirPath );
|
||||
|
||||
QString myVersion = myVersionLog.value( "version" );
|
||||
myServerReport += QString( "<h3>Version: %1</h3>" ).arg( myVersion.isEmpty() ? "(empty)" : myVersion );
|
||||
myServerReport += QString( "<h3><a href='%1'>Version: %2</a></h3>" ).arg( myVersionLog.value( "getCapabilitiesUrl" ) ).arg( myVersion.isEmpty() ? "(empty)" : myVersion );
|
||||
|
||||
if ( !myVersionLog.value( "error" ).isEmpty() )
|
||||
{
|
||||
@ -433,13 +507,15 @@ void TestQgsWcsPublicServers::report()
|
||||
QString myLogPath = myVersionDir.absolutePath() + QDir::separator() + myLogFileName;
|
||||
QMap<QString, QString>myLog = readLog( myLogPath );
|
||||
QStringList myValues;
|
||||
myValues << myLog.value( "identifier" );
|
||||
myValues << QString( "<a href='%1'>%2</a>" ).arg( myLog.value( "describeCoverageUrl" ) ).arg( myLog.value( "identifier" ) );
|
||||
myValues << myLog.value( "version" );
|
||||
QString imgPath = myVersionDir.absolutePath() + QDir::separator() + QFileInfo( myLogPath ).completeBaseName() + ".png";
|
||||
|
||||
if ( !myLog.value( "error" ).isEmpty() )
|
||||
{
|
||||
myValues << myLog.value( "error" );
|
||||
QStringList issues = issueDescriptions( myServerLog.value( "server" ), myLog.value( "identifier" ), myLog.value( "version" ) );
|
||||
myValues << issues.join( "<br>" );
|
||||
myVersionReport += row( myValues, "cellerr" );
|
||||
myVersionErrCount++;
|
||||
}
|
||||
@ -473,10 +549,10 @@ void TestQgsWcsPublicServers::report()
|
||||
myVersionReport += row( myValues, cls );
|
||||
}
|
||||
} // coverages
|
||||
myVersionReport += "</table>";
|
||||
myVersionReport += "</table>\n";
|
||||
// prepend counts
|
||||
myVersionReport.prepend( QString( "<b>Coverages: %1</b><br>" ).arg( myVersionCoverageCount ) +
|
||||
QString( "<b>Errors: %1</b><br>" ).arg( myVersionErrCount ) +
|
||||
myVersionReport.prepend( QString( "<b>Coverages: %1</b><br>\n" ).arg( myVersionCoverageCount ) +
|
||||
QString( "<b>Errors: %1</b><br>\n" ).arg( myVersionErrCount ) +
|
||||
QString( "<b>Warnings: %1</b><br><br>" ).arg( myVersionWarnCount ) );
|
||||
myServerReport += myVersionReport;
|
||||
}
|
||||
@ -504,12 +580,12 @@ void TestQgsWcsPublicServers::report()
|
||||
myRep += "</style>";
|
||||
|
||||
myRep += QString( "<p>Tested first %1 coverages for each server/version</p>" ).arg( mMaxCoverages );
|
||||
myRep += QString( "<b>Servers: %1</b><br>" ).arg( myServerCount );
|
||||
myRep += QString( "<b>Servers with error: %1</b><br>" ).arg( myServerErrCount );
|
||||
myRep += QString( "<b>Servers with warning: %1</b><br>" ).arg( myServerWarnCount );
|
||||
myRep += QString( "<b>Coverages: %1</b><br>" ).arg( myCoverageCount );
|
||||
myRep += QString( "<b>Coverage errors: %1</b><br>" ).arg( myCoverageErrCount );
|
||||
myRep += QString( "<b>Coverage warnings: %1</b><br>" ).arg( myCoverageWarnCount );
|
||||
myRep += QString( "<b>Servers: %1</b><br>\n" ).arg( myServerCount );
|
||||
myRep += QString( "<b>Servers with error: %1</b><br>\n" ).arg( myServerErrCount );
|
||||
myRep += QString( "<b>Servers with warning: %1</b><br>\n" ).arg( myServerWarnCount );
|
||||
myRep += QString( "<b>Coverages: %1</b><br>\n" ).arg( myCoverageCount );
|
||||
myRep += QString( "<b>Coverage errors: %1</b><br>\n" ).arg( myCoverageErrCount );
|
||||
myRep += QString( "<b>Coverage warnings: %1</b><br>\n" ).arg( myCoverageWarnCount );
|
||||
|
||||
myRep += myReport;
|
||||
|
||||
@ -555,7 +631,7 @@ QString TestQgsWcsPublicServers::row( QStringList theValues, QString theClass )
|
||||
}
|
||||
myRow += QString( "<td class='cell %1' %2>%3</td>" ).arg( theClass ).arg( colspan ).arg( val );
|
||||
}
|
||||
myRow += "</tr>";
|
||||
myRow += "</tr>\n";
|
||||
return myRow;
|
||||
}
|
||||
|
||||
@ -566,9 +642,11 @@ void usage( std::string const & appName )
|
||||
<< "Console application for QGIS WCS provider (WCS client) testing.\n"
|
||||
<< "Usage: " << appName << " [options] CACHE_DIR\n"
|
||||
<< " options: \n"
|
||||
<< "\t[--server URL]\tWCS server URL to be tested\n"
|
||||
<< "\t[--coverage coverage]\tCoverage name to be tested\n"
|
||||
<< "\t[--server URL]\tWCS server URL to be tested.\n"
|
||||
<< "\t[--coverage coverage]\tCoverage name to be tested.\n"
|
||||
<< "\t[--num count]\tMaximum number of coverages to test per server. Default 2.\n"
|
||||
<< "\t[--version version]\tWCS version to be tested.\n"
|
||||
<< "\t[--force]\tForce retrieve, overwrite cache.\n"
|
||||
<< " FILES:\n"
|
||||
<< " Path to directory where cached results are stored.\n"
|
||||
<< " Coverage once retrieved (success or fail) is not requested again until the cache is deleted.\n";
|
||||
@ -586,6 +664,7 @@ int main( int argc, char *argv[] )
|
||||
|
||||
QString myServer;
|
||||
QString myCoverage;
|
||||
QString myVersion;
|
||||
int myMaxCoverages = 2;
|
||||
bool myForce;
|
||||
|
||||
@ -597,6 +676,7 @@ int main( int argc, char *argv[] )
|
||||
{"server", required_argument, 0, 's'},
|
||||
{"coverage", required_argument, 0, 'c'},
|
||||
{"num", required_argument, 0, 'n'},
|
||||
{"version", required_argument, 0, 'v'},
|
||||
{"force", no_argument, 0, 'f'},
|
||||
{0, 0, 0, 0}
|
||||
};
|
||||
@ -606,7 +686,7 @@ int main( int argc, char *argv[] )
|
||||
/* getopt_long stores the option index here. */
|
||||
int option_index = 0;
|
||||
|
||||
optionChar = getopt_long( argc, argv, "hscnf",
|
||||
optionChar = getopt_long( argc, argv, "hscnvf",
|
||||
long_options, &option_index );
|
||||
|
||||
/* Detect the end of the options. */
|
||||
@ -637,6 +717,10 @@ int main( int argc, char *argv[] )
|
||||
myMaxCoverages = QString( optarg ).toInt();
|
||||
break;
|
||||
|
||||
case 'v':
|
||||
myVersion = QString( optarg );
|
||||
break;
|
||||
|
||||
case 'f':
|
||||
myForce = true;
|
||||
break;
|
||||
@ -656,6 +740,7 @@ int main( int argc, char *argv[] )
|
||||
QgsDebugMsg( QString( "myServer = %1" ).arg( myServer ) );
|
||||
QgsDebugMsg( QString( "myCoverage = %1" ).arg( myCoverage ) );
|
||||
QgsDebugMsg( QString( "myMaxCoverages = %1" ).arg( myMaxCoverages ) );
|
||||
QgsDebugMsg( QString( "myVersion = %1" ).arg( myVersion ) );
|
||||
|
||||
if ( !myCoverage.isEmpty() && myServer.isEmpty() )
|
||||
{
|
||||
@ -691,7 +776,7 @@ int main( int argc, char *argv[] )
|
||||
QgsApplication::init( QString() );
|
||||
QgsApplication::initQgis();
|
||||
|
||||
TestQgsWcsPublicServers myTest( myCacheDirPath, myMaxCoverages, myServer, myCoverage, myForce );
|
||||
TestQgsWcsPublicServers myTest( myCacheDirPath, myMaxCoverages, myServer, myCoverage, myVersion, myForce );
|
||||
myTest.init();
|
||||
myTest.test();
|
||||
myTest.report();
|
||||
|
@ -38,6 +38,7 @@ class TestQgsWcsPublicServers: public QObject
|
||||
QStringList versions; // version regex
|
||||
QStringList coverages; // coverage regex
|
||||
QString description; // problem description
|
||||
Issue( const QString & d ) : description( d ) {}
|
||||
};
|
||||
struct Server
|
||||
{
|
||||
@ -48,7 +49,7 @@ class TestQgsWcsPublicServers: public QObject
|
||||
};
|
||||
|
||||
|
||||
TestQgsWcsPublicServers( const QString & cacheDirPath, int maxCoverages, const QString & server = QString(), const QString & coverage = QString(), bool force = false );
|
||||
TestQgsWcsPublicServers( const QString & cacheDirPath, int maxCoverages, const QString & server = QString(), const QString & coverage = QString(), const QString &version = QString(), bool force = false );
|
||||
|
||||
void init();
|
||||
void test();
|
||||
@ -60,6 +61,8 @@ class TestQgsWcsPublicServers: public QObject
|
||||
|
||||
QMap<QString, QString> readLog( QString theFileName );
|
||||
|
||||
QStringList issueDescriptions( const QString & url, const QString & coverage, const QString &version );
|
||||
|
||||
QString mCacheDirPath;
|
||||
QDir mCacheDir;
|
||||
|
||||
@ -68,6 +71,7 @@ class TestQgsWcsPublicServers: public QObject
|
||||
|
||||
QString mServer;
|
||||
QString mCoverage;
|
||||
QString mVersion;
|
||||
|
||||
// Force cached
|
||||
bool mForce;
|
||||
|
59
tests/src/providers/wcs-servers.json
Normal file
59
tests/src/providers/wcs-servers.json
Normal file
@ -0,0 +1,59 @@
|
||||
[
|
||||
{
|
||||
url: 'http://demo.opengeo.org/geoserver/wcs',
|
||||
issues: [
|
||||
{
|
||||
coverages: [ 'og:0' ],
|
||||
versions: [ ],
|
||||
description: 'Server fails on DescribeCoverage with: java.io.IOException null Translator error Unexpected error occurred during describe coverage xml encoding ...'
|
||||
}
|
||||
]
|
||||
}, {
|
||||
url: 'http://demo.geonode.org/geoserver/wcs'
|
||||
}, {
|
||||
url: 'http://demo.mapserver.org/cgi-bin/wcs'
|
||||
}, {
|
||||
// Some (first) coverages do not advertise any supportedCRS and sever gives
|
||||
// error both with native CRS (EPSG::561005) and EPSG:4326
|
||||
// MOD* coverages work OK
|
||||
url: 'http://argon.geogr.uni-jena.de:8080/geoserver/ows'
|
||||
}, {
|
||||
// geobrain.laits.gmu.edu servers are quite slow
|
||||
url: 'http://geobrain.laits.gmu.edu/cgi-bin/gbwcs-dem'
|
||||
/*
|
||||
}, {
|
||||
url: 'http://geobrain.laits.gmu.edu/cgi-bin/ows8/wcseo'
|
||||
}, {
|
||||
url: 'http://geobrain.laits.gmu.edu/cgi-bin/wcs110'
|
||||
}, {
|
||||
url: 'http://geobrain.laits.gmu.edu/cgi-bin/wcs-all'
|
||||
}, {
|
||||
url: 'http://ws.csiss.gmu.edu/cgi-bin/wcs-t'
|
||||
}, {
|
||||
// Big and slow
|
||||
url: 'http://ws.laits.gmu.edu/cgi-bin/wcs-all'
|
||||
}, {
|
||||
// Slow
|
||||
url: 'http://iceds.ge.ucl.ac.uk/cgi-bin/icedswcs'
|
||||
*/
|
||||
}, {
|
||||
url: 'http://motherlode.ucar.edu:8080/thredds/wcs/fmrc/NCEP/DGEX/Alaska_12km/NCEP-DGEX-Alaska_12km_best.ncd'
|
||||
}, {
|
||||
url: 'http://navigator.state.or.us/ArcGIS/services/Framework/Imagery_Mosaic2009/ImageServer/WCSServer'
|
||||
}, {
|
||||
url: 'http://nsidc.org/cgi-bin/atlas_north'
|
||||
/*
|
||||
}, {
|
||||
// Slow
|
||||
url: 'http://sedac.ciesin.columbia.edu/geoserver/wcs'
|
||||
}, {
|
||||
// Big and slow
|
||||
url: 'http://webmap.ornl.gov/ogcbroker/wcs'
|
||||
}, {
|
||||
// Currently very slow or down
|
||||
url: 'http://www.sogeo.ch/geoserver/wcs'
|
||||
}, {
|
||||
url: 'http://zeus.pin.unifi.it/gi-wcs/http'
|
||||
*/
|
||||
}
|
||||
]
|
Loading…
x
Reference in New Issue
Block a user