@thewtex/vtk.js-esm
Version:
Visualization Toolkit for the Web
213 lines (158 loc) • 6.61 kB
JavaScript
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 };