天天看點

通過經緯度坐标計算距離的方法(經緯度距離計算)ZZ

最近在網上搜尋“通過經緯度坐标計算距離的方法”,發現網上大部分都是如下的代碼:

#define PI 3.14159265

static double Rc = 6378137;  // 赤道半徑

static double Rj = 6356725;  // 極半徑

class JWD

{

public:

double m_Longitude, m_Latitude;

double m_RadLo, m_RadLa;

double Ec;

double Ed;

JWD(double longitude, double latitude)

  m_Longitude = longitude;

  m_Latitude = latitude;

      m_RadLo = longitude * PI/180.;

  m_RadLa = latitude * PI/180.;

  Ec = Rj + (Rc - Rj) * (90.-m_Latitude) / 90.;

  Ed = Ec * cos(m_RadLa);

}

~JWD() {};

};

static JWD GetJWDB(JWD A, double x,double y)

double dx=x;

double dy=y;

double BJD = (dx/A.Ed + A.m_RadLo) * 180./PI;

double BWD = (dy/A.Ec + A.m_RadLa) * 180./PI;

JWD B(BJD, BWD);

return B;

void main()

double referla=30.0;

double referlo=60.0;

double dx=500.0;

double dy=60.0;

    JWD A(referla,referlo),B(0.0,0.0);

    B=GetJWDB(A,dx,dy);

cout < < "  LA = " < < B.m_Latitude < < "  LO= " < < B.m_Longitude < < endl;

上面這段與之類似的代碼是最容易通過搜尋引擎找到的。大部分都是互相的轉載,從來沒有說明和注釋。給初學者造成了很大的困擾。特别是:

Ec = Rj + (Rc - Rj) * (90.-m_Latitude) / 90.;

Ed = Ec * cos(m_RadLa);

Ec、Ed這2個參數,有人還在CSDN上發帖詢問“函數中Ec,Ed是什麼意思”。但從來沒有見到有人回答。

提問的連結:

<a href="http://www.gisforum.net/bbs/TopicOther.asp?t=5&amp;BoardID=33&amp;id=155609">http://www.gisforum.net/bbs/TopicOther.asp?t=5&amp;BoardID=33&amp;id=155609</a>

<a href="http://bbs.csdn.net/topics/320024634">http://bbs.csdn.net/topics/320024634</a>

我剛開始接觸這個問題,在中文世界中也隻能搜到這些Ctrl+C 到Ctrl+V的東西。全球最大的中文網際網路上也沒有任何解答。已經明白的人知道很簡單,但初學者肯定很疑惑。更何況現在LBS應用已經非常多了。肯定有非常多的人已經找到了更好的解答方式。 但對于我來說,用最常用的關鍵詞,最容易的找到了這些複制的答案,但疑點重重。本着好奇的心,經過一番了解,我把結果給大家分析一下。下面是C#的代碼:

<a></a>

上面這個函數一看就是懂中文的人搞的,名字叫GetJWDB,取得經緯度。他根據輸入的經度、緯度、距離和一個角度,得到另外一個經緯度坐标,輸出參數為BJD、BWD。

1)angle * Math.PI / 180.0 作用是将角度轉換為弧度,經緯度坐标是角度值,計算時需要換為弧度。這裡所有的計算都是用弧度。

2)函數以正北方(due north) 也就是指南針的方向為0度,順時針方向增加。如下圖,Distance距離如果是d的話,dx就是x軸方向的長度,即longitude經度方向的長度;dy就是y軸方向的長度,即latitude緯度方向的長度。

dx、dy的計算方式也可以是以正東(due east)方向為0度。那:dx=distance* Cos(θ),dy=distance*Sin(θ)。差別是Cos 與Sin互換。(圖上未标)

通過經緯度坐标計算距離的方法(經緯度距離計算)ZZ

圖1

3)Ea 表示赤道半徑,Eb表示極半徑,地球是一個近似球體,Ea與Eb稍微有點差距。ec的作用就是修正因為緯度不斷變化的球半徑長度。如果在GLAT=0,即在赤道上的時候,ec=Eb+(Ea-Eb)*(90-0)/90=Ea,那ec就剛好是赤道半徑Ea;如果在極點GLAT=90,ec=Eb+(Ea-Eb)*(90-90)/90=Eb,那ec 就剛好是極半徑Eb。

