import * as cornerstone from '@cornerstonejs/core'; import * as cornerstoneTools from '@cornerstonejs/tools'; import TibialPlateauAngleTool from '@/components/measures/TibialPlateauAngleTool'; 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'; import TTAMeasurementTool from '@/components/measures/TTAMeasurementTool'; import CBLOMeasurementTool from '@/components/measures/CBLOMeasurementTool'; import HipCoverageMeasurementTool from '@/components/measures/HipCoverageMeasurementTool'; import HipDorsalCoverageTool from '@/components/measures/HipDorsalCoverageTool'; import CircleCenterMeasurementTool from '@/components/measures/CircleCenterMeasurementTool'; import MidlineMeasurementTool from '@/components/measures/MidlineMeasurementTool'; import FindMidpointMeasurementTool from '@/components/measures/FindMidpointMeasurementTool'; import VerticalTiltMeasurementTool from '@/components/measures/VerticalTiltMeasurementTool'; import HorizontalTiltMeasurementTool from '@/components/measures/HorizontalTiltMeasurementTool'; import PolygonLengthMeasurementTool from '@/components/measures/PolygonLengthMeasurementTool'; import PolylineLengthMeasurementTool from '@/components/measures/PolylineLengthMeasurementTool'; import LineGrayscaleMeasurementTool from '@/components/measures/LineGrayscaleMeasurementTool'; import RectangleGrayscaleMeasurementTool from '@/components/measures/RectangleGrayscaleMeasurementTool'; const { ToolGroupManager, LengthTool, AngleTool, WindowLevelTool, MagnifyTool, Enums: csToolsEnums, } = cornerstoneTools; const { MouseBindings } = csToolsEnums; /** * 测量工具管理器 * 统一管理所有测量相关的工具操作 */ export class MeasurementToolManager { /** * 根据 viewportId 获取对应的工具组 */ static getToolGroup( viewportId: string ): cornerstoneTools.Types.IToolGroup | undefined { const toolGroupId = `STACK_TOOL_GROUP_ID_${viewportId}`; const toolGroup = ToolGroupManager.getToolGroup(toolGroupId); if (!toolGroup) { console.warn( `[MeasurementToolManager] Tool group not found for viewport: ${viewportId}` ); } return toolGroup; } /** * 激活线段测量工具 */ static activateLengthTool(viewportId: string): boolean { const toolGroup = MeasurementToolManager.getToolGroup(viewportId); if (!toolGroup) return false; try { // 停用其他可能冲突的工具 toolGroup.setToolPassive(WindowLevelTool.toolName, { removeAllBindings: true, }); toolGroup.setToolPassive(MagnifyTool.toolName, { removeAllBindings: true, }); // 激活线段测量工具 toolGroup.setToolActive(LengthTool.toolName, { bindings: [{ mouseButton: MouseBindings.Primary }], }); console.log( `[MeasurementToolManager] Length tool activated for viewport: ${viewportId}` ); return true; } catch (error) { console.error( `[MeasurementToolManager] Error activating length tool:`, error ); return false; } } /** * 停用线段测量工具 */ static deactivateLengthTool(viewportId: string): boolean { const toolGroup = MeasurementToolManager.getToolGroup(viewportId); if (!toolGroup) return false; try { toolGroup.setToolPassive(LengthTool.toolName, { removeAllBindings: true, }); console.log( `[MeasurementToolManager] Length tool deactivated for viewport: ${viewportId}` ); return true; } catch (error) { console.error( `[MeasurementToolManager] Error deactivating length tool:`, error ); return false; } } /** * 检查线段测量工具是否处于激活状态 */ static isLengthToolActive(viewportId: string): boolean { const toolGroup = MeasurementToolManager.getToolGroup(viewportId); if (!toolGroup) return false; try { const activeTool = toolGroup.getActivePrimaryMouseButtonTool(); return activeTool === LengthTool.toolName; } catch (error) { console.error( `[MeasurementToolManager] Error checking tool state:`, error ); return false; } } /** * 切换线段测量工具状态 */ static toggleLengthTool(viewportId: string): boolean { const isActive = this.isLengthToolActive(viewportId); if (isActive) { return this.deactivateLengthTool(viewportId); } else { return this.activateLengthTool(viewportId); } } /** * 激活角度测量工具 */ static activateAngleTool(viewportId: string): boolean { const toolGroup = MeasurementToolManager.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.setToolActive(AngleTool.toolName, { bindings: [{ mouseButton: MouseBindings.Primary }], }); console.log( `[MeasurementToolManager] Angle tool activated for viewport: ${viewportId}` ); return true; } catch (error) { console.error( `[MeasurementToolManager] Error activating angle tool:`, error ); return false; } } /** * 停用角度测量工具 */ static deactivateAngleTool(viewportId: string): boolean { const toolGroup = MeasurementToolManager.getToolGroup(viewportId); if (!toolGroup) return false; try { toolGroup.setToolPassive(AngleTool.toolName, { removeAllBindings: true, }); console.log( `[MeasurementToolManager] Angle tool deactivated for viewport: ${viewportId}` ); return true; } catch (error) { console.error( `[MeasurementToolManager] Error deactivating angle tool:`, error ); return false; } } /** * 清除指定 viewport 的所有线段测量标注 */ static clearLengthMeasurements(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( LengthTool.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} length measurements for viewport: ${viewportId}` ); return true; } catch (error) { console.error( `[MeasurementToolManager] Error clearing measurements:`, error ); return false; } } /** * 获取指定 viewport 的所有线段测量结果 */ // eslint-disable-next-line static getLengthMeasurements(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( LengthTool.toolName, viewport.element ); return annotations.map((annotation) => ({ annotationUID: annotation.annotationUID, length: annotation.data?.cachedStats?.length || 0, unit: annotation.data?.cachedStats?.unit || 'mm', points: annotation.data?.handles?.points || [], })); } catch (error) { console.error( `[MeasurementToolManager] Error getting measurements:`, error ); return []; } } /** * 为多个 viewport 批量激活线段测量工具 */ static activateLengthToolForViewports(viewportIds: string[]): boolean[] { return viewportIds.map((viewportId) => this.activateLengthTool(viewportId)); } /** * 为多个 viewport 批量停用线段测量工具 */ static deactivateLengthToolForViewports(viewportIds: string[]): boolean[] { return viewportIds.map((viewportId) => this.deactivateLengthTool(viewportId) ); } /** * 为多个 viewport 批量清除线段测量 */ static clearLengthMeasurementsForViewports(viewportIds: string[]): boolean[] { return viewportIds.map((viewportId) => this.clearLengthMeasurements(viewportId) ); } /** * 检查角度测量工具是否处于激活状态 */ static isAngleToolActive(viewportId: string): boolean { const toolGroup = MeasurementToolManager.getToolGroup(viewportId); if (!toolGroup) return false; try { const activeTool = toolGroup.getActivePrimaryMouseButtonTool(); return activeTool === AngleTool.toolName; } catch (error) { console.error( `[MeasurementToolManager] Error checking angle tool state:`, error ); return false; } } /** * 切换角度测量工具状态 */ static toggleAngleTool(viewportId: string): boolean { const isActive = this.isAngleToolActive(viewportId); if (isActive) { return this.deactivateAngleTool(viewportId); } else { return this.activateAngleTool(viewportId); } } /** * 清除指定 viewport 的所有角度测量标注 */ static clearAngleMeasurements(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( AngleTool.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} angle measurements for viewport: ${viewportId}` ); return true; } catch (error) { console.error( `[MeasurementToolManager] Error clearing angle measurements:`, error ); return false; } } /** * 获取指定 viewport 的所有角度测量结果 */ // eslint-disable-next-line static getAngleMeasurements(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( AngleTool.toolName, viewport.element ); return annotations.map((annotation) => ({ annotationUID: annotation.annotationUID, angle: annotation.data?.cachedStats?.angle || 0, unit: annotation.data?.cachedStats?.unit || 'degrees', points: annotation.data?.handles?.points || [], })); } catch (error) { console.error( `[MeasurementToolManager] Error getting angle measurements:`, error ); return []; } } /** * 为多个 viewport 批量激活角度测量工具 */ static activateAngleToolForViewports(viewportIds: string[]): boolean[] { return viewportIds.map((viewportId) => this.activateAngleTool(viewportId)); } /** * 为多个 viewport 批量停用角度测量工具 */ static deactivateAngleToolForViewports(viewportIds: string[]): boolean[] { return viewportIds.map((viewportId) => this.deactivateAngleTool(viewportId) ); } /** * 为多个 viewport 批量清除角度测量 */ static clearAngleMeasurementsForViewports(viewportIds: string[]): boolean[] { return viewportIds.map((viewportId) => this.clearAngleMeasurements(viewportId) ); } // ==================== 胫骨平台夹角测量工具 ==================== /** * 激活胫骨平台夹角测量工具 */ static activateTibialPlateauAngleTool(viewportId: string): boolean { const toolGroup = MeasurementToolManager.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.setToolActive(TibialPlateauAngleTool.toolName, { bindings: [{ mouseButton: MouseBindings.Primary }], }); // 获取工具实例并激活修改模式 const toolInstance = toolGroup.getToolInstance( TibialPlateauAngleTool.toolName ) as TibialPlateauAngleTool; // 使用参数中的 viewportId,而不是硬编码 const viewport = cornerstone.getEnabledElementByViewportId(viewportId)?.viewport; if (toolInstance && viewport.element) { toolInstance._activateModify(viewport.element); } // 自动创建一个预设的注解 try { if (viewport && viewport.element) { // 创建预设注解 const defaultAnnotation = TibialPlateauAngleTool.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( TibialPlateauAngleTool.toolName ) as TibialPlateauAngleTool; if (toolInstance && '_updateCachedStats' in toolInstance) { (toolInstance as any)._updateCachedStats(defaultAnnotation, enabledElement); } } // 触发渲染更新 // 触发渲染更新 const viewportIdsToRender = cornerstoneTools.utilities.viewportFilters.getViewportIdsWithToolToRender( viewport.element, TibialPlateauAngleTool.toolName ); cornerstoneTools.utilities.triggerAnnotationRenderForViewportIds( viewportIdsToRender ); console.log('[MeasurementToolManager] Default TPA annotation created successfully'); } } catch (error) { console.error('[MeasurementToolManager] Failed to create default annotation:', error); // 注解创建失败不影响工具激活 } console.log( `[MeasurementToolManager] TibialPlateauAngle tool activated for viewport: ${viewportId}` ); return true; } catch (error) { console.error( `[MeasurementToolManager] Error activating TibialPlateauAngle tool:`, error ); return false; } } /** * 停用胫骨平台夹角测量工具 */ static deactivateTibialPlateauAngleTool(viewportId: string): boolean { const toolGroup = MeasurementToolManager.getToolGroup(viewportId); if (!toolGroup) return false; try { toolGroup.setToolPassive(TibialPlateauAngleTool.toolName, { removeAllBindings: true, }); console.log( `[MeasurementToolManager] TibialPlateauAngle tool deactivated for viewport: ${viewportId}` ); return true; } catch (error) { console.error( `[MeasurementToolManager] Error deactivating TibialPlateauAngle tool:`, error ); return false; } } /** * 检查胫骨平台夹角测量工具是否处于激活状态 */ static isTibialPlateauAngleToolActive(viewportId: string): boolean { const toolGroup = MeasurementToolManager.getToolGroup(viewportId); if (!toolGroup) return false; try { const activeTool = toolGroup.getActivePrimaryMouseButtonTool(); return activeTool === TibialPlateauAngleTool.toolName; } catch (error) { console.error( `[MeasurementToolManager] Error checking TibialPlateauAngle tool state:`, error ); return false; } } /** * 切换胫骨平台夹角测量工具状态 */ static toggleTibialPlateauAngleTool(viewportId: string): boolean { const isActive = this.isTibialPlateauAngleToolActive(viewportId); if (isActive) { return this.deactivateTibialPlateauAngleTool(viewportId); } else { return this.activateTibialPlateauAngleTool(viewportId); } } /** * 清除指定 viewport 的所有胫骨平台夹角测量标注 */ static clearTibialPlateauAngleMeasurements(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( TibialPlateauAngleTool.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} TibialPlateauAngle measurements for viewport: ${viewportId}` ); return true; } catch (error) { console.error( `[MeasurementToolManager] Error clearing TibialPlateauAngle measurements:`, error ); return false; } } /** * 获取指定 viewport 的所有胫骨平台夹角测量结果 */ // eslint-disable-next-line static getTibialPlateauAngleMeasurements(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( TibialPlateauAngleTool.toolName, viewport.element ); return annotations.map((annotation) => ({ annotationUID: annotation.annotationUID, TPA: annotation.data?.cachedStats?.TPA || 0, unit: 'degrees', points: annotation.data?.handles?.points || [], })); } catch (error) { console.error( `[MeasurementToolManager] Error getting TibialPlateauAngle measurements:`, error ); return []; } } /** * 为多个 viewport 批量激活胫骨平台夹角测量工具 */ static activateTibialPlateauAngleToolForViewports( viewportIds: string[] ): boolean[] { return viewportIds.map((viewportId) => this.activateTibialPlateauAngleTool(viewportId) ); } /** * 为多个 viewport 批量停用胫骨平台夹角测量工具 */ static deactivateTibialPlateauAngleToolForViewports( viewportIds: string[] ): boolean[] { return viewportIds.map((viewportId) => this.deactivateTibialPlateauAngleTool(viewportId) ); } /** * 为多个 viewport 批量清除胫骨平台夹角测量 */ static clearTibialPlateauAngleMeasurementsForViewports( viewportIds: string[] ): boolean[] { return viewportIds.map((viewportId) => this.clearTibialPlateauAngleMeasurements(viewportId) ); } // ==================== 髋臼水平角测量工具 ==================== /** * 激活髋臼水平角测量工具 */ static activateDARAMeasurementTool(viewportId: string): boolean { const toolGroup = MeasurementToolManager.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.setToolActive(DARAMeasurementTool.toolName, { bindings: [{ mouseButton: MouseBindings.Primary }], }); // 获取工具实例并激活修改模式 const toolInstance = toolGroup.getToolInstance( DARAMeasurementTool.toolName ) as DARAMeasurementTool; // 使用参数中的 viewportId,而不是硬编码 const viewport = cornerstone.getEnabledElementByViewportId(viewportId)?.viewport; if (toolInstance && viewport.element) { toolInstance._activateModify(viewport.element); } // 自动创建一个预设的注解 try { const viewport = cornerstone.getEnabledElementByViewportId(viewportId)?.viewport; if (viewport && viewport.element) { // 创建预设注解 const defaultAnnotation = DARAMeasurementTool.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( DARAMeasurementTool.toolName ) as DARAMeasurementTool; if (toolInstance && '_updateCachedStats' in toolInstance) { (toolInstance as any)._updateCachedStats(defaultAnnotation, enabledElement); } } // 触发渲染更新 viewport.render(); console.log('[MeasurementToolManager] Default DARA annotation created successfully'); } } catch (error) { console.error('[MeasurementToolManager] Failed to create default DARA annotation:', error); // 注解创建失败不影响工具激活 } console.log( `[MeasurementToolManager] DARA tool activated for viewport: ${viewportId}` ); return true; } catch (error) { console.error( `[MeasurementToolManager] Error activating DARA tool:`, error ); return false; } } /** * 停用髋臼水平角测量工具 */ static deactivateDARAMeasurementTool(viewportId: string): boolean { const toolGroup = MeasurementToolManager.getToolGroup(viewportId); if (!toolGroup) return false; try { toolGroup.setToolPassive(DARAMeasurementTool.toolName, { removeAllBindings: true, }); console.log( `[MeasurementToolManager] DARA tool deactivated for viewport: ${viewportId}` ); return true; } catch (error) { console.error( `[MeasurementToolManager] Error deactivating DARA tool:`, error ); return false; } } /** * 检查髋臼水平角测量工具是否处于激活状态 */ static isDARAMeasurementToolActive(viewportId: string): boolean { const toolGroup = MeasurementToolManager.getToolGroup(viewportId); if (!toolGroup) return false; try { const activeTool = toolGroup.getActivePrimaryMouseButtonTool(); return activeTool === DARAMeasurementTool.toolName; } catch (error) { console.error( `[MeasurementToolManager] Error checking DARA tool state:`, error ); return false; } } /** * 切换髋臼水平角测量工具状态 */ static toggleDARAMeasurementTool(viewportId: string): boolean { const isActive = this.isDARAMeasurementToolActive(viewportId); if (isActive) { return this.deactivateDARAMeasurementTool(viewportId); } else { return this.activateDARAMeasurementTool(viewportId); } } /** * 清除指定 viewport 的所有髋臼水平角测量标注 */ static clearDARAMeasurements(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( DARAMeasurementTool.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} DARA measurements for viewport: ${viewportId}` ); return true; } catch (error) { console.error( `[MeasurementToolManager] Error clearing DARA measurements:`, error ); return false; } } /** * 获取指定 viewport 的所有髋臼水平角测量结果 */ // eslint-disable-next-line static getDARAMeasurements(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( DARAMeasurementTool.toolName, viewport.element ); return annotations.map((annotation) => ({ annotationUID: annotation.annotationUID, angleLeft: annotation.data?.cachedStats?.angleLeft || 0, angleRight: annotation.data?.cachedStats?.angleRight || 0, unit: 'degrees', points: annotation.data?.handles?.points || [], })); } catch (error) { console.error( `[MeasurementToolManager] Error getting DARA measurements:`, error ); return []; } } /** * 为多个 viewport 批量激活髋臼水平角测量工具 */ static activateDARAMeasurementToolForViewports( viewportIds: string[] ): boolean[] { return viewportIds.map((viewportId) => this.activateDARAMeasurementTool(viewportId) ); } /** * 为多个 viewport 批量停用髋臼水平角测量工具 */ static deactivateDARAMeasurementToolForViewports( viewportIds: string[] ): boolean[] { return viewportIds.map((viewportId) => this.deactivateDARAMeasurementTool(viewportId) ); } /** * 为多个 viewport 批量清除髋臼水平角测量 */ static clearDARAMeasurementsForViewports(viewportIds: string[]): boolean[] { return viewportIds.map((viewportId) => this.clearDARAMeasurements(viewportId) ); } // ==================== 髋关节牵引指数测量工具 ==================== /** * 激活髋关节牵引指数测量工具 */ static activateHipDIMeasurementTool(viewportId: string): boolean { const toolGroup = MeasurementToolManager.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.setToolActive(HipDIMeasurementTool.toolName, { bindings: [{ mouseButton: MouseBindings.Primary }], }); // 获取工具实例并激活修改模式 const toolInstance = toolGroup.getToolInstance( HipDIMeasurementTool.toolName ) as HipDIMeasurementTool; const viewport = cornerstone.getEnabledElementByViewportId(viewportId)?.viewport; if (toolInstance && viewport.element) { toolInstance._activateModify(viewport.element); } // 自动创建一个预设的注解 try { if (viewport && viewport.element) { // 创建预设注解 const defaultAnnotation = HipDIMeasurementTool.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( HipDIMeasurementTool.toolName ) as HipDIMeasurementTool; if (toolInstance && '_updateCachedStats' in toolInstance) { (toolInstance as any)._updateCachedStats(defaultAnnotation, enabledElement); } } // 触发渲染更新 viewport.render(); console.log('[MeasurementToolManager] Default HipDI annotation created successfully'); } } catch (error) { console.error('[MeasurementToolManager] Failed to create default HipDI annotation:', error); // 注解创建失败不影响工具激活 } console.log( `[MeasurementToolManager] HipDI tool activated for viewport: ${viewportId}` ); return true; } catch (error) { console.error( `[MeasurementToolManager] Error activating HipDI tool:`, error ); return false; } } /** * 停用髋关节牵引指数测量工具 */ static deactivateHipDIMeasurementTool(viewportId: string): boolean { const toolGroup = MeasurementToolManager.getToolGroup(viewportId); if (!toolGroup) return false; try { toolGroup.setToolPassive(HipDIMeasurementTool.toolName, { removeAllBindings: true, }); console.log( `[MeasurementToolManager] HipDI tool deactivated for viewport: ${viewportId}` ); return true; } catch (error) { console.error( `[MeasurementToolManager] Error deactivating HipDI tool:`, error ); return false; } } /** * 检查髋关节牵引指数测量工具是否处于激活状态 */ static isHipDIMeasurementToolActive(viewportId: string): boolean { const toolGroup = MeasurementToolManager.getToolGroup(viewportId); if (!toolGroup) return false; try { const activeTool = toolGroup.getActivePrimaryMouseButtonTool(); return activeTool === HipDIMeasurementTool.toolName; } catch (error) { console.error( `[MeasurementToolManager] Error checking HipDI tool state:`, error ); return false; } } /** * 切换髋关节牵引指数测量工具状态 */ static toggleHipDIMeasurementTool(viewportId: string): boolean { const isActive = this.isHipDIMeasurementToolActive(viewportId); if (isActive) { return this.deactivateHipDIMeasurementTool(viewportId); } else { return this.activateHipDIMeasurementTool(viewportId); } } /** * 清除指定 viewport 的所有髋关节牵引指数测量标注 */ static clearHipDIMeasurements(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( HipDIMeasurementTool.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} HipDI measurements for viewport: ${viewportId}` ); return true; } catch (error) { console.error( `[MeasurementToolManager] Error clearing HipDI measurements:`, error ); return false; } } /** * 获取指定 viewport 的所有髋关节牵引指数测量结果 */ // eslint-disable-next-line static getHipDIMeasurements(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( HipDIMeasurementTool.toolName, viewport.element ); return annotations.map((annotation) => ({ annotationUID: annotation.annotationUID, DI: annotation.data?.cachedStats?.DI || 0, distance: annotation.data?.cachedStats?.distance || 0, unit: 'ratio', points: annotation.data?.handles?.points || [], })); } catch (error) { console.error( `[MeasurementToolManager] Error getting HipDI measurements:`, error ); return []; } } /** * 为多个 viewport 批量激活髋关节牵引指数测量工具 */ static activateHipDIMeasurementToolForViewports( viewportIds: string[] ): boolean[] { return viewportIds.map((viewportId) => this.activateHipDIMeasurementTool(viewportId) ); } /** * 为多个 viewport 批量停用髋关节牵引指数测量工具 */ static deactivateHipDIMeasurementToolForViewports( viewportIds: string[] ): boolean[] { return viewportIds.map((viewportId) => this.deactivateHipDIMeasurementTool(viewportId) ); } /** * 为多个 viewport 批量清除髋关节牵引指数测量 */ static clearHipDIMeasurementsForViewports(viewportIds: string[]): boolean[] { return viewportIds.map((viewportId) => this.clearHipDIMeasurements(viewportId) ); } // ==================== 髋关节水平角测量工具 ==================== /** * 激活髋关节水平角测量工具 */ static activateHipNHAAngleMeasurementTool(viewportId: string): boolean { const toolGroup = MeasurementToolManager.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.setToolActive(HipNHAAngleMeasurementTool.toolName, { bindings: [{ mouseButton: MouseBindings.Primary }], }); // 获取工具实例并激活修改模式 const toolInstance = toolGroup.getToolInstance( HipNHAAngleMeasurementTool.toolName ) as HipNHAAngleMeasurementTool; const viewport = cornerstone.getEnabledElementByViewportId(viewportId)?.viewport; if (toolInstance && viewport.element) { toolInstance._activateModify(viewport.element); } // 自动创建一个预设的注解 try { if (viewport && viewport.element) { // 创建预设注解 const defaultAnnotation = HipNHAAngleMeasurementTool.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( HipNHAAngleMeasurementTool.toolName ) as HipNHAAngleMeasurementTool; if (toolInstance && '_updateCachedStats' in toolInstance) { (toolInstance as any)._updateCachedStats(defaultAnnotation, enabledElement); } } // 触发渲染更新 viewport.render(); console.log('[MeasurementToolManager] Default HipNHA annotation created successfully'); } } catch (error) { console.error('[MeasurementToolManager] Failed to create default HipNHA annotation:', error); // 注解创建失败不影响工具激活 } console.log( `[MeasurementToolManager] HipNHA tool activated for viewport: ${viewportId}` ); return true; } catch (error) { console.error( `[MeasurementToolManager] Error activating HipNHA tool:`, error ); return false; } } /** * 停用髋关节水平角测量工具 */ static deactivateHipNHAAngleMeasurementTool(viewportId: string): boolean { const toolGroup = MeasurementToolManager.getToolGroup(viewportId); if (!toolGroup) return false; try { toolGroup.setToolPassive(HipNHAAngleMeasurementTool.toolName, { removeAllBindings: true, }); console.log( `[MeasurementToolManager] HipNHA tool deactivated for viewport: ${viewportId}` ); return true; } catch (error) { console.error( `[MeasurementToolManager] Error deactivating HipNHA tool:`, error ); return false; } } /** * 检查髋关节水平角测量工具是否处于激活状态 */ static isHipNHAAngleMeasurementToolActive(viewportId: string): boolean { const toolGroup = MeasurementToolManager.getToolGroup(viewportId); if (!toolGroup) return false; try { const activeTool = toolGroup.getActivePrimaryMouseButtonTool(); return activeTool === HipNHAAngleMeasurementTool.toolName; } catch (error) { console.error( `[MeasurementToolManager] Error checking HipNHA tool state:`, error ); return false; } } /** * 切换髋关节水平角测量工具状态 */ static toggleHipNHAAngleMeasurementTool(viewportId: string): boolean { const isActive = this.isHipNHAAngleMeasurementToolActive(viewportId); if (isActive) { return this.deactivateHipNHAAngleMeasurementTool(viewportId); } else { return this.activateHipNHAAngleMeasurementTool(viewportId); } } /** * 清除指定 viewport 的所有髋关节水平角测量标注 */ static clearHipNHAAngleMeasurements(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( HipNHAAngleMeasurementTool.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} HipNHA measurements for viewport: ${viewportId}` ); return true; } catch (error) { console.error( `[MeasurementToolManager] Error clearing HipNHA measurements:`, error ); return false; } } /** * 获取指定 viewport 的所有髋关节水平角测量结果 */ // eslint-disable-next-line static getHipNHAAngleMeasurements(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( HipNHAAngleMeasurementTool.toolName, viewport.element ); return annotations.map((annotation) => ({ annotationUID: annotation.annotationUID, angleLeft: annotation.data?.cachedStats?.angleLeft || 0, angleRight: annotation.data?.cachedStats?.angleRight || 0, unit: 'degrees', points: annotation.data?.handles?.points || [], })); } catch (error) { console.error( `[MeasurementToolManager] Error getting HipNHA measurements:`, error ); return []; } } /** * 为多个 viewport 批量激活髋关节水平角测量工具 */ static activateHipNHAAngleMeasurementToolForViewports( viewportIds: string[] ): boolean[] { return viewportIds.map((viewportId) => this.activateHipNHAAngleMeasurementTool(viewportId) ); } /** * 为多个 viewport 批量停用髋关节水平角测量工具 */ static deactivateHipNHAAngleMeasurementToolForViewports( viewportIds: string[] ): boolean[] { return viewportIds.map((viewportId) => this.deactivateHipNHAAngleMeasurementTool(viewportId) ); } /** * 为多个 viewport 批量清除髋关节水平角测量 */ static clearHipNHAAngleMeasurementsForViewports(viewportIds: string[]): boolean[] { return viewportIds.map((viewportId) => this.clearHipNHAAngleMeasurements(viewportId) ); } // ==================== 心锥比测量工具 ==================== /** * 激活心锥比测量工具 */ static activateVHSMeasurementTool(viewportId: string): boolean { const toolGroup = MeasurementToolManager.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.setToolActive(VHSMeasurementTool.toolName, { bindings: [{ mouseButton: MouseBindings.Primary }], }); // 获取工具实例并激活修改模式 const toolInstance = toolGroup.getToolInstance( VHSMeasurementTool.toolName ) as VHSMeasurementTool; const viewport = cornerstone.getEnabledElementByViewportId(viewportId)?.viewport; if (toolInstance && viewport.element) { toolInstance._activateModify(viewport.element); } // 自动创建一个预设的注解 try { if (viewport && viewport.element) { // 创建预设注解 const defaultAnnotation = VHSMeasurementTool.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( VHSMeasurementTool.toolName ) as VHSMeasurementTool; if (toolInstance && '_updateCachedStats' in toolInstance) { (toolInstance as any)._updateCachedStats(defaultAnnotation, enabledElement); } } // 触发渲染更新 viewport.render(); console.log('[MeasurementToolManager] Default VHS annotation created successfully'); } } catch (error) { console.error('[MeasurementToolManager] Failed to create default VHS annotation:', error); // 注解创建失败不影响工具激活 } console.log( `[MeasurementToolManager] VHS tool activated for viewport: ${viewportId}` ); return true; } catch (error) { console.error( `[MeasurementToolManager] Error activating VHS tool:`, error ); return false; } } /** * 停用心锥比测量工具 */ static deactivateVHSMeasurementTool(viewportId: string): boolean { const toolGroup = MeasurementToolManager.getToolGroup(viewportId); if (!toolGroup) return false; try { toolGroup.setToolPassive(VHSMeasurementTool.toolName, { removeAllBindings: true, }); console.log( `[MeasurementToolManager] VHS tool deactivated for viewport: ${viewportId}` ); return true; } catch (error) { console.error( `[MeasurementToolManager] Error deactivating VHS tool:`, error ); return false; } } /** * 检查心锥比测量工具是否处于激活状态 */ static isVHSMeasurementToolActive(viewportId: string): boolean { const toolGroup = MeasurementToolManager.getToolGroup(viewportId); if (!toolGroup) return false; try { const activeTool = toolGroup.getActivePrimaryMouseButtonTool(); return activeTool === VHSMeasurementTool.toolName; } catch (error) { console.error( `[MeasurementToolManager] Error checking VHS tool state:`, error ); return false; } } /** * 切换心锥比测量工具状态 */ static toggleVHSMeasurementTool(viewportId: string): boolean { const isActive = this.isVHSMeasurementToolActive(viewportId); if (isActive) { return this.deactivateVHSMeasurementTool(viewportId); } else { return this.activateVHSMeasurementTool(viewportId); } } /** * 清除指定 viewport 的所有心锥比测量标注 */ static clearVHSMeasurements(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( VHSMeasurementTool.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} VHS measurements for viewport: ${viewportId}` ); return true; } catch (error) { console.error( `[MeasurementToolManager] Error clearing VHS measurements:`, error ); return false; } } /** * 获取指定 viewport 的所有心锥比测量结果 */ // eslint-disable-next-line static getVHSMeasurements(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( VHSMeasurementTool.toolName, viewport.element ); return annotations.map((annotation) => ({ annotationUID: annotation.annotationUID, vhs: annotation.data?.cachedStats?.vhs || 0, longAxisCount: annotation.data?.cachedStats?.longAxisCount || 0, shortAxisCount: annotation.data?.cachedStats?.shortAxisCount || 0, ratio: annotation.data?.cachedStats?.ratio || 0, unit: 'ratio', points: annotation.data?.handles?.points || [], })); } catch (error) { console.error( `[MeasurementToolManager] Error getting VHS measurements:`, error ); return []; } } /** * 为多个 viewport 批量激活心锥比测量工具 */ static activateVHSMeasurementToolForViewports( viewportIds: string[] ): boolean[] { return viewportIds.map((viewportId) => this.activateVHSMeasurementTool(viewportId) ); } /** * 为多个 viewport 批量停用心锥比测量工具 */ static deactivateVHSMeasurementToolForViewports( viewportIds: string[] ): boolean[] { return viewportIds.map((viewportId) => this.deactivateVHSMeasurementTool(viewportId) ); } /** * 为多个 viewport 批量清除心锥比测量 */ static clearVHSMeasurementsForViewports(viewportIds: string[]): boolean[] { return viewportIds.map((viewportId) => this.clearVHSMeasurements(viewportId) ); } // ==================== TPLO测量工具 ==================== /** * 激活TPLO测量工具 */ static activateTPLOMeasurementTool(viewportId: string): boolean { const toolGroup = MeasurementToolManager.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 = MeasurementToolManager.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 = MeasurementToolManager.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) ); } // ==================== TTA测量工具 ==================== /** * 激活TTA测量工具 */ static activateTTAMeasurementTool(viewportId: string): boolean { const toolGroup = MeasurementToolManager.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, }); toolGroup.setToolPassive(TPLOMeasurementTool.toolName, { removeAllBindings: true, }); // 激活TTA测量工具 toolGroup.setToolActive(TTAMeasurementTool.toolName, { bindings: [{ mouseButton: MouseBindings.Primary }], }); // 获取工具实例并激活修改模式 const toolInstance = toolGroup.getToolInstance( TTAMeasurementTool.toolName ) as TTAMeasurementTool; const viewport = cornerstone.getEnabledElementByViewportId(viewportId)?.viewport; if (toolInstance && viewport.element) { toolInstance._activateModify(viewport.element); } // 自动创建一个预设的注解 try { if (viewport && viewport.element) { // 创建预设注解 const defaultAnnotation = TTAMeasurementTool.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( TTAMeasurementTool.toolName ) as TTAMeasurementTool; if (toolInstance && '_updateCachedStats' in toolInstance) { (toolInstance as any)._updateCachedStats(defaultAnnotation, enabledElement); } } // 触发渲染更新 viewport.render(); console.log('[MeasurementToolManager] Default TTA annotation created successfully'); } } catch (error) { console.error('[MeasurementToolManager] Failed to create default TTA annotation:', error); // 注解创建失败不影响工具激活 } console.log( `[MeasurementToolManager] TTA tool activated for viewport: ${viewportId}` ); return true; } catch (error) { console.error( `[MeasurementToolManager] Error activating TTA tool:`, error ); return false; } } /** * 停用TTA测量工具 */ static deactivateTTAMeasurementTool(viewportId: string): boolean { const toolGroup = MeasurementToolManager.getToolGroup(viewportId); if (!toolGroup) return false; try { toolGroup.setToolPassive(TTAMeasurementTool.toolName, { removeAllBindings: true, }); console.log( `[MeasurementToolManager] TTA tool deactivated for viewport: ${viewportId}` ); return true; } catch (error) { console.error( `[MeasurementToolManager] Error deactivating TTA tool:`, error ); return false; } } /** * 检查TTA测量工具是否处于激活状态 */ static isTTAMeasurementToolActive(viewportId: string): boolean { const toolGroup = MeasurementToolManager.getToolGroup(viewportId); if (!toolGroup) return false; try { const activeTool = toolGroup.getActivePrimaryMouseButtonTool(); return activeTool === TTAMeasurementTool.toolName; } catch (error) { console.error( `[MeasurementToolManager] Error checking TTA tool state:`, error ); return false; } } /** * 切换TTA测量工具状态 */ static toggleTTAMeasurementTool(viewportId: string): boolean { const isActive = this.isTTAMeasurementToolActive(viewportId); if (isActive) { return this.deactivateTTAMeasurementTool(viewportId); } else { return this.activateTTAMeasurementTool(viewportId); } } /** * 清除指定 viewport 的所有TTA测量标注 */ static clearTTAMeasurements(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( TTAMeasurementTool.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} TTA measurements for viewport: ${viewportId}` ); return true; } catch (error) { console.error( `[MeasurementToolManager] Error clearing TTA measurements:`, error ); return false; } } /** * 获取指定 viewport 的所有TTA测量结果 */ // eslint-disable-next-line static getTTAMeasurements(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( TTAMeasurementTool.toolName, viewport.element ); return annotations.map((annotation) => ({ annotationUID: annotation.annotationUID, ttaDistance: annotation.data?.cachedStats?.ttaDistance || 0, unit: 'mm', points: annotation.data?.handles?.points || [], })); } catch (error) { console.error( `[MeasurementToolManager] Error getting TTA measurements:`, error ); return []; } } /** * 为多个 viewport 批量激活TTA测量工具 */ static activateTTAMeasurementToolForViewports( viewportIds: string[] ): boolean[] { return viewportIds.map((viewportId) => this.activateTTAMeasurementTool(viewportId) ); } /** * 为多个 viewport 批量停用TTA测量工具 */ static deactivateTTAMeasurementToolForViewports( viewportIds: string[] ): boolean[] { return viewportIds.map((viewportId) => this.deactivateTTAMeasurementTool(viewportId) ); } /** * 为多个 viewport 批量清除TTA测量 */ static clearTTAMeasurementsForViewports(viewportIds: string[]): boolean[] { return viewportIds.map((viewportId) => this.clearTTAMeasurements(viewportId) ); } // ==================== CBLO(水平截骨术)测量工具 ==================== /** * 激活CBLO测量工具 */ static activateCBLOMeasurementTool(viewportId: string): boolean { const toolGroup = MeasurementToolManager.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 }); toolGroup.setToolPassive(TPLOMeasurementTool.toolName, { removeAllBindings: true }); toolGroup.setToolPassive(TTAMeasurementTool.toolName, { removeAllBindings: true }); toolGroup.setToolActive(CBLOMeasurementTool.toolName, { bindings: [{ mouseButton: MouseBindings.Primary }], }); const toolInstance = toolGroup.getToolInstance(CBLOMeasurementTool.toolName) as CBLOMeasurementTool; const viewport = cornerstone.getEnabledElementByViewportId(viewportId)?.viewport; if (toolInstance && viewport.element) { toolInstance._activateModify(viewport.element); } try { if (viewport && viewport.element) { const defaultAnnotation = CBLOMeasurementTool.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(CBLOMeasurementTool.toolName) as CBLOMeasurementTool; if (toolInstance && '_updateCachedStats' in toolInstance) { (toolInstance as any)._updateCachedStats(defaultAnnotation, enabledElement); } } viewport.render(); console.log('[MeasurementToolManager] Default CBLO annotation created successfully'); } } catch (error) { console.error('[MeasurementToolManager] Failed to create default CBLO annotation:', error); } console.log(`[MeasurementToolManager] CBLO tool activated for viewport: ${viewportId}`); return true; } catch (error) { console.error(`[MeasurementToolManager] Error activating CBLO tool:`, error); return false; } } static deactivateCBLOMeasurementTool(viewportId: string): boolean { const toolGroup = MeasurementToolManager.getToolGroup(viewportId); if (!toolGroup) return false; try { toolGroup.setToolPassive(CBLOMeasurementTool.toolName, { removeAllBindings: true }); console.log(`[MeasurementToolManager] CBLO tool deactivated for viewport: ${viewportId}`); return true; } catch (error) { console.error(`[MeasurementToolManager] Error deactivating CBLO tool:`, error); return false; } } static clearCBLOMeasurements(viewportId: string): boolean { try { const viewport = cornerstone.getEnabledElementByViewportId(viewportId)?.viewport; if (!viewport) return false; const annotations = cornerstoneTools.annotation.state.getAnnotations( CBLOMeasurementTool.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} CBLO measurements for viewport: ${viewportId}`); return true; } catch (error) { console.error(`[MeasurementToolManager] Error clearing CBLO measurements:`, error); return false; } } static clearCBLOMeasurementsForViewports(viewportIds: string[]): boolean[] { return viewportIds.map((viewportId) => this.clearCBLOMeasurements(viewportId)); } // ==================== HipCoverage(股骨头覆盖率)测量工具 ==================== static activateHipCoverageMeasurementTool(viewportId: string): boolean { const toolGroup = MeasurementToolManager.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 }); toolGroup.setToolPassive(TPLOMeasurementTool.toolName, { removeAllBindings: true }); toolGroup.setToolPassive(TTAMeasurementTool.toolName, { removeAllBindings: true }); toolGroup.setToolPassive(CBLOMeasurementTool.toolName, { removeAllBindings: true }); toolGroup.setToolActive(HipCoverageMeasurementTool.toolName, { bindings: [{ mouseButton: MouseBindings.Primary }], }); const toolInstance = toolGroup.getToolInstance(HipCoverageMeasurementTool.toolName) as HipCoverageMeasurementTool; const viewport = cornerstone.getEnabledElementByViewportId(viewportId)?.viewport; if (toolInstance && viewport.element) { toolInstance._activateModify(viewport.element); } try { if (viewport && viewport.element) { const defaultAnnotation = HipCoverageMeasurementTool.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(HipCoverageMeasurementTool.toolName) as HipCoverageMeasurementTool; if (toolInstance && '_updateCachedStats' in toolInstance) { (toolInstance as any)._updateCachedStats(defaultAnnotation, enabledElement); } } viewport.render(); console.log('[MeasurementToolManager] Default HipCoverage annotation created successfully'); } } catch (error) { console.error('[MeasurementToolManager] Failed to create default HipCoverage annotation:', error); } console.log(`[MeasurementToolManager] HipCoverage tool activated for viewport: ${viewportId}`); return true; } catch (error) { console.error(`[MeasurementToolManager] Error activating HipCoverage tool:`, error); return false; } } static deactivateHipCoverageMeasurementTool(viewportId: string): boolean { const toolGroup = MeasurementToolManager.getToolGroup(viewportId); if (!toolGroup) return false; try { toolGroup.setToolPassive(HipCoverageMeasurementTool.toolName, { removeAllBindings: true }); console.log(`[MeasurementToolManager] HipCoverage tool deactivated for viewport: ${viewportId}`); return true; } catch (error) { console.error(`[MeasurementToolManager] Error deactivating HipCoverage tool:`, error); return false; } } static clearHipCoverageMeasurements(viewportId: string): boolean { try { const viewport = cornerstone.getEnabledElementByViewportId(viewportId)?.viewport; if (!viewport) return false; const annotations = cornerstoneTools.annotation.state.getAnnotations( HipCoverageMeasurementTool.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} HipCoverage measurements for viewport: ${viewportId}`); return true; } catch (error) { console.error(`[MeasurementToolManager] Error clearing HipCoverage measurements:`, error); return false; } } static clearHipCoverageMeasurementsForViewports(viewportIds: string[]): boolean[] { return viewportIds.map((viewportId) => this.clearHipCoverageMeasurements(viewportId)); } // ==================== HipDorsalCoverage(髋臼背覆盖)测量工具 ==================== static activateHipDorsalCoverageTool(viewportId: string): boolean { const toolGroup = MeasurementToolManager.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 }); toolGroup.setToolPassive(TPLOMeasurementTool.toolName, { removeAllBindings: true }); toolGroup.setToolPassive(TTAMeasurementTool.toolName, { removeAllBindings: true }); toolGroup.setToolPassive(CBLOMeasurementTool.toolName, { removeAllBindings: true }); toolGroup.setToolPassive(HipCoverageMeasurementTool.toolName, { removeAllBindings: true }); toolGroup.setToolActive(HipDorsalCoverageTool.toolName, { bindings: [{ mouseButton: MouseBindings.Primary }], }); const toolInstance = toolGroup.getToolInstance(HipDorsalCoverageTool.toolName) as HipDorsalCoverageTool; const viewport = cornerstone.getEnabledElementByViewportId(viewportId)?.viewport; if (toolInstance && viewport.element) { toolInstance._activateModify(viewport.element); } try { if (viewport && viewport.element) { const defaultAnnotation = HipDorsalCoverageTool.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(HipDorsalCoverageTool.toolName) as HipDorsalCoverageTool; if (toolInstance && '_updateCachedStats' in toolInstance) { (toolInstance as any)._updateCachedStats(defaultAnnotation, enabledElement); } } viewport.render(); console.log('[MeasurementToolManager] Default HipDorsalCoverage annotation created successfully'); } } catch (error) { console.error('[MeasurementToolManager] Failed to create default HipDorsalCoverage annotation:', error); } console.log(`[MeasurementToolManager] HipDorsalCoverage tool activated for viewport: ${viewportId}`); return true; } catch (error) { console.error(`[MeasurementToolManager] Error activating HipDorsalCoverage tool:`, error); return false; } } static deactivateHipDorsalCoverageTool(viewportId: string): boolean { const toolGroup = MeasurementToolManager.getToolGroup(viewportId); if (!toolGroup) return false; try { toolGroup.setToolPassive(HipDorsalCoverageTool.toolName, { removeAllBindings: true }); console.log(`[MeasurementToolManager] HipDorsalCoverage tool deactivated for viewport: ${viewportId}`); return true; } catch (error) { console.error(`[MeasurementToolManager] Error deactivating HipDorsalCoverage tool:`, error); return false; } } static clearHipDorsalCoverageMeasurements(viewportId: string): boolean { try { const viewport = cornerstone.getEnabledElementByViewportId(viewportId)?.viewport; if (!viewport) return false; const annotations = cornerstoneTools.annotation.state.getAnnotations( HipDorsalCoverageTool.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} HipDorsalCoverage measurements for viewport: ${viewportId}`); return true; } catch (error) { console.error(`[MeasurementToolManager] Error clearing HipDorsalCoverage measurements:`, error); return false; } } static clearHipDorsalCoverageMeasurementsForViewports(viewportIds: string[]): boolean[] { return viewportIds.map((viewportId) => this.clearHipDorsalCoverageMeasurements(viewportId)); } // ==================== CircleCenter(找圆心)测量工具 ==================== static activateCircleCenterMeasurementTool(viewportId: string): boolean { const toolGroup = MeasurementToolManager.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 }); toolGroup.setToolPassive(TPLOMeasurementTool.toolName, { removeAllBindings: true }); toolGroup.setToolPassive(TTAMeasurementTool.toolName, { removeAllBindings: true }); toolGroup.setToolPassive(CBLOMeasurementTool.toolName, { removeAllBindings: true }); toolGroup.setToolPassive(HipCoverageMeasurementTool.toolName, { removeAllBindings: true }); toolGroup.setToolPassive(HipDorsalCoverageTool.toolName, { removeAllBindings: true }); toolGroup.setToolActive(CircleCenterMeasurementTool.toolName, { bindings: [{ mouseButton: MouseBindings.Primary }], }); const toolInstance = toolGroup.getToolInstance(CircleCenterMeasurementTool.toolName) as CircleCenterMeasurementTool; const viewport = cornerstone.getEnabledElementByViewportId(viewportId)?.viewport; if (toolInstance && viewport.element) { toolInstance._activateModify(viewport.element); } try { if (viewport && viewport.element) { const defaultAnnotation = CircleCenterMeasurementTool.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(CircleCenterMeasurementTool.toolName) as CircleCenterMeasurementTool; if (toolInstance && '_updateCachedStats' in toolInstance) { (toolInstance as any)._updateCachedStats(defaultAnnotation, enabledElement); } } // 触发渲染更新 viewport.render(); console.log('[MeasurementToolManager] Default CircleCenter annotation created successfully'); } } catch (error) { console.error('[MeasurementToolManager] Failed to create default CircleCenter annotation:', error); } console.log(`[MeasurementToolManager] CircleCenter tool activated for viewport: ${viewportId}`); return true; } catch (error) { console.error(`[MeasurementToolManager] Error activating CircleCenter tool:`, error); return false; } } static deactivateCircleCenterMeasurementTool(viewportId: string): boolean { const toolGroup = MeasurementToolManager.getToolGroup(viewportId); if (!toolGroup) return false; try { toolGroup.setToolPassive(CircleCenterMeasurementTool.toolName, { removeAllBindings: true }); console.log(`[MeasurementToolManager] CircleCenter tool deactivated for viewport: ${viewportId}`); return true; } catch (error) { console.error(`[MeasurementToolManager] Error deactivating CircleCenter tool:`, error); return false; } } static clearCircleCenterMeasurements(viewportId: string): boolean { try { const viewport = cornerstone.getEnabledElementByViewportId(viewportId)?.viewport; if (!viewport) return false; const annotations = cornerstoneTools.annotation.state.getAnnotations( CircleCenterMeasurementTool.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} CircleCenter measurements for viewport: ${viewportId}`); return true; } catch (error) { console.error(`[MeasurementToolManager] Error clearing CircleCenter measurements:`, error); return false; } } static clearCircleCenterMeasurementsForViewports(viewportIds: string[]): boolean[] { return viewportIds.map((viewportId) => this.clearCircleCenterMeasurements(viewportId)); } // ==================== Midline(找中线)测量工具 ==================== static activateMidlineMeasurementTool(viewportId: string): boolean { const toolGroup = MeasurementToolManager.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 }); toolGroup.setToolPassive(TPLOMeasurementTool.toolName, { removeAllBindings: true }); toolGroup.setToolPassive(TTAMeasurementTool.toolName, { removeAllBindings: true }); toolGroup.setToolPassive(CBLOMeasurementTool.toolName, { removeAllBindings: true }); toolGroup.setToolPassive(HipCoverageMeasurementTool.toolName, { removeAllBindings: true }); toolGroup.setToolPassive(HipDorsalCoverageTool.toolName, { removeAllBindings: true }); toolGroup.setToolPassive(CircleCenterMeasurementTool.toolName, { removeAllBindings: true }); toolGroup.setToolActive(MidlineMeasurementTool.toolName, { bindings: [{ mouseButton: MouseBindings.Primary }], }); const toolInstance = toolGroup.getToolInstance(MidlineMeasurementTool.toolName) as MidlineMeasurementTool; const viewport = cornerstone.getEnabledElementByViewportId(viewportId)?.viewport; if (toolInstance && viewport.element) { toolInstance._activateModify(viewport.element); } try { if (viewport && viewport.element) { const defaultAnnotation = MidlineMeasurementTool.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(MidlineMeasurementTool.toolName) as MidlineMeasurementTool; if (toolInstance && '_updateCachedStats' in toolInstance) { (toolInstance as any)._updateCachedStats(defaultAnnotation, enabledElement); } } const viewportIdsToRender = cornerstoneTools.utilities.viewportFilters.getViewportIdsWithToolToRender( viewport.element, MidlineMeasurementTool.toolName ); cornerstoneTools.utilities.triggerAnnotationRenderForViewportIds( viewportIdsToRender ); console.log('[MeasurementToolManager] Default Midline annotation created successfully'); } } catch (error) { console.error('[MeasurementToolManager] Failed to create default Midline annotation:', error); } console.log(`[MeasurementToolManager] Midline tool activated for viewport: ${viewportId}`); return true; } catch (error) { console.error(`[MeasurementToolManager] Error activating Midline tool:`, error); return false; } } static deactivateMidlineMeasurementTool(viewportId: string): boolean { const toolGroup = MeasurementToolManager.getToolGroup(viewportId); if (!toolGroup) return false; try { toolGroup.setToolPassive(MidlineMeasurementTool.toolName, { removeAllBindings: true }); console.log(`[MeasurementToolManager] Midline tool deactivated for viewport: ${viewportId}`); return true; } catch (error) { console.error(`[MeasurementToolManager] Error deactivating Midline tool:`, error); return false; } } static clearMidlineMeasurements(viewportId: string): boolean { try { const viewport = cornerstone.getEnabledElementByViewportId(viewportId)?.viewport; if (!viewport) return false; const annotations = cornerstoneTools.annotation.state.getAnnotations( MidlineMeasurementTool.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} Midline measurements for viewport: ${viewportId}`); return true; } catch (error) { console.error(`[MeasurementToolManager] Error clearing Midline measurements:`, error); return false; } } static clearMidlineMeasurementsForViewports(viewportIds: string[]): boolean[] { return viewportIds.map((viewportId) => this.clearMidlineMeasurements(viewportId)); } // ==================== FindMidpoint(找中点)测量工具 ==================== static activateFindMidpointMeasurementTool(viewportId: string): boolean { const toolGroup = MeasurementToolManager.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 }); toolGroup.setToolPassive(TPLOMeasurementTool.toolName, { removeAllBindings: true }); toolGroup.setToolPassive(TTAMeasurementTool.toolName, { removeAllBindings: true }); toolGroup.setToolPassive(CBLOMeasurementTool.toolName, { removeAllBindings: true }); toolGroup.setToolPassive(HipCoverageMeasurementTool.toolName, { removeAllBindings: true }); toolGroup.setToolPassive(HipDorsalCoverageTool.toolName, { removeAllBindings: true }); toolGroup.setToolPassive(CircleCenterMeasurementTool.toolName, { removeAllBindings: true }); toolGroup.setToolPassive(MidlineMeasurementTool.toolName, { removeAllBindings: true }); toolGroup.setToolActive(FindMidpointMeasurementTool.toolName, { bindings: [{ mouseButton: MouseBindings.Primary }], }); const toolInstance = toolGroup.getToolInstance(FindMidpointMeasurementTool.toolName) as FindMidpointMeasurementTool; const viewport = cornerstone.getEnabledElementByViewportId(viewportId)?.viewport; if (toolInstance && viewport.element) { toolInstance._activateModify(viewport.element); } try { if (viewport && viewport.element) { const defaultAnnotation = FindMidpointMeasurementTool.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(FindMidpointMeasurementTool.toolName) as FindMidpointMeasurementTool; if (toolInstance && '_updateCachedStats' in toolInstance) { (toolInstance as any)._updateCachedStats(defaultAnnotation, enabledElement); } } const viewportIdsToRender = cornerstoneTools.utilities.viewportFilters.getViewportIdsWithToolToRender( viewport.element, FindMidpointMeasurementTool.toolName ); cornerstoneTools.utilities.triggerAnnotationRenderForViewportIds( viewportIdsToRender ); console.log('[MeasurementToolManager] Default FindMidpoint annotation created successfully'); } } catch (error) { console.error('[MeasurementToolManager] Failed to create default FindMidpoint annotation:', error); } console.log(`[MeasurementToolManager] FindMidpoint tool activated for viewport: ${viewportId}`); return true; } catch (error) { console.error(`[MeasurementToolManager] Error activating FindMidpoint tool:`, error); return false; } } static deactivateFindMidpointMeasurementTool(viewportId: string): boolean { const toolGroup = MeasurementToolManager.getToolGroup(viewportId); if (!toolGroup) return false; try { toolGroup.setToolPassive(FindMidpointMeasurementTool.toolName, { removeAllBindings: true }); console.log(`[MeasurementToolManager] FindMidpoint tool deactivated for viewport: ${viewportId}`); return true; } catch (error) { console.error(`[MeasurementToolManager] Error deactivating FindMidpoint tool:`, error); return false; } } static clearFindMidpointMeasurements(viewportId: string): boolean { try { const viewport = cornerstone.getEnabledElementByViewportId(viewportId)?.viewport; if (!viewport) return false; const annotations = cornerstoneTools.annotation.state.getAnnotations( FindMidpointMeasurementTool.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} FindMidpoint measurements for viewport: ${viewportId}`); return true; } catch (error) { console.error(`[MeasurementToolManager] Error clearing FindMidpoint measurements:`, error); return false; } } static clearFindMidpointMeasurementsForViewports(viewportIds: string[]): boolean[] { return viewportIds.map((viewportId) => this.clearFindMidpointMeasurements(viewportId)); } // ==================== VerticalTilt(直线垂直倾斜度)测量工具 ==================== static activateVerticalTiltMeasurementTool(viewportId: string): boolean { const toolGroup = MeasurementToolManager.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 }); toolGroup.setToolPassive(TPLOMeasurementTool.toolName, { removeAllBindings: true }); toolGroup.setToolPassive(TTAMeasurementTool.toolName, { removeAllBindings: true }); toolGroup.setToolPassive(CBLOMeasurementTool.toolName, { removeAllBindings: true }); toolGroup.setToolPassive(HipCoverageMeasurementTool.toolName, { removeAllBindings: true }); toolGroup.setToolPassive(HipDorsalCoverageTool.toolName, { removeAllBindings: true }); toolGroup.setToolPassive(CircleCenterMeasurementTool.toolName, { removeAllBindings: true }); toolGroup.setToolPassive(MidlineMeasurementTool.toolName, { removeAllBindings: true }); toolGroup.setToolPassive(FindMidpointMeasurementTool.toolName, { removeAllBindings: true }); toolGroup.setToolActive(VerticalTiltMeasurementTool.toolName, { bindings: [{ mouseButton: MouseBindings.Primary }], }); const toolInstance = toolGroup.getToolInstance(VerticalTiltMeasurementTool.toolName) as VerticalTiltMeasurementTool; const viewport = cornerstone.getEnabledElementByViewportId(viewportId)?.viewport; if (toolInstance && viewport.element) { toolInstance._activateModify(viewport.element); } try { if (viewport && viewport.element) { const defaultAnnotation = VerticalTiltMeasurementTool.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(VerticalTiltMeasurementTool.toolName) as VerticalTiltMeasurementTool; if (toolInstance && '_updateCachedStats' in toolInstance) { (toolInstance as any)._updateCachedStats(defaultAnnotation, enabledElement); } } const viewportIdsToRender = cornerstoneTools.utilities.viewportFilters.getViewportIdsWithToolToRender( viewport.element, VerticalTiltMeasurementTool.toolName ); cornerstoneTools.utilities.triggerAnnotationRenderForViewportIds( viewportIdsToRender ); console.log('[MeasurementToolManager] Default VerticalTilt annotation created successfully'); } } catch (error) { console.error('[MeasurementToolManager] Failed to create default VerticalTilt annotation:', error); } console.log(`[MeasurementToolManager] VerticalTilt tool activated for viewport: ${viewportId}`); return true; } catch (error) { console.error(`[MeasurementToolManager] Error activating VerticalTilt tool:`, error); return false; } } static deactivateVerticalTiltMeasurementTool(viewportId: string): boolean { const toolGroup = MeasurementToolManager.getToolGroup(viewportId); if (!toolGroup) return false; try { toolGroup.setToolPassive(VerticalTiltMeasurementTool.toolName, { removeAllBindings: true }); console.log(`[MeasurementToolManager] VerticalTilt tool deactivated for viewport: ${viewportId}`); return true; } catch (error) { console.error(`[MeasurementToolManager] Error deactivating VerticalTilt tool:`, error); return false; } } static clearVerticalTiltMeasurements(viewportId: string): boolean { try { const viewport = cornerstone.getEnabledElementByViewportId(viewportId)?.viewport; if (!viewport) return false; const annotations = cornerstoneTools.annotation.state.getAnnotations( VerticalTiltMeasurementTool.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} VerticalTilt measurements for viewport: ${viewportId}`); return true; } catch (error) { console.error(`[MeasurementToolManager] Error clearing VerticalTilt measurements:`, error); return false; } } static clearVerticalTiltMeasurementsForViewports(viewportIds: string[]): boolean[] { return viewportIds.map((viewportId) => this.clearVerticalTiltMeasurements(viewportId)); } // ==================== HorizontalTilt(直线水平倾斜度)测量工具 ==================== static activateHorizontalTiltMeasurementTool(viewportId: string): boolean { const toolGroup = MeasurementToolManager.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 }); toolGroup.setToolPassive(TPLOMeasurementTool.toolName, { removeAllBindings: true }); toolGroup.setToolPassive(TTAMeasurementTool.toolName, { removeAllBindings: true }); toolGroup.setToolPassive(CBLOMeasurementTool.toolName, { removeAllBindings: true }); toolGroup.setToolPassive(HipCoverageMeasurementTool.toolName, { removeAllBindings: true }); toolGroup.setToolPassive(HipDorsalCoverageTool.toolName, { removeAllBindings: true }); toolGroup.setToolPassive(CircleCenterMeasurementTool.toolName, { removeAllBindings: true }); toolGroup.setToolPassive(MidlineMeasurementTool.toolName, { removeAllBindings: true }); toolGroup.setToolPassive(FindMidpointMeasurementTool.toolName, { removeAllBindings: true }); toolGroup.setToolPassive(VerticalTiltMeasurementTool.toolName, { removeAllBindings: true }); toolGroup.setToolActive(HorizontalTiltMeasurementTool.toolName, { bindings: [{ mouseButton: MouseBindings.Primary }], }); const toolInstance = toolGroup.getToolInstance(HorizontalTiltMeasurementTool.toolName) as HorizontalTiltMeasurementTool; const viewport = cornerstone.getEnabledElementByViewportId(viewportId)?.viewport; if (toolInstance && viewport.element) { toolInstance._activateModify(viewport.element); } try { if (viewport && viewport.element) { const defaultAnnotation = HorizontalTiltMeasurementTool.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(HorizontalTiltMeasurementTool.toolName) as HorizontalTiltMeasurementTool; if (toolInstance && '_updateCachedStats' in toolInstance) { (toolInstance as any)._updateCachedStats(defaultAnnotation, enabledElement); } } const viewportIdsToRender = cornerstoneTools.utilities.viewportFilters.getViewportIdsWithToolToRender( viewport.element, HorizontalTiltMeasurementTool.toolName ); cornerstoneTools.utilities.triggerAnnotationRenderForViewportIds( viewportIdsToRender ); console.log('[MeasurementToolManager] Default HorizontalTilt annotation created successfully'); } } catch (error) { console.error('[MeasurementToolManager] Failed to create default HorizontalTilt annotation:', error); } console.log(`[MeasurementToolManager] HorizontalTilt tool activated for viewport: ${viewportId}`); return true; } catch (error) { console.error(`[MeasurementToolManager] Error activating HorizontalTilt tool:`, error); return false; } } static deactivateHorizontalTiltMeasurementTool(viewportId: string): boolean { const toolGroup = MeasurementToolManager.getToolGroup(viewportId); if (!toolGroup) return false; try { toolGroup.setToolPassive(HorizontalTiltMeasurementTool.toolName, { removeAllBindings: true }); console.log(`[MeasurementToolManager] HorizontalTilt tool deactivated for viewport: ${viewportId}`); return true; } catch (error) { console.error(`[MeasurementToolManager] Error deactivating HorizontalTilt tool:`, error); return false; } } static clearHorizontalTiltMeasurements(viewportId: string): boolean { try { const viewport = cornerstone.getEnabledElementByViewportId(viewportId)?.viewport; if (!viewport) return false; const annotations = cornerstoneTools.annotation.state.getAnnotations( HorizontalTiltMeasurementTool.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} HorizontalTilt measurements for viewport: ${viewportId}`); return true; } catch (error) { console.error(`[MeasurementToolManager] Error clearing HorizontalTilt measurements:`, error); return false; } } static clearHorizontalTiltMeasurementsForViewports(viewportIds: string[]): boolean[] { return viewportIds.map((viewportId) => this.clearHorizontalTiltMeasurements(viewportId)); } // ==================== PolygonLengthMeasurement(多边形长度测量)工具 ==================== /** * 激活多边形长度测量工具 */ static activatePolygonLengthMeasurementTool(viewportId: string): boolean { const toolGroup = MeasurementToolManager.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 }); toolGroup.setToolPassive(TPLOMeasurementTool.toolName, { removeAllBindings: true }); toolGroup.setToolPassive(TTAMeasurementTool.toolName, { removeAllBindings: true }); toolGroup.setToolPassive(CBLOMeasurementTool.toolName, { removeAllBindings: true }); toolGroup.setToolPassive(HipCoverageMeasurementTool.toolName, { removeAllBindings: true }); toolGroup.setToolPassive(HipDorsalCoverageTool.toolName, { removeAllBindings: true }); toolGroup.setToolPassive(CircleCenterMeasurementTool.toolName, { removeAllBindings: true }); toolGroup.setToolPassive(MidlineMeasurementTool.toolName, { removeAllBindings: true }); toolGroup.setToolPassive(FindMidpointMeasurementTool.toolName, { removeAllBindings: true }); toolGroup.setToolPassive(VerticalTiltMeasurementTool.toolName, { removeAllBindings: true }); toolGroup.setToolPassive(HorizontalTiltMeasurementTool.toolName, { removeAllBindings: true }); // 激活多边形长度测量工具 toolGroup.setToolActive(PolygonLengthMeasurementTool.toolName, { bindings: [{ mouseButton: MouseBindings.Primary }], }); // 获取工具实例并激活绘制模式(因为多边形工具是绘制类型的) const toolInstance = toolGroup.getToolInstance(PolygonLengthMeasurementTool.toolName) as PolygonLengthMeasurementTool; const viewport = cornerstone.getEnabledElementByViewportId(viewportId)?.viewport; if (toolInstance && viewport.element) { toolInstance._activateDraw(viewport.element); } console.log(`[MeasurementToolManager] PolygonLengthMeasurement tool activated for viewport: ${viewportId}`); return true; } catch (error) { console.error(`[MeasurementToolManager] Error activating PolygonLengthMeasurement tool:`, error); return false; } } /** * 停用多边形长度测量工具 */ static deactivatePolygonLengthMeasurementTool(viewportId: string): boolean { const toolGroup = MeasurementToolManager.getToolGroup(viewportId); if (!toolGroup) return false; try { toolGroup.setToolPassive(PolygonLengthMeasurementTool.toolName, { removeAllBindings: true }); console.log(`[MeasurementToolManager] PolygonLengthMeasurement tool deactivated for viewport: ${viewportId}`); return true; } catch (error) { console.error(`[MeasurementToolManager] Error deactivating PolygonLengthMeasurement tool:`, error); return false; } } /** * 清除指定 viewport 的所有多边形长度测量标注 */ static clearPolygonLengthMeasurements(viewportId: string): boolean { try { const viewport = cornerstone.getEnabledElementByViewportId(viewportId)?.viewport; if (!viewport) return false; const annotations = cornerstoneTools.annotation.state.getAnnotations( PolygonLengthMeasurementTool.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} PolygonLength measurements for viewport: ${viewportId}`); return true; } catch (error) { console.error(`[MeasurementToolManager] Error clearing PolygonLength measurements:`, error); return false; } } static clearPolygonLengthMeasurementsForViewports(viewportIds: string[]): boolean[] { return viewportIds.map((viewportId) => this.clearPolygonLengthMeasurements(viewportId)); } // ==================== PolylineLengthMeasurement(拆线长度测量)工具 ==================== /** * 激活拆线长度测量工具 */ static activatePolylineLengthMeasurementTool(viewportId: string): boolean { const toolGroup = MeasurementToolManager.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 }); toolGroup.setToolPassive(TPLOMeasurementTool.toolName, { removeAllBindings: true }); toolGroup.setToolPassive(TTAMeasurementTool.toolName, { removeAllBindings: true }); toolGroup.setToolPassive(CBLOMeasurementTool.toolName, { removeAllBindings: true }); toolGroup.setToolPassive(HipCoverageMeasurementTool.toolName, { removeAllBindings: true }); toolGroup.setToolPassive(HipDorsalCoverageTool.toolName, { removeAllBindings: true }); toolGroup.setToolPassive(CircleCenterMeasurementTool.toolName, { removeAllBindings: true }); toolGroup.setToolPassive(MidlineMeasurementTool.toolName, { removeAllBindings: true }); toolGroup.setToolPassive(FindMidpointMeasurementTool.toolName, { removeAllBindings: true }); toolGroup.setToolPassive(VerticalTiltMeasurementTool.toolName, { removeAllBindings: true }); toolGroup.setToolPassive(HorizontalTiltMeasurementTool.toolName, { removeAllBindings: true }); toolGroup.setToolPassive(PolygonLengthMeasurementTool.toolName, { removeAllBindings: true }); // 激活拆线长度测量工具 toolGroup.setToolActive(PolylineLengthMeasurementTool.toolName, { bindings: [{ mouseButton: MouseBindings.Primary }], }); // 获取工具实例并激活绘制模式(因为折线工具是绘制类型的) const toolInstance = toolGroup.getToolInstance(PolylineLengthMeasurementTool.toolName) as PolylineLengthMeasurementTool; const viewport = cornerstone.getEnabledElementByViewportId(viewportId)?.viewport; if (toolInstance && viewport.element) { toolInstance._activateDraw(viewport.element); } console.log(`[MeasurementToolManager] PolylineLengthMeasurement tool activated for viewport: ${viewportId}`); return true; } catch (error) { console.error(`[MeasurementToolManager] Error activating PolylineLengthMeasurement tool:`, error); return false; } } /** * 停用拆线长度测量工具 */ static deactivatePolylineLengthMeasurementTool(viewportId: string): boolean { const toolGroup = MeasurementToolManager.getToolGroup(viewportId); if (!toolGroup) return false; try { toolGroup.setToolPassive(PolylineLengthMeasurementTool.toolName, { removeAllBindings: true }); console.log(`[MeasurementToolManager] PolylineLengthMeasurement tool deactivated for viewport: ${viewportId}`); return true; } catch (error) { console.error(`[MeasurementToolManager] Error deactivating PolylineLengthMeasurement tool:`, error); return false; } } /** * 清除指定 viewport 的所有拆线长度测量标注 */ static clearPolylineLengthMeasurements(viewportId: string): boolean { try { const viewport = cornerstone.getEnabledElementByViewportId(viewportId)?.viewport; if (!viewport) return false; const annotations = cornerstoneTools.annotation.state.getAnnotations( PolylineLengthMeasurementTool.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} PolylineLength measurements for viewport: ${viewportId}`); return true; } catch (error) { console.error(`[MeasurementToolManager] Error clearing PolylineLength measurements:`, error); return false; } } static clearPolylineLengthMeasurementsForViewports(viewportIds: string[]): boolean[] { return viewportIds.map((viewportId) => this.clearPolylineLengthMeasurements(viewportId)); } // ==================== LineGrayscaleMeasurement(直线灰度测量)工具 ==================== /** * 激活直线灰度测量工具 */ static activateLineGrayscaleMeasurementTool(viewportId: string): boolean { const toolGroup = MeasurementToolManager.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 }); toolGroup.setToolPassive(TPLOMeasurementTool.toolName, { removeAllBindings: true }); toolGroup.setToolPassive(TTAMeasurementTool.toolName, { removeAllBindings: true }); toolGroup.setToolPassive(CBLOMeasurementTool.toolName, { removeAllBindings: true }); toolGroup.setToolPassive(HipCoverageMeasurementTool.toolName, { removeAllBindings: true }); toolGroup.setToolPassive(HipDorsalCoverageTool.toolName, { removeAllBindings: true }); toolGroup.setToolPassive(CircleCenterMeasurementTool.toolName, { removeAllBindings: true }); toolGroup.setToolPassive(MidlineMeasurementTool.toolName, { removeAllBindings: true }); toolGroup.setToolPassive(FindMidpointMeasurementTool.toolName, { removeAllBindings: true }); toolGroup.setToolPassive(VerticalTiltMeasurementTool.toolName, { removeAllBindings: true }); toolGroup.setToolPassive(HorizontalTiltMeasurementTool.toolName, { removeAllBindings: true }); toolGroup.setToolPassive(PolygonLengthMeasurementTool.toolName, { removeAllBindings: true }); toolGroup.setToolPassive(PolylineLengthMeasurementTool.toolName, { removeAllBindings: true }); // 激活直线灰度测量工具 toolGroup.setToolActive(LineGrayscaleMeasurementTool.toolName, { bindings: [{ mouseButton: MouseBindings.Primary }], }); // 获取工具实例并激活修改模式 const toolInstance = toolGroup.getToolInstance(LineGrayscaleMeasurementTool.toolName) as LineGrayscaleMeasurementTool; const viewport = cornerstone.getEnabledElementByViewportId(viewportId)?.viewport; if (toolInstance && viewport.element) { toolInstance._activateModify(viewport.element); } // 自动创建一个预设的注解 try { if (viewport && viewport.element) { const defaultAnnotation = LineGrayscaleMeasurementTool.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(LineGrayscaleMeasurementTool.toolName) as LineGrayscaleMeasurementTool; if (toolInstance && '_updateCachedStats' in toolInstance) { (toolInstance as any)._updateCachedStats(defaultAnnotation, enabledElement); } } viewport.render(); console.log('[MeasurementToolManager] Default LineGrayscale annotation created successfully'); } } catch (error) { console.error('[MeasurementToolManager] Failed to create default LineGrayscale annotation:', error); } console.log(`[MeasurementToolManager] LineGrayscaleMeasurement tool activated for viewport: ${viewportId}`); return true; } catch (error) { console.error(`[MeasurementToolManager] Error activating LineGrayscaleMeasurement tool:`, error); return false; } } /** * 停用直线灰度测量工具 */ static deactivateLineGrayscaleMeasurementTool(viewportId: string): boolean { const toolGroup = MeasurementToolManager.getToolGroup(viewportId); if (!toolGroup) return false; try { toolGroup.setToolPassive(LineGrayscaleMeasurementTool.toolName, { removeAllBindings: true }); console.log(`[MeasurementToolManager] LineGrayscaleMeasurement tool deactivated for viewport: ${viewportId}`); return true; } catch (error) { console.error(`[MeasurementToolManager] Error deactivating LineGrayscaleMeasurement tool:`, error); return false; } } /** * 清除指定 viewport 的所有直线灰度测量标注 */ static clearLineGrayscaleMeasurements(viewportId: string): boolean { try { const viewport = cornerstone.getEnabledElementByViewportId(viewportId)?.viewport; if (!viewport) return false; const annotations = cornerstoneTools.annotation.state.getAnnotations( LineGrayscaleMeasurementTool.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} LineGrayscale measurements for viewport: ${viewportId}`); return true; } catch (error) { console.error(`[MeasurementToolManager] Error clearing LineGrayscale measurements:`, error); return false; } } /** * 为多个 viewport 批量清除直线灰度测量 */ static clearLineGrayscaleMeasurementsForViewports(viewportIds: string[]): boolean[] { return viewportIds.map((viewportId) => this.clearLineGrayscaleMeasurements(viewportId)); } // ==================== RectangleGrayscaleMeasurement(矩形区域灰度测量)工具 ==================== /** * 激活矩形区域灰度测量工具 */ static activateRectangleGrayscaleMeasurementTool(viewportId: string): boolean { const toolGroup = MeasurementToolManager.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 }); toolGroup.setToolPassive(TPLOMeasurementTool.toolName, { removeAllBindings: true }); toolGroup.setToolPassive(TTAMeasurementTool.toolName, { removeAllBindings: true }); toolGroup.setToolPassive(CBLOMeasurementTool.toolName, { removeAllBindings: true }); toolGroup.setToolPassive(HipCoverageMeasurementTool.toolName, { removeAllBindings: true }); toolGroup.setToolPassive(HipDorsalCoverageTool.toolName, { removeAllBindings: true }); toolGroup.setToolPassive(CircleCenterMeasurementTool.toolName, { removeAllBindings: true }); toolGroup.setToolPassive(MidlineMeasurementTool.toolName, { removeAllBindings: true }); toolGroup.setToolPassive(FindMidpointMeasurementTool.toolName, { removeAllBindings: true }); toolGroup.setToolPassive(VerticalTiltMeasurementTool.toolName, { removeAllBindings: true }); toolGroup.setToolPassive(HorizontalTiltMeasurementTool.toolName, { removeAllBindings: true }); toolGroup.setToolPassive(PolygonLengthMeasurementTool.toolName, { removeAllBindings: true }); toolGroup.setToolPassive(PolylineLengthMeasurementTool.toolName, { removeAllBindings: true }); toolGroup.setToolPassive(LineGrayscaleMeasurementTool.toolName, { removeAllBindings: true }); // 激活矩形区域灰度测量工具 toolGroup.setToolActive(RectangleGrayscaleMeasurementTool.toolName, { bindings: [{ mouseButton: MouseBindings.Primary }], }); // 获取工具实例并激活修改模式 const toolInstance = toolGroup.getToolInstance(RectangleGrayscaleMeasurementTool.toolName) as RectangleGrayscaleMeasurementTool; const viewport = cornerstone.getEnabledElementByViewportId(viewportId)?.viewport; if (toolInstance && viewport.element) { toolInstance._activateModify(viewport.element); } // 自动创建一个预设的注解 try { if (viewport && viewport.element) { const defaultAnnotation = RectangleGrayscaleMeasurementTool.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(RectangleGrayscaleMeasurementTool.toolName) as RectangleGrayscaleMeasurementTool; if (toolInstance && '_updateCachedStats' in toolInstance) { (toolInstance as any)._updateCachedStats(defaultAnnotation, enabledElement); } } viewport.render(); console.log('[MeasurementToolManager] Default RectangleGrayscale annotation created successfully'); } } catch (error) { console.error('[MeasurementToolManager] Failed to create default RectangleGrayscale annotation:', error); } console.log(`[MeasurementToolManager] RectangleGrayscaleMeasurement tool activated for viewport: ${viewportId}`); return true; } catch (error) { console.error(`[MeasurementToolManager] Error activating RectangleGrayscaleMeasurement tool:`, error); return false; } } /** * 停用矩形区域灰度测量工具 */ static deactivateRectangleGrayscaleMeasurementTool(viewportId: string): boolean { const toolGroup = MeasurementToolManager.getToolGroup(viewportId); if (!toolGroup) return false; try { toolGroup.setToolPassive(RectangleGrayscaleMeasurementTool.toolName, { removeAllBindings: true }); console.log(`[MeasurementToolManager] RectangleGrayscaleMeasurement tool deactivated for viewport: ${viewportId}`); return true; } catch (error) { console.error(`[MeasurementToolManager] Error deactivating RectangleGrayscaleMeasurement tool:`, error); return false; } } /** * 清除指定 viewport 的所有矩形区域灰度测量标注 */ static clearRectangleGrayscaleMeasurements(viewportId: string): boolean { try { const viewport = cornerstone.getEnabledElementByViewportId(viewportId)?.viewport; if (!viewport) return false; const annotations = cornerstoneTools.annotation.state.getAnnotations( RectangleGrayscaleMeasurementTool.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} RectangleGrayscale measurements for viewport: ${viewportId}`); return true; } catch (error) { console.error(`[MeasurementToolManager] Error clearing RectangleGrayscale measurements:`, error); return false; } } /** * 为多个 viewport 批量清除矩形区域灰度测量 */ static clearRectangleGrayscaleMeasurementsForViewports(viewportIds: string[]): boolean[] { return viewportIds.map((viewportId) => this.clearRectangleGrayscaleMeasurements(viewportId)); } }