Skip to content
Snippets Groups Projects
Forked from gmsh / gmsh
17871 commits behind the upstream repository.
2D_Mesh_Aniso.cpp 28.97 KiB
// $Id: 2D_Mesh_Aniso.cpp,v 1.48 2006-01-29 22:53:41 geuzaine Exp $
//
// Copyright (C) 1997-2006 C. Geuzaine, J.-F. Remacle
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
// USA.
// 
// Please report all bugs and problems to <gmsh@geuz.org>.

// Anisotropic Delaunay mesh generator

#include "Gmsh.h"
#include "Numeric.h"
#include "Geo.h"
#include "CAD.h"
#include "Mesh.h"
#include "Interpolation.h"
#include "Create.h"
#include "Context.h"

extern Context_T CTX;
extern double LC2D;

inline void cgsmpl(Simplex * s, double &x, double &y)
{
  x = (1. / 3.) * (s->V[0]->Pos.X + s->V[1]->Pos.X + s->V[2]->Pos.X);
  y = (1. / 3.) * (s->V[0]->Pos.Y + s->V[1]->Pos.Y + s->V[2]->Pos.Y);
}

extern Simplex MyNewBoundary;
extern Mesh *THEM;
extern double MAXIMUM_LC_FOR_SURFACE;
extern int Alerte_Point_Scabreux;
extern PointRecord *gPointArray;
extern Surface *PARAMETRIC;

static Tree_T *Tsd, *Sim_Sur_Le_Bord;
static List_T *Simplexes_Destroyed, *Simplexes_New, *Suppress;
static Simplex *THES;
static Vertex *THEV;
static Surface *SURF;
static Tree_T *FacesTree;
static int ZONEELIMINEE, Methode = 0;
static double volume;
static List_T *coquille;
static Edge *THEEDGE;

double Interpole_lcTriangle(Simplex * s, Vertex * vv)
{
  double Xp, Yp, X[3], Y[3], det, u, v, q1, q2, q3;

  if(THEM->BackgroundMeshType == ONFILE){
    Vertex *v2 = Create_Vertex(-1, vv->Pos.X, vv->Pos.Y, 0.0, 0.0, 0.0);
    Vertex *dum;
    Calcule_Z_Plan(&v2, &dum);
    Projette_Inverse(&v2, &dum);
    double val = BGMXYZ(v2->Pos.X, v2->Pos.Y, v2->Pos.Z);
    Free_Vertex(&v2, 0);
    return val;
  }

  Xp = vv->Pos.X;
  Yp = vv->Pos.Y;

  X[0] = s->V[0]->Pos.X;
  X[1] = s->V[1]->Pos.X;
  X[2] = s->V[2]->Pos.X;

  Y[0] = s->V[0]->Pos.Y;
  Y[1] = s->V[1]->Pos.Y;
  Y[2] = s->V[2]->Pos.Y;

  q1 = s->V[0]->lc;
  q2 = s->V[1]->lc;
  q3 = s->V[2]->lc;

  det = (X[2] - X[0]) * (Y[1] - Y[0]) - (Y[2] - Y[0]) * (X[1] - X[0]);

  if(det != 0.0) {
    u = ((Xp - X[0]) * (Y[1] - Y[0]) - (Yp - Y[0]) * (X[1] - X[0])) / det;
    v = ((X[2] - X[0]) * (Yp - Y[0]) - (Y[2] - Y[0]) * (Xp - X[0])) / det;
  }
  else {
    u = v = 0.0;
  }
  return (q1 * (1. - u - v) + q2 * v + q3 * u);
}


/* Au sens Riemannien, trouver le centre de l'ellipse
   triangle de sommets (x1,x2,x3)

   T                   T
   (x-x1)  M (x-x1) = (x-x2)  M (x-x2)
   T                   T
   (x-x1)  M (x-x1) = (x-x3)  M (x-x3)
 */

void matXmat(int n, double mat1[3][3], double mat2[3][3], double Res[3][3])
{
  for(int i = 0; i < n; i++) {
    for(int j = 0; j < n; j++) {
      Res[i][j] = 0.0;
      for(int k = 0; k < n; k++)
        Res[i][j] += mat1[i][k] * mat2[k][j];
    }
  }
}

void TmatXmat(int n, double mat1[3][3], double mat2[3][3], double Res[3][3])
{
  for(int i = 0; i < n; i++) {
    for(int j = 0; j < n; j++) {
      Res[i][j] = 0.0;
      for(int k = 0; k < n; k++)
        Res[i][j] += mat1[k][i] * mat2[k][j];
    }
  }
}

Simplex *Create_Simplex_For2dmesh(Vertex * v1, Vertex * v2, Vertex * v3,
                                  Vertex * v4)
{
  Simplex *s;
  double p12, p23, p13;
  double srf = ((v2->Pos.X - v1->Pos.X) *
                (v3->Pos.Y - v2->Pos.Y) -
                (v3->Pos.X - v2->Pos.X) * (v2->Pos.Y - v1->Pos.Y));
  if(srf > 0)
    s = Create_Simplex(v3, v2, v1, v4);
  else
    s = Create_Simplex(v1, v2, v3, v4);

  THEM->Metric->setSimplexQuality(s, PARAMETRIC);

  if(PARAMETRIC) {
    if((!v2->ListCurves && !v3->ListCurves && !v3->ListCurves)) {
      prosca(v1->us, v2->us, &p12);
      p12 = fabs(p12);
      prosca(v1->us, v3->us, &p13);
      p13 = fabs(p13);
      prosca(v2->us, v3->us, &p23);
      p23 = fabs(p23);
      if(s->Quality < CONV_VALUE &&
         (p12 < THEM->Metric->min_cos || p13 < THEM->Metric->min_cos ||
          p23 < THEM->Metric->min_cos))
        s->Quality = 1.0;
    }
  }
  return s;
}

