【经纬度坐标系、墨卡托投影坐标系和屏幕坐标系转换详解】
地图坐标系转换详解
- 1. 引言
- 2. 坐标系定义
- 2.1 经纬度坐标系
- 2.2 墨卡托投影坐标系
- 3.3 屏幕坐标系
- 2. 坐标系间的转换
- 2.1 经纬度坐标系到墨卡托投影坐标系
- 2.2 墨卡托投影坐标系到经纬度坐标系
- 2.3 墨卡托投影坐标系到屏幕坐标系
- 2.4 屏幕坐标系到墨卡托投影坐标系
- 2.5 经纬度坐标系到屏幕坐标系
- 2.6 屏幕坐标系到经纬度坐标系
- 3. 示例代码
- 4. 结语
1. 引言
在地理信息系统(GIS)领域,坐标系转换是一项基础而重要的任务。本文将围绕三种主要的地图坐标系——墨卡托投影坐标系、屏幕坐标系和经纬度坐标系——探讨它们之间的相互转换关系,并提供相应的数学推导及实现方法。
2. 坐标系定义
2.1 经纬度坐标系
原点:经纬度坐标系的原点是位于赤道和格林威治子午线交点的位置,即 (0°, 0°)
。
- 定义:经纬度坐标系是最常见的地理坐标系统,其中经度(longitude)范围是
-180°
到+180°
,纬度(latitude)范围是-90°
到+90°
。 - 坐标轴:经度值从西向东递增,纬度值从南向北递增。
- 符号表示:
(lon, lat)
。
North (positive latitude)||+---+---+| | |
West (-longitude) +---+---+ East (positive longitude)| | |+---+---+||South (negative latitude)
2.2 墨卡托投影坐标系
原点:墨卡托投影坐标系的原点通常位于 (0°, 0°)
,即赤道和格林威治子午线的交点。但在实际应用中,特别是在Web地图服务中,原点可能被设置为地图的中心点,以适应特定的地图范围。
- 定义:墨卡托投影是一种圆柱投影,地球表面在投影平面上表现为正方形网格,适用于Web地图服务。
- 坐标轴:X 轴代表经度,Y 轴代表纬度,但纬度经过了变形处理。
- 符号表示:
(x, y)
。
谷歌地图、微软地图、百度地图、腾讯地图、高德地图等网络地图所使用的投影都是网络墨卡托投影(Web Mercator),尽管我们喜欢把百度地图、高德地图称之为火星坐标系,不过它们还是没逃出网络墨卡托投影的手心。
North (positive y)||+---+---+| | |
West (negative x) +---+---+ East (positive x)| | |+---+---+||South (negative y)
3.3 屏幕坐标系
原点:屏幕坐标系的原点通常位于屏幕的左上角,即 (0, 0)。这意味着 X 值从左向右增大,Y 值从上向下增大。
- 定义:屏幕坐标系是图形显示设备(如显示器)的像素坐标系统。
- 坐标轴:通常情况下,原点位于左上角,X 轴水平向右,Y 轴垂直向下。
- 符号表示:
(x_screen, y_screen)
。
+------------------------------------> x+| | (o o) | / V \ | (_______) | | | ∨y+
2. 坐标系间的转换
2.1 经纬度坐标系到墨卡托投影坐标系
墨卡托投影的转换公式如下:
x m e r c a t o r = R ⋅ x l o n g i t u d e ⋅ π 180 x_{mercator} = \frac{R \cdot {x_{longitude} } \cdot \pi}{180} xmercator=180R⋅xlongitude⋅π
y m e r c a t o r = R ⋅ ln ( tan ( π 4 + y l a t i t u d e 2 ) ) π 180 y_{mercator} = \frac{R \cdot \ln(\tan(\frac{\pi}{4} + \frac{y_{latitude}}{2})) \pi}{180} ymercator=180R⋅ln(tan(4π+2ylatitude))π
其中,经纬度以角度为单位, R R R是地球半径,通常取为 6378137 米。
2.2 墨卡托投影坐标系到经纬度坐标系
反向转换公式为:
x l o n g i t u d e = 180 ⋅ x m e r c a t o r π ⋅ R x_{longitude} = \frac{180\cdot x_{mercator}}{\pi\cdot R} xlongitude=π⋅R180⋅xmercator
y l a t i t u d e = ( 2 ⋅ arctan ( e y m e r c a t o r / R ) − π 2 ) 180 π y_{latitude} = \frac{(2 \cdot \arctan(e^{y_{mercator}/R}) - \frac{\pi}{2})180}{\pi} ylatitude=π(2⋅arctan(eymercator/R)−2π)180
2.3 墨卡托投影坐标系到屏幕坐标系
假设屏幕分辨率是 width
和 height
,并且屏幕中心对应于地图的中心点 ( x c e n t e r , y c e n t e r ) (x_{center}, y_{center}) (xcenter,ycenter),缩放级别为 zoomLevel。
计算缩放因子:
s c a l e = 2 z o o m l e v e l scale =2^{zoomlevel} scale=2zoomlevel
计算屏幕中心点对应的墨卡托投影坐标:
x c e n t e r _ s r e e n = x c e n t e r _ m e r a t o r ; y c e n t e r _ s r e e n = y c e n t e r _ m e r a t o r x_{center\_sreen} = x_{center\_merator} ;y_{center\_sreen} = y_{center\_merator} xcenter_sreen=xcenter_merator;ycenter_sreen=ycenter_merator
计算屏幕坐标:
x s c r e e n = ( x m e r a t o r − x c e n t e r _ m e r a t o r R ) ⋅ s c a l e + w i d t h 2 x_{screen} = (\frac{x_{merator}-x_{center\_merator}}{R})\cdot scale +\frac {width}{2} xscreen=(Rxmerator−xcenter_merator)⋅scale+2width
y s c r e e n = h e i g h 2 − ( y m e r a t o r − y c e n t e r _ m e r a t o r R ) ⋅ s c a l e y_{screen} = \frac {heigh}{2}-(\frac{y_{merator}-y_{center\_merator}}{R})\cdot scale yscreen=2heigh−(Rymerator−ycenter_merator)⋅scale
2.4 屏幕坐标系到墨卡托投影坐标系
假设屏幕坐标为 ( x s r e e n , y s r e e n ) (x_{sreen},y_{sreen}) (xsreen,ysreen) ,屏幕分辨率为 width 和 height,屏幕中心对应于地图的中心点 ( x c e n t e r s r e e n , y c e n t e r s r e e n ) (x_{center_sreen},y_{center_sreen}) (xcentersreen,ycentersreen) ,缩放级别为 zoomLevel
计算缩放因子:
s c a l e = 2 z o o m l e v e l scale =2^{zoomlevel} scale=2zoomlevel
计算墨卡托中心点对应的投影屏幕坐标:
x c e n t e r _ m e r a t o r = x c e n t e r _ s r e e n ; y c e n t e r _ m e r a t o r = y c e n t e r _ s r e e n x_{center\_merator} = x_{center\_sreen} ;y_{center\_merator} = y_{center\_sreen} xcenter_merator=xcenter_sreen;ycenter_merator=ycenter_sreen
计算屏幕坐标:
x m e r a t o r = ( x s r e e n − s c a l e 2 ) ⋅ R s c a l e + x c e n t e r _ m e r a t o r x_{merator} = (x_{sreen}-\frac{scale}{2})\cdot \frac {R}{scale} + x_{center\_merator} xmerator=(xsreen−2scale)⋅scaleR+xcenter_merator
y m e r a t o r = y c e n t e r _ m e r a t o r − ( y s r e e n − s c a l e 2 ) ⋅ R s c a l e y_{merator} = y_{center\_merator} - (y_{sreen}-\frac{scale}{2})\cdot \frac {R}{scale} ymerator=ycenter_merator−(ysreen−2scale)⋅scaleR
2.5 经纬度坐标系到屏幕坐标系
结合上述 2.1 和 2.3 的转换公式,可以得到:
x s c r e e n = ( R ⋅ x l o n g i t u d e ⋅ π 180 − x c e n t e r _ m e r a t o r R ) ⋅ s c a l e + w i d t h 2 x_{screen} = (\frac{\frac{R \cdot {x_{longitude} } \cdot \pi}{180}-x_{center\_merator}}{R})\cdot scale +\frac {width}{2} xscreen=(R180R⋅xlongitude⋅π−xcenter_merator)⋅scale+2width
y s c r e e n = h e i g h 2 − ( R ⋅ ln ( tan ( π 4 + y l a t i t u d e 2 ) ) π 180 − y c e n t e r _ m e r a t o r R ) ⋅ s c a l e y_{screen} = \frac {heigh}{2}-(\frac{\frac{R \cdot \ln(\tan(\frac{\pi}{4} + \frac{y_{latitude}}{2})) \pi}{180}-y_{center\_merator}}{R})\cdot scale yscreen=2heigh−(R180R⋅ln(tan(4π+2ylatitude))π−ycenter_merator)⋅scale
2.6 屏幕坐标系到经纬度坐标系
结合上述 2.4 和 2.2 的转换公式,可以得到:
x l o n g i t u d e = 180 ⋅ ( ( x s r e e n − s c a l e 2 ) ⋅ R s c a l e + x c e n t e r _ m e r a t o r ) π ⋅ R x_{longitude} = \frac{180\cdot ((x_{sreen}-\frac{scale}{2})\cdot \frac {R}{scale} + x_{center\_merator})}{\pi\cdot R} xlongitude=π⋅R180⋅((xsreen−2scale)⋅scaleR+xcenter_merator)
y l a t i t u d e = ( 2 ⋅ arctan ( e y c e n t e r _ m e r a t o r − ( y s r e e n − s c a l e 2 ) ⋅ R s c a l e R ) − π 2 ) 180 π y_{latitude} = \frac{(2 \cdot \arctan(e^{\frac{y_{center\_merator} - (y_{sreen}-\frac{scale}{2})\cdot \frac {R}{scale}}R}) - \frac{\pi}{2})180}{\pi} ylatitude=π(2⋅arctan(eRycenter_merator−(ysreen−2scale)⋅scaleR)−2π)180
3. 示例代码
以下是一个简单的 C++ 示例代码,演示了上述部分转换的过程:
#include <iostream>
#include <cmath>// 常量定义
const double EARTH_RADIUS = 6378137.0; // 地球半径,单位:米
const double PI = 3.14159265358979323846;// 经纬度坐标结构体
struct LatLng {double lat; // 纬度double lng; // 经度
};// 墨卡托投影坐标结构体
struct Mercator {double x; // 经度方向的投影坐标double y; // 纬度方向的投影坐标
};// 屏幕坐标结构体
struct Screen {double x; // 屏幕x坐标double y; // 屏幕y坐标
};// 经纬度转墨卡托投影
Mercator latLngToMercator(const LatLng& latLng) {Mercator mercator;mercator.x = latLng.lng * EARTH_RADIUS * PI / 180.0;mercator.y = log(tan((90.0 + latLng.lat) * PI / 360.0)) * EARTH_RADIUS;return mercator;
}// 墨卡托投影转经纬度
LatLng mercatorToLatLng(const Mercator& mercator) {LatLng latLng;latLng.lng = mercator.x / (EARTH_RADIUS * PI / 180.0);latLng.lat = 180.0 / PI * (2.0 * atan(exp(mercator.y / EARTH_RADIUS)) - PI / 2.0);return latLng;
}// 墨卡托投影转屏幕坐标
Screen mercatorToScreen(const Mercator& mercator, double zoomLevel) {Screen screen;double scale = pow(2.0, zoomLevel);screen.x = mercator.x * scale / EARTH_RADIUS + 0.5;screen.y = 0.5 - mercator.y * scale / EARTH_RADIUS;return screen;
}// 屏幕坐标转墨卡托投影
Mercator screenToMercator(const Screen& screen, double zoomLevel) {Mercator mercator;double scale = pow(2.0, zoomLevel);mercator.x = (screen.x - 0.5) * EARTH_RADIUS / scale;mercator.y = (0.5 - screen.y) * EARTH_RADIUS / scale;return mercator;
}// 屏幕坐标转经纬度
LatLng screenToLatLng(const Screen& screen, double zoomLevel) {Mercator mercator = screenToMercator(screen, zoomLevel);return mercatorToLatLng(mercator);
}// 经纬度转屏幕坐标
Screen latLngToScreen(const LatLng& latLng, double zoomLevel) {Mercator mercator = latLngToMercator(latLng);return mercatorToScreen(mercator, zoomLevel);
}// 测试代码
int main() {LatLng latLng = {39.9042, 116.4074}; // 北京经纬度double zoomLevel = 10.0; // 缩放级别// 经纬度转墨卡托投影Mercator mercator = latLngToMercator(latLng);std::cout << "经纬度转墨卡托投影: (" << mercator.x << ", " << mercator.y << ")" << std::endl;// 墨卡托投影转经纬度LatLng latLng2 = mercatorToLatLng(mercator);std::cout << "墨卡托投影转经纬度: (" << latLng2.lat << ", " << latLng2.lng << ")" << std::endl;// 墨卡托投影转屏幕坐标Screen screen = mercatorToScreen(mercator, zoomLevel);std::cout << "墨卡托投影转屏幕坐标: (" << screen.x << ", " << screen.y << ")" << std::endl;// 屏幕坐标转墨卡托投影Mercator mercator2 = screenToMercator(screen, zoomLevel);std::cout << "屏幕坐标转墨卡托投影: (" << mercator2.x << ", " << mercator2.y << ")" << std::endl;// 屏幕坐标转经纬度LatLng latLng3 = screenToLatLng(screen, zoomLevel);std::cout << "屏幕坐标转经纬度: (" << latLng3.lat << ", " << latLng3.lng << ")" << std::endl;// 经纬度转屏幕坐标Screen screen2 = latLngToScreen(latLng, zoomLevel);std::cout << "经纬度转屏幕坐标: (" << screen2.x << ", " << screen2.y << ")" << std::endl;return 0;
}
测试效果:
4. 结语
🥳🥳🥳现在,我们在本教程中,您学习了不同坐标系之间的转换涉及到几何变换和数学运算。理解这些转换对于开发地图应用至关重要,希望本文能帮助开发者更好地理解和运用坐标系转换技术。🛹🛹🛹从而实现对外部世界进行感知,充分认识这个有机与无机的环境,后期会持续分享esp32跑freertos实用案列🥳🥳🥳科学地合理地进行创作和发挥效益,然后为人类社会发展贡献一点微薄之力。🤣🤣🤣
如果你有任何问题,可以通过q group(945348278)加入鹏鹏小分队,期待与你思维的碰撞😘😘😘