shikeying
2024-01-11 3b67e947e36133e2a40eb2737b15ea375e157ea0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
package com.walker.location;
 
import com.walker.infrastructure.utils.StringUtils;
 
import java.util.ArrayList;
import java.util.List;
 
/**
 * 计算GeoHash工具类,该对象可创建单例。
 * <pre>
 *     1 = 2500km;
 *     2 = 630km;
 *     3 = 78km;
 *     4 = 30km;
 *     5 = 2.4km;
 *     6 = 610m;
 *     7 = 76m;
 *     8 = 19m;
 * </pre>
 * @author 时克英
 * @date 2023-04-18
 */
public class GeoHashHelper {
    public final double Max_Lat = 90;
    public final double Min_Lat = -90;
    public final double Max_Lng = 180;
    public final double Min_Lng = -180;
    private final int length = 20;
    private final double latUnit = (Max_Lat - Min_Lat) / (1 << 20);
    private final double lngUnit = (Max_Lng - Min_Lng) / (1 << 20);
    private final String[] base32Lookup =
            {"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"};
 
    private void convert(double min, double max, double value, List<Character> list) {
        if (list.size() > (length - 1)) {
            return;
        }
        double mid = (max + min) / 2;
        if (value < mid) {
//            list.add('0');
            list.add(StringUtils.CHAR_ZERO);
            convert(min, mid, value, list);
        } else {
//            list.add('1');
            list.add(StringUtils.CHAR_ONE);
            convert(mid, max, value, list);
        }
    }
 
    private String base32Encode(final String str) {
        String unit = StringUtils.EMPTY_STRING;
        StringBuilder sb = new StringBuilder();
        for (int start = 0; start < str.length(); start = start + 5) {
            unit = str.substring(start, start + 5);
            sb.append(base32Lookup[convertToIndex(unit)]);
        }
        return sb.toString();
    }
 
    private int convertToIndex(String str) {
        int length = str.length();
        int result = 0;
        for (int index = 0; index < length; index++) {
            result += str.charAt(index) == StringUtils.CHAR_ZERO ? 0 : 1 << (length - 1 - index);
        }
        return result;
    }
 
    public String encode(double lat, double lng) {
        List<Character> latList = new ArrayList<Character>();
        List<Character> lngList = new ArrayList<Character>();
        convert(Min_Lat, Max_Lat, lat, latList);
        convert(Min_Lng, Max_Lng, lng, lngList);
        StringBuilder sb = new StringBuilder();
        for (int index = 0; index < latList.size(); index++) {
            sb.append(lngList.get(index)).append(latList.get(index));
        }
        return base32Encode(sb.toString());
    }
 
    public List<String> around(double lat, double lng) {
        List<String> list = new ArrayList<String>();
        list.add(encode(lat, lng));
        list.add(encode(lat + latUnit, lng));
        list.add(encode(lat - latUnit, lng));
        list.add(encode(lat, lng + lngUnit));
        list.add(encode(lat, lng - lngUnit));
        list.add(encode(lat + latUnit, lng + lngUnit));
        list.add(encode(lat + latUnit, lng - lngUnit));
        list.add(encode(lat - latUnit, lng + lngUnit));
        list.add(encode(lat - latUnit, lng - lngUnit));
        return list;
    }
}