Skip to content

Commit 0f645ff

Browse files
authored
Merge pull request #505 from agirault/manipulators-improvement
SliceManipulator and ImageMapper improvements
2 parents 225f8e5 + b23eb5f commit 0f645ff

File tree

5 files changed

+142
-4
lines changed

5 files changed

+142
-4
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
import macro from 'vtk.js/Sources/macro';
2+
import vtkCameraManipulator from 'vtk.js/Sources/Interaction/Manipulators/CameraManipulator';
3+
import vtkMath from 'vtk.js/Sources/Common/Core/Math';
4+
5+
// ----------------------------------------------------------------------------
6+
// vtkSliceManipulator methods
7+
// ----------------------------------------------------------------------------
8+
9+
function vtkSliceManipulator(publicAPI, model) {
10+
// Set our className
11+
model.classHierarchy.push('vtkSliceManipulator');
12+
13+
publicAPI.onAnimation = (interactor, renderer) => {
14+
const lastPtr = interactor.getPointerIndex();
15+
const pos = interactor.getAnimationEventPosition(lastPtr);
16+
const lastPos = interactor.getLastAnimationEventPosition(lastPtr);
17+
18+
if (!pos || !lastPos || !renderer) {
19+
return;
20+
}
21+
22+
const dy = pos.y - lastPos.y;
23+
24+
const camera = renderer.getActiveCamera();
25+
const range = camera.getClippingRange();
26+
let distance = camera.getDistance();
27+
28+
// scale the interaction by the height of the viewport
29+
let viewportHeight = 0.0;
30+
if (camera.getParallelProjection()) {
31+
viewportHeight = camera.getParallelScale();
32+
} else {
33+
const angle = vtkMath.radiansFromDegrees(camera.getViewAngle());
34+
viewportHeight = 2.0 * distance * Math.tan(0.5 * angle);
35+
}
36+
37+
const size = interactor.getView().getViewportSize(renderer);
38+
const delta = dy * viewportHeight / size[1];
39+
distance += delta;
40+
41+
// clamp the distance to the clipping range
42+
if (distance < range[0]) {
43+
distance = range[0] + viewportHeight * 1e-3;
44+
}
45+
if (distance > range[1]) {
46+
distance = range[1] - viewportHeight * 1e-3;
47+
}
48+
camera.setDistance(distance);
49+
};
50+
51+
publicAPI.onPinch = (interactor) => {
52+
const interactorStyle = interactor.getInteractorStyle();
53+
let renderer = interactorStyle.getCurrentRenderer();
54+
55+
if (!renderer) {
56+
const pos = interactor.getAnimationEventPosition(
57+
interactor.getPointerIndex()
58+
);
59+
renderer = interactor.findPokedRenderer(pos);
60+
if (!renderer) {
61+
return;
62+
}
63+
}
64+
65+
let delta = interactor.getScale() / interactor.getLastScale();
66+
delta = 1.0 - delta;
67+
delta *= 25; // TODO: expose factor?
68+
69+
const camera = renderer.getActiveCamera();
70+
const range = camera.getClippingRange();
71+
let distance = camera.getDistance();
72+
distance += delta;
73+
74+
// clamp the distance to the clipping range
75+
if (distance < range[0]) {
76+
distance = range[0];
77+
}
78+
if (distance > range[1]) {
79+
distance = range[1];
80+
}
81+
camera.setDistance(distance);
82+
};
83+
}
84+
85+
// ----------------------------------------------------------------------------
86+
// Object factory
87+
// ----------------------------------------------------------------------------
88+
89+
const DEFAULT_VALUES = {};
90+
91+
// ----------------------------------------------------------------------------
92+
93+
export function extend(publicAPI, model, initialValues = {}) {
94+
Object.assign(model, DEFAULT_VALUES, initialValues);
95+
96+
// Inheritance
97+
vtkCameraManipulator.extend(publicAPI, model, initialValues);
98+
99+
// Object specific methods
100+
vtkSliceManipulator(publicAPI, model);
101+
}
102+
103+
// ----------------------------------------------------------------------------
104+
105+
export const newInstance = macro.newInstance(extend, 'vtkSliceManipulator');
106+
107+
// ----------------------------------------------------------------------------
108+
109+
export default Object.assign({ newInstance, extend });

