用 Python 计算两点距离:坐标签到的输入校验与边界
阅读鸿蒙开发实践中心的“使用 Agent 生成鸿蒙端云一体员工签到 App”案例时,我注意到一个容易忽略的环节:位置签到最终要把两个经纬度转换成距离,再与允许半径比较。本文用 Python 标准库单独实现一个球面距离示例,帮助理解这一步的边界;这不是对原案例后端实现的复现,也没有部署该案例。
先明确输入与单位
经度范围是 -180 到 180 度,纬度范围是 -90 到 90 度。函数返回距离,单位是米。球面模型把地球简化为半径约 6371 千米的球体,适合教学和粗略距离估计;精确测量需要考虑地球椭球模型、坐标系和设备精度。
一个可运行的距离函数
下面的实现使用 Haversine 公式。先验证输入为有限数值,再将角度转为弧度,最后计算球面大圆距离。对中间变量夹在 0 到 1 的范围内,是为了避免浮点舍入让平方根或反三角函数遇到越界值。
from math import asin, cos, isfinite, radians, sin, sqrt
EARTH_RADIUS_M = 6_371_000
def distance_m(lat1, lon1, lat2, lon2):
coordinates = (lat1, lon1, lat2, lon2)
if not all(isinstance(v, (int, float)) and not isinstance(v, bool) and isfinite(v) for v in coordinates):
raise ValueError("coordinates must be finite numbers")
if not (-90 <= lat1 <= 90 and -90 <= lat2 <= 90 and -180 <= lon1 <= 180 and -180 <= lon2 <= 180):
raise ValueError("latitude or longitude out of range")
a1, a2 = radians(lat1), radians(lat2)
dlat, dlon = radians(lat2 - lat1), radians(lon2 - lon1)
a = sin(dlat / 2) ** 2 + cos(a1) * cos(a2) * sin(dlon / 2) ** 2
return 2 * EARTH_RADIUS_M * asin(sqrt(min(1.0, max(0.0, a))))
做几个小检查
相同坐标的距离应为 0;赤道附近纬度相差 1 度约为 111 千米;交换起点与终点,距离应相同;无效纬度与 NaN 应被拒绝。本地运行这五项断言均通过。示例不依赖网络,也不采集任何人的位置。
把这个函数用于签到逻辑时,还要单独校验半径为非负有限数,并约定边界点(例如距离等于半径时)如何处理。设备定位存在误差,不能把计算出的米数当成绝对精度;实际业务应记录定位时间和精度,必要时给用户重新定位或人工复核的途径。身份鉴权、定位数据最小化和安全传输也需要在完整系统中处理。
参考阅读:华为云鸿蒙开发实践中心《使用 Agent 生成鸿蒙端云一体员工签到 App》。本文代码为独立的小型演示。
- 点赞
- 收藏
- 关注作者
评论(0)