<div class="show-content-free"> <h3>根據經緯度計算距離公式</h3> <div class="image-view" data-width="437" data-height="76"><img data-original-src="//upload-images.jianshu.io/upload_images/2833665-36cf75cbabf61869.png" data-original-width="437" data-original-height="76" data-original-format="image/png" data-original-filesize="14687" class="" style="cursor: zoom-in;" src="//upload-images.jianshu.io/upload_images/2833665-36cf75cbabf61869.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/437/format/webp"></div> <div class="image-caption">公式</div> <p>對上面的公式解釋以下:</p> <ol> <li>Lung1 Lat1表示A點經緯度, Lung2 Lat2表示B點經緯度;</li> <li>a=Lat1 – Lat2 爲兩點緯度之差 b=Lung1 -Lung2 爲兩點經度之差;</li> <li>6378.137爲地球半徑,單位爲公里;</li> <li>計算出來的結果單位爲公里,若將半徑改成米爲單位則計算的結果單位爲米。</li> <li>計算精度與谷歌地圖的距離精度差很少,相差範圍在0.2米如下。</li> </ol> <h3>參數說明</h3> <p>lng:經度<br> lat:緯度<br> 地球半徑:6378.137(公里)</p> <p>通常地圖上顯示的座標順序爲,緯度在前(範圍-90 ~ 90),經度在後(範圍-180 ~ 180)</p> <h3>各類語言計算距離的代碼</h3> <blockquote> <p>這種計算方式通常都是直線距離</p> </blockquote> <p>sql語句</p> <pre class="hljs php"><code class="php">SELECT *, <span class="hljs-number">6378.138</span> * <span class="hljs-number">2</span> * ASIN( SQRT( POW( SIN( ( <span class="hljs-string">'.$lat.'</span> * PI() / <span class="hljs-number">180</span> - lat * PI() / <span class="hljs-number">180</span> ) / <span class="hljs-number">2</span> ), <span class="hljs-number">2</span> ) + COS(<span class="hljs-string">'.$lat.'</span> * PI() / <span class="hljs-number">180</span>) * COS(lat * PI() / <span class="hljs-number">180</span>) * POW( SIN( ( <span class="hljs-string">'.$lng.'</span> * PI() / <span class="hljs-number">180</span> - lng * PI() / <span class="hljs-number">180</span> ) / <span class="hljs-number">2</span> ), <span class="hljs-number">2</span> ) ) ) *<span class="hljs-number">1000</span> <span class="hljs-keyword">AS</span> distance FROM distance ORDER BY distance ASC </code></pre> <p>php計算距離</p> <pre class="hljs php"><code class="php"><span class="hljs-comment">/** * 根據兩點間的經緯度計算距離 * <span class="hljs-doctag">@param</span> $lng1 * <span class="hljs-doctag">@param</span> $lat1 * <span class="hljs-doctag">@param</span> $lng2 * <span class="hljs-doctag">@param</span> $lat2 * <span class="hljs-doctag">@return</span> int */</span> <span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getDistance</span><span class="hljs-params">($lng1, $lat1, $lng2, $lat2)</span> </span>{ <span class="hljs-comment">//將角度轉爲狐度</span> $radLat1 = deg2rad($lat1);<span class="hljs-comment">//deg2rad()函數將角度轉換爲弧度</span> $radLat2 = deg2rad($lat2); $radLng1 = deg2rad($lng1); $radLng2 = deg2rad($lng2); $a = $radLat1 - $radLat2; $b = $radLng1 - $radLng2; $s = <span class="hljs-number">2</span> * asin(sqrt(pow(sin($a / <span class="hljs-number">2</span>), <span class="hljs-number">2</span>) + cos($radLat1) * cos($radLat2) * pow(sin($b / <span class="hljs-number">2</span>), <span class="hljs-number">2</span>))) * <span class="hljs-number">6378.137</span> * <span class="hljs-number">1000</span>; <span class="hljs-keyword">return</span> $s; } </code></pre> <p>js求距離的方法</p> <pre class="hljs javascript"><code class="javascript"><span class="hljs-comment">/** * 轉換弧度 * @param d * @returns {number} */</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getRad</span>(<span class="hljs-params">d</span>)</span>{ <span class="hljs-keyword">var</span> PI = <span class="hljs-built_in">Math</span>.PI; <span class="hljs-keyword">return</span> d*PI/<span class="hljs-number">180.0</span>; }javascript
<span class="hljs-comment">/**php
- 根據經緯度計算兩點間距離
- @param lng1
- @param lat1
- @param lng2
- @param lat2
- @returns {number|*}
- @constructor /</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">CoolWPDistance</span>(<span class="hljs-params">lng1,lat1,lng2,lat2</span>)</span>{ <span class="hljs-keyword">var</span> f = getRad((lat1 + lat2)/<span class="hljs-number">2</span>); <span class="hljs-keyword">var</span> g = getRad((lat1 - lat2)/<span class="hljs-number">2</span>); <span class="hljs-keyword">var</span> l = getRad((lng1 - lng2)/<span class="hljs-number">2</span>); <span class="hljs-keyword">var</span> sg = <span class="hljs-built_in">Math</span>.sin(g); <span class="hljs-keyword">var</span> sl = <span class="hljs-built_in">Math</span>.sin(l); <span class="hljs-keyword">var</span> sf = <span class="hljs-built_in">Math</span>.sin(f); <span class="hljs-keyword">var</span> s,c,w,r,d,h1,h2; <span class="hljs-keyword">var</span> a = <span class="hljs-number">6378137.0</span>;<span class="hljs-comment">//The Radius of eath in meter.</span> <span class="hljs-keyword">var</span> fl = <span class="hljs-number">1</span>/<span class="hljs-number">298.257</span>; sg = sgsg; sl = slsl; sf = sfsf; s = sg*(<span class="hljs-number">1</span>-sl) + (<span class="hljs-number">1</span>-sf)sl; c = (<span class="hljs-number">1</span>-sg)(<span class="hljs-number">1</span>-sl) + sfsl; w = <span class="hljs-built_in">Math</span>.atan(<span class="hljs-built_in">Math</span>.sqrt(s/c)); r = <span class="hljs-built_in">Math</span>.sqrt(sc)/w; d = <span class="hljs-number">2</span>wa; h1 = (<span class="hljs-number">3</span>r <span class="hljs-number">-1</span>)/<span class="hljs-number">2</span>/c; h2 = (<span class="hljs-number">3</span>r +<span class="hljs-number">1</span>)/<span class="hljs-number">2</span>/s; s = d(<span class="hljs-number">1</span> + fl(h1sf(<span class="hljs-number">1</span>-sg) - h2*(<span class="hljs-number">1</span>-sf)*sg)); <span class="hljs-keyword">if</span>(s >= <span class="hljs-number">1000</span> && s <= <span class="hljs-number">99000</span>){ <span class="hljs-keyword">var</span> kilometer = s/<span class="hljs-number">1000</span>; s = kilometer.toFixed(<span class="hljs-number">1</span>) + <span class="hljs-string">'km'</span>; }<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span>(s > <span class="hljs-number">99000</span>){ s = <span class="hljs-string">'>99km'</span>; }<span class="hljs-keyword">else</span>{ s = <span class="hljs-built_in">Math</span>.round(s) + <span class="hljs-string">'m'</span>; } <span class="hljs-comment">// s = s/1000;</span> <span class="hljs-comment">// s = s.toFixed(2);//指定小數點後的位數。</span> <span class="hljs-keyword">return</span> s; }
</code></pre>java
<p>以上代碼大部分來自網上收集,通過驗證過的,可使用</p> <h1>原理</h1> <p>根據兩點經緯度計算距離</p> <p>這些經緯線是怎樣定出來的呢?地球是在不停地繞地軸旋轉(地軸是一根經過地球南北兩極和地球中心的假想線),在地球中腰畫一個與地軸垂直的大圓圈,使圈上的每一點都和南北兩極的距離相等,這個圓圈就叫做「赤道」。</p> <p>在赤道的南北兩邊,畫出許多和赤道平行的圓圈,就是「緯圈」;構成這些圓圈的線段,叫作緯線。咱們把赤道定爲緯度零度,向南向北各爲90度,在赤道以南的叫南緯,在赤道以北的叫北緯。北極就是北緯90度,南極就是南緯90度。緯度的高低也標誌着氣候的冷熱,如赤道和低緯度地地區無冬,兩極和高緯度地區無夏,中緯度地區四季分明。 其次,從北極點到南極點,能夠畫出許多南北方向的與地球赤道垂直的大圓圈,這叫做「經圈」;構成這些圓圈的線段,就叫經線。</p> <p>公元1884平面座標圖年,國際上規定以經過英國倫敦近郊的格林尼治天文臺的經線做爲計算經度的起點,即經度零度零分零秒,也稱「本初子午線」。在它東面的爲東經,共180度;在它西面的爲西經,共180度。由於地球是圓的,因此東經180度和西經180度的經線是同一條經線。各國公定180度經線爲「國際日期變動線」。</p> <p>爲了不同一地區使用兩個不一樣的日期,國際日期變線在遇陸地時略有偏離。 每一經度和緯度還能夠再細分爲60分,每一分再分爲60秒以及秒的小數。利用經緯線,咱們就能夠肯定地球上每個地方的具體位置,而且把它在地圖或地球儀上表示出來。</p> <p>例如問北京的經緯度是多少?咱們很容易從地圖上查出來是東經116度24分,北緯39度54分。在大海中航行的船隻,只要把所在地的經度測出來,就能夠肯定船在海洋中的位置和前進方向。 緯度共有90度。赤道爲0度,向兩極排列,圈子越小,度數越大。橫線是緯度,豎線是經度。<br> 固然能夠計算,四元二次方程。 經度和緯度都是一種角度。經度是個兩面角,是兩個經線平面的夾角。因全部經線都是同樣長,爲了度量經度選取一個起點面,經1884年國際會議協商,決定以經過英國倫敦近郊、泰晤士河南岸的格林尼治皇家天文臺(舊址)的一臺主要子午儀十字絲的那條經線爲起始經線,稱爲本初子午線。</p> <p>本初子午線平面是起點面,終點面是本地經線平面。某一點的經度,就是該點所在的經線平面與本初子午線平面間的夾角。在赤道上度量,自本初子午線平面做爲起點面,分別往東往西度量,往東量值稱爲東經度,往西量值稱爲西<br> 經度。因而可知,一地的經度是該地對於本初子午線的方向和角距離。本初子午線是0°經度,東經度的最大值爲180°,西經度的最大值爲180°,東、西經180°經線是同一根經線,所以不分東經或西經,而統稱180°經線。 緯度是個線面角。起點面是赤道平面,線是本地的地面法線。所謂法線,即垂直於參考扁球體表面的線。某地的緯度就是該地的法線與赤道平面之間的夾角。緯度在本地經線上度量,由赤道向南、北度量,向北量值稱爲北緯度,向南量值稱爲南緯度。因而可知,一地的緯度是該地對於赤道的方向和角距離。赤道是0°緯線,北緯度的最大值爲90°,即北極點;南緯度的最大值爲90°,即南極點。</p> <h1>經緯度互換</h1> <p>度(DDD):E 108.90593度 N 34.21630度</p> <p>如何將度(DDD): 108.90593度換算成度分秒(DMS)東經E 108度54分22.2秒?<br> 轉換方法是將108.90593整數位不變取108(度),用0.90593<em>60=54.3558,取整數位54(分),0.3558</em>60=21.348再取整數位21(秒),故轉化爲108度54分21秒.</p> <p>一樣將度分秒(DMS):東經E 108度54分22.2秒 換算成度(DDD)的方法以下:108度54分22.2秒=108+(54/60)+(22.2/3600)=108.90616度</p> <p>由於計算時小數位保留的緣由,致使正反計算存在必定偏差,但偏差影響不是很大。1秒的偏差就是幾米的樣子。GPS車友能夠用上述方法換算成本身須要的單位座標。</p> <h1>經緯度換算成米</h1> <p>緯度分爲60分,每一分再分爲60秒以及秒的小數。</p> <p>緯度線投射在圖上看似水平的平行線,但其實是不一樣半徑的圓。有相同特定緯度的全部位置都在同一個緯線上。<br> 赤道的緯度爲0°,將行星平分爲南半球和北半球。<br> 緯度是指某點與地球球心的連線和地球赤道面所成的線面角,其數值在0至90度之間。位於赤道以北的點的緯度叫北緯,記爲N,位於赤道以南的點的緯度稱南緯,記爲S。<br> 緯度數值在0至30度之間的地區稱爲低緯地區,緯度數值在30至60度之間的地區稱爲中緯地區,緯度數值在60至90度之間的地區稱爲高緯地區。<br> 赤道、南迴歸線、北迴歸線、南極圈和北極圈是特殊的緯線。<br> 緯度1秒的長度<br> 地球的子午線總長度大約40008km。平均:<br> 緯度1度 = 大約111km<br> 緯度1分 = 大約1.85km<br> 緯度1秒 = 大約30.9m</p> <p>根據地球上任意兩點的經緯度計算兩點間的距離</p> <p>地球是一個近乎標準的橢球體,它的赤道半徑爲6378.140公里,極半徑爲 6356.755公里,平均半徑6371.004公里。若是咱們假設地球是一個完美的球體,那麼它的半徑就是地球的平均半徑,記爲R。若是以0度經線爲基 準,那麼根據地球表面任意兩點的經緯度就能夠計算出這兩點間的地表距離(這裏忽略地球表面地形對計算帶來的偏差,僅僅是理論上的估算值)。設第一點A的經 緯度爲(LonA, LatA),第二點B的經緯度爲(LonB, LatB),按照0度經線的基準,東經取經度的正值(Longitude),西經取經度負值(-Longitude),北緯取90-緯度值(90- Latitude),南緯取90+緯度值(90+Latitude),則通過上述處理事後的兩點被計爲(MLonA, MLatA)和(MLonB, MLatB)。那麼根據三角推導,能夠獲得計算兩點距離的以下公式:</p> <pre class="hljs cpp"><code class="cpp">C = <span class="hljs-built_in">sin</span>(MLatA)*<span class="hljs-built_in">sin</span>(MLatB)*<span class="hljs-built_in">cos</span>(MLonA-MLonB) + <span class="hljs-built_in">cos</span>(MLatA)*<span class="hljs-built_in">cos</span>(MLatB) Distance = R*Arccos(C)*Pi/<span class="hljs-number">180</span> </code></pre> <p>這裏,R和Distance單位是相同,若是是採用6371.004公里做爲半徑,那麼Distance就是公里爲單位,若是要使用其餘單位,好比mile,還須要作單位換算,1公里=0.621371192mile</p> <p>若是僅對經度做正負的處理,而不對緯度做90-Latitude(假設都是北半球,南半球只有澳洲具備應用意義)的處理,那麼公式將是:</p> <pre class="hljs cpp"><code class="cpp">C = <span class="hljs-built_in">sin</span>(LatA)*<span class="hljs-built_in">sin</span>(LatB) + <span class="hljs-built_in">cos</span>(LatA)*<span class="hljs-built_in">cos</span>(LatB)*<span class="hljs-built_in">cos</span>(MLonA-MLonB)git
Distance = R*Arccos(C)*Pi/<span class="hljs-number">180</span> </code></pre>web
<p>以上經過簡單的三角變換就能夠推出。</p> <p>若是三角函數的輸入和輸出都採用弧度值,那麼公式還能夠寫做:</p> <pre class="hljs cpp"><code class="cpp">C = <span class="hljs-built_in">sin</span>(LatA*Pi/<span class="hljs-number">180</span>)*<span class="hljs-built_in">sin</span>(LatB*Pi/<span class="hljs-number">180</span>) + <span class="hljs-built_in">cos</span>(LatA*Pi/<span class="hljs-number">180</span>)*<span class="hljs-built_in">cos</span>(LatB*Pi/<span class="hljs-number">180</span>)*<span class="hljs-built_in">cos</span>((MLonA-MLonB)*Pi/<span class="hljs-number">180</span>)sql
Distance = R*Arccos(C)*Pi/<span class="hljs-number">180</span> </code></pre>數據庫
<p>也就是:</p> <pre class="hljs cpp"><code class="cpp">C = <span class="hljs-built_in">sin</span>(LatA/<span class="hljs-number">57.2958</span>)*<span class="hljs-built_in">sin</span>(LatB/<span class="hljs-number">57.2958</span>) + <span class="hljs-built_in">cos</span>(LatA/<span class="hljs-number">57.2958</span>)*<span class="hljs-built_in">cos</span>(LatB/<span class="hljs-number">57.2958</span>)*<span class="hljs-built_in">cos</span>((MLonA-MLonB)/<span class="hljs-number">57.2958</span>)函數
Distance = R*Arccos(C) = <span class="hljs-number">6371.004</span>Arccos(C) kilometer = <span class="hljs-number">0.621371192</span><span class="hljs-number">6371.004</span>*Arccos(C) mile = <span class="hljs-number">3958.758349716768</span>*Arccos(C) mile </code></pre>ui
<p>在實際應用當中,通常是經過一個個體的郵政編碼來查找該郵政編碼對應的地區中心的經緯度,然 後再根據這些經緯度來計算彼此的距離,從而估算出某些羣體之間的大體距離範圍(好比酒店旅客的分佈範圍-各個旅客的郵政編碼對應的經緯度和酒店的經緯度所 計算的距離範圍-等等),因此,經過郵政編碼查詢經緯度這樣一個數據庫是一個頗有用的資源。</p>編碼
</div>