zoukankan      html  css  js  c++  java
  • GeoHash解析及java实现

    GeoHash解析请参考这里:

    http://www.open-open.com/lib/view/open1417940079964.html

    java实现GeoHash,代码已注释。

    import java.util.BitSet;
    import java.util.HashMap;
    
    /**
     * 地理知识补充: Latitude(纬度)[-90, 90],Longitude(经度)[-180, 180]
     * 
     * @author FengKang 2014-10-03
     *
     */
    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' };
    
        // decode时进行解码之用
        final static HashMap<Character, Integer> lookup = new HashMap<>();
        static {
            int i = 0;
            for (char ch : digits) {
                lookup.put(ch, i++);
            }
        }
    
        /**
         * 在[floor, ceil]区间内对lat进行编码 区间的划分次数为numbits次
         * 
         * @param lat
         *            -待编码经/纬度
         * @param floor
         * @param ceil
         * @return 二进制编码
         */
        private BitSet getBits(double lat, double floor, double ceil) {
            BitSet buffer = new BitSet(numbits);
            for (int i = 0; i < numbits; ++i) {
                double mid = (floor + ceil) / 2;
                if (lat >= mid) {
                    buffer.set(i);
                    floor = mid;
                } else {
                    ceil = mid;
                }
            }
    
            return buffer;
        }
    
        /**
         * 将long型i的二进制位中,每5位映射为一个digits[]中的编码 
         * 这里的实现方法是参照Long.java中toString的实现
         * 
         * @param i
         * @return
         */
        private static String base32(long i) {
            char[] buf = new char[65]; // buf[0]备用,若为负数则存储'-'
            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 String encode(double lat, double lon) {
            BitSet latbits = getBits(lat, -90, 90);
            BitSet lonbits = getBits(lon, -180, 180);
    
            /* ! 先经度后纬度交错组合编码 */
            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');
            }
    
            System.out.println(buffer.toString());
            // 将2进制字符串转换为10进制long型
            return base32(Long.parseLong(buffer.toString(), 2));
        }
    
        /**
         * 根据bs对区间[floor, ceil]进行划分 
         * 0表示位于区间[floor, (floor + ceil)/2]
         * 1表示位于区间[(floor + ceil)/2, ceil]
         * 
         * @param bs
         *            二进制序列
         * @param floor
         *            初始区间边界[floor, ceil]
         * @param ceil
         * @return 区间边界,最接近bs序列的区间边界
         */
        private double decode(BitSet bs, double floor, double ceil) {
            double mid = 0;
            for (int i = 0; i < bs.length(); ++i) {
                mid = (floor + ceil) / 2;
                if (bs.get(i)) {
                    floor = mid; // 右区间
                } else {
                    ceil = mid; // 左区间
                }
            }
    
            return mid;
        }
    
        public double[] decode(String geohash) {
            StringBuilder buffer = new StringBuilder();
            for (char ch : geohash.toCharArray()) {
                int i = lookup.get(ch) + 32; // 保证转换后的二进制字符串为5位
                // +32转换为1#####,然后从下标为1处进行截取,即#####
                buffer.append(Integer.toString(i, 2).substring(1));
            }
            // System.out.println(buffer);
    
            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);
            }
    
            double lon = decode(lonset, -180, 180);
            double lat = decode(latSet, -90, 90);
    
            return new double[] { lat, lon };
        }
    
        public static void main(String[] args) throws Exception {
            Geohash geoHash = new Geohash();
            String encodes = geoHash.encode(45, 125);
            System.out.println(encodes);
    
            double[] decodes = geoHash.decode(encodes);
            System.out.println(decodes[0]);
            System.out.println(decodes[1]);
    
            /**
             * 输出结果 111100101000000010101000000010101000000010101000000010101000
             * yb0bh2n0p058 45.0 124.9999999254942
             */
        }
    }

    注:代码非本人所写,本人仅仅添加一些注释!

  • 相关阅读:
    vsc连接wsl时node进程占用cpu高
    LifeCycles属性
    让kbmMWClientQuery更新视图
    uniGUI免登录的实现
    uniGUI 快速定制手机端输入界面布局
    更新IDE的背景
    Delphi 10.4.1来了
    如何修改windows服务器最大的tcp连接数
    uniGUI怎么升级jquery
    【转】UniGUI的布局使用说明
  • 原文地址:https://www.cnblogs.com/fengkang1008/p/4853839.html
Copyright © 2011-2022 走看看