标签:style blog sqrt adl ima ase box 长度 list
基于c#语言 geohash算法基本实现源码,参见: https://github.com/sharonjl/geohash-net , 源码中具体包含如下方法:
但在实际应用的过程中,由于GeoHash是将区域划分为一个个规则矩形,并对每个矩形进行编码,这样在查询附近POI信息时会导致以下问题,比如红色的点是我们的位 置,绿色的两个点分别是附近的两个餐馆,但是在查询的时候会发现距离较远餐馆的GeoHash编码与我们一样(因为在同一个GeoHash区域块上),而 较近餐馆的GeoHash编码与我们不一致。这个问题往往产生在边界处,如下图:
解决方案:在查询时,除了使用定位点的GeoHash编码进行匹配外,还使用周围8个区域的GeoHash编码,取出相邻的8个区域范围内的所有餐馆作为第一层过滤,然后根据当前位置计算出与8个相邻区域内每个餐厅的距离,按距离的由小到大顺序返回结果,扩展代码如下:
/// <summary>
/// 获取九个格子 顺序 本身 上、下、左、右、 左上、 右上、 左下、右下
/// </summary>
/// <param name="geohash"></param>
/// <returns></returns>
public List<string> GetGeoHashExpand(String geohash)
{
String geohashTop = CalculateAdjacent(geohash, Direction.Top);//上
String geohashBottom = CalculateAdjacent(geohash, Direction.Bottom);//下
String geohashLeft = CalculateAdjacent(geohash, Direction.Left);//左
String geohashRight = CalculateAdjacent(geohash, Direction.Right);//右
String geohashTopLeft = CalculateAdjacent(geohashLeft, Direction.Top);//左上
String geohashTopRight = CalculateAdjacent(geohashRight, Direction.Top);//右上
String geohashBottomLeft = CalculateAdjacent(geohashLeft, Direction.Bottom);//左下
String geohashBottomRight = CalculateAdjacent(geohashRight, Direction.Bottom);//右下
return new List<string>() { geohash, geohashTop, geohashBottom, geohashLeft, geohashRight,
geohashTopLeft, geohashTopRight, geohashBottomLeft, geohashBottomRight };
}
//地球半径,单位米
private const double EARTH_RADIUS = 6378137;
/// <summary>
/// 计算两点位置的距离,返回两点的距离,单位 米
/// 该公式为GOOGLE提供,误差小于0.2米
/// </summary>
/// <param name="lat1">第一点纬度</param>
/// <param name="lng1">第一点经度</param>
/// <param name="lat2">第二点纬度</param>
/// <param name="lng2">第二点经度</param>
/// <returns></returns>
public static double GetDistance(double lat1, double lng1, double lat2, double lng2)
{
double radLat1 = Rad(lat1);
double radLng1 = Rad(lng1);
double radLat2 = Rad(lat2);
double radLng2 = Rad(lng2);
double a = radLat1 - radLat2;
double b = radLng1 - radLng2;
double result = 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))) * EARTH_RADIUS;
return result;
}
/// <summary>
/// 经纬度转化成弧度
/// </summary>
/// <param name="d"></param>
/// <returns></returns>
private static double Rad(double d)
{
return (double)d * Math.PI / 180d;
}
public double[] Decode_bbox(string hash_string)
{
bool isLon = true;
double maxLat = 90,minLat = -90,maxLon = 180,minLon = -180,mid;
int hashValue = 0;
int l = hash_string.Length;
for (int i = 0; i < l; i++)
{
string code = Convert.ToString(hash_string[i]);
hashValue = BASE32_CODES_DICT[code];
for (var bits = 4; bits >= 0; bits--)
{
var bit = (hashValue >> bits) & 1;
if (isLon)
{
mid = (maxLon + minLon) / 2;
if (bit == 1)
{
minLon = mid;
}
else
{
maxLon = mid;
}
}
else
{
mid = (maxLat + minLat) / 2;
if (bit == 1)
{
minLat = mid;
}
else
{
maxLat = mid;
}
}
isLon = !isLon;
}
}
return new double[] { minLat, minLon, maxLat, maxLon };
}
标签:style blog sqrt adl ima ase box 长度 list
原文地址:http://www.cnblogs.com/tgzhu/p/6211751.html