Skip to content

Commit

Permalink
[wms] If an explicit CRS is not set in a layer's URI, then take the
Browse files Browse the repository at this point in the history
first sensible CRS advertised by the provider's capabilities as the
layer's CRS

Avoids the messy situation where a WMS layer requires a valid CRS
to be set, yet QGIS provides no public API to retrieve the available
CRS for WMS layers. WIthout this fix it's necessary for plugins
to manually write their own capabilities parsing code in order to
retrieve the available CRSes for a service... ouch!
  • Loading branch information
nyalldawson committed Aug 10, 2020
1 parent 68e8e23 commit c7c38e1
Show file tree
Hide file tree
Showing 5 changed files with 353 additions and 0 deletions.
18 changes: 18 additions & 0 deletions src/providers/wms/qgswmscapabilities.h
Expand Up @@ -367,6 +367,24 @@ struct QgsWmsLayerProperty

return false;
}

/**
* Attempts to return a preferred CRS from the list of available CRS definitions.
*
* Prioritises the first listed CRS, unless it's a block listed value.
*/
QString preferredAvailableCrs() const
{
static QSet< QString > sSkipList { QStringLiteral( "EPSG:900913" ) };
for ( const QString &candidate : crs )
{
if ( sSkipList.contains( candidate ) )
continue;

return candidate;
}
return crs.value( 0 );
}
};

