UNPKG

@kitware/vtk.js

Version:

Visualization Toolkit for the Web

309 lines (277 loc) 10.7 kB
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 };