Work from Medken branch
This commit is contained in:
1 parent
bee1e38044
commit
31d34a3fb5
12 files changed
+944
-557
No files matched your search
@@ -0,0 +1,273 @@
|
||||
|
||||
/**
|
||||
* This is a temporary function which will return a hardcoded hanging protocol as a JavaScript object
|
||||
* The purpose of this is to act as a stub until we are actually parsing DICOM Hanging Protocol files,
|
||||
* since Orthanc doesn't seem to support them yet.
|
||||
*
|
||||
* Soon we will be using instanceDataToJsObject to produce this object from the HangingProtocol WADO
|
||||
* instance
|
||||
*
|
||||
*/
|
||||
function getMammoHangingProtocol() {
|
||||
var tagValues = {
|
||||
HangingProtocolStorage: '1.2.840.10008.5.1.4.38.1'
|
||||
};
|
||||
|
||||
var protocol = {
|
||||
sopClassUid: tagValues.HangingProtocolStorage,
|
||||
sopInstanceUid: '1.2.840.113986.2.664566.21121125.85669.911', // A random Uid
|
||||
hangingProtocolName: 'MammoCadProtocol',
|
||||
hangingProtocolDescription: 'Mammography screening protocol',
|
||||
hangingProtocolLevel: 'SITE',
|
||||
hangingProtocolCreator: 'Erik',
|
||||
hangingProtocolCreationDateTime: '20020101104200',
|
||||
hangingProtocolDefinitionSequence: [{
|
||||
modality: 'MG',
|
||||
laterality: '',
|
||||
procedureCodeSequence: {
|
||||
codeValue: 98765,
|
||||
codingSchemeDesignator: '99Local',
|
||||
codingSchemeVersion: 1.5,
|
||||
codeMeaning: 'Mammogram'
|
||||
},
|
||||
anatomicRegionSequence: {
|
||||
codeValue: 'T-D1100',
|
||||
codingSchemeDesignator: 'SNM3',
|
||||
codeMeaning: 'BREAST'
|
||||
},
|
||||
reasonForRequestedProcedureCodeSequence: {
|
||||
codeValue: 'I67.1',
|
||||
codingSchemeDesignator: 'I10',
|
||||
codeMeaning: 'Calcification'
|
||||
}
|
||||
}],
|
||||
hangingProtocolUserIdentificationCodeSequence: [],
|
||||
hangingProtocolUserGroupName: 'ABC Hospital',
|
||||
numberOfPriorsReferenced: 1,
|
||||
imageSetsSequence: [{
|
||||
imageSetSelectorSequence: [{
|
||||
ImageSetSelectorUsageFlag: 'NO_MATCH',
|
||||
SelectorAttribute: '00180015',
|
||||
SelectorValueNumber: '1',
|
||||
SelectorAttributeVR: 'CS',
|
||||
SelectorCSValue: 'BREAST'
|
||||
}],
|
||||
timeBasedImageSetsSequence: [{
|
||||
ImageSetNumber: 1,
|
||||
ImageSetSelectorCategory: 'RELATIVE_TIME',
|
||||
RelativeTime: '0\0',
|
||||
RelativeTimeUnits: 'MINUTES',
|
||||
ImageSetLabel: 'Current MG Breast'
|
||||
},
|
||||
{
|
||||
ImageSetNumber: 2,
|
||||
ImageSetSelectorCategory: 'ABSTRACT_PRIOR',
|
||||
AbstractPriorValue: '1\\1',
|
||||
ImageSetLabel: 'Prior MG Breast'
|
||||
}]
|
||||
}],
|
||||
// Skip Number of Screens for now,
|
||||
// Skip Nominal Screen Definition Sequence for now,
|
||||
|
||||
// http://dicom.nema.org/medical/dicom/current/output/chtml/part03/sect_C.23.3.html
|
||||
DisplaySetsSequence: [
|
||||
{
|
||||
// Left side image (R MLO Current)
|
||||
ImageSetNumber: 1,
|
||||
DisplaySetNumber: 1,
|
||||
DisplaySetPresentationGroup: 1,
|
||||
DisplaySetPresentationGroupDescription: 'Current Mediolateral only',
|
||||
ImageBoxesSequence: [{
|
||||
DisplayEnvironmentSpatialPosition: '0\0.2\0.16667\0',
|
||||
ImageBoxNumber: 1,
|
||||
ImageBoxLayoutType: 'STACK'
|
||||
}],
|
||||
FilterOperationsSequence: [{
|
||||
SelectorAttributeVR: 'CS',
|
||||
SelectorCSValue: 'R CC',
|
||||
FilterByCategory: 'SERIES_DESCRIPTION',
|
||||
FilterByOperator: 'MEMBER_OF'
|
||||
}]
|
||||
}, {
|
||||
// Right side image (L MLO Current)
|
||||
ImageSetNumber: 1,
|
||||
DisplaySetNumber: 1,
|
||||
DisplaySetPresentationGroup: 1,
|
||||
ImageBoxesSequence: [{
|
||||
ImageBoxNumber: 1,
|
||||
ImageBoxLayoutType: 'STACK'
|
||||
}],
|
||||
FilterOperationsSequence: [{
|
||||
SelectorAttributeVR: 'CS',
|
||||
SelectorCSValue: 'L CC',
|
||||
FilterByCategory: 'SERIES_DESCRIPTION',
|
||||
FilterByOperator: 'MEMBER_OF'
|
||||
}]
|
||||
},
|
||||
{
|
||||
// Left side image (R MLO Current)
|
||||
ImageSetNumber: 1,
|
||||
DisplaySetNumber: 1,
|
||||
DisplaySetPresentationGroup: 2,
|
||||
DisplaySetPresentationGroupDescription: 'Current Mediolateral only',
|
||||
ImageBoxesSequence: [{
|
||||
DisplayEnvironmentSpatialPosition: '0\0.2\0.16667\0',
|
||||
ImageBoxNumber: 1,
|
||||
ImageBoxLayoutType: 'STACK'
|
||||
}],
|
||||
FilterOperationsSequence: [{
|
||||
SelectorAttributeVR: 'CS',
|
||||
SelectorCSValue: 'R MLO',
|
||||
FilterByCategory: 'SERIES_DESCRIPTION',
|
||||
FilterByOperator: 'MEMBER_OF'
|
||||
}],
|
||||
ReformattingOperationType: '',
|
||||
ReformattingThickness: '',
|
||||
ReformattingInterval: '',
|
||||
ReformattingOperationInitialViewDirection: '',
|
||||
SortingOperationsSequence: [],
|
||||
DisplaySetPatientOrientation: '',
|
||||
VOIType: ''
|
||||
}, {
|
||||
// Right side image (L MLO Current)
|
||||
ImageSetNumber: 1,
|
||||
DisplaySetNumber: 1,
|
||||
DisplaySetPresentationGroup: 2,
|
||||
ImageBoxesSequence: [{
|
||||
ImageBoxNumber: 1,
|
||||
ImageBoxLayoutType: 'STACK'
|
||||
}],
|
||||
FilterOperationsSequence: [{
|
||||
SelectorAttributeVR: 'CS',
|
||||
SelectorCSValue: 'L MLO',
|
||||
FilterByCategory: 'SERIES_DESCRIPTION',
|
||||
FilterByOperator: 'MEMBER_OF'
|
||||
}]
|
||||
}, {
|
||||
// Testing purposes
|
||||
// Left side image (R MLO Current)
|
||||
ImageSetNumber: 1,
|
||||
DisplaySetNumber: 1,
|
||||
DisplaySetPresentationGroup: 3,
|
||||
DisplaySetPresentationGroupDescription: 'Current Mediolateral only',
|
||||
ImageBoxesSequence: [{
|
||||
DisplayEnvironmentSpatialPosition: '0\0.2\0.16667\0',
|
||||
ImageBoxNumber: 1,
|
||||
ImageBoxLayoutType: 'STACK'
|
||||
}],
|
||||
FilterOperationsSequence: [{
|
||||
SelectorAttributeVR: 'CS',
|
||||
SelectorCSValue: 'R MLO',
|
||||
FilterByCategory: 'SERIES_DESCRIPTION',
|
||||
FilterByOperator: 'MEMBER_OF'
|
||||
}]
|
||||
}, {
|
||||
// Right side image (R CC Current)
|
||||
ImageSetNumber: 1,
|
||||
DisplaySetNumber: 1,
|
||||
DisplaySetPresentationGroup: 3,
|
||||
ImageBoxesSequence: [{
|
||||
ImageBoxNumber: 1,
|
||||
ImageBoxLayoutType: 'STACK'
|
||||
}],
|
||||
FilterOperationsSequence: [{
|
||||
SelectorAttributeVR: 'CS',
|
||||
SelectorCSValue: 'R CC',
|
||||
FilterByCategory: 'SERIES_DESCRIPTION',
|
||||
FilterByOperator: 'MEMBER_OF'
|
||||
}]
|
||||
}],
|
||||
PartialDataDisplayHandling: 'MAINTAIN_LAYOUT',
|
||||
SynchronizedScrollingSequence: [],
|
||||
NavigationIndicatorSequence: []
|
||||
};
|
||||
|
||||
return protocol;
|
||||
}
|
||||
|
||||
function findSetsByPresentationGroup(DisplaySetsSequence, DisplaySetPresentationGroup) {
|
||||
var presentationGroupSets = [];
|
||||
DisplaySetsSequence.forEach(function(displaySet) {
|
||||
if (displaySet.DisplaySetPresentationGroup === DisplaySetPresentationGroup) {
|
||||
presentationGroupSets.push(displaySet);
|
||||
}
|
||||
});
|
||||
return presentationGroupSets;
|
||||
}
|
||||
|
||||
function findStudy(displaySet, studies) {
|
||||
// Placeholder for now
|
||||
return studies.find().fetch()[0].studyInstanceUid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Uses the FilterOperationsSequence information to find
|
||||
* the relevant series for display in this display set
|
||||
*
|
||||
* @param displaySet
|
||||
* @param study
|
||||
* @returns {String} The instance Uid of the series to be displayed
|
||||
*/
|
||||
function findSeries(displaySet, study) {
|
||||
var categoryDictionary = {
|
||||
SERIES_DESCRIPTION: 'seriesDescription'
|
||||
};
|
||||
|
||||
// TODO=Put these inside a loop? We need to support multiple filter operations,
|
||||
// not just one
|
||||
var filterBy = displaySet.FilterOperationsSequence[0].FilterByCategory;
|
||||
var selectorValue = displaySet.FilterOperationsSequence[0].SelectorCSValue;
|
||||
var filterType = displaySet.FilterOperationsSequence[0].FilterByOperator;
|
||||
var category = categoryDictionary[filterBy];
|
||||
|
||||
var seriesInstanceUid;
|
||||
study.seriesList.forEach(function(series) {
|
||||
// TODO = Add other FilterBy operators
|
||||
if (filterType === 'MEMBER_OF') {
|
||||
if (series[category] === selectorValue) {
|
||||
seriesInstanceUid = series.seriesInstanceUid;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return seriesInstanceUid;
|
||||
}
|
||||
|
||||
/**
|
||||
* (Work in progress) Uses the information from a DICOM Hanging Protocol
|
||||
* to identify and display studies and series in the image viewer
|
||||
*
|
||||
* @param hangingProtocol
|
||||
* @param inputData
|
||||
* @returns {Array} Array of viewport data to be displayed
|
||||
*/
|
||||
function applyDICOMHangingProtocol(hangingProtocol, inputData) {
|
||||
log.info('applyDICOMHangingProtocol');
|
||||
var presentationGroup = inputData.DisplaySetPresentationGroup || 1;
|
||||
var studies = ViewerStudies;
|
||||
var currentDisplaySets = findSetsByPresentationGroup(hangingProtocol.DisplaySetsSequence, presentationGroup);
|
||||
|
||||
var viewportData = {
|
||||
viewports: []
|
||||
};
|
||||
|
||||
currentDisplaySets.forEach(function(displaySet, index) {
|
||||
// TODO= Find study information by image set properties and
|
||||
// image set number of this display set
|
||||
var ImageSetNumber = displaySet.ImageSetNumber;
|
||||
|
||||
studyInstanceUid = findStudy(displaySet, studies);
|
||||
|
||||
var study = ViewerStudies.findOne({studyInstanceUid: studyInstanceUid});
|
||||
seriesInstanceUid = findSeries(displaySet, study);
|
||||
|
||||
viewportData.viewports[index] = {
|
||||
seriesInstanceUid: seriesInstanceUid,
|
||||
studyInstanceUid: studyInstanceUid,
|
||||
currentImageIdIndex: 0
|
||||
};
|
||||
});
|
||||
|
||||
return viewportData;
|
||||
}
|
||||
@@ -0,0 +1,172 @@
|
||||
/**
|
||||
* This is a temporary function which will return a hardcoded hanging protocol as a JavaScript object
|
||||
*/
|
||||
getMammoHangingProtocolObject = function() {
|
||||
var protocol = {
|
||||
// Need to expand this to allow real searches for studies
|
||||
studiesNeeded: [
|
||||
'current',
|
||||
'prior'
|
||||
],
|
||||
primaryModality: 'MG',
|
||||
stages: [{
|
||||
stage: 1,
|
||||
rows: 2,
|
||||
columns: 4,
|
||||
viewports: [{
|
||||
seriesDescription: 'RCC',
|
||||
study: 'prior'
|
||||
}, {
|
||||
seriesDescription: 'LCC',
|
||||
study: 'prior'
|
||||
}, {
|
||||
seriesDescription: 'RMLO',
|
||||
study: 'prior'
|
||||
}, {
|
||||
seriesDescription: 'LMLO',
|
||||
study: 'prior'
|
||||
}, {
|
||||
seriesDescription: 'RCC',
|
||||
study: 'current'
|
||||
}, {
|
||||
seriesDescription: 'LCC',
|
||||
study: 'current'
|
||||
}, {
|
||||
seriesDescription: 'RMLO',
|
||||
study: 'current'
|
||||
}, {
|
||||
seriesDescription: 'LMLO',
|
||||
study: 'current'
|
||||
}
|
||||
]
|
||||
}, {
|
||||
stage: 2,
|
||||
rows: 1,
|
||||
columns: 2,
|
||||
viewports: [{
|
||||
seriesDescription: 'RCC',
|
||||
study: 'current'
|
||||
}, {
|
||||
seriesDescription: 'LCC',
|
||||
study: 'current'
|
||||
}
|
||||
]
|
||||
}, {
|
||||
stage: 3,
|
||||
rows: 1,
|
||||
columns: 2,
|
||||
viewports: [{
|
||||
seriesDescription: 'RMLO',
|
||||
study: 'current'
|
||||
}, {
|
||||
seriesDescription: 'LMLO',
|
||||
study: 'current'
|
||||
}
|
||||
]
|
||||
}, {
|
||||
stage: 4,
|
||||
rows: 1,
|
||||
columns: 2,
|
||||
viewports: [{
|
||||
seriesDescription: 'RCC',
|
||||
study: 'current'
|
||||
}, {
|
||||
seriesDescription: 'RCC',
|
||||
study: 'prior'
|
||||
}
|
||||
]
|
||||
}, {
|
||||
stage: 5,
|
||||
rows: 1,
|
||||
columns: 2,
|
||||
viewports: [{
|
||||
seriesDescription: 'LCC',
|
||||
study: 'current'
|
||||
}, {
|
||||
seriesDescription: 'LCC',
|
||||
study: 'prior'
|
||||
}
|
||||
]
|
||||
}, {
|
||||
stage: 6,
|
||||
rows: 1,
|
||||
columns: 2,
|
||||
viewports: [{
|
||||
seriesDescription: 'LMLO',
|
||||
study: 'current'
|
||||
}, {
|
||||
seriesDescription: 'LMLO',
|
||||
study: 'prior'
|
||||
}
|
||||
]
|
||||
}, {
|
||||
stage: 7,
|
||||
rows: 1,
|
||||
columns: 2,
|
||||
viewports: [{
|
||||
seriesDescription: 'RMLO',
|
||||
study: 'current'
|
||||
}, {
|
||||
seriesDescription: 'RMLO',
|
||||
study: 'prior'
|
||||
}
|
||||
]
|
||||
}, {
|
||||
stage: 8,
|
||||
rows: 2,
|
||||
columns: 4,
|
||||
viewports: [{
|
||||
seriesDescription: 'RCC',
|
||||
study: 'prior',
|
||||
options: {
|
||||
includeCADMarkers: true
|
||||
}
|
||||
}, {
|
||||
seriesDescription: 'LCC',
|
||||
study: 'prior',
|
||||
options: {
|
||||
includeCADMarkers: true
|
||||
}
|
||||
}, {
|
||||
seriesDescription: 'RMLO',
|
||||
study: 'prior',
|
||||
options: {
|
||||
includeCADMarkers: true
|
||||
}
|
||||
}, {
|
||||
seriesDescription: 'LMLO',
|
||||
study: 'prior',
|
||||
options: {
|
||||
includeCADMarkers: true
|
||||
}
|
||||
}, {
|
||||
seriesDescription: 'RCC',
|
||||
study: 'current',
|
||||
options: {
|
||||
includeCADMarkers: true
|
||||
}
|
||||
}, {
|
||||
seriesDescription: 'LCC',
|
||||
study: 'current',
|
||||
options: {
|
||||
includeCADMarkers: true
|
||||
}
|
||||
}, {
|
||||
seriesDescription: 'RMLO',
|
||||
study: 'current',
|
||||
options: {
|
||||
includeCADMarkers: true
|
||||
}
|
||||
}, {
|
||||
seriesDescription: 'LMLO',
|
||||
study: 'current',
|
||||
options: {
|
||||
includeCADMarkers: true
|
||||
}
|
||||
}
|
||||
]
|
||||
}]
|
||||
};
|
||||
|
||||
return protocol;
|
||||
};
|
||||
@@ -0,0 +1,14 @@
|
||||
var modalityViewportSettingsFunctions = {};
|
||||
getModalityDefaultViewport = function(series, enabledElement, imageId) {
|
||||
var modality = series.modality;
|
||||
|
||||
if (!modalityViewportSettingsFunctions[modality]) {
|
||||
return;
|
||||
}
|
||||
|
||||
return modalityViewportSettingsFunctions[modality](series, enabledElement, imageId);
|
||||
};
|
||||
|
||||
setModalityDefaultViewportFunction = function(modality, fn) {
|
||||
modalityViewportSettingsFunctions[modality] = fn;
|
||||
};
|
||||
File diff suppressed because it is too large.
Load diff
Reference in new issue
Block a user