/**
Expand Down
13 changes: 13 additions & 0 deletions src/providers/wms/qgswmsprovider.cpp
Expand Up @@ -178,6 +178,19 @@ QgsWmsProvider::QgsWmsProvider( QString const &uri, const ProviderOptions &optio
temporalCapabilities()->setAvailableReferenceTemporalRange( mSettings.mFixedReferenceRange );
}
}

if ( mSettings.mCrsId.isEmpty() && !mSettings.mActiveSubLayers.empty() )
{
// if crs not specified via layer uri, use the first available from server capabilities
for ( const QgsWmsLayerProperty &property : qgis::as_const( mCaps.mLayersSupported ) )
{
if ( property.name == mSettings.mActiveSubLayers[0] )
{
mSettings.mCrsId = property.preferredAvailableCrs();
break;
}
}
}
}

// setImageCrs is using mTiled !!!
Expand Down
17 changes: 17 additions & 0 deletions tests/src/providers/testqgswmscapabilities.cpp
Expand Up @@ -79,6 +79,23 @@ class TestQgsWmsCapabilities: public QObject
QString( "http://www.example.com/fb.png" ) );
}

void guessCrs()
{
QgsWmsCapabilities capabilities;

QFile file( QStringLiteral( TEST_DATA_DIR ) + "/provider/GetCapabilities2.xml" );
QVERIFY( file.open( QIODevice::ReadOnly | QIODevice::Text ) );
const QByteArray content = file.readAll();
QVERIFY( content.size() > 0 );
const QgsWmsParserSettings config;

QVERIFY( capabilities.parseResponse( content, config ) );
QCOMPARE( capabilities.supportedLayers().size(), 5 );

QCOMPARE( capabilities.supportedLayers().at( 0 ).preferredAvailableCrs(), QStringLiteral( "EPSG:3857" ) );

}

void wmstSettings()
{
QgsWmsSettings settings = QgsWmsSettings();
Expand Down
21 changes: 21 additions & 0 deletions tests/src/providers/testqgswmsprovider.cpp
Expand Up @@ -101,6 +101,27 @@ class TestQgsWmsProvider: public QObject
"STYLES=&FORMAT=&TRANSPARENT=TRUE" ) );
}

void noCrsSpecified()
{
QgsWmsProvider provider( QStringLiteral( "http://localhost:8380/mapserv?xxx&layers=agri_zones&styles=&format=image/jpg" ), QgsDataProvider::ProviderOptions(), mCapabilities );
QCOMPARE( provider.crs().authid(), QStringLiteral( "EPSG:2056" ) );
QgsWmsProvider provider2( QStringLiteral( "http://localhost:8380/mapserv?xxx&layers=agri_zones&styles=&format=image/jpg&crs=EPSG:4326" ), QgsDataProvider::ProviderOptions(), mCapabilities );
QCOMPARE( provider2.crs().authid(), QStringLiteral( "EPSG:4326" ) );

QFile file( QStringLiteral( TEST_DATA_DIR ) + "/provider/GetCapabilities2.xml" );
QVERIFY( file.open( QIODevice::ReadOnly | QIODevice::Text ) );
const QByteArray content = file.readAll();
QVERIFY( content.size() > 0 );
const QgsWmsParserSettings config;

QgsWmsCapabilities capabilities;
QVERIFY( capabilities.parseResponse( content, config ) );
QgsWmsProvider provider3( QStringLiteral( "http://localhost:8380/mapserv?xxx&layers=agri_zones&styles=&format=image/jpg&crs=EPSG:4326" ), QgsDataProvider::ProviderOptions(), &capabilities );
QCOMPARE( provider3.crs().authid(), QStringLiteral( "EPSG:4326" ) );
QgsWmsProvider provider4( QStringLiteral( "http://localhost:8380/mapserv?xxx&layers=agri_zones&styles=&format=image/jpg" ), QgsDataProvider::ProviderOptions(), &capabilities );
QCOMPARE( provider4.crs().authid(), QStringLiteral( "EPSG:3857" ) );
}

void testMBTiles()
{
QString dataDir( TEST_DATA_DIR );
Expand Down
284 changes: 284 additions & 0 deletions tests/testdata/provider/GetCapabilities2.xml
@@ -0,0 +1,284 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<WMS_Capabilities version="1.3.0" xmlns="http://www.opengis.net/wms" xmlns:sld="http://www.opengis.net/sld" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:ms="http://mapserver.gis.umn.edu/mapserver" xsi:schemaLocation="http://www.opengis.net/wms http://schemas.opengis.net/wms/1.3.0/capabilities_1_3_0.xsd http://www.opengis.net/sld http://schemas.opengis.net/sld/1.1.0/sld_capabilities.xsd http://mapserver.gis.umn.edu/mapserver http://localhost:8380/mapserv?service=WMS&amp;version=1.3.0&amp;request=GetSchemaExtension">
<!-- MapServer version 7.0.1 OUTPUT=PNG OUTPUT=JPEG OUTPUT=KML SUPPORTS=PROJ SUPPORTS=AGG SUPPORTS=FREETYPE SUPPORTS=CAIRO SUPPORTS=SVG_SYMBOLS SUPPORTS=RSVG SUPPORTS=ICONV SUPPORTS=FRIBIDI SUPPORTS=WMS_SERVER SUPPORTS=WMS_CLIENT SUPPORTS=WFS_SERVER SUPPORTS=WFS_CLIENT SUPPORTS=WCS_SERVER SUPPORTS=SOS_SERVER SUPPORTS=FASTCGI SUPPORTS=THREADS SUPPORTS=GEOS INPUT=JPEG INPUT=POSTGIS INPUT=OGR INPUT=GDAL INPUT=SHAPEFILE -->
<Service>
<Name>WMS</Name>
<Title>Test</Title>
<Abstract>Test</Abstract>
<OnlineResource xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="http://localhost:8380/mapserv?"/>
<ContactInformation>
</ContactInformation>
<MaxWidth>5000</MaxWidth>
<MaxHeight>5000</MaxHeight>
</Service>

<Capability>
<Request>
<GetCapabilities>
<Format>text/xml</Format>
<DCPType>
<HTTP>
<Get><OnlineResource xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="http://localhost:8380/mapserv?"/></Get>
<Post><OnlineResource xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="http://localhost:8380/mapserv?"/></Post>
</HTTP>
</DCPType>
</GetCapabilities>
<GetMap>
<Format>image/jpeg</Format>
<Format>image/png</Format>
<DCPType>
<HTTP>
<Get><OnlineResource xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="http://localhost:8380/mapserv?"/></Get>
<Post><OnlineResource xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="http://localhost:8380/mapserv?"/></Post>
</HTTP>
</DCPType>
</GetMap>
<GetFeatureInfo>
<Format>text/plain</Format>
<Format>application/vnd.ogc.gml</Format>
<DCPType>
<HTTP>
<Get><OnlineResource xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="http://localhost:8380/mapserv?"/></Get>
<Post><OnlineResource xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="http://localhost:8380/mapserv?"/></Post>
</HTTP>
</DCPType>
</GetFeatureInfo>
<sld:DescribeLayer>
<Format>text/xml</Format>
<DCPType>
<HTTP>
<Get><OnlineResource xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="http://localhost:8380/mapserv?"/></Get>
<Post><OnlineResource xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="http://localhost:8380/mapserv?"/></Post>
</HTTP>
</DCPType>
</sld:DescribeLayer>
<sld:GetLegendGraphic>
<Format>image/jpeg</Format>
<Format>image/png</Format>
<Format>image/png; mode=8bit</Format>
<DCPType>
<HTTP>
<Get><OnlineResource xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="http://localhost:8380/mapserv?"/></Get>
<Post><OnlineResource xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="http://localhost:8380/mapserv?"/></Post>
</HTTP>
</DCPType>
</sld:GetLegendGraphic>
<ms:GetStyles>
<Format>text/xml</Format>
<DCPType>
<HTTP>
<Get><OnlineResource xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="http://localhost:8380/mapserv?"/></Get>
<Post><OnlineResource xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="http://localhost:8380/mapserv?"/></Post>
</HTTP>
</DCPType>
</ms:GetStyles>
</Request>
<Exception>
<Format>XML</Format>
<Format>BLANK</Format>
</Exception>
<sld:UserDefinedSymbolization SupportSLD="1" UserLayer="0" UserStyle="1" RemoteWFS="0" InlineFeature="0" RemoteWCS="0"/>
<Layer>
<Name>test</Name>
<Title>Test</Title>
<Abstract>Test</Abstract>
<CRS>EPSG:900913</CRS>
<CRS>EPSG:3857</CRS>
<CRS>EPSG:25832</CRS>
<CRS>EPSG:25833</CRS>
<CRS>EPSG:29192</CRS>
<CRS>EPSG:29193</CRS>
<CRS>EPSG:31466</CRS>
<CRS>EPSG:31467</CRS>
<CRS>EPSG:31468</CRS>
<CRS>EPSG:32648</CRS>
<CRS>EPSG:4326</CRS>
<CRS>EPSG:4674</CRS>
<CRS>EPSG:3068</CRS>
<CRS>EPSG:3034</CRS>
<CRS>EPSG:3035</CRS>
<CRS>EPSG:2100</CRS>
<CRS>EPSG:31463</CRS>
<CRS>EPSG:4258</CRS>
<CRS>EPSG:4839</CRS>
<CRS>EPSG:2180</CRS>
<CRS>EPSG:21781</CRS>
<CRS>EPSG:2056</CRS>
<CRS>EPSG:4647</CRS>
<CRS>EPSG:4686</CRS>
<CRS>EPSG:5243</CRS>
<EX_GeographicBoundingBox>
<westBoundLongitude>5.01393</westBoundLongitude>
<eastBoundLongitude>11.4774</eastBoundLongitude>
<southBoundLatitude>45.356</southBoundLatitude>
<northBoundLatitude>48.3001</northBoundLatitude>
</EX_GeographicBoundingBox>
<BoundingBox CRS="EPSG:2056" minx="2.42e+06" miny="1.03e+06" maxx="2.9e+06" maxy="1.35e+06"/>
<Layer queryable="1" opaque="0" cascaded="0">
<Name>agri_zones</Name>
<Title>agri_zones</Title>
<CRS>EPSG:900913</CRS>
<CRS>EPSG:3857</CRS>
<CRS>EPSG:25832</CRS>
<CRS>EPSG:25833</CRS>
<CRS>EPSG:29192</CRS>
<CRS>EPSG:29193</CRS>
<CRS>EPSG:31466</CRS>
<CRS>EPSG:31467</CRS>
<CRS>EPSG:31468</CRS>
<CRS>EPSG:32648</CRS>
<CRS>EPSG:4326</CRS>
<CRS>EPSG:4674</CRS>
<CRS>EPSG:3068</CRS>
<CRS>EPSG:3034</CRS>
<CRS>EPSG:3035</CRS>
<CRS>EPSG:2100</CRS>
<CRS>EPSG:31463</CRS>
<CRS>EPSG:4258</CRS>
<CRS>EPSG:4839</CRS>
<CRS>EPSG:2180</CRS>
<CRS>EPSG:21781</CRS>
<CRS>EPSG:2056</CRS>
<CRS>EPSG:4647</CRS>
<CRS>EPSG:4686</CRS>
<CRS>EPSG:5243</CRS>
<EX_GeographicBoundingBox>
<westBoundLongitude>5.01393</westBoundLongitude>
<eastBoundLongitude>11.4774</eastBoundLongitude>
<southBoundLatitude>45.356</southBoundLatitude>
<northBoundLatitude>48.3001</northBoundLatitude>
</EX_GeographicBoundingBox>
<BoundingBox CRS="EPSG:2056" minx="2.42e+06" miny="1.03e+06" maxx="2.9e+06" maxy="1.35e+06"/>
<MetadataURL type="TC211">
<Format>text/html</Format>
<OnlineResource xmlns:xlink="http://www.w3.org/1999/xlink" xlink:type="simple" xlink:href="http://www.example.com/bar"/>
</MetadataURL>
<Style>
<Name>yt_style</Name>
<Title>yt_style</Title>
<LegendURL width="23" height="19">
<Format>image/png</Format>
<OnlineResource xmlns:xlink="http://www.w3.org/1999/xlink" xlink:type="simple" xlink:href="http://www.example.com/yt.png"/>
</LegendURL>
</Style>
<Style>
<Name>fb_style</Name>
<Title>fb_style</Title>
<LegendURL width="23" height="19">
<Format>image/png</Format>
<OnlineResource xmlns:xlink="http://www.w3.org/1999/xlink" xlink:type="simple" xlink:href="http://www.example.com/fb.png"/>
</LegendURL>
</Style>
</Layer>
<Layer>
<Name>cadastre</Name>
<Title>cadastre</Title>
<Abstract>cadastre</Abstract>
<Style>
<Name>default</Name>
<Title>default</Title>
<LegendURL width="88" height="50">
<Format>image/png</Format>
<OnlineResource xmlns:xlink="http://www.w3.org/1999/xlink" xlink:type="simple" xlink:href="http://localhost:8380/mapserv?version=1.3.0&amp;service=WMS&amp;request=GetLegendGraphic&amp;sld_version=1.1.0&amp;layer=cadastre&amp;format=image/png&amp;STYLE=default"/>
</LegendURL>
</Style>
<Layer queryable="1" opaque="0" cascaded="0">
<Name>buildings</Name>
<Title>buildings</Title>
<CRS>EPSG:900913</CRS>
<CRS>EPSG:3857</CRS>
<CRS>EPSG:25832</CRS>
<CRS>EPSG:25833</CRS>
<CRS>EPSG:29192</CRS>
<CRS>EPSG:29193</CRS>
<CRS>EPSG:31466</CRS>
<CRS>EPSG:31467</CRS>
<CRS>EPSG:31468</CRS>
<CRS>EPSG:32648</CRS>
<CRS>EPSG:4326</CRS>
<CRS>EPSG:4674</CRS>
<CRS>EPSG:3068</CRS>
<CRS>EPSG:3034</CRS>
<CRS>EPSG:3035</CRS>
<CRS>EPSG:2100</CRS>
<CRS>EPSG:31463</CRS>
<CRS>EPSG:4258</CRS>
<CRS>EPSG:4839</CRS>
<CRS>EPSG:2180</CRS>
<CRS>EPSG:21781</CRS>
<CRS>EPSG:2056</CRS>
<CRS>EPSG:4647</CRS>
<CRS>EPSG:4686</CRS>
<CRS>EPSG:5243</CRS>
<EX_GeographicBoundingBox>
<westBoundLongitude>5.01393</westBoundLongitude>
<eastBoundLongitude>11.4774</eastBoundLongitude>
<southBoundLatitude>45.356</southBoundLatitude>
<northBoundLatitude>48.3001</northBoundLatitude>
</EX_GeographicBoundingBox>
<BoundingBox CRS="EPSG:2056" minx="2.42e+06" miny="1.03e+06" maxx="2.9e+06" maxy="1.35e+06"/>
<MetadataURL type="TC211">
<Format>text/html</Format>
<OnlineResource xmlns:xlink="http://www.w3.org/1999/xlink" xlink:type="simple" xlink:href="http://www.example.com/bar"/>
</MetadataURL>
<Style>
<Name>default</Name>
<Title>default</Title>
<LegendURL width="88" height="20">
<Format>image/png</Format>
<OnlineResource xmlns:xlink="http://www.w3.org/1999/xlink" xlink:type="simple" xlink:href="http://www.example.com/buildings.png"/>
</LegendURL>
</Style>
</Layer>
<Layer queryable="1" opaque="0" cascaded="0">
<Name>land_surveing_parcels</Name>
<Title>land_surveing_parcels</Title>
<CRS>EPSG:900913</CRS>
<CRS>EPSG:3857</CRS>
<CRS>EPSG:25832</CRS>
<CRS>EPSG:25833</CRS>
<CRS>EPSG:29192</CRS>
<CRS>EPSG:29193</CRS>
<CRS>EPSG:31466</CRS>
<CRS>EPSG:31467</CRS>
<CRS>EPSG:31468</CRS>
<CRS>EPSG:32648</CRS>
<CRS>EPSG:4326</CRS>
<CRS>EPSG:4674</CRS>
<CRS>EPSG:3068</CRS>
<CRS>EPSG:3034</CRS>
<CRS>EPSG:3035</CRS>
<CRS>EPSG:2100</CRS>
<CRS>EPSG:31463</CRS>
<CRS>EPSG:4258</CRS>
<CRS>EPSG:4839</CRS>
<CRS>EPSG:2180</CRS>
<CRS>EPSG:21781</CRS>
<CRS>EPSG:2056</CRS>
<CRS>EPSG:4647</CRS>
<CRS>EPSG:4686</CRS>
<CRS>EPSG:5243</CRS>
<EX_GeographicBoundingBox>
<westBoundLongitude>5.01393</westBoundLongitude>
<eastBoundLongitude>11.4774</eastBoundLongitude>
<southBoundLatitude>45.356</southBoundLatitude>
<northBoundLatitude>48.3001</northBoundLatitude>
</EX_GeographicBoundingBox>
<BoundingBox CRS="EPSG:2056" minx="2.42e+06" miny="1.03e+06" maxx="2.9e+06" maxy="1.35e+06"/>
<MetadataURL type="TC211">
<Format>text/html</Format>
<OnlineResource xmlns:xlink="http://www.w3.org/1999/xlink" xlink:type="simple" xlink:href="http://www.example.com/bar"/>
</MetadataURL>
<Style>
<Name>default</Name>
<Title>default</Title>
<LegendURL width="84" height="20">
<Format>image/png</Format>
<OnlineResource xmlns:xlink="http://www.w3.org/1999/xlink" xlink:type="simple" xlink:href="http://localhost:8380/mapserv?version=1.3.0&amp;service=WMS&amp;request=GetLegendGraphic&amp;sld_version=1.1.0&amp;layer=land_surveing_parcels&amp;format=image/png&amp;STYLE=default"/>
</LegendURL>
</Style>
</Layer>
</Layer>
</Layer>
</Capability>
</WMS_Capabilities>

0 comments on commit c7c38e1

Please sign in to comment.