/*
 * 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 <t_t1.hxx>

Triangulo_T1::Triangulo_T1() {
  ref=0;
  krit=-999.;
  lk=NIL;
  lk0=NIL;
  for (int i=0; i<3; i++) {
    s[i]=NIL;
    t[i]=NIL;
    a[i]=NIL;
  }
}
Triangulo_T1::Triangulo_T1(Vertice_T1* s0, Vertice_T1* s1, Vertice_T1* s2,
                           Triangulo_T1* t0, Triangulo_T1* t1, Triangulo_T1* t2,
                           Arista_T1* a0, Arista_T1* a1, Arista_T1* a2, int reff=0) { 
  ref=reff;
  krit=-999.;
  lk=NIL;
  lk0=NIL;
  s[0]=s0; s[1]=s1; s[2]=s2;
  t[0]=t0; t[1]=t1; t[2]=t2;
  a[0]=a0; a[1]=a1; a[2]=a2;
}
Triangulo_T1::Triangulo_T1(Vertice_T1& s0, Vertice_T1& s1, Vertice_T1& s2,
                           Triangulo_T1& t0, Triangulo_T1& t1, Triangulo_T1& t2,
                           Arista_T1& a0, Arista_T1& a1, Arista_T1& a2, int reff=0) { 
  ref=reff;
  krit=-999.;
  lk=NIL;
  lk0=NIL;
  s[0]=&s0; s[1]=&s1; s[2]=&s2;
  t[0]=&t0; t[1]=&t1; t[2]=&t2;
  a[0]=&a0; a[1]=&a1; a[2]=&a2;
}
Triangulo_T1::Triangulo_T1(Vertice_T1* s0[], Triangulo_T1* t0[], Arista_T1* a0[],
                           int reff=0) {
  ref=reff;
  krit=-999.;
  lk=NIL;
  lk0=NIL;
  for (int i=0; i<3; i++) { 
    s[i]=s0[i];
    t[i]=t0[i];
    a[i]=a0[i];
  }
}
Triangulo_T1::Triangulo_T1(const Triangulo_T1& tt) {
  ref=tt.ref;
  krit=tt.krit;
  lk=tt.lk;
  lk0=tt.lk0;
  for (int i=0; i<3; i++) { 
    s[i]=tt.s[i];
    t[i]=tt.t[i];
    a[i]=tt.a[i];
  }
}
void Triangulo_T1::set(Vertice_T1* s0, Vertice_T1* s1, Vertice_T1* s2,
		       Triangulo_T1* t0, Triangulo_T1* t1, Triangulo_T1* t2,
		       Arista_T1* a0, Arista_T1* a1, Arista_T1* a2, int reff=0) { 
  ref=reff;
  s[0]=s0; s[1]=s1; s[2]=s2;
  t[0]=t0; t[1]=t1; t[2]=t2;
  a[0]=a0; a[1]=a1; a[2]=a2;
}                                                          
void Triangulo_T1::set(Vertice_T1& s0, Vertice_T1& s1, Vertice_T1& s2,
		       Triangulo_T1& t0, Triangulo_T1& t1, Triangulo_T1& t2,
		       Arista_T1& a0, Arista_T1& a1, Arista_T1& a2, int reff=0) { 
  ref=reff;
  s[0]=&s0; s[1]=&s1; s[2]=&s2;
  t[0]=&t0; t[1]=&t1; t[2]=&t2;
  a[0]=&a0; a[1]=&a1; a[2]=&a2;
}
void Triangulo_T1::set(Vertice_T1* s0[], Triangulo_T1* t0[], Arista_T1* a0[],
		       int reff=0) {
  ref=reff;
  for (int i=0; i<3; i++) { 
    s[i]=s0[i];
    t[i]=t0[i];
    a[i]=a0[i];
  }
}
void Triangulo_T1::set(const Triangulo_T1& tt) {
  ref=tt.ref;
  krit=tt.krit;
  lk=tt.lk;
  lk0=tt.lk0;
  for (int i=0; i<3; i++) { 
    s[i]=tt.s[i];
    t[i]=tt.t[i];
    a[i]=tt.a[i];
  }
}

Triangulo_T1& Triangulo_T1::operator=(const Triangulo_T1& tt)  {
  ref=tt.ref;
  krit=tt.krit;
  lk=tt.lk;
  lk0=tt.lk0;
  for (int i=0; i<3; i++) { 
    s[i]=tt.s[i];
    t[i]=tt.t[i];
    a[i]=tt.a[i];
  }
  return *this;
}
void Triangulo_T1::write(ostream& os)
{os <<"Triangulo_T1:"<<this<<"; De Referencia:"<< ref<< endl
    <<"   De nodos  :"<<s[0]<<", "<<s[1]<<", "<<s[2]<<endl
    <<"   De aristas:"<<a[0]<<", "<<a[1]<<", "<<a[2]<<endl
    <<"   T. vecinos:"<<t[0]<<", "<<t[1]<<", "<<t[2]<<endl
    <<"   Criterio:"<<krit<<endl;
if(lk) os<<"   Link:"<<lk<<endl;
if(lk0) os<<"   Link0:"<<lk0<<endl;
os<<*s[0]<<endl<<*s[1]<<endl<<*s[2]<<endl;
os<<*a[0]<<endl<<*a[1]<<endl<<*a[2]<<endl;

}

ostream& operator<<(ostream& os, Triangulo_T1& tt) {tt.write(os); return os;}

/*
       *********   SUBRRUTINA HK    ************.

       Entrada:Triangulo apuntado por this.
       Salida: el minimo de las longitudes del triangulo.
*/
Scalar Triangulo_T1::hk() {

  Scalar lg,lg0;
  int i;
  lg=1e+30;
  for (i=0; i<3; i++) {
    lg0=a[i]->hf();
    if (lg0<lg) lg=lg0;
  }
  return lg;
}

