Skip to content

Commit 94c6611

Browse files
committed
feat(Sources) Added new source for Cylinder
Implemented faceted polygons for sides and caps, normals and texture coordinates for cylinder source. Added API documentation, test and example.
1 parent 55779b7 commit 94c6611

File tree

7 files changed

+414
-0
lines changed

7 files changed

+414
-0
lines changed
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
## Usage
2+
3+
```js
4+
import CylinderSource from 'vtk.js/Sources/Filters/Sources/CylinderSource';
5+
6+
const CylinderSource = CylinderSource.New({ height: 2, radius: 1, resolution: 80 });
7+
const polydata = CylinderSource.getOutput();
8+
```
9+
10+
### Height (set/get)
11+
12+
Floating point number representing the height of the cylinder.
13+
14+
### Radius (set/get)
15+
16+
Floating point number representing the radius of the cylinder base.
17+
18+
### Resolution (set/get)
19+
20+
Integer representing the number of facets used to define cylinder.
21+
22+
### Capping (set/get)
23+
24+
Boolean letting you cap the cylinder with polygons at its ends.
25+
26+
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
<table>
2+
<tr>
3+
<td>Height</td>
4+
<td colspan="3">
5+
<input class='height' type="range" min="0.5" max="2.0" step="0.1" value="1.0" />
6+
</td>
7+
</tr>
8+
<tr>
9+
<td>Radius</td>
10+
<td colspan="3">
11+
<input class='radius' type="range" min="0.5" max="2.0" step="0.1" value="1.0" />
12+
</td>
13+
</tr>
14+
<tr>
15+
<td>Resolution</td>
16+
<td colspan="3">
17+
<input class='resolution' type="range" min="4" max="100" step="1" value="6" />
18+
</td>
19+
</tr>
20+
<tr>
21+
<td>Capping</td>
22+
<td colspan="3">
23+
<input class='capping' type="checkbox" checked />
24+
</td>
25+
</tr>
26+
<tr style="text-align: center;">
27+
<td></td>
28+
<td>X</td>
29+
<td>Y</td>
30+
<td>Z</td>
31+
</tr>
32+
<tr>
33+
<td>Origin</td>
34+
<td>
35+
<input style="width: 50px" class='center' data-index="0" type="range" min="-1" max="1" step="0.1" value="0" />
36+
</td>
37+
<td>
38+
<input style="width: 50px" class='center' data-index="1" type="range" min="-1" max="1" step="0.1" value="0" />
39+
</td>
40+
<td>
41+
<input style="width: 50px" class='center' data-index="2" type="range" min="-1" max="1" step="0.1" value="0" />
42+
</td>
43+
</tr>
44+
</table>
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
import 'vtk.js/Sources/favicon';
2+
3+
import vtkFullScreenRenderWindow from 'vtk.js/Sources/Rendering/Misc/FullScreenRenderWindow';
4+
import vtkActor from 'vtk.js/Sources/Rendering/Core/Actor';
5+
import vtkCylinderSource from 'vtk.js/Sources/Filters/Sources/CylinderSource';
6+
import vtkMapper from 'vtk.js/Sources/Rendering/Core/Mapper';
7+
8+
import controlPanel from './controlPanel.html';
9+
10+
// ----------------------------------------------------------------------------
11+
// Standard rendering code setup
12+
// ----------------------------------------------------------------------------
13+
14+
const fullScreenRenderer = vtkFullScreenRenderWindow.newInstance({ background: [0, 0, 0] });
15+
const renderer = fullScreenRenderer.getRenderer();
16+
const renderWindow = fullScreenRenderer.getRenderWindow();
17+
18+
// ----------------------------------------------------------------------------
19+
// Example code
20+
// ----------------------------------------------------------------------------
21+
22+
function createCylinderPipeline() {
23+
const cylinderSource = vtkCylinderSource.newInstance();
24+
const actor = vtkActor.newInstance();
25+
const mapper = vtkMapper.newInstance();
26+
27+
actor.setMapper(mapper);
28+
mapper.setInputConnection(cylinderSource.getOutputPort());
29+
30+
renderer.addActor(actor);
31+
return { cylinderSource, mapper, actor };
32+
}
33+
34+
const pipelines = [createCylinderPipeline(), createCylinderPipeline()];
35+
36+
// Create red wireframe baseline
37+
pipelines[0].actor.getProperty().setRepresentation(1);
38+
pipelines[0].actor.getProperty().setColor(1, 0, 0);
39+
40+
renderer.resetCamera();
41+
renderWindow.render();
42+
43+
// -----------------------------------------------------------
44+
// UI control handling
45+
// -----------------------------------------------------------
46+
47+
fullScreenRenderer.addController(controlPanel);
48+
49+
['height', 'radius', 'resolution'].forEach((propertyName) => {
50+
document.querySelector(`.${propertyName}`).addEventListener('input', (e) => {
51+
const value = Number(e.target.value);
52+
pipelines[0].cylinderSource.set({ [propertyName]: value });
53+
pipelines[1].cylinderSource.set({ [propertyName]: value });
54+
renderWindow.render();
55+
});
56+
});
57+
58+
document.querySelector('.capping').addEventListener('change', (e) => {
59+
const capping = !!(e.target.checked);
60+
pipelines[0].cylinderSource.set({ capping });
61+
pipelines[1].cylinderSource.set({ capping });
62+
renderWindow.render();
63+
});
64+
65+
const centerElems = document.querySelectorAll('.center');
66+
67+
function updateTransformedCylinder() {
68+
const center = [0, 0, 0];
69+
for (let i = 0; i < 3; i++) {
70+
center[Number(centerElems[i].dataset.index)] = Number(centerElems[i].value);
71+
}
72+
console.log('updateTransformedCylinder', center);
73+
pipelines[1].cylinderSource.set({ center });
74+
renderWindow.render();
75+
}
76+
77+
for (let i = 0; i < 3; i++) {
78+
centerElems[i].addEventListener('input', updateTransformedCylinder);
79+
}
80+
81+
// -----------------------------------------------------------
82+
// Make some variables global so that you can inspect and
83+
// modify objects in your browser's developer console:
84+
// -----------------------------------------------------------
85+
86+
global.pipelines = pipelines;
87+
global.renderer = renderer;
88+
global.renderWindow = renderWindow;
Lines changed: 199 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,199 @@
1+
import macro from 'vtk.js/Sources/macro';
2+
import vtkDataArray from 'vtk.js/Sources/Common/Core/DataArray';
3+
import vtkPolyData from 'vtk.js/Sources/Common/DataModel/PolyData';
4+
5+
// ----------------------------------------------------------------------------
6+
// vtkCylinderSource methods
7+
// ----------------------------------------------------------------------------
8+
9+
function vtkCylinderSource(publicAPI, model) {
10+
// Set our classname
11+
model.classHierarchy.push('vtkCylinderSource');
12+
13+
function requestData(inData, outData) {
14+
if (model.deleted) {
15+
return;
16+
}
17+
18+
let dataset = outData[0];
19+
20+
const angle = 2.0 * Math.PI / model.resolution;
21+
let numberOfPoints = 2 * model.resolution;
22+
let numberOfPolys = 5 * model.resolution;
23+
24+
if (model.capping) {
25+
numberOfPoints = 4 * model.resolution;
26+
numberOfPolys = (7 * model.resolution) + 2;
27+
}
28+
29+
// Points
30+
const points = new window[model.pointType](numberOfPoints * 3);
31+
32+
// Cells
33+
let cellLocation = 0;
34+
const polys = new Uint32Array(numberOfPolys);
35+
36+
// Normals
37+
const normalsData = new Float32Array(numberOfPoints * 3);
38+
const normals = vtkDataArray.newInstance(
39+
{ numberOfComponents: 3, values: normalsData, name: 'Normals' });
40+
41+
// Texture coords
42+
const tcData = new Float32Array(numberOfPoints * 2);
43+
const tcoords = vtkDataArray.newInstance(
44+
{ numberOfComponents: 2, values: tcData, name: 'TCoords' });
45+
46+
// Generate points for all sides
47+
const nbot = [0.0, 0.0, 0.0];
48+
const ntop = [0.0, 0.0, 0.0];
49+
const xbot = [0.0, 0.0, 0.0];
50+
const xtop = [0.0, 0.0, 0.0];
51+
const tcbot = [0.0, 0.0];
52+
const tctop = [0.0, 0.0];
53+
for (let i = 0; i < model.resolution; i++) {
54+
// x coordinate
55+
nbot[0] = Math.cos(i * angle);
56+
ntop[0] = nbot[0];
57+
xbot[0] = (model.radius * nbot[0]) + model.center[0];
58+
xtop[0] = xbot[0];
59+
tcbot[0] = Math.abs((2.0 * i / model.resolution) - 1.0);
60+
tctop[0] = tcbot[0];
61+
62+
// y coordinate
63+
xbot[1] = (0.5 * model.height) + model.center[1];
64+
xtop[1] = (-0.5 * model.height) + model.center[1];
65+
tcbot[1] = 0.0;
66+
tctop[1] = 1.0;
67+
68+
// z coordinate
69+
nbot[2] = -(Math.sin(i * angle));
70+
ntop[2] = nbot[2];
71+
xbot[2] = (model.radius * nbot[2]) + model.center[2];
72+
xtop[2] = xbot[2];
73+
74+
const pointIdx = 2 * i;
75+
for (let j = 0; j < 3; j++) {
76+
normalsData[(pointIdx * 3) + j] = nbot[j];
77+
normalsData[((pointIdx + 1) * 3) + j] = ntop[j];
78+
points[(pointIdx * 3) + j] = xbot[j];
79+
points[((pointIdx + 1) * 3) + j] = xtop[j];
80+
if (j < 2) {
81+
tcData[(pointIdx * 2) + j] = tcbot[j];
82+
tcData[((pointIdx + 1) * 2) + j] = tctop[j];
83+
}
84+
}
85+
}
86+
87+
// Generate polygons for sides
88+
for (let i = 0; i < model.resolution; i++) {
89+
polys[cellLocation++] = 4;
90+
polys[cellLocation++] = 2 * i;
91+
polys[cellLocation++] = (2 * i) + 1;
92+
const pt = ((2 * i) + 3) % (2 * model.resolution);
93+
polys[cellLocation++] = pt;
94+
polys[cellLocation++] = pt - 1;
95+
}
96+
97+
if (model.capping) {
98+
// Generate points for top/bottom polygons
99+
for (let i = 0; i < model.resolution; i++) {
100+
// x coordinate
101+
xbot[0] = model.radius * Math.cos(i * angle);
102+
xtop[0] = xbot[0];
103+
tcbot[0] = xbot[0];
104+
tctop[0] = xbot[0];
105+
xbot[0] += model.center[0];
106+
xtop[0] += model.center[0];
107+
108+
// y coordinate
109+
nbot[1] = 1.0;
110+
ntop[1] = -1.0;
111+
xbot[1] = (0.5 * model.height) + model.center[1];
112+
xtop[1] = (-0.5 * model.height) + model.center[1];
113+
114+
// z coordinate
115+
xbot[2] = -model.radius * Math.sin(i * angle);
116+
xtop[2] = xbot[2];
117+
tcbot[1] = xbot[2];
118+
tctop[1] = xbot[2];
119+
xbot[2] += model.center[2];
120+
xtop[2] += model.center[2];
121+
const botIdx = (2 * model.resolution) + i;
122+
const topIdx = (3 * model.resolution) + model.resolution - i - 1;
123+
for (let j = 0; j < 3; j++) {
124+
normalsData[(3 * botIdx) + j] = nbot[j];
125+
normalsData[(3 * topIdx) + j] = ntop[j];
126+
points[(3 * botIdx) + j] = xbot[j];
127+
points[(3 * topIdx) + j] = xtop[j];
128+
if (j < 2) {
129+
tcData[(2 * botIdx) + j] = tcbot[j];
130+
tcData[(2 * topIdx) + j] = tctop[j];
131+
}
132+
}
133+
}
134+
135+
// Generate polygons for top/bottom
136+
polys[cellLocation++] = model.resolution;
137+
for (let i = 0; i < model.resolution; i++) {
138+
polys[cellLocation++] = (2 * model.resolution) + i;
139+
}
140+
polys[cellLocation++] = model.resolution;
141+
for (let i = 0; i < model.resolution; i++) {
142+
polys[cellLocation++] = (3 * model.resolution) + i;
143+
}
144+
}
145+
146+
dataset = vtkPolyData.newInstance();
147+
dataset.getPoints().setData(points, 3);
148+
dataset.getPolys().setData(polys, 1);
149+
dataset.getPointData().setNormals(normals);
150+
dataset.getPointData().setTCoords(tcoords);
151+
152+
// Update output
153+
outData[0] = dataset;
154+
}
155+
156+
// Expose methods
157+
publicAPI.requestData = requestData;
158+
}
159+
160+
// ----------------------------------------------------------------------------
161+
// Object factory
162+
// ----------------------------------------------------------------------------
163+
164+
const DEFAULT_VALUES = {
165+
height: 1.0,
166+
radius: 1.0,
167+
resolution: 6,
168+
center: [0, 0, 0],
169+
capping: true,
170+
pointType: 'Float32Array',
171+
};
172+
173+
// ----------------------------------------------------------------------------
174+
175+
export function extend(publicAPI, model, initialValues = {}) {
176+
Object.assign(model, DEFAULT_VALUES, initialValues);
177+
178+
// Build VTK API
179+
macro.obj(publicAPI, model);
180+
macro.setGet(publicAPI, model, [
181+
'height',
182+
'radius',
183+
'resolution',
184+
'capping',
185+
]);
186+
macro.setGetArray(publicAPI, model, [
187+
'center',
188+
], 3);
189+
macro.algo(publicAPI, model, 0, 1);
190+
vtkCylinderSource(publicAPI, model);
191+
}
192+
193+
// ----------------------------------------------------------------------------
194+
195+
export const newInstance = macro.newInstance(extend, 'vtkCylinderSource');
196+
197+
// ----------------------------------------------------------------------------
198+
199+
export default { newInstance, extend };

0 commit comments

Comments
 (0)