/*En l'honneur de ma femme Stephanie... */

void VSIM_2D(void *a, void *b)
{
  Simplex *S;

  S = *(Simplex **) a;
  if(S->V[2])
    volume += fabs(S->Volume_Simplexe2D());
}

void Box_2_Triangles(List_T * P, Surface * s)
{
#define FACT 1.1
#define LOIN 0.2

  int i, j;
  static int pts[4][2] = { {0, 0},
			   {1, 0},
			   {1, 1},
			   {0, 1} };
  static int tri[2][3] = { {1, 4, 2},
			   {2, 4, 3} };
  double Xm = 0., Ym = 0., XM = 0., YM = 0., Xc = 0., Yc = 0.;
  Simplex *S, *ps;
  Vertex *V, *v, *pv;
  List_T *smp;

  smp = List_Create(2, 1, sizeof(Simplex *));

  V = (Vertex *) Malloc(4 * sizeof(Vertex));

  for(i = 0; i < List_Nbr(P); i++) {
    List_Read(P, i, &v);
    if(!i) {
      Xm = XM = v->Pos.X;
      Ym = YM = v->Pos.Y;
    }
    else {
      Xm = DMIN(Xm, v->Pos.X);
      XM = DMAX(XM, v->Pos.X);
      Ym = DMIN(Ym, v->Pos.Y);
      YM = DMAX(YM, v->Pos.Y);
    }
  }
  if(Xm == XM)
    XM = Xm + 1.;
  if(Ym == YM)
    YM = Ym + 1.;

  Xc = XM - Xm;
  Yc = YM - Ym;

  /* Longueur Caracteristique */

  LC2D = sqrt(Xc * Xc + Yc * Yc);

  for(i = 0; i < 4; i++) {
    if(pts[i][0])
      V[i].Freeze.X = V[i].Pos.X = Xm - LOIN * Xc;
    else
      V[i].Freeze.X = V[i].Pos.X = XM + LOIN * Xc;
    if(pts[i][1])
      V[i].Freeze.Y = V[i].Pos.Y = Ym - LOIN * Yc;
    else
      V[i].Freeze.Y = V[i].Pos.Y = YM + LOIN * Yc;

    V[i].Freeze.Z = V[i].Pos.Z = 0.0;

    V[i].Num = -(++THEM->MaxPointNum);
    V[i].ListSurf = NULL;
    pv = &V[i];
    pv->lc = 1.0;
    pv->Mov = NULL;
    Tree_Replace(s->Vertices, &pv);
  }

  /* 2 Triangles forment le maillage de la boite */

  for(i = 0; i < 2; i++) {
    S = Create_Simplex_For2dmesh(&V[tri[i][0] - 1], &V[tri[i][1] - 1],
                                 &V[tri[i][2] - 1], NULL);
    List_Add(smp, &S);
    S->iEnt = s->Num;
  }

  Link_Simplexes(smp, NULL);
  for(i = 0; i < List_Nbr(smp); i++) {
    List_Read(smp, i, &ps);
    for(j = 0; j < 3; j++)
      if(ps->S[j] == NULL)
        ps->S[j] = &MyNewBoundary;
    Tree_Replace(s->Simplexes, &ps);
  }

  List_Delete(smp);

}


int Intersect_Edges_2d(Edge * a, Edge * b)
{
  double mat[2][2];
  double rhs[2], x[2];
  mat[0][0] = (a->V[1]->Pos.X - a->V[0]->Pos.X);
  mat[0][1] = -(b->V[1]->Pos.X - b->V[0]->Pos.X);
  mat[1][0] = (a->V[1]->Pos.Y - a->V[0]->Pos.Y);
  mat[1][1] = -(b->V[1]->Pos.Y - b->V[0]->Pos.Y);
  rhs[0] = b->V[0]->Pos.X - a->V[0]->Pos.X;
  rhs[1] = b->V[0]->Pos.Y - a->V[0]->Pos.Y;
  if(!sys2x2(mat, rhs, x))
    return 0;
  if(x[0] > 0.0 && x[0] < 1.0 && x[1] > 0.0 && x[1] < 1.0)
    return 1;
  return 0;
}

void putaindecoquille_2D(void *a, void *b)
{
  Edge *e = (Edge *) a;
  if(!compareVertex(&e->V[0], &THEEDGE->V[0]) ||
     !compareVertex(&e->V[0], &THEEDGE->V[1]) ||
     !compareVertex(&e->V[1], &THEEDGE->V[0]) ||
     !compareVertex(&e->V[1], &THEEDGE->V[1])) {
    return;
  }
  if(Intersect_Edges_2d(e, THEEDGE))
    List_Add(coquille, &e);
}

