// RealMesh2d.cpp
//
// J.Liu, R.Cali
// ColoState, Jan.-Jun. 2007


#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include "GeoElt2d.h"
#include "PtVec2d.h"
#include "RealMesh2d.h"
using namespace std;


// RealMesh2d: default constructor

RealMesh2d::RealMesh2d() 
{
   NumNds = 0;
   NumElts = 0;
   NumEdges = 0;
   BgnLblElt = 0;
   BgnLblNd = 0;
   BgnLblEdge = 0;
   EltType = 0;  // Null pointer
   LblVrtx = 0;  // Null pointer
   nd = 0;  // Null pointer
}


// RealMesh2d: constructor 
// from a data file with a fixed structure

RealMesh2d::RealMesh2d(char *filename) 
{
   FILE *fp;
   int i, id, ie, j, NumVrtz;
   double x, y;

   if (NULL==(fp=fopen(filename, "r"))) {
      puts("Open data file failed.  Exit.");
      exit(-1);
   }

   fscanf(fp, "%7d", &NumElts);
   fscanf(fp, "%7d", &NumNds);
   fscanf(fp, "%7d", &NumEdges);
   fscanf(fp, "%2d", &BgnLblElt);
   fscanf(fp, "%2d", &BgnLblNd);
   fscanf(fp, "%2d", &BgnLblEdge);

   EltType = new int [NumElts];
   LblVrtx = new int *[NumElts];
   for (ie=0; ie<NumElts; ++ie)  LblVrtx[ie] = 0;  // Null pointer

   for (ie=0; ie<NumElts; ++ie) {
      fscanf(fp, "%7d", &i);
      fscanf(fp, "%3d", EltType+ie);

      switch (EltType[ie]) {
      case rect2d:  // rectangle in 2-dim
         NumVrtz = 2;
         break;
      case trig:  // triangle
         NumVrtz = 3;
         break;
      case quadri:  // quadrilateral
         NumVrtz = 4;
         break;
      }

      LblVrtx[ie] = new int[NumVrtz];
      for (j=0; j<NumVrtz; ++j)  fscanf(fp, "%7d", LblVrtx[ie]+j);
   }

   nd = new PtVec2d[NumNds];

   for (id=0; id<NumNds; ++id) {
      fscanf(fp, "%7d", &i);
      fscanf(fp, "%lf  %lf", &x, &y);
      nd[id] = PtVec2d(x, y);
   }

   edge = new int [NumEdges][5];

   for (ie=0; ie<NumEdges; ++ie) {
      fscanf(fp, "%7d", &i);
      fscanf(fp, "%2d", &edge[ie][0]);
      for (j=1; j<=4; ++j)  fscanf(fp, "%7d", &edge[ie][j]);
   }

   fclose(fp);
   cout << "Reading real mesh finished\n";
}


// RealMesh2d: destructor

RealMesh2d::~RealMesh2d() 
{
   delete[] EltType;
   for (int i=0; i<NumElts; ++i)  delete[] LblVrtx[i];
   delete[] LblVrtx;
   delete[] nd;
   delete[] edge;
}


// RealMesh2d: get element info

int* RealMesh2d::getEltInfo(int &eltType, int lblElt) const
{
   int i = lblElt-BgnLblElt;
   eltType = EltType[i];

   int NumVrtz = 0;
   switch (eltType) {
   case rect2d:  // rectangle in 2-dim
      NumVrtz = 2;
      break;
   case trig:  // triangle
      NumVrtz = 3;
      break;
   case quadri:  // quadrilateral
      NumVrtz = 4;
      break;
   }

   int *lblVrtx = new int[NumVrtz];
   for (int j=0; j<NumVrtz; ++j)  lblVrtx[j] = LblVrtx[i][j];

   return lblVrtx;
}


// RealMesh2d: get edge info

void RealMesh2d::getEdgeInfo(int &edgeType, PtVec2d &P1, PtVec2d &P2, 
   int &ie1, int &ie2, int ie) const 
{
   int le = ie-BgnLblEdge;
   edgeType = edge[le][0];
   P1 = nd[edge[le][1]-BgnLblNd];
   P2 = nd[edge[le][2]-BgnLblNd];
   ie1 = edge[le][3];
   ie2 = edge[le][4];
   return;
}


// RealMesh2d: compute the maximal mesh size

double RealMesh2d::maxMeshSize() const 
{
   return 1.0;
}


// RealMesh2d: compute the minimal mesh size

double RealMesh2d::minMeshSize() const 
{
   int i, j, numVrtz;
   PtVec2d *vrtx=0;
   double maxEdge=0.0, minEdge=1.0;

   double minSize = 1.0;
   for (i=0; i<NumElts; ++i) {
      if (EltType[i]==rect2d) {  // rectangle in 2-dim
         numVrtz = 2;
         vrtx = new PtVec2d[numVrtz];
         vrtx[0] = nd[LblVrtx[i][0]];
         vrtx[1] = nd[LblVrtx[i][1]];
         Rect2d R = Rect2d(vrtx[0], vrtx[1]);
         delete[] vrtx;
         R.getMaxMinEdges(maxEdge, minEdge);
      }

      if (EltType[i]==trig) {  // triangle
         numVrtz = 3;
         vrtx = new PtVec2d[numVrtz];
         for (j=0; j<numVrtz; ++j)  vrtx[j] = nd[LblVrtx[i][j]];
         Trig T = Trig(vrtx[0], vrtx[1], vrtx[2]);
         delete[] vrtx;
         T.getMaxMinEdges(maxEdge, minEdge);
      }

      if (minEdge<minSize)  minSize = minEdge;      
   }

   return minSize;
}


// RealMesh2d: Saving mesh for verification

void RealMesh2d::saveMesh() const 
{
   FILE *fp;

   if (NULL==(fp=fopen("VeriMesh.dat", "w"))) {
      puts("Open data file failed.  Exit.");
      exit(-1);
   }

   for (int ie=0; ie<NumElts; ++ie)  {
      int NumVrtz = 0;
      switch (EltType[ie]) {
      case rect2d:  // rectangle in 2-dim
         NumVrtz = 2;
         break;
      case trig:  // triangle
         NumVrtz = 3;
         break;
      }

      fprintf(fp, "%7d  %2d:  ", ie+BgnLblElt, NumVrtz);
      for (int j=0; j<NumVrtz; ++j)  fprintf(fp, "%7d  ", LblVrtx[ie][j]);
      fprintf(fp, "\n");
   }

   for (int id=0; id<NumNds; ++id) {
      fprintf(fp, "%7d  ", id+BgnLblNd);
      fprintf(fp, "%7.4f  %7.4f\n", nd[id].xCrd(), nd[id].yCrd());
   }

   for (ie=0; ie<NumEdges; ++ie) {
      fprintf(fp, "%7d  %2d:  ", ie+BgnLblEdge, edge[ie][0]);
      for (int j=1; j<=4; ++j)  fprintf(fp, "%7d  ", edge[ie][j]);
      fprintf(fp, "\n");
   }

   fclose(fp);
   return;
}
