Skip to content
Snippets Groups Projects
Select Git revision
  • 7c3cf4b70a1870fe4e8c4403e760f6d372f68041
  • master default
  • library-names
  • fix_script_header
  • fix_libdir
  • fix_cmake_hdf5
  • partition
  • cgnsUnstructured
  • partitioning
  • HighOrderBLCurving
  • gmsh_3_0_5
  • gmsh_3_0_4
  • gmsh_3_0_3
  • gmsh_3_0_2
  • gmsh_3_0_1
  • gmsh_3_0_0
  • gmsh_2_16_0
  • gmsh_2_15_0
  • gmsh_2_14_1
  • gmsh_2_14_0
  • gmsh_2_13_2
  • gmsh_2_13_1
  • gmsh_2_12_0
  • gmsh_2_11_0
  • gmsh_2_10_1
  • gmsh_2_10_0
  • gmsh_2_9_3
  • gmsh_2_9_2
  • gmsh_2_9_1
  • gmsh_2_9_0
30 results

3D_Mesh_Old.cpp

Blame
  • Forked from gmsh / gmsh
    Source project has a limited visibility.
    3D_Mesh_Old.cpp 20.46 KiB
    // $Id: 3D_Mesh_Old.cpp,v 1.16 2006-01-28 18:44:19 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>.
    
    /*
      Isotropic Delaunay 3D
    
      tant que l'arbre des tetraedres de qualites inacceptables 
      n'est pas vide {
        prendre le plus mauvais tetraedre;
        creer un nouveau point;
        eliminer les tetraedres dont le cercle circonscrit contient le point;
        reconstruire le volume convexe;
      } 
    
    */
    
    
    #include "Gmsh.h"
    #include "Numeric.h"
    #include "Mesh.h"
    #include "3D_Mesh.h"
    #include "Create.h"
    #include "Context.h"
    
    extern Mesh *THEM, *LOCAL;
    extern Context_T CTX;
    extern int FACE_DIMENSION;
    
    static Tree_T *Tsd, *Sim_Sur_Le_Bord, *POINTS_TREE;
    static List_T *Simplexes_Destroyed, *Simplexes_New, *Suppress;
    static List_T *LLL, *POINTS;
    static Simplex *THES;
    static Vertex *THEV;
    static Tree_T *SimXFac;
    static double volume, LC3D;
    static int ZONEELIMINEE, Methode = 0;
    
    Simplex MyNewBoundary;
    int Alerte_Point_Scabreux;
    
    void DebugSimplexe(Simplex * s)
    {
      int i;
    
      fprintf(stderr, "Simplexe %p = %d %d %d %d \n",
              s, s->V[0]->Num, s->V[1]->Num, s->V[2]->Num, s->V[3]->Num);
    
      for(i = 0; i < 4; i++) {
        if(s->S[i] != &MyNewBoundary)
          printf(" face : %d %d %d -> Simplexe %p\n",
                 s->F[i].V[0]->Num, s->F[i].V[1]->Num, s->F[i].V[2]->Num,
                 s->S[i]);
        else
          printf(" face : %d %d %d -> Simplexe Boundary\n",
                 s->F[i].V[0]->Num, s->F[i].V[1]->Num, s->F[i].V[2]->Num);
      }
    }
    
    void VSIM(void *a, void *b)
    {
      Simplex *S;
    
      S = *(Simplex **) a;
      if(S->V[3])
        volume += fabs(S->Volume_Simplexe());
    }
    
    void add_points(void *a, void *b)
    {
      Tree_Insert(POINTS_TREE, a);
    }
    
    void add_points_2(void *a, void *b)
    {
      List_Add(POINTS, a);
    }
    
    
    double Interpole_lcTetraedre(Simplex * s, Vertex * v)
    {
      double mat[3][3], rhs[3], sol[3], det;
    
      s->matsimpl(mat);
      rhs[0] = v->Pos.X - s->V[0]->Pos.X;
      rhs[1] = v->Pos.Y - s->V[0]->Pos.Y;
      rhs[2] = v->Pos.Z - s->V[0]->Pos.Z;
    
      sys3x3(mat, rhs, sol, &det);
      if(det == 0.0 ||
         (1. - sol[0] - sol[1] - sol[2]) > 1. ||
         (1. - sol[0] - sol[1] - sol[2]) < 0. ||
         sol[0] > 1. ||
         sol[1] > 1. ||
         sol[2] > 1. || sol[0] < 0. || sol[1] < 0. || sol[2] < 0.) {
        return DMAX(s->V[0]->lc,
                    DMAX(s->V[1]->lc, DMAX(s->V[2]->lc, s->V[3]->lc)));
        //sol[0] = sol[1] = sol[2] = 0.25;
      }
    
      return (s->V[0]->lc * (1. - sol[0] - sol[1] - sol[2]) +
              sol[0] * s->V[1]->lc + sol[1] * s->V[2]->lc + sol[2] * s->V[3]->lc);
    }
    
    Vertex *NewVertex(Simplex * s)
    {
      Vertex *v;
    
      v =
        Create_Vertex(++THEM->MaxPointNum, s->Center.X, s->Center.Y, s->Center.Z,
                      1., 0.0);
      v->lc = Interpole_lcTetraedre(s, v);
    
      return (v);
    }
    
    int Pt_In_Circum(Simplex * s, Vertex * v)
    {
      double d1, d2, eps;
    
      /* Determine si un point est dans le cercle circonscrit a un simplexe */
    
      d1 = s->Radius;
      d2 = sqrt(DSQR(v->Pos.X - s->Center.X) +
                DSQR(v->Pos.Y - s->Center.Y) + DSQR(v->Pos.Z - s->Center.Z));
    
      eps = fabs(d1 - d2) / (d1 + d2);
    
      if(eps < 1.e-12) {
        return (0); // return 1 ? 0 ?
      }
    
      if(d2 < d1)
        return (1);
    
      return (0);
    }
    
    void Action_First_Simplexes(void *a, void *b)
    {
      Simplex **q;
    
      if(!THES) {
        q = (Simplex **) a;
        if(Pt_In_Circum(*q, THEV)) {
          THES = *q;
        }
      }
    }
    
    void LiS(void *a, void *b)
    {
      int j, N;
      SxF SXF, *pSXF;
      Simplex **pS, *S;
    
      pS = (Simplex **) a;
      S = *pS;
      N = (S->V[3]) ? 4 : 3;
    
      for(j = 0; j < N; j++) {
        SXF.F = S->F[j];
        if((pSXF = (SxF *) Tree_PQuery(SimXFac, &SXF))) {
          /* Creation du lien */
          S->S[j] = pSXF->S;
          pSXF->S->S[pSXF->NumFaceSimpl] = S;
        }
        else {
          SXF.S = S;
          SXF.NumFaceSimpl = j;
          Tree_Add(SimXFac, &SXF);
        }
      }
    }
    
    void RzS(void *a, void *b)
    {
      int j, N;
      Simplex **pS, *S;
      pS = (Simplex **) a;
      S = *pS;
    
      N = (S->V[3]) ? 4 : 3;
    
      for(j = 0; j < N; j++) {
        if((S->S[j]) == NULL) {
          S->S[j] = &MyNewBoundary;
        }
      }
    }
    
    /* Cree les liens entre les simplexes, c.a.d recherche les voisins */
    
    void Link_Simplexes(List_T * Sim, Tree_T * Tim)
    {
      Simplex *S;
      int i;
    
      SimXFac = Tree_Create(sizeof(SxF), compareSxF);
      if(Sim) {
        for(i = 0; i < List_Nbr(Sim); i++) {
          List_Read(Sim, i, &S);
          LiS(&S, NULL);
        }
        for(i = 0; i < List_Nbr(Sim); i++) {
          List_Read(Sim, i, &S);
          RzS(&S, NULL);
        }
      }
      else {
        Tree_Action(Tim, LiS);
        Tree_Action(Tim, RzS);
      }
      Tree_Delete(SimXFac);
    }
    
    void Box_6_Tetraedron(List_T * P, Mesh * m)
    {
    #define FACT 1.1
    #define LOIN 0.2
    
      int i, j;
      static int pts[8][3] = { {0, 0, 0},
      {1, 0, 0},
      {1, 1, 0},
      {0, 1, 0},
      {0, 0, 1},
      {1, 0, 1},
      {1, 1, 1},
      {0, 1, 1}
      };
      static int tet[6][4] = { {1, 5, 2, 4},
      {2, 5, 6, 4},
      {4, 5, 6, 8},
      {6, 4, 8, 7},
      {6, 4, 7, 3},
      {2, 3, 4, 6}
      };
      double Xm, Ym, Zm, XM, YM, ZM, Xc, Yc, Zc;
      Simplex *S, *ps;
      Vertex *V, *v, *pv;
      List_T *smp;
    
      smp = List_Create(8, 1, sizeof(Simplex *));
    
      V = (Vertex *) Malloc(8 * 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;
          Zm = ZM = v->Pos.Z;
        }
        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);
          Zm = DMIN(Zm, v->Pos.Z);
          ZM = DMAX(ZM, v->Pos.Z);
        }
      }
      if(Xm == XM)
        XM = Xm + 1.;
      if(Ym == YM)
        YM = Ym + 1.;
      if(Zm == ZM)
        ZM = Zm + 1.;
    
      Xc = XM - Xm;
      Yc = YM - Ym;
      Zc = ZM - Zm;
    
      /* initialisation de la grille */
    
      m->Grid.init = 0;
      m->Grid.min.X = Xm - LOIN * FACT * Xc;
      m->Grid.min.Y = Ym - LOIN * FACT * Yc;
      m->Grid.min.Z = Zm - LOIN * FACT * Zc;
      m->Grid.max.X = XM + LOIN * FACT * Xc;
      m->Grid.max.Y = YM + LOIN * FACT * Yc;
      m->Grid.max.Z = ZM + LOIN * FACT * Zc;
    
      m->Grid.Nx = m->Grid.Ny = m->Grid.Nz = 20;
    
      /* Longueur Caracteristique */
    
      LC3D = sqrt(Xc * Xc + Yc * Yc + Zc * Zc);
    
      /* Points de la boite de 1 a 8 
    
         Z    8____________7
         |   /|           /|
         |  / |          / |
         | /  |         /  |
         5|/___|________/6  |
         |   4|________|___|3
         |   /         |   /
         |  / Y        |  /
         | /           | /
         |/____________|/___ X
         1             2
    
       */
    
      for(i = 0; i < 8; i++) {
        if(pts[i][0])
          V[i].Pos.X = Xm - LOIN * Xc;
        else
          V[i].Pos.X = XM + LOIN * Xc;
    
        if(pts[i][1])
          V[i].Pos.Y = Ym - LOIN * Yc;
        else
          V[i].Pos.Y = YM + LOIN * Yc;
    
        if(pts[i][2])
          V[i].Pos.Z = Zm - LOIN * Zc;
        else
          V[i].Pos.Z = ZM + LOIN * Zc;
    
        V[i].Num = -(++THEM->MaxPointNum);
        pv = &V[i];
        pv->lc = 1.0;
        pv->Mov = NULL;
        Tree_Replace(m->Vertices, &pv);
      }
    
      /* 6 Tetraedres forment le maillage de la boite */
    
      for(i = 0; i < 6; i++) {
        S = Create_Simplex(&V[tet[i][0] - 1], &V[tet[i][1] - 1],
                           &V[tet[i][2] - 1], &V[tet[i][3] - 1]);
        List_Add(smp, &S);
      }
    
      Link_Simplexes(smp, NULL);
      for(i = 0; i < List_Nbr(smp); i++) {
        List_Read(smp, i, &ps);
        for(j = 0; j < 4; j++)
          if(ps->S[j] == NULL)
            ps->S[j] = &MyNewBoundary;
        Tree_Replace(m->Simplexes, &ps);
      }
    
    }
    
    
    void Fill_Sim_Des(void *a, void *b)
    {
      Simplex **S;
      S = (Simplex **) a;
      if(Pt_In_Circum(*S, THEV))
        List_Add(Simplexes_Destroyed, a);
    }
    
    void TStoLS(void *a, void *b)
    {
      List_Add(Simplexes_Destroyed, a);
    }
    
    void TAtoLA(void *a, void *b)
    {
      List_Add(Simplexes_New, a);
    }
    
    void CrSi(void *a, void *b)
    {
      SxF *S;
      Simplex *s;
      S = (SxF *) a;
      if(S->NumFaceSimpl == 1) {
        s = Create_Simplex(THEV, S->F.V[0], S->F.V[1], S->F.V[2]);
        s->iEnt = ZONEELIMINEE;
        THEM->Metric->setSimplexQuality(s);
        List_Add(Simplexes_New, &s);
      }
      else if(S->NumFaceSimpl != 2) {
        Msg(WARNING, "Huh! Panic in CrSi");
      }
    }
    
    
    void NewSimplexes(Mesh * m, 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 < 4; 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);
      Tree_Delete(SimXFac);
    }
    
    
    
    /* Methode recursive : Rempli Tsd les simplexes detruits 
       Invariant : Le simplexe est a eliminer
       Le simplexe n'est pas encore considere */
    
    int recur_bowyer(Simplex * s)
    {
      int i;
    
      Tree_Insert(Tsd, &s);
      for(i = 0; i < 4; i++) {
        if(s->S[i] && s->S[i] != &MyNewBoundary && !Tree_Query(Tsd, &s->S[i])) {
          if(Pt_In_Circum(s->S[i], THEV) && (s->iEnt == s->S[i]->iEnt)) {
            recur_bowyer(s->S[i]);
          }
          else {
            if(s->iEnt != s->S[i]->iEnt) {
              //Msg(WARNING, "Point scabreux %d", s->S[i]->Num);
              Alerte_Point_Scabreux = 1;
            }
            Tree_Insert(Sim_Sur_Le_Bord, &s->S[i]);
          }
        }
      }
      return 1;
    }
    
    bool Bowyer_Watson(Mesh * m, Vertex * v, Simplex * S, int force)
    {
      int i;
      Simplex *s;
      double volumeold, volumenew;
    
      THEV = v;
    
      double x =
        (S->V[0]->Pos.X + S->V[1]->Pos.X + S->V[2]->Pos.X + S->V[3]->Pos.X) / 4.;
      double y =
        (S->V[0]->Pos.Y + S->V[1]->Pos.Y + S->V[2]->Pos.Y + S->V[3]->Pos.Y) / 4.;
      double z =
        (S->V[0]->Pos.Z + S->V[1]->Pos.Z + S->V[2]->Pos.Z + S->V[3]->Pos.Z) / 4.;
    
      if(force)
        THEM->Metric->Identity();
      else
        THEM->Metric->setMetric(x, y, z);
    
      Tsd = Tree_Create(sizeof(Simplex *), compareSimplex);
      Sim_Sur_Le_Bord = Tree_Create(sizeof(Simplex *), compareSimplex);
      List_Reset(Simplexes_Destroyed);
      List_Reset(Simplexes_New);
    
      if(Methode) {
        Tree_Action(m->Simplexes, Fill_Sim_Des);
      }
      else {
        recur_bowyer(S);
      }
    
      Tree_Action(Tsd, TStoLS);
      NewSimplexes(m, 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(List_Pointer(Simplexes_Destroyed, i), NULL);
        }
        volumeold = volume;
        volume = 0.0;
        for(i = 0; i < List_Nbr(Simplexes_New); i++) {
          VSIM(List_Pointer(Simplexes_New, i), NULL);
        }
        volumenew = volume;
      }
      else {
        volumeold = 1.0;
        volumenew = 1.0;
      }
    
      /* critere du volume */
    
      if((fabs(volumeold - volumenew) / (volumeold + volumenew)) > 1.e-8) {
        if(Tree_Suppress(m->Simplexes, &S)) {
          S->Quality = 0.0;
          Tree_Add(m->Simplexes, &S);
        }
        if(force) {
          List_Reset(Simplexes_Destroyed);
          List_Reset(Simplexes_New);
          Tree_Delete(Sim_Sur_Le_Bord);
          Tree_Delete(Tsd);
          //printf(" Aie Aie Aie volume changed %g -> %g\n",volumeold,volumenew);
          return false;
        }
      }
      else {
        Tree_Add(m->Vertices, &THEV);
        for(i = 0; i < List_Nbr(Simplexes_New); i++) {
          Tree_Add(m->Simplexes, List_Pointer(Simplexes_New, i));
        }
    
        /* Suppression des simplexes elimines */
    
        for(i = 0; i < List_Nbr(Simplexes_Destroyed); i++) {
          List_Read(Simplexes_Destroyed, i, &s);
          if(!Tree_Suppress(m->Simplexes, &s))
            Msg(GERROR, "Impossible to delete simplex");
          Free_Simplex(&s, 0);
        }
    
        /* Creation des liens entre nouveaux simplexes */
    
        Tree_Action(Sim_Sur_Le_Bord, TAtoLA);
        Link_Simplexes(Simplexes_New, m->Simplexes);
      }
    
      Tree_Delete(Sim_Sur_Le_Bord);
      Tree_Delete(Tsd);
      return true;
    }
    
    void Convex_Hull_Mesh(List_T * Points, Mesh * m)
    {
      int i, j, N, n;
      int Nbr_OK = 0, Nbr_NOTOK = 0;
    
      N = List_Nbr(Points);
      n = IMAX(N / 20, 1);
    
      Box_6_Tetraedron(Points, m);
      // List_Sort (Points, comparePosition);
    
      for(i = 0; i < N; i++) {
        THES = NULL;
        List_Read(Points, i, &THEV);
    
        if(Simplexes_New)
          for(j = 0; j < List_Nbr(Simplexes_New); j++) {
            Action_First_Simplexes(List_Pointer(Simplexes_New, j), NULL);
          }
    
        if(!THES) {
          Tree_Action(m->Simplexes, Action_First_Simplexes);
          Nbr_OK++;
        }
        else {
          Nbr_NOTOK++;
        }
        if(i % n == n - 1) {
          volume = 0.0;
          Tree_Action(m->Simplexes, VSIM);
          Msg(STATUS3, "Nod=%d/%d Elm=%d", i + 1, N, Tree_Nbr(m->Simplexes));
          Msg(STATUS1, "Vol=%g", volume);
        }
        if(!THES) {
          Msg(WARNING, "Vertex (%g,%g,%g) in no simplex", THEV->Pos.X,
              THEV->Pos.Y, THEV->Pos.Z);
          THEV->Pos.X +=
            CTX.mesh.rand_factor * LC3D * (1. -
                                           (double)rand() / (double)RAND_MAX);
          THEV->Pos.Y +=
            CTX.mesh.rand_factor * LC3D * (1. -
                                           (double)rand() / (double)RAND_MAX);
          THEV->Pos.Z +=
            CTX.mesh.rand_factor * LC3D * (1. -
                                           (double)rand() / (double)RAND_MAX);
          Tree_Action(m->Simplexes, Action_First_Simplexes);
        }
        bool ca_marche = Bowyer_Watson(m, THEV, THES, 1);
        int count = 0;
        while(!ca_marche) {
          count++;
          double dx =
            CTX.mesh.rand_factor * LC3D * (1. -
                                           (double)rand() / (double)RAND_MAX);
          double dy =
            CTX.mesh.rand_factor * LC3D * (1. -
                                           (double)rand() / (double)RAND_MAX);
          double dz =
            CTX.mesh.rand_factor * LC3D * (1. -
                                           (double)rand() / (double)RAND_MAX);
          THEV->Pos.X += dx;
          THEV->Pos.Y += dy;
          THEV->Pos.Z += dz;
          THES = NULL;
          Tree_Action(m->Simplexes, Action_First_Simplexes);
          ca_marche = Bowyer_Watson(m, THEV, THES, 1);
          THEV->Pos.X -= dx;
          THEV->Pos.Y -= dy;
          THEV->Pos.Z -= dz;
          if(count > 5) {
            N++;
            List_Add(POINTS, &THEV);
            Msg(WARNING, "Unable to add point %d (will try it later)", THEV->Num);
            break;
          }
        }
      }
    }
    
    void suppress_vertex(void *data, void *dum)
    {
      Vertex **pv;
    
      pv = (Vertex **) data;
      if((*pv)->Num < 0)
        List_Add(Suppress, pv);
    }
    
    void suppress_simplex(void *data, void *dum)
    {
      Simplex **pv;
    
      pv = (Simplex **) data;
      if((*pv)->iEnt == 0)
        List_Add(Suppress, pv);
    }
    
    void add_in_bgm(void *a, void *b)
    {
      Simplex **s, *S;
    
      s = (Simplex **) a;
      S = *s;
      List_Add(LLL, S);
    }
    
    void Bgm_With_Points(Mesh * bgm)
    {
      int i;
      Simplex *s;
    
      bgm->BGM.bgm = List_Create(Tree_Nbr(bgm->Simplexes), 10, sizeof(Simplex));
      LLL = bgm->BGM.bgm;
      Tree_Action(bgm->Simplexes, add_in_bgm);
      for(i = 0; i < List_Nbr(LLL); i++) {
        s = (Simplex *) List_Pointer(LLL, i);
        AddSimplexInGrid(bgm, s, BOITE);
      }
    }
    
    void Create_BgMesh(int Type, double lc, Mesh * m)
    {
      m->BGM.Typ = Type;
      switch (Type) {
      case CONSTANT:
        m->BGM.lc = lc;
        break;
      case ONFILE:
        break;
      case WITHPOINTS:
        m->BGM.bgm = NULL;
        break;
      }
    }
    
    void Maillage_Volume(void *data, void *dum)
    {
      Volume *v, **pv;
      Mesh M;
      Surface S, *s;
      Simplex *simp;
      Vertex *newv;
      int n, N;
      double uvw[3];
      int i;
    
      FACE_DIMENSION = 2;
    
      pv = (Volume **) data;
      v = *pv;
    
      if(v->Dirty) {
        Msg(INFO, "Not meshing dirty Volume %d", v->Num);
        return;
      }
    
      if(Extrude_Mesh(v)) {
      }
      else if(MeshTransfiniteVolume(v)) {
      }
      else if(v->Typ == 99999) {
    
        Simplexes_New = List_Create(10, 10, sizeof(Simplex *));
        Simplexes_Destroyed = List_Create(10, 10, sizeof(Simplex *));
    
        LOCAL = &M;
        Create_BgMesh(THEM->BGM.Typ, .2, LOCAL);
        s = &S;
    
        POINTS_TREE = Tree_Create(sizeof(Vertex *), comparePosition);
        POINTS = List_Create(100, 100, sizeof(Vertex *));
        LOCAL->Simplexes = v->Simplexes;
        LOCAL->Vertices = v->Vertices;
    
        for(i = 0; i < List_Nbr(v->Surfaces); i++) {
          List_Read(v->Surfaces, i, &s);
          Tree_Action(s->Vertices, add_points);
        }
        Tree_Action(POINTS_TREE, add_points_2);
        Tree_Delete(POINTS_TREE);
    
        N = List_Nbr(POINTS);
        n = N / 30 + 1;
    
        if(!N)
          return;
    
        /* Creation d'un maillage initial respectant la frontiere */
    
        Msg(STATUS2, "Mesh 3D... (initial)");
    
        Convex_Hull_Mesh(POINTS, LOCAL);
    
        if(!Coherence(v, LOCAL))
          Msg(GERROR,
              "Surface recovery failed (send a bug report with the geo file to <gmsh@geuz.org>!)");
    
        Link_Simplexes(NULL, LOCAL->Simplexes);
    
        if(CTX.mesh.initial_only == 3) {
          POINTS_TREE = THEM->Vertices;
          Tree_Action(v->Vertices, add_points);
          POINTS_TREE = THEM->Simplexes;
          Tree_Action(v->Simplexes, add_points);
          return;
        }
    
        /* Suppression des noeuds de num < 0 */
    
        Suppress = List_Create(10, 10, sizeof(Vertex *));
        Tree_Action(v->Vertices, suppress_vertex);
        for(i = 0; i < List_Nbr(Suppress); i++) {
          Tree_Suppress(v->Vertices, List_Pointer(Suppress, i));
        }
        List_Delete(Suppress);
    
        /* Suppression des elements dont le num de vol == 0 (cad qui
           n'appartiennent a auncun volume defini) */
    
        Suppress = List_Create(10, 10, sizeof(Simplex *));
        Tree_Action(v->Simplexes, suppress_simplex);
        for(i = 0; i < List_Nbr(Suppress); i++) {
          Tree_Suppress(v->Simplexes, List_Pointer(Suppress, i));
        }
    
        List_Delete(Suppress);
    
        if(Tree_Nbr(LOCAL->Simplexes) == 0)
          return;
    
        /* Si il reste quelque chose a mailler en volume : */
    
        Msg(STATUS2, "Mesh 3D... (final)");
    
        v->Simplexes = LOCAL->Simplexes;
    
        Bgm_With_Points(LOCAL);
        POINTS_TREE = THEM->Simplexes;
    
        Tree_Right(LOCAL->Simplexes, &simp);
        i = 0;
    
        while(simp->Quality > CONV_VALUE) {
          newv = NewVertex(simp);
          while(!simp->Pt_In_Simplexe(newv, uvw, 1.e-5) &&
                (simp->S[0] == &MyNewBoundary ||
                 !simp->S[0]->Pt_In_Simplexe(newv, uvw, 1.e-5)) &&
                (simp->S[1] == &MyNewBoundary ||
                 !simp->S[1]->Pt_In_Simplexe(newv, uvw, 1.e-5)) &&
                (simp->S[2] == &MyNewBoundary ||
                 !simp->S[2]->Pt_In_Simplexe(newv, uvw, 1.e-5)) &&
                (simp->S[3] == &MyNewBoundary ||
                 !simp->S[3]->Pt_In_Simplexe(newv, uvw, 1.e-5))) {
            Tree_Suppress(LOCAL->Simplexes, &simp);
            simp->Quality = 0.1;
            Tree_Insert(LOCAL->Simplexes, &simp);
            Tree_Right(LOCAL->Simplexes, &simp);
            if(simp->Quality < CONV_VALUE)
              break;
            newv = NewVertex(simp);
          }
          if(simp->Quality < CONV_VALUE)
            break;
          i++;
          if(i % n == n - 1) {
            volume = 0.0;
            Tree_Action(LOCAL->Simplexes, VSIM);
            Msg(STATUS3, "Nod=%d Elm=%d",
                Tree_Nbr(LOCAL->Vertices), Tree_Nbr(LOCAL->Simplexes));
            Msg(STATUS1, "Vol(%g) Conv(%g->%g)", volume, simp->Quality,
                CONV_VALUE);
            double adv = 100. * (CONV_VALUE / simp->Quality);
          }
          Bowyer_Watson(LOCAL, newv, simp, 0);
          Tree_Right(LOCAL->Simplexes, &simp);
        }
    
        POINTS_TREE = THEM->Vertices;
        Tree_Action(v->Vertices, add_points);
        POINTS_TREE = THEM->Simplexes;
        Tree_Action(v->Simplexes, add_points);
    
        if(CTX.mesh.quality) {
          extern void SwapEdges3D(Mesh * M, Volume * v, double GammaPrescribed,
                                  bool order);
          Msg(STATUS3, "Swapping edges (1st pass)");
          SwapEdges3D(THEM, v, CTX.mesh.quality, true);
          Msg(STATUS3, "Swapping edges (2nd pass)");
          SwapEdges3D(THEM, v, CTX.mesh.quality, false);
          Msg(STATUS3, "Swapping edges (last pass)");
          SwapEdges3D(THEM, v, CTX.mesh.quality, true);
        }
    
        if(CTX.mesh.nb_smoothing) {
          /*
             Msg(STATUS3, "Smoothing volume %d", v->Num);
             tnxe = Tree_Create (sizeof (NXE), compareNXE);
             create_NXE (v->Vertices, v->Simplexes, tnxe);
             for (int i = 0; i < CTX.mesh.nb_smoothing; i++)
             Tree_Action (tnxe, ActionLiss);
             delete_NXE (tnxe);
             Msg(STATUS3, "Swapping edges (last pass)");
             SwapEdges3D (THEM, v, 0.5, true);
           */
        }
    
        List_Delete(Simplexes_New);
        List_Delete(Simplexes_Destroyed);
      }
    
    }