UNPKG

@thewtex/vtk.js-esm

Version:

Visualization Toolkit for the Web

213 lines (158 loc) 6.61 kB
import macro from '../../macro.js'; import vtkPolyData from '../../Common/DataModel/PolyData.js'; import vtkCaseTable from './ImageMarchingSquares/caseTable.js'; var vtkErrorMacro = macro.vtkErrorMacro, vtkDebugMacro = macro.vtkDebugMacro; // ---------------------------------------------------------------------------- // vtkImageMarchingSquares methods // ---------------------------------------------------------------------------- function vtkImageMarchingSquares(publicAPI, model) { // Set our className model.classHierarchy.push('vtkImageMarchingSquares'); publicAPI.getContourValues = function () { return model.contourValues; }; publicAPI.setContourValues = function (cValues) { model.contourValues = cValues; publicAPI.modified(); }; var ids = []; var pixelScalars = []; var pixelPts = []; var edgeMap = new Map(); // Retrieve scalars and pixel coordinates. i-j-k is origin of pixel. publicAPI.getPixelScalars = function (i, j, k, slice, dims, origin, spacing, s) { // First get the indices for the pixel ids[0] = k * slice + j * dims[0] + i; // i, j, k ids[1] = ids[0] + 1; // i+1, j, k ids[2] = ids[0] + dims[0]; // i, j+1, k ids[3] = ids[2] + 1; // i+1, j+1, k // Now retrieve the scalars for (var ii = 0; ii < 4; ++ii) { pixelScalars[ii] = s[ids[ii]]; } }; // Retrieve pixel coordinates. i-j-k is origin of pixel. publicAPI.getPixelPoints = function (i, j, k, dims, origin, spacing) { // (i,i+1),(j,j+1),(k,k+1) - i varies fastest; then j; then k pixelPts[0] = origin[0] + i * spacing[0]; // 0 pixelPts[1] = origin[1] + j * spacing[1]; pixelPts[2] = pixelPts[0] + spacing[0]; // 1 pixelPts[3] = pixelPts[1]; pixelPts[4] = pixelPts[0]; // 2 pixelPts[5] = pixelPts[1] + spacing[1]; pixelPts[6] = pixelPts[2]; // 3 pixelPts[7] = pixelPts[5]; }; publicAPI.produceLines = function (cVal, i, j, k, slice, dims, origin, spacing, scalars, points, lines) { var CASE_MASK = [1, 2, 8, 4]; // case table is actually for quad var xyz = []; var pId; var tmp; var edge = []; publicAPI.getPixelScalars(i, j, k, slice, dims, origin, spacing, scalars); var index = 0; for (var idx = 0; idx < 4; idx++) { if (pixelScalars[idx] >= cVal) { index |= CASE_MASK[idx]; // eslint-disable-line no-bitwise } } var pixelLines = vtkCaseTable.getCase(index); if (pixelLines[0] < 0) { return; // don't get the pixel coordinates, nothing to do } publicAPI.getPixelPoints(i, j, k, dims, origin, spacing); var z = origin[2] + k * spacing[2]; for (var _idx = 0; pixelLines[_idx] >= 0; _idx += 3) { lines.push(2); for (var eid = 0; eid < 2; eid++) { var edgeVerts = vtkCaseTable.getEdge(pixelLines[_idx + eid]); pId = undefined; if (model.mergePoints) { edge[0] = ids[edgeVerts[0]]; edge[1] = ids[edgeVerts[1]]; if (edge[0] > edge[1]) { tmp = edge[0]; edge[0] = edge[1]; edge[1] = tmp; } pId = edgeMap.get(edge); } if (pId === undefined) { var t = (cVal - pixelScalars[edgeVerts[0]]) / (pixelScalars[edgeVerts[1]] - pixelScalars[edgeVerts[0]]); var x0 = pixelPts.slice(edgeVerts[0] * 2, (edgeVerts[0] + 1) * 2); var x1 = pixelPts.slice(edgeVerts[1] * 2, (edgeVerts[1] + 1) * 2); xyz[0] = x0[0] + t * (x1[0] - x0[0]); xyz[1] = x0[1] + t * (x1[1] - x0[1]); pId = points.length / 3; points.push(xyz[0], xyz[1], z); if (model.mergePoints) { edge[0] = ids[edgeVerts[0]]; edge[1] = ids[edgeVerts[1]]; if (edge[0] > edge[1]) { tmp = edge[0]; edge[0] = edge[1]; edge[1] = tmp; } edgeMap[edge] = pId; } } lines.push(pId); } } }; publicAPI.requestData = function (inData, outData) { // implement requestData var input = inData[0]; if (!input) { vtkErrorMacro('Invalid or missing input'); return; } console.time('msquares'); // Retrieve output and volume data var origin = input.getOrigin(); var spacing = input.getSpacing(); var dims = input.getDimensions(); var s = input.getPointData().getScalars().getData(); // Points - dynamic array var pBuffer = []; // Cells - dynamic array var lBuffer = []; // Ensure slice is valid var slice = dims[0] * dims[1]; var k = Math.round(model.slice); if (k >= dims[2]) { k = 0; } // Loop over all contour values, and then pixels, determine case and process for (var cv = 0; cv < model.contourValues.length; ++cv) { for (var j = 0; j < dims[1] - 1; ++j) { for (var i = 0; i < dims[0] - 1; ++i) { publicAPI.produceLines(model.contourValues[cv], i, j, k, slice, dims, origin, spacing, s, pBuffer, lBuffer); } } edgeMap.clear(); } // Update output var polydata = vtkPolyData.newInstance(); polydata.getPoints().setData(new Float32Array(pBuffer), 3); polydata.getLines().setData(new Uint32Array(lBuffer)); outData[0] = polydata; vtkDebugMacro('Produced output'); console.timeEnd('msquares'); }; } // ---------------------------------------------------------------------------- // Object factory // ---------------------------------------------------------------------------- var DEFAULT_VALUES = { contourValues: [], slice: 0, mergePoints: false }; // ---------------------------------------------------------------------------- function extend(publicAPI, model) { var 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, ['slice', 'mergePoints']); // Object specific methods macro.algo(publicAPI, model, 1, 1); vtkImageMarchingSquares(publicAPI, model); } // ---------------------------------------------------------------------------- var newInstance = macro.newInstance(extend, 'vtkImageMarchingSquares'); // ---------------------------------------------------------------------------- var vtkImageMarchingSquares$1 = { newInstance: newInstance, extend: extend }; export default vtkImageMarchingSquares$1; export { extend, newInstance };