• Skip to content
  • Skip to link menu
KDE 4.0 API Reference
  • KDE API Reference
  • kdeedu
  • Sitemap
  • Contact Us
 

kalzium

camera.cpp

Go to the documentation of this file.
00001 /**********************************************************************
00002   Camera - Class for representing the view.
00003 
00004   Copyright (C) 2007 Benoit Jacob <jacob@math.jussieu.fr>
00005 
00006   This file is part of the Avogadro molecular editor project.
00007   For more information, see <http://avogadro.sourceforge.net/>
00008 
00009   Avogadro is free software; you can redistribute it and/or modify 
00010   it under the terms of the GNU General Public License as published by 
00011   the Free Software Foundation; either version 2 of the License, or 
00012   (at your option) any later version.
00013 
00014   Avogadro is distributed in the hope that it will be useful,
00015   but WITHOUT ANY WARRANTY; without even the implied warranty of
00016   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00017   GNU General Public License for more details.
00018 
00019   You should have received a copy of the GNU General Public License
00020   along with this program; if not, write to the Free Software
00021   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
00022   02110-1301, USA.
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     // if the molecule is empty, we want to look at its center
00151     // (which is probably at the origin, but who knows) from some distance
00152     // (here 10.0).
00153     if( d->parent->molecule()->NumAtoms() == 0 )
00154     {
00155       d->modelview.translate( d->parent->center() - Vector3d( 0, 0, 10 ) );
00156       return;
00157     }
00158     
00159     // if we're here, the molecule is not empty, i.e. has atoms.
00160     // we want a top-down view on it, i.e. the molecule should fit as well as
00161     // possible in the (X,Y)-plane. Equivalently, we want the Z axis to be parallel
00162     // to the normal vector of the molecule's fitting plane.
00163     // Thus we construct a suitable base-change rotation.
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     // set the camera's matrix to be (the 4x4 version of) this rotation.
00170     setModelview(rotation);
00171   
00172     // now we want to move backwards, in order
00173     // to view the molecule from a distance, not from inside it.
00174     // This translation must be applied after the above rotation, so we
00175     // want a left-multiplication here. Whence pretranslate().
00176     const Vector3d Zaxis(0,0,1);
00177     pretranslate( - 3.0 * ( d->parent->radius() + CAMERA_NEAR_DISTANCE ) * Zaxis );
00178     
00179     // the above rotation is meant to be a rotation around the molecule's
00180     // center. So before this rotation is applied, the molecule's center
00181     // must be brought to the origin of the coordinate systemby a translation.
00182     // As this translation must be applied first, we want a right-multiplication here.
00183     // Whence translate().
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     // radius() returns the radius without electrons. We add 0.3 nanometer,
00193     // which is about the biggest possible VDW radius of an atom.
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     // project the reference point
00220     Eigen::Vector3d projected = project(ref);
00221 
00222     // Now unproject the pixel of coordinates (x,height-y) into a 3D point having the same Z-index
00223     // as the reference point.
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 } // end namespace Avogadro

kalzium

Skip menu "kalzium"
  • Main Page
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members
  • Related Pages

kdeedu

Skip menu "kdeedu"
  • kalzium
  • kanagram
  • kig
  • klettres
  • kstars
  • libkdeedu
  •   keduvocdocument
  •   docs
  •   src
  • parley
Generated for kdeedu by doxygen 1.5.4
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal