Marble

GeoSceneMercatorTileProjection.cpp
1/*
2 SPDX-FileCopyrightText: 2016 Friedrich W. H. Kossebau <kossebau@kde.org>
3
4 SPDX-License-Identifier: LGPL-2.0-or-later
5*/
6
7#include "GeoSceneMercatorTileProjection.h"
8
9#include <GeoDataLatLonBox.h>
10#include <MarbleMath.h>
11
12
13namespace Marble
14{
15
19
20
21GeoSceneMercatorTileProjection::~GeoSceneMercatorTileProjection()
22{
23}
24
25GeoSceneAbstractTileProjection::Type GeoSceneMercatorTileProjection::type() const
26{
27 return Mercator;
28}
29
30
31static inline
32unsigned int lowerBoundTileIndex(qreal baseTileIndex)
33{
34 const qreal floorBaseTileIndex = floor(baseTileIndex);
35 unsigned int tileIndex = static_cast<unsigned int>(floorBaseTileIndex);
36 return (baseTileIndex == floorBaseTileIndex) ? tileIndex-1 : tileIndex;
37}
38
39static inline
40unsigned int upperBoundTileIndex(qreal baseTileIndex)
41{
42 return (unsigned int)floor(baseTileIndex);
43}
44
45static inline
46qreal baseTileXFromLon(qreal lon, unsigned int tileCount)
47{
48 return 0.5 * (lon / M_PI + 1.0) * tileCount;
49}
50
51static inline
52qreal baseTileYFromLat(qreal latitude, unsigned int tileCount)
53{
54 // We need to calculate the tile position from the latitude
55 // projected using the Mercator projection. This requires the inverse Gudermannian
56 // function which is only defined between -85°S and 85°N. Therefore in order to
57 // prevent undefined results we need to restrict our calculation.
58 // Using 85.0 instead of some more correct 85.05113, to avoid running into NaN issues.
59 qreal maxAbsLat = 85.0 * DEG2RAD;
60 qreal lat = (qAbs(latitude) > maxAbsLat) ? latitude/qAbs(latitude) * maxAbsLat : latitude;
61 return (0.5 * (1.0 - gdInv(lat) / M_PI) * tileCount);
62}
63
64// on tile borders selects the tile to the east
65static inline
66unsigned int eastBoundTileXFromLon(qreal lon, unsigned int tileCount)
67{
68 // special casing tile-map end
69 if (lon == M_PI) {
70 return 0;
71 }
72 return upperBoundTileIndex(baseTileXFromLon(lon, tileCount));
73}
74
75// on tile borders selects the tile to the west
76static inline
77unsigned int westBoundTileXFromLon(qreal lon, unsigned int tileCount)
78{
79 // special casing tile-map end
80 if (lon == -M_PI) {
81 return tileCount-1;
82 }
83 return lowerBoundTileIndex(baseTileXFromLon(lon, tileCount));
84}
85
86// on tile borders selects the tile to the south
87static inline
88unsigned int southBoundTileYFromLat(qreal lat, unsigned int tileCount)
89{
90 // special casing tile-map end
91 if (lat == -M_PI*0.5) {
92 // calculate with normal lat value
93 lat = M_PI * 0.5;
94 }
95 return upperBoundTileIndex(baseTileYFromLat(lat, tileCount));
96}
97
98// on tile borders selects the tile to the north
99static inline
100unsigned int northBoundTileYFromLat(qreal lat, unsigned int tileCount)
101{
102 // special casing tile-map end
103 if (lat == M_PI*0.5) {
104 // calculate with normal lat value
105 lat = - M_PI * 0.5;
106 }
107 return lowerBoundTileIndex(baseTileYFromLat(lat, tileCount));
108}
109
110
111static inline
112qreal lonFromTileX(unsigned int x, unsigned int tileCount)
113{
114 return ( (2*M_PI * x) / tileCount - M_PI );
115}
116
117static inline
118qreal latFromTileY(unsigned int y, unsigned int tileCount)
119{
120 return gd(M_PI * (1.0 - (2.0 * y) / tileCount));
121}
122
123
125{
126 const unsigned int xTileCount = (1 << zoomLevel) * levelZeroColumns();
127
128 const int westX = eastBoundTileXFromLon(latLonBox.west(), xTileCount);
129 const int eastX = westBoundTileXFromLon(latLonBox.east(), xTileCount);
130
131 const unsigned int yTileCount = (1 << zoomLevel) * levelZeroRows();
132
133 const int northY = southBoundTileYFromLat(latLonBox.north(), yTileCount);
134 const int southY = northBoundTileYFromLat(latLonBox.south(), yTileCount);
135
136 return QRect(QPoint(westX, northY), QPoint(eastX, southY));
137}
138
139
141{
142 const unsigned int xTileCount = (1 << zoomLevel) * levelZeroColumns();
143 const unsigned int yTileCount = (1 << zoomLevel) * levelZeroRows();
144
145 const qreal west = lonFromTileX(x, xTileCount);
146 const qreal north = latFromTileY(y, yTileCount);
147
148 const qreal east = lonFromTileX(x + 1, xTileCount);
149 const qreal south = latFromTileY(y + 1, yTileCount);
150
151 return GeoDataLatLonBox(north, south, east, west);
152}
153
154}
A class that defines a 2D bounding box for geographic data.
qreal north(GeoDataCoordinates::Unit unit=GeoDataCoordinates::Radian) const
Get the northern boundary of the bounding box.
qreal east(GeoDataCoordinates::Unit unit=GeoDataCoordinates::Radian) const
Get the eastern boundary of the bounding box.
qreal west(GeoDataCoordinates::Unit unit=GeoDataCoordinates::Radian) const
Get the western boundary of the bounding box.
qreal south(GeoDataCoordinates::Unit unit=GeoDataCoordinates::Radian) const
Get the southern boundary of the bounding box.
GeoSceneMercatorTileProjection()
Construct a new GeoSceneMercatorTileProjection.
GeoSceneAbstractTileProjection::Type type() const override
GeoDataLatLonBox geoCoordinates(int zoomLevel, int x, int y) const override
QRect tileIndexes(const GeoDataLatLonBox &latLonBox, int zoomLevel) const override
Binds a QML item to a specific geodetic location in screen coordinates.
qreal gdInv(qreal x)
This method is a fast Mac Laurin power series approximation of the.
Definition MarbleMath.h:73
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Fri Jun 14 2024 11:54:16 by doxygen 1.10.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.