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 type { ThemeConfig } from '../../themes/types';
|
||||||
import { IBimComponent } from '../../types/component';
|
import { IBimComponent } from '../../types/component';
|
||||||
import { themeManager } from '../../services/theme';
|
import { themeManager } from '../../services/theme';
|
||||||
import type { EngineOptions, ModelLoadOptions } from './types';
|
import type { EngineOptions, ModelLoadOptions, EngineInfo } from './types';
|
||||||
import type { MeasureMode } from '../../types/measure';
|
import { type MeasureMode } from '../../types/measure';
|
||||||
import type { MeasureUnit, MeasurePrecision } from '../measure-panel/types';
|
import type { MeasureUnit, MeasurePrecision } from '../measure-panel/types';
|
||||||
import type { SectionBoxRange } from '../section-box-panel/types';
|
import type { SectionBoxRange } from '../section-box-panel/types';
|
||||||
import { ManagerRegistry } from '../../core/manager-registry';
|
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 { createEngine as createEngineSDK } from '../../../../bim_engine_base/dist/bim-engine-sdk.es';
|
||||||
import "../../../../bim_engine_base/dist/iflow-engine-base.css"
|
import "../../../../bim_engine_base/dist/iflow-engine-base.css"
|
||||||
|
|
||||||
// 重新导出类型,方便外部引用
|
export type { EngineOptions, ModelLoadOptions, EngineInfo };
|
||||||
export type { EngineOptions, ModelLoadOptions };
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 创建 Engine 实例的工厂函数
|
* 创建 Engine 实例的工厂函数
|
||||||
@@ -274,14 +273,38 @@ export class Engine implements IBimComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
console.log(`[Engine] Activating measure: ${mode}`);
|
console.log(`[Engine] Activating measure: ${mode}`);
|
||||||
const measureKey = `${mode}Measure`;
|
const measure = this.engine.measure;
|
||||||
const measureInstance = (this.engine.measure as any)[measureKey];
|
|
||||||
if (measureInstance && typeof measureInstance.active === 'function') {
|
switch (mode) {
|
||||||
measureInstance.active();
|
case 'clearHeight':
|
||||||
this.currentMeasureType = mode;
|
measure.clearHeightMeasure.active();
|
||||||
} else {
|
break;
|
||||||
console.error(`[Engine] Measure type ${mode} not available.`);
|
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();
|
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');
|
console.log('[Engine] Activating first person mode');
|
||||||
this.engine.controlModule.switchFirstPersonMode();
|
this.engine.controlModule.switchFirstPersonMode();
|
||||||
|
this.loadWalkSettings();
|
||||||
this.isWalkModeActive = true;
|
this.isWalkModeActive = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -520,46 +556,55 @@ export class Engine implements IBimComponent {
|
|||||||
this.isWalkModeActive = false;
|
this.isWalkModeActive = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
private static WALK_SPEED_KEY = 'bim-walk-speed';
|
||||||
* 设置漫游移动速度
|
private static WALK_GRAVITY_KEY = 'bim-walk-gravity';
|
||||||
* @param speed 移动速度(默认 0.02)
|
private static WALK_COLLISION_KEY = 'bim-walk-collision';
|
||||||
*/
|
|
||||||
public setWalkSpeed(speed: number): void {
|
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.');
|
console.error('[Engine] Cannot set walk speed: engine not initialized.');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
localStorage.setItem(Engine.WALK_SPEED_KEY, String(speed));
|
||||||
console.log('[Engine] Setting walk speed:', speed);
|
this.engine.controlModule.setMoveSpeed(speed);
|
||||||
this.engine.controlModule.firstPersonControls.moveSpeed = speed;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 设置漫游重力开关
|
|
||||||
* @param enabled 是否启用重力
|
|
||||||
*/
|
|
||||||
public setWalkGravity(enabled: boolean): void {
|
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.');
|
console.error('[Engine] Cannot set walk gravity: engine not initialized.');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
localStorage.setItem(Engine.WALK_GRAVITY_KEY, String(enabled));
|
||||||
console.log('[Engine] Setting walk gravity:', enabled);
|
this.engine.controlModule.setApplyGravity(enabled);
|
||||||
this.engine.controlModule.firstPersonControls.applyGravity = enabled;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 设置漫游碰撞检测开关
|
|
||||||
* @param enabled 是否启用碰撞检测
|
|
||||||
*/
|
|
||||||
public setWalkCollision(enabled: boolean): void {
|
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.');
|
console.error('[Engine] Cannot set walk collision: engine not initialized.');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
localStorage.setItem(Engine.WALK_COLLISION_KEY, String(enabled));
|
||||||
|
this.engine.controlModule.setApplyCollision(enabled);
|
||||||
|
}
|
||||||
|
|
||||||
console.log('[Engine] Setting walk collision:', enabled);
|
private loadWalkSettings(): void {
|
||||||
this.engine.controlModule.firstPersonControls.applyCollision = enabled;
|
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();
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ==================== 结束:构件操作 ====================
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 销毁组件 (接口实现)
|
* 销毁组件 (接口实现)
|
||||||
* 清理资源、取消订阅、销毁引擎实例
|
* 清理资源、取消订阅、销毁引擎实例
|
||||||
|
|||||||
@@ -41,7 +41,11 @@ export const enUS: TranslationDictionary = {
|
|||||||
hideOthers: 'Hide Others',
|
hideOthers: 'Hide Others',
|
||||||
transparentOthers: 'Transparent Others',
|
transparentOthers: 'Transparent Others',
|
||||||
fitSectionBox: 'Fit Section Box',
|
fitSectionBox: 'Fit Section Box',
|
||||||
showAll: 'Show All'
|
showAll: 'Show All',
|
||||||
|
quickSelect: 'Quick Select',
|
||||||
|
selectSameType: 'Select Same Type',
|
||||||
|
selectSameLevel: 'Select Same Level',
|
||||||
|
selectSameLevelType: 'Select Same Level & Type'
|
||||||
},
|
},
|
||||||
tree: {
|
tree: {
|
||||||
searchPlaceholder: 'Please enter content to search',
|
searchPlaceholder: 'Please enter content to search',
|
||||||
@@ -107,15 +111,6 @@ export const enUS: TranslationDictionary = {
|
|||||||
slope: 'Slope:',
|
slope: 'Slope:',
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
units: {
|
|
||||||
mm: 'mm',
|
|
||||||
cm: 'cm',
|
|
||||||
m: 'm',
|
|
||||||
km: 'km',
|
|
||||||
deg: '°',
|
|
||||||
m2: 'm²',
|
|
||||||
percent: '%',
|
|
||||||
},
|
|
||||||
settings: {
|
settings: {
|
||||||
title: 'Settings',
|
title: 'Settings',
|
||||||
unit: 'Unit:',
|
unit: 'Unit:',
|
||||||
@@ -173,11 +168,23 @@ export const enUS: TranslationDictionary = {
|
|||||||
},
|
},
|
||||||
exit: 'Exit',
|
exit: 'Exit',
|
||||||
path: {
|
path: {
|
||||||
dialogTitle: 'Path Walk'
|
dialogTitle: 'Path Roaming',
|
||||||
|
duration: 'Duration',
|
||||||
|
durationUnit: 's',
|
||||||
|
loop: 'Loop',
|
||||||
|
addPoint: 'Add Point',
|
||||||
|
deleteAll: 'Delete All',
|
||||||
|
point: 'Point',
|
||||||
|
play: 'Play',
|
||||||
|
stop: 'Stop',
|
||||||
|
noPoints: 'No points yet'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
map: {
|
info: {
|
||||||
dialogTitle: 'Map'
|
dialogTitle: 'Basic Info',
|
||||||
|
meshCount: 'Mesh Count',
|
||||||
|
totalTriangles: 'Total Triangles',
|
||||||
|
totalVertices: 'Total Vertices',
|
||||||
},
|
},
|
||||||
aiChat: {
|
aiChat: {
|
||||||
title: 'AI Assistant',
|
title: 'AI Assistant',
|
||||||
|
|||||||
@@ -61,6 +61,14 @@ export interface TranslationDictionary {
|
|||||||
transparentOthers: string;
|
transparentOthers: string;
|
||||||
fitSectionBox: string;
|
fitSectionBox: string;
|
||||||
showAll: string;
|
showAll: string;
|
||||||
|
/** 快速选择 */
|
||||||
|
quickSelect: string;
|
||||||
|
/** 选择同类模型 */
|
||||||
|
selectSameType: string;
|
||||||
|
/** 选择同层模型 */
|
||||||
|
selectSameLevel: string;
|
||||||
|
/** 选择同层同类模型 */
|
||||||
|
selectSameLevelType: string;
|
||||||
};
|
};
|
||||||
tree: {
|
tree: {
|
||||||
searchPlaceholder: string;
|
searchPlaceholder: string;
|
||||||
@@ -111,16 +119,6 @@ export interface TranslationDictionary {
|
|||||||
slope: string;
|
slope: string;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
units: {
|
|
||||||
mm: string;
|
|
||||||
cm: string;
|
|
||||||
m: string;
|
|
||||||
km: string;
|
|
||||||
deg: string;
|
|
||||||
m2: string;
|
|
||||||
percent: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 设置面板(单位/精度)
|
* 设置面板(单位/精度)
|
||||||
*/
|
*/
|
||||||
@@ -181,11 +179,33 @@ export interface TranslationDictionary {
|
|||||||
};
|
};
|
||||||
exit: string;
|
exit: string;
|
||||||
path: {
|
path: {
|
||||||
|
/** 对话框标题 */
|
||||||
dialogTitle: string;
|
dialogTitle: string;
|
||||||
|
/** 漫游时间标签 */
|
||||||
|
duration: string;
|
||||||
|
/** 时间单位 */
|
||||||
|
durationUnit: string;
|
||||||
|
/** 循环播放 */
|
||||||
|
loop: string;
|
||||||
|
/** 添加漫游点按钮 */
|
||||||
|
addPoint: string;
|
||||||
|
/** 删除全部按钮 */
|
||||||
|
deleteAll: string;
|
||||||
|
/** 漫游点前缀 */
|
||||||
|
point: string;
|
||||||
|
/** 播放按钮 */
|
||||||
|
play: string;
|
||||||
|
/** 停止按钮 */
|
||||||
|
stop: string;
|
||||||
|
/** 无漫游点提示 */
|
||||||
|
noPoints: string;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
map: {
|
info: {
|
||||||
dialogTitle: string;
|
dialogTitle: string;
|
||||||
|
meshCount: string;
|
||||||
|
totalTriangles: string;
|
||||||
|
totalVertices: string;
|
||||||
};
|
};
|
||||||
aiChat: {
|
aiChat: {
|
||||||
title: string;
|
title: string;
|
||||||
|
|||||||
@@ -41,7 +41,11 @@ export const zhCN: TranslationDictionary = {
|
|||||||
hideOthers: '其他构件隐藏',
|
hideOthers: '其他构件隐藏',
|
||||||
transparentOthers: '其他构件半透明',
|
transparentOthers: '其他构件半透明',
|
||||||
fitSectionBox: '剖切盒适应',
|
fitSectionBox: '剖切盒适应',
|
||||||
showAll: '显示全部'
|
showAll: '显示全部',
|
||||||
|
quickSelect: '快速选择',
|
||||||
|
selectSameType: '选择同类模型',
|
||||||
|
selectSameLevel: '选择同层模型',
|
||||||
|
selectSameLevelType: '选择同层同类模型'
|
||||||
},
|
},
|
||||||
tree: {
|
tree: {
|
||||||
searchPlaceholder: '请输入要搜索的内容',
|
searchPlaceholder: '请输入要搜索的内容',
|
||||||
@@ -107,15 +111,6 @@ export const zhCN: TranslationDictionary = {
|
|||||||
slope: '坡度:',
|
slope: '坡度:',
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
units: {
|
|
||||||
mm: 'mm',
|
|
||||||
cm: 'cm',
|
|
||||||
m: 'm',
|
|
||||||
km: 'km',
|
|
||||||
deg: '°',
|
|
||||||
m2: 'm²',
|
|
||||||
percent: '%',
|
|
||||||
},
|
|
||||||
settings: {
|
settings: {
|
||||||
title: '设置',
|
title: '设置',
|
||||||
unit: '单位:',
|
unit: '单位:',
|
||||||
@@ -173,11 +168,23 @@ export const zhCN: TranslationDictionary = {
|
|||||||
},
|
},
|
||||||
exit: '退出',
|
exit: '退出',
|
||||||
path: {
|
path: {
|
||||||
dialogTitle: '路径漫游'
|
dialogTitle: '路径漫游',
|
||||||
|
duration: '漫游时间',
|
||||||
|
durationUnit: '秒',
|
||||||
|
loop: '循环播放',
|
||||||
|
addPoint: '添加漫游点',
|
||||||
|
deleteAll: '删除全部',
|
||||||
|
point: '漫游点',
|
||||||
|
play: '播放漫游',
|
||||||
|
stop: '停止漫游',
|
||||||
|
noPoints: '暂无漫游点,请添加'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
map: {
|
info: {
|
||||||
dialogTitle: '地图'
|
dialogTitle: '基本信息',
|
||||||
|
meshCount: '构件数量',
|
||||||
|
totalTriangles: '三角面数量',
|
||||||
|
totalVertices: '顶点数量',
|
||||||
},
|
},
|
||||||
aiChat: {
|
aiChat: {
|
||||||
title: 'AI 助手',
|
title: 'AI 助手',
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
* 3D 引擎管理器
|
* 3D 引擎管理器
|
||||||
* 负责管理 3D 渲染引擎的初始化、模型加载和测量功能
|
* 负责管理 3D 渲染引擎的初始化、模型加载和测量功能
|
||||||
*/
|
*/
|
||||||
import { Engine, type EngineOptions, type ModelLoadOptions } from '../components/engine';
|
import { Engine, type EngineOptions, type ModelLoadOptions, type EngineInfo } from '../components/engine';
|
||||||
import { BaseManager } from '../core/base-manager';
|
import { BaseManager } from '../core/base-manager';
|
||||||
import { RightKeyManager } from './right-key-manager';
|
import { RightKeyManager } from './right-key-manager';
|
||||||
import type { MeasureMode } from '../types/measure';
|
import type { MeasureMode } from '../types/measure';
|
||||||
@@ -76,7 +76,7 @@ export class EngineManager extends BaseManager {
|
|||||||
group: 'component',
|
group: 'component',
|
||||||
order: 2,
|
order: 2,
|
||||||
onClick: () => {
|
onClick: () => {
|
||||||
console.log('[Menu] 隐藏选中构件 - 暂未实现');
|
this.hideSelectedModels();
|
||||||
this.rightKey?.hide();
|
this.rightKey?.hide();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -88,7 +88,7 @@ export class EngineManager extends BaseManager {
|
|||||||
group: 'component',
|
group: 'component',
|
||||||
order: 3,
|
order: 3,
|
||||||
onClick: () => {
|
onClick: () => {
|
||||||
console.log('[Menu] 半透明选中构件 - 暂未实现');
|
this.translucentSelectedModels();
|
||||||
this.rightKey?.hide();
|
this.rightKey?.hide();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -105,7 +105,7 @@ export class EngineManager extends BaseManager {
|
|||||||
id: 'hideOthers',
|
id: 'hideOthers',
|
||||||
label: 'menu.hideOthers',
|
label: 'menu.hideOthers',
|
||||||
onClick: () => {
|
onClick: () => {
|
||||||
console.log('[Menu] 隔离 - 其他构件隐藏 - 暂未实现');
|
this.isolateSelectedModels();
|
||||||
this.rightKey?.hide();
|
this.rightKey?.hide();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -113,34 +113,68 @@ export class EngineManager extends BaseManager {
|
|||||||
id: 'transparentOthers',
|
id: 'transparentOthers',
|
||||||
label: 'menu.transparentOthers',
|
label: 'menu.transparentOthers',
|
||||||
onClick: () => {
|
onClick: () => {
|
||||||
console.log('[Menu] 隔离 - 其他构件半透明 - 暂未实现');
|
this.translucentOtherModels();
|
||||||
this.rightKey?.hide();
|
this.rightKey?.hide();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
});
|
});
|
||||||
|
|
||||||
// 5. 剖切盒适应
|
// 5. 快速选择(带子菜单)
|
||||||
|
items.push({
|
||||||
|
id: 'quickSelect',
|
||||||
|
label: 'menu.quickSelect',
|
||||||
|
group: 'component',
|
||||||
|
order: 5,
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
id: 'selectSameType',
|
||||||
|
label: 'menu.selectSameType',
|
||||||
|
onClick: () => {
|
||||||
|
this.batchSelectSameTypeModel();
|
||||||
|
this.rightKey?.hide();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'selectSameLevel',
|
||||||
|
label: 'menu.selectSameLevel',
|
||||||
|
onClick: () => {
|
||||||
|
this.batchSelectSameLevelModel();
|
||||||
|
this.rightKey?.hide();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'selectSameLevelType',
|
||||||
|
label: 'menu.selectSameLevelType',
|
||||||
|
onClick: () => {
|
||||||
|
this.batchSelectSameLevelTypeModel();
|
||||||
|
this.rightKey?.hide();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
});
|
||||||
|
|
||||||
|
// 6. 剖切盒适应
|
||||||
items.push({
|
items.push({
|
||||||
id: 'fitSectionBox',
|
id: 'fitSectionBox',
|
||||||
label: 'menu.fitSectionBox',
|
label: 'menu.fitSectionBox',
|
||||||
group: 'component',
|
group: 'component',
|
||||||
order: 5,
|
order: 6,
|
||||||
onClick: () => {
|
onClick: () => {
|
||||||
console.log('[Menu] 剖切盒适应 - 暂未实现');
|
this.fitSectionBoxToModel();
|
||||||
this.rightKey?.hide();
|
this.rightKey?.hide();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// 6. 显示全部(始终显示)
|
// 7. 显示全部(始终显示)
|
||||||
items.push({
|
items.push({
|
||||||
id: 'showAll',
|
id: 'showAll',
|
||||||
label: 'menu.showAll',
|
label: 'menu.showAll',
|
||||||
group: 'component',
|
group: 'component',
|
||||||
order: 6,
|
order: 7,
|
||||||
onClick: () => {
|
onClick: () => {
|
||||||
console.log('[Menu] 显示全部 - 暂未实现');
|
this.showAllModels();
|
||||||
this.rightKey?.hide();
|
this.rightKey?.hide();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -326,6 +360,13 @@ export class EngineManager extends BaseManager {
|
|||||||
this.engineInstance.recoverSection();
|
this.engineInstance.recoverSection();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public fitSectionBoxToModel(): void {
|
||||||
|
if (!this.engineInstance) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.engineInstance.fitSectionBoxToModel();
|
||||||
|
}
|
||||||
|
|
||||||
/** 激活框选放大功能 */
|
/** 激活框选放大功能 */
|
||||||
public activateZoomBox(): void {
|
public activateZoomBox(): void {
|
||||||
if (!this.engineInstance) {
|
if (!this.engineInstance) {
|
||||||
@@ -354,51 +395,24 @@ export class EngineManager extends BaseManager {
|
|||||||
this.engineInstance.deactivateFirstPersonMode();
|
this.engineInstance.deactivateFirstPersonMode();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 设置漫游移动速度
|
|
||||||
* @param speed 移动速度
|
|
||||||
*/
|
|
||||||
public setWalkSpeed(speed: number): void {
|
public setWalkSpeed(speed: number): void {
|
||||||
if (!this.engineInstance) {
|
this.engineInstance?.setWalkSpeed(speed);
|
||||||
console.warn('[EngineManager] 3D Engine not initialized.');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.engineInstance.setWalkSpeed(speed);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 设置漫游重力开关
|
|
||||||
* @param enabled 是否启用重力
|
|
||||||
*/
|
|
||||||
public setWalkGravity(enabled: boolean): void {
|
public setWalkGravity(enabled: boolean): void {
|
||||||
if (!this.engineInstance) {
|
this.engineInstance?.setWalkGravity(enabled);
|
||||||
console.warn('[EngineManager] 3D Engine not initialized.');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.engineInstance.setWalkGravity(enabled);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 设置漫游碰撞检测开关
|
|
||||||
* @param enabled 是否启用碰撞检测
|
|
||||||
*/
|
|
||||||
public setWalkCollision(enabled: boolean): void {
|
public setWalkCollision(enabled: boolean): void {
|
||||||
if (!this.engineInstance) {
|
this.engineInstance?.setWalkCollision(enabled);
|
||||||
console.warn('[EngineManager] 3D Engine not initialized.');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.engineInstance.setWalkCollision(enabled);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
public toggleMiniMap(): void {
|
||||||
* 获取漫游模式是否激活
|
this.engineInstance?.toggleMiniMap();
|
||||||
* @returns 是否处于漫游模式
|
|
||||||
*/
|
|
||||||
public isFirstPersonModeActive(): boolean {
|
|
||||||
if (!this.engineInstance) {
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
return this.engineInstance.isFirstPersonModeActive();
|
|
||||||
|
public isFirstPersonModeActive(): boolean {
|
||||||
|
return this.engineInstance?.isFirstPersonModeActive() ?? false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ==================== 结束:漫游功能 ====================
|
// ==================== 结束:漫游功能 ====================
|
||||||
@@ -443,8 +457,134 @@ export class EngineManager extends BaseManager {
|
|||||||
return this.engineInstance?.getMajorTreeData() ?? [];
|
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();
|
||||||
|
}
|
||||||
|
|
||||||
|
// ==================== 结束:路径漫游 ====================
|
||||||
|
|
||||||
|
// ==================== 构件操作 ====================
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 隐藏选中构件
|
||||||
|
*/
|
||||||
|
public hideSelectedModels(): void {
|
||||||
|
this.engineInstance?.hideSelectedModels();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 半透明选中构件
|
||||||
|
*/
|
||||||
|
public translucentSelectedModels(): void {
|
||||||
|
this.engineInstance?.translucentSelectedModels();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 隔离选中构件(隐藏其他)
|
||||||
|
*/
|
||||||
|
public isolateSelectedModels(): void {
|
||||||
|
this.engineInstance?.isolateSelectedModels();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 半透明其他构件
|
||||||
|
*/
|
||||||
|
public translucentOtherModels(): void {
|
||||||
|
this.engineInstance?.translucentOtherModels();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 显示所有模型
|
||||||
|
*/
|
||||||
|
public showAllModels(): void {
|
||||||
|
this.engineInstance?.showAllModels();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 批量选择同类模型
|
||||||
|
*/
|
||||||
|
public batchSelectSameTypeModel(): void {
|
||||||
|
this.engineInstance?.batchSelectSameTypeModel();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 批量选择同层模型
|
||||||
|
*/
|
||||||
|
public batchSelectSameLevelModel(): void {
|
||||||
|
this.engineInstance?.batchSelectSameLevelModel();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 批量选择同层同类模型
|
||||||
|
*/
|
||||||
|
public batchSelectSameLevelTypeModel(): void {
|
||||||
|
this.engineInstance?.batchSelectSameLevelTypeModel();
|
||||||
|
}
|
||||||
|
|
||||||
|
// ==================== 结束:构件操作 ====================
|
||||||
|
|
||||||
/** 销毁引擎管理器 */
|
/** 销毁引擎管理器 */
|
||||||
public destroy(): void {
|
public destroy(): void {
|
||||||
if (this.engineInstance) {
|
if (this.engineInstance) {
|
||||||
|
|||||||
Reference in New Issue
Block a user