4.3 KiB
Bug Fix: Duplicate Segmentation Entries When Switching Layouts
Issue Description
Linear Issue: OHI-2076
Title: [Bug] Duplicate entries for same segmentation when switching between Common and advanced layout
When switching from a Common layout to an advanced layout (e.g., 3D Four-Up) in the OHIF Viewer, duplicate entries for the same segmentation appear in the Segmentation Panel.
Root Cause
The issue was in the useViewportSegmentations hook located at:
extensions/cornerstone/src/hooks/useViewportSegmentations.ts
When a viewport contains multiple representations of the same segmentation (e.g., both a LABELMAP and SURFACE representation), the hook was creating separate entries for each representation, even though they belong to the same segmentation. This resulted in duplicate entries in the Segmentation Panel.
The problem occurred because:
- When switching layouts, new viewports are created
- The synchronizer may add the same segmentation with different representation types to these viewports
- The
getSegmentationRepresentations(viewportId)call returns ALL representations for that viewport - Each representation was mapped to a separate entry, creating duplicates
Solution
Added deduplication logic in the useViewportSegmentations hook to ensure only one entry per unique segmentationId is shown in the panel, regardless of how many representation types exist.
Code Changes
File: extensions/cornerstone/src/hooks/useViewportSegmentations.ts
Before:
const representations = segmentationService.getSegmentationRepresentations(viewportId);
const newSegmentationsWithRepresentations = representations.map(representation => {
const segmentation = segmentationService.getSegmentation(representation.segmentationId);
const mappedSegmentation = mapSegmentationToDisplay(segmentation, customizationService);
return {
representation,
segmentation: mappedSegmentation,
};
});
After:
const representations = segmentationService.getSegmentationRepresentations(viewportId);
// Deduplicate representations by segmentationId to prevent showing
// the same segmentation multiple times in the panel when it has
// multiple representation types (e.g., labelmap and surface)
const uniqueSegmentationMap = new Map();
representations.forEach(representation => {
if (!uniqueSegmentationMap.has(representation.segmentationId)) {
uniqueSegmentationMap.set(representation.segmentationId, representation);
}
});
const newSegmentationsWithRepresentations = Array.from(uniqueSegmentationMap.values()).map(
representation => {
const segmentation = segmentationService.getSegmentation(representation.segmentationId);
const mappedSegmentation = mapSegmentationToDisplay(segmentation, customizationService);
return {
representation,
segmentation: mappedSegmentation,
};
}
);
How It Works
- After retrieving all representations for a viewport, we create a
Mapkeyed bysegmentationId - We iterate through all representations and only add the first occurrence of each unique
segmentationId - This ensures that even if a segmentation has multiple representation types (labelmap, surface, etc.), only one entry appears in the panel
- The fix is applied at the data source level, ensuring consistency across all panel views
Testing
To verify the fix:
- Launch OHIF Viewer with segmentation data (e.g., https://viewer-dev.ohif.org/segmentation?StudyInstanceUIDs=1.3.6.1.4.1.14519.5.2.1.1706.8374.643249677828306008300337414785)
- Drag and drop a segmentation into the Common layout viewport
- Switch to an advanced layout (e.g., 3D Four-Up)
- Verify that only one entry per segmentation appears in the Segmentation Panel (no duplicates)
Impact
- Scope: Minimal - only affects the display logic in the Segmentation Panel
- Breaking Changes: None
- Performance: Negligible - adds a simple Map-based deduplication step
- User Experience: Significantly improved - eliminates confusion from duplicate entries
Related Files
/workspace/extensions/cornerstone/src/hooks/useViewportSegmentations.ts(modified)/workspace/extensions/cornerstone/src/hooks/useActiveViewportSegmentationRepresentations.ts(uses the fixed hook)/workspace/extensions/cornerstone/src/panels/PanelSegmentation.tsx(consumes the data)