From cb43af5c2caf2184bbf1a8e417f44e9aeaa2fdd9 Mon Sep 17 00:00:00 2001
From: shuishen <1109946754@qq.com>
Date: Thu, 29 Jan 2026 13:38:20 +0800
Subject: [PATCH] feat:增加设备特效椭球

---
 applications/drone-command/src/views/areaManage/partition/shapeTools/edit/EditBufferCircleTool.js |  235 ++++++++++++++++++++++++++++++++++++++++++++++++++--------
 1 files changed, 201 insertions(+), 34 deletions(-)

diff --git a/applications/drone-command/src/views/areaManage/partition/shapeTools/edit/EditBufferCircleTool.js b/applications/drone-command/src/views/areaManage/partition/shapeTools/edit/EditBufferCircleTool.js
index abf1a5e..61e40b4 100644
--- a/applications/drone-command/src/views/areaManage/partition/shapeTools/edit/EditBufferCircleTool.js
+++ b/applications/drone-command/src/views/areaManage/partition/shapeTools/edit/EditBufferCircleTool.js
@@ -1,4 +1,4 @@
-import * as Cesium from 'cesium'
+import * as Cesium from 'cesium'
 import { MapTooltip } from '../Tooltip'
 import { ToolBase } from '../ToolBase'
 import { buildEllipsePositions, cartesianToLocal } from '../shapeUtils'
@@ -9,26 +9,71 @@
 		lat: point.lat ?? point.latitude,
 	}))
 
