docs: update to next version [BUMP BETA] (#4493)
This commit is contained in:
1 parent
f4775eccae
commit
6d0fa11ff8
299 files changed
+5417
-1311
No files matched your search
+48
@@ -0,0 +1,48 @@
|
||||
---
|
||||
id: seg-new-arch
|
||||
title: New Architecture
|
||||
---
|
||||
|
||||
|
||||
## New Architecture
|
||||
|
||||
* **Viewport-Centric Architecture**
|
||||
* Previous: Segmentations were tied to toolGroups
|
||||
* Now: Segmentations are tied directly to viewports
|
||||
* Impact: More granular control but requires significant code changes
|
||||
|
||||
* **Representation Management**
|
||||
* Previous: Required managing segmentation representation UIDs
|
||||
* Now: Uses simpler segmentationId + type combination
|
||||
* Impact: Simplified but requires API updates
|
||||
|
||||
|
||||
|
||||
If you are not familiar with the difference between a segmentation and a segmentation representation, below
|
||||
|
||||
<details>
|
||||
<summary>Read More</summary>
|
||||
|
||||
In Cornerstone3DTools, we have decoupled the concept of a Segmentation from a Segmentation Representation. This means that from one Segmentation we can create multiple Segmentation Representations. For instance, a Segmentation Representation of a 3D Labelmap, can be created from a Segmentation data, and a Segmentation Representation of a Contour can be created from the same Segmentation data. This way we have decouple the presentational aspect of a Segmentation from the underlying data.
|
||||
|
||||
|
||||
Similar relationship structure has been adapted in popular medical imaging softwares such as 3D Slicer with the addition of polymorph segmentation.
|
||||
|
||||
- https://github.com/PerkLab/PolySeg
|
||||
- https://www.slicer.org/
|
||||
|
||||
|
||||
|
||||
</details>
|
||||
|
||||
|
||||
|
||||
|
||||
### Architecture Overview
|
||||
|
||||
The new architecture in Cornerstone3D 2.0 makes a clear distinction between:
|
||||
|
||||
* A segmentation (the data structure containing segments)
|
||||
* A segmentation representation (how that segmentation is visualized in a specific viewport)
|
||||
|
||||
Let's now review what has changed
|
||||
+433
@@ -0,0 +1,433 @@
|
||||
---
|
||||
id: seg-api
|
||||
title: SegmentationService API
|
||||
---
|
||||
|
||||
|
||||
|
||||
Below we will review the changes to the API of the `SegmentationService`
|
||||
|
||||
# SegmentationService API
|
||||
|
||||
## Events
|
||||
|
||||
SEGMENTATION_UPDATED -> SEGMENTATION_MODIFIED
|
||||
|
||||
|
||||
Just a rename to match the cornerstone terminology
|
||||
|
||||
## VolumeId vs SegmentationId
|
||||
|
||||
Previously, we used the SegmentationId as the VolumeId for volume-based segmentations, which led to confusion and issues.
|
||||
|
||||
Now, we have two separate IDs: one for the segmentation and one for the volume.
|
||||
|
||||
`segmentationService.getLabelmapVolume(segmentationId)` will return the volume associated with the segmentation.
|
||||
|
||||
If your code uses `cache.getVolume(segmentationId)`, update it to use the new `getLabelmapVolume` method.
|
||||
|
||||
|
||||
## getSegmentation(segmentationId)
|
||||
|
||||
remains the same it will return the segmentation object = cornerstone segmentation object with the following properties:
|
||||
|
||||
```js
|
||||
/**
|
||||
* Global Segmentation Data which is used for the segmentation
|
||||
*/
|
||||
type Segmentation = {
|
||||
/** segmentation id */
|
||||
segmentationId: string;
|
||||
/** segmentation label */
|
||||
label: string;
|
||||
segments: {
|
||||
[segmentIndex: number]: Segment;
|
||||
};
|
||||
/**
|
||||
* Representations of the segmentation. Each segmentation "can" be viewed
|
||||
* in various representations. For instance, if a DICOM SEG is loaded, the main
|
||||
* representation is the labelmap. However, for DICOM RT the main representation
|
||||
* is contours, and other representations can be derived from the contour (currently
|
||||
* only labelmap representation is supported)
|
||||
*/
|
||||
representationData: RepresentationsData;
|
||||
/**
|
||||
* Segmentation level stats, Note each segment can have its own stats
|
||||
* This is used for caching stats for the segmentation level
|
||||
*/
|
||||
cachedStats: { [key: string]: unknown };
|
||||
};
|
||||
|
||||
export type Segment = {
|
||||
/** segment index */
|
||||
segmentIndex: number;
|
||||
/** segment label */
|
||||
label: string;
|
||||
/** is segment locked for editing */
|
||||
locked: boolean;
|
||||
/** cached stats for the segment, e.g., pt suv mean, max etc. */
|
||||
cachedStats: { [key: string]: unknown };
|
||||
/** is segment active for editing, at the same time only one segment can be active for editing */
|
||||
active: boolean;
|
||||
};
|
||||
```
|
||||
|
||||
|
||||
<details>
|
||||
<summary>Compared to Cornerstone3D 1.x</summary>
|
||||
|
||||
Previously this function was returning this
|
||||
|
||||
```js
|
||||
export type Segmentation = {
|
||||
segmentationId: string;
|
||||
type: Enums.SegmentationRepresentations;
|
||||
label: string;
|
||||
activeSegmentIndex: number;
|
||||
segmentsLocked: Set<number>;
|
||||
cachedStats: { [key: string]: number };
|
||||
segmentLabels: { [key: string]: string };
|
||||
representationData: SegmentationRepresentationData;
|
||||
};
|
||||
|
||||
```
|
||||
|
||||
As you can see `segmentLabels`, `segmentsLocked`, `activeSegmentIndex`, are all gathered under the new `segments` object. We now have support for per segment cachedStats as well.
|
||||
|
||||
</details>
|
||||
|
||||
---
|
||||
|
||||
## getSegmentations
|
||||
|
||||
It provides all segmentations in the state. Previously, it accepted a `filterNonhydrated` flag, but since we've moved away from hydration and every loaded segmentation is now hydrated by default, it returns all segmentations.
|
||||
|
||||
|
||||
|
||||
|
||||
---
|
||||
|
||||
## getActiveSegmentation
|
||||
|
||||
|
||||
After migrating to viewport-specific segmentations, different viewports can have distinct active segmentations for editing. The panel will always display the active segmentation when the active viewport changes.
|
||||
|
||||
Before (3.8)
|
||||
|
||||
```js
|
||||
// Returns full segmentation object
|
||||
public getActiveSegmentation(): Segmentation {
|
||||
const segmentations = this.getSegmentations();
|
||||
return segmentations.find(segmentation => segmentation.isActive);
|
||||
}
|
||||
```
|
||||
|
||||
After (3.9)
|
||||
|
||||
```js
|
||||
public getActiveSegmentation(viewportId: string): Segmentation | null {
|
||||
return cstSegmentation.activeSegmentation.getActiveSegmentation(viewportId);
|
||||
}
|
||||
```
|
||||
|
||||
<details>
|
||||
<summary>Key Changes</summary>
|
||||
|
||||
1. **Viewport Specificity**
|
||||
- Before: Global active segmentation across all tool groups
|
||||
- After: Active segmentation per viewport
|
||||
2. **Required Parameters**
|
||||
- Before: No parameters needed
|
||||
- After: Requires viewportId parameter
|
||||
</details>
|
||||
|
||||
|
||||
<details>
|
||||
<summary>Migration Examples</summary>
|
||||
|
||||
**Before:**
|
||||
|
||||
```js
|
||||
// Get active segmentation
|
||||
const activeSegmentation = segmentationService.getActiveSegmentation();
|
||||
if (activeSegmentation) {
|
||||
console.log('Active segmentation:', activeSegmentation.segmentationId);
|
||||
console.log('Active segment:', activeSegmentation.activeSegmentIndex);
|
||||
}
|
||||
```
|
||||
|
||||
**After:**
|
||||
|
||||
```js
|
||||
// Get active segmentation for specific viewport
|
||||
const activeSegmentation = segmentationService.getActiveSegmentation('viewport1');
|
||||
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
---
|
||||
|
||||
## getToolGroupIdsWithSegmentation
|
||||
|
||||
is now -> `getViewportIdsWithSegmentation` as you guessed
|
||||
|
||||
|
||||
|
||||
## setActiveSegmentationForToolGroup
|
||||
|
||||
-> setActiveSegmentation
|
||||
|
||||
|
||||
|
||||
**Before (OHIF 3.8)**
|
||||
|
||||
```js
|
||||
setActiveSegmentationForToolGroup(
|
||||
segmentationId: string,
|
||||
toolGroupId?: string,
|
||||
suppressEvents?: boolean
|
||||
): void
|
||||
```
|
||||
|
||||
**After (OHIF 3.9)**
|
||||
|
||||
```js
|
||||
setActiveSegmentation(
|
||||
viewportId: string,
|
||||
segmentationId: string
|
||||
): void
|
||||
```
|
||||
|
||||
<details>
|
||||
<summary>Migration Examples</summary>
|
||||
|
||||
1. **Basic Usage Update**
|
||||
|
||||
```js
|
||||
// Before - OHIF 3.8
|
||||
segmentationService.setActiveSegmentationForToolGroup(
|
||||
segmentationId,
|
||||
toolGroupId
|
||||
);
|
||||
// After - OHIF 3.9
|
||||
segmentationService.setActiveSegmentation(
|
||||
viewportId,
|
||||
segmentationId
|
||||
);
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
|
||||
|
||||
---
|
||||
|
||||
|
||||
## addSegment
|
||||
|
||||
The `addSegment` method in OHIF 3.9 has been updated to handle segmentation properties in a viewport-centric way, removing tool group dependencies and simplifying the configuration structure.
|
||||
|
||||
|
||||
**Before (OHIF 3.8)**
|
||||
|
||||
```js
|
||||
addSegment(
|
||||
segmentationId: string,
|
||||
config: {
|
||||
segmentIndex?: number;
|
||||
toolGroupId?: string;
|
||||
properties?: {
|
||||
label?: string;
|
||||
color?: ohifTypes.RGB;
|
||||
opacity?: number;
|
||||
visibility?: boolean;
|
||||
isLocked?: boolean;
|
||||
active?: boolean;
|
||||
};
|
||||
}
|
||||
): void
|
||||
```
|
||||
|
||||
**After (OHIF 3.9)**
|
||||
|
||||
```js
|
||||
addSegment(
|
||||
segmentationId: string,
|
||||
config: {
|
||||
segmentIndex?: number;
|
||||
label?: string;
|
||||
isLocked?: boolean;
|
||||
active?: boolean;
|
||||
color?: csTypes.Color;
|
||||
visibility?: boolean;
|
||||
}
|
||||
): void
|
||||
```
|
||||
|
||||
<details>
|
||||
<summary>Key Changes</summary>
|
||||
|
||||
1. **Configuration Structure**
|
||||
- Removed double nested `properties` object
|
||||
- Configuration options now at top level
|
||||
- Removed `toolGroupId` parameter
|
||||
- Removed `opacity` parameter (now part of color)
|
||||
2. **Segment Index Generation**
|
||||
- Changed from length-based to max-value-based indexing
|
||||
- More reliable for non-sequential segment indices
|
||||
3. **Color Handling**
|
||||
- Color now includes alpha channel (opacity)
|
||||
- Applied to all relevant viewports automatically
|
||||
</details>
|
||||
|
||||
|
||||
|
||||
|
||||
<details>
|
||||
<summary>Migration Examples</summary>
|
||||
|
||||
1. **Basic Segment Creation**
|
||||
|
||||
```js
|
||||
// Before - OHIF 3.8
|
||||
segmentationService.addSegment(segmentationId, {
|
||||
properties: {
|
||||
label: 'Segment 1'
|
||||
}
|
||||
});
|
||||
// After - OHIF 3.9
|
||||
segmentationService.addSegment(segmentationId, {
|
||||
label: 'Segment 1'
|
||||
});
|
||||
```
|
||||
|
||||
2. **Creating Segment with Color**
|
||||
|
||||
```js
|
||||
// Before - OHIF 3.8
|
||||
segmentationService.addSegment(segmentationId, {
|
||||
properties: {
|
||||
color: [255, 0, 0],
|
||||
opacity: 255
|
||||
}
|
||||
});
|
||||
// After - OHIF 3.9
|
||||
segmentationService.addSegment(segmentationId, {
|
||||
color: [255, 0, 0, 255] // RGB + Alpha
|
||||
});
|
||||
```
|
||||
|
||||
3. **Setting Visibility and Lock Status**
|
||||
|
||||
```js
|
||||
// Before - OHIF 3.8
|
||||
segmentationService.addSegment(segmentationId, {
|
||||
toolGroupId: 'myToolGroup',
|
||||
properties: {
|
||||
visibility: true,
|
||||
isLocked: true
|
||||
}
|
||||
});
|
||||
// After - OHIF 3.9
|
||||
segmentationService.addSegment(segmentationId, {
|
||||
visibility: true,
|
||||
isLocked: true
|
||||
});
|
||||
```
|
||||
|
||||
4. **Complete Configuration Example**
|
||||
|
||||
```js
|
||||
// Before - OHIF 3.8
|
||||
segmentationService.addSegment(segmentationId, {
|
||||
segmentIndex: 1,
|
||||
toolGroupId: 'myToolGroup',
|
||||
properties: {
|
||||
label: 'Tumor',
|
||||
color: [255, 0, 0],
|
||||
opacity: 200,
|
||||
visibility: true,
|
||||
isLocked: false,
|
||||
active: true
|
||||
}
|
||||
});
|
||||
// After - OHIF 3.9
|
||||
segmentationService.addSegment(segmentationId, {
|
||||
segmentIndex: 1,
|
||||
label: 'Tumor',
|
||||
color: [255, 0, 0, 200], // RGB + Alpha
|
||||
visibility: true,
|
||||
isLocked: false,
|
||||
active: true
|
||||
});
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
|
||||
|
||||
|
||||
<details>
|
||||
<summary>Important Changes</summary>
|
||||
|
||||
1. **Tool Group Removal**
|
||||
```js
|
||||
// Before - OHIF 3.8
|
||||
segmentationService.addSegment(segmentationId, {
|
||||
toolGroupId: 'myToolGroup'
|
||||
// ... other properties
|
||||
});
|
||||
// After - OHIF 3.9
|
||||
// No tool group needed - automatically applies to all relevant viewports
|
||||
segmentationService.addSegment(segmentationId, {
|
||||
// ... properties
|
||||
});
|
||||
```
|
||||
|
||||
2. **Segment Index Generation**
|
||||
```js
|
||||
// Before - OHIF 3.8
|
||||
// Used array length
|
||||
segmentIndex = segmentation.segments.length === 0 ? 1 : segmentation.segments.length;
|
||||
// After - OHIF 3.9
|
||||
// Uses highest existing index + 1
|
||||
segmentIndex = Math.max(...Object.keys(csSegmentation.segments).map(Number)) + 1;
|
||||
```
|
||||
|
||||
3. **Color and Opacity**
|
||||
```js
|
||||
// Before - OHIF 3.8
|
||||
segmentationService.addSegment(segmentationId, {
|
||||
properties: {
|
||||
color: [255, 0, 0],
|
||||
opacity: 200
|
||||
}
|
||||
});
|
||||
|
||||
// After - OHIF 3.9
|
||||
segmentationService.addSegment(segmentationId, {
|
||||
color: [255, 0, 0, 200] // Combined color and opacity
|
||||
});
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
|
||||
---
|
||||
|
||||
---
|
||||
|
||||
## getActiveSegment
|
||||
|
||||
now requires viewportId, since we have moved away from global active segmentation to viewport specific one
|
||||
|
||||
**API Changes**
|
||||
|
||||
```js
|
||||
// Before
|
||||
getActiveSegment(): Segment
|
||||
|
||||
// After
|
||||
getActiveSegment(viewportId: string): Segment | null
|
||||
```
|
||||
+189
@@ -0,0 +1,189 @@
|
||||
---
|
||||
id: seg-representation
|
||||
title: Segmentation Representations
|
||||
---
|
||||
|
||||
|
||||
|
||||
|
||||
## Segmentation Representation Management API
|
||||
|
||||
```js
|
||||
addSegmentationRepresentationToToolGroup
|
||||
removeSegmentationRepresentationFromToolGroup
|
||||
getSegmentationRepresentationsForToolGroup
|
||||
```
|
||||
|
||||
In Cornerstone3D 2.0, segmentation representation management has shifted from a tool group-centric approach to a viewport-centric approach. This architectural change provides better control over segmentation rendering and simplifies the mental model for managing segmentations.
|
||||
|
||||
|
||||
### Adding Segmentation Representations
|
||||
|
||||
**Before (3.8)**:
|
||||
|
||||
```js
|
||||
// Tool group-based approach
|
||||
await segmentation.addSegmentationRepresentationToToolGroup(
|
||||
toolGroupId,
|
||||
segmentationId,
|
||||
hydrateSegmentation,
|
||||
csToolsEnums.SegmentationRepresentations.Labelmap
|
||||
);
|
||||
```
|
||||
|
||||
**After (3.9)**:
|
||||
|
||||
```js
|
||||
// Viewport-centric approach
|
||||
await segmentation.addSegmentationRepresentation(
|
||||
viewportId,
|
||||
{
|
||||
segmentationId: segmentationId,
|
||||
type: csToolsEnums.SegmentationRepresentations.Labelmap,
|
||||
}
|
||||
);
|
||||
```
|
||||
|
||||
### Removing Segmentation Representations
|
||||
|
||||
**Before** :
|
||||
|
||||
```js
|
||||
// Remove specific representations from a tool group
|
||||
segmentation.removeSegmentationRepresentationFromToolGroup(
|
||||
toolGroupId,
|
||||
[segmentationRepresentationUID]
|
||||
);
|
||||
// Remove all representations from a tool group
|
||||
segmentation.removeSegmentationRepresentationFromToolGroup(toolGroupId);
|
||||
```
|
||||
|
||||
**After**
|
||||
|
||||
```js
|
||||
// Remove specific representation from a viewport
|
||||
segmentation.removeSegmentationRepresentation(
|
||||
viewportId,
|
||||
{
|
||||
segmentationId: segmentationId,
|
||||
type: csToolsEnums.SegmentationRepresentations.Labelmap
|
||||
}
|
||||
);
|
||||
// Remove all representations from a viewport
|
||||
segmentation.removeSegmentationRepresentations(viewportId);
|
||||
```
|
||||
|
||||
### Getting Segmentation Representations
|
||||
|
||||
**Before**:
|
||||
|
||||
```js
|
||||
// Get representations for a tool group
|
||||
const representations = segmentation.getSegmentationRepresentationsForToolGroup(toolGroupId);
|
||||
```
|
||||
|
||||
**After** :
|
||||
|
||||
```js
|
||||
// Get all representations for a viewport
|
||||
const representations = segmentation.getSegmentationRepresentations(viewportId);
|
||||
|
||||
// Get specific type of representations
|
||||
const labelmapReps = segmentation.getSegmentationRepresentations(viewportId, {
|
||||
type: csToolsEnums.SegmentationRepresentations.Labelmap
|
||||
});
|
||||
|
||||
// Get representations for specific segmentation
|
||||
const segmentationReps = segmentation.getSegmentationRepresentations(viewportId, {
|
||||
segmentationId: segmentationId
|
||||
});
|
||||
|
||||
// Get specific representation
|
||||
const representation = segmentation.getSegmentationRepresentation(viewportId, {
|
||||
segmentationId: segmentationId,
|
||||
type: csToolsEnums.SegmentationRepresentations.Labelmap
|
||||
});
|
||||
```
|
||||
|
||||
### Understanding the Specifier Pattern
|
||||
|
||||
The Cornerstone3D 2.0 (OHIF 3.9) API introduces a "specifier" pattern that provides more flexible and precise control over segmentation representations. A specifier is an object that can include:
|
||||
|
||||
```js
|
||||
type Specifier = {
|
||||
segmentationId?: string; // The ID of the segmentation
|
||||
type?: SegmentationRepresentations; // The type of representation (Labelmap, Contour, etc.)
|
||||
}
|
||||
```
|
||||
|
||||
The specifier pattern allows for:
|
||||
|
||||
1. **Precise Targeting**: You can target specific segmentations and representation types
|
||||
- Allows direct access to individual segmentations
|
||||
- Enables filtering by representation type
|
||||
|
||||
2. **Flexible Querying**: You can get all representations of a certain type or for a specific segmentation
|
||||
- Query by segmentation ID
|
||||
- Query by representation type
|
||||
- Combine queries for specific needs
|
||||
|
||||
3. **Granular Control**: You can manage representations at different levels of specificity
|
||||
- Viewport level control
|
||||
- Segmentation level control
|
||||
- Individual representation type control
|
||||
|
||||
### Examples of Specifier Usage
|
||||
|
||||
```js
|
||||
// Get all labelmap representations in a viewport
|
||||
const labelmaps = segmentation.getSegmentationRepresentations(viewportId, {
|
||||
type: csToolsEnums.SegmentationRepresentations.Labelmap
|
||||
});
|
||||
|
||||
// Get all representations of a specific segmentation (including contour, labelmap, surface)
|
||||
const segReps = segmentation.getSegmentationRepresentations(viewportId, {
|
||||
segmentationId: 'seg123'
|
||||
});
|
||||
|
||||
// Get a specific representation
|
||||
const specificRep = segmentation.getSegmentationRepresentation(viewportId, {
|
||||
segmentationId: 'seg123',
|
||||
type: csToolsEnums.SegmentationRepresentations.Labelmap
|
||||
});
|
||||
```
|
||||
|
||||
<details>
|
||||
<summary>Benefits of the New Approach</summary>
|
||||
|
||||
1. **Direct Viewport Control**:
|
||||
- Each viewport can have its own unique representation configuration
|
||||
- No need to create separate tool groups for different viewport representations
|
||||
2. **Simpler Mental Model**:
|
||||
- Representations are directly tied to where they're displayed
|
||||
- No intermediate tool group layer to manage
|
||||
3. **More Flexible Rendering**:
|
||||
- Each viewport can render the same segmentation differently
|
||||
- Better support for multiple views of the same data
|
||||
4. **Improved Type Safety**:
|
||||
- Specifier pattern provides better TypeScript support
|
||||
- More explicit API with clearer intentions
|
||||
</details>
|
||||
|
||||
|
||||
<details>
|
||||
<summary>Migration Tips</summary>
|
||||
|
||||
1. **Replace Tool Group References**:
|
||||
- Search your codebase for `toolGroupId` references in segmentation code
|
||||
- Replace with appropriate `viewportId` references
|
||||
2. **Update Event Handlers**:
|
||||
- Update any code listening for segmentation events
|
||||
- Events now include viewportId instead of toolGroupId
|
||||
3. **Review Representation Management**:
|
||||
- Identify where you manage segmentation representations
|
||||
- Convert to using the new viewport-centric methods
|
||||
4. **Consider Viewport Context**:
|
||||
- Think about segmentation representation in terms of viewport display
|
||||
- Use specifiers to target specific representations when needed
|
||||
|
||||
</details>
|
||||
+215
@@ -0,0 +1,215 @@
|
||||
---
|
||||
id: seg-creation
|
||||
title: Segmentation Creation
|
||||
---
|
||||
|
||||
## createEmptySegmentationForViewport
|
||||
|
||||
is now `createLabelmapForViewport` to align with other segmentation creation methods.
|
||||
|
||||
Run it using `commandsManager.runCommand('createLabelmapForViewport', {viewportId})`.
|
||||
|
||||
## createSegmentationForDisplaySet
|
||||
|
||||
is now -> `createLabelmapForDisplaySet`
|
||||
|
||||
Since we are moving towards segmentations be contours as well, this is renamed to clearly state the purpose.
|
||||
Since OHIF 3.9 introduced Stack Segmentation support, we no longer generate a volume-based labelmap or convert the viewport to a volume viewport by default. Our default creation is now stack-based.
|
||||
|
||||
API Changes
|
||||
- `createSegmentationForDisplaySet` has been renamed to `createLabelmapForDisplaySet`.
|
||||
- Pass a `displaySet` object instead of a `displaySetInstanceUID`. This change enhances type safety and flexibility, accommodating future updates to the `displaySetService`.
|
||||
|
||||
**Before (OHIF 3.8)**
|
||||
|
||||
```js
|
||||
async createSegmentationForDisplaySet(
|
||||
displaySetInstanceUID: string,
|
||||
options?: {
|
||||
segmentationId: string;
|
||||
FrameOfReferenceUID: string;
|
||||
label: string;
|
||||
}
|
||||
): Promise<string>
|
||||
```
|
||||
|
||||
**After (OHIF 3.9)**
|
||||
|
||||
```js
|
||||
// Method 1: Display Set Based
|
||||
async createLabelmapForDisplaySet(
|
||||
displaySet: DisplaySet,
|
||||
options?: {
|
||||
segmentationId?: string;
|
||||
label: string;
|
||||
segments?: {
|
||||
[segmentIndex: number]: Partial<Segment>
|
||||
};
|
||||
}
|
||||
): Promise<string>
|
||||
```
|
||||
|
||||
|
||||
<details>
|
||||
<summary>Migration Examples</summary>
|
||||
|
||||
|
||||
```js
|
||||
// Before - OHIF 3.8
|
||||
const segmentationId = await segmentationService.createSegmentationForDisplaySet(
|
||||
displaySetInstanceUID,
|
||||
{
|
||||
label: 'My Segmentation'
|
||||
}
|
||||
);
|
||||
```
|
||||
|
||||
```js
|
||||
// After - OHIF 3.9
|
||||
// Option 1: If you have a display set UID
|
||||
const displaySet = displaySetService.getDisplaySetByUID(displaySetInstanceUID);
|
||||
|
||||
const segmentationId = await segmentationService.createLabelmapForDisplaySet(
|
||||
displaySet,
|
||||
{
|
||||
label: 'My Segmentation'
|
||||
}
|
||||
);
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
---
|
||||
|
||||
## createSegmentationForRTDisplaySet
|
||||
|
||||
|
||||
**Before (OHIF 3.8)**
|
||||
|
||||
```js
|
||||
async createSegmentationForRTDisplaySet(
|
||||
rtDisplaySet,
|
||||
segmentationId?: string,
|
||||
suppressEvents = false
|
||||
): Promise<string>
|
||||
```
|
||||
|
||||
**After (OHIF 3.9)**
|
||||
|
||||
```js
|
||||
async createSegmentationForRTDisplaySet(
|
||||
rtDisplaySet,
|
||||
options: {
|
||||
segmentationId?: string;
|
||||
type: SegmentationRepresentations; // not required, defaults to Contour
|
||||
}
|
||||
): Promise<string>
|
||||
```
|
||||
|
||||
|
||||
<details>
|
||||
<summary>Migration Examples</summary>
|
||||
|
||||
if you were not passing segmentationId, you don't need to change anything
|
||||
|
||||
|
||||
```js
|
||||
// Before - OHIF 3.8
|
||||
const segmentationId = await segmentationService.createSegmentationForRTDisplaySet(
|
||||
rtDisplaySet
|
||||
);
|
||||
|
||||
// After - OHIF 3.9
|
||||
const segmentationId = await segmentationService.createSegmentationForRTDisplaySet(
|
||||
rtDisplaySet,
|
||||
);
|
||||
```
|
||||
|
||||
if you were passing segmentationId, you need to update the API to pass an options object and set the segmentationId in there.
|
||||
|
||||
```js
|
||||
// Before - OHIF 3.8
|
||||
const segmentationId = await segmentationService.createSegmentationForRTDisplaySet(
|
||||
rtDisplaySet,
|
||||
'custom-id',
|
||||
);
|
||||
// After - OHIF 3.9
|
||||
const segmentationId = await segmentationService.createSegmentationForRTDisplaySet(
|
||||
rtDisplaySet,
|
||||
{
|
||||
segmentationId: 'custom-id',
|
||||
type: csToolsEnums.SegmentationRepresentations.Contour
|
||||
}
|
||||
);
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
---
|
||||
|
||||
|
||||
## createSegmentationForSEGDisplaySet Changes
|
||||
|
||||
**Before (OHIF 3.8)**
|
||||
|
||||
```js
|
||||
async createSegmentationForSEGDisplaySet(
|
||||
segDisplaySet,
|
||||
segmentationId?: string,
|
||||
suppressEvents = false
|
||||
): Promise<string>
|
||||
```
|
||||
|
||||
**After (OHIF 3.9)**
|
||||
|
||||
```js
|
||||
async createSegmentationForSEGDisplaySet(
|
||||
segDisplaySet,
|
||||
options: {
|
||||
segmentationId?: string;
|
||||
type: SegmentationRepresentations; // not required, defaults to Labelmap
|
||||
}
|
||||
): Promise<string>
|
||||
```
|
||||
|
||||
<details>
|
||||
<summary>Migration Examples</summary>
|
||||
|
||||
1. **Basic Usage Update**
|
||||
|
||||
```
|
||||
// Before - OHIF 3.8
|
||||
const segmentationId = await segmentationService.createSegmentationForSEGDisplaySet(
|
||||
segDisplaySet
|
||||
);
|
||||
// After - OHIF 3.9
|
||||
const segmentationId = await segmentationService.createSegmentationForSEGDisplaySet(
|
||||
segDisplaySet,
|
||||
{
|
||||
type: csToolsEnums.SegmentationRepresentations.Labelmap
|
||||
}
|
||||
);
|
||||
```
|
||||
|
||||
2. **Custom Configuration**
|
||||
|
||||
```
|
||||
// Before - OHIF 3.8
|
||||
const segmentationId = await segmentationService.createSegmentationForSEGDisplaySet(
|
||||
segDisplaySet,
|
||||
'custom-id',
|
||||
false
|
||||
);
|
||||
// After - OHIF 3.9
|
||||
const segmentationId = await segmentationService.createSegmentationForSEGDisplaySet(
|
||||
segDisplaySet,
|
||||
{
|
||||
segmentationId: 'custom-id',
|
||||
type: csToolsEnums.SegmentationRepresentations.Labelmap
|
||||
}
|
||||
);
|
||||
```
|
||||
</details>
|
||||
|
||||
|
||||
---
|
||||
+193
@@ -0,0 +1,193 @@
|
||||
---
|
||||
id: seg-service-mod
|
||||
title: SegmentationService Modifications
|
||||
---
|
||||
|
||||
|
||||
---
|
||||
|
||||
|
||||
## Segmentation Representation Management API
|
||||
|
||||
```js
|
||||
addSegmentationRepresentationToToolGroup
|
||||
removeSegmentationRepresentationFromToolGroup
|
||||
getSegmentationRepresentationsForToolGroup
|
||||
```
|
||||
|
||||
In Cornerstone3D 2.0, segmentation representation management has shifted from a tool group-centric approach to a viewport-centric approach. This architectural change provides better control over segmentation rendering and simplifies the mental model for managing segmentations.
|
||||
|
||||
|
||||
### Adding Segmentation Representations
|
||||
|
||||
**Before (3.8)**:
|
||||
|
||||
```js
|
||||
// Tool group-based approach
|
||||
await segmentation.addSegmentationRepresentationToToolGroup(
|
||||
toolGroupId,
|
||||
segmentationId,
|
||||
hydrateSegmentation,
|
||||
csToolsEnums.SegmentationRepresentations.Labelmap
|
||||
);
|
||||
```
|
||||
|
||||
**After (3.9)**:
|
||||
|
||||
```js
|
||||
// Viewport-centric approach
|
||||
await segmentation.addSegmentationRepresentation(
|
||||
viewportId,
|
||||
{
|
||||
segmentationId: segmentationId,
|
||||
type: csToolsEnums.SegmentationRepresentations.Labelmap,
|
||||
}
|
||||
);
|
||||
```
|
||||
|
||||
### Removing Segmentation Representations
|
||||
|
||||
**Before** :
|
||||
|
||||
```js
|
||||
// Remove specific representations from a tool group
|
||||
segmentation.removeSegmentationRepresentationFromToolGroup(
|
||||
toolGroupId,
|
||||
[segmentationRepresentationUID]
|
||||
);
|
||||
// Remove all representations from a tool group
|
||||
segmentation.removeSegmentationRepresentationFromToolGroup(toolGroupId);
|
||||
```
|
||||
|
||||
**After**
|
||||
|
||||
```js
|
||||
// Remove specific representation from a viewport
|
||||
segmentation.removeSegmentationRepresentation(
|
||||
viewportId,
|
||||
{
|
||||
segmentationId: segmentationId,
|
||||
type: csToolsEnums.SegmentationRepresentations.Labelmap
|
||||
}
|
||||
);
|
||||
// Remove all representations from a viewport
|
||||
segmentation.removeSegmentationRepresentations(viewportId);
|
||||
```
|
||||
|
||||
### Getting Segmentation Representations
|
||||
|
||||
**Before**:
|
||||
|
||||
```js
|
||||
// Get representations for a tool group
|
||||
const representations = segmentation.getSegmentationRepresentationsForToolGroup(toolGroupId);
|
||||
```
|
||||
|
||||
**After** :
|
||||
|
||||
```js
|
||||
// Get all representations for a viewport
|
||||
const representations = segmentation.getSegmentationRepresentations(viewportId);
|
||||
|
||||
// Get specific type of representations
|
||||
const labelmapReps = segmentation.getSegmentationRepresentations(viewportId, {
|
||||
type: csToolsEnums.SegmentationRepresentations.Labelmap
|
||||
});
|
||||
|
||||
// Get representations for specific segmentation
|
||||
const segmentationReps = segmentation.getSegmentationRepresentations(viewportId, {
|
||||
segmentationId: segmentationId
|
||||
});
|
||||
|
||||
// Get specific representation
|
||||
const representation = segmentation.getSegmentationRepresentation(viewportId, {
|
||||
segmentationId: segmentationId,
|
||||
type: csToolsEnums.SegmentationRepresentations.Labelmap
|
||||
});
|
||||
```
|
||||
|
||||
### Understanding the Specifier Pattern
|
||||
|
||||
The Cornerstone3D 2.0 (OHIF 3.9) API introduces a "specifier" pattern that provides more flexible and precise control over segmentation representations. A specifier is an object that can include:
|
||||
|
||||
```js
|
||||
type Specifier = {
|
||||
segmentationId?: string; // The ID of the segmentation
|
||||
type?: SegmentationRepresentations; // The type of representation (Labelmap, Contour, etc.)
|
||||
}
|
||||
```
|
||||
|
||||
The specifier pattern allows for:
|
||||
|
||||
1. **Precise Targeting**: You can target specific segmentations and representation types
|
||||
- Allows direct access to individual segmentations
|
||||
- Enables filtering by representation type
|
||||
|
||||
2. **Flexible Querying**: You can get all representations of a certain type or for a specific segmentation
|
||||
- Query by segmentation ID
|
||||
- Query by representation type
|
||||
- Combine queries for specific needs
|
||||
|
||||
3. **Granular Control**: You can manage representations at different levels of specificity
|
||||
- Viewport level control
|
||||
- Segmentation level control
|
||||
- Individual representation type control
|
||||
|
||||
### Examples of Specifier Usage
|
||||
|
||||
```js
|
||||
// Get all labelmap representations in a viewport
|
||||
const labelmaps = segmentation.getSegmentationRepresentations(viewportId, {
|
||||
type: csToolsEnums.SegmentationRepresentations.Labelmap
|
||||
});
|
||||
|
||||
// Get all representations of a specific segmentation (including contour, labelmap, surface)
|
||||
const segReps = segmentation.getSegmentationRepresentations(viewportId, {
|
||||
segmentationId: 'seg123'
|
||||
});
|
||||
|
||||
// Get a specific representation
|
||||
const specificRep = segmentation.getSegmentationRepresentation(viewportId, {
|
||||
segmentationId: 'seg123',
|
||||
type: csToolsEnums.SegmentationRepresentations.Labelmap
|
||||
});
|
||||
```
|
||||
|
||||
<details>
|
||||
<summary>Benefits of the New Approach</summary>
|
||||
|
||||
1. **Direct Viewport Control**:
|
||||
- Each viewport can have its own unique representation configuration
|
||||
- No need to create separate tool groups for different viewport representations
|
||||
2. **Simpler Mental Model**:
|
||||
- Representations are directly tied to where they're displayed
|
||||
- No intermediate tool group layer to manage
|
||||
3. **More Flexible Rendering**:
|
||||
- Each viewport can render the same segmentation differently
|
||||
- Better support for multiple views of the same data
|
||||
4. **Improved Type Safety**:
|
||||
- Specifier pattern provides better TypeScript support
|
||||
- More explicit API with clearer intentions
|
||||
</details>
|
||||
|
||||
|
||||
<details>
|
||||
<summary>Migration Tips</summary>
|
||||
|
||||
1. **Replace Tool Group References**:
|
||||
- Search your codebase for `toolGroupId` references in segmentation code
|
||||
- Replace with appropriate `viewportId` references
|
||||
2. **Update Event Handlers**:
|
||||
- Update any code listening for segmentation events
|
||||
- Events now include viewportId instead of toolGroupId
|
||||
3. **Review Representation Management**:
|
||||
- Identify where you manage segmentation representations
|
||||
- Convert to using the new viewport-centric methods
|
||||
4. **Consider Viewport Context**:
|
||||
- Think about segmentation representation in terms of viewport display
|
||||
- Use specifiers to target specific representations when needed
|
||||
|
||||
</details>
|
||||
|
||||
|
||||
---
|
||||
+362
@@ -0,0 +1,362 @@
|
||||
---
|
||||
id: seg-style
|
||||
title: SegmentationService Style
|
||||
---
|
||||
|
||||
|
||||
## Style
|
||||
|
||||
|
||||
### setSegmentVisibility
|
||||
|
||||
since visibility is viewport concern and representation is what is being toggled ->
|
||||
|
||||
**Before (OHIF 3.8)**
|
||||
|
||||
```js
|
||||
setSegmentVisibility(
|
||||
segmentationId: string,
|
||||
segmentIndex: number,
|
||||
isVisible: boolean,
|
||||
toolGroupId?: string
|
||||
): void
|
||||
```
|
||||
|
||||
**After (OHIF 3.9)**
|
||||
|
||||
```js
|
||||
setSegmentVisibility(
|
||||
viewportId: string,
|
||||
segmentationId: string,
|
||||
segmentIndex: number,
|
||||
isVisible: boolean,
|
||||
type?: SegmentationRepresentations
|
||||
): void
|
||||
```
|
||||
|
||||
<details>
|
||||
<summary>Migration Example</summary>
|
||||
|
||||
```js
|
||||
// Before
|
||||
segmentationService.setSegmentVisibility(
|
||||
'segmentation1',
|
||||
1,
|
||||
true,
|
||||
'toolGroup1'
|
||||
);
|
||||
// After
|
||||
segmentationService.setSegmentVisibility(
|
||||
'viewport1',
|
||||
'segmentation1',
|
||||
1,
|
||||
true
|
||||
);
|
||||
```
|
||||
|
||||
**Getting Viewport IDs**
|
||||
|
||||
When you need to update visibility across multiple viewports:
|
||||
|
||||
```js
|
||||
// Before
|
||||
const toolGroupIds = ['toolGroup1', 'toolGroup2'];
|
||||
toolGroupIds.forEach(toolGroupId => {
|
||||
segmentationService.setSegmentVisibility(
|
||||
'segmentation1',
|
||||
1,
|
||||
true,
|
||||
toolGroupId
|
||||
);
|
||||
});
|
||||
// After
|
||||
const viewportIds = segmentationService.getViewportIdsWithSegmentation('segmentation1');
|
||||
viewportIds.forEach(viewportId => {
|
||||
segmentationService.setSegmentVisibility(
|
||||
viewportId,
|
||||
'segmentation1',
|
||||
1,
|
||||
true
|
||||
);
|
||||
});
|
||||
```
|
||||
|
||||
|
||||
</details>
|
||||
|
||||
|
||||
### get/set Configuration -> get/setStyle
|
||||
|
||||
The segmentation configuration system has been completely redesigned:
|
||||
|
||||
- Moved from global/toolGroup configuration to viewport-specific styles
|
||||
- Split rendering of inactive segmentations into separate API
|
||||
- More granular control over styles at different levels (global, segmentation, viewport, segment)
|
||||
|
||||
|
||||
**Before (OHIF 3.8)**
|
||||
|
||||
```js
|
||||
interface SegmentationConfig {
|
||||
brushSize: number;
|
||||
brushThresholdGate: number;
|
||||
fillAlpha: number;
|
||||
fillAlphaInactive: number;
|
||||
outlineWidthActive: number;
|
||||
renderFill: boolean;
|
||||
renderInactiveSegmentations: boolean;
|
||||
renderOutline: boolean;
|
||||
outlineOpacity: number;
|
||||
outlineOpacityInactive: number;
|
||||
}
|
||||
```
|
||||
|
||||
**After (OHIF 3.9)**
|
||||
|
||||
```js
|
||||
// Style Types
|
||||
interface StyleSpecifier {
|
||||
viewportId?: string;
|
||||
segmentationId?: string;
|
||||
type: SegmentationRepresentations;
|
||||
segmentIndex?: number;
|
||||
}
|
||||
interface LabelmapStyle {
|
||||
renderOutline: boolean;
|
||||
outlineWidth: number;
|
||||
renderFill: boolean;
|
||||
fillAlpha: number;
|
||||
outlineAlpha: number;
|
||||
// ....
|
||||
}
|
||||
// Functions
|
||||
getStyle(specifier: StyleSpecifier): LabelmapStyle | ContourStyle | SurfaceStyle;
|
||||
setStyle(specifier: StyleSpecifier, style: LabelmapStyle | ContourStyle | SurfaceStyle): void;
|
||||
setRenderInactiveSegmentations(viewportId: string, renderInactive: boolean): void;
|
||||
getRenderInactiveSegmentations(viewportId: string): boolean;
|
||||
```
|
||||
|
||||
|
||||
**Before:**
|
||||
|
||||
```js
|
||||
// Get global configuration
|
||||
const config = segmentationService.getConfiguration();
|
||||
console.log(config.fillAlpha, config.renderOutline);
|
||||
// Get tool group specific config
|
||||
const toolGroupConfig = segmentationService.getConfiguration('toolGroup1');
|
||||
```
|
||||
|
||||
**After:**
|
||||
|
||||
```js
|
||||
// Get global style for labelmap
|
||||
const labelmapStyle = segmentationService.getStyle({
|
||||
type: SegmentationRepresentations.Labelmap
|
||||
});
|
||||
// Get viewport-specific style
|
||||
const viewportStyle = segmentationService.getStyle({
|
||||
viewportId: 'viewport1',
|
||||
type: SegmentationRepresentations.Labelmap
|
||||
});
|
||||
// Get segmentation-specific style
|
||||
const segmentationStyle = segmentationService.getStyle({
|
||||
segmentationId: 'seg1',
|
||||
type: SegmentationRepresentations.Labelmap
|
||||
});
|
||||
// Get segment-specific style
|
||||
const segmentStyle = segmentationService.getStyle({
|
||||
segmentationId: 'seg1',
|
||||
type: SegmentationRepresentations.Labelmap,
|
||||
segmentIndex: 1
|
||||
});
|
||||
```
|
||||
|
||||
|
||||
|
||||
**Setting Configuration/Style**
|
||||
|
||||
**Before:**
|
||||
|
||||
```js
|
||||
segmentationService.setConfiguration({
|
||||
fillAlpha: 0.5,
|
||||
outlineWidthActive: 2,
|
||||
renderOutline: true,
|
||||
renderFill: true,
|
||||
renderInactiveSegmentations: true
|
||||
});
|
||||
```
|
||||
|
||||
**After:**
|
||||
|
||||
```js
|
||||
// Set global style
|
||||
segmentationService.setStyle(
|
||||
{ type: SegmentationRepresentations.Labelmap },
|
||||
{
|
||||
fillAlpha: 0.5,
|
||||
outlineWidth: 2,
|
||||
renderOutline: true,
|
||||
renderFill: true
|
||||
}
|
||||
);
|
||||
// Set viewport-specific style
|
||||
segmentationService.setStyle(
|
||||
{
|
||||
viewportId: 'viewport1',
|
||||
type: SegmentationRepresentations.Labelmap
|
||||
},
|
||||
{
|
||||
fillAlpha: 0.5,
|
||||
outlineWidth: 2
|
||||
}
|
||||
);
|
||||
// Handle inactive segmentations separately
|
||||
segmentationService.setRenderInactiveSegmentations('viewport1', true);
|
||||
```
|
||||
|
||||
|
||||
<details>
|
||||
<summary>Migration Examples</summary>
|
||||
|
||||
**Combining Multiple Style Settings**
|
||||
|
||||
**Before:**
|
||||
|
||||
```js
|
||||
segmentationService.setConfiguration({
|
||||
fillAlpha: 0.5,
|
||||
fillAlphaInactive: 0.2,
|
||||
outlineWidthActive: 2,
|
||||
outlineOpacity: 1,
|
||||
outlineOpacityInactive: 0.5,
|
||||
renderOutline: true,
|
||||
renderFill: true,
|
||||
renderInactiveSegmentations: true
|
||||
});
|
||||
```
|
||||
|
||||
**After:**
|
||||
|
||||
```js
|
||||
// Set base style
|
||||
segmentationService.setStyle(
|
||||
{ type: SegmentationRepresentations.Labelmap },
|
||||
{
|
||||
fillAlpha: 0.5,
|
||||
outlineWidth: 2,
|
||||
outlineAlpha: 1,
|
||||
renderOutline: true,
|
||||
renderFill: true
|
||||
}
|
||||
);
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
|
||||
|
||||
**Set inactive rendering per viewport**
|
||||
|
||||
```js
|
||||
segmentationService.setRenderInactiveSegmentations('viewport1', true);
|
||||
// Set style for inactive segments if needed
|
||||
segmentationService.setStyle(
|
||||
{
|
||||
viewportId: 'viewport1',
|
||||
type: SegmentationRepresentations.Labelmap,
|
||||
segmentationId: 'seg1'
|
||||
},
|
||||
{
|
||||
fillAlpha: 0.2,
|
||||
outlineAlpha: 0.5
|
||||
}
|
||||
);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
|
||||
|
||||
## setSegmentRGBAColor , setSegmentOpacity, setSegmentRGBA
|
||||
Previously, the SegmentationService had multiple redundant methods for setting colors and opacity (`setSegmentRGBA`, `setSegmentColor`, `setSegmentOpacity`). This led to confusion and potential state inconsistencies between the service and Cornerstone.js Tools.
|
||||
|
||||
The old methods (`setSegmentRGBA`, `setSegmentRGBA`, and `setSegmentOpacity`) are now removed.
|
||||
|
||||
|
||||
1. Replace `setSegmentRGBAColor`, `setSegmentRGBA`, and `setSegmentOpacity` calls: Replace all instances of the old methods with the new `setSegmentColor` method. Note that you now need to provide the `viewportId` as the first argument since segment color is managed per viewport and representation in cornerstone3D.
|
||||
|
||||
|
||||
**Before**
|
||||
|
||||
```js
|
||||
// Old API:
|
||||
segmentationService.setSegmentRGBAColor(segmentationId, segmentIndex, rgbaColor, toolGroupId);
|
||||
segmentationService.setSegmentRGBA(segmentationId, segmentIndex, rgbaColor, toolGroupId);
|
||||
segmentationService.setSegmentOpacity(segmentationId, segmentIndex, opacity, toolGroupId);
|
||||
```
|
||||
|
||||
**After**
|
||||
|
||||
```js
|
||||
// New API:
|
||||
segmentationService.setSegmentColor(viewportId, segmentationId, segmentIndex, color); // color is an array of [red, green, blue, alpha]
|
||||
```
|
||||
|
||||
The new `color` argument is an array representing the RGBA color, where the alpha component determines the opacity. Since the Cornerstone Tools library handles segment color per viewport and representation, we require the `viewportId` as an argument now.
|
||||
|
||||
|
||||
|
||||
2. **Retrieve Segment Color using** `getSegmentColor`: The new `getSegmentColor` provides a way to fetch the color of a segment within a specific viewport.
|
||||
|
||||
```js
|
||||
const color = segmentationService.getSegmentColor(viewportId, segmentationId, segmentIndex); //returns [r, g, b, a]
|
||||
```
|
||||
|
||||
|
||||
---
|
||||
|
||||
|
||||
|
||||
## ToggleSegmentationVisibility
|
||||
|
||||
In Cornerstone3D v2.x, `toggleSegmentationVisibility` has been replaced with `toggleSegmentationRepresentationVisibility`. This change reflects the fact that
|
||||
a representation is what is being toggled, not the segmentation.
|
||||
|
||||
|
||||
**Before (OHIF 3.8)**
|
||||
|
||||
```js
|
||||
// Toggle visibility for a segmentation globally
|
||||
segmentationService.toggleSegmentationVisibility(segmentationId);
|
||||
```
|
||||
|
||||
**After (OHIF 3.9)**
|
||||
|
||||
```js
|
||||
// Toggle visibility for a segmentation representation in a specific viewport
|
||||
segmentationService.toggleSegmentationRepresentationVisibility(viewportId, {
|
||||
segmentationId: segmentationId,
|
||||
type: csToolsEnums.SegmentationRepresentations.Labelmap
|
||||
});
|
||||
```
|
||||
|
||||
**Migration Steps**
|
||||
|
||||
1. Update all calls to `toggleSegmentationVisibility` to use `toggleSegmentationRepresentationVisibility`
|
||||
2. Add the required `viewportId` parameter
|
||||
3. Add a `type` parameter specifying the representation type (e.g., Labelmap, Contour)
|
||||
4. If you were toggling visibility across all viewports, you'll need to loop through the viewports:
|
||||
|
||||
|
||||
<details>
|
||||
<summary>Additional Notes</summary>
|
||||
|
||||
|
||||
- Each viewport can now have independent visibility settings for the same segmentation
|
||||
- The visibility state is specific to the representation type (Labelmap, Contour, etc.)
|
||||
- To check current visibility, use `getSegmentationRepresentationVisibility(viewportId, { segmentationId, type })`
|
||||
</details>
|
||||
|
||||
---
|
||||
+374
@@ -0,0 +1,374 @@
|
||||
---
|
||||
id: seg-other
|
||||
title: Other Changes
|
||||
---
|
||||
|
||||
|
||||
|
||||
|
||||
## addOrUpdateSegmentation
|
||||
|
||||
This was a public method but there is a good chance you were not using it
|
||||
|
||||
|
||||
**Before (OHIF 3.8)**
|
||||
|
||||
```js
|
||||
// Before
|
||||
addOrUpdateSegmentation(
|
||||
segmentation: Segmentation,
|
||||
suppressEvents = false,
|
||||
notYetUpdatedAtSource = false
|
||||
): string
|
||||
```
|
||||
|
||||
**After**
|
||||
|
||||
```js
|
||||
addOrUpdateSegmentation(
|
||||
segmentationInput: SegmentationPublicInput | Partial<Segmentation>
|
||||
)
|
||||
```
|
||||
|
||||
### Data Structure Changes
|
||||
|
||||
The segmentation object that was used previously was a custom segmentation object that was used internally by the SegmentationService. But
|
||||
we have moved to the cornerstone public segmentation input type.
|
||||
|
||||
**Before:**
|
||||
|
||||
```js
|
||||
const segmentation = {
|
||||
id: 'segmentation1',
|
||||
type: SegmentationRepresentations.Labelmap,
|
||||
isActive: true,
|
||||
activeSegmentIndex: 1,
|
||||
segments: [
|
||||
{
|
||||
segmentIndex: 1,
|
||||
color: [255, 0, 0],
|
||||
isVisible: true,
|
||||
isLocked: false,
|
||||
opacity: 255
|
||||
}
|
||||
],
|
||||
label: 'Segmentation 1',
|
||||
cachedStats: {},
|
||||
representationData: {
|
||||
LABELMAP: {
|
||||
volumeId: 'volume1',
|
||||
referencedVolumeId: 'reference1'
|
||||
}
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
|
||||
**After:**
|
||||
|
||||
This matches the cornerstone public segmentation input type.
|
||||
|
||||
```js
|
||||
const segmentationInput = {
|
||||
segmentationId: 'segmentation1',
|
||||
representation: {
|
||||
type: SegmentationRepresentations.Labelmap,
|
||||
data: {
|
||||
imageIds: segmentationImageIds,
|
||||
referencedVolumeId: 'reference1'
|
||||
}
|
||||
},
|
||||
config: {
|
||||
label: 'Segmentation 1',
|
||||
segments: {
|
||||
1: {
|
||||
label: 'Segment 1',
|
||||
active: true,
|
||||
locked: false
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
<details>
|
||||
<summary>Migration Examples</summary>
|
||||
|
||||
|
||||
```js
|
||||
// Before
|
||||
const newSegmentation = {
|
||||
id: 'seg1',
|
||||
type: SegmentationRepresentations.Labelmap,
|
||||
segments: [...],
|
||||
representationData: {
|
||||
LABELMAP: {
|
||||
volumeId: 'volume1',
|
||||
referencedVolumeId: 'reference1'
|
||||
}
|
||||
}
|
||||
};
|
||||
segmentationService.addOrUpdateSegmentation(newSegmentation);
|
||||
|
||||
// After
|
||||
segmentationService.addOrUpdateSegmentation({
|
||||
segmentationId: 'seg1',
|
||||
representation: {
|
||||
type: SegmentationRepresentations.Labelmap,
|
||||
data: {
|
||||
imageIds: segmentationImageIds,
|
||||
referencedVolumeId: 'reference1'
|
||||
}
|
||||
},
|
||||
config: {
|
||||
segments: {
|
||||
1: {
|
||||
label: 'Segment 1',
|
||||
active: true
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
|
||||
**Updating Existing Segmentation**
|
||||
|
||||
```js
|
||||
// Before
|
||||
const updatedSegmentation = {
|
||||
...existingSegmentation,
|
||||
segments: [...modifiedSegments],
|
||||
activeSegmentIndex: 2
|
||||
};
|
||||
segmentationService.addOrUpdateSegmentation(updatedSegmentation);
|
||||
|
||||
// After
|
||||
segmentationService.addOrUpdateSegmentation({
|
||||
segmentationId: 'seg1',
|
||||
config: {
|
||||
segments: {
|
||||
2: { active: true },
|
||||
}
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
|
||||
## loadSegmentationsForViewport
|
||||
|
||||
same as addOrUpdateSegmentation, you should pass in the new segmentation data structure.
|
||||
|
||||
For instance
|
||||
|
||||
**Before**
|
||||
|
||||
```js
|
||||
const segmentations = [
|
||||
{
|
||||
id: '1',
|
||||
label: 'Segmentations',
|
||||
segments: labels.map((label, index) => ({
|
||||
segmentIndex: index + 1,
|
||||
label
|
||||
})),
|
||||
isActive: true,
|
||||
activeSegmentIndex: 1,
|
||||
},
|
||||
];
|
||||
|
||||
commandsManager.runCommand('loadSegmentationsForViewport', {
|
||||
segmentations,
|
||||
});
|
||||
```
|
||||
|
||||
|
||||
|
||||
**After**
|
||||
|
||||
```js
|
||||
|
||||
const labels = ['Segment 1', 'Segment 2', 'Segment 3'];
|
||||
|
||||
const segmentations = [
|
||||
{
|
||||
segmentationId: '1',
|
||||
representation: {
|
||||
type: Enums.SegmentationRepresentations.Labelmap,
|
||||
},
|
||||
config: {
|
||||
label: 'Segmentations',
|
||||
segments: labels.reduce((acc, label, index) => {
|
||||
acc[index + 1] = {
|
||||
label,
|
||||
active: index === 0, // First segment is active
|
||||
locked: false,
|
||||
};
|
||||
return acc;
|
||||
}, {}),
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
commandsManager.runCommand('loadSegmentationsForViewport', {
|
||||
segmentations,
|
||||
});
|
||||
```
|
||||
|
||||
|
||||
---
|
||||
|
||||
|
||||
|
||||
|
||||
## highlightSegment
|
||||
|
||||
**Before (OHIF 3.8)**
|
||||
|
||||
```js
|
||||
// Before (v1.x)
|
||||
highlightSegment(
|
||||
segmentationId: string,
|
||||
segmentIndex: number,
|
||||
toolGroupId?: string,
|
||||
alpha = 0.9,
|
||||
animationLength = 750,
|
||||
hideOthers = true,
|
||||
highlightFunctionType = 'ease-in-out'
|
||||
)
|
||||
|
||||
```
|
||||
|
||||
**After (OHIF 3.9)**
|
||||
|
||||
```js
|
||||
highlightSegment(
|
||||
segmentationId: string,
|
||||
segmentIndex: number,
|
||||
viewportId?: string, // notice viewportId instead of toolGroupId
|
||||
alpha = 0.9,
|
||||
animationLength = 750,
|
||||
hideOthers = true,
|
||||
highlightFunctionType = 'ease-in-out'
|
||||
)
|
||||
```
|
||||
|
||||
<details>
|
||||
<summary>Key Changes</summary>
|
||||
|
||||
1. Removed `toolGroupId` in favor of `viewportId`
|
||||
2. If no viewportId is provided, highlights in all relevant viewports
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary>Migration Examples</summary>
|
||||
|
||||
**Basic Usage**
|
||||
|
||||
```js
|
||||
// Before
|
||||
segmentationService.highlightSegment(
|
||||
'seg1',
|
||||
1,
|
||||
'toolGroup1',
|
||||
0.9,
|
||||
750,
|
||||
true,
|
||||
);
|
||||
// After
|
||||
segmentationService.highlightSegment(
|
||||
'seg1',
|
||||
1,
|
||||
'viewport1',
|
||||
0.9,
|
||||
750,
|
||||
true
|
||||
);
|
||||
```
|
||||
|
||||
**Highlighting in Multiple Views**
|
||||
|
||||
```js
|
||||
// Before
|
||||
const toolGroupIds = ['toolGroup1', 'toolGroup2'];
|
||||
toolGroupIds.forEach(toolGroupId => {
|
||||
segmentationService.highlightSegment(
|
||||
'seg1',
|
||||
1,
|
||||
toolGroupId
|
||||
);
|
||||
});
|
||||
// After - Method 1: Let service handle multiple viewports
|
||||
segmentationService.highlightSegment('seg1', 1);
|
||||
// After - Method 2: Explicitly specify viewports
|
||||
const viewportIds = ['viewport1', 'viewport2'];
|
||||
viewportIds.forEach(viewportId => {
|
||||
segmentationService.highlightSegment(
|
||||
'seg1',
|
||||
1,
|
||||
viewportId
|
||||
);
|
||||
});
|
||||
```
|
||||
</details>
|
||||
|
||||
---
|
||||
|
||||
## jumpToSegmentCenter
|
||||
|
||||
**Before (OHIF 3.8)**
|
||||
|
||||
```js
|
||||
jumpToSegmentCenter(
|
||||
segmentationId: string,
|
||||
segmentIndex: number,
|
||||
toolGroupId?: string,
|
||||
highlightAlpha = 0.9,
|
||||
highlightSegment = true,
|
||||
animationLength = 750,
|
||||
highlightHideOthers = false,
|
||||
highlightFunctionType = 'ease-in-out'
|
||||
)
|
||||
```
|
||||
|
||||
**After (OHIF 3.9)**
|
||||
|
||||
```js
|
||||
jumpToSegmentCenter(
|
||||
segmentationId: string,
|
||||
segmentIndex: number,
|
||||
viewportId? string, // notice viewportId instead of toolGroupId
|
||||
highlightAlpha = 0.9,
|
||||
highlightSegment = true,
|
||||
animationLength = 750,
|
||||
highlightHideOthers = false,
|
||||
highlightFunctionType = 'ease-in-out'
|
||||
)
|
||||
```
|
||||
|
||||
<details>
|
||||
<summary>Key Changes</summary>
|
||||
|
||||
1. Removed `toolGroupId` parameter infavor of viewportId
|
||||
2. Automatically handles relevant viewports if `viewportId` not provided
|
||||
|
||||
|
||||
```
|
||||
// Before
|
||||
segmentationService.jumpToSegmentCenter(
|
||||
'seg1',
|
||||
1,
|
||||
'toolGroup1'
|
||||
);
|
||||
// After
|
||||
segmentationService.jumpToSegmentCenter(
|
||||
'seg1',
|
||||
1,
|
||||
'viewportId1'
|
||||
);
|
||||
```
|
||||
|
||||
</details>
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
---
|
||||
id: segmentation-index
|
||||
title: Segmentation
|
||||
sidebar_position: 1
|
||||
---
|
||||
|
||||
:::info
|
||||
This migration involves significant architectural changes to the segmentation system. While we typically aim for incremental updates, the shift from a tool group-centric to a viewport-centric architecture was necessary to support OHIF 3.9's advanced visualization capabilities, and more flexible segmentation handling.
|
||||
|
||||
Don't worry - we'll guide you through each change step by step!
|
||||
:::
|
||||
Reference in new issue
Block a user