电子地图坐标系统研究整理
2015-12-28 14:33
337 查看
一、电子地图坐标系统简介
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 | 火星坐标 |
注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,高德体系的地图
相关文章推荐
- AsyncTask
- bzoj3139: [Hnoi2013]比赛
- 电力系统相关
- Android屏幕适配
- SpringMVC Controller 返回值的可选类型
- CentOS 6.3安装MySQL 5.7.10(rpm方式)
- Monkey 使用笔记(1)
- apache工程地址总结
- C++实现的农历算法
- Problem E: 判断一个正整数是否为偶数。
- 强引用,软引用,弱引用
- j2se应用启动初始屏居中代码
- 使用quick-cocos2dx制作拼图游戏
- ecshop后台,listtable.js使用
- HTTP常见错误代码
- UVA 10340 )(暴力)
- 学习密码
- 怎样使用TabPageIndicator 怎样依赖第三方框架
- 《你的生命有什么可能》---- 读书笔记
- embed标签