@cornerstonejs/tools 1.59.0 → 1.59.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/cjs/stateManagement/segmentation/polySeg/Labelmap/convertContourToLabelmap.js +14 -2
- package/dist/cjs/stateManagement/segmentation/polySeg/Labelmap/convertContourToLabelmap.js.map +1 -1
- package/dist/cjs/stateManagement/segmentation/polySeg/Labelmap/labelmapComputationStrategies.js +8 -15
- package/dist/cjs/stateManagement/segmentation/polySeg/Labelmap/labelmapComputationStrategies.js.map +1 -1
- package/dist/cjs/types/ContourAnnotation.d.ts +1 -0
- package/dist/cjs/utilities/math/polyline/combinePolyline.js +2 -2
- package/dist/cjs/utilities/math/polyline/containsPoint.d.ts +4 -1
- package/dist/cjs/utilities/math/polyline/containsPoint.js +11 -1
- package/dist/cjs/utilities/math/polyline/containsPoint.js.map +1 -1
- package/dist/cjs/utilities/math/polyline/index.d.ts +2 -1
- package/dist/cjs/utilities/math/polyline/index.js +3 -1
- package/dist/cjs/utilities/math/polyline/index.js.map +1 -1
- package/dist/cjs/utilities/math/polyline/isPointInsidePolyline3D.d.ts +3 -1
- package/dist/cjs/utilities/math/polyline/isPointInsidePolyline3D.js +17 -18
- package/dist/cjs/utilities/math/polyline/isPointInsidePolyline3D.js.map +1 -1
- package/dist/cjs/utilities/math/polyline/projectTo2D.d.ts +5 -0
- package/dist/cjs/utilities/math/polyline/projectTo2D.js +30 -0
- package/dist/cjs/utilities/math/polyline/projectTo2D.js.map +1 -0
- package/dist/cjs/workers/polySegConverters.js +32 -6
- package/dist/cjs/workers/polySegConverters.js.map +1 -1
- package/dist/esm/stateManagement/segmentation/polySeg/Labelmap/convertContourToLabelmap.js +13 -2
- package/dist/esm/stateManagement/segmentation/polySeg/Labelmap/convertContourToLabelmap.js.map +1 -1
- package/dist/esm/stateManagement/segmentation/polySeg/Labelmap/labelmapComputationStrategies.js +8 -15
- package/dist/esm/stateManagement/segmentation/polySeg/Labelmap/labelmapComputationStrategies.js.map +1 -1
- package/dist/esm/utilities/math/polyline/combinePolyline.js +2 -2
- package/dist/esm/utilities/math/polyline/containsPoint.js +11 -1
- package/dist/esm/utilities/math/polyline/containsPoint.js.map +1 -1
- package/dist/esm/utilities/math/polyline/index.js +2 -1
- package/dist/esm/utilities/math/polyline/index.js.map +1 -1
- package/dist/esm/utilities/math/polyline/isPointInsidePolyline3D.js +17 -18
- package/dist/esm/utilities/math/polyline/isPointInsidePolyline3D.js.map +1 -1
- package/dist/esm/utilities/math/polyline/projectTo2D.js +26 -0
- package/dist/esm/utilities/math/polyline/projectTo2D.js.map +1 -0
- package/dist/esm/workers/polySegConverters.js +33 -7
- package/dist/esm/workers/polySegConverters.js.map +1 -1
- package/dist/types/stateManagement/segmentation/polySeg/Labelmap/convertContourToLabelmap.d.ts.map +1 -1
- package/dist/types/stateManagement/segmentation/polySeg/Labelmap/labelmapComputationStrategies.d.ts.map +1 -1
- package/dist/types/types/ContourAnnotation.d.ts +1 -0
- package/dist/types/types/ContourAnnotation.d.ts.map +1 -1
- package/dist/types/utilities/math/polyline/containsPoint.d.ts +4 -1
- package/dist/types/utilities/math/polyline/containsPoint.d.ts.map +1 -1
- package/dist/types/utilities/math/polyline/index.d.ts +2 -1
- package/dist/types/utilities/math/polyline/index.d.ts.map +1 -1
- package/dist/types/utilities/math/polyline/isPointInsidePolyline3D.d.ts +3 -1
- package/dist/types/utilities/math/polyline/isPointInsidePolyline3D.d.ts.map +1 -1
- package/dist/types/utilities/math/polyline/projectTo2D.d.ts +6 -0
- package/dist/types/utilities/math/polyline/projectTo2D.d.ts.map +1 -0
- package/dist/umd/985.index.js +1 -1
- package/dist/umd/985.index.js.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/stateManagement/segmentation/polySeg/Labelmap/convertContourToLabelmap.ts +27 -4
- package/src/stateManagement/segmentation/polySeg/Labelmap/labelmapComputationStrategies.ts +9 -15
- package/src/types/ContourAnnotation.ts +1 -0
- package/src/utilities/math/polyline/combinePolyline.ts +2 -2
- package/src/utilities/math/polyline/containsPoint.ts +16 -1
- package/src/utilities/math/polyline/index.ts +2 -0
- package/src/utilities/math/polyline/isPointInsidePolyline3D.ts +21 -27
- package/src/utilities/math/polyline/projectTo2D.ts +52 -0
- package/src/workers/polySegConverters.js +51 -17
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cornerstonejs/tools",
|
|
3
|
-
"version": "1.59.
|
|
3
|
+
"version": "1.59.1",
|
|
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.59.
|
|
32
|
+
"@cornerstonejs/core": "^1.59.1",
|
|
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": "f8957765edd911ce0e78ed21f8de92ca4b01f516"
|
|
63
63
|
}
|
|
@@ -13,6 +13,7 @@ import {
|
|
|
13
13
|
} from '@cornerstonejs/core';
|
|
14
14
|
import {
|
|
15
15
|
Annotation,
|
|
16
|
+
ContourAnnotation,
|
|
16
17
|
ContourSegmentationData,
|
|
17
18
|
PolySegConversionOptions,
|
|
18
19
|
} from '../../../../types';
|
|
@@ -256,14 +257,36 @@ function _getAnnotationMapFromSegmentation(
|
|
|
256
257
|
? options.segmentIndices
|
|
257
258
|
: Array.from(annotationMap.keys());
|
|
258
259
|
|
|
259
|
-
const annotationUIDsInSegmentMap = new Map<number,
|
|
260
|
+
const annotationUIDsInSegmentMap = new Map<number, any>();
|
|
260
261
|
segmentIndices.forEach((index) => {
|
|
261
262
|
const annotationUIDsInSegment = annotationMap.get(index);
|
|
262
263
|
|
|
263
|
-
|
|
264
|
-
|
|
264
|
+
// Todo: there is a bug right now where the annotationUIDsInSegment has both
|
|
265
|
+
// children and parent annotations, so we need to filter out the parent
|
|
266
|
+
// annotations only
|
|
265
267
|
|
|
266
|
-
|
|
268
|
+
let uids = Array.from(annotationUIDsInSegment);
|
|
269
|
+
|
|
270
|
+
uids = uids.filter(
|
|
271
|
+
(uid) => !(getAnnotation(uid) as Annotation).parentAnnotationUID
|
|
272
|
+
);
|
|
273
|
+
|
|
274
|
+
const annotations = uids.map((uid) => {
|
|
275
|
+
const annotation = getAnnotation(uid) as ContourAnnotation;
|
|
276
|
+
const hasChildAnnotations = annotation.childAnnotationUIDs?.length;
|
|
277
|
+
|
|
278
|
+
return {
|
|
279
|
+
polyline: annotation.data.contour.polyline,
|
|
280
|
+
referencedImageId: annotation.metadata.referencedImageId,
|
|
281
|
+
holesPolyline:
|
|
282
|
+
hasChildAnnotations &&
|
|
283
|
+
annotation.childAnnotationUIDs.map((childUID) => {
|
|
284
|
+
const childAnnotation = getAnnotation(
|
|
285
|
+
childUID
|
|
286
|
+
) as ContourAnnotation;
|
|
287
|
+
return childAnnotation.data.contour.polyline;
|
|
288
|
+
}),
|
|
289
|
+
};
|
|
267
290
|
});
|
|
268
291
|
|
|
269
292
|
annotationUIDsInSegmentMap.set(index, annotations);
|
|
@@ -86,21 +86,15 @@ async function computeLabelmapFromContourSegmentation(
|
|
|
86
86
|
const segmentation = getSegmentation(segmentationId);
|
|
87
87
|
const representationData = segmentation.representationData.CONTOUR;
|
|
88
88
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
}
|
|
98
|
-
result = await convertContourToStackLabelmap(representationData, {
|
|
99
|
-
segmentIndices,
|
|
100
|
-
segmentationRepresentationUID: options.segmentationRepresentationUID,
|
|
101
|
-
viewport: options.viewport,
|
|
102
|
-
});
|
|
103
|
-
}
|
|
89
|
+
const convertFunction = isVolume
|
|
90
|
+
? convertContourToVolumeLabelmap
|
|
91
|
+
: convertContourToStackLabelmap;
|
|
92
|
+
|
|
93
|
+
const result = await convertFunction(representationData, {
|
|
94
|
+
segmentIndices,
|
|
95
|
+
segmentationRepresentationUID: options.segmentationRepresentationUID,
|
|
96
|
+
viewport: options.viewport,
|
|
97
|
+
});
|
|
104
98
|
|
|
105
99
|
return result;
|
|
106
100
|
}
|
|
@@ -74,9 +74,9 @@ function getSourceAndTargetPointsList(
|
|
|
74
74
|
PolylineIntersectionPoint[]
|
|
75
75
|
>();
|
|
76
76
|
|
|
77
|
-
const
|
|
77
|
+
const isFirstPointInside = containsPoint(sourcePolyline, targetPolyline[0]);
|
|
78
78
|
|
|
79
|
-
let intersectionPointDirection =
|
|
79
|
+
let intersectionPointDirection = isFirstPointInside
|
|
80
80
|
? PolylinePointDirection.Exiting
|
|
81
81
|
: PolylinePointDirection.Entering;
|
|
82
82
|
|
|
@@ -17,7 +17,12 @@ import isClosed from './isClosed';
|
|
|
17
17
|
export default function containsPoint(
|
|
18
18
|
polyline: Types.Point2[],
|
|
19
19
|
point: Types.Point2,
|
|
20
|
-
|
|
20
|
+
options: {
|
|
21
|
+
closed?: boolean;
|
|
22
|
+
holes?: Types.Point2[][];
|
|
23
|
+
} = {
|
|
24
|
+
closed: undefined,
|
|
25
|
+
}
|
|
21
26
|
): boolean {
|
|
22
27
|
if (polyline.length < 3) {
|
|
23
28
|
return false;
|
|
@@ -26,6 +31,16 @@ export default function containsPoint(
|
|
|
26
31
|
const numPolylinePoints = polyline.length;
|
|
27
32
|
let numIntersections = 0;
|
|
28
33
|
|
|
34
|
+
const { closed, holes } = options;
|
|
35
|
+
|
|
36
|
+
if (holes?.length) {
|
|
37
|
+
for (const hole of holes) {
|
|
38
|
+
if (containsPoint(hole, point)) {
|
|
39
|
+
return false;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
29
44
|
// Test intersection against [end, start] line segment if it should be closed
|
|
30
45
|
const shouldClose = !(closed === undefined ? isClosed(polyline) : closed);
|
|
31
46
|
const maxSegmentIndex = polyline.length - (shouldClose ? 1 : 2);
|
|
@@ -19,6 +19,7 @@ import pointsAreWithinCloseContourProximity from './pointsAreWithinCloseContourP
|
|
|
19
19
|
import addCanvasPointsToArray from './addCanvasPointsToArray';
|
|
20
20
|
import pointCanProjectOnLine from './pointCanProjectOnLine';
|
|
21
21
|
import { isPointInsidePolyline3D } from './isPointInsidePolyline3D';
|
|
22
|
+
import { projectTo2D } from './projectTo2D';
|
|
22
23
|
|
|
23
24
|
export {
|
|
24
25
|
isClosed,
|
|
@@ -43,4 +44,5 @@ export {
|
|
|
43
44
|
mergePolylines,
|
|
44
45
|
subtractPolylines,
|
|
45
46
|
isPointInsidePolyline3D,
|
|
47
|
+
projectTo2D,
|
|
46
48
|
};
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { Types } from '@cornerstonejs/core';
|
|
2
2
|
import containsPoint from './containsPoint';
|
|
3
|
+
import { projectTo2D } from './projectTo2D';
|
|
3
4
|
|
|
4
5
|
/**
|
|
5
6
|
* Determines whether a 3D point is inside a polyline in 3D space.
|
|
@@ -9,42 +10,35 @@ import containsPoint from './containsPoint';
|
|
|
9
10
|
*
|
|
10
11
|
* @param point - The 3D point to test.
|
|
11
12
|
* @param polyline - The polyline represented as an array of 3D points.
|
|
13
|
+
* @param options.holesPolyline - An array of polylines representing each hole, so it
|
|
14
|
+
* is an array of arrays of 3D points.
|
|
12
15
|
* @returns A boolean indicating whether the point is inside the polyline.
|
|
13
16
|
* @throws An error if a shared dimension index cannot be found for the polyline points.
|
|
14
17
|
*/
|
|
15
18
|
export function isPointInsidePolyline3D(
|
|
16
19
|
point: Types.Point3,
|
|
17
|
-
polyline: Types.Point3[]
|
|
20
|
+
polyline: Types.Point3[],
|
|
21
|
+
options: { holes?: Types.Point3[][] } = {}
|
|
18
22
|
) {
|
|
19
|
-
|
|
23
|
+
const { sharedDimensionIndex, projectedPolyline } = projectTo2D(polyline);
|
|
20
24
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
// Use the first three points, two is enough but three is more robust
|
|
24
|
-
let sharedDimensionIndex;
|
|
25
|
+
const { holes } = options;
|
|
26
|
+
const projectedHoles = [] as Types.Point2[][];
|
|
25
27
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
break;
|
|
31
|
-
}
|
|
32
|
-
}
|
|
28
|
+
if (holes) {
|
|
29
|
+
for (let i = 0; i < holes.length; i++) {
|
|
30
|
+
const hole = holes[i];
|
|
31
|
+
const hole2D = [] as Types.Point2[];
|
|
33
32
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
33
|
+
for (let j = 0; j < hole.length; j++) {
|
|
34
|
+
hole2D.push([
|
|
35
|
+
hole[j][(sharedDimensionIndex + 1) % 3],
|
|
36
|
+
hole[j][(sharedDimensionIndex + 2) % 3],
|
|
37
|
+
]);
|
|
38
|
+
}
|
|
39
39
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
for (let i = 0; i < polyline.length; i++) {
|
|
44
|
-
points2D.push([
|
|
45
|
-
polyline[i][(sharedDimensionIndex + 1) % 3],
|
|
46
|
-
polyline[i][(sharedDimensionIndex + 2) % 3],
|
|
47
|
-
]);
|
|
40
|
+
projectedHoles.push(hole2D);
|
|
41
|
+
}
|
|
48
42
|
}
|
|
49
43
|
|
|
50
44
|
const point2D = [
|
|
@@ -52,5 +46,5 @@ export function isPointInsidePolyline3D(
|
|
|
52
46
|
point[(sharedDimensionIndex + 2) % 3],
|
|
53
47
|
] as Types.Point2;
|
|
54
48
|
|
|
55
|
-
return containsPoint(
|
|
49
|
+
return containsPoint(projectedPolyline, point2D, { holes: projectedHoles });
|
|
56
50
|
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { utilities } from '@cornerstonejs/core';
|
|
2
|
+
import type { Types } from '@cornerstonejs/core';
|
|
3
|
+
|
|
4
|
+
const epsilon = 1e-6;
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Projects a polyline from 3D to 2D by reducing one dimension.
|
|
8
|
+
*
|
|
9
|
+
* @param polyline - The polyline to be projected.
|
|
10
|
+
* @returns An object containing the shared dimension index and the projected polyline in 2D.
|
|
11
|
+
* @throws Error if a shared dimension index cannot be found for the polyline.
|
|
12
|
+
*/
|
|
13
|
+
export function projectTo2D(polyline: Types.Point3[]) {
|
|
14
|
+
// We need to reduce one dimension to 2D, so basically
|
|
15
|
+
// we need to find the dimension index that is shared by all points
|
|
16
|
+
// Use the first three points, two is enough but three is more robust
|
|
17
|
+
let sharedDimensionIndex;
|
|
18
|
+
|
|
19
|
+
const testPoints = utilities.getRandomSampleFromArray(polyline, 50);
|
|
20
|
+
|
|
21
|
+
for (let i = 0; i < 3; i++) {
|
|
22
|
+
if (
|
|
23
|
+
testPoints.every(
|
|
24
|
+
(point, index, array) => Math.abs(point[i] - array[0][i]) < epsilon
|
|
25
|
+
)
|
|
26
|
+
) {
|
|
27
|
+
sharedDimensionIndex = i;
|
|
28
|
+
break;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
if (sharedDimensionIndex === undefined) {
|
|
33
|
+
throw new Error(
|
|
34
|
+
'Cannot find a shared dimension index for polyline, probably oblique plane'
|
|
35
|
+
);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// convert polyline list and point to 2D
|
|
39
|
+
const points2D = [] as Types.Point2[];
|
|
40
|
+
|
|
41
|
+
const firstDim = (sharedDimensionIndex + 1) % 3;
|
|
42
|
+
const secondDim = (sharedDimensionIndex + 2) % 3;
|
|
43
|
+
|
|
44
|
+
for (let i = 0; i < polyline.length; i++) {
|
|
45
|
+
points2D.push([polyline[i][firstDim], polyline[i][secondDim]]);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
return {
|
|
49
|
+
sharedDimensionIndex,
|
|
50
|
+
projectedPolyline: points2D,
|
|
51
|
+
};
|
|
52
|
+
}
|
|
@@ -10,7 +10,12 @@ import vtkCutter from '@kitware/vtk.js/Filters/Core/Cutter';
|
|
|
10
10
|
|
|
11
11
|
import { getBoundingBoxAroundShapeWorld } from '../utilities/boundingBox';
|
|
12
12
|
import { pointInShapeCallback } from '../utilities';
|
|
13
|
-
import {
|
|
13
|
+
import {
|
|
14
|
+
containsPoint,
|
|
15
|
+
getAABB,
|
|
16
|
+
isPointInsidePolyline3D,
|
|
17
|
+
projectTo2D,
|
|
18
|
+
} from '../utilities/math/polyline';
|
|
14
19
|
import { isPlaneIntersectingAABB } from '../utilities/planar';
|
|
15
20
|
|
|
16
21
|
/**
|
|
@@ -161,9 +166,12 @@ const polySegConverters = {
|
|
|
161
166
|
const annotations = annotationUIDsInSegmentMap.get(index);
|
|
162
167
|
|
|
163
168
|
for (const annotation of annotations) {
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
169
|
+
if (!annotation.polyline) {
|
|
170
|
+
continue;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
const { polyline, holesPolyline } = annotation;
|
|
174
|
+
const bounds = getBoundingBoxAroundShapeWorld(polyline);
|
|
167
175
|
|
|
168
176
|
const [iMin, jMin, kMin] = utilities.transformWorldToIndex(imageData, [
|
|
169
177
|
bounds[0][0],
|
|
@@ -177,15 +185,29 @@ const polySegConverters = {
|
|
|
177
185
|
bounds[2][1],
|
|
178
186
|
]);
|
|
179
187
|
|
|
188
|
+
const { projectedPolyline, sharedDimensionIndex } =
|
|
189
|
+
projectTo2D(polyline);
|
|
190
|
+
|
|
191
|
+
const holes = holesPolyline?.map((hole) => {
|
|
192
|
+
const { projectedPolyline: projectedHole } = projectTo2D(hole);
|
|
193
|
+
return projectedHole;
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
const firstDim = (sharedDimensionIndex + 1) % 3;
|
|
197
|
+
const secondDim = (sharedDimensionIndex + 2) % 3;
|
|
198
|
+
|
|
180
199
|
// Run the pointInShapeCallback for the combined bounding box
|
|
181
200
|
pointInShapeCallback(
|
|
182
201
|
imageData,
|
|
183
202
|
(pointLPS) => {
|
|
203
|
+
const point2D = [pointLPS[firstDim], pointLPS[secondDim]];
|
|
204
|
+
|
|
184
205
|
// Check if the point is inside any of the polylines for this segment
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
206
|
+
const isInside = containsPoint(projectedPolyline, point2D, {
|
|
207
|
+
holes,
|
|
208
|
+
});
|
|
209
|
+
|
|
210
|
+
return isInside;
|
|
189
211
|
},
|
|
190
212
|
({ pointIJK }) => {
|
|
191
213
|
segmentationVoxelManager.setAtIJKPoint(pointIJK, index);
|
|
@@ -250,14 +272,12 @@ const polySegConverters = {
|
|
|
250
272
|
const annotations = annotationUIDsInSegmentMap.get(index);
|
|
251
273
|
|
|
252
274
|
for (const annotation of annotations) {
|
|
253
|
-
if (!annotation
|
|
275
|
+
if (!annotation.polyline) {
|
|
254
276
|
continue;
|
|
255
277
|
}
|
|
256
|
-
const bounds = getBoundingBoxAroundShapeWorld(
|
|
257
|
-
annotation.data.contour.polyline
|
|
258
|
-
);
|
|
259
278
|
|
|
260
|
-
const { referencedImageId } = annotation
|
|
279
|
+
const { polyline, holesPolyline, referencedImageId } = annotation;
|
|
280
|
+
const bounds = getBoundingBoxAroundShapeWorld(polyline);
|
|
261
281
|
|
|
262
282
|
const { manager: segmentationVoxelManager, imageData } =
|
|
263
283
|
segmentationVoxelManagers.get(referencedImageId);
|
|
@@ -274,15 +294,29 @@ const polySegConverters = {
|
|
|
274
294
|
bounds[2][1],
|
|
275
295
|
]);
|
|
276
296
|
|
|
297
|
+
const { projectedPolyline, sharedDimensionIndex } =
|
|
298
|
+
projectTo2D(polyline);
|
|
299
|
+
|
|
300
|
+
const holes = holesPolyline?.map((hole) => {
|
|
301
|
+
const { projectedPolyline: projectedHole } = projectTo2D(hole);
|
|
302
|
+
return projectedHole;
|
|
303
|
+
});
|
|
304
|
+
|
|
305
|
+
const firstDim = (sharedDimensionIndex + 1) % 3;
|
|
306
|
+
const secondDim = (sharedDimensionIndex + 2) % 3;
|
|
307
|
+
|
|
277
308
|
// Run the pointInShapeCallback for the combined bounding box
|
|
278
309
|
pointInShapeCallback(
|
|
279
310
|
imageData,
|
|
280
311
|
(pointLPS) => {
|
|
312
|
+
const point2D = [pointLPS[firstDim], pointLPS[secondDim]];
|
|
313
|
+
|
|
281
314
|
// Check if the point is inside any of the polylines for this segment
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
315
|
+
const isInside = containsPoint(projectedPolyline, point2D, {
|
|
316
|
+
holes,
|
|
317
|
+
});
|
|
318
|
+
|
|
319
|
+
return isInside;
|
|
286
320
|
},
|
|
287
321
|
({ pointIJK }) => {
|
|
288
322
|
segmentationVoxelManager.setAtIJKPoint(pointIJK, index);
|