电子地图坐标系统研究整理

来源:互联网 发布:网络分线再接路由器 编辑:程序博客网 时间:2024/06/10 00:14

一、电子地图坐标系统简介

WGS-84坐标系:即地球坐标系,国际经纬度坐标标准
GCJ-02坐标系:即火星坐标系,WGS84坐标系经加密后的坐标系,国测局制定。
BD-09坐标系:即百度坐标系,GCJ02坐标系经加密后的坐标系。

GCJ-02坐标系统,就是在标准的WGS-84坐标系统上进行了人为的偏移,比如Google地图、腾讯SOSO地图等就是直接使用了国家GCJ-02坐标系统,我们有一个不成文的说法,前者叫地球坐标,后者叫火星坐标,并且,火星坐标是无法转换成地球坐标的(网上虽然有一定的方法,但基本上都是基于偏移数据库,精度较高的数据库需要购买,当然这都是一种破解手段)。

所有的电子地图、导航设备,都需要加入国家保密插件。第一步,地图公司测绘地图,测绘完成后,送到国家测绘局,将真实坐标的电子地图,加密成“火星坐标”,这样的地图才是可以出版和发布的,然后才可以让GPS公司处理。第二步,所有的GPS公司,只要需要汽车导航的,需要用到导航电子地图的,都需要在软件中加入国家保密算法,将COM口读出来的真实的坐标信号,加密转换成国家要求的保密的坐标。这样,GPS导航仪和导航电子地图就可以完全匹配,GPS也就可以正常工作了。

API 坐标系 百度地图API 百度坐标 腾讯搜搜地图API 火星坐标 搜狐搜狗地图API 搜狗坐标* 阿里云地图API 火星坐标 图吧MapBar地图API 图吧坐标 高德MapABC地图API 火星坐标 灵图51ditu地图API 火星坐标

注1:百度地图使用百度坐标,支持从地球坐标和火星坐标导入成百度坐标,但无法导出。并且批量坐标转换一次只能转换20个(待验证)。
注2:搜狗地图支持直接显示地球坐标,支持地球坐标、火星坐标、百度坐标导入成搜狗坐标,同样,搜狗坐标也无法导出。

说完坐标系统,我们自然能够知道这里的问题,通过以下问题,来说说我对此的研究。

二、各个坐标系的相互转换

1.火星坐标系 (GCJ-02) 与百度坐标系 (BD-09) 的转换算法

其中 bd_encrypt 将 GCJ-02 坐标转换成 BD-09 坐标, bd_decrypt 反之。

void bd_encrypt(double gg_lat, double gg_lon, double &bd_lat, double &bd_lon)  {      double x = gg_lon, y = gg_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_lon = z * cos(theta) + 0.0065;      bd_lat = z * sin(theta) + 0.006;  }  void bd_decrypt(double bd_lat, double bd_lon, double &gg_lat, double &gg_lon)  {      double x = bd_lon - 0.0065, y = bd_lat - 0.006;      double z = sqrt(x * x + y * y) - 0.00002 * sin(y * x_pi);      double theta = atan2(y, x) - 0.000003 * cos(x * x_pi);      gg_lon = z * cos(theta);      gg_lat = z * sin(theta);  }  

2.地球坐标系 (WGS-84) 到火星坐标系 (GCJ-02) 的转换算法

WGS-84 到 GCJ-02 的转换(即 GPS 加偏)算法

