/*
 * 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 <header.hxx>
#include <t_t1_dl.hxx>
#include <v_t1.hxx>
#include <m_t0.hxx>


extern Scalar criter (R2,R2,R2,Metrica);

void   mshreg0(Triangulo_T1_dlist* t_vec, Vertice_T1* so,Scalar omega,
	       Scalar crit_min,Mallado_T0* malla){

  Triangulo_T1_dlink* Lt_lk;
  Triangulo_T1* t0;
  Triangulo_T0* t0_so,*tri0=malla->saca_triangle(0);
  Metrica mm,mtr0;
  Metrica ma(0,0,0);
  R2 coor[3];
  R2 smiemb(0,0);
  R2 cor,co_so,despl;
  Scalar* criterios;
  Scalar depx,depy;
  Scalar bx,by;
  Scalar area;
  Scalar despl_max,d0;
  Scalar eps=malla->eps_malla()/3.0;
  int num_it=10;
  int p_pos[3];
  int num,ss;
  int conta,err=0,err0;
  int cont=0,i;
  int t_ini,t_fin;
  Boolean area_negativa=FALSE;
  p_pos[0]=1;p_pos[1]=2;p_pos[2]=0;

  num=t_vec->num_elem();
  criterios=new Scalar[num];
  if (criterios==NIL) ERROR();
  conta=0;
  Lt_lk=t_vec->principio();
  despl_max=1e+30;
  co_so=so->c;
  t0_so=so->t0;
  mtr0=so->mtr;
  cont=0;
  while (Lt_lk) {
    t0=Lt_lk->t;
    criterios[conta]=t0->krit;
    ss=t0->sommet_sig(so);
    if (ss!=-1) {
      mm=((so->mtr.inv(err0)+t0->s[ss]->mtr.inv(err0))/2.0).inv(err0);
      d0=distance(t0->s[ss]->c,co_so);
      if (d0<despl_max) despl_max=d0; 
      smiemb=smiemb+(mm*t0->s[ss]->c);
      ma=ma+mm;
      cor=cor+t0->s[ss]->c;
    }
    else {
      cerr<<"Vertice no encontrado."<<endl;
      cout<<*so<<endl<<*t0<<endl;
      exit(-1);
    }
    conta++;
    Lt_lk=Lt_lk->sig();
  }
  if (ss!=-1) {
    ss=p_pos[ss];
    if (t0->t[ss]==NIL) {
      mm=((so->mtr.inv(err0)+t0->s[ss]->mtr.inv(err0))/2.0).inv(err0);
      d0=distance(t0->s[ss]->c,co_so);
      if (d0<despl_max) despl_max=d0; 
      smiemb=smiemb+(mm*t0->s[ss]->c);
      ma=ma+mm;
      cor=cor+t0->s[ss]->c;
      conta++;
    }
  }
  mm=ma.inv(err);
  if (err==1) 
    cor=cor/Scalar(conta);
  else 
    cor=mm*smiemb;
  if (fabs(despl_max)<1e-30) {
    cerr<<"Atencion. Mallado degenerado. Arista de long. :"<<despl_max<<endl;
    cerr<<"Error: mshreg0."<<endl;
    exit(1);
  }
  despl_max=despl_max/3.0;
  if (despl_max>eps) despl_max=eps;
  depx=omega*(so->c.x-cor.x);
  depy=omega*(so->c.y-cor.y);
  despl.set(depx,depy);
  d0=despl.norme();
  if (d0>despl_max) {
    depx=depx*despl_max/d0;
    depy=depy*despl_max/d0;
  }
  cont=0;
  do {
    err=0;
    area_negativa=FALSE;
    bx=co_so.x-depx;
    by=co_so.y-depy;
    despl.set(bx,by);
    so->c=despl;
    t_ini=((so->t0)-tri0);
    so->mtr=malla->metrica(so->c,t_ini,t_fin);
    so->t0=malla->saca_triangle(t_fin);
    Lt_lk=t_vec->principio();
    conta=0;
    while (Lt_lk) {             
      t0=Lt_lk->t;
      area=t0->area2D();
      if (area<=0) {
        //if (ang0>45 && area>0) cout<<"mshreg0:"<<ang0<<endl;
        area_negativa=TRUE;
        cont++;
        depx=depx*pow(0.8,cont);
        depy=depy*pow(0.8,cont);
        err=1;
        break;
        
      }
      else {
        mm.set(0,0,0);
        for (i=0;i<3;i++) {
          mm=mm+(t0->s[i]->mtr.inv(err0))/3.0;
          coor[i]=t0->s[i]->c;
        } 
        mm=mm.inv(err0);
        t0->krit=criter(coor[0],coor[1],coor[2],mm); 
        if (t0->krit<crit_min) { 
          cont++;
          depx=depx*pow(0.8,cont);
          depy=depy*pow(0.8,cont);
          err=1;
          break;
        }
      }
      conta++;
      Lt_lk=Lt_lk->sig();
    }
  } while (area_negativa==TRUE && cont<num_it-1);
  if (err) {
    conta=0;
    so->c=co_so;
    so->t0=t0_so;
    so->mtr=mtr0;
    Lt_lk=t_vec->principio();
    while (Lt_lk) {
      t0=Lt_lk->t;              
      t0->krit=criterios[conta];
      conta++; 
      Lt_lk=Lt_lk->sig();
    }
  }
  delete[] criterios;
}
 
