Skip to content

Commit

Permalink
Merge pull request #442 from Kitware/better-ConcentricCylinderSource
Browse files Browse the repository at this point in the history
fix(ConcentricCylinderSource): Add support for masking layers
  • Loading branch information
jourdain authored Dec 1, 2017
2 parents 1036ca6 + 0027bb5 commit 304e95f
Show file tree
Hide file tree
Showing 3 changed files with 244 additions and 40 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
<table>
<tr>
<td colspan="2">
[s] for surface <br/> [w] for wireframe
</td>
</tr>
<tr>
<td colspan="2">
<hr/>
</td>
</tr>
<tr>
<td>Skip Inner cells</td>
<td>
<input class='skipInnerFaces' type="checkbox" checked />
</td>
</tr>
<tr>
<td colspan="2">
<hr/>
</td>
</tr>
<tr>
<td>Hide Layer 0</td>
<td>
<input class='mask' data-layer="0" type="checkbox" />
</td>
</tr>
<tr>
<td>Hide Layer 1</td>
<td>
<input class='mask' data-layer="1" type="checkbox" />
</td>
</tr>
<tr>
<td>Hide Layer 2</td>
<td>
<input class='mask' data-layer="2" type="checkbox" />
</td>
</tr>
<tr>
<td>Hide Layer 3</td>
<td>
<input class='mask' data-layer="3" type="checkbox" />
</td>
</tr>
<tr>
<td>Hide Layer 4</td>
<td>
<input class='mask' data-layer="4" type="checkbox" />
</td>
</tr>
<tr>
<td>Hide Layer 5</td>
<td>
<input class='mask' data-layer="5" type="checkbox" />
</td>
</tr>
<tr>
<td>Hide Layer 6</td>
<td>
<input class='mask' data-layer="6" type="checkbox" />
</td>
</tr>
<tr>
<td>Hide Layer 7</td>
<td>
<input class='mask' data-layer="7" type="checkbox" />
</td>
</tr>

</table>
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,13 @@ import vtkMapper from 'vtk.js/Sources/Rendering/Core/Mapper';

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

import controlPanel from './controlPanel.html';

// ----------------------------------------------------------------------------
// Standard rendering code setup
// ----------------------------------------------------------------------------

const fullScreenRenderer = vtkFullScreenRenderWindow.newInstance({ background: [0, 0, 0] });
const fullScreenRenderer = vtkFullScreenRenderWindow.newInstance({ background: [0.5, 0.5, 0.5] });
const renderer = fullScreenRenderer.getRenderer();
const renderWindow = fullScreenRenderer.getRenderWindow();

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

// -----------------------------------------------------------
// UI control handling
// -----------------------------------------------------------

fullScreenRenderer.addController(controlPanel);

document.querySelector('.skipInnerFaces').addEventListener('change', (e) => {
const skipInnerFaces = !!(e.target.checked);
cylinder.setSkipInnerFaces(skipInnerFaces);
renderWindow.render();
});

const masksButtons = document.querySelectorAll('.mask');
let count = masksButtons.length;
while (count--) {
masksButtons[count].addEventListener('change', (e) => {
const mask = !!(e.target.checked);
const index = Number(e.target.dataset.layer);
cylinder.setMaskLayer(index, mask);
renderWindow.render();
});
}

