From 8f045dac059e9e5bdf5dc4e36f6895d8cb3b8b6f Mon Sep 17 00:00:00 2001 From: Adnane Belmadiaf Date: Sun, 5 Oct 2025 00:18:43 +0200 Subject: [PATCH] feat(RegularPolygonSource): add vtkRegularPolygonSource --- .../docs/gallery/RegularPolygonSource.jpg | Bin 0 -> 10859 bytes Documentation/content/examples/index.md | 2 + .../Sources/PlatonicSolidSource/index.d.ts | 6 +- .../example/controlPanel.html | 8 + .../RegularPolygonSource/example/index.js | 62 ++++++ .../Sources/RegularPolygonSource/index.d.ts | 183 ++++++++++++++++++ .../Sources/RegularPolygonSource/index.js | 166 ++++++++++++++++ .../test/testRegularPolygon.js | 64 ++++++ .../test/testRegularPolygon.png | Bin 0 -> 6404 bytes Sources/Filters/Sources/index.js | 2 + 10 files changed, 490 insertions(+), 3 deletions(-) create mode 100644 Documentation/content/docs/gallery/RegularPolygonSource.jpg create mode 100644 Sources/Filters/Sources/RegularPolygonSource/example/controlPanel.html create mode 100644 Sources/Filters/Sources/RegularPolygonSource/example/index.js create mode 100644 Sources/Filters/Sources/RegularPolygonSource/index.d.ts create mode 100644 Sources/Filters/Sources/RegularPolygonSource/index.js create mode 100644 Sources/Filters/Sources/RegularPolygonSource/test/testRegularPolygon.js create mode 100644 Sources/Filters/Sources/RegularPolygonSource/test/testRegularPolygon.png diff --git a/Documentation/content/docs/gallery/RegularPolygonSource.jpg b/Documentation/content/docs/gallery/RegularPolygonSource.jpg new file mode 100644 index 0000000000000000000000000000000000000000..ded657bbe02cc74323e2e6999de4ffe76ab8ac03 GIT binary patch literal 10859 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 literal 0 HcmV?d00001 diff --git a/Documentation/content/examples/index.md b/Documentation/content/examples/index.md index b92e8a2ad50..f63f6759b62 100644 --- a/Documentation/content/examples/index.md +++ b/Documentation/content/examples/index.md @@ -151,6 +151,7 @@ This will allow you to see the some live code running in your browser. Just pick [![PlaneSource Example][PlaneSource]](./PlaneSource.html "PlaneSource") [![PointSource Example][PointSource]](./PointSource.html "PointSource") [![PlatonicSolidSource Example][PlatonicSolidSource]](./PlatonicSolidSource.html "PlatonicSolidSource") +[![RegularPolygonSource Example][RegularPolygonSource]](./RegularPolygonSource.html "RegularPolygonSource") [![SLICSource Example][SLICSource]](./SLICSource.html "SLICSource") [![SphereSource Example][SphereSource]](./SphereSource.html "SphereSource") [![WarpScalar Example][WarpScalargif]](./WarpScalar.html "WarpScalar") @@ -173,6 +174,7 @@ This will allow you to see the some live code running in your browser. Just pick [PlaneSource]: ../docs/gallery/PlaneSource.jpg [PointSource]: ../docs/gallery/PointSource.jpg [PlatonicSolidSource]: ../docs/gallery/PlatonicSolidSource.jpg +[RegularPolygonSource]: ../docs/gallery/RegularPolygonSource.jpg [SLICSource]: ../docs/gallery/SLICSource.jpg [SphereSource]: ../docs/gallery/SphereSource.gif [WarpScalargif]: ../docs/gallery/WarpScalar.gif diff --git a/Sources/Filters/Sources/PlatonicSolidSource/index.d.ts b/Sources/Filters/Sources/PlatonicSolidSource/index.d.ts index 659e4de6e84..393ae38e379 100644 --- a/Sources/Filters/Sources/PlatonicSolidSource/index.d.ts +++ b/Sources/Filters/Sources/PlatonicSolidSource/index.d.ts @@ -96,10 +96,10 @@ export function newInstance( * * @example * ```js - * import vtkPlatonicSolidSource from '@kitware/vtk.js/Filters/Sources/RegularPolygonSource'; + * import vtkPlatonicSolidSource from '@kitware/vtk.js/Filters/Sources/PlatonicSolidSource'; * - * const regularPolygonSource = vtkPlatonicSolidSource.newInstance(); - * const polydata = regularPolygonSource.getOutputData(); + * const platonicSolidSource = vtkPlatonicSolidSource.newInstance(); + * const polydata = platonicSolidSource.getOutputData(); * ``` */ export declare const vtkPlatonicSolidSource: { diff --git a/Sources/Filters/Sources/RegularPolygonSource/example/controlPanel.html b/Sources/Filters/Sources/RegularPolygonSource/example/controlPanel.html new file mode 100644 index 00000000000..014e7d29234 --- /dev/null +++ b/Sources/Filters/Sources/RegularPolygonSource/example/controlPanel.html @@ -0,0 +1,8 @@ + + + + + +
Number Of Sides + +
diff --git a/Sources/Filters/Sources/RegularPolygonSource/example/index.js b/Sources/Filters/Sources/RegularPolygonSource/example/index.js new file mode 100644 index 00000000000..85048b326e3 --- /dev/null +++ b/Sources/Filters/Sources/RegularPolygonSource/example/index.js @@ -0,0 +1,62 @@ +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 vtkFullScreenRenderWindow from '@kitware/vtk.js/Rendering/Misc/FullScreenRenderWindow'; +import vtkActor from '@kitware/vtk.js/Rendering/Core/Actor'; +import vtkRegularPolygonSource from '@kitware/vtk.js/Filters/Sources/RegularPolygonSource'; +import vtkMapper from '@kitware/vtk.js/Rendering/Core/Mapper'; +import { Representation } from '@kitware/vtk.js/Rendering/Core/Property/Constants'; + +import controlPanel from './controlPanel.html'; + +// ---------------------------------------------------------------------------- +// Standard rendering code setup +// ---------------------------------------------------------------------------- + +const fullScreenRenderer = vtkFullScreenRenderWindow.newInstance(); +const renderer = fullScreenRenderer.getRenderer(); +const renderWindow = fullScreenRenderer.getRenderWindow(); + +// ---------------------------------------------------------------------------- +// Example code +// ---------------------------------------------------------------------------- +const regularPolygonSource = vtkRegularPolygonSource.newInstance(); + +const mapper = vtkMapper.newInstance(); +const actor = vtkActor.newInstance(); + +actor.getProperty().setRepresentation(Representation.WIREFRAME); + +mapper.setInputConnection(regularPolygonSource.getOutputPort()); +actor.setMapper(mapper); + +renderer.addActor(actor); +renderer.resetCamera(); +renderWindow.render(); + +// ----------------------------------------------------------- +// UI control handling +// ----------------------------------------------------------- + +fullScreenRenderer.addController(controlPanel); + +['numberOfSides'].forEach((propertyName) => { + document.querySelector(`.${propertyName}`).addEventListener('input', (e) => { + const value = Number(e.target.value); + regularPolygonSource.set({ [propertyName]: value }); + renderWindow.render(); + }); +}); + +// ----------------------------------------------------------- +// Make some variables global so that you can inspect and +// modify objects in your browser's developer console: +// ----------------------------------------------------------- + +global.regularPolygonSource = regularPolygonSource; +global.mapper = mapper; +global.actor = actor; +global.renderer = renderer; +global.renderWindow = renderWindow; diff --git a/Sources/Filters/Sources/RegularPolygonSource/index.d.ts b/Sources/Filters/Sources/RegularPolygonSource/index.d.ts new file mode 100644 index 00000000000..7970fe0e8e2 --- /dev/null +++ b/Sources/Filters/Sources/RegularPolygonSource/index.d.ts @@ -0,0 +1,183 @@ +import { vtkAlgorithm, vtkObject } from '../../../interfaces'; +import { Vector3 } from '../../../types'; +import { DesiredOutputPrecision } from '../../../Common/DataModel/DataSetAttributes'; + +/** + * + */ +export interface IPlaneSourceInitialValues { + numberOfSides?: number; + center?: Vector3; + normal?: Vector3; + radius?: number; + generatePolygon?: boolean; + generatePolyline?: boolean; + outputPointsPrecision?: DesiredOutputPrecision; +} + +type vtkRegularPolygonSourceBase = vtkObject & + Omit< + vtkAlgorithm, + | 'getInputData' + | 'setInputData' + | 'setInputConnection' + | 'getInputConnection' + | 'addInputConnection' + | 'addInputData' + >; + +export interface vtkRegularPolygonSource extends vtkRegularPolygonSourceBase { + /** + * Get the center of the regular polygon. + * @returns {Vector3} center of the polygon + */ + getCenter(): Vector3; + + /** + * Get a reference to the center of the regular polygon. + * @returns {Vector3} reference to the center of the polygon + */ + getCenterByReference(): Vector3; + + /** + * Get whether to generate polygon points. + * @returns {Boolean} true if polygon points are generated, false otherwise + */ + getGeneratePolygon(): boolean; + + /** + * Get whether to generate polyline points. + * @returns {Boolean} true if polyline points are generated, false otherwise + */ + getGeneratePolyline(): boolean; + + /** + * Get the normal of the regular polygon. + * @returns {Vector3} normal of the polygon + */ + getNormal(): Vector3; + + /** + * Get a reference to the normal of the regular polygon. + * @returns {Vector3} reference to the normal of the polygon + */ + getNormalByReference(): Vector3; + + /** + * Get the number of sides for the regular polygon. + * @returns {Number} number of sides + */ + getNumberOfSides(): number; + + /** + * Get the output points precision. + * @returns {DesiredOutputPrecision} the output points precision + */ + getOutputPointsPrecision(): DesiredOutputPrecision; + + /** + * Get the radius of the regular polygon. + * @returns {Number} radius of the polygon + */ + getRadius(): number; + + /** + * + * @param inData + * @param outData + */ + requestData(inData: any, outData: any): void; + + /** + * Set the center of the regular polygon. + * @param {Vector3} center + * @returns {Boolean} true if the value was changed, false otherwise + */ + setCenter(center: Vector3): boolean; + + /** + * Set whether to generate polygon points. + * @param generatePolygon + * @returns {Boolean} true if the value was changed, false otherwise + */ + setGeneratePolygon(generatePolygon: boolean): boolean; + + /** + * Set whether to generate polyline points. + * @param generatePolyline + * @returns {Boolean} true if the value was changed, false otherwise + */ + setGeneratePolyline(generatePolyline: boolean): boolean; + + /** + * Set the normal of the regular polygon. + * @param {Vector3} normal + * @returns {Boolean} true if the value was changed, false otherwise + */ + setNormal(normal: Vector3): boolean; + + /** + * Set the number of sides for the regular polygon. + * @param numberOfSides + * @returns {Boolean} true if the value was changed, false otherwise + */ + setNumberOfSides(numberOfSides: number): boolean; + + /** + * Set the output points precision. + * @param outputPointsPrecision + * @returns {Boolean} true if the value was changed, false otherwise + */ + setOutputPointsPrecision( + outputPointsPrecision: DesiredOutputPrecision + ): boolean; + + /** + * Set the radius of the regular polygon. + * @param radius + * @returns {Boolean} true if the value was changed, false otherwise + */ + setRadius(radius: number): boolean; +} + +/** + * Method used to decorate a given object (publicAPI+model) with vtkRegularPolygonSource characteristics. + * + * @param publicAPI object on which methods will be bounds (public) + * @param model object on which data structure will be bounds (protected) + * @param {IPlaneSourceInitialValues} [initialValues] (default: {}) + */ +export function extend( + publicAPI: object, + model: object, + initialValues?: IPlaneSourceInitialValues +): void; + +/** + * Method used to create a new instance of vtkRegularPolygonSource. + * @param {IPlaneSourceInitialValues} [initialValues] for pre-setting some of its content + */ +export function newInstance( + initialValues?: IPlaneSourceInitialValues +): vtkRegularPolygonSource; + +/** + * vtkRegularPolygonSource is a source object that creates a single n-sided + * polygon and/or polyline. The polygon is centered at a specified point, + * orthogonal to a specified normal, and with a circumscribing radius set by the + * user. The user can also specify the number of sides of the polygon ranging + * from [3,N]. + * + * @example + * ```js + * import vtkRegularPolygonSource from '@kitware/vtk.js/Filters/Sources/RegularPolygonSource'; + * + * const regularPolygonSource = vtkRegularPolygonSource.newInstance(); + * const polydata = regularPolygonSource.getOutputData(); + * ``` + */ +export declare const vtkRegularPolygonSource: { + newInstance: typeof newInstance; + extend: typeof extend; +}; +export default vtkRegularPolygonSource; diff --git a/Sources/Filters/Sources/RegularPolygonSource/index.js b/Sources/Filters/Sources/RegularPolygonSource/index.js new file mode 100644 index 00000000000..7aa883fd7b3 --- /dev/null +++ b/Sources/Filters/Sources/RegularPolygonSource/index.js @@ -0,0 +1,166 @@ +import macro from 'vtk.js/Sources/macros'; +import vtkMath from 'vtk.js/Sources/Common/Core/Math'; +import vtkPolyData from 'vtk.js/Sources/Common/DataModel/PolyData'; +import vtkPoints from 'vtk.js/Sources/Common/Core/Points'; +import vtkCellArray from 'vtk.js/Sources/Common/Core/CellArray'; +import { VtkDataTypes } from 'vtk.js/Sources/Common/Core/DataArray/Constants'; +import { DesiredOutputPrecision } from 'vtk.js/Sources/Common/DataModel/DataSetAttributes/Constants'; + +// ---------------------------------------------------------------------------- +// vtkRegularPolygonSource methods +// ---------------------------------------------------------------------------- + +function vtkRegularPolygonSource(publicAPI, model) { + // Set our className + model.classHierarchy.push('vtkRegularPolygonSource'); + + publicAPI.requestData = (inData, outData) => { + const output = outData[0]?.initialize() || vtkPolyData.newInstance(); + const numPts = model.numberOfSides; + + const newPoints = vtkPoints.newInstance({ + dataType: + model.outputPointsPrecision === DesiredOutputPrecision.DOUBLE + ? VtkDataTypes.DOUBLE + : VtkDataTypes.FLOAT, + }); + + // Generate polyline if requested + if (model.generatePolyline) { + const newLine = vtkCellArray.newInstance(); + const linePoints = []; + for (let i = 0; i < numPts; i++) { + linePoints.push(i); + } + linePoints.push(0); // close the polyline + newLine.insertNextCell(linePoints); + output.setLines(newLine); + } + + // Generate polygon if requested + if (model.generatePolygon) { + const newPoly = vtkCellArray.newInstance(); + const polyPoints = []; + for (let i = 0; i < numPts; i++) { + polyPoints.push(i); + } + newPoly.insertNextCell(polyPoints); + output.setPolys(newPoly); + } + + // Make sure the polygon normal is a unit vector + const n = [...model.normal]; + const nLength = vtkMath.normalize(n); + if (nLength === 0.0) { + n[0] = 0.0; + n[1] = 0.0; + n[2] = 1.0; + } + + // Find a vector in the polygon plane (perpendicular to normal) + const px = [0, 0, 0]; + const py = [0, 0, 0]; + let foundPlaneVector = false; + + // Cross with unit axis vectors and eventually find vector in the polygon plane + const axis = [1.0, 0.0, 0.0]; + vtkMath.cross(n, axis, px); + const pxLength = vtkMath.normalize(px); + if (pxLength > 1.0e-3) { + foundPlaneVector = true; + } + + if (!foundPlaneVector) { + axis[0] = 0.0; + axis[1] = 1.0; + axis[2] = 0.0; + vtkMath.cross(n, axis, px); + const pxLength2 = vtkMath.normalize(px); + if (pxLength2 > 1.0e-3) { + foundPlaneVector = true; + } + } + + if (!foundPlaneVector) { + axis[0] = 0.0; + axis[1] = 0.0; + axis[2] = 1.0; + vtkMath.cross(n, axis, px); + vtkMath.normalize(px); + } + + // Create second orthogonal axis in polygon plane + vtkMath.cross(px, n, py); + + // Generate polygon points + const theta = (2.0 * Math.PI) / numPts; + const points = []; + const r = [0, 0, 0]; + const x = [0, 0, 0]; + + for (let j = 0; j < numPts; j++) { + const cosTheta = Math.cos(j * theta); + const sinTheta = Math.sin(j * theta); + + r[0] = px[0] * cosTheta + py[0] * sinTheta; + r[1] = px[1] * cosTheta + py[1] * sinTheta; + r[2] = px[2] * cosTheta + py[2] * sinTheta; + + x[0] = model.center[0] + model.radius * r[0]; + x[1] = model.center[1] + model.radius * r[1]; + x[2] = model.center[2] + model.radius * r[2]; + + points.push(x[0], x[1], x[2]); + } + + newPoints.setData(points); + output.setPoints(newPoints); + + outData[0] = output; + }; +} + +// ---------------------------------------------------------------------------- +// Object factory +// ---------------------------------------------------------------------------- + +const DEFAULT_VALUES = { + numberOfSides: 6, + center: [0.0, 0.0, 0.0], + normal: [0.0, 0.0, 1.0], + radius: 0.5, + generatePolygon: true, + generatePolyline: true, + outputPointsPrecision: DesiredOutputPrecision.FLOAT, +}; + +// ---------------------------------------------------------------------------- + +export function extend(publicAPI, model, initialValues = {}) { + Object.assign(model, DEFAULT_VALUES, initialValues); + + // Build VTK API + macro.obj(publicAPI, model); + macro.algo(publicAPI, model, 0, 1); + + // Build VTK API + macro.setGet(publicAPI, model, [ + 'numberOfSides', + 'radius', + 'generatePolygon', + 'generatePolyline', + 'outputPointsPrecision', + ]); + + macro.setGetArray(publicAPI, model, ['center', 'normal'], 3); + + vtkRegularPolygonSource(publicAPI, model); +} + +// ---------------------------------------------------------------------------- + +export const newInstance = macro.newInstance(extend, 'vtkRegularPolygonSource'); + +// ---------------------------------------------------------------------------- + +export default { newInstance, extend }; diff --git a/Sources/Filters/Sources/RegularPolygonSource/test/testRegularPolygon.js b/Sources/Filters/Sources/RegularPolygonSource/test/testRegularPolygon.js new file mode 100644 index 00000000000..aeafa9ff9c3 --- /dev/null +++ b/Sources/Filters/Sources/RegularPolygonSource/test/testRegularPolygon.js @@ -0,0 +1,64 @@ +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 vtkRegularPolygonSource from 'vtk.js/Sources/Filters/Sources/RegularPolygonSource'; +import vtkActor from 'vtk.js/Sources/Rendering/Core/Actor'; +import vtkMapper from 'vtk.js/Sources/Rendering/Core/Mapper'; +import { Representation } from 'vtk.js/Sources/Rendering/Core/Property/Constants'; + +import baseline from './testRegularPolygon.png'; + +test.onlyIfWebGL('Test vtkRegularPolygonSource Rendering', (t) => { + const gc = testUtils.createGarbageCollector(); + t.ok('rendering', 'vtkRegularPolygonSource 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()); + actor.getProperty().setRepresentation(Representation.WIREFRAME); + + renderer.addActor(actor); + + const mapper = gc.registerResource(vtkMapper.newInstance()); + actor.setMapper(mapper); + + const regularPolygonSource = gc.registerResource( + vtkRegularPolygonSource.newInstance() + ); + mapper.setInputConnection(regularPolygonSource.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/Sources/regularPolygonSource/testRegularPolygon', + t, + 2.5 + ) + ) + .finally(gc.releaseResources); + renderWindow.render(); + return promise; +}); diff --git a/Sources/Filters/Sources/RegularPolygonSource/test/testRegularPolygon.png b/Sources/Filters/Sources/RegularPolygonSource/test/testRegularPolygon.png new file mode 100644 index 0000000000000000000000000000000000000000..2ecb6237063440fb92ea7c136538bab565a2addf GIT binary patch literal 6404 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 literal 0 HcmV?d00001 diff --git a/Sources/Filters/Sources/index.js b/Sources/Filters/Sources/index.js index eeb901b7667..9624826dfca 100644 --- a/Sources/Filters/Sources/index.js +++ b/Sources/Filters/Sources/index.js @@ -13,6 +13,7 @@ import vtkLineSource from './LineSource'; import vtkPlaneSource from './PlaneSource'; import vtkPlatonicSolidSource from './PlatonicSolidSource'; import vtkPointSource from './PointSource'; +import vtkRegularPolygonSource from './RegularPolygonSource'; import vtkRTAnalyticSource from './RTAnalyticSource'; import vtkSLICSource from './SLICSource'; import vtkSphereSource from './SphereSource'; @@ -34,6 +35,7 @@ export default { vtkPlaneSource, vtkPlatonicSolidSource, vtkPointSource, + vtkRegularPolygonSource, vtkRTAnalyticSource, vtkSLICSource, vtkSphereSource,