diff --git a/extensions/cornerstone-dynamic-volume/src/panels/DynamicDataPanel.tsx b/extensions/cornerstone-dynamic-volume/src/panels/DynamicDataPanel.tsx index 6be93c1d3..d885d2e95 100644 --- a/extensions/cornerstone-dynamic-volume/src/panels/DynamicDataPanel.tsx +++ b/extensions/cornerstone-dynamic-volume/src/panels/DynamicDataPanel.tsx @@ -4,7 +4,7 @@ import PanelGenerateImage from './PanelGenerateImage'; function DynamicDataPanel({ servicesManager, commandsManager }) { return (
{ + const { cornerstoneViewportService, toolbarService, segmentationService } = + servicesManager.services; + toolbarService.registerEventForToolbarUpdate(cornerstoneViewportService, [ + cornerstoneViewportService.EVENTS.VIEWPORT_DATA_CHANGED, + ]); + + toolbarService.registerEventForToolbarUpdate(segmentationService, [ + segmentationService.EVENTS.SEGMENTATION_ADDED, + segmentationService.EVENTS.SEGMENTATION_REMOVED, + segmentationService.EVENTS.SEGMENTATION_UPDATED, + ]); + + toolbarService.registerEventForToolbarUpdate(cornerstone.eventTarget, [ + cornerstoneTools.Enums.Events.TOOL_ACTIVATED, + ]); + }, + onModeExit: ({ servicesManager }): void => { const { cineService } = servicesManager.services; // Empty out the image load and retrieval pools to prevent memory leaks diff --git a/extensions/cornerstone/src/init.tsx b/extensions/cornerstone/src/init.tsx index b7ec7abde..9e5f2c38c 100644 --- a/extensions/cornerstone/src/init.tsx +++ b/extensions/cornerstone/src/init.tsx @@ -99,26 +99,10 @@ export default async function init({ uiNotificationService, cornerstoneViewportService, hangingProtocolService, - toolbarService, viewportGridService, stateSyncService, - segmentationService, } = servicesManager.services as CornerstoneServices; - toolbarService.registerEventForToolbarUpdate(cornerstoneViewportService, [ - cornerstoneViewportService.EVENTS.VIEWPORT_DATA_CHANGED, - ]); - - toolbarService.registerEventForToolbarUpdate(segmentationService, [ - segmentationService.EVENTS.SEGMENTATION_ADDED, - segmentationService.EVENTS.SEGMENTATION_REMOVED, - segmentationService.EVENTS.SEGMENTATION_UPDATED, - ]); - - toolbarService.registerEventForToolbarUpdate(eventTarget, [ - cornerstoneTools.Enums.Events.TOOL_ACTIVATED, - ]); - window.services = servicesManager.services; window.extensionManager = extensionManager; window.commandsManager = commandsManager; diff --git a/extensions/cornerstone/src/services/CornerstoneCacheService/CornerstoneCacheService.ts b/extensions/cornerstone/src/services/CornerstoneCacheService/CornerstoneCacheService.ts index a8d40b3d0..74f5d7ac3 100644 --- a/extensions/cornerstone/src/services/CornerstoneCacheService/CornerstoneCacheService.ts +++ b/extensions/cornerstone/src/services/CornerstoneCacheService/CornerstoneCacheService.ts @@ -98,7 +98,21 @@ class CornerstoneCacheService { const volume = cs3DCache.getVolume(volumeId); if (volume) { - cs3DCache.removeVolumeLoadObject(volumeId); + if (volume.imageIds) { + // also for each imageId in the volume, remove the imageId from the cache + // since that will hold the old metadata as well + + volume.imageIds.forEach(imageId => { + if (cs3DCache.getImageLoadObject(imageId)) { + cs3DCache.removeImageLoadObject(imageId); + } + }); + } + + // this shouldn't be via removeVolumeLoadObject, since that will + // remove the texture as well, but here we really just need a remove + // from registry so that we load it again + cs3DCache._volumeCache.delete(volumeId); this.volumeImageIds.delete(volumeId); } diff --git a/extensions/cornerstone/src/services/SegmentationService/SegmentationService.ts b/extensions/cornerstone/src/services/SegmentationService/SegmentationService.ts index 579dc93bd..355bcd0f5 100644 --- a/extensions/cornerstone/src/services/SegmentationService/SegmentationService.ts +++ b/extensions/cornerstone/src/services/SegmentationService/SegmentationService.ts @@ -1147,6 +1147,10 @@ class SegmentationService extends PubSubService { displaySet.isHydrated = isHydrated; displaySetService.setDisplaySetMetadataInvalidated(displaySetUID, false); + + this._broadcastEvent(this.EVENTS.SEGMENTATION_UPDATED, { + segmentation: this.getSegmentation(displaySetUID), + }); } private _highlightLabelmap( diff --git a/extensions/cornerstone/src/utils/measurementServiceMappings/CircleROI.ts b/extensions/cornerstone/src/utils/measurementServiceMappings/CircleROI.ts index c995fb171..88ca76862 100644 --- a/extensions/cornerstone/src/utils/measurementServiceMappings/CircleROI.ts +++ b/extensions/cornerstone/src/utils/measurementServiceMappings/CircleROI.ts @@ -2,6 +2,7 @@ import SUPPORTED_TOOLS from './constants/supportedTools'; import { getDisplayUnit } from './utils'; import getSOPInstanceAttributes from './utils/getSOPInstanceAttributes'; import { utils } from '@ohif/core'; +import { getStatisticDisplayString } from './utils/getValueDisplayString'; const CircleROI = { toAnnotation: measurement => {}, @@ -193,11 +194,7 @@ function getDisplayText(mappedAnnotations, displaySet, customizationService) { mappedAnnotations.forEach(mappedAnnotation => { const { unit, max, SeriesNumber } = mappedAnnotation; - let maxStr = ''; - if (max) { - const roundedMax = utils.roundNumber(max, 2); - maxStr = `Max: ${roundedMax} ${getDisplayUnit(unit)} `; - } + const maxStr = getStatisticDisplayString(max, unit, 'max'); const str = `${maxStr}(S:${SeriesNumber}${instanceText}${frameText})`; if (!displayText.includes(str)) { diff --git a/extensions/cornerstone/src/utils/measurementServiceMappings/EllipticalROI.ts b/extensions/cornerstone/src/utils/measurementServiceMappings/EllipticalROI.ts index 30a925dd1..c406b9972 100644 --- a/extensions/cornerstone/src/utils/measurementServiceMappings/EllipticalROI.ts +++ b/extensions/cornerstone/src/utils/measurementServiceMappings/EllipticalROI.ts @@ -2,6 +2,7 @@ import SUPPORTED_TOOLS from './constants/supportedTools'; import { getDisplayUnit } from './utils'; import getSOPInstanceAttributes from './utils/getSOPInstanceAttributes'; import { utils } from '@ohif/core'; +import { getStatisticDisplayString } from './utils/getValueDisplayString'; const EllipticalROI = { toAnnotation: measurement => {}, @@ -192,12 +193,7 @@ function getDisplayText(mappedAnnotations, displaySet, customizationService) { mappedAnnotations.forEach(mappedAnnotation => { const { unit, max, SeriesNumber } = mappedAnnotation; - let maxStr = ''; - if (max) { - const roundedMax = utils.roundNumber(max, 2); - maxStr = `Max: ${roundedMax} ${getDisplayUnit(unit)} `; - } - + const maxStr = getStatisticDisplayString(max, unit, 'max'); const str = `${maxStr}(S:${SeriesNumber}${instanceText}${frameText})`; if (!displayText.includes(str)) { displayText.push(str); diff --git a/extensions/cornerstone/src/utils/measurementServiceMappings/RectangleROI.ts b/extensions/cornerstone/src/utils/measurementServiceMappings/RectangleROI.ts index 943822de7..4718e617a 100644 --- a/extensions/cornerstone/src/utils/measurementServiceMappings/RectangleROI.ts +++ b/extensions/cornerstone/src/utils/measurementServiceMappings/RectangleROI.ts @@ -2,6 +2,7 @@ import SUPPORTED_TOOLS from './constants/supportedTools'; import { getDisplayUnit } from './utils'; import getSOPInstanceAttributes from './utils/getSOPInstanceAttributes'; import { utils } from '@ohif/core'; +import { getStatisticDisplayString } from './utils/getValueDisplayString'; const RectangleROI = { toAnnotation: measurement => {}, @@ -193,11 +194,7 @@ function getDisplayText(mappedAnnotations, displaySet, customizationService) { mappedAnnotations.forEach(mappedAnnotation => { const { unit, max, SeriesNumber } = mappedAnnotation; - let maxStr = ''; - if (max) { - const roundedMax = utils.roundNumber(max, 2); - maxStr = `Max: ${roundedMax} ${getDisplayUnit(unit)} `; - } + const maxStr = getStatisticDisplayString(max, unit, 'max'); const str = `${maxStr}(S:${SeriesNumber}${instanceText}${frameText})`; if (!displayText.includes(str)) { diff --git a/extensions/cornerstone/src/utils/measurementServiceMappings/SplineROI.ts b/extensions/cornerstone/src/utils/measurementServiceMappings/SplineROI.ts index 05ed5b1dc..b1bac9f54 100644 --- a/extensions/cornerstone/src/utils/measurementServiceMappings/SplineROI.ts +++ b/extensions/cornerstone/src/utils/measurementServiceMappings/SplineROI.ts @@ -1,6 +1,5 @@ import SUPPORTED_TOOLS from './constants/supportedTools'; import getSOPInstanceAttributes from './utils/getSOPInstanceAttributes'; -import { getDisplayUnit } from './utils'; import { utils } from '@ohif/core'; /** diff --git a/extensions/cornerstone/src/utils/measurementServiceMappings/utils/getValueDisplayString.js b/extensions/cornerstone/src/utils/measurementServiceMappings/utils/getValueDisplayString.js new file mode 100644 index 000000000..aa0fe316c --- /dev/null +++ b/extensions/cornerstone/src/utils/measurementServiceMappings/utils/getValueDisplayString.js @@ -0,0 +1,12 @@ +import { utils } from '@ohif/core'; +import getDisplayUnit from './getDisplayUnit'; + +export const getStatisticDisplayString = (numbers, unit, key) => { + if (Array.isArray(numbers) && numbers.length > 0) { + const results = numbers.map(number => utils.roundNumber(number, 2)); + return `${key.charAt(0).toUpperCase() + key.slice(1)}: ${results.join(', ')} ${getDisplayUnit(unit)}`; + } + + const result = utils.roundNumber(numbers, 2); + return `${key.charAt(0).toUpperCase() + key.slice(1)}: ${result} ${getDisplayUnit(unit)}`; +}; diff --git a/modes/segmentation/src/initToolGroups.ts b/modes/segmentation/src/initToolGroups.ts index 8b2c28da9..540edf01d 100644 --- a/modes/segmentation/src/initToolGroups.ts +++ b/modes/segmentation/src/initToolGroups.ts @@ -55,10 +55,13 @@ function createTools(utilityModule) { parentTool: 'Brush', configuration: { activeStrategy: 'THRESHOLD_INSIDE_CIRCLE', - preview: { - enabled: true, - }, + // preview: { + // enabled: true, + // }, strategySpecificConfiguration: { + // to use the use the center segment index to determine + // if inside -> same segment, if outside -> eraser + // useCenterSegmentIndex: true, THRESHOLD: { isDynamic: true, dynamicRadius: 3, diff --git a/modes/segmentation/src/segmentationButtons.ts b/modes/segmentation/src/segmentationButtons.ts index cb096a9c6..800ea99fd 100644 --- a/modes/segmentation/src/segmentationButtons.ts +++ b/modes/segmentation/src/segmentationButtons.ts @@ -112,21 +112,15 @@ const toolbarButtons: Button[] = [ commands: { commandName: 'setBrushSize', commandOptions: { - toolNames: ['ThresholdCircularBrush', 'ThresholdSphereBrush'], + toolNames: [ + 'ThresholdCircularBrush', + 'ThresholdSphereBrush', + 'ThresholdCircularBrushDynamic', + ], }, }, }, - { - name: 'Shape', - type: 'radio', - id: 'eraser-mode', - value: 'ThresholdCircularBrush', - values: [ - { value: 'ThresholdCircularBrush', label: 'Circle' }, - { value: 'ThresholdSphereBrush', label: 'Sphere' }, - ], - commands: 'setToolActiveToolbar', - }, + { name: 'Threshold', type: 'radio', @@ -148,6 +142,19 @@ const toolbarButtons: Button[] = [ } }, }, + { + name: 'Shape', + type: 'radio', + id: 'eraser-mode', + value: 'ThresholdCircularBrush', + values: [ + { value: 'ThresholdCircularBrush', label: 'Circle' }, + { value: 'ThresholdSphereBrush', label: 'Sphere' }, + ], + condition: ({ options }) => + options.find(option => option.id === 'dynamic-mode').value === 'ThresholdRange', + commands: 'setToolActiveToolbar', + }, { name: 'ThresholdRange', type: 'double-range', diff --git a/modes/tmtv/src/index.js b/modes/tmtv/src/index.js index 7acca7c92..da318a527 100644 --- a/modes/tmtv/src/index.js +++ b/modes/tmtv/src/index.js @@ -1,7 +1,7 @@ import { hotkeys, classes } from '@ohif/core'; import toolbarButtons from './toolbarButtons.js'; import { id } from './id.js'; -import initToolGroups, { toolGroupIds } from './initToolGroups.js'; +import initToolGroups from './initToolGroups.js'; import setCrosshairsConfiguration from './utils/setCrosshairsConfiguration.js'; import setFusionActiveVolume from './utils/setFusionActiveVolume.js'; import i18n from 'i18next'; @@ -112,19 +112,6 @@ function modeFactory({ modeConfiguration }) { }, ]); - // This is a hack and we need to find a better way to enable - // some tools that require the viewport to be ready - const { unsubscribe: unsub1 } = viewportGridService.subscribe( - viewportGridService.EVENTS.VIEWPORTS_READY, - () => { - commandsManager.run('setToolEnabled', { - toolName: 'OrientationMarker', - toolGroupId: 'mipToolGroup', - }); - unsub1(); - } - ); - // For the hanging protocol we need to decide on the window level // based on whether the SUV is corrected or not, hence we can't hard // code the window level in the hanging protocol but we add a custom diff --git a/platform/app/src/routes/Mode/Mode.tsx b/platform/app/src/routes/Mode/Mode.tsx index 53b881e51..791927455 100644 --- a/platform/app/src/routes/Mode/Mode.tsx +++ b/platform/app/src/routes/Mode/Mode.tsx @@ -242,7 +242,7 @@ export default function ModeRoute({ const lowerVal = val.toLowerCase(); if (lowerVal !== 'studyinstanceuids') { // Not sure why the case matters here - it doesn't in the URL - if (lowerVal === 'seriesinstanceuid') { + if (lowerVal === 'seriesinstanceuids') { const seriesUIDs = getSplitParam(lowerVal, query); return { ...acc, diff --git a/platform/app/src/routes/Mode/defaultRouteInit.ts b/platform/app/src/routes/Mode/defaultRouteInit.ts index 975ac4d8b..863cb1946 100644 --- a/platform/app/src/routes/Mode/defaultRouteInit.ts +++ b/platform/app/src/routes/Mode/defaultRouteInit.ts @@ -4,7 +4,7 @@ import isSeriesFilterUsed from '../../utils/isSeriesFilterUsed'; import { utils, Enums } from '@ohif/core'; -const { sortingCriteria } = utils; +const { sortingCriteria, getSplitParam } = utils; /** * Initialize the route. @@ -95,6 +95,18 @@ export async function defaultRouteInit( }); }); + // is displaysets from URL and has initialSOPInstanceUID or initialSeriesInstanceUID + // then we need to wait for all display sets to be retrieved before applying the hanging protocol + const params = new URLSearchParams(window.location.search); + + const initialSeriesInstanceUID = getSplitParam('initialseriesinstanceuid', params); + const initialSOPInstanceUID = getSplitParam('initialsopinstanceuid', params); + + let displaySetFromUrl = false; + if (initialSeriesInstanceUID || initialSOPInstanceUID) { + displaySetFromUrl = true; + } + await Promise.allSettled(allRetrieves).then(async promises => { log.timeEnd(Enums.TimingEnum.STUDY_TO_DISPLAY_SETS); log.time(Enums.TimingEnum.DISPLAY_SETS_TO_FIRST_IMAGE); @@ -109,7 +121,16 @@ export async function defaultRouteInit( promises.forEach(promise => { const retrieveSeriesMetadataPromise = promise.value; - if (Array.isArray(retrieveSeriesMetadataPromise)) { + if (!Array.isArray(retrieveSeriesMetadataPromise)) { + return; + } + + if (displaySetFromUrl) { + const requiredSeriesPromises = retrieveSeriesMetadataPromise.map(promise => + promise.start() + ); + allPromises.push(Promise.allSettled(requiredSeriesPromises)); + } else { const { requiredSeries, remaining } = hangingProtocolService.filterSeriesRequiredForRun( hangingProtocolId, retrieveSeriesMetadataPromise diff --git a/platform/core/src/services/HangingProtocolService/HangingProtocolService.ts b/platform/core/src/services/HangingProtocolService/HangingProtocolService.ts index 90c19c458..524a45615 100644 --- a/platform/core/src/services/HangingProtocolService/HangingProtocolService.ts +++ b/platform/core/src/services/HangingProtocolService/HangingProtocolService.ts @@ -1314,19 +1314,18 @@ export default class HangingProtocolService extends PubSubService { ); // Use the display set provided instead - // Todo: find out what is wrong here - // if (reuseDisplaySetUID) { - // if (viewportOptions.allowUnmatchedView !== true) { - // this.validateDisplaySetSelectMatch(viewportDisplaySet, id, reuseDisplaySetUID); - // } - // const displaySetInfo: HangingProtocol.DisplaySetInfo = { - // displaySetInstanceUID: reuseDisplaySetUID, - // displaySetOptions, - // }; + if (reuseDisplaySetUID) { + if (viewportOptions.allowUnmatchedView !== true) { + this.validateDisplaySetSelectMatch(viewportDisplaySet, id, reuseDisplaySetUID); + } + const displaySetInfo: HangingProtocol.DisplaySetInfo = { + displaySetInstanceUID: reuseDisplaySetUID, + displaySetOptions, + }; - // displaySetsInfo.push(displaySetInfo); - // return; - // } + displaySetsInfo.push(displaySetInfo); + return; + } // Use the display set index to allow getting the "next" match, eg // matching all display sets, and get the matchedDisplaySetsIndex'th item diff --git a/platform/core/src/services/HangingProtocolService/custom-attribute/isDisplaySetFromUrl.ts b/platform/core/src/services/HangingProtocolService/custom-attribute/isDisplaySetFromUrl.ts index 20ebb76fe..0689e0c05 100644 --- a/platform/core/src/services/HangingProtocolService/custom-attribute/isDisplaySetFromUrl.ts +++ b/platform/core/src/services/HangingProtocolService/custom-attribute/isDisplaySetFromUrl.ts @@ -13,15 +13,16 @@ const isDisplaySetFromUrl = (displaySet): boolean => { if (!initialSeriesInstanceUID && !initialSOPInstanceUID) { return false; } - const isSeriesMatch = - !initialSeriesInstanceUID || - initialSeriesInstanceUID.some(seriesUID => displaySet.SeriesInstanceUID === seriesUID); - const isSopMatch = - !initialSOPInstanceUID || - displaySet.instances?.some?.(instance => - initialSOPInstanceUID.some(sopUID => sopUID === instance.SOPInstanceUID) - ); - return isSeriesMatch && isSopMatch; + + const isSeriesMatch = initialSeriesInstanceUID?.some( + seriesUID => displaySet.SeriesInstanceUID === seriesUID + ); + + const isSopMatch = initialSOPInstanceUID?.some(sopUID => + displaySet.instances?.some(instance => sopUID === instance.SOPInstanceUID) + ); + + return isSeriesMatch || isSopMatch; }; /** Returns the index location of the requested image, or the defaultValue in this. diff --git a/platform/core/src/utils/metadataProvider/getPixelSpacingInformation.js b/platform/core/src/utils/metadataProvider/getPixelSpacingInformation.js index 9e8425a15..0941136c5 100644 --- a/platform/core/src/utils/metadataProvider/getPixelSpacingInformation.js +++ b/platform/core/src/utils/metadataProvider/getPixelSpacingInformation.js @@ -28,7 +28,6 @@ export default function getPixelSpacingInformation(instance) { PixelSpacingCalibrationType, PixelSpacingCalibrationDescription, EstimatedRadiographicMagnificationFactor, - SequenceOfUltrasoundRegions, } = instance; const isProjection = projectionRadiographSOPClassUIDs.includes(SOPClassUID); @@ -90,21 +89,6 @@ export default function getPixelSpacingInformation(instance) { PixelSpacing: CorrectedImagerPixelSpacing, isProjection, }; - } else if (SequenceOfUltrasoundRegions && typeof SequenceOfUltrasoundRegions === 'object') { - const { PhysicalDeltaX, PhysicalDeltaY } = SequenceOfUltrasoundRegions; - const USPixelSpacing = [PhysicalDeltaX * 10, PhysicalDeltaY * 10]; - - return { - PixelSpacing: USPixelSpacing, - }; - } else if ( - SequenceOfUltrasoundRegions && - Array.isArray(SequenceOfUltrasoundRegions) && - SequenceOfUltrasoundRegions.length > 1 - ) { - log.warn( - 'Sequence of Ultrasound Regions > one entry. This is not yet implemented, all measurements will be shown in pixels.' - ); } else if (isProjection === false && !ImagerPixelSpacing) { // If only Pixel Spacing is present, and this is not a projection radiograph, // we can stop here diff --git a/platform/docs/docs/configuration/url.md b/platform/docs/docs/configuration/url.md index c81464e2f..cac7e5ad4 100644 --- a/platform/docs/docs/configuration/url.md +++ b/platform/docs/docs/configuration/url.md @@ -120,47 +120,74 @@ values. ::: -### SeriesInstanceUID, SeriesInstanceUIDs and initialSeriesInstanceUID +### SeriesInstanceUIDs Sometimes you need to only retrieve a specific series in a study, you can do that by providing series level QIDO query parameters in the URL such as -SeriesInstanceUID or SeriesNumber. This does NOT work with instance or study +SeriesInstanceUIDs. This does NOT work with instance or study level parameters. For example: ```js -http://localhost:3000/viewer?StudyInstanceUIDs=1.3.6.1.4.1.25403.345050719074.3824.20170125113417.1&SeriesInstanceUID=1.3.6.1.4.1.25403.345050719074.3824.20170125113545.4 +http://localhost:3000/viewer?StudyInstanceUIDs=1.3.6.1.4.1.25403.345050719074.3824.20170125095438.5&SeriesInstanceUIDs=1.3.6.1.4.1.25403.345050719074.3824.20170125095449.8 ``` This will only open the viewer with one series (one displaySet) loaded, and no queries made for any other series. Sometimes you need to only retrieve a subset of series in a study, you can do -that by providing study level wado query parameters in the URL such as -SeriesInstanceUIDs. For example: +that by providing more than one series, separated by commas. For example: ```js -http://localhost:3000/viewer?StudyInstanceUIDs=1.3.6.1.4.1.25403.345050719074.3824.20170125113417.1&SeriesInstanceUIDs=1.3.6.1.4.1.25403.345050719074.3824.20170125113545.4,1.3.6.1.4.1.25403.345050719074.3824.20170125113545.5 +http://localhost:3000/viewer?StudyInstanceUIDs=1.3.6.1.4.1.25403.345050719074.3824.20170125095438.5&SeriesInstanceUIDs=1.3.6.1.4.1.25403.345050719074.3824.20170125095449.8,1.3.6.1.4.1.25403.345050719074.3824.20170125095506.10 ``` This will only open the viewer with two series (two displaySets) loaded, and no queries made for any other series. -Alternatively, sometimes you want to just open the study on a specified series -and/or display a particular sop instance, which you can accomplish using: -`initialSeriesInstanceUID` and/or `initialSOPInstanceUID` -to select the series to open on, but allowing other -series to be present in the study browser panel. This is the same behaviour -as in OHIF 2.0, albeit on different URL parameters. For example: +### initialSeriesInstanceUID + +Alternatively, sometimes you want to just open the study on a specified series, but allowing other +series to be present too. This is the same behavior can be +achieved by using the `initialSeriesInstanceUID` parameter. For example: ```js -http://localhost:3000/viewer?StudyInstanceUIDs=1.3.6.1.4.1.25403.345050719074.3824.20170125113417.1&initialSeriesInstanceUID=1.3.6.1.4.1.25403.345050719074.3824.20170125113545.4 +http://localhost:3000/viewer?StudyInstanceUIDs=1.3.6.1.4.1.25403.345050719074.3824.20170125095438.5&initialSeriesInstanceUID=1.3.6.1.4.1.25403.345050719074.3824.20170125095449.8 ``` +This will open all the series in the study, but the viewer will start with the +series specified by the `initialSeriesInstanceUID` parameter. + + Note that you can combine these, if you want to load a specific set of series plus show an initial one as the first one selected, for example: ```js -http://localhost:3000/viewer?StudyInstanceUIDs=1.3.6.1.4.1.25403.345050719074.3824.20170125113417.1&SeriesInstanceUID=1.3.6.1.4.1.25403.345050719074.3824.20170125113545.4&initialSopInstanceUID=1.3.6.1.4.1.25403.345050719074.3824.20170125113546.1 +http://localhost:3000/viewer?StudyInstanceUIDs=1.3.6.1.4.1.25403.345050719074.3824.20170125095438.5&SeriesInstanceUIDs=1.3.6.1.4.1.25403.345050719074.3824.20170125095449.8,1.3.6.1.4.1.25403.345050719074.3824.20170125095506.10&initialSeriesInstanceUID=1.3.6.1.4.1.25403.345050719074.3824.20170125095506.10 +``` + +### initialSopInstanceUID + +You can also specify the initial SOP Instance to be displayed by using the +`initialSopInstanceUID` parameter. For example: + +```js +http://localhost:3000/viewer?StudyInstanceUIDs=1.3.6.1.4.1.25403.345050719074.3824.20170125095438.5&SeriesInstanceUIDs=1.3.6.1.4.1.25403.345050719074.3824.20170125095449.8&initialSopInstanceUID=1.3.6.1.4.1.25403.345050719074.3824.20170125095501.9 +``` + +This will open the study with the filtered series, and navigate to the slice 101 +which happens to be the SOP Instance specified by the `initialSopInstanceUID` + +Note: again you can mix and match + +```js +http://localhost:3000/viewer?StudyInstanceUIDs=1.3.6.1.4.1.25403.345050719074.3824.20170125095438.5&SeriesInstanceUIDs=1.3.6.1.4.1.25403.345050719074.3824.20170125095449.8,1.3.6.1.4.1.25403.345050719074.3824.20170125095506.10&initialSeriesInstanceUID=1.3.6.1.4.1.25403.345050719074.3824.20170125095506.10&initialSopInstanceUID=1.3.6.1.4.1.25403.345050719074.3824.20170125095510.8 +``` + +You can even load the whole study and only specify the initial SOP Instance to be displayed. Although +it will take more time to match, but it works as expected. + +```js +http://localhost:3000/viewer?StudyInstanceUIDs=1.3.6.1.4.1.25403.345050719074.3824.20170125095438.5&initialSopInstanceUID=1.3.6.1.4.1.25403.345050719074.3824.20170125095510.8 ``` ### hangingProtocolId @@ -169,6 +196,11 @@ You can select the initial hanging protocol to apply by using the hangingProtocolId parameter. The selected parameter must be available in a hangingProtocolModule registration, but does not have to be active. +For instance for loading a specific study in mpr mode from start you can use: + +```js +http://localhost:3000/viewer?StudyInstanceUIDs=1.3.6.1.4.1.25403.345050719074.3824.20170125095438.5&hangingProtocolId=@ohif/mnGrid +``` ### token