@cornerstonejs/tools 4.12.3 → 4.12.5

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 (32) hide show
  1. package/dist/esm/enums/MeasurementType.d.ts +6 -0
  2. package/dist/esm/enums/MeasurementType.js +7 -0
  3. package/dist/esm/enums/index.d.ts +1 -0
  4. package/dist/esm/enums/index.js +1 -0
  5. package/dist/esm/tools/SculptorTool/CircleSculptCursor.d.ts +8 -10
  6. package/dist/esm/tools/SculptorTool/CircleSculptCursor.js +33 -133
  7. package/dist/esm/tools/SculptorTool.d.ts +20 -5
  8. package/dist/esm/tools/SculptorTool.js +243 -52
  9. package/dist/esm/tools/annotation/BidirectionalTool.d.ts +0 -2
  10. package/dist/esm/tools/annotation/BidirectionalTool.js +24 -28
  11. package/dist/esm/tools/annotation/CircleROITool.d.ts +1 -2
  12. package/dist/esm/tools/annotation/CircleROITool.js +51 -44
  13. package/dist/esm/tools/annotation/EllipticalROITool.js +1 -1
  14. package/dist/esm/tools/annotation/LengthTool.d.ts +0 -2
  15. package/dist/esm/tools/annotation/LengthTool.js +13 -25
  16. package/dist/esm/tools/annotation/PlanarFreehandROITool.d.ts +2 -1
  17. package/dist/esm/tools/annotation/PlanarFreehandROITool.js +70 -68
  18. package/dist/esm/tools/base/BaseTool.d.ts +4 -2
  19. package/dist/esm/tools/base/BaseTool.js +38 -11
  20. package/dist/esm/tools/segmentation/BrushTool.js +9 -0
  21. package/dist/esm/tools/segmentation/CircleROIStartEndThresholdTool.js +4 -1
  22. package/dist/esm/types/CalculatorTypes.d.ts +4 -3
  23. package/dist/esm/types/ISculptToolShape.d.ts +6 -4
  24. package/dist/esm/utilities/contours/index.d.ts +1 -2
  25. package/dist/esm/utilities/contours/index.js +1 -2
  26. package/dist/esm/utilities/getCalibratedUnits.d.ts +2 -0
  27. package/dist/esm/utilities/getCalibratedUnits.js +32 -63
  28. package/dist/esm/version.d.ts +1 -1
  29. package/dist/esm/version.js +1 -1
  30. package/package.json +3 -3
  31. package/dist/esm/utilities/contours/calculatePerimeter.d.ts +0 -2
  32. package/dist/esm/utilities/contours/calculatePerimeter.js +0 -16
