@cornerstonejs/tools 2.18.3 → 2.18.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.
@@ -0,0 +1,8 @@
1
+ interface RotationMatrixInformation {
2
+ isStandard: boolean;
3
+ rotationMatrix: number[];
4
+ }
5
+ export declare function inverse3x3Matrix(matrix: number[]): number[];
6
+ export declare function checkStandardBasis(directions: number[]): RotationMatrixInformation;
7
+ export declare function rotatePoints(rotationMatrix: number[], origin: number[], points: number[]): number[];
8
+ export {};
@@ -0,0 +1,103 @@
1
+ function validate3x3Matrix(matrix) {
2
+ if (!Array.isArray(matrix) || matrix.length !== 9) {
3
+ throw new Error('Matrix must be an array of 9 numbers');
4
+ }
5
+ if (!matrix.every((n) => typeof n === 'number' && !isNaN(n))) {
6
+ throw new Error('Matrix must contain only valid numbers');
7
+ }
8
+ }
9
+ export function inverse3x3Matrix(matrix) {
10
+ validate3x3Matrix(matrix);
11
+ const mat = [
12
+ [matrix[0], matrix[1], matrix[2]],
13
+ [matrix[3], matrix[4], matrix[5]],
14
+ [matrix[6], matrix[7], matrix[8]],
15
+ ];
16
+ const determinant = mat[0][0] * (mat[1][1] * mat[2][2] - mat[1][2] * mat[2][1]) -
17
+ mat[0][1] * (mat[1][0] * mat[2][2] - mat[1][2] * mat[2][0]) +
18
+ mat[0][2] * (mat[1][0] * mat[2][1] - mat[1][1] * mat[2][0]);
19
+ if (Math.abs(determinant) < 1e-10) {
20
+ throw new Error('Matrix is not invertible (determinant is zero)');
21
+ }
22
+ const adjugate = [
23
+ [
24
+ mat[1][1] * mat[2][2] - mat[1][2] * mat[2][1],
25
+ -(mat[0][1] * mat[2][2] - mat[0][2] * mat[2][1]),
26
+ mat[0][1] * mat[1][2] - mat[0][2] * mat[1][1],
27
+ ],
28
+ [
29
+ -(mat[1][0] * mat[2][2] - mat[1][2] * mat[2][0]),
30
+ mat[0][0] * mat[2][2] - mat[0][2] * mat[2][0],
31
+ -(mat[0][0] * mat[1][2] - mat[0][2] * mat[1][0]),
32
+ ],
33
+ [
34
+ mat[1][0] * mat[2][1] - mat[1][1] * mat[2][0],
35
+ -(mat[0][0] * mat[2][1] - mat[0][1] * mat[2][0]),
36
+ mat[0][0] * mat[1][1] - mat[0][1] * mat[1][0],
37
+ ],
38
+ ];
39
+ const inverse = [];
40
+ for (let i = 0; i < 3; i++) {
41
+ for (let j = 0; j < 3; j++) {
42
+ inverse.push(adjugate[i][j] / determinant);
43
+ }
44
+ }
45
+ return inverse;
46
+ }
47
+ function normalizeVector(v) {
48
+ const magnitude = Math.sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]);
49
+ return v.map((component) => component / magnitude);
50
+ }
51
+ export function checkStandardBasis(directions) {
52
+ validate3x3Matrix(directions);
53
+ const xVector = directions.slice(0, 3);
54
+ const yVector = directions.slice(3, 6);
55
+ const zVector = directions.slice(6, 9);
56
+ const normalizedX = normalizeVector(xVector);
57
+ const normalizedY = normalizeVector(yVector);
58
+ const normalizedZ = normalizeVector(zVector);
59
+ const standardBasis = {
60
+ x: [1, 0, 0],
61
+ y: [0, 1, 0],
62
+ z: [0, 0, 1],
63
+ };
64
+ const epsilon = 1e-10;
65
+ const isStandard = normalizedX.every((val, i) => Math.abs(val - standardBasis.x[i]) < epsilon) &&
66
+ normalizedY.every((val, i) => Math.abs(val - standardBasis.y[i]) < epsilon) &&
67
+ normalizedZ.every((val, i) => Math.abs(val - standardBasis.z[i]) < epsilon);
68
+ const rotationMatrix = isStandard
69
+ ? [...standardBasis.x, ...standardBasis.y, ...standardBasis.z]
70
+ : inverse3x3Matrix([...normalizedX, ...normalizedY, ...normalizedZ]);
71
+ return {
72
+ isStandard,
73
+ rotationMatrix,
74
+ };
75
+ }
76
+ function rotatePoint(point, origin, rotationMatrix) {
77
+ const x = point[0] - origin[0];
78
+ const y = point[1] - origin[1];
79
+ const z = point[2] - origin[2];
80
+ return [
81
+ rotationMatrix[0] * x +
82
+ rotationMatrix[1] * y +
83
+ rotationMatrix[2] * z +
84
+ origin[0],
85
+ rotationMatrix[3] * x +
86
+ rotationMatrix[4] * y +
87
+ rotationMatrix[5] * z +
88
+ origin[1],
89
+ rotationMatrix[6] * x +
90
+ rotationMatrix[7] * y +
91
+ rotationMatrix[8] * z +
92
+ origin[2],
93
+ ];
94
+ }
95
+ export function rotatePoints(rotationMatrix, origin, points) {
96
+ const rotatedPoints = [];
97
+ for (let i = 0; i < points.length; i += 3) {
98
+ const point = points.slice(i, i + 3);
99
+ const rotated = rotatePoint(point, origin, rotationMatrix);
100
+ rotatedPoints.push(...rotated);
101
+ }
102
+ return rotatedPoints;
103
+ }
@@ -67,7 +67,13 @@ export default class BrushStrategy {
67
67
  }) => import("../../../types").NamedStatistics;
