1. 计算两点(经纬度)之间的距离(km/公里)
public class DistanceCalculator {
private static final double EARTH_RADIUS = 6371.0; // 地球半径,单位 km
public static double calculateDistance(double lat1, double lon1, double lat2, double lon2) {
// 将经纬度转换为弧度
double radLat1 = Math.toRadians(lat1);
double radLon1 = Math.toRadians(lon1);
double radLat2 = Math.toRadians(lat2);
double radLon2 = Math.toRadians(lon2);
// 使用余弦定理计算距离
double distance = Math.acos(Math.sin(radLat1) * Math.sin(radLat2)
+ Math.cos(radLat1) * Math.cos(radLat2) * Math.cos(radLon2 - radLon1)) * EARTH_RADIUS;
// 返回距离,单位 km
return distance;
}
public static void main(String[] args) {
double lat1 = 31.2304;
double lon1 = 121.4737;
double lat2 = 39.9042;
double lon2 = 116.4074;
double distance = calculateDistance(lat1, lon1, lat2, lon2);
System.out.println("Distance: " + distance + " km");
}
}
2. 点到直线的距离
可以使用 Haversine 公式计算两点之间的球面距离(即地球表面上的距离),然后用三角形余弦定理计算出点到线段的直线距离。
public static double haversine(double lat1, double lon1, double lat2, double lon2) {
double R = 6371; // 地球半径,单位为千米
double dLat = Math.toRadians(lat2 - lat1);
double dLon = Math.toRadians(lon2 - lon1);
double a = Math.sin(dLat / 2) * Math.sin(dLat / 2) +
Math.cos(Math.toRadians(lat1)) * Math.cos(Math.toRadians(lat2)) *
Math.sin(dLon / 2) * Math.sin(dLon / 2);
double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
double distance = R * c;
return distance;
}
这个函数可以计算出两个点之间的球面距离(单位为千米),输入的经度和纬度应该是以度为单位的。
然后我们需要计算出点到线段的垂足坐标,可以使用向量的法线公式得到
public static double[] perpendicularFoot(double lat, double lon,
double lat1, double lon1, double lat2, double lon2) {
double[] p1 = {lat1, lon1};
double[] p2 = {lat2, lon2};
double[] p = {lat, lon};
double[] v1 = Vector.sub(p, p1);
double[] v2 = Vector.sub(p2, p1);
double t = Vector.dot(v1, v2) / Vector.dot(v2, v2);
double[] foot = Vector.add(p1, Vector.mult(v2, t));
return foot;
}
其中 `Vector` 是一个向量计算的工具类,可以定义如下:
public class Vector {
public static double[] sub(double[] a, double[] b) {
return new double[] {a[0] - b[0], a[1] - b[1]};
}
public static double[] add(double[] a, double[] b) {
return new double[] {a[0] + b[0], a[1] + b[1]};
}
public static double[] mult(double[] a, double c) {
return new double[] {a[0] * c, a[1] * c};
}
public static double dot(double[] a, double[] b) {
return a[0] * b[0] + a[1] * b[1];
}
public static double[] normalize(double[] a) {
double norm = Math.sqrt(a[0] * a[0] + a[1] * a[1]);
return new double[] {a[0] / norm, a[1] / norm};
}
public static double[] perpendicular(double[] a) {
return new double[] {-a[1], a[0]};
}
}
最后,我们可以计算出点到线段的距离:
public static double pointToSegmentDistance(double lat, double lon,
double lat1, double lon1, double lat2, double lon2) {
double[] foot = perpendicularFoot(lat, lon, lat1, lon1, lat2, lon2);
double distance = haversine(lat, lon, foot[0], foot[1]);
double[] pv = Vector.sub(foot, new double[]{lat, lon});
double[] v1 = Vector.sub(new double[]{lat2, lon2}, new double[]{lat1, lon1});
double[] v2 = Vector.sub(new double[]{lat, lon}, new double[]{lat1, lon1});
double dot_product = Vector.dot(pv, Vector.normalize(v1));
if (dot_product >= 0 && dot_product <= Vector.dot(v1, v1)) {
// 垂足点在线段上
return distance;
} else {
// 垂足点不在线段上,取点到两个端点的距离中的最小值
double dist1 = haversine(lat, lon, lat1, lon1);
double dist2 = haversine(lat, lon, lat2, lon2);
return Math.min(dist1, dist2);
}
}
输入的经度和纬度应该是以度为单位的,输出的距离单位为千米。