查看: 2307|回复: 1

GPS真实坐标与火星地图坐标/百度地图坐标的转换

[复制链接]

该用户从未签到

发表于 2020-7-18 13:22 | 显示全部楼层 |阅读模式
      使用GPS模块可以获得真实地理坐标,但是,往往我们将得到的数据放到一些地图服务商提供的地图上查看会发现偏移很大。其实,很多人忽略了一点,国家为了电子地图安全,强制要求地图服务商对地图坐标进行加密,产生随机偏移,因此我们看到的地图上标注的地理位置并不是自己的真实地理位置。GCJ-02加密标准是基本的数据加密算法,百度地图在GCJ-02的基础上又加入了自己的一套加密算法。以下将获得的GPS数据转换为GCJ-02地理坐标或百度地图坐标,通过逆向地理编码你就能查到具体的位置信息。
  1. #include <M5Stack.h>
  2. #include <TinyGPS++.h>
  3. #include <math.h>
  4. static const uint32_t GPSBaud = 9600;
  5. TinyGPSPlus gps;
  6. HardwareSerial ss(2);

  7. double pi = 3.14159265358979324;      //圆周率
  8. double ee = 0.00669342162296594323;   //椭球的偏心率
  9. double a = 6378245.0;                 //卫星椭球坐标投影到平面地图坐标系的投影因子
  10. double x_pi = 3.14159265358979324 * 3000.0 / 180.0;  //圆周率转换量
  11. double Lat;
  12. double Lon;

  13. // 求弧度
  14. double radian(double d)
  15. {
  16.     return d * pi / 180.0;   //角度1? = π / 180
  17. }

  18. double transformLat(double lat, double lon)    //纬度转化
  19. {
  20.    double ret = -100.0 + 2.0 * lat + 3.0 * lon + 0.2 * lon * lon + 0.1 * lat * lon + 0.2 * sqrt(abs(lat));
  21.    ret += (20.0 * sin(6.0 * lat * pi) + 20.0 * sin(2.0 * lat * pi)) * 2.0 / 3.0;
  22.    ret += (20.0 * sin(lon * pi) + 40.0 * sin(lon / 3.0 * pi)) * 2.0 / 3.0;
  23.    ret += (160.0 * sin(lon / 12.0 * pi) + 320 * sin(lon * pi  / 30.0)) * 2.0 / 3.0;
  24.    return ret;
  25. }


  26. double transformLon(double lat,double lon)   //经度转化
  27. {
  28.    double ret = 300.0 + lat + 2.0 * lon + 0.1 * lat * lat + 0.1 * lat * lon + 0.1 * sqrt(abs(lat));
  29.    ret += (20.0 * sin(6.0 * lat * pi) + 20.0 * sin(2.0 * lat * pi)) * 2.0 / 3.0;
  30.    ret += (20.0 * sin(lat * pi) + 40.0 * sin(lat / 3.0 * pi)) * 2.0 / 3.0;
  31.    ret += (150.0 * sin(lat / 12.0 * pi) + 300.0 * sin(lat / 30.0 * pi)) * 2.0 / 3.0;
  32.    return ret;
  33. }


  34. /*****************************************************************************
  35. * WGS84(GPS坐标系) to 火星坐标系(GCJ-02)
  36. *
  37. * @param lat
  38. * @param lon
  39. * @return
  40. ****************************************************************************/
  41. void GPS84_To_GCJ02(double WGS84_Lat, double WGS84_Lon,double * GCJ02_Lat, double * GCJ02_Lon)
  42. {
  43.   double dLat;
  44.   double dLon;
  45.   double radLat;
  46.   double magic;
  47.   double sqrtMagic;

  48.   dLat = transformLat(WGS84_Lon - 105.0, WGS84_Lat - 35.0);
  49.   dLon = transformLon(WGS84_Lon - 105.0, WGS84_Lat - 35.0);
  50.   radLat = WGS84_Lat / 180.0 * pi;
  51.   magic = sin(radLat);
  52.   magic = 1 - ee * magic * magic;
  53.   sqrtMagic = sqrt(magic);
  54.   dLat = (dLat * 180.0) / ((a * (1 - ee)) / (magic * sqrtMagic) * pi);
  55.   dLon = (dLon * 180.0) / (a / sqrtMagic * cos(radLat) * pi);
  56.   *GCJ02_Lat = WGS84_Lat + dLat;    //GCJ02_Lat是百度纬度存储变量的地址  *GCJ02_Lat就是那个值
  57.   *GCJ02_Lon = WGS84_Lon + dLon;    //GCJ02_Lon是百度经度存储变量的地址  *GCJ02_Lon
  58. }



  59. /*****************************************
  60. * 火星坐标系 (GCJ-02) 与百度坐标系 (BD-09) 的转换算法 将 GCJ-02 坐标转换成 BD-09 坐标
  61. *
  62. * @param gg_lat
  63. * @param gg_lon
  64. *****************************************/
  65. //传入的参数    GCJ02_To_BD09(*BD09_Lat,*BD09_Lon,BD09_Lat,BD09_Lon);
  66. //(*BD09_Lat,*BD09_Lon)火星坐标,(BD09_Lat,BD09_Lon)是变量的地址
  67. void GCJ02_To_BD09(double GCJ02_Lat,double GCJ02_Lon,double * BD_09_Lat,double * BD_09_Lon)
  68. {
  69.     double x = GCJ02_Lon, y = GCJ02_Lat;
  70.     double z= sqrt(x * x + y * y) + 0.00002 * sin(y * x_pi);
  71.     double theta =atan2(y, x) + 0.000003 * cos(x * x_pi);
  72.     *BD_09_Lon = z * cos(theta) + 0.0065;
  73.     *BD_09_Lat = z * sin(theta) + 0.006;
  74. }


  75. /*************************************************************
  76. 函数名称:GPS_transformation(double WGS84_Lat, double WGS84_Lon,double * BD_09_Lat, double * BD_09_Lon)
  77. 函数功能:GPS坐标转百度地图坐标
  78. 输入参数:WGS84_Lat,WGS84_Lon GPS获取到真实经纬度  储存得到的百度经纬度变量的地址 BD_09_Lat,BD_09_Lon指向那个变量
  79. 输出参数:
  80. *************************************************************/
  81. void GPS_transformation(double WGS84_Lat,double WGS84_Lon,double * BD_09_Lat,double * BD_09_Lon)
  82. {
  83.    GPS84_To_GCJ02(WGS84_Lat,WGS84_Lon,BD_09_Lat,BD_09_Lon);           //GPS坐标转火星坐标
  84.    GCJ02_To_BD09(*BD_09_Lat,*BD_09_Lon,BD_09_Lat,BD_09_Lon);           //火星坐标转百度坐标
  85. }



  86. /*************************************************************
  87. 函数名称:double GetDistance(double lat1, double lng1, double lat2, double lng2)
  88. 函数功能:返回两个点之间的距离
  89. 输入参数:两个点的经纬度(角度)
  90. 输出参数:距离(单位:km)
  91. *************************************************************/
  92. double Cal_Distance(double lat1, double lng1, double lat2, double lng2)
  93. {
  94.     double EARTH_RADIUS = 6378.137;        //地球近似半径
  95.     double radLat1 = radian(lat1);
  96.     double radLat2 = radian(lat2);
  97.     double a = radLat1 - radLat2;
  98.     double b = radian(lng1) - radian(lng2);
  99.      
  100.     double dst = 2 * asin((sqrt(pow(sin(a / 2), 2) + cos(radLat1) * cos(radLat2) * pow(sin(b / 2), 2) )));    //asin()反正弦值函数
  101.      
  102.     dst = dst * EARTH_RADIUS;
  103.     dst= (uint32_t)(dst * 10000.0) / 10000.0;//舍弃小数点后4位的数
  104.     return dst;
  105. }

  106. static void smartDelay(unsigned long ms)
  107. {
  108.   unsigned long start = millis();
  109.   do
  110.   {
  111.     while (ss.available())
  112.       gps.encode(ss.read());
  113.   } while (millis() - start < ms);
  114. }


  115. void setup() {
  116.   M5.begin();
  117.   ss.begin(GPSBaud);

  118. }

  119. void loop() {
  120.   M5.Lcd.setCursor(0, 0, 2);
  121.   M5.Lcd.printf("%16.12f\n", gps.location.lat());
  122.   M5.Lcd.printf("%16.12f\n", gps.location.lng());
  123.   GPS_transformation(gps.location.lat(),gps.location.lng(), &Lat, &Lon);
  124.   M5.Lcd.printf("%16.12f\n",Lat);
  125.   M5.Lcd.printf("%16.12f\n",Lon);
  126.   smartDelay(2000);
  127.   //M5.Lcd.clear();

  128. }
