AppendPolyData

Introduction

vtkAppendPolyData - append one or more polygonal datasets together

vtkAppendPolyData is a filter that appends one of more polygonal datasets into a
single polygonal dataset. All geometry is extracted and appended, but point and
cell attributes (i.e., scalars, vectors, normals) are extracted and appended
only if all datasets have the point and/or cell attributes available. (For
example, if one dataset has point scalars but another does not, point scalars
will not be appended.)

Usage

Provide the first input to the filter via the standard
setInput(Data/Connection) methods. Any additional inputs can be provided via
the addInput(Data/Connection) methods. When only a single input is provided,
it is passed through as is to the output.

const cone = vtkConeSource.newInstance();
const cylinder = vtkCylinderSource.newInstance();

const appendPolyData = vtkAppendPolyData.newInstance();
appendPolyData.setInputConnection(cone.getOutputPort());
appendPolyData.addInputConnection(cylinder.getOutputPort());

const appendedData = appendPolyData.getOutputData();

Methods

extend

Method used to decorate a given object (publicAPI+model) with vtkAppendPolyData characteristics.

Argument Type Required Description
publicAPI Yes object on which methods will be bounds (public)
model Yes object on which data structure will be bounds (protected)
initialValues IAppendPolyDataInitialValues No (default: {})

getOutputPointsPrecision

Get the desired precision for the output types.

newInstance

Method used to create a new instance of vtkAppendPolyData

Argument Type Required Description
initialValues IAppendPolyDataInitialValues No for pre-setting some of its content

requestData

Argument Type Required Description
inData Yes
outData Yes

setOutputPointsPrecision

Set the desired precision for the output types.

Argument Type Required Description
outputPointsPrecision Yes

Source

index.d.ts
import { vtkAlgorithm, vtkObject } from '../../../interfaces';

export enum DesiredOutputPrecision {
/**
* Output precision should match the input precision
*/
DEFAULT,

/**
* Output single-precision floating-point (i.e. float32)
*/
SINGLE,

/**
* Output double-precision floating point (i.e. float64)
*/
DOUBLE,
}

/**
*
*/
export interface IAppendPolyDataInitialValues {
outputPointsPrecision?: DesiredOutputPrecision;
}

type vtkAppendPolyDataBase = vtkObject & vtkAlgorithm;

export interface vtkAppendPolyData extends vtkAppendPolyDataBase {
/**
* Get the desired precision for the output types.
*/
getOutputPointsPrecision(): DesiredOutputPrecision;

/**
* Set the desired precision for the output types.
* @param outputPointsPrecision
*/
setOutputPointsPrecision(
outputPointsPrecision: DesiredOutputPrecision
): boolean;

/**
*
* @param inData
* @param outData
*/
requestData(inData: any, outData: any): void;
}

/**
* Method used to decorate a given object (publicAPI+model) with vtkAppendPolyData characteristics.
*
* @param publicAPI object on which methods will be bounds (public)
* @param model object on which data structure will be bounds (protected)
* @param {IAppendPolyDataInitialValues} [initialValues] (default: {})
*/
export function extend(
publicAPI: object,
model: object,
initialValues?: IAppendPolyDataInitialValues
): void;

/**
* Method used to create a new instance of vtkAppendPolyData
* @param {IAppendPolyDataInitialValues} [initialValues] for pre-setting some of its content
*/
export function newInstance(
initialValues?: IAppendPolyDataInitialValues
): vtkAppendPolyData;

