00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
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
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
00108 int vertexCount = 2 * d->faces + 2;
00109
00110
00111 freeBuffers();
00112
00113
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
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
00149 Vector3d axis = end2 - end1;
00150
00151
00152
00153 Vector3d axisNormalized = axis.normalized();
00154 Vector3d ortho1, ortho2;
00155 ortho1.loadOrtho(axisNormalized);
00156 ortho1 *= radius;
00157 axisNormalized.cross( ortho1, &ortho2 );
00158
00159
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
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
00195 Vector3d axis = end2 - end1;
00196
00197
00198
00199
00200
00201
00202
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
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
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 }