File indexing completed on 2025-01-05 03:59:11
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 "GeoSceneMercatorTileProjection.h" 0008 0009 #include <GeoDataLatLonBox.h> 0010 #include <MarbleMath.h> 0011 0012 0013 namespace Marble 0014 { 0015 0016 GeoSceneMercatorTileProjection::GeoSceneMercatorTileProjection() 0017 { 0018 } 0019 0020 0021 GeoSceneMercatorTileProjection::~GeoSceneMercatorTileProjection() 0022 { 0023 } 0024 0025 GeoSceneAbstractTileProjection::Type GeoSceneMercatorTileProjection::type() const 0026 { 0027 return Mercator; 0028 } 0029 0030 0031 static inline 0032 unsigned int lowerBoundTileIndex(qreal baseTileIndex) 0033 { 0034 const qreal floorBaseTileIndex = floor(baseTileIndex); 0035 unsigned int tileIndex = static_cast<unsigned int>(floorBaseTileIndex); 0036 return (baseTileIndex == floorBaseTileIndex) ? tileIndex-1 : tileIndex; 0037 } 0038 0039 static inline 0040 unsigned int upperBoundTileIndex(qreal baseTileIndex) 0041 { 0042 return (unsigned int)floor(baseTileIndex); 0043 } 0044 0045 static inline 0046 qreal baseTileXFromLon(qreal lon, unsigned int tileCount) 0047 { 0048 return 0.5 * (lon / M_PI + 1.0) * tileCount; 0049 } 0050 0051 static inline 0052 qreal baseTileYFromLat(qreal latitude, unsigned int tileCount) 0053 { 0054 // We need to calculate the tile position from the latitude 0055 // projected using the Mercator projection. This requires the inverse Gudermannian 0056 // function which is only defined between -85°S and 85°N. Therefore in order to 0057 // prevent undefined results we need to restrict our calculation. 0058 // Using 85.0 instead of some more correct 85.05113, to avoid running into NaN issues. 0059 qreal maxAbsLat = 85.0 * DEG2RAD; 0060 qreal lat = (qAbs(latitude) > maxAbsLat) ? latitude/qAbs(latitude) * maxAbsLat : latitude; 0061 return (0.5 * (1.0 - gdInv(lat) / M_PI) * tileCount); 0062 } 0063 0064 // on tile borders selects the tile to the east 0065 static inline 0066 unsigned int eastBoundTileXFromLon(qreal lon, unsigned int tileCount) 0067 { 0068 // special casing tile-map end 0069 if (lon == M_PI) { 0070 return 0; 0071 } 0072 return upperBoundTileIndex(baseTileXFromLon(lon, tileCount)); 0073 } 0074 0075 // on tile borders selects the tile to the west 0076 static inline 0077 unsigned int westBoundTileXFromLon(qreal lon, unsigned int tileCount) 0078 { 0079 // special casing tile-map end 0080 if (lon == -M_PI) { 0081 return tileCount-1; 0082 } 0083 return lowerBoundTileIndex(baseTileXFromLon(lon, tileCount)); 0084 } 0085 0086 // on tile borders selects the tile to the south 0087 static inline 0088 unsigned int southBoundTileYFromLat(qreal lat, unsigned int tileCount) 0089 { 0090 // special casing tile-map end 0091 if (lat == -M_PI*0.5) { 0092 // calculate with normal lat value 0093 lat = M_PI * 0.5; 0094 } 0095 return upperBoundTileIndex(baseTileYFromLat(lat, tileCount)); 0096 } 0097 0098 // on tile borders selects the tile to the north 0099 static inline 0100 unsigned int northBoundTileYFromLat(qreal lat, unsigned int tileCount) 0101 { 0102 // special casing tile-map end 0103 if (lat == M_PI*0.5) { 0104 // calculate with normal lat value 0105 lat = - M_PI * 0.5; 0106 } 0107 return lowerBoundTileIndex(baseTileYFromLat(lat, tileCount)); 0108 } 0109 0110 0111 static inline 0112 qreal lonFromTileX(unsigned int x, unsigned int tileCount) 0113 { 0114 return ( (2*M_PI * x) / tileCount - M_PI ); 0115 } 0116 0117 static inline 0118 qreal latFromTileY(unsigned int y, unsigned int tileCount) 0119 { 0120 return gd(M_PI * (1.0 - (2.0 * y) / tileCount)); 0121 } 0122 0123 0124 QRect GeoSceneMercatorTileProjection::tileIndexes(const GeoDataLatLonBox &latLonBox, int zoomLevel) const 0125 { 0126 const unsigned int xTileCount = (1 << zoomLevel) * levelZeroColumns(); 0127 0128 const int westX = eastBoundTileXFromLon(latLonBox.west(), xTileCount); 0129 const int eastX = westBoundTileXFromLon(latLonBox.east(), xTileCount); 0130 0131 const unsigned int yTileCount = (1 << zoomLevel) * levelZeroRows(); 0132 0133 const int northY = southBoundTileYFromLat(latLonBox.north(), yTileCount); 0134 const int southY = northBoundTileYFromLat(latLonBox.south(), yTileCount); 0135 0136 return QRect(QPoint(westX, northY), QPoint(eastX, southY)); 0137 } 0138 0139 0140 GeoDataLatLonBox GeoSceneMercatorTileProjection::geoCoordinates(int zoomLevel, int x, int y) const 0141 { 0142 const unsigned int xTileCount = (1 << zoomLevel) * levelZeroColumns(); 0143 const unsigned int yTileCount = (1 << zoomLevel) * levelZeroRows(); 0144 0145 const qreal west = lonFromTileX(x, xTileCount); 0146 const qreal north = latFromTileY(y, yTileCount); 0147 0148 const qreal east = lonFromTileX(x + 1, xTileCount); 0149 const qreal south = latFromTileY(y + 1, yTileCount); 0150 0151 return GeoDataLatLonBox(north, south, east, west); 0152 } 0153 0154 }