package com.walker.location;
import com.walker.infrastructure.utils.StringUtils;
import java.util.ArrayList;
import java.util.List;
/**
* 计算GeoHash工具类,该对象可创建单例。
*
* 1 = 2500km;
* 2 = 630km;
* 3 = 78km;
* 4 = 30km;
* 5 = 2.4km;
* 6 = 610m;
* 7 = 76m;
* 8 = 19m;
*
* @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 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 latList = new ArrayList();
List lngList = new ArrayList();
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 around(double lat, double lng) {
List list = new ArrayList();
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;
}
}