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

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 (116) 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 +15 -6
  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 +17 -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/classes/ImageVolume.js +2 -3
  22. package/dist/cjs/cache/classes/ImageVolume.js.map +1 -1
  23. package/dist/cjs/init.d.ts +1 -1
  24. package/dist/cjs/init.js +1 -1
  25. package/dist/cjs/init.js.map +1 -1
  26. package/dist/cjs/loaders/volumeLoader.d.ts +1 -1
  27. package/dist/cjs/loaders/volumeLoader.js.map +1 -1
  28. package/dist/cjs/requestPool/requestPoolManager.js +1 -1
  29. package/dist/cjs/requestPool/requestPoolManager.js.map +1 -1
  30. package/dist/cjs/types/AffineMatrix.d.ts +27 -0
  31. package/dist/cjs/types/AffineMatrix.js +3 -0
  32. package/dist/cjs/types/AffineMatrix.js.map +1 -0
  33. package/dist/cjs/types/IImage.d.ts +1 -0
  34. package/dist/cjs/types/IVolumeViewport.d.ts +2 -0
  35. package/dist/cjs/types/Mat3.d.ts +1 -11
  36. package/dist/cjs/types/ViewportProperties.d.ts +2 -1
  37. package/dist/cjs/types/index.d.ts +2 -1
  38. package/dist/cjs/utilities/calculateViewportsSpatialRegistration.js +9 -14
  39. package/dist/cjs/utilities/calculateViewportsSpatialRegistration.js.map +1 -1
  40. package/dist/cjs/utilities/getClosestStackImageIndexForPoint.js +12 -6
  41. package/dist/cjs/utilities/getClosestStackImageIndexForPoint.js.map +1 -1
  42. package/dist/cjs/utilities/getRuntimeId.js +2 -1
  43. package/dist/cjs/utilities/getRuntimeId.js.map +1 -1
  44. package/dist/cjs/utilities/windowLevel.js +4 -4
  45. package/dist/cjs/utilities/windowLevel.js.map +1 -1
  46. package/dist/esm/RenderingEngine/BaseVolumeViewport.d.ts +4 -1
  47. package/dist/esm/RenderingEngine/BaseVolumeViewport.js +28 -2
  48. package/dist/esm/RenderingEngine/BaseVolumeViewport.js.map +1 -1
  49. package/dist/esm/RenderingEngine/RenderingEngine.js.map +1 -1
  50. package/dist/esm/RenderingEngine/StackViewport.d.ts +1 -0
  51. package/dist/esm/RenderingEngine/StackViewport.js +15 -6
  52. package/dist/esm/RenderingEngine/StackViewport.js.map +1 -1
  53. package/dist/esm/RenderingEngine/VolumeViewport.d.ts +2 -0
  54. package/dist/esm/RenderingEngine/VolumeViewport.js +17 -0
  55. package/dist/esm/RenderingEngine/VolumeViewport.js.map +1 -1
  56. package/dist/esm/RenderingEngine/VolumeViewport3D.d.ts +1 -0
  57. package/dist/esm/RenderingEngine/VolumeViewport3D.js +3 -0
  58. package/dist/esm/RenderingEngine/VolumeViewport3D.js.map +1 -1
  59. package/dist/esm/RenderingEngine/helpers/cpuFallback/rendering/getVOILut.js +3 -1
  60. package/dist/esm/RenderingEngine/helpers/cpuFallback/rendering/getVOILut.js.map +1 -1
  61. package/dist/esm/RenderingEngine/helpers/cpuFallback/rendering/renderColorImage.js +3 -2
  62. package/dist/esm/RenderingEngine/helpers/cpuFallback/rendering/renderColorImage.js.map +1 -1
  63. package/dist/esm/RenderingEngine/helpers/setVolumesForViewports.js.map +1 -1
  64. package/dist/esm/Settings.js +4 -2
  65. package/dist/esm/Settings.js.map +1 -1
  66. package/dist/esm/cache/classes/ImageVolume.js +2 -3
  67. package/dist/esm/cache/classes/ImageVolume.js.map +1 -1
  68. package/dist/esm/init.d.ts +1 -1
  69. package/dist/esm/init.js +1 -1
  70. package/dist/esm/init.js.map +1 -1
  71. package/dist/esm/loaders/volumeLoader.d.ts +1 -1
  72. package/dist/esm/loaders/volumeLoader.js.map +1 -1
  73. package/dist/esm/requestPool/requestPoolManager.js +1 -1
  74. package/dist/esm/requestPool/requestPoolManager.js.map +1 -1
  75. package/dist/esm/types/AffineMatrix.d.ts +27 -0
  76. package/dist/esm/types/AffineMatrix.js +2 -0
  77. package/dist/esm/types/AffineMatrix.js.map +1 -0
  78. package/dist/esm/types/IImage.d.ts +1 -0
  79. package/dist/esm/types/IVolumeViewport.d.ts +2 -0
  80. package/dist/esm/types/Mat3.d.ts +1 -11
  81. package/dist/esm/types/ViewportProperties.d.ts +2 -1
  82. package/dist/esm/types/index.d.ts +2 -1
  83. package/dist/esm/utilities/calculateViewportsSpatialRegistration.js +9 -14
  84. package/dist/esm/utilities/calculateViewportsSpatialRegistration.js.map +1 -1
  85. package/dist/esm/utilities/getClosestStackImageIndexForPoint.js +12 -6
  86. package/dist/esm/utilities/getClosestStackImageIndexForPoint.js.map +1 -1
  87. package/dist/esm/utilities/getRuntimeId.js +2 -1
  88. package/dist/esm/utilities/getRuntimeId.js.map +1 -1
  89. package/dist/esm/utilities/windowLevel.js +4 -4
  90. package/dist/esm/utilities/windowLevel.js.map +1 -1
  91. package/dist/umd/index.js +1 -1
  92. package/dist/umd/index.js.map +1 -1
  93. package/package.json +2 -2
  94. package/src/RenderingEngine/BaseVolumeViewport.ts +55 -1
  95. package/src/RenderingEngine/RenderingEngine.ts +1 -0
  96. package/src/RenderingEngine/StackViewport.ts +23 -7
  97. package/src/RenderingEngine/VolumeViewport.ts +34 -0
  98. package/src/RenderingEngine/VolumeViewport3D.ts +4 -0
  99. package/src/RenderingEngine/helpers/cpuFallback/rendering/getVOILut.ts +9 -1
  100. package/src/RenderingEngine/helpers/cpuFallback/rendering/renderColorImage.ts +5 -3
  101. package/src/RenderingEngine/helpers/setVolumesForViewports.ts +3 -1
  102. package/src/Settings.ts +6 -2
  103. package/src/cache/classes/ImageVolume.ts +3 -3
  104. package/src/init.ts +1 -1
  105. package/src/loaders/volumeLoader.ts +2 -2
  106. package/src/requestPool/requestPoolManager.ts +1 -1
  107. package/src/types/AffineMatrix.ts +8 -0
  108. package/src/types/IImage.ts +2 -0
  109. package/src/types/IVolumeViewport.ts +8 -0
  110. package/src/types/Mat3.ts +3 -11
  111. package/src/types/ViewportProperties.ts +3 -1
  112. package/src/types/index.ts +2 -0
  113. package/src/utilities/calculateViewportsSpatialRegistration.ts +21 -28
  114. package/src/utilities/getClosestStackImageIndexForPoint.ts +18 -6
  115. package/src/utilities/getRuntimeId.ts +3 -1
  116. 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.2",
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": "c154f7531c166db29a54fe41c76a22ecc7ac47c8"
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 {
@@ -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
@@ -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;
@@ -14,6 +14,8 @@ import type {
14
14
  import type { ViewportInput } from '../types/IViewport';
15
15
  import { actorIsA, getClosestImageId } from '../utilities';
16
16
  import BaseVolumeViewport from './BaseVolumeViewport';
17
+ import setDefaultVolumeVOI from './helpers/setDefaultVolumeVOI';
18
+ import vtkVolume from '@kitware/vtk.js/Rendering/Core/Volume';
17
19
 
18
20
  /**
19
21
  * An object representing a VolumeViewport. VolumeViewports are used to render
@@ -350,6 +352,38 @@ class VolumeViewport extends BaseVolumeViewport {
350
352
  };
351
353
 
352
354
  getRotation = (): number => 0;
355
+
356
+ /**
357
+ * Reset the viewport properties to the default values
358
+ *
359
+
360
+ * @param volumeId - Optional volume ID to specify which volume properties to reset.
361
+ * If not provided, it will reset the properties of the default actor.
362
+ *
363
+ * @returns void
364
+ */
365
+ public resetProperties(volumeId?: string): void {
366
+ this._resetProperties(volumeId);
367
+ }
368
+
369
+ private _resetProperties(volumeId?: string) {
370
+ // Get the actor based on the volumeId if provided, otherwise use the default actor.
371
+ const volumeActor = volumeId
372
+ ? this.getActor(volumeId)
373
+ : this.getDefaultActor();
374
+
375
+ if (!volumeActor) {
376
+ throw new Error(`No actor found for the given volumeId: ${volumeId}`);
377
+ }
378
+
379
+ const imageVolume = cache.getVolume(volumeActor.uid);
380
+ if (!imageVolume) {
381
+ throw new Error(
382
+ `imageVolume with id: ${volumeActor.uid} does not exist in cache`
383
+ );
384
+ }
385
+ setDefaultVolumeVOI(volumeActor.actor as vtkVolume, imageVolume, false);
386
+ }
353
387
  }
354
388
 
355
389
  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;
@@ -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 */
@@ -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
  };