using System;   namespace Navi  {      class EvilTransform      {          const double pi = 3.14159265358979324;          //           // Krasovsky 1940           //           // a = 6378245.0, 1/f = 298.3           // b = a * (1 - f)           // ee = (a^2 - b^2) / a^2;           const double a = 6378245.0;          const double ee = 0.00669342162296594323;          //           // World Geodetic System ==> Mars Geodetic System           public static void transform(double wgLat, double wgLon, out double mgLat, out double mgLon)          {              if (outOfChina(wgLat, wgLon))              {                  mgLat = wgLat;                  mgLon = wgLon;                  return;              }              double dLat = transformLat(wgLon - 105.0, wgLat - 35.0);              double dLon = transformLon(wgLon - 105.0, wgLat - 35.0);              double radLat = wgLat / 180.0 * pi;              double magic = Math.Sin(radLat);              magic = 1 - ee * magic * magic;              double sqrtMagic = Math.Sqrt(magic);              dLat = (dLat * 180.0) / ((a * (1 - ee)) / (magic * sqrtMagic) * pi);              dLon = (dLon * 180.0) / (a / sqrtMagic * Math.Cos(radLat) * pi);              mgLat = wgLat + dLat;              mgLon = wgLon + dLon;          }          static bool outOfChina(double lat, double lon)          {              if (lon < 72.004 || lon > 137.8347)                  return true;              if (lat < 0.8293 || lat > 55.8271)                  return true;              return false;          }          static double transformLat(double x, double y)          {              double ret = -100.0 + 2.0 * x + 3.0 * y + 0.2 * y * y + 0.1 * x * y + 0.2 * Math.Sqrt(Math.Abs(x));              ret += (20.0 * Math.Sin(6.0 * x * pi) + 20.0 * Math.Sin(2.0 * x * pi)) * 2.0 / 3.0;              ret += (20.0 * Math.Sin(y * pi) + 40.0 * Math.Sin(y / 3.0 * pi)) * 2.0 / 3.0;              ret += (160.0 * Math.Sin(y / 12.0 * pi) + 320 * Math.Sin(y * pi / 30.0)) * 2.0 / 3.0;              return ret;          }          static double transformLon(double x, double y)          {              double ret = 300.0 + x + 2.0 * y + 0.1 * x * x + 0.1 * x * y + 0.1 * Math.Sqrt(Math.Abs(x));              ret += (20.0 * Math.Sin(6.0 * x * pi) + 20.0 * Math.Sin(2.0 * x * pi)) * 2.0 / 3.0;              ret += (20.0 * Math.Sin(x * pi) + 40.0 * Math.Sin(x / 3.0 * pi)) * 2.0 / 3.0;              ret += (150.0 * Math.Sin(x / 12.0 * pi) + 300.0 * Math.Sin(x / 30.0 * pi)) * 2.0 / 3.0;              return ret;          }      }  }  

以上参考自:http://www.xue5.com/Mobile/iOS/679842.html

3.百度在线转换API

http://api.map.baidu.com/ag/coord/convert?from=0&to=4&x=longitude&y=latitude  from: 来源坐标系   (0 表示 WGS-84 坐标;2 表示GCJ-02 坐标)  to: 转换后的坐标  (4 表示 BD-09 坐标,即百度地图使用的行)  x: 经度  y: 纬度  

请求之后会返回一串Json

{      "error":0,      "x":"MTIxLjUwMDIyODIxNDk2",      "y":"MzEuMjM1ODUwMjYwMTE3"  }  error:是结果是否出错标志位,0 表示成功x: 坐标系 2 时为经度,4 时为纬度(Base64编码)y: 坐标系 4 时为经度,2 时为纬度(Base64编码)

什么情况,经纬度居然还加密?那接下来也只好见招拆招了

import java.io.BufferedReader;  import java.io.IOException;  import java.io.InputStream;  import java.io.InputStreamReader;  import java.io.OutputStreamWriter;  import java.net.URL;  import java.net.URLConnection;  import com.sun.org.apache.xerces.internal.impl.dv.util.Base64;  public class BaiduAPIConverter extends Thread {    public static void testPost(String x, String y) throws IOException {      try {        URL url = new URL("http://api.map.baidu.com/ag/coord/convert?from=2&to=4&x="+ x + "&y=" + y);        URLConnection connection = url.openConnection();        connection.setDoOutput(true);        OutputStreamWriter out = new OutputStreamWriter(connection.getOutputStream(), "utf-8");        // remember to clean up         out.flush();        out.close();        // 一旦发送成功,用以下方法就可以得到服务器的回应:         String sCurrentLine, sTotalString;        sCurrentLine = sTotalString = "";        InputStream l_urlStream;        l_urlStream = connection.getInputStream();        BufferedReader l_reader = new BufferedReader(new InputStreamReader(l_urlStream));        while ((sCurrentLine = l_reader.readLine()) != null) {          if (!sCurrentLine.equals(""))            sTotalString += sCurrentLine;        }        sTotalString = sTotalString.substring(1, sTotalString.length() - 1);        String[] results = sTotalString.split("\\,");        if (results.length == 3) {          if (results[0].split("\\:")[1].equals("0")) {            String mapX = results[1].split("\\:")[1];            String mapY = results[2].split("\\:")[1];            mapX = mapX.substring(1, mapX.length() - 1);            mapY = mapY.substring(1, mapY.length() - 1);            mapX = new String(Base64.decode(mapX));            mapY = new String(Base64.decode(mapY));            System.out.println("\t" + mapX + "\t" + mapY);          }        }       sleep(10000);      } catch (InterruptedException e) {        // TODO Auto-generated catch block         e.printStackTrace();      }    }    /**    * @param args    * @throws IOException    */    public static void main(String[] args) throws IOException {      testPost("120.151379", "30.184678");      System.out.println("ok");    }  }  

到这里也差不多好了,主要的代码都写出来了,其他的您就自己写吧。
以上参考自:http://scalpel.me/archives/136

四、百度内置转换方法,可以不局限于百度定位SDK

在百度地图中取得WGS-84坐标,调用如下方法:

BMapManager.getLocationManager().setLocationCoordinateType(MKLocationManager.MK_COORDINATE_WGS84);

这样从百度api中取得的坐标就是WGS-84了,可是这种坐标如果显示到百度地图上就会偏移,也就是说取出一个坐标,原封不动的显示上去就偏移了,所以为了显示也是正常就需要在绘制到百度地图上之前转换成BD-09。
转换成BD-09,调用方法:

GeoPoint wgs84;GeoPoint bd09= CoordinateConvert.bundleDecode(CoordinateConvert.fromWgs84ToBaidu(wgs84));

这里实在不明白为何要设计成CoordinateConvert.fromWgs84ToBaidu(wgs84)返回了一个Bundle,所以还需要CoordinateConvert.bundleDecode()再转成GeoPoint。

参考文章:
国内各地图API坐标系统比较与转换
关于百度地图坐标转换接口的研究
构建自己的百度地图坐标纠偏数据库
GPS纠偏算法,适用于google,高德体系的地图

0 0
原创粉丝点击