經過這兩天的研究,我想有些東西有必要寫一下,同時也幫助需要的人
這是一個查找附近的人的一個算法,在網上找了這篇文章 http://blog.csdn.net/dyllove98/article/details/9795815,他的算最小正方形的四個頂點有點問題。
第一步 ,我們試想一下,如果我們要查找附近五公里的人,是不是最先想到根據自己的經緯度(如果連經緯度都不知道怎么回事,我想你應該知道度娘),再往數據庫里面獲取其他人的經緯度,根據兩個經緯度獲取他們的距離,
如果距離小於5公里的話,那就符合條件。
獲取距離用兩種情況,第一種就是全部查出來在代碼里面進行算,第二種情況就是在sql 里面寫個函數,在數據庫里面算
代碼算距離算法:
public static double GetDistance(Degree Degree1, Degree Degree2) { double radLat1 = radians(Degree1.Y); double radLat2 = radians(Degree2.Y); double a = radLat1 - radLat2; double b = radians(Degree1.X) - radians(Degree2.X); double s = 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))); s = s * EARTH_RADIUS; s = Math.Round(s * 10000) / 10000; return s; }
radians是個角度轉弧度的算法
private static double degrees(double d) { return d * (180 / Math.PI); }
如果不知道里面的算法是個怎樣的原理,你可以百度相關的三角函數公式
sql 距離算法
SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON GO ALTER function [dbo].[fnGetDistance](@LatBegin float, @LngBegin float, @LatEnd float, @LngEnd float) returns float as begin --距離(千米) declare @Distance float; declare @EARTH_RADIUS float; set @EARTH_RADIUS = 6378.137; declare @RadLatBegin float, @RadLatEnd float, @RadLatDiff float, @RadLngDiff float; set @RadLatBegin = @LatBegin * pi()/180.0; set @RadLatEnd = @LatEnd * pi()/180.; set @RadLatDiff = @RadLatBegin - @RadLatEnd; set @RadLngDiff = @LngBegin * pi()/180.0 - @LngEnd * pi()/180.0; set @Distance = 2 * asin(sqrt(power(sin(@RadLatDiff/2), 2) + cos(@RadLatBegin) * cos(@RadLatEnd) * power(sin(@RadLngDiff/2), 2))); set @Distance = @Distance * @EARTH_RADIUS; --set @Distance = Round(@Distance * 10000) / 10000 return @Distance end
如果你跟我上面的想法一致的話,我只能對你說處理小數據量還可以。
例如:我們現在要做一個停車管理系統,需車位的可以查附近的供車位的,供車位的可以查附近需車位的,如果數據庫里面有一萬條供車位的經緯度,需車位訪問服務器,服務器要進行十萬次距離換算,如果同時有十個人進行訪問的話,那服務器被你輕而易舉的百萬數據量訪問了。
那有什么辦法可以解決呢?
先看這張圖,我們知道原點的坐標也就是我們的經緯度,也在知道半徑(附近幾公里),就可以得到圓的最小正方形,從而根據公式可以得到 正方形的四個頂點 就曉得了 最小經緯度和最大經緯度
把我們得到的經緯度往數據庫里面一查 ,就能輕然一舉的把符合范圍內的人查
出來。
根據經緯度和距離,得到四個頂點的距離算法
private static void GetlatLon(double GLON, double GLAT, double distance, double angle, out double newLon,out double newLat) { double Ea = 6378137; // 赤道半徑 double Eb = 6356725; // 極半徑 double dx = distance * Math.Sin(angle * Math.PI / 180.0); double dy = distance * Math.Cos(angle * Math.PI / 180.0); //double ec = 6356725 + 21412 * (90.0 - GLAT) / 90.0; // 21412 是赤道半徑與極半徑的差 double ec = Eb + (Ea - Eb) * (90.0 - GLAT) / 90.0; double ed = ec * Math.Cos(GLAT * Math.PI / 180); newLon = (dx / ed + GLON * Math.PI / 180.0) * 180.0 / Math.PI; newLat = (dy / ec + GLAT * Math.PI / 180.0) * 180.0 / Math.PI; } public static Degree[] GetRectRange(double centorLogitude,double centorlatitude, double distance) { double temp = 0.0; double maxLatitude; double minLatitude; double maxLongitude; double minLongitude; GetlatLon(centorLogitude, centorlatitude, distance, 0, out temp, out maxLatitude); GetlatLon(centorLogitude, centorlatitude, distance, 180, out temp, out minLatitude); GetlatLon(centorLogitude, centorlatitude, distance, 90, out maxLongitude, out temp); GetlatLon(centorLogitude, centorlatitude, distance, 270, out minLongitude, out temp); maxLatitude = Math.Round(maxLatitude,6); minLatitude = Math.Round(minLatitude,6); maxLongitude = Math.Round(maxLongitude,6); minLongitude = Math.Round(minLongitude,6); return new Degree[] { new Degree(minLongitude,maxLatitude),//left-top new Degree(minLongitude,minLatitude),//left-bottom new Degree(maxLongitude,maxLatitude),//right-top new Degree(maxLongitude,minLatitude) //right-bottom }; }
這些東西經過測試的 相差不到 1,2米
還是那就話如有不懂的地方 請聯系我 QQ:209229923,或在下發為我留言