java 经纬度计算

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);
    }
}
 
输入的经度和纬度应该是以度为单位的,输出的距离单位为千米。

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值