原理解析吧,参照网上的一个回答http://q.cnblogs.com/q/41339/
众所周知地球是一个不规则椭圆体,GIS中的坐标系定义由基准面和地图投影两组参数确定,而基准面的定义则由特定椭球体及其对应的转换参数确定。 基准面是利用特定椭球体对特定地区地球表面的逼近,因此每个国家或地区均有各自的基准面。基准面是在椭球体基础上建立的,椭球体可以对应多个基准面,而基准面只能对应一个椭球体。
意思就是无论是谷歌地图、搜搜地图还是高德地图、百度地图区别只是针对不同的大地地理坐标系标准制作的经纬度,不存在准不准的问题,大家都是准的只是参照物或者说是标准不一样。
谷歌地图采用的是WGS84地理坐标系(中国范围除外),谷歌中国地图和搜搜中国地图采用的是GCJ02地理坐标系,百度采用的是BD09坐标系,而设备一般包含GPS芯片或者北斗芯片获取的经纬度为WGS84地理坐标系,为什么不统一用WGS84地理坐标系这就是国家地理测绘总局对于出版地图的要求,出版地图必须符合GCJ02坐标系标准了,也就是国家规定不能直接使用WGS84地理坐标系。所以定位大家感觉不准确很多又叫出版地图为火星地图其实只是坐标系不一样而已。
这就是为什么设备采集的经纬度在地图上显示的时候经常有很大的偏差,远远超出民用GPS 10米偏移量的技术规范,于是我们就有了谷歌地图纠偏 腾讯搜搜纠偏 混合地图纠偏 百度谷歌互转存在的价值。
那如何对谷歌地图纠偏、搜搜soso地图纠偏或者对百度地图纠偏呢,如果用算法目前没有太好的算法直接转换,所以大家采用的都是比对的方法吧地球划分成若干个小块找到地图的偏差量记录下来,然后根据任意经纬度找寻最接近的偏差量加上偏差量就可以实现不同地图之间的经纬度转换。现在有0.01度纠偏经纬度信息,可以提供任意格式,可以直接把经纬度偏移量调整回来。
百度地图纠偏信息包含中国海域一共29,699,997条纠偏数据,谷歌地图只包含中国陆地一共12,597,551条纠偏数据。
下面又是我在网上找到别人写的两个纠偏的算法。
第一个:
package correctPosition;
public class MapPoint
{
private double latitude;
private double longitude;
private double x;
private double y;
public double getLatitude()
{
return latitude;
}
public void setLatitude(double latitude)
{
this.latitude = latitude;
}
public double getLongitude()
{
return longitude;
}
public void setLongitude(double longitude)
{
this.longitude = longitude;
}
public double getX()
{
return x;
}
public void setX(double x)
{
this.x = x;
}
public double getY()
{
return y;
}
public void setY(double y)
{
this.y = y;
}
}
package correctPosition;
/**
* 经纬度纠偏工具类
* [一句话功能简述]<p>
* [功能详细描述]<p>
* @author PeiYu
* @version 1.0, 2012-8-24
* @see
* @since gframe-v100
*/
public class MapFix
{
private double casm_f = 0.0;
private double casm_rr = 0.0;
private double casm_t1 = 0.0;
private double casm_t2 = 0.0;
private double casm_x1 = 0.0;
private double casm_x2 = 0.0;
private double casm_y1 = 0.0;
private double casm_y2 = 0.0;
private MapFix()
{
casm_rr = 0.0;
casm_t1 = 0.0;
casm_t2 = 0.0;
casm_x1 = 0.0;
casm_y1 = 0.0;
casm_x2 = 0.0;
casm_y2 = 0.0;
casm_f = 0.0;
}
private static MapFix instance;
public static MapFix getInstance()
{
if (instance == null)
{
instance = new MapFix();
}
return instance;
}
/**
* 纠偏
* @param x 经度
* @param y 纬度
* @return [0]纠偏后经度 [1]纠偏后纬度
*/
public double[] fix(double x , double y)
{
double[] res = new double[2];
try
{
double num = x * 3686400.0;
double num2 = y * 3686400.0;
double num3 = 0.0;
double num4 = 0.0;
double num5 = 0.0;
MapPoint point = wgtochina_lb(1, (int) num, (int) num2, (int) num5, (int) num3, (int) num4);
double num6 = point.getX();
double num7 = point.getY();
num6 /= 3686400.0;
num7 /= 3686400.0;
res[0] = num6;
res[1] = num7;
}
catch (Exception ex)
{
System.out.println(ex);
}
return res;
}
private void IniCasm(double w_time , double w_lng , double w_lat)
{
casm_t1 = w_time;
casm_t2 = w_time;
double num = (int) (w_time / 0.357);
casm_rr = w_time - (num * 0.357);
if (w_time == 0.0)
{
casm_rr = 0.3;
}
casm_x1 = w_lng;
casm_y1 = w_lat;
casm_x2 = w_lng;
casm_y2 = w_lat;
casm_f = 3.0;
}
private double random_yj()
{
double num = 314159269.0;
double num2 = 453806245.0;
casm_rr = (num * casm_rr) + num2;
double num3 = (int) (casm_rr / 2.0);
casm_rr -= num3 * 2.0;
casm_rr /= 2.0;
return casm_rr;
}
private double Transform_jy5(double x , double xx)
{
double num = 6378245.0;
double num2 = 0.00669342;
double num3 = Math.sqrt(1.0 - ((num2 * yj_sin2(x * 0.0174532925199433)) * yj_sin2(x * 0.0174532925199433)));
return ((xx * 180.0) / (((num / num3) * Math.cos(x * 0.0174532925199433)) * 3.1415926));
}
private double Transform_jyj5(double x , double yy)
{
double num = 6378245.0;
double num2 = 0.00669342;
double d = 1.0 - ((num2 * yj_sin2(x * 0.0174532925199433)) * yj_sin2(x * 0.0174532925199433));
double num4 = (num * (1.0 - num2)) / (d * Math.sqrt(d));
return ((yy * 180.0) / (num4 * 3.1415926));
}
private double Transform_yj5(double x , double y)
{
double num = ((((300.0 + (1.0 * x)) + (2.0 * y)) + ((0.1 * x) * x)) + ((0.1 * x) * y))
+ (0.1 * Math.sqrt(Math.sqrt(x * x)));
num += ((20.0 * yj_sin2(18.849555921538762 * x)) + (20.0 * yj_sin2(6.283185307179588 * x))) * 0.6667;
num += ((20.0 * yj_sin2(3.141592653589794 * x)) + (40.0 * yj_sin2(1.0471975511965981 * x))) * 0.6667;
return (num + (((150.0 * yj_sin2(0.26179938779914952 * x)) + (300.0 * yj_sin2(0.10471975511965979 * x))) * 0.6667));
}
private double Transform_yjy5(double x , double y)
{
double num = ((((-100.0 + (2.0 * x)) + (3.0 * y)) + ((0.2 * y) * y)) + ((0.1 * x) * y))
+ (0.2 * Math.sqrt(Math.sqrt(x * x)));
num += ((20.0 * yj_sin2(18.849555921538762 * x)) + (20.0 * yj_sin2(6.283185307179588 * x))) * 0.6667;
num += ((20.0 * yj_sin2(3.141592653589794 * y)) + (40.0 * yj_sin2(1.0471975511965981 * y))) * 0.6667;
return (num + (((160.0 * yj_sin2(0.26179938779914952 * y)) + (320.0 * yj_sin2(0.10471975511965979 * y))) * 0.6667));
}
private MapPoint wgtochina_lb(int wg_flag , int wg_lng , int wg_lat , int wg_heit , int wg_week , int wg_time)
{
MapPoint point = null;
if (wg_heit <= 0x1388)
{
double num = wg_lng;
num /= 3686400.0;
double x = wg_lat;
x /= 3686400.0;
if (num < 72.004)
{
return point;
}
if (num > 137.8347)
{
return point;
}
if (x < 0.8293)
{
return point;
}
if (x > 55.8271)
{
return point;
}
if (wg_flag == 0)
{
IniCasm((double) wg_time, (double) wg_lng, (double) wg_lat);
point = new MapPoint();
point.setLatitude((double) wg_lng);
point.setLongitude((double) wg_lat);
return point;
}
casm_t2 = wg_time;
double num3 = (casm_t2 - casm_t1) / 1000.0;
if (num3 <= 0.0)
{
casm_t1 = casm_t2;
casm_f++;
casm_x1 = casm_x2;
casm_f++;
casm_y1 = casm_y2;
casm_f++;
}
else if (num3 > 120.0)
{
if (casm_f == 3.0)
{
casm_f = 0.0;
casm_x2 = wg_lng;
casm_y2 = wg_lat;
double num4 = casm_x2 - casm_x1;
double num5 = casm_y2 - casm_y1;
double num6 = Math.sqrt((num4 * num4) + (num5 * num5)) / num3;
if (num6 > 3185.0)
{
return point;
}
}
casm_t1 = casm_t2;
casm_f++;
casm_x1 = casm_x2;
casm_f++;
casm_y1 = casm_y2;
casm_f++;
}
double xx = Transform_yj5(num - 105.0, x - 35.0);
double yy = Transform_yjy5(num - 105.0, x - 35.0);
double num9 = wg_heit;
xx = ((xx + (num9 * 0.001)) + yj_sin2(wg_time * 0.0174532925199433)) + random_yj();
yy = ((yy + (num9 * 0.001)) + yj_sin2(wg_time * 0.0174532925199433)) + random_yj();
point = new MapPoint();
point.setX((num + Transform_jy5(x, xx)) * 3686400.0);
point.setY((x + Transform_jyj5(x, yy)) * 3686400.0);
}
return point;
}
private double yj_sin2(double x)
{
double num = 0.0;
if (x < 0.0)
{
x = -x;
num = 1.0;
}
int num2 = (int) (x / 6.28318530717959);
double num3 = x - (num2 * 6.28318530717959);
if (num3 > 3.1415926535897931)
{
num3 -= 3.1415926535897931;
if (num == 1.0)
{
num = 0.0;
}
else if (num == 0.0)
{
num = 1.0;
}
}
x = num3;
double num4 = x;
double num5 = x;
num3 *= num3;
num5 *= num3;
num4 -= num5 * 0.166666666666667;
num5 *= num3;
num4 += num5 * 0.00833333333333333;
num5 *= num3;
num4 -= num5 * 0.000198412698412698;
num5 *= num3;
num4 += num5 * 2.75573192239859E-06;
num5 *= num3;
num4 -= num5 * 2.50521083854417E-08;
if (num == 1.0)
{
num4 = -num4;
}
return num4;
}
}
package correctPosition;
public class Test
{
/**
* @param args
*/
public static void main(String[] args)
{
// 纠偏前的经度
//double lon = 103.9804764;
// 纠偏前的纬度
// double lat = 30.605864;
double lon = 103.98707398732;
double lat = 30.611553862277;
double point[] = MapFix.getInstance().fix(lon, lat);
// 纠偏后的经度
double correctLon = point[0];
// 纠偏后的纬度
double correctLat = point[1];
System.out.println("纠偏前经度:" + lon + ",纬度:" + lat);
System.out.println("纠偏后经度:" + correctLon + ",纬度:" + correctLat);
}
}
第二个:
package cn.bdx.util;
import java.util.HashMap;
import java.util.Map;
/**
* gps纠偏算法,适用于google,高德体系的地图
*
* @author Administrator
*/
public class GpsCorrect {
final static double pi = 3.14159265358979324;
final static double a = 6378245.0;
final static double ee = 0.00669342162296594323;
public static void main(String[] args) {
System.out.println(transform(103.98707398732,30.611553862277));
}
public static Map<String,Double> transform(double wgLat, double wgLon) {
// if (outOfChina(wgLat, wgLon)) {
// latlng[0] = wgLat;
// latlng[1] = wgLon;
// return null;
// }
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);
// lat = wgLat + dLat;
// lng = wgLon + dLon;
Map<String,Double> lnglatList = new HashMap<String,Double>();
lnglatList.put("lng", wgLon+dLon);
lnglatList.put("lat", wgLat + dLat);
//LatLng CHENGDU = new LatLng(wgLat + dLat, wgLon + dLon);
return lnglatList;
}
/*
private static boolean 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;
}
*/
private 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;
}
private 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;
}
}
这两种算法在高德地图与百度地图上面都进行了测试,测试结果第一种算法的定位精度要比第二种算法要精确一点。