@kitware/vtk.js
Version:
Visualization Toolkit for the Web
189 lines (163 loc) • 6.44 kB
JavaScript
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 };