/*
 *  R : A Computer Language for Statistical Data Analysis
 *  Copyright (C) 2001-3 Paul Murrell
 *                2003 The R Core Team
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, a copy is available at
 *  https://www.R-project.org/Licenses/
 */

#include "grid.h" 
#include <math.h>

/* Code for matrices, matrix multiplication, etc for performing
 *  2D affine transformations:  translations, scaling, and rotations.
 */

double locationX(LLocation l) {
    return l[0];
}

double locationY(LLocation l) {
    return l[1];
}

void copyTransform(LTransform t1, LTransform t2)
{
    int i, j;
    for (i=0; i<3; i++) 
	for (j=0; j<3; j++)
	    t2[i][j] = t1[i][j];
}

void invTransform(LTransform t, LTransform invt)
{
    double det = t[0][0]*(t[2][2]*t[1][1] - t[2][1]*t[1][2]) - 
	t[1][0]*(t[2][2]*t[0][1] - t[2][1]*t[0][2]) +
	t[2][0]*(t[1][2]*t[0][1] - t[1][1]*t[0][2]);
    if (det == 0)
	error(_("singular transformation matrix"));
    invt[0][0] = 1/det*(t[2][2]*t[1][1] - t[2][1]*t[1][2]);
    invt[0][1] = -1/det*(t[2][2]*t[0][1] - t[2][1]*t[0][2]);
    invt[0][2] = 1/det*(t[1][2]*t[0][1] - t[1][1]*t[0][2]);
    invt[1][0] = -1/det*(t[2][2]*t[1][0] - t[2][0]*t[1][2]);
    invt[1][1] = 1/det*(t[2][2]*t[0][0] - t[2][0]*t[0][2]);
    invt[1][2] = -1/det*(t[1][2]*t[0][0] - t[1][0]*t[0][2]);
    invt[2][0] = 1/det*(t[2][1]*t[1][0] - t[2][0]*t[1][1]);
    invt[2][1] = -1/det*(t[2][1]*t[0][0] - t[2][0]*t[0][1]);
    invt[2][2] = 1/det*(t[1][1]*t[0][0] - t[1][0]*t[0][1]);
}

void identity(LTransform m) 
{
    int i, j;
    for (i=0; i<3; i++) 
	for (j=0; j<3; j++)
	    if (i == j)
		m[i][j] = 1;
	    else
		m[i][j] = 0;
}

void translation(double tx, double ty, LTransform m)
{
    identity(m);
    m[2][0] = tx;
    m[2][1] = ty;
}

void scaling(double sx, double sy, LTransform m)
{
    identity(m);
    m[0][0] = sx;
    m[1][1] = sy;
}

void rotation(double theta, LTransform m)
{
    double thetarad = theta/180*M_PI;
    double costheta = cos(thetarad);
    double sintheta = sin(thetarad);
    identity(m);
    m[0][0] = costheta;
    m[0][1] = sintheta;
    m[1][0] = -sintheta;
    m[1][1] = costheta;
}

void multiply(LTransform m1, LTransform m2, LTransform m)
{
    m[0][0] = m1[0][0]*m2[0][0] + m1[0][1]*m2[1][0] + m1[0][2]*m2[2][0];
    m[0][1] = m1[0][0]*m2[0][1] + m1[0][1]*m2[1][1] + m1[0][2]*m2[2][1];
    m[0][2] = m1[0][0]*m2[0][2] + m1[0][1]*m2[1][2] + m1[0][2]*m2[2][2];
    m[1][0] = m1[1][0]*m2[0][0] + m1[1][1]*m2[1][0] + m1[1][2]*m2[2][0];
    m[1][1] = m1[1][0]*m2[0][1] + m1[1][1]*m2[1][1] + m1[1][2]*m2[2][1];
    m[1][2] = m1[1][0]*m2[0][2] + m1[1][1]*m2[1][2] + m1[1][2]*m2[2][2];
    m[2][0] = m1[2][0]*m2[0][0] + m1[2][1]*m2[1][0] + m1[2][2]*m2[2][0];
    m[2][1] = m1[2][0]*m2[0][1] + m1[2][1]*m2[1][1] + m1[2][2]*m2[2][1];
    m[2][2] = m1[2][0]*m2[0][2] + m1[2][1]*m2[1][2] + m1[2][2]*m2[2][2];
}

void location(double x, double y, LLocation v)
{
    v[0] = x;
    v[1] = y;
    v[2] = 1;
}

void trans(LLocation vin, LTransform m, LLocation vout)
{
    vout[0] = vin[0]*m[0][0] + vin[1]*m[1][0] + vin[2]*m[2][0];
    vout[1] = vin[0]*m[0][1] + vin[1]*m[1][1] + vin[2]*m[2][1];
    vout[2] = vin[0]*m[0][2] + vin[1]*m[1][2] + vin[2]*m[2][2];
}

/* Testing code
 * Need to undocument main() below and add #include <math.h> at top of file
 * Correct answers are "2.67 2.00 1.00" for m4=identity
 * and "0.00 2.00 1.00" for m4=rotation
 */

/*
  main() 
  {
  LLocation v1, v2; 
  LTransform m1, m2, m3, m4, m5, m6, m7, m8, m9, m10, m11;
  location(9, 10, v1);
  translation(-5, -6, m1);
  scaling(1/7.0, 1/8.0, m2);
  scaling(7, 8, m3);
  identity(m4);  
  rotation(3.141592 / 2, m4); 
  translation(4, 4, m5);
  scaling(1/3.0, 1/4.0, m6);
  multiply(m1, m2, m7);
  multiply(m7, m3, m8);
  multiply(m8, m4, m9);
  multiply(m9, m5, m10);
  multiply(m10, m6, m11);
  transform(v1, m11, v2);
  printf("%1.2f %1.2f %1.2f\n", v2[0], v2[1], v2[2]);	  
  }
*/

