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

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