吉安感知网项目-前端
shuishen
2026-01-29 cb43af5c2caf2184bbf1a8e417f44e9aeaa2fdd9
applications/drone-command/src/views/areaManage/partition/shapeTools/edit/EditEllipseTool.js
@@ -9,14 +9,53 @@
   cartesianToLocal,
} 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,
})
const normalizePoints = points =>
   (points || []).map(point => ({
      lng: point.lng ?? point.longitude,
      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)
}
const resolveCartographic = point => {
   if (!point) return null
   if (Number.isFinite(point.x) && Number.isFinite(point.y) && Number.isFinite(point.z)) {
      return Cesium.Cartographic.fromCartesian(point)
   }
   const lngLat = resolveLngLat(point)
   if (!lngLat) return null
   return Cesium.Cartographic.fromDegrees(lngLat.lng, lngLat.lat, lngLat.height || 0)
}
export class EditEllipseTool extends ToolBase {
   constructor(viewer) {
   constructor(viewer, options = {}) {
      super(viewer)
      this.tooltip = new MapTooltip(viewer)
      this.dataSource = null
@@ -28,24 +67,46 @@
      this.majorEntity = null
      this.minorEntity = null
      this.ellipseEntity = null
      this.style = resolveStyle(options?.style)
   }
   start(points = []) {
      const normalized = normalizePoints(points)
      const bounds = getBoundsFromLngLats(normalized)
      const center = getCenterFromBounds(bounds)
      if (!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)
   start(data = []) {
      const inputPoints = Array.isArray(data?.points) ? data.points : data
      const meta = data?.meta || null
      const metaCenter = resolveCartesian(meta?.center)
      if (metaCenter) {
         this.centerCartesian = metaCenter
         const centerCarto = Cesium.Cartographic.fromCartesian(metaCenter)
         const majorFromMeta = Number.isFinite(meta?.semiMajor) ? Number(meta.semiMajor) : 0
         const minorFromMeta = Number.isFinite(meta?.semiMinor) ? Number(meta.semiMinor) : 0
         const majorPoint = resolveCartographic(meta?.majorPoint)
         const minorPoint = resolveCartographic(meta?.minorPoint)
         const majorDistance =
            majorFromMeta || (majorPoint ? getMetersBetween(centerCarto, majorPoint) : 0)
         const minorDistance =
            minorFromMeta || (minorPoint ? getMetersBetween(centerCarto, minorPoint) : 0)
         if (majorDistance > 0) this.semiMajor = Math.max(1, majorDistance)
         if (minorDistance > 0) this.semiMinor = Math.max(1, minorDistance)
         if (this.semiMinor > this.semiMajor) this.semiMinor = this.semiMajor
      }
      if (!this.centerCartesian || !this.semiMajor || !this.semiMinor) {
         const normalized = normalizePoints(inputPoints)
         const bounds = getBoundsFromLngLats(normalized)
         const center = getCenterFromBounds(bounds)
         if (!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)
      }
      this.dataSource = new Cesium.CustomDataSource('edit-ellipse')
      this.viewer.dataSources.add(this.dataSource)
@@ -85,9 +146,15 @@
      const local = cartesianToLocal(this.centerCartesian, position)
      if (this.dragType === 'major') {
         this.semiMajor = Math.max(1, Math.abs(local.x))
         if (this.semiMajor < this.semiMinor) {
            this.semiMajor = this.semiMinor
         }
      }
      if (this.dragType === 'minor') {
         this.semiMinor = Math.max(1, Math.abs(local.y))
         if (this.semiMinor > this.semiMajor) {
            this.semiMinor = this.semiMajor
         }
      }
      this.updateAxisPoints()
   }
@@ -97,7 +164,16 @@
      this.dragType = null
      this.enableMapControl()
      const positions = buildEllipsePositions(this.centerCartesian, this.semiMajor, this.semiMinor)
      this.notify('getPolygonPositions', positions)
      this.notify('getPolygonPositions', {
         positions,
         meta: {
            center: this.centerCartesian,
            majorPoint: this.getAxisPoint(this.semiMajor, 0),
            minorPoint: this.getAxisPoint(0, this.semiMinor),
            semiMajor: this.semiMajor,
            semiMinor: this.semiMinor,
         },
      })
   }
   createEntities() {
@@ -106,9 +182,9 @@
         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,
         },
@@ -156,7 +232,16 @@
   getPositions() {
      if (!this.centerCartesian) return []
      return buildEllipsePositions(this.centerCartesian, this.semiMajor, this.semiMinor)
      return {
         positions: buildEllipsePositions(this.centerCartesian, this.semiMajor, this.semiMinor),
         meta: {
            center: this.centerCartesian,
            majorPoint: this.getAxisPoint(this.semiMajor, 0),
            minorPoint: this.getAxisPoint(0, this.semiMinor),
            semiMajor: this.semiMajor,
            semiMinor: this.semiMinor,
         },
      }
   }
   getAxisPoint(eastMeters, northMeters) {
@@ -172,6 +257,14 @@
      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
      }
   }
   disableMapControl() {
      const controller = this.viewer.scene.screenSpaceCameraController
      controller.enableRotate = false