@cornerstonejs/tools 1.70.6 → 1.70.7
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/dist/cjs/enums/Events.d.ts +2 -0
- package/dist/cjs/enums/Events.js +2 -0
- package/dist/cjs/enums/Events.js.map +1 -1
- package/dist/cjs/store/ToolGroupManager/ToolGroup.js +12 -0
- package/dist/cjs/store/ToolGroupManager/ToolGroup.js.map +1 -1
- package/dist/cjs/tools/OrientationMarkerTool.d.ts +0 -2
- package/dist/cjs/tools/OrientationMarkerTool.js +41 -27
- package/dist/cjs/tools/OrientationMarkerTool.js.map +1 -1
- package/dist/cjs/tools/annotation/BidirectionalTool.js +15 -8
- package/dist/cjs/tools/annotation/BidirectionalTool.js.map +1 -1
- package/dist/cjs/tools/annotation/CircleROITool.js +19 -18
- package/dist/cjs/tools/annotation/CircleROITool.js.map +1 -1
- package/dist/cjs/tools/annotation/EllipticalROITool.d.ts +1 -1
- package/dist/cjs/tools/annotation/EllipticalROITool.js +21 -20
- package/dist/cjs/tools/annotation/EllipticalROITool.js.map +1 -1
- package/dist/cjs/tools/annotation/PlanarFreehandROITool.js +27 -4
- package/dist/cjs/tools/annotation/PlanarFreehandROITool.js.map +1 -1
- package/dist/cjs/tools/annotation/RectangleROITool.js +18 -18
- package/dist/cjs/tools/annotation/RectangleROITool.js.map +1 -1
- package/dist/cjs/tools/annotation/SplineROITool.js +16 -2
- package/dist/cjs/tools/annotation/SplineROITool.js.map +1 -1
- package/dist/cjs/utilities/getCalibratedUnits.d.ts +1 -5
- package/dist/cjs/utilities/getCalibratedUnits.js +13 -45
- package/dist/cjs/utilities/getCalibratedUnits.js.map +1 -1
- package/dist/cjs/utilities/index.d.ts +2 -2
- package/dist/cjs/utilities/index.js +4 -4
- package/dist/cjs/utilities/index.js.map +1 -1
- package/dist/esm/enums/Events.js +2 -0
- package/dist/esm/enums/Events.js.map +1 -1
- package/dist/esm/store/ToolGroupManager/ToolGroup.js +12 -0
- package/dist/esm/store/ToolGroupManager/ToolGroup.js.map +1 -1
- package/dist/esm/tools/OrientationMarkerTool.js +42 -28
- package/dist/esm/tools/OrientationMarkerTool.js.map +1 -1
- package/dist/esm/tools/annotation/BidirectionalTool.js +16 -9
- package/dist/esm/tools/annotation/BidirectionalTool.js.map +1 -1
- package/dist/esm/tools/annotation/CircleROITool.js +21 -20
- package/dist/esm/tools/annotation/CircleROITool.js.map +1 -1
- package/dist/esm/tools/annotation/EllipticalROITool.js +23 -22
- package/dist/esm/tools/annotation/EllipticalROITool.js.map +1 -1
- package/dist/esm/tools/annotation/PlanarFreehandROITool.js +29 -6
- package/dist/esm/tools/annotation/PlanarFreehandROITool.js.map +1 -1
- package/dist/esm/tools/annotation/RectangleROITool.js +19 -19
- package/dist/esm/tools/annotation/RectangleROITool.js.map +1 -1
- package/dist/esm/tools/annotation/SplineROITool.js +17 -3
- package/dist/esm/tools/annotation/SplineROITool.js.map +1 -1
- package/dist/esm/utilities/getCalibratedUnits.js +13 -41
- package/dist/esm/utilities/getCalibratedUnits.js.map +1 -1
- package/dist/esm/utilities/index.js +2 -2
- package/dist/esm/utilities/index.js.map +1 -1
- package/dist/types/enums/Events.d.ts +2 -0
- package/dist/types/enums/Events.d.ts.map +1 -1
- package/dist/types/store/ToolGroupManager/ToolGroup.d.ts.map +1 -1
- package/dist/types/tools/OrientationMarkerTool.d.ts +0 -2
- package/dist/types/tools/OrientationMarkerTool.d.ts.map +1 -1
- package/dist/types/tools/annotation/BidirectionalTool.d.ts.map +1 -1
- package/dist/types/tools/annotation/CircleROITool.d.ts.map +1 -1
- package/dist/types/tools/annotation/EllipticalROITool.d.ts +1 -1
- package/dist/types/tools/annotation/EllipticalROITool.d.ts.map +1 -1
- package/dist/types/tools/annotation/PlanarFreehandROITool.d.ts.map +1 -1
- package/dist/types/tools/annotation/RectangleROITool.d.ts.map +1 -1
- package/dist/types/tools/annotation/SplineROITool.d.ts.map +1 -1
- package/dist/types/utilities/getCalibratedUnits.d.ts +1 -5
- package/dist/types/utilities/getCalibratedUnits.d.ts.map +1 -1
- package/dist/types/utilities/index.d.ts +2 -2
- package/dist/types/utilities/index.d.ts.map +1 -1
- package/dist/umd/index.js +1 -1
- package/dist/umd/index.js.map +1 -1
- package/package.json +3 -3
- package/src/enums/Events.ts +6 -0
- package/src/store/ToolGroupManager/ToolGroup.ts +16 -0
- package/src/tools/OrientationMarkerTool.ts +67 -49
- package/src/tools/annotation/BidirectionalTool.ts +28 -15
- package/src/tools/annotation/CircleROITool.ts +24 -25
- package/src/tools/annotation/EllipticalROITool.ts +28 -39
- package/src/tools/annotation/PlanarFreehandROITool.ts +56 -11
- package/src/tools/annotation/RectangleROITool.ts +23 -23
- package/src/tools/annotation/SplineROITool.ts +36 -4
- package/src/utilities/getCalibratedUnits.ts +18 -74
- package/src/utilities/index.ts +6 -6
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cornerstonejs/tools",
|
|
3
|
-
"version": "1.70.
|
|
3
|
+
"version": "1.70.7",
|
|
4
4
|
"description": "Cornerstone3D Tools",
|
|
5
5
|
"main": "src/index.ts",
|
|
6
6
|
"types": "dist/types/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.70.
|
|
32
|
+
"@cornerstonejs/core": "^1.70.7",
|
|
33
33
|
"@icr/polyseg-wasm": "0.4.0",
|
|
34
34
|
"@types/offscreencanvas": "2019.7.3",
|
|
35
35
|
"comlink": "^4.4.1",
|
|
@@ -59,5 +59,5 @@
|
|
|
59
59
|
"type": "individual",
|
|
60
60
|
"url": "https://ohif.org/donate"
|
|
61
61
|
},
|
|
62
|
-
"gitHead": "
|
|
62
|
+
"gitHead": "4b6774d20ea66e2fa2815edc042b57565b816959"
|
|
63
63
|
}
|
package/src/enums/Events.ts
CHANGED
|
@@ -18,6 +18,12 @@ enum Events {
|
|
|
18
18
|
*/
|
|
19
19
|
TOOL_ACTIVATED = 'CORNERSTONE_TOOLS_TOOL_ACTIVATED',
|
|
20
20
|
|
|
21
|
+
// fired when a viewport is added to the toolGroup
|
|
22
|
+
TOOLGROUP_VIEWPORT_ADDED = 'CORNERSTONE_TOOLS_TOOLGROUP_VIEWPORT_ADDED',
|
|
23
|
+
|
|
24
|
+
// fired when a viewport is removed from the toolGroup
|
|
25
|
+
TOOLGROUP_VIEWPORT_REMOVED = 'CORNERSTONE_TOOLS_TOOLGROUP_VIEWPORT_REMOVED',
|
|
26
|
+
|
|
21
27
|
/**
|
|
22
28
|
* Triggers on the eventTarget when a mode of a tool is changed (active, passive, enabled and disabled).
|
|
23
29
|
*
|
|
@@ -239,6 +239,14 @@ export default class ToolGroup implements IToolGroup {
|
|
|
239
239
|
if (runtimeSettings.get('useCursors')) {
|
|
240
240
|
this.setViewportsCursorByToolName(toolName);
|
|
241
241
|
}
|
|
242
|
+
|
|
243
|
+
const eventDetail = {
|
|
244
|
+
toolGroupId: this.id,
|
|
245
|
+
viewportId,
|
|
246
|
+
renderingEngineId: renderingEngineUIDToUse,
|
|
247
|
+
};
|
|
248
|
+
|
|
249
|
+
triggerEvent(eventTarget, Events.TOOLGROUP_VIEWPORT_ADDED, eventDetail);
|
|
242
250
|
}
|
|
243
251
|
|
|
244
252
|
/**
|
|
@@ -273,6 +281,14 @@ export default class ToolGroup implements IToolGroup {
|
|
|
273
281
|
this.viewportsInfo.splice(indices[i], 1);
|
|
274
282
|
}
|
|
275
283
|
}
|
|
284
|
+
|
|
285
|
+
const eventDetail = {
|
|
286
|
+
toolGroupId: this.id,
|
|
287
|
+
viewportId,
|
|
288
|
+
renderingEngineId,
|
|
289
|
+
};
|
|
290
|
+
|
|
291
|
+
triggerEvent(eventTarget, Events.TOOLGROUP_VIEWPORT_REMOVED, eventDetail);
|
|
276
292
|
}
|
|
277
293
|
|
|
278
294
|
public setActiveStrategy(toolName: string, strategyName: string) {
|
|
@@ -9,11 +9,13 @@ import vtkPolyData from '@kitware/vtk.js/Common/DataModel/PolyData';
|
|
|
9
9
|
import { BaseTool } from './base';
|
|
10
10
|
import {
|
|
11
11
|
Enums,
|
|
12
|
+
eventTarget,
|
|
12
13
|
getEnabledElementByIds,
|
|
13
14
|
getRenderingEngines,
|
|
14
15
|
} from '@cornerstonejs/core';
|
|
15
16
|
import { filterViewportsWithToolEnabled } from '../utilities/viewportFilters';
|
|
16
17
|
import { getToolGroup } from '../store/ToolGroupManager';
|
|
18
|
+
import { Events } from '../enums';
|
|
17
19
|
|
|
18
20
|
const OverlayMarkerType = {
|
|
19
21
|
ANNOTATED_CUBE: 1,
|
|
@@ -36,8 +38,6 @@ class OrientationMarkerTool extends BaseTool {
|
|
|
36
38
|
|
|
37
39
|
static OVERLAY_MARKER_TYPES = OverlayMarkerType;
|
|
38
40
|
|
|
39
|
-
configuration_invalidated = true;
|
|
40
|
-
|
|
41
41
|
constructor(
|
|
42
42
|
toolProps = {},
|
|
43
43
|
defaultToolProps = {
|
|
@@ -88,18 +88,16 @@ class OrientationMarkerTool extends BaseTool {
|
|
|
88
88
|
) {
|
|
89
89
|
super(toolProps, defaultToolProps);
|
|
90
90
|
this.orientationMarkers = {};
|
|
91
|
-
this.configuration_invalidated = true;
|
|
92
91
|
}
|
|
93
92
|
|
|
94
93
|
onSetToolEnabled = (): void => {
|
|
95
94
|
this.initViewports();
|
|
96
|
-
this.configuration_invalidated = true;
|
|
97
95
|
this._subscribeToViewportEvents();
|
|
98
96
|
};
|
|
99
97
|
|
|
100
98
|
onSetToolActive = (): void => {
|
|
101
99
|
this.initViewports();
|
|
102
|
-
|
|
100
|
+
|
|
103
101
|
this._subscribeToViewportEvents();
|
|
104
102
|
};
|
|
105
103
|
|
|
@@ -108,11 +106,6 @@ class OrientationMarkerTool extends BaseTool {
|
|
|
108
106
|
this._unsubscribeToViewportNewVolumeSet();
|
|
109
107
|
};
|
|
110
108
|
|
|
111
|
-
reset = () => {
|
|
112
|
-
this.configuration_invalidated = true;
|
|
113
|
-
this.initViewports();
|
|
114
|
-
};
|
|
115
|
-
|
|
116
109
|
_getViewportsInfo = () => {
|
|
117
110
|
const viewports = getToolGroup(this.toolGroupId).viewportsInfo;
|
|
118
111
|
|
|
@@ -130,50 +123,77 @@ class OrientationMarkerTool extends BaseTool {
|
|
|
130
123
|
};
|
|
131
124
|
|
|
132
125
|
_unsubscribeToViewportNewVolumeSet() {
|
|
133
|
-
const
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
126
|
+
const unsubscribe = () => {
|
|
127
|
+
const viewportsInfo = this._getViewportsInfo();
|
|
128
|
+
viewportsInfo.forEach(({ viewportId, renderingEngineId }) => {
|
|
129
|
+
const { viewport } = getEnabledElementByIds(
|
|
130
|
+
viewportId,
|
|
131
|
+
renderingEngineId
|
|
132
|
+
);
|
|
133
|
+
const { element } = viewport;
|
|
134
|
+
|
|
135
|
+
element.removeEventListener(
|
|
136
|
+
Enums.Events.VOLUME_VIEWPORT_NEW_VOLUME,
|
|
137
|
+
this.initViewports.bind(this)
|
|
138
|
+
);
|
|
139
|
+
|
|
140
|
+
const resizeObserver = this._resizeObservers.get(viewportId);
|
|
141
|
+
resizeObserver.unobserve(element);
|
|
142
|
+
});
|
|
143
|
+
};
|
|
144
|
+
|
|
145
|
+
eventTarget.removeEventListener(Events.TOOLGROUP_VIEWPORT_ADDED, (evt) => {
|
|
146
|
+
if (evt.detail.toolGroupId !== this.toolGroupId) {
|
|
147
|
+
return;
|
|
148
|
+
}
|
|
149
|
+
unsubscribe();
|
|
150
|
+
this.initViewports();
|
|
149
151
|
});
|
|
150
152
|
}
|
|
151
153
|
|
|
152
154
|
_subscribeToViewportEvents() {
|
|
153
|
-
const
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
155
|
+
const subscribeToElementResize = () => {
|
|
156
|
+
const viewportsInfo = this._getViewportsInfo();
|
|
157
|
+
viewportsInfo.forEach(({ viewportId, renderingEngineId }) => {
|
|
158
|
+
const { viewport } = getEnabledElementByIds(
|
|
159
|
+
viewportId,
|
|
160
|
+
renderingEngineId
|
|
161
|
+
);
|
|
162
|
+
const { element } = viewport;
|
|
163
|
+
this.initViewports();
|
|
164
|
+
|
|
165
|
+
element.addEventListener(
|
|
166
|
+
Enums.Events.VOLUME_VIEWPORT_NEW_VOLUME,
|
|
167
|
+
this.initViewports.bind(this)
|
|
168
|
+
);
|
|
169
|
+
|
|
170
|
+
const resizeObserver = new ResizeObserver(() => {
|
|
171
|
+
// Todo: i wish there was a better way to do this
|
|
172
|
+
setTimeout(() => {
|
|
173
|
+
const { viewport } = getEnabledElementByIds(
|
|
174
|
+
viewportId,
|
|
175
|
+
renderingEngineId
|
|
176
|
+
);
|
|
177
|
+
this.resize(viewportId);
|
|
178
|
+
viewport.render();
|
|
179
|
+
}, 100);
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
resizeObserver.observe(element);
|
|
183
|
+
|
|
184
|
+
this._resizeObservers.set(viewportId, resizeObserver);
|
|
172
185
|
});
|
|
186
|
+
};
|
|
173
187
|
|
|
174
|
-
|
|
188
|
+
subscribeToElementResize();
|
|
175
189
|
|
|
176
|
-
|
|
190
|
+
eventTarget.addEventListener(Events.TOOLGROUP_VIEWPORT_ADDED, (evt) => {
|
|
191
|
+
if (evt.detail.toolGroupId !== this.toolGroupId) {
|
|
192
|
+
return;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
subscribeToElementResize();
|
|
196
|
+
this.initViewports();
|
|
177
197
|
});
|
|
178
198
|
}
|
|
179
199
|
|
|
@@ -276,8 +296,6 @@ class OrientationMarkerTool extends BaseTool {
|
|
|
276
296
|
viewport.addWidget(this.getToolName(), orientationWidget);
|
|
277
297
|
renderWindow.render();
|
|
278
298
|
viewport.getRenderingEngine().render();
|
|
279
|
-
|
|
280
|
-
this.configuration_invalidated = false;
|
|
281
299
|
}
|
|
282
300
|
|
|
283
301
|
private async createCustomActor() {
|
|
@@ -2,10 +2,7 @@ import { vec2, vec3 } from 'gl-matrix';
|
|
|
2
2
|
import { getEnabledElement, utilities as csUtils } from '@cornerstonejs/core';
|
|
3
3
|
import type { Types } from '@cornerstonejs/core';
|
|
4
4
|
|
|
5
|
-
import {
|
|
6
|
-
getCalibratedLengthUnits,
|
|
7
|
-
getCalibratedScale,
|
|
8
|
-
} from '../../utilities/getCalibratedUnits';
|
|
5
|
+
import { getCalibratedLengthUnitsAndScale } from '../../utilities/getCalibratedUnits';
|
|
9
6
|
import { roundNumber } from '../../utilities';
|
|
10
7
|
import { AnnotationTool } from '../base';
|
|
11
8
|
import throttle from '../../utilities/throttle';
|
|
@@ -40,7 +37,6 @@ import {
|
|
|
40
37
|
TextBoxHandle,
|
|
41
38
|
PublicToolProps,
|
|
42
39
|
ToolProps,
|
|
43
|
-
InteractionTypes,
|
|
44
40
|
SVGDrawingHelper,
|
|
45
41
|
} from '../../types';
|
|
46
42
|
import { BidirectionalAnnotation } from '../../types/ToolSpecificAnnotationTypes';
|
|
@@ -1272,17 +1268,32 @@ class BidirectionalTool extends AnnotationTool {
|
|
|
1272
1268
|
}
|
|
1273
1269
|
|
|
1274
1270
|
const { imageData, dimensions } = image;
|
|
1275
|
-
const scale = getCalibratedScale(image);
|
|
1276
|
-
const dist1 = this._calculateLength(worldPos1, worldPos2) / scale;
|
|
1277
|
-
const dist2 = this._calculateLength(worldPos3, worldPos4) / scale;
|
|
1278
|
-
const length = dist1 > dist2 ? dist1 : dist2;
|
|
1279
|
-
const width = dist1 > dist2 ? dist2 : dist1;
|
|
1280
|
-
|
|
1281
1271
|
const index1 = transformWorldToIndex(imageData, worldPos1);
|
|
1282
1272
|
const index2 = transformWorldToIndex(imageData, worldPos2);
|
|
1283
1273
|
const index3 = transformWorldToIndex(imageData, worldPos3);
|
|
1284
1274
|
const index4 = transformWorldToIndex(imageData, worldPos4);
|
|
1285
1275
|
|
|
1276
|
+
const handles1 = [index1, index2];
|
|
1277
|
+
const handles2 = [index3, index4];
|
|
1278
|
+
|
|
1279
|
+
const { scale: scale1, units: units1 } = getCalibratedLengthUnitsAndScale(
|
|
1280
|
+
image,
|
|
1281
|
+
handles1
|
|
1282
|
+
);
|
|
1283
|
+
|
|
1284
|
+
const { scale: scale2, units: units2 } = getCalibratedLengthUnitsAndScale(
|
|
1285
|
+
image,
|
|
1286
|
+
handles2
|
|
1287
|
+
);
|
|
1288
|
+
|
|
1289
|
+
const dist1 = this._calculateLength(worldPos1, worldPos2) / scale1;
|
|
1290
|
+
const dist2 = this._calculateLength(worldPos3, worldPos4) / scale2;
|
|
1291
|
+
const length = dist1 > dist2 ? dist1 : dist2;
|
|
1292
|
+
const width = dist1 > dist2 ? dist2 : dist1;
|
|
1293
|
+
|
|
1294
|
+
const lengthUnit = dist1 > dist2 ? units1 : units2;
|
|
1295
|
+
const widthUnit = dist1 > dist2 ? units2 : units1;
|
|
1296
|
+
|
|
1286
1297
|
this._isInsideVolume(index1, index2, index3, index4, dimensions)
|
|
1287
1298
|
? (this.isHandleOutsideImage = false)
|
|
1288
1299
|
: (this.isHandleOutsideImage = true);
|
|
@@ -1290,7 +1301,9 @@ class BidirectionalTool extends AnnotationTool {
|
|
|
1290
1301
|
cachedStats[targetId] = {
|
|
1291
1302
|
length,
|
|
1292
1303
|
width,
|
|
1293
|
-
unit:
|
|
1304
|
+
unit: units1,
|
|
1305
|
+
lengthUnit,
|
|
1306
|
+
widthUnit,
|
|
1294
1307
|
};
|
|
1295
1308
|
}
|
|
1296
1309
|
|
|
@@ -1321,7 +1334,7 @@ class BidirectionalTool extends AnnotationTool {
|
|
|
1321
1334
|
|
|
1322
1335
|
function defaultGetTextLines(data, targetId): string[] {
|
|
1323
1336
|
const { cachedStats, label } = data;
|
|
1324
|
-
const { length, width, unit } = cachedStats[targetId];
|
|
1337
|
+
const { length, width, unit, lengthUnit, widthUnit } = cachedStats[targetId];
|
|
1325
1338
|
|
|
1326
1339
|
const textLines = [];
|
|
1327
1340
|
if (label) {
|
|
@@ -1334,8 +1347,8 @@ function defaultGetTextLines(data, targetId): string[] {
|
|
|
1334
1347
|
// spaceBetweenSlices & pixelSpacing &
|
|
1335
1348
|
// magnitude in each direction? Otherwise, this is "px"?
|
|
1336
1349
|
textLines.push(
|
|
1337
|
-
`L: ${roundNumber(length)} ${unit}`,
|
|
1338
|
-
`W: ${roundNumber(width)} ${unit}`
|
|
1350
|
+
`L: ${roundNumber(length)} ${lengthUnit || unit}`,
|
|
1351
|
+
`W: ${roundNumber(width)} ${widthUnit || unit}`
|
|
1339
1352
|
);
|
|
1340
1353
|
|
|
1341
1354
|
return textLines;
|
|
@@ -7,13 +7,8 @@ import {
|
|
|
7
7
|
} from '@cornerstonejs/core';
|
|
8
8
|
import type { Types } from '@cornerstonejs/core';
|
|
9
9
|
|
|
10
|
-
import {
|
|
11
|
-
|
|
12
|
-
getCalibratedAreaUnits,
|
|
13
|
-
getCalibratedScale,
|
|
14
|
-
getCalibratedAspect,
|
|
15
|
-
} from '../../utilities/getCalibratedUnits';
|
|
16
|
-
import { roundNumber } from '../../utilities';
|
|
10
|
+
import { getCalibratedAspect } from '../../utilities/getCalibratedUnits';
|
|
11
|
+
import { getCalibratedLengthUnitsAndScale, roundNumber } from '../../utilities';
|
|
17
12
|
import throttle from '../../utilities/throttle';
|
|
18
13
|
import {
|
|
19
14
|
addAnnotation,
|
|
@@ -891,30 +886,30 @@ class CircleROITool extends AnnotationTool {
|
|
|
891
886
|
|
|
892
887
|
const { dimensions, imageData, metadata, hasPixelSpacing } = image;
|
|
893
888
|
|
|
894
|
-
const
|
|
889
|
+
const pos1Index = transformWorldToIndex(imageData, worldPos1);
|
|
895
890
|
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
891
|
+
pos1Index[0] = Math.floor(pos1Index[0]);
|
|
892
|
+
pos1Index[1] = Math.floor(pos1Index[1]);
|
|
893
|
+
pos1Index[2] = Math.floor(pos1Index[2]);
|
|
899
894
|
|
|
900
|
-
const
|
|
895
|
+
const pos2Index = transformWorldToIndex(imageData, worldPos2);
|
|
901
896
|
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
897
|
+
pos2Index[0] = Math.floor(pos2Index[0]);
|
|
898
|
+
pos2Index[1] = Math.floor(pos2Index[1]);
|
|
899
|
+
pos2Index[2] = Math.floor(pos2Index[2]);
|
|
905
900
|
|
|
906
901
|
// Check if one of the indexes are inside the volume, this then gives us
|
|
907
902
|
// Some area to do stats over.
|
|
908
903
|
|
|
909
|
-
if (this._isInsideVolume(
|
|
910
|
-
const iMin = Math.min(
|
|
911
|
-
const iMax = Math.max(
|
|
904
|
+
if (this._isInsideVolume(pos1Index, pos2Index, dimensions)) {
|
|
905
|
+
const iMin = Math.min(pos1Index[0], pos2Index[0]);
|
|
906
|
+
const iMax = Math.max(pos1Index[0], pos2Index[0]);
|
|
912
907
|
|
|
913
|
-
const jMin = Math.min(
|
|
914
|
-
const jMax = Math.max(
|
|
908
|
+
const jMin = Math.min(pos1Index[1], pos2Index[1]);
|
|
909
|
+
const jMax = Math.max(pos1Index[1], pos2Index[1]);
|
|
915
910
|
|
|
916
|
-
const kMin = Math.min(
|
|
917
|
-
const kMax = Math.max(
|
|
911
|
+
const kMin = Math.min(pos1Index[2], pos2Index[2]);
|
|
912
|
+
const kMax = Math.max(pos1Index[2], pos2Index[2]);
|
|
918
913
|
|
|
919
914
|
const boundsIJK = [
|
|
920
915
|
[iMin, iMax],
|
|
@@ -942,7 +937,11 @@ class CircleROITool extends AnnotationTool {
|
|
|
942
937
|
worldPos2
|
|
943
938
|
);
|
|
944
939
|
const isEmptyArea = worldWidth === 0 && worldHeight === 0;
|
|
945
|
-
const
|
|
940
|
+
const handles = [pos1Index, pos2Index];
|
|
941
|
+
const { scale, units, areaUnits } = getCalibratedLengthUnitsAndScale(
|
|
942
|
+
image,
|
|
943
|
+
handles
|
|
944
|
+
);
|
|
946
945
|
const aspect = getCalibratedAspect(image);
|
|
947
946
|
const area = Math.abs(
|
|
948
947
|
Math.PI *
|
|
@@ -986,9 +985,9 @@ class CircleROITool extends AnnotationTool {
|
|
|
986
985
|
statsArray: stats.array,
|
|
987
986
|
pointsInShape: pointsInShape,
|
|
988
987
|
isEmptyArea,
|
|
989
|
-
areaUnit:
|
|
988
|
+
areaUnit: areaUnits,
|
|
990
989
|
radius: worldWidth / 2 / scale,
|
|
991
|
-
radiusUnit:
|
|
990
|
+
radiusUnit: units,
|
|
992
991
|
perimeter: (2 * Math.PI * (worldWidth / 2)) / scale,
|
|
993
992
|
modalityUnit,
|
|
994
993
|
};
|
|
@@ -7,10 +7,7 @@ import {
|
|
|
7
7
|
} from '@cornerstonejs/core';
|
|
8
8
|
import type { Types } from '@cornerstonejs/core';
|
|
9
9
|
|
|
10
|
-
import {
|
|
11
|
-
getCalibratedAreaUnits,
|
|
12
|
-
getCalibratedScale,
|
|
13
|
-
} from '../../utilities/getCalibratedUnits';
|
|
10
|
+
import { getCalibratedLengthUnitsAndScale } from '../../utilities/getCalibratedUnits';
|
|
14
11
|
import { roundNumber } from '../../utilities';
|
|
15
12
|
import throttle from '../../utilities/throttle';
|
|
16
13
|
import {
|
|
@@ -56,10 +53,7 @@ import { EllipticalROIAnnotation } from '../../types/ToolSpecificAnnotationTypes
|
|
|
56
53
|
import triggerAnnotationRenderForViewportIds from '../../utilities/triggerAnnotationRenderForViewportIds';
|
|
57
54
|
import { pointInShapeCallback } from '../../utilities/';
|
|
58
55
|
import { StyleSpecifier } from '../../types/AnnotationStyle';
|
|
59
|
-
import {
|
|
60
|
-
ModalityUnitOptions,
|
|
61
|
-
getModalityUnit,
|
|
62
|
-
} from '../../utilities/getModalityUnit';
|
|
56
|
+
import { getModalityUnit } from '../../utilities/getModalityUnit';
|
|
63
57
|
import { isViewportPreScaled } from '../../utilities/viewport/isViewportPreScaled';
|
|
64
58
|
import { BasicStatsCalculator } from '../../utilities/math/basic';
|
|
65
59
|
|
|
@@ -791,12 +785,7 @@ class EllipticalROITool extends AnnotationTool {
|
|
|
791
785
|
areaUnit: null,
|
|
792
786
|
};
|
|
793
787
|
|
|
794
|
-
this._calculateCachedStats(
|
|
795
|
-
annotation,
|
|
796
|
-
viewport,
|
|
797
|
-
renderingEngine,
|
|
798
|
-
enabledElement
|
|
799
|
-
);
|
|
788
|
+
this._calculateCachedStats(annotation, viewport, renderingEngine);
|
|
800
789
|
} else if (annotation.invalidated) {
|
|
801
790
|
this._throttledCalculateCachedStats(
|
|
802
791
|
annotation,
|
|
@@ -972,12 +961,7 @@ class EllipticalROITool extends AnnotationTool {
|
|
|
972
961
|
return renderStatus;
|
|
973
962
|
};
|
|
974
963
|
|
|
975
|
-
_calculateCachedStats = (
|
|
976
|
-
annotation,
|
|
977
|
-
viewport,
|
|
978
|
-
renderingEngine,
|
|
979
|
-
enabledElement
|
|
980
|
-
) => {
|
|
964
|
+
_calculateCachedStats = (annotation, viewport, renderingEngine) => {
|
|
981
965
|
const data = annotation.data;
|
|
982
966
|
const { element } = viewport;
|
|
983
967
|
|
|
@@ -1010,34 +994,34 @@ class EllipticalROITool extends AnnotationTool {
|
|
|
1010
994
|
continue;
|
|
1011
995
|
}
|
|
1012
996
|
|
|
1013
|
-
const { dimensions, imageData, metadata
|
|
997
|
+
const { dimensions, imageData, metadata } = image;
|
|
1014
998
|
|
|
1015
|
-
const
|
|
999
|
+
const pos1Index = transformWorldToIndex(imageData, worldPos1);
|
|
1016
1000
|
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1001
|
+
pos1Index[0] = Math.floor(pos1Index[0]);
|
|
1002
|
+
pos1Index[1] = Math.floor(pos1Index[1]);
|
|
1003
|
+
pos1Index[2] = Math.floor(pos1Index[2]);
|
|
1020
1004
|
|
|
1021
|
-
const
|
|
1005
|
+
const post2Index = transformWorldToIndex(imageData, worldPos2);
|
|
1022
1006
|
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1007
|
+
post2Index[0] = Math.floor(post2Index[0]);
|
|
1008
|
+
post2Index[1] = Math.floor(post2Index[1]);
|
|
1009
|
+
post2Index[2] = Math.floor(post2Index[2]);
|
|
1026
1010
|
|
|
1027
1011
|
// Check if one of the indexes are inside the volume, this then gives us
|
|
1028
1012
|
// Some area to do stats over.
|
|
1029
1013
|
|
|
1030
|
-
if (this._isInsideVolume(
|
|
1014
|
+
if (this._isInsideVolume(pos1Index, post2Index, dimensions)) {
|
|
1031
1015
|
this.isHandleOutsideImage = false;
|
|
1032
1016
|
|
|
1033
|
-
const iMin = Math.min(
|
|
1034
|
-
const iMax = Math.max(
|
|
1017
|
+
const iMin = Math.min(pos1Index[0], post2Index[0]);
|
|
1018
|
+
const iMax = Math.max(pos1Index[0], post2Index[0]);
|
|
1035
1019
|
|
|
1036
|
-
const jMin = Math.min(
|
|
1037
|
-
const jMax = Math.max(
|
|
1020
|
+
const jMin = Math.min(pos1Index[1], post2Index[1]);
|
|
1021
|
+
const jMax = Math.max(pos1Index[1], post2Index[1]);
|
|
1038
1022
|
|
|
1039
|
-
const kMin = Math.min(
|
|
1040
|
-
const kMax = Math.max(
|
|
1023
|
+
const kMin = Math.min(pos1Index[2], post2Index[2]);
|
|
1024
|
+
const kMax = Math.max(pos1Index[2], post2Index[2]);
|
|
1041
1025
|
|
|
1042
1026
|
const boundsIJK = [
|
|
1043
1027
|
[iMin, iMax],
|
|
@@ -1065,7 +1049,13 @@ class EllipticalROITool extends AnnotationTool {
|
|
|
1065
1049
|
worldPos2
|
|
1066
1050
|
);
|
|
1067
1051
|
const isEmptyArea = worldWidth === 0 && worldHeight === 0;
|
|
1068
|
-
|
|
1052
|
+
|
|
1053
|
+
const handles = [pos1Index, post2Index];
|
|
1054
|
+
const { scale, areaUnits } = getCalibratedLengthUnitsAndScale(
|
|
1055
|
+
image,
|
|
1056
|
+
handles
|
|
1057
|
+
);
|
|
1058
|
+
|
|
1069
1059
|
const area =
|
|
1070
1060
|
Math.abs(Math.PI * (worldWidth / 2) * (worldHeight / 2)) /
|
|
1071
1061
|
scale /
|
|
@@ -1095,7 +1085,6 @@ class EllipticalROITool extends AnnotationTool {
|
|
|
1095
1085
|
);
|
|
1096
1086
|
|
|
1097
1087
|
const stats = this.configuration.statsCalculator.getStatistics();
|
|
1098
|
-
|
|
1099
1088
|
cachedStats[targetId] = {
|
|
1100
1089
|
Modality: metadata.Modality,
|
|
1101
1090
|
area,
|
|
@@ -1105,7 +1094,7 @@ class EllipticalROITool extends AnnotationTool {
|
|
|
1105
1094
|
statsArray: stats.array,
|
|
1106
1095
|
pointsInShape,
|
|
1107
1096
|
isEmptyArea,
|
|
1108
|
-
areaUnit:
|
|
1097
|
+
areaUnit: areaUnits,
|
|
1109
1098
|
modalityUnit,
|
|
1110
1099
|
};
|
|
1111
1100
|
} else {
|
|
@@ -7,11 +7,8 @@ import {
|
|
|
7
7
|
import type { Types } from '@cornerstonejs/core';
|
|
8
8
|
import { vec3 } from 'gl-matrix';
|
|
9
9
|
|
|
10
|
-
import {
|
|
11
|
-
|
|
12
|
-
getCalibratedScale,
|
|
13
|
-
} from '../../utilities/getCalibratedUnits';
|
|
14
|
-
import { roundNumber } from '../../utilities';
|
|
10
|
+
import { getCalibratedLengthUnitsAndScale } from '../../utilities/getCalibratedUnits';
|
|
11
|
+
import { math, roundNumber } from '../../utilities';
|
|
15
12
|
import { polyline } from '../../utilities/math';
|
|
16
13
|
import { filterAnnotationsForDisplay } from '../../utilities/planar';
|
|
17
14
|
import throttle from '../../utilities/throttle';
|
|
@@ -727,11 +724,6 @@ class PlanarFreehandROITool extends ContourSegmentationBaseTool {
|
|
|
727
724
|
const deltaInX = vec3.distance(originalWorldPoint, deltaXPoint);
|
|
728
725
|
const deltaInY = vec3.distance(originalWorldPoint, deltaYPoint);
|
|
729
726
|
|
|
730
|
-
const scale = getCalibratedScale(image);
|
|
731
|
-
let area = polyline.getArea(canvasCoordinates) / scale / scale;
|
|
732
|
-
// Convert from canvas_pixels ^2 to mm^2
|
|
733
|
-
area *= deltaInX * deltaInY;
|
|
734
|
-
|
|
735
727
|
const worldPosIndex = csUtils.transformWorldToIndex(imageData, points[0]);
|
|
736
728
|
worldPosIndex[0] = Math.floor(worldPosIndex[0]);
|
|
737
729
|
worldPosIndex[1] = Math.floor(worldPosIndex[1]);
|
|
@@ -764,6 +756,59 @@ class PlanarFreehandROITool extends ContourSegmentationBaseTool {
|
|
|
764
756
|
kMax = Math.max(kMax, worldPosIndex[2]);
|
|
765
757
|
}
|
|
766
758
|
|
|
759
|
+
const worldPosIndex2 = csUtils.transformWorldToIndex(
|
|
760
|
+
imageData,
|
|
761
|
+
points[1]
|
|
762
|
+
);
|
|
763
|
+
worldPosIndex2[0] = Math.floor(worldPosIndex2[0]);
|
|
764
|
+
worldPosIndex2[1] = Math.floor(worldPosIndex2[1]);
|
|
765
|
+
worldPosIndex2[2] = Math.floor(worldPosIndex2[2]);
|
|
766
|
+
|
|
767
|
+
const { scale, areaUnits } = getCalibratedLengthUnitsAndScale(
|
|
768
|
+
image,
|
|
769
|
+
() => {
|
|
770
|
+
const polyline = data.contour.polyline;
|
|
771
|
+
const numPoints = polyline.length;
|
|
772
|
+
const projectedPolyline = new Array(numPoints);
|
|
773
|
+
|
|
774
|
+
for (let i = 0; i < numPoints; i++) {
|
|
775
|
+
projectedPolyline[i] = viewport.worldToCanvas(polyline[i]);
|
|
776
|
+
}
|
|
777
|
+
|
|
778
|
+
const {
|
|
779
|
+
maxX: canvasMaxX,
|
|
780
|
+
maxY: canvasMaxY,
|
|
781
|
+
minX: canvasMinX,
|
|
782
|
+
minY: canvasMinY,
|
|
783
|
+
} = math.polyline.getAABB(projectedPolyline);
|
|
784
|
+
|
|
785
|
+
const topLeftBBWorld = viewport.canvasToWorld([
|
|
786
|
+
canvasMinX,
|
|
787
|
+
canvasMinY,
|
|
788
|
+
]);
|
|
789
|
+
|
|
790
|
+
const topLeftBBIndex = csUtils.transformWorldToIndex(
|
|
791
|
+
imageData,
|
|
792
|
+
topLeftBBWorld
|
|
793
|
+
);
|
|
794
|
+
|
|
795
|
+
const bottomRightBBWorld = viewport.canvasToWorld([
|
|
796
|
+
canvasMaxX,
|
|
797
|
+
canvasMaxY,
|
|
798
|
+
]);
|
|
799
|
+
|
|
800
|
+
const bottomRightBBIndex = csUtils.transformWorldToIndex(
|
|
801
|
+
imageData,
|
|
802
|
+
bottomRightBBWorld
|
|
803
|
+
);
|
|
804
|
+
|
|
805
|
+
return [topLeftBBIndex, bottomRightBBIndex];
|
|
806
|
+
}
|
|
807
|
+
);
|
|
808
|
+
let area = polyline.getArea(canvasCoordinates) / scale / scale;
|
|
809
|
+
// Convert from canvas_pixels ^2 to mm^2
|
|
810
|
+
area *= deltaInX * deltaInY;
|
|
811
|
+
|
|
767
812
|
// Expand bounding box
|
|
768
813
|
const iDelta = 0.01 * (iMax - iMin);
|
|
769
814
|
const jDelta = 0.01 * (jMax - jMin);
|
|
@@ -852,7 +897,7 @@ class PlanarFreehandROITool extends ContourSegmentationBaseTool {
|
|
|
852
897
|
stdDev: stats.stdDev?.value,
|
|
853
898
|
statsArray: stats.array,
|
|
854
899
|
pointsInShape: pointsInShape,
|
|
855
|
-
areaUnit:
|
|
900
|
+
areaUnit: areaUnits,
|
|
856
901
|
modalityUnit,
|
|
857
902
|
};
|
|
858
903
|
}
|