cesium测量功能(一):距离测量

328 阅读3分钟

功能:测量两个经纬度之间的距离

核心类:Cesium.EllipsoidGeodesic

function transformWGS84ToCartographic(position) {
  return position
      ? Cesium.Cartographic.fromDegrees(
          position.lng || position.lon,
          position.lat,
          position.alt
      )
      : Cesium.Cartographic.ZERO;
}
​
function getPositionDistance(positions) {
    /*
  * positions:存储坐标点的数组
  * distance:累加值,用来存储计算出的所有点之间的总距离
  * transformWGS84ToCartographic:将 WGS84 坐标(经纬度高度)转换为 笛卡尔坐标系 下的       Cartographic 坐标
  * Cesium.EllipsoidGeodesic:计算地球椭球表面两点之间的最短距离
  * setEndPoints:将两个点设置为起点和终点,计算这两个点之间的地表距离
  * geodesic.surfaceDistance:获取这两个点之间的表面距离,单位是米
  * */  
  let distance = 0;
  for (let i = 0; i < positions.length - 1; i++) {
    let point1cartographic = transformWGS84ToCartographic(positions[i]);
    let point2cartographic = transformWGS84ToCartographic(
        positions[i + 1]
    );
    let geodesic = new Cesium.EllipsoidGeodesic();
    geodesic.setEndPoints(point1cartographic, point2cartographic);
    let s = geodesic.surfaceDistance;
   //通过勾股定理解决高度差问题,获得三维空间中两点之间的实际直线距离
    s = Math.sqrt(
        Math.pow(s, 2) +
        Math.pow(point2cartographic.height - point1cartographic.height, 2)
    );
    distance = distance + s;
  }
  //保留小数点后三位
  return distance.toFixed(3);
}

实现测量功能:

通过鼠标左键来存储需要测量距离的坐标点,每两个坐标点之间连一条线,第二个坐标标明线的长度,鼠标右键取消测量功能

/*拾取位置点
* 从鼠标点击位置 (px) 对应的笛卡尔坐标 (Cartesian3),
* 并根据点击的位置判断该位置是在3D模型、地形或者地球表面上。
* 具体来说 先通过 drillPick 方法检测点击是否在3D模型或地形上,
* 再根据不同的情况进行坐标转换
* */
function getCatesian3FromPX(px) {
  if (viewer && px) {
    let picks = viewer.scene.drillPick(px);
    let cartesian = null;
    let isOn3dtiles = false,
    isOnTerrain = false;
   //处理3D模型或3D Tiles
    for (let i in picks) {
      let pick = picks[i];
​
      if (
          (pick && pick.primitive instanceof Cesium.Cesium3DTileFeature) ||
          (pick && pick.primitive instanceof Cesium.Cesium3DTileset) ||
          (pick && pick.primitive instanceof Cesium.Model)
      ) {
        isOn3dtiles = true;
      }
    }
    if (isOn3dtiles) {
      viewer.scene.pick(px); // pick
      cartesian = viewer.scene.pickPosition(px);
      if (cartesian) {
        let cartographic = Cesium.Cartographic.fromCartesian(cartesian);
        if (cartographic.height < 0) cartographic.height = 0;
        let lon = Cesium.Math.toDegrees(cartographic.longitude),
            lat = Cesium.Math.toDegrees(cartographic.latitude),
            height = cartographic.height;
        cartesian = transformWGS84ToCartesian({
          lng: lon,
          lat: lat,
          alt: height,
        });
      }
    }
 //处理地形
    let boolTerrain = viewer.terrainProvider instanceof Cesium.EllipsoidTerrainProvider;
    if (!isOn3dtiles && !boolTerrain) {
      let ray =  viewer.scene.camera.getPickRay(px);
      if (!ray) return null;
      cartesian = viewer.scene.globe.pick(ray, viewer.scene);
      isOnTerrain = true;
    }
   //处理地球表面
    if (!isOn3dtiles && !isOnTerrain && boolTerrain) {
      cartesian = viewer.scene.camera.pickEllipsoid(px, viewer.scene.globe.ellipsoid);
    }
    //转换坐标
    if (cartesian) {
      let position = transformCartesianToWGS84(cartesian);
      if (position.alt < 0) {
        cartesian = transformWGS84ToCartesian(position, 0.1);
      }
      return cartesian;
    }
    return false;
​
  }
​
}
    let  positions = [];
     let  lineEntity = new Cesium.Entity();
     let handlers = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas);
    //监听鼠标的左键单击事件,存储点击的坐标点
     handlers.setInputAction(function (event){
        let cartesian = getCatesian3FromPX(event.position);
        if (cartesian && cartesian.x) {
          if (positions.length == 0) {
            positions.push(cartesian.clone());
          }
          // 添加量测信息点
          addPoint(cartesian,cartesian.x,positions);
          positions.push(cartesian);
        }
      },Cesium.ScreenSpaceEventType.LEFT_CLICK)
    //鼠标移动事件:存入新的坐标
     handlers.setInputAction(function (event){
       let cartesian = getCatesian3FromPX(event.endPosition);
       if (positions.length >= 2) {
         if (cartesian && cartesian.x) {
           positions.pop();
           positions.push(cartesian);
         }
       }
     },Cesium.ScreenSpaceEventType.MOUSE_MOVE)
     handlers.setInputAction(function (event){
         //结束鼠标监听事件
       handlers.destroy();
       handlers = null;
       let cartesian = getCatesian3FromPX(event.position);
         //添加点
       addPoint(cartesian,cartesian.x,positions);
     },Cesium.ScreenSpaceEventType.RIGHT_CLICK)
      //添加线
     lineEntity.polyline = {
       width: 5,
       material: Cesium.Color.BLUE.withAlpha(0.8),
       clampToGround: false,
     };
     lineEntity.polyline.positions = new Cesium.CallbackProperty(function () {
       return positions;
     }, false);
     viewer.entities.add(lineEntity)
