先上效果吧,实现了飞行过程中的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;
},
}
有问题在公众号中留言。