使用geohash实现附近位置检索并且计算与当前位置的距离

1、使用geohash.encode();方法计算出当前经纬度的位置编码;

例如:(113.76630306243896,34.772396824521024的编码是t4813ym59twz)

2、字符串相似的表示距离相近,使用sql的like查询't481%'即可获得附近的位置,模糊查询位数约大表示距离约近;

使用geohash实现附近位置检索并且计算与当前位置的距离_第1张图片

3、如果位置位于格子边界两侧的两点,距离非常近,但是位置编码大不相同,可同时搜索当前格子周围的8个格子。使用expand.calculateAdjacent();方法获取当前位置周围8个格子。

4sql中使用foreach 结合or查询9个格子的位置编码;

5、最后使用DisUtil.GetDistance()获取位置的距离;

参考文章https://blog.csdn.net/shixiaoguo90/article/details/23909687

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 lookup = new HashMap();

    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();

 

       // even bits

       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);

       }

 

       // odd bits

       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);

       }

       // 中国地理坐标:东经73°至东经135°,北纬至北纬53°

       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));

    }

 

}

 

 

public class DisUtil {

    private static final double EARTH_RADIUS = 6371000;// 赤道半径(单位m)

 

    /**

     * 转化为弧度(rad)

     */

    private static double rad(double d) {

       return d * Math.PI / 180.0;

    }

 

    /**

     * 基于googleMap中的算法得到两经纬度之间的距离,计算精度与谷歌地图的距离精度差点儿相同。相差范围在0.2米下面

     *

     * @param lon1 第一点的精度

     * @param lat1 第一点的纬度

     * @param lon2 第二点的精度

     * @param lat3 第二点的纬度

     * @return 返回的距离,单位m

     */

    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 class expand {

 

    public static int BITS[] = { 16, 8, 4, 2, 1 };

 

    public static String BASE32 = "0123456789bcdefghjkmnpqrstuvwxyz";

 

    public static int RIGHT = 0;

    public static int LEFT = 1;

    public static int TOP = 2;

    public static int BOTTOM = 3;

 

    public static int EVEN = 0;

    public static int ODD = 1;

 

    public static String[][] NEIGHBORS;

    public static String[][] BORDERS;

 

    static {

       NEIGHBORS = new String[4][2];

       BORDERS = new String[4][2];

 

       NEIGHBORS[BOTTOM][EVEN] = "bc01fg45238967deuvhjyznpkmstqrwx";

       NEIGHBORS[TOP][EVEN] = "238967debc01fg45kmstqrwxuvhjyznp";

       NEIGHBORS[LEFT][EVEN] = "p0r21436x8zb9dcf5h7kjnmqesgutwvy";

       NEIGHBORS[RIGHT][EVEN] = "14365h7k9dcfesgujnmqp0r2twvyx8zb";

 

       BORDERS[BOTTOM][EVEN] = "bcfguvyz";

       BORDERS[TOP][EVEN] = "0145hjnp";

       BORDERS[LEFT][EVEN] = "prxz";

       BORDERS[RIGHT][EVEN] = "028b";

 

       NEIGHBORS[BOTTOM][ODD] = NEIGHBORS[LEFT][EVEN];

       NEIGHBORS[TOP][ODD] = NEIGHBORS[RIGHT][EVEN];

       NEIGHBORS[LEFT][ODD] = NEIGHBORS[BOTTOM][EVEN];

       NEIGHBORS[RIGHT][ODD] = NEIGHBORS[TOP][EVEN];

 

       BORDERS[BOTTOM][ODD] = BORDERS[LEFT][EVEN];

       BORDERS[TOP][ODD] = BORDERS[RIGHT][EVEN];

       BORDERS[LEFT][ODD] = BORDERS[BOTTOM][EVEN];

       BORDERS[RIGHT][ODD] = BORDERS[TOP][EVEN];

    }

 

 

    public static String calculateAdjacent(String srcHash, int dir) {

       srcHash = srcHash.toLowerCase();

       char lastChr = srcHash.charAt(srcHash.length() - 1);

       int type = (srcHash.length() % 2) == 1 ? ODD : EVEN;

       String base = srcHash.substring(0, srcHash.length() - 1);

       if (BORDERS[dir][type].indexOf(lastChr) != -1) {

           base = calculateAdjacent(base, dir);

       }

       return base + BASE32.charAt(NEIGHBORS[dir][type].indexOf(lastChr));

    }

 

    public static String[] getGeoHashExpand(String geohash) {

       try {

           String geohashTop = calculateAdjacent(geohash, TOP);

           String geohashBottom = calculateAdjacent(geohash, BOTTOM);

           String geohashRight = calculateAdjacent(geohash, RIGHT);

           String geohashLeft = calculateAdjacent(geohash, LEFT);

 

           String geohashTopLeft = calculateAdjacent(geohashLeft, TOP);

           String geohashTopRight = calculateAdjacent(geohashRight, TOP);

           String geohashBottomRight = calculateAdjacent(geohashRight, BOTTOM);

           String geohashBottomLeft = calculateAdjacent(geohashLeft, BOTTOM);

 

           String[] expand = { geohash, geohashTop, geohashBottom, geohashRight, geohashLeft, geohashTopLeft,

                  geohashTopRight, geohashBottomRight, geohashBottomLeft };

           return expand;

       } catch (Exception e) {

           return null;

       }

    }

 

你可能感兴趣的:(java)