Skip to content

Commit 86b85f7

Browse files
dakerfinetjul
authored andcommitted
feat(Sphere): add bounding sphere computation
Add support for computeBoundingSphere and computeBoundingSphereFromSpheres
1 parent 9949cff commit 86b85f7

5 files changed

Lines changed: 462 additions & 0 deletions

File tree

61 KB
Loading
Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
import '@kitware/vtk.js/favicon';
2+
3+
// Load the rendering pieces we want to use (for both WebGL and WebGPU)
4+
import '@kitware/vtk.js/Rendering/Profiles/Geometry';
5+
6+
import vtkSphere from 'vtk.js/Sources/Common/DataModel/Sphere';
7+
import vtkActor from '@kitware/vtk.js/Rendering/Core/Actor';
8+
import vtkMapper from '@kitware/vtk.js/Rendering/Core/Mapper';
9+
import vtkFullScreenRenderWindow from '@kitware/vtk.js/Rendering/Misc/FullScreenRenderWindow';
10+
import vtkSphereSource from '@kitware/vtk.js/Filters/Sources/SphereSource';
11+
12+
import GUI from 'lil-gui';
13+
14+
// ----------------------------------------------------------------------------
15+
// Example code
16+
// ----------------------------------------------------------------------------
17+
18+
const fullScreenRenderer = vtkFullScreenRenderWindow.newInstance();
19+
const renderer = fullScreenRenderer.getRenderer();
20+
const renderWindow = fullScreenRenderer.getRenderWindow();
21+
22+
function makeSphereActor(
23+
center,
24+
radius,
25+
color,
26+
wireframe = false,
27+
opacity = 1.0
28+
) {
29+
const source = vtkSphereSource.newInstance({
30+
center,
31+
radius,
32+
thetaResolution: 50,
33+
phiResolution: 50,
34+
});
35+
const mapper = vtkMapper.newInstance();
36+
mapper.setInputConnection(source.getOutputPort());
37+
38+
const actor = vtkActor.newInstance();
39+
actor.setMapper(mapper);
40+
actor.getProperty().setColor(color[0], color[1], color[2]);
41+
actor.getProperty().setOpacity(opacity);
42+
if (wireframe) {
43+
actor.getProperty().setRepresentationToWireframe();
44+
actor.getProperty().setLineWidth(2);
45+
}
46+
return actor;
47+
}
48+
49+
// ----------------------------------------------------------------------------
50+
// Scene 1: bounding sphere from points (left side)
51+
// ----------------------------------------------------------------------------
52+
const points = [0.0, 0.0, 0.0, 2.0, 0.0, 0.0, 1.0, 1.0, 0.0, -1.0, 0.0, 0.0];
53+
const pointBoundingSphere = vtkSphere.computeBoundingSphere(points);
54+
55+
for (let i = 0; i < points.length; i += 3) {
56+
const point = [points[i], points[i + 1], points[i + 2]];
57+
renderer.addActor(makeSphereActor(point, 0.08, [0.1, 0.7, 1.0]));
58+
}
59+
60+
renderer.addActor(
61+
makeSphereActor(
62+
[pointBoundingSphere[0], pointBoundingSphere[1], pointBoundingSphere[2]],
63+
pointBoundingSphere[3],
64+
[1.0, 0.2, 0.2],
65+
true
66+
)
67+
);
68+
69+
// ----------------------------------------------------------------------------
70+
// Scene 2: bounding sphere from spheres (right side)
71+
// ----------------------------------------------------------------------------
72+
const xOffset = 8.0;
73+
const spheres = [
74+
[0.0 + xOffset, 0.0, 0.0, 1.0],
75+
[4.0 + xOffset, 0.0, 0.0, 1.0],
76+
[2.0 + xOffset, 0.0, 0.0, 0.5],
77+
];
78+
const spheresBoundingSphere =
79+
vtkSphere.computeBoundingSphereFromSpheres(spheres);
80+
81+
spheres.forEach((sphere) => {
82+
renderer.addActor(
83+
makeSphereActor(
84+
[sphere[0], sphere[1], sphere[2]],
85+
sphere[3],
86+
[0.2, 1.0, 0.5],
87+
false,
88+
0.35
89+
)
90+
);
91+
});
92+
93+
renderer.addActor(
94+
makeSphereActor(
95+
[
96+
spheresBoundingSphere[0],
97+
spheresBoundingSphere[1],
98+
spheresBoundingSphere[2],
99+
],
100+
spheresBoundingSphere[3],
101+
[1.0, 0.75, 0.2],
102+
true
103+
)
104+
);
105+
106+
renderer.setBackground(0.12, 0.14, 0.18);
107+
renderer.resetCamera();
108+
renderWindow.render();
109+
110+
const sceneGuide = {
111+
scene1: `Input: cyan points represented as small spheres
112+
Result: red wireframe sphere
113+
API: vtkSphere.computeBoundingSphere(points)`,
114+
scene2: `Input: green spheres
115+
Result: orange wireframe sphere
116+
API: vtkSphere.computeBoundingSphereFromSpheres(spheres)`,
117+
};
118+
119+
const gui = new GUI({ title: 'Controls' });
120+
121+
function addReadOnlyTextArea(folder, object, key, label) {
122+
const controller = folder.add(object, key).name(label).listen().disable();
123+
controller.domElement.style.display = 'block';
124+
controller.domElement.style.minHeight = 'auto';
125+
const nameEl = controller.domElement.querySelector('.name');
126+
const widgetEl = controller.domElement.querySelector('.widget');
127+
if (nameEl) {
128+
nameEl.style.width = '100%';
129+
nameEl.style.paddingBottom = '4px';
130+
}
131+
if (widgetEl) {
132+
widgetEl.style.width = '100%';
133+
}
134+
const input = controller.domElement.querySelector('input');
135+
if (input && input.parentElement) {
136+
const textArea = document.createElement('textarea');
137+
textArea.value = String(object[key]);
138+
textArea.readOnly = true;
139+
textArea.rows = 5;
140+
textArea.style.width = '100%';
141+
textArea.style.resize = 'none';
142+
textArea.style.fontFamily = 'monospace';
143+
textArea.style.fontSize = '11px';
144+
input.parentElement.replaceChild(textArea, input);
145+
}
146+
return controller;
147+
}
148+
149+
addReadOnlyTextArea(gui, sceneGuide, 'scene1', 'Left scene');
150+
addReadOnlyTextArea(gui, sceneGuide, 'scene2', 'Right scene');

