@cornerstonejs/tools 1.61.7 → 1.63.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 (39) hide show
  1. package/dist/cjs/index.d.ts +2 -2
  2. package/dist/cjs/index.js +2 -1
  3. package/dist/cjs/index.js.map +1 -1
  4. package/dist/cjs/tools/index.d.ts +2 -1
  5. package/dist/cjs/tools/index.js +4 -1
  6. package/dist/cjs/tools/index.js.map +1 -1
  7. package/dist/cjs/tools/segmentation/CircleROIStartEndThresholdTool.d.ts +63 -0
  8. package/dist/cjs/tools/segmentation/CircleROIStartEndThresholdTool.js +347 -0
  9. package/dist/cjs/tools/segmentation/CircleROIStartEndThresholdTool.js.map +1 -0
  10. package/dist/cjs/tools/segmentation/RectangleROIStartEndThresholdTool.d.ts +3 -0
  11. package/dist/cjs/tools/segmentation/RectangleROIStartEndThresholdTool.js +73 -0
  12. package/dist/cjs/tools/segmentation/RectangleROIStartEndThresholdTool.js.map +1 -1
  13. package/dist/cjs/types/ToolSpecificAnnotationTypes.d.ts +34 -1
  14. package/dist/esm/index.js +2 -2
  15. package/dist/esm/index.js.map +1 -1
  16. package/dist/esm/tools/index.js +2 -1
  17. package/dist/esm/tools/index.js.map +1 -1
  18. package/dist/esm/tools/segmentation/CircleROIStartEndThresholdTool.js +342 -0
  19. package/dist/esm/tools/segmentation/CircleROIStartEndThresholdTool.js.map +1 -0
  20. package/dist/esm/tools/segmentation/RectangleROIStartEndThresholdTool.js +75 -2
  21. package/dist/esm/tools/segmentation/RectangleROIStartEndThresholdTool.js.map +1 -1
  22. package/dist/types/index.d.ts +2 -2
  23. package/dist/types/index.d.ts.map +1 -1
  24. package/dist/types/tools/index.d.ts +2 -1
  25. package/dist/types/tools/index.d.ts.map +1 -1
  26. package/dist/types/tools/segmentation/CircleROIStartEndThresholdTool.d.ts +64 -0
  27. package/dist/types/tools/segmentation/CircleROIStartEndThresholdTool.d.ts.map +1 -0
  28. package/dist/types/tools/segmentation/RectangleROIStartEndThresholdTool.d.ts +3 -0
  29. package/dist/types/tools/segmentation/RectangleROIStartEndThresholdTool.d.ts.map +1 -1
  30. package/dist/types/types/ToolSpecificAnnotationTypes.d.ts +34 -1
  31. package/dist/types/types/ToolSpecificAnnotationTypes.d.ts.map +1 -1
  32. package/dist/umd/index.js +1 -1
  33. package/dist/umd/index.js.map +1 -1
  34. package/package.json +3 -3
  35. package/src/index.ts +2 -0
  36. package/src/tools/index.ts +2 -0
  37. package/src/tools/segmentation/CircleROIStartEndThresholdTool.ts +677 -0
  38. package/src/tools/segmentation/RectangleROIStartEndThresholdTool.ts +134 -2
  39. package/src/types/ToolSpecificAnnotationTypes.ts +43 -8
