【经纬度坐标系、墨卡托投影坐标系和屏幕坐标系转换详解】

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=180Rxlongitudeπ

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=180Rln(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=πR180xmercator
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=π(2arctan(eymercator/R)2π)180

2.3 墨卡托投影坐标系到屏幕坐标系

假设屏幕分辨率是 widthheight,并且屏幕中心对应于地图的中心点 ( 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=(Rxmeratorxcenter_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(Rymeratorycenter_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=(xsreen2scale)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(ysreen2scale)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=(R180Rxlongitudeπ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(R180Rln(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((xsreen2scale)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=π(2arctan(eRycenter_merator(ysreen2scale)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)加入鹏鹏小分队,期待与你思维的碰撞😘😘😘

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

2345VOR

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值