scadr
Version:
Render multi-part OpenSCAD files to STL
115 lines (114 loc) • 4.08 kB
JavaScript
;
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.parseSTL = void 0;
/**
* Parse STL file (binary or ASCII format) into a list of triangles
*/
function parseSTL(filePath) {
return __awaiter(this, void 0, void 0, function* () {
const fs = require("node:fs/promises");
const buffer = yield fs.readFile(filePath);
// Check if it's ASCII STL by looking for "solid" at the beginning
const header = buffer.toString('ascii', 0, 5);
if (header === 'solid') {
return parseASCIISTL(buffer);
}
else {
return parseBinarySTL(buffer);
}
});
}
exports.parseSTL = parseSTL;
function parseASCIISTL(buffer) {
const content = buffer.toString('utf8');
const triangles = [];
const lines = content.split('\n').map(line => line.trim());
let i = 0;
// Skip header line (solid name)
while (i < lines.length && !lines[i].startsWith('facet normal')) {
i++;
}
while (i < lines.length) {
const line = lines[i];
if (line.startsWith('facet normal')) {
const normalParts = line.split(/\s+/).slice(2);
const normal = [
parseFloat(normalParts[0]),
parseFloat(normalParts[1]),
parseFloat(normalParts[2])
];
i++; // Skip "outer loop"
i++;
const vertices = [
[0, 0, 0], [0, 0, 0], [0, 0, 0]
];
// Read 3 vertices
for (let v = 0; v < 3; v++) {
const vertexLine = lines[i];
const vertexParts = vertexLine.split(/\s+/).slice(1);
vertices[v] = [
parseFloat(vertexParts[0]),
parseFloat(vertexParts[1]),
parseFloat(vertexParts[2])
];
i++;
}
triangles.push({ normal, vertices });
i++; // Skip "endloop"
i++; // Skip "endfacet"
}
else {
i++;
}
}
return { triangles };
}
function parseBinarySTL(buffer) {
const triangles = [];
// Skip 80-byte header
let offset = 80;
// Read number of triangles (4 bytes, little endian)
const numTriangles = buffer.readUInt32LE(offset);
offset += 4;
for (let i = 0; i < numTriangles; i++) {
// Read normal (3 floats, 12 bytes)
const normal = [
buffer.readFloatLE(offset),
buffer.readFloatLE(offset + 4),
buffer.readFloatLE(offset + 8)
];
offset += 12;
// Read 3 vertices (9 floats, 36 bytes)
const vertices = [
[
buffer.readFloatLE(offset),
buffer.readFloatLE(offset + 4),
buffer.readFloatLE(offset + 8)
],
[
buffer.readFloatLE(offset + 12),
buffer.readFloatLE(offset + 16),
buffer.readFloatLE(offset + 20)
],
[
buffer.readFloatLE(offset + 24),
buffer.readFloatLE(offset + 28),
buffer.readFloatLE(offset + 32)
]
];
offset += 36;
// Skip attribute byte count (2 bytes)
offset += 2;
triangles.push({ normal, vertices });
}
return { triangles };
}