java实例 - gps经纬度坐标转百度地图坐标

蔷薇部落 2014-01-20

天朝地图坐标和gps坐标不在一个次元中.

具体原因可以参见这篇文章:  gps纠偏及大陆地图偏移原因

地图纠偏的主要手段有以下几种:

(一)利用已有的api接口

(1)百度api: 

地址:   http://api.map.baidu.com/ag/coord/convert?x=121.583140&y=31.341174&from=0&to=2&mode=1

结果:[{"error":0,"x":"MTIxLjU4NzM2NDA5NTA1","y":"MzEuMzM5MDI3NTA2NTE="}]

说明:

请求参数中x为gps经度, y为gps纬度. from to是标识类型转换的方式.具体可以去查百度的api.

返回结果中error为0表示没有错误,返回的x和y是base64算法后的结果(可以自行Google加解密base64),解密后就是:121.58736409505和31.33902750651,这个就是百度坐标。

(2)其他人已经实现好了的api

如: http://map.yanue.net/gpsApi.php?lat=22.502412986242&lng=113.93832783228 等.大家看一下就明白,不具体描述了.

优点: 方便, 可靠, 免费

缺点: 受限于网络速度与api查询次数

(二)利用数据库纠偏

原理和实现方式,参见: gps纠偏数据库及gps纠偏算法PHP

有点: 可靠.适合于大型项目

缺点: 需要数据库支持.免费的纠偏数据库精度低,基本不更新.高精度的库需要额外付费,成本大.

(三)利用代码实现小范围地区的纠偏

原理和c的实现,参见:  一种根据纠偏数据对火星坐标进行完美拟合的方法

简单说, 在一个极有限的范围内, 我们可以将gps和百度坐标之间的变化视作是一种与参考点相关的线性的变化.

参见上面的博客, 我的java代码实现如下:

package test;

public class Tester {

	// 定义4个坐标参考点 gps (百度坐标值)
	// 福州东北参考点(福州市晋安区东山村)gps 26.105833333333333, 119.36166666666666
	// (26.1087320550,119.3731015851)
	// System.out.println(degress(26, 06, 21) + ", " + degress(119, 21, 42));
	// 福州西北参考点(绿洲寨公园)gps 26.105833333333333, 119.21166666666667
	// (26.1083582702,119.2230388300)
	// System.out.println(degress(26, 06, 21) + ", " + degress(119, 12, 42));
	// 福州西南参考点(福州市闽侯县南屿镇)gps 25.974999999999998, 119.21166666666667
	// (25.9776145157,119.2230386554)
	// System.out.println(degress(25, 58, 30) + ", " + degress(119, 12, 42));
	// 福州东南参考点(城门镇)gps 25.974999999999998, 119.36166666666666
	// (25.9779880657,119.3731014562)
	// System.out.println(degress(25, 58, 30) + ", " + degress(119, 21, 42));

	static MapSubject x0y0 = new MapSubject(25.974999999999998, 119.21166666666667,
			25.9776145157, 119.2230386554);
	static MapSubject x1y0 = new MapSubject(26.105833333333333, 119.21166666666667,
			26.1083582702, 119.2230388300);
	static MapSubject x1y1 = new MapSubject(26.105833333333333, 119.36166666666666,
			26.1087320550, 119.3731015851);
	static MapSubject x0y1 = new MapSubject(25.974999999999998, 119.36166666666666,
			25.9779880657, 119.3731014562);

	/**
	 * gps经纬度转小数 
	 * @param v1      度
	 * @param v2      分
	 * @param v3      秒
	 * @return
	 */
	public static double degree(double v1, double v2, double v3) {
		return v1 / 1.0 + v2 / 60.0 + v3 / 3600.0;
	}
	
	/**
	 * 小数转经纬度
	 * @param degree
	 * @return
	 */
	public static String reverDegree(double degree){
		StringBuilder sb = new StringBuilder();
		int du = (int)(degree / 1);
		sb.append(String.valueOf(du) + "度");
		degree = degree % 1 * 60;
		int fen = (int)( degree / 1);
		sb.append(String.valueOf(fen) + "分");
		degree = degree % 1 * 60;
		double miao = degree;
		sb.append(String.valueOf(miao) + "秒");		
		return sb.toString();
	}
	
	public static MapSubject gpsToBaidu(double tGpsLat, double tGpsLng){
		return gpsToBaidu(tGpsLat, tGpsLng, "");
	}

