UNPKG

@kitware/vtk.js

Version:

Visualization Toolkit for the Web

189 lines (163 loc) 6.44 kB
import { vec3 } from 'gl-matrix'; import { m as macro } from '../../macros2.js'; import vtkTriangle from '../../Common/DataModel/Triangle.js'; import { FormatTypes } from './STLWriter/Constants.js'; // @author: Thomas Beznik <thomas.beznik@relu.eu>, with the help of Julien Finet <julien.finet@kitware.com> (https://github.com/Kitware/vtk-js/issues/1442) const { vtkErrorMacro } = macro; // ---------------------------------------------------------------------------- // Global methods // ---------------------------------------------------------------------------- function writeFloatBinary(dataView, offset, float) { dataView.setFloat32(offset, float.toPrecision(6), true); return offset + 4; } function writeVectorBinary(dataView, offset, vector) { let off = writeFloatBinary(dataView, offset, vector[0]); off = writeFloatBinary(dataView, off, vector[1]); return writeFloatBinary(dataView, off, vector[2]); } // ---------------------------------------------------------------------------- // vtkSTLWriter methods // ---------------------------------------------------------------------------- const binaryWriter = () => { let offset = 0; let dataView = null; return { init: polyData => { const polys = polyData.getPolys().getData(); const buffer = new ArrayBuffer(80 + 4 + 50 * polys.length / 4); // buffer for the full file; size = header (80) + num cells (4) + 50 bytes per poly dataView = new DataView(buffer); }, writeHeader: polyData => { offset += 80; // Header is empty // TODO: could add date, version, package // First need to write the number of cells dataView.setUint32(offset, polyData.getNumberOfCells(), true); offset += 4; }, writeTriangle: (v1, v2, v3, dn) => { offset = writeVectorBinary(dataView, offset, dn); offset = writeVectorBinary(dataView, offset, v1); offset = writeVectorBinary(dataView, offset, v2); offset = writeVectorBinary(dataView, offset, v3); offset += 2; // unused 'attribute byte count' is a Uint16 }, writeFooter: polyData => {}, getOutputData: () => dataView }; }; const asciiWriter = () => { let file = ''; return { init: polyData => {}, writeHeader: polyData => { file += 'solid ascii\n'; }, writeTriangle: (v1, v2, v3, dn) => { file += ` facet normal ${dn[0].toPrecision(6)} ${dn[1].toPrecision(6)} ${dn[2].toPrecision(6)}\n`; file += ' outer loop\n'; file += ` vertex ${v1[0].toPrecision(6)} ${v1[1].toPrecision(6)} ${v1[2].toPrecision(6)}\n`; file += ` vertex ${v2[0].toPrecision(6)} ${v2[1].toPrecision(6)} ${v2[2].toPrecision(6)}\n`; file += ` vertex ${v3[0].toPrecision(6)} ${v3[1].toPrecision(6)} ${v3[2].toPrecision(6)}\n`; file += ' endloop\n'; file += ' endfacet\n'; }, writeFooter: polyData => { file += 'endsolid\n'; }, getOutputData: () => file }; }; function writeSTL(polyData) { let format = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : FormatTypes.BINARY; let transform = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : null; let writer = null; if (format === FormatTypes.BINARY) { writer = binaryWriter(); } else if (format === FormatTypes.ASCII) { writer = asciiWriter(); } else { vtkErrorMacro('Invalid format type'); } writer.init(polyData); writer.writeHeader(polyData); const polys = polyData.getPolys().getData(); const points = polyData.getPoints().getData(); const strips = polyData.getStrips() ? polyData.getStrips().getData() : null; const n = []; let v1 = []; let v2 = []; let v3 = []; // Strips if (strips && strips.length > 0) { throw new Error('Unsupported strips'); } // Polys for (let i = 0; i < polys.length;) { const pointNumber = polys[i++]; if (pointNumber) { v1 = [points[polys[i] * 3], points[polys[i] * 3 + 1], points[polys[i++] * 3 + 2]]; v2 = [points[polys[i] * 3], points[polys[i] * 3 + 1], points[polys[i++] * 3 + 2]]; v3 = [points[polys[i] * 3], points[polys[i] * 3 + 1], points[polys[i++] * 3 + 2]]; if (transform) { vec3.transformMat4(v1, v1, transform); vec3.transformMat4(v2, v2, transform); vec3.transformMat4(v3, v3, transform); } vtkTriangle.computeNormal(v1, v2, v3, n); writer.writeTriangle(v1, v2, v3, n); } } writer.writeFooter(polyData); return writer.getOutputData(); } // ---------------------------------------------------------------------------- // Static API // ---------------------------------------------------------------------------- const STATIC = { writeSTL }; // ---------------------------------------------------------------------------- // vtkSTLWriter methods // ---------------------------------------------------------------------------- function vtkSTLWriter(publicAPI, model) { // Set our className model.classHierarchy.push('vtkSTLWriter'); publicAPI.requestData = (inData, outData) => { const input = inData[0]; if (!input || input.getClassName() !== 'vtkPolyData') { vtkErrorMacro('Invalid or missing input'); return; } outData[0] = writeSTL(input, model.format, model.transform); }; } // ---------------------------------------------------------------------------- // Object factory // ---------------------------------------------------------------------------- const DEFAULT_VALUES = { format: FormatTypes.BINARY, transform: null }; // ---------------------------------------------------------------------------- function extend(publicAPI, model) { let initialValues = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {}; Object.assign(model, DEFAULT_VALUES, initialValues); // Make this a VTK object macro.obj(publicAPI, model); // Also make it an algorithm with one input and one output macro.algo(publicAPI, model, 1, 1); macro.setGet(publicAPI, model, ['format', 'transform']); // Object specific methods vtkSTLWriter(publicAPI, model); } // ---------------------------------------------------------------------------- const newInstance = macro.newInstance(extend, 'vtkSTLWriter'); // ---------------------------------------------------------------------------- var vtkSTLWriter$1 = { newInstance, extend, ...STATIC }; export { STATIC, vtkSTLWriter$1 as default, extend, newInstance };