坐标距离计算

坐标距离计算

横纬竖经,经线连接南北两极,纬度是与赤道平行的闭合线圈。经度最高180°,纬度最高90°

纬度:北纬为正(+),南纬为负(-)。赤道为0度。

经度:东经为正(+),西经为负(-)。本初子午线(0度)和180度经线为分界线

书写上是先纬后经

东经2°20’14’‘,北纬48°50’11’‘,西经 77°03’56’‘,北纬 38°55’17’’
统一转成度
function du(h,m,s){
if(h < 0){
m = - m
s = -s
}
du= h + m/60 + s/3600
return du
}

l1 = du(-2,20,14)
p1= du(48, 50, 11)

l2 = du(77,03,56)
p2 = du(38,55,17)

低精度Haversine公式,看作球体半径6371km
public class Haversine {
 
    // 地球半径(单位:公里)
    private static final int r = 6371;
 
    /**
     * 计算两个经纬度坐标点之间的距离(单位:公里)
     * @param lat1 点1的纬度
     * @param lon1 点1的经度
     * @param lat2 点2的纬度
     * @param lon2 点2的经度
     * @return 两点之间的距离(单位:公里)
     */
    public static double jiSuan(double lat1, double lon1, double lat2, double lon2) {
        // 将经纬度从度数转换为弧度
        double lat1Rad = Math.toRadians(lat1);
        double lon1Rad = Math.toRadians(lon1);
        double lat2Rad = Math.toRadians(lat2);
        double lon2Rad = Math.toRadians(lon2);
 
        // 计算经度差和纬度差
        double dLon = lon2Rad - lon1Rad;
        double dLat = lat2Rad - lat1Rad;
 
        // 应用Haversine公式
        double a = Math.pow(Math.sin(dLat / 2), 2)
                + Math.cos(lat1Rad) * Math.cos(lat2Rad) * Math.pow(Math.sin(dLon / 2), 2);
        double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
        double distance = r * c;
 
        return distance;
    }
}

高精度Vincenty公式,地球当成椭球

public class Vincenty {
 
    // WGS84椭球参数
    private static final double A = 6378137.0;     // 长半轴 (单位:米)
    private static final double F = 1 / 298.257223563; // 扁率
    private static final double B = A * (1 - F);       // 短半轴
 
