/**************************************************************************
  
  quaternion.h

  A quaternion class

  ---------------------------------------------------------------------

  Feb 1998, Paul Rademacher (rademach@cs.unc.edu)  
                
**************************************************************************/

#ifndef _QUATERNION_H_
#define _QUATERNION_H_

#include "algebra3.h"
#include <stdio.h>
#include <stdlib.h>


/* this line defines a new type: pointer to a function which returns a */
/* float and takes as argument a float */
typedef float (*V_FCT_PTR)(float);


/****************************************************************
*                    Quaternion                                 *
****************************************************************/

class quat
{
  /*protected: */
public:

  vec3  v;  /* vector component */
  float s;  /* scalar component */

  /*public: */
  
  /* Constructors */

  quat(void);
  quat(const float x, const float y, const float z, const float w);
  quat( vec3 v, float s ); 
  quat( float s, vec3 v );
  quat(const float *d );      /* copy from four-element float array */
  quat(const double *f );     /* copy from four-element double array */
  quat(const quat &q );        /* copy from other quat */

  /* Assignment operators */

  quat &operator  = ( const quat &v );      /* assignment of a quat */
  quat &operator += ( const quat &v );      /* incrementation by a quat */
  quat &operator -= ( const quat &v );      /* decrementation by a quat */
  quat &operator *= ( const float d );      /* multiplication by a constant */
  quat &operator /= ( const float d );      /* division by a constant */
  float &operator [] ( int i);              /* indexing */
  
  /* special functions */
  
  float length(void);                    /* length of a quat */
  float length2(void);                   /* squared length of a quat */
  quat &normalize(void);                 /* normalize a quat */
  quat &apply(V_FCT_PTR fct);            /* apply a func. to each component */
  void  set( float x, float y, float z );   /* set quat */
  void  set( vec3 v, float s );             /* set quat */
  void  print( FILE *file, char *name );    /* print quat to a file */
  vec3  xform( const vec3 &v );             /* q*v*q-1 */
  mat4  to_mat4( void );
  void  set_angle( float f );               /* set rot angle (degrees) */
  void  scale_angle( float f );             /* scale rot angle (degrees) */
  float get_angle( void );                  /* set rot angle (degrees) */
  vec3  get_axis( void );                   /* get axis */

  /* friends */

  friend quat operator - (const quat &v);                   /* -q1 */
  friend quat operator + (const quat &a, const quat &b);    /* q1 + q2 */
  friend quat operator - (const quat &a, const quat &b);    /* q1 - q2 */
  friend quat operator * (const quat &a, const float d);    /* q1 * 3.0 */
  friend quat operator * (const float d, const quat &a);    /* 3.0 * q1 */
  friend quat operator * (const quat &a, const quat &b);    /* q1 * q2 */
  friend quat operator / (const quat &a, const float d);    /* q1 / 3.0 */
  friend int operator == (const quat &a, const quat &b);    /* q1 == q2 ? */
  friend int operator != (const quat &a, const quat &b);    /* q1 != q2 ? */
  friend void swap(quat &a, quat &b);                       /* swap q1  &q2 */
  /*friend quat min(const quat &a, const quat &b);          -- min(q1, q2) */
  /*friend quat max(const quat &a, const quat &b);          -- max(q1, q2) */
  friend quat prod(const quat &a, const quat &b);      /* term by term mult */
                                }; 

/* Utility functions */

quat quat_identity( void );        /* Returns quaternion identity element */
quat quat_slerp( quat from, quat to, float t );

#endif
