本文思路与代码实现完全参考了这篇文章: 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数据文件,计算得到的值居然能粗略拟合百度的二次火星坐标,我自己都觉得这是不是有些不可思议了?
相关推荐
基于java的开发源码-OrientDB(基于Java的实例开发源码-文档数据库) 图形版.zip 基于java的开发源码-OrientDB(基于Java的实例开发源码-文档数据库) 图形版.zip 基于java的开发源码-OrientDB(基于Java的实例开发源码-...
javascript实例应用---连接数据库实例.rarjavascript实例应用---连接数据库实例.rarjavascript实例应用---连接数据库实例.rarjavascript实例应用---连接数据库实例.rar
在这个“java实例-jdbc连接数据库模拟oracle”中,我们很可能会看到一个名为`test.java`的源代码文件,它包含了上述步骤的实现。这个简单的程序可能用于演示如何在Java中进行数据库的连接和查询,例如,模拟不同的...
在"基于Java的实例源码-OrientDB(基于Java的实例源码-文档数据库) 社区版.zip"这个压缩包中,包含了OrientDB社区版的源代码,这对于学习和理解OrientDB的工作原理以及如何在Java项目中集成它是极其宝贵的资源。...
Access自带的示例数据库----罗斯文数据库.doc
标题“PB存取图片实例-asa数据库”表明我们要探讨的是如何使用PowerBuilder(PB)这一编程工具,与ASA(Adaptive Server Anywhere)数据库协同工作,实现图片的存储和读取功能。ASA数据库是Sybase公司的一个轻量级...
这个压缩包文件“Access2016数据库基础与应用教程-实例数据库及数据.zip”显然是为了教学目的而设计的,包含了实际的数据库示例和相关数据,帮助用户学习和理解Access 2016的基本概念和高级功能。 在Access 2016中...
标题中的“基于Java的实例开发源码-Oracle数据库工具 WARTS.zip”表明这是一个使用Java编程语言开发的Oracle数据库管理工具。WARTS(可能是Web-based Application for Reporting, Tracking and Status)是一个开源...
在"基于Java的实例开发源码-OrientDB(基于Java的实例开发源码-文档数据库) 社区版.zip"中,我们获得的是OrientDB社区版的源码,这对于深入理解OrientDB的工作原理以及如何利用Java进行数据库开发是非常宝贵的资源。...
使用PHP访问MySQL数据库---连接数据库实例.pptx
本压缩包“基于Java的源码-OrientDB(基于Java的实例开发源码-文档数据库) 图形版.zip”提供了使用Java语言开发OrientDB的实例代码和图形界面的相关资源,对于学习和理解如何在Java环境中与OrientDB进行交互非常有...
Java实例-幸运观众手机号码抽取器 这是一份 Java 实例项目,关于幸运观众手机号码抽取器的设计和实现。本文档将从实验介绍、系统需求分析、项目分析、数据库设计、系统实现与运行、系统功能评价与改进思路等方面对...
在使用百度地图JavaScript API进行开发时,几何图形的绘制、保存到数据库以及后续的展示是常见的需求。这个项目涉及到的主要知识点包括地图API的使用、几何对象的创建与操作、数据交互以及前端展示技术。 首先,...
实例12-UDP协议实现网络通讯 ... 实例94-查询分析器 实例95-DAO读写ACCESS文件 实例96-创建XML文件 实例97-浏览数据库 实例98-BLOBS 实例99-ORACLE数据库 实例100-读写DBF文件 技术有些陈旧,但内容简单、涵盖面...
本实例源码是关于BoneCP数据库连接池的实现,它是一个高效且轻量级的连接池库,适用于Java环境。在本压缩包中,包含了配置文件bonecp-default-config.xml以及相关的类库。 首先,`bonecp-default-config.xml`是...
总的来说,"mysql-connector-java-5.1.38.jar"是连接Java应用程序和MySQL数据库的关键组件,它通过JDBC接口实现了两者间的通信。正确配置和使用这个驱动,能帮助开发者高效地进行数据库操作,实现数据的存储和检索。
【标题】"JAVA 小数据库实例" 是一个大学课程项目,旨在通过JAVA语言实现一个小型的数据库系统。这个系统具备图形用户界面(GUI),能够支持用户进行登录、注册以及对数据的基本操作,如添加、删除、查询和修改。这...
Oracle数据库实例管理是数据库设计与开发中的重要环节。Oracle服务器由数据库和实例两部分组成,其中实例是由一系列内存结构和操作系统进程构成的,为Oracle客户提供服务。一个实例只能与一个数据库对应,反之亦然。...
在本实例"JAVA100例之实例88JavaBean连接数据库"中,我们将探讨如何利用JavaBean来实现与数据库的交互。数据库连接是Java开发中的基础技能,它允许我们读取、写入或更新存储在数据库中的信息。 首先,我们需要了解...
该光盘中有《Java数据库编程实例》一书中的所有实例源程序代码,编译通过的实例类代码 和JBuilder工程文件,以及实例中应用的数据库,并有在实例中涉及的相关Java类文件(数据库 驱动程序)。配书光盘中全部内容包括...