[OHIF-288] Rehydrating SRs is missing Labels (#1885)
* WIP * Finish OHIF-288, need to update dcmjs. * Remove unused copied resources. * Cleaned up label import code. * Update for dcmjs Findings -> Finding. * Update dcmjs * Remove debuggers * Respond to reviewer comments. * update dcmjs version Co-authored-by: Danny Brown <danny.ri.brown@gmail.com>
This commit is contained in:
parent
ce40f04f2e
commit
3eba027003
@ -35,7 +35,7 @@
|
|||||||
"cornerstone-math": "^0.1.8",
|
"cornerstone-math": "^0.1.8",
|
||||||
"cornerstone-tools": "4.18.1",
|
"cornerstone-tools": "4.18.1",
|
||||||
"cornerstone-wado-image-loader": "^3.1.2",
|
"cornerstone-wado-image-loader": "^3.1.2",
|
||||||
"dcmjs": "0.14.2",
|
"dcmjs": "0.16.0",
|
||||||
"dicom-parser": "^1.8.3",
|
"dicom-parser": "^1.8.3",
|
||||||
"hammerjs": "^2.0.8",
|
"hammerjs": "^2.0.8",
|
||||||
"prop-types": "^15.6.2",
|
"prop-types": "^15.6.2",
|
||||||
|
|||||||
@ -34,7 +34,7 @@
|
|||||||
"react": "^16.13.1",
|
"react": "^16.13.1",
|
||||||
"react-dom": "^16.13.1",
|
"react-dom": "^16.13.1",
|
||||||
"webpack": "^4.0.0",
|
"webpack": "^4.0.0",
|
||||||
"dcmjs": "0.14.2"
|
"dcmjs": "0.16.0"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/runtime": "7.7.6"
|
"@babel/runtime": "7.7.6"
|
||||||
|
|||||||
@ -28,7 +28,7 @@
|
|||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"@ohif/core": "^0.50.0",
|
"@ohif/core": "^0.50.0",
|
||||||
"dcmjs": "0.14.2",
|
"dcmjs": "0.16.0",
|
||||||
"prop-types": "^15.6.2",
|
"prop-types": "^15.6.2",
|
||||||
"react": "^16.11.0",
|
"react": "^16.11.0",
|
||||||
"react-dom": "^16.11.0"
|
"react-dom": "^16.11.0"
|
||||||
|
|||||||
@ -31,7 +31,7 @@
|
|||||||
"@ohif/core": "^0.50.0",
|
"@ohif/core": "^0.50.0",
|
||||||
"cornerstone-core": "^2.2.8",
|
"cornerstone-core": "^2.2.8",
|
||||||
"cornerstone-tools": "4.18.1",
|
"cornerstone-tools": "4.18.1",
|
||||||
"dcmjs": "0.14.2",
|
"dcmjs": "0.16.0",
|
||||||
"prop-types": "^15.6.2",
|
"prop-types": "^15.6.2",
|
||||||
"react": "^16.8.6",
|
"react": "^16.8.6",
|
||||||
"react-dom": "^16.8.6"
|
"react-dom": "^16.8.6"
|
||||||
|
|||||||
@ -31,7 +31,7 @@
|
|||||||
"@ohif/core": "^0.50.0",
|
"@ohif/core": "^0.50.0",
|
||||||
"cornerstone-core": "^2.2.8",
|
"cornerstone-core": "^2.2.8",
|
||||||
"cornerstone-tools": "4.18.1",
|
"cornerstone-tools": "4.18.1",
|
||||||
"dcmjs": "0.14.2",
|
"dcmjs": "0.16.0",
|
||||||
"prop-types": "^15.6.2",
|
"prop-types": "^15.6.2",
|
||||||
"react": "^16.8.6",
|
"react": "^16.8.6",
|
||||||
"react-dom": "^16.8.6"
|
"react-dom": "^16.8.6"
|
||||||
|
|||||||
@ -35,7 +35,7 @@
|
|||||||
"cornerstone-math": "^0.1.8",
|
"cornerstone-math": "^0.1.8",
|
||||||
"cornerstone-tools": "4.18.1",
|
"cornerstone-tools": "4.18.1",
|
||||||
"cornerstone-wado-image-loader": "^3.1.2",
|
"cornerstone-wado-image-loader": "^3.1.2",
|
||||||
"dcmjs": "0.14.2",
|
"dcmjs": "0.16.0",
|
||||||
"dicom-parser": "^1.8.3",
|
"dicom-parser": "^1.8.3",
|
||||||
"hammerjs": "^2.0.8",
|
"hammerjs": "^2.0.8",
|
||||||
"prop-types": "^15.6.2",
|
"prop-types": "^15.6.2",
|
||||||
|
|||||||
@ -8,6 +8,7 @@ import { ViewportActionBar, useViewportGrid } from '@ohif/ui';
|
|||||||
import TOOL_NAMES from './constants/toolNames';
|
import TOOL_NAMES from './constants/toolNames';
|
||||||
import { adapters } from 'dcmjs';
|
import { adapters } from 'dcmjs';
|
||||||
import getToolStateToCornerstoneMeasurementSchema from './utils/getToolStateToCornerstoneMeasurementSchema';
|
import getToolStateToCornerstoneMeasurementSchema from './utils/getToolStateToCornerstoneMeasurementSchema';
|
||||||
|
import getLabelFromDCMJSImportedToolData from './utils/getLabelFromDCMJSImportedToolData';
|
||||||
import id from './id';
|
import id from './id';
|
||||||
|
|
||||||
const { formatDate } = utils;
|
const { formatDate } = utils;
|
||||||
@ -376,6 +377,8 @@ function OHIFCornerstoneSRViewport({
|
|||||||
|
|
||||||
const source = MeasurementService.getSource('CornerstoneTools', '4');
|
const source = MeasurementService.getSource('CornerstoneTools', '4');
|
||||||
|
|
||||||
|
data.label = getLabelFromDCMJSImportedToolData(data);
|
||||||
|
|
||||||
MeasurementService.addRawMeasurement(
|
MeasurementService.addRawMeasurement(
|
||||||
source,
|
source,
|
||||||
toolType,
|
toolType,
|
||||||
|
|||||||
@ -25,13 +25,19 @@ const CodeNameCodeSequenceValues = {
|
|||||||
TrackingUniqueIdentifier: '112040',
|
TrackingUniqueIdentifier: '112040',
|
||||||
TrackingIdentifier: '112039',
|
TrackingIdentifier: '112039',
|
||||||
Finding: '121071',
|
Finding: '121071',
|
||||||
|
FindingSite: 'G-C0E3', // SRT
|
||||||
|
CornerstoneFreeText: 'CORNERSTONEFREETEXT', // CST4
|
||||||
|
};
|
||||||
|
|
||||||
|
const CodingSchemeDesignators = {
|
||||||
|
SRT: 'SRT',
|
||||||
|
cornerstoneTools4: 'CST4',
|
||||||
};
|
};
|
||||||
|
|
||||||
const RELATIONSHIP_TYPE = {
|
const RELATIONSHIP_TYPE = {
|
||||||
INFERRED_FROM: 'INFERRED FROM',
|
INFERRED_FROM: 'INFERRED FROM',
|
||||||
};
|
};
|
||||||
|
|
||||||
const CORNERSTONE_CODING_SCHEME_DESIGNATOR = 'CST4';
|
|
||||||
const CORNERSTONE_FREETEXT_CODE_VALUE = 'CORNERSTONEFREETEXT';
|
const CORNERSTONE_FREETEXT_CODE_VALUE = 'CORNERSTONEFREETEXT';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -428,12 +434,20 @@ function _processNonGeometricallyDefinedMeasurement(mergedContentSequence) {
|
|||||||
CodeNameCodeSequenceValues.TrackingIdentifier
|
CodeNameCodeSequenceValues.TrackingIdentifier
|
||||||
);
|
);
|
||||||
|
|
||||||
const Findings = mergedContentSequence.filter(
|
const Finding = mergedContentSequence.find(
|
||||||
item =>
|
item =>
|
||||||
item.ConceptNameCodeSequence.CodeValue ===
|
item.ConceptNameCodeSequence.CodeValue ===
|
||||||
CodeNameCodeSequenceValues.Finding
|
CodeNameCodeSequenceValues.Finding
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const FindingSites = mergedContentSequence.filter(
|
||||||
|
item =>
|
||||||
|
item.ConceptNameCodeSequence.CodingSchemeDesignator ===
|
||||||
|
CodingSchemeDesignators.SRT &&
|
||||||
|
item.ConceptNameCodeSequence.CodeValue ===
|
||||||
|
CodeNameCodeSequenceValues.FindingSite
|
||||||
|
);
|
||||||
|
|
||||||
const measurement = {
|
const measurement = {
|
||||||
loaded: false,
|
loaded: false,
|
||||||
labels: [],
|
labels: [],
|
||||||
@ -442,19 +456,33 @@ function _processNonGeometricallyDefinedMeasurement(mergedContentSequence) {
|
|||||||
TrackingIdentifier: TrackingIdentifierContentItem.TextValue,
|
TrackingIdentifier: TrackingIdentifierContentItem.TextValue,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (Findings.length) {
|
if (
|
||||||
// TODO -> Pull in labels when we have them, just free text for now.
|
Finding &&
|
||||||
const cornerstoneFreeTextFinding = Findings.find(
|
|
||||||
Finding =>
|
|
||||||
Finding.ConceptCodeSequence.CodingSchemeDesignator ===
|
Finding.ConceptCodeSequence.CodingSchemeDesignator ===
|
||||||
CORNERSTONE_CODING_SCHEME_DESIGNATOR &&
|
CodingSchemeDesignators.cornerstoneTools4 &&
|
||||||
Finding.ConceptCodeSequence.CodeValue ===
|
Finding.ConceptCodeSequence.CodeValue ===
|
||||||
CORNERSTONE_FREETEXT_CODE_VALUE
|
CodeNameCodeSequenceValues.CornerstoneFreeText
|
||||||
);
|
) {
|
||||||
if (cornerstoneFreeTextFinding) {
|
|
||||||
measurement.labels.push({
|
measurement.labels.push({
|
||||||
label: CORNERSTONE_FREETEXT_CODE_VALUE,
|
label: CORNERSTONE_FREETEXT_CODE_VALUE,
|
||||||
value: cornerstoneFreeTextFinding.ConceptCodeSequence.CodeMeaning,
|
value: Finding.ConceptCodeSequence.CodeMeaning,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO -> Eventually hopefully support SNOMED or some proper code library, just free text for now.
|
||||||
|
if (FindingSites.length) {
|
||||||
|
const cornerstoneFreeTextFindingSite = FindingSites.find(
|
||||||
|
FindingSite =>
|
||||||
|
FindingSite.ConceptCodeSequence.CodingSchemeDesignator ===
|
||||||
|
CodingSchemeDesignators.cornerstoneTools4 &&
|
||||||
|
FindingSite.ConceptCodeSequence.CodeValue ===
|
||||||
|
CodeNameCodeSequenceValues.CornerstoneFreeText
|
||||||
|
);
|
||||||
|
|
||||||
|
if (cornerstoneFreeTextFindingSite) {
|
||||||
|
measurement.labels.push({
|
||||||
|
label: CORNERSTONE_FREETEXT_CODE_VALUE,
|
||||||
|
value: cornerstoneFreeTextFindingSite.ConceptCodeSequence.CodeMeaning,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -280,10 +280,9 @@ export default class DICOMSRDisplayTool extends BaseTool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function _getTextBoxLinesFromLabels(labels) {
|
function _getTextBoxLinesFromLabels(labels) {
|
||||||
// TODO -> max 2 for now, need a generic solution for this!
|
// TODO -> max 3 for now (label + shortAxis + longAxis), need a generic solution for this!
|
||||||
|
|
||||||
const labelLength = Math.min(labels.length, 2);
|
|
||||||
|
|
||||||
|
const labelLength = Math.min(labels.length, 3);
|
||||||
const lines = [];
|
const lines = [];
|
||||||
|
|
||||||
for (let i = 0; i < labelLength; i++) {
|
for (let i = 0; i < labelLength; i++) {
|
||||||
|
|||||||
@ -0,0 +1,23 @@
|
|||||||
|
/**
|
||||||
|
* Extracts the label from the toolData imported from dcmjs. We need to do this
|
||||||
|
* as dcmjs does not depeend on OHIF/the MeasurementService, it just produces data for cornestoneTools.
|
||||||
|
* This optional data is available for the consumer to process if they wish to.
|
||||||
|
* @param {object} toolData The tooldata relating to the
|
||||||
|
*
|
||||||
|
* @returns {string} The extracted label.
|
||||||
|
*/
|
||||||
|
export default function getLabelFromDCMJSImportedToolData(toolData) {
|
||||||
|
const { findingSites = [], finding } = toolData;
|
||||||
|
|
||||||
|
let freeTextLabel = findingSites.find(
|
||||||
|
fs => fs.CodeValue === 'CORNERSTONEFREETEXT'
|
||||||
|
);
|
||||||
|
|
||||||
|
if (freeTextLabel) {
|
||||||
|
return freeTextLabel.CodeMeaning;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (finding && finding.CodeValue === 'CORNERSTONEFREETEXT') {
|
||||||
|
return finding.CodeMeaning;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -51,7 +51,7 @@ function Length(measurementData, imageId, _getValueTypeFromToolType) {
|
|||||||
StudyInstanceUID,
|
StudyInstanceUID,
|
||||||
} = instance;
|
} = instance;
|
||||||
|
|
||||||
const { handles } = measurementData;
|
const { handles, label } = measurementData;
|
||||||
|
|
||||||
const points = [];
|
const points = [];
|
||||||
Object.keys(handles).map(handle => {
|
Object.keys(handles).map(handle => {
|
||||||
@ -75,6 +75,7 @@ function Length(measurementData, imageId, _getValueTypeFromToolType) {
|
|||||||
length: measurementData.length,
|
length: measurementData.length,
|
||||||
type: _getValueTypeFromToolType(tool),
|
type: _getValueTypeFromToolType(tool),
|
||||||
points,
|
points,
|
||||||
|
label,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -88,7 +89,7 @@ function Bidirectional(measurementData, imageId, _getValueTypeFromToolType) {
|
|||||||
StudyInstanceUID,
|
StudyInstanceUID,
|
||||||
} = instance;
|
} = instance;
|
||||||
|
|
||||||
const { handles } = measurementData;
|
const { handles, label } = measurementData;
|
||||||
|
|
||||||
const longAxis = [handles.start, handles.end];
|
const longAxis = [handles.start, handles.end];
|
||||||
const shortAxis = [handles.perpendicularStart, handles.perpendicularEnd];
|
const shortAxis = [handles.perpendicularStart, handles.perpendicularEnd];
|
||||||
@ -106,6 +107,7 @@ function Bidirectional(measurementData, imageId, _getValueTypeFromToolType) {
|
|||||||
longestDiameter: measurementData.longestDiameter,
|
longestDiameter: measurementData.longestDiameter,
|
||||||
type: _getValueTypeFromToolType(tool),
|
type: _getValueTypeFromToolType(tool),
|
||||||
points: { longAxis, shortAxis },
|
points: { longAxis, shortAxis },
|
||||||
|
label,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -119,7 +121,8 @@ function EllipticalRoi(measurementData, imageId, _getValueTypeFromToolType) {
|
|||||||
StudyInstanceUID,
|
StudyInstanceUID,
|
||||||
} = instance;
|
} = instance;
|
||||||
|
|
||||||
const { start, end } = measurementData.handles;
|
const { handles, label } = measurementData;
|
||||||
|
const { start, end } = handles;
|
||||||
|
|
||||||
const halfXLength = Math.abs(start.x - end.x) / 2;
|
const halfXLength = Math.abs(start.x - end.x) / 2;
|
||||||
const halfYLength = Math.abs(start.y - end.y) / 2;
|
const halfYLength = Math.abs(start.y - end.y) / 2;
|
||||||
@ -161,6 +164,7 @@ function EllipticalRoi(measurementData, imageId, _getValueTypeFromToolType) {
|
|||||||
.area /* TODO: Add concept names instead (descriptor) */,
|
.area /* TODO: Add concept names instead (descriptor) */,
|
||||||
type: _getValueTypeFromToolType(tool),
|
type: _getValueTypeFromToolType(tool),
|
||||||
points,
|
points,
|
||||||
|
label,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -198,5 +202,6 @@ function ArrowAnnotate(measurementData, imageId, _getValueTypeFromToolType) {
|
|||||||
text: measurementData.text,
|
text: measurementData.text,
|
||||||
type: _getValueTypeFromToolType(tool),
|
type: _getValueTypeFromToolType(tool),
|
||||||
points,
|
points,
|
||||||
|
label,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@ -29,7 +29,7 @@
|
|||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"@ohif/core": "^0.50.0",
|
"@ohif/core": "^0.50.0",
|
||||||
"cornerstone-tools": "4.18.1",
|
"cornerstone-tools": "4.18.1",
|
||||||
"dcmjs": "0.14.2",
|
"dcmjs": "0.16.0",
|
||||||
"prop-types": "^15.6.2",
|
"prop-types": "^15.6.2",
|
||||||
"react": "^16.13.1",
|
"react": "^16.13.1",
|
||||||
"react-dom": "^16.13.1",
|
"react-dom": "^16.13.1",
|
||||||
|
|||||||
@ -18,7 +18,8 @@ async function createReportAsync(servicesManager, dataSource, measurements) {
|
|||||||
try {
|
try {
|
||||||
const naturalizedReport = await DICOMSR.storeMeasurements(
|
const naturalizedReport = await DICOMSR.storeMeasurements(
|
||||||
measurements,
|
measurements,
|
||||||
dataSource
|
dataSource,
|
||||||
|
['ArrowAnnotate']
|
||||||
);
|
);
|
||||||
|
|
||||||
DisplaySetService.makeDisplaySets([naturalizedReport], {
|
DisplaySetService.makeDisplaySets([naturalizedReport], {
|
||||||
|
|||||||
@ -147,8 +147,6 @@ function PanelMeasurementTableTracking({ servicesManager, extensionManager }) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function exportReport() {
|
function exportReport() {
|
||||||
const dataSources = extensionManager.getDataSources();
|
|
||||||
const dataSource = dataSources[0];
|
|
||||||
const measurements = MeasurementService.getMeasurements();
|
const measurements = MeasurementService.getMeasurements();
|
||||||
const trackedMeasurements = measurements.filter(
|
const trackedMeasurements = measurements.filter(
|
||||||
m =>
|
m =>
|
||||||
@ -156,8 +154,9 @@ function PanelMeasurementTableTracking({ servicesManager, extensionManager }) {
|
|||||||
trackedSeries.includes(m.referenceSeriesUID)
|
trackedSeries.includes(m.referenceSeriesUID)
|
||||||
);
|
);
|
||||||
|
|
||||||
// TODO -> local download.
|
const additionalFindings = ['ArrowAnnotate'];
|
||||||
DICOMSR.downloadReport(trackedMeasurements, dataSource);
|
|
||||||
|
DICOMSR.downloadReport(trackedMeasurements, additionalFindings);
|
||||||
}
|
}
|
||||||
|
|
||||||
const jumpToImage = ({ id, isActive }) => {
|
const jumpToImage = ({ id, isActive }) => {
|
||||||
|
|||||||
@ -33,7 +33,7 @@
|
|||||||
"@ohif/ui": "^2.0.0",
|
"@ohif/ui": "^2.0.0",
|
||||||
"cornerstone-core": "^2.3.0",
|
"cornerstone-core": "^2.3.0",
|
||||||
"cornerstone-wado-image-loader": "^3.1.2",
|
"cornerstone-wado-image-loader": "^3.1.2",
|
||||||
"dcmjs": "0.14.2",
|
"dcmjs": "0.16.0",
|
||||||
"dicom-parser": "^1.8.3",
|
"dicom-parser": "^1.8.3",
|
||||||
"i18next": "^17.0.3",
|
"i18next": "^17.0.3",
|
||||||
"i18next-browser-languagedetector": "^3.0.1",
|
"i18next-browser-languagedetector": "^3.0.1",
|
||||||
|
|||||||
@ -38,7 +38,7 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/runtime": "7.7.6",
|
"@babel/runtime": "7.7.6",
|
||||||
"ajv": "^6.10.0",
|
"ajv": "^6.10.0",
|
||||||
"dcmjs": "0.14.2",
|
"dcmjs": "0.16.0",
|
||||||
"dicomweb-client": "^0.6.0",
|
"dicomweb-client": "^0.6.0",
|
||||||
"immer": "6.0.2",
|
"immer": "6.0.2",
|
||||||
"isomorphic-base64": "^1.0.2",
|
"isomorphic-base64": "^1.0.2",
|
||||||
|
|||||||
@ -46,10 +46,12 @@ const retrieveMeasurements = server => {
|
|||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @param {object[]} measurementData An array of measurements from the measurements service
|
* @param {object[]} measurementData An array of measurements from the measurements service
|
||||||
|
* @param {string[]} additionalFindingTypes toolTypes that should be stored with labels as Findings
|
||||||
|
* as opposed to Finding Sites.
|
||||||
* that you wish to serialize.
|
* that you wish to serialize.
|
||||||
*/
|
*/
|
||||||
const downloadReport = measurementData => {
|
const downloadReport = (measurementData, additionalFindingTypes = []) => {
|
||||||
const srDataset = generateReport(measurementData);
|
const srDataset = generateReport(measurementData, additionalFindingTypes);
|
||||||
const reportBlob = dcmjs.data.datasetToBlob(srDataset);
|
const reportBlob = dcmjs.data.datasetToBlob(srDataset);
|
||||||
|
|
||||||
//Create a URL for the binary.
|
//Create a URL for the binary.
|
||||||
@ -61,10 +63,13 @@ const downloadReport = measurementData => {
|
|||||||
*
|
*
|
||||||
* @param {object[]} measurementData An array of measurements from the measurements service
|
* @param {object[]} measurementData An array of measurements from the measurements service
|
||||||
* that you wish to serialize.
|
* that you wish to serialize.
|
||||||
|
* @param {string[]} additionalFindingTypes toolTypes that should be stored with labels as Findings
|
||||||
*/
|
*/
|
||||||
const generateReport = measurementData => {
|
const generateReport = (measurementData, additionalFindingTypes) => {
|
||||||
const ids = measurementData.map(md => md.id);
|
const filteredToolState = _getFilteredCornerstoneToolState(
|
||||||
const filteredToolState = _getFilteredCornerstoneToolState(ids);
|
measurementData,
|
||||||
|
additionalFindingTypes
|
||||||
|
);
|
||||||
|
|
||||||
const report = MeasurementReport.generateReport(
|
const report = MeasurementReport.generateReport(
|
||||||
filteredToolState,
|
filteredToolState,
|
||||||
@ -79,9 +84,15 @@ const generateReport = measurementData => {
|
|||||||
* @param {object[]} measurementData An array of measurements from the measurements service
|
* @param {object[]} measurementData An array of measurements from the measurements service
|
||||||
* that you wish to serialize.
|
* that you wish to serialize.
|
||||||
* @param {object} dataSource The dataSource that you wish to use to persist the data.
|
* @param {object} dataSource The dataSource that you wish to use to persist the data.
|
||||||
|
* @param {string[]} additionalFindingTypes toolTypes that should be stored with labels as Findings
|
||||||
|
* as opposed to Finding Sites.
|
||||||
* @return {object} The naturalized report
|
* @return {object} The naturalized report
|
||||||
*/
|
*/
|
||||||
const storeMeasurements = async (measurementData, dataSource) => {
|
const storeMeasurements = async (
|
||||||
|
measurementData,
|
||||||
|
dataSource,
|
||||||
|
additionalFindingTypes = []
|
||||||
|
) => {
|
||||||
// TODO -> Eventually use the measurements directly and not the dcmjs adapter,
|
// TODO -> Eventually use the measurements directly and not the dcmjs adapter,
|
||||||
// But it is good enough for now whilst we only have cornerstone as a datasource.
|
// But it is good enough for now whilst we only have cornerstone as a datasource.
|
||||||
log.info('[DICOMSR] storeMeasurements');
|
log.info('[DICOMSR] storeMeasurements');
|
||||||
@ -92,7 +103,10 @@ const storeMeasurements = async (measurementData, dataSource) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const naturalizedReport = generateReport(measurementData);
|
const naturalizedReport = generateReport(
|
||||||
|
measurementData,
|
||||||
|
additionalFindingTypes
|
||||||
|
);
|
||||||
const { StudyInstanceUID } = naturalizedReport;
|
const { StudyInstanceUID } = naturalizedReport;
|
||||||
|
|
||||||
await dataSource.store.dicom(naturalizedReport);
|
await dataSource.store.dicom(naturalizedReport);
|
||||||
@ -110,7 +124,12 @@ const storeMeasurements = async (measurementData, dataSource) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
function _getFilteredCornerstoneToolState(uidFilter) {
|
function _getFilteredCornerstoneToolState(
|
||||||
|
measurementData,
|
||||||
|
additionalFindingTypes
|
||||||
|
) {
|
||||||
|
const uidFilter = measurementData.map(md => md.id);
|
||||||
|
|
||||||
const globalToolState = cornerstoneTools.globalImageIdSpecificToolStateManager.saveToolState();
|
const globalToolState = cornerstoneTools.globalImageIdSpecificToolStateManager.saveToolState();
|
||||||
const filteredToolState = {};
|
const filteredToolState = {};
|
||||||
|
|
||||||
@ -127,9 +146,38 @@ function _getFilteredCornerstoneToolState(uidFilter) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const measurmentDataI = measurementData.find(md => md.id === toolDataI.id);
|
||||||
|
|
||||||
const toolData = imageIdSpecificToolState[toolType].data;
|
const toolData = imageIdSpecificToolState[toolType].data;
|
||||||
|
|
||||||
toolData.push(toolDataI);
|
let finding;
|
||||||
|
const findingSites = [];
|
||||||
|
|
||||||
|
// NOTE -> Any kind of freetext value abuses the DICOM standard,
|
||||||
|
// As CodeValues should map 1:1 with CodeMeanings.
|
||||||
|
// Ideally we would actually use SNOMED codes for this.
|
||||||
|
if (measurmentDataI.label) {
|
||||||
|
if (additionalFindingTypes.includes(toolType)) {
|
||||||
|
finding = {
|
||||||
|
CodeValue: 'CORNERSTONEFREETEXT',
|
||||||
|
CodingSchemeDesignator: 'CST4',
|
||||||
|
CodeMeaning: measurmentDataI.label,
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
findingSites.push({
|
||||||
|
CodeValue: 'CORNERSTONEFREETEXT',
|
||||||
|
CodingSchemeDesignator: 'CST4',
|
||||||
|
CodeMeaning: measurmentDataI.label,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const measurement = Object.assign({}, toolDataI, {
|
||||||
|
finding,
|
||||||
|
findingSites,
|
||||||
|
});
|
||||||
|
|
||||||
|
toolData.push(measurement);
|
||||||
}
|
}
|
||||||
|
|
||||||
const uids = uidFilter.slice();
|
const uids = uidFilter.slice();
|
||||||
|
|||||||
@ -69,7 +69,7 @@
|
|||||||
"cornerstone-math": "^0.1.8",
|
"cornerstone-math": "^0.1.8",
|
||||||
"cornerstone-tools": "4.18.1",
|
"cornerstone-tools": "4.18.1",
|
||||||
"cornerstone-wado-image-loader": "^3.1.2",
|
"cornerstone-wado-image-loader": "^3.1.2",
|
||||||
"dcmjs": "0.14.2",
|
"dcmjs": "0.16.0",
|
||||||
"dicom-parser": "^1.8.3",
|
"dicom-parser": "^1.8.3",
|
||||||
"dicomweb-client": "^0.4.4",
|
"dicomweb-client": "^0.4.4",
|
||||||
"dotenv-webpack": "^1.7.0",
|
"dotenv-webpack": "^1.7.0",
|
||||||
|
|||||||
@ -7364,10 +7364,10 @@ dateformat@^3.0.0:
|
|||||||
resolved "https://registry.yarnpkg.com/dateformat/-/dateformat-3.0.3.tgz#a6e37499a4d9a9cf85ef5872044d62901c9889ae"
|
resolved "https://registry.yarnpkg.com/dateformat/-/dateformat-3.0.3.tgz#a6e37499a4d9a9cf85ef5872044d62901c9889ae"
|
||||||
integrity sha512-jyCETtSl3VMZMWeRo7iY1FL19ges1t55hMo5yaam4Jrsm5EPL89UQkoQRyiI+Yf4k8r2ZpdngkV8hr1lIdjb3Q==
|
integrity sha512-jyCETtSl3VMZMWeRo7iY1FL19ges1t55hMo5yaam4Jrsm5EPL89UQkoQRyiI+Yf4k8r2ZpdngkV8hr1lIdjb3Q==
|
||||||
|
|
||||||
dcmjs@0.14.2:
|
dcmjs@0.16.0:
|
||||||
version "0.14.2"
|
version "0.16.0"
|
||||||
resolved "https://registry.yarnpkg.com/dcmjs/-/dcmjs-0.14.2.tgz#bc4926c3312632ec61a5d68753c0857aebb65793"
|
resolved "https://registry.yarnpkg.com/dcmjs/-/dcmjs-0.16.0.tgz#714755d006c3a49cf65ef13e627ff7a23151d35a"
|
||||||
integrity sha512-W4/f34Ph6Nrc95QhL/7f1kPlfR2YJMbyEsbPELt3xml17SFnkEgXAeO41qHZ7KywozO/lBW5sXGOpMenuYVV2g==
|
integrity sha512-41nY3Isg5i5FoSd1s67aUgUHi146r+fb8JuiRvDsxvm7MEkkdjIzMYMtxjsrVwKRW1xRH+x34nxbV9+8cc7WQw==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@babel/polyfill" "^7.8.3"
|
"@babel/polyfill" "^7.8.3"
|
||||||
"@babel/runtime" "^7.8.4"
|
"@babel/runtime" "^7.8.4"
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user