Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

OHIF 3.9 Recovery 3 #4697

Open
wants to merge 7 commits into
base: release/3.9
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ function OHIFCornerstonePMAPViewport(props: withAppTypes) {
viewportType: 'volume',
orientation: viewportOptions.orientation,
viewportId: viewportOptions.viewportId,
presentationIds: viewportOptions.presentationIds,
}}
displaySetOptions={[{}, pmapDisplaySetOptions]}
></Component>
Expand Down
10 changes: 9 additions & 1 deletion extensions/cornerstone-dicom-rt/src/loadRTStruct.js
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,7 @@ export default async function loadRTStruct(extensionManager, rtStructDisplaySet,
SeriesInstanceUID: instance.SeriesInstanceUID,
ROIContours: [],
visible: true,
ReferencedSOPInstanceUIDsSet: new Set(),
};

for (let i = 0; i < ROIContourSequence.length; i++) {
Expand All @@ -142,7 +143,8 @@ export default async function loadRTStruct(extensionManager, rtStructDisplaySet,

const contourPoints = [];
for (let c = 0; c < ContourSequenceArray.length; c++) {
const { ContourData, NumberOfContourPoints, ContourGeometricType } = ContourSequenceArray[c];
const { ContourData, NumberOfContourPoints, ContourGeometricType, ContourImageSequence } =
ContourSequenceArray[c];

let isSupported = false;

Expand Down Expand Up @@ -172,6 +174,12 @@ export default async function loadRTStruct(extensionManager, rtStructDisplaySet,
type: ContourGeometricType,
isSupported,
});

if (ContourImageSequence?.ReferencedSOPInstanceUID) {
structureSet.ReferencedSOPInstanceUIDsSet.add(
ContourImageSequence?.ReferencedSOPInstanceUID
);
}
}

_setROIContourMetadata(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import promptHydrateRT from '../utils/promptHydrateRT';
import _getStatusComponent from './_getStatusComponent';

import createRTToolGroupAndAddTools from '../utils/initRTToolGroup';
import { SegmentationRepresentations } from '@cornerstonejs/tools/enums';
import { usePositionPresentationStore } from '@ohif/extension-cornerstone';

const RT_TOOLGROUP_BASE_NAME = 'RTToolGroup';

Expand Down Expand Up @@ -43,8 +43,8 @@ function OHIFCornerstoneRTViewport(props: withAppTypes) {
const [viewportGrid, viewportGridService] = useViewportGrid();

// States
const [isToolGroupCreated, setToolGroupCreated] = useState(false);
const [selectedSegment, setSelectedSegment] = useState(1);
const { setPositionPresentation } = usePositionPresentationStore();

// Hydration means that the RT is opened and segments are loaded into the
// segmentation panel, and RT is also rendered on any viewport that is in the
Expand Down Expand Up @@ -123,6 +123,7 @@ function OHIFCornerstoneRTViewport(props: withAppTypes) {
toolGroupId: toolGroupId,
orientation: viewportOptions.orientation,
viewportId: viewportOptions.viewportId,
presentationIds: viewportOptions.presentationIds,
}}
onElementEnabled={evt => {
props.onElementEnabled?.(evt);
Expand Down Expand Up @@ -185,6 +186,19 @@ function OHIFCornerstoneRTViewport(props: withAppTypes) {
setRtIsLoading(false);
}

if (rtDisplaySet?.firstSegmentedSliceImageId && viewportOptions?.presentationIds) {
const { firstSegmentedSliceImageId } = rtDisplaySet;
const { presentationIds } = viewportOptions;

setPositionPresentation(presentationIds.positionPresentationId, {
viewportType: 'stack',
viewReference: {
referencedImageId: firstSegmentedSliceImageId,
},
viewPresentation: {},
});
}

if (evt.overlappingSegments) {
uiNotificationService.show({
title: 'Overlapping Segments',
Expand Down Expand Up @@ -247,8 +261,6 @@ function OHIFCornerstoneRTViewport(props: withAppTypes) {

toolGroup = createRTToolGroupAndAddTools(toolGroupService, customizationService, toolGroupId);

setToolGroupCreated(true);

return () => {
// remove the segmentation representations if seg displayset changed
segmentationService.removeSegmentationRepresentations(viewportId);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { LoadingIndicatorTotalPercent, useViewportGrid, ViewportActionArrows } f
import createSEGToolGroupAndAddTools from '../utils/initSEGToolGroup';
import promptHydrateSEG from '../utils/promptHydrateSEG';
import _getStatusComponent from './_getStatusComponent';
import { usePositionPresentationStore } from '@ohif/extension-cornerstone';
import { SegmentationRepresentations } from '@cornerstonejs/tools/enums';

const SEG_TOOLGROUP_BASE_NAME = 'SEGToolGroup';
Expand Down Expand Up @@ -41,6 +42,7 @@ function OHIFCornerstoneSEGViewport(props: withAppTypes) {

// States
const [selectedSegment, setSelectedSegment] = useState(1);
const { setPositionPresentation } = usePositionPresentationStore();

// Hydration means that the SEG is opened and segments are loaded into the
// segmentation panel, and SEG is also rendered on any viewport that is in the
Expand Down Expand Up @@ -198,6 +200,17 @@ function OHIFCornerstoneSEGViewport(props: withAppTypes) {
if (evt.segDisplaySet.displaySetInstanceUID === segDisplaySet.displaySetInstanceUID) {
setSegIsLoading(false);
}

if (segDisplaySet?.firstSegmentedSliceImageId && viewportOptions?.presentationIds) {
const { firstSegmentedSliceImageId } = segDisplaySet;
const { presentationIds } = viewportOptions;

setPositionPresentation(presentationIds.positionPresentationId, {
viewReference: {
referencedImageId: firstSegmentedSliceImageId,
},
});
}
}
);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,24 +9,20 @@ import { Icon, Tooltip, useViewportGrid, ViewportActionArrows } from '@ohif/ui';
import hydrateStructuredReport from '../utils/hydrateStructuredReport';
import { useAppConfig } from '@state';
import createReferencedImageDisplaySet from '../utils/createReferencedImageDisplaySet';
import { usePositionPresentationStore } from '@ohif/extension-cornerstone';

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

const SR_TOOLGROUP_BASE_NAME = 'SRToolGroup';

function OHIFCornerstoneSRMeasurementViewport(props: withAppTypes) {
const {
commandsManager,
children,
dataSource,
displaySets,
viewportOptions,
servicesManager,
extensionManager,
} = props;
const { children, dataSource, displaySets, viewportOptions, servicesManager, extensionManager } =
props;

const [appConfig] = useAppConfig();

const { setPositionPresentation } = usePositionPresentationStore();

const {
displaySetService,
cornerstoneViewportService,
Expand Down Expand Up @@ -157,30 +153,13 @@ function OHIFCornerstoneSRMeasurementViewport(props: withAppTypes) {
setActiveImageDisplaySetData(referencedDisplaySet);
setReferencedDisplaySetMetadata(referencedDisplaySetMetadata);

if (
referencedDisplaySet.displaySetInstanceUID ===
activeImageDisplaySetData?.displaySetInstanceUID
) {
const { measurements } = srDisplaySet;

// it means that we have a new referenced display set, and the
// imageIdIndex will handle it by updating the viewport, but if they
// are the same we just need to use measurementService to jump to the
// new measurement
const csViewport = cornerstoneViewportService.getCornerstoneViewport(viewportId);

if (!csViewport) {
return;
}

const imageIds = csViewport.getImageIds();

const imageIdIndex = imageIds.indexOf(measurements[newMeasurementSelected].imageId);

if (imageIdIndex !== -1) {
csViewport.setImageIdIndex(imageIdIndex);
}
}
const { presentationIds } = viewportOptions;
const measurement = srDisplaySet.measurements[newMeasurementSelected];
setPositionPresentation(presentationIds.positionPresentationId, {
viewReference: {
referencedImageId: measurement.imageId,
},
});
});
},
[dataSource, srDisplaySet, activeImageDisplaySetData, viewportId]
Expand All @@ -202,10 +181,6 @@ function OHIFCornerstoneSRMeasurementViewport(props: withAppTypes) {
return null;
}

const initialImageIndex = activeImageDisplaySetData.images.findIndex(
image => image.imageId === measurement.imageId
);

return (
<Component
{...props}
Expand All @@ -230,7 +205,6 @@ function OHIFCornerstoneSRMeasurementViewport(props: withAppTypes) {
props.onElementEnabled?.(evt);
onElementEnabled(evt);
}}
initialImageIndex={initialImageIndex}
isJumpToMeasurementDisabled={true}
></Component>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -262,7 +262,6 @@ function _getInstanceFromSegmentations(segmentations, { servicesManager }) {
}

function updateSegmentationsChartDisplaySet({ servicesManager }: withAppTypes): void {
debugger;
const { segmentationService } = servicesManager.services;
const segmentations = segmentationService.getSegmentations();
const { seriesMetadata, instance } =
Expand Down
2 changes: 1 addition & 1 deletion extensions/cornerstone/src/hps/frameView.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ const frameView: Types.HangingProtocol.Protocol = {
},
{
attribute: 'isDisplaySetFromUrl',
weight: 10,
weight: 20,
constraint: {
equals: true,
},
Expand Down
8 changes: 8 additions & 0 deletions extensions/cornerstone/src/panels/PanelSegmentation.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,14 @@ export default function PanelSegmentation({
const firstImageId = referencedImageIds[0];

const instance = metaData.get('instance', firstImageId);

if (!instance) {
return {
segmentationId,
isExportable: false,
};
}

const { SOPInstanceUID, SeriesInstanceUID } = instance;

const displaySet = displaySetService.getDisplaySetForSOPInstanceUID(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -478,14 +478,24 @@ class SegmentationService extends PubSubService {
// We should parse the segmentation as separate slices to support overlapping segments.
// This parsing should occur in the CornerstoneJS library adapters.
// For now, we use the volume returned from the library and chop it here.
let firstSegmentedSliceImageId = null;
for (let i = 0; i < derivedSegmentationImages.length; i++) {
const voxelManager = derivedSegmentationImages[i]
.voxelManager as csTypes.IVoxelManager<number>;
const scalarData = voxelManager.getScalarData();
scalarData.set(volumeScalarData.slice(i * scalarData.length, (i + 1) * scalarData.length));
const sliceData = volumeScalarData.slice(i * scalarData.length, (i + 1) * scalarData.length);
scalarData.set(sliceData);
voxelManager.setScalarData(scalarData);

// Check if this slice has any non-zero voxels and we haven't found one yet
if (!firstSegmentedSliceImageId && sliceData.some(value => value !== 0)) {
firstSegmentedSliceImageId = derivedSegmentationImages[i].referencedImageId;
}
}

// assign the first non zero voxel image id to the segDisplaySet
segDisplaySet.firstSegmentedSliceImageId = firstSegmentedSliceImageId;

this._broadcastEvent(EVENTS.SEGMENTATION_LOADING_COMPLETE, {
segmentationId,
segDisplaySet,
Expand Down Expand Up @@ -542,7 +552,19 @@ class SegmentationService extends PubSubService {
}

const rtDisplaySetUID = rtDisplaySet.displaySetInstanceUID;
const referencedDisplaySet = this.servicesManager.services.displaySetService.getDisplaySetByUID(
rtDisplaySet.referencedDisplaySetInstanceUID
);

const referencedImageIdsWithGeometry = Array.from(structureSet.ReferencedSOPInstanceUIDsSet);

const referencedImageIds = referencedDisplaySet.instances.map(image => image.imageId);
// find the first image id that contains a referenced SOP instance UID
const firstSegmentedSliceImageId = referencedImageIds.find(imageId =>
referencedImageIdsWithGeometry.some(referencedId => imageId.includes(referencedId))
);

rtDisplaySet.firstSegmentedSliceImageId = firstSegmentedSliceImageId;
// Map ROI contours to RT Struct Data
const allRTStructData = mapROIContoursToRTStructData(structureSet, rtDisplaySetUID);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -605,10 +605,6 @@ class CornerstoneViewportService extends PubSubService implements IViewportServi
let initialImageIndexToUse =
presentations?.positionPresentation?.initialImageIndex ?? initialImageIndex;

if (initialImageIndexToUse === undefined || initialImageIndexToUse === null) {
initialImageIndexToUse = this._getInitialImageIndexForViewport(viewportInfo, imageIds) || 0;
}

const { rotation, flipHorizontal, displayArea } = viewportInfo.getViewportOptions();

const properties = { ...presentations.lutPresentation?.properties };
Expand Down Expand Up @@ -637,12 +633,26 @@ class CornerstoneViewportService extends PubSubService implements IViewportServi
});

let imageIdsToSet = imageIds;
const res = this._processExtraDisplaySetsForViewport(viewport);
imageIdsToSet = res?.imageIds ?? imageIdsToSet;
const overlayProcessingResult = this._processExtraDisplaySetsForViewport(viewport);
imageIdsToSet = overlayProcessingResult?.imageIds ?? imageIdsToSet;

const referencedImageId = presentations?.positionPresentation?.viewReference?.referencedImageId;
if (referencedImageId) {
initialImageIndexToUse = imageIdsToSet.indexOf(referencedImageId);
}

if (initialImageIndexToUse === undefined || initialImageIndexToUse === null) {
initialImageIndexToUse = this._getInitialImageIndexForViewport(viewportInfo, imageIds) || 0;
}

return viewport.setStack(imageIdsToSet, initialImageIndexToUse).then(() => {
viewport.setProperties({ ...properties });
this.setPresentations(viewport.id, presentations, viewportInfo);

if (overlayProcessingResult?.addOverlayFn) {
overlayProcessingResult.addOverlayFn();
}

if (displayArea) {
viewport.setDisplayArea(displayArea);
}
Expand Down Expand Up @@ -827,10 +837,14 @@ class CornerstoneViewportService extends PubSubService implements IViewportServi
});

// For SEG and RT viewports
this._processExtraDisplaySetsForViewport(viewport);
const { addOverlayFn } = this._processExtraDisplaySetsForViewport(viewport) || {};

await viewport.setVolumes(volumeInputArray);

if (addOverlayFn) {
addOverlayFn();
}

volumesProperties.forEach(({ properties, volumeId }) => {
viewport.setProperties(properties, volumeId);
});
Expand Down Expand Up @@ -880,8 +894,12 @@ class CornerstoneViewportService extends PubSubService implements IViewportServi
segOrRTSOverlayDisplaySet.referencedDisplaySetInstanceUID
);
const imageIds = referenceDisplaySet.images.map(image => image.imageId);
this.addOverlayRepresentationForDisplaySet(segOrRTSOverlayDisplaySet, viewport);
return { imageIds };

return {
imageIds,
addOverlayFn: () =>
this.addOverlayRepresentationForDisplaySet(segOrRTSOverlayDisplaySet, viewport),
};
}

private addOverlayRepresentationForDisplaySet(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { PositionPresentation } from '../types/Presentation';
import { addUniqueIndex, JOIN_STR } from './presentationUtils';

const PRESENTATION_TYPE_ID = 'positionPresentationId';
const DEBUG_STORE = true;
const DEBUG_STORE = false;

/**
* Represents the state and actions for managing position presentations.
Expand Down
Loading
Loading