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
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
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
00107 int vertexCount = 2 * d->faces + 2;
00108
00109
00110 freeBuffers();
00111
00112
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
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
00148 Vector3d axis = end2 - end1;
00149
00150
00151
00152 Vector3d axisNormalized = axis / axis.norm();
00153 Vector3d ortho1, ortho2;
00154 ortho1.loadOrtho(axisNormalized);
00155 ortho1 *= radius;
00156 axisNormalized.cross( ortho1, &ortho2 );
00157
00158
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
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
00194 Vector3d axis = end2 - end1;
00195
00196
00197
00198
00199
00200
00201
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
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
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 }