@kitware/vtk.js
Version:
Visualization Toolkit for the Web
228 lines (212 loc) • 9.13 kB
JavaScript
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 };