ACloudViewer  3.9.4
A Modern Library for 3D Data Processing
ViewControl.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 // Avoid warning caused by redefinition of APIENTRY macro
11 // defined also in glfw3.h
12 #ifdef _WIN32
13 #include <windows.h>
14 #endif
15 
16 #include <GLFW/glfw3.h>
17 #include <Logging.h>
18 
19 #include <Eigen/Dense>
20 #include <cmath> // jspark
21 
22 namespace cloudViewer {
23 namespace visualization {
24 using namespace cloudViewer;
25 
26 const double ViewControl::FIELD_OF_VIEW_MAX = 90.0;
27 const double ViewControl::FIELD_OF_VIEW_MIN = 5.0;
28 const double ViewControl::FIELD_OF_VIEW_DEFAULT = 60.0;
29 const double ViewControl::FIELD_OF_VIEW_STEP = 5.0;
30 
31 const double ViewControl::ZOOM_DEFAULT = 0.7;
32 const double ViewControl::ZOOM_MIN = 0.02;
33 const double ViewControl::ZOOM_MAX = 2.0;
34 const double ViewControl::ZOOM_STEP = 0.02;
35 
36 const double ViewControl::ROTATION_RADIAN_PER_PIXEL = 0.003;
37 
39  const Eigen::Matrix4d
40  &model_matrix /* = Eigen::Matrix4d::Identity()*/) {
41  if (window_height_ <= 0 || window_width_ <= 0) {
43  "[ViewControl] SetViewPoint() failed because window height and "
44  "width are not set.");
45  return;
46  }
47  glViewport(0, 0, window_width_, window_height_);
49  // Perspective projection
50  z_near_ =
54  distance_ -
55  3.0 * bounding_box_.GetMaxExtent());
61  } else {
62  // Orthogonal projection
63  // We use some black magic to support distance_ in orthogonal view
73  }
75  model_matrix_ = model_matrix.cast<GLfloat>();
77 
78  // uncomment to use the deprecated functions of legacy OpenGL
79  // glMatrixMode(GL_PROJECTION);
80  // glLoadIdentity();
81  // glMatrixMode(GL_MODELVIEW);
82  // glLoadIdentity();
83  // glMultMatrixf(MVP_matrix_.data());
84 }
85 
88  status.zoom_ = zoom_;
89  status.lookat_ = lookat_;
90  status.up_ = up_;
91  status.front_ = front_;
94  return true;
95 }
96 
99  zoom_ = status.zoom_;
100  lookat_ = status.lookat_;
101  up_ = status.up_;
102  front_ = status.front_;
107  return true;
108 }
109 
110 void ViewControl::SetLookat(const Eigen::Vector3d &lookat) {
111  lookat_ = lookat;
113 }
114 
115 void ViewControl::SetUp(const Eigen::Vector3d &up) {
116  up_ = up;
118 }
119 
120 void ViewControl::SetFront(const Eigen::Vector3d &front) {
121  front_ = front;
123 }
124 
125 void ViewControl::SetZoom(const double zoom) {
126  zoom_ = zoom;
128 }
129 
131  camera::PinholeCameraParameters &parameters) {
132  if (window_height_ <= 0 || window_width_ <= 0) {
134  "[ViewControl] ConvertToPinholeCameraParameters() failed "
135  "because window height and width are not set.");
136  return false;
137  }
138  if (GetProjectionType() == ProjectionType::Orthogonal) {
140  "[ViewControl] ConvertToPinholeCameraParameters() failed "
141  "because orthogonal view cannot be translated to a pinhole "
142  "camera.");
143  return false;
144  }
146  auto intrinsic = camera::PinholeCameraIntrinsic();
147  intrinsic.width_ = window_width_;
148  intrinsic.height_ = window_height_;
149  intrinsic.intrinsic_matrix_.setIdentity();
150  double fov_rad = field_of_view_ / 180.0 * M_PI;
151  double tan_half_fov = std::tan(fov_rad / 2.0);
152  intrinsic.intrinsic_matrix_(0, 0) = intrinsic.intrinsic_matrix_(1, 1) =
153  (double)window_height_ / tan_half_fov / 2.0;
154  intrinsic.intrinsic_matrix_(0, 2) = (double)window_width_ / 2.0 - 0.5;
155  intrinsic.intrinsic_matrix_(1, 2) = (double)window_height_ / 2.0 - 0.5;
156  parameters.intrinsic_ = intrinsic;
157  Eigen::Matrix4d extrinsic;
158  extrinsic.setZero();
159  Eigen::Vector3d front_dir = front_.normalized();
160  Eigen::Vector3d up_dir = up_.normalized();
161  Eigen::Vector3d right_dir = right_.normalized();
162  extrinsic.block<1, 3>(0, 0) = right_dir.transpose();
163  extrinsic.block<1, 3>(1, 0) = -up_dir.transpose();
164  extrinsic.block<1, 3>(2, 0) = -front_dir.transpose();
165  extrinsic(0, 3) = -right_dir.dot(eye_);
166  extrinsic(1, 3) = up_dir.dot(eye_);
167  extrinsic(2, 3) = front_dir.dot(eye_);
168  extrinsic(3, 3) = 1.0;
169  parameters.extrinsic_ = extrinsic;
170  return true;
171 }
172 
174  const camera::PinholeCameraParameters &parameters,
175  bool allow_arbitrary) {
176  auto intrinsic = parameters.intrinsic_;
177  auto extrinsic = parameters.extrinsic_;
178 
179  constexpr double threshold = 1.e-6;
180  if (!allow_arbitrary &&
181  (window_height_ <= 0 || window_width_ <= 0 ||
182  window_height_ != intrinsic.height_ ||
183  window_width_ != intrinsic.width_ ||
184  std::abs(intrinsic.intrinsic_matrix_(0, 2) -
185  ((double)window_width_ / 2.0 - 0.5)) > threshold ||
186  std::abs(intrinsic.intrinsic_matrix_(1, 2) -
187  ((double)window_height_ / 2.0 - 0.5)) > threshold)) {
189  "[ViewControl] ConvertFromPinholeCameraParameters() failed "
190  "because window height and width do not match.");
191  return false;
192  }
193  double tan_half_fov =
194  (double)window_height_ / (intrinsic.intrinsic_matrix_(1, 1) * 2.0);
195  double fov_rad = std::atan(tan_half_fov) * 2.0;
196  double old_fov = field_of_view_;
197  field_of_view_ = fov_rad * 180.0 / M_PI;
198  if (!allow_arbitrary) {
201  if (GetProjectionType() == ProjectionType::Orthogonal) {
202  field_of_view_ = old_fov;
204  "[ViewControl] ConvertFromPinholeCameraParameters() failed "
205  "because field of view is impossible.");
206  return false;
207  }
208  }
209  right_ = extrinsic.block<1, 3>(0, 0).transpose();
210  up_ = -extrinsic.block<1, 3>(1, 0).transpose();
211  front_ = -extrinsic.block<1, 3>(2, 0).transpose();
212  eye_ = extrinsic.block<3, 3>(0, 0).inverse() *
213  (extrinsic.block<3, 1>(0, 3) * -1.0);
214 
215  auto bb_center = bounding_box_.GetCenter();
216  double ideal_distance = std::abs((eye_ - bb_center).dot(front_));
217  double ideal_zoom = ideal_distance *
218  std::tan(field_of_view_ * 0.5 / 180.0 * M_PI) /
220  zoom_ = ideal_zoom;
221  if (!allow_arbitrary) {
222  zoom_ = std::max(std::min(ideal_zoom, ZOOM_MAX), ZOOM_MIN);
223  }
225  distance_ = view_ratio_ / std::tan(field_of_view_ * 0.5 / 180.0 * M_PI);
227  return true;
228 }
229 
232  return ProjectionType::Orthogonal;
233  } else {
235  }
236 }
237 
242  up_ = Eigen::Vector3d(0.0, 1.0, 0.0);
243  front_ = Eigen::Vector3d(0.0, 0.0, 1.0);
245 }
246 
248  front_ = front_.normalized();
249  right_ = up_.cross(front_).normalized();
252  distance_ = view_ratio_ / std::tan(field_of_view_ * 0.5 / 180.0 * M_PI);
254  } else {
256  distance_ =
257  view_ratio_ / std::tan(FIELD_OF_VIEW_STEP * 0.5 / 180.0 * M_PI);
259  }
260 
262 }
263 
270 }
271 
275  aspect_ = (double)window_width_ / (double)window_height_;
277 }
278 
279 void ViewControl::Scale(double scale) {
282 }
283 
284 void ViewControl::Rotate(double x,
285  double y,
286  double xo /* = 0.0*/,
287  double yo /* = 0.0*/) {
288  // some black magic to do rotation
289  double alpha = x * ROTATION_RADIAN_PER_PIXEL;
290  double beta = y * ROTATION_RADIAN_PER_PIXEL;
291  front_ = (front_ * std::cos(alpha) - right_ * std::sin(alpha)).normalized();
292  right_ = up_.cross(front_).normalized();
293  front_ = (front_ * std::cos(beta) + up_ * std::sin(beta)).normalized();
294  up_ = front_.cross(right_).normalized();
296 }
297 
299  double y,
300  double xo /* = 0.0*/,
301  double yo /* = 0.0*/) {
302  Eigen::Vector3d shift = right_ * (-x) / window_height_ * view_ratio_ * 2.0 +
303  up_ * y / window_height_ * view_ratio_ * 2.0;
304  eye_ += shift;
305  lookat_ += shift;
307 }
308 
310  double right,
311  double up) {
312  lookat_ += (-forward) * front_.normalized() + right * right_.normalized() +
313  up * up_.normalized();
315 }
316 
318  double y,
319  double xo /* = 0.0*/,
320  double yo /* = 0.0*/) {
321  const double degrees_per_unit = 100 / distance_;
322  const double x_shift = (-x) / window_height_ * view_ratio_ * 2.0;
323  const double y_shift = y / window_height_ * view_ratio_ * 2.0;
324 
325  local_rotate_up_accum_ += y_shift;
326  local_rotate_right_accum_ += x_shift;
327 
328  const auto m =
329  Eigen::AngleAxisd(
330  -degrees_per_unit * local_rotate_up_accum_ * M_PI / 180,
332  Eigen::AngleAxisd(
333  degrees_per_unit * local_rotate_right_accum_ * M_PI / 180,
335 
339 
340  // Prevent SetProjectionParameters re-setting camera local rotation starts
341  auto orig_up = start_local_rotate_up_;
342  auto orig_right = start_local_rotate_right_;
343  auto orig_eye = start_local_rotate_eye_;
344  auto orig_front = start_local_rotate_front_;
345  auto orig_lookat = start_local_rotate_lookat_;
346  auto orig_up_accum = local_rotate_up_accum_;
347  auto orig_right_accum = local_rotate_right_accum_;
348 
350 
351  start_local_rotate_up_ = orig_up;
352  start_local_rotate_right_ = orig_right;
353  start_local_rotate_eye_ = orig_eye;
354  start_local_rotate_front_ = orig_front;
355  start_local_rotate_lookat_ = orig_lookat;
356  local_rotate_up_accum_ = orig_up_accum;
357  local_rotate_right_accum_ = orig_right_accum;
358 }
359 
368 }
369 
370 void ViewControl::Roll(double x) {
371  double alpha = x * ROTATION_RADIAN_PER_PIXEL;
372  // Rotates up_ vector using Rodrigues' rotation formula.
373  // front_ vector is an axis of rotation.
374  up_ = up_ * std::cos(alpha) + front_.cross(up_) * std::sin(alpha) +
375  front_ * (front_.dot(up_)) * (1.0 - std::cos(alpha));
376  up_.normalized();
378 }
379 
380 } // namespace visualization
381 } // namespace cloudViewer
constexpr double M_PI
Pi.
Definition: CVConst.h:19
int width
int height
PointCoordinateType GetMaxExtent() const
Definition: ecvBBox.h:156
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
virtual Eigen::Vector3d GetCenter() const override
Returns the center of the geometry coordinates.
Definition: ecvBBox.h:87
virtual bool IsEmpty() const override
Definition: ecvBBox.h:72
const Vector3Tpl< T > & maxCorner() const
Returns max corner (const)
Definition: BoundingBox.h:156
void setValidity(bool state)
Sets bonding box validity.
Definition: BoundingBox.h:200
const Vector3Tpl< T > & minCorner() const
Returns min corner (const)
Definition: BoundingBox.h:154
Contains the pinhole camera intrinsic parameters.
Contains both intrinsic and extrinsic pinhole camera parameters.
PinholeCameraIntrinsic intrinsic_
PinholeCameraIntrinsic object.
Eigen::Matrix4d_u extrinsic_
Camera extrinsic parameters.
static const double FIELD_OF_VIEW_STEP
Definition: ViewControl.h:30
bool ConvertFromViewParameters(const ViewParameters &status)
Definition: ViewControl.cpp:97
ProjectionType GetProjectionType() const
void SetFront(const Eigen::Vector3d &front)
void SetUp(const Eigen::Vector3d &up)
virtual void Translate(double x, double y, double xo=0.0, double yo=0.0)
Function to process translation.
virtual void Rotate(double x, double y, double xo=0.0, double yo=0.0)
Function to process rotation.
virtual void CameraLocalTranslate(double forward, double right, double up)
virtual void CameraLocalRotate(double x, double y, double xo=0.0, double yo=0.0)
virtual void ChangeFieldOfView(double step)
virtual void ChangeWindowSize(int width, int height)
bool ConvertFromPinholeCameraParameters(const camera::PinholeCameraParameters &parameters, bool allow_arbitrary=false)
void SetLookat(const Eigen::Vector3d &lookat)
virtual void Scale(double scale)
static const double FIELD_OF_VIEW_DEFAULT
Definition: ViewControl.h:29
void SetViewMatrices(const Eigen::Matrix4d &model_matrix=Eigen::Matrix4d::Identity())
Definition: ViewControl.cpp:38
bool ConvertToPinholeCameraParameters(camera::PinholeCameraParameters &parameters)
static const double ROTATION_RADIAN_PER_PIXEL
Definition: ViewControl.h:37
bool ConvertToViewParameters(ViewParameters &status) const
Function to get equivalent view parameters (support orthogonal)
Definition: ViewControl.cpp:86
#define LogWarning(...)
Definition: Logging.h:72
__host__ __device__ float dot(float2 a, float2 b)
Definition: cutil_math.h:1119
int min(int a, int b)
Definition: cutil_math.h:53
__host__ __device__ int2 abs(int2 v)
Definition: cutil_math.h:1267
int max(int a, int b)
Definition: cutil_math.h:48
GLMatrix4f LookAt(const Eigen::Vector3d &eye, const Eigen::Vector3d &lookat, const Eigen::Vector3d &up)
Definition: GLHelper.cpp:31
GLMatrix4f Perspective(double field_of_view_, double aspect, double z_near, double z_far)
Definition: GLHelper.cpp:50
GLMatrix4f Ortho(double left, double right, double bottom, double top, double z_near, double z_far)
Definition: GLHelper.cpp:65
Generic file read and write utility for python interface.