@@ -568,7 +568,7 @@ class EllipticalROITool extends AnnotationTool {
568
568
  const { worldWidth, worldHeight } = getWorldWidthAndHeightFromTwoPoints(viewPlaneNormal, viewUp, worldPos1, worldPos2);
569
569
  const isEmptyArea = worldWidth === 0 && worldHeight === 0;
570
570
  const handles = [pos1Index, pos2Index];
571
- const { scale, unit, areaUnit } = getCalibratedLengthUnitsAndScale(image, handles);
571
+ const { scale, areaUnit } = getCalibratedLengthUnitsAndScale(image, handles);
572
572
  const aspect = getCalibratedAspect(image);
573
573
  const area = Math.abs(Math.PI *
574
574
  (worldWidth / scale / 2) *
@@ -35,8 +35,6 @@ declare class LengthTool extends AnnotationTool {
35
35
  _activateDraw: (element: HTMLDivElement) => void;
36
36
  _deactivateDraw: (element: HTMLDivElement) => void;
37
37
  renderAnnotation: (enabledElement: Types.IEnabledElement, svgDrawingHelper: SVGDrawingHelper) => boolean;
38
- _calculateLength(pos1: any, pos2: any): number;
39
38
  _calculateCachedStats(annotation: any, renderingEngine: any, enabledElement: any): any;
40
- _isInsideVolume(index1: any, index2: any, dimensions: any): boolean;
41
39
  }
42
40
  export default LengthTool;
@@ -1,4 +1,4 @@
1
- import { Events, ChangeTypes } from '../../enums';
1
+ import { Events, ChangeTypes, MeasurementType } from '../../enums';
2
2
  import { getEnabledElement, utilities as csUtils, utilities, getEnabledElementByViewportId, } from '@cornerstonejs/core';
3
3
  import { getCalibratedLengthUnitsAndScale } from '../../utilities/getCalibratedUnits';
4
4
  import { AnnotationTool } from '../base';
@@ -15,7 +15,6 @@ import { getTextBoxCoordsCanvas } from '../../utilities/drawing';
15
15
  import triggerAnnotationRenderForViewportIds from '../../utilities/triggerAnnotationRenderForViewportIds';
16
16
  import { resetElementCursor, hideElementCursor, } from '../../cursors/elementCursor';
17
17
  import { getStyleProperty } from '../../stateManagement/annotation/config/helpers';
18
- const { transformWorldToIndex } = csUtils;
19
18
  class LengthTool extends AnnotationTool {
20
19
  static { this.toolName = 'Length'; }
21
20
  constructor(toolProps = {}, defaultToolProps = {
@@ -384,17 +383,9 @@ class LengthTool extends AnnotationTool {
384
383
  triggerAnnotationRenderForViewportIds(viewportIdsToRender);
385
384
  evt.preventDefault();
386
385
  }
387
- _calculateLength(pos1, pos2) {
388
- const dx = pos1[0] - pos2[0];
389
- const dy = pos1[1] - pos2[1];
390
- const dz = pos1[2] - pos2[2];
391
- return Math.sqrt(dx * dx + dy * dy + dz * dz);
392
- }
393
386
  _calculateCachedStats(annotation, renderingEngine, enabledElement) {
394
387
  const data = annotation.data;
395
388
  const { element } = enabledElement.viewport;
396
- const worldPos1 = data.handles.points[0];
397
- const worldPos2 = data.handles.points[1];
398
389
  const { cachedStats } = data;
399
390
  const targetIds = Object.keys(cachedStats);
400
391
  for (let i = 0; i < targetIds.length; i++) {
@@ -404,20 +395,21 @@ class LengthTool extends AnnotationTool {
404
395
  continue;
405
396
  }
406
397
  const { imageData, dimensions } = image;
407
- const index1 = transformWorldToIndex(imageData, worldPos1);
408
- const index2 = transformWorldToIndex(imageData, worldPos2);
409
- const handles = [index1, index2];
410
- const { scale, unit } = getCalibratedLengthUnitsAndScale(image, handles);
411
- const length = this._calculateLength(worldPos1, worldPos2) / scale;
412
- if (this._isInsideVolume(index1, index2, dimensions)) {
413
- this.isHandleOutsideImage = false;
414
- }
415
- else {
416
- this.isHandleOutsideImage = true;
417
- }
398
+ const handles = data.handles.points.map((point) => imageData.worldToIndex(point));
399
+ const calibrate = getCalibratedLengthUnitsAndScale(image, handles);
400
+ const { unit } = calibrate;
401
+ const length = LengthTool.calculateLengthInIndex(calibrate, handles);
402
+ this.isHandleOutsideImage = !LengthTool.isInsideVolume(dimensions, handles);
403
+ const namedLength = {
404
+ name: 'length',
405
+ value: length,
406
+ unit,
407
+ type: MeasurementType.Linear,
408
+ };
418
409
  cachedStats[targetId] = {
419
410
  length,
420
411
  unit,
412
+ statsArray: [namedLength],
421
413
  };
422
414
  }
423
415
  const invalidated = annotation.invalidated;
@@ -427,10 +419,6 @@ class LengthTool extends AnnotationTool {
427
419
  }
428
420
  return cachedStats;
429
421
  }
430
- _isInsideVolume(index1, index2, dimensions) {
431
- return (csUtils.indexWithinDimensions(index1, dimensions) &&
432
- csUtils.indexWithinDimensions(index2, dimensions));
433
- }
434
422
  }
435
423
  function defaultGetTextLines(data, targetId) {
436
424
  const cachedVolumeStats = data.cachedStats[targetId];
@@ -48,12 +48,13 @@ declare class PlanarFreehandROITool extends ContourSegmentationBaseTool {
48
48
  deltaInX: any;
49
49
  deltaInY: any;
50
50
  }): void;
51
- protected updateOpenCachedStats({ targetId, metadata, cachedStats, modalityUnit, calibratedScale, points, }: {
51
+ protected updateOpenCachedStats({ targetId, metadata, cachedStats, modalityUnit, calibratedScale, imageData, points, }: {
52
52
  targetId: any;
53
53
  metadata: any;
54
54
  cachedStats: any;
55
55
  modalityUnit: any;
56
56
  calibratedScale: any;
57
+ imageData: any;
57
58
  points: any;
58
59
  }): void;
59
60
  private _renderStats;
@@ -19,9 +19,8 @@ import { getTextBoxCoordsCanvas } from '../../utilities/drawing';
19
19
  import { getLineSegmentIntersectionsCoordinates } from '../../utilities/math/polyline';
20
20
  import { isViewportPreScaled } from '../../utilities/viewport/isViewportPreScaled';
21
21
  import { BasicStatsCalculator } from '../../utilities/math/basic';
22
- import calculatePerimeter from '../../utilities/contours/calculatePerimeter';
23
22
  import ContourSegmentationBaseTool from '../base/ContourSegmentationBaseTool';
24
- import { KeyboardBindings, ChangeTypes } from '../../enums';
23
+ import { KeyboardBindings, ChangeTypes, MeasurementType } from '../../enums';
25
24
  import { getPixelValueUnits } from '../../utilities/getPixelValueUnits';
26
25
  const { pointCanProjectOnLine } = polyline;
27
26
  const { EPSILON } = CONSTANTS;
@@ -150,23 +149,22 @@ class PlanarFreehandROITool extends ContourSegmentationBaseTool {
150
149
  isSuvScaled: this.isSuvScaled(viewport, targetId, annotation.metadata.referencedImageId),
151
150
  };
152
151
  const modalityUnit = getPixelValueUnits(metadata.Modality, annotation.metadata.referencedImageId, modalityUnitOptions);
153
- const calibratedScale = getCalibratedLengthUnitsAndScale(image, () => {
154
- const polyline = data.contour.polyline;
155
- const numPoints = polyline.length;
156
- const projectedPolyline = new Array(numPoints);
157
- for (let i = 0; i < numPoints; i++) {
158
- projectedPolyline[i] = viewport.worldToCanvas(polyline[i]);
159
- }
160
- const { maxX: canvasMaxX, maxY: canvasMaxY, minX: canvasMinX, minY: canvasMinY, } = math.polyline.getAABB(projectedPolyline);
161
- const topLeftBBWorld = viewport.canvasToWorld([canvasMinX, canvasMinY]);
162
- const topLeftBBIndex = csUtils.transformWorldToIndex(imageData, topLeftBBWorld);
163
- const bottomRightBBWorld = viewport.canvasToWorld([
164
- canvasMaxX,
165
- canvasMaxY,
166
- ]);
167
- const bottomRightBBIndex = csUtils.transformWorldToIndex(imageData, bottomRightBBWorld);
168
- return [topLeftBBIndex, bottomRightBBIndex];
169
- });
152
+ const polyline = data.contour.polyline;
153
+ const numPoints = polyline.length;
154
+ const projectedPolyline = new Array(numPoints);
155
+ for (let i = 0; i < numPoints; i++) {
156
+ projectedPolyline[i] = viewport.worldToCanvas(polyline[i]);
157
+ }
158
+ const { maxX: canvasMaxX, maxY: canvasMaxY, minX: canvasMinX, minY: canvasMinY, } = math.polyline.getAABB(projectedPolyline);
159
+ const topLeftBBWorld = viewport.canvasToWorld([canvasMinX, canvasMinY]);
160
+ const topLeftBBIndex = csUtils.transformWorldToIndex(imageData, topLeftBBWorld);
161
+ const bottomRightBBWorld = viewport.canvasToWorld([
162
+ canvasMaxX,
163
+ canvasMaxY,
164
+ ]);
165
+ const bottomRightBBIndex = csUtils.transformWorldToIndex(imageData, bottomRightBBWorld);
166
+ const handles = [topLeftBBIndex, bottomRightBBIndex];
167
+ const calibratedScale = getCalibratedLengthUnitsAndScale(image, handles);
170
168
  const canvasPoint = canvasCoordinates[0];
171
169
  const originalWorldPoint = viewport.canvasToWorld(canvasPoint);
172
170
  const deltaXPoint = viewport.canvasToWorld([
@@ -179,30 +177,24 @@ class PlanarFreehandROITool extends ContourSegmentationBaseTool {
179
177
  ]);
180
178
  const deltaInX = vec3.distance(originalWorldPoint, deltaXPoint);
181
179
  const deltaInY = vec3.distance(originalWorldPoint, deltaYPoint);
180
+ const statsArgs = {
181
+ targetId,
182
+ viewport,
183
+ canvasCoordinates,
184
+ points,
185
+ imageData,
186
+ metadata,
187
+ cachedStats,
188
+ modalityUnit,
189
+ calibratedScale,
190
+ deltaInX,
191
+ deltaInY,
192
+ };
182
193
  if (closed) {
183
- this.updateClosedCachedStats({
184
- targetId,
185
- viewport,
186
- canvasCoordinates,
187
- points,
188
- imageData,
189
- metadata,
190
- cachedStats,
191
- modalityUnit,
192
- calibratedScale,
193
- deltaInX,
194
- deltaInY,
195
- });
194
+ this.updateClosedCachedStats(statsArgs);
196
195
  }
197
196
  else {
198
- this.updateOpenCachedStats({
199
- metadata,
200
- targetId,
201
- cachedStats,
202
- modalityUnit,
203
- calibratedScale,
204
- points,
205
- });
197
+ this.updateOpenCachedStats(statsArgs);
206
198
  }
207
199
  }
208
200
  const invalidated = annotation.invalidated;
@@ -255,12 +247,12 @@ class PlanarFreehandROITool extends ContourSegmentationBaseTool {
255
247
  this._throttledCalculateCachedStats = throttle(this._calculateCachedStats, 100, { trailing: true });
256
248
  }
257
249
  filterInteractableAnnotationsForElement(element, annotations) {
258
- if (!annotations || !annotations.length) {
259
- return;
250
+ if (!annotations?.length) {
251
+ return [];
260
252
  }
261
253
  const baseFilteredAnnotations = super.filterInteractableAnnotationsForElement(element, annotations);
262
- if (!baseFilteredAnnotations || !baseFilteredAnnotations.length) {
263
- return;
254
+ if (!baseFilteredAnnotations?.length) {
255
+ return [];
264
256
  }
265
257
  const enabledElement = getEnabledElement(element);
266
258
  const { viewport } = enabledElement;
@@ -432,21 +424,15 @@ class PlanarFreehandROITool extends ContourSegmentationBaseTool {
432
424
  updateClosedCachedStats({ viewport, points, imageData, metadata, cachedStats, targetId, modalityUnit, canvasCoordinates, calibratedScale, deltaInX, deltaInY, }) {
433
425
  const { scale, areaUnit, unit } = calibratedScale;
434
426
  const { voxelManager } = viewport.getImageData();
435
- const worldPosIndex = csUtils.transformWorldToIndex(imageData, points[0]);
436
- worldPosIndex[0] = Math.floor(worldPosIndex[0]);
437
- worldPosIndex[1] = Math.floor(worldPosIndex[1]);
438
- worldPosIndex[2] = Math.floor(worldPosIndex[2]);
439
- let iMin = worldPosIndex[0];
440
- let iMax = worldPosIndex[0];
441
- let jMin = worldPosIndex[1];
442
- let jMax = worldPosIndex[1];
443
- let kMin = worldPosIndex[2];
444
- let kMax = worldPosIndex[2];
445
- for (let j = 1; j < points.length; j++) {
446
- const worldPosIndex = csUtils.transformWorldToIndex(imageData, points[j]);
447
- worldPosIndex[0] = Math.floor(worldPosIndex[0]);
448
- worldPosIndex[1] = Math.floor(worldPosIndex[1]);
449
- worldPosIndex[2] = Math.floor(worldPosIndex[2]);
427
+ const indexPoints = points.map((point) => imageData.worldToIndex(point));
428
+ let iMin = Number.MAX_SAFE_INTEGER;
429
+ let iMax = Number.MIN_SAFE_INTEGER;
430
+ let jMin = Number.MAX_SAFE_INTEGER;
431
+ let jMax = Number.MIN_SAFE_INTEGER;
432
+ let kMin = Number.MAX_SAFE_INTEGER;
433
+ let kMax = Number.MIN_SAFE_INTEGER;
434
+ for (let j = 0; j < points.length; j++) {
435
+ const worldPosIndex = indexPoints[j].map(Math.floor);
450
436
  iMin = Math.min(iMin, worldPosIndex[0]);
451
437
  iMax = Math.max(iMax, worldPosIndex[0]);
452
438
  jMin = Math.min(jMin, worldPosIndex[1]);
@@ -454,13 +440,9 @@ class PlanarFreehandROITool extends ContourSegmentationBaseTool {
454
440
  kMin = Math.min(kMin, worldPosIndex[2]);
455
441
  kMax = Math.max(kMax, worldPosIndex[2]);
456
442
  }
457
- const worldPosIndex2 = csUtils.transformWorldToIndex(imageData, points[1]);
458
- worldPosIndex2[0] = Math.floor(worldPosIndex2[0]);
459
- worldPosIndex2[1] = Math.floor(worldPosIndex2[1]);
460
- worldPosIndex2[2] = Math.floor(worldPosIndex2[2]);
461
443
  let area = polyline.getArea(canvasCoordinates) / scale / scale;
462
444
  area *= deltaInX * deltaInY;
463
- const perimeter = calculatePerimeter(points, closed) / scale;
445
+ const perimeter = PlanarFreehandROITool.calculateLengthInIndex(calibratedScale, indexPoints, closed);
464
446
  const iDelta = 0.01 * (iMax - iMin);
465
447
  const jDelta = 0.01 * (jMax - jMin);
466
448
  const kDelta = 0.01 * (kMax - kMin);
@@ -515,6 +497,18 @@ class PlanarFreehandROITool extends ContourSegmentationBaseTool {
515
497
  });
516
498
  }
517
499
  const stats = this.configuration.statsCalculator.getStatistics();
500
+ const namedArea = {
501
+ name: 'area',
502
+ value: area,
503
+ unit: areaUnit,
504
+ type: MeasurementType.Area,
505
+ };
506
+ const namedPerimeter = {
507
+ name: 'perimeter',
508
+ value: perimeter,
509
+ unit,
510
+ type: MeasurementType.Linear,
511
+ };
518
512
  cachedStats[targetId] = {
519
513
  Modality: metadata.Modality,
520
514
  area,
@@ -523,21 +517,29 @@ class PlanarFreehandROITool extends ContourSegmentationBaseTool {
523
517
  max: stats.max?.value,
524
518
  min: stats.min?.value,
525
519
  stdDev: stats.stdDev?.value,
526
- statsArray: stats.array,
520
+ statsArray: [namedArea, namedPerimeter, ...stats.array],
527
521
  pointsInShape: pointsInShape,
528
522
  areaUnit,
529
523
  modalityUnit,
530
524
  unit,
531
525
  };
532
526
  }
533
- updateOpenCachedStats({ targetId, metadata, cachedStats, modalityUnit, calibratedScale, points, }) {
534
- const { scale, unit } = calibratedScale;
535
- const length = calculatePerimeter(points, closed) / scale;
527
+ updateOpenCachedStats({ targetId, metadata, cachedStats, modalityUnit, calibratedScale, imageData, points, }) {
528
+ const { unit } = calibratedScale;
529
+ const indexPoints = points.map((point) => imageData.worldToIndex(point));
530
+ const length = PlanarFreehandROITool.calculateLengthInIndex(calibratedScale, indexPoints);
531
+ const namedLength = {
532
+ name: 'length',
533
+ value: length,
534
+ unit,
535
+ type: MeasurementType.Linear,
536
+ };
536
537
  cachedStats[targetId] = {
537
538
  Modality: metadata.Modality,
538
539
  length,
539
540
  modalityUnit,
540
541
  unit,
542
+ statArray: [namedLength],
541
543
  };
542
544
  }
543
545
  }
@@ -1,4 +1,4 @@
1
- import { utilities } from '@cornerstonejs/core';
1
+ import { utilities as csUtils } from '@cornerstonejs/core';
2
2
  import type { Types } from '@cornerstonejs/core';
3
3
  import ToolModes from '../../enums/ToolModes';
4
4
  import type StrategyCallbacks from '../../enums/StrategyCallbacks';
@@ -9,7 +9,7 @@ declare abstract class BaseTool {
9
9
  configuration: Record<string, any>;
10
10
  toolGroupId: string;
11
11
  mode: ToolModes;
12
- protected memo: utilities.HistoryMemo.Memo;
12
+ protected memo: csUtils.HistoryMemo.Memo;
13
13
  static defaults: {
14
14
  configuration: {
15
15
  strategies: {};
@@ -36,5 +36,7 @@ declare abstract class BaseTool {
36
36
  doneEditMemo(): void;
37
37
  static startGroupRecording(): void;
38
38
  static endGroupRecording(): void;
39
+ static calculateLengthInIndex(calibrate: any, indexPoints: any, closed?: boolean): number;
40
+ static isInsideVolume(dimensions: any, indexPoints: any): boolean;
39
41
  }
40
42
  export default BaseTool;
@@ -1,6 +1,6 @@
1
- import { utilities } from '@cornerstonejs/core';
1
+ import { utilities as csUtils } from '@cornerstonejs/core';
2
2
  import ToolModes from '../../enums/ToolModes';
3
- const { DefaultHistoryMemo } = utilities.HistoryMemo;
3
+ const { DefaultHistoryMemo } = csUtils.HistoryMemo;
4
4
  class BaseTool {
5
5
  static { this.defaults = {
6
6
  configuration: {
@@ -12,7 +12,7 @@ class BaseTool {
12
12
  }; }
13
13
  constructor(toolProps, defaultToolProps) {
14
14
  const mergedDefaults = BaseTool.mergeDefaultProps(BaseTool.defaults, defaultToolProps);
15
- const initialProps = utilities.deepMerge(mergedDefaults, toolProps);
15
+ const initialProps = csUtils.deepMerge(mergedDefaults, toolProps);
16
16
  const { configuration = {}, supportedInteractionTypes, toolGroupId, } = initialProps;
17
17
  this.toolGroupId = toolGroupId;
18
18
  this.supportedInteractionTypes = supportedInteractionTypes || [];
@@ -23,7 +23,7 @@ class BaseTool {
23
23
  if (!additionalProps) {
24
24
  return defaultProps;
25
25
  }
26
- return utilities.deepMerge(defaultProps, additionalProps);
26
+ return csUtils.deepMerge(defaultProps, additionalProps);
27
27
  }
28
28
  get toolName() {
29
29
  return this.getToolName();
@@ -43,7 +43,7 @@ class BaseTool {
43
43
  return strategies[activeStrategy][callbackType]?.call(this, enabledElement, operationData, ...extraArgs);
44
44
  }
45
45
  setConfiguration(newConfiguration) {
46
- this.configuration = utilities.deepMerge(this.configuration, newConfiguration);
46
+ this.configuration = csUtils.deepMerge(this.configuration, newConfiguration);
47
47
  }
48
48
  setActiveStrategy(strategyName) {
49
49
  this.setConfiguration({ activeStrategy: strategyName });
@@ -51,8 +51,8 @@ class BaseTool {
51
51
  getTargetImageData(targetId) {
52
52
  if (targetId.startsWith('imageId:')) {
53
53
  const imageId = targetId.split('imageId:')[1];
54
- const imageURI = utilities.imageIdToURI(imageId);
55
- let viewports = utilities.getViewportsWithImageURI(imageURI);
54
+ const imageURI = csUtils.imageIdToURI(imageId);
55
+ let viewports = csUtils.getViewportsWithImageURI(imageURI);
56
56
  if (!viewports || !viewports.length) {
57
57
  return;
58
58
  }
@@ -65,16 +65,16 @@ class BaseTool {
65
65
  return viewports[0].getImageData();
66
66
  }
67
67
  else if (targetId.startsWith('volumeId:')) {
68
- const volumeId = utilities.getVolumeId(targetId);
69
- const viewports = utilities.getViewportsWithVolumeId(volumeId);
68
+ const volumeId = csUtils.getVolumeId(targetId);
69
+ const viewports = csUtils.getViewportsWithVolumeId(volumeId);
70
70
  if (!viewports || !viewports.length) {
71
71
  return;
72
72
  }
73
73
  return viewports[0].getImageData();
74
74
  }
75
75
  else if (targetId.startsWith('videoId:')) {
76
- const imageURI = utilities.imageIdToURI(targetId);
77
- const viewports = utilities.getViewportsWithImageURI(imageURI);
76
+ const imageURI = csUtils.imageIdToURI(targetId);
77
+ const viewports = csUtils.getViewportsWithImageURI(imageURI);
78
78
  if (!viewports || !viewports.length) {
79
79
  return;
80
80
  }
@@ -129,6 +129,33 @@ class BaseTool {
129
129
  static endGroupRecording() {
130
130
  DefaultHistoryMemo.endGroupRecording();
131
131
  }
132
+ static calculateLengthInIndex(calibrate, indexPoints, closed = false) {
133
+ const scale = calibrate?.scale || 1;
134
+ const scaleY = calibrate?.scaleY || scale;
135
+ const scaleZ = calibrate?.scaleZ || scale;
136
+ let length = 0;
137
+ const count = indexPoints.length;
138
+ const start = closed ? 0 : 1;
139
+ let lastPoint = closed ? indexPoints[count - 1] : indexPoints[0];
140
+ for (let i = start; i < count; i++) {
141
+ const point = indexPoints[i];
142
+ const dx = (point[0] - lastPoint[0]) / scale;
143
+ const dy = (point[1] - lastPoint[1]) / scaleY;
144
+ const dz = (point[2] - lastPoint[2]) / scaleZ;
145
+ length += Math.sqrt(dx * dx + dy * dy + dz * dz);
146
+ lastPoint = point;
147
+ }
148
+ return length;
149
+ }
150
+ static isInsideVolume(dimensions, indexPoints) {
151
+ const { length: count } = indexPoints;
152
+ for (let i = 0; i < count; i++) {
153
+ if (!csUtils.indexWithinDimensions(indexPoints[i], dimensions)) {
154
+ return false;
155
+ }
156
+ }
157
+ return true;
158
+ }
132
159
  }
133
160
  BaseTool.toolName = 'BaseTool';
134
161
  export default BaseTool;
@@ -113,6 +113,9 @@ class BrushTool extends LabelmapBaseTool {
113
113
  const hoverData = this._hoverData || this.createHoverData(element);
114
114
  triggerAnnotationRenderForViewportUIDs(hoverData.viewportIdsToRender);
115
115
  const operationData = this.getOperationData(element);
116
+ if (!operationData) {
117
+ return false;
118
+ }
116
119
  this.applyActiveStrategyCallback(enabledElement, operationData, StrategyCallbacks.OnInteractionStart);
117
120
  return true;
118
121
  };
@@ -218,6 +221,9 @@ class BrushTool extends LabelmapBaseTool {
218
221
  this._hoverData = this.createHoverData(element, currentCanvas);
219
222
  this._calculateCursor(element, currentCanvas);
220
223
  const operationData = this.getOperationData(element);
224
+ if (!operationData) {
225
+ return;
226
+ }
221
227
  operationData.strokePointsWorld = [
222
228
  vec3.clone(this._lastDragInfo.world),
223
229
  vec3.clone(currentWorld),
@@ -238,6 +244,9 @@ class BrushTool extends LabelmapBaseTool {
238
244
  const { element } = eventData;
239
245
  const enabledElement = getEnabledElement(element);
240
246
  const operationData = this.getOperationData(element);
247
+ if (!operationData) {
248
+ return;
249
+ }
241
250
  if (!this._previewData.preview && !this._previewData.isDrag) {
242
251
  this.applyActiveStrategy(enabledElement, operationData);
243
252
  }
@@ -418,7 +418,10 @@ class CircleROIStartEndThresholdTool extends CircleROITool {
418
418
  worldPos2Index[2] = Math.floor(worldPos2Index[2]);
419
419
  worldPos2Index[indexOfProjection] =
420
420
  worldProjectionPointIndex[indexOfProjection];
421
- if (this._isInsideVolume(worldPos1Index, worldPos2Index, dimensions)) {
421
+ if (CircleROITool.isInsideVolume(dimensions, [
422
+ worldPos1Index,
423
+ worldPos2Index,
424
+ ])) {
422
425
  const iMin = Math.min(worldPos1Index[0], worldPos2Index[0]);
423
426
  const iMax = Math.max(worldPos1Index[0], worldPos2Index[0]);
424
427
  const jMin = Math.min(worldPos1Index[1], worldPos2Index[1]);
@@ -1,13 +1,15 @@
1
1
  import type { Types } from '@cornerstonejs/core';
2
- type Statistics = {
2
+ import type { MeasurementType } from '../enums/MeasurementType';
3
+ export type Statistics = {
3
4
  name: string;
4
5
  label?: string;
5
6
  value: number | number[];
6
7
  unit: null | string;
7
8
  pointIJK?: Types.Point3;
8
9
  pointLPS?: Types.Point3;
10
+ type?: MeasurementType;
9
11
  };
10
- type NamedStatistics = {
12
+ export type NamedStatistics = {
11
13
  mean: Statistics & {
12
14
  name: 'mean';
13
15
  };
@@ -60,4 +62,3 @@ type NamedStatistics = {
60
62
  }>;
61
63
  array: Statistics[];
62
64
  };
63
- export type { Statistics, NamedStatistics };
@@ -1,12 +1,14 @@
1
1
  import type { Types } from '@cornerstonejs/core';
2
2
  import type { SVGDrawingHelper, EventTypes, ContourAnnotation } from '.';
3
- import type { PushedHandles } from '../tools/SculptorTool/CircleSculptCursor';
4
- import type { SculptData } from '../tools/SculptorTool';
5
3
  export interface ISculptToolShape {
6
4
  renderShape(svgDrawingHelper: SVGDrawingHelper, canvasLocation: Types.Point2, options: any): void;
7
- pushHandles(viewport: Types.IViewport, sculptData: SculptData): PushedHandles;
8
5
  configureToolSize(evt: EventTypes.InteractionEventType): void;
6
+ interpolatePoint(viewport: Types.IViewport, angle: number, center: Types.Point2): Types.Point2;
7
+ getEdge(viewport: Types.IViewport, p1: Types.Point3, p2: Types.Point3, mouseCanvas: Types.Point2): {
8
+ point: Types.Point3;
9
+ angle: number;
10
+ canvasPoint: Types.Point2;
11
+ };
9
12
  updateToolSize(canvasCoords: Types.Point2, viewport: Types.IViewport, activeAnnotation: ContourAnnotation): void;
10
13
  getMaxSpacing(minSpacing: number): number;
11
- getInsertPosition(previousIndex: number, nextIndex: number, sculptData: SculptData): Types.Point3;
12
14
  }
@@ -10,6 +10,5 @@ import getContourHolesDataCanvas from './getContourHolesDataCanvas';
10
10
  import updateContourPolyline from './updateContourPolyline';
11
11
  import acceptAutogeneratedInterpolations from './interpolation/acceptAutogeneratedInterpolations';
12
12
  import findHandlePolylineIndex from './findHandlePolylineIndex';
13
- import calculatePerimeter from './calculatePerimeter';
14
13
  import findIslands from './findIslands';
15
- export { areCoplanarContours, contourFinder, getDeduplicatedVTKPolyDataPoints, detectContourHoles, findContourHoles, generateContourSetsFromLabelmap, AnnotationToPointData, getContourHolesDataWorld, getContourHolesDataCanvas, updateContourPolyline, acceptAutogeneratedInterpolations, findHandlePolylineIndex, calculatePerimeter, findIslands, };
14
+ export { areCoplanarContours, contourFinder, getDeduplicatedVTKPolyDataPoints, detectContourHoles, findContourHoles, generateContourSetsFromLabelmap, AnnotationToPointData, getContourHolesDataWorld, getContourHolesDataCanvas, updateContourPolyline, acceptAutogeneratedInterpolations, findHandlePolylineIndex, findIslands, };
@@ -10,6 +10,5 @@ import getContourHolesDataCanvas from './getContourHolesDataCanvas';
10
10
  import updateContourPolyline from './updateContourPolyline';
11
11
  import acceptAutogeneratedInterpolations from './interpolation/acceptAutogeneratedInterpolations';
12
12
  import findHandlePolylineIndex from './findHandlePolylineIndex';
13
- import calculatePerimeter from './calculatePerimeter';
14
13
  import findIslands from './findIslands';
15
- export { areCoplanarContours, contourFinder, getDeduplicatedVTKPolyDataPoints, detectContourHoles, findContourHoles, generateContourSetsFromLabelmap, AnnotationToPointData, getContourHolesDataWorld, getContourHolesDataCanvas, updateContourPolyline, acceptAutogeneratedInterpolations, findHandlePolylineIndex, calculatePerimeter, findIslands, };
14
+ export { areCoplanarContours, contourFinder, getDeduplicatedVTKPolyDataPoints, detectContourHoles, findContourHoles, generateContourSetsFromLabelmap, AnnotationToPointData, getContourHolesDataWorld, getContourHolesDataCanvas, updateContourPolyline, acceptAutogeneratedInterpolations, findHandlePolylineIndex, findIslands, };
@@ -2,6 +2,8 @@ declare const getCalibratedLengthUnitsAndScale: (image: any, handles: any) => {
2
2
  unit: string;
3
3
  areaUnit: string;
4
4
  scale: number;
5
+ scaleY: number;
6
+ scaleZ: number;
5
7
  volumeUnit: string;
6
8
  };
7
9
  declare const getCalibratedProbeUnitsAndValue: (image: any, handles: any) => {