#include <triangl.hxx>

void Triangulation::build(long nbs,long nbt,rpoint* rrp, int* nng, triangle* ttr, int* nngt) {
  int i,j;
  this->set(nbs,nbt);
  for (i=0; i<nbs; i++) {
    rp[i].x=rrp[i].x;
    rp[i].y=rrp[i].y;
    ng[i]=nng[i];
  }
  for (i=0; i<nbt; i++) {
    ngt[i]=nngt[i];
    for (j=0; j<3; j++) {
      tr[i][j]=ttr[i][j];
    }
  }
}

int Triangulation::build (char* name) {
  int nbs,nbt,i,j;
  this->clear();
#ifdef DEBUG
  cout<<endl<<endl;
  cout<<"============================================="<<endl;
  cout<<"        INPUT MESH  (FORMAT .AM_FMT)"<<endl;
  cout<<"============================================="<<endl;
  cout<<endl;
#endif /* DEBUG */
  OPENI(lectura, name);
  lectura >>nbs>>nbt;   //  N. of vertices and  triangles.
  NEXTLINE(lectura);
  
  this->set(nbs,nbt);
  
  for (i=0; i<nt; i++) {
    for (j=0; j<3; j++) {
      lectura >>tr[i][j];
      this->tr[i][j]--;
    }
  }
  for (i=0; i<np; i++){
    lectura >>rp[i].x>>rp[i].y;
  }
  
  for (i=0; i<nt; i++) {
    lectura >> ngt[i];
    if (ngt[i]<0) {
      cerr<<"Attention. Mesh with negative references of triangles."<<endl;
      cerr<<"Error in subroutine Triangulation::build"<<endl;
      exit(1);
    }
  }      
  for (i=0; i<np; i++) {
    lectura >> ng[i];
    if (ng[i]<0) {
      cerr<<"Attention. Mesh with negative references of vertices."<<endl;
      cerr<<"Error in subroutine Triangulation::build"<<endl;
      exit(1);
    }
  }
  lectura.close();
  return 0;
}
void Triangulation::write(char* name) {
  int i,j,paso=0;

#ifdef DEBUG
  cout<<endl<<endl;
  cout<<"============================================="<<endl;
  cout<<"        WRITE MESH  (FORMAT .AM_FMT)"<<endl;
  cout<<"============================================="<<endl;
  cout<<endl;
#endif /* DEBUG */
  
  OPEN(escritura, name);  
  //number of vertices and triangles.
  escritura <<" "<<np<<" "<<nt<<"  -- nbs,nbt"<<endl; 
  for (i=0; i<nt; i++) {
    for (j=0; j<3; j++) {
      escritura <<setw(7)<<tr[i][j]+1;
    }
    escritura<<"     ";
    if (paso) {
      paso=0; escritura<<endl;}
    else
      paso++;
  }
  if (paso) escritura<<endl;  
  paso=0;
  escritura.setf(ios::scientific,ios::floatfield); 
  for (i=0; i<np; i++) {
    escritura<<setw(15)<<Scalar(rp[i].x)<<setw(15)<<Scalar(rp[i].y)<<"       ";
    if (paso) {
      paso=0; escritura<<endl;}
    else
      paso++;
  }
  if (paso) escritura<<endl;
  paso=0;
  for (i=0; i<nt; i++) {
    escritura<<setw(8)<< ngt[i];
    if (paso==9) {
      paso=0; escritura<<endl;}
    else
      paso++;
  }
  if (paso) escritura<<endl;  
  paso=0;
  for (i=0; i<np; i++) {
    escritura<<setw(8)<< ng[i];
    if (paso==9) {
      paso=0; escritura<<endl;}
    else
      paso++;
  }
  if (paso) escritura<<endl; 
  escritura.close();
}
Mesh_characteristic* Triangulation::characteristic() {
  Mesh_characteristic *ch_mesh;
  R2 c0,c1;
  Scalar dist;
  int i,j;
  int sig[3]={1,2,0};
  ch_mesh=new Mesh_characteristic;
  if (ch_mesh==NIL) ERROR();
#ifdef DEBUG
  cout<<endl<<endl;
  cout<<"============================================="<<endl;
  cout<<"       COMPUTING MESH CHARACTERISTIC"<<endl;
  cout<<"============================================="<<endl;
  cout<<endl;
#endif /* DEBUG */
  ch_mesh->df[0].set(1e+30,1e+30);
  ch_mesh->df[1].set(-1e+30,-1e+30);
  ch_mesh->ed_min=1e+30;
  ch_mesh->ed_max=-1e+30;
  for (i=0; i<np; i++) {
    ch_mesh->df[0].x=MIN(ch_mesh->df[0].x,Scalar(rp[i].x));
    ch_mesh->df[0].y=MIN(ch_mesh->df[0].y,Scalar(rp[i].y));
    ch_mesh->df[1].x=MAX(ch_mesh->df[1].x,Scalar(rp[i].x));
    ch_mesh->df[1].y=MAX(ch_mesh->df[1].y,Scalar(rp[i].y));
  }
  for (i=0; i<nt; i++) {
    for (j=0; j<3; j++) {
      c0.set(Scalar(rp[tr[i][j]].x),Scalar(rp[tr[i][j]].y));
      c1.set(Scalar(rp[tr[i][sig[j]]].x),Scalar(rp[tr[i][sig[j]]].y));
      dist=(c0-c1).norma();
      ch_mesh->ed_min=MIN(ch_mesh->ed_min,dist);
      ch_mesh->ed_max=MAX(ch_mesh->ed_max,dist);
    }
  }
  if (ch_mesh->ed_min<1e-18) {
    cerr<<"Attention. Degenerated mesh. edge length="<<ch_mesh->ed_min<<endl;
    exit (1);
  }
  else {
    if (ch_mesh->ed_min<1.0) {
      ch_mesh->scale=1.0/ch_mesh->ed_min;
    }
    else {
      ch_mesh->scale=1.0;
    }
  }
  return ch_mesh;
}
