File indexing completed on 2024-04-14 03:48:04

0001 // SPDX-License-Identifier: LGPL-2.1-or-later
0002 //
0003 // SPDX-FileCopyrightText: 2010, 2011 Bernhard Beschow <bbeschow@cs.tu-berlin.de>
0004 //
0005 
0006 // Own
0007 #include "ServerLayout.h"
0008 
0009 #include "GeoSceneTileDataset.h"
0010 #include "GeoDataLatLonBox.h"
0011 #include "MarbleGlobal.h"
0012 #include "TileId.h"
0013 
0014 #include <QUrlQuery>
0015 
0016 #include <cmath>
0017 
0018 namespace Marble
0019 {
0020 
0021 ServerLayout::ServerLayout( GeoSceneTileDataset *textureLayer )
0022     : m_textureLayer( textureLayer )
0023 {
0024 }
0025 
0026 ServerLayout::~ServerLayout()
0027 {
0028 }
0029 
0030 MarbleServerLayout::MarbleServerLayout( GeoSceneTileDataset *textureLayer )
0031     : ServerLayout( textureLayer )
0032 {
0033 }
0034 
0035 QUrl MarbleServerLayout::downloadUrl( const QUrl &prototypeUrl, const TileId &id ) const
0036 {
0037     const QString path = QString( "%1/%2/%3/%3_%4.%5" )
0038         .arg( prototypeUrl.path() )
0039         .arg( id.zoomLevel() )
0040         .arg(id.y(), tileDigits, 10, QLatin1Char('0'))
0041         .arg(id.x(), tileDigits, 10, QLatin1Char('0'))
0042         .arg( m_textureLayer->fileFormat().toLower() );
0043 
0044     QUrl url = prototypeUrl;
0045     url.setPath( path );
0046 
0047     return url;
0048 }
0049 
0050 QString MarbleServerLayout::name() const
0051 {
0052     return "Marble";
0053 }
0054 
0055 QString ServerLayout::sourceDir() const
0056 {
0057     return m_textureLayer ? m_textureLayer->sourceDir() : QString();
0058 }
0059 
0060 
0061 OsmServerLayout::OsmServerLayout( GeoSceneTileDataset *textureLayer )
0062     : ServerLayout( textureLayer )
0063 {
0064 }
0065 
0066 QUrl OsmServerLayout::downloadUrl( const QUrl &prototypeUrl, const TileId &id ) const
0067 {
0068     const QString suffix = m_textureLayer->fileFormat().toLower();
0069     const QString path = QString( "%1/%2/%3.%4" ).arg( id.zoomLevel() )
0070                                                  .arg( id.x() )
0071                                                  .arg( id.y() )
0072                                                  .arg( suffix );
0073 
0074     QUrl url = prototypeUrl;
0075     url.setPath( url.path() + path );
0076 
0077     return url;
0078 }
0079 
0080 QString OsmServerLayout::name() const
0081 {
0082     return "OpenStreetMap";
0083 }
0084 
0085 
0086 CustomServerLayout::CustomServerLayout( GeoSceneTileDataset *texture )
0087     : ServerLayout( texture )
0088 {
0089 }
0090 
0091 QUrl CustomServerLayout::downloadUrl( const QUrl &prototypeUrl, const TileId &id ) const
0092 {
0093     const GeoDataLatLonBox bbox = m_textureLayer->tileProjection()->geoCoordinates(id);
0094 
0095     QString urlStr = prototypeUrl.toString( QUrl::DecodeReserved );
0096 
0097     urlStr.replace( "{z}", QString::number( id.zoomLevel() ) );
0098     urlStr.replace( "{zoomLevel}", QString::number( id.zoomLevel() ) );
0099     urlStr.replace( "{x}", QString::number( id.x() ) );
0100     urlStr.replace( "{y}", QString::number( id.y() ) );
0101     urlStr.replace( "{west}", QString::number( bbox.west( GeoDataCoordinates::Degree ), 'f', 12 ) );
0102     urlStr.replace( "{south}", QString::number( bbox.south( GeoDataCoordinates::Degree ), 'f', 12 ) );
0103     urlStr.replace( "{east}", QString::number( bbox.east( GeoDataCoordinates::Degree ), 'f', 12 ) );
0104     urlStr.replace( "{north}", QString::number( bbox.north( GeoDataCoordinates::Degree ), 'f', 12 ) );
0105 
0106     return QUrl( urlStr );
0107 }
0108 
0109 QString CustomServerLayout::name() const
0110 {
0111     return "Custom";
0112 }
0113 
0114 
0115 WmsServerLayout::WmsServerLayout( GeoSceneTileDataset *texture )
0116     : ServerLayout( texture )
0117 {
0118 }
0119 
0120 QUrl WmsServerLayout::downloadUrl( const QUrl &prototypeUrl, const Marble::TileId &tileId ) const
0121 {
0122     const GeoDataLatLonBox box = m_textureLayer->tileProjection()->geoCoordinates(tileId);
0123 
0124     QUrlQuery url(prototypeUrl.query());
0125     url.addQueryItem( "service", "WMS" );
0126     url.addQueryItem( "request", "GetMap" );
0127     url.addQueryItem( "version", "1.1.1" );
0128     if ( !url.hasQueryItem( "styles" ) )
0129         url.addQueryItem( "styles", "" );
0130     if ( !url.hasQueryItem( "format" ) ) {
0131         url.addQueryItem("format", QLatin1String("image/") + m_textureLayer->fileFormat().toLower());
0132     }
0133     if ( !url.hasQueryItem( "srs" ) ) {
0134         url.addQueryItem( "srs", epsgCode() );
0135     }
0136     if ( !url.hasQueryItem( "layers" ) )
0137         url.addQueryItem( "layers", m_textureLayer->name() );
0138     url.addQueryItem( "width", QString::number( m_textureLayer->tileSize().width() ) );
0139     url.addQueryItem( "height", QString::number( m_textureLayer->tileSize().height() ) );
0140     double west, south, east, north;
0141     if (m_textureLayer->tileProjectionType() == GeoSceneAbstractTileProjection::Mercator) {
0142         // Oddly enough epsg:3857 is measured in meters - so let's convert this accordingly
0143         west = (box.west( GeoDataCoordinates::Degree ) * 20037508.34) / 180;
0144         south = 20037508.34 / M_PI * log(tan(((90 + box.south( GeoDataCoordinates::Degree )) * M_PI) / 360));
0145         east = (box.east( GeoDataCoordinates::Degree ) * 20037508.34) / 180;
0146         north = 20037508.34 / M_PI * log(tan(((90 + box.north( GeoDataCoordinates::Degree )) * M_PI) / 360));
0147     }
0148     else {
0149         west = box.west( GeoDataCoordinates::Degree );
0150         south = box.south( GeoDataCoordinates::Degree );
0151         east = box.east( GeoDataCoordinates::Degree );
0152         north = box.north( GeoDataCoordinates::Degree );
0153     }
0154 
0155     url.addQueryItem( "bbox", QString( "%1,%2,%3,%4" ).arg( QString::number( west, 'f', 12 ),
0156                                                             QString::number( south, 'f', 12 ),
0157                                                             QString::number( east, 'f', 12 ),
0158                                                             QString::number( north, 'f', 12 ) ) );
0159     QUrl finalUrl = prototypeUrl;
0160     finalUrl.setQuery(url);
0161     return finalUrl;
0162 }
0163 
0164 QString WmsServerLayout::name() const
0165 {
0166     return "WebMapService";
0167 }
0168 
0169 QString WmsServerLayout::epsgCode() const
0170 {
0171     switch (m_textureLayer->tileProjectionType()) {
0172         case GeoSceneAbstractTileProjection::Equirectangular:
0173             return "EPSG:4326";
0174         case GeoSceneAbstractTileProjection::Mercator:
0175             return "EPSG:3857";
0176     }
0177 
0178     Q_ASSERT( false ); // not reached
0179     return QString();
0180 }
0181 
0182 WmtsServerLayout::WmtsServerLayout( GeoSceneTileDataset *texture )
0183     : ServerLayout( texture )
0184 {
0185 }
0186 
0187 QUrl WmtsServerLayout::downloadUrl( const QUrl &prototypeUrl, const Marble::TileId &id ) const
0188 {
0189 //    const GeoDataLatLonBox bbox = m_textureLayer->tileProjection()->geoCoordinates(id);
0190 
0191     QString urlStr = prototypeUrl.toString( QUrl::DecodeReserved );
0192 
0193     urlStr.replace(urlStr.indexOf(QLatin1String("{TileMatrix}")), QLatin1String("{TileMatrix}").size(),  QString::number(id.zoomLevel()));
0194     urlStr.replace(urlStr.indexOf(QLatin1String("{TileRow}")), QLatin1String("{TileRow}").size(),  QString::number(id.y()));
0195     urlStr.replace(urlStr.indexOf(QLatin1String("{TileCol}")), QLatin1String("{TileCol}").size(),  QString::number(id.x()));
0196     return QUrl( urlStr );
0197 }
0198 
0199 QString WmtsServerLayout::name() const
0200 {
0201     return "WebMapTileService";
0202 }
0203 
0204 QString WmtsServerLayout::epsgCode() const
0205 {
0206     switch (m_textureLayer->tileProjectionType()) {
0207         case GeoSceneAbstractTileProjection::Equirectangular:
0208             return "EPSG:4326";
0209         case GeoSceneAbstractTileProjection::Mercator:
0210             return "EPSG:3857";
0211     }
0212 
0213     Q_ASSERT( false ); // not reached
0214     return QString();
0215 }
0216 
0217 
0218 QuadTreeServerLayout::QuadTreeServerLayout( GeoSceneTileDataset *textureLayer )
0219     : ServerLayout( textureLayer )
0220 {
0221 }
0222 
0223 QUrl QuadTreeServerLayout::downloadUrl( const QUrl &prototypeUrl, const Marble::TileId &id ) const
0224 {
0225     QString urlStr = prototypeUrl.toString( QUrl::DecodeReserved );
0226 
0227     urlStr.replace( "{quadIndex}", encodeQuadTree( id ) );
0228 
0229     return QUrl( urlStr );
0230 }
0231 
0232 QString QuadTreeServerLayout::name() const
0233 {
0234     return "QuadTree";
0235 }
0236 
0237 QString QuadTreeServerLayout::encodeQuadTree( const Marble::TileId &id )
0238 {
0239     QString tileNum;
0240 
0241     for ( int i = id.zoomLevel(); i >= 0; i-- ) {
0242         const int tileX = (id.x() >> i) % 2;
0243         const int tileY = (id.y() >> i) % 2;
0244         const int num = ( 2 * tileY ) + tileX;
0245 
0246         tileNum += QString::number( num );
0247     }
0248 
0249     return tileNum;
0250 }
0251 
0252 TmsServerLayout::TmsServerLayout(GeoSceneTileDataset *textureLayer )
0253     : ServerLayout( textureLayer )
0254 {
0255 }
0256 
0257 QUrl TmsServerLayout::downloadUrl( const QUrl &prototypeUrl, const TileId &id ) const
0258 {
0259     const QString suffix = m_textureLayer->fileFormat().toLower();
0260     // y coordinate in TMS start at the bottom of the map (South) and go upwards,
0261     // opposed to OSM which start at the top.
0262     //
0263     // https://wiki.osgeo.org/wiki/Tile_Map_Service_Specification
0264     int y_frombottom = ( 1<<id.zoomLevel() ) - id.y() - 1 ;
0265 
0266     const QString path = QString( "%1/%2/%3.%4" ).arg( id.zoomLevel() )
0267                                                  .arg( id.x() )
0268                                                  .arg( y_frombottom )
0269                                                  .arg( suffix );
0270     QUrl url = prototypeUrl;
0271     url.setPath( url.path() + path );
0272 
0273     return url;
0274 }
0275 
0276 QString TmsServerLayout::name() const
0277 {
0278     return "TileMapService";
0279 }
0280 
0281 }