void Recover_Edge(Surface * s, Edge * e, EdgesContainer & Edges)
{
  THEEDGE = e;
  int i;
  Edge *me, E;
  Vertex *v[2];

  coquille = List_Create(3, 3, sizeof(Edge *));
  /*On cherche la coquille */
  Tree_Action(Edges.AllEdges, putaindecoquille_2D);
  Msg(INFO, "Edge %d->%d, %d intersections",
      e->V[0]->Num, e->V[1]->Num, List_Nbr(coquille));

  if(List_Nbr(coquille) == 1) {
    Msg(WARNING, "Unable to swap edge");
    List_Delete(coquille);
    return;
  }

  /*on swappe au hasard jusqu'a ce qu l'arete soit recuperee */
  while(List_Nbr(coquille)) {

    i = (int)(List_Nbr(coquille) * rand() / (RAND_MAX + 1.0));
    //i = rand () % List_Nbr (coquille);
    List_Read(coquille, i, &me);
    v[0] = me->V[0];
    v[1] = me->V[1];
    List_Suppress(coquille, &me, compareEdgePtr);
    Edges.SwapEdge(v);
    if(Edges.Search(e->V[0], e->V[1]))
      break;
    E.V[0] = v[0];
    E.V[1] = v[1];
    me = (Edge *) Tree_PQuery(Edges.AllEdges, &E);
    putaindecoquille_2D(me, NULL);
  }

  List_Delete(coquille);

  Msg(INFO, "Edge recovered");
  /*On swappe */
}

void constraint_the_edge(int isurf, int iv1, int iv2)
{
  Vertex *v1 = FindVertex(iv1, THEM);
  Vertex *v2 = FindVertex(iv2, THEM);
  Surface *s = FindSurface(isurf, THEM);
  Edge e;

  if(!v1 || !v2)
    return;
  EdgesContainer EdgesOnSurface(s->Simplexes);
  e.V[0] = v1;
  e.V[1] = v2;
  if(!EdgesOnSurface.Search(v1, v2)) {
    Recover_Edge(s, &e, EdgesOnSurface);
  }
}

void missing_edges_2d(Surface * s)
{
  int i, j;
  Curve *c;
  Vertex *v1, *v2;
  Edge e;

  EdgesContainer EdgesOnSurface(s->Simplexes);

  for(i = 0; i < List_Nbr(s->Generatrices); i++) {
    List_Read(s->Generatrices, i, &c);
    for(j = 1; j < List_Nbr(c->Vertices); j++) {
      List_Read(c->Vertices, j - 1, &v1);
      List_Read(c->Vertices, j, &v2);
      e.V[0] = v1;
      e.V[1] = v2;
      if(!EdgesOnSurface.Search(v1, v2)) {
        Msg(INFO, "Missing edge %d->%d", v1->Num, v2->Num);
        Recover_Edge(s, &e, EdgesOnSurface);
      }
    }
  }
}

int Restore_Boundary(Surface * s)
{
  missing_edges_2d(s);
  return 1;
}

int Maillage_Edge(Vertex * v1, Vertex * v2, List_T * Points)
{
  int i;
  static int qq = 1;
  Simplex S, *s;

  s = &S;
  s->F[0].V[0] = v1;
  s->F[0].V[1] = v2;

  if(Tree_Search(FacesTree, &s))
    return 0;

  s = Create_Simplex_For2dmesh(v1, v2, NULL, NULL);
  Tree_Add(FacesTree, &s);

  Curve *c = Create_Curve(qq++, MSH_SEGM_LINE, 1, NULL, NULL, -1, -1, 0, 1);
  Vertex *v;
  c->Control_Points = List_Create(2, 1, sizeof(Vertex *));
  List_Add(c->Control_Points, &v1);
  List_Add(c->Control_Points, &v2);
  c->beg = v1;
  c->end = v2;
  Maillage_Curve(&c, NULL);
  for(i = 1; i < List_Nbr(c->Vertices) - 1; i++) {
    List_Read(c->Vertices, i, &v);
    List_Delete(v->ListCurves);
    v->ListCurves = NULL;
    List_Add(Points, &v);
  }
  List_Delete(c->Vertices);
  List_Delete(c->Control_Points);
  Free_Curve(&c, 0);
  return 1;
}
void Action_First_Simplexes_2D(void *a, void *b)
{
  Simplex *q;

  if(!THES) {
    q = *(Simplex **) a;
    if(q->Pt_In_Ellipse(THEV, THEM->Metric->m)) {
      THES = q;
    }
  }
}

void Fill_Sim_Des_2D(void *a, void *b)
{
  Simplex *S;
  S = *(Simplex **) a;
  if(S->Pt_In_Ellipse(THEV, THEM->Metric->m))
    List_Add(Simplexes_Destroyed, a);
}

void TStoLS_2D(void *a, void *b)
{
  List_Add(Simplexes_Destroyed, a);
}

void TAtoLA_2D(void *a, void *b)
{
  List_Add(Simplexes_New, a);
}

void CrSi_2D(void *a, void *b)
{
  SxF *S;
  Simplex *s;
  S = (SxF *) a;
  if(S->NumFaceSimpl == 1) {
    s = Create_Simplex_For2dmesh(THEV, S->F.V[0], S->F.V[1], NULL);
    s->iEnt = ZONEELIMINEE;
    List_Add(Simplexes_New, &s);
  }
  else if(S->NumFaceSimpl != 2) {
    Msg(GERROR, "Panic in CrSi_2D...");
  }
}