4)Ed是GLAT所在緯度的緯度圈的半徑,如下圖:

通過經緯度坐标計算距離的方法(經緯度距離計算)ZZ

圖2

截面過球心,此時截面的面積最大,此圓叫球的大圓(Great Cycle),沿着經線進行截面,得到的都是大圓(Great Cycle)。球面被不經過球心. 的截面所截得的圓. 叫做小圓。緯度圈所在的圓是一個小圓。地球半徑R,平均值R=6371.0Km, Ed如果用地球半徑R表示,那就是Ed=R*Cos(θ),可以參看

5)按照地球經緯度的劃分,如下圖:

每等分的緯度之間,經度線段的長度是一定的。 A段,B段長度是一樣的。

每一等分的經度之間,緯度線段的長度是從赤道向2極點減小的。C端,D段的長度是不一樣的。

通過經緯度坐标計算距離的方法(經緯度距離計算)ZZ

圖3

參看上圖,那dx / ed 就相當于是在GLAT這個緯度上dx長度與總長度的占比,算出來應該是個經度跨度。如果這個經度跨度加上起始給定的經度就是最終的經度。

同理 dy/R就是在GLON這個經度上的dy長度與地球平均半徑R的占比,算出來應該是一個緯度跨度。如果這個緯度跨度加上起始給定的緯度就是最終的緯度。這裡使用了R,取地球平均半徑。

dy/ec 就是用不斷修正的ec半徑替代了平均半徑R。

(dy / ec + GLAT * Math.PI / 180.0) 就是起始緯度加上distance距離的最終緯度,同時需要将該結果轉換為角度。 轉換角度方法是:弧度* 180.0 / Math.PI。

BWD = (dy / ec + GLAT * Math.PI / 180.0) * 180.0 / Math.PI;

(dx / ed + GLON * Math.PI / 180.0)就是起始經度加上distance距離的最終經度,同時需要将該結果轉換為角度。

BJD = (dx / ed + GLON * Math.PI / 180.0) * 180.0 / Math.PI;

這個根據一個經緯度坐标、距離然後求另外一個經緯度坐标的作用,主要就是确定一個最小外包矩形(Minimum bounding rectangle,簡稱MBR)。例如,我要找一個坐标點(lat,lon)的5公裡範圍内的所有商戶資訊、景點資訊等。這個MBR就是一個最大的範圍,這個矩形是包含5公裡範圍内所有這些有效資訊的一個最小矩形。利用公式,求出四個方向0度、90度、180度、270度方向上的四個坐标點就可以得到這個MBR。

這裡得到的maxLatitude, minLatitude, maxLongitude, minLongitude就組成矩形的四個頂點。

網上另外的方法,

<a href="http://www.movable-type.co.uk/scripts/latlong.html">http://www.movable-type.co.uk/scripts/latlong.html</a>

這裡的“Destination point given distance and bearing from start point”一節介紹了。我直接把代碼貼上來:

這裡GetRectRange 這個函數 也是以正北方(due north)為起始角度,順時針方向,求得maxLatitude, minLatitude, maxLongitude, minLongitude 這樣一個MBR。2種方法的誤差很小。我覺得都是可以用的公式。

如果有一個應用,表裡存有100萬的資料,資料包含一個lat、lon的經緯度資訊。就可以先根據輸入的經緯度和距離得到一個MBR,然後通過類似

SELECT Id

FROM IdInfoTable

WHERE latitude &gt;= minLat AND latitude &lt; maxLat

AND longitude &gt;= minLon AND longitude &lt; maxLon

完整代碼:

謹以此文紀念那篇CSDN上因為 “本文章已過去太久遠了,不再提供回複功能。”而永遠至今晚為止都還沒有答案的文章!

如今LBS應用泛濫,JavaScript到處都能看到源碼,gitHub上sourceCode随處可見的時代,希望此文能引導後人,少走我的彎路。如果有更好的方案,也歡迎留言。值此慶祝五一佳節!

本文轉自莫水千流部落格園部落格,原文連結:http://www.cnblogs.com/zhoug2020/p/7634187.html,如需轉載請自行聯系原作者

繼續閱讀