@cornerstonejs/tools 1.14.2 → 1.14.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cornerstonejs/tools",
3
- "version": "1.14.2",
3
+ "version": "1.14.4",
4
4
  "description": "Cornerstone3D Tools",
5
5
  "main": "dist/umd/index.js",
6
6
  "types": "dist/esm/index.d.ts",
@@ -29,7 +29,7 @@
29
29
  "webpack:watch": "webpack --mode development --progress --watch --config ./.webpack/webpack.dev.js"
30
30
  },
31
31
  "dependencies": {
32
- "@cornerstonejs/core": "^1.14.2",
32
+ "@cornerstonejs/core": "^1.14.4",
33
33
  "lodash.clonedeep": "4.5.0",
34
34
  "lodash.get": "^4.4.2"
35
35
  },
@@ -52,5 +52,5 @@
52
52
  "type": "individual",
53
53
  "url": "https://ohif.org/donate"
54
54
  },
55
- "gitHead": "7fb460c47629f6694a78c6bed836b432e1af13a3"
55
+ "gitHead": "96dc1772a2f77a7626c07e19434b42753e9d4188"
56
56
  }
@@ -205,6 +205,7 @@ class Synchronizer {
205
205
  }
206
206
 
207
207
  this._ignoreFiredEvents = true;
