前言:基于cesium实现飞机延航线飞行并可实时增加航线
效果:基于cesium飞机飞行航线视频_哔哩哔哩_bilibili
思路:
1.创建cesium (省略.....)
2.理清需要那些功能,在这里我们用到了cesium得画点,画线,画面,以及cesium时间控件,对时间轴进行设置等
3.接下来就开始创作了,其中还有一些细节,大家自行体会,
万年不变老开头
话不多说直接上代码
完整代码如下,当然还有一些缺陷或者bug,请大家指正,我会改进
以下是调用代码及参数
有一点功能需要引用turf.js来进行每个间距的距离计算
turf官网: Turf.js中文网
turf引用 在线: <script src="https://unpkg.com/@turf/turf/turf.min.js"></script>
// ----------------------
let demoPointArr = [
[105.688371, 25.289973, 10000],
[109.161164, 25.878748, 15000],
[109.468776, 27.102328, 30000],
[104.196792, 26.691527, 25000],
[105.380841, 28.098639, 20000],
[111.151287, 30.029206, 15000],
[106.574412, 30.015039, 15000],
[103.906272, 32.108362, 30000],
[110.544005, 32.318148, 10000],
];
let demoGonArr = [
[105.688371, 25.289973, 10000],
[109.161164, 25.878748, 15000],
[109.468776, 27.102328, 150000],
[111.151287, 30.029206, 15000],
[110.544005, 32.318148, 10000],
[103.906272, 32.108362, 90000],
[104.19679, 26.691527, 40000],
[105.688371, 25.289973, 10000],
];
mapFunc.flyTo({
lng: demoPointArr[4][0],
lat: demoPointArr[4][1],
elevation: 3000000,
});
// 加载模拟飞行
flyDemo.implement(demoPointArr, demoGonArr);
// 改变速度
document.getElementById("speedInput").onchange = (val) => {
// console.log(val.target.value);
flyDemo.changeSpeed(Number(val.target.value));
};
// 视角改变
// 俯视
function btnTopView() {
flyDemo.topView();
}
// 平视
function btnHorizontals() {
flyDemo.horizontals();
}
// 视角跟随
function btnPerspectiveFollowing() {
flyDemo.perspectiveFollowing();
}
// 增加飞行轨迹
function btnAddFlyTrajectory() {
let demo1 = [
...demoPointArr,
...[
[105.989995, 34.250554, 15000],
[112.616139, 33.883412, 10000],
],
];
// .push(
// ...[
// [105.989995, 34250554, 15000],
// [112.616139, 33883412, 10000],
// ]
// );
console.log("ddd", demo1);
flyDemo.addFlyTrajectory(demo1);
}
以下为执行代码
let flyEntity = null;
let cylinderDemo = null;
let startTime = Cesium.JulianDate.fromDate(new Date());
let endTime = null;
let allTime = null;
let nodeTimeArr = [0];
let timeInterval = 30;
const flyDemo = {
implement: (demoPointArr = [], demoGonArr = []) => {
// console.log(9999999, demoPointArr);
// 线数据
let lineDataArr = [];
// 画点
demoPointArr.forEach((a, n) => {
flyDemo.drawPonit(a, n);
lineDataArr.push(...a);
});
// 画线
flyDemo.drawPolyline(lineDataArr);
// 画面
// flyDemo.drawPlaygon(demoGonArr);
// 加载模拟飞行
flyDemo.loadSimulationFly(demoPointArr);
},
// 画点
drawPonit: (lonAndLat, num) => {
// return
const entityPoint = viewer.entities.add({
position: Cesium.Cartesian3.fromDegrees(...lonAndLat),
name: "point_name",
point: {
color: Cesium.Color.fromCssColorString("#fc3d4a"),
outlineColor: Cesium.Color.fromCssColorString("#fc3d4a"),
pixelSize: 11,
},
label: {
show: true,
text: String(num),
font: "normal 22px MicroSoft YaHei",
fillColor: Cesium.Color.WHITE,
style: Cesium.LabelStyle.FILL_AND_OUTLINE,
outlineWidth: 1,
verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
pixelOffset: new Cesium.Cartesian2(0, -20),
showBackground: !0,
backgroundColor: new Cesium.Color(0, 0, 0, 0),
},
});
return entityPoint;
},
// 画线
drawPolyline: (lineArr) => {
const entityLine = viewer.entities.add({
name: "polyline_name",
polyline: {
positions: Cesium.Cartesian3.fromDegreesArrayHeights(lineArr),
width: 5,
material: Cesium.Color.fromCssColorString("#fcc31f"),
},
});
return entityLine;
},
// 画面
drawPlaygon: (gonArr) => {
let lonLats = (data) => {
let arr = [];
for (let d in data) {
//判断经纬度范围
if (
data[d][0] >= -180 &&
data[d][0] <= 180 &&
data[d][1] >= -90 &&
data[d][1] <= 90
) {
arr.push(data[d][0], data[d][1]);
} else {
console.log("经纬度数值不对:", data[d][0], data[d][1]);
}
}
return arr;
};
const entityPolygon = viewer.entities.add({
name: "polyGon_name",
polygon: {
clampToGround: true, //开启贴地
hierarchy: new Cesium.PolygonHierarchy(
Cesium.Cartesian3.fromDegreesArray(lonLats(gonArr))
),
material: Cesium.Color.BLUE.withAlpha(0.5),
// distanceDisplayCondition: new Cesium.DistanceDisplayCondition(0, 300000)
},
});
return entityPolygon;
},
// 画锥体
drawCylinder: (lonAndLat) => {
const cylinderEntity = viewer.entities.add({
name: "cylinder_name",
position: Cesium.Cartesian3.fromDegrees(
lonAndLat[0],
lonAndLat[1],
lonAndLat[2]
),
cylinder: {
length: 1,
topRadius: 0.0,
bottomRadius: 40000.0,
// outline: true,
// outlineColor: Cesium.Color.WHITE,
// outlineWidth: 4,
// material: Cesium.Color.fromRandom({ alpha: 1.0 }),#dddddd
material: new Cesium.Color.fromCssColorString("#dddddd"),
},
});
return cylinderEntity;
},
// 画模型
drawModel: (lonAndLat, startTime, endTime, propertyFly) => {
const flyEntityDemo = viewer.entities.add({
// 与时间进行关联
availability: new Cesium.TimeIntervalCollection([
new Cesium.TimeInterval({
start: startTime,
stop: endTime,
}),
]),
id: "demo",
position: Cesium.Cartesian3.fromDegrees(
lonAndLat[0],
lonAndLat[1],
lonAndLat[2] * 10
),
orientation: new Cesium.VelocityOrientationProperty(propertyFly),
model: {
uri: "./Cesium_Air.glb",
minimumPixelSize: 128,
},
// 飞行路径
path: {
resolution: 1,
material: new Cesium.PolylineGlowMaterialProperty({
glowPower: 0.1,
color: Cesium.Color.YELLOW,
}),
// leadTime、trailTime 不设置 path全显示
// leadTime:0,// 设置为0时 模型通过后显示path
// trailTime: 0,// 设置为0时 模型通过后隐藏path
width: 10,
},
});
return flyEntityDemo;
},
// 加载模拟飞行
loadSimulationFly: (demoPointArr = []) => {
// 获取总时间和节点时间
flyDemo.getAllTime(demoPointArr);
// 配置飞行轨迹时间线
flyDemo.setTimeLine();
// 根据模拟数据创建对应时间与坐标的SampledPositionProperty并生成entity实体
// 创建SampledPositionProperty
// 设置到每一个点位的时间和坐标进行关联
// 飞机
const propertyFlyData = flyDemo.mapPropertyData(demoPointArr, "fly");
// 锥体
const propertyCylinderData = flyDemo.mapPropertyData(
demoPointArr,
"cylinder"
);
// ----------
// 画锥体
cylinderDemo = flyDemo.drawCylinder(demoPointArr[0]);
// --------
// ----------
// 画模型
flyEntity = flyDemo.drawModel(
demoPointArr[0],
startTime,
endTime,
propertyFlyData
);
// --------
cylinderDemo.position = propertyCylinderData;
flyEntity.position = propertyFlyData;
},
// 改变速度
changeSpeed: (val = Number) => {
// console.log("speed 改变速度");
viewer.clock.multiplier = val;
},
// 视角改变
// 俯视
topView: () => {
viewer.trackedEntity = undefined;
viewer.zoomTo(
flyEntity,
new Cesium.HeadingPitchRange(0, Cesium.Math.toRadians(-90), 2000000)
);
},
// 平视
horizontals: () => {
viewer.trackedEntity = undefined;
viewer.zoomTo(
flyEntity,
new Cesium.HeadingPitchRange(
Cesium.Math.toRadians(-90),
Cesium.Math.toRadians(-15),
2000000
)
);
},
// 视角跟随
perspectiveFollowing: () => {
flyEntity.viewFrom = new Cesium.Cartesian3(0.0, -1000.0, 1500.0);
viewer.trackedEntity = flyEntity;
},
// 增加飞行轨迹
addFlyTrajectory: (val) => {
// console.log(val);
flyDemo.getAllTime(val);
// 设置到每一个点位的时间和坐标进行关联
// 飞机
const propertyFlyData = flyDemo.mapPropertyData(val, "fly");
// 锥体
const propertyCylinderData = flyDemo.mapPropertyData(val, "cylinder");
// 设置阴影
cylinderDemo.position = propertyCylinderData;
// console.log("ddd flyEntity", flyEntity);
// 设置飞机
// 设置结束时间
endTime = Cesium.JulianDate.addSeconds(
startTime,
allTime,
new Cesium.JulianDate()
);
flyEntity.position = propertyFlyData;
flyEntity.availability = new Cesium.TimeIntervalCollection([
new Cesium.TimeInterval({
start: startTime,
stop: endTime,
}),
]);
flyEntity.orientation = new Cesium.VelocityOrientationProperty(
propertyFlyData
);
// 设置时间轴
// 设置结束时间
viewer.clock.stopTime = endTime.clone();
// 设置时间轴
viewer.timeline.zoomTo(startTime, endTime);
},
// 设置时间轴
setTimeLine: () => {
// 配置飞行轨迹时间线
// 1.设置两点之间飞行所用时间间隔
timeInterval = 30;
// 2.计算飞完一整个航线所需要的时间
// console.log(allTime);
// 3.设置起始时间即获取当前时间
// console.log(startTime);
// 4.获取结束时间
endTime = Cesium.JulianDate.addSeconds(
startTime,
allTime,
new Cesium.JulianDate()
);
// 5.设置时钟
// 开始时间
viewer.clock.startTime = startTime.clone();
// 设置当前时间
viewer.clock.currentTime = startTime.clone();
// 设置结束时间
viewer.clock.stopTime = endTime.clone();
// 设置飞行速率 (飞行速度)
viewer.clock.multiplier = 20;
// 循环飞行
viewer.clock.clockRange = Cesium.ClockRange.LOOP_STOP;
// 设置时间轴
viewer.timeline.zoomTo(startTime, endTime);
},
// 获取总用时
getAllTime: (data) => {
allTime = 0;
nodeTimeArr = [0];
for (let i = 0; i < data.length; i++) {
// console.log("ddd i ", i);
if (i < data.length - 1) {
let from = turf.point([data[i][0], data[i][1]]);
let to = turf.point([data[i + 1][0], data[i + 1][1]]);
let options = { units: "kilometers" };
let distance = turf.distance(from, to, options);
// console.log("ddd distance", Math.round(distance / timeInterval));
allTime = allTime + Math.round(distance / timeInterval);
nodeTimeArr.push(allTime);
}
// console.log("ddd 2", allTime);
}
},
// 数据处理
mapPropertyData: (data, isFlyOrCylinder) => {
// 根据模拟数据创建对应时间与坐标的SampledPositionProperty并生成entity实体
// 创建SampledPositionProperty
let property = new Cesium.SampledPositionProperty();
for (let i = 0; i < data.length; i++) {
// console.log("ddd nodeTimeArr[i]", nodeTimeArr[i]);
// 获取到点的时间
let time = Cesium.JulianDate.addSeconds(
startTime,
nodeTimeArr[i], //+2是给一个基础默认时间
new Cesium.JulianDate()
);
// console.log("ddd time", time);
// 获取点位
let position = Cesium.Cartesian3.fromDegrees(
data[i][0],
data[i][1],
isFlyOrCylinder == "fly" ? data[i][2] * 10 : data[i][2]
);
// 将时间和位置进行关联
// console.log('ddd property',property);
property.addSample(time, position);
}
return property;
},
// 屏幕坐标转化成经纬度
Cartesian3_to_WGS84: (point) => {
let cartesian3 = new Cesium.Cartesian3(point.x, point.y, point.z);
let cartographic = Cesium.Cartographic.fromCartesian(cartesian3);
let lat = Cesium.Math.toDegrees(cartographic.latitude);
let lng = Cesium.Math.toDegrees(cartographic.longitude);
let alt = cartographic.height;
return {
lat: lat,
lng: lng,
alt: alt,
};
},
};
最后谢谢大家观看,第一次创作,感谢大家!
如有不好的地方,欢迎指正.
也作为在工作当中的积累,展示在这里.
同时也欢迎技术交流,本人cesium小白,热爱学习,希望学到更多!