From d4f51c5e3cc55abaeed015933d40b35c0448fd78 Mon Sep 17 00:00:00 2001 From: Erik Ziegler Date: Sun, 10 May 2020 16:33:04 +0200 Subject: [PATCH] Work on adding SOPClassHandler module based on default behaviour currently in OHIF --- .../default/src/getLayoutTemplateModule.js | 4 +- .../default/src/getSopClassHandlerModule.js | 335 ++++++++++++++++++ extensions/default/src/index.js | 2 + platform/core/package.json | 11 +- platform/core/src/dicomMetadataStore.js | 20 +- .../core/src/extensions/ExtensionManager.js | 1 + platform/viewer/src/routes/ModeRoute.js | 10 +- .../src/routes/SOPClassHandlerManager.js | 11 +- yarn.lock | 29 +- 9 files changed, 403 insertions(+), 20 deletions(-) create mode 100644 extensions/default/src/getSopClassHandlerModule.js diff --git a/extensions/default/src/getLayoutTemplateModule.js b/extensions/default/src/getLayoutTemplateModule.js index 0fdee6694..d07972e64 100644 --- a/extensions/default/src/getLayoutTemplateModule.js +++ b/extensions/default/src/getLayoutTemplateModule.js @@ -170,7 +170,7 @@ const ViewportToolbar = () => { return ; }; -function viewerLayout({ leftPanels, rightPanels, extensionManager }) { +function viewerLayout({ leftPanels, rightPanels, extensionManager, displaySetInstanceUids }) { const getPanelData = id => { const entry = extensionManager.getModuleEntry(id); // TODO, not sure why sidepanel content has to be JSX, and not a children prop? @@ -188,6 +188,8 @@ function viewerLayout({ leftPanels, rightPanels, extensionManager }) { const leftPanelComponents = leftPanels.map(getPanelData); const rightPanelComponents = rightPanels.map(getPanelData); + console.warn(displaySetInstanceUids); + return (
diff --git a/extensions/default/src/getSopClassHandlerModule.js b/extensions/default/src/getSopClassHandlerModule.js new file mode 100644 index 000000000..c42b43c61 --- /dev/null +++ b/extensions/default/src/getSopClassHandlerModule.js @@ -0,0 +1,335 @@ +import { isImage } from '@ohif/core/src/utils/isImage'; +import ImageSet from '@ohif/core/src/classes/ImageSet'; +import isDisplaySetReconstructable from '@ohif/core/src/utils/isDisplaySetReconstructable'; + +const isMultiFrame = instance => { + return instance.NumberOfFrames > 1; +}; + +const makeDisplaySet = (instances) => { + const instance = instances[0]; + const imageSet = new ImageSet(instances); + + // set appropriate attributes to image set... + imageSet.setAttributes({ + displaySetInstanceUid: imageSet.uid, // create a local alias for the imageSet UID + seriesDate: instance.SeriesDate, + seriesTime: instance.SeriesTime, + seriesInstanceUid: instance.SeriesInstanceUID, + seriesNumber: instance.SeriesNumber, + seriesDescription: instance.SeriesDescription, + numImageFrames: instances.length, + frameRate: instance.FrameTime, + modality: instance.Modality, + isMultiFrame: isMultiFrame(instance), + }); + + // Sort the images in this series if needed + const shallSort = true; //!OHIF.utils.ObjectPath.get(Meteor, 'settings.public.ui.sortSeriesByIncomingOrder'); + if (shallSort) { + imageSet.sortBy((a, b) => { + // Sort by InstanceNumber (0020,0013) + return ( + (parseInt(a.InstanceNumber) || 0) - + (parseInt(b.InstanceNumber) || 0) + ); + }); + } + + // Include the first image instance number (after sorted) + /*imageSet.setAttribute( + 'instanceNumber', + imageSet.getImage(0).InstanceNumber + );*/ + + /*const isReconstructable = isDisplaySetReconstructable(series, instances); + + imageSet.isReconstructable = isReconstructable.value; + + if (isReconstructable.missingFrames) { + // TODO -> This is currently unused, but may be used for reconstructing + // Volumes with gaps later on. + imageSet.missingFrames = isReconstructable.missingFrames; + }*/ + + return imageSet; +}; + +const isSingleImageModality = modality => { + return modality === 'CR' || modality === 'MG' || modality === 'DX'; +}; + +function getSopClassUids(instances) { + const uniqueSopClassUidsInSeries = new Set(); + instances.forEach(instance => { + uniqueSopClassUidsInSeries.add(instance.SOPClassUID); + }); + const sopClassUids = Array.from(uniqueSopClassUidsInSeries); + + return sopClassUids; +} + +/** + * Basic SOPClassHandler: + * - For all Image types that are stackable, create + * a displaySet with a stack of images + * + * @param {Array} sopClassHandlerModules List of SOP Class Modules + * @param {SeriesMetadata} series The series metadata object from which the display sets will be created + * @returns {Array} The list of display sets created for the given series object + */ +function getDisplaySetFromSeries(instances) { + // If the series has no instances, stop here + if (!instances || !instances.length) { + throw new Error('No instances were provided'); + } + + const displaySets = []; + const sopClassUids = getSopClassUids(instances); + + // Search through the instances (InstanceMetadata object) of this series + // Split Multi-frame instances and Single-image modalities + // into their own specific display sets. Place the rest of each + // series into another display set. + const stackableInstances = []; + instances.forEach(instance => { + // All imaging modalities must have a valid value for sopClassUid (x00080016) or rows (x00280010) + if (!isImage(instance.SOPClassUID) && !instance.Rows) { + return; + } + + let displaySet; + + if (isMultiFrame(instance)) { + displaySet = makeDisplaySet([instance]); + + displaySet.setAttributes({ + sopClassUids, + isClip: true, + seriesInstanceUid: instance.SeriesInstanceUID, + studyInstanceUid: instance.StudyInstanceUID, + numImageFrames: instance.NumberOfFrames, + instanceNumber: instance.InstanceNumber, + acquisitionDatetime: instance.AcquisitionDateTime, + }); + displaySets.push(displaySet); + } else if (isSingleImageModality(instance.modality)) { + displaySet = makeDisplaySet([instance]); + displaySet.setAttributes({ + sopClassUids, + studyInstanceUid: instance.StudyInstanceUID, + seriesInstanceUid: instance.SeriesInstanceUID, + instanceNumber: instance.InstanceNumber, + acquisitionDatetime: instance.AcquisitionDateTime, + }); + displaySets.push(displaySet); + } else { + stackableInstances.push(instance); + } + }); + + if (stackableInstances.length) { + const displaySet = makeDisplaySet(stackableInstances); + displaySet.setAttribute('studyInstanceUid', instances[0].StudyInstanceUID); + displaySet.setAttributes({ + sopClassUids, + }); + displaySets.push(displaySet); + } + + return displaySets; +} + +// TODO: Remove since we have roughly the same thing in dcmjs +const sopClassDictionary = { + ComputedRadiographyImageStorage: '1.2.840.10008.5.1.4.1.1.1', + DigitalXRayImageStorageForPresentation: '1.2.840.10008.5.1.4.1.1.1.1', + DigitalXRayImageStorageForProcessing: '1.2.840.10008.5.1.4.1.1.1.1.1', + DigitalMammographyXRayImageStorageForPresentation: + '1.2.840.10008.5.1.4.1.1.1.2', + DigitalMammographyXRayImageStorageForProcessing: + '1.2.840.10008.5.1.4.1.1.1.2.1', + DigitalIntraOralXRayImageStorageForPresentation: + '1.2.840.10008.5.1.4.1.1.1.3', + DigitalIntraOralXRayImageStorageForProcessing: + '1.2.840.10008.5.1.4.1.1.1.3.1', + CTImageStorage: '1.2.840.10008.5.1.4.1.1.2', + EnhancedCTImageStorage: '1.2.840.10008.5.1.4.1.1.2.1', + LegacyConvertedEnhancedCTImageStorage: '1.2.840.10008.5.1.4.1.1.2.2', + UltrasoundMultiframeImageStorage: '1.2.840.10008.5.1.4.1.1.3.1', + MRImageStorage: '1.2.840.10008.5.1.4.1.1.4', + EnhancedMRImageStorage: '1.2.840.10008.5.1.4.1.1.4.1', + MRSpectroscopyStorage: '1.2.840.10008.5.1.4.1.1.4.2', + EnhancedMRColorImageStorage: '1.2.840.10008.5.1.4.1.1.4.3', + LegacyConvertedEnhancedMRImageStorage: '1.2.840.10008.5.1.4.1.1.4.4', + UltrasoundImageStorage: '1.2.840.10008.5.1.4.1.1.6.1', + EnhancedUSVolumeStorage: '1.2.840.10008.5.1.4.1.1.6.2', + SecondaryCaptureImageStorage: '1.2.840.10008.5.1.4.1.1.7', + MultiframeSingleBitSecondaryCaptureImageStorage: + '1.2.840.10008.5.1.4.1.1.7.1', + MultiframeGrayscaleByteSecondaryCaptureImageStorage: + '1.2.840.10008.5.1.4.1.1.7.2', + MultiframeGrayscaleWordSecondaryCaptureImageStorage: + '1.2.840.10008.5.1.4.1.1.7.3', + MultiframeTrueColorSecondaryCaptureImageStorage: + '1.2.840.10008.5.1.4.1.1.7.4', + Sop12LeadECGWaveformStorage: '1.2.840.10008.5.1.4.1.1.9.1.1', + GeneralECGWaveformStorage: '1.2.840.10008.5.1.4.1.1.9.1.2', + AmbulatoryECGWaveformStorage: '1.2.840.10008.5.1.4.1.1.9.1.3', + HemodynamicWaveformStorage: '1.2.840.10008.5.1.4.1.1.9.2.1', + CardiacElectrophysiologyWaveformStorage: '1.2.840.10008.5.1.4.1.1.9.3.1', + BasicVoiceAudioWaveformStorage: '1.2.840.10008.5.1.4.1.1.9.4.1', + GeneralAudioWaveformStorage: '1.2.840.10008.5.1.4.1.1.9.4.2', + ArterialPulseWaveformStorage: '1.2.840.10008.5.1.4.1.1.9.5.1', + RespiratoryWaveformStorage: '1.2.840.10008.5.1.4.1.1.9.6.1', + GrayscaleSoftcopyPresentationStateStorage: '1.2.840.10008.5.1.4.1.1.11.1', + ColorSoftcopyPresentationStateStorage: '1.2.840.10008.5.1.4.1.1.11.2', + PseudoColorSoftcopyPresentationStateStorage: '1.2.840.10008.5.1.4.1.1.11.3', + BlendingSoftcopyPresentationStateStorage: '1.2.840.10008.5.1.4.1.1.11.4', + XAXRFGrayscaleSoftcopyPresentationStateStorage: + '1.2.840.10008.5.1.4.1.1.11.5', + XRayAngiographicImageStorage: '1.2.840.10008.5.1.4.1.1.12.1', + EnhancedXAImageStorage: '1.2.840.10008.5.1.4.1.1.12.1.1', + XRayRadiofluoroscopicImageStorage: '1.2.840.10008.5.1.4.1.1.12.2', + EnhancedXRFImageStorage: '1.2.840.10008.5.1.4.1.1.12.2.1', + XRay3DAngiographicImageStorage: '1.2.840.10008.5.1.4.1.1.13.1.1', + XRay3DCraniofacialImageStorage: '1.2.840.10008.5.1.4.1.1.13.1.2', + BreastTomosynthesisImageStorage: '1.2.840.10008.5.1.4.1.1.13.1.3', + BreastProjectionXRayImageStorageForPresentation: + '1.2.840.10008.5.1.4.1.1.13.1.4', + BreastProjectionXRayImageStorageForProcessing: + '1.2.840.10008.5.1.4.1.1.13.1.5', + IntravascularOpticalCoherenceTomographyImageStorageForPresentation: + '1.2.840.10008.5.1.4.1.1.14.1', + IntravascularOpticalCoherenceTomographyImageStorageForProcessing: + '1.2.840.10008.5.1.4.1.1.14.2', + NuclearMedicineImageStorage: '1.2.840.10008.5.1.4.1.1.20', + RawDataStorage: '1.2.840.10008.5.1.4.1.1.66', + SpatialRegistrationStorage: '1.2.840.10008.5.1.4.1.1.66.1', + SpatialFiducialsStorage: '1.2.840.10008.5.1.4.1.1.66.2', + DeformableSpatialRegistrationStorage: '1.2.840.10008.5.1.4.1.1.66.3', + SegmentationStorage: '1.2.840.10008.5.1.4.1.1.66.4', + SurfaceSegmentationStorage: '1.2.840.10008.5.1.4.1.1.66.5', + RealWorldValueMappingStorage: '1.2.840.10008.5.1.4.1.1.67', + SurfaceScanMeshStorage: '1.2.840.10008.5.1.4.1.1.68.1', + SurfaceScanPointCloudStorage: '1.2.840.10008.5.1.4.1.1.68.2', + VLEndoscopicImageStorage: '1.2.840.10008.5.1.4.1.1.77.1.1', + VideoEndoscopicImageStorage: '1.2.840.10008.5.1.4.1.1.77.1.1.1', + VLMicroscopicImageStorage: '1.2.840.10008.5.1.4.1.1.77.1.2', + VideoMicroscopicImageStorage: '1.2.840.10008.5.1.4.1.1.77.1.2.1', + VLSlideCoordinatesMicroscopicImageStorage: '1.2.840.10008.5.1.4.1.1.77.1.3', + VLPhotographicImageStorage: '1.2.840.10008.5.1.4.1.1.77.1.4', + VideoPhotographicImageStorage: '1.2.840.10008.5.1.4.1.1.77.1.4.1', + OphthalmicPhotography8BitImageStorage: '1.2.840.10008.5.1.4.1.1.77.1.5.1', + OphthalmicPhotography16BitImageStorage: '1.2.840.10008.5.1.4.1.1.77.1.5.2', + StereometricRelationshipStorage: '1.2.840.10008.5.1.4.1.1.77.1.5.3', + OphthalmicTomographyImageStorage: '1.2.840.10008.5.1.4.1.1.77.1.5.4', + VLWholeSlideMicroscopyImageStorage: '1.2.840.10008.5.1.4.1.1.77.1.6', + LensometryMeasurementsStorage: '1.2.840.10008.5.1.4.1.1.78.1', + AutorefractionMeasurementsStorage: '1.2.840.10008.5.1.4.1.1.78.2', + KeratometryMeasurementsStorage: '1.2.840.10008.5.1.4.1.1.78.3', + SubjectiveRefractionMeasurementsStorage: '1.2.840.10008.5.1.4.1.1.78.4', + VisualAcuityMeasurementsStorage: '1.2.840.10008.5.1.4.1.1.78.5', + SpectaclePrescriptionReportStorage: '1.2.840.10008.5.1.4.1.1.78.6', + OphthalmicAxialMeasurementsStorage: '1.2.840.10008.5.1.4.1.1.78.7', + IntraocularLensCalculationsStorage: '1.2.840.10008.5.1.4.1.1.78.8', + MacularGridThicknessandVolumeReport: '1.2.840.10008.5.1.4.1.1.79.1', + OphthalmicVisualFieldStaticPerimetryMeasurementsStorage: + '1.2.840.10008.5.1.4.1.1.80.1', + OphthalmicThicknessMapStorage: '1.2.840.10008.5.1.4.1.1.81.1', + CornealTopographyMapStorage: '1.2.840.10008.5.1.4.1.1.82.1', + BasicTextSR: '1.2.840.10008.5.1.4.1.1.88.11', + EnhancedSR: '1.2.840.10008.5.1.4.1.1.88.22', + ComprehensiveSR: '1.2.840.10008.5.1.4.1.1.88.33', + Comprehensive3DSR: '1.2.840.10008.5.1.4.1.1.88.34', + ProcedureLog: '1.2.840.10008.5.1.4.1.1.88.40', + MammographyCADSR: '1.2.840.10008.5.1.4.1.1.88.50', + KeyObjectSelection: '1.2.840.10008.5.1.4.1.1.88.59', + ChestCADSR: '1.2.840.10008.5.1.4.1.1.88.65', + XRayRadiationDoseSR: '1.2.840.10008.5.1.4.1.1.88.67', + RadiopharmaceuticalRadiationDoseSR: '1.2.840.10008.5.1.4.1.1.88.68', + ColonCADSR: '1.2.840.10008.5.1.4.1.1.88.69', + ImplantationPlanSRDocumentStorage: '1.2.840.10008.5.1.4.1.1.88.70', + EncapsulatedPDFStorage: '1.2.840.10008.5.1.4.1.1.104.1', + EncapsulatedCDAStorage: '1.2.840.10008.5.1.4.1.1.104.2', + PositronEmissionTomographyImageStorage: '1.2.840.10008.5.1.4.1.1.128', + EnhancedPETImageStorage: '1.2.840.10008.5.1.4.1.1.130', + LegacyConvertedEnhancedPETImageStorage: '1.2.840.10008.5.1.4.1.1.128.1', + BasicStructuredDisplayStorage: '1.2.840.10008.5.1.4.1.1.131', + RTImageStorage: '1.2.840.10008.5.1.4.1.1.481.1', + RTDoseStorage: '1.2.840.10008.5.1.4.1.1.481.2', + RTStructureSetStorage: '1.2.840.10008.5.1.4.1.1.481.3', + RTBeamsTreatmentRecordStorage: '1.2.840.10008.5.1.4.1.1.481.4', + RTPlanStorage: '1.2.840.10008.5.1.4.1.1.481.5', + RTBrachyTreatmentRecordStorage: '1.2.840.10008.5.1.4.1.1.481.6', + RTTreatmentSummaryRecordStorage: '1.2.840.10008.5.1.4.1.1.481.7', + RTIonPlanStorage: '1.2.840.10008.5.1.4.1.1.481.8', + RTIonBeamsTreatmentRecordStorage: '1.2.840.10008.5.1.4.1.1.481.9', + RTBeamsDeliveryInstructionStorage: '1.2.840.10008.5.1.4.34.7', + GenericImplantTemplateStorage: '1.2.840.10008.5.1.4.43.1', + ImplantAssemblyTemplateStorage: '1.2.840.10008.5.1.4.44.1', + ImplantTemplateGroupStorage: '1.2.840.10008.5.1.4.45.1', +}; + +const sopClassUids = [ + sopClassDictionary.ComputedRadiographyImageStorage, + sopClassDictionary.DigitalXRayImageStorageForPresentation, + sopClassDictionary.DigitalXRayImageStorageForProcessing, + sopClassDictionary.DigitalMammographyXRayImageStorageForPresentation, + sopClassDictionary.DigitalMammographyXRayImageStorageForProcessing, + sopClassDictionary.DigitalIntraOralXRayImageStorageForPresentation, + sopClassDictionary.DigitalIntraOralXRayImageStorageForProcessing, + sopClassDictionary.CTImageStorage, + sopClassDictionary.EnhancedCTImageStorage, + sopClassDictionary.LegacyConvertedEnhancedCTImageStorage, + sopClassDictionary.UltrasoundMultiframeImageStorage, + sopClassDictionary.MRImageStorage, + sopClassDictionary.EnhancedMRImageStorage, + sopClassDictionary.EnhancedMRColorImageStorage, + sopClassDictionary.LegacyConvertedEnhancedMRImageStorage, + sopClassDictionary.UltrasoundImageStorage, + sopClassDictionary.SecondaryCaptureImageStorage, + sopClassDictionary.MultiframeSingleBitSecondaryCaptureImageStorage, + sopClassDictionary.MultiframeGrayscaleByteSecondaryCaptureImageStorage, + sopClassDictionary.MultiframeGrayscaleWordSecondaryCaptureImageStorage, + sopClassDictionary.MultiframeTrueColorSecondaryCaptureImageStorage, + sopClassDictionary.XRayAngiographicImageStorage, + sopClassDictionary.EnhancedXAImageStorage, + sopClassDictionary.XRayRadiofluoroscopicImageStorage, + sopClassDictionary.EnhancedXRFImageStorage, + sopClassDictionary.XRay3DAngiographicImageStorage, + sopClassDictionary.XRay3DCraniofacialImageStorage, + sopClassDictionary.BreastTomosynthesisImageStorage, + sopClassDictionary.BreastProjectionXRayImageStorageForPresentation, + sopClassDictionary.BreastProjectionXRayImageStorageForProcessing, + sopClassDictionary.IntravascularOpticalCoherenceTomographyImageStorageForPresentation, + sopClassDictionary.IntravascularOpticalCoherenceTomographyImageStorageForProcessing, + sopClassDictionary.NuclearMedicineImageStorage, + sopClassDictionary.VLEndoscopicImageStorage, + sopClassDictionary.VideoEndoscopicImageStorage, + sopClassDictionary.VLMicroscopicImageStorage, + sopClassDictionary.VideoMicroscopicImageStorage, + sopClassDictionary.VLSlideCoordinatesMicroscopicImageStorage, + sopClassDictionary.VLPhotographicImageStorage, + sopClassDictionary.VideoPhotographicImageStorage, + sopClassDictionary.OphthalmicPhotography8BitImageStorage, + sopClassDictionary.OphthalmicPhotography16BitImageStorage, + sopClassDictionary.OphthalmicTomographyImageStorage, + sopClassDictionary.VLWholeSlideMicroscopyImageStorage, + sopClassDictionary.PositronEmissionTomographyImageStorage, + sopClassDictionary.EnhancedPETImageStorage, + sopClassDictionary.LegacyConvertedEnhancedPETImageStorage, + sopClassDictionary.RTImageStorage, +]; + +function getSopClassHandlerModule() { + return [ + { + name: 'stack', + sopClassUids, + getDisplaySetFromSeries, + }, + ]; +} + +export default getSopClassHandlerModule; diff --git a/extensions/default/src/index.js b/extensions/default/src/index.js index 572c826f1..3fae68f77 100644 --- a/extensions/default/src/index.js +++ b/extensions/default/src/index.js @@ -2,6 +2,7 @@ import getContextModule from './getContextModule.js'; import getDataSourcesModule from './getDataSourcesModule.js'; import getLayoutTemplateModule from './getLayoutTemplateModule.js'; import getPanelModule from './getPanelModule.js'; +import getSopClassHandlerModule from './getSopClassHandlerModule.js'; export default { /** @@ -12,4 +13,5 @@ export default { getDataSourcesModule, getLayoutTemplateModule, getPanelModule, + getSopClassHandlerModule }; diff --git a/platform/core/package.json b/platform/core/package.json index 378d39e06..115f1de21 100644 --- a/platform/core/package.json +++ b/platform/core/package.json @@ -30,23 +30,16 @@ "test:unit:ci": "jest --ci --runInBand --collectCoverage" }, "peerDependencies": { -<<<<<<< HEAD - "cornerstone-core": "^2.2.8", - "cornerstone-tools": "4.15.1", - "cornerstone-wado-image-loader": "^3.1.0", -======= "cornerstone-core": "^2.3.0", "cornerstone-tools": "^4.12.0", "cornerstone-wado-image-loader": "^3.0.0", ->>>>>>> 4a8675655... feat: nuke UI project; start new with updated tooling BREAKING_CHANGE (#1468) "dicom-parser": "^1.8.3" }, "dependencies": { "@babel/runtime": "7.7.6", "ajv": "^6.10.0", - "dcmjs": "^0.12.2", - "dicomweb-client": "^0.6.0", - "immer": "6.0.2", + "dcmjs": "^0.12.4", + "dicomweb-client": "^0.5.2", "isomorphic-base64": "^1.0.2", "lodash.clonedeep": "^4.5.0", "lodash.merge": "^4.6.1", diff --git a/platform/core/src/dicomMetadataStore.js b/platform/core/src/dicomMetadataStore.js index 3e7469c29..b0bbe7038 100644 --- a/platform/core/src/dicomMetadataStore.js +++ b/platform/core/src/dicomMetadataStore.js @@ -1,4 +1,20 @@ +import { createStudyFromSOPInstanceList, + addInstancesToStudy } from './studies/services/wado/studyInstanceHelpers'; +import * as dcmjs from 'dcmjs'; + +const exampleInstances = [{"00080005":{"vr":"CS","Value":["ISO_IR 100"]},"00080008":{"vr":"CS","Value":["ORIGINAL","PRIMARY","LOCALIZER"]},"00080016":{"vr":"UI","Value":["1.2.840.10008.5.1.4.1.1.2"]},"00080018":{"vr":"UI","Value":["1.3.6.1.4.1.25403.345050719074.3824.20170126082902.6"]},"00080020":{"vr":"DA","Value":["20141125"]},"00080021":{"vr":"DA","Value":["20141125"]},"00080022":{"vr":"DA","Value":["20141125"]},"00080023":{"vr":"DA","Value":["20141125"]},"00080030":{"vr":"TM","Value":["094528.000"]},"00080031":{"vr":"TM","Value":["094604.688"]},"00080032":{"vr":"TM","Value":["094623.600"]},"00080033":{"vr":"TM","Value":["094623.600"]},"00080050":{"vr":"SH","Value":["000092218"]},"00080060":{"vr":"CS","Value":["CT"]},"00080070":{"vr":"LO","Value":["TOSHIBA"]},"00080080":{"vr":"LO","Value":["Precision Imaging Metrics"]},"00080090":{"vr":"PN"},"00081010":{"vr":"SH"},"00081030":{"vr":"LO","Value":["DFCI CT CHEST W CONTRAST 6023"]},"00081032":{"vr":"SQ","Value":[{"00080100":{"vr":"SH","Value":["6023"]},"00080102":{"vr":"SH","Value":["GEIIS"]},"00080103":{"vr":"SH","Value":["0"]},"00080104":{"vr":"LO","Value":["DFCI CT CHEST W CONTRAST 6023"]}}]},"0008103E":{"vr":"LO","Value":["2.0"]},"00081040":{"vr":"LO"},"00081070":{"vr":"PN"},"00081090":{"vr":"LO","Value":["Aquilion"]},"00081110":{"vr":"SQ","Value":[{"00081150":{"vr":"UI","Value":["1.2.840.100008.3.1.2.3.1"]},"00081155":{"vr":"UI","Value":["1.3.6.1.4.1.25403.345050719074.3824.20170126082902.4"]}}]},"00100010":{"vr":"PN","Value":[{"Alphabetic":"Venus"}]},"00100020":{"vr":"LO","Value":["0000005"]},"00100021":{"vr":"LO","Value":["001R74:20050625:205502036:195212"]},"00100030":{"vr":"DA"},"00100040":{"vr":"CS","Value":["F"]},"00101000":{"vr":"LO"},"00101010":{"vr":"AS"},"00101020":{"vr":"DS"},"00101030":{"vr":"DS"},"00104000":{"vr":"LT"},"00180015":{"vr":"CS","Value":["CHEST_TO_PELVIS"]},"00180022":{"vr":"CS","Value":["SCANOSCOPE"]},"00180050":{"vr":"DS","Value":[2.0]},"00180060":{"vr":"DS","Value":[120.0]},"00180090":{"vr":"DS","Value":[1000.0]},"00181000":{"vr":"LO"},"00181020":{"vr":"LO","Value":["V4.86ER003"]},"00181030":{"vr":"LO","Value":["Chest / Abdomen/Pelvis 5mm"]},"00181100":{"vr":"DS","Value":[1000.0]},"00181120":{"vr":"DS","Value":[0.0]},"00181130":{"vr":"DS","Value":[102.0]},"00181140":{"vr":"CS","Value":["CW"]},"00181150":{"vr":"IS","Value":[6840]},"00181151":{"vr":"IS","Value":[100]},"00181152":{"vr":"IS","Value":[600]},"00181160":{"vr":"SH","Value":["LARGE"]},"00181170":{"vr":"IS","Value":[12]},"00181190":{"vr":"DS","Value":[1.6,1.4]},"00181210":{"vr":"SH","Value":["FL03"]},"00185100":{"vr":"CS","Value":["FFS"]},"0020000D":{"vr":"UI","Value":["1.3.6.1.4.1.25403.345050719074.3824.20170126082902.1"]},"0020000E":{"vr":"UI","Value":["1.3.6.1.4.1.25403.345050719074.3824.20170126082902.2"]},"00200010":{"vr":"SH"},"00200011":{"vr":"IS","Value":[1]},"00200012":{"vr":"IS","Value":[2]},"00200013":{"vr":"IS","Value":[2]},"00200020":{"vr":"CS","Value":["F","P"]},"00200032":{"vr":"DS","Value":[-1.7E-4,-512.0,1925.0]},"00200037":{"vr":"DS","Value":[0.0,0.0,-1.0,0.0,1.0,-0.0]},"00200052":{"vr":"UI","Value":["1.3.6.1.4.1.25403.345050719074.3824.20170126082902.5"]},"00201040":{"vr":"LO"},"00201041":{"vr":"DS","Value":[342.0]},"00280002":{"vr":"US","Value":[1]},"00280004":{"vr":"CS","Value":["MONOCHROME2"]},"00280010":{"vr":"US","Value":[512]},"00280011":{"vr":"US","Value":[512]},"00280030":{"vr":"DS","Value":[2.0,2.0]},"00280100":{"vr":"US","Value":[16]},"00280101":{"vr":"US","Value":[16]},"00280102":{"vr":"US","Value":[15]},"00280103":{"vr":"US","Value":[1]},"00281050":{"vr":"DS","Value":[110.0]},"00281051":{"vr":"DS","Value":[320.0]},"00281052":{"vr":"DS","Value":[0.0]},"00281053":{"vr":"DS","Value":[1.0]},"00321033":{"vr":"LO","Value":["OUTDFRAD"]},"00400002":{"vr":"DA","Value":["20141125"]},"00400003":{"vr":"TM","Value":["091000"]},"00400004":{"vr":"DA","Value":["20141125"]},"00400005":{"vr":"TM","Value":["094000.000"]},"00400244":{"vr":"DA","Value":["20141125"]},"00400245":{"vr":"TM","Value":["094528.000"]},"00400253":{"vr":"SH","Value":["3708"]},"00400260":{"vr":"SQ","Value":[{"00080100":{"vr":"SH","Value":["6035"]},"00080102":{"vr":"SH","Value":["CCG_CSTemp"]},"00080104":{"vr":"LO","Value":["6035/DFCT2 CT 3-SITES W/OC"]}}]},"00402017":{"vr":"LO","Value":["14159097"]},"7FE00010":{"vr":"OW","BulkDataURI":"http://server.dcmjs.org/dcm4chee-arc/aets/DCM4CHEE/rs/studies/1.3.6.1.4.1.25403.345050719074.3824.20170126082902.1/series/1.3.6.1.4.1.25403.345050719074.3824.20170126082902.2/instances/1.3.6.1.4.1.25403.345050719074.3824.20170126082902.6"}},{"00080005":{"vr":"CS","Value":["ISO_IR 100"]},"00080008":{"vr":"CS","Value":["ORIGINAL","PRIMARY","LOCALIZER"]},"00080016":{"vr":"UI","Value":["1.2.840.10008.5.1.4.1.1.2"]},"00080018":{"vr":"UI","Value":["1.3.6.1.4.1.25403.345050719074.3824.20170126082902.3"]},"00080020":{"vr":"DA","Value":["20141125"]},"00080021":{"vr":"DA","Value":["20141125"]},"00080022":{"vr":"DA","Value":["20141125"]},"00080023":{"vr":"DA","Value":["20141125"]},"00080030":{"vr":"TM","Value":["094528.000"]},"00080031":{"vr":"TM","Value":["094604.688"]},"00080032":{"vr":"TM","Value":["094557.250"]},"00080033":{"vr":"TM","Value":["094557.250"]},"00080050":{"vr":"SH","Value":["000092218"]},"00080060":{"vr":"CS","Value":["CT"]},"00080070":{"vr":"LO","Value":["TOSHIBA"]},"00080080":{"vr":"LO","Value":["Precision Imaging Metrics"]},"00080090":{"vr":"PN"},"00081010":{"vr":"SH"},"00081030":{"vr":"LO","Value":["DFCI CT CHEST W CONTRAST 6023"]},"00081032":{"vr":"SQ","Value":[{"00080100":{"vr":"SH","Value":["6023"]},"00080102":{"vr":"SH","Value":["GEIIS"]},"00080103":{"vr":"SH","Value":["0"]},"00080104":{"vr":"LO","Value":["DFCI CT CHEST W CONTRAST 6023"]}}]},"0008103E":{"vr":"LO","Value":["2.0"]},"00081040":{"vr":"LO"},"00081070":{"vr":"PN"},"00081090":{"vr":"LO","Value":["Aquilion"]},"00081110":{"vr":"SQ","Value":[{"00081150":{"vr":"UI","Value":["1.2.840.100008.3.1.2.3.1"]},"00081155":{"vr":"UI","Value":["1.3.6.1.4.1.25403.345050719074.3824.20170126082902.4"]}}]},"00100010":{"vr":"PN","Value":[{"Alphabetic":"Venus"}]},"00100020":{"vr":"LO","Value":["0000005"]},"00100021":{"vr":"LO","Value":["001R74:20050625:205502036:195212"]},"00100030":{"vr":"DA"},"00100040":{"vr":"CS","Value":["F"]},"00101000":{"vr":"LO"},"00101010":{"vr":"AS"},"00101020":{"vr":"DS"},"00101030":{"vr":"DS"},"00104000":{"vr":"LT"},"00180015":{"vr":"CS","Value":["CHEST_TO_PELVIS"]},"00180022":{"vr":"CS","Value":["SCANOSCOPE"]},"00180050":{"vr":"DS","Value":[2.0]},"00180060":{"vr":"DS","Value":[120.0]},"00180090":{"vr":"DS","Value":[1000.0]},"00181000":{"vr":"LO"},"00181020":{"vr":"LO","Value":["V4.86ER003"]},"00181030":{"vr":"LO","Value":["Chest / Abdomen/Pelvis 5mm"]},"00181100":{"vr":"DS","Value":[1000.0]},"00181120":{"vr":"DS","Value":[0.0]},"00181130":{"vr":"DS","Value":[102.0]},"00181140":{"vr":"CS","Value":["CW"]},"00181150":{"vr":"IS","Value":[6857]},"00181151":{"vr":"IS","Value":[50]},"00181152":{"vr":"IS","Value":[300]},"00181160":{"vr":"SH","Value":["LARGE"]},"00181170":{"vr":"IS","Value":[6]},"00181190":{"vr":"DS","Value":[1.6,1.4]},"00181210":{"vr":"SH","Value":["FL03"]},"00185100":{"vr":"CS","Value":["FFS"]},"0020000D":{"vr":"UI","Value":["1.3.6.1.4.1.25403.345050719074.3824.20170126082902.1"]},"0020000E":{"vr":"UI","Value":["1.3.6.1.4.1.25403.345050719074.3824.20170126082902.2"]},"00200010":{"vr":"SH"},"00200011":{"vr":"IS","Value":[1]},"00200012":{"vr":"IS","Value":[1]},"00200013":{"vr":"IS","Value":[1]},"00200020":{"vr":"CS","Value":["L","F"]},"00200032":{"vr":"DS","Value":[-512.0,1.7E-4,1925.0]},"00200037":{"vr":"DS","Value":[1.0,0.0,0.0,0.0,0.0,-1.0]},"00200052":{"vr":"UI","Value":["1.3.6.1.4.1.25403.345050719074.3824.20170126082902.5"]},"00201040":{"vr":"LO"},"00201041":{"vr":"DS","Value":[342.0]},"00280002":{"vr":"US","Value":[1]},"00280004":{"vr":"CS","Value":["MONOCHROME2"]},"00280010":{"vr":"US","Value":[512]},"00280011":{"vr":"US","Value":[512]},"00280030":{"vr":"DS","Value":[2.0,2.0]},"00280100":{"vr":"US","Value":[16]},"00280101":{"vr":"US","Value":[16]},"00280102":{"vr":"US","Value":[15]},"00280103":{"vr":"US","Value":[1]},"00281050":{"vr":"DS","Value":[100.0]},"00281051":{"vr":"DS","Value":[230.0]},"00281052":{"vr":"DS","Value":[0.0]},"00281053":{"vr":"DS","Value":[1.0]},"00321033":{"vr":"LO","Value":["OUTDFRAD"]},"00400002":{"vr":"DA","Value":["20141125"]},"00400003":{"vr":"TM","Value":["091000"]},"00400004":{"vr":"DA","Value":["20141125"]},"00400005":{"vr":"TM","Value":["094000.000"]},"00400244":{"vr":"DA","Value":["20141125"]},"00400245":{"vr":"TM","Value":["094528.000"]},"00400253":{"vr":"SH","Value":["3708"]},"00400260":{"vr":"SQ","Value":[{"00080100":{"vr":"SH","Value":["6035"]},"00080102":{"vr":"SH","Value":["CCG_CSTemp"]},"00080104":{"vr":"LO","Value":["6035/DFCT2 CT 3-SITES W/OC"]}}]},"00402017":{"vr":"LO","Value":["14159097"]},"7FE00010":{"vr":"OW","BulkDataURI":"http://server.dcmjs.org/dcm4chee-arc/aets/DCM4CHEE/rs/studies/1.3.6.1.4.1.25403.345050719074.3824.20170126082902.1/series/1.3.6.1.4.1.25403.345050719074.3824.20170126082902.2/instances/1.3.6.1.4.1.25403.345050719074.3824.20170126082902.3"}}]; + +const { naturalizeDataset } = dcmjs.data.DicomMetaDictionary; +const instances = exampleInstances.map(naturalizeDataset); + + const dicomMetadataStore = { - // TODO James - // + onSeriesMetadataLoaded: (callback) => { + setTimeout(function() { + callback(instances); + }, 3000) + } }; + +export { dicomMetadataStore }; +export default dicomMetadataStore; diff --git a/platform/core/src/extensions/ExtensionManager.js b/platform/core/src/extensions/ExtensionManager.js index 66eb4e07e..167a88769 100644 --- a/platform/core/src/extensions/ExtensionManager.js +++ b/platform/core/src/extensions/ExtensionManager.js @@ -151,6 +151,7 @@ export default class ExtensionManager { log.error( `Exception thrown while trying to call ${getModuleFnName} for the ${extensionId} extension` ); + log.error(ex); } }; diff --git a/platform/viewer/src/routes/ModeRoute.js b/platform/viewer/src/routes/ModeRoute.js index afb4d4b26..eca400c70 100644 --- a/platform/viewer/src/routes/ModeRoute.js +++ b/platform/viewer/src/routes/ModeRoute.js @@ -26,19 +26,21 @@ export default function ModeRoute({ ); const LayoutComponent = layoutTemplateModuleEntry.component; - //const LayoutComponent = props =>
{'Testing'}
; // Add SOPClassHandlers to a new SOPClassManager. - /*const manager = new SOPClassHandlerManager( + const manager = new SOPClassHandlerManager( extensionManager, sopClassHandlers - );*/ + ); + + /*setInterval(() => { + setDisplaySetInstanceUids(manager.displaySets); + }, 5000);*/ const queryParams = location.search; // Call the data source to start building the view model? //dataSource(queryParams); - //metadataStore.onModified(); const onUpdatedCallback = () => { diff --git a/platform/viewer/src/routes/SOPClassHandlerManager.js b/platform/viewer/src/routes/SOPClassHandlerManager.js index 3bd2cb5d4..815af99d9 100644 --- a/platform/viewer/src/routes/SOPClassHandlerManager.js +++ b/platform/viewer/src/routes/SOPClassHandlerManager.js @@ -6,10 +6,17 @@ export default class SOPClassHandlerManager { extensionManager.getModuleEntry ); - dicomMetadataStore.listen(this.onSeriesMetadataLoaded); + dicomMetadataStore.onSeriesMetadataLoaded(this.onSeriesMetadataLoaded); + + // TODO, this is unclear. How are we getting the created display sets out? + this.displaySets = []; } onSeriesMetadataLoaded = instances => { + if (!instances || !instances.length) { + throw new Error("No instances were provided."); + } + const SOPClassHandlers = this.SOPClassHandlers; for (let i = 0; i < SOPClassHandlers.length; i++) { @@ -17,7 +24,7 @@ export default class SOPClassHandlerManager { if (handler.sopClassUids.includes(instances[0].SOPClassUID)) { // TODO: This step is still unclear to me - return handler.getDisplaySetFromSeries(series); + this.displaySets = handler.getDisplaySetFromSeries(instances).map(a => a.displaySetInstanceUid); } } }; diff --git a/yarn.lock b/yarn.lock index 8963a7f25..485a8da01 100644 --- a/yarn.lock +++ b/yarn.lock @@ -767,6 +767,14 @@ core-js "^2.6.5" regenerator-runtime "^0.13.2" +"@babel/polyfill@^7.8.3": + version "7.8.7" + resolved "https://registry.yarnpkg.com/@babel/polyfill/-/polyfill-7.8.7.tgz#151ec24c7135481336168c3bd8b8bf0cf91c032f" + integrity sha512-LeSfP9bNZH2UOZgcGcZ0PIHUt1ZuHub1L3CVmEyqLxCeDLm4C5Gi8jRH8ZX2PNpDhQCo0z6y/+DIs2JlliXW8w== + dependencies: + core-js "^2.6.5" + regenerator-runtime "^0.13.4" + "@babel/preset-env@^7.5.0", "@babel/preset-env@^7.5.5", "@babel/preset-env@^7.7.6": version "7.8.6" resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.8.6.tgz#2a0773b08589ecba4995fc71b1965e4f531af40b" @@ -888,6 +896,13 @@ dependencies: regenerator-runtime "^0.13.4" +"@babel/runtime@^7.8.4": + version "7.9.6" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.9.6.tgz#a9102eb5cadedf3f31d08a9ecf294af7827ea29f" + integrity sha512-64AF1xY3OAkFHqOb9s4jpgk1Mm5vDZ4L3acHvAml+53nO1XbXLuDodsVpO4OIUsmemlUHMxNdYMNJmsvOwLrvQ== + dependencies: + regenerator-runtime "^0.13.4" + "@babel/standalone@^7.4.5": version "7.8.6" resolved "https://registry.yarnpkg.com/@babel/standalone/-/standalone-7.8.6.tgz#1364534775c83bf7b7988e4ca98823bef56a0a53" @@ -6311,7 +6326,17 @@ dateformat@^3.0.0: resolved "https://registry.yarnpkg.com/dateformat/-/dateformat-3.0.3.tgz#a6e37499a4d9a9cf85ef5872044d62901c9889ae" integrity sha512-jyCETtSl3VMZMWeRo7iY1FL19ges1t55hMo5yaam4Jrsm5EPL89UQkoQRyiI+Yf4k8r2ZpdngkV8hr1lIdjb3Q== -dcmjs@^0.8.2, dcmjs@^0.8.3: +dcmjs@^0.12.4: + version "0.12.4" + resolved "https://registry.yarnpkg.com/dcmjs/-/dcmjs-0.12.4.tgz#82c24abdc357ea5281b78eb2cae8b781f7392aa3" + integrity sha512-N1ZsXqZIysirqdytb7h572TyIjmxpvCjrzdjtQsuPN8gC2EpxsUHQ598CPzaJBpBy9i1kfKuq4h2Jwt99cr/QQ== + dependencies: + "@babel/polyfill" "^7.8.3" + "@babel/runtime" "^7.8.4" + loglevelnext "^3.0.1" + ndarray "^1.0.19" + +dcmjs@^0.8.2: version "0.8.3" resolved "https://registry.yarnpkg.com/dcmjs/-/dcmjs-0.8.3.tgz#fff1b030b6cb2d6e2afb1aa99840bfa853724c31" integrity sha512-eXQjqgtJf9+oseraKDNDm2A5F3Th4B2GJeZtjStj0IFXxjlbPOzdq3PfCyxdwfRaKOBIwr0q3YK/Vfs2CpQY8Q== @@ -13635,7 +13660,7 @@ natural-compare@^1.4.0: resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" integrity sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc= -ndarray@^1.0.18: +ndarray@^1.0.18, ndarray@^1.0.19: version "1.0.19" resolved "https://registry.yarnpkg.com/ndarray/-/ndarray-1.0.19.tgz#6785b5f5dfa58b83e31ae5b2a058cfd1ab3f694e" integrity sha512-B4JHA4vdyZU30ELBw3g7/p9bZupyew5a7tX1Y/gGeF2hafrPaQZhgrGQfsvgfYbgdFZjYwuEcnaobeM/WMW+HQ==