void NewSimplexes_2D(Surface * s, List_T * Sim, List_T * news)
{
  int i, j;
  Tree_T *SimXFac;
  Simplex *S;
  SxF SXF, *pSXF;

  SimXFac = Tree_Create(sizeof(SxF), compareSxF);

  for(i = 0; i < List_Nbr(Sim); i++) {
    List_Read(Sim, i, &S);
    if(!i)
      ZONEELIMINEE = S->iEnt;
    else {
      if(S->iEnt != ZONEELIMINEE) {
        Msg(WARNING, "Huh! The elimination failed %d %d",
            S->iEnt, ZONEELIMINEE);
      }
    }
    for(j = 0; j < 3; j++) {
      SXF.F = S->F[j];

      if((pSXF = (SxF *) Tree_PQuery(SimXFac, &SXF))) {
        (pSXF->NumFaceSimpl)++;
      }
      else {
        SXF.NumFaceSimpl = 1;
        Tree_Add(SimXFac, &SXF);
      }
    }
  }

  /* Les faces non communes sont obligatoirement a la frontiere ...
     -> Nouveaux simplexes */

  Tree_Action(SimXFac, CrSi_2D);
  Tree_Delete(SimXFac);
}

int recur_bowyer_2D(Simplex * s)
{
  int i;

  Tree_Insert(Tsd, &s);
  for(i = 0; i < 3; i++) {
    if(s->S[i] && s->S[i] != &MyNewBoundary && !Tree_Query(Tsd, &s->S[i])) {
      if(s->S[i]->Pt_In_Ellipse(THEV, THEM->Metric->m)
         && (s->iEnt == s->S[i]->iEnt)) {
        recur_bowyer_2D(s->S[i]);
      }
      else {
        if(s->iEnt != s->S[i]->iEnt) {
          Alerte_Point_Scabreux = 1;
        }
        Tree_Insert(Sim_Sur_Le_Bord, &s->S[i]);
      }
    }
  }
  return 1;
}


bool draw_simplex2d(Surface * sur, Simplex * s, bool nouv)
{
  Vertex v1, v2, v3;

  if(!CTX.mesh.interactive)
    return false;

  if(s == &MyNewBoundary || !s || !s->iEnt)
    return false;

  v1 = InterpolateSurface(sur->Support, s->V[0]->Pos.X, s->V[0]->Pos.Y, 0, 0);
  v2 = InterpolateSurface(sur->Support, s->V[1]->Pos.X, s->V[1]->Pos.Y, 0, 0);
  v3 = InterpolateSurface(sur->Support, s->V[2]->Pos.X, s->V[2]->Pos.Y, 0, 0);

#if defined(HAVE_FLTK)
  double x[3], y[3], z[3];
  x[0] = v1.Pos.X;
  x[1] = v2.Pos.X;
  x[2] = v3.Pos.X;
  y[0] = v1.Pos.Y;
  y[1] = v2.Pos.Y;
  y[2] = v3.Pos.Y;
  z[0] = v1.Pos.Z;
  z[1] = v2.Pos.Z;
  z[2] = v3.Pos.Z;
  void draw_polygon_2d(double r, double g, double b, int n,
                       double *x, double *y, double *z);
  if(nouv)
    draw_polygon_2d(1., 0., 0., 3, x, y, z);
  else
    draw_polygon_2d(0., 0., 0., 3, x, y, z);
#endif
  return true;
}

