大圆公式

在地球表面上,大圆航线是两点之间最短距离的路径,它总是沿着穿过地球中心的一个大圆弧。Haversine公式是一种用于计算两个球面上两点之间最短弧长(也就是大圆距离)的方法,能够确保计算的是沿着地球表面的最短路径。在航空和导航领域,它经常用于计算飞行路径上两个地点之间的最短距离,这就是所谓的大圆航线。

Haversine公式的一般形式如下:

1
2
3
a = sin²(Δlat/2) + cos(lat1) * cos(lat2) * sin²(Δlon/2)
c = 2 * atan2(√a, √(1-a))
d = R * c

其中:

  • Δlat和Δlon分别是两个点的纬度和经度差异。
  • lat1和lat2分别是两个点的纬度。
  • R是地球的半径,通常使用平均半径,约为6371千米(或3959英里)。
  • d是两点之间的大圆距离。

通过Haversine公式,你可以计算两个地点之间的大圆距离,这对于飞行路径规划和导航非常有用。注意,这个公式基于球面几何,忽略了地球的不规则性,但在大多数情况下提供了足够的准确性。如果需要更高精度的计算,还可以使用更复杂的椭球模型或地理信息系统(GIS)工具。

泰国Phanak岛乘船拍摄的风景

代码实现

网站公告栏的“欢迎信息”中,通过IP获取到访问者的地理位置(经纬度、国家、城市),在后台通过一个函数计算出和站长的距离,显示在页面上(感谢 Fomalhaut🥝 提供的 魔改教程vercel-thinkjs (kxyr.top) 提供的API)

在目前上线版本fomal.js文件中,配置的公式如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function getDistance(e1, n1, e2, n2) {
const R = 6371
const {sin, cos, asin, PI, hypot} = Math
let getPoint = (e, n) => {
e *= PI / 180
n *= PI / 180
return {x: cos(n) * cos(e), y: cos(n) * sin(e), z: sin(n)}
}

let a = getPoint(e1, n1)
let b = getPoint(e2, n2)
let c = hypot(a.x - b.x, a.y - b.y, a.z - b.z)
let r = asin(c / 2) * 2 * R
return Math.round(r);
}

这个getDistance函数计算两个地球表面上的点之间的距离,这两个点由它们的经度(e)和纬度(n)坐标指定。使用的公式是haversine公式,它提供两点之间的大圆距离,这是地球表面上的最短距离。

下面是代码的解释:

  • R 是地球的半径(以千米为单位)。
  • sin, cos, asin, PI, hypot 是从 Math 对象中提取出来的,便于使用。
  • 局部函数 getPoint 将经度和纬度从度转换为弧度,并计算地球表面上的3D笛卡尔坐标 (x, y, z),因为Math库中的三角函数接受的参数单位是弧度。
  • 使用getPoint 函数将两个坐标值转换成 ab 是两个点的3D坐标,使用hypot函数计算3D空间中两个点之间的欧几里得距离 c
  • 使用asin函数将欧氏距离转换为大圆距离r,并将其与2倍的地球半径R相乘,得到haversine公式计算的球面距离 r
  • 使用Math.round方法将距离 r 四舍五入到最近的千米。

虽然经度和纬度的值可以是负数(例如,南纬和西经的坐标),但是这个getDistance函数在计算两点之间的距离时不会返回负值。它使用的haversine公式和欧几里得距离都是基于两点之间的绝对距离计算的,结果总是非负的。

在这个函数中,经度和纬度被转换为弧度,并且用来计算两点在地球上的3D笛卡尔坐标。然后,使用hypot函数计算这两个点在3D空间中的直线距离。hypot函数计算的是两点之间的直线距离,是一个绝对值,所以不会是负数。

自2023年10月7日起,博客改为使用 IP-API.com 提供的API,其官方的 说明文档 中,给出了该公式的另一种代码实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
function getDistanceFromLatLonInKm(lat1, lon1, lat2, lon2) {
var R = 6371; // Radius of the earth in km
var dLat = deg2rad(lat2-lat1); // deg2rad below
var dLon = deg2rad(lon2-lon1);
var a =
Math.sin(dLat/2) * Math.sin(dLat/2) +
Math.cos(deg2rad(lat1)) * Math.cos(deg2rad(lat2)) *
Math.sin(dLon/2) * Math.sin(dLon/2);
var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
var d = R * c; // Distance in km
return d;
}

function deg2rad(deg) {
return deg * (Math.PI/180)
}

这个 getDistanceFromLatLonInKm 函数也是计算两个地球表面上的点之间的距离(以千米为单位),和之前的函数类似,但是这个函数直接使用了 haversine 公式。以下是它的工作方式:

  • R 是地球的半径(以千米为单位)。
  • dLatdLon 分别是两个纬度和经度之间的差值,并且转换为弧度。
  • a 是haversine公式的一部分,它使用三角函数来计算两点之间的圆上距离的平方。
  • c 是两点之间的圆心角。
  • d 是两点之间的实际距离,用千米为单位。
  • deg2rad 函数,将度数转换为弧度。