    /**
     * 计算两个经纬度坐标点之间的距离(单位:米)
     * @param lat1 点1的纬度(度数)
     * @param lon1 点1的经度(度数)
     * @param lat2 点2的纬度(度数)
     * @param lon2 点2的经度(度数)
     * @return 两点之间的距离(单位:米)
     */
    public static double calculateDistance(double lat1, double lon1, double lat2, double lon2) {
        double L = Math.toRadians(lon2 - lon1);
        double U1 = Math.atan((1 - F) * Math.tan(Math.toRadians(lat1)));
        double U2 = Math.atan((1 - F) * Math.tan(Math.toRadians(lat2)));
        double sinU1 = Math.sin(U1);
        double cosU1 = Math.cos(U1);
        double sinU2 = Math.sin(U2);
        double cosU2 = Math.cos(U2);
 
        double lambda = L;
        double lambdaP;
        double iterLimit = 100;
        double sinLambda;
        double cosLambda;
        double sinSigma;
        double cosSigma;
        double sigma;
        double sinAlpha;
        double cosSqAlpha;
        double cos2SigmaM;
        double C;
        double deltaSigma;
 
        do {
            sinLambda = Math.sin(lambda);
            cosLambda = Math.cos(lambda);
            sinSigma = Math.sqrt((cosU2 * sinLambda) * (cosU2 * sinLambda) +
                    (cosU1 * sinU2 - sinU1 * cosU2 * cosLambda) * (cosU1 * sinU2 - sinU1 * cosU2 * cosLambda));
            if (sinSigma == 0) {
                return 0; // 两点重合
            }
            cosSigma = sinU1 * sinU2 + cosU1 * cosU2 * cosLambda;
            sigma = Math.atan2(sinSigma, cosSigma);
            sinAlpha = cosU1 * cosU2 * sinLambda / sinSigma;
            cosSqAlpha = 1 - sinAlpha * sinAlpha;
            cos2SigmaM = cosSigma - 2 * sinU1 * sinU2 / cosSqAlpha;
            if (Double.isNaN(cos2SigmaM)) {
                cos2SigmaM = 0; // 防止NaN
            }
            C = F / 16 * cosSqAlpha * (4 + F * (4 - 3 * cosSqAlpha));
            lambdaP = lambda;
            lambda = L + (1 - C) * F * sinAlpha *
                    (sigma + C * sinSigma * (cos2SigmaM + C * cosSigma * (-1 + 2 * cos2SigmaM * cos2SigmaM)));
            iterLimit--;
        } while (Math.abs(lambda - lambdaP) > 1e-12 && iterLimit > 0);
 
        if (iterLimit <= 0) {
            return Double.NaN; // 迭代未收敛
        }
 
        double uSq = cosSqAlpha * (A * A - B * B) / (B * B);
        double A2 = 1 + uSq / 16384 * (4096 + uSq * (-768 + uSq * (320 - 175 * uSq)));
        double B2 = uSq / 1024 * (256 + uSq * (-128 + uSq * (74 - 47 * uSq)));
        deltaSigma = B2 * sinSigma * (cos2SigmaM + B2 / 4 * (cosSigma * (-1 + 2 * cos2SigmaM * cos2SigmaM) -
                B2 / 6 * cos2SigmaM * (-3 + 4 * sinSigma * sinSigma) * (-3 + 4 * cos2SigmaM * cos2SigmaM)));
        double s = B * A2 * (sigma - deltaSigma);
 
        return s;
    }
 

判断一个点是否在多边形区域内-射线法

public class GeoPointInPolygon {
 
    /**
     * 判断经纬度点是否在多边形内(射线法)
     * @param polygon 多边形顶点列表(按顺序排列,可闭合可不闭合)
     * @param testPoint 待测经纬度点
     * @return true表示点在多边形内,false表示点在多边形外
     */
    public static boolean isPointInPolygon(double[][] polygon, double[] testPoint) {
        int n = polygon.length;
        boolean inside = false;
 
        for (int i = 0, j = n - 1; i < n; j = i++) {
            double[] p1 = polygon[i];
            double[] p2 = polygon[j];
 
            // 检查边是否与射线相交
            if (((p1[1] > testPoint[1]) != (p2[1] > testPoint[1])) &&
                (testPoint[0] < (p2[0] - p1[0]) * (testPoint[1] - p1[1]) / (p2[1] - p1[1]) + p1[0])) {
                inside = !inside;
            }
        }
 
        return inside;
    }
 
    public static void main(String[] args) {
        // 定义多边形顶点(按顺序排列,可闭合可不闭合)
        double[][] polygon = {
            {116.3974, 39.9093}, // 顶点1(经度, 纬度)
            {116.3974, 39.9151}, // 顶点2
            {116.4148, 39.9151}, // 顶点3
            {116.4148, 39.9093}  // 顶点4(闭合多边形时可不写,但写上也无妨)
        };
 
        // 待测经纬度点
        double[] pointInside = {116.4061, 39.9121};   // 在多边形内(故宫)
        double[] pointOutside = {116.4061, 39.9251};  // 在多边形外
        double[] pointOnEdge = {116.3974, 39.9151};   // 在多边形边上
 
        // 判断点是否在多边形内
        System.out.println("点 (116.4061, 39.9121) 是否在多边形内: " + isPointInPolygon(polygon, pointInside));
        System.out.println("点 (116.4061, 39.9251) 是否在多边形内: " + isPointInPolygon(polygon, pointOutside));
        System.out.println("点 (116.3974, 39.9151) 是否在多边形内: " + isPointInPolygon(polygon, pointOnEdge));
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值