Skip to content

Commit 304e95f

Browse files
authored
Merge pull request #442 from Kitware/better-ConcentricCylinderSource
fix(ConcentricCylinderSource): Add support for masking layers
2 parents 1036ca6 + 0027bb5 commit 304e95f

File tree

3 files changed

+244
-40
lines changed

3 files changed

+244
-40
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
<table>
2+
<tr>
3+
<td colspan="2">
4+
[s] for surface <br/> [w] for wireframe
5+
</td>
6+
</tr>
7+
<tr>
8+
<td colspan="2">
9+
<hr/>
10+
</td>
11+
</tr>
12+
<tr>
13+
<td>Skip Inner cells</td>
14+
<td>
15+
<input class='skipInnerFaces' type="checkbox" checked />
16+
</td>
17+
</tr>
18+
<tr>
19+
<td colspan="2">
20+
<hr/>
21+
</td>
22+
</tr>
23+
<tr>
24+
<td>Hide Layer 0</td>
25+
<td>
26+
<input class='mask' data-layer="0" type="checkbox" />
27+
</td>
28+
</tr>
29+
<tr>
30+
<td>Hide Layer 1</td>
31+
<td>
32+
<input class='mask' data-layer="1" type="checkbox" />
33+
</td>
34+
</tr>
35+
<tr>
36+
<td>Hide Layer 2</td>
37+
<td>
38+
<input class='mask' data-layer="2" type="checkbox" />
39+
</td>
40+
</tr>
41+
<tr>
42+
<td>Hide Layer 3</td>
43+
<td>
44+
<input class='mask' data-layer="3" type="checkbox" />
45+
</td>
46+
</tr>
47+
<tr>
48+
<td>Hide Layer 4</td>
49+
<td>
50+
<input class='mask' data-layer="4" type="checkbox" />
51+
</td>
52+
</tr>
53+
<tr>
54+
<td>Hide Layer 5</td>
55+
<td>
56+
<input class='mask' data-layer="5" type="checkbox" />
57+
</td>
58+
</tr>
59+
<tr>
60+
<td>Hide Layer 6</td>
61+
<td>
62+
<input class='mask' data-layer="6" type="checkbox" />
63+
</td>
64+
</tr>
65+
<tr>
66+
<td>Hide Layer 7</td>
67+
<td>
68+
<input class='mask' data-layer="7" type="checkbox" />
69+
</td>
70+
</tr>
71+
72+
</table>

Sources/Filters/Sources/ConcentricCylinderSource/example/index.js

+27-1
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,13 @@ import vtkMapper from 'vtk.js/Sources/Rendering/Core/Mapper';
77

88
// import { ColorMode, ScalarMode } from 'vtk.js/Sources/Rendering/Core/Mapper/Constants';
99

10+
import controlPanel from './controlPanel.html';
11+
1012
// ----------------------------------------------------------------------------
1113
// Standard rendering code setup
1214
// ----------------------------------------------------------------------------
1315

14-
const fullScreenRenderer = vtkFullScreenRenderWindow.newInstance({ background: [0, 0, 0] });
16+
const fullScreenRenderer = vtkFullScreenRenderWindow.newInstance({ background: [0.5, 0.5, 0.5] });
1517
const renderer = fullScreenRenderer.getRenderer();
1618
const renderWindow = fullScreenRenderer.getRenderWindow();
1719

@@ -24,6 +26,7 @@ const cylinder = vtkConcentricCylinderSource.newInstance({
2426
radius: [0.2, 0.3, 0.4, 0.6, 0.7, 0.8, 0.9, 1],
2527
cellFields: [0, 0.2, 0.4, 0.6, 0.7, 0.8, 0.9, 1],
2628
resolution: 120,
29+
skipInnerFaces: true,
2730
});
2831
const actor = vtkActor.newInstance();
2932
const mapper = vtkMapper.newInstance();
@@ -39,6 +42,29 @@ renderer.addActor(actor);
3942
renderer.resetCamera();
4043
renderWindow.render();
4144

