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
12namespace Marble
13{
14
16
17GeoSceneMercatorTileProjection::~GeoSceneMercatorTileProjection() = default;
18
19GeoSceneAbstractTileProjection::Type GeoSceneMercatorTileProjection::type() const
20{
21 return Mercator;
22}
23
24static inline unsigned int lowerBoundTileIndex(qreal baseTileIndex)
25{
26 const qreal floorBaseTileIndex = floor(baseTileIndex);
27 auto tileIndex = static_cast<unsigned int>(floorBaseTileIndex);
28 return (baseTileIndex == floorBaseTileIndex) ? tileIndex - 1 : tileIndex;
29}
30
31static inline unsigned int upperBoundTileIndex(qreal baseTileIndex)
32{
33 return (unsigned int)floor(baseTileIndex);
34}
35
36static inline qreal baseTileXFromLon(qreal lon, unsigned int tileCount)
37{
38 return 0.5 * (lon / M_PI + 1.0) * tileCount;
39}
40
41static inline qreal baseTileYFromLat(qreal latitude, unsigned int tileCount)
42{
43 // We need to calculate the tile position from the latitude
44 // projected using the Mercator projection. This requires the inverse Gudermannian
45 // function which is only defined between -85°S and 85°N. Therefore in order to
46 // prevent undefined results we need to restrict our calculation.
47 // Using 85.0 instead of some more correct 85.05113, to avoid running into NaN issues.
48 qreal maxAbsLat = 85.0 * DEG2RAD;
49 qreal lat = (qAbs(latitude) > maxAbsLat) ? latitude / qAbs(latitude) * maxAbsLat : latitude;
50 return (0.5 * (1.0 - gdInv(lat) / M_PI) * tileCount);
51}
52
53// on tile borders selects the tile to the east
54static inline unsigned int eastBoundTileXFromLon(qreal lon, unsigned int tileCount)
55{
56 // special casing tile-map end
57 if (lon == M_PI) {
58 return 0;
59 }
60 return upperBoundTileIndex(baseTileXFromLon(lon, tileCount));
61}
62
63// on tile borders selects the tile to the west
64static inline unsigned int westBoundTileXFromLon(qreal lon, unsigned int tileCount)
65{
66 // special casing tile-map end
67 if (lon == -M_PI) {
68 return tileCount - 1;
69 }
70 return lowerBoundTileIndex(baseTileXFromLon(lon, tileCount));
71}
72
73// on tile borders selects the tile to the south
74static inline unsigned int southBoundTileYFromLat(qreal lat, unsigned int tileCount)
75{
76 // special casing tile-map end
77 if (lat == -M_PI * 0.5) {
78 // calculate with normal lat value
79 lat = M_PI * 0.5;
80 }
81 return upperBoundTileIndex(baseTileYFromLat(lat, tileCount));
82}
83
84// on tile borders selects the tile to the north
85static inline unsigned int northBoundTileYFromLat(qreal lat, unsigned int tileCount)
86{
87 // special casing tile-map end
88 if (lat == M_PI * 0.5) {
89 // calculate with normal lat value
90 lat = -M_PI * 0.5;
91 }
92 return lowerBoundTileIndex(baseTileYFromLat(lat, tileCount));
93}
94
95static inline qreal lonFromTileX(unsigned int x, unsigned int tileCount)
96{
97 return ((2 * M_PI * x) / tileCount - M_PI);
98}
99
100static inline qreal latFromTileY(unsigned int y, unsigned int tileCount)
101{
102 return gd(M_PI * (1.0 - (2.0 * y) / tileCount));
103}
104
106{
107 const unsigned int xTileCount = (1 << zoomLevel) * levelZeroColumns();
108
109 const int westX = eastBoundTileXFromLon(latLonBox.west(), xTileCount);
110 const int eastX = westBoundTileXFromLon(latLonBox.east(), xTileCount);
111
112 const unsigned int yTileCount = (1 << zoomLevel) * levelZeroRows();
113
114 const int northY = southBoundTileYFromLat(latLonBox.north(), yTileCount);
115 const int southY = northBoundTileYFromLat(latLonBox.south(), yTileCount);
116
117 return QRect(QPoint(westX, northY), QPoint(eastX, southY));
118}
119
121{
122 const unsigned int xTileCount = (1 << zoomLevel) * levelZeroColumns();
123 const unsigned int yTileCount = (1 << zoomLevel) * levelZeroRows();
124
125 const qreal west = lonFromTileX(x, xTileCount);
126 const qreal north = latFromTileY(y, yTileCount);
127
128 const qreal east = lonFromTileX(x + 1, xTileCount);
129 const qreal south = latFromTileY(y + 1, yTileCount);
130
131 return {north, south, east, west};
132}
133
134}
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:71
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Sat Dec 21 2024 17:04:14 by doxygen 1.12.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.