/** * 3D 引擎管理器 * 负责管理 3D 渲染引擎的初始化、模型加载和测量功能 */ import { Engine, type EngineOptions, type ModelLoadOptions, type EngineInfo } from '../components/engine'; import { BaseManager } from '../core/base-manager'; import { RightKeyManager } from './right-key-manager'; import type { MeasureMode } from '../types/measure'; import type { MeasureUnit, MeasurePrecision } from '../components/measure-panel/types'; import type { SectionBoxRange } from '../components/section-box-panel/types'; import type { MenuItemConfig } from '../components/menu/item'; import { ManagerRegistry } from '../core/manager-registry'; /** * 3D 引擎管理器 * 封装底层 3D 引擎,提供模型加载、相机控制、测量等功能 */ export class EngineManager extends BaseManager { /** 容器元素 */ private container: HTMLElement; /** 引擎实例 */ private engineInstance: Engine | null = null; /** 右键菜单管理器 */ public rightKey: RightKeyManager | null = null; constructor(container: HTMLElement) { super(); this.container = container; } /** * 初始化 3D 引擎 * @param options 引擎配置选项 * @returns 是否初始化成功 */ public initialize(options?: Omit): boolean { if (this.engineInstance && this.engineInstance.isInitialized()) { console.warn('[EngineManager] 3D Engine already initialized. Destroying old instance...'); this.engineInstance.destroy(); this.engineInstance = null; } try { this.engineInstance = new Engine({ container: this.container, ...options, }); this.engineInstance.init(); this.rightKey = new RightKeyManager(this.container); this.rightKey.registerHandler((_e) => { const selected = this.getSelectedComponent(); const items: MenuItemConfig[] = []; if (selected) { // 1. 构件详情 items.push({ id: 'componentDetail', label: 'menu.componentDetail', group: 'component', order: 1, divider: true, onClick: () => { const registry = ManagerRegistry.getInstance(); registry.componentDetail?.show(); this.rightKey?.hide(); } }); // 2. 隐藏选中构件 items.push({ id: 'hideSelected', label: 'menu.hideSelected', group: 'component', order: 2, onClick: () => { const models = this.getHighlightModels(); if (models) { this.hideModels(models); } this.rightKey?.hide(); } }); // 3. 半透明选中构件 items.push({ id: 'transparentSelected', label: 'menu.transparentSelected', group: 'component', order: 3, onClick: () => { const models = this.getHighlightModels(); if (models) { this.translucentModels(models); } this.rightKey?.hide(); } }); // 4. 取消半透明 items.push({ id: 'cancelTranslucent', label: 'menu.cancelTranslucent', group: 'component', order: 4, onClick: () => { this.unTranslucentModel(); this.rightKey?.hide(); } }); // 5. 隔离选中构件(带子菜单) items.push({ id: 'isolateSelected', label: 'menu.isolateSelected', group: 'component', order: 5, divider: true, children: [ { id: 'hideOthers', label: 'menu.hideOthers', onClick: () => { const models = this.getHighlightModels(); if (models) { this.isolateModels(models); } this.rightKey?.hide(); } }, { id: 'transparentOthers', label: 'menu.transparentOthers', onClick: () => { const models = this.getHighlightModels(); if (models) { this.translucentOtherModels(models); } this.rightKey?.hide(); } } ] }); // 6. 快速选择(带子菜单) items.push({ id: 'quickSelect', label: 'menu.quickSelect', group: 'component', order: 6, children: [ { id: 'selectSameType', label: 'menu.selectSameType', onClick: () => { const models = this.getHighlightModels(); if (models) { this.batchSelectSameTypeModel(models); } this.rightKey?.hide(); } }, { id: 'selectSameLevel', label: 'menu.selectSameLevel', onClick: () => { const models = this.getHighlightModels(); if (models) { this.batchSelectSameLevelModel(models); } this.rightKey?.hide(); } }, { id: 'selectSameLevelType', label: 'menu.selectSameLevelType', onClick: () => { const models = this.getHighlightModels(); if (models) { this.batchSelectSameLevelTypeModel(models); } this.rightKey?.hide(); } } ] }); // 7. 剖切盒适应 items.push({ id: 'fitSectionBox', label: 'menu.fitSectionBox', group: 'component', order: 7, onClick: () => { this.fitSectionBoxToModel(); this.rightKey?.hide(); } }); } // 8. 显示全部(始终显示) items.push({ id: 'showAll', label: 'menu.showAll', group: 'component', order: 8, onClick: () => { this.showAllModels(); this.emit('menu:show-all', {}); this.rightKey?.hide(); } }); return items; }); return this.engineInstance.isInitialized(); } catch (error) { console.error('[EngineManager] Failed to initialize 3D engine:', error); this.engineInstance = null; return false; } } /** * 检查引擎是否已初始化 * @returns 是否已初始化 */ public isInitialized(): boolean { return this.engineInstance !== null && this.engineInstance.isInitialized(); } /** * 加载模型 * @param urls 模型 URL 数组 * @param options 加载选项 */ public loadModel(urls: string[], options?: ModelLoadOptions): void { if (!this.engineInstance) { console.warn('[EngineManager] 3D Engine not initialized.'); return; } this.engineInstance.loadModel(urls, options); } /** * 获取底层引擎实例 * @returns 引擎实例 */ public getEngine(): any { if (!this.engineInstance) { console.warn('[EngineManager] 3D Engine not initialized.'); return null; } return this.engineInstance.getEngine(); } /** 相机回到初始位置 */ public CameraGoHome(): void { if (!this.engineInstance) { console.warn('[EngineManager] 3D Engine not initialized.'); return; } this.engineInstance.CameraGoHome(); } /** 暂停渲染 */ public pauseRendering(): void { if (!this.engineInstance) { console.warn('[EngineManager] 3D Engine not initialized.'); return; } this.engineInstance.pauseRendering(); } /** 恢复渲染 */ public resumeRendering(): void { if (!this.engineInstance) { console.warn('[EngineManager] 3D Engine not initialized.'); return; } this.engineInstance.resumeRendering(); } /** * 激活测量模式 * @param mode 测量模式 */ public activateMeasure(mode: MeasureMode): void { if (!this.engineInstance) { console.warn('[EngineManager] 3D Engine not initialized.'); return; } this.engineInstance.activateMeasure(mode); } /** 停用测量模式 */ public deactivateMeasure(): void { if (!this.engineInstance) { return; } this.engineInstance.deactivateMeasure(); } /** * 获取当前测量类型 * @returns 当前测量模式 */ public getCurrentMeasureType(): MeasureMode | null { if (!this.engineInstance) { return null; } return this.engineInstance.getCurrentMeasureType(); } public clearAllMeasures(): void { if (!this.engineInstance) { return; } this.engineInstance.clearAllMeasures(); } public saveMeasureSetting(setting: { unit: MeasureUnit; precision: MeasurePrecision }): void { if (!this.engineInstance) { return; } this.engineInstance.saveMeasureSetting(setting); } public activeSection(mode: 'x' | 'y' | 'z' | 'box' | 'face'): void { if (!this.engineInstance) { console.warn('[EngineManager] 3D Engine not initialized.'); return; } this.engineInstance.activeSection(mode); } /** * 获取当前激活的剖切模式 * @returns 当前剖切模式,未激活时返回 null */ public getCurrentSectionMode(): 'x' | 'y' | 'z' | 'box' | 'face' | null { if (!this.engineInstance) { return null; } return this.engineInstance.getCurrentSectionMode(); } /** * 停用所有剖切功能 * @remarks 关闭剖切对话框时调用 */ public deactivateSection(): void { if (!this.engineInstance) { return; } this.engineInstance.deactivateSection(); } /** * 设置剖切盒范围 * @param range 各轴的剖切范围 (百分比 0-100) * @remarks 仅在 'box' 模式下有效 */ public setSectionBoxRange(range: SectionBoxRange): void { if (!this.engineInstance) { console.warn('[EngineManager] 3D Engine not initialized.'); return; } this.engineInstance.setSectionBoxRange(range); } /** * 隐藏剖切面(临时隐藏,可恢复) * @remarks 配合 recoverSection() 使用 */ public hideSection(): void { if (!this.engineInstance) { return; } this.engineInstance.hideSection(); } /** * 恢复剖切面(从隐藏状态恢复) * @remarks 恢复被 hideSection() 隐藏的剖切面 */ public recoverSection(): void { if (!this.engineInstance) { return; } this.engineInstance.recoverSection(); } public fitSectionBoxToModel(): void { if (!this.engineInstance) { return; } this.engineInstance.fitSectionBoxToModel(); } /** * 剖切盒适应(缩放到场景整体包围盒) * @remarks 对接底层 clipping.scaleBox() */ public scaleSectionBox(): void { if (!this.engineInstance) { return; } this.engineInstance.scaleSectionBox(); } /** * 反向剖切 * @remarks 对接底层 clipping.reverse() */ public reverseSection(): void { if (!this.engineInstance) { return; } this.engineInstance.reverseSection(); } /** 激活框选放大功能 */ public activateZoomBox(): void { if (!this.engineInstance) { console.warn('[EngineManager] 3D Engine not initialized.'); return; } this.engineInstance.activateZoomBox(); } // ==================== 漫游功能 ==================== /** 激活第一人称漫游模式 */ public activateFirstPersonMode(): void { if (!this.engineInstance) { console.warn('[EngineManager] 3D Engine not initialized.'); return; } this.engineInstance.activateFirstPersonMode(); } /** 停用第一人称漫游模式 */ public deactivateFirstPersonMode(): void { if (!this.engineInstance) { return; } this.engineInstance.deactivateFirstPersonMode(); } public setWalkSpeed(speed: number): void { this.engineInstance?.setWalkSpeed(speed); } public setWalkGravity(enabled: boolean): void { this.engineInstance?.setWalkGravity(enabled); } public setWalkCollision(enabled: boolean): void { this.engineInstance?.setWalkCollision(enabled); } public toggleMiniMap(): void { this.engineInstance?.toggleMiniMap(); } public isFirstPersonModeActive(): boolean { return this.engineInstance?.isFirstPersonModeActive() ?? false; } // ==================== 结束:漫游功能 ==================== // ==================== 构件选中 ==================== /** * 获取当前选中的构件 * @returns 选中构件的 URL 和 ID,未选中时返回 null */ public getSelectedComponent(): { url: string; id: string } | null { return this.engineInstance?.getSelectedComponent() ?? null; } /** * 获取构件属性 * @param url 模型 URL * @param id 构件 ID * @param callback 回调函数,接收属性数据 */ public getComponentProperties( url: string, id: string, callback: (data: any) => void ): void { this.engineInstance?.getComponentProperties(url, id, callback); } // ==================== 结束:构件选中 ==================== // ==================== 模型树 ==================== public getTypeTreeData(): any[] { return this.engineInstance?.getTypeTreeData() ?? []; } public getLevelTreeData(): any[] { return this.engineInstance?.getLevelTreeData() ?? []; } public getMajorTreeData(): any[] { return this.engineInstance?.getMajorTreeData() ?? []; } public getEngineInfo(): EngineInfo | null { return this.engineInstance?.getEngineInfo() ?? null; } // ==================== 结束:模型树 ==================== // ==================== 路径漫游 ==================== /** * 添加漫游点 * 将当前相机位置添加为一个漫游点 */ public pathRoamingAddPoint(): void { this.engineInstance?.pathRoamingAddPoint(); } /** * 删除指定索引的漫游点 * @param index 要删除的漫游点索引 */ public pathRoamingRemovePoint(index: number): void { this.engineInstance?.pathRoamingRemovePoint(index); } /** * 清除所有漫游点 */ public pathRoamingClearPoints(): void { this.engineInstance?.pathRoamingClearPoints(); } /** * 获取所有漫游点 * @returns 漫游点数组 */ public pathRoamingGetPoints(): any[] { return this.engineInstance?.pathRoamingGetPoints() ?? []; } /** * 跳转到指定漫游点 * @param index 目标漫游点索引 */ public pathRoamingJumpToPoint(index: number): void { this.engineInstance?.pathRoamingJumpToPoint(index); } /** * 播放漫游 * @param options 播放选项,包含时长、循环、回调等配置 */ public pathRoamingPlay(options?: { duration?: number; loop?: boolean; onComplete?: () => void; onPointComplete?: (pointIndex: number) => void; }): void { this.engineInstance?.pathRoamingPlay(options); } /** * 停止漫游 */ public pathRoamingStop(): void { this.engineInstance?.pathRoamingStop(); } // ==================== 结束:路径漫游 ==================== // ==================== 构件操作 ==================== /** * 获取当前高亮(选中)的模型 * @returns 高亮模型对象,未选中时返回 null */ public getHighlightModels(): any { return this.engineInstance?.getHighlightModels() ?? null; } /** * 高亮指定模型构件 * * @param models - 要高亮的模型数组,格式: [{ url: string, ids: string[] }] * * @example * manager.highlightModel([ * { url: 'https://xxx/models/xxx/', ids: [350518, 350520] } * ]); */ public highlightModel(models: { url: string; ids: number[] }[]): void { this.engineInstance?.highlightModel(models); } public unhighlightAllModels(): void { this.engineInstance?.unhighlightAllModels(); } public viewScaleToModel(models: { url: string; ids: number[] }[]): void { this.engineInstance?.viewScaleToModel(models); } public hideModels(models: { url: string; ids: number[] }[]): void { this.engineInstance?.hideModels(models); } public showModel(models: { url: string; ids: number[] }[]): void { this.engineInstance?.showModel(models); } /** * 半透明指定模型 * @param models 要半透明的模型对象 */ public translucentModels(models: any): void { this.engineInstance?.translucentModels(models); } /** * 取消半透明 */ public unTranslucentModel(): void { this.engineInstance?.unTranslucentModel(); } /** * 隔离指定模型(隐藏其他) * @param models 要隔离的模型对象 */ public isolateModels(models: any): void { this.engineInstance?.isolateModels(models); } /** * 半透明其他构件 * @param models 基准模型对象 */ public translucentOtherModels(models: any): void { this.engineInstance?.translucentOtherModels(models); } /** * 显示所有模型 */ public showAllModels(): void { this.engineInstance?.showAllModels(); } /** * 批量选择同类模型 * @param models 基准模型对象 */ public batchSelectSameTypeModel(models: any): void { this.engineInstance?.batchSelectSameTypeModel(models); } /** * 批量选择同层模型 * @param models 基准模型对象 */ public batchSelectSameLevelModel(models: any): void { this.engineInstance?.batchSelectSameLevelModel(models); } /** * 批量选择同层同类模型 * @param models 基准模型对象 */ public batchSelectSameLevelTypeModel(models: any): void { this.engineInstance?.batchSelectSameLevelTypeModel(models); } // ==================== 结束:构件操作 ==================== /** 销毁引擎管理器 */ public destroy(): void { if (this.engineInstance) { this.engineInstance.destroy(); this.engineInstance = null; } if (this.rightKey) { this.rightKey.destroy(); this.rightKey = null; } super.destroy(); } }