Skip to content

Commit 058f287

Browse files
committed
wcs preferred version, identify
1 parent f8e3dde commit 058f287

File tree

4 files changed

+173
-54
lines changed

4 files changed

+173
-54
lines changed

src/providers/wcs/qgswcscapabilities.cpp

+47-35
Original file line numberDiff line numberDiff line change
@@ -80,8 +80,6 @@ QgsWcsCapabilities::QgsWcsCapabilities( QgsDataSourceURI const &theUri ):
8080
{
8181
QgsDebugMsg( "uri = " + mUri.encodedUri() );
8282

83-
mUserVersion = QUrl( mUri.param( "url" ) ).queryItemValue( "VERSION" );
84-
8583
retrieveServerCapabilities();
8684
}
8785

@@ -99,14 +97,9 @@ QgsWcsCapabilities::~QgsWcsCapabilities()
9997
void QgsWcsCapabilities::setUri( QgsDataSourceURI const &theUri )
10098
{
10199
mUri = theUri;
102-
mCoverageCount = 0;
103-
mCoveragesSupported.clear();
104-
QgsWcsCapabilitiesProperty c;
105-
mCapabilities = c;
106100

107-
mUserVersion = QUrl( mUri.param( "url" ) ).queryItemValue( "VERSION" );
108-
109-
retrieveServerCapabilities( true );
101+
clear();
102+
retrieveServerCapabilities( );
110103
}
111104

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

