fix(segmentation): Segmentation not displayed and unable to draw segments when switching back to volume/stack viewport from 3D viewport (#5430)

Co-authored-by: Vinicius Faria <viniciusfariaresende@gmail.com>
This commit is contained in:
Devu-trenser 2025-10-08 03:10:32 +05:30 committed by GitHub
parent c4902f2b9e
commit 78df8ff03a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 54 additions and 10 deletions

View File

@ -648,7 +648,6 @@ describe('SegmentationService', () => {
jest
.spyOn(cstSegmentation.state, 'updateLabelmapSegmentationImageReferences')
.mockReturnValue(undefined);
// @ts-expect-error - getLabelmapImageIds is wrongly typed at cornerstone3D
jest.spyOn(cstSegmentation, 'getLabelmapImageIds').mockReturnValue([imageId]);
jest
.spyOn(cstSegmentation, 'addSegmentationRepresentations')
@ -949,6 +948,37 @@ describe('SegmentationService', () => {
});
});
it('should add a surface segmentation representation to volume viewport without need for handling', async () => {
jest
.spyOn(cstSegmentation.state, 'getSegmentation')
.mockReturnValue(mockCornerstoneSegmentation as cstTypes.Segmentation);
jest
.spyOn(serviceManagerMock.services.cornerstoneViewportService, 'getCornerstoneViewport')
// only needed interfaces for the addSegmentationRepresentation call
.mockReturnValue({
...mockCornerstoneVolumeViewport,
type: ViewportType.VOLUME_3D,
} as unknown as csTypes.IVolumeViewport);
jest
.spyOn(cstSegmentation, 'addSegmentationRepresentations')
.mockReturnValueOnce(undefined);
await service.addSegmentationRepresentation(viewportId, {
segmentationId: mockCornerstoneSegmentation.segmentationId,
});
expect(serviceManagerMock.services.viewportGridService.getState).not.toHaveBeenCalled();
expect(cstSegmentation.addSegmentationRepresentations).toHaveBeenCalledTimes(1);
expect(cstSegmentation.addSegmentationRepresentations).toHaveBeenCalledWith(viewportId, [
{
type: csToolsEnums.SegmentationRepresentations.Surface,
segmentationId: mockCornerstoneSegmentation.segmentationId,
config: { colorLUTOrIndex: undefined },
},
]);
});
it('should add a volume segmentation representation to volume viewport through SegmentationService handling', async () => {
mockCornerstoneVolumeViewport.type = ViewportType.ORTHOGRAPHIC;
jest
@ -1007,7 +1037,6 @@ describe('SegmentationService', () => {
jest
.spyOn(cstSegmentation, 'addSegmentationRepresentations')
.mockReturnValueOnce(undefined);
// @ts-expect-error - getLabelmapImageIds is wrongly typed at cornerstone3D
jest.spyOn(cstSegmentation, 'getLabelmapImageIds').mockReturnValue([imageId]);
jest
.spyOn(cache, 'getImage')
@ -2033,7 +2062,7 @@ describe('SegmentationService', () => {
jest.spyOn(cstSegmentation.config.color, 'setSegmentIndexColor').mockReturnValue(undefined);
jest
.spyOn(cstSegmentation.state, 'getSegmentationRepresentations')
.mockReturnValue([{ colorLUTIndex: 1 }]);
.mockReturnValue([{ colorLUTIndex: 1 }] as cstTypes.SegmentationRepresentation[]);
service.addSegment(segmentationId, config);
@ -2203,7 +2232,7 @@ describe('SegmentationService', () => {
it('should set the color of the segment', () => {
jest
.spyOn(cstSegmentation.state, 'getSegmentationRepresentations')
.mockReturnValue([{ colorLUTIndex: 1 }]);
.mockReturnValue([{ colorLUTIndex: 1 }] as cstTypes.SegmentationRepresentation[]);
jest.spyOn(cstSegmentation.config.color, 'setSegmentIndexColor').mockReturnValue(undefined);
service.setSegmentColor(viewportId, segmentationId, segmentIndex, color);
@ -2226,7 +2255,7 @@ describe('SegmentationService', () => {
it('should set the color of the segment with the colorLUTIndex', async () => {
jest
.spyOn(cstSegmentation.state, 'getSegmentationRepresentations')
.mockReturnValue([{ colorLUTIndex: 1 }]);
.mockReturnValue([{ colorLUTIndex: 1 }] as cstTypes.SegmentationRepresentation[]);
jest.spyOn(cstSegmentation.config.color, 'setSegmentIndexColor').mockReturnValue(undefined);
service.setSegmentColor(viewportId, segmentationId, segmentIndex, color);
@ -2246,7 +2275,7 @@ describe('SegmentationService', () => {
await service.addSegmentationRepresentation(viewportId, {
segmentationId: segmentationId,
type: csToolsEnums.SegmentationRepresentations.Labelmap,
config: { active: true },
config: { blendMode: csEnums.BlendModes.COMPOSITE },
suppressEvents: true,
});
@ -2255,7 +2284,7 @@ describe('SegmentationService', () => {
{
type: csToolsEnums.SegmentationRepresentations.Labelmap,
segmentationId: segmentationId,
config: { colorLUTOrIndex: 1, active: true },
config: { colorLUTOrIndex: 1, blendMode: csEnums.BlendModes.COMPOSITE },
},
]);
});

View File

@ -295,10 +295,12 @@ class SegmentationService extends PubSubService {
const colorLUTIndex = this._segmentationIdToColorLUTIndexMap.get(segmentationId);
const defaultRepresentationType = LABELMAP;
let representationTypeToUse = type || defaultRepresentationType;
let isConverted = false;
const defaultRepresentationType: csToolsEnums.SegmentationRepresentations =
csViewport.type === ViewportType.VOLUME_3D ? SURFACE : LABELMAP;
let representationTypeToUse = type || defaultRepresentationType;
if (representationTypeToUse === LABELMAP) {
const { isVolumeViewport, isVolumeSegmentation } = this.determineViewportAndSegmentationType(
csViewport,

View File

@ -1335,10 +1335,23 @@ class CornerstoneViewportService extends PubSubService implements IViewportServi
segmentationPresentation.forEach((presentationItem: SegmentationPresentationItem) => {
const { segmentationId, type, hydrated } = presentationItem;
const { Labelmap, Surface } = csToolsEnums.SegmentationRepresentations;
const representationType = (() => {
if (type === Surface) {
if (viewport.type === csEnums.ViewportType.VOLUME_3D) {
return Surface;
} else {
return Labelmap;
}
}
return type;
})();
if (hydrated) {
segmentationService.addSegmentationRepresentation(viewport.id, {
segmentationId,
type,
type: representationType,
});
}
});