@cornerstonejs/tools 3.16.1 → 3.16.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/esm/tools/SculptorTool/CircleSculptCursor.d.ts +6 -0
- package/dist/esm/tools/SculptorTool/CircleSculptCursor.js +86 -16
- package/dist/esm/tools/SculptorTool.d.ts +2 -0
- package/dist/esm/tools/SculptorTool.js +5 -1
- package/dist/esm/version.d.ts +1 -1
- package/dist/esm/version.js +1 -1
- package/package.json +3 -3
|
@@ -8,6 +8,9 @@ export type PushedHandles = {
|
|
|
8
8
|
};
|
|
9
9
|
declare class CircleSculptCursor implements ISculptToolShape {
|
|
10
10
|
static shapeName: string;
|
|
11
|
+
static readonly CHAIN_MAINTENANCE_ITERATIONS = 3;
|
|
12
|
+
static readonly CHAIN_PULL_STRENGTH_FACTOR = 0.3;
|
|
13
|
+
static readonly MAX_INTER_DISTANCE_FACTOR = 1.2;
|
|
11
14
|
private toolInfo;
|
|
12
15
|
renderShape(svgDrawingHelper: SVGDrawingHelper, canvasLocation: Types.Point2, options: unknown): void;
|
|
13
16
|
pushHandles(viewport: Types.IViewport, sculptData: SculptData): PushedHandles;
|
|
@@ -16,5 +19,8 @@ declare class CircleSculptCursor implements ISculptToolShape {
|
|
|
16
19
|
getMaxSpacing(minSpacing: number): number;
|
|
17
20
|
getInsertPosition(previousIndex: number, nextIndex: number, sculptData: SculptData): Types.Point3;
|
|
18
21
|
private pushOneHandle;
|
|
22
|
+
private directionalVector;
|
|
23
|
+
private calculateMeanConsecutiveDistance;
|
|
24
|
+
private maintainChainStructure;
|
|
19
25
|
}
|
|
20
26
|
export default CircleSculptCursor;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { vec3 } from 'gl-matrix';
|
|
1
2
|
import { getEnabledElement } from '@cornerstonejs/core';
|
|
2
3
|
import { distancePointToContour } from '../distancePointToContour';
|
|
3
4
|
import { drawCircle as drawCircleSvg } from '../../drawingSvg';
|
|
@@ -10,6 +11,9 @@ class CircleSculptCursor {
|
|
|
10
11
|
};
|
|
11
12
|
}
|
|
12
13
|
static { this.shapeName = 'Circle'; }
|
|
14
|
+
static { this.CHAIN_MAINTENANCE_ITERATIONS = 3; }
|
|
15
|
+
static { this.CHAIN_PULL_STRENGTH_FACTOR = 0.3; }
|
|
16
|
+
static { this.MAX_INTER_DISTANCE_FACTOR = 1.2; }
|
|
13
17
|
renderShape(svgDrawingHelper, canvasLocation, options) {
|
|
14
18
|
const circleUID = '0';
|
|
15
19
|
drawCircleSvg(svgDrawingHelper, 'SculptorTool', circleUID, canvasLocation, this.toolInfo.toolSize, options);
|
|
@@ -17,13 +21,17 @@ class CircleSculptCursor {
|
|
|
17
21
|
pushHandles(viewport, sculptData) {
|
|
18
22
|
const { points, mouseCanvasPoint } = sculptData;
|
|
19
23
|
const pushedHandles = { first: undefined, last: undefined };
|
|
24
|
+
const worldRadius = point.distanceToPoint(viewport.canvasToWorld(mouseCanvasPoint), viewport.canvasToWorld([
|
|
25
|
+
mouseCanvasPoint[0] + this.toolInfo.toolSize,
|
|
26
|
+
mouseCanvasPoint[1],
|
|
27
|
+
]));
|
|
20
28
|
for (let i = 0; i < points.length; i++) {
|
|
21
29
|
const handleCanvasPoint = viewport.worldToCanvas(points[i]);
|
|
22
30
|
const distanceToHandle = point.distanceToPoint(handleCanvasPoint, mouseCanvasPoint);
|
|
23
31
|
if (distanceToHandle > this.toolInfo.toolSize) {
|
|
24
32
|
continue;
|
|
25
33
|
}
|
|
26
|
-
this.pushOneHandle(i,
|
|
34
|
+
this.pushOneHandle(i, worldRadius, sculptData);
|
|
27
35
|
if (pushedHandles.first === undefined) {
|
|
28
36
|
pushedHandles.first = i;
|
|
29
37
|
pushedHandles.last = i;
|
|
@@ -32,6 +40,11 @@ class CircleSculptCursor {
|
|
|
32
40
|
pushedHandles.last = i;
|
|
33
41
|
}
|
|
34
42
|
}
|
|
43
|
+
if (pushedHandles.first !== undefined && pushedHandles.last !== undefined) {
|
|
44
|
+
for (let i = 0; i < CircleSculptCursor.CHAIN_MAINTENANCE_ITERATIONS; i++) {
|
|
45
|
+
this.maintainChainStructure(sculptData, pushedHandles);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
35
48
|
return pushedHandles;
|
|
36
49
|
}
|
|
37
50
|
configureToolSize(evt) {
|
|
@@ -85,23 +98,80 @@ class CircleSculptCursor {
|
|
|
85
98
|
const worldPosition = viewport.canvasToWorld(insertPosition);
|
|
86
99
|
return worldPosition;
|
|
87
100
|
}
|
|
88
|
-
pushOneHandle(i,
|
|
101
|
+
pushOneHandle(i, worldRadius, sculptData) {
|
|
89
102
|
const { points, mousePoint } = sculptData;
|
|
90
|
-
const toolSize = this.toolInfo.toolSize;
|
|
91
103
|
const handle = points[i];
|
|
92
|
-
const directionUnitVector =
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
104
|
+
const directionUnitVector = this.directionalVector(mousePoint, handle);
|
|
105
|
+
const position = vec3.scaleAndAdd(vec3.create(), mousePoint, directionUnitVector, worldRadius);
|
|
106
|
+
handle[0] = position[0];
|
|
107
|
+
handle[1] = position[1];
|
|
108
|
+
handle[2] = position[2];
|
|
109
|
+
}
|
|
110
|
+
directionalVector(p1, p2) {
|
|
111
|
+
return vec3.normalize(vec3.create(), [
|
|
112
|
+
p2[0] - p1[0],
|
|
113
|
+
p2[1] - p1[1],
|
|
114
|
+
p2[2] - p1[2],
|
|
115
|
+
]);
|
|
116
|
+
}
|
|
117
|
+
calculateMeanConsecutiveDistance(points) {
|
|
118
|
+
if (points.length < 2) {
|
|
119
|
+
return 0;
|
|
120
|
+
}
|
|
121
|
+
let totalDistance = 0;
|
|
122
|
+
const numPoints = points.length;
|
|
123
|
+
for (let i = 0; i < numPoints; i++) {
|
|
124
|
+
const nextIndex = (i + 1) % numPoints;
|
|
125
|
+
const distance = point.distanceToPoint(points[i], points[nextIndex]);
|
|
126
|
+
totalDistance += distance;
|
|
127
|
+
}
|
|
128
|
+
return totalDistance / numPoints;
|
|
129
|
+
}
|
|
130
|
+
maintainChainStructure(sculptData, pushedHandles) {
|
|
131
|
+
const { points } = sculptData;
|
|
132
|
+
const first = pushedHandles.first;
|
|
133
|
+
const last = pushedHandles.last;
|
|
134
|
+
const mean = Math.round((first + last) / 2);
|
|
135
|
+
const numPoints = points.length;
|
|
136
|
+
if (!sculptData.meanDistance) {
|
|
137
|
+
sculptData.meanDistance = this.calculateMeanConsecutiveDistance(points);
|
|
138
|
+
}
|
|
139
|
+
const maxInterDistance = sculptData.meanDistance * CircleSculptCursor.MAX_INTER_DISTANCE_FACTOR;
|
|
140
|
+
for (let i = mean; i >= 0; i--) {
|
|
141
|
+
if (i >= numPoints - 1 || i < 0) {
|
|
142
|
+
continue;
|
|
143
|
+
}
|
|
144
|
+
const nextIndex = i + 1;
|
|
145
|
+
const distanceToNext = point.distanceToPoint(points[i], points[nextIndex]);
|
|
146
|
+
if (distanceToNext > maxInterDistance) {
|
|
147
|
+
const pullDirection = this.directionalVector(points[i], points[nextIndex]);
|
|
148
|
+
const pullStrength = (distanceToNext - sculptData.meanDistance) / sculptData.meanDistance;
|
|
149
|
+
const adjustmentMagnitude = pullStrength *
|
|
150
|
+
sculptData.meanDistance *
|
|
151
|
+
CircleSculptCursor.CHAIN_PULL_STRENGTH_FACTOR;
|
|
152
|
+
points[i][0] += pullDirection[0] * adjustmentMagnitude;
|
|
153
|
+
points[i][1] += pullDirection[1] * adjustmentMagnitude;
|
|
154
|
+
points[i][2] += pullDirection[2] * adjustmentMagnitude;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
for (let i = mean + 1; i < numPoints; i++) {
|
|
158
|
+
if (i >= numPoints || i <= 0) {
|
|
159
|
+
continue;
|
|
160
|
+
}
|
|
161
|
+
const previousIndex = i - 1;
|
|
162
|
+
const distanceToPrevious = point.distanceToPoint(points[i], points[previousIndex]);
|
|
163
|
+
if (distanceToPrevious > maxInterDistance) {
|
|
164
|
+
const pullDirection = this.directionalVector(points[i], points[previousIndex]);
|
|
165
|
+
const pullStrength = (distanceToPrevious - sculptData.meanDistance) /
|
|
166
|
+
sculptData.meanDistance;
|
|
167
|
+
const adjustmentMagnitude = pullStrength *
|
|
168
|
+
sculptData.meanDistance *
|
|
169
|
+
CircleSculptCursor.CHAIN_PULL_STRENGTH_FACTOR;
|
|
170
|
+
points[i][0] += pullDirection[0] * adjustmentMagnitude;
|
|
171
|
+
points[i][1] += pullDirection[1] * adjustmentMagnitude;
|
|
172
|
+
points[i][2] += pullDirection[2] * adjustmentMagnitude;
|
|
173
|
+
}
|
|
174
|
+
}
|
|
105
175
|
}
|
|
106
176
|
}
|
|
107
177
|
export default CircleSculptCursor;
|
|
@@ -4,9 +4,11 @@ import type { EventTypes, PublicToolProps, ToolProps, SVGDrawingHelper } from '.
|
|
|
4
4
|
import type { ISculptToolShape } from '../types/ISculptToolShape';
|
|
5
5
|
export type SculptData = {
|
|
6
6
|
mousePoint: Types.Point3;
|
|
7
|
+
deltaWorld: Types.Point3;
|
|
7
8
|
mouseCanvasPoint: Types.Point2;
|
|
8
9
|
points: Array<Types.Point3>;
|
|
9
10
|
maxSpacing: number;
|
|
11
|
+
meanDistance?: number;
|
|
10
12
|
element: HTMLDivElement;
|
|
11
13
|
};
|
|
12
14
|
declare class SculptorTool extends BaseTool {
|
|
@@ -21,6 +21,7 @@ class SculptorTool extends BaseTool {
|
|
|
21
21
|
],
|
|
22
22
|
toolShape: 'circle',
|
|
23
23
|
referencedToolName: 'PlanarFreehandROI',
|
|
24
|
+
updateCursorSize: 'dynamic',
|
|
24
25
|
},
|
|
25
26
|
}) {
|
|
26
27
|
super(toolProps, defaultToolProps);
|
|
@@ -100,6 +101,7 @@ class SculptorTool extends BaseTool {
|
|
|
100
101
|
this.sculptData = {
|
|
101
102
|
mousePoint: eventData.currentPoints.world,
|
|
102
103
|
mouseCanvasPoint: eventData.currentPoints.canvas,
|
|
104
|
+
deltaWorld: eventData.deltaPoints.world,
|
|
103
105
|
points,
|
|
104
106
|
maxSpacing: cursorShape.getMaxSpacing(config.minSpacing),
|
|
105
107
|
element: element,
|
|
@@ -139,7 +141,9 @@ class SculptorTool extends BaseTool {
|
|
|
139
141
|
else {
|
|
140
142
|
const cursorShape = this.registeredShapes.get(this.selectedShape);
|
|
141
143
|
const canvasCoords = eventData.currentPoints.canvas;
|
|
142
|
-
|
|
144
|
+
if (this.configuration.updateCursorSize === 'dynamic') {
|
|
145
|
+
cursorShape.updateToolSize(canvasCoords, viewport, activeAnnotation);
|
|
146
|
+
}
|
|
143
147
|
}
|
|
144
148
|
triggerAnnotationRenderForViewportIds(this.commonData.viewportIdsToRender);
|
|
145
149
|
}
|
package/dist/esm/version.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const version = "3.16.
|
|
1
|
+
export declare const version = "3.16.2";
|
package/dist/esm/version.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const version = '3.16.
|
|
1
|
+
export const version = '3.16.2';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cornerstonejs/tools",
|
|
3
|
-
"version": "3.16.
|
|
3
|
+
"version": "3.16.2",
|
|
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.16.
|
|
111
|
+
"@cornerstonejs/core": "^3.16.2",
|
|
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": "
|
|
130
|
+
"gitHead": "575c73857dd19b22980ad035c014072e0156ddd0"
|
|
131
131
|
}
|