some fixes to the cmake files. It still is not working
[kdeedu-porting.git] / kalzium / libavogadro-kalzium / src / cylinder.cpp
blobd095b6a8d5504945c9656c1ffede5e6dc953e555
1 /**********************************************************************
2 Cylinder - OpenGL Cylinder drawing class.
4 Copyright (C) 2006,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 "cylinder.h"
26 #include <QGLWidget>
28 using namespace Eigen;
30 namespace Avogadro {
32 class CylinderPrivate {
33 public:
34 CylinderPrivate() : vertexBuffer(0), normalBuffer(0), displayList(0), isValid(false) {}
36 /** Pointer to the buffer storing the vertex array */
37 Eigen::Vector3f *vertexBuffer;
38 /** Pointer to the buffer storing the normal array */
39 Eigen::Vector3f *normalBuffer;
40 /** The id of the OpenGL display list */
41 GLuint displayList;
42 /** Equals true if the vertex array has been correctly initialized */
43 bool isValid;
45 /** the number of faces of the cylinder. This only
46 * includes the lateral faces, as the base and top faces (the
47 * two discs) are not rendered. */
48 int faces;
51 Cylinder::Cylinder(int faces) : d(new CylinderPrivate)
53 setup(faces);
56 Cylinder::~Cylinder()
58 freeBuffers();
59 if( d->displayList ) {
60 glDeleteLists( d->displayList, 1 );
62 delete d;
65 void Cylinder::freeBuffers()
67 if( d->normalBuffer )
69 delete [] d->normalBuffer;
70 d->normalBuffer = 0;
72 if( d->vertexBuffer )
74 delete [] d->vertexBuffer;
75 d->vertexBuffer = 0;
79 void Cylinder::setup( int faces )
81 if( d->isValid && faces == d->faces ) return;
82 d->faces = faces;
83 initialize();
86 void Cylinder::initialize()
88 d->isValid = false;
89 if( d->faces < 0 ) return;
91 // compile display list and free buffers
92 if( ! d->displayList ) d->displayList = glGenLists( 1 );
93 if( ! d->displayList ) return;
95 if( d->faces < 3 )
97 glNewList( d->displayList, GL_COMPILE );
98 glLineWidth(1.0);
99 glBegin(GL_LINES);
100 glVertex3f(0, 0, 0);
101 glVertex3f(0, 0, 1);
102 glEnd();
103 glEndList();
105 else
107 // compute number of vertices
108 int vertexCount = 2 * d->faces + 2;
110 // deallocate any previously allocated buffer
111 freeBuffers();
113 // allocate memory for buffers
114 d->vertexBuffer = new Vector3f[vertexCount];
115 if( ! d->vertexBuffer ) return;
116 d->normalBuffer = new Vector3f[vertexCount];
117 if( ! d->normalBuffer ) return;
119 float baseAngle = 2 * M_PI / d->faces;
120 // build vertex and normal buffers
121 for( int i = 0; i <= d->faces; i++ )
123 float angle = baseAngle * i;
124 Vector3f v( cosf(angle), sinf(angle), 0.0f );
125 d->normalBuffer[ 2 * i ] = v;
126 d->normalBuffer[ 2 * i + 1 ] = v;
127 d->vertexBuffer[ 2 * i ] = v;
128 d->vertexBuffer[ 2 * i + 1 ] = v;
129 d->vertexBuffer[ 2 * i ].z() = 1.0f;
131 glEnableClientState( GL_VERTEX_ARRAY );
132 glEnableClientState( GL_NORMAL_ARRAY );
133 glNewList( d->displayList, GL_COMPILE );
134 glVertexPointer( 3, GL_FLOAT, 0, d->vertexBuffer );
135 glNormalPointer( GL_FLOAT, 0, d->normalBuffer );
136 glDrawArrays( GL_QUAD_STRIP, 0, vertexCount );
137 glEndList();
138 glDisableClientState( GL_VERTEX_ARRAY );
139 glDisableClientState( GL_NORMAL_ARRAY );
141 freeBuffers();
142 d->isValid = true;
145 void Cylinder::draw( const Vector3d &end1, const Vector3d &end2,
146 double radius ) const
148 // the "axis vector" of the cylinder
149 Vector3d axis = end2 - end1;
151 // construct an orthogonal basis whose first vector is axis, and whose other vectors
152 // have norm equal to 'radius'.
153 Vector3d axisNormalized = axis.normalized();
154 Vector3d ortho1, ortho2;
155 ortho1.loadOrtho(axisNormalized);
156 ortho1 *= radius;
157 axisNormalized.cross( ortho1, &ortho2 );
159 // construct the 4D transformation matrix
160 Matrix4d matrix;
162 matrix(0, 0) = ortho1(0);
163 matrix(1, 0) = ortho1(1);
164 matrix(2, 0) = ortho1(2);
165 matrix(3, 0) = 0.0;
167 matrix(0, 1) = ortho2(0);
168 matrix(1, 1) = ortho2(1);
169 matrix(2, 1) = ortho2(2);
170 matrix(3, 1) = 0.0;
172 matrix(0, 2) = axis(0);
173 matrix(1, 2) = axis(1);
174 matrix(2, 2) = axis(2);
175 matrix(3, 2) = 0.0;
177 matrix(0, 3) = end1(0);
178 matrix(1, 3) = end1(1);
179 matrix(2, 3) = end1(2);
180 matrix(3, 3) = 1.0;
182 //now we can do the actual drawing !
183 glPushMatrix();
184 glMultMatrixd( matrix.array() );
185 glCallList( d->displayList );
186 glPopMatrix();
189 void Cylinder::drawMulti( const Vector3d &end1, const Vector3d &end2,
190 double radius, int order, double shift,
191 const Vector3d &planeNormalVector ) const
194 // the "axis vector" of the cylinder
195 Vector3d axis = end2 - end1;
197 // now we want to construct an orthonormal basis whose first
198 // vector is axis.normalized(). We don't use Eigen's loadOrthoBasis()
199 // for that, because we want one more thing. The second vector in this
200 // basis, which we call ortho1, should be approximately lying in the
201 // z=0 plane if possible. This is to ensure double bonds don't look
202 // like single bonds from the default point of view.
203 double axisNorm = axis.norm();
204 if( axisNorm == 0.0 ) return;
205 Vector3d axisNormalized = axis / axisNorm;
207 Vector3d ortho1 = axisNormalized.cross(planeNormalVector);
208 double ortho1Norm = ortho1.norm();
209 if( ortho1Norm > 0.001 ) ortho1 /= ortho1Norm;
210 else ortho1 = axisNormalized.ortho();
211 ortho1 *= radius;
213 Vector3d ortho2 = cross( axisNormalized, ortho1 );
215 // construct the 4D transformation matrix
216 Matrix4d matrix;
218 matrix(0, 0) = ortho1(0);
219 matrix(1, 0) = ortho1(1);
220 matrix(2, 0) = ortho1(2);
221 matrix(3, 0) = 0.0;
223 matrix(0, 1) = ortho2(0);
224 matrix(1, 1) = ortho2(1);
225 matrix(2, 1) = ortho2(2);
226 matrix(3, 1) = 0.0;
228 matrix(0, 2) = axis(0);
229 matrix(1, 2) = axis(1);
230 matrix(2, 2) = axis(2);
231 matrix(3, 2) = 0.0;
233 matrix(0, 3) = end1(0);
234 matrix(1, 3) = end1(1);
235 matrix(2, 3) = end1(2);
236 matrix(3, 3) = 1.0;
238 //now we can do the actual drawing !
239 glPushMatrix();
240 glMultMatrixd( matrix.array() );
241 if( order == 1 )
242 glCallList( d->displayList );
243 else
245 double angleOffset = 0.0;
246 if( order >= 3 )
248 if( order == 3 ) angleOffset = 90.0;
249 else angleOffset = 22.5;
252 double displacementFactor = shift / radius;
253 for( int i = 0; i < order; i++)
255 glPushMatrix();
256 glRotated( angleOffset + 360.0 * i / order,
257 0.0, 0.0, 1.0 );
258 glTranslated( displacementFactor, 0.0, 0.0 );
259 glCallList( d->displayList );
260 glPopMatrix();
263 glPopMatrix();