|
使用GPS模块可以获得真实地理坐标,但是,往往我们将得到的数据放到一些地图服务商提供的地图上查看会发现偏移很大。其实,很多人忽略了一点,国家为了电子地图安全,强制要求地图服务商对地图坐标进行加密,产生随机偏移,因此我们看到的地图上标注的地理位置并不是自己的真实地理位置。GCJ-02加密标准是基本的数据加密算法,百度地图在GCJ-02的基础上又加入了自己的一套加密算法。以下将获得的GPS数据转换为GCJ-02地理坐标或百度地图坐标,通过逆向地理编码你就能查到具体的位置信息。
- #include <M5Stack.h>
- #include <TinyGPS++.h>
- #include <math.h>
- static const uint32_t GPSBaud = 9600;
- TinyGPSPlus gps;
- HardwareSerial ss(2);
- double pi = 3.14159265358979324; //圆周率
- double ee = 0.00669342162296594323; //椭球的偏心率
- double a = 6378245.0; //卫星椭球坐标投影到平面地图坐标系的投影因子
- double x_pi = 3.14159265358979324 * 3000.0 / 180.0; //圆周率转换量
- double Lat;
- double Lon;
- // 求弧度
- double radian(double d)
- {
- return d * pi / 180.0; //角度1? = π / 180
- }
- double transformLat(double lat, double lon) //纬度转化
- {
- double ret = -100.0 + 2.0 * lat + 3.0 * lon + 0.2 * lon * lon + 0.1 * lat * lon + 0.2 * sqrt(abs(lat));
- ret += (20.0 * sin(6.0 * lat * pi) + 20.0 * sin(2.0 * lat * pi)) * 2.0 / 3.0;
- ret += (20.0 * sin(lon * pi) + 40.0 * sin(lon / 3.0 * pi)) * 2.0 / 3.0;
- ret += (160.0 * sin(lon / 12.0 * pi) + 320 * sin(lon * pi / 30.0)) * 2.0 / 3.0;
- return ret;
- }
- double transformLon(double lat,double lon) //经度转化
- {
- double ret = 300.0 + lat + 2.0 * lon + 0.1 * lat * lat + 0.1 * lat * lon + 0.1 * sqrt(abs(lat));
- ret += (20.0 * sin(6.0 * lat * pi) + 20.0 * sin(2.0 * lat * pi)) * 2.0 / 3.0;
- ret += (20.0 * sin(lat * pi) + 40.0 * sin(lat / 3.0 * pi)) * 2.0 / 3.0;
- ret += (150.0 * sin(lat / 12.0 * pi) + 300.0 * sin(lat / 30.0 * pi)) * 2.0 / 3.0;
- return ret;
- }
- /*****************************************************************************
- * WGS84(GPS坐标系) to 火星坐标系(GCJ-02)
- *
- * @param lat
- * @param lon
- * @return
- ****************************************************************************/
- void GPS84_To_GCJ02(double WGS84_Lat, double WGS84_Lon,double * GCJ02_Lat, double * GCJ02_Lon)
- {
- double dLat;
- double dLon;
- double radLat;
- double magic;
- double sqrtMagic;
-
- dLat = transformLat(WGS84_Lon - 105.0, WGS84_Lat - 35.0);
- dLon = transformLon(WGS84_Lon - 105.0, WGS84_Lat - 35.0);
- radLat = WGS84_Lat / 180.0 * pi;
- magic = sin(radLat);
- magic = 1 - ee * magic * magic;
- sqrtMagic = sqrt(magic);
- dLat = (dLat * 180.0) / ((a * (1 - ee)) / (magic * sqrtMagic) * pi);
- dLon = (dLon * 180.0) / (a / sqrtMagic * cos(radLat) * pi);
- *GCJ02_Lat = WGS84_Lat + dLat; //GCJ02_Lat是百度纬度存储变量的地址 *GCJ02_Lat就是那个值
- *GCJ02_Lon = WGS84_Lon + dLon; //GCJ02_Lon是百度经度存储变量的地址 *GCJ02_Lon
- }
- /*****************************************
- * 火星坐标系 (GCJ-02) 与百度坐标系 (BD-09) 的转换算法 将 GCJ-02 坐标转换成 BD-09 坐标
- *
- * @param gg_lat
- * @param gg_lon
- *****************************************/
- //传入的参数 GCJ02_To_BD09(*BD09_Lat,*BD09_Lon,BD09_Lat,BD09_Lon);
- //(*BD09_Lat,*BD09_Lon)火星坐标,(BD09_Lat,BD09_Lon)是变量的地址
- void GCJ02_To_BD09(double GCJ02_Lat,double GCJ02_Lon,double * BD_09_Lat,double * BD_09_Lon)
- {
- double x = GCJ02_Lon, y = GCJ02_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);
- *BD_09_Lon = z * cos(theta) + 0.0065;
- *BD_09_Lat = z * sin(theta) + 0.006;
- }
- /*************************************************************
- 函数名称:GPS_transformation(double WGS84_Lat, double WGS84_Lon,double * BD_09_Lat, double * BD_09_Lon)
- 函数功能:GPS坐标转百度地图坐标
- 输入参数:WGS84_Lat,WGS84_Lon GPS获取到真实经纬度 储存得到的百度经纬度变量的地址 BD_09_Lat,BD_09_Lon指向那个变量
- 输出参数:
- *************************************************************/
- void GPS_transformation(double WGS84_Lat,double WGS84_Lon,double * BD_09_Lat,double * BD_09_Lon)
- {
- GPS84_To_GCJ02(WGS84_Lat,WGS84_Lon,BD_09_Lat,BD_09_Lon); //GPS坐标转火星坐标
- GCJ02_To_BD09(*BD_09_Lat,*BD_09_Lon,BD_09_Lat,BD_09_Lon); //火星坐标转百度坐标
- }
- /*************************************************************
- 函数名称:double GetDistance(double lat1, double lng1, double lat2, double lng2)
- 函数功能:返回两个点之间的距离
- 输入参数:两个点的经纬度(角度)
- 输出参数:距离(单位:km)
- *************************************************************/
- double Cal_Distance(double lat1, double lng1, double lat2, double lng2)
- {
- double EARTH_RADIUS = 6378.137; //地球近似半径
- double radLat1 = radian(lat1);
- double radLat2 = radian(lat2);
- double a = radLat1 - radLat2;
- double b = radian(lng1) - radian(lng2);
-
- double dst = 2 * asin((sqrt(pow(sin(a / 2), 2) + cos(radLat1) * cos(radLat2) * pow(sin(b / 2), 2) ))); //asin()反正弦值函数
-
- dst = dst * EARTH_RADIUS;
- dst= (uint32_t)(dst * 10000.0) / 10000.0;//舍弃小数点后4位的数
- return dst;
- }
- static void smartDelay(unsigned long ms)
- {
- unsigned long start = millis();
- do
- {
- while (ss.available())
- gps.encode(ss.read());
- } while (millis() - start < ms);
- }
- void setup() {
- M5.begin();
- ss.begin(GPSBaud);
- }
- void loop() {
- M5.Lcd.setCursor(0, 0, 2);
- M5.Lcd.printf("%16.12f\n", gps.location.lat());
- M5.Lcd.printf("%16.12f\n", gps.location.lng());
- GPS_transformation(gps.location.lat(),gps.location.lng(), &Lat, &Lon);
- M5.Lcd.printf("%16.12f\n",Lat);
- M5.Lcd.printf("%16.12f\n",Lon);
- smartDelay(2000);
- //M5.Lcd.clear();
-
- }
复制代码 如何测试计算的准不准呢,我是在百度开发者控制中心找到位置服务的接口测试进行逆向地理编码来查看解析的位置是否正确,这样可以保证我在百度系内调用任何地理数据都准确无误。
|
|