# 效果
最终完整代码请看下面的封装一栏
# 基本思路
我们将他分为两个步骤来做第一步加载一个ellipsoid加载半圆体,第二步用cesium提供的wall属性加载一个立体墙,运用cesium提供的viewer.clock.onTick开启动画效果听起来很简单。下面我们来进行实现
# 实现方法
第一步我们先用cesium中提供ellipsoid方法加载半圆体,先看一下ellipsoid中都有哪些属性
属性名 | 属性含义 |
distanceDisplayCondition | 指定将在距相机多远的距离显示和隐藏 new Cesium.DistanceDisplayCondition(0.0,10.5e6 ), |
fill | 设置填充色显示隐藏 |
heightReference | 默认值: HeightReference.NONE |
innerRadii | 指定椭圆体的内半径 默认值: radii |
material | 设置球体材质 如:new Cesium.Color.fromCssColorString("#00dcff82") |
maximumClock | 设置指定椭球最大时钟角的属性 |
maximumCone | 指定椭圆体最大锥角的属性 如:Cesium.Math.toRadians(90) |
minimumClock | 设置指定椭球最小时钟角的属性 |
minimumCone | 指定椭圆体最小锥角的属性 |
outline | 设置指定corridor 是否有轮廓的Property 。true或false |
outlineColor | 轮廓线颜色 |
outlineWidth | 轮廓线宽度 |
radii | 设置指定椭圆体的半径。 Cartesian3 Property |
shadows | 设置阴影 默认值: ShadowMode.DISABLED |
show | 设置实体显示隐藏 |
slicePartitions | 设置指定每 360 度的径向切片数的属性 默认值: 64 |
stackPartitions | 设置指定堆栈数的属性 默认值: 64 |
subdivisions | 指定每个轮廓环的样本数,确定曲率的粒度 默认值: 128 |
viewer.entities.add({
position: Cesium.Cartesian3.fromDegrees(
-80,
35
),
ellipsoid: {
radii: new Cesium.Cartesian3(
100000.0,
100000.0,
100000.0
),
maximumCone: Cesium.Math.toRadians(90),
material: new Cesium.Color.fromCssColorString("#00dcff82"),
outline: true,
outlineColor: new Cesium.Color.fromCssColorString("#00dcff82"),
outlineWidth: 1,
distanceDisplayCondition: new Cesium.DistanceDisplayCondition(
0.0,
10.5e6
),
},
});
现在我们就行看见一个静态的半球体
第二步我们cesium中提供的wall来加载里面类似扇叶在动的东西,先不着急写代码,我们先来看一下wall里面的属性值
属性 | 含义值 |
material | 设置材质 |
maximumHeights | 用于墙顶的高度数组,而不是每个位置的高度 |
minimumHeights | 用于墙底的高度数组 |
outline | 设置指定corridor 是否有轮廓的Property 默认 |
outlineColor | 轮廓线颜色 |
outlineWidth | 轮廓线宽度 |
fill | 设置填充色显示隐藏 |
distanceDisplayCondition | new Cesium.DistanceDisplayCondition( 0.0, 5.5e6 )距相机多远的距离处显示或隐藏 |
shadows | ShadowMode.DISABLED设置投影 |
show | true或false实体显示隐藏(动态改变直接改变show就可以) |
注意wall加载出来的立体墙并不不是我们想要的,看图我们可以知道我们想要一个1/4圆形立体墙,我们可以通过两个算法来得到,我们分为两步第一步先来确定平面扫描区域,在来确定里面扫描区域。
先来确定平面扫描区域
// 根据第一个点 偏移距离 角度 求取第二个点的坐标
function calcPoints(x1, y1, radius, heading){
var m = Cesium.Transforms.eastNorthUpToFixedFrame(Cesium.Cartesian3.fromDegrees(x1, y1));
var rx = radius * Math.cos(heading * Math.PI / 180.0);
var ry = radius * Math.sin(heading * Math.PI / 180.0);
var translation = Cesium.Cartesian3.fromElements(rx, ry, 0);
var d = Cesium.Matrix4.multiplyByPoint(m, translation, new Cesium.Cartesian3());
var c = Cesium.Cartographic.fromCartesian(d);
var x2 = Cesium.Math.toDegrees(c.longitude);
var y2 = Cesium.Math.toDegrees(c.latitude);
return computeCirclularFlight(x1, y1, x2, y2, 0, 90);
}
确定立面扫描区域
// 根据两个点 开始角度、夹角度 求取立面的扇形
function computeCirclularFlight(x1, y1, x2, y2, fx, angle) {
let positionArr = [];
positionArr.push(x1);
positionArr.push(y1);
positionArr.push(0);
var radius = Cesium.Cartesian3.distance(Cesium.Cartesian3.fromDegrees(x1, y1), Cesium.Cartesian3.fromDegrees(x2, y2));
for (let i = fx; i <= fx + angle; i++) {
let h = radius * Math.sin(i * Math.PI / 180.0);
let r = Math.cos(i * Math.PI / 180.0);
let x = (x2 - x1) * r + x1;
let y = (y2 - y1) * r + y1;
positionArr.push(x);
positionArr.push(y);
positionArr.push(h);
}
return positionArr;
}
然后来进行加载立体墙
// An highlighted block
viewer.entities.add({
position: Cesium.Cartesian3.fromDegrees(
-80,
35
),
wall: {
positions: new Cesium.CallbackProperty(() => {
return Cesium.Cartesian3.fromDegreesArrayHeights(positionArr);
}, false),
material: new Cesium.Color.fromCssColorString("#00dcff82"),
distanceDisplayCondition: new Cesium.DistanceDisplayCondition(
0.0,
10.5e6
),
},
});
var heading = 0;
var positionArr = calcPoints(
-80,
35,
100000.0,//此处芋圆的半径保持一致
heading
);
此时我们可以看到一个静态的效果已经出来了,但是还出现了一个问题他并没有动,没有达到我们想要的效果如下图所示
我们在仔细观察cesium文档中给我们提供了一个viewer.clock.onTick方法
viewer.clock.onTick.addEventListener(() => {
heading += 10.0;
positionArr = calcPoints(
-80,
35,
100000.0,
heading
);
});
现在我们的动画效果就出现了,来看一眼完整代码
viewer.entities.add({
position: Cesium.Cartesian3.fromDegrees(
-80,
35
),
wall: {
positions: new Cesium.CallbackProperty(() => {
return Cesium.Cartesian3.fromDegreesArrayHeights(positionArr);
}, false),
material: new Cesium.Color.fromCssColorString("#00dcff82"),
distanceDisplayCondition: new Cesium.DistanceDisplayCondition(
0.0,
10.5e6
),
},
ellipsoid: {
radii: new Cesium.Cartesian3(
100000.0,
100000.0,
100000.0
),
maximumCone: Cesium.Math.toRadians(90),
material: new Cesium.Color.fromCssColorString("#00dcff82"),
outline: true,
outlineColor: new Cesium.Color.fromCssColorString("#00dcff82"),
outlineWidth: 1,
distanceDisplayCondition: new Cesium.DistanceDisplayCondition(
0.0,
10.5e6
),
},
});
var heading = 0;
var positionArr = calcPoints(
-80,
35,
100000.0,//此处芋圆的半径保持一致
heading
);
viewer.clock.onTick.addEventListener(() => {
heading += 10.0;
positionArr = calcPoints(
-80,
35,
100000.0,
heading
);
});
function calcPoints(x1, y1, radius, heading){
var m = Cesium.Transforms.eastNorthUpToFixedFrame(Cesium.Cartesian3.fromDegrees(x1, y1));
var rx = radius * Math.cos(heading * Math.PI / 180.0);
var ry = radius * Math.sin(heading * Math.PI / 180.0);
var translation = Cesium.Cartesian3.fromElements(rx, ry, 0);
var d = Cesium.Matrix4.multiplyByPoint(m, translation, new Cesium.Cartesian3());
var c = Cesium.Cartographic.fromCartesian(d);
var x2 = Cesium.Math.toDegrees(c.longitude);
var y2 = Cesium.Math.toDegrees(c.latitude);
return computeCirclularFlight(x1, y1, x2, y2, 0, 90);
}
function computeCirclularFlight(x1, y1, x2, y2, fx, angle) {
let positionArr = [];
positionArr.push(x1);
positionArr.push(y1);
positionArr.push(0);
var radius = Cesium.Cartesian3.distance(Cesium.Cartesian3.fromDegrees(x1, y1), Cesium.Cartesian3.fromDegrees(x2, y2));
for (let i = fx; i <= fx + angle; i++) {
let h = radius * Math.sin(i * Math.PI / 180.0);
let r = Math.cos(i * Math.PI / 180.0);
let x = (x2 - x1) * r + x1;
let y = (y2 - y1) * r + y1;
positionArr.push(x);
positionArr.push(y);
positionArr.push(h);
}
return positionArr;
}
哇这代码看起来很乱,不便于后期维护,我们可以对其进行封装一下 ,让代码更加美观
# 封装
我们用es6 class对其进行封装,我们先命名一个js文件,trackMatte.js
/**
*
* @param {Viewer} viewer
* @param {Cartesian3} position 经纬度
* @param {String} id
* @param {number} shortwaveRange 半径
* @return {*}
*
*/
export default class TrackMatte {
constructor(val) {
this.viewer = val.viewer;
this.id = val.id;
this.shortwaveRange = val.shortwaveRange;
this.longitude = val.position[0],
this.latitude = val.position[1],
this.position = Cesium.Cartesian3.fromDegrees(
val.position[0],
val.position[1],
);
this.heading = 0;
this.positionArr = this.calcPoints(
val.position[0],
val.position[1],
val.shortwaveRange,
0
) //储存脏数据
this.addEntities()
}
addEntities(){
let entity = this.viewer.entities.add({
id: this.id,
position: this.position,
wall: {
positions: new Cesium.CallbackProperty(() => {
return Cesium.Cartesian3.fromDegreesArrayHeights(this.positionArr);
}, false),
material: new Cesium.Color.fromCssColorString("#00dcff82"),
distanceDisplayCondition: new Cesium.DistanceDisplayCondition(
0.0,
10.5e6
),
},
ellipsoid: {
radii: new Cesium.Cartesian3(
this.shortwaveRange,
this.shortwaveRange,
this.shortwaveRange
),
maximumCone: Cesium.Math.toRadians(90),
material: new Cesium.Color.fromCssColorString("#00dcff82"),
outline: true,
outlineColor: new Cesium.Color.fromCssColorString("#00dcff82"),
outlineWidth: 1,
distanceDisplayCondition: new Cesium.DistanceDisplayCondition(
0.0,
10.5e6
),
},
});
this.addPostRender()
}
addPostRender(){
this.viewer.clock.onTick.addEventListener(() => {
this.heading += 10.0;//可调节转动速度
this.positionArr = this.calcPoints(
this.longitude,
this.latitude,
this.shortwaveRange,
this.heading
);
});
}
calcPoints(x1, y1, radius, heading) {
var m = Cesium.Transforms.eastNorthUpToFixedFrame(
Cesium.Cartesian3.fromDegrees(x1, y1)
);
var rx = radius * Math.cos((heading * Math.PI) / 180.0);
var ry = radius * Math.sin((heading * Math.PI) / 180.0);
var translation = Cesium.Cartesian3.fromElements(rx, ry, 0);
var d = Cesium.Matrix4.multiplyByPoint(
m,
translation,
new Cesium.Cartesian3()
);
var c = Cesium.Cartographic.fromCartesian(d);
var x2 = Cesium.Math.toDegrees(c.longitude);
var y2 = Cesium.Math.toDegrees(c.latitude);
return this.computeCirclularFlight(x1, y1, x2, y2, 0, 90);
}
computeCirclularFlight(x1, y1, x2, y2, fx, angle) {
let positionArr = [];
positionArr.push(x1);
positionArr.push(y1);
positionArr.push(0);
var radius = Cesium.Cartesian3.distance(
Cesium.Cartesian3.fromDegrees(x1, y1),
Cesium.Cartesian3.fromDegrees(x2, y2)
);
for (let i = fx; i <= fx + angle; i++) {
let h = radius * Math.sin((i * Math.PI) / 180.0);
let r = Math.cos((i * Math.PI) / 180.0);
let x = (x2 - x1) * r + x1;
let y = (y2 - y1) * r + y1;
positionArr.push(x);
positionArr.push(y);
positionArr.push(h);
}
return positionArr;
}
}
最后我们只需在我们页面中引用即可
import TrackMatte from "./trackMatte.js"
trackMatte(){
let trackMatte = new TrackMatte({
viewer:viewer,
id:1,
shortwaveRange:100000.0,
position:[-80,35],
})
}
至此我们我们的效果就与开始图中的效果一摸一样了。大功告成