`

java实例 - 使用数据库实现百度地图纠偏

阅读更多

本文思路与代码实现完全参考了这篇文章: gps纠偏数据库及gps纠偏算法PHP

感谢文章作者yanue的无私分享与帮助.

以下代码中所使用到的数据库文件offset.dat请到yanue的网站进行下载.

 

正文代码如下:

package test.offset;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.URL;
import java.net.URLConnection;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.springframework.util.Assert;

import sun.misc.BASE64Decoder;

/**
 * @author 200cc
 *
 */

public class OffsetReader {
	
	static final double M_PI = 3.14159265358979323846264338327950288;
	static final double M_E = 2.71828182845904523536028747135266250;
	
	static final String DIR = "d:\\download\\offset.dat";	
	
	/**
	 * 读取数据库offset.dat文件
	 * @param count 读取数据计数
	 * @return
	 * @throws Exception
	 */
	public static OffsetData[] readOffset(int count) throws Exception{
		/*
		* dat文件结构:该文件为0.01精度校正数据,并以lng和lat递增形式组合.
		* 其中以8个字节为一组:
		* lng : 2字节经度,如12151表示121.51
		* lat : 2字节纬度,如3130表示31.30
		* x_off : 2字节地图x轴偏移像素值
		* y_off : 2字节地图y轴偏移像素值
		*
		*/
		OffsetData[] datas = new OffsetData[count];		
		File f = new File(DIR);	
		Assert.isTrue(f.exists() && f.isFile());		
		FileInputStream fis = new FileInputStream(f);
		byte[] buf = new byte[8];
		@SuppressWarnings("unused")
		int len = 0;
		int cnt = 0;
		while(-1 != (len = fis.read(buf, 0, buf.length))){
			if (cnt >= count) break; 
			int lngS = byte2short(buf, 0) ; // byte[] to short
			int latS = byte2short(buf, 2) ; // byte[] to short
			int x = byte2short(buf, 4) ; // byte[] to short
			int y = byte2short(buf, 6) ; // byte[] to short
			datas[cnt] = new OffsetData(lngS, latS, x, y);
			cnt++;
		}
		return datas;
	}
	
	public static void main(String[] args) throws Exception {
		OffsetData[] datas = readOffset(10);
		for (OffsetData data : datas){
			System.out.println(data);
			geoLatLng(data);
			getBaiduGeo(data.getLat() * 1.0 / 100, data.getLng() * 1.0 / 100);
                        System.out.println("----------------------");
		}		
	}
	
	/**
	 * 获取baidu api计算的经纬
	 * @param lat	纬度
	 * @param lng	经度
	 * @throws Exception
	 */
	public static void getBaiduGeo(double lat, double lng) throws Exception{
		//baidu API
		String urlAddr = "http://api.map.baidu.com/ag/coord/convert?x=" + lng 
				+ "&y=" + lat + "&from=0&to=2&mode=1";
		System.out.println("request: " + urlAddr);
		URL url = new URL(urlAddr);		
		URLConnection connection = url.openConnection();
		connection.setDoOutput(true); //将连接设置为输出模式.即发起一个http请求
		//URLConnection通常作为输入来使用,如下载一个web页面.
		//但同时也能进行输出,将数据向web页面传送.
		OutputStreamWriter out = new OutputStreamWriter(connection.getOutputStream(), "utf-8");
		out.flush();
		out.close();
		//发送成功后,获取得到服务器的响应
		InputStream is = connection.getInputStream();
		BufferedReader br = new BufferedReader(new InputStreamReader(is));
		String line = "";
		StringBuilder sb = new StringBuilder();
		while(null != (line = br.readLine())){
			sb.append(line);
		}
		System.out.println("response: " + sb.toString());
		//[{"error":0,"x":"NzMuNTAzMzU1MDM0NzIy","y":"MzkuMzAwMTQxODcyODM="}]
		Pattern p = Pattern.compile("\"x\":\"(.+)\",\"y\":\"(.+)\""); //正则
		Matcher m = p.matcher(sb.toString());
		String strLng = "", strLat = "";
		if(m.find()){
			BASE64Decoder decoder = new BASE64Decoder();
			strLng = new String(decoder.decodeBuffer(m.group(1)));
			strLat = new String(decoder.decodeBuffer(m.group(2)));
		}else{
			throw new RuntimeException("");
		}
		System.out.println("baidu Geo: " + strLat + ", " + strLng);
		Thread.sleep(1000); //暂停一会. baidu Api有发起次数限制.
	}
	
	/**
	 * byte[] 转 short
	 * @param b
	 * @param index
	 * @return
	 */
	public static short byte2short(byte[] b, int index){
		 return (short) (((b[index + 1] << 8) | b[index + 0] & 0xff));
	}
	
	/**
	 * byte[] 转 float
	 * @param b
	 * @param index
	 * @return
	 */
	public static float getFloat(byte[] b, int index) {  
	    int l;  
	    l = b[index + 0];  
	    l &= 0xff;  
	    l |= ((long) b[index + 1] << 8);  
	    l &= 0xffff;  
	    l |= ((long) b[index + 2] << 16);  
	    l &= 0xffffff;  
	    l |= ((long) b[index + 3] << 24);  
	    return Float.intBitsToFloat(l);  
	}
		
	
	public static void geoLatLng(OffsetData data){
		geoLatLng(data.getLng() * 1.0 / 100, data.getLat() * 1.0 / 100, data.getOffsetPixelX(), data.getOffsetPixelY());
	}
	
	/**
	 * 使用数据库计算经纬度坐标
	 * @param lng 	实际(gps)经度
	 * @param lat	实际(gps)纬度
	 * @param offsetX	地图x轴偏移像素值
	 * @param offsetY	地图y轴偏移像素值
	 */
	public static void geoLatLng(double lng, double lat, int offsetX, int offsetY){
		double lngPixel = lngToPixel(lng, 18) + offsetX;
		double latPixel = latToPixel(lat, 18) + offsetY;
		double mixLat = pixelToLat(latPixel, 18);
		double mixLng = pixelToLng(lngPixel, 18);
		System.out.println("calculate geo: " + mixLat + ", " + mixLng);
	}
	
	public static double lngToPixel(double lng, int zoom){
		double res = (lng  + 180) * (256 << zoom) / 360;
		//System.out.println("lngToPixel: lng=" + lng + " --> res=" + res );
		return res;
	}
	
	public static double latToPixel(double lat , int zoom){
		double siny = Math.sin(lat * M_PI / 180);
		double y = Math.log((1 + siny) / (1 - siny));
		double res = (128 << zoom) * (1 - y / (2 * M_PI));
		//System.out.println("latToPixel: lat=" + lat + " --> res=" + res );
		return res;
	}
	
	public static double pixelToLng(double pixelX, int zoom){
		double res = pixelX * 360 / (256 << zoom) - 180;
		//System.out.println("pixelToLng: pixelX=" + pixelX + " --> res=" + res );
		return res;
	}
	
	public static double pixelToLat(double pixelY, int zoom){
		double y = 2 * M_PI * (1 - pixelY /(128 << zoom));
		double z = Math.pow(M_E , y);
		double siny = (z - 1) / (z + 1);
		double res = Math.asin(siny) * 180 / M_PI;
		//System.out.println("pixelToLat: pixelY=" + pixelY + " --> res=" + res );
		return res;
	}
	
	public static class OffsetData{
		
		int lng;
		int lat;
		int offsetPixelX;
		int offsetPixelY;
		
		public OffsetData(int lng, int lat, int x, int y){
			this.lng = lng;
			this.lat = lat;
			this.offsetPixelX = x;
			this.offsetPixelY = y;
		}
		
		public String toString(){
			return this.lng + ", " + this.lat + ", " + this.offsetPixelX + ", " + this.offsetPixelY;
		}
		
		public int getLng() {
			return lng;
		}

		public void setLng(int lng) {
			this.lng = lng;
		}

		public int getLat() {
			return lat;
		}

		public void setLat(int lat) {
			this.lat = lat;
		}

		public int getOffsetPixelX() {
			return offsetPixelX;
		}

		public void setOffsetPixelX(int offsetPixelX) {
			this.offsetPixelX = offsetPixelX;
		}

		public int getOffsetPixelY() {
			return offsetPixelY;
		}

		public void setOffsetPixelY(int offsetPixelY) {
			this.offsetPixelY = offsetPixelY;
		}		
		
	}
	
}

 

运行后结果:

7350, 3930, 624, -35
calculate geo: 39.30014529193229, 73.50334739685061
request: http://api.map.baidu.com/ag/coord/convert?x=73.5&y=39.3&from=0&to=2&mode=1
response: [{"error":0,"x":"NzMuNTAzMzU1MDM0NzIy","y":"MzkuMzAwMTQxODcyODM="}]
baidu Geo: 39.30014187283, 73.503355034722
----------------------
7350, 3931, 624, -36
calculate geo: 39.31014942177512, 73.50334739685061
request: http://api.map.baidu.com/ag/coord/convert?x=73.5&y=39.31&from=0&to=2&mode=1
response: [{"error":0,"x":"NzMuNTAzMzU1MzA1OTk=","y":"MzkuMzEwMTQ2NzU1NjQy"}]
baidu Geo: 39.310146755642, 73.50335530599
----------------------
7350, 3932, 624, -37
calculate geo: 39.32015355042689, 73.50334739685061
request: http://api.map.baidu.com/ag/coord/convert?x=73.5&y=39.32&from=0&to=2&mode=1
response: [{"error":0,"x":"NzMuNTAzMzU1NTc3MjU3","y":"MzkuMzIwMTUxMzY3MTg3"}]
baidu Geo: 39.320151367187, 73.503355577257
----------------------
7350, 3933, 625, -38
calculate geo: 39.33015767788718, 73.50335276126864
request: http://api.map.baidu.com/ag/coord/convert?x=73.5&y=39.33&from=0&to=2&mode=1
response: [{"error":0,"x":"NzMuNTAzMzU2MTE5Nzky","y":"MzkuMzMwMTU1NzA3NDY1"}]
baidu Geo: 39.330155707465, 73.503356119792
----------------------
7350, 3934, 625, -39
calculate geo: 39.34016180415566, 73.50335276126864
request: http://api.map.baidu.com/ag/coord/convert?x=73.5&y=39.34&from=0&to=2&mode=1
response: [{"error":0,"x":"NzMuNTAzMzU2MzkxMDU5","y":"MzkuMzQwMTYwMzE5MDE="}]
baidu Geo: 39.34016031901, 73.503356391059
----------------------
7350, 3935, 625, -40
calculate geo: 39.350165929231935, 73.50335276126864
request: http://api.map.baidu.com/ag/coord/convert?x=73.5&y=39.35&from=0&to=2&mode=1
response: [{"error":0,"x":"NzMuNTAzMzU2NjYyMzI2","y":"MzkuMzUwMTY0NjU5Mjg4"}]
baidu Geo: 39.350164659288, 73.503356662326
----------------------
7350, 3936, 625, -41
calculate geo: 39.36017005311557, 73.50335276126864
request: http://api.map.baidu.com/ag/coord/convert?x=73.5&y=39.36&from=0&to=2&mode=1
response: [{"error":0,"x":"NzMuNTAzMzU2OTMzNTk0","y":"MzkuMzYwMTY4OTk5NTY2"}]
baidu Geo: 39.360168999566, 73.503356933594
----------------------
7350, 3937, 625, -42
calculate geo: 39.37017417580627, 73.50335276126864
request: http://api.map.baidu.com/ag/coord/convert?x=73.5&y=39.37&from=0&to=2&mode=1
response: [{"error":0,"x":"NzMuNTAzMzU3NDc2MTI4","y":"MzkuMzcwMTczMDY4NTc2"}]
baidu Geo: 39.370173068576, 73.503357476128
----------------------
7350, 3938, 625, -43
calculate geo: 39.380178297303594, 73.50335276126864
request: http://api.map.baidu.com/ag/coord/convert?x=73.5&y=39.38&from=0&to=2&mode=1
response: [{"error":0,"x":"NzMuNTAzMzU3NzQ3Mzk2","y":"MzkuMzgwMTc3MTM3NTg3"}]
baidu Geo: 39.380177137587, 73.503357747396
----------------------
7351, 3930, 616, -28
calculate geo: 39.30011623356995, 73.51330448150634
request: http://api.map.baidu.com/ag/coord/convert?x=73.51&y=39.3&from=0&to=2&mode=1
response: [{"error":0,"x":"NzMuNTEzMzEyMTc0NDc5","y":"MzkuMzAwMTEyMDMzNDI="}]
baidu Geo: 39.30011203342, 73.513312174479
----------------------

 

总结:

从运行结果可以看到,使用数据库计算后的结果,与baidu返回的数据间的差值大约在0.0001左右.误差值还是挺大的.- -b.

 

本人能力有限,代码中肯定还存在错误,恳请诸位指正.

 

此外还衍生出一个问题: 我在网上查到

Q:百度坐标为何有偏移?
A:国际经纬度坐标标准为WGS-84,国内必须至少使用国测局制定的GCJ-02,对地理位置进行首次加密。百度坐标在此基础上,进行了BD-09二次加密措施,更加保护了个人隐私。...

 使用这个offset.dat数据文件,计算得到的值居然能粗略拟合百度的二次火星坐标,我自己都觉得这是不是有些不可思议了?

分享到:
评论

相关推荐

    javascript实例应用---连接数据库实例.rar

    javascript实例应用---连接数据库实例.rarjavascript实例应用---连接数据库实例.rarjavascript实例应用---连接数据库实例.rarjavascript实例应用---连接数据库实例.rar

    基于Java的实例源码-OrientDB(基于Java的实例源码-文档数据库) 社区版.zip

    在"基于Java的实例源码-OrientDB(基于Java的实例源码-文档数据库) 社区版.zip"这个压缩包中,包含了OrientDB社区版的源代码,这对于学习和理解OrientDB的工作原理以及如何在Java项目中集成它是极其宝贵的资源。...

    PB存取图片实例-asa数据库

    标题“PB存取图片实例-asa数据库”表明我们要探讨的是如何使用PowerBuilder(PB)这一编程工具,与ASA(Adaptive Server Anywhere)数据库协同工作,实现图片的存储和读取功能。ASA数据库是Sybase公司的一个轻量级...

    Shiro应用实例-数据库

    Java安全框架Shiro的使用实例-数据库

    Access2016数据库基础与应用教程-实例数据库及数据.zip

    这个压缩包文件“Access2016数据库基础与应用教程-实例数据库及数据.zip”显然是为了教学目的而设计的,包含了实际的数据库示例和相关数据,帮助用户学习和理解Access 2016的基本概念和高级功能。 在Access 2016中...

    基于Java的实例开发源码-Oracle数据库工具 WARTS.zip

    标题中的“基于Java的实例开发源码-Oracle数据库工具 WARTS.zip”表明这是一个使用Java编程语言开发的Oracle数据库管理工具。WARTS(可能是Web-based Application for Reporting, Tracking and Status)是一个开源...

    基于Java的实例开发源码-OrientDB(基于Java的实例开发源码-文档数据库) 社区版.zip

    在"基于Java的实例开发源码-OrientDB(基于Java的实例开发源码-文档数据库) 社区版.zip"中,我们获得的是OrientDB社区版的源码,这对于深入理解OrientDB的工作原理以及如何利用Java进行数据库开发是非常宝贵的资源。...

    使用PHP访问MySQL数据库---连接数据库实例.pptx

    使用PHP访问MySQL数据库---连接数据库实例.pptx

    基于Java的源码-OrientDB(基于Java的实例开发源码-文档数据库) 图形版.zip

    本压缩包“基于Java的源码-OrientDB(基于Java的实例开发源码-文档数据库) 图形版.zip”提供了使用Java语言开发OrientDB的实例代码和图形界面的相关资源,对于学习和理解如何在Java环境中与OrientDB进行交互非常有...

    百度地图js版api几何图形绘制保存到数据库并展示

    在使用百度地图JavaScript API进行开发时,几何图形的绘制、保存到数据库以及后续的展示是常见的需求。这个项目涉及到的主要知识点包括地图API的使用、几何对象的创建与操作、数据交互以及前端展示技术。 首先,...

    基于Java的实例源码-数据库连接池 BoneCP.zip

    本实例源码是关于BoneCP数据库连接池的实现,它是一个高效且轻量级的连接池库,适用于Java环境。在本压缩包中,包含了配置文件bonecp-default-config.xml以及相关的类库。 首先,`bonecp-default-config.xml`是...

    mysql-connector-java-5.1.38.jar

    总的来说,"mysql-connector-java-5.1.38.jar"是连接Java应用程序和MySQL数据库的关键组件,它通过JDBC接口实现了两者间的通信。正确配置和使用这个驱动,能帮助开发者高效地进行数据库操作,实现数据的存储和检索。

    java-数据库—省县区三级联动

    在这个场景中,我们关注的是"java-数据库—省县区三级联动"的功能实现,这通常用于地址选择或者地理信息相关的Web应用中。下面将详细阐述这个主题涉及的知识点。 首先,我们要理解的是数据库层面的内容。在提供的...

    SpringBoot使用注解实现 Redis 数据库的切换.zip

    为了实现数据库的切换,我们需要创建多个`RedisTemplate`实例,每个实例对应一个数据库。SpringBoot本身并不直接提供这样的功能,但我们可以自定义配置类来实现。创建一个名为`RedisConfig`的配置类,使用`@...

    mysql-connector-java-5.1.47-bin.jar

    一旦`mysql-connector-java`被正确引入,你就可以使用JDBC API来执行数据库相关的操作。以下是一些基本步骤: 1. 加载驱动:使用`Class.forName()`方法加载MySQL的JDBC驱动。 ```java Class.forName(...

    基于Java的实例源码-连接postsql数据库的Java代码.zip

    本实例源码提供了使用Java连接PostgreSQL数据库的方法,这对于学习Java数据库编程或在实际项目中应用非常有价值。 首先,我们需要了解Java中用于数据库操作的JDBC(Java Database Connectivity)API。JDBC是Java...

    java源码包---java 源码 大量 实例

     Java实现的FTP连接与数据浏览程序,实现实例化可操作的窗口。  部分源代码摘录:  ftpClient = new FtpClient(); //实例化FtpClient对象  String serverAddr=jtfServer.getText(); //得到服务器地址  ...

    java连接数据库代码

    Java连接数据库是应用程序与数据库交互的基础,通过Java的JDBC(Java Database Connectivity)API,开发者可以实现对多种数据库系统的操作。以下将详细讲解标题和描述中提到的知识点,并结合给出的部分内容进行扩展...

    mysql数据库驱动包mysql-connector-java-5.1.39-SNAPSHOT-bin.jar

    4. **Type 4 (纯Java驱动)**:使用Java实现数据库的网络协议,如MySQL Connector/J,提供最佳性能和平台独立性。 **Jira与MySQL的集成** Jira是一款流行的项目管理软件,广泛应用于敏捷开发团队。默认情况下,Jira...

    Java数据库编程实例

    此外,我们还可以利用高级的JDBC API,如`CallableStatement`用于调用存储过程,以及`ConnectionPool`实现数据库连接池,提高应用程序的性能和效率。 在实际项目中,为了简化数据库操作,通常会使用ORM(对象关系...

Global site tag (gtag.js) - Google Analytics