/* Mathematiques de l'informatique graphique    */
/* Transformation geometrique generique         */
/*                                              */
/* Auteur: Nicolas JANEY                        */
/* nicolas.janey@univ-fcomte.fr                 */
/* Octobre 2012                                 */

#include <stdlib.h>
#include <stdio.h>
#include <math.h>

#include "TransformationGeometrique.h"
#include "CoordonneesHomogenes.h"

/* Constructeurs                                */

static double **allocation(int n) {
  double **c =(double **) calloc(n,sizeof(double *));
  if ( c ) {
    for ( int i = 0 ; i < n ; i++ )
      c[i] =(double *) calloc(n,sizeof(double)); }
  return(c);
}

static void liberation(int n,double **c) {
  for ( int i = 0 ; i < n ; i++ )
    free(c[i]);
  free(c);
}

TransformationGeometrique::TransformationGeometrique(int n) {
  this->n = n;
  c = allocation(n);
  for ( int i = 0 ; i < n ; i++ )
    for ( int j = 0 ; j < n ; j++ )
      c[i][j] =( i == j ) ? 1.0 : 0.0;
}

TransformationGeometrique::TransformationGeometrique(int n,double *t) {
  this->n = n;
  c = allocation(n);
  int k = 0;
  for ( int i = 0 ; i < n ; i++ )
    for ( int j = 0 ; j < n ; j++ ) {
      c[i][j] = t[k];
      k++; }
}

TransformationGeometrique::TransformationGeometrique(int n,double **t) {
  this->n = n;
  c = allocation(n);
  for ( int i = 0 ; i < n ; i++ )
    for ( int j = 0 ; j < n ; j++ )
      c[i][j] = t[i][j];
}

TransformationGeometrique::TransformationGeometrique(TransformationGeometrique *tg) {
  n = tg->n;
  c = allocation(n);
  for ( int i = 0 ; i < n ; i++ )
    for ( int j = 0 ; j < n ; j++ )
      c[i][j] = tg->c[i][j];
}

/* Destructeur                                  */

TransformationGeometrique::~TransformationGeometrique(void) {
  liberation(n,c);
}

/* Methodes                                     */

void TransformationGeometrique::print(void) {
  for ( int i = 0 ; i < n ; i++ ) {
    printf("%8.3lf",c[i][0]);
    for ( int j = 1 ; j < n ; j++ )
      printf(" %8.3lf",c[i][j]);
    printf("\n"); }
}

void TransformationGeometrique::compose(TransformationGeometrique *t1,TransformationGeometrique *t2) {
  double **cc = allocation(n);
  for ( int i = 0 ; i < n ; i++ )
    for ( int j = 0 ; j < n ; j++ ) {
      for ( int k = 0 ; k < n ; k++ )
        cc[i][j] += t1->c[i][k]*t2->c[k][j]; }
  for ( int i = 0 ; i < n ; i++ )
    for ( int j = 0 ; j < n ; j++ )
      this->c[i][j] = cc[i][j];
  liberation(n,cc);
}

void TransformationGeometrique::compose(TransformationGeometrique *tg) {
  double **aux = allocation(n);
  for ( int i = 0 ; i < n ; i++ )
    for ( int j = 0 ; j < n ; j++ ) {
      for ( int k = 0 ; k < n ; k++ )
        aux[i][j] += tg->c[i][k]*c[k][j]; }
  for ( int i = 0 ; i < n ; i++ )
    for ( int j = 0 ; j < n ; j++ )
      c[i][j] = aux[i][j];
  liberation(n,aux);
}

void TransformationGeometrique::transforme(CoordonneesHomogenes *ch) {
  double *t =(double *) calloc(n,sizeof(double));
  if ( t ) {
    for ( int i = 0 ; i < n ; i++ ) {
      for ( int k = 0 ; k < n ; k++ )
        t[i] += c[i][k]*ch->c[k]; }
    for ( int i = 0 ; i < n ; i++ ) {
      ch->c[i] = t[i]; }
    free(t); }
}
