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


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

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

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

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

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

     终于找到想要的文章

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

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

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

    废话不多少直接上代码:

      1 /// <summary>
      2     /// 经纬度坐标
      3     /// </summary>    
      4 
      5   public class Degree
      6     {
      7         public Degree(double x, double y)
      8         {
      9             X = x;
     10             Y = y;
     11         }
     12         private double x;
     13 
     14         public double X
     15         {
     16             get { return x; }
     17             set { x = value; }
     18         }
     19         private double y;
     20 
     21         public double Y
     22         {
     23             get { return y; }
     24             set { y = value; }
     25         }
     26     }
     27 
     28 
     29     public class CoordDispose
     30     {
     31         private const double EARTH_RADIUS = 6378137.0;//地球半径(米)
     32 
     33         /// <summary>
     34         /// 角度数转换为弧度公式
     35         /// </summary>
     36         /// <param name="d"></param>
     37         /// <returns></returns>
     38         private static double radians(double d)
     39         {
     40             return d * Math.PI / 180.0;
     41         }
     42 
     43         /// <summary>
     44         /// 弧度转换为角度数公式
     45         /// </summary>
     46         /// <param name="d"></param>
     47         /// <returns></returns>
     48         private static double degrees(double d)
     49         {
     50             return d * (180 / Math.PI);
     51         }
     52 
     53         /// <summary>
     54         /// 计算两个经纬度之间的直接距离
     55         /// </summary>
     56 
     57         public static double GetDistance(Degree Degree1, Degree Degree2)
     58         {
     59             double radLat1 = radians(Degree1.X);
     60             double radLat2 = radians(Degree2.X);
     61             double a = radLat1 - radLat2;
     62             double b = radians(Degree1.Y) - radians(Degree2.Y);
     63 
     64             double s = 2 * Math.Asin(Math.Sqrt(Math.Pow(Math.Sin(a / 2), 2) +
     65              Math.Cos(radLat1) * Math.Cos(radLat2) * Math.Pow(Math.Sin(b / 2), 2)));
     66             s = s * EARTH_RADIUS;
     67             s = Math.Round(s * 10000) / 10000;
     68             return s;
     69         }
     70 
     71         /// <summary>
     72         /// 计算两个经纬度之间的直接距离(google 算法)
     73         /// </summary>
     74         public static double GetDistanceGoogle(Degree Degree1, Degree Degree2)
     75         {
     76             double radLat1 = radians(Degree1.X);
     77             double radLng1 = radians(Degree1.Y);
     78             double radLat2 = radians(Degree2.X);
     79             double radLng2 = radians(Degree2.Y);
     80 
     81             double s = Math.Acos(Math.Cos(radLat1) * Math.Cos(radLat2) * Math.Cos(radLng1 - radLng2) + Math.Sin(radLat1) * Math.Sin(radLat2));
     82             s = s * EARTH_RADIUS;
     83             s = Math.Round(s * 10000) / 10000;
     84             return s;
     85         }
     86 
     87         /// <summary>
     88         /// 以一个经纬度为中心计算出四个顶点
     89         /// </summary>
     90         /// <param name="distance">半径(米)</param>
     91         /// <returns></returns>
     92         public static Degree[] GetDegreeCoordinates(Degree Degree1, double distance)
     93         {
     94             double dlng = 2 * Math.Asin(Math.Sin(distance / (2 * EARTH_RADIUS)) / Math.Cos(Degree1.X));
     95             dlng = degrees(dlng);//一定转换成角度数  原PHP文章这个地方说的不清楚根本不正确 后来lz又查了很多资料终于搞定了
     96 
     97             double dlat = distance / EARTH_RADIUS;
     98             dlat = degrees(dlat);//一定转换成角度数
     99 
    100             return new Degree[] { new Degree(Math.Round(Degree1.X + dlat,6), Math.Round(Degree1.Y - dlng,6)),//left-top
    101                                   new Degree(Math.Round(Degree1.X - dlat,6), Math.Round(Degree1.Y - dlng,6)),//left-bottom
    102                                   new Degree(Math.Round(Degree1.X + dlat,6), Math.Round(Degree1.Y + dlng,6)),//right-top
    103                                   new Degree(Math.Round(Degree1.X - dlat,6), Math.Round(Degree1.Y + dlng,6)) //right-bottom
    104             };
    105 
    106         }
    107     }

      测试方法:

     1  static void Main(string[] args)
     2         {
     3             double a = CoordDispose.GetDistance(new Degree(116.412007, 39.947545), new Degree(116.412924, 39.947918));//116.416984,39.944959
     4             double b = CoordDispose.GetDistanceGoogle(new Degree(116.412007, 39.947545), new Degree(116.412924, 39.947918));
     5             Degree[] dd = CoordDispose.GetDegreeCoordinates(new Degree(116.412007, 39.947545), 102);
     6             Console.WriteLine(a+" "+b);
     7             Console.WriteLine(dd[0].X + "," + dd[0].Y );
     8             Console.WriteLine(dd[3].X + "," + dd[3].Y);
     9             Console.ReadLine();
    10         }

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

    拿到圆的顶点就好办了

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

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

    SELECT id,zuobiao FROM dbo.zuobiao WHERE zuobiao<>'' AND 
    dbo.Get_StrArrayStrOfIndex(zuobiao,',',1)>116.41021 AND
    dbo.Get_StrArrayStrOfIndex(zuobiao,',',1)<116.413804 AND
    dbo.Get_StrArrayStrOfIndex(zuobiao,',',2)<39.949369 AND
    dbo.Get_StrArrayStrOfIndex(zuobiao,',',2)>39.945721
  • 相关阅读:
    MapReduce job在JobTracker初始化源码级分析
    Flume-NG源码阅读之FileChannel
    linux下gzip压缩同样内容大小不一样
    mapreduce job提交流程源码级分析(三)
    JobTracker启动流程源码级分析
    机器学习经典算法之K-Means
    机器学习经典算法之KNN
    机器学习经典算法之SVM
    机器学习经典算法之朴素贝叶斯分类
    机器学习经典算法之决策树
  • 原文地址:https://www.cnblogs.com/cake/p/3240325.html
Copyright © 2020-2023  润新知