File indexing completed on 2025-01-05 03:59:03
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::fromUtf8( "%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 QString::fromUtf8("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::fromUtf8( "%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 QString::fromUtf8("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( QString::fromUtf8("{z}"), QString::number( id.zoomLevel() ) ); 0098 urlStr.replace( QString::fromUtf8("{zoomLevel}"), QString::number( id.zoomLevel() ) ); 0099 urlStr.replace( QString::fromUtf8("{x}"), QString::number( id.x() ) ); 0100 urlStr.replace( QString::fromUtf8("{y}"), QString::number( id.y() ) ); 0101 urlStr.replace( QString::fromUtf8("{west}"), QString::number( bbox.west( GeoDataCoordinates::Degree ), 'f', 12 ) ); 0102 urlStr.replace( QString::fromUtf8("{south}"), QString::number( bbox.south( GeoDataCoordinates::Degree ), 'f', 12 ) ); 0103 urlStr.replace( QString::fromUtf8("{east}"), QString::number( bbox.east( GeoDataCoordinates::Degree ), 'f', 12 ) ); 0104 urlStr.replace( QString::fromUtf8("{north}"), QString::number( bbox.north( GeoDataCoordinates::Degree ), 'f', 12 ) ); 0105 0106 return QUrl( urlStr ); 0107 } 0108 0109 QString CustomServerLayout::name() const 0110 { 0111 return QString::fromUtf8("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( QString::fromUtf8("service"), QString::fromUtf8("WMS") ); 0126 url.addQueryItem( QString::fromUtf8("request"), QString::fromUtf8("GetMap") ); 0127 url.addQueryItem( QString::fromUtf8("version"), QString::fromUtf8("1.1.1") ); 0128 if ( !url.hasQueryItem( QString::fromUtf8("styles") ) ) 0129 url.addQueryItem(QString::fromUtf8( "styles"), QString::fromUtf8("") ); 0130 if ( !url.hasQueryItem( QString::fromUtf8("format") ) ) { 0131 url.addQueryItem(QString::fromUtf8("format"), QLatin1String("image/") + m_textureLayer->fileFormat().toLower()); 0132 } 0133 if ( !url.hasQueryItem( QString::fromUtf8("srs") ) ) { 0134 url.addQueryItem( QString::fromUtf8("srs"), epsgCode() ); 0135 } 0136 if ( !url.hasQueryItem( QString::fromUtf8("layers") ) ) 0137 url.addQueryItem( QString::fromUtf8("layers"), m_textureLayer->name() ); 0138 url.addQueryItem( QString::fromUtf8("width"), QString::number( m_textureLayer->tileSize().width() ) ); 0139 url.addQueryItem( QString::fromUtf8("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( QString::fromUtf8("bbox"), QString::fromUtf8( "%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 QString::fromUtf8("WebMapService"); 0167 } 0168 0169 QString WmsServerLayout::epsgCode() const 0170 { 0171 switch (m_textureLayer->tileProjectionType()) { 0172 case GeoSceneAbstractTileProjection::Equirectangular: 0173 return QString::fromUtf8("EPSG:4326"); 0174 case GeoSceneAbstractTileProjection::Mercator: 0175 return QString::fromUtf8("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 QString::fromUtf8("WebMapTileService"); 0202 } 0203 0204 QString WmtsServerLayout::epsgCode() const 0205 { 0206 switch (m_textureLayer->tileProjectionType()) { 0207 case GeoSceneAbstractTileProjection::Equirectangular: 0208 return QString::fromUtf8("EPSG:4326"); 0209 case GeoSceneAbstractTileProjection::Mercator: 0210 return QString::fromUtf8("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( QString::fromUtf8("{quadIndex}"), encodeQuadTree( id ) ); 0228 0229 return QUrl( urlStr ); 0230 } 0231 0232 QString QuadTreeServerLayout::name() const 0233 { 0234 return QString::fromUtf8("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::fromUtf8( "%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 QString::fromUtf8("TileMapService"); 0279 } 0280 0281 }