GPS定位,經緯度附近地點查詢–C 實現方法
阿新 • • 發佈:2018-11-16
分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow
也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!
目前的工作是需要手機查詢附近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-top101 new Degree(Math.Round(Degree1.X - dlat,6), Math.Round(Degree1.Y - dlng,6)),//left-bottom102 new Degree(Math.Round(Degree1.X + dlat,6), Math.Round(Degree1.Y + dlng,6)),//right-top103 new Degree(Math.Round(Degree1.X - dlat,6), Math.Round(Degree1.Y + dlng,6)) //right-bottom104 };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 ANDdbo.Get_StrArrayStrOfIndex(zuobiao,',',1)<116.413804 ANDdbo.Get_StrArrayStrOfIndex(zuobiao,',',2)<39.949369 ANDdbo.Get_StrArrayStrOfIndex(zuobiao,',',2)>39.945721