@kitware/vtk.js 34.1.0 → 34.3.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.
@@ -0,0 +1,397 @@
1
+ import { m as macro } from '../../macros2.js';
2
+ import { s as subtract } from '../../Common/Core/Math/index.js';
3
+ import vtkPolyData from '../../Common/DataModel/PolyData.js';
4
+ import vtkDataArray from '../../Common/Core/DataArray.js';
5
+ import vtkCellArray from '../../Common/Core/CellArray.js';
6
+ import { isClockWise, getBoundingSize, triangulateShape, computeBevelVector, scalePoint, buildLidFaces, buildSideFaces, createShapePath } from './VectorText/Utils.js';
7
+
8
+ const {
9
+ vtkErrorMacro,
10
+ vtkWarningMacro
11
+ } = macro;
12
+
13
+ // ----------------------------------------------------------------------------
14
+ // vtkVectorText methods
15
+ // ----------------------------------------------------------------------------
16
+
17
+ function vtkVectorText(publicAPI, model) {
18
+ // Set our className
19
+ model.classHierarchy.push('vtkVectorText');
20
+
21
+ // -------------------------------------------------------------------------
22
+ // Private methods
23
+ // -------------------------------------------------------------------------
24
+
25
+ /**
26
+ * Process a shape into 3D geometry
27
+ * @param {Object} shape - The shape to process
28
+ * @param {Array} offsetSize - The offset size for positioning the shape
29
+ * @param {Array} letterColor - The color for the shape
30
+ */
31
+ function addShape(shape, offsetSize, letterColor) {
32
+ // extract contour + holes, offset them
33
+ const curveSegments = model.curveSegments;
34
+ const steps = model.steps;
35
+ const depth = model.depth;
36
+
37
+ // Calculate bevel parameters
38
+ const bevelEnabled = model.bevelEnabled;
39
+ let bevelThickness = model.bevelThickness;
40
+ let bevelSize = bevelThickness - 0.1;
41
+ let bevelOffset = model.bevelOffset;
42
+ let bevelSegments = model.bevelSegments;
43
+ if (!bevelEnabled) {
44
+ bevelSegments = 0;
45
+ bevelThickness = 0;
46
+ bevelSize = 0;
47
+ bevelOffset = 0;
48
+ }
49
+
50
+ // Extract points from shape
51
+ const shapePoints = shape.extractPoints(curveSegments);
52
+ let vertices = shapePoints.shape;
53
+ const holes = shapePoints.holes;
54
+
55
+ // Offset points to the correct position
56
+ vertices.forEach(p => {
57
+ p[0] += offsetSize[0];
58
+ p[1] += offsetSize[1];
59
+ });
60
+ holes.forEach(hole => {
61
+ hole.forEach(p => {
62
+ p[0] += offsetSize[0];
63
+ p[1] += offsetSize[1];
64
+ });
65
+ });
66
+
67
+ // Check if we have enough points to create a shape
68
+ if (vertices.length < 3) {
69
+ vtkWarningMacro('Not enough points to create a shape');
70
+ return;
71
+ }
72
+
73
+ // Triangulate the shape
74
+ const faces = triangulateShape(model.earcut, vertices, holes);
75
+ const contour = vertices;
76
+
77
+ // Combine all vertices (contour and holes)
78
+ vertices = [...vertices, ...holes.flat()];
79
+ const vlen = vertices.length;
80
+
81
+ // Calculate bevel vectors for the contour
82
+ const contourMovements = [];
83
+ for (let i = 0, j = contour.length - 1, k = i + 1; i < contour.length; i++, j++, k++) {
84
+ if (j === contour.length) j = 0;
85
+ if (k === contour.length) k = 0;
86
+ contourMovements[i] = computeBevelVector(contour[i], contour[j], contour[k]);
87
+ }
88
+
89
+ // Calculate bevel vectors for the holes
90
+ const holesMovements = [];
91
+ let oneHoleMovements;
92
+ let verticesMovements = [...contourMovements];
93
+ for (let h = 0, hl = holes.length; h < hl; h++) {
94
+ const ahole = holes[h];
95
+ oneHoleMovements = [];
96
+ for (let i = 0, j = ahole.length - 1, k = i + 1; i < ahole.length; i++, j++, k++) {
97
+ if (j === ahole.length) j = 0;
98
+ if (k === ahole.length) k = 0;
99
+ oneHoleMovements[i] = computeBevelVector(ahole[i], ahole[j], ahole[k]);
100
+ }
101
+ holesMovements.push(oneHoleMovements);
102
+ verticesMovements = [...verticesMovements, ...oneHoleMovements];
103
+ }
104
+
105
+ // Generate all the layers of points
106
+ const layers = [];
107
+
108
+ // Bottom bevel layers
109
+ for (let b = 0; b < bevelSegments; b++) {
110
+ const t = b / bevelSegments;
111
+ const z = bevelThickness * Math.cos(t * Math.PI / 2);
112
+ const bs = bevelSize * Math.sin(t * Math.PI / 2) + bevelOffset;
113
+
114
+ // Add points for contour and holes
115
+ for (let i = 0; i < contour.length; i++) {
116
+ const vert = scalePoint(contour[i], contourMovements[i], bs);
117
+ layers.push(vert[0], vert[1], -z + offsetSize[2]);
118
+ }
119
+ for (let h = 0, hl = holes.length; h < hl; h++) {
120
+ const ahole = holes[h];
121
+ oneHoleMovements = holesMovements[h];
122
+ for (let i = 0; i < ahole.length; i++) {
123
+ const vert = scalePoint(ahole[i], oneHoleMovements[i], bs);
124
+ layers.push(vert[0], vert[1], -z + offsetSize[2]);
125
+ }
126
+ }
127
+ }
128
+
129
+ // Base layer (z=0)
130
+ const bs = bevelSize + bevelOffset;
131
+ for (let i = 0; i < vlen; i++) {
132
+ const vert = bevelEnabled ? scalePoint(vertices[i], verticesMovements[i], bs) : vertices[i];
133
+ layers.push(vert[0], vert[1], 0 + offsetSize[2]);
134
+ }
135
+
136
+ // Middle layers
137
+ for (let s = 1; s <= steps; s++) {
138
+ for (let i = 0; i < vlen; i++) {
139
+ const vert = bevelEnabled ? scalePoint(vertices[i], verticesMovements[i], bs) : vertices[i];
140
+ layers.push(vert[0], vert[1], depth / steps * s + offsetSize[2]);
141
+ }
142
+ }
143
+
144
+ // Top bevel layers
145
+ for (let b = bevelSegments - 1; b >= 0; b--) {
146
+ const t = b / bevelSegments;
147
+ const z = bevelThickness * Math.cos(t * Math.PI / 2);
148
+ const topBevelSize = bevelSize * Math.sin(t * Math.PI / 2) + bevelOffset;
149
+ for (let i = 0, il = contour.length; i < il; i++) {
150
+ const vert = scalePoint(contour[i], contourMovements[i], topBevelSize);
151
+ layers.push(vert[0], vert[1], depth + z + offsetSize[2]);
152
+ }
153
+ for (let h = 0, hl = holes.length; h < hl; h++) {
154
+ const ahole = holes[h];
155
+ oneHoleMovements = holesMovements[h];
156
+ for (let i = 0, il = ahole.length; i < il; i++) {
157
+ const vert = scalePoint(ahole[i], oneHoleMovements[i], topBevelSize);
158
+ layers.push(vert[0], vert[1], depth + z + offsetSize[2]);
159
+ }
160
+ }
161
+ }
162
+
163
+ // Build all the faces
164
+ buildLidFaces(layers, faces, vlen, steps, bevelEnabled, bevelSegments, model.verticesArray, model.uvArray, model.colorArray, letterColor);
165
+ buildSideFaces(layers, contour, holes, vlen, steps, bevelSegments, model.verticesArray, model.uvArray, model.colorArray, letterColor);
166
+ }
167
+
168
+ /**
169
+ * Creates shape paths from the font and text
170
+ */
171
+ function buildShape() {
172
+ model.shapes = [];
173
+ if (!model.font || !model.text) {
174
+ return;
175
+ }
176
+ const path = model.font.getPath(model.text, 0, 0, model.fontSize);
177
+ if (!path || !path.commands || !path.commands.length) {
178
+ return;
179
+ }
180
+ let first;
181
+ let shapePath = createShapePath();
182
+ const commands = path.commands;
183
+ for (let i = 0; i < commands.length; i++) {
184
+ const command = commands[i];
185
+
186
+ // start a fresh shape if the previous one was closed
187
+ shapePath = shapePath || createShapePath();
188
+ switch (command.type) {
189
+ case 'M':
190
+ // Move to
191
+ shapePath.moveTo(command.x, -command.y);
192
+ first = command;
193
+ break;
194
+ case 'L':
195
+ // Line to
196
+ shapePath.lineTo(command.x, -command.y);
197
+ break;
198
+ case 'C':
199
+ // Cubic bezier curve
200
+ shapePath.bezierCurveTo(command.x1, -command.y1, command.x2, -command.y2, command.x, -command.y);
201
+ break;
202
+ case 'Q':
203
+ // Quadratic bezier curve
204
+ shapePath.quadraticCurveTo(command.x1, -command.y1, command.x, -command.y);
205
+ break;
206
+ case 'Z':
207
+ // Close path
208
+ // Close the contour
209
+ shapePath.lineTo(first.x, -first.y);
210
+
211
+ // Determine if this path is a clockwise contour (shape) or a counter-clockwise hole
212
+ if (isClockWise(shapePath.getPoints(1))) {
213
+ model.shapes.push(shapePath);
214
+ } else {
215
+ // Find which shape this hole belongs to
216
+ for (let j = 0; j < model.shapes.length; j++) {
217
+ const shape = model.shapes[j];
218
+ if (shape.isIntersect(shapePath)) {
219
+ shape.holes.push(shapePath);
220
+ break;
221
+ }
222
+ }
223
+ }
224
+
225
+ // Mark for restart on next iteration
226
+ shapePath = null;
227
+ break;
228
+ default:
229
+ console.warn(`Unknown path command: ${command.type}`);
230
+ break;
231
+ }
232
+ }
233
+
234
+ // If there's an unclosed shape, add it
235
+ if (shapePath) {
236
+ model.shapes.push(shapePath);
237
+ }
238
+ }
239
+
240
+ /**
241
+ * Creates a vtkPolyData from the processed shapes
242
+ * @returns {Object} vtkPolyData instance
243
+ */
244
+ function buildPolyData() {
245
+ model.verticesArray = [];
246
+ model.uvArray = [];
247
+ model.colorArray = [];
248
+ const polyData = vtkPolyData.newInstance();
249
+ const cells = vtkCellArray.newInstance();
250
+ const pointData = polyData.getPointData();
251
+
252
+ // Calculate the bounding box to center the text
253
+ const boundingSize = getBoundingSize(model.shapes, model.depth, model.curveSegments);
254
+ const offsetSize = [0, 0, 0];
255
+ subtract(boundingSize.min, boundingSize.max, offsetSize);
256
+
257
+ // Process each shape
258
+ let letterIndex = 0;
259
+ model.shapes.forEach(shape => {
260
+ let color = null;
261
+ if (typeof model.perLetterFaceColors === 'function') {
262
+ color = model.perLetterFaceColors(letterIndex) || [1, 1, 1];
263
+ }
264
+ addShape(shape, offsetSize, color);
265
+ letterIndex++;
266
+ });
267
+
268
+ // Create triangle indices
269
+ const vertexCount = model.verticesArray.length / 3;
270
+ const indices = [];
271
+
272
+ // Generate indices for triangles
273
+ for (let i = 0; i < vertexCount; i += 3) {
274
+ indices.push(i, i + 2, i + 1);
275
+ }
276
+
277
+ // Create cells for polydata
278
+ const cellSize = indices.length;
279
+ cells.resize(cellSize + cellSize / 3); // Allocate space for cells (+1 for size per cell)
280
+
281
+ // Add triangles to cells
282
+ for (let i = 0; i < indices.length; i += 3) {
283
+ cells.insertNextCell([indices[i], indices[i + 1], indices[i + 2]]);
284
+ }
285
+ polyData.setPolys(cells);
286
+
287
+ // Set points (vertices)
288
+ polyData.getPoints().setData(new Float32Array(model.verticesArray), 3);
289
+
290
+ // Set texture coordinates
291
+ const da = vtkDataArray.newInstance({
292
+ numberOfComponents: 2,
293
+ values: new Float32Array(model.uvArray),
294
+ name: 'TEXCOORD_0'
295
+ });
296
+ pointData.addArray(da);
297
+ pointData.setActiveTCoords(da.getName());
298
+
299
+ // Set color array if present
300
+ if (model.colorArray && model.colorArray.length) {
301
+ const ca = vtkDataArray.newInstance({
302
+ numberOfComponents: 3,
303
+ values: new Float32Array(model.colorArray),
304
+ name: 'Colors'
305
+ });
306
+ pointData.addArray(ca);
307
+ pointData.setActiveScalars(ca.getName());
308
+ }
309
+ return polyData;
310
+ }
311
+
312
+ // -------------------------------------------------------------------------
313
+ // Public methods
314
+ // -------------------------------------------------------------------------
315
+
316
+ /**
317
+ * Handles the request to generate vector text data
318
+ * @param {Object} inData - Input data (not used)
319
+ * @param {Object} outData - Output data target
320
+ */
321
+ publicAPI.requestData = (inData, outData) => {
322
+ if (!model.font) {
323
+ vtkErrorMacro('Font object not set, make sure the TTF file is parsed using opentype.js.');
324
+ return;
325
+ }
326
+ if (!model.text) {
327
+ vtkErrorMacro('Text not set. Cannot generate vector text.');
328
+ return;
329
+ }
330
+ buildShape();
331
+ outData[0] = buildPolyData();
332
+ };
333
+ }
334
+
335
+ // ----------------------------------------------------------------------------
336
+ // Object factory
337
+ // ----------------------------------------------------------------------------
338
+
339
+ /**
340
+ * Default values for the VectorText model
341
+ * shapes: Array to store shape paths
342
+ * verticesArray: Array of vertex coordinates
343
+ * uvArray: Array of texture coordinates
344
+ * font: Font object (from opentype.js)
345
+ * earcut: Earcut module for triangulation
346
+ * fontSize: Font size in points
347
+ * depth: Depth of the extruded text
348
+ * steps: Number of steps in extrusion (for curved surfaces)
349
+ * bevelEnabled: Whether to add beveled edges
350
+ * curveSegments: Number of segments for curved paths
351
+ * bevelThickness: Thickness of the bevel
352
+ * bevelSize: Size of the bevel
353
+ * bevelOffset: Offset of the bevel
354
+ * bevelSegments: Number of segments in the bevel
355
+ * text: The text to render
356
+ * perLetterFaceColors: Function to get per-letter face colors
357
+ */
358
+ const DEFAULT_VALUES = {
359
+ shapes: [],
360
+ verticesArray: [],
361
+ uvArray: [],
362
+ font: null,
363
+ earcut: null,
364
+ // Earcut module for triangulation
365
+ fontSize: 10,
366
+ depth: 1,
367
+ steps: 1,
368
+ bevelEnabled: false,
369
+ curveSegments: 12,
370
+ bevelThickness: 0.2,
371
+ bevelSize: 0.1,
372
+ bevelOffset: 0,
373
+ bevelSegments: 1,
374
+ text: null,
375
+ perLetterFaceColors: null // (letterIndex: number) => [r,g,b]
376
+ };
377
+
378
+ function extend(publicAPI, model) {
379
+ let initialValues = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
380
+ Object.assign(model, DEFAULT_VALUES, initialValues);
381
+
382
+ // Object methods
383
+ macro.obj(publicAPI, model);
384
+ macro.algo(publicAPI, model, 0, 1);
385
+
386
+ // Build VTK API with automatic getters/setters
387
+ macro.setGet(publicAPI, model, ['fontSize', 'text', 'depth', 'steps', 'bevelEnabled', 'curveSegments', 'bevelThickness', 'bevelSize', 'bevelOffset', 'bevelSegments', 'perLetterFaceColors']);
388
+ macro.set(publicAPI, model, ['font']);
389
+ vtkVectorText(publicAPI, model);
390
+ }
391
+ const newInstance = macro.newInstance(extend, 'vtkVectorText');
392
+ var vtkVector = {
393
+ newInstance,
394
+ extend
395
+ };
396
+
397
+ export { vtkVector as default, extend, newInstance };
package/Rendering/Core.js CHANGED
@@ -38,6 +38,9 @@ import vtkSkybox from './Core/Skybox.js';
38
38
  import vtkSphereMapper from './Core/SphereMapper.js';
