Procházet zdrojové kódy

feat(processing): implement adding L markers to multiple selected viewers simultaneously

sw před 1 měsícem
rodič
revize
a10cc1daec

+ 4 - 2
src/pages/view/components/ViewerContainer.tsx

@@ -1,5 +1,5 @@
 import React, { useState, useEffect, ReactElement } from 'react';
-import StackViewer from './viewers/stack.image.viewer';
+import StackViewer, { addLMark } from './viewers/stack.image.viewer';
 import { useSelector, useDispatch } from 'react-redux';
 import store, { RootState } from '@/states/store';
 import { clearAction } from '@/states/view/functionAreaSlice';
@@ -101,8 +101,10 @@ const ViewerContainer: React.FC<ViewerContainerProps> = ({ imageUrls }) => {
       switch (action) {
         case 'Add L Mark':
           selectedViewers.forEach((index) => {
-            viewersState[index].props.addLMark();
+            // viewersState[index].props.addLMark();
+            addLMark(`viewport-${index}`);
           });
+
           break;
         case 'Add R Mark':
           // Implement the logic to add an R mark

+ 64 - 43
src/pages/view/components/viewers/stack.image.viewer.tsx

@@ -17,10 +17,19 @@ const {
   PlanarRotateTool,
 } = cornerstoneTools;
 const { MouseBindings } = csToolsEnums;
-let toolGroup: cornerstoneTools.Types.IToolGroup;
-let currentViewportId: string;
-
-function overlayRedRectangle() {
+// 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;
@@ -78,24 +87,6 @@ function overlayRedRectangle() {
   ctx.fill('evenodd'); // Fill with red
 }
 
-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();
-      //取消工具激活状态
-      const toolGroup = ToolGroupManager.getToolGroup('STACK_TOOL_GROUP_ID');
-      if (!toolGroup) {
-        console.log('toolGroup not found');
-      }
-      toolGroup?.setToolPassive('LinearSplineROI', { removeAllBindings: true });
-    }
-  }
-);
-
 function registerTools(viewportId, renderingEngineId) {
   // Add tools to Cornerstone3D
   cornerstoneTools.addTool(MagnifyTool);
@@ -106,12 +97,12 @@ function registerTools(viewportId, renderingEngineId) {
   cornerstoneTools.addTool(LabelTool);
   cornerstoneTools.addTool(PlanarRotateTool);
   // Define a tool group
-  const toolGroupId = 'STACK_TOOL_GROUP_ID';
+  const toolGroupId = `STACK_TOOL_GROUP_ID_${viewportId}`;
   const toolGroupTmp = ToolGroupManager.createToolGroup(toolGroupId);
   if (!toolGroupTmp) {
     return;
   }
-  toolGroup = toolGroupTmp;
+  const toolGroup = toolGroupTmp;
   // Add tools to the tool group
   toolGroup.addTool(MagnifyTool.toolName);
   toolGroup.addTool(PanTool.toolName);
@@ -164,9 +155,11 @@ function registerTools(viewportId, renderingEngineId) {
 
   toolGroup.addViewport(viewportId, renderingEngineId);
 }
-export function addLMark(): void {
+export function addLMark(currentViewportId: string): void {
   // Implement the logic to add an L mark
-  console.log('Adding L Mark');
+  console.log('Adding L Mark viewport id : ', currentViewportId);
+  const toolGroup = getToolgroupByViewportId(currentViewportId);
+  // currentViewportId = viewportId;
   toolGroup.setToolActive(LabelTool.toolName, {
     bindings: [
       // {
@@ -184,6 +177,7 @@ export function addLMark(): void {
   // cursors.elementCursor.resetElementCursor(elementRef.current as HTMLDivElement);
 }
 export function addRLabel(viewportId) {
+  const toolGroup = getToolgroupByViewportId(viewportId);
   toolGroup.setToolActive(LabelTool.toolName, {
     bindings: [],
   });
@@ -195,7 +189,8 @@ export function addRLabel(viewportId) {
   toolGroup.setToolPassive(LabelTool.toolName, { removeAllBindings: true });
 }
 
-export function adjustBrightnessAndContrast() {
+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) {
@@ -213,14 +208,14 @@ export function adjustBrightnessAndContrast() {
   }
 }
 
-export function fitImageSize() {
+export function fitImageSize(currentViewportId: string) {
   const viewport = cornerstone.getEnabledElementByViewportId(currentViewportId)
     .viewport as cornerstone.StackViewport;
   viewport.resetCamera();
   viewport.render();
 }
 
-export function deleteSelectedMark(): void {
+export function deleteSelectedMark(currentViewportId: string): void {
   const viewport =
     cornerstone.getEnabledElementByViewportId(currentViewportId).viewport;
   const allAnnotations = cornerstoneTools.annotation.state.getAllAnnotations();
@@ -234,11 +229,12 @@ export function deleteSelectedMark(): void {
   viewport.render();
 }
 
-export function addMask(): void {
+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: {
@@ -250,7 +246,7 @@ export function addMask(): void {
   });
 }
 
-export function remoteMask(): void {
+export function remoteMask(currentViewportId: string): void {
   // 1. 获取所有 annotation
   const all = annotation.state.getAllAnnotations();
 
@@ -283,7 +279,7 @@ export function remoteMask(): void {
     });
   }
 }
-export function HorizontalFlip(): void {
+export function HorizontalFlip(currentViewportId: string): void {
   const viewport = cornerstone.getEnabledElementByViewportId(currentViewportId)
     .viewport as cornerstone.StackViewport;
   // 切换水平翻转状态
@@ -292,7 +288,7 @@ export function HorizontalFlip(): void {
   console.log('Flipping Image Horizontally');
 }
 
-export function VerticalFlip(): void {
+export function VerticalFlip(currentViewportId: string): void {
   const viewport = cornerstone.getEnabledElementByViewportId(currentViewportId)
     .viewport as cornerstone.StackViewport;
   // 切换竖直翻转状态
@@ -300,7 +296,7 @@ export function VerticalFlip(): void {
   viewport.setCamera({ flipVertical: !flipVertical });
 }
 
-export function ApplyColormap(): void {
+export function ApplyColormap(currentViewportId: string): void {
   const viewport = cornerstone.getEnabledElementByViewportId(currentViewportId)
     .viewport as cornerstone.StackViewport;
   // Implement the logic to apply colormap
@@ -309,7 +305,7 @@ export function ApplyColormap(): void {
   console.log('Applying Colormap');
 }
 
-export function RotateCounterclockwise90(): void {
+export function RotateCounterclockwise90(currentViewportId: string): void {
   const viewport = cornerstone.getEnabledElementByViewportId(currentViewportId)
     .viewport as cornerstone.StackViewport;
   // 获取当前相机
@@ -345,7 +341,7 @@ export function RotateCounterclockwise90(): void {
   console.log('Rotating Image Counterclockwise 90°');
 }
 
-export function RotateClockwise90(): void {
+export function RotateClockwise90(currentViewportId: string): void {
   const viewport = cornerstone.getEnabledElementByViewportId(currentViewportId)
     .viewport as cornerstone.StackViewport;
   const camera = viewport.getCamera();
@@ -378,7 +374,7 @@ export function RotateClockwise90(): void {
   console.log('Rotating Image Clockwise 90°');
 }
 
-export function ResetImage(): void {
+export function ResetImage(currentViewportId: string): void {
   const viewport = cornerstone.getEnabledElementByViewportId(currentViewportId)
     .viewport as cornerstone.StackViewport;
   // Implement the logic to reset the image
@@ -390,7 +386,7 @@ export function ResetImage(): void {
   console.log('Resetting Image');
 }
 
-export function InvertImage(): void {
+export function InvertImage(currentViewportId: string): void {
   const viewport = cornerstone.getEnabledElementByViewportId(currentViewportId)
     .viewport as cornerstone.StackViewport;
   // Implement the logic to invert the image
@@ -400,7 +396,9 @@ export function InvertImage(): void {
   console.log('Inverting Image');
 }
 
-export function setOriginalSize(viewport) {
+export function setOriginalSize(currentViewportId: string) {
+  const viewport = cornerstone.getEnabledElementByViewportId(currentViewportId)
+    .viewport as cornerstone.StackViewport;
   // 1) 先正常 fit(或本来就是 fit 状态)
   viewport.resetCamera();
 
@@ -429,8 +427,9 @@ export function setOriginalSize(viewport) {
   viewport.render();
 }
 
-export function activateMagnifier() {
+export function activateMagnifier(currentViewportId: string) {
   console.log('Activating Magnifier');
+  const toolGroup = getToolgroupByViewportId(currentViewportId);
   const isActive =
     toolGroup.getActivePrimaryMouseButtonTool() === MagnifyTool.toolName;
   if (isActive) {
@@ -448,7 +447,7 @@ export function activateMagnifier() {
   }
 }
 
-export function invertContrast() {
+export function invertContrast(currentViewportId: string) {
   const viewport =
     cornerstone.getEnabledElementByViewportId(currentViewportId).viewport;
   const targetBool = !viewport.getProperties().invert;
@@ -458,7 +457,8 @@ export function invertContrast() {
   viewport.render();
 }
 
-export function rotateAnyAngle() {
+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(
@@ -527,7 +527,28 @@ const StackViewer = ({
       //     };
       //   },
       // });
-      currentViewportId = viewportId;
+      // 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!,