Sources/Common/DataModel/Sphere/index.d.ts

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,34 @@ export function newInstance(initialValues?: ISphereInitialValues): vtkSphere;
9090
*/
9191
declare function evaluate(radius: number, center: Vector3, x: Vector3): number;
9292

93+
/**
94+
* Approximate bounding sphere for a point set represented as a flat xyz array.
95+
* Returns `[cx, cy, cz, r]`.
96+
*
97+
* @param {Array<number>|TypedArray} pts flat xyz point coordinates
98+
* @param {number} [numPts] number of points to process
99+
* @param {number[]} [hints] two point ids expected to be far apart
100+
*/
101+
declare function computeBoundingSphere(
102+
pts: Array<number> | ArrayLike<number>,
103+
numPts?: number,
104+
hints?: number[]
105+
): [number, number, number, number];
106+
107+
/**
108+
* Approximate bounding sphere for an array of spheres `[x, y, z, r]`.
109+
* Returns `[cx, cy, cz, r]`.
110+
*
111+
* @param {Array<Vector4>} spheres list of spheres
112+
* @param {number} [numSpheres] number of spheres to process
113+
* @param {number[]} [hints] two sphere ids expected to be far apart
114+
*/
115+
declare function computeBoundingSphereFromSpheres(
116+
spheres: Array<[number, number, number, number]>,
117+
numSpheres?: number,
118+
hints?: number[]
119+
): [number, number, number, number];
120+
93121
/**
94122
* vtkSphere provides methods for creating a 1D cubic spline object from given
95123
* parameters, and allows for the calculation of the spline value and derivative
@@ -99,5 +127,7 @@ export declare const vtkSphere: {
99127
newInstance: typeof newInstance;
100128
extend: typeof extend;
101129
evaluate: typeof evaluate;
130+
computeBoundingSphere: typeof computeBoundingSphere;
131+
computeBoundingSphereFromSpheres: typeof computeBoundingSphereFromSpheres;
102132
};
103133
export default vtkSphere;

0 commit comments

Comments
 (0)