吉安感知网项目-前端
张含笑
2026-01-29 9fb4de853fc8aab2000f312ba2b8907e3dc9a61d
applications/drone-command/src/views/areaManage/partition/shapeTools/draw/DrawEllipseTool.js
@@ -1,25 +1,32 @@
import * as Cesium from 'cesium'
import { MapTooltip } from '../Tooltip'
import { ToolBase } from '../ToolBase'
import {
   getBoundsFromCartesians,
   getCenterFromBounds,
   getMetersBetween,
   buildEllipsePositions,
} from '../shapeUtils'
import { buildEllipsePositions } from '../shapeUtils'
const DEFAULT_STYLE = {
   fill: Cesium.Color.fromBytes(45, 140, 240, 99),
   outline: Cesium.Color.fromBytes(45, 140, 240, 255),
}
const resolveStyle = style => ({
   fill: style?.fill || DEFAULT_STYLE.fill,
   outline: style?.outline || DEFAULT_STYLE.outline,
})
export class DrawEllipseTool extends ToolBase {
   constructor(viewer) {
   constructor(viewer, options = {}) {
      super(viewer)
      this.tooltip = new MapTooltip(viewer)
      this.dataSource = null
      this.ellipseEntity = null
      this.startPosition = null
      this.endPosition = null
      this.centerCartesian = null
      this.majorPoint = null
      this.minorPoint = null
      this.semiMajor = 0
      this.semiMinor = 0
      this.isDrawing = false
      this.drawStep = 0
      this.isCompleted = false
      this.style = resolveStyle(options?.style)
   }
   start() {
@@ -28,26 +35,40 @@
      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.tooltip.show('单击设置起点', { x: 0, y: 0 })
      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.startPosition) {
         this.startPosition = position
         this.endPosition = position
      if (this.drawStep === 0) {
         this.centerCartesian = position
         this.semiMajor = 1
         this.semiMinor = 1
         this.isDrawing = true
         this.drawStep = 1
         this.createEntities()
         this.tooltip.show('单击结束绘制', click.position)
         this.tooltip.show('单击设置长轴', click.position)
         return
      }
      if (this.isDrawing) {
         this.endPosition = position
         this.updateEllipseByBounds()
      if (this.drawStep === 1) {
         this.majorPoint = position
         this.semiMajor = Math.max(1, this.getSurfaceDistance(this.centerCartesian, this.majorPoint))
         this.semiMinor = this.semiMajor
         this.drawStep = 2
         this.tooltip.show('单击设置短轴', click.position)
         return
      }
      if (this.drawStep === 2) {
         this.minorPoint = position
         const minorRadius = Math.max(1, this.getSurfaceDistance(this.centerCartesian, this.minorPoint))
         this.semiMinor = Math.min(minorRadius, this.semiMajor)
         this.isDrawing = false
         this.drawStep = 0
         this.isCompleted = true
         const positions = buildEllipsePositions(this.centerCartesian, this.semiMajor, this.semiMinor)
         this.notify('getPolygonPositions', positions)
         this.tooltip.hide()
@@ -56,32 +77,21 @@
   }
   handleMouseMove(movement) {
      if (!this.isDrawing) {
         this.tooltip.move(movement.endPosition)
         return
      }
      if (this.isCompleted) return
      this.tooltip.move(movement.endPosition)
      if (!this.isDrawing) return
      const position = this.getPositionFromScreen(movement.endPosition)
      if (!position) return
      this.endPosition = position
      this.updateEllipseByBounds()
      this.tooltip.move(movement.endPosition)
   }
   updateEllipseByBounds() {
      const bounds = getBoundsFromCartesians([this.startPosition, this.endPosition])
      const center = getCenterFromBounds(bounds)
      if (!bounds || !center) return
      this.centerCartesian = Cesium.Cartesian3.fromRadians(center.longitude, center.latitude)
      const eastWest = getMetersBetween(
         new Cesium.Cartographic(bounds.west, center.latitude),
         new Cesium.Cartographic(bounds.east, center.latitude)
      )
      const northSouth = getMetersBetween(
         new Cesium.Cartographic(center.longitude, bounds.south),
         new Cesium.Cartographic(center.longitude, bounds.north)
      )
      this.semiMajor = Math.max(1, eastWest / 2)
      this.semiMinor = Math.max(1, northSouth / 2)
      if (this.drawStep === 1) {
         const radius = Math.max(1, this.getSurfaceDistance(this.centerCartesian, position))
         this.semiMajor = radius
         this.semiMinor = radius
         return
      }
      if (this.drawStep === 2) {
         const minorRadius = Math.max(1, this.getSurfaceDistance(this.centerCartesian, position))
         this.semiMinor = Math.min(minorRadius, this.semiMajor)
      }
   }
   createEntities() {
@@ -91,13 +101,20 @@
         ellipse: {
            semiMajorAxis: new Cesium.CallbackProperty(() => this.semiMajor, false),
            semiMinorAxis: new Cesium.CallbackProperty(() => this.semiMinor, false),
            material: Cesium.Color.fromBytes(45, 140, 240, 99),
            material: this.style.fill,
            outline: true,
            outlineColor: Cesium.Color.fromBytes(45, 140, 240, 255),
            outlineColor: this.style.outline,
            outlineWidth: 2,
            heightReference: Cesium.HeightReference.CLAMP_TO_GROUND,
         },
      })
   }
   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
   }
   clearPreviewEntities() {
@@ -111,6 +128,14 @@
      const cartesian = scene.pickPosition(screenPosition)
      if (cartesian) return cartesian
      return scene.camera.pickEllipsoid(screenPosition, scene.globe.ellipsoid)
   }
   setStyle(style) {
      this.style = resolveStyle(style)
      if (this.ellipseEntity?.ellipse) {
         this.ellipseEntity.ellipse.material = this.style.fill
         this.ellipseEntity.ellipse.outlineColor = this.style.outline
      }
   }
   destroy() {
@@ -127,9 +152,11 @@
      }
      this.tooltip?.destroy()
      this.tooltip = null
      this.startPosition = null
      this.endPosition = null
      this.centerCartesian = null
      this.majorPoint = null
      this.minorPoint = null
      this.isDrawing = false
      this.drawStep = 0
      this.isCompleted = false
   }
}