Skip to content
Permalink
Browse files

wcs preferred version, identify

  • Loading branch information
blazek committed Jul 10, 2012
1 parent f8e3dde commit 058f287f46a60474cad26cfa7d491605502d940b
@@ -80,8 +80,6 @@ QgsWcsCapabilities::QgsWcsCapabilities( QgsDataSourceURI const &theUri ):
{
QgsDebugMsg( "uri = " + mUri.encodedUri() );

mUserVersion = QUrl( mUri.param( "url" ) ).queryItemValue( "VERSION" );

retrieveServerCapabilities();
}

@@ -99,14 +97,9 @@ QgsWcsCapabilities::~QgsWcsCapabilities()
void QgsWcsCapabilities::setUri( QgsDataSourceURI const &theUri )
{
mUri = theUri;
mCoverageCount = 0;
mCoveragesSupported.clear();
QgsWcsCapabilitiesProperty c;
mCapabilities = c;

mUserVersion = QUrl( mUri.param( "url" ) ).queryItemValue( "VERSION" );

retrieveServerCapabilities( true );
clear();
retrieveServerCapabilities( );
}

QString QgsWcsCapabilities::prepareUri( QString uri )
@@ -195,39 +188,62 @@ bool QgsWcsCapabilities::sendRequest( QString const & url )
return true;
}

bool QgsWcsCapabilities::retrieveServerCapabilities( bool forceRefresh )
void QgsWcsCapabilities::clear()
{
if ( mCapabilitiesResponse.isNull() || forceRefresh )
mCoverageCount = 0;
mCoveragesSupported.clear();
QgsWcsCapabilitiesProperty c;
mCapabilities = c;
}

bool QgsWcsCapabilities::retrieveServerCapabilities( )
{
clear();
QStringList versions;

// 1.0.0 - VERSION
// 1.1.0 - AcceptedVersions (not supported by UMN Mapserver 6.0.3 - defaults to 1.1.1
versions << "AcceptVersions=1.1.0,1.0.0" << "VERSION=1.0.0";

foreach( QString v, versions )
{
// Check if user tried to force version
if ( !mUserVersion.isEmpty() && !mUserVersion.startsWith( "1.0." ) && !mUserVersion.startsWith( "1.1." ) )
if ( retrieveServerCapabilities( v ) )
{
mErrorTitle = tr( "Version not supported" );
mErrorFormat = "text/plain";
mError = tr( "The version %1 specified in connection URL parameter VERSION is not supported by QGIS" ).arg( mUserVersion );
return false;
return true;
}
}

QString url = prepareUri( mUri.param( "url" ) ) + "SERVICE=WCS&REQUEST=GetCapabilities";
return false;
}

