// $Source: /local/data/cvs/yellowbank/tile/qtransform.cc,v $
// $Revision: 1.2 $
// $State: Exp $
// $Date: 2004/07/19 03:54:07 $
// $Author: yrp001 $
// $Locker:  $

#include "qtransform.h"

qtransform::
qtransform() {
  reset();
}

qtransform::
qtransform( const qtransform& other ) {
  for( int y = 0; y < 3; y++ )
    for( int x = 0; x < 3; x++ )
      _tm[x][y] = other._tm[x][y];
}

qtransform::
qtransform( double* tm ) {
  for( int y = 0; y < 3; y++ )
    for( int x = 0; x < 3; x++ )
      _tm[x][y] = tm[ (y*3)+x ];
}

void
qtransform::
reset() {
  // create identity matrix
  _tm[0][0] = 1.0;
  _tm[1][0] = 0.0;
  _tm[2][0] = 0.0;
  _tm[0][1] = 0.0;
  _tm[1][1] = 1.0;
  _tm[2][1] = 0.0;
  _tm[0][2] = 0.0;
  _tm[1][2] = 0.0;
  _tm[2][2] = 1.0;
}

void
qtransform::
translate( const qpoint& p ) {
  translate( p.getx(), p.gety() );
}

void
qtransform::
translate( double tx, double ty ) {

  double ct[3][3]; // current transformation matrix
  for( int y = 0; y < 3; y++ )
    for( int x = 0; x < 3; x++ )
      ct[x][y] = _tm[x][y];

  double t[3][3]; // translation matrix
  t[0][0] = 1.0;
  t[1][0] = 0.0;
  t[2][0] = tx;
  t[0][1] = 0.0;
  t[1][1] = 1.0;
  t[2][1] = ty;
  t[0][2] = 0.0;
  t[1][2] = 0.0;
  t[2][2] = 1.0;

  for( int rl = 0; rl < 3; rl++ ) // row left
    for( int cr = 0; cr < 3; cr++ ) // column right
      _tm[cr][rl] = 
	t[0][rl] * ct[cr][0] +
	t[1][rl] * ct[cr][1] +
	t[2][rl] * ct[cr][2];
}

void
qtransform::
scale( double sx, double sy ) {

  double ct[3][3]; // current transformation matrix
  for( int y = 0; y < 3; y++ )
    for( int x = 0; x < 3; x++ )
      ct[x][y] = _tm[x][y];

  double s[3][3]; // scale matrix
  s[0][0] = sx;
  s[1][0] = 0;
  s[2][0] = 0;
  s[0][1] = 0;
  s[1][1] = sy;
  s[2][1] = 0;
  s[0][2] = 0;
  s[1][2] = 0;
  s[2][2] = 1;

  for( int rl = 0; rl < 3; rl++ ) // row left
    for( int cr = 0; cr < 3; cr++ ) // column right
      _tm[cr][rl] = 
	s[0][rl] * ct[cr][0] +
	s[1][rl] * ct[cr][1] +
	s[2][rl] * ct[cr][2];
}

void
qtransform::
rotate( double angrad ) {

  double ct[3][3]; // current transformation matrix
  for( int y = 0; y < 3; y++ )
    for( int x = 0; x < 3; x++ )
      ct[x][y] = _tm[x][y];

  double ca = cos( angrad );
  double sa = sin( angrad );

  double r[3][3];
  r[0][0] = ca;
  r[1][0] = -sa;
  r[2][0] = 0;
  r[0][1] = sa;
  r[1][1] = ca;
  r[2][1] = 0;
  r[0][2] = 0;
  r[1][2] = 0;
  r[2][2] = 1;

  for( int rl = 0; rl < 3; rl++ ) // row left
    for( int cr = 0; cr < 3; cr++ ) // column right
      _tm[cr][rl] = 
	r[0][rl] * ct[cr][0] +
	r[1][rl] * ct[cr][1] +
	r[2][rl] * ct[cr][2];
}

void
qtransform::
rotate( const qpoint& pt, double angrad ) {
  translate( -pt.getx(), -pt.gety() );
  rotate( angrad );
  translate( pt.getx(), pt.gety() );
}

void
qtransform::
rotate( double x, double y, double angrad ) {
  translate( -x, -y );
  rotate( angrad );
  translate( x, y );
}

void
qtransform::
mirrorx() {

  double ct[3][3]; // current transformation matrix
  for( int y = 0; y < 3; y++ )
    for( int x = 0; x < 3; x++ )
      ct[x][y] = _tm[x][y];

  double m[3][3];
  m[0][0] = 1;
  m[1][0] = 0;
  m[2][0] = 0;
  m[0][1] = 0;
  m[1][1] = -1;
  m[2][1] = 0;
  m[0][2] = 0;
  m[1][2] = 0;
  m[2][2] = 1;

  for( int rl = 0; rl < 3; rl++ ) // row left
    for( int cr = 0; cr < 3; cr++ ) // column right
      _tm[cr][rl] = 
	m[0][rl] * ct[cr][0] +
	m[1][rl] * ct[cr][1] +
	m[2][rl] * ct[cr][2];
}

