最近处理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);} elsedis = 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;
}
通过上面的方法,将很短距离的球面坐标看做平面坐标,从而计算出点到直线的垂足。最后,使用计算的垂足点再进行处理,经过验证,定位效果基本上符合要求。