Skip to content

Commit

Permalink
fix(viewport): Reset viewport state and fix CINE looping, thumbnail r…
Browse files Browse the repository at this point in the history
…esolution, and dynamic tool settings (#4037)
  • Loading branch information
sedghi authored Apr 16, 2024
1 parent a6c6fff commit f99a0bf
Show file tree
Hide file tree
Showing 80 changed files with 1,148 additions and 820 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,10 @@ function OHIFCornerstoneRTViewport(props) {
orientation: viewportOptions.orientation,
viewportId: viewportOptions.viewportId,
}}
onElementEnabled={onElementEnabled}
onElementEnabled={evt => {
props.onElementEnabled?.(evt);
onElementEnabled(evt);
}}
onElementDisabled={onElementDisabled}
></Component>
);
Expand Down
6 changes: 3 additions & 3 deletions extensions/cornerstone-dicom-seg/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -46,9 +46,9 @@
},
"dependencies": {
"@babel/runtime": "^7.20.13",
"@cornerstonejs/adapters": "^1.70.5",
"@cornerstonejs/core": "^1.70.5",
"@kitware/vtk.js": "30.3.1",
"@cornerstonejs/adapters": "^1.70.6",
"@cornerstonejs/core": "^1.70.6",
"@kitware/vtk.js": "30.3.3",
"react-color": "^2.19.3"
}
}
27 changes: 0 additions & 27 deletions extensions/cornerstone-dicom-seg/src/commandsModule.ts
Original file line number Diff line number Diff line change
Expand Up @@ -434,30 +434,6 @@ const commandsModule = ({
});
});
},
toggleThresholdRangeAndDynamic() {
const toolGroupIds = toolGroupService.getToolGroupIds();

if (!toolGroupIds) {
return;
}

toolGroupIds.forEach(toolGroupId => {
const toolGroup = toolGroupService.getToolGroup(toolGroupId);
const brushInstances = segmentationUtils.getBrushToolInstances(toolGroup.id);

brushInstances.forEach(({ configuration }) => {
const { activeStrategy, strategySpecificConfiguration } = configuration;

if (activeStrategy.startsWith('THRESHOLD')) {
const thresholdConfig = strategySpecificConfiguration.THRESHOLD;

if (thresholdConfig) {
thresholdConfig.isDynamic = !thresholdConfig.isDynamic;
}
}
});
});
},
};

