@kitware/vtk.js
Version:
Visualization Toolkit for the Web
309 lines (277 loc) • 10.7 kB
JavaScript
import { m as macro } from '../../macros2.js';
import { FormatTypes, TextureCoordinatesName } from './PLYWriter/Constants.js';
const {
vtkErrorMacro,
vtkWarningMacro
} = macro;
// ----------------------------------------------------------------------------
// vtkPLYWriter methods
// ----------------------------------------------------------------------------
const writeHeader = (polyData, fileFormat, fileType, headerComments, textureFileName, textureCoordinatesName, vertexCount, faceListLength, withNormals, withUVs, withColors, withIndices) => {
const isBinary = fileFormat !== FormatTypes.ASCII;
let format;
if (isBinary) {
format = fileType ? 'binary_little_endian' : 'binary_big_endian';
} else format = 'ascii';
headerComments.unshift('VTK.js generated PLY File');
if (textureFileName) {
headerComments.push(`TextureFile ${textureFileName}`);
}
const commentElements = headerComments.map(comment => `comment ${comment}`).join('\n');
const header = ['ply', `format ${format} 1.0`, `${commentElements}`, `element vertex ${vertexCount}`, 'property float x', 'property float y', 'property float z'];
// normals
if (withNormals) {
header.push('property float nx', 'property float ny', 'property float nz');
}
// uvs
if (withUVs) {
header.push(`property float ${textureCoordinatesName[0]}`, `property float ${textureCoordinatesName[1]}`);
}
// colors
if (withColors) {
header.push('property uchar red', 'property uchar green', 'property uchar blue');
}
// faces
if (withIndices) {
header.push(`element face ${faceListLength}`, 'property list uchar int vertex_indices');
}
header.push('end_header\n');
return header.join('\n');
};
const binaryWriter = () => {
let output;
let vOffset;
let fOffset;
const indexByteCount = 4;
let ft;
return {
init: polyData => {},
writeHeader: (polyData, fileFormat, fileType, headerComments, textureFileName, textureCoordinatesName, numPts, numPolys, withNormals, withUVs, withColors, withIndices) => {
const vertexCount = polyData.getPoints().getNumberOfPoints();
ft = fileType;
// 1 byte shape descriptor
// 3 vertex indices at ${indexByteCount} bytes
const faceListLength = withIndices ? numPolys * (indexByteCount * 3 + 1) : 0;
// 3 position values at 4 bytes
// 3 normal values at 4 bytes
// 3 color channels with 1 byte
// 2 uv values at 4 bytes
const vertexListLength = vertexCount * (4 * 3 + (withNormals ? 4 * 3 : 0) + (withUVs ? 4 * 2 : 0) + (withColors ? 3 : 0));
const header = writeHeader(polyData, fileFormat, fileType, headerComments, textureFileName, textureCoordinatesName, numPts, numPolys, withNormals, withUVs, withColors, withIndices);
const headerBin = new TextEncoder().encode(header);
output = new DataView(new ArrayBuffer(headerBin.length + vertexListLength + faceListLength));
new Uint8Array(output.buffer).set(headerBin, 0);
vOffset = headerBin.length;
fOffset = vOffset + vertexListLength;
},
writeVertice: (x, y, z, nx, ny, nz, u, v, r, g, b) => {
// xyz
output.setFloat32(vOffset, x, ft);
vOffset += 4;
output.setFloat32(vOffset, y, ft);
vOffset += 4;
output.setFloat32(vOffset, z, ft);
vOffset += 4;
// nxnynz
if (nx !== null && ny !== null && nz !== null) {
output.setFloat32(vOffset, nx, ft);
vOffset += 4;
output.setFloat32(vOffset, ny, ft);
vOffset += 4;
output.setFloat32(vOffset, nz, ft);
vOffset += 4;
}
// uv
if (u !== null && v !== null) {
output.setFloat32(vOffset, u, ft);
vOffset += 4;
output.setFloat32(vOffset, v, ft);
vOffset += 4;
}
// rgb
if (r !== null && g !== null && b !== null) {
output.setUint8(vOffset, r);
vOffset += 1;
output.setUint8(vOffset, g);
vOffset += 1;
output.setUint8(vOffset, b);
vOffset += 1;
}
},
writeFace: (n, x, y, z) => {
output.setUint8(fOffset, n);
fOffset += 1;
output.setUint32(fOffset, x, ft);
fOffset += indexByteCount;
output.setUint32(fOffset, y, ft);
fOffset += indexByteCount;
output.setUint32(fOffset, z, ft);
fOffset += indexByteCount;
},
writeFooter: polyData => {},
getOutputData: () => output
};
};
const asciiWriter = () => {
let fileContent = '';
return {
init: polyData => {},
writeHeader: (polyData, fileFormat, fileType, headerComments, textureFileName, textureCoordinatesName, numPts, numPolys, withNormals, withUVs, withColors, withIndices) => {
fileContent += writeHeader(polyData, fileFormat, fileType, headerComments, textureFileName, textureCoordinatesName, numPts, numPolys, withNormals, withUVs, withColors, withIndices);
},
writeVertice: (x, y, z, nx, ny, nz, u, v, r, g, b) => {
fileContent += `${x} ${y} ${z}`;
if (nx !== null && ny !== null && nz !== null) {
fileContent += ` ${nx} ${ny} ${nz}`;
}
if (u !== null && v !== null) {
fileContent += ` ${u} ${v}`;
}
if (r !== null && g !== null && b !== null) {
fileContent += ` ${r} ${g} ${b}`;
}
fileContent += '\n';
},
writeFace: (n, x, y, z) => {
fileContent += `${n} ${x} ${y} ${z}\n`;
},
writeFooter: polyData => {},
getOutputData: () => fileContent
};
};
function writePLY(polyData, format, dataByteOrder, headerComments, textureFileName, textureCoordinatesName, transform, withNormals, withUVs, withColors, withIndices) {
const inPts = polyData.getPoints();
const polys = polyData.getPolys();
if (inPts === null || polys === null) {
vtkErrorMacro('No data to write!');
}
let writer = null;
if (format === FormatTypes.BINARY) {
writer = binaryWriter();
} else if (format === FormatTypes.ASCII) {
writer = asciiWriter();
} else {
vtkErrorMacro('Invalid type format');
}
let tCoordsName = textureCoordinatesName;
if (typeof textureCoordinatesName === 'undefined') {
vtkWarningMacro('Invalid TextureCoordinatesName value, fallback to default uv values');
tCoordsName = TextureCoordinatesName.UV;
}
writer.init(polyData);
const numPts = inPts.getNumberOfPoints();
const numPolys = polys.getNumberOfCells();
// textureCoords / uvs
const textureCoords = polyData.getPointData().getTCoords();
// eslint-disable-next-line no-param-reassign
withUVs = !(textureCoords === null);
// scalars / colors
const scalars = polyData.getPointData().getScalars();
// eslint-disable-next-line no-param-reassign
withColors = !(scalars === null);
const fileType = dataByteOrder ? 0 : 1;
writer.writeHeader(polyData, format, fileType, headerComments, textureFileName, tCoordsName, numPts, numPolys, withNormals, withUVs, withColors, withIndices);
const normals = polyData.getPointData().getNormals();
// points / vertices
for (let i = 0; i < numPts; i++) {
// eslint-disable-next-line prefer-const
let p = inPts.getPoint(i);
// coords
// divide by 1 to remove trailing zeros
const x = p[0].toPrecision(6) / 1;
const y = p[1].toPrecision(6) / 1;
const z = p[2].toPrecision(6) / 1;
// normals
let nx = null;
let ny = null;
let nz = null;
// uvs
let u = null;
let v = null;
// colors
let r = null;
let g = null;
let b = null;
if (textureCoords) {
u = textureCoords.getData()[i * 2];
v = textureCoords.getData()[i * 2 + 1];
}
if (scalars) {
r = scalars.getData()[i * 3];
g = scalars.getData()[i * 3 + 1];
b = scalars.getData()[i * 3 + 2];
}
if (normals) {
nx = normals.getData()[i * 3];
ny = normals.getData()[i * 3 + 1];
nz = normals.getData()[i * 3 + 2];
}
writer.writeVertice(x, y, z, nx, ny, nz, u, v, r, g, b);
}
// polys / indices
const pd = polys.getData();
for (let i = 0, l = pd.length; i < l; i += 4) {
writer.writeFace(pd[i + 0], pd[i + 1], pd[i + 2], pd[i + 3]);
}
writer.writeFooter(polyData);
return writer.getOutputData();
}
// ----------------------------------------------------------------------------
// Static API
// ----------------------------------------------------------------------------
const STATIC = {
writePLY
};
// ----------------------------------------------------------------------------
// vtkPLYWriter methods
// ----------------------------------------------------------------------------
function vtkPLYWriter(publicAPI, model) {
// Set our className
model.classHierarchy.push('vtkPLYWriter');
publicAPI.requestData = (inData, outData) => {
const input = inData[0];
if (!input || input.getClassName() !== 'vtkPolyData') {
vtkErrorMacro('Invalid or missing input');
return;
}
outData[0] = writePLY(input, model.format, model.dataByteOrder, model.headerComments, model.textureFileName, model.textureCoordinatesName, model.transform, model.withNormals, model.withUVs, model.withColors, model.withIndices);
};
}
// ----------------------------------------------------------------------------
// Object factory
// ----------------------------------------------------------------------------
const DEFAULT_VALUES = {
format: FormatTypes.ASCII,
dataByteOrder: 0,
headerComments: [],
textureFileName: null,
textureCoordinatesName: TextureCoordinatesName.UV,
transform: null,
withNormals: true,
withUVs: true,
withColors: true,
withIndices: true
};
// ----------------------------------------------------------------------------
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', 'dataByteOrder',
// binary_little_endian 0 binary_big_endian 1
'headerComments', 'textureFileName', 'textureCoordinatesName', 'transform', 'withNormals', 'withUVs', 'withColors', 'withIndices']);
// Object specific methods
vtkPLYWriter(publicAPI, model);
}
// ----------------------------------------------------------------------------
const newInstance = macro.newInstance(extend, 'vtkPLYWriter');
// ----------------------------------------------------------------------------
var vtkPLYWriter$1 = {
newInstance,
extend,
...STATIC
};
export { STATIC, vtkPLYWriter$1 as default, extend, newInstance };