/*     *********   SUBRRUTINA AREA  ************.
       Entrada: Triangulo apuntado por this.
       Salida: Area del Triangulo.
*/
Scalar Triangulo_T1::area() {
  R2 v1,v2;
  Scalar det;
  v1=(s[1]->c)-(s[0]->c);
  v2=(s[2]->c)-(s[0]->c);
  det=fabs((v1.x*v2.y-v1.y*v2.x)/2.0);
  return det;
}

/*     
       ***********  SUBRRUTINA AREA2D   *****************
         entrada: Triangulo apuntado por this.
         salida: Area con signo. (Nos da si el triangulo
                                  esta + o - orientado.)
*/
Scalar Triangulo_T1::area2D() {
  R2 v1,v2;
  Scalar det;
  v1=(s[1]->c)-(s[0]->c);
  v2=(s[2]->c)-(s[0]->c);
  det=(v1.x*v2.y-v1.y*v2.x)/2.0;
  if (fabs(det)<1e-12) det=0;
  return det;
}


/*
   ****************  SUBRRUTINA  SOMMET  *****************
     Da la posicion de un vertice en el triangulo apuntado
     por this.
      Entrada: Triangulo apuntado por this.
               s0: Puntero al vertice.
      Salida:  Entero. 0-1-2. Indica la numeracion
               local en el triangulo.
               -1 si el vertice no pertenece al triangulo.
*/
int Triangulo_T1::sommet(Vertice_T1* s0) {
  int pos=-1;
  for (int i=0; i<3; i++) {
    if (s[i]==s0) {
      pos=i;
      break;
    }
  }
  if (pos==-1) {
    cerr<<"Error 1. Sub Triangulo_T1::sommet"<<endl;
    cout<<*s0<<endl;
    cout<<*this<<endl;
    exit(1);
  }
  return pos;
}
/*
   ****************  SUBRRUTINA  SOMMET  *****************
     Da la posicion de un vertice en el triangulo apuntado
     por this.
      Entrada: Triangulo apuntado por this.
               s0: Puntero al vertice.
      Salida:  Entero. 0-1-2. Indica la numeracion
               local en el triangulo.
               -1 si el vertice no pertenece al triangulo.
*/
int Triangulo_T1::sommet0(Vertice_T1* s0) {
  int pos=-1;
  for (int i=0; i<3; i++) {
    if (s[i]==s0) {
      pos=i;
      break;
    }
  }
  return pos;
}