@@ -8,7 +8,11 @@ import {
8
8
  import type { Types } from '@cornerstonejs/core';
9
9
 
10
10
  import { vec3 } from 'gl-matrix';
11
- import { addAnnotation, getAnnotations } from '../../stateManagement';
11
+ import {
12
+ addAnnotation,
13
+ getAnnotations,
14
+ removeAnnotation,
15
+ } from '../../stateManagement';
12
16
  import { isAnnotationLocked } from '../../stateManagement/annotation/annotationLocking';
13
17
  import { triggerAnnotationModified } from '../../stateManagement/annotation/helpers/state';
14
18
  import {
@@ -18,8 +22,12 @@ import {
18
22
  import { getViewportIdsWithToolToRender } from '../../utilities/viewportFilters';
19
23
  import throttle from '../../utilities/throttle';
20
24
  import { isAnnotationVisible } from '../../stateManagement/annotation/annotationVisibility';
21
- import { hideElementCursor } from '../../cursors/elementCursor';
25
+ import {
26
+ hideElementCursor,
27
+ resetElementCursor,
28
+ } from '../../cursors/elementCursor';
22
29
  import triggerAnnotationRenderForViewportIds from '../../utilities/triggerAnnotationRenderForViewportIds';
30
+ import { triggerAnnotationCompleted } from '../../stateManagement/annotation/helpers/state';
23
31
 
24
32
  import {
25
33
  PublicToolProps,
@@ -30,6 +38,7 @@ import {
30
38
  import { RectangleROIStartEndThresholdAnnotation } from '../../types/ToolSpecificAnnotationTypes';
31
39
  import RectangleROITool from '../annotation/RectangleROITool';
32
40
  import { StyleSpecifier } from '../../types/AnnotationStyle';
41
+ import { pointInShapeCallback } from '../../utilities/';
33
42
 
34
43
  const { transformWorldToIndex } = csUtils;
35
44
 
@@ -63,6 +72,7 @@ class RectangleROIStartEndThresholdTool extends RectangleROITool {
63
72
  defaultToolProps: ToolProps = {
64
73
  configuration: {
65
74
  numSlicesToPropagate: 10,
75
+ computePointsInsideVolume: false,
66
76
  },
67
77
  }
68
78
  ) {
@@ -151,6 +161,7 @@ class RectangleROIStartEndThresholdTool extends RectangleROITool {
151
161
  startSlice: startIndex,
152
162
  endSlice: endIndex,
153
163
  cachedStats: {
164
+ pointsInVolume: [],
154
165
  projectionPoints: [],
155
166
  projectionPointsImageIds: [referencedImageId],
156
167
  },
@@ -203,6 +214,54 @@ class RectangleROIStartEndThresholdTool extends RectangleROITool {
203
214
  return annotation;
204
215
  };
205
216
 
217
+ _endCallback = (evt: EventTypes.InteractionEventType): void => {
218
+ const eventDetail = evt.detail;
219
+ const { element } = eventDetail;
220
+
221
+ const { annotation, viewportIdsToRender, newAnnotation, hasMoved } =
222
+ this.editData;
223
+ const { data } = annotation;
224
+
225
+ if (newAnnotation && !hasMoved) {
226
+ return;
227
+ }
228
+
229
+ data.handles.activeHandleIndex = null;
230
+
231
+ this._deactivateModify(element);
232
+ this._deactivateDraw(element);
233
+
234
+ resetElementCursor(element);
235
+
236
+ const enabledElement = getEnabledElement(element);
237
+
238
+ this.editData = null;
239
+ this.isDrawing = false;
240
+
241
+ if (
242
+ this.isHandleOutsideImage &&
243
+ this.configuration.preventHandleOutsideImage
244
+ ) {
245
+ removeAnnotation(annotation.annotationUID);
246
+ }
247
+
248
+ const targetId = this.getTargetId(enabledElement.viewport);
249
+ const imageVolume = cache.getVolume(targetId.split(/volumeId:|\?/)[1]);
250
+
251
+ if (this.configuration.calculatePointsInsideVolume) {
252
+ this._computePointsInsideVolume(annotation, imageVolume, enabledElement);
253
+ }
254
+
255
+ triggerAnnotationRenderForViewportIds(
256
+ enabledElement.renderingEngine,
257
+ viewportIdsToRender
258
+ );
259
+
260
+ if (newAnnotation) {
261
+ triggerAnnotationCompleted(annotation);
262
+ }
263
+ };
264
+
206
265
  // Todo: make it work for planes other than acquisition planes
207
266
  _computeProjectionPoints(
208
267
  annotation: RectangleROIStartEndThresholdAnnotation,
@@ -261,6 +320,79 @@ class RectangleROIStartEndThresholdTool extends RectangleROITool {
261
320
  data.cachedStats.projectionPointsImageIds = projectionPointsImageIds;
262
321
  }
263
322
 
323
+ //This function return all the points inside the ROI for every slices between startSlice and endSlice
324
+ _computePointsInsideVolume(annotation, imageVolume, enabledElement) {
325
+ const { data } = annotation;
326
+ const projectionPoints = data.cachedStats.projectionPoints;
327
+
328
+ const pointsInsideVolume: Types.Point3[][] = [[]];
329
+
330
+ for (let i = 0; i < projectionPoints.length; i++) {
331
+ // If image does not exists for the targetId, skip. This can be due
332
+ // to various reasons such as if the target was a volumeViewport, and
333
+ // the volumeViewport has been decached in the meantime.
334
+ if (!imageVolume) {
335
+ continue;
336
+ }
337
+
338
+ const projectionPoint = projectionPoints[i][0];
339
+
340
+ const worldPos1 = data.handles.points[0];
341
+ const worldPos2 = data.handles.points[3];
342
+
343
+ const { dimensions, imageData } = imageVolume;
344
+
345
+ const worldPos1Index = transformWorldToIndex(imageData, worldPos1);
346
+ //We only need to change the Z of our bounds so we are getting the Z from the current projection point
347
+ const worldProjectionPointIndex = transformWorldToIndex(
348
+ imageData,
349
+ projectionPoint
350
+ );
351
+
352
+ worldPos1Index[0] = Math.floor(worldPos1Index[0]);
353
+ worldPos1Index[1] = Math.floor(worldPos1Index[1]);
354
+ worldPos1Index[2] = Math.floor(worldProjectionPointIndex[2]);
355
+
356
+ const worldPos2Index = transformWorldToIndex(imageData, worldPos2);
357
+
358
+ worldPos2Index[0] = Math.floor(worldPos2Index[0]);
359
+ worldPos2Index[1] = Math.floor(worldPos2Index[1]);
360
+ worldPos2Index[2] = Math.floor(worldProjectionPointIndex[2]);
361
+
362
+ // Check if one of the indexes are inside the volume, this then gives us
363
+ // Some area to do stats over.
364
+
365
+ if (this._isInsideVolume(worldPos1Index, worldPos2Index, dimensions)) {
366
+ this.isHandleOutsideImage = false;
367
+ const iMin = Math.min(worldPos1Index[0], worldPos2Index[0]);
368
+ const iMax = Math.max(worldPos1Index[0], worldPos2Index[0]);
369
+
370
+ const jMin = Math.min(worldPos1Index[1], worldPos2Index[1]);
371
+ const jMax = Math.max(worldPos1Index[1], worldPos2Index[1]);
372
+
373
+ const kMin = Math.min(worldPos1Index[2], worldPos2Index[2]);
374
+ const kMax = Math.max(worldPos1Index[2], worldPos2Index[2]);
375
+
376
+ const boundsIJK = [
377
+ [iMin, iMax],
378
+ [jMin, jMax],
379
+ [kMin, kMax],
380
+ ] as [Types.Point2, Types.Point2, Types.Point2];
381
+
382
+ const pointsInShape = pointInShapeCallback(
383
+ imageData,
384
+ () => true,
385
+ null,
386
+ boundsIJK
387
+ );
388
+
389
+ //@ts-ignore
390
+ pointsInsideVolume.push(pointsInShape);
391
+ }
392
+ }
393
+ data.cachedStats.pointsInVolume = pointsInsideVolume;
394
+ }
395
+
264
396
  _calculateCachedStatsTool(annotation, enabledElement) {
265
397
  const data = annotation.data;
266
398
  const { element, viewport } = enabledElement;
@@ -35,6 +35,7 @@ export interface RectangleROIAnnotation extends Annotation {
35
35
  cachedStats?:
36
36
  | ROICachedStats
37
37
  | {
38
+ pointsInVolume?: Types.Point3[];
38
39
  projectionPoints?: Types.Point3[];
39
40
  projectionPointsImageIds?: string[];
40
41
  };
@@ -110,13 +111,18 @@ export interface CircleROIAnnotation extends Annotation {
110
111
  };
111
112
  };
112
113
  label: string;
113
- cachedStats?: ROICachedStats & {
114
- [targetId: string]: {
115
- radius: number;
116
- radiusUnit: string;
117
- perimeter: number;
118
- };
119
- };
114
+ cachedStats?:
115
+ | (ROICachedStats & {
116
+ [targetId: string]: {
117
+ radius: number;
118
+ radiusUnit: string;
119
+ perimeter: number;
120
+ };
121
+ })
122
+ | {
123
+ pointsInVolume: Types.Point3[];
124
+ projectionPoints: Types.Point3[][];
125
+ };
120
126
  };
121
127
  }
122
128
 
@@ -236,6 +242,7 @@ export interface RectangleROIStartEndThresholdAnnotation extends Annotation {
236
242
  startSlice: number;
237
243
  endSlice: number;
238
244
  cachedStats: {
245
+ pointsInVolume: Types.Point3[];
239
246
  projectionPoints: Types.Point3[][]; // first slice p1, p2, p3, p4; second slice p1, p2, p3, p4 ...
240
247
  projectionPointsImageIds: string[];
241
248
  };
@@ -246,6 +253,35 @@ export interface RectangleROIStartEndThresholdAnnotation extends Annotation {
246
253
  };
247
254
  }
248
255
 
256
+ export interface CircleROIStartEndThresholdAnnotation extends Annotation {
257
+ metadata: {
258
+ cameraPosition?: Types.Point3;
259
+ cameraFocalPoint?: Types.Point3;
260
+ viewPlaneNormal?: Types.Point3;
261
+ viewUp?: Types.Point3;
262
+ annotationUID?: string;
263
+ FrameOfReferenceUID: string;
264
+ referencedImageId?: string;
265
+ toolName: string;
266
+ enabledElement: any; // Todo: how to remove this from the annotation??
267
+ volumeId: string;
268
+ spacingInNormal: number;
269
+ };
270
+ data: {
271
+ label: string;
272
+ startSlice: number;
273
+ endSlice: number;
274
+ cachedStats?: {
275
+ pointsInVolume: Types.Point3[];
276
+ projectionPoints: Types.Point3[][];
277
+ };
278
+ handles: {
279
+ points: [Types.Point3, Types.Point3]; // [center, end]
280
+ activeHandleIndex: number | null;
281
+ };
282
+ };
283
+ }
284
+
249
285
  export type PlanarFreehandROIAnnotation = ContourAnnotation & {
250
286
  data: {
251
287
  label?: string;
@@ -256,7 +292,6 @@ export type PlanarFreehandROIAnnotation = ContourAnnotation & {
256
292
  cachedStats?: ROICachedStats;
257
293
  };
258
294
  };
259
-
260
295
  export type PlanarFreehandContourSegmentationAnnotation =
261
296
  PlanarFreehandROIAnnotation & ContourSegmentationAnnotationData;
262
297