Skip to content

Commit 78d2d04

Browse files
committed
feat(InteractorStyleManipulator): revert update of center of rotation
Add vtkMouseCameraTrackballPanManipulatorAutoCenter closes #3309
1 parent 7ca74c6 commit 78d2d04

File tree

4 files changed

+276
-102
lines changed
  • Sources/Interaction
    • Manipulators/MouseCameraTrackballPanManipulatorAutoCenter
    • Style

4 files changed

+276
-102
lines changed
Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
import macro from 'vtk.js/Sources/macros';
2+
import vtkMouseCameraTrackballPanManipulator from 'vtk.js/Sources/Interaction/Manipulators/MouseCameraTrackballPanManipulator';
3+
import { mat4, vec3 } from 'gl-matrix';
4+
5+
// ----------------------------------------------------------------------------
6+
// Helper functions for center of rotation adjustment
7+
// ----------------------------------------------------------------------------
8+
9+
/**
10+
* Transforms a vector by the transformation delta between two matrices.
11+
*
12+
* @param {Object} tempObjects - Temporary matrices/vectors for computation
13+
* @param {mat4} beforeMatrix - Matrix before transformation
14+
* @param {mat4} afterMatrix - Matrix after transformation
15+
* @param {Array} vector - Vector to transform [x, y, z]
16+
* @returns {Array} Transformed vector [x, y, z]
17+
*/
18+
function transformVectorByTransformation(
19+
tempObjects,
20+
beforeMatrix,
21+
afterMatrix,
22+
vector
23+
) {
24+
const { matrixA, matrixB, newCenter } = tempObjects;
25+
26+
// The view matrix from vtk.js is row-major, but gl-matrix expects column-major.
27+
// We need to transpose them before use.
28+
mat4.transpose(matrixA, beforeMatrix);
29+
30+
mat4.transpose(matrixB, afterMatrix);
31+
mat4.invert(matrixB, matrixB);
32+
33+
// Compute delta transformation matrix
34+
mat4.multiply(matrixA, matrixB, matrixA);
35+
36+
vec3.transformMat4(newCenter, vector, matrixA);
37+
return newCenter;
38+
}
39+
40+
/**
41+
* Computes the new center of rotation based on camera movement.
42+
* When the camera moves (pan), the center of rotation should move
43+
* by the same transformation.
44+
*
45+
* @param {Object} tempObjects - Temporary matrices/vectors for computation
46+
* @param {Object} renderer - VTK renderer
47+
* @param {mat4} beforeCameraMatrix - Camera view matrix before movement
48+
* @param {Array} oldCenterOfRotation - Previous center of rotation [x, y, z]
49+
* @returns {Array} New center of rotation [x, y, z]
50+
*/
51+
function computeNewCenterOfRotation(
52+
tempObjects,
53+
renderer,
54+
beforeCameraMatrix,
55+
oldCenterOfRotation
56+
) {
57+
const cam = renderer.getActiveCamera();
58+
if (!cam || !beforeCameraMatrix) {
59+
return oldCenterOfRotation;
60+
}
61+
const afterMatrixRowMajor = cam.getViewMatrix();
62+
63+
return transformVectorByTransformation(
64+
tempObjects,
65+
beforeCameraMatrix,
66+
afterMatrixRowMajor,
67+
oldCenterOfRotation
68+
);
69+
}
70+
71+
function getCameraMatrix(renderer, tempMatrix) {
72+
const cam = renderer.getActiveCamera();
73+
if (cam) {
74+
mat4.copy(tempMatrix, cam.getViewMatrix());
75+
return tempMatrix;
76+
}
77+
return null;
78+
}
79+
80+
function vtkMouseCameraTrackballPanManipulatorAutoCenter(publicAPI, model) {
81+
model.classHierarchy.push('vtkMouseCameraTrackballPanManipulatorAutoCenter');
82+
83+
const tempCameraMatrix = mat4.create();
84+
const tempComputeObjects = {
85+
matrixA: mat4.create(),
86+
matrixB: mat4.create(),
87+
newCenter: vec3.create(),
88+
};
89+
90+
const superOnMouseMove = publicAPI.onMouseMove;
91+
92+
publicAPI.onMouseMove = (interactor, renderer, position) => {
93+
if (!position) {
94+
return;
95+
}
96+
const beforeCameraMatrix = getCameraMatrix(renderer, tempCameraMatrix);
97+
98+
superOnMouseMove(interactor, renderer, position);
99+
100+
if (beforeCameraMatrix && model.center) {
101+
const newCenter = computeNewCenterOfRotation(
102+
tempComputeObjects,
103+
renderer,
104+
beforeCameraMatrix,
105+
model.center
106+
);
107+
publicAPI.setCenter(newCenter);
108+
109+
const style = interactor.getInteractorStyle();
110+
if (style && style.setCenterOfRotation) {
111+
style.setCenterOfRotation(newCenter);
112+
}
113+
}
114+
};
115+
}
116+
117+
// ----------------------------------------------------------------------------
118+
// Object factory
119+
// ----------------------------------------------------------------------------
120+
121+
const DEFAULT_VALUES = {};
122+
123+
// ----------------------------------------------------------------------------
124+
125+
export function extend(publicAPI, model, initialValues = {}) {
126+
Object.assign(model, DEFAULT_VALUES, initialValues);
127+
128+
// Inheritance
129+
vtkMouseCameraTrackballPanManipulator.extend(publicAPI, model, initialValues);
130+
131+
// Object specific methods
132+
vtkMouseCameraTrackballPanManipulatorAutoCenter(publicAPI, model);
133+
}
134+
135+
// ----------------------------------------------------------------------------
136+
137+
export const newInstance = macro.newInstance(
138+
extend,
139+
'vtkMouseCameraTrackballPanManipulatorAutoCenter'
140+
);
141+
142+
// ----------------------------------------------------------------------------
143+
144+
export default { newInstance, extend };

