参考文档: http://blog.csdn.net/wangxiafghj/article/details/9014363geohash 算法原理及实现方式 http://blog.charlee.li/geohash-intro/ geohash:用字符串实现附近地点搜索 http://blog.sina.com.cn/s/blog_7c05385f0101eofb.html 查找附近点--Geohash方案讨论 http://www.wubiao.info/372 查找附近的xxx 球面距离以及Geohash方案探讨 http://en.wikipedia.org/wiki/Haversine_formula Haversine formula球面距离公式 http://www.codecodex.com/wiki/Calculate_Distance_Between_Two_Points_on_a_Globe 球面距离公式代码实现 http://developer.baidu.com/map/jsdemo.htm#a6_1 球面距离公式验证 http://www.wubiao.info/470 Mysql or Mongodb LBS快速实现方案
geohash有以下几个特点: 首先,geohash用一个字符串表示经度和纬度两个坐标。某些情况下无法在两列上同时应用索引 (例如MySQL 4之前的版本,Google App Engine的数据层等),利用geohash,只需在一列上应用索引即可。 其次,geohash表示的并不是一个点,而是一个矩形区域。比如编码wx4g0ec19,它表示的是一个矩形区域。 使用者可以发布地址编码,既能表明自己位于北海公园附近,又不至于暴露自己的精确坐标,有助于隐私保护。 第三,编码的前缀可以表示更大的区域。例如wx4g0ec1,它的前缀wx4g0e表示包含编码wx4g0ec1在内的更大范围。 这个特性可以用于附近地点搜索。首先根据用户当前坐标计算geohash(例如wx4g0ec1)然后取其前缀进行查询 (SELECT * FROM place WHERE geohash LIKE 'wx4g0e%'),即可查询附近的所有地点。 Geohash比直接用经纬度的高效很多。 Geohash算法实现(Java版本) - package com.DistTest;
- import java.util.BitSet;
- import java.util.HashMap;
-
- public class Geohash {
-
- private static int numbits = 6 * 5;
- final static char[] digits = { '0', '1', '2', '3', '4', '5', '6', '7', '8',
- '9', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'j', 'k', 'm', 'n', 'p',
- 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z' };
-
- final static HashMap<Character, Integer> lookup = new HashMap<Character, Integer>();
- static {
- int i = 0;
- for (char c : digits)
- lookup.put(c, i++);
- }
-
- public double[] decode(String geohash) {
- StringBuilder buffer = new StringBuilder();
- for (char c : geohash.toCharArray()) {
-
- int i = lookup.get(c) + 32;
- buffer.append( Integer.toString(i, 2).substring(1) );
- }
-
- BitSet lonset = new BitSet();
- BitSet latset = new BitSet();
-
-
- int j =0;
- for (int i=0; i< numbits*2;i+=2) {
- boolean isSet = false;
- if ( i < buffer.length() )
- isSet = buffer.charAt(i) == '1';
- lonset.set(j++, isSet);
- }
-
-
- j=0;
- for (int i=1; i< numbits*2;i+=2) {
- boolean isSet = false;
- if ( i < buffer.length() )
- isSet = buffer.charAt(i) == '1';
- latset.set(j++, isSet);
- }
-
- double lon = decode(lonset, 70, 140);
- double lat = decode(latset, 0, 60);
-
- return new double[] {lat, lon};
- }
-
- private double decode(BitSet bs, double floor, double ceiling) {
- double mid = 0;
- for (int i=0; i<bs.length(); i++) {
- mid = (floor + ceiling) / 2;
- if (bs.get(i))
- floor = mid;
- else
- ceiling = mid;
- }
- return mid;
- }
-
-
- public String encode(double lat, double lon) {
- BitSet latbits = getBits(lat, 0, 60);
- BitSet lonbits = getBits(lon, 70, 140);
- StringBuilder buffer = new StringBuilder();
- for (int i = 0; i < numbits; i++) {
- buffer.append( (lonbits.get(i))?'1':'0');
- buffer.append( (latbits.get(i))?'1':'0');
- }
- return base32(Long.parseLong(buffer.toString(), 2));
- }
-
- private BitSet getBits(double lat, double floor, double ceiling) {
- BitSet buffer = new BitSet(numbits);
- for (int i = 0; i < numbits; i++) {
- double mid = (floor + ceiling) / 2;
- if (lat >= mid) {
- buffer.set(i);
- floor = mid;
- } else {
- ceiling = mid;
- }
- }
- return buffer;
- }
-
- public static String base32(long i) {
- char[] buf = new char[65];
- int charPos = 64;
- boolean negative = (i < 0);
- if (!negative)
- i = -i;
- while (i <= -32) {
- buf[charPos--] = digits[(int) (-(i % 32))];
- i /= 32;
- }
- buf[charPos] = digits[(int) (-i)];
-
- if (negative)
- buf[--charPos] = '-';
- return new String(buf, charPos, (65 - charPos));
- }
-
- }
球面距离公式: - package com.DistTest;
- public class Test{
- private static final double EARTH_RADIUS = 6371000;
-
-
-
-
- private static double rad(double d)
- {
- return d * Math.PI / 180.0;
- }
-
-
-
-
-
-
-
-
- public static double GetDistance(double lon1,double lat1,double lon2, double lat2)
- {
- double radLat1 = rad(lat1);
- double radLat2 = rad(lat2);
- double a = radLat1 - radLat2;
- double b = rad(lon1) - rad(lon2);
- double s = 2 * Math.asin(Math.sqrt(Math.pow(Math.sin(a/2),2)+Math.cos(radLat1)*Math.cos(radLat2)*Math.pow(Math.sin(b/2),2)));
- s = s * EARTH_RADIUS;
- s = Math.round(s * 10000) / 10000;
- return s;
- }
-
- public static void main(String []args){
- double lon1=109.0145193757;
- double lat1=34.236080797698;
- double lon2=108.9644583556;
- double lat2=34.286439088548;
- double dist;
- String geocode;
-
- dist=Test.GetDistance(lon1, lat1, lon2, lat2);
- System.out.println("两点相距:" + dist + " 米");
-
-
- Geohash geohash = new Geohash();
- geocode=geohash.encode(lat1, lon1);
- System.out.println("当前位置编码:" + geocode);
-
- geocode=geohash.encode(lat2, lon2);
- System.out.println("远方位置编码:" + geocode);
-
- }
-
-
-
-
-
-
-
-
- }
附近网点距离排序 - package com.DistTest;
-
- import java.sql.DriverManager;
- import java.sql.ResultSet;
- import java.sql.SQLException;
- import java.sql.Connection;
- import java.sql.Statement;
-
-
- public class sqlTest {
-
- public static void main(String[] args) throws Exception {
- Connection conn = null;
- String sql;
- String url = "jdbc:mysql://132.97.**.**/test?"
- + "user=***&password=****&useUnicode=true&characterEncoding=UTF8";
-
- try {
- Class.forName("com.mysql.jdbc.Driver");
-
-
- conn = DriverManager.getConnection(url);
-
- Statement stmt = conn.createStatement();
- sql = "select * from retailersinfotable limit 1,10";
- ResultSet rs = stmt.executeQuery(sql);
- double lon1=109.0145193757;
- double lat1=34.236080797698;
- System.out.println("当前位置:");
- int i=0;
- String[][] array = new String[10][3];
- while (rs.next()){
-
- double lon2=Double.parseDouble(rs.getString("Longitude"));
- double lat2=Double.parseDouble(rs.getString("Latitude"));
-
-
- Geohash geohash = new Geohash();
- String geocode=geohash.encode(lat2, lon2).substring(0, 9);
-
-
- int dist=(int) Test.GetDistance(lon1, lat1, lon2, lat2);
-
- array[i][0]=String.valueOf(i);
- array[i][1]=geocode;
- array[i][2]=Integer.toString(dist);
-
- i++;
-
-
- }
-
- array=sqlTest.getOrder(array);
- sqlTest.showArray(array);
-
-
-
-
- } catch (SQLException e) {
- System.out.println("MySQL操作错误");
- e.printStackTrace();
- } finally {
- conn.close();
- }
-
- }
-
-
-
- public static String[][] getOrder(String[][] array){
- for (int j = 0; j < array.length ; j++) {
- for (int bb = 0; bb < array.length - 1; bb++) {
- String[] ss;
- int a1=Integer.valueOf(array[bb][2]);
- int a2=Integer.valueOf(array[bb+1][2]);
- if (a1>a2) {
- ss = array[bb];
- array[bb] = array[bb + 1];
- array[bb + 1] = ss;
-
- }
- }
- }
- return array;
- }
-
-
- public static void showArray(String[][] array){
- for(int a=0;a<array.length;a++){
- for(int j=0;j<array[0].length;j++)
- System.out.print(array[a][j]+" ");
- System.out.println();
- }
- }
-
- }
 来源:http://blog.csdn.net/sunrise_2013/article/details/42024813 |