// Emacs will be in -*- Mode: c++ -*-
//
// ********** DO NOT REMOVE THIS BANNER **********
//
// SUMMARY: Language for a Finite Element Method
// RELEASE: 2.0     
// USAGE  : 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 with- 
//          out our consent : fax (33)1 44 27 44 11        
//
// AUTHORS:  D. Bernardi, Y. Darmaillac F. Hecht,    
//           P. Parole O. Pironneau C. Prud'homme
// ORG    :          
// E-MAIL :   pironneau@ann.jussieu.fr     
//
// ORIG-DATE:     June-94
// LAST-MOD:     14-Sep-97 at 22:46:37 by Christophe Prud'homme
//
// DESCRIPTION:  
// DESCRIP-END.
//


#include <stdlib.h>
#include <stdio.h>
#include <math.h>

/*
 * FreeFem includes
 */
#include <triangul.h>
#include <rgraph.h>
#include <opclass.h>
#include <ugraph.h>


int            *ordre;
float          *table;
rpoint         *proj;
extern triangulation t;
float xfmin = 0.F, xfmax = 0.F;

void            Init (rpoint * rp, int ns, char *s);
void            quicksort (float *tb, int *o, int n);
void            initt (void);
void            projection (float *f);
void            contour (int ng[], int coul);

void 
Init (rpoint * rp, int ns, char *s)
{
  int             i;
  float           xmn = rp->x;
  float           xmx = rp->x;
  float           ymn = rp->y;
  float           ymx = rp->y;
  float           xctr, yctr, ray;
  float           x, y;

  for (i = 1; i < ns; i++)
     {
       x = (rp[i]).x;
       y = (rp[i]).y;
       xmx = x > xmx ? x : xmx;
       xmn = xmn > x ? x : xmn;
       ymx = y > ymx ? y : ymx;
       ymn = ymn > y ? y : ymn;
     }
  xctr = (xmx + xmn) / 2;
  yctr = (ymx + ymn) / 2;
  ray = (xmx - xctr) > (ymx - yctr) ? xmx - xctr : ymx - yctr;
  reffecran ();
  if (*s == 'o')
    cadreortho (xctr, yctr, ray);
  else
    cadre (xmn, xmx, ymn, ymx);

}


void 
quicksort (float *tb, int *o, int n)
{
  int             i, j;
  int             b;
  float           x, y;

  while (n > 1)
     {
       x = tb[n / 2];
       for (i = 0, j = n - 1; i <= j; i++, j--)
	  {
	    while (tb[i] > x)
	      i++;
	    while (tb[j] < x)
	      j--;
	    if (i > j)
	      break;
	    y = tb[i];
	    tb[i] = tb[j];
	    tb[j] = y;
	    b = o[i];
	    o[i] = o[j];
	    o[j] = b;
	  }
       n -= i;
       if (n > j + 1)
	  {
	    quicksort (tb, o, j + 1);
	    tb += i;
	    o += i;
	  }
       else
	  {
	    quicksort (tb + i, o + i, n);
	    n = j + 1;
	  }
     }
}


void 
initt (void)
{
  rpoint         *r = t.rp;
  triangle       *tt = t.tr;
  int             n = t.nt;
  int             i;

  table = new float[n];

//    closegraphique();
  ordre = new int[n];

  for (i = 0; i < n; i++)
    ordre[i] = i;
  for (i = 0; i < n; i++)
    table[i] = (r[tt[i][0]].y + r[tt[i][1]].y + r[tt[i][2]].y) / 3;
}

void 
projection (float *f)
{
  int             i;
  rpoint         *rp = t.rp;

  proj = new rpoint[t.np];
  for (i = 0; i < t.np; i++)
     {
       proj[i].x = rp[i].x / 5;
       proj[i].y = f[i] + rp[i].y / 3;
     }
}

