Mechanics of Defect Evolution Library
Loading...
Searching...
No Matches
FrameCameraRotation.h
Go to the documentation of this file.
1/* This file is part of MoDELib, distributed under GNU GPL v2. */
2#ifndef model_FrameCameraRotation_H_
3#define model_FrameCameraRotation_H_
4#include <Eigen/Geometry>
5#include <vtkCamera.h>
6#include <vtkWeakPointer.h>
7#include <cmath>
8#include <cstddef>
9#include <stdexcept>
10
11namespace model
12{
14 {
15 Eigen::Matrix3d applied = Eigen::Matrix3d::Identity();
16 vtkWeakPointer<vtkCamera> lastCamera;
17 bool advanced = false;
18
19 public:
20 void apply(vtkCamera *camera, const Eigen::Vector3d &center, const Eigen::Vector3d &axis,
21 double degreesPerFrame, size_t frameID, double advancePerFrame = 0.0)
22 {
23 if(!center.allFinite() || !axis.allFinite() || axis.stableNorm() == 0.0 || !std::isfinite(degreesPerFrame) || !std::isfinite(advancePerFrame))
24 {
25 throw std::invalid_argument("Enter a finite, nonzero rotation axis and finite angle and advance.");
26 }
27 if(lastCamera.GetPointer() != camera)
28 {
29 applied.setIdentity();
30 lastCamera = camera;
31 advanced = false;
32 }
33 // Reduce the absolute angle before conversion to radians. Sparse runIDs
34 // and backward navigation therefore have the same orientation as direct jumps.
35 const long double degrees = std::fmod(static_cast<long double>(degreesPerFrame) * frameID, 360.0L);
36 const Eigen::Matrix3d target = Eigen::AngleAxisd(
37 static_cast<double>(degrees) * std::acos(-1.0) / 180.0, axis.stableNormalized()).toRotationMatrix();
38 if(degreesPerFrame == 0.0 && advancePerFrame == 0.0 && !advanced && target.isApprox(applied, 1.e-14))
39 {
40 return;
41 }
42 // Remove the previous automatic rotation before applying the new one.
43 // Recenter the current view on the box while retaining its viewing
44 // direction and zoom. Panning must not move the automatic rotation axis.
45 const Eigen::Matrix3d change = target * applied.transpose();
46 const Eigen::Vector3d focal(camera->GetFocalPoint());
47 const Eigen::Vector3d offset = change * (Eigen::Vector3d(camera->GetPosition()) - focal);
48 const double travel = advancePerFrame * static_cast<double>(frameID);
49 if(!std::isfinite(travel))
50 {
51 throw std::invalid_argument("Camera advance times frameID must be finite.");
52 }
53 Eigen::Vector3d targetFocal = center;
54 if(offset.stableNorm()>0.0)
55 {
56 targetFocal -= travel * offset.stableNormalized();
57 }
58 // Translate eye and focal point together so crossing the center neither
59 // collapses the viewing direction nor turns the camera backward.
60 const Eigen::Vector3d position = targetFocal + offset;
61 if(advancePerFrame != 0.0)
62 {
63 camera->ParallelProjectionOff();
64 }
65 const Eigen::Vector3d up = change * Eigen::Vector3d(camera->GetViewUp());
66 camera->SetFocalPoint(targetFocal.data());
67 camera->SetPosition(position.data());
68 camera->SetViewUp(up.data());
69 camera->OrthogonalizeViewUp();
70 applied = target;
71 advanced = advancePerFrame != 0.0;
72 }
73 };
74}
75#endif
void apply(vtkCamera *camera, const Eigen::Vector3d &center, const Eigen::Vector3d &axis, double degreesPerFrame, size_t frameID, double advancePerFrame=0.0)
int axis