/**
* vtkAppendPolyData - append one or more polygonal datasets together
*
* vtkAppendPolyData is a filter that appends one of more polygonal datasets into a
* single polygonal dataset. All geometry is extracted and appended, but point and
* cell attributes (i.e., scalars, vectors, normals) are extracted and appended
* only if all datasets have the point and/or cell attributes available. (For
* example, if one dataset has point scalars but another does not, point scalars
* will not be appended.)
*
* @example
* Provide the first input to the filter via the standard
* `setInput(Data/Connection)` methods. Any additional inputs can be provided via
* the `addInput(Data/Connection)` methods. When only a single input is provided,
* it is passed through as is to the output.
*
* ```js
* const cone = vtkConeSource.newInstance();
* const cylinder = vtkCylinderSource.newInstance();
*
* const appendPolyData = vtkAppendPolyData.newInstance();
* appendPolyData.setInputConnection(cone.getOutputPort());
* appendPolyData.addInputConnection(cylinder.getOutputPort());
*
* const appendedData = appendPolyData.getOutputData();
* ```
*/
export declare const vtkAppendPolyData: {
newInstance: typeof newInstance;
extend: typeof extend;
};
export default vtkAppendPolyData;
index.js
import macro from 'vtk.js/Sources/macros';
import vtkDataArray from 'vtk.js/Sources/Common/Core/DataArray';
import vtkPoints from 'vtk.js/Sources/Common/Core/Points';
import vtkPolyData from 'vtk.js/Sources/Common/DataModel/PolyData';

import { DesiredOutputPrecision } from 'vtk.js/Sources/Common/DataModel/DataSetAttributes/Constants';
import { VtkDataTypes } from 'vtk.js/Sources/Common/Core/DataArray/Constants';

const { vtkErrorMacro } = macro;

function offsetCellArray(typedArray, offset) {
let currentIdx = 0;
return typedArray.map((value, index) => {
if (index === currentIdx) {
currentIdx += value + 1;
return value;
}
return value + offset;
});
}

function appendCellData(dest, src, ptOffset, cellOffset) {
dest.set(offsetCellArray(src, ptOffset), cellOffset);
}

// ----------------------------------------------------------------------------
// vtkAppendPolyData methods
// ----------------------------------------------------------------------------

