@cornerstonejs/core 1.4.6 → 1.6.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.
Files changed (85) hide show
  1. package/dist/cjs/RenderingEngine/BaseVolumeViewport.js +1 -0
  2. package/dist/cjs/RenderingEngine/BaseVolumeViewport.js.map +1 -1
  3. package/dist/cjs/RenderingEngine/RenderingEngine.js +2 -0
  4. package/dist/cjs/RenderingEngine/RenderingEngine.js.map +1 -1
  5. package/dist/cjs/RenderingEngine/StackViewport.d.ts +2 -0
  6. package/dist/cjs/RenderingEngine/StackViewport.js +51 -75
  7. package/dist/cjs/RenderingEngine/StackViewport.js.map +1 -1
  8. package/dist/cjs/RenderingEngine/Viewport.d.ts +5 -0
  9. package/dist/cjs/RenderingEngine/Viewport.js +9 -0
  10. package/dist/cjs/RenderingEngine/Viewport.js.map +1 -1
  11. package/dist/cjs/enums/CalibrationTypes.d.ts +10 -0
  12. package/dist/cjs/enums/CalibrationTypes.js +15 -0
  13. package/dist/cjs/enums/CalibrationTypes.js.map +1 -0
  14. package/dist/cjs/enums/ViewportStatus.d.ts +8 -0
  15. package/dist/cjs/enums/ViewportStatus.js +12 -0
  16. package/dist/cjs/enums/ViewportStatus.js.map +1 -0
  17. package/dist/cjs/enums/index.d.ts +3 -1
  18. package/dist/cjs/enums/index.js +5 -1
  19. package/dist/cjs/enums/index.js.map +1 -1
  20. package/dist/cjs/types/CPUIImageData.d.ts +2 -0
  21. package/dist/cjs/types/EventTypes.d.ts +4 -2
  22. package/dist/cjs/types/IImageCalibration.d.ts +11 -0
  23. package/dist/cjs/types/IImageCalibration.js +3 -0
  24. package/dist/cjs/types/IImageCalibration.js.map +1 -0
  25. package/dist/cjs/types/IImageData.d.ts +2 -0
  26. package/dist/cjs/types/IViewport.d.ts +3 -0
  27. package/dist/cjs/types/index.d.ts +2 -1
  28. package/dist/cjs/utilities/calibratedPixelSpacingMetadataProvider.d.ts +3 -7
  29. package/dist/cjs/utilities/calibratedPixelSpacingMetadataProvider.js.map +1 -1
  30. package/dist/cjs/utilities/imageToWorldCoords.js +4 -1
  31. package/dist/cjs/utilities/imageToWorldCoords.js.map +1 -1
  32. package/dist/cjs/utilities/worldToImageCoords.js +4 -1
  33. package/dist/cjs/utilities/worldToImageCoords.js.map +1 -1
  34. package/dist/esm/RenderingEngine/BaseVolumeViewport.js +2 -1
  35. package/dist/esm/RenderingEngine/BaseVolumeViewport.js.map +1 -1
  36. package/dist/esm/RenderingEngine/RenderingEngine.js +2 -0
  37. package/dist/esm/RenderingEngine/RenderingEngine.js.map +1 -1
  38. package/dist/esm/RenderingEngine/StackViewport.d.ts +2 -0
  39. package/dist/esm/RenderingEngine/StackViewport.js +24 -49
  40. package/dist/esm/RenderingEngine/StackViewport.js.map +1 -1
  41. package/dist/esm/RenderingEngine/Viewport.d.ts +5 -0
  42. package/dist/esm/RenderingEngine/Viewport.js +9 -0
  43. package/dist/esm/RenderingEngine/Viewport.js.map +1 -1
  44. package/dist/esm/enums/CalibrationTypes.d.ts +10 -0
  45. package/dist/esm/enums/CalibrationTypes.js +12 -0
  46. package/dist/esm/enums/CalibrationTypes.js.map +1 -0
  47. package/dist/esm/enums/ViewportStatus.d.ts +8 -0
  48. package/dist/esm/enums/ViewportStatus.js +10 -0
  49. package/dist/esm/enums/ViewportStatus.js.map +1 -0
  50. package/dist/esm/enums/index.d.ts +3 -1
  51. package/dist/esm/enums/index.js +3 -1
  52. package/dist/esm/enums/index.js.map +1 -1
  53. package/dist/esm/types/CPUIImageData.d.ts +2 -0
  54. package/dist/esm/types/EventTypes.d.ts +4 -2
  55. package/dist/esm/types/IImageCalibration.d.ts +11 -0
  56. package/dist/esm/types/IImageCalibration.js +2 -0
  57. package/dist/esm/types/IImageCalibration.js.map +1 -0
  58. package/dist/esm/types/IImageData.d.ts +2 -0
  59. package/dist/esm/types/IViewport.d.ts +3 -0
  60. package/dist/esm/types/index.d.ts +2 -1
  61. package/dist/esm/utilities/calibratedPixelSpacingMetadataProvider.d.ts +3 -7
  62. package/dist/esm/utilities/calibratedPixelSpacingMetadataProvider.js.map +1 -1
  63. package/dist/esm/utilities/imageToWorldCoords.js +4 -1
  64. package/dist/esm/utilities/imageToWorldCoords.js.map +1 -1
  65. package/dist/esm/utilities/worldToImageCoords.js +4 -1
  66. package/dist/esm/utilities/worldToImageCoords.js.map +1 -1
  67. package/dist/umd/index.js +1 -1
  68. package/dist/umd/index.js.map +1 -1
  69. package/package.json +2 -2
  70. package/src/RenderingEngine/BaseVolumeViewport.ts +2 -0
  71. package/src/RenderingEngine/RenderingEngine.ts +3 -1
  72. package/src/RenderingEngine/StackViewport.ts +36 -97
  73. package/src/RenderingEngine/Viewport.ts +23 -0
  74. package/src/enums/CalibrationTypes.ts +55 -0
  75. package/src/enums/ViewportStatus.ts +14 -0
  76. package/src/enums/index.ts +4 -0
  77. package/src/types/CPUIImageData.ts +3 -0
  78. package/src/types/EventTypes.ts +6 -2
  79. package/src/types/IImageCalibration.ts +41 -0
  80. package/src/types/IImageData.ts +4 -0
  81. package/src/types/IViewport.ts +5 -0
  82. package/src/types/index.ts +2 -0
  83. package/src/utilities/calibratedPixelSpacingMetadataProvider.ts +4 -10
  84. package/src/utilities/imageToWorldCoords.ts +5 -2
  85. package/src/utilities/worldToImageCoords.ts +5 -4
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cornerstonejs/core",
3
- "version": "1.4.6",
3
+ "version": "1.6.0",
4
4
  "description": "",
