File indexing completed on 2024-05-19 03:51:50

0001 /*
0002     SPDX-FileCopyrightText: 2016 Friedrich W. H. Kossebau <kossebau@kde.org>
0003 
0004     SPDX-License-Identifier: LGPL-2.0-or-later
0005 */
0006 
0007 #include "GeoSceneEquirectTileProjection.h"
0008 
0009 #include <GeoDataLatLonBox.h>
0010 
0011 namespace Marble
0012 {
0013 
0014 GeoSceneEquirectTileProjection::GeoSceneEquirectTileProjection()
0015 {
0016 }
0017 
0018 
0019 GeoSceneEquirectTileProjection::~GeoSceneEquirectTileProjection()
0020 {
0021 }
0022 
0023 GeoSceneAbstractTileProjection::Type GeoSceneEquirectTileProjection::type() const
0024 {
0025     return Equirectangular;
0026 }
0027 
0028 
0029 static inline
0030 unsigned int lowerBoundTileIndex(qreal baseTileIndex)
0031 {
0032     const qreal floorBaseTileIndex = floor(baseTileIndex);
0033     unsigned int tileIndex = static_cast<unsigned int>(floorBaseTileIndex);
0034     return (baseTileIndex == floorBaseTileIndex) ? tileIndex-1 : tileIndex;
0035 }
0036 
0037 static inline
0038 unsigned int upperBoundTileIndex(qreal baseTileIndex)
0039 {
0040     return (unsigned int)floor(baseTileIndex);
0041 }
0042 
0043 static inline
0044 qreal baseTileXFromLon(qreal lon, unsigned int tileCount)
0045 {
0046     return 0.5 * (lon / M_PI + 1.0) * tileCount;
0047 }
0048 
0049 static inline
0050 qreal baseTileYFromLat(qreal lat, unsigned int tileCount)
0051 {
0052     return (0.5 - lat / M_PI) * tileCount;
0053 }
0054 
0055 
0056 // on tile borders selects the tile to the east
0057 static inline
0058 unsigned int eastBoundTileXFromLon(qreal lon, unsigned int tileCount)
0059 {
0060     // special casing tile-map end
0061     if (lon == M_PI) {
0062         return 0;
0063     }
0064     return upperBoundTileIndex(baseTileXFromLon(lon, tileCount));
0065 }
0066 
0067 // on tile borders selects the tile to the west
0068 static inline
0069 unsigned int westBoundTileXFromLon(qreal lon, unsigned int tileCount)
0070 {
0071     // special casing tile-map end
0072     if (lon == -M_PI) {
0073         return tileCount-1;
0074     }
0075     return lowerBoundTileIndex(baseTileXFromLon(lon, tileCount));
0076 }
0077 
0078 // on tile borders selects the tile to the south
0079 static inline
0080 unsigned int southBoundTileYFromLat(qreal lat, unsigned int tileCount)
0081 {
0082     // special casing tile-map end
0083     if (lat == -M_PI*0.5) {
0084         return 0;
0085     }
0086     return upperBoundTileIndex(baseTileYFromLat(lat, tileCount));
0087 }
0088 
0089 // on tile borders selects the tile to the north
0090 static inline
0091 unsigned int northBoundTileYFromLat(qreal lat, unsigned int tileCount)
0092 {
0093     // special casing tile-map end
0094     if (lat == M_PI*0.5) {
0095         return tileCount-1;
0096     }
0097     return lowerBoundTileIndex(baseTileYFromLat(lat, tileCount));
0098 }
0099 
0100 
0101 QRect GeoSceneEquirectTileProjection::tileIndexes(const GeoDataLatLonBox &latLonBox, int zoomLevel) const
0102 {
0103     const unsigned int xTileCount = (1 << zoomLevel) * levelZeroColumns();
0104 
0105     const int westX =   eastBoundTileXFromLon(latLonBox.west(),  xTileCount);
0106     const int eastX =   westBoundTileXFromLon(latLonBox.east(),  xTileCount);
0107 
0108     const unsigned int yTileCount = (1 << zoomLevel) * levelZeroRows();
0109 
0110     const int northY = southBoundTileYFromLat(latLonBox.north(), yTileCount);
0111     const int southY = northBoundTileYFromLat(latLonBox.south(), yTileCount);
0112 
0113     return QRect(QPoint(westX, northY), QPoint(eastX, southY));
0114 }
0115 
0116 GeoDataLatLonBox GeoSceneEquirectTileProjection::geoCoordinates(int zoomLevel, int x, int y) const
0117 {
0118     const qreal radiusX = (1 << zoomLevel) * levelZeroColumns() / 2.0;
0119     const qreal radiusY = (1 << zoomLevel) * levelZeroRows() / 2.0;
0120 
0121     const qreal west  = (x - radiusX) / radiusX * M_PI;
0122     const qreal north = (radiusY - y) / radiusY * M_PI / 2.0;
0123 
0124     const qreal east  = ((x + 1) - radiusX) / radiusX * M_PI;
0125     const qreal south = (radiusY - (y + 1)) / radiusY * M_PI / 2.0;
0126 
0127     return GeoDataLatLonBox(north, south, east, west);
0128 }
0129 
0130 }