import React, { useEffect, useRef } from 'react'; import * as cornerstone from '@cornerstonejs/core'; import type { Types } from '@cornerstonejs/core'; import * as cornerstoneTools from '@cornerstonejs/tools'; import { annotation, SplineROITool } from '@cornerstonejs/tools'; import { eventTarget } from '@cornerstonejs/core'; import { registerGlobalTools } from '@/utils/cornerstoneToolsSetup'; import { MeasurementToolManager } from '@/utils/measurementToolManager'; 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 { boolean } from 'zod'; const { MagnifyTool, PanTool, WindowLevelTool, StackScrollTool, ZoomTool, LabelTool, LengthTool, AngleTool,//角度测量工具 ToolGroupManager, Enums: csToolsEnums, PlanarRotateTool, } = cornerstoneTools; const { MouseBindings } = csToolsEnums; // let toolGroup: cornerstoneTools.Types.IToolGroup; // let currentViewportId: string; function getToolgroupByViewportId(currentViewportId: string) { const toolGroup = ToolGroupManager.getToolGroup( `STACK_TOOL_GROUP_ID_${currentViewportId}` ); if (!toolGroup) { console.log('toolGroup not found'); throw new Error('Tool group not found'); } return toolGroup; } function overlayRedRectangle(currentViewportId: string) { const viewport = cornerstone.getEnabledElementByViewportId(currentViewportId) .viewport as cornerstone.StackViewport; const viewportElement = viewport.element; const annotations = cornerstoneTools.annotation.state.getAnnotations( 'LinearSplineROI', viewportElement ); if (!annotations || annotations.length === 0) { console.log('No ROI annotations found'); return; } const annotation = annotations[annotations.length - 1]; const points = annotation?.data?.handles?.points; // 创建一个覆盖 Canvas const canvas = document.createElement('canvas'); canvas.style.position = 'absolute'; canvas.width = viewportElement.clientWidth; canvas.height = viewportElement.clientHeight; viewportElement.firstChild?.appendChild(canvas); const ctx = canvas.getContext('2d'); if (!ctx) { throw new Error('Failed to get 2D context from canvas'); } ctx.fillStyle = 'rgba(0, 0, 0, 1)'; // 将 ROI 坐标转换为 Canvas 坐标 if (!points) { console.log('No points found in handles'); return; } // Convert all points to canvas coordinates const z = viewport.getCurrentImageIdIndex() || 0; const canvasPoints = points.map((point: Types.Point2 | Types.Point3) => { const point3D: Types.Point3 = point.length === 2 ? [point[0], point[1], z] : point; return viewport.worldToCanvas(point3D); }); // Log for debugging console.log('Canvas Points:', canvasPoints); // Draw the polygon ctx.beginPath(); ctx.rect(0, 0, canvas.width, canvas.height); // Full canvas for evenodd rule ctx.moveTo(canvasPoints[0][0], canvasPoints[0][1]); // Start at the first point for (let i = 1; i < canvasPoints.length; i++) { ctx.lineTo(canvasPoints[i][0], canvasPoints[i][1]); // Connect to subsequent points } ctx.closePath(); // Close the polygon ctx.fill('evenodd'); // Fill with red } function registerTools(viewportId, renderingEngineId) { // 确保全局工具已注册(只会执行一次) registerGlobalTools(); // 创建该 viewport 的工具组 const toolGroupId = `STACK_TOOL_GROUP_ID_${viewportId}`; const toolGroupTmp = ToolGroupManager.createToolGroup(toolGroupId); if (!toolGroupTmp) { console.error( `[registerTools] Failed to create tool group for viewport: ${viewportId}` ); return; } const toolGroup = toolGroupTmp; // 添加工具到工具组 toolGroup.addTool(MagnifyTool.toolName); toolGroup.addTool(PanTool.toolName); toolGroup.addTool(WindowLevelTool.toolName); toolGroup.addTool(StackScrollTool.toolName); toolGroup.addTool(ZoomTool.toolName); toolGroup.addTool(LabelTool.toolName); toolGroup.addTool(PlanarRotateTool.toolName); toolGroup.addTool(LengthTool.toolName); // 添加线段测量工具 toolGroup.addTool(AngleTool.toolName); // 添加角度测量工具 toolGroup.addTool(TibialPlateauAngleTool.toolName); // 添加胫骨平台夹角测量工具 toolGroup.addTool(DARAMeasurementTool.toolName); // 添加髋臼水平角测量工具 toolGroup.addTool(HipDIMeasurementTool.toolName); // 添加髋关节牵引指数测量工具 toolGroup.addTool(HipNHAAngleMeasurementTool.toolName); // 添加髋关节水平角测量工具 toolGroup.addTool(VHSMeasurementTool.toolName); // 添加心锥比测量工具 toolGroup.addTool(TPLOMeasurementTool.toolName); // 添加TPLO测量工具 // 设置默认工具状态 setupDefaultToolStates(toolGroup); // 添加 viewport 到工具组 toolGroup.addViewport(viewportId, renderingEngineId); console.log(`[registerTools] Tools registered for viewport: ${viewportId}`); } /** * 设置默认工具状态 */ function setupDefaultToolStates(toolGroup: cornerstoneTools.Types.IToolGroup) { // 设置平移工具(中键) toolGroup.setToolActive(PanTool.toolName, { bindings: [ { mouseButton: MouseBindings.Auxiliary, // Middle Click }, ], }); // 设置缩放工具(右键) toolGroup.setToolActive(ZoomTool.toolName, { bindings: [ { mouseButton: MouseBindings.Secondary, // Right Click }, ], }); // 设置滚轮滚动工具 toolGroup.setToolActive(StackScrollTool.toolName, { bindings: [ { mouseButton: MouseBindings.Wheel, // Mouse Wheel }, ], }); // 其他工具默认为被动状态 toolGroup.setToolPassive(MagnifyTool.toolName); toolGroup.setToolPassive(WindowLevelTool.toolName); toolGroup.setToolPassive(LabelTool.toolName); toolGroup.setToolPassive(PlanarRotateTool.toolName); toolGroup.setToolPassive(LengthTool.toolName); toolGroup.setToolPassive(AngleTool.toolName); toolGroup.setToolPassive(TibialPlateauAngleTool.toolName); toolGroup.setToolPassive(DARAMeasurementTool.toolName); toolGroup.setToolPassive(HipDIMeasurementTool.toolName); toolGroup.setToolPassive(HipNHAAngleMeasurementTool.toolName); toolGroup.setToolPassive(VHSMeasurementTool.toolName); toolGroup.setToolPassive(TPLOMeasurementTool.toolName); } export function addLMark(currentViewportId: string): void { // Implement the logic to add an L mark console.log('Adding L Mark viewport id : ', currentViewportId); const toolGroup = getToolgroupByViewportId(currentViewportId); // currentViewportId = viewportId; toolGroup.setToolActive(LabelTool.toolName, { bindings: [ // { // mouseButton: MouseBindings.Primary, // Left Click // }, ], }); const position: Types.Point3 = [100, 100, 0]; // Example position const text = 'L'; // Predefined text LabelTool.hydrate(currentViewportId, position, text); toolGroup.setToolPassive(LabelTool.toolName, { removeAllBindings: true, }); // const enabledElement = cornerstone.getEnabledElementByViewportId(currentViewportId); // cursors.elementCursor.resetElementCursor(elementRef.current as HTMLDivElement); } export function addRLabel(viewportId) { const toolGroup = getToolgroupByViewportId(viewportId); toolGroup.setToolActive(LabelTool.toolName, { bindings: [], }); const element = document.getElementById(viewportId); const elementHeight = element ? element.getBoundingClientRect().height : 0; const position: Types.Point3 = [100, elementHeight / 2, 0]; // Example position const text = 'R'; // Predefined text LabelTool.hydrate(viewportId, position, text); toolGroup.setToolPassive(LabelTool.toolName, { removeAllBindings: true }); } export function adjustBrightnessAndContrast(currentViewportId: string) { const toolGroup = getToolgroupByViewportId(currentViewportId); const planar = toolGroup.getToolInstance(WindowLevelTool.toolName); // Reset rotation angle const isActive = planar.mode === csToolsEnums.ToolModes.Active; if (isActive) { toolGroup.setToolPassive(WindowLevelTool.toolName, { removeAllBindings: true, }); } else { toolGroup.setToolActive(WindowLevelTool.toolName, { bindings: [ { mouseButton: MouseBindings.Primary, // Left Click }, ], }); } } export function fitImageSize(currentViewportId: string) { const viewport = cornerstone.getEnabledElementByViewportId(currentViewportId) .viewport as cornerstone.StackViewport; viewport.resetCamera(); viewport.render(); } export function deleteSelectedMark(currentViewportId: string): void { const viewport = cornerstone.getEnabledElementByViewportId(currentViewportId).viewport; const allAnnotations = cornerstoneTools.annotation.state.getAllAnnotations(); for (const annotation of allAnnotations) { if (annotation.data.text === 'L' || annotation.data.text === 'R') { cornerstoneTools.annotation.state.removeAnnotation( annotation.annotationUID! ); } } viewport.render(); } export function addMask(currentViewportId: string): void { // Implement the logic to add a mask console.log('Adding Mask'); // Add the specific logic to add a mask here cornerstoneTools.addTool(SplineROITool); const toolGroup = getToolgroupByViewportId(currentViewportId); toolGroup.addTool(SplineROITool.toolName); toolGroup.addToolInstance('LinearSplineROI', SplineROITool.toolName, { spline: { type: SplineROITool.SplineTypes.Linear, }, }); toolGroup.setToolActive('LinearSplineROI', { bindings: [{ mouseButton: MouseBindings.Primary }], }); } export function remoteMask(currentViewportId: string): void { // 1. 获取所有 annotation const all = annotation.state.getAllAnnotations(); // 2. 过滤出 LinearSplineROI 产生的 const toRemove = all.filter( (a) => a.metadata?.toolName === 'LinearSplineROI' ); // 3. 逐条删掉 toRemove.forEach((a) => { if (a.annotationUID) { annotation.state.removeAnnotation(a.annotationUID); } }); const viewport = cornerstone.getEnabledElementByViewportId(currentViewportId) .viewport as cornerstone.StackViewport; viewport.render(); console.log('Deleting Digital Mask'); const viewportElement = viewport.element; const firstChild = viewportElement.firstChild; if (firstChild) { const canvasElements = Array.from(firstChild.childNodes).filter( (child): child is Element => child instanceof Element && child.tagName === 'CANVAS' ); canvasElements.slice(1).forEach((canvas) => { firstChild.removeChild(canvas); }); } } export function HorizontalFlip(currentViewportId: string): void { const viewport = cornerstone.getEnabledElementByViewportId(currentViewportId) .viewport as cornerstone.StackViewport; // 切换水平翻转状态 const { flipHorizontal } = viewport.getCamera(); viewport.setCamera({ flipHorizontal: !flipHorizontal }); console.log('Flipping Image Horizontally'); } export function VerticalFlip(currentViewportId: string): void { const viewport = cornerstone.getEnabledElementByViewportId(currentViewportId) .viewport as cornerstone.StackViewport; // 切换竖直翻转状态 const { flipVertical } = viewport.getCamera(); viewport.setCamera({ flipVertical: !flipVertical }); } export function ApplyColormap(currentViewportId: string): void { const viewport = cornerstone.getEnabledElementByViewportId(currentViewportId) .viewport as cornerstone.StackViewport; // Implement the logic to apply colormap viewport.setProperties({ colormap: { name: 'hsv' } }); viewport.render(); console.log('Applying Colormap'); } export function RotateCounterclockwise90(currentViewportId: string): void { const viewport = cornerstone.getEnabledElementByViewportId(currentViewportId) .viewport as cornerstone.StackViewport; // 获取当前相机 const camera = viewport.getCamera(); // 计算新的旋转角度(当前角度 + 90度) const newRotation = (camera.rotation ?? 0) + 90; // 但计算viewUp向量时,我们应该使用90度的弧度,而不是新角度的弧度! const ninetyDegreesRadians = (90 * Math.PI) / 180; // 获取当前的viewUp向量 const currentViewUp = camera.viewUp || [0, 1, 0]; // 计算旋转后的viewUp向量(这才是正确的相对旋转) const newViewUp: [number, number, number] = [ currentViewUp[0] * Math.cos(ninetyDegreesRadians) - currentViewUp[1] * Math.sin(ninetyDegreesRadians), currentViewUp[0] * Math.sin(ninetyDegreesRadians) + currentViewUp[1] * Math.cos(ninetyDegreesRadians), 0, ]; // 设置新的相机参数 viewport.setCamera({ ...camera, viewUp: newViewUp, rotation: newRotation % 360, // 确保角度在0-359范围内 }); viewport.render(); console.log('Rotating Image Counterclockwise 90°'); } export function RotateClockwise90(currentViewportId: string): void { const viewport = cornerstone.getEnabledElementByViewportId(currentViewportId) .viewport as cornerstone.StackViewport; const camera = viewport.getCamera(); // 计算新的旋转角度(当前角度 + 90度) const newRotation = (camera.rotation ?? 0) - 90; // 但计算viewUp向量时,我们应该使用90度的弧度,而不是新角度的弧度! const ninetyDegreesRadians = (90 * Math.PI) / 180; // 获取当前的viewUp向量 const currentViewUp = camera.viewUp || [0, 1, 0]; // 计算旋转后的viewUp向量(这才是正确的相对旋转) const newViewUp: [number, number, number] = [ currentViewUp[0] * Math.cos(ninetyDegreesRadians) - currentViewUp[1] * Math.sin(ninetyDegreesRadians), currentViewUp[0] * Math.sin(ninetyDegreesRadians) + currentViewUp[1] * Math.cos(ninetyDegreesRadians), 0, ]; // 设置新的相机参数 viewport.setCamera({ ...camera, viewUp: newViewUp, rotation: newRotation % 360, // 确保角度在0-359范围内 }); viewport.render(); console.log('Rotating Image Clockwise 90°'); } export function ResetImage(currentViewportId: string): void { const viewport = cornerstone.getEnabledElementByViewportId(currentViewportId) .viewport as cornerstone.StackViewport; // Implement the logic to reset the image // Resets the viewport's camera viewport.resetCamera(); // Resets the viewport's properties viewport.resetProperties(); viewport.render(); console.log('Resetting Image'); } export function InvertImage(currentViewportId: string): void { const viewport = cornerstone.getEnabledElementByViewportId(currentViewportId) .viewport as cornerstone.StackViewport; // Implement the logic to invert the image const invert = !viewport.getProperties().invert; viewport.setProperties({ invert }); viewport.render(); console.log('Inverting Image'); } export function setOriginalSize(currentViewportId: string) { const viewport = cornerstone.getEnabledElementByViewportId(currentViewportId) .viewport as cornerstone.StackViewport; // 1) 先正常 fit(或本来就是 fit 状态) viewport.resetCamera(); // 2) 计算“fit → 1:1”的放大倍数 const { dimensions, spacing } = viewport.getImageData(); console.log(`dimensions:${dimensions}, spacing:${spacing}`); const canvas = viewport.canvas; // 水平方向 1:1 需要的倍率 const cssPixelsPerDicomPx = canvas.clientWidth / (dimensions[0] * spacing[0]); // 垂直方向 1:1 需要的倍率 const cssPixelsPerDicomPy = canvas.clientHeight / (dimensions[1] * spacing[1]); // 取两者最小值,保证整张图不会被裁剪 const zoomFactor = Math.min(cssPixelsPerDicomPx, cssPixelsPerDicomPy); console.log(`zoomFactor:${zoomFactor}`); console.log( `canvas.clientWidth:${canvas.clientWidth}, dimensions[0]:${dimensions[0]}, spacing[0]:${spacing[0]}` ); console.log( `canvas.clientHeight:${canvas.clientHeight}, dimensions[1]:${dimensions[1]}, spacing[1]:${spacing[1]}` ); // 3) 直接放大 const zoom = viewport.getZoom(); viewport.setZoom((zoom * 1) / zoomFactor); viewport.render(); } export function activateMagnifier(currentViewportId: string) { console.log('Activating Magnifier'); const toolGroup = getToolgroupByViewportId(currentViewportId); const isActive = toolGroup.getActivePrimaryMouseButtonTool() === MagnifyTool.toolName; if (isActive) { toolGroup.setToolPassive(MagnifyTool.toolName, { removeAllBindings: true, }); } else { toolGroup.setToolActive(MagnifyTool.toolName, { bindings: [ { mouseButton: MouseBindings.Primary, // Left Click }, ], }); } } export function invertContrast(currentViewportId: string) { const viewport = cornerstone.getEnabledElementByViewportId(currentViewportId).viewport; const targetBool = !viewport.getProperties().invert; viewport.setProperties({ invert: targetBool, }); viewport.render(); } export function rotateAnyAngle(currentViewportId: string) { const toolGroup = getToolgroupByViewportId(currentViewportId); const planar = toolGroup.getToolInstance(PlanarRotateTool.toolName); // Reset rotation angle const isActive = planar.mode === csToolsEnums.ToolModes.Active; console.log( `PlanarRotateTool is currently ${isActive ? 'active' : 'inactive'}` ); if (isActive) { toolGroup.setToolPassive(PlanarRotateTool.toolName, { removeAllBindings: true, }); } else { toolGroup.setToolActive(PlanarRotateTool.toolName, { bindings: [ { mouseButton: MouseBindings.Primary, // Left Click }, ], }); } console.log('Rotating Image by Any Angle'); } // ==================== 线段测量相关函数 ==================== /** * 激活线段测量工具 */ export function activateLengthMeasurement(viewportId: string): boolean { console.log( `[activateLengthMeasurement] Activating length measurement for viewport: ${viewportId}` ); return MeasurementToolManager.activateLengthTool(viewportId); } /** * 停用线段测量工具 */ export function deactivateLengthMeasurement(viewportId: string): boolean { console.log( `[deactivateLengthMeasurement] Deactivating length measurement for viewport: ${viewportId}` ); return MeasurementToolManager.deactivateLengthTool(viewportId); } /** * 切换线段测量工具状态 */ export function toggleLengthMeasurement(viewportId: string): boolean { console.log( `[toggleLengthMeasurement] Toggling length measurement for viewport: ${viewportId}` ); return MeasurementToolManager.toggleLengthTool(viewportId); } /** * 清除线段测量标注 */ export function clearLengthMeasurements(viewportId: string): boolean { console.log( `[clearLengthMeasurements] Clearing length measurements for viewport: ${viewportId}` ); return MeasurementToolManager.clearLengthMeasurements(viewportId); } /** * 获取线段测量结果 */ // eslint-disable-next-line export function getLengthMeasurements(viewportId: string): any[] { console.log( `[getLengthMeasurements] Getting length measurements for viewport: ${viewportId}` ); return MeasurementToolManager.getLengthMeasurements(viewportId); } /** * 检查线段测量工具是否激活 */ export function isLengthMeasurementActive(viewportId: string): boolean { return MeasurementToolManager.isLengthToolActive(viewportId); } // ==================== 角度测量相关函数 ==================== /** * 激活角度测量工具 */ export function activateAngleMeasurement(viewportId: string): boolean { console.log( `[activateAngleMeasurement] Activating angle measurement for viewport: ${viewportId}` ); return MeasurementToolManager.activateAngleTool(viewportId); } /** * 停用角度测量工具 */ export function deactivateAngleMeasurement(viewportId: string): boolean { console.log( `[deactivateAngleMeasurement] Deactivating angle measurement for viewport: ${viewportId}` ); return MeasurementToolManager.deactivateAngleTool(viewportId); } /** * 切换角度测量工具状态 */ export function toggleAngleMeasurement(viewportId: string): boolean { console.log( `[toggleAngleMeasurement] Toggling angle measurement for viewport: ${viewportId}` ); return MeasurementToolManager.toggleAngleTool(viewportId); } /** * 清除角度测量标注 */ export function clearAngleMeasurements(viewportId: string): boolean { console.log( `[clearAngleMeasurements] Clearing angle measurements for viewport: ${viewportId}` ); return MeasurementToolManager.clearAngleMeasurements(viewportId); } /** * 获取角度测量结果 */ // eslint-disable-next-line export function getAngleMeasurements(viewportId: string): any[] { console.log( `[getAngleMeasurements] Getting angle measurements for viewport: ${viewportId}` ); return MeasurementToolManager.getAngleMeasurements(viewportId); } /** * 检查角度测量工具是否激活 */ export function isAngleMeasurementActive(viewportId: string): boolean { return MeasurementToolManager.isAngleToolActive(viewportId); } // ==================== 胫骨平台夹角测量相关函数 ==================== /** * 激活胫骨平台夹角测量工具 */ export function activateTibialPlateauAngleMeasurement(viewportId: string): boolean { console.log( `[activateTibialPlateauAngleMeasurement] Activating TPA measurement for viewport: ${viewportId}` ); return MeasurementToolManager.activateTibialPlateauAngleTool(viewportId); } /** * 停用胫骨平台夹角测量工具 */ export function deactivateTibialPlateauAngleMeasurement(viewportId: string): boolean { console.log( `[deactivateTibialPlateauAngleMeasurement] Deactivating TPA measurement for viewport: ${viewportId}` ); return MeasurementToolManager.deactivateTibialPlateauAngleTool(viewportId); } /** * 切换胫骨平台夹角测量工具状态 */ export function toggleTibialPlateauAngleMeasurement(viewportId: string): boolean { console.log( `[toggleTibialPlateauAngleMeasurement] Toggling TPA measurement for viewport: ${viewportId}` ); return MeasurementToolManager.toggleTibialPlateauAngleTool(viewportId); } /** * 清除胫骨平台夹角测量标注 */ export function clearTibialPlateauAngleMeasurements(viewportId: string): boolean { console.log( `[clearTibialPlateauAngleMeasurements] Clearing TPA measurements for viewport: ${viewportId}` ); return MeasurementToolManager.clearTibialPlateauAngleMeasurements(viewportId); } /** * 获取胫骨平台夹角测量结果 */ // eslint-disable-next-line export function getTibialPlateauAngleMeasurements(viewportId: string): any[] { console.log( `[getTibialPlateauAngleMeasurements] Getting TPA measurements for viewport: ${viewportId}` ); return MeasurementToolManager.getTibialPlateauAngleMeasurements(viewportId); } /** * 检查胫骨平台夹角测量工具是否激活 */ export function isTibialPlateauAngleMeasurementActive(viewportId: string): boolean { return MeasurementToolManager.isTibialPlateauAngleToolActive(viewportId); } // ==================== 髋臼水平角测量相关函数 ==================== /** * 激活髋臼水平角测量工具 */ export function activateDARAMeasurement(viewportId: string): boolean { console.log( `[activateDARAMeasurement] Activating DARA measurement for viewport: ${viewportId}` ); return MeasurementToolManager.activateDARAMeasurementTool(viewportId); } /** * 停用髋臼水平角测量工具 */ export function deactivateDARAMeasurement(viewportId: string): boolean { console.log( `[deactivateDARAMeasurement] Deactivating DARA measurement for viewport: ${viewportId}` ); return MeasurementToolManager.deactivateDARAMeasurementTool(viewportId); } /** * 切换髋臼水平角测量工具状态 */ export function toggleDARAMeasurement(viewportId: string): boolean { console.log( `[toggleDARAMeasurement] Toggling DARA measurement for viewport: ${viewportId}` ); return MeasurementToolManager.toggleDARAMeasurementTool(viewportId); } /** * 清除髋臼水平角测量标注 */ export function clearDARAMeasurements(viewportId: string): boolean { console.log( `[clearDARAMeasurements] Clearing DARA measurements for viewport: ${viewportId}` ); return MeasurementToolManager.clearDARAMeasurements(viewportId); } /** * 获取髋臼水平角测量结果 */ // eslint-disable-next-line export function getDARAMeasurements(viewportId: string): any[] { console.log( `[getDARAMeasurements] Getting DARA measurements for viewport: ${viewportId}` ); return MeasurementToolManager.getDARAMeasurements(viewportId); } /** * 检查髋臼水平角测量工具是否激活 */ export function isDARAMeasurementActive(viewportId: string): boolean { return MeasurementToolManager.isDARAMeasurementToolActive(viewportId); } // ==================== 髋关节牵引指数测量相关函数 ==================== /** * 激活髋关节牵引指数测量工具 */ export function activateHipDIMeasurement(viewportId: string): boolean { console.log( `[activateHipDIMeasurement] Activating HipDI measurement for viewport: ${viewportId}` ); return MeasurementToolManager.activateHipDIMeasurementTool(viewportId); } /** * 停用髋关节牵引指数测量工具 */ export function deactivateHipDIMeasurement(viewportId: string): boolean { console.log( `[deactivateHipDIMeasurement] Deactivating HipDI measurement for viewport: ${viewportId}` ); return MeasurementToolManager.deactivateHipDIMeasurementTool(viewportId); } /** * 切换髋关节牵引指数测量工具状态 */ export function toggleHipDIMeasurement(viewportId: string): boolean { console.log( `[toggleHipDIMeasurement] Toggling HipDI measurement for viewport: ${viewportId}` ); return MeasurementToolManager.toggleHipDIMeasurementTool(viewportId); } /** * 清除髋关节牵引指数测量标注 */ export function clearHipDIMeasurements(viewportId: string): boolean { console.log( `[clearHipDIMeasurements] Clearing HipDI measurements for viewport: ${viewportId}` ); return MeasurementToolManager.clearHipDIMeasurements(viewportId); } /** * 获取髋关节牵引指数测量结果 */ // eslint-disable-next-line export function getHipDIMeasurements(viewportId: string): any[] { console.log( `[getHipDIMeasurements] Getting HipDI measurements for viewport: ${viewportId}` ); return MeasurementToolManager.getHipDIMeasurements(viewportId); } /** * 检查髋关节牵引指数测量工具是否激活 */ export function isHipDIMeasurementActive(viewportId: string): boolean { return MeasurementToolManager.isHipDIMeasurementToolActive(viewportId); } // ==================== 髋关节水平角测量相关函数 ==================== /** * 激活髋关节水平角测量工具 */ export function activateHipNHAAngleMeasurement(viewportId: string): boolean { console.log( `[activateHipNHAAngleMeasurement] Activating HipNHA measurement for viewport: ${viewportId}` ); return MeasurementToolManager.activateHipNHAAngleMeasurementTool(viewportId); } /** * 停用髋关节水平角测量工具 */ export function deactivateHipNHAAngleMeasurement(viewportId: string): boolean { console.log( `[deactivateHipNHAAngleMeasurement] Deactivating HipNHA measurement for viewport: ${viewportId}` ); return MeasurementToolManager.deactivateHipNHAAngleMeasurementTool(viewportId); } /** * 切换髋关节水平角测量工具状态 */ export function toggleHipNHAAngleMeasurement(viewportId: string): boolean { console.log( `[toggleHipNHAAngleMeasurement] Toggling HipNHA measurement for viewport: ${viewportId}` ); return MeasurementToolManager.toggleHipNHAAngleMeasurementTool(viewportId); } /** * 清除髋关节水平角测量标注 */ export function clearHipNHAAngleMeasurements(viewportId: string): boolean { console.log( `[clearHipNHAAngleMeasurements] Clearing HipNHA measurements for viewport: ${viewportId}` ); return MeasurementToolManager.clearHipNHAAngleMeasurements(viewportId); } /** * 获取髋关节水平角测量结果 */ // eslint-disable-next-line export function getHipNHAAngleMeasurements(viewportId: string): any[] { console.log( `[getHipNHAAngleMeasurements] Getting HipNHA measurements for viewport: ${viewportId}` ); return MeasurementToolManager.getHipNHAAngleMeasurements(viewportId); } /** * 检查髋关节水平角测量工具是否激活 */ export function isHipNHAAngleMeasurementActive(viewportId: string): boolean { return MeasurementToolManager.isHipNHAAngleMeasurementToolActive(viewportId); } // ==================== TPLO测量相关函数 ==================== /** * 激活TPLO测量工具 */ export function activateTPLOMeasurement(viewportId: string): boolean { console.log( `[activateTPLOMeasurement] Activating TPLO measurement for viewport: ${viewportId}` ); return MeasurementToolManager.activateTPLOMeasurementTool(viewportId); } /** * 停用TPLO测量工具 */ export function deactivateTPLOMeasurement(viewportId: string): boolean { console.log( `[deactivateTPLOMeasurement] Deactivating TPLO measurement for viewport: ${viewportId}` ); return MeasurementToolManager.deactivateTPLOMeasurementTool(viewportId); } /** * 切换TPLO测量工具状态 */ export function toggleTPLOMeasurement(viewportId: string): boolean { console.log( `[toggleTPLOMeasurement] Toggling TPLO measurement for viewport: ${viewportId}` ); return MeasurementToolManager.toggleTPLOMeasurementTool(viewportId); } /** * 清除TPLO测量标注 */ export function clearTPLOMeasurements(viewportId: string): boolean { console.log( `[clearTPLOMeasurements] Clearing TPLO measurements for viewport: ${viewportId}` ); return MeasurementToolManager.clearTPLOMeasurements(viewportId); } /** * 获取TPLO测量结果 */ // eslint-disable-next-line export function getTPLOMeasurements(viewportId: string): any[] { console.log( `[getTPLOMeasurements] Getting TPLO measurements for viewport: ${viewportId}` ); return MeasurementToolManager.getTPLOMeasurements(viewportId); } /** * 检查TPLO测量工具是否激活 */ export function isTPLOMeasurementActive(viewportId: string): boolean { return MeasurementToolManager.isTPLOMeasurementToolActive(viewportId); } const StackViewer = ({ imageIndex = 0, imageUrls = [], viewportId, renderingEngineId, selected }: { imageIndex?: number; imageUrls?: string[]; viewportId: string; renderingEngineId: string; selected?: boolean; }) => { const elementRef = useRef(null); // const action = useSelector((state: RootState) => state.functionArea.action); // const dispatch = useDispatch(); useEffect(() => { const setup = async () => { // // 初始化 Cornerstone // cornerstone.init(); // cornerstoneTools.init(); // const state = store.getState(); // console.log(`当前系统模式:${state.systemMode.mode}`); // const token = // state.systemMode.mode === SystemMode.Emergency // ? state.product.guest // : state.userInfo.token; // console.log(`token stack.image.viewer: ${token}`); // cornerstoneDICOMImageLoader.init({ // maxWebWorkers: navigator.hardwareConcurrency || 1, // errorInterceptor: (error) => { // if (error.status === 401) { // console.error('Authentication failed. Please refresh the token.'); // } // console.error(`请求dcm文件出错:${error}`); // }, // beforeSend: (xhr, imageId, defaultHeaders) => { // return { // ...defaultHeaders, // Authorization: `Bearer ${token}`, // Language: 'en', // Product: 'DROS', // Source: 'Electron', // }; // }, // }); // const currentViewportId = viewportId; eventTarget.addEventListener( cornerstoneTools.Enums.Events.ANNOTATION_COMPLETED, (evt) => { const { annotation } = evt.detail; console.log('Annotation completed event:', annotation); if (annotation.metadata.toolName === 'LinearSplineROI') { console.log('SplineROITool annotation completed:', annotation); overlayRedRectangle(viewportId); //取消工具激活状态 const toolGroup = ToolGroupManager.getToolGroup( 'STACK_TOOL_GROUP_ID' ); if (!toolGroup) { console.log('toolGroup not found'); } toolGroup?.setToolPassive('LinearSplineROI', { removeAllBindings: true, }); } } ); const viewportInput: cornerstone.Types.PublicViewportInput = { viewportId, element: elementRef.current!, type: cornerstone.Enums.ViewportType.STACK, }; const renderingEngine = cornerstone.getRenderingEngine(renderingEngineId); if (!renderingEngine) { console.error( `[stack.image.viewer] No rendering engine with id ${renderingEngineId} found` ); return; } // Enable the element for use with Cornerstone renderingEngine.enableElement(viewportInput); registerTools(viewportId, renderingEngine.id); // Get the stack viewport that was created const viewport = renderingEngine.getViewport( viewportId ) as cornerstone.Types.IStackViewport; // 给定一个dcm文件路径,加载并显示出来 try { await viewport.setStack(imageUrls, imageIndex); } catch (error) { if (error instanceof Error) { console.error( '[stack.image.viewer] Error setting image stack:', error ); } else { console.error('[stack.image.viewer] Unknown error:', error); } } viewport.render(); }; setup(); }, [elementRef, imageIndex, viewportId, renderingEngineId]); return (
e.preventDefault()} style={{ width: '100%', height: '100%', backgroundColor: '#000', border: selected ? '2px solid blue' : '1px solid gray', }} /> ); }; export default StackViewer;