MCPcopy Create free account
hub / github.com/CNCKitchen/stlTexturizer / validateAndCleanGeometry

Function validateAndCleanGeometry

js/stlLoader.js:50–102  ·  view source on GitHub ↗

* Scan a non-indexed geometry's position array and remove: * - triangles with any non-finite (NaN / ±Infinity) coordinate * - degenerate triangles whose area is below 1e-12 mm² * * Operates in-place by compacting the Float32Array and replacing the * BufferAttribute. Any existing normal attr

(geometry)

Source from the content-addressed store, hash-verified

48 *
49 * Operates in-place by compacting the Float32Array and replacing the
50 * BufferAttribute. Any existing normal attribute is deleted so that
51 * setupGeometry will recompute it on the clean data.
52 *
53 * Returns { nanCount, degenerateCount } so callers can warn the user.
54 */
55function validateAndCleanGeometry(geometry) {
56 const pos = geometry.attributes.position;
57 const src = pos.array; // Float32Array, 9 floats per triangle
58 const triCount = src.length / 9;
59
60 let writeIdx = 0;
61 let nanCount = 0;
62 let degenerateCount = 0;
63
64 for (let t = 0; t < triCount; t++) {
65 const b = t * 9;
66 const ax = src[b], ay = src[b+1], az = src[b+2];
67 const bx = src[b+3], by = src[b+4], bz = src[b+5];
68 const cx = src[b+6], cy = src[b+7], cz = src[b+8];
69
70 if (!isFinite(ax) || !isFinite(ay) || !isFinite(az) ||
71 !isFinite(bx) || !isFinite(by) || !isFinite(bz) ||
72 !isFinite(cx) || !isFinite(cy) || !isFinite(cz)) {
73 nanCount++;
74 continue;
75 }
76
77 // Cross product of (B−A) × (C−A); skip if area² < 1e-24 (area < 1e-12)
78 const ux = bx-ax, uy = by-ay, uz = bz-az;
79 const vx = cx-ax, vy = cy-ay, vz = cz-az;
80 const area2 = (uy*vz-uz*vy)**2 + (uz*vx-ux*vz)**2 + (ux*vy-uy*vx)**2;
81 if (area2 < 1e-24) {
82 degenerateCount++;
83 continue;
84 }
85
86 if (writeIdx !== b) {
87 src[writeIdx] = ax; src[writeIdx+1] = ay; src[writeIdx+2] = az;
88 src[writeIdx+3] = bx; src[writeIdx+4] = by; src[writeIdx+5] = bz;
89 src[writeIdx+6] = cx; src[writeIdx+7] = cy; src[writeIdx+8] = cz;
90 }
91 writeIdx += 9;
92 }
93
94 const removed = nanCount + degenerateCount;
95 if (removed > 0) {
96 geometry.setAttribute('position', new THREE.BufferAttribute(src.slice(0, writeIdx), 3));
97 geometry.deleteAttribute('normal'); // stale — recomputed below
98 }
99
100 if (writeIdx === 0) {
101 throw new Error(
102 `All ${triCount} triangles in the mesh are invalid (${nanCount} NaN, ${degenerateCount} degenerate). Cannot load file.`
103 );
104 }
105

Callers 1

setupGeometryFunction · 0.85

Calls

no outgoing calls

Tested by

no test coverage detected