1.cesium 创建三维航线
写的磕磕绊绊 期间遇到很多问题
1.无人机的姿态实时更新
查阅cesium文档 发现了Cesium.Transforms.headingPitchRollQuaternion(position, hpr)
2.无人机视锥跟随无人机转向
这个问题困了好久 一开始尝试自己画了锥形 后面控制锥形旋转 平移 一直没成功 只能做到一直向下探测跟随 后面做了个模型 一开始也没成功 直达发现模型修改原点起点位置 将模型用blender把起点设置成锥顶
3.无人机飞行会有后退动作
在画航线的时候 一开始设置
// interpolationAlgorithm: Cesium.HermitePolynomialApproximation,
// interpolationDegree: 2
发现在碰到重复点的时候会有一个向前起飞又回退的动作 考虑过速度和惯性问题 一直尝试也没成功 后来改成
interpolationDegree: 1,
interpolationAlgorithm: Cesium.LinearApproximation
4.目前还存在的问题
点击航线将无人机定位到航线点击位置 存在误差 在俯视的情况下 正确性颇高 但是其他角度就会有问题
init () {
const Cesium = this.Cesium
// console.log(this.path3DList)
this.showSpin = true
let _this = this
let startTime = ""
let endTime = ""
if (this.flightPathList.length) {
startTime = this.flightPathList[0].recordTime ? moment(this.flightPathList[0].recordTime).format("YYYY-MM-DDTHH:mm:ss") + "Z" : ''
endTime = this.flightPathList[this.flightPathList.length - 1].recordTime ? moment(this.flightPathList[this.flightPathList.length - 1].recordTime).format("YYYY-MM-DDTHH:mm:ss") + "Z" : ''
}
var viewer = new Cesium.Viewer("cesiumContainer", {
infoBox: false,
terrainProvider: Cesium.createWorldTerrain(),
shouldAnimate: false,
geocoder: false,//右上角第一个位置的查找工具
homeButton: false,//右上角第二个位置的home图标
sceneModePicker: false,//右上角第三个选择视角模式
baseLayerPicker: false,//右上角第四个位置的图层选择器
navigationHelpButton: false,//右上角第五个导航帮助按钮
timeline: true,
animation: false,//控制左下角的动画器件
fullscreenButton: false,
scene3DOnly: true,
selectionIndicator: true,
})
//设置地形
// viewer.terrainProvider = Cesium.createWorldTerrain({
// requestWaterMask: true,//水渲染需求
// requestVertexNormals: true//顶点法线渲染需求
// })
// viewer.scene.globe.depthTestAgainstTerrain = true//深度显示(用于湖泊河流 水深对周围景观的影响)
// viewer.scene.globe.enableLighting = true//全局日照(受太阳,月亮的位置而影响光照信息)
// console.log(this.flightPathList)
let point = this.flightPathList[this.currentCount]
// console.log(point.yaw, point.pitch, point.roll, Number(point.height), 'height')
var initialPosition = new Cesium.Cartesian3.fromDegrees(point.longitude, point.latitude, Number(point.height))//摄像机位置 ,经度,纬度,高度
// var initialOrientation = new Cesium.HeadingPitchRoll.fromDegrees(point.yaw, point.pitch, point.roll)//飞行 专用的 表示旋转角度之类的东西:
var homeCameraView = {
destination: initialPosition,
// orientation: {
// heading: Number(initialOrientation.heading) + 5, //偏航角
// pitch: Number(initialOrientation.pitch) + 5, //俯仰角
// roll: initialOrientation.roll//滚转角
// },
complete: () => {
setTimeout(() => {
viewer.camera.zoomOut(2000)
this.showSpin = false
}, 2000)
}
}
//飞行时,相机的动画属性设置
homeCameraView.dutaion = 1.0
homeCameraView.maximumHeight = 2000
homeCameraView.pitchAdjustHeight = 2000
homeCameraView.endTransform = Cesium.Matrix4.IDENTITY
//
// var CesiumViewerSceneController = viewer.scene.screenSpaceCameraController
// CesiumViewerSceneController.inertiaSpin = 1
// CesiumViewerSceneController.inertiaTranslate = 1
// CesiumViewerSceneController.inertiaZoom = 1
var czml = [
{
id: "document",
name: "CZML Path",
version: "1.0",
clock: {
interval: `${startTime}/${endTime}`,
currentTime: `${startTime}`,
// currentTime: `${'2021-11-16T17:03:44Z'}`,
multiplier: 1,
clockStep: Cesium.ClockStep.TICK_DEPENDENT,
// clockStep: 1
},
},
{
id: "path_2",
name: "path2",
availability: `${startTime}/${endTime}`,
path: {
show: [
{
interval: `${startTime}/${endTime}`,
boolean: false
}
],
width: 0,
},
position: {
epoch: `${startTime}`,
cartographicDegrees: this.path3DList,
},
},
{
id: "path",
name: "path1",
availability: `${startTime}/${endTime}`,
path: {
show: [
{
interval: `${startTime}/${endTime}`,
boolean: true
}
],
width: 6,
material: {
solidColor: {
color: { rgba: [255, 161, 65, 255], }
}
}
},
billboard: {
color: {
rgba: [0, 255, 255, 255]
},
eyeOffset: { "cartesian": [0, 0, 0] },
pixelOffset: { "cartesian2": [0, 0] },
horizontalOrigin: "CENTER",
verticalOrigin: "CENTER",
image: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAICAYAAADED76LAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAjSURBVChTYyAa/EcDUGEIgIphAKg0XRSAAFQMDqDChAADAwDC13+BJ+0oDwAAAABJRU5ErkJgggAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==",
scale: 1,
show: true
},
position: {
epoch: `${startTime}`,
cartographicDegrees: this.path3DList,
},
}
]
var dronePromise = Cesium.CzmlDataSource.load(czml)
var drone
var drone_2
dronePromise.then(dataSource => {
viewer.dataSources.add(dataSource)
drone = dataSource.entities.getById('path')
drone_2 = dataSource.entities.getById('path_2')
// 无人机模型
drone.model = {
id: 'wrj',
name: 'wrj',
uri: '/WRJ02.glb',
minimumPixelSize: 48,
scale: 0.2,
maximumScale: 10
}
// uri: 'https://gist.githubusercontent.com/rahwang/9843cb77fc1c6d07c287566ed4e08ee3/raw/dc3a9ff6fc73b784519ac9371c0e2cbd3ab3dc47/CesiumDrone.gltf',
// 添加无人机位置
//VelocityOrientationProperty(速度方向属性):基于所给的位置属性的速度来得出一个四元旋转属性
// drone.orientation = new Cesium.VelocityOrientationProperty(drone.position)
drone.position.setInterpolationOptions({
// interpolationAlgorithm: Cesium.HermitePolynomialApproximation,
// interpolationDegree: 2
interpolationDegree: 1,
interpolationAlgorithm: Cesium.LinearApproximation
})
drone_2.position.setInterpolationOptions({
interpolationDegree: 1,
interpolationAlgorithm: Cesium.LinearApproximation
})
drone_2.model = {
id: 'wrj_zhuiti',
name: 'wrj_zhuiti',
uri: '/WRJ_zhuiti.glb',
minimumPixelSize: 48,
scale: 1,
maximumScale: 10
}
//跟踪无人机
// viewer.trackedEntity = drone
//取消跟踪无人机
// viewer.trackedEntity = undefined
viewer.camera.flyTo(homeCameraView)
})
//白模
// var shpTileset = new Cesium.Cesium3DTileset({
// url: 'http://10.2.13.73:9000/model/ad9d5be0767e11ebab9c9b084bddd6a4/tileset.json',
// })
// shpTileset.style = new Cesium.Cesium3DTileStyle({
// color: {
// conditions: [
// ["${height} >= 300", "rgba(45, 0, 75, 0.5)"],
// ["${height} >= 200", "rgb(102, 71, 151)"],
// ["${height} >= 100", "rgb(170, 162, 204)"],
// ["${height} >= 50", "rgb(224, 226, 238)"],
// ["${height} >= 25", "rgb(252, 230, 200)"],
// ["${height} >= 10", "rgb(248, 176, 87)"],
// ["${height} >= 5", "rgb(198, 106, 11)"],
// ["true", "rgb(127, 59, 8)"],
// ],
// },
// })
// viewer.scene.primitives.add(shpTileset)
viewer.timeline.makeLabel = (datetime) => {
return this.timeFmt(datetime, "HH:mm:ss")
}
viewer.timeline.zoomTo(viewer.clock.startTime, viewer.clock.stopTime)//设置时间轴可见趋近
viewer.clock.canAnimate = false
viewer.clock.onTick.addEventListener((tick) => {
// this.scanEntity.orientation = null
// viewer.entities.remove(this.scanBox)
let time = this.timeFmt(tick.currentTime, "YYYY-MM-DD HH:mm:ss")
this.preTime = this.nowTime
this.nowTime = time
if (this.preTime == this.nowTime) {
return
}
this.currentTime = getTime(this.flightPathList[0].recordTime, time)
let allTime = (new Date(this.flightPathList[this.flightPathList.length - 1].recordTime).getTime() - new Date(this.flightPathList[0].recordTime).getTime()) / 1000
let nowTime = (new Date(time).getTime() - new Date(this.flightPathList[0].recordTime).getTime()) / 1000
this.currentWidth = (nowTime * 1000) / (allTime * 1000) * 100 + '%'
this.isPlay = viewer.clock.shouldAnimate
this.$emit('start3D', { isPlay: viewer.clock.shouldAnimate, time, tick: viewer.clock.shouldAnimate })
function getTime (start, now) {
let time = (new Date(now).getTime() - new Date(start).getTime()) / 1000
// console.log(time, 'time')
_this.$emit('getCurrentCount', time)
let s = showNum(time % 60)
let m = showNum(parseInt(time / 60))
return `${m}:${s}`
}
function showNum (num) {
if (num < 10) {
return '0' + num
}
return num
}
//设置偏转俯仰翻滚
if (this.timePathList[time]) {
let { pitch, roll, yaw, longitude, latitude, height } = this.timePathList[time]
var position = Cesium.Cartesian3.fromDegrees(longitude, latitude, height)
var position_2 = Cesium.Cartesian3.fromDegrees(longitude, latitude, height)
//no 视锥
var hpr = new Cesium.HeadingPitchRoll(Cesium.Math.toRadians(Number(yaw) + 90), Cesium.Math.toRadians(Number(pitch)), Cesium.Math.toRadians(Number(roll)))
//has 视锥
// var hpr = new Cesium.HeadingPitchRoll(Cesium.Math.toRadians(Number(yaw) + 180), Cesium.Math.toRadians(Number(pitch)), Cesium.Math.toRadians(Number(roll)))
var orientation = Cesium.Transforms.headingPitchRollQuaternion(position, hpr)
drone.orientation = orientation
viewer.entities.remove(this.scanBox)
var headingC = Cesium.Math.toRadians(180 + Number(yaw))
var pitchC = Cesium.Math.toRadians(90.0 + 0)
var rollC = Cesium.Math.toRadians(0)
var hprC = new Cesium.HeadingPitchRoll(headingC, pitchC, rollC)
drone_2.orientation = Cesium.Transforms.headingPitchRollQuaternion(position_2, hprC)
}
})
viewer.clock.onStop.addEventListener((tick) => {
viewer.clock.shouldAnimate = false
this.$emit('clearMap3D')
})
//航点
this.drawPoint(viewer)
//
// currentCount
var time_count = new Date(_this.flightPathList[_this.currentCount].recordTime)
var utc_time = Cesium.JulianDate.fromDate(time_count)//UTC
viewer.clock.currentTime = Cesium.JulianDate.addHours(utc_time, 8, new Cesium.JulianDate())
//航点点击
viewer.screenSpaceEventHandler.setInputAction(function leftClick (movement) {
var pickedFeature = viewer.scene.pick(movement.position)
console.log(pickedFeature)
if (pickedFeature && pickedFeature.id && pickedFeature.id._name == "point") {
let time_bj = new Date(_this.flightPathList[pickedFeature.id._id].recordTime)
let utc = Cesium.JulianDate.fromDate(time_bj)//UTC
viewer.clock.currentTime = Cesium.JulianDate.addHours(utc, 8, new Cesium.JulianDate())
return
}
if (pickedFeature && pickedFeature.id && (pickedFeature.id._name == "wrj_zhuiti" || pickedFeature.id._name == 'wrj' || pickedFeature.id._name == 'path2')) {
return
}
if (pickedFeature && pickedFeature.id && (pickedFeature.id._name != "wrj_zhuiti" || pickedFeature.id._name != 'path2')) {
let pointSelectArray = []
var earthPosition = viewer.camera.pickEllipsoid(movement.position, viewer.scene.globe.ellipsoid)
var cartographic = Cesium.Cartographic.fromCartesian(earthPosition, viewer.scene.globe.ellipsoid, new Cesium.Cartographic())
var lng = Cesium.Math.toDegrees(cartographic.longitude)
var lat = Cesium.Math.toDegrees(cartographic.latitude)
// var height = cartographic.height
// function getDistance (lng1, lat1, lng2, lat2) {
// let startPosition = new Cesium.Cartesian3.fromDegrees(lng1, lat1)
// let endPosition = new Cesium.Cartesian3.fromDegrees(lng2, lat2)
// let distance = Cesium.Cartesian3.distance(startPosition, endPosition)//求两点直线距离,单位为米
// return distance
// }
// console.log("[Lng=>" + lng + ",Lat=>" + lat + ",H=>" + height + "]")
// 经纬度转换成三角函数中度分表形式
function rad (d) {
return d * Math.PI / 180.0
}
// 根据经纬度计算距离
function getDistance (lng1, lat1, lng2, lat2,) {
var radLat1 = rad(lat1)
var radLat2 = rad(lat2)
var a = radLat1 - radLat2
var b = rad(lng1) - rad(lng2)
var s = 2 * Math.asin(Math.sqrt(Math.pow(Math.sin(a / 2), 2) +
Math.cos(radLat1) * Math.cos(radLat2) * Math.pow(Math.sin(b / 2), 2)))
s = s * 6378.137 // EARTH_RADIUS;
s = Math.round(s * 10000) //输出为公里
return s
}
_this.flightPathList.forEach(el => {
pointSelectArray.push(getDistance(el.longitude, el.latitude, lng, lat))
})
// console.log(lat, lng, height, pointSelectArray)
//获取最小值的下标
function getMinIndex (arr) {
var min = arr[0]
//声明了个变量 保存下标值
var index = 0
for (var i = 0; i < arr.length; i++) {
if (min > arr[i]) {
min = arr[i]
index = i
}
}
return index
}
let index = getMinIndex(pointSelectArray)
let time_bj = new Date(_this.flightPathList[index].recordTime)
let utc = Cesium.JulianDate.fromDate(time_bj)//UTC
viewer.clock.currentTime = Cesium.JulianDate.addHours(utc, 8, new Cesium.JulianDate())
}
}, Cesium.ScreenSpaceEventType.LEFT_UP)//LEFT_CLICK
//鼠标移动
var handler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas)
handler.setInputAction((movement) => {
var haveEn = viewer.scene.pick(movement.endPosition)
// console.log(haveEn, 'haveEn1', haveEn.id._id)
if (haveEn) {
viewer._container.style.cursor = "pointer"
} else {
viewer._container.style.cursor = "default"
}
}, Cesium.ScreenSpaceEventType.MOUSE_MOVE)
viewer._cesiumWidget._creditContainer.style.display = "none"
this.viewer = viewer
console.log(viewer)
},