WithCoderWithCoderWithCoder

Cesium中点至直线的垂足点和距离计算

    最近处理GPS定位坐标在Cesium中显示的问题,需要将定位坐标绘制到指定的路线上。但实际的显示结果是,因为定位不准确,最终绘制的GPS坐标基本都是在路线周围乱跳。为了效果好看一点,最终的想法将球面上短距离的路线看作是平面坐标中的直线,将定位坐标通过计算,算出坐标点到直线的垂足点,将垂足点作为最终的定位坐标。

    整理相关 JS 方法如下:

    1. 计算点到直线的垂足点

/**
 * 点到直线的垂足点
 */
function getFootPoint(point, start, end) {
    var A = end.Latitude - start.Latitude; 
    var B = start.Longitude - end.Longitude; 
    var C = end.Longitude * start.Latitude - start.Longitude * end.Latitude; 
    if (A * A + B * B < 1e-13) {
        return start; // start与end重叠
    } else if (Math.abs(A * point.Longitude + B * point.Latitude + C) < 1e-13) {
        return point; // point在直线上(start_end)
    } else {
        var Longitude = (B * B * point.Longitude - A * B * point.Latitude - A * C) / (A * A + B * B);
        var Latitude = (-A * B * point.Longitude + A * A * point.Latitude - B * C) / (A * A + B * B);
        return {
            Longitude: Longitude,
            Latitude: Latitude
        };
    }
}

    2. 计算点到直线的距离(平面坐标

/**
 * 点到直线的距离
 */
function getDistancePoineToLine_planeCoord(point, start, end) {
    var A = end.Latitude - start.Latitude; 
    var B = start.Longitude - end.Longitude;
    var C = end.Longitude * start.Latitude - start.Longitude * end.Latitude;
    if (A * A + B * B < 1e-13) { // pnt1与pnt2重叠
        var dx = point.Longitude - start.Longitude;
        var dy = point.Latitude - start.Latitude;
        return Math.sqrt(dx * dx + dy * dy);
    } else if (Math.abs(A * point.Longitude + B * point.Latitude + C) < 1e-13) {
        return 0; // point在直线上(pnt1_pnt2)
    } else {
        var distance = Math.abs(A * point.Longitude + B * point.Latitude + C) / Math.sqrt(A * A + B * B);
        return distance;
    }
}

    3. 计算点到线的距离(WGS84坐标)

/**
 * 点到线的距离
 */
function getDistance_wgs84(p1_x, p1_y, p2_x, p2_y) {
    var lat1 = p1_x;
    var lon1 = p1_y;
    var lat2 = p2_x;
    var lon2 = p2_y;

    var earch_radius = 6371008.8; // 地球半径 平均值 米
    //用haversine公式计算球面两点间的距离
    //经纬度转换成弧度
    var h_lat1 = lat1 * Math.PI / 180.0;
    var h_lon1 = lon1 * Math.PI / 180.0;
    var h_lat2 = lat2 * Math.PI / 180.0;
    var h_lon2 = lon2 * Math.PI / 180.0;
    //差值
    var vlon = Math.abs(h_lon1 - h_lon2);
    var vlat = Math.abs(h_lat1 - h_lat2);
    //
    var h = HaverSin(vlat) + Math.cos(h_lat1) * Math.cos(h_lat2) * HaverSin(vlon);
    //
    var d = 2 * earch_radius * Math.asin(Math.sqrt(h));
    //
    return d;
}

function HaverSin(theta) {
    var v = Math.sin(theta / 2);
    return v * v;
}

    4. 计算点到线的距离(笛卡尔坐标)

/**
 * 点到线的距离
 */
function getDistanceByPointToLine_Coordinate(point, pnt1, pnt2) {
    var dis = 0;
    if (pnt1.x == pnt2.x) {
        if (pnt1.y == pnt2.y) {
            var dx = point.x - pnt1.x;
            var dy = point.y - pnt1.y;
            dis = Math.sqrt(dx * dx + dy * dy);
        } else
            dis = Math.abs(point.x - pnt1.x);
    } else {
        var lineK = (pnt2.y - pnt1.y) / (pnt2.x - pnt1.x);
        var lineC = (pnt2.x * pnt1.y - pnt1.x * pnt2.y) / (pnt2.x - pnt1.x);
        dis = Math.abs(lineK * point.x - point.y + lineC) / (Math.sqrt(lineK * lineK + 1));
    }

    return dis;
}

    通过上面的方法,将很短距离的球面坐标看做平面坐标,从而计算出点到直线的垂足。最后,使用计算的垂足点再进行处理,经过验证,定位效果基本上符合要求。

欢迎分享交流,转载请注明出处:WithCoder » Cesium中点至直线的垂足点和距离计算