@cornerstonejs/core 2.0.0-beta.1 → 2.0.0-beta.3

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.
Files changed (124) hide show
  1. package/dist/cjs/RenderingEngine/BaseVolumeViewport.d.ts +4 -1
  2. package/dist/cjs/RenderingEngine/BaseVolumeViewport.js +28 -2
  3. package/dist/cjs/RenderingEngine/BaseVolumeViewport.js.map +1 -1
  4. package/dist/cjs/RenderingEngine/RenderingEngine.js.map +1 -1
  5. package/dist/cjs/RenderingEngine/StackViewport.d.ts +1 -0
  6. package/dist/cjs/RenderingEngine/StackViewport.js +17 -8
  7. package/dist/cjs/RenderingEngine/StackViewport.js.map +1 -1
  8. package/dist/cjs/RenderingEngine/VolumeViewport.d.ts +2 -0
  9. package/dist/cjs/RenderingEngine/VolumeViewport.js +30 -0
  10. package/dist/cjs/RenderingEngine/VolumeViewport.js.map +1 -1
  11. package/dist/cjs/RenderingEngine/VolumeViewport3D.d.ts +1 -0
  12. package/dist/cjs/RenderingEngine/VolumeViewport3D.js +3 -0
  13. package/dist/cjs/RenderingEngine/VolumeViewport3D.js.map +1 -1
  14. package/dist/cjs/RenderingEngine/helpers/cpuFallback/rendering/getVOILut.js +3 -1
  15. package/dist/cjs/RenderingEngine/helpers/cpuFallback/rendering/getVOILut.js.map +1 -1
  16. package/dist/cjs/RenderingEngine/helpers/cpuFallback/rendering/renderColorImage.js +3 -2
  17. package/dist/cjs/RenderingEngine/helpers/cpuFallback/rendering/renderColorImage.js.map +1 -1
  18. package/dist/cjs/RenderingEngine/helpers/setVolumesForViewports.js.map +1 -1
  19. package/dist/cjs/Settings.js +4 -2
  20. package/dist/cjs/Settings.js.map +1 -1
  21. package/dist/cjs/cache/cache.d.ts +3 -1
  22. package/dist/cjs/cache/cache.js +12 -7
  23. package/dist/cjs/cache/cache.js.map +1 -1
  24. package/dist/cjs/cache/classes/ImageVolume.js +2 -3
  25. package/dist/cjs/cache/classes/ImageVolume.js.map +1 -1
  26. package/dist/cjs/init.d.ts +1 -1
  27. package/dist/cjs/init.js +1 -1
  28. package/dist/cjs/init.js.map +1 -1
  29. package/dist/cjs/loaders/volumeLoader.d.ts +1 -1
  30. package/dist/cjs/loaders/volumeLoader.js.map +1 -1
  31. package/dist/cjs/requestPool/requestPoolManager.js +1 -1
  32. package/dist/cjs/requestPool/requestPoolManager.js.map +1 -1
  33. package/dist/cjs/types/AffineMatrix.d.ts +27 -0
  34. package/dist/cjs/types/AffineMatrix.js +3 -0
  35. package/dist/cjs/types/AffineMatrix.js.map +1 -0
  36. package/dist/cjs/types/IImage.d.ts +3 -0
  37. package/dist/cjs/types/IVolumeViewport.d.ts +2 -0
  38. package/dist/cjs/types/Mat3.d.ts +1 -11
  39. package/dist/cjs/types/ViewportProperties.d.ts +2 -1
  40. package/dist/cjs/types/index.d.ts +2 -1
  41. package/dist/cjs/utilities/calculateViewportsSpatialRegistration.js +9 -14
  42. package/dist/cjs/utilities/calculateViewportsSpatialRegistration.js.map +1 -1
  43. package/dist/cjs/utilities/getClosestStackImageIndexForPoint.js +12 -6
  44. package/dist/cjs/utilities/getClosestStackImageIndexForPoint.js.map +1 -1
  45. package/dist/cjs/utilities/getRuntimeId.js +2 -1
  46. package/dist/cjs/utilities/getRuntimeId.js.map +1 -1
  47. package/dist/cjs/utilities/windowLevel.js +4 -4
  48. package/dist/cjs/utilities/windowLevel.js.map +1 -1
  49. package/dist/esm/RenderingEngine/BaseVolumeViewport.d.ts +4 -1
  50. package/dist/esm/RenderingEngine/BaseVolumeViewport.js +28 -2
  51. package/dist/esm/RenderingEngine/BaseVolumeViewport.js.map +1 -1
  52. package/dist/esm/RenderingEngine/RenderingEngine.js.map +1 -1
  53. package/dist/esm/RenderingEngine/StackViewport.d.ts +1 -0
  54. package/dist/esm/RenderingEngine/StackViewport.js +17 -8
  55. package/dist/esm/RenderingEngine/StackViewport.js.map +1 -1
  56. package/dist/esm/RenderingEngine/VolumeViewport.d.ts +2 -0
  57. package/dist/esm/RenderingEngine/VolumeViewport.js +32 -2
  58. package/dist/esm/RenderingEngine/VolumeViewport.js.map +1 -1
  59. package/dist/esm/RenderingEngine/VolumeViewport3D.d.ts +1 -0
  60. package/dist/esm/RenderingEngine/VolumeViewport3D.js +3 -0
  61. package/dist/esm/RenderingEngine/VolumeViewport3D.js.map +1 -1
  62. package/dist/esm/RenderingEngine/helpers/cpuFallback/rendering/getVOILut.js +3 -1
  63. package/dist/esm/RenderingEngine/helpers/cpuFallback/rendering/getVOILut.js.map +1 -1
  64. package/dist/esm/RenderingEngine/helpers/cpuFallback/rendering/renderColorImage.js +3 -2
  65. package/dist/esm/RenderingEngine/helpers/cpuFallback/rendering/renderColorImage.js.map +1 -1
  66. package/dist/esm/RenderingEngine/helpers/setVolumesForViewports.js.map +1 -1
  67. package/dist/esm/Settings.js +4 -2
  68. package/dist/esm/Settings.js.map +1 -1
  69. package/dist/esm/cache/cache.d.ts +3 -1
  70. package/dist/esm/cache/cache.js +12 -7
  71. package/dist/esm/cache/cache.js.map +1 -1
  72. package/dist/esm/cache/classes/ImageVolume.js +2 -3
  73. package/dist/esm/cache/classes/ImageVolume.js.map +1 -1
  74. package/dist/esm/init.d.ts +1 -1
  75. package/dist/esm/init.js +1 -1
  76. package/dist/esm/init.js.map +1 -1
  77. package/dist/esm/loaders/volumeLoader.d.ts +1 -1
  78. package/dist/esm/loaders/volumeLoader.js.map +1 -1
  79. package/dist/esm/requestPool/requestPoolManager.js +1 -1
  80. package/dist/esm/requestPool/requestPoolManager.js.map +1 -1
  81. package/dist/esm/types/AffineMatrix.d.ts +27 -0
  82. package/dist/esm/types/AffineMatrix.js +2 -0
  83. package/dist/esm/types/AffineMatrix.js.map +1 -0
  84. package/dist/esm/types/IImage.d.ts +3 -0
  85. package/dist/esm/types/IVolumeViewport.d.ts +2 -0
  86. package/dist/esm/types/Mat3.d.ts +1 -11
  87. package/dist/esm/types/ViewportProperties.d.ts +2 -1
  88. package/dist/esm/types/index.d.ts +2 -1
  89. package/dist/esm/utilities/calculateViewportsSpatialRegistration.js +9 -14
  90. package/dist/esm/utilities/calculateViewportsSpatialRegistration.js.map +1 -1
  91. package/dist/esm/utilities/getClosestStackImageIndexForPoint.js +12 -6
  92. package/dist/esm/utilities/getClosestStackImageIndexForPoint.js.map +1 -1
  93. package/dist/esm/utilities/getRuntimeId.js +2 -1
  94. package/dist/esm/utilities/getRuntimeId.js.map +1 -1
  95. package/dist/esm/utilities/windowLevel.js +4 -4
  96. package/dist/esm/utilities/windowLevel.js.map +1 -1
  97. package/dist/umd/index.js +1 -1
  98. package/dist/umd/index.js.map +1 -1
  99. package/package.json +2 -2
  100. package/src/RenderingEngine/BaseVolumeViewport.ts +55 -1
  101. package/src/RenderingEngine/RenderingEngine.ts +1 -0
  102. package/src/RenderingEngine/StackViewport.ts +25 -9
  103. package/src/RenderingEngine/Viewport.ts +1 -1
  104. package/src/RenderingEngine/VolumeViewport.ts +53 -2
  105. package/src/RenderingEngine/VolumeViewport3D.ts +4 -0
  106. package/src/RenderingEngine/helpers/cpuFallback/rendering/getVOILut.ts +9 -1
  107. package/src/RenderingEngine/helpers/cpuFallback/rendering/renderColorImage.ts +5 -3
  108. package/src/RenderingEngine/helpers/setVolumesForViewports.ts +3 -1
  109. package/src/Settings.ts +6 -2
  110. package/src/cache/cache.ts +33 -18
  111. package/src/cache/classes/ImageVolume.ts +3 -3
  112. package/src/init.ts +1 -1
  113. package/src/loaders/volumeLoader.ts +2 -2
  114. package/src/requestPool/requestPoolManager.ts +1 -1
  115. package/src/types/AffineMatrix.ts +8 -0
  116. package/src/types/IImage.ts +4 -0
  117. package/src/types/IVolumeViewport.ts +8 -0
  118. package/src/types/Mat3.ts +3 -11
  119. package/src/types/ViewportProperties.ts +3 -1
  120. package/src/types/index.ts +2 -0
  121. package/src/utilities/calculateViewportsSpatialRegistration.ts +21 -28
  122. package/src/utilities/getClosestStackImageIndexForPoint.ts +18 -6
  123. package/src/utilities/getRuntimeId.ts +3 -1
  124. package/src/utilities/windowLevel.ts +13 -4
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cornerstonejs/core",
3
- "version": "2.0.0-beta.1",
3
+ "version": "2.0.0-beta.3",
4
4
  "description": "",
