/*
 * ADAPT2D : a software for automatic mesh adaptation in 2D
 *
 * AUTHOR : Manuel J. Castro Diaz(e-mail:castro@gamba.cie.uma.es)
 * ADAPTED FOR FREEFEM : Prud'homme Christophe (e-mail:prudhomm@ann.jussieu.fr) 
 *
 * this code is public domain
 * 
 * You may copy freely these files and use it for    
 * teaching or research. These or part of these may   
 * not be sold or used for a commercial purpose without
 * our consent
 * 
 * Any problems should be reported to the AUTHOR
 * at the following address : castro@gamba.cie.uma.es
 */


#include <metric.hxx> 

void Metrica::write(ostream& f) {
  f.setf(ios::scientific,ios::floatfield);
  f << '[' <<setw(13)<< coef[0] << ',' <<setw(13)<< coef[1] << ']' <<endl ;
  f << '[' <<setw(13)<< coef[1] << ',' <<setw(13)<< coef[2] << ']' <<endl ;
  f << "Factor:"<<factor<<endl;
  f.setf(0,ios::floatfield);}

ostream& operator<<(ostream& f, Metrica& c) {c.write(f); return f;}

Metrica::Metrica  () :factor(1) {
  int i=0; for (i=0; i<3; i++) coef[i]=0;}
Metrica::Metrica (Scalar c0,Scalar c1,Scalar c2) { 
  factor=1;
  coef[0]=c0;coef[1]=c1; coef[2]=c2; }
Metrica::Metrica (Scalar c0,Scalar c1,Scalar c2,Scalar ff) { 
  factor=ff;
  coef[0]=c0;coef[1]=c1; coef[2]=c2;}
Metrica::Metrica (Scalar* co): factor(1) {
  int i=0; while (i<3) {coef[i]=co[i]; i++;} }
  
void Metrica::set (Scalar c0,Scalar c1,Scalar c2) { 
  coef[0]=c0;coef[1]=c1; coef[2]=c2; }
void Metrica::set (Scalar c0,Scalar c1,Scalar c2,Scalar ff) {
  coef[0]=c0;coef[1]=c1; coef[2]=c2; 
  factor=ff; }

void Metrica::set (Scalar* co) {
  int i=0; while (i<3) {coef[i]=co[i]; i++;} }
void Metrica::set (const Metrica& mm) {
  int i=0;
  factor=mm.factor;
  while (i<3) {
    coef[i]=mm.coef[i]; i++;}
}
Metrica&  Metrica::operator=(const Metrica& cc) {
  int i=0;
  factor=cc.factor;
  while (i<3) { 
    coef[i]=cc.coef[i]; i++;}
  return *this;
}
  Scalar Metrica::determinante() {
    Scalar det;
    if (factor<1e-30){
      cerr<<"Attention. Metric factor=0."<<endl;
      cerr<<"Error in subroutine Metrica::determinante."<<endl;
      exit(1);
    }
    det=coef[0]*coef[2]-coef[1]*coef[1];
    det=det*pow(factor*factor,2);
    return det;
  }
Metrica Metrica::operator+(Metrica mm) {
  if (factor<1e-30 || mm.factor<1e-30) {
    cerr<<"Attention. Metric factor=0."<<endl;
    cerr<<"Error in subroutine Metrica::operator+."<<endl;
    exit(1);
  }
  return Metrica(factor*factor*coef[0]+mm.factor*mm.factor*mm.coef[0],\
                 factor*factor*coef[1]+mm.factor*mm.factor*mm.coef[1],\
                 factor*factor*coef[2]+mm.factor*mm.factor*mm.coef[2],1);
}
Metrica Metrica::operator*(Scalar cc) {
  if (factor<1e-30) {
    cerr<<"Attention. Metric factor=0."<<endl;
    cerr<<"Error in subroutine  Metrica::operator*(Scalar)."<<endl;
    exit(1);
  }
  return Metrica(factor*factor*coef[0]*cc,factor*factor*coef[1]*cc,\
                 factor*factor*coef[2]*cc,1);
}
Metrica Metrica::operator/(Scalar cc) {
  if (factor<1e-30) {
    cerr<<"Attention. Metric factor=0."<<endl;
    cerr<<"Error in subroutine Metrica::operator/(Scalar)."<<endl;
    exit(1);
  }
  return Metrica(factor*factor*coef[0]/cc,factor*factor*coef[1]/cc,\
                 factor*factor*coef[2]/cc,1);
}

R2 Metrica::operator*(R2 x) {
  R2 r0;
  if (factor<1e-30) {
    cerr<<"Attencion. Factor de =0."<<endl;
    cerr<<"Error in subroutine Metrica::operator*(R2)."<<endl;
    exit(1);
  }
  r0.set(coef[0]*x.x+coef[1]*x.y,\
         coef[1]*x.x+coef[2]*x.y);
  r0=r0*(factor*factor);
  return r0;
}
Metrica Metrica::operator*(Metrica m0) {
  Metrica m;
  Scalar c0,c1,c2;
  Scalar f;
  if (factor<1e-30 || m0.factor<1e-30) {
    cerr<<"Attention. metric factor=0."<<endl;
    cerr<<"Error in subroutine  Metrica::operator*(Metrica)."<<endl;
    exit(1);
  }
  f=factor*factor*m0.factor*m0.factor;
  c0=coef[0]*m0.coef[0]+coef[1]*m0.coef[1];
  c1=coef[0]*m0.coef[1]+coef[1]*m0.coef[2];
  c2=coef[1]*m0.coef[1]+coef[2]*m0.coef[2];
 
  m.set(c0,c1,c2,1);
  m=m*f;
  return m; 
}
Metrica Metrica::inv(int& err) {
  Metrica m0;
  Scalar c0,c1,c2;
  Scalar det;
  err=0;
  if (factor<1e-30) {
    cerr<<"Attencion. Metric factor=0."<<endl;
    cerr<<"Error in subroutine Metrica::inv."<<endl;
    m0.set(1,0,1);
    err=1;
    return m0;      
  }
  m0=*this;
  m0=m0*1.0;      
  det=m0.determinante();
  if (det<1e-30) {
    cerr<<"Attention. Metric no invertible. Det:"<<det<<endl;
    cerr<<"Error in subroutine Metrica::inv."<<endl;
    m0.set(1,0,1);
    err=1;
    return m0; 
  }
  c0= m0.coef[2];
  c1=-m0.coef[1];
  c2= m0.coef[0];
  m0.set(c0,c1,c2,1);
  m0=m0/det;
  return m0;
}
