事實上,地球上任意兩個坐標點在地平線上的距離並不是直線,而是球面的弧線。
下面介紹如何利用正矢公式計算已知經緯度數據的兩個坐標點之間的距離。半正矢公式也成為Haversine公式,它最早時航海學中的重要公式,其原理是將地球看作圓形,利用公式來計算圓形表面上任意兩個點之間的弧線距離。
Haversine公式中與本項目有關的公式為:
相關符號解釋如下:
d : 兩點之間的弧線總距離
r : 球體的半徑
Q1,Q2: 第一個和第二個坐標點的緯度(需要將角度轉換為弧度表示)
y1,y2 : 第一個和第二個坐標點的經度(需要將角度轉換為弧度表示)
看個例子:
HTML5運動數據記錄頁面的設計與實現:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>跑步記錄功能的設計與實現</title>
<style>
div {
text-align: left;
margin: auto;
padding: 10px;
}
.center {
text-align: center
}
</style>
</head>
<body>
<h3>跑步記錄功能的設計與實現</h3>
<hr />
<div>
<h4>您的當前狀態</h4>
<ul>
<li>
開始時間:<span id="start_time"></span>
</li>
<li>
完成時間:<span id="end_time"></span>
</li>
<li>
總距離:<span id="distance">0</span>km
</li>
</ul>
<h4>詳細信息</h4>
<ul>
<li>
經度:<span id="long"></span>°
</li>
<li>
緯度:<span id="lat"></span>°
</li>
<li>
位置精確度:<span id="acc"></span>
</li>
<li>
海拔高度:<span id="alt">0</span>m
</li>
<li>
速度:<span id="speed">0</span>m/s
</li>
</ul>
<div class="center">
<button id="btn" onclick="toggleBtn()">
開始記錄
</button>
</div>
</div>
<script>
//前一次獲取的經度
var oldLong;
//前一次獲取緯度
var oldLat;
//最新獲取的經度
var currentLong;
//最新獲取的緯度
var currentLat;
//獲取地理位置
function getLocation() {
if (navigator.geolocation) {
var watchID = navigator.geolocation.watchPosition(showPosition, showError, options);
} else {
alert("對不起,您的瀏覽器不支持HTML5地理定位API");
}
}
//回調函數,用於接收獲取的經緯度以及描述信息
function showPosition(position) {
//更新經緯度數據
if (currentLong != null && currentLat != null) {
oldLong = currentLong;
oldLat = currentLat;
}
currentLong = position.coords.longitude;
currentLat = position.coords.latitude;
alert(currentLong + "," + currentLat);
//更新經度
var long = document.getElementById("long");
long.innerHTML = currentLong;
//更新緯度
var lat = document.getElementById("lat");
lat.innerHTML = currentLat;
//更新位置精確度
var acc = document.getElementById("acc");
acc.innerHTML = position.coords.accuracy;
//更新海拔高度
var alt = document.getElementById("alt");
alt.innerHTML = position.coords.altitude;
//更新速度
var speed = document.getElementById("speed");
speed = position.coords.speed;
//更新運動距離
if (oldLat != null && oldLong != null) {
//計算本次運行的距離
var d = getDistance(currentLat, currentLong, oldLat, oldLong);
//獲取頁面上目前的總距離
var lastDistance = document.getElementById("distance").innerHTML;
alert(d);
//將總距離加上本次運動的距離,再更新到頁面上
document.getElementById("distance").innerHTML = parseFloat(lastDistance) + d;
}
}
//回調函數,用於接收獲取失敗時的錯誤代碼
function showError(error) {
switch(error.code) {
case error.PERMISSION_DENIED:
alert("用戶拒絕了地理定位的請求。");
break;
case error.POSITION_UNAVAILABLE:
alert("位置信息不可用。");
break;
case error.TIMEOUT:
alert("請求超時。");
break;
case error.UNKNOWN_ERROR:
alert("未知錯誤發生。");
break;
}
}
//定位參數設置
var options = {
enableHighAccuracy : true,
timeout : 2000,
maximunAge : 2000
};
//當前運動狀態,true為正在運動,false為沒有運動
var isRunning = false;
//顯示運動開始時間的<span>對象
var start_time = document.getElementById("start_time");
//顯示運動結束時間的<span>對象
var end_time = document.getElementById("end_time");
function toggleBtn() {
var btn = document.getElementById("btn");
//開始運動
if (!isRunning) {
//獲取當前時間對象
var now = new Date();
//更新開始時間信息
start_time.innerHTML = now.toLocaleString();
//清空結束時間信息
end_time.innerHTML = "";
//更新運動狀態為true,表示正在運動
isRunning = true;
//更新按鈕上的文字內容
btn.innerHTML = "完成記錄";
//運動總距離清零
document.getElementById("distance").innerHTML = "0";
//開始定位
getLocation();
}
//結束運動
else {
//更新運動狀態為false,表示結束運動
isRunning = false;
//更新按鈕上的文字內容
btn.innerHTML = "開始記錄";
//獲取當前時間對象
var now = new Date();
//更新結束時間信息
end_time.innerHTML = now.toLocaleString();
}
}
//角度轉換為弧度
function toRadians(degree) {
return degree * Math.PI / 180;
}
//計算兩個坐標點之間的距離
function getDistance(lat1, long1, lat2, long2) {
// 地球的半徑(單位:公里)
var R = 6371;
//角度轉換為弧度
var deltaLat = toRadians(lat2 - lat1);
var deltaLong = toRadians(long2 - long1);
lat1 = toRadians(lat1);
lat2 = toRadians(lat2);
//計算過程
var h = Math.sin(deltaLat / 2) * Math.sin(deltaLat / 2) + Math.cos(lat1) * Math.cos(lat2) * Math.sin(deltaLong / 2) * Math.sin(deltaLong / 2);
//求距離
var d = 2 * R * Math.asin(Math.sqrt(h));
return d;
}
</script>
</body>
</html>
HTML5運動數據記錄頁面的設計與實現: