ContourLoopExtraction

Introduction

vtkContourLoopExtraction specific static methods.

Methods

extend

Method use to decorate a given object (publicAPI+model) with vtkContourLoopExtraction characteristics.

Argument Type Required Description
publicAPI Yes - Object on which methods will be bound (public).
model Yes - Object on which data structure will be bound (protected).
initialValues Yes - (Optional) Initial values to assign to the model.

extractContours

Extracts contour loops from the given polydata input and populates the given output.

Argument Type Required Description
input Yes - The input polydata
output Yes - The output polydata

newInstance

Method used to create a new instance of vtkContourLoopExtraction.

Argument Type Required Description
initialValues Yes - (Optional) Initial values for the instance.

requestData

Runs the contour extraction algorithm with the given input and output data.

Argument Type Required Description
inData Yes - The input data for the contour extraction.
outData Yes - The output data where the extracted contours will be stored.

traverseLoop

Traverses a loop starting from a given line and point, in a specified direction.

Argument Type Required Description
pd Yes - The polydata which to traverse.
dir Yes - The direction of traversal.
startLineId Yes - The ID of the starting line.
startPtId Yes - The ID of the starting point.
loopPoints Yes - The array to store the traversed points of the loop.

Returns

Type Description
The last point ID after traversal.

Source

index.d.ts
import { vtkAlgorithm, vtkObject } from '../../../interfaces';
import vtkPolyData from '../../../Common/DataModel/PolyData';
/**
* Initial configuration values for vtkContourLoopExtraction instances.
*/
export interface IContourLoopExtractionInitialValues {}

type vtkContourLoopExtractionBase = vtkObject & vtkAlgorithm;

export interface vtkContourLoopExtraction extends vtkContourLoopExtractionBase {
/**
* Runs the contour extraction algorithm with the given input and output data.
* @param inData - The input data for the contour extraction.
* @param outData - The output data where the extracted contours will be stored.
*/
requestData(inData: vtkPolyData[], outData: vtkPolyData[]): void;

/**
* Extracts contour loops from the given polydata input and populates the given output.
* @param input - The input polydata
* @param output - The output polydata
*/
extractContours(input: vtkPolyData, output: vtkPolyData): void;

/**
* Traverses a loop starting from a given line and point, in a specified direction.
* @param pd - The polydata which to traverse.
* @param dir - The direction of traversal.
* @param startLineId - The ID of the starting line.
* @param startPtId - The ID of the starting point.
* @param loopPoints - The array to store the traversed points of the loop.
* @returns The last point ID after traversal.
*/
traverseLoop(
pd: vtkPolyData,
dir: number,
startLineId: number,
startPtId: number,
loopPoints: Array<{ t: number; ptId: number }>
): number;
}

// ----------------------------------------------------------------------------
// Static API
// ----------------------------------------------------------------------------

/**
* Method use to decorate a given object (publicAPI+model) with vtkContourLoopExtraction characteristics.
*
* @param publicAPI - Object on which methods will be bound (public).
* @param model - Object on which data structure will be bound (protected).
* @param initialValues - (Optional) Initial values to assign to the model.
*/
export function extend(
publicAPI: object,
model: object,
initialValues?: IContourLoopExtractionInitialValues
): void;

/**
* Method used to create a new instance of vtkContourLoopExtraction.
*
* @param initialValues - (Optional) Initial values for the instance.
*/
export function newInstance(
initialValues?: IContourLoopExtractionInitialValues
): vtkContourLoopExtraction;

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

/**
* vtkContourLoopExtraction specific static methods.
*/
export declare const vtkContourLoopExtraction: {
newInstance: typeof newInstance;
extend: typeof extend;
};

export default vtkContourLoopExtraction;
index.js
import macro from 'vtk.js/Sources/macros';
import vtkPolyData from 'vtk.js/Sources/Common/DataModel/PolyData';

const Dir = {
Forward: 1,
Backward: -1,
};

const visited = new Set();

function vtkContourLoopExtraction(publicAPI, model) {
publicAPI.requestData = (inData, outData) => {
const [input] = inData;

if (!outData[0]) {
outData[0] = vtkPolyData.newInstance();
}
const [output] = outData;
publicAPI.extractContours(input, output);
output.modified();
};

publicAPI.traverseLoop = (pd, dir, startLineId, startPtId, loopPoints) => {
let lineId = startLineId;
let lastPtId = startPtId;
let terminated = false;
let numInserted = 0;

while (!terminated) {
const { cellPointIds } = pd.getCellPoints(lineId);
if (!cellPointIds) {
// eslint-disable-next-line no-continue
continue;
}

lastPtId =
cellPointIds[0] !== lastPtId ? cellPointIds[0] : cellPointIds[1];
numInserted++;

// parametric point value
const t = dir * numInserted;
loopPoints.push({ t, ptId: lastPtId });

const lineCell = pd.getPointCells(lastPtId);

if (lineCell.length !== 2 || lastPtId === startPtId) {
// looped
return lastPtId;
}

if (lineCell.length === 2) {
// continue along loop
lineId = lineCell[0] !== lineId ? lineCell[0] : lineCell[1];
visited.add(lineId);
} else {
// empty or invalid cell
terminated = true;
}
}

return lastPtId;
};

publicAPI.extractContours = (input, output) => {
const loops = [];
visited.clear();

const inLines = input.getLines();
output.getPoints().setData(Float32Array.from(input.getPoints().getData()));

// TODO skip if cached input mtime hasn't changed.
// iterate over input lines
for (let li = 0; li < inLines.getNumberOfCells(); li++) {
if (visited.has(li)) {
// eslint-disable-next-line no-continue
continue;
}

const { cellPointIds } = input.getCellPoints(li);
if (!cellPointIds) {
// eslint-disable-next-line no-continue
continue;
}

visited.add(li);
const startPtId = cellPointIds[0];

const loopPoints = [];
loopPoints.push({ t: 0, ptId: startPtId });

const endPtId = publicAPI.traverseLoop(
input,
Dir.Forward,
li,
startPtId,
loopPoints
);

if (startPtId !== endPtId) {
// didn't find a loop. Go other direction to see where we end up
publicAPI.traverseLoop(input, Dir.Backward, li, startPtId, loopPoints);
loopPoints.sort((a, b) => (a.t < b.t ? -1 : 1));
// make closed contour
if (
loopPoints.length &&
loopPoints[0].ptId !== loopPoints[loopPoints.length - 1]?.ptId
) {
loopPoints.push({ ...loopPoints[loopPoints.length - 1] });
}
}

if (loopPoints.length) {
loops.push(loopPoints);
}
}

// clear output lines
const outLines = output.getLines();
outLines.resize(0);

loops.forEach((loop) => {
outLines.insertNextCell(loop.map((pt) => pt.ptId));
});
};
}

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

const DEFAULT_VALUES = {};

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

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

macro.obj(publicAPI, model);
macro.algo(publicAPI, model, 1, 1);

vtkContourLoopExtraction(publicAPI, model);
}

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

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

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

export default { newInstance, extend };