@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.
- package/Common/Core/Math/index.js +1 -1
- package/Common/Core/Math.js +1 -1
- package/Rendering/Core/TextActor.d.ts +64 -0
- package/Rendering/Core/TextActor.js +134 -0
- package/Rendering/Core/TextProperty.d.ts +206 -0
- package/Rendering/Core/TextProperty.js +61 -0
- package/Rendering/Core/VectorText/Utils.js +520 -0
- package/Rendering/Core/VectorText.d.ts +183 -0
- package/Rendering/Core/VectorText.js +397 -0
- package/Rendering/Core.js +6 -0
- package/Rendering/OpenGL/Texture.js +1 -1
- package/Widgets/Widgets3D/AngleWidget.js +1 -1
- package/Widgets/Widgets3D/ResliceCursorWidget/behavior.js +1 -1
- package/Widgets/Widgets3D/ResliceCursorWidget/helpers.js +1 -1
- package/index.d.ts +3 -0
- package/package.json +1 -1
|
@@ -0,0 +1,520 @@
|
|
|
1
|
+
import { D as areEquals } from '../../../Common/Core/Math/index.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Computes UV coordinates for top/bottom faces
|
|
5
|
+
* @param {Array} vertices - The vertices array
|
|
6
|
+
* @param {Number} iA - First index
|
|
7
|
+
* @param {Number} iB - Second index
|
|
8
|
+
* @param {Number} iC - Third index
|
|
9
|
+
* @returns {Array} Array of UV coordinates
|
|
10
|
+
*/
|
|
11
|
+
function computeFacesUV(vertices, iA, iB, iC) {
|
|
12
|
+
const ax = vertices[iA * 3];
|
|
13
|
+
const ay = vertices[iA * 3 + 1];
|
|
14
|
+
const bx = vertices[iB * 3];
|
|
15
|
+
const by = vertices[iB * 3 + 1];
|
|
16
|
+
const cx = vertices[iC * 3];
|
|
17
|
+
const cy = vertices[iC * 3 + 1];
|
|
18
|
+
return [[ax, ay], [bx, by], [cx, cy]];
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Computes UV coordinates for side walls
|
|
23
|
+
* @param {Array} vertices - The vertices array
|
|
24
|
+
* @param {Number} iA - First index
|
|
25
|
+
* @param {Number} iB - Second index
|
|
26
|
+
* @param {Number} iC - Third index
|
|
27
|
+
* @param {Number} iD - Fourth index
|
|
28
|
+
* @returns {Array} Array of UV coordinates
|
|
29
|
+
*/
|
|
30
|
+
function computeSidesUV(vertices, iA, iB, iC, iD) {
|
|
31
|
+
const ax = vertices[iA * 3];
|
|
32
|
+
const ay = vertices[iA * 3 + 1];
|
|
33
|
+
const az = vertices[iA * 3 + 2];
|
|
34
|
+
const bx = vertices[iB * 3];
|
|
35
|
+
const by = vertices[iB * 3 + 1];
|
|
36
|
+
const bz = vertices[iB * 3 + 2];
|
|
37
|
+
const cx = vertices[iC * 3];
|
|
38
|
+
const cy = vertices[iC * 3 + 1];
|
|
39
|
+
const cz = vertices[iC * 3 + 2];
|
|
40
|
+
const dx = vertices[iD * 3];
|
|
41
|
+
const dy = vertices[iD * 3 + 1];
|
|
42
|
+
const dz = vertices[iD * 3 + 2];
|
|
43
|
+
|
|
44
|
+
// Determine the best UV mapping direction based on geometry
|
|
45
|
+
if (Math.abs(ay - by) < Math.abs(ax - bx)) {
|
|
46
|
+
return [[ax, 1 - az], [bx, 1 - bz], [cx, 1 - cz], [dx, 1 - dz]];
|
|
47
|
+
}
|
|
48
|
+
return [[ay, 1 - az], [by, 1 - bz], [cy, 1 - cz], [dy, 1 - dz]];
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Creates a shape path object with methods for path operations
|
|
53
|
+
* @returns {Object} A shape path object with methods for manipulating paths
|
|
54
|
+
*/
|
|
55
|
+
function createShapePath() {
|
|
56
|
+
const curves = [];
|
|
57
|
+
const currentPoint = [0, 0];
|
|
58
|
+
const holes = [];
|
|
59
|
+
return {
|
|
60
|
+
curves,
|
|
61
|
+
currentPoint,
|
|
62
|
+
holes,
|
|
63
|
+
moveTo(x, y) {
|
|
64
|
+
currentPoint[0] = x;
|
|
65
|
+
currentPoint[1] = y;
|
|
66
|
+
},
|
|
67
|
+
lineTo(x, y) {
|
|
68
|
+
const start = [...currentPoint];
|
|
69
|
+
const end = [x, y];
|
|
70
|
+
curves.push({
|
|
71
|
+
curveType: 'LineCurve',
|
|
72
|
+
start,
|
|
73
|
+
end,
|
|
74
|
+
getPointAt(t) {
|
|
75
|
+
return [start[0] + t * (end[0] - start[0]), start[1] + t * (end[1] - start[1])];
|
|
76
|
+
},
|
|
77
|
+
getPoints(resolution) {
|
|
78
|
+
const points = [];
|
|
79
|
+
for (let i = 0; i <= resolution; i++) {
|
|
80
|
+
points.push(this.getPointAt(i / resolution));
|
|
81
|
+
}
|
|
82
|
+
return points;
|
|
83
|
+
}
|
|
84
|
+
});
|
|
85
|
+
currentPoint[0] = x;
|
|
86
|
+
currentPoint[1] = y;
|
|
87
|
+
},
|
|
88
|
+
quadraticCurveTo(cpX, cpY, x, y) {
|
|
89
|
+
const start = [...currentPoint];
|
|
90
|
+
const end = [x, y];
|
|
91
|
+
const cp = [cpX, cpY];
|
|
92
|
+
curves.push({
|
|
93
|
+
curveType: 'QuadraticBezierCurve',
|
|
94
|
+
cp,
|
|
95
|
+
start,
|
|
96
|
+
end,
|
|
97
|
+
getPointAt(t) {
|
|
98
|
+
const oneMinusT = 1 - t;
|
|
99
|
+
return [oneMinusT * oneMinusT * start[0] + 2 * oneMinusT * t * cp[0] + t * t * end[0], oneMinusT * oneMinusT * start[1] + 2 * oneMinusT * t * cp[1] + t * t * end[1]];
|
|
100
|
+
},
|
|
101
|
+
getPoints(resolution) {
|
|
102
|
+
const points = [];
|
|
103
|
+
for (let i = 0; i <= resolution; i++) {
|
|
104
|
+
points.push(this.getPointAt(i / resolution));
|
|
105
|
+
}
|
|
106
|
+
return points;
|
|
107
|
+
}
|
|
108
|
+
});
|
|
109
|
+
currentPoint[0] = x;
|
|
110
|
+
currentPoint[1] = y;
|
|
111
|
+
},
|
|
112
|
+
bezierCurveTo(cp1X, cp1Y, cp2X, cp2Y, x, y) {
|
|
113
|
+
const start = [...currentPoint];
|
|
114
|
+
const end = [x, y];
|
|
115
|
+
const cp1 = [cp1X, cp1Y];
|
|
116
|
+
const cp2 = [cp2X, cp2Y];
|
|
117
|
+
curves.push({
|
|
118
|
+
curveType: 'BezierCurve',
|
|
119
|
+
cp1,
|
|
120
|
+
cp2,
|
|
121
|
+
start,
|
|
122
|
+
end,
|
|
123
|
+
getPointAt(t) {
|
|
124
|
+
const oneMinusT = 1 - t;
|
|
125
|
+
return [oneMinusT * oneMinusT * oneMinusT * start[0] + 3 * oneMinusT * oneMinusT * t * cp1[0] + 3 * oneMinusT * t * t * cp2[0] + t * t * t * end[0], oneMinusT * oneMinusT * oneMinusT * start[1] + 3 * oneMinusT * oneMinusT * t * cp1[1] + 3 * oneMinusT * t * t * cp2[1] + t * t * t * end[1]];
|
|
126
|
+
},
|
|
127
|
+
getPoints(resolution) {
|
|
128
|
+
const points = [];
|
|
129
|
+
for (let i = 0; i <= resolution; i++) {
|
|
130
|
+
points.push(this.getPointAt(i / resolution));
|
|
131
|
+
}
|
|
132
|
+
return points;
|
|
133
|
+
}
|
|
134
|
+
});
|
|
135
|
+
currentPoint[0] = x;
|
|
136
|
+
currentPoint[1] = y;
|
|
137
|
+
},
|
|
138
|
+
/**
|
|
139
|
+
* Get points from the shape
|
|
140
|
+
* @param {*} divisions
|
|
141
|
+
* @returns
|
|
142
|
+
*/
|
|
143
|
+
getPoints(divisions) {
|
|
144
|
+
let last;
|
|
145
|
+
const points = [];
|
|
146
|
+
for (let i = 0; i < curves.length; i++) {
|
|
147
|
+
const curve = curves[i];
|
|
148
|
+
let resolution = divisions;
|
|
149
|
+
if (curve.curveType === 'EllipseCurve') {
|
|
150
|
+
resolution = divisions * 2;
|
|
151
|
+
} else if (curve.curveType === 'LineCurve') {
|
|
152
|
+
resolution = 1;
|
|
153
|
+
}
|
|
154
|
+
const pts = curve.getPoints(resolution);
|
|
155
|
+
for (let j = 0; j < pts.length; j++) {
|
|
156
|
+
const point = pts[j];
|
|
157
|
+
// eslint-disable-next-line no-continue
|
|
158
|
+
if (last && areEquals(last, point)) continue;
|
|
159
|
+
points.push(point);
|
|
160
|
+
last = point;
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
return points;
|
|
164
|
+
},
|
|
165
|
+
/**
|
|
166
|
+
* Extract points from the shape
|
|
167
|
+
* @param {*} divisions
|
|
168
|
+
* @returns
|
|
169
|
+
*/
|
|
170
|
+
extractPoints(divisions) {
|
|
171
|
+
const points = this.getPoints(divisions);
|
|
172
|
+
const holesPoints = this.holes.map(hole => hole.getPoints(divisions));
|
|
173
|
+
return {
|
|
174
|
+
shape: points,
|
|
175
|
+
holes: holesPoints
|
|
176
|
+
};
|
|
177
|
+
},
|
|
178
|
+
/**
|
|
179
|
+
* Defines if a given point is inside the polygon defines by the path
|
|
180
|
+
* @param {*} point
|
|
181
|
+
* @param {*} polygon
|
|
182
|
+
* @returns {boolean}
|
|
183
|
+
*/
|
|
184
|
+
isPointInside(point, polygon) {
|
|
185
|
+
const x = point[0];
|
|
186
|
+
const y = point[1];
|
|
187
|
+
let isInside = false;
|
|
188
|
+
for (let i = 0, j = polygon.length - 1; i < polygon.length; j = i++) {
|
|
189
|
+
const xi = polygon[i][0];
|
|
190
|
+
const yi = polygon[i][1];
|
|
191
|
+
const xj = polygon[j][0];
|
|
192
|
+
const yj = polygon[j][1];
|
|
193
|
+
const intersect = yi > y !== yj > y && x < (xj - xi) * (y - yi) / (yj - yi) + xi;
|
|
194
|
+
if (intersect) isInside = !isInside;
|
|
195
|
+
}
|
|
196
|
+
return isInside;
|
|
197
|
+
},
|
|
198
|
+
isIntersect(path) {
|
|
199
|
+
const pathA = this.getPoints(1, curves, false);
|
|
200
|
+
const pathB = path.getPoints(1);
|
|
201
|
+
return this.isPointInside(pathB[0], pathA);
|
|
202
|
+
}
|
|
203
|
+
};
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
/**
|
|
207
|
+
* Calculates the bounding box size for a set of shapes
|
|
208
|
+
* @param {Array} shapes - Array of shape objects
|
|
209
|
+
* @param {Number} depth - Depth of the 3D text
|
|
210
|
+
* @param {Number} curveSegments - Number of segments for curved paths
|
|
211
|
+
* @returns {Object} Object with min and max point coordinates
|
|
212
|
+
*/
|
|
213
|
+
function getBoundingSize(shapes, depth, curveSegments) {
|
|
214
|
+
const minPoint = [Infinity, Infinity, depth > 0 ? 0 : depth];
|
|
215
|
+
const maxPoint = [-Infinity, -Infinity, depth < 0 ? 0 : depth];
|
|
216
|
+
for (let i = 0; i < shapes.length; i++) {
|
|
217
|
+
const shape = shapes[i];
|
|
218
|
+
const shapePoints = shape.extractPoints(curveSegments);
|
|
219
|
+
for (let j = 0; j < shapePoints.shape.length; j++) {
|
|
220
|
+
const p = shapePoints.shape[j];
|
|
221
|
+
if (p[0] < minPoint[0]) minPoint[0] = p[0];
|
|
222
|
+
if (p[1] < minPoint[1]) minPoint[1] = p[1];
|
|
223
|
+
if (p[0] > maxPoint[0]) maxPoint[0] = p[0];
|
|
224
|
+
if (p[1] > maxPoint[1]) maxPoint[1] = p[1];
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
return {
|
|
228
|
+
min: minPoint,
|
|
229
|
+
max: maxPoint
|
|
230
|
+
};
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
/**
|
|
234
|
+
* Removes duplicate end points in a points array
|
|
235
|
+
* @param {Array} points - Array of points
|
|
236
|
+
*/
|
|
237
|
+
function removeDupEndPoints(points) {
|
|
238
|
+
const l = points.length;
|
|
239
|
+
const isEqual = areEquals(points[l - 1], points[0]);
|
|
240
|
+
if (l > 2 && isEqual) {
|
|
241
|
+
points.pop();
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
/**
|
|
246
|
+
* Checks if the points are in a clockwise order
|
|
247
|
+
* @param {Array} points - Array of points [x, y]
|
|
248
|
+
* @returns {Boolean} True if points are in clockwise order
|
|
249
|
+
*/
|
|
250
|
+
function isClockWise(points) {
|
|
251
|
+
let sum = 0.0;
|
|
252
|
+
const n = points.length;
|
|
253
|
+
for (let p = n - 1, q = 0; q < n; p = q++) {
|
|
254
|
+
sum += points[p][0] * points[q][1] - points[q][0] * points[p][1];
|
|
255
|
+
}
|
|
256
|
+
// Positive signed area means counter-clockwise, so return true if area is negative
|
|
257
|
+
return sum * 0.5 < 0;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
/**
|
|
261
|
+
* Computes the bevel vector for a point in a shape.
|
|
262
|
+
* @param {Array} pt - Current point [x, y]
|
|
263
|
+
* @param {Array} prev - Previous point [x, y]
|
|
264
|
+
* @param {Array} next - Next point [x, y]
|
|
265
|
+
* @returns {Array} Normalized bevel vector [x, y]
|
|
266
|
+
*/
|
|
267
|
+
function computeBevelVector(pt, prev, next) {
|
|
268
|
+
const vPrevX = pt[0] - prev[0];
|
|
269
|
+
const vPrevY = pt[1] - prev[1];
|
|
270
|
+
const vNextX = next[0] - pt[0];
|
|
271
|
+
const vNextY = next[1] - pt[1];
|
|
272
|
+
|
|
273
|
+
// Check collinearity
|
|
274
|
+
const cross = vPrevX * vNextY - vPrevY * vNextX;
|
|
275
|
+
let tx;
|
|
276
|
+
let ty;
|
|
277
|
+
let shrinkBy;
|
|
278
|
+
if (Math.abs(cross) > Number.EPSILON) {
|
|
279
|
+
// non‐collinear
|
|
280
|
+
const lenPrev = Math.hypot(vPrevX, vPrevY);
|
|
281
|
+
const lenNext = Math.hypot(vNextX, vNextY);
|
|
282
|
+
|
|
283
|
+
// shift prev and next perpendicular to themselves
|
|
284
|
+
const prevShiftX = prev[0] - vPrevY / lenPrev;
|
|
285
|
+
const prevShiftY = prev[1] + vPrevX / lenPrev;
|
|
286
|
+
const nextShiftX = next[0] - vNextY / lenNext;
|
|
287
|
+
const nextShiftY = next[1] + vNextX / lenNext;
|
|
288
|
+
|
|
289
|
+
// intersection factor
|
|
290
|
+
const sf = ((nextShiftX - prevShiftX) * vNextY - (nextShiftY - prevShiftY) * vNextX) / (vPrevX * vNextY - vPrevY * vNextX);
|
|
291
|
+
tx = prevShiftX + vPrevX * sf - pt[0];
|
|
292
|
+
ty = prevShiftY + vPrevY * sf - pt[1];
|
|
293
|
+
const lensq = tx * tx + ty * ty;
|
|
294
|
+
if (lensq <= 2) {
|
|
295
|
+
return [tx, ty];
|
|
296
|
+
}
|
|
297
|
+
shrinkBy = Math.sqrt(lensq / 2);
|
|
298
|
+
} else {
|
|
299
|
+
// collinear or opposing
|
|
300
|
+
const sameDir = vPrevX > 0 && vNextX > 0 || vPrevX < 0 && vNextX < 0 || Math.sign(vPrevY) === Math.sign(vNextY);
|
|
301
|
+
if (sameDir) {
|
|
302
|
+
// perpendicular to prev
|
|
303
|
+
tx = -vPrevY;
|
|
304
|
+
ty = vPrevX;
|
|
305
|
+
shrinkBy = Math.hypot(vPrevX, vPrevY);
|
|
306
|
+
} else {
|
|
307
|
+
// just offset along prev
|
|
308
|
+
tx = vPrevX;
|
|
309
|
+
ty = vPrevY;
|
|
310
|
+
shrinkBy = Math.sqrt((vPrevX * vPrevX + vPrevY * vPrevY) / 2);
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
return [tx / shrinkBy, ty / shrinkBy];
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
/**
|
|
317
|
+
* Triangulates a shape with holes
|
|
318
|
+
* @param {Array} contour - Array of contour points
|
|
319
|
+
* @param {Array} holes - Array of hole paths
|
|
320
|
+
* @returns {Array} Array of triangle faces as arrays of indices
|
|
321
|
+
*/
|
|
322
|
+
function triangulateShape(earcut, contour, holes) {
|
|
323
|
+
const faces = [];
|
|
324
|
+
const vertices = [];
|
|
325
|
+
const holeIndices = [];
|
|
326
|
+
removeDupEndPoints(contour);
|
|
327
|
+
for (let i = 0; i < contour.length; i++) {
|
|
328
|
+
vertices.push(contour[i][0], contour[i][1]);
|
|
329
|
+
}
|
|
330
|
+
let holeIndex = contour.length;
|
|
331
|
+
holes.forEach(removeDupEndPoints);
|
|
332
|
+
for (let i = 0; i < holes.length; i++) {
|
|
333
|
+
holeIndices.push(holeIndex);
|
|
334
|
+
const hole = holes[i];
|
|
335
|
+
holeIndex += hole.length;
|
|
336
|
+
for (let j = 0; j < hole.length; j++) {
|
|
337
|
+
vertices.push(hole[j][0], hole[j][1]);
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
const triangles = earcut(vertices, holeIndices);
|
|
341
|
+
for (let i = 0; i < triangles.length; i += 3) {
|
|
342
|
+
faces.push(triangles.slice(i, i + 3));
|
|
343
|
+
}
|
|
344
|
+
return faces;
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
/**
|
|
348
|
+
* Scales a point along a vector
|
|
349
|
+
* @param {Array} pt - Point to scale [x, y]
|
|
350
|
+
* @param {Array} vec - Direction vector [x, y]
|
|
351
|
+
* @param {Number} size - Scale amount
|
|
352
|
+
* @returns {Array} Scaled point [x, y]
|
|
353
|
+
*/
|
|
354
|
+
function scalePoint(pt, vec, size) {
|
|
355
|
+
const rt = [pt[0], pt[1]];
|
|
356
|
+
rt[0] += vec[0] * size;
|
|
357
|
+
rt[1] += vec[1] * size;
|
|
358
|
+
return rt;
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
/**
|
|
362
|
+
* Creates triangle faces with specified indices
|
|
363
|
+
* @param {Array} layers - The layers array with vertex positions
|
|
364
|
+
* @param {Number} a - First index
|
|
365
|
+
* @param {Number} b - Second index
|
|
366
|
+
* @param {Number} c - Third index
|
|
367
|
+
* @param {Array} verticesArray - The output vertices array
|
|
368
|
+
* @param {Array} uvArray - The output UV array
|
|
369
|
+
* @param {Array} colorArray - The output color array
|
|
370
|
+
* @param {Array} color - The color [r, g, b]
|
|
371
|
+
* @param {Boolean} perFaceUV - Flag for per-face UV mapping
|
|
372
|
+
* @param {Number} faceIndex - Index of the face for UV mapping
|
|
373
|
+
*/
|
|
374
|
+
function addTriangle(layers, a, b, c, verticesArray, uvArray, colorArray, color) {
|
|
375
|
+
const tri = [a, c, b];
|
|
376
|
+
tri.forEach(i => {
|
|
377
|
+
verticesArray.push(layers[i * 3], layers[i * 3 + 1], layers[i * 3 + 2]);
|
|
378
|
+
});
|
|
379
|
+
const nextIndex = verticesArray.length / 3;
|
|
380
|
+
const uvs = computeFacesUV(verticesArray, nextIndex - 3, nextIndex - 2, nextIndex - 1);
|
|
381
|
+
|
|
382
|
+
// Add each UV coordinate pair to the array
|
|
383
|
+
uvs.forEach(uv => {
|
|
384
|
+
uvArray.push(uv[0], uv[1]);
|
|
385
|
+
});
|
|
386
|
+
if (colorArray && color) {
|
|
387
|
+
for (let i = 0; i < 3; ++i) colorArray.push(color[0], color[1], color[2]);
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
/**
|
|
392
|
+
* Creates quad faces with specified indices
|
|
393
|
+
* @param {Array} layers - The layers array with vertex positions
|
|
394
|
+
* @param {Number} a - First index
|
|
395
|
+
* @param {Number} b - Second index
|
|
396
|
+
* @param {Number} c - Third index
|
|
397
|
+
* @param {Number} d - Fourth index
|
|
398
|
+
* @param {Array} verticesArray - The output vertices array
|
|
399
|
+
* @param {Array} uvArray - The output UV array
|
|
400
|
+
* @param {Array} colorArray - The output color array
|
|
401
|
+
* @param {Array} color - The color [r, g, b]
|
|
402
|
+
*/
|
|
403
|
+
function addQuad(layers, a, b, c, d, verticesArray, uvArray, colorArray, color) {
|
|
404
|
+
const quad = [a, d, b, b, d, c];
|
|
405
|
+
quad.forEach(i => verticesArray.push(layers[i * 3], layers[i * 3 + 1], layers[i * 3 + 2]));
|
|
406
|
+
const nextIndex = verticesArray.length / 3;
|
|
407
|
+
const uvs = computeSidesUV(verticesArray, nextIndex - 6, nextIndex - 3, nextIndex - 2, nextIndex - 1);
|
|
408
|
+
|
|
409
|
+
// UV coordinates for both triangles of the quad
|
|
410
|
+
// First triangle
|
|
411
|
+
uvArray.push(uvs[0][0], uvs[0][1]);
|
|
412
|
+
uvArray.push(uvs[1][0], uvs[1][1]);
|
|
413
|
+
uvArray.push(uvs[3][0], uvs[3][1]);
|
|
414
|
+
|
|
415
|
+
// Second triangle
|
|
416
|
+
uvArray.push(uvs[1][0], uvs[1][1]);
|
|
417
|
+
uvArray.push(uvs[2][0], uvs[2][1]);
|
|
418
|
+
uvArray.push(uvs[3][0], uvs[3][1]);
|
|
419
|
+
if (colorArray && color) {
|
|
420
|
+
for (let i = 0; i < 6; ++i) colorArray.push(color[0], color[1], color[2]);
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
/**
|
|
425
|
+
* Creates the faces for the top and bottom of the 3D text
|
|
426
|
+
* @param {Array} layers - The layers array with vertex positions
|
|
427
|
+
* @param {Array} faces - The triangulated faces
|
|
428
|
+
* @param {Number} vlen - The number of vertices
|
|
429
|
+
* @param {Number} steps - The number of steps
|
|
430
|
+
* @param {Boolean} bevelEnabled - Whether bevel is enabled
|
|
431
|
+
* @param {Number} bevelSegments - Number of bevel segments
|
|
432
|
+
* @param {Array} verticesArray - The output vertices array
|
|
433
|
+
* @param {Array} uvArray - The output UV array
|
|
434
|
+
*/
|
|
435
|
+
function buildLidFaces(layers, faces, vlen, steps, bevelEnabled, bevelSegments, verticesArray, uvArray, colorArray, color) {
|
|
436
|
+
if (bevelEnabled) {
|
|
437
|
+
let layer = 0;
|
|
438
|
+
let offset = vlen * layer; // Bottom faces
|
|
439
|
+
faces.forEach(_ref => {
|
|
440
|
+
let [a, b, c] = _ref;
|
|
441
|
+
addTriangle(layers, c + offset, b + offset, a + offset, verticesArray, uvArray, colorArray, color);
|
|
442
|
+
});
|
|
443
|
+
layer = steps + bevelSegments * 2;
|
|
444
|
+
offset = vlen * layer;
|
|
445
|
+
|
|
446
|
+
// Top faces
|
|
447
|
+
faces.forEach(_ref2 => {
|
|
448
|
+
let [a, b, c] = _ref2;
|
|
449
|
+
addTriangle(layers, a + offset, b + offset, c + offset, verticesArray, uvArray, colorArray, color);
|
|
450
|
+
});
|
|
451
|
+
} else {
|
|
452
|
+
// Bottom faces
|
|
453
|
+
faces.forEach(_ref3 => {
|
|
454
|
+
let [a, b, c] = _ref3;
|
|
455
|
+
addTriangle(layers, c, b, a, verticesArray, uvArray, colorArray, color);
|
|
456
|
+
});
|
|
457
|
+
|
|
458
|
+
// Top faces
|
|
459
|
+
const offset = vlen * steps;
|
|
460
|
+
faces.forEach(_ref4 => {
|
|
461
|
+
let [a, b, c] = _ref4;
|
|
462
|
+
addTriangle(layers, a + offset, b + offset, c + offset, verticesArray, uvArray, colorArray, color);
|
|
463
|
+
});
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
/**
|
|
468
|
+
* Creates side walls for contour or hole
|
|
469
|
+
* @param {Array} layers - The layers array
|
|
470
|
+
* @param {Array} contour - The contour points
|
|
471
|
+
* @param {Number} layerOffset - Offset for the layer
|
|
472
|
+
* @param {Number} vlen - The number of vertices
|
|
473
|
+
* @param {Number} steps - The number of steps
|
|
474
|
+
* @param {Number} bevelSegments - The number of bevel segments
|
|
475
|
+
* @param {Array} verticesArray - The output vertices array
|
|
476
|
+
* @param {Array} uvArray - The output UV array
|
|
477
|
+
*/
|
|
478
|
+
function buildWalls(layers, contour, layerOffset, vlen, steps, bevelSegments, verticesArray, uvArray, colorArray, color) {
|
|
479
|
+
const totalLayers = steps + bevelSegments * 2;
|
|
480
|
+
for (let i = 0; i < contour.length; i++) {
|
|
481
|
+
const j = i;
|
|
482
|
+
const k = i === 0 ? contour.length - 1 : i - 1;
|
|
483
|
+
for (let s = 0; s < totalLayers; s++) {
|
|
484
|
+
const slen1 = vlen * s;
|
|
485
|
+
const slen2 = vlen * (s + 1);
|
|
486
|
+
const a = layerOffset + j + slen1;
|
|
487
|
+
const b = layerOffset + k + slen1;
|
|
488
|
+
const c = layerOffset + k + slen2;
|
|
489
|
+
const d = layerOffset + j + slen2;
|
|
490
|
+
addQuad(layers, a, b, c, d, verticesArray, uvArray, colorArray, color);
|
|
491
|
+
}
|
|
492
|
+
}
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
/**
|
|
496
|
+
* Builds the side faces of the 3D text
|
|
497
|
+
* @param {Array} layers - The layers array
|
|
498
|
+
* @param {Array} contour - The contour points
|
|
499
|
+
* @param {Array} holes - The holes
|
|
500
|
+
* @param {Number} vlen - The number of vertices
|
|
501
|
+
* @param {Number} steps - The number of steps
|
|
502
|
+
* @param {Number} bevelSegments - The number of bevel segments
|
|
503
|
+
* @param {Array} verticesArray - The output vertices array
|
|
504
|
+
* @param {Array} uvArray - The output UV array
|
|
505
|
+
*/
|
|
506
|
+
function buildSideFaces(layers, contour, holes, vlen, steps, bevelSegments, verticesArray, uvArray, colorArray, color) {
|
|
507
|
+
let layerOffset = 0;
|
|
508
|
+
// Create contour walls
|
|
509
|
+
buildWalls(layers, contour, layerOffset, vlen, steps, bevelSegments, verticesArray, uvArray, colorArray, color);
|
|
510
|
+
layerOffset += contour.length;
|
|
511
|
+
|
|
512
|
+
// Create hole walls
|
|
513
|
+
for (let i = 0; i < holes.length; i++) {
|
|
514
|
+
const ahole = holes[i];
|
|
515
|
+
buildWalls(layers, ahole, layerOffset, vlen, steps, bevelSegments, verticesArray, uvArray, colorArray, color);
|
|
516
|
+
layerOffset += ahole.length;
|
|
517
|
+
}
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
export { addQuad, addTriangle, buildLidFaces, buildSideFaces, buildWalls, computeBevelVector, computeFacesUV, computeSidesUV, createShapePath, getBoundingSize, isClockWise, scalePoint, triangulateShape };
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
import { vtkAlgorithm, vtkObject } from './../../interfaces';
|
|
2
|
+
import { Nullable, RGBColor } from './../../types';
|
|
3
|
+
|
|
4
|
+
export interface IVectorTextInitialValues {
|
|
5
|
+
fontSize?: number;
|
|
6
|
+
text?: string;
|
|
7
|
+
depth?: number;
|
|
8
|
+
steps?: number;
|
|
9
|
+
bevelEnabled?: boolean;
|
|
10
|
+
curveSegments?: number;
|
|
11
|
+
bevelThickness?: number;
|
|
12
|
+
bevelSize?: number;
|
|
13
|
+
bevelOffset?: number;
|
|
14
|
+
bevelSegments?: number;
|
|
15
|
+
font?: any;
|
|
16
|
+
earcut?: any; // Earcut module for triangulation
|
|
17
|
+
perLetterFaceColors?: (letterIndex: number) => [number, number, number];
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
type vtkVectorTextBase = vtkObject & vtkAlgorithm;
|
|
21
|
+
|
|
22
|
+
export interface vtkVectorText extends vtkVectorTextBase {
|
|
23
|
+
/**
|
|
24
|
+
* Returns whether beveling is enabled.
|
|
25
|
+
*/
|
|
26
|
+
getBevelEnabled(): boolean;
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Returns the number of segments used for the bevel geometry.
|
|
30
|
+
*/
|
|
31
|
+
getBevelSegments(): number;
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Returns the size of the bevel.
|
|
35
|
+
*/
|
|
36
|
+
getBevelSize(): number;
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Returns the thickness of the bevel.
|
|
40
|
+
*/
|
|
41
|
+
getBevelThickness(): number;
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Returns the offset of the bevel.
|
|
45
|
+
*/
|
|
46
|
+
getBevelOffset(): number;
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Returns the number of curve segments used for the text geometry.
|
|
50
|
+
*/
|
|
51
|
+
getCurveSegments(): number;
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Returns the extrusion depth of the text.
|
|
55
|
+
*/
|
|
56
|
+
getDepth(): number;
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Returns the current font size.
|
|
60
|
+
*/
|
|
61
|
+
getFontSize(): number;
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Returns the number of steps used for the text geometry.
|
|
65
|
+
*/
|
|
66
|
+
getSteps(): number;
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Returns the current text string.
|
|
70
|
+
*/
|
|
71
|
+
getText(): string;
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Gets or sets the per-letter face color function.
|
|
75
|
+
* @param fn - Function mapping letter index to [r,g,b] color.
|
|
76
|
+
*/
|
|
77
|
+
getPerLetterFaceColors(): Nullable<(letterIndex: number) => RGBColor>;
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Enables or disables beveling.
|
|
81
|
+
* @param bevelEnabled - True to enable beveling, false to disable.
|
|
82
|
+
*/
|
|
83
|
+
setBevelEnabled(bevelEnabled: boolean): boolean;
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Sets the number of segments used for the bevel geometry.
|
|
87
|
+
* @param bevelSegments - The number of bevel segments.
|
|
88
|
+
*/
|
|
89
|
+
setBevelSegments(bevelSegments: number): boolean;
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Sets the size of the bevel.
|
|
93
|
+
* @param bevelSize - The bevel size.
|
|
94
|
+
*/
|
|
95
|
+
setBevelSize(bevelSize: number): boolean;
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Sets the thickness of the bevel.
|
|
99
|
+
* @param bevelThickness - The bevel thickness.
|
|
100
|
+
*/
|
|
101
|
+
setBevelThickness(bevelThickness: number): boolean;
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Sets the offset of the bevel.
|
|
105
|
+
* @param bevelOffset - The bevel offset.
|
|
106
|
+
*/
|
|
107
|
+
setBevelOffset(bevelOffset: number): boolean;
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Sets the number of curve segments used for the text geometry.
|
|
111
|
+
* @param curveSegments - The number of curve segments.
|
|
112
|
+
*/
|
|
113
|
+
setCurveSegments(curveSegments: number): boolean;
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Sets the extrusion depth of the text.
|
|
117
|
+
* @param depth - The new depth value.
|
|
118
|
+
*/
|
|
119
|
+
setDepth(depth: number): boolean;
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Sets the font object used for rendering the text.
|
|
123
|
+
* This should be a parsed font object from opentype.js.
|
|
124
|
+
* @param font - The font object.
|
|
125
|
+
*/
|
|
126
|
+
setFont(font: any): boolean;
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* Sets the font size.
|
|
130
|
+
* @param fontSize - The new font size.
|
|
131
|
+
*/
|
|
132
|
+
setFontSize(fontSize: number): boolean;
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Sets the number of steps used for the text geometry.
|
|
136
|
+
* @param steps - The number of steps.
|
|
137
|
+
*/
|
|
138
|
+
setSteps(steps: number): boolean;
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* Sets the text string.
|
|
142
|
+
* @param text - The new text to display.
|
|
143
|
+
*/
|
|
144
|
+
setText(text: string): boolean;
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* Sets the per-letter face color function.
|
|
148
|
+
* @param fn - Function mapping letter index to [r,g,b] color.
|
|
149
|
+
*/
|
|
150
|
+
setPerLetterFaceColors(fn: (letterIndex: number) => RGBColor): boolean;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* Method use to decorate a given object (publicAPI+model) with vtkVectorText characteristics.
|
|
155
|
+
*
|
|
156
|
+
* @param publicAPI object on which methods will be bounds (public)
|
|
157
|
+
* @param model object on which data structure will be bounds (protected)
|
|
158
|
+
* @param {IVectorTextInitialValues} [initialValues] (default: {})
|
|
159
|
+
*/
|
|
160
|
+
export function extend(
|
|
161
|
+
publicAPI: object,
|
|
162
|
+
model: object,
|
|
163
|
+
initialValues?: IVectorTextInitialValues
|
|
164
|
+
): void;
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* Method use to create a new instance of vtkVectorText
|
|
168
|
+
* @param {IVectorTextInitialValues} [initialValues] for pre-setting some of its content
|
|
169
|
+
*/
|
|
170
|
+
export function newInstance(
|
|
171
|
+
initialValues?: IVectorTextInitialValues
|
|
172
|
+
): vtkVectorText;
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* vtkVectorText generates vtkPolyData from an input string.
|
|
176
|
+
* The TTF file needs to be parsed using opentype.js and then passed to
|
|
177
|
+
* vtkVectorText via the setFont method.
|
|
178
|
+
*/
|
|
179
|
+
export declare const vtkVectorText: {
|
|
180
|
+
newInstance: typeof newInstance;
|
|
181
|
+
extend: typeof extend;
|
|
182
|
+
};
|
|
183
|
+
export default vtkVectorText;
|