cesium property实现飞行实时姿态仿真

7 篇文章 6 订阅
4 篇文章 2 订阅

先上效果吧,实现了飞行过程中的head朝向,pitch俯仰角的动态线性调整。由于zz敏感,把仿真地区的地图给隐藏了,显得有点暗。将就看吧。更关注我的公众号,查看效果。

        cesium中有多种类型的property,通过它可以实现各种不同的动态变化过度效果,从接口文档中汇总,我们可以看到property有以下几种类别的property。property的作用是让的设置的value随时间变化。value可以是各种cesium内置的类型或其他基本类型。他是根据addSample()来设置各个时间下的所对应的value。按照下图中的分类,本文使用的是基本property类型,本文会对这些基本类型进行介绍,其他的property类型,等博主做出更有趣的例子后再讲解。

这里设置飞行姿态变化,主要使用的是基本property类型的SampledProperty和timeIntervalCollectionProperty进行了实践。

SampledProperty:用来通过给定多个不同时间点的Sample,然后在每两个时间点之间进行线性插值的一种Property。他的表现效果是呈现线性变化的,比如下面BOX 的高度变化过程:

value的类型可以是Number、Cartesians2、Cartesians3等很多数值相关的类型,比如我们这里将其设置为4元数来Cesium.Quaternion 见代码41。通过addsample来设置不同时间的姿态,见代码130和159。

TimeIntervalCollectionProperty: 他表示的效果是随时间跳跃性的,构造方法的选项自然也不一样,拿创建的盒子示例来说,表现出来的特点就是盒子尺寸的变化是跳跃式的。效果如下:

CompositeProperty: 用于组合property的效果,可以把多种不同类型的ConstantProperty、SampleProperty、TimeIntervalCollectionProperty等Property组合在一起来操作。比如前一个时间段需要线性运动,后一段时间再跳跃式运动。

ConstantProperty:表示value不会随时间变化,但是并不代表不可改变,property可以通过setvalue来实现value的变化。

上面的介绍图,借鉴了网上大佬的博客,暂时找不到当时的地址了,如有侵犯,请见谅。

    以上就是对基本property类型的简介,我们通过下面的代码可以看到,例子中还有使用了SampledPositionProperty,它是指位置的变化,使用方式同上面的property类似。

        对以上property有了一定的认识之后,要实现飞行姿态模拟仿真的动态变化的思路如下:

1、通过手工设置或者起点、终点间插值实现飞行路线所经过的点,本文通过插值计算。

2、计算相邻点间的飞行时间

3、计算相邻点间起点到下一点的朝向(head),俯仰角(pitch)和旋转角(roll本实例未添加)

4、在相应点通过addsample()添加姿态信息。具体姿态变化效果看你选择的是哪种property,比如sampledProperty过渡会更自然,timeInterval会跳跃式显示,效果相对不够平滑。

具体实现代码如下


