@cornerstonejs/tools 5.4.13 → 5.4.14
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/esm/eventListeners/segmentation/segmentationDataModifiedEventListener.js +2 -2
- package/dist/esm/stateManagement/segmentation/SegmentationRenderingEngine.d.ts +2 -1
- package/dist/esm/stateManagement/segmentation/SegmentationRenderingEngine.js +45 -1
- package/dist/esm/tools/displayTools/Labelmap/addVolumesAsIndependentComponents.js +42 -11
- package/dist/esm/version.d.ts +1 -1
- package/dist/esm/version.js +1 -1
- package/package.json +4 -4
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { triggerSegmentationRenderForModified } from '../../stateManagement/segmentation/SegmentationRenderingEngine.js';
|
|
2
2
|
import onLabelmapSegmentationDataModified from './labelmap/onLabelmapSegmentationDataModified.js';
|
|
3
3
|
import { getSegmentation } from '../../stateManagement/segmentation/getSegmentation.js';
|
|
4
4
|
const onSegmentationDataModified = function (evt) {
|
|
@@ -7,6 +7,6 @@ const onSegmentationDataModified = function (evt) {
|
|
|
7
7
|
if (representationData.Labelmap) {
|
|
8
8
|
onLabelmapSegmentationDataModified(evt);
|
|
9
9
|
}
|
|
10
|
-
|
|
10
|
+
triggerSegmentationRenderForModified(segmentationId);
|
|
11
11
|
};
|
|
12
12
|
export default onSegmentationDataModified;
|
|
@@ -17,5 +17,6 @@ declare class SegmentationRenderingEngine {
|
|
|
17
17
|
}
|
|
18
18
|
declare function triggerSegmentationRender(viewportId?: string): void;
|
|
19
19
|
declare function triggerSegmentationRenderBySegmentationId(segmentationId?: string): void;
|
|
20
|
+
declare function triggerSegmentationRenderForModified(segmentationId?: string): void;
|
|
20
21
|
declare const segmentationRenderingEngine: SegmentationRenderingEngine;
|
|
21
|
-
export { triggerSegmentationRender, triggerSegmentationRenderBySegmentationId, segmentationRenderingEngine, };
|
|
22
|
+
export { triggerSegmentationRender, triggerSegmentationRenderBySegmentationId, triggerSegmentationRenderForModified, segmentationRenderingEngine, };
|
|
@@ -169,5 +169,49 @@ function triggerSegmentationRender(viewportId) {
|
|
|
169
169
|
function triggerSegmentationRenderBySegmentationId(segmentationId) {
|
|
170
170
|
segmentationRenderingEngine.renderSegmentation(segmentationId);
|
|
171
171
|
}
|
|
172
|
+
const DEFERRED_SEGMENTATION_RENDER_DELAY_MS = 240;
|
|
173
|
+
const deferredSegmentationRenderTimers = new Map();
|
|
174
|
+
function isProjectionHeavySegmentationViewport(viewport) {
|
|
175
|
+
const blendMode = viewport.getBlendMode?.();
|
|
176
|
+
if (blendMode === Enums.BlendModes.LABELMAP_EDGE_PROJECTION_BLEND) {
|
|
177
|
+
return true;
|
|
178
|
+
}
|
|
179
|
+
const planarViewport = viewport;
|
|
180
|
+
if (typeof planarViewport.getDisplaySetPresentation !== 'function') {
|
|
181
|
+
return false;
|
|
182
|
+
}
|
|
183
|
+
const dataIds = [];
|
|
184
|
+
const sourceDataId = planarViewport.getSourceDataId?.();
|
|
185
|
+
if (sourceDataId) {
|
|
186
|
+
dataIds.push(sourceDataId);
|
|
187
|
+
}
|
|
188
|
+
planarViewport.getActors?.().forEach((actorEntry) => {
|
|
189
|
+
if (actorEntry.representationUID) {
|
|
190
|
+
dataIds.push(String(actorEntry.representationUID));
|
|
191
|
+
}
|
|
192
|
+
});
|
|
193
|
+
return dataIds.some((dataId) => (planarViewport.getDisplaySetPresentation(dataId)?.slabThickness ?? 0) > 0);
|
|
194
|
+
}
|
|
195
|
+
function triggerSegmentationRenderForModified(segmentationId) {
|
|
196
|
+
const viewportIds = segmentationRenderingEngine._getViewportIdsForSegmentation(segmentationId);
|
|
197
|
+
viewportIds.forEach((viewportId) => {
|
|
198
|
+
const { viewport } = getEnabledElementByViewportId(viewportId) || {};
|
|
199
|
+
if (!viewport) {
|
|
200
|
+
return;
|
|
201
|
+
}
|
|
202
|
+
if (!isProjectionHeavySegmentationViewport(viewport)) {
|
|
203
|
+
segmentationRenderingEngine.renderSegmentationsForViewport(viewportId);
|
|
204
|
+
return;
|
|
205
|
+
}
|
|
206
|
+
const existingTimer = deferredSegmentationRenderTimers.get(viewportId);
|
|
207
|
+
if (existingTimer !== undefined) {
|
|
208
|
+
clearTimeout(existingTimer);
|
|
209
|
+
}
|
|
210
|
+
deferredSegmentationRenderTimers.set(viewportId, setTimeout(() => {
|
|
211
|
+
deferredSegmentationRenderTimers.delete(viewportId);
|
|
212
|
+
segmentationRenderingEngine.renderSegmentationsForViewport(viewportId);
|
|
213
|
+
}, DEFERRED_SEGMENTATION_RENDER_DELAY_MS));
|
|
214
|
+
});
|
|
215
|
+
}
|
|
172
216
|
const segmentationRenderingEngine = new SegmentationRenderingEngine();
|
|
173
|
-
export { triggerSegmentationRender, triggerSegmentationRenderBySegmentationId, segmentationRenderingEngine, };
|
|
217
|
+
export { triggerSegmentationRender, triggerSegmentationRenderBySegmentationId, triggerSegmentationRenderForModified, segmentationRenderingEngine, };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { cache, Enums, convertMapperToNotSharedMapper, volumeLoader, eventTarget,
|
|
1
|
+
import { cache, Enums, convertMapperToNotSharedMapper, volumeLoader, eventTarget, } from '@cornerstonejs/core';
|
|
2
2
|
import { Events, SegmentationRepresentations } from '../../../enums/index.js';
|
|
3
3
|
import { getSegmentation } from '../../../stateManagement/segmentation/getSegmentation.js';
|
|
4
4
|
const internalCache = new Map();
|
|
@@ -52,6 +52,8 @@ export async function addVolumesAsIndependentComponents({ viewport, volumeInputs
|
|
|
52
52
|
}
|
|
53
53
|
viewport.removeActors([uid]);
|
|
54
54
|
const oldMapper = actor.getMapper();
|
|
55
|
+
const sharedImageData = oldMapper.getInputData();
|
|
56
|
+
const originalScalars = sharedImageData.getPointData().getScalars() ?? null;
|
|
55
57
|
const mapper = convertMapperToNotSharedMapper(oldMapper);
|
|
56
58
|
actor.setMapper(mapper);
|
|
57
59
|
mapper.setBlendMode(Enums.BlendModes.LABELMAP_EDGE_PROJECTION_BLEND);
|
|
@@ -68,9 +70,16 @@ export async function addVolumesAsIndependentComponents({ viewport, volumeInputs
|
|
|
68
70
|
.getProperty()
|
|
69
71
|
.getIndependentComponents();
|
|
70
72
|
actor.getProperty().setIndependentComponents(true);
|
|
73
|
+
const oldUseLabelOutline = actor.getProperty().getUseLabelOutline();
|
|
74
|
+
const oldLabelOutlineOpacity = actor.getProperty().getLabelOutlineOpacity();
|
|
75
|
+
const oldLabelOutlineThickness = actor
|
|
76
|
+
.getProperty()
|
|
77
|
+
.getLabelOutlineThickness();
|
|
78
|
+
const representationUID = volumeInputArray[0].representationUID ??
|
|
79
|
+
`${segmentationId}-${SegmentationRepresentations.Labelmap}`;
|
|
71
80
|
viewport.addActor({
|
|
72
81
|
...defaultActor,
|
|
73
|
-
representationUID
|
|
82
|
+
representationUID,
|
|
74
83
|
});
|
|
75
84
|
internalCache.set(uid, {
|
|
76
85
|
added: true,
|
|
@@ -82,7 +91,7 @@ export async function addVolumesAsIndependentComponents({ viewport, volumeInputs
|
|
|
82
91
|
preLoad: load,
|
|
83
92
|
});
|
|
84
93
|
function onSegmentationDataModified(evt) {
|
|
85
|
-
const { segmentationId } = evt.detail;
|
|
94
|
+
const { segmentationId, modifiedSlicesToUse } = evt.detail;
|
|
86
95
|
const { representationData } = getSegmentation(segmentationId);
|
|
87
96
|
const { volumeId: segVolumeId } = representationData.Labelmap;
|
|
88
97
|
if (segVolumeId !== segImageVolume.volumeId) {
|
|
@@ -92,19 +101,30 @@ export async function addVolumesAsIndependentComponents({ viewport, volumeInputs
|
|
|
92
101
|
const segVoxelManager = segmentationVolume.voxelManager;
|
|
93
102
|
const imageData = mapper.getInputData();
|
|
94
103
|
const array = imageData.getPointData().getArray(0);
|
|
95
|
-
const
|
|
104
|
+
const combinedData = array.getData();
|
|
96
105
|
const newComp = 2;
|
|
97
106
|
const dims = segImageData.getDimensions();
|
|
98
|
-
const
|
|
107
|
+
const sliceSize = dims[0] * dims[1];
|
|
108
|
+
const slices = modifiedSlicesToUse?.length
|
|
109
|
+
? modifiedSlicesToUse
|
|
110
|
+
: Array.from({ length: dims[2] }, (_, i) => i);
|
|
99
111
|
for (const z of slices) {
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
112
|
+
const sliceStart = z * sliceSize;
|
|
113
|
+
const sliceImage = cache.getImage(segmentationVolume.imageIds?.[z]);
|
|
114
|
+
const sliceData = sliceImage?.voxelManager?.getScalarData?.();
|
|
115
|
+
if (sliceData?.length === sliceSize) {
|
|
116
|
+
for (let i = 0; i < sliceSize; ++i) {
|
|
117
|
+
combinedData[(sliceStart + i) * newComp + 1] = sliceData[i];
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
else {
|
|
121
|
+
for (let i = 0; i < sliceSize; ++i) {
|
|
122
|
+
const iTuple = sliceStart + i;
|
|
123
|
+
combinedData[iTuple * newComp + 1] = segVoxelManager.getAtIndex(iTuple);
|
|
104
124
|
}
|
|
105
125
|
}
|
|
106
126
|
}
|
|
107
|
-
array.setData(
|
|
127
|
+
array.setData(combinedData);
|
|
108
128
|
imageData.modified();
|
|
109
129
|
viewport.render();
|
|
110
130
|
}
|
|
@@ -113,7 +133,7 @@ export async function addVolumesAsIndependentComponents({ viewport, volumeInputs
|
|
|
113
133
|
if (evt.detail.viewportId !== viewport.id) {
|
|
114
134
|
return;
|
|
115
135
|
}
|
|
116
|
-
eventTarget.
|
|
136
|
+
eventTarget.removeEventListenerDebounced(Events.SEGMENTATION_DATA_MODIFIED, onSegmentationDataModified);
|
|
117
137
|
eventTarget.removeEventListener(Events.SEGMENTATION_REPRESENTATION_REMOVED, onSegmentationRepresentationRemoved);
|
|
118
138
|
const actorEntry = viewport.getActor(uid);
|
|
119
139
|
if (actorEntry) {
|
|
@@ -124,11 +144,22 @@ export async function addVolumesAsIndependentComponents({ viewport, volumeInputs
|
|
|
124
144
|
return;
|
|
125
145
|
}
|
|
126
146
|
actor.setMapper(oldMapper);
|
|
147
|
+
const pointData = sharedImageData.getPointData();
|
|
148
|
+
if (originalScalars) {
|
|
149
|
+
pointData.setScalars(originalScalars);
|
|
150
|
+
}
|
|
151
|
+
else {
|
|
152
|
+
pointData.removeArray('Pixels');
|
|
153
|
+
}
|
|
154
|
+
sharedImageData.modified();
|
|
127
155
|
actor.getProperty().setColorMixPreset(oldColorMixPreset);
|
|
128
156
|
actor
|
|
129
157
|
.getProperty()
|
|
130
158
|
.setForceNearestInterpolation(1, oldForceNearestInterpolation);
|
|
131
159
|
actor.getProperty().setIndependentComponents(oldIndependentComponents);
|
|
160
|
+
actor.getProperty().setUseLabelOutline(oldUseLabelOutline);
|
|
161
|
+
actor.getProperty().setLabelOutlineOpacity(oldLabelOutlineOpacity);
|
|
162
|
+
actor.getProperty().setLabelOutlineThickness(oldLabelOutlineThickness);
|
|
132
163
|
viewport.addActor({
|
|
133
164
|
...defaultActor,
|
|
134
165
|
});
|
package/dist/esm/version.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const version = "5.4.
|
|
1
|
+
export declare const version = "5.4.14";
|
package/dist/esm/version.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const version = '5.4.
|
|
1
|
+
export const version = '5.4.14';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cornerstonejs/tools",
|
|
3
|
-
"version": "5.4.
|
|
3
|
+
"version": "5.4.14",
|
|
4
4
|
"description": "Cornerstone3D Tools",
|
|
5
5
|
"types": "./dist/esm/index.d.ts",
|
|
6
6
|
"module": "./dist/esm/index.js",
|
|
@@ -126,11 +126,11 @@
|
|
|
126
126
|
"lodash.get": "4.4.2"
|
|
127
127
|
},
|
|
128
128
|
"devDependencies": {
|
|
129
|
-
"@cornerstonejs/core": "5.4.
|
|
129
|
+
"@cornerstonejs/core": "5.4.14",
|
|
130
130
|
"canvas": "3.2.0"
|
|
131
131
|
},
|
|
132
132
|
"peerDependencies": {
|
|
133
|
-
"@cornerstonejs/core": "5.4.
|
|
133
|
+
"@cornerstonejs/core": "5.4.14",
|
|
134
134
|
"@kitware/vtk.js": "35.5.3",
|
|
135
135
|
"@types/d3-array": "3.2.1",
|
|
136
136
|
"@types/d3-interpolate": "3.0.4",
|
|
@@ -149,5 +149,5 @@
|
|
|
149
149
|
"type": "individual",
|
|
150
150
|
"url": "https://ohif.org/donate"
|
|
151
151
|
},
|
|
152
|
-
"gitHead": "
|
|
152
|
+
"gitHead": "44424ece1744c4ee1fdd4c6304abc9005bf3bd39"
|
|
153
153
|
}
|