import * as Cesium from 'cesium'
|
import { getPointPositionsHeight } from './mapUtil'
|
|
const DEVICE_RANGE_MATERIAL_TYPE = 'DeviceRangeEllipsoid'
|
let deviceRangeMaterialRegistered = false
|
|
export const registerDeviceRangeMaterial = () => {
|
if (deviceRangeMaterialRegistered || !Cesium?.Material) return
|
deviceRangeMaterialRegistered = true
|
Cesium.Material._materialCache.addMaterial(DEVICE_RANGE_MATERIAL_TYPE, {
|
fabric: {
|
type: DEVICE_RANGE_MATERIAL_TYPE,
|
uniforms: {
|
color: new Cesium.Color(1.0, 0.0, 0.0, 0.7),
|
speed: 3.0,
|
globalAlpha: 0.9
|
},
|
source: `
|
uniform vec4 color;
|
uniform float speed;
|
uniform float globalAlpha;
|
|
czm_material czm_getMaterial(czm_materialInput materialInput)
|
{
|
czm_material material = czm_getDefaultMaterial(materialInput);
|
vec2 st = materialInput.st;
|
|
float time = fract(czm_frameNumber * speed / 1000.0);
|
|
if (st.t < 0.5) {
|
discard;
|
}
|
|
float alphaMars3D = abs(smoothstep(0.5, 1.0, fract(-st.t - time)));
|
alphaMars3D += 0.1;
|
|
material.alpha = alphaMars3D * globalAlpha;
|
material.diffuse = color.rgb;
|
|
return material;
|
}
|
`,
|
},
|
translucent: () => true,
|
})
|
}
|
|
export const createDeviceRangeMaterial = () => {
|
registerDeviceRangeMaterial()
|
return Cesium.Material.fromType(DEVICE_RANGE_MATERIAL_TYPE, {
|
color: Cesium.Color.fromBytes(0, 255, 255, 155),
|
})
|
}
|
|
export const getDeviceLngLat = device => {
|
const lngRaw = device?.longitude ?? device?.lng ?? device?.lon
|
const latRaw = device?.latitude ?? device?.lat
|
const lng = Number(lngRaw)
|
const lat = Number(latRaw)
|
if (!Number.isFinite(lng) || !Number.isFinite(lat)) return null
|
return { lng, lat }
|
}
|
|
export const normalizeDeviceRange = value => {
|
const range = Number(value)
|
if (!Number.isFinite(range) || range <= 0) return 2000
|
return range
|
}
|
|
export const resolveDeviceTerrainHeight = async (viewer, position) => {
|
if (!viewer || !position) return 0
|
const lng = position.lng ?? position.longitude
|
const lat = position.lat ?? position.latitude
|
if (!Number.isFinite(Number(lng)) || !Number.isFinite(Number(lat))) return 0
|
try {
|
const results = await getPointPositionsHeight([{ lng: Number(lng), lat: Number(lat) }], viewer)
|
const height = Number(results?.[0]?.ASL)
|
return Number.isFinite(height) ? height : 0
|
} catch (error) {
|
return 0
|
}
|
}
|
|
export const createDeviceRangePrimitiveWithHeight = (position, rangeMeters, height, material = null) => {
|
if (!position || !Number.isFinite(rangeMeters)) return null
|
const lng = position.lng ?? position.longitude
|
const lat = position.lat ?? position.latitude
|
if (!Number.isFinite(Number(lng)) || !Number.isFinite(Number(lat))) return null
|
const center = Cesium.Cartesian3.fromDegrees(Number(lng), Number(lat), Number(height) || 0)
|
const radii = new Cesium.Cartesian3(rangeMeters, rangeMeters, rangeMeters)
|
const geometry = new Cesium.EllipsoidGeometry({
|
radii,
|
vertexFormat: Cesium.MaterialAppearance.MaterialSupport.TEXTURED?.vertexFormat
|
|| Cesium.VertexFormat.POSITION_AND_NORMAL,
|
})
|
const instance = new Cesium.GeometryInstance({
|
geometry,
|
modelMatrix: Cesium.Transforms.eastNorthUpToFixedFrame(center),
|
})
|
return new Cesium.Primitive({
|
geometryInstances: instance,
|
appearance: new Cesium.MaterialAppearance({
|
material: material || createDeviceRangeMaterial(),
|
closed: true,
|
translucent: true,
|
flat: true,
|
faceForward: true,
|
}),
|
asynchronous: false
|
})
|
}
|
|
export const createDeviceRangePrimitive = async (viewer, position, rangeMeters, material = null) => {
|
if (!viewer) return null
|
const height = await resolveDeviceTerrainHeight(viewer, position)
|
return createDeviceRangePrimitiveWithHeight(position, rangeMeters, height, material)
|
}
|