GeoHashアルゴリズムは近くの店舗と距離を取得します
GeoHashを知ってる
GeoHashアルゴリズムは2次元の緯度座標を直接文字列に変換し,各文字列は矩形領域を表す,すなわち,この矩形領域内のすべての点(緯度座標)が同じGeoHash文字列を共有し,文字列の長さが大きいほど矩形の領域が小さくなり,経度も高くなる.文字列は距離が近いことを表し、文字列の接頭辞マッチングを利用して近くのPOI情報をクエリーすることができる.
GeoHashアルゴリズムの手順
地球の緯度区間は[-90,90]、経度区間は[-18080]であり、区間法によって経度と緯度をそれぞれ計算し、もし私たちが得た現在の座標が経度-0.12866、緯度38.534413であれば、緯度を例に挙げる.緯度を平均して2つの区間に分けた:[-90,0],[0,90]は、左区間と右区間となり、38.534413が右区間に属すると判断でき、値は1、(左区間に属すると値は0); 次に右区間を分割し続けると[0,45],[45,90]となり,このとき38.534413は左区間に属し,値は0 となる.上記の手順を再帰すると、区間の値はますます38.534413 に近づく.アルゴリズムが進むにつれて、私たちは1つのシーケンスを得ることができて、シーケンスの長さは再帰の回数と関係がありますが、必ず保証しなければならないのは経度と緯度のシーケンスの長さが同じで、私のここで設定した再帰の長さは30で、経度と緯度を合わせると60 です.アルゴリズムに基づいて最終的に得られた経度のシーケンスは[0,1,1,1,1,1,1,1,1,1,0,1,0,0,0,0,緯度のシーケンスは[1,0,1,1,0,1,1,1,0,1,1,0,1,1,1,1,0,1,0,1,0,0,0,0,1,0,0,0,0の順であり,その後,このシーケンスに基づいて新しいシーケンス偶数ビット放経度,奇数ビット放緯度を再結合し,2列の符号化組合せを組み合わせて新しい列を生成する[0,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,0,0,1,1,1,1,1,0,1,1,0,1,1,0,0,0,0,0,実はこのシーケンスはバイナリ の列です最後に、この新しい列を10進に変換して0-9、b-z(a,i,l,oを除く)を用いてこの10進を符号化した文字列eyzgjnfr 4 p 0 pが最終的なGeoHash符号化である.下図は、ネット上で与えられた異なる符号化長が与える精度である:
GeoHashの値を取得した後も、同じようにデータベースに近いデータを保存できます.私の最近のデータをクエリーするたびに、理論的にはGeoHashの値を精度に基づいて切り取って曖昧なクエリーを行うことができますが、クエリーには問題があります.クエリーするたびに現在の座標がこの矩形の真ん中にあることを保証できません.座標が矩形の辺にある場合は、境界、それではあなたはその近くのデータを得ることができなくて、それではこの問題はどのように解決しますか?実はとても簡単で、あなたの現在の位置の矩形を九宮格の中間格子にして、更にその隣接する8つの矩形を取得します.
他の8つの領域のGeoHashを取得するのも簡単で、上の表はすでに各領域内の経度と緯度の幅を与えて、それでは直接加減した後に周辺の隣接する8つの格子を得ることができて、私はここで自分でGeoHashのアルゴリズムを書いて、現在の座標のGeoHashの値と隣接する8つの格子の値を得て、コードは比較的に多くて貼らないで、GitHubの上で1つあります他の人の書いたJAVAバージョンのを直接持ってきて使うことができて、geohash-javaを叫んで、mavenの倉庫の中にもあるようです
使用方法も簡単です.
林朝昆のブログから
GeoHashアルゴリズムは2次元の緯度座標を直接文字列に変換し,各文字列は矩形領域を表す,すなわち,この矩形領域内のすべての点(緯度座標)が同じGeoHash文字列を共有し,文字列の長さが大きいほど矩形の領域が小さくなり,経度も高くなる.文字列は距離が近いことを表し、文字列の接頭辞マッチングを利用して近くのPOI情報をクエリーすることができる.
GeoHashアルゴリズムの手順
地球の緯度区間は[-90,90]、経度区間は[-18080]であり、区間法によって経度と緯度をそれぞれ計算し、もし私たちが得た現在の座標が経度-0.12866、緯度38.534413であれば、緯度を例に挙げる.
GeoHashの値を取得した後も、同じようにデータベースに近いデータを保存できます.私の最近のデータをクエリーするたびに、理論的にはGeoHashの値を精度に基づいて切り取って曖昧なクエリーを行うことができますが、クエリーには問題があります.クエリーするたびに現在の座標がこの矩形の真ん中にあることを保証できません.座標が矩形の辺にある場合は、境界、それではあなたはその近くのデータを得ることができなくて、それではこの問題はどのように解決しますか?実はとても簡単で、あなたの現在の位置の矩形を九宮格の中間格子にして、更にその隣接する8つの矩形を取得します.
他の8つの領域のGeoHashを取得するのも簡単で、上の表はすでに各領域内の経度と緯度の幅を与えて、それでは直接加減した後に周辺の隣接する8つの格子を得ることができて、私はここで自分でGeoHashのアルゴリズムを書いて、現在の座標のGeoHashの値と隣接する8つの格子の値を得て、コードは比較的に多くて貼らないで、GitHubの上で1つあります他の人の書いたJAVAバージョンのを直接持ってきて使うことができて、geohash-javaを叫んで、mavenの倉庫の中にもあるようです
使用方法も簡単です.
/**
* Created by linchaokun on 2018/4/9.
*/
public class GeohashUtil {
private static String format = "0.000000";
private static final double EARTH_RADIUS = 6371000;// ( m)
private static int numberOfCharacters = 12;
/**
* Geohash
*
* @param lat
*
* @param lon
*
* @return Geohash
*/
public static String encode(double lat, double lon) {
return getGeoHash(lat,lon,numberOfCharacters).toBase32();
}
/**
* Geohash
*
* @param lat
*
* @param lon
*
* @param number
* 1-12
* @return Geohash
*/
public static String encode(double lat, double lon,int number) {
return getGeoHash(lat,lon,number).toBase32();
}
/**
* GeoHash
*
* @param lat
*
* @param lon
*
* @return Geohash
*/
public static List encodes(double lat, double lon){
List hashs = new ArrayList<>();
GeoHash[] adjacent = getGeoHash(lat,lon,numberOfCharacters).getAdjacent();// GeoHash
for (GeoHash hash : adjacent) {
hashs.add(hash.toBase32());
}
return hashs;
}
/**
* GeoHash
*
* @param lat
*
* @param lon
*
* @param number
* 1-12
* @return Geohash
*/
public static List encodes(double lat, double lon,int number){
List hashs = new ArrayList<>();
GeoHash[] adjacent = getGeoHash(lat,lon,number).getAdjacent();// GeoHash
for (GeoHash hash : adjacent) {
hashs.add(hash.toBase32());
}
return hashs;
}
/**
* GeoHash
* @param geohash
* @return
*/
public static double[] decode(String geohash){
GeoHash geoHash = GeoHash.fromGeohashString(geohash);
WGS84Point point = geoHash.getPoint();
double lat = point.getLatitude();
double lon = point.getLongitude();
DecimalFormat df = new DecimalFormat(format);
return new double[]{Double.parseDouble(df.format(lat)),Double.parseDouble(df.format(lon))};
}
/**
* googleMap , , 0.2
* @param lat1
* @param lng1
* @param lat2
* @param lng2
* @return , m
* */
public static double distance(double lat1, double lng1, double lat2, double lng2) {
double x1 = Math.cos(lat1) * Math.cos(lng1);
double y1 = Math.cos(lat1) * Math.sin(lng1);
double z1 = Math.sin(lat1);
double x2 = Math.cos(lat2) * Math.cos(lng2);
double y2 = Math.cos(lat2) * Math.sin(lng2);
double z2 = Math.sin(lat2);
double lineDistance =
Math.sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2) + (z1 - z2) * (z1 - z2));
double s = EARTH_RADIUS * Math.PI * 2 * Math.asin(0.5 * lineDistance) / 180;
return Math.round(s * 10000) / 10000;
}
private static GeoHash getGeoHash(double lat, double lon,int number){
DecimalFormat df = new DecimalFormat(format);
return GeoHash.withCharacterPrecision(Double.parseDouble(df.format(lat)),Double.parseDouble(df.format(lon)),number);
}
public static void main(String []args){
//116.402843,39.999375 wx4g8c9v
//116.3967,39.99932 wx4g89tk
//116.40382,39.918118 wx4g0ffe
double lon1=116.402843;
double lat1=39.999375;
double lon2=116.40382;
double lat2=39.918118;
double dist;
String geocode;
List hashs = new ArrayList<>();
dist = distance(lat1,lon1,lat2,lon2);
System.out.println(" 1:" + dist + " ");
hashs=encodes(lat1, lon1);
System.out.println(" :" + hashs.toString());
hashs=encodes(lat2, lon2);
System.out.println(" :" + hashs.toString());
double[] decode = GeohashUtil.decode(encode(lat1, lon1));
System.out.println(decode[0]+","+decode[1]);
}
}
林朝昆のブログから