fix: the start/end command in TMTV for the ROIStartEndThreshold tools (#4281)
This commit is contained in:
parent
4b91ce4df9
commit
38c19fab77
@ -12,9 +12,10 @@ import dicomRTAnnotationExport from './utils/dicomRTAnnotationExport/RTStructure
|
||||
import { getWebWorkerManager } from '@cornerstonejs/core';
|
||||
|
||||
const metadataProvider = classes.MetadataProvider;
|
||||
const RECTANGLE_ROI_THRESHOLD_MANUAL_TOOL_IDS = [
|
||||
const ROI_THRESHOLD_MANUAL_TOOL_IDS = [
|
||||
'RectangleROIStartEndThreshold',
|
||||
'RectangleROIThreshold',
|
||||
'CircleROIStartEndThreshold'
|
||||
];
|
||||
const LABELMAP = csTools.Enums.SegmentationRepresentations.Labelmap;
|
||||
|
||||
@ -204,7 +205,7 @@ const commandsModule = ({ servicesManager, commandsManager, extensionManager }:
|
||||
const { referencedVolumeId } = cs.cache.getVolume(segVolumeId);
|
||||
|
||||
const annotationUIDs = _getAnnotationsSelectedByToolNames(
|
||||
RECTANGLE_ROI_THRESHOLD_MANUAL_TOOL_IDS
|
||||
ROI_THRESHOLD_MANUAL_TOOL_IDS
|
||||
);
|
||||
|
||||
if (annotationUIDs.length === 0) {
|
||||
@ -291,7 +292,7 @@ const commandsModule = ({ servicesManager, commandsManager, extensionManager }:
|
||||
const referencedVolume = cs.cache.getVolume(referencedVolumeId);
|
||||
|
||||
const annotationUIDs = _getAnnotationsSelectedByToolNames(
|
||||
RECTANGLE_ROI_THRESHOLD_MANUAL_TOOL_IDS
|
||||
ROI_THRESHOLD_MANUAL_TOOL_IDS
|
||||
);
|
||||
|
||||
const annotations = annotationUIDs.map(annotationUID =>
|
||||
@ -469,38 +470,18 @@ const commandsModule = ({ servicesManager, commandsManager, extensionManager }:
|
||||
},
|
||||
setStartSliceForROIThresholdTool: () => {
|
||||
const { viewport } = _getActiveViewportsEnabledElement();
|
||||
const { focalPoint, viewPlaneNormal } = viewport.getCamera();
|
||||
const { focalPoint } = viewport.getCamera();
|
||||
|
||||
const selectedAnnotationUIDs = _getAnnotationsSelectedByToolNames(
|
||||
RECTANGLE_ROI_THRESHOLD_MANUAL_TOOL_IDS
|
||||
ROI_THRESHOLD_MANUAL_TOOL_IDS
|
||||
);
|
||||
|
||||
const annotationUID = selectedAnnotationUIDs[0];
|
||||
|
||||
const annotation = csTools.annotation.state.getAnnotation(annotationUID);
|
||||
|
||||
const { handles } = annotation.data;
|
||||
const { points } = handles;
|
||||
|
||||
// get the current slice Index
|
||||
const sliceIndex = viewport.getCurrentImageIdIndex();
|
||||
annotation.data.startSlice = sliceIndex;
|
||||
|
||||
// distance between camera focal point and each point on the rectangle
|
||||
const newPoints = points.map(point => {
|
||||
const distance = vec3.create();
|
||||
vec3.subtract(distance, focalPoint, point);
|
||||
// distance in the direction of the viewPlaneNormal
|
||||
const distanceInViewPlane = vec3.dot(distance, viewPlaneNormal);
|
||||
// new point is current point minus distanceInViewPlane
|
||||
const newPoint = vec3.create();
|
||||
vec3.scaleAndAdd(newPoint, point, viewPlaneNormal, distanceInViewPlane);
|
||||
|
||||
return newPoint;
|
||||
//
|
||||
});
|
||||
|
||||
handles.points = newPoints;
|
||||
// set the current focalpoint
|
||||
annotation.data.startCoordinate = focalPoint;
|
||||
// IMPORTANT: invalidate the toolData for the cached stat to get updated
|
||||
// and re-calculate the projection points
|
||||
annotation.invalidated = true;
|
||||
@ -510,16 +491,16 @@ const commandsModule = ({ servicesManager, commandsManager, extensionManager }:
|
||||
const { viewport } = _getActiveViewportsEnabledElement();
|
||||
|
||||
const selectedAnnotationUIDs = _getAnnotationsSelectedByToolNames(
|
||||
RECTANGLE_ROI_THRESHOLD_MANUAL_TOOL_IDS
|
||||
ROI_THRESHOLD_MANUAL_TOOL_IDS
|
||||
);
|
||||
|
||||
const annotationUID = selectedAnnotationUIDs[0];
|
||||
|
||||
const annotation = csTools.annotation.state.getAnnotation(annotationUID);
|
||||
|
||||
// get the current slice Index
|
||||
const sliceIndex = viewport.getCurrentImageIdIndex();
|
||||
annotation.data.endSlice = sliceIndex;
|
||||
// get the current focalpoint
|
||||
const focalPointToEnd = viewport.getCamera().focalPoint;
|
||||
annotation.data.endCoordinate = focalPointToEnd;
|
||||
|
||||
// IMPORTANT: invalidate the toolData for the cached stat to get updated
|
||||
// and re-calculate the projection points
|
||||
@ -535,7 +516,7 @@ const commandsModule = ({ servicesManager, commandsManager, extensionManager }:
|
||||
|
||||
Object.keys(stateManager.annotations).forEach(frameOfReferenceUID => {
|
||||
const forAnnotations = stateManager.annotations[frameOfReferenceUID];
|
||||
const ROIAnnotations = RECTANGLE_ROI_THRESHOLD_MANUAL_TOOL_IDS.reduce(
|
||||
const ROIAnnotations = ROI_THRESHOLD_MANUAL_TOOL_IDS.reduce(
|
||||
(annotations, toolName) => [...annotations, ...(forAnnotations[toolName] ?? [])],
|
||||
[]
|
||||
);
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { addTool, RectangleROIStartEndThresholdTool } from '@cornerstonejs/tools';
|
||||
import { addTool, RectangleROIStartEndThresholdTool, CircleROIStartEndThresholdTool } from '@cornerstonejs/tools';
|
||||
|
||||
import measurementServiceMappingsFactory from './utils/measurementServiceMappings/measurementServiceMappingsFactory';
|
||||
|
||||
@ -15,8 +15,9 @@ export default function init({ servicesManager }) {
|
||||
servicesManager.services;
|
||||
|
||||
addTool(RectangleROIStartEndThresholdTool);
|
||||
addTool(CircleROIStartEndThresholdTool);
|
||||
|
||||
const { RectangleROIStartEndThreshold } = measurementServiceMappingsFactory(
|
||||
const { RectangleROIStartEndThreshold, CircleROIStartEndThreshold } = measurementServiceMappingsFactory(
|
||||
measurementService,
|
||||
displaySetService,
|
||||
cornerstoneViewportService
|
||||
@ -34,4 +35,12 @@ export default function init({ servicesManager }) {
|
||||
RectangleROIStartEndThreshold.toAnnotation,
|
||||
RectangleROIStartEndThreshold.toMeasurement
|
||||
);
|
||||
|
||||
measurementService.addMapping(
|
||||
csTools3DVer1MeasurementSource,
|
||||
'CircleROIStartEndThreshold',
|
||||
CircleROIStartEndThreshold.matchingCriteria,
|
||||
CircleROIStartEndThreshold.toAnnotation,
|
||||
CircleROIStartEndThreshold.toMeasurement
|
||||
);
|
||||
}
|
||||
|
||||
@ -0,0 +1,67 @@
|
||||
import SUPPORTED_TOOLS from './constants/supportedTools';
|
||||
import getSOPInstanceAttributes from './utils/getSOPInstanceAttributes';
|
||||
|
||||
const CircleROIStartEndThreshold = {
|
||||
toAnnotation: (measurement, definition) => { },
|
||||
|
||||
/**
|
||||
* Maps cornerstone annotation event data to measurement service format.
|
||||
*
|
||||
* @param {Object} cornerstone Cornerstone event data
|
||||
* @return {Measurement} Measurement instance
|
||||
*/
|
||||
toMeasurement: (csToolsEventDetail, displaySetService, cornerstoneViewportService) => {
|
||||
const { annotation, viewportId } = csToolsEventDetail;
|
||||
const { metadata, data, annotationUID } = annotation;
|
||||
|
||||
if (!metadata || !data) {
|
||||
console.warn('Length tool: Missing metadata or data');
|
||||
return null;
|
||||
}
|
||||
|
||||
const { toolName, referencedImageId, FrameOfReferenceUID } = metadata;
|
||||
const validToolType = SUPPORTED_TOOLS.includes(toolName);
|
||||
|
||||
if (!validToolType) {
|
||||
throw new Error('Tool not supported');
|
||||
}
|
||||
|
||||
const { SOPInstanceUID, SeriesInstanceUID, StudyInstanceUID } = getSOPInstanceAttributes(
|
||||
referencedImageId,
|
||||
cornerstoneViewportService,
|
||||
viewportId
|
||||
);
|
||||
|
||||
let displaySet;
|
||||
|
||||
if (SOPInstanceUID) {
|
||||
displaySet = displaySetService.getDisplaySetForSOPInstanceUID(
|
||||
SOPInstanceUID,
|
||||
SeriesInstanceUID
|
||||
);
|
||||
} else {
|
||||
displaySet = displaySetService.getDisplaySetsForSeries(SeriesInstanceUID);
|
||||
}
|
||||
|
||||
const { cachedStats } = data;
|
||||
|
||||
return {
|
||||
uid: annotationUID,
|
||||
SOPInstanceUID,
|
||||
FrameOfReferenceUID,
|
||||
// points,
|
||||
metadata,
|
||||
referenceSeriesUID: SeriesInstanceUID,
|
||||
referenceStudyUID: StudyInstanceUID,
|
||||
toolName: metadata.toolName,
|
||||
displaySetInstanceUID: displaySet.displaySetInstanceUID,
|
||||
label: metadata.label,
|
||||
// displayText: displayText,
|
||||
data: data.cachedStats,
|
||||
type: 'CircleROIStartEndThreshold',
|
||||
// getReport,
|
||||
};
|
||||
},
|
||||
};
|
||||
|
||||
export default CircleROIStartEndThreshold;
|
||||
@ -1,4 +1,5 @@
|
||||
import RectangleROIStartEndThreshold from './RectangleROIStartEndThreshold';
|
||||
import CircleROIStartEndThreshold from './CircleROIStartEndThreshold'
|
||||
|
||||
const measurementServiceMappingsFactory = (
|
||||
measurementService,
|
||||
@ -20,6 +21,20 @@ const measurementServiceMappingsFactory = (
|
||||
},
|
||||
],
|
||||
},
|
||||
CircleROIStartEndThreshold: {
|
||||
toAnnotation: CircleROIStartEndThreshold.toAnnotation,
|
||||
toMeasurement: csToolsAnnotation =>
|
||||
CircleROIStartEndThreshold.toMeasurement(
|
||||
csToolsAnnotation,
|
||||
displaySetService,
|
||||
cornerstoneViewportService
|
||||
),
|
||||
matchingCriteria: [
|
||||
{
|
||||
valueType: measurementService.VALUE_TYPES.ROI_THRESHOLD_MANUAL,
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
47
yarn.lock
47
yarn.lock
@ -1492,6 +1492,7 @@
|
||||
resolved "https://registry.yarnpkg.com/@colors/colors/-/colors-1.5.0.tgz#bb504579c1cae923e6576a4f5da43d25f97bdbd9"
|
||||
integrity sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==
|
||||
|
||||
|
||||
"@cornerstonejs/adapters@^1.81.6", "@cornerstonejs/adapters@^1.82.0":
|
||||
version "1.82.0"
|
||||
resolved "https://registry.yarnpkg.com/@cornerstonejs/adapters/-/adapters-1.82.0.tgz#4c7ae6341ad7bcf5cf0213e5252fbac009da23b6"
|
||||
@ -1530,10 +1531,10 @@
|
||||
resolved "https://registry.yarnpkg.com/@cornerstonejs/codec-openjph/-/codec-openjph-2.4.5.tgz#8690b61a86fa53ef38a70eee9d665a79229517c0"
|
||||
integrity sha512-MZCUy8VG0VG5Nl1l58+g+kH3LujAzLYTfJqkwpWI2gjSrGXnP6lgwyy4GmPRZWVoS40/B1LDNALK905cNWm+sg==
|
||||
|
||||
"@cornerstonejs/core@^1.78.1":
|
||||
version "1.78.1"
|
||||
resolved "https://registry.yarnpkg.com/@cornerstonejs/core/-/core-1.78.1.tgz#e7db1afd573dd631e0ad4157706deb59844ca1b7"
|
||||
integrity sha512-BfClVMEPM6IwU4TlAEh305jZOwK+xQBgf5jQywBea1DKf5KPYUFhnZcrxaWlZ44ldlpvsGBHZhDuTpdwjYszBg==
|
||||
"@cornerstonejs/core@^1.78.1", "@cornerstonejs/core@^1.81.3":
|
||||
version "1.81.3"
|
||||
resolved "https://registry.yarnpkg.com/@cornerstonejs/core/-/core-1.81.3.tgz#76deaee4a2cce24db5695cb87857accea5645263"
|
||||
integrity sha512-Uievs/wBpw20Xj4B+8UEjb/qe+cmSfz2oWfQzBANcWoqI5pXD77evXE0s6hORCMr4yFUmTIMbGnWwXT2fF2bYw==
|
||||
dependencies:
|
||||
"@kitware/vtk.js" "30.4.1"
|
||||
comlink "^4.4.1"
|
||||
@ -1553,15 +1554,15 @@
|
||||
lodash.clonedeep "4.5.0"
|
||||
|
||||
"@cornerstonejs/dicom-image-loader@^1.77.6":
|
||||
version "1.78.1"
|
||||
resolved "https://registry.yarnpkg.com/@cornerstonejs/dicom-image-loader/-/dicom-image-loader-1.78.1.tgz#d8eef8f65e7069bef26a0f569a2d89bf7c48c9de"
|
||||
integrity sha512-S37NlGD3FPrwE9qQcLVQA7pyzRlAIO+XBS7y2AgHWgXlHysRlJP+s4BWdLuwz7+Xh6cVh5g6mj/g+z51zep2kQ==
|
||||
version "1.81.3"
|
||||
resolved "https://registry.yarnpkg.com/@cornerstonejs/dicom-image-loader/-/dicom-image-loader-1.81.3.tgz#8d9165b351954999bbc566d811a9eedd2363d55c"
|
||||
integrity sha512-QFqr0Jq9DWvoBB1rTwI6gL4fc3pawpnG6ebDSZpz+uPmG/QcGYaeGNT+Szrcu2V/q1ByOU/Jxn8ZG5Nuo+kD6A==
|
||||
dependencies:
|
||||
"@cornerstonejs/codec-charls" "^1.2.3"
|
||||
"@cornerstonejs/codec-libjpeg-turbo-8bit" "^1.2.2"
|
||||
"@cornerstonejs/codec-openjpeg" "^1.2.2"
|
||||
"@cornerstonejs/codec-openjph" "^2.4.5"
|
||||
"@cornerstonejs/core" "^1.78.1"
|
||||
"@cornerstonejs/core" "^1.81.3"
|
||||
dicom-parser "^1.8.9"
|
||||
pako "^2.0.4"
|
||||
uuid "^9.0.0"
|
||||
@ -5476,10 +5477,10 @@
|
||||
dependencies:
|
||||
"@types/node" "*"
|
||||
|
||||
"@types/node@*", "@types/node@^20.12.12":
|
||||
version "20.14.5"
|
||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-20.14.5.tgz#fe35e3022ebe58b8f201580eb24e1fcfc0f2487d"
|
||||
integrity sha512-aoRR+fJkZT2l0aGOJhuA8frnCSoNX6W7U2mpNq63+BxBIj5BQFt8rHy627kijCmm63ijdSdwvGgpUsU6MBsZZA==
|
||||
"@types/node@*":
|
||||
version "20.14.9"
|
||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-20.14.9.tgz#12e8e765ab27f8c421a1820c99f5f313a933b420"
|
||||
integrity sha512-06OCtnTXtWOZBJlRApleWndH4JsRVs1pDCc8dLSQp+7PpUpX3ePdHyeNSFTeSe7FtKyQkrlPvHwJOW3SLd8Oyg==
|
||||
dependencies:
|
||||
undici-types "~5.26.4"
|
||||
|
||||
@ -5500,6 +5501,13 @@
|
||||
dependencies:
|
||||
undici-types "~5.26.4"
|
||||
|
||||
"@types/node@^20.12.12":
|
||||
version "20.14.5"
|
||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-20.14.5.tgz#fe35e3022ebe58b8f201580eb24e1fcfc0f2487d"
|
||||
integrity sha512-aoRR+fJkZT2l0aGOJhuA8frnCSoNX6W7U2mpNq63+BxBIj5BQFt8rHy627kijCmm63ijdSdwvGgpUsU6MBsZZA==
|
||||
dependencies:
|
||||
undici-types "~5.26.4"
|
||||
|
||||
"@types/normalize-package-data@^2.4.0":
|
||||
version "2.4.4"
|
||||
resolved "https://registry.yarnpkg.com/@types/normalize-package-data/-/normalize-package-data-2.4.4.tgz#56e2cc26c397c038fab0e3a917a12d5c5909e901"
|
||||
@ -5727,9 +5735,9 @@
|
||||
source-map "^0.6.0"
|
||||
|
||||
"@types/webxr@^0.5.5":
|
||||
version "0.5.16"
|
||||
resolved "https://registry.yarnpkg.com/@types/webxr/-/webxr-0.5.16.tgz#28955aa2d1197d1ef0b9826ae0f7e68f7eca0601"
|
||||
integrity sha512-0E0Cl84FECtzrB4qG19TNTqpunw0F1YF0QZZnFMF6pDw1kNKJtrlTKlVB34stGIsHbZsYQ7H0tNjPfZftkHHoA==
|
||||
version "0.5.19"
|
||||
resolved "https://registry.yarnpkg.com/@types/webxr/-/webxr-0.5.19.tgz#463a27bc06ff1c0a0c997e86b48bf24c5f50a4af"
|
||||
integrity sha512-4hxA+NwohSgImdTSlPXEqDqqFktNgmTXQ05ff1uWam05tNGroCMp4G+4XVl6qWm1p7GQ/9oD41kAYsSssF6Mzw==
|
||||
|
||||
"@types/ws@^8.2.2", "@types/ws@^8.5.5":
|
||||
version "8.5.10"
|
||||
@ -12536,13 +12544,20 @@ is-ci@^2.0.0:
|
||||
dependencies:
|
||||
ci-info "^2.0.0"
|
||||
|
||||
is-core-module@^2.1.0, is-core-module@^2.13.0, is-core-module@^2.13.1, is-core-module@^2.5.0, is-core-module@^2.8.1:
|
||||
is-core-module@^2.1.0, is-core-module@^2.13.1, is-core-module@^2.5.0, is-core-module@^2.8.1:
|
||||
version "2.13.1"
|
||||
resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.13.1.tgz#ad0d7532c6fea9da1ebdc82742d74525c6273384"
|
||||
integrity sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==
|
||||
dependencies:
|
||||
hasown "^2.0.0"
|
||||
|
||||
is-core-module@^2.13.0:
|
||||
version "2.14.0"
|
||||
resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.14.0.tgz#43b8ef9f46a6a08888db67b1ffd4ec9e3dfd59d1"
|
||||
integrity sha512-a5dFJih5ZLYlRtDc0dZWP7RiKr6xIKzmn/oAYCDvdLThadVgyJwlaoQPmRtMSpz+rk0OGAgIu+TcM9HUF0fk1A==
|
||||
dependencies:
|
||||
hasown "^2.0.2"
|
||||
|
||||
is-data-view@^1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/is-data-view/-/is-data-view-1.0.1.tgz#4b4d3a511b70f3dc26d42c03ca9ca515d847759f"
|
||||
|
||||
Loading…
Reference in New Issue
Block a user