// -*- Mode: c++ -*-
// $Id: float4.H,v 1.3 1998/02/11 03:46:44 neel Exp $
// $Source: /u2/graphics/projects/6.838/gvis/gprims/float4.H,v $

#ifndef	__FLOAT4_H__
#define	__FLOAT4_H__

static char 
__rcs_ref_float4_h( void )
{
  static char rcs_id_h[] = "$Header: /u2/graphics/projects/6.838/gvis/gprims/float4.H,v 1.3 1998/02/11 03:46:44 neel Exp $";
  return rcs_id_h[0];
}

// Do not change anything above this line
static char avoid_stupid_compiler_warnings22 = __rcs_ref_float4_h();

#include <assert.h>
#include "utils.H"

class Float3;
typedef Float3 Point3;
typedef Float3 Vector3;

class ostream;
class istream;


// A general 4vector class.
class Float4 {
  
  // constructors / destructor
public:
  
  Float4                 ( void ) {} 
  inline Float4          ( const float a, const float b, 
			   const float c, const float d )
                         { v[X] = a, v[Y] = b, v[Z] = c, v[W] = d; }
  inline Float4          ( const Float4& c );
  inline Float4          ( const float* a );
  inline Float4          ( const double* a );
  // construct plane from base point, normal
  inline Float4          ( const Point3 &base, Vector3 norm );
  // construct plane from a normal and a point
  inline Float4          ( const Point3 &pt, float s );
  // construct plane from two points a,b ( vec = a-b ) 
  inline Float4          ( const Point3 &, const Point3 & );

      
  ~Float4                ( void ) {}
  
  
  // operator declarations/definitions
public:
  operator float*             ( void )                { return &v[X]; }
  operator const float*       ( void ) const          { return &v[X]; }
  
  friend istream& operator>>  ( istream&, Float4& );
  friend ostream& operator<<  ( ostream&, const Float4& );
  void            print       ( ostream& os ) const;
  
  Float4&         operator=   ( const Float4& c )
  { v[X] = c.v[X], v[Y] = c.v[Y], v[Z] = c.v[Z], v[W] = c.v[W]; return *this; }
  
  Float4          operator+   ( const Float4& c ) const
  { return Float4( v[X]+c.v[X], v[Y]+c.v[Y], v[Z]+c.v[Z], v[W]+c.v[W] ); }
  
  Float4          operator-   ( const Float4& c ) const
  { return Float4( v[X]-c.v[X], v[Y]-c.v[Y], v[Z]-c.v[Z], v[W]-c.v[W] ); }
  
  Float4          operator*   ( const float s ) const
  { return Float4( s * v[X], s * v[Y], s * v[Z], s * v[W] ); }
  
  friend Float4   operator*   ( const float s, const Float4& c )
  { return Float4( s * c.v[X], s * c.v[Y], s * c.v[Z], s * c.v[W] ); }
  
  Float4          operator/   ( const float s ) const
  { return Float4( v[X] / s, v[Y] / s, v[Z] / s, v[W] / s ); }
  
  Float4&         operator+=  ( const Float4& c )
  { v[X] += c.v[X], v[Y] += c.v[Y], v[Z] += c.v[Z], v[W] += c.v[W];
  return *this; }
  
  Float4&         operator-=  ( const Float4& c )
  { v[X] -= c.v[X], v[Y] -= c.v[Y], v[Z] -= c.v[Z], v[W] -= c.v[W];
  return *this; }
  
  Float4&         operator*=  ( const float s )
  { v[X] *= s, v[Y] *= s, v[Z] *= s, v[W] *= s; return *this; }
  
  Float4&         operator/=  ( const float s )
  { v[X] /= s, v[Y] /= s, v[Z] /= s, v[W] /= s; return *this; }
  
  Float4          operator-   ( void ) const
  { return Float4( -v[X], -v[Y], -v[Z], -v[W] ); }
  
  int             operator==  ( const Float4& o ) const
  { return ZERO( v[X] - o.v[X] ) && ZERO( v[Y] - o.v[Y] )
      && ZERO( v[Z] - o.v[Z] ) && ZERO( v[W] - o.v[W] ); }
  
  int             operator!=  ( const Float4& o ) const
  { return !ZERO( v[X] - o.v[X] ) || !ZERO( v[Y] - o.v[Y] )
      || !ZERO( v[Z] - o.v[Z] ) || !ZERO( v[W] - o.v[W] ); }
  
  
  // accessors
public:  
  // homogenous pt. accessors
  float&          x          ( void )         { return v[X]; }
  float           x          ( void ) const   { return v[X]; }
  float&          y          ( void )         { return v[Y]; }
  float           y          ( void ) const   { return v[Y]; }
  float&          z          ( void )         { return v[Z]; }
  float           z          ( void ) const   { return v[Z]; }
  float&          w          ( void )         { return v[W]; }
  float           w          ( void ) const   { return v[W]; }
  
  // color accessors
  float&          r          ( void )         { return v[0]; }
  float           r          ( void ) const   { return v[0]; }
  float&          g          ( void )         { return v[1]; }
  float           g          ( void ) const   { return v[1]; }
  float&          b          ( void )         { return v[2]; }
  float           b          ( void ) const   { return v[2]; }
  float&          a          ( void )         { return v[3]; }
  float           a          ( void ) const   { return v[3]; }

  // plane eqn. accessors
  float&          A          ( void )         { return v[X]; }
  float           A          ( void ) const   { return v[X]; }
  float&          B          ( void )         { return v[Y]; }
  float           B          ( void ) const   { return v[Y]; }
  float&          C          ( void )         { return v[Z]; }
  float           C          ( void ) const   { return v[Z]; }
  float&          D          ( void )         { return v[W]; }
  float           D          ( void ) const   { return v[W]; }
  
  
  // numerical / geometric routines
public:
  // dots with input
  float           dot        ( const Float4& c )    const
  { return v[X] * c.v[X] + v[Y] * c.v[Y] + v[Z] * c.v[Z] + v[W] * c.v[W]; }
  
  // dots against itself
  float           dot        ( void ) const
  { return v[X] * v[X] + v[Y] * v[Y] + v[Z] * v[Z] + v[W] * v[W]; }
  
  float           sum        ( void ) const
  { return v[X] + v[Y] + v[Z] + v[W]; }

  // dots with plane normal
  inline float    dot        ( const Float3& f ) const;
  
  // length 
  float           length     ( void ) const
  { return sqrtf( dot() ); }  
  
  // distance from 3D input vector
  inline float       dist       ( const Float3& f ) const;
  
  // distance from 4D input vector
  float           dist       ( const Float4& c ) const 
  { return ( *this - c ).length(); }
  
  // return normal (i.e., plane gradient vector)
  inline Float3*     normal          ( void );
  
  // modify vector to become unit length
  inline int         normalize       ( void );
  
  // raise each element of the vector to a power
  void               power           ( double pow );
  
private:
  float	v[4];
};


// cartesian 4D point
typedef Float4 Point4;

// homogenous 3D point
typedef Float4 Point3H;

// 4-vector 
typedef Float4 Vector4;

// 3D plane
typedef Float4 Plane3;

// ( R, G, B, alpha ) color
typedef	Float4 Color4;

// quaternion 
typedef	Float4 Quaternion;


#endif	/* __FLOAT4_H__ */




