573 lines
19 KiB
JavaScript
573 lines
19 KiB
JavaScript
|
|
import { ref } from 'vue'
|
|||
|
|
import * as Cesium from 'cesium'
|
|||
|
|
import { useMapStore } from '@/map'
|
|||
|
|
import {
|
|||
|
|
BEFORE_IMAGERY_CONFIG,
|
|||
|
|
AFTER_IMAGERY_CONFIG,
|
|||
|
|
SPLIT_CONFIG,
|
|||
|
|
getModelCompareConfig
|
|||
|
|
} from '../config/modelCompare.config'
|
|||
|
|
import { use3DTiles } from './use3DTiles'
|
|||
|
|
import { useMapMarkers } from './useMapMarkers'
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 调试模式开关
|
|||
|
|
* 生产环境自动关闭详细日志
|
|||
|
|
*/
|
|||
|
|
const DEBUG = import.meta.env.DEV
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 图层标识常量
|
|||
|
|
* @constant {string} BEFORE_LAYER_ID - 灾前现场实景图层 ID
|
|||
|
|
* @constant {string} AFTER_LAYER_ID - 灾后现场实景图层 ID
|
|||
|
|
*/
|
|||
|
|
const BEFORE_LAYER_ID = BEFORE_IMAGERY_CONFIG.id
|
|||
|
|
const AFTER_LAYER_ID = AFTER_IMAGERY_CONFIG.id
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 模型对比(灾前/灾后影像对比)业务逻辑
|
|||
|
|
*
|
|||
|
|
* 技术方案:
|
|||
|
|
* - 使用单个 Cesium 实例,通过 imagery split(影像分屏)实现左右对比视图
|
|||
|
|
* - 左侧显示灾前现场实景,右侧显示灾后现场实景
|
|||
|
|
* - 默认只显示灾后影像,启用对比模式后同时显示两套影像
|
|||
|
|
*
|
|||
|
|
* 使用示例:
|
|||
|
|
* ```js
|
|||
|
|
* const { isModelCompareActive, initModelCompareLayers, toggleModelCompare } = useModelCompare()
|
|||
|
|
*
|
|||
|
|
* // 在地图就绪后初始化图层
|
|||
|
|
* mapStore.onReady(async () => {
|
|||
|
|
* await initModelCompareLayers()
|
|||
|
|
* })
|
|||
|
|
*
|
|||
|
|
* // 切换对比模式
|
|||
|
|
* await toggleModelCompare(true) // 启用
|
|||
|
|
* await toggleModelCompare(false) // 禁用
|
|||
|
|
* ```
|
|||
|
|
*
|
|||
|
|
* @returns {Object} 模型对比相关状态和方法
|
|||
|
|
* @returns {Ref<boolean>} isModelCompareActive - 模型对比模式是否激活
|
|||
|
|
* @returns {Function} initModelCompareLayers - 初始化灾前/灾后图层
|
|||
|
|
* @returns {Function} enableModelCompare - 启用模型对比模式
|
|||
|
|
* @returns {Function} disableModelCompare - 禁用模型对比模式
|
|||
|
|
* @returns {Function} toggleModelCompare - 切换模型对比模式
|
|||
|
|
*/
|
|||
|
|
export function useModelCompare() {
|
|||
|
|
const mapStore = useMapStore()
|
|||
|
|
|
|||
|
|
// 初始化 3D Tiles 管理
|
|||
|
|
const {
|
|||
|
|
load3DTileset,
|
|||
|
|
waitForTilesetReady,
|
|||
|
|
remove3DTileset
|
|||
|
|
} = use3DTiles()
|
|||
|
|
|
|||
|
|
/** 模型对比模式是否激活 */
|
|||
|
|
const isModelCompareActive = ref(false)
|
|||
|
|
|
|||
|
|
/** 图层是否已初始化 */
|
|||
|
|
const initialized = ref(false)
|
|||
|
|
|
|||
|
|
/** 是否正在执行切换操作(防止并发) */
|
|||
|
|
const isToggling = ref(false)
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 其他影像图层的原始可见性状态
|
|||
|
|
* 用于在禁用对比模式后恢复原始状态,而非强制全部打开
|
|||
|
|
* Map<layerId: string, visible: boolean>
|
|||
|
|
*/
|
|||
|
|
const originalLayerVisibility = new Map()
|
|||
|
|
|
|||
|
|
/** 灾前 Tileset 引用(用于在禁用时移除) */
|
|||
|
|
let beforeTilesetRef = null
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 从 viewer 中查找指定配置的 3D Tileset
|
|||
|
|
* @param {Cesium.Viewer} viewer
|
|||
|
|
* @param {string} configId - 配置ID,'before' 或 'after'
|
|||
|
|
* @returns {Cesium.Cesium3DTileset | null}
|
|||
|
|
*/
|
|||
|
|
const findTilesetByConfig = (viewer, configId) => {
|
|||
|
|
if (!viewer?.scene?.primitives) return null
|
|||
|
|
|
|||
|
|
const config = getModelCompareConfig()
|
|||
|
|
const targetUrl = configId === 'after' ? config.after3DTiles.url : config.before3DTiles.url
|
|||
|
|
|
|||
|
|
// 遍历所有 primitives 查找匹配的 tileset
|
|||
|
|
for (let i = 0; i < viewer.scene.primitives.length; i++) {
|
|||
|
|
const primitive = viewer.scene.primitives.get(i)
|
|||
|
|
if (primitive instanceof Cesium.Cesium3DTileset) {
|
|||
|
|
// 比较 URL(去除查询参数和尾部斜杠)
|
|||
|
|
const primitiveUrl = primitive.resource?.url || primitive._url || ''
|
|||
|
|
const normalizedPrimitiveUrl = primitiveUrl.split('?')[0].replace(/\/$/, '')
|
|||
|
|
const normalizedTargetUrl = targetUrl.split('?')[0].replace(/\/$/, '')
|
|||
|
|
|
|||
|
|
if (normalizedPrimitiveUrl === normalizedTargetUrl) {
|
|||
|
|
return primitive
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return null
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 设置所有 entities 的 splitDirection
|
|||
|
|
* @param {Cesium.Viewer} viewer
|
|||
|
|
* @param {Cesium.SplitDirection} splitDirection
|
|||
|
|
*/
|
|||
|
|
const setEntitiesSplitDirection = (viewer, splitDirection) => {
|
|||
|
|
if (!viewer?.entities) return
|
|||
|
|
|
|||
|
|
console.log(`[useModelCompare] 设置所有 entities 的 splitDirection 为: ${splitDirection}`)
|
|||
|
|
let updatedCount = 0
|
|||
|
|
|
|||
|
|
const entities = viewer.entities.values
|
|||
|
|
for (let i = 0; i < entities.length; i++) {
|
|||
|
|
const entity = entities[i]
|
|||
|
|
|
|||
|
|
// 设置 entity 级别的 splitDirection
|
|||
|
|
entity.splitDirection = splitDirection
|
|||
|
|
|
|||
|
|
// 设置图形属性的 splitDirection
|
|||
|
|
if (entity.billboard) {
|
|||
|
|
if (typeof entity.billboard.splitDirection === 'object' && entity.billboard.splitDirection.setValue) {
|
|||
|
|
entity.billboard.splitDirection.setValue(splitDirection)
|
|||
|
|
} else {
|
|||
|
|
entity.billboard.splitDirection = new Cesium.ConstantProperty(splitDirection)
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (entity.polygon) {
|
|||
|
|
if (typeof entity.polygon.splitDirection === 'object' && entity.polygon.splitDirection.setValue) {
|
|||
|
|
entity.polygon.splitDirection.setValue(splitDirection)
|
|||
|
|
} else {
|
|||
|
|
entity.polygon.splitDirection = new Cesium.ConstantProperty(splitDirection)
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
updatedCount++
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
console.log(`[useModelCompare] 已更新 ${updatedCount} 个 entities 的 splitDirection`)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 初始化灾前/灾后影像图层
|
|||
|
|
*
|
|||
|
|
* - 仅在首次调用时创建图层
|
|||
|
|
* - 如果地图未就绪,会自动等待地图就绪后再执行
|
|||
|
|
* - 使用占位符 URL,需在接入真实数据时替换为实际影像服务地址
|
|||
|
|
*
|
|||
|
|
* @async
|
|||
|
|
* @throws {Error} 当图层创建失败时抛出错误
|
|||
|
|
*/
|
|||
|
|
const initModelCompareLayers = async () => {
|
|||
|
|
// 防止重复初始化
|
|||
|
|
if (initialized.value) {
|
|||
|
|
console.log('[useModelCompare] 图层已初始化,跳过重复初始化')
|
|||
|
|
return
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 实际的图层初始化逻辑
|
|||
|
|
* @async
|
|||
|
|
* @private
|
|||
|
|
*/
|
|||
|
|
const doInit = async () => {
|
|||
|
|
try {
|
|||
|
|
const { layer } = mapStore.services()
|
|||
|
|
|
|||
|
|
// 获取当前环境的配置
|
|||
|
|
const config = getModelCompareConfig()
|
|||
|
|
|
|||
|
|
// 检查图层是否已存在(可能被其他模块创建)
|
|||
|
|
const beforeExists = layer.getLayer(BEFORE_LAYER_ID)
|
|||
|
|
const afterExists = layer.getLayer(AFTER_LAYER_ID)
|
|||
|
|
|
|||
|
|
// 创建灾前影像图层
|
|||
|
|
if (!beforeExists) {
|
|||
|
|
if (DEBUG) console.log('[useModelCompare] 创建灾前影像图层...')
|
|||
|
|
await layer.addLayer({
|
|||
|
|
id: config.before.id,
|
|||
|
|
type: 'WebTileLayer',
|
|||
|
|
url: config.before.url,
|
|||
|
|
options: {
|
|||
|
|
visible: config.before.visible,
|
|||
|
|
},
|
|||
|
|
meta: {
|
|||
|
|
title: config.before.name,
|
|||
|
|
sceneType: 'before',
|
|||
|
|
description: config.before.description
|
|||
|
|
}
|
|||
|
|
})
|
|||
|
|
if (DEBUG) console.log('[useModelCompare] 灾前影像图层创建成功')
|
|||
|
|
} else {
|
|||
|
|
if (DEBUG) console.log('[useModelCompare] 灾前影像图层已存在')
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 创建灾后影像图层
|
|||
|
|
if (!afterExists) {
|
|||
|
|
if (DEBUG) console.log('[useModelCompare] 创建灾后影像图层...')
|
|||
|
|
await layer.addLayer({
|
|||
|
|
id: config.after.id,
|
|||
|
|
type: 'WebTileLayer',
|
|||
|
|
url: config.after.url,
|
|||
|
|
options: {
|
|||
|
|
visible: config.after.visible,
|
|||
|
|
},
|
|||
|
|
meta: {
|
|||
|
|
title: config.after.name,
|
|||
|
|
sceneType: 'after',
|
|||
|
|
description: config.after.description
|
|||
|
|
}
|
|||
|
|
})
|
|||
|
|
if (DEBUG) console.log('[useModelCompare] 灾后影像图层创建成功')
|
|||
|
|
} else {
|
|||
|
|
if (DEBUG) console.log('[useModelCompare] 灾后影像图层已存在')
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
initialized.value = true
|
|||
|
|
if (DEBUG) console.log('[useModelCompare] 图层初始化完成')
|
|||
|
|
} catch (error) {
|
|||
|
|
console.error('[useModelCompare] 图层初始化失败:', error)
|
|||
|
|
throw new Error(`模型对比图层初始化失败: ${error.message}`)
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 如果地图已就绪,直接执行初始化
|
|||
|
|
if (mapStore.isReady()) {
|
|||
|
|
await doInit()
|
|||
|
|
return
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 否则等待地图就绪后再执行
|
|||
|
|
console.log('[useModelCompare] 等待地图就绪...')
|
|||
|
|
await new Promise((resolve, reject) => {
|
|||
|
|
mapStore.onReady(async () => {
|
|||
|
|
try {
|
|||
|
|
await doInit()
|
|||
|
|
resolve()
|
|||
|
|
} catch (error) {
|
|||
|
|
reject(error)
|
|||
|
|
}
|
|||
|
|
})
|
|||
|
|
})
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 启用模型对比模式
|
|||
|
|
*
|
|||
|
|
* 启用后:
|
|||
|
|
* - 左半屏显示灾前影像
|
|||
|
|
* - 右半屏显示灾后影像
|
|||
|
|
* - 分割线位置默认为中心(0.5)
|
|||
|
|
*
|
|||
|
|
* @async
|
|||
|
|
*/
|
|||
|
|
const enableModelCompare = async () => {
|
|||
|
|
if (DEBUG) console.log('[useModelCompare] 启用模型对比模式...')
|
|||
|
|
|
|||
|
|
// 确保图层已初始化
|
|||
|
|
await initModelCompareLayers()
|
|||
|
|
|
|||
|
|
// 如果地图未就绪,无法操作
|
|||
|
|
if (!mapStore.isReady()) {
|
|||
|
|
console.warn('[useModelCompare] 地图未就绪,无法启用对比模式')
|
|||
|
|
return
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
try {
|
|||
|
|
const { layer } = mapStore.services()
|
|||
|
|
|
|||
|
|
// 检查图层是否存在
|
|||
|
|
const beforeLayer = layer.getLayer(BEFORE_LAYER_ID)
|
|||
|
|
const afterLayer = layer.getLayer(AFTER_LAYER_ID)
|
|||
|
|
|
|||
|
|
if (!beforeLayer || !afterLayer) {
|
|||
|
|
console.error('[useModelCompare] 图层不存在,无法启用对比模式')
|
|||
|
|
throw new Error('模型对比图层不存在')
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 🔧 修复:保存其他影像图层的原始可见性状态
|
|||
|
|
// 在隐藏图层前先记录它们的状态,以便后续恢复
|
|||
|
|
originalLayerVisibility.clear() // 清空旧状态
|
|||
|
|
const allLayers = layer.listLayers()
|
|||
|
|
|
|||
|
|
allLayers.forEach(layerRecord => {
|
|||
|
|
if (layerRecord.type === 'imagery' &&
|
|||
|
|
layerRecord.id !== BEFORE_LAYER_ID &&
|
|||
|
|
layerRecord.id !== AFTER_LAYER_ID) {
|
|||
|
|
// 保存原始可见性状态
|
|||
|
|
originalLayerVisibility.set(layerRecord.id, layerRecord.show)
|
|||
|
|
// 隐藏图层,避免遮挡分屏效果
|
|||
|
|
layer.showLayer(layerRecord.id, false)
|
|||
|
|
}
|
|||
|
|
})
|
|||
|
|
|
|||
|
|
if (DEBUG) {
|
|||
|
|
console.log('[useModelCompare] 已保存图层状态:',
|
|||
|
|
Array.from(originalLayerVisibility.entries()))
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 左侧:灾前影像;右侧:灾后影<E5908E><E5BDB1><EFBFBD>
|
|||
|
|
console.log('[useModelCompare] 设置灾前图层为左侧...')
|
|||
|
|
layer.setSplit(BEFORE_LAYER_ID, 'left')
|
|||
|
|
|
|||
|
|
console.log('[useModelCompare] 设置灾后图层为右侧...')
|
|||
|
|
layer.setSplit(AFTER_LAYER_ID, 'right')
|
|||
|
|
|
|||
|
|
// 设置分割位置为中心(可以后续扩展为可拖动调整)
|
|||
|
|
console.log('[useModelCompare] 设置分割位置为 0.5...')
|
|||
|
|
layer.setSplitPosition(0.5)
|
|||
|
|
|
|||
|
|
// 直接使用新 API 设置分割位置(绕过可能的旧 API 问题)
|
|||
|
|
const viewer = mapStore.viewer
|
|||
|
|
if (viewer) {
|
|||
|
|
// 尝试新 API
|
|||
|
|
if ('splitPosition' in viewer.scene) {
|
|||
|
|
viewer.scene.splitPosition = 0.5
|
|||
|
|
console.log('[useModelCompare] 使用新 API: scene.splitPosition = 0.5')
|
|||
|
|
}
|
|||
|
|
// 兼容旧 API
|
|||
|
|
if ('imagerySplitPosition' in viewer.scene) {
|
|||
|
|
viewer.scene.imagerySplitPosition = 0.5
|
|||
|
|
console.log('[useModelCompare] 使用旧 API: scene.imagerySplitPosition = 0.5')
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
console.log('[useModelCompare] viewer.scene.splitPosition:', viewer.scene.splitPosition)
|
|||
|
|
console.log('[useModelCompare] viewer.scene.imagerySplitPosition:', viewer.scene.imagerySplitPosition)
|
|||
|
|
|
|||
|
|
// 检查所有影像图层
|
|||
|
|
const imageryLayers = viewer.imageryLayers
|
|||
|
|
console.log('[useModelCompare] 影像图层总数:', imageryLayers.length)
|
|||
|
|
|
|||
|
|
for (let i = 0; i < imageryLayers.length; i++) {
|
|||
|
|
const imgLayer = imageryLayers.get(i)
|
|||
|
|
console.log(`[useModelCompare] 图层 ${i}:`, {
|
|||
|
|
show: imgLayer.show,
|
|||
|
|
alpha: imgLayer.alpha,
|
|||
|
|
splitDirection: imgLayer.splitDirection
|
|||
|
|
})
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 确保两个图层都可见
|
|||
|
|
console.log('[useModelCompare] 显示灾前图层...')
|
|||
|
|
layer.showLayer(BEFORE_LAYER_ID, true)
|
|||
|
|
|
|||
|
|
console.log('[useModelCompare] 显示灾后图层...')
|
|||
|
|
layer.showLayer(AFTER_LAYER_ID, true)
|
|||
|
|
|
|||
|
|
// 调试:检查设置后的状态
|
|||
|
|
const beforeLayerAfter = layer.getLayer(BEFORE_LAYER_ID)
|
|||
|
|
const afterLayerAfter = layer.getLayer(AFTER_LAYER_ID)
|
|||
|
|
|
|||
|
|
console.log('[useModelCompare] 设置后的灾前图层:', beforeLayerAfter)
|
|||
|
|
console.log('[useModelCompare] 灾前图层 splitDirection (设置后):', beforeLayerAfter?.obj?.splitDirection)
|
|||
|
|
console.log('[useModelCompare] 灾前图层 show:', beforeLayerAfter?.obj?.show)
|
|||
|
|
|
|||
|
|
console.log('[useModelCompare] 设置后的灾后图层:', afterLayerAfter)
|
|||
|
|
console.log('[useModelCompare] 灾后图层 splitDirection (设置后):', afterLayerAfter?.obj?.splitDirection)
|
|||
|
|
console.log('[useModelCompare] 灾后图层 show:', afterLayerAfter?.obj?.show)
|
|||
|
|
|
|||
|
|
// 再次检查所有图层的最终状态
|
|||
|
|
if (viewer) {
|
|||
|
|
console.log('[useModelCompare] === 最终影像图层状态 ===')
|
|||
|
|
const imageryLayers = viewer.imageryLayers
|
|||
|
|
for (let i = 0; i < imageryLayers.length; i++) {
|
|||
|
|
const imgLayer = imageryLayers.get(i)
|
|||
|
|
console.log(`[useModelCompare] 最终图层 ${i}:`, {
|
|||
|
|
show: imgLayer.show,
|
|||
|
|
alpha: imgLayer.alpha,
|
|||
|
|
splitDirection: imgLayer.splitDirection
|
|||
|
|
})
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// ============ 处理 3D Tiles 模型 ============
|
|||
|
|
console.log('[useModelCompare] 开始处理 3D Tiles 模型分割...')
|
|||
|
|
|
|||
|
|
// 查找灾后模型
|
|||
|
|
const afterTileset = findTilesetByConfig(viewer, 'after')
|
|||
|
|
if (afterTileset) {
|
|||
|
|
console.log('[useModelCompare] 找到灾后3D模型,设置为右侧显示')
|
|||
|
|
afterTileset.splitDirection = Cesium.SplitDirection.RIGHT
|
|||
|
|
} else {
|
|||
|
|
console.warn('[useModelCompare] 未找到灾后3D模型')
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 查找或加载灾前3D模型
|
|||
|
|
let beforeTileset = findTilesetByConfig(viewer, 'before')
|
|||
|
|
if (!beforeTileset) {
|
|||
|
|
console.log('[useModelCompare] 加载灾前3D模型...')
|
|||
|
|
beforeTileset = await load3DTileset(
|
|||
|
|
viewer,
|
|||
|
|
'before',
|
|||
|
|
false, // 不自动缩放
|
|||
|
|
Cesium.SplitDirection.LEFT // 左侧显示
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
if (beforeTileset) {
|
|||
|
|
// 保存引用,用于禁用时移除
|
|||
|
|
beforeTilesetRef = beforeTileset
|
|||
|
|
console.log('[useModelCompare] 灾前3D模型加载成功,等待就绪...')
|
|||
|
|
await waitForTilesetReady(beforeTileset)
|
|||
|
|
console.log('[useModelCompare] 灾前3D模型已就绪')
|
|||
|
|
} else {
|
|||
|
|
console.warn('[useModelCompare] 灾前3D模型加载失败')
|
|||
|
|
}
|
|||
|
|
} else {
|
|||
|
|
console.log('[useModelCompare] 找到已存在的灾前3D模型,设置为左侧显示')
|
|||
|
|
beforeTileset.splitDirection = Cesium.SplitDirection.LEFT
|
|||
|
|
beforeTilesetRef = beforeTileset
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// ============ 处理标记点和实体 ============
|
|||
|
|
console.log('[useModelCompare] 设置所有实体为右侧显示(灾后场景)...')
|
|||
|
|
setEntitiesSplitDirection(viewer, Cesium.SplitDirection.RIGHT)
|
|||
|
|
|
|||
|
|
isModelCompareActive.value = true
|
|||
|
|
console.log('[useModelCompare] 模型对比模式已启用(包含3D模型分割和标记点)')
|
|||
|
|
} catch (error) {
|
|||
|
|
console.error('[useModelCompare] 启用模型对比模式失败:', error)
|
|||
|
|
throw new Error(`启用模型对比模式失败: ${error.message}`)
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 禁用模型对比模式
|
|||
|
|
*
|
|||
|
|
* 禁用后:
|
|||
|
|
* - 取消影像分屏
|
|||
|
|
* - 隐藏灾前影像
|
|||
|
|
* - 保留灾后影像作为默认视图
|
|||
|
|
* - 恢复其他图层的原始可见性状态
|
|||
|
|
*
|
|||
|
|
* @async
|
|||
|
|
*/
|
|||
|
|
const disableModelCompare = async () => {
|
|||
|
|
if (DEBUG) console.log('[useModelCompare] 禁用模型对比模式...')
|
|||
|
|
|
|||
|
|
// 如果地图未就绪,仅更新状态即可
|
|||
|
|
if (!mapStore.isReady()) {
|
|||
|
|
isModelCompareActive.value = false
|
|||
|
|
console.warn('[useModelCompare] 地图未就绪,仅更新状态')
|
|||
|
|
return
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
try {
|
|||
|
|
const { layer } = mapStore.services()
|
|||
|
|
const viewer = mapStore.viewer
|
|||
|
|
|
|||
|
|
// ============ 处理影像图层 ============
|
|||
|
|
// 取消影像分屏
|
|||
|
|
layer.setSplit(BEFORE_LAYER_ID, 'none')
|
|||
|
|
layer.setSplit(AFTER_LAYER_ID, 'none')
|
|||
|
|
|
|||
|
|
// 隐藏灾前图层,保留灾后图层
|
|||
|
|
layer.showLayer(BEFORE_LAYER_ID, false)
|
|||
|
|
layer.showLayer(AFTER_LAYER_ID, true)
|
|||
|
|
|
|||
|
|
// 🔧 修复:恢复其他影像图层的原始可见性状态
|
|||
|
|
// 而非强制全部打开
|
|||
|
|
if (originalLayerVisibility.size > 0) {
|
|||
|
|
originalLayerVisibility.forEach((visible, layerId) => {
|
|||
|
|
layer.showLayer(layerId, visible)
|
|||
|
|
})
|
|||
|
|
if (DEBUG) {
|
|||
|
|
console.log('[useModelCompare] 已恢复影像图层状态:',
|
|||
|
|
Array.from(originalLayerVisibility.entries()))
|
|||
|
|
}
|
|||
|
|
// 清空已恢复的状态记录
|
|||
|
|
originalLayerVisibility.clear()
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// ============ 处理 3D Tiles 模型 ============
|
|||
|
|
console.log('[useModelCompare] 开始恢复 3D Tiles 模型状态...')
|
|||
|
|
|
|||
|
|
// 查找并恢复灾后模型为全屏显示
|
|||
|
|
const afterTileset = findTilesetByConfig(viewer, 'after')
|
|||
|
|
if (afterTileset) {
|
|||
|
|
console.log('[useModelCompare] 恢复灾后3D模型为全屏显示')
|
|||
|
|
afterTileset.splitDirection = Cesium.SplitDirection.NONE
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 移除灾前模型
|
|||
|
|
if (beforeTilesetRef) {
|
|||
|
|
console.log('[useModelCompare] 移除灾前3D模型')
|
|||
|
|
viewer.scene.primitives.remove(beforeTilesetRef)
|
|||
|
|
beforeTilesetRef = null
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// ============ 处理标记点和实体 ============
|
|||
|
|
console.log('[useModelCompare] 恢复所有实体为全屏显示...')
|
|||
|
|
setEntitiesSplitDirection(viewer, Cesium.SplitDirection.NONE)
|
|||
|
|
|
|||
|
|
isModelCompareActive.value = false
|
|||
|
|
if (DEBUG) console.log('[useModelCompare] 模型对比模式已禁用(包含3D模型和标记点恢复)')
|
|||
|
|
} catch (error) {
|
|||
|
|
console.error('[useModelCompare] 禁用模型对比模式失败:', error)
|
|||
|
|
throw new Error(`禁用模型对比模式失败: ${error.message}`)
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 切换模型对比模式
|
|||
|
|
*
|
|||
|
|
* @async
|
|||
|
|
* @param {boolean} active - true 启用,false 禁用
|
|||
|
|
*/
|
|||
|
|
const toggleModelCompare = async (active) => {
|
|||
|
|
if (DEBUG) console.log(`[useModelCompare] 切换模型对比模式: ${active ? '启用' : '禁用'}`)
|
|||
|
|
|
|||
|
|
// 防止并发切换
|
|||
|
|
if (isToggling.value) {
|
|||
|
|
console.warn('[useModelCompare] 正在执行切换操作,忽略本次请求')
|
|||
|
|
return
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 如果地图未就绪,延迟执行
|
|||
|
|
if (!mapStore.isReady()) {
|
|||
|
|
console.warn('[useModelCompare] 地图未就绪,将在地图就绪后执行切换')
|
|||
|
|
await new Promise((resolve) => {
|
|||
|
|
mapStore.onReady(() => resolve())
|
|||
|
|
})
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 保存之前的状态,用于错误回滚
|
|||
|
|
const previousState = isModelCompareActive.value
|
|||
|
|
|
|||
|
|
isToggling.value = true
|
|||
|
|
|
|||
|
|
try {
|
|||
|
|
if (active) {
|
|||
|
|
await enableModelCompare()
|
|||
|
|
} else {
|
|||
|
|
await disableModelCompare()
|
|||
|
|
}
|
|||
|
|
} catch (error) {
|
|||
|
|
console.error('[useModelCompare] 切换模型对比模式失败:', error)
|
|||
|
|
// 在发生错误时恢复到之前的状态
|
|||
|
|
isModelCompareActive.value = previousState
|
|||
|
|
throw error
|
|||
|
|
} finally {
|
|||
|
|
isToggling.value = false
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return {
|
|||
|
|
// 状态
|
|||
|
|
isModelCompareActive,
|
|||
|
|
|
|||
|
|
// 方法
|
|||
|
|
initModelCompareLayers,
|
|||
|
|
enableModelCompare,
|
|||
|
|
disableModelCompare,
|
|||
|
|
toggleModelCompare
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
export default useModelCompare
|