/*
    ***************  SUBRRUTINA ARISTA  ******************
    Determina el n. local de la arista formada por los
      vertice s0 y s1.
      Entrada: triangulo apuntado por this.
               s0 y s1. Puntero a dos vertices.
      Salida: La posicion local de la arista. (0-1-2).
              -1 la arista no esta en el triangulo.
*/
int Triangulo_T1::arista(Vertice_T1* s0, Vertice_T1* s1) {
  int p_pos[3];
  int p_neg[3];
  int i,pos=-1;
  int aa=-1;
  p_pos[0]=1;p_pos[1]=2;p_pos[2]=0;
  p_neg[0]=2;p_neg[1]=0;p_neg[2]=1;
  
  for (i=0; i<3; i++) {
    if (s[i]==s0) {
      pos=i;
      break;
    }
  }
  if (pos>=0) {
    if (s1==s[p_pos[pos]])
      aa=pos;
    else {
      if (s1==s[p_neg[pos]])
	aa=p_neg[pos];
    }
  }
  if (aa==-1) {
    cerr<<"Error 1.  Subrrutina Triangulo_T1::arista"<<endl;
    cout<<*s0<<endl<<*s1<<endl;
    cout<<*this<<endl;
    exit(1);
  }
  return aa;
}

/*    
     *********      SUBRRUTINA ARISTA    **********
        Idem que la anterior pero el dato de entrada
        es un puntero a la arista. (aa).
*/
int Triangulo_T1::arista(Arista_T1* aa) {
  int pos=-1;
  for (int i=0; i<3; i++) {
    if (a[i]==aa) {
      pos=i;
      break;
    }
  }
  if (pos==-1) {
    cerr<<"Error 1.  Subrrutina Triangulo_T1::arista"<<endl;
    cout<<*aa<<endl;
    cout<<*(aa->s[0])<<endl<<*(aa->s[1])<<endl;
    cout<<*this<<endl;
    exit(1);
  }
  
  return pos;
}
   

/*
    ***************  SUBRRUTINA ARISTA  ******************
    Determina el n. local de la arista formada por los
      vertice s0 y s1.
      Entrada: triangulo apuntado por this.
               s0 y s1. Puntero a dos vertices.
      Salida: La posicion local de la arista. (0-1-2).
              -1 la arista no esta en el triangulo.
*/
int Triangulo_T1::arista0(Vertice_T1* s0, Vertice_T1* s1) {
  int p_pos[3];
  int p_neg[3];
  int i,pos=-1;
  int aa=-1;
  p_pos[0]=1;p_pos[1]=2;p_pos[2]=0;
  p_neg[0]=2;p_neg[1]=0;p_neg[2]=1;
  
  for (i=0; i<3; i++) {
    if (s[i]==s0) {
      pos=i;
      break;
    }
  }
  if (pos>=0) {
    if (s1==s[p_pos[pos]])
      aa=pos;
    else {
      if (s1==s[p_neg[pos]])
	aa=p_neg[pos];
    }
  }
  return aa;
}

/*    
     *********      SUBRRUTINA ARISTA    **********
        Idem que la anterior pero el dato de entrada
        es un puntero a la arista. (aa).
*/
int Triangulo_T1::arista0(Arista_T1* aa) {
  int pos=-1;
  for (int i=0; i<3; i++) {
    if (a[i]==aa) {
      pos=i;
      break;
    }
  }
  return pos;
}
   



