@cornerstonejs/core 3.10.30 → 3.11.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/esm/RenderingEngine/BaseVolumeViewport.d.ts +2 -0
- package/dist/esm/RenderingEngine/BaseVolumeViewport.js +44 -14
- package/dist/esm/RenderingEngine/StackViewport.js +5 -1
- package/dist/esm/RenderingEngine/Viewport.d.ts +1 -1
- package/dist/esm/RenderingEngine/Viewport.js +41 -3
- package/dist/esm/RenderingEngine/VolumeViewport.d.ts +0 -1
- package/dist/esm/RenderingEngine/VolumeViewport.js +4 -22
- package/dist/esm/cache/classes/BaseStreamingImageVolume.js +6 -5
- package/dist/esm/enums/Events.d.ts +2 -1
- package/dist/esm/enums/Events.js +1 -0
- package/dist/esm/types/Colormap.d.ts +1 -0
- package/dist/esm/types/EventTypes.d.ts +9 -1
- package/dist/esm/types/PixelDataTypedArray.d.ts +2 -2
- package/dist/esm/utilities/colormap.d.ts +3 -0
- package/dist/esm/utilities/colormap.js +76 -0
- package/dist/esm/utilities/getBufferConfiguration.js +3 -1
- package/dist/esm/utilities/getClosestImageId.js +4 -3
- package/dist/esm/utilities/getScalingParameters.js +10 -4
- package/package.json +2 -2
|
@@ -43,6 +43,7 @@ declare abstract class BaseVolumeViewport extends Viewport {
|
|
|
43
43
|
scroll(delta?: number): void;
|
|
44
44
|
abstract isInAcquisitionPlane(): boolean;
|
|
45
45
|
setViewReference(viewRef: ViewReference): void;
|
|
46
|
+
private setThreshold;
|
|
46
47
|
setProperties({ voiRange, VOILUTFunction, invert, colormap, preset, interpolationType, slabThickness, }?: VolumeViewportProperties, volumeId?: string, suppressEvents?: boolean): void;
|
|
47
48
|
resetToDefaultProperties(volumeId: string): void;
|
|
48
49
|
private setPreset;
|
|
@@ -72,6 +73,7 @@ declare abstract class BaseVolumeViewport extends Viewport {
|
|
|
72
73
|
worldToCanvas: (worldPos: Point3) => Point2;
|
|
73
74
|
hasImageURI: (imageURI: string) => boolean;
|
|
74
75
|
protected _getOrientationVectors(orientation: OrientationAxis | OrientationVectors): OrientationVectors;
|
|
76
|
+
protected _getAcquisitionPlaneOrientation(): OrientationVectors;
|
|
75
77
|
getSlabThickness(): number;
|
|
76
78
|
getIntensityFromWorld(point: Point3): number;
|
|
77
79
|
getImageIds: (volumeId?: string) => string[];
|
|
@@ -13,7 +13,7 @@ import * as colormapUtils from '../utilities/colormap';
|
|
|
13
13
|
import invertRgbTransferFunction from '../utilities/invertRgbTransferFunction';
|
|
14
14
|
import createSigmoidRGBTransferFunction from '../utilities/createSigmoidRGBTransferFunction';
|
|
15
15
|
import transformWorldToIndex from '../utilities/transformWorldToIndex';
|
|
16
|
-
import { findMatchingColormap } from '../utilities/colormap';
|
|
16
|
+
import { findMatchingColormap, updateOpacity as colormapUpdateOpacity, updateThreshold as colormapUpdateThreshold, } from '../utilities/colormap';
|
|
17
17
|
import { getTransferFunctionNodes } from '../utilities/transferFunctionUtils';
|
|
18
18
|
import createVolumeActor from './helpers/createVolumeActor';
|
|
19
19
|
import volumeNewImageEventDispatcher, { resetVolumeNewImageState, } from './helpers/volumeNewImageEventDispatcher';
|
|
@@ -334,19 +334,14 @@ class BaseVolumeViewport extends Viewport {
|
|
|
334
334
|
const { volumeActor } = applicableVolumeActorInfo;
|
|
335
335
|
const ofun = vtkPiecewiseFunction.newInstance();
|
|
336
336
|
if (typeof colormap.opacity === 'number') {
|
|
337
|
-
|
|
338
|
-
.getProperty()
|
|
339
|
-
.getRGBTransferFunction(0)
|
|
340
|
-
.getRange();
|
|
341
|
-
ofun.addPoint(range[0], colormap.opacity);
|
|
342
|
-
ofun.addPoint(range[1], colormap.opacity);
|
|
337
|
+
colormapUpdateOpacity(volumeActor, colormap.opacity);
|
|
343
338
|
}
|
|
344
339
|
else {
|
|
345
340
|
colormap.opacity.forEach(({ opacity, value }) => {
|
|
346
341
|
ofun.addPoint(value, opacity);
|
|
347
342
|
});
|
|
343
|
+
volumeActor.getProperty().setScalarOpacity(0, ofun);
|
|
348
344
|
}
|
|
349
|
-
volumeActor.getProperty().setScalarOpacity(0, ofun);
|
|
350
345
|
if (!this.viewportProperties.colormap) {
|
|
351
346
|
this.viewportProperties.colormap = {};
|
|
352
347
|
}
|
|
@@ -580,6 +575,18 @@ class BaseVolumeViewport extends Viewport {
|
|
|
580
575
|
throw new Error(`Incompatible view refs: ${refFrameOfReference}!==${this.getFrameOfReferenceUID()}`);
|
|
581
576
|
}
|
|
582
577
|
}
|
|
578
|
+
setThreshold(colormap, volumeId) {
|
|
579
|
+
const applicableVolumeActorInfo = this._getApplicableVolumeActor(volumeId);
|
|
580
|
+
if (!applicableVolumeActorInfo) {
|
|
581
|
+
return;
|
|
582
|
+
}
|
|
583
|
+
const { volumeActor } = applicableVolumeActorInfo;
|
|
584
|
+
colormapUpdateThreshold(volumeActor, colormap.threshold);
|
|
585
|
+
if (!this.viewportProperties.colormap) {
|
|
586
|
+
this.viewportProperties.colormap = {};
|
|
587
|
+
}
|
|
588
|
+
this.viewportProperties.colormap.threshold = colormap.threshold;
|
|
589
|
+
}
|
|
583
590
|
setProperties({ voiRange, VOILUTFunction, invert, colormap, preset, interpolationType, slabThickness, } = {}, volumeId, suppressEvents = false) {
|
|
584
591
|
if (this.globalDefaultProperties == null) {
|
|
585
592
|
this.setDefaultProperties({
|
|
@@ -600,6 +607,9 @@ class BaseVolumeViewport extends Viewport {
|
|
|
600
607
|
if (colormap?.opacity != null) {
|
|
601
608
|
this.setOpacity(colormap, volumeId);
|
|
602
609
|
}
|
|
610
|
+
if (colormap?.threshold != null) {
|
|
611
|
+
this.setThreshold(colormap, volumeId);
|
|
612
|
+
}
|
|
603
613
|
if (voiRange !== undefined) {
|
|
604
614
|
this.setVOI(voiRange, volumeId, suppressEvents);
|
|
605
615
|
}
|
|
@@ -862,14 +872,34 @@ class BaseVolumeViewport extends Viewport {
|
|
|
862
872
|
throw new Error('Invalid orientation object. It must contain viewPlaneNormal and viewUp');
|
|
863
873
|
}
|
|
864
874
|
}
|
|
865
|
-
else if (typeof orientation === 'string'
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
875
|
+
else if (typeof orientation === 'string') {
|
|
876
|
+
if (orientation === 'acquisition') {
|
|
877
|
+
return this._getAcquisitionPlaneOrientation();
|
|
878
|
+
}
|
|
879
|
+
else if (MPR_CAMERA_VALUES[orientation]) {
|
|
880
|
+
this.viewportProperties.orientation = orientation;
|
|
881
|
+
return MPR_CAMERA_VALUES[orientation];
|
|
882
|
+
}
|
|
869
883
|
}
|
|
870
|
-
|
|
871
|
-
|
|
884
|
+
throw new Error(`Invalid orientation: ${orientation}. Valid orientations are: ${Object.keys(MPR_CAMERA_VALUES).join(', ')}`);
|
|
885
|
+
}
|
|
886
|
+
_getAcquisitionPlaneOrientation() {
|
|
887
|
+
const actorEntry = this.getDefaultActor();
|
|
888
|
+
if (!actorEntry) {
|
|
889
|
+
return;
|
|
890
|
+
}
|
|
891
|
+
const volumeId = this.getVolumeId();
|
|
892
|
+
const imageVolume = cache.getVolume(volumeId);
|
|
893
|
+
if (!imageVolume) {
|
|
894
|
+
throw new Error(`imageVolume with id: ${volumeId} does not exist in cache`);
|
|
872
895
|
}
|
|
896
|
+
const { direction } = imageVolume;
|
|
897
|
+
const viewPlaneNormal = direction.slice(6, 9).map((x) => -x);
|
|
898
|
+
const viewUp = direction.slice(3, 6).map((x) => -x);
|
|
899
|
+
return {
|
|
900
|
+
viewPlaneNormal,
|
|
901
|
+
viewUp,
|
|
902
|
+
};
|
|
873
903
|
}
|
|
874
904
|
getSlabThickness() {
|
|
875
905
|
const actors = this.getActors();
|
|
@@ -1195,6 +1195,10 @@ class StackViewport extends Viewport {
|
|
|
1195
1195
|
origin = [0, 0, 0];
|
|
1196
1196
|
}
|
|
1197
1197
|
this._imageData.setOrigin(origin);
|
|
1198
|
+
const actor = this.getActor(this.id);
|
|
1199
|
+
if (actor) {
|
|
1200
|
+
actor.referencedId = image.imageId;
|
|
1201
|
+
}
|
|
1198
1202
|
updateVTKImageDataWithCornerstoneImage(this._imageData, image);
|
|
1199
1203
|
}
|
|
1200
1204
|
_loadAndDisplayImage(imageId, imageIdIndex) {
|
|
@@ -1462,7 +1466,7 @@ class StackViewport extends Viewport {
|
|
|
1462
1466
|
oldActors[0].actor = actor;
|
|
1463
1467
|
}
|
|
1464
1468
|
else {
|
|
1465
|
-
oldActors.unshift({ uid: this.id, actor });
|
|
1469
|
+
oldActors.unshift({ uid: this.id, actor, referencedId: image.imageId });
|
|
1466
1470
|
}
|
|
1467
1471
|
this.setActors(oldActors);
|
|
1468
1472
|
const { viewPlaneNormal, viewUp } = this._getCameraOrientation(direction);
|
|
@@ -76,7 +76,7 @@ declare class Viewport {
|
|
|
76
76
|
getActorUIDByIndex(index: number): string;
|
|
77
77
|
getActorByIndex(index: number): ActorEntry;
|
|
78
78
|
setActors(actors: ActorEntry[]): void;
|
|
79
|
-
_removeActor(actorUID: string):
|
|
79
|
+
_removeActor(actorUID: string): ActorEntry | undefined;
|
|
80
80
|
removeActors(actorUIDs: string[]): void;
|
|
81
81
|
addActors(actors: ActorEntry[], options?: {
|
|
82
82
|
resetCamera?: boolean;
|
|
@@ -211,22 +211,41 @@ class Viewport {
|
|
|
211
211
|
return this.getActors()[index];
|
|
212
212
|
}
|
|
213
213
|
setActors(actors) {
|
|
214
|
+
const currentActors = this.getActors();
|
|
214
215
|
this.removeAllActors();
|
|
215
216
|
this.addActors(actors, { resetCamera: true });
|
|
217
|
+
triggerEvent(this.element, Events.ACTORS_CHANGED, {
|
|
218
|
+
viewportId: this.id,
|
|
219
|
+
removedActors: currentActors,
|
|
220
|
+
addedActors: actors,
|
|
221
|
+
currentActors: actors,
|
|
222
|
+
});
|
|
216
223
|
}
|
|
217
224
|
_removeActor(actorUID) {
|
|
218
225
|
const actorEntry = this.getActor(actorUID);
|
|
219
226
|
if (!actorEntry) {
|
|
220
|
-
console.warn(`Actor ${actorUID} does not exist
|
|
227
|
+
console.warn(`Actor ${actorUID} does not exist in ${this.id}, can't remove`);
|
|
221
228
|
return;
|
|
222
229
|
}
|
|
223
230
|
const renderer = this.getRenderer();
|
|
224
|
-
renderer.
|
|
231
|
+
renderer.removeActor(actorEntry.actor);
|
|
225
232
|
this._actors.delete(actorUID);
|
|
233
|
+
return actorEntry;
|
|
226
234
|
}
|
|
227
235
|
removeActors(actorUIDs) {
|
|
236
|
+
const removedActors = [];
|
|
228
237
|
actorUIDs.forEach((actorUID) => {
|
|
229
|
-
this._removeActor(actorUID);
|
|
238
|
+
const removedActor = this._removeActor(actorUID);
|
|
239
|
+
if (removedActor) {
|
|
240
|
+
removedActors.push(removedActor);
|
|
241
|
+
}
|
|
242
|
+
});
|
|
243
|
+
const currentActors = this.getActors();
|
|
244
|
+
triggerEvent(this.element, Events.ACTORS_CHANGED, {
|
|
245
|
+
viewportId: this.id,
|
|
246
|
+
removedActors,
|
|
247
|
+
addedActors: [],
|
|
248
|
+
currentActors,
|
|
230
249
|
});
|
|
231
250
|
}
|
|
232
251
|
addActors(actors, options = {}) {
|
|
@@ -246,6 +265,12 @@ class Viewport {
|
|
|
246
265
|
this.setViewReference(prevViewRef);
|
|
247
266
|
this.setViewPresentation(prevViewPresentation);
|
|
248
267
|
}
|
|
268
|
+
triggerEvent(this.element, Events.ACTORS_CHANGED, {
|
|
269
|
+
viewportId: this.id,
|
|
270
|
+
removedActors: [],
|
|
271
|
+
addedActors: actors,
|
|
272
|
+
currentActors: this.getActors(),
|
|
273
|
+
});
|
|
249
274
|
}
|
|
250
275
|
addActor(actorEntry) {
|
|
251
276
|
const { uid: actorUID, actor } = actorEntry;
|
|
@@ -265,10 +290,23 @@ class Viewport {
|
|
|
265
290
|
renderer?.addActor(actor);
|
|
266
291
|
this._actors.set(actorUID, Object.assign({}, actorEntry));
|
|
267
292
|
this.updateCameraClippingPlanesAndRange();
|
|
293
|
+
triggerEvent(this.element, Events.ACTORS_CHANGED, {
|
|
294
|
+
viewportId: this.id,
|
|
295
|
+
removedActors: [],
|
|
296
|
+
addedActors: [actorEntry],
|
|
297
|
+
currentActors: this.getActors(),
|
|
298
|
+
});
|
|
268
299
|
}
|
|
269
300
|
removeAllActors() {
|
|
301
|
+
const currentActors = this.getActors();
|
|
270
302
|
this.getRenderer()?.removeAllViewProps();
|
|
271
303
|
this._actors = new Map();
|
|
304
|
+
triggerEvent(this.element, Events.ACTORS_CHANGED, {
|
|
305
|
+
viewportId: this.id,
|
|
306
|
+
removedActors: currentActors,
|
|
307
|
+
addedActors: [],
|
|
308
|
+
currentActors: [],
|
|
309
|
+
});
|
|
272
310
|
return;
|
|
273
311
|
}
|
|
274
312
|
resetCameraNoEvent() {
|
|
@@ -13,7 +13,6 @@ declare class VolumeViewport extends BaseVolumeViewport {
|
|
|
13
13
|
jumpToWorld(worldPos: Point3): boolean;
|
|
14
14
|
setOrientation(orientation: OrientationAxis | OrientationVectors, immediate?: boolean): void;
|
|
15
15
|
protected setCameraClippingRange(): void;
|
|
16
|
-
private _getAcquisitionPlaneOrientation;
|
|
17
16
|
private _setViewPlaneToAcquisitionPlane;
|
|
18
17
|
getBlendMode(filterActorUIDs?: string[]): BlendModes;
|
|
19
18
|
setBlendMode(blendMode: BlendModes, filterActorUIDs?: any[], immediate?: boolean): void;
|
|
@@ -131,11 +131,11 @@ class VolumeViewport extends BaseVolumeViewport {
|
|
|
131
131
|
setOrientation(orientation, immediate = true) {
|
|
132
132
|
let viewPlaneNormal, viewUp;
|
|
133
133
|
if (typeof orientation === 'string') {
|
|
134
|
-
if (
|
|
135
|
-
({ viewPlaneNormal, viewUp } =
|
|
134
|
+
if (orientation === OrientationAxis.ACQUISITION) {
|
|
135
|
+
({ viewPlaneNormal, viewUp } = super._getAcquisitionPlaneOrientation());
|
|
136
136
|
}
|
|
137
|
-
else if (orientation
|
|
138
|
-
({ viewPlaneNormal, viewUp } =
|
|
137
|
+
else if (MPR_CAMERA_VALUES[orientation]) {
|
|
138
|
+
({ viewPlaneNormal, viewUp } = MPR_CAMERA_VALUES[orientation]);
|
|
139
139
|
}
|
|
140
140
|
else {
|
|
141
141
|
throw new Error(`Invalid orientation: ${orientation}. Use Enums.OrientationAxis instead.`);
|
|
@@ -168,24 +168,6 @@ class VolumeViewport extends BaseVolumeViewport {
|
|
|
168
168
|
activeCamera.setClippingRange(RENDERING_DEFAULTS.MINIMUM_SLAB_THICKNESS, RENDERING_DEFAULTS.MAXIMUM_RAY_DISTANCE);
|
|
169
169
|
}
|
|
170
170
|
}
|
|
171
|
-
_getAcquisitionPlaneOrientation() {
|
|
172
|
-
const actorEntry = this.getDefaultActor();
|
|
173
|
-
if (!actorEntry) {
|
|
174
|
-
return;
|
|
175
|
-
}
|
|
176
|
-
const volumeId = this.getVolumeId();
|
|
177
|
-
const imageVolume = cache.getVolume(volumeId);
|
|
178
|
-
if (!imageVolume) {
|
|
179
|
-
throw new Error(`imageVolume with id: ${volumeId} does not exist in cache`);
|
|
180
|
-
}
|
|
181
|
-
const { direction } = imageVolume;
|
|
182
|
-
const viewPlaneNormal = direction.slice(6, 9).map((x) => -x);
|
|
183
|
-
const viewUp = direction.slice(3, 6).map((x) => -x);
|
|
184
|
-
return {
|
|
185
|
-
viewPlaneNormal,
|
|
186
|
-
viewUp,
|
|
187
|
-
};
|
|
188
|
-
}
|
|
189
171
|
_setViewPlaneToAcquisitionPlane(imageVolume) {
|
|
190
172
|
let viewPlaneNormal, viewUp;
|
|
191
173
|
if (imageVolume) {
|
|
@@ -206,11 +206,12 @@ export default class BaseStreamingImageVolume extends ImageVolume {
|
|
|
206
206
|
rescaleIntercept: modalityLutModule.rescaleIntercept,
|
|
207
207
|
modality: generalSeriesModule.modality,
|
|
208
208
|
};
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
209
|
+
const modality = scalingParameters.modality;
|
|
210
|
+
if (modality === 'PT' || modality === 'RTDOSE') {
|
|
211
|
+
const scalingFactor = metaData.get('scalingModule', imageId);
|
|
212
|
+
if (scalingFactor) {
|
|
213
|
+
this._addScalingToVolume(scalingFactor);
|
|
214
|
+
Object.assign(scalingParameters, scalingFactor);
|
|
214
215
|
}
|
|
215
216
|
}
|
|
216
217
|
const floatAfterScale = hasFloatScalingParameters(scalingParameters);
|
|
@@ -42,6 +42,7 @@ declare enum Events {
|
|
|
42
42
|
DYNAMIC_VOLUME_TIME_POINT_LOADED = "DYNAMIC_VOLUME_TIME_POINT_LOADED",
|
|
43
43
|
GEOMETRY_LOADED = "GEOMETRY_LOADED",
|
|
44
44
|
GEOMETRY_LOAD_PROGRESS = "GEOMETRY_LOAD_PROGRESS",
|
|
45
|
-
GEOMETRY_LOADED_FAILED = "GEOMETRY_LOADED_FAILED"
|
|
45
|
+
GEOMETRY_LOADED_FAILED = "GEOMETRY_LOADED_FAILED",
|
|
46
|
+
ACTORS_CHANGED = "CORNERSTONE_ACTORS_CHANGED"
|
|
46
47
|
}
|
|
47
48
|
export default Events;
|
package/dist/esm/enums/Events.js
CHANGED
|
@@ -44,5 +44,6 @@ var Events;
|
|
|
44
44
|
Events["GEOMETRY_LOADED"] = "GEOMETRY_LOADED";
|
|
45
45
|
Events["GEOMETRY_LOAD_PROGRESS"] = "GEOMETRY_LOAD_PROGRESS";
|
|
46
46
|
Events["GEOMETRY_LOADED_FAILED"] = "GEOMETRY_LOADED_FAILED";
|
|
47
|
+
Events["ACTORS_CHANGED"] = "CORNERSTONE_ACTORS_CHANGED";
|
|
47
48
|
})(Events || (Events = {}));
|
|
48
49
|
export default Events;
|
|
@@ -13,6 +13,7 @@ import type DisplayArea from './displayArea';
|
|
|
13
13
|
import type IImageCalibration from './IImageCalibration';
|
|
14
14
|
import type { ColormapPublic } from './Colormap';
|
|
15
15
|
import type IVolumeViewport from './IVolumeViewport';
|
|
16
|
+
import type { ActorEntry } from './IActor';
|
|
16
17
|
interface CameraModifiedEventDetail {
|
|
17
18
|
previousCamera: ICamera;
|
|
18
19
|
camera: ICamera;
|
|
@@ -184,4 +185,11 @@ type StackViewportNewStackEvent = CustomEventType<StackViewportNewStackEventDeta
|
|
|
184
185
|
type StackViewportScrollEvent = CustomEventType<StackViewportScrollEventDetail>;
|
|
185
186
|
type StackScrollOutOfBoundsEvent = CustomEventType<StackScrollOutOfBoundsEventDetail>;
|
|
186
187
|
type VolumeScrollOutOfBoundsEvent = CustomEventType<VolumeScrollOutOfBoundsEventDetail>;
|
|
187
|
-
|
|
188
|
+
interface ActorsChangedEventDetail {
|
|
189
|
+
viewportId: string;
|
|
190
|
+
removedActors: ActorEntry[];
|
|
191
|
+
addedActors: ActorEntry[];
|
|
192
|
+
currentActors: ActorEntry[];
|
|
193
|
+
}
|
|
194
|
+
type ActorsChangedEvent = CustomEventType<ActorsChangedEventDetail>;
|
|
195
|
+
export type { VolumeScrollOutOfBoundsEventDetail, VolumeScrollOutOfBoundsEvent, ActorsChangedEventDetail, ActorsChangedEvent, CameraModifiedEventDetail, CameraModifiedEvent, VoiModifiedEvent, VoiModifiedEventDetail, ColormapModifiedEvent, ColormapModifiedEventDetail, DisplayAreaModifiedEvent, DisplayAreaModifiedEventDetail, ElementDisabledEvent, ElementDisabledEventDetail, ElementEnabledEvent, ElementEnabledEventDetail, ImageRenderedEventDetail, ImageRenderedEvent, ImageVolumeModifiedEvent, ImageVolumeModifiedEventDetail, ImageVolumeLoadingCompletedEvent, ImageVolumeLoadingCompletedEventDetail, ImageLoadedEvent, ImageLoadedEventDetail, ImageLoadedFailedEventDetail, ImageLoadedFailedEvent, VolumeLoadedEvent, VolumeLoadedEventDetail, VolumeLoadedFailedEvent, VolumeLoadedFailedEventDetail, ImageCacheImageAddedEvent, ImageCacheImageAddedEventDetail, ImageCacheImageRemovedEvent, ImageCacheImageRemovedEventDetail, VolumeCacheVolumeAddedEvent, VolumeCacheVolumeAddedEventDetail, VolumeCacheVolumeRemovedEvent, VolumeCacheVolumeRemovedEventDetail, StackNewImageEvent, StackNewImageEventDetail, PreStackNewImageEvent, PreStackNewImageEventDetail, ImageSpacingCalibratedEvent, ImageSpacingCalibratedEventDetail, VolumeNewImageEvent, VolumeNewImageEventDetail, StackViewportNewStackEvent, StackViewportNewStackEventDetail, StackViewportScrollEvent, StackViewportScrollEventDetail, StackScrollOutOfBoundsEvent, StackScrollOutOfBoundsEventDetail, CameraResetEvent, CameraResetEventDetail, };
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export type PixelDataTypedArray = Float32Array | Int16Array | Uint16Array | Uint8Array | Int8Array | Uint8ClampedArray;
|
|
2
|
-
export type PixelDataTypedArrayString = 'Float32Array' | 'Int16Array' | 'Uint16Array' | 'Uint8Array' | 'Int8Array' | 'Uint8ClampedArray' | 'none';
|
|
1
|
+
export type PixelDataTypedArray = Float32Array | Int16Array | Uint16Array | Uint8Array | Int8Array | Uint8ClampedArray | Uint32Array | Int32Array;
|
|
2
|
+
export type PixelDataTypedArrayString = 'Float32Array' | 'Int16Array' | 'Uint16Array' | 'Uint8Array' | 'Int8Array' | 'Uint8ClampedArray' | 'Uint32Array' | 'Int32Array' | 'none';
|
|
@@ -3,4 +3,7 @@ declare function registerColormap(colormap: ColormapRegistration): void;
|
|
|
3
3
|
declare function getColormap(name: any): any;
|
|
4
4
|
declare function getColormapNames(): any[];
|
|
5
5
|
declare function findMatchingColormap(rgbPoints: any, actor: any): ColormapPublic | null;
|
|
6
|
+
export declare function setColorMapTransferFunctionForVolumeActor(volumeInfo: any): void;
|
|
7
|
+
export declare function updateOpacity(volumeActor: any, newOpacity: any): void;
|
|
8
|
+
export declare function updateThreshold(volumeActor: any, newThreshold: any): void;
|
|
6
9
|
export { getColormap, getColormapNames, registerColormap, findMatchingColormap, };
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import vtkColorMaps from '@kitware/vtk.js/Rendering/Core/ColorTransferFunction/ColorMaps';
|
|
2
|
+
import vtkColorTransferFunction from '@kitware/vtk.js/Rendering/Core/ColorTransferFunction';
|
|
3
|
+
import vtkPiecewiseFunction from '@kitware/vtk.js/Common/DataModel/PiecewiseFunction';
|
|
2
4
|
import isEqual from './isEqual';
|
|
3
5
|
import { actorIsA } from './actorCheck';
|
|
4
6
|
const _colormaps = new Map();
|
|
@@ -54,4 +56,78 @@ function findMatchingColormap(rgbPoints, actor) {
|
|
|
54
56
|
opacity,
|
|
55
57
|
};
|
|
56
58
|
}
|
|
59
|
+
export function setColorMapTransferFunctionForVolumeActor(volumeInfo) {
|
|
60
|
+
const { volumeActor, preset, opacity = 0.9, threshold = null, colorRange = [0, 5], } = volumeInfo;
|
|
61
|
+
const mapper = volumeActor.getMapper();
|
|
62
|
+
mapper.setSampleDistance(1.0);
|
|
63
|
+
const cfun = vtkColorTransferFunction.newInstance();
|
|
64
|
+
const presetToUse = preset || vtkColorMaps.getPresetByName('hsv');
|
|
65
|
+
cfun.applyColorMap(presetToUse);
|
|
66
|
+
cfun.setMappingRange(colorRange[0], colorRange[1]);
|
|
67
|
+
volumeActor.getProperty().setRGBTransferFunction(0, cfun);
|
|
68
|
+
updateOpacityWithThreshold(volumeActor, opacity, threshold);
|
|
69
|
+
}
|
|
70
|
+
export function updateOpacity(volumeActor, newOpacity) {
|
|
71
|
+
const currentThreshold = getThresholdValue(volumeActor);
|
|
72
|
+
updateOpacityWithThreshold(volumeActor, newOpacity, currentThreshold);
|
|
73
|
+
}
|
|
74
|
+
export function updateThreshold(volumeActor, newThreshold) {
|
|
75
|
+
const currentOpacity = getMaxOpacity(volumeActor);
|
|
76
|
+
updateOpacityWithThreshold(volumeActor, currentOpacity, newThreshold);
|
|
77
|
+
}
|
|
78
|
+
function updateOpacityWithThreshold(volumeActor, opacity, threshold) {
|
|
79
|
+
const transferFunction = volumeActor.getProperty().getRGBTransferFunction(0);
|
|
80
|
+
const range = transferFunction.getRange();
|
|
81
|
+
const ofun = vtkPiecewiseFunction.newInstance();
|
|
82
|
+
if (threshold !== null) {
|
|
83
|
+
const delta = Math.abs(range[1] - range[0]) * 0.001;
|
|
84
|
+
const thresholdValue = Math.max(range[0], Math.min(range[1], threshold));
|
|
85
|
+
ofun.addPoint(range[0], 0);
|
|
86
|
+
ofun.addPoint(thresholdValue - delta, 0);
|
|
87
|
+
ofun.addPoint(thresholdValue, opacity);
|
|
88
|
+
ofun.addPoint(range[1], opacity);
|
|
89
|
+
}
|
|
90
|
+
else {
|
|
91
|
+
ofun.addPoint(range[0], opacity);
|
|
92
|
+
ofun.addPoint(range[1], opacity);
|
|
93
|
+
}
|
|
94
|
+
volumeActor.getProperty().setScalarOpacity(0, ofun);
|
|
95
|
+
}
|
|
96
|
+
function getThresholdValue(volumeActor) {
|
|
97
|
+
const opacityFunction = volumeActor.getProperty().getScalarOpacity(0);
|
|
98
|
+
if (!opacityFunction) {
|
|
99
|
+
return null;
|
|
100
|
+
}
|
|
101
|
+
const dataArray = opacityFunction.getDataPointer();
|
|
102
|
+
if (!dataArray || dataArray.length <= 4) {
|
|
103
|
+
return null;
|
|
104
|
+
}
|
|
105
|
+
for (let i = 0; i < dataArray.length - 2; i += 2) {
|
|
106
|
+
const x1 = dataArray[i];
|
|
107
|
+
const y1 = dataArray[i + 1];
|
|
108
|
+
const x2 = dataArray[i + 2];
|
|
109
|
+
const y2 = dataArray[i + 3];
|
|
110
|
+
if (y1 === 0 && y2 > 0) {
|
|
111
|
+
return x2;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
return null;
|
|
115
|
+
}
|
|
116
|
+
function getMaxOpacity(volumeActor) {
|
|
117
|
+
const opacityFunction = volumeActor.getProperty().getScalarOpacity(0);
|
|
118
|
+
if (!opacityFunction) {
|
|
119
|
+
return 1.0;
|
|
120
|
+
}
|
|
121
|
+
const dataArray = opacityFunction.getDataPointer();
|
|
122
|
+
if (!dataArray || dataArray.length === 0) {
|
|
123
|
+
return 1.0;
|
|
124
|
+
}
|
|
125
|
+
let maxOpacity = 0;
|
|
126
|
+
for (let i = 1; i < dataArray.length; i += 2) {
|
|
127
|
+
if (dataArray[i] > maxOpacity) {
|
|
128
|
+
maxOpacity = dataArray[i];
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
return maxOpacity;
|
|
132
|
+
}
|
|
57
133
|
export { getColormap, getColormapNames, registerColormap, findMatchingColormap, };
|
|
@@ -4,6 +4,8 @@ function getConstructorFromType(bufferType, isVolumeBuffer) {
|
|
|
4
4
|
return Float32Array;
|
|
5
5
|
case 'Uint8Array':
|
|
6
6
|
return Uint8Array;
|
|
7
|
+
case 'Uint32Array':
|
|
8
|
+
return Uint32Array;
|
|
7
9
|
case 'Uint16Array':
|
|
8
10
|
case 'Int16Array':
|
|
9
11
|
if (!isVolumeBuffer) {
|
|
@@ -15,7 +17,7 @@ function getConstructorFromType(bufferType, isVolumeBuffer) {
|
|
|
15
17
|
}
|
|
16
18
|
default:
|
|
17
19
|
if (bufferType) {
|
|
18
|
-
throw new Error('TargetBuffer should be Float32Array, Uint8Array, Uint16Array, or
|
|
20
|
+
throw new Error('TargetBuffer should be Float32Array, Uint8Array, Uint16Array, Int16Array, or Uint32Array');
|
|
19
21
|
}
|
|
20
22
|
else {
|
|
21
23
|
return Float32Array;
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { vec3 } from 'gl-matrix';
|
|
2
2
|
import * as metaData from '../metaData';
|
|
3
|
+
import { coreLog } from './logger';
|
|
3
4
|
import getSpacingInNormalDirection from './getSpacingInNormalDirection';
|
|
4
5
|
import { EPSILON } from '../constants';
|
|
6
|
+
const log = coreLog.getLogger('utilities', 'getClosestImageId');
|
|
5
7
|
export default function getClosestImageId(imageVolume, worldPos, viewPlaneNormal, options) {
|
|
6
8
|
const { direction, spacing, imageIds } = imageVolume;
|
|
7
9
|
const { ignoreSpacing = false } = options || {};
|
|
@@ -11,7 +13,6 @@ export default function getClosestImageId(imageVolume, worldPos, viewPlaneNormal
|
|
|
11
13
|
const kVector = direction.slice(6, 9);
|
|
12
14
|
const dotProduct = vec3.dot(kVector, viewPlaneNormal);
|
|
13
15
|
if (Math.abs(dotProduct) < 1 - EPSILON) {
|
|
14
|
-
console.debug('View plane normal is not parallel to the image scan axis. Unable to find closest imageId.');
|
|
15
16
|
return;
|
|
16
17
|
}
|
|
17
18
|
let halfSpacingInNormalDirection;
|
|
@@ -25,7 +26,7 @@ export default function getClosestImageId(imageVolume, worldPos, viewPlaneNormal
|
|
|
25
26
|
const imageId = imageIds[i];
|
|
26
27
|
const imagePlaneModule = metaData.get('imagePlaneModule', imageId);
|
|
27
28
|
if (!imagePlaneModule?.imagePositionPatient) {
|
|
28
|
-
|
|
29
|
+
log.warn(`Missing imagePositionPatient for imageId: ${imageId}`);
|
|
29
30
|
continue;
|
|
30
31
|
}
|
|
31
32
|
const { imagePositionPatient } = imagePlaneModule;
|
|
@@ -46,7 +47,7 @@ export default function getClosestImageId(imageVolume, worldPos, viewPlaneNormal
|
|
|
46
47
|
}
|
|
47
48
|
}
|
|
48
49
|
if (closestImageId === undefined) {
|
|
49
|
-
|
|
50
|
+
log.warn('No imageId found within the specified criteria (half spacing or absolute closest).');
|
|
50
51
|
}
|
|
51
52
|
return closestImageId;
|
|
52
53
|
}
|
|
@@ -8,13 +8,19 @@ export default function getScalingParameters(imageId) {
|
|
|
8
8
|
rescaleIntercept: modalityLutModule.rescaleIntercept ?? 0,
|
|
9
9
|
modality,
|
|
10
10
|
};
|
|
11
|
-
const
|
|
11
|
+
const scalingModules = metaData.get('scalingModule', imageId) || {};
|
|
12
12
|
return {
|
|
13
13
|
...scalingParameters,
|
|
14
14
|
...(modality === 'PT' && {
|
|
15
|
-
suvbw:
|
|
16
|
-
suvbsa:
|
|
17
|
-
suvlbm:
|
|
15
|
+
suvbw: scalingModules.suvbw,
|
|
16
|
+
suvbsa: scalingModules.suvbsa,
|
|
17
|
+
suvlbm: scalingModules.suvlbm,
|
|
18
|
+
}),
|
|
19
|
+
...(modality === 'RTDOSE' && {
|
|
20
|
+
doseGridScaling: scalingModules.DoseGridScaling,
|
|
21
|
+
doseSummation: scalingModules.DoseSummation,
|
|
22
|
+
doseType: scalingModules.DoseType,
|
|
23
|
+
doseUnit: scalingModules.DoseUnit,
|
|
18
24
|
}),
|
|
19
25
|
};
|
|
20
26
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cornerstonejs/core",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.11.0",
|
|
4
4
|
"description": "Cornerstone3D Core",
|
|
5
5
|
"module": "./dist/esm/index.js",
|
|
6
6
|
"types": "./dist/esm/index.d.ts",
|
|
@@ -91,5 +91,5 @@
|
|
|
91
91
|
"type": "individual",
|
|
92
92
|
"url": "https://ohif.org/donate"
|
|
93
93
|
},
|
|
94
|
-
"gitHead": "
|
|
94
|
+
"gitHead": "e051da49a8fb4e7559861e9d3de08fdeb108c53b"
|
|
95
95
|
}
|