@kitware/vtk.js
Version:
Visualization Toolkit for the Web
786 lines (745 loc) • 27.9 kB
JavaScript
import { m as macro } from '../../macros2.js';
import vtkCellArray from '../../Common/Core/CellArray.js';
import vtkDataArray from '../../Common/Core/DataArray.js';
import { l as normalize, j as cross, n as norm, d as dot, f as distance2BetweenPoints } from '../../Common/Core/Math/index.js';
import vtkPoints from '../../Common/Core/Points.js';
import vtkPolyData from '../../Common/DataModel/PolyData.js';
import { DesiredOutputPrecision } from '../../Common/DataModel/DataSetAttributes/Constants.js';
import { VtkDataTypes } from '../../Common/Core/DataArray/Constants.js';
import Constants from './TubeFilter/Constants.js';
const {
VaryRadius,
GenerateTCoords
} = Constants;
const {
vtkDebugMacro,
vtkErrorMacro,
vtkWarningMacro
} = macro;
// ----------------------------------------------------------------------------
// vtkTubeFilter methods
// ----------------------------------------------------------------------------
function vtkTubeFilter(publicAPI, model) {
// Set our classname
model.classHierarchy.push('vtkTubeFilter');
function computeOffset(offset, npts) {
let newOffset = offset;
if (model.sidesShareVertices) {
newOffset += model.numberOfSides * npts;
} else {
// points are duplicated
newOffset += 2 * model.numberOfSides * npts;
}
if (model.capping) {
// cap points are duplicated
newOffset += 2 * model.numberOfSides;
}
return newOffset;
}
function findNextValidSegment(points, pointIds, start) {
const ptId = pointIds[start];
const ps = points.slice(3 * ptId, 3 * (ptId + 1));
let end = start + 1;
while (end < pointIds.length) {
const endPtId = pointIds[end];
const pe = points.slice(3 * endPtId, 3 * (endPtId + 1));
if (ps !== pe) {
return end - 1;
}
++end;
}
return pointIds.length;
}
function generateSlidingNormals(pts, lines, normals, firstNormal = null) {
let normal = [0.0, 0.0, 1.0];
const lineData = lines;
// lid = 0;
let npts = lineData[0];
for (let i = 0; i < lineData.length; i += npts + 1) {
npts = lineData[i];
if (npts === 1) {
// return arbitrary
normals.setTuple(lineData[i + 1], normal);
} else if (npts > 1) {
let sNextId = 0;
let sPrev = [0, 0, 0];
const sNext = [0, 0, 0];
const linePts = lineData.slice(i + 1, i + 1 + npts);
sNextId = findNextValidSegment(pts, linePts, 0);
if (sNextId !== npts) {
// at least one valid segment
let pt1Id = linePts[sNextId];
let pt1 = pts.slice(3 * pt1Id, 3 * (pt1Id + 1));
let pt2Id = linePts[sNextId + 1];
let pt2 = pts.slice(3 * pt2Id, 3 * (pt2Id + 1));
sPrev = pt2.map((elem, idx) => elem - pt1[idx]);
normalize(sPrev);
// compute first normal
if (firstNormal) {
normal = firstNormal;
} else {
// find the next valid, non-parallel segment
while (++sNextId < npts) {
sNextId = findNextValidSegment(pts, linePts, sNextId);
if (sNextId !== npts) {
pt1Id = linePts[sNextId];
pt1 = pts.slice(3 * pt1Id, 3 * (pt1Id + 1));
pt2Id = linePts[sNextId + 1];
pt2 = pts.slice(3 * pt2Id, 3 * (pt2Id + 1));
for (let j = 0; j < 3; ++j) {
sNext[j] = pt2[j] - pt1[j];
}
normalize(sNext);
// now the starting normal should simply be the cross product.
// In the following if statement, we check for the case where
// the two segments are parallel, in which case, continue
// searching for the next valid segment
const n = [0.0, 0.0, 0.0];
cross(sPrev, sNext, n);
if (norm(n) > 1.0e-3) {
normal = n;
sPrev = sNext;
break;
}
}
}
if (sNextId >= npts) {
// only one valid segment
// a little trick to find orthogonal normal
for (let j = 0; j < 3; ++j) {
if (sPrev[j] !== 0.0) {
normal[(j + 2) % 3] = 0.0;
normal[(j + 1) % 3] = 1.0;
normal[j] = -sPrev[(j + 1) % 3] / sPrev[j];
break;
}
}
}
}
normalize(normal);
// compute remaining normals
let lastNormalId = 0;
while (++sNextId < npts) {
sNextId = findNextValidSegment(pts, linePts, sNextId);
if (sNextId === npts) {
break;
}
pt1Id = linePts[sNextId];
pt1 = pts.slice(3 * pt1Id, 3 * (pt1Id + 1));
pt2Id = linePts[sNextId + 1];
pt2 = pts.slice(3 * pt2Id, 3 * (pt2Id + 1));
for (let j = 0; j < 3; ++j) {
sNext[j] = pt2[j] - pt1[j];
}
normalize(sNext);
// compute rotation vector
const w = [0.0, 0.0, 0.0];
cross(sPrev, normal, w);
if (normalize(w) !== 0.0) {
// can't use this segment otherwise
const q = [0.0, 0.0, 0.0];
cross(sNext, sPrev, q);
if (normalize(q) !== 0.0) {
// can't use this segment otherwise
const f1 = dot(q, normal);
let f2 = 1.0 - f1 * f1;
if (f2 > 0.0) {
f2 = Math.sqrt(f2);
} else {
f2 = 0.0;
}
const c = [0, 0, 0];
for (let j = 0; j < 3; ++j) {
c[j] = sNext[j] + sPrev[j];
}
normalize(c);
cross(c, q, w);
cross(sPrev, q, c);
if (dot(normal, c) * dot(w, c) < 0.0) {
f2 *= -1.0;
}
// insert current normal before updating
for (let j = lastNormalId; j < sNextId; ++j) {
normals.setTuple(linePts[j], normal);
}
lastNormalId = sNextId;
sPrev = sNext;
// compute next normal
normal = f1 * q + f2 * w;
}
}
}
// insert last normal for the remaining points
for (let j = lastNormalId; j < npts; ++j) {
normals.setTuple(linePts[j], normal);
}
} else {
// no valid segments
for (let j = 0; j < npts; ++j) {
normals.setTuple(linePts[j], normal);
}
}
}
}
return 1;
}
function generatePoints(offset, npts, pts, inPts, newPts, pd, outPD, newNormals, inScalars, range, inVectors, maxSpeed, inNormals, theta) {
// Use averaged segment to create beveled effect.
const sNext = [0.0, 0.0, 0.0];
const sPrev = [0.0, 0.0, 0.0];
const startCapNorm = [0.0, 0.0, 0.0];
const endCapNorm = [0.0, 0.0, 0.0];
let p = [0.0, 0.0, 0.0];
let pNext = [0.0, 0.0, 0.0];
let s = [0.0, 0.0, 0.0];
let n = [0.0, 0.0, 0.0];
const w = [0.0, 0.0, 0.0];
const nP = [0.0, 0.0, 0.0];
const normal = [0.0, 0.0, 0.0];
let sFactor = 1.0;
let ptId = offset;
const vector = [];
for (let j = 0; j < npts; ++j) {
// First point
if (j === 0) {
p = inPts.slice(3 * pts[0], 3 * (pts[0] + 1));
pNext = inPts.slice(3 * pts[1], 3 * (pts[1] + 1));
for (let i = 0; i < 3; ++i) {
sNext[i] = pNext[i] - p[i];
sPrev[i] = sNext[i];
startCapNorm[i] = -sPrev[i];
}
normalize(startCapNorm);
} else if (j === npts - 1) {
for (let i = 0; i < 3; ++i) {
sPrev[i] = sNext[i];
p[i] = pNext[i];
endCapNorm[i] = sNext[i];
}
normalize(endCapNorm);
} else {
for (let i = 0; i < 3; ++i) {
p[i] = pNext[i];
}
pNext = inPts.slice(3 * pts[j + 1], 3 * (pts[j + 1] + 1));
for (let i = 0; i < 3; ++i) {
sPrev[i] = sNext[i];
sNext[i] = pNext[i] - p[i];
}
}
if (normalize(sNext) === 0.0) {
vtkWarningMacro('Coincident points!');
return 0;
}
for (let i = 0; i < 3; ++i) {
s[i] = (sPrev[i] + sNext[i]) / 2.0; // average vector
}
n = inNormals.slice(3 * pts[j], 3 * (pts[j] + 1));
// if s is zero then just use sPrev cross n
if (normalize(s) === 0.0) {
cross(sPrev, n, s);
if (normalize(s) === 0.0) {
vtkDebugMacro('Using alternate bevel vector');
}
}
cross(s, n, w);
if (normalize(w) === 0.0) {
let msg = 'Bad normal: s = ';
msg += `${s[0]}, ${s[1]}, ${s[2]}`;
msg += ` n = ${n[0]}, ${n[1]}, ${n[2]}`;
vtkWarningMacro(msg);
return 0;
}
cross(w, s, nP); // create orthogonal coordinate system
normalize(nP);
// Compute a scalar factor based on scalars or vectors
if (inScalars && model.varyRadius === VaryRadius.VARY_RADIUS_BY_SCALAR) {
sFactor = 1.0 + (model.radiusFactor - 1.0) * (inScalars.getComponent(pts[j], 0) - range[0]) / (range[1] - range[0]);
} else if (inVectors && model.varyRadius === VaryRadius.VARY_RADIUS_BY_VECTOR) {
sFactor = Math.sqrt(maxSpeed / norm(inVectors.getTuple(pts[j], vector)));
if (sFactor > model.radiusFactor) {
sFactor = model.radiusFactor;
}
} else if (inScalars && model.varyRadius === VaryRadius.VARY_RADIUS_BY_ABSOLUTE_SCALAR) {
sFactor = inScalars.getComponent(pts[j], 0);
if (sFactor < 0.0) {
vtkWarningMacro('Scalar value less than zero, skipping line');
return 0;
}
}
// create points around line
if (model.sidesShareVertices) {
for (let k = 0; k < model.numberOfSides; ++k) {
for (let i = 0; i < 3; ++i) {
normal[i] = w[i] * Math.cos(k * theta) + nP[i] * Math.sin(k * theta);
s[i] = p[i] + model.radius * sFactor * normal[i];
newPts[3 * ptId + i] = s[i];
newNormals[3 * ptId + i] = normal[i];
}
outPD.passData(pd, pts[j], ptId);
ptId++;
} // for each side
} else {
const nRight = [0, 0, 0];
const nLeft = [0, 0, 0];
for (let k = 0; k < model.numberOfSides; ++k) {
for (let i = 0; i < 3; ++i) {
// Create duplicate vertices at each point
// and adjust the associated normals so that they are
// oriented with the facets. This preserves the tube's
// polygonal appearance, as if by flat-shading around the tube,
// while still allowing smooth (gouraud) shading along the
// tube as it bends.
normal[i] = w[i] * Math.cos(k * theta) + nP[i] * Math.sin(k * theta);
nRight[i] = w[i] * Math.cos((k - 0.5) * theta) + nP[i] * Math.sin((k - 0.5) * theta);
nLeft[i] = w[i] * Math.cos((k + 0.5) * theta) + nP[i] * Math.sin((k + 0.5) * theta);
s[i] = p[i] + model.radius * sFactor * normal[i];
newPts[3 * ptId + i] = s[i];
newNormals[3 * ptId + i] = nRight[i];
newPts[3 * (ptId + 1) + i] = s[i];
newNormals[3 * (ptId + 1) + i] = nLeft[i];
}
outPD.passData(pd, pts[j], ptId + 1);
ptId += 2;
} // for each side
} // else separate vertices
} // for all points in the polyline
// Produce end points for cap. They are placed at tail end of points.
if (model.capping) {
let numCapSides = model.numberOfSides;
let capIncr = 1;
if (!model.sidesShareVertices) {
numCapSides = 2 * model.numberOfSides;
capIncr = 2;
}
// the start cap
for (let k = 0; k < numCapSides; k += capIncr) {
s = newPts.slice(3 * (offset + k), 3 * (offset + k + 1));
for (let i = 0; i < 3; ++i) {
newPts[3 * ptId + i] = s[i];
newNormals[3 * ptId + i] = startCapNorm[i];
}
outPD.passData(pd, pts[0], ptId);
ptId++;
}
// the end cap
let endOffset = offset + (npts - 1) * model.numberOfSides;
if (!model.sidesShareVertices) {
endOffset = offset + 2 * (npts - 1) * model.numberOfSides;
}
for (let k = 0; k < numCapSides; k += capIncr) {
s = newPts.slice(3 * (endOffset + k), 3 * (endOffset + k + 1));
for (let i = 0; i < 3; ++i) {
newPts[3 * ptId + i] = s[i];
newNormals[3 * ptId + i] = endCapNorm[i];
}
outPD.passData(pd, pts[npts - 1], ptId);
ptId++;
}
} // if capping
return 1;
}
function generateStrips(offset, npts, inCellId, outCellId, inCD, outCD, newStrips) {
let i1 = 0;
let i2 = 0;
let i3 = 0;
let newOutCellId = outCellId;
let outCellIdx = 0;
const newStripsData = newStrips.getData();
let cellId = 0;
while (outCellIdx < newStripsData.length) {
if (cellId === outCellId) {
break;
}
outCellIdx += newStripsData[outCellIdx] + 1;
cellId++;
}
if (model.sidesShareVertices) {
for (let k = offset; k < model.numberOfSides + offset; k += model.onRatio) {
i1 = k % model.numberOfSides;
i2 = (k + 1) % model.numberOfSides;
newStripsData[outCellIdx++] = npts * 2;
for (let i = 0; i < npts; ++i) {
i3 = i * model.numberOfSides;
newStripsData[outCellIdx++] = offset + i2 + i3;
newStripsData[outCellIdx++] = offset + i1 + i3;
}
outCD.passData(inCD, inCellId, newOutCellId++);
} // for each side of the tube
} else {
for (let k = offset; k < model.numberOfSides + offset; k += model.onRatio) {
i1 = 2 * (k % model.numberOfSides) + 1;
i2 = 2 * ((k + 1) % model.numberOfSides);
// outCellId = newStrips.getNumberOfCells(true);
newStripsData[outCellIdx] = npts * 2;
outCellIdx++;
for (let i = 0; i < npts; ++i) {
i3 = i * 2 * model.numberOfSides;
newStripsData[outCellIdx++] = offset + i2 + i3;
newStripsData[outCellIdx++] = offset + i1 + i3;
}
outCD.passData(inCD, inCellId, newOutCellId++);
} // for each side of the tube
}
// Take care of capping. The caps are n-sided polygons that can be easily
// triangle stripped.
if (model.capping) {
let startIdx = offset + npts * model.numberOfSides;
let idx = 0;
if (!model.sidesShareVertices) {
startIdx = offset + 2 * npts * model.numberOfSides;
}
// The start cap
newStripsData[outCellIdx++] = model.numberOfSides;
newStripsData[outCellIdx++] = startIdx;
newStripsData[outCellIdx++] = startIdx + 1;
let k = 0;
for (i1 = model.numberOfSides - 1, i2 = 2, k = 0; k < model.numberOfSides - 2; ++k) {
if (k % 2) {
idx = startIdx + i2;
newStripsData[outCellIdx++] = idx;
i2++;
} else {
idx = startIdx + i1;
newStripsData[outCellIdx++] = idx;
i1--;
}
}
outCD.passData(inCD, inCellId, newOutCellId++);
// The end cap - reversed order to be consistent with normal
startIdx += model.numberOfSides;
newStripsData[outCellIdx++] = model.numberOfSides;
newStripsData[outCellIdx++] = startIdx;
newStripsData[outCellIdx++] = startIdx + model.numberOfSides - 1;
for (i1 = model.numberOfSides - 2, i2 = 1, k = 0; k < model.numberOfSides - 2; ++k) {
if (k % 2) {
idx = startIdx + i1;
newStripsData[outCellIdx++] = idx;
i1--;
} else {
idx = startIdx + i2;
newStripsData[outCellIdx++] = idx;
i2++;
}
}
outCD.passData(inCD, inCellId, newOutCellId++);
}
return newOutCellId;
}
function generateTCoords(offset, npts, pts, inPts, inScalars, newTCoords) {
let numSides = model.numberOfSides;
if (!model.sidesShareVertices) {
numSides = 2 * model.numberOfSides;
}
let tc = 0.0;
let s0 = 0.0;
let s = 0.0;
const inScalarsData = inScalars.getData();
if (model.generateTCoords === GenerateTCoords.TCOORDS_FROM_SCALARS) {
s0 = inScalarsData[pts[0]];
for (let i = 0; i < npts; ++i) {
s = inScalarsData[pts[i]];
tc = (s - s0) / model.textureLength;
for (let k = 0; k < numSides; ++k) {
const tcy = k / (numSides - 1);
const tcId = 2 * (offset + i * numSides + k);
newTCoords[tcId] = tc;
newTCoords[tcId + 1] = tcy;
}
}
} else if (model.generateTCoords === GenerateTCoords.TCOORDS_FROM_LENGTH) {
let len = 0.0;
const xPrev = inPts.slice(3 * pts[0], 3 * (pts[0] + 1));
for (let i = 0; i < npts; ++i) {
const x = inPts.slice(3 * pts[i], 3 * (pts[i] + 1));
len += Math.sqrt(distance2BetweenPoints(x, xPrev));
tc = len / model.textureLength;
for (let k = 0; k < numSides; ++k) {
const tcy = k / (numSides - 1);
const tcId = 2 * (offset + i * numSides + k);
newTCoords[tcId] = tc;
newTCoords[tcId + 1] = tcy;
}
for (let k = 0; k < 3; ++k) {
xPrev[k] = x[k];
}
}
} else if (model.generateTCoords === GenerateTCoords.TCOORDS_FROM_NORMALIZED_LENGTH) {
let len = 0.0;
let len1 = 0.0;
let xPrev = inPts.slice(3 * pts[0], 3 * (pts[0] + 1));
for (let i = 0; i < npts; ++i) {
const x = inPts.slice(3 * pts[i], 3 * (pts[i] + 1));
len1 += Math.sqrt(distance2BetweenPoints(x, xPrev));
for (let k = 0; k < 3; ++k) {
xPrev[k] = x[k];
}
}
xPrev = inPts.slice(3 * pts[0], 3 * (pts[0] + 1));
for (let i = 0; i < npts; ++i) {
const x = inPts.slice(3 * pts[i], 3 * (pts[i] + 1));
len += Math.sqrt(distance2BetweenPoints(x, xPrev));
tc = len / len1;
for (let k = 0; k < numSides; ++k) {
const tcy = k / (numSides - 1);
const tcId = 2 * (offset + i * numSides + k);
newTCoords[tcId] = tc;
newTCoords[tcId + 1] = tcy;
}
for (let k = 0; k < 3; ++k) {
xPrev[k] = x[k];
}
}
}
// Capping, set the endpoints as appropriate
if (model.capping) {
const startIdx = offset + npts * numSides;
// start cap
for (let ik = 0; ik < model.numberOfSides; ++ik) {
const tcId = 2 * (startIdx + ik);
newTCoords[tcId] = 0.0;
newTCoords[tcId + 1] = 0.0;
}
// end cap
for (let ik = 0; ik < model.numberOfSides; ++ik) {
const tcId = 2 * (startIdx + model.numberOfSides + ik);
newTCoords[tcId] = 0.0;
newTCoords[tcId + 1] = 0.0;
}
}
}
publicAPI.requestData = (inData, outData) => {
// implement requestData
// pass through for now
const output = outData[0]?.initialize() || vtkPolyData.newInstance();
outData[0] = output;
const input = inData[0];
if (!input) {
vtkErrorMacro('Invalid or missing input');
return;
}
// Allocate output
const inPts = input.getPoints();
if (!inPts) {
return;
}
const numPts = inPts.getNumberOfPoints();
if (numPts < 1) {
return;
}
const inLines = input.getLines();
if (!inLines) {
return;
}
const numLines = inLines.getNumberOfCells();
if (numLines < 1) {
return;
}
let numNewPts = 0;
let numStrips = 0;
const inLinesData = inLines.getData();
let npts = inLinesData[0];
for (let i = 0; i < inLinesData.length; i += npts + 1) {
npts = inLinesData[i];
numNewPts = computeOffset(numNewPts, npts);
numStrips += (2 * npts + 1) * Math.ceil(model.numberOfSides / model.onRatio);
if (model.capping) {
numStrips += 2 * (model.numberOfSides + 1);
}
}
let pointType = inPts.getDataType();
if (model.outputPointsPrecision === DesiredOutputPrecision.SINGLE) {
pointType = VtkDataTypes.FLOAT;
} else if (model.outputPointsPrecision === DesiredOutputPrecision.DOUBLE) {
pointType = VtkDataTypes.DOUBLE;
}
const newPts = vtkPoints.newInstance({
dataType: pointType,
size: numNewPts * 3,
numberOfComponents: 3
});
const numNormals = 3 * numNewPts;
const newNormalsData = new Float32Array(numNormals);
const newNormals = vtkDataArray.newInstance({
numberOfComponents: 3,
values: newNormalsData,
name: 'TubeNormals'
});
const newStripsData = new Uint32Array(numStrips);
const newStrips = vtkCellArray.newInstance({
values: newStripsData
});
let newStripId = 0;
let inNormals = input.getPointData().getNormals();
let inNormalsData = null;
let generateNormals = false;
if (!inNormals || model.useDefaultNormal) {
inNormalsData = new Float32Array(3 * numPts);
inNormals = vtkDataArray.newInstance({
numberOfComponents: 3,
values: inNormalsData,
name: 'Normals'
});
if (model.useDefaultNormal) {
inNormalsData = inNormalsData.map((elem, index) => {
const i = index % 3;
return model.defaultNormal[i];
});
} else {
generateNormals = true;
}
}
// loop over pointData arrays and resize based on numNewPts
const numArrays = input.getPointData().getNumberOfArrays();
let oldArray = null;
let newArray = null;
for (let i = 0; i < numArrays; i++) {
oldArray = input.getPointData().getArrayByIndex(i);
newArray = vtkDataArray.newInstance({
name: oldArray.getName(),
dataType: oldArray.getDataType(),
numberOfComponents: oldArray.getNumberOfComponents(),
size: numNewPts * oldArray.getNumberOfComponents()
});
output.getPointData().addArray(newArray); // concat newArray to end
}
// loop over cellData arrays and resize based on numNewCells
let numNewCells = inLines.getNumberOfCells() * model.numberOfSides;
if (model.capping) {
numNewCells += 2;
}
const numCellArrays = input.getCellData().getNumberOfArrays();
for (let i = 0; i < numCellArrays; i++) {
oldArray = input.getCellData().getArrayByIndex(i);
newArray = vtkDataArray.newInstance({
name: oldArray.getName(),
dataType: oldArray.getDataType(),
numberOfComponents: oldArray.getNumberOfComponents(),
size: numNewCells * oldArray.getNumberOfComponents()
});
output.getCellData().addArray(newArray); // concat newArray to end
}
const inScalars = publicAPI.getInputArrayToProcess(0);
let outScalars = null;
let range = [];
if (inScalars) {
// allocate output scalar array
// assuming point scalars for now
outScalars = vtkDataArray.newInstance({
name: inScalars.getName(),
dataType: inScalars.getDataType(),
numberOfComponents: inScalars.getNumberOfComponents(),
size: numNewPts * inScalars.getNumberOfComponents()
});
range = inScalars.getRange();
if (range[1] - range[0] === 0.0) {
if (model.varyRadius === VaryRadius.VARY_RADIUS_BY_SCALAR) {
vtkWarningMacro('Scalar range is zero!');
}
range[1] = range[0] + 1.0;
}
}
const inVectors = publicAPI.getInputArrayToProcess(1);
let maxSpeed = 0;
if (inVectors) {
maxSpeed = inVectors.getMaxNorm();
}
const outCD = output.getCellData();
outCD.copyNormalsOff();
outCD.passData(input.getCellData());
const outPD = output.getPointData();
if (outPD.getNormals() !== null) {
outPD.copyNormalsOff();
}
if (inScalars && outScalars) {
outPD.setScalars(outScalars);
}
// TCoords
let newTCoords = null;
if (model.generateTCoords === GenerateTCoords.TCOORDS_FROM_SCALARS && inScalars || model.generateTCoords === GenerateTCoords.TCOORDS_FROM_LENGTH || model.generateTCoords === GenerateTCoords.TCOORDS_FROM_NORMALIZED_LENGTH) {
const newTCoordsData = new Float32Array(2 * numNewPts);
newTCoords = vtkDataArray.newInstance({
numberOfComponents: 2,
values: newTCoordsData,
name: 'TCoords'
});
outPD.copyTCoordsOff();
}
outPD.passData(input.getPointData());
// Create points along each polyline that are connected into numberOfSides
// triangle strips.
const theta = 2.0 * Math.PI / model.numberOfSides;
npts = inLinesData[0];
let offset = 0;
let inCellId = input.getVerts().getNumberOfCells();
for (let i = 0; i < inLinesData.length; i += npts + 1) {
npts = inLinesData[i];
const pts = inLinesData.slice(i + 1, i + 1 + npts);
if (npts > 1) {
// if not, skip tubing this line
if (generateNormals) {
const polyLine = inLinesData.slice(i, i + npts + 1);
generateSlidingNormals(inPts.getData(), polyLine, inNormals);
}
}
// generate points
if (generatePoints(offset, npts, pts, inPts.getData(), newPts.getData(), input.getPointData(), outPD, newNormalsData, inScalars, range, inVectors, maxSpeed, inNormalsData, theta)) {
// generate strips for the polyline
newStripId = generateStrips(offset, npts, inCellId, newStripId, input.getCellData(), outCD, newStrips);
// generate texture coordinates for the polyline
if (newTCoords) {
generateTCoords(offset, npts, pts, inPts.getData(), inScalars, newTCoords.getData());
}
} else {
// skip tubing this line
vtkWarningMacro('Could not generate points');
}
// lineIdx += npts;
// Compute the new offset for the next polyline
offset = computeOffset(offset, npts);
inCellId++;
}
output.setPoints(newPts);
output.setStrips(newStrips);
output.setPointData(outPD);
outPD.setNormals(newNormals);
};
}
// ----------------------------------------------------------------------------
// Object factory
// ----------------------------------------------------------------------------
const DEFAULT_VALUES = {
outputPointsPrecision: DesiredOutputPrecision.DEFAULT,
radius: 0.5,
varyRadius: VaryRadius.VARY_RADIUS_OFF,
numberOfSides: 3,
radiusFactor: 10,
defaultNormal: [0, 0, 1],
useDefaultNormal: false,
sidesShareVertices: true,
capping: false,
onRatio: 1,
offset: 0,
generateTCoords: GenerateTCoords.TCOORDS_OFF,
textureLength: 1.0
};
// ----------------------------------------------------------------------------
function extend(publicAPI, model, initialValues = {}) {
Object.assign(model, DEFAULT_VALUES, initialValues);
// Build VTK API
macro.setGet(publicAPI, model, ['outputPointsPrecision', 'radius', 'varyRadius', 'numberOfSides', 'radiusFactor', 'defaultNormal', 'useDefaultNormal', 'sidesShareVertices', 'capping', 'onRatio', 'offset', 'generateTCoords', 'textureLength']);
// 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
vtkTubeFilter(publicAPI, model);
}
// ----------------------------------------------------------------------------
const newInstance = macro.newInstance(extend, 'vtkTubeFilter');
// ----------------------------------------------------------------------------
var vtkTubeFilter$1 = {
newInstance,
extend
};
export { vtkTubeFilter$1 as default, extend, newInstance };