import * as cornerstone from '@cornerstonejs/core'; import * as cornerstoneTools from '@cornerstonejs/tools'; import TibialPlateauAngleTool from '@/components/measures/TibialPlateauAngleTool'; 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 = this.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 = this.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 = this.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); } } /** * 清除指定 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 activateAngleTool(viewportId: string): boolean { const toolGroup = this.getToolGroup(viewportId); if (!toolGroup) return false; try { // 停用其他可能冲突的工具 toolGroup.setToolPassive(WindowLevelTool.toolName, { removeAllBindings: true, }); toolGroup.setToolPassive(MagnifyTool.toolName, { removeAllBindings: true, }); toolGroup.setToolPassive(LengthTool.toolName, { removeAllBindings: true, }); // 激活角度测量工具 toolGroup.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 = this.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; } } /** * 检查角度测量工具是否处于激活状态 */ static isAngleToolActive(viewportId: string): boolean { const toolGroup = this.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 = this.getToolGroup(viewportId); if (!toolGroup) return false; try { // 停用其他可能冲突的工具 toolGroup.setToolPassive(WindowLevelTool.toolName, { removeAllBindings: true, }); toolGroup.setToolPassive(MagnifyTool.toolName, { removeAllBindings: true, }); toolGroup.setToolPassive(LengthTool.toolName, { removeAllBindings: true, }); toolGroup.setToolPassive(AngleTool.toolName, { removeAllBindings: true, }); // 激活胫骨平台夹角测量工具 toolGroup.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 = this.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 = this.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) ); } }