-
-
Notifications
You must be signed in to change notification settings - Fork 383
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #432 from Kitware/concentric-cylinder-source
fix(ConcentricCylinderSource): Add new source for Concentric Cylinder
- Loading branch information
Showing
3 changed files
with
287 additions
and
9 deletions.
There are no files selected for viewing
49 changes: 49 additions & 0 deletions
49
Sources/Filters/Sources/ConcentricCylinderSource/example/index.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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; |
227 changes: 227 additions & 0 deletions
227
Sources/Filters/Sources/ConcentricCylinderSource/index.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 }; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters