ohif-viewer/extensions/cornerstone/src/utils/measurementServiceMappings/ArrowAnnotate.js
md-prog b93067b6a2
feat: Annotation and Measurements support on multi-frame DICOM (#2973)
* added utilities to get frameNumber from imageId and add frameNumber to per-frame instance copy

* Fix measurements' display texts on the Measurements Panel to have the correct instance number and frame number

* fixed minor React bugs (errors on console)

* fixed React's console bugs that are logged for some series that doesn't have "description"

* bug fix - multi-frame files was not loading frames correctly. It was loading Frame 1 twice, and not loading the last frame. Due to wrong frame number indexing (frame number begins with 1, not 0)

* metadata parser fix - providing default values of imagePlaneModule

* measurement SR support on multi-frame DICOM

* bug fix - jumping to the selected measurment on multi-frame DICOM

* upgrade dcmjs dependency to 2.8.1

* StudySummary component - allow "description" to be null

* make getUIDsFromImageID() method public from MetadataProvider

* imageId usage fixes to be more stable

* change the variable name to be more meaningful

* fix metaProvider importing

* for(...of) instead of for(i=0;i<length;..)
as that doesn't assume anything about the layout/design and just gets next until done.

* use Array.findIndex instead of plain for loop

* use ReferencedSOPSequence[0] - because the ReferencedSOPSequence is an array that happens to have attributes of child zero when of length 1, but you shouldn't count on that.

* DisplaySetService.getDisplaySetForSOPInstanceUID() - added optional frameNumber parameter for future usage : now they are just ignored as we are not supporting multiframe splits

* simple code refactoring

* refactoring for checking undefined values - mappedAnnotations

* remove unreachable code

* code refactoring  - prefer conditional chaining

* fix how we access imageIds of viewport (StackViewport)
2022-10-13 11:07:56 -04:00

147 lines
3.5 KiB
JavaScript

import SUPPORTED_TOOLS from './constants/supportedTools';
import getSOPInstanceAttributes from './utils/getSOPInstanceAttributes';
const Length = {
toAnnotation: measurement => {},
/**
* Maps cornerstone annotation event data to measurement service format.
*
* @param {Object} cornerstone Cornerstone event data
* @return {Measurement} Measurement instance
*/
toMeasurement: (
csToolsEventDetail,
DisplaySetService,
CornerstoneViewportService,
getValueTypeFromToolType
) => {
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 { points } = data.handles;
const mappedAnnotations = getMappedAnnotations(
annotation,
DisplaySetService
);
const displayText = getDisplayText(mappedAnnotations, displaySet);
return {
uid: annotationUID,
SOPInstanceUID,
FrameOfReferenceUID,
points,
metadata,
referenceSeriesUID: SeriesInstanceUID,
referenceStudyUID: StudyInstanceUID,
frameNumber: mappedAnnotations[0]?.frameNumber || 1,
toolName: metadata.toolName,
displaySetInstanceUID: displaySet.displaySetInstanceUID,
label: data.text,
text: data.text,
displayText: displayText,
data: data.cachedStats,
type: getValueTypeFromToolType(toolName),
getReport: () => {
throw new Error('Not implemented');
},
};
},
};
function getMappedAnnotations(annotation, DisplaySetService) {
const { metadata, data } = annotation;
const { text } = data;
const { referencedImageId } = metadata;
const annotations = [];
const {
SOPInstanceUID,
SeriesInstanceUID,
frameNumber,
} = getSOPInstanceAttributes(referencedImageId);
const displaySet = DisplaySetService.getDisplaySetForSOPInstanceUID(
SOPInstanceUID,
SeriesInstanceUID,
frameNumber
);
const { SeriesNumber } = displaySet;
annotations.push({
SeriesInstanceUID,
SOPInstanceUID,
SeriesNumber,
frameNumber,
text,
});
return annotations;
}
function getDisplayText(mappedAnnotations, displaySet) {
if (!mappedAnnotations) {
return '';
}
const displayText = [];
// Area is the same for all series
const { SeriesNumber, SOPInstanceUID, frameNumber } = mappedAnnotations[0];
const instance = displaySet.images.find(
image => image.SOPInstanceUID === SOPInstanceUID
);
let InstanceNumber;
if (instance) {
InstanceNumber = instance.InstanceNumber;
}
const instanceText = InstanceNumber ? ` I: ${InstanceNumber}` : '';
const frameText = displaySet.isMultiFrame ? ` F: ${frameNumber}` : '';
displayText.push(`(S: ${SeriesNumber}${instanceText}${frameText})`);
return displayText;
}
export default Length;