Skip to content

Commit bed0aa0

Browse files
authored
Merge pull request #460 from sankhesh/cylinder_source
feat(Sources) Added new source for Cylinder
2 parents bfda1e2 + 94c6611 commit bed0aa0

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)