1 // Copyright (C) 2012-2019 The VPaint Developers.
2 // See the COPYRIGHT file at the top-level directory of this distribution
3 // and at https://github.com/dalboris/vpaint/blob/master/COPYRIGHT
4 //
5 // Licensed under the Apache License, Version 2.0 (the "License");
6 // you may not use this file except in compliance with the License.
7 // You may obtain a copy of the License at
8 //
9 //     http://www.apache.org/licenses/LICENSE-2.0
10 //
11 // Unless required by applicable law or agreed to in writing, software
12 // distributed under the License is distributed on an "AS IS" BASIS,
13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 // See the License for the specific language governing permissions and
15 // limitations under the License.
16 
17 #ifndef GLWIDGET_CAMERA_H
18 #define GLWIDGET_CAMERA_H
19 
20 #include <Eigen/Core>
21 #include <Eigen/Geometry>
22 
23 /*
24  * The Camera is defined by:
25  *   - The position of its focus point
26  *   - Its distance and angle around this point
27  *   - Its aperture
28  *
29  *   There are only 2 angles to define the orientation of the camera: yaw and
30  *   pitch (no roll). This is a voluntary loss of degree of freedom: we force
31  *   the horizon line to be horizontal on screen (avoid getting lost and/or
32  *   sea-sick).
33  *
34  */
35 
36 class GLWidget_Camera
37 {
38 public:
39     // initialization: correctly positionned to see a unit cube
GLWidget_Camera()40     GLWidget_Camera() :
41         r_(4), theta_(3.14/10), phi_(3.14/6),
42         focus_x_(0), focus_y_(0), focus_z_(0),
43         fovy_(3.14/4)
44     {
45         setDirty_();
46     }
47 
48     // Camera position and orientation (= View Matrix)
r()49     double r()       const { return r_;       }
theta()50     double theta()   const { return theta_;   }
phi()51     double phi()     const { return phi_;     }
focus_x()52     double focus_x() const { return focus_x_; }
focus_y()53     double focus_y() const { return focus_y_; }
focus_z()54     double focus_z() const { return focus_z_; }
55 
56     // Camera field of view (= Projection Matrix)
fovy()57     double fovy()    const { return fovy_;    }
58 
59     // Setters
setR(double r)60     void setR(double r)             { r_=r;             setDirty_(); }
setTheta(double theta)61     void setTheta(double theta)     { theta_=theta;     setDirty_(); }
setPhi(double phi)62     void setPhi(double phi)         { phi_=phi;         setDirty_(); }
setFocus_x(double focus_x)63     void setFocus_x(double focus_x) { focus_x_=focus_x; setDirty_(); }
setFocus_y(double focus_y)64     void setFocus_y(double focus_y) { focus_y_=focus_y; setDirty_(); }
setFocus_z(double focus_z)65     void setFocus_z(double focus_z) { focus_z_=focus_z; setDirty_(); }
setFovy(double fovy)66     void setFovy(double fovy)       { fovy_=fovy;       setDirty_(); }
67 
68     // Get matrices
viewMatrix()69     Eigen::Affine3d viewMatrix() const
70     {
71         computeViewMatrix_();
72         return viewMatrix_;
73     }
74 
viewMatrixInverse()75     Eigen::Affine3d viewMatrixInverse() const
76     {
77         computeViewMatrixInverse_();
78         return viewMatrixInverse_;
79     }
80 
81     // convenient methods to access other geometric properties
position()82     Eigen::Vector3d position() const
83     {
84         double cos_theta = std::cos(theta());
85         double sin_theta = std::sin(theta());
86         double cos_phi   = std::cos(phi());
87         double sin_phi   = std::sin(phi());
88 
89         return Eigen::Vector3d(
90                     focus_x() + r() * cos_theta * sin_phi,
91                     focus_y() + r() * sin_theta,
92                     focus_z() + r() * cos_theta * cos_phi);
93     }
94 
focusPoint()95     Eigen::Vector3d focusPoint() const
96     {
97         return Eigen::Vector3d(focus_x(),    focus_y(), focus_z());
98     }
99 
upDirection()100     Eigen::Vector3d upDirection() const
101     {
102         double cos_theta = std::cos(theta());
103         double sin_theta = std::sin(theta());
104         double cos_phi   = std::cos(phi());
105         double sin_phi   = std::sin(phi());
106 
107         return Eigen::Vector3d(
108                     - sin_theta * sin_phi,
109                     cos_theta,
110                     - sin_theta * cos_phi);
111     }
112 
113 
114 private:
115     // Camera parameters
116     double r_;
117     double theta_;
118     double phi_;
119     double focus_x_;
120     double focus_y_;
121     double focus_z_;
122     double fovy_;
123 
124     // Matrix
125     mutable bool viewMatrixDirty_;
126     mutable bool viewMatrixInverseDirty_;
127     mutable Eigen::Affine3d viewMatrix_;
128     mutable Eigen::Affine3d viewMatrixInverse_;
setDirty_()129     void setDirty_()
130     {
131         viewMatrixDirty_ = true;
132         viewMatrixInverseDirty_ = true;
133     }
computeViewMatrix_()134     void computeViewMatrix_() const
135     {
136         if(viewMatrixDirty_)
137         {
138             // [...] compute it
139             viewMatrixDirty_ = false;
140         }
141     }
computeViewMatrixInverse_()142     void computeViewMatrixInverse_() const
143     {
144         if(viewMatrixInverseDirty_)
145         {
146             computeViewMatrix_();
147             viewMatrixInverse_ = viewMatrix_.inverse();
148             viewMatrixInverseDirty_ = false;
149         }
150     }
151 
152 public:
153     EIGEN_MAKE_ALIGNED_OPERATOR_NEW
154 
155 };
156 
157 
158 #endif
159