SphereSource

Introduction

vtkSphereSource is a source object that creates a user-specified number of
points within a specified radius about a specified center point. By default
location of the points is random within the sphere. It is also possible to
generate random points only on the surface of the sphere. The output PolyData
has the specified number of points and 1 cell - a vtkPolyVertex containing
all of the points.

Usage

import vtkSphereSource from '@kitware/vtk.js/Filters/Sources/SphereSource';

const sphere = vtkSphereSource.newInstance();
const polydata = sphere.getOutputData();

Methods

extend

Method used to decorate a given object (publicAPI+model) with vtkSphereSource characteristics.

Argument Type Required Description
publicAPI Yes object on which methods will be bounds (public)
model Yes object on which data structure will be bounds (protected)
initialValues ISphereSourceInitialValues No (default: {})

getCenter

Get the center of the sphere.

getCenterByReference

Get the center of the sphere.

getEndPhi

Get the ending latitude angle.

getEndTheta

Set the ending longitude angle.

getLatLongTessellation

getPhiResolution

Get the number of points in the latitude direction (ranging from StartPhi to EndPhi).

getRadius

Get the radius of sphere.

getStartPhi

Get the starting latitude angle in degrees (0 is at north pole).

getStartTheta

Get the starting longitude angle.

getThetaResolution

Get the number of points in the longitude direction (ranging from StartTheta to EndTheta).

newInstance

Method used to create a new instance of vtkSphereSource.

Argument Type Required Description
initialValues ISphereSourceInitialValues No for pre-setting some of its content

requestData

Argument Type Required Description
inData Yes
outData Yes

setCenter

Set the center of the sphere.

Argument Type Required Description
center Vector3 Yes The center point’s coordinates.

setCenter

Set the center of the sphere.

Argument Type Required Description
x Number Yes The x coordinate.
y Number Yes The y coordinate.
z Number Yes The z coordinate.

setCenterFrom

Set the center of the sphere.

Argument Type Required Description
center Vector3 Yes The center point’s coordinates.

setEndPhi

Set the ending latitude angle.

Argument Type Required Description
endPhi Number Yes The ending latitude angle in degrees.

setEndTheta

Set the ending longitude angle.

Argument Type Required Description
endTheta Number Yes The ending latitude longitude in degrees.

setLatLongTessellation

Cause the sphere to be tessellated with edges along the latitude and
longitude lines. If off, triangles are generated at non-polar regions,
which results in edges that are not parallel to latitude and longitude
lines. If on, quadrilaterals are generated everywhere except at the
poles. This can be useful for generating a wireframe sphere with natural
latitude and longitude lines.

Argument Type Required Description
latLongTessellation Boolean Yes

setPhiResolution

Set the number of points in the latitude direction (ranging from StartPhi to EndPhi).

Argument Type Required Description
phiResolution Number Yes The number of points.

setRadius

Set the radius of sphere.

Argument Type Required Description
radius Number Yes The radius of sphere.

setStartPhi

Set the starting latitude angle (0 is at north pole).

Argument Type Required Description
startPhi Number Yes The starting latitude angle in degrees.

setStartTheta

Set the starting longitude angle.

Argument Type Required Description
startTheta Number Yes The starting longitude angle in degrees.

setThetaResolution

Set the number of points in the longitude direction (ranging from StartTheta to EndTheta).

Argument Type Required Description
thetaResolution Number Yes The number of points.

Source

index.d.ts
import { vtkAlgorithm, vtkObject } from "../../../interfaces";
import { Vector3 } from "../../../types";

/**
*
*/
export interface ISphereSourceInitialValues {
radius?: number;
latLongTessellation?: boolean;
thetaResolution?: number;
startTheta?: number;
endTheta?: number;
phiResolution?: number;
startPhi?: number;
endPhi?: number;
center?: Vector3;
pointType?: string;
}

type vtkSphereSourceBase = vtkObject & Omit<vtkAlgorithm,
| 'getInputData'
| 'setInputData'
| 'setInputConnection'
| 'getInputConnection'
| 'addInputConnection'
| 'addInputData'>;

