@cornerstonejs/tools 3.25.0 → 3.26.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.
- package/dist/esm/tools/annotation/CircleROITool.js +93 -53
- package/dist/esm/tools/segmentation/CircleROIStartEndThresholdTool.d.ts +1 -1
- package/dist/esm/tools/segmentation/CircleROIStartEndThresholdTool.js +62 -46
- package/dist/esm/types/ToolSpecificAnnotationTypes.d.ts +8 -2
- package/dist/esm/version.d.ts +1 -1
- package/dist/esm/version.js +1 -1
- package/package.json +3 -3
|
@@ -19,6 +19,7 @@ import { isViewportPreScaled } from '../../utilities/viewport/isViewportPreScale
|
|
|
19
19
|
import { getCanvasCircleCorners, getCanvasCircleRadius, } from '../../utilities/math/circle';
|
|
20
20
|
import { pointInEllipse } from '../../utilities/math/ellipse';
|
|
21
21
|
import { BasicStatsCalculator } from '../../utilities/math/basic';
|
|
22
|
+
import { vec2, vec3 } from 'gl-matrix';
|
|
22
23
|
const { transformWorldToIndex } = csUtils;
|
|
23
24
|
class CircleROITool extends AnnotationTool {
|
|
24
25
|
static { this.toolName = 'CircleROI'; }
|
|
@@ -32,6 +33,7 @@ class CircleROITool extends AnnotationTool {
|
|
|
32
33
|
calculateStats: true,
|
|
33
34
|
getTextLines: defaultGetTextLines,
|
|
34
35
|
statsCalculator: BasicStatsCalculator,
|
|
36
|
+
simplified: true,
|
|
35
37
|
},
|
|
36
38
|
}) {
|
|
37
39
|
super(toolProps, defaultToolProps);
|
|
@@ -41,12 +43,25 @@ class CircleROITool extends AnnotationTool {
|
|
|
41
43
|
const { currentPoints, element } = eventDetail;
|
|
42
44
|
const worldPos = currentPoints.world;
|
|
43
45
|
const enabledElement = getEnabledElement(element);
|
|
44
|
-
const { viewport
|
|
46
|
+
const { viewport } = enabledElement;
|
|
45
47
|
this.isDrawing = true;
|
|
46
48
|
const camera = viewport.getCamera();
|
|
47
49
|
const { viewPlaneNormal, viewUp } = camera;
|
|
48
50
|
const referencedImageId = this.getReferencedImageId(viewport, worldPos, viewPlaneNormal, viewUp);
|
|
49
51
|
const FrameOfReferenceUID = viewport.getFrameOfReferenceUID();
|
|
52
|
+
let points;
|
|
53
|
+
if (this.configuration.simplified) {
|
|
54
|
+
points = [[...worldPos], [...worldPos]];
|
|
55
|
+
}
|
|
56
|
+
else {
|
|
57
|
+
points = [
|
|
58
|
+
[...worldPos],
|
|
59
|
+
[...worldPos],
|
|
60
|
+
[...worldPos],
|
|
61
|
+
[...worldPos],
|
|
62
|
+
[...worldPos],
|
|
63
|
+
];
|
|
64
|
+
}
|
|
50
65
|
const annotation = {
|
|
51
66
|
highlighted: true,
|
|
52
67
|
invalidated: true,
|
|
@@ -71,7 +86,7 @@ class CircleROITool extends AnnotationTool {
|
|
|
71
86
|
bottomRight: [0, 0, 0],
|
|
72
87
|
},
|
|
73
88
|
},
|
|
74
|
-
points
|
|
89
|
+
points,
|
|
75
90
|
activeHandleIndex: null,
|
|
76
91
|
},
|
|
77
92
|
cachedStats: {},
|
|
@@ -94,18 +109,12 @@ class CircleROITool extends AnnotationTool {
|
|
|
94
109
|
this.isPointNearTool = (element, annotation, canvasCoords, proximity) => {
|
|
95
110
|
const enabledElement = getEnabledElement(element);
|
|
96
111
|
const { viewport } = enabledElement;
|
|
97
|
-
const {
|
|
98
|
-
const
|
|
99
|
-
const
|
|
100
|
-
const radius = getCanvasCircleRadius(
|
|
101
|
-
const radiusPoint = getCanvasCircleRadius([
|
|
102
|
-
|
|
103
|
-
canvasCoords,
|
|
104
|
-
]);
|
|
105
|
-
if (Math.abs(radiusPoint - radius) < proximity / 2) {
|
|
106
|
-
return true;
|
|
107
|
-
}
|
|
108
|
-
return false;
|
|
112
|
+
const { points } = annotation.data.handles;
|
|
113
|
+
const canvasHandles = points.map((p) => viewport.worldToCanvas(p));
|
|
114
|
+
const canvasCenter = canvasHandles[0];
|
|
115
|
+
const radius = getCanvasCircleRadius([canvasCenter, canvasHandles[1]]);
|
|
116
|
+
const radiusPoint = getCanvasCircleRadius([canvasCenter, canvasCoords]);
|
|
117
|
+
return Math.abs(radiusPoint - radius) < proximity / 2;
|
|
109
118
|
};
|
|
110
119
|
this.toolSelectedCallback = (evt, annotation) => {
|
|
111
120
|
const eventDetail = evt.detail;
|
|
@@ -119,8 +128,6 @@ class CircleROITool extends AnnotationTool {
|
|
|
119
128
|
};
|
|
120
129
|
hideElementCursor(element);
|
|
121
130
|
this._activateModify(element);
|
|
122
|
-
const enabledElement = getEnabledElement(element);
|
|
123
|
-
const { renderingEngine } = enabledElement;
|
|
124
131
|
triggerAnnotationRenderForViewportIds(viewportIdsToRender);
|
|
125
132
|
evt.preventDefault();
|
|
126
133
|
};
|
|
@@ -147,8 +154,6 @@ class CircleROITool extends AnnotationTool {
|
|
|
147
154
|
};
|
|
148
155
|
this._activateModify(element);
|
|
149
156
|
hideElementCursor(element);
|
|
150
|
-
const enabledElement = getEnabledElement(element);
|
|
151
|
-
const { renderingEngine } = enabledElement;
|
|
152
157
|
triggerAnnotationRenderForViewportIds(viewportIdsToRender);
|
|
153
158
|
evt.preventDefault();
|
|
154
159
|
};
|
|
@@ -166,7 +171,6 @@ class CircleROITool extends AnnotationTool {
|
|
|
166
171
|
this._deactivateModify(element);
|
|
167
172
|
this._deactivateDraw(element);
|
|
168
173
|
resetElementCursor(element);
|
|
169
|
-
const { renderingEngine } = getEnabledElement(element);
|
|
170
174
|
this.editData = null;
|
|
171
175
|
this.isDrawing = false;
|
|
172
176
|
if (this.isHandleOutsideImage &&
|
|
@@ -181,19 +185,39 @@ class CircleROITool extends AnnotationTool {
|
|
|
181
185
|
this._dragDrawCallback = (evt) => {
|
|
182
186
|
this.isDrawing = true;
|
|
183
187
|
const eventDetail = evt.detail;
|
|
184
|
-
const { element } = eventDetail;
|
|
185
|
-
const {
|
|
186
|
-
const currentCanvasPoints = currentPoints.canvas;
|
|
188
|
+
const { element, currentPoints } = eventDetail;
|
|
189
|
+
const { world: worldPos, canvas: currentCanvasPoints } = currentPoints;
|
|
187
190
|
const enabledElement = getEnabledElement(element);
|
|
188
191
|
const { viewport } = enabledElement;
|
|
189
192
|
const { canvasToWorld } = viewport;
|
|
190
193
|
const { annotation, viewportIdsToRender, newAnnotation } = this.editData;
|
|
191
194
|
this.createMemo(element, annotation, { newAnnotation });
|
|
192
195
|
const { data } = annotation;
|
|
193
|
-
data.handles.points
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
196
|
+
const centerWorld = data.handles.points[0];
|
|
197
|
+
const centerCanvas = viewport.worldToCanvas(centerWorld);
|
|
198
|
+
if (this.configuration.simplified) {
|
|
199
|
+
data.handles.points[1] = worldPos;
|
|
200
|
+
}
|
|
201
|
+
else {
|
|
202
|
+
const radiusCanvas = vec2.distance(centerCanvas, currentCanvasPoints);
|
|
203
|
+
data.handles.points[0] = [...centerWorld];
|
|
204
|
+
data.handles.points[1] = canvasToWorld([
|
|
205
|
+
centerCanvas[0],
|
|
206
|
+
centerCanvas[1] - radiusCanvas,
|
|
207
|
+
]);
|
|
208
|
+
data.handles.points[2] = canvasToWorld([
|
|
209
|
+
centerCanvas[0],
|
|
210
|
+
centerCanvas[1] + radiusCanvas,
|
|
211
|
+
]);
|
|
212
|
+
data.handles.points[3] = canvasToWorld([
|
|
213
|
+
centerCanvas[0] - radiusCanvas,
|
|
214
|
+
centerCanvas[1],
|
|
215
|
+
]);
|
|
216
|
+
data.handles.points[4] = canvasToWorld([
|
|
217
|
+
centerCanvas[0] + radiusCanvas,
|
|
218
|
+
centerCanvas[1],
|
|
219
|
+
]);
|
|
220
|
+
}
|
|
197
221
|
annotation.invalidated = true;
|
|
198
222
|
this.editData.hasMoved = true;
|
|
199
223
|
triggerAnnotationRenderForViewportIds(viewportIdsToRender);
|
|
@@ -231,8 +255,6 @@ class CircleROITool extends AnnotationTool {
|
|
|
231
255
|
this._dragHandle(evt);
|
|
232
256
|
annotation.invalidated = true;
|
|
233
257
|
}
|
|
234
|
-
const enabledElement = getEnabledElement(element);
|
|
235
|
-
const { renderingEngine } = enabledElement;
|
|
236
258
|
triggerAnnotationRenderForViewportIds(viewportIdsToRender);
|
|
237
259
|
if (annotation.invalidated) {
|
|
238
260
|
triggerAnnotationModified(annotation, element, ChangeTypes.HandlesUpdated);
|
|
@@ -246,23 +268,36 @@ class CircleROITool extends AnnotationTool {
|
|
|
246
268
|
const { annotation, handleIndex } = this.editData;
|
|
247
269
|
const { data } = annotation;
|
|
248
270
|
const { points } = data.handles;
|
|
249
|
-
const
|
|
250
|
-
const { currentPoints } = eventDetail;
|
|
251
|
-
const currentCanvasPoints = currentPoints.canvas;
|
|
271
|
+
const { currentPoints, deltaPoints } = eventDetail;
|
|
252
272
|
if (handleIndex === 0) {
|
|
253
|
-
const
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
canvasCoordinates[1][0] + dXCanvas,
|
|
258
|
-
canvasCoordinates[1][1] + dYCanvas,
|
|
259
|
-
];
|
|
260
|
-
points[0] = canvasToWorld(canvasCenter);
|
|
261
|
-
points[1] = canvasToWorld(canvasEnd);
|
|
273
|
+
const worldPosDelta = deltaPoints.world;
|
|
274
|
+
points.forEach((point) => {
|
|
275
|
+
vec3.add(point, point, worldPosDelta);
|
|
276
|
+
});
|
|
262
277
|
}
|
|
263
278
|
else {
|
|
264
|
-
points[
|
|
279
|
+
const centerWorld = points[0];
|
|
280
|
+
const centerCanvas = worldToCanvas(centerWorld);
|
|
281
|
+
const currentCanvasPoint = currentPoints.canvas;
|
|
282
|
+
const newRadiusCanvas = vec2.distance(centerCanvas, currentCanvasPoint);
|
|
283
|
+
points[1] = canvasToWorld([
|
|
284
|
+
centerCanvas[0],
|
|
285
|
+
centerCanvas[1] - newRadiusCanvas,
|
|
286
|
+
]);
|
|
287
|
+
points[2] = canvasToWorld([
|
|
288
|
+
centerCanvas[0],
|
|
289
|
+
centerCanvas[1] + newRadiusCanvas,
|
|
290
|
+
]);
|
|
291
|
+
points[3] = canvasToWorld([
|
|
292
|
+
centerCanvas[0] - newRadiusCanvas,
|
|
293
|
+
centerCanvas[1],
|
|
294
|
+
]);
|
|
295
|
+
points[4] = canvasToWorld([
|
|
296
|
+
centerCanvas[0] + newRadiusCanvas,
|
|
297
|
+
centerCanvas[1],
|
|
298
|
+
]);
|
|
265
299
|
}
|
|
300
|
+
annotation.invalidated = true;
|
|
266
301
|
};
|
|
267
302
|
this.cancel = (element) => {
|
|
268
303
|
if (this.isDrawing) {
|
|
@@ -271,9 +306,8 @@ class CircleROITool extends AnnotationTool {
|
|
|
271
306
|
this._deactivateModify(element);
|
|
272
307
|
resetElementCursor(element);
|
|
273
308
|
const { annotation, viewportIdsToRender, newAnnotation } = this.editData;
|
|
274
|
-
const { data } = annotation;
|
|
275
309
|
annotation.highlighted = false;
|
|
276
|
-
data.handles.activeHandleIndex = null;
|
|
310
|
+
annotation.data.handles.activeHandleIndex = null;
|
|
277
311
|
triggerAnnotationRenderForViewportIds(viewportIdsToRender);
|
|
278
312
|
if (newAnnotation) {
|
|
279
313
|
triggerAnnotationCompleted(annotation);
|
|
@@ -351,8 +385,11 @@ class CircleROITool extends AnnotationTool {
|
|
|
351
385
|
});
|
|
352
386
|
const canvasCoordinates = points.map((p) => viewport.worldToCanvas(p));
|
|
353
387
|
const center = canvasCoordinates[0];
|
|
354
|
-
const radius = getCanvasCircleRadius(canvasCoordinates);
|
|
355
|
-
const canvasCorners = getCanvasCircleCorners(
|
|
388
|
+
const radius = getCanvasCircleRadius([center, canvasCoordinates[1]]);
|
|
389
|
+
const canvasCorners = getCanvasCircleCorners([
|
|
390
|
+
center,
|
|
391
|
+
canvasCoordinates[1],
|
|
392
|
+
]);
|
|
356
393
|
const { centerPointRadius } = this.configuration;
|
|
357
394
|
if (!data.cachedStats[targetId] ||
|
|
358
395
|
data.cachedStats[targetId].areaUnit == null) {
|
|
@@ -400,7 +437,12 @@ class CircleROITool extends AnnotationTool {
|
|
|
400
437
|
if (!isAnnotationLocked(annotationUID) &&
|
|
401
438
|
!this.editData &&
|
|
402
439
|
activeHandleIndex !== null) {
|
|
403
|
-
|
|
440
|
+
if (this.configuration.simplified) {
|
|
441
|
+
activeHandleCanvasCoords = [canvasCoordinates[activeHandleIndex]];
|
|
442
|
+
}
|
|
443
|
+
else {
|
|
444
|
+
activeHandleCanvasCoords = canvasCoordinates;
|
|
445
|
+
}
|
|
404
446
|
}
|
|
405
447
|
if (activeHandleCanvasCoords) {
|
|
406
448
|
const handleGroupUID = '0';
|
|
@@ -451,7 +493,7 @@ class CircleROITool extends AnnotationTool {
|
|
|
451
493
|
}
|
|
452
494
|
const textBoxPosition = viewport.worldToCanvas(data.handles.textBox.worldPosition);
|
|
453
495
|
const textBoxUID = '1';
|
|
454
|
-
const boundingBox = drawLinkedTextBoxSvg(svgDrawingHelper, annotationUID, textBoxUID, textLines, textBoxPosition, canvasCoordinates, {}, options);
|
|
496
|
+
const boundingBox = drawLinkedTextBoxSvg(svgDrawingHelper, annotationUID, textBoxUID, textLines, textBoxPosition, [center, canvasCoordinates[1]], {}, options);
|
|
455
497
|
const { x: left, y: top, width, height } = boundingBox;
|
|
456
498
|
data.handles.textBox.worldBoundingBox = {
|
|
457
499
|
topLeft: viewport.canvasToWorld([left, top]),
|
|
@@ -471,8 +513,10 @@ class CircleROITool extends AnnotationTool {
|
|
|
471
513
|
const wasInvalidated = annotation.invalidated;
|
|
472
514
|
const { points } = data.handles;
|
|
473
515
|
const canvasCoordinates = points.map((p) => viewport.worldToCanvas(p));
|
|
516
|
+
const canvasCenter = canvasCoordinates[0];
|
|
517
|
+
const canvasTop = canvasCoordinates[1];
|
|
474
518
|
const { viewPlaneNormal, viewUp } = viewport.getCamera();
|
|
475
|
-
const [topLeftCanvas, bottomRightCanvas] = (getCanvasCircleCorners(
|
|
519
|
+
const [topLeftCanvas, bottomRightCanvas] = (getCanvasCircleCorners([canvasCenter, canvasTop]));
|
|
476
520
|
const topLeftWorld = viewport.canvasToWorld(topLeftCanvas);
|
|
477
521
|
const bottomRightWorld = viewport.canvasToWorld(bottomRightCanvas);
|
|
478
522
|
const { cachedStats } = data;
|
|
@@ -506,11 +550,7 @@ class CircleROITool extends AnnotationTool {
|
|
|
506
550
|
[jMin, jMax],
|
|
507
551
|
[kMin, kMax],
|
|
508
552
|
];
|
|
509
|
-
const center = [
|
|
510
|
-
(topLeftWorld[0] + bottomRightWorld[0]) / 2,
|
|
511
|
-
(topLeftWorld[1] + bottomRightWorld[1]) / 2,
|
|
512
|
-
(topLeftWorld[2] + bottomRightWorld[2]) / 2,
|
|
513
|
-
];
|
|
553
|
+
const center = points[0];
|
|
514
554
|
const xRadius = Math.abs(topLeftWorld[0] - bottomRightWorld[0]) / 2;
|
|
515
555
|
const yRadius = Math.abs(topLeftWorld[1] - bottomRightWorld[1]) / 2;
|
|
516
556
|
const zRadius = Math.abs(topLeftWorld[2] - bottomRightWorld[2]) / 2;
|
|
@@ -25,6 +25,7 @@ class CircleROIStartEndThresholdTool extends CircleROITool {
|
|
|
25
25
|
constructor(toolProps = {}, defaultToolProps = {
|
|
26
26
|
supportedInteractionTypes: ['Mouse', 'Touch'],
|
|
27
27
|
configuration: {
|
|
28
|
+
simplified: true,
|
|
28
29
|
storePointData: false,
|
|
29
30
|
numSlicesToPropagate: 10,
|
|
30
31
|
calculatePointsInsideVolume: true,
|
|
@@ -59,6 +60,19 @@ class CircleROIStartEndThresholdTool extends CircleROITool {
|
|
|
59
60
|
const startCoord = this._getStartCoordinate(worldPos, spacingInNormal, viewPlaneNormal);
|
|
60
61
|
const endCoord = this._getEndCoordinate(worldPos, spacingInNormal, viewPlaneNormal);
|
|
61
62
|
const FrameOfReferenceUID = viewport.getFrameOfReferenceUID();
|
|
63
|
+
let points;
|
|
64
|
+
if (this.configuration.simplified) {
|
|
65
|
+
points = [[...worldPos], [...worldPos]];
|
|
66
|
+
}
|
|
67
|
+
else {
|
|
68
|
+
points = [
|
|
69
|
+
[...worldPos],
|
|
70
|
+
[...worldPos],
|
|
71
|
+
[...worldPos],
|
|
72
|
+
[...worldPos],
|
|
73
|
+
[...worldPos],
|
|
74
|
+
];
|
|
75
|
+
}
|
|
62
76
|
const annotation = {
|
|
63
77
|
highlighted: true,
|
|
64
78
|
invalidated: true,
|
|
@@ -87,7 +101,7 @@ class CircleROIStartEndThresholdTool extends CircleROITool {
|
|
|
87
101
|
bottomRight: [0, 0, 0],
|
|
88
102
|
},
|
|
89
103
|
},
|
|
90
|
-
points
|
|
104
|
+
points,
|
|
91
105
|
activeHandleIndex: null,
|
|
92
106
|
},
|
|
93
107
|
cachedStats: {
|
|
@@ -168,9 +182,15 @@ class CircleROIStartEndThresholdTool extends CircleROITool {
|
|
|
168
182
|
const color = this.getStyle('color', styleSpecifier, annotation);
|
|
169
183
|
const canvasCoordinates = points.map((p) => viewport.worldToCanvas(p));
|
|
170
184
|
const center = canvasCoordinates[0];
|
|
171
|
-
const radius = getCanvasCircleRadius(
|
|
185
|
+
const radius = getCanvasCircleRadius([
|
|
186
|
+
canvasCoordinates[0],
|
|
187
|
+
canvasCoordinates[1],
|
|
188
|
+
]);
|
|
172
189
|
const { centerPointRadius } = this.configuration;
|
|
173
|
-
const canvasCorners = getCanvasCircleCorners(
|
|
190
|
+
const canvasCorners = getCanvasCircleCorners([
|
|
191
|
+
canvasCoordinates[0],
|
|
192
|
+
canvasCoordinates[1],
|
|
193
|
+
]);
|
|
174
194
|
const focalPoint = viewport.getCamera().focalPoint;
|
|
175
195
|
const viewplaneNormal = viewport.getCamera().viewPlaneNormal;
|
|
176
196
|
let tempStartCoordinate = startCoordinate;
|
|
@@ -214,7 +234,12 @@ class CircleROIStartEndThresholdTool extends CircleROITool {
|
|
|
214
234
|
!this.editData &&
|
|
215
235
|
activeHandleIndex !== null &&
|
|
216
236
|
isMiddleSlice) {
|
|
217
|
-
|
|
237
|
+
if (this.configuration.simplified) {
|
|
238
|
+
activeHandleCanvasCoords = [canvasCoordinates[activeHandleIndex]];
|
|
239
|
+
}
|
|
240
|
+
else {
|
|
241
|
+
activeHandleCanvasCoords = canvasCoordinates;
|
|
242
|
+
}
|
|
218
243
|
}
|
|
219
244
|
if (activeHandleCanvasCoords) {
|
|
220
245
|
const handleGroupUID = '0';
|
|
@@ -274,7 +299,7 @@ class CircleROIStartEndThresholdTool extends CircleROITool {
|
|
|
274
299
|
}
|
|
275
300
|
const textBoxPosition = viewport.worldToCanvas(data.handles.textBox.worldPosition);
|
|
276
301
|
const textBoxUID = '1';
|
|
277
|
-
const boundingBox = drawLinkedTextBoxSvg(svgDrawingHelper, annotationUID, textBoxUID, textLines, textBoxPosition, canvasCoordinates, {}, options);
|
|
302
|
+
const boundingBox = drawLinkedTextBoxSvg(svgDrawingHelper, annotationUID, textBoxUID, textLines, textBoxPosition, [canvasCoordinates[0], canvasCoordinates[1]], {}, options);
|
|
278
303
|
const { x: left, y: top, width, height } = boundingBox;
|
|
279
304
|
data.handles.textBox.worldBoundingBox = {
|
|
280
305
|
topLeft: viewport.canvasToWorld([left, top]),
|
|
@@ -296,45 +321,26 @@ class CircleROIStartEndThresholdTool extends CircleROITool {
|
|
|
296
321
|
_computeProjectionPoints(annotation, imageVolume) {
|
|
297
322
|
const { data, metadata } = annotation;
|
|
298
323
|
const { viewPlaneNormal, spacingInNormal } = metadata;
|
|
299
|
-
const { imageData } = imageVolume;
|
|
300
324
|
const { startCoordinate, endCoordinate } = data;
|
|
301
325
|
const { points } = data.handles;
|
|
302
|
-
const startIJK = transformWorldToIndex(imageData, points[0]);
|
|
303
|
-
const endIJK = transformWorldToIndex(imageData, points[0]);
|
|
304
326
|
const handlesToStart = csUtils.deepClone(points);
|
|
305
|
-
const startWorld = vec3.
|
|
306
|
-
|
|
307
|
-
const
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
handlesToStart[1][2] = startCoordinate;
|
|
315
|
-
}
|
|
316
|
-
else if (projectionAxisIndex == 0) {
|
|
317
|
-
startWorld[0] = startCoordinate;
|
|
318
|
-
endWorld[0] = endCoordinate;
|
|
319
|
-
handlesToStart[0][0] = startCoordinate;
|
|
320
|
-
handlesToStart[1][0] = startCoordinate;
|
|
321
|
-
}
|
|
322
|
-
else if (projectionAxisIndex == 1) {
|
|
323
|
-
startWorld[1] = startCoordinate;
|
|
324
|
-
endWorld[1] = endCoordinate;
|
|
325
|
-
handlesToStart[0][1] = startCoordinate;
|
|
326
|
-
handlesToStart[1][1] = startCoordinate;
|
|
327
|
-
}
|
|
328
|
-
const direction = vec3.create();
|
|
329
|
-
vec3.subtract(direction, endWorld, startWorld);
|
|
330
|
-
const distance = vec3.length(direction);
|
|
331
|
-
vec3.normalize(direction, direction);
|
|
327
|
+
const startWorld = vec3.clone(points[0]);
|
|
328
|
+
const endWorld = vec3.clone(points[0]);
|
|
329
|
+
const indexOfNormal = this._getIndexOfCoordinatesForViewplaneNormal(viewPlaneNormal);
|
|
330
|
+
startWorld[indexOfNormal] = startCoordinate;
|
|
331
|
+
endWorld[indexOfNormal] = endCoordinate;
|
|
332
|
+
handlesToStart.forEach((handlePoint) => {
|
|
333
|
+
handlePoint[indexOfNormal] = startCoordinate;
|
|
334
|
+
});
|
|
335
|
+
const distance = vec3.distance(startWorld, endWorld);
|
|
332
336
|
const newProjectionPoints = [];
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
337
|
+
if (distance >= 0) {
|
|
338
|
+
newProjectionPoints.push(handlesToStart.map((p) => Array.from(p)));
|
|
339
|
+
}
|
|
340
|
+
for (let dist = spacingInNormal; dist <= distance; dist += spacingInNormal) {
|
|
341
|
+
newProjectionPoints.push(handlesToStart.map((point) => {
|
|
336
342
|
const newPoint = vec3.create();
|
|
337
|
-
vec3.scaleAndAdd(newPoint, point,
|
|
343
|
+
vec3.scaleAndAdd(newPoint, point, viewPlaneNormal, dist);
|
|
338
344
|
return Array.from(newPoint);
|
|
339
345
|
}));
|
|
340
346
|
}
|
|
@@ -348,11 +354,18 @@ class CircleROIStartEndThresholdTool extends CircleROITool {
|
|
|
348
354
|
const pointsInsideVolume = [[]];
|
|
349
355
|
const image = this.getTargetImageData(targetId);
|
|
350
356
|
const canvasCoordinates = data.handles.points.map((p) => viewport.worldToCanvas(p));
|
|
351
|
-
const
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
const
|
|
357
|
+
const baseTopLeftCanvas = getCanvasCircleCorners([
|
|
358
|
+
canvasCoordinates[0],
|
|
359
|
+
canvasCoordinates[1],
|
|
360
|
+
])[0];
|
|
361
|
+
const baseBottomRightCanvas = getCanvasCircleCorners([
|
|
362
|
+
canvasCoordinates[0],
|
|
363
|
+
canvasCoordinates[1],
|
|
364
|
+
])[1];
|
|
365
|
+
const basePos1 = viewport.canvasToWorld(baseTopLeftCanvas);
|
|
366
|
+
const basePos2 = viewport.canvasToWorld(baseBottomRightCanvas);
|
|
367
|
+
const { worldWidth, worldHeight } = getWorldWidthAndHeightFromTwoPoints(viewPlaneNormal, viewUp, basePos1, basePos2);
|
|
368
|
+
const measureInfo = getCalibratedLengthUnitsAndScale(image, data.handles.points);
|
|
356
369
|
const aspect = getCalibratedAspect(image);
|
|
357
370
|
const area = Math.abs(Math.PI *
|
|
358
371
|
(worldWidth / measureInfo.scale / 2) *
|
|
@@ -367,8 +380,11 @@ class CircleROIStartEndThresholdTool extends CircleROITool {
|
|
|
367
380
|
continue;
|
|
368
381
|
}
|
|
369
382
|
const centerWorld = projectionPoints[i][0];
|
|
370
|
-
const
|
|
371
|
-
const [topLeftCanvas, bottomRightCanvas] = (getCanvasCircleCorners(
|
|
383
|
+
const currentCanvasCoordinates = projectionPoints[i].map((p) => viewport.worldToCanvas(p));
|
|
384
|
+
const [topLeftCanvas, bottomRightCanvas] = (getCanvasCircleCorners([
|
|
385
|
+
currentCanvasCoordinates[0],
|
|
386
|
+
currentCanvasCoordinates[1],
|
|
387
|
+
]));
|
|
372
388
|
const topLeftWorld = viewport.canvasToWorld(topLeftCanvas);
|
|
373
389
|
const bottomRightWorld = viewport.canvasToWorld(bottomRightCanvas);
|
|
374
390
|
const worldPos1 = topLeftWorld;
|
|
@@ -109,7 +109,13 @@ export interface AdvancedMagnifyAnnotation extends Annotation {
|
|
|
109
109
|
export interface CircleROIAnnotation extends Annotation {
|
|
110
110
|
data: {
|
|
111
111
|
handles: {
|
|
112
|
-
points: [
|
|
112
|
+
points: [
|
|
113
|
+
Types.Point3,
|
|
114
|
+
Types.Point3,
|
|
115
|
+
Types.Point3,
|
|
116
|
+
Types.Point3,
|
|
117
|
+
Types.Point3
|
|
118
|
+
];
|
|
113
119
|
activeHandleIndex: number | null;
|
|
114
120
|
textBox?: {
|
|
115
121
|
hasMoved: boolean;
|
|
@@ -287,7 +293,7 @@ export interface CircleROIStartEndThresholdAnnotation extends Annotation {
|
|
|
287
293
|
statistics?: ROICachedStats;
|
|
288
294
|
};
|
|
289
295
|
handles: {
|
|
290
|
-
points:
|
|
296
|
+
points: Types.Point3[];
|
|
291
297
|
activeHandleIndex: number | null;
|
|
292
298
|
textBox?: {
|
|
293
299
|
hasMoved: boolean;
|
package/dist/esm/version.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const version = "3.
|
|
1
|
+
export declare const version = "3.26.0";
|
package/dist/esm/version.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const version = '3.
|
|
1
|
+
export const version = '3.26.0';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cornerstonejs/tools",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.26.0",
|
|
4
4
|
"description": "Cornerstone3D Tools",
|
|
5
5
|
"types": "./dist/esm/index.d.ts",
|
|
6
6
|
"module": "./dist/esm/index.js",
|
|
@@ -108,7 +108,7 @@
|
|
|
108
108
|
"canvas": "^3.1.0"
|
|
109
109
|
},
|
|
110
110
|
"peerDependencies": {
|
|
111
|
-
"@cornerstonejs/core": "^3.
|
|
111
|
+
"@cornerstonejs/core": "^3.26.0",
|
|
112
112
|
"@kitware/vtk.js": "32.12.1",
|
|
113
113
|
"@types/d3-array": "^3.0.4",
|
|
114
114
|
"@types/d3-interpolate": "^3.0.1",
|
|
@@ -127,5 +127,5 @@
|
|
|
127
127
|
"type": "individual",
|
|
128
128
|
"url": "https://ohif.org/donate"
|
|
129
129
|
},
|
|
130
|
-
"gitHead": "
|
|
130
|
+
"gitHead": "a851443310a66ee3620011723733112128c2a7ba"
|
|
131
131
|
}
|