吉安感知网项目-前端
chenyao
2026-01-29 f083281ab75f61390a04daa2484f330f8df4178f
applications/drone-command/src/views/areaManage/partition/shapeTools/draw/DrawBufferCircleTool.js
New file
@@ -0,0 +1,236 @@
import * as Cesium from 'cesium'
import { MapTooltip } from '../Tooltip'
import { ToolBase } from '../ToolBase'
import { buildEllipsePositions } from '../shapeUtils'
export class DrawBufferCircleTool extends ToolBase {
   constructor(viewer) {
      super(viewer)
      this.tooltip = new MapTooltip(viewer)
      this.dataSource = null
      this.centerCartesian = null
      this.radiusLevel1 = 0
      this.radiusLevel2 = 0
      this.radiusLevel3 = 0
      this.circleLevel1Entity = null
      this.circleLevel2Entity = null
      this.circleLevel3Entity = null
      this.circleLevel1OutlineEntity = null
      this.circleLevel2OutlineEntity = null
      this.circleLevel3OutlineEntity = null
      this.isDrawing = false
      this.drawStep = 0
      this.isCompleted = false
   }
   start() {
      this.dataSource = new Cesium.CustomDataSource('draw-buffer-circle')
      this.viewer.dataSources.add(this.dataSource)
      this.handler = new Cesium.ScreenSpaceEventHandler(this.viewer.scene.canvas)
      this.handler.setInputAction(click => this.handleLeftClick(click), Cesium.ScreenSpaceEventType.LEFT_CLICK)
      this.handler.setInputAction(movement => this.handleMouseMove(movement), Cesium.ScreenSpaceEventType.MOUSE_MOVE)
      this.drawStep = 0
      this.isCompleted = false
      this.tooltip.show('单击设置中心点', { x: 0, y: 0 })
   }
   handleLeftClick(click) {
      if (this.isCompleted) return
      const position = this.getPositionFromScreen(click.position)
      if (!position) return
      if (this.drawStep === 0) {
         this.centerCartesian = position
         this.radiusLevel1 = 1
         this.radiusLevel2 = 1
         this.radiusLevel3 = 1
         this.isDrawing = true
         this.drawStep = 1
         this.createEntities()
         this.tooltip.show('单击设置一级缓冲圆', click.position)
         return
      }
      if (this.drawStep === 1) {
         const radius = Math.max(1, this.getSurfaceDistance(this.centerCartesian, position))
         this.radiusLevel1 = radius
         this.radiusLevel2 = radius
         this.radiusLevel3 = radius
         this.drawStep = 2
         this.tooltip.show('单击设置二级缓冲圆', click.position)
         return
      }
      if (this.drawStep === 2) {
         const radius = Math.max(1, this.getSurfaceDistance(this.centerCartesian, position))
         this.radiusLevel2 = Math.max(radius, this.radiusLevel1)
         this.radiusLevel3 = this.radiusLevel2
         this.drawStep = 3
         this.tooltip.show('单击设置三级缓冲圆', click.position)
         return
      }
      if (this.drawStep === 3) {
         const radius = Math.max(1, this.getSurfaceDistance(this.centerCartesian, position))
         this.radiusLevel3 = Math.max(radius, this.radiusLevel2)
         this.isDrawing = false
         this.drawStep = 0
         this.isCompleted = true
         const positions = buildEllipsePositions(this.centerCartesian, this.radiusLevel3, this.radiusLevel3)
         this.notify('getPolygonPositions', {
            positions,
            meta: {
               center: this.centerCartesian,
               bufferRadii: [this.radiusLevel1, this.radiusLevel2, this.radiusLevel3],
            },
         })
         this.tooltip.hide()
         this.clearPreviewEntities()
      }
   }
   handleMouseMove(movement) {
      if (this.isCompleted) return
      this.tooltip.move(movement.endPosition)
      if (!this.isDrawing) return
      const position = this.getPositionFromScreen(movement.endPosition)
      if (!position) return
      if (this.drawStep === 1) {
         const radius = Math.max(1, this.getSurfaceDistance(this.centerCartesian, position))
         this.radiusLevel1 = radius
         this.radiusLevel2 = radius
         this.radiusLevel3 = radius
         return
      }
      if (this.drawStep === 2) {
         const radius = Math.max(1, this.getSurfaceDistance(this.centerCartesian, position))
         this.radiusLevel2 = Math.max(radius, this.radiusLevel1)
         this.radiusLevel3 = this.radiusLevel2
         return
      }
      if (this.drawStep === 3) {
         const radius = Math.max(1, this.getSurfaceDistance(this.centerCartesian, position))
         this.radiusLevel3 = Math.max(radius, this.radiusLevel2)
      }
   }
   createEntities() {
      if (this.circleLevel1Entity || this.circleLevel2Entity || this.circleLevel3Entity) return
      this.circleLevel1Entity = this.dataSource.entities.add({
         position: new Cesium.CallbackProperty(() => this.centerCartesian, false),
         ellipse: {
            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),
         },
      })
   }
   clearPreviewEntities() {
      if (!this.dataSource) return
      this.dataSource.entities.removeAll()
      this.circleLevel1Entity = null
      this.circleLevel2Entity = null
      this.circleLevel3Entity = null
      this.circleLevel1OutlineEntity = null
      this.circleLevel2OutlineEntity = null
      this.circleLevel3OutlineEntity = null
   }
   getSurfaceDistance(startCartesian, endCartesian) {
      const start = Cesium.Cartographic.fromCartesian(startCartesian)
      const end = Cesium.Cartographic.fromCartesian(endCartesian)
      const geodesic = new Cesium.EllipsoidGeodesic(start, end)
      return geodesic.surfaceDistance
   }
   getPositionFromScreen(screenPosition) {
      const scene = this.viewer.scene
      const cartesian = scene.pickPosition(screenPosition)
      if (cartesian) return cartesian
      return scene.camera.pickEllipsoid(screenPosition, scene.globe.ellipsoid)
   }
   destroy() {
      if (this.dataSource) {
         this.dataSource.entities.removeAll()
         this.viewer.dataSources.remove(this.dataSource)
         this.dataSource = null
      }
      if (this.handler) {
         this.handler.removeInputAction(Cesium.ScreenSpaceEventType.LEFT_CLICK)
         this.handler.removeInputAction(Cesium.ScreenSpaceEventType.MOUSE_MOVE)
         this.handler.destroy()
         this.handler = null
      }
      this.tooltip?.destroy()
      this.tooltip = null
      this.centerCartesian = null
      this.radiusLevel1 = 0
      this.radiusLevel2 = 0
      this.radiusLevel3 = 0
      this.isDrawing = false
      this.drawStep = 0
      this.isCompleted = false
   }
}