diff --git a/Documentation/content/docs/gallery/RegularPolygonSource.jpg b/Documentation/content/docs/gallery/RegularPolygonSource.jpg
new file mode 100644
index 00000000000..ded657bbe02
Binary files /dev/null and b/Documentation/content/docs/gallery/RegularPolygonSource.jpg differ
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 @@
+
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 00000000000..2ecb6237063
Binary files /dev/null and b/Sources/Filters/Sources/RegularPolygonSource/test/testRegularPolygon.png differ
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,