export interface vtkSphereSource extends vtkSphereSourceBase {

/**
* Get the center of the sphere.
* @default [0, 0, 0]
*/
getCenter(): Vector3;

/**
* Get the center of the sphere.
*/
getCenterByReference(): Vector3;


/**
* Get the ending latitude angle.
* @default 180.0
*/
getEndPhi(): number;

/**
* Set the ending longitude angle.
* @default 360.0
*/
getEndTheta(): number;

/**
*
* @default false
*/
getLatLongTessellation(): boolean;

/**
* Get the number of points in the latitude direction (ranging from StartPhi to EndPhi).
* @default 8
*/
getPhiResolution(): number;

/**
* Get the radius of sphere.
* @default 0.5
*/
getRadius(): number;

/**
* Get the starting latitude angle in degrees (0 is at north pole).
* @default 0.0
*/
getStartPhi(): number;

/**
* Get the starting longitude angle.
* @default 0.0
*/
getStartTheta(): number;

/**
* Get the number of points in the longitude direction (ranging from StartTheta to EndTheta).
* @default 8
*/
getThetaResolution(): number;

/**
*
* @param inData
* @param outData
*/
requestData(inData: any, outData: any): void;

/**
* Set the center of the sphere.
* @param {Number} x The x coordinate.
* @param {Number} y The y coordinate.
* @param {Number} z The z coordinate.
*/
setCenter(x: number, y: number, z: number): boolean;

/**
* Set the center of the sphere.
* @param {Vector3} center The center point's coordinates.
*/
setCenter(center: Vector3): boolean;

/**
* Set the center of the sphere.
* @param {Vector3} center The center point's coordinates.
*/
setCenterFrom(center: Vector3): boolean;

/**
* Set the ending latitude angle.
* @param {Number} endPhi The ending latitude angle in degrees.
*/
setEndPhi(endPhi: number): boolean;

/**
* Set the ending longitude angle.
* @param {Number} endTheta The ending latitude longitude in degrees.
*/
setEndTheta(endTheta: number): boolean;

/**
* Cause the sphere to be tessellated with edges along the latitude and
* longitude lines. If off, triangles are generated at non-polar regions,
* which results in edges that are not parallel to latitude and longitude
* lines. If on, quadrilaterals are generated everywhere except at the
* poles. This can be useful for generating a wireframe sphere with natural
* latitude and longitude lines.
* @param {Boolean} latLongTessellation
*/
setLatLongTessellation(latLongTessellation: boolean): boolean;

/**
* Set the number of points in the latitude direction (ranging from StartPhi to EndPhi).
* @param {Number} phiResolution The number of points.
*/
setPhiResolution(phiResolution: number): boolean;

/**
* Set the radius of sphere.
* @param {Number} radius The radius of sphere.
*/
setRadius(radius: number): boolean;

/**
* Set the starting longitude angle.
* @param {Number} startTheta The starting longitude angle in degrees.
*/
setStartTheta(startTheta: number): boolean;

/**
* Set the starting latitude angle (0 is at north pole).
* @param {Number} startPhi The starting latitude angle in degrees.
*/
setStartPhi(startPhi: number): boolean;

/**
* Set the number of points in the longitude direction (ranging from StartTheta to EndTheta).
* @param {Number} thetaResolution The number of points.
*/
setThetaResolution(thetaResolution: number): boolean;
}

/**
* Method used to decorate a given object (publicAPI+model) with vtkSphereSource characteristics.
*
* @param publicAPI object on which methods will be bounds (public)
* @param model object on which data structure will be bounds (protected)
* @param {ISphereSourceInitialValues} [initialValues] (default: {})
*/
export function extend(publicAPI: object, model: object, initialValues?: ISphereSourceInitialValues): void;

/**
* Method used to create a new instance of vtkSphereSource.
* @param {ISphereSourceInitialValues} [initialValues] for pre-setting some of its content
*/
export function newInstance(initialValues?: ISphereSourceInitialValues): vtkSphereSource;

