ACloudViewer  3.9.4
A Modern Library for 3D Data Processing
MatrixInteractorLogic.cpp
Go to the documentation of this file.
1 // ----------------------------------------------------------------------------
2 // - CloudViewer: www.cloudViewer.org -
3 // ----------------------------------------------------------------------------
4 // Copyright (c) 2018-2024 www.cloudViewer.org
5 // SPDX-License-Identifier: MIT
6 // ----------------------------------------------------------------------------
7 
9 
10 namespace cloudViewer {
11 namespace visualization {
12 namespace rendering {
13 
15 
19 }
20 
22 
24 
26  return model_bounds_;
27 }
28 
30  model_size_ = (bounds.GetMaxBound() - bounds.GetMinBound()).norm();
31  model_bounds_ = bounds;
32 }
33 
35  return center_of_rotation_;
36 }
37 
39  const Camera::Transform& matrix,
40  const Eigen::Vector3f& center_of_rotation) {
41  matrix_ = matrix;
42  center_of_rotation_ = center_of_rotation;
43 
44  matrix_at_mouse_down_ = matrix;
45  center_of_rotation_at_mouse_down_ = center_of_rotation;
46 }
47 
49  matrix_ = matrix;
50 }
51 
53  return matrix_;
54 }
55 
56 void MatrixInteractorLogic::Rotate(int dx, int dy) {
57  auto matrix = matrix_at_mouse_down_; // copy
58  Eigen::AngleAxisf rot_matrix(0, Eigen::Vector3f(1, 0, 0));
59 
60  // We want to rotate as if we were rotating an imaginary trackball
61  // centered at the point of rotation. To do this we need an axis
62  // of rotation and an angle about the axis. To find the axis, we
63  // imagine that the viewing plane has been translated into the screen
64  // so that it intersects the center of rotation. The axis we want
65  // to rotate around is perpendicular to the vector defined by (dx, dy)
66  // (assuming +x is right and +y is up). (Imagine the situation if the
67  // mouse movement is (100, 0) or (0, 100).) Now it is easy to find
68  // the perpendicular in 2D. Conveniently, (axis.x, axis.y, 0) is the
69  // correct axis in camera-local coordinates. We can multiply by the
70  // camera's rotation matrix to get the correct world vector.
71  dy = -dy; // up is negative, but the calculations are easiest to
72  // imagine up is positive.
73  Eigen::Vector3f axis(float(-dy), float(dx), 0); // rotate by 90 deg in 2D
74  axis = axis.normalized();
75  float theta = CalcRotateRadians(dx, dy);
76 
77  axis = matrix.rotation() * axis; // convert axis to world coords
78  rot_matrix = rot_matrix * Eigen::AngleAxisf(-theta, axis);
79 
80  auto pos = matrix * Eigen::Vector3f(0, 0, 0);
81  Eigen::Vector3f to_cor = center_of_rotation_ - pos;
82  auto dist = to_cor.norm();
83  // If the center of rotation is behind the camera we need to flip
84  // the sign of 'dist'. We can just dotprod with the forward vector
85  // of the camera. Forward is [0, 0, -1] for an identity matrix,
86  // so forward is simply rotation * [0, 0, -1].
87  Eigen::Vector3f forward =
88  matrix.rotation() * Eigen::Vector3f{0.0f, 0.0f, -1.0f};
89  if (to_cor.dot(forward) < 0) {
90  dist = -dist;
91  }
93  m.fromPositionOrientationScale(center_of_rotation_,
94  rot_matrix * matrix.rotation(),
95  Eigen::Vector3f(1, 1, 1));
96  m.translate(Eigen::Vector3f(0, 0, dist));
97 
98  matrix_ = m;
99 }
100 
102  int dy,
103  const Eigen::Vector3f& x_axis,
104  const Eigen::Vector3f& y_axis) {
105  auto matrix = matrix_at_mouse_down_; // copy
106 
107  dy = -dy; // up is negative, but the calculations are easiest to
108  // imagine up is positive.
109  Eigen::Vector3f axis = dx * x_axis + dy * y_axis;
110  axis = axis.normalized();
111  float theta = CalcRotateRadians(dx, dy);
112 
113  axis = matrix.rotation() * axis; // convert axis to world coords
114  auto rot_matrix =
115  Camera::Transform::Identity() * Eigen::AngleAxisf(-theta, axis);
116 
117  auto pos = matrix * Eigen::Vector3f(0, 0, 0);
118  auto dist = (center_of_rotation_ - pos).norm();
120  m.fromPositionOrientationScale(center_of_rotation_,
121  rot_matrix * matrix.rotation(),
122  Eigen::Vector3f(1, 1, 1));
123  m.translate(Eigen::Vector3f(0, 0, dist));
124 
125  matrix_ = m;
126 }
127 
129  Eigen::Vector3f moved(float(dx), float(dy), 0);
130  return 0.5f * float(M_PI) * moved.norm() / (0.5f * float(view_height_));
131 }
132 
133 void MatrixInteractorLogic::RotateZ(int dx, int dy) {
134  // RotateZ rotates around the axis normal to the screen. Since we
135  // will be rotating using camera coordinates, we want to rotate
136  // about (0, 0, 1).
137  Eigen::Vector3f axis(0, 0, 1);
138  auto rad = CalcRotateZRadians(dx, dy);
139  auto matrix = matrix_at_mouse_down_; // copy
140  matrix.rotate(Eigen::AngleAxisf(rad, axis));
141  matrix_ = matrix;
142 }
143 
145  int dy,
146  const Eigen::Vector3f& forward) {
147  auto rad = CalcRotateZRadians(dx, dy);
148  Eigen::AngleAxisf rot_matrix(rad, forward);
149 
150  Camera::Transform matrix = matrix_at_mouse_down_; // copy
151  matrix.translate(center_of_rotation_);
152  matrix *= rot_matrix;
153  matrix.translate(-center_of_rotation_);
154  matrix_ = matrix;
155 }
156 
158  // Moving half the height should rotate 360 deg (= 2 * PI).
159  // This makes it easy to rotate enough without rotating too much.
160  return float(4.0 * M_PI * dy / view_height_);
161 }
162 
163 void MatrixInteractorLogic::Dolly(float dy, DragType drag_type) {
164  if (drag_type == DragType::MOUSE) {
165  float dist = CalcDollyDist(dy, drag_type, matrix_at_mouse_down_);
166  Dolly(dist, matrix_at_mouse_down_); // copies the matrix
167  } else {
168  float dist = CalcDollyDist(dy, drag_type, matrix_);
169  Dolly(dist, matrix_);
170  }
171 }
172 
173 // Note: we pass `matrix` by value because we want to copy it,
174 // as translate() will be modifying it.
176  // Dolly is just moving the camera forward. Filament uses right as +x,
177  // up as +y, and forward as -z (standard OpenGL coordinates). So to
178  // move forward all we need to do is translate the camera matrix by
179  // dist * (0, 0, -1). Note that translating by camera_->GetForwardVector
180  // would be incorrect, since GetForwardVector() returns the forward
181  // vector in world space, but the translation happens in camera space.)
182  // Since we want trackpad down (negative) to go forward ("pulling" the
183  // model toward the viewer) we need to negate dy.
184  auto forward = Eigen::Vector3f(0, 0, -z_dist); // zDist * (0, 0, -1)
185  matrix.translate(forward);
186  matrix_ = matrix;
187 }
188 
190  DragType drag_type,
191  const Camera::Transform& matrix) {
192  float length =
193  (center_of_rotation_ - matrix * Eigen::Vector3f(0.0f, 0.0f, 0.0f))
194  .norm();
195  length = std::max(float(0.02 * model_size_), length);
196  float dist = 0.0f; // initialize to make GCC happy
197  switch (drag_type) {
198  case DragType::MOUSE:
199  // Zoom out is "push away" or up, is a negative value for
200  // mousing
201  dist = float(dy) * 0.0025f * float(length);
202  break;
204  // Zoom out is "push away" or up, is a positive value for
205  // two-finger scrolling, so we need to invert dy.
206  dist = float(-dy) * 0.01f * float(length);
207  break;
208  case DragType::WHEEL: // actual mouse wheel, same as two-fingers
209  dist = float(-dy) * 0.05f * float(length);
210  break;
211  }
212  return dist;
213 }
214 
215 } // namespace rendering
216 } // namespace visualization
217 } // namespace cloudViewer
constexpr double M_PI
Pi.
Definition: CVConst.h:19
int width
int height
Bounding box structure.
Definition: ecvBBox.h:25
virtual Eigen::Vector3d GetMaxBound() const override
Returns max bounds for geometry coordinates.
Definition: ecvBBox.h:84
virtual Eigen::Vector3d GetMinBound() const override
Returns min bounds for geometry coordinates.
Definition: ecvBBox.h:81
Eigen::Transform< float, 3, Eigen::Affine > Transform
Definition: Camera.h:29
void SetMouseDownInfo(const Camera::Transform &matrix, const Eigen::Vector3f &center_of_rotation)
virtual void RotateZ(int dx, int dy)
Rotates about the forward axis of the matrix.
float CalcDollyDist(float dy, DragType drag_type, const Camera::Transform &matrix)
virtual void RotateZWorld(int dx, int dy, const Eigen::Vector3f &forward)
virtual void RotateWorld(int dx, int dy, const Eigen::Vector3f &x_axis, const Eigen::Vector3f &y_axis)
__host__ __device__ float length(float2 v)
Definition: cutil_math.h:1162
int max(int a, int b)
Definition: cutil_math.h:48
static double dist(double x1, double y1, double x2, double y2)
Definition: lsd.c:207
Generic file read and write utility for python interface.