/*******************************************************************************
*                                                                              *
*                                   Viewmol                                    *
*                                                                              *
*                             C Y L I N D E R . C                              *
*                                                                              *
*                 Copyright (c) Joerg-R. Hill, October 2003                    *
*                                                                              *
********************************************************************************
*
* $Id: cylinder.c,v 1.6 2003/11/07 10:59:10 jrh Exp $
* $Log: cylinder.c,v $
* Revision 1.6  2003/11/07 10:59:10  jrh
* Release 2.4
*
* Revision 1.5  2000/12/10 15:03:46  jrh
* Release 2.3
*
* Revision 1.4  1999/05/24 01:25:02  jrh
* Release 2.2.1
*
* Revision 1.3  1999/02/07 21:46:18  jrh
* Release 2.2
*
* Revision 1.2  1998/01/26 00:47:17  jrh
* Release 2.1
*
* Revision 1.1  1996/12/10  18:40:09  jrh
* Initial revision
*
*/
#include<math.h>
#include<GL/gl.h>
#include<GL/glu.h>

extern void (*drawCylinder)(GLUquadricObj *, GLdouble, GLdouble, GLdouble, GLint, GLint);
extern void (*drawCone)(GLUquadricObj *, GLdouble, GLdouble, GLdouble, GLint, GLint);

GLdouble buildRotationMatrix(double x, double y, double z, GLdouble tmat[4][4])
{
  double height, d, ca, sa, cb, sb;

  height=sqrt((double)(x*x + y*y + z*z));

  /* Builds the rotation matrix for rotating a vector defined by
     the points (0, 0, 0) and (0, 0, height) to the orientation
     (x, y, z) */

  if ((d=sqrt((double)(x*x + y*y))) != 0.0)
  {
    ca=y/d;
    sa=x/d;
    y=x*sa+y*ca;
  }
  else
  {
    ca=1.0;
    sa=0.0;
  }
  if ((d=sqrt((double)(y*y + z*z))) != 0.0)
  {
    cb=z/d;
    sb=y/d;
  }
  else
  {
    cb=1.0;
    sb=0.0;
  }
  tmat[0][0]=ca;
  tmat[1][0]=sa*cb;
  tmat[2][0]=sa*sb;
  tmat[3][0]=0.0e0;
  tmat[0][1]=(-sa);
  tmat[1][1]=ca*cb;
  tmat[2][1]=ca*sb;
  tmat[3][1]=0.0e0;
  tmat[0][2]=0.;
  tmat[1][2]=(-sb);
  tmat[2][2]=cb;
  tmat[3][2]=0.0e0;
  tmat[0][3]=tmat[1][3]=tmat[2][3]=0.0e0;
  tmat[3][3]=1.0e0; 

  return(height);
}

void cylinder(double x1, double y1, double z1, double x2, double y2, double z2,
              double r, int n, GLenum mode)
{
  GLUquadricObj *obj;
  double vx=x2-x1, vy=y2-y1, vz=z2-z1;
  GLdouble tmat[4][4], height;

  height=buildRotationMatrix(vx, vy, vz, tmat);
  tmat[3][0]=x1;
  tmat[3][1]=y1;
  tmat[3][2]=z1;

  /* Select drawing function depending on mode */

  obj=gluNewQuadric();
  gluQuadricDrawStyle(obj, mode);
  gluQuadricTexture(obj, GL_TRUE);
  if (mode == GLU_FILL) gluQuadricNormals(obj, (GLenum)GLU_SMOOTH);
  else                  gluQuadricNormals(obj, (GLenum)GLU_NONE);

  glPushMatrix();
  glMultMatrixd((GLdouble *)tmat);
  (*drawCylinder)(obj, r, r, height, n, 1);
  glPopMatrix();
}

void cone(double x1, double y1, double z1, double x2, double y2, double z2,
          double rBase, int n)
{
  GLUquadricObj *obj;
  double vx=x2-x1, vy=y2-y1, vz=z2-z1;
  GLdouble tmat[4][4], height;

  height=buildRotationMatrix(vx, vy, vz, tmat);
  tmat[3][0]=x1;
  tmat[3][1]=y1;
  tmat[3][2]=z1;

  obj=gluNewQuadric();
  gluQuadricDrawStyle(obj, (GLenum)GLU_FILL);
  gluQuadricNormals(obj, (GLenum)GLU_SMOOTH);

  glPushMatrix();
  glMultMatrixd((GLdouble *)tmat);
  (*drawCone)(obj, rBase, 0.0e0, height, n, 1);
  glPopMatrix();
}