bool Bowyer_Watson_2D(Surface * sur, Vertex * v, Simplex * S, int force)
{
  int i;
  Simplex *s;
  static int init = 1;
  double volumeold, volumenew;

  THEV = v;

  double x = (S->V[0]->Pos.X + S->V[1]->Pos.X + S->V[2]->Pos.X) / 3.;
  double y = (S->V[0]->Pos.Y + S->V[1]->Pos.Y + S->V[2]->Pos.Y) / 3.;

  if(force)
    THEM->Metric->setMetricMin(x, y, sur->Support);
  else
    THEM->Metric->setMetric(x, y, sur->Support);

  Tsd = Tree_Create(sizeof(Simplex *), compareSimplex);
  Sim_Sur_Le_Bord = Tree_Create(sizeof(Simplex *), compareSimplex);
  if(init) {
    Simplexes_New = List_Create(10, 10, sizeof(Simplex *));
    Simplexes_Destroyed = List_Create(10, 10, sizeof(Simplex *));
    init = 0;
  }

  if(Methode) {
    Tree_Action(sur->Simplexes, Fill_Sim_Des_2D);
    S = NULL;
  }
  else {
    recur_bowyer_2D(S);
  }

  Tree_Action(Tsd, TStoLS_2D);
  NewSimplexes_2D(sur, Simplexes_Destroyed, Simplexes_New);

  /* calcul des volumes des simplexes crees */

  if(Alerte_Point_Scabreux || !CTX.mesh.speed_max) {
    volume = 0.0;
    for(i = 0; i < List_Nbr(Simplexes_Destroyed); i++) {
      VSIM_2D(List_Pointer(Simplexes_Destroyed, i), NULL);
    }
    volumeold = volume;
    volume = 0.0;
    for(i = 0; i < List_Nbr(Simplexes_New); i++) {
      VSIM_2D(List_Pointer(Simplexes_New, i), NULL);
    }
    volumenew = volume;
    if(volumeold + volumenew == 0.0)
      volumenew = 1.0;
  }
  else {
    volumeold = 1.0;
    volumenew = 1.0;
  }

  /* critere du volume */

  if((fabs(volumeold - volumenew) / (volumeold + volumenew)) > 1.e-8) {
    if(S) {
      Tree_Suppress(sur->Simplexes, &S);
      S->Quality /= 2.;
      Tree_Add(sur->Simplexes, &S);
    }
    if(force) {
      List_Reset(Simplexes_New);
      List_Reset(Simplexes_Destroyed);
      Tree_Delete(Sim_Sur_Le_Bord);
      Tree_Delete(Tsd);
      return false;
    }
  }
  else {
    Tree_Add(sur->Vertices, &THEV);

    /* Suppression des simplexes elimines */
    for(i = 0; i < List_Nbr(Simplexes_Destroyed); i++) {
      List_Read(Simplexes_Destroyed, i, &s);
      draw_simplex2d(sur, s, 0);
      if(!Tree_Suppress(sur->Simplexes, &s)) {
        Msg(WARNING, "Failed to suppress simplex %d", s->Num);
      }
      Free_Simplex(&s, 0);
    }
    for(i = 0; i < List_Nbr(Simplexes_New); i++) {
      List_Read(Simplexes_New, i, &s);
      if(0 || !force) {
        double xc = s->Center.X;
        double yc = s->Center.Y;
        double rd = s->Radius;
        cgsmpl(s, x, y);
        THEM->Metric->setMetric(x, y, sur->Support);
        THEM->Metric->setSimplexQuality(s, sur->Support);
        s->Center.X = xc;
        s->Center.Y = yc;
        s->Radius = rd;
        if(force)
          THEM->Metric->Identity();
      }
      draw_simplex2d(sur, s, 1);
      Tree_Add(sur->Simplexes, &s);
    }

    /* Creation des liens entre nouveaux simplexes */

    Tree_Action(Sim_Sur_Le_Bord, TAtoLA_2D);
    Link_Simplexes(Simplexes_New, sur->Simplexes);
  }

  List_Reset(Simplexes_New);
  List_Reset(Simplexes_Destroyed);
  Tree_Delete(Sim_Sur_Le_Bord);
  Tree_Delete(Tsd);
  return true;
}

void Convex_Hull_Mesh_2D(List_T * Points, Surface * s)
{
  int i, N;

  N = List_Nbr(Points);

  Box_2_Triangles(Points, s);
  for(i = 0; i < N; i++) {
    THES = NULL;
    List_Read(Points, i, &THEV);
    Tree_Action(s->Simplexes, Action_First_Simplexes_2D);
    /*
       if(i%n == n-1){
       volume = 0.0;
       Tree_Action(s->Simplexes,VSIM_2D);
       Msg(STATUS3, %d->%d Nodes, %d Elements",i+1,N,Tree_Nbr(s->Simplexes));
       } 
     */
    if(!THES) {
      Msg(GERROR, "Vertex (%g,%g,%g) in no simplex", THEV->Pos.X, THEV->Pos.Y,
          THEV->Pos.Z);
      THEV->Pos.X +=
        CTX.mesh.rand_factor * LC2D * (1. -
                                       (double)rand() / (double)RAND_MAX);
      THEV->Pos.Y +=
        CTX.mesh.rand_factor * LC2D * (1. -
                                       (double)rand() / (double)RAND_MAX);
      THEV->Pos.Z +=
        CTX.mesh.rand_factor * LC2D * (1. -
                                       (double)rand() / (double)RAND_MAX);
      Tree_Action(s->Simplexes, Action_First_Simplexes_2D);
    }
    bool ca_marche = Bowyer_Watson_2D(s, THEV, THES, 1);
    while(!ca_marche) {
      double dx =
        CTX.mesh.rand_factor * LC2D * (1. -
                                       (double)rand() / (double)RAND_MAX);
      double dy =
        CTX.mesh.rand_factor * LC2D * (1. -
                                       (double)rand() / (double)RAND_MAX);
      THEV->Pos.X += dx;
      THEV->Pos.Y += dy;
      ca_marche = Bowyer_Watson_2D(s, THEV, THES, 1);
      THEV->Pos.X -= dx;
      THEV->Pos.Y -= dy;
    }
  }

}

/* recuperation de la surface */

static List_T *ListCurves, *ListAllCurves;
static Tree_T *keep;
static Simplex *SIMP;
static int iSurface;

void attribueSurface(void *a, void *b)
{
  Simplex *s;
  s = *(Simplex **) a;
  s->iEnt = iSurface;
}

void Trouve_Simplex_2D(void *a, void *b)
{
  Simplex *s;
  if(SIMP != NULL)
    return;
  s = *(Simplex **) a;
  if(s->iEnt < 0)
    SIMP = s;
}

void Trouve_Simplex_Bord_2D(void *a, void *b)
{
  Simplex *s;

  if(SIMP != NULL)
    return;
  s = *(Simplex **) a;
  if(s->V[0]->Num < 0 || s->V[1]->Num < 0 || s->V[2]->Num < 0)
    SIMP = s;
}

