Python 经纬度距离计算:从鸿蒙签到案例拆解 Haversine

举报
yd_243677465 发表于 2026/11/12 10:40:03 2026/11/12
【摘要】 浏览鸿蒙开发实践中心的员工签到案例时,看到它使用经纬度和 Haversine 公式判断员工与签到点的距离。下面把其中的距离计算单独拿出来,用 Python 标准库做一个可运行的小实验。本文只验证球面距离函数,没有部署案例中的 App 或后端。 从坐标到距离经纬度的单位通常是度,而三角函数使用弧度。Haversine 先通过两点纬度、经度差计算球面中心角,再乘地球半径,得到沿球面的近似距离。这...

浏览鸿蒙开发实践中心的员工签到案例时,看到它使用经纬度和 Haversine 公式判断员工与签到点的距离。下面把其中的距离计算单独拿出来,用 Python 标准库做一个可运行的小实验。本文只验证球面距离函数,没有部署案例中的 App 或后端。

从坐标到距离

经纬度的单位通常是度,而三角函数使用弧度。Haversine 先通过两点纬度、经度差计算球面中心角,再乘地球半径,得到沿球面的近似距离。这里使用平均半径 6,371,000 米,结果单位为米。真实地球并非完美球体,因此这适合一般距离估算,不能直接当作精密测绘结果。

一个可运行的实现

函数接收两个点,参数顺序为纬度、经度。先拒绝越界坐标和 NaN 等非有限值,再计算中心角。浮点误差有时会使中间值略微越过 0 或 1,因此在开平方前将其约束到有效范围。

from math import asin, cos, isfinite, radians, sin, sqrt

EARTH_RADIUS_M = 6_371_000

def distance_m(lat1, lon1, lat2, lon2):
    values = (lat1, lon1, lat2, lon2)
    if not all(isinstance(v, (int, float)) and not isinstance(v, bool) and isfinite(v) for v in values):
        raise ValueError('坐标必须为有限数字')
    if not (-90 <= lat1 <= 90 and -90 <= lat2 <= 90 and -180 <= lon1 <= 180 and -180 <= lon2 <= 180):
        raise ValueError('纬度应在[-90,90],经度应在[-180,180]')
    p1, p2 = radians(lat1), radians(lat2)
    dp, dl = p2 - p1, radians(lon2 - lon1)
    a = sin(dp / 2) ** 2 + cos(p1) * cos(p2) * sin(dl / 2) ** 2
    return 2 * EARTH_RADIUS_M * asin(sqrt(min(1.0, max(0.0, a))))

if __name__ == '__main__':
    assert distance_m(0, 0, 0, 0) == 0
    assert 111_000 < distance_m(0, 0, 1, 0) < 111_300
    assert abs(distance_m(31.2, 121.5, 30.2, 120.5) - distance_m(30.2, 120.5, 31.2, 121.5)) < 1e-8
    assert 20_000_000 < distance_m(0, 0, 0, 180) < 20_100_000
    for sample in [(91, 0, 0, 0), (0, 181, 0, 0), (float('nan'), 0, 0, 0)]:
        try:
            distance_m(*sample)
            raise AssertionError('invalid coordinates accepted')
        except ValueError:
            pass
    print('7 checks passed')

保存为 distance_demo.py 后用 Python 运行。如果断言全部通过,会输出 7 checks passed。测试覆盖同一点距离为零、赤道附近相差一纬度约 111 公里、交换两点顺序、对跖点,以及三种非法输入。它们能发现单位、参数范围和数值稳定性的常见错误,但不能证明所有输入都正确。

怎样用于签到判断

服务端可先校验签到点配置和员工位置,再比较 distance_m 的返回值与允许半径。要约定边界:例如距离小于或等于 100 米算在范围内;计算过程不要先把距离四舍五入,否则边界附近可能误判。存储时应保留足够精度,并在日志中使用适当的隐私保护措施。

距离接近阈值时,还应考虑定位精度、坐标系差异、位置上报时间和定位权限;坐标缺失或精度不足时,应返回明确提示,而不是默认为签到成功。距离函数也不能独立证明位置真实或取代服务端权限校验。

小结

这个练习把案例里的一个计算点拆成了独立函数:统一单位、校验输入、处理浮点边界,再用可重复的断言检查关键性质。资料来源:华为云鸿蒙开发实践中心《使用 Agent 生成鸿蒙端云一体员工签到 App》;文中 Python 示例为本次独立编写。

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0)

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。