if ( ! sendRequest( url ) ) { return false; }
bool QgsWcsCapabilities::retrieveServerCapabilities( QString preferredVersion )
{
clear();

QgsDebugMsg( "Converting to Dom." );
QString url = prepareUri( mUri.param( "url" ) ) + "SERVICE=WCS&REQUEST=GetCapabilities";

bool domOK;
domOK = parseCapabilitiesDom( mCapabilitiesResponse, mCapabilities );
if ( !preferredVersion.isEmpty() )
{
url += "&" + preferredVersion;
}

if ( !domOK )
{
// We had an Dom exception -
// mErrorTitle and mError are pre-filled by parseCapabilitiesDom
if ( ! sendRequest( url ) ) { return false; }

mError += tr( "\nTried URL: %1" ).arg( url );
QgsDebugMsg( "Converting to Dom." );

QgsDebugMsg( "!domOK: " + mError );
bool domOK;
domOK = parseCapabilitiesDom( mCapabilitiesResponse, mCapabilities );

return false;
}
if ( !domOK )
{
// We had an Dom exception -
// mErrorTitle and mError are pre-filled by parseCapabilitiesDom

mError += tr( "\nTried URL: %1" ).arg( url );

QgsDebugMsg( "!domOK: " + mError );

return false;
}

return true;
@@ -246,12 +262,8 @@ 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=1.0.0&COVERAGE=" + coverage->identifier;
QString url = prepareUri( mUri.param( "url" ) ) + "SERVICE=WCS&REQUEST=DescribeCoverage&COVERAGE=" + coverage->identifier;
if ( mUserVersion.isEmpty() )
{
url += "&VERSION=" + mVersion;
}
url += "&VERSION=" + mVersion;

if ( ! sendRequest( url ) ) { return false; }

@@ -236,6 +236,8 @@ class QgsWcsCapabilities : public QObject
void capabilitiesReplyProgress( qint64, qint64 );

private:
void clear();

void showMessageBox( const QString &title, const QString &text );

//! Get tag name without namespace
@@ -262,16 +264,19 @@ class QgsWcsCapabilities : public QObject
/**
* \brief Retrieve and parse the (cached) Capabilities document from the server
*
* \param forceRefresh if true, ignores any previous response cached in memory
* and always contact the server for a new copy.
* \param preferredVersion - optional version KVP
*
* \retval false if the capabilities document could not be retrieved or parsed -
* see lastError() for more info
*
* When this returns, "layers" will make sense.
*
* TODO: Make network-timeout tolerant
*/
bool retrieveServerCapabilities( bool forceRefresh = false );
bool retrieveServerCapabilities( QString preferredVersion );

/** Retrieve the best WCS version supported by server and QGIS */
bool retrieveServerCapabilities( );

//! \return false if the capabilities document could not be parsed - see lastError() for more info
bool parseCapabilitiesDom( QByteArray const &xml, QgsWcsCapabilitiesProperty &capabilities );
@@ -316,9 +321,6 @@ class QgsWcsCapabilities : public QObject
//! Response capabilities version
QString mVersion;

//! Version specified by user in url
QString mUserVersion;

/**
* Capabilities of the WCS Server (raw)
*/
@@ -366,13 +366,15 @@ void QgsWcsProvider::readBlock( int bandNo, QgsRectangle const & viewExtent, in
{
QgsDebugMsg( "Entered" );

/*
if ( myExpectedSize != myImageSize ) // should not happen
// Requested extent must at least partialy overlap coverage extent, otherwise
// server gives error. QGIS usually does not request blocks outside raster extent
// (higher level checks) but it is better to do check here as well
if ( !viewExtent.intersects( mCoverageExtent ) )
{
QgsMessageLog::logMessage( tr( "unexpected image size" ), tr( "WCS" ) );
// TODO: set block to null values
memset( block, 0, pixelWidth * pixelHeight * typeSize( dataType( bandNo ) ) / 8 );
return;
}
*/

// abort running (untiled) request
if ( mCacheReply )
@@ -382,17 +384,15 @@ void QgsWcsProvider::readBlock( int bandNo, QgsRectangle const & viewExtent, in
mCacheReply = 0;
}

// Can we reuse the previously cached image?
if ( mCachedGdalDataset &&
mCachedViewExtent == viewExtent &&
mCachedViewWidth == pixelWidth &&
mCachedViewHeight == pixelHeight )
// Can we reuse the previously cached coverage?
if ( !mCachedGdalDataset ||
mCachedViewExtent != viewExtent ||
mCachedViewWidth != pixelWidth ||
mCachedViewHeight != pixelHeight )
{
//return mCachedImage;
getCache( bandNo, viewExtent, pixelWidth, pixelHeight );
}

getCache( bandNo, viewExtent, pixelWidth, pixelHeight );

if ( mCachedGdalDataset )
{
// TODO band
@@ -408,17 +408,22 @@ void QgsWcsProvider::readBlock( int bandNo, QgsRectangle const & viewExtent, in
}
else
{
QgsDebugMsg( tr( "Recieved coverage has wrong size" ) );
QgsMessageLog::logMessage( tr( "Received coverage has wrong size" ), tr( "WCS" ) );
return;
}
}
}

void QgsWcsProvider::getCache( int bandNo, QgsRectangle const & viewExtent, int pixelWidth, int pixelHeight )
{
QgsDebugMsg( "Entered" );
// delete cached data
clearCache();

mCachedViewExtent = viewExtent;
mCachedViewWidth = pixelWidth;
mCachedViewHeight = pixelHeight;

// --------------- BOUNDING BOX --------------------------------
//according to the WCS spec for 1.1, some CRS have inverted axis
// box:
@@ -1484,6 +1489,105 @@ QString QgsWcsProvider::metadata()
return metadata;
}

bool QgsWcsProvider::identify( const QgsPoint& thePoint, QMap<QString, QString>& theResults )
{
QgsDebugMsg( "Entered" );
theResults.clear();

if ( !extent().contains( thePoint ) )
{
// Outside the raster
for ( int i = 1; i <= bandCount(); i++ )
{
theResults[ generateBandName( i )] = tr( "out of extent" );
}
return true;
}

// It would be nice to use last cached block if possible, unfortunately we don't know
// at which resolution identify() is called. It may happen, that user zoomed in with
// layer switched off, canvas resolution increased, but provider cache was not refreshed.
// In that case the resolution is too low and identify() could give wron results.
// So we have to read always a block of data around the point on highest resolution
// if not already cached.
// TODO: change provider identify() prototype to pass also the resolution

int width, height;
if ( mHasSize )
{
width = mWidth;
height = mHeight;
}
else
{
// Bad in any case, either not precise or too much data requests
width = height = 1000;
}
double xRes = mCoverageExtent.width() / width;
double yRes = mCoverageExtent.height() / height;

if ( !mCachedGdalDataset ||
!mCachedViewExtent.contains( thePoint ) ||
mCachedViewWidth == 0 || mCachedViewHeight == 0 ||
mCachedViewExtent.width() / mCachedViewWidth - xRes > TINY_VALUE ||
mCachedViewExtent.height() / mCachedViewHeight - yRes > TINY_VALUE )
{
int half = 50;
QgsRectangle extent( thePoint.x() - xRes * half, thePoint.y() - yRes * half,
thePoint.x() + xRes * half, thePoint.y() + yRes * half );
getCache( 1, extent, 2*half, 2*half );

}

if ( !mCachedGdalDataset ||
!mCachedViewExtent.contains( thePoint ) )
{
return false; // should not happen
}

double x = thePoint.x();
double y = thePoint.y();

// Calculate the row / column where the point falls
xRes = ( mCachedViewExtent.xMaximum() - mCachedViewExtent.xMinimum() ) / mCachedViewWidth;
yRes = ( mCachedViewExtent.yMaximum() - mCachedViewExtent.yMinimum() ) / mCachedViewHeight;

// Offset, not the cell index -> flor
int col = ( int ) floor(( x - mCachedViewExtent.xMinimum() ) / xRes );
int row = ( int ) floor(( mCachedViewExtent.yMaximum() - y ) / yRes );

QgsDebugMsg( "row = " + QString::number( row ) + " col = " + QString::number( col ) );

for ( int i = 1; i <= GDALGetRasterCount( mCachedGdalDataset ); i++ )
{
GDALRasterBandH gdalBand = GDALGetRasterBand( mCachedGdalDataset, i );
double value;

CPLErr err = GDALRasterIO( gdalBand, GF_Read, col, row, 1, 1,
&value, 1, 1, GDT_Float64, 0, 0 );

if ( err != CPLE_None )
{
QgsLogger::warning( "RasterIO error: " + QString::fromUtf8( CPLGetLastErrorMsg() ) );
}

QString v;

if ( mValidNoDataValue && ( fabs( value - mNoDataValue[i-1] ) <= TINY_VALUE || value != value ) )
{
v = tr( "null (no data)" );
}
else
{
v.setNum( value );
}

theResults[ generateBandName( i )] = v;
}

return true;
}

QString QgsWcsProvider::identifyAsText( const QgsPoint &point )
{
Q_UNUSED( point );
@@ -149,6 +149,7 @@ class QgsWcsProvider : public QgsRasterDataProvider
int xSize() const;
int ySize() const;
QString metadata();
bool identify( const QgsPoint& thePoint, QMap<QString, QString>& theResults );
QString identifyAsHtml( const QgsPoint& point );
QString identifyAsText( const QgsPoint& point );
QString lastErrorTitle();

0 comments on commit 058f287

Please sign in to comment.
You can’t perform that action at this time.