| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,249 @@ | ||
| /*************************************************************************** | ||
| qgsgdalproviderbase.cpp - Common base class for GDAL and WCS provider | ||
| ------------------- | ||
| begin : November, 2010 | ||
| copyright : (C) 2010 by Radim Blazek | ||
| email : radim dot blazek at gmail dot com | ||
| ***************************************************************************/ | ||
|
|
||
| /*************************************************************************** | ||
| * * | ||
| * This program is free software; you can redistribute it and/or modify * | ||
| * it under the terms of the GNU General Public License as published by * | ||
| * the Free Software Foundation; either version 2 of the License, or * | ||
| * (at your option) any later version. * | ||
| * * | ||
| ***************************************************************************/ | ||
|
|
||
| #include "qgsapplication.h" | ||
| #include "qgslogger.h" | ||
| #include "qgsgdalproviderbase.h" | ||
|
|
||
| #include <QSettings> | ||
|
|
||
| QgsGdalProviderBase::QgsGdalProviderBase() | ||
| { | ||
| QgsDebugMsg( "Entered" ); | ||
|
|
||
| // first get the GDAL driver manager | ||
| QgsGdalProviderBase::registerGdalDrivers(); | ||
| } | ||
|
|
||
| QgsGdalProviderBase::~QgsGdalProviderBase() | ||
| { | ||
| } | ||
|
|
||
| /** | ||
| * @param theBandNumber the number of the band for which you want a color table | ||
| * @param theList a pointer the object that will hold the color table | ||
| * @return true of a color table was able to be read, false otherwise | ||
| */ | ||
| QList<QgsColorRampShader::ColorRampItem> QgsGdalProviderBase::colorTable( GDALDatasetH gdalDataset, int theBandNumber )const | ||
| { | ||
| QgsDebugMsg( "entered." ); | ||
| QList<QgsColorRampShader::ColorRampItem> ct; | ||
|
|
||
| //Invalid band number, segfault prevention | ||
| if ( 0 >= theBandNumber ) | ||
| { | ||
| QgsDebugMsg( "Invalid parameter" ); | ||
| return ct; | ||
| } | ||
|
|
||
| GDALRasterBandH myGdalBand = GDALGetRasterBand( gdalDataset, theBandNumber ); | ||
| GDALColorTableH myGdalColorTable = GDALGetRasterColorTable( myGdalBand ); | ||
|
|
||
| if ( myGdalColorTable ) | ||
| { | ||
| QgsDebugMsg( "Color table found" ); | ||
| int myEntryCount = GDALGetColorEntryCount( myGdalColorTable ); | ||
| GDALColorInterp myColorInterpretation = GDALGetRasterColorInterpretation( myGdalBand ); | ||
| QgsDebugMsg( "Color Interpretation: " + QString::number(( int )myColorInterpretation ) ); | ||
| GDALPaletteInterp myPaletteInterpretation = GDALGetPaletteInterpretation( myGdalColorTable ); | ||
| QgsDebugMsg( "Palette Interpretation: " + QString::number(( int )myPaletteInterpretation ) ); | ||
|
|
||
| const GDALColorEntry* myColorEntry = 0; | ||
| for ( int myIterator = 0; myIterator < myEntryCount; myIterator++ ) | ||
| { | ||
| myColorEntry = GDALGetColorEntry( myGdalColorTable, myIterator ); | ||
|
|
||
| if ( !myColorEntry ) | ||
| { | ||
| continue; | ||
| } | ||
| else | ||
| { | ||
| //Branch on the color interpretation type | ||
| if ( myColorInterpretation == GCI_GrayIndex ) | ||
| { | ||
| QgsColorRampShader::ColorRampItem myColorRampItem; | ||
| myColorRampItem.label = ""; | ||
| myColorRampItem.value = ( double )myIterator; | ||
| myColorRampItem.color = QColor::fromRgb( myColorEntry->c1, myColorEntry->c1, myColorEntry->c1, myColorEntry->c4 ); | ||
| ct.append( myColorRampItem ); | ||
| } | ||
| else if ( myColorInterpretation == GCI_PaletteIndex ) | ||
| { | ||
| QgsColorRampShader::ColorRampItem myColorRampItem; | ||
| myColorRampItem.value = ( double )myIterator; | ||
| myColorRampItem.label = QString::number( myColorRampItem.value ); | ||
| //Branch on palette interpretation | ||
| if ( myPaletteInterpretation == GPI_RGB ) | ||
| { | ||
| myColorRampItem.color = QColor::fromRgb( myColorEntry->c1, myColorEntry->c2, myColorEntry->c3, myColorEntry->c4 ); | ||
| } | ||
| else if ( myPaletteInterpretation == GPI_CMYK ) | ||
| { | ||
| myColorRampItem.color = QColor::fromCmyk( myColorEntry->c1, myColorEntry->c2, myColorEntry->c3, myColorEntry->c4 ); | ||
| } | ||
| else if ( myPaletteInterpretation == GPI_HLS ) | ||
| { | ||
| myColorRampItem.color = QColor::fromHsv( myColorEntry->c1, myColorEntry->c3, myColorEntry->c2, myColorEntry->c4 ); | ||
| } | ||
| else | ||
| { | ||
| myColorRampItem.color = QColor::fromRgb( myColorEntry->c1, myColorEntry->c1, myColorEntry->c1, myColorEntry->c4 ); | ||
| } | ||
| ct.append( myColorRampItem ); | ||
| } | ||
| else | ||
| { | ||
| QgsDebugMsg( "Color interpretation type not supported yet" ); | ||
| return ct; | ||
| } | ||
| } | ||
| } | ||
| } | ||
| else | ||
| { | ||
| QgsDebugMsg( "No color table found for band " + QString::number( theBandNumber ) ); | ||
| return ct; | ||
| } | ||
|
|
||
| QgsDebugMsg( "Color table loaded successfully" ); | ||
| return ct; | ||
| } | ||
|
|
||
| QgsRasterInterface::DataType QgsGdalProviderBase::dataTypeFromGdal( int theGdalDataType ) const | ||
| { | ||
| switch ( theGdalDataType ) | ||
| { | ||
| case GDT_Unknown: | ||
| return QgsRasterDataProvider::UnknownDataType; | ||
| break; | ||
| case GDT_Byte: | ||
| return QgsRasterDataProvider::Byte; | ||
| break; | ||
| case GDT_UInt16: | ||
| return QgsRasterDataProvider::UInt16; | ||
| break; | ||
| case GDT_Int16: | ||
| return QgsRasterDataProvider::Int16; | ||
| break; | ||
| case GDT_UInt32: | ||
| return QgsRasterDataProvider::UInt32; | ||
| break; | ||
| case GDT_Int32: | ||
| return QgsRasterDataProvider::Int32; | ||
| break; | ||
| case GDT_Float32: | ||
| return QgsRasterDataProvider::Float32; | ||
| break; | ||
| case GDT_Float64: | ||
| return QgsRasterDataProvider::Float64; | ||
| break; | ||
| case GDT_CInt16: | ||
| return QgsRasterDataProvider::CInt16; | ||
| break; | ||
| case GDT_CInt32: | ||
| return QgsRasterDataProvider::CInt32; | ||
| break; | ||
| case GDT_CFloat32: | ||
| return QgsRasterDataProvider::CFloat32; | ||
| break; | ||
| case GDT_CFloat64: | ||
| return QgsRasterDataProvider::CFloat64; | ||
| break; | ||
| case GDT_TypeCount: | ||
| // make gcc happy | ||
| break; | ||
| } | ||
| return QgsRasterDataProvider::UnknownDataType; | ||
| } | ||
|
|
||
| int QgsGdalProviderBase::colorInterpretationFromGdal( int gdalColorInterpretation ) const | ||
| { | ||
| switch ( gdalColorInterpretation ) | ||
| { | ||
| case GCI_Undefined: | ||
| return QgsRasterDataProvider::UndefinedColorInterpretation; | ||
| break; | ||
| case GCI_GrayIndex: | ||
| return QgsRasterDataProvider::GrayIndex; | ||
| break; | ||
| case GCI_PaletteIndex: | ||
| return QgsRasterDataProvider::PaletteIndex; | ||
| break; | ||
| case GCI_RedBand: | ||
| return QgsRasterDataProvider::RedBand; | ||
| break; | ||
| case GCI_GreenBand: | ||
| return QgsRasterDataProvider::GreenBand; | ||
| break; | ||
| case GCI_BlueBand: | ||
| return QgsRasterDataProvider::BlueBand; | ||
| break; | ||
| case GCI_AlphaBand: | ||
| return QgsRasterDataProvider::AlphaBand; | ||
| break; | ||
| case GCI_HueBand: | ||
| return QgsRasterDataProvider::HueBand; | ||
| break; | ||
| case GCI_SaturationBand: | ||
| return QgsRasterDataProvider::SaturationBand; | ||
| break; | ||
| case GCI_LightnessBand: | ||
| return QgsRasterDataProvider::LightnessBand; | ||
| break; | ||
| case GCI_CyanBand: | ||
| return QgsRasterDataProvider::CyanBand; | ||
| break; | ||
| case GCI_MagentaBand: | ||
| return QgsRasterDataProvider::MagentaBand; | ||
| break; | ||
| case GCI_YellowBand: | ||
| return QgsRasterDataProvider::YellowBand; | ||
| break; | ||
| case GCI_BlackBand: | ||
| return QgsRasterDataProvider::BlackBand; | ||
| break; | ||
| case GCI_YCbCr_YBand: | ||
| return QgsRasterDataProvider::YCbCr_YBand; | ||
| break; | ||
| case GCI_YCbCr_CbBand: | ||
| return QgsRasterDataProvider::YCbCr_CbBand; | ||
| break; | ||
| case GCI_YCbCr_CrBand: | ||
| return QgsRasterDataProvider::YCbCr_CrBand; | ||
| break; | ||
| default: | ||
| break; | ||
| } | ||
| return QgsRasterDataProvider::UndefinedColorInterpretation; | ||
| } | ||
|
|
||
| void QgsGdalProviderBase::registerGdalDrivers() | ||
| { | ||
| GDALAllRegister(); | ||
| QSettings mySettings; | ||
| QString myJoinedList = mySettings.value( "gdal/skipList", "" ).toString(); | ||
| if ( !myJoinedList.isEmpty() ) | ||
| { | ||
| QStringList myList = myJoinedList.split( " " ); | ||
| for ( int i = 0; i < myList.size(); ++i ) | ||
| { | ||
| QgsApplication::skipGdalDriver( myList.at( i ) ); | ||
| } | ||
| QgsApplication::applyGdalSkippedDrivers(); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,59 @@ | ||
| /*************************************************************************** | ||
| qgsgdalproviderbase.h - Common base class for GDAL and WCS provider | ||
| ------------------- | ||
| begin : November, 2010 | ||
| copyright : (C) 2010 by Radim Blazek | ||
| email : radim dot blazek at gmail dot com | ||
| ***************************************************************************/ | ||
|
|
||
| /*************************************************************************** | ||
| * * | ||
| * This program is free software; you can redistribute it and/or modify * | ||
| * it under the terms of the GNU General Public License as published by * | ||
| * the Free Software Foundation; either version 2 of the License, or * | ||
| * (at your option) any later version. * | ||
| * * | ||
| ***************************************************************************/ | ||
|
|
||
| #ifndef QGSGDALPROVIDERBASE_H | ||
| #define QGSGDALPROVIDERBASE_H | ||
|
|
||
| #include "qgsrasterdataprovider.h" | ||
| #include "qgscolorrampshader.h" | ||
|
|
||
| #include <QList> | ||
|
|
||
| #define CPL_SUPRESS_CPLUSPLUS | ||
| #include <gdal.h> | ||
|
|
||
| #if defined(GDAL_VERSION_NUM) && GDAL_VERSION_NUM >= 1800 | ||
| #define TO8F(x) (x).toUtf8().constData() | ||
| #define FROM8(x) QString::fromUtf8(x) | ||
| #else | ||
| #define TO8F(x) QFile::encodeName( x ).constData() | ||
| #define FROM8(x) QString::fromLocal8Bit(x) | ||
| #endif | ||
|
|
||
| /** | ||
| \brief Base clasee for GDAL and WCS providers. | ||
| */ | ||
| class QgsGdalProviderBase | ||
| { | ||
| public: | ||
| QgsGdalProviderBase( ); | ||
|
|
||
| ~QgsGdalProviderBase(); | ||
|
|
||
| /** \brief ensures that GDAL drivers are registered, but only once */ | ||
| static void registerGdalDrivers(); | ||
| protected: | ||
|
|
||
| QgsRasterInterface::DataType dataTypeFromGdal( int theGdalDataType ) const; | ||
|
|
||
| int colorInterpretationFromGdal( int gdalColorInterpretation ) const; | ||
|
|
||
| QList<QgsColorRampShader::ColorRampItem> colorTable( GDALDatasetH gdalDataset, int bandNo )const; | ||
| }; | ||
|
|
||
| #endif | ||
|
|
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,34 @@ | ||
|
|
||
| SET (WCS_SRCS | ||
| ../gdal/qgsgdalproviderbase.cpp | ||
| qgswcsprovider.cpp | ||
| qgswcscapabilities.cpp | ||
| qgswcssourceselect.cpp | ||
| qgswcsdataitems.cpp | ||
| ) | ||
| SET (WCS_MOC_HDRS | ||
| ../gdal/qgsgdalproviderbase.h | ||
| qgswcsprovider.h | ||
| qgswcscapabilities.h | ||
| qgswcssourceselect.h | ||
| qgswcsdataitems.h | ||
| ) | ||
|
|
||
| QT4_WRAP_CPP (WCS_MOC_SRCS ${WCS_MOC_HDRS}) | ||
|
|
||
| INCLUDE_DIRECTORIES( . ../../core ../../core/raster ../../gui | ||
| ../gdal | ||
| ${CMAKE_CURRENT_BINARY_DIR}/../../ui | ||
| ${GDAL_INCLUDE_DIR} | ||
| ) | ||
|
|
||
| ADD_LIBRARY(wcsprovider MODULE ${WCS_SRCS} ${WCS_MOC_SRCS}) | ||
|
|
||
| TARGET_LINK_LIBRARIES(wcsprovider | ||
| qgis_core | ||
| qgis_gui | ||
| ) | ||
|
|
||
| INSTALL (TARGETS wcsprovider | ||
| RUNTIME DESTINATION ${QGIS_PLUGIN_DIR} | ||
| LIBRARY DESTINATION ${QGIS_PLUGIN_DIR}) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,43 @@ | ||
| WCS URI | ||
| ------- | ||
|
|
||
| Example: url=http://127.0.0.1/wcs&identifier=coverage1 | ||
|
|
||
| WCS URI is composed of key=value pairs separated by '&'. It is the same format like query string in URL, encoded the same way. QgsDataSourceURI should be used to construct the URI to ensure that special characters are encoded properly. | ||
|
|
||
| Parameters: | ||
|
|
||
| * url (required) : WCS Server URL. Do not use VERSION in URL, because each version of WCS is using different parameter name for GetCapabilities version, see param version. | ||
|
|
||
| * identifier (required) : Coverage name | ||
|
|
||
| * time (optional) : time position or time period (beginPosition/endPosition[/timeResolution]) | ||
|
|
||
| * format (optional) : Supported format name. Default is the first supported format with tif in name or the first supported format. | ||
|
|
||
| * crs (optional) : CRS in form AUTHORITY:ID, e.g. EPSG:4326. Default is EPSG:4326 if supported or the first supported CRS. | ||
|
|
||
| * username (optional) : Username for basic authentication. | ||
|
|
||
| * password (optional) : Password for basic authentication. | ||
|
|
||
| * IgnoreGetMapUrl (optional,hack) : If specified (set to 1), ignore GetCoverage URL advertised by GetCapabilities. May be necessary if a server is not configured properly. | ||
|
|
||
| * InvertAxisOrientation (optional,hack) : If specified (set to 1), switch axis in GetCoverage request. May be necessary for geographic CRS if a server is using wrong axis order. | ||
|
|
||
| * IgnoreAxisOrientation (optional,hack) : If specified (set to 1), do not invert axis orientation according to WCS standard for geographic CRS. | ||
|
|
||
|
|
||
| Python console example: | ||
|
|
||
| from PyQt4.QtCore import QString | ||
|
|
||
| uri = QgsDataSourceURI() | ||
| uri.setParam ("url", "http://wcs.qgis.org/1.9.0/wcs" ) | ||
| uri.setParam ( "identifier", "band1_int16_noct_epsg4326" ) | ||
|
|
||
| layer = QgsRasterLayer( QString(uri.encodedUri()), "WCS test", "wcs" ) | ||
| layer.isValid() | ||
|
|
||
| QgsMapLayerRegistry.instance().addMapLayer(layer) | ||
|
|
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,309 @@ | ||
| /*************************************************************************** | ||
| qgswcsdataitems.cpp | ||
| --------------------- | ||
| begin : 2 July, 2012 | ||
| copyright : (C) 2012 by Radim Blazek | ||
| email : radim dot blazek at gmail.com | ||
| *************************************************************************** | ||
| * * | ||
| * This program is free software; you can redistribute it and/or modify * | ||
| * it under the terms of the GNU General Public License as published by * | ||
| * the Free Software Foundation; either version 2 of the License, or * | ||
| * (at your option) any later version. * | ||
| * * | ||
| ***************************************************************************/ | ||
| #include "qgsapplication.h" | ||
| #include "qgswcsdataitems.h" | ||
| #include "qgswcsprovider.h" | ||
| #include "qgslogger.h" | ||
| #include "qgsdatasourceuri.h" | ||
| #include "qgswcssourceselect.h" | ||
| #include "qgsowsconnection.h" | ||
| #include "qgsnewhttpconnection.h" | ||
|
|
||
| #include <QFileInfo> | ||
| #include <QSettings> | ||
|
|
||
| QgsWCSConnectionItem::QgsWCSConnectionItem( QgsDataItem* parent, QString name, QString path ) | ||
| : QgsDataCollectionItem( parent, name, path ) | ||
| { | ||
| mIcon = QgsApplication::getThemeIcon( "mIconWcs.png" ); | ||
| } | ||
|
|
||
| QgsWCSConnectionItem::~QgsWCSConnectionItem() | ||
| { | ||
| QgsDebugMsg( "Entered" ); | ||
| } | ||
|
|
||
| QVector<QgsDataItem*> QgsWCSConnectionItem::createChildren() | ||
| { | ||
| QgsDebugMsg( "Entered" ); | ||
| QVector<QgsDataItem*> children; | ||
|
|
||
| QString encodedUri = mPath; | ||
| QgsDataSourceURI uri; | ||
| uri.setEncodedUri( encodedUri ); | ||
| QgsDebugMsg( "encodedUri = " + encodedUri ); | ||
|
|
||
| mCapabilities.setUri( uri ); | ||
|
|
||
| // Attention: supportedLayers() gives tree leafes, not top level | ||
| if ( !mCapabilities.lastError().isEmpty() ) | ||
| { | ||
| //children.append( new QgsErrorItem( this, tr( "Failed to retrieve layers" ), mPath + "/error" ) ); | ||
| // TODO: show the error without adding child | ||
| return children; | ||
| } | ||
|
|
||
| foreach ( QgsWcsCoverageSummary coverageSummary, mCapabilities.capabilities().contents.coverageSummary ) | ||
| { | ||
| // Attention, the name may be empty | ||
| QgsDebugMsg( QString::number( coverageSummary.orderId ) + " " + coverageSummary.identifier + " " + coverageSummary.title ); | ||
| QString pathName = coverageSummary.identifier.isEmpty() ? QString::number( coverageSummary.orderId ) : coverageSummary.identifier; | ||
|
|
||
| QgsWCSLayerItem * layer = new QgsWCSLayerItem( this, coverageSummary.title, mPath + "/" + pathName, mCapabilities.capabilities(), uri, coverageSummary ); | ||
|
|
||
| children.append( layer ); | ||
| } | ||
| return children; | ||
| } | ||
|
|
||
| bool QgsWCSConnectionItem::equal( const QgsDataItem *other ) | ||
| { | ||
| if ( type() != other->type() ) | ||
| { | ||
| return false; | ||
| } | ||
| const QgsWCSConnectionItem *o = dynamic_cast<const QgsWCSConnectionItem *>( other ); | ||
| if ( !o ) | ||
| { | ||
| return false; | ||
| } | ||
|
|
||
| return ( mPath == o->mPath && mName == o->mName ); | ||
| } | ||
|
|
||
| QList<QAction*> QgsWCSConnectionItem::actions() | ||
| { | ||
| QList<QAction*> lst; | ||
|
|
||
| QAction* actionEdit = new QAction( tr( "Edit..." ), this ); | ||
| connect( actionEdit, SIGNAL( triggered() ), this, SLOT( editConnection() ) ); | ||
| lst.append( actionEdit ); | ||
|
|
||
| QAction* actionDelete = new QAction( tr( "Delete" ), this ); | ||
| connect( actionDelete, SIGNAL( triggered() ), this, SLOT( deleteConnection() ) ); | ||
| lst.append( actionDelete ); | ||
|
|
||
| return lst; | ||
| } | ||
|
|
||
| void QgsWCSConnectionItem::editConnection() | ||
| { | ||
| QgsNewHttpConnection nc( 0, "/Qgis/connections-wcs/", mName ); | ||
|
|
||
| if ( nc.exec() ) | ||
| { | ||
| // the parent should be updated | ||
| mParent->refresh(); | ||
| } | ||
| } | ||
|
|
||
| void QgsWCSConnectionItem::deleteConnection() | ||
| { | ||
| QgsOWSConnection::deleteConnection( "WCS", mName ); | ||
| // the parent should be updated | ||
| mParent->refresh(); | ||
| } | ||
|
|
||
|
|
||
| // --------------------------------------------------------------------------- | ||
|
|
||
| QgsWCSLayerItem::QgsWCSLayerItem( QgsDataItem* parent, QString name, QString path, QgsWcsCapabilitiesProperty capabilitiesProperty, QgsDataSourceURI dataSourceUri, QgsWcsCoverageSummary coverageSummary ) | ||
| : QgsLayerItem( parent, name, path, QString(), QgsLayerItem::Raster, "wcs" ), | ||
| mCapabilities( capabilitiesProperty ), | ||
| mDataSourceUri( dataSourceUri ), | ||
| mCoverageSummary( coverageSummary ) | ||
| { | ||
| QgsDebugMsg( "uri = " + mDataSourceUri.encodedUri() ); | ||
| mUri = createUri(); | ||
| // Populate everything, it costs nothing, all info about layers is collected | ||
| foreach ( QgsWcsCoverageSummary coverageSummary, mCoverageSummary.coverageSummary ) | ||
| { | ||
| // Attention, the name may be empty | ||
| QgsDebugMsg( QString::number( coverageSummary.orderId ) + " " + coverageSummary.identifier + " " + coverageSummary.title ); | ||
| QString pathName = coverageSummary.identifier.isEmpty() ? QString::number( coverageSummary.orderId ) : coverageSummary.identifier; | ||
| QgsWCSLayerItem * layer = new QgsWCSLayerItem( this, coverageSummary.title, mPath + "/" + pathName, mCapabilities, mDataSourceUri, coverageSummary ); | ||
| mChildren.append( layer ); | ||
| } | ||
|
|
||
| if ( mChildren.size() == 0 ) | ||
| { | ||
| //mIcon = iconRaster(); | ||
| mIcon = QgsApplication::getThemeIcon( "mIconWcs.png" ); | ||
| } | ||
| mPopulated = true; | ||
| } | ||
|
|
||
| QgsWCSLayerItem::~QgsWCSLayerItem() | ||
| { | ||
| } | ||
|
|
||
| QString QgsWCSLayerItem::createUri() | ||
| { | ||
| if ( mCoverageSummary.identifier.isEmpty() ) | ||
| return ""; // layer collection | ||
|
|
||
| // Number of styles must match number of layers | ||
| mDataSourceUri.setParam( "identifier", mCoverageSummary.identifier ); | ||
|
|
||
| // TODO(?): with WCS 1.0 GetCapabilities does not contain CRS and formats, | ||
| // to get them we would need to call QgsWcsCapabilities::describeCoverage | ||
| // but it is problematic to get QgsWcsCapabilities here (copy not allowed | ||
| // by QObject, pointer is dangerous (OWS provider is changing parent)) | ||
| // We leave CRS and format default for now. | ||
|
|
||
| QString format; | ||
| // get first supported by GDAL and server | ||
| // TODO | ||
| //QStringList mimes = QgsGdalProvider::supportedMimes().keys(); | ||
| QStringList mimes; | ||
| // prefer tiff | ||
| if ( mimes.contains( "image/tiff" ) && mCoverageSummary.supportedFormat.contains( "image/tiff" ) ) | ||
| { | ||
| format = "image/tiff"; | ||
| } | ||
| else | ||
| { | ||
| foreach ( QString f, mimes ) | ||
| { | ||
| if ( mCoverageSummary.supportedFormat.indexOf( f ) >= 0 ) | ||
| { | ||
| format = f; | ||
| break; | ||
| } | ||
| } | ||
| } | ||
| if ( !format.isEmpty() ) | ||
| { | ||
| mDataSourceUri.setParam( "format", format ); | ||
| } | ||
|
|
||
| QString crs; | ||
|
|
||
| // TODO: prefer project CRS | ||
| // get first known if possible | ||
| QgsCoordinateReferenceSystem testCrs; | ||
| foreach ( QString c, mCoverageSummary.supportedCrs ) | ||
| { | ||
| testCrs.createFromOgcWmsCrs( c ); | ||
| if ( testCrs.isValid() ) | ||
| { | ||
| crs = c; | ||
| break; | ||
| } | ||
| } | ||
| if ( crs.isEmpty() && mCoverageSummary.supportedCrs.size() > 0 ) | ||
| { | ||
| crs = mCoverageSummary.supportedCrs.value( 0 ); | ||
| } | ||
| if ( !crs.isEmpty() ) | ||
| { | ||
| mDataSourceUri.setParam( "crs", crs ); | ||
| } | ||
|
|
||
| return mDataSourceUri.encodedUri(); | ||
| } | ||
|
|
||
| // --------------------------------------------------------------------------- | ||
|
|
||
| QgsWCSRootItem::QgsWCSRootItem( QgsDataItem* parent, QString name, QString path ) | ||
| : QgsDataCollectionItem( parent, name, path ) | ||
| { | ||
| mIcon = QgsApplication::getThemeIcon( "mIconWcs.png" ); | ||
|
|
||
| populate(); | ||
| } | ||
|
|
||
| QgsWCSRootItem::~QgsWCSRootItem() | ||
| { | ||
| } | ||
|
|
||
| QVector<QgsDataItem*>QgsWCSRootItem::createChildren() | ||
| { | ||
| QVector<QgsDataItem*> connections; | ||
| foreach ( QString connName, QgsOWSConnection::connectionList( "WCS" ) ) | ||
| { | ||
| //QgsDataItem * conn = new QgsWCSConnectionItem( this, connName, mPath + "/" + connName ); | ||
| QgsOWSConnection connection( "WCS", connName ); | ||
| QgsDataItem * conn = new QgsWCSConnectionItem( this, connName, connection.uri().encodedUri() ); | ||
|
|
||
| conn->setIcon( QgsApplication::getThemeIcon( "mIconConnect.png" ) ); | ||
| connections.append( conn ); | ||
| } | ||
| return connections; | ||
| } | ||
|
|
||
| QList<QAction*> QgsWCSRootItem::actions() | ||
| { | ||
| QList<QAction*> lst; | ||
|
|
||
| QAction* actionNew = new QAction( tr( "New Connection..." ), this ); | ||
| connect( actionNew, SIGNAL( triggered() ), this, SLOT( newConnection() ) ); | ||
| lst.append( actionNew ); | ||
|
|
||
| return lst; | ||
| } | ||
|
|
||
|
|
||
| QWidget * QgsWCSRootItem::paramWidget() | ||
| { | ||
| QgsWCSSourceSelect *select = new QgsWCSSourceSelect( 0, 0, true, true ); | ||
| connect( select, SIGNAL( connectionsChanged() ), this, SLOT( connectionsChanged() ) ); | ||
| return select; | ||
| return 0; | ||
| } | ||
| void QgsWCSRootItem::connectionsChanged() | ||
| { | ||
| refresh(); | ||
| } | ||
|
|
||
| void QgsWCSRootItem::newConnection() | ||
| { | ||
| QgsNewHttpConnection nc( 0, "/Qgis/connections-wcs/" ); | ||
|
|
||
| if ( nc.exec() ) | ||
| { | ||
| refresh(); | ||
| } | ||
| } | ||
|
|
||
| // --------------------------------------------------------------------------- | ||
|
|
||
| static QString filterString; | ||
| static QStringList extensions = QStringList(); | ||
| static QStringList wildcards = QStringList(); | ||
|
|
||
| QGISEXTERN int dataCapabilities() | ||
| { | ||
| return QgsDataProvider::Net; | ||
| } | ||
|
|
||
| QGISEXTERN QgsDataItem * dataItem( QString thePath, QgsDataItem* parentItem ) | ||
| { | ||
| QgsDebugMsg( "thePath = " + thePath ); | ||
| if ( thePath.isEmpty() ) | ||
| { | ||
| // Top level WCS | ||
| return new QgsWCSRootItem( parentItem, "WCS", "wcs:" ); | ||
| } | ||
|
|
||
| // OWS server | ||
| QgsDebugMsg( "connection found in uri" ); | ||
| return new QgsWCSConnectionItem( parentItem, "WCS", thePath ); | ||
| } | ||
|
|
||
| QGISEXTERN QgsWCSSourceSelect * selectWidget( QWidget * parent, Qt::WFlags fl ) | ||
| { | ||
| return new QgsWCSSourceSelect( parent, fl ); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,78 @@ | ||
| /*************************************************************************** | ||
| qgswcsdataitems.h | ||
| --------------------- | ||
| begin : 2 July, 2012 | ||
| copyright : (C) 2012 by Radim Blazek | ||
| email : radim dot blazek at gmail.com | ||
| *************************************************************************** | ||
| * * | ||
| * This program is free software; you can redistribute it and/or modify * | ||
| * it under the terms of the GNU General Public License as published by * | ||
| * the Free Software Foundation; either version 2 of the License, or * | ||
| * (at your option) any later version. * | ||
| * * | ||
| ***************************************************************************/ | ||
| #ifndef QGSWCSDATAITEMS_H | ||
| #define QGSWCSDATAITEMS_H | ||
|
|
||
| #include "qgsdataitem.h" | ||
| #include "qgsdatasourceuri.h" | ||
| #include "qgswcscapabilities.h" | ||
|
|
||
| class QgsWCSConnectionItem : public QgsDataCollectionItem | ||
| { | ||
| Q_OBJECT | ||
| public: | ||
| QgsWCSConnectionItem( QgsDataItem* parent, QString name, QString path ); | ||
| ~QgsWCSConnectionItem(); | ||
|
|
||
| QVector<QgsDataItem*> createChildren(); | ||
| virtual bool equal( const QgsDataItem *other ); | ||
|
|
||
| virtual QList<QAction*> actions(); | ||
|
|
||
| QgsWcsCapabilities mCapabilities; | ||
| QVector<QgsWcsCoverageSummary> mLayerProperties; | ||
|
|
||
| public slots: | ||
| void editConnection(); | ||
| void deleteConnection(); | ||
| }; | ||
|
|
||
| // WCS Layers may be nested, so that they may be both QgsDataCollectionItem and QgsLayerItem | ||
| // We have to use QgsDataCollectionItem and support layer methods if necessary | ||
| class QgsWCSLayerItem : public QgsLayerItem | ||
| { | ||
| Q_OBJECT | ||
| public: | ||
| QgsWCSLayerItem( QgsDataItem* parent, QString name, QString path, | ||
| QgsWcsCapabilitiesProperty capabilitiesProperty, QgsDataSourceURI dataSourceUri, QgsWcsCoverageSummary coverageSummary ); | ||
| ~QgsWCSLayerItem(); | ||
|
|
||
| QString createUri(); | ||
|
|
||
| QgsWcsCapabilitiesProperty mCapabilities; | ||
| QgsDataSourceURI mDataSourceUri; | ||
| QgsWcsCoverageSummary mCoverageSummary; | ||
| }; | ||
|
|
||
| class QgsWCSRootItem : public QgsDataCollectionItem | ||
| { | ||
| Q_OBJECT | ||
| public: | ||
| QgsWCSRootItem( QgsDataItem* parent, QString name, QString path ); | ||
| ~QgsWCSRootItem(); | ||
|
|
||
| QVector<QgsDataItem*> createChildren(); | ||
|
|
||
| virtual QList<QAction*> actions(); | ||
|
|
||
| virtual QWidget * paramWidget(); | ||
|
|
||
| public slots: | ||
| void connectionsChanged(); | ||
|
|
||
| void newConnection(); | ||
| }; | ||
|
|
||
| #endif // QGSWCSDATAITEMS_H |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,76 @@ | ||
| # Standard includes and utils to compile into all tests. | ||
|
|
||
| ##################################################### | ||
| # Don't forget to include output directory, otherwise | ||
| # the UI file won't be wrapped! | ||
| INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR} | ||
| ${CMAKE_CURRENT_BINARY_DIR} | ||
| ${CMAKE_SOURCE_DIR}/src/core | ||
| ${CMAKE_SOURCE_DIR}/src/core/raster | ||
| ${QT_INCLUDE_DIR} | ||
| ${GDAL_INCLUDE_DIR} | ||
| ${PROJ_INCLUDE_DIR} | ||
| ${GEOS_INCLUDE_DIR} | ||
| ) | ||
|
|
||
| ############################################################# | ||
| # Compiler defines | ||
|
|
||
| # This define is used for tests that need to locate the test | ||
| # data under tests/testdata in the qgis source tree. | ||
| # the TEST_DATA_DIR variable is set in the top level CMakeLists.txt | ||
| ADD_DEFINITIONS(-DTEST_DATA_DIR="\\"${TEST_DATA_DIR}\\"") | ||
|
|
||
| ADD_DEFINITIONS(-DINSTALL_PREFIX="\\"${CMAKE_INSTALL_PREFIX}\\"") | ||
|
|
||
| SET(TEST_SERVER_URL "http://wcs.qgis.org/${COMPLETE_VERSION}") | ||
| ADD_DEFINITIONS(-DTEST_SERVER_URL="\\"${TEST_SERVER_URL}\\"") | ||
|
|
||
| ############################################################# | ||
| # libraries | ||
|
|
||
| # because of htonl | ||
| IF (WIN32) | ||
| SET(PLATFORM_LIBRARIES wsock32) | ||
| ENDIF (WIN32) | ||
|
|
||
| # Since the tests are not actually installed, but rather | ||
| # run directly from the build/src/tests dir we need to | ||
| # ensure the qgis libs can be found. | ||
| IF (APPLE) | ||
| # For Mac OS X, the executable must be at the root of the bundle's executable folder | ||
| SET (CMAKE_INSTALL_NAME_DIR @executable_path/../../../src/core) | ||
| ENDIF (APPLE) | ||
|
|
||
| #note for tests we should not include the moc of our | ||
| #qtests in the executable file list as the moc is | ||
| #directly included in the sources | ||
| #and should not be compiled twice. Trying to include | ||
| #them in will cause an error at build time | ||
|
|
||
| #No relinking and full RPATH for the install tree | ||
| #See: http://www.cmake.org/Wiki/CMake_RPATH_handling#No_relinking_and_full_RPATH_for_the_install_tree | ||
|
|
||
| MACRO (ADD_QGIS_TEST testname testsrc) | ||
| SET(qgis_${testname}_SRCS ${testsrc} ${util_SRCS}) | ||
| SET(qgis_${testname}_MOC_CPPS ${testsrc}) | ||
| QT4_WRAP_CPP(qgis_${testname}_MOC_SRCS ${qgis_${testname}_MOC_CPPS}) | ||
| ADD_CUSTOM_TARGET(qgis_${testname}moc ALL DEPENDS ${qgis_${testname}_MOC_SRCS}) | ||
| ADD_EXECUTABLE(qgis_${testname} ${qgis_${testname}_SRCS}) | ||
| ADD_DEPENDENCIES(qgis_${testname} qgis_${testname}moc) | ||
| TARGET_LINK_LIBRARIES(qgis_${testname} | ||
| ${QT_QTXML_LIBRARY} | ||
| ${QT_QTCORE_LIBRARY} | ||
| ${QT_QTSVG_LIBRARY} | ||
| ${QT_QTTEST_LIBRARY} | ||
| ${PROJ_LIBRARY} | ||
| ${GEOS_LIBRARY} | ||
| ${GDAL_LIBRARY} | ||
| qgis_core) | ||
| ADD_TEST(qgis_${testname} ${CMAKE_CURRENT_BINARY_DIR}/../../../output/bin/qgis_${testname}) | ||
| ENDMACRO (ADD_QGIS_TEST) | ||
|
|
||
| ############################################################# | ||
| # Tests: | ||
|
|
||
| ADD_QGIS_TEST(wcsprovidertest testqgswcsprovider.cpp) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,339 @@ | ||
| /*************************************************************************** | ||
| testqgswcsprovider.cpp | ||
| -------------------------------------- | ||
| Date : July 2012 | ||
| Copyright : (C) 2012 by Radim Blazek | ||
| Email : radim dot blazek at gmail dot com | ||
| *************************************************************************** | ||
| * * | ||
| * This program is free software; you can redistribute it and/or modify * | ||
| * it under the terms of the GNU General Public License as published by * | ||
| * the Free Software Foundation; either version 2 of the License, or * | ||
| * (at your option) any later version. * | ||
| * * | ||
| ***************************************************************************/ | ||
| #include <cmath> | ||
|
|
||
| #include <QtTest> | ||
| #include <QObject> | ||
| #include <QString> | ||
| #include <QStringList> | ||
| #include <QObject> | ||
| #include <QApplication> | ||
|
|
||
| #include <qgsdatasourceuri.h> | ||
| #include <qgsrasterlayer.h> | ||
| #include <qgsrasterdataprovider.h> | ||
| #include <qgsproviderregistry.h> | ||
| #include <qgsapplication.h> | ||
|
|
||
| #define TINY_VALUE std::numeric_limits<double>::epsilon() * 20 | ||
|
|
||
| /** \ingroup UnitTests | ||
| * This is a unit test for the QgsRasterLayer class. | ||
| */ | ||
| class TestQgsWcsProvider: public QObject | ||
| { | ||
| Q_OBJECT; | ||
| private slots: | ||
| void initTestCase();// will be called before the first testfunction is executed. | ||
| void cleanupTestCase();// will be called after the last testfunction was executed. | ||
| void init() {};// will be called before each testfunction is executed. | ||
| void cleanup() {};// will be called after every testfunction. | ||
|
|
||
| void read(); | ||
| private: | ||
| bool read( QString theIdentifier, QString theWcsUri, QString theFilePath, QString & theReport ); | ||
| // Log error in html | ||
| void error( QString theMessage, QString &theReport ); | ||
| // compare values and add table row in html report, set ok to false if not equal | ||
| QString compareHead(); | ||
| bool compare( double wcsVal, double gdalVal, double theTolerance ); | ||
| void compare( QString theParamName, int wcsVal, int gdalVal, QString &theReport, bool &theOk ); | ||
| void compare( QString theParamName, double wcsVal, double gdalVal, QString &theReport, bool &theOk, double theTolerance = 0 ); | ||
| void compareRow( QString theParamName, QString wcsVal, QString gdalVal, QString &theReport, bool theOk, QString theDifference = "", QString theTolerance = "" ); | ||
| double tolerance( double val, int places = 6 ); | ||
| QString mTestDataDir; | ||
| QString mReport; | ||
| QString mUrl; | ||
| }; | ||
|
|
||
| //runs before all tests | ||
| void TestQgsWcsProvider::initTestCase() | ||
| { | ||
| // init QGIS's paths - true means that all path will be inited from prefix | ||
| QgsApplication::init( QString() ); | ||
| QgsApplication::initQgis(); | ||
| QString mySettings = QgsApplication::showSettings(); | ||
| mySettings = mySettings.replace( "\n", "<br />" ); | ||
| mReport += "<h1>WCS provider tests</h1>\n"; | ||
| mReport += "<p>" + mySettings + "</p>"; | ||
|
|
||
| mReport += "<style>"; | ||
| mReport += ".tab { border-spacing: 0px; border-width: 1px 1px 0 0; border-style: solid; }"; | ||
| mReport += ".cell { border-width: 0 0 1px 1px; border-style: solid; font-size: smaller; text-align: center}"; | ||
| mReport += ".ok { background: #00ff00; }"; | ||
| mReport += ".err { background: #ff0000; }"; | ||
| mReport += ".errmsg { color: #ff0000; }"; | ||
| mReport += "</style>"; | ||
|
|
||
|
|
||
| //create some objects that will be used in all tests... | ||
| //create a raster layer that will be used in all tests... | ||
| mTestDataDir = QString( TEST_DATA_DIR ) + QDir::separator() + "raster"; | ||
| qDebug() << "mTestDataDir = " << mTestDataDir; | ||
|
|
||
| mUrl = QString( TEST_SERVER_URL ) + QDir::separator() + "wcs"; | ||
| } | ||
|
|
||
| //runs after all tests | ||
| void TestQgsWcsProvider::cleanupTestCase() | ||
| { | ||
| QString myReportFile = QDir::tempPath() + QDir::separator() + "qgiswcstest.html"; | ||
| QFile myFile( myReportFile ); | ||
| //if ( myFile.open( QIODevice::WriteOnly | QIODevice::Append ) ) | ||
| if ( myFile.open( QIODevice::WriteOnly ) ) | ||
| { | ||
| QTextStream myQTextStream( &myFile ); | ||
| myQTextStream << mReport; | ||
| myFile.close(); | ||
| } | ||
| } | ||
|
|
||
| void TestQgsWcsProvider::read( ) | ||
| { | ||
| bool ok = true; | ||
| QStringList versions; | ||
|
|
||
| versions << "1.0" << "1.1"; | ||
|
|
||
| QStringList identifiers; | ||
|
|
||
| // identifiers in mapfile have the same name as files without .tif extension | ||
| identifiers << "band1_byte_noct_epsg4326"; | ||
| identifiers << "band1_int16_noct_epsg4326"; | ||
| identifiers << "band1_float32_noct_epsg4326"; | ||
| identifiers << "band3_byte_noct_epsg4326"; | ||
| identifiers << "band3_int16_noct_epsg4326"; | ||
| identifiers << "band3_float32_noct_epsg4326"; | ||
|
|
||
| // How to reasonably log multiple fails within this loop? | ||
| foreach ( QString version, versions ) | ||
| { | ||
| foreach ( QString identifier, identifiers ) | ||
| { | ||
| QString filePath = mTestDataDir + QDir::separator() + identifier + ".tif"; | ||
|
|
||
| QgsDataSourceURI uri; | ||
| uri.setParam( "url", mUrl ); | ||
| uri.setParam( "identifier", identifier ); | ||
| uri.setParam( "crs", "epsg:4326" ); | ||
| uri.setParam( "version", version ); | ||
|
|
||
| if ( !read( identifier, uri.encodedUri(), filePath, mReport ) ) | ||
| { | ||
| ok = false; | ||
| } | ||
| } | ||
| } | ||
| QVERIFY2( ok, "Reading data failed. See report for details." ); | ||
| } | ||
|
|
||
| bool TestQgsWcsProvider::read( QString theIdentifier, QString theWcsUri, QString theFilePath, QString & theReport ) | ||
| { | ||
| bool ok = true; | ||
|
|
||
| theReport += QString( "<h2>Identifier (coverage): %1</h2>" ).arg( theIdentifier ); | ||
|
|
||
| QgsRasterDataProvider* wcsProvider = QgsRasterLayer::loadProvider( "wcs", theWcsUri ); | ||
| if ( !wcsProvider || !wcsProvider->isValid() ) | ||
| { | ||
| error( QString( "Cannot load WCS provider with URI: %1" ).arg( QString( theWcsUri ) ), theReport ); | ||
| ok = false; | ||
| } | ||
|
|
||
| QgsRasterDataProvider* gdalProvider = QgsRasterLayer::loadProvider( "gdal", theFilePath ); | ||
| if ( !gdalProvider || !gdalProvider->isValid() ) | ||
| { | ||
| error( QString( "Cannot load GDAL provider with URI: %1" ).arg( theFilePath ), theReport ); | ||
| ok = false; | ||
| } | ||
|
|
||
| if ( !ok ) return false; | ||
|
|
||
| theReport += QString( "WCS URI: %1<br>" ).arg( theWcsUri.replace( "&", "&" ) ); | ||
| theReport += QString( "GDAL URI: %1<br>" ).arg( theFilePath ); | ||
|
|
||
| theReport += "<br>"; | ||
| theReport += "<table class='tab'>"; | ||
| theReport += compareHead(); | ||
|
|
||
| compare( "Band count", wcsProvider->bandCount(), gdalProvider->bandCount(), theReport, ok ); | ||
|
|
||
| compare( "Width", wcsProvider->xSize(), gdalProvider->xSize(), theReport, ok ); | ||
| compare( "Height", wcsProvider->ySize(), gdalProvider->ySize(), theReport, ok ); | ||
|
|
||
| compareRow( "Extent", wcsProvider->extent().toString(), gdalProvider->extent().toString(), theReport, wcsProvider->extent() == gdalProvider->extent() ); | ||
| if ( wcsProvider->extent() != gdalProvider->extent() ) ok = false; | ||
|
|
||
| if ( !ok ) return false; | ||
|
|
||
| compare( "No data (NULL) value", wcsProvider->noDataValue(), gdalProvider->noDataValue(), theReport, ok ); | ||
|
|
||
| theReport += "</table>"; | ||
|
|
||
|
|
||
| bool allOk = true; | ||
| for ( int band = 1; band <= gdalProvider->bandCount(); band++ ) | ||
| { | ||
| bool bandOk = true; | ||
| theReport += QString( "<h3>Band %1</h3>" ).arg( band ); | ||
| theReport += "<table class='tab'>"; | ||
| theReport += compareHead(); | ||
|
|
||
| // Data types may differ (?) | ||
| bool typesOk = true; | ||
| compare( "Source data type", wcsProvider->srcDataType( band ), gdalProvider->srcDataType( band ), theReport, typesOk ); | ||
| compare( "Data type", wcsProvider->dataType( band ), gdalProvider->dataType( band ), theReport, typesOk ) ; | ||
|
|
||
| bool statsOk = true; | ||
| QgsRasterBandStats wcsStats = wcsProvider->bandStatistics( band ); | ||
| QgsRasterBandStats gdalStats = gdalProvider->bandStatistics( band ); | ||
|
|
||
| // Min/max may 'slightly' differ, for big numbers however, the difference may | ||
| // be quite big, for example for Float32 with max -3.332e+38, the difference is 1.47338e+24 | ||
| double tol = tolerance( gdalStats.minimumValue ); | ||
| compare( "Minimum value", wcsStats.minimumValue, gdalStats.minimumValue, theReport, statsOk, tol ); | ||
| tol = tolerance( gdalStats.maximumValue ); | ||
| compare( "Maximum value", wcsStats.maximumValue, gdalStats.maximumValue, theReport, statsOk, tol ); | ||
|
|
||
| // TODO: enable once fixed (WCS excludes nulls but GDAL does not) | ||
| //compare( "Cells count", wcsStats.elementCount, gdalStats.elementCount, theReport, statsOk ); | ||
|
|
||
| tol = tolerance( gdalStats.mean ); | ||
| compare( "Mean", wcsStats.mean, gdalStats.mean, theReport, statsOk, tol ); | ||
|
|
||
| // stdDev usually differ significantly | ||
| tol = tolerance( gdalStats.stdDev, 1 ); | ||
| compare( "Standard deviation", wcsStats.stdDev, gdalStats.stdDev, theReport, statsOk, tol ); | ||
|
|
||
| theReport += "</table>"; | ||
| theReport += "<br>"; | ||
|
|
||
| if ( !bandOk ) | ||
| { | ||
| allOk = false; | ||
| continue; | ||
| } | ||
|
|
||
| if ( !statsOk || !typesOk ) | ||
| { | ||
| allOk = false; | ||
| // create values table anyway so that values are available | ||
| } | ||
|
|
||
| theReport += "<table><tr>"; | ||
| theReport += "<td>Data comparison</td>"; | ||
| theReport += "<td class='cell ok' style='border: 1px solid'>correct value</td>"; | ||
| theReport += "<td></td>"; | ||
| theReport += "<td class='cell err' style='border: 1px solid'>wrong value<br>expected value</td></tr>"; | ||
| theReport += "</tr></table>"; | ||
| theReport += "<br>"; | ||
|
|
||
| int width = gdalProvider->xSize(); | ||
| int height = gdalProvider->ySize(); | ||
| int blockSize = width * height * gdalProvider->typeSize( gdalProvider->dataType( band ) ) ; | ||
| void * gdalData = malloc( blockSize ); | ||
| void * wcsData = malloc( blockSize ); | ||
|
|
||
| gdalProvider->readBlock( band, gdalProvider->extent(), width, height, gdalData ); | ||
| wcsProvider->readBlock( band, gdalProvider->extent(), width, height, wcsData ); | ||
|
|
||
| // compare data values | ||
| QString htmlTable = "<table class='tab'>"; | ||
| for ( int row = 0; row < height; row ++ ) | ||
| { | ||
| htmlTable += "<tr>"; | ||
| for ( int col = 0; col < width; col ++ ) | ||
| { | ||
| bool cellOk = true; | ||
| double wcsVal = wcsProvider->readValue( wcsData, wcsProvider->dataType( band ), row * width + col ); | ||
| double gdalVal = gdalProvider->readValue( gdalData, gdalProvider->dataType( band ), row * width + col ); | ||
|
|
||
| QString valStr; | ||
| if ( compare( wcsVal, gdalVal, 0 ) ) | ||
| { | ||
| valStr = QString( "%1" ).arg( wcsVal ); | ||
| } | ||
| else | ||
| { | ||
| cellOk = false; | ||
| allOk = false; | ||
| valStr = QString( "%1<br>%2" ).arg( wcsVal ).arg( gdalVal ); | ||
| } | ||
| htmlTable += QString( "<td class='cell %1'>%2</td>" ).arg( cellOk ? "ok" : "err" ).arg( valStr ); | ||
| } | ||
| htmlTable += "</tr>"; | ||
| } | ||
| htmlTable += "</table>"; | ||
|
|
||
| theReport += htmlTable; | ||
|
|
||
| free( gdalData ); | ||
| free( wcsData ); | ||
| } | ||
| delete wcsProvider; | ||
| delete gdalProvider; | ||
| return allOk; | ||
| } | ||
|
|
||
| void TestQgsWcsProvider::error( QString theMessage, QString &theReport ) | ||
| { | ||
| theReport += "<font class='errmsg'>Error: "; | ||
| theReport += theMessage; | ||
| theReport += "</font>"; | ||
| } | ||
|
|
||
| double TestQgsWcsProvider::tolerance( double val, int places ) | ||
| { | ||
| // float precission is about 7 decimal digits, double about 16 | ||
| // default places = 6 | ||
| return 1. * pow( 10, round( log10( qAbs( val ) ) - places ) ); | ||
| } | ||
|
|
||
| QString TestQgsWcsProvider::compareHead() | ||
| { | ||
| return "<tr><th class='cell'>Param name</th><th class='cell'>WCS (tested) value</th><th class='cell'>GDAL (expected) value</th><th class='cell'>Difference</th><th class='cell'>Tolerance</th></tr>"; | ||
| } | ||
|
|
||
| void TestQgsWcsProvider::compare( QString theParamName, int wcsVal, int gdalVal, QString &theReport, bool &theOk ) | ||
| { | ||
| bool ok = wcsVal == gdalVal; | ||
| compareRow( theParamName, QString::number( wcsVal ), QString::number( gdalVal ), theReport, ok, QString::number( wcsVal - gdalVal ) ); | ||
| if ( !ok ) theOk = false; | ||
| } | ||
|
|
||
| bool TestQgsWcsProvider::compare( double wcsVal, double gdalVal, double theTolerance ) | ||
| { | ||
| // values may be nan | ||
| return ( std::isnan( wcsVal ) && std::isnan( gdalVal ) ) || ( qAbs( wcsVal - gdalVal ) <= theTolerance ); | ||
| } | ||
|
|
||
| void TestQgsWcsProvider::compare( QString theParamName, double wcsVal, double gdalVal, QString &theReport, bool &theOk, double theTolerance ) | ||
| { | ||
| bool ok = compare( wcsVal, gdalVal, theTolerance ); | ||
| compareRow( theParamName, QString::number( wcsVal ), QString::number( gdalVal ), theReport, ok, QString::number( wcsVal - gdalVal ), QString::number( theTolerance ) ); | ||
| if ( !ok ) theOk = false; | ||
| } | ||
|
|
||
| void TestQgsWcsProvider::compareRow( QString theParamName, QString wcsVal, QString gdalVal, QString &theReport, bool theOk, QString theDifference, QString theTolerance ) | ||
| { | ||
| theReport += "<tr>"; | ||
| theReport += QString( "<td class='cell'>%1</td><td class='cell %2'>%3</td><td class='cell'>%4</td>" ).arg( theParamName ).arg( theOk ? "ok" : "err" ).arg( wcsVal ).arg( gdalVal ); | ||
| theReport += QString( "<td class='cell'>%1</td>" ).arg( theDifference ); | ||
| theReport += QString( "<td class='cell'>%1</td>" ).arg( theTolerance ); | ||
| theReport += "</tr>"; | ||
| } | ||
|
|
||
| QTEST_MAIN( TestQgsWcsProvider ) | ||
| #include "moc_testqgswcsprovider.cxx" |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,23 @@ | ||
| WCS test server installation | ||
| ---------------------------- | ||
| WCS test server is based on UMN MapServer running on qgis.org. | ||
|
|
||
| 1. Install UMN MapServer (mapserver.org) version 6.0 or higher with WCS support (--with-wcs configure option if compiled from source) | ||
|
|
||
| 2. Copy test data from qgis source tests/testdata/raster somewhere on server, for example to /var/www/data/test/1.9.0/tests/testdata/raster. | ||
|
|
||
| 3. Edit WCS mapfile, for example /var/www/data/test/1.9.0/tests/testdata/raster/wcs.map and set SHAPEPATH to the path where data were copied, e.g.: | ||
| SHAPEPATH "/var/www/data/test/1.9.0/tests/testdata/raster/" | ||
|
|
||
| 4. Create script in cgi-bin dir where mapfile is specified, e.g. /usr/lib/cgi-bin/wcstest-1.9.0: | ||
|
|
||
| #! /bin/sh | ||
| MS_MAPFILE=/var/www/data/test/1.9.0/tests/testdata/raster/wcs.map | ||
| export MS_MAPFILE | ||
| ./mapserv | ||
|
|
||
| 5. Configure Web server, for example if Apache is used, add rewrite rule to config file using /test/<version>/wcs path: | ||
|
|
||
| RewriteRule /test/1.9.0/wcs /cgi-bin/wcstest-1.9.0 [PT] | ||
|
|
||
| 6. WARNING: If possible, don't change WCS server URL for released versions. If the server URL has to be changed for development and future versions, change also the variable TEST_SERVER_URL in tests/src/providers/CMakeLists.txt. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,13 @@ | ||
| <PAMDataset> | ||
| <PAMRasterBand band="1"> | ||
| <Metadata> | ||
| <MDI key="COLOR_TABLE_RULE_RGB_0">2.000000e+00 1.280000e+02 0 255 0 255 255 0</MDI> | ||
| <MDI key="COLOR_TABLE_RULE_RGB_1">1.280000e+02 2.540000e+02 255 255 0 255 0 0</MDI> | ||
| <MDI key="COLOR_TABLE_RULES_COUNT">2</MDI> | ||
| <MDI key="STATISTICS_MAXIMUM">254</MDI> | ||
| <MDI key="STATISTICS_MEAN">135.53086419753</MDI> | ||
| <MDI key="STATISTICS_MINIMUM">2</MDI> | ||
| <MDI key="STATISTICS_STDDEV">73.957459647589</MDI> | ||
| </Metadata> | ||
| </PAMRasterBand> | ||
| </PAMDataset> |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,13 @@ | ||
| <PAMDataset> | ||
| <PAMRasterBand band="1"> | ||
| <Metadata> | ||
| <MDI key="COLOR_TABLE_RULE_RGB_0">2.000000e+00 1.280000e+02 0 255 0 255 255 0</MDI> | ||
| <MDI key="COLOR_TABLE_RULE_RGB_1">1.280000e+02 2.540000e+02 255 255 0 255 0 0</MDI> | ||
| <MDI key="COLOR_TABLE_RULES_COUNT">2</MDI> | ||
| <MDI key="STATISTICS_MAXIMUM">254</MDI> | ||
| <MDI key="STATISTICS_MEAN">135.53086419753</MDI> | ||
| <MDI key="STATISTICS_MINIMUM">2</MDI> | ||
| <MDI key="STATISTICS_STDDEV">73.957459647589</MDI> | ||
| </Metadata> | ||
| </PAMRasterBand> | ||
| </PAMDataset> |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,12 @@ | ||
| <PAMDataset> | ||
| <PAMRasterBand band="1"> | ||
| <Metadata> | ||
| <MDI key="COLOR_TABLE_RULE_RGB_0">0.000000e+00 0.000000e+00 255 127 0 255 127 0</MDI> | ||
| <MDI key="COLOR_TABLE_RULES_COUNT">1</MDI> | ||
| <MDI key="STATISTICS_MAXIMUM">3.3999999521444e+38</MDI> | ||
| <MDI key="STATISTICS_MEAN">2.4177777984595e+37</MDI> | ||
| <MDI key="STATISTICS_MINIMUM">-3.3319999287626e+38</MDI> | ||
| <MDI key="STATISTICS_STDDEV">1.9800745699579e+38</MDI> | ||
| </Metadata> | ||
| </PAMRasterBand> | ||
| </PAMDataset> |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,13 @@ | ||
| <PAMDataset> | ||
| <PAMRasterBand band="1"> | ||
| <Metadata> | ||
| <MDI key="COLOR_TABLE_RULE_RGB_0">-3.211166e+04 3.276700e+02 0 255 0 255 255 0</MDI> | ||
| <MDI key="COLOR_TABLE_RULE_RGB_1">3.276700e+02 3.276700e+04 255 255 0 255 0 0</MDI> | ||
| <MDI key="COLOR_TABLE_RULES_COUNT">2</MDI> | ||
| <MDI key="STATISTICS_MAXIMUM">32767</MDI> | ||
| <MDI key="STATISTICS_MEAN">2330.024691358</MDI> | ||
| <MDI key="STATISTICS_MINIMUM">-32111</MDI> | ||
| <MDI key="STATISTICS_STDDEV">19082.231766347</MDI> | ||
| </Metadata> | ||
| </PAMRasterBand> | ||
| </PAMDataset> |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,35 @@ | ||
| <PAMDataset> | ||
| <PAMRasterBand band="1"> | ||
| <Metadata> | ||
| <MDI key="COLOR_TABLE_RULE_RGB_0">2.000000e+00 1.280000e+02 0 255 0 255 255 0</MDI> | ||
| <MDI key="COLOR_TABLE_RULE_RGB_1">1.280000e+02 2.540000e+02 255 255 0 255 0 0</MDI> | ||
| <MDI key="COLOR_TABLE_RULES_COUNT">2</MDI> | ||
| <MDI key="STATISTICS_MAXIMUM">254</MDI> | ||
| <MDI key="STATISTICS_MEAN">135.53086419753</MDI> | ||
| <MDI key="STATISTICS_MINIMUM">2</MDI> | ||
| <MDI key="STATISTICS_STDDEV">73.957459647589</MDI> | ||
| </Metadata> | ||
| </PAMRasterBand> | ||
| <PAMRasterBand band="2"> | ||
| <Metadata> | ||
| <MDI key="COLOR_TABLE_RULE_RGB_0">2.000000e+00 1.280000e+02 0 255 0 255 255 0</MDI> | ||
| <MDI key="COLOR_TABLE_RULE_RGB_1">1.280000e+02 2.540000e+02 255 255 0 255 0 0</MDI> | ||
| <MDI key="COLOR_TABLE_RULES_COUNT">2</MDI> | ||
| <MDI key="STATISTICS_MAXIMUM">254</MDI> | ||
| <MDI key="STATISTICS_MEAN">135.53086419753</MDI> | ||
| <MDI key="STATISTICS_MINIMUM">2</MDI> | ||
| <MDI key="STATISTICS_STDDEV">73.957459647589</MDI> | ||
| </Metadata> | ||
| </PAMRasterBand> | ||
| <PAMRasterBand band="3"> | ||
| <Metadata> | ||
| <MDI key="COLOR_TABLE_RULE_RGB_0">2.000000e+00 1.280000e+02 0 255 0 255 255 0</MDI> | ||
| <MDI key="COLOR_TABLE_RULE_RGB_1">1.280000e+02 2.540000e+02 255 255 0 255 0 0</MDI> | ||
| <MDI key="COLOR_TABLE_RULES_COUNT">2</MDI> | ||
| <MDI key="STATISTICS_MAXIMUM">254</MDI> | ||
| <MDI key="STATISTICS_MEAN">135.53086419753</MDI> | ||
| <MDI key="STATISTICS_MINIMUM">2</MDI> | ||
| <MDI key="STATISTICS_STDDEV">73.957459647589</MDI> | ||
| </Metadata> | ||
| </PAMRasterBand> | ||
| </PAMDataset> |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,32 @@ | ||
| <PAMDataset> | ||
| <PAMRasterBand band="1"> | ||
| <Metadata> | ||
| <MDI key="COLOR_TABLE_RULE_RGB_0">0.000000e+00 0.000000e+00 255 127 0 255 127 0</MDI> | ||
| <MDI key="COLOR_TABLE_RULES_COUNT">1</MDI> | ||
| <MDI key="STATISTICS_MAXIMUM">3.3999999521444e+38</MDI> | ||
| <MDI key="STATISTICS_MEAN">2.4177777984595e+37</MDI> | ||
| <MDI key="STATISTICS_MINIMUM">-3.3319999287626e+38</MDI> | ||
| <MDI key="STATISTICS_STDDEV">1.9800745699579e+38</MDI> | ||
| </Metadata> | ||
| </PAMRasterBand> | ||
| <PAMRasterBand band="2"> | ||
| <Metadata> | ||
| <MDI key="COLOR_TABLE_RULE_RGB_0">0.000000e+00 0.000000e+00 255 127 0 255 127 0</MDI> | ||
| <MDI key="COLOR_TABLE_RULES_COUNT">1</MDI> | ||
| <MDI key="STATISTICS_MAXIMUM">3.3999999521444e+38</MDI> | ||
| <MDI key="STATISTICS_MEAN">2.4177777984595e+37</MDI> | ||
| <MDI key="STATISTICS_MINIMUM">-3.3319999287626e+38</MDI> | ||
| <MDI key="STATISTICS_STDDEV">1.9800745699579e+38</MDI> | ||
| </Metadata> | ||
| </PAMRasterBand> | ||
| <PAMRasterBand band="3"> | ||
| <Metadata> | ||
| <MDI key="COLOR_TABLE_RULE_RGB_0">0.000000e+00 0.000000e+00 255 127 0 255 127 0</MDI> | ||
| <MDI key="COLOR_TABLE_RULES_COUNT">1</MDI> | ||
| <MDI key="STATISTICS_MAXIMUM">3.3999999521444e+38</MDI> | ||
| <MDI key="STATISTICS_MEAN">2.4177777984595e+37</MDI> | ||
| <MDI key="STATISTICS_MINIMUM">-3.3319999287626e+38</MDI> | ||
| <MDI key="STATISTICS_STDDEV">1.9800745699579e+38</MDI> | ||
| </Metadata> | ||
| </PAMRasterBand> | ||
| </PAMDataset> |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,35 @@ | ||
| <PAMDataset> | ||
| <PAMRasterBand band="1"> | ||
| <Metadata> | ||
| <MDI key="COLOR_TABLE_RULE_RGB_0">-3.211166e+04 3.276700e+02 0 255 0 255 255 0</MDI> | ||
| <MDI key="COLOR_TABLE_RULE_RGB_1">3.276700e+02 3.276700e+04 255 255 0 255 0 0</MDI> | ||
| <MDI key="COLOR_TABLE_RULES_COUNT">2</MDI> | ||
| <MDI key="STATISTICS_MAXIMUM">32767</MDI> | ||
| <MDI key="STATISTICS_MEAN">2330.024691358</MDI> | ||
| <MDI key="STATISTICS_MINIMUM">-32111</MDI> | ||
| <MDI key="STATISTICS_STDDEV">19082.231766347</MDI> | ||
| </Metadata> | ||
| </PAMRasterBand> | ||
| <PAMRasterBand band="2"> | ||
| <Metadata> | ||
| <MDI key="COLOR_TABLE_RULE_RGB_0">-3.211166e+04 3.276700e+02 0 255 0 255 255 0</MDI> | ||
| <MDI key="COLOR_TABLE_RULE_RGB_1">3.276700e+02 3.276700e+04 255 255 0 255 0 0</MDI> | ||
| <MDI key="COLOR_TABLE_RULES_COUNT">2</MDI> | ||
| <MDI key="STATISTICS_MAXIMUM">32767</MDI> | ||
| <MDI key="STATISTICS_MEAN">2330.024691358</MDI> | ||
| <MDI key="STATISTICS_MINIMUM">-32111</MDI> | ||
| <MDI key="STATISTICS_STDDEV">19082.231766347</MDI> | ||
| </Metadata> | ||
| </PAMRasterBand> | ||
| <PAMRasterBand band="3"> | ||
| <Metadata> | ||
| <MDI key="COLOR_TABLE_RULE_RGB_0">-3.211166e+04 3.276700e+02 0 255 0 255 255 0</MDI> | ||
| <MDI key="COLOR_TABLE_RULE_RGB_1">3.276700e+02 3.276700e+04 255 255 0 255 0 0</MDI> | ||
| <MDI key="COLOR_TABLE_RULES_COUNT">2</MDI> | ||
| <MDI key="STATISTICS_MAXIMUM">32767</MDI> | ||
| <MDI key="STATISTICS_MEAN">2330.024691358</MDI> | ||
| <MDI key="STATISTICS_MINIMUM">-32111</MDI> | ||
| <MDI key="STATISTICS_STDDEV">19082.231766347</MDI> | ||
| </Metadata> | ||
| </PAMRasterBand> | ||
| </PAMDataset> |