feat: Added support for TID 1410 relationship types (#2942)
* Added support for TID 1410 relationship types * Added POLYLINE rendering from ladeirarodolfo to PR * Rolled Dockerfile back to master to make merge easier * Minor cleanup
This commit is contained in:
parent
7f770e4fb6
commit
af09578544
@ -16,6 +16,7 @@ const sopClassUids = [
|
||||
'1.2.840.10008.5.1.4.1.1.88.11', //BASIC_TEXT_SR:
|
||||
'1.2.840.10008.5.1.4.1.1.88.22', //ENHANCED_SR:
|
||||
'1.2.840.10008.5.1.4.1.1.88.33', //COMPREHENSIVE_SR:
|
||||
'1.2.840.10008.5.1.4.1.1.88.34', //COMPREHENSIVE_3D_SR:
|
||||
];
|
||||
|
||||
const CORNERSTONE_3D_TOOLS_SOURCE_NAME = 'Cornerstone3DTools';
|
||||
@ -44,6 +45,7 @@ const CodingSchemeDesignators = {
|
||||
|
||||
const RELATIONSHIP_TYPE = {
|
||||
INFERRED_FROM: 'INFERRED FROM',
|
||||
CONTAINS: 'CONTAINS',
|
||||
};
|
||||
|
||||
const CORNERSTONE_FREETEXT_CODE_VALUE = 'CORNERSTONEFREETEXT';
|
||||
@ -376,7 +378,6 @@ function _processMeasurement(mergedContentSequence) {
|
||||
function _processTID1410Measurement(mergedContentSequence) {
|
||||
// Need to deal with TID 1410 style measurements, which will have a SCOORD or SCOORD3D at the top level,
|
||||
// And non-geometric representations where each NUM has "INFERRED FROM" SCOORD/SCOORD3D
|
||||
// TODO -> Look at RelationshipType => Contains means
|
||||
|
||||
const graphicItem = mergedContentSequence.find(
|
||||
group => group.ValueType === 'SCOORD'
|
||||
@ -536,9 +537,14 @@ function _processNonGeometricallyDefinedMeasurement(mergedContentSequence) {
|
||||
function _getCoordsFromSCOORDOrSCOORD3D(item) {
|
||||
const { ValueType, RelationshipType, GraphicType, GraphicData } = item;
|
||||
|
||||
if (RelationshipType !== RELATIONSHIP_TYPE.INFERRED_FROM) {
|
||||
if (
|
||||
!(
|
||||
RelationshipType == RELATIONSHIP_TYPE.INFERRED_FROM ||
|
||||
RelationshipType == RELATIONSHIP_TYPE.CONTAINS
|
||||
)
|
||||
) {
|
||||
console.warn(
|
||||
`Relationshiptype === ${RelationshipType}. Cannot deal with NON TID-1400 SCOORD group with RelationshipType !== "INFERRED FROM."`
|
||||
`Relationshiptype === ${RelationshipType}. Cannot deal with NON TID-1400 SCOORD group with RelationshipType !== "INFERRED FROM" or "CONTAINS"`
|
||||
);
|
||||
|
||||
return;
|
||||
@ -597,12 +603,18 @@ function _getReferencedImagesList(ImagingMeasurementReportContentSequence) {
|
||||
|
||||
_getSequenceAsArray(ImageLibraryGroup.ContentSequence).forEach(item => {
|
||||
const { ReferencedSOPSequence } = item;
|
||||
const {
|
||||
ReferencedSOPClassUID,
|
||||
ReferencedSOPInstanceUID,
|
||||
} = ReferencedSOPSequence;
|
||||
|
||||
referencedImages.push({ ReferencedSOPClassUID, ReferencedSOPInstanceUID });
|
||||
if (item.hasOwnProperty('ReferencedSOPClassUID')) {
|
||||
const {
|
||||
ReferencedSOPClassUID,
|
||||
ReferencedSOPInstanceUID,
|
||||
} = ReferencedSOPSequence;
|
||||
|
||||
referencedImages.push({
|
||||
ReferencedSOPClassUID,
|
||||
ReferencedSOPInstanceUID,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
return referencedImages;
|
||||
|
||||
@ -99,7 +99,7 @@ export default class DICOMSRDisplayTool extends AnnotationTool {
|
||||
const annotation = filteredAnnotations[i];
|
||||
const annotationUID = annotation.annotationUID;
|
||||
const { renderableData } = annotation.data.cachedStats;
|
||||
const { label, cachedStats } = annotation.data;
|
||||
const { cachedStats } = annotation.data;
|
||||
const { referencedImageId } = annotation.metadata;
|
||||
|
||||
styleSpecifier.annotationUID = annotationUID;
|
||||
@ -121,22 +121,30 @@ export default class DICOMSRDisplayTool extends AnnotationTool {
|
||||
const renderableDataForGraphicType = renderableData[GraphicType];
|
||||
|
||||
let renderMethod;
|
||||
let renderTextBox;
|
||||
let canvasCoordinatesAdapter;
|
||||
|
||||
switch (GraphicType) {
|
||||
case SCOORD_TYPES.POINT:
|
||||
renderMethod = this.renderPoint;
|
||||
renderTextBox = this.renderTextBox;
|
||||
break;
|
||||
case SCOORD_TYPES.MULTIPOINT:
|
||||
renderMethod = this.renderMultipoint;
|
||||
renderTextBox = this.renderTextBox;
|
||||
break;
|
||||
case SCOORD_TYPES.POLYLINE:
|
||||
renderMethod = this.renderPolyLine;
|
||||
break;
|
||||
case SCOORD_TYPES.CIRCLE:
|
||||
renderMethod = this.renderEllipse;
|
||||
renderTextBox = this.renderTextBox;
|
||||
break;
|
||||
case SCOORD_TYPES.ELLIPSE:
|
||||
renderMethod = this.renderEllipse;
|
||||
renderTextBox = this.renderTextBox;
|
||||
canvasCoordinatesAdapter =
|
||||
utilities.math.ellipse.getCanvasEllipseCorners;
|
||||
break;
|
||||
default:
|
||||
throw new Error(`Unsupported GraphicType: ${GraphicType}`);
|
||||
@ -151,60 +159,18 @@ export default class DICOMSRDisplayTool extends AnnotationTool {
|
||||
options
|
||||
);
|
||||
|
||||
if (!canvasCoordinates) {
|
||||
return;
|
||||
}
|
||||
|
||||
const textLines = this._getTextBoxLinesFromLabels(label);
|
||||
|
||||
let canvasCornersToUseForTextBox = canvasCoordinates;
|
||||
|
||||
if (GraphicType === SCOORD_TYPES.ELLIPSE) {
|
||||
canvasCornersToUseForTextBox = utilities.math.ellipse.getCanvasEllipseCorners(
|
||||
canvasCoordinates
|
||||
if (typeof renderTextBox === 'function') {
|
||||
renderTextBox.call(
|
||||
this,
|
||||
svgDrawingHelper,
|
||||
viewport,
|
||||
canvasCoordinates,
|
||||
canvasCoordinatesAdapter,
|
||||
annotation,
|
||||
styleSpecifier,
|
||||
options
|
||||
);
|
||||
}
|
||||
|
||||
const canvasTextBoxCoords = utilities.drawing.getTextBoxCoordsCanvas(
|
||||
canvasCornersToUseForTextBox
|
||||
);
|
||||
|
||||
annotation.data.handles.textBox.worldPosition = viewport.canvasToWorld(
|
||||
canvasTextBoxCoords
|
||||
);
|
||||
|
||||
const textBoxPosition = viewport.worldToCanvas(
|
||||
annotation.data.handles.textBox.worldPosition
|
||||
);
|
||||
|
||||
const textBoxUID = '1';
|
||||
const textBoxOptions = this.getLinkedTextBoxStyle(
|
||||
styleSpecifier,
|
||||
annotation
|
||||
);
|
||||
|
||||
const boundingBox = drawing.drawLinkedTextBox(
|
||||
svgDrawingHelper,
|
||||
annotationUID,
|
||||
textBoxUID,
|
||||
textLines,
|
||||
textBoxPosition,
|
||||
canvasCoordinates,
|
||||
{},
|
||||
{
|
||||
...textBoxOptions,
|
||||
color,
|
||||
}
|
||||
);
|
||||
|
||||
const { x: left, y: top, width, height } = boundingBox;
|
||||
|
||||
annotation.data.handles.textBox.worldBoundingBox = {
|
||||
topLeft: viewport.canvasToWorld([left, top]),
|
||||
topRight: viewport.canvasToWorld([left + width, top]),
|
||||
bottomLeft: viewport.canvasToWorld([left, top + height]),
|
||||
bottomRight: viewport.canvasToWorld([left + width, top + height]),
|
||||
};
|
||||
});
|
||||
}
|
||||
};
|
||||
@ -217,28 +183,32 @@ export default class DICOMSRDisplayTool extends AnnotationTool {
|
||||
referencedImageId,
|
||||
options
|
||||
) {
|
||||
// Todo: this needs to use the drawPolyLine from cs3D since it is implemented
|
||||
// now, before it was implemented with a loop over drawLine which is hacky
|
||||
|
||||
const drawingOptions = {
|
||||
color: options.color,
|
||||
width: options.lineWidth,
|
||||
};
|
||||
let canvasCoordinates;
|
||||
renderableData.map((data, index) => {
|
||||
canvasCoordinates = data.map(p => viewport.worldToCanvas(p));
|
||||
|
||||
const lineUID = `${index}`;
|
||||
if (canvasCoordinates.length === 2) {
|
||||
const lineUID = `${index}`;
|
||||
drawing.drawLine(
|
||||
svgDrawingHelper,
|
||||
annotationUID,
|
||||
lineUID,
|
||||
canvasCoordinates[0],
|
||||
canvasCoordinates[1],
|
||||
{
|
||||
color: options.color,
|
||||
width: options.lineWidth,
|
||||
}
|
||||
drawingOptions
|
||||
);
|
||||
} else {
|
||||
throw new Error('Drawing polyline for SR not yet implemented');
|
||||
drawing.drawPolyline(
|
||||
svgDrawingHelper,
|
||||
annotationUID,
|
||||
lineUID,
|
||||
canvasCoordinates,
|
||||
drawingOptions
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
@ -367,6 +337,71 @@ export default class DICOMSRDisplayTool extends AnnotationTool {
|
||||
|
||||
return canvasCoordinates;
|
||||
}
|
||||
|
||||
renderTextBox(
|
||||
svgDrawingHelper,
|
||||
viewport,
|
||||
canvasCoordinates,
|
||||
canvasCoordinatesAdapter,
|
||||
annotation,
|
||||
styleSpecifier,
|
||||
options = {}
|
||||
) {
|
||||
if (!canvasCoordinates || !annotation) {
|
||||
return;
|
||||
}
|
||||
|
||||
const { annotationUID, data = {} } = annotation;
|
||||
const { label } = data;
|
||||
const { color } = options;
|
||||
|
||||
let adaptedCanvasCoordinates = canvasCoordinates;
|
||||
// adapt coordinates if there is an adapter
|
||||
if (typeof canvasCoordinatesAdapter === 'function') {
|
||||
adaptedCanvasCoordinates = canvasCoordinatesAdapter(canvasCoordinates);
|
||||
}
|
||||
const textLines = this._getTextBoxLinesFromLabels(label);
|
||||
const canvasTextBoxCoords = utilities.drawing.getTextBoxCoordsCanvas(
|
||||
adaptedCanvasCoordinates
|
||||
);
|
||||
|
||||
annotation.data.handles.textBox.worldPosition = viewport.canvasToWorld(
|
||||
canvasTextBoxCoords
|
||||
);
|
||||
|
||||
const textBoxPosition = viewport.worldToCanvas(
|
||||
annotation.data.handles.textBox.worldPosition
|
||||
);
|
||||
|
||||
const textBoxUID = '1';
|
||||
const textBoxOptions = this.getLinkedTextBoxStyle(
|
||||
styleSpecifier,
|
||||
annotation
|
||||
);
|
||||
|
||||
const boundingBox = drawing.drawLinkedTextBox(
|
||||
svgDrawingHelper,
|
||||
annotationUID,
|
||||
textBoxUID,
|
||||
textLines,
|
||||
textBoxPosition,
|
||||
canvasCoordinates,
|
||||
{},
|
||||
{
|
||||
...textBoxOptions,
|
||||
color,
|
||||
}
|
||||
);
|
||||
|
||||
const { x: left, y: top, width, height } = boundingBox;
|
||||
|
||||
annotation.data.handles.textBox.worldBoundingBox = {
|
||||
topLeft: viewport.canvasToWorld([left, top]),
|
||||
topRight: viewport.canvasToWorld([left + width, top]),
|
||||
bottomLeft: viewport.canvasToWorld([left, top + height]),
|
||||
bottomRight: viewport.canvasToWorld([left + width, top + height]),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
const SHORT_HAND_MAP = {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user