three-cad-viewer 4.3.4 → 4.3.6

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 (59) hide show
  1. package/dist/scene/clipping.d.ts +6 -0
  2. package/dist/three-cad-viewer.esm.js +20 -5
  3. package/dist/three-cad-viewer.esm.js.map +1 -1
  4. package/dist/three-cad-viewer.esm.min.js +1 -1
  5. package/dist/three-cad-viewer.js +20 -5
  6. package/dist/three-cad-viewer.min.js +1 -1
  7. package/package.json +2 -3
  8. package/src/_version.ts +0 -1
  9. package/src/camera/camera.ts +0 -445
  10. package/src/camera/controls/CADOrbitControls.ts +0 -241
  11. package/src/camera/controls/CADTrackballControls.ts +0 -598
  12. package/src/camera/controls.ts +0 -380
  13. package/src/core/patches.ts +0 -16
  14. package/src/core/studio-manager.ts +0 -652
  15. package/src/core/types.ts +0 -892
  16. package/src/core/viewer-state.ts +0 -784
  17. package/src/core/viewer.ts +0 -4821
  18. package/src/index.ts +0 -151
  19. package/src/rendering/environment.ts +0 -840
  20. package/src/rendering/light-detection.ts +0 -327
  21. package/src/rendering/material-factory.ts +0 -735
  22. package/src/rendering/material-presets.ts +0 -289
  23. package/src/rendering/raycast.ts +0 -291
  24. package/src/rendering/room-environment.ts +0 -192
  25. package/src/rendering/studio-composer.ts +0 -577
  26. package/src/rendering/studio-floor.ts +0 -108
  27. package/src/rendering/texture-cache.ts +0 -324
  28. package/src/rendering/tree-model.ts +0 -542
  29. package/src/rendering/triplanar.ts +0 -329
  30. package/src/scene/animation.ts +0 -343
  31. package/src/scene/axes.ts +0 -108
  32. package/src/scene/bbox.ts +0 -223
  33. package/src/scene/clipping.ts +0 -640
  34. package/src/scene/grid.ts +0 -864
  35. package/src/scene/nestedgroup.ts +0 -1444
  36. package/src/scene/objectgroup.ts +0 -866
  37. package/src/scene/orientation.ts +0 -259
  38. package/src/scene/render-shape.ts +0 -634
  39. package/src/tools/cad_tools/measure.ts +0 -811
  40. package/src/tools/cad_tools/select.ts +0 -100
  41. package/src/tools/cad_tools/tools.ts +0 -231
  42. package/src/tools/cad_tools/ui.ts +0 -454
  43. package/src/tools/cad_tools/zebra.ts +0 -369
  44. package/src/types/html.d.ts +0 -5
  45. package/src/types/n8ao.d.ts +0 -28
  46. package/src/types/three-augmentation.d.ts +0 -60
  47. package/src/ui/display.ts +0 -3295
  48. package/src/ui/index.html +0 -505
  49. package/src/ui/info.ts +0 -177
  50. package/src/ui/slider.ts +0 -206
  51. package/src/ui/toolbar.ts +0 -347
  52. package/src/ui/treeview.ts +0 -945
  53. package/src/utils/decode-instances.ts +0 -233
  54. package/src/utils/font.ts +0 -60
  55. package/src/utils/gpu-tracker.ts +0 -265
  56. package/src/utils/logger.ts +0 -92
  57. package/src/utils/sizeof.ts +0 -116
  58. package/src/utils/timer.ts +0 -69
  59. package/src/utils/utils.ts +0 -446