void CourbesDansSurface(Surface * s, List_T * ListAllCurves)
{
  int i, iseg;
  Curve *c;
  for(i = 0; i < List_Nbr(s->Generatrices); i++) {
    List_Read(s->Generatrices, i, &c);
    iseg = abs(c->Num);
    List_Replace(ListAllCurves, &iseg, fcmp_int);
  }
}

int isListaSurface(List_T * ListSurf, Surface * s)
{
  int NN, j, srf;
  bool found;
  Curve *c;
  NN = 0;
  found = true;
  for(j = 0; j < List_Nbr(s->Generatrices); j++) {
    List_Read(s->Generatrices, j, &c);
    srf = abs(c->Num);
    if(!List_Search(ListSurf, &srf, fcmp_int)) {
      found = false;
    }
    else
      NN++;
  }
  if(found && NN == List_Nbr(ListSurf))
    return s->Num;
  return 0;
}

static List_T *StackSimp;
#define MAX_DEPTH 500

void recur_trouve_surface(Simplex * s, int *Depth)
{
  int i, j;
  Simplex *pS, S;

  if(s->iEnt != -1)
    return;

  if((*Depth) > MAX_DEPTH) {
    List_Add(StackSimp, &s);
    return;
  }

  (*Depth)++;
  s->iEnt = -2;
  Tree_Add(keep, &s);
  for(i = 0; i < 3; i++) {
    pS = &S;
    pS->F[0] = s->F[i];
    if(Tree_Query(FacesTree, &pS)
       && List_Search(ListAllCurves, &pS->iEnt, fcmp_int)) {
      j = abs(pS->iEnt);
      List_Replace(ListCurves, &j, fcmp_int);
    }
    else if(s->S[i] && s->S[i] != &MyNewBoundary) {
      recur_trouve_surface(s->S[i], Depth);
    }
  }
  (*Depth)--;
}

extern int compareSimpSurf(const void *a, const void *b);

void Restore_Surface(Surface * s)
{
  int N;
  int i, depth;

  StackSimp = List_Create(100, 100, sizeof(Simplex *));
  ListCurves = List_Create(2, 2, sizeof(int));
  iSurface = -1;
  Tree_Action(s->Simplexes, attribueSurface);

  /* Les simplexes sur le bord exterieur sont elimines */
  ListAllCurves = List_Create(10, 3, sizeof(int));
  CourbesDansSurface(s, ListAllCurves);


  SIMP = NULL;
  Tree_Action(s->Simplexes, Trouve_Simplex_Bord_2D);

  if(SIMP) {
    List_Add(StackSimp, &SIMP);
    keep = Tree_Create(sizeof(Simplex *), compareQuality);
    depth = 0;
    i = 0;
    do {
      List_Read(StackSimp, i, &SIMP);
      recur_trouve_surface(SIMP, &depth);
    }
    while(++i < List_Nbr(StackSimp));
    List_Reset(StackSimp);

    N = Tree_Nbr(keep);

    iSurface = 0;
    Tree_Action(keep, attribueSurface);
    Tree_Delete(keep);
    List_Reset(ListCurves);
  }

  while(1) {
    SIMP = NULL;
    keep = Tree_Create(sizeof(Simplex *), compareQuality);
    Tree_Action(s->Simplexes, Trouve_Simplex_2D);
    if(!SIMP)
      break;
    List_Add(StackSimp, &SIMP);
    depth = 0;
    i = 0;
    do {
      List_Read(StackSimp, i, &SIMP);
      recur_trouve_surface(SIMP, &depth);
    } while(++i < List_Nbr(StackSimp));

    iSurface = isListaSurface(ListCurves, s);

    N = Tree_Nbr(keep);
    Msg(INFO,
        "Initial mesh of Surface %d: %d simplices, %d/%d curves, %d faces",
        iSurface, N, List_Nbr(ListCurves), List_Nbr(ListAllCurves),
        Tree_Nbr(FacesTree));

    Tree_Action(keep, attribueSurface);
    Tree_Delete(keep);
    List_Reset(ListCurves);
    List_Reset(StackSimp);
  }
  // MEMORY LEAK (JF)
  List_Delete(StackSimp);
  List_Delete(ListCurves);
  List_Delete(ListAllCurves);

}

void suppress_simplex_2D(void *data, void *dum)
{
  Simplex **pv;

  pv = (Simplex **) data;
  if((*pv)->iEnt == 0)
    List_Add(Suppress, pv);
}

Vertex *NewVertex_2D(Simplex * s)
{
  Vertex *v = NULL;
  double lc;
  lc = (s->V[0]->lc + s->V[1]->lc + s->V[2]->lc) / 3.;

  //lc = DMIN(MAXIMUM_LC_FOR_SURFACE,lc);

  /*v = Create_Vertex(  ++THEM->MaxPointNum,
     (s->V[0]->Pos.X + s->V[1]->Pos.X + s->V[2]->Pos.X)/3.,
     (s->V[0]->Pos.Y + s->V[1]->Pos.Y + s->V[2]->Pos.Y)/3.,
     0.0, lc, 0.0);
   */

  if(1){ // INSERTION_CENTROID
    v = Create_Vertex(++THEM->MaxPointNum, s->Center.X, s->Center.Y, 0.0, lc, 0.0);
  }
  else{ // INSERTION_EDGE
    Vertex *vv[2];
    double l = THEM->Metric->getWorstEdge(s, PARAMETRIC, vv);
    double f = 0.5;

    if(vv[0]->lc <= vv[1]->lc)
      f = vv[0]->lc / l;
    else
      f = 1. - (vv[1]->lc / l);

    if(f >= 1)
      v =
        Create_Vertex(++THEM->MaxPointNum, s->Center.X, s->Center.Y, 0.0, lc,
                      0.0);
    else
      v = Create_Vertex(++THEM->MaxPointNum,
                        f * vv[0]->Pos.X + (1. - f) * vv[1]->Pos.X,
                        f * vv[0]->Pos.Y + (1. - f) * vv[1]->Pos.Y, 0.0, lc,
                        0.0);
  }

  v->lc = Interpole_lcTriangle(s, v);

  if(PARAMETRIC) {
    if(!v->ListCurves)
      Normal2Surface(PARAMETRIC->Support, v->Pos.X, v->Pos.Y, v->us);
    else {
      v->us[0] = v->us[1] = v->us[2] = 0.0;
    }
  }
  return (v);
}

void TRIE_MON_GARS(void *a, void *b)
{
  Simplex *s = *(Simplex **) a;
  s->Fourre_Simplexe(s->V[0], s->V[1], s->V[2], s->V[3]);
  s->iEnt = SURF->Num;
  s->S[0] = s->S[1] = s->S[2] = NULL;
  THEM->Metric->setSimplexQuality(s, PARAMETRIC);
  //SURF->Num;
  //qsort(s->F[0].V,3,sizeof(Vertex*),compareVertex);
}

void RandomSwapEdges2d(Surface * s)
{
  int i, j = 1, k;
  List_T *AllTrg = Tree2List(s->Simplexes);
  Simplex *t;
  for(i = 0; i < List_Nbr(AllTrg); i++) {
    k = rand() % List_Nbr(AllTrg);
    List_Read(AllTrg, k, &t);
    j = rand() % 3;
    if(draw_simplex2d(s, t, false))
      draw_simplex2d(s, t->S[j], false);
    t->SwapEdge(j);
    if(draw_simplex2d(s, t, true))
      draw_simplex2d(s, t->S[j], true);
  }
}

void IntelligentSwapEdges(Surface * s, GMSHMetric * m)
{
  int i, j, k;
  List_T *AllTrg = Tree2List(s->Simplexes);
  Vertex *p[4], *q[4];
  Simplex *t;
  for(i = 0; i < List_Nbr(AllTrg); i++) {
    k = rand() % List_Nbr(AllTrg);
    List_Read(AllTrg, k, &t);
    j = rand() % 3;
    if(t->ExtractOppositeEdges(j, p, q)) {
      double qp = 2. * m->EdgeLengthOnSurface(s, p, 1)
        / (RacineDeTrois * (p[0]->lc + p[1]->lc));
      double qq = 2. * m->EdgeLengthOnSurface(s, q, 1)
        / (RacineDeTrois * (q[0]->lc + q[1]->lc));
      if(fabs(qp) > fabs(qq)) {
        if(draw_simplex2d(s, t, false))
          draw_simplex2d(s, t->S[j], false);
        t->SwapEdge(j);
        if(draw_simplex2d(s, t, true))
          draw_simplex2d(s, t->S[j], true);
      }
    }
  }
  List_Delete(AllTrg);
}

