GPS原始坐标转百度地图坐标(纯C代码)

460 阅读5分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第1天,点击查看活动详情

说到GPS,大家都不陌生,现在的手机、健康手环里都有GPS设备,导航软件、运动健身设备都需要GPS来记录轨迹,分享运动时光,这些都需要GPS的支持。这篇文章就就介绍如何获取GPS模块输出的数据,并且进行转换,得到百度地图可以直接使用的经纬度。

image.png

在完成GPS数据转换之前,先了解一下GPS相关的知识点:(下面的介绍来至网络)

随着BDS系统完成亚太地区组网、GLONASS 系统再次实现满星座部署以及GPS系统的现代化,多系统集成已逐步成为网络 RTK 技术的发展趋势。

国际导航界的一个重要发展趋势是多模定位。北斗(中国)、GPS(美国)、GLONASS(俄罗斯)、GALILEO(欧盟)四大全球系统最多可以有 140 多颗卫星提供定位信号,多模联合定位与单 GPS 定位相比,可以大大改善“城市峡谷”环境中的卫星遮挡问题,使得定位更准确,定位率更高,定位的有效性获得经一步改善,有助于在小区,街道,高架等恶劣环境获得合理的定位效果。在不增加成本的情况下,升级成多模定位,已经是智能定位设备的大趋势。

什么是 BDS ? BDS 是中国具有完全自主知识产权的北斗卫星导航系统的简称。是继美国全球卫星定位系统和俄罗斯全球卫星导航系统 GLONASS 之后第三个成熟的卫星导航系统。北斗系统从工程实施上分为北斗一代和北斗二代。北斗二代卫星目前在轨并正常运行的卫星 14 颗,覆盖亚太地区。中国计划 2020 年 BDS 实现全球覆盖。

什么是 GPS ? GPS 全称全球定位系统,起初由美国军方主导建设,因良好的技术基础而被广泛民用。市场上喜好将导航仪、定位仪等设备统称为”GPS”,其实是这些定位终端中携带有支持接收 GPS 卫星信号并实现定位的 GPS 芯片。

什么是 GALILEO ? GALILEO 是欧盟的全球卫星导航系统。2014年处于实验阶段,发射4颗实验卫星。 「GP-02」是安信可科技基于中科微新一代自主研发的射频基带一体化导航 SoC 芯片自主研发的模组,具有低功耗,小体积等特点,首次支持 BDS+GPS 双模联合定位,是终端设备替代单 GPS 模块,或增加北斗定位功能的最佳选择。可支持客户在 tracker,OBD,定位手环,校园卡等智能设备中升级多模定位功能。

一、环境介绍

GPS模块型号: 中科微电子GPS模块

GPS输出的原始数据帧:

 $GNGGA,114955.000,2842.4158,N,11549.5439,E,1,05,3.8,54.8,M,0.0,M,,*4F
 $GNGLL,2842.4158,N,11549.5439,E,114955.000,A,A*4D
 $GPGSA,A,3,10,31,18,,,,,,,,,,5.7,3.8,4.2*37
 $BDGSA,A,3,07,10,,,,,,,,,,,5.7,3.8,4.2*2A
 $GPGSV,3,1,10,10,49,184,42,12,16,039,,14,54,341,,18,22,165,23*7B
 $GPGSV,3,2,10,22,11,318,,25,51,055,,26,24,205,,29,13,110,*7C
 $GPGSV,3,3,10,31,50,287,36,32,66,018,*7F
 $BDGSV,1,1,04,03,,,07,05,,,29,07,79,246,33,10,52,232,19*62
 $GNRMC,114955.000,A,2842.4158,N,11549.5439,E,0.00,44.25,061117,,,A*4D
 $GNVTG,44.25,T,,M,0.00,N,0.00,K,A*14
 $GNZDA,114955.000,06,11,2017,00,00*47
 $GPTXT,01,01,01,ANTENNA OK*35

二、需求介绍

得到GPS原始坐标数据之后,想通过百度地图API接口直接显示实际定位。

国际经纬度坐标标准为WGS-84,国内必须至少使用国测局制定的GCJ- 02,对地理位置进行首次加密。

百度坐标在此基础上,进行了BD-09二次加密措施,更加保护了个人隐私。

百度对外接口的坐标系并不是GPS采集的真实经 纬度,需要通过坐标转换接口进行转换。

三、C语言代码

