From 744be26032980317d34d22643bf7bdd59a8dbedb Mon Sep 17 00:00:00 2001
From: chenyao <1219716595@qq.com>
Date: Sat, 13 Sep 2025 17:32:57 +0800
Subject: [PATCH] feat:更新网格管理

---
 vite.config.mjs                                        |   10 
 src/views/gridManagement/GridSettings/OccupancyGrid.js | 1293 +++++++++++++++++++++++++
 src/api/airspace/airspace.js                           |   34 
 src/utils/cesium/publicCesium.js                       |    1 
 src/views/gridManagement/gridManagement.vue            |  623 ++++++++++++
 src/views/gridManagement/GridSettings/PathPlanning.js  | 1058 ++++++++++++++++++++
 src/views/airspace/airspaceType.vue                    |   15 
 7 files changed, 3,028 insertions(+), 6 deletions(-)

diff --git a/src/api/airspace/airspace.js b/src/api/airspace/airspace.js
index 8d9c3f2..5ff6871 100644
--- a/src/api/airspace/airspace.js
+++ b/src/api/airspace/airspace.js
@@ -62,4 +62,36 @@
     params
   })
 }
-// ----------空域录入相关接口调用----------
\ No newline at end of file
+// ----------空域录入相关接口调用----------
+
+// ----------网格管理相关接口调用----------
+export const airGridPage = params => {
+  return request({
+    url: '/drone-device-core/airgrid/page',
+    method: 'get',
+    params
+  })
+}
+
+export const airGridUpdate = data => {
+  return request({
+    url: '/drone-device-core/airgrid/update',
+    method: 'put',
+    data: data,
+  })
+}
+
+export const airGridAdd= data => {
+  return request({
+    url: '/drone-device-core/airgrid/add',
+    method: 'post',
+    data: data,
+  })
+}
+
+export const airGridDelete= data => {
+  return request({
+    url: '/drone-device-core/airgrid/delete/' + data,
+    method: 'delete',
+  })
+}
\ No newline at end of file
diff --git a/src/utils/cesium/publicCesium.js b/src/utils/cesium/publicCesium.js
index ef65590..e0d3d88 100644
--- a/src/utils/cesium/publicCesium.js
+++ b/src/utils/cesium/publicCesium.js
@@ -224,6 +224,7 @@
 
 	// 飞行 flyto
 	flyTo (pointOption, time = 4, height = 3000, orientation = {}, complete = () => { }) {
+		console.log(pointOption, )
 		if (!pointOption.longitude && !pointOption.latitude) return
 		const destination = Cesium.Cartesian3.fromDegrees(pointOption.longitude, pointOption.latitude, height)
 		const duration = time
diff --git a/src/views/airspace/airspaceType.vue b/src/views/airspace/airspaceType.vue
index 0f927b4..42613b6 100644
--- a/src/views/airspace/airspaceType.vue
+++ b/src/views/airspace/airspaceType.vue
@@ -126,10 +126,19 @@
   rowView.value = row
 }
 function handleDelete (row) {
-  airSpaceTypeDelete(row.id).then(res => {
-    ElMessage.success('删除成功')
-    getList()
+  // 确定要删除么?
+  ElMessage({
+    message: '确定要删除么?',
+    type: 'warning',
+    showClose: true,
+    onClose: () => {
+      airSpaceTypeDelete(row.id).then(res => {
+        ElMessage.success('删除成功')
+        getList()
+      })
+    }
   })
+  
 }
 function handleAdd() {
   titleTxt.value = '新增'
diff --git a/src/views/gridManagement/GridSettings/OccupancyGrid.js b/src/views/gridManagement/GridSettings/OccupancyGrid.js
new file mode 100644
index 0000000..8f9dc1a
--- /dev/null
+++ b/src/views/gridManagement/GridSettings/OccupancyGrid.js
@@ -0,0 +1,1293 @@
+// ================================
+// 3D占用网格系统模块
+// ================================
+import * as Cesium from 'cesium'
+
+class OccupancyGrid {
+  constructor(viewer, config = {}, gridParams) {
+    this.viewer = viewer
+    this.gridEntities = []
+    this.tilesBoundingBoxes = [] // 存储瓦片边界框
+    this.gridParams = gridParams
+
+    // 网格配置参数 - 可自定义
+    this.config = {
+      // 网格单元尺寸配置
+      gridSize: config.gridSize || 50, // 网格单元大小(米)
+      gridWidth: config.gridWidth || 50, // 网格宽度(米)
+      gridHeight: config.gridHeight || 50, // 网格高度(米)
+      gridDepth: config.gridDepth || 50, // 网格深度(米)
+
+      // 区域扩展配置
+      heightExtension: config.heightExtension || 120, // 向上向下各扩展120米,确保4层网格(总高度240米,4×50=200米,留有余量)
+      widthExtension: config.widthExtension || 100, // 水平方向扩展100米
+
+      // 颜色配置
+      occupiedColor: config.occupiedColor || Cesium.Color.RED.withAlpha(0.7), // 占用网格颜色(红色)
+      freeColor: config.freeColor || Cesium.Color.GREEN.withAlpha(0.3), // 空闲网格颜色(绿色)
+      occupiedOutlineColor: config.occupiedOutlineColor || Cesium.Color.DARKRED, // 占用网格边框颜色
+      freeOutlineColor: config.freeOutlineColor || Cesium.Color.DARKGREEN, // 空闲网格边框颜色
+      outlineWidth: config.outlineWidth || 1, // 边框宽度
+
+      // 透明度配置
+      occupiedAlpha: config.occupiedAlpha || 0.7, // 占用网格透明度
+      freeAlpha: config.freeAlpha || 0.3, // 空闲网格透明度
+
+      // 性能优化配置
+      maxGridCount: config.maxGridCount || 10000, // 最大网格数量限制
+      enableBatching: config.enableBatching || true, // 是否启用批处理优化
+
+      // 调试配置
+      showOccupiedOnly: config.showOccupiedOnly || false, // 是否只显示占用的网格
+      showFreeOnly: config.showFreeOnly || false, // 是否只显示空闲的网格
+      enableLogging: config.enableLogging || true // 是否启用详细日志
+    }
+
+    // 向后兼容旧参数
+    this.gridSize = this.config.gridSize
+    this.heightExtension = this.config.heightExtension
+  }
+
+  // ================================
+  // 更新配置
+  // ================================
+  updateConfig (newConfig) {
+    this.config = { ...this.config, ...newConfig }
+
+    // 更新向后兼容参数
+    this.gridSize = this.config.gridSize
+    this.heightExtension = this.config.heightExtension
+
+    if (this.config.enableLogging) {
+      console.log('网格配置已更新:', this.config)
+    }
+  }
+
+  // ================================
+  // 获取当前配置
+  // ================================
+  getConfig () {
+    return { ...this.config }
+  }
+
+  // ================================
+  // 生成占用网格 - 使用配置参数
+  // ================================
+  async generateOccupancyGrid (waypoints) {
+    if (waypoints.length < 2) {
+      console.warn('需要至少2个航点来生成占用网格')
+      return
+    }
+
+    // 清除之前的网格
+    this.clearGrid()
+
+    // 获取起点和终点
+    const startPoint = waypoints[0]
+    const endPoint = waypoints[waypoints.length - 1]
+
+    // 计算边界框
+    const bounds = this.calculateBounds(startPoint, endPoint)
+
+    // 收集3D瓦片的边界框信息
+    await this.collectTilesBoundingBoxes(bounds)
+
+    // 生成网格
+    await this.createGrid(bounds)
+
+    if (this.config.enableLogging) {
+      console.log('3D占用网格生成完成')
+      console.log(`网格尺寸: ${this.config.gridWidth}m x ${this.config.gridHeight}m x ${this.config.gridDepth}m`)
+      console.log(`总网格数量: ${this.gridEntities.length}`)
+      console.log(`瓦片边界框数量: ${this.tilesBoundingBoxes.length}`)
+    }
+  }
+
+  // ================================
+  // 使用航线瓦片数据生成占用网格 - 使用配置参数
+  // ================================
+  async generateOccupancyGridWithTiles (waypoints, flightPathTiles) {
+    if (waypoints.length < 2) {
+      console.warn('需要至少2个航点来生成占用网格')
+      return
+    }
+
+    if (this.config.enableLogging) {
+      console.log(`开始生成占用网格,将分析网格范围内的所有叶子瓦片节点`)
+    }
+
+    // 清除之前的网格
+    this.clearGrid()
+
+    // 获取起点和终点
+    const startPoint = waypoints[0]
+    const endPoint = waypoints[waypoints.length - 1]
+
+    // 计算边界框
+    const bounds = this.calculateBounds(startPoint, endPoint)
+
+    // 获取瓦片集,用于遍历叶子节点
+    this.tileset = this.getTileset()
+
+    if (!this.tileset) {
+      console.warn('未找到瓦片集,无法生成占用网格')
+      return
+    }
+
+    // 生成网格
+    await this.createGrid(bounds)
+
+    if (this.config.enableLogging) {
+      console.log('使用叶子瓦片节点的3D占用网格生成完成')
+      console.log(`网格尺寸: ${this.config.gridWidth}m x ${this.config.gridHeight}m x ${this.config.gridDepth}m`)
+      console.log(`总网格数量: ${this.gridEntities.length}`)
+    }
+  }
+
+  // ================================
+  // 获取瓦片集
+  // ================================
+  getTileset () {
+    const primitives = this.viewer.scene.primitives
+
+    for (let i = 0; i < primitives.length; i++) {
+      const primitive = primitives.get(i)
+      if (primitive instanceof Cesium.Cesium3DTileset) {
+        return primitive
+      }
+    }
+
+    return null
+  }
+
+  // ================================
+  // 计算边界框 - 使用配置参数
+  // ================================
+  calculateBounds (startPoint, endPoint) {
+    // 转换为地理坐标
+    const startCartographic = Cesium.Cartographic.fromCartesian(startPoint.position)
+    const endCartographic = Cesium.Cartographic.fromCartesian(endPoint.position)
+
+    // 计算基础边界
+    let minLon = Math.min(startCartographic.longitude, endCartographic.longitude)
+    let maxLon = Math.max(startCartographic.longitude, endCartographic.longitude)
+    let minLat = Math.min(startCartographic.latitude, endCartographic.latitude)
+    let maxLat = Math.max(startCartographic.latitude, endCartographic.latitude)
+
+    // 应用水平扩展
+    const earthRadius = 6371000
+    const widthExtensionLon = this.config.widthExtension / (earthRadius * Math.cos((minLat + maxLat) / 2))
+    const widthExtensionLat = this.config.widthExtension / earthRadius
+
+    minLon -= widthExtensionLon
+    maxLon += widthExtensionLon
+    minLat -= widthExtensionLat
+    maxLat += widthExtensionLat
+
+    // 计算平均高度和垂直扩展
+    const avgHeight = (startPoint.height + endPoint.height) / 2
+    const heightOffset = 20 // 向上平移50米,避免网格被tileset遮盖
+    const minHeight = avgHeight - this.config.heightExtension + heightOffset
+    const maxHeight = avgHeight + this.config.heightExtension + heightOffset
+
+    const bounds = {
+      minLon: minLon,
+      maxLon: maxLon,
+      minLat: minLat,
+      maxLat: maxLat,
+      minHeight: minHeight,
+      maxHeight: maxHeight,
+      avgHeight: avgHeight
+    }
+
+    if (this.config.enableLogging) {
+      console.log('计算网格边界范围:', {
+        经度范围: `${Cesium.Math.toDegrees(minLon).toFixed(6)} 到 ${Cesium.Math.toDegrees(maxLon).toFixed(6)}`,
+        纬度范围: `${Cesium.Math.toDegrees(minLat).toFixed(6)} 到 ${Cesium.Math.toDegrees(maxLat).toFixed(6)}`,
+        高度范围: `${minHeight.toFixed(1)}m 到 ${maxHeight.toFixed(1)}m (向上平移50m)`,
+        水平扩展: `${this.config.widthExtension}m`,
+        垂直扩展: `${this.config.heightExtension}m`
+      })
+    }
+
+    return bounds
+  }
+
+  // ================================
+  // 收集3D瓦片的边界框信息
+  // ================================
+  async collectTilesBoundingBoxes (bounds) {
+    this.tilesBoundingBoxes = []
+
+    // 获取所有的图元
+    const primitives = this.viewer.scene.primitives
+    let tileset = null
+
+    // 查找3D Tiles图层
+    for (let i = 0; i < primitives.length; i++) {
+      const primitive = primitives.get(i)
+      if (primitive instanceof Cesium.Cesium3DTileset) {
+        tileset = primitive
+        break
+      }
+    }
+
+    if (!tileset || !tileset.root) {
+      console.warn('未找到3D Tiles图层')
+      return
+    }
+
+    // 等待瓦片集加载完成
+    if (!tileset.ready) {
+      await tileset.readyPromise
+    }
+
+    // 遍历瓦片树并收集边界框
+    this.traverseTiles(tileset.root, bounds)
+
+    console.log(`收集到${this.tilesBoundingBoxes.length}个瓦片边界框`)
+  }
+
+  // ================================
+  // 收集航线瓦片的边界框信息
+  // ================================
+  collectFlightPathTilesBoundingBoxes (flightPathTiles) {
+    console.log('开始收集航线瓦片边界框信息')
+    this.tilesBoundingBoxes = []
+
+    flightPathTiles.forEach((tile, index) => {
+      try {
+        // 获取边界体信息
+        let boundingVolume = null
+
+        if (tile.boundingVolume) {
+          boundingVolume = tile.boundingVolume
+        } else if (tile._boundingVolume) {
+          boundingVolume = tile._boundingVolume
+        } else if (tile.contentBoundingVolume) {
+          boundingVolume = tile.contentBoundingVolume
+        }
+
+        if (!boundingVolume) {
+          console.warn(`瓦片 ${index} 没有边界体信息`)
+          return
+        }
+
+        let boundingBox = null
+
+        // 处理不同类型的边界体
+        if (boundingVolume instanceof Cesium.OrientedBoundingBox) {
+          boundingBox = this.orientedBoundingBoxToAxisAligned(boundingVolume)
+        }
+        else if (boundingVolume instanceof Cesium.BoundingSphere) {
+          boundingBox = this.sphereToAxisAligned(boundingVolume)
+        }
+        else if (boundingVolume.orientedBoundingBox) {
+          boundingBox = this.orientedBoundingBoxToAxisAligned(boundingVolume.orientedBoundingBox)
+        }
+        else if (boundingVolume.boundingSphere) {
+          boundingBox = this.sphereToAxisAligned(boundingVolume.boundingSphere)
+        }
+        else if (boundingVolume._orientedBoundingBox) {
+          boundingBox = this.orientedBoundingBoxToAxisAligned(boundingVolume._orientedBoundingBox)
+        }
+        else if (boundingVolume._boundingSphere) {
+          boundingBox = this.sphereToAxisAligned(boundingVolume._boundingSphere)
+        }
+
+        if (boundingBox) {
+          this.tilesBoundingBoxes.push(boundingBox)
+          console.log(`添加瓦片 ${index} 的边界框`)
+        } else {
+          console.warn(`无法处理瓦片 ${index} 的边界体类型`)
+        }
+      } catch (error) {
+        console.warn(`处理瓦片 ${index} 边界体时出错:`, error)
+      }
+    })
+
+    console.log(`成功收集 ${this.tilesBoundingBoxes.length} 个航线瓦片边界框`)
+  }
+
+  // ================================
+  // 遍历瓦片树
+  // ================================
+  traverseTiles (tile, bounds) {
+    if (!tile) return
+
+    // 获取瓦片的边界框
+    const boundingVolume = tile.boundingVolume
+    if (boundingVolume) {
+      let boundingBox = null
+
+      try {
+        // 检查是否有中心点和半径(球体)
+        if (boundingVolume.center && boundingVolume.radius !== undefined) {
+          boundingBox = this.sphereToBox(boundingVolume)
+        }
+        // 检查是否有中心点和半轴(盒子)
+        else if (boundingVolume.center && boundingVolume.halfAxes) {
+          const halfAxes = boundingVolume.halfAxes
+          const halfExtents = new Cesium.Cartesian3(
+            Math.max(10, Cesium.Cartesian3.magnitude(new Cesium.Cartesian3(halfAxes[0], halfAxes[1], halfAxes[2]))),
+            Math.max(10, Cesium.Cartesian3.magnitude(new Cesium.Cartesian3(halfAxes[3], halfAxes[4], halfAxes[5]))),
+            Math.max(10, Cesium.Cartesian3.magnitude(new Cesium.Cartesian3(halfAxes[6], halfAxes[7], halfAxes[8])))
+          )
+          boundingBox = {
+            center: boundingVolume.center,
+            halfExtents: halfExtents
+          }
+        }
+        // 检查是否有区域信息
+        else if (boundingVolume.west !== undefined && boundingVolume.east !== undefined) {
+          boundingBox = this.regionToBox(boundingVolume)
+        }
+        // 默认情况:创建一个小的边界框
+        else if (boundingVolume.center) {
+          boundingBox = {
+            center: boundingVolume.center,
+            halfExtents: new Cesium.Cartesian3(50, 50, 50) // 默认50米
+          }
+        }
+      } catch (error) {
+        console.warn('处理边界体积时出错:', error)
+        return
+      }
+
+      if (boundingBox && this.isBoundingBoxInRegion(boundingBox, bounds)) {
+        this.tilesBoundingBoxes.push(boundingBox)
+      }
+    }
+
+    // 递归遍历子瓦片
+    if (tile.children && tile.children.length > 0) {
+      for (const child of tile.children) {
+        this.traverseTiles(child, bounds)
+      }
+    }
+  }
+
+  // ================================
+  // 将球体转换为包围盒
+  // ================================
+  sphereToBox (sphere) {
+    const center = sphere.center
+    const radius = sphere.radius
+
+    // 创建一个立方体包围盒
+    const halfExtents = new Cesium.Cartesian3(radius, radius, radius)
+
+    return {
+      center: center,
+      halfExtents: halfExtents
+    }
+  }
+
+  // ================================
+  // 将区域转换为包围盒
+  // ================================
+  regionToBox (region) {
+    // 计算区域的中心点
+    const centerLon = (region.west + region.east) / 2
+    const centerLat = (region.south + region.north) / 2
+    const centerHeight = (region.minimumHeight + region.maximumHeight) / 2
+
+    const center = Cesium.Cartesian3.fromRadians(centerLon, centerLat, centerHeight)
+
+    // 计算区域的半尺寸
+    const lonExtent = (region.east - region.west) / 2
+    const latExtent = (region.north - region.south) / 2
+    const heightExtent = (region.maximumHeight - region.minimumHeight) / 2
+
+    // 转换为笛卡尔坐标的半扩展
+    const earthRadius = 6371000
+    const halfExtents = new Cesium.Cartesian3(
+      lonExtent * earthRadius * Math.cos(centerLat),
+      latExtent * earthRadius,
+      heightExtent
+    )
+
+    return {
+      center: center,
+      halfExtents: halfExtents
+    }
+  }
+
+  // ================================
+  // 检查边界框是否在感兴趣区域内
+  // ================================
+  isBoundingBoxInRegion (boundingBox, bounds) {
+    // 将边界框中心转换为地理坐标
+    const centerCartographic = Cesium.Cartographic.fromCartesian(boundingBox.center)
+
+    // 检查是否在地理范围内
+    return (centerCartographic.longitude >= bounds.minLon &&
+      centerCartographic.longitude <= bounds.maxLon &&
+      centerCartographic.latitude >= bounds.minLat &&
+      centerCartographic.latitude <= bounds.maxLat &&
+      centerCartographic.height >= bounds.minHeight &&
+      centerCartographic.height <= bounds.maxHeight)
+  }
+
+  // ================================
+  // 创建网格 - 使用配置参数
+  // ================================
+  async createGrid (bounds) {
+    // 将地理坐标转换为距离(米)
+    const earthRadius = 6371000 // 地球半径(米)
+
+    // 计算经纬度范围对应的实际距离
+    const latDistance = (bounds.maxLat - bounds.minLat) * earthRadius
+    const lonDistance = (bounds.maxLon - bounds.minLon) * earthRadius * Math.cos((bounds.minLat + bounds.maxLat) / 2)
+    const heightDistance = bounds.maxHeight - bounds.minHeight
+
+    // 计算网格数量 - 使用配置的网格尺寸
+    const gridCountX = Math.ceil(lonDistance / this.config.gridWidth)
+    const gridCountY = Math.ceil(latDistance / this.config.gridHeight)
+    const gridCountZ = Math.ceil(heightDistance / this.config.gridDepth)
+
+    const totalGridCount = gridCountX * gridCountY * gridCountZ
+
+    if (this.config.enableLogging) {
+      console.log(`计划生成网格数量: ${gridCountX} x ${gridCountY} x ${gridCountZ} = ${totalGridCount}`)
+      console.log(`网格单元尺寸: 宽${this.config.gridWidth}m x 高${this.config.gridHeight}m x 深${this.config.gridDepth}m`)
+      console.log(`实际距离: 经度${lonDistance.toFixed(1)}m x 纬度${latDistance.toFixed(1)}m x 高度${heightDistance.toFixed(1)}m`)
+      console.log(`垂直方向: 高度范围${heightDistance.toFixed(1)}m ÷ 网格深度${this.config.gridDepth}m = ${gridCountZ}层网格`)
+    }
+
+    // 性能保护:检查网格数量是否超出限制
+    if (totalGridCount > this.config.maxGridCount) {
+      console.warn(`网格数量 ${totalGridCount} 超过最大限制 ${this.config.maxGridCount},将进行优化处理`)
+
+      // 自动调整网格尺寸
+      const scaleFactor = Math.cbrt(totalGridCount / this.config.maxGridCount)
+      const adjustedGridSize = this.config.gridSize * scaleFactor
+
+      console.log(`自动调整网格尺寸从 ${this.config.gridSize}m 到 ${adjustedGridSize.toFixed(1)}m`)
+
+      // 重新计算网格数量
+      const newGridCountX = Math.ceil(lonDistance / adjustedGridSize)
+      const newGridCountY = Math.ceil(latDistance / adjustedGridSize)
+      const newGridCountZ = Math.ceil(heightDistance / adjustedGridSize)
+
+      if (this.config.enableLogging) {
+        console.log(`调整后网格数量: ${newGridCountX} x ${newGridCountY} x ${newGridCountZ} = ${newGridCountX * newGridCountY * newGridCountZ}`)
+      }
+
+      // 使用调整后的参数
+      return this.createGridWithCustomSize(bounds, newGridCountX, newGridCountY, newGridCountZ, adjustedGridSize)
+    }
+
+    // 正常情况下生成网格
+    return this.createGridWithCustomSize(bounds, gridCountX, gridCountY, gridCountZ, this.config.gridSize)
+  }
+
+  // ================================
+  // 使用自定义尺寸创建网格
+  // ================================
+  async createGridWithCustomSize (bounds, gridCountX, gridCountY, gridCountZ, gridSize) {
+    let occupiedCount = 0
+    let freeCount = 0
+
+    // 批处理参数
+    const batchSize = this.config.enableBatching ? 100 : 1
+    let batchCount = 0
+
+    // 生成网格立方体
+    for (let i = 0; i < gridCountX; i++) {
+      for (let j = 0; j < gridCountY; j++) {
+        for (let k = 0; k < gridCountZ; k++) {
+          const gridCenter = this.calculateGridCenter(bounds, i, j, k, gridCountX, gridCountY, gridCountZ)
+          const isOccupied = await this.checkOccupancy(gridCenter)
+
+          // 计算网格索引号 (i, j, k)
+          const gridIndex = { x: i, y: j, z: k }
+
+          // 根据配置决定是否显示
+          let shouldCreate = true
+          if (this.config.showOccupiedOnly && !isOccupied) {
+            shouldCreate = false
+          }
+          if (this.config.showFreeOnly && isOccupied) {
+            shouldCreate = false
+          }
+
+          if (shouldCreate) {
+            this.createGridCube(gridCenter, isOccupied, gridSize, gridIndex)
+          }
+
+          // 统计
+          if (isOccupied) {
+            occupiedCount++
+          } else {
+            freeCount++
+          }
+
+          // 批处理优化:每处理一定数量后让出控制权
+          batchCount++
+          if (this.config.enableBatching && batchCount >= batchSize) {
+            batchCount = 0
+            await new Promise(resolve => setTimeout(resolve, 1)) // 让出1ms给浏览器
+          }
+        }
+      }
+    }
+
+    if (this.config.enableLogging) {
+      this.gridParams.hasGrid = true
+      console.log(`网格生成完成 - 占用: ${occupiedCount}, 空闲: ${freeCount}, 总计: ${this.gridEntities.length}`)
+    }
+  }
+
+  // ================================
+  // 计算网格中心点
+  // ================================
+  calculateGridCenter (bounds, i, j, k, gridCountX, gridCountY, gridCountZ) {
+    // 计算网格中心的地理坐标
+    const lonStep = (bounds.maxLon - bounds.minLon) / gridCountX
+    const latStep = (bounds.maxLat - bounds.minLat) / gridCountY
+    const heightStep = (bounds.maxHeight - bounds.minHeight) / gridCountZ
+
+    const lon = bounds.minLon + (i + 0.5) * lonStep
+    const lat = bounds.minLat + (j + 0.5) * latStep
+    const height = bounds.minHeight + (k + 0.5) * heightStep
+
+    return {
+      longitude: lon,
+      latitude: lat,
+      height: height
+    }
+  }
+
+  // ================================
+  // 检查占用状态 - 基于网格范围内的叶子瓦片节点及其外包盒求交
+  // ================================
+  async checkOccupancy (gridCenter) {
+    if (!this.tileset) {
+      return false // 没有瓦片集,默认未占用
+    }
+
+    // 计算网格单元的边界范围
+    const gridBounds = this.calculateGridBounds(gridCenter)
+
+    // 收集网格范围内的所有叶子瓦片节点
+    const leafTilesInGrid = []
+    this.findLeafTilesInGridBounds(this.tileset.root, gridBounds, leafTilesInGrid)
+    console.log(this.tileset.root, gridBounds, 'this.tileset.root')
+    if (leafTilesInGrid.length === 0) {
+      return false // 没有叶子瓦片,标记为未占用
+    }
+
+    // 使用叶子节点的外包盒与网格单元进行精确求交计算
+    const hasIntersection = this.checkGridTileIntersections(gridBounds, leafTilesInGrid)
+
+    if (hasIntersection) {
+      console.log(`网格单元 [${Cesium.Math.toDegrees(gridCenter.longitude).toFixed(6)}, ${Cesium.Math.toDegrees(gridCenter.latitude).toFixed(6)}, ${gridCenter.height.toFixed(1)}] 与 ${leafTilesInGrid.length} 个叶子瓦片相交`)
+    }
+
+    return hasIntersection
+  }
+
+  // ================================
+  // 递归查找网格范围内的叶子瓦片节点
+  // ================================
+  findLeafTilesInGridBounds (tile, gridBounds, leafTiles) {
+    if (!tile) {
+      return
+    }
+
+    // 检查是否为叶子节点
+    const isLeafNode = !tile.children || tile.children.length === 0
+
+    // 首先检查当前瓦片是否与网格边界相交
+    const intersects = this.isTileIntersectingGridBounds(tile, gridBounds)
+
+    if (!intersects) {
+      return // 如果当前瓦片不与网格相交,则跳过其所有子节点
+    }
+
+    if (isLeafNode) {
+      // 只有叶子节点才添加到结果中
+      leafTiles.push(tile)
+    } else {
+      // 中间节点与网格相交,继续遍历其子节点
+      for (let i = 0; i < tile.children.length; i++) {
+        this.findLeafTilesInGridBounds(tile.children[i], gridBounds, leafTiles)
+      }
+    }
+  }
+
+  // ================================
+  // 检查瓦片是否与网格边界相交(简化版本,用于预筛选)
+  // ================================
+  isTileIntersectingGridBounds (tile, gridBounds) {
+    // 获取瓦片的边界体信息
+    let boundingVolume = null
+
+    if (tile.boundingVolume) {
+      boundingVolume = tile.boundingVolume
+    } else if (tile._boundingVolume) {
+      boundingVolume = tile._boundingVolume
+    } else if (tile.contentBoundingVolume) {
+      boundingVolume = tile.contentBoundingVolume
+    }
+
+    if (!boundingVolume) {
+      return false // 没有边界体信息
+    }
+
+    try {
+      // 简化的边界检测,用于快速预筛选
+      let tileBounds = null
+
+      if (boundingVolume instanceof Cesium.OrientedBoundingBox) {
+        tileBounds = this.getSimpleBoundsFromOBB(boundingVolume)
+      }
+      else if (boundingVolume instanceof Cesium.BoundingSphere) {
+        tileBounds = this.getSimpleBoundsFromSphere(boundingVolume)
+      }
+      else if (boundingVolume.orientedBoundingBox) {
+        tileBounds = this.getSimpleBoundsFromOBB(boundingVolume.orientedBoundingBox)
+      }
+      else if (boundingVolume.boundingSphere) {
+        tileBounds = this.getSimpleBoundsFromSphere(boundingVolume.boundingSphere)
+      }
+      else if (boundingVolume._orientedBoundingBox) {
+        tileBounds = this.getSimpleBoundsFromOBB(boundingVolume._orientedBoundingBox)
+      }
+      else if (boundingVolume._boundingSphere) {
+        tileBounds = this.getSimpleBoundsFromSphere(boundingVolume._boundingSphere)
+      }
+
+      if (!tileBounds) {
+        return false
+      }
+
+      // 简单的3D AABB相交检测
+      const tolerance = 0.0001
+
+      const intersects = !(
+        gridBounds.maxLon < tileBounds.minLon - tolerance ||
+        gridBounds.minLon > tileBounds.maxLon + tolerance ||
+        gridBounds.maxLat < tileBounds.minLat - tolerance ||
+        gridBounds.minLat > tileBounds.maxLat + tolerance ||
+        gridBounds.maxHeight < tileBounds.minHeight - tolerance ||
+        gridBounds.minHeight > tileBounds.maxHeight + tolerance
+      )
+
+      return intersects
+
+    } catch (error) {
+      console.warn('预筛选瓦片边界体时出错:', error)
+      return true // 出错时保守地返回true,让后续精确计算处理
+    }
+  }
+
+  // ================================
+  // 从OrientedBoundingBox获取简化边界(用于预筛选)
+  // ================================
+  getSimpleBoundsFromOBB (obb) {
+    const center = obb.center
+    const halfAxes = obb.halfAxes
+
+    // 计算边界盒的大致范围
+    const xAxis = new Cesium.Cartesian3()
+    const yAxis = new Cesium.Cartesian3()
+    const zAxis = new Cesium.Cartesian3()
+    Cesium.Matrix3.getColumn(halfAxes, 0, xAxis)
+    Cesium.Matrix3.getColumn(halfAxes, 1, yAxis)
+    Cesium.Matrix3.getColumn(halfAxes, 2, zAxis)
+
+    // 估算边界盒的最大扩展
+    const maxExtent = Math.max(
+      Cesium.Cartesian3.magnitude(xAxis),
+      Cesium.Cartesian3.magnitude(yAxis),
+      Cesium.Cartesian3.magnitude(zAxis)
+    )
+
+    // 将中心转换为地理坐标
+    const centerCartographic = Cesium.Cartographic.fromCartesian(center)
+    const centerLon = Cesium.Math.toDegrees(centerCartographic.longitude)
+    const centerLat = Cesium.Math.toDegrees(centerCartographic.latitude)
+    const centerHeight = centerCartographic.height
+
+    // 估算经纬度范围
+    const deltaLon = maxExtent / (111320 * Math.cos(centerCartographic.latitude))
+    const deltaLat = maxExtent / 110540
+
+    return {
+      minLon: centerLon - deltaLon,
+      maxLon: centerLon + deltaLon,
+      minLat: centerLat - deltaLat,
+      maxLat: centerLat + deltaLat,
+      minHeight: centerHeight - maxExtent,
+      maxHeight: centerHeight + maxExtent
+    }
+  }
+
+  // ================================
+  // 从BoundingSphere获取简化边界(用于预筛选)
+  // ================================
+  getSimpleBoundsFromSphere (sphere) {
+    const center = sphere.center
+    const radius = sphere.radius
+
+    // 将球心转换为地理坐标
+    const centerCartographic = Cesium.Cartographic.fromCartesian(center)
+    const centerLon = Cesium.Math.toDegrees(centerCartographic.longitude)
+    const centerLat = Cesium.Math.toDegrees(centerCartographic.latitude)
+    const centerHeight = centerCartographic.height
+
+    // 估算经纬度范围
+    const deltaLon = radius / (111320 * Math.cos(centerCartographic.latitude))
+    const deltaLat = radius / 110540
+
+    return {
+      minLon: centerLon - deltaLon,
+      maxLon: centerLon + deltaLon,
+      minLat: centerLat - deltaLat,
+      maxLat: centerLat + deltaLat,
+      minHeight: centerHeight - radius,
+      maxHeight: centerHeight + radius
+    }
+  }
+
+  // ================================
+  // 检查网格与叶子瓦片的精确求交
+  // ================================
+  checkGridTileIntersections (gridBounds, leafTiles) {
+    for (const tile of leafTiles) {
+      if (this.isGridIntersectingTileBoundingBox(gridBounds, tile)) {
+        return true // 找到一个相交的叶子瓦片即可确定占用状态
+      }
+    }
+    return false
+  }
+
+  // ================================
+  // 检查网格是否与瓦片外包盒相交(精确计算)
+  // ================================
+  isGridIntersectingTileBoundingBox (gridBounds, tile) {
+    // 获取瓦片的边界体信息
+    let boundingVolume = null
+
+    if (tile.boundingVolume) {
+      boundingVolume = tile.boundingVolume
+    } else if (tile._boundingVolume) {
+      boundingVolume = tile._boundingVolume
+    } else if (tile.contentBoundingVolume) {
+      boundingVolume = tile.contentBoundingVolume
+    }
+
+    if (!boundingVolume) {
+      return false // 没有边界体信息
+    }
+
+    try {
+      // 获取瓦片边界框的8个顶点(轴对齐)
+      const tileVertices = this.getTileBoundingBoxVertices(boundingVolume)
+
+      if (!tileVertices) {
+        return false
+      }
+
+      // 将网格边界转换为轴对齐边界框的8个顶点
+      const gridVertices = this.getGridBoundingBoxVertices(gridBounds)
+
+      // 执行3D AABB求交检测
+      return this.checkAABBIntersection(gridVertices, tileVertices)
+
+    } catch (error) {
+      console.warn('处理瓦片边界体时出错:', error)
+      return false
+    }
+  }
+
+  // ================================
+  // 获取瓦片边界框的8个顶点(参考FlightPathTiles方法)
+  // ================================
+  getTileBoundingBoxVertices (boundingVolume) {
+    let center = null
+    let halfAxes = null
+
+    // 处理不同类型的边界体
+    if (boundingVolume instanceof Cesium.OrientedBoundingBox) {
+      center = boundingVolume.center
+      halfAxes = boundingVolume.halfAxes
+    } else if (boundingVolume.orientedBoundingBox) {
+      center = boundingVolume.orientedBoundingBox.center
+      halfAxes = boundingVolume.orientedBoundingBox.halfAxes
+    } else if (boundingVolume._orientedBoundingBox) {
+      center = boundingVolume._orientedBoundingBox.center
+      halfAxes = boundingVolume._orientedBoundingBox.halfAxes
+    } else if (boundingVolume instanceof Cesium.BoundingSphere) {
+      return this.getBoundingSphereVertices(boundingVolume)
+    } else if (boundingVolume.boundingSphere) {
+      return this.getBoundingSphereVertices(boundingVolume.boundingSphere)
+    } else if (boundingVolume._boundingSphere) {
+      return this.getBoundingSphereVertices(boundingVolume._boundingSphere)
+    }
+
+    if (!center || !halfAxes) {
+      return null
+    }
+
+    return this.calculateBoundingBoxVertices(center, halfAxes)
+  }
+
+  // ================================
+  // 计算边界框的8个顶点(轴对齐,参考FlightPathTiles方法)
+  // ================================
+  calculateBoundingBoxVertices (center, halfAxes) {
+    // 计算所有8个顶点,然后找到轴对齐的边界框
+    const tempVertices = []
+    const directions = [
+      [-1, -1, -1], [-1, -1, 1], [-1, 1, -1], [-1, 1, 1],
+      [1, -1, -1], [1, -1, 1], [1, 1, -1], [1, 1, 1]
+    ]
+
+    // 提取三个轴向的向量
+    const xAxis = new Cesium.Cartesian3()
+    const yAxis = new Cesium.Cartesian3()
+    const zAxis = new Cesium.Cartesian3()
+    Cesium.Matrix3.getColumn(halfAxes, 0, xAxis)
+    Cesium.Matrix3.getColumn(halfAxes, 1, yAxis)
+    Cesium.Matrix3.getColumn(halfAxes, 2, zAxis)
+
+    // 计算原始的8个顶点
+    directions.forEach(dir => {
+      const vertex = Cesium.Cartesian3.clone(center)
+      Cesium.Cartesian3.add(vertex, Cesium.Cartesian3.multiplyByScalar(xAxis, dir[0], new Cesium.Cartesian3()), vertex)
+      Cesium.Cartesian3.add(vertex, Cesium.Cartesian3.multiplyByScalar(yAxis, dir[1], new Cesium.Cartesian3()), vertex)
+      Cesium.Cartesian3.add(vertex, Cesium.Cartesian3.multiplyByScalar(zAxis, dir[2], new Cesium.Cartesian3()), vertex)
+      tempVertices.push(vertex)
+    })
+
+    // 转换为地理坐标,找到边界范围
+    let minLon = Infinity, maxLon = -Infinity
+    let minLat = Infinity, maxLat = -Infinity
+    let minHeight = Infinity, maxHeight = -Infinity
+
+    tempVertices.forEach(vertex => {
+      const cartographic = Cesium.Cartographic.fromCartesian(vertex)
+      const lon = Cesium.Math.toDegrees(cartographic.longitude)
+      const lat = Cesium.Math.toDegrees(cartographic.latitude)
+      const height = cartographic.height
+
+      minLon = Math.min(minLon, lon)
+      maxLon = Math.max(maxLon, lon)
+      minLat = Math.min(minLat, lat)
+      maxLat = Math.max(maxLat, lat)
+      minHeight = Math.min(minHeight, height)
+      maxHeight = Math.max(maxHeight, height)
+    })
+
+    // 创建轴对齐的边界框顶点(平行于地面)
+    const vertices = [
+      // 底面4个顶点
+      Cesium.Cartesian3.fromDegrees(minLon, minLat, minHeight), // 0: 左下后
+      Cesium.Cartesian3.fromDegrees(maxLon, minLat, minHeight), // 1: 右下后
+      Cesium.Cartesian3.fromDegrees(minLon, maxLat, minHeight), // 2: 左上后
+      Cesium.Cartesian3.fromDegrees(maxLon, maxLat, minHeight), // 3: 右上后
+      // 顶面4个顶点
+      Cesium.Cartesian3.fromDegrees(minLon, minLat, maxHeight), // 4: 左下前
+      Cesium.Cartesian3.fromDegrees(maxLon, minLat, maxHeight), // 5: 右下前
+      Cesium.Cartesian3.fromDegrees(minLon, maxLat, maxHeight), // 6: 左上前
+      Cesium.Cartesian3.fromDegrees(maxLon, maxLat, maxHeight)  // 7: 右上前
+    ]
+
+    return vertices
+  }
+
+  // ================================
+  // 处理球体边界的情况
+  // ================================
+  getBoundingSphereVertices (sphere) {
+    const center = sphere.center
+    const radius = sphere.radius
+
+    // 将球心转换为地理坐标
+    const centerCartographic = Cesium.Cartographic.fromCartesian(center)
+    const centerLon = Cesium.Math.toDegrees(centerCartographic.longitude)
+    const centerLat = Cesium.Math.toDegrees(centerCartographic.latitude)
+    const centerHeight = centerCartographic.height
+
+    // 估算经纬度范围(简化处理)
+    const deltaLon = radius / (111320 * Math.cos(centerCartographic.latitude)) // 经度差
+    const deltaLat = radius / 110540 // 纬度差
+
+    // 创建轴对齐的边界框顶点
+    const vertices = [
+      // 底面4个顶点
+      Cesium.Cartesian3.fromDegrees(centerLon - deltaLon, centerLat - deltaLat, centerHeight - radius),
+      Cesium.Cartesian3.fromDegrees(centerLon + deltaLon, centerLat - deltaLat, centerHeight - radius),
+      Cesium.Cartesian3.fromDegrees(centerLon - deltaLon, centerLat + deltaLat, centerHeight - radius),
+      Cesium.Cartesian3.fromDegrees(centerLon + deltaLon, centerLat + deltaLat, centerHeight - radius),
+      // 顶面4个顶点
+      Cesium.Cartesian3.fromDegrees(centerLon - deltaLon, centerLat - deltaLat, centerHeight + radius),
+      Cesium.Cartesian3.fromDegrees(centerLon + deltaLon, centerLat - deltaLat, centerHeight + radius),
+      Cesium.Cartesian3.fromDegrees(centerLon - deltaLon, centerLat + deltaLat, centerHeight + radius),
+      Cesium.Cartesian3.fromDegrees(centerLon + deltaLon, centerLat + deltaLat, centerHeight + radius)
+    ]
+
+    return vertices
+  }
+
+  // ================================
+  // 获取网格边界框的8个顶点
+  // ================================
+  getGridBoundingBoxVertices (gridBounds) {
+    const vertices = [
+      // 底面4个顶点
+      Cesium.Cartesian3.fromDegrees(gridBounds.minLon, gridBounds.minLat, gridBounds.minHeight),
+      Cesium.Cartesian3.fromDegrees(gridBounds.maxLon, gridBounds.minLat, gridBounds.minHeight),
+      Cesium.Cartesian3.fromDegrees(gridBounds.minLon, gridBounds.maxLat, gridBounds.minHeight),
+      Cesium.Cartesian3.fromDegrees(gridBounds.maxLon, gridBounds.maxLat, gridBounds.minHeight),
+      // 顶面4个顶点
+      Cesium.Cartesian3.fromDegrees(gridBounds.minLon, gridBounds.minLat, gridBounds.maxHeight),
+      Cesium.Cartesian3.fromDegrees(gridBounds.maxLon, gridBounds.minLat, gridBounds.maxHeight),
+      Cesium.Cartesian3.fromDegrees(gridBounds.minLon, gridBounds.maxLat, gridBounds.maxHeight),
+      Cesium.Cartesian3.fromDegrees(gridBounds.maxLon, gridBounds.maxLat, gridBounds.maxHeight)
+    ]
+
+    return vertices
+  }
+
+  // ================================
+  // 检查两个轴对齐边界框(AABB)是否相交
+  // ================================
+  checkAABBIntersection (vertices1, vertices2) {
+    // 将顶点转换为地理坐标进行比较
+    const bounds1 = this.getVerticesBounds(vertices1)
+    const bounds2 = this.getVerticesBounds(vertices2)
+
+    // 3D AABB相交检测
+    const tolerance = 0.0001
+
+    const intersects = !(
+      bounds1.maxLon < bounds2.minLon - tolerance ||
+      bounds1.minLon > bounds2.maxLon + tolerance ||
+      bounds1.maxLat < bounds2.minLat - tolerance ||
+      bounds1.minLat > bounds2.maxLat + tolerance ||
+      bounds1.maxHeight < bounds2.minHeight - tolerance ||
+      bounds1.minHeight > bounds2.maxHeight + tolerance
+    )
+
+    return intersects
+  }
+
+  // ================================
+  // 从顶点计算边界范围
+  // ================================
+  getVerticesBounds (vertices) {
+    let minLon = Infinity, maxLon = -Infinity
+    let minLat = Infinity, maxLat = -Infinity
+    let minHeight = Infinity, maxHeight = -Infinity
+
+    vertices.forEach(vertex => {
+      const cartographic = Cesium.Cartographic.fromCartesian(vertex)
+      const lon = Cesium.Math.toDegrees(cartographic.longitude)
+      const lat = Cesium.Math.toDegrees(cartographic.latitude)
+      const height = cartographic.height
+
+      minLon = Math.min(minLon, lon)
+      maxLon = Math.max(maxLon, lon)
+      minLat = Math.min(minLat, lat)
+      maxLat = Math.max(maxLat, lat)
+      minHeight = Math.min(minHeight, height)
+      maxHeight = Math.max(maxHeight, height)
+    })
+
+    return {
+      minLon: minLon,
+      maxLon: maxLon,
+      minLat: minLat,
+      maxLat: maxLat,
+      minHeight: minHeight,
+      maxHeight: maxHeight
+    }
+  }
+
+  // ================================
+  // 计算网格单元的边界范围
+  // ================================
+  calculateGridBounds (gridCenter) {
+    const gridLon = Cesium.Math.toDegrees(gridCenter.longitude)
+    const gridLat = Cesium.Math.toDegrees(gridCenter.latitude)
+    const gridHeight = gridCenter.height
+
+    // 计算网格单元的边界范围
+    const earthRadius = 6371000
+    const halfSize = this.gridSize / 2
+
+    // 计算经纬度的半范围
+    const deltaLon = halfSize / (earthRadius * Math.cos(gridCenter.latitude))
+    const deltaLat = halfSize / earthRadius
+
+    return {
+      minLon: gridLon - Cesium.Math.toDegrees(deltaLon),
+      maxLon: gridLon + Cesium.Math.toDegrees(deltaLon),
+      minLat: gridLat - Cesium.Math.toDegrees(deltaLat),
+      maxLat: gridLat + Cesium.Math.toDegrees(deltaLat),
+      minHeight: gridHeight - halfSize,
+      maxHeight: gridHeight + halfSize
+    }
+  }
+
+
+
+
+
+  // ================================
+  // 创建网格单元的边界框
+  // ================================
+  createGridBoundingBox (gridCenter) {
+    // 将地理坐标转换为笛卡尔坐标
+    const centerCartesian = Cesium.Cartesian3.fromRadians(
+      gridCenter.longitude,
+      gridCenter.latitude,
+      gridCenter.height
+    )
+
+    // 创建半扩展向量
+    const halfSize = this.gridSize / 2
+    const halfExtents = new Cesium.Cartesian3(halfSize, halfSize, halfSize)
+
+    return {
+      center: centerCartesian,
+      halfExtents: halfExtents
+    }
+  }
+
+  // ================================
+  // 检查两个边界框是否相交
+  // ================================
+  checkBoundingBoxIntersection (box1, box2) {
+    // 计算两个边界框的最小和最大点
+    const box1Min = Cesium.Cartesian3.subtract(box1.center, box1.halfExtents, new Cesium.Cartesian3())
+    const box1Max = Cesium.Cartesian3.add(box1.center, box1.halfExtents, new Cesium.Cartesian3())
+
+    const box2Min = Cesium.Cartesian3.subtract(box2.center, box2.halfExtents, new Cesium.Cartesian3())
+    const box2Max = Cesium.Cartesian3.add(box2.center, box2.halfExtents, new Cesium.Cartesian3())
+
+    // 检查在三个轴上是否都有重叠
+    return (box1Min.x <= box2Max.x && box1Max.x >= box2Min.x &&
+      box1Min.y <= box2Max.y && box1Max.y >= box2Min.y &&
+      box1Min.z <= box2Max.z && box1Max.z >= box2Min.z)
+  }
+
+  // ================================
+  // 创建网格立方体 - 使用配置的颜色和尺寸
+  // ================================
+  createGridCube (gridCenter, isOccupied, customGridSize = null, gridIndex = null) {
+    // 将地理坐标转换为笛卡尔坐标
+    const position = Cesium.Cartesian3.fromRadians(
+      gridCenter.longitude,
+      gridCenter.latitude,
+      gridCenter.height
+    )
+
+    // 使用配置的颜色和透明度
+    const color = isOccupied ?
+      (this.config.occupiedColor || Cesium.Color.RED.withAlpha(this.config.occupiedAlpha)) :
+      (this.config.freeColor || Cesium.Color.GREEN.withAlpha(this.config.freeAlpha))
+
+    const outlineColor = isOccupied ?
+      this.config.occupiedOutlineColor :
+      this.config.freeOutlineColor
+
+    // 使用自定义尺寸或配置的网格尺寸
+    const gridSize = customGridSize || this.config.gridSize
+    const dimensions = new Cesium.Cartesian3(
+      this.config.gridWidth || gridSize,
+      this.config.gridHeight || gridSize,
+      this.config.gridDepth || gridSize
+    )
+
+    // 创建立方体实体
+    const entity = this.viewer.entities.add({
+      position: position,
+      show: isOccupied ? this.gridParams.showOccupancy : this.gridParams.showIdle,
+      box: {
+        dimensions: dimensions,
+        material: color,
+        outline: true,
+        outlineColor: outlineColor,
+        outlineWidth: this.config.outlineWidth
+      },
+      // 添加占用状态标记,用于统计
+      properties: {
+        isOccupied: isOccupied,
+        gridType: isOccupied ? 'occupied' : 'free',
+        createdAt: new Date().toISOString(),
+        gridIndex: gridIndex // 存储网格索引号
+      }
+    })
+
+    this.gridEntities.push(entity)
+
+    if (isOccupied && this.config.enableLogging) {
+      const indexStr = gridIndex ? `索引[${gridIndex.x},${gridIndex.y},${gridIndex.z}] ` : ''
+      console.log(`创建占用网格 ${indexStr}在位置: [${Cesium.Math.toDegrees(gridCenter.longitude).toFixed(6)}, ${Cesium.Math.toDegrees(gridCenter.latitude).toFixed(6)}, ${gridCenter.height.toFixed(1)}]`)
+    }
+  }
+
+  // ================================
+  // 清除网格
+  // ================================
+  clearGrid () {
+    // 移除所有网格实体
+    this.gridEntities.forEach(entity => {
+      this.viewer.entities.remove(entity)
+    })
+    this.gridEntities = []
+
+    // 清除瓦片边界框数据
+    this.tilesBoundingBoxes = []
+
+    console.log('已清除3D占用网格')
+  }
+
+  // ================================
+  // 切换网格显示
+  // ================================
+  toggleGridVisibility (visible) {
+    this.gridEntities.forEach(entity => {
+      entity.show = visible
+    })
+
+    console.log(`3D占用网格${visible ? '显示' : '隐藏'}`)
+  }
+
+  // ================================
+  // 获取网格统计信息 - 使用配置参数
+  // ================================
+  getGridStatistics () {
+    const totalGrids = this.gridEntities.length
+    const occupiedGrids = this.gridEntities.filter(entity =>
+      entity.properties && entity.properties.isOccupied
+    ).length
+    const freeGrids = totalGrids - occupiedGrids
+    const occupancyRate = totalGrids > 0 ? Math.round((occupiedGrids / totalGrids) * 100) : 0
+
+    if (this.config.enableLogging) {
+      console.log(`网格统计: 总计${totalGrids}, 占用${occupiedGrids}, 空闲${freeGrids}, 占用率${occupancyRate}%`)
+      console.log(`网格配置: 尺寸${this.config.gridWidth}x${this.config.gridHeight}x${this.config.gridDepth}m, 扩展${this.config.heightExtension}m(垂直)/${this.config.widthExtension}m(水平)`)
+    }
+
+    return {
+      total: totalGrids,
+      occupied: occupiedGrids,
+      free: freeGrids,
+      occupancyRate: occupancyRate,
+      config: this.getConfig()
+    }
+  }
+
+  // ================================
+  // 获取占用网格数量
+  // ================================
+  getOccupiedGridCount () {
+    return this.gridEntities.filter(entity =>
+      entity.properties && entity.properties.isOccupied
+    ).length
+  }
+
+  // 只显示占用
+  sheGridDisplay () {
+    this.gridEntities.forEach(entity => {
+      const isOccupied = entity.properties.isOccupied?._value
+      entity.show = isOccupied ? this.gridParams.showOccupancy : this.gridParams.showIdle
+    })
+  }
+
+  // ================================
+  // 将OrientedBoundingBox转换为轴对齐边界框
+  // ================================
+  orientedBoundingBoxToAxisAligned (obb) {
+    const center = obb.center
+    const halfAxes = obb.halfAxes
+
+    // 计算8个顶点
+    const vertices = []
+    const directions = [
+      [-1, -1, -1], [-1, -1, 1], [-1, 1, -1], [-1, 1, 1],
+      [1, -1, -1], [1, -1, 1], [1, 1, -1], [1, 1, 1]
+    ]
+
+    // 提取三个轴向的向量
+    const xAxis = new Cesium.Cartesian3()
+    const yAxis = new Cesium.Cartesian3()
+    const zAxis = new Cesium.Cartesian3()
+    Cesium.Matrix3.getColumn(halfAxes, 0, xAxis)
+    Cesium.Matrix3.getColumn(halfAxes, 1, yAxis)
+    Cesium.Matrix3.getColumn(halfAxes, 2, zAxis)
+
+    directions.forEach(dir => {
+      const vertex = Cesium.Cartesian3.clone(center)
+      Cesium.Cartesian3.add(vertex, Cesium.Cartesian3.multiplyByScalar(xAxis, dir[0], new Cesium.Cartesian3()), vertex)
+      Cesium.Cartesian3.add(vertex, Cesium.Cartesian3.multiplyByScalar(yAxis, dir[1], new Cesium.Cartesian3()), vertex)
+      Cesium.Cartesian3.add(vertex, Cesium.Cartesian3.multiplyByScalar(zAxis, dir[2], new Cesium.Cartesian3()), vertex)
+      vertices.push(vertex)
+    })
+
+    // 转换为地理坐标,找到边界范围
+    let minLon = Infinity, maxLon = -Infinity
+    let minLat = Infinity, maxLat = -Infinity
+    let minHeight = Infinity, maxHeight = -Infinity
+
+    vertices.forEach(vertex => {
+      const cartographic = Cesium.Cartographic.fromCartesian(vertex)
+      const lon = Cesium.Math.toDegrees(cartographic.longitude)
+      const lat = Cesium.Math.toDegrees(cartographic.latitude)
+      const height = cartographic.height
+
+      minLon = Math.min(minLon, lon)
+      maxLon = Math.max(maxLon, lon)
+      minLat = Math.min(minLat, lat)
+      maxLat = Math.max(maxLat, lat)
+      minHeight = Math.min(minHeight, height)
+      maxHeight = Math.max(maxHeight, height)
+    })
+
+    return {
+      center: center,
+      minLon: minLon,
+      maxLon: maxLon,
+      minLat: minLat,
+      maxLat: maxLat,
+      minHeight: minHeight,
+      maxHeight: maxHeight
+    }
+  }
+
+  // ================================
+  // 将BoundingSphere转换为轴对齐边界框
+  // ================================
+  sphereToAxisAligned (sphere) {
+    const center = sphere.center
+    const radius = sphere.radius
+
+    // 将球心转换为地理坐标
+    const centerCartographic = Cesium.Cartographic.fromCartesian(center)
+    const centerLon = Cesium.Math.toDegrees(centerCartographic.longitude)
+    const centerLat = Cesium.Math.toDegrees(centerCartographic.latitude)
+    const centerHeight = centerCartographic.height
+
+    // 估算经纬度范围(简化处理)
+    const deltaLon = radius / (111320 * Math.cos(centerCartographic.latitude)) // 经度差
+    const deltaLat = radius / 110540 // 纬度差
+
+    return {
+      center: center,
+      minLon: centerLon - deltaLon,
+      maxLon: centerLon + deltaLon,
+      minLat: centerLat - deltaLat,
+      maxLat: centerLat + deltaLat,
+      minHeight: centerHeight - radius,
+      maxHeight: centerHeight + radius
+    }
+  }
+}
+
+export default OccupancyGrid
diff --git a/src/views/gridManagement/GridSettings/PathPlanning.js b/src/views/gridManagement/GridSettings/PathPlanning.js
new file mode 100644
index 0000000..abc18a9
--- /dev/null
+++ b/src/views/gridManagement/GridSettings/PathPlanning.js
@@ -0,0 +1,1058 @@
+// ================================
+// A*航线规划模块 - 基于3D栅格索引
+// ================================
+import * as Cesium from 'cesium'
+
+class PathPlanning {
+  constructor(viewer, occupancyGrid) {
+    this.viewer = viewer;
+    this.occupancyGrid = occupancyGrid;
+    this.pathEntities = [];
+    this.isEnabled = false;
+
+    // 路径配置
+    this.config = {
+      pathColor: Cesium.Color.YELLOW.withAlpha(0.8), // 路径颜色(黄色)
+      pathOutlineColor: Cesium.Color.ORANGE, // 路径边框颜色
+      startPointColor: Cesium.Color.BLUE.withAlpha(0.9), // 起点颜色(蓝色)
+      endPointColor: Cesium.Color.BLUE.withAlpha(0.9), // 终点颜色(蓝色)
+      startEndOutlineColor: Cesium.Color.DARKBLUE, // 起点终点边框颜色
+      outlineWidth: 2, // 边框宽度
+      enableDiagonal: true, // 是否允许对角线移动(3D中为26连通性)
+      verticalWeight: 1.2 // 垂直移动权重(略高于水平移动)
+    };
+
+    // 显示控制
+    this.showOnlyPath = false; // 是否只显示路径单元
+    this.hasActivePath = false; // 是否有活跃的路径
+
+    // 3D栅格数据结构
+    this.grid3D = null; // 3维数组存储占用状态
+    this.gridDimensions = { width: 0, height: 0, depth: 0 }; // 栅格尺寸
+    this.gridEntityMap = new Map(); // 栅格索引(字符串)到实体的映射
+    this.indexToEntityMap = new Map(); // 栅格索引对象到实体的映射
+
+    // A*算法相关
+    this.openList = []; // 开放列表
+    this.closedList = []; // 关闭列表
+  }
+
+  // ================================
+  // 启用/禁用路径规划功能
+  // ================================
+  setEnabled(enabled) {
+    this.isEnabled = enabled;
+    if (!enabled) {
+      this.clearPath();
+    }
+  }
+
+  // ================================
+  // A*路径规划主函数 - 完全基于3D栅格索引
+  // ================================
+  async planPath() {
+    if (!this.isEnabled || !this.occupancyGrid.gridEntities.length) {
+      console.warn('路径规划未启用或网格未生成');
+      return;
+    }
+
+    try {
+      console.log('开始基于3D栅格索引的A*路径规划...');
+
+      // 1. 构建3D栅格索引结构和占用状态数组
+      this.build3DGridStructure();
+
+      // 2. 通过最近邻查找获取航线起点和终点对应的3D栅格索引
+      const { startIndex, endIndex } = await this.findWaypointGridIndices();
+
+      if (!startIndex || !endIndex) {
+        console.warn('无法找到航线起点或终点对应的栅格索引');
+        alert('无法找到航线起点或终点对应的栅格索引!');
+        return;
+      }
+
+      console.log('起点栅格索引:', startIndex);
+      console.log('终点栅格索引:', endIndex);
+      console.log('3D栅格维度:', this.gridDimensions);
+
+      // 3. 首先显示起点和终点(蓝色)
+      console.log('首先显示起点和终点...');
+      this.visualizeStartEndPoints(startIndex, endIndex);
+
+      // 等待一小段时间让用户看到起点和终点
+      await new Promise(resolve => setTimeout(resolve, 1000));
+
+      // 4. 在三维数组上执行A*路径规划
+      console.log('开始执行A*路径规划算法...');
+      const pathIndices = this.aStarOnGrid3D(startIndex, endIndex);
+
+      if (pathIndices && pathIndices.length > 0) {
+        // 5. 通过索引找到对应的3D占用网格单元,复制并修改颜色(包含起点终点的蓝色)
+        this.visualizePathByGridCopy(pathIndices, startIndex, endIndex);
+        console.log(`路径规划成功,路径长度:${pathIndices.length}个栅格索引`);
+
+        // 更新UI
+        this.updatePathInfo(pathIndices);
+      } else {
+        console.warn('未找到可行路径');
+        alert('未找到从起点到终点的可行路径!');
+        // 即使没找到路径,也保持起点终点的显示
+      }
+
+    } catch (error) {
+      console.error('路径规划错误:', error);
+      alert('路径规划过程中发生错误,请查看控制台日志。');
+    }
+  }
+
+  // ================================
+  // 构建3D栅格索引结构和占用状态数组 - 直接使用网格实体properties数据
+  // ================================
+  build3DGridStructure() {
+    console.log('开始构建3D栅格索引结构,直接使用网格实体properties数据...');
+
+    if (!this.occupancyGrid.gridEntities.length) {
+      throw new Error('没有可用的占用网格实体');
+    }
+
+    // 第一步:分析所有网格实体,从properties中提取gridIndex,确定栅格维度
+    let minX = Infinity, minY = Infinity, minZ = Infinity;
+    let maxX = -Infinity, maxY = -Infinity, maxZ = -Infinity;
+
+    const validEntities = [];
+
+    // 遍历所有网格实体,提取gridIndex信息
+    for (const entity of this.occupancyGrid.gridEntities) {
+      // 直接从properties中获取gridIndex
+      if (entity.properties && entity.properties.gridIndex) {
+        const gridIndex = entity.properties.gridIndex.getValue();
+
+        if (gridIndex && typeof gridIndex.x === 'number' &&
+            typeof gridIndex.y === 'number' && typeof gridIndex.z === 'number') {
+
+          // 更新维度范围
+          minX = Math.min(minX, gridIndex.x);
+          maxX = Math.max(maxX, gridIndex.x);
+          minY = Math.min(minY, gridIndex.y);
+          maxY = Math.max(maxY, gridIndex.y);
+          minZ = Math.min(minZ, gridIndex.z);
+          maxZ = Math.max(maxZ, gridIndex.z);
+
+          validEntities.push(entity);
+        } else {
+          console.warn('网格实体properties中的gridIndex格式不正确:', gridIndex);
+        }
+      } else {
+        console.warn('网格实体缺少gridIndex属性');
+      }
+    }
+
+    if (validEntities.length === 0) {
+      throw new Error('没有找到包含有效gridIndex的网格实体');
+    }
+
+    // 计算栅格维度(基于实际的索引范围)
+    this.gridDimensions = {
+      width: maxX - minX + 1,
+      height: maxY - minY + 1,
+      depth: maxZ - minZ + 1
+    };
+
+    console.log(`从properties提取的3D栅格维度: ${this.gridDimensions.width} x ${this.gridDimensions.height} x ${this.gridDimensions.depth}`);
+    console.log(`索引范围: X[${minX}, ${maxX}], Y[${minY}, ${maxY}], Z[${minZ}, ${maxZ}]`);
+
+    // 第二步:初始化3D占用状态数组
+    this.grid3D = new Array(this.gridDimensions.width);
+    for (let x = 0; x < this.gridDimensions.width; x++) {
+      this.grid3D[x] = new Array(this.gridDimensions.height);
+      for (let y = 0; y < this.gridDimensions.height; y++) {
+        this.grid3D[x][y] = new Array(this.gridDimensions.depth);
+        for (let z = 0; z < this.gridDimensions.depth; z++) {
+          this.grid3D[x][y][z] = {
+            occupied: false,
+            entity: null,
+            exists: false
+          };
+        }
+      }
+    }
+
+    // 第三步:直接使用实体properties数据填充3D数组
+    this.gridEntityMap.clear();
+    this.indexToEntityMap.clear();
+
+    let mappedCount = 0;
+    let occupiedCount = 0;
+    let freeCount = 0;
+
+    // 记录索引偏移量,将原始索引映射到数组索引
+    this.indexOffset = { x: minX, y: minY, z: minZ };
+
+    for (const entity of validEntities) {
+      const gridIndex = entity.properties.gridIndex.getValue();
+      const isOccupied = entity.properties.isOccupied ? entity.properties.isOccupied.getValue() : false;
+
+      // 转换为数组索引(相对于最小值的偏移)
+      const arrayX = gridIndex.x - minX;
+      const arrayY = gridIndex.y - minY;
+      const arrayZ = gridIndex.z - minZ;
+
+      // 确保索引在有效范围内
+      if (arrayX >= 0 && arrayX < this.gridDimensions.width &&
+          arrayY >= 0 && arrayY < this.gridDimensions.height &&
+          arrayZ >= 0 && arrayZ < this.gridDimensions.depth) {
+
+        // 存储到3D数组
+        this.grid3D[arrayX][arrayY][arrayZ] = {
+          occupied: isOccupied,
+          entity: entity,
+          exists: true,
+          originalIndex: { x: gridIndex.x, y: gridIndex.y, z: gridIndex.z } // 保存原始索引
+        };
+
+        // 建立映射关系
+        const gridKey = `${arrayX},${arrayY},${arrayZ}`;
+        this.gridEntityMap.set(gridKey, entity);
+        this.indexToEntityMap.set(`${arrayX}_${arrayY}_${arrayZ}`, entity);
+
+        mappedCount++;
+        if (isOccupied) {
+          occupiedCount++;
+        } else {
+          freeCount++;
+        }
+      } else {
+        console.warn(`网格索引超出范围: 原始(${gridIndex.x}, ${gridIndex.y}, ${gridIndex.z}) -> 数组(${arrayX}, ${arrayY}, ${arrayZ})`);
+      }
+    }
+
+    console.log(`3D栅格结构构建完成:`);
+    console.log(`- 栅格维度: ${this.gridDimensions.width} x ${this.gridDimensions.height} x ${this.gridDimensions.depth}`);
+    console.log(`- 索引偏移: (${this.indexOffset.x}, ${this.indexOffset.y}, ${this.indexOffset.z})`);
+    console.log(`- 映射实体数: ${mappedCount}`);
+    console.log(`- 占用栅格: ${occupiedCount}`);
+    console.log(`- 空闲栅格: ${freeCount}`);
+    console.log(`- 占用率: ${mappedCount > 0 ? ((occupiedCount / mappedCount) * 100).toFixed(1) : 0}%`);
+  }
+
+  // ================================
+  // 通过最近邻查找获取航线起点和终点对应的3D栅格索引
+  // ================================
+  async findWaypointGridIndices() {
+    console.log('开始通过最近邻查找航线起点和终点对应的栅格索引...');
+
+    // 获取航线航点
+    const waypoints = this.getFlightWaypoints();
+
+    if (!waypoints || waypoints.length < 2) {
+      console.warn('航线航点不足,无法确定起点和终点');
+      return { startIndex: null, endIndex: null };
+    }
+
+    const startWaypoint = waypoints[0];
+    const endWaypoint = waypoints[waypoints.length - 1];
+
+    console.log('航线起点位置:', startWaypoint.position);
+    console.log('航线终点位置:', endWaypoint.position);
+
+    // 使用最近邻搜索找到对应的栅格索引
+    const startIndex = this.findNearestGridIndex(startWaypoint.position);
+    const endIndex = this.findNearestGridIndex(endWaypoint.position);
+
+    if (!startIndex) {
+      console.error('无法找到航线起点对应的栅格索引');
+      return { startIndex: null, endIndex: null };
+    }
+
+    if (!endIndex) {
+      console.error('无法找到航线终点对应的栅格索引');
+      return { startIndex: null, endIndex: null };
+    }
+
+    // 验证找到的栅格索引是否可通行
+    if (this.grid3D[startIndex.x][startIndex.y][startIndex.z].occupied) {
+      console.warn('起点栅格被占用,尝试寻找附近的空闲栅格...');
+      const freeStartIndex = this.findNearestFreeGrid(startIndex);
+      if (freeStartIndex) {
+        console.log(`找到起点附近的空闲栅格: (${freeStartIndex.x}, ${freeStartIndex.y}, ${freeStartIndex.z})`);
+        startIndex.x = freeStartIndex.x;
+        startIndex.y = freeStartIndex.y;
+        startIndex.z = freeStartIndex.z;
+      } else {
+        console.error('起点附近没有可通行的栅格');
+        return { startIndex: null, endIndex: null };
+      }
+    }
+
+    if (this.grid3D[endIndex.x][endIndex.y][endIndex.z].occupied) {
+      console.warn('终点栅格被占用,尝试寻找附近的空闲栅格...');
+      const freeEndIndex = this.findNearestFreeGrid(endIndex);
+      if (freeEndIndex) {
+        console.log(`找到终点附近的空闲栅格: (${freeEndIndex.x}, ${freeEndIndex.y}, ${freeEndIndex.z})`);
+        endIndex.x = freeEndIndex.x;
+        endIndex.y = freeEndIndex.y;
+        endIndex.z = freeEndIndex.z;
+      } else {
+        console.error('终点附近没有可通行的栅格');
+        return { startIndex: null, endIndex: null };
+      }
+    }
+
+    console.log(`成功找到起点栅格索引: (${startIndex.x}, ${startIndex.y}, ${startIndex.z})`);
+    console.log(`成功找到终点栅格索引: (${endIndex.x}, ${endIndex.y}, ${endIndex.z})`);
+
+    return { startIndex, endIndex };
+  }
+
+  // ================================
+  // 最近邻搜索:找到距离指定世界坐标最近的栅格索引 - 直接使用properties数据
+  // ================================
+  findNearestGridIndex(targetPosition) {
+    let nearestIndex = null;
+    let minDistance = Infinity;
+    let nearestEntity = null;
+
+    // 直接遍历所有网格实体,使用properties中的gridIndex
+    for (const entity of this.occupancyGrid.gridEntities) {
+      if (entity.properties && entity.properties.gridIndex && entity.position) {
+        try {
+          // 获取栅格实体的位置
+          const entityPosition = entity.position.getValue(this.viewer.clock.currentTime);
+
+          // 计算距离
+          const distance = Cesium.Cartesian3.distance(targetPosition, entityPosition);
+
+          if (distance < minDistance) {
+            minDistance = distance;
+            nearestEntity = entity;
+
+            // 直接从properties获取gridIndex,并转换为数组索引
+            const originalIndex = entity.properties.gridIndex.getValue();
+            nearestIndex = {
+              x: originalIndex.x - this.indexOffset.x,
+              y: originalIndex.y - this.indexOffset.y,
+              z: originalIndex.z - this.indexOffset.z,
+              original: originalIndex // 保存原始索引以便调试
+            };
+          }
+        } catch (error) {
+          console.warn('处理网格实体时出错:', error);
+        }
+      }
+    }
+
+    if (nearestIndex) {
+      console.log(`找到最近栅格索引: 数组索引(${nearestIndex.x}, ${nearestIndex.y}, ${nearestIndex.z}), 原始索引(${nearestIndex.original.x}, ${nearestIndex.original.y}, ${nearestIndex.original.z}), 距离: ${minDistance.toFixed(2)}m`);
+
+      // 验证找到的索引是否有效
+      if (!this.isValidGridIndex(nearestIndex)) {
+        console.error('找到的栅格索引无效');
+        return null;
+      }
+
+      // 移除original属性,只返回数组索引
+      return { x: nearestIndex.x, y: nearestIndex.y, z: nearestIndex.z };
+    } else {
+      console.warn('未找到最近的栅格索引');
+      return null;
+    }
+  }
+
+  // ================================
+  // 寻找指定栅格索引附近的空闲(可通行)栅格
+  // ================================
+  findNearestFreeGrid(centerIndex) {
+    const searchRadius = 3; // 搜索半径
+
+    for (let radius = 1; radius <= searchRadius; radius++) {
+      for (let dx = -radius; dx <= radius; dx++) {
+        for (let dy = -radius; dy <= radius; dy++) {
+          for (let dz = -radius; dz <= radius; dz++) {
+            const x = centerIndex.x + dx;
+            const y = centerIndex.y + dy;
+            const z = centerIndex.z + dz;
+
+            if (this.isValidGridIndex({ x, y, z })) {
+              const cell = this.grid3D[x][y][z];
+              if (cell.exists && !cell.occupied) {
+                return { x, y, z };
+              }
+            }
+          }
+        }
+      }
+    }
+
+    return null; // 未找到空闲栅格
+  }
+
+  // ================================
+  // 获取航线航点
+  // ================================
+  getFlightWaypoints() {
+    // 尝试从UAVApp获取航线航点
+    if (window.uavApp && window.uavApp.waypoints && window.uavApp.waypoints.length > 0) {
+      return window.uavApp.waypoints;
+    }
+
+    console.warn('未找到航线航点,将无法进行基于航线的路径规划');
+    return [];
+  }
+
+  // ================================
+  // 在三维数组上执行A*路径规划算法
+  // ================================
+  aStarOnGrid3D(startIndex, endIndex) {
+    console.log('开始在三维数组上执行A*路径规划算法...');
+    console.log(`起点: (${startIndex.x}, ${startIndex.y}, ${startIndex.z})`);
+    console.log(`终点: (${endIndex.x}, ${endIndex.y}, ${endIndex.z})`);
+
+    // 清理算法数据结构
+    this.openList = [];
+    this.closedList = [];
+
+    // 创建起始节点
+    const startNode = {
+      x: startIndex.x,
+      y: startIndex.y,
+      z: startIndex.z,
+      g: 0,
+      h: this.calculateHeuristic(startIndex, endIndex),
+      f: 0,
+      parent: null
+    };
+    startNode.f = startNode.g + startNode.h;
+
+    this.openList.push(startNode);
+
+    let iterations = 0;
+    const maxIterations = 50000;
+    let verticalMoves = 0;
+
+    while (this.openList.length > 0 && iterations < maxIterations) {
+      iterations++;
+
+      // 找到f值最小的节点
+      this.openList.sort((a, b) => a.f - b.f);
+      const currentNode = this.openList.shift();
+
+      // 如果到达终点
+      if (currentNode.x === endIndex.x &&
+          currentNode.y === endIndex.y &&
+          currentNode.z === endIndex.z) {
+        console.log(`A*算法完成,迭代次数:${iterations}`);
+        console.log(`垂直移动次数:${verticalMoves}`);
+        return this.reconstructPath(currentNode);
+      }
+
+      // 将当前节点移到关闭列表
+      this.closedList.push(currentNode);
+
+      // 获取邻居节点
+      const neighbors = this.getNeighbors(currentNode);
+
+      for (const neighbor of neighbors) {
+        // 跳过已在关闭列表中的节点
+        if (this.isInClosedList(neighbor)) {
+          continue;
+        }
+
+        // 检查是否可通行
+        if (!this.isTraversable(neighbor.x, neighbor.y, neighbor.z)) {
+          continue;
+        }
+
+        // 计算移动成本
+        const moveCost = this.getMoveCost(currentNode, neighbor);
+        const tentativeG = currentNode.g + moveCost;
+
+        // 统计垂直移动
+        if (neighbor.z !== currentNode.z) {
+          verticalMoves++;
+        }
+
+        // 检查是否已在开放列表中
+        const existingNode = this.findInOpenList(neighbor);
+        if (existingNode) {
+          if (tentativeG < existingNode.g) {
+            existingNode.g = tentativeG;
+            existingNode.h = this.calculateHeuristic(neighbor, endIndex);
+            existingNode.f = existingNode.g + existingNode.h;
+            existingNode.parent = currentNode;
+          }
+        } else {
+          const newNode = {
+            x: neighbor.x,
+            y: neighbor.y,
+            z: neighbor.z,
+            g: tentativeG,
+            h: this.calculateHeuristic(neighbor, endIndex),
+            f: 0,
+            parent: currentNode
+          };
+          newNode.f = newNode.g + newNode.h;
+          this.openList.push(newNode);
+        }
+      }
+
+      // 每1000次迭代输出一次进度
+      if (iterations % 1000 === 0) {
+        const openCount = this.openList.length;
+        const closedCount = this.closedList.length;
+        console.log(`A*算法进度: ${iterations}次迭代, 开放列表: ${openCount}, 关闭列表: ${closedCount}`);
+      }
+    }
+
+    console.warn(`A*算法未找到路径,迭代次数:${iterations}`);
+    return null;
+  }
+
+  // ================================
+  // 重构路径
+  // ================================
+  reconstructPath(endNode) {
+    const path = [];
+    let currentNode = endNode;
+
+    while (currentNode) {
+      path.unshift({
+        x: currentNode.x,
+        y: currentNode.y,
+        z: currentNode.z
+      });
+      currentNode = currentNode.parent;
+    }
+
+    console.log(`路径重构完成,路径长度: ${path.length}个节点`);
+    return path;
+  }
+
+  // ================================
+  // 计算启发式函数(3D曼哈顿距离)
+  // ================================
+  calculateHeuristic(index1, index2) {
+    const dx = Math.abs(index1.x - index2.x);
+    const dy = Math.abs(index1.y - index2.y);
+    const dz = Math.abs(index1.z - index2.z);
+
+    // 使用3D曼哈顿距离,给垂直移动适当权重
+    return dx + dy + (dz * this.config.verticalWeight);
+  }
+
+  // ================================
+  // 获取邻居节点(3D:26连通性)
+  // ================================
+  getNeighbors(currentNode) {
+    const neighbors = [];
+
+    // 3D搜索:包括所有26个方向的邻居
+    for (let dx = -1; dx <= 1; dx++) {
+      for (let dy = -1; dy <= 1; dy++) {
+        for (let dz = -1; dz <= 1; dz++) {
+          if (dx === 0 && dy === 0 && dz === 0) continue;
+
+          // 如果不允许对角线移动,只使用6连通性
+          if (!this.config.enableDiagonal) {
+            const isDirectional = (Math.abs(dx) + Math.abs(dy) + Math.abs(dz)) === 1;
+            if (!isDirectional) continue;
+          }
+
+          const newX = currentNode.x + dx;
+          const newY = currentNode.y + dy;
+          const newZ = currentNode.z + dz;
+
+          // 检查边界
+          if (this.isValidGridIndex({ x: newX, y: newY, z: newZ })) {
+            neighbors.push({ x: newX, y: newY, z: newZ });
+          }
+        }
+      }
+    }
+
+    return neighbors;
+  }
+
+  // ================================
+  // A*算法辅助方法
+  // ================================
+  isInClosedList(node) {
+    return this.closedList.some(n =>
+      n.x === node.x && n.y === node.y && n.z === node.z
+    );
+  }
+
+  findInOpenList(node) {
+    return this.openList.find(n =>
+      n.x === node.x && n.y === node.y && n.z === node.z
+    );
+  }
+
+  // ================================
+  // 检查位置是否可通行
+  // ================================
+  isTraversable(x, y, z) {
+    if (!this.isValidGridIndex({ x, y, z })) {
+      return false;
+    }
+
+    const cell = this.grid3D[x][y][z];
+
+    // 如果该位置不存在网格实体,则不可通行
+    if (!cell.exists) {
+      return false;
+    }
+
+    // 如果有实体但未被占用,可通行
+    return !cell.occupied;
+  }
+
+  // ================================
+  // 计算移动成本
+  // ================================
+  getMoveCost(fromNode, toNode) {
+    const dx = Math.abs(toNode.x - fromNode.x);
+    const dy = Math.abs(toNode.y - fromNode.y);
+    const dz = Math.abs(toNode.z - fromNode.z);
+
+    // 计算基础移动成本
+    let baseCost;
+    if (dx && dy && dz) {
+      baseCost = Math.sqrt(3); // 3D对角线移动
+    } else if ((dx && dy) || (dx && dz) || (dy && dz)) {
+      baseCost = Math.sqrt(2); // 2D对角线移动
+    } else {
+      baseCost = 1; // 直线移动
+    }
+
+    // 如果是垂直移动,应用垂直权重
+    if (dz > 0) {
+      baseCost *= this.config.verticalWeight;
+    }
+
+    return baseCost;
+  }
+
+  // ================================
+  // 通过索引找到对应的3D占用网格单元,复制并修改为黄色 - 使用properties数据
+  // ================================
+  visualizePathByGridCopy(pathIndices, startIndex, endIndex) {
+    console.log('开始通过复制网格单元可视化路径...');
+    console.log('路径索引序列:', pathIndices.map(p => `(${p.x},${p.y},${p.z})`).join(' -> '));
+    console.log(`路径总长度: ${pathIndices.length}个栅格索引`);
+
+    // 清除之前的路径
+    this.clearPath();
+
+    let copiedCount = 0;
+    let missingCount = 0;
+
+    for (let i = 0; i < pathIndices.length; i++) {
+      const gridIndex = pathIndices[i];
+
+      // 从3D数组中获取对应的网格单元
+      const cell = this.grid3D[gridIndex.x][gridIndex.y][gridIndex.z];
+
+      if (cell.exists && cell.entity) {
+        // 获取原始网格实体的信息
+        const sourceEntity = cell.entity;
+        const sourcePosition = sourceEntity.position.getValue(this.viewer.clock.currentTime);
+        const sourceDimensions = sourceEntity.box.dimensions.getValue();
+
+        // 获取原始索引(用于显示和命名)
+        const originalIndex = cell.originalIndex || {
+          x: gridIndex.x + this.indexOffset.x,
+          y: gridIndex.y + this.indexOffset.y,
+          z: gridIndex.z + this.indexOffset.z
+        };
+
+        // 判断是否为起点或终点
+        const isStartPoint = (gridIndex.x === startIndex.x &&
+                             gridIndex.y === startIndex.y &&
+                             gridIndex.z === startIndex.z);
+        const isEndPoint = (gridIndex.x === endIndex.x &&
+                           gridIndex.y === endIndex.y &&
+                           gridIndex.z === endIndex.z);
+
+        // 根据点的类型选择颜色和名称
+        let entityColor, outlineColor, entityName, pointType;
+
+        if (isStartPoint) {
+          entityColor = this.config.startPointColor;
+          outlineColor = this.config.startEndOutlineColor;
+          entityName = `StartPoint_${originalIndex.x}_${originalIndex.y}_${originalIndex.z}`;
+          pointType = '起点';
+        } else if (isEndPoint) {
+          entityColor = this.config.endPointColor;
+          outlineColor = this.config.startEndOutlineColor;
+          entityName = `EndPoint_${originalIndex.x}_${originalIndex.y}_${originalIndex.z}`;
+          pointType = '终点';
+        } else {
+          entityColor = this.config.pathColor;
+          outlineColor = this.config.pathOutlineColor;
+          entityName = `PathGrid_${originalIndex.x}_${originalIndex.y}_${originalIndex.z}`;
+          pointType = '路径';
+        }
+
+        // 复制网格单元,修改颜色
+        const pathEntity = this.viewer.entities.add({
+          name: entityName,
+          position: sourcePosition,
+          box: {
+            dimensions: sourceDimensions,
+            material: entityColor,
+            outline: true,
+            outlineColor: outlineColor,
+            outlineWidth: this.config.outlineWidth
+          },
+          properties: {
+            isPathGrid: true,
+            gridIndex: originalIndex, // 使用原始索引
+            arrayIndex: { x: gridIndex.x, y: gridIndex.y, z: gridIndex.z }, // 保存数组索引
+            sourceEntityId: sourceEntity.id,
+            pathStep: copiedCount,
+            pointType: pointType
+          }
+        });
+
+        this.pathEntities.push(pathEntity);
+        copiedCount++;
+
+        console.log(`复制网格单元 数组索引[${gridIndex.x}, ${gridIndex.y}, ${gridIndex.z}] 原始索引[${originalIndex.x}, ${originalIndex.y}, ${originalIndex.z}] -> ${pointType}网格`);
+
+      } else {
+        missingCount++;
+        console.warn(`网格索引 [${gridIndex.x}, ${gridIndex.y}, ${gridIndex.z}] 对应的网格单元不存在`);
+      }
+    }
+
+    // 设置路径状态
+    this.hasActivePath = copiedCount > 0;
+
+    // 如果启用了只显示路径模式,隐藏其他网格
+    if (this.showOnlyPath && this.hasActivePath) {
+      this.updateGridVisibility();
+    }
+
+    console.log(`路径可视化完成:`);
+    console.log(`- 成功复制网格: ${copiedCount}个`);
+    console.log(`- 缺失网格: ${missingCount}个`);
+
+    // 显示起点和终点的原始索引
+    const startOriginalIndex = this.grid3D[startIndex.x][startIndex.y][startIndex.z].originalIndex ||
+      { x: startIndex.x + this.indexOffset.x, y: startIndex.y + this.indexOffset.y, z: startIndex.z + this.indexOffset.z };
+    const endOriginalIndex = this.grid3D[endIndex.x][endIndex.y][endIndex.z].originalIndex ||
+      { x: endIndex.x + this.indexOffset.x, y: endIndex.y + this.indexOffset.y, z: endIndex.z + this.indexOffset.z };
+
+    console.log(`- 起点: 数组索引(${startIndex.x}, ${startIndex.y}, ${startIndex.z}) 原始索引(${startOriginalIndex.x}, ${startOriginalIndex.y}, ${startOriginalIndex.z}) -> 蓝色`);
+    console.log(`- 终点: 数组索引(${endIndex.x}, ${endIndex.y}, ${endIndex.z}) 原始索引(${endOriginalIndex.x}, ${endOriginalIndex.y}, ${endOriginalIndex.z}) -> 蓝色`);
+
+    if (missingCount > 0) {
+      console.warn(`⚠️ 有${missingCount}个路径索引对应的网格单元缺失`);
+    }
+
+    // 统计路径的3D特征
+    this.analyzePathCharacteristics(pathIndices);
+  }
+
+  // ================================
+  // 分析路径特征
+  // ================================
+  analyzePathCharacteristics(pathIndices) {
+    if (!pathIndices || pathIndices.length === 0) {
+      return;
+    }
+
+    console.log('=== 路径特征分析 ===');
+
+    // 计算路径的空间范围
+    const xValues = pathIndices.map(p => p.x);
+    const yValues = pathIndices.map(p => p.y);
+    const zValues = pathIndices.map(p => p.z);
+
+    const xRange = [Math.min(...xValues), Math.max(...xValues)];
+    const yRange = [Math.min(...yValues), Math.max(...yValues)];
+    const zRange = [Math.min(...zValues), Math.max(...zValues)];
+
+    console.log(`X轴范围: [${xRange[0]}, ${xRange[1]}], 跨度: ${xRange[1] - xRange[0]}`);
+    console.log(`Y轴范围: [${yRange[0]}, ${yRange[1]}], 跨度: ${yRange[1] - yRange[0]}`);
+    console.log(`Z轴范围: [${zRange[0]}, ${zRange[1]}], 跨度: ${zRange[1] - zRange[0]}`);
+
+    // 统计移动类型
+    let verticalMoves = 0;
+    let horizontalMoves = 0;
+    let diagonalMoves = 0;
+
+    for (let i = 1; i < pathIndices.length; i++) {
+      const prev = pathIndices[i - 1];
+      const curr = pathIndices[i];
+
+      const dx = Math.abs(curr.x - prev.x);
+      const dy = Math.abs(curr.y - prev.y);
+      const dz = Math.abs(curr.z - prev.z);
+
+      if (dz > 0) verticalMoves++;
+      if (dx > 0 || dy > 0) horizontalMoves++;
+      if ((dx && dy) || (dx && dz) || (dy && dz)) diagonalMoves++;
+    }
+
+    const totalMoves = pathIndices.length - 1;
+    console.log(`总移动步数: ${totalMoves}`);
+    console.log(`垂直移动: ${verticalMoves} (${(verticalMoves/totalMoves*100).toFixed(1)}%)`);
+    console.log(`水平移动: ${horizontalMoves} (${(horizontalMoves/totalMoves*100).toFixed(1)}%)`);
+    console.log(`对角移动: ${diagonalMoves} (${(diagonalMoves/totalMoves*100).toFixed(1)}%)`);
+
+    // 检查3D路径特征
+    const hasVerticalVariation = (zRange[1] - zRange[0]) > 0;
+    if (hasVerticalVariation) {
+      console.log('✅ 路径包含3D垂直变化,成功进行了立体路径规划');
+    } else {
+      console.log('ℹ️ 路径没有垂直变化,为平面路径');
+    }
+
+    console.log('=== 分析完成 ===');
+  }
+
+  // ================================
+  // 清除路径
+  // ================================
+  clearPath() {
+    // 从场景中移除路径网格实体
+    for (const pathEntity of this.pathEntities) {
+      if (this.viewer.entities.contains(pathEntity)) {
+        this.viewer.entities.remove(pathEntity);
+      }
+    }
+
+    this.pathEntities = [];
+    this.hasActivePath = false; // 重置路径状态
+
+    // 恢复所有网格的显示
+    // this.updateGridVisibility();
+
+    console.log('路径已清除,所有路径网格(包括起点、终点)已从场景中移除');
+  }
+
+  // ================================
+  // 更新路径信息UI
+  // ================================
+  updatePathInfo(pathIndices) {
+    const pathLengthElement = document.getElementById('pathLength');
+    const pathStatusElement = document.getElementById('pathStatus');
+
+    if (pathLengthElement) {
+      pathLengthElement.textContent = pathIndices.length;
+    }
+
+    if (pathStatusElement) {
+      pathStatusElement.textContent = '规划完成';
+    }
+  }
+
+  // ================================
+  // 设置只显示路径模式
+  // ================================
+  setShowOnlyPath(showOnly) {
+    this.showOnlyPath = showOnly;
+    this.updateGridVisibility();
+    console.log(`只显示路径模式: ${showOnly ? '启用' : '禁用'}`);
+  }
+
+  // ================================
+  // 更新网格显示状态
+  // ================================
+  updateGridVisibility() {
+    if (!this.occupancyGrid.gridEntities.length) {
+      return;
+    }
+
+    // 控制原始占用网格的显示
+    for (const entity of this.occupancyGrid.gridEntities) {
+      if (entity.show !== undefined) {
+        if (this.showOnlyPath && this.hasActivePath) {
+          // 只显示路径模式:隐藏原始网格
+          entity.show = false;
+        } else {
+          // 正常显示模式:显示所有原始网格
+          entity.show = true;
+        }
+      }
+    }
+
+    // 控制路径网格的显示(黄色路径网格始终显示,除非被清除)
+    for (const pathEntity of this.pathEntities) {
+      if (pathEntity.show !== undefined) {
+        pathEntity.show = true; // 路径网格始终显示
+      }
+    }
+
+    const pathGridCount = this.pathEntities.length;
+    const originalGridCount = this.occupancyGrid.gridEntities.length;
+
+    console.log(`网格显示状态已更新: ${this.showOnlyPath ? '只显示路径' : '显示全部'}`);
+    console.log(`当前显示: 原始网格 ${this.showOnlyPath && this.hasActivePath ? 0 : originalGridCount} 个, 路径网格 ${pathGridCount} 个`);
+  }
+
+  // ================================
+  // 验证栅格索引是否有效
+  // ================================
+  isValidGridIndex(index) {
+    return index &&
+           typeof index.x === 'number' &&
+           typeof index.y === 'number' &&
+           typeof index.z === 'number' &&
+           index.x >= 0 && index.x < this.gridDimensions.width &&
+           index.y >= 0 && index.y < this.gridDimensions.height &&
+           index.z >= 0 && index.z < this.gridDimensions.depth;
+  }
+
+  // ================================
+  // 首先显示起点和终点(蓝色)
+  // ================================
+  visualizeStartEndPoints(startIndex, endIndex) {
+    console.log('开始显示起点和终点...');
+
+    // 清除之前的路径(如果有)
+    this.clearPath();
+
+    // 显示起点(蓝色)
+    this.createPointVisualization(startIndex, 'start');
+
+    // 显示终点(蓝色)
+    this.createPointVisualization(endIndex, 'end');
+
+    console.log(`起点和终点已显示为蓝色:`);
+    console.log(`- 起点: (${startIndex.x}, ${startIndex.y}, ${startIndex.z})`);
+    console.log(`- 终点: (${endIndex.x}, ${endIndex.y}, ${endIndex.z})`);
+  }
+
+  // ================================
+  // 创建单个点的可视化(起点或终点) - 使用properties数据
+  // ================================
+  createPointVisualization(gridIndex, pointType) {
+    // 从3D数组中获取对应的网格单元
+    const cell = this.grid3D[gridIndex.x][gridIndex.y][gridIndex.z];
+
+    if (cell.exists && cell.entity) {
+      // 获取原始网格实体的信息
+      const sourceEntity = cell.entity;
+      const sourcePosition = sourceEntity.position.getValue(this.viewer.clock.currentTime);
+      const sourceDimensions = sourceEntity.box.dimensions.getValue();
+
+      // 获取原始索引(用于显示和命名)
+      const originalIndex = cell.originalIndex || {
+        x: gridIndex.x + this.indexOffset.x,
+        y: gridIndex.y + this.indexOffset.y,
+        z: gridIndex.z + this.indexOffset.z
+      };
+
+      // 根据点类型设置属性
+      let entityColor, outlineColor, entityName, pointTypeChinese;
+
+      if (pointType === 'start') {
+        entityColor = this.config.startPointColor;
+        outlineColor = this.config.startEndOutlineColor;
+        entityName = `StartPoint_${originalIndex.x}_${originalIndex.y}_${originalIndex.z}`;
+        pointTypeChinese = '起点';
+      } else if (pointType === 'end') {
+        entityColor = this.config.endPointColor;
+        outlineColor = this.config.startEndOutlineColor;
+        entityName = `EndPoint_${originalIndex.x}_${originalIndex.y}_${originalIndex.z}`;
+        pointTypeChinese = '终点';
+      }
+
+      // 创建点的可视化实体
+      const pointEntity = this.viewer.entities.add({
+        name: entityName,
+        position: sourcePosition,
+        box: {
+          dimensions: sourceDimensions,
+          material: entityColor,
+          outline: true,
+          outlineColor: outlineColor,
+          outlineWidth: this.config.outlineWidth
+        },
+        properties: {
+          isPathGrid: true,
+          gridIndex: originalIndex, // 使用原始索引
+          arrayIndex: { x: gridIndex.x, y: gridIndex.y, z: gridIndex.z }, // 保存数组索引
+          sourceEntityId: sourceEntity.id,
+          pointType: pointTypeChinese
+        }
+      });
+
+      this.pathEntities.push(pointEntity);
+      console.log(`创建${pointTypeChinese}可视化: 数组索引[${gridIndex.x}, ${gridIndex.y}, ${gridIndex.z}] 原始索引[${originalIndex.x}, ${originalIndex.y}, ${originalIndex.z}]`);
+
+    } else {
+      console.warn(`网格索引 [${gridIndex.x}, ${gridIndex.y}, ${gridIndex.z}] 对应的网格单元不存在,无法创建${pointType}可视化`);
+    }
+  }
+
+  // ================================
+  // 设置路径实体透明度
+  // ================================
+  setPathAlpha(alpha) {
+    if (alpha < 0.1 || alpha > 1.0) {
+      console.warn('透明度值应该在0.1到1.0之间');
+      return;
+    }
+
+    console.log(`设置路径透明度为: ${alpha}`);
+
+    // 更新配置中的颜色透明度
+    this.config.pathColor = Cesium.Color.YELLOW.withAlpha(alpha);
+    this.config.startPointColor = Cesium.Color.BLUE.withAlpha(alpha);
+    this.config.endPointColor = Cesium.Color.BLUE.withAlpha(alpha);
+
+    // 更新所有现有的路径实体透明度
+    let updatedCount = 0;
+
+    for (const pathEntity of this.pathEntities) {
+      if (pathEntity.box && pathEntity.box.material) {
+        try {
+          // 获取实体的类型
+          const pointType = pathEntity.properties && pathEntity.properties.pointType ?
+            pathEntity.properties.pointType.getValue() : '路径';
+
+          // 根据实体类型设置对应的颜色
+          let newColor;
+          if (pointType === '起点' || pointType === '终点') {
+            newColor = Cesium.Color.BLUE.withAlpha(alpha);
+          } else {
+            newColor = Cesium.Color.YELLOW.withAlpha(alpha);
+          }
+
+          // 更新实体的材质颜色
+          pathEntity.box.material = newColor;
+          updatedCount++;
+
+        } catch (error) {
+          console.warn('更新路径实体透明度时出错:', error);
+        }
+      }
+    }
+
+    console.log(`成功更新${updatedCount}个路径实体的透明度`);
+  }
+
+  // ================================
+  // 获取当前路径透明度
+  // ================================
+  getPathAlpha() {
+    // 从配置中获取当前透明度
+    if (this.config.pathColor && this.config.pathColor.alpha !== undefined) {
+      return this.config.pathColor.alpha;
+    }
+    return 0.8; // 默认透明度
+  }
+}
+
+// ================================
+// 导出模块(如果使用模块系统)
+// ================================
+if (typeof module !== 'undefined' && module.exports) {
+  module.exports = PathPlanning;
+}
+
+
+export default PathPlanning
diff --git a/src/views/gridManagement/gridManagement.vue b/src/views/gridManagement/gridManagement.vue
new file mode 100644
index 0000000..fbe3f7a
--- /dev/null
+++ b/src/views/gridManagement/gridManagement.vue
@@ -0,0 +1,623 @@
+<template>
+  <div class="gridManagement">
+    <div class="search-box">
+      <el-form :model="params" inline>
+        <div style="display: flex;justify-content: space-between">
+         <div>
+          <el-form-item label="网格名称:">
+            <el-input v-model="params.gridName" placeholder="请输入网格名称" clearable />
+          </el-form-item>
+         </div>
+         <div>
+          <el-form-item>
+            <el-button type="primary" @click="getList">搜索</el-button>
+            <el-button @click="cancelSearch">取消</el-button>
+          </el-form-item>
+         </div>
+        </div>
+      </el-form>
+      <div>
+        <el-button type="primary" icon="el-icon-plus" @click="handleAdd">新增网格</el-button>
+      </div>
+    </div>
+    <div class="mange-table">
+			<el-table border :data="tableList" class="custom-header">
+				<el-table-column label="序号" type="index" width="60"></el-table-column>
+        <el-table-column prop="grid_name" label="网格名称" align="center" show-overflow-tooltip></el-table-column>
+        <el-table-column prop="start_point" label="起点" align="center" show-overflow-tooltip></el-table-column>
+        <el-table-column prop="end_point" label="终点" align="center" show-overflow-tooltip></el-table-column>
+        <el-table-column prop="create_time" label="创建时间" align="center"></el-table-column>
+        <el-table-column prop="nick_name" label="创建人" align="center"></el-table-column>
+				<el-table-column label="操作" width="180" align="center">
+					<template #default="scope">
+            <!-- <el-button icon="el-icon-view" type="text" @click="handleDetail(scope.row)">查看</el-button> -->
+            <el-button icon="el-icon-edit" type="text" @click="handleEdit(scope.row)">编辑</el-button>
+						<el-button icon="el-icon-delete" type="text" @click="handleDelete(scope.row)">删除</el-button>
+					</template>
+				</el-table-column>
+			</el-table>
+		</div>
+		<div class="pagination">
+			<el-pagination class="ztzf-pagination" popper-class="custom-pagination-dropdown" background
+				:page-sizes="[10, 20, 30, 40, 50, 100]" :size="size" v-model:current-page="params.current"
+				v-model:page-size="params.size" layout="total, sizes, prev, pager, next, jumper" :total="total"
+				@size-change="handleSizeChange" @current-change="handleCurrentChange" />
+		</div>
+  </div>
+  <el-dialog class="ztzf-dialog" append-to-body v-model="isShowEditView" :title="titleTxt"
+		:width="pxToRem(1000)" :close-on-click-modal="false" :destroy-on-close="true" @close="handleClose">
+		<div class="content-edit">
+      <el-form ref="ruleFormRef" :model="editParams" :rules="rules" inline>
+        <el-form-item label="网格名称" prop="grid_name">
+          <el-input v-model="editParams.grid_name" />
+        </el-form-item>
+      </el-form>
+      <div class="map-container">
+				<div id="GridManagementMap" class="ztzf-cesium"></div>
+			</div>
+      <div class="btns">
+        <el-button type="primary" @click="meshAnalysis"><el-icon><Location /></el-icon>开启网格</el-button>
+        <el-button type="primary" @click="clearGrid"><el-icon><DeleteLocation /></el-icon>清除网格</el-button>
+        <el-button v-if="titleTxt === '新增'" type="primary" @click="submit(ruleFormRef)"><el-icon><CirclePlus /></el-icon>确认</el-button>
+        <el-button v-else type="primary" @click="submit(ruleFormRef)"><el-icon><CircleCheck /></el-icon>修改</el-button>
+        <el-button @click="isShowEditView = false"><el-icon><CircleClose /></el-icon>取消</el-button>
+      </div>
+        <div v-show="showContextMenu" class="context-menu" :style="contextMenuStyle">
+          <div class="menu-item" @click="clearAllPoints">清空网格</div>
+        </div>
+    </div>
+	</el-dialog>
+</template>
+<script setup>
+import { airGridPage, airGridUpdate, airGridAdd, airGridDelete } from '@/api/airspace/airspace';
+import { ElMessage, ElMessageBox, ElLoading } from 'element-plus';
+import * as Cesium from 'cesium';
+import { PublicCesium } from '@/utils/cesium/publicCesium'
+import OccupancyGrid from './GridSettings/OccupancyGrid'
+import PathPlanning from './GridSettings/PathPlanning'
+import newStartPoint from '@/assets/images/newStartPoint.png'
+import { cartesian3Convert,getLnglatAltitude } from '@/utils/cesium/mapUtil'
+import { ArrowLineMaterialProperty } from '@/utils/cesium/Material'
+import { getPolyLine } from '@/views/RoutePlan/PointAirLine/pointWayLineUtils'
+
+let arrowLineMaterialProperty = new ArrowLineMaterialProperty({
+	color: new Cesium.Color(128 / 255, 215 / 255, 255 / 255, 1),
+	directionColor: new Cesium.Color(1, 1, 1, 1),
+	outlineColor: new Cesium.Color(1, 1, 1, 1),
+	outlineWidth: 0,
+	speed: 5,
+})
+
+const total = ref(0)
+const params = ref({
+  current: 1,
+  size: 10,
+  gridName: '',
+});
+
+let titleTxt = ref('新增')
+let tableList = ref([])
+
+let isShowView = ref(false)
+
+let rowView = ref({})
+
+const showContextMenu = ref(false)
+const contextMenuStyle = ref({
+	left: '0px',
+	top: '0px',
+})
+
+let isShowEditView = ref(false)
+
+const ruleFormRef = ref()
+let editParams = ref({
+  id: '',
+  grid_name: '',
+  start_point: '',
+  end_point: '',
+})
+const rules = reactive({
+  grid_name: [
+    {
+      required: true,
+      message: '请输入网格名称',
+      trigger: 'blur',
+    },
+  ],
+})
+
+function cancelSearch() {
+  params.value = {
+    id: '',
+    gridName: '',
+  }
+  params.value.current = 1
+  getList()
+}
+
+function getList() {
+  airGridPage(params.value).then(res => {
+    tableList.value = res.data.data.records || []
+    total.value = res.data.data.total || 0
+  })
+}
+
+function handleDelete (row) {
+  ElMessageBox.confirm('确定删除吗?', '提示', {
+    confirmButtonText: '确定',
+    cancelButtonText: '取消',
+    type: 'warning',
+  })
+    .then(() => {
+      airGridDelete(row.id).then(res => {
+        ElMessage.success('删除成功')
+        getList()
+      }).catch(error => {
+        ElMessage.error('删除失败');
+      });
+    })
+    .catch(() => {
+      ElMessage({
+        type: 'info',
+        message: '已取消删除',
+      })
+    });
+}
+async function handleAdd() {
+  titleTxt.value = '新增'
+  editParams.value.grid_name = ''
+  isShowEditView.value = true
+  await nextTick()
+	initMap()
+}
+
+async function handleEdit(row) {
+  titleTxt.value = '编辑'
+  isShowEditView.value = true
+  editParams.value = { ...row }
+  const startPoint = row.start_point.split(',')
+  const endPoint = row.end_point.split(',')
+  const height = row.grid_height.split(',')
+  pointList.value.push({
+    longitude: Number(startPoint[0]),
+    latitude: Number(startPoint[1]),
+    height: Number(height[0]),
+  })
+  pointList.value.push({
+    longitude: Number(endPoint[0]),
+    latitude: Number(endPoint[1]),
+    height: Number(height[0]),
+  })
+  await nextTick()
+	initMap()
+}
+
+function handleSizeChange(val) {
+  params.value.size = val
+  getList()
+}
+
+function handleCurrentChange(val) {
+  params.value.current = val
+  getList()
+}
+
+async function submit(formValidate) {
+  if (!formValidate) return
+  await formValidate.validate((valid, fields) => {
+    if (valid) {
+      if (pointList.value.length === 0) {
+        ElMessage.warning('请先添加起点和终点')
+        return
+      }
+      const params = {
+        id: editParams.value.id,
+        grid_name: editParams.value.grid_name,
+        start_point: `${pointList.value[0].longitude},${pointList.value[0].latitude}`,
+        end_point: `${pointList.value[1].longitude},${pointList.value[1].latitude}`,
+        grid_height: `${pointList.value[0].height},${pointList.value[1].height}`,
+      }
+      if (titleTxt.value === '新增') {
+        airGridAdd(params).then(res => {
+          isShowEditView.value = false
+          ElMessage.success('新增成功')
+          getList()
+        })
+      } else {
+        airGridUpdate(params).then(res => {
+          isShowEditView.value = false
+          ElMessage.success('操作成功')
+          getList()
+        })
+      }
+      
+    } 
+  })
+}
+
+let publicCesiumInstance = null
+let viewer = null
+const viewInstance = shallowRef(null);
+let handler = null
+let occupancyGrid = null
+// 地图
+const initMap = async () => {
+	if (!document.getElementById('GridManagementMap')) {
+		return
+	}
+	publicCesiumInstance = new PublicCesium({
+		dom: 'GridManagementMap',
+    flyToContour: false,
+		flatMode: false,
+		terrain: true,
+		layerMode: 4,
+		contour: true,
+	})
+	viewer = publicCesiumInstance.getViewer()
+  viewInstance.value = publicCesiumInstance;
+  viewer.scene.globe.depthTestAgainstTerrain = true;
+
+  // viewer.flyTo({latitude: 28.624613214568868,longitude:115.85669891599704}, 4, 65)
+  viewer?.camera.flyTo({
+    destination: Cesium.Cartesian3.fromDegrees(115.85669891599704, 28.624613214568868, 1000),
+    duration: 1,
+    orientation: {
+      heading: Cesium.Math.toRadians(0.0),
+      pitch: Cesium.Math.toRadians(-90.0),
+      roll: 0.0,
+    },
+  });
+  addCustomLayers(tilesTreeData.value.title, tilesTreeData.value)
+  occupancyGrid = new OccupancyGrid(viewer, gridConfig, gridParams)
+  
+  // 添加事件
+  handler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas)
+	handler.setInputAction(singleClickEvent, Cesium.ScreenSpaceEventType.LEFT_CLICK)
+  handler.setInputAction(click => {
+		// 获取鼠标在页面上的坐标
+		const mousePosition = {
+			x: event.clientX,
+			y: event.clientY,
+		}
+
+		showContextMenu.value = true
+		contextMenuStyle.value = {
+			left: mousePosition.x + 'px',
+			top: mousePosition.y + 'px',
+			position: 'fixed', // 确保使用固定定位
+			zIndex: 9999, // 确保菜单显示在最上层
+		}
+	}, Cesium.ScreenSpaceEventType.RIGHT_CLICK)
+  cesiumContextMenu(false)
+  if (titleTxt.value === '编辑') {
+    ShowTwoPoints()
+    // meshAnalysis()
+  }
+}
+
+// 倾斜摄影
+const tilesTreeData = ref(
+	{
+		id: '1',
+		label: '空间大厦',
+		type: 'layer-map',
+		title: 'kjds_3Dtile',
+		mapType: 'Cesium3DTile',
+		src: '/3Dtile/kjds/tileset.json',
+	},
+)
+
+const gridParams = reactive({
+	hasGrid: false, //生成了网格
+	hasRoute: false, //生成了航线
+	showIdle: true, //显示占用网格
+	showOccupancy: true, //显示空闲网格
+})
+
+// 初始化占用网格 - 使用自定义配置
+const gridConfig = {
+	// 网格尺寸配置
+	gridSize: 6,
+
+	gridWidth: 12,
+	gridHeight: 12,
+	gridDepth: 12,
+
+	// 区域扩展配置(确保4层网格生成)
+	heightExtension: 72, // 向上向下各扩展120米,确保4层网格(总高度240米,4×50=200米,留有余量)
+	widthExtension: 12, // 水平方向扩展100米
+
+	// 颜色配置
+	occupiedColor: Cesium.Color.RED.withAlpha(0.05),
+	freeColor: Cesium.Color.GREEN.withAlpha(0.05),
+	occupiedOutlineColor: Cesium.Color.DARKRED,
+	freeOutlineColor: Cesium.Color.DARKGREEN,
+	outlineWidth: 1,
+
+	// 性能配置100000
+	maxGridCount: 500000,
+	enableBatching: true,
+
+	// 显示配置
+	showOccupiedOnly: false,
+	showFreeOnly: false,
+	enableLogging: true,
+}
+
+const addCustomLayers = async (layerName, options) => {
+	if (options.mapType === 'arcgis') {
+		let imageryProvider = new Cesium.WebMapTileServiceImageryProvider({
+			url: options.src,
+			layer: options.title,
+			style: 'default',
+			format: 'image/png',
+			tileMatrixSetID: 'default',
+			tilingScheme: new Cesium.GeographicTilingScheme(),
+			tileMatrixLabels: [
+				'0',
+				'1',
+				'2',
+				'3',
+				'4',
+				'5',
+				'6',
+				'7',
+				'8',
+				'9',
+				'10',
+				'11',
+				'12',
+				'13',
+				'14',
+				'15',
+				'16',
+				'17',
+				'18',
+				'19',
+			],
+		})
+
+		 viewer?.imageryLayers.addImageryProvider(imageryProvider)
+	}
+
+	if (options.mapType === 'Cesium3DTile') {
+		const tileset = await Cesium.Cesium3DTileset.fromUrl(options.src)
+
+		 viewer?.scene.primitives.add(tileset)
+	}
+}
+let pointList = ref([])
+async function singleClickEvent(movement) {
+  cesiumContextMenu(false)
+  if (pointList.value.length === 2) {
+    ElMessage.warning('最多只能添加两个点,可以先清空')
+    return
+  }
+  // 先清除point-
+  viewer.entities.removeAll()
+  const { longitude, latitude } = cartesian3Convert(viewer.scene.pickPosition(movement.position), viewer)
+  let result = await getLnglatAltitude(longitude, latitude, viewer)
+  let height = result.height + 60
+  const point = { longitude, latitude, height }
+  pointList.value.push(point)
+  ShowTwoPoints()
+}
+
+// 生成两个点
+function ShowTwoPoints() {
+  pointList.value.map((item, index) => {
+    const position = Cesium.Cartesian3.fromDegrees(
+      Number(item.longitude),
+      Number(item.latitude),
+      Number(item.height)
+    )
+    viewer.entities.add({
+      id: `point-${index}`,
+      position: position,
+      billboard: {
+        image: new Cesium.ConstantProperty(newStartPoint),
+        width: 40,
+				height: 40,
+      },
+    })
+    viewer?.entities.add({
+				id: 'placement-' + index,
+				position: position,
+				polyline: getPolyLine(viewer, { value: pointList.value }, index),
+			})
+  })
+  const position1 = Cesium.Cartesian3.fromDegrees(
+      Number(pointList.value[0].longitude),
+      Number(pointList.value[0].latitude),
+      Number(pointList.value[0].height)
+    )
+    const position2= Cesium.Cartesian3.fromDegrees(
+      Number(pointList.value[1].longitude),
+      Number(pointList.value[1].latitude),
+      Number(pointList.value[1].height)
+    )
+    // 获取两点在屏幕上的位置
+    // const screenPos1 = Cesium.SceneTransforms?.wgs84ToWindowCoordinates?.(viewer.scene, position1) 
+    // || viewer.scene.cartesianToCanvasCoordinates(position1);
+    // const screenPos2 = Cesium.SceneTransforms?.wgs84ToWindowCoordinates?.(viewer.scene, position2) 
+    // || viewer.scene.cartesianToCanvasCoordinates(position2);
+
+    // // // 生成屏幕矩形
+    // const boundingRect = new Cesium.BoundingRectangle(
+    //   Math.min(screenPos1.x, screenPos2.x),
+    //   Math.min(screenPos1.y, screenPos2.y),
+    //   Math.abs(screenPos1.x - screenPos2.x),
+    //   Math.abs(screenPos1.y - screenPos2.y)
+    // );
+    // const center = Cesium.Cartesian3.midpoint(screenPos1, screenPos2, new Cesium.Cartesian3());
+    // const angle = Cesium.Math.PI_OVER_FOUR; // 45度
+
+    // viewer.entities.add({
+    //   position: center,
+    //   rectangle: {
+    //     coordinates: boundingRect,
+    //     material: Cesium.Color.BLUE.withAlpha(0.5),
+    //     rotation: angle // 弧度制旋转
+    //   }
+    // });
+  viewer.entities.add({
+    id: `line`,
+    polyline: {
+      width: 2,
+      eyeOffset: new Cesium.Cartesian3(0, 0, -6),
+      material: arrowLineMaterialProperty,
+      clampToGround: false,
+      positions: [position1, position2],
+    },
+  })
+}
+
+// 禁用浏览器默认行为处理
+const preventDefault = event => {
+	event.preventDefault()
+	return
+}
+
+const cesiumContextMenu = (isAdd = true) => {
+	let cesium = document.getElementById('GridManagementMap')
+	if (!cesium) return
+	if (isAdd) {
+		cesium.addEventListener('contextmenu', preventDefault)
+	} else {
+		cesium.removeEventListener('contextmenu', preventDefault)
+	}
+}
+
+// 生成网格
+function meshAnalysis() {
+  if (pointList.value.length !== 2) {
+    ElMessage.warning('请先添加起点和终点')
+    return
+  }
+	const pointList1 = pointList.value.map(i => {
+		const cartographic = Cesium.Cartographic.fromDegrees(i.longitude, i.latitude, i.height)
+		const { x, y, z } = Cesium.Cartesian3.fromRadians(
+			cartographic.longitude,
+			cartographic.latitude,
+			cartographic.height
+		)
+		return { ...i, position: { x, y, z } }
+	})
+	window.uavApp = {
+		waypoints: pointList1,
+	}
+	occupancyGrid.generateOccupancyGridWithTiles(pointList1)
+}
+// 清除网格
+function clearGrid() {
+	occupancyGrid.clearGrid()
+	gridParams.hasGrid = false
+}
+
+const handleClose = () => {
+  // 清除editParams
+  editParams.value = {
+    id: '',
+    grid_name: '',
+    grid_height: '',
+    start_point: '',
+    end_point: '',
+  }
+  pointList.value = []
+	publicCesiumInstance?.viewerDestroy()
+	publicCesiumInstance = null
+	viewer = null
+  isShowEditView.value = false
+  viewer?.scene.primitives.remove(tilesTreeData.value.title)
+  cesiumContextMenu(false)
+}
+
+function clearAllPoints() {
+  showContextMenu.value = false
+  pointList.value = []
+  viewer?.entities.removeAll()
+  clearGrid()
+}
+
+onMounted(() => {
+  getList()
+})
+</script>
+
+<style lang="scss" scoped>
+  .gridManagement {
+    height: 0;
+    flex: 1;
+    padding: 20px;
+    margin: 0 10px 10px 10px;
+    background-color: #ffffff;
+    // padding: 10px 20px;
+    border-radius: 5px;
+    display: flex;
+    flex-direction: column;
+    .search-box {
+      margin-top: 20px;
+      height: 80px;
+    }
+
+    :deep(.el-input) {
+      .el-input__wrapper {
+        width: 200px;
+      }
+    }
+
+    // 表格
+    .mange-table {
+      height: 0;
+      flex: 1;
+      margin-top: 18px;
+      overflow: auto;
+    }
+    :deep(.el-pagination) {
+      display: flex;
+      justify-content: right;
+    }
+
+    :deep(.el-pagination button) {
+      background: center center no-repeat none !important;
+      color: #8eb8ea !important;
+    }
+  }
+.content-edit {
+  height: 550px;
+  .map-container {
+		height: 440px;
+
+		#GridManagementMap {
+			width: 100%;
+			height: 100%;
+		}
+	}
+  .btns {
+    margin-top: 16px;
+    display: flex;
+    justify-content: center;
+  }
+  .context-menu {
+			position: fixed;
+			background: #0f1929;
+			border: 1px solid #51a8ff;
+			border-radius: 4px;
+			padding: 4px 0;
+			z-index: 9999;
+			min-width: 100px; // 设置最小宽度
+			box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.3);
+
+			.menu-item {
+				padding: 8px 16px;
+				color: #d3e9ff;
+				cursor: pointer;
+
+				&:hover {
+					background: rgba(81, 168, 255, 0.1);
+				}
+			}
+		}
+}
+</style>
\ No newline at end of file
diff --git a/vite.config.mjs b/vite.config.mjs
index 7c1f6b1..9a62dc8 100644
--- a/vite.config.mjs
+++ b/vite.config.mjs
@@ -5,7 +5,7 @@
 // https://vitejs.dev/config/
 export default ({ mode, command }) => {
   const env = loadEnv(mode, process.cwd())
-  const { VITE_APP_ENV, VITE_APP_BASE, VITE_APP_URL } = env
+  const { VITE_APP_ENV, VITE_APP_BASE, VITE_APP_URL, VITE_APP_MAP_TILE_URL } = env
   // 判断是打生产环境包
   const isProd = VITE_APP_ENV === 'production'
 
@@ -43,7 +43,13 @@
           target: VITE_APP_URL,
           changeOrigin: true,
           rewrite: path => path.replace(/^\/api/, ''),
-        }
+        },
+
+        '/3Dtile': {
+          target: VITE_APP_MAP_TILE_URL,
+          changeOrigin: true,
+          rewrite: path => path.replace(/^\/3Dtile/, ''),
+        },
       },
     },
     assetsInclude: ['**/*.gltf'],

--
Gitblit v1.9.3