原创
MySQL以及Java根据经纬度计算距离
温馨提示:
本文最后更新于 2021年03月31日,已超过 1,345 天没有更新。若文章内的图片失效(无法正常加载),请留言反馈或直接联系我。
球面距离公式
球面距离公式是计算球面上两点间距离的公式。
举个例子:已知,设R为球体半径,点A ,纬度角β1 ,经度角α1 ;点B ,纬度角β2 ,经度角α2。求点A和点B两点间的距离?
公式:S=R·arccos[cosβ1·cosβ·2cos(α1-α2)+sinβ1·sinβ2]
公式参考:球面距离公式
地球半径
地球半径:6371.393千米。
计算坐标点
广州塔,经纬度:113.324553,23.106414
东方明珠电视塔,经纬度:121.499718,31.239703
关于在线经纬度获取的话,可以看看高德地图的:https://lbs.amap.com/tools/picker
Java版本
/**
* 根据球面距离公式计算两个地点之间的距离
*
* <p>公式:S=R·arccos[cosβ1·cosβ·2cos(α1-α2)+sinβ1·sinβ2]
*/
@UtilityClass
public class DistanceUtil {
/** 地球半径(单位:米) */
private static final double EARTH_RADIUS = 6371393;
/** 以度为单位的角度值乘以该常数以获得以弧度为单位的角度值。 */
private static final double DEGREES_TO_RADIANS = 0.017453292519943295;
/**
* 根据公式进行计算
*
* @param longitude1 位置1经度
* @param latitude1 位置1纬度
* @param longitude2 位置2经度
* @param latitude2 位置2纬度
* @return 返回计算的距离,单位:米
*/
public static double getDistance(
Double longitude1, Double latitude1, Double longitude2, Double latitude2) {
double radiansLongitude1 = toRadians(longitude1);
double radiansLatitude1 = toRadians(latitude1);
double radiansLongitude2 = toRadians(longitude2);
double radiansLatitude2 = Math.toRadians(latitude2);
final double cos =
BigDecimal.valueOf(Math.cos(radiansLatitude1))
.multiply(BigDecimal.valueOf(Math.cos(radiansLatitude2)))
.multiply(
BigDecimal.valueOf(
Math.cos(
BigDecimal.valueOf(radiansLongitude1)
.subtract(BigDecimal.valueOf(radiansLongitude2))
.doubleValue())))
.add(
BigDecimal.valueOf(Math.sin(radiansLatitude1))
.multiply(BigDecimal.valueOf(Math.sin(radiansLatitude2))))
.doubleValue();
double acos = Math.acos(cos);
return BigDecimal.valueOf(EARTH_RADIUS).multiply(BigDecimal.valueOf(acos)).doubleValue();
}
/**
* 参考:{@link Math#toRadians(double)}
*
* @param value value
* @return {double}
*/
private static double toRadians(double value) {
return BigDecimal.valueOf(value).multiply(BigDecimal.valueOf(DEGREES_TO_RADIANS)).doubleValue();
}
/**
* 测试
*
* <pre>
* 广州塔,经纬度:113.324553,23.106414
* 东方明珠电视塔,经纬度:121.499718,31.239703
* </pre>
*
* @param args args
*/
public static void main(String[] args) {
double distance = getDistance(113.324553, 23.106414, 121.499718, 31.239703);
System.out.println(distance);
}
}
计算结果(单位:米):
1212391.2574948743
MySQL版本
开始写计算函数
有了前面球面距离计算公式
基础之后,我们就可以一葫芦画瓢写出mysql版的函数了。
创建calculate_distance
函数
这里我将计算距离结果单位设置为米。
CREATE FUNCTION calculate_distance ( longitude1 DOUBLE, latitude1 DOUBLE, longitude2 DOUBLE, latitude2 DOUBLE ) RETURNS DOUBLE
BEGIN
RETURN 6371393 * ACOS(
COS( RADIANS( latitude1 ))
* COS( RADIANS( latitude2 ))
* COS( RADIANS( longitude2 - longitude1 ))
+ SIN( RADIANS( latitude1 ))
* SIN( RADIANS( latitude2 ))
);
END;
说明: MySQL中的RADIANS
函数
将度数值转换为弧度值。
mysql> SELECT RADIANS(180);
+-------------------+
| RADIANS(180) |
+-------------------+
| 3.141592653589793 |
+-------------------+
1 row in set (0.03 sec)
MySQL计算示例
示例sql查询两点的距离,实际情况你可以根据自己数据库中的字段去调整sql,在此我仅仅是演示:
mysql> SELECT calculate_distance(113.324553, 23.106414, 121.499718, 31.239703);
+------------------------------------------------------------------+
| calculate_distance(113.324553, 23.106414, 121.499718, 31.239703) |
+------------------------------------------------------------------+
| 1212391.2574948743 |
+------------------------------------------------------------------+
1 row in set (0.06 sec)
计算结果跟前面Java版本的一样。
结果大概都是1212391米。
对比验证计算结果
注意,以下结果仅供参考!
高德地图验证结果
广州塔到东方明珠电视塔的距离:1213675 米。跟我们公式计算(Java版本&MySQL版本)的误差大概是:1284 米。
百度地图验证结果
广州塔到东方明珠电视塔的距离:1212315.87 米。跟我们公式计算(Java版本&MySQL版本)的误差大概是:75.13 米。
结尾
毕竟这是计算的直线距离,不同的计算方法、坐标系(Sphere坐标系、WGS84坐标系)、精度等等因素都会影响计算的结果。
如果要计算驾车、步行这种分类计算距离的,建议可以去看看使用高德地图、百度地图、腾讯地图的API。
- 本文标签: Java MySQL
- 本文链接: http://www.lzhpo.com/article/171
- 版权声明: 本文由lzhpo原创发布,转载请遵循《署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0)》许可协议授权