下面代码在QtCreator里编写,可以将代码移植到任何支持C语言的环境中编译运行。

 #include <QCoreApplication>
 #include "QString"
 #include <QDebug>
 extern "C"
 {
 #include "math.h"
 }
 ​
 class GPS_Data
 {
 public:
     double lat; //纬度
     double lng; //经度
     QString GPS_Data;
 };
 class GPS_Data gps_data;
 ​
 void GPS_ReadUasrtData();
 ​
 ​
 #define M_PI  3.14159265358979324
 double  a = 6378245.0;
 double  ee = 0.00669342162296594323;
 double  x_pi = M_PI * 3000.0 / 180.0;
 ​
 double wgs2gcj_lat(double x, double y)
 {
    double ret1 = -100.0 + 2.0 * x + 3.0 * y + 0.2 * y * y + 0.1 * x * y  + 0.2 * sqrt(abs(x));
    ret1 += (20.0 * sin(6.0 * x * M_PI) + 20.0 * sin(2.0 * x  * M_PI)) * 2.0 / 3.0;
    ret1 += (20.0 * sin(y * M_PI) + 40.0 * sin(y / 3.0 * M_PI)) * 2.0 / 3.0;
    ret1 += (160.0 * sin(y / 12.0 * M_PI) + 320 * sin(y * M_PI  / 30.0)) * 2.0 / 3.0;
    return ret1;
 }
 ​
 double  wgs2gcj_lng(double x, double y)
 {
     double ret2 = 300.0 + x + 2.0 * y + 0.1 * x * x + 0.1 * x * y + 0.1  * sqrt(abs(x));
     ret2 += (20.0 *sin(6.0 * x * M_PI) + 20.0 * sin(2.0 * x  * M_PI)) * 2.0 / 3.0;
     ret2 += (20.0 * sin(x * M_PI) + 40.0 * sin(x / 3.0 * M_PI)) * 2.0 / 3.0;
     ret2 += (150.0 *sin(x / 12.0 * M_PI) + 300.0 * sin(x / 30.0  * M_PI)) * 2.0 / 3.0;
     return ret2;
 }
 ​
 void wgs2gcj(double *lat,double *lng)
 {
     double dLat = wgs2gcj_lat(*lng - 105.0, *lat - 35.0);
     double dLon = wgs2gcj_lng(*lng - 105.0, *lat - 35.0);
     double radLat = *lat / 180.0 * M_PI;
     double magic = sin(radLat);
     magic = 1 - ee * magic * magic;
     double sqrtMagic = sqrt(magic);
     dLat = (dLat * 180.0) / ((a * (1 - ee)) / (magic * sqrtMagic) * M_PI);
     dLon = (dLon * 180.0) / (a / sqrtMagic * cos(radLat) * M_PI);
     *lat = *lat + dLat;
     *lng = *lng + dLon;
 }
 ​
 void gcj2bd(double *lat,double *lng)
 {
    double x = *lng, y = *lat;
    double z = sqrt(x * x + y * y) + 0.00002 * sin(y * x_pi);
    double theta = atan2(y, x) + 0.000003 * cos(x * x_pi);
    *lng = z * cos(theta) + 0.0065;
    *lat = z * sin(theta) + 0.006;
 }
 ​
 int main(int argc, char *argv[])
 {
     QCoreApplication a(argc, argv);
     GPS_ReadUasrtData();
 ​
     //得到GPS原始坐标
     double lat=gps_data.lat;
     double lng=gps_data.lng;
 ​
     //坐标转换
     wgs2gcj(&lat,&lng);
     gcj2bd(&lat,&lng);
 ​
     //得到百度地图的坐标,可以直接在百度地图上显示
     qDebug()<<"纬度: "<<QString("%1").arg(lat,0,'g',13);
     qDebug()<<"经度: "<<QString("%1").arg(lng,0,'g',13);
 ​
     return a.exec();
 }
 ​
 ​
 void GPS_ReadUasrtData()
 {
     /*GPS的原始数据帧*/
     gps_data.GPS_Data="$GNGGA,114955.000,2842.4158,N,11549.5439,E,1,05,3.8,54.8,M,0.0,M,,*4F"
             "$GNGLL,2842.4158,N,11549.5439,E,114955.000,A,A*4D"
             "$GPGSA,A,3,10,31,18,,,,,,,,,,5.7,3.8,4.2*37"
             "$BDGSA,A,3,07,10,,,,,,,,,,,5.7,3.8,4.2*2A"
            " $GPGSV,3,1,10,10,49,184,42,12,16,039,,14,54,341,,18,22,165,23*7B"
             "$GPGSV,3,2,10,22,11,318,,25,51,055,,26,24,205,,29,13,110,*7C"
             "$GPGSV,3,3,10,31,50,287,36,32,66,018,*7F"
             "$BDGSV,1,1,04,03,,,07,05,,,29,07,79,246,33,10,52,232,19*62"
             "$GNRMC,114955.000,A,2842.4158,N,11549.5439,E,0.00,44.25,061117,,,A*4D"
             "$GNVTG,44.25,T,,M,0.00,N,0.00,K,A*14"
             "$GNZDA,114955.000,06,11,2017,00,00*47"
             "$GPTXT,01,01,01,ANTENNA OK*35";
 ​
     /*解析GPS模块的数据*/
     //QString lat; //纬度
     //QString lng; //经度
     if(gps_data.GPS_Data.size()>200)
     {
         int index=gps_data.GPS_Data.indexOf("$GNGGA");
         if(index>=0)
         {
             QString text=gps_data.GPS_Data.mid(index);
             if(text.size()>60)
             {
                 QString lat=text.section(',',2,2);
                 QString lng=text.section(',',4,4);
                 if(lat.isEmpty()==false && lng.isEmpty()==false)
                 {
                     unsigned int int_data;
                     double s_Longitude,s_latitude;
 ​
                     //转换纬度
                     s_latitude=lat.toDouble();
 ​
                     s_latitude=s_latitude/100;
                     int_data=s_latitude;//得到纬度整数部分
                     s_latitude=s_latitude-int_data;//得到纬度小数部分
                     s_latitude=(s_latitude)*100;
                     gps_data.lat=int_data+(s_latitude/60.0); //得到转换后的值
 ​
                     //转换经度
                     s_Longitude=lng.toDouble();
 ​
                     s_Longitude=s_Longitude/100;
                     int_data=s_Longitude;//得到经度整数部分
                     s_Longitude=s_Longitude-int_data; //得到经度小数部分
                     s_Longitude=s_Longitude*100;
 ​
                     //gai guo le
                     gps_data.lng=int_data+(s_Longitude/60.0);
 ​
                 }
             }
         }
         gps_data.GPS_Data.clear();
     }
 }

image.png

image.png

image.png