5
5
  "main": "dist/umd/index.js",
6
6
  "types": "dist/esm/index.d.ts",
@@ -44,5 +44,5 @@
44
44
  "type": "individual",
45
45
  "url": "https://ohif.org/donate"
46
46
  },
47
- "gitHead": "611a684e4c3674d12cc66b749cf19d0f1b5698da"
47
+ "gitHead": "cfde297ad3a3ef5f1976751654c847ea63610749"
48
48
  }
@@ -13,6 +13,7 @@ import {
13
13
  BlendModes,
14
14
  Events,
15
15
  OrientationAxis,
16
+ ViewportStatus,
16
17
  VOILUTFunctionType,
17
18
  } from '../enums';
18
19
  import ViewportType from '../enums/ViewportType';
@@ -591,6 +592,7 @@ abstract class BaseVolumeViewport extends Viewport implements IVolumeViewport {
591
592
  }
592
593
 
593
594
  this._setVolumeActors(volumeActors);
595
+ this.viewportStatus = ViewportStatus.PRE_RENDER;
594
596
 
595
597
  triggerEvent(this.element, Events.VOLUME_VIEWPORT_NEW_VOLUME, {
596
598
  viewportId: this.id,
@@ -20,7 +20,7 @@ import type {
20
20
  InternalViewportInput,
21
21
  NormalizedViewportInput,
22
22
  } from '../types/IViewport';
23
- import { OrientationAxis } from '../enums';
23
+ import { OrientationAxis, ViewportStatus } from '../enums';
24
24
  import VolumeViewport3D from './VolumeViewport3D';
25
25
 
26
26
  type ViewportDisplayCoords = {
@@ -1107,6 +1107,7 @@ class RenderingEngine implements IRenderingEngine {
1107
1107
  const eventDetail =
1108
1108
  this.renderViewportUsingCustomOrVtkPipeline(viewport);
1109
1109
  eventDetailArray.push(eventDetail);
1110
+ viewport.setRendered();
1110
1111
 
1111
1112
  // This viewport has been rendered, we can remove it from the set
1112
1113
  this._needsRender.delete(viewport.id);
@@ -1251,6 +1252,7 @@ class RenderingEngine implements IRenderingEngine {
1251
1252
  suppressEvents,
1252
1253
  viewportId,
1253
1254
  renderingEngineId,
1255
+ viewportStatus: viewport.viewportStatus,
1254
1256
  };
1255
1257
  }
1256
1258
 
@@ -10,7 +10,6 @@ import vtkColorTransferFunction from '@kitware/vtk.js/Rendering/Core/ColorTransf
10
10
  import * as metaData from '../metaData';
11
11
  import Viewport from './Viewport';
12
12
  import eventTarget from '../eventTarget';
13
- import Events from '../enums/Events';
14
13
  import {
15
14
  triggerEvent,
16
15
  isEqual,
@@ -41,6 +40,7 @@ import {
41
40
  VolumeActor,
42
41
  Mat3,
43
42
  ColormapRegistration,
43
+ IImageCalibration,
44
44
  } from '../types';
45
45
  import { ViewportInput } from '../types/IViewport';
46
46
  import drawImageSync from './helpers/cpuFallback/drawImageSync';
@@ -48,8 +48,13 @@ import { getColormap } from './helpers/cpuFallback/colors/index';
48
48
 
49
49
  import { loadAndCacheImage } from '../loaders/imageLoader';
50
50
  import imageLoadPoolManager from '../requestPool/imageLoadPoolManager';
51
- import InterpolationType from '../enums/InterpolationType';
52
- import VOILUTFunctionType from '../enums/VOILUTFunctionType';
51
+ import {
52
+ InterpolationType,
53
+ RequestType,
54
+ Events,
55
+ CalibrationTypes,
56
+ VOILUTFunctionType,
57
+ } from '../enums';
53
58
  import canvasToPixel from './helpers/cpuFallback/rendering/canvasToPixel';
54
59
  import pixelToCanvas from './helpers/cpuFallback/rendering/pixelToCanvas';
55
60
  import getDefaultViewport from './helpers/cpuFallback/rendering/getDefaultViewport';
@@ -59,7 +64,6 @@ import resize from './helpers/cpuFallback/rendering/resize';
59
64
  import resetCamera from './helpers/cpuFallback/rendering/resetCamera';
60
65
  import { Transform } from './helpers/cpuFallback/rendering/transform';
61
66
  import { getConfiguration, getShouldUseCPURendering } from '../init';
62
- import RequestType from '../enums/RequestType';
63
67
  import {
64
68
  StackViewportNewStackEventDetail,
65
69
  StackViewportScrollEventDetail,
@@ -74,6 +78,7 @@ import {
74
78
  ImagePixelModule,
75
79
  ImagePlaneModule,
76
80
  } from '../types';
81
+ import ViewportStatus from '../enums/ViewportStatus';
77
82
 
78
83
  const EPSILON = 1; // Slice Thickness
79
84
 
@@ -90,8 +95,10 @@ interface ImageDataMetaData {
90
95
  }
91
96
  // TODO This needs to be exposed as its published to consumers.
92
97
  type CalibrationEvent = {
93
- rowScale: number;
94
- columnScale: number;
98
+ rowScale?: number;
99
+ columnScale?: number;
100
+ scale: number;
101
+ calibration: IImageCalibration;
95
102
  };
96
103
 
97
104
  type SetVOIOptions = {
@@ -410,6 +417,7 @@ class StackViewport extends Viewport implements IStackViewport {
410
417
  metadata: { Modality: this.modality },
411
418
  scaling: this.scaling,
412
419
  hasPixelSpacing: this.hasPixelSpacing,
420
+ calibration: this.calibration,
413
421
  preScale: {
414
422
  ...this.csImage.preScale,
415
423
  },
@@ -451,6 +459,7 @@ class StackViewport extends Viewport implements IStackViewport {
451
459
  },
452
460
  scalarData: this.cpuImagePixelData,
453
461
  hasPixelSpacing: this.hasPixelSpacing,
462
+ calibration: this.calibration,
454
463
  preScale: {
455
464
  ...this.csImage.preScale,
456
465
  },
@@ -557,6 +566,7 @@ class StackViewport extends Viewport implements IStackViewport {
557
566
  const voiLUTFunctionEnum = this._getValidVOILUTFunction(voiLUTFunction);
558
567
  this.VOILUTFunction = voiLUTFunctionEnum;
559
568
 
569
+ this.calibration = null;
560
570
  let imagePlaneModule = this._getImagePlaneModule(imageId);
561
571
 
562
572
  if (!this.useCPURendering) {
@@ -590,89 +600,19 @@ class StackViewport extends Viewport implements IStackViewport {
590
600
  * @returns modified imagePlaneModule with the calibrated spacings
591
601
  */
592
602
  private calibrateIfNecessary(imageId, imagePlaneModule) {
593
- const calibratedPixelSpacing = metaData.get(
594
- 'calibratedPixelSpacing',
595
- imageId
596
- );
597
-
598
- if (!calibratedPixelSpacing) {
599
- return imagePlaneModule;
600
- }
601
-
602
- const {
603
- rowPixelSpacing: calibratedRowSpacing,
604
- columnPixelSpacing: calibratedColumnSpacing,
605
- } = calibratedPixelSpacing;
603
+ const calibration = metaData.get('calibratedPixelSpacing', imageId);
604
+ const isUpdated = this.calibration !== calibration;
605
+ const { scale } = calibration || {};
606
+ this.hasPixelSpacing = scale > 0 || imagePlaneModule.rowPixelSpacing > 0;
607
+ imagePlaneModule.calibration = calibration;
606
608
 
607
- // Todo: This is necessary in general, but breaks an edge case when an image
608
- // is calibrated to some other spacing, and it gets calibrated BACK to the
609
- // original spacing.
610
- if (
611
- imagePlaneModule.rowPixelSpacing === calibratedRowSpacing &&
612
- imagePlaneModule.columnPixelSpacing === calibratedColumnSpacing
613
- ) {
614
- return imagePlaneModule;
615
- }
609
+ if (!isUpdated) return imagePlaneModule;
616
610
 
617
- // Check if there is already an actor
618
- const imageDataMetadata = this.getImageData();
619
-
620
- // If no actor (first load) and calibration matches the dicom header
621
- if (
622
- !imageDataMetadata &&
623
- imagePlaneModule.rowPixelSpacing === calibratedRowSpacing &&
624
- imagePlaneModule.columnPixelSpacing === calibratedColumnSpacing
625
- ) {
626
- return imagePlaneModule;
627
- }
628
-
629
- // If no actor (first load) and calibration doesn't match headers
630
- // -> needs calibration
631
- if (
632
- !imageDataMetadata &&
633
- (imagePlaneModule.rowPixelSpacing !== calibratedRowSpacing ||
634
- imagePlaneModule.columnPixelSpacing !== calibratedColumnSpacing)
635
- ) {
636
- this._publishCalibratedEvent = true;
637
-
638
- this._calibrationEvent = <CalibrationEvent>{
639
- rowScale: calibratedRowSpacing / imagePlaneModule.rowPixelSpacing,
640
- columnScale:
641
- calibratedColumnSpacing / imagePlaneModule.columnPixelSpacing,
642
- };
643
-
644
- // modify the calibration object to store the actual updated values applied
645
- calibratedPixelSpacing.appliedSpacing = calibratedPixelSpacing;
646
- // This updates the render copy
647
- imagePlaneModule.rowPixelSpacing = calibratedRowSpacing;
648
- imagePlaneModule.columnPixelSpacing = calibratedColumnSpacing;
649
- return imagePlaneModule;
650
- }
651
-
652
- // If there is already an actor, check if calibration is needed for the current actor
653
- const { imageData } = imageDataMetadata;
654
- const [columnPixelSpacing, rowPixelSpacing] = imageData.getSpacing();
655
-
656
- // modify the calibration object to store the actual updated values applied
657
- calibratedPixelSpacing.appliedSpacing = calibratedPixelSpacing;
658
- imagePlaneModule.rowPixelSpacing = calibratedRowSpacing;
659
- imagePlaneModule.columnPixelSpacing = calibratedColumnSpacing;
660
-
661
- // If current actor spacing matches the calibrated spacing
662
- if (
663
- rowPixelSpacing === calibratedRowSpacing &&
664
- columnPixelSpacing === calibratedPixelSpacing
665
- ) {
666
- // No calibration is required
667
- return imagePlaneModule;
668
- }
669
-
670
- // Calibration is required
611
+ this.calibration = calibration;
671
612
  this._publishCalibratedEvent = true;
672
-
673
613
  this._calibrationEvent = <CalibrationEvent>{
674
- rowScale: calibratedRowSpacing / rowPixelSpacing,
675
- columnScale: calibratedColumnSpacing / columnPixelSpacing,
614
+ scale,
615
+ calibration,
676
616
  };
677
617
 
678
618
  return imagePlaneModule;
@@ -696,6 +636,9 @@ class StackViewport extends Viewport implements IStackViewport {
696
636
  }: StackViewportProperties = {},
697
637
  suppressEvents = false
698
638
  ): void {
639
+ this.viewportStatus = this.csImage
640
+ ? ViewportStatus.PRE_RENDER
641
+ : ViewportStatus.LOADING;
699
642
  // if voi is not applied for the first time, run the setVOI function
700
643
  // which will apply the default voi based on the range
701
644
  if (typeof voiRange !== 'undefined') {
@@ -753,6 +696,7 @@ class StackViewport extends Viewport implements IStackViewport {
753
696
  public resetProperties(): void {
754
697
  this.cpuRenderingInvalidated = true;
755
698
  this.voiUpdatedWithSetProperties = false;
699
+ this.viewportStatus = ViewportStatus.PRE_RENDER;
756
700
 
757
701
  this.fillWithBackgroundColor();
758
702
 
@@ -1494,6 +1438,7 @@ class StackViewport extends Viewport implements IStackViewport {
1494
1438
  this.voiRange = null;
1495
1439
  this.interpolationType = InterpolationType.LINEAR;
1496
1440
  this.invert = false;
1441
+ this.viewportStatus = ViewportStatus.LOADING;
1497
1442
 
1498
1443
  this.fillWithBackgroundColor();
1499
1444
 
@@ -1715,6 +1660,7 @@ class StackViewport extends Viewport implements IStackViewport {
1715
1660
  }
1716
1661
 
1717
1662
  this._setCSImage(image);
1663
+ this.viewportStatus = ViewportStatus.PRE_RENDER;
1718
1664
 
1719
1665
  const eventDetail: EventTypes.StackNewImageEventDetail = {
1720
1666
  image,
@@ -2648,6 +2594,7 @@ class StackViewport extends Viewport implements IStackViewport {
2648
2594
  element: this.element,
2649
2595
  viewportId: this.id,
2650
2596
  renderingEngineId: this.renderingEngineId,
2597
+ viewportStatus: this.viewportStatus,
2651
2598
  };
2652
2599
  };
2653
2600
 
@@ -2709,28 +2656,20 @@ class StackViewport extends Viewport implements IStackViewport {
2709
2656
  imageId
2710
2657
  );
2711
2658
 
2659
+ this.calibration ||= imagePlaneModule.calibration;
2660
+
2712
2661
  const newImagePlaneModule: ImagePlaneModule = {
2713
2662
  ...imagePlaneModule,
2714
2663
  };
2715
2664
 
2716
- if (calibratedPixelSpacing?.appliedSpacing) {
2717
- // Over-ride the image plane module spacing, as the measurement data
2718
- // has already been created with the calibrated spacing provided from
2719
- // down below inside calibrateIfNecessary
2720
- const { rowPixelSpacing, columnPixelSpacing } =
2721
- calibratedPixelSpacing.appliedSpacing;
2722
- newImagePlaneModule.rowPixelSpacing = rowPixelSpacing;
2723
- newImagePlaneModule.columnPixelSpacing = columnPixelSpacing;
2724
- }
2725
-
2726
2665
  if (!newImagePlaneModule.columnPixelSpacing) {
2727
2666
  newImagePlaneModule.columnPixelSpacing = 1;
2728
- this.hasPixelSpacing = false;
2667
+ this.hasPixelSpacing = this.calibration?.scale > 0;
2729
2668
  }
2730
2669
 
2731
2670
  if (!newImagePlaneModule.rowPixelSpacing) {
2732
2671
  newImagePlaneModule.rowPixelSpacing = 1;
2733
- this.hasPixelSpacing = false;
2672
+ this.hasPixelSpacing = this.calibration?.scale > 0;
2734
2673
  }
2735
2674
 
2736
2675
  if (!newImagePlaneModule.columnCosines) {
@@ -7,6 +7,7 @@ import { vec2, vec3 } from 'gl-matrix';
7
7
  import _cloneDeep from 'lodash.clonedeep';
8
8
 
9
9
  import Events from '../enums/Events';
10
+ import ViewportStatus from '../enums/ViewportStatus';
10
11
  import ViewportType from '../enums/ViewportType';
11
12
  import renderingEngineCache from './renderingEngineCache';
12
13
  import { triggerEvent, planar, isImageActor, actorIsA } from '../utilities';
@@ -26,6 +27,7 @@ import type {
26
27
  import type { ViewportInput, IViewport } from '../types/IViewport';
27
28
  import type { vtkSlabCamera } from './vtkClasses/vtkSlabCamera';
28
29
  import { getConfiguration } from '../init';
30
+ import IImageCalibration from '../types/IImageCalibration';
29
31
 
30
32
  /**
31
33
  * An object representing a single viewport, which is a camera
@@ -50,6 +52,10 @@ class Viewport implements IViewport {
50
52
  protected flipHorizontal = false;
51
53
  protected flipVertical = false;
52
54
  public isDisabled: boolean;
55
+ /** Record the renddering status, mostly for testing purposes, but can also
56
+ * be useful for knowing things like whether the viewport is initialized
57
+ */
58
+ public viewportStatus: ViewportStatus = ViewportStatus.NO_DATA;
53
59
 
54
60
  /** sx of viewport on the offscreen canvas */
55
61
  sx: number;
@@ -69,6 +75,7 @@ class Viewport implements IViewport {
69
75
  /** A flag representing if viewport methods should fire events or not */
70
76
  readonly suppressEvents: boolean;
71
77
  protected hasPixelSpacing = true;
78
+ protected calibration: IImageCalibration;
72
79
  /** The camera that is initially defined on the reset for
73
80
  * the relative pan/zoom
74
81
  */
@@ -117,6 +124,22 @@ class Viewport implements IViewport {
117
124
  return false;
118
125
  }
119
126
 
127
+ /**
128
+ * Indicate that the image has been rendered.
129
+ * This will set hte viewportStatus to RENDERED if there is image data
130
+ * available to actually be rendered - otherwise, the rendering simply showed
131
+ * the background image.
132
+ */
133
+ public setRendered() {
134
+ if (
135
+ this.viewportStatus === ViewportStatus.NO_DATA ||
136
+ this.viewportStatus === ViewportStatus.LOADING
137
+ ) {
138
+ return;
139
+ }
140
+ this.viewportStatus = ViewportStatus.RENDERED;
141
+ }
142
+
120
143
  /**
121
144
  * Returns the rendering engine driving the `Viewport`.
122
145
  *
@@ -0,0 +1,55 @@
1
+ /**
2
+ * Defines the calibration types available. These define how the units
3
+ * for measurements are specified.
4
+ */
5
+ export enum CalibrationTypes {
6
+ /**
7
+ * Not applicable means the units are directly defind by the underlying
8
+ * hardware, such as CT and MR volumetric displays, so no special handling
9
+ * or notification is required.
10
+ */
11
+ NOT_APPLICABLE = '',
12
+ /**
13
+ * ERMF is estimated radiographic magnification factor. This defines how
14
+ * much the image is magnified at the detector as opposed to the location in
15
+ * the body of interest. This occurs because the radiation beam is expanding
16
+ * and effectively magnifies the image on the detector compared to where the
17
+ * point of interest in the body is.
18
+ * This suggests that measurements can be partially trusted, but the user
19
+ * still needs to be aware that different depths within the body have differing
20
+ * ERMF values, so precise measurements would still need to be manually calibrated.
21
+ */
22
+ ERMF = 'ERMF',
23
+ /**
24
+ * User calibration means that the user has provided a custom calibration
25
+ * specifying how large the image data is. This type can occur on
26
+ * volumetric images, eg for scout images that might have invalid spacing
27
+ * tags.
28
+ */
29
+ USER = 'User',
30
+ /**
31
+ * A projection calibration means the raw detector size, without any
32
+ * ERMF applied, meaning that the size in the body cannot be trusted and
33
+ * that a calibration should be applied.
34
+ * This is different from Error in that there is simply no magnification
35
+ * factor applied as opposed to having multiple, inconsistent magnification
36
+ * factors.
37
+ */
38
+ PROJECTION = 'Proj',
39
+ /**
40
+ * A region calibration is used for other types of images, typically
41
+ * ultrasouunds where the distance in the image may mean something other than
42
+ * physical distance, such as mV or Hz or some other measurement values.
43
+ */
44
+ REGION = 'Region',
45
+ /**
46
+ * Error is used to define mismatches between various units, such as when
47
+ * there are two different ERMF values specified. This is an indication to
48
+ * NOT trust the measurement values but to manually calibrate.
49
+ */
50
+ ERROR = 'Error',
51
+ /** Uncalibrated image */
52
+ UNCALIBRATED = 'Uncalibrated',
53
+ }
54
+
55
+ export default CalibrationTypes;
@@ -0,0 +1,14 @@
1
+ enum ViewportStatus {
2
+ /** Initial state before any volumes or stacks are available*/
3
+ NO_DATA = 'noData',
4
+ /** Stack/volumes are available but are in progress */
5
+ LOADING = 'loading',
6
+ /** Ready to be rendered */
7
+ PRE_RENDER = 'preRender',
8
+ /** In the midst of a resize */
9
+ RESIZE = 'resize',
10
+ /** Rendered image data */
11
+ RENDERED = 'rendered',
12
+ }
13
+
14
+ export default ViewportStatus;
@@ -9,10 +9,13 @@ import GeometryType from './GeometryType';
9
9
  import ContourType from './ContourType';
10
10
  import VOILUTFunctionType from './VOILUTFunctionType';
11
11
  import DynamicOperatorType from './DynamicOperatorType';
12
+ import CalibrationTypes from './CalibrationTypes';
13
+ import ViewportStatus from './ViewportStatus';
12
14
 
13
15
  export {
14
16
  Events,
15
17
  BlendModes,
18
+ CalibrationTypes,
16
19
  InterpolationType,
17
20
  RequestType,
18
21
  ViewportType,
@@ -22,4 +25,5 @@ export {
22
25
  ContourType,
23
26
  VOILUTFunctionType,
24
27
  DynamicOperatorType,
28
+ ViewportStatus,
25
29
  };
@@ -1,4 +1,5 @@
1
1
  import { Point3, Scaling, Mat3, PixelDataTypedArray } from '../types';
2
+ import IImageCalibration from './IImageCalibration';
2
3
 
3
4
  type CPUImageData = {
4
5
  worldToIndex?: (point: Point3) => Point3;
@@ -24,6 +25,8 @@ type CPUIImageData = {
24
25
  scaling: Scaling;
25
26
  /** whether the image has pixel spacing and it is not undefined */
26
27
  hasPixelSpacing?: boolean;
28
+ calibration?: IImageCalibration;
29
+
27
30
  /** preScale object */
28
31
  preScale?: {
29
32
  /** boolean flag to indicate whether the image has been scaled */
@@ -8,7 +8,9 @@ import type IImage from './IImage';
8
8
  import type IImageVolume from './IImageVolume';
9
9
  import type { VOIRange } from './voi';
10
10
  import type VOILUTFunctionType from '../enums/VOILUTFunctionType';
11
+ import type ViewportStatus from '../enums/ViewportStatus';
11
12
  import type DisplayArea from './displayArea';
13
+ import IImageCalibration from './IImageCalibration';
12
14
 
13
15
  /**
14
16
  * CAMERA_MODIFIED Event's data
@@ -96,6 +98,8 @@ type ImageRenderedEventDetail = {
96
98
  renderingEngineId: string;
97
99
  /** Whether to suppress the event */
98
100
  suppressEvents?: boolean;
101
+ /** Include information on whether this is a real rendering or just background */
102
+ viewportStatus: ViewportStatus;
99
103
  };
100
104
  /**
101
105
  * IMAGE_VOLUME_MODIFIED Event's data
@@ -225,8 +229,8 @@ type ImageSpacingCalibratedEventDetail = {
225
229
  viewportId: string;
226
230
  renderingEngineId: string;
227
231
  imageId: string;
228
- rowScale: number;
229
- columnScale: number;
232
+ /** calibration contains the scaling information as well as other calibration info */
233
+ calibration: IImageCalibration;
230
234
  imageData: vtkImageData;
231
235
  worldToIndex: mat4;
232
236
  };
@@ -0,0 +1,41 @@
1
+ import CalibrationTypes from '../enums/CalibrationTypes';
2
+
3
+ /**
4
+ * IImageCalibration is an object that stores information about the type
5
+ * of image calibration.
6
+ */
7
+ export interface IImageCalibration {
8
+ /**
9
+ * The pixel spacing for the image, in mm between pixel centers
10
+ * These are not required, and are deprecated in favour of getting the original
11
+ * image spacing and then applying the transforms. The values here should
12
+ * be identical to original spacing.
13
+ */
14
+ rowPixelSpacing?: number;
15
+ columnPixelSpacing?: number;
16
+ /** The scaling of measurement values relative to the base pixel spacing (1 if not specified) */
17
+ scale?: number;
18
+ /**
19
+ * The calibration aspect ratio for non-square calibrations.
20
+ * This is the aspect ratio similar to the scale above that applies when
21
+ * the viewport is displaying non-square image pixels as square screen pixels.
22
+ *
23
+ * Defaults to 1 if not specified, and is also 1 if the Viewport has squared
24
+ * up the image pixels so that they are displayed as a square.
25
+ * Not well handled currently as this needs to be incorporated into
26
+ * tools when doing calculations.
27
+ */
28
+ aspect?: number;
29
+ /** The type of the pixel spacing, distinguishing between various
30
+ * types projection (CR/DX/MG) spacing and volumetric spacing (the type is
31
+ * an empty string as it doesn't get a suffix, but this distinguishes it
32
+ * from other types)
33
+ */
34
+ type: CalibrationTypes;
35
+ /** A tooltip which can be used to explain the calibration information */
36
+ tooltip?: string;
37
+ /** The DICOM defined ultrasound regions. Used for non-distance spacing units. */
38
+ sequenceOfUltrasoundRegions?: Record<string, unknown>[];
39
+ }
40
+
41
+ export default IImageCalibration;
@@ -1,5 +1,6 @@
1
1
  import type { vtkImageData } from '@kitware/vtk.js/Common/DataModel/ImageData';
2
2
  import { Point3, Scaling, Mat3 } from '../types';
3
+ import IImageCalibration from './IImageCalibration';
3
4
 
4
5
  /**
5
6
  * IImageData of an image, which stores actual scalarData and metaData about the image.
@@ -24,6 +25,9 @@ interface IImageData {
24
25
  scaling?: Scaling;
25
26
  /** whether the image has pixel spacing and it is not undefined */
26
27
  hasPixelSpacing?: boolean;
28
+
29
+ calibration?: IImageCalibration;
30
+
27
31
  /** preScale object */
28
32
  preScale?: {
29
33
  /** boolean flag to indicate whether the image has been scaled */
@@ -4,6 +4,7 @@ import Point3 from './Point3';
4
4
  import ViewportInputOptions from './ViewportInputOptions';
5
5
  import { ActorEntry } from './IActor';
6
6
  import ViewportType from '../enums/ViewportType';
7
+ import ViewportStatus from '../enums/ViewportStatus';
7
8
  import DisplayArea from './displayArea';
8
9
 
9
10
  /**
@@ -38,6 +39,8 @@ interface IViewport {
38
39
  suppressEvents: boolean;
39
40
  /** if the viewport has been disabled */
40
41
  isDisabled: boolean;
42
+ /** The rendering state of this viewport */
43
+ viewportStatus: ViewportStatus;
41
44
  /** the rotation applied to the view */
42
45
  getRotation: () => number;
43
46
  /** frameOfReferenceUID the viewport's default actor is rendering */
@@ -88,6 +91,8 @@ interface IViewport {
88
91
  getCanvas(): HTMLCanvasElement;
89
92
  /** returns camera object */
90
93
  getCamera(): ICamera;
94
+ /** Sets the rendered state to rendered if the render actually showed image data */
95
+ setRendered(): void;
91
96
  /** returns the parallel zoom relative to the default (eg returns 1 after reset) */
92
97
  getZoom(): number;
93
98
  /** Sets the relative zoom - set to 1 to reset it */
@@ -30,6 +30,7 @@ import type Plane from './Plane';
30
30
  import type IStreamingImageVolume from './IStreamingImageVolume';
31
31
  import type ViewportInputOptions from './ViewportInputOptions';
32
32
  import type IImageData from './IImageData';
33
+ import type IImageCalibration from './IImageCalibration';
33
34
  import type CPUIImageData from './CPUIImageData';
34
35
  import type { CPUImageData } from './CPUIImageData';
35
36
  import type IImage from './IImage';
@@ -102,6 +103,7 @@ export type {
102
103
  IStreamingImageVolume,
103
104
  IImage,
104
105
  IImageData,
106
+ IImageCalibration,
105
107
  CPUIImageData,
106
108
  CPUImageData,
107
109
  EventTypes,
@@ -1,13 +1,7 @@
1
1
  import imageIdToURI from './imageIdToURI';
2
+ import { IImageCalibration } from '../types';
2
3
 
3
- export type CalibratedPixelValue = {
4
- rowPixelSpacing: number;
5
- columnPixelSpacing: number;
6
- // These values get updated by the viewport after the change to record the applied value
7
- appliedSpacing?: CalibratedPixelValue;
8
- };
9
-
10
- const state: Record<string, CalibratedPixelValue> = {}; // Calibrated pixel spacing per imageId
4
+ const state: Record<string, IImageCalibration> = {}; // Calibrated pixel spacing per imageId
11
5
 
12
6
  /**
13
7
  * Simple metadataProvider object to store metadata for calibrated spacings.
@@ -20,7 +14,7 @@ const metadataProvider = {
20
14
  * @param imageId - the imageId for the metadata to store
21
15
  * @param payload - the payload composed of new calibrated pixel spacings
22
16
  */
23
- add: (imageId: string, payload: CalibratedPixelValue): void => {
17
+ add: (imageId: string, payload: IImageCalibration): void => {
24
18
  const imageURI = imageIdToURI(imageId);
25
19
  state[imageURI] = payload;
26
20
  },
@@ -31,7 +25,7 @@ const metadataProvider = {
31
25
  * @param imageId - the imageId to enquire about
32
26
  * @returns the calibrated pixel spacings for the imageId if it exists, otherwise undefined
33
27
  */
34
- get: (type: string, imageId: string): CalibratedPixelValue => {
28
+ get: (type: string, imageId: string): IImageCalibration => {
35
29
  if (type === 'calibratedPixelSpacing') {
36
30
  const imageURI = imageIdToURI(imageId);
37
31
  return state[imageURI];
@@ -23,12 +23,15 @@ export default function imageToWorldCoords(
23
23
 
24
24
  const {
25
25
  columnCosines,
26
- columnPixelSpacing,
27
26
  rowCosines,
28
- rowPixelSpacing,
29
27
  imagePositionPatient: origin,
30
28
  } = imagePlaneModule;
31
29
 
30
+ let { columnPixelSpacing, rowPixelSpacing } = imagePlaneModule;
31
+ // Use ||= to convert null and 0 as well as undefined to 1
32
+ columnPixelSpacing ||= 1;
33
+ rowPixelSpacing ||= 1;
34
+
32
35
  // calculate the image coordinates in the world space
33
36
  const imageCoordsInWorld = vec3.create();
34
37