39
39
  import vtkStickMapper from './Core/StickMapper.js';
40
40
  import vtkTexture from './Core/Texture.js';
41
+ import vtkTextActor from './Core/TextActor.js';
42
+ import vtkTextProperty from './Core/TextProperty.js';
43
+ import vtkVector from './Core/VectorText.js';
41
44
  import vtkViewport from './Core/Viewport.js';
42
45
  import vtkVolume from './Core/Volume.js';
43
46
  import vtkVolumeMapper from './Core/VolumeMapper.js';
@@ -87,6 +90,9 @@ var Core = {
87
90
  vtkSphereMapper,
88
91
  vtkStickMapper,
89
92
  vtkTexture,
93
+ vtkTextActor,
94
+ vtkTextProperty,
95
+ vtkVector,
90
96
  vtkViewport,
91
97
  vtkVolume,
92
98
  vtkVolumeMapper,
@@ -3,7 +3,7 @@ import Constants from './Texture/Constants.js';
3
3
  import HalfFloat from '../../Common/Core/HalfFloat.js';
4
4
  import { n as newInstance$1, o as obj, s as set, e as setGet, g as get, i as moveToProtected, a as newTypedArray, c as macro } from '../../macros2.js';
5
5
  import vtkDataArray from '../../Common/Core/DataArray.js';
6
- import { V as isPowerOfTwo, R as nearestPowerOfTwo } from '../../Common/Core/Math/index.js';
6
+ import { W as isPowerOfTwo, R as nearestPowerOfTwo } from '../../Common/Core/Math/index.js';
7
7
  import vtkViewNode from '../SceneGraph/ViewNode.js';
8
8
  import { registerOverride } from './ViewNodeFactory.js';
9
9
  import supportsNorm16LinearCached from './Texture/supportsNorm16Linear.js';
@@ -3,7 +3,7 @@ import vtkAbstractWidgetFactory from '../Core/AbstractWidgetFactory.js';
3
3
  import vtkPlanePointManipulator from '../Manipulators/PlaneManipulator.js';
4
4
  import vtkPolyLineRepresentation from '../Representations/PolyLineRepresentation.js';
5
5
  import vtkSphereHandleRepresentation from '../Representations/SphereHandleRepresentation.js';
6
- import { s as subtract, W as angleBetweenVectors } from '../../Common/Core/Math/index.js';
6
+ import { s as subtract, X as angleBetweenVectors } from '../../Common/Core/Math/index.js';
7
7
  import widgetBehavior from './AngleWidget/behavior.js';
8
8
  import generateState from './AngleWidget/state.js';
9
9
  import { ViewTypes } from '../Core/WidgetManager/Constants.js';
@@ -1,7 +1,7 @@
1
1
  import { m as macro } from '../../../macros2.js';
2
2
  import vtkBoundingBox from '../../../Common/DataModel/BoundingBox.js';
3
3
  import vtkLine from '../../../Common/DataModel/Line.js';
4
- import { k as add, l as normalize, s as subtract, d as dot, j as cross, m as multiplyAccumulate, w as multiplyScalar, X as signedAngleBetweenVectors } from '../../../Common/Core/Math/index.js';
4
+ import { k as add, l as normalize, s as subtract, d as dot, j as cross, m as multiplyAccumulate, w as multiplyScalar, Y as signedAngleBetweenVectors } from '../../../Common/Core/Math/index.js';
5
5
  import { getLineNames, getOtherLineName, updateState, boundPointOnPlane, getLinePlaneName, getLineInPlaneName, rotateVector } from './helpers.js';
6
6
  import { InteractionMethodsName, ScrollingMethods, planeNameToViewType } from './Constants.js';
7
7
 
@@ -2,7 +2,7 @@ import vtkBoundingBox, { STATIC } from '../../../Common/DataModel/BoundingBox.js
2
2
  import vtkCubeSource from '../../../Filters/Sources/CubeSource.js';
3
3
  import vtkCutter from '../../../Filters/Core/Cutter.js';
4
4
  import vtkPlane from '../../../Common/DataModel/Plane.js';
5
- import { s as subtract, l as normalize, j as cross, w as multiplyScalar, m as multiplyAccumulate, X as signedAngleBetweenVectors } from '../../../Common/Core/Math/index.js';
5
+ import { s as subtract, l as normalize, j as cross, w as multiplyScalar, m as multiplyAccumulate, Y as signedAngleBetweenVectors } from '../../../Common/Core/Math/index.js';
6
6
  import vtkMatrixBuilder from '../../../Common/Core/MatrixBuilder.js';
7
7
  import { viewTypeToPlaneName, planeNameToViewType, planeNames } from './Constants.js';
8
8
 
package/index.d.ts CHANGED
@@ -205,7 +205,10 @@
205
205
  /// <reference path="./Rendering/Core/Skybox.d.ts" />
206
206
  /// <reference path="./Rendering/Core/SphereMapper.d.ts" />
207
207
  /// <reference path="./Rendering/Core/StickMapper.d.ts" />
208
+ /// <reference path="./Rendering/Core/TextActor.d.ts" />
209
+ /// <reference path="./Rendering/Core/TextProperty.d.ts" />
208
210
  /// <reference path="./Rendering/Core/Texture.d.ts" />
211
+ /// <reference path="./Rendering/Core/VectorText.d.ts" />
209
212
  /// <reference path="./Rendering/Core/Viewport.d.ts" />
210
213
  /// <reference path="./Rendering/Core/Volume.d.ts" />
211
214
  /// <reference path="./Rendering/Core/VolumeMapper/Constants.d.ts" />
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kitware/vtk.js",
3
- "version": "34.1.0",
3
+ "version": "34.3.0",
4
4
  "description": "Visualization Toolkit for the Web",
5
5
  "keywords": [
6
6
  "3d",