farhan reza

在建置以位置為基礎的網路應用程式時,開發者通常預設使用 Haversine 公式來計算兩個 GPS 座標之間的距離和方位角。對大多數應用程式而言,假設地球是完美球體已經「足夠好」了。

但是,如果你正在建置一個應用程式,其絕對精確度是不可妥協的呢?

在建置 Quranbookk 的朝拜指南針——一個幫助全球穆斯林找到麥加克爾白確切方向的網路應用程式——時,我很快發現標準球面數學會引入不可接受的誤差範圍。

以下是我捨棄 Haversine 公式,以及如何使用 Next.js 和 Karney 的測地線演算法實作亞毫米級精確度解決方案的原因。

Haversine 公式的問題

Haversine 公式計算地球表面上的最短距離,但它假設地球是完美球體。實際上,地球是一個扁球體(赤道較寬、兩極較扁平)。

當從全球各地計算朝向麥加的方位角時(例如從北美或北歐),這種「球體假設」可能導致數度誤差。當建置一個宗教工具,用戶依賴絕對準確度時,偏離幾度對使用者體驗和信任而言是重大的失敗。

引入 Karney 的測地線演算法

為了解決這個問題,我改用 WGS84 橢球體模型,採用 Charles Karney 的測地線演算法。Karney 的演算法計算橢球體表面兩點之間的最短路徑,而非在完美球體上畫線。

數學複雜度顯著提高,涉及橢圓積分,但結果是方位角和距離計算準確至毫米以下的誤差範圍。

在 Next.js 中實作

由於我正在建置現代網路平台,效能至關重要。我使用 Next.js 15 App Router 建置應用程式。

為了在不膨脹客戶端套件的情況下處理繁重的計算,繁重的測地線計算可以動態處理。對於客戶端,我使用了 HTML5 Geolocation API 結合 DeviceOrientation 事件來讀取裝置的磁力計。

// A simplified conceptual approach
import { Geodesic } from 'geographiclib-geodesic';

export function calculatePreciseBearing(lat, lng, destinationLat, destinationLng) {
  const geod = Geodesic.WGS84; 
  const r = geod.Inverse(lat, lng, destinationLat, destinationLng);

  // r.azi1 gives the precise forward azimuth (bearing)
  return r.azi1; 
}

Enter fullscreen mode Exit fullscreen mode

結果

透過結合 Karney 的演算法與 Next.js 的邊緣效能,最終的指南針極為輕量,完全在瀏覽器中執行(無需下載行動應用程式),並提供超越大多數原生應用程式的數學精確度。

如果你正在建置位置關鍵型應用程式,請停止預設使用 Haversine。數學稍難一些,但精確度值得。如果你想查看即時實作,請前往我的平台: 朝拜指南針 - Quranbookk