Cesium空间分析-通视分析

进入正题,前段时间做了一个通视分析的功能。

功能很简单:给定“观察点”与“目标点”,判断两点之间是否有“阻碍点”,并能够计算出阻碍点。效果如下图:

实现思路:仍然是“分而治之”,将观察点与被观察点连成的线段,分割成无限多的小段。获取每一段端点的实际高程值,与线段上该点的理论高程值。比较二者大小。若 实际高程值>理论高程值,则不通视,且理论高程值为障碍点。

技术关键点:(1)将线段分割为很多小段,并获取每一段的端点。

(2)线段上的点,需要同时获取屏幕坐标和真实世界坐标

tip:结果的准确性,取决于分割的颗粒度。

最新的规则要求博文有字数限制。

没办法,凑一点字数吧。希望后续我也能更新更多的三维相关的文章。

字数还不够?凑字君上线。聊一聊我最近做的功能吧:视频投放(简陋版)、点、线、填充绘制、飞行(flyTo)、粒子特效。但这些功能都有素材,所以不想写啦。

实现代码:

private sightline(startWorldPoint: Cesium.Cartesian3,
    endWorldPoint: Cesium.Cartesian3):Cesium.Cartesian3{
    let barrierPoint:Cesium.Cartesian3 = Cesium.Cartesian3.ZERO;
    // const startWorldPoint = pickCartesian(this.viewer,startPoint).cartesian;
    // const endWorlePoint = pickCartesian(this.viewer,endPoint).cartesian;
    // console.log("start:" +startWorldPoint )
    // console.log("end:" +endWorlePoint )
    const startPoint = convertCartesian3ToCartesian2(this.viewer,startWorldPoint);
    const endPoint = convertCartesian3ToCartesian2(this.viewer,endWorldPoint);
    const worldLength = calculateSpatialDistance(startWorldPoint,endWorldPoint);
    const windowLength = calculateWindowDistance(startPoint,endPoint);
    const worldInterval = worldLength/100.0;
    const windowInterval = windowLength/100.0;
    for(let i = 1; i< 100; i++){
      const tempWindowPoint = findWindowPositionByPixelInterval(startPoint,endPoint,windowInterval*i);
      const tempPoint = findCartesian3ByDistance(startWorldPoint,endWorldPoint,worldInterval * i);
      const surfacePoint = pickCartesian(this.viewer,tempWindowPoint);
 
      const tempRad = Cesium.Cartographic.fromCartesian(tempPoint);
      const surfaceRad = Cesium.Cartographic.fromCartesian(surfacePoint.cartesian);
               
      if(surfaceRad.height >  tempRad.height){
        barrierPoint = tempPoint;
        break;
      }
    }
    return barrierPoint;
  }

export function convertCartesian3ToCartesian2(viewer:Cesium.Viewer,position:Cesium.Cartesian3):Cesium.Cartesian2{
  return Cesium.SceneTransforms.wgs84ToWindowCoordinates(viewer.scene,position)
}

export function calculateSpatialDistance(
  startPoint: Cesium.Cartesian3,
  endPoint: Cesium.Cartesian3
):number{
  return Math.sqrt(Math.pow(endPoint.x - startPoint.x,2) + Math.pow(endPoint.y - startPoint.y,2) +Math.pow(endPoint.z - startPoint.z,2) );
}

export function calculateWindowDistance(startPoint: Cesium.Cartesian2,endPoint: Cesium.Cartesian2):number{
  return Math.sqrt(Math.pow(endPoint.y - startPoint.y,2) + Math.pow(endPoint.x - startPoint.x,2));
}

export function findWindowPositionByPixelInterval(startPosition:Cesium.Cartesian2,endPosition:Cesium.Cartesian2,interval:number):Cesium.Cartesian2{
  const result = new Cesium.Cartesian2(0,0);
  const length = Math.sqrt(Math.pow(endPosition.x - startPosition.x,2) + Math.pow(endPosition.y - startPosition.y,2));
  if(length< interval){
    return result;
  }else{
    const x = (interval/length)*(endPosition.x - startPosition.x) + startPosition.x;
    //alert(interval/length)
    const y = (interval/length)*(endPosition.y - startPosition.y) + startPosition.y;
    result.x = x;
    result.y = y;
  }
  return result;
}

export function findCartesian3ByDistance(startPosition:Cesium.Cartesian3,endPosition:Cesium.Cartesian3,interval:number):Cesium.Cartesian3{
  const result = new Cesium.Cartesian3(0,0,0);
  const length = Math.sqrt(Math.pow(endPosition.z-startPosition.z,2)+Math.pow(endPosition.x - startPosition.x,2) + Math.pow(endPosition.y - startPosition.y,2));
  if(length< interval){
    return result;
  }else{
    const x = (interval/length)*(endPosition.x - startPosition.x) + startPosition.x;
    //alert(interval/length)
    const y = (interval/length)*(endPosition.y - startPosition.y) + startPosition.y;
    const z = (interval/length)*(endPosition.z - startPosition.z) + startPosition.z;
    result.x = x;
    result.y = y;
    result.z = z;
  }
  return result;
}

export function pickCartesian(viewer:Cesium.Viewer,windowPosition:Cesium.Cartesian2):PickResult{
  //根据窗口坐标,从场景的深度缓冲区中拾取相应的位置,返回笛卡尔坐标。
  const cartesianModel = viewer.scene.pickPosition(windowPosition); 
  //场景相机向指定的鼠标位置(屏幕坐标)发射射线
  const ray = viewer.camera.getPickRay(windowPosition);
  //获取射线与三维球相交的点(即该鼠标位置对应的三维球坐标点,因为模型不属于球面的物体,所以无法捕捉模型表面)
  const cartesianTerrain = viewer.scene.globe.pick(ray,viewer.scene);

  const result = new PickResult();
  if(typeof(cartesianModel) !== 'undefined' && typeof(cartesianTerrain) !== 'undefined'){
    result.cartesian = cartesianModel || cartesianTerrain;
    result.CartesianModel = cartesianModel;
    result.cartesianTerrain = cartesianTerrain as Cesium.Cartesian3;
    result.windowCoordinates = windowPosition.clone();
    //坐标不一致,证明是模型,采用绝对高度。否则是地形,用贴地模式。
    result.altitudeMode = cartesianModel.z.toFixed(0) !== cartesianTerrain!.z.toFixed(0) ? Cesium.HeightReference.NONE:Cesium.HeightReference.CLAMP_TO_GROUND;
  }
  return result;
}

  • 2
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值