Haversine公式
该公式通过考虑地球的曲率,能够较为准确地估算两点间的大圆距离。以下是Java实现代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
|
public class DistanceCalculator {
public static void main(String[] args) {
// 示例:计算北京和上海之间的距离
double lat1 = 39.9042; // 北京纬度
double lon1 = 116.4074; // 北京经度
double lat2 = 31.2304; // 上海纬度
double lon2 = 121.4737; // 上海经度
double distance = calculateDistance(lat1, lon1, lat2, lon2);
System.out.println("距离: " + distance + " 公里");
}
/**
* 使用Haversine公式计算两个经纬度点之间的距离
* @param lat1 第一个点的纬度(十进制度数)
* @param lon1 第一个点的经度(十进制度数)
* @param lat2 第二个点的纬度(十进制度数)
* @param lon2 第二个点的经度(十进制度数)
* @return 两点之间的距离,单位为公里
*/
public static double calculateDistance(double lat1, double lon1, double lat2, double lon2) {
final int EARTH_RADIUS = 6371000; // 地球平均半径,单位:公里
// 将十进制度数转换为弧度
double lat1Rad = Math.toRadians(lat1);
double lon1Rad = Math.toRadians(lon1);
double lat2Rad = Math.toRadians(lat2);
double lon2Rad = Math.toRadians(lon2);
// 计算纬度和经度的差值
double deltaLat = lat2Rad - lat1Rad;
double deltaLon = lon2Rad - lon1Rad;
// Haversine公式计算
double a = Math.pow(Math.sin(deltaLat / 2), 2)
+ Math.cos(lat1Rad) * Math.cos(lat2Rad)
* Math.pow(Math.sin(deltaLon / 2), 2);
double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
return EARTH_RADIUS * c;
}
}
|
代码说明:
单位处理: 输入参数为十进制度数(例如:39.9042°N),计算结果以米为单位。
Haversine公式步骤:
将经纬度转换为弧度。
计算纬度和经度的差值(Δφ和Δλ)。
应用公式计算角距离(a和c)。
最终距离由地球半径乘以角距离得出。
精度说明: 公式假设地球为完美球体,实际地球为椭球,因此存在微小误差(通常小于0.5%)。
此方法适用于大多数需要快速估算地理距离的场景,如地理位置服务、导航应用等。
使用 Geodesy 库(基于 Vincenty 公式)
Geodesy 库支持更复杂的椭球模型(如 WGS84),适合高精度场景。需要先添加依赖:
Maven 依赖:
1
2
3
4
5
|
<dependency>
<groupId>org.gavaghan</groupId>
<artifactId>geodesy</artifactId>
<version>1.1.3</version>
</dependency>
|
运行 HTML
Java 代码示例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
import org.gavaghan.geodesy.*;
public class GeodesyDistance {
public static void main(String[] args) {
// 初始化坐标点(纬度, 经度)
GlobalPosition beijing = new GlobalPosition(39.9042, 116.4074, 0);
GlobalPosition shanghai = new GlobalPosition(31.2304, 121.4737, 0);
// 使用 Vincenty 公式计算距离(单位:米)
GeodeticCalculator geoCalc = new GeodeticCalculator();
Ellipsoid reference = Ellipsoid.WGS84; // 使用 WGS84 椭球模型
double distance = geoCalc.calculateGeodeticCurve(reference, shanghai, beijing).getEllipsoidalDistance();
System.out.println("距离: " + distance / 1000 + " 公里");
}
}
|
关键点:
精度更高:Vincenty 公式在椭球模型下的误差通常小于 1毫米。
椭球模型选择:支持多种标准(如 Ellipsoid.WGS84、Ellipsoid.GRS80)。
异常处理:当两点几乎是“对跖点”(antipodal)时可能不收敛,需捕获 ArithmeticException。
GeoTools 是一个功能强大的 GIS 工具库,支持复杂的地理空间操作。需要添加依赖:
Maven 依赖:
1
2
3
4
5
|
<dependency>
<groupId>org.geotools</groupId>
<artifactId>gt-main</artifactId>
<version>25.0</version>
</dependency>
|
运行 HTML
Java 代码示例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
import org.geotools.referencing.GeodeticCalculator;
import org.geotools.referencing.crs.DefaultGeographicCRS;
public class GeoToolsDistance {
public static void main(String[] args) throws Exception {
// 初始化 GeodeticCalculator(默认使用 WGS84 坐标系)
GeodeticCalculator geoCalc = new GeodeticCalculator(DefaultGeographicCRS.WGS84);
// 设置起点(北京)
geoCalc.setStartingGeographicPoint(116.4074, 39.9042);
// 设置终点(上海)
geoCalc.setDestinationGeographicPoint(121.4737, 31.2304);
// 获取距离(单位:米)
double distance = geoCalc.getOrthodromicDistance();
System.out.println("距离: " + distance / 1000 + " 公里");
}
}
|
关键点:
默认坐标系:DefaultGeographicCRS.WGS84 是标准经纬度坐标系。
更多功能:支持方位角计算、坐标投影转换等高级操作。
性能优化:适合处理大规模地理数据。
方法对比
| 方法 |
精度 |
效率 |
复杂度 |
适用场景 |
| Haversine |
0.5% 误差 |
极高 |
简单 |
快速估算,小范围距离计算 |
| Geodesy (Vincenty) |
毫米级 |
高 |
中等 |
高精度测量(如测绘、导航) |
| GeoTools |
高 |
中 |
复杂 |
GIS 系统、复杂地理分析 |