00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025 #include <config.h>
00026
00027 #include <avogadro/glwidget.h>
00028 #include <avogadro/camera.h>
00029
00030 using namespace Eigen;
00031
00032 namespace Avogadro
00033 {
00034 class CameraPrivate
00035 {
00036 public:
00037 CameraPrivate() {};
00038
00039 MatrixP3d modelview, projection;
00040 const GLWidget *parent;
00041 double angleOfViewY;
00042 };
00043
00044 Camera::Camera(const GLWidget *parent, double angleOfViewY) : d(new CameraPrivate)
00045 {
00046 d->modelview.loadIdentity();
00047 d->projection.loadIdentity();
00048 d->parent = parent;
00049 d->angleOfViewY = angleOfViewY;
00050 }
00051
00052 Camera::~Camera()
00053 {
00054 delete d;
00055 }
00056
00057 void Camera::setParent(const GLWidget *parent)
00058 {
00059 d->parent = parent;
00060 }
00061
00062 void Camera::normalize()
00063 {
00064 Matrix3d m;
00065 Vector3d c0, c1, c2;
00066 d->modelview.getLinearComponent(&m);
00067
00068 m.getColumn(0, &c0);
00069 c0.normalize();
00070 m.setColumn(0, c0);
00071 m.getColumn(1, &c1);
00072 c1.normalize();
00073 c1 -= dot(c0, c1) * c0;
00074 c1.normalize();
00075 m.setColumn(1, c1);
00076 m.getColumn(2, &c2);
00077 c2.normalize();
00078 c2 -= dot(c0, c2) * c0;
00079 c2 -= dot(c1, c2) * c1;
00080 c2.normalize();
00081 m.setColumn(2, c2);
00082
00083 d->modelview.setLinearComponent(m);
00084 d->modelview.matrix().setRow(3, Vector4d(0.0, 0.0, 0.0, 1.0));
00085 }
00086
00087 const GLWidget *Camera::parent() const
00088 {
00089 return d->parent;
00090 }
00091
00092 void Camera::setAngleOfViewY(double angleOfViewY)
00093 {
00094 d->angleOfViewY = angleOfViewY;
00095 }
00096
00097 double Camera::angleOfViewY() const
00098 {
00099 return d->angleOfViewY;
00100 }
00101
00102 void Camera::translate(const Eigen::Vector3d &vector)
00103 {
00104 d->modelview.translate(vector);
00105 }
00106
00107 void Camera::pretranslate(const Eigen::Vector3d &vector)
00108 {
00109 d->modelview.pretranslate(vector);
00110 }
00111
00112 void Camera::rotate(const double &angle, const Eigen::Vector3d &axis)
00113 {
00114 d->modelview.rotate3(angle, axis);
00115 normalize();
00116 }
00117
00118 void Camera::prerotate(const double &angle, const Eigen::Vector3d &axis)
00119 {
00120 d->modelview.prerotate3(angle, axis);
00121 normalize();
00122 }
00123
00124 const double Camera::distance(const Eigen::Vector3d & point) const
00125 {
00126 return ( d->modelview * point ).norm();
00127 }
00128
00129 void Camera::setModelview(const Eigen::MatrixP3d &matrix)
00130 {
00131 d->modelview = matrix;
00132 }
00133
00134 const Eigen::MatrixP3d & Camera::modelview() const
00135 {
00136 return d->modelview;
00137 }
00138
00139 Eigen::MatrixP3d & Camera::modelview()
00140 {
00141 return d->modelview;
00142 }
00143
00144 void Camera::initializeViewPoint()
00145 {
00146 d->modelview.loadIdentity();
00147 if( d->parent == 0 ) return;
00148 if( d->parent->molecule() == 0 ) return;
00149
00150
00151
00152
00153 if( d->parent->molecule()->NumAtoms() == 0 )
00154 {
00155 d->modelview.translate( d->parent->center() - Vector3d( 0, 0, 10 ) );
00156 return;
00157 }
00158
00159
00160
00161
00162
00163
00164 Matrix3d rotation;
00165 rotation.setRow(2, d->parent->normalVector());
00166 rotation.setRow(0, rotation.row(2).ortho());
00167 rotation.setRow(1, rotation.row(2).cross(rotation.row(0)));
00168
00169
00170 setModelview(rotation);
00171
00172
00173
00174
00175
00176 const Vector3d Zaxis(0,0,1);
00177 pretranslate( - 3.0 * ( d->parent->radius() + CAMERA_NEAR_DISTANCE ) * Zaxis );
00178
00179
00180
00181
00182
00183
00184 translate( - d->parent->center() );
00185 }
00186
00187 void Camera::applyPerspective() const
00188 {
00189 if( d->parent == 0 ) return;
00190 if( d->parent->molecule() == 0 ) return;
00191
00192
00193
00194 double molRadius = d->parent->radius() + CAMERA_MOL_RADIUS_MARGIN;
00195 double distanceToMolCenter = distance( d->parent->center() );
00196 double zNear = std::max( CAMERA_NEAR_DISTANCE, distanceToMolCenter - molRadius );
00197 double zFar = distanceToMolCenter + molRadius;
00198 double aspectRatio = static_cast<double>(d->parent->width()) / d->parent->height();
00199 gluPerspective( d->angleOfViewY, aspectRatio, zNear, zFar );
00200 glGetDoublev(GL_PROJECTION_MATRIX, d->projection.array());
00201 }
00202
00203 void Camera::applyModelview() const
00204 {
00205 glMultMatrixd( d->modelview.array() );
00206 }
00207
00208 Eigen::Vector3d Camera::unProject(const Eigen::Vector3d & v) const
00209 {
00210 GLint viewport[4] = {0, 0, parent()->width(), parent()->height() };
00211 Eigen::Vector3d pos;
00212 gluUnProject(v.x(), parent()->height() - v.y(), v.z(),
00213 d->modelview.array(), d->projection.array(), viewport, &pos.x(), &pos.y(), &pos.z());
00214 return pos;
00215 }
00216
00217 Eigen::Vector3d Camera::unProject(const QPoint& p, const Eigen::Vector3d& ref) const
00218 {
00219
00220 Eigen::Vector3d projected = project(ref);
00221
00222
00223
00224 Eigen::Vector3d pos = unProject( Eigen::Vector3d( p.x(), p.y(), projected.z() ));
00225
00226 return pos;
00227 }
00228
00229 Eigen::Vector3d Camera::unProject(const QPoint& p) const
00230 {
00231 return unProject(p, parent()->center());
00232 }
00233
00234 Eigen::Vector3d Camera::project(const Eigen::Vector3d & v) const
00235 {
00236 GLint viewport[4] = {0, 0, parent()->width(), parent()->height() };
00237 Eigen::Vector3d pos;
00238 gluProject(v.x(), v.y(), v.z(),
00239 d->modelview.array(), d->projection.array(), viewport, &pos.x(), &pos.y(), &pos.z());
00240
00241 return pos;
00242 }
00243
00244 Eigen::Vector3d Camera::backtransformedXAxis() const
00245 {
00246 return Eigen::Vector3d( d->modelview(0, 0),
00247 d->modelview(0, 1),
00248 d->modelview(0, 2) );
00249 }
00250
00251 Eigen::Vector3d Camera::backtransformedYAxis() const
00252 {
00253 return Eigen::Vector3d( d->modelview(1, 0),
00254 d->modelview(1, 1),
00255 d->modelview(1, 2) );
00256 }
00257
00258 Eigen::Vector3d Camera::backtransformedZAxis() const
00259 {
00260 return Eigen::Vector3d( d->modelview(2, 0),
00261 d->modelview(2, 1),
00262 d->modelview(2, 2) );
00263 }
00264
00265 }