|
@@ -5,6 +5,7 @@ import DARAMeasurementTool from '@/components/measures/DARAMeasurementTool';
|
|
|
import HipDIMeasurementTool from '@/components/measures/HipDIMeasurementTool';
|
|
|
import HipNHAAngleMeasurementTool from '@/components/measures/HipNHAAngleMeasurementTool';
|
|
|
import VHSMeasurementTool from '@/components/measures/VHSMeasurementTool';
|
|
|
+import TPLOMeasurementTool from '@/components/measures/TPLOMeasurementTool';
|
|
|
|
|
|
const {
|
|
|
ToolGroupManager,
|
|
@@ -1745,4 +1746,275 @@ export class MeasurementToolManager {
|
|
|
this.clearVHSMeasurements(viewportId)
|
|
|
);
|
|
|
}
|
|
|
+
|
|
|
+ // ==================== TPLO测量工具 ====================
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 激活TPLO测量工具
|
|
|
+ */
|
|
|
+ static activateTPLOMeasurementTool(viewportId: string): boolean {
|
|
|
+ const toolGroup = this.getToolGroup(viewportId);
|
|
|
+ if (!toolGroup) return false;
|
|
|
+
|
|
|
+ try {
|
|
|
+ // 停用其他可能冲突的工具
|
|
|
+ toolGroup.setToolPassive(WindowLevelTool.toolName, {
|
|
|
+ removeAllBindings: true,
|
|
|
+ });
|
|
|
+ toolGroup.setToolPassive(MagnifyTool.toolName, {
|
|
|
+ removeAllBindings: true,
|
|
|
+ });
|
|
|
+ toolGroup.setToolPassive(LengthTool.toolName, {
|
|
|
+ removeAllBindings: true,
|
|
|
+ });
|
|
|
+ toolGroup.setToolPassive(AngleTool.toolName, {
|
|
|
+ removeAllBindings: true,
|
|
|
+ });
|
|
|
+ toolGroup.setToolPassive(TibialPlateauAngleTool.toolName, {
|
|
|
+ removeAllBindings: true,
|
|
|
+ });
|
|
|
+ toolGroup.setToolPassive(DARAMeasurementTool.toolName, {
|
|
|
+ removeAllBindings: true,
|
|
|
+ });
|
|
|
+ toolGroup.setToolPassive(HipDIMeasurementTool.toolName, {
|
|
|
+ removeAllBindings: true,
|
|
|
+ });
|
|
|
+ toolGroup.setToolPassive(HipNHAAngleMeasurementTool.toolName, {
|
|
|
+ removeAllBindings: true,
|
|
|
+ });
|
|
|
+ toolGroup.setToolPassive(VHSMeasurementTool.toolName, {
|
|
|
+ removeAllBindings: true,
|
|
|
+ });
|
|
|
+
|
|
|
+ // 激活TPLO测量工具
|
|
|
+ toolGroup.setToolActive(TPLOMeasurementTool.toolName, {
|
|
|
+ bindings: [{ mouseButton: MouseBindings.Primary }],
|
|
|
+ });
|
|
|
+
|
|
|
+ // 获取工具实例并激活修改模式
|
|
|
+ const toolInstance = toolGroup.getToolInstance(
|
|
|
+ TPLOMeasurementTool.toolName
|
|
|
+ ) as TPLOMeasurementTool;
|
|
|
+
|
|
|
+ const viewport = cornerstone.getEnabledElementByViewportId(viewportId)?.viewport;
|
|
|
+ if (toolInstance && viewport.element) {
|
|
|
+ toolInstance._activateModify(viewport.element);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 自动创建一个预设的注解
|
|
|
+ try {
|
|
|
+ if (viewport && viewport.element) {
|
|
|
+ // 创建预设注解
|
|
|
+ const defaultAnnotation = TPLOMeasurementTool.createDefaultAnnotation(
|
|
|
+ viewport.element as HTMLDivElement,
|
|
|
+ viewport as cornerstone.Types.IStackViewport
|
|
|
+ );
|
|
|
+
|
|
|
+ // 添加注解到状态管理
|
|
|
+ cornerstoneTools.annotation.state.addAnnotation(
|
|
|
+ defaultAnnotation,
|
|
|
+ viewport.element
|
|
|
+ );
|
|
|
+
|
|
|
+ // 获取工具实例并更新缓存统计数据
|
|
|
+ const enabledElement = cornerstone.getEnabledElement(viewport.element);
|
|
|
+ if (enabledElement) {
|
|
|
+ const toolInstance = toolGroup.getToolInstance(
|
|
|
+ TPLOMeasurementTool.toolName
|
|
|
+ ) as TPLOMeasurementTool;
|
|
|
+
|
|
|
+ if (toolInstance && '_updateCachedStats' in toolInstance) {
|
|
|
+ (toolInstance as any)._updateCachedStats(defaultAnnotation, enabledElement);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 触发渲染更新
|
|
|
+ viewport.render();
|
|
|
+
|
|
|
+ console.log('[MeasurementToolManager] Default TPLO annotation created successfully');
|
|
|
+ }
|
|
|
+ } catch (error) {
|
|
|
+ console.error('[MeasurementToolManager] Failed to create default TPLO annotation:', error);
|
|
|
+ // 注解创建失败不影响工具激活
|
|
|
+ }
|
|
|
+
|
|
|
+ console.log(
|
|
|
+ `[MeasurementToolManager] TPLO tool activated for viewport: ${viewportId}`
|
|
|
+ );
|
|
|
+ return true;
|
|
|
+ } catch (error) {
|
|
|
+ console.error(
|
|
|
+ `[MeasurementToolManager] Error activating TPLO tool:`,
|
|
|
+ error
|
|
|
+ );
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 停用TPLO测量工具
|
|
|
+ */
|
|
|
+ static deactivateTPLOMeasurementTool(viewportId: string): boolean {
|
|
|
+ const toolGroup = this.getToolGroup(viewportId);
|
|
|
+ if (!toolGroup) return false;
|
|
|
+
|
|
|
+ try {
|
|
|
+ toolGroup.setToolPassive(TPLOMeasurementTool.toolName, {
|
|
|
+ removeAllBindings: true,
|
|
|
+ });
|
|
|
+ console.log(
|
|
|
+ `[MeasurementToolManager] TPLO tool deactivated for viewport: ${viewportId}`
|
|
|
+ );
|
|
|
+ return true;
|
|
|
+ } catch (error) {
|
|
|
+ console.error(
|
|
|
+ `[MeasurementToolManager] Error deactivating TPLO tool:`,
|
|
|
+ error
|
|
|
+ );
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 检查TPLO测量工具是否处于激活状态
|
|
|
+ */
|
|
|
+ static isTPLOMeasurementToolActive(viewportId: string): boolean {
|
|
|
+ const toolGroup = this.getToolGroup(viewportId);
|
|
|
+ if (!toolGroup) return false;
|
|
|
+
|
|
|
+ try {
|
|
|
+ const activeTool = toolGroup.getActivePrimaryMouseButtonTool();
|
|
|
+ return activeTool === TPLOMeasurementTool.toolName;
|
|
|
+ } catch (error) {
|
|
|
+ console.error(
|
|
|
+ `[MeasurementToolManager] Error checking TPLO tool state:`,
|
|
|
+ error
|
|
|
+ );
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 切换TPLO测量工具状态
|
|
|
+ */
|
|
|
+ static toggleTPLOMeasurementTool(viewportId: string): boolean {
|
|
|
+ const isActive = this.isTPLOMeasurementToolActive(viewportId);
|
|
|
+
|
|
|
+ if (isActive) {
|
|
|
+ return this.deactivateTPLOMeasurementTool(viewportId);
|
|
|
+ } else {
|
|
|
+ return this.activateTPLOMeasurementTool(viewportId);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 清除指定 viewport 的所有TPLO测量标注
|
|
|
+ */
|
|
|
+ static clearTPLOMeasurements(viewportId: string): boolean {
|
|
|
+ try {
|
|
|
+ const viewport =
|
|
|
+ cornerstone.getEnabledElementByViewportId(viewportId)?.viewport;
|
|
|
+ if (!viewport) {
|
|
|
+ console.warn(
|
|
|
+ `[MeasurementToolManager] Viewport not found: ${viewportId}`
|
|
|
+ );
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ const annotations = cornerstoneTools.annotation.state.getAnnotations(
|
|
|
+ TPLOMeasurementTool.toolName,
|
|
|
+ viewport.element
|
|
|
+ );
|
|
|
+
|
|
|
+ let removedCount = 0;
|
|
|
+ annotations.forEach((annotation) => {
|
|
|
+ if (annotation.annotationUID) {
|
|
|
+ cornerstoneTools.annotation.state.removeAnnotation(
|
|
|
+ annotation.annotationUID
|
|
|
+ );
|
|
|
+ removedCount++;
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ viewport.render();
|
|
|
+ console.log(
|
|
|
+ `[MeasurementToolManager] Cleared ${removedCount} TPLO measurements for viewport: ${viewportId}`
|
|
|
+ );
|
|
|
+ return true;
|
|
|
+ } catch (error) {
|
|
|
+ console.error(
|
|
|
+ `[MeasurementToolManager] Error clearing TPLO measurements:`,
|
|
|
+ error
|
|
|
+ );
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 获取指定 viewport 的所有TPLO测量结果
|
|
|
+ */
|
|
|
+ // eslint-disable-next-line
|
|
|
+ static getTPLOMeasurements(viewportId: string): any[] {
|
|
|
+ try {
|
|
|
+ const viewport =
|
|
|
+ cornerstone.getEnabledElementByViewportId(viewportId)?.viewport;
|
|
|
+ if (!viewport) {
|
|
|
+ console.warn(
|
|
|
+ `[MeasurementToolManager] Viewport not found: ${viewportId}`
|
|
|
+ );
|
|
|
+ return [];
|
|
|
+ }
|
|
|
+
|
|
|
+ const annotations = cornerstoneTools.annotation.state.getAnnotations(
|
|
|
+ TPLOMeasurementTool.toolName,
|
|
|
+ viewport.element
|
|
|
+ );
|
|
|
+
|
|
|
+ return annotations.map((annotation) => ({
|
|
|
+ annotationUID: annotation.annotationUID,
|
|
|
+ tpa: annotation.data?.cachedStats?.tpa || 0,
|
|
|
+ sawRadiusPx: annotation.data?.cachedStats?.sawRadiusPx || 0,
|
|
|
+ sawRadiusMm: annotation.data?.cachedStats?.sawRadiusMm || 0,
|
|
|
+ unit: 'mixed',
|
|
|
+ points: annotation.data?.handles?.points || [],
|
|
|
+ }));
|
|
|
+ } catch (error) {
|
|
|
+ console.error(
|
|
|
+ `[MeasurementToolManager] Error getting TPLO measurements:`,
|
|
|
+ error
|
|
|
+ );
|
|
|
+ return [];
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 为多个 viewport 批量激活TPLO测量工具
|
|
|
+ */
|
|
|
+ static activateTPLOMeasurementToolForViewports(
|
|
|
+ viewportIds: string[]
|
|
|
+ ): boolean[] {
|
|
|
+ return viewportIds.map((viewportId) =>
|
|
|
+ this.activateTPLOMeasurementTool(viewportId)
|
|
|
+ );
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 为多个 viewport 批量停用TPLO测量工具
|
|
|
+ */
|
|
|
+ static deactivateTPLOMeasurementToolForViewports(
|
|
|
+ viewportIds: string[]
|
|
|
+ ): boolean[] {
|
|
|
+ return viewportIds.map((viewportId) =>
|
|
|
+ this.deactivateTPLOMeasurementTool(viewportId)
|
|
|
+ );
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 为多个 viewport 批量清除TPLO测量
|
|
|
+ */
|
|
|
+ static clearTPLOMeasurementsForViewports(viewportIds: string[]): boolean[] {
|
|
|
+ return viewportIds.map((viewportId) =>
|
|
|
+ this.clearTPLOMeasurements(viewportId)
|
|
|
+ );
|
|
|
+ }
|
|
|
}
|