mirror of
https://github.com/qgis/QGIS.git
synced 2025-02-25 00:58:06 -05:00
[FEATURE] Native support for XYZ tile layers
Yes, that means OpenStreetMap tiles and various other sources! No GUI so far...
This commit is contained in:
parent
0c51c3f08d
commit
c4181fa04d
@ -40,6 +40,37 @@ bool QgsWmsSettings::parseUri( const QString& uriString )
|
||||
QgsDataSourceUri uri;
|
||||
uri.setEncodedUri( uriString );
|
||||
|
||||
mXyz = false; // assume WMS / WMTS
|
||||
|
||||
if ( uri.param( "type" ) == "xyz" )
|
||||
{
|
||||
// for XYZ tiles most of the things do not apply
|
||||
mTiled = true;
|
||||
mXyz = true;
|
||||
mTileDimensionValues.clear();
|
||||
mTileMatrixSetId = "tms0";
|
||||
mMaxWidth = 0;
|
||||
mMaxHeight = 0;
|
||||
mHttpUri = uri.param( "url" );
|
||||
mBaseUrl = mHttpUri;
|
||||
mAuth.mUserName.clear();
|
||||
mAuth.mPassword.clear();
|
||||
mAuth.mReferer.clear();
|
||||
mAuth.mAuthCfg.clear();
|
||||
mIgnoreGetMapUrl = false;
|
||||
mIgnoreGetFeatureInfoUrl = false;
|
||||
mSmoothPixmapTransform = false;
|
||||
mDpiMode = dpiNone; // does not matter what we set here
|
||||
mActiveSubLayers = QStringList( "xyz" ); // just a placeholder to have one sub-layer
|
||||
mActiveSubStyles = QStringList( "xyz" ); // just a placeholder to have one sub-style
|
||||
mActiveSubLayerVisibility.clear();
|
||||
mFeatureCount = 0;
|
||||
mImageMimeType.clear();
|
||||
mCrsId = "EPSG:3857";
|
||||
mEnableContextualLegend = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
mTiled = false;
|
||||
mTileDimensionValues.clear();
|
||||
|
||||
|
@ -339,18 +339,20 @@ struct QgsWmtsTileMatrix
|
||||
|
||||
struct QgsWmtsTileMatrixSet
|
||||
{
|
||||
QString identifier;
|
||||
QString title, abstract;
|
||||
QStringList keywords;
|
||||
QString crs;
|
||||
QString wkScaleSet;
|
||||
QString identifier; //!< tile matrix set identifier
|
||||
QString title; //!< human readable tile matrix set name
|
||||
QString abstract; //!< brief description of the tile matrix set
|
||||
QStringList keywords; //!< list of words/phrases to describe the dataset
|
||||
QString crs; //!< CRS of the tile matrix set
|
||||
QString wkScaleSet; //!< optional reference to a well-known scale set
|
||||
//! available tile matrixes (key = pixel span in map units)
|
||||
QMap<double, QgsWmtsTileMatrix> tileMatrices;
|
||||
|
||||
//! Returns closest tile resolution to the requested one. (resolution = width [map units] / with [pixels])
|
||||
const QgsWmtsTileMatrix* findNearestResolution( double vres ) const;
|
||||
};
|
||||
|
||||
enum QgsTileMode { WMTS, WMSC };
|
||||
enum QgsTileMode { WMTS, WMSC, XYZ };
|
||||
|
||||
struct QgsWmtsTileMatrixLimits
|
||||
{
|
||||
@ -382,16 +384,22 @@ struct QgsWmtsStyle
|
||||
QList<QgsWmtsLegendURL> legendURLs;
|
||||
};
|
||||
|
||||
/**
|
||||
* In case of multi-dimensional data, the service metadata can describe their multi-
|
||||
* dimensionality and tiles can be requested at specific values in these dimensions.
|
||||
* Examples of dimensions are Time, Elevation and Band.
|
||||
*/
|
||||
struct QgsWmtsDimension
|
||||
{
|
||||
QString identifier;
|
||||
QString title, abstract;
|
||||
QStringList keywords;
|
||||
QString UOM;
|
||||
QString unitSymbol;
|
||||
QString defaultValue;
|
||||
bool current;
|
||||
QStringList values;
|
||||
QString identifier; //!< name of the dimensional axis
|
||||
QString title; //!< human readable name
|
||||
QString abstract; //!< brief description of the dimension
|
||||
QStringList keywords; //!< list of words/phrases to describe the dataset
|
||||
QString UOM; //!< units of measure of dimensional axis
|
||||
QString unitSymbol; //!< symbol of the units
|
||||
QString defaultValue; //!< default value to be used if value is not specified in request
|
||||
bool current; //!< indicates whether temporal data are normally kept current
|
||||
QStringList values; //!< available values for this dimension
|
||||
};
|
||||
|
||||
struct QgsWmtsTileLayer
|
||||
@ -404,6 +412,7 @@ struct QgsWmtsTileLayer
|
||||
QStringList formats;
|
||||
QStringList infoFormats;
|
||||
QString defaultStyle;
|
||||
//! available dimensions (optional, for multi-dimensional data)
|
||||
QHash<QString, QgsWmtsDimension> dimensions;
|
||||
QHash<QString, QgsWmtsStyle> styles;
|
||||
QHash<QString, QgsWmtsTileMatrixSetLink> setLinks;
|
||||
@ -532,7 +541,11 @@ class QgsWmsSettings
|
||||
|
||||
//! layer is tiled, tile layer and active matrix set
|
||||
bool mTiled;
|
||||
//! whether we actually work with XYZ tiles instead of WMS / WMTS
|
||||
bool mXyz;
|
||||
//! chosen values for dimensions in case of multi-dimensional data (key=dim id, value=dim value)
|
||||
QHash<QString, QString> mTileDimensionValues;
|
||||
//! name of the chosen tile matrix set
|
||||
QString mTileMatrixSetId;
|
||||
|
||||
/**
|
||||
|
@ -79,6 +79,7 @@ static QString DEFAULT_LATLON_CRS = "CRS:84";
|
||||
|
||||
QMap<QString, QgsWmsStatistics::Stat> QgsWmsStatistics::sData;
|
||||
|
||||
|
||||
QgsWmsProvider::QgsWmsProvider( QString const& uri, const QgsWmsCapabilities* capabilities )
|
||||
: QgsRasterDataProvider( uri )
|
||||
, mHttpGetLegendGraphicResponse( nullptr )
|
||||
@ -110,14 +111,26 @@ QgsWmsProvider::QgsWmsProvider( QString const& uri, const QgsWmsCapabilities* ca
|
||||
if ( !addLayers() )
|
||||
return;
|
||||
|
||||
// if there are already parsed capabilities, use them!
|
||||
if ( capabilities )
|
||||
mCaps = *capabilities;
|
||||
|
||||
// Make sure we have capabilities - other functions here may need them
|
||||
if ( !retrieveServerCapabilities() )
|
||||
if ( mSettings.mXyz )
|
||||
{
|
||||
return;
|
||||
// we are working with XYZ tiles
|
||||
// no need to get capabilities, the whole definition is in URI
|
||||
// so we just generate a dummy WMTS definition
|
||||
setupXyzCapabilities( uri );
|
||||
}
|
||||
else
|
||||
{
|
||||
// we are working with WMS / WMTS server
|
||||
|
||||
// if there are already parsed capabilities, use them!
|
||||
if ( capabilities )
|
||||
mCaps = *capabilities;
|
||||
|
||||
// Make sure we have capabilities - other functions here may need them
|
||||
if ( !retrieveServerCapabilities() )
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// setImageCrs is using mTiled !!!
|
||||
@ -781,6 +794,28 @@ QImage *QgsWmsProvider::draw( QgsRectangle const & viewExtent, int pixelWidth, i
|
||||
}
|
||||
break;
|
||||
|
||||
case XYZ:
|
||||
{
|
||||
QString url = mSettings.mBaseUrl;
|
||||
int z = tm->identifier.toInt();
|
||||
int i = 0;
|
||||
for ( int row = row0; row <= row1; row++ )
|
||||
{
|
||||
for ( int col = col0; col <= col1; col++ )
|
||||
{
|
||||
QString turl( url );
|
||||
turl.replace( "{x}", QString::number( col ), Qt::CaseInsensitive );
|
||||
turl.replace( "{y}", QString::number( row ), Qt::CaseInsensitive );
|
||||
turl.replace( "{z}", QString::number( z ), Qt::CaseInsensitive );
|
||||
|
||||
if ( feedback && !feedback->preview_only )
|
||||
QgsDebugMsg( QString( "tileRequest %1 %2/%3 (%4,%5): %6" ).arg( mTileReqNo ).arg( i++ ).arg( n ).arg( row ).arg( col ).arg( turl ) );
|
||||
requests << QgsWmsTiledImageDownloadHandler::TileRequest( turl, tm->tileRect( col, row ), i );
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
QgsDebugMsg( QString( "unexpected tile mode %1" ).arg( mTileLayer->tileMode ) );
|
||||
return image;
|
||||
@ -935,6 +970,60 @@ bool QgsWmsProvider::retrieveServerCapabilities( bool forceRefresh )
|
||||
}
|
||||
|
||||
|
||||
void QgsWmsProvider::setupXyzCapabilities( const QString &uri )
|
||||
{
|
||||
QgsDataSourceUri parsedUri;
|
||||
parsedUri.setEncodedUri( uri );
|
||||
|
||||
QgsCoordinateTransform ct( QgsCoordinateReferenceSystem( "EPSG:4326" ), QgsCoordinateReferenceSystem( mSettings.mCrsId ) );
|
||||
// the whole world is projected to a square:
|
||||
// X going from 180 W to 180 E
|
||||
// Y going from ~85 N to ~85 S (=atan(sinh(pi)) ... to get a square)
|
||||
QgsPoint topLeftLonLat( -180, 180.0 / M_PI * atan( sinh( M_PI ) ) );
|
||||
QgsPoint bottomRightLonLat( 180, 180.0 / M_PI * atan( sinh( -M_PI ) ) );
|
||||
QgsPoint topLeft = ct.transform( topLeftLonLat );
|
||||
QgsPoint bottomRight = ct.transform( bottomRightLonLat );
|
||||
double xspan = ( bottomRight.x() - topLeft.x() );
|
||||
|
||||
QgsWmsBoundingBoxProperty bbox;
|
||||
bbox.crs = mSettings.mCrsId;
|
||||
bbox.box = QgsRectangle( topLeft.x(), bottomRight.y(), bottomRight.x(), topLeft.y() );
|
||||
|
||||
QgsWmtsTileLayer tl;
|
||||
tl.tileMode = XYZ;
|
||||
tl.identifier = "xyz"; // as set in parseUri
|
||||
tl.boundingBoxes << bbox;
|
||||
mCaps.mTileLayersSupported.append( tl );
|
||||
|
||||
QgsWmtsTileMatrixSet tms;
|
||||
tms.identifier = "tms0"; // as set in parseUri
|
||||
tms.crs = mSettings.mCrsId;
|
||||
mCaps.mTileMatrixSets[tms.identifier] = tms;
|
||||
|
||||
int minZoom = 0;
|
||||
int maxZoom = 18;
|
||||
if ( parsedUri.hasParam( "zmin" ) )
|
||||
minZoom = parsedUri.param( "zmin" ).toInt();
|
||||
if ( parsedUri.hasParam( "zmax" ) )
|
||||
maxZoom = parsedUri.param( "zmax" ).toInt();
|
||||
|
||||
// zoom 0 is one tile for the whole world
|
||||
for ( int zoom = minZoom; zoom <= maxZoom; ++zoom )
|
||||
{
|
||||
QgsWmtsTileMatrix tm;
|
||||
tm.identifier = QString::number( zoom );
|
||||
tm.topLeft = topLeft;
|
||||
tm.tileWidth = 256;
|
||||
tm.tileHeight = 256;
|
||||
tm.matrixWidth = pow( 2, zoom );
|
||||
tm.matrixHeight = pow( 2, zoom );
|
||||
tm.tres = xspan / ( tm.tileWidth * tm.matrixWidth );
|
||||
|
||||
mCaps.mTileMatrixSets[tms.identifier].tileMatrices[tm.tres] = tm;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Qgis::DataType QgsWmsProvider::dataType( int bandNo ) const
|
||||
{
|
||||
return sourceDataType( bandNo );
|
||||
@ -1835,6 +1924,10 @@ QString QgsWmsProvider::metadata()
|
||||
{
|
||||
metadata += tr( "WMS-C" );
|
||||
}
|
||||
else if ( l.tileMode == XYZ )
|
||||
{
|
||||
metadata += tr( "XYZ" );
|
||||
}
|
||||
else
|
||||
{
|
||||
metadata += tr( "Invalid tile mode" );
|
||||
|
@ -363,6 +363,9 @@ class QgsWmsProvider : public QgsRasterDataProvider
|
||||
|
||||
private:
|
||||
|
||||
//! In case of XYZ tile layer, setup capabilities from its URI
|
||||
void setupXyzCapabilities( const QString& uri );
|
||||
|
||||
QImage *draw( QgsRectangle const & viewExtent, int pixelWidth, int pixelHeight, QgsRasterBlockFeedback* feedback );
|
||||
|
||||
/**
|
||||
|
Loading…
x
Reference in New Issue
Block a user