+const resolveLngLat = point => {
+	if (!point) return null
+	const lng = point.lng ?? point.longitude
+	const lat = point.lat ?? point.latitude
+	if (Number.isFinite(lng) && Number.isFinite(lat)) {
+		return { lng: Number(lng), lat: Number(lat), height: Number(point.height) || 0 }
+	}
+	return null
+}
+
+const resolveCartesian = point => {
+	if (!point) return null
+	if (Number.isFinite(point.x) && Number.isFinite(point.y) && Number.isFinite(point.z)) {
+		return new Cesium.Cartesian3(point.x, point.y, point.z)
+	}
+	const lngLat = resolveLngLat(point)
+	if (!lngLat) return null
+	return Cesium.Cartesian3.fromDegrees(lngLat.lng, lngLat.lat, lngLat.height || 0)
+}
+
 export class EditBufferCircleTool extends ToolBase {
 	constructor(viewer) {
 		super(viewer)
 		this.tooltip = new MapTooltip(viewer)
 		this.dataSource = null
 		this.centerCartesian = null
-		this.radius = 0
+		this.radiusLevel1 = 0
+		this.radiusLevel2 = 0
+		this.radiusLevel3 = 0
 		this.dragType = null
-		this.circleEntity = null
+		this.circleLevel1Entity = null
+		this.circleLevel2Entity = null
+		this.circleLevel3Entity = null
+		this.circleLevel1OutlineEntity = null
+		this.circleLevel2OutlineEntity = null
+		this.circleLevel3OutlineEntity = null
 		this.centerEntity = null
-		this.radiusEntity = null
+		this.radiusLevel1Entity = null
+		this.radiusLevel2Entity = null
+		this.radiusLevel3Entity = null
 	}
 
-	start(points = []) {
-		const normalized = normalizePoints(points)
-		if (!normalized.length) return
-		const centerLng = normalized.reduce((sum, p) => sum + p.lng, 0) / normalized.length
-		const centerLat = normalized.reduce((sum, p) => sum + p.lat, 0) / normalized.length
-		this.centerCartesian = Cesium.Cartesian3.fromDegrees(centerLng, centerLat)
-		this.radius = this.estimateRadius(normalized)
+	start(data = []) {
+		const inputPoints = Array.isArray(data?.points) ? data.points : data
+		const normalized = normalizePoints(inputPoints)
+		const metaCenter = resolveCartesian(data?.meta?.center)
+		if (metaCenter) {
+			this.centerCartesian = metaCenter
+		} else {
+			if (!normalized.length) return
+			const centerLng = normalized.reduce((sum, p) => sum + p.lng, 0) / normalized.length
+			const centerLat = normalized.reduce((sum, p) => sum + p.lat, 0) / normalized.length
+			this.centerCartesian = Cesium.Cartesian3.fromDegrees(centerLng, centerLat)
+		}
+		const radii = Array.isArray(data?.meta?.bufferRadii) ? data.meta.bufferRadii : null
+		if (radii?.length) {
+			const [r1, r2, r3] = radii
+			this.radiusLevel1 = Number.isFinite(r1) && r1 > 0 ? r1 : 1
+			this.radiusLevel2 = Number.isFinite(r2) && r2 > 0 ? Math.max(r2, this.radiusLevel1) : this.radiusLevel1
+			this.radiusLevel3 = Number.isFinite(r3) && r3 > 0 ? Math.max(r3, this.radiusLevel2) : this.radiusLevel2
+		} else {
+			this.radiusLevel3 = this.estimateRadius(normalized)
+			this.radiusLevel2 = this.radiusLevel3
+			this.radiusLevel1 = this.radiusLevel3
+		}
 
 		this.dataSource = new Cesium.CustomDataSource('edit-buffer-circle')
 		this.viewer.dataSources.add(this.dataSource)
@@ -59,7 +104,9 @@
 		const picked = this.viewer.scene.pick(evt.position)?.id
 		if (!picked) return
 		if (picked.customType === 'circle-center') this.dragType = 'center'
-		if (picked.customType === 'circle-radius') this.dragType = 'radius'
+		if (picked.customType === 'circle-radius-1') this.dragType = 'radius-1'
+		if (picked.customType === 'circle-radius-2') this.dragType = 'radius-2'
+		if (picked.customType === 'circle-radius-3') this.dragType = 'radius-3'
 		if (this.dragType) this.disableMapControl()
 	}
 
@@ -71,34 +118,114 @@
 
 		if (this.dragType === 'center') {
 			this.centerCartesian = position
-			this.updateRadiusPoint()
+			this.updateRadiusPoints()
 			return
 		}
 
 		const local = cartesianToLocal(this.centerCartesian, position)
-		this.radius = Math.max(1, Math.sqrt(local.x * local.x + local.y * local.y))
-		this.updateRadiusPoint()
+		const radius = Math.max(1, Math.sqrt(local.x * local.x + local.y * local.y))
+		if (this.dragType === 'radius-1') {
+			this.radiusLevel1 = radius
+			if (this.radiusLevel2 < this.radiusLevel1) this.radiusLevel2 = this.radiusLevel1
+			if (this.radiusLevel3 < this.radiusLevel2) this.radiusLevel3 = this.radiusLevel2
+		}
+		if (this.dragType === 'radius-2') {
+			this.radiusLevel2 = Math.max(radius, this.radiusLevel1)
+			if (this.radiusLevel3 < this.radiusLevel2) this.radiusLevel3 = this.radiusLevel2
+		}
+		if (this.dragType === 'radius-3') {
+			this.radiusLevel3 = Math.max(radius, this.radiusLevel2)
+		}
+		this.updateRadiusPoints()
 	}
 
 	handleLeftUp() {
 		if (!this.dragType) return
 		this.dragType = null
 		this.enableMapControl()
-		const positions = buildEllipsePositions(this.centerCartesian, this.radius, this.radius)
-		this.notify('getPolygonPositions', positions)
+		const positions = buildEllipsePositions(this.centerCartesian, this.radiusLevel3, this.radiusLevel3)
+		this.notify('getPolygonPositions', {
+			positions,
+			meta: {
+				center: this.centerCartesian,
+				bufferRadii: [this.radiusLevel1, this.radiusLevel2, this.radiusLevel3],
+				controlPoints: [
+					this.centerCartesian,
+					this.getRadiusPoint(this.radiusLevel1),
+					this.getRadiusPoint(this.radiusLevel2),
+					this.getRadiusPoint(this.radiusLevel3),
+				],
+			},
+		})
 	}
 
 	createEntities() {
-		this.circleEntity = this.dataSource.entities.add({
+		this.circleLevel1Entity = this.dataSource.entities.add({
 			position: new Cesium.CallbackProperty(() => this.centerCartesian, false),
 			ellipse: {
-				semiMajorAxis: new Cesium.CallbackProperty(() => this.radius, false),
-				semiMinorAxis: new Cesium.CallbackProperty(() => this.radius, false),
-				material: Cesium.Color.fromBytes(45, 140, 240, 99),
-				outline: true,
-				outlineColor: Cesium.Color.fromBytes(45, 140, 240, 255),
-				outlineWidth: 2,
+				semiMajorAxis: new Cesium.CallbackProperty(() => this.radiusLevel1, false),
+				semiMinorAxis: new Cesium.CallbackProperty(() => this.radiusLevel1, false),
+				material: Cesium.Color.fromBytes(247, 20, 20, 128),
+				outline: false,
 				heightReference: Cesium.HeightReference.CLAMP_TO_GROUND,
+			},
+		})
+		this.circleLevel1OutlineEntity = this.dataSource.entities.add({
+			polyline: {
+				positions: new Cesium.CallbackProperty(() => {
+					if (!this.centerCartesian || this.radiusLevel1 <= 0) return []
+					const positions = buildEllipsePositions(this.centerCartesian, this.radiusLevel1, this.radiusLevel1)
+					return positions.length ? [...positions, positions[0]] : positions
+				}, false),
+				clampToGround: true,
+				width: 2,
+				material: Cesium.Color.fromBytes(255, 0, 0, 255),
+			},
+		})
+
+		this.circleLevel2Entity = this.dataSource.entities.add({
+			position: new Cesium.CallbackProperty(() => this.centerCartesian, false),
+			ellipse: {
+				semiMajorAxis: new Cesium.CallbackProperty(() => this.radiusLevel2, false),
+				semiMinorAxis: new Cesium.CallbackProperty(() => this.radiusLevel2, false),
+				material: Cesium.Color.fromBytes(255, 235, 59, 128),
+				outline: false,
+				heightReference: Cesium.HeightReference.CLAMP_TO_GROUND,
+			},
+		})
+		this.circleLevel2OutlineEntity = this.dataSource.entities.add({
+			polyline: {
+				positions: new Cesium.CallbackProperty(() => {
+					if (!this.centerCartesian || this.radiusLevel2 <= 0) return []
+					const positions = buildEllipsePositions(this.centerCartesian, this.radiusLevel2, this.radiusLevel2)
+					return positions.length ? [...positions, positions[0]] : positions
+				}, false),
+				clampToGround: true,
+				width: 2,
+				material: Cesium.Color.fromBytes(255, 235, 59, 255),
+			},
+		})
+
+		this.circleLevel3Entity = this.dataSource.entities.add({
+			position: new Cesium.CallbackProperty(() => this.centerCartesian, false),
+			ellipse: {
+				semiMajorAxis: new Cesium.CallbackProperty(() => this.radiusLevel3, false),
+				semiMinorAxis: new Cesium.CallbackProperty(() => this.radiusLevel3, false),
+				material: Cesium.Color.fromBytes(25, 178, 230, 128),
+				outline: false,
+				heightReference: Cesium.HeightReference.CLAMP_TO_GROUND,
+			},
+		})
+		this.circleLevel3OutlineEntity = this.dataSource.entities.add({
+			polyline: {
+				positions: new Cesium.CallbackProperty(() => {
+					if (!this.centerCartesian || this.radiusLevel3 <= 0) return []
+					const positions = buildEllipsePositions(this.centerCartesian, this.radiusLevel3, this.radiusLevel3)
+					return positions.length ? [...positions, positions[0]] : positions
+				}, false),
+				clampToGround: true,
+				width: 2,
+				material: Cesium.Color.fromBytes(0, 251, 255, 255),
 			},
 		})
 
@@ -113,31 +240,66 @@
 			customType: 'circle-center',
 		})
 
-		this.radiusEntity = this.dataSource.entities.add({
-			position: new Cesium.CallbackProperty(() => this.getRadiusPoint(), false),
+		this.radiusLevel1Entity = this.dataSource.entities.add({
+			position: new Cesium.CallbackProperty(() => this.getRadiusPoint(this.radiusLevel1), false),
 			point: {
 				pixelSize: 10,
 				color: Cesium.Color.fromBytes(255, 255, 255, 200),
 				heightReference: Cesium.HeightReference.CLAMP_TO_GROUND,
 				disableDepthTestDistance: Number.POSITIVE_INFINITY,
 			},
-			customType: 'circle-radius',
+			customType: 'circle-radius-1',
+		})
+
+		this.radiusLevel2Entity = this.dataSource.entities.add({
+			position: new Cesium.CallbackProperty(() => this.getRadiusPoint(this.radiusLevel2), false),
+			point: {
+				pixelSize: 10,
+				color: Cesium.Color.fromBytes(255, 255, 255, 200),
+				heightReference: Cesium.HeightReference.CLAMP_TO_GROUND,
+				disableDepthTestDistance: Number.POSITIVE_INFINITY,
+			},
+			customType: 'circle-radius-2',
+		})
+
+		this.radiusLevel3Entity = this.dataSource.entities.add({
+			position: new Cesium.CallbackProperty(() => this.getRadiusPoint(this.radiusLevel3), false),
+			point: {
+				pixelSize: 10,
+				color: Cesium.Color.fromBytes(255, 255, 255, 200),
+				heightReference: Cesium.HeightReference.CLAMP_TO_GROUND,
+				disableDepthTestDistance: Number.POSITIVE_INFINITY,
+			},
+			customType: 'circle-radius-3',
 		})
 	}
 
-	updateRadiusPoint() {
-		if (!this.radiusEntity) return
-		this.radiusEntity.position = this.getRadiusPoint()
+	updateRadiusPoints() {
+		if (this.radiusLevel1Entity) this.radiusLevel1Entity.position = this.getRadiusPoint(this.radiusLevel1)
+		if (this.radiusLevel2Entity) this.radiusLevel2Entity.position = this.getRadiusPoint(this.radiusLevel2)
+		if (this.radiusLevel3Entity) this.radiusLevel3Entity.position = this.getRadiusPoint(this.radiusLevel3)
 	}
 
 	getPositions() {
 		if (!this.centerCartesian) return []
-		return buildEllipsePositions(this.centerCartesian, this.radius, this.radius)
+		return {
+			positions: buildEllipsePositions(this.centerCartesian, this.radiusLevel3, this.radiusLevel3),
+			meta: {
+				center: this.centerCartesian,
+				bufferRadii: [this.radiusLevel1, this.radiusLevel2, this.radiusLevel3],
+				controlPoints: [
+					this.centerCartesian,
+					this.getRadiusPoint(this.radiusLevel1),
+					this.getRadiusPoint(this.radiusLevel2),
+					this.getRadiusPoint(this.radiusLevel3),
+				],
+			},
+		}
 	}
 
-	getRadiusPoint() {
+	getRadiusPoint(radius) {
 		const frame = Cesium.Transforms.eastNorthUpToFixedFrame(this.centerCartesian)
-		const local = new Cesium.Cartesian3(this.radius, 0, 0)
+		const local = new Cesium.Cartesian3(radius, 0, 0)
 		return Cesium.Matrix4.multiplyByPoint(frame, local, new Cesium.Cartesian3())
 	}
 
@@ -178,7 +340,12 @@
 		this.tooltip?.destroy()
 		this.tooltip = null
 		this.centerCartesian = null
-		this.radius = 0
+		this.radiusLevel1 = 0
+		this.radiusLevel2 = 0
+		this.radiusLevel3 = 0
+		this.circleLevel1OutlineEntity = null
+		this.circleLevel2OutlineEntity = null
+		this.circleLevel3OutlineEntity = null
 		this.dragType = null
 	}
 }

--
Gitblit v1.9.3