diff --git a/src/lib/marble/DownloadRegion.cpp b/src/lib/marble/DownloadRegion.cpp --- a/src/lib/marble/DownloadRegion.cpp +++ b/src/lib/marble/DownloadRegion.cpp @@ -56,10 +56,10 @@ qreal const globalHeight = textureLayer->tileSize().height() * textureLayer->tileRowCount( m_visibleTileLevel ); qreal const normGlobalHeight = globalHeight / M_PI; - switch ( textureLayer->tileProjection() ) { - case GeoSceneTileDataset::Equirectangular: + switch (textureLayer->tileProjectionType()) { + case GeoSceneAbstractTileProjection::Equirectangular: return static_cast( globalHeight * 0.5 - lat * normGlobalHeight ); - case GeoSceneTileDataset::Mercator: + case GeoSceneAbstractTileProjection::Mercator: if ( fabs( lat ) < 1.4835 ) return static_cast( globalHeight * 0.5 - gdInv( lat ) * 0.5 * normGlobalHeight ); if ( lat >= +1.4835 ) diff --git a/src/lib/marble/MapThemeManager.cpp b/src/lib/marble/MapThemeManager.cpp --- a/src/lib/marble/MapThemeManager.cpp +++ b/src/lib/marble/MapThemeManager.cpp @@ -563,7 +563,7 @@ texture->setSourceDir( sourceDir ); texture->setFileFormat( extension ); texture->setInstallMap( fileName ); - texture->setProjection(GeoSceneTileDataset::Equirectangular); + texture->setTileProjection(GeoSceneAbstractTileProjection::Equirectangular); layer->addDataset(texture); diff --git a/src/lib/marble/MapWizard.cpp b/src/lib/marble/MapWizard.cpp --- a/src/lib/marble/MapWizard.cpp +++ b/src/lib/marble/MapWizard.cpp @@ -789,7 +789,7 @@ texture->setLevelZeroRows( 1 ); texture->setLevelZeroColumns( 1 ); texture->setServerLayout( new WmsServerLayout( texture ) ); - texture->setProjection( GeoSceneTileDataset::Equirectangular ); + texture->setTileProjection(GeoSceneAbstractTileProjection::Equirectangular); } else if( d->mapProviderType == MapWizardPrivate::StaticUrlMap ) @@ -803,7 +803,7 @@ texture->setLevelZeroRows( 1 ); texture->setLevelZeroColumns( 1 ); texture->setServerLayout( new CustomServerLayout( texture ) ); - texture->setProjection( GeoSceneTileDataset::Mercator ); + texture->setTileProjection(GeoSceneAbstractTileProjection::Mercator); } else if( d->mapProviderType == MapWizardPrivate::StaticImageMap ) @@ -813,7 +813,7 @@ texture->setFileFormat( d->format.toUpper() ); texture->setInstallMap(document->head()->theme() + QLatin1Char('.') + d->format); texture->setServerLayout( new MarbleServerLayout( texture ) ); - texture->setProjection( GeoSceneTileDataset::Equirectangular ); + texture->setTileProjection(GeoSceneAbstractTileProjection::Equirectangular); int imageWidth = QImage( image ).width(); int tileSize = c_defaultTileSize; diff --git a/src/lib/marble/MergedLayerDecorator.h b/src/lib/marble/MergedLayerDecorator.h --- a/src/lib/marble/MergedLayerDecorator.h +++ b/src/lib/marble/MergedLayerDecorator.h @@ -57,7 +57,7 @@ int tileRowCount( int level ) const; - GeoSceneTextureTileDataset::Projection tileProjection() const; + GeoSceneAbstractTileProjection::Type tileProjectionType() const; QSize tileSize() const; diff --git a/src/lib/marble/MergedLayerDecorator.cpp b/src/lib/marble/MergedLayerDecorator.cpp --- a/src/lib/marble/MergedLayerDecorator.cpp +++ b/src/lib/marble/MergedLayerDecorator.cpp @@ -145,11 +145,11 @@ return TileLoaderHelper::levelToRow( levelZeroRows, level ); } -GeoSceneTileDataset::Projection MergedLayerDecorator::tileProjection() const +GeoSceneAbstractTileProjection::Type MergedLayerDecorator::tileProjectionType() const { Q_ASSERT( !d->m_textureLayers.isEmpty() ); - return d->m_textureLayers.at( 0 )->projection(); + return d->m_textureLayers.at( 0 )->tileProjectionType(); } QSize MergedLayerDecorator::tileSize() const @@ -217,7 +217,8 @@ /* All tiles are covering the same area. Pick one. */ const TileId tileId = tiles.first()->id(); - GeoDataLatLonBox tileLatLonBox = tileId.toLatLonBox( findRelevantTextureLayers( tileId ).first() ); + GeoDataLatLonBox tileLatLonBox; + findRelevantTextureLayers(tileId).first()->tileProjection()->geoCoordinates(tileId, tileLatLonBox); /* Map the ground overlay to the image. */ for ( int i = 0; i < m_groundOverlays.size(); ++i ) { @@ -245,13 +246,14 @@ const qreal rad2Pixel = global_height / M_PI; qreal latPixelPosition = rad2Pixel/2 * gdInv(tileLatLonBox.north()); + const bool isMercatorTileProjection = (m_textureLayers.at( 0 )->tileProjectionType() == GeoSceneAbstractTileProjection::Mercator); for ( int y = 0; y < tileImage->height(); ++y ) { QRgb *scanLine = ( QRgb* ) ( tileImage->scanLine( y ) ); qreal lat = 0; - if (m_textureLayers.at( 0 )->projection() == GeoSceneTileDataset::Mercator) { + if (isMercatorTileProjection) { lat = gd(2 * (latPixelPosition - y) * pixel2Rad ); } else { @@ -583,10 +585,16 @@ if ( !candidate->hasMaximumTileLevel() || candidate->maximumTileLevel() >= stackedTileId.zoomLevel() ) { //check if the tile intersects with texture bounds - if ( candidate->latLonBox().isNull() - || candidate->latLonBox().intersects( stackedTileId.toLatLonBox( candidate ) ) ) - { - result.append( candidate ); + if (candidate->latLonBox().isNull()) { + result.append(candidate); + } + else { + GeoDataLatLonBox bbox; + candidate->tileProjection()->geoCoordinates(stackedTileId, bbox); + + if (candidate->latLonBox().intersects(bbox)) { + result.append( candidate ); + } } } } diff --git a/src/lib/marble/ScanlineTextureMapperContext.h b/src/lib/marble/ScanlineTextureMapperContext.h --- a/src/lib/marble/ScanlineTextureMapperContext.h +++ b/src/lib/marble/ScanlineTextureMapperContext.h @@ -73,7 +73,7 @@ private: StackedTileLoader *const m_tileLoader; - GeoSceneTileDataset::Projection const m_textureProjection; + GeoSceneAbstractTileProjection::Type const m_textureProjection; /// size of the tiles of of the current texture layer QSize const m_tileSize; @@ -123,9 +123,9 @@ inline qreal ScanlineTextureMapperContext::rad2PixelY( const qreal lat ) const { switch ( m_textureProjection ) { - case GeoSceneTileDataset::Equirectangular: + case GeoSceneAbstractTileProjection::Equirectangular: return -lat * m_normGlobalHeight; - case GeoSceneTileDataset::Mercator: + case GeoSceneAbstractTileProjection::Mercator: if ( fabs( lat ) < 1.4835 ) { // We develop the inverse Gudermannian into a MacLaurin Series: // In spite of the many elements needed to get decent diff --git a/src/lib/marble/ScanlineTextureMapperContext.cpp b/src/lib/marble/ScanlineTextureMapperContext.cpp --- a/src/lib/marble/ScanlineTextureMapperContext.cpp +++ b/src/lib/marble/ScanlineTextureMapperContext.cpp @@ -24,7 +24,7 @@ ScanlineTextureMapperContext::ScanlineTextureMapperContext( StackedTileLoader * const tileLoader, int tileLevel ) : m_tileLoader( tileLoader ), - m_textureProjection( tileLoader->tileProjection() ), // cache texture projection + m_textureProjection(tileLoader->tileProjectionType()), // cache texture projection m_tileSize( tileLoader->tileSize() ), // cache tile size m_tileLevel( tileLevel ), m_globalWidth( m_tileSize.width() * m_tileLoader->tileColumnCount( m_tileLevel ) ), diff --git a/src/lib/marble/ServerLayout.cpp b/src/lib/marble/ServerLayout.cpp --- a/src/lib/marble/ServerLayout.cpp +++ b/src/lib/marble/ServerLayout.cpp @@ -95,7 +95,8 @@ QUrl CustomServerLayout::downloadUrl( const QUrl &prototypeUrl, const TileId &id ) const { - const GeoDataLatLonBox bbox = id.toLatLonBox( m_textureLayer ); + GeoDataLatLonBox bbox; + m_textureLayer->tileProjection()->geoCoordinates(id, bbox); QString urlStr = prototypeUrl.toString( QUrl::DecodeReserved ); @@ -123,7 +124,8 @@ QUrl WmsServerLayout::downloadUrl( const QUrl &prototypeUrl, const Marble::TileId &tileId ) const { - GeoDataLatLonBox box = tileId.toLatLonBox( m_textureLayer ); + GeoDataLatLonBox box; + m_textureLayer->tileProjection()->geoCoordinates(tileId, box); QUrlQuery url(prototypeUrl.query()); url.addQueryItem( "service", "WMS" ); @@ -160,10 +162,10 @@ QString WmsServerLayout::epsgCode() const { - switch ( m_textureLayer->projection() ) { - case GeoSceneTileDataset::Equirectangular: + switch (m_textureLayer->tileProjectionType()) { + case GeoSceneAbstractTileProjection::Equirectangular: return "EPSG:4326"; - case GeoSceneTileDataset::Mercator: + case GeoSceneAbstractTileProjection::Mercator: return "EPSG:3785"; } diff --git a/src/lib/marble/StackedTileLoader.h b/src/lib/marble/StackedTileLoader.h --- a/src/lib/marble/StackedTileLoader.h +++ b/src/lib/marble/StackedTileLoader.h @@ -74,7 +74,7 @@ int tileRowCount( int level ) const; - GeoSceneTextureTileDataset::Projection tileProjection() const; + GeoSceneAbstractTileProjection::Type tileProjectionType() const; QSize tileSize() const; diff --git a/src/lib/marble/StackedTileLoader.cpp b/src/lib/marble/StackedTileLoader.cpp --- a/src/lib/marble/StackedTileLoader.cpp +++ b/src/lib/marble/StackedTileLoader.cpp @@ -77,9 +77,9 @@ return d->m_layerDecorator->tileRowCount( level ); } -GeoSceneTileDataset::Projection StackedTileLoader::tileProjection() const +GeoSceneAbstractTileProjection::Type StackedTileLoader::tileProjectionType() const { - return d->m_layerDecorator->tileProjection(); + return d->m_layerDecorator->tileProjectionType(); } QSize StackedTileLoader::tileSize() const diff --git a/src/lib/marble/TileId.h b/src/lib/marble/TileId.h --- a/src/lib/marble/TileId.h +++ b/src/lib/marble/TileId.h @@ -21,8 +21,6 @@ namespace Marble { class GeoDataCoordinates; -class GeoSceneTileDataset; -class GeoDataLatLonBox; class MARBLE_EXPORT TileId { @@ -39,14 +37,8 @@ bool operator==( TileId const& rhs ) const; bool operator<( TileId const& rhs ) const; - GeoDataLatLonBox toLatLonBox( const GeoSceneTileDataset *textureLayer ) const; static TileId fromCoordinates( const GeoDataCoordinates& coords, int zoomLevel ); - static unsigned int lon2tileX( qreal lon, unsigned int maxTileX ); - static unsigned int lat2tileY( qreal lat, unsigned int maxTileY ); - static qreal tileX2lon( unsigned int x, unsigned int maxTileX ); - static qreal tileY2lat( unsigned int y, unsigned int maxTileY ); - private: uint m_mapThemeIdHash; int m_zoomLevel; diff --git a/src/lib/marble/TileId.cpp b/src/lib/marble/TileId.cpp --- a/src/lib/marble/TileId.cpp +++ b/src/lib/marble/TileId.cpp @@ -12,9 +12,7 @@ // Own #include "TileId.h" -#include "MarbleMath.h" -#include "GeoDataLatLonBox.h" -#include "GeoSceneTileDataset.h" +#include "GeoDataCoordinates.h" #include @@ -36,32 +34,6 @@ { } -GeoDataLatLonBox TileId::toLatLonBox( const GeoSceneTileDataset *textureLayer ) const -{ - - qreal radius = ( 1 << zoomLevel() ) * textureLayer->levelZeroColumns() / 2.0; - - qreal lonLeft = ( x() - radius ) / radius * M_PI; - qreal lonRight = ( x() - radius + 1 ) / radius * M_PI; - - radius = ( 1 << zoomLevel() ) * textureLayer->levelZeroRows() / 2.0; - qreal latTop = 0; - qreal latBottom = 0; - - switch ( textureLayer->projection() ) { - case GeoSceneTileDataset::Equirectangular: - latTop = ( radius - y() ) / radius * M_PI / 2.0; - latBottom = ( radius - y() - 1 ) / radius * M_PI / 2.0; - break; - case GeoSceneTileDataset::Mercator: - latTop = atan( sinh( ( radius - y() ) / radius * M_PI ) ); - latBottom = atan( sinh( ( radius - y() - 1 ) / radius * M_PI ) ); - break; - } - - return GeoDataLatLonBox( latTop, latBottom, lonRight, lonLeft ); -} - TileId TileId::fromCoordinates(const GeoDataCoordinates &coords, int zoomLevel) { if ( zoomLevel < 0 ) { @@ -89,36 +61,6 @@ return TileId(0, zoomLevel, x, y); } -unsigned int TileId::lon2tileX( qreal lon, unsigned int maxTileX ) -{ - return (unsigned int)floor(0.5 * (lon / M_PI + 1.0) * maxTileX); -} - -unsigned int TileId::lat2tileY( qreal latitude, unsigned int maxTileY ) -{ - // We need to calculate the tile position from the latitude - // projected using the Mercator projection. This requires the inverse Gudermannian - // function which is only defined between -85°S and 85°N. Therefore in order to - // prevent undefined results we need to restrict our calculation: - qreal maxAbsLat = 85.0 * DEG2RAD; - qreal lat = (qAbs(latitude) > maxAbsLat) ? latitude/qAbs(latitude) * maxAbsLat : latitude; - return (unsigned int)floor(0.5 * (1.0 - gdInv(lat) / M_PI) * maxTileY); -} - - -qreal TileId::tileX2lon( unsigned int x, unsigned int maxTileX ) -{ - return ( (2*M_PI * x) / maxTileX - M_PI ); -} - -qreal TileId::tileY2lat( unsigned int y, unsigned int maxTileY ) -{ - return gd(M_PI * (1.0 - (2.0 * y) / maxTileY)); -} - - - - } #ifndef QT_NO_DEBUG_STREAM diff --git a/src/lib/marble/VectorTileModel.cpp b/src/lib/marble/VectorTileModel.cpp --- a/src/lib/marble/VectorTileModel.cpp +++ b/src/lib/marble/VectorTileModel.cpp @@ -115,19 +115,19 @@ m_deleteDocumentsLater = true; } - const unsigned int maxTileX = ( 1 << tileZoomLevel ) * m_layer->levelZeroColumns(); - const unsigned int maxTileY = ( 1 << tileZoomLevel ) * m_layer->levelZeroRows(); + // TODO: maxTileX should be hidden in tileProjection or tilelayer + const unsigned int maxTileX = (1 << tileZoomLevel) * m_layer->levelZeroColumns() - 1; /** LOGIC FOR DOWNLOADING ALL THE TILES THAT ARE INSIDE THE SCREEN AT THE CURRENT ZOOM LEVEL **/ // New tiles X and Y for moved screen coordinates // More info: http://wiki.openstreetmap.org/wiki/Slippy_map_tilenames#Subtiles // More info: http://wiki.openstreetmap.org/wiki/Slippy_map_tilenames#C.2FC.2B.2B - // Sometimes the formula returns wrong huge values, x and y have to be between 0 and 2^ZoomLevel - unsigned int westX = qBound( 0, TileId::lon2tileX( latLonBox.west(), maxTileX ), maxTileX); - unsigned int northY = qBound( 0, TileId::lat2tileY( latLonBox.north(), maxTileY ), maxTileY); - unsigned int eastX = qBound( 0, TileId::lon2tileX( latLonBox.east(), maxTileX ), maxTileX); - unsigned int southY = qBound( 0, TileId::lat2tileY( latLonBox.south(), maxTileY ), maxTileY ); + int westX; + int northY; + int eastX; + int southY; + m_layer->tileProjection()->tileCoordinates(latLonBox, tileZoomLevel, westX, northY, eastX, southY); // Download tiles and send them to VectorTileLayer // When changing zoom, download everything inside the screen @@ -197,7 +197,8 @@ m_deleteDocumentsLater = false; m_documents.clear(); } - GeoDataLatLonBox const boundingBox = id.toLatLonBox(m_layer); + GeoDataLatLonBox boundingBox; + m_layer->tileProjection()->geoCoordinates(id, boundingBox); m_documents[id] = QSharedPointer(new CacheDocument(document, this, boundingBox)); emit tileAdded(document); } diff --git a/src/lib/marble/geodata/CMakeLists.txt b/src/lib/marble/geodata/CMakeLists.txt --- a/src/lib/marble/geodata/CMakeLists.txt +++ b/src/lib/marble/geodata/CMakeLists.txt @@ -77,6 +77,9 @@ ) SET ( geodata_scene_SRCS + geodata/scene/GeoSceneAbstractTileProjection.cpp + geodata/scene/GeoSceneMercatorTileProjection.cpp + geodata/scene/GeoSceneEquirectTileProjection.cpp geodata/scene/GeoSceneIcon.cpp geodata/scene/GeoSceneTileDataset.cpp geodata/scene/GeoSceneVectorTileDataset.cpp diff --git a/src/lib/marble/geodata/handlers/dgml/DgmlProjectionTagHandler.cpp b/src/lib/marble/geodata/handlers/dgml/DgmlProjectionTagHandler.cpp --- a/src/lib/marble/geodata/handlers/dgml/DgmlProjectionTagHandler.cpp +++ b/src/lib/marble/geodata/handlers/dgml/DgmlProjectionTagHandler.cpp @@ -47,15 +47,16 @@ // Attribute name, default to "Equirectangular" const QString nameStr = parser.attribute( dgmlAttr_name ).trimmed(); if ( !nameStr.isEmpty() ) { - GeoSceneTileDataset::Projection projection = GeoSceneTileDataset::Equirectangular; - if (nameStr == QLatin1String("Equirectangular")) - projection = GeoSceneTileDataset::Equirectangular; - else if (nameStr == QLatin1String("Mercator")) - projection = GeoSceneTileDataset::Mercator; - else + GeoSceneAbstractTileProjection::Type tileProjectionType = GeoSceneAbstractTileProjection::Equirectangular; + if (nameStr == QLatin1String("Equirectangular")) { + tileProjectionType = GeoSceneAbstractTileProjection::Equirectangular; + } else if (nameStr == QLatin1String("Mercator")) { + tileProjectionType = GeoSceneAbstractTileProjection::Mercator; + } else { parser.raiseWarning( QString( "Value not allowed for attribute name: %1" ).arg( nameStr )); + } - parentItem.nodeAs()->setProjection( projection ); + parentItem.nodeAs()->setTileProjection(tileProjectionType); } return 0; } diff --git a/src/lib/marble/geodata/scene/GeoSceneAbstractTileProjection.h b/src/lib/marble/geodata/scene/GeoSceneAbstractTileProjection.h new file mode 100644 --- /dev/null +++ b/src/lib/marble/geodata/scene/GeoSceneAbstractTileProjection.h @@ -0,0 +1,117 @@ +/* + Copyright 2016 Friedrich W. H. Kossebau + + This file is part of the KDE project + + This library is free software you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + aint with this library see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef MARBLE_GEOSCENEABSTRACTTILEPROJECTION_H +#define MARBLE_GEOSCENEABSTRACTTILEPROJECTION_H + +#include "geodata_export.h" +#include + +#include + +namespace Marble +{ + +class GeoSceneAbstractTileProjectionPrivate; + +class GeoDataLatLonBox; + +// TODO: int or unsigned int for tile x/y coordinates? can the conversion fail? +// TODO: what about maps only covering a part? + +/** + * @short A base class for projections between tile coordinates and geo coordinates in Marble. + */ +class GEODATA_EXPORT GeoSceneAbstractTileProjection +{ +public: + enum Type { Equirectangular, Mercator }; + + /** + * @brief Construct a new GeoSceneAbstractTileProjection. + */ + GeoSceneAbstractTileProjection(); + + virtual ~GeoSceneAbstractTileProjection(); + +public: + virtual GeoSceneAbstractTileProjection::Type type() const = 0; + + int levelZeroColumns() const; + void setLevelZeroColumns(int levelZeroColumns); + + int levelZeroRows() const; + void setLevelZeroRows(int levelZeroRows); + + /** + * @brief Get the tile coordinates which cover the given geographical box. + * @param latLonBox the geo coordinates of the requested tiles + * @param zoomLevel the zoomlevel of the requested tiles + * @param westX the x coordinate of the western tiles is returned through this parameter + * @param northY the y coordinate of the northern tiles is returned through this parameter + * @param eastX the x coordinate of the eastern tiles is returned through this parameter + * @param southY the y coordinate of the southern tiles is returned through this parameter + */ + virtual void tileCoordinates(const GeoDataLatLonBox& latLonBox, int zoomLevel, + int& westX, int& northY, int& eastX, int& southY) const = 0; + + /** + * @brief Get the north-west geo coordinates corresponding to a tile. + * @param x the north x coordinate of the tile + * @param y the west y coordinate of the tile + * @param zoomLevel the zoomlevel of the tile + * @param northLon the longitude angle in radians is returned through this parameter + * @param westLat the latitude angle in radians is returned through this parameter + */ + virtual void geoCoordinates(int x, int y, + int zoomLevel, + qreal& northLon, qreal& westLat) const = 0; + + /** + * @brief Get the boundary geo coordinates corresponding to a tile. + * @param x the north x coordinate of the tile + * @param y the west y coordinate of the tile + * @param zoomLevel the zoomlevel of the tile + * @param latLonBox the boundary geo coordinates are set to this GeoDataLatLonBox + */ + virtual void geoCoordinates(int x, int y, + int zoomLevel, + GeoDataLatLonBox& latLonBox) const = 0; + + /** + * @brief Get the boundary geo coordinates corresponding to a tile. + * @param tileId the id of the tile + * @param latLonBox the boundary geo coordinates are set to this GeoDataLatLonBox + */ + void geoCoordinates(const TileId& tileId, + GeoDataLatLonBox& latLonBox) const + { + geoCoordinates(tileId.x(), tileId.y(), tileId.zoomLevel(), latLonBox); + } + + private: + Q_DISABLE_COPY(GeoSceneAbstractTileProjection) + const QScopedPointer d_ptr; +}; + +} + +#endif diff --git a/src/lib/marble/geodata/scene/GeoSceneAbstractTileProjection.cpp b/src/lib/marble/geodata/scene/GeoSceneAbstractTileProjection.cpp new file mode 100644 --- /dev/null +++ b/src/lib/marble/geodata/scene/GeoSceneAbstractTileProjection.cpp @@ -0,0 +1,72 @@ +/* + Copyright 2016 Friedrich W. H. Kossebau + + This file is part of the KDE project + + This library is free software you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + aint with this library see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include "GeoSceneAbstractTileProjection.h" + +namespace Marble +{ + +class GeoSceneAbstractTileProjectionPrivate +{ +public: + GeoSceneAbstractTileProjectionPrivate(); + +public: + int levelZeroColumns; + int levelZeroRows; +}; + +GeoSceneAbstractTileProjectionPrivate::GeoSceneAbstractTileProjectionPrivate() + : levelZeroColumns(1) + , levelZeroRows(1) +{ +} + +GeoSceneAbstractTileProjection::GeoSceneAbstractTileProjection() + : d_ptr(new GeoSceneAbstractTileProjectionPrivate()) +{ +} + +GeoSceneAbstractTileProjection::~GeoSceneAbstractTileProjection() +{ +} + +int GeoSceneAbstractTileProjection::levelZeroColumns() const +{ + return d_ptr->levelZeroColumns; +} + +void GeoSceneAbstractTileProjection::setLevelZeroColumns(int levelZeroColumns) +{ + d_ptr->levelZeroColumns = levelZeroColumns; +} + +int GeoSceneAbstractTileProjection::levelZeroRows() const +{ + return d_ptr->levelZeroRows; +} + +void GeoSceneAbstractTileProjection::setLevelZeroRows(int levelZeroRows) +{ + d_ptr->levelZeroRows = levelZeroRows; +} + +} diff --git a/src/lib/marble/geodata/scene/GeoSceneEquirectTileProjection.h b/src/lib/marble/geodata/scene/GeoSceneEquirectTileProjection.h new file mode 100644 --- /dev/null +++ b/src/lib/marble/geodata/scene/GeoSceneEquirectTileProjection.h @@ -0,0 +1,83 @@ +/* + Copyright 2016 Friedrich W. H. Kossebau + + This file is part of the KDE project + + This library is free software you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + aint with this library see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef MARBLE_GEOSCENEEQUIRECTTILEPROJECTION_H +#define MARBLE_GEOSCENEEQUIRECTTILEPROJECTION_H + +#include "GeoSceneAbstractTileProjection.h" + +namespace Marble +{ + +/** + * Convertes the x and y indizes of tiles to and from geo coordinates. + * For tiles of maps in Equirectangular projection. + * + * Tiles do have the same width and the same height per zoomlevel. + * The number of tiles per dimension is twice that of the previous lower zoomlevel. + * The indexing is done in x dimension eastwards, with the first tiles beginning at -180 degree + * and an x value of 0 and the last tiles ending at +180 degree, + * in y dimension southwards with the first tiles beginning at +90 degree and a y value of 0 + * and the last tiles ending at -90 degree. + */ +class GEODATA_EXPORT GeoSceneEquirectTileProjection : public GeoSceneAbstractTileProjection +{ +public: + /** + * @brief Construct a new GeoSceneEquirectTileProjection. + */ + GeoSceneEquirectTileProjection(); + + ~GeoSceneEquirectTileProjection() override; + +public: + /** + * @copydoc + */ + GeoSceneAbstractTileProjection::Type type() const override; + + /** + * @copydoc + */ + void tileCoordinates(const GeoDataLatLonBox& latLonBox, int zoomLevel, + int& westX, int& northY, int& eastX, int& southY) const override; + + /** + * @copydoc + */ + void geoCoordinates(int x, int y, + int zoomLevel, + qreal& northLon, qreal& westLat) const override; + + /** + * @copydoc + */ + void geoCoordinates(int x, int y, + int zoomLevel, + GeoDataLatLonBox& latLonBox) const override; + + private: + Q_DISABLE_COPY(GeoSceneEquirectTileProjection) +}; + +} + +#endif diff --git a/src/lib/marble/geodata/scene/GeoSceneEquirectTileProjection.cpp b/src/lib/marble/geodata/scene/GeoSceneEquirectTileProjection.cpp new file mode 100644 --- /dev/null +++ b/src/lib/marble/geodata/scene/GeoSceneEquirectTileProjection.cpp @@ -0,0 +1,100 @@ +/* + Copyright 2016 Friedrich W. H. Kossebau + + This file is part of the KDE project + + This library is free software you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + aint with this library see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include "GeoSceneEquirectTileProjection.h" + +#include +#include + +namespace Marble +{ + +GeoSceneEquirectTileProjection::GeoSceneEquirectTileProjection() +{ +} + + +GeoSceneEquirectTileProjection::~GeoSceneEquirectTileProjection() +{ +} + +GeoSceneAbstractTileProjection::Type GeoSceneEquirectTileProjection::type() const +{ + return Equirectangular; +} + + +static inline +unsigned int tileXFromLon(qreal lon, unsigned int tileCount) +{ + return (unsigned int)floor(0.5 * (lon / M_PI + 1.0) * tileCount); +} + +static inline +unsigned int tileYFromLat(qreal lat, unsigned int tileCount) +{ + return (unsigned int)floor(0.5 - lat / M_PI) * tileCount; +} + + +void GeoSceneEquirectTileProjection::tileCoordinates(const GeoDataLatLonBox& latLonBox, int zoomLevel, + int& westX, int& northY, int& eastX, int& southY) const +{ + const unsigned int xTileCount = (1 << zoomLevel) * levelZeroColumns(); + const unsigned int yTileCount = (1 << zoomLevel) * levelZeroRows(); + + westX = tileXFromLon(latLonBox.west(), xTileCount); + northY = tileYFromLat(latLonBox.north(), yTileCount); + eastX = tileXFromLon(latLonBox.east(), xTileCount); + southY = tileYFromLat(latLonBox.south(), yTileCount); +} + +void GeoSceneEquirectTileProjection::geoCoordinates(int x, int y, + int zoomLevel, + qreal& northLon, qreal& westLat) const +{ + qreal radius = (1 << zoomLevel) * levelZeroColumns() / 2.0; + + westLat = (x - radius ) / radius * M_PI; + + radius = (1 << zoomLevel) * levelZeroRows() / 2.0; + + northLon = (radius - y) / radius * M_PI / 2.0; +} + +void GeoSceneEquirectTileProjection::geoCoordinates(int x, int y, + int zoomLevel, + GeoDataLatLonBox& latLonBox) const +{ + qreal radius = (1 << zoomLevel) * levelZeroColumns() / 2.0; + + qreal lonLeft = (x - radius ) / radius * M_PI; + qreal lonRight = (x - radius + 1 ) / radius * M_PI; + + radius = (1 << zoomLevel) * levelZeroRows() / 2.0; + + qreal latTop = (radius - y) / radius * M_PI / 2.0; + qreal latBottom = (radius - y - 1) / radius * M_PI / 2.0; + + latLonBox.setBoundaries(latTop, latBottom, lonRight, lonLeft); +} + +} diff --git a/src/lib/marble/geodata/scene/GeoSceneMercatorTileProjection.h b/src/lib/marble/geodata/scene/GeoSceneMercatorTileProjection.h new file mode 100644 --- /dev/null +++ b/src/lib/marble/geodata/scene/GeoSceneMercatorTileProjection.h @@ -0,0 +1,83 @@ +/* + Copyright 2016 Friedrich W. H. Kossebau + + This file is part of the KDE project + + This library is free software you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + aint with this library see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef MARBLE_GEOSCENEMERCATORTILEPROJECTION_H +#define MARBLE_GEOSCENEMERCATORTILEPROJECTION_H + +#include "GeoSceneAbstractTileProjection.h" + +namespace Marble +{ + +/** + * Convertes the x and y indizes of tiles to and from geo coordinates. + * For tiles of maps in Mercator projection. + * + * Tiles do have the same width and the same height per zoomlevel. + * The number of tiles per dimension is twice that of the previous lower zoomlevel. + * The indexing is done in x dimension eastwards, with the first tiles beginning at -180 degree + * and an x value of 0 and the last tiles ending at +180 degree, + * in y dimension southwards with the first tiles beginning at +90 degree and a y value of 0 + * and the last tiles ending at -90 degree. + */ +class GEODATA_EXPORT GeoSceneMercatorTileProjection : public GeoSceneAbstractTileProjection +{ +public: + /** + * @brief Construct a new GeoSceneMercatorTileProjection. + */ + GeoSceneMercatorTileProjection(); + + ~GeoSceneMercatorTileProjection() override; + +public: + /** + * @copydoc + */ + GeoSceneAbstractTileProjection::Type type() const override; + + /** + * @copydoc + */ + void tileCoordinates(const GeoDataLatLonBox& latLonBox, int zoomLevel, + int& westX, int& northY, int& eastX, int& southY) const override; + + /** + * @copydoc + */ + void geoCoordinates(int x, int y, + int zoomLevel, + qreal& northLon, qreal& westLat) const override; + + /** + * @copydoc + */ + void geoCoordinates(int x, int y, + int zoomLevel, + GeoDataLatLonBox& latLonBox) const override; + +private: + Q_DISABLE_COPY(GeoSceneMercatorTileProjection) +}; + +} + +#endif diff --git a/src/lib/marble/geodata/scene/GeoSceneMercatorTileProjection.cpp b/src/lib/marble/geodata/scene/GeoSceneMercatorTileProjection.cpp new file mode 100644 --- /dev/null +++ b/src/lib/marble/geodata/scene/GeoSceneMercatorTileProjection.cpp @@ -0,0 +1,127 @@ +/* + Copyright 2016 Friedrich W. H. Kossebau + + This file is part of the KDE project + + This library is free software you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + aint with this library see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include "GeoSceneMercatorTileProjection.h" + +#include +#include + + +namespace Marble +{ + +GeoSceneMercatorTileProjection::GeoSceneMercatorTileProjection() +{ +} + + +GeoSceneMercatorTileProjection::~GeoSceneMercatorTileProjection() +{ +} + +GeoSceneAbstractTileProjection::Type GeoSceneMercatorTileProjection::type() const +{ + return Mercator; +} + + +static inline +unsigned int tileXFromLon(qreal lon, unsigned int tileCount) +{ + return (unsigned int)floor(0.5 * (lon / M_PI + 1.0) * tileCount); +} + +static inline +unsigned int tileYFromLat(qreal latitude, unsigned int tileCount) +{ + // We need to calculate the tile position from the latitude + // projected using the Mercator projection. This requires the inverse Gudermannian + // function which is only defined between -85°S and 85°N. Therefore in order to + // prevent undefined results we need to restrict our calculation: + qreal maxAbsLat = 85.0 * DEG2RAD; + qreal lat = (qAbs(latitude) > maxAbsLat) ? latitude/qAbs(latitude) * maxAbsLat : latitude; + return (unsigned int)floor(0.5 * (1.0 - gdInv(lat) / M_PI) * tileCount); +} + + +static inline +qreal lonFromTileX(unsigned int x, unsigned int tileCount) +{ + return ( (2*M_PI * x) / tileCount - M_PI ); +} + +static inline +qreal latFromTileY(unsigned int y, unsigned int tileCount) +{ + return gd(M_PI * (1.0 - (2.0 * y) / tileCount)); +} + + +void GeoSceneMercatorTileProjection::tileCoordinates(const GeoDataLatLonBox& latLonBox, int zoomLevel, + int& westX, int& northY, int& eastX, int& southY) const +{ + const unsigned int xTileCount = (1 << zoomLevel) * levelZeroColumns(); + const unsigned int yTileCount = (1 << zoomLevel) * levelZeroRows(); + + westX = tileXFromLon(latLonBox.west(), xTileCount); + northY = tileYFromLat(latLonBox.north(), yTileCount); + eastX = tileXFromLon(latLonBox.east(), xTileCount); + southY = tileYFromLat(latLonBox.south(), yTileCount); + + // Old comment: Sometimes the formula returns wrong huge values, x and y have to be between 0 and 2^ZoomLevel + // TODO: check with unit tests if this is still the case + westX = qBound( 0, westX, xTileCount-1); + northY = qBound(0, northY, yTileCount-1); + eastX = qBound( 0, eastX, xTileCount-1); + southY = qBound(0, southY, yTileCount-1); +} + +void GeoSceneMercatorTileProjection::geoCoordinates(int tileX, int tileY, + int zoomLevel, + qreal& northLon, qreal& westLat) const +{ + const unsigned int xTileCount = (1 << zoomLevel) * levelZeroColumns(); + const unsigned int yTileCount = (1 << zoomLevel) * levelZeroRows(); + + northLon = latFromTileY(tileY, xTileCount); + westLat = lonFromTileX(tileX, yTileCount); +} + + +void GeoSceneMercatorTileProjection::geoCoordinates(int x, int y, + int zoomLevel, + GeoDataLatLonBox& latLonBox) const +{ + + qreal radius = (1 << zoomLevel) * levelZeroColumns() / 2.0; + + qreal lonLeft = (x - radius) / radius * M_PI; + qreal lonRight = (x - radius + 1) / radius * M_PI; + + radius = (1 << zoomLevel) * levelZeroRows() / 2.0; + + qreal latTop = atan(sinh((radius - y) / radius * M_PI)); + qreal latBottom = atan(sinh((radius - y - 1) / radius * M_PI)); + + latLonBox.setBoundaries(latTop, latBottom, lonRight, lonLeft); +} + +} diff --git a/src/lib/marble/geodata/scene/GeoSceneTileDataset.h b/src/lib/marble/geodata/scene/GeoSceneTileDataset.h --- a/src/lib/marble/geodata/scene/GeoSceneTileDataset.h +++ b/src/lib/marble/geodata/scene/GeoSceneTileDataset.h @@ -20,6 +20,7 @@ #include #include "GeoSceneAbstractDataset.h" +#include "GeoSceneAbstractTileProjection.h" #include "MarbleGlobal.h" class QStringList; @@ -45,7 +46,6 @@ { public: enum StorageLayout { Marble, OpenStreetMap, TileMapService }; - enum Projection { Equirectangular, Mercator }; explicit GeoSceneTileDataset( const QString& name ); ~GeoSceneTileDataset(); @@ -84,8 +84,10 @@ const QSize tileSize() const; void setTileSize( const QSize &tileSize ); - Projection projection() const; - void setProjection( const Projection ); + void setTileProjection(GeoSceneAbstractTileProjection::Type projectionType); + + const GeoSceneAbstractTileProjection * tileProjection() const; + GeoSceneAbstractTileProjection::Type tileProjectionType() const; QString blending() const; void setBlending( const QString &name ); @@ -120,7 +122,7 @@ int m_maximumTileLevel; QVector m_tileLevels; mutable QSize m_tileSize; - Projection m_projection; + GeoSceneAbstractTileProjection *m_tileProjection; QString m_blending; /// List of Urls which are used in a round robin fashion diff --git a/src/lib/marble/geodata/scene/GeoSceneTileDataset.cpp b/src/lib/marble/geodata/scene/GeoSceneTileDataset.cpp --- a/src/lib/marble/geodata/scene/GeoSceneTileDataset.cpp +++ b/src/lib/marble/geodata/scene/GeoSceneTileDataset.cpp @@ -14,6 +14,8 @@ #include "GeoSceneTileDataset.h" #include "GeoSceneTypes.h" +#include "GeoSceneEquirectTileProjection.h" +#include "GeoSceneMercatorTileProjection.h" #include "DownloadPolicy.h" #include "MarbleDebug.h" @@ -37,17 +39,20 @@ m_levelZeroRows( defaultLevelZeroRows ), m_minimumTileLevel(0), m_maximumTileLevel( -1 ), - m_projection( Equirectangular ), + m_tileProjection(new GeoSceneEquirectTileProjection()), m_blending(), m_downloadUrls(), m_nextUrl( m_downloadUrls.constEnd() ) { + m_tileProjection->setLevelZeroColumns(m_levelZeroColumns); + m_tileProjection->setLevelZeroRows(m_levelZeroRows); } GeoSceneTileDataset::~GeoSceneTileDataset() { qDeleteAll( m_downloadPolicies ); delete m_serverLayout; + delete m_tileProjection; } const char* GeoSceneTileDataset::nodeType() const @@ -104,6 +109,7 @@ void GeoSceneTileDataset::setLevelZeroColumns( const int columns ) { m_levelZeroColumns = columns; + m_tileProjection->setLevelZeroColumns(m_levelZeroColumns); } int GeoSceneTileDataset::levelZeroRows() const @@ -114,6 +120,7 @@ void GeoSceneTileDataset::setLevelZeroRows( const int rows ) { m_levelZeroRows = rows; + m_tileProjection->setLevelZeroColumns(m_levelZeroColumns); } int GeoSceneTileDataset::maximumTileLevel() const @@ -208,14 +215,31 @@ } } -GeoSceneTileDataset::Projection GeoSceneTileDataset::projection() const +void GeoSceneTileDataset::setTileProjection(GeoSceneAbstractTileProjection::Type projectionType) { - return m_projection; + if (m_tileProjection->type() == projectionType) { + return; + } + + delete m_tileProjection; + if (projectionType == GeoSceneAbstractTileProjection::Mercator) { + m_tileProjection = new GeoSceneMercatorTileProjection(); + } else { + m_tileProjection = new GeoSceneEquirectTileProjection(); + } + + m_tileProjection->setLevelZeroColumns(m_levelZeroColumns); + m_tileProjection->setLevelZeroRows(m_levelZeroRows); +} + +const GeoSceneAbstractTileProjection * GeoSceneTileDataset::tileProjection() const +{ + return m_tileProjection; } -void GeoSceneTileDataset::setProjection( const Projection projection ) +GeoSceneAbstractTileProjection::Type GeoSceneTileDataset::tileProjectionType() const { - m_projection = projection; + return m_tileProjection->type(); } // Even though this method changes the internal state, it may be const diff --git a/src/lib/marble/geodata/writers/dgml/DgmlTextureTagWriter.cpp b/src/lib/marble/geodata/writers/dgml/DgmlTextureTagWriter.cpp --- a/src/lib/marble/geodata/writers/dgml/DgmlTextureTagWriter.cpp +++ b/src/lib/marble/geodata/writers/dgml/DgmlTextureTagWriter.cpp @@ -89,9 +89,10 @@ } writer.writeStartElement( dgml::dgmlTag_Projection ); - if( texture->projection() == GeoSceneTileDataset::Mercator ) { + const GeoSceneAbstractTileProjection::Type tileProjectionType = texture->tileProjectionType(); + if (tileProjectionType == GeoSceneAbstractTileProjection::Mercator) { writer.writeAttribute( "name", "Mercator" ); - } else if ( texture->projection() == GeoSceneTileDataset::Equirectangular ) { + } else if (tileProjectionType == GeoSceneAbstractTileProjection::Equirectangular) { writer.writeAttribute( "name", "Equirectangular" ); } writer.writeEndElement(); diff --git a/src/lib/marble/layers/TextureLayer.h b/src/lib/marble/layers/TextureLayer.h --- a/src/lib/marble/layers/TextureLayer.h +++ b/src/lib/marble/layers/TextureLayer.h @@ -79,7 +79,7 @@ QSize tileSize() const; - GeoSceneTileDataset::Projection tileProjection() const; + GeoSceneAbstractTileProjection::Type tileProjectionType() const; int tileColumnCount( int level ) const; int tileRowCount( int level ) const; diff --git a/src/lib/marble/layers/TextureLayer.cpp b/src/lib/marble/layers/TextureLayer.cpp --- a/src/lib/marble/layers/TextureLayer.cpp +++ b/src/lib/marble/layers/TextureLayer.cpp @@ -412,7 +412,7 @@ d->m_texmapper = new EquirectScanlineTextureMapper( &d->m_tileLoader ); break; case Mercator: - if ( d->m_textures.at(0)->projection() == GeoSceneTileDataset::Mercator ) { + if (d->m_textures.at(0)->tileProjectionType() == GeoSceneAbstractTileProjection::Mercator) { d->m_texmapper = new TileScalingTextureMapper( &d->m_tileLoader ); } else { d->m_texmapper = new MercatorScanlineTextureMapper( &d->m_tileLoader ); @@ -499,9 +499,9 @@ return d->m_layerDecorator.tileSize(); } -GeoSceneTileDataset::Projection TextureLayer::tileProjection() const +GeoSceneAbstractTileProjection::Type TextureLayer::tileProjectionType() const { - return d->m_layerDecorator.tileProjection(); + return d->m_layerDecorator.tileProjectionType(); } int TextureLayer::tileColumnCount( int level ) const diff --git a/tests/TestGeoSceneWriter.cpp b/tests/TestGeoSceneWriter.cpp --- a/tests/TestGeoSceneWriter.cpp +++ b/tests/TestGeoSceneWriter.cpp @@ -219,7 +219,7 @@ GeoSceneTileDataset* texture = new GeoSceneTileDataset( "map" ); texture->setSourceDir( "earth/testmap" ); texture->setFileFormat( "png" ); - texture->setProjection( GeoSceneTileDataset::Equirectangular ); + texture->setTileProjection(GeoSceneAbstractTileProjection::Equirectangular); texture->addDownloadUrl( QUrl( "http://download.kde.org/marble/map/{x}/{y}/{zoomLevel}" ) ); texture->addDownloadUrl( QUrl( "http://download.google.com/marble/map/{x}/{y}/{zoomLevel}" ) ); texture->addDownloadPolicy( DownloadBrowse, 20 ); diff --git a/tools/vectorosm-tilecreator/TileIterator.cpp b/tools/vectorosm-tilecreator/TileIterator.cpp --- a/tools/vectorosm-tilecreator/TileIterator.cpp +++ b/tools/vectorosm-tilecreator/TileIterator.cpp @@ -9,8 +9,8 @@ // #include "TileIterator.h" -#include "TileId.h" -#include "VectorTileModel.h" + +#include "GeoSceneMercatorTileProjection.h" #include @@ -45,13 +45,14 @@ TileIterator::TileIterator(const GeoDataLatLonBox &latLonBox, int zoomLevel) { - qreal north, west, south, east; - latLonBox.boundaries(north, south, east, west); - unsigned int N = pow(2, zoomLevel); - m_bounds.setLeft(TileId::lon2tileX(west, N)); - m_bounds.setTop(TileId::lat2tileY(north, N)); - m_bounds.setRight(TileId::lon2tileX(east, N)); - m_bounds.setBottom(TileId::lat2tileY(south, N)); + int westX, northY, eastX, southY; + GeoSceneMercatorTileProjection tileProjection; + tileProjection.tileCoordinates(latLonBox, zoomLevel, westX, northY, eastX, southY); + + m_bounds.setLeft(westX); + m_bounds.setTop(northY); + m_bounds.setRight(eastX); + m_bounds.setBottom(southY); } TileIterator::const_iterator TileIterator::begin() const diff --git a/tools/vectorosm-tilecreator/VectorClipper.h b/tools/vectorosm-tilecreator/VectorClipper.h --- a/tools/vectorosm-tilecreator/VectorClipper.h +++ b/tools/vectorosm-tilecreator/VectorClipper.h @@ -15,6 +15,7 @@ #include "OsmPlacemarkData.h" #include +#include namespace Marble { @@ -29,6 +30,9 @@ private: void copyTags(const GeoDataPlacemark &source, GeoDataPlacemark &target) const; void copyTags(const OsmPlacemarkData &originalPlacemarkData, OsmPlacemarkData& targetOsmData) const; + +private: + GeoSceneMercatorTileProjection m_tileProjection; }; } diff --git a/tools/vectorosm-tilecreator/VectorClipper.cpp b/tools/vectorosm-tilecreator/VectorClipper.cpp --- a/tools/vectorosm-tilecreator/VectorClipper.cpp +++ b/tools/vectorosm-tilecreator/VectorClipper.cpp @@ -168,13 +168,16 @@ GeoDataDocument *VectorClipper::clipTo(unsigned int zoomLevel, unsigned int tileX, unsigned int tileY) { - unsigned int N = pow(2, zoomLevel); GeoDataLatLonBox tileBoundary; - qreal north = TileId::tileY2lat(tileY, N); - qreal south = TileId::tileY2lat(tileY+1, N); - qreal west = TileId::tileX2lon(tileX, N); - qreal east = TileId::tileX2lon(tileX+1, N); + qreal north; + qreal south; + qreal west; + qreal east; + m_tileProjection.geoCoordinates(tileX, tileY, zoomLevel, west, north); + m_tileProjection.geoCoordinates(tileX+1, tileY+1, zoomLevel, east, south); tileBoundary.setBoundaries(north, south, east, west); + // TODO: are geo coordinates of tile boundaries exactly the same? + // if, then some GeoSceneMercatorTileProjection::geoCoordinates(..., tileBoundary) would be nice here instead GeoDataDocument *tile = clipTo(tileBoundary); QString tileName = QString("%1/%2/%3").arg(zoomLevel).arg(tileX).arg(tileY);