5
5
  "main": "dist/umd/index.js",
6
6
  "types": "dist/esm/index.d.ts",
@@ -46,5 +46,5 @@
46
46
  "type": "individual",
47
47
  "url": "https://ohif.org/donate"
48
48
  },
49
- "gitHead": "8cb0ace8dd10393a32f88507ef911ce823b0069d"
49
+ "gitHead": "d78cf780d4383a61ea0a9762bafa4104666757a4"
50
50
  }
@@ -12,6 +12,7 @@ import {
12
12
  import {
13
13
  BlendModes,
14
14
  Events,
15
+ InterpolationType,
15
16
  OrientationAxis,
16
17
  ViewportStatus,
17
18
  VOILUTFunctionType,
@@ -367,6 +368,23 @@ abstract class BaseVolumeViewport extends Viewport implements IVolumeViewport {
367
368
  return newRGBTransferFunction;
368
369
  }
369
370
 
371
+ private setInterpolationType(
372
+ interpolationType: InterpolationType,
373
+ volumeId?: string
374
+ ) {
375
+ const applicableVolumeActorInfo = this._getApplicableVolumeActor(volumeId);
376
+
377
+ if (!applicableVolumeActorInfo) {
378
+ return;
379
+ }
380
+
381
+ const { volumeActor } = applicableVolumeActorInfo;
382
+ const volumeProperty = volumeActor.getProperty();
383
+
384
+ // @ts-ignore
385
+ volumeProperty.setInterpolationType(interpolationType);
386
+ }
387
+
370
388
  /**
371
389
  * Sets the properties for the volume viewport on the volume
372
390
  * (if fusion, it sets it for the first volume in the fusion)
@@ -449,6 +467,7 @@ abstract class BaseVolumeViewport extends Viewport implements IVolumeViewport {
449
467
  invert,
450
468
  colormap,
451
469
  preset,
470
+ interpolationType,
452
471
  }: VolumeViewportProperties = {},
453
472
  volumeId?: string,
454
473
  suppressEvents = false
@@ -467,6 +486,10 @@ abstract class BaseVolumeViewport extends Viewport implements IVolumeViewport {
467
486
  this.setVOI(voiRange, volumeId, suppressEvents);
468
487
  }
469
488
 
489
+ if (typeof interpolationType !== 'undefined') {
490
+ this.setInterpolationType(interpolationType);
491
+ }
492
+
470
493
  if (VOILUTFunction !== undefined) {
471
494
  this.setVOILUTFunction(VOILUTFunction, volumeId, suppressEvents);
472
495
  }
@@ -519,7 +542,9 @@ abstract class BaseVolumeViewport extends Viewport implements IVolumeViewport {
519
542
  const volumeActor = actorEntry.actor as vtkVolume;
520
543
  const volumeId = actorEntry.uid;
521
544
  const volume = cache.getVolume(volumeId);
522
- if (!volume) return null;
545
+ if (!volume) {
546
+ return null;
547
+ }
523
548
  const cfun = volumeActor.getProperty().getRGBTransferFunction(0);
524
549
  const [lower, upper] =
525
550
  this.VOILUTFunction === 'SIGMOID'
@@ -847,6 +872,8 @@ abstract class BaseVolumeViewport extends Viewport implements IVolumeViewport {
847
872
  *
848
873
  */
849
874
  private _setVolumeActors(volumeActorEntries: Array<ActorEntry>): void {
875
+ // New volume actors implies resetting the inverted flag (i.e. like starting from scratch).
876
+ this.inverted = false;
850
877
  this.setActors(volumeActorEntries);
851
878
  }
852
879
 
@@ -1078,6 +1105,31 @@ abstract class BaseVolumeViewport extends Viewport implements IVolumeViewport {
1078
1105
  return volume.getScalarData()[voxelIndex];
1079
1106
  }
1080
1107
 
1108
+ /**
1109
+ * Returns the list of image Ids for the current viewport
1110
+ *
1111
+ * @param volumeId - volumeId
1112
+ * @returns list of strings for image Ids
1113
+ */
1114
+ public getImageIds = (volumeId?: string): Array<string> => {
1115
+ const applicableVolumeActorInfo = this._getApplicableVolumeActor(volumeId);
1116
+
1117
+ if (!applicableVolumeActorInfo) {
1118
+ throw new Error(`No actor found for the given volumeId: ${volumeId}`);
1119
+ }
1120
+
1121
+ const volumeIdToUse = applicableVolumeActorInfo.volumeId;
1122
+
1123
+ const imageVolume = cache.getVolume(volumeIdToUse);
1124
+ if (!imageVolume) {
1125
+ throw new Error(
1126
+ `imageVolume with id: ${volumeIdToUse} does not exist in cache`
1127
+ );
1128
+ }
1129
+
1130
+ return imageVolume.imageIds;
1131
+ };
1132
+
1081
1133
  abstract getCurrentImageIdIndex(): number;
1082
1134
 
1083
1135
  abstract getCurrentImageId(): string;
@@ -1092,6 +1144,8 @@ abstract class BaseVolumeViewport extends Viewport implements IVolumeViewport {
1092
1144
  slabThickness: number,
1093
1145
  filterActorUIDs?: Array<string>
1094
1146
  ): void;
1147
+
1148
+ abstract resetProperties(volumeId?: string): void;
1095
1149
  }
1096
1150
 
1097
1151
  export default BaseVolumeViewport;
@@ -54,6 +54,7 @@ const VIEWPORT_MIN_SIZE = 2;
54
54
  * trigger a render on a specific viewport(s). Each viewport also has a `.render` method which can be used to trigger a render on that
55
55
  * viewport.
56
56
  *
57
+ *
57
58
  * Rendering engine uses `detect-gpu` external library to detect if GPU is available and
58
59
  * it has minimum requirement to be able to render a volume with vtk.js. If GPU is not available
59
60
  * RenderingEngine will throw an error if you try to render a volume; however, for StackViewports
@@ -130,6 +130,8 @@ class StackViewport extends Viewport implements IStackViewport {
130
130
  private VOILUTFunction: VOILUTFunctionType;
131
131
  //
132
132
  private invert = false;
133
+ // The initial invert of the image loaded as opposed to the invert status of the viewport itself (see above).
134
+ private initialInvert = false;
133
135
  private interpolationType: InterpolationType;
134
136
 
135
137
  // Helpers
@@ -606,7 +608,9 @@ class StackViewport extends Viewport implements IStackViewport {
606
608
  this.hasPixelSpacing = scale > 0 || imagePlaneModule.rowPixelSpacing > 0;
607
609
  imagePlaneModule.calibration = calibration;
608
610
 
609
- if (!isUpdated) return imagePlaneModule;
611
+ if (!isUpdated) {
612
+ return imagePlaneModule;
613
+ }
610
614
 
611
615
  this.calibration = calibration;
612
616
  this._publishCalibratedEvent = true;
@@ -728,7 +732,7 @@ class StackViewport extends Viewport implements IStackViewport {
728
732
  this.setRotation(0);
729
733
  }
730
734
  this.setInterpolationType(InterpolationType.LINEAR);
731
- this.setInvertColor(false);
735
+ this.setInvertColor(this.initialInvert);
732
736
  }
733
737
 
734
738
  private _setPropertiesFromCache(): void {
@@ -1013,7 +1017,7 @@ class StackViewport extends Viewport implements IStackViewport {
1013
1017
  ? vec3.negate(vec3.create(), this.initialViewUp)
1014
1018
  : this.initialViewUp;
1015
1019
 
1016
- this.setCamera({
1020
+ this.setCameraNoEvent({
1017
1021
  viewUp: initialViewUp as Point3,
1018
1022
  });
1019
1023
 
@@ -1755,10 +1759,17 @@ class StackViewport extends Viewport implements IStackViewport {
1755
1759
  return;
1756
1760
  }
1757
1761
 
1758
- //If Photometric Interpretation is not the same for the next image we are trying to load, invalidate the stack to recreate the VTK imageData
1762
+ // If Photometric Interpretation is not the same for the next image we are trying to load
1763
+ // invalidate the stack to recreate the VTK imageData
1764
+ const csImgFrame = this.csImage?.imageFrame;
1765
+ const imgFrame = image?.imageFrame;
1766
+
1767
+ // if a volume is decached into images then the imageFrame will be undefined
1759
1768
  if (
1760
- this.csImage?.imageFrame.photometricInterpretation !==
1761
- image?.imageFrame?.photometricInterpretation
1769
+ csImgFrame?.photometricInterpretation !==
1770
+ imgFrame?.photometricInterpretation ||
1771
+ this.csImage?.photometricInterpretation !==
1772
+ image?.photometricInterpretation
1762
1773
  ) {
1763
1774
  this.stackInvalidated = true;
1764
1775
  }
@@ -2057,8 +2068,10 @@ class StackViewport extends Viewport implements IStackViewport {
2057
2068
  forceRecreateLUTFunction: !!monochrome1,
2058
2069
  });
2059
2070
 
2071
+ this.initialInvert = !!monochrome1;
2072
+
2060
2073
  // should carry over the invert color from the previous image if has been applied
2061
- this.setInvertColor(this.invert || !!monochrome1);
2074
+ this.setInvertColor(this.invert || this.initialInvert);
2062
2075
 
2063
2076
  // Saving position of camera on render, to cache the panning
2064
2077
  this.cameraFocalPointOnRender = this.getCamera().focalPoint;
@@ -2142,6 +2155,7 @@ class StackViewport extends Viewport implements IStackViewport {
2142
2155
  // Update the state of the viewport to the new imageIdIndex;
2143
2156
  this.currentImageIdIndex = imageIdIndex;
2144
2157
  this.hasPixelSpacing = true;
2158
+ this.viewportStatus = ViewportStatus.PRE_RENDER;
2145
2159
 
2146
2160
  // Todo: trigger an event to allow applications to hook into START of loading state
2147
2161
  // Currently we use loadHandlerManagers for this
@@ -2225,7 +2239,7 @@ class StackViewport extends Viewport implements IStackViewport {
2225
2239
 
2226
2240
  const targetImageId = imageIds[newTargetImageIdIndex];
2227
2241
 
2228
- const imageAlreadyLoaded = cache.isImageIdCached(targetImageId);
2242
+ const imageAlreadyLoaded = cache.isLoaded(targetImageId);
2229
2243
 
2230
2244
  // If image is already cached we want to scroll right away; however, if it is
2231
2245
  // not cached, we can debounce the scroll event to avoid firing multiple scroll
@@ -2564,7 +2578,9 @@ class StackViewport extends Viewport implements IStackViewport {
2564
2578
  public hasImageURI = (imageURI: string): boolean => {
2565
2579
  const imageIds = this.imageIds;
2566
2580
  for (let i = 0; i < imageIds.length; i++) {
2567
- if (imageIdToURI(imageIds[i]) === imageURI) return true;
2581
+ if (imageIdToURI(imageIds[i]) === imageURI) {
2582
+ return true;
2583
+ }
2568
2584
  }
2569
2585
 
2570
2586
  return false;
@@ -126,7 +126,7 @@ class Viewport implements IViewport {
126
126
 
127
127
  /**
128
128
  * Indicate that the image has been rendered.
129
- * This will set hte viewportStatus to RENDERED if there is image data
129
+ * This will set the viewportStatus to RENDERED if there is image data
130
130
  * available to actually be rendered - otherwise, the rendering simply showed
131
131
  * the background image.
132
132
  */
@@ -1,9 +1,11 @@
1
1
  import vtkPlane from '@kitware/vtk.js/Common/DataModel/Plane';
2
+ import vtkVolume from '@kitware/vtk.js/Rendering/Core/Volume';
3
+
2
4
  import { vec3 } from 'gl-matrix';
3
5
 
4
6
  import cache from '../cache';
5
7
  import { MPR_CAMERA_VALUES, RENDERING_DEFAULTS } from '../constants';
6
- import { BlendModes, OrientationAxis } from '../enums';
8
+ import { BlendModes, OrientationAxis, Events } from '../enums';
7
9
  import type {
8
10
  ActorEntry,
9
11
  IImageVolume,
@@ -12,8 +14,9 @@ import type {
12
14
  Point3,
13
15
  } from '../types';
14
16
  import type { ViewportInput } from '../types/IViewport';
15
- import { actorIsA, getClosestImageId } from '../utilities';
17
+ import { actorIsA, getClosestImageId, triggerEvent } from '../utilities';
16
18
  import BaseVolumeViewport from './BaseVolumeViewport';
19
+ import setDefaultVolumeVOI from './helpers/setDefaultVolumeVOI';
17
20
 
18
21
  /**
19
22
  * An object representing a VolumeViewport. VolumeViewports are used to render
@@ -350,6 +353,54 @@ class VolumeViewport extends BaseVolumeViewport {
350
353
  };
351
354
 
352
355
  getRotation = (): number => 0;
356
+
357
+ /**
358
+ * Reset the viewport properties to the default values
359
+ *
360
+
361
+ * @param volumeId - Optional volume ID to specify which volume properties to reset.
362
+ * If not provided, it will reset the properties of the default actor.
363
+ *
364
+ * @returns void
365
+ */
366
+ public resetProperties(volumeId?: string): void {
367
+ this._resetProperties(volumeId);
368
+ }
369
+
370
+ private _resetProperties(volumeId?: string) {
371
+ // Get the actor based on the volumeId if provided, otherwise use the default actor.
372
+ const volumeActor = volumeId
373
+ ? this.getActor(volumeId)
374
+ : this.getDefaultActor();
375
+
376
+ if (!volumeActor) {
377
+ throw new Error(`No actor found for the given volumeId: ${volumeId}`);
378
+ }
379
+
380
+ const imageVolume = cache.getVolume(volumeActor.uid);
381
+ if (!imageVolume) {
382
+ throw new Error(
383
+ `imageVolume with id: ${volumeActor.uid} does not exist in cache`
384
+ );
385
+ }
386
+ setDefaultVolumeVOI(volumeActor.actor as vtkVolume, imageVolume, false);
387
+
388
+ const range = (volumeActor.actor as vtkVolume)
389
+ .getProperty()
390
+ .getRGBTransferFunction(0)
391
+ .getMappingRange();
392
+
393
+ const eventDetails = {
394
+ viewportId: volumeActor.uid,
395
+ range: {
396
+ lower: range[0],
397
+ upper: range[1],
398
+ },
399
+ volumeId: volumeActor.uid,
400
+ };
401
+
402
+ triggerEvent(this.element, Events.VOI_MODIFIED, eventDetails);
403
+ }
353
404
  }
354
405
 
355
406
  export default VolumeViewport;
@@ -60,6 +60,10 @@ class VolumeViewport3D extends BaseVolumeViewport {
60
60
  ): void {
61
61
  return null;
62
62
  }
63
+
64
+ resetProperties(volumeId?: string): void {
65
+ return null;
66
+ }
63
67
  }
64
68
 
65
69
  export default VolumeViewport3D;
@@ -15,6 +15,11 @@
15
15
  */
16
16
 
17
17
  /**
18
+ * Generates the linear VOI LUT function.
19
+ * From the DICOM standard:
20
+ * https://dicom.nema.org/medical/dicom/current/output/html/part03.html#sect_C.11.2.1.2.1
21
+ * ((x - (c - 0.5)) / (w-1) + 0.5) * (ymax- ymin) + ymin
22
+ * clipped to the ymin...ymax range
18
23
  *
19
24
  * @param {Number} windowWidth Window Width
20
25
  * @param {Number} windowCenter Window Center
@@ -23,7 +28,10 @@
23
28
  */
24
29
  function generateLinearVOILUT(windowWidth: number, windowCenter: number) {
25
30
  return function (modalityLutValue) {
26
- return ((modalityLutValue - windowCenter) / windowWidth + 0.5) * 255.0;
31
+ const value =
32
+ ((modalityLutValue - (windowCenter - 0.5)) / (windowWidth - 1) + 0.5) *
33
+ 255.0;
34
+ return Math.min(Math.max(value, 0), 255);
27
35
  };
28
36
  }
29
37
 
@@ -72,10 +72,12 @@ function getRenderCanvas(
72
72
  const renderCanvas = enabledElement.renderingTools.renderCanvas;
73
73
 
74
74
  // The ww/wc is identity and not inverted - get a canvas with the image rendered into it for
75
- // Fast drawing
75
+ // Fast drawing. Note that this is 256/128, and NOT 255/127, per the DICOM
76
+ // standard, but allow either.
77
+ const { windowWidth, windowCenter } = enabledElement.viewport.voi;
76
78
  if (
77
- enabledElement.viewport.voi.windowWidth === 255 &&
78
- enabledElement.viewport.voi.windowCenter === 127 &&
79
+ (windowWidth === 256 || windowWidth === 255) &&
80
+ (windowCenter === 128 || windowCenter === 127) &&
79
81
  enabledElement.viewport.invert === false &&
80
82
  image.getCanvas &&
81
83
  image.getCanvas()
@@ -34,7 +34,9 @@ async function setVolumesForViewports(
34
34
 
35
35
  // if not instance of BaseVolumeViewport, throw
36
36
  if (!(viewport instanceof BaseVolumeViewport)) {
37
- throw new Error('setVolumesForViewports only supports VolumeViewport and VolumeViewport3D');
37
+ throw new Error(
38
+ 'setVolumesForViewports only supports VolumeViewport and VolumeViewport3D'
39
+ );
38
40
  }
39
41
  });
40
42
 
package/src/Settings.ts CHANGED
@@ -250,10 +250,14 @@ function get(dictionary: Record<string, unknown>, key: string): unknown {
250
250
  */
251
251
  function isValidKey(key: string): boolean {
252
252
  let last: number, current: number, previous: number;
253
- if (typeof key !== 'string' || (last = key.length - 1) < 0) return false;
253
+ if (typeof key !== 'string' || (last = key.length - 1) < 0) {
254
+ return false;
255
+ }
254
256
  previous = -1;
255
257
  while ((current = key.indexOf('.', previous + 1)) >= 0) {
256
- if (current - previous < 2 || current === last) return false;
258
+ if (current - previous < 2 || current === last) {
259
+ return false;
260
+ }
257
261
  previous = current;
258
262
  }
259
263
  return true;
@@ -15,34 +15,40 @@ import { triggerEvent, imageIdToURI } from '../utilities';
15
15
  import eventTarget from '../eventTarget';
16
16
  import Events from '../enums/Events';
17
17
 
18
- const MAX_CACHE_SIZE_1GB = 1073741824;
18
+ const ONE_GB = 1073741824;
19
19
 
20
+ /**
21
+ * Stores images, volumes and geometry.
22
+ * There are two sizes - the max cache size, that controls the overal maximum
23
+ * size, and the instance size, which controls how big any single object can
24
+ * be. Defaults are 3 GB and 2 GB - 8 bytes (just enough to allow allocating it
25
+ * without crashing).
26
+ * The 3 gb is tuned to the chromium garbage collection cycle to allow image volumes
27
+ * to be used/discarded.
28
+ */
20
29
  class Cache implements ICache {
21
- private readonly _imageCache: Map<string, ICachedImage>; // volatile space
22
- private readonly _volumeCache: Map<string, ICachedVolume>; // non-volatile space
30
+ // used to store image data (2d)
31
+ private readonly _imageCache = new Map<string, ICachedImage>(); // volatile space
32
+ // used to store volume data (3d)
33
+ private readonly _volumeCache = new Map<string, ICachedVolume>(); // non-volatile space
23
34
  // Todo: contour for now, but will be used for surface, etc.
24
35
  private readonly _geometryCache: Map<string, ICachedGeometry>;
25
- private _imageCacheSize: number;
26
- private _volumeCacheSize: number;
27
- private _maxCacheSize: number;
36
+
37
+ private _imageCacheSize = 0;
38
+ private _volumeCacheSize = 0;
39
+ private _maxCacheSize = 3 * ONE_GB;
40
+ private _maxInstanceSize = 2 * ONE_GB - 8;
28
41
 
29
42
  constructor() {
30
- // used to store image data (2d)
31
- this._imageCache = new Map();
32
- // used to store volume data (3d)
33
- this._volumeCache = new Map();
34
43
  // used to store object data (contour, surface, etc.)
35
44
  this._geometryCache = new Map();
36
- this._imageCacheSize = 0;
37
- this._volumeCacheSize = 0;
38
- this._maxCacheSize = MAX_CACHE_SIZE_1GB; // Default 1GB
39
45
  }
40
46
 
41
47
  /**
42
48
  * Set the maximum cache Size
43
49
  *
44
- * Maximum cache size should be set before adding the data; otherwise, it
45
- * will throw an error.
50
+ * Maximum cache size should be set before adding the data. If set after,
51
+ * and it is smaller than the current size, will cause issues.
46
52
  *
47
53
  * @param newMaxCacheSize - new maximum cache size
48
54
  *
@@ -59,7 +65,7 @@ class Cache implements ICache {
59
65
  /**
60
66
  * Checks if there is enough space in the cache for requested byte size
61
67
  *
62
- * It throws error, if the sum of volatile (image) cache and unallocated cache
68
+ * It returns false, if the sum of volatile (image) cache and unallocated cache
63
69
  * is less than the requested byteLength
64
70
  *
65
71
  * @param byteLength - byte length of requested byte size
@@ -67,6 +73,9 @@ class Cache implements ICache {
67
73
  * @returns - boolean indicating if there is enough space in the cache
68
74
  */
69
75
  public isCacheable = (byteLength: number): boolean => {
76
+ if (byteLength > this._maxInstanceSize) {
77
+ return false;
78
+ }
70
79
  const unallocatedSpace = this.getBytesAvailable();
71
80
  const imageCacheSize = this._imageCacheSize;
72
81
  const availableSpace = unallocatedSpace + imageCacheSize;
@@ -81,6 +90,13 @@ class Cache implements ICache {
81
90
  */
82
91
  public getMaxCacheSize = (): number => this._maxCacheSize;
83
92
 
93
+ /**
94
+ * Returns maximum size of a single instance (volume or single image)
95
+ *
96
+ * @returns maximum instance size
97
+ */
98
+ public getMaxInstanceSize = (): number => this._maxInstanceSize;
99
+
84
100
  /**
85
101
  * Returns current size of the cache
86
102
  *
@@ -384,7 +400,6 @@ class Cache implements ICache {
384
400
  cachedImage.image = image;
385
401
  cachedImage.sizeInBytes = image.sizeInBytes;
386
402
  this._incrementImageCacheSize(cachedImage.sizeInBytes);
387
-
388
403
  const eventDetails: EventTypes.ImageCacheImageAddedEventDetail = {
389
404
  image: cachedImage,
390
405
  };
@@ -429,7 +444,7 @@ class Cache implements ICache {
429
444
  * @param imageId - image Id to check
430
445
  * @returns boolean
431
446
  */
432
- public isImageIdCached(imageId: string): boolean {
447
+ public isLoaded(imageId: string): boolean {
433
448
  const cachedImage = this._imageCache.get(imageId);
434
449
 
435
450
  if (!cachedImage) {
@@ -151,12 +151,12 @@ export class ImageVolume implements IImageVolume {
151
151
  */
152
152
  destroy(): void {
153
153
  // TODO: GPU memory associated with volume is not cleared.
154
- this.vtkOpenGLTexture.releaseGraphicsResources();
155
- this.vtkOpenGLTexture.destroyTexture();
156
- this.vtkOpenGLTexture.delete();
157
154
  this.imageData.delete();
158
155
  this.imageData = null;
159
156
  this.scalarData = null;
157
+
158
+ this.vtkOpenGLTexture.releaseGraphicsResources();
159
+ this.vtkOpenGLTexture.delete();
160
160
  }
161
161
  }
162
162
 
package/src/init.ts CHANGED
@@ -100,7 +100,7 @@ function hasSharedArrayBuffer() {
100
100
  * @returns A promise that resolves to true cornerstone has been initialized successfully.
101
101
  * @category Initialization
102
102
  */
103
- async function init(configuration = {}): Promise<boolean> {
103
+ async function init(configuration = config): Promise<boolean> {
104
104
  if (csRenderInitialized) {
105
105
  return csRenderInitialized;
106
106
  }
@@ -132,7 +132,7 @@ let unknownVolumeLoader;
132
132
  */
133
133
  function loadVolumeFromVolumeLoader(
134
134
  volumeId: string,
135
- options: VolumeLoaderOptions
135
+ options?: VolumeLoaderOptions
136
136
  ): Types.IVolumeLoadObject {
137
137
  const colonIndex = volumeId.indexOf(':');
138
138
  const scheme = volumeId.substring(0, colonIndex);
@@ -210,7 +210,7 @@ export function loadVolume(
210
210
  */
211
211
  export async function createAndCacheVolume(
212
212
  volumeId: string,
213
- options: VolumeLoaderOptions
213
+ options?: VolumeLoaderOptions
214
214
  ): Promise<Record<string, any>> {
215
215
  if (volumeId === undefined) {
216
216
  throw new Error(
@@ -307,7 +307,7 @@ class RequestPoolManager {
307
307
  const priorities = Object.keys(this.requestPool[type])
308
308
  .map(Number)
309
309
  .filter((priority) => this.requestPool[type][priority].length)
310
- .sort();
310
+ .sort((a, b) => a - b);
311
311
  return priorities;
312
312
  }
313
313
 
@@ -0,0 +1,8 @@
1
+ type AffineMatrix = [
2
+ [number, number, number, number],
3
+ [number, number, number, number],
4
+ [number, number, number, number],
5
+ [number, number, number, number]
6
+ ];
7
+
8
+ export type { AffineMatrix };
@@ -72,6 +72,8 @@ interface IImage {
72
72
  sliceThickness?: number;
73
73
  /** whether image pixels are inverted in color */
74
74
  invert: boolean;
75
+ /** image photometric interpretation */
76
+ photometricInterpretation?: string;
75
77
  /** image size in number of bytes */
76
78
  sizeInBytes: number;
77
79
  /** CPU: custom modality LUT for image */
@@ -91,6 +93,8 @@ interface IImage {
91
93
  suvbwToSuvbsa?: number;
92
94
  };
93
95
  };
96
+ loadTimeInMS?: number;
97
+ decodeTimeInMS?: number;
94
98
  /** CPU: image statistics for rendering */
95
99
  stats?: {
96
100
  lastStoredPixelDataToCanvasImageDataTime?: number;
@@ -28,6 +28,10 @@ export default interface IVolumeViewport extends IViewport {
28
28
  * projected onto the `Viewport`'s `canvas`.
29
29
  */
30
30
  worldToCanvas: (worldPos: Point3) => Point2;
31
+ /**
32
+ * Returns the list of image Ids for the current viewport
33
+ */
34
+ getImageIds: (volumeId?: string) => string[];
31
35
  /**
32
36
  * Uses viewport camera and volume actor to decide if the viewport
33
37
  * is looking at the volume in the direction of acquisition (imageIds).
@@ -138,4 +142,8 @@ export default interface IVolumeViewport extends IViewport {
138
142
  getImageData(volumeId?: string): IImageData | undefined;
139
143
 
140
144
  setOrientation(orientation: OrientationAxis): void;
145
+ /**
146
+ * Reset the viewport properties to the default values
147
+ */
148
+ resetProperties(volumeId?: string): void;
141
149
  }
package/src/types/Mat3.ts CHANGED
@@ -1,16 +1,8 @@
1
1
  /**
2
2
  * This represents a 3x3 matrix of numbers
3
3
  */
4
- type Mat3 = [
5
- number,
6
- number,
7
- number,
8
- number,
9
- number,
10
- number,
11
- number,
12
- number,
13
- number
14
- ];
4
+ type Mat3 =
5
+ | [number, number, number, number, number, number, number, number, number]
6
+ | Float32Array;
15
7
 
16
8
  export default Mat3;
@@ -1,4 +1,4 @@
1
- import { VOILUTFunctionType } from '../enums';
1
+ import { InterpolationType, VOILUTFunctionType } from '../enums';
2
2
  import { VOIRange } from './voi';
3
3
 
4
4
  /**
@@ -11,6 +11,8 @@ type ViewportProperties = {
11
11
  VOILUTFunction?: VOILUTFunctionType;
12
12
  /** invert flag - whether the image is inverted */
13
13
  invert?: boolean;
14
+ /** interpolation type */
15
+ interpolationType?: InterpolationType;
14
16
  };
15
17
 
16
18
  export type { ViewportProperties };
@@ -81,6 +81,7 @@ import type { ViewportProperties } from './ViewportProperties';
81
81
  import type { PixelDataTypedArray } from './PixelDataTypedArray';
82
82
  import type { ImagePixelModule } from './ImagePixelModule';
83
83
  import type { ImagePlaneModule } from './ImagePlaneModule';
84
+ import type { AffineMatrix } from './AffineMatrix';
84
85
 
85
86
  export type {
86
87
  // config
@@ -173,4 +174,5 @@ export type {
173
174
  PixelDataTypedArray,
174
175
  ImagePixelModule,
175
176
  ImagePlaneModule,
177
+ AffineMatrix,
176
178
  };