QGroundControl
Ground Control Station for MAVLink Drones
Loading...
Searching...
No Matches
TileMath.cc
Go to the documentation of this file.
1#include "TileMath.h"
2
3#include <QtCore/QDebug>
4#include <QtCore/QtMath>
5
6#include <algorithm>
7#include <cmath>
8
9namespace TileMath {
10
11QDebug operator<<(QDebug debug, const TileKey& key)
12{
13 const QDebugStateSaver saver(debug);
14 debug.nospace() << key.zoom << '/' << key.x << '/' << key.y;
15 return debug;
16}
17
18double worldSize()
19{
20 return 2.0 * M_PI * kEarthRadius;
21}
22
23QPointF geoToWorld(const QGeoCoordinate& coord)
24{
25 const double lat = std::clamp(coord.latitude(), -kMaxLatitude, kMaxLatitude);
26 const double x = qDegreesToRadians(coord.longitude()) * kEarthRadius;
27 const double y = std::log(std::tan(M_PI_4 + qDegreesToRadians(lat) / 2.0)) * kEarthRadius;
28 return QPointF(x, y);
29}
30
31QGeoCoordinate worldToGeo(const QPointF& world)
32{
33 const double lon = qRadiansToDegrees(world.x() / kEarthRadius);
34 const double lat = qRadiansToDegrees(2.0 * std::atan(std::exp(world.y() / kEarthRadius)) - M_PI_2);
35 return QGeoCoordinate(lat, lon, 0);
36}
37
38double mercatorScale(double latitude)
39{
40 const double lat = std::clamp(latitude, -kMaxLatitude, kMaxLatitude);
41 return 1.0 / std::cos(qDegreesToRadians(lat));
42}
43
44bool isValidKey(const TileKey& key)
45{
46 if ((key.zoom < kMinZoom) || (key.zoom > kMaxZoom)) {
47 return false;
48 }
49 const int tilesAtZoom = 1 << key.zoom;
50 return (key.x >= 0) && (key.x < tilesAtZoom) && (key.y >= 0) && (key.y < tilesAtZoom);
51}
52
53double tileSpanAtZoom(int zoom)
54{
55 return worldSize() / static_cast<double>(1 << std::clamp(zoom, kMinZoom, kMaxZoom));
56}
57
58QPointF tileMinCorner(const TileKey& key)
59{
60 const double span = tileSpanAtZoom(key.zoom);
61 const double half = worldSize() / 2.0;
62 const double minX = -half + (key.x * span);
63 const double minY = half - ((key.y + 1) * span);
64 return QPointF(minX, minY);
65}
66
67TileKey tileForWorld(const QPointF& world, int zoom)
68{
69 const int clampedZoom = std::clamp(zoom, kMinZoom, kMaxZoom);
70 const double span = tileSpanAtZoom(clampedZoom);
71 const double half = worldSize() / 2.0;
72 const int tileCount = 1 << clampedZoom;
73
74 const double x = std::clamp(world.x(), -half, half);
75 const double y = std::clamp(world.y(), -half, half);
76
77 TileKey key;
78 key.zoom = clampedZoom;
79 key.x = std::clamp(static_cast<int>(std::floor((x + half) / span)), 0, tileCount - 1);
80 key.y = std::clamp(static_cast<int>(std::floor((half - y) / span)), 0, tileCount - 1);
81 return key;
82}
83
84double metersPerPixelAtZoom(int zoom)
85{
86 return tileSpanAtZoom(zoom) / static_cast<double>(kTilePixels);
87}
88
89int zoomForMetersPerPixel(double metersPerPixel)
90{
91 if (metersPerPixel <= 0.0) {
92 return kMaxZoom;
93 }
94 const double zoomExact = std::log2(metersPerPixelAtZoom(kMinZoom) / metersPerPixel);
95 return std::clamp(static_cast<int>(std::ceil(zoomExact)), kMinZoom, kMaxZoom);
96}
97
98} // namespace TileMath
constexpr double kMaxLatitude
Mercator latitude clamp (deg)
Definition TileMath.h:29
constexpr int kTilePixels
Nominal tile edge used for meters-per-pixel.
Definition TileMath.h:32
double worldSize()
Full mercator world extent (2*pi*R) in world meters.
Definition TileMath.cc:18
constexpr double kEarthRadius
WGS84 equatorial radius (m)
Definition TileMath.h:28
QPointF geoToWorld(const QGeoCoordinate &coord)
Geo -> world meters. Latitude is clamped to +/-kMaxLatitude.
Definition TileMath.cc:23
QPointF tileMinCorner(const TileKey &key)
South-west (minimum x/y) corner of a tile in world meters.
Definition TileMath.cc:58
constexpr int kMaxZoom
Definition TileMath.h:31
bool isValidKey(const TileKey &key)
True if zoom is within [kMinZoom, kMaxZoom] and x/y address a tile at that zoom.
Definition TileMath.cc:44
QDebug operator<<(QDebug debug, const TileKey &key)
Streams as slippy "zoom/x/y" notation for logging.
Definition TileMath.cc:11
constexpr int kMinZoom
Definition TileMath.h:30
int zoomForMetersPerPixel(double metersPerPixel)
Smallest zoom whose resolution is at least as fine as metersPerPixel (clamped to valid range)
Definition TileMath.cc:89
double mercatorScale(double latitude)
Definition TileMath.cc:38
double metersPerPixelAtZoom(int zoom)
World meters spanned by one pixel of a kTilePixels tile at zoom (equator)
Definition TileMath.cc:84
QGeoCoordinate worldToGeo(const QPointF &world)
World meters -> geo (altitude 0)
Definition TileMath.cc:31
double tileSpanAtZoom(int zoom)
Edge length of one tile at zoom, in world meters.
Definition TileMath.cc:53
TileKey tileForWorld(const QPointF &world, int zoom)
Tile containing a world point. World coordinates are clamped to the world extent.
Definition TileMath.cc:67