Skip to content

Commit 8a1ad57

Browse files
committed
wcs 1.1 axis switch fix
1 parent 8349d52 commit 8a1ad57

File tree

3 files changed

+87
-29
lines changed

3 files changed

+87
-29
lines changed

src/providers/wcs/qgswcscapabilities.cpp

+11-1
Original file line numberDiff line numberDiff line change
@@ -919,8 +919,18 @@ bool QgsWcsCapabilities::parseDescribeCoverageDom11( QByteArray const &xml, QgsW
919919
}
920920
else
921921
{
922-
QgsRectangle box( low[0], low[1], high[0], high[1] ) ;
922+
QgsRectangle box;
923+
QgsCoordinateReferenceSystem crs;
924+
if ( crs.createFromOgcWmsCrs( authid ) && crs.axisInverted() )
925+
{
926+
box = QgsRectangle( low[1], low[0], high[1], high[0] );
927+
}
928+
else
929+
{
930+
box = QgsRectangle( low[0], low[1], high[0], high[1] );
931+
}
923932
coverage->boundingBoxes.insert( authid, box );
933+
QgsDebugMsg( "crs: " + crs.authid() + " " + crs.description() + QString( " axisInverted = %1" ).arg( crs.axisInverted() ) );
924934
QgsDebugMsg( "BoundingBox: " + authid + " : " + box.toString() );
925935
}
926936
}

src/providers/wcs/qgswcsprovider.cpp

