0
# Text and Utilities
1
2
This module provides text rendering capabilities for creating 2D/3D text outlines and various utility functions for angle conversions, data processing, and geometry validation.
3
4
## Text Capabilities
5
6
Texts provide sets of segments for each character or text strings. The segments can be used to create outlines for both 2D and 3D geometry. Note: Only ASCII characters are supported.
7
8
### Vector Text
9
10
Generate vector text as line segments for creating text outlines.
11
12
```javascript { .api }
13
/**
14
* Generate vector text as line segments from text string
15
* @param {Object} options - Text options
16
* @param {Number} [options.xOffset=0] - X offset for text positioning
17
* @param {Number} [options.yOffset=0] - Y offset for text positioning
18
* @param {Number} [options.height=21] - Height of text characters
19
* @param {Number} [options.extrudeOffset=0] - Offset for 3D extrusion preparation
20
* @param {String} [options.input] - Text string to convert (deprecated, use text parameter)
21
* @param {String} text - Text string to convert to vector segments
22
* @returns {Array} Array of line segment arrays, each representing character outlines
23
*/
24
function vectorText(options: {
25
xOffset?: number,
26
yOffset?: number,
27
height?: number,
28
extrudeOffset?: number,
29
input?: string
30
}, text: string): Array<Array<[number, number]>>;
31
```
32
33
**Usage Examples:**
34
35
```javascript
36
const { vectorText } = require('@jscad/modeling').text;
37
const { extrudeLinear } = require('@jscad/modeling').extrusions;
38
const { geom2 } = require('@jscad/modeling').geometries;
39
40
// Create simple text outline
41
const textSegments = vectorText({}, 'HELLO');
42
// Returns array of line segment arrays for each character
43
44
// Create text with custom positioning and size
45
const largeText = vectorText({
46
xOffset: 10,
47
yOffset: 5,
48
height: 42
49
}, 'BIG TEXT');
50
51
// Convert text segments to 2D geometries for further processing
52
const textGeometries = textSegments.map(segments => {
53
// Each segments array represents one character
54
return geom2.fromPoints(segments);
55
});
56
57
// Create 3D text by extruding
58
const text3D = textGeometries.map(geom =>
59
extrudeLinear({ height: 5 }, geom)
60
);
61
```
62
63
### Vector Character
64
65
Generate vector segments for individual characters.
66
67
```javascript { .api }
68
/**
69
* Generate vector segments for a single character
70
* @param {Object} options - Character options
71
* @param {Number} [options.xOffset=0] - X offset for character positioning
72
* @param {Number} [options.yOffset=0] - Y offset for character positioning
73
* @param {Number} [options.height=21] - Height of character
74
* @param {String} character - Single character to convert (ASCII only)
75
* @returns {Array} Array of line segments representing the character outline
76
*/
77
function vectorChar(options: {
78
xOffset?: number,
79
yOffset?: number,
80
height?: number
81
}, character: string): Array<[number, number]>;
82
```
83
84
**Usage Examples:**
85
86
```javascript
87
const { vectorChar } = require('@jscad/modeling').text;
88
89
// Get segments for individual character
90
const letterA = vectorChar({}, 'A');
91
const letterB = vectorChar({ xOffset: 30 }, 'B'); // Offset to position next to A
92
93
// Create custom character with scaling
94
const bigLetter = vectorChar({ height: 100 }, 'X');
95
96
// Build custom text by combining characters
97
const customText = [];
98
const characters = 'CUSTOM';
99
let currentOffset = 0;
100
101
characters.split('').forEach(char => {
102
const charSegments = vectorChar({
103
xOffset: currentOffset,
104
height: 30
105
}, char);
106
customText.push(charSegments);
107
currentOffset += 25; // Space between characters
108
});
109
```
110
111
## Utility Functions
112
113
Utility functions of various sorts, including conversions from different angular measures and data processing helpers.
114
115
### Angle Conversions
116
117
Convert between degrees and radians.
118
119
```javascript { .api }
120
/**
121
* Convert degrees to radians
122
* @param {Number} degrees - Angle in degrees
123
* @returns {Number} Angle in radians
124
*/
125
function degToRad(degrees: number): number;
126
127
/**
128
* Convert radians to degrees
129
* @param {Number} radians - Angle in radians
130
* @returns {Number} Angle in degrees
131
*/
132
function radToDeg(radians: number): number;
133
```
134
135
**Usage Examples:**
136
137
```javascript
138
const { degToRad, radToDeg } = require('@jscad/modeling').utils;
139
140
// Convert common angles
141
const rightAngleRad = degToRad(90); // π/2 ≈ 1.5708
142
const halfTurnRad = degToRad(180); // π ≈ 3.1416
143
const fullTurnRad = degToRad(360); // 2π ≈ 6.2832
144
145
// Convert back to degrees
146
const degrees90 = radToDeg(Math.PI / 2); // 90
147
const degrees180 = radToDeg(Math.PI); // 180
148
const degrees360 = radToDeg(Math.PI * 2); // 360
149
150
// Use in geometric calculations
151
const { rotateZ } = require('@jscad/modeling').transforms;
152
const { cube } = require('@jscad/modeling').primitives;
153
154
const myCube = cube({ size: 10 });
155
const rotated45 = rotateZ(degToRad(45), myCube);
156
const rotated90 = rotateZ(degToRad(90), myCube);
157
```
158
159
### Data Processing
160
161
Utilities for processing arrays and geometric data.
162
163
```javascript { .api }
164
/**
165
* Flatten nested arrays into a single-level array
166
* @param {Array} array - Nested array to flatten
167
* @returns {Array} Flattened array
168
*/
169
function flatten(array: any[]): any[];
170
171
/**
172
* Insert item into sorted array at correct position
173
* @param {*} item - Item to insert
174
* @param {Array} array - Sorted array to insert into
175
* @param {Function} [compareFn] - Comparison function for sorting
176
* @returns {Array} Array with item inserted
177
*/
178
function insertSorted(item: any, array: any[], compareFn?: (a: any, b: any) => number): any[];
179
180
/**
181
* Numeric sort comparison function
182
* @param {Number} a - First number
183
* @param {Number} b - Second number
184
* @returns {Number} Comparison result (-1, 0, or 1)
185
*/
186
function fnNumberSort(a: number, b: number): number;
187
```
188
189
**Usage Examples:**
190
191
```javascript
192
const { flatten, insertSorted, fnNumberSort } = require('@jscad/modeling').utils;
193
194
// Flatten nested arrays
195
const nested = [[1, 2], [3, [4, 5]], 6];
196
const flat = flatten(nested); // [1, 2, 3, 4, 5, 6]
197
198
// Use with geometry operations
199
const { union } = require('@jscad/modeling').booleans;
200
const nestedShapes = [
201
[cube({ size: 1 }), cube({ size: 2 })],
202
[sphere({ radius: 1 }), sphere({ radius: 2 })]
203
];
204
const allShapes = flatten(nestedShapes);
205
const combined = union(...allShapes);
206
207
// Insert into sorted array
208
const sortedNumbers = [1, 3, 5, 7, 9];
209
const withInserted = insertSorted(6, sortedNumbers, fnNumberSort);
210
// Result: [1, 3, 5, 6, 7, 9]
211
212
// Sort numeric array
213
const unsorted = [3.7, 1.2, 8.9, 2.1, 5.6];
214
const sorted = unsorted.sort(fnNumberSort); // [1.2, 2.1, 3.7, 5.6, 8.9]
215
```
216
217
### Geometry Validation
218
219
Utilities for validating and analyzing geometric data.
220
221
```javascript { .api }
222
/**
223
* Check if all shapes in array are the same type
224
* @param {Array} shapes - Array of geometry objects to check
225
* @returns {Boolean} True if all shapes are the same type
226
*/
227
function areAllShapesTheSameType(shapes: any[]): boolean;
228
```
229
230
**Usage Examples:**
231
232
```javascript
233
const { areAllShapesTheSameType } = require('@jscad/modeling').utils;
234
const { cube, sphere } = require('@jscad/modeling').primitives;
235
const { circle, rectangle } = require('@jscad/modeling').primitives;
236
237
// Check 3D shapes
238
const shapes3D = [cube({ size: 5 }), cube({ size: 3 }), cube({ size: 8 })];
239
const allSameType3D = areAllShapesTheSameType(shapes3D); // true (all geom3)
240
241
// Check mixed shapes
242
const mixedShapes = [cube({ size: 5 }), circle({ radius: 3 })];
243
const allSameTypeMixed = areAllShapesTheSameType(mixedShapes); // false (geom3 and geom2)
244
245
// Use for validation before boolean operations
246
const { union } = require('@jscad/modeling').booleans;
247
const validateAndUnion = (shapes) => {
248
if (!areAllShapesTheSameType(shapes)) {
249
throw new Error('All shapes must be the same type for boolean operations');
250
}
251
return union(...shapes);
252
};
253
```
254
255
### Segment Calculation
256
257
Calculate appropriate segment counts for curved shapes.
258
259
```javascript { .api }
260
/**
261
* Calculate number of segments for given radius to maintain smoothness
262
* @param {Number} radius - Radius of curved shape
263
* @returns {Number} Recommended number of segments
264
*/
265
function radiusToSegments(radius: number): number;
266
```
267
268
**Usage Examples:**
269
270
```javascript
271
const { radiusToSegments } = require('@jscad/modeling').utils;
272
const { circle, cylinder } = require('@jscad/modeling').primitives;
273
274
// Calculate appropriate segments for different radii
275
const smallRadius = 2;
276
const mediumRadius = 10;
277
const largeRadius = 50;
278
279
const smallSegments = radiusToSegments(smallRadius); // ~16
280
const mediumSegments = radiusToSegments(mediumRadius); // ~32
281
const largeSegments = radiusToSegments(largeRadius); // ~64
282
283
// Use for creating smooth curves
284
const smoothCircles = [
285
circle({ radius: smallRadius, segments: smallSegments }),
286
circle({ radius: mediumRadius, segments: mediumSegments }),
287
circle({ radius: largeRadius, segments: largeSegments })
288
];
289
290
// Apply to 3D shapes
291
const smoothCylinder = cylinder({
292
radius: 15,
293
height: 10,
294
segments: radiusToSegments(15)
295
});
296
```
297
298
## Advanced Text and Utility Techniques
299
300
### Custom Text Layout
301
302
Create complex text layouts with multiple lines and formatting:
303
304
```javascript
305
const { vectorText, vectorChar } = require('@jscad/modeling').text;
306
const { degToRad } = require('@jscad/modeling').utils;
307
const { rotateZ, translate } = require('@jscad/modeling').transforms;
308
309
// Multi-line text layout
310
const createMultilineText = (lines, options = {}) => {
311
const {
312
lineHeight = 30,
313
characterSpacing = 25,
314
height = 21
315
} = options;
316
317
const textGeometries = [];
318
319
lines.forEach((line, lineIndex) => {
320
let xOffset = 0;
321
line.split('').forEach(char => {
322
if (char !== ' ') {
323
const charSegments = vectorChar({
324
xOffset,
325
yOffset: -lineIndex * lineHeight,
326
height
327
}, char);
328
textGeometries.push(charSegments);
329
}
330
xOffset += characterSpacing;
331
});
332
});
333
334
return textGeometries;
335
};
336
337
const multilineText = createMultilineText([
338
'LINE ONE',
339
'LINE TWO',
340
'LINE THREE'
341
]);
342
```
343
344
### Curved Text
345
346
Create text along curved paths:
347
348
```javascript
349
const { vectorChar } = require('@jscad/modeling').text;
350
const { degToRad, radToDeg } = require('@jscad/modeling').utils;
351
const { rotateZ, translate } = require('@jscad/modeling').transforms;
352
353
// Text along circular arc
354
const createArcText = (text, radius, startAngle = 0) => {
355
const chars = text.split('');
356
const angleStep = degToRad(15); // Angle between characters
357
358
return chars.map((char, index) => {
359
const angle = startAngle + (index * angleStep);
360
const x = Math.cos(angle) * radius;
361
const y = Math.sin(angle) * radius;
362
363
// Create character and position/rotate it
364
const charSegments = vectorChar({}, char);
365
return translate([x, y, 0],
366
rotateZ(angle + Math.PI/2, charSegments)
367
);
368
});
369
};
370
371
const arcText = createArcText('CURVED TEXT', 50, degToRad(0));
372
```
373
374
### Batch Processing Utilities
375
376
Process large datasets efficiently:
377
378
```javascript
379
const { flatten, areAllShapesTheSameType } = require('@jscad/modeling').utils;
380
const { union } = require('@jscad/modeling').booleans;
381
382
// Batch process shapes with validation
383
const batchProcess = (shapeGroups, operation) => {
384
const flatShapes = flatten(shapeGroups);
385
386
// Group by type
387
const groupedByType = {};
388
flatShapes.forEach(shape => {
389
const type = shape.type || 'unknown';
390
if (!groupedByType[type]) {
391
groupedByType[type] = [];
392
}
393
groupedByType[type].push(shape);
394
});
395
396
// Process each type group
397
const results = [];
398
Object.values(groupedByType).forEach(typeGroup => {
399
if (areAllShapesTheSameType(typeGroup)) {
400
results.push(operation(...typeGroup));
401
}
402
});
403
404
return results;
405
};
406
407
// Usage
408
const shapeGroups = [
409
[cube({ size: 1 }), cube({ size: 2 })],
410
[circle({ radius: 1 }), circle({ radius: 2 })]
411
];
412
const processed = batchProcess(shapeGroups, union);
413
```
414
415
### Performance Optimization
416
417
Optimize operations using utility functions:
418
419
```javascript
420
const { radiusToSegments, fnNumberSort } = require('@jscad/modeling').utils;
421
422
// Adaptive detail levels
423
const createAdaptiveDetail = (shapes) => {
424
return shapes.map(shape => {
425
if (shape.radius) {
426
const segments = radiusToSegments(shape.radius);
427
return { ...shape, segments };
428
}
429
return shape;
430
});
431
};
432
433
// Efficient sorting for geometric data
434
const sortGeometricData = (points) => {
435
// Sort by distance from origin
436
return points.sort((a, b) => {
437
const distA = Math.sqrt(a[0]*a[0] + a[1]*a[1]);
438
const distB = Math.sqrt(b[0]*b[0] + b[1]*b[1]);
439
return fnNumberSort(distA, distB);
440
});
441
};
442
```