复制代码
如何测试计算的准不准呢,我是在百度开发者控制中心找到位置服务的接口测试进行逆向地理编码来查看解析的位置是否正确,这样可以保证我在百度系内调用任何地理数据都准确无误。
235406stc5q521nu1828e2.jpg

该用户从未签到

发表于 2020-7-19 07:59 | 显示全部楼层
厉害,高手呀!
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

arduino程序设计基础 blinker物联网解决方案

热门推荐

【教程】pico+hx711电子秤
【教程】pico+hx711电子秤
pico+hx711电子秤 【前言】 我做过多款电子秤,这次移植到pico上
ESP8266+Onenet平台远程数据传输和控制
ESP8266+Onenet平台远程数
这是我的第一个diy,主要功能实现了onenet云平台温湿度数据的传输和远程控制LED灯平台
【Arduino】108种传感器模块系列实验(48)---三轴ADXL345模块
【Arduino】108种传感器模
37款传感器与模块的提法,在网络上广泛流传,其实Arduino能够兼容的传感器模块肯定是
ps2遥控小车——uno实现
ps2遥控小车——uno实现
前几天在阁楼发现了好久以前3d打印,激光切割的底盘,于是决定做这个东西 正好手上又
震惊!OLED菜单竟只用10行代码就可以完成到完美!!!
震惊!OLED菜单竟只用10行
震惊!OLED菜单竟只用10行代码就可
Copyright   ©2015-2016  Arduino中文社区  Powered by©Discuz!   
快速回复 返回顶部 返回列表