在有的时候,我们会遇到需要将GPS坐标转换成地球表面的平面坐标。虽然想起来很简单,只需要把GPS球坐标系转换成球表面的平面直角坐标系,但是,当查阅很多资料之后,我们会发现地球不是一个椭球状,不同的地区使用的地球椭球模型还不一样。尤其是对于我们这种从没有系统学过GIS等等这类知识的人,想在短短几天之内搞定GPS转平面坐标,还真的是不容易。索性,目前有一个很棒的库,称之为PROJ4,可以用C++进行调用,官网地址为https://proj4.org/index.html 。关于PROJ4的配置方法这里不再提了,主要是如何使用这个库。
由于地球不是一个椭球,所以在不同的地方使用不同的椭球进行逼近最好。如中国地区使用的有克拉索夫斯基椭球、1975年标准椭球等等,而全球定位GPS系统使用的又是另一种WGS84椭球。目前,中国常见的标准坐标系有CGJ02、BD09、西安80、北京54、CGCS2000。其中火星坐标CGJ02、百度坐标BD09、CGCS2000均以地球质量中心为原点,是空间坐标。而西安80和北京54分别以我国中部的陕西省泾阳县永乐镇和前苏联的普尔科沃位原点的平面坐标系,分别是1980年和1954年制定。因此西安80坐标系是中国官方最准确的平面坐标系。只需要进行GPS到西安80坐标系的转换,即可得到平面坐标。
那么,如何选定参数才能让PROJ4这个开源库执行我们想要的WGS84到西安80坐标转换的功能呢?PROJ4这个库的参数确实太多了,官方的文档看得也是头晕,对于没学过GIS想快速上手的人来说很难用。所以,经过几天的摸索,我们偶然间查到了这个网站:https://mygeodata.cloud/cs2cs/
这是一个在线的坐标转换的网站,同时提供了PROJ4的参数设定代码,这样我们就不需要去看说明书,然后去一步一步设定具体的参数了。我们选择“choose input coordinate system...”
写在第一个的就是WGS84这个GPS所用的系统。点击选择之后,就可以看到自动生成了我们想要的代码:
+proj=longlat +datum=WGS84 +no_defs
同样的,我们可以选择输出坐标的形式。如在“choose output coordinate system”里面打字xian 1980
有西安1980的球面坐标和不同的投影方式,投影方式适用的经纬度地区均不同。特别要注意,有的投影方式的坐标原点是不变的,相同的GPS坐标计算出来结果略有差异是因为坐标原点改变了。而有的投影方式坐标原点改变了, 所以采用不同的投影方式,有时候的坐标差距很大,有时候的坐标差距很小。
这个上面的EPSG好像是一个代号,应该是某个组织将常见的地图坐标系等等都整理了一遍然后给他们编了号码,编号具体意思查询可以在https://epsg.io/上面查询,常见的GPS所用的是EPSG:4226等等。所以使用EPSG上面的标准投影算法,比我们自己找资料然后考虑用哪种投影应该要好。
最后贴上所做出来的c++源代码,上面的字符串hangzhou和wgs84使用的分别是在杭州处投影的80坐标系和全球GPS坐标系
#include
#include
#include
#include
using namespace std;
#define pi 3.141592653
int main(void)
{
double longtitude1 = 120;//GPS经度
double latitude1 = 30;//GPS纬度
double x;
double y;
//杭州经度:120.19 , 纬度:30.26
//坐标系/投影方式/EPSG代号: Xian 1980 / 3-degree Gauss-Kruger zone 40 /EPSG:2364
//投影方式适用范围:中国东经118°30'~东经121°30'
//参数:
const char *city = "+proj=tmerc +lat_0=0 +lon_0=120 +k=1 +x_0=40500000 +y_0=0 +a=6378140 +b=6356755.288157528 +units=m +no_defs ";
const char *wgs84 = "+proj=longlat +datum=WGS84 +no_defs ";//GPS所用坐标系,EPSG:4326
projPJ pj_wgs84 = pj_init_plus(wgs84);
projPJ pj_city = pj_init_plus(city);
printf("********GPS经纬度转换成中国西安80标准坐标系*******\n\n\n");
printf("GPS经纬度\t%lf\t%lf\n\n", longtitude1, latitude1);
//经纬度角度改弧度
x = longtitude1 * DEG_TO_RAD;
y = latitude1 * DEG_TO_RAD;
//将GPS经纬度投影转换
//在东经118°30'~东经121°30'进行投影计算(杭州地区)
pj_transform(pj_wgs84, pj_city, 1, 1, &x, &y, NULL);
printf("在杭州附近投影\n投影方式:3-degree Gauss-Kruger\n得到坐标\t%lf\t%lf\n\n", x, y);
//变换回GPS的WGS84坐标系
printf("\n******在杭州反投影将西安80转GPS坐标******\n\n");
printf("西安坐标%lf\t%lf\t",x,y);
pj_transform(pj_city, pj_wgs84, 1, 1, &x, &y, NULL);
printf("GPS反变换经纬度\t%lf\t%lf\n\n", x / DEG_TO_RAD, y / DEG_TO_RAD);
//西安80变换回GPS的WGS84坐标系
//坐标1
x = 39500000;
y = 5000000;
printf("西安坐标%lf\t%lf\t", x, y);
pj_transform(pj_city, pj_wgs84, 1, 1, &x, &y, NULL);
printf("GPS反变换经纬度\t%lf\t%lf\n\n", x / DEG_TO_RAD, y / DEG_TO_RAD);
//坐标2
x = 39500001;
y = 5000000;
printf("西安坐标%lf\t%lf\t", x, y);
pj_transform(pj_city, pj_wgs84, 1, 1, &x, &y, NULL);
printf("GPS反变换经纬度\t%lf\t%lf\n\n", x / DEG_TO_RAD, y / DEG_TO_RAD);
//坐标3
x = 39500001;
y = 5000100;
printf("西安坐标%lf\t%lf\t", x, y);
pj_transform(pj_city, pj_wgs84, 1, 1, &x, &y, NULL);
printf("GPS反变换经纬度\t%lf\t%lf\n\n", x / DEG_TO_RAD, y / DEG_TO_RAD);
system("pause");
return 0;
}