Files
bim_engine/src/managers/engine-manager.ts
2026-04-24 11:16:37 +08:00

400 lines
15 KiB
TypeScript

/**
* 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<EngineOptions, 'container'>): 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();
}
}