Skip to content

Commit 5523179

Browse files
PaulHaxfloryst
authored andcommitted
feat(InteractorStyleManipulator): update center of rotation on pan
This enhances pan then rotate interaction. After panning, move the center of rotation the same vector that the camera position moved. Before, if the user panned the camera, zoomed in, then rotated, they would rotate around a point that was not in the center of the camera.
1 parent ff6160b commit 5523179

File tree

1 file changed

+69
-1
lines changed
  • Sources/Interaction/Style/InteractorStyleManipulator

1 file changed

+69
-1
lines changed

Sources/Interaction/Style/InteractorStyleManipulator/index.js

Lines changed: 69 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import macro from 'vtk.js/Sources/macros';
22
import { MouseButton } from 'vtk.js/Sources/Rendering/Core/RenderWindowInteractor/Constants';
33
import vtkInteractorStyle from 'vtk.js/Sources/Rendering/Core/InteractorStyle';
4+
import { mat4, vec3, vec4 } from 'gl-matrix';
45

56
const { vtkDebugMacro } = macro;
67
const { States } = vtkInteractorStyle;
@@ -134,6 +135,47 @@ function dollyByFactor(interactor, renderer, factor) {
134135
}
135136
}
136137

138+
function getCameraMatrix(renderer) {
139+
const cam = renderer.getActiveCamera();
140+
if (cam) {
141+
const M = mat4.create();
142+
mat4.copy(M, cam.getViewMatrix());
143+
return M;
144+
}
145+
return null;
146+
}
147+
148+
function computeNewCenterOfRotation(beforeM, renderer, oldCenterOfRotation) {
149+
const cam = renderer.getActiveCamera();
150+
if (!cam || !beforeM) {
151+
return oldCenterOfRotation;
152+
}
153+
154+
// The view matrix from vtk.js is row-major, but gl-matrix expects column-major.
155+
// We need to transpose them before use.
156+
const beforeMatrix = mat4.create();
157+
mat4.transpose(beforeMatrix, beforeM);
158+
159+
const afterMatrixRowMajor = cam.getViewMatrix();
160+
const afterMatrix = mat4.create();
161+
mat4.transpose(afterMatrix, afterMatrixRowMajor);
162+
163+
// Now we can proceed with column-major matrices.
164+
const invAfterM = mat4.create();
165+
mat4.invert(invAfterM, afterMatrix);
166+
167+
const deltaM = mat4.create();
168+
// deltaM = inv(afterM) * beforeM
169+
mat4.multiply(deltaM, invAfterM, beforeMatrix);
170+
171+
if (!mat4.equals(deltaM, mat4.identity(mat4.create()))) {
172+
const center = vec4.fromValues(...oldCenterOfRotation, 1);
173+
vec4.transformMat4(center, center, deltaM);
174+
return vec3.fromValues(center[0], center[1], center[2]);
175+
}
176+
return oldCenterOfRotation;
177+
}
178+
137179
// ----------------------------------------------------------------------------
138180
// Static API
139181
// ----------------------------------------------------------------------------
@@ -504,11 +546,25 @@ function vtkInteractorStyleManipulator(publicAPI, model) {
504546
publicAPI.handleMouseMove = (callData) => {
505547
model.cachedMousePosition = callData.position;
506548
if (model.currentManipulator && model.currentManipulator.onMouseMove) {
549+
const renderer = model.getRenderer(callData);
550+
const beforeM = getCameraMatrix(renderer);
551+
507552
model.currentManipulator.onMouseMove(
508553
model._interactor,
509-
model.getRenderer(callData),
554+
renderer,
510555
callData.position
511556
);
557+
558+
const newCenter = computeNewCenterOfRotation(
559+
beforeM,
560+
renderer,
561+
model.centerOfRotation
562+
);
563+
564+
if (!vec3.equals(model.centerOfRotation, newCenter)) {
565+
publicAPI.setCenterOfRotation(newCenter);
566+
}
567+
512568
publicAPI.invokeInteractionEvent(INTERACTION_EVENT);
513569
}
514570
};
@@ -672,6 +728,9 @@ function vtkInteractorStyleManipulator(publicAPI, model) {
672728

673729
//----------------------------------------------------------------------------
674730
publicAPI.handlePan = (callData) => {
731+
const renderer = model.getRenderer(callData);
732+
const beforeM = getCameraMatrix(renderer);
733+
675734
let count = model.gestureManipulators.length;
676735
let actionCount = 0;
677736
while (count--) {
@@ -686,6 +745,15 @@ function vtkInteractorStyleManipulator(publicAPI, model) {
686745
}
687746
}
688747
if (actionCount) {
748+
const newCenter = computeNewCenterOfRotation(
749+
beforeM,
750+
renderer,
751+
model.centerOfRotation
752+
);
753+
754+
if (!vec3.equals(model.centerOfRotation, newCenter)) {
755+
publicAPI.setCenterOfRotation(newCenter);
756+
}
689757
publicAPI.invokeInteractionEvent(INTERACTION_EVENT);
690758
}
691759
};

0 commit comments

Comments
 (0)