refactor(3d-situational-awareness): 增强双地图相机同步功能并加入防御性检查机制

*   引入视窗(viewer)存在性和销毁检查,以防止同步过程中发生错误。
*   引入原子停止标志(atomic stop flags)和移动结束(moveEnd)追踪,以优化控制流程。
*   提高位置变化检测的精度,并优化日志记录功能。
This commit is contained in:
Zzc 2025-11-27 18:04:58 +08:00
parent bb5bed014c
commit 49e963e196

View File

@ -102,10 +102,32 @@ export function useDualMapCompare() {
let isSyncing = false let isSyncing = false
const handleCameraSync = () => { const handleCameraSync = () => {
if (isSyncing) return if (isSyncing) return
// 防御检查1viewer 存在性检查
if (!rightViewerInstance || !leftViewerInstance) {
return
}
// 防御检查2viewer destroyed 状态检查
if (rightViewerInstance.isDestroyed?.() || leftViewerInstance.isDestroyed?.()) {
return
}
isSyncing = true isSyncing = true
requestAnimationFrame(() => { requestAnimationFrame(() => {
try { try {
// 再次检查requestAnimationFrame 可能延迟执行)
if (!rightViewerInstance || !leftViewerInstance) {
isSyncing = false
return
}
if (rightViewerInstance.isDestroyed?.() || leftViewerInstance.isDestroyed?.()) {
isSyncing = false
return
}
const rightCamera = rightViewerInstance.camera const rightCamera = rightViewerInstance.camera
leftViewerInstance.camera.setView({ leftViewerInstance.camera.setView({
destination: rightCamera.position.clone(), destination: rightCamera.position.clone(),
@ -129,8 +151,13 @@ export function useDualMapCompare() {
_moveEndHandler: null, _moveEndHandler: null,
_lastPosition: null, _lastPosition: null,
_interval: null, _interval: null,
_stopped: false, // 新增:原子性停止标志
_moveEndReceived: false, // 新增:标记 moveEnd 是否已触发
start: () => { start: () => {
// 重置停止标志
syncController._stopped = false
const controller = rightViewerInstance.scene.screenSpaceCameraController const controller = rightViewerInstance.scene.screenSpaceCameraController
if (!controller) { if (!controller) {
@ -142,13 +169,27 @@ export function useDualMapCompare() {
if (typeof rightViewerInstance.camera.moveStart?.addEventListener === 'function' && if (typeof rightViewerInstance.camera.moveStart?.addEventListener === 'function' &&
typeof rightViewerInstance.camera.moveEnd?.addEventListener === 'function') { typeof rightViewerInstance.camera.moveEnd?.addEventListener === 'function') {
// 监听相机移动开始(替代所有操作类型监听) // 监听相机移动开始
const moveStartHandler = rightViewerInstance.camera.moveStart.addEventListener(() => { const moveStartHandler = rightViewerInstance.camera.moveStart.addEventListener(() => {
if (syncController._stopped) return // 检查停止标志
syncController._isUserInteracting = true syncController._isUserInteracting = true
console.log('[useDualMapCompare] 捕获相机操作开始') console.log('[useDualMapCompare] 捕获相机操作开始')
// 新增拖动持续监听 // 改进:只在首次触发时启动递归
const onDragFrame = () => { const onDragFrame = () => {
// 停止检查
if (syncController._stopped) {
console.log('[useDualMapCompare] 停止标志已设置,退出递归')
return
}
// viewer 有效性检查
if (!rightViewerInstance || rightViewerInstance.isDestroyed?.()) {
console.log('[useDualMapCompare] Viewer已销毁退出递归')
return
}
if (syncController._isUserInteracting) { if (syncController._isUserInteracting) {
console.log('[useDualMapCompare] 主同步触发') console.log('[useDualMapCompare] 主同步触发')
handleCameraSync() handleCameraSync()
@ -158,12 +199,17 @@ export function useDualMapCompare() {
requestAnimationFrame(onDragFrame) requestAnimationFrame(onDragFrame)
}) })
// 2. 同步逻辑 syncController._interactionHandlers.push(moveStartHandler)
// 2. 监听相机移动结束
syncController._moveEndHandler = rightViewerInstance.camera.moveEnd.addEventListener(() => { syncController._moveEndHandler = rightViewerInstance.camera.moveEnd.addEventListener(() => {
if (syncController._stopped) return // 检查停止标志
if (syncController._isUserInteracting) { if (syncController._isUserInteracting) {
console.log('[useDualMapCompare] 主同步触发') console.log('[useDualMapCompare] moveEnd 事件触发,等待相机完全停止...')
handleCameraSync() // 不要立即重置 _isUserInteracting让 setInterval 继续检测
syncController._isUserInteracting = false // 标记为"移动已结束但可能还在惯性滑动"
syncController._moveEndReceived = true
} }
}) })
@ -172,62 +218,113 @@ export function useDualMapCompare() {
return return
} }
// 3. 保险同步逻辑 // 3. 保险同步逻辑setInterval
syncController._lastPosition = new Cesium.Cartesian3() syncController._lastPosition = new Cesium.Cartesian3()
syncController._moveEndReceived = false // 重置标志
syncController._interval = setInterval(() => { syncController._interval = setInterval(() => {
// 停止检查
if (syncController._stopped) return
// viewer 有效性检查
if (!rightViewerInstance || rightViewerInstance.isDestroyed?.()) {
console.log('[useDualMapCompare] Viewer已销毁停止定时同步')
if (syncController._interval) {
clearInterval(syncController._interval)
syncController._interval = null
}
return
}
const isMoving = controller.isMoving const isMoving = controller.isMoving
const currentPosition = rightViewerInstance.camera.position const currentPosition = rightViewerInstance.camera.position
if (syncController._isUserInteracting) { if (syncController._isUserInteracting) {
if (isMoving) { if (isMoving) {
// 相机正在移动,持续更新位置
Cesium.Cartesian3.clone(currentPosition, syncController._lastPosition)
syncController._moveEndReceived = false // 重置标志
} else {
// 相机已停止移动
if (syncController._moveEndReceived) {
// moveEnd 已触发且相机已停止,执行最终同步
const positionChanged = !Cesium.Cartesian3.equalsEpsilon(
currentPosition,
syncController._lastPosition,
0.001 // 更高精度
)
if (positionChanged) {
console.log('[useDualMapCompare] 相机完全停止,执行最终同步')
handleCameraSync()
Cesium.Cartesian3.clone(currentPosition, syncController._lastPosition) Cesium.Cartesian3.clone(currentPosition, syncController._lastPosition)
} else { } else {
console.log('[useDualMapCompare] 相机完全停止,位置无变化')
}
// 重置状态
syncController._isUserInteracting = false
syncController._moveEndReceived = false
} else {
// 相机停止但 moveEnd 未触发(可能是微小移动后停止)
const positionChanged = !Cesium.Cartesian3.equalsEpsilon( const positionChanged = !Cesium.Cartesian3.equalsEpsilon(
currentPosition, currentPosition,
syncController._lastPosition, syncController._lastPosition,
0.1 0.1
) )
if (positionChanged) { if (positionChanged) {
console.log('[useDualMapCompare] 保险同步触发') console.log('[useDualMapCompare] 保险同步触发相机停止但moveEnd未触发')
handleCameraSync() handleCameraSync()
} Cesium.Cartesian3.clone(currentPosition, syncController._lastPosition)
if (!controller.isMoving) {
syncController._isUserInteracting = false syncController._isUserInteracting = false
} }
Cesium.Cartesian3.clone(currentPosition, syncController._lastPosition) }
} }
} }
}, 300) }, 300)
console.log('[useDualMapCompare] 智能同步设置完成') console.log('[useDualMapCompare] 智能同步已启动')
}, },
stop: () => { stop: () => {
const controller = rightViewerInstance.scene.screenSpaceCameraController // 原子性设置停止标志(最优先)
syncController._stopped = true
// 移除 moveStart 监听 // 立即清除定时器
syncController._interactionHandlers.forEach(handler => {
if (typeof rightViewerInstance.camera.moveStart?.removeEventListener === 'function') {
rightViewerInstance.camera.moveStart.removeEventListener(handler)
}
})
syncController._interactionHandlers = []
// 移除 moveEnd 监听
if (syncController._moveEndHandler &&
typeof rightViewerInstance.camera.moveEnd?.removeEventListener === 'function') {
rightViewerInstance.camera.moveEnd.removeEventListener(syncController._moveEndHandler)
}
// 清除保险同步
if (syncController._interval) { if (syncController._interval) {
clearInterval(syncController._interval) clearInterval(syncController._interval)
syncController._interval = null syncController._interval = null
} }
// 移除事件监听器(需要检查 viewer 是否仍然有效)
if (rightViewerInstance && !rightViewerInstance.isDestroyed?.()) {
syncController._interactionHandlers.forEach(handler => {
if (typeof rightViewerInstance.camera.moveStart?.removeEventListener === 'function') {
try {
rightViewerInstance.camera.moveStart.removeEventListener(handler)
} catch (e) {
console.warn('[useDualMapCompare] 移除 moveStart 监听器失败:', e)
}
}
})
if (syncController._moveEndHandler &&
typeof rightViewerInstance.camera.moveEnd?.removeEventListener === 'function') {
try {
rightViewerInstance.camera.moveEnd.removeEventListener(syncController._moveEndHandler)
} catch (e) {
console.warn('[useDualMapCompare] 移除 moveEnd 监听器失败:', e)
}
}
}
syncController._interactionHandlers = []
syncController._moveEndHandler = null
syncController._isUserInteracting = false syncController._isUserInteracting = false
syncController._moveEndReceived = false // 重置标志
syncController._lastPosition = null syncController._lastPosition = null
console.log('[useDualMapCompare] 智能同步已移除')
console.log('[useDualMapCompare] 智能同步已完全停止')
} }
} }