@cornerstonejs/tools 3.31.10 → 3.31.12

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.
@@ -1,11 +1,8 @@
1
- import { vec3 } from 'gl-matrix';
2
1
  import type { Types } from '@cornerstonejs/core';
3
2
  import BrushStrategy from './BrushStrategy';
4
- declare function createPointInEllipse(worldInfo: {
5
- topLeftWorld: Types.Point3;
6
- bottomRightWorld: Types.Point3;
7
- center: Types.Point3 | vec3;
8
- }): (pointLPS: Types.Point3) => boolean;
3
+ import type { CanvasCoordinates } from '../../../types';
4
+ export declare function getEllipseCornersFromCanvasCoordinates(canvasCoordinates: CanvasCoordinates): Array<Types.Point2>;
5
+ declare function createPointInEllipse(cornersInWorld?: Types.Point3[]): (pointLPS: Types.Point3) => boolean;
9
6
  declare const CIRCLE_STRATEGY: BrushStrategy;
10
7
  declare const CIRCLE_THRESHOLD_STRATEGY: BrushStrategy;
11
8
  declare const fillInsideCircle: (enabledElement: any, operationData: any) => unknown;
@@ -1,50 +1,67 @@
1
1
  import { vec3 } from 'gl-matrix';
2
2
  import { utilities as csUtils } from '@cornerstonejs/core';
3
- import { getCanvasEllipseCorners, precalculatePointInEllipse, } from '../../../utilities/math/ellipse';
4
3
  import { getBoundingBoxAroundShapeIJK } from '../../../utilities/boundingBox';
5
4
  import BrushStrategy from './BrushStrategy';
6
5
  import { StrategyCallbacks } from '../../../enums';
7
6
  import compositions from './compositions';
8
7
  import { pointInSphere } from '../../../utilities/math/sphere';
9
8
  const { transformWorldToIndex, isEqual } = csUtils;
9
+ export function getEllipseCornersFromCanvasCoordinates(canvasCoordinates) {
10
+ const [bottom, top, left, right] = canvasCoordinates;
11
+ const topLeft = [left[0], top[1]];
12
+ const bottomRight = [right[0], bottom[1]];
13
+ const bottomLeft = [left[0], bottom[1]];
14
+ const topRight = [right[0], top[1]];
15
+ return [topLeft, bottomRight, bottomLeft, topRight];
16
+ }
10
17
  const initializeCircle = {
11
18
  [StrategyCallbacks.Initialize]: (operationData) => {
12
19
  const { points, viewport, segmentationImageData, } = operationData;
13
20
  if (!points) {
14
21
  return;
15
22
  }
16
- const center = vec3.fromValues(0, 0, 0);
17
- points.forEach((point) => {
18
- vec3.add(center, center, point);
19
- });
20
- vec3.scale(center, center, 1 / points.length);
23
+ const center = vec3.create();
24
+ if (points.length >= 2) {
25
+ vec3.add(center, points[0], points[1]);
26
+ vec3.scale(center, center, 0.5);
27
+ }
28
+ else {
29
+ vec3.copy(center, points[0]);
30
+ }
21
31
  operationData.centerWorld = center;
22
32
  operationData.centerIJK = transformWorldToIndex(segmentationImageData, center);
23
33
  const canvasCoordinates = points.map((p) => viewport.worldToCanvas(p));
24
- const [topLeftCanvas, bottomRightCanvas] = getCanvasEllipseCorners(canvasCoordinates);
25
- const topLeftWorld = viewport.canvasToWorld(topLeftCanvas);
26
- const bottomRightWorld = viewport.canvasToWorld(bottomRightCanvas);
34
+ const corners = getEllipseCornersFromCanvasCoordinates(canvasCoordinates);
35
+ const cornersInWorld = corners.map((corner) => viewport.canvasToWorld(corner));
27
36
  const circleCornersIJK = points.map((world) => {
28
37
  return transformWorldToIndex(segmentationImageData, world);
29
38
  });
30
39
  const boundsIJK = getBoundingBoxAroundShapeIJK(circleCornersIJK, segmentationImageData.getDimensions());
31
- operationData.isInObject = createPointInEllipse({
32
- topLeftWorld,
33
- bottomRightWorld,
34
- center,
35
- });
40
+ operationData.isInObject = createPointInEllipse(cornersInWorld);
36
41
  operationData.isInObjectBoundsIJK = boundsIJK;
37
42
  },
38
43
  };
