/** * 3D 引擎管理器 * 负责管理 3D 渲染引擎的初始化、模型加载和生命周期 * * 设计原则: * - EngineManager 只暴露面向外部用户的公共 API * - 内部管理器通过 getEngineComponent() 直接访问 Engine 组件 * - 不再透传 Engine 组件的方法 */ import { Engine, type EngineOptions, type ModelLoadOptions } from '../components/engine'; import { BaseManager } from '../core/base-manager'; import { RightKeyManager } from './right-key-manager'; import type { MenuItemConfig } from '../components/menu/item'; import { ManagerRegistry } from '../core/manager-registry'; import type { DrawingPinRecord } from '../types/events'; /** * 3D 引擎管理器 * 封装底层 3D 引擎,提供模型加载、渲染控制等公共 API */ export class EngineManager extends BaseManager { /** 容器元素 */ private container: HTMLElement; /** 引擎组件实例 */ private engineInstance: Engine | null = null; /** 右键菜单管理器 */ public rightKey: RightKeyManager | null = null; constructor(container: HTMLElement, registry: ManagerRegistry) { super(registry); this.container = container; } /** * 获取 Engine 组件实例 * 内部管理器通过此方法直接访问 Engine 组件的全部能力 * @returns Engine 组件实例,未初始化时返回 null */ public getEngineComponent(): Engine | null { return this.engineInstance; } /** * 初始化 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.registry); this.engineInstance.init(); this.rightKey = new RightKeyManager(this.container, this.registry); this.rightKey.registerHandler((_e) => { const selected = this.engineInstance?.getSelectedComponent(); const items: MenuItemConfig[] = []; if (selected) { // 1. 构件详情 items.push({ id: 'componentDetail', label: 'menu.componentDetail', group: 'component', order: 1, divider: true, onClick: () => { const registry = this.registry; registry.componentDetail?.show(); this.rightKey?.hide(); } }); // 2. 隐藏选中构件 items.push({ id: 'hideSelected', label: 'menu.hideSelected', group: 'component', order: 2, onClick: () => { const models = this.engineInstance?.getHighlightModels(); if (models) { this.engineInstance?.hideModels(models); } this.rightKey?.hide(); } }); // 3. 半透明选中构件 items.push({ id: 'transparentSelected', label: 'menu.transparentSelected', group: 'component', order: 3, onClick: () => { const models = this.engineInstance?.getHighlightModels(); if (models) { this.engineInstance?.translucentModels(models); } this.rightKey?.hide(); } }); // 4. 取消半透明 items.push({ id: 'cancelTranslucent', label: 'menu.cancelTranslucent', group: 'component', order: 4, onClick: () => { this.engineInstance?.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.engineInstance?.getHighlightModels(); if (models) { this.engineInstance?.isolateModels(models); } this.rightKey?.hide(); } }, { id: 'transparentOthers', label: 'menu.transparentOthers', onClick: () => { const models = this.engineInstance?.getHighlightModels(); if (models) { this.engineInstance?.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.engineInstance?.getHighlightModels(); if (models) { this.engineInstance?.batchSelectSameTypeModel(models); } this.rightKey?.hide(); } }, { id: 'selectSameLevel', label: 'menu.selectSameLevel', onClick: () => { const models = this.engineInstance?.getHighlightModels(); if (models) { this.engineInstance?.batchSelectSameLevelModel(models); } this.rightKey?.hide(); } }, { id: 'selectSameLevelType', label: 'menu.selectSameLevelType', onClick: () => { const models = this.engineInstance?.getHighlightModels(); if (models) { this.engineInstance?.batchSelectSameLevelTypeModel(models); } this.rightKey?.hide(); } } ] }); // 7. 剖切盒适应 items.push({ id: 'fitSectionBox', label: 'menu.fitSectionBox', group: 'component', order: 7, onClick: () => { this.engineInstance?.fitSectionBoxToModel(); this.rightKey?.hide(); } }); } // 8. 显示全部(始终显示) items.push({ id: 'showAll', label: 'menu.showAll', group: 'component', order: 8, onClick: () => { this.engineInstance?.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); } /** 暂停渲染 */ 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 params 查询参数 * @param params.url 模型 URL * @param params.ids 构件 ID 数组 * @returns 构件数据 */ public getModelPosition(params: { url: string; ids: number[] }): any { if (!this.engineInstance) { console.warn('[EngineManager] 3D Engine not initialized.'); return null; } return this.engineInstance.getModelPosition(params); } /** * 跳转到指定相机视角(问题报告用) * @param cameraData 相机配置数据,包含 position、target、rotation 等信息 * @returns 是否跳转成功 */ public jumpToCamera(cameraData: any): boolean { if (!this.engineInstance) { console.warn('[EngineManager] 3D Engine not initialized.'); return false; } return this.engineInstance.jumpToCamera(cameraData); } public setMainViewPort(viewData: any): void { if (!this.engineInstance) { console.warn('[EngineManager] 3D Engine not initialized.'); return; } this.engineInstance.setMainViewPort(viewData); } public getConstructTreeData(): { level: any[]; type: any[]; major: any[] } { if (!this.engineInstance) { console.warn('[EngineManager] 3D Engine not initialized.'); return { level: [], type: [], major: [] }; } return { level: this.engineInstance.getLevelTreeData(), type: this.engineInstance.getTypeTreeData(), major: this.engineInstance.getMajorTreeData(), }; } public getComponentProperties(url: string, id: string, callback: (data: any) => void): void { if (!this.engineInstance) { console.warn('[EngineManager] 3D Engine not initialized.'); return; } this.engineInstance.getComponentProperties(url, id, callback); } public setPinRecords(records: DrawingPinRecord[]): void { console.log('[EngineManager] setPinRecords called, records count:', records.length); if (!this.engineInstance) { console.warn('[EngineManager] 3D Engine not initialized.'); return; } this.engineInstance.setPinRecords(records); } public setPinList(records: DrawingPinRecord[]): void { this.setPinRecords(records); } public registerRightKeyHandler(handler: (e: MouseEvent) => MenuItemConfig[] | null): void { if (!this.rightKey) { console.warn('[EngineManager] RightKey manager not initialized.'); return; } this.rightKey.registerHandler(handler); } public unregisterRightKeyHandler(handler: (e: MouseEvent) => MenuItemConfig[] | null): void { if (!this.rightKey) { console.warn('[EngineManager] RightKey manager not initialized.'); return; } this.rightKey.unregisterHandler(handler); } public clearRightKeyHandlers(keepDefault: boolean = true): void { if (!this.rightKey) { console.warn('[EngineManager] RightKey manager not initialized.'); return; } this.rightKey.clearHandlers(keepDefault); } public showRightKeyMenu(x: number, y: number, items: MenuItemConfig[], groupOrder?: string[]): void { if (!this.rightKey) { console.warn('[EngineManager] RightKey manager not initialized.'); return; } this.rightKey.showMenu(x, y, items, groupOrder); } public hideRightKeyMenu(): void { if (!this.rightKey) { console.warn('[EngineManager] RightKey manager not initialized.'); return; } this.rightKey.hide(); } /** 销毁引擎管理器 */ public destroy(): void { if (this.engineInstance) { this.engineInstance.destroy(); this.engineInstance = null; } if (this.rightKey) { this.rightKey.destroy(); this.rightKey = null; } super.destroy(); } }