/**
* vtkSphereSource is a source object that creates a user-specified number of
* points within a specified radius about a specified center point. By default
* location of the points is random within the sphere. It is also possible to
* generate random points only on the surface of the sphere. The output PolyData
* has the specified number of points and 1 cell - a vtkPolyVertex containing
* all of the points.
*
* @example
* ```js
* import vtkSphereSource from '@kitware/vtk.js/Filters/Sources/SphereSource';
*
* const sphere = vtkSphereSource.newInstance();
* const polydata = sphere.getOutputData();
* ```
*/
export declare const vtkSphereSource: {
newInstance: typeof newInstance,
extend: typeof extend,
};
export default vtkSphereSource;
index.js
import macro from 'vtk.js/Sources/macros';
import vtkPolyData from 'vtk.js/Sources/Common/DataModel/PolyData';
import vtkDataArray from 'vtk.js/Sources/Common/Core/DataArray';

// ----------------------------------------------------------------------------
// vtkSphereSource methods
// ----------------------------------------------------------------------------

function vtkSphereSource(publicAPI, model) {
// Set our className
model.classHierarchy.push('vtkSphereSource');

publicAPI.requestData = (inData, outData) => {
if (model.deleted) {
return;
}

let dataset = outData[0];
const pointDataType = dataset
? dataset.getPoints().getDataType()
: model.pointType;
dataset = vtkPolyData.newInstance();

// ----------------------------------------------------------------------
let numPoles = 0;

// Check data, determine increments, and convert to radians
let { thetaResolution } = model;
let startTheta =
model.startTheta < model.endTheta ? model.startTheta : model.endTheta;
startTheta *= Math.PI / 180.0;
let endTheta =
model.endTheta > model.startTheta ? model.endTheta : model.startTheta;
endTheta *= Math.PI / 180.0;

let startPhi =
model.startPhi < model.endPhi ? model.startPhi : model.endPhi;
startPhi *= Math.PI / 180.0;
let endPhi = model.endPhi > model.startPhi ? model.endPhi : model.startPhi;
endPhi *= Math.PI / 180.0;

if (Math.abs(startTheta - endTheta) < 2.0 * Math.PI) {
++thetaResolution;
}
const deltaTheta = (endTheta - startTheta) / model.thetaResolution;

const jStart = model.startPhi <= 0.0 ? 1 : 0;
const jEnd = model.phiResolution + (model.endPhi >= 180.0 ? -1 : 0);

const numPts = model.phiResolution * thetaResolution + 2;
const numPolys = model.phiResolution * 2 * model.thetaResolution;

// Points
let pointIdx = 0;
let points = macro.newTypedArray(pointDataType, numPts * 3);

// Normals
let normals = new Float32Array(numPts * 3);

// Cells
let cellLocation = 0;
let polys = new Uint32Array(numPolys * 5);

// Create north pole if needed
if (model.startPhi <= 0.0) {
points[pointIdx * 3 + 0] = model.center[0];
points[pointIdx * 3 + 1] = model.center[1];
points[pointIdx * 3 + 2] = model.center[2] + model.radius;

normals[pointIdx * 3 + 0] = 0;
normals[pointIdx * 3 + 1] = 0;
normals[pointIdx * 3 + 2] = 1;

pointIdx++;
numPoles++;
}

// Create south pole if needed
if (model.endPhi >= 180.0) {
points[pointIdx * 3 + 0] = model.center[0];
points[pointIdx * 3 + 1] = model.center[1];
points[pointIdx * 3 + 2] = model.center[2] - model.radius;

normals[pointIdx * 3 + 0] = 0;
normals[pointIdx * 3 + 1] = 0;
normals[pointIdx * 3 + 2] = -1;

pointIdx++;
numPoles++;
}

const phiResolution = model.phiResolution - numPoles;
const deltaPhi = (endPhi - startPhi) / (model.phiResolution - 1);

// Create intermediate points
for (let i = 0; i < thetaResolution; i++) {
const theta = startTheta + i * deltaTheta;
for (let j = jStart; j < jEnd; j++) {
const phi = startPhi + j * deltaPhi;
const radius = model.radius * Math.sin(phi);

normals[pointIdx * 3 + 0] = radius * Math.cos(theta);
normals[pointIdx * 3 + 1] = radius * Math.sin(theta);
normals[pointIdx * 3 + 2] = model.radius * Math.cos(phi);

points[pointIdx * 3 + 0] = normals[pointIdx * 3 + 0] + model.center[0];
points[pointIdx * 3 + 1] = normals[pointIdx * 3 + 1] + model.center[1];
points[pointIdx * 3 + 2] = normals[pointIdx * 3 + 2] + model.center[2];

let norm = Math.sqrt(
normals[pointIdx * 3 + 0] * normals[pointIdx * 3 + 0] +
normals[pointIdx * 3 + 1] * normals[pointIdx * 3 + 1] +
normals[pointIdx * 3 + 2] * normals[pointIdx * 3 + 2]
);

norm = norm === 0 ? 1 : norm;
normals[pointIdx * 3 + 0] /= norm;
normals[pointIdx * 3 + 1] /= norm;
normals[pointIdx * 3 + 2] /= norm;

pointIdx++;
}
}

// Generate mesh connectivity
const base = phiResolution * thetaResolution;

if (Math.abs(startTheta - endTheta) < 2.0 * Math.PI) {
--thetaResolution;
}

// around north pole
if (model.startPhi <= 0.0) {
for (let i = 0; i < thetaResolution; i++) {
polys[cellLocation++] = 3;
polys[cellLocation++] = phiResolution * i + numPoles;
polys[cellLocation++] = ((phiResolution * (i + 1)) % base) + numPoles;
polys[cellLocation++] = 0;
}
}

// around south pole
if (model.endPhi >= 180.0) {
const numOffset = phiResolution - 1 + numPoles;

for (let i = 0; i < thetaResolution; i++) {
polys[cellLocation++] = 3;
polys[cellLocation++] = phiResolution * i + numOffset;
polys[cellLocation++] = numPoles - 1;
polys[cellLocation++] = ((phiResolution * (i + 1)) % base) + numOffset;
}
}

// bands in-between poles
for (let i = 0; i < thetaResolution; i++) {
for (let j = 0; j < phiResolution - 1; j++) {
const a = phiResolution * i + j + numPoles;
const b = a + 1;
const c = ((phiResolution * (i + 1) + j) % base) + numPoles + 1;

if (!model.latLongTessellation) {
polys[cellLocation++] = 3;
polys[cellLocation++] = a;
polys[cellLocation++] = b;
polys[cellLocation++] = c;
polys[cellLocation++] = 3;
polys[cellLocation++] = a;
polys[cellLocation++] = c;
polys[cellLocation++] = c - 1;
} else {
polys[cellLocation++] = 4;
polys[cellLocation++] = a;
polys[cellLocation++] = b;
polys[cellLocation++] = c;
polys[cellLocation++] = c - 1;
}
}
}

// Squeeze
points = points.subarray(0, pointIdx * 3);
dataset.getPoints().setData(points, 3);

normals = normals.subarray(0, pointIdx * 3);
const normalArray = vtkDataArray.newInstance({
name: 'Normals',
values: normals,
numberOfComponents: 3,
});
dataset.getPointData().setNormals(normalArray);

polys = polys.subarray(0, cellLocation);
dataset.getPolys().setData(polys, 1);

// Update output
outData[0] = dataset;
};
}

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

const DEFAULT_VALUES = {
radius: 0.5,
latLongTessellation: false,
thetaResolution: 8,
startTheta: 0.0,
endTheta: 360.0,
phiResolution: 8,
startPhi: 0.0,
endPhi: 180.0,
center: [0, 0, 0],
pointType: 'Float64Array',
};

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

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

// Build VTK API
macro.obj(publicAPI, model);
macro.setGet(publicAPI, model, [
'radius',
'latLongTessellation',
'thetaResolution',
'startTheta',
'endTheta',
'phiResolution',
'startPhi',
'endPhi',
]);
macro.setGetArray(publicAPI, model, ['center'], 3);
macro.algo(publicAPI, model, 0, 1);
vtkSphereSource(publicAPI, model);
}

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

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

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

export default { newInstance, extend };