PolyData

Introduction

vtkPolyData creates an m x n array of quadrilaterals arranged as a regular
tiling in a plane. The plane is defined by specifying an origin point, and then
two other points that, together with the origin, define two axes for the plane.
These axes do not have to be orthogonal - so you can create a parallelogram.
(The axes must not be parallel.) The resolution of the plane (i.e., number of
subdivisions) is controlled by the ivars XResolution and YResolution.

By default, the plane is centered at the origin and perpendicular to the z-axis,
with width and height of length 1 and resolutions set to 1.

Methods

buildCells

Create data structure that allows random access of cells.

buildLinks

Create upward links from points to cells that use each point. Enables
topologically complex queries.

Argument Type Required Description
initialSize Yes {Number}

extend

Method used to decorate a given object (publicAPI+model) with vtkPolyData 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 IPolyDataInitialValues No (default: {})

getCell

If you know the type of cell, you may provide it to improve performances.

Argument Type Required Description
cellId Yes
cellHint Yes

getCellEdgeNeighbors

Get the neighbors at an edge.

Argument Type Required Description
cellId Yes
point1 Yes
point2 Yes

getCellPoints

Get a list of point ids that define a cell.

Argument Type Required Description
cellId Yes {Number}

getCells

Get the cell array defining cells.

getLines

Get the cell array defining lines.

getLinks

getNumberOfCells

Determine the number of cells composing the polydata.

getNumberOfLines

Determine the number of lines composing the polydata.

getNumberOfPoints

Determine the number of points composing the polydata.

getNumberOfPolys

Determine the number of polys composing the polydata.

getNumberOfStrips

Determine the number of strips composing the polydata.

getNumberOfVerts

Determine the number of vertices composing the polydata.

getPointCells

Topological inquiry to get cells using point.

Argument Type Required Description
ptId Yes

getPolys

Get the cell array defining polys.

getStrips

Get the cell array defining strips.

getVerts

Get the cell array defining vertices. If there are no vertices, an empty
array will be returned (convenience to simplify traversal).

newInstance

Method used to create a new instance of vtkPolyData.

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

setLines

Set the cell array defining lines.

Argument Type Required Description
lines Yes {vtkCellArray}

setPolys

Set the cell array defining polys.

Argument Type Required Description
polys Yes {vtkCellArray}

setStrips

Set the cell array defining strips.

Argument Type Required Description
strips Yes {vtkCellArray}

setVerts

Set the cell array defining vertices.

Argument Type Required Description
verts Yes {vtkCellArray}

Source

Constants.js
export const POLYDATA_FIELDS = ['verts', 'lines', 'polys', 'strips'];

export default {
POLYDATA_FIELDS,
};
index.d.ts
import { vec3 } from 'gl-matrix';
import vtkCellArray from 'vtk.js/Sources/Common/Core/CellArray';
import vtkPointSet from 'vtk.js/Sources/Common/DataModel/PointSet';

/**
*
*/
interface IPolyDataInitialValues {
}


export interface vtkPolyData extends vtkPointSet {

/**
* Create data structure that allows random access of cells.
*/
buildCells(): void;

/**
* Create upward links from points to cells that use each point. Enables
* topologically complex queries.
* @param initialSize {Number}
*/
buildLinks(initialSize?: number): void;

/**
* If you know the type of cell, you may provide it to improve performances.
* @param cellId
* @param cellHint
*/
getCell(cellId: any, cellHint: any): void;

/**
* Get the neighbors at an edge.
* @param cellId
* @param point1
* @param point2
*/
getCellEdgeNeighbors(cellId: any, point1: any, point2: any): void;

/**
* Get a list of point ids that define a cell.
* @param cellId {Number}
* @return an object made of the cellType and a subarray `cellPointIds` of the cell points.
*/
getCellPoints(cellId: number): object;

/**
* Get the cell array defining cells.
*/
getCells(): vtkCellArray;

/**
* Get the cell array defining lines.
*/
getLines(): vtkCellArray;

/**
*
*/
getLinks(): any;

/**
* Determine the number of cells composing the polydata.
*/
getNumberOfCells(): number;

/**
* Determine the number of lines composing the polydata.
*/
getNumberOfLines(): number;

/**
* Determine the number of points composing the polydata.
*/
getNumberOfPoints(): number;

/**
* Determine the number of polys composing the polydata.
*/
getNumberOfPolys(): number;

/**
* Determine the number of strips composing the polydata.
*/
getNumberOfStrips(): number;

/**
* Determine the number of vertices composing the polydata.
*/
getNumberOfVerts(): number;

/**
* Topological inquiry to get cells using point.
* @param ptId
*/
getPointCells(ptId: any): void;

/**
* Get the cell array defining polys.
*/
getPolys(): vtkCellArray;

/**
* Get the cell array defining strips.
*/
getStrips(): vtkCellArray;

/**
* Get the cell array defining vertices. If there are no vertices, an empty
* array will be returned (convenience to simplify traversal).
*/
getVerts(): vtkCellArray;

/**
* Set the cell array defining lines.
* @param lines {vtkCellArray}
*/
setLines(lines: vtkCellArray): boolean;

/**
* Set the cell array defining polys.
* @param polys {vtkCellArray}
*/
setPolys(polys: vtkCellArray): boolean;

/**
* Set the cell array defining strips.
* @param strips {vtkCellArray}
*/
setStrips(strips: vtkCellArray): boolean;

/**
* Set the cell array defining vertices.
* @param verts {vtkCellArray}
*/
setVerts(verts: vtkCellArray): boolean;
}

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

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

/**
* vtkPolyData creates an m x n array of quadrilaterals arranged as a regular
* tiling in a plane. The plane is defined by specifying an origin point, and then
* two other points that, together with the origin, define two axes for the plane.
* These axes do not have to be orthogonal - so you can create a parallelogram.
* (The axes must not be parallel.) The resolution of the plane (i.e., number of
* subdivisions) is controlled by the ivars XResolution and YResolution.
*
* By default, the plane is centered at the origin and perpendicular to the z-axis,
* with width and height of length 1 and resolutions set to 1.
*/
export declare const vtkPolyData: {
newInstance: typeof newInstance,
extend: typeof extend,
};
export default vtkPolyData;
index.js
import macro from 'vtk.js/Sources/macro';
import vtk from 'vtk.js/Sources/vtk';
import vtkCellArray from 'vtk.js/Sources/Common/Core/CellArray';
import vtkCellLinks from 'vtk.js/Sources/Common/DataModel/CellLinks';
import vtkCellTypes from 'vtk.js/Sources/Common/DataModel/CellTypes';
import vtkLine from 'vtk.js/Sources/Common/DataModel/Line';
import vtkPointSet from 'vtk.js/Sources/Common/DataModel/PointSet';
import vtkTriangle from 'vtk.js/Sources/Common/DataModel/Triangle';

import { CellType } from 'vtk.js/Sources/Common/DataModel/CellTypes/Constants';
import { POLYDATA_FIELDS } from 'vtk.js/Sources/Common/DataModel/PolyData/Constants';

const { vtkWarningMacro } = macro;

export const CELL_FACTORY = {
[CellType.VTK_LINE]: vtkLine,
[CellType.VTK_POLY_LINE]: vtkLine,
[CellType.VTK_TRIANGLE]: vtkTriangle,
};

// ----------------------------------------------------------------------------
// vtkPolyData methods
// ----------------------------------------------------------------------------