208
+ const promises = [];
208
209
  try {
209
210
  for (let i = 0; i < this._targetViewports.length; i++) {
210
211
  const targetViewport = this._targetViewports[i];
@@ -214,19 +215,26 @@ class Synchronizer {
214
215
  if (targetIsSource) {
215
216
  continue;
216
217
  }
217
-
218
- this._eventHandler(
219
- this,
220
- sourceViewport,
221
- targetViewport,
222
- sourceEvent,
223
- this._options
218
+ promises.push(
219
+ this._eventHandler(
220
+ this,
221
+ sourceViewport,
222
+ targetViewport,
223
+ sourceEvent,
224
+ this._options
225
+ )
224
226
  );
225
227
  }
226
228
  } catch (ex) {
227
229
  console.warn(`Synchronizer, for: ${this._eventName}`, ex);
228
230
  } finally {
229
- this._ignoreFiredEvents = false;
231
+ if (promises.length) {
232
+ Promise.allSettled(promises).then(() => {
233
+ this._ignoreFiredEvents = false;
234
+ });
235
+ } else {
236
+ this._ignoreFiredEvents = false;
237
+ }
230
238
  }
231
239
  }
232
240
 
@@ -1,4 +1,4 @@
1
- import { vec3 } from 'gl-matrix';
1
+ import { vec3, mat4 } from 'gl-matrix';
2
2
  import {
3
3
  getRenderingEngine,
4
4
  Types,
@@ -8,28 +8,27 @@ import {
8
8
  import { Synchronizer } from '../../store';
9
9
  import { jumpToSlice } from '../../utilities';
10
10
  import areViewportsCoplanar from './areViewportsCoplanar ';
11
+
12
+ const getSpatialRegistration = (targetId, sourceId) =>
13
+ utilities.spatialRegistrationMetadataProvider.get(
14
+ 'spatialRegistrationModule',
15
+ [targetId, sourceId]
16
+ );
17
+
11
18
  /**
12
19
  * Synchronizer callback to synchronize the source viewport image to the
13
- * target viewports closest image in its stack. There are two scenarios
20
+ * target viewports closest image in its stack.
14
21
  *
15
- * 1) viewports are in the same frameOfReferenceUID then we can use the
16
- * absolute imagePositionPatient for the source viewport's current image
17
- * and set the target viewport's image to the closest image in its stack
18
- * (which might have different slice thickness so cannot use slice number)
22
+ * This synchronizer does a setup (which can already be predefined as required)
23
+ * to register the target and soruce viewports. The registration will default
24
+ * to the identity registration if the same FOR is present in both viewports,
25
+ * unless the option `useInitialPosition` is set in the target viewport.
19
26
  *
20
- * 2) viewports have different frameOfReferenceUIDs then we look inside the
21
- * registrationMetadataProvider to check if there is a corresponding matrix
22
- * for mapping between the source and target viewport if so it is used to
23
- * and is applied to the imagePositionPatient of the source viewport's to
24
- * get the imagePositionPatient of the target viewport's closest image in
25
- * its stack.
26
- * Note for 2) The consuming apps using Cornerstone3D (OHIF, etc) are responsible
27
- * to provide such data in the registrationMetadataProvider. This can be done
27
+ * The consuming apps using Cornerstone3D (OHIF, etc) MAY provide such data in
28
+ * the registrationMetadataProvider to override the data here. This can be done
28
29
  * by various methods 1) Using spatialRegistrationModule inside dicom 2) assuming
29
30
  * the user has actually manually scrolled the target viewport to the correct
30
31
  * slice before initiating the synchronization 3) using some other method
31
- * But overall, the consuming app is responsible for providing the data.
32
- *
33
32
  *
34
33
  * @param synchronizerInstance - The Instance of the Synchronizer
35
34
  * @param sourceViewport - The list of IDs defining the source viewport.
@@ -53,13 +52,16 @@ export default async function stackImageSyncCallback(
53
52
  sourceViewport.viewportId
54
53
  ) as Types.IStackViewport;
55
54
 
55
+ const options = synchronizerInstance.getOptions(targetViewport.viewportId);
56
+
57
+ if (options?.disabled) {
58
+ return;
59
+ }
60
+
56
61
  const tViewport = renderingEngine.getViewport(
57
62
  targetViewport.viewportId
58
63
  ) as Types.IStackViewport;
59
64
 
60
- const frameOfReferenceUID1 = sViewport.getFrameOfReferenceUID();
61
- const frameOfReferenceUID2 = tViewport.getFrameOfReferenceUID();
62
-
63
65
  const imageId1 = sViewport.getCurrentImageId();
64
66
  const imagePlaneModule1 = metaData.get('imagePlaneModule', imageId1);
65
67
  const sourceImagePositionPatient = imagePlaneModule1.imagePositionPatient;
@@ -70,69 +72,62 @@ export default async function stackImageSyncCallback(
70
72
  return;
71
73
  }
72
74
 
73
- if (frameOfReferenceUID1 === frameOfReferenceUID2) {
74
- // if frames of references are the same we can use the absolute
75
- // imagePositionPatient to find the closest image in the target viewport's stack
76
- const closestImageIdIndex = _getClosestImageIdIndex(
77
- sourceImagePositionPatient,
78
- targetImageIds
79
- );
75
+ // if the frame of reference is different we need to use the registrationMetadataProvider
76
+ // and add that to the imagePositionPatient of the source viewport to get the
77
+ // imagePositionPatient of the target viewport's closest image in its stack
78
+ let registrationMatrixMat4 = getSpatialRegistration(
79
+ targetViewport.viewportId,
80
+ sourceViewport.viewportId
81
+ );
80
82
 
83
+ if (!registrationMatrixMat4) {
84
+ const frameOfReferenceUID1 = sViewport.getFrameOfReferenceUID();
85
+ const frameOfReferenceUID2 = tViewport.getFrameOfReferenceUID();
81
86
  if (
82
- closestImageIdIndex.index !== -1 &&
83
- tViewport.getCurrentImageIdIndex() !== closestImageIdIndex.index
87
+ frameOfReferenceUID1 === frameOfReferenceUID2 &&
88
+ options.useInitialPosition !== false
84
89
  ) {
85
- // await tViewport.setImageIdIndex(closestImageIdIndex.index);
86
- await jumpToSlice(tViewport.element, {
87
- imageIndex: closestImageIdIndex.index,
88
- });
89
-
90
- return;
91
- }
92
- } else {
93
- // if the frame of reference is different we need to use the registrationMetadataProvider
94
- // and add that to the imagePositionPatient of the source viewport to get the
95
- // imagePositionPatient of the target viewport's closest image in its stack
96
- const registrationMatrixMat4 =
97
- utilities.spatialRegistrationMetadataProvider.get(
98
- 'spatialRegistrationModule',
99
- [targetViewport.viewportId, sourceViewport.viewportId]
90
+ registrationMatrixMat4 = mat4.identity(mat4.create());
91
+ } else {
92
+ utilities.calculateViewportsSpatialRegistration(sViewport, tViewport);
93
+ registrationMatrixMat4 = getSpatialRegistration(
94
+ targetViewport.viewportId,
95
+ sourceViewport.viewportId
100
96
  );
101
-
97
+ }
102
98
  if (!registrationMatrixMat4) {
103
- throw new Error(
104
- `No registration matrix found for sourceViewport: ${sourceViewport.viewportId} and targetViewport: ${targetViewport.viewportId}, viewports with different frameOfReferenceUIDs must have a registration matrix in the registrationMetadataProvider. Use calculateViewportsRegistrationMatrix to calculate the matrix.`
105
- );
99
+ return;
106
100
  }
101
+ }
107
102
 
108
- // apply the registration matrix to the source viewport's imagePositionPatient
109
- // to get the target viewport's imagePositionPatient
110
- const targetImagePositionPatientWithRegistrationMatrix = vec3.transformMat4(
111
- vec3.create(),
112
- sourceImagePositionPatient,
113
- registrationMatrixMat4
114
- );
103
+ // apply the registration matrix to the source viewport's imagePositionPatient
104
+ // to get the target viewport's imagePositionPatient
105
+ const targetImagePositionPatientWithRegistrationMatrix = vec3.transformMat4(
106
+ vec3.create(),
107
+ sourceImagePositionPatient,
108
+ registrationMatrixMat4
109
+ );
115
110
 
116
- // find the closest image in the target viewport's stack to the
117
- // targetImagePositionPatientWithRegistrationMatrix
118
- const closestImageIdIndex2 = _getClosestImageIdIndex(
119
- targetImagePositionPatientWithRegistrationMatrix,
120
- targetImageIds
121
- );
111
+ // find the closest image in the target viewport's stack to the
112
+ // targetImagePositionPatientWithRegistrationMatrix
113
+ const closestImageIdIndex2 = _getClosestImageIdIndex(
114
+ targetImagePositionPatientWithRegistrationMatrix,
115
+ targetImageIds
116
+ );
122
117
 
123
- if (
124
- closestImageIdIndex2.index !== -1 &&
125
- tViewport.getCurrentImageIdIndex() !== closestImageIdIndex2.index
126
- ) {
127
- await jumpToSlice(tViewport.element, {
128
- imageIndex: closestImageIdIndex2.index,
129
- });
130
- }
118
+ if (
119
+ closestImageIdIndex2.index !== -1 &&
120
+ tViewport.getCurrentImageIdIndex() !== closestImageIdIndex2.index
121
+ ) {
122
+ await jumpToSlice(tViewport.element, {
123
+ imageIndex: closestImageIdIndex2.index,
124
+ });
131
125
  }
132
126
  }
133
127
 
134
128
  function _getClosestImageIdIndex(targetPoint, imageIds) {
135
129
  // todo: this does not assume orientation yet, but that can be added later
130
+ // todo: handle multiframe images
136
131
  return imageIds.reduce(
137
132
  (closestImageIdIndex, imageId, index) => {
138
133
  const { imagePositionPatient } = metaData.get(
@@ -39,7 +39,7 @@ export default function voiSyncCallback(
39
39
  voiRange: range,
40
40
  };
41
41
 
42
- if (options.syncInvertState && invertStateChanged) {
42
+ if (options?.syncInvertState && invertStateChanged) {
43
43
  tProperties.invert = invert;
44
44
  }
45
45
 
@@ -808,7 +808,7 @@ class AngleTool extends AnnotationTool {
808
808
  );
809
809
 
810
810
  cachedStats[targetId] = {
811
- angle,
811
+ angle: isNaN(angle) ? 'Incomplete Angle' : angle,
812
812
  };
813
813
  }
814
814