const definitions = {
Expand Down Expand Up @@ -491,9 +467,6 @@ const commandsModule = ({
setThresholdRange: {
commandFn: actions.setThresholdRange,
},
toggleThresholdRangeAndDynamic: {
commandFn: actions.toggleThresholdRangeAndDynamic,
},
};

return {
Expand Down
6 changes: 1 addition & 5 deletions extensions/cornerstone-dicom-seg/src/getToolbarModule.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,12 +59,8 @@ function getToolNameForButton(button) {
const commands = props?.commands || button.commands;
const commandsArray = Array.isArray(commands) ? commands : [commands];
const firstCommand = commandsArray[0];
if (typeof firstCommand === 'string') {
// likely not a cornerstone tool
return null;
}

if ('commandOptions' in firstCommand) {
if (firstCommand?.commandOptions) {
return firstCommand.commandOptions.toolName ?? props?.id ?? button.id;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,13 @@ export default function PanelSegmentation({
extensionManager,
configuration,
}) {
const { segmentationService, viewportGridService, uiDialogService } = servicesManager.services;
const { segmentationService, viewportGridService, uiDialogService, displaySetService } =
servicesManager.services;

const { t } = useTranslation('PanelSegmentation');

const [selectedSegmentationId, setSelectedSegmentationId] = useState(null);
const [addSegmentationClassName, setAddSegmentationClassName] = useState('');
const [segmentationConfiguration, setSegmentationConfiguration] = useState(
segmentationService.getConfiguration()
);
Expand Down Expand Up @@ -52,6 +54,52 @@ export default function PanelSegmentation({
};
}, []);

// temporary measure to not allow add segmentation when the selected viewport
// is stack viewport
useEffect(() => {
const handleActiveViewportChange = viewportId => {
const displaySetUIDs = viewportGridService.getDisplaySetsUIDsForViewport(
viewportId || viewportGridService.getActiveViewportId()
);

if (!displaySetUIDs) {
return;
}

const isReconstructable =
displaySetUIDs?.some(displaySetUID => {
const displaySet = displaySetService.getDisplaySetByUID(displaySetUID);
return displaySet?.isReconstructable;
}) || false;

if (isReconstructable) {
setAddSegmentationClassName('');
} else {
setAddSegmentationClassName('ohif-disabled');
}
};

// Handle initial state
handleActiveViewportChange();

const changed = viewportGridService.EVENTS.ACTIVE_VIEWPORT_ID_CHANGED;
const ready = viewportGridService.EVENTS.VIEWPORTS_READY;

const subs = [];
[ready, changed].forEach(evt => {
const { unsubscribe } = viewportGridService.subscribe(evt, ({ viewportId }) => {
handleActiveViewportChange(viewportId);
});

subs.push(unsubscribe);
});

// Clean up
return () => {
subs.forEach(unsub => unsub());
};
}, []);

const getToolGroupIds = segmentationId => {
const toolGroupIds = segmentationService.getToolGroupIdsWithSegmentation(segmentationId);

Expand Down Expand Up @@ -152,6 +200,7 @@ export default function PanelSegmentation({
segmentationService.removeSegment(segmentationId, segmentIndex);
};

// segment hide
const onToggleSegmentVisibility = (segmentationId, segmentIndex) => {
const segmentation = segmentationService.getSegmentation(segmentationId);
const segmentInfo = segmentation.segments[segmentIndex];
Expand Down Expand Up @@ -257,6 +306,7 @@ export default function PanelSegmentation({
disableEditing={configuration.disableEditing}
activeSegmentationId={selectedSegmentationId || ''}
onSegmentationAdd={onSegmentationAddWrapper}
addSegmentationClassName={addSegmentationClassName}
showAddSegment={allowAddSegment}
onSegmentationClick={onSegmentationClick}
onSegmentationDelete={onSegmentationDelete}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,10 @@ function OHIFCornerstoneSEGViewport(props) {
orientation: viewportOptions.orientation,
viewportId: viewportOptions.viewportId,
}}
onElementEnabled={onElementEnabled}
onElementEnabled={evt => {
props.onElementEnabled?.(evt);
onElementEnabled(evt);
}}
onElementDisabled={onElementDisabled}
></Component>
);
Expand Down
6 changes: 3 additions & 3 deletions extensions/cornerstone-dicom-sr/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -46,9 +46,9 @@
},
"dependencies": {
"@babel/runtime": "^7.20.13",
"@cornerstonejs/adapters": "^1.70.5",
"@cornerstonejs/core": "^1.70.5",
"@cornerstonejs/tools": "^1.70.5",
"@cornerstonejs/adapters": "^1.70.6",
"@cornerstonejs/core": "^1.70.6",
"@cornerstonejs/tools": "^1.70.6",
"classnames": "^2.3.2"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ export default class DICOMSRDisplayTool extends AnnotationTool {

// Filter toolData to only render the data for the active SR.
const filteredAnnotations = annotations.filter(annotation =>
trackingUniqueIdentifiers.includes(annotation.data?.cachedStats?.TrackingUniqueIdentifier)
trackingUniqueIdentifiers.includes(annotation.data?.TrackingUniqueIdentifier)
);

if (!viewport._actors?.size) {
Expand All @@ -82,8 +82,7 @@ export default class DICOMSRDisplayTool extends AnnotationTool {
for (let i = 0; i < filteredAnnotations.length; i++) {
const annotation = filteredAnnotations[i];
const annotationUID = annotation.annotationUID;
const { renderableData } = annotation.data.cachedStats;
const { cachedStats } = annotation.data;
const { renderableData, TrackingUniqueIdentifier } = annotation.data;
const { referencedImageId } = annotation.metadata;

styleSpecifier.annotationUID = annotationUID;
Expand All @@ -95,7 +94,7 @@ export default class DICOMSRDisplayTool extends AnnotationTool {
const lineWidth = this.getStyle('lineWidth', styleSpecifier, annotation);
const lineDash = this.getStyle('lineDash', styleSpecifier, annotation);
const color =
cachedStats.TrackingUniqueIdentifier === activeTrackingUniqueIdentifier
TrackingUniqueIdentifier === activeTrackingUniqueIdentifier
? 'rgb(0, 255, 0)'
: this.getStyle('color', styleSpecifier, annotation);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,10 +51,9 @@ export default function addDICOMSRDisplayAnnotation(measurement, imageId, frameN
handles: {
textBox: measurement.textBox ?? {},
},
cachedStats: {
TrackingUniqueIdentifier: measurementData.TrackingUniqueIdentifier,
renderableData: measurementData.renderableData,
},
cachedStats: {},
TrackingUniqueIdentifier: measurementData.TrackingUniqueIdentifier,
renderableData: measurementData.renderableData,
frameNumber,
},
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { setTrackingUniqueIdentifiersForElement } from '../tools/modules/dicomSR
import { Icon, Tooltip, useViewportGrid, ViewportActionArrows } from '@ohif/ui';
import hydrateStructuredReport from '../utils/hydrateStructuredReport';
import { useAppConfig } from '@state';
import createReferencedImageDisplaySet from '../utils/createReferencedImageDisplaySet';

const MEASUREMENT_TRACKING_EXTENSION_ID = '@ohif/extension-measurement-tracking';

Expand Down Expand Up @@ -203,7 +204,10 @@ function OHIFCornerstoneSRViewport(props) {
// The positionIds for the viewport aren't meaningful for the child display sets
positionIds: null,
}}
onElementEnabled={onElementEnabled}
onElementEnabled={evt => {
props.onElementEnabled?.(evt);
onElementEnabled(evt);
}}
initialImageIndex={initialImageIndex}
isJumpToMeasurementDisabled={true}
></Component>
Expand Down Expand Up @@ -378,6 +382,10 @@ async function _getViewportReferencedDisplaySetData(
measurementSelected,
displaySetService
) {
const { measurements } = displaySet;
const measurement = measurements[measurementSelected];

const { displaySetInstanceUID } = measurement;
if (!displaySet.keyImageDisplaySet) {
// Create a new display set, and preserve a reference to it here,
// so that it can be re-displayed and shown inside the SR viewport.
Expand Down
6 changes: 3 additions & 3 deletions extensions/cornerstone-dynamic-volume/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,9 @@
},
"dependencies": {
"@babel/runtime": "^7.20.13",
"@cornerstonejs/core": "^1.70.5",
"@cornerstonejs/streaming-image-volume-loader": "^1.70.5",
"@cornerstonejs/tools": "^1.70.5",
"@cornerstonejs/core": "^1.70.6",
"@cornerstonejs/streaming-image-volume-loader": "^1.70.6",
"@cornerstonejs/tools": "^1.70.6",
"classnames": "^2.3.2"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ const DynamicVolumeControls = ({
className="w-1/2"
onClick={() => {
setComputedView(false);
onDynamicClick();
onDynamicClick?.();
}}
>
4D
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,7 @@ export default function PanelGenerateImage({ servicesManager, commandsManager })
}

const { element } = viewportInfo;
cineService.playClip(element, { framesPerSecond: frameRate });
cineService.playClip(element, { framesPerSecond: frameRate, viewportId: activeViewportId });
};

const handleStop = () => {
Expand Down
12 changes: 6 additions & 6 deletions extensions/cornerstone/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@
"@cornerstonejs/codec-libjpeg-turbo-8bit": "^1.2.2",
"@cornerstonejs/codec-openjpeg": "^1.2.2",
"@cornerstonejs/codec-openjph": "^2.4.2",
"@cornerstonejs/dicom-image-loader": "^1.70.5",
"@cornerstonejs/dicom-image-loader": "^1.70.6",
"@icr/polyseg-wasm": "^0.4.0",
"@ohif/core": "3.8.0-beta.80",
"@ohif/ui": "3.8.0-beta.80",
Expand All @@ -55,12 +55,12 @@
},
"dependencies": {
"@babel/runtime": "^7.20.13",
"@cornerstonejs/adapters": "^1.70.5",
"@cornerstonejs/core": "^1.70.5",
"@cornerstonejs/streaming-image-volume-loader": "^1.70.5",
"@cornerstonejs/tools": "^1.70.5",
"@cornerstonejs/adapters": "^1.70.6",
"@cornerstonejs/core": "^1.70.6",
"@cornerstonejs/streaming-image-volume-loader": "^1.70.6",
"@cornerstonejs/tools": "^1.70.6",
"@icr/polyseg-wasm": "^0.4.0",
"@kitware/vtk.js": "30.3.1",
"@kitware/vtk.js": "30.3.3",
"html2canvas": "^1.4.1",
"lodash.debounce": "4.0.8",
"lodash.merge": "^4.6.2",
Expand Down
13 changes: 12 additions & 1 deletion extensions/cornerstone/src/Viewport/OHIFCornerstoneViewport.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -114,10 +114,21 @@ const OHIFCornerstoneViewport = React.memo(props => {
// of the imageData in the OHIFCornerstoneViewport. This prop is used
// to set the initial state of the viewport's first image to render
initialImageIndex,
// if the viewport is part of a hanging protocol layout
// we should not really rely on the old synchronizers and
// you see below we only rehydrate the synchronizers if the viewport
// is not part of the hanging protocol layout. HPs should
// define their own synchronizers. Since the synchronizers are
// viewportId dependent and
isHangingProtocolLayout,
} = props;

const viewportId = viewportOptions.viewportId;

if (!viewportId) {
throw new Error('Viewport ID is required');
}

// Since we only have support for dynamic data in volume viewports, we should
// handle this case here and set the viewportType to volume if any of the
// displaySets are dynamic volumes
Expand Down Expand Up @@ -194,7 +205,7 @@ const OHIFCornerstoneViewport = React.memo(props => {

const synchronizersStore = stateSyncService.getState().synchronizersStore;

if (synchronizersStore?.[viewportId]?.length) {
if (synchronizersStore?.[viewportId]?.length && !isHangingProtocolLayout) {
// If the viewport used to have a synchronizer, re apply it again
_rehydrateSynchronizers(synchronizersStore, viewportId, syncGroupService);
}
Expand Down
Loading

0 comments on commit f99a0bf

Please sign in to comment.