/*   
     *********** SUBRRUTINA  VECINO  *****************
      Determina el triangulo vecino a uno dado por la
       arista que empieza o termina por vertice so segun
       un sentido.
      Entrada: Triangulo apuntado por this.
               Puntero a un vertice. (so)
               sentido + o -.(sent=1 o -1).
         (Si sent=1 -> trian. vecino por la arista que
                       tiene como primer vertice so.
          Si sent=-1 ->trian. vecino por la arista que
                       tiene por vertice final so. )
      Salida: Puntero al triangulo vecino.
            (NIL si no hay).
*/
Triangulo_T1*  Triangulo_T1::vecino(Vertice_T1* so, int sent) {
  Triangulo_T1* tr=NIL;
  int inv[3];
  int pos=-1;
  inv[0]=2;inv[1]=0;inv[2]=1;
  for (int i=0; i<3; i++) {
    if (s[i]==so) {
      pos=i;
      break;
    }
  }
  if (pos>=0) {
    if (sent==1) 
      tr=t[pos];
    else
      tr=t[inv[pos]];
  }
  if (pos==-1) {
    cerr<<"Error 1. Triangulo_T1::vecino"<<endl;
    cout<<*so<<endl<<"Sentido:"<<sent<<endl;
    cout<<*this<<endl;
    exit(1);
  }
  return tr;
}

/*    
    ***********   SUBRRUTINA SOMMET_SIG  *************
  Determina la posicion del vertice siguiente a uno 
    dado por un puntero al mismo.
      Entrada:  Triangulo apuntado por this.
                Puntero al vertice. (so).
      Salida:   La posicion local del siguiente vertice
                al dado en dicho triangulo. (0-1-2).
              (-1 si el vertice dado no pertenece al
                triangulo apuntado por this.)
*/
int Triangulo_T1::sommet_sig(Vertice_T1* so) {
  int som=-1,i;
  int p[3];
  p[0]=1;p[1]=2;p[2]=0;
  for (i=0; i<3; i++) {
    if (s[i]==so) {
      som=p[i];
      break;
    }
  }
  if (som==-1) {
    cerr<<"Error 1. Triangulo_T1::sommet_sig"<<endl;
    cout<<*so<<endl;
    cout<<*this<<endl;
    exit(1);
  }
  return som;
}




       

/*               COORDENADAS BARICENTRICAS DE UN PUNTO

      Entrada:   pt= Punto.
      -------

      Salida:   coor= R2 que contiene l1,l2. La tercera coor.
      ------          baricentrica se obtiene como 1-l1-l2
                     
------------------------------------------------------------------------
*/

R2 Triangulo_T1::coor_bar(const R2& pt) {
  R2 coor;
  coor=coor_b(s[0]->c,s[1]->c,s[2]->c,pt);
  return coor;
}

Arista_T1* Triangulo_T1::supr_arista(int& pos) {
  Arista_T1* a0;
  Vertice_T1* s0;
  Scalar dist0,dist=1e+30;
  int i;
  int ps;
  
  for (i=0; i<3; i++) {  
    dist0=distance(a[i]->s[0]->c,a[i]->s[0]->mtr,a[i]->s[1]->c,a[i]->s[1]->mtr);
    if (dist0<dist) {
      dist=dist0;
      ps=i;
    }
  }
  a0=a[ps];
  s0=a0->s[0];
  pos=0;
  if ((s0->ref!=0 || s0->inters!=FALSE) && (a0->s[1]->ref>=0)) pos=1;
  return a0;
}

R2 Triangulo_T1::altura(int pos0) {
  R2 vec,tang;
  Scalar ang,d0,tg;  
  int ant[3]={2,0,1};
  tang.set(s[ant[ant[pos0]]]->c.x-s[pos0]->c.x,s[ant[ant[pos0]]]->c.y-s[pos0]->c.y);
  tg=tang.norma();
  if (tg<1e-20) { 
    cerr<<"Error. Arista degenerada. Sub. Triagulo_T1::altura."<<endl;
    exit(1);
  }
  else
    tang=tang/tg;
  vec.set(tang.y,-tang.x);
  ang=angle(a[ant[pos0]],a[pos0]);
  d0=fabs((a[ant[pos0]]->s[0]->c-a[ant[pos0]]->s[1]->c).norme()*sin(ang*PI/180.0));
  vec=vec*d0;
  return vec;
}
