国内各地图API坐标系统⽐较与转换
备注:资料均来源与⽹上,这⾥稍加整理,有错欢迎指出
⼀、各个坐标系的概况
众所周知地球是⼀个不规则椭圆体,GIS中的坐标系定义由基准⾯和地图投影两组参数确定,⽽基准⾯的定义则由特定椭球体及其对应的转换参数确定。 基准⾯是利⽤特定椭球体对特定地区地球表⾯的逼近,因此每个国家或地区均有各⾃的基准⾯。基准⾯是在椭球体基础上建⽴的,椭球体可以对应多个基准⾯,⽽基准⾯只能对应⼀个椭球体。意思就是⽆论是⾕歌地图、搜搜地图还是⾼德地图、百度地图区别只是针对不同的⼤地地理坐标系标准制作的经纬度,不存在准不准的问题,⼤家都是准的只是参照物或者说是标准不⼀样。⾕歌地图采⽤的是WGS84地理坐标系(中国范围除外),⾕歌中国地图和搜搜中国地图采⽤的是GCJ02地理坐标系,百度采⽤的是BD09坐标系,⽽设备⼀般包含GPS芯⽚或者北⽃芯⽚获取的经纬度为WGS84地理坐标系,为什么不统⼀⽤WGS84地理坐标系这就是国家地理测绘总局对于出版地图的要求,出版地图必须符合GCJ02坐标系标准了,也就是国家规定不能直接使⽤WGS84地理坐标系。所以定位⼤家感觉不准确很多⼜叫出版地图为⽕星地图其实只是坐标系不⼀样⽽已。这就是为什么设备采集的经纬度在地图上显⽰的时候经常有很⼤的偏差,远远超出民⽤GPS 10⽶偏移量的技术规范。
以上参考⾃:haotsp
总结:
WGS84坐标系:即地球坐标系,国际上通⽤的坐标系。
GCJ02坐标系:即⽕星坐标系,WGS84坐标系经加密后的坐标系。
BD09坐标系:即百度坐标系,GCJ02坐标系经加密后的坐标系。
搜狗坐标系、图吧坐标系等,估计也是在GCJ02基础上加密⽽成的。
⼆、各个地图API采⽤的坐标系
API坐标系
百度地图API百度坐标
腾讯搜搜地图API⽕星坐标
搜狐搜狗地图API搜狗坐标*
阿⾥云地图API⽕星坐标
图吧MapBar地图API图吧坐标
⾼德MapABC地图API⽕星坐标
灵图51ditu地图API⽕星坐标
注1:百度地图使⽤百度坐标,⽀持从地球坐标和⽕星坐标导⼊成百度坐标,但⽆法导出。并且批量坐标转换⼀次只能转换20个(待验证)。注2:搜狗地图⽀持直接显⽰地球坐标,⽀持地球坐标、⽕星坐标、百度坐标导⼊成搜狗坐标,同样,搜狗坐标也⽆法导出。
个⼈认为:采⽤⾃家坐标体系,⽽不采⽤国内通⽤的⽕星坐标体系,实在是⾃寻短处。当然,百度是因为做的⾜够⼤、⾜够好,所以很霸道,也为以后⼀统天下⽽不让别⼈⽠分之⽽做准备吧。搜狗虽然⽤⾃家坐标体系,但能将地球坐标直接导⼊,此举也属唯⼀。⽽图吧地图不知道学什么加密⽅式,以前⽤地球坐标⽤的好好的,现在⽤图吧⾃⼰的坐标,难道是因为给百度做过所以也来了这么⼀招?或者沿⽤百度?不得⽽知。
本⽂的⽬的在于:做地图开发的时候,不希望被⼀家地图API迁就,所以采⽤⽕星坐标是正确的选择,希望本⽂能够对选择使⽤谁家API的开发者提供⼀点帮助吧。就我个⼈⽽⾔,我绝不会使⽤⾮⽕星坐标
系统的地图API,虽然百度地图API很好很强⼤确实很吸引我。
三、各个坐标系的相互转换
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;
}
}
}
以上参考⾃:www.xue5/Mobile/iOS/679842.html
3.百度在线转换API
api.map.baidu/ag/coord/convert?from=0&to=4&x=longitude&y=latitude from: 来源坐标系(0表⽰原始GPS坐标,2表⽰Google坐标)
to: 转换后的坐标 (4就是百度⾃⼰啦,好像这个必须是4才⾏)
x: 精度
y: 纬度
请求之后会返回⼀串Json
{
"error":0,
"x":"MTIxLjUwMDIyODIxNDk2",
"y":"MzEuMjM1ODUwMjYwMTE3"
}
error:是结果是否出错标志位,"0"表⽰OK
x: 百度坐标系的精度(Base64加密)
y: 百度坐标系的纬度(Base64加密)
什么情况,经纬度居然还加密?那接下来也只好见招拆招了
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.URL;
import java.URLConnection;
import s.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("api.map.baidu/ag/coord/convert?from=2&to=4&x="+ x + "&y=" + y); URLConnection connection = url.openConnection();
connection.setDoOutput(true);
OutputStreamWriter out = new OutputStream(), "utf-8");
// remember to clean up
out.flush();
out.close();
// ⼀旦发送成功,⽤以下⽅法就可以得到服务器的回应:
String sCurrentLine, sTotalString;
sCurrentLine = sTotalString = "";
InputStream l_urlStream;
l_urlStream = InputStream();
BufferedReader l_reader = new BufferedReader(new InputStreamReader(l_urlStream));
while ((sCurrentLine = adLine()) != 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);
transform和convert的区别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");
}
}
到这⾥也差不多好了,主要的代码都写出来了,其他的您就⾃⼰写吧。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论