Sources/Interaction/Style/InteractorStyleManipulator/api.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ sent to it. Also, changing the CenterOfRotation during interaction i.e. after a
2222
button press but before a button up has no effect until the next button press. The
2323
default value is [0, 0, 0].
2424

25+
For automatic center adjustment during panning operations, use `MouseCameraTrackballPanManipulatorAutoCenter` instead of the standard `MouseCameraTrackballPanManipulator`.
26+
2527
### rotationFactor
2628

2729
Set/Get the rotation factor. Propagates the rotation factor to the manipulators.

Sources/Interaction/Style/InteractorStyleManipulator/index.js

Lines changed: 2 additions & 102 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
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 } from 'gl-matrix';
54

65
const { vtkDebugMacro } = macro;
76
const { States } = vtkInteractorStyle;
@@ -135,77 +134,6 @@ function dollyByFactor(interactor, renderer, factor) {
135134
}
136135
}
137136

138-
function getCameraMatrix(renderer, tempMatrix) {
139-
const cam = renderer.getActiveCamera();
140-
if (cam) {
141-
mat4.copy(tempMatrix, cam.getViewMatrix());
142-
return tempMatrix;
143-
}
144-
return null;
145-
}
146-
147-
/**
148-
* Transforms a vector by the transformation delta between two matrices.
149-
*
150-
* @param {Object} tempObjects - Temporary matrices/vectors for computation
151-
* @param {mat4} beforeMatrix - Matrix before transformation
152-
* @param {mat4} afterMatrix - Matrix after transformation
153-
* @param {Array} vector - Vector to transform [x, y, z]
154-
* @returns {Array} Transformed vector [x, y, z]
155-
*/
156-
function transformVectorByTransformation(
157-
tempObjects,
158-
beforeMatrix,
159-
afterMatrix,
160-
vector
161-
) {
162-
const { matrixA, matrixB, newCenter } = tempObjects;
163-
164-
// The view matrix from vtk.js is row-major, but gl-matrix expects column-major.
165-
// We need to transpose them before use.
166-
mat4.transpose(matrixA, beforeMatrix);
167-
168-
mat4.transpose(matrixB, afterMatrix);
169-
mat4.invert(matrixB, matrixB);
170-
171-
// Compute delta transformation matrix
172-
mat4.multiply(matrixA, matrixB, matrixA);
173-
174-
vec3.transformMat4(newCenter, vector, matrixA);
175-
return newCenter;
176-
}
177-
178-
/**
179-
* Computes the new center of rotation based on camera movement.
180-
* When the camera moves (pan), the center of rotation should move
181-
* by the same transformation to maintain consistent rotation behavior.
182-
*
183-
* @param {Object} tempObjects - Temporary matrices/vectors for computation
184-
* @param {Object} renderer - VTK renderer
185-
* @param {mat4} beforeCameraMatrix - Camera view matrix before movement
186-
* @param {Array} oldCenterOfRotation - Previous center of rotation [x, y, z]
187-
* @returns {Array} New center of rotation [x, y, z]
188-
*/
189-
function computeNewCenterOfRotation(
190-
tempObjects,
191-
renderer,
192-
beforeCameraMatrix,
193-
oldCenterOfRotation
194-
) {
195-
const cam = renderer.getActiveCamera();
196-
if (!cam || !beforeCameraMatrix) {
197-
return oldCenterOfRotation;
198-
}
199-
const afterMatrixRowMajor = cam.getViewMatrix();
200-
201-
return transformVectorByTransformation(
202-
tempObjects,
203-
beforeCameraMatrix,
204-
afterMatrixRowMajor,
205-
oldCenterOfRotation
206-
);
207-
}
208-
209137
// ----------------------------------------------------------------------------
210138
// Static API
211139
// ----------------------------------------------------------------------------
@@ -224,14 +152,6 @@ function vtkInteractorStyleManipulator(publicAPI, model) {
224152
// Set our className
225153
model.classHierarchy.push('vtkInteractorStyleManipulator');
226154

227-
// Initialize temporary objects to reduce garbage collection
228-
const tempCameraMatrix = mat4.create();
229-
const tempComputeObjects = {
230-
matrixA: mat4.create(),
231-
matrixB: mat4.create(),
232-
newCenter: vec3.create(),
233-
};
234-
235155
model.currentVRManipulators = new Map();
236156
model.mouseManipulators = [];
237157
model.keyboardManipulators = [];
@@ -584,23 +504,11 @@ function vtkInteractorStyleManipulator(publicAPI, model) {
584504
publicAPI.handleMouseMove = (callData) => {
585505
model.cachedMousePosition = callData.position;
586506
if (model.currentManipulator && model.currentManipulator.onMouseMove) {
587-
const renderer = model.getRenderer(callData);
588-
const beforeCameraMatrix = getCameraMatrix(renderer, tempCameraMatrix);
589-
590507
model.currentManipulator.onMouseMove(
591508
model._interactor,
592-
renderer,
509+
model.getRenderer(callData),
593510
callData.position
594511
);
595-
596-
const newCenter = computeNewCenterOfRotation(
597-
tempComputeObjects,
598-
renderer,
599-
beforeCameraMatrix,
600-
model.centerOfRotation
601-
);
602-
publicAPI.setCenterOfRotation(newCenter);
603-
604512
publicAPI.invokeInteractionEvent(INTERACTION_EVENT);
605513
}
606514
};
@@ -765,7 +673,6 @@ function vtkInteractorStyleManipulator(publicAPI, model) {
765673
//----------------------------------------------------------------------------
766674
publicAPI.handlePan = (callData) => {
767675
const renderer = model.getRenderer(callData);
768-
const beforeCameraMatrix = getCameraMatrix(renderer, tempCameraMatrix);
769676

770677
let count = model.gestureManipulators.length;
771678
let actionCount = 0;
@@ -776,15 +683,8 @@ function vtkInteractorStyleManipulator(publicAPI, model) {
776683
actionCount++;
777684
}
778685
}
779-
if (actionCount) {
780-
const newCenter = computeNewCenterOfRotation(
781-
tempComputeObjects,
782-
renderer,
783-
beforeCameraMatrix,
784-
model.centerOfRotation
785-
);
786-
publicAPI.setCenterOfRotation(newCenter);
787686

687+
if (actionCount) {
788688
publicAPI.invokeInteractionEvent(INTERACTION_EVENT);
789689
}
790690
};

0 commit comments

Comments
 (0)