使用C++计算地理区域内的瓦片坐标
本文介绍了如何使用C++编程语言计算给定地理区域内的瓦片坐标。通过将经度和纬度转换为对应缩放级别下的瓦片X和Y坐标,可以确定该区域涉及的所有瓦片。使用一个简单的瓦片计算器类,通过提供两个坐标点和缩放级别作为输入,可以计算出该区域内所有瓦片的坐标。详细的代码示例和注释解释了经度和纬度到瓦片坐标的转换过程,帮助读者了解该算法的原理和实现方式。这种计算瓦片坐标的方法对于构建地图应用程序和进行地理数据分析非常有用。
https://wiki.openstreetmap.org/wiki/Slippy_map_tilenames#C/C++
https://tools.geofabrik.de/calc/#type=geofabrik_standard&bbox=72.686499,0.749734,136.132789,53.997465
以下示例代码,详细解释了每个函数的作用和原理:
#include <iostream>
#include <cmath>
#include <vector>
#include <numbers>
struct GeoCoordinate {
double lat; // 纬度
double lon; // 经度
};
class TileCalculator {
public:
/**
* 计算给定区域内的瓦片坐标
*
* @param coord1 区域的第一个坐标点
* @param coord2 区域的第二个坐标点
* @param zoom 瓦片的缩放级别(zoom level)
*/
static void CalculateTiles(const GeoCoordinate& coord1, const GeoCoordinate& coord2, int zoom) {
// Convert latitude and longitude to tile coordinates
int tileX1 = lonToTileX(coord1.lon, zoom); // 获取第一个坐标点的瓦片X坐标
int tileY1 = latToTileY(coord1.lat, zoom); // 获取第一个坐标点的瓦片Y坐标
int tileX2 = lonToTileX(coord2.lon, zoom); // 获取第二个坐标点的瓦片X坐标
int tileY2 = latToTileY(coord2.lat, zoom); // 获取第二个坐标点的瓦片Y坐标
// Find the minimum and maximum tile coordinates
int minX = std::min(tileX1, tileX2); // 计算最小瓦片X坐标
int maxX = std::max(tileX1, tileX2); // 计算最大瓦片X坐标
int minY = std::min(tileY1, tileY2); // 计算最小瓦片Y坐标
int maxY = std::max(tileY1, tileY2); // 计算最大瓦片Y坐标
// Calculate all the tiles within the given range
std::vector<std::pair<int, int>> tiles;
for (int x = minX; x <= maxX; ++x) {
for (int y = minY; y <= maxY; ++y) {
tiles.emplace_back(x, y); // 将瓦片坐标加入到瓦片列表中
}
}
std::cout << "Total Tiles: " << tiles.size() << std::endl;
// Output the calculated tiles
std::cout << "Tiles in the region:" << std::endl;
for (const auto& tile : tiles) {
std::cout << "Tile X: " << tile.first << " Y: " << tile.second << " Zoom: " << zoom << std::endl;
}
}
private:
/**
* 将经度转换为瓦片X坐标
*
* @param lon 经度值
* @param zoom 瓦片的缩放级别(zoom level)
* @return 瓦片X坐标
*/
static int lonToTileX(double lon, int zoom) {
double n = std::pow(2.0, zoom); // 计算总的瓦片数(2的zoom次方)
double x = ((lon + 180.0) / 360.0) * n; // 根据经度计算瓦片X坐标
return static_cast<int>(std::floor(x));
}
/**
* 将纬度转换为瓦片Y坐标
*
* @param lat 纬度值
* @param zoom 瓦片的缩放级别(zoom level)
* @return 瓦片Y坐标
*/
static int latToTileY(double lat, int zoom) {
double n = std::pow(2.0, zoom); // 计算总的瓦片数(2的zoom次方)
double latRad = lat * std::numbers::pi / 180.0; // 将纬度转换为弧度
double y = (1.0 - std::log(std::tan(latRad) + (1.0 / std::cos(latRad))) / std::numbers::pi) / 2.0 * n; // 根据纬度计算瓦片Y坐标
return static_cast<int>(std::floor(y));
}
};
int main() {
GeoCoordinate coord1 = {23.944263939709483, 111.95644852132074};
GeoCoordinate coord2 = {23.219312773466363, 115.01064762433803};
int zoom = 13;
TileCalculator::CalculateTiles(coord1, coord2, zoom);
return 0;
}
该示例代码通过将经度(lon)和纬度(lat)包装在GeoCoordinate
结构体中,使得代码更易读和维护。CalculateTiles
方法接受两个坐标点和缩放级别(zoom level),并根据这些参数计算瓦片坐标。最终,计算出给定区域内的瓦片坐标并输出。
计算瓦片坐标的原理是将地理坐标(经纬度)转换为对应缩放级别下的瓦片坐标。lonToTileX
函数将经度转换为瓦片X坐标,使用公式:((lon + 180.0) / 360.0) * n
,其中lon
是经度值,n
是总的瓦片数(2的zoom次方)。latToTileY
函数将纬度转换为瓦片Y坐标,使用公式:(1.0 - log(tan(latRad) + (1.0 / cos(latRad))) / pi) / 2.0 * n
,其中lat
是纬度值,latRad
是将纬度转换为弧度后的值,n
是总的瓦片数。
通过计算出两个坐标点对应的瓦片坐标范围,可以得到该范围内的所有瓦片坐标,并输出结果。
这样,我们就可以使用TileCalculator类来计算给定区域和缩放级别下的瓦片坐标。