Skip to content

Commit 4e872bb

Browse files
feat(slicehelper): add helper for slicing imagemapper with clip planes
To deprecate vtkInteractorStyleMPRSlice I add a helper using two clip planes instead. The included example is similar to vtkInteractorStyleMPRSlice example. re #1872
1 parent 3adc48b commit 4e872bb

File tree

2 files changed

+146
-0
lines changed

2 files changed

+146
-0
lines changed

Examples/Volume/MPRSlice/index.js

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
import 'vtk.js/Sources/favicon';
2+
/* eslint-disable */
3+
4+
import 'vtk.js/Sources/Rendering/Profiles/Volume';
5+
6+
// Force DataAccessHelper to have access to various data source
7+
import 'vtk.js/Sources/IO/Core/DataAccessHelper/HtmlDataAccessHelper';
8+
import 'vtk.js/Sources/IO/Core/DataAccessHelper/HttpDataAccessHelper';
9+
import 'vtk.js/Sources/IO/Core/DataAccessHelper/JSZipDataAccessHelper';
10+
11+
import vtkHttpDataSetReader from 'vtk.js/Sources/IO/Core/HttpDataSetReader';
12+
import vtkFullScreenRenderWindow from 'vtk.js/Sources/Rendering/Misc/FullScreenRenderWindow';
13+
import vtkVolume from 'vtk.js/Sources/Rendering/Core/Volume';
14+
import vtkVolumeMapper from 'vtk.js/Sources/Rendering/Core/VolumeMapper';
15+
import vtkSliceHelper from 'vtk.js/Sources/Rendering/Core/SliceHelper';
16+
17+
// ----------------------------------------------------------------------------
18+
// Standard rendering code setup
19+
// ----------------------------------------------------------------------------
20+
21+
const fullScreenRenderer = vtkFullScreenRenderWindow.newInstance({
22+
background: [0, 0, 0],
23+
});
24+
const renderer = fullScreenRenderer.getRenderer();
25+
const renderWindow = fullScreenRenderer.getRenderWindow();
26+
27+
global.fullScreen = fullScreenRenderer;
28+
global.renderWindow = renderWindow;
29+
30+
// ----------------------------------------------------------------------------
31+
// Example code
32+
// ----------------------------------------------------------------------------
33+
34+
const reader = vtkHttpDataSetReader.newInstance({ fetchGzip: true });
35+
const actor = vtkVolume.newInstance();
36+
const mapper = vtkVolumeMapper.newInstance();
37+
mapper.setSampleDistance(1.1);
38+
actor.setMapper(mapper);
39+
mapper.setInputConnection(reader.getOutputPort());
40+
41+
const mprSlice = vtkSliceHelper.newInstance({ mapper });
42+
43+
reader.setUrl(`${__BASE_PATH__}/data/volume/headsq.vti`).then(() => {
44+
reader.loadData().then(() => {
45+
const data = reader.getOutputData();
46+
renderer.addVolume(actor);
47+
const [xMin, xMax, yMin, yMax, zMin, zMax] = data.getBounds();
48+
mprSlice.setOrigin([
49+
(xMin + xMax) / 2,
50+
(yMin + yMax) / 2,
51+
(zMin + zMax) / 2,
52+
]);
53+
54+
renderer.resetCamera();
55+
renderWindow.render();
56+
});
57+
});
58+
59+
// Set MPR slice to follow camera orientation
60+
const camera = renderer.getActiveCamera();
61+
camera.onModified(() => {
62+
const direction = camera.getDirectionOfProjection();
63+
mprSlice.setNormal(direction);
64+
});
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
import macro from 'vtk.js/Sources/macros';
2+
import vtkPlane from 'vtk.js/Sources/Common/DataModel/Plane';
3+
4+
function vtkSliceHelper(publicAPI, model) {
5+
model.classHierarchy.push('vtkSliceHelper');
6+
7+
const superClass = { ...publicAPI };
8+
9+
function update() {
10+
const [x, y, z] = model.normal;
11+
model.clipPlane1.setNormal([x, y, z]);
12+
model.clipPlane2.setNormal([-x, -y, -z]);
13+
14+
const origin1 = [
15+
model.origin[0] - (x * model.thickness) / 2,
16+
model.origin[1] - (y * model.thickness) / 2,
17+
model.origin[2] - (z * model.thickness) / 2,
18+
];
19+
model.clipPlane1.setOrigin(origin1);
20+
21+
const origin2 = [
22+
model.origin[0] + (x * model.thickness) / 2,
23+
model.origin[1] + (y * model.thickness) / 2,
24+
model.origin[2] + (z * model.thickness) / 2,
25+
];
26+
model.clipPlane2.setOrigin(origin2);
27+
}
28+
29+
publicAPI.addMapper = (mapper) => {
30+
mapper.addClippingPlane(model.clipPlane1);
31+
mapper.addClippingPlane(model.clipPlane2);
32+
};
33+
34+
publicAPI.setThickness = (thickness) => {
35+
superClass.setThickness(thickness);
36+
update();
37+
};
38+
publicAPI.setOrigin = (origin) => {
39+
superClass.setOrigin(origin);
40+
update();
41+
};
42+
publicAPI.setNormal = (normal) => {
43+
superClass.setNormal(normal);
44+
update();
45+
};
46+
}
47+
48+
// ----------------------------------------------------------------------------
49+
// Object factory
50+
// ----------------------------------------------------------------------------
51+
52+
const DEFAULT_VALUES = {
53+
thickness: 3,
54+
origin: [0, 0, 0],
55+
normal: [1, 0, 0],
56+
};
57+
58+
export function extend(publicAPI, model, initialValues = {}) {
59+
Object.assign(model, DEFAULT_VALUES, initialValues);
60+
61+
model.clipPlane1 = vtkPlane.newInstance();
62+
model.clipPlane2 = vtkPlane.newInstance();
63+
64+
// Build VTK API
65+
macro.obj(publicAPI, model);
66+
macro.setGet(publicAPI, model, ['thickness', 'origin', 'normal']);
67+
68+
// Object methods
69+
vtkSliceHelper(publicAPI, model);
70+
71+
if (initialValues.mapper) {
72+
publicAPI.addMapper(initialValues.mapper);
73+
}
74+
}
75+
76+
// ----------------------------------------------------------------------------
77+
78+
export const newInstance = macro.newInstance(extend, 'vtkSliceHelper');
79+
80+
// ----------------------------------------------------------------------------
81+
82+
export default { newInstance, extend };

0 commit comments

Comments
 (0)