45+
// -----------------------------------------------------------
46+
// UI control handling
47+
// -----------------------------------------------------------
48+
49+
fullScreenRenderer.addController(controlPanel);
50+
51+
document.querySelector('.skipInnerFaces').addEventListener('change', (e) => {
52+
const skipInnerFaces = !!(e.target.checked);
53+
cylinder.setSkipInnerFaces(skipInnerFaces);
54+
renderWindow.render();
55+
});
56+
57+
const masksButtons = document.querySelectorAll('.mask');
58+
let count = masksButtons.length;
59+
while (count--) {
60+
masksButtons[count].addEventListener('change', (e) => {
61+
const mask = !!(e.target.checked);
62+
const index = Number(e.target.dataset.layer);
63+
cylinder.setMaskLayer(index, mask);
64+
renderWindow.render();
65+
});
66+
}
67+
4268
// -----------------------------------------------------------
4369
// Make some variables global so that you can inspect and
4470
// modify objects in your browser's developer console:

Sources/Filters/Sources/ConcentricCylinderSource/index.js

+145-39
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,34 @@ function vtkConcentricCylinderSource(publicAPI, model) {
3838
publicAPI.setRadius = (index, radius) => { model.radius[index] = radius; publicAPI.modified(); };
3939
publicAPI.setCellField = (index, field) => { model.cellFields[index] = field; publicAPI.modified(); };
4040

41+
42+
publicAPI.removeMask = () => {
43+
model.mask = null;
44+
publicAPI.modified();
45+
};
46+
47+
publicAPI.setMaskLayer = (index, hidden) => {
48+
let changeDetected = false;
49+
50+
if (!model.mask && hidden) {
51+
changeDetected = true;
52+
model.mask = [];
53+
}
54+
55+
if (model.mask) {
56+
if (!model.mask[index] !== !hidden) {
57+
changeDetected = true;
58+
}
59+
model.mask[index] = hidden;
60+
}
61+
62+
if (changeDetected) {
63+
publicAPI.modified();
64+
}
65+
};
66+
67+
publicAPI.getMaskLayer = index => ((index === undefined) ? model.mask : model.mask[index]);
68+
4169
function requestData(inData, outData) {
4270
if (model.deleted || !model.radius.length) {
4371
return;
@@ -52,8 +80,66 @@ function vtkConcentricCylinderSource(publicAPI, model) {
5280
const angle = 2 * Math.PI / model.resolution;
5381
const zRef = model.height / 2.0;
5482
const numberOfPoints = model.resolution * nbLayers * 2;
55-
const cellArraySize = (2 * (model.resolution + 1)) + (5 * model.resolution) + ((nbLayers - 1) * model.resolution * 20);
56-
const nbCells = 2 + model.resolution + ((nbLayers - 1) * 4 * model.resolution);
83+
84+
// Compute cell count
85+
let cellArraySize = 0;
86+
let nbCells = 0;
87+
88+
if (!model.skipInnerFaces && !model.mask) {
89+
// We keep everything
90+
cellArraySize = (2 * (model.resolution + 1)) + (5 * model.resolution) + ((nbLayers - 1) * model.resolution * 20);
91+
nbCells = 2 + model.resolution + ((nbLayers - 1) * 4 * model.resolution);
92+
} else if (!model.skipInnerFaces && model.mask) {
93+
// We skip some cylinders
94+
// Handle core
95+
if (!model.mask[0]) {
96+
cellArraySize += (2 * (model.resolution + 1)) + (5 * model.resolution);
97+
nbCells += 2 + model.resolution;
98+
}
99+
// Handle inside cylinders
100+
for (let layer = 1; layer < nbLayers; layer++) {
101+
if (!model.mask[layer]) {
102+
// Add inside cylinder count
103+
cellArraySize += model.resolution * 20;
104+
nbCells += 4 * model.resolution;
105+
}
106+
}
107+
} else {
108+
// We skip cylinders and internal faces
109+
if (!model.skipInnerFaces || !model.mask || !model.mask[0]) {
110+
// core handling
111+
cellArraySize += (2 * (model.resolution + 1));
112+
nbCells += 2;
113+
if (model.radius.length === 1 || !model.skipInnerFaces || (model.mask && model.mask[1])) {
114+
// add side faces
115+
cellArraySize += 5 * model.resolution;
116+
nbCells += model.resolution;
117+
}
118+
}
119+
120+
// Handle inside cylinders
121+
for (let layer = 1; layer < nbLayers; layer++) {
122+
if (!model.skipInnerFaces || !model.mask || !model.mask[layer]) {
123+
const lastLayer = (nbLayers - 1 === layer);
124+
125+
// Add inside cylinder
126+
cellArraySize += model.resolution * 10;
127+
nbCells += model.resolution * 2; // top + bottom
128+
129+
// Do we add innerFaces
130+
if (!model.skipInnerFaces || (model.mask && model.mask[layer - 1])) {
131+
cellArraySize += model.resolution * 5;
132+
nbCells += model.resolution;
133+
}
134+
135+
// Do we add outterFaces
136+
if (lastLayer || !model.skipInnerFaces || (model.mask && model.mask[layer + 1])) {
137+
cellArraySize += model.resolution * 5;
138+
nbCells += model.resolution;
139+
}
140+
}
141+
}
142+
}
57143

58144
// Points
59145
let pointIdx = 0;
@@ -90,34 +176,47 @@ function vtkConcentricCylinderSource(publicAPI, model) {
90176
// Create cells for the core
91177
let currentField = model.cellFields[0];
92178

93-
// Core: Top disk
94-
field[fieldLocation++] = currentField;
95-
polys[cellLocation++] = model.resolution;
96-
for (let i = 0; i < model.resolution; i++) {
97-
polys[cellLocation++] = i;
98-
}
99-
100-
// Core: Bottom disk
101-
field[fieldLocation++] = currentField;
102-
polys[cellLocation++] = model.resolution;
103-
for (let i = 0; i < model.resolution; i++) {
104-
polys[cellLocation++] = (2 * model.resolution) - i - 1;
105-
}
106-
107-
// Core: sides
108-
for (let i = 0; i < model.resolution; i++) {
109-
polys[cellLocation++] = 4;
110-
polys[cellLocation++] = (i + 1) % model.resolution;
111-
polys[cellLocation++] = i;
112-
polys[cellLocation++] = i + model.resolution;
113-
polys[cellLocation++] = ((i + 1) % model.resolution) + model.resolution;
179+
// Core: filtering
180+
if (!model.mask || !model.mask[0]) {
181+
// Core: Top disk
182+
field[fieldLocation++] = currentField;
183+
polys[cellLocation++] = model.resolution;
184+
for (let i = 0; i < model.resolution; i++) {
185+
polys[cellLocation++] = i;
186+
}
114187

188+
// Core: Bottom disk
115189
field[fieldLocation++] = currentField;
190+
polys[cellLocation++] = model.resolution;
191+
for (let i = 0; i < model.resolution; i++) {
192+
polys[cellLocation++] = (2 * model.resolution) - i - 1;
193+
}
194+
195+
// Core: sides
196+
if (!model.skipInnerFaces || (model.mask && model.mask[1]) || nbLayers === 1) {
197+
for (let i = 0; i < model.resolution; i++) {
198+
polys[cellLocation++] = 4;
199+
polys[cellLocation++] = (i + 1) % model.resolution;
200+
polys[cellLocation++] = i;
201+
polys[cellLocation++] = i + model.resolution;
202+
polys[cellLocation++] = ((i + 1) % model.resolution) + model.resolution;
203+
204+
field[fieldLocation++] = currentField;
205+
}
206+
}
116207
}
117208

118209
// Create cells for the layers
119210
for (let layer = 1; layer < nbLayers; layer++) {
211+
// Skip layer if masked
212+
if (model.mask && model.mask[layer]) {
213+
/* eslint-disable no-continue */
214+
continue;
215+
/* eslint-enable no-continue */
216+
}
217+
120218
const offset = model.resolution * 2 * (layer - 1);
219+
const lastLayer = (nbLayers - 1 === layer);
121220
currentField = model.cellFields[layer];
122221

123222
// Create top
@@ -143,25 +242,29 @@ function vtkConcentricCylinderSource(publicAPI, model) {
143242
}
144243

145244
// Create inner
146-
for (let i = 0; i < model.resolution; i++) {
147-
polys[cellLocation++] = 4;
148-
polys[cellLocation++] = i + offset;
149-
polys[cellLocation++] = ((i + 1) % model.resolution) + offset;
150-
polys[cellLocation++] = ((i + 1) % model.resolution) + model.resolution + offset;
151-
polys[cellLocation++] = i + model.resolution + offset;
152-
153-
field[fieldLocation++] = currentField;
245+
if (!model.skipInnerFaces || (model.mask && model.mask[layer - 1])) {
246+
for (let i = 0; i < model.resolution; i++) {
247+
polys[cellLocation++] = 4;
248+
polys[cellLocation++] = i + offset;
249+
polys[cellLocation++] = ((i + 1) % model.resolution) + offset;
250+
polys[cellLocation++] = ((i + 1) % model.resolution) + model.resolution + offset;
251+
polys[cellLocation++] = i + model.resolution + offset;
252+
253+
field[fieldLocation++] = currentField;
254+
}
154255
}
155256

156257
// Create outter
157-
for (let i = 0; i < model.resolution; i++) {
158-
polys[cellLocation++] = 4;
159-
polys[cellLocation++] = ((i + 1) % model.resolution) + offset + (2 * model.resolution);
160-
polys[cellLocation++] = i + offset + (2 * model.resolution);
161-
polys[cellLocation++] = i + model.resolution + offset + (2 * model.resolution);
162-
polys[cellLocation++] = ((i + 1) % model.resolution) + model.resolution + offset + (2 * model.resolution);
163-
164-
field[fieldLocation++] = currentField;
258+
if (!model.skipInnerFaces || lastLayer || (model.mask && (model.mask[layer + 1] || lastLayer))) {
259+
for (let i = 0; i < model.resolution; i++) {
260+
polys[cellLocation++] = 4;
261+
polys[cellLocation++] = ((i + 1) % model.resolution) + offset + (2 * model.resolution);
262+
polys[cellLocation++] = i + offset + (2 * model.resolution);
263+
polys[cellLocation++] = i + model.resolution + offset + (2 * model.resolution);
264+
polys[cellLocation++] = ((i + 1) % model.resolution) + model.resolution + offset + (2 * model.resolution);
265+
266+
field[fieldLocation++] = currentField;
267+
}
165268
}
166269
}
167270

@@ -196,6 +299,8 @@ const DEFAULT_VALUES = {
196299
resolution: 6,
197300
center: [0, 0, 0],
198301
direction: [0.0, 0.0, 1.0],
302+
skipInnerFaces: true,
303+
mask: null, // If present, array to know if a layer should be skipped(=true)
199304
pointType: 'Float32Array',
200305
};
201306

@@ -209,6 +314,7 @@ export function extend(publicAPI, model, initialValues = {}) {
209314
macro.setGet(publicAPI, model, [
210315
'height',
211316
'resolution',
317+
'skipInnerFaces',
212318
]);
213319
macro.setGetArray(publicAPI, model, [
214320
'center',

0 commit comments

Comments
 (0)