some fixes to the cmake files. It still is not working
[kdeedu-porting.git] / kalzium / libavogadro-kalzium / src / camera.cpp
blob8904fddd83fa5a80091b83d8a9637060ff76e7bf
1 /**********************************************************************
2 Camera - Class for representing the view.
4 Copyright (C) 2007 Benoit Jacob
6 This file is part of the Avogadro molecular editor project.
7 For more information, see <http://avogadro.sourceforge.net/>
9 Avogadro is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
14 Avogadro is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
22 02110-1301, USA.
23 **********************************************************************/
25 #include <config.h>
26 #include <avogadro/camera.h>
27 #include <avogadro/glwidget.h>
29 using namespace Eigen;
31 namespace Avogadro
33 class CameraPrivate
35 public:
36 CameraPrivate() {};
38 MatrixP3d modelview, projection;
39 const GLWidget *parent;
40 double angleOfViewY;
43 Camera::Camera(const GLWidget *parent, double angleOfViewY) : d(new CameraPrivate)
45 d->modelview.loadIdentity();
46 d->projection.loadIdentity();
47 d->parent = parent;
48 d->angleOfViewY = angleOfViewY;
51 Camera::~Camera()
53 delete d;
56 Camera::Camera(const Camera *camera) : d(new CameraPrivate)
58 d->modelview = camera->d->modelview;
59 d->projection = camera->d->projection;
60 d->parent = camera->d->parent;
61 d->angleOfViewY = camera->d->angleOfViewY;
64 void Camera::setParent(const GLWidget *parent)
66 d->parent = parent;
69 void Camera::normalize()
71 Matrix3d m;
72 Vector3d c0, c1, c2;
73 d->modelview.getLinearComponent(&m);
75 m.getColumn(0, &c0);
76 c0.normalize();
77 m.setColumn(0, c0);
78 m.getColumn(1, &c1);
79 c1.normalize();
80 c1 -= dot(c0, c1) * c0;
81 c1.normalize();
82 m.setColumn(1, c1);
83 m.getColumn(2, &c2);
84 c2.normalize();
85 c2 -= dot(c0, c2) * c0;
86 c2 -= dot(c1, c2) * c1;
87 c2.normalize();
88 m.setColumn(2, c2);
90 d->modelview.setLinearComponent(m);
91 d->modelview.matrix().setRow(3, Vector4d(0.0, 0.0, 0.0, 1.0));
94 const GLWidget *Camera::parent() const
96 return d->parent;
99 void Camera::setAngleOfViewY(double angleOfViewY)
101 d->angleOfViewY = angleOfViewY;
104 double Camera::angleOfViewY() const
106 return d->angleOfViewY;
109 void Camera::translate(const Eigen::Vector3d &vector)
111 d->modelview.translate(vector);
114 void Camera::pretranslate(const Eigen::Vector3d &vector)
116 d->modelview.pretranslate(vector);
119 void Camera::rotate(const double &angle, const Eigen::Vector3d &axis)
121 d->modelview.rotate3(angle, axis);
122 normalize();
125 void Camera::prerotate(const double &angle, const Eigen::Vector3d &axis)
127 d->modelview.prerotate3(angle, axis);
128 normalize();
131 const double Camera::distance(const Eigen::Vector3d & point) const
133 return ( d->modelview * point ).norm();
136 void Camera::setModelview(const Eigen::MatrixP3d &matrix)
138 d->modelview = matrix;
141 const Eigen::MatrixP3d & Camera::modelview() const
143 return d->modelview;
146 Eigen::MatrixP3d & Camera::modelview()
148 return d->modelview;
151 void Camera::initializeViewPoint()
153 d->modelview.loadIdentity();
154 if( d->parent == 0 ) return;
155 if( d->parent->molecule() == 0 ) return;
157 // if the molecule is empty, we want to look at its center
158 // (which is probably at the origin, but who knows) from some distance
159 // (here 10.0).
160 if( d->parent->molecule()->NumAtoms() == 0 )
162 d->modelview.translate( d->parent->center() - Vector3d( 0, 0, 10 ) );
163 return;
166 // if we're here, the molecule is not empty, i.e. has atoms.
167 // we want a top-down view on it, i.e. the molecule should fit as well as
168 // possible in the (X,Y)-plane. Equivalently, we want the Z axis to be parallel
169 // to the normal vector of the molecule's fitting plane.
170 // Thus we construct a suitable base-change rotation.
171 Matrix3d rotation;
172 rotation.setRow(2, d->parent->normalVector());
173 rotation.setRow(0, rotation.row(2).ortho());
174 rotation.setRow(1, rotation.row(2).cross(rotation.row(0)));
176 // set the camera's matrix to be (the 4x4 version of) this rotation.
177 setModelview(rotation);
179 // now we want to move backwards, in order
180 // to view the molecule from a distance, not from inside it.
181 // This translation must be applied after the above rotation, so we
182 // want a left-multiplication here. Whence pretranslate().
183 const Vector3d Zaxis(0,0,1);
184 pretranslate( - 3.0 * ( d->parent->radius() + CAMERA_NEAR_DISTANCE ) * Zaxis );
186 // the above rotation is meant to be a rotation around the molecule's
187 // center. So before this rotation is applied, the molecule's center
188 // must be brought to the origin of the coordinate systemby a translation.
189 // As this translation must be applied first, we want a right-multiplication here.
190 // Whence translate().
191 translate( - d->parent->center() );
194 void Camera::applyPerspective() const
196 if( d->parent == 0 ) return;
197 if( d->parent->molecule() == 0 ) return;
199 double molRadius = d->parent->radius() + CAMERA_MOL_RADIUS_MARGIN;
200 double distanceToMolCenter = distance( d->parent->center() );
201 double zNear = std::max( CAMERA_NEAR_DISTANCE, distanceToMolCenter - molRadius );
202 double zFar = distanceToMolCenter + molRadius;
203 double aspectRatio = static_cast<double>(d->parent->width()) / d->parent->height();
204 gluPerspective( d->angleOfViewY, aspectRatio, zNear, zFar );
205 glGetDoublev(GL_PROJECTION_MATRIX, d->projection.array());
208 void Camera::applyModelview() const
210 glMultMatrixd( d->modelview.array() );
213 Eigen::Vector3d Camera::unProject(const Eigen::Vector3d & v) const
215 GLint viewport[4] = {0, 0, parent()->width(), parent()->height() };
216 Eigen::Vector3d pos;
217 gluUnProject(v.x(), parent()->height() - v.y(), v.z(),
218 d->modelview.array(), d->projection.array(), viewport, &pos.x(), &pos.y(), &pos.z());
219 return pos;
222 Eigen::Vector3d Camera::unProject(const QPoint& p, const Eigen::Vector3d& ref) const
224 return unProject( Eigen::Vector3d( p.x(), p.y(), project(ref).z() ));
227 Eigen::Vector3d Camera::unProject(const QPoint& p) const
229 return unProject(p, parent()->center());
232 Eigen::Vector3d Camera::project(const Eigen::Vector3d & v) const
234 GLint viewport[4] = {0, 0, parent()->width(), parent()->height() };
235 Eigen::Vector3d pos;
236 gluProject(v.x(), v.y(), v.z(),
237 d->modelview.array(), d->projection.array(), viewport, &pos.x(), &pos.y(), &pos.z());
239 pos.y() = parent()->height() - pos.y();
240 return pos;
243 Eigen::Vector3d Camera::backTransformedXAxis() const
245 return Eigen::Vector3d( d->modelview(0, 0),
246 d->modelview(0, 1),
247 d->modelview(0, 2) );
250 Eigen::Vector3d Camera::backTransformedYAxis() const
252 return Eigen::Vector3d( d->modelview(1, 0),
253 d->modelview(1, 1),
254 d->modelview(1, 2) );
257 Eigen::Vector3d Camera::backTransformedZAxis() const
259 return Eigen::Vector3d( d->modelview(2, 0),
260 d->modelview(2, 1),
261 d->modelview(2, 2) );
264 Eigen::Vector3d Camera::transformedXAxis() const
266 // The x unit vector in space coordinates
267 return Eigen::Vector3d( d->modelview(0, 0),
268 d->modelview(1, 0),
269 d->modelview(2, 0) );
272 Eigen::Vector3d Camera::transformedYAxis() const
274 // The y unit vector in space coordinates
275 return Eigen::Vector3d( d->modelview(0, 1),
276 d->modelview(1, 1),
277 d->modelview(2, 1) );
280 Eigen::Vector3d Camera::transformedZAxis() const
282 // The z unit vector in space coordinates
283 return Eigen::Vector3d( d->modelview(0, 2),
284 d->modelview(1, 2),
285 d->modelview(2, 2) );
288 } // end namespace Avogadro