@cornerstonejs/tools 1.84.0 → 1.84.2
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/cjs/utilities/planarFreehandROITool/smoothAnnotation.d.ts +5 -2
- package/dist/cjs/utilities/planarFreehandROITool/smoothAnnotation.js +44 -27
- package/dist/cjs/utilities/planarFreehandROITool/smoothAnnotation.js.map +1 -1
- package/dist/esm/utilities/planarFreehandROITool/smoothAnnotation.js +43 -26
- package/dist/esm/utilities/planarFreehandROITool/smoothAnnotation.js.map +1 -1
- package/dist/types/utilities/planarFreehandROITool/smoothAnnotation.d.ts +5 -2
- package/dist/types/utilities/planarFreehandROITool/smoothAnnotation.d.ts.map +1 -1
- package/dist/umd/index.js +1 -1
- package/dist/umd/index.js.map +1 -1
- package/package.json +3 -3
- package/src/utilities/planarFreehandROITool/smoothAnnotation.ts +86 -43
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cornerstonejs/tools",
|
|
3
|
-
"version": "1.84.
|
|
3
|
+
"version": "1.84.2",
|
|
4
4
|
"description": "Cornerstone3D Tools",
|
|
5
5
|
"main": "src/index.ts",
|
|
6
6
|
"types": "dist/types/index.d.ts",
|
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
"webpack:watch": "webpack --mode development --progress --watch --config ./.webpack/webpack.dev.js"
|
|
30
30
|
},
|
|
31
31
|
"dependencies": {
|
|
32
|
-
"@cornerstonejs/core": "^1.84.
|
|
32
|
+
"@cornerstonejs/core": "^1.84.2",
|
|
33
33
|
"@icr/polyseg-wasm": "0.4.0",
|
|
34
34
|
"@types/offscreencanvas": "2019.7.3",
|
|
35
35
|
"comlink": "^4.4.1",
|
|
@@ -59,5 +59,5 @@
|
|
|
59
59
|
"type": "individual",
|
|
60
60
|
"url": "https://ohif.org/donate"
|
|
61
61
|
},
|
|
62
|
-
"gitHead": "
|
|
62
|
+
"gitHead": "79667170db3c7d65acfcea1359c06b3f74763b40"
|
|
63
63
|
}
|
|
@@ -1,88 +1,131 @@
|
|
|
1
1
|
import { Types } from '@cornerstonejs/core';
|
|
2
|
+
import { mat4, vec3 } from 'gl-matrix';
|
|
2
3
|
import { PlanarFreehandROITool } from '../../tools';
|
|
3
4
|
import { ToolGroupManager } from '../../store';
|
|
4
5
|
import { PlanarFreehandROIAnnotation } from '../../types/ToolSpecificAnnotationTypes';
|
|
5
6
|
import interpolateSegmentPoints from './interpolation/interpolateSegmentPoints';
|
|
6
7
|
|
|
8
|
+
export type SmoothOptions = {
|
|
9
|
+
knotsRatioPercentage: number;
|
|
10
|
+
loop: number;
|
|
11
|
+
};
|
|
12
|
+
|
|
7
13
|
function shouldPreventInterpolation(
|
|
8
|
-
enabledElement: Types.IEnabledElement,
|
|
9
14
|
annotation: PlanarFreehandROIAnnotation,
|
|
10
|
-
|
|
15
|
+
options?: SmoothOptions
|
|
11
16
|
): boolean {
|
|
12
|
-
|
|
17
|
+
const knotsRatioPercentage = options?.knotsRatioPercentage || 30;
|
|
18
|
+
if (
|
|
19
|
+
!annotation?.data?.contour?.polyline?.length ||
|
|
20
|
+
knotsRatioPercentage <= 0
|
|
21
|
+
) {
|
|
13
22
|
return true;
|
|
14
23
|
}
|
|
15
24
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
}
|
|
25
|
+
return false;
|
|
26
|
+
}
|
|
19
27
|
|
|
20
|
-
|
|
21
|
-
const
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
28
|
+
function rotateMatrix(normal, focal) {
|
|
29
|
+
const mat = mat4.create();
|
|
30
|
+
const eye = vec3.add(vec3.create(), focal, normal);
|
|
31
|
+
const up =
|
|
32
|
+
Math.abs(normal[0]) > 0.1
|
|
33
|
+
? vec3.fromValues(-normal[1], normal[0], 0)
|
|
34
|
+
: vec3.fromValues(0, -normal[2], normal[1]);
|
|
35
|
+
// Use the focal point as the "eye" position so that the focal point get rotated to 0 for the k coordinate.
|
|
36
|
+
mat4.lookAt(mat, focal, eye, up);
|
|
37
|
+
return mat;
|
|
38
|
+
}
|
|
25
39
|
|
|
26
|
-
|
|
27
|
-
|
|
40
|
+
/**
|
|
41
|
+
* Rotate the array to prevent interpolation at endpoints causing non-smooth endpoints
|
|
42
|
+
* Rotates the list in place.
|
|
43
|
+
*/
|
|
44
|
+
function rotate(list, count = Math.floor(Math.random() * (list.length - 1))) {
|
|
45
|
+
if (count === 0) {
|
|
46
|
+
return 0;
|
|
28
47
|
}
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
48
|
+
const srcList = [...list];
|
|
49
|
+
const { length } = list;
|
|
50
|
+
for (let i = 0; i < length; i++) {
|
|
51
|
+
list[i] = srcList[(i + count + length) % length];
|
|
32
52
|
}
|
|
33
|
-
|
|
34
|
-
const toolInstance = toolGroup.getToolInstance(annotation.metadata.toolName);
|
|
35
|
-
|
|
36
|
-
// strategy to prevent non PlanarFreehandTool
|
|
37
|
-
if (!(toolInstance instanceof PlanarFreehandROITool)) {
|
|
38
|
-
return true;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
return (
|
|
42
|
-
toolInstance.isDrawing ||
|
|
43
|
-
toolInstance.isEditingOpen ||
|
|
44
|
-
toolInstance.isEditingClosed
|
|
45
|
-
);
|
|
53
|
+
return count;
|
|
46
54
|
}
|
|
55
|
+
|
|
47
56
|
/**
|
|
48
57
|
* Interpolates a given annotation from a given enabledElement.
|
|
49
58
|
* It mutates annotation param.
|
|
50
|
-
* The param knotsRatioPercentage defines the percentage of points to be considered as knots on the interpolation process.
|
|
51
|
-
*
|
|
59
|
+
* The param options.knotsRatioPercentage defines the percentage of points to be considered as knots on the interpolation process.
|
|
60
|
+
* The param options.loop can be set to run smoothing repeatedly. This results in
|
|
61
|
+
* additional smoothing.
|
|
62
|
+
* This works by translating the annotation into the view plane normal orientation, with a zero k component, and then
|
|
63
|
+
* performing the smoothing in-plane, and converting back to the original orientation.
|
|
64
|
+
* Closed polylines are smoothed at a random starting spot in order to prevent
|
|
65
|
+
* the start/end points from not being smoothed.
|
|
66
|
+
*
|
|
67
|
+
* Note that each smoothing iteration will reduce the size of the annotation, particularly
|
|
68
|
+
* for closed annotations. This occurs because a smaller/rounder annotation is smoother
|
|
69
|
+
* in some sense than the original.
|
|
52
70
|
*/
|
|
53
71
|
export default function smoothAnnotation(
|
|
54
|
-
enabledElement: Types.IEnabledElement,
|
|
55
72
|
annotation: PlanarFreehandROIAnnotation,
|
|
56
|
-
|
|
73
|
+
options?: SmoothOptions
|
|
57
74
|
): boolean {
|
|
58
75
|
// prevent running while there is any tool annotation being modified
|
|
59
|
-
if (
|
|
60
|
-
shouldPreventInterpolation(enabledElement, annotation, knotsRatioPercentage)
|
|
61
|
-
) {
|
|
76
|
+
if (shouldPreventInterpolation(annotation, options)) {
|
|
62
77
|
return false;
|
|
63
78
|
}
|
|
64
79
|
|
|
65
|
-
const {
|
|
80
|
+
const { viewPlaneNormal } = annotation.metadata;
|
|
81
|
+
const { closed, polyline } = annotation.data.contour;
|
|
82
|
+
|
|
66
83
|
// use only 2 dimensions on interpolation (what visually matters),
|
|
67
84
|
// otherwise a 3d interpolation might have a totally different output as it consider one more dimension.
|
|
68
|
-
const
|
|
69
|
-
|
|
85
|
+
const rotateMat = rotateMatrix(
|
|
86
|
+
viewPlaneNormal,
|
|
87
|
+
annotation.data.contour.polyline[0]
|
|
88
|
+
);
|
|
89
|
+
const canvasPoints = <Types.Point2[]>annotation.data.contour.polyline.map(
|
|
90
|
+
(p) => {
|
|
91
|
+
const planeP = vec3.transformMat4(vec3.create(), p, rotateMat);
|
|
92
|
+
return [planeP[0], planeP[1]];
|
|
93
|
+
}
|
|
70
94
|
);
|
|
71
|
-
|
|
95
|
+
let rotation = closed ? rotate(canvasPoints) : 0;
|
|
96
|
+
let interpolatedCanvasPoints = <Types.Point2[]>(
|
|
72
97
|
interpolateSegmentPoints(
|
|
73
98
|
canvasPoints,
|
|
74
99
|
0,
|
|
75
100
|
canvasPoints.length,
|
|
76
|
-
knotsRatioPercentage
|
|
101
|
+
options?.knotsRatioPercentage || 30
|
|
77
102
|
)
|
|
78
103
|
);
|
|
79
104
|
|
|
80
105
|
if (interpolatedCanvasPoints === canvasPoints) {
|
|
81
106
|
return false;
|
|
82
107
|
}
|
|
108
|
+
// Reverse the rotation so that handles still line up.
|
|
109
|
+
rotate(interpolatedCanvasPoints, -rotation);
|
|
83
110
|
|
|
84
|
-
|
|
85
|
-
|
|
111
|
+
for (let i = 1; i < options?.loop; i++) {
|
|
112
|
+
rotation = closed ? rotate(interpolatedCanvasPoints) : 0;
|
|
113
|
+
interpolatedCanvasPoints = <Types.Point2[]>(
|
|
114
|
+
interpolateSegmentPoints(
|
|
115
|
+
interpolatedCanvasPoints,
|
|
116
|
+
0,
|
|
117
|
+
canvasPoints.length,
|
|
118
|
+
options?.knotsRatioPercentage || 30
|
|
119
|
+
)
|
|
120
|
+
);
|
|
121
|
+
rotate(interpolatedCanvasPoints, -rotation);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
const unRotate = mat4.invert(mat4.create(), rotateMat);
|
|
125
|
+
annotation.data.contour.polyline = <Types.Point3[]>(
|
|
126
|
+
interpolatedCanvasPoints.map((p) =>
|
|
127
|
+
vec3.transformMat4([0, 0, 0], [...p, 0], unRotate)
|
|
128
|
+
)
|
|
86
129
|
);
|
|
87
130
|
|
|
88
131
|
return true;
|