@thewtex/vtk.js-esm
Version:
Visualization Toolkit for the Web
301 lines (238 loc) • 9.67 kB
JavaScript
import DataAccessHelper from '../Core/DataAccessHelper.js';
import macro from '../../macro.js';
import vtkCellArray from '../../Common/Core/CellArray.js';
import vtkDataArray from '../../Common/Core/DataArray.js';
import vtkPolyData from '../../Common/DataModel/PolyData.js';
import '../Core/DataAccessHelper/LiteHttpDataAccessHelper.js';
// import 'vtk.js/Sources/IO/Core/DataAccessHelper/HttpDataAccessHelper'; // HTTP + zip
// import 'vtk.js/Sources/IO/Core/DataAccessHelper/HtmlDataAccessHelper'; // html + base64 + zip
// import 'vtk.js/Sources/IO/Core/DataAccessHelper/JSZipDataAccessHelper'; // zip
var vtkErrorMacro = macro.vtkErrorMacro;
var decoderModule = {}; // ----------------------------------------------------------------------------
// static methods
// ----------------------------------------------------------------------------
/**
* Load the WASM decoder from url and set the decoderModule
* @param url
* @param binaryName
* @return {Promise<boolean>}
*/
function setWasmBinary(url, binaryName) {
var dracoDecoderType = {};
return new Promise(function (resolve, reject) {
dracoDecoderType.wasmBinaryFile = binaryName;
var xhr = new XMLHttpRequest();
xhr.open('GET', url, true);
xhr.responseType = 'arraybuffer';
xhr.onload = function () {
if (xhr.status === 200) {
dracoDecoderType.wasmBinary = xhr.response; // Use Promise.resolve to be compatible with versions before Draco 1.4.0
Promise.resolve(window.DracoDecoderModule(dracoDecoderType)).then(function (module) {
decoderModule = module;
resolve(true);
}, reject);
} else {
reject(Error("WASM binary could not be loaded: ".concat(xhr.statusText)));
}
};
xhr.send(null);
});
}
function setDracoDecoder(createDracoModule) {
decoderModule = createDracoModule({});
}
function getDracoDecoder() {
return decoderModule;
} // ----------------------------------------------------------------------------
// vtkDracoReader methods
// ----------------------------------------------------------------------------
function decodeBuffer(buffer) {
var byteArray = new Int8Array(buffer);
var decoder = new decoderModule.Decoder();
var decoderBuffer = new decoderModule.DecoderBuffer();
decoderBuffer.Init(byteArray, byteArray.length);
var geometryType = decoder.GetEncodedGeometryType(decoderBuffer);
var dracoGeometry;
if (geometryType === decoderModule.TRIANGULAR_MESH) {
dracoGeometry = new decoderModule.Mesh();
var status = decoder.DecodeBufferToMesh(decoderBuffer, dracoGeometry);
if (!status.ok()) {
vtkErrorMacro("Could not decode Draco file: ".concat(status.error_msg()));
}
} else {
vtkErrorMacro('Wrong geometry type, expected mesh, got point cloud.');
}
decoderModule.destroy(decoderBuffer);
decoderModule.destroy(decoder);
return dracoGeometry;
}
function getDracoAttributeAsFloat32Array(dracoGeometry, attributeId) {
var decoder = new decoderModule.Decoder();
var attribute = decoder.GetAttribute(dracoGeometry, attributeId);
var numberOfComponents = attribute.num_components();
var numberOfPoints = dracoGeometry.num_points();
var attributeData = new decoderModule.DracoFloat32Array();
decoder.GetAttributeFloatForAllPoints(dracoGeometry, attribute, attributeData);
var i = numberOfPoints * numberOfComponents;
var attributeArray = new Float32Array(i);
while (i--) {
attributeArray[i] = attributeData.GetValue(i);
}
return attributeArray;
}
function getPolyDataFromDracoGeometry(dracoGeometry) {
var decoder = new decoderModule.Decoder(); // Get position attribute ID
var positionAttributeId = decoder.GetAttributeId(dracoGeometry, decoderModule.POSITION);
if (positionAttributeId === -1) {
console.error('No position attribute found in the decoded model.');
decoderModule.destroy(decoder);
decoderModule.destroy(dracoGeometry);
return null;
}
var positionArray = getDracoAttributeAsFloat32Array(dracoGeometry, positionAttributeId); // Read indices
var i = dracoGeometry.num_faces();
var indices = new Uint32Array(i * 4);
var indicesArray = new decoderModule.DracoInt32Array();
while (i--) {
decoder.GetFaceFromMesh(dracoGeometry, i, indicesArray);
var index = i * 4;
indices[index] = 3;
indices[index + 1] = indicesArray.GetValue(0);
indices[index + 2] = indicesArray.GetValue(1);
indices[index + 3] = indicesArray.GetValue(2);
} // Create polyData and add positions and indinces
var cellArray = vtkCellArray.newInstance({
values: indices
});
var polyData = vtkPolyData.newInstance({
polys: cellArray
});
polyData.getPoints().setData(positionArray); // Look for other attributes
var pointData = polyData.getPointData(); // Normals
var normalAttributeId = decoder.GetAttributeId(dracoGeometry, decoderModule.NORMAL);
if (normalAttributeId !== -1) {
var normalArray = getDracoAttributeAsFloat32Array(dracoGeometry, decoderModule.NORMAL);
var normals = vtkDataArray.newInstance({
numberOfComponents: 3,
values: normalArray,
name: 'Normals'
});
pointData.setNormals(normals);
} // Texture coordinates
var texCoordAttributeId = decoder.GetAttributeId(dracoGeometry, decoderModule.TEX_COORD);
if (texCoordAttributeId !== -1) {
var texCoordArray = getDracoAttributeAsFloat32Array(dracoGeometry, texCoordAttributeId);
var texCoords = vtkDataArray.newInstance({
numberOfComponents: 2,
values: texCoordArray,
name: 'TCoords'
});
pointData.setTCoords(texCoords);
} // Scalars
var colorAttributeId = decoder.GetAttributeId(dracoGeometry, decoderModule.COLOR);
if (colorAttributeId !== -1) {
var colorArray = getDracoAttributeAsFloat32Array(dracoGeometry, colorAttributeId);
var scalars = vtkDataArray.newInstance({
numberOfComponents: 3,
values: colorArray,
name: 'Scalars'
});
pointData.setScalars(scalars);
}
decoderModule.destroy(decoder);
return polyData;
}
function vtkDracoReader(publicAPI, model) {
// Set our className
model.classHierarchy.push('vtkDracoReader'); // Create default dataAccessHelper if not available
if (!model.dataAccessHelper) {
model.dataAccessHelper = DataAccessHelper.get('http');
} // Internal method to fetch Array
function fetchData(url) {
var option = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
var compression = model.compression,
progressCallback = model.progressCallback;
if (option.binary) {
return model.dataAccessHelper.fetchBinary(url, {
compression: compression,
progressCallback: progressCallback
});
}
return model.dataAccessHelper.fetchText(publicAPI, url, {
compression: compression,
progressCallback: progressCallback
});
} // Set DataSet url
publicAPI.setUrl = function (url) {
var option = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {
binary: true
};
model.url = url; // Remove the file in the URL
var path = url.split('/');
path.pop();
model.baseURL = path.join('/');
model.compression = option.compression; // Fetch metadata
return publicAPI.loadData({
progressCallback: option.progressCallback,
binary: !!option.binary
});
}; // Fetch the actual data arrays
publicAPI.loadData = function () {
var option = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
var promise = fetchData(model.url, option);
promise.then(publicAPI.parse);
return promise;
};
publicAPI.parse = function (content) {
publicAPI.parseAsArrayBuffer(content);
};
publicAPI.parseAsArrayBuffer = function (content) {
if (!content) {
return;
}
if (content !== model.parseData) {
publicAPI.modified();
} else {
return;
}
model.parseData = content;
var dracoGeometry = decodeBuffer(content);
var polyData = getPolyDataFromDracoGeometry(dracoGeometry);
decoderModule.destroy(dracoGeometry);
model.output[0] = polyData;
};
publicAPI.requestData = function () {
publicAPI.parse(model.parseData);
};
} // ----------------------------------------------------------------------------
// Object factory
// ----------------------------------------------------------------------------
var DEFAULT_VALUES = {// baseURL: null,
// dataAccessHelper: null,
// url: null,
}; // ----------------------------------------------------------------------------
function extend(publicAPI, model) {
var initialValues = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
Object.assign(model, DEFAULT_VALUES, initialValues); // Build VTK API
macro.obj(publicAPI, model);
macro.get(publicAPI, model, ['url', 'baseURL']);
macro.setGet(publicAPI, model, ['dataAccessHelper']);
macro.algo(publicAPI, model, 0, 1); // vtkDracoReader methods
vtkDracoReader(publicAPI, model); // To support destructuring
if (!model.compression) {
model.compression = null;
}
if (!model.progressCallback) {
model.progressCallback = null;
}
} // ----------------------------------------------------------------------------
var newInstance = macro.newInstance(extend, 'vtkDracoReader'); // ----------------------------------------------------------------------------
var vtkDracoReader$1 = {
extend: extend,
newInstance: newInstance,
setDracoDecoder: setDracoDecoder,
setWasmBinary: setWasmBinary,
getDracoDecoder: getDracoDecoder
};
export default vtkDracoReader$1;
export { extend, newInstance };