GPS定位,经纬度附近地点查询–C#实现方法

  目前的工作是需要手机查找附近N米以内的商户,功能如下图

GPS定位,经纬度附近地点查询–C#实现方法

数据库中记录了商家在百度标注的经纬度(如:116.412007, 39.947545),

最初想法  以圆心点为中心点,对半径做循环,半径每增加一个像素(暂定1米)再对周长做循环,到数据库中查询对应点的商家(真是一个长时间的循环工作)

上网百度类似的文章有了点眉目

大致想法是已知一个中心点,一个半径,求圆包含于圆抛物线里所有的点,这样的话就需要知道所要求的这个圆的对角线的顶点,问题来了 经纬度是一个点,半径是一个距离,不能直接加减

终于找到想要的文章

http://digdeeply.org/archives/06152067.html

PHP,Mysql-根据一个给定经纬度的点,进行附近地点查询–合理利用算法,效率提高2125倍

参考原文章 lz改成了C#类

GPS定位,经纬度附近地点查询–C#实现方法

废话不多少直接上代码:

 /// <summary>
/// 经纬度坐标
/// </summary>   public class Degree
{
public Degree(double x, double y)
{
X = x;
Y = y;
}
private double x; public double X
{
get { return x; }
set { x = value; }
}
private double y; public double Y
{
get { return y; }
set { y = value; }
}
} public class CoordDispose
{
private const double EARTH_RADIUS = 6378137.0;//地球半径(米) /// <summary>
/// 角度数转换为弧度公式
/// </summary>
/// <param name="d"></param>
/// <returns></returns>
private static double radians(double d)
{
return d * Math.PI / 180.0;
} /// <summary>
/// 弧度转换为角度数公式
/// </summary>
/// <param name="d"></param>
/// <returns></returns>
private static double degrees(double d)
{
return d * ( / Math.PI);
} /// <summary>
/// 计算两个经纬度之间的直接距离
/// </summary> public static double GetDistance(Degree Degree1, Degree Degree2)
{
double radLat1 = radians(Degree1.X);
double radLat2 = radians(Degree2.X);
double a = radLat1 - radLat2;
double b = radians(Degree1.Y) - radians(Degree2.Y); double s = * Math.Asin(Math.Sqrt(Math.Pow(Math.Sin(a / ), ) +
Math.Cos(radLat1) * Math.Cos(radLat2) * Math.Pow(Math.Sin(b / ), )));
s = s * EARTH_RADIUS;
s = Math.Round(s * ) / ;
return s;
} /// <summary>
/// 计算两个经纬度之间的直接距离(google 算法)
/// </summary>
public static double GetDistanceGoogle(Degree Degree1, Degree Degree2)
{
double radLat1 = radians(Degree1.X);
double radLng1 = radians(Degree1.Y);
double radLat2 = radians(Degree2.X);
double radLng2 = radians(Degree2.Y); double s = Math.Acos(Math.Cos(radLat1) * Math.Cos(radLat2) * Math.Cos(radLng1 - radLng2) + Math.Sin(radLat1) * Math.Sin(radLat2));
s = s * EARTH_RADIUS;
s = Math.Round(s * ) / ;
return s;
} /// <summary>
/// 以一个经纬度为中心计算出四个顶点
/// </summary>
/// <param name="distance">半径(米)</param>
/// <returns></returns>
public static Degree[] GetDegreeCoordinates(Degree Degree1, double distance)
{
double dlng = * Math.Asin(Math.Sin(distance / ( * EARTH_RADIUS)) / Math.Cos(Degree1.X));
dlng = degrees(dlng);//一定转换成角度数 原PHP文章这个地方说的不清楚根本不正确 后来lz又查了很多资料终于搞定了 double dlat = distance / EARTH_RADIUS;
dlat = degrees(dlat);//一定转换成角度数 return new Degree[] { new Degree(Math.Round(Degree1.X + dlat,), Math.Round(Degree1.Y - dlng,)),//left-top
new Degree(Math.Round(Degree1.X - dlat,), Math.Round(Degree1.Y - dlng,)),//left-bottom
new Degree(Math.Round(Degree1.X + dlat,), Math.Round(Degree1.Y + dlng,)),//right-top
new Degree(Math.Round(Degree1.X - dlat,), Math.Round(Degree1.Y + dlng,)) //right-bottom
}; }
}

  测试方法:

  static void Main(string[] args)
{
double a = CoordDispose.GetDistance(new Degree(116.412007, 39.947545), new Degree(116.412924, 39.947918));//116.416984,39.944959
double b = CoordDispose.GetDistanceGoogle(new Degree(116.412007, 39.947545), new Degree(116.412924, 39.947918));
Degree[] dd = CoordDispose.GetDegreeCoordinates(new Degree(116.412007, 39.947545), );
Console.WriteLine(a+" "+b);
Console.WriteLine(dd[].X + "," + dd[].Y );
Console.WriteLine(dd[].X + "," + dd[].Y);
Console.ReadLine();
}

lz试了很多次 误差在1米左右

拿到圆的顶点就好办了

数据库要是sql 2008的可以直接进行空间索引经纬度字段,这样应该性能更好(没有试过)

lz公司数据库还老 2005的 这也没关系,关键是经纬度拆分计算,这个就不用说了 网上多的是 最后上个实现的sql语句

SELECT id,zuobiao FROM dbo.zuobiao WHERE zuobiao<>'' AND
dbo.Get_StrArrayStrOfIndex(zuobiao,',',)>116.41021 AND
dbo.Get_StrArrayStrOfIndex(zuobiao,',',)<116.413804 AND
dbo.Get_StrArrayStrOfIndex(zuobiao,',',)<39.949369 AND
dbo.Get_StrArrayStrOfIndex(zuobiao,',',)>39.945721
上一篇:经典sql面试题(学生表_课程表_成绩表_教师表)


下一篇:JavaWeb项目配置化之Properties类的使用