2025-12-04 18:41:11 +08:00
|
|
|
|
import { Engine, type EngineOptions, type ModelLoadOptions } from '../components/engine';
|
2025-12-08 10:02:24 +08:00
|
|
|
|
import { BimComponent } from '../core/component';
|
|
|
|
|
|
import type { BimEngine } from '../bim-engine';
|
2025-12-10 09:42:05 +08:00
|
|
|
|
import { RightKeyManager } from './right-key-manager';
|
|
|
|
|
|
import { infoMenuButton } from '../components/menu/buttons/info';
|
|
|
|
|
|
import { homeMenuButton } from '../components/menu/buttons/home';
|
2026-01-15 14:13:13 +08:00
|
|
|
|
import type { MeasureMode } from '../types/measure';
|
2025-12-04 18:41:11 +08:00
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 3D 引擎管理器
|
|
|
|
|
|
* 负责连接 Engine 组件和 BimEngine,向外部暴露简化的 API
|
|
|
|
|
|
* 采用延迟初始化模式,用户需主动调用 initialize() 方法
|
|
|
|
|
|
*/
|
2025-12-08 10:02:24 +08:00
|
|
|
|
export class EngineManager extends BimComponent {
|
2025-12-04 18:41:11 +08:00
|
|
|
|
/** 3D 引擎挂载的父容器 */
|
|
|
|
|
|
private container: HTMLElement;
|
|
|
|
|
|
/** 3D 引擎组件实例 */
|
2025-12-08 10:02:24 +08:00
|
|
|
|
private engineInstance: Engine | null = null;
|
2025-12-04 18:41:11 +08:00
|
|
|
|
|
2025-12-10 09:42:05 +08:00
|
|
|
|
public rightKey: RightKeyManager | null = null; // 右键菜单管理器
|
|
|
|
|
|
|
2025-12-04 18:41:11 +08:00
|
|
|
|
/**
|
|
|
|
|
|
* 构造函数
|
2025-12-08 10:02:24 +08:00
|
|
|
|
* @param engine 引擎实例
|
2025-12-04 18:41:11 +08:00
|
|
|
|
* @param container 3D 引擎挂载的目标容器
|
|
|
|
|
|
*/
|
2025-12-08 10:02:24 +08:00
|
|
|
|
constructor(engine: BimEngine, container: HTMLElement) {
|
|
|
|
|
|
super(engine);
|
2025-12-04 18:41:11 +08:00
|
|
|
|
this.container = container;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 初始化 3D 引擎
|
|
|
|
|
|
* @param options 引擎配置选项(可选,如果不提供则使用默认配置)
|
|
|
|
|
|
* @returns 是否初始化成功
|
|
|
|
|
|
*/
|
|
|
|
|
|
public initialize(options?: Omit<EngineOptions, 'container'>): boolean {
|
|
|
|
|
|
// 如果已经初始化,先销毁旧的实例
|
2025-12-08 10:02:24 +08:00
|
|
|
|
if (this.engineInstance && this.engineInstance.isInitialized()) {
|
2025-12-04 18:41:11 +08:00
|
|
|
|
console.warn('[EngineManager] 3D Engine already initialized. Destroying old instance...');
|
2025-12-08 10:02:24 +08:00
|
|
|
|
this.engineInstance.destroy();
|
|
|
|
|
|
this.engineInstance = null;
|
2025-12-04 18:41:11 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
|
// 创建 Engine 组件实例
|
|
|
|
|
|
// options 中的配置会自动复制给 createEngine 使用
|
2025-12-08 10:02:24 +08:00
|
|
|
|
this.engineInstance = new Engine({
|
2025-12-04 18:41:11 +08:00
|
|
|
|
container: this.container,
|
|
|
|
|
|
...options, // 合并配置选项
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
// 调用组件的 init 方法初始化引擎
|
2025-12-08 10:02:24 +08:00
|
|
|
|
this.engineInstance.init();
|
2025-12-04 18:41:11 +08:00
|
|
|
|
|
2025-12-10 09:42:05 +08:00
|
|
|
|
// 初始化右键 (移到 return 之前)
|
|
|
|
|
|
this.rightKey = new RightKeyManager(this.engine, this.container);
|
|
|
|
|
|
|
|
|
|
|
|
// 注册默认右键菜单
|
|
|
|
|
|
this.rightKey.registerHandler((_e) => {
|
|
|
|
|
|
return [
|
|
|
|
|
|
infoMenuButton(this.engine),
|
|
|
|
|
|
homeMenuButton(this.engine)
|
|
|
|
|
|
];
|
|
|
|
|
|
});
|
|
|
|
|
|
|
2025-12-08 10:02:24 +08:00
|
|
|
|
return this.engineInstance.isInitialized();
|
2025-12-04 18:41:11 +08:00
|
|
|
|
} catch (error) {
|
|
|
|
|
|
console.error('[EngineManager] Failed to initialize 3D engine:', error);
|
2025-12-08 10:02:24 +08:00
|
|
|
|
this.engineInstance = null;
|
2025-12-04 18:41:11 +08:00
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
/**
|
2025-12-10 09:42:05 +08:00
|
|
|
|
* 检<EFBFBD><EFBFBD><EFBFBD> 3D 引擎是否已初始化
|
2025-12-04 18:41:11 +08:00
|
|
|
|
*/
|
|
|
|
|
|
public isInitialized(): boolean {
|
2025-12-08 10:02:24 +08:00
|
|
|
|
return this.engineInstance !== null && this.engineInstance.isInitialized();
|
2025-12-04 18:41:11 +08:00
|
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 加载 3D 模型
|
|
|
|
|
|
* @param url 模型文件 URL
|
|
|
|
|
|
* @param options 加载选项(位置、旋转、缩放)
|
|
|
|
|
|
*/
|
|
|
|
|
|
public loadModel(url: string, options?: ModelLoadOptions): void {
|
2026-01-15 14:13:13 +08:00
|
|
|
|
if (!this.engineInstance) {
|
|
|
|
|
|
console.warn('[EngineManager] 3D Engine not initialized.');
|
2025-12-04 18:41:11 +08:00
|
|
|
|
return;
|
|
|
|
|
|
}
|
2025-12-08 10:02:24 +08:00
|
|
|
|
this.engineInstance.loadModel(url, options);
|
2025-12-04 18:41:11 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-01-15 14:13:13 +08:00
|
|
|
|
|
2025-12-04 18:41:11 +08:00
|
|
|
|
/**
|
|
|
|
|
|
* 获取原始 3D 引擎实例
|
|
|
|
|
|
* 用于直接调用第三方引擎的其他 API
|
|
|
|
|
|
*/
|
|
|
|
|
|
public getEngine(): any {
|
2025-12-08 10:02:24 +08:00
|
|
|
|
if (!this.engineInstance) {
|
2025-12-04 18:41:11 +08:00
|
|
|
|
console.warn('[EngineManager] 3D Engine not initialized.');
|
|
|
|
|
|
return null;
|
|
|
|
|
|
}
|
2025-12-08 10:02:24 +08:00
|
|
|
|
return this.engineInstance.getEngine();
|
2025-12-04 18:41:11 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-01-15 14:13:13 +08:00
|
|
|
|
/**
|
|
|
|
|
|
* 回到主视角
|
|
|
|
|
|
*/
|
|
|
|
|
|
public CameraGoHome(): void {
|
|
|
|
|
|
if (!this.engineInstance) {
|
|
|
|
|
|
console.warn('[EngineManager] 3D Engine not initialized.');
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
this.engineInstance.CameraGoHome();
|
|
|
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 激活测量功能
|
|
|
|
|
|
* @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();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 获取当前激活的测量类型
|
|
|
|
|
|
*/
|
|
|
|
|
|
public getCurrentMeasureType(): MeasureMode | null {
|
|
|
|
|
|
if (!this.engineInstance) {
|
|
|
|
|
|
return null;
|
|
|
|
|
|
}
|
|
|
|
|
|
return this.engineInstance.getCurrentMeasureType();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ==================== 结束:测量功能方法 ====================
|
|
|
|
|
|
|
2025-12-04 18:41:11 +08:00
|
|
|
|
/**
|
|
|
|
|
|
* 销毁 3D 引擎实例
|
|
|
|
|
|
*/
|
|
|
|
|
|
public destroy(): void {
|
2025-12-08 10:02:24 +08:00
|
|
|
|
if (this.engineInstance) {
|
|
|
|
|
|
this.engineInstance.destroy();
|
|
|
|
|
|
this.engineInstance = null;
|
2025-12-04 18:41:11 +08:00
|
|
|
|
}
|
2025-12-10 09:42:05 +08:00
|
|
|
|
if (this.rightKey) {
|
|
|
|
|
|
this.rightKey.destroy();
|
|
|
|
|
|
this.rightKey = null;
|
|
|
|
|
|
}
|
2025-12-04 18:41:11 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|