@@ -1,9 +1,15 @@
1
1
  import { vec3, mat4 } from 'gl-matrix';
2
2
  import { IStackViewport } from '../types';
3
- import { StackViewport } from '../RenderingEngine';
4
3
  import spatialRegistrationMetadataProvider from './spatialRegistrationMetadataProvider';
5
4
  import { metaData } from '..';
6
- import isEqual from './isEqual';
5
+
6
+ /**
7
+ * Defines the allowed difference as a percent between the unit normals before
8
+ * two planes are considered not coplanar. Since this value is small compared
9
+ * to the unit lenght, this value is approximately the angular difference, measured
10
+ * in radians. That is, allow about a 3 degrees variation.
11
+ */
12
+ const ALLOWED_DELTA = 0.05;
7
13
 
8
14
  /**
9
15
  * It calculates the registration matrix between two viewports (currently only
@@ -21,40 +27,28 @@ function calculateViewportsSpatialRegistration(
21
27
  viewport1: IStackViewport,
22
28
  viewport2: IStackViewport
23
29
  ): void {
24
- if (
25
- !(viewport1 instanceof StackViewport) ||
26
- !(viewport2 instanceof StackViewport)
27
- ) {
28
- throw new Error(
29
- 'calculateViewportsSpatialRegistration: Both viewports must be StackViewports, volume viewports are not supported yet'
30
- );
31
- }
32
-
33
- const isSameFrameOfReference =
34
- viewport1.getFrameOfReferenceUID() === viewport2.getFrameOfReferenceUID();
35
-
36
- if (isSameFrameOfReference) {
37
- return;
38
- }
39
-
40
30
  const imageId1 = viewport1.getCurrentImageId();
41
31
  const imageId2 = viewport2.getCurrentImageId();
42
32
 
43
33
  const imagePlaneModule1 = metaData.get('imagePlaneModule', imageId1);
44
34
  const imagePlaneModule2 = metaData.get('imagePlaneModule', imageId2);
45
35
 
46
- const isSameImagePlane =
47
- imagePlaneModule1 &&
48
- imagePlaneModule2 &&
49
- isEqual(
50
- imagePlaneModule1.imageOrientationPatient,
51
- imagePlaneModule2.imageOrientationPatient
52
- );
36
+ if (!imagePlaneModule1 || !imagePlaneModule2) {
37
+ console.log('Viewport spatial registration requires image plane module');
38
+ return;
39
+ }
40
+ const { imageOrientationPatient: iop2 } = imagePlaneModule2;
41
+ const isSameImagePlane = imagePlaneModule1.imageOrientationPatient.every(
42
+ (v, i) => Math.abs(v - iop2[i]) < ALLOWED_DELTA
43
+ );
53
44
 
54
45
  if (!isSameImagePlane) {
55
- throw new Error(
56
- 'Viewport spatial registration only supported for same orientation (hence translation only) for now'
46
+ console.log(
47
+ 'Viewport spatial registration only supported for same orientation (hence translation only) for now',
48
+ imagePlaneModule1?.imageOrientationPatient,
49
+ imagePlaneModule2?.imageOrientationPatient
57
50
  );
51
+ return;
58
52
  }
59
53
 
60
54
  const imagePositionPatient1 = imagePlaneModule1.imagePositionPatient;
@@ -67,7 +61,6 @@ function calculateViewportsSpatialRegistration(
67
61
  );
68
62
 
69
63
  const mat = mat4.fromTranslation(mat4.create(), translation);
70
-
71
64
  spatialRegistrationMetadataProvider.add([viewport1.id, viewport2.id], mat);
72
65
  }
73
66
 
@@ -29,11 +29,15 @@ export function calculateMinimalDistanceForStackViewport(
29
29
  const imageIds = viewport.getImageIds();
30
30
  const currentImageIdIndex = viewport.getCurrentImageIdIndex();
31
31
 
32
- if (imageIds.length === 0) return null;
32
+ if (imageIds.length === 0) {
33
+ return null;
34
+ }
33
35
 
34
36
  const getDistance = (imageId: string): null | number => {
35
37
  const planeMetadata = getPlaneMetadata(imageId);
36
- if (!planeMetadata) return null;
38
+ if (!planeMetadata) {
39
+ return null;
40
+ }
37
41
  const plane = planar.planeEquation(
38
42
  planeMetadata.planeNormal,
39
43
  planeMetadata.imagePositionPatient
@@ -53,22 +57,30 @@ export function calculateMinimalDistanceForStackViewport(
53
57
  for (let i = 0; i < higherImageIds.length; i++) {
54
58
  const id = higherImageIds[i];
55
59
  const distance = getDistance(id);
56
- if (distance === null) continue;
60
+ if (distance === null) {
61
+ continue;
62
+ }
57
63
  if (distance <= closestStack.distance) {
58
64
  closestStack.distance = distance;
59
65
  closestStack.index = i + currentImageIdIndex + 1;
60
- } else break;
66
+ } else {
67
+ break;
68
+ }
61
69
  }
62
70
  //check lower indices
63
71
  const lowerImageIds = imageIds.slice(0, currentImageIdIndex);
64
72
  for (let i = lowerImageIds.length - 1; i >= 0; i--) {
65
73
  const id = lowerImageIds[i];
66
74
  const distance = getDistance(id);
67
- if (distance === null || distance === closestStack.distance) continue;
75
+ if (distance === null || distance === closestStack.distance) {
76
+ continue;
77
+ }
68
78
  if (distance < closestStack.distance) {
69
79
  closestStack.distance = distance;
70
80
  closestStack.index = i;
71
- } else break;
81
+ } else {
82
+ break;
83
+ }
72
84
  }
73
85
  return closestStack.distance === Infinity ? null : closestStack;
74
86
  }
@@ -46,7 +46,9 @@ function getNextRuntimeId(
46
46
  n = n + 1;
47
47
  } else {
48
48
  n = 0;
49
- if (i + 1 === idComponents.length) idComponents.push(0);
49
+ if (i + 1 === idComponents.length) {
50
+ idComponents.push(0);
51
+ }
50
52
  }
51
53
  idComponents[i] = n;
52
54
  }