最短路

101 阅读1分钟

startPoint和endPoint是地图上选中的起点和终点,有经纬度和高度信息。 noFlyPositions是多个多边形的geoJSON格式数组。

function getNoDangerRoadNew(startPoint, endPoint) {
  const lineSegment = turf.lineString([
    [startPoint.lng, startPoint.lat],
    [endPoint.lng, endPoint.lat]
  ])
  let insectPolygon
  for (let i = 0; i < noFlyPositions.length; i++) {
    const polygon = turf.polygon([noFlyPositions[i]])
    if (turf.booleanIntersects(lineSegment, polygon)) {
      insectPolygon = polygon
      break
    }
  }
  if (!insectPolygon) { return [] }
  // 目前只支持凸多边形
  // turf.convex(insectPolygon)
  const start = turf.point([startPoint.lng, startPoint.lat])
  const end = turf.point([endPoint.lng, endPoint.lat])
  const pointsAll = turf.explode(insectPolygon)
  pointsAll.features.push(start, end)
  const polygonNew = turf.convex(pointsAll)
  
  // 提取多边形的顶点
  const vertices = JSON.parse(JSON.stringify(polygonNew.geometry.coordinates[0]))
  vertices.pop()

  // 查找起始点和终点的索引
  const startIdx = vertices.findIndex(pt => turf.booleanEqual(turf.point(pt), start))
  const endIdx = vertices.findIndex(pt => turf.booleanEqual(turf.point(pt), end))

  const clockwisePath = []
  const counterClockwisePath = []
  if (startIdx < endIdx) {
    // 计算顺时针路径
    for (let i = startIdx; i <= endIdx; i++) {
      clockwisePath.push(vertices[i % vertices.length]) // 顺时针
    }
    // 计算逆时针路径
    for (let i = startIdx; i + vertices.length >= endIdx; i--) {
      counterClockwisePath.push(vertices[(i + vertices.length) % vertices.length]) // 逆时针
    }
  } else {
    // 计算顺时针路径
    for (let i = startIdx; i - vertices.length <= endIdx; i++) {
      clockwisePath.push(vertices[i % vertices.length]) // 顺时针
    }
    // 计算逆时针路径
    for (let i = startIdx; i >= endIdx; i--) {
      counterClockwisePath.push(vertices[i % vertices.length]) // 逆时针
    }
  }
  
  const clockwiseLine = turf.lineString(clockwisePath)
  const counterClockwiseLine = turf.lineString(counterClockwisePath)

  // 计算两条线段的长度
  const clockwiseLength = turf.length(clockwiseLine)
  const counterClockwiseLength = turf.length(counterClockwiseLine)
  const selectedLine = clockwiseLength < counterClockwiseLength ? clockwisePath : counterClockwisePath
  const centroid = turf.centroid(polygonNew)
  
  // 添加绕过效果
  for (let i = 1; i < selectedLine.length - 1; i++) {
    const vertexPoint = turf.point(selectedLine[i])
    selectedLine[i] = getDest(centroid, vertexPoint)
  }
  // 添加上升过程
  const flyLine = []
  flyLine.push(addAltToVertex(selectedLine[0], startPoint.alt))
  for (let i = 0; i < selectedLine.length; i++) {
    const tmpPoint = addAltToVertex(selectedLine[i], startPoint.alt + 100)
    flyLine.push(tmpPoint)
  }
  flyLine.push(addAltToVertex(selectedLine[selectedLine.length - 1], endPoint.alt))
  return flyLine
}

//添加高度到经纬度数据中
function addAltToVertex(vertex, height) {
  return [vertex[0], vertex[1], height]
}

//求延长线上0.3km的点
function getDest(centroid, vertexPoint) {
  const distance = 0.3
  const bearing = turf.bearing(centroid, vertexPoint)
  const extendedPoint = turf.destination(vertexPoint, distance, bearing)
  return extendedPoint.geometry.coordinates
}