@cornerstonejs/tools 4.16.4 → 4.17.1
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/annotation/planarFreehandROITool/drawLoop.js +7 -5
- package/dist/esm/tools/annotation/planarFreehandROITool/findOpenUShapedContourVectorToPeak.d.ts +2 -1
- package/dist/esm/tools/annotation/planarFreehandROITool/findOpenUShapedContourVectorToPeak.js +60 -2
- package/dist/esm/tools/annotation/planarFreehandROITool/openContourEditLoop.js +2 -3
- package/dist/esm/tools/annotation/planarFreehandROITool/renderMethods.js +35 -19
- package/dist/esm/version.d.ts +1 -1
- package/dist/esm/version.js +1 -1
- package/package.json +3 -3
|
@@ -7,7 +7,7 @@ import { shouldSmooth, getInterpolatedPoints, } from '../../../utilities/planarF
|
|
|
7
7
|
import getMouseModifierKey from '../../../eventDispatchers/shared/getMouseModifier';
|
|
8
8
|
import triggerAnnotationRenderForViewportIds from '../../../utilities/triggerAnnotationRenderForViewportIds';
|
|
9
9
|
import { triggerAnnotationModified, triggerContourAnnotationCompleted, } from '../../../stateManagement/annotation/helpers/state';
|
|
10
|
-
import
|
|
10
|
+
import { resolveVectorToPeak } from './findOpenUShapedContourVectorToPeak';
|
|
11
11
|
import { polyline } from '../../../utilities/math';
|
|
12
12
|
import { removeAnnotation } from '../../../stateManagement/annotation/annotationState';
|
|
13
13
|
import { ContourWindingDirection } from '../../../types/ContourAnnotation';
|
|
@@ -193,10 +193,12 @@ function completeDrawOpenContour(element, options) {
|
|
|
193
193
|
worldPoints[0],
|
|
194
194
|
worldPoints[worldPoints.length - 1],
|
|
195
195
|
];
|
|
196
|
-
if (annotation.data.isOpenUShapeContour
|
|
197
|
-
|
|
198
|
-
annotation.data.
|
|
199
|
-
|
|
196
|
+
if (!annotation.data.isOpenUShapeContour &&
|
|
197
|
+
this.configuration?.openUShapeContour) {
|
|
198
|
+
annotation.data.isOpenUShapeContour = this.configuration.openUShapeContour;
|
|
199
|
+
}
|
|
200
|
+
if (annotation.data.isOpenUShapeContour) {
|
|
201
|
+
annotation.data.openUShapeContourVectorToPeak = resolveVectorToPeak(canvasPoints, viewport, annotation.data.isOpenUShapeContour);
|
|
200
202
|
}
|
|
201
203
|
if (!textBox.hasMoved) {
|
|
202
204
|
triggerContourAnnotationCompleted(annotation, contourHoleProcessingEnabled);
|
package/dist/esm/tools/annotation/planarFreehandROITool/findOpenUShapedContourVectorToPeak.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { Types } from '@cornerstonejs/core';
|
|
2
2
|
import type { PlanarFreehandROIAnnotation } from '../../../types/ToolSpecificAnnotationTypes';
|
|
3
3
|
export default function findOpenUShapedContourVectorToPeak(canvasPoints: Types.Point2[], viewport: Types.IStackViewport | Types.IVolumeViewport): Types.Point3[];
|
|
4
|
-
export declare function
|
|
4
|
+
export declare function resolveVectorToPeak(canvasPoints: Types.Point2[], viewport: Types.IStackViewport | Types.IVolumeViewport, variant: PlanarFreehandROIAnnotation['data']['isOpenUShapeContour']): Types.Point3[] | null;
|
|
5
|
+
export declare function resolveVectorToPeakOnRender(enabledElement: Types.IEnabledElement, annotation: PlanarFreehandROIAnnotation): Types.Point3[] | null;
|
package/dist/esm/tools/annotation/planarFreehandROITool/findOpenUShapedContourVectorToPeak.js
CHANGED
|
@@ -32,8 +32,66 @@ export default function findOpenUShapedContourVectorToPeak(canvasPoints, viewpor
|
|
|
32
32
|
const toFurthestWorld = toFurthest.map(viewport.canvasToWorld);
|
|
33
33
|
return toFurthestWorld;
|
|
34
34
|
}
|
|
35
|
-
export function
|
|
35
|
+
export function resolveVectorToPeak(canvasPoints, viewport, variant) {
|
|
36
|
+
if (variant === 'orthogonalT') {
|
|
37
|
+
return findOpenUShapedContourVectorToPeakOrthogonal(canvasPoints, viewport);
|
|
38
|
+
}
|
|
39
|
+
if (variant === 'lineSegment') {
|
|
40
|
+
return null;
|
|
41
|
+
}
|
|
42
|
+
if (variant) {
|
|
43
|
+
return findOpenUShapedContourVectorToPeak(canvasPoints, viewport);
|
|
44
|
+
}
|
|
45
|
+
return null;
|
|
46
|
+
}
|
|
47
|
+
export function resolveVectorToPeakOnRender(enabledElement, annotation) {
|
|
36
48
|
const { viewport } = enabledElement;
|
|
37
49
|
const canvasPoints = annotation.data.contour.polyline.map(viewport.worldToCanvas);
|
|
38
|
-
return
|
|
50
|
+
return resolveVectorToPeak(canvasPoints, viewport, annotation.data.isOpenUShapeContour);
|
|
51
|
+
}
|
|
52
|
+
function findOpenUShapedContourVectorToPeakOrthogonal(canvasPoints, viewport) {
|
|
53
|
+
const first = canvasPoints[0];
|
|
54
|
+
const last = canvasPoints[canvasPoints.length - 1];
|
|
55
|
+
const firstToLastUnitVector = vec2.sub(vec2.create(), last, first);
|
|
56
|
+
vec2.normalize(firstToLastUnitVector, firstToLastUnitVector);
|
|
57
|
+
const chordDir = [
|
|
58
|
+
firstToLastUnitVector[0],
|
|
59
|
+
firstToLastUnitVector[1],
|
|
60
|
+
];
|
|
61
|
+
const centerOfFirstToLast = [
|
|
62
|
+
(first[0] + last[0]) / 2,
|
|
63
|
+
(first[1] + last[1]) / 2,
|
|
64
|
+
];
|
|
65
|
+
const delta = vec2.create();
|
|
66
|
+
let prevDp = null;
|
|
67
|
+
let prevPoint = null;
|
|
68
|
+
let orthogonalPoint = null;
|
|
69
|
+
for (const p of canvasPoints) {
|
|
70
|
+
vec2.sub(delta, p, centerOfFirstToLast);
|
|
71
|
+
const dp = vec2.dot(chordDir, delta);
|
|
72
|
+
if (prevDp !== null && prevDp * dp < 0) {
|
|
73
|
+
const t = Math.abs(prevDp) / (Math.abs(prevDp) + Math.abs(dp));
|
|
74
|
+
orthogonalPoint = [
|
|
75
|
+
prevPoint[0] + t * (p[0] - prevPoint[0]),
|
|
76
|
+
prevPoint[1] + t * (p[1] - prevPoint[1]),
|
|
77
|
+
];
|
|
78
|
+
break;
|
|
79
|
+
}
|
|
80
|
+
if (Math.abs(dp) < 1e-10) {
|
|
81
|
+
orthogonalPoint = p;
|
|
82
|
+
break;
|
|
83
|
+
}
|
|
84
|
+
prevDp = dp;
|
|
85
|
+
prevPoint = p;
|
|
86
|
+
}
|
|
87
|
+
if (!orthogonalPoint) {
|
|
88
|
+
console.warn('No orthogonal intersection found for open U-shaped contour');
|
|
89
|
+
return null;
|
|
90
|
+
}
|
|
91
|
+
const toOrthogonal = [
|
|
92
|
+
orthogonalPoint,
|
|
93
|
+
centerOfFirstToLast,
|
|
94
|
+
];
|
|
95
|
+
const toOrthogonalWorld = toOrthogonal.map(viewport.canvasToWorld);
|
|
96
|
+
return toOrthogonalWorld;
|
|
39
97
|
}
|
|
@@ -7,7 +7,7 @@ import { polyline } from '../../../utilities/math';
|
|
|
7
7
|
import { shouldSmooth, getInterpolatedPoints, } from '../../../utilities/planarFreehandROITool/smoothPoints';
|
|
8
8
|
import triggerAnnotationRenderForViewportIds from '../../../utilities/triggerAnnotationRenderForViewportIds';
|
|
9
9
|
import updateContourPolyline from '../../../utilities/contours/updateContourPolyline';
|
|
10
|
-
import
|
|
10
|
+
import { resolveVectorToPeak } from './findOpenUShapedContourVectorToPeak';
|
|
11
11
|
import { triggerAnnotationModified } from '../../../stateManagement/annotation/helpers/state';
|
|
12
12
|
const { addCanvasPointsToArray, getSubPixelSpacingAndXYDirections } = polyline;
|
|
13
13
|
function activateOpenContourEdit(evt, annotation, viewportIdsToRender) {
|
|
@@ -289,8 +289,7 @@ function completeOpenContourEdit(element) {
|
|
|
289
289
|
worldPoints[worldPoints.length - 1],
|
|
290
290
|
];
|
|
291
291
|
if (annotation.data.isOpenUShapeContour) {
|
|
292
|
-
annotation.data.openUShapeContourVectorToPeak =
|
|
293
|
-
findOpenUShapedContourVectorToPeak(fusedCanvasPoints, viewport);
|
|
292
|
+
annotation.data.openUShapeContourVectorToPeak = resolveVectorToPeak(fusedCanvasPoints, viewport, annotation.data.isOpenUShapeContour);
|
|
294
293
|
}
|
|
295
294
|
triggerAnnotationModified(annotation, element);
|
|
296
295
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { drawHandles as drawHandlesSvg, drawPolyline as drawPolylineSvg, drawPath as drawPathSvg, } from '../../../drawingSvg';
|
|
2
2
|
import { polyline } from '../../../utilities/math';
|
|
3
|
-
import {
|
|
3
|
+
import { resolveVectorToPeakOnRender } from './findOpenUShapedContourVectorToPeak';
|
|
4
4
|
import getContourHolesDataCanvas from '../../../utilities/contours/getContourHolesDataCanvas';
|
|
5
5
|
const { pointsAreWithinCloseContourProximity } = polyline;
|
|
6
6
|
function _getRenderingOptions(enabledElement, annotation) {
|
|
@@ -20,7 +20,9 @@ function _getRenderingOptions(enabledElement, annotation) {
|
|
|
20
20
|
width: lineWidth,
|
|
21
21
|
lineDash,
|
|
22
22
|
fillColor,
|
|
23
|
-
fillOpacity
|
|
23
|
+
fillOpacity: this.configuration?.fillOpacity !== undefined
|
|
24
|
+
? this.configuration.fillOpacity
|
|
25
|
+
: fillOpacity,
|
|
24
26
|
closePath: isClosedContour,
|
|
25
27
|
};
|
|
26
28
|
return options;
|
|
@@ -34,7 +36,9 @@ function renderContour(enabledElement, svgDrawingHelper, annotation) {
|
|
|
34
36
|
}
|
|
35
37
|
else {
|
|
36
38
|
if (annotation.data.isOpenUShapeContour) {
|
|
37
|
-
|
|
39
|
+
if (annotation.data.isOpenUShapeContour !== 'lineSegment') {
|
|
40
|
+
calculateUShapeContourVectorToPeakIfNotPresent(enabledElement, annotation);
|
|
41
|
+
}
|
|
38
42
|
this.renderOpenUShapedContour(enabledElement, svgDrawingHelper, annotation);
|
|
39
43
|
}
|
|
40
44
|
else {
|
|
@@ -44,8 +48,7 @@ function renderContour(enabledElement, svgDrawingHelper, annotation) {
|
|
|
44
48
|
}
|
|
45
49
|
function calculateUShapeContourVectorToPeakIfNotPresent(enabledElement, annotation) {
|
|
46
50
|
if (!annotation.data.openUShapeContourVectorToPeak) {
|
|
47
|
-
annotation.data.openUShapeContourVectorToPeak =
|
|
48
|
-
findOpenUShapedContourVectorToPeakOnRender(enabledElement, annotation);
|
|
51
|
+
annotation.data.openUShapeContourVectorToPeak = resolveVectorToPeakOnRender(enabledElement, annotation);
|
|
49
52
|
}
|
|
50
53
|
}
|
|
51
54
|
function renderClosedContour(enabledElement, svgDrawingHelper, annotation) {
|
|
@@ -97,15 +100,12 @@ function renderOpenUShapedContour(enabledElement, svgDrawingHelper, annotation)
|
|
|
97
100
|
const { openUShapeContourVectorToPeak } = annotation.data;
|
|
98
101
|
const { polyline } = annotation.data.contour;
|
|
99
102
|
this.renderOpenContour(enabledElement, svgDrawingHelper, annotation);
|
|
100
|
-
|
|
103
|
+
const isLineSegmentOnly = annotation.data.isOpenUShapeContour === 'lineSegment';
|
|
104
|
+
if (!isLineSegmentOnly && !openUShapeContourVectorToPeak) {
|
|
101
105
|
return;
|
|
102
106
|
}
|
|
103
107
|
const firstCanvasPoint = viewport.worldToCanvas(polyline[0]);
|
|
104
108
|
const lastCanvasPoint = viewport.worldToCanvas(polyline[polyline.length - 1]);
|
|
105
|
-
const openUShapeContourVectorToPeakCanvas = [
|
|
106
|
-
viewport.worldToCanvas(openUShapeContourVectorToPeak[0]),
|
|
107
|
-
viewport.worldToCanvas(openUShapeContourVectorToPeak[1]),
|
|
108
|
-
];
|
|
109
109
|
const options = this._getRenderingOptions(enabledElement, annotation);
|
|
110
110
|
drawPolylineSvg(svgDrawingHelper, annotation.annotationUID, 'first-to-last', [firstCanvasPoint, lastCanvasPoint], {
|
|
111
111
|
color: options.color,
|
|
@@ -113,15 +113,31 @@ function renderOpenUShapedContour(enabledElement, svgDrawingHelper, annotation)
|
|
|
113
113
|
closePath: false,
|
|
114
114
|
lineDash: '2,2',
|
|
115
115
|
});
|
|
116
|
-
|
|
117
|
-
openUShapeContourVectorToPeakCanvas[
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
116
|
+
if (!isLineSegmentOnly) {
|
|
117
|
+
const openUShapeContourVectorToPeakCanvas = [
|
|
118
|
+
viewport.worldToCanvas(openUShapeContourVectorToPeak[0]),
|
|
119
|
+
viewport.worldToCanvas(openUShapeContourVectorToPeak[1]),
|
|
120
|
+
];
|
|
121
|
+
drawPolylineSvg(svgDrawingHelper, annotation.annotationUID, 'midpoint-to-open-contour', [
|
|
122
|
+
openUShapeContourVectorToPeakCanvas[0],
|
|
123
|
+
openUShapeContourVectorToPeakCanvas[1],
|
|
124
|
+
], {
|
|
125
|
+
color: options.color,
|
|
126
|
+
width: options.width,
|
|
127
|
+
closePath: false,
|
|
128
|
+
lineDash: '2,2',
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
if (options.fillOpacity > 0) {
|
|
132
|
+
const canvasPolyline = polyline.map((worldPos) => viewport.worldToCanvas(worldPos));
|
|
133
|
+
drawPathSvg(svgDrawingHelper, annotation.annotationUID, 'u-shape-fill', [[...canvasPolyline, firstCanvasPoint]], {
|
|
134
|
+
color: options.fillColor || options.color,
|
|
135
|
+
fillColor: options.fillColor || options.color,
|
|
136
|
+
fillOpacity: options.fillOpacity,
|
|
137
|
+
closePath: true,
|
|
138
|
+
width: 0,
|
|
139
|
+
});
|
|
140
|
+
}
|
|
125
141
|
}
|
|
126
142
|
function renderContourBeingDrawn(enabledElement, svgDrawingHelper, annotation) {
|
|
127
143
|
const options = this._getRenderingOptions(enabledElement, annotation);
|
package/dist/esm/version.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const version = "4.
|
|
1
|
+
export declare const version = "4.17.1";
|
package/dist/esm/version.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const version = '4.
|
|
1
|
+
export const version = '4.17.1';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cornerstonejs/tools",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.17.1",
|
|
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.2.0"
|
|
109
109
|
},
|
|
110
110
|
"peerDependencies": {
|
|
111
|
-
"@cornerstonejs/core": "4.
|
|
111
|
+
"@cornerstonejs/core": "4.17.1",
|
|
112
112
|
"@kitware/vtk.js": "34.15.1",
|
|
113
113
|
"@types/d3-array": "3.2.1",
|
|
114
114
|
"@types/d3-interpolate": "3.0.4",
|
|
@@ -127,5 +127,5 @@
|
|
|
127
127
|
"type": "individual",
|
|
128
128
|
"url": "https://ohif.org/donate"
|
|
129
129
|
},
|
|
130
|
-
"gitHead": "
|
|
130
|
+
"gitHead": "d49400cbb32c44559d51d56e018cde563aca361a"
|
|
131
131
|
}
|