@kitware/vtk.js 34.7.0 → 34.8.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.
@@ -60,6 +60,19 @@ export function pointInPolygon(
60
60
  normal: Vector3
61
61
  ): PolygonIntersectionState;
62
62
 
63
+ /**
64
+ * Compute the centroid of a polygon.
65
+ * @param {Array<number>} poly - Array of point indices for the polygon
66
+ * @param {vtkPoints} points - vtkPoints instance
67
+ * @param {Vector3} [centroid] - Optional output array (length 3)
68
+ * @returns {Vector3} The centroid as [x, y, z]
69
+ */
70
+ export function computeCentroid(
71
+ poly: Array<number>,
72
+ points: TypedArray,
73
+ centroid?: Vector3
74
+ ): Vector3;
75
+
63
76
  /**
64
77
  * Method used to decorate a given object (publicAPI+model) with vtkPolygon characteristics.
65
78
  *
@@ -187,6 +187,32 @@ function getNormal(poly, points, normal) {
187
187
  return normalize(normal);
188
188
  }
189
189
 
190
+ /**
191
+ * Compute the centroid of a polygon.
192
+ * @param {Array<number>} poly - Array of point indices for the polygon
193
+ * @param {vtkPoints} points - vtkPoints instance
194
+ * @param {Vector3} [centroid] - Optional output array (length 3)
195
+ * @returns {Vector3} The centroid as [x, y, z]
196
+ */
197
+ function computeCentroid(poly, points) {
198
+ let centroid = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : [0, 0, 0];
199
+ centroid[0] = 0;
200
+ centroid[1] = 0;
201
+ centroid[2] = 0;
202
+ const n = poly.length;
203
+ const p = [];
204
+ for (let i = 0; i < n; i++) {
205
+ points.getPoint(poly[i], p);
206
+ centroid[0] += p[0];
207
+ centroid[1] += p[1];
208
+ centroid[2] += p[2];
209
+ }
210
+ centroid[0] /= n;
211
+ centroid[1] /= n;
212
+ centroid[2] /= n;
213
+ return centroid;
214
+ }
215
+
190
216
  // ----------------------------------------------------------------------------
191
217
  // Static API
192
218
  // ----------------------------------------------------------------------------
@@ -195,7 +221,8 @@ const STATIC = {
195
221
  PolygonWithPointIntersectionState,
196
222
  pointInPolygon,
197
223
  getBounds,
198
- getNormal
224
+ getNormal,
225
+ computeCentroid
199
226
  };
200
227
 
201
228
  // ----------------------------------------------------------------------------
@@ -384,4 +411,4 @@ var vtkPolygon$1 = {
384
411
  ...STATIC
385
412
  };
386
413
 