int AlgorithmeMaillage2DAnisotropeModeJF(Surface * s)
{
  List_T *Points = List_Create(100, 100, sizeof(Vertex *));
  int j, i, N, n;
  List_T *c;
  Curve *cur, *curinv;
  extern int FACE_DIMENSION;
  Simplex *simp;
  Vertex *newv;
  static int COUNT = 0;

  FACE_DIMENSION = 1;

  SURF = s;

  if(s->Typ == MSH_SURF_PLAN || s->Typ == MSH_SURF_REGL
     || s->Typ == MSH_SURF_TRIC)
    PARAMETRIC = NULL;

  ZONEELIMINEE = s->Num;

  for(i = 0; i < List_Nbr(s->Contours); i++) {
    List_Read(s->Contours, i, &c);
    for(j = 0; j < List_Nbr(c); j++) {
      Vertex *pv;
      List_Read(c, j, &pv);
      List_Add(Points, &pv);
    }
  }

  N = List_Nbr(Points);
  n = N + 100;

  Msg(STATUS2, "Mesh 2D... (initial)");

  Convex_Hull_Mesh_2D(Points, s);
  List_Reset(Points);
  Link_Simplexes(NULL, s->Simplexes);

  //return 1;

  if(!Restore_Boundary(s)) {
    //s->Simplexes = Tree_Create(sizeof(Simplex*),compareSimplex);
    FACE_DIMENSION = 2;
    Tree_Action(s->Simplexes, TRIE_MON_GARS);
    return 1;
  }

  Tree_Action(s->Simplexes, TRIE_MON_GARS);
  Link_Simplexes(NULL, s->Simplexes);
  List_T *List = Tree2List(s->Simplexes);
  Tree_Delete(s->Simplexes);
  s->Simplexes = Tree_Create(sizeof(Simplex *), compareQuality);
  for(i = 0; i < List_Nbr(List); i++)
    Tree_Add(s->Simplexes, List_Pointer(List, i));
  List_Delete(List);

  //  return 1;

  FacesTree = Tree_Create(sizeof(Simplex *), compareSimpSurf);
  for(i = 0; i < List_Nbr(s->Generatrices); i++) {
    List_Read(s->Generatrices, i, &cur);
    curinv = FindCurve(abs(cur->Num), THEM);
    List_T *temp = Tree2List(curinv->Simplexes);
    for(j = 0; j < List_Nbr(temp); j++) {
      Tree_Add(FacesTree, List_Pointer(temp, j));
    }
    List_Delete(temp);
  }

  Restore_Surface(s);

  // MEMORY LEAK (JF)
  Tree_Delete(FacesTree);

  Suppress = List_Create(10, 10, sizeof(Simplex *));
  Tree_Action(s->Simplexes, suppress_simplex_2D);
  for(i = 0; i < List_Nbr(Suppress); i++) {
    Tree_Suppress(s->Simplexes, List_Pointer(Suppress, i));
  }

  Msg(STATUS2, "Mesh 2D... (final)");

  if(!Tree_Right(s->Simplexes, &simp))
    Msg(WARNING, "No simplex left");
  else {
    i = 0;
    while(simp->Quality > CONV_VALUE) {
      newv = NewVertex_2D(simp);
      while(!simp->Pt_In_Simplex_2D(newv) &&
            (simp->S[0] == &MyNewBoundary
             || !simp->S[0]->Pt_In_Simplex_2D(newv))
            && (simp->S[1] == &MyNewBoundary
                || !simp->S[1]->Pt_In_Simplex_2D(newv))
            && (simp->S[2] == &MyNewBoundary
                || !simp->S[2]->Pt_In_Simplex_2D(newv))) {
        /*
           Msg(INFO,"pt : %12.5E %12.5E",newv->Pos.X,newv->Pos.Y);
           Msg(INFO,"not in : (%12.5E %12.5E) (%12.5E %12.5E) (%12.5E %12.5E)",
           simp->V[0]->Pos.X,simp->V[0]->Pos.Y,simp->V[1]->Pos.X,
           simp->V[1]->Pos.Y,simp->V[2]->Pos.X,simp->V[2]->Pos.Y);
         */
        Tree_Suppress(s->Simplexes, &simp);
        simp->Quality /= 2.;
        Tree_Insert(s->Simplexes, &simp);
        Tree_Right(s->Simplexes, &simp);
        if(simp->Quality < CONV_VALUE)
          break;
        newv = NewVertex_2D(simp);
      }
      if(simp->Quality < CONV_VALUE)
        break;
      i++;
      if(i % n == n - 1) {
        volume = 0.0;
        Tree_Action(s->Simplexes, VSIM_2D);
        Msg(STATUS3, "Nod=%d Elm=%d",
            Tree_Nbr(s->Vertices), Tree_Nbr(s->Simplexes));
        Msg(STATUS1, "Vol(%g) Conv(%g->%g)", volume, simp->Quality,
            CONV_VALUE);
      }
      Bowyer_Watson_2D(s, newv, simp, 0);
      Tree_Right(s->Simplexes, &simp);
      //if(i>COUNT)break;
    }
  }

  //for(i=0;i<3;i++)RandomSwapEdges2d(s);
  //for(i=0;i<2;i++)IntelligentSwapEdges(s,THEM->Metric);

  List_Reset(Points);
  FACE_DIMENSION = 2;
  COUNT++;

  Tree_Action(s->Simplexes, TRIE_MON_GARS);
  Link_Simplexes(NULL, s->Simplexes);
  List = Tree2List(s->Simplexes);
  Tree_Delete(s->Simplexes);
  s->Simplexes = Tree_Create(sizeof(Simplex *), compareSimplex);
  for(i = 0; i < List_Nbr(List); i++)
    Tree_Add(s->Simplexes, List_Pointer(List, i));
  List_Delete(List);

  /*suppression des points de la boite */
  List = Tree2List(s->Vertices);
  for(i = 0; i < List_Nbr(List); i++) {
    List_Read(List, i, &THEV);
    if(THEV->Num < 0) {
      Tree_Suppress(s->Vertices, &THEV);
      // BUG BUG BUG BUG BUG BUG BUG BUG BUG BUG BUG BUG 
      // MEMORY LEAK (JF) BUT THIS CAUSES PROBLEMS AFTER !!      
      // Free(THEV);
      // BUG BUG BUG BUG BUG BUG BUG BUG BUG BUG BUG BUG 
    }
  }
  List_Delete(List);

  if(!Tree_Nbr(s->Simplexes))
    Msg(GERROR, "No triangles in surface %d", s->Num);

  /*
     RandomSwapEdges2d(s);
     for(i=0;i<1;i++)IntelligentSwapEdges(s,THEM->Metric);
   */
  //IntelligentSwapEdges(s,THEM->Metric);

  List_Delete(Points);


  // WAS A MEMORY LEAK
  for(i = 0; i < List_Nbr(Suppress); i++) {
    Free_Simplex(List_Pointer(Suppress, i), 0);
  }
  List_Delete(Suppress);


  return 1;
}