@cornerstonejs/core 3.10.31 → 3.11.1

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.
@@ -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
- const range = volumeActor
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
- MPR_CAMERA_VALUES[orientation]) {
867
- this.viewportProperties.orientation = orientation;
868
- return MPR_CAMERA_VALUES[orientation];
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
- else {
871
- throw new Error(`Invalid orientation: ${orientation}. Valid orientations are: ${Object.keys(MPR_CAMERA_VALUES).join(', ')}`);
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): void;
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 for this viewport`);
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.removeViewProp(actorEntry.actor);
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 (MPR_CAMERA_VALUES[orientation]) {
135
- ({ viewPlaneNormal, viewUp } = MPR_CAMERA_VALUES[orientation]);
134
+ if (orientation === OrientationAxis.ACQUISITION) {
135
+ ({ viewPlaneNormal, viewUp } = super._getAcquisitionPlaneOrientation());
136
136
  }
137
- else if (orientation === 'acquisition') {
138
- ({ viewPlaneNormal, viewUp } = this._getAcquisitionPlaneOrientation());
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
- if (scalingParameters.modality === 'PT') {
210
- const suvFactor = metaData.get('scalingModule', imageId);
211
- if (suvFactor) {
212
- this._addScalingToVolume(suvFactor);
213
- scalingParameters.suvbw = suvFactor.suvbw;
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;
@@ -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;
@@ -12,5 +12,6 @@ interface OpacityMapping {
12
12
  interface ColormapPublic {
13
13
  name?: string;
14
14
  opacity?: OpacityMapping[] | number;
15
+ threshold?: number;
15
16
  }
16
17
  export type { ColormapRegistration, ColormapPublic, OpacityMapping };
@@ -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
- export type { VolumeScrollOutOfBoundsEventDetail, VolumeScrollOutOfBoundsEvent, 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, };
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 Int16Array');
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
- console.warn(`Missing imagePositionPatient for imageId: ${imageId}`);
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
- console.debug('No imageId found within the specified criteria (half spacing or absolute closest).');
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 suvFactor = metaData.get('scalingModule', imageId) || {};
11
+ const scalingModules = metaData.get('scalingModule', imageId) || {};
12
12
  return {
13
13
  ...scalingParameters,
14
14
  ...(modality === 'PT' && {
15
- suvbw: suvFactor.suvbw,
16
- suvbsa: suvFactor.suvbsa,
17
- suvlbm: suvFactor.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.10.31",
3
+ "version": "3.11.1",
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": "f7d656d8b175c3ff00b145cdd5ceedf910afeda1"
94
+ "gitHead": "9e71e94884bd1c8734911b98ac67a5676fcaaecb"
95
95
  }