@cornerstonejs/tools 1.40.3 → 1.42.0
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/drawingSvg/drawHandle.d.ts +4 -0
- package/dist/cjs/drawingSvg/drawHandle.js +66 -0
- package/dist/cjs/drawingSvg/drawHandle.js.map +1 -0
- package/dist/cjs/drawingSvg/drawHandles.js +4 -60
- package/dist/cjs/drawingSvg/drawHandles.js.map +1 -1
- package/dist/cjs/drawingSvg/index.d.ts +2 -1
- package/dist/cjs/drawingSvg/index.js +3 -1
- package/dist/cjs/drawingSvg/index.js.map +1 -1
- package/dist/cjs/eventDispatchers/keyboardEventHandlers/keyDown.js +2 -1
- package/dist/cjs/eventDispatchers/keyboardEventHandlers/keyDown.js.map +1 -1
- package/dist/cjs/index.d.ts +2 -2
- package/dist/cjs/index.js +3 -2
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/stateManagement/annotation/annotationState.js +3 -0
- package/dist/cjs/stateManagement/annotation/annotationState.js.map +1 -1
- package/dist/cjs/tools/annotation/AngleTool.js.map +1 -1
- package/dist/cjs/tools/annotation/BidirectionalTool.js +7 -6
- package/dist/cjs/tools/annotation/BidirectionalTool.js.map +1 -1
- package/dist/cjs/tools/annotation/LengthTool.js +4 -3
- package/dist/cjs/tools/annotation/LengthTool.js.map +1 -1
- package/dist/cjs/tools/annotation/ProbeTool.js +24 -3
- package/dist/cjs/tools/annotation/ProbeTool.js.map +1 -1
- package/dist/cjs/tools/annotation/UltrasoundDirectionalTool.d.ts +36 -0
- package/dist/cjs/tools/annotation/UltrasoundDirectionalTool.js +483 -0
- package/dist/cjs/tools/annotation/UltrasoundDirectionalTool.js.map +1 -0
- package/dist/cjs/tools/index.d.ts +2 -1
- package/dist/cjs/tools/index.js +3 -1
- package/dist/cjs/tools/index.js.map +1 -1
- package/dist/cjs/types/ToolSpecificAnnotationTypes.d.ts +28 -0
- package/dist/cjs/types/index.d.ts +2 -1
- package/dist/cjs/utilities/contours/AnnotationToPointData.d.ts +11 -0
- package/dist/cjs/utilities/contours/AnnotationToPointData.js +44 -0
- package/dist/cjs/utilities/contours/AnnotationToPointData.js.map +1 -0
- package/dist/cjs/utilities/contours/RectangleROIStartEndThreshold.d.ts +6 -0
- package/dist/cjs/utilities/contours/RectangleROIStartEndThreshold.js +43 -0
- package/dist/cjs/utilities/contours/RectangleROIStartEndThreshold.js.map +1 -0
- package/dist/cjs/utilities/contours/contourFinder.d.ts +7 -0
- package/dist/cjs/utilities/contours/contourFinder.js +68 -0
- package/dist/cjs/utilities/contours/contourFinder.js.map +1 -0
- package/dist/cjs/utilities/contours/detectContourHoles.d.ts +5 -0
- package/dist/cjs/utilities/contours/detectContourHoles.js +78 -0
- package/dist/cjs/utilities/contours/detectContourHoles.js.map +1 -0
- package/dist/cjs/utilities/contours/generateContourSetsFromLabelmap.d.ts +4 -0
- package/dist/cjs/utilities/contours/generateContourSetsFromLabelmap.js +124 -0
- package/dist/cjs/utilities/contours/generateContourSetsFromLabelmap.js.map +1 -0
- package/dist/cjs/utilities/contours/index.d.ts +6 -0
- package/dist/cjs/utilities/contours/index.js +17 -0
- package/dist/cjs/utilities/contours/index.js.map +1 -0
- package/dist/cjs/utilities/contours/mergePoints.d.ts +8 -0
- package/dist/cjs/utilities/contours/mergePoints.js +77 -0
- package/dist/cjs/utilities/contours/mergePoints.js.map +1 -0
- package/dist/cjs/utilities/getCalibratedUnits.d.ts +16 -2
- package/dist/cjs/utilities/getCalibratedUnits.js +127 -5
- package/dist/cjs/utilities/getCalibratedUnits.js.map +1 -1
- package/dist/cjs/utilities/index.d.ts +2 -1
- package/dist/cjs/utilities/index.js +3 -1
- package/dist/cjs/utilities/index.js.map +1 -1
- package/dist/cjs/utilities/segmentation/contourAndFindLargestBidirectional.d.ts +1 -0
- package/dist/cjs/utilities/segmentation/contourAndFindLargestBidirectional.js +31 -0
- package/dist/cjs/utilities/segmentation/contourAndFindLargestBidirectional.js.map +1 -0
- package/dist/cjs/utilities/segmentation/createBidirectionalToolData.d.ts +14 -0
- package/dist/cjs/utilities/segmentation/createBidirectionalToolData.js +43 -0
- package/dist/cjs/utilities/segmentation/createBidirectionalToolData.js.map +1 -0
- package/dist/cjs/utilities/segmentation/findLargestBidirectional.d.ts +1 -0
- package/dist/cjs/utilities/segmentation/findLargestBidirectional.js +94 -0
- package/dist/cjs/utilities/segmentation/findLargestBidirectional.js.map +1 -0
- package/dist/cjs/utilities/segmentation/index.d.ts +4 -1
- package/dist/cjs/utilities/segmentation/index.js +7 -1
- package/dist/cjs/utilities/segmentation/index.js.map +1 -1
- package/dist/cjs/utilities/segmentation/isLineInSegment.d.ts +9 -0
- package/dist/cjs/utilities/segmentation/isLineInSegment.js +55 -0
- package/dist/cjs/utilities/segmentation/isLineInSegment.js.map +1 -0
- package/dist/cjs/utilities/segmentation/segmentContourAction.d.ts +17 -0
- package/dist/cjs/utilities/segmentation/segmentContourAction.js +122 -0
- package/dist/cjs/utilities/segmentation/segmentContourAction.js.map +1 -0
- package/dist/esm/drawingSvg/drawHandle.js +61 -0
- package/dist/esm/drawingSvg/drawHandle.js.map +1 -0
- package/dist/esm/drawingSvg/drawHandles.js +4 -60
- package/dist/esm/drawingSvg/drawHandles.js.map +1 -1
- package/dist/esm/drawingSvg/index.js +2 -1
- package/dist/esm/drawingSvg/index.js.map +1 -1
- package/dist/esm/eventDispatchers/keyboardEventHandlers/keyDown.js +2 -1
- package/dist/esm/eventDispatchers/keyboardEventHandlers/keyDown.js.map +1 -1
- package/dist/esm/index.js +2 -2
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/stateManagement/annotation/annotationState.js +3 -0
- package/dist/esm/stateManagement/annotation/annotationState.js.map +1 -1
- package/dist/esm/tools/annotation/AngleTool.js.map +1 -1
- package/dist/esm/tools/annotation/BidirectionalTool.js +7 -6
- package/dist/esm/tools/annotation/BidirectionalTool.js.map +1 -1
- package/dist/esm/tools/annotation/LengthTool.js +5 -4
- package/dist/esm/tools/annotation/LengthTool.js.map +1 -1
- package/dist/esm/tools/annotation/ProbeTool.js +24 -3
- package/dist/esm/tools/annotation/ProbeTool.js.map +1 -1
- package/dist/esm/tools/annotation/UltrasoundDirectionalTool.js +478 -0
- package/dist/esm/tools/annotation/UltrasoundDirectionalTool.js.map +1 -0
- package/dist/esm/tools/index.js +2 -1
- package/dist/esm/tools/index.js.map +1 -1
- package/dist/esm/utilities/contours/AnnotationToPointData.js +39 -0
- package/dist/esm/utilities/contours/AnnotationToPointData.js.map +1 -0
- package/dist/esm/utilities/contours/RectangleROIStartEndThreshold.js +41 -0
- package/dist/esm/utilities/contours/RectangleROIStartEndThreshold.js.map +1 -0
- package/dist/esm/utilities/contours/contourFinder.js +63 -0
- package/dist/esm/utilities/contours/contourFinder.js.map +1 -0
- package/dist/esm/utilities/contours/detectContourHoles.js +74 -0
- package/dist/esm/utilities/contours/detectContourHoles.js.map +1 -0
- package/dist/esm/utilities/contours/generateContourSetsFromLabelmap.js +117 -0
- package/dist/esm/utilities/contours/generateContourSetsFromLabelmap.js.map +1 -0
- package/dist/esm/utilities/contours/index.js +7 -0
- package/dist/esm/utilities/contours/index.js.map +1 -0
- package/dist/esm/utilities/contours/mergePoints.js +73 -0
- package/dist/esm/utilities/contours/mergePoints.js.map +1 -0
- package/dist/esm/utilities/getCalibratedUnits.js +125 -6
- package/dist/esm/utilities/getCalibratedUnits.js.map +1 -1
- package/dist/esm/utilities/index.js +2 -1
- package/dist/esm/utilities/index.js.map +1 -1
- package/dist/esm/utilities/segmentation/contourAndFindLargestBidirectional.js +25 -0
- package/dist/esm/utilities/segmentation/contourAndFindLargestBidirectional.js.map +1 -0
- package/dist/esm/utilities/segmentation/createBidirectionalToolData.js +40 -0
- package/dist/esm/utilities/segmentation/createBidirectionalToolData.js.map +1 -0
- package/dist/esm/utilities/segmentation/findLargestBidirectional.js +96 -0
- package/dist/esm/utilities/segmentation/findLargestBidirectional.js.map +1 -0
- package/dist/esm/utilities/segmentation/index.js +4 -1
- package/dist/esm/utilities/segmentation/index.js.map +1 -1
- package/dist/esm/utilities/segmentation/isLineInSegment.js +50 -0
- package/dist/esm/utilities/segmentation/isLineInSegment.js.map +1 -0
- package/dist/esm/utilities/segmentation/segmentContourAction.js +98 -0
- package/dist/esm/utilities/segmentation/segmentContourAction.js.map +1 -0
- package/dist/types/drawingSvg/drawHandle.d.ts +5 -0
- package/dist/types/drawingSvg/drawHandle.d.ts.map +1 -0
- package/dist/types/drawingSvg/drawHandles.d.ts.map +1 -1
- package/dist/types/drawingSvg/index.d.ts +2 -1
- package/dist/types/drawingSvg/index.d.ts.map +1 -1
- package/dist/types/eventDispatchers/keyboardEventHandlers/keyDown.d.ts.map +1 -1
- package/dist/types/index.d.ts +2 -2
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/stateManagement/annotation/annotationState.d.ts.map +1 -1
- package/dist/types/tools/annotation/AngleTool.d.ts.map +1 -1
- package/dist/types/tools/annotation/BidirectionalTool.d.ts.map +1 -1
- package/dist/types/tools/annotation/LengthTool.d.ts.map +1 -1
- package/dist/types/tools/annotation/ProbeTool.d.ts.map +1 -1
- package/dist/types/tools/annotation/UltrasoundDirectionalTool.d.ts +37 -0
- package/dist/types/tools/annotation/UltrasoundDirectionalTool.d.ts.map +1 -0
- package/dist/types/tools/index.d.ts +2 -1
- package/dist/types/tools/index.d.ts.map +1 -1
- package/dist/types/types/ToolSpecificAnnotationTypes.d.ts +28 -0
- package/dist/types/types/ToolSpecificAnnotationTypes.d.ts.map +1 -1
- package/dist/types/types/index.d.ts +2 -1
- package/dist/types/types/index.d.ts.map +1 -1
- package/dist/types/utilities/contours/AnnotationToPointData.d.ts +12 -0
- package/dist/types/utilities/contours/AnnotationToPointData.d.ts.map +1 -0
- package/dist/types/utilities/contours/RectangleROIStartEndThreshold.d.ts +7 -0
- package/dist/types/utilities/contours/RectangleROIStartEndThreshold.d.ts.map +1 -0
- package/dist/types/utilities/contours/contourFinder.d.ts +8 -0
- package/dist/types/utilities/contours/contourFinder.d.ts.map +1 -0
- package/dist/types/utilities/contours/detectContourHoles.d.ts +6 -0
- package/dist/types/utilities/contours/detectContourHoles.d.ts.map +1 -0
- package/dist/types/utilities/contours/generateContourSetsFromLabelmap.d.ts +5 -0
- package/dist/types/utilities/contours/generateContourSetsFromLabelmap.d.ts.map +1 -0
- package/dist/types/utilities/contours/index.d.ts +7 -0
- package/dist/types/utilities/contours/index.d.ts.map +1 -0
- package/dist/types/utilities/contours/mergePoints.d.ts +9 -0
- package/dist/types/utilities/contours/mergePoints.d.ts.map +1 -0
- package/dist/types/utilities/getCalibratedUnits.d.ts +16 -2
- package/dist/types/utilities/getCalibratedUnits.d.ts.map +1 -1
- package/dist/types/utilities/index.d.ts +2 -1
- package/dist/types/utilities/index.d.ts.map +1 -1
- package/dist/types/utilities/segmentation/contourAndFindLargestBidirectional.d.ts +2 -0
- package/dist/types/utilities/segmentation/contourAndFindLargestBidirectional.d.ts.map +1 -0
- package/dist/types/utilities/segmentation/createBidirectionalToolData.d.ts +15 -0
- package/dist/types/utilities/segmentation/createBidirectionalToolData.d.ts.map +1 -0
- package/dist/types/utilities/segmentation/findLargestBidirectional.d.ts +2 -0
- package/dist/types/utilities/segmentation/findLargestBidirectional.d.ts.map +1 -0
- package/dist/types/utilities/segmentation/index.d.ts +4 -1
- package/dist/types/utilities/segmentation/index.d.ts.map +1 -1
- package/dist/types/utilities/segmentation/isLineInSegment.d.ts +10 -0
- package/dist/types/utilities/segmentation/isLineInSegment.d.ts.map +1 -0
- package/dist/types/utilities/segmentation/segmentContourAction.d.ts +18 -0
- package/dist/types/utilities/segmentation/segmentContourAction.d.ts.map +1 -0
- package/dist/umd/index.js +1 -1
- package/dist/umd/index.js.map +1 -1
- package/package.json +3 -3
- package/src/drawingSvg/drawHandle.ts +88 -0
- package/src/drawingSvg/drawHandles.ts +9 -75
- package/src/drawingSvg/index.ts +2 -0
- package/src/eventDispatchers/keyboardEventHandlers/keyDown.ts +7 -1
- package/src/index.ts +2 -0
- package/src/stateManagement/annotation/annotationState.ts +3 -0
- package/src/tools/annotation/AngleTool.ts +0 -1
- package/src/tools/annotation/BidirectionalTool.ts +9 -5
- package/src/tools/annotation/LengthTool.ts +6 -8
- package/src/tools/annotation/ProbeTool.ts +31 -7
- package/src/tools/annotation/UltrasoundDirectionalTool.ts +916 -0
- package/src/tools/index.ts +2 -0
- package/src/types/ToolSpecificAnnotationTypes.ts +29 -0
- package/src/types/index.ts +2 -0
- package/src/utilities/contours/AnnotationToPointData.ts +61 -0
- package/src/utilities/contours/RectangleROIStartEndThreshold.ts +60 -0
- package/src/utilities/contours/contourFinder.ts +78 -0
- package/src/utilities/contours/detectContourHoles.ts +147 -0
- package/src/utilities/contours/generateContourSetsFromLabelmap.ts +160 -0
- package/src/utilities/contours/index.ts +14 -0
- package/src/utilities/contours/mergePoints.ts +108 -0
- package/src/utilities/getCalibratedUnits.ts +203 -7
- package/src/utilities/index.ts +2 -0
- package/src/utilities/segmentation/contourAndFindLargestBidirectional.ts +46 -0
- package/src/utilities/segmentation/createBidirectionalToolData.ts +68 -0
- package/src/utilities/segmentation/findLargestBidirectional.ts +159 -0
- package/src/utilities/segmentation/index.ts +6 -0
- package/src/utilities/segmentation/isLineInSegment.ts +84 -0
- package/src/utilities/segmentation/segmentContourAction.ts +169 -0
|
@@ -1,12 +1,31 @@
|
|
|
1
|
-
import { Enums } from '@cornerstonejs/core';
|
|
1
|
+
import { Enums, utilities } from '@cornerstonejs/core';
|
|
2
2
|
|
|
3
3
|
const { CalibrationTypes } = Enums;
|
|
4
4
|
const PIXEL_UNITS = 'px';
|
|
5
5
|
|
|
6
|
+
const SUPPORTED_REGION_DATA_TYPES = [
|
|
7
|
+
1, // Tissue
|
|
8
|
+
];
|
|
9
|
+
|
|
10
|
+
const SUPPORTED_LENGTH_VARIANT = [
|
|
11
|
+
'3,3', // x: cm & y:cm
|
|
12
|
+
];
|
|
13
|
+
|
|
14
|
+
const SUPPORTED_PROBE_VARIANT = [
|
|
15
|
+
'4,3', // x: seconds & y : cm
|
|
16
|
+
];
|
|
17
|
+
|
|
18
|
+
const UNIT_MAPPING = {
|
|
19
|
+
3: 'cm',
|
|
20
|
+
4: 'seconds',
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
const EPS = 1e-3;
|
|
24
|
+
|
|
6
25
|
/**
|
|
7
26
|
* Extracts the length units and the type of calibration for those units
|
|
8
27
|
* into the response. The length units will typically be either mm or px
|
|
9
|
-
* while the calibration type can be any of a number of different
|
|
28
|
+
* while the calibration type can be any of a number of different calibration types.
|
|
10
29
|
*
|
|
11
30
|
* Volumetric images have no calibration type, so are just the raw mm.
|
|
12
31
|
*
|
|
@@ -23,14 +42,16 @@ const getCalibratedLengthUnits = (handles, image): string => {
|
|
|
23
42
|
const { calibration, hasPixelSpacing } = image;
|
|
24
43
|
// Anachronistic - moving to using calibration consistently, but not completed yet
|
|
25
44
|
const units = hasPixelSpacing ? 'mm' : PIXEL_UNITS;
|
|
26
|
-
if (
|
|
45
|
+
if (
|
|
46
|
+
!calibration ||
|
|
47
|
+
(!calibration.type && !calibration.sequenceOfUltrasoundRegions)
|
|
48
|
+
) {
|
|
27
49
|
return units;
|
|
28
50
|
}
|
|
29
51
|
if (calibration.type === CalibrationTypes.UNCALIBRATED) {
|
|
30
52
|
return PIXEL_UNITS;
|
|
31
53
|
}
|
|
32
|
-
|
|
33
|
-
if (calibration.SequenceOfUltrasoundRegions) {
|
|
54
|
+
if (calibration.sequenceOfUltrasoundRegions) {
|
|
34
55
|
return 'US Region';
|
|
35
56
|
}
|
|
36
57
|
return `${units} ${calibration.type}`;
|
|
@@ -46,7 +67,7 @@ const getCalibratedAreaUnits = (handles, image): string => {
|
|
|
46
67
|
if (!calibration || !calibration.type) {
|
|
47
68
|
return units;
|
|
48
69
|
}
|
|
49
|
-
if (calibration.
|
|
70
|
+
if (calibration.sequenceOfUltrasoundRegions) {
|
|
50
71
|
return 'US Region';
|
|
51
72
|
}
|
|
52
73
|
return `${units} ${calibration.type}`;
|
|
@@ -56,7 +77,180 @@ const getCalibratedAreaUnits = (handles, image): string => {
|
|
|
56
77
|
* Gets the scale divisor for converting from internal spacing to
|
|
57
78
|
* image spacing for calibrated images.
|
|
58
79
|
*/
|
|
59
|
-
const getCalibratedScale = (image) =>
|
|
80
|
+
const getCalibratedScale = (image, handles = []) => {
|
|
81
|
+
if (image.calibration?.sequenceOfUltrasoundRegions) {
|
|
82
|
+
// image.spacing / image.us.space
|
|
83
|
+
} else if (image.calibration?.scale) {
|
|
84
|
+
return image.calibration.scale;
|
|
85
|
+
} else {
|
|
86
|
+
return 1;
|
|
87
|
+
}
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Extracts the calibrated length units, area units, and the scale
|
|
92
|
+
* for converting from internal spacing to image spacing.
|
|
93
|
+
*
|
|
94
|
+
* @param handles - to detect if spacing information is different between points
|
|
95
|
+
* @param image - to extract the calibration from
|
|
96
|
+
* @returns Object containing the units, area units, and scale
|
|
97
|
+
*/
|
|
98
|
+
const getCalibratedLengthUnitsAndScale = (image, handles) => {
|
|
99
|
+
const [imageIndex1, imageIndex2] = handles;
|
|
100
|
+
const { calibration, hasPixelSpacing } = image;
|
|
101
|
+
let units = hasPixelSpacing ? 'mm' : PIXEL_UNITS;
|
|
102
|
+
const areaUnits = units + SQUARE;
|
|
103
|
+
let scale = 1;
|
|
104
|
+
let calibrationType = '';
|
|
105
|
+
|
|
106
|
+
if (
|
|
107
|
+
!calibration ||
|
|
108
|
+
(!calibration.type && !calibration.sequenceOfUltrasoundRegions)
|
|
109
|
+
) {
|
|
110
|
+
return { units, areaUnits, scale };
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
if (calibration.type === CalibrationTypes.UNCALIBRATED) {
|
|
114
|
+
return { units: PIXEL_UNITS, areaUnits: PIXEL_UNITS + SQUARE, scale };
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
if (calibration.sequenceOfUltrasoundRegions) {
|
|
118
|
+
let regions = calibration.sequenceOfUltrasoundRegions.filter(
|
|
119
|
+
(region) =>
|
|
120
|
+
imageIndex1[0] >= region.regionLocationMinX0 &&
|
|
121
|
+
imageIndex1[0] <= region.regionLocationMaxX1 &&
|
|
122
|
+
imageIndex1[1] >= region.regionLocationMinY0 &&
|
|
123
|
+
imageIndex1[1] <= region.regionLocationMaxY1 &&
|
|
124
|
+
imageIndex2[0] >= region.regionLocationMinX0 &&
|
|
125
|
+
imageIndex2[0] <= region.regionLocationMaxX1 &&
|
|
126
|
+
imageIndex2[1] >= region.regionLocationMinY0 &&
|
|
127
|
+
imageIndex2[1] <= region.regionLocationMaxY1
|
|
128
|
+
);
|
|
129
|
+
|
|
130
|
+
// If we are not in a region at all we should show the underlying calibration
|
|
131
|
+
// which might be the mm spacing for the image
|
|
132
|
+
if (!regions?.length) {
|
|
133
|
+
return { units, areaUnits, scale };
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// if we are in a region then it is the question of whether we support it
|
|
137
|
+
// or not. If we do not support it we should show px
|
|
138
|
+
|
|
139
|
+
regions = regions.filter(
|
|
140
|
+
(region) =>
|
|
141
|
+
SUPPORTED_REGION_DATA_TYPES.includes(region.regionDataType) &&
|
|
142
|
+
SUPPORTED_LENGTH_VARIANT.includes(
|
|
143
|
+
`${region.physicalUnitXDirection},${region.physicalUnitYDirection}`
|
|
144
|
+
)
|
|
145
|
+
);
|
|
146
|
+
|
|
147
|
+
if (!regions.length) {
|
|
148
|
+
return { units: PIXEL_UNITS, areaUnits: PIXEL_UNITS + SQUARE, scale };
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
// Todo: expand on this logic
|
|
152
|
+
const region = regions[0];
|
|
153
|
+
|
|
154
|
+
const physicalDeltaX = Math.abs(region.physicalDeltaX);
|
|
155
|
+
const physicalDeltaY = Math.abs(region.physicalDeltaY);
|
|
156
|
+
|
|
157
|
+
// if we are in a supported region then we should check if the
|
|
158
|
+
// physicalDeltaX and physicalDeltaY are the same. If they are not
|
|
159
|
+
// then we should show px again, but if they are the same then we should
|
|
160
|
+
// show the units
|
|
161
|
+
const isSamePhysicalDelta = utilities.isEqual(
|
|
162
|
+
physicalDeltaX,
|
|
163
|
+
physicalDeltaY,
|
|
164
|
+
EPS
|
|
165
|
+
);
|
|
166
|
+
|
|
167
|
+
if (isSamePhysicalDelta) {
|
|
168
|
+
scale = 1 / (physicalDeltaX * physicalDeltaY * 100);
|
|
169
|
+
calibrationType = 'US Region';
|
|
170
|
+
units = 'mm';
|
|
171
|
+
} else {
|
|
172
|
+
return { units: PIXEL_UNITS, areaUnits: PIXEL_UNITS + SQUARE, scale };
|
|
173
|
+
}
|
|
174
|
+
} else if (calibration.scale) {
|
|
175
|
+
scale = calibration.scale;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
return {
|
|
179
|
+
units: units + (calibrationType ? ` ${calibrationType}` : ''),
|
|
180
|
+
areaUnits: areaUnits + (calibrationType ? ` ${calibrationType}` : ''),
|
|
181
|
+
scale,
|
|
182
|
+
};
|
|
183
|
+
};
|
|
184
|
+
|
|
185
|
+
const getCalibratedProbeUnitsAndValue = (image, handles) => {
|
|
186
|
+
const [imageIndex] = handles;
|
|
187
|
+
const { calibration } = image;
|
|
188
|
+
let units = ['raw'];
|
|
189
|
+
let values = [null];
|
|
190
|
+
let calibrationType = '';
|
|
191
|
+
|
|
192
|
+
if (
|
|
193
|
+
!calibration ||
|
|
194
|
+
(!calibration.type && !calibration.sequenceOfUltrasoundRegions)
|
|
195
|
+
) {
|
|
196
|
+
return { units, values };
|
|
197
|
+
// Todo: add support for other scenarios
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
if (calibration.sequenceOfUltrasoundRegions) {
|
|
201
|
+
// for Probe tool
|
|
202
|
+
const supportedRegionsMetadata =
|
|
203
|
+
calibration.sequenceOfUltrasoundRegions.filter(
|
|
204
|
+
(region) =>
|
|
205
|
+
SUPPORTED_REGION_DATA_TYPES.includes(region.regionDataType) &&
|
|
206
|
+
SUPPORTED_PROBE_VARIANT.includes(
|
|
207
|
+
`${region.physicalUnitXDirection},${region.physicalUnitYDirection}`
|
|
208
|
+
)
|
|
209
|
+
);
|
|
210
|
+
|
|
211
|
+
if (!supportedRegionsMetadata?.length) {
|
|
212
|
+
return { units, values };
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
const region = supportedRegionsMetadata.find(
|
|
216
|
+
(region) =>
|
|
217
|
+
imageIndex[0] >= region.regionLocationMinX0 &&
|
|
218
|
+
imageIndex[0] <= region.regionLocationMaxX1 &&
|
|
219
|
+
imageIndex[1] >= region.regionLocationMinY0 &&
|
|
220
|
+
imageIndex[1] <= region.regionLocationMaxY1
|
|
221
|
+
);
|
|
222
|
+
|
|
223
|
+
if (!region) {
|
|
224
|
+
return { units, values };
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
// Todo: I think this is a ok assumption for now that if the referencePixelX0 and referencePixelY0
|
|
228
|
+
// are not defined, then we can assume 0 for them
|
|
229
|
+
const { referencePixelX0 = 0, referencePixelY0 = 0 } = region;
|
|
230
|
+
const { physicalDeltaX, physicalDeltaY } = region;
|
|
231
|
+
|
|
232
|
+
const yValue =
|
|
233
|
+
(imageIndex[1] - region.regionLocationMinY0 - referencePixelY0) *
|
|
234
|
+
physicalDeltaY;
|
|
235
|
+
|
|
236
|
+
const xValue =
|
|
237
|
+
(imageIndex[0] - region.regionLocationMinX0 - referencePixelX0) *
|
|
238
|
+
physicalDeltaX;
|
|
239
|
+
|
|
240
|
+
calibrationType = 'US Region';
|
|
241
|
+
values = [xValue, yValue];
|
|
242
|
+
units = [
|
|
243
|
+
UNIT_MAPPING[region.physicalUnitXDirection],
|
|
244
|
+
UNIT_MAPPING[region.physicalUnitYDirection],
|
|
245
|
+
];
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
return {
|
|
249
|
+
units,
|
|
250
|
+
values,
|
|
251
|
+
calibrationType,
|
|
252
|
+
};
|
|
253
|
+
};
|
|
60
254
|
|
|
61
255
|
/** Gets the aspect ratio of the screen display relative to the image
|
|
62
256
|
* display in order to square up measurement values.
|
|
@@ -71,6 +265,8 @@ export default getCalibratedLengthUnits;
|
|
|
71
265
|
export {
|
|
72
266
|
getCalibratedAreaUnits,
|
|
73
267
|
getCalibratedLengthUnits,
|
|
268
|
+
getCalibratedLengthUnitsAndScale,
|
|
74
269
|
getCalibratedScale,
|
|
75
270
|
getCalibratedAspect,
|
|
271
|
+
getCalibratedProbeUnitsAndValue,
|
|
76
272
|
};
|
package/src/utilities/index.ts
CHANGED
|
@@ -26,6 +26,7 @@ import { pointToString } from './pointToString';
|
|
|
26
26
|
import annotationFrameRange from './annotationFrameRange';
|
|
27
27
|
|
|
28
28
|
// name spaces
|
|
29
|
+
import * as contours from './contours';
|
|
29
30
|
import * as segmentation from './segmentation';
|
|
30
31
|
import * as drawing from './drawing';
|
|
31
32
|
import * as math from './math';
|
|
@@ -63,6 +64,7 @@ export {
|
|
|
63
64
|
getCalibratedAreaUnits,
|
|
64
65
|
getCalibratedScale,
|
|
65
66
|
segmentation,
|
|
67
|
+
contours,
|
|
66
68
|
triggerAnnotationRenderForViewportIds,
|
|
67
69
|
triggerAnnotationRender,
|
|
68
70
|
pointInShapeCallback,
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { generateContourSetsFromLabelmap } from '../contours';
|
|
2
|
+
import SegmentationRepresentations from '../../enums/SegmentationRepresentations';
|
|
3
|
+
import findLargestBidirectional from './findLargestBidirectional';
|
|
4
|
+
|
|
5
|
+
const EPSILON = 1e-2;
|
|
6
|
+
const { Labelmap } = SegmentationRepresentations;
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Generates a contour object over the segment, and then uses the contouring to
|
|
10
|
+
* find the largest bidirectional object that can be applied within the acquisition
|
|
11
|
+
* plane that is within the segment index, or the contained segment indices.
|
|
12
|
+
*
|
|
13
|
+
* @param segmentation.segments - a list of segments to apply the contour to.
|
|
14
|
+
* @param segmentation.segments.containedSegmentIndices - a set of segment indexes equivalent to the primary segment
|
|
15
|
+
* @param segmentation.segments.label - the label for the segment
|
|
16
|
+
* @param segmentation.segments.color - the color to use for the segment label
|
|
17
|
+
*/
|
|
18
|
+
export default function contourAndFindLargestBidirectional(segmentation) {
|
|
19
|
+
const contours = generateContourSetsFromLabelmap({
|
|
20
|
+
segmentations: segmentation,
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
if (!contours?.length || !contours[0].sliceContours.length) {
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const {
|
|
28
|
+
representationData,
|
|
29
|
+
segments = [
|
|
30
|
+
null,
|
|
31
|
+
{ label: 'Unspecified', color: null, containedSegmentIndices: null },
|
|
32
|
+
],
|
|
33
|
+
} = segmentation;
|
|
34
|
+
const { volumeId: segVolumeId } = representationData[Labelmap];
|
|
35
|
+
|
|
36
|
+
const segmentIndex = segments.findIndex((it) => !!it);
|
|
37
|
+
if (segmentIndex === -1) {
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
segments[segmentIndex].segmentIndex = segmentIndex;
|
|
41
|
+
return findLargestBidirectional(
|
|
42
|
+
contours[0],
|
|
43
|
+
segVolumeId,
|
|
44
|
+
segments[segmentIndex]
|
|
45
|
+
);
|
|
46
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import type { Types } from '@cornerstonejs/core';
|
|
2
|
+
import type { Annotation } from '../../types/AnnotationTypes';
|
|
3
|
+
|
|
4
|
+
export type BidirectionalData = {
|
|
5
|
+
majorAxis: [Types.Point3, Types.Point3];
|
|
6
|
+
minorAxis: [Types.Point3, Types.Point3];
|
|
7
|
+
maxMajor: number;
|
|
8
|
+
maxMinor: number;
|
|
9
|
+
segmentIndex: number;
|
|
10
|
+
label?: string;
|
|
11
|
+
color?: string | number[];
|
|
12
|
+
referencedImageId: string;
|
|
13
|
+
FrameOfReferenceUID: string;
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Creates data suitable for the BidirectionalTool from the basic bidirectional
|
|
18
|
+
* data object.
|
|
19
|
+
*/
|
|
20
|
+
export default function createBidirectionalToolData(
|
|
21
|
+
bidirectionalData: BidirectionalData,
|
|
22
|
+
viewport
|
|
23
|
+
): Annotation {
|
|
24
|
+
const {
|
|
25
|
+
majorAxis,
|
|
26
|
+
minorAxis,
|
|
27
|
+
label = '',
|
|
28
|
+
FrameOfReferenceUID,
|
|
29
|
+
referencedImageId,
|
|
30
|
+
} = bidirectionalData;
|
|
31
|
+
const [major0, major1] = majorAxis;
|
|
32
|
+
const [minor0, minor1] = minorAxis;
|
|
33
|
+
|
|
34
|
+
const { viewUp, viewPlaneNormal } = viewport.getCamera();
|
|
35
|
+
const points = [major0, major1, minor0, minor1];
|
|
36
|
+
const bidirectionalToolData = {
|
|
37
|
+
highlighted: true,
|
|
38
|
+
invalidated: true,
|
|
39
|
+
metadata: {
|
|
40
|
+
toolName: 'Bidirectional',
|
|
41
|
+
viewPlaneNormal,
|
|
42
|
+
viewUp,
|
|
43
|
+
FrameOfReferenceUID,
|
|
44
|
+
referencedImageId,
|
|
45
|
+
},
|
|
46
|
+
data: {
|
|
47
|
+
handles: {
|
|
48
|
+
points,
|
|
49
|
+
textBox: {
|
|
50
|
+
hasMoved: false,
|
|
51
|
+
worldPosition: [0, 0, 0] as Types.Point3,
|
|
52
|
+
worldBoundingBox: {
|
|
53
|
+
topLeft: [0, 0, 0] as Types.Point3,
|
|
54
|
+
topRight: [0, 0, 0] as Types.Point3,
|
|
55
|
+
bottomLeft: [0, 0, 0] as Types.Point3,
|
|
56
|
+
bottomRight: [0, 0, 0] as Types.Point3,
|
|
57
|
+
},
|
|
58
|
+
},
|
|
59
|
+
activeHandleIndex: null,
|
|
60
|
+
},
|
|
61
|
+
label,
|
|
62
|
+
cachedStats: {},
|
|
63
|
+
},
|
|
64
|
+
isLocked: false,
|
|
65
|
+
isVisible: true,
|
|
66
|
+
};
|
|
67
|
+
return bidirectionalToolData;
|
|
68
|
+
}
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
import { vec3 } from 'gl-matrix';
|
|
2
|
+
|
|
3
|
+
import { createIsInSegment, isLineInSegment } from './isLineInSegment';
|
|
4
|
+
import type { BidirectionalData } from './createBidirectionalToolData';
|
|
5
|
+
|
|
6
|
+
const EPSILON = 1e-2;
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Search in the contours for the given segment to find the largest bidirectional
|
|
10
|
+
* that will fit entirely within the slice contours inside the contours object.
|
|
11
|
+
* Assumptions/implementation details:
|
|
12
|
+
*
|
|
13
|
+
* 1. The major and minor bidirectional lines must not cross the contour
|
|
14
|
+
* 2. The center point for both major and minor bidirectional lines must be
|
|
15
|
+
* within the segment, or the contained segment index.
|
|
16
|
+
* 3. The major/minor axis must be orthogonal
|
|
17
|
+
*
|
|
18
|
+
* Note this does NOT test that the major/minor axis intersect. Normally they will, but
|
|
19
|
+
* it isn't a hard requirement.
|
|
20
|
+
*
|
|
21
|
+
* The way that islands within the contours are handled is to allow the island to be
|
|
22
|
+
* coloured with something that is contained - that way both open and closed islands
|
|
23
|
+
* can be handled correctly for finding the bidirectional (an open island is a section
|
|
24
|
+
* inside the segment that is open to the outside - this can happen at bone endpoints or when
|
|
25
|
+
* one region flows into another)
|
|
26
|
+
*/
|
|
27
|
+
export default function findLargestBidirectional(
|
|
28
|
+
contours,
|
|
29
|
+
segVolumeId: string,
|
|
30
|
+
segment
|
|
31
|
+
) {
|
|
32
|
+
const { sliceContours } = contours;
|
|
33
|
+
const { segmentIndex, containedSegmentIndices } = segment;
|
|
34
|
+
let maxBidirectional;
|
|
35
|
+
const isInSegment = createIsInSegment(
|
|
36
|
+
segVolumeId,
|
|
37
|
+
segmentIndex,
|
|
38
|
+
containedSegmentIndices
|
|
39
|
+
);
|
|
40
|
+
for (const sliceContour of sliceContours) {
|
|
41
|
+
const bidirectional = createBidirectionalForSlice(
|
|
42
|
+
sliceContour,
|
|
43
|
+
isInSegment,
|
|
44
|
+
maxBidirectional
|
|
45
|
+
);
|
|
46
|
+
if (!bidirectional) {
|
|
47
|
+
continue;
|
|
48
|
+
}
|
|
49
|
+
maxBidirectional = bidirectional;
|
|
50
|
+
}
|
|
51
|
+
if (maxBidirectional) {
|
|
52
|
+
Object.assign(maxBidirectional, segment);
|
|
53
|
+
}
|
|
54
|
+
return maxBidirectional;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* This function creates a bidirectional data object for the given slice and
|
|
59
|
+
* slice contour, only when the major distance is larger than currentMax, or
|
|
60
|
+
* equal to current max and the minor is larger than currentMax's minor.
|
|
61
|
+
* It does this by looking at every pair of distances in sliceCountour to find
|
|
62
|
+
* those larger than the currentMax, and then finds the minor distance for those
|
|
63
|
+
* major distances.
|
|
64
|
+
*
|
|
65
|
+
*/
|
|
66
|
+
function createBidirectionalForSlice(
|
|
67
|
+
sliceContour,
|
|
68
|
+
isInSegment,
|
|
69
|
+
currentMax = { maxMajor: 0, maxMinor: 0 }
|
|
70
|
+
) {
|
|
71
|
+
const { points } = sliceContour.polyData;
|
|
72
|
+
const { maxMinor: currentMaxMinor, maxMajor: currentMaxMajor } = currentMax;
|
|
73
|
+
let maxMajor = currentMaxMajor * currentMaxMajor;
|
|
74
|
+
let maxMinor = currentMaxMinor * currentMaxMinor;
|
|
75
|
+
let maxMajorPoints;
|
|
76
|
+
for (let index1 = 0; index1 < points.length; index1++) {
|
|
77
|
+
for (let index2 = index1 + 1; index2 < points.length; index2++) {
|
|
78
|
+
const point1 = points[index1];
|
|
79
|
+
const point2 = points[index2];
|
|
80
|
+
const distance2 = vec3.sqrDist(point1, point2);
|
|
81
|
+
if (distance2 < maxMajor) {
|
|
82
|
+
continue;
|
|
83
|
+
}
|
|
84
|
+
if (distance2 - EPSILON < maxMajor + EPSILON && maxMajorPoints) {
|
|
85
|
+
// Consider adding to the set of points rather than continuing here
|
|
86
|
+
// so that all minor axis can be tested
|
|
87
|
+
continue;
|
|
88
|
+
}
|
|
89
|
+
if (!isInSegment.testCenter(point1, point2)) {
|
|
90
|
+
// Center between the two points has to be in the segment, otherwise
|
|
91
|
+
// this is out of bounds.
|
|
92
|
+
continue;
|
|
93
|
+
}
|
|
94
|
+
if (!isLineInSegment(point1, point2, isInSegment)) {
|
|
95
|
+
// If the line intersects the segment boundary, then skip it
|
|
96
|
+
continue;
|
|
97
|
+
}
|
|
98
|
+
maxMajor = distance2 - EPSILON;
|
|
99
|
+
maxMajorPoints = [index1, index2];
|
|
100
|
+
maxMinor = 0;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
if (!maxMajorPoints) {
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
maxMajor = Math.sqrt(maxMajor + EPSILON);
|
|
108
|
+
const handle0 = points[maxMajorPoints[0]];
|
|
109
|
+
const handle1 = points[maxMajorPoints[1]];
|
|
110
|
+
const unitMajor = vec3.sub(vec3.create(), handle0, handle1);
|
|
111
|
+
vec3.scale(unitMajor, unitMajor, 1 / maxMajor);
|
|
112
|
+
|
|
113
|
+
let maxMinorPoints;
|
|
114
|
+
|
|
115
|
+
for (let index1 = 0; index1 < points.length; index1++) {
|
|
116
|
+
for (let index2 = index1 + 1; index2 < points.length; index2++) {
|
|
117
|
+
const point1 = points[index1];
|
|
118
|
+
const point2 = points[index2];
|
|
119
|
+
const distance2 = vec3.sqrDist(point1, point2);
|
|
120
|
+
if (distance2 <= maxMinor) {
|
|
121
|
+
continue;
|
|
122
|
+
}
|
|
123
|
+
const delta = vec3.sub(vec3.create(), point1, point2);
|
|
124
|
+
|
|
125
|
+
const dot = Math.abs(vec3.dot(delta, unitMajor)) / Math.sqrt(distance2);
|
|
126
|
+
if (dot > EPSILON) {
|
|
127
|
+
continue;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
if (!isInSegment.testCenter(point1, point2)) {
|
|
131
|
+
// Center between the two points has to be in the segment, otherwise
|
|
132
|
+
// this is out of bounds.
|
|
133
|
+
continue;
|
|
134
|
+
}
|
|
135
|
+
if (!isLineInSegment(point1, point2, isInSegment)) {
|
|
136
|
+
continue;
|
|
137
|
+
}
|
|
138
|
+
maxMinor = distance2;
|
|
139
|
+
maxMinorPoints = [index1, index2];
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
if (!maxMinorPoints) {
|
|
144
|
+
// Didn't find a larger minor distance
|
|
145
|
+
return;
|
|
146
|
+
}
|
|
147
|
+
maxMinor = Math.sqrt(maxMinor);
|
|
148
|
+
const handle2 = points[maxMinorPoints[0]];
|
|
149
|
+
const handle3 = points[maxMinorPoints[1]];
|
|
150
|
+
|
|
151
|
+
const bidirectional = {
|
|
152
|
+
majorAxis: [handle0, handle1],
|
|
153
|
+
minorAxis: [handle2, handle3],
|
|
154
|
+
maxMajor,
|
|
155
|
+
maxMinor,
|
|
156
|
+
...sliceContour,
|
|
157
|
+
} as BidirectionalData;
|
|
158
|
+
return bidirectional;
|
|
159
|
+
}
|
|
@@ -15,6 +15,9 @@ import {
|
|
|
15
15
|
setBrushThresholdForToolGroup,
|
|
16
16
|
} from './brushThresholdForToolGroup';
|
|
17
17
|
import thresholdSegmentationByRange from './thresholdSegmentationByRange';
|
|
18
|
+
import contourAndFindLargestBidirectional from './contourAndFindLargestBidirectional';
|
|
19
|
+
import createBidirectionalToolData from './createBidirectionalToolData';
|
|
20
|
+
import segmentContourAction from './segmentContourAction';
|
|
18
21
|
|
|
19
22
|
export {
|
|
20
23
|
thresholdVolumeByRange,
|
|
@@ -30,4 +33,7 @@ export {
|
|
|
30
33
|
getBrushThresholdForToolGroup,
|
|
31
34
|
setBrushThresholdForToolGroup,
|
|
32
35
|
thresholdSegmentationByRange,
|
|
36
|
+
contourAndFindLargestBidirectional,
|
|
37
|
+
createBidirectionalToolData,
|
|
38
|
+
segmentContourAction,
|
|
33
39
|
};
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import type { Types } from '@cornerstonejs/core';
|
|
2
|
+
import { cache } from '@cornerstonejs/core';
|
|
3
|
+
import { vec3 } from 'gl-matrix';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Determines if there is a point between point1 and point2 which is not
|
|
7
|
+
* contained in the segmentation
|
|
8
|
+
*/
|
|
9
|
+
export default function isLineInSegment(
|
|
10
|
+
point1: Types.Point3,
|
|
11
|
+
point2: Types.Point3,
|
|
12
|
+
isInSegment
|
|
13
|
+
) {
|
|
14
|
+
const ijk1 = isInSegment.toIJK(point1);
|
|
15
|
+
const ijk2 = isInSegment.toIJK(point2);
|
|
16
|
+
const testPoint = vec3.create();
|
|
17
|
+
const { testIJK } = isInSegment;
|
|
18
|
+
const delta = vec3.sub(vec3.create(), ijk1, ijk2);
|
|
19
|
+
|
|
20
|
+
// Test once for index value between the two points, so the max of the
|
|
21
|
+
// difference in IJK values
|
|
22
|
+
const testSize = Math.round(Math.max(...delta.map(Math.abs)));
|
|
23
|
+
if (testSize < 2) {
|
|
24
|
+
// No need to test when there are only two points
|
|
25
|
+
return true;
|
|
26
|
+
}
|
|
27
|
+
const unitDelta = vec3.scale(vec3.create(), delta, 1 / testSize);
|
|
28
|
+
|
|
29
|
+
for (let i = 1; i < testSize; i++) {
|
|
30
|
+
vec3.scaleAndAdd(testPoint, ijk2, unitDelta, i);
|
|
31
|
+
if (!testIJK(testPoint)) {
|
|
32
|
+
return false;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
return true;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Creates a function that tests to see if the provided line segment, specified
|
|
40
|
+
* in LPS space (as endpoints) is contained in the segment
|
|
41
|
+
*/
|
|
42
|
+
function createIsInSegment(
|
|
43
|
+
segVolumeId: string,
|
|
44
|
+
segmentIndex: number,
|
|
45
|
+
containedSegmentIndices?: Set<number>
|
|
46
|
+
) {
|
|
47
|
+
// Get segmentation volume
|
|
48
|
+
const vol = cache.getVolume(segVolumeId);
|
|
49
|
+
if (!vol) {
|
|
50
|
+
console.warn(`No volume found for ${segVolumeId}`);
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const segData = vol.imageData.getPointData().getScalars().getData();
|
|
55
|
+
const width = vol.dimensions[0];
|
|
56
|
+
const pixelsPerSlice = width * vol.dimensions[1];
|
|
57
|
+
|
|
58
|
+
return {
|
|
59
|
+
/**
|
|
60
|
+
* Find the center point between point1 and point2, convert it to IJK space
|
|
61
|
+
* and test if the value at that location is in the segment
|
|
62
|
+
*/
|
|
63
|
+
testCenter: (point1, point2) => {
|
|
64
|
+
const point = vec3.add(vec3.create(), point1, point2).map((it) => it / 2);
|
|
65
|
+
const ijk = vol.imageData.worldToIndex(point as vec3).map(Math.round);
|
|
66
|
+
const [i, j, k] = ijk;
|
|
67
|
+
const index = i + j * width + k * pixelsPerSlice;
|
|
68
|
+
const value = segData[index];
|
|
69
|
+
return value === segmentIndex || containedSegmentIndices?.has(value);
|
|
70
|
+
},
|
|
71
|
+
|
|
72
|
+
toIJK: (point) => vol.imageData.worldToIndex(point as vec3),
|
|
73
|
+
|
|
74
|
+
testIJK: (ijk) => {
|
|
75
|
+
const [i, j, k] = ijk;
|
|
76
|
+
const index =
|
|
77
|
+
Math.round(i) + Math.round(j) * width + Math.round(k) * pixelsPerSlice;
|
|
78
|
+
const value = segData[index];
|
|
79
|
+
return value === segmentIndex || containedSegmentIndices?.has(value);
|
|
80
|
+
},
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
export { createIsInSegment, isLineInSegment };
|