function vtkPolyData(publicAPI, model) {
// Set our className
model.classHierarchy.push('vtkPolyData');

function camelize(str) {
return str
.replace(/(?:^\w|[A-Z]|\b\w)/g, (letter) => letter.toUpperCase())
.replace(/\s+/g, '');
}

// build empty cell arrays and set methods
POLYDATA_FIELDS.forEach((type) => {
publicAPI[`getNumberOf${camelize(type)}`] = () =>
model[type].getNumberOfCells();
if (!model[type]) {
model[type] = vtkCellArray.newInstance();
} else {
model[type] = vtk(model[type]);
}
});

publicAPI.getNumberOfCells = () =>
POLYDATA_FIELDS.reduce(
(num, cellType) => num + model[cellType].getNumberOfCells(),
0
);

const superShallowCopy = publicAPI.shallowCopy;
publicAPI.shallowCopy = (other, debug = false) => {
superShallowCopy(other, debug);
POLYDATA_FIELDS.forEach((type) => {
model[type] = vtkCellArray.newInstance();
model[type].shallowCopy(other.getReferenceByName(type));
});
};

publicAPI.buildCells = () => {
// here are the number of cells we have
const nVerts = publicAPI.getNumberOfVerts();
const nLines = publicAPI.getNumberOfLines();
const nPolys = publicAPI.getNumberOfPolys();
const nStrips = publicAPI.getNumberOfStrips();

// pre-allocate the space we need
const nCells = nVerts + nLines + nPolys + nStrips;

const types = new Uint8Array(nCells);
let pTypes = types;
const locs = new Uint32Array(nCells);
let pLocs = locs;

// record locations and type of each cell.
// verts
if (nVerts) {
let nextCellPts = 0;
model.verts.getCellSizes().forEach((numCellPts, index) => {
pLocs[index] = nextCellPts;
pTypes[index] =
numCellPts > 1 ? CellType.VTK_POLY_VERTEX : CellType.VTK_VERTEX;
nextCellPts += numCellPts + 1;
});

pLocs = pLocs.subarray(nVerts);
pTypes = pTypes.subarray(nVerts);
}

// lines
if (nLines) {
let nextCellPts = 0;
model.lines.getCellSizes().forEach((numCellPts, index) => {
pLocs[index] = nextCellPts;
pTypes[index] =
numCellPts > 2 ? CellType.VTK_POLY_LINE : CellType.VTK_LINE;
if (numCellPts === 1) {
vtkWarningMacro(
'Building VTK_LINE ',
index,
' with only one point, but VTK_LINE needs at least two points. Check the input.'
);
}
nextCellPts += numCellPts + 1;
});

pLocs = pLocs.subarray(nLines);
pTypes = pTypes.subarray(nLines);
}

// polys
if (nPolys) {
let nextCellPts = 0;
model.polys.getCellSizes().forEach((numCellPts, index) => {
pLocs[index] = nextCellPts;
switch (numCellPts) {
case 3:
pTypes[index] = CellType.VTK_TRIANGLE;
break;
case 4:
pTypes[index] = CellType.VTK_QUAD;
break;
default:
pTypes[index] = CellType.VTK_POLYGON;
break;
}
if (numCellPts < 3) {
vtkWarningMacro(
'Building VTK_TRIANGLE ',
index,
' with less than three points, but VTK_TRIANGLE needs at least three points. Check the input.'
);
}
nextCellPts += numCellPts + 1;
});

pLocs += pLocs.subarray(nPolys);
pTypes += pTypes.subarray(nPolys);
}

// strips
if (nStrips) {
let nextCellPts = 0;
pTypes.fill(CellType.VTK_TRIANGLE_STRIP, 0, nStrips);

model.strips.getCellSizes().forEach((numCellPts, index) => {
pLocs[index] = nextCellPts;
nextCellPts += numCellPts + 1;
});
}

// set up the cell types data structure
model.cells = vtkCellTypes.newInstance();
model.cells.setCellTypes(nCells, types, locs);
};

/**
* Create upward links from points to cells that use each point. Enables
* topologically complex queries.
*/
publicAPI.buildLinks = (initialSize = 0) => {
if (model.cells === undefined) {
publicAPI.buildCells();
}

model.links = vtkCellLinks.newInstance();
if (initialSize > 0) {
model.links.allocate(initialSize);
} else {
model.links.allocate(publicAPI.getPoints().getNumberOfPoints());
}

model.links.buildLinks(publicAPI);
};

// Returns an object made of the cellType and a subarray `cellPointIds` of
// the cell points.
publicAPI.getCellPoints = (cellId) => {
const cellType = model.cells.getCellType(cellId);
let cells = null;
switch (cellType) {
case CellType.VTK_VERTEX:
case CellType.VTK_POLY_VERTEX:
cells = model.verts;
break;

case CellType.VTK_LINE:
case CellType.VTK_POLY_LINE:
cells = model.lines;
break;

case CellType.VTK_TRIANGLE:
case CellType.VTK_QUAD:
case CellType.VTK_POLYGON:
cells = model.polys;
break;

case CellType.VTK_TRIANGLE_STRIP:
cells = model.strips;
break;

default:
cells = null;
return { type: 0, cellPointIds: null };
}
const loc = model.cells.getCellLocation(cellId);
const cellPointIds = cells.getCell(loc);
return { cellType, cellPointIds };
};

publicAPI.getPointCells = (ptId) => model.links.getCells(ptId);

publicAPI.getCellEdgeNeighbors = (cellId, point1, point2) => {
const link1 = model.links.getLink(point1);
const link2 = model.links.getLink(point2);

return link1.cells.filter(
(cell) => cell !== cellId && link2.cells.indexOf(cell) !== -1
);
};

/**
* If you know the type of cell, you may provide it to improve performances.
*/
publicAPI.getCell = (cellId, cellHint = null) => {
const cellInfo = publicAPI.getCellPoints(cellId);
const cell = cellHint || CELL_FACTORY[cellInfo.cellType].newInstance();
cell.initialize(publicAPI.getPoints(), cellInfo.cellPointIds);
return cell;
};
}

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

const DEFAULT_VALUES = {
// verts: null,
// lines: null,
// polys: null,
// strips: null,
// cells: null,
// links: null,
};

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

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

// Inheritance
vtkPointSet.extend(publicAPI, model, initialValues);
macro.get(publicAPI, model, ['cells', 'links']);
macro.setGet(publicAPI, model, ['verts', 'lines', 'polys', 'strips']);

// Object specific methods
vtkPolyData(publicAPI, model);
}

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

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

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

export default { newInstance, extend };