void 
graph3d (float *fct, int waitm)
{

  int             i, j, coul;
  int             coul1 = 11, coul2 = 3;
  int             p1, p2, p3;
  float           test;
  triangle       *tt = t.tr;
  rpoint         *pp = t.rp;

  initt ();
  quicksort (table, ordre, t.nt);
  delete[]table;
  table = NULL;
  projection (fct);
  Init (proj, t.np, "n");
  for (i = 0; i < t.nt; i++)
     {
       float           poly[6];
       int             ii = ordre[i];

       for (j = 0; j < 3; j++)
	  {
	    poly[2 * j] = proj[tt[ii][j]].x;
	    poly[2 * j + 1] = proj[tt[ii][j]].y;
	  }
       if (pp[tt[ii][0]].y < pp[tt[ii][1]].y)
	  {
	    p1 = tt[ii][0];
	    p2 = tt[ii][1];
	  }
       else
	  {
	    p2 = tt[ii][0];
	    p1 = tt[ii][1];
	  }
       if (pp[tt[ii][2]].y < pp[p2].y)
	 if (pp[tt[ii][2]].y < pp[p1].y)
	    {
	      p3 = p2;
	      p2 = p1;
	      p1 = tt[ii][2];
	    }
	 else
	    {
	      p3 = p2;
	      p2 = tt[ii][2];
	    }
       else
	 p3 = tt[ii][2];
       test = proj[p3].y * (proj[p1].x - proj[p2].x) +
	 proj[p3].x * (proj[p2].y - proj[p1].y) +
	 proj[p2].x * proj[p1].y - proj[p1].x * proj[p2].y;
       if (test <= 0)
	 if (proj[p2].x < proj[p1].x)
	   coul = coul2;
	 else
	   coul = coul1;
       else if (proj[p2].x > proj[p1].x)
	 coul = coul2;
       else
	 coul = coul1;
       if (i == 0 && coul == coul2)
	  {
	    int             exchg;

	    exchg = coul2;
	    coul = coul2 = coul1;
	    coul1 = exchg;
	  }
/*     couleurint(coul); */
       /*    raffpoly(3,poly); */
/*     couleur(4); */
       rmoveto (proj[tt[ii][2]].x, proj[tt[ii][2]].y);
       for (j = 0; j < 3; j++)
	  {
	    rlineto (proj[tt[ii][j]].x, proj[tt[ii][j]].y);
	  }
     }
  rattente (waitm);
  delete[]proj;
  proj = NULL;
  delete[]ordre;
  ordre = NULL;
}


void 
showtriangulation (int waitm)
{
  int             i, j;
  triangle       *tt = t.tr;
  rpoint         *pp = t.rp;

  Init (pp, t.np, "o");
  couleur (6);
  for (i = 0; i < t.nt; i++)
     {
       rmoveto (pp[tt[i][2]].x, pp[tt[i][2]].y);
       for (j = 0; j < 3; j++)
	 rlineto (pp[tt[i][j]].x, pp[tt[i][j]].y);
     }
  rattente (waitm);
}


void 
contour (int ng[], int coul)
{
  int             i = 0, j, jp;
  int             tj, tjp;
  triangle       *tt = t.tr;
  rpoint         *pp = t.rp;

  couleur (coul);
  for (; i < t.nt; i++)
    for (j = 0; j < 3; j++)
       {
	 jp = j + 1 == 3 ? 0 : j + 1;
	 tj = tt[i][j];
	 tjp = tt[i][jp];
	 if (ng[tj] != 0 && ng[tjp] != 0)
	    {
	      rmoveto (pp[tj].x, pp[tj].y);
	      rlineto (pp[tjp].x, pp[tjp].y);
	    }
       }
}


void 
equpot (int *ng, float *f, int nl, int waitm)
{
  float           qp[2][5];
  int             ns = t.np, nt = t.nt;
  triangle       *tr = t.tr;
  rpoint         *rp = t.rp;
  float           xln, fm, xf, xfm, fi, fj, xlam;
  int             im, i, j, k, l, ik, jk;

  Init (rp, ns, "o");
  contour (ng, 11);
  couleur (2);

  fm = f[0];			/*   search fmin and fmax */
  xfm = fm;
  for (i = 1; i <= ns; i++)
     {
       if (f[i - 1] > fm)
	 fm = f[i - 1];
       if (f[i - 1] < xfm)
	 xfm = f[i - 1];
     }
  if ((float) fabs (fm - xfm) < 1.0e-15)
    nl = 1;
  for (l = 1; l <= nl; l++)	/*    loop on the level curves */
     {
       if (nl == 1)
	 xln = 0.5F;
       else
	 xln = (l - 1.0F) / (nl - 1.0F);
       xf = xfm + (fm - xfm) * xln;
       for (k = 1; k <= nt; k++)	/*   loop on each triangle */
	  {
	    im = 0;
	    for (i = 0; i <= 2; i++)
	       {
		 j = ((i + 1) == 3 ? 0 : i + 1);
		 ik = tr[k - 1][i];
		 jk = tr[k - 1][j];
		 fi = realpart (f[ik]);
		 fj = realpart (f[jk]);
		 if (((fi <= xf) && (fj >= xf)) || ((fi >= xf) && (fj <= xf)))
		    {
		      if ((float) fabs (fi - fj) <= 0.1e-10)	/* one side must be drawn */
			 {
			   rmoveto (rp[ik].x, rp[ik].y);
			   rlineto (rp[jk].x, rp[jk].y);
			 }
		      else
			 {
			   xlam = (fi - xf) / (fi - fj);
			   im = im + 1;
			   qp[0][im] = rp[ik].x * (1.0F - xlam) + rp[jk].x * xlam;
			   qp[1][im] = rp[ik].y * (1.0F - xlam) + rp[jk].y * xlam;
			 }
		    }
	       }
	    if (im >= 2)	/*    draw one segment */
	       {
		 rmoveto (qp[0][1], qp[1][1]);
		 rlineto (qp[0][2], qp[1][2]);
	       }
	  }
     }
  xfmin = xfm; /* solution min */
  xfmax = fm; /* solution max */
  contour (ng, 11);
  rattente (waitm);
}