68
68
  };
69
69
  labelmapInterpolation: {
70
- interpolate: (operationData: InitializedOperationData, configuration: import("@itk-wasm/morphological-contour-interpolation").MorphologicalContourInterpolationOptions) => InitializedOperationData;
70
+ interpolate: (operationData: InitializedOperationData, configuration: {
71
+ label?: number;
72
+ axis?: number;
73
+ noHeuristicAlignment?: boolean;
74
+ noUseDistanceTransform?: boolean;
75
+ useCustomSlicePositions?: boolean;
76
+ }) => Promise<InitializedOperationData>;
71
77
  };
72
78
  };
73
79
  protected static childFunctions: {
@@ -38,7 +38,13 @@ declare const _default: {
38
38
  }) => import("../../../../types").NamedStatistics;
39
39
  };
40
40
  labelmapInterpolation: {
41
- interpolate: (operationData: import("../BrushStrategy").InitializedOperationData, configuration: import("@itk-wasm/morphological-contour-interpolation").MorphologicalContourInterpolationOptions) => import("../BrushStrategy").InitializedOperationData;
41
+ interpolate: (operationData: import("../BrushStrategy").InitializedOperationData, configuration: {
42
+ label?: number;
43
+ axis?: number;
44
+ noHeuristicAlignment?: boolean;
45
+ noUseDistanceTransform?: boolean;
46
+ useCustomSlicePositions?: boolean;
47
+ }) => Promise<import("../BrushStrategy").InitializedOperationData>;
42
48
  };
43
49
  };
44
50
  export default _default;
@@ -1,6 +1,12 @@
1
- import type { MorphologicalContourInterpolationOptions } from '@itk-wasm/morphological-contour-interpolation';
2
1
  import type { InitializedOperationData } from '../BrushStrategy';
2
+ type MorphologicalContourInterpolationOptions = {
3
+ label?: number;
4
+ axis?: number;
5
+ noHeuristicAlignment?: boolean;
6
+ noUseDistanceTransform?: boolean;
7
+ useCustomSlicePositions?: boolean;
8
+ };
3
9
  declare const _default: {
4
- interpolate: (operationData: InitializedOperationData, configuration: MorphologicalContourInterpolationOptions) => InitializedOperationData;
10
+ interpolate: (operationData: InitializedOperationData, configuration: MorphologicalContourInterpolationOptions) => Promise<InitializedOperationData>;
5
11
  };
6
12
  export default _default;
@@ -1,12 +1,10 @@
1
- import { morphologicalContourInterpolation } from '@itk-wasm/morphological-contour-interpolation';
2
- import { utilities } from '@cornerstonejs/core';
1
+ import { utilities, peerImport } from '@cornerstonejs/core';
3
2
  import StrategyCallbacks from '../../../../enums/StrategyCallbacks';
4
3
  import getItkImage from '../utils/getItkImage';
5
4
  import { triggerSegmentationDataModified } from '../../../../stateManagement/segmentation/triggerSegmentationEvents';
6
5
  import PreviewMethods from './preview';
