Skip to content
Permalink
Browse files
Partial fix for #9196 - better handling of bounding boxes of WMS layers
Do not use WGS84 bounding box for all layers - instead use either bounding box
as declared in capabilities document for requested CRS, or make best effort
to get bounding box from WGS84 bounding box.
  • Loading branch information
wonder-sk committed Jan 29, 2014
1 parent 7a9e682 commit ba0a6378039d5ffa3cc9fda3749c21f1c4a51c63
Showing with 92 additions and 57 deletions.
  1. +87 −52 src/providers/wms/qgswmsprovider.cpp
  2. +5 −5 src/providers/wms/qgswmsprovider.h
@@ -2566,28 +2566,6 @@ void QgsWmsProvider::parseLayer( QDomElement const & e, QgsWmsLayerProperty& lay
// can be combined with others later in supportedCrsForLayers()
mCrsForLayer[ layerProperty.name ] = layerProperty.crs;

// Store the WGS84 (CRS:84) extent so that it can be combined with others later
// in calculateExtent()

// Apply the coarse bounding box first
mExtentForLayer[ layerProperty.name ] = layerProperty.ex_GeographicBoundingBox;

// see if we can refine the bounding box with the CRS-specific bounding boxes
for ( int i = 0; i < layerProperty.boundingBox.size(); i++ )
{
QgsDebugMsg( "testing bounding box CRS which is "
+ layerProperty.boundingBox[i].crs + "." );

if ( layerProperty.boundingBox[i].crs == DEFAULT_LATLON_CRS )
{
mExtentForLayer[ layerProperty.name ] = layerProperty.boundingBox[i].box;
}
}

QgsDebugMsg( "extent for "
+ layerProperty.name + " is "
+ mExtentForLayer[ layerProperty.name ].toString( 3 ) + "." );

// Insert into the local class' registry
mLayersSupported.push_back( layerProperty );

@@ -2613,6 +2591,88 @@ void QgsWmsProvider::parseLayer( QDomElement const & e, QgsWmsLayerProperty& lay
QgsDebugMsg( "exiting." );
}


static const QgsWmsLayerProperty* _findNestedLayerProperty( const QString& layerName, const QgsWmsLayerProperty* prop )
{
if ( prop->name == layerName )
return prop;

foreach ( const QgsWmsLayerProperty& child, prop->layer )
{
if ( const QgsWmsLayerProperty* res = _findNestedLayerProperty( layerName, &child ) )
return res;
}

return 0;
}


bool QgsWmsProvider::extentForNonTiledLayer( const QString& layerName, const QString& crs, QgsRectangle& extent )
{
const QgsWmsLayerProperty* layerProperty = _findNestedLayerProperty( layerName, &mCapabilities.capability.layer );
if ( !layerProperty )
return false;

// see if we can refine the bounding box with the CRS-specific bounding boxes
for ( int i = 0; i < layerProperty->boundingBox.size(); i++ )
{
if ( layerProperty->boundingBox[i].crs == crs )
{
// exact bounding box is provided for this CRS
extent = layerProperty->boundingBox[i].box;
return true;
}
}

// exact bounding box for given CRS is not listed - we need to pick a different
// bounding box definition - either the coarse bounding box (in WGS84)
// or one of the alternative bounding box definitions for the layer

// Use the coarse bounding box
extent = layerProperty->ex_GeographicBoundingBox;

for ( int i = 0; i < layerProperty->boundingBox.size(); i++ )
{
if ( layerProperty->boundingBox[i].crs == DEFAULT_LATLON_CRS )
{
if ( layerProperty->boundingBox[i].box.contains( extent ) )
continue; // this bounding box is less specific (probably inherited from parent)

// this BBox is probably better than the one in ex_GeographicBoundingBox
extent = layerProperty->boundingBox[i].box;
break;
}
}

// transform it to requested CRS

QgsCoordinateReferenceSystem dst, wgs;
if ( !wgs.createFromOgcWmsCrs( DEFAULT_LATLON_CRS ) || !dst.createFromOgcWmsCrs( crs ) )
return false;

QgsCoordinateTransform xform( wgs, dst );
QgsDebugMsg( QString("transforming layer extent %1").arg( extent.toString( true ) ) );
try
{
extent = xform.transformBoundingBox( extent );
}
catch ( QgsCsException &cse )
{
Q_UNUSED( cse );
return false;
}
QgsDebugMsg( QString("transformed layer extent %1").arg( extent.toString( true ) ) );

//make sure extent does not contain 'inf' or 'nan'
if ( !extent.isFinite() )
{
return false;
}

return true;
}


void QgsWmsProvider::parseTileSetProfile( QDomElement const &e )
{
QStringList resolutions, layers, styles;
@@ -3376,33 +3436,16 @@ bool QgsWmsProvider::calculateExtent()
++it )
{
QgsDebugMsg( "Sublayer iterator: " + *it );
// This is the extent for the layer name in *it
if ( !mExtentForLayer.contains( *it ) )
{
mLayerExtent = QgsRectangle();
appendError( ERR( tr( "Extent for layer %1 not found in capabilities" ).arg( *it ) ) );
continue;
}

QgsRectangle extent = mExtentForLayer.find( *it ).value();

// Convert to the user's CRS as required
try
{
extent = mCoordinateTransform->transformBoundingBox( extent, QgsCoordinateTransform::ForwardTransform );
}
catch ( QgsCsException &cse )
{
Q_UNUSED( cse );
continue; //ignore extents of layers which cannot be transformed info the required CRS
}

//make sure extent does not contain 'inf' or 'nan'
if ( !extent.isFinite() )
QgsRectangle extent;
if ( !extentForNonTiledLayer( *it, mImageCrs, extent ) )
{
QgsDebugMsg( "extent for " + *it + " is invalid! (ignoring)" );
continue;
}

QgsDebugMsg( "extent for " + *it + " is " + extent.toString( 3 ) + "." );

// add to the combined extent of all the active sublayers
if ( firstLayer )
{
@@ -3572,14 +3615,6 @@ QString QgsWmsProvider::layerMetadata( QgsWmsLayerProperty &layer )
metadata += QString::number( layer.fixedHeight );
metadata += "</td></tr>";

// Layer Fixed Height
metadata += "<tr><td>";
metadata += tr( "WGS 84 Bounding Box" );
metadata += "</td>";
metadata += "<td>";
metadata += mExtentForLayer[ layer.name ].toString();
metadata += "</td></tr>";

// Layer Coordinate Reference Systems
for ( int j = 0; j < qMin( layer.crs.size(), 10 ); j++ )
{
@@ -778,6 +778,11 @@ class QgsWmsProvider : public QgsRasterDataProvider
private:
void showMessageBox( const QString& title, const QString& text );

/**
* Try to get best extent for the layer in given CRS. Returns true on success, false otherwise (layer not found, invalid CRS, transform failed)
*/
bool extentForNonTiledLayer( const QString& layerName, const QString& crs, QgsRectangle& extent );

// case insensitive attribute value lookup
static QString nodeAttribute( const QDomElement &e, QString name, QString defValue = QString::null );

@@ -996,11 +1001,6 @@ class QgsWmsProvider : public QgsRasterDataProvider
*/
QList<QgsWmtsTheme> mTileThemes;

/**
* extents per layer (in WMS CRS:84 datum)
*/
QMap<QString, QgsRectangle> mExtentForLayer;

/**
* available CRSs per layer
*/

0 comments on commit ba0a637

Please sign in to comment.