feat(menu): implement right-click menu functions for model operations
- Add i18n translations for quick select menu (zh-CN, en-US) - Add 8 model operation methods to Engine layer - Add 8 proxy methods to EngineManager layer - Implement right-click menu handlers for hide/translucent/isolate/show all - Add quick select submenu (same type/level/level+type) - Replace console.log placeholders with actual API calls
This commit is contained in:
@@ -1,8 +1,8 @@
|
||||
import type { ThemeConfig } from '../../themes/types';
|
||||
import { IBimComponent } from '../../types/component';
|
||||
import { themeManager } from '../../services/theme';
|
||||
import type { EngineOptions, ModelLoadOptions } from './types';
|
||||
import type { MeasureMode } from '../../types/measure';
|
||||
import type { EngineOptions, ModelLoadOptions, EngineInfo } from './types';
|
||||
import { type MeasureMode } from '../../types/measure';
|
||||
import type { MeasureUnit, MeasurePrecision } from '../measure-panel/types';
|
||||
import type { SectionBoxRange } from '../section-box-panel/types';
|
||||
import { ManagerRegistry } from '../../core/manager-registry';
|
||||
@@ -11,8 +11,7 @@ import { ManagerRegistry } from '../../core/manager-registry';
|
||||
import { createEngine as createEngineSDK } from '../../../../bim_engine_base/dist/bim-engine-sdk.es';
|
||||
import "../../../../bim_engine_base/dist/iflow-engine-base.css"
|
||||
|
||||
// 重新导出类型,方便外部引用
|
||||
export type { EngineOptions, ModelLoadOptions };
|
||||
export type { EngineOptions, ModelLoadOptions, EngineInfo };
|
||||
|
||||
/**
|
||||
* 创建 Engine 实例的工厂函数
|
||||
@@ -274,14 +273,38 @@ export class Engine implements IBimComponent {
|
||||
}
|
||||
|
||||
console.log(`[Engine] Activating measure: ${mode}`);
|
||||
const measureKey = `${mode}Measure`;
|
||||
const measureInstance = (this.engine.measure as any)[measureKey];
|
||||
if (measureInstance && typeof measureInstance.active === 'function') {
|
||||
measureInstance.active();
|
||||
this.currentMeasureType = mode;
|
||||
} else {
|
||||
console.error(`[Engine] Measure type ${mode} not available.`);
|
||||
const measure = this.engine.measure;
|
||||
|
||||
switch (mode) {
|
||||
case 'clearHeight':
|
||||
measure.clearHeightMeasure.active();
|
||||
break;
|
||||
case 'clearDistance':
|
||||
measure.clearDistanceMeasure.active();
|
||||
break;
|
||||
case 'distance':
|
||||
measure.distanceMeasure.active();
|
||||
break;
|
||||
case 'elevation':
|
||||
measure.elevationMeasure.active();
|
||||
break;
|
||||
case 'point':
|
||||
measure.pointMeasure.active();
|
||||
break;
|
||||
case 'angle':
|
||||
measure.angleMeasure.active();
|
||||
break;
|
||||
case 'area':
|
||||
measure.areaMeasure.active();
|
||||
break;
|
||||
case 'slope':
|
||||
measure.slopeMeasure.active();
|
||||
break;
|
||||
default:
|
||||
console.error(`[Engine] Unknown measure type: ${mode}`);
|
||||
return;
|
||||
}
|
||||
this.currentMeasureType = mode;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -470,6 +493,18 @@ export class Engine implements IBimComponent {
|
||||
this.engine.clipping.recover();
|
||||
}
|
||||
|
||||
public fitSectionBoxToModel(): void {
|
||||
if (!this._isInitialized || !this.engine) {
|
||||
console.error('[Engine] Cannot fit section box: engine not initialized.');
|
||||
return;
|
||||
}
|
||||
const model = this.engine.engineStatus?.highlightModels;
|
||||
if (model) {
|
||||
console.log('[Engine] Fitting section box to model');
|
||||
this.engine.clipping?.clippingModel(model);
|
||||
}
|
||||
}
|
||||
|
||||
// ==================== 结束:剖切功能 ====================
|
||||
|
||||
// ==================== 漫游功能 ====================
|
||||
@@ -499,6 +534,7 @@ export class Engine implements IBimComponent {
|
||||
|
||||
console.log('[Engine] Activating first person mode');
|
||||
this.engine.controlModule.switchFirstPersonMode();
|
||||
this.loadWalkSettings();
|
||||
this.isWalkModeActive = true;
|
||||
}
|
||||
|
||||
@@ -520,46 +556,55 @@ export class Engine implements IBimComponent {
|
||||
this.isWalkModeActive = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置漫游移动速度
|
||||
* @param speed 移动速度(默认 0.02)
|
||||
*/
|
||||
private static WALK_SPEED_KEY = 'bim-walk-speed';
|
||||
private static WALK_GRAVITY_KEY = 'bim-walk-gravity';
|
||||
private static WALK_COLLISION_KEY = 'bim-walk-collision';
|
||||
|
||||
public setWalkSpeed(speed: number): void {
|
||||
if (!this._isInitialized || !this.engine?.controlModule?.firstPersonControls) {
|
||||
if (!this._isInitialized || !this.engine?.controlModule) {
|
||||
console.error('[Engine] Cannot set walk speed: engine not initialized.');
|
||||
return;
|
||||
}
|
||||
|
||||
console.log('[Engine] Setting walk speed:', speed);
|
||||
this.engine.controlModule.firstPersonControls.moveSpeed = speed;
|
||||
localStorage.setItem(Engine.WALK_SPEED_KEY, String(speed));
|
||||
this.engine.controlModule.setMoveSpeed(speed);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置漫游重力开关
|
||||
* @param enabled 是否启用重力
|
||||
*/
|
||||
public setWalkGravity(enabled: boolean): void {
|
||||
if (!this._isInitialized || !this.engine?.controlModule?.firstPersonControls) {
|
||||
if (!this._isInitialized || !this.engine?.controlModule) {
|
||||
console.error('[Engine] Cannot set walk gravity: engine not initialized.');
|
||||
return;
|
||||
}
|
||||
|
||||
console.log('[Engine] Setting walk gravity:', enabled);
|
||||
this.engine.controlModule.firstPersonControls.applyGravity = enabled;
|
||||
localStorage.setItem(Engine.WALK_GRAVITY_KEY, String(enabled));
|
||||
this.engine.controlModule.setApplyGravity(enabled);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置漫游碰撞检测开关
|
||||
* @param enabled 是否启用碰撞检测
|
||||
*/
|
||||
public setWalkCollision(enabled: boolean): void {
|
||||
if (!this._isInitialized || !this.engine?.controlModule?.firstPersonControls) {
|
||||
if (!this._isInitialized || !this.engine?.controlModule) {
|
||||
console.error('[Engine] Cannot set walk collision: engine not initialized.');
|
||||
return;
|
||||
}
|
||||
localStorage.setItem(Engine.WALK_COLLISION_KEY, String(enabled));
|
||||
this.engine.controlModule.setApplyCollision(enabled);
|
||||
}
|
||||
|
||||
console.log('[Engine] Setting walk collision:', enabled);
|
||||
this.engine.controlModule.firstPersonControls.applyCollision = enabled;
|
||||
private loadWalkSettings(): void {
|
||||
if (!this.engine?.controlModule) return;
|
||||
|
||||
const speed = localStorage.getItem(Engine.WALK_SPEED_KEY);
|
||||
const gravity = localStorage.getItem(Engine.WALK_GRAVITY_KEY);
|
||||
const collision = localStorage.getItem(Engine.WALK_COLLISION_KEY);
|
||||
|
||||
this.engine.controlModule.setMoveSpeed(speed ? Number(speed) : 1);
|
||||
this.engine.controlModule.setApplyGravity(gravity === 'true');
|
||||
this.engine.controlModule.setApplyCollision(collision === 'true');
|
||||
}
|
||||
|
||||
public toggleMiniMap(): void {
|
||||
if (!this._isInitialized || !this.engine?.controlModule) {
|
||||
console.error('[Engine] Cannot toggle mini map: engine not initialized.');
|
||||
return;
|
||||
}
|
||||
this.engine.controlModule.toggleMinMap();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -643,6 +688,220 @@ export class Engine implements IBimComponent {
|
||||
this.engine.rangeScale?.active();
|
||||
}
|
||||
|
||||
public getEngineInfo(): EngineInfo | null {
|
||||
if (!this._isInitialized || !this.engine) {
|
||||
console.warn('[Engine] Engine not initialized.');
|
||||
return null;
|
||||
}
|
||||
return this.engine.engineInfo.getEngineInfo() as EngineInfo;
|
||||
}
|
||||
|
||||
// ==================== 路径漫游 ====================
|
||||
|
||||
/**
|
||||
* 添加漫游点
|
||||
* 将当前相机位置添加为一个漫游点
|
||||
*/
|
||||
public pathRoamingAddPoint(): void {
|
||||
// 检查引擎是否已初始化
|
||||
if (!this._isInitialized || !this.engine?.pathRoaming) {
|
||||
console.warn('[Engine] pathRoaming not available');
|
||||
return;
|
||||
}
|
||||
// 调用底层 API 添加点位
|
||||
this.engine.pathRoaming.addPoint(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除指定索引的漫游点
|
||||
* @param index 要删除的漫游点索引
|
||||
*/
|
||||
public pathRoamingRemovePoint(index: number): void {
|
||||
if (!this._isInitialized || !this.engine?.pathRoaming) {
|
||||
console.warn('[Engine] pathRoaming not available');
|
||||
return;
|
||||
}
|
||||
this.engine.pathRoaming.removePoint(index);
|
||||
}
|
||||
|
||||
/**
|
||||
* 清除所有漫游点
|
||||
*/
|
||||
public pathRoamingClearPoints(): void {
|
||||
if (!this._isInitialized || !this.engine?.pathRoaming) {
|
||||
console.warn('[Engine] pathRoaming not available');
|
||||
return;
|
||||
}
|
||||
this.engine.pathRoaming.clearPoints();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取所有漫游点
|
||||
* @returns 漫游点数组
|
||||
*/
|
||||
public pathRoamingGetPoints(): any[] {
|
||||
if (!this._isInitialized || !this.engine?.pathRoaming) {
|
||||
console.warn('[Engine] pathRoaming not available');
|
||||
return [];
|
||||
}
|
||||
return this.engine.pathRoaming.getPoints() ?? [];
|
||||
}
|
||||
|
||||
/**
|
||||
* 跳转到指定漫游点
|
||||
* @param index 目标漫游点索引
|
||||
*/
|
||||
public pathRoamingJumpToPoint(index: number): void {
|
||||
if (!this._isInitialized || !this.engine?.pathRoaming) {
|
||||
console.warn('[Engine] pathRoaming not available');
|
||||
return;
|
||||
}
|
||||
this.engine.pathRoaming.jumpToPoint(index);
|
||||
}
|
||||
|
||||
/**
|
||||
* 播放漫游
|
||||
* @param options 播放选项,包含时长、循环、回调等配置
|
||||
*/
|
||||
public pathRoamingPlay(options?: {
|
||||
duration?: number;
|
||||
loop?: boolean;
|
||||
onComplete?: () => void;
|
||||
onPointComplete?: (pointIndex: number) => void;
|
||||
}): void {
|
||||
if (!this._isInitialized || !this.engine?.pathRoaming) {
|
||||
console.warn('[Engine] pathRoaming not available');
|
||||
return;
|
||||
}
|
||||
this.engine.pathRoaming.play(options);
|
||||
}
|
||||
|
||||
/**
|
||||
* 停止漫游
|
||||
*/
|
||||
public pathRoamingStop(): void {
|
||||
if (!this._isInitialized || !this.engine?.pathRoaming) {
|
||||
console.warn('[Engine] pathRoaming not available');
|
||||
return;
|
||||
}
|
||||
this.engine.pathRoaming.stop();
|
||||
}
|
||||
|
||||
// ==================== 结束:路径漫游 ====================
|
||||
|
||||
// ==================== 构件操作 ====================
|
||||
|
||||
/**
|
||||
* 隐藏选中构件
|
||||
*/
|
||||
public hideSelectedModels(): void {
|
||||
if (!this._isInitialized || !this.engine?.modelToolModule) {
|
||||
console.warn('[Engine] Cannot hide models: engine not initialized.');
|
||||
return;
|
||||
}
|
||||
const models = this.engine.engineStatus?.highlightModels;
|
||||
if (models) {
|
||||
this.engine.modelToolModule.hideModel(models);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 半透明选中构件
|
||||
*/
|
||||
public translucentSelectedModels(): void {
|
||||
if (!this._isInitialized || !this.engine?.modelToolModule) {
|
||||
console.warn('[Engine] Cannot translucent models: engine not initialized.');
|
||||
return;
|
||||
}
|
||||
const models = this.engine.engineStatus?.highlightModels;
|
||||
if (models) {
|
||||
this.engine.modelToolModule.translucentModel(models);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 隔离选中构件(隐藏其他)
|
||||
*/
|
||||
public isolateSelectedModels(): void {
|
||||
if (!this._isInitialized || !this.engine?.modelToolModule) {
|
||||
console.warn('[Engine] Cannot isolate models: engine not initialized.');
|
||||
return;
|
||||
}
|
||||
const models = this.engine.engineStatus?.highlightModels;
|
||||
if (models) {
|
||||
this.engine.modelToolModule.isolateModel(models);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 半透明其他构件
|
||||
*/
|
||||
public translucentOtherModels(): void {
|
||||
if (!this._isInitialized || !this.engine?.modelToolModule) {
|
||||
console.warn('[Engine] Cannot translucent other models: engine not initialized.');
|
||||
return;
|
||||
}
|
||||
const models = this.engine.engineStatus?.highlightModels;
|
||||
if (models) {
|
||||
this.engine.modelToolModule.translucentOtherModel(models);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 显示所有模型
|
||||
*/
|
||||
public showAllModels(): void {
|
||||
if (!this._isInitialized || !this.engine?.modelToolModule) {
|
||||
console.warn('[Engine] Cannot show all models: engine not initialized.');
|
||||
return;
|
||||
}
|
||||
this.engine.modelToolModule.showAllModels();
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量选择同类模型
|
||||
*/
|
||||
public batchSelectSameTypeModel(): void {
|
||||
if (!this._isInitialized || !this.engine?.modelToolModule) {
|
||||
console.warn('[Engine] Cannot batch select: engine not initialized.');
|
||||
return;
|
||||
}
|
||||
const models = this.engine.engineStatus?.highlightModels;
|
||||
if (models) {
|
||||
this.engine.modelToolModule.batchSelectSameTypeModel(models);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量选择同层模型
|
||||
*/
|
||||
public batchSelectSameLevelModel(): void {
|
||||
if (!this._isInitialized || !this.engine?.modelToolModule) {
|
||||
console.warn('[Engine] Cannot batch select: engine not initialized.');
|
||||
return;
|
||||
}
|
||||
const models = this.engine.engineStatus?.highlightModels;
|
||||
if (models) {
|
||||
this.engine.modelToolModule.batchSelectSameLevelModel(models);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量选择同层同类模型
|
||||
*/
|
||||
public batchSelectSameLevelTypeModel(): void {
|
||||
if (!this._isInitialized || !this.engine?.modelToolModule) {
|
||||
console.warn('[Engine] Cannot batch select: engine not initialized.');
|
||||
return;
|
||||
}
|
||||
const models = this.engine.engineStatus?.highlightModels;
|
||||
if (models) {
|
||||
this.engine.modelToolModule.batchSelectSameLevelTypeModel(models);
|
||||
}
|
||||
}
|
||||
|
||||
// ==================== 结束:构件操作 ====================
|
||||
|
||||
/**
|
||||
* 销毁组件 (接口实现)
|
||||
* 清理资源、取消订阅、销毁引擎实例
|
||||
|
||||
Reference in New Issue
Block a user