import {
  getSiteTimes,
  courseAngle,
  coursePitchAngle,
} from "@/utils/cesiumjs/cesiumUtils";
function createfly(positions) {
      let viewer = this.viewer;
      let siteobj = getSiteTimes(positions, 1);
      var start = Cesium.JulianDate.fromDate(new Date());
      var stop = Cesium.JulianDate.addSeconds(
        start,
        siteobj.timeSum,//时间数组
        // 100000,
        new Cesium.JulianDate()
      );
      //Make sure viewer is at the desired time.
      viewer.clock.startTime = start.clone();
      viewer.clock.stopTime = stop.clone();
      viewer.clock.currentTime = start.clone();
      viewer.clock.clockRange = Cesium.ClockRange.LOOP_STOP; //Loop at the end
      viewer.clock.multiplier = 10;
      viewer.timeline.zoomTo(start, stop);
      //设置进攻路径
      let startp = Cesium.Cartesian3.fromDegrees(
        120.709006,
        22.752524,
        48603.6642
      );
      let endp = Cesium.Cartesian3.fromDegrees(
        121.094252,
        23.457862,
        36909.212
      );
      // let positions = generateCurve(startp,endp)

      // 飞机初始姿态
      // var ori = changeEntityMat(-60,-60,200,[positions[0].x,positions[0].y])
      // 位置信息的property
      var pathPosition = new Cesium.SampledPositionProperty();
      // 姿态property
      var oriProp = new Cesium.SampledProperty(Cesium.Quaternion);
      // var oriProp= new Cesium.TimeIntervalCollectionProperty()

      var entityPath = viewer.entities.add({
        id: "plane" + positions[0].x,
        position: pathPosition,
        name: "path",
        path: {
          show: true,
          leadTime: 0,
          trailTime: 60,
          width: 10,
          resolution: 1,
          material:
            // new PolylineTrailLinkMaterialProperty(
            //     Cesium.Color.BLUE,
            //     5000,
            //     flowMater
            // )
            new Cesium.PolylineGlowMaterialProperty({
              glowPower: 0.3,
              taperPower: 0.3,
              color: Cesium.Color.PALEGOLDENROD,
            }),
        },
        model: {
          uri: "./model/Cesium_Air.glb",
          minimumPixelSize: 64,
          // maximumScale: 200,
          // color:Cesium.Color.NAVY,
          // scale:0.3,
        },
        orientation: oriProp,
      });
      // 设置SampledPositionProperty和SampledProperty
      positions.forEach((item, i) => {
        var time = Cesium.JulianDate.addSeconds(
          start,
          i * 5,
          new Cesium.JulianDate()
        );
        var timenext = Cesium.JulianDate.addSeconds(
          start,
          (i + 1) * 5,
          new Cesium.JulianDate()
        );
        pathPosition.addSample(time, item);

        // 设置姿态
        // 将世界坐标转为经纬度
        let ellise = viewer.scene.globe.ellipsoid;
        let lngnext,
          latnext,
          altnext = {};
        let lng = Cesium.Math.toDegrees(
          ellise.cartesianToCartographic(item).longitude
        );
        let lat = Cesium.Math.toDegrees(
          ellise.cartesianToCartographic(item).latitude
        );
        let alt = ellise.cartesianToCartographic(item).height;
        if (i + 1 < positions.length) {
          lngnext = Cesium.Math.toDegrees(
            ellise.cartesianToCartographic(positions[i + 1]).longitude
          );
          latnext = Cesium.Math.toDegrees(
            ellise.cartesianToCartographic(positions[i + 1]).latitude
          );
          altnext = ellise.cartesianToCartographic(positions[i + 1]).height;
        }
        // 初始姿态
        if (i === 0) {
          // let headangle = computeHeading(lat,lng,latnext,lngnext)
          let heada = courseAngle(lng, lat, lngnext, latnext);
          let pitch = coursePitchAngle(
            lng,
            lat,
            alt,
            lngnext,
            latnext,
            altnext
          );

          var hpr = new Cesium.HeadingPitchRoll(
            Cesium.Math.toRadians(0 - heada),
            Cesium.Math.toRadians(pitch),
            Cesium.Math.toRadians(0)
          );
          var qua = Cesium.Transforms.headingPitchRollQuaternion(item, hpr);
          oriProp.addSample(time, qua);
          // oriProp.intervals.addInterval( new Cesium.TimeInterval({
          //     start : time,
          //     stop : timenext,
          //     isStartIncluded : true,
          //     isStopIncluded : false,
          //     data : qua
          // }))
        } else if (i  > 0 && i  < positions.length-1) {
          // 更新位置
          
          let heada1 = courseAngle(lng, lat, lngnext, latnext);
          let pitch1 = coursePitchAngle(
            lng,
            lat,
            alt,
            lngnext,
            latnext,
            altnext
          );


          var hpr = new Cesium.HeadingPitchRoll(
            Cesium.Math.toRadians(0 - heada1),
            Cesium.Math.toRadians(pitch1),
            Cesium.Math.toRadians(0)
          );
          // var transform = Cesium.Transforms.headingPitchRollToFixedFrame(item, hpr);
          var qua = Cesium.Transforms.headingPitchRollQuaternion(item, hpr);
          oriProp.addSample(time, qua);
          // oriProp.intervals.addInterval( new Cesium.TimeInterval({
          //     start : time,
          //     stop : timenext,
          //     isStartIncluded : true,
          //     isStopIncluded : false,
          //     data : qua
          // }))
        }
      });
    }
    funtion interpolatLine(positions, num) {
      let time = [];
      for (let i = 0; i < num - 1; i++) {
        let t1 = Math.round((1 / (num - 1)) * 100) / 100;
        time.push(t1 * i);
      }
      time.push(1.0);
      var spline = new Cesium.CatmullRomSpline({
        times: time, //[0.0, 0.2, 0.4, 0.64,0.8,1],
        points: positions,
      });
      var RES = [];
      for (var i = 0; i <= 260; i++) {
        var cartesian3 = spline.evaluate(i / 260);
        RES.push(cartesian3);
      }
      return RES;
    },
  }

有问题在公众号中留言。

  • 8
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值