2026-01-22 15:23:57 +08:00
|
|
|
|
import { BaseDialogManager } from '../core/base-dialog-manager';
|
2025-12-24 19:02:34 +08:00
|
|
|
|
import { SectionBoxPanel } from '../components/section-box-panel';
|
|
|
|
|
|
import type { SectionBoxRange } from '../components/section-box-panel/types';
|
|
|
|
|
|
|
2026-01-22 15:23:57 +08:00
|
|
|
|
export class SectionBoxDialogManager extends BaseDialogManager {
|
2025-12-24 19:02:34 +08:00
|
|
|
|
private panel: SectionBoxPanel | null = null;
|
2026-02-02 18:18:36 +08:00
|
|
|
|
private unsubscribeSectionMove: (() => void) | null = null;
|
2025-12-24 19:02:34 +08:00
|
|
|
|
|
2026-01-22 15:23:57 +08:00
|
|
|
|
/** 对话框唯一标识 */
|
|
|
|
|
|
protected get dialogId(): string {
|
|
|
|
|
|
return 'section-box-dialog';
|
2025-12-24 19:02:34 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-01-22 15:23:57 +08:00
|
|
|
|
/** 对话框标题(国际化 key) */
|
|
|
|
|
|
protected get dialogTitle(): string {
|
|
|
|
|
|
return 'sectionBox.dialogTitle';
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/** 对话框宽度 */
|
|
|
|
|
|
protected get dialogWidth(): number {
|
|
|
|
|
|
return 280;
|
2025-12-24 19:02:34 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
2026-01-22 15:23:57 +08:00
|
|
|
|
* 获取对话框位置
|
|
|
|
|
|
* 定位在容器右下角
|
2025-12-24 19:02:34 +08:00
|
|
|
|
*/
|
2026-01-22 15:23:57 +08:00
|
|
|
|
protected getDialogPosition(): { x: number; y: number } {
|
|
|
|
|
|
const container = this.registry.container;
|
|
|
|
|
|
if (!container) return { x: 100, y: 100 };
|
2025-12-24 19:02:34 +08:00
|
|
|
|
|
2026-01-22 15:23:57 +08:00
|
|
|
|
const containerWidth = container.clientWidth;
|
|
|
|
|
|
const containerHeight = container.clientHeight;
|
|
|
|
|
|
const paddingRight = 20;
|
|
|
|
|
|
const paddingBottom = 50;
|
2025-12-24 19:02:34 +08:00
|
|
|
|
|
2026-01-22 15:23:57 +08:00
|
|
|
|
return {
|
|
|
|
|
|
x: containerWidth - this.dialogWidth - paddingRight,
|
|
|
|
|
|
y: containerHeight - paddingBottom - 300
|
|
|
|
|
|
};
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 创建对话框内容
|
|
|
|
|
|
* 初始化剖切盒面板并设置回调
|
|
|
|
|
|
*/
|
|
|
|
|
|
protected createContent(): HTMLElement {
|
2025-12-24 19:02:34 +08:00
|
|
|
|
this.panel = new SectionBoxPanel({
|
|
|
|
|
|
defaultHidden: false,
|
|
|
|
|
|
defaultReversed: false,
|
|
|
|
|
|
onHideToggle: (isHidden) => {
|
2026-02-02 16:36:17 +08:00
|
|
|
|
console.log('[SectionBoxDialogManager] 隐藏切换:', isHidden);
|
|
|
|
|
|
if (isHidden) {
|
|
|
|
|
|
this.registry.engine3d?.hideSection();
|
|
|
|
|
|
} else {
|
|
|
|
|
|
this.registry.engine3d?.recoverSection();
|
|
|
|
|
|
}
|
2025-12-24 19:02:34 +08:00
|
|
|
|
},
|
|
|
|
|
|
onReverseToggle: (isReversed) => {
|
2026-02-04 18:20:30 +08:00
|
|
|
|
console.log('[SectionBoxDialogManager] 反向切换:', isReversed);
|
|
|
|
|
|
// 底层 reverse() 为“切换一次”,这里不使用 isReversed 作为入参,只要用户点击就触发。
|
|
|
|
|
|
this.registry.engine3d?.reverseSection();
|
2025-12-24 19:02:34 +08:00
|
|
|
|
},
|
|
|
|
|
|
onFitToModel: () => {
|
2026-02-04 18:20:30 +08:00
|
|
|
|
// 对接底层 scaleBox():缩放剖切盒到场景整体包围盒
|
|
|
|
|
|
this.registry.engine3d?.scaleSectionBox();
|
2025-12-24 19:02:34 +08:00
|
|
|
|
},
|
|
|
|
|
|
onReset: () => {
|
2026-02-04 18:20:30 +08:00
|
|
|
|
// 重置定义:关闭剖切再打开剖切盒。
|
|
|
|
|
|
// UI 侧会自行将滑块强制恢复到 0-100,并将隐藏/反向按钮恢复为关闭状态。
|
|
|
|
|
|
this.registry.engine3d?.deactivateSection();
|
|
|
|
|
|
this.registry.engine3d?.activeSection('box');
|
|
|
|
|
|
// 确保剖切可见(避免上一次处于隐藏状态导致“看起来没重置”)
|
|
|
|
|
|
this.registry.engine3d?.recoverSection();
|
2025-12-24 19:02:34 +08:00
|
|
|
|
},
|
|
|
|
|
|
onRangeChange: (range) => {
|
2026-01-28 12:00:55 +08:00
|
|
|
|
this.registry.engine3d?.setSectionBoxRange(range);
|
2025-12-24 19:02:34 +08:00
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
this.panel.init();
|
2026-01-22 15:23:57 +08:00
|
|
|
|
return this.panel.element;
|
|
|
|
|
|
}
|
2025-12-24 19:02:34 +08:00
|
|
|
|
|
2026-01-22 15:23:57 +08:00
|
|
|
|
protected onDialogCreated(): void {
|
2026-02-02 16:25:32 +08:00
|
|
|
|
this.registry.engine3d?.activeSection('box');
|
2026-01-22 15:23:57 +08:00
|
|
|
|
this.dialog?.fitHeight(false);
|
2026-02-02 18:18:36 +08:00
|
|
|
|
|
|
|
|
|
|
const engine = this.registry.engine3d?.getEngine();
|
|
|
|
|
|
if (engine?.events) {
|
|
|
|
|
|
const handler = (data: any) => {
|
|
|
|
|
|
if (data && this.panel) {
|
|
|
|
|
|
this.panel.setRange(data as Partial<SectionBoxRange>);
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
engine.events.on('section-move', handler);
|
|
|
|
|
|
this.unsubscribeSectionMove = () => engine.events.off('section-move', handler);
|
|
|
|
|
|
}
|
2026-01-22 15:23:57 +08:00
|
|
|
|
}
|
2025-12-24 19:02:34 +08:00
|
|
|
|
|
2026-01-22 15:23:57 +08:00
|
|
|
|
protected onDialogClose(): void {
|
2026-02-02 18:18:36 +08:00
|
|
|
|
if (this.unsubscribeSectionMove) {
|
|
|
|
|
|
this.unsubscribeSectionMove();
|
|
|
|
|
|
this.unsubscribeSectionMove = null;
|
|
|
|
|
|
}
|
2026-01-22 15:23:57 +08:00
|
|
|
|
this.registry.toolbar?.setBtnActive('section-box', false);
|
2025-12-24 19:02:34 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-01-22 15:23:57 +08:00
|
|
|
|
protected onBeforeDestroy(): void {
|
2026-02-02 18:18:36 +08:00
|
|
|
|
if (this.unsubscribeSectionMove) {
|
|
|
|
|
|
this.unsubscribeSectionMove();
|
|
|
|
|
|
this.unsubscribeSectionMove = null;
|
|
|
|
|
|
}
|
2026-02-02 16:25:32 +08:00
|
|
|
|
this.registry.engine3d?.deactivateSection();
|
2026-01-22 15:23:57 +08:00
|
|
|
|
if (this.panel) {
|
|
|
|
|
|
this.panel.destroy();
|
|
|
|
|
|
this.panel = null;
|
|
|
|
|
|
}
|
2025-12-24 19:02:34 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
2026-01-22 15:23:57 +08:00
|
|
|
|
* 获取剖切盒隐藏状态
|
|
|
|
|
|
* @returns 是否隐藏
|
2025-12-24 19:02:34 +08:00
|
|
|
|
*/
|
|
|
|
|
|
public getHiddenState(): boolean {
|
|
|
|
|
|
return this.panel?.getHiddenState() ?? false;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
2026-01-22 15:23:57 +08:00
|
|
|
|
* 设置剖切盒隐藏状态
|
|
|
|
|
|
* @param isHidden 是否隐藏
|
2025-12-24 19:02:34 +08:00
|
|
|
|
*/
|
|
|
|
|
|
public setHiddenState(isHidden: boolean): void {
|
|
|
|
|
|
this.panel?.setHiddenState(isHidden);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
2026-01-22 15:23:57 +08:00
|
|
|
|
* 获取剖切盒反向状态
|
|
|
|
|
|
* @returns 是否反向(显示盒内/盒外)
|
2025-12-24 19:02:34 +08:00
|
|
|
|
*/
|
|
|
|
|
|
public getReversedState(): boolean {
|
|
|
|
|
|
return this.panel?.getReversedState() ?? false;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
2026-01-22 15:23:57 +08:00
|
|
|
|
* 设置剖切盒反向状态
|
|
|
|
|
|
* @param isReversed 是否反向
|
2025-12-24 19:02:34 +08:00
|
|
|
|
*/
|
|
|
|
|
|
public setReversedState(isReversed: boolean): void {
|
|
|
|
|
|
this.panel?.setReversedState(isReversed);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
2026-01-22 15:23:57 +08:00
|
|
|
|
* 获取剖切盒范围
|
|
|
|
|
|
* @returns 六面体范围 { minX, maxX, minY, maxY, minZ, maxZ }
|
2025-12-24 19:02:34 +08:00
|
|
|
|
*/
|
|
|
|
|
|
public getRange(): SectionBoxRange | null {
|
|
|
|
|
|
return this.panel?.getRange() ?? null;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
2026-01-22 15:23:57 +08:00
|
|
|
|
* 设置剖切盒范围
|
|
|
|
|
|
* @param range 部分或全部范围值
|
2025-12-24 19:02:34 +08:00
|
|
|
|
*/
|
|
|
|
|
|
public setRange(range: Partial<SectionBoxRange>): void {
|
|
|
|
|
|
this.panel?.setRange(range);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|