这个函数使用的各个数学运算(如 Math.sin, Math.cos, Math.sqrtMath.atan2)都是针对距离和角度计算的,它们的结果或者是非负的(如平方根或三角函数的结果),或者是通过进一步的计算转化为非负的(如通过 Math.atan2 计算的 c 以及最终的 d)。

现实生活中的航线

海上航行的航线选择取决于多种因素,包括但不限于距离、预计的航行时间、海洋和气象条件、潮流、风速风向、以及可能的危险区域等。这些因素可能影响船只是否选择直接沿大圆航线或其他路径航行。

1. 大圆航线

在理想的情况下,当仅考虑两点之间的最短距离时,船只通常会选择大圆航线作为航行路径,因为它代表了两点之间的最短物理距离。现代的航海导航系统,比如GPS和其他相关技术,可以实时计算并调整船只沿大圆航线的航行方向。然而,仅仅选择物理上的最短距离并不总是最高效或最安全的航线。

2. 沿着纬度航行

在某些情况下,船只可能选择沿着一个特定纬度航行。这种方式在历史上比较常见,尤其是在尚未拥有现代导航技术的时代。沿着纬度线(也称为“平行线”)航行技术上更为简单,可以通过观察天体(如太阳和星星)来保持船只的航线。然而,除非目标地点刚好在同一纬度上,否则这种方法通常不是最短的航行路径。

实际上,在现代海上航行中,船舶的航线通常是基于多种因素、通过专业的航路规划软件和经验丰富的船长或导航员共同决策的结果。大圆航线或许提供一个理论上的最短路径,但船舶可能因应各种实际的海上条件和其他考虑进行适时的航线调整。

3. 六分仪

六分仪是一个用于测量两个物体之间角度的仪器,通常用于测量星体(比如太阳或星星)相对于水平线的角度。在航海中,六分仪用于天文导航,帮助船只确定其经纬度,进而找到准确的地理位置。所以,六分仪不是仅用于沿纬度航行的工具,它是一个用于测量角度和确定位置的工具。

参考视频:航海定位的天才设计,六分仪的工作原理!

六分仪通常包括以下主要部分:

  1. 框架(Frame):通常呈半圆形或四分之一圆形,上面标有度数刻度,度数范围通常是0到120度。
  2. 主镜(Index Mirror):这是一个小镜子,安装在一个可旋转的臂(指数臂)上。它用于反射观察者视线中的对象,如太阳或星星。
  3. 人字臂(Index Arm):这个臂长且可移动,用来调整主镜的角度。
  4. 地平镜(Horizon Mirror):另一个半透镜,反射水平线到观察者的视线中。
  5. 望远镜(Telescope):观察者通过望远镜看物体和反射在两个镜子上的影像。
  6. 滤光片(Shades):滤光片用于观测太阳,以防视线受损。

基本使用步骤如下:

  1. 调整仪器:在使用六分仪之前,通常需要进行一些基本的校准,以确保准确的测量。这可能包括调整镜子的角度,确保六分仪的各部分清洁,以及设置滤光片等。
  2. 测量角度:将望远镜对准一个天体(例如太阳或星星),然后移动指数臂,直到地平镜中的水平线映像和主镜中的天体映像对齐。在这个位置,你可以在六分仪的刻度上读取天体和地平线之间的角度。
  3. 记录数据:记录下测量到的角度和测量的确切时间。使用这些数据和天文表,可以计算观察者的地理位置。
  4. 确定位置:根据测得的角度和确切的时间(通常使用航海钟)来查找天文表(例如年度的《天文学年历》),确定观察者的精确位置。如果测量的是天体与水平线的角度,则这些数据通常用来计算纬度。若要计算经度,还需要知道观测时的格林尼治标准时间。

在航海历史上,六分仪的使用方式通常如下:

  • 确定纬度:通过测量中天时太阳离水平线的角度,船长可以确定船只的纬度。因为当太阳达到其在天空中的最高点(即中天)时,它所在的纬度就是观测位置的纬度。
  • 确定经度:需要知道格林尼治的准确时间,通过比较格林尼治时间和本地时间,船长可以计算出与格林尼治的经度差。这个计算在引入精确的航海钟后变得更加准确和可行。

六分仪在现代已经不是航海定位的主要工具,因为全球定位系统(GPS)提供了一个更快捷、准确的定位方法。然而,六分仪仍然作为备用工具在某些情况下(例如GPS系统失效时)被使用,并且它在航海教育和培训中仍然占有一席之地,用于教育和训练船员传统的航海技能。

简而言之,船只的实际航线会基于多种因素来决定,并不总是简单的选择大圆航线或沿着某一纬度航行。现代航海已经能够利用各种高科技工具,包括卫星导航、海洋气象数据和计算机辅助航路规划系统,以优化航线、提高安全性和效率。