198-
bool QgsWcsCapabilities::retrieveServerCapabilities( bool forceRefresh )
191+
void QgsWcsCapabilities::clear()
199192
{
200-
if ( mCapabilitiesResponse.isNull() || forceRefresh )
193+
mCoverageCount = 0;
194+
mCoveragesSupported.clear();
195+
QgsWcsCapabilitiesProperty c;
196+
mCapabilities = c;
197+
}
198+
199+
bool QgsWcsCapabilities::retrieveServerCapabilities( )
200+
{
201+
clear();
202+
QStringList versions;
203+
204+
// 1.0.0 - VERSION
205+
// 1.1.0 - AcceptedVersions (not supported by UMN Mapserver 6.0.3 - defaults to 1.1.1
206+
versions << "AcceptVersions=1.1.0,1.0.0" << "VERSION=1.0.0";
207+
208+
foreach( QString v, versions )
201209
{
202-
// Check if user tried to force version
203-
if ( !mUserVersion.isEmpty() && !mUserVersion.startsWith( "1.0." ) && !mUserVersion.startsWith( "1.1." ) )
210+
if ( retrieveServerCapabilities( v ) )
204211
{
205-
mErrorTitle = tr( "Version not supported" );
206-
mErrorFormat = "text/plain";
207-
mError = tr( "The version %1 specified in connection URL parameter VERSION is not supported by QGIS" ).arg( mUserVersion );
208-
return false;
212+
return true;
209213
}
214+
}
210215

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

213-
if ( ! sendRequest( url ) ) { return false; }
219+
bool QgsWcsCapabilities::retrieveServerCapabilities( QString preferredVersion )
220+
{
221+
clear();
214222

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

217-
bool domOK;
218-
domOK = parseCapabilitiesDom( mCapabilitiesResponse, mCapabilities );
225+
if ( !preferredVersion.isEmpty() )
226+
{
227+
url += "&" + preferredVersion;
228+
}
219229

220-
if ( !domOK )
221-
{
222-
// We had an Dom exception -
223-
// mErrorTitle and mError are pre-filled by parseCapabilitiesDom
230+
if ( ! sendRequest( url ) ) { return false; }
224231

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

227-
QgsDebugMsg( "!domOK: " + mError );
234+
bool domOK;
235+
domOK = parseCapabilitiesDom( mCapabilitiesResponse, mCapabilities );
228236

229-
return false;
230-
}
237+
if ( !domOK )
238+
{
239+
// We had an Dom exception -
240+
// mErrorTitle and mError are pre-filled by parseCapabilitiesDom
241+
242+
mError += tr( "\nTried URL: %1" ).arg( url );
243+
244+
QgsDebugMsg( "!domOK: " + mError );
245+
246+
return false;
231247
}
232248

233249
return true;
@@ -246,12 +262,8 @@ bool QgsWcsCapabilities::describeCoverage( QString const &identifier, bool force
246262

247263
if ( coverage->described && ! forceRefresh ) return true;
248264

249-
//QString url = prepareUri( mUri.param( "url" ) ) + "SERVICE=WCS&REQUEST=DescribeCoverage&VERSION=1.0.0&COVERAGE=" + coverage->identifier;
250265
QString url = prepareUri( mUri.param( "url" ) ) + "SERVICE=WCS&REQUEST=DescribeCoverage&COVERAGE=" + coverage->identifier;
251-
if ( mUserVersion.isEmpty() )
252-
{
253-
url += "&VERSION=" + mVersion;
254-
}
266+
url += "&VERSION=" + mVersion;
255267

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

src/providers/wcs/qgswcscapabilities.h

+8-6
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,8 @@ class QgsWcsCapabilities : public QObject
236236
void capabilitiesReplyProgress( qint64, qint64 );
237237

238238
private:
239+
void clear();
240+
239241
void showMessageBox( const QString &title, const QString &text );
240242

241243
//! Get tag name without namespace
@@ -262,16 +264,19 @@ class QgsWcsCapabilities : public QObject
262264
/**
263265
* \brief Retrieve and parse the (cached) Capabilities document from the server
264266
*
265-
* \param forceRefresh if true, ignores any previous response cached in memory
266-
* and always contact the server for a new copy.
267+
* \param preferredVersion - optional version KVP
268+
*
267269
* \retval false if the capabilities document could not be retrieved or parsed -
268270
* see lastError() for more info
269271
*
270272
* When this returns, "layers" will make sense.
271273
*
272274
* TODO: Make network-timeout tolerant
273275
*/
274-
bool retrieveServerCapabilities( bool forceRefresh = false );
276+
bool retrieveServerCapabilities( QString preferredVersion );
277+
278+
/** Retrieve the best WCS version supported by server and QGIS */
279+
bool retrieveServerCapabilities( );
275280

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

319-
//! Version specified by user in url
320-
QString mUserVersion;
321-
322324
/**
323325
* Capabilities of the WCS Server (raw)
324326
*/

src/providers/wcs/qgswcsprovider.cpp

+117-13
Original file line numberDiff line numberDiff line change
@@ -366,13 +366,15 @@ void QgsWcsProvider::readBlock( int bandNo, QgsRectangle const & viewExtent, in
366366
{
367367
QgsDebugMsg( "Entered" );
368368

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

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

385-
// Can we reuse the previously cached image?
386-
if ( mCachedGdalDataset &&
387-
mCachedViewExtent == viewExtent &&
388-
mCachedViewWidth == pixelWidth &&
389-
mCachedViewHeight == pixelHeight )
387+
// Can we reuse the previously cached coverage?
388+
if ( !mCachedGdalDataset ||
389+
mCachedViewExtent != viewExtent ||
390+
mCachedViewWidth != pixelWidth ||
391+
mCachedViewHeight != pixelHeight )
390392
{
391-
//return mCachedImage;
393+
getCache( bandNo, viewExtent, pixelWidth, pixelHeight );
392394
}
393395

394-
getCache( bandNo, viewExtent, pixelWidth, pixelHeight );
395-
396396
if ( mCachedGdalDataset )
397397
{
398398
// TODO band
@@ -408,17 +408,22 @@ void QgsWcsProvider::readBlock( int bandNo, QgsRectangle const & viewExtent, in
408408
}
409409
else
410410
{
411-
QgsDebugMsg( tr( "Recieved coverage has wrong size" ) );
411+
QgsMessageLog::logMessage( tr( "Received coverage has wrong size" ), tr( "WCS" ) );
412412
return;
413413
}
414414
}
415415
}
416416

417417
void QgsWcsProvider::getCache( int bandNo, QgsRectangle const & viewExtent, int pixelWidth, int pixelHeight )
418418
{
419+
QgsDebugMsg( "Entered" );
419420
// delete cached data
420421
clearCache();
421422

423+
mCachedViewExtent = viewExtent;
424+
mCachedViewWidth = pixelWidth;
425+
mCachedViewHeight = pixelHeight;
426+
422427
// --------------- BOUNDING BOX --------------------------------
423428
//according to the WCS spec for 1.1, some CRS have inverted axis
424429
// box:
@@ -1484,6 +1489,105 @@ QString QgsWcsProvider::metadata()
14841489
return metadata;
14851490
}
14861491

1492+
bool QgsWcsProvider::identify( const QgsPoint& thePoint, QMap<QString, QString>& theResults )
1493+
{
1494+
QgsDebugMsg( "Entered" );
1495+
theResults.clear();
1496+
1497+
if ( !extent().contains( thePoint ) )
1498+
{
1499+
// Outside the raster
1500+
for ( int i = 1; i <= bandCount(); i++ )
1501+
{
1502+
theResults[ generateBandName( i )] = tr( "out of extent" );
1503+
}
1504+
return true;
1505+
}
1506+
1507+
// It would be nice to use last cached block if possible, unfortunately we don't know
1508+
// at which resolution identify() is called. It may happen, that user zoomed in with
1509+
// layer switched off, canvas resolution increased, but provider cache was not refreshed.
1510+
// In that case the resolution is too low and identify() could give wron results.
1511+
// So we have to read always a block of data around the point on highest resolution
1512+
// if not already cached.
1513+
// TODO: change provider identify() prototype to pass also the resolution
1514+
1515+
int width, height;
1516+
if ( mHasSize )
1517+
{
1518+
width = mWidth;
1519+
height = mHeight;
1520+
}
1521+
else
1522+
{
1523+
// Bad in any case, either not precise or too much data requests
1524+
width = height = 1000;
1525+
}
1526+
double xRes = mCoverageExtent.width() / width;
1527+
double yRes = mCoverageExtent.height() / height;
1528+
1529+
if ( !mCachedGdalDataset ||
1530+
!mCachedViewExtent.contains( thePoint ) ||
1531+
mCachedViewWidth == 0 || mCachedViewHeight == 0 ||
1532+
mCachedViewExtent.width() / mCachedViewWidth - xRes > TINY_VALUE ||
1533+
mCachedViewExtent.height() / mCachedViewHeight - yRes > TINY_VALUE )
1534+
{
1535+
int half = 50;
1536+
QgsRectangle extent( thePoint.x() - xRes * half, thePoint.y() - yRes * half,
1537+
thePoint.x() + xRes * half, thePoint.y() + yRes * half );
1538+
getCache( 1, extent, 2*half, 2*half );
1539+
1540+
}
1541+
1542+
if ( !mCachedGdalDataset ||
1543+
!mCachedViewExtent.contains( thePoint ) )
1544+
{
1545+
return false; // should not happen
1546+
}
1547+
1548+
double x = thePoint.x();
1549+
double y = thePoint.y();
1550+
1551+
// Calculate the row / column where the point falls
1552+
xRes = ( mCachedViewExtent.xMaximum() - mCachedViewExtent.xMinimum() ) / mCachedViewWidth;
1553+
yRes = ( mCachedViewExtent.yMaximum() - mCachedViewExtent.yMinimum() ) / mCachedViewHeight;
1554+
1555+
// Offset, not the cell index -> flor
1556+
int col = ( int ) floor(( x - mCachedViewExtent.xMinimum() ) / xRes );
1557+
int row = ( int ) floor(( mCachedViewExtent.yMaximum() - y ) / yRes );
1558+
1559+
QgsDebugMsg( "row = " + QString::number( row ) + " col = " + QString::number( col ) );
1560+
1561+
for ( int i = 1; i <= GDALGetRasterCount( mCachedGdalDataset ); i++ )
1562+
{
1563+
GDALRasterBandH gdalBand = GDALGetRasterBand( mCachedGdalDataset, i );
1564+
double value;
1565+
1566+
CPLErr err = GDALRasterIO( gdalBand, GF_Read, col, row, 1, 1,
1567+
&value, 1, 1, GDT_Float64, 0, 0 );
1568+
1569+
if ( err != CPLE_None )
1570+
{
1571+
QgsLogger::warning( "RasterIO error: " + QString::fromUtf8( CPLGetLastErrorMsg() ) );
1572+
}
1573+
1574+
QString v;
1575+
1576+
if ( mValidNoDataValue && ( fabs( value - mNoDataValue[i-1] ) <= TINY_VALUE || value != value ) )
1577+
{
1578+
v = tr( "null (no data)" );
1579+
}
1580+
else
1581+
{
1582+
v.setNum( value );
1583+
}
1584+
1585+
theResults[ generateBandName( i )] = v;
1586+
}
1587+
1588+
return true;
1589+
}
1590+
14871591
QString QgsWcsProvider::identifyAsText( const QgsPoint &point )
14881592
{
14891593
Q_UNUSED( point );

src/providers/wcs/qgswcsprovider.h

+1
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,7 @@ class QgsWcsProvider : public QgsRasterDataProvider
149149
int xSize() const;
150150
int ySize() const;
151151
QString metadata();
152+
bool identify( const QgsPoint& thePoint, QMap<QString, QString>& theResults );
152153
QString identifyAsHtml( const QgsPoint& point );
153154
QString identifyAsText( const QgsPoint& point );
154155
QString lastErrorTitle();

0 commit comments

Comments
 (0)