@@ -1,634 +0,0 @@
1
- /**
2
- * Shape tessellation and decomposition for rendering CAD objects.
3
- */
4
-
5
- import * as THREE from "three";
6
- import { NestedGroup } from "./nestedgroup.js";
7
- import { BoundingBox } from "./bbox.js";
8
- import { flatten } from "../utils/utils.js";
9
- import { hasTrianglesPerFace, hasSegmentsPerEdge } from "../core/types.js";
10
- import type { Shapes, Shape, VisibilityState } from "../core/types.js";
11
-
12
- // =============================================================================
13
- // Types
14
- // =============================================================================
15
-
16
- /**
17
- * Tree data structure for shape visibility navigation.
18
- * Maps object names to either nested tree data or visibility state.
19
- */
20
- interface ShapeTreeData {
21
- [key: string]: ShapeTreeData | VisibilityState;
22
- }
23
-
24
- /**
25
- * Result from rendering tessellated shapes.
26
- */
27
- interface RenderResult {
28
- group: NestedGroup;
29
- tree: ShapeTreeData;
30
- }
31
-
32
- /**
33
- * Configuration options for shape rendering.
34
- */
35
- interface ShapeRenderConfig {
36
- cadWidth: number;
37
- height: number;
38
- edgeColor: number;
39
- transparent: boolean;
40
- defaultOpacity: number;
41
- metalness: number;
42
- roughness: number;
43
- normalLen: number;
44
- }
45
-
46
- // =============================================================================
47
- // Helper Functions
48
- // =============================================================================
49
-
50
- /** Convert a hex color number to CSS hex string */
51
- function hexToColorString(hex: number | string): string {
52
- // If already a string with #, return as-is
53
- if (typeof hex === "string") {
54
- return hex.startsWith("#") ? hex : `#${hex}`;
55
- }
56
- return `#${hex.toString(16).padStart(6, "0")}`;
57
- }
58
-
59
- // =============================================================================
60
- // ShapeRenderer Class
61
- // =============================================================================
62
-
63
- /**
64
- * Handles tessellation and decomposition of CAD shapes for rendering.
65
- */
66
- class ShapeRenderer {
67
- private config: ShapeRenderConfig;
68
- private _bbox: BoundingBox | null = null;
69
-
70
- constructor(config: ShapeRenderConfig) {
71
- this.config = config;
72
- }
73
-
74
- /**
75
- * Get the computed bounding box (set after rendering if shapes.bb is defined).
76
- */
77
- get bbox(): BoundingBox | null {
78
- return this._bbox;
79
- }
80
-
81
- /**
82
- * Update configuration (e.g., when state changes).
83
- */
84
- updateConfig(config: Partial<ShapeRenderConfig>): void {
85
- this.config = { ...this.config, ...config };
86
- }
87
-
88
- /**
89
- * Render tessellated shapes of a CAD object.
90
- * @param shapes - The Shapes object representing the tessellated CAD object.
91
- * @returns A nested THREE.Group object.
92
- */
93
- private _renderTessellatedShapes(shapes: Shapes): NestedGroup {
94
- const nestedGroup = new NestedGroup(
95
- shapes,
96
- this.config.cadWidth,
97
- this.config.height,
98
- this.config.edgeColor,
99
- this.config.transparent,
100
- this.config.defaultOpacity,
101
- this.config.metalness,
102
- this.config.roughness,
103
- this.config.normalLen,
104
- );
105
- if (shapes.bb) {
106
- this._bbox = new BoundingBox(
107
- new THREE.Vector3(shapes.bb.xmin, shapes.bb.ymin, shapes.bb.zmin),
108
- new THREE.Vector3(shapes.bb.xmax, shapes.bb.ymax, shapes.bb.zmax),
109
- );
110
- }
111
- nestedGroup.render();
112
- return nestedGroup;
113
- }
114
-
115
- /**
116
- * Retrieve the navigation tree from a Shapes object.
117
- * @param shapes - The Shapes object.
118
- * @returns The navigation tree object.
119
- */
120
- private _getTree(shapes: Shapes): ShapeTreeData {
121
- const _getTree = (parts: Shapes[]): ShapeTreeData => {
122
- const result: ShapeTreeData = {};
123
- for (const part of parts) {
124
- if (part.parts != null) {
125
- result[part.name] = _getTree(part.parts);
126
- } else {
127
- result[part.name] = part.state as VisibilityState;
128
- }
129
- }
130
- return result;
131
- };
132
- const tree: ShapeTreeData = {};
133
- tree[shapes.name] = _getTree(shapes.parts ?? []);
134
- return tree;
135
- }
136
-
137
- /**
138
- * Decompose a CAD object into faces, edges and vertices.
139
- * @param part - The part to decompose.
140
- * @returns A decomposed part object.
141
- */
142
- private _decompose(part: Shapes): Shapes {
143
- const shape = part.shape!;
144
- let j: number;
145
-
146
- part.parts = [];
147
-
148
- if (part.type === "shapes") {
149
- // decompose faces
150
- const new_part: Shapes = {
151
- version: 2,
152
- name: "faces",
153
- id: `${part.id}/faces`,
154
- parts: [],
155
- loc: [
156
- [0, 0, 0],
157
- [0, 0, 0, 1],
158
- ],
159
- };
160
- let triangles: Uint32Array | number[];
161
- // _convertArrays must be called before _decompose to ensure TypedArrays
162
- if (!(shape.vertices instanceof Float32Array)) {
163
- throw new Error("_decompose requires shape.vertices to be Float32Array (call _convertArrays first)");
164
- }
165
- if (!(shape.normals instanceof Float32Array)) {
166
- throw new Error("_decompose requires shape.normals to be Float32Array (call _convertArrays first)");
167
- }
168
- const vertices = shape.vertices;
169
- const normals = shape.normals;
170
- const uvs = shape.uvs instanceof Float32Array ? shape.uvs : null;
171
- // Determine format and validate
172
- let current = 0;
173
- if (hasTrianglesPerFace(shape)) {
174
- // Binary format: flat Uint32Array with per-face counts
175
- if (!(shape.triangles instanceof Uint32Array)) {
176
- throw new Error("Expected Uint32Array for triangles in binary format");
177
- }
178
- const trianglesArray = shape.triangles;
179
- const perFace = shape.triangles_per_face;
180
- const num = perFace.length;
181
- for (j = 0; j < num; j++) {
182
- triangles = trianglesArray.subarray(
183
- current,
184
- current + 3 * perFace[j],
185
- );
186
- current += 3 * perFace[j];
187
-
188
- const vecs = new Float32Array(triangles.length * 3);
189
- const norms = new Float32Array(triangles.length * 3);
190
- const uvArr = uvs ? new Float32Array(triangles.length * 2) : null;
191
- for (let i = 0; i < triangles.length; i++) {
192
- const s = triangles[i];
193
- vecs[3 * i] = vertices[3 * s];
194
- vecs[3 * i + 1] = vertices[3 * s + 1];
195
- vecs[3 * i + 2] = vertices[3 * s + 2];
196
- norms[3 * i] = normals[3 * s];
197
- norms[3 * i + 1] = normals[3 * s + 1];
198
- norms[3 * i + 2] = normals[3 * s + 2];
199
- if (uvs && uvArr) {
200
- uvArr[2 * i] = uvs[2 * s];
201
- uvArr[2 * i + 1] = uvs[2 * s + 1];
202
- }
203
- }
204
- const newShapeObj: Shape = {
205
- triangles: [...Array(triangles.length).keys()],
206
- vertices: Array.from(vecs),
207
- normals: Array.from(norms),
208
- edges: [],
209
- obj_vertices: [],
210
- edge_types: [],
211
- face_types: [shape.face_types[j]],
212
- };
213
- if (uvArr) {
214
- newShapeObj.uvs = Array.from(uvArr);
215
- }
216
- const new_shape: Shapes = {
217
- version: 2,
218
- loc: [
219
- [0, 0, 0],
220
- [0, 0, 0, 1],
221
- ],
222
- name: `faces_${j}`,
223
- id: `${part.id}/faces/faces_${j}`,
224
- type: "shapes",
225
- color: part.color,
226
- alpha: part.alpha,
227
- renderback: part.subtype !== "solid",
228
- state: [1, 3],
229
- accuracy: part.accuracy,
230
- bb: null,
231
- shape: newShapeObj,
232
- };
233
- if (part.texture) {
234
- new_shape.texture = part.texture;
235
- }
236
- if (part.material) {
237
- new_shape.material = part.material;
238
- }
239
- new_shape.geomtype = shape.face_types[j];
240
- new_shape.subtype = part.subtype;
241
- new_shape.exploded = true;
242
- new_part.parts!.push(new_shape);
243
- }
244
- } else {
245
- // Non-binary format: nested number[][] arrays
246
- if (!Array.isArray(shape.triangles) || !Array.isArray(shape.triangles[0])) {
247
- throw new Error("Expected nested array for triangles in non-binary format");
248
- }
249
- // After validation, we know shape.triangles is number[][] (TypeScript can't infer this)
250
- const trianglesNested = shape.triangles as number[][];
251
- const num = trianglesNested.length;
252
- for (j = 0; j < num; j++) {
253
- triangles = trianglesNested[j];
254
-
255
- const vecs = new Float32Array(triangles.length * 3);
256
- const norms = new Float32Array(triangles.length * 3);
257
- const uvArr = uvs ? new Float32Array(triangles.length * 2) : null;
258
- for (let i = 0; i < triangles.length; i++) {
259
- const s = triangles[i];
260
- vecs[3 * i] = vertices[3 * s];
261
- vecs[3 * i + 1] = vertices[3 * s + 1];
262
- vecs[3 * i + 2] = vertices[3 * s + 2];
263
- norms[3 * i] = normals[3 * s];
264
- norms[3 * i + 1] = normals[3 * s + 1];
265
- norms[3 * i + 2] = normals[3 * s + 2];
266
- if (uvs && uvArr) {
267
- uvArr[2 * i] = uvs[2 * s];
268
- uvArr[2 * i + 1] = uvs[2 * s + 1];
269
- }
270
- }
271
- const newShapeObj2: Shape = {
272
- triangles: [...Array(triangles.length).keys()],
273
- vertices: Array.from(vecs),
274
- normals: Array.from(norms),
275
- edges: [],
276
- obj_vertices: [],
277
- edge_types: [],
278
- face_types: [shape.face_types[j]],
279
- };
280
- if (uvArr) {
281
- newShapeObj2.uvs = Array.from(uvArr);
282
- }
283
- const new_shape: Shapes = {
284
- version: 2,
285
- loc: [
286
- [0, 0, 0],
287
- [0, 0, 0, 1],
288
- ],
289
- name: `faces_${j}`,
290
- id: `${part.id}/faces/faces_${j}`,
291
- type: "shapes",
292
- color: part.color,
293
- alpha: part.alpha,
294
- renderback: part.subtype !== "solid",
295
- state: [1, 3],
296
- accuracy: part.accuracy,
297
- bb: null,
298
- shape: newShapeObj2,
299
- };
300
- if (part.texture) {
301
- new_shape.texture = part.texture;
302
- }
303
- if (part.material) {
304
- new_shape.material = part.material;
305
- }
306
- new_shape.geomtype = shape.face_types[j];
307
- new_shape.subtype = part.subtype;
308
- new_shape.exploded = true;
309
- new_part.parts!.push(new_shape);
310
- }
311
- }
312
-
313
- part.parts.push(new_part);
314
- }
315
-
316
- if (part.type === "shapes" || part.type === "edges") {
317
- // decompose edges
318
- const new_part: Shapes = {
319
- version: 2,
320
- parts: [],
321
- loc: [
322
- [0, 0, 0],
323
- [0, 0, 0, 1],
324
- ],
325
- name: "edges",
326
- id: `${part.id}/edges`,
327
- };
328
- // Check if multiColor (array of colors per edge)
329
- const multiColorArray = Array.isArray(part.color) ? part.color : null;
330
- let color: string | string[] | undefined;
331
- let edge: Float32Array | number[];
332
- let current = 0;
333
-
334
- if (hasSegmentsPerEdge(shape)) {
335
- // Binary format: flat Float32Array with per-edge counts
336
- if (!(shape.edges instanceof Float32Array)) {
337
- throw new Error("Expected Float32Array for edges in binary format");
338
- }
339
- const edgesArray = shape.edges;
340
- const perEdge = shape.segments_per_edge;
341
- const num = perEdge.length;
342
- for (j = 0; j < num; j++) {
343
- edge = edgesArray.subarray(current, current + 6 * perEdge[j]);
344
- current += 6 * perEdge[j];
345
- color = multiColorArray ? multiColorArray[j] : part.color;
346
- const new_shape: Shapes = {
347
- version: 2,
348
- loc: [
349
- [0, 0, 0],
350
- [0, 0, 0, 1],
351
- ],
352
- name: `edges_${j}`,
353
- id: `${part.id}/edges/edges_${j}`,
354
- type: "edges",
355
- color:
356
- part.type === "shapes"
357
- ? hexToColorString(this.config.edgeColor)
358
- : color,
359
- state: [3, 1],
360
- bb: null,
361
- shape: {
362
- edges: Array.from(edge),
363
- vertices: [],
364
- normals: [],
365
- triangles: [],
366
- obj_vertices: [],
367
- edge_types: [shape.edge_types[j]],
368
- face_types: [],
369
- },
370
- };
371
- new_shape.width = part.type === "shapes" ? 1 : part.width;
372
- new_shape.geomtype = shape.edge_types[j];
373
- new_part.parts!.push(new_shape);
374
- }
375
- } else {
376
- // Non-binary format: nested number[][] arrays
377
- const edgesRaw = shape.edges;
378
- if (!Array.isArray(edgesRaw) || (edgesRaw.length > 0 && !Array.isArray(edgesRaw[0]))) {
379
- throw new Error("Expected nested array for edges in non-binary format");
380
- }
381
- // After validation, we know this is number[][] (TypeScript can't infer from the check)
382
- const edgesNested = edgesRaw as number[][];
383
- const num = edgesNested.length;
384
- for (j = 0; j < num; j++) {
385
- edge = edgesNested[j];
386
- color = multiColorArray ? multiColorArray[j] : part.color;
387
- const new_shape: Shapes = {
388
- version: 2,
389
- loc: [
390
- [0, 0, 0],
391
- [0, 0, 0, 1],
392
- ],
393
- name: `edges_${j}`,
394
- id: `${part.id}/edges/edges_${j}`,
395
- type: "edges",
396
- color:
397
- part.type === "shapes"
398
- ? hexToColorString(this.config.edgeColor)
399
- : color,
400
- state: [3, 1],
401
- bb: null,
402
- shape: {
403
- edges: edge,
404
- vertices: [],
405
- normals: [],
406
- triangles: [],
407
- obj_vertices: [],
408
- edge_types: [shape.edge_types[j]],
409
- face_types: [],
410
- },
411
- };
412
- new_shape.width = part.type === "shapes" ? 1 : part.width;
413
- new_shape.geomtype = shape.edge_types[j];
414
- new_part.parts!.push(new_shape);
415
- }
416
- }
417
- if (new_part.parts!.length > 0) {
418
- part.parts.push(new_part);
419
- }
420
- }
421
-
422
- // decompose vertices
423
- const new_part: Shapes = {
424
- version: 2,
425
- parts: [],
426
- loc: [
427
- [0, 0, 0],
428
- [0, 0, 0, 1],
429
- ],
430
- name: "vertices",
431
- id: `${part.id}/vertices`,
432
- };
433
- const vertices = shape.obj_vertices;
434
- for (j = 0; j < vertices.length / 3; j++) {
435
- const new_shape: Shapes = {
436
- version: 2,
437
- loc: [
438
- [0, 0, 0],
439
- [0, 0, 0, 1],
440
- ],
441
- name: `vertices_${j}`,
442
- id: `${part.id}/vertices/vertices_${j}`,
443
- type: "vertices",
444
- color:
445
- part.type === "shapes" || part.type === "edges"
446
- ? hexToColorString(this.config.edgeColor)
447
- : part.color,
448
- state: [3, 1],
449
- bb: null,
450
- shape: {
451
- obj_vertices: [
452
- vertices[3 * j],
453
- vertices[3 * j + 1],
454
- vertices[3 * j + 2],
455
- ],
456
- vertices: [],
457
- normals: [],
458
- triangles: [],
459
- edges: [],
460
- edge_types: [],
461
- face_types: [],
462
- },
463
- };
464
- new_shape.size =
465
- part.type === "shapes" || part.type === "edges" ? 4 : part.size;
466
- new_part.parts!.push(new_shape);
467
- }
468
- if (new_part.parts!.length > 0) {
469
- part.parts.push(new_part);
470
- }
471
- delete part.shape;
472
- delete part.color;
473
- delete part.alpha;
474
- delete part.accuracy;
475
- delete part.renderback;
476
-
477
- return part;
478
- }
479
-
480
- /**
481
- * Convert Shape arrays to TypedArrays for efficient rendering.
482
- * Note: This mutates the shape in place.
483
- */
484
- private _convertArrays(shape: Shape): void {
485
- // Mutable interface to allow TypedArray assignment
486
- interface MutableShape {
487
- triangles: number[] | number[][] | Uint32Array;
488
- edges: number[] | number[][] | Float32Array;
489
- vertices: number[] | Float32Array;
490
- normals: number[] | number[][] | Float32Array;
491
- obj_vertices: number[] | Float32Array;
492
- face_types: number[] | Uint32Array;
493
- edge_types: number[] | Uint8Array | Uint32Array;
494
- triangles_per_face?: number[] | Uint32Array;
495
- segments_per_edge?: number[] | Uint32Array;
496
- uvs?: number[] | Float32Array;
497
- }
498
-
499
- // Shape interface matches MutableShape - we cast to allow reassignment
500
- const s: MutableShape = shape;
501
-
502
- // triangles: flat array or nested array -> Uint32Array
503
- // Note: Only flat triangles (with triangles_per_face) are converted here.
504
- // Nested triangles (number[][]) are kept as-is for _decompose to handle.
505
- if (s.triangles != null && !(s.triangles instanceof Uint32Array)) {
506
- // Only convert if it's a flat number[] (has triangles_per_face)
507
- if (s.triangles_per_face !== undefined) {
508
- if (!Array.isArray(s.triangles[0])) {
509
- s.triangles = new Uint32Array(s.triangles as number[]);
510
- }
511
- }
512
- // If no triangles_per_face, leave as number[][] for _decompose
513
- }
514
-
515
- // edges: nested number[][] -> Float32Array (flattened)
516
- // Only flatten if it's actually nested (no segments_per_edge means nested format)
517
- if (s.edges != null && !(s.edges instanceof Float32Array)) {
518
- if (s.segments_per_edge !== undefined) {
519
- if (!Array.isArray(s.edges[0])) {
520
- // Flat number[] — convert directly
521
- s.edges = new Float32Array(s.edges as number[]);
522
- } else {
523
- // Nested number[][] with segments_per_edge — flatten then convert
524
- s.edges = new Float32Array(flatten(s.edges as number[][], 1));
525
- }
526
- }
527
- // If no segments_per_edge, leave as number[][] for _decompose
528
- }
529
-
530
- // vertices: always flat number[] -> Float32Array
531
- if (s.vertices != null && !(s.vertices instanceof Float32Array)) {
532
- s.vertices = new Float32Array(s.vertices as number[]);
533
- }
534
-
535
- // normals: flat or nested -> Float32Array
536
- // Only process if there are normals (non-empty array)
537
- if (s.normals != null && !(s.normals instanceof Float32Array)) {
538
- if (Array.isArray(s.normals) && s.normals.length > 0) {
539
- if (Array.isArray(s.normals[0])) {
540
- // Nested format: flatten first
541
- s.normals = new Float32Array(flatten(s.normals as number[][], 2));
542
- } else {
543
- // Already flat
544
- s.normals = new Float32Array(s.normals as number[]);
545
- }
546
- }
547
- }
548
-
549
- // obj_vertices: always flat number[] -> Float32Array
550
- if (s.obj_vertices != null && !(s.obj_vertices instanceof Float32Array)) {
551
- s.obj_vertices = new Float32Array(s.obj_vertices as number[]);
552
- }
553
-
554
- // uvs: flat number[] -> Float32Array (2 floats per vertex)
555
- if (s.uvs != null && !(s.uvs instanceof Float32Array)) {
556
- s.uvs = new Float32Array(s.uvs as number[]);
557
- }
558
-
559
- // face_types: number[] -> Uint32Array
560
- if (s.face_types != null && !(s.face_types instanceof Uint32Array)) {
561
- s.face_types = new Uint32Array(s.face_types);
562
- }
563
-
564
- // edge_types: number[] or Uint8Array -> Uint32Array
565
- if (s.edge_types != null && !(s.edge_types instanceof Uint32Array)) {
566
- if (s.edge_types instanceof Uint8Array) {
567
- s.edge_types = new Uint32Array(s.edge_types);
568
- } else {
569
- s.edge_types = new Uint32Array(s.edge_types);
570
- }
571
- }
572
-
573
- // triangles_per_face: number[] -> Uint32Array
574
- if (
575
- s.triangles_per_face != null &&
576
- !(s.triangles_per_face instanceof Uint32Array)
577
- ) {
578
- s.triangles_per_face = new Uint32Array(s.triangles_per_face);
579
- }
580
-
581
- // segments_per_edge: number[] -> Uint32Array
582
- if (
583
- s.segments_per_edge != null &&
584
- !(s.segments_per_edge instanceof Uint32Array)
585
- ) {
586
- s.segments_per_edge = new Uint32Array(s.segments_per_edge);
587
- }
588
- }
589
-
590
- /**
591
- * Recursively process shapes, converting arrays and decomposing parts.
592
- */
593
- private _processShapes(shapes: Shapes): Shapes {
594
- if (shapes.version === 2 || shapes.version === 3) {
595
- const parts: Shapes[] = [];
596
- for (let i = 0; i < (shapes.parts?.length ?? 0); i++) {
597
- const part = shapes.parts![i];
598
- if (part.shape != null) {
599
- this._convertArrays(part.shape);
600
- }
601
- if (part.parts != null) {
602
- const tmp = this._processShapes(part);
603
- parts.push(tmp);
604
- } else {
605
- parts.push(this._decompose(part));
606
- }
607
- }
608
- shapes.parts = parts;
609
- }
610
- return shapes;
611
- }
612
-
613
- /**
614
- * Render the shapes of the CAD object.
615
- * @param exploded - Whether to render the compact or exploded version
616
- * @param shapes - The Shapes object.
617
- * @returns A nested THREE.Group object and navigation tree.
618
- */
619
- render(exploded: boolean, shapes: Shapes): RenderResult {
620
- let processedShapes: Shapes;
621
- if (exploded) {
622
- processedShapes = this._processShapes(structuredClone(shapes));
623
- } else {
624
- processedShapes = structuredClone(shapes);
625
- }
626
- const group = this._renderTessellatedShapes(processedShapes);
627
- const tree = this._getTree(processedShapes);
628
-
629
- return { group, tree };
630
- }
631
- }
632
-
633
- export { ShapeRenderer };
634
- export type { ShapeTreeData, RenderResult, ShapeRenderConfig };