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

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM