@cornerstonejs/tools 1.22.1 → 1.23.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.
Files changed (117) hide show
  1. package/dist/cjs/drawingSvg/drawPolyline.d.ts +2 -0
  2. package/dist/cjs/drawingSvg/drawPolyline.js +5 -2
  3. package/dist/cjs/drawingSvg/drawPolyline.js.map +1 -1
  4. package/dist/cjs/enums/SegmentationRepresentations.d.ts +2 -1
  5. package/dist/cjs/enums/SegmentationRepresentations.js +1 -0
  6. package/dist/cjs/enums/SegmentationRepresentations.js.map +1 -1
  7. package/dist/cjs/index.d.ts +2 -2
  8. package/dist/cjs/index.js +3 -2
  9. package/dist/cjs/index.js.map +1 -1
  10. package/dist/cjs/stateManagement/segmentation/addSegmentationRepresentations.js +5 -0
  11. package/dist/cjs/stateManagement/segmentation/addSegmentationRepresentations.js.map +1 -1
  12. package/dist/cjs/tools/SegmentationIntersectionTool.d.ts +18 -0
  13. package/dist/cjs/tools/SegmentationIntersectionTool.js +184 -0
  14. package/dist/cjs/tools/SegmentationIntersectionTool.js.map +1 -0
  15. package/dist/cjs/tools/displayTools/Contour/addContourSetsToElement.js.map +1 -1
  16. package/dist/cjs/tools/displayTools/SegmentationDisplayTool.js +7 -3
  17. package/dist/cjs/tools/displayTools/SegmentationDisplayTool.js.map +1 -1
  18. package/dist/cjs/tools/displayTools/Surface/addSurfaceToElement.d.ts +2 -0
  19. package/dist/cjs/tools/displayTools/Surface/addSurfaceToElement.js +84 -0
  20. package/dist/cjs/tools/displayTools/Surface/addSurfaceToElement.js.map +1 -0
  21. package/dist/cjs/tools/displayTools/Surface/index.d.ts +2 -0
  22. package/dist/cjs/tools/displayTools/Surface/index.js +9 -0
  23. package/dist/cjs/tools/displayTools/Surface/index.js.map +1 -0
  24. package/dist/cjs/tools/displayTools/Surface/removeSurfaceFromElement.d.ts +2 -0
  25. package/dist/cjs/tools/displayTools/Surface/removeSurfaceFromElement.js +14 -0
  26. package/dist/cjs/tools/displayTools/Surface/removeSurfaceFromElement.js.map +1 -0
  27. package/dist/cjs/tools/displayTools/Surface/surfaceDisplay.d.ts +11 -0
  28. package/dist/cjs/tools/displayTools/Surface/surfaceDisplay.js +140 -0
  29. package/dist/cjs/tools/displayTools/Surface/surfaceDisplay.js.map +1 -0
  30. package/dist/cjs/tools/index.d.ts +2 -1
  31. package/dist/cjs/tools/index.js +3 -1
  32. package/dist/cjs/tools/index.js.map +1 -1
  33. package/dist/cjs/types/SegmentationStateTypes.d.ts +9 -1
  34. package/dist/cjs/types/SurfaceTypes.d.ts +4 -0
  35. package/dist/cjs/types/SurfaceTypes.js +3 -0
  36. package/dist/cjs/types/SurfaceTypes.js.map +1 -0
  37. package/dist/cjs/utilities/index.d.ts +3 -1
  38. package/dist/cjs/utilities/index.js +5 -1
  39. package/dist/cjs/utilities/index.js.map +1 -1
  40. package/dist/cjs/utilities/math/point/distanceToPoint.d.ts +3 -1
  41. package/dist/cjs/utilities/math/point/distanceToPoint.js +5 -5
  42. package/dist/cjs/utilities/math/point/distanceToPoint.js.map +1 -1
  43. package/dist/cjs/utilities/pointToString.d.ts +1 -0
  44. package/dist/cjs/utilities/pointToString.js +13 -0
  45. package/dist/cjs/utilities/pointToString.js.map +1 -0
  46. package/dist/cjs/utilities/polyData/utils.d.ts +4 -0
  47. package/dist/cjs/utilities/polyData/utils.js +58 -0
  48. package/dist/cjs/utilities/polyData/utils.js.map +1 -0
  49. package/dist/esm/drawingSvg/drawPolyline.d.ts +2 -0
  50. package/dist/esm/drawingSvg/drawPolyline.js +5 -2
  51. package/dist/esm/drawingSvg/drawPolyline.js.map +1 -1
  52. package/dist/esm/enums/SegmentationRepresentations.d.ts +2 -1
  53. package/dist/esm/enums/SegmentationRepresentations.js +1 -0
  54. package/dist/esm/enums/SegmentationRepresentations.js.map +1 -1
  55. package/dist/esm/index.d.ts +2 -2
  56. package/dist/esm/index.js +2 -2
  57. package/dist/esm/index.js.map +1 -1
  58. package/dist/esm/stateManagement/segmentation/addSegmentationRepresentations.js +5 -0
  59. package/dist/esm/stateManagement/segmentation/addSegmentationRepresentations.js.map +1 -1
  60. package/dist/esm/tools/SegmentationIntersectionTool.d.ts +18 -0
  61. package/dist/esm/tools/SegmentationIntersectionTool.js +177 -0
  62. package/dist/esm/tools/SegmentationIntersectionTool.js.map +1 -0
  63. package/dist/esm/tools/displayTools/Contour/addContourSetsToElement.js.map +1 -1
  64. package/dist/esm/tools/displayTools/SegmentationDisplayTool.js +7 -3
  65. package/dist/esm/tools/displayTools/SegmentationDisplayTool.js.map +1 -1
  66. package/dist/esm/tools/displayTools/Surface/addSurfaceToElement.d.ts +2 -0
  67. package/dist/esm/tools/displayTools/Surface/addSurfaceToElement.js +79 -0
  68. package/dist/esm/tools/displayTools/Surface/addSurfaceToElement.js.map +1 -0
  69. package/dist/esm/tools/displayTools/Surface/index.d.ts +2 -0
  70. package/dist/esm/tools/displayTools/Surface/index.js +3 -0
  71. package/dist/esm/tools/displayTools/Surface/index.js.map +1 -0
  72. package/dist/esm/tools/displayTools/Surface/removeSurfaceFromElement.d.ts +2 -0
  73. package/dist/esm/tools/displayTools/Surface/removeSurfaceFromElement.js +12 -0
  74. package/dist/esm/tools/displayTools/Surface/removeSurfaceFromElement.js.map +1 -0
  75. package/dist/esm/tools/displayTools/Surface/surfaceDisplay.d.ts +11 -0
  76. package/dist/esm/tools/displayTools/Surface/surfaceDisplay.js +101 -0
  77. package/dist/esm/tools/displayTools/Surface/surfaceDisplay.js.map +1 -0
  78. package/dist/esm/tools/index.d.ts +2 -1
  79. package/dist/esm/tools/index.js +2 -1
  80. package/dist/esm/tools/index.js.map +1 -1
  81. package/dist/esm/types/SegmentationStateTypes.d.ts +9 -1
  82. package/dist/esm/types/SurfaceTypes.d.ts +4 -0
  83. package/dist/esm/types/SurfaceTypes.js +2 -0
  84. package/dist/esm/types/SurfaceTypes.js.map +1 -0
  85. package/dist/esm/utilities/index.d.ts +3 -1
  86. package/dist/esm/utilities/index.js +3 -1
  87. package/dist/esm/utilities/index.js.map +1 -1
  88. package/dist/esm/utilities/math/point/distanceToPoint.d.ts +3 -1
  89. package/dist/esm/utilities/math/point/distanceToPoint.js +5 -5
  90. package/dist/esm/utilities/math/point/distanceToPoint.js.map +1 -1
  91. package/dist/esm/utilities/pointToString.d.ts +1 -0
  92. package/dist/esm/utilities/pointToString.js +9 -0
  93. package/dist/esm/utilities/pointToString.js.map +1 -0
  94. package/dist/esm/utilities/polyData/utils.d.ts +4 -0
  95. package/dist/esm/utilities/polyData/utils.js +52 -0
  96. package/dist/esm/utilities/polyData/utils.js.map +1 -0
  97. package/dist/umd/index.js +1 -1
  98. package/dist/umd/index.js.map +1 -1
  99. package/package.json +4 -4
  100. package/src/drawingSvg/drawPolyline.ts +17 -11
  101. package/src/enums/SegmentationRepresentations.ts +1 -1
  102. package/src/index.ts +2 -0
  103. package/src/stateManagement/segmentation/addSegmentationRepresentations.ts +8 -0
  104. package/src/tools/SegmentationIntersectionTool.ts +300 -0
  105. package/src/tools/displayTools/Contour/addContourSetsToElement.ts +1 -1
  106. package/src/tools/displayTools/SegmentationDisplayTool.ts +10 -4
  107. package/src/tools/displayTools/Surface/addSurfaceToElement.ts +115 -0
  108. package/src/tools/displayTools/Surface/index.ts +3 -0
  109. package/src/tools/displayTools/Surface/removeSurfaceFromElement.ts +35 -0
  110. package/src/tools/displayTools/Surface/surfaceDisplay.ts +215 -0
  111. package/src/tools/index.ts +2 -0
  112. package/src/types/SegmentationStateTypes.ts +18 -1
  113. package/src/types/SurfaceTypes.ts +10 -0
  114. package/src/utilities/index.ts +4 -0
  115. package/src/utilities/math/point/distanceToPoint.ts +12 -11
  116. package/src/utilities/pointToString.ts +10 -0
  117. package/src/utilities/polyData/utils.ts +82 -0
@@ -0,0 +1,215 @@
1
+ import {
2
+ cache,
3
+ getEnabledElementByIds,
4
+ Types,
5
+ utilities,
6
+ Enums,
7
+ } from '@cornerstonejs/core';
8
+
9
+ import * as SegmentationState from '../../../stateManagement/segmentation/segmentationState';
10
+ import * as SegmentationConfig from '../../../stateManagement/segmentation/config/segmentationConfig';
11
+ import Representations from '../../../enums/SegmentationRepresentations';
12
+ import { getToolGroup } from '../../../store/ToolGroupManager';
13
+ import {
14
+ RepresentationPublicInput,
15
+ SegmentationRepresentationConfig,
16
+ ToolGroupSpecificRepresentation,
17
+ } from '../../../types/SegmentationStateTypes';
18
+
19
+ import removeSurfaceFromElement from './removeSurfaceFromElement';
20
+ import addSurfaceToElement from './addSurfaceToElement';
21
+
22
+ /**
23
+ * It adds a new segmentation representation to the segmentation state
24
+ * @param toolGroupId - The id of the toolGroup that the segmentation
25
+ * belongs to
26
+ * @param representationInput - RepresentationPublicInput
27
+ * @param toolGroupSpecificConfig - The configuration that is specific to the toolGroup.
28
+ * @returns The segmentationRepresentationUID
29
+ */
30
+ async function addSegmentationRepresentation(
31
+ toolGroupId: string,
32
+ representationInput: RepresentationPublicInput,
33
+ toolGroupSpecificConfig?: SegmentationRepresentationConfig
34
+ ): Promise<string> {
35
+ const { segmentationId } = representationInput;
36
+ const segmentationRepresentationUID = utilities.uuidv4();
37
+ // Todo: make these configurable during representation input by user
38
+ const segmentsHidden = new Set() as Set<number>;
39
+ const colorLUTIndex = 0;
40
+ const active = true;
41
+ const toolGroupSpecificRepresentation: ToolGroupSpecificRepresentation = {
42
+ segmentationId,
43
+ segmentationRepresentationUID,
44
+ type: Representations.Surface,
45
+ segmentsHidden,
46
+ colorLUTIndex,
47
+ active,
48
+ segmentationRepresentationSpecificConfig: {},
49
+ segmentSpecificConfig: {},
50
+ config: {},
51
+ };
52
+ // Update the toolGroup specific configuration
53
+ if (toolGroupSpecificConfig) {
54
+ // Since setting configuration on toolGroup will trigger a segmentationRepresentation
55
+ // update event, we don't want to trigger the event twice, so we suppress
56
+ // the first one
57
+ const currentToolGroupConfig =
58
+ SegmentationConfig.getToolGroupSpecificConfig(toolGroupId);
59
+ const mergedConfig = utilities.deepMerge(
60
+ currentToolGroupConfig,
61
+ toolGroupSpecificConfig
62
+ );
63
+ SegmentationConfig.setToolGroupSpecificConfig(toolGroupId, {
64
+ renderInactiveSegmentations:
65
+ mergedConfig.renderInactiveSegmentations || true,
66
+ representations: {
67
+ ...mergedConfig.representations,
68
+ },
69
+ });
70
+ }
71
+ SegmentationState.addSegmentationRepresentation(
72
+ toolGroupId,
73
+ toolGroupSpecificRepresentation
74
+ );
75
+ return segmentationRepresentationUID;
76
+ }
77
+
78
+ /**
79
+ * It removes a segmentation representation from the tool group's viewports and
80
+ * from the segmentation state
81
+ * @param toolGroupId - The toolGroupId of the toolGroup that the
82
+ * segmentationRepresentation belongs to.
83
+ * @param segmentationRepresentationUID - This is the unique identifier
84
+ * for the segmentation representation.
85
+ * @param renderImmediate - If true, the viewport will be rendered
86
+ * immediately after the segmentation representation is removed.
87
+ */
88
+ function removeSegmentationRepresentation(
89
+ toolGroupId: string,
90
+ segmentationRepresentationUID: string,
91
+ renderImmediate = false
92
+ ): void {
93
+ _removeSurfaceFromToolGroupViewports(
94
+ toolGroupId,
95
+ segmentationRepresentationUID
96
+ );
97
+ SegmentationState.removeSegmentationRepresentation(
98
+ toolGroupId,
99
+ segmentationRepresentationUID
100
+ );
101
+
102
+ if (renderImmediate) {
103
+ const viewportsInfo = getToolGroup(toolGroupId).getViewportsInfo();
104
+ viewportsInfo.forEach(({ viewportId, renderingEngineId }) => {
105
+ const enabledElement = getEnabledElementByIds(
106
+ viewportId,
107
+ renderingEngineId
108
+ );
109
+ enabledElement.viewport.render();
110
+ });
111
+ }
112
+ }
113
+
114
+ /**
115
+ * It renders the Surface for the given segmentation
116
+ * @param viewport - The viewport object
117
+ * @param representation - ToolGroupSpecificRepresentation
118
+ * @param toolGroupConfig - This is the configuration object for the tool group
119
+ */
120
+ async function render(
121
+ viewport: Types.IVolumeViewport,
122
+ representation: ToolGroupSpecificRepresentation,
123
+ toolGroupConfig: SegmentationRepresentationConfig
124
+ ): Promise<void> {
125
+ const {
126
+ colorLUTIndex,
127
+ active,
128
+ segmentationId,
129
+ segmentationRepresentationUID,
130
+ segmentsHidden,
131
+ } = representation;
132
+
133
+ const segmentation = SegmentationState.getSegmentation(segmentationId);
134
+ const SurfaceData = segmentation.representationData[Representations.Surface];
135
+ const { geometryId } = SurfaceData;
136
+
137
+ if (!geometryId) {
138
+ console.warn(
139
+ `No Surfaces found for segmentationId ${segmentationId}. Skipping render.`
140
+ );
141
+ }
142
+
143
+ const geometry = cache.getGeometry(geometryId);
144
+ if (!geometry) {
145
+ throw new Error(`No Surfaces found for geometryId ${geometryId}`);
146
+ }
147
+
148
+ if (geometry.type !== Enums.GeometryType.SURFACE) {
149
+ // Todo: later we can support converting other geometries to Surfaces
150
+ throw new Error(
151
+ `Geometry type ${geometry.type} not supported for rendering.`
152
+ );
153
+ }
154
+
155
+ if (!geometry.data) {
156
+ console.warn(
157
+ `No Surfaces found for geometryId ${geometryId}. Skipping render.`
158
+ );
159
+ return;
160
+ }
161
+
162
+ const surface = geometry.data;
163
+
164
+ const surfaceUID = `${segmentationRepresentationUID}_${surface.id}}`;
165
+ _renderSurface(viewport, surface, surfaceUID);
166
+
167
+ viewport.resetCamera();
168
+ viewport.render();
169
+ }
170
+
171
+ function _renderSurface(
172
+ viewport: Types.IVolumeViewport,
173
+ surface: any,
174
+ surfaceUID: string
175
+ ): void {
176
+ const actorUID = surfaceUID;
177
+ const actorEntry = viewport.getActor(actorUID);
178
+
179
+ if (!actorEntry) {
180
+ addSurfaceToElement(viewport.element, surface, actorUID);
181
+ } else {
182
+ throw new Error('Not implemented yet. (Update surface)');
183
+ }
184
+ }
185
+
186
+ function _removeSurfaceFromToolGroupViewports(
187
+ toolGroupId: string,
188
+ segmentationRepresentationUID: string
189
+ ): void {
190
+ const toolGroup = getToolGroup(toolGroupId);
191
+
192
+ if (toolGroup === undefined) {
193
+ throw new Error(`ToolGroup with ToolGroupId ${toolGroupId} does not exist`);
194
+ }
195
+
196
+ const { viewportsInfo } = toolGroup;
197
+
198
+ for (const viewportInfo of viewportsInfo) {
199
+ const { viewportId, renderingEngineId } = viewportInfo;
200
+ const enabledElement = getEnabledElementByIds(
201
+ viewportId,
202
+ renderingEngineId
203
+ );
204
+ removeSurfaceFromElement(
205
+ enabledElement.viewport.element,
206
+ segmentationRepresentationUID
207
+ );
208
+ }
209
+ }
210
+
211
+ export default {
212
+ render,
213
+ addSegmentationRepresentation,
214
+ removeSegmentationRepresentation,
215
+ };
@@ -13,6 +13,7 @@ import MagnifyTool from './MagnifyTool';
13
13
  import AdvancedMagnifyTool from './AdvancedMagnifyTool';
14
14
  import ReferenceLinesTool from './ReferenceLinesTool';
15
15
  import OverlayGridTool from './OverlayGridTool';
16
+ import SegmentationIntersectionTool from './SegmentationIntersectionTool';
16
17
  //
17
18
  import BidirectionalTool from './annotation/BidirectionalTool';
18
19
  import LengthTool from './annotation/LengthTool';
@@ -62,6 +63,7 @@ export {
62
63
  CrosshairsTool,
63
64
  ReferenceLinesTool,
64
65
  OverlayGridTool,
66
+ SegmentationIntersectionTool,
65
67
  BidirectionalTool,
66
68
  LengthTool,
67
69
  ProbeTool,
@@ -9,6 +9,10 @@ import type {
9
9
  LabelmapRenderingConfig,
10
10
  LabelmapSegmentationData,
11
11
  } from './LabelmapTypes';
12
+ import {
13
+ SurfaceSegmentationData,
14
+ SurfaceRenderingConfig,
15
+ } from './SurfaceTypes';
12
16
 
13
17
  /**
14
18
  * Four elements RGBA as 0-255
@@ -30,6 +34,8 @@ export type RepresentationConfig = {
30
34
  LABELMAP?: LabelmapConfig;
31
35
  /** contour configuration */
32
36
  CONTOUR?: ContourConfig;
37
+ /** surface configuration */
38
+ SURFACE?: any;
33
39
  };
