/***************************************************************************************
*****                        CLASS FRAME IMPLEMENTATION                            *****
****************************************************************************************
** Author: Peter Stuart
** Date:   3/7/98
** Description: This class represents a coordinate frame. The frame is made up of three
**   orthogonal vectors u, v, w, and origin point o. Methods include finding the 
**   matrix to trasform coordinates from frame space to cartesian space, changing
**   orientation and position in both frame and cartesian coordinates, and the 
**   standard relational, assignment, and output stream methods.
**
** Note: All of these graphics classes use a right-handed coordinate system.
**
***************************************************************************************/

#include "Frame.hpp"

/* Constructor ************
** Default values for private variables:
** _u: <1.0, 0.0, 0.0>
** _v: <0.0, 1.0, 0.0>
** _w: <0.0, 0.0, 1.0>
** _o: <0.0, 0.0, 0.0>
*/

Frame::Frame (const Vector& u, const Vector& v, const Vector& w, const Point& o)
{
   _u = u;
   _v = v;
   _w = w;
   _o = o;
}

// Copy Constructor
Frame::Frame (const Frame& fr)
{
   _u = fr._u;
   _v = fr._v;
   _w = fr._w;
   _o = fr._o;
}
	
// Destructor
Frame::~Frame (void)
{
   ;
}

// BASIC OPERATIONS ///////////////

// Transform Frame using matrix
// NOTE: Since the frame's origin is a separate variable, it is necessary to 
//   break the matrix into its rotation and translation parts. The rotation
//   part is then used on the vectors of the frame, and the translation
//   part is used on the frame's position. It was done this way so that
//   the vectors of the frame would stay unit vectors.

void Frame::transformFrame (const Matrix4D& mat)
{
   Matrix4D rot, move;
   Point opt;

   rot = mat;
   rot.setElement(3, 0, 0.0);
   rot.setElement(3, 1, 0.0);
   rot.setElement(3, 2, 0.0);

   move = move.identity();
   move.setElement(3, 0, mat.getElement(3, 0));
   move.setElement(3, 1, mat.getElement(3, 1));
   move.setElement(3, 2, mat.getElement(3, 2));

   _o = _o*move;
   _u = (_u*rot).direction();
   _v = (_v*rot).direction();
   _w = (_w*rot).direction();
}

// Translate frame with respect to its own coordinate system
void     Frame::translateFrame (const double& x, const double& y, const double& z)
{
   Matrix4D move, trans;
   trans.setElement(0, 0, _u.x());
   trans.setElement(0, 1, _v.x());
   trans.setElement(0, 2, _w.x());
   trans.setElement(1, 0, _u.y());
   trans.setElement(1, 1, _v.y());
   trans.setElement(1, 2, _w.y());
   trans.setElement(2, 0, _u.z());
   trans.setElement(2, 1, _v.z());
   trans.setElement(2, 2, _w.z());
   trans.setElement(3, 3, 1.0);

   move = translate(x, y, z);
   move = trans*move*trans.inverse();
   _o = _o*move;
}

// rotate frame with respect to its own coordinate system
void Frame::rotateFrame (const double& x, const double& y, const double& z)
{
   Matrix4D trans, rot;
   trans.setElement(0, 0, _u.x());
   trans.setElement(0, 1, _v.x());
   trans.setElement(0, 2, _w.x());
   trans.setElement(1, 0, _u.y());
   trans.setElement(1, 1, _v.y());
   trans.setElement(1, 2, _w.y());
   trans.setElement(2, 0, _u.z());
   trans.setElement(2, 1, _v.z());
   trans.setElement(2, 2, _w.z());
   trans.setElement(3, 3, 1.0);

   rot = rotate(x, y, z);
   rot = trans*rot*trans.inverse();

   _u = (_u*rot).direction();
   _v = (_v*rot).direction();
   _w = (_w*rot).direction();
}

// Create frame to cartesian frame coordinate transformation matrix
Matrix4D Frame::frameTransform(void)
{
   Matrix4D temp;  // returning matrix

   // set matrix to transform coordinates to the cartesian frame
   temp.setElement(0, 0, _u.x());
   temp.setElement(0, 1, _v.x());
   temp.setElement(0, 2, _w.x());
   temp.setElement(1, 0, _u.y());
   temp.setElement(1, 1, _v.y());
   temp.setElement(1, 2, _w.y());
   temp.setElement(2, 0, _u.z());
   temp.setElement(2, 1, _v.z());
   temp.setElement(2, 2, _w.z());
   temp.setElement(3, 0, _o.x());
   temp.setElement(3, 1, _o.y());
   temp.setElement(3, 2, _o.z());
   temp.setElement(3, 3, 1.0);

   return temp;
}

// Create cartesian frame to frame coordinate transformation matrix
Matrix4D Frame::cartTransform(void)
{
   Matrix4D temp;   // returning matrix
   Vector   j;      // vector from origin to frame position

   j = zeroPoint - _o;

   temp.setElement(0, 0, _u.x());
   temp.setElement(0, 1, _v.x());
   temp.setElement(0, 2, _w.x());
   temp.setElement(1, 0, _u.y());
   temp.setElement(1, 1, _v.y());
   temp.setElement(1, 2, _w.y());
   temp.setElement(2, 0, _u.z());
   temp.setElement(2, 1, _v.z());
   temp.setElement(2, 2, _w.z());
   temp.setElement(3, 0, _u.dot(j));
   temp.setElement(3, 1, _v.dot(j));
   temp.setElement(3, 2, _w.dot(j));
   temp.setElement(3, 3, 1.0);

   return temp;
}

// ELEMENTARY OPEARTORS //////////////////////////

// Assignment operator
Frame&   Frame::operator =  (const Frame& fr)
{
   if (this == &fr)
      return (*this);

   _u = fr._u;
   _v = fr._v;
   _w = fr._w;
   _o = fr._o;

   return (*this);
}

// Relational operators
int operator == (const Frame& fr1, const Frame& fr2)
{
   if (fr1._u != fr2._u)
      return FALSE;
   if (fr1._v != fr2._v)
      return FALSE;
   if (fr1._w != fr2._w)
      return FALSE;
   if (fr1._o != fr2._o)
      return FALSE;

   return TRUE;
}

int operator != (const Frame& fr1, const Frame& fr2)
{
   if (fr1._u != fr2._u)
      return TRUE;
   if (fr1._v != fr2._v)
      return TRUE;
   if (fr1._w != fr2._w)
      return TRUE;
   if (fr1._o != fr2._o)
      return TRUE;

   return FALSE;
}

// output stream
ostream& operator << (ostream& co, const Frame& fr)
{
   co << "\nu: " << fr._u
      << "\nv: " << fr._v
      << "\nw: " << fr._w
      << "\no: " << fr._o;

   return co;
}

    Source: geocities.com/collegepark/4206

               ( geocities.com/collegepark)