/***
 * 坐标数组转换 笛卡尔转86
 *
 * @param {Array} cartesianArr 三维位置坐标数组
 *
 * @return {Array} {lng,lat,alt} 地理坐标数组
 */
function transformCartesianArrayToWGS84Array(cartesianArr,viewer) {
    if (viewer) {
        return cartesianArr
            ? cartesianArr.map(function (item) {
                return transformCartesianToWGS84(item,viewer);
            })
            : [];
    }
}
/**
 * 获取84坐标的距离
 * @param {*} positions
 */
function getPositionDistance(positions) {
    let distance = 0;
    for (let i = 0; i < positions.length - 1; i++) {
        let point1cartographic = transformWGS84ToCartographic(positions[i]);
        let point2cartographic = transformWGS84ToCartographic(
            positions[i + 1]
        );
        let geodesic = new Cesium.EllipsoidGeodesic();
        geodesic.setEndPoints(point1cartographic, point2cartographic);
        let s = geodesic.surfaceDistance;
        s = Math.sqrt(
            Math.pow(s, 2) +
            Math.pow(point2cartographic.height - point1cartographic.height, 2)
        );
        distance = distance + s;
    }
    return distance.toFixed(3);
}
function addPoint(pos,id,positions){
  //添加点的实体
  let list = {
    id:id,
    name:'点',
    show:true,
    position:pos,
    point:{
      color:Cesium.Color.GREEN,
      pixelSize:20,
      outlineColor: Cesium.Color.SKYBLUE, //边框颜色
      outlineWidth: 2, //边框宽度
    },
    label:{
      text:
          (
              getPositionDistance(
                  transformCartesianArrayToWGS84Array(positions,data.viewer)
              ) / 1000
          ).toFixed(4) + "公里",
      show: true,
      showBackground: true,
      font: "14px monospace",
      horizontalOrigin: Cesium.HorizontalOrigin.LEFT,
      verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
      pixelOffset: new Cesium.Cartesian2(-10, -10)
    }
  }
  let entity = data.viewer.entities.add(list)
  pageResource.measuringDistanceList.floatModels.push(entity);
  pageResource.measuringDistanceList.floatModelIds.push(list.id);
}

距离测试.jpg