#ifndef D2HOMOGENEOUS_H
#define D2HOMOGENEOUS_H


#include <point.h>

#include <print.h>


class d2homogeneous;

/*!
\brief Implementing the homogeneous coorinate system in 2D.

  The homogeneous coordinate system combines transforms and shifting.
  These operations are turned into multiplying 3 by 3 matricies.
  Since matrix multiplication is associative the client applies
  successive transformations by multiplying the current transform.

  To apply the transform to a point simply multiply the transform
  with the point.

  point3<double> is a homogeneous point with 1 in the z component.
  point2<double> is often what the client wants so interfaces
  support both types of points.  

  I have used non const references as both input and output.  
  When a reference is used for both input and output it will be 
  documented.  eg p = M*p in the matrixMultiply method.

*/
class d2homogeneous
{
public:

  /** The state. */
  double matrix[9];

  /** Constructor sets the matrix to identity. */
  d2homogeneous();

  /** Interpret matrix_ as three rows of points. */
  d2homogeneous( doublec * matrix_);

  /** p2 = M*p the transformed point of p. */
  void matrixMultiply
  ( 
    point3<double> & p2,
    point3<double> const & p
  ) const;

  /** p2 = M*p the transformed point of p. */
  void matrixMultiply
  ( 
    point2<double> & p2,
    point2<double> const & p
  ) const;

  /** p = M*p the transformed point of p. */
  void matrixMultiply( point2<double> & p ) const;


  /** Clear the current state and make it a translation. */
  void setTranslate(point2<double> const & p);

  /** Clear the current state and make it a rotation. */
  void setRotate(doublec theta);

  /** The diagonals in the matix are set to 0. */
  void setIdentity();
  /** All matrix elements except the last are set to 0, 
      the last 1. */
  void setZero();

  /** Generalized rotation by rotating about some point p. */
  void setRotateAboutPoint
  (
    doublec theta, 
    point2<double> const & p
  );

  /** Apply successive transformations through matrix 
      multiplication. */
  d2homogeneous & operator *= (d2homogeneous const & w);

  /** Extract the k'th row. */
  void rowk(point3<double> & x, uintc k) const
    { uintc w=3*k; x.x=matrix[0+w]; x.y=matrix[1+w]; 
      x.z=matrix[2+w]; }

  /** Extract the k'th column. */
  void columnk(point3<double> & x, uintc k) const
    { x.x=matrix[0+k]; x.y=matrix[3+k]; x.z=matrix[6+k]; }

  /** Display the matrix state. */
  operator string() const;
};

/** The left most operand contains the result.  The client
  is responsible for memory and correct use! */
d2homogeneous & operator * 
(
  d2homogeneous & a, 
  d2homogeneous const & b
);




#endif



