in pathology/viewer/src/services/dicom-annotations.service.ts [734:812]
private buildAnnotationGroupModel(
annotationGroup: AnnotationGroup, pixelSize: PixelSize): DicomModel {
const annotationGroupModel: DicomModel = {
[DicomTag.ANNOTATION_GROUP_NUMBER]:
dicomAttr('US', [annotationGroup.idNumber]),
[DicomTag.ANNOTATION_GROUP_UID]: dicomAttr(
'UI', annotationGroup.annotationGroupUid || this.generateUUID()),
[DicomTag.ANNOTATION_GROUP_LABEL]:
dicomAttr('LO', annotationGroup.annotationGroupLabel),
[DicomTag.ANNOTATION_GROUP_DESCRIPTION]:
dicomAttr('UT', annotationGroup.annotationGroupDescription),
[DicomTag.ANNOTATION_GROUP_GENERATION_TYPE]:
dicomAttr('CS', annotationGroup.annotationGroupGenerationType),
} as DicomModel;
if (annotationGroup.annotationPropertyCategoryCodeSequence?.length) {
annotationGroupModel[DicomTag
.ANNOTATION_PROPERTY_CATEGORY_CODE_SEQUENCE] =
dicomAttr(
'SQ',
[this.buildAnnotationPropertyCategoryCodeModel(
annotationGroup.annotationPropertyCategoryCodeSequence[0])]);
} else {
// Use default category
// dicom.nema.org/medical/dicom/current/output/chtml/part03/chapter_8.html#sect_8.1
const defaultCategory = {
'00080100': dicomAttr('SH', '91723000'), // Anatomical structure
'00080102': dicomAttr('SH', 'SCT'), // SNOMED CT code
'00080104': dicomAttr('LO', 'Anatomical structure'),
};
annotationGroupModel[DicomTag
.ANNOTATION_PROPERTY_CATEGORY_CODE_SEQUENCE] =
dicomAttr('SQ', [defaultCategory]);
}
// Hardcode a generic label until we give such option in to the user.
// The comment provided by the user represents the text meaning.
const propertyTypeCodeSequence = {
'00080100':
dicomAttr('SH', '395538009'), // Microscopic specimen observation
'00080102': dicomAttr('SH', 'SCT'), // SNOMED CT code
'00080104': dicomAttr('LO', annotationGroup.annotationGroupDescription),
};
annotationGroupModel[DicomTag.ANNOTATION_PROPERTY_TYPE_CODE_SEQUENCE] =
dicomAttr('SQ', [propertyTypeCodeSequence]);
annotationGroupModel[DicomTag.GRAPHIC_TYPE] =
dicomAttr('CS', annotationGroup.graphicType);
const pixelCoordinates = metersToPixelsWithYFlip(
annotationGroup.pointCoordinatesData, pixelSize);
const base64Coordinates = numberArrayToInlineBinary(
Float32Array,
isPolygonClockwise(pixelCoordinates) ?
pixelCoordinates :
flipPointOrder(pixelCoordinates));
annotationGroupModel[DicomTag.POINT_COORDINATES_DATA] = {
'InlineBinary': base64Coordinates,
'vr': 'OF'
} as Attribute;
const longPrimitivePointIndexList =
annotationGroup.longPrimitivePointIndexList;
const base64LongPrimitive =
numberArrayToInlineBinary(Int32Array, longPrimitivePointIndexList);
annotationGroupModel[DicomTag.LONG_PRIMITIVE_POINT_INDEX_LIST] = {
'InlineBinary': base64LongPrimitive,
'vr': 'OL'
} as Attribute;
annotationGroupModel[DicomTag.NUMBER_OF_ANNOTATIONS] =
dicomAttr('UL', [longPrimitivePointIndexList.length]);
annotationGroupModel[DicomTag.ANNOTATION_APPLIES_TO_ALL_OPTICAL_PATHS] =
dicomAttr('CS', 'YES');
return annotationGroupModel;
}