Marble

GeoSceneMercatorTileProjection.cpp
1 /*
2  SPDX-FileCopyrightText: 2016 Friedrich W. H. Kossebau <[email protected]>
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 
13 namespace Marble
14 {
15 
17 {
18 }
19 
20 
21 GeoSceneMercatorTileProjection::~GeoSceneMercatorTileProjection()
22 {
23 }
24 
25 GeoSceneAbstractTileProjection::Type GeoSceneMercatorTileProjection::type() const
26 {
27  return Mercator;
28 }
29 
30 
31 static inline
32 unsigned 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 
39 static inline
40 unsigned int upperBoundTileIndex(qreal baseTileIndex)
41 {
42  return (unsigned int)floor(baseTileIndex);
43 }
44 
45 static inline
46 qreal baseTileXFromLon(qreal lon, unsigned int tileCount)
47 {
48  return 0.5 * (lon / M_PI + 1.0) * tileCount;
49 }
50 
51 static inline
52 qreal 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
65 static inline
66 unsigned 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
76 static inline
77 unsigned 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
87 static inline
88 unsigned 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
99 static inline
100 unsigned 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 
111 static inline
112 qreal lonFromTileX(unsigned int x, unsigned int tileCount)
113 {
114  return ( (2*M_PI * x) / tileCount - M_PI );
115 }
116 
117 static inline
118 qreal 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 }
qreal gdInv(qreal x)
This method is a fast Mac Laurin power series approximation of the.
Definition: MarbleMath.h:73
GeoSceneAbstractTileProjection::Type type() const override
qreal east(GeoDataCoordinates::Unit unit=GeoDataCoordinates::Radian) const
Get the eastern boundary of the bounding box.
qreal north(GeoDataCoordinates::Unit unit=GeoDataCoordinates::Radian) const
Get the northern boundary of the bounding box.
qreal west(GeoDataCoordinates::Unit unit=GeoDataCoordinates::Radian) const
Get the western boundary of the bounding box.
GeoDataLatLonBox geoCoordinates(int zoomLevel, int x, int y) const override
A class that defines a 2D bounding box for geographic data.
Binds a QML item to a specific geodetic location in screen coordinates.
qreal south(GeoDataCoordinates::Unit unit=GeoDataCoordinates::Radian) const
Get the southern boundary of the bounding box.
GeoSceneMercatorTileProjection()
Construct a new GeoSceneMercatorTileProjection.
QRect tileIndexes(const GeoDataLatLonBox &latLonBox, int zoomLevel) const override
This file is part of the KDE documentation.
Documentation copyright © 1996-2023 The KDE developers.
Generated on Thu Sep 21 2023 04:12:26 by doxygen 1.8.17 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.