function vtkAppendPolyData(publicAPI, model) {
// Set our classname
model.classHierarchy.push('vtkAppendPolyData');

publicAPI.requestData = (inData, outData) => {
// implement requestData
const numberOfInputs = publicAPI.getNumberOfInputPorts();
if (!numberOfInputs) {
vtkErrorMacro('No input specified.');
return;
}

if (numberOfInputs === 1) {
// pass through filter
outData[0] = inData[0];
return;
}

// Allocate output
const output = vtkPolyData.newInstance();

let numPts = 0;
let pointType = 0;
let ttype = 1;
let firstType = 1;
let numVerts = 0;
let numLines = 0;
let numStrips = 0;
let numPolys = 0;

// Field data is propagated to output only if present in all inputs
let hasPtNormals = true; // assume present by default
let hasPtTCoords = true;
let hasPtScalars = true;

for (let i = 0; i < numberOfInputs; i++) {
const ds = inData[i];
if (!ds) {
// eslint-disable-next-line
continue;
}
const dsNumPts = ds.getPoints().getNumberOfPoints();
numPts += dsNumPts;
numVerts += ds.getVerts().getNumberOfValues();
numLines += ds.getLines().getNumberOfValues();
numStrips += ds.getStrips().getNumberOfValues();
numPolys += ds.getPolys().getNumberOfValues();

if (dsNumPts) {
if (firstType) {
firstType = 0;
pointType = ds.getPoints().getDataType();
}
ttype = ds.getPoints().getDataType();
pointType = pointType > ttype ? pointType : ttype;
}

const ptD = ds.getPointData();
if (ptD) {
hasPtNormals = hasPtNormals && ptD.getNormals() !== null;
hasPtTCoords = hasPtTCoords && ptD.getTCoords() !== null;
hasPtScalars = hasPtScalars && ptD.getScalars() !== null;
} else {
hasPtNormals = false;
hasPtTCoords = false;
hasPtScalars = false;
}
}

if (model.outputPointsPrecision === DesiredOutputPrecision.SINGLE) {
pointType = VtkDataTypes.FLOAT;
} else if (model.outputPointsPrecision === DesiredOutputPrecision.DOUBLE) {
pointType = VtkDataTypes.DOUBLE;
}

const points = vtkPoints.newInstance({ dataType: pointType });
points.setNumberOfPoints(numPts);
const pointData = points.getData();

const vertData = new Uint32Array(numVerts);
const lineData = new Uint32Array(numLines);
const stripData = new Uint32Array(numStrips);
const polyData = new Uint32Array(numPolys);

let newPtNormals = null;
let newPtTCoords = null;
let newPtScalars = null;

const lds = inData[numberOfInputs - 1];
if (hasPtNormals) {
const dsNormals = lds.getPointData().getNormals();
newPtNormals = vtkDataArray.newInstance({
numberOfComponents: 3,
numberOfTuples: numPts,
size: 3 * numPts,
dataType: dsNormals.getDataType(),
name: dsNormals.getName(),
});
}
if (hasPtTCoords) {
const dsTCoords = lds.getPointData().getTCoords();
newPtTCoords = vtkDataArray.newInstance({
numberOfComponents: 2,
numberOfTuples: numPts,
size: 2 * numPts,
dataType: dsTCoords.getDataType(),
name: dsTCoords.getName(),
});
}
if (hasPtScalars) {
const dsScalars = lds.getPointData().getScalars();
newPtScalars = vtkDataArray.newInstance({
numberOfComponents: dsScalars.getNumberOfComponents(),
numberOfTuples: numPts,
size: numPts * dsScalars.getNumberOfComponents(),
dataType: dsScalars.getDataType(),
name: dsScalars.getName(),
});
}

numPts = 0;
numVerts = 0;
numLines = 0;
numStrips = 0;
numPolys = 0;
for (let i = 0; i < numberOfInputs; i++) {
const ds = inData[i];
pointData.set(ds.getPoints().getData(), numPts * 3);
appendCellData(vertData, ds.getVerts().getData(), numPts, numVerts);
numVerts += ds.getVerts().getNumberOfValues();
appendCellData(lineData, ds.getLines().getData(), numPts, numLines);
numLines += ds.getLines().getNumberOfValues();
appendCellData(stripData, ds.getStrips().getData(), numPts, numStrips);
numStrips += ds.getStrips().getNumberOfValues();
appendCellData(polyData, ds.getPolys().getData(), numPts, numPolys);
numPolys += ds.getPolys().getNumberOfValues();

const dsPD = ds.getPointData();
if (hasPtNormals) {
const ptNorms = dsPD.getNormals();
newPtNormals.getData().set(ptNorms.getData(), numPts * 3);
}
if (hasPtTCoords) {
const ptTCoords = dsPD.getTCoords();
newPtTCoords.getData().set(ptTCoords.getData(), numPts * 2);
}
if (hasPtScalars) {
const ptScalars = dsPD.getScalars();
newPtScalars
.getData()
.set(
ptScalars.getData(),
numPts * newPtScalars.getNumberOfComponents()
);
}

numPts += ds.getPoints().getNumberOfPoints();
}

output.setPoints(points);
output.getVerts().setData(vertData);
output.getLines().setData(lineData);
output.getStrips().setData(stripData);
output.getPolys().setData(polyData);
if (newPtNormals) {
output.getPointData().setNormals(newPtNormals);
}
if (newPtTCoords) {
output.getPointData().setTCoords(newPtTCoords);
}
if (newPtScalars) {
output.getPointData().setScalars(newPtScalars);
}
outData[0] = output;
};
}

// ----------------------------------------------------------------------------
// Object factory
// ----------------------------------------------------------------------------

const DEFAULT_VALUES = {
outputPointsPrecision: DesiredOutputPrecision.DEFAULT,
};

// ----------------------------------------------------------------------------

export function extend(publicAPI, model, initialValues = {}) {
Object.assign(model, DEFAULT_VALUES, initialValues);

// Build VTK API
macro.setGet(publicAPI, model, ['outputPointsPrecision']);

// 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
vtkAppendPolyData(publicAPI, model);
}

// ----------------------------------------------------------------------------

export const newInstance = macro.newInstance(extend, 'vtkAppendPolyData');

// ----------------------------------------------------------------------------

export default { newInstance, extend };