Sources/Interaction/Manipulators/index.js

+2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import vtkCameraManipulator from './CameraManipulator';
2+
import vtkSliceManipulator from './SliceManipulator';
23
import vtkTrackballMultiRotate from './TrackballMultiRotate';
34
import vtkTrackballPan from './TrackballPan';
45
import vtkTrackballRoll from './TrackballRoll';
@@ -8,6 +9,7 @@ import vtkTrackballZoomToMouse from './TrackballZoomToMouse';
89

910
export default {
1011
vtkCameraManipulator,
12+
vtkSliceManipulator,
1113
vtkTrackballMultiRotate,
1214
vtkTrackballPan,
1315
vtkTrackballRoll,

Sources/Rendering/Core/ImageMapper/example/index.js

+1
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ const iStyle = vtkInteractorStyleImage.newInstance();
3737
iStyle.setInteractionMode('IMAGE_SLICING');
3838
renderWindow.getInteractor().setInteractorStyle(iStyle);
3939

40+
renderer.getActiveCamera().setParallelProjection(true);
4041
renderer.addActor(actor);
4142
renderer.resetCamera();
4243
renderWindow.render();

Sources/Rendering/Core/ImageMapper/index.js

+28-2
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,38 @@ function vtkImageMapper(publicAPI, model) {
1616
// Set our className
1717
model.classHierarchy.push('vtkImageMapper');
1818

19-
publicAPI.setZSliceFromCamera = (cam) => {
19+
publicAPI.setSliceFromCamera = (cam) => {
2020
const image = publicAPI.getInputData();
2121
const fp = cam.getFocalPoint();
2222
const idx = [];
2323
image.worldToIndex(fp, idx);
24-
publicAPI.setZSlice(Math.floor(idx[2] + 0.5));
24+
25+
let id = 0;
26+
const bds = publicAPI.getBounds();
27+
switch (publicAPI.getCurrentSlicingMode()) {
28+
case SlicingMode.X:
29+
id = idx[0];
30+
id = Math.floor(id + 0.5);
31+
id = Math.min(id, bds[1]);
32+
id = Math.max(id, bds[0]);
33+
publicAPI.setXSlice(id);
34+
break;
35+
case SlicingMode.Y:
36+
id = idx[1];
37+
id = Math.floor(id + 0.5);
38+
id = Math.min(id, bds[3]);
39+
id = Math.max(id, bds[2]);
40+
publicAPI.setYSlice(id);
41+
break;
42+
case SlicingMode.Z:
43+
id = idx[2];
44+
id = Math.floor(id + 0.5);
45+
id = Math.min(id, bds[5]);
46+
id = Math.max(id, bds[4]);
47+
publicAPI.setZSlice(id);
48+
break;
49+
default:
50+
}
2551
};
2652

2753
publicAPI.setZSliceIndex = (id) => {

Sources/Rendering/OpenGL/ImageMapper/index.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -46,9 +46,9 @@ function vtkOpenGLImageMapper(publicAPI, model) {
4646
model.openGLCamera = model.openGLRenderer.getViewNodeFor(
4747
ren.getActiveCamera()
4848
);
49-
// is zslice set by the camera
49+
// is slice set by the camera
5050
if (model.renderable.getSliceAtFocalPoint()) {
51-
model.renderable.setZSliceFromCamera(ren.getActiveCamera());
51+
model.renderable.setSliceFromCamera(ren.getActiveCamera());
5252
}
5353
}
5454
};

0 commit comments

Comments
 (0)