143 lines
5.3 KiB
TypeScript
143 lines
5.3 KiB
TypeScript
import { Types, annotation } from '@cornerstonejs/tools';
|
|
import { metaData } from '@cornerstonejs/core';
|
|
import { adaptersSR } from '@cornerstonejs/adapters';
|
|
|
|
import getRenderableData from './getRenderableData';
|
|
import toolNames from '../tools/toolNames';
|
|
|
|
const { MeasurementReport } = adaptersSR.Cornerstone3D;
|
|
|
|
/**
|
|
* Adds a DICOM SR (Structured Report) annotation to the annotation manager.
|
|
* This function processes measurement data from DICOM SR and converts it into
|
|
* a format suitable for display in the Cornerstone3D viewer.
|
|
*
|
|
* @param {Object} params - The parameters object
|
|
* @param {Object} params.measurement - The DICOM SR measurement data containing coordinates, labels, and metadata
|
|
* @param {Array} params.measurement.coords - Array of coordinate objects with GraphicType, ValueType, and other properties
|
|
* @param {string} params.measurement.TrackingUniqueIdentifier - Unique identifier for the measurement
|
|
* @param {string} params.measurement.TrackingIdentifier - Tracking identifier for adapter lookup
|
|
* @param {Array} [params.measurement.labels] - Optional array of label objects
|
|
* @param {string} [params.measurement.displayText] - Optional display text for the annotation
|
|
* @param {Object} [params.measurement.textBox] - Optional text box configuration
|
|
* @param {string|null} [params.imageId] - Optional image ID for the referenced image (defaults to null)
|
|
* @param {number|null} [params.frameNumber] - Optional frame number for multi-frame images (defaults to null)
|
|
* @param {Object} params.displaySet - The display set containing the image
|
|
* @param {string} params.displaySet.displaySetInstanceUID - Unique identifier for the display set
|
|
* @returns {void}
|
|
*
|
|
* @example
|
|
* ```typescript
|
|
* addSRAnnotation({
|
|
* measurement: {
|
|
* TrackingUniqueIdentifier: '1.2.3.4.5',
|
|
* TrackingIdentifier: 'POINT',
|
|
* coords: [{
|
|
* GraphicType: 'POINT',
|
|
* ValueType: 'SCOORD',
|
|
* // ... other coordinate properties
|
|
* }],
|
|
* labels: [{ value: 'Measurement Point' }],
|
|
* displayText: 'Point measurement'
|
|
* },
|
|
* imageId: 'wadouri:file://path/to/image.dcm', // Optional
|
|
* frameNumber: 0, // Optional
|
|
* displaySet: { displaySetInstanceUID: '1.2.3.4' }
|
|
* });
|
|
* ```
|
|
*/
|
|
export default function addSRAnnotation({ measurement, imageId = null, frameNumber = null, displaySet }) {
|
|
/** @type {string} The tool name to use for the annotation, defaults to DICOMSRDisplay */
|
|
let toolName = toolNames.DICOMSRDisplay;
|
|
|
|
/**
|
|
* @type {Object} Renderable data organized by graphic type
|
|
* Groups coordinate data by GraphicType for efficient rendering
|
|
*/
|
|
const renderableData = measurement.coords.reduce((acc, coordProps) => {
|
|
acc[coordProps.GraphicType] = acc[coordProps.GraphicType] || [];
|
|
acc[coordProps.GraphicType].push(getRenderableData({ ...coordProps, imageId }));
|
|
return acc;
|
|
}, {});
|
|
|
|
const { TrackingUniqueIdentifier } = measurement;
|
|
const { ValueType: valueType, GraphicType: graphicType } = measurement.coords[0];
|
|
const graphicTypePoints = renderableData[graphicType];
|
|
|
|
/** TODO: Read the tool name from the DICOM SR identification type in the future. */
|
|
let frameOfReferenceUID = null;
|
|
let planeRestriction = null;
|
|
|
|
if (imageId) {
|
|
const imagePlaneModule = metaData.get('imagePlaneModule', imageId);
|
|
frameOfReferenceUID = imagePlaneModule?.frameOfReferenceUID;
|
|
}
|
|
|
|
if (valueType === 'SCOORD3D') {
|
|
const adapter = MeasurementReport.getAdapterForTrackingIdentifier(
|
|
measurement.TrackingIdentifier
|
|
);
|
|
if (!adapter) {
|
|
toolName = toolNames.SRSCOORD3DPoint;
|
|
}
|
|
|
|
// get the ReferencedFrameOfReferenceUID from the measurement
|
|
frameOfReferenceUID = measurement.coords[0].ReferencedFrameOfReferenceSequence;
|
|
|
|
planeRestriction = {
|
|
FrameOfReferenceUID: frameOfReferenceUID,
|
|
point: graphicTypePoints[0][0],
|
|
};
|
|
}
|
|
|
|
// Store the view reference for use in initial navigation
|
|
measurement.viewReference = {
|
|
planeRestriction,
|
|
FrameOfReferenceUID: frameOfReferenceUID,
|
|
referencedImageId: imageId,
|
|
};
|
|
|
|
/**
|
|
* @type {Types.Annotation} The annotation object to be added to the annotation manager
|
|
* Contains all necessary metadata and data for rendering the DICOM SR measurement
|
|
*/
|
|
const SRAnnotation: Types.Annotation = {
|
|
annotationUID: TrackingUniqueIdentifier,
|
|
highlighted: false,
|
|
isLocked: false,
|
|
isPreview: toolName === toolNames.DICOMSRDisplay,
|
|
invalidated: false,
|
|
metadata: {
|
|
toolName,
|
|
planeRestriction,
|
|
valueType,
|
|
graphicType,
|
|
FrameOfReferenceUID: frameOfReferenceUID,
|
|
referencedImageId: imageId,
|
|
displaySetInstanceUID: displaySet.displaySetInstanceUID,
|
|
},
|
|
data: {
|
|
label: measurement.labels?.[0]?.value || undefined,
|
|
displayText: measurement.displayText || undefined,
|
|
handles: {
|
|
textBox: measurement.textBox ?? {},
|
|
points: graphicTypePoints[0],
|
|
},
|
|
cachedStats: {},
|
|
frameNumber,
|
|
renderableData,
|
|
TrackingUniqueIdentifier,
|
|
labels: measurement.labels,
|
|
},
|
|
};
|
|
|
|
/**
|
|
* Add the annotation to the annotation state manager.
|
|
* Note: Using annotation.state.addAnnotation() instead of annotationManager.addAnnotation()
|
|
* because the latter was not triggering annotation_added events properly.
|
|
*
|
|
* @param {Types.Annotation} SRAnnotation - The annotation to add
|
|
*/
|
|
annotation.state.addAnnotation(SRAnnotation);
|
|
}
|