@cornerstonejs/tools 3.16.0 → 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.
@@ -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, distanceToHandle, sculptData);
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, distanceToHandle, sculptData) {
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
- x: (handle[0] - mousePoint[0]) / distanceToHandle,
94
- y: (handle[1] - mousePoint[1]) / distanceToHandle,
95
- z: (handle[2] - mousePoint[2]) / distanceToHandle,
96
- };
97
- const position = {
98
- x: mousePoint[0] + toolSize * directionUnitVector.x,
99
- y: mousePoint[1] + toolSize * directionUnitVector.y,
100
- z: mousePoint[2] + toolSize * directionUnitVector.z,
101
- };
102
- handle[0] = position.x;
103
- handle[1] = position.y;
104
- handle[2] = position.z;
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
- cursorShape.updateToolSize(canvasCoords, viewport, activeAnnotation);
144
+ if (this.configuration.updateCursorSize === 'dynamic') {
145
+ cursorShape.updateToolSize(canvasCoords, viewport, activeAnnotation);
146
+ }
143
147
  }
144
148
  triggerAnnotationRenderForViewportIds(this.commonData.viewportIdsToRender);
145
149
  }
@@ -1 +1 @@
1
- export declare const version = "3.16.0";
1
+ export declare const version = "3.16.2";
@@ -1 +1 @@
1
- export const version = '3.16.0';
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.0",
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.0",
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": "16136620b12d12a19fe62f8b8a2ddbc468c4543b"
130
+ "gitHead": "575c73857dd19b22980ad035c014072e0156ddd0"
131
131
  }