From bd97006524ba1156b88d76cab97eba9b90c9c859 Mon Sep 17 00:00:00 2001 From: Sebastien Jourdain Date: Tue, 28 Nov 2017 13:42:39 -0700 Subject: [PATCH] fix(ConcentricCylinderSource): Add new source to build concentric cylinders --- .../ConcentricCylinderSource/example/index.js | 49 ++++ .../Sources/ConcentricCylinderSource/index.js | 227 ++++++++++++++++++ Sources/Filters/Sources/index.js | 20 +- 3 files changed, 287 insertions(+), 9 deletions(-) create mode 100644 Sources/Filters/Sources/ConcentricCylinderSource/example/index.js create mode 100644 Sources/Filters/Sources/ConcentricCylinderSource/index.js diff --git a/Sources/Filters/Sources/ConcentricCylinderSource/example/index.js b/Sources/Filters/Sources/ConcentricCylinderSource/example/index.js new file mode 100644 index 00000000000..06774a39b98 --- /dev/null +++ b/Sources/Filters/Sources/ConcentricCylinderSource/example/index.js @@ -0,0 +1,49 @@ +import 'vtk.js/Sources/favicon'; + +import vtkFullScreenRenderWindow from 'vtk.js/Sources/Rendering/Misc/FullScreenRenderWindow'; +import vtkActor from 'vtk.js/Sources/Rendering/Core/Actor'; +import vtkConcentricCylinderSource from 'vtk.js/Sources/Filters/Sources/ConcentricCylinderSource'; +import vtkMapper from 'vtk.js/Sources/Rendering/Core/Mapper'; + +// import { ColorMode, ScalarMode } from 'vtk.js/Sources/Rendering/Core/Mapper/Constants'; + +// ---------------------------------------------------------------------------- +// Standard rendering code setup +// ---------------------------------------------------------------------------- + +const fullScreenRenderer = vtkFullScreenRenderWindow.newInstance({ background: [0, 0, 0] }); +const renderer = fullScreenRenderer.getRenderer(); +const renderWindow = fullScreenRenderer.getRenderWindow(); + +// ---------------------------------------------------------------------------- +// Example code +// ---------------------------------------------------------------------------- + +const cylinder = vtkConcentricCylinderSource.newInstance({ + height: 0.25, + 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, +}); +const actor = vtkActor.newInstance(); +const mapper = vtkMapper.newInstance(); + +actor.setMapper(mapper); +mapper.setInputConnection(cylinder.getOutputPort()); + +const lut = mapper.getLookupTable(); +lut.setValueRange(0.2, 1); +lut.setHueRange(0.666, 0); + +renderer.addActor(actor); +renderer.resetCamera(); +renderWindow.render(); + +// ----------------------------------------------------------- +// Make some variables global so that you can inspect and +// modify objects in your browser's developer console: +// ----------------------------------------------------------- + +global.cylinder = cylinder; +global.renderer = renderer; +global.renderWindow = renderWindow; diff --git a/Sources/Filters/Sources/ConcentricCylinderSource/index.js b/Sources/Filters/Sources/ConcentricCylinderSource/index.js new file mode 100644 index 00000000000..288752f6a6e --- /dev/null +++ b/Sources/Filters/Sources/ConcentricCylinderSource/index.js @@ -0,0 +1,227 @@ +import macro from 'vtk.js/Sources/macro'; +import vtkPolyData from 'vtk.js/Sources/Common/DataModel/PolyData'; +import vtkMatrixBuilder from 'vtk.js/Sources/Common/Core/MatrixBuilder'; +import vtkDataArray from 'vtk.js/Sources/Common/Core/DataArray'; + +// ---------------------------------------------------------------------------- +// vtkConcentricCylinderSource methods +// ---------------------------------------------------------------------------- + +function vtkConcentricCylinderSource(publicAPI, model) { + // Set our className + model.classHierarchy.push('vtkConcentricCylinderSource'); + + // Internal private function + function validateCellFields() { + while (model.cellFields.length < model.radius.length) { + model.cellFields.push(model.cellFields.length); + } + } + + publicAPI.clearRadius = () => { + model.radius = []; + model.cellFields = []; + publicAPI.modified(); + }; + + publicAPI.addRadius = (radius, cellField) => { + model.radius.push(radius); + if (cellField !== undefined) { + model.cellFields.push(cellField); + } + validateCellFields(); + publicAPI.modified(); + }; + + publicAPI.getNumberOfRadius = () => model.radius.length; + publicAPI.getRadius = (index = 0) => model.radius[index]; + publicAPI.setRadius = (index, radius) => { model.radius[index] = radius; publicAPI.modified(); }; + publicAPI.setCellField = (index, field) => { model.cellFields[index] = field; publicAPI.modified(); }; + + function requestData(inData, outData) { + if (model.deleted || !model.radius.length) { + return; + } + + // Make sure we have concistency + validateCellFields(); + + let dataset = outData[0]; + + const nbLayers = model.radius.length; + 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); + + // Points + let pointIdx = 0; + const points = new window[model.pointType](numberOfPoints * 3); + + // Cells + let cellLocation = 0; + const polys = new Uint32Array(cellArraySize); + + // CellFields + let fieldLocation = 0; + const field = new Float32Array(nbCells); + + // Create points + for (let layer = 0; layer < nbLayers; layer++) { + const radius = model.radius[layer]; + // Create top + for (let i = 0; i < model.resolution; i++) { + points[(pointIdx * 3) + 0] = radius * Math.cos(i * angle); + points[(pointIdx * 3) + 1] = radius * Math.sin(i * angle); + points[(pointIdx * 3) + 2] = zRef; + pointIdx++; + } + + // Create bottom + for (let i = 0; i < model.resolution; i++) { + points[(pointIdx * 3) + 0] = radius * Math.cos(i * angle); + points[(pointIdx * 3) + 1] = radius * Math.sin(i * angle); + points[(pointIdx * 3) + 2] = -zRef; + pointIdx++; + } + } + + // 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; + + field[fieldLocation++] = currentField; + } + + // Create cells for the layers + for (let layer = 1; layer < nbLayers; layer++) { + const offset = model.resolution * 2 * (layer - 1); + currentField = model.cellFields[layer]; + + // Create top + 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) + (2 * model.resolution) + offset; + polys[cellLocation++] = i + (2 * model.resolution) + offset; + + field[fieldLocation++] = currentField; + } + + // Create bottom + for (let i = 0; i < model.resolution; i++) { + polys[cellLocation++] = 4; + polys[cellLocation++] = ((i + 1) % model.resolution) + offset + model.resolution; + polys[cellLocation++] = i + offset + model.resolution; + polys[cellLocation++] = i + (2 * model.resolution) + offset + model.resolution; + polys[cellLocation++] = ((i + 1) % model.resolution) + (2 * model.resolution) + offset + model.resolution; + + field[fieldLocation++] = currentField; + } + + // 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; + } + + // 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; + } + } + + // Apply tranformation to the points coordinates + vtkMatrixBuilder + .buildFromRadian() + .translate(...model.center) + .rotateFromDirections([0, 0, 1], model.direction) + .apply(points); + + dataset = vtkPolyData.newInstance(); + dataset.getPoints().setData(points, 3); + dataset.getPolys().setData(polys, 1); + dataset.getCellData().setScalars(vtkDataArray.newInstance({ name: 'layer', values: field })); + + // Update output + outData[0] = dataset; + } + + // Expose methods + publicAPI.requestData = requestData; +} + +// ---------------------------------------------------------------------------- +// Object factory +// ---------------------------------------------------------------------------- + +const DEFAULT_VALUES = { + height: 1.0, + radius: [0.5], + cellFields: [1], + resolution: 6, + center: [0, 0, 0], + direction: [0.0, 0.0, 1.0], + pointType: 'Float32Array', +}; + +// ---------------------------------------------------------------------------- + +export function extend(publicAPI, model, initialValues = {}) { + Object.assign(model, DEFAULT_VALUES, initialValues); + + // Build VTK API + macro.obj(publicAPI, model); + macro.setGet(publicAPI, model, [ + 'height', + 'resolution', + ]); + macro.setGetArray(publicAPI, model, [ + 'center', + 'direction', + ], 3); + macro.algo(publicAPI, model, 0, 1); + vtkConcentricCylinderSource(publicAPI, model); +} + +// ---------------------------------------------------------------------------- + +export const newInstance = macro.newInstance(extend, 'vtkConcentricCylinderSource'); + +// ---------------------------------------------------------------------------- + +export default { newInstance, extend }; diff --git a/Sources/Filters/Sources/index.js b/Sources/Filters/Sources/index.js index a1583447f97..96447a496ef 100644 --- a/Sources/Filters/Sources/index.js +++ b/Sources/Filters/Sources/index.js @@ -1,14 +1,16 @@ -import vtkConeSource from './ConeSource'; -import vtkCubeSource from './CubeSource'; -import vtkImageGridSource from './ImageGridSource'; -import vtkLineSource from './LineSource'; -import vtkPlaneSource from './PlaneSource'; -import vtkPointSource from './PointSource'; -import vtkRTAnalyticSource from './RTAnalyticSource'; -import vtkSLICSource from './SLICSource'; -import vtkSphereSource from './SphereSource'; +import vtkConcentricCylinderSource from './ConcentricCylinderSource'; +import vtkConeSource from './ConeSource'; +import vtkCubeSource from './CubeSource'; +import vtkImageGridSource from './ImageGridSource'; +import vtkLineSource from './LineSource'; +import vtkPlaneSource from './PlaneSource'; +import vtkPointSource from './PointSource'; +import vtkRTAnalyticSource from './RTAnalyticSource'; +import vtkSLICSource from './SLICSource'; +import vtkSphereSource from './SphereSource'; export default { + vtkConcentricCylinderSource, vtkConeSource, vtkCubeSource, vtkImageGridSource,