        /**
	 * 
	 * @param tGpsLat 目标gps纬度
	 * @param tGpsLng 目标gps经度
	 * @param realBaidu 从百度api获取的坐标
	 * @return
	 */
	public static MapSubject gpsToBaidu(double tGpsLat, double tGpsLng, String realBaidu) {
		
		/*// 参考点的纠偏数据
		System.out.println(x0y0.getOffsetLat() + ", " + x0y0.getOffsetLng());
		System.out.println(x1y0.getOffsetLat() + ", " + x1y0.getOffsetLng());
		System.out.println(x1y1.getOffsetLat() + ", " + x1y1.getOffsetLng());
		System.out.println(x0y1.getOffsetLat() + ", " + x0y1.getOffsetLng());*/

		System.out.println("targetGps: " + tGpsLat + "," + tGpsLng);
		System.out.println("Real targetBaidu: " + realBaidu);

		// 计算纠偏影响系数
		double param0 = (tGpsLat - x0y0.getBdLat())	* (tGpsLng - x0y0.getBdLng());
		double param1 = (x0y1.getBdLat() - tGpsLat)	* (tGpsLng - x0y1.getBdLng());
		double param2 = (x1y1.getBdLat() - tGpsLat)	* (x1y1.getBdLng() - tGpsLng);
		double param3 = (tGpsLat - x1y0.getBdLat())	* (x1y0.getBdLng() - tGpsLng);

		double tOffsetLat = x0y0.getOffsetLat() * param0 + x0y1.getOffsetLat() * param1 
				+ x1y1.getOffsetLat() * param2 + x1y0.getOffsetLat() * param3;
		double tOffsetLng = x0y0.getOffsetLng() * param0 + x0y1.getOffsetLng() * param1 
				+ x1y1.getOffsetLng() * param2 + x1y0.getOffsetLng() * param3;

		double tBdLat = tGpsLat + tOffsetLat + 0.003; //0.003 修正值.为多次测试比较后得到的一个近似的常量值
		double tBdLng = tGpsLng + tOffsetLng + 0.011; //同上

		System.out.println("Calc targetBaidu: " + tBdLat + "," + tBdLng);
		System.out.println("---------------------------");
		
		return new MapSubject(tGpsLat, tGpsLng, tBdLat, tBdLng);

	}

	public static void main(String[] args) {
		
		gpsToBaidu(26.1100000000, 119.2700000000, "26.1131933362,119.2811939364");
		
		gpsToBaidu(26.0697361026, 119.3022537231, "26.0725808678,119.3136200409");
		
		gpsToBaidu(26.0481851155, 119.2573320865, "26.0513207295,119.2685508427");
		
		gpsToBaidu(26.0135952280, 119.2724275589, "26.0168640068,119.2836105099");
		
		gpsToBaidu(26.0163287437, 119.3032836914, "26.0192058631,119.3146067513");
		
		gpsToBaidu(26.0888307969, 119.3262434006, "26.0914428213,119.3376982627");
		
		gpsToBaidu(25.974999999999998, 119.21166666666667, "25.9776145157,119.2230386554");		
	}

	public static class MapSubject {
		double gpsLng;	//gps经度
		double gpsLat;	//gps纬度
		double bdLng;	//百度经度
		double bdLat;	//百度纬度
		double offsetLng; //经度纠偏值 = 百度经度 - gps经度
		double offsetLat; //纬度纠偏值 = 百度纬度 - gps纬度

		public MapSubject() {
		}

		public MapSubject(double gpsLat, double gpsLng, double bdLat, double bdLng) {
			this.gpsLat = gpsLat;
			this.gpsLng = gpsLng;
			this.bdLat = bdLat;
			this.bdLng = bdLng;
			this.offsetLat = bdLat - gpsLat;
			this.offsetLng = bdLng - gpsLng;
		}

		public double getGpsLng() {
			return gpsLng;
		}

		public void setGpsLng(double gpsLng) {
			this.gpsLng = gpsLng;
		}

		public double getGpsLat() {
			return gpsLat;
		}

		public void setGpsLat(double gpsLat) {
			this.gpsLat = gpsLat;
		}

		public double getBdLng() {
			return bdLng;
		}

		public void setBdLng(double bdLng) {
			this.bdLng = bdLng;
		}

		public double getBdLat() {
			return bdLat;
		}

		public void setBdLat(double bdLat) {
			this.bdLat = bdLat;
		}

		public double getOffsetLng() {
			return offsetLng;
		}

		public void setOffsetLng(double offsetLng) {
			this.offsetLng = offsetLng;
		}

		public double getOffsetLat() {
			return offsetLat;
		}

		public void setOffsetLat(double offsetLat) {
			this.offsetLat = offsetLat;
		}
	}

}

 使用http://www.gpsspg.com/maps.htm验证,使用代码计算在预设范围内的点,gps转百度坐标的结果与实际值的误差在0.0001-0.001,  对于手边的这个项目来说,已经可堪使用了. 

如果设置更多更密集的参考点,误差值将进一步减小.

优点: 方便.

缺点: 计算值与实际值偏差大, 不适合高精度的定位.

相关推荐