UNPKG

@kitware/vtk.js

Version:

Visualization Toolkit for the Web

228 lines (212 loc) 9.13 kB
import vtk from '../../vtk.js'; import { m as macro } from '../../macros2.js'; import vtkDataArray from '../../Common/Core/DataArray.js'; import vtkPoints from '../../Common/Core/Points.js'; import { FieldDataTypes } from '../../Common/DataModel/DataSet/Constants.js'; import { AttributeTypes } from '../../Common/DataModel/DataSetAttributes/Constants.js'; const { vtkWarningMacro } = macro; // ---------------------------------------------------------------------------- // vtkCalculator methods // ---------------------------------------------------------------------------- function vtkCalculator(publicAPI, model) { // Set our className model.classHierarchy.push('vtkCalculator'); publicAPI.setFormula = formula => { if (formula === model.formula) { return false; } model.formula = formula; publicAPI.modified(); return true; }; publicAPI.getFormula = () => model.formula; publicAPI.augmentInputArrays = (locn, arraysIn) => { const arraysOut = arraysIn.slice(0); // shallow-copy the inputs // Make point coordinates available whenever the field-data is associated with // points or graph vertices: if (locn === FieldDataTypes.POINT || locn === FieldDataTypes.VERTEX) { arraysOut.push({ location: FieldDataTypes.COORDINATE }); } // TODO: Make cell connectivity available when field-data is associated with // cells or graph edges. return arraysOut; }; publicAPI.createSimpleFormulaObject = function (locn, arrNames, resultName, singleValueFormula) { let options = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : {}; return { getArrays: inData => ({ // don't augment input data array in case of structured input dataset input: inData[0]?.isA('vtkImageData') ? arrNames.map(x => ({ location: locn, name: x })) : publicAPI.augmentInputArrays(locn, arrNames.map(x => ({ location: locn, name: x }))), output: [{ location: locn, name: resultName, attribute: 'outputAttributeType' in options ? options.outputAttributeType : AttributeTypes.SCALARS, numberOfComponents: 'numberOfOutputComponents' in options ? options.numberOfOutputComponents : 1 }] }), evaluate: (arraysIn, arraysOut) => { const tuples = new Array(arraysIn.length); const arrayInAccessors = arraysIn.map((x, jj) => { const nc = x.getNumberOfComponents(); const rawData = x.getData(); return nc === 1 ? ii => rawData[ii] : ii => x.getTuple(ii, tuples[jj]); }); const arrayOut = arraysOut[0]; const arrayOutRaw = arrayOut.getData(); const nc = arrayOut.getNumberOfComponents(); let tupleOut = new Array(nc); if (nc === 1) { arrayOutRaw.forEach((xxx, ii) => { arrayOutRaw[ii] = singleValueFormula(...arrayInAccessors.map(x => x(ii)), ii, tupleOut); }); } else { const nt = arrayOut.getNumberOfTuples(); for (let ii = 0; ii < nt; ++ii) { tupleOut = singleValueFormula(...arrayInAccessors.map(x => x(ii)), ii, tupleOut); arrayOut.setTuple(ii, tupleOut); } } } }; }; publicAPI.setFormulaSimple = function (locn, arrNames, resultName, formula) { let options = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : {}; return publicAPI.setFormula(publicAPI.createSimpleFormulaObject(locn, arrNames, resultName, formula, options)); }; publicAPI.prepareArrays = (arraySpec, inData, outData) => { const arraysIn = []; const arraysOut = []; arraySpec.input.forEach(spec => { if (spec.location === FieldDataTypes.COORDINATE) { arraysIn.push(inData.getPoints()); } else { const fetchArrayContainer = [[FieldDataTypes.UNIFORM, x => x.getFieldData()], [FieldDataTypes.POINT, x => x.getPointData()], [FieldDataTypes.CELL, x => x.getCellData()], [FieldDataTypes.VERTEX, x => x.getVertexData()], [FieldDataTypes.EDGE, x => x.getEdgeData()], [FieldDataTypes.ROW, x => x.getRowData()]].reduce((result, value) => { result[value[0]] = value[1]; return result; }, {}); const dsa = 'location' in spec && spec.location in fetchArrayContainer ? fetchArrayContainer[spec.location](inData) : null; if (dsa) { if (spec.name) { arraysIn.push(dsa.getArrayByName(spec.name)); } else if ('index' in spec) { arraysIn.push(dsa.getArrayByIndex(spec.index)); } else if ('attribute' in spec && spec.location !== FieldDataTypes.UNIFORM) { arraysIn.push(dsa.getActiveAttribute(spec.attribute)); } else { vtkWarningMacro(`No matching array for specifier "${JSON.stringify(spec)}".`); arraysIn.push(null); } } else { vtkWarningMacro(`Specifier "${JSON.stringify(spec)}" did not provide a usable location.`); arraysIn.push(null); } } }); arraySpec.output.forEach(spec => { const fullSpec = { ...spec }; const ncomp = 'numberOfComponents' in fullSpec ? fullSpec.numberOfComponents : 1; if (spec.location === FieldDataTypes.UNIFORM && 'tuples' in fullSpec) { fullSpec.size = ncomp * fullSpec.tuples; } if (spec.location === FieldDataTypes.COORDINATE) { const inPts = inData.getPoints(); const pts = vtkPoints.newInstance({ dataType: inPts.getDataType() }); pts.setNumberOfPoints(inPts.getNumberOfPoints(), inPts.getNumberOfComponents()); outData.setPoints(pts); arraysOut.push(pts); } else { const fetchArrayContainer = [[FieldDataTypes.UNIFORM, x => x.getFieldData(), (x, y) => 'tuples' in y ? y.tuples : 0], [FieldDataTypes.POINT, x => x.getPointData(), x => x.getNumberOfPoints()], [FieldDataTypes.CELL, x => x.getCellData(), x => x.getNumberOfCells()], [FieldDataTypes.VERTEX, x => x.getVertexData(), x => x.getNumberOfVertices()], [FieldDataTypes.EDGE, x => x.getEdgeData(), x => x.getNumberOfEdges()], [FieldDataTypes.ROW, x => x.getRowData(), x => x.getNumberOfRows()]].reduce((result, value) => { result[value[0]] = { getData: value[1], getSize: value[2] }; return result; }, {}); let dsa = null; let tuples = 0; if ('location' in spec && spec.location in fetchArrayContainer) { dsa = fetchArrayContainer[spec.location].getData(outData); tuples = fetchArrayContainer[spec.location].getSize(inData, fullSpec); } if (tuples <= 0) { vtkWarningMacro(`Output array size could not be determined for ${JSON.stringify(spec)}.`); arraysOut.push(null); } else if (dsa) { fullSpec.size = ncomp * tuples; const arrOut = vtkDataArray.newInstance(fullSpec); const arrIdx = dsa.addArray(arrOut); if ('attribute' in fullSpec && spec.location !== FieldDataTypes.UNIFORM) { dsa.setActiveAttributeByIndex(arrIdx, fullSpec.attribute); } arraysOut.push(arrOut); } else { vtkWarningMacro(`Specifier "${JSON.stringify(spec)}" did not provide a usable location.`); arraysOut.push(null); } } }); return { arraysIn, arraysOut }; }; publicAPI.requestData = (inData, outData) => { if (!model.formula) { return 0; } const arraySpec = model.formula.getArrays(inData); const newDataSet = outData[0]?.initialize() || vtk({ vtkClass: inData[0].getClassName() }); newDataSet.shallowCopy(inData[0]); outData[0] = newDataSet; const arrays = publicAPI.prepareArrays(arraySpec, inData[0], outData[0]); model.formula.evaluate(arrays.arraysIn, arrays.arraysOut); return 1; }; } // ---------------------------------------------------------------------------- // Object factory // ---------------------------------------------------------------------------- const DEFAULT_VALUES = { formula: { getArrays: () => ({ input: [], output: [] }), evaluate: () => null } }; // ---------------------------------------------------------------------------- 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); // Object specific methods vtkCalculator(publicAPI, model); } // ---------------------------------------------------------------------------- const newInstance = macro.newInstance(extend, 'vtkCalculator'); // ---------------------------------------------------------------------------- var vtkCalculator$1 = { newInstance, extend }; export { vtkCalculator$1 as default, extend, newInstance };