diff --git a/Documentation/content/docs/gallery/ShrinkPolyData.jpg b/Documentation/content/docs/gallery/ShrinkPolyData.jpg new file mode 100644 index 00000000000..1b16f9f7bb6 Binary files /dev/null and b/Documentation/content/docs/gallery/ShrinkPolyData.jpg differ diff --git a/Documentation/content/examples/index.md b/Documentation/content/examples/index.md index 4e81c621d59..3789ff72f00 100644 --- a/Documentation/content/examples/index.md +++ b/Documentation/content/examples/index.md @@ -108,7 +108,7 @@ This will allow you to see the some live code running in your browser. Just pick [![Cutter Example][Cutter]](./Cutter.html "Cutter") [![PolyDataNormals Example][PolyDataNormals]](./PolyDataNormals.html "PolyDataNormals") [![ThresholdPoints Example][ThresholdPoints]](./ThresholdPoints.html "Cut/Treshold points with point data criteria") - +[![ShrinkPolyData Example][ShrinkPolyData]](./ShrinkPolyData.html "ShrinkPolyData") @@ -128,6 +128,7 @@ This will allow you to see the some live code running in your browser. Just pick [Cutter]: ../docs/gallery/Cutter.jpg [PolyDataNormals]: ../docs/gallery/PolyDataNormals.jpg [ThresholdPoints]: ../docs/gallery/ThresholdPoints.jpg +[ShrinkPolyData]: ../docs/gallery/ShrinkPolyData.jpg # Sources diff --git a/Sources/Common/DataModel/Polygon/index.d.ts b/Sources/Common/DataModel/Polygon/index.d.ts index 625ff29a82e..9cc230eb419 100644 --- a/Sources/Common/DataModel/Polygon/index.d.ts +++ b/Sources/Common/DataModel/Polygon/index.d.ts @@ -60,6 +60,19 @@ export function pointInPolygon( normal: Vector3 ): PolygonIntersectionState; +/** + * Compute the centroid of a polygon. + * @param {Array} poly - Array of point indices for the polygon + * @param {vtkPoints} points - vtkPoints instance + * @param {Vector3} [centroid] - Optional output array (length 3) + * @returns {Vector3} The centroid as [x, y, z] + */ +export function computeCentroid( + poly: Array, + points: TypedArray, + centroid?: Vector3 +): Vector3; + /** * Method used to decorate a given object (publicAPI+model) with vtkPolygon characteristics. * diff --git a/Sources/Common/DataModel/Polygon/index.js b/Sources/Common/DataModel/Polygon/index.js index ca6c82ad47f..ca636ac6d74 100644 --- a/Sources/Common/DataModel/Polygon/index.js +++ b/Sources/Common/DataModel/Polygon/index.js @@ -215,6 +215,31 @@ export function getNormal(poly, points, normal) { return vtkMath.normalize(normal); } +/** + * Compute the centroid of a polygon. + * @param {Array} poly - Array of point indices for the polygon + * @param {vtkPoints} points - vtkPoints instance + * @param {Vector3} [centroid] - Optional output array (length 3) + * @returns {Vector3} The centroid as [x, y, z] + */ +export function computeCentroid(poly, points, centroid = [0, 0, 0]) { + centroid[0] = 0; + centroid[1] = 0; + centroid[2] = 0; + const n = poly.length; + const p = []; + for (let i = 0; i < n; i++) { + points.getPoint(poly[i], p); + centroid[0] += p[0]; + centroid[1] += p[1]; + centroid[2] += p[2]; + } + centroid[0] /= n; + centroid[1] /= n; + centroid[2] /= n; + return centroid; +} + // ---------------------------------------------------------------------------- // Static API // ---------------------------------------------------------------------------- @@ -224,6 +249,7 @@ const STATIC = { pointInPolygon, getBounds, getNormal, + computeCentroid, }; // ---------------------------------------------------------------------------- diff --git a/Sources/Filters/General/ShrinkPolyData/example/controlPanel.html b/Sources/Filters/General/ShrinkPolyData/example/controlPanel.html new file mode 100644 index 00000000000..3f2c8153b9c --- /dev/null +++ b/Sources/Filters/General/ShrinkPolyData/example/controlPanel.html @@ -0,0 +1,8 @@ + + + + + +
Shrink Factor + +
diff --git a/Sources/Filters/General/ShrinkPolyData/example/index.js b/Sources/Filters/General/ShrinkPolyData/example/index.js new file mode 100644 index 00000000000..836c2974b60 --- /dev/null +++ b/Sources/Filters/General/ShrinkPolyData/example/index.js @@ -0,0 +1,52 @@ +import '@kitware/vtk.js/favicon'; + +// Load the rendering pieces we want to use (for both WebGL and WebGPU) +import '@kitware/vtk.js/Rendering/Profiles/Geometry'; +import '@kitware/vtk.js/IO/Core/DataAccessHelper/HttpDataAccessHelper'; + +import vtkFullScreenRenderWindow from '@kitware/vtk.js/Rendering/Misc/FullScreenRenderWindow'; +import vtkActor from '@kitware/vtk.js/Rendering/Core/Actor'; +import vtkHttpDataSetReader from '@kitware/vtk.js/IO/Core/HttpDataSetReader'; +import vtkShrinkPolyData from '@kitware/vtk.js/Filters/General/ShrinkPolyData'; +import vtkMapper from '@kitware/vtk.js/Rendering/Core/Mapper'; +import controlPanel from './controlPanel.html'; + +// ---------------------------------------------------------------------------- +// Standard rendering code setup +// ---------------------------------------------------------------------------- + +const fullScreenRenderer = vtkFullScreenRenderWindow.newInstance(); +const renderer = fullScreenRenderer.getRenderer(); +const renderWindow = fullScreenRenderer.getRenderWindow(); + +fullScreenRenderer.addController(controlPanel); + +// ---------------------------------------------------------------------------- +// Example code +// ---------------------------------------------------------------------------- +const shrinkPolyData = vtkShrinkPolyData.newInstance(); +shrinkPolyData.setShrinkFactor(0.25); + +const actor = vtkActor.newInstance(); +const mapper = vtkMapper.newInstance(); +mapper.setInputConnection(shrinkPolyData.getOutputPort()); +actor.setMapper(mapper); + +const reader = vtkHttpDataSetReader.newInstance({ fetchGzip: true }); +shrinkPolyData.setInputConnection(reader.getOutputPort()); + +reader.setUrl(`${__BASE_PATH__}/data/cow.vtp`).then(() => { + reader.loadData().then(() => { + renderer.addActor(actor); + renderer.resetCamera(); + renderWindow.render(); + }); +}); + +['shrinkFactor'].forEach((propertyName) => { + document.querySelector(`.${propertyName}`).addEventListener('input', (e) => { + const value = Number(e.target.value); + shrinkPolyData.set({ [propertyName]: value }); + renderWindow.render(); + }); +}); diff --git a/Sources/Filters/General/ShrinkPolyData/index.d.ts b/Sources/Filters/General/ShrinkPolyData/index.d.ts new file mode 100644 index 00000000000..a62578bebc7 --- /dev/null +++ b/Sources/Filters/General/ShrinkPolyData/index.d.ts @@ -0,0 +1,85 @@ +import { DesiredOutputPrecision } from '../../../Common/DataModel/DataSetAttributes'; +import { vtkAlgorithm, vtkObject } from '../../../interfaces'; +import { Vector3 } from '../../../types'; + +/** + * + */ +export interface IShrinkPolyDataInitialValues { + shrinkFactor?: number; +} + +type vtkShrinkPolyDataBase = vtkObject & vtkAlgorithm; + +export interface vtkShrinkPolyData extends vtkShrinkPolyDataBase { + /** + * Expose methods + * @param inData + * @param outData + */ + requestData(inData: any, outData: any): void; + + /** + * Get the shrink factor. + */ + getShrinkFactor(): number; + + /** + * Set the shrink factor. + * @param {Number} shrinkFactor + */ + setShrinkFactor(shrinkFactor: number): boolean; + + /** + * Shrink two points towards their midpoint by a shrink factor. + * @param {Vector3} p1 - The [x, y, z] coordinates of the first point + * @param {Vector3} p2 - The [x, y, z] coordinates of the second point + * @param {number} shrinkFactor - The shrink factor (0.0 to 1.0) + * @param {Number[]} [shrunkPoints] - Optional array to store the shrunk points + * @returns {Number[]} Array containing the two new points + */ + shrinkLine( + p1: Vector3, + p2: Vector3, + shrinkFactor: number, + shrunkPoints?: Number[] + ): Number[]; +} + +/** + * Method used to decorate a given object (publicAPI+model) with vtkShrinkPolyData characteristics. + * + * @param publicAPI object on which methods will be bounds (public) + * @param model object on which data structure will be bounds (protected) + * @param {IShrinkPolyDataInitialValues} [initialValues] (default: {}) + */ +export function extend( + publicAPI: object, + model: object, + initialValues?: IShrinkPolyDataInitialValues +): void; + +/** + * Method used to create a new instance of vtkShrinkPolyData. + * @param {IShrinkPolyDataInitialValues} [initialValues] for pre-setting some of its content + */ +export function newInstance( + initialValues?: IShrinkPolyDataInitialValues +): vtkShrinkPolyData; + +/** + * vtkShrinkPolyData shrinks cells composing a polygonal dataset (e.g., + * vertices, lines, polygons, and triangle strips) towards their centroid. The + * centroid of a cell is computed as the average position of the cell points. + * Shrinking results in disconnecting the cells from one another. The output + * dataset type of this filter is polygonal data. + * + * During execution the filter passes its input cell data to its output. Point + * data attributes are copied to the points created during the shrinking + * process. + */ +export declare const vtkShrinkPolyData: { + newInstance: typeof newInstance; + extend: typeof extend; +}; +export default vtkShrinkPolyData; diff --git a/Sources/Filters/General/ShrinkPolyData/index.js b/Sources/Filters/General/ShrinkPolyData/index.js new file mode 100644 index 00000000000..f0cf3471eb1 --- /dev/null +++ b/Sources/Filters/General/ShrinkPolyData/index.js @@ -0,0 +1,384 @@ +import macro from 'vtk.js/Sources/macros'; +import vtkCellArray from 'vtk.js/Sources/Common/Core/CellArray'; +import vtkPolyData from 'vtk.js/Sources/Common/DataModel/PolyData'; +import vtkPoints from 'vtk.js/Sources/Common/Core/Points'; +import vtkPolygon from 'vtk.js/Sources/Common/DataModel/Polygon'; + +const { vtkErrorMacro } = macro; + +// ---------------------------------------------------------------------------- +// vtkShrinkPolyData methods +// ---------------------------------------------------------------------------- + +function vtkShrinkPolyData(publicAPI, model) { + // Set our className + model.classHierarchy.push('vtkShrinkPolyData'); + + /** + * Shrink a point towards a given center by a shrink factor. + * @param {Vector3} point - The [x, y, z] coordinates of the point to shrink + * @param {Vector3} center - The [x, y, z] coordinates of the center + * @param {number} shrinkFactor - The shrink factor (0.0 to 1.0) + * @param {Vector3} [shrunkPoint] - Optional array to store the shrunk point + * @returns {Vector3} The shrunk point [x, y, z] coordinates + */ + function shrinkTowardsPoint(point, center, shrinkFactor, shrunkPoint = []) { + shrunkPoint[0] = center[0] + shrinkFactor * (point[0] - center[0]); + shrunkPoint[1] = center[1] + shrinkFactor * (point[1] - center[1]); + shrunkPoint[2] = center[2] + shrinkFactor * (point[2] - center[2]); + return shrunkPoint; + } + + /** + * Shrinks a cell towards its center by a shrink factor. + * @param {number[]} cellPointIds - Array of point indices that define the cell + * @param {vtkPoints} inPoints - Input points + * @param {number} shrinkFactor - The shrink factor (0.0 to 1.0) + * @param {Float32Array} newPointsData - Output array to store new point coordinates + * @param {number} outCount - Current index in the output points array + * @returns {Object} Object containing newPointIds array and updated outCount + */ + function shrinkCell( + cellPointIds, + inPoints, + shrinkFactor, + newPointsData, + outCount + ) { + const inPts = inPoints.getData(); + const center = [0, 0, 0]; + const newPointIds = []; + const shrunkPoint = [0, 0, 0]; + const currentPoint = [0, 0, 0]; + + let nextOutCount = outCount; + + const numPoints = cellPointIds.length; + + if (numPoints === 0) { + return { newPointIds, outCount: nextOutCount }; + } + + if (numPoints === 1) { + // vertex - no shrinking needed, just copy the point + const ptId = cellPointIds[0]; + newPointsData[nextOutCount * 3] = inPts[ptId * 3]; + newPointsData[nextOutCount * 3 + 1] = inPts[ptId * 3 + 1]; + newPointsData[nextOutCount * 3 + 2] = inPts[ptId * 3 + 2]; + newPointIds.push(nextOutCount); + nextOutCount++; + } else if (numPoints === 2) { + // line - shrink towards midpoint + + // Calculate midpoint as center + vtkPolygon.computeCentroid(cellPointIds, inPoints, center); + + // Shrink both points towards center + for (let i = 0; i < 2; i++) { + const ptId = cellPointIds[i]; + currentPoint[0] = inPts[ptId * 3]; + currentPoint[1] = inPts[ptId * 3 + 1]; + currentPoint[2] = inPts[ptId * 3 + 2]; + + shrinkTowardsPoint(currentPoint, center, shrinkFactor, shrunkPoint); + + newPointsData[nextOutCount * 3] = shrunkPoint[0]; + newPointsData[nextOutCount * 3 + 1] = shrunkPoint[1]; + newPointsData[nextOutCount * 3 + 2] = shrunkPoint[2]; + newPointIds.push(nextOutCount); + nextOutCount++; + } + } else { + // polygon/triangle - shrink towards centroid + vtkPolygon.computeCentroid(cellPointIds, inPoints, center); + + // Shrink each point towards centroid + for (let i = 0; i < numPoints; i++) { + const ptId = cellPointIds[i]; + currentPoint[0] = inPts[ptId * 3]; + currentPoint[1] = inPts[ptId * 3 + 1]; + currentPoint[2] = inPts[ptId * 3 + 2]; + + shrinkTowardsPoint(currentPoint, center, shrinkFactor, shrunkPoint); + + newPointsData[nextOutCount * 3] = shrunkPoint[0]; + newPointsData[nextOutCount * 3 + 1] = shrunkPoint[1]; + newPointsData[nextOutCount * 3 + 2] = shrunkPoint[2]; + newPointIds.push(nextOutCount); + nextOutCount++; + } + } + + return { newPointIds, outCount: nextOutCount }; + } + + // Internal method to process the shrinking + function shrinkData(input, output) { + const inPoints = input.getPoints(); + const inVerts = input.getVerts(); + const inLines = input.getLines(); + const inPolys = input.getPolys(); + const inStrips = input.getStrips(); + + const shrinkFactor = model.shrinkFactor; + + let numNewPts = 0; + + if (inVerts) { + const cellSizes = inVerts.getCellSizes(); + for (let i = 0; i < cellSizes.length; i++) { + numNewPts += cellSizes[i]; + } + } + + if (inLines) { + const cellSizes = inLines.getCellSizes(); + for (let i = 0; i < cellSizes.length; i++) { + numNewPts += (cellSizes[i] - 1) * 2; + } + } + + if (inPolys) { + const cellSizes = inPolys.getCellSizes(); + for (let i = 0; i < cellSizes.length; i++) { + numNewPts += cellSizes[i]; + } + } + + if (inStrips) { + const cellSizes = inStrips.getCellSizes(); + for (let i = 0; i < cellSizes.length; i++) { + numNewPts += (cellSizes[i] - 2) * 3; + } + } + + const newPointsData = new Float32Array(numNewPts * 3); + const newPoints = vtkPoints.newInstance(); + newPoints.setData(newPointsData, 3); + + const newVerts = vtkCellArray.newInstance(); + const newLines = vtkCellArray.newInstance(); + const newPolys = vtkCellArray.newInstance(); + + let outCount = 0; + + // Process vertices + if (inVerts) { + const vertData = inVerts.getData(); + const newVertData = []; + const cellPointIds = []; + + for (let i = 0; i < vertData.length; ) { + cellPointIds.length = 0; // Clear previous point IDs + const npts = vertData[i]; + for (let j = 1; j <= npts; j++) { + cellPointIds.push(vertData[i + j]); + } + + const result = shrinkCell( + cellPointIds, + inPoints, + shrinkFactor, + newPointsData, + outCount + ); + outCount = result.outCount; + + newVertData.push(npts); + newVertData.push(...result.newPointIds); + + i += npts + 1; + } + + newVerts.setData(new Uint32Array(newVertData)); + } + + // Process lines + if (inLines) { + const lineData = inLines.getData(); + const newLineData = []; + + for (let i = 0; i < lineData.length; ) { + const npts = lineData[i]; + + // Process each line segment + for (let j = 0; j < npts - 1; j++) { + const cellPointIds = [lineData[i + j + 1], lineData[i + j + 2]]; + + const result = shrinkCell( + cellPointIds, + inPoints, + shrinkFactor, + newPointsData, + outCount + ); + outCount = result.outCount; + + newLineData.push(2, result.newPointIds[0], result.newPointIds[1]); + } + + i += npts + 1; + } + + newLines.setData(new Uint32Array(newLineData)); + } + + // Process polygons + if (inPolys) { + const polyData = inPolys.getData(); + const newPolyData = []; + const cellPointIds = []; + + for (let i = 0; i < polyData.length; ) { + cellPointIds.length = 0; // Clear previous point IDs + const npts = polyData[i]; + + for (let j = 1; j <= npts; j++) { + cellPointIds.push(polyData[i + j]); + } + + const result = shrinkCell( + cellPointIds, + inPoints, + shrinkFactor, + newPointsData, + outCount + ); + outCount = result.outCount; + + newPolyData.push(npts); + newPolyData.push(...result.newPointIds); + + i += npts + 1; + } + + newPolys.setData(new Uint32Array(newPolyData)); + } + + // Process triangle strips (convert to triangles and shrink) + if (inStrips) { + const stripData = inStrips.getData(); + const newPolyData = []; + + for (let i = 0; i < stripData.length; ) { + const npts = stripData[i]; + + for (let j = 0; j < npts - 2; j++) { + const cellPointIds = [ + stripData[i + j + 1], + stripData[i + j + 2], + stripData[i + j + 3], + ]; + + const result = shrinkCell( + cellPointIds, + inPoints, + shrinkFactor, + newPointsData, + outCount + ); + outCount = result.outCount; + + // Triangle strips alternate the winding order of each triangle as you + // move along the strip. This means that the orientation + // (clockwise/counter-clockwise) flips for every new triangle. To + // ensure consistent face orientation (so normals and rendering are + // correct), we reverse the vertex order for every odd triangle. + // Example strip with vertices [0,1,2,3,4,5] produces these triangles: + // + // 0───2───4 Triangle 0: (0,1,2) [CCW] + // │ ╱ │ ╱ │ Triangle 1: (1,3,2) [CW -> reversed to (2,3,1) for CCW] + // │╱ │╱ │ Triangle 2: (2,3,4) [CCW] + // 1───3───5 Triangle 3: (3,5,4) [CW -> reversed to (4,5,3) for CCW] + const newIds = [...result.newPointIds]; + if (j % 2) { + const tmp = newIds[0]; + newIds[0] = newIds[2]; + newIds[2] = tmp; + } + + newPolyData.push(3, newIds[0], newIds[1], newIds[2]); + } + i += npts + 1; + } + + if (newPolyData.length > 0) { + const existingPolyData = newPolys.getData(); + const combinedPolyData = new Uint32Array( + existingPolyData.length + newPolyData.length + ); + combinedPolyData.set(existingPolyData); + combinedPolyData.set(newPolyData, existingPolyData.length); + newPolys.setData(combinedPolyData); + } + } + + // Set output + output.setPoints(newPoints); + output.setVerts(newVerts); + output.setLines(newLines); + output.setPolys(newPolys); + + // Copy cell data + output.getCellData().passData(input.getCellData()); + } + + publicAPI.requestData = (inData, outData) => { + const input = inData[0]; + const output = outData[0] || vtkPolyData.newInstance(); + + if (!input) { + vtkErrorMacro('No input!'); + return; + } + + if (!input.getPoints()) { + vtkErrorMacro('Input has no points!'); + return; + } + + shrinkData(input, output); + + outData[0] = output; + }; + + // Set the shrink factor + publicAPI.setShrinkFactor = (shrinkFactor) => { + if (shrinkFactor !== model.shrinkFactor) { + model.shrinkFactor = Math.max(0.0, Math.min(1.0, shrinkFactor)); + publicAPI.modified(); + } + }; +} + +// ---------------------------------------------------------------------------- +// Object factory +// ---------------------------------------------------------------------------- + +const DEFAULT_VALUES = { + shrinkFactor: 0.5, +}; + +// ---------------------------------------------------------------------------- + +export function extend(publicAPI, model, initialValues = {}) { + Object.assign(model, DEFAULT_VALUES, initialValues); + + // Build VTK API + macro.obj(publicAPI, model); + + // Also make it an algorithm with one input and one output + macro.algo(publicAPI, model, 1, 1); + + macro.setGet(publicAPI, model, ['shrinkFactor']); + + vtkShrinkPolyData(publicAPI, model); +} + +// ---------------------------------------------------------------------------- + +export const newInstance = macro.newInstance(extend, 'vtkShrinkPolyData'); + +// ---------------------------------------------------------------------------- + +export default { newInstance, extend }; diff --git a/Sources/Filters/General/ShrinkPolyData/test/testShrinkPolyData.js b/Sources/Filters/General/ShrinkPolyData/test/testShrinkPolyData.js new file mode 100644 index 00000000000..ba5bc7a73cb --- /dev/null +++ b/Sources/Filters/General/ShrinkPolyData/test/testShrinkPolyData.js @@ -0,0 +1,73 @@ +import test from 'tape'; +import testUtils from 'vtk.js/Sources/Testing/testUtils'; + +import 'vtk.js/Sources/Rendering/Misc/RenderingAPIs'; +import vtkRenderWindow from 'vtk.js/Sources/Rendering/Core/RenderWindow'; +import vtkRenderer from 'vtk.js/Sources/Rendering/Core/Renderer'; +import vtkShrinkPolyData from 'vtk.js/Sources/Filters/General/ShrinkPolyData'; +import vtkActor from 'vtk.js/Sources/Rendering/Core/Actor'; +import vtkMapper from 'vtk.js/Sources/Rendering/Core/Mapper'; +import vtkSphereSource from 'vtk.js/Sources/Filters/Sources/SphereSource'; + +import baseline from './testShrinkPolyData.png'; + +test.onlyIfWebGL('Test vtkShrinkPolyData Rendering', (t) => { + const gc = testUtils.createGarbageCollector(); + t.ok('rendering', 'vtkShrinkPolyData Rendering'); + + // Create some control UI + const container = document.querySelector('body'); + const renderWindowContainer = gc.registerDOMElement( + document.createElement('div') + ); + container.appendChild(renderWindowContainer); + + // create what we will view + const renderWindow = gc.registerResource(vtkRenderWindow.newInstance()); + const renderer = gc.registerResource(vtkRenderer.newInstance()); + renderWindow.addRenderer(renderer); + renderer.setBackground(0.32, 0.34, 0.43); + + const actor = gc.registerResource(vtkActor.newInstance()); + renderer.addActor(actor); + + const mapper = gc.registerResource(vtkMapper.newInstance()); + actor.setMapper(mapper); + + const sphere = gc.registerResource( + vtkSphereSource.newInstance({ + radius: 1.0, + thetaResolution: 20, + phiResolution: 20, + }) + ); + + const shrink = gc.registerResource( + vtkShrinkPolyData.newInstance({ + shrinkFactor: 0.5, + }) + ); + shrink.setInputConnection(sphere.getOutputPort()); + mapper.setInputConnection(shrink.getOutputPort()); + + // now create something to view it, in this case webgl + const glwindow = gc.registerResource(renderWindow.newAPISpecificView()); + glwindow.setContainer(renderWindowContainer); + renderWindow.addView(glwindow); + glwindow.setSize(400, 400); + + const promise = glwindow + .captureNextImage() + .then((image) => + testUtils.compareImages( + image, + [baseline], + 'Filters/General/ShrinkPolyData/testShrinkPolyData', + t, + 2.5 + ) + ) + .finally(gc.releaseResources); + renderWindow.render(); + return promise; +}); diff --git a/Sources/Filters/General/ShrinkPolyData/test/testShrinkPolyData.png b/Sources/Filters/General/ShrinkPolyData/test/testShrinkPolyData.png new file mode 100644 index 00000000000..66f81e2247a Binary files /dev/null and b/Sources/Filters/General/ShrinkPolyData/test/testShrinkPolyData.png differ diff --git a/Sources/Filters/General/index.js b/Sources/Filters/General/index.js index 7c7b1873dd8..ea7f760f34c 100644 --- a/Sources/Filters/General/index.js +++ b/Sources/Filters/General/index.js @@ -15,6 +15,7 @@ import vtkOBBTree from './OBBTree'; import vtkOutlineFilter from './OutlineFilter'; import vtkPaintFilter from './PaintFilter'; import vtkScalarToRGBA from './ScalarToRGBA'; +import vtkShrinkPolyData from './ShrinkPolyData'; import vtkTransformPolyDataFilter from './TransformPolyDataFilter'; import vtkTriangleFilter from './TriangleFilter'; import vtkTubeFilter from './TubeFilter'; @@ -39,6 +40,7 @@ export default { vtkOutlineFilter, vtkPaintFilter, vtkScalarToRGBA, + vtkShrinkPolyData, vtkTransformPolyDataFilter, vtkTriangleFilter, vtkTubeFilter,