utils/Screen.js

import { Cesium } from '../../namespace'
/**
 * 地图场景相关方法集
 * @module Screen
 */

/**
 * 返回点集的范围,默认弧度:[west, south, east, north]
 * @method
 * @param {Array<Cartesian3>} points 点集,笛卡尔坐标
 * @param {Boolean} degrees 是否返回值为经纬度,true-返回值为经纬度值;false-返回值为弧度值
 * @returns {Array<Number>} 四至范围 => [west, south, east, north]
 */
export const getExtent = (points, degrees) => {
  let west = 100000000
  let south = 100000000
  let east = -100000000
  let north = -100000000
  for (let i = 0; i < points.length; i++) {
    const cartographic = Cesium.Cartographic.fromCartesian(points[i])

    const { longitude, latitude } = cartographic
    west = Math.min(longitude, west)
    south = Math.min(latitude, south)
    east = Math.max(longitude, east)
    north = Math.max(latitude, north)
  }
  if (degrees) {
    west = Cesium.Math.toDegrees(west)
    south = Cesium.Math.toDegrees(south)
    east = Cesium.Math.toDegrees(east)
    north = Cesium.Math.toDegrees(north)
  }

  return [west, south, east, north]
}

// 获取中心点
export function getCenter(viewer) {
  const scene = viewer.scene
  const target = pickCenterPoint(scene)
  let bestTarget = target

  const globe = scene.globe
  const cartographic = scene.camera.positionCartographic.clone()
  const height = globe.getHeight(cartographic)
  cartographic.height = height || 0
  bestTarget = Cesium.Ellipsoid.WGS84.cartographicToCartesian(cartographic)
  const result = formatPosition(bestTarget)
  // 获取地球中心点世界位置  与  摄像机的世界位置  之间的距离
  const distance = Cesium.Cartesian3.distance(
    bestTarget,
    scene.camera.positionWC
  )
  result.cameraZ = distance
  return result
}

function pickCenterPoint(scene) {
  const canvas = scene.canvas
  const center = new Cesium.Cartesian2(
    canvas.clientWidth / 2,
    canvas.clientHeight / 2
  )
  const ray = scene.camera.getPickRay(center)
  const target = scene.globe.pick(ray, scene)
  return target || scene.camera.pickEllipsoid(center)
}

function formatPosition(position) {
  const cartographic = Cesium.Cartographic.fromCartesian(position)
  const result = {}
  result.y = formatNum(Cesium.Math.toDegrees(cartographic.latitude), 6)
  result.x = formatNum(Cesium.Math.toDegrees(cartographic.longitude), 6)
  result.z = formatNum(cartographic.height, 2)
  return result
}

function formatNum(num, digits) {
  return Number(num.toFixed(digits || 0))
}

function getScreenCenter(viewer) {
  const result = viewer.camera.pickEllipsoid(
    new Cesium.Cartesian2(
      viewer.canvas.clientWidth / 2,
      viewer.canvas.clientHeight / 2
    )
  )
  const curPosition = Cesium.Ellipsoid.WGS84.cartesianToCartographic(result)
  const lon = (curPosition.longitude * 180) / Math.PI
  const lat = (curPosition.latitude * 180) / Math.PI
  return { x: lon, y: lat }
}

// 切换场景模式
export function changeSV23D(viewer, type) {
  const result = getCenter(viewer)
  const curPosition = getScreenCenter(viewer)
  const center = Cesium.Cartesian3.fromDegrees(curPosition.x, curPosition.y)
  if (type === 'sceneView') {
    viewer.scene.screenSpaceCameraController.enableTilt = true
    let x = -90
    let pitch
    const handle3d = () => {
      x += 1
      pitch = viewer.camera.pitch
      if (pitch < -0.6981317007977318) {
        tilesTransform(viewer, getNavigationCenter(viewer), true)
      } else {
        viewer.scene.preUpdate.removeEventListener(handle3d)
        viewer.camera.lookAtTransform(Cesium.Matrix4.IDENTITY)
      }
    }
    viewer.scene.preUpdate.addEventListener(handle3d)
  } else {
    let pitch
    let x = -Cesium.Math.toDegrees(Math.abs(viewer.camera.pitch))
    const handle2d = () => {
      x -= 1
      pitch = viewer.camera.pitch
      if (pitch > -1.5533430342749532) {
        tilesTransform(viewer, getNavigationCenter(viewer), false)
      } else {
        const result = getCenter(viewer)
        viewer.scene.preUpdate.removeEventListener(handle2d)
        viewer.camera.lookAt(
          center,
          new Cesium.HeadingPitchRange(0, pitch, result.cameraZ)
        )
        viewer.camera.lookAtTransform(Cesium.Matrix4.IDENTITY)
        viewer.scene.screenSpaceCameraController.enableTilt = false
      }
    }
    viewer.scene.preUpdate.addEventListener(handle2d)
  }
}

function tilesTransform(viewer, cartesian0, isUp) {
  const camera = viewer.scene.camera
  const mag = Cesium.Cartesian3.magnitude(cartesian0)
  const radii = Cesium.Cartesian3.fromElements(
    mag,
    mag,
    mag,
    new Cesium.Cartesian3()
  )
  const newEllipsoid = Cesium.Ellipsoid.fromCartesian3(
    radii,
    new Cesium.Ellipsoid()
  )
  viewer.scene._screenSpaceCameraController._rotateFactor = 1.0
  viewer.scene._screenSpaceCameraController._rotateRateRangeAdjustment = 1.0
  camera.constrainedAxis = Cesium.Cartesian3.UNIT_Z
  const oldTransform = Cesium.Matrix4.clone(
    camera.transform,
    new Cesium.Matrix4()
  )
  const verticalTransform = Cesium.Transforms.eastNorthUpToFixedFrame(
    cartesian0,
    newEllipsoid,
    new Cesium.Matrix4()
  )
  camera._setTransform(verticalTransform)
  if (isUp) {
    camera.rotateUp(camera.pitch > -0.4 ? 0 : 0.05)
  } else {
    camera.rotateDown(0.05)
  }
  camera._setTransform(oldTransform)
}

function getNavigationCenter(viewer) {
  const scene = viewer.scene
  //获取地图导航操作中心
  const x = scene.canvas.clientWidth / 2
  const y = scene.canvas.clientHeight / 2
  const pick1 = new Cesium.Cartesian2(x, y)
  const ray = scene.camera.getPickRay(pick1)
  const cartesian0 = scene.globe.pick(ray, scene)
  return cartesian0
}