通过entity加载的实体,根据后端socket请求数据,经纬度发生变化,平滑移动
class Device {
/**
* 设备基类
* @param {*} mapView 地图操作类
* @param {*} id 设备id
* @param {*} modelUri 模型
*/
constructor(mapView, id, modelUri, options) {
this.mapView = mapView
this.mapView.map.clock.shouldAnimate = true
this.id = id
this.entity = null
this.imageEntity = null
this.label = null
this.speed = 0
this.lon = 0
this.lat = 0
this.heading = 0
this.modelUri = modelUri
this.modelScale = 1
this.isDrill = false
this.groundHeight = 0
this.sampledPositionProperty = new Cesium.SampledPositionProperty()
if (options) {
this.modelScale = options.scale
;(this.isDrill = options.isDrill), (this.is3d = options.is3d)
}
this.cacheTime = null
this.cachePosition = null
this.lastSampledTime = null
this.lastOrientation = null
this.empty = null
this.equalCount = 0
this.init()
}
/**
* 初始化实体对象
*/
init() {
var eyeSet = new Cesium.Cartesian3(0, 6, 0)
this.entity = this.mapView.map.entities.add({
id: this.id,
model: {
uri: this.modelUri,
scale: this.modelScale,
minimumPixelSize: 28,
runAnimations: false,
shadows: Cesium.ShadowMode.DISABLED
},
label: {
text: '',
font: '12px sans-serif',
showBackground: true,
backgroundPadding: new Cesium.Cartesian2(3, 3),
eyeOffset: eyeSet,
verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
distanceDisplayCondition: new Cesium.DistanceDisplayCondition(0.0, 8000.0)
}
})
Object.assign(this.entity, { isFirstEnter: true })
}
addData(data) {
if (!data.online) {
return
}
data.heading = data.heading || 0
const equal = floatsEqual(this.lon, data.longitude) && floatsEqual(this.lat, data.latitude) && floatsEqual(this.heading, data.heading)
if (equal) this.equalCount++
else this.equalCount = 0
if (!equal || this.equalCount < 3) {
if (data.deviceId.includes('.mml') || data.deviceId.includes('.truck') || data.deviceId.includes('.cmd')) {
this.entity.label.text = (data.speed ? data.speed : 0) + 'km/h' + '\n' + data.name
} else {
this.entity.label.text = data.name
}
if (this.empty != null) {
this.entity.model.uri = this.empty ? './Cesium/models/kuangka.glb' : './Cesium/models/kuangka_full_earth.glb'
}
this.empty = formatLoadState(data.produceState)
if (this.entity.isFirstEnter) {
// 首次
const height = this.mapView.map.scene.sampleHeight(Cesium.Cartographic.fromDegrees(data.longitude, data.latitude))
const time = this.mapView.map.clock.currentTime
const position = Cesium.Cartesian3.fromDegrees(data.longitude, data.latitude, height)
this.entity.position = position
this.entity.orientation = Cesium.Transforms.headingPitchRollQuaternion(position, new Cesium.HeadingPitchRoll(-data.heading, 0, 0))
this.lon = data.longitude
this.lat = data.latitude
this.heading = data.heading
this.cacheTime = time
this.cachePosition = position
this.entity.isFirstEnter = false
} else {
if (!floatsEqual(this.lon, data.longitude) || !floatsEqual(this.lat, data.latitude)) {
// 位置变化
const height = this.mapView.map.scene.sampleHeight(Cesium.Cartographic.fromDegrees(data.longitude, data.latitude))
const time = this.mapView.map.clock.currentTime
const position = Cesium.Cartesian3.fromDegrees(data.longitude, data.latitude, height)
if (!(this.entity.position instanceof Cesium.SampledPositionProperty)) {
this.lastSampledTime = null
this.entity.position = new Cesium.SampledPositionProperty()
this.entity.position.forwardExtrapolationType = Cesium.ExtrapolationType.HOLD
// this.entity.orientation = new Cesium.VelocityOrientationProperty(this.entity.position)
this.entity.orientation = new Cesium.CallbackProperty((time) => {
const currentPos = this.entity.position.getValue(time)
const pastPos = this.entity.position.getValue(Cesium.JulianDate.addSeconds(time, -0.1, new Cesium.JulianDate()))
const velocity = currentPos && pastPos && Cesium.Cartesian3.subtract(currentPos, pastPos, new Cesium.Cartesian3())
if (!velocity || Cesium.Cartesian3.magnitude(velocity) < 0.15 || Cesium.Cartesian3.magnitude(velocity) > 1.5) {
return this.lastOrientation || Cesium.Transforms.headingPitchRollQuaternion(currentPos, new Cesium.HeadingPitchRoll(-data.heading, 0, 0))
} else {
let current = new Cesium.VelocityOrientationProperty(this.entity.position).getValue(time)
this.lastOrientation = current || this.lastOrientation || Cesium.Transforms.headingPitchRollQuaternion(currentPos, new Cesium.HeadingPitchRoll(-data.heading, 0, 0))
return this.lastOrientation
}
}, false)
}
let duration, startTime
if (!this.lastSampledTime) {
duration = 7.5
startTime = time
} else {
const diff = Cesium.JulianDate.secondsDifference(time, this.lastSampledTime)
if (diff >= 0) {
// 当前时间比采样时间慢了
duration = 7.5
startTime = time
} else if (diff <= -5) {
// 当前时间比采样时间快了超过5秒
duration = 2.5
startTime = this.lastSampledTime
} else {
// 当前时间比采样时间快了不超过5秒
duration = Cesium.JulianDate.secondsDifference(time, this.cacheTime)
startTime = this.lastSampledTime
}
}
const samples = 20
for (let i = 0; i <= samples; ++i) {
const factor = i / samples
const sampleTime = Cesium.JulianDate.addSeconds(startTime, duration * factor, new Cesium.JulianDate())
const samplePosition = Cesium.Cartesian3.lerp(this.cachePosition, position, factor, new Cesium.Cartesian3())
this.entity.position.addSample(sampleTime, samplePosition)
this.lastSampledTime = sampleTime
}
// this.entity.orientation = Cesium.Transforms.headingPitchRollQuaternion(position, new Cesium.HeadingPitchRoll(-data.heading, 0, 0))
this.lon = data.longitude
this.lat = data.latitude
this.heading = data.heading
this.cacheTime = time
this.cachePosition = position
} else {
// 朝向变化
// const height = this.mapView.map.scene.sampleHeight(Cesium.Cartographic.fromDegrees(data.longitude, data.latitude))
const time = this.mapView.map.clock.currentTime
const position = /* Cesium.Cartesian3.fromDegrees(data.longitude, data.latitude, height) */ this.cachePosition
this.entity.position = position
this.entity.orientation = Cesium.Transforms.headingPitchRollQuaternion(position, new Cesium.HeadingPitchRoll(-data.heading, 0, 0))
this.lon = data.longitude
this.lat = data.latitude
this.heading = data.heading
this.cacheTime = time
this.cachePosition = position
}
}
}
}
/**
* 添加
* @param data 设备数据
*/
addDataOld(data) {
const equal = floatsEqual(this.speed, data.speed) && floatsEqual(this.lon, data.longitude) && floatsEqual(this.lat, data.latitude) && floatsEqual(this.heading, data.heading)
if (data.online && !equal) {
this.speed = data.speed
this.lon = data.longitude
this.lat = data.latitude
this.heading = data.heading
let heading = null
// let height = null
if (data?.heading) {
heading = data.heading
} else {
heading = 0
}
if (this.entity.billboard) {
this.entity.billboard.rotation = heading + Math.PI / 2
}
if (data?.deviceId?.indexOf('.drill') == -1 && data?.deviceId?.indexOf('.shovel') == -1 && data?.deviceId?.indexOf('.worker') == -1) {
this.entity.label.text = (data.speed ? data.speed : 0) + 'km/h' + '\n' + data.name
} else {
this.entity.label.text = data.name
}
this.entity.label.horizontalOrigin = Cesium.HorizontalOrigin.LEFT
this.entity.show = true
this.entity.label.showBackground = true
if (!isNaN(data.longitude) && !isNaN(data.latitude)) {
var d = this.mapView.map.scene.sampleHeight(
new Cesium.Cartographic(
Cesium.Math.toRadians(data.longitude), //转换成弧度
Cesium.Math.toRadians(data.latitude) //弧度
)
)
if (d) {
this.groundHeight = d
}
if (this.entity.isFirstEnter == true) {
this.entity.isFirstEnter = false
const position = Cesium.Cartesian3.fromDegrees(data.longitude, data.latitude, this.groundHeight)
this.entity.position = position
this.entity.orientation = Cesium.Transforms.headingPitchRollQuaternion(position, new Cesium.HeadingPitchRoll(heading, 0, 0))
Object.assign(this.entity, { lastPos: [data.longitude, data.latitude, this.groundHeight] })
Object.assign(this.entity, { firstHeight: this.groundHeight })
} else {
if (data.speed != null && data.speed != 0 && data.speed != '') {
if (this.entity.position instanceof Cesium.SampledPositionProperty) {
} else {
this.entity.position = new Cesium.SampledPositionProperty()
}
this.updatePosition(data)
} else {
const position = Cesium.Cartesian3.fromDegrees(data.longitude, data.latitude, this.entity.firstHeight)
this.entity.position = position
this.entity.lastPos = [data.longitude, data.latitude, this.entity.firstHeight]
}
}
}
}
}
updatePosition(data) {
let viewer = this.mapView.map
let positionsOld = Cesium.Cartesian3.fromDegrees(this.entity.lastPos[0], this.entity.lastPos[1], this.entity.lastPos[2])
let positionsNew = Cesium.Cartesian3.fromDegrees(data.longitude, data.latitude, this.groundHeight)
if (this.entity.lastPos[0] != data.longitude || this.entity.lastPos[1] != data.latitude) {
var start = Cesium.JulianDate.fromDate(new Date())
let numberOfSamples = 20
let totalSeconds = 7.0 //动画时间执行完毕
for (let i = 0; i <= numberOfSamples; ++i) {
const factor = i / numberOfSamples
let time = Cesium.JulianDate.addSeconds(start, factor * totalSeconds, new Cesium.JulianDate())
const locationFactor = Math.pow(factor, 2)
const location = Cesium.Cartesian3.lerp(
positionsOld, //传递的上一个坐标
positionsNew, //传递的下一个坐标
locationFactor,
new Cesium.Cartesian3()
)
this.entity.position.addSample(time, location)
this.sampledPositionProperty.addSample(time, location)
}
this.entity.orientation = new Cesium.VelocityOrientationProperty(this.entity.position)
this.entity.lastPos = [data.longitude, data.latitude, this.groundHeight]
}
}
/**
* 销毁设备
*/
destroy() {
this.mapView.map.entities.remove(this.entity)
this.mapView = this.id = this.entity = this.positionsProperty = this.headingProperty = null
}
}