// -----------------------------------------------------------
// Make some variables global so that you can inspect and
// modify objects in your browser's developer console:
Expand Down
184 changes: 145 additions & 39 deletions Sources/Filters/Sources/ConcentricCylinderSource/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,34 @@ function vtkConcentricCylinderSource(publicAPI, model) {
publicAPI.setRadius = (index, radius) => { model.radius[index] = radius; publicAPI.modified(); };
publicAPI.setCellField = (index, field) => { model.cellFields[index] = field; publicAPI.modified(); };


publicAPI.removeMask = () => {
model.mask = null;
publicAPI.modified();
};

publicAPI.setMaskLayer = (index, hidden) => {
let changeDetected = false;

if (!model.mask && hidden) {
changeDetected = true;
model.mask = [];
}

if (model.mask) {
if (!model.mask[index] !== !hidden) {
changeDetected = true;
}
model.mask[index] = hidden;
}

if (changeDetected) {
publicAPI.modified();
}
};

publicAPI.getMaskLayer = index => ((index === undefined) ? model.mask : model.mask[index]);

function requestData(inData, outData) {
if (model.deleted || !model.radius.length) {
return;
Expand All @@ -52,8 +80,66 @@ function vtkConcentricCylinderSource(publicAPI, model) {
const angle = 2 * Math.PI / model.resolution;
const zRef = model.height / 2.0;
const numberOfPoints = model.resolution * nbLayers * 2;
const cellArraySize = (2 * (model.resolution + 1)) + (5 * model.resolution) + ((nbLayers - 1) * model.resolution * 20);
const nbCells = 2 + model.resolution + ((nbLayers - 1) * 4 * model.resolution);

// Compute cell count
let cellArraySize = 0;
let nbCells = 0;

if (!model.skipInnerFaces && !model.mask) {
// We keep everything
cellArraySize = (2 * (model.resolution + 1)) + (5 * model.resolution) + ((nbLayers - 1) * model.resolution * 20);
nbCells = 2 + model.resolution + ((nbLayers - 1) * 4 * model.resolution);
} else if (!model.skipInnerFaces && model.mask) {
// We skip some cylinders
// Handle core
if (!model.mask[0]) {
cellArraySize += (2 * (model.resolution + 1)) + (5 * model.resolution);
nbCells += 2 + model.resolution;
}
// Handle inside cylinders
for (let layer = 1; layer < nbLayers; layer++) {
if (!model.mask[layer]) {
// Add inside cylinder count
cellArraySize += model.resolution * 20;
nbCells += 4 * model.resolution;
}
}
} else {
// We skip cylinders and internal faces
if (!model.skipInnerFaces || !model.mask || !model.mask[0]) {
// core handling
cellArraySize += (2 * (model.resolution + 1));
nbCells += 2;
if (model.radius.length === 1 || !model.skipInnerFaces || (model.mask && model.mask[1])) {
// add side faces
cellArraySize += 5 * model.resolution;
nbCells += model.resolution;
}
}

// Handle inside cylinders
for (let layer = 1; layer < nbLayers; layer++) {
if (!model.skipInnerFaces || !model.mask || !model.mask[layer]) {
const lastLayer = (nbLayers - 1 === layer);

// Add inside cylinder
cellArraySize += model.resolution * 10;
nbCells += model.resolution * 2; // top + bottom

// Do we add innerFaces
if (!model.skipInnerFaces || (model.mask && model.mask[layer - 1])) {
cellArraySize += model.resolution * 5;
nbCells += model.resolution;
}

// Do we add outterFaces
if (lastLayer || !model.skipInnerFaces || (model.mask && model.mask[layer + 1])) {
cellArraySize += model.resolution * 5;
nbCells += model.resolution;
}
}
}
}

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

// Core: Top disk
field[fieldLocation++] = currentField;
polys[cellLocation++] = model.resolution;
for (let i = 0; i < model.resolution; i++) {
polys[cellLocation++] = i;
}

// Core: Bottom disk
field[fieldLocation++] = currentField;
polys[cellLocation++] = model.resolution;
for (let i = 0; i < model.resolution; i++) {
polys[cellLocation++] = (2 * model.resolution) - i - 1;
}

// Core: sides
for (let i = 0; i < model.resolution; i++) {
polys[cellLocation++] = 4;
polys[cellLocation++] = (i + 1) % model.resolution;
polys[cellLocation++] = i;
polys[cellLocation++] = i + model.resolution;
polys[cellLocation++] = ((i + 1) % model.resolution) + model.resolution;
// Core: filtering
if (!model.mask || !model.mask[0]) {
// Core: Top disk
field[fieldLocation++] = currentField;
polys[cellLocation++] = model.resolution;
for (let i = 0; i < model.resolution; i++) {
polys[cellLocation++] = i;
}

// Core: Bottom disk
field[fieldLocation++] = currentField;
polys[cellLocation++] = model.resolution;
for (let i = 0; i < model.resolution; i++) {
polys[cellLocation++] = (2 * model.resolution) - i - 1;
}

// Core: sides
if (!model.skipInnerFaces || (model.mask && model.mask[1]) || nbLayers === 1) {
for (let i = 0; i < model.resolution; i++) {
polys[cellLocation++] = 4;
polys[cellLocation++] = (i + 1) % model.resolution;
polys[cellLocation++] = i;
polys[cellLocation++] = i + model.resolution;
polys[cellLocation++] = ((i + 1) % model.resolution) + model.resolution;

field[fieldLocation++] = currentField;
}
}
}

// Create cells for the layers
for (let layer = 1; layer < nbLayers; layer++) {
// Skip layer if masked
if (model.mask && model.mask[layer]) {
/* eslint-disable no-continue */
continue;
/* eslint-enable no-continue */
}

const offset = model.resolution * 2 * (layer - 1);
const lastLayer = (nbLayers - 1 === layer);
currentField = model.cellFields[layer];

// Create top
Expand All @@ -143,25 +242,29 @@ function vtkConcentricCylinderSource(publicAPI, model) {
}

// Create inner
for (let i = 0; i < model.resolution; i++) {
polys[cellLocation++] = 4;
polys[cellLocation++] = i + offset;
polys[cellLocation++] = ((i + 1) % model.resolution) + offset;
polys[cellLocation++] = ((i + 1) % model.resolution) + model.resolution + offset;
polys[cellLocation++] = i + model.resolution + offset;

field[fieldLocation++] = currentField;
if (!model.skipInnerFaces || (model.mask && model.mask[layer - 1])) {
for (let i = 0; i < model.resolution; i++) {
polys[cellLocation++] = 4;
polys[cellLocation++] = i + offset;
polys[cellLocation++] = ((i + 1) % model.resolution) + offset;
polys[cellLocation++] = ((i + 1) % model.resolution) + model.resolution + offset;
polys[cellLocation++] = i + model.resolution + offset;

field[fieldLocation++] = currentField;
}
}

// Create outter
for (let i = 0; i < model.resolution; i++) {
polys[cellLocation++] = 4;
polys[cellLocation++] = ((i + 1) % model.resolution) + offset + (2 * model.resolution);
polys[cellLocation++] = i + offset + (2 * model.resolution);
polys[cellLocation++] = i + model.resolution + offset + (2 * model.resolution);
polys[cellLocation++] = ((i + 1) % model.resolution) + model.resolution + offset + (2 * model.resolution);

field[fieldLocation++] = currentField;
if (!model.skipInnerFaces || lastLayer || (model.mask && (model.mask[layer + 1] || lastLayer))) {
for (let i = 0; i < model.resolution; i++) {
polys[cellLocation++] = 4;
polys[cellLocation++] = ((i + 1) % model.resolution) + offset + (2 * model.resolution);
polys[cellLocation++] = i + offset + (2 * model.resolution);
polys[cellLocation++] = i + model.resolution + offset + (2 * model.resolution);
polys[cellLocation++] = ((i + 1) % model.resolution) + model.resolution + offset + (2 * model.resolution);

field[fieldLocation++] = currentField;
}
}
}

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

Expand All @@ -209,6 +314,7 @@ export function extend(publicAPI, model, initialValues = {}) {
macro.setGet(publicAPI, model, [
'height',
'resolution',
'skipInnerFaces',
]);
macro.setGetArray(publicAPI, model, [
'center',
Expand Down

0 comments on commit 304e95f

Please sign in to comment.