diff --git a/data/maps/earth/srtm2/srtm2.dgml b/data/maps/earth/srtm2/srtm2.dgml
index 8ce7deb78..e2ff45502 100644
--- a/data/maps/earth/srtm2/srtm2.dgml
+++ b/data/maps/earth/srtm2/srtm2.dgml
@@ -1,46 +1,45 @@
SRTM Data
earth
srtm2
false
900
21000
false
diff --git a/src/lib/marble/ServerLayout.cpp b/src/lib/marble/ServerLayout.cpp
index eff081dae..63a8a24d3 100644
--- a/src/lib/marble/ServerLayout.cpp
+++ b/src/lib/marble/ServerLayout.cpp
@@ -1,232 +1,236 @@
//
// This file is part of the Marble Virtual Globe.
//
// This program is free software licensed under the GNU LGPL. You can
// find a copy of this license in LICENSE.txt in the top directory of
// the source code.
//
// Copyright 2010,2011 Bernhard Beschow
//
// Own
#include "ServerLayout.h"
#include "GeoSceneTileDataset.h"
#include "MarbleGlobal.h"
#include "TileId.h"
#include
#include
namespace Marble
{
ServerLayout::ServerLayout( GeoSceneTileDataset *textureLayer )
: m_textureLayer( textureLayer )
{
}
ServerLayout::~ServerLayout()
{
}
MarbleServerLayout::MarbleServerLayout( GeoSceneTileDataset *textureLayer )
: ServerLayout( textureLayer )
{
}
QUrl MarbleServerLayout::downloadUrl( const QUrl &prototypeUrl, const TileId &id ) const
{
- const QString path = QString( "%1maps/%2/%3/%4/%4_%5.%6" )
+ const QString path = QString( "%1/%2/%3/%3_%4.%5" )
.arg( prototypeUrl.path() )
- .arg( m_textureLayer->sourceDir() )
.arg( id.zoomLevel() )
.arg( id.y(), tileDigits, 10, QChar('0') )
.arg( id.x(), tileDigits, 10, QChar('0') )
.arg( m_textureLayer->fileFormat().toLower() );
QUrl url = prototypeUrl;
url.setPath( path );
return url;
}
QString MarbleServerLayout::name() const
{
return "Marble";
}
+QString ServerLayout::sourceDir() const
+{
+ return m_textureLayer ? m_textureLayer->sourceDir() : QString();
+}
+
OsmServerLayout::OsmServerLayout( GeoSceneTileDataset *textureLayer )
: ServerLayout( textureLayer )
{
}
QUrl OsmServerLayout::downloadUrl( const QUrl &prototypeUrl, const TileId &id ) const
{
const QString suffix = m_textureLayer->fileFormat().toLower();
const QString path = QString( "%1/%2/%3.%4" ).arg( id.zoomLevel() )
.arg( id.x() )
.arg( id.y() )
.arg( suffix );
QUrl url = prototypeUrl;
url.setPath( url.path() + path );
return url;
}
QString OsmServerLayout::name() const
{
return "OpenStreetMap";
}
CustomServerLayout::CustomServerLayout( GeoSceneTileDataset *texture )
: ServerLayout( texture )
{
}
QUrl CustomServerLayout::downloadUrl( const QUrl &prototypeUrl, const TileId &id ) const
{
const GeoDataLatLonBox bbox = id.toLatLonBox( m_textureLayer );
QString urlStr = prototypeUrl.toString( QUrl::DecodeReserved );
urlStr.replace( "{zoomLevel}", QString::number( id.zoomLevel() ) );
urlStr.replace( "{x}", QString::number( id.x() ) );
urlStr.replace( "{y}", QString::number( id.y() ) );
urlStr.replace( "{west}", QString::number( bbox.west( GeoDataCoordinates::Degree ), 'f', 12 ) );
urlStr.replace( "{south}", QString::number( bbox.south( GeoDataCoordinates::Degree ), 'f', 12 ) );
urlStr.replace( "{east}", QString::number( bbox.east( GeoDataCoordinates::Degree ), 'f', 12 ) );
urlStr.replace( "{north}", QString::number( bbox.north( GeoDataCoordinates::Degree ), 'f', 12 ) );
return QUrl( urlStr );
}
QString CustomServerLayout::name() const
{
return "Custom";
}
WmsServerLayout::WmsServerLayout( GeoSceneTileDataset *texture )
: ServerLayout( texture )
{
}
QUrl WmsServerLayout::downloadUrl( const QUrl &prototypeUrl, const Marble::TileId &tileId ) const
{
GeoDataLatLonBox box = tileId.toLatLonBox( m_textureLayer );
QUrlQuery url(prototypeUrl.query());
url.addQueryItem( "service", "WMS" );
url.addQueryItem( "request", "GetMap" );
url.addQueryItem( "version", "1.1.1" );
if ( !url.hasQueryItem( "styles" ) )
url.addQueryItem( "styles", "" );
if ( !url.hasQueryItem( "format" ) ) {
if ( m_textureLayer->fileFormat().toLower() == "jpg" )
url.addQueryItem( "format", "image/jpeg" );
else
url.addQueryItem( "format", "image/" + m_textureLayer->fileFormat().toLower() );
}
if ( !url.hasQueryItem( "srs" ) ) {
url.addQueryItem( "srs", epsgCode() );
}
if ( !url.hasQueryItem( "layers" ) )
url.addQueryItem( "layers", m_textureLayer->name() );
url.addQueryItem( "width", QString::number( m_textureLayer->tileSize().width() ) );
url.addQueryItem( "height", QString::number( m_textureLayer->tileSize().height() ) );
url.addQueryItem( "bbox", QString( "%1,%2,%3,%4" ).arg( QString::number( box.west( GeoDataCoordinates::Degree ), 'f', 12 ) )
.arg( QString::number( box.south( GeoDataCoordinates::Degree ), 'f', 12 ) )
.arg( QString::number( box.east( GeoDataCoordinates::Degree ), 'f', 12 ) )
.arg( QString::number( box.north( GeoDataCoordinates::Degree ), 'f', 12 ) ) );
QUrl finalUrl = prototypeUrl;
finalUrl.setQuery(url);
return finalUrl;
}
QString WmsServerLayout::name() const
{
return "WebMapService";
}
QString WmsServerLayout::epsgCode() const
{
switch ( m_textureLayer->projection() ) {
case GeoSceneTileDataset::Equirectangular:
return "EPSG:4326";
case GeoSceneTileDataset::Mercator:
return "EPSG:3785";
}
Q_ASSERT( false ); // not reached
return QString();
}
QuadTreeServerLayout::QuadTreeServerLayout( GeoSceneTileDataset *textureLayer )
: ServerLayout( textureLayer )
{
}
QUrl QuadTreeServerLayout::downloadUrl( const QUrl &prototypeUrl, const Marble::TileId &id ) const
{
QString urlStr = prototypeUrl.toString( QUrl::DecodeReserved );
urlStr.replace( "{quadIndex}", encodeQuadTree( id ) );
return QUrl( urlStr );
}
QString QuadTreeServerLayout::name() const
{
return "QuadTree";
}
QString QuadTreeServerLayout::encodeQuadTree( const Marble::TileId &id )
{
QString tileNum;
for ( int i = id.zoomLevel(); i >= 0; i-- ) {
const int tileX = (id.x() >> i) % 2;
const int tileY = (id.y() >> i) % 2;
const int num = ( 2 * tileY ) + tileX;
tileNum += QString::number( num );
}
return tileNum;
}
TmsServerLayout::TmsServerLayout(GeoSceneTileDataset *textureLayer )
: ServerLayout( textureLayer )
{
}
QUrl TmsServerLayout::downloadUrl( const QUrl &prototypeUrl, const TileId &id ) const
{
const QString suffix = m_textureLayer->fileFormat().toLower();
// y coordinate in TMS start at the bottom of the map (South) and go upwards,
// opposed to OSM which start at the top.
//
// http://wiki.osgeo.org/wiki/Tile_Map_Service_Specification
int y_frombottom = ( 1<
//
#ifndef MARBLE_SERVERLAYOUT_H
#define MARBLE_SERVERLAYOUT_H
#include
namespace Marble
{
class GeoSceneTileDataset;
class TileId;
class ServerLayout
{
public:
explicit ServerLayout( GeoSceneTileDataset *textureLayer );
virtual ~ServerLayout();
/**
* Translates given tile @p id using a @p prototypeUrl into an URL
* that can be used for downloading.
*
* @param prototypeUrl prototype URL, to be completed by this method
* @param id Marble-specific ID of requested tile
* @return completed URL for requested tile id
*/
virtual QUrl downloadUrl( const QUrl &prototypeUrl, const TileId &id ) const = 0;
/**
* Returns the name of the server layout to be used as the value in the
* mode attribute in the DGML file.
*/
virtual QString name() const = 0;
+ /**
+ * Returns the sourceDir of the texture layer, or an empty string if the texture layer is 0
+ */
+ QString sourceDir() const;
+
protected:
GeoSceneTileDataset *const m_textureLayer;
};
class MarbleServerLayout : public ServerLayout
{
public:
explicit MarbleServerLayout( GeoSceneTileDataset *textureLayer );
/**
* Completes the path of the @p prototypeUrl and returns it.
*/
virtual QUrl downloadUrl( const QUrl &prototypeUrl, const TileId & ) const;
virtual QString name() const;
};
class OsmServerLayout : public ServerLayout
{
public:
explicit OsmServerLayout( GeoSceneTileDataset *textureLayer );
/**
* Appends %zoomLevel/%x/%y.%suffix to the path of the @p prototypeUrl and returns
* the result.
*/
virtual QUrl downloadUrl( const QUrl &prototypeUrl, const TileId & ) const;
virtual QString name() const;
};
class CustomServerLayout : public ServerLayout
{
public:
explicit CustomServerLayout( GeoSceneTileDataset *texture );
/**
* Replaces escape sequences in the @p prototypeUrl by the values in @p id
* and returns the result.
*
* Escape sequences are: {zoomLevel}, {x}, and {y}.
*/
virtual QUrl downloadUrl( const QUrl &prototypeUrl, const TileId &id ) const;
virtual QString name() const;
};
class WmsServerLayout : public ServerLayout
{
public:
explicit WmsServerLayout( GeoSceneTileDataset *texture );
/**
* Adds WMS query items to the @p prototypeUrl and returns the result.
*
* The following items are added: service, request, version, width, height, bbox.
*
* The following items are only added if they are not already specified in the dgml file:
* styles, format, srs, layers.
*/
virtual QUrl downloadUrl( const QUrl &prototypeUrl, const Marble::TileId &tileId ) const;
virtual QString name() const;
QString epsgCode() const;
};
class QuadTreeServerLayout : public ServerLayout
{
public:
explicit QuadTreeServerLayout( GeoSceneTileDataset* textureLayer );
virtual QUrl downloadUrl( const QUrl &, const Marble::TileId & ) const;
virtual QString name() const;
private:
static QString encodeQuadTree( const Marble::TileId & );
};
class TmsServerLayout : public ServerLayout
{
public:
explicit TmsServerLayout( GeoSceneTileDataset *textureLayer );
/**
* Appends %zoomLevel/%x/2^%zoomLevel-%y-1.%suffix to the path of the @p prototypeUrl and returns
* the result.
* TMS (TileMapService) maps take the origin for y coordinate at the bottom of the map,
* as opposed to what Marble and OpenStreepMap (SlippyTiles) do.
*/
virtual QUrl downloadUrl( const QUrl &prototypeUrl, const TileId & ) const;
virtual QString name() const;
};
}
#endif
diff --git a/src/lib/marble/geodata/scene/GeoSceneTileDataset.cpp b/src/lib/marble/geodata/scene/GeoSceneTileDataset.cpp
index 6ddc0817e..18a351222 100644
--- a/src/lib/marble/geodata/scene/GeoSceneTileDataset.cpp
+++ b/src/lib/marble/geodata/scene/GeoSceneTileDataset.cpp
@@ -1,312 +1,318 @@
/*
This file is part of the Marble Virtual Globe.
This program is free software licensed under the GNU LGPL. You can
find a copy of this license in LICENSE.txt in the top directory of
the source code.
Copyright (C) 2008 Torsten Rahn
Copyright (C) 2008 Jens-Michael Hoffmann
Copyright 2012 Ander Pijoan
*/
#include "GeoSceneTileDataset.h"
#include "GeoSceneTypes.h"
#include "DownloadPolicy.h"
#include "MarbleDebug.h"
#include "MarbleDirs.h"
#include "ServerLayout.h"
#include "TileId.h"
#include
namespace Marble
{
GeoSceneTileDataset::GeoSceneTileDataset( const QString& name )
: GeoSceneAbstractDataset( name ),
m_sourceDir(),
m_installMap(),
m_storageLayoutMode(Marble),
m_serverLayout( new MarbleServerLayout( this ) ),
m_levelZeroColumns( defaultLevelZeroColumns ),
m_levelZeroRows( defaultLevelZeroRows ),
m_minimumTileLevel(0),
m_maximumTileLevel( -1 ),
m_projection( Equirectangular ),
m_blending(),
m_downloadUrls(),
m_nextUrl( m_downloadUrls.constEnd() )
{
}
GeoSceneTileDataset::~GeoSceneTileDataset()
{
qDeleteAll( m_downloadPolicies );
delete m_serverLayout;
}
const char* GeoSceneTileDataset::nodeType() const
{
return GeoSceneTypes::GeoSceneTileDatasetType;
}
QString GeoSceneTileDataset::sourceDir() const
{
return m_sourceDir;
}
void GeoSceneTileDataset::setSourceDir( const QString& sourceDir )
{
m_sourceDir = sourceDir;
}
QString GeoSceneTileDataset::installMap() const
{
return m_installMap;
}
void GeoSceneTileDataset::setInstallMap( const QString& installMap )
{
m_installMap = installMap;
}
GeoSceneTileDataset::StorageLayout GeoSceneTileDataset::storageLayout() const
{
return m_storageLayoutMode;
}
void GeoSceneTileDataset::setStorageLayout( const StorageLayout layout )
{
m_storageLayoutMode = layout;
}
void GeoSceneTileDataset::setServerLayout( const ServerLayout *layout )
{
delete m_serverLayout;
m_serverLayout = layout;
}
const ServerLayout* GeoSceneTileDataset::serverLayout() const
{
return m_serverLayout;
}
int GeoSceneTileDataset::levelZeroColumns() const
{
return m_levelZeroColumns;
}
void GeoSceneTileDataset::setLevelZeroColumns( const int columns )
{
m_levelZeroColumns = columns;
}
int GeoSceneTileDataset::levelZeroRows() const
{
return m_levelZeroRows;
}
void GeoSceneTileDataset::setLevelZeroRows( const int rows )
{
m_levelZeroRows = rows;
}
int GeoSceneTileDataset::maximumTileLevel() const
{
return m_maximumTileLevel;
}
void GeoSceneTileDataset::setMaximumTileLevel( const int maximumTileLevel )
{
m_maximumTileLevel = maximumTileLevel;
}
int GeoSceneTileDataset::minimumTileLevel() const
{
return m_minimumTileLevel;
}
void GeoSceneTileDataset::setMinimumTileLevel(int level)
{
m_minimumTileLevel = level;
}
void GeoSceneTileDataset::setTileLevels(const QString &tileLevels)
{
if (tileLevels.isEmpty()) {
m_tileLevels.clear();
return;
}
QStringList values = tileLevels.split(',');
foreach(const QString &value, values) {
bool canParse(false);
int const tileLevel = value.trimmed().toInt(&canParse);
if (canParse && tileLevel >= 0 && tileLevel < 100) {
m_tileLevels << tileLevel;
} else {
mDebug() << "Cannot parse tile level part " << value << " in " << tileLevels << ", ignoring it.";
}
}
if (!m_tileLevels.isEmpty()) {
qSort(m_tileLevels);
m_minimumTileLevel = m_tileLevels.first();
m_maximumTileLevel = m_tileLevels.last();
}
}
QVector GeoSceneTileDataset::tileLevels() const
{
return m_tileLevels;
}
QVector GeoSceneTileDataset::downloadUrls() const
{
return m_downloadUrls;
}
const QSize GeoSceneTileDataset::tileSize() const
{
if ( m_tileSize.isEmpty() ) {
const TileId id( 0, 0, 0, 0 );
QString const fileName = relativeTileFileName( id );
QFileInfo const dirInfo( fileName );
QString const path = dirInfo.isAbsolute() ? fileName : MarbleDirs::path( fileName );
QImage testTile( path );
if ( testTile.isNull() ) {
mDebug() << "Tile size is missing in dgml and no base tile found in " << themeStr();
mDebug() << "Using default tile size " << c_defaultTileSize;
m_tileSize = QSize( c_defaultTileSize, c_defaultTileSize );
} else {
m_tileSize = testTile.size();
}
if ( m_tileSize.isEmpty() ) {
mDebug() << "Tile width or height cannot be 0. Falling back to default tile size.";
m_tileSize = QSize( c_defaultTileSize, c_defaultTileSize );
}
}
Q_ASSERT( !m_tileSize.isEmpty() );
return m_tileSize;
}
void GeoSceneTileDataset::setTileSize( const QSize &tileSize )
{
if ( tileSize.isEmpty() ) {
mDebug() << "Ignoring invalid tile size " << tileSize;
} else {
m_tileSize = tileSize;
}
}
GeoSceneTileDataset::Projection GeoSceneTileDataset::projection() const
{
return m_projection;
}
void GeoSceneTileDataset::setProjection( const Projection projection )
{
m_projection = projection;
}
// Even though this method changes the internal state, it may be const
// because the compiler is forced to invoke this method for different TileIds.
QUrl GeoSceneTileDataset::downloadUrl( const TileId &id ) const
{
// default download url
- if ( m_downloadUrls.empty() )
- return m_serverLayout->downloadUrl( QUrl( "http://files.kde.org/marble/" ), id );
+ if ( m_downloadUrls.empty() ) {
+ QUrl const defaultUrl = QUrl(QString("%1/%2")
+ .arg("https://maps.kde.org")
+ .arg(m_serverLayout->sourceDir()));
+ mDebug() << "No download URL specified for tiles stored in "
+ << m_sourceDir << ", falling back to " << defaultUrl.toString();
+ return m_serverLayout->downloadUrl(defaultUrl, id);
+ }
if ( m_nextUrl == m_downloadUrls.constEnd() )
m_nextUrl = m_downloadUrls.constBegin();
const QUrl url = m_serverLayout->downloadUrl( *m_nextUrl, id );
++m_nextUrl;
return url;
}
void GeoSceneTileDataset::addDownloadUrl( const QUrl & url )
{
m_downloadUrls.append( url );
// FIXME: this could be done only once
m_nextUrl = m_downloadUrls.constBegin();
}
QString GeoSceneTileDataset::relativeTileFileName( const TileId &id ) const
{
const QString suffix = fileFormat().toLower();
QString relFileName;
switch ( m_storageLayoutMode ) {
default:
mDebug() << Q_FUNC_INFO << "Invalid storage layout mode! Falling back to default.";
case GeoSceneTileDataset::Marble:
relFileName = QString( "%1/%2/%3/%3_%4.%5" )
.arg( themeStr() )
.arg( id.zoomLevel() )
.arg( id.y(), tileDigits, 10, QChar('0') )
.arg( id.x(), tileDigits, 10, QChar('0') )
.arg( suffix );
break;
case GeoSceneTileDataset::OpenStreetMap:
relFileName = QString( "%1/%2/%3/%4.%5" )
.arg( themeStr() )
.arg( id.zoomLevel() )
.arg( id.x() )
.arg( id.y() )
.arg( suffix );
break;
case GeoSceneTileDataset::TileMapService:
relFileName = QString( "%1/%2/%3/%4.%5" )
.arg( themeStr() )
.arg( id.zoomLevel() )
.arg( id.x() )
.arg( ( 1< GeoSceneTileDataset::downloadPolicies() const
{
return m_downloadPolicies;
}
void GeoSceneTileDataset::addDownloadPolicy( const DownloadUsage usage, const int maximumConnections )
{
DownloadPolicy * const policy = new DownloadPolicy( DownloadPolicyKey( hostNames(), usage ));
policy->setMaximumConnections( maximumConnections );
m_downloadPolicies.append( policy );
mDebug() << "added download policy" << hostNames() << usage << maximumConnections;
}
QStringList GeoSceneTileDataset::hostNames() const
{
QStringList result;
QVector::const_iterator pos = m_downloadUrls.constBegin();
QVector::const_iterator const end = m_downloadUrls.constEnd();
for (; pos != end; ++pos )
result.append( (*pos).host() );
return result;
}
}