// 判断坐标点是否存在区域内
function isPointInArea(point, area) {
let x = point[0];
let y = point[1];
let isInside = false;
for (let i = 0, j = area.length - 1; i < area.length; j = i++) {
let xi = area[i][0];
let yi = area[i][1];
let xj = area[j][0];
let yj = area[j][1];
let intersect = ((yi > y) != (yj > y)) &&
(x < (xj - xi) * (y - yi) / (yj - yi) + xi);
if (intersect) isInside = !isInside;
}
return isInside;
}
// 获取最短距离的端点坐标
function minDistanceLineSegmentToArea(point, area) {
let minDistance = Infinity;
let isProjectionPoint,startPoint1,endPoint1;
for (let i = 0; i < area.length; i++) {
let startPoint = area[i];
let endPoint = area[(i + 1) % area.length]; // 下一个顶点,形成边
// [是否投影点,点到线段的距离,线段的起始点(若不是投影点则返回 点到线段最短端点的端点坐标)]
const [isProjectionPoint1,distance,startPoint2, endPoint2] = pointToLineDistance(point, startPoint, endPoint);
console.log(point, startPoint, endPoint,distance);
if (distance < minDistance) {
minDistance = distance;
isProjectionPoint= isProjectionPoint1
startPoint1= startPoint2
endPoint1= endPoint2
}
}
// 返回[是否投影点,点到线段的距离,线段的起始点(若不是投影点则返回 点到线段最短端点的端点坐标)]
return [isProjectionPoint,startPoint1,endPoint1];
}
// 计算点到线段之间的距离
function pointToLineDistance(point, segmentStart, segmentEnd) {
let isProjectionPoint = false // 是否投影点
// 计算线段的方向向量
let dx = segmentEnd[0] - segmentStart[0];
let dy = segmentEnd[1] - segmentStart[1];
// 计算点到线段的投影点
let u = ((point[0] - segmentStart[0]) * dx + (point[1] - segmentStart[1]) * dy) / (dx * dx + dy * dy);
let px, py;
if (u <= 0) {
px = segmentStart[0];
py = segmentStart[1];
} else if (u >= 1) {
px = segmentEnd[0];
py = segmentEnd[1];
} else {
px = segmentStart[0] + u * dx;
py = segmentStart[1] + u * dy;
}
// 计算最短距离
let distanceToSegment;
if (u <= 0 || u >= 1) {
// 点在线段外部
let distanceToStart = Math.sqrt(Math.pow(point[0] - segmentStart[0], 2) + Math.pow(point[1] - segmentStart[1], 2));
let distanceToEnd = Math.sqrt(Math.pow(point[0] - segmentEnd[0], 2) + Math.pow(point[1] - segmentEnd[1], 2));
distanceToSegment = Math.min(distanceToStart, distanceToEnd);
segmentStart = distanceToSegment === distanceToStart ? segmentStart:segmentEnd
segmentEnd = distanceToSegment === distanceToStart ? segmentStart:segmentEnd
} else {
isProjectionPoint = true
// 点在线段内部
distanceToSegment = Math.sqrt(Math.pow(point[0] - px, 2) + Math.pow(point[1] - py, 2));
console.log('u:',u);
console.log('---:',point, segmentStart, segmentEnd,distanceToSegment);
}
// 返回 [是否投影点,点到线段的距离,线段的起始点(若不是投影点则返回 点到线段最短端点的端点坐标)]
return [isProjectionPoint,distanceToSegment,segmentStart, segmentEnd];
}
// 计算投影点的坐标
function calculateProjectionPoint(point, segmentStart, segmentEnd) {
let dx = segmentEnd[0] - segmentStart[0];
let dy = segmentEnd[1] - segmentStart[1];
let u = ((point[0] - segmentStart[0]) * dx + (point[1] - segmentStart[1]) * dy) / (dx * dx + dy * dy);
let px = segmentStart[0] + u * dx;
let py = segmentStart[1] + u * dy;
return [px, py];
}
function deg2rad(deg) {
return deg * (Math.PI / 180);
}
function getDistanceFromLatLonInKm( lon1,lat1, lon2,lat2) {
const R = 6371; // 地球半径,单位为千米
const dLat = deg2rad(lat2 - lat1);
const dLon = deg2rad(lon2 - lon1);
const a =
Math.sin(dLat / 2) * Math.sin(dLat / 2) +
Math.cos(deg2rad(lat1)) * Math.cos(deg2rad(lat2)) *
Math.sin(dLon / 2) * Math.sin(dLon / 2);
const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
const distance = R * c; // 单位为千米
return distance;
}
// 示例坐标点和坐标区域
let point = [120.502665,31.60207]; // 坐标点 [纬度, 经度]
let area = [
[120.50161, 31.60445],
[120.501484, 31.607747],
[120.501905, 31.610399],
[120.506745, 31.611654],
[120.507165, 31.610005],
[120.508554, 31.608643],
[120.509943, 31.605919],
[120.512889, 31.604306],
[120.517476, 31.60126],
[120.520506, 31.597209],
[120.513646, 31.597245],
[120.512047, 31.599862],
[120.50948, 31.601654],
[120.505903, 31.603697]
]; // 坐标区域的多个点
let isPointOutArea = !isPointInArea(point, area)
// 坐标点如果在区域内则不用计算距离
if(!isPointOutArea) return
let [isProjectionPoint,segmentStart,segmentEnd] = minDistanceLineSegmentToArea(point, area);
let projectionPoint
if(isProjectionPoint){
// 计算投影点坐标
projectionPoint = calculateProjectionPoint(point, segmentStart, segmentEnd);
}else{
// 将最短距离的端点坐标当作投影点
projectionPoint = segmentStart;
}
// 计算两点之间的距离
const distance = getDistanceFromLatLonInKm(...point,...projectionPoint);
console.log(distance); // 输出两点之间的距离,单位为千米
javascript计算一个坐标点到一个区域的最短距离
于 2024-07-10 10:02:47 首次发布