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

kalzium

cylinder.cpp

Go to the documentation of this file.
00001 /**********************************************************************
00002   Cylinder - OpenGL Cylinder drawing class.
00003 
00004   Copyright (C) 2006,2007 Benoit Jacob
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 "cylinder.h"
00026 #include <QGLWidget>
00027 
00028 using namespace Eigen;
00029 
00030 namespace Avogadro {
00031 
00032   class CylinderPrivate {
00033     public:
00034       CylinderPrivate() : vertexBuffer(0), normalBuffer(0), displayList(0), isValid(false) {}
00035 
00037       Eigen::Vector3f *vertexBuffer;
00039       Eigen::Vector3f *normalBuffer;
00041       GLuint displayList;
00043       bool isValid;
00044 
00048       int faces;
00049   };
00050 
00051   Cylinder::Cylinder(int faces) : d(new CylinderPrivate)
00052   {
00053     setup(faces);
00054   }
00055 
00056   Cylinder::~Cylinder()
00057   {
00058     freeBuffers();
00059     if( d->displayList ) {
00060       glDeleteLists( d->displayList, 1 );
00061     }
00062     delete d;
00063   }
00064 
00065   void Cylinder::freeBuffers()
00066   {
00067     if( d->normalBuffer )
00068     {
00069       delete [] d->normalBuffer;
00070       d->normalBuffer = 0;
00071     }
00072     if( d->vertexBuffer )
00073     {
00074       delete [] d->vertexBuffer;
00075       d->vertexBuffer = 0;
00076     }
00077   }
00078 
00079   void Cylinder::setup( int faces )
00080   {
00081     if( d->isValid && faces == d->faces ) return;
00082     d->faces = faces;
00083     initialize();
00084   }
00085 
00086   void Cylinder::initialize()
00087   {
00088     d->isValid = false;
00089     if( d->faces < 0 ) return;
00090 
00091     // compile display list and free buffers
00092     if( ! d->displayList ) d->displayList = glGenLists( 1 );
00093     if( ! d->displayList ) return;
00094 
00095     if( d->faces < 3 )
00096     {
00097       glNewList( d->displayList, GL_COMPILE );
00098       glLineWidth(1.0);
00099       glBegin(GL_LINES);
00100       glVertex3f(0, 0, 0);
00101       glVertex3f(0, 0, 1);
00102       glEnd();
00103       glEndList();
00104     }
00105     else
00106     {
00107       // compute number of vertices
00108       int vertexCount = 2 * d->faces + 2;
00109 
00110       // deallocate any previously allocated buffer
00111       freeBuffers();
00112 
00113       // allocate memory for buffers
00114       d->vertexBuffer = new Vector3f[vertexCount];
00115       if( ! d->vertexBuffer ) return;
00116       d->normalBuffer = new Vector3f[vertexCount];
00117       if( ! d->normalBuffer ) return;
00118 
00119       float baseAngle = 2 * M_PI / d->faces;
00120       // build vertex and normal buffers
00121       for( int i = 0; i <= d->faces; i++ )
00122       {
00123         float angle = baseAngle * i;
00124         Vector3f v( cosf(angle), sinf(angle), 0.0f );
00125         d->normalBuffer[ 2 * i ] = v;
00126         d->normalBuffer[ 2 * i + 1 ] = v;
00127         d->vertexBuffer[ 2 * i ] = v;
00128         d->vertexBuffer[ 2 * i + 1 ] = v;
00129         d->vertexBuffer[ 2 * i ].z() = 1.0f;
00130       }
00131       glEnableClientState( GL_VERTEX_ARRAY );
00132       glEnableClientState( GL_NORMAL_ARRAY );
00133       glNewList( d->displayList, GL_COMPILE );
00134       glVertexPointer( 3, GL_FLOAT, 0, d->vertexBuffer );
00135       glNormalPointer( GL_FLOAT, 0, d->normalBuffer );
00136       glDrawArrays( GL_QUAD_STRIP, 0, vertexCount );
00137       glEndList();
00138       glDisableClientState( GL_VERTEX_ARRAY );
00139       glDisableClientState( GL_NORMAL_ARRAY );
00140     }
00141     freeBuffers();
00142     d->isValid = true;
00143   }
00144 
00145   void Cylinder::draw( const Vector3d &end1, const Vector3d &end2,
00146       double radius ) const
00147   {
00148     // the "axis vector" of the cylinder
00149     Vector3d axis = end2 - end1;
00150 
00151     // construct an orthogonal basis whose first vector is axis, and whose other vectors
00152     // have norm equal to 'radius'.
00153     Vector3d axisNormalized = axis.normalized();
00154     Vector3d ortho1, ortho2;
00155     ortho1.loadOrtho(axisNormalized);
00156     ortho1 *= radius;
00157     axisNormalized.cross( ortho1, &ortho2 );
00158 
00159     // construct the 4D transformation matrix
00160     Matrix4d matrix;
00161 
00162     matrix(0, 0) = ortho1(0);
00163     matrix(1, 0) = ortho1(1);
00164     matrix(2, 0) = ortho1(2);
00165     matrix(3, 0) = 0.0;
00166 
00167     matrix(0, 1) = ortho2(0);
00168     matrix(1, 1) = ortho2(1);
00169     matrix(2, 1) = ortho2(2);
00170     matrix(3, 1) = 0.0;
00171 
00172     matrix(0, 2) = axis(0);
00173     matrix(1, 2) = axis(1);
00174     matrix(2, 2) = axis(2);
00175     matrix(3, 2) = 0.0;
00176 
00177     matrix(0, 3) = end1(0);
00178     matrix(1, 3) = end1(1);
00179     matrix(2, 3) = end1(2);
00180     matrix(3, 3) = 1.0;
00181 
00182     //now we can do the actual drawing !
00183     glPushMatrix();
00184     glMultMatrixd( matrix.array() );
00185     glCallList( d->displayList );
00186     glPopMatrix();
00187   }
00188 
00189   void Cylinder::drawMulti( const Vector3d &end1, const Vector3d &end2,
00190       double radius, int order, double shift,
00191       const Vector3d &planeNormalVector ) const
00192   {
00193 
00194     // the "axis vector" of the cylinder
00195     Vector3d axis = end2 - end1;
00196 
00197     // now we want to construct an orthonormal basis whose first
00198     // vector is axis.normalized(). We don't use Eigen's loadOrthoBasis()
00199     // for that, because we want one more thing. The second vector in this
00200     // basis, which we call ortho1, should be approximately lying in the
00201     // z=0 plane if possible. This is to ensure double bonds don't look
00202     // like single bonds from the default point of view.
00203     double axisNorm = axis.norm();
00204     if( axisNorm == 0.0 ) return;
00205     Vector3d axisNormalized = axis / axisNorm;
00206 
00207     Vector3d ortho1 = axisNormalized.cross(planeNormalVector);
00208     double ortho1Norm = ortho1.norm();
00209     if( ortho1Norm > 0.001 ) ortho1 /= ortho1Norm;
00210     else ortho1 = axisNormalized.ortho();
00211     ortho1 *= radius;
00212 
00213     Vector3d ortho2 = cross( axisNormalized, ortho1 );
00214 
00215     // construct the 4D transformation matrix
00216     Matrix4d matrix;
00217 
00218     matrix(0, 0) = ortho1(0);
00219     matrix(1, 0) = ortho1(1);
00220     matrix(2, 0) = ortho1(2);
00221     matrix(3, 0) = 0.0;
00222 
00223     matrix(0, 1) = ortho2(0);
00224     matrix(1, 1) = ortho2(1);
00225     matrix(2, 1) = ortho2(2);
00226     matrix(3, 1) = 0.0;
00227 
00228     matrix(0, 2) = axis(0);
00229     matrix(1, 2) = axis(1);
00230     matrix(2, 2) = axis(2);
00231     matrix(3, 2) = 0.0;
00232 
00233     matrix(0, 3) = end1(0);
00234     matrix(1, 3) = end1(1);
00235     matrix(2, 3) = end1(2);
00236     matrix(3, 3) = 1.0;
00237 
00238     //now we can do the actual drawing !
00239     glPushMatrix();
00240     glMultMatrixd( matrix.array() );
00241     if( order == 1 )
00242       glCallList( d->displayList );
00243     else
00244     {
00245       double angleOffset = 0.0;
00246       if( order >= 3 )
00247       {
00248         if( order == 3 ) angleOffset = 90.0;
00249         else angleOffset = 22.5;
00250       }
00251 
00252       double displacementFactor = shift / radius;
00253       for( int i = 0; i < order; i++)
00254       {
00255         glPushMatrix();
00256         glRotated( angleOffset + 360.0 * i / order,
00257             0.0, 0.0, 1.0 );
00258         glTranslated( displacementFactor, 0.0, 0.0 );
00259         glCallList( d->displayList );
00260         glPopMatrix();
00261       }
00262     }
00263     glPopMatrix();
00264   }
00265 
00266 }

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
  •   lib
  • klettres
  • kstars
  • libkdeedu
  •   keduvocdocument
  •   docs
  •   src
  • parley
  •   stepcore
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