From 89380e6260a75d1d3b94de687ebcc2f50d50659d Mon Sep 17 00:00:00 2001
From: shuishen <1109946754@qq.com>
Date: Tue, 03 Feb 2026 15:44:33 +0800
Subject: [PATCH] feat:环境变量配置调整
---
applications/drone-command/src/components/map-container/device-map-container.vue | 712 ++++++++++++++++++++++++++++++++++------------------------
1 files changed, 414 insertions(+), 298 deletions(-)
diff --git a/applications/drone-command/src/components/map-container/device-map-container.vue b/applications/drone-command/src/components/map-container/device-map-container.vue
index d877826..7819129 100644
--- a/applications/drone-command/src/components/map-container/device-map-container.vue
+++ b/applications/drone-command/src/components/map-container/device-map-container.vue
@@ -47,36 +47,40 @@
<script setup>
import * as Cesium from 'cesium'
import CommonCesiumMap from '@/components/map-container/common-cesium-map.vue'
-import { geomAnalysis } from '@ztzf/utils'
import { buildEllipsePositions } from '@/utils/cesium/shapeTools'
import { AREA_TYPE_STYLE_MAP, BUFFER_LEVEL_STYLES, DEFAULT_AREA_STYLE } from '@ztzf/constants'
-import { fwDefenseZonePageApi } from '@/views/areaManage/defenseZone/defenseZoneApi'
import { fwAreaDivideListApi } from '@/views/areaManage/partition/partitionApi'
-import { fwDefenseSceneListApi } from '@/views/areaManage/sceneConfig/sceneConfigApi'
-import { cockpitAggregationApi } from '@/api/dataCockpit'
+
+import { fwDefenseSceneManageListApi } from '@/views/areaManage/sceneManage/sceneManageApi'
+
+import { newCockpitAggregationApi } from '@/api/dataCockpit'
import layerControlIcon from '@/assets/images/dataCockpit/layerControl.png'
import equipmentIcon from '@/assets/images/dataCockpit/map/equipment.png'
+import offlineEquipmentIcon from '@/assets/images/dataCockpit/map/offline-equipment.png'
import droneIcon from '@/assets/images/dataCockpit/map/drone.png'
import aggregationIcon from '@/assets/images/dataCockpit/map/aggregation.png'
import commandPostIcon from '@/assets/images/dataCockpit/map/command-post.png'
import jaGeojsonRaw from '@/assets/geojson/ja.geojson?raw'
import DevicePopup from './components/DevicePopup.vue'
import DronePopup from './components/DronePopup.vue'
+import dayjs from 'dayjs'
import {
- RING_STYLES,
- addDeviceRings,
createDroneTrackMaterial,
createRadialGradientMaterial,
getTexturedVertexFormat,
} from './device-map-materials'
+import { getPointPositionsHeight } from '@/utils/cesium/mapUtil'
+import { createDeviceRangePrimitiveWithHeight } from '@/utils/cesium/deviceRange'
import dzIcon from '@/assets/images/dataCockpit/map/dz-map-layer.png'
import yxIcon from '@/assets/images/dataCockpit/map/yx-map-layer.png'
const CLUSTER_HEIGHT = 100000
const DETAIL_HEIGHT = 10000
+const POLYGON_HEIGHT_M = 0.2
+const DRONE_TRACK_DURATION_S = 30 * 60
const props = defineProps({
- onlineDevices: {
+ allDevices: {
type: Array,
default: () => [],
},
@@ -99,7 +103,6 @@
})
const emit = defineEmits(['droneSignal', 'droneCounter', 'droneFavorite'])
-const DEFAULT_ZONE_PAGE_SIZE = 999
const mapRef = ref(null)
let viewer = null
@@ -110,25 +113,28 @@
let deviceBillboardCollection = null
let deviceRingOutlinePrimitives = []
let deviceRingFillPrimitives = []
-let defenseZonePrimitive = null
-let defenseZoneOutlinePrimitive = null
-let partitionPrimitive = null
-let partitionOutlinePrimitive = null
+let partitionFillPrimitives = []
+let partitionOutlinePrimitives = []
let aggregationSource = null
let commandPostBillboardCollection = null
let droneTrackBillboardCollection = null
let droneTrackPolylineCollection = null
let droneTrackTickHandler = null
+let droneTrackRafId = null
let droneTrackStartTime = null
+let droneTrackAnimStartAt = 0
+let droneTrackLastTickAt = 0
let droneTrackRuntime = []
+let droneTrackSource = null
+let mapReadyHandled = false
let favoritePulseRafId = null
let favoritePulseStartAt = 0
let favoritePulseElapsed = 0
const favoritePulseEntities = []
const pulseBaseColor = Cesium.Color.fromCssColorString('#FF3B30')
-const PULSE_MIN_RADIUS_M = 60
-const PULSE_MAX_RADIUS_M = 180
-const PULSE_DURATION_S = 1.6
+const PULSE_MIN_RADIUS_M = 2
+const PULSE_MAX_RADIUS_M = 30
+const PULSE_DURATION_S = 1.4
const detailVisible = ref(true)
const clusterVisible = ref(false)
const countyCenterMap = new Map()
@@ -211,27 +217,105 @@
return canvas
}
+class PulseSphereMaterialProperty {
+ constructor(color, speed = 1.2, bands = 3.0, softness = 0.18) {
+ this._definitionChanged = new Cesium.Event()
+ this.color = color
+ this.speed = speed
+ this.bands = bands
+ this.softness = softness
+ }
+ get isConstant() {
+ return true
+ }
+ get definitionChanged() {
+ return this._definitionChanged
+ }
+ getType() {
+ return 'PulseSphereMaterial'
+ }
+ getValue(_time, result = {}) {
+ result.color = this.color
+ result.time = (performance.now() / 1000) * this.speed
+ result.bands = this.bands
+ result.softness = this.softness
+ return result
+ }
+ equals(other) {
+ return (
+ other instanceof PulseSphereMaterialProperty &&
+ Cesium.Color.equals(this.color, other.color) &&
+ this.speed === other.speed &&
+ this.bands === other.bands &&
+ this.softness === other.softness
+ )
+ }
+}
+
+let pulseSphereMaterial = null
+const getPulseSphereMaterial = () => {
+ if (pulseSphereMaterial) return pulseSphereMaterial
+ Cesium.Material._materialCache.addMaterial('PulseSphereMaterial', {
+ fabric: {
+ type: 'PulseSphereMaterial',
+ uniforms: {
+ color: pulseBaseColor.withAlpha(0.45),
+ time: 0,
+ bands: 3.0,
+ softness: 0.18,
+ },
+ source: `
+ czm_material czm_getMaterial(czm_materialInput materialInput)
+ {
+ czm_material material = czm_getDefaultMaterial(materialInput);
+ vec3 normalEC = normalize(materialInput.normalEC);
+ vec3 viewEC = normalize(-materialInput.positionToEyeEC);
+ float ndv = max(dot(normalEC, viewEC), 0.0);
+ float fresnel = pow(1.0 - ndv, 1.6);
+ float wave = sin((ndv * bands + time) * 6.2831853);
+ float ring = smoothstep(-softness, softness, wave);
+ float alpha = (ring * 0.6 + fresnel * 0.4) * color.a;
+ material.diffuse = color.rgb;
+ material.alpha = alpha;
+ return material;
+ }
+ `,
+ },
+ translucent: () => true,
+ })
+ pulseSphereMaterial = new PulseSphereMaterialProperty(pulseBaseColor.withAlpha(0.45), 1.1, 3.2, 0.22)
+ return pulseSphereMaterial
+}
+
const createFavoritePulseEntity = (billboard) => {
if (!viewer || !billboard) return
- const material = new Cesium.ImageMaterialProperty({
- image: getPulseCanvas(),
- transparent: true,
- })
+ const material = getPulseSphereMaterial()
const pulse = {
material,
offset: Math.random() * PULSE_DURATION_S,
entity: null,
}
+ const getPulseRadius3D = () => {
+ const radius = getPulseRadius(pulse)
+ return new Cesium.Cartesian3(radius, radius, radius)
+ }
pulse.entity = viewer.entities.add({
- position: new Cesium.CallbackProperty(() => billboard.position, false),
- ellipse: {
- semiMajorAxis: new Cesium.CallbackProperty(() => getPulseRadius(pulse), false),
- semiMinorAxis: new Cesium.CallbackProperty(() => getPulseRadius(pulse), false),
+ position: new Cesium.CallbackProperty(() => getBillboardPosition(billboard), false),
+ ellipsoid: {
+ radii: new Cesium.CallbackProperty(() => getPulseRadius3D(), false),
material,
- heightReference: Cesium.HeightReference.CLAMP_TO_GROUND,
},
})
favoritePulseEntities.push(pulse)
+}
+
+const getBillboardPosition = billboard => {
+ if (!viewer || !billboard) return null
+ const position = billboard.position
+ if (position?.getValue) {
+ return position.getValue(viewer.clock.currentTime)
+ }
+ return position
}
const getDevicePosition = item => {
@@ -251,6 +335,7 @@
if (!Number.isFinite(range) || range <= 0) return null
return range
}
+
const ensureCockpitPrimitiveLayer = () => {
if (!viewer) return
@@ -282,10 +367,12 @@
if (!viewer) return
ensureCockpitPrimitiveLayer()
cockpitPrimitiveLayer.removeAll(false)
- if (defenseZonePrimitive) cockpitPrimitiveLayer.add(defenseZonePrimitive)
- if (defenseZoneOutlinePrimitive) cockpitPrimitiveLayer.add(defenseZoneOutlinePrimitive)
- if (partitionPrimitive) cockpitPrimitiveLayer.add(partitionPrimitive)
- if (partitionOutlinePrimitive) cockpitPrimitiveLayer.add(partitionOutlinePrimitive)
+ if (partitionFillPrimitives.length) {
+ partitionFillPrimitives.forEach(primitive => cockpitPrimitiveLayer.add(primitive))
+ }
+ if (partitionOutlinePrimitives.length) {
+ partitionOutlinePrimitives.forEach(primitive => cockpitPrimitiveLayer.add(primitive))
+ }
if (deviceRingFillPrimitives.length) {
deviceRingFillPrimitives.forEach(primitive => cockpitPrimitiveLayer.add(primitive))
}
@@ -325,27 +412,16 @@
}
}
-const clearDefenseZoneEntities = () => {
- if (!viewer) return
- if (defenseZonePrimitive) {
- removeCockpitPrimitive(defenseZonePrimitive)
- defenseZonePrimitive = null
- }
- if (defenseZoneOutlinePrimitive) {
- removeCockpitPrimitive(defenseZoneOutlinePrimitive)
- defenseZoneOutlinePrimitive = null
- }
-}
const clearPartitionEntities = () => {
if (!viewer) return
- if (partitionPrimitive) {
- removeCockpitPrimitive(partitionPrimitive)
- partitionPrimitive = null
+ if (partitionFillPrimitives.length) {
+ partitionFillPrimitives.forEach(primitive => removeCockpitPrimitive(primitive))
+ partitionFillPrimitives = []
}
- if (partitionOutlinePrimitive) {
- removeCockpitPrimitive(partitionOutlinePrimitive)
- partitionOutlinePrimitive = null
+ if (partitionOutlinePrimitives.length) {
+ partitionOutlinePrimitives.forEach(primitive => removeCockpitPrimitive(primitive))
+ partitionOutlinePrimitives = []
}
}
@@ -380,10 +456,16 @@
const setDetailVisibility = visible => {
detailVisible.value = visible
- if (defenseZonePrimitive) defenseZonePrimitive.show = visible
- if (defenseZoneOutlinePrimitive) defenseZoneOutlinePrimitive.show = visible
- if (partitionPrimitive) partitionPrimitive.show = visible
- if (partitionOutlinePrimitive) partitionOutlinePrimitive.show = visible
+ if (partitionFillPrimitives.length) {
+ partitionFillPrimitives.forEach(primitive => {
+ primitive.show = visible
+ })
+ }
+ if (partitionOutlinePrimitives.length) {
+ partitionOutlinePrimitives.forEach(primitive => {
+ primitive.show = visible
+ })
+ }
if (commandPostBillboardCollection) commandPostBillboardCollection.show = visible
if (deviceBillboardCollection) deviceBillboardCollection.show = visible
if (deviceRingFillPrimitives.length) {
@@ -412,6 +494,7 @@
const setDroneVisibility = visible => {
if (droneTrackBillboardCollection) droneTrackBillboardCollection.show = visible
if (droneTrackPolylineCollection) droneTrackPolylineCollection.show = visible
+ if (droneTrackSource) droneTrackSource.show = visible
if (favoritePulseEntities.length) {
favoritePulseEntities.forEach(pulse => {
if (pulse?.entity) pulse.entity.show = visible
@@ -538,6 +621,10 @@
}
droneTrackPolylineCollection = null
}
+ if (droneTrackSource) {
+ viewer.dataSources.remove(droneTrackSource)
+ droneTrackSource = null
+ }
droneTrackRuntime = []
if (favoritePulseEntities.length) {
favoritePulseEntities.forEach(pulse => {
@@ -571,44 +658,96 @@
}
}
+const ensureDroneTrackSource = () => {
+ if (!viewer) return
+ if (!droneTrackSource) {
+ droneTrackSource = new Cesium.CustomDataSource('droneTrackSource')
+ viewer.dataSources.add(droneTrackSource)
+ }
+}
+
+const setupDroneTrackClock = () => {
+ if (!viewer) return
+ const startTime = Cesium.JulianDate.now()
+ const stopTime = Cesium.JulianDate.addSeconds(startTime, DRONE_TRACK_DURATION_S, new Cesium.JulianDate())
+ viewer.clock.startTime = startTime
+ viewer.clock.stopTime = stopTime
+ viewer.clock.currentTime = startTime
+ viewer.clock.multiplier = 1
+ viewer.clock.clockStep = Cesium.ClockStep.SYSTEM_CLOCK_MULTIPLIER
+ viewer.clock.clockRange = Cesium.ClockRange.CLAMPED
+}
+
+const updateDroneTrackPositions = elapsed => {
+ if (!viewer || !viewer.scene || !droneTrackRuntime.length) return
+ droneTrackRuntime.forEach(track => {
+ if (!track?.billboard || track.billboard.isDestroyed?.()) return
+ if (!track?.polyline) return
+ if (!track.positions || track.positions.length < 2) return
+ const duration = track.duration
+ if (duration <= 0) return
+ const t = Math.min(Math.max(elapsed, 0), duration)
+ const seg = Math.min(track.positions.length - 2, Math.floor(t / track.segmentDuration))
+ const ratio = (t - seg * track.segmentDuration) / track.segmentDuration
+ const isEntityPosition = typeof track.billboard?.position?.getValue === 'function'
+ const pos = isEntityPosition
+ ? getBillboardPosition(track.billboard)
+ : Cesium.Cartesian3.lerp(
+ track.positions[seg],
+ track.positions[seg + 1],
+ ratio,
+ new Cesium.Cartesian3()
+ )
+ if (!pos) return
+ if (!isEntityPosition) {
+ track.billboard.position = pos
+ }
+ const pathCount = Math.min(track.positions.length - 1, Math.floor(t / track.segmentDuration))
+ const pathPositions = track.positions.slice(0, pathCount + 1)
+ track.polyline.positions = [...pathPositions, pos]
+ })
+}
+
const startDroneTrackAnimation = () => {
if (!viewer) return
stopDroneTrackAnimation()
- droneTrackStartTime = Cesium.JulianDate.now()
- droneTrackTickHandler = clock => {
- if (!viewer || viewer.isDestroyed?.() || !viewer.scene) {
- stopDroneTrackAnimation()
+ droneTrackStartTime = viewer.clock.startTime
+ viewer.clock.shouldAnimate = true
+ droneTrackAnimStartAt = performance.now()
+ droneTrackLastTickAt = droneTrackAnimStartAt
+ const renderTick = now => {
+ if (!viewer || viewer.isDestroyed?.()) {
+ droneTrackRafId = null
return
}
- if (!droneTrackRuntime.length) return
- const current = clock.currentTime
- const elapsed = Cesium.JulianDate.secondsDifference(current, droneTrackStartTime)
- droneTrackRuntime.forEach(track => {
- if (!track?.billboard || track.billboard.isDestroyed?.()) return
- if (!track.billboard._scene) return
- if (!track.positions || track.positions.length < 2) return
- const duration = track.duration
- if (duration <= 0) return
- const t = ((elapsed % duration) + duration) % duration
- const seg = Math.min(track.positions.length - 2, Math.floor(t / track.segmentDuration))
- const ratio = (t - seg * track.segmentDuration) / track.segmentDuration
- const pos = Cesium.Cartesian3.lerp(
- track.positions[seg],
- track.positions[seg + 1],
- ratio,
- new Cesium.Cartesian3()
+ const deltaSeconds = Math.max(0, (now - droneTrackLastTickAt) / 1000)
+ droneTrackLastTickAt = now
+ if (viewer.clock?.currentTime && viewer.clock?.stopTime) {
+ const nextTime = Cesium.JulianDate.addSeconds(
+ viewer.clock.currentTime,
+ deltaSeconds * (viewer.clock.multiplier || 1),
+ new Cesium.JulianDate()
)
- track.billboard.position = pos
- })
+ if (Cesium.JulianDate.greaterThan(nextTime, viewer.clock.stopTime)) {
+ viewer.clock.currentTime = viewer.clock.stopTime
+ } else {
+ viewer.clock.currentTime = nextTime
+ }
+ }
+ const elapsed = Cesium.JulianDate.secondsDifference(viewer.clock.currentTime, droneTrackStartTime)
+ updateDroneTrackPositions(elapsed)
+ viewer.scene?.requestRender?.()
+ droneTrackRafId = requestAnimationFrame(renderTick)
}
- viewer.clock.onTick.addEventListener(droneTrackTickHandler)
- viewer.clock.shouldAnimate = true
+ droneTrackRafId = requestAnimationFrame(renderTick)
}
const stopDroneTrackAnimation = () => {
- if (!viewer || !droneTrackTickHandler) return
- viewer.clock.onTick.removeEventListener(droneTrackTickHandler)
droneTrackTickHandler = null
+ if (droneTrackRafId) {
+ cancelAnimationFrame(droneTrackRafId)
+ droneTrackRafId = null
+ }
}
const startFavoritePulseAnimation = () => {
@@ -638,10 +777,11 @@
clearDroneTrackEntities()
if (!list?.length) return
ensureDroneTrackCollections()
+ ensureDroneTrackSource()
+ setupDroneTrackClock()
droneTrackBillboardCollection.show = detailVisible.value
droneTrackPolylineCollection.show = detailVisible.value
droneTrackRuntime = []
- const segmentDuration = 6
const baseTrackColor = Cesium.Color.fromCssColorString('red')
; (list || []).forEach((item, trackIndex) => {
const position = getDevicePosition(item)
@@ -651,6 +791,7 @@
const positions = points.map(point =>
Cesium.Cartesian3.fromDegrees(point.longitude, point.latitude, point.height)
)
+ const segmentDuration = DRONE_TRACK_DURATION_S / Math.max(positions.length - 1, 1)
let trackMaterial = createDroneTrackMaterial({
color: baseTrackColor,
speed: 4.5,
@@ -661,49 +802,73 @@
if (!trackMaterial) {
trackMaterial = Cesium.Material.fromType('Color', { color: baseTrackColor })
}
- droneTrackPolylineCollection.add({
- positions,
+ const polyline = droneTrackPolylineCollection.add({
+ positions: [positions[0]],
width: 3,
material: trackMaterial,
})
const droneId = `drone-alarm-${item?.alarmRecordId ?? item?.id ?? trackIndex}`
- const billboard = droneTrackBillboardCollection.add({
- position: positions[positions.length - 1],
- image: droneIcon,
- width: 36,
- height: 36,
- verticalOrigin: Cesium.VerticalOrigin.CENTER,
- disableDepthTestDistance: Number.POSITIVE_INFINITY,
+ const startTime = viewer.clock.startTime
+ const stopTime = viewer.clock.stopTime
+ const positionProperty = new Cesium.SampledPositionProperty()
+ positions.forEach((pos, index) => {
+ const sampleTime = Cesium.JulianDate.addSeconds(
+ startTime,
+ index * segmentDuration,
+ new Cesium.JulianDate()
+ )
+ positionProperty.addSample(sampleTime, pos)
})
- billboard.id = droneId
+ positionProperty.setInterpolationOptions({
+ interpolationDegree: 1,
+ interpolationAlgorithm: Cesium.LinearApproximation,
+ })
+ const entity = droneTrackSource.entities.add({
+ id: droneId,
+ availability: new Cesium.TimeIntervalCollection([
+ new Cesium.TimeInterval({
+ start: startTime,
+ stop: stopTime,
+ }),
+ ]),
+ position: positionProperty,
+ orientation: new Cesium.VelocityOrientationProperty(positionProperty),
+ billboard: {
+ image: droneIcon,
+ width: 36,
+ height: 36,
+ verticalOrigin: Cesium.VerticalOrigin.CENTER,
+ disableDepthTestDistance: Number.POSITIVE_INFINITY,
+ },
+ })
const speedMs = Math.round(Cesium.Cartesian3.distance(positions[0], positions[1]) / segmentDuration)
- dronePickMap.set(droneId, {
- data: {
- ...item,
- flightHeightM: item.flightHeightM ?? points[0].height,
- flightSpeedMs: item.flightSpeedMs ?? speedMs,
- longitude: item.longitude ?? points[0].longitude,
- latitude: item.latitude ?? points[0].latitude,
- },
- billboard,
- })
- if (isFavorited(item)) {
- createFavoritePulseEntity(billboard)
- }
+ dronePickMap.set(droneId, {
+ data: {
+ ...item,
+ flightHeightM: item.flightHeightM ?? points[0].height,
+ flightSpeedMs: item.flightSpeedMs ?? speedMs,
+ longitude: item.longitude ?? points[0].longitude,
+ latitude: item.latitude ?? points[0].latitude,
+ },
+ billboard: entity,
+ })
+ if (isFavorited(item)) {
+ createFavoritePulseEntity(entity)
+ }
droneTrackRuntime.push({
positions,
- billboard,
+ polyline,
+ billboard: entity,
segmentDuration,
- duration: (points.length - 1) * segmentDuration,
+ duration: DRONE_TRACK_DURATION_S,
})
})
- viewer.clock.multiplier = 1
startDroneTrackAnimation()
startFavoritePulseAnimation()
reorderCockpitPrimitives()
}
-const renderDeviceEntities = devices => {
+const renderDeviceEntities = async devices => {
if (!viewer) return
ensureCockpitPrimitiveLayer()
ensureDeviceCollections()
@@ -718,195 +883,154 @@
}
devicePickMap.clear()
deviceBillboardCollection.show = detailVisible.value
- const ringFillInstancesByStyle = RING_STYLES.map(() => [])
- const ringOutlineInstancesByStyle = RING_STYLES.map(() => [])
+ const deviceEntries = []
+ const devicePositions = []
devices.forEach((item, index) => {
+ const isOnline = String(item.status) === '0'
+
const position = getDevicePosition(item)
if (!position) return
const entityId = `online-device-${item.id ?? index}-${index}`
const rangeMeters = getDeviceRange(item)
- addDeviceRings(position, ringFillInstancesByStyle, ringOutlineInstancesByStyle, rangeMeters)
+ devicePositions.push({ lng: position.longitude, lat: position.latitude })
const billboard = deviceBillboardCollection.add({
position: Cesium.Cartesian3.fromDegrees(position.longitude, position.latitude, 0),
- image: equipmentIcon,
+ image: isOnline ? equipmentIcon : offlineEquipmentIcon,
width: 40,
height: 56,
verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
})
billboard.id = entityId
devicePickMap.set(entityId, { data: item, billboard })
+ deviceEntries.push({ position, rangeMeters, billboard, isOnline })
})
if (selectedTargetType.value === 'device' && selectedDeviceBillboard && !devicePickMap.has(selectedDeviceBillboard.id)) {
closePopup()
}
- ringFillInstancesByStyle.forEach((instances, index) => {
- if (!instances.length) return
- const ring = RING_STYLES[index]
- const alpha = ring.alpha ?? 0.64
- const innerRatio =
- typeof ring.innerRatio === 'number'
- ? ring.innerRatio
- : ring.inner && ring.outer
- ? Math.min(Math.max(ring.inner / ring.outer, 0), 0.9)
- : 0
- const material = createRadialGradientMaterial(
- Cesium.Color.fromCssColorString(ring.gradient[0]).withAlpha(alpha),
- Cesium.Color.fromCssColorString(ring.gradient[1]).withAlpha(alpha),
- {
- gamma: 1.7,
- innerCutoff: innerRatio,
+ if (deviceEntries.length) {
+ const heights = await getPointPositionsHeight(devicePositions, viewer)
+ deviceEntries.forEach((entry, index) => {
+ const height = Number(heights?.[index]?.ASL)
+ const centerHeight = Number.isFinite(height) ? height : 0
+ if (entry.billboard) {
+ entry.billboard.position = Cesium.Cartesian3.fromDegrees(
+ entry.position.longitude,
+ entry.position.latitude,
+ centerHeight
+ )
}
- )
- const primitive = new Cesium.GroundPrimitive({
- geometryInstances: instances,
- appearance: new Cesium.MaterialAppearance({
- material,
- translucent: true,
- }),
+ if (!entry.isOnline) return
+ if (!Number.isFinite(entry.rangeMeters) || entry.rangeMeters <= 0) return
+ const primitive = createDeviceRangePrimitiveWithHeight(entry.position, entry.rangeMeters, centerHeight)
+ if (!primitive) return
+ primitive.show = detailVisible.value
+ addCockpitPrimitive(primitive)
+ deviceRingFillPrimitives.push(primitive)
})
- primitive.show = detailVisible.value
- addCockpitPrimitive(primitive)
- deviceRingFillPrimitives.push(primitive)
- })
- ringOutlineInstancesByStyle.forEach(instances => {
- if (!instances.length) return
- const primitive = new Cesium.GroundPolylinePrimitive({
- geometryInstances: instances,
- appearance: new Cesium.PolylineColorAppearance(),
- })
- primitive.show = detailVisible.value
- addCockpitPrimitive(primitive)
- deviceRingOutlinePrimitives.push(primitive)
- })
+ }
reorderCockpitPrimitives()
}
-const getDefenseZonePositions = geom => {
- const points = geomAnalysis(geom)
- if (points.length < 3) return []
- const first = points[0]
- const last = points[points.length - 1]
- const list =
- first && last && first.longitude === last.longitude && first.latitude === last.latitude
- ? points.slice(0, -1)
- : points
- return list.map(item => Cesium.Cartesian3.fromDegrees(item.longitude, item.latitude))
+const elevatePositions = async (positions, height = POLYGON_HEIGHT_M) => {
+ if (!Array.isArray(positions) || !positions.length) return []
+ if (!viewer) return positions
+ const points = positions
+ .map(pos => {
+ const carto = Cesium.Cartographic.fromCartesian(pos)
+ if (!carto) return null
+ return {
+ lng: Cesium.Math.toDegrees(carto.longitude),
+ lat: Cesium.Math.toDegrees(carto.latitude),
+ }
+ })
+ .filter(Boolean)
+ if (!points.length) return positions
+ const heights = await getPointPositionsHeight(points, viewer)
+ return heights.map(item => Cesium.Cartesian3.fromDegrees(item.longitude, item.latitude, (item.ASL ?? 0) + height))
}
const getAreaTypeStyle = areaType => {
return AREA_TYPE_STYLE_MAP?.[String(areaType)] || DEFAULT_AREA_STYLE
}
-const buildZonePrimitives = (zones, lineColor, fillColor1, fillColor2) => {
- if (!viewer) return { primitive: null, outlinePrimitive: null }
- const polygonInstances = []
- const lineInstances = []
- const texturedVertexFormat = getTexturedVertexFormat()
- ; (zones || []).forEach((zone, index) => {
- if (!zone?.geom) return
- const positions = getDefenseZonePositions(zone.geom)
- if (!positions.length) return
- const polygon = new Cesium.PolygonGeometry({
- polygonHierarchy: new Cesium.PolygonHierarchy(positions),
- vertexFormat: texturedVertexFormat,
- })
- polygonInstances.push(
- new Cesium.GeometryInstance({
- geometry: polygon,
- })
- )
- const linePositions = positions.length > 1 ? [...positions, positions[0]] : positions
- lineInstances.push(
- new Cesium.GeometryInstance({
- geometry: new Cesium.GroundPolylineGeometry({
- positions: linePositions,
- width: 2,
- }),
- attributes: {
- color: Cesium.ColorGeometryInstanceAttribute.fromColor(
- Cesium.Color.fromCssColorString(lineColor)
- ),
- },
- })
- )
- })
- let primitive = null
- if (polygonInstances.length) {
- const baseColor1 = Cesium.Color.fromCssColorString(fillColor1)
- const baseColor2 = Cesium.Color.fromCssColorString(fillColor2)
- const material = createRadialGradientMaterial(baseColor1.withAlpha(0.64), baseColor2.withAlpha(0.64))
- primitive = new Cesium.GroundPrimitive({
- geometryInstances: polygonInstances,
- appearance: new Cesium.MaterialAppearance({
- material,
- translucent: true,
- }),
- })
- addCockpitPrimitive(primitive)
- }
- let outlinePrimitive = null
- if (lineInstances.length) {
- outlinePrimitive = new Cesium.GroundPolylinePrimitive({
- geometryInstances: lineInstances,
- appearance: new Cesium.PolylineColorAppearance(),
- })
- addCockpitPrimitive(outlinePrimitive)
- }
- return { primitive, outlinePrimitive }
-}
-
-const buildPartitionPrimitives = shapes => {
- if (!viewer) return { primitive: null, outlinePrimitive: null }
- const polygonInstances = []
- const lineInstances = []
- const vertexFormat = Cesium.PerInstanceColorAppearance.VERTEX_FORMAT
+const buildPartitionPrimitives = async shapes => {
+ if (!viewer) return { primitives: [], outlinePrimitives: [] }
+ const vertexFormat = getTexturedVertexFormat()
+ const groups = new Map()
+ const tasks = []
; (shapes || []).forEach(shape => {
if (!shape?.positions || shape.positions.length < 3) return
+ const outlineColor = shape.outlineColor
+ const fillColor = shape.fillColor
+ const key = `${outlineColor.toCssColorString()}|${fillColor.toCssColorString()}`
+ if (!groups.has(key)) {
+ groups.set(key, { outlineColor, fillColor, polygonInstances: [], lineInstances: [] })
+ }
+ const group = groups.get(key)
const positions = shape.positions
- const polygon = new Cesium.PolygonGeometry({
- polygonHierarchy: new Cesium.PolygonHierarchy(positions),
- vertexFormat,
+ tasks.push(
+ elevatePositions(positions).then(elevatedPositions => {
+ if (!elevatedPositions.length) return
+ const polygon = new Cesium.PolygonGeometry({
+ polygonHierarchy: new Cesium.PolygonHierarchy(elevatedPositions),
+ perPositionHeight: true,
+ vertexFormat,
+ })
+ group.polygonInstances.push(
+ new Cesium.GeometryInstance({
+ geometry: polygon,
+ })
+ )
+ const linePositions =
+ elevatedPositions.length > 1
+ ? [...elevatedPositions, elevatedPositions[0]]
+ : elevatedPositions
+ group.lineInstances.push(
+ new Cesium.GeometryInstance({
+ geometry: new Cesium.PolylineGeometry({
+ positions: linePositions,
+ width: 2,
+ }),
+ attributes: {
+ color: Cesium.ColorGeometryInstanceAttribute.fromColor(outlineColor),
+ },
+ })
+ )
+ })
+ )
+ })
+
+ if (tasks.length) await Promise.all(tasks)
+
+ const primitives = []
+ const outlinePrimitives = []
+ groups.forEach(group => {
+ if (group.polygonInstances.length) {
+ const material = createRadialGradientMaterial(group.outlineColor, group.fillColor, {
+ gamma: 1.7,
+ innerCutoff: 0,
})
- polygonInstances.push(
- new Cesium.GeometryInstance({
- geometry: polygon,
- attributes: {
- color: Cesium.ColorGeometryInstanceAttribute.fromColor(shape.fillColor),
- },
- })
- )
- const linePositions = positions.length > 1 ? [...positions, positions[0]] : positions
- lineInstances.push(
- new Cesium.GeometryInstance({
- geometry: new Cesium.GroundPolylineGeometry({
- positions: linePositions,
- width: 2,
- }),
- attributes: {
- color: Cesium.ColorGeometryInstanceAttribute.fromColor(
- shape.outlineColor
- ),
- },
- })
- )
- })
- let primitive = null
- if (polygonInstances.length) {
- primitive = new Cesium.GroundPrimitive({
- geometryInstances: polygonInstances,
- appearance: new Cesium.PerInstanceColorAppearance({ translucent: true, flat: true }),
- })
- addCockpitPrimitive(primitive)
- }
- let outlinePrimitive = null
- if (lineInstances.length) {
- outlinePrimitive = new Cesium.GroundPolylinePrimitive({
- geometryInstances: lineInstances,
- appearance: new Cesium.PolylineColorAppearance(),
- })
- addCockpitPrimitive(outlinePrimitive)
- }
- return { primitive, outlinePrimitive }
+ const primitive = new Cesium.Primitive({
+ geometryInstances: group.polygonInstances,
+ appearance: new Cesium.MaterialAppearance({
+ material,
+ translucent: true,
+ }),
+ })
+ addCockpitPrimitive(primitive)
+ primitives.push(primitive)
+ }
+ if (group.lineInstances.length) {
+ const outlinePrimitive = new Cesium.Primitive({
+ geometryInstances: group.lineInstances,
+ appearance: new Cesium.PolylineColorAppearance(),
+ })
+ addCockpitPrimitive(outlinePrimitive)
+ outlinePrimitives.push(outlinePrimitive)
+ }
+ })
+
+ return { primitives, outlinePrimitives }
}
const parseGeomJson = geomJson => {
@@ -995,46 +1119,36 @@
return shapes
}
-const renderDefenseZones = zones => {
- if (!viewer) return
- clearDefenseZoneEntities()
- const result = buildZonePrimitives(zones, '#72F3FF', '#72F3FF', '#0A7C88')
- defenseZonePrimitive = result.primitive
- defenseZoneOutlinePrimitive = result.outlinePrimitive
- if (defenseZonePrimitive) defenseZonePrimitive.show = detailVisible.value
- if (defenseZoneOutlinePrimitive) defenseZoneOutlinePrimitive.show = detailVisible.value
- reorderCockpitPrimitives()
-}
-
-const renderPartitions = zones => {
+const renderPartitions = async zones => {
if (!viewer) return
clearPartitionEntities()
const shapes = resolvePartitionShapes(zones)
- const result = buildPartitionPrimitives(shapes)
- partitionPrimitive = result.primitive
- partitionOutlinePrimitive = result.outlinePrimitive
- if (partitionPrimitive) partitionPrimitive.show = detailVisible.value
- if (partitionOutlinePrimitive) partitionOutlinePrimitive.show = detailVisible.value
- reorderCockpitPrimitives()
-}
-
-const loadDefenseZones = async () => {
- if (!viewer) return
- try {
- const res = await fwDefenseZonePageApi({ current: 1, size: DEFAULT_ZONE_PAGE_SIZE })
- renderDefenseZones(res?.data?.data?.records ?? [])
- } catch (error) {
- renderDefenseZones([])
+ const result = await buildPartitionPrimitives(shapes)
+ partitionFillPrimitives = result.primitives
+ partitionOutlinePrimitives = result.outlinePrimitives
+ if (partitionFillPrimitives.length) {
+ partitionFillPrimitives.forEach(primitive => {
+ primitive.show = detailVisible.value
+ })
}
+ if (partitionOutlinePrimitives.length) {
+ partitionOutlinePrimitives.forEach(primitive => {
+ primitive.show = detailVisible.value
+ })
+ }
+ reorderCockpitPrimitives()
}
const loadPartitions = async () => {
if (!viewer) return
try {
- const res = await fwAreaDivideListApi()
- renderPartitions(res?.data?.data ?? [])
+ const res = await fwAreaDivideListApi({
+ isSetSceneManage: 1,
+ flyTime: dayjs().format('YYYY-MM-DD HH:mm:ss'),
+ })
+ await renderPartitions(res?.data?.data ?? [])
} catch (error) {
- renderPartitions([])
+ await renderPartitions([])
}
}
@@ -1097,7 +1211,7 @@
const updatePopupPosition = () => {
if (!viewer || !selectedDeviceBillboard) return
- const cartesian = selectedDeviceBillboard.position
+ const cartesian = getBillboardPosition(selectedDeviceBillboard)
if (!cartesian) return
const screenPosition = viewer.scene.cartesianToCanvasCoordinates(cartesian)
if (!screenPosition) return
@@ -1181,7 +1295,7 @@
const loadAggregation = async () => {
try {
- const res = await cockpitAggregationApi({
+ const res = await newCockpitAggregationApi({
effectiveRangeKmIsNotNull: 1
})
renderAggregation(res?.data?.data ?? [])
@@ -1192,7 +1306,9 @@
const loadCommandPosts = async () => {
try {
- const res = await fwDefenseSceneListApi()
+ const res = await fwDefenseSceneManageListApi({
+ time: dayjs().format('YYYY-MM-DD HH:mm:ss')
+ })
renderCommandPosts(res?.data?.data ?? [])
} catch (error) {
renderCommandPosts([])
@@ -1201,7 +1317,7 @@
watch(
- () => props.onlineDevices,
+ () => props.allDevices,
devices => {
renderDeviceEntities(devices || [])
},
@@ -1264,6 +1380,8 @@
}
const handleMapReady = ({ viewer: mapViewer, publicCesium: mapPublic }) => {
+ if (mapReadyHandled) return
+ mapReadyHandled = true
viewer = mapViewer
publicCesium = mapPublic
ensureCockpitPrimitiveLayer()
@@ -1271,8 +1389,7 @@
const height = viewer?.camera?.positionCartographic?.height
const stage = getStageByHeight(height)
updateStageDisplay(stage)
- renderDeviceEntities(props.onlineDevices)
- loadDefenseZones()
+ renderDeviceEntities(props.allDevices)
loadPartitions()
loadAggregation()
loadCommandPosts()
@@ -1300,7 +1417,6 @@
onBeforeUnmount(() => {
document.removeEventListener('click', handleClickOutside)
clearDeviceEntities()
- clearDefenseZoneEntities()
clearPartitionEntities()
clearAggregationEntities()
clearCommandPostEntities()
--
Gitblit v1.9.3