@gridspace/raster-path 1.0.2

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,114 @@
1
+ // parse-stl.js
2
+ // Pure JavaScript STL parser (binary and ASCII)
3
+
4
+ // Calculate bounds from positions array
5
+ function calculateBounds(positions) {
6
+ let minX = Infinity, minY = Infinity, minZ = Infinity;
7
+ let maxX = -Infinity, maxY = -Infinity, maxZ = -Infinity;
8
+
9
+ for (let i = 0; i < positions.length; i += 3) {
10
+ const x = positions[i];
11
+ const y = positions[i + 1];
12
+ const z = positions[i + 2];
13
+
14
+ minX = Math.min(minX, x);
15
+ maxX = Math.max(maxX, x);
16
+ minY = Math.min(minY, y);
17
+ maxY = Math.max(maxY, y);
18
+ minZ = Math.min(minZ, z);
19
+ maxZ = Math.max(maxZ, z);
20
+ }
21
+
22
+ return {
23
+ min: { x: minX, y: minY, z: minZ },
24
+ max: { x: maxX, y: maxY, z: maxZ }
25
+ };
26
+ }
27
+
28
+ // Parse binary STL file
29
+ export function parseBinarySTL(buffer) {
30
+ const dataView = new DataView(buffer);
31
+
32
+ // Skip 80-byte header
33
+ const numTriangles = dataView.getUint32(80, true); // little-endian
34
+
35
+ const positions = new Float32Array(numTriangles * 9);
36
+ let offset = 84; // After header and triangle count
37
+
38
+ for (let i = 0; i < numTriangles; i++) {
39
+ // Skip normal (12 bytes)
40
+ offset += 12;
41
+
42
+ // Read 3 vertices (9 floats)
43
+ for (let j = 0; j < 9; j++) {
44
+ positions[i * 9 + j] = dataView.getFloat32(offset, true);
45
+ offset += 4;
46
+ }
47
+
48
+ // Skip attribute byte count (2 bytes)
49
+ offset += 2;
50
+ }
51
+
52
+ const bounds = calculateBounds(positions);
53
+ return { positions, triangleCount: numTriangles, bounds };
54
+ }
55
+
56
+ // Parse ASCII STL file
57
+ export function parseASCIISTL(text) {
58
+ const positions = [];
59
+ const lines = text.split('\n');
60
+ let inFacet = false;
61
+ const vertices = [];
62
+
63
+ for (const line of lines) {
64
+ const trimmed = line.trim();
65
+
66
+ if (trimmed.startsWith('facet')) {
67
+ inFacet = true;
68
+ vertices.length = 0;
69
+ } else if (trimmed.startsWith('vertex')) {
70
+ if (inFacet) {
71
+ const parts = trimmed.split(/\s+/);
72
+ vertices.push(
73
+ parseFloat(parts[1]),
74
+ parseFloat(parts[2]),
75
+ parseFloat(parts[3])
76
+ );
77
+ }
78
+ } else if (trimmed.startsWith('endfacet')) {
79
+ if (vertices.length === 9) {
80
+ positions.push(...vertices);
81
+ }
82
+ inFacet = false;
83
+ }
84
+ }
85
+
86
+ const positionsArray = new Float32Array(positions);
87
+ const bounds = calculateBounds(positionsArray);
88
+
89
+ return {
90
+ positions: positionsArray,
91
+ triangleCount: positions.length / 9,
92
+ bounds
93
+ };
94
+ }
95
+
96
+ // Auto-detect and parse STL file
97
+ export function parseSTL(buffer) {
98
+ // Try to detect if binary or ASCII
99
+ const view = new Uint8Array(buffer);
100
+ const header = String.fromCharCode(...view.slice(0, 5));
101
+
102
+ if (header === 'solid') {
103
+ // Might be ASCII, but could also be binary with "solid" in header
104
+ // Try to decode as text
105
+ const text = new TextDecoder().decode(buffer);
106
+ if (text.includes('facet') && text.includes('vertex')) {
107
+ // Looks like ASCII
108
+ return parseASCIISTL(text);
109
+ }
110
+ }
111
+
112
+ // Default to binary
113
+ return parseBinarySTL(buffer);
114
+ }