MySQL中计算两目的地路径上到第三目的地的最近距离
计算Destination3到Destination1-Destination2路径的最短球面距离
这里的“路径”默认指两点之间的大圆线段(而非无限延伸的大圆),需分两种场景计算:
- 当Destination3到路径的垂线落点在Dest1-Dest2线段内时,取垂线距离;
- 当垂线落点在线段外时,取到最近端点(Dest1或Dest2)的距离。
完整SQL实现(考虑线段范围)
以下代码会自动判断场景并返回正确结果,复用了你现有距离计算的逻辑:
$query->selectRaw(" -- 计算三个两两之间的球面弧度距离 @d12 := ACOS(LEAST(1.0, COS(RADIANS(lat2))*COS(RADIANS(lat1))*COS(RADIANS(lng2-lng1)) + SIN(RADIANS(lat2))*SIN(RADIANS(lat1)))), @d13 := ACOS(LEAST(1.0, COS(RADIANS(lat3))*COS(RADIANS(lat1))*COS(RADIANS(lng3-lng1)) + SIN(RADIANS(lat3))*SIN(RADIANS(lat1)))), @d23 := ACOS(LEAST(1.0, COS(RADIANS(lat3))*COS(RADIANS(lat2))*COS(RADIANS(lng3-lng2)) + SIN(RADIANS(lat3))*SIN(RADIANS(lat2)))), -- 计算Dest1到垂线落点的弧长占总路径的比例 @t := (POW(SIN(@d13/2), 2) - POW(SIN((@d23-@d12)/2), 2)) / (SIN(@d12)*SIN(@d13)), -- 生成最终最短距离(单位:公里) 111.111 * DEGREES( IF( @t BETWEEN 0 AND 1, ACOS(COS(@d13) - @t*SIN(@d12)*SIN(@d13)), LEAST(@d13, @d23) ) ) AS closest_distance ");
代码说明
- 两两距离计算:
@d12/@d13/@d23分别是三组点之间的球面弧度距离,逻辑和你现有代码一致; - 落点判断:
@t的取值范围0<=t<=1代表垂线落点在Dest1-Dest2线段内; - 距离计算:
- 落点在线段内时,用球面三角公式计算垂线距离;
- 落点在线段外时,直接取到最近端点的距离;
- 单位转换:
111.111是将弧度距离转为公里的系数,若需英里可替换为69.0。
简化版(仅考虑整个大圆路径)
如果不需要限制路径为线段(允许最短距离落在Dest1/Dest2的延长线上),可使用更简洁的垂线距离公式:
$query->selectRaw(" 111.111 * DEGREES( ASIN( LEAST(1.0, SIN(ACOS(LEAST(1.0, COS(RADIANS(lat3))*COS(RADIANS(lat1))*COS(RADIANS(lng3-lng1)) + SIN(RADIANS(lat3))*SIN(RADIANS(lat1))))) * SIN(ACOS(LEAST(1.0, COS(RADIANS(lat2))*COS(RADIANS(lat1))*COS(RADIANS(lng2-lng1)) + SIN(RADIANS(lat2))*SIN(RADIANS(lat1))))) - ACOS(LEAST(1.0, COS(RADIANS(lat3))*COS(RADIANS(lat2))*COS(RADIANS(lng3-lng2)) + SIN(RADIANS(lat3))*SIN(RADIANS(lat2)))) ) ) ) AS closest_distance ");
内容的提问来源于stack exchange,提问作者sabansaulic
相关产品推荐
相关产品推荐

