@cornerstonejs/tools 0.56.6 → 0.57.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/stateManagement/segmentation/SegmentationStateManager.d.ts +1 -1
- package/dist/cjs/stateManagement/segmentation/SegmentationStateManager.js +5 -2
- package/dist/cjs/stateManagement/segmentation/SegmentationStateManager.js.map +1 -1
- package/dist/cjs/stateManagement/segmentation/config/segmentationColor.js.map +1 -1
- package/dist/cjs/stateManagement/segmentation/config/segmentationVisibility.js +23 -5
- package/dist/cjs/stateManagement/segmentation/config/segmentationVisibility.js.map +1 -1
- package/dist/cjs/stateManagement/segmentation/segmentationState.js +0 -10
- package/dist/cjs/stateManagement/segmentation/segmentationState.js.map +1 -1
- package/dist/cjs/tools/displayTools/Contour/addContourSetsToElement.d.ts +3 -0
- package/dist/cjs/tools/displayTools/Contour/addContourSetsToElement.js +70 -0
- package/dist/cjs/tools/displayTools/Contour/addContourSetsToElement.js.map +1 -0
- package/dist/cjs/tools/displayTools/Contour/addOrUpdateContourSets.d.ts +3 -0
- package/dist/cjs/tools/displayTools/Contour/addOrUpdateContourSets.js +14 -0
- package/dist/cjs/tools/displayTools/Contour/addOrUpdateContourSets.js.map +1 -0
- package/dist/cjs/tools/displayTools/Contour/contourConfig.d.ts +3 -0
- package/dist/cjs/tools/displayTools/Contour/contourConfig.js +14 -0
- package/dist/cjs/tools/displayTools/Contour/contourConfig.js.map +1 -0
- package/dist/cjs/tools/displayTools/Contour/contourConfigCache.d.ts +9 -0
- package/dist/cjs/tools/displayTools/Contour/contourConfigCache.js +17 -0
- package/dist/cjs/tools/displayTools/Contour/contourConfigCache.js.map +1 -0
- package/dist/cjs/tools/displayTools/Contour/contourDisplay.d.ts +1 -1
- package/dist/cjs/tools/displayTools/Contour/contourDisplay.js +4 -52
- package/dist/cjs/tools/displayTools/Contour/contourDisplay.js.map +1 -1
- package/dist/cjs/tools/displayTools/Contour/updateContourSets.d.ts +3 -0
- package/dist/cjs/tools/displayTools/Contour/updateContourSets.js +78 -0
- package/dist/cjs/tools/displayTools/Contour/updateContourSets.js.map +1 -0
- package/dist/cjs/tools/displayTools/Contour/utils.d.ts +6 -0
- package/dist/cjs/tools/displayTools/Contour/utils.js +63 -0
- package/dist/cjs/tools/displayTools/Contour/utils.js.map +1 -0
- package/dist/cjs/tools/displayTools/Labelmap/labelmapDisplay.js.map +1 -1
- package/dist/cjs/types/ContourTypes.d.ts +1 -0
- package/dist/cjs/types/SegmentationStateTypes.d.ts +4 -4
- package/dist/cjs/types/index.d.ts +2 -2
- package/dist/esm/stateManagement/segmentation/SegmentationStateManager.d.ts +1 -1
- package/dist/esm/stateManagement/segmentation/SegmentationStateManager.js +5 -2
- package/dist/esm/stateManagement/segmentation/SegmentationStateManager.js.map +1 -1
- package/dist/esm/stateManagement/segmentation/config/segmentationColor.js.map +1 -1
- package/dist/esm/stateManagement/segmentation/config/segmentationVisibility.js +19 -5
- package/dist/esm/stateManagement/segmentation/config/segmentationVisibility.js.map +1 -1
- package/dist/esm/stateManagement/segmentation/segmentationState.js +1 -11
- package/dist/esm/stateManagement/segmentation/segmentationState.js.map +1 -1
- package/dist/esm/tools/displayTools/Contour/addContourSetsToElement.d.ts +3 -0
- package/dist/esm/tools/displayTools/Contour/addContourSetsToElement.js +63 -0
- package/dist/esm/tools/displayTools/Contour/addContourSetsToElement.js.map +1 -0
- package/dist/esm/tools/displayTools/Contour/addOrUpdateContourSets.d.ts +3 -0
- package/dist/esm/tools/displayTools/Contour/addOrUpdateContourSets.js +10 -0
- package/dist/esm/tools/displayTools/Contour/addOrUpdateContourSets.js.map +1 -0
- package/dist/esm/tools/displayTools/Contour/contourConfig.d.ts +3 -0
- package/dist/esm/tools/displayTools/Contour/contourConfig.js +12 -0
- package/dist/esm/tools/displayTools/Contour/contourConfig.js.map +1 -0
- package/dist/esm/tools/displayTools/Contour/contourConfigCache.d.ts +9 -0
- package/dist/esm/tools/displayTools/Contour/contourConfigCache.js +11 -0
- package/dist/esm/tools/displayTools/Contour/contourConfigCache.js.map +1 -0
- package/dist/esm/tools/displayTools/Contour/contourDisplay.d.ts +1 -1
- package/dist/esm/tools/displayTools/Contour/contourDisplay.js +6 -54
- package/dist/esm/tools/displayTools/Contour/contourDisplay.js.map +1 -1
- package/dist/esm/tools/displayTools/Contour/updateContourSets.d.ts +3 -0
- package/dist/esm/tools/displayTools/Contour/updateContourSets.js +71 -0
- package/dist/esm/tools/displayTools/Contour/updateContourSets.js.map +1 -0
- package/dist/esm/tools/displayTools/Contour/utils.d.ts +6 -0
- package/dist/esm/tools/displayTools/Contour/utils.js +53 -0
- package/dist/esm/tools/displayTools/Contour/utils.js.map +1 -0
- package/dist/esm/tools/displayTools/Labelmap/labelmapDisplay.js.map +1 -1
- package/dist/esm/types/ContourTypes.d.ts +1 -0
- package/dist/esm/types/SegmentationStateTypes.d.ts +4 -4
- package/dist/esm/types/index.d.ts +2 -2
- package/dist/umd/index.js +1 -1
- package/dist/umd/index.js.map +1 -1
- package/package.json +3 -3
- package/src/stateManagement/segmentation/SegmentationStateManager.ts +10 -7
- package/src/stateManagement/segmentation/config/segmentationColor.ts +1 -0
- package/src/stateManagement/segmentation/config/segmentationVisibility.ts +25 -7
- package/src/stateManagement/segmentation/segmentationState.ts +7 -23
- package/src/tools/displayTools/Contour/addContourSetsToElement.ts +110 -0
- package/src/tools/displayTools/Contour/addOrUpdateContourSets.ts +28 -0
- package/src/tools/displayTools/Contour/contourConfig.ts +15 -0
- package/src/tools/displayTools/Contour/contourConfigCache.ts +37 -0
- package/src/tools/displayTools/Contour/contourDisplay.ts +11 -91
- package/src/tools/displayTools/Contour/updateContourSets.ts +111 -0
- package/src/tools/displayTools/Contour/utils.ts +117 -0
- package/src/tools/displayTools/Labelmap/labelmapDisplay.ts +5 -2
- package/src/types/ContourTypes.ts +2 -0
- package/src/types/SegmentationStateTypes.ts +22 -8
- package/src/types/index.ts +2 -0
- package/dist/cjs/tools/displayTools/Contour/addContourToElement.d.ts +0 -4
- package/dist/cjs/tools/displayTools/Contour/addContourToElement.js +0 -87
- package/dist/cjs/tools/displayTools/Contour/addContourToElement.js.map +0 -1
- package/dist/esm/tools/displayTools/Contour/addContourToElement.d.ts +0 -4
- package/dist/esm/tools/displayTools/Contour/addContourToElement.js +0 -80
- package/dist/esm/tools/displayTools/Contour/addContourToElement.js.map +0 -1
- package/src/tools/displayTools/Contour/addContourToElement.ts +0 -135
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cornerstonejs/tools",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.57.0",
|
|
4
4
|
"description": "Cornerstone3D Tools",
|
|
5
5
|
"main": "dist/umd/index.js",
|
|
6
6
|
"types": "dist/esm/index.d.ts",
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
"webpack:watch": "webpack --mode development --progress --watch --config ./.webpack/webpack.dev.js"
|
|
27
27
|
},
|
|
28
28
|
"dependencies": {
|
|
29
|
-
"@cornerstonejs/core": "^0.
|
|
29
|
+
"@cornerstonejs/core": "^0.37.0",
|
|
30
30
|
"lodash.clonedeep": "4.5.0",
|
|
31
31
|
"lodash.get": "^4.4.2"
|
|
32
32
|
},
|
|
@@ -52,5 +52,5 @@
|
|
|
52
52
|
"type": "individual",
|
|
53
53
|
"url": "https://ohif.org/donate"
|
|
54
54
|
},
|
|
55
|
-
"gitHead": "
|
|
55
|
+
"gitHead": "1e40104275742f14a7a48b076f244610f90e8657"
|
|
56
56
|
}
|
|
@@ -1,29 +1,32 @@
|
|
|
1
|
-
import cloneDeep from 'lodash.clonedeep';
|
|
2
1
|
import { utilities as csUtils } from '@cornerstonejs/core';
|
|
2
|
+
import cloneDeep from 'lodash.clonedeep';
|
|
3
3
|
|
|
4
4
|
import CORNERSTONE_COLOR_LUT from '../../constants/COLOR_LUT';
|
|
5
5
|
|
|
6
|
+
import { SegmentationRepresentations } from '../../enums';
|
|
7
|
+
import getDefaultContourConfig from '../../tools/displayTools/Contour/contourConfig';
|
|
8
|
+
import getDefaultLabelmapConfig from '../../tools/displayTools/Labelmap/labelmapConfig';
|
|
6
9
|
import type {
|
|
7
|
-
SegmentationState,
|
|
8
10
|
ColorLUT,
|
|
11
|
+
RepresentationConfig,
|
|
9
12
|
Segmentation,
|
|
10
|
-
ToolGroupSpecificRepresentation,
|
|
11
13
|
SegmentationRepresentationConfig,
|
|
12
|
-
|
|
13
|
-
RepresentationConfig,
|
|
14
|
+
SegmentationState,
|
|
14
15
|
SegmentSpecificRepresentationConfig,
|
|
16
|
+
ToolGroupSpecificRepresentation,
|
|
17
|
+
ToolGroupSpecificRepresentations,
|
|
15
18
|
} from '../../types/SegmentationStateTypes';
|
|
16
|
-
import getDefaultLabelmapConfig from '../../tools/displayTools/Labelmap/labelmapConfig';
|
|
17
|
-
import { SegmentationRepresentations } from '../../enums';
|
|
18
19
|
|
|
19
20
|
// Initialize the default configuration
|
|
20
21
|
// Note: when we get other representations, we should set their default representations too.
|
|
21
22
|
const defaultLabelmapConfig = getDefaultLabelmapConfig();
|
|
23
|
+
const defaultContourConfig = getDefaultContourConfig();
|
|
22
24
|
|
|
23
25
|
const newGlobalConfig: SegmentationRepresentationConfig = {
|
|
24
26
|
renderInactiveSegmentations: true,
|
|
25
27
|
representations: {
|
|
26
28
|
[SegmentationRepresentations.Labelmap]: defaultLabelmapConfig,
|
|
29
|
+
[SegmentationRepresentations.Contour]: defaultContourConfig,
|
|
27
30
|
},
|
|
28
31
|
};
|
|
29
32
|
|
|
@@ -3,6 +3,7 @@ import * as SegmentationState from '../../../stateManagement/segmentation/segmen
|
|
|
3
3
|
import { Color } from '../../../types/SegmentationStateTypes';
|
|
4
4
|
import { ColorLUT } from '../../../types/SegmentationStateTypes';
|
|
5
5
|
import { triggerSegmentationRepresentationModified } from '../triggerSegmentationEvents';
|
|
6
|
+
import { SegmentationRepresentations } from '../../../enums';
|
|
6
7
|
|
|
7
8
|
/**
|
|
8
9
|
* addColorLUT - Adds a new color LUT to the state at the given colorLUTIndex.
|
|
@@ -1,16 +1,34 @@
|
|
|
1
|
-
import { cache } from '@cornerstonejs/core';
|
|
1
|
+
import { cache, Types } from '@cornerstonejs/core';
|
|
2
2
|
import * as SegmentationState from '../../../stateManagement/segmentation/segmentationState';
|
|
3
3
|
import { getSegmentationRepresentations } from '../../../stateManagement/segmentation/segmentationState';
|
|
4
4
|
import { ToolGroupSpecificRepresentation } from '../../../types/SegmentationStateTypes';
|
|
5
5
|
import { triggerSegmentationRepresentationModified } from '../triggerSegmentationEvents';
|
|
6
|
+
import SegmentationRepresentations from '../../../enums/SegmentationRepresentations';
|
|
6
7
|
|
|
7
8
|
function getSegmentationIndices(segmentationId) {
|
|
8
|
-
const
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
9
|
+
const segmentation = SegmentationState.getSegmentation(segmentationId);
|
|
10
|
+
|
|
11
|
+
if (segmentation.type === SegmentationRepresentations.Labelmap) {
|
|
12
|
+
const volume = cache.getVolume(segmentationId);
|
|
13
|
+
const scalarData = volume.getScalarData();
|
|
14
|
+
|
|
15
|
+
const keySet = {};
|
|
16
|
+
scalarData.forEach((it) => (keySet[it] = it));
|
|
17
|
+
return Object.keys(keySet).map((it) => parseInt(it, 10));
|
|
18
|
+
} else if (segmentation.type === SegmentationRepresentations.Contour) {
|
|
19
|
+
const geometryIds = segmentation.representationData.CONTOUR?.geometryIds;
|
|
20
|
+
|
|
21
|
+
if (!geometryIds) {
|
|
22
|
+
throw new Error(
|
|
23
|
+
`No geometryIds found for segmentationId ${segmentationId}`
|
|
24
|
+
);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
return geometryIds.map((geometryId) => {
|
|
28
|
+
const geometry = cache.getGeometry(geometryId) as Types.IGeometry;
|
|
29
|
+
return (geometry.data as Types.IContourSet).getSegmentIndex();
|
|
30
|
+
});
|
|
31
|
+
}
|
|
14
32
|
}
|
|
15
33
|
|
|
16
34
|
/**
|
|
@@ -1,10 +1,3 @@
|
|
|
1
|
-
import { defaultSegmentationStateManager } from './SegmentationStateManager';
|
|
2
|
-
import {
|
|
3
|
-
triggerSegmentationRepresentationModified,
|
|
4
|
-
triggerSegmentationModified,
|
|
5
|
-
triggerSegmentationRepresentationRemoved,
|
|
6
|
-
triggerSegmentationRemoved,
|
|
7
|
-
} from './triggerSegmentationEvents';
|
|
8
1
|
import type {
|
|
9
2
|
ColorLUT,
|
|
10
3
|
RepresentationConfig,
|
|
@@ -15,10 +8,15 @@ import type {
|
|
|
15
8
|
ToolGroupSpecificRepresentation,
|
|
16
9
|
ToolGroupSpecificRepresentations,
|
|
17
10
|
} from '../../types/SegmentationStateTypes';
|
|
11
|
+
import { defaultSegmentationStateManager } from './SegmentationStateManager';
|
|
12
|
+
import {
|
|
13
|
+
triggerSegmentationModified,
|
|
14
|
+
triggerSegmentationRemoved,
|
|
15
|
+
triggerSegmentationRepresentationModified,
|
|
16
|
+
triggerSegmentationRepresentationRemoved,
|
|
17
|
+
} from './triggerSegmentationEvents';
|
|
18
18
|
|
|
19
19
|
import normalizeSegmentationInput from './helpers/normalizeSegmentationInput';
|
|
20
|
-
import getDefaultLabelmapConfig from '../../tools/displayTools/Labelmap/labelmapConfig';
|
|
21
|
-
import { SegmentationRepresentations } from '../../enums';
|
|
22
20
|
|
|
23
21
|
/**
|
|
24
22
|
* It returns the defaultSegmentationStateManager.
|
|
@@ -385,21 +383,7 @@ function addColorLUT(colorLUT: ColorLUT, index: number): void {
|
|
|
385
383
|
// Todo: trigger event color LUT added
|
|
386
384
|
}
|
|
387
385
|
|
|
388
|
-
// Initialize the default configuration
|
|
389
|
-
// Note: when we get other representations, we should set their default representations too.
|
|
390
|
-
const defaultLabelmapConfig = getDefaultLabelmapConfig();
|
|
391
|
-
|
|
392
|
-
const newGlobalConfig: SegmentationRepresentationConfig = {
|
|
393
|
-
renderInactiveSegmentations: true,
|
|
394
|
-
representations: {
|
|
395
|
-
[SegmentationRepresentations.Labelmap]: defaultLabelmapConfig,
|
|
396
|
-
},
|
|
397
|
-
};
|
|
398
|
-
|
|
399
|
-
setGlobalConfig(newGlobalConfig, true);
|
|
400
|
-
|
|
401
386
|
export {
|
|
402
|
-
// state manager
|
|
403
387
|
getDefaultSegmentationStateManager,
|
|
404
388
|
// Segmentation
|
|
405
389
|
getSegmentation,
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import { cache, Types } from '@cornerstonejs/core';
|
|
2
|
+
import vtkDataArray from '@kitware/vtk.js/Common/Core/DataArray';
|
|
3
|
+
import vtkAppendPolyData from '@kitware/vtk.js/Filters/General/AppendPolyData';
|
|
4
|
+
import vtkActor from '@kitware/vtk.js/Rendering/Core/Actor';
|
|
5
|
+
import vtkMapper from '@kitware/vtk.js/Rendering/Core/Mapper';
|
|
6
|
+
|
|
7
|
+
import {
|
|
8
|
+
getPolyData,
|
|
9
|
+
getSegmentSpecificConfig,
|
|
10
|
+
validateGeometry,
|
|
11
|
+
} from './utils';
|
|
12
|
+
|
|
13
|
+
import {
|
|
14
|
+
SegmentationRepresentationConfig,
|
|
15
|
+
ToolGroupSpecificContourRepresentation,
|
|
16
|
+
} from '../../../types';
|
|
17
|
+
import { getConfigCache, setConfigCache } from './contourConfigCache';
|
|
18
|
+
|
|
19
|
+
export function addContourSetsToElement(
|
|
20
|
+
viewport: Types.IVolumeViewport,
|
|
21
|
+
geometryIds: string[],
|
|
22
|
+
contourRepresentation: ToolGroupSpecificContourRepresentation,
|
|
23
|
+
contourRepresentationConfig: SegmentationRepresentationConfig,
|
|
24
|
+
contourActorUID: string
|
|
25
|
+
) {
|
|
26
|
+
const { segmentationRepresentationUID, segmentsHidden } =
|
|
27
|
+
contourRepresentation;
|
|
28
|
+
const appendPolyData = vtkAppendPolyData.newInstance();
|
|
29
|
+
|
|
30
|
+
const scalarToColorMap = new Map();
|
|
31
|
+
const segmentSpecificMap = new Map();
|
|
32
|
+
|
|
33
|
+
geometryIds.forEach((geometryId) => {
|
|
34
|
+
const geometry = cache.getGeometry(geometryId);
|
|
35
|
+
|
|
36
|
+
if (!geometry) {
|
|
37
|
+
console.warn(
|
|
38
|
+
`No geometry found for geometryId ${geometryId}. Skipping render.`
|
|
39
|
+
);
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const segmentIndex = (geometry.data as Types.IContourSet).getSegmentIndex();
|
|
44
|
+
|
|
45
|
+
validateGeometry(geometry);
|
|
46
|
+
|
|
47
|
+
const segmentSpecificConfig = getSegmentSpecificConfig(
|
|
48
|
+
contourRepresentation,
|
|
49
|
+
geometryId,
|
|
50
|
+
segmentIndex
|
|
51
|
+
);
|
|
52
|
+
|
|
53
|
+
const contourSet = geometry.data;
|
|
54
|
+
const polyData = getPolyData(contourSet);
|
|
55
|
+
const color = contourSet.getColor();
|
|
56
|
+
|
|
57
|
+
const size = polyData.getPoints().getNumberOfPoints();
|
|
58
|
+
|
|
59
|
+
const scalars = vtkDataArray.newInstance({
|
|
60
|
+
size: size * 4,
|
|
61
|
+
numberOfComponents: 4,
|
|
62
|
+
dataType: 'Uint8Array',
|
|
63
|
+
});
|
|
64
|
+
for (let i = 0; i < size; ++i) {
|
|
65
|
+
scalars.setTuple(i, [...color, 255]);
|
|
66
|
+
}
|
|
67
|
+
polyData.getPointData().setScalars(scalars);
|
|
68
|
+
|
|
69
|
+
if (segmentSpecificConfig) {
|
|
70
|
+
segmentSpecificMap.set(segmentIndex, segmentSpecificConfig);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
scalarToColorMap.set(segmentIndex, [
|
|
74
|
+
...color,
|
|
75
|
+
segmentsHidden.has(segmentIndex) ? 0 : 255,
|
|
76
|
+
]);
|
|
77
|
+
|
|
78
|
+
segmentIndex === 0
|
|
79
|
+
? appendPolyData.setInputData(polyData)
|
|
80
|
+
: appendPolyData.addInputData(polyData);
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
const polyDataOutput = appendPolyData.getOutputData();
|
|
84
|
+
|
|
85
|
+
const outlineWidthActive =
|
|
86
|
+
contourRepresentationConfig.representations.CONTOUR.outlineWidthActive;
|
|
87
|
+
|
|
88
|
+
const mapper = vtkMapper.newInstance();
|
|
89
|
+
mapper.setInputData(polyDataOutput);
|
|
90
|
+
|
|
91
|
+
const actor = vtkActor.newInstance();
|
|
92
|
+
actor.setMapper(mapper);
|
|
93
|
+
actor.getProperty().setLineWidth(outlineWidthActive);
|
|
94
|
+
|
|
95
|
+
// set the config cache for later update of the contour
|
|
96
|
+
setConfigCache(
|
|
97
|
+
segmentationRepresentationUID,
|
|
98
|
+
Object.assign({}, getConfigCache(segmentationRepresentationUID), {
|
|
99
|
+
segmentsHidden: new Set(segmentsHidden),
|
|
100
|
+
segmentSpecificMap,
|
|
101
|
+
outlineWidthActive,
|
|
102
|
+
})
|
|
103
|
+
);
|
|
104
|
+
|
|
105
|
+
actor.setForceOpaque(true);
|
|
106
|
+
|
|
107
|
+
viewport.addActor({ uid: contourActorUID, actor });
|
|
108
|
+
viewport.resetCamera();
|
|
109
|
+
viewport.render();
|
|
110
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { Types } from '@cornerstonejs/core';
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
SegmentationRepresentationConfig,
|
|
5
|
+
ToolGroupSpecificContourRepresentation,
|
|
6
|
+
} from '../../../types';
|
|
7
|
+
import { addContourSetsToElement } from './addContourSetsToElement';
|
|
8
|
+
import { updateContourSets } from './updateContourSets';
|
|
9
|
+
|
|
10
|
+
export function addOrUpdateContourSets(
|
|
11
|
+
viewport: Types.IVolumeViewport,
|
|
12
|
+
geometryIds: string[],
|
|
13
|
+
contourRepresentation: ToolGroupSpecificContourRepresentation,
|
|
14
|
+
contourRepresentationConfig: SegmentationRepresentationConfig
|
|
15
|
+
) {
|
|
16
|
+
const { segmentationRepresentationUID } = contourRepresentation;
|
|
17
|
+
const actorUID = `CONTOUR_${segmentationRepresentationUID}`;
|
|
18
|
+
const actor = viewport.getActor(actorUID);
|
|
19
|
+
|
|
20
|
+
const addOrUpdateFn = actor ? updateContourSets : addContourSetsToElement;
|
|
21
|
+
addOrUpdateFn(
|
|
22
|
+
viewport,
|
|
23
|
+
geometryIds,
|
|
24
|
+
contourRepresentation,
|
|
25
|
+
contourRepresentationConfig,
|
|
26
|
+
actorUID
|
|
27
|
+
);
|
|
28
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { ContourConfig } from '../../../types/ContourTypes';
|
|
2
|
+
|
|
3
|
+
const defaultContourConfig: ContourConfig = {
|
|
4
|
+
renderOutline: true,
|
|
5
|
+
outlineWidthActive: 2,
|
|
6
|
+
outlineWidthInactive: 2,
|
|
7
|
+
outlineOpacity: 1,
|
|
8
|
+
outlineOpacityInactive: 0.85,
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
function getDefaultContourConfig(): ContourConfig {
|
|
12
|
+
return defaultContourConfig;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export default getDefaultContourConfig;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
type ConfigCache = {
|
|
2
|
+
segmentsHidden: Set<number>;
|
|
3
|
+
outlineWidthActive: number;
|
|
4
|
+
visibility: boolean;
|
|
5
|
+
};
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Config cache is used to store the config for a given segmentation
|
|
9
|
+
* representation. This is used to avoid having to recompute the config
|
|
10
|
+
* every time the user changes the active segment, and also for performance
|
|
11
|
+
* reasons.
|
|
12
|
+
*/
|
|
13
|
+
const configCachePerSegmentationRepresentationUID = new Map();
|
|
14
|
+
|
|
15
|
+
export function getConfigCache(
|
|
16
|
+
segmentationRepresentationUID: string
|
|
17
|
+
): ConfigCache {
|
|
18
|
+
return configCachePerSegmentationRepresentationUID.get(
|
|
19
|
+
segmentationRepresentationUID
|
|
20
|
+
);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export function setConfigCache(
|
|
24
|
+
segmentationRepresentationUID: string,
|
|
25
|
+
config: ConfigCache
|
|
26
|
+
) {
|
|
27
|
+
configCachePerSegmentationRepresentationUID.set(
|
|
28
|
+
segmentationRepresentationUID,
|
|
29
|
+
config
|
|
30
|
+
);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export function deleteConfigCache(segmentationRepresentationUID: string) {
|
|
34
|
+
configCachePerSegmentationRepresentationUID.delete(
|
|
35
|
+
segmentationRepresentationUID
|
|
36
|
+
);
|
|
37
|
+
}
|
|
@@ -1,6 +1,4 @@
|
|
|
1
1
|
import {
|
|
2
|
-
cache,
|
|
3
|
-
Enums,
|
|
4
2
|
getEnabledElementByIds,
|
|
5
3
|
Types,
|
|
6
4
|
utilities as csUtils,
|
|
@@ -15,12 +13,8 @@ import {
|
|
|
15
13
|
SegmentationRepresentationConfig,
|
|
16
14
|
ToolGroupSpecificRepresentation,
|
|
17
15
|
} from '../../../types/SegmentationStateTypes';
|
|
18
|
-
|
|
19
|
-
import
|
|
20
|
-
addContourSetToElement,
|
|
21
|
-
addContourToElement,
|
|
22
|
-
} from './addContourToElement';
|
|
23
|
-
import { default as removeContourFromElement } from './removeContourFromElement';
|
|
16
|
+
import { addOrUpdateContourSets } from './addOrUpdateContourSets';
|
|
17
|
+
import removeContourFromElement from './removeContourFromElement';
|
|
24
18
|
|
|
25
19
|
/**
|
|
26
20
|
* It adds a new segmentation representation to the segmentation state
|
|
@@ -123,17 +117,10 @@ function removeSegmentationRepresentation(
|
|
|
123
117
|
*/
|
|
124
118
|
async function render(
|
|
125
119
|
viewport: Types.IVolumeViewport,
|
|
126
|
-
|
|
120
|
+
representationConfig: ToolGroupSpecificRepresentation,
|
|
127
121
|
toolGroupConfig: SegmentationRepresentationConfig
|
|
128
122
|
): Promise<void> {
|
|
129
|
-
const {
|
|
130
|
-
colorLUTIndex,
|
|
131
|
-
active,
|
|
132
|
-
segmentationId,
|
|
133
|
-
segmentationRepresentationUID,
|
|
134
|
-
segmentsHidden,
|
|
135
|
-
} = representation;
|
|
136
|
-
|
|
123
|
+
const { segmentationId } = representationConfig;
|
|
137
124
|
const segmentation = SegmentationState.getSegmentation(segmentationId);
|
|
138
125
|
const contourData = segmentation.representationData[Representations.Contour];
|
|
139
126
|
const { geometryIds } = contourData;
|
|
@@ -144,80 +131,13 @@ async function render(
|
|
|
144
131
|
);
|
|
145
132
|
}
|
|
146
133
|
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
) {
|
|
155
|
-
geometryIds.forEach((geometryId) => {
|
|
156
|
-
const geometry = cache.getGeometry(geometryId);
|
|
157
|
-
if (!geometry) {
|
|
158
|
-
throw new Error(`No contours found for geometryId ${geometryId}`);
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
if (geometry.type !== Enums.GeometryType.CONTOUR) {
|
|
162
|
-
// Todo: later we can support converting other geometries to contours
|
|
163
|
-
throw new Error(
|
|
164
|
-
`Geometry type ${geometry.type} not supported for rendering.`
|
|
165
|
-
);
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
if (!geometry.data) {
|
|
169
|
-
console.warn(
|
|
170
|
-
`No contours found for geometryId ${geometryId}. Skipping render.`
|
|
171
|
-
);
|
|
172
|
-
return;
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
const contourSet = geometry.data;
|
|
176
|
-
|
|
177
|
-
_renderContourSet(viewport, contourSet, segmentationRepresentationUID);
|
|
178
|
-
});
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
function _renderContourSet(
|
|
182
|
-
viewport: Types.IVolumeViewport,
|
|
183
|
-
contourSet: Types.IContourSet,
|
|
184
|
-
segmentationRepresentationUID: string,
|
|
185
|
-
separated = false
|
|
186
|
-
): void {
|
|
187
|
-
if (separated) {
|
|
188
|
-
contourSet.getContours().forEach((contour: Types.IContour, index) => {
|
|
189
|
-
const contourUID = `${segmentationRepresentationUID}_${contourSet.id}_${index}}`;
|
|
190
|
-
_renderContour(viewport, contour, contourUID);
|
|
191
|
-
});
|
|
192
|
-
} else {
|
|
193
|
-
const contourUID = `${segmentationRepresentationUID}_${contourSet.id}`;
|
|
194
|
-
const actorUID = contourUID;
|
|
195
|
-
const actorEntry = viewport.getActor(actorUID);
|
|
196
|
-
|
|
197
|
-
if (!actorEntry) {
|
|
198
|
-
addContourSetToElement(viewport.element, contourSet, actorUID);
|
|
199
|
-
} else {
|
|
200
|
-
throw new Error('Not implemented yet. (Update contour)');
|
|
201
|
-
}
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
viewport.resetCamera();
|
|
205
|
-
viewport.render();
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
function _renderContour(
|
|
209
|
-
viewport: Types.IVolumeViewport,
|
|
210
|
-
contour: Types.IContour,
|
|
211
|
-
contourUID: string
|
|
212
|
-
): void {
|
|
213
|
-
const actorUID = contourUID;
|
|
214
|
-
const actorEntry = viewport.getActor(actorUID);
|
|
215
|
-
|
|
216
|
-
if (!actorEntry) {
|
|
217
|
-
addContourToElement(viewport.element, contour, actorUID);
|
|
218
|
-
} else {
|
|
219
|
-
throw new Error('Not implemented yet. (Update contour)');
|
|
220
|
-
}
|
|
134
|
+
// add the contour sets to the viewport
|
|
135
|
+
addOrUpdateContourSets(
|
|
136
|
+
viewport,
|
|
137
|
+
geometryIds,
|
|
138
|
+
representationConfig,
|
|
139
|
+
toolGroupConfig
|
|
140
|
+
);
|
|
221
141
|
}
|
|
222
142
|
|
|
223
143
|
function _removeContourFromToolGroupViewports(
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import { cache, Types } from '@cornerstonejs/core';
|
|
2
|
+
import vtkDataArray from '@kitware/vtk.js/Common/Core/DataArray';
|
|
3
|
+
import vtkAppendPolyData from '@kitware/vtk.js/Filters/General/AppendPolyData';
|
|
4
|
+
import vtkActor from '@kitware/vtk.js/Rendering/Core/Actor';
|
|
5
|
+
|
|
6
|
+
import {
|
|
7
|
+
SegmentationRepresentationConfig,
|
|
8
|
+
ToolGroupSpecificContourRepresentation,
|
|
9
|
+
} from '../../../types';
|
|
10
|
+
import { getConfigCache, setConfigCache } from './contourConfigCache';
|
|
11
|
+
import { getPolyData } from './utils';
|
|
12
|
+
|
|
13
|
+
export function updateContourSets(
|
|
14
|
+
viewport: Types.IVolumeViewport,
|
|
15
|
+
geometryIds: string[],
|
|
16
|
+
contourRepresentation: ToolGroupSpecificContourRepresentation,
|
|
17
|
+
contourRepresentationConfig: SegmentationRepresentationConfig,
|
|
18
|
+
contourActorUID: string
|
|
19
|
+
) {
|
|
20
|
+
const { segmentationRepresentationUID, segmentsHidden } =
|
|
21
|
+
contourRepresentation;
|
|
22
|
+
const newContourConfig = contourRepresentationConfig.representations.CONTOUR;
|
|
23
|
+
const cachedConfig = getConfigCache(segmentationRepresentationUID);
|
|
24
|
+
|
|
25
|
+
const contourSetsActor = viewport.getActor(contourActorUID);
|
|
26
|
+
|
|
27
|
+
if (!contourSetsActor) {
|
|
28
|
+
console.warn(
|
|
29
|
+
`No contour actor found for actorUID ${contourActorUID}. Skipping render.`
|
|
30
|
+
);
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const { actor } = contourSetsActor;
|
|
35
|
+
|
|
36
|
+
const newOutlineWithActive = newContourConfig.outlineWidthActive;
|
|
37
|
+
|
|
38
|
+
if (cachedConfig?.outlineWidthActive !== newOutlineWithActive) {
|
|
39
|
+
(actor as vtkActor).getProperty().setLineWidth(newOutlineWithActive);
|
|
40
|
+
|
|
41
|
+
setConfigCache(
|
|
42
|
+
segmentationRepresentationUID,
|
|
43
|
+
Object.assign({}, cachedConfig, {
|
|
44
|
+
outlineWidthActive: newOutlineWithActive,
|
|
45
|
+
})
|
|
46
|
+
);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const mapper = (actor as vtkActor).getMapper();
|
|
50
|
+
const lut = mapper.getLookupTable();
|
|
51
|
+
|
|
52
|
+
const segmentsToSetToInvisible = [];
|
|
53
|
+
const segmentsToSetToVisible = [];
|
|
54
|
+
|
|
55
|
+
for (const segmentIndex of segmentsHidden) {
|
|
56
|
+
if (!cachedConfig?.segmentsHidden.has(segmentIndex)) {
|
|
57
|
+
segmentsToSetToInvisible.push(segmentIndex);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// the other way around
|
|
62
|
+
for (const segmentIndex of cachedConfig.segmentsHidden) {
|
|
63
|
+
if (!segmentsHidden.has(segmentIndex)) {
|
|
64
|
+
segmentsToSetToVisible.push(segmentIndex);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
if (segmentsToSetToInvisible.length || segmentsToSetToVisible.length) {
|
|
68
|
+
const appendPolyData = vtkAppendPolyData.newInstance();
|
|
69
|
+
|
|
70
|
+
geometryIds.forEach((geometryId) => {
|
|
71
|
+
const geometry = cache.getGeometry(geometryId);
|
|
72
|
+
const { data: contourSet } = geometry;
|
|
73
|
+
const segmentIndex = (contourSet as Types.IContourSet).getSegmentIndex();
|
|
74
|
+
const color = contourSet.getColor();
|
|
75
|
+
const visibility = segmentsToSetToInvisible.includes(segmentIndex)
|
|
76
|
+
? 0
|
|
77
|
+
: 255;
|
|
78
|
+
const polyData = getPolyData(contourSet);
|
|
79
|
+
|
|
80
|
+
const size = polyData.getPoints().getNumberOfPoints();
|
|
81
|
+
|
|
82
|
+
const scalars = vtkDataArray.newInstance({
|
|
83
|
+
size: size * 4,
|
|
84
|
+
numberOfComponents: 4,
|
|
85
|
+
dataType: 'Uint8Array',
|
|
86
|
+
});
|
|
87
|
+
for (let i = 0; i < size; ++i) {
|
|
88
|
+
scalars.setTuple(i, [...color, visibility]);
|
|
89
|
+
}
|
|
90
|
+
polyData.getPointData().setScalars(scalars);
|
|
91
|
+
|
|
92
|
+
segmentIndex === 0
|
|
93
|
+
? appendPolyData.setInputData(polyData)
|
|
94
|
+
: appendPolyData.addInputData(polyData);
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
const polyDataOutput = appendPolyData.getOutputData();
|
|
98
|
+
mapper.setInputData(polyDataOutput);
|
|
99
|
+
|
|
100
|
+
setConfigCache(
|
|
101
|
+
segmentationRepresentationUID,
|
|
102
|
+
Object.assign({}, cachedConfig, {
|
|
103
|
+
segmentsHidden: new Set(segmentsHidden),
|
|
104
|
+
})
|
|
105
|
+
);
|
|
106
|
+
|
|
107
|
+
mapper.setLookupTable(lut);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
viewport.render();
|
|
111
|
+
}
|