void 
equpotd (int *ng, float *f, int nl, int waitm)
{
  float           qp[2][5];
  int             ns = t.np, nt = t.nt;
  triangle       *tr = t.tr;
  rpoint         *rp = t.rp;
  float           xln, fm, xf, xfm, fi, fj, xlam;
  int             im, i, j, k, l, ik, jk;

  Init (rp, ns, "o");
  contour (ng, 11);
  couleur (2);

  fm = f[0];			/*   search fmin and fmax */
  xfm = fm;
  for (i = 1; i <= 3 * nt; i++)
     {
       if (f[i - 1] > fm)
	 fm = f[i - 1];
       if (f[i - 1] < xfm)
	 xfm = f[i - 1];
     }
  if ((float) fabs (fm - xfm) < 1.0e-15)
    nl = 1;
  for (k = 1; k <= nt; k++)	/*   loop on each triangle */
     {
       for (l = 1; l <= nl; l++)	/*    loop on the level curves */
	  {
	    if (nl == 1)
	      xln = 0.5F;
	    else
	      xln = (l - 1.0F) / (nl - 1.0F);
	    xf = xfm + (fm - xfm) * xln;
	    im = 0;
	    for (i = 0; i <= 2; i++)
	       {
		 j = ((i + 1) == 3 ? 0 : i + 1);
		 ik = tr[k - 1][i];
		 jk = tr[k - 1][j];
		 fi = realpart (f[3 * (k - 1) + i]);
		 fj = realpart (f[3 * (k - 1) + j]);
		 if (((fi <= xf) && (fj >= xf)) || ((fi >= xf) && (fj <= xf)))
		    {
		      if ((float) fabs (fi - fj) <= 0.1e-10)	/* one side must be drawn */
			 {
			   rmoveto (rp[ik].x, rp[ik].y);
			   rlineto (rp[jk].x, rp[jk].y);
			 }
		      else
			 {
			   xlam = (fi - xf) / (fi - fj);
			   im = im + 1;
			   qp[0][im] = rp[ik].x * (1.0F - xlam) + rp[jk].x * xlam;
			   qp[1][im] = rp[ik].y * (1.0F - xlam) + rp[jk].y * xlam;
			 }
		    }
	       }
	    if (im >= 2)	/*    draw one segment */
	       {
		 rmoveto (qp[0][1], qp[1][1]);
		 rlineto (qp[0][2], qp[1][2]);
	       }
	  }
     }
  contour (ng, 11);
  rattente (waitm);
}

void 
showbdy (long nbs, float *cr, long nba, long *arete, float *hh, int waitm)
{
  long            i;
  float           d, x, y, xmx = -(float)1e10, xmn = (float)1e10, ymx = -(float)1e10, ymn = (float)1e10;
  float           xctr, yctr, ray;

  for (i = 0; i < nbs; i++)
     {
       x = cr[2 * i];
       y = cr[2 * i + 1];
       xmx = x > xmx ? x : xmx;
       xmn = xmn > x ? x : xmn;
       ymx = y > ymx ? y : ymx;
       ymn = ymn > y ? y : ymn;
     }
  xctr = (xmx + xmn) / 2;
  yctr = (ymx + ymn) / 2;
  ray = (xmx - xctr) > (ymx - yctr) ? xmx - xctr : ymx - yctr;
  reffecran ();
  cadreortho (xctr, yctr, ray);
  for (i = 0; i < nbs; i++)
     {
       d = 0.1F * hh[i];
       rmoveto (cr[2 * i], cr[2 * i + 1]);
       rlineto (d + cr[2 * i], cr[2 * i + 1]);
       rlineto (d + cr[2 * i], d + cr[2 * i + 1]);
       rlineto (cr[2 * i], d + cr[2 * i + 1]);
       rlineto (cr[2 * i], cr[2 * i + 1]);
     }
  for (i = 0; i < nba; i++)
     {
       rmoveto (cr[2 * arete[2 * i]], cr[2 * arete[2 * i] + 1]);
       rlineto (cr[2 * arete[2 * i + 1]], cr[2 * arete[2 * i + 1] + 1]);
     }
  rattente (waitm);
}