387
- export { vtkPolygon$1 as default, extend, getBounds, getNormal, newInstance };
414
+ export { computeCentroid, vtkPolygon$1 as default, extend, getBounds, getNormal, newInstance };
@@ -0,0 +1,85 @@
1
+ import { DesiredOutputPrecision } from './../../Common/DataModel/DataSetAttributes';
2
+ import { vtkAlgorithm, vtkObject } from './../../interfaces';
3
+ import { Vector3 } from './../../types';
4
+
5
+ /**
6
+ *
7
+ */
8
+ export interface IShrinkPolyDataInitialValues {
9
+ shrinkFactor?: number;
10
+ }
11
+
12
+ type vtkShrinkPolyDataBase = vtkObject & vtkAlgorithm;
13
+
14
+ export interface vtkShrinkPolyData extends vtkShrinkPolyDataBase {
15
+ /**
16
+ * Expose methods
17
+ * @param inData
18
+ * @param outData
19
+ */
20
+ requestData(inData: any, outData: any): void;
21
+
22
+ /**
23
+ * Get the shrink factor.
24
+ */
25
+ getShrinkFactor(): number;
26
+
27
+ /**
28
+ * Set the shrink factor.
29
+ * @param {Number} shrinkFactor
30
+ */
31
+ setShrinkFactor(shrinkFactor: number): boolean;
32
+
33
+ /**
34
+ * Shrink two points towards their midpoint by a shrink factor.
35
+ * @param {Vector3} p1 - The [x, y, z] coordinates of the first point
36
+ * @param {Vector3} p2 - The [x, y, z] coordinates of the second point
37
+ * @param {number} shrinkFactor - The shrink factor (0.0 to 1.0)
38
+ * @param {Number[]} [shrunkPoints] - Optional array to store the shrunk points
39
+ * @returns {Number[]} Array containing the two new points
40
+ */
41
+ shrinkLine(
42
+ p1: Vector3,
43
+ p2: Vector3,
44
+ shrinkFactor: number,
45
+ shrunkPoints?: Number[]
46
+ ): Number[];
47
+ }
48
+
49
+ /**
50
+ * Method used to decorate a given object (publicAPI+model) with vtkShrinkPolyData characteristics.
51
+ *
52
+ * @param publicAPI object on which methods will be bounds (public)
53
+ * @param model object on which data structure will be bounds (protected)
54
+ * @param {IShrinkPolyDataInitialValues} [initialValues] (default: {})
55
+ */
56
+ export function extend(
57
+ publicAPI: object,
58
+ model: object,
59
+ initialValues?: IShrinkPolyDataInitialValues
60
+ ): void;
61
+
62
+ /**
63
+ * Method used to create a new instance of vtkShrinkPolyData.
64
+ * @param {IShrinkPolyDataInitialValues} [initialValues] for pre-setting some of its content
65
+ */
66
+ export function newInstance(
67
+ initialValues?: IShrinkPolyDataInitialValues
68
+ ): vtkShrinkPolyData;
69
+
70
+ /**
71
+ * vtkShrinkPolyData shrinks cells composing a polygonal dataset (e.g.,
72
+ * vertices, lines, polygons, and triangle strips) towards their centroid. The
73
+ * centroid of a cell is computed as the average position of the cell points.
74
+ * Shrinking results in disconnecting the cells from one another. The output
75
+ * dataset type of this filter is polygonal data.
76
+ *
77
+ * During execution the filter passes its input cell data to its output. Point
78
+ * data attributes are copied to the points created during the shrinking
79
+ * process.
80
+ */
81
+ export declare const vtkShrinkPolyData: {
82
+ newInstance: typeof newInstance;
83
+ extend: typeof extend;
84
+ };
85
+ export default vtkShrinkPolyData;
@@ -0,0 +1,317 @@
1
+ import { m as macro } from '../../macros2.js';
2
+ import vtkCellArray from '../../Common/Core/CellArray.js';
3
+ import vtkPolyData from '../../Common/DataModel/PolyData.js';
4
+ import vtkPoints from '../../Common/Core/Points.js';
5
+ import vtkPolygon from '../../Common/DataModel/Polygon.js';
6
+
7
+ const {
8
+ vtkErrorMacro
9
+ } = macro;
10
+
11
+ // ----------------------------------------------------------------------------
12
+ // vtkShrinkPolyData methods
13
+ // ----------------------------------------------------------------------------
14
+
15
+ function vtkShrinkPolyData(publicAPI, model) {
16
+ // Set our className
17
+ model.classHierarchy.push('vtkShrinkPolyData');
18
+
19
+ /**
20
+ * Shrink a point towards a given center by a shrink factor.
21
+ * @param {Vector3} point - The [x, y, z] coordinates of the point to shrink
22
+ * @param {Vector3} center - The [x, y, z] coordinates of the center
23
+ * @param {number} shrinkFactor - The shrink factor (0.0 to 1.0)
24
+ * @param {Vector3} [shrunkPoint] - Optional array to store the shrunk point
25
+ * @returns {Vector3} The shrunk point [x, y, z] coordinates
26
+ */
27
+ function shrinkTowardsPoint(point, center, shrinkFactor) {
28
+ let shrunkPoint = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : [];
29
+ shrunkPoint[0] = center[0] + shrinkFactor * (point[0] - center[0]);
30
+ shrunkPoint[1] = center[1] + shrinkFactor * (point[1] - center[1]);
31
+ shrunkPoint[2] = center[2] + shrinkFactor * (point[2] - center[2]);
32
+ return shrunkPoint;
33
+ }
34
+
35
+ /**
36
+ * Shrinks a cell towards its center by a shrink factor.
37
+ * @param {number[]} cellPointIds - Array of point indices that define the cell
38
+ * @param {vtkPoints} inPoints - Input points
39
+ * @param {number} shrinkFactor - The shrink factor (0.0 to 1.0)
40
+ * @param {Float32Array} newPointsData - Output array to store new point coordinates
41
+ * @param {number} outCount - Current index in the output points array
42
+ * @returns {Object} Object containing newPointIds array and updated outCount
43
+ */
44
+ function shrinkCell(cellPointIds, inPoints, shrinkFactor, newPointsData, outCount) {
45
+ const inPts = inPoints.getData();
46
+ const center = [0, 0, 0];
47
+ const newPointIds = [];
48
+ const shrunkPoint = [0, 0, 0];
49
+ const currentPoint = [0, 0, 0];
50
+ let nextOutCount = outCount;
51
+ const numPoints = cellPointIds.length;
52
+ if (numPoints === 0) {
53
+ return {
54
+ newPointIds,
55
+ outCount: nextOutCount
56
+ };
57
+ }
58
+ if (numPoints === 1) {
59
+ // vertex - no shrinking needed, just copy the point
60
+ const ptId = cellPointIds[0];
61
+ newPointsData[nextOutCount * 3] = inPts[ptId * 3];
62
+ newPointsData[nextOutCount * 3 + 1] = inPts[ptId * 3 + 1];
63
+ newPointsData[nextOutCount * 3 + 2] = inPts[ptId * 3 + 2];
64
+ newPointIds.push(nextOutCount);
65
+ nextOutCount++;
66
+ } else if (numPoints === 2) {
67
+ // line - shrink towards midpoint
68
+
69
+ // Calculate midpoint as center
70
+ vtkPolygon.computeCentroid(cellPointIds, inPoints, center);
71
+
72
+ // Shrink both points towards center
73
+ for (let i = 0; i < 2; i++) {
74
+ const ptId = cellPointIds[i];
75
+ currentPoint[0] = inPts[ptId * 3];
76
+ currentPoint[1] = inPts[ptId * 3 + 1];
77
+ currentPoint[2] = inPts[ptId * 3 + 2];
78
+ shrinkTowardsPoint(currentPoint, center, shrinkFactor, shrunkPoint);
79
+ newPointsData[nextOutCount * 3] = shrunkPoint[0];
80
+ newPointsData[nextOutCount * 3 + 1] = shrunkPoint[1];
81
+ newPointsData[nextOutCount * 3 + 2] = shrunkPoint[2];
82
+ newPointIds.push(nextOutCount);
83
+ nextOutCount++;
84
+ }
85
+ } else {
86
+ // polygon/triangle - shrink towards centroid
87
+ vtkPolygon.computeCentroid(cellPointIds, inPoints, center);
88
+
89
+ // Shrink each point towards centroid
90
+ for (let i = 0; i < numPoints; i++) {
91
+ const ptId = cellPointIds[i];
92
+ currentPoint[0] = inPts[ptId * 3];
93
+ currentPoint[1] = inPts[ptId * 3 + 1];
94
+ currentPoint[2] = inPts[ptId * 3 + 2];
95
+ shrinkTowardsPoint(currentPoint, center, shrinkFactor, shrunkPoint);
96
+ newPointsData[nextOutCount * 3] = shrunkPoint[0];
97
+ newPointsData[nextOutCount * 3 + 1] = shrunkPoint[1];
98
+ newPointsData[nextOutCount * 3 + 2] = shrunkPoint[2];
99
+ newPointIds.push(nextOutCount);
100
+ nextOutCount++;
101
+ }
102
+ }
103
+ return {
104
+ newPointIds,
105
+ outCount: nextOutCount
106
+ };
107
+ }
108
+
109
+ // Internal method to process the shrinking
110
+ function shrinkData(input, output) {
111
+ const inPoints = input.getPoints();
112
+ const inVerts = input.getVerts();
113
+ const inLines = input.getLines();
114
+ const inPolys = input.getPolys();
115
+ const inStrips = input.getStrips();
116
+ const shrinkFactor = model.shrinkFactor;
117
+ let numNewPts = 0;
118
+ if (inVerts) {
119
+ const cellSizes = inVerts.getCellSizes();
120
+ for (let i = 0; i < cellSizes.length; i++) {
121
+ numNewPts += cellSizes[i];
122
+ }
123
+ }
124
+ if (inLines) {
125
+ const cellSizes = inLines.getCellSizes();
126
+ for (let i = 0; i < cellSizes.length; i++) {
127
+ numNewPts += (cellSizes[i] - 1) * 2;
128
+ }
129
+ }
130
+ if (inPolys) {
131
+ const cellSizes = inPolys.getCellSizes();
132
+ for (let i = 0; i < cellSizes.length; i++) {
133
+ numNewPts += cellSizes[i];
134
+ }
135
+ }
136
+ if (inStrips) {
137
+ const cellSizes = inStrips.getCellSizes();
138
+ for (let i = 0; i < cellSizes.length; i++) {
139
+ numNewPts += (cellSizes[i] - 2) * 3;
140
+ }
141
+ }
142
+ const newPointsData = new Float32Array(numNewPts * 3);
143
+ const newPoints = vtkPoints.newInstance();
144
+ newPoints.setData(newPointsData, 3);
145
+ const newVerts = vtkCellArray.newInstance();
146
+ const newLines = vtkCellArray.newInstance();
147
+ const newPolys = vtkCellArray.newInstance();
148
+ let outCount = 0;
149
+
150
+ // Process vertices
151
+ if (inVerts) {
152
+ const vertData = inVerts.getData();
153
+ const newVertData = [];
154
+ const cellPointIds = [];
155
+ for (let i = 0; i < vertData.length;) {
156
+ cellPointIds.length = 0; // Clear previous point IDs
157
+ const npts = vertData[i];
158
+ for (let j = 1; j <= npts; j++) {
159
+ cellPointIds.push(vertData[i + j]);
160
+ }
161
+ const result = shrinkCell(cellPointIds, inPoints, shrinkFactor, newPointsData, outCount);
162
+ outCount = result.outCount;
163
+ newVertData.push(npts);
164
+ newVertData.push(...result.newPointIds);
165
+ i += npts + 1;
166
+ }
167
+ newVerts.setData(new Uint32Array(newVertData));
168
+ }
169
+
170
+ // Process lines
171
+ if (inLines) {
172
+ const lineData = inLines.getData();
173
+ const newLineData = [];
174
+ for (let i = 0; i < lineData.length;) {
175
+ const npts = lineData[i];
176
+
177
+ // Process each line segment
178
+ for (let j = 0; j < npts - 1; j++) {
179
+ const cellPointIds = [lineData[i + j + 1], lineData[i + j + 2]];
180
+ const result = shrinkCell(cellPointIds, inPoints, shrinkFactor, newPointsData, outCount);
181
+ outCount = result.outCount;
182
+ newLineData.push(2, result.newPointIds[0], result.newPointIds[1]);
183
+ }
184
+ i += npts + 1;
185
+ }
186
+ newLines.setData(new Uint32Array(newLineData));
187
+ }
188
+
189
+ // Process polygons
190
+ if (inPolys) {
191
+ const polyData = inPolys.getData();
192
+ const newPolyData = [];
193
+ const cellPointIds = [];
194
+ for (let i = 0; i < polyData.length;) {
195
+ cellPointIds.length = 0; // Clear previous point IDs
196
+ const npts = polyData[i];
197
+ for (let j = 1; j <= npts; j++) {
198
+ cellPointIds.push(polyData[i + j]);
199
+ }
200
+ const result = shrinkCell(cellPointIds, inPoints, shrinkFactor, newPointsData, outCount);
201
+ outCount = result.outCount;
202
+ newPolyData.push(npts);
203
+ newPolyData.push(...result.newPointIds);
204
+ i += npts + 1;
205
+ }
206
+ newPolys.setData(new Uint32Array(newPolyData));
207
+ }
208
+
209
+ // Process triangle strips (convert to triangles and shrink)
210
+ if (inStrips) {
211
+ const stripData = inStrips.getData();
212
+ const newPolyData = [];
213
+ for (let i = 0; i < stripData.length;) {
214
+ const npts = stripData[i];
215
+ for (let j = 0; j < npts - 2; j++) {
216
+ const cellPointIds = [stripData[i + j + 1], stripData[i + j + 2], stripData[i + j + 3]];
217
+ const result = shrinkCell(cellPointIds, inPoints, shrinkFactor, newPointsData, outCount);
218
+ outCount = result.outCount;
219
+
220
+ // Triangle strips alternate the winding order of each triangle as you
221
+ // move along the strip. This means that the orientation
222
+ // (clockwise/counter-clockwise) flips for every new triangle. To
223
+ // ensure consistent face orientation (so normals and rendering are
224
+ // correct), we reverse the vertex order for every odd triangle.
225
+ // Example strip with vertices [0,1,2,3,4,5] produces these triangles:
226
+ //
227
+ // 0───2───4 Triangle 0: (0,1,2) [CCW]
228
+ // │ ╱ │ ╱ │ Triangle 1: (1,3,2) [CW -> reversed to (2,3,1) for CCW]
229
+ // │╱ │╱ │ Triangle 2: (2,3,4) [CCW]
230
+ // 1───3───5 Triangle 3: (3,5,4) [CW -> reversed to (4,5,3) for CCW]
231
+ const newIds = [...result.newPointIds];
232
+ if (j % 2) {
233
+ const tmp = newIds[0];
234
+ newIds[0] = newIds[2];
235
+ newIds[2] = tmp;
236
+ }
237
+ newPolyData.push(3, newIds[0], newIds[1], newIds[2]);
238
+ }
239
+ i += npts + 1;
240
+ }
241
+ if (newPolyData.length > 0) {
242
+ const existingPolyData = newPolys.getData();
243
+ const combinedPolyData = new Uint32Array(existingPolyData.length + newPolyData.length);
244
+ combinedPolyData.set(existingPolyData);
245
+ combinedPolyData.set(newPolyData, existingPolyData.length);
246
+ newPolys.setData(combinedPolyData);
247
+ }
248
+ }
249
+
250
+ // Set output
251
+ output.setPoints(newPoints);
252
+ output.setVerts(newVerts);
253
+ output.setLines(newLines);
254
+ output.setPolys(newPolys);
255
+
256
+ // Copy cell data
257
+ output.getCellData().passData(input.getCellData());
258
+ }
259
+ publicAPI.requestData = (inData, outData) => {
260
+ const input = inData[0];
261
+ const output = outData[0] || vtkPolyData.newInstance();
262
+ if (!input) {
263
+ vtkErrorMacro('No input!');
264
+ return;
265
+ }
266
+ if (!input.getPoints()) {
267
+ vtkErrorMacro('Input has no points!');
268
+ return;
269
+ }
270
+ shrinkData(input, output);
271
+ outData[0] = output;
272
+ };
273
+
274
+ // Set the shrink factor
275
+ publicAPI.setShrinkFactor = shrinkFactor => {
276
+ if (shrinkFactor !== model.shrinkFactor) {
277
+ model.shrinkFactor = Math.max(0.0, Math.min(1.0, shrinkFactor));
278
+ publicAPI.modified();
279
+ }
280
+ };
281
+ }
282
+
283
+ // ----------------------------------------------------------------------------
284
+ // Object factory
285
+ // ----------------------------------------------------------------------------
286
+
287
+ const DEFAULT_VALUES = {
288
+ shrinkFactor: 0.5
289
+ };
290
+
291
+ // ----------------------------------------------------------------------------
292
+
293
+ function extend(publicAPI, model) {
294
+ let initialValues = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
295
+ Object.assign(model, DEFAULT_VALUES, initialValues);
296
+
297
+ // Build VTK API
298
+ macro.obj(publicAPI, model);
299
+
300
+ // Also make it an algorithm with one input and one output
301
+ macro.algo(publicAPI, model, 1, 1);
302
+ macro.setGet(publicAPI, model, ['shrinkFactor']);
303
+ vtkShrinkPolyData(publicAPI, model);
304
+ }
305
+
306
+ // ----------------------------------------------------------------------------
307
+
308
+ const newInstance = macro.newInstance(extend, 'vtkShrinkPolyData');
309
+
310
+ // ----------------------------------------------------------------------------
311
+
312
+ var vtkShrinkPolyData$1 = {
313
+ newInstance,
314
+ extend
315
+ };
316
+
317
+ export { vtkShrinkPolyData$1 as default, extend, newInstance };
@@ -15,6 +15,7 @@ import vtkOBBTree from './General/OBBTree.js';
15
15
  import vtkOutlineFilter from './General/OutlineFilter.js';
16
16
  import vtkPaintFilter from './General/PaintFilter.js';
17
17
  import vtkScalarToRGBA from './General/ScalarToRGBA.js';
18
+ import vtkShrinkPolyData from './General/ShrinkPolyData.js';
18
19
  import vtkTransformPolyDataFilter from './General/TransformPolyDataFilter.js';
19
20
  import vtkTriangleFilter from './General/TriangleFilter.js';
20
21
  import vtkTubeFilter from './General/TubeFilter.js';
@@ -39,6 +40,7 @@ var General = {
39
40
  vtkOutlineFilter,
40
41
  vtkPaintFilter,
41
42
  vtkScalarToRGBA,
43
+ vtkShrinkPolyData,
42
44
  vtkTransformPolyDataFilter,
43
45
  vtkTriangleFilter,
44
46
  vtkTubeFilter,