From aadfbab40f54bc98d1c151fc80df93b634e39b45 Mon Sep 17 00:00:00 2001 From: Nyall Dawson Date: Thu, 16 Mar 2023 10:18:25 +1000 Subject: [PATCH] Split vector tile classes into separate files --- .../vectortile/qgsvectortilelayer.sip.in | 4 - src/core/CMakeLists.txt | 10 + ...qgsarcgisvectortileservicedataprovider.cpp | 53 +++ .../qgsarcgisvectortileservicedataprovider.h | 47 ++ .../qgsmbtilesvectortiledataprovider.cpp | 127 ++++++ .../qgsmbtilesvectortiledataprovider.h | 54 +++ .../vectortile/qgsvectortiledataprovider.cpp | 75 ++++ .../vectortile/qgsvectortiledataprovider.h | 89 ++++ src/core/vectortile/qgsvectortilelayer.cpp | 424 +----------------- src/core/vectortile/qgsvectortilelayer.h | 162 +------ .../vectortile/qgsvectortilelayerrenderer.cpp | 11 +- .../vectortile/qgsvectortilelayerrenderer.h | 6 +- src/core/vectortile/qgsvectortileloader.cpp | 9 +- src/core/vectortile/qgsvectortileloader.h | 14 +- .../qgsvtpkvectortiledataprovider.cpp | 110 +++++ .../qgsvtpkvectortiledataprovider.h | 54 +++ .../qgsxyzvectortiledataprovider.cpp | 170 +++++++ .../vectortile/qgsxyzvectortiledataprovider.h | 63 +++ 18 files changed, 874 insertions(+), 608 deletions(-) create mode 100644 src/core/vectortile/qgsarcgisvectortileservicedataprovider.cpp create mode 100644 src/core/vectortile/qgsarcgisvectortileservicedataprovider.h create mode 100644 src/core/vectortile/qgsmbtilesvectortiledataprovider.cpp create mode 100644 src/core/vectortile/qgsmbtilesvectortiledataprovider.h create mode 100644 src/core/vectortile/qgsvectortiledataprovider.cpp create mode 100644 src/core/vectortile/qgsvectortiledataprovider.h create mode 100644 src/core/vectortile/qgsvtpkvectortiledataprovider.cpp create mode 100644 src/core/vectortile/qgsvtpkvectortiledataprovider.h create mode 100644 src/core/vectortile/qgsxyzvectortiledataprovider.cpp create mode 100644 src/core/vectortile/qgsxyzvectortiledataprovider.h diff --git a/python/core/auto_generated/vectortile/qgsvectortilelayer.sip.in b/python/core/auto_generated/vectortile/qgsvectortilelayer.sip.in index 95874a3e3cd..e6a4cd09315 100644 --- a/python/core/auto_generated/vectortile/qgsvectortilelayer.sip.in +++ b/python/core/auto_generated/vectortile/qgsvectortilelayer.sip.in @@ -9,8 +9,6 @@ - - class QgsVectorTileLayer : QgsMapLayer { %Docstring(signature="appended") @@ -281,8 +279,6 @@ Emitted whenever the selected features in the layer are changed. }; - - /************************************************************************ * This file has been generated automatically from * * * diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 972bcaca071..03a547a810e 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -890,11 +890,14 @@ set(QGIS_CORE_SRCS vector/qgsvectorlayerundopassthroughcommand.cpp vector/qgsvectorlayerutils.cpp + vectortile/qgsarcgisvectortileservicedataprovider.cpp vectortile/qgsmapboxglstyleconverter.cpp + vectortile/qgsmbtilesvectortiledataprovider.cpp vectortile/qgsvectortilebasiclabeling.cpp vectortile/qgsvectortilebasicrenderer.cpp vectortile/qgsvectortileconnection.cpp vectortile/qgsvectortiledataitems.cpp + vectortile/qgsvectortiledataprovider.cpp vectortile/qgsvectortilelabeling.cpp vectortile/qgsvectortilelayer.cpp vectortile/qgsvectortilelayerrenderer.cpp @@ -907,6 +910,8 @@ set(QGIS_CORE_SRCS vectortile/qgsvectortileutils.cpp vectortile/qgsvectortilewriter.cpp vectortile/qgsvtpktiles.cpp + vectortile/qgsvtpkvectortiledataprovider.cpp + vectortile/qgsxyzvectortiledataprovider.cpp ${CMAKE_CURRENT_BINARY_DIR}/qgsexpression_texts.cpp @@ -1899,11 +1904,14 @@ set(QGIS_CORE_HDRS vector/qgsvectorlayerundopassthroughcommand.h vector/qgsvectorlayerutils.h + vectortile/qgsarcgisvectortileservicedataprovider.h vectortile/qgsmapboxglstyleconverter.h + vectortile/qgsmbtilesvectortiledataprovider.h vectortile/qgsvectortilebasiclabeling.h vectortile/qgsvectortilebasicrenderer.h vectortile/qgsvectortileconnection.h vectortile/qgsvectortiledataitems.h + vectortile/qgsvectortiledataprovider.h vectortile/qgsvectortilelabeling.h vectortile/qgsvectortilelayer.h vectortile/qgsvectortilelayerrenderer.h @@ -1917,6 +1925,8 @@ set(QGIS_CORE_HDRS vectortile/qgsvectortileutils.h vectortile/qgsvectortilewriter.h vectortile/qgsvtpktiles.h + vectortile/qgsvtpkvectortiledataprovider.h + vectortile/qgsxyzvectortiledataprovider.h ) set(QGIS_CORE_PRIVATE_HDRS diff --git a/src/core/vectortile/qgsarcgisvectortileservicedataprovider.cpp b/src/core/vectortile/qgsarcgisvectortileservicedataprovider.cpp new file mode 100644 index 00000000000..33127d48177 --- /dev/null +++ b/src/core/vectortile/qgsarcgisvectortileservicedataprovider.cpp @@ -0,0 +1,53 @@ +/*************************************************************************** + qgsarcgisvectortileservicedataprovider.cpp + -------------------------------------- + Date : March 2020 + Copyright : (C) 2020 by Martin Dobias + Email : wonder dot sk at gmail dot com + *************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#include "qgsarcgisvectortileservicedataprovider.h" +#include "qgsthreadingutils.h" + +///@cond PRIVATE + +QgsArcGisVectorTileServiceDataProvider::QgsArcGisVectorTileServiceDataProvider( const QString &uri, const QString &sourcePath, const ProviderOptions &providerOptions, ReadFlags flags ) + : QgsXyzVectorTileDataProvider( uri, providerOptions, flags ) + , mSourcePath( sourcePath ) +{ + +} + +QgsVectorTileDataProvider *QgsArcGisVectorTileServiceDataProvider::clone() const +{ + QGIS_PROTECT_QOBJECT_THREAD_ACCESS + + ProviderOptions options; + options.transformContext = transformContext(); + return new QgsArcGisVectorTileServiceDataProvider( dataSourceUri(), mSourcePath, options, mReadFlags ); +} + +QString QgsArcGisVectorTileServiceDataProvider::sourcePath() const +{ + QGIS_PROTECT_QOBJECT_THREAD_ACCESS + + return mSourcePath; +} + +bool QgsArcGisVectorTileServiceDataProvider::isValid() const +{ + QGIS_PROTECT_QOBJECT_THREAD_ACCESS + + return true; +} + +///@endcond + + diff --git a/src/core/vectortile/qgsarcgisvectortileservicedataprovider.h b/src/core/vectortile/qgsarcgisvectortileservicedataprovider.h new file mode 100644 index 00000000000..6f0bd518460 --- /dev/null +++ b/src/core/vectortile/qgsarcgisvectortileservicedataprovider.h @@ -0,0 +1,47 @@ +/*************************************************************************** + qgsarcgisvectortileservicedataprovider.h + -------------------------------------- + Date : March 2020 + Copyright : (C) 2020 by Martin Dobias + Email : wonder dot sk at gmail dot com + *************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#ifndef QGSARCGISVECTORTILESERVICEDATAPROVIDER_H +#define QGSARCGISVECTORTILESERVICEDATAPROVIDER_H + +#include "qgis_core.h" +#include "qgis_sip.h" +#include "qgsxyzvectortiledataprovider.h" + +#define SIP_NO_FILE + +///@cond PRIVATE + +class CORE_EXPORT QgsArcGisVectorTileServiceDataProvider : public QgsXyzVectorTileDataProvider +{ + Q_OBJECT + + public: + QgsArcGisVectorTileServiceDataProvider( const QString &uri, + const QString &sourcePath, + const QgsDataProvider::ProviderOptions &providerOptions, + QgsDataProvider::ReadFlags flags ); + QgsVectorTileDataProvider *clone() const override; + QString sourcePath() const override; + bool isValid() const override; + + private: + + QString mSourcePath; +}; + +///@endcond + +#endif // QGSARCGISVECTORTILESERVICEDATAPROVIDER_H diff --git a/src/core/vectortile/qgsmbtilesvectortiledataprovider.cpp b/src/core/vectortile/qgsmbtilesvectortiledataprovider.cpp new file mode 100644 index 00000000000..1dc8a3804ee --- /dev/null +++ b/src/core/vectortile/qgsmbtilesvectortiledataprovider.cpp @@ -0,0 +1,127 @@ +/*************************************************************************** + qgsmbtilesvectortiledataprovider.cpp + -------------------------------------- + Date : March 2020 + Copyright : (C) 2020 by Martin Dobias + Email : wonder dot sk at gmail dot com + *************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#include "qgsmbtilesvectortiledataprovider.h" +#include "qgsthreadingutils.h" +#include "qgsmbtiles.h" +#include "qgstiles.h" +#include "qgsvectortileloader.h" +#include "qgsziputils.h" +#include "qgslogger.h" + +///@cond PRIVATE + +QgsMbTilesVectorTileDataProvider::QgsMbTilesVectorTileDataProvider( const QString &uri, const ProviderOptions &providerOptions, ReadFlags flags ) + : QgsVectorTileDataProvider( uri, providerOptions, flags ) +{ + +} + +QgsVectorTileDataProvider *QgsMbTilesVectorTileDataProvider::clone() const +{ + QGIS_PROTECT_QOBJECT_THREAD_ACCESS + + ProviderOptions options; + options.transformContext = transformContext(); + return new QgsMbTilesVectorTileDataProvider( dataSourceUri(), options, mReadFlags ); +} + +QString QgsMbTilesVectorTileDataProvider::sourcePath() const +{ + QGIS_PROTECT_QOBJECT_THREAD_ACCESS + + QgsDataSourceUri dsUri; + dsUri.setEncodedUri( dataSourceUri() ); + return dsUri.param( QStringLiteral( "url" ) ); +} + +bool QgsMbTilesVectorTileDataProvider::isValid() const +{ + QGIS_PROTECT_QOBJECT_THREAD_ACCESS + + return true; +} + +QgsCoordinateReferenceSystem QgsMbTilesVectorTileDataProvider::crs() const +{ + QGIS_PROTECT_QOBJECT_THREAD_ACCESS + + return QgsCoordinateReferenceSystem( QStringLiteral( "EPSG:3857" ) ); +} + +QByteArray QgsMbTilesVectorTileDataProvider::readTile( const QgsTileMatrix &, const QgsTileXYZ &id, QgsFeedback *feedback ) const +{ + QGIS_PROTECT_QOBJECT_THREAD_ACCESS + + QgsDataSourceUri dsUri; + dsUri.setEncodedUri( dataSourceUri() ); + + QgsMbTiles mbReader( dsUri.param( QStringLiteral( "url" ) ) ); + mbReader.open(); + return loadFromMBTiles( mbReader, id, feedback ); +} + +QList QgsMbTilesVectorTileDataProvider::readTiles( const QgsTileMatrix &, const QVector &tiles, QgsFeedback *feedback ) const +{ + QGIS_PROTECT_QOBJECT_THREAD_ACCESS + + QgsDataSourceUri dsUri; + dsUri.setEncodedUri( dataSourceUri() ); + + QgsMbTiles mbReader( dsUri.param( QStringLiteral( "url" ) ) ); + mbReader.open(); + + QList rawTiles; + rawTiles.reserve( tiles.size() ); + for ( QgsTileXYZ id : std::as_const( tiles ) ) + { + if ( feedback && feedback->isCanceled() ) + break; + + const QByteArray rawData = loadFromMBTiles( mbReader, id, feedback ); + if ( !rawData.isEmpty() ) + { + rawTiles.append( QgsVectorTileRawData( id, rawData ) ); + } + } + return rawTiles; +} + +QByteArray QgsMbTilesVectorTileDataProvider::loadFromMBTiles( QgsMbTiles &mbTileReader, const QgsTileXYZ &id, QgsFeedback *feedback ) +{ + // MBTiles uses TMS specs with Y starting at the bottom while XYZ uses Y starting at the top + const int rowTMS = static_cast( pow( 2, id.zoomLevel() ) - id.row() - 1 ); + QByteArray gzippedTileData = mbTileReader.tileData( id.zoomLevel(), id.column(), rowTMS ); + if ( gzippedTileData.isEmpty() ) + { + return QByteArray(); + } + + if ( feedback && feedback->isCanceled() ) + return QByteArray(); + + QByteArray data; + if ( !QgsZipUtils::decodeGzip( gzippedTileData, data ) ) + { + QgsDebugMsg( QStringLiteral( "Failed to decompress tile " ) + id.toString() ); + return QByteArray(); + } + + QgsDebugMsgLevel( QStringLiteral( "Tile blob size %1 -> uncompressed size %2" ).arg( gzippedTileData.size() ).arg( data.size() ), 2 ); + return data; +} +///@endcond + + diff --git a/src/core/vectortile/qgsmbtilesvectortiledataprovider.h b/src/core/vectortile/qgsmbtilesvectortiledataprovider.h new file mode 100644 index 00000000000..f9294ee159c --- /dev/null +++ b/src/core/vectortile/qgsmbtilesvectortiledataprovider.h @@ -0,0 +1,54 @@ +/*************************************************************************** + qgsmbtilesvectortiledataprovider.h + -------------------------------------- + Date : March 2020 + Copyright : (C) 2020 by Martin Dobias + Email : wonder dot sk at gmail dot com + *************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#ifndef QGSMBTILESVECTORTILEDATAPROVIDER_H +#define QGSMBTILESVECTORTILEDATAPROVIDER_H + +#include "qgis_core.h" +#include "qgis_sip.h" +#include "qgsvectortiledataprovider.h" + +class QgsMbTiles; + +#define SIP_NO_FILE + +///@cond PRIVATE + +class CORE_EXPORT QgsMbTilesVectorTileDataProvider : public QgsVectorTileDataProvider +{ + Q_OBJECT + + public: + QgsMbTilesVectorTileDataProvider( const QString &uri, + const QgsDataProvider::ProviderOptions &providerOptions, + QgsDataProvider::ReadFlags flags ); + + QgsVectorTileDataProvider *clone() const override; + QString sourcePath() const override; + bool isValid() const override; + QgsCoordinateReferenceSystem crs() const override; + QByteArray readTile( const QgsTileMatrix &tileMatrix, const QgsTileXYZ &id, QgsFeedback *feedback = nullptr ) const override; + QList readTiles( const QgsTileMatrix &, const QVector &tiles, QgsFeedback *feedback = nullptr ) const override; + + private: + + //! Returns raw tile data for a single tile loaded from MBTiles file + static QByteArray loadFromMBTiles( QgsMbTiles &mbTileReader, const QgsTileXYZ &id, QgsFeedback *feedback = nullptr ); + +}; + +///@endcond + +#endif // QGSMBTILESVECTORTILEDATAPROVIDER_H diff --git a/src/core/vectortile/qgsvectortiledataprovider.cpp b/src/core/vectortile/qgsvectortiledataprovider.cpp new file mode 100644 index 00000000000..2db803440c3 --- /dev/null +++ b/src/core/vectortile/qgsvectortiledataprovider.cpp @@ -0,0 +1,75 @@ +/*************************************************************************** + qgsvectortiledataprovider.cpp + -------------------------------------- + Date : March 2020 + Copyright : (C) 2020 by Martin Dobias + Email : wonder dot sk at gmail dot com + *************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#include "qgsvectortiledataprovider.h" +#include "qgsthreadingutils.h" + +#include + +QgsVectorTileDataProvider::QgsVectorTileDataProvider( + const QString &uri, + const ProviderOptions &options, + QgsDataProvider::ReadFlags flags ) + : QgsDataProvider( uri, options, flags ) +{} + +QString QgsVectorTileDataProvider::name() const +{ + QGIS_PROTECT_QOBJECT_THREAD_ACCESS + + return QStringLiteral( "vectortile" ); +} + +QString QgsVectorTileDataProvider::description() const +{ + QGIS_PROTECT_QOBJECT_THREAD_ACCESS + + return QString(); +} + +QgsRectangle QgsVectorTileDataProvider::extent() const +{ + QGIS_PROTECT_QOBJECT_THREAD_ACCESS + + return QgsRectangle(); +} + +bool QgsVectorTileDataProvider::renderInPreview( const PreviewContext &context ) +{ + QGIS_PROTECT_QOBJECT_THREAD_ACCESS + + // Vector tiles by design are very CPU light to render, so we are much more permissive here compared + // with other layer types. (Generally if a vector tile layer has taken more than a few milliseconds to render it's + // a result of network requests, and the tile manager class handles these gracefully for us) + return context.lastRenderingTimeMs <= 1000; +} + +bool QgsVectorTileDataProvider::supportsAsync() const +{ + QGIS_PROTECT_QOBJECT_THREAD_ACCESS + + return false; +} + +QNetworkRequest QgsVectorTileDataProvider::tileRequest( const QgsTileMatrix &, const QgsTileXYZ &, Qgis::RendererUsage ) const +{ + QGIS_PROTECT_QOBJECT_THREAD_ACCESS + + return QNetworkRequest(); +} + +///@endcond + + diff --git a/src/core/vectortile/qgsvectortiledataprovider.h b/src/core/vectortile/qgsvectortiledataprovider.h new file mode 100644 index 00000000000..ce0d2cf737c --- /dev/null +++ b/src/core/vectortile/qgsvectortiledataprovider.h @@ -0,0 +1,89 @@ +/*************************************************************************** + qgsvectortiledataprovider.h + -------------------------------------- + Date : March 2020 + Copyright : (C) 2020 by Martin Dobias + Email : wonder dot sk at gmail dot com + *************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#ifndef QGSVECTORTILEDATAPROVIDER_H +#define QGSVECTORTILEDATAPROVIDER_H + +#include "qgis_core.h" +#include "qgis_sip.h" +#include "qgsdataprovider.h" + +class QgsTileMatrix; +class QgsTileXYZ; +class QgsVectorTileRawData; + +#define SIP_NO_FILE + +/** + * Base class for vector tile layer data providers. + * + * \note Not available in Python bindings + * + * \since QGIS 3.22 + */ +class CORE_EXPORT QgsVectorTileDataProvider : public QgsDataProvider +{ + Q_OBJECT + + public: + + /** + * Constructor for QgsVectorTileDataProvider, with the specified \a uri. + */ + QgsVectorTileDataProvider( const QString &uri, + const QgsDataProvider::ProviderOptions &providerOptions, + QgsDataProvider::ReadFlags flags ); + + QString name() const override; + QString description() const override; + QgsRectangle extent() const override; + bool renderInPreview( const QgsDataProvider::PreviewContext &context ) override; + + /** + * Returns the source path for the data. + */ + virtual QString sourcePath() const = 0; + + /** + * Returns a clone of the data provider. + */ + virtual QgsVectorTileDataProvider *clone() const = 0 SIP_FACTORY; + + /** + * Returns TRUE if the provider supports async tile reading. + * + * The default implementation returns FALSE. + */ + virtual bool supportsAsync() const; + + /** + * Returns raw tile data for a single tile. + */ + virtual QByteArray readTile( const QgsTileMatrix &tileMatrix, const QgsTileXYZ &id, QgsFeedback *feedback = nullptr ) const = 0; + + /** + * Returns raw tile data for a range of tiles. + */ + virtual QList readTiles( const QgsTileMatrix &tileMatrix, const QVector &tiles, QgsFeedback *feedback = nullptr ) const = 0; + + /** + * Returns a network request for a tile. + * + * The default implementation returns an invalid request. + */ + virtual QNetworkRequest tileRequest( const QgsTileMatrix &tileMatrix, const QgsTileXYZ &id, Qgis::RendererUsage usage ) const; +}; + +#endif // QGSVECTORTILEDATAPROVIDER_H diff --git a/src/core/vectortile/qgsvectortilelayer.cpp b/src/core/vectortile/qgsvectortilelayer.cpp index 531d2c8f856..cc97d61e513 100644 --- a/src/core/vectortile/qgsvectortilelayer.cpp +++ b/src/core/vectortile/qgsvectortilelayer.cpp @@ -22,10 +22,8 @@ #include "qgsvectortilebasiclabeling.h" #include "qgsvectortilebasicrenderer.h" #include "qgsvectortilelabeling.h" -#include "qgsvectortileloader.h" #include "qgsvectortileutils.h" #include "qgsnetworkaccessmanager.h" - #include "qgsdatasourceuri.h" #include "qgslayermetadataformatter.h" #include "qgsblockingnetworkrequest.h" @@ -39,10 +37,11 @@ #include "qgsvectortilemvtdecoder.h" #include "qgsthreadingutils.h" #include "qgsproviderregistry.h" -#include "qgsziputils.h" -#include "qgsapplication.h" -#include "qgsmessagelog.h" -#include "qgsauthmanager.h" +#include "qgsvectortiledataprovider.h" +#include "qgsmbtilesvectortiledataprovider.h" +#include "qgsarcgisvectortileservicedataprovider.h" +#include "qgsxyzvectortiledataprovider.h" +#include "qgsvtpkvectortiledataprovider.h" #include #include @@ -1317,416 +1316,3 @@ void QgsVectorTileLayer::removeSelection() } -// -// QgsVectorTileDataProvider -// -///@cond PRIVATE -QgsVectorTileDataProvider::QgsVectorTileDataProvider( const QString &uri, - const ProviderOptions &options, - QgsDataProvider::ReadFlags flags ) - : QgsDataProvider( uri, options, flags ) -{} - -QString QgsVectorTileDataProvider::name() const -{ - QGIS_PROTECT_QOBJECT_THREAD_ACCESS - - return QStringLiteral( "vectortile" ); -} - -QString QgsVectorTileDataProvider::description() const -{ - QGIS_PROTECT_QOBJECT_THREAD_ACCESS - - return QString(); -} - -QgsRectangle QgsVectorTileDataProvider::extent() const -{ - QGIS_PROTECT_QOBJECT_THREAD_ACCESS - - return QgsRectangle(); -} - -bool QgsVectorTileDataProvider::renderInPreview( const PreviewContext &context ) -{ - QGIS_PROTECT_QOBJECT_THREAD_ACCESS - - // Vector tiles by design are very CPU light to render, so we are much more permissive here compared - // with other layer types. (Generally if a vector tile layer has taken more than a few milliseconds to render it's - // a result of network requests, and the tile manager class handles these gracefully for us) - return context.lastRenderingTimeMs <= 1000; -} - -bool QgsVectorTileDataProvider::supportsAsync() const -{ - return false; -} - -QNetworkRequest QgsVectorTileDataProvider::tileRequest( const QgsTileMatrix &, const QgsTileXYZ &, Qgis::RendererUsage ) const -{ - return QNetworkRequest(); -} - -// -// QgsXyzVectorTileDataProvider -// - -QgsXyzVectorTileDataProvider::QgsXyzVectorTileDataProvider( const QString &uri, const ProviderOptions &providerOptions, ReadFlags flags ) - : QgsVectorTileDataProvider( uri, providerOptions, flags ) -{ - QgsDataSourceUri dsUri; - dsUri.setEncodedUri( uri ); - - mAuthCfg = dsUri.authConfigId(); - mHeaders = dsUri.httpHeaders(); -} - -QgsVectorTileDataProvider *QgsXyzVectorTileDataProvider::clone() const -{ - QGIS_PROTECT_QOBJECT_THREAD_ACCESS - - ProviderOptions options; - options.transformContext = transformContext(); - return new QgsXyzVectorTileDataProvider( dataSourceUri(), options, mReadFlags ); -} - -QString QgsXyzVectorTileDataProvider::sourcePath() const -{ - QGIS_PROTECT_QOBJECT_THREAD_ACCESS - - QgsDataSourceUri dsUri; - dsUri.setEncodedUri( dataSourceUri() ); - return dsUri.param( QStringLiteral( "url" ) ); -} - -bool QgsXyzVectorTileDataProvider::isValid() const -{ - QGIS_PROTECT_QOBJECT_THREAD_ACCESS - - return true; -} - -QgsCoordinateReferenceSystem QgsXyzVectorTileDataProvider::crs() const -{ - QGIS_PROTECT_QOBJECT_THREAD_ACCESS - - return QgsCoordinateReferenceSystem( QStringLiteral( "EPSG:3857" ) ); -} - -bool QgsXyzVectorTileDataProvider::supportsAsync() const -{ - return true; -} - -QByteArray QgsXyzVectorTileDataProvider::readTile( const QgsTileMatrix &tileMatrix, const QgsTileXYZ &id, QgsFeedback *feedback ) const -{ - return loadFromNetwork( id, tileMatrix, sourcePath(), mAuthCfg, mHeaders, feedback ); -} - -QList QgsXyzVectorTileDataProvider::readTiles( const QgsTileMatrix &tileMatrix, const QVector &tiles, QgsFeedback *feedback ) const -{ - QList rawTiles; - rawTiles.reserve( tiles.size() ); - const QString source = sourcePath(); - for ( QgsTileXYZ id : std::as_const( tiles ) ) - { - if ( feedback && feedback->isCanceled() ) - break; - - const QByteArray rawData = loadFromNetwork( id, tileMatrix, source, mAuthCfg, mHeaders, feedback ); - if ( !rawData.isEmpty() ) - { - rawTiles.append( QgsVectorTileRawData( id, rawData ) ); - } - } - return rawTiles; -} - -QNetworkRequest QgsXyzVectorTileDataProvider::tileRequest( const QgsTileMatrix &tileMatrix, const QgsTileXYZ &id, Qgis::RendererUsage usage ) const -{ - QString urlTemplate = sourcePath(); - - if ( urlTemplate.contains( QLatin1String( "{usage}" ) ) ) - { - switch ( usage ) - { - case Qgis::RendererUsage::View: - urlTemplate.replace( QLatin1String( "{usage}" ), QLatin1String( "view" ) ); - break; - case Qgis::RendererUsage::Export: - urlTemplate.replace( QLatin1String( "{usage}" ), QLatin1String( "export" ) ); - break; - case Qgis::RendererUsage::Unknown: - urlTemplate.replace( QLatin1String( "{usage}" ), QString() ); - break; - } - } - - const QString url = QgsVectorTileUtils::formatXYZUrlTemplate( urlTemplate, id, tileMatrix ); - - QNetworkRequest request( url ); - QgsSetRequestInitiatorClass( request, QStringLiteral( "QgsXyzVectorTileDataProvider" ) ); - QgsSetRequestInitiatorId( request, id.toString() ); - - request.setAttribute( static_cast( QNetworkRequest::User + 1 ), id.column() ); - request.setAttribute( static_cast( QNetworkRequest::User + 2 ), id.row() ); - request.setAttribute( static_cast( QNetworkRequest::User + 3 ), id.zoomLevel() ); - - request.setAttribute( QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::PreferCache ); - request.setAttribute( QNetworkRequest::CacheSaveControlAttribute, true ); - - mHeaders.updateNetworkRequest( request ); - - if ( !mAuthCfg.isEmpty() && !QgsApplication::authManager()->updateNetworkRequest( request, mAuthCfg ) ) - { - QgsMessageLog::logMessage( tr( "network request update failed for authentication config" ), tr( "Network" ) ); - } - - return request; -} - -QByteArray QgsXyzVectorTileDataProvider::loadFromNetwork( const QgsTileXYZ &id, const QgsTileMatrix &tileMatrix, const QString &requestUrl, const QString &authid, const QgsHttpHeaders &headers, QgsFeedback *feedback ) -{ - QString url = QgsVectorTileUtils::formatXYZUrlTemplate( requestUrl, id, tileMatrix ); - QNetworkRequest nr; - nr.setUrl( QUrl( url ) ); - - headers.updateNetworkRequest( nr ); - - QgsBlockingNetworkRequest req; - req.setAuthCfg( authid ); - QgsDebugMsgLevel( QStringLiteral( "Blocking request: " ) + url, 2 ); - QgsBlockingNetworkRequest::ErrorCode errCode = req.get( nr, false, feedback ); - if ( errCode != QgsBlockingNetworkRequest::NoError ) - { - QgsDebugMsg( QStringLiteral( "Request failed: " ) + url ); - return QByteArray(); - } - QgsNetworkReplyContent reply = req.reply(); - QgsDebugMsgLevel( QStringLiteral( "Request successful, content size %1" ).arg( reply.content().size() ), 2 ); - return reply.content(); -} - -// -// QgsMbTilesVectorTileDataProvider -// - -QgsMbTilesVectorTileDataProvider::QgsMbTilesVectorTileDataProvider( const QString &uri, const ProviderOptions &providerOptions, ReadFlags flags ) - : QgsVectorTileDataProvider( uri, providerOptions, flags ) -{ - -} - -QgsVectorTileDataProvider *QgsMbTilesVectorTileDataProvider::clone() const -{ - QGIS_PROTECT_QOBJECT_THREAD_ACCESS - - ProviderOptions options; - options.transformContext = transformContext(); - return new QgsMbTilesVectorTileDataProvider( dataSourceUri(), options, mReadFlags ); -} - -QString QgsMbTilesVectorTileDataProvider::sourcePath() const -{ - QGIS_PROTECT_QOBJECT_THREAD_ACCESS - - QgsDataSourceUri dsUri; - dsUri.setEncodedUri( dataSourceUri() ); - return dsUri.param( QStringLiteral( "url" ) ); -} - -bool QgsMbTilesVectorTileDataProvider::isValid() const -{ - QGIS_PROTECT_QOBJECT_THREAD_ACCESS - - return true; -} - -QgsCoordinateReferenceSystem QgsMbTilesVectorTileDataProvider::crs() const -{ - QGIS_PROTECT_QOBJECT_THREAD_ACCESS - - return QgsCoordinateReferenceSystem( QStringLiteral( "EPSG:3857" ) ); -} - -QByteArray QgsMbTilesVectorTileDataProvider::readTile( const QgsTileMatrix &, const QgsTileXYZ &id, QgsFeedback *feedback ) const -{ - QgsDataSourceUri dsUri; - dsUri.setEncodedUri( dataSourceUri() ); - - QgsMbTiles mbReader( dsUri.param( QStringLiteral( "url" ) ) ); - mbReader.open(); - return loadFromMBTiles( mbReader, id, feedback ); -} - -QList QgsMbTilesVectorTileDataProvider::readTiles( const QgsTileMatrix &, const QVector &tiles, QgsFeedback *feedback ) const -{ - QgsDataSourceUri dsUri; - dsUri.setEncodedUri( dataSourceUri() ); - - QgsMbTiles mbReader( dsUri.param( QStringLiteral( "url" ) ) ); - mbReader.open(); - - QList rawTiles; - rawTiles.reserve( tiles.size() ); - for ( QgsTileXYZ id : std::as_const( tiles ) ) - { - if ( feedback && feedback->isCanceled() ) - break; - - const QByteArray rawData = loadFromMBTiles( mbReader, id, feedback ); - if ( !rawData.isEmpty() ) - { - rawTiles.append( QgsVectorTileRawData( id, rawData ) ); - } - } - return rawTiles; -} - -QByteArray QgsMbTilesVectorTileDataProvider::loadFromMBTiles( QgsMbTiles &mbTileReader, const QgsTileXYZ &id, QgsFeedback *feedback ) -{ - // MBTiles uses TMS specs with Y starting at the bottom while XYZ uses Y starting at the top - const int rowTMS = static_cast( pow( 2, id.zoomLevel() ) - id.row() - 1 ); - QByteArray gzippedTileData = mbTileReader.tileData( id.zoomLevel(), id.column(), rowTMS ); - if ( gzippedTileData.isEmpty() ) - { - return QByteArray(); - } - - if ( feedback && feedback->isCanceled() ) - return QByteArray(); - - QByteArray data; - if ( !QgsZipUtils::decodeGzip( gzippedTileData, data ) ) - { - QgsDebugMsg( QStringLiteral( "Failed to decompress tile " ) + id.toString() ); - return QByteArray(); - } - - QgsDebugMsgLevel( QStringLiteral( "Tile blob size %1 -> uncompressed size %2" ).arg( gzippedTileData.size() ).arg( data.size() ), 2 ); - return data; -} - -// -// QgsVtpkVectorTileDataProvider -// - -QgsVtpkVectorTileDataProvider::QgsVtpkVectorTileDataProvider( const QString &uri, const ProviderOptions &providerOptions, ReadFlags flags ) - : QgsVectorTileDataProvider( uri, providerOptions, flags ) -{ - -} - -QgsVectorTileDataProvider *QgsVtpkVectorTileDataProvider::clone() const -{ - QGIS_PROTECT_QOBJECT_THREAD_ACCESS - - ProviderOptions options; - options.transformContext = transformContext(); - return new QgsVtpkVectorTileDataProvider( dataSourceUri(), options, mReadFlags ); -} - -QString QgsVtpkVectorTileDataProvider::sourcePath() const -{ - QGIS_PROTECT_QOBJECT_THREAD_ACCESS - - QgsDataSourceUri dsUri; - dsUri.setEncodedUri( dataSourceUri() ); - return dsUri.param( QStringLiteral( "url" ) ); -} - -bool QgsVtpkVectorTileDataProvider::isValid() const -{ - QGIS_PROTECT_QOBJECT_THREAD_ACCESS - - return true; -} - -QgsCoordinateReferenceSystem QgsVtpkVectorTileDataProvider::crs() const -{ - QGIS_PROTECT_QOBJECT_THREAD_ACCESS - - return QgsCoordinateReferenceSystem( QStringLiteral( "EPSG:3857" ) ); -} - -QByteArray QgsVtpkVectorTileDataProvider::readTile( const QgsTileMatrix &, const QgsTileXYZ &id, QgsFeedback *feedback ) const -{ - QgsDataSourceUri dsUri; - dsUri.setEncodedUri( dataSourceUri() ); - QgsVtpkTiles reader( dsUri.param( QStringLiteral( "url" ) ) ); - reader.open(); - return loadFromVtpk( reader, id, feedback ); -} - -QList QgsVtpkVectorTileDataProvider::readTiles( const QgsTileMatrix &, const QVector &tiles, QgsFeedback *feedback ) const -{ - QgsDataSourceUri dsUri; - dsUri.setEncodedUri( dataSourceUri() ); - - QgsVtpkTiles reader( dsUri.param( QStringLiteral( "url" ) ) ); - reader.open(); - - QList rawTiles; - rawTiles.reserve( tiles.size() ); - for ( QgsTileXYZ id : std::as_const( tiles ) ) - { - if ( feedback && feedback->isCanceled() ) - break; - - const QByteArray rawData = loadFromVtpk( reader, id, feedback ); - if ( !rawData.isEmpty() ) - { - rawTiles.append( QgsVectorTileRawData( id, rawData ) ); - } - } - return rawTiles; -} - -QByteArray QgsVtpkVectorTileDataProvider::loadFromVtpk( QgsVtpkTiles &vtpkTileReader, const QgsTileXYZ &id, QgsFeedback * ) -{ - const QByteArray tileData = vtpkTileReader.tileData( id.zoomLevel(), id.column(), id.row() ); - if ( tileData.isEmpty() ) - { - return QByteArray(); - } - return tileData; -} - -// -// QgsArcGisVectorTileServiceDataProvider -// - -QgsArcGisVectorTileServiceDataProvider::QgsArcGisVectorTileServiceDataProvider( const QString &uri, const QString &sourcePath, const ProviderOptions &providerOptions, ReadFlags flags ) - : QgsXyzVectorTileDataProvider( uri, providerOptions, flags ) - , mSourcePath( sourcePath ) -{ - -} - -QgsVectorTileDataProvider *QgsArcGisVectorTileServiceDataProvider::clone() const -{ - QGIS_PROTECT_QOBJECT_THREAD_ACCESS - - ProviderOptions options; - options.transformContext = transformContext(); - return new QgsArcGisVectorTileServiceDataProvider( dataSourceUri(), mSourcePath, options, mReadFlags ); -} - -QString QgsArcGisVectorTileServiceDataProvider::sourcePath() const -{ - QGIS_PROTECT_QOBJECT_THREAD_ACCESS - - return mSourcePath; -} - -bool QgsArcGisVectorTileServiceDataProvider::isValid() const -{ - QGIS_PROTECT_QOBJECT_THREAD_ACCESS - - return true; -} - -///@endcond - - diff --git a/src/core/vectortile/qgsvectortilelayer.h b/src/core/vectortile/qgsvectortilelayer.h index 6ad12c65ba0..cdb448e1b45 100644 --- a/src/core/vectortile/qgsvectortilelayer.h +++ b/src/core/vectortile/qgsvectortilelayer.h @@ -18,21 +18,15 @@ #include "qgis_core.h" #include "qgis_sip.h" - #include "qgsmaplayer.h" #include "qgsvectortilematrixset.h" #include "qgsfeatureid.h" -class QgsVectorTileLabeling; class QgsVectorTileRenderer; -class QgsVectorTileRawData; -class QgsVectorTileDataProvider; - -class QgsTileXYZ; +class QgsVectorTileLabeling; class QgsFeature; class QgsGeometry; class QgsSelectionContext; -class QgsMbTiles; /** * \ingroup core @@ -317,160 +311,6 @@ class CORE_EXPORT QgsVectorTileLayer : public QgsMapLayer bool loadDefaultStyleAndSubLayersPrivate( QString &error, QStringList &warnings, QList< QgsMapLayer * > *subLayers ); - }; -#ifndef SIP_RUN -///@cond PRIVATE - -/** - * A minimal data provider for vector tile layers. - * - * \since QGIS 3.22 - */ -class QgsVectorTileDataProvider : public QgsDataProvider -{ - Q_OBJECT - - public: - QgsVectorTileDataProvider( const QString &uri, - const QgsDataProvider::ProviderOptions &providerOptions, - QgsDataProvider::ReadFlags flags ); - QString name() const override; - QString description() const override; - QgsRectangle extent() const override; - bool renderInPreview( const QgsDataProvider::PreviewContext &context ) override; - - //! Renders the source path for the data - virtual QString sourcePath() const = 0; - - //! Returns a clone of the data provider - virtual QgsVectorTileDataProvider *clone() const = 0 SIP_FACTORY; - - /** - * Returns TRUE if the provider supports async tile reading. - * - * The default implementation returns FALSE. - */ - virtual bool supportsAsync() const; - - //! Returns raw tile data for a single tile - virtual QByteArray readTile( const QgsTileMatrix &tileMatrix, const QgsTileXYZ &id, QgsFeedback *feedback = nullptr ) const = 0; - - //! Returns raw tile data for a range of tiles - virtual QList readTiles( const QgsTileMatrix &, const QVector &tiles, QgsFeedback *feedback = nullptr ) const = 0; - - /** - * Returns a network request for a tile. - * - * The default implementation returns an invalid request. - */ - virtual QNetworkRequest tileRequest( const QgsTileMatrix &tileMatrix, const QgsTileXYZ &id, Qgis::RendererUsage usage ) const; -}; - -class QgsXyzVectorTileDataProvider : public QgsVectorTileDataProvider -{ - Q_OBJECT - - public: - QgsXyzVectorTileDataProvider( const QString &uri, - const QgsDataProvider::ProviderOptions &providerOptions, - QgsDataProvider::ReadFlags flags ); - - QgsVectorTileDataProvider *clone() const override; - QString sourcePath() const override; - bool isValid() const override; - QgsCoordinateReferenceSystem crs() const override; - bool supportsAsync() const override; - QByteArray readTile( const QgsTileMatrix &tileMatrix, const QgsTileXYZ &id, QgsFeedback *feedback = nullptr ) const override; - QList readTiles( const QgsTileMatrix &, const QVector &tiles, QgsFeedback *feedback = nullptr ) const override; - QNetworkRequest tileRequest( const QgsTileMatrix &tileMatrix, const QgsTileXYZ &id, Qgis::RendererUsage usage ) const override; - - protected: - - QString mAuthCfg; - QgsHttpHeaders mHeaders; - - private: - - //! Returns raw tile data for a single tile, doing a HTTP request. Block the caller until tile data are downloaded. - static QByteArray loadFromNetwork( const QgsTileXYZ &id, - const QgsTileMatrix &tileMatrix, - const QString &requestUrl, - const QString &authid, - const QgsHttpHeaders &headers, - QgsFeedback *feedback = nullptr ); - -}; - -class QgsMbTilesVectorTileDataProvider : public QgsVectorTileDataProvider -{ - Q_OBJECT - - public: - QgsMbTilesVectorTileDataProvider( const QString &uri, - const QgsDataProvider::ProviderOptions &providerOptions, - QgsDataProvider::ReadFlags flags ); - - QgsVectorTileDataProvider *clone() const override; - QString sourcePath() const override; - bool isValid() const override; - QgsCoordinateReferenceSystem crs() const override; - QByteArray readTile( const QgsTileMatrix &tileMatrix, const QgsTileXYZ &id, QgsFeedback *feedback = nullptr ) const override; - QList readTiles( const QgsTileMatrix &, const QVector &tiles, QgsFeedback *feedback = nullptr ) const override; - - private: - - //! Returns raw tile data for a single tile loaded from MBTiles file - static QByteArray loadFromMBTiles( QgsMbTiles &mbTileReader, const QgsTileXYZ &id, QgsFeedback *feedback = nullptr ); - -}; - -class QgsVtpkTiles; - -class QgsVtpkVectorTileDataProvider : public QgsVectorTileDataProvider -{ - Q_OBJECT - - public: - QgsVtpkVectorTileDataProvider( const QString &uri, - const QgsDataProvider::ProviderOptions &providerOptions, - QgsDataProvider::ReadFlags flags ); - - QgsVectorTileDataProvider *clone() const override; - QString sourcePath() const override; - bool isValid() const override; - QgsCoordinateReferenceSystem crs() const override; - QByteArray readTile( const QgsTileMatrix &tileMatrix, const QgsTileXYZ &id, QgsFeedback *feedback = nullptr ) const override; - QList readTiles( const QgsTileMatrix &, const QVector &tiles, QgsFeedback *feedback = nullptr ) const override; - - private: - - //! Returns raw tile data for a single tile loaded from VTPK file - static QByteArray loadFromVtpk( QgsVtpkTiles &vtpkTileReader, const QgsTileXYZ &id, QgsFeedback *feedback = nullptr ); - -}; - -class QgsArcGisVectorTileServiceDataProvider : public QgsXyzVectorTileDataProvider -{ - Q_OBJECT - - public: - QgsArcGisVectorTileServiceDataProvider( const QString &uri, - const QString &sourcePath, - const QgsDataProvider::ProviderOptions &providerOptions, - QgsDataProvider::ReadFlags flags ); - QgsVectorTileDataProvider *clone() const override; - QString sourcePath() const override; - bool isValid() const override; - - private: - - QString mSourcePath; -}; - -///@endcond -#endif - - #endif // QGSVECTORTILELAYER_H diff --git a/src/core/vectortile/qgsvectortilelayerrenderer.cpp b/src/core/vectortile/qgsvectortilelayerrenderer.cpp index 36bdcd45637..af0eddd8293 100644 --- a/src/core/vectortile/qgsvectortilelayerrenderer.cpp +++ b/src/core/vectortile/qgsvectortilelayerrenderer.cpp @@ -14,24 +14,21 @@ ***************************************************************************/ #include "qgsvectortilelayerrenderer.h" - -#include -#include - #include "qgsexpressioncontextutils.h" #include "qgsfeedback.h" #include "qgslogger.h" - -#include "qgsvectortilebasicrenderer.h" #include "qgsvectortilemvtdecoder.h" #include "qgsvectortilelayer.h" #include "qgsvectortileloader.h" #include "qgsvectortileutils.h" - #include "qgslabelingengine.h" #include "qgsvectortilelabeling.h" #include "qgsmapclippingutils.h" #include "qgsrendercontext.h" +#include "qgsvectortiledataprovider.h" + +#include +#include QgsVectorTileLayerRenderer::QgsVectorTileLayerRenderer( QgsVectorTileLayer *layer, QgsRenderContext &context ) : QgsMapLayerRenderer( layer->id(), &context ) diff --git a/src/core/vectortile/qgsvectortilelayerrenderer.h b/src/core/vectortile/qgsvectortilelayerrenderer.h index e400e3d641d..95ba035fd0c 100644 --- a/src/core/vectortile/qgsvectortilelayerrenderer.h +++ b/src/core/vectortile/qgsvectortilelayerrenderer.h @@ -19,15 +19,15 @@ #define SIP_NO_FILE #include "qgsmaplayerrenderer.h" +#include "qgsvectortilerenderer.h" +#include "qgsmapclippingregion.h" +#include "qgsvectortilematrixset.h" class QgsVectorTileLayer; class QgsVectorTileRawData; class QgsVectorTileLabelProvider; class QgsVectorTileDataProvider; -#include "qgsvectortilerenderer.h" -#include "qgsmapclippingregion.h" -#include "qgsvectortilematrixset.h" /** * \ingroup core diff --git a/src/core/vectortile/qgsvectortileloader.cpp b/src/core/vectortile/qgsvectortileloader.cpp index 0543809e7f7..6c25d037f3c 100644 --- a/src/core/vectortile/qgsvectortileloader.cpp +++ b/src/core/vectortile/qgsvectortileloader.cpp @@ -14,17 +14,16 @@ ***************************************************************************/ #include "qgsvectortileloader.h" - -#include - #include "qgslogger.h" #include "qgsvectortileutils.h" #include "qgsapplication.h" -#include "qgsvectortilelayer.h" +#include "qgsvectortiledataprovider.h" #include "qgsfeedback.h" - #include "qgstiledownloadmanager.h" +#include + + QgsVectorTileLoader::QgsVectorTileLoader( const QgsVectorTileDataProvider *provider, const QgsTileMatrix &tileMatrix, const QgsTileRange &range, const QPointF &viewCenter, QgsFeedback *feedback, Qgis::RendererUsage usage ) : mEventLoop( new QEventLoop ) , mFeedback( feedback ) diff --git a/src/core/vectortile/qgsvectortileloader.h b/src/core/vectortile/qgsvectortileloader.h index ba28c1752fd..09a7c79a72c 100644 --- a/src/core/vectortile/qgsvectortileloader.h +++ b/src/core/vectortile/qgsvectortileloader.h @@ -20,9 +20,13 @@ #include "qgstiles.h" -class QByteArray; class QgsFeedback; +class QgsTileDownloadManagerReply; +class QgsVectorTileDataProvider; +class QByteArray; +class QNetworkReply; +class QEventLoop; /** * \ingroup core @@ -44,14 +48,6 @@ class QgsVectorTileRawData }; -class QNetworkReply; -class QEventLoop; - -class QgsVtpkTiles; - -class QgsTileDownloadManagerReply; -class QgsVectorTileDataProvider; - /** * \ingroup core * \brief The loader class takes care of loading raw vector tile data from a tile source. diff --git a/src/core/vectortile/qgsvtpkvectortiledataprovider.cpp b/src/core/vectortile/qgsvtpkvectortiledataprovider.cpp new file mode 100644 index 00000000000..2ca16700547 --- /dev/null +++ b/src/core/vectortile/qgsvtpkvectortiledataprovider.cpp @@ -0,0 +1,110 @@ +/*************************************************************************** + qgsvtpkvectortiledataprovider.cpp + -------------------------------------- + Date : March 2020 + Copyright : (C) 2020 by Martin Dobias + Email : wonder dot sk at gmail dot com + *************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#include "qgsvtpkvectortiledataprovider.h" +#include "qgsthreadingutils.h" +#include "qgsvtpktiles.h" +#include "qgsvectortileloader.h" + +///@cond PRIVATE + +QgsVtpkVectorTileDataProvider::QgsVtpkVectorTileDataProvider( const QString &uri, const ProviderOptions &providerOptions, ReadFlags flags ) + : QgsVectorTileDataProvider( uri, providerOptions, flags ) +{ + +} + +QgsVectorTileDataProvider *QgsVtpkVectorTileDataProvider::clone() const +{ + QGIS_PROTECT_QOBJECT_THREAD_ACCESS + + ProviderOptions options; + options.transformContext = transformContext(); + return new QgsVtpkVectorTileDataProvider( dataSourceUri(), options, mReadFlags ); +} + +QString QgsVtpkVectorTileDataProvider::sourcePath() const +{ + QGIS_PROTECT_QOBJECT_THREAD_ACCESS + + QgsDataSourceUri dsUri; + dsUri.setEncodedUri( dataSourceUri() ); + return dsUri.param( QStringLiteral( "url" ) ); +} + +bool QgsVtpkVectorTileDataProvider::isValid() const +{ + QGIS_PROTECT_QOBJECT_THREAD_ACCESS + + return true; +} + +QgsCoordinateReferenceSystem QgsVtpkVectorTileDataProvider::crs() const +{ + QGIS_PROTECT_QOBJECT_THREAD_ACCESS + + return QgsCoordinateReferenceSystem( QStringLiteral( "EPSG:3857" ) ); +} + +QByteArray QgsVtpkVectorTileDataProvider::readTile( const QgsTileMatrix &, const QgsTileXYZ &id, QgsFeedback *feedback ) const +{ + QGIS_PROTECT_QOBJECT_THREAD_ACCESS + + QgsDataSourceUri dsUri; + dsUri.setEncodedUri( dataSourceUri() ); + QgsVtpkTiles reader( dsUri.param( QStringLiteral( "url" ) ) ); + reader.open(); + return loadFromVtpk( reader, id, feedback ); +} + +QList QgsVtpkVectorTileDataProvider::readTiles( const QgsTileMatrix &, const QVector &tiles, QgsFeedback *feedback ) const +{ + QGIS_PROTECT_QOBJECT_THREAD_ACCESS + + QgsDataSourceUri dsUri; + dsUri.setEncodedUri( dataSourceUri() ); + + QgsVtpkTiles reader( dsUri.param( QStringLiteral( "url" ) ) ); + reader.open(); + + QList rawTiles; + rawTiles.reserve( tiles.size() ); + for ( QgsTileXYZ id : std::as_const( tiles ) ) + { + if ( feedback && feedback->isCanceled() ) + break; + + const QByteArray rawData = loadFromVtpk( reader, id, feedback ); + if ( !rawData.isEmpty() ) + { + rawTiles.append( QgsVectorTileRawData( id, rawData ) ); + } + } + return rawTiles; +} + +QByteArray QgsVtpkVectorTileDataProvider::loadFromVtpk( QgsVtpkTiles &vtpkTileReader, const QgsTileXYZ &id, QgsFeedback * ) +{ + const QByteArray tileData = vtpkTileReader.tileData( id.zoomLevel(), id.column(), id.row() ); + if ( tileData.isEmpty() ) + { + return QByteArray(); + } + return tileData; +} + +///@endcond + + diff --git a/src/core/vectortile/qgsvtpkvectortiledataprovider.h b/src/core/vectortile/qgsvtpkvectortiledataprovider.h new file mode 100644 index 00000000000..7795305cde0 --- /dev/null +++ b/src/core/vectortile/qgsvtpkvectortiledataprovider.h @@ -0,0 +1,54 @@ +/*************************************************************************** + qgsvtpkvectortiledataprovider.h + -------------------------------------- + Date : March 2020 + Copyright : (C) 2020 by Martin Dobias + Email : wonder dot sk at gmail dot com + *************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#ifndef QGSVTPKVECTORTILEDATAPROVIDER_H +#define QGSVTPKVECTORTILEDATAPROVIDER_H + +#include "qgis_core.h" +#include "qgis_sip.h" +#include "qgsvectortiledataprovider.h" + +#define SIP_NO_FILE + +///@cond PRIVATE + +class QgsVtpkTiles; + +class QgsVtpkVectorTileDataProvider : public QgsVectorTileDataProvider +{ + Q_OBJECT + + public: + QgsVtpkVectorTileDataProvider( const QString &uri, + const QgsDataProvider::ProviderOptions &providerOptions, + QgsDataProvider::ReadFlags flags ); + + QgsVectorTileDataProvider *clone() const override; + QString sourcePath() const override; + bool isValid() const override; + QgsCoordinateReferenceSystem crs() const override; + QByteArray readTile( const QgsTileMatrix &tileMatrix, const QgsTileXYZ &id, QgsFeedback *feedback = nullptr ) const override; + QList readTiles( const QgsTileMatrix &, const QVector &tiles, QgsFeedback *feedback = nullptr ) const override; + + private: + + //! Returns raw tile data for a single tile loaded from VTPK file + static QByteArray loadFromVtpk( QgsVtpkTiles &vtpkTileReader, const QgsTileXYZ &id, QgsFeedback *feedback = nullptr ); + +}; + +///@endcond + +#endif // QGSVTPKVECTORTILEDATAPROVIDER_H diff --git a/src/core/vectortile/qgsxyzvectortiledataprovider.cpp b/src/core/vectortile/qgsxyzvectortiledataprovider.cpp new file mode 100644 index 00000000000..00318a5fc8a --- /dev/null +++ b/src/core/vectortile/qgsxyzvectortiledataprovider.cpp @@ -0,0 +1,170 @@ +/*************************************************************************** + qgsxyzvectortiledataprovider.cpp + -------------------------------------- + Date : March 2020 + Copyright : (C) 2020 by Martin Dobias + Email : wonder dot sk at gmail dot com + *************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#include "qgsxyzvectortiledataprovider.h" +#include "qgsthreadingutils.h" +#include "qgstiles.h" +#include "qgsvectortileloader.h" +#include "qgsvectortileutils.h" +#include "qgsnetworkaccessmanager.h" +#include "qgsapplication.h" +#include "qgsauthmanager.h" +#include "qgsmessagelog.h" +#include "qgsblockingnetworkrequest.h" +#include "qgslogger.h" + +#include + +///@cond PRIVATE + +QgsXyzVectorTileDataProvider::QgsXyzVectorTileDataProvider( const QString &uri, const ProviderOptions &providerOptions, ReadFlags flags ) + : QgsVectorTileDataProvider( uri, providerOptions, flags ) +{ + QgsDataSourceUri dsUri; + dsUri.setEncodedUri( uri ); + + mAuthCfg = dsUri.authConfigId(); + mHeaders = dsUri.httpHeaders(); +} + +QgsVectorTileDataProvider *QgsXyzVectorTileDataProvider::clone() const +{ + QGIS_PROTECT_QOBJECT_THREAD_ACCESS + + ProviderOptions options; + options.transformContext = transformContext(); + return new QgsXyzVectorTileDataProvider( dataSourceUri(), options, mReadFlags ); +} + +QString QgsXyzVectorTileDataProvider::sourcePath() const +{ + QGIS_PROTECT_QOBJECT_THREAD_ACCESS + + QgsDataSourceUri dsUri; + dsUri.setEncodedUri( dataSourceUri() ); + return dsUri.param( QStringLiteral( "url" ) ); +} + +bool QgsXyzVectorTileDataProvider::isValid() const +{ + QGIS_PROTECT_QOBJECT_THREAD_ACCESS + + return true; +} + +QgsCoordinateReferenceSystem QgsXyzVectorTileDataProvider::crs() const +{ + QGIS_PROTECT_QOBJECT_THREAD_ACCESS + + return QgsCoordinateReferenceSystem( QStringLiteral( "EPSG:3857" ) ); +} + +bool QgsXyzVectorTileDataProvider::supportsAsync() const +{ + return true; +} + +QByteArray QgsXyzVectorTileDataProvider::readTile( const QgsTileMatrix &tileMatrix, const QgsTileXYZ &id, QgsFeedback *feedback ) const +{ + return loadFromNetwork( id, tileMatrix, sourcePath(), mAuthCfg, mHeaders, feedback ); +} + +QList QgsXyzVectorTileDataProvider::readTiles( const QgsTileMatrix &tileMatrix, const QVector &tiles, QgsFeedback *feedback ) const +{ + QList rawTiles; + rawTiles.reserve( tiles.size() ); + const QString source = sourcePath(); + for ( QgsTileXYZ id : std::as_const( tiles ) ) + { + if ( feedback && feedback->isCanceled() ) + break; + + const QByteArray rawData = loadFromNetwork( id, tileMatrix, source, mAuthCfg, mHeaders, feedback ); + if ( !rawData.isEmpty() ) + { + rawTiles.append( QgsVectorTileRawData( id, rawData ) ); + } + } + return rawTiles; +} + +QNetworkRequest QgsXyzVectorTileDataProvider::tileRequest( const QgsTileMatrix &tileMatrix, const QgsTileXYZ &id, Qgis::RendererUsage usage ) const +{ + QString urlTemplate = sourcePath(); + + if ( urlTemplate.contains( QLatin1String( "{usage}" ) ) ) + { + switch ( usage ) + { + case Qgis::RendererUsage::View: + urlTemplate.replace( QLatin1String( "{usage}" ), QLatin1String( "view" ) ); + break; + case Qgis::RendererUsage::Export: + urlTemplate.replace( QLatin1String( "{usage}" ), QLatin1String( "export" ) ); + break; + case Qgis::RendererUsage::Unknown: + urlTemplate.replace( QLatin1String( "{usage}" ), QString() ); + break; + } + } + + const QString url = QgsVectorTileUtils::formatXYZUrlTemplate( urlTemplate, id, tileMatrix ); + + QNetworkRequest request( url ); + QgsSetRequestInitiatorClass( request, QStringLiteral( "QgsXyzVectorTileDataProvider" ) ); + QgsSetRequestInitiatorId( request, id.toString() ); + + request.setAttribute( static_cast( QNetworkRequest::User + 1 ), id.column() ); + request.setAttribute( static_cast( QNetworkRequest::User + 2 ), id.row() ); + request.setAttribute( static_cast( QNetworkRequest::User + 3 ), id.zoomLevel() ); + + request.setAttribute( QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::PreferCache ); + request.setAttribute( QNetworkRequest::CacheSaveControlAttribute, true ); + + mHeaders.updateNetworkRequest( request ); + + if ( !mAuthCfg.isEmpty() && !QgsApplication::authManager()->updateNetworkRequest( request, mAuthCfg ) ) + { + QgsMessageLog::logMessage( tr( "network request update failed for authentication config" ), tr( "Network" ) ); + } + + return request; +} + +QByteArray QgsXyzVectorTileDataProvider::loadFromNetwork( const QgsTileXYZ &id, const QgsTileMatrix &tileMatrix, const QString &requestUrl, const QString &authid, const QgsHttpHeaders &headers, QgsFeedback *feedback ) +{ + QString url = QgsVectorTileUtils::formatXYZUrlTemplate( requestUrl, id, tileMatrix ); + QNetworkRequest nr; + nr.setUrl( QUrl( url ) ); + + headers.updateNetworkRequest( nr ); + + QgsBlockingNetworkRequest req; + req.setAuthCfg( authid ); + QgsDebugMsgLevel( QStringLiteral( "Blocking request: " ) + url, 2 ); + QgsBlockingNetworkRequest::ErrorCode errCode = req.get( nr, false, feedback ); + if ( errCode != QgsBlockingNetworkRequest::NoError ) + { + QgsDebugMsg( QStringLiteral( "Request failed: " ) + url ); + return QByteArray(); + } + QgsNetworkReplyContent reply = req.reply(); + QgsDebugMsgLevel( QStringLiteral( "Request successful, content size %1" ).arg( reply.content().size() ), 2 ); + return reply.content(); +} + +///@endcond + + diff --git a/src/core/vectortile/qgsxyzvectortiledataprovider.h b/src/core/vectortile/qgsxyzvectortiledataprovider.h new file mode 100644 index 00000000000..dea63faa198 --- /dev/null +++ b/src/core/vectortile/qgsxyzvectortiledataprovider.h @@ -0,0 +1,63 @@ +/*************************************************************************** + qgsxyzvectortiledataprovider.h + -------------------------------------- + Date : March 2020 + Copyright : (C) 2020 by Martin Dobias + Email : wonder dot sk at gmail dot com + *************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#ifndef QGSXYZVECTORTILEDATAPROVIDER_H +#define QGSXYZVECTORTILEDATAPROVIDER_H + +#include "qgis_core.h" +#include "qgis_sip.h" +#include "qgsvectortiledataprovider.h" + +#define SIP_NO_FILE + +///@cond PRIVATE +class CORE_EXPORT QgsXyzVectorTileDataProvider : public QgsVectorTileDataProvider +{ + Q_OBJECT + + public: + QgsXyzVectorTileDataProvider( const QString &uri, + const QgsDataProvider::ProviderOptions &providerOptions, + QgsDataProvider::ReadFlags flags ); + + QgsVectorTileDataProvider *clone() const override; + QString sourcePath() const override; + bool isValid() const override; + QgsCoordinateReferenceSystem crs() const override; + bool supportsAsync() const override; + QByteArray readTile( const QgsTileMatrix &tileMatrix, const QgsTileXYZ &id, QgsFeedback *feedback = nullptr ) const override; + QList readTiles( const QgsTileMatrix &, const QVector &tiles, QgsFeedback *feedback = nullptr ) const override; + QNetworkRequest tileRequest( const QgsTileMatrix &tileMatrix, const QgsTileXYZ &id, Qgis::RendererUsage usage ) const override; + + protected: + + QString mAuthCfg; + QgsHttpHeaders mHeaders; + + private: + + //! Returns raw tile data for a single tile, doing a HTTP request. Block the caller until tile data are downloaded. + static QByteArray loadFromNetwork( const QgsTileXYZ &id, + const QgsTileMatrix &tileMatrix, + const QString &requestUrl, + const QString &authid, + const QgsHttpHeaders &headers, + QgsFeedback *feedback = nullptr ); + +}; + +///@endcond + +#endif // QGSXYZVECTORTILEDATAPROVIDER_H