void
qtransform::
mirror( double angrad ) {
  rotate( -angrad );
  mirrorx();
  rotate( angrad );
}

void
qtransform::
mirror( const qpoint& pt, double angrad ) {
  translate( -pt.getx(), -pt.gety() );
  rotate( -angrad );
  mirrorx();
  rotate( angrad );
  translate( pt.getx(), pt.gety() );
}

void
qtransform::
mirror( double x, double y, double angrad ) {
  translate( -x, -y );
  rotate( -angrad );
  mirrorx();
  rotate( angrad );
  translate( x, y );
}

void
qtransform::
mirror( const qpoint& p1, const qpoint& p2 ) {
  qpoint p = p2 - p1;
  mirror( p1, p.anglef() );
}

void
qtransform::
mirror( const qedge& e ) {
  mirror( e.apoint(), e.anglef() );
}

void
qtransform::
skewx( double skx ) {

  double ct[3][3]; // current transformation matrix
  for( int y = 0; y < 3; y++ )
    for( int x = 0; x < 3; x++ )
      ct[x][y] = _tm[x][y];

  double sx[3][3];
  sx[0][0] = 1;
  sx[1][0] = tan( skx );
  sx[2][0] = 0;
  sx[0][1] = 0;
  sx[1][1] = 1;
  sx[2][1] = 0;
  sx[0][2] = 0;
  sx[1][2] = 0;
  sx[2][2] = 1;

  for( int rl = 0; rl < 3; rl++ ) // row left
    for( int cr = 0; cr < 3; cr++ ) // column right
      _tm[cr][rl] = 
	//	ct[0][rl] * sx[cr][0] +
	//	ct[1][rl] * sx[cr][1] +
	//	ct[2][rl] * sx[cr][2];
	sx[0][rl] * ct[cr][0] +
	sx[1][rl] * ct[cr][1] +
	sx[2][rl] * ct[cr][2];
}

void
qtransform::
skewy( double sky ) {

  double ct[3][3]; // current transformation matrix
  for( int y = 0; y < 3; y++ )
    for( int x = 0; x < 3; x++ )
      ct[x][y] = _tm[x][y];

  double sy[3][3];
  sy[0][0] = 1;
  sy[1][0] = 0;
  sy[2][0] = 0;
  sy[0][1] = tan( sky );
  sy[1][1] = 1;
  sy[2][1] = 0;
  sy[0][2] = 0;
  sy[1][2] = 0;
  sy[2][2] = 1;

  for( int rl = 0; rl < 3; rl++ ) // row left
    for( int cr = 0; cr < 3; cr++ ) // column right
      _tm[cr][rl] = 
	//	ct[0][rl] * sy[cr][0] +
	//	ct[1][rl] * sy[cr][1] +
	//	ct[2][rl] * sy[cr][2];
	sy[0][rl] * ct[cr][0] +
	sy[1][rl] * ct[cr][1] +
	sy[2][rl] * ct[cr][2];
}

int
qtransform::
operator==( const qtransform& rhs ) const {
  for( int y = 0; y < 3; y++ )
    for( int x = 0; x < 3; x++ )
      if( _tm[x][y] != rhs._tm[x][y] )
	return 0;
  return 1;
}

qtransform&
qtransform::
operator=( const qtransform& rhs ) {
  if( &rhs == this )
    return *this;
  for( int y = 0; y < 3; y++ )
    for( int x = 0; x < 3; x++ )
      _tm[x][y] = rhs._tm[x][y];
  return *this;
}

qtransform
qtransform::
operator*( const qtransform& rhs ) const {
  double tm[9];
  for( int rl = 0; rl < 3; rl++ ) // row left
    for( int cr = 0; cr < 3; cr++ ) { // column right
      tm[ (rl*3)+cr ] = 
	rhs._tm[0][rl] * _tm[cr][0] +
	rhs._tm[1][rl] * _tm[cr][1] +
	rhs._tm[2][rl] * _tm[cr][2];
    }
  return qtransform( tm );
}

qpoint
qtransform::
operator*( const qpoint& rhs ) const {
  double x, y;
  x = (_tm[0][0] * rhs.getx()) + (_tm[1][0] * rhs.gety()) + (_tm[2][0] * 1.0);
  y = (_tm[0][1] * rhs.getx()) + (_tm[1][1] * rhs.gety()) + (_tm[2][1] * 1.0);
  return qpoint( x, y );
}

std::ostream&
operator<<( std::ostream& os, qtransform& t ) {
  for( int y = 0; y < 3; y++ )
    for( int x = 0; x < 3; x++ )
      os << t._tm[x][y] << " ";
  return os;
}

std::istream&
operator>>( std::istream& is, qtransform& t ) {
  for( int y = 0; y < 3; y++ )
    for( int x = 0; x < 3; x++ )
      is >> t._tm[x][y];
  return is;
}