39
- function createPointInEllipse(worldInfo) {
40
- const { topLeftWorld, bottomRightWorld, center } = worldInfo;
41
- const xRadius = Math.abs(topLeftWorld[0] - bottomRightWorld[0]) / 2;
42
- const yRadius = Math.abs(topLeftWorld[1] - bottomRightWorld[1]) / 2;
43
- const zRadius = Math.abs(topLeftWorld[2] - bottomRightWorld[2]) / 2;
44
- const radius = Math.max(xRadius, yRadius, zRadius);
45
- if (isEqual(xRadius, radius) &&
46
- isEqual(yRadius, radius) &&
47
- isEqual(zRadius, radius)) {
44
+ function createPointInEllipse(cornersInWorld = []) {
45
+ if (!cornersInWorld || cornersInWorld.length !== 4) {
46
+ throw new Error('createPointInEllipse: cornersInWorld must have 4 points');
47
+ }
48
+ const [topLeft, bottomRight, bottomLeft, topRight] = cornersInWorld;
49
+ const center = vec3.create();
50
+ vec3.add(center, topLeft, bottomRight);
51
+ vec3.scale(center, center, 0.5);
52
+ const majorAxisVec = vec3.create();
53
+ vec3.subtract(majorAxisVec, topRight, topLeft);
54
+ const xRadius = vec3.length(majorAxisVec) / 2;
55
+ vec3.normalize(majorAxisVec, majorAxisVec);
56
+ const minorAxisVec = vec3.create();
57
+ vec3.subtract(minorAxisVec, bottomLeft, topLeft);
58
+ const yRadius = vec3.length(minorAxisVec) / 2;
59
+ vec3.normalize(minorAxisVec, minorAxisVec);
60
+ const normal = vec3.create();
61
+ vec3.cross(normal, majorAxisVec, minorAxisVec);
62
+ vec3.normalize(normal, normal);
63
+ if (isEqual(xRadius, yRadius)) {
64
+ const radius = xRadius;
48
65
  const sphereObj = {
49
66
  center,
50
67
  radius,
@@ -52,14 +69,20 @@ function createPointInEllipse(worldInfo) {
52
69
  };
53
70
  return (pointLPS) => pointInSphere(sphereObj, pointLPS);
54
71
  }
55
- const ellipseObj = {
56
- center: center,
57
- xRadius,
58
- yRadius,
59
- zRadius,
72
+ return (pointLPS) => {
73
+ const pointVec = vec3.create();
74
+ vec3.subtract(pointVec, pointLPS, center);
75
+ const distToPlane = vec3.dot(pointVec, normal);
76
+ const proj = vec3.create();
77
+ vec3.scaleAndAdd(proj, pointVec, normal, -distToPlane);
78
+ const fromTopLeft = vec3.create();
79
+ const centerToTopLeft = vec3.create();
80
+ vec3.subtract(centerToTopLeft, center, topLeft);
81
+ vec3.subtract(fromTopLeft, proj, centerToTopLeft);
82
+ const x = vec3.dot(fromTopLeft, majorAxisVec);
83
+ const y = vec3.dot(fromTopLeft, minorAxisVec);
84
+ return (x * x) / (xRadius * xRadius) + (y * y) / (yRadius * yRadius) <= 1;
60
85
  };
61
- const { precalculated } = precalculatePointInEllipse(ellipseObj, {});
62
- return precalculated;
63
86
  }
64
87
  const CIRCLE_STRATEGY = new BrushStrategy('Circle', compositions.regionFill, compositions.setValue, initializeCircle, compositions.determineSegmentIndex, compositions.preview, compositions.labelmapStatistics);
65
88
  const CIRCLE_THRESHOLD_STRATEGY = new BrushStrategy('CircleThreshold', compositions.regionFill, compositions.setValue, initializeCircle, compositions.determineSegmentIndex, compositions.dynamicThreshold, compositions.threshold, compositions.preview, compositions.islandRemoval, compositions.labelmapStatistics);
@@ -1,16 +1,13 @@
1
1
  import { vec3 } from 'gl-matrix';
2
2
  import { utilities as csUtils, StackViewport } from '@cornerstonejs/core';
3
- import { getBoundingBoxAroundShapeIJK, getBoundingBoxAroundShapeWorld, } from '../../../utilities/boundingBox';
4
- import { triggerSegmentationDataModified } from '../../../stateManagement/segmentation/triggerSegmentationEvents';
5
- import { getStrategyData } from './utils/getStrategyData';
6
- import { isAxisAlignedRectangle } from '../../../utilities/rectangleROITool/isAxisAlignedRectangle';
3
+ import { getBoundingBoxAroundShapeIJK } from '../../../utilities/boundingBox';
7
4
  import BrushStrategy from './BrushStrategy';
8
5
  import { StrategyCallbacks } from '../../../enums';
9
6
  import compositions from './compositions';
10
7
  const { transformWorldToIndex } = csUtils;
11
8
  const initializeRectangle = {
12
9
  [StrategyCallbacks.Initialize]: (operationData) => {
13
- const { points, imageVoxelManager, viewport, segmentationImageData, segmentationVoxelManager, } = operationData;
10
+ const { points, viewport, segmentationImageData, } = operationData;
14
11
  if (!points) {
15
12
  return;
16
13
  }
@@ -36,8 +33,18 @@ function createPointInRectangle(viewport, points, segmentationImageData) {
36
33
  });
37
34
  });
38
35
  const boundsIJK = getBoundingBoxAroundShapeIJK(rectangleCornersIJK, segmentationImageData.getDimensions());
39
- const isStackViewport = viewport instanceof StackViewport;
40
- const isAligned = isStackViewport || isAxisAlignedRectangle(rectangleCornersIJK);
36
+ const [p0, p1, p2, p3] = points;
37
+ const axisU = vec3.create();
38
+ const axisV = vec3.create();
39
+ vec3.subtract(axisU, p1, p0);
40
+ vec3.subtract(axisV, p3, p0);
41
+ const uLen = vec3.length(axisU);
42
+ const vLen = vec3.length(axisV);
43
+ vec3.normalize(axisU, axisU);
44
+ vec3.normalize(axisV, axisV);
45
+ const normal = vec3.create();
46
+ vec3.cross(normal, axisU, axisV);
47
+ vec3.normalize(normal, normal);
41
48
  const direction = segmentationImageData.getDirection();
42
49
  const spacing = segmentationImageData.getSpacing();
43
50
  const { viewPlaneNormal } = viewport.getCamera();
@@ -45,23 +52,18 @@ function createPointInRectangle(viewport, points, segmentationImageData) {
45
52
  direction,
46
53
  spacing,
47
54
  }, viewPlaneNormal);
48
- const pointsBoundsLPS = getBoundingBoxAroundShapeWorld(points);
49
- let [[xMin, xMax], [yMin, yMax], [zMin, zMax]] = pointsBoundsLPS;
50
- xMin -= EPS;
51
- xMax += EPS;
52
- yMin -= EPS;
53
- yMax += EPS;
54
- zMin -= EPS;
55
- zMax += EPS;
56
- const pointInShapeFn = isAligned
57
- ? () => true
58
- : (pointLPS) => {
59
- const [x, y, z] = pointLPS;
60
- const xInside = x >= xMin && x <= xMax;
61
- const yInside = y >= yMin && y <= yMax;
62
- const zInside = z >= zMin && z <= zMax;
63
- return xInside && yInside && zInside;
64
- };
55
+ const pointInShapeFn = (pointLPS) => {
56
+ const v = vec3.create();
57
+ vec3.subtract(v, pointLPS, p0);
58
+ const u = vec3.dot(v, axisU);
59
+ const vproj = vec3.dot(v, axisV);
60
+ const d = Math.abs(vec3.dot(v, normal));
61
+ return (u >= -EPS &&
62
+ u <= uLen + EPS &&
63
+ vproj >= -EPS &&
64
+ vproj <= vLen + EPS &&
65
+ d <= EPS);
66
+ };
65
67
  return { boundsIJK, pointInShapeFn };
66
68
  }
67
69
  const RECTANGLE_STRATEGY = new BrushStrategy('Rectangle', compositions.regionFill, compositions.setValue, initializeRectangle, compositions.determineSegmentIndex, compositions.preview, compositions.labelmapStatistics);
@@ -3,7 +3,7 @@ import { vec3 } from 'gl-matrix';
3
3
  import BrushStrategy from './BrushStrategy';
4
4
  import compositions from './compositions';
5
5
  import StrategyCallbacks from '../../../enums/StrategyCallbacks';
6
- import { createEllipseInPoint } from './fillCircle';
6
+ import { createEllipseInPoint, getEllipseCornersFromCanvasCoordinates, } from './fillCircle';
7
7
  const { transformWorldToIndex } = csUtils;
8
8
  import { getSphereBoundsInfoFromViewport } from '../../../utilities/getSphereBoundsInfo';
9
9
  const sphereComposition = {
@@ -12,20 +12,22 @@ const sphereComposition = {
12
12
  if (!points) {
13
13
  return;
14
14
  }
15
- const center = vec3.fromValues(0, 0, 0);
16
- points.forEach((point) => {
17
- vec3.add(center, center, point);
18
- });
19
- vec3.scale(center, center, 1 / points.length);
15
+ const center = vec3.create();
16
+ if (points.length >= 2) {
17
+ vec3.add(center, points[0], points[1]);
18
+ vec3.scale(center, center, 0.5);
19
+ }
20
+ else {
21
+ vec3.copy(center, points[0]);
22
+ }
20
23
  operationData.centerWorld = center;
21
24
  operationData.centerIJK = transformWorldToIndex(segmentationImageData, center);
22
- const { boundsIJK: newBoundsIJK, topLeftWorld, bottomRightWorld, } = getSphereBoundsInfoFromViewport(points.slice(0, 2), segmentationImageData, viewport);
25
+ const { boundsIJK: newBoundsIJK } = getSphereBoundsInfoFromViewport(points.slice(0, 2), segmentationImageData, viewport);
26
+ const canvasCoordinates = points.map((p) => viewport.worldToCanvas(p));
27
+ const corners = getEllipseCornersFromCanvasCoordinates(canvasCoordinates);
28
+ const cornersInWorld = corners.map((corner) => viewport.canvasToWorld(corner));
23
29
  operationData.isInObjectBoundsIJK = newBoundsIJK;
24
- operationData.isInObject = createEllipseInPoint({
25
- topLeftWorld,
26
- bottomRightWorld,
27
- center,
28
- });
30
+ operationData.isInObject = createEllipseInPoint(cornersInWorld);
29
31
  },
30
32
  };
31
33
  const SPHERE_STRATEGY = new BrushStrategy('Sphere', compositions.regionFill, compositions.setValue, sphereComposition, compositions.determineSegmentIndex, compositions.preview, compositions.labelmapStatistics, compositions.ensureSegmentationVolumeFor3DManipulation);
@@ -1 +1 @@
1
- export declare const version = "3.31.10";
1
+ export declare const version = "3.31.12";
@@ -1 +1 @@
1
- export const version = '3.31.10';
1
+ export const version = '3.31.12';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cornerstonejs/tools",
3
- "version": "3.31.10",
3
+ "version": "3.31.12",
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.31.10",
111
+ "@cornerstonejs/core": "^3.31.12",
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": "df57f1e6505d3e058dbe3d9715da2d2cba89fe5a"
130
+ "gitHead": "56d8740d4fc313de859611b51e1d10b42cc6ffa1"
131
131
  }