+60-27
Original file line numberDiff line numberDiff line change
@@ -259,8 +259,9 @@ QgsWcsProvider::QgsWcsProvider( QString const &uri )
259259
mFixBox = true;
260260
QgsDebugMsg( "Test response size is smaller by pixel, using mFixBox" );
261261
}
262-
// Geoserver is sometimes giving rotated raster (probably for geographic CRS,
263-
// switched axis?)
262+
// Geoserver is giving rotated raster for geographic CRS - switched axis,
263+
// Geoserver developers argue that changed axis order applies also to
264+
// returned raster, that is exagerated IMO but we have to handle that.
264265
if (( responseWidth == requestHeight && responseHeight == requestWidth ) ||
265266
( responseWidth == requestHeight - 1 && responseHeight == requestWidth - 1 ) )
266267
{
@@ -546,33 +547,47 @@ void QgsWcsProvider::readBlock( int bandNo, QgsRectangle const & viewExtent, in
546547

547548
if ( mCachedGdalDataset )
548549
{
549-
int width = GDALGetRasterXSize( mCachedGdalDataset );
550-
int height = GDALGetRasterYSize( mCachedGdalDataset );
551-
552550
// It may happen (Geoserver) that if requested BBOX is larger than coverage
553551
// extent, the returned data cover intersection of requested BBOX and coverage
554552
// extent scaled to requested WIDTH/HEIGHT => check extent
553+
// Unfortunately if received raster does not hac CRS, the extent is raster size
554+
// and in that case it cannot be used to verify extent
555+
QgsCoordinateReferenceSystem cacheCrs;
556+
if ( !cacheCrs.createFromWkt( GDALGetProjectionRef( mCachedGdalDataset ) ) &&
557+
!cacheCrs.createFromWkt( GDALGetGCPProjection( mCachedGdalDataset ) ) )
558+
{
559+
QgsDebugMsg( "Cached does not have CRS" );
560+
}
561+
QgsDebugMsg( "Cache CRS: " + cacheCrs.authid() + " " + cacheCrs.description() );
562+
555563
QgsRectangle cacheExtent = QgsGdalProviderBase::extent( mCachedGdalDataset );
556564
QgsDebugMsg( "viewExtent = " + viewExtent.toString() );
557565
QgsDebugMsg( "cacheExtent = " + cacheExtent.toString() );
558-
// using doubleNear is too precise, example accetable difference:
559-
// 179.9999999306699863 x 179.9999999306700431
560-
if ( !doubleNearSig( cacheExtent.xMinimum(), viewExtent.xMinimum(), 10 ) ||
561-
!doubleNearSig( cacheExtent.yMinimum(), viewExtent.yMinimum(), 10 ) ||
562-
!doubleNearSig( cacheExtent.xMaximum(), viewExtent.xMaximum(), 10 ) ||
563-
!doubleNearSig( cacheExtent.yMaximum(), viewExtent.yMaximum(), 10 ) )
566+
// TODO: check also rotated
567+
if ( cacheCrs.isValid() && !mFixRotate )
564568
{
565-
QgsDebugMsg( "cacheExtent and viewExtent differ" );
566-
QgsMessageLog::logMessage( tr( "Received coverage has wrong extent %1 (expected %2)" ).arg( cacheExtent.toString() ).arg( viewExtent.toString() ), tr( "WCS" ) );
567-
// We are doing all possible to avoid this situation,
568-
// If it happens, it would be possible to rescale the portion we get
569-
// to only part of the data block, but it is better to left it
570-
// blank, so that the problem may be discovered in its origin.
571-
return;
569+
// using doubleNear is too precise, example accetable difference:
570+
// 179.9999999306699863 x 179.9999999306700431
571+
if ( !doubleNearSig( cacheExtent.xMinimum(), viewExtent.xMinimum(), 10 ) ||
572+
!doubleNearSig( cacheExtent.yMinimum(), viewExtent.yMinimum(), 10 ) ||
573+
!doubleNearSig( cacheExtent.xMaximum(), viewExtent.xMaximum(), 10 ) ||
574+
!doubleNearSig( cacheExtent.yMaximum(), viewExtent.yMaximum(), 10 ) )
575+
{
576+
QgsDebugMsg( "cacheExtent and viewExtent differ" );
577+
QgsMessageLog::logMessage( tr( "Received coverage has wrong extent %1 (expected %2)" ).arg( cacheExtent.toString() ).arg( viewExtent.toString() ), tr( "WCS" ) );
578+
// We are doing all possible to avoid this situation,
579+
// If it happens, it would be possible to rescale the portion we get
580+
// to only part of the data block, but it is better to left it
581+
// blank, so that the problem may be discovered in its origin.
582+
return;
583+
}
572584
}
573585

574-
GDALRasterBandH gdalBand = GDALGetRasterBand( mCachedGdalDataset, bandNo );
586+
int width = GDALGetRasterXSize( mCachedGdalDataset );
587+
int height = GDALGetRasterYSize( mCachedGdalDataset );
575588
QgsDebugMsg( QString( "cached data width = %1 height = %2 (expected %3 x %4)" ).arg( width ).arg( height ).arg( pixelWidth ).arg( pixelHeight ) );
589+
590+
GDALRasterBandH gdalBand = GDALGetRasterBand( mCachedGdalDataset, bandNo );
576591
// TODO: check type? , check band count?
577592
if ( mFixRotate && width == pixelHeight && height == pixelWidth )
578593
{
@@ -742,12 +757,16 @@ void QgsWcsProvider::getCache( int bandNo, QgsRectangle const & viewExtent, int
742757
// GridOffsets WCS 1.1:
743758
// GridType urn:ogc:def:method:WCS:1.1:2dSimpleGrid : 2 values
744759
// GridType urn:ogc:def:method:WCS:1.1:2dGridIn2dCrs : 4 values, the center two of these offsets will be zero when the GridCRS is not rotated or skewed in the GridBaseCRS.
745-
// The second offset must be negative because origin is in upper corner
760+
// The yOff must be negative because origin is in upper corner
746761
// WCS 1.1.2: BaseX = origin(1) + offsets(1) * GridX
747762
// BaseY = origin(2) + offsets(2) * GridY
748763
// otherwise GeoServer gives mirrored result, however
749764
// Mapserver works OK with both positive and negative
750-
double yOff = mFixRotate ? yRes : -yRes;
765+
// OTOH, the yOff offset must not be negative with mFixRotate and Geoserver 2.1-SNAPSHOT
766+
// but it must be negative with GeoServer 2.1.3 and mFixRotate. I am not sure
767+
// at this moment 100% -> disabling positive yOff for now - TODO: try other servers
768+
//double yOff = mFixRotate ? yRes : -yRes; // this was working with some servers I think
769+
double yOff = -yRes;
751770
QString gridOffsets = QString( changeXY ? "%2,%1" : "%1,%2" )
752771
//setQueryItem( url, "GRIDTYPE", "urn:ogc:def:method:WCS:1.1:2dGridIn2dCrs" );
753772
//QString gridOffsets = QString( changeXY ? "%2,0,0,%1" : "%1,0,0,%2" )
@@ -1426,13 +1445,27 @@ bool QgsWcsProvider::calculateExtent()
14261445
QgsRectangle cacheExtent = QgsGdalProviderBase::extent( mCachedGdalDataset );
14271446
QgsDebugMsg( "mCoverageExtent = " + mCoverageExtent.toString() );
14281447
QgsDebugMsg( "cacheExtent = " + cacheExtent.toString() );
1429-
if ( !doubleNearSig( cacheExtent.xMinimum(), mCoverageExtent.xMinimum(), 10 ) ||
1430-
!doubleNearSig( cacheExtent.yMinimum(), mCoverageExtent.yMinimum(), 10 ) ||
1431-
!doubleNearSig( cacheExtent.xMaximum(), mCoverageExtent.xMaximum(), 10 ) ||
1432-
!doubleNearSig( cacheExtent.yMaximum(), mCoverageExtent.yMaximum(), 10 ) )
1448+
QgsCoordinateReferenceSystem cacheCrs;
1449+
if ( !cacheCrs.createFromWkt( GDALGetProjectionRef( mCachedGdalDataset ) ) &&
1450+
!cacheCrs.createFromWkt( GDALGetGCPProjection( mCachedGdalDataset ) ) )
14331451
{
1434-
QgsDebugMsg( "cacheExtent and mCoverageExtent differ, mCoverageExtent cut to cacheExtent" );
1435-
mCoverageExtent = cacheExtent;
1452+
QgsDebugMsg( "Cached does not have CRS" );
1453+
}
1454+
QgsDebugMsg( "Cache CRS: " + cacheCrs.authid() + " " + cacheCrs.description() );
1455+
1456+
// We can only verify extent if CRS is set
1457+
// If dataset comes rotated, GDAL probably cuts latitude extend, disable
1458+
// extent check for rotated, TODO: verify
1459+
if ( cacheCrs.isValid() && !mFixRotate )
1460+
{
1461+
if ( !doubleNearSig( cacheExtent.xMinimum(), mCoverageExtent.xMinimum(), 10 ) ||
1462+
!doubleNearSig( cacheExtent.yMinimum(), mCoverageExtent.yMinimum(), 10 ) ||
1463+
!doubleNearSig( cacheExtent.xMaximum(), mCoverageExtent.xMaximum(), 10 ) ||
1464+
!doubleNearSig( cacheExtent.yMaximum(), mCoverageExtent.yMaximum(), 10 ) )
1465+
{
1466+
QgsDebugMsg( "cacheExtent and mCoverageExtent differ, mCoverageExtent cut to cacheExtent" );
1467+
mCoverageExtent = cacheExtent;
1468+
}
14361469
}
14371470
}
14381471
else

tests/src/providers/wcs-servers.json

+16-1
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,22 @@
6262
offender: 'server',
6363
coverages: [ 'modis-001' ],
6464
versions: [ '1.0.0' ],
65-
description: "The server DescribeCoverage advertises temporalDomain.timePosition 2002-001, but GetCoverages fails with 'msWCSGetCoverage(): WCS server error. Underlying layer is not tiled, unable to do temporal subsetting.' if TIME=2002-001 is used."
65+
description: "The server DescribeCoverage advertises temporalDomain.timePosition 2002-001, but GetCoverage fails with 'msWCSGetCoverage(): WCS server error. Underlying layer is not tiled, unable to do temporal subsetting.' if TIME=2002-001 is used."
66+
}
67+
]
68+
}, {
69+
url: 'http://geoserver-dev-1.irradiare.com:8080/geoserver/ows',
70+
issues: [
71+
{
72+
offender: 'server',
73+
versions: [ '1.0.0' ],
74+
description: "The server fails in GetCapabilities with 'java.io.IOException
75+
null Translator error No input stream for the provided source...'"
76+
},{
77+
offender: 'server',
78+
coverages: [ 'Arc_Sample' ],
79+
versions: [ '1.1.1' ],
80+
description: "The problem seems to be that some versions of Geoserver (2.1.3) require latitude in GRIDOFFSETS to be negative and other versions (2.1-SNAPSHOT) positive. BTW: GetCoverage returns raster without CRS and thues the extent means raster size and cannot be used to verify extent"
6681
}
6782
]
6883
}, {

0 commit comments

Comments
 (0)