34
40
 
35
41
  export type SegmentationRepresentationConfig = {
@@ -42,6 +48,7 @@ export type SegmentationRepresentationConfig = {
42
48
  export type SegmentationRepresentationData = {
43
49
  LABELMAP?: LabelmapSegmentationData;
44
50
  CONTOUR?: ContourSegmentationData;
51
+ SURFACE?: SurfaceSegmentationData;
45
52
  };
46
53
 
47
54
  /**
@@ -132,6 +139,13 @@ export type ToolGroupSpecificContourRepresentation =
132
139
  segmentSpecificConfig?: SegmentSpecificRepresentationConfig;
133
140
  };
134
141
 
142
+ export type ToolGroupSpecificSurfaceRepresentation =
143
+ ToolGroupSpecificRepresentationState & {
144
+ config: SurfaceRenderingConfig;
145
+ segmentationRepresentationSpecificConfig?: RepresentationConfig;
146
+ segmentSpecificConfig?: SegmentSpecificRepresentationConfig;
147
+ };
148
+
135
149
  export type ToolGroupSpecificRepresentation =
136
150
  | ToolGroupSpecificLabelmapRepresentation
137
151
  | ToolGroupSpecificContourRepresentation;
@@ -252,7 +266,10 @@ export type SegmentationPublicInput = {
252
266
  segmentationId: string;
253
267
  representation: {
254
268
  type: Enums.SegmentationRepresentations;
255
- data: LabelmapSegmentationData | ContourSegmentationData;
269
+ data:
270
+ | LabelmapSegmentationData
271
+ | ContourSegmentationData
272
+ | SurfaceSegmentationData;
256
273
  };
257
274
  };
258
275
 
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Labelmap representation type
3
+ */
4
+ export type SurfaceRenderingConfig = {
5
+ // not much here yet
6
+ };
7
+
8
+ export type SurfaceSegmentationData = {
9
+ geometryId: string;
10
+ };
@@ -17,6 +17,7 @@ import pointInShapeCallback from './pointInShapeCallback';
17
17
  import pointInSurroundingSphereCallback from './pointInSurroundingSphereCallback';
18
18
  import scroll from './scroll';
19
19
  import roundNumber from './roundNumber';
20
+ import { pointToString } from './pointToString';
20
21
 
21
22
  // name spaces
22
23
  import * as segmentation from './segmentation';
@@ -33,6 +34,7 @@ import { stackPrefetch, stackContextPrefetch } from './stackPrefetch';
33
34
  import * as viewport from './viewport';
34
35
  import * as touch from './touch';
35
36
  import * as dynamicVolume from './dynamicVolume';
37
+ import * as polyDataUtils from './polyData/utils';
36
38
 
37
39
  // Events
38
40
  import { triggerEvent } from '@cornerstonejs/core';
@@ -68,4 +70,6 @@ export {
68
70
  stackContextPrefetch,
69
71
  scroll,
70
72
  roundNumber,
73
+ pointToString,
74
+ polyDataUtils,
71
75
  };
@@ -1,22 +1,23 @@
1
1
  import type { Types } from '@cornerstonejs/core';
2
2
 
3
+ type Point = Types.Point2 | Types.Point3;
4
+
3
5
  /**
4
6
  * Calculates the distance of a point to another point
5
7
  *
6
- * @param p1 - x,y of the point
7
- * @param p2 - x,y of the point
8
+ * @param p1 - x,y or x,y,z of the point
9
+ * @param p2 - x,y or x,y,z of the point
8
10
  * @returns distance
9
11
  */
10
- export default function distanceToPoint(
11
- p1: Types.Point2,
12
- p2: Types.Point2
13
- ): number {
14
- if (p1?.length !== 2 || p2?.length !== 2) {
15
- throw Error('points should have 2 elements of [x, y]');
12
+ export default function distanceToPoint(p1: Point, p2: Point): number {
13
+ if (p1.length !== p2.length) {
14
+ throw Error('Both points should have the same dimensionality');
16
15
  }
17
16
 
18
- const [x1, y1] = p1;
19
- const [x2, y2] = p2;
17
+ const [x1, y1, z1 = 0] = p1;
18
+ const [x2, y2, z2 = 0] = p2;
20
19
 
21
- return Math.sqrt(Math.pow(x1 - x2, 2) + Math.pow(y1 - y2, 2));
20
+ return Math.sqrt(
21
+ Math.pow(x1 - x2, 2) + Math.pow(y1 - y2, 2) + Math.pow(z1 - z2, 2)
22
+ );
22
23
  }
@@ -0,0 +1,10 @@
1
+ export function pointToString(point, decimals = 5) {
2
+ return (
3
+ parseFloat(point[0]).toFixed(decimals) +
4
+ ',' +
5
+ parseFloat(point[1]).toFixed(decimals) +
6
+ ',' +
7
+ parseFloat(point[2]).toFixed(decimals) +
8
+ ','
9
+ );
10
+ }
@@ -0,0 +1,82 @@
1
+ import vtkPolyData from '@kitware/vtk.js/Common/DataModel/PolyData';
2
+
3
+ /**
4
+ * Gets a point from an array of numbers given its index
5
+ * @param points array of number, each point defined by three consecutive numbers
6
+ * @param idx index of the point to retrieve
7
+ * @returns
8
+ */
9
+ export function getPoint(points, idx) {
10
+ if (idx < points.length / 3) {
11
+ return [points[idx * 3], points[idx * 3 + 1], points[idx * 3 + 2]];
12
+ }
13
+ }
14
+
15
+ /**
16
+ * Extract contour point sets from the outline of a poly data actor
17
+ * @param polyData - vtk polyData
18
+ * @returns
19
+ */
20
+ export function getPolyDataPointIndexes(polyData: vtkPolyData) {
21
+ const linesData = polyData.getLines().getData();
22
+ let idx = 0;
23
+ const lineSegments = new Map<number, number[]>();
24
+
25
+ // Populate lineSegments map
26
+ while (idx < linesData.length) {
27
+ const segmentSize = linesData[idx++];
28
+ const segment = [];
29
+ for (let i = 0; i < segmentSize; i++) {
30
+ segment.push(linesData[idx + i]);
31
+ }
32
+ lineSegments.set(segment[0], segment);
33
+ idx += segmentSize;
34
+ }
35
+
36
+ const contours = [];
37
+
38
+ // Function to find an available starting point
39
+ const findStartingPoint = (map) => {
40
+ for (const [key, value] of map.entries()) {
41
+ if (value !== undefined) {
42
+ return key;
43
+ }
44
+ }
45
+ return -1;
46
+ };
47
+
48
+ // Build contours
49
+ let startPoint = findStartingPoint(lineSegments);
50
+ while (startPoint !== -1) {
51
+ const contour = [startPoint];
52
+ while (lineSegments.has(startPoint)) {
53
+ const nextPoint = lineSegments.get(startPoint)[1];
54
+ if (lineSegments.has(nextPoint)) {
55
+ contour.push(nextPoint);
56
+ }
57
+ lineSegments.delete(startPoint);
58
+ startPoint = nextPoint;
59
+ }
60
+ contours.push(contour);
61
+ startPoint = findStartingPoint(lineSegments);
62
+ }
63
+
64
+ return contours.length ? contours : undefined;
65
+ }
66
+
67
+ /**
68
+ * Extract contour points from a poly data object
69
+ * @param polyData - vtk polyData
70
+ * @returns
71
+ */
72
+ export function getPolyDataPoints(polyData: vtkPolyData) {
73
+ const contoursIndexes = getPolyDataPointIndexes(polyData);
74
+ if (!contoursIndexes) {
75
+ return;
76
+ }
77
+
78
+ const rawPointsData = polyData.getPoints().getData();
79
+ return contoursIndexes.map((contourIndexes) =>
80
+ contourIndexes.map((index) => getPoint(rawPointsData, index))
81
+ );
82
+ }