7
- const { VoxelManager } = utilities;
8
6
  export default {
9
- [StrategyCallbacks.Interpolate]: (operationData, configuration) => {
7
+ [StrategyCallbacks.Interpolate]: async (operationData, configuration) => {
10
8
  const { segmentationImageData, segmentIndex, preview, segmentationVoxelManager, previewSegmentIndex, previewVoxelManager, } = operationData;
11
9
  if (preview) {
12
10
  const callback = ({ index }) => {
@@ -15,7 +13,18 @@ export default {
15
13
  previewVoxelManager.forEach(callback);
16
14
  }
17
15
  const inputImage = getItkImage(segmentationImageData, 'interpolation');
18
- const outputPromise = morphologicalContourInterpolation(inputImage, {
16
+ let itkModule;
17
+ try {
18
+ itkModule = await peerImport('@itk-wasm/morphological-contour-interpolation');
19
+ if (!itkModule) {
20
+ throw new Error('Module not found');
21
+ }
22
+ }
23
+ catch (error) {
24
+ console.debug("Warning: '@itk-wasm/morphological-contour-interpolation' module not found. Please install it separately.");
25
+ return operationData;
26
+ }
27
+ const outputPromise = itkModule.morphologicalContourInterpolation(inputImage, {
19
28
  ...configuration,
20
29
  label: segmentIndex,
21
30
  webWorker: false,
@@ -1 +1 @@
1
- export default function clip(a: any, b: any, box: any, da?: any, db?: any): 1 | 0;
1
+ export default function clip(a: any, b: any, box: any, da?: any, db?: any): 0 | 1;
@@ -2,7 +2,6 @@ import { expose } from 'comlink';
2
2
  import { utilities } from '@cornerstonejs/core';
3
3
  import vtkImageData from '@kitware/vtk.js/Common/DataModel/ImageData';
4
4
  import vtkDataArray from '@kitware/vtk.js/Common/Core/DataArray';
5
- import ICRPolySeg from '@icr/polyseg-wasm';
6
5
  import vtkPlane from '@kitware/vtk.js/Common/DataModel/Plane';
7
6
  import vtkPolyData from '@kitware/vtk.js/Common/DataModel/PolyData';
8
7
  import vtkContourLoopExtraction from '@kitware/vtk.js/Filters/General/ContourLoopExtraction';
@@ -10,11 +9,21 @@ import vtkCutter from '@kitware/vtk.js/Filters/Core/Cutter';
10
9
  import { getBoundingBoxAroundShapeWorld } from '../utilities/boundingBox';
11
10
  import { containsPoint, getAABB, projectTo2D, } from '../utilities/math/polyline';
12
11
  import { isPlaneIntersectingAABB } from '../utilities/planar';
12
+ import { checkStandardBasis, rotatePoints } from '../geometricSurfaceUtils';
13
13
  const polySegConverters = {
14
14
  polySeg: null,
15
15
  polySegInitializing: false,
16
16
  polySegInitializingPromise: null,
17
17
  async initializePolySeg(progressCallback) {
18
+ let ICRPolySeg;
19
+ try {
20
+ ICRPolySeg = (await import('@icr/polyseg-wasm')).default;
21
+ }
22
+ catch (error) {
23
+ console.error(error);
24
+ console.debug("Warning: '@icr/polyseg-wasm' module not found. Please install it separately.");
25
+ return;
26
+ }
18
27
  if (this.polySegInitializing) {
19
28
  await this.polySegInitializingPromise;
20
29
  return;
@@ -47,14 +56,16 @@ const polySegConverters = {
47
56
  const [progressCallback] = callbacks;
48
57
  await this.initializePolySeg(progressCallback);
49
58
  const results = this.polySeg.instance.convertLabelmapToSurface(args.scalarData, args.dimensions, args.spacing, args.direction, args.origin, [args.segmentIndex]);
59
+ const rotationInfo = checkStandardBasis(args.direction);
60
+ if (!rotationInfo.isStandard) {
61
+ const rotatedPoints = rotatePoints(rotationInfo.rotationMatrix, args.origin, results.points);
62
+ results.points = [...rotatedPoints];
63
+ }
50
64
  return results;
51
65
  },
52
66
  async convertContourToVolumeLabelmap(args, ...callbacks) {
53
67
  const [progressCallback] = callbacks;
54
- const polySeg = await new ICRPolySeg();
55
- await polySeg.initialize({
56
- updateProgress: progressCallback,
57
- });
68
+ await this.initializePolySeg(progressCallback);
58
69
  const { segmentIndices, scalarData, annotationUIDsInSegmentMap, dimensions, origin, direction, spacing, } = args;
59
70
  const segmentationVoxelManager = utilities.VoxelManager.createScalarVolumeVoxelManager({
60
71
  dimensions,
@@ -124,10 +135,7 @@ const polySegConverters = {
124
135
  },
125
136
  async convertContourToStackLabelmap(args, ...callbacks) {
126
137
  const [progressCallback] = callbacks;
127
- const polySeg = await new ICRPolySeg();
128
- await polySeg.initialize({
129
- updateProgress: progressCallback,
130
- });
138
+ await this.initializePolySeg(progressCallback);
131
139
  const { segmentationsInfo, annotationUIDsInSegmentMap, segmentIndices } = args;
132
140
  const segmentationVoxelManagers = new Map();
133
141
  segmentationsInfo.forEach((segmentationInfo, referencedImageId) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cornerstonejs/tools",
3
- "version": "2.18.3",
3
+ "version": "2.18.5",
4
4
  "description": "Cornerstone3D Tools",
5
5
  "types": "./dist/esm/index.d.ts",
6
6
  "module": "./dist/esm/index.js",
@@ -104,7 +104,7 @@
104
104
  "canvas": "^2.11.2"
105
105
  },
106
106
  "peerDependencies": {
107
- "@cornerstonejs/core": "^2.18.3",
107
+ "@cornerstonejs/core": "^2.18.5",
108
108
  "@kitware/vtk.js": "32.9.0",
109
109
  "@types/d3-array": "^3.0.4",
110
110
  "@types/d3-interpolate": "^3.0.1",
@@ -123,5 +123,5 @@
123
123
  "type": "individual",
124
124
  "url": "https://ohif.org/donate"
125
125
  },
126
- "gitHead": "cc92461656c37883686759ab4b495219046f4be7"
126
+ "gitHead": "be8bb617be050ca5aa5a9d2d61013a9c674efa5d"
127
127
  }