diff --git a/CMakeLists.txt b/CMakeLists.txt
index 50377251b0e15ef18136b7d5eedc858e7906b6a2..c534812957ad9466a0f279c161120f9bdddcb790 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -37,6 +37,7 @@ option(ENABLE_MPI "Enable MPI parallelization" OFF)
 option(ENABLE_MSVC_STATIC_RUNTIME "Use static Visual C++ runtime" OFF)
 option(ENABLE_NATIVE_FILE_CHOOSER "Enable native file chooser in GUI" ON)
 option(ENABLE_NETGEN "Enable Netgen mesh generator" ON)
+option(ENABLE_BAMG "Enable Bamg mesh generator" ON)
 option(ENABLE_OCC "Enable Open CASCADE geometrical models" ON)
 option(ENABLE_ACIS "Enable ACIS geometrical models" ON)
 option(ENABLE_OSMESA "Use OSMesa for offscreen rendering" OFF)
@@ -495,6 +496,13 @@ if(ENABLE_NETGEN)
   add_definitions(-DNO_PARALLEL_THREADS)
 endif(ENABLE_NETGEN)
 
+if(ENABLE_BAMG)
+  add_subdirectory(contrib/bamg)
+  include_directories(contrib/bamg contrib/bamg/bamglib)
+  set_config_option(HAVE_BAMG "Bamg")
+endif(ENABLE_BAMG)
+
+
 if(ENABLE_TETGEN_NEW AND EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/contrib/TetgenNew/tetgen.h)
   add_subdirectory(contrib/TetgenNew)
   include_directories(contrib/TetgenNew)
diff --git a/Common/CommandLine.cpp b/Common/CommandLine.cpp
index b44acf09066473c27d14e7ea12e49404a3d9e661..b9967b6b092c36d99c32b0295558328dbbf46d5b 100644
--- a/Common/CommandLine.cpp
+++ b/Common/CommandLine.cpp
@@ -511,6 +511,8 @@ void GetOptions(int argc, char *argv[])
             CTX::instance()->mesh.algo2d = ALGO_2D_DELAUNAY;
           else if(!strncmp(argv[i], "front2d", 7) || !strncmp(argv[i], "frontal", 7))
             CTX::instance()->mesh.algo2d = ALGO_2D_FRONTAL;
+          else if(!strncmp(argv[i], "bamg",4))
+            CTX::instance()->mesh.algo2d = ALGO_2D_BAMG;
           else if(!strncmp(argv[i], "del3d", 5) || !strncmp(argv[i], "tetgen", 6))
             CTX::instance()->mesh.algo2d = ALGO_3D_DELAUNAY;
           else if(!strncmp(argv[i], "front3d", 7) || !strncmp(argv[i], "netgen", 6))
diff --git a/Common/GmshConfig.h.in b/Common/GmshConfig.h.in
index ef67a45ae1bae295987620ed2f4bb0dc097ce57c..5728ace40ee1da111c5e373de05b24829670a7a6 100644
--- a/Common/GmshConfig.h.in
+++ b/Common/GmshConfig.h.in
@@ -9,6 +9,7 @@
 #cmakedefine HAVE_64BIT_SIZE_T
 #cmakedefine HAVE_ACIS
 #cmakedefine HAVE_ANN
+#cmakedefine HAVE_BAMG
 #cmakedefine HAVE_BLAS
 #cmakedefine HAVE_CHACO
 #cmakedefine HAVE_DLOPEN
diff --git a/Common/GmshDefines.h b/Common/GmshDefines.h
index 948ad4c51fab398792f4cb01d05f352e4453d079..d4ebdd94fe4e44b5a8a4b1898ad6565997339b9a 100644
--- a/Common/GmshDefines.h
+++ b/Common/GmshDefines.h
@@ -147,6 +147,7 @@
 #define ALGO_2D_MESHADAPT_OLD  4
 #define ALGO_2D_DELAUNAY       5
 #define ALGO_2D_FRONTAL        6
+#define ALGO_2D_BAMG           7
 
 // 3D meshing algorithms (numbers should not be changed)
 #define ALGO_3D_DELAUNAY       1
diff --git a/Geo/OCCFace.cpp b/Geo/OCCFace.cpp
index a72342ff450cb597b0469da7e7f437b1de3a7a54..828a68059b9b4a925f4cbb868ea2ab4a2234ae69 100644
--- a/Geo/OCCFace.cpp
+++ b/Geo/OCCFace.cpp
@@ -238,12 +238,13 @@ double OCCFace::curvatures(const SPoint2 &param,
     return -1.;
   }
 
-  *curvMax = std::max(fabs(prop.MinCurvature()), fabs(prop.MaxCurvature()));
-  *curvMin = std::min(fabs(prop.MinCurvature()), fabs(prop.MaxCurvature()));
+  *curvMax = prop.MaxCurvature();
+  *curvMin = prop.MinCurvature();
 
   gp_Dir dMax = gp_Dir();
   gp_Dir dMin = gp_Dir();
   prop.CurvatureDirections(dMax,dMin);
+
   (*dirMax)[0] = dMax.X();
   (*dirMax)[1] = dMax.Y();
   (*dirMax)[2] = dMax.Z();
diff --git a/Geo/STensor3.h b/Geo/STensor3.h
index 7301af82253b2c09a15e34119b3f935496f5ab20..e2c78844a4afe2e3a91a035f99974d8199233105 100644
--- a/Geo/STensor3.h
+++ b/Geo/STensor3.h
@@ -61,7 +61,8 @@ class SMetric3 {
       e(0,0) = t1(0); e(0,1) = t1(1); e(0,2) = t1(2);
       e(1,0) = t2(0); e(1,1) = t2(1); e(1,2) = t2(2);
       e(2,0) = t3(0); e(2,1) = t3(1); e(2,2) = t3(2);
-      e.invertInPlace();
+      e.transposeInPlace();
+      //      e.invertInPlace();
     
       fullMatrix<double> tmp(3,3);
       tmp(0,0) = l1 * e(0,0);
diff --git a/Mesh/BackgroundMesh.cpp b/Mesh/BackgroundMesh.cpp
index 26138a3ed4d2b64865dcf85ca784f8298313fb38..76e1500b2182c3b817b6f3d8cea0f1f8fefb626d 100644
--- a/Mesh/BackgroundMesh.cpp
+++ b/Mesh/BackgroundMesh.cpp
@@ -81,6 +81,74 @@ static double max_surf_curvature(const GVertex *gv)
   return val;
 }
 
+static SMetric3 metric_based_on_surface_curvature(const GFace *gf, double u, double v)
+{
+  if (gf->geomType() == GEntity::Plane)return SMetric3(1.e-6);
+  double cmax, cmin;
+  SVector3 dirMax,dirMin;
+  cmax = gf->curvatures(SPoint2(u, v),&dirMax, &dirMin, &cmax,&cmin);
+  if (cmin == 0)cmin =1.e-5;
+  if (cmax == 0)cmax =1.e-5;
+  double lambda2 =  ((2 * M_PI) /( fabs(cmax) *  CTX::instance()->mesh.minCircPoints ) );
+  double lambda1 =  ((2 * M_PI) /( fabs(cmin) *  CTX::instance()->mesh.minCircPoints ) );
+  SVector3 Z = crossprod(dirMax,dirMin);
+
+  lambda1 = std::max(lambda1, CTX::instance()->mesh.lcMin);
+  lambda2 = std::max(lambda2, CTX::instance()->mesh.lcMin);
+  lambda1 = std::min(lambda1, CTX::instance()->mesh.lcMax);
+  lambda2 = std::min(lambda2, CTX::instance()->mesh.lcMax);
+  if (gf->tag() == 36  || gf->tag() == 62)
+    printf("%g %g -- %g %g -- %g %g %g --  %g %g %g -- %g %g %g -- %g %g\n",u,v,cmax,cmin,
+	   dirMax.x(),dirMax.y(),dirMax.z(),
+	   dirMin.x(),dirMin.y(),dirMin.z(),
+	   Z.x(),Z.y(),Z.z(),
+	   lambda1,lambda2);
+  
+  SMetric3 curvMetric (1./(lambda1*lambda1),1./(lambda2*lambda2),1.e-5, 
+		       dirMin, dirMax, Z );
+  return curvMetric;
+}
+
+static SMetric3 metric_based_on_surface_curvature(const GEdge *ge, double u)
+{
+  SMetric3 mesh_size(1.e-05);
+  std::list<GFace *> faces = ge->faces();
+  std::list<GFace *>::iterator it = faces.begin();
+  int count = 0;
+  while(it != faces.end()){
+    if ((*it)->geomType() != GEntity::CompoundSurface){
+      SPoint2 par = ge->reparamOnFace((*it), u, 1);
+      SMetric3 m = metric_based_on_surface_curvature (*it, par.x(), par.y());
+      if (!count) mesh_size = m;
+      else mesh_size = intersection ( mesh_size, m);    
+      if ( ge->tag() == 197)
+	printf("edge %d face %d g %g %g -> %g %g %g\n",ge->tag(),(*it)->tag(),
+	       m(0,0),m(1,1),m(2,2),mesh_size(0,0),mesh_size(1,1),mesh_size(2,2));
+      count++;
+    }
+    ++it;
+  }  
+  return mesh_size;
+}
+
+static SMetric3 metric_based_on_surface_curvature(const GVertex *gv)
+{
+  SMetric3 mesh_size(1.e-5);
+  std::list<GEdge*> l_edges = gv->edges();
+  for (std::list<GEdge*>::const_iterator ite = l_edges.begin(); 
+       ite != l_edges.end(); ++ite){
+    GEdge *_myGEdge = *ite;
+    Range<double> bounds = _myGEdge->parBounds(0);
+    if (gv == _myGEdge->getBeginVertex())
+      mesh_size = intersection ( mesh_size, 
+				 metric_based_on_surface_curvature (_myGEdge, bounds.low()));    
+    else
+      mesh_size = intersection ( mesh_size, 
+				 metric_based_on_surface_curvature (_myGEdge, bounds.high()));  }
+  return mesh_size;
+}
+
+
 // the mesh vertex is classified on a model vertex.  we compute the
 // maximum of the curvature of model faces surrounding this point if
 // it is classified on a model edge, we do the same for all model
@@ -116,6 +184,33 @@ static double LC_MVertex_CURV(GEntity *ge, double U, double V)
   return lc;
 }
 
+
+static SMetric3 LC_MVertex_CURV_ANISO(GEntity *ge, double U, double V)
+{
+  switch(ge->dim()){
+  case 0:        
+    {
+      SMetric3 m = metric_based_on_surface_curvature((const GVertex *)ge);
+      //      printf("0d\n");
+      return m;
+    }
+    break;
+  case 1:
+    {
+      SMetric3 m = metric_based_on_surface_curvature((const GEdge *)ge,U);
+      //      printf("1d %g %g %g\n",m(0,0),m(1,1),m(2,2));
+      return m;
+    }
+    break;
+  case 2:
+    {
+      return metric_based_on_surface_curvature((const GFace *)ge,U,V);
+    }
+    break;
+  }
+  Msg::Fatal("curvature control impossible to compute for a volume !");
+}
+
 // compute the mesh size at a given vertex due to prescribed sizes at
 // mesh vertices
 static double LC_MVertex_PNTS(GEntity *ge, double U, double V)
@@ -192,6 +287,9 @@ double BGM_MeshSize(GEntity *ge, double U, double V,
 
 
 // anisotropic version of the background field
+// for now, only works with bamg in 2D, work
+// in progress
+
 SMetric3 BGM_MeshMetric(GEntity *ge, 
                         double U, double V, 
                         double X, double Y, double Z)
@@ -201,40 +299,44 @@ SMetric3 BGM_MeshMetric(GEntity *ge,
 
   // lc from points            
   double l2 = MAX_LC;
-  if(CTX::instance()->mesh.lcFromPoints && ge->dim() < 2) 
-    l2 = LC_MVertex_PNTS(ge, U, V);
+  // if(CTX::instance()->mesh.lcFromPoints && ge->dim() < 2) 
+  //    l2 = LC_MVertex_PNTS(ge, U, V);
   
   // lc from curvature
-  double l3 = MAX_LC;
+  SMetric3 l3(1./(MAX_LC*MAX_LC));
   if(CTX::instance()->mesh.lcFromCurvature && ge->dim() < 3)
-    l3 = LC_MVertex_CURV(ge, U, V);
+    l3 = LC_MVertex_CURV_ANISO(ge, U, V);
 
   // lc from fields
-  SMetric3 l4(MAX_LC);
+  SMetric3 l4(1./(MAX_LC*MAX_LC));
   FieldManager *fields = GModel::current()->getFields();
   if(fields->background_field > 0){
     Field *f = fields->get(fields->background_field);
     if(f){
       if (!f->isotropic())
         (*f)(X, Y, Z, l4,ge);
-      else
-        l4 = SMetric3((*f)(X, Y, Z, ge));
+      else{
+	double L = (*f)(X, Y, Z, ge);
+        l4 = SMetric3(1/(L*L));
+      }
     }
   }
   
   // take the minimum, then constrain by lcMin and lcMax
-  double lc = std::min(std::min(l1, l2), l3);
+  double lc = std::min(l1, l2);
   lc = std::max(lc, CTX::instance()->mesh.lcMin);
   lc = std::min(lc, CTX::instance()->mesh.lcMax);
 
   if(lc <= 0.){
-     Msg::Error("Wrong mesh element size lc = %g (lcmin = %g, lcmax = %g)",
+    Msg::Error("Wrong mesh element size lc = %g (lcmin = %g, lcmax = %g)",
                lc, CTX::instance()->mesh.lcMin, CTX::instance()->mesh.lcMax);
-     lc = l1;
+    lc = l1;
   }
-
-  SMetric3 LC(lc);
-  return intersection (l4, LC);
+  
+  SMetric3 LC(1./(lc*lc));
+  SMetric3 m = intersection(intersection (l4, LC),l3);
+  //  printf("%g %g %g %g %g %g\n",m(0,0),m(1,1),m(2,2),m(0,1),m(0,2),m(1,2));
+  return m;
   //  return lc * CTX::instance()->mesh.lcFactor;
 }
 
diff --git a/Mesh/CMakeLists.txt b/Mesh/CMakeLists.txt
index faa3cdb9f851a613232687d2e32f95bb4863f14b..ab0fc79380535c0c15db93b74067d21656836461 100644
--- a/Mesh/CMakeLists.txt
+++ b/Mesh/CMakeLists.txt
@@ -11,6 +11,7 @@ set(SRC
     meshGFace.cpp 
     meshGFaceTransfinite.cpp 
     meshGFaceExtruded.cpp 
+    meshGFaceBamg.cpp 
     meshGFaceBDS.cpp 
     meshGFaceDelaunayInsertion.cpp 
     meshGFaceLloyd.cpp 
diff --git a/Mesh/meshGEdge.cpp b/Mesh/meshGEdge.cpp
index 06cea7868f3fe2bc2d06f90f2e88d6d245bc4cbe..1a542e40a365496879a33fe200c8f1c573f2af40 100644
--- a/Mesh/meshGEdge.cpp
+++ b/Mesh/meshGEdge.cpp
@@ -11,6 +11,7 @@
 #include "Numeric.h"
 #include "GmshMessage.h"
 #include "Context.h"
+#include "STensor3.h"
 
 #define SQU(a)      ((a)*(a))
 
@@ -98,9 +99,39 @@ static double F_Lc(GEdge *ge, double t)
   SVector3 der = ge->firstDer(t);
   const double d = norm(der);
 
-  return d / lc_here;
+  SMetric3 metric (1./(lc_here*lc_here));
+  
+  //  metric(0,0) = metric(0,0)*10000;
+
+  double lSquared = dot (der,metric,der);
+
+  return sqrt(lSquared);
 }
 
+static double F_Lc_aniso(GEdge *ge, double t)
+{
+  GPoint p = ge->point(t);
+  SMetric3 lc_here;
+
+  Range<double> bounds = ge->parBounds(0);
+  double t_begin = bounds.low();
+  double t_end = bounds.high();
+
+  if(t == t_begin)
+    lc_here = BGM_MeshMetric(ge->getBeginVertex(), t, 0, p.x(), p.y(), p.z());
+  else if(t == t_end)
+    lc_here = BGM_MeshMetric(ge->getEndVertex(), t, 0, p.x(), p.y(), p.z());
+  else
+    lc_here = BGM_MeshMetric(ge, t, 0, p.x(), p.y(), p.z());
+
+  SVector3 der = ge->firstDer(t);
+
+  double lSquared = dot (der,lc_here,der);
+
+  return sqrt(lSquared);
+}
+
+
 static double F_Transfinite(GEdge *ge, double t_)
 {
   double length = ge->length();
@@ -325,7 +356,7 @@ void meshGEdge::operator() (GEdge *ge)
     N = ge->meshAttributes.nbPointsTransfinite;
   }
   else{
-    if(CTX::instance()->mesh.lcIntegrationPrecision > 1.e-8){
+    if(CTX::instance()->mesh.lcIntegrationPrecision > 1.e-2){
       std::vector<IntPoint> lcPoints;
       Integration(ge, t_begin, t_end, F_Lc_usingInterpLcBis, lcPoints, 
                   CTX::instance()->mesh.lcIntegrationPrecision);
@@ -333,8 +364,12 @@ void meshGEdge::operator() (GEdge *ge)
       a = Integration(ge, t_begin, t_end, F_Lc_usingInterpLc, Points, 1.e-8);
     }
     else{
-      a = Integration(ge, t_begin, t_end, F_Lc, Points,
-                      CTX::instance()->mesh.lcIntegrationPrecision);
+      if (CTX::instance()->mesh.algo2d == ALGO_2D_BAMG) 
+	a = Integration(ge, t_begin, t_end, F_Lc_aniso, Points,
+			CTX::instance()->mesh.lcIntegrationPrecision);
+      else
+	a = Integration(ge, t_begin, t_end, F_Lc, Points,
+			CTX::instance()->mesh.lcIntegrationPrecision);
     }
     N = std::max(ge->minimumMeshSegments() + 1, (int)(a + 1.));
   }
diff --git a/Mesh/meshGFace.cpp b/Mesh/meshGFace.cpp
index 72a71cba2a2f4e753b7ce2855c07660fe8e9ef3a..5345a11cbac9b28a5e9cbeb0f28250466cec9c63 100644
--- a/Mesh/meshGFace.cpp
+++ b/Mesh/meshGFace.cpp
@@ -9,6 +9,7 @@
 #include "meshGFace.h"
 #include "meshGFaceBDS.h"
 #include "meshGFaceDelaunayInsertion.h"
+#include "meshGFaceBamg.h"
 #include "meshGFaceQuadrilateralize.h"
 #include "meshGFaceOptimize.h"
 #include "DivideAndConquer.h"
@@ -299,7 +300,8 @@ static void remeshUnrecoveredEdges(std::map<MVertex*, BDS_Point*> &recoverMapInv
 
 static bool algoDelaunay2D(GFace *gf)
 {
-  if(noSeam(gf) && (CTX::instance()->mesh.algo2d == ALGO_2D_DELAUNAY || 
+  if(noSeam(gf) && (CTX::instance()->mesh.algo2d == ALGO_2D_DELAUNAY ||
+		    CTX::instance()->mesh.algo2d == ALGO_2D_BAMG || 
                     CTX::instance()->mesh.algo2d == ALGO_2D_FRONTAL))
     return true;
   return false;
@@ -824,8 +826,12 @@ static bool meshGenerator(GFace *gf, int RECUR_ITER,
   if(algoDelaunay2D(gf)){
     if(CTX::instance()->mesh.algo2d == ALGO_2D_FRONTAL)
       bowyerWatsonFrontal(gf);
-    else
+    else if(CTX::instance()->mesh.algo2d == ALGO_2D_DELAUNAY)
+      bowyerWatson(gf);
+    else {
       bowyerWatson(gf);
+      meshGFaceBamg(gf);
+    }
     for(int i = 0; i < CTX::instance()->mesh.nbSmoothing; i++) 
       laplaceSmoothing(gf);
   }
@@ -1378,8 +1384,10 @@ static bool meshGeneratorPeriodic(GFace *gf, bool debug = true)
   if(algoDelaunay2D(gf)){
     if(CTX::instance()->mesh.algo2d == ALGO_2D_FRONTAL)
       bowyerWatsonFrontal(gf);
-    else
+    else if(CTX::instance()->mesh.algo2d == ALGO_2D_DELAUNAY)
       bowyerWatson(gf);
+    else 
+      meshGFaceBamg(gf);
     for(int i = 0; i < CTX::instance()->mesh.nbSmoothing; i++) 
       laplaceSmoothing(gf);
   }
@@ -1444,11 +1452,14 @@ void meshGFace::operator() (GFace *gf)
   }
 
   const char *algo = "Unknown";
-  if(algoDelaunay2D(gf))
-    algo = (CTX::instance()->mesh.algo2d == ALGO_2D_FRONTAL) ? 
-      "Frontal" : "Delaunay";
+  if(CTX::instance()->mesh.algo2d == ALGO_2D_FRONTAL)
+    algo = "Frontal";
+  else if(CTX::instance()->mesh.algo2d == ALGO_2D_DELAUNAY)
+    algo = "Delaunay";
   else if(CTX::instance()->mesh.algo2d == ALGO_2D_MESHADAPT_OLD)
     algo = "MeshAdapt (old)";
+  else if(CTX::instance()->mesh.algo2d == ALGO_2D_BAMG)
+    algo = "Bamg";
   else 
     algo = "MeshAdapt";
 
@@ -1471,7 +1482,7 @@ void meshGFace::operator() (GFace *gf)
        (gf, debugSurface >= 0 || debugSurface == -100))
       Msg::Error("Impossible to mesh face %d", gf->tag());
   }
-
+  
   Msg::Debug("Type %d %d triangles generated, %d internal vertices",
              gf->geomType(), gf->triangles.size(), gf->mesh_vertices.size());
 
diff --git a/Mesh/meshGFaceBamg.cpp b/Mesh/meshGFaceBamg.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..03e78f6e07cb82c91184bb24dfbe626177658af0
--- /dev/null
+++ b/Mesh/meshGFaceBamg.cpp
@@ -0,0 +1,214 @@
+#include <iostream>
+#include "meshGFaceBamg.h"
+#include "meshGFaceLloyd.h"
+#include "GmshMessage.h"
+#include "GFace.h"
+#include "GModel.h"
+#include "MVertex.h"
+#include "MTriangle.h"
+#include "MLine.h"
+#include "GmshConfig.h"
+#include "Context.h"
+#include <list>
+#include <map>
+#include "BackgroundMesh.h"
+
+#ifdef HAVE_BAMG
+long verbosity = 0;
+#include "Mesh2d.hpp"
+#include "Mesh2.h"
+Mesh2 *Bamg(Mesh2 *Thh, double * args,double *mm11,double *mm12,double *mm22, bool);
+//#include "bamg-gmsh.hpp"
+
+static void computeMeshMetricsForBamg (GFace *gf,
+				       int numV,
+				       Vertex2 *bamgVertices,  
+				       double *mm11, 
+				       double *mm12, 
+				       double *mm22,
+				       int iter ){
+  //  char name[245];
+  //  sprintf(name,"bgmBamg-%d-%d.pos",gf->tag(),iter);
+  //  if (iter < 2){
+  //    backgroundMesh::set(gf);
+  //    backgroundMesh::current()->print(name, 0);
+  //  }
+
+  fullMatrix<double> J(2,3), JT(3,2),M(3,3),R(2,2),W(2,3);
+  for (int i=0;i<numV;++i){
+    double u = bamgVertices[i][0];
+    double v = bamgVertices[i][1];
+    GPoint gp = gf->point(SPoint2(u,v));
+    SMetric3 m = BGM_MeshMetric(gf,u,v,gp.x(),gp.y(),gp.z());
+    
+    // compute the derivatives of the parametrization
+    Pair<SVector3, SVector3> der = gf->firstDer(SPoint2(u, v));
+
+    J(0,0) = JT(0,0) = der.first().x();
+    J(0,1) = JT(1,0) = der.first().y();
+    J(0,2) = JT(2,0) = der.first().z();
+    J(1,0) = JT(0,1) = der.second().x();
+    J(1,1) = JT(1,1) = der.second().y();
+    J(1,2) = JT(2,1) = der.second().z();
+
+    m.getMat(M);
+    J.mult(M,W);
+    W.mult(JT,R);
+    bamg::Metric M1(R(0,0),R(1,0),R(1,1));
+    mm11[i] = M1.a11;
+    mm12[i] = M1.a21;
+    mm22[i] = M1.a22;    
+  }
+
+
+}
+
+static void meshGFaceBamg_ ( GFace *gf , int iter, bool initialMesh){
+  std::set<MVertex*> all;
+  std::map<int,MVertex*> recover;
+  for (int i=0;i<gf->triangles.size();i++){
+    for (int j=0;j<3;j++)all.insert(gf->triangles[i]->getVertex(j));
+  }
+  Vertex2 *bamgVertices = new Vertex2[all.size()];
+  int index = 0;
+  for(std::set<MVertex*>::iterator it = all.begin(); it!=all.end(); ++it){
+    if ((*it)->onWhat()->dim() < 2){
+      SPoint2 p;
+      bool success = reparamMeshVertexOnFace(*it, gf, p);
+      bamgVertices[index][0] = p.x();
+      bamgVertices[index][1] = p.y();
+      bamgVertices[index].lab = index;
+      recover[index] = *it;
+      (*it)->setIndex(index++);
+    }
+  }
+  int nbFixedVertices = index;
+  for(std::set<MVertex*>::iterator it = all.begin(); it!=all.end(); ++it){
+    // FIXME : SEAMS should have to be taken into account here !!!
+    if ((*it)->onWhat()->dim() >= 2){
+      SPoint2 p;
+      bool success = reparamMeshVertexOnFace(*it, gf, p);
+      bamgVertices[index][0] = p.x();
+      bamgVertices[index][1] = p.y();
+      recover[index] = *it;
+      (*it)->setIndex(index++);
+    }
+  }
+
+  Triangle2 *bamgTriangles = new Triangle2[gf->triangles.size()];
+  for (int i=0;i<gf->triangles.size();i++){    
+
+    int nodes [3] = {gf->triangles[i]->getVertex(0)->getIndex(),
+		     gf->triangles[i]->getVertex(1)->getIndex(),
+		     gf->triangles[i]->getVertex(2)->getIndex()};
+    double u1(bamgVertices[nodes[0]][0]);
+    double u2(bamgVertices[nodes[1]][0]);
+    double u3(bamgVertices[nodes[2]][0]);
+    double v1(bamgVertices[nodes[0]][1]);
+    double v2(bamgVertices[nodes[1]][1]);
+    double v3(bamgVertices[nodes[2]][1]);
+    double sign = (u2-u1)*(v3-v1) - (u3-u1)*(v2-v1);
+    if (sign < 0){
+      int temp = nodes[0];
+      nodes[0] = nodes[1];
+      nodes[1] = temp;
+    }
+    
+    bamgTriangles[i].init (bamgVertices,nodes,gf->tag());
+  }
+  std::list<GEdge*> edges = gf->edges();
+  int numEdges = 0;
+  for (std::list<GEdge*>::iterator it = edges.begin(); it != edges.end(); ++it){
+    numEdges += (*it)->lines.size();
+  }
+
+  Seg *bamgBoundary = new Seg[numEdges];
+
+  int count = 0;
+  for (std::list<GEdge*>::iterator it = edges.begin(); it != edges.end(); ++it){
+    for (int i=0; i<(*it)->lines.size();++i){
+      int nodes [2] = {(*it)->lines[i]->getVertex(0)->getIndex(),
+		       (*it)->lines[i]->getVertex(1)->getIndex()};      
+      bamgBoundary[count].init (bamgVertices,nodes,(*it)->tag());
+      bamgBoundary[count++].lab = count;
+    }
+  }
+  Mesh2 bamgMesh ( all.size(), gf->triangles.size(), numEdges,
+		   bamgVertices, bamgTriangles,bamgBoundary);
+  double *mm11 = new double [all.size()];
+  double *mm12 = new double [all.size()];
+  double *mm22 = new double [all.size()];
+  double args[256];
+  computeMeshMetricsForBamg (gf,all.size(),bamgVertices,mm11,mm12,mm22,iter);
+  for (int i=0;i<256;i++)args[i] = -1.1e100;
+  Mesh2 *refinedBamgMesh = 0;
+  try{
+    refinedBamgMesh = Bamg (&bamgMesh, args, mm11,mm12,mm22, initialMesh);
+    Msg::Info ("bamg succeeded %d vertices %d triangles",
+	       refinedBamgMesh->nv,refinedBamgMesh->nt);
+  }
+  catch(...){
+    Msg::Error ("bamg failed");
+    return ;
+  }
+  delete [] mm11;
+  delete [] mm12;
+  delete [] mm22;
+  std::map<int,MVertex*> yetAnother;
+  for (int i=0;i< refinedBamgMesh->nv;i++){
+    Vertex2 &v = refinedBamgMesh->vertices[i];
+    //    printf("v.lab = %d\n",v.lab);
+    if (i >= nbFixedVertices){
+      GPoint gp = gf->point(SPoint2(v[0],v[1]));
+      MFaceVertex *x = new MFaceVertex(gp.x(),gp.y(),gp.z(),gf,v[0],v[1]);
+      yetAnother[i] = x;
+      gf->mesh_vertices.push_back(x);
+    }
+    else {
+      yetAnother[i] = recover[i];
+    }
+  }
+
+  for (int i=0;i<gf->triangles.size();i++){    
+    delete gf->triangles[i];
+  }
+  gf->triangles.clear();
+  for (int i=0;i< refinedBamgMesh->nt;i++){
+    Triangle2 &t = refinedBamgMesh->triangles[i];
+    Vertex2 &v1 = t[0];
+    Vertex2 &v2 = t[1];
+    Vertex2 &v3 = t[2];
+    gf->triangles.push_back(new MTriangle(yetAnother[(*refinedBamgMesh)(v1)],
+					  yetAnother[(*refinedBamgMesh)(v2)],
+					  yetAnother[(*refinedBamgMesh)(v3)]
+					  ));    
+  }
+
+
+  if (refinedBamgMesh)delete refinedBamgMesh;
+}
+void meshGFaceBamg ( GFace *gf ){
+
+  int nT = gf->triangles.size();
+  //  meshGFaceBamg_ ( gf , 0, true);
+  for (int i=1;i<14;i++){
+    //    char name[245];
+    //    sprintf(name,"hop%d.msh",i);
+    //    GModel::current()->writeMSH(name);
+    meshGFaceBamg_ ( gf , i, false);
+    //    sprintf(name,"hap%d.msh",i);
+    //    GModel::current()->writeMSH(name);
+    
+    int nTnow = gf->triangles.size();
+    if (fabs((double)(nTnow - nT)) < 0.01 * nT)break;
+    nT = nTnow;
+  }
+  //  lloydAlgorithm lloyd (20);
+  //  lloyd(gf);
+}
+
+#else
+void meshGFaceBamg ( GFace *gf ){
+  Msg::Fatal("Gmsh msust be compiled with the Bidimensional Anisotropic Mesh Generator (Bamg) in order to support that option");
+}
+#endif
diff --git a/Mesh/meshGFaceBamg.h b/Mesh/meshGFaceBamg.h
new file mode 100644
index 0000000000000000000000000000000000000000..dc57394256970a4303defc0f0249838f9e319267
--- /dev/null
+++ b/Mesh/meshGFaceBamg.h
@@ -0,0 +1,6 @@
+#ifndef _MESHGFACE_BAMG_
+#define _MESHGFACE_BAMG_
+class GFace;
+void meshGFaceBamg ( GFace *gf );
+
+#endif
diff --git a/Numeric/fullMatrix.cpp b/Numeric/fullMatrix.cpp
index 632e1a93ccc31f96f79ef6684025e50c7123a923..d6bc9400ebb9d55bd915b34fb0fc170447a2af19 100644
--- a/Numeric/fullMatrix.cpp
+++ b/Numeric/fullMatrix.cpp
@@ -259,7 +259,7 @@ bool fullMatrix<double>::invertInPlace()
 
   if(info == 0) return true;
   if(info > 0)
-    Msg::Error("U(%d,%d)=0 in matrix inversion", info, info);
+    Msg::Error("U(%d,%d)=0 in matrix in place inversion", info, info);
   else
     Msg::Error("Wrong %d-th argument in matrix inversion", -info);
   return false;
diff --git a/benchmarks/2d/Square-01.geo b/benchmarks/2d/Square-01.geo
index a31a52030be939cdfa67fc015b91fb62ce132f00..e6aab03099f01d00f9dce173efdc20436f26f101 100644
--- a/benchmarks/2d/Square-01.geo
+++ b/benchmarks/2d/Square-01.geo
@@ -1,8 +1,9 @@
-lc = .1;       
+fact = 100;
+lc = .1 * fact;       
 Point(1) = {0.0,0.0,0,lc};       
-Point(2) = {1,0.0,0,lc};       
-Point(3) = {1,1,0,lc};       
-Point(4) = {0,1,0,lc};       
+Point(2) = {1* fact,0.0,0,lc};       
+Point(3) = {1* fact,1* fact,0,lc*.1};       
+Point(4) = {0,1* fact,0,lc};       
 Line(1) = {3,2};       
 Line(2) = {2,1};       
 Line(3) = {1,4};       
diff --git a/benchmarks/2d/naca12_2d.geo b/benchmarks/2d/naca12_2d.geo
index 6baf8b1e2f6c2a3f617ea1ecab6b61bc1b7032e4..d5d5e3a6b666680d8d67bc61b5582083686c44d4 100644
--- a/benchmarks/2d/naca12_2d.geo
+++ b/benchmarks/2d/naca12_2d.geo
@@ -1,5 +1,5 @@
 lc = 0.2 ;
-lc2 = 1 ;
+lc2 = 10 ;
 lc3 = 0.1 ;
 Point(1) =  {1.000000e+00,0.000000e+00,0.000000e+00,lc3}; 
 Point(2) =  {9.997533e-01,0.000000e+00,-3.498543e-05,lc}; 
diff --git a/benchmarks/2d/square.geo b/benchmarks/2d/square.geo
index f71192fde8f4f84386c89297a0f70bc6d6e96103..62bd5d191c4c25b5f0dddc76bf1bac1d3aa0abed 100644
--- a/benchmarks/2d/square.geo
+++ b/benchmarks/2d/square.geo
@@ -1,8 +1,9 @@
-lc=0.03;
+
+lc=0.3;
 Point(1) = {0, 0, 0,lc};
-Point(2) = {0, 1, 0,lc};
-Point(3) = {1, 1, 0,lc};
-Point(4) = {1, 0, 0,lc};
+Point(2) = {0, 1, 0,lc/1};
+Point(3) = {1, 1, 0,lc/1};
+Point(4) = {1, 0, 0,lc/1};
 Line(1) = {2, 3};
 Line(2) = {3, 4};
 Line(3) = {4, 1};
diff --git a/benchmarks/2d/wing-splines.geo b/benchmarks/2d/wing-splines.geo
index 55d9ee96ee923da62e5e15660fd00ced8e713681..a6eeab357b6fdb9c543f084781a70a7617c231cc 100644
--- a/benchmarks/2d/wing-splines.geo
+++ b/benchmarks/2d/wing-splines.geo
@@ -1,6 +1,7 @@
-scale = 1 ;
 
-lc_wing = 0.1 * scale ;
+scale = .01 ;
+
+lc_wing = 0.0001 * scale ;
 lc_box = 10 * scale ;
 
 Point(3895) = {1.177410e-02*scale,-2.768003e-03*scale,0,lc_wing};
@@ -513,29 +514,9 @@ Point(4268) = {1.114765e+00*scale,-1.246442e-01*scale,0,lc_wing};
 Point(4291) = {1.120249e+00*scale,-1.301373e-01*scale,0,lc_wing};
 Point(4336) = {1.122990e+00*scale,-1.328839e-01*scale,0,lc_wing};
 
-Point(11) = {4.552264e+01*scale,-2.254225e+01*scale,0,lc_box};
-Point(2233) = {4.552264e+01*scale,-1.129225e+01*scale,0,lc_box};
-Point(5) = {4.552264e+01*scale,-4.224671e-02*scale,0,lc_box};
-Point(2236) = {4.552264e+01*scale,1.120775e+01*scale,0,lc_box};
-Point(14) = {4.552264e+01*scale,2.245775e+01*scale,0,lc_box};
 Point(2) = {4.552264e+01*scale,4.495775e+01*scale,0,lc_box};
-Point(15) = {2.302264e+01*scale,4.495775e+01*scale,0,lc_box};
-Point(2301) = {1.177264e+01*scale,4.495775e+01*scale,0,lc_box};
-Point(6) = {5.226384e-01*scale,4.495775e+01*scale,0,lc_box};
-Point(2304) = {-1.072736e+01*scale,4.495775e+01*scale,0,lc_box};
-Point(18) = {-2.197736e+01*scale,4.495775e+01*scale,0,lc_box};
 Point(3) = {-4.447736e+01*scale,4.495775e+01*scale,0,lc_box};
-Point(19) = {-4.447736e+01*scale,2.245775e+01*scale,0,lc_box};
-Point(2240) = {-4.447736e+01*scale,1.120775e+01*scale,0,lc_box};
-Point(7) = {-4.447736e+01*scale,-4.224671e-02*scale,0,lc_box};
-Point(2243) = {-4.447736e+01*scale,-1.129225e+01*scale,0,lc_box};
-Point(22) = {-4.447736e+01*scale,-2.254225e+01*scale,0,lc_box};
 Point(4) = {-4.447736e+01*scale,-4.504225e+01*scale,0,lc_box};
-Point(23) = {-2.197736e+01*scale,-4.504225e+01*scale,0,lc_box};
-Point(2317) = {-1.072736e+01*scale,-4.504225e+01*scale,0,lc_box};
-Point(8) = {5.226384e-01*scale,-4.504225e+01*scale,0,lc_box};
-Point(2297) = {1.177264e+01*scale,-4.504225e+01*scale,0,lc_box};
-Point(10) = {2.302264e+01*scale,-4.504225e+01*scale,0,lc_box};
 Point(1) = {4.552264e+01*scale,-4.504225e+01*scale,0,lc_box};
 
 //one
@@ -612,7 +593,7 @@ Line Loop(405) = {10,11,12};
 Plane Surface(406) = {403,404,401,405};
 
 lc4 = lc_wing * 4;
-
+/*
 Point(4351) = {0.4,-0,0,lc4};
 Point(4352) = {1.4,0,0,lc4};
 Point(4353) = {0.4,-1,0,lc4};
@@ -622,4 +603,4 @@ Circle(407) = {4352,4351,4355};
 Circle(408) = {4355,4351,4354};
 Circle(409) = {4354,4351,4353};
 Circle(410) = {4353,4351,4352};
-
+*/
diff --git a/benchmarks/boolean/constraintSurface.lua b/benchmarks/boolean/constraintSurface.lua
index 85dee40eb7ac9d72466d067663ce2bf46782b3e9..bf9aa6020d02325d1139395381502b7061e61d3b 100644
--- a/benchmarks/boolean/constraintSurface.lua
+++ b/benchmarks/boolean/constraintSurface.lua
@@ -3,30 +3,30 @@ g = GModel()
 v1 = g:addVertex(0, 0, 0, .1)
 v2 = g:addVertex(1, 0, 0, .1)
 v3 = g:addVertex(1, 1, 0, .1)
-v4 = g:addVertex(0, 1, 1, .1)
+v4 = g:addVertex(0, 3, 1, .1)
 v5 = g:addVertex(2, 3, 0, .1)
 v6 = g:addVertex(-2, 3, 0, .1)
 v7 = g:addVertex(-1, 3, 0, .1)
 
-v11 = g:addVertex(2.5, 2.5, 0, .1)
-v12 = g:addVertex(2.6, 2.5, 0, .1)
-v13 = g:addVertex(2.6, 2.6, 0, .1)
-v14 = g:addVertex(2.5, 2.6, 0, .1)
+--v11 = g:addVertex(2.5, 2.5, 0, .1)
+--v12 = g:addVertex(2.6, 2.5, 0, .1)
+--v13 = g:addVertex(2.6, 2.6, 0, .1)
+--v14 = g:addVertex(2.5, 2.6, 0, .1)
 
 
 e7 = g:addBezier (v2,v1, {{v3:x(),v3:y(),0},{v4:x(),v4:y(),0},{v5:x(),v5:y(),0},{v6:x(),v6:y(),0},{v7:x(),v7:y(),0}}); 							   
-e8 = g:addLine (v2,v1);
+--e8 = g:addLine (v2,v1);
 
-v221 = g:addVertex(0, 0, 1, .1)
-v121 = g:addVertex(1, 0, 1, .1)
-e17 = g:addBezier (v121,v221, {{v3:x()+1,v3:y(),1},{v4:x(),v4:y(),1},{v5:x(),v5:y(),1},{v6:x(),v6:y(),1},{v7:x(),v7:y(),1}}); 							   
+v221 = g:addVertex(0, 0, 10, .1)
+v121 = g:addVertex(1, 0, 10, .1)
+e17 = g:addBezier (v121,v221, {{v3:x()+1,v3:y(),10},{v4:x(),v4:y()+2,10},{v5:x(),v5:y()-3,10},{v6:x(),v6:y(),10},{v7:x(),v7:y(),10}}); 							   
 
-e11 = g:addLine (v11,v12);
-e12 = g:addLine (v12,v13);
-e13 = g:addLine (v13,v14);
-e14 = g:addLine (v14,v11);
+--e11 = g:addLine (v11,v12);
+--e12 = g:addLine (v12,v13);
+--e13 = g:addLine (v13,v14);
+--e14 = g:addLine (v14,v11);
 
 
 g:addRuledFaces ({{e7},{e17}})
-g:addFace ({e7,e8},{{0,0,0}})
-g:addFace ({e11,e12,e13,e14})
+--g:addFace ({e7,e8},{{0,0,0}})
+--g:addFace ({e11,e12,e13,e14})
diff --git a/benchmarks/boolean/cube1.lua b/benchmarks/boolean/cube1.lua
index 72effd501f017fde744b17d4c5c392eeba8186e3..ad5499c9ff74a2b2929a13c0b8b8d757a5e20e22 100644
--- a/benchmarks/boolean/cube1.lua
+++ b/benchmarks/boolean/cube1.lua
@@ -4,7 +4,7 @@ g = GModel()
 v1 = g:addVertex(0, 0, 0, 1)
 v2 = g:addVertex(1, 0, 0, 1)
 e1 = g:addLine(v1, v2)
-f1 = g:extrude(e1, {0,0,0}, {0,1,0})
+f1 = g:extrude(e1, {0,0,0}, {0,10,0})
 r1 = g:extrude(f1, {0,0,0}, {0,0,1})
 r1 = g:revolve(f1, {-.1,0,0}, {-.1,1,0}, 3.1415 / 2)
 
diff --git a/benchmarks/boolean/nurbs.lua b/benchmarks/boolean/nurbs.lua
index bd83cf472f7512f1952a742e085c6e325b5a3d1e..5c0b048e6ad369b88c188cdb2d366b3d664c0267 100644
--- a/benchmarks/boolean/nurbs.lua
+++ b/benchmarks/boolean/nurbs.lua
@@ -9,22 +9,22 @@ v5 = g:addVertex(2,1,0,.1);
 v6 = g:addVertex(2.5,-.05,0,.1); 
 v7 = g:addVertex(1.5,-1,0,.1); 
 
-g:addLine(v1,v3);
-g:addLine(v3,v4);
-g:addLine(v4,v5);
-g:addLine(v5,v6);
-g:addLine(v6,v7);
-g:addLine(v7,v2);
+--g:addLine(v1,v3);
+--g:addLine(v3,v4);
+--g:addLine(v4,v5);
+--g:addLine(v5,v6);
+--g:addLine(v6,v7);
+--g:addLine(v7,v2);
 
 --g:addNURBS (v1,v2, {{0.1,0.1,0},{0.2,0.1,0},{0.3,0.2,0},{0.4,0.6,0},{0.9,0.8,0}},
 --	   {0,0,0,0,0.25,0.5,0.75,1,1,1,1},{1,1,1,1,1,1,1},{4,1,1,1,1,1,4}); 
 
-g:addBezier (v1,v2, {{v3:x(),v3:y(),0},{v4:x(),v4:y(),0},{v5:x(),v5:y(),0},{v6:x(),v6:y(),0},{v7:x(),v7:y(),0}}); 
-g:addNURBS (v1,v2, {{v3:x(),v3:y(),0},{v4:x(),v4:y(),0},{v5:x(),v5:y(),0},{v6:x(),v6:y(),0},{v7:x(),v7:y(),0}},
-            {0,0.25,0.5,0.75,1},{1,1,1,1,1,1,1},{4,1,1,1,4}); 							   
-g:addNURBS (v1,v2, {{v3:x(),v3:y(),0},{v4:x(),v4:y(),0},{v5:x(),v5:y(),0},{v6:x(),v6:y(),0},{v7:x(),v7:y(),0}},	   
-	   {0,0.5,1},{1,1,1,1,1,1,1},{4,3,4}); 							   
+--g:addBezier (v1,v2, {{v3:x(),v3:y(),0},{v4:x(),v4:y(),0},{v5:x(),v5:y(),0},{v6:x(),v6:y(),0},{v7:x(),v7:y(),0}}); 
+--g:addNURBS (v1,v2, {{v3:x(),v3:y(),0},{v4:x(),v4:y(),0},{v5:x(),v5:y(),0},{v6:x(),v6:y(),0},{v7:x(),v7:y(),0}},
+--            {0,0.25,0.5,0.75,1},{1,1,1,1,1,1,1},{4,1,1,1,4}); 							   
+--g:addNURBS (v1,v2, {{v3:x(),v3:y(),0},{v4:x(),v4:y(),0},{v5:x(),v5:y(),0},{v6:x(),v6:y(),0},{v7:x(),v7:y(),0}},	   	   {0,0.5,1},{1,1,1,1,1,1,1},{4,3,4}); 							   
 
-g:addNURBS (v1,v2, {{v3:x(),v3:y(),0},{v4:x(),v4:y(),0},{v5:x(),v5:y(),0},{v6:x(),v6:y(),0},{v7:x(),v7:y(),0}},	   
+e1 = g:addNURBS (v1,v2, {{v3:x(),v3:y(),0},{v4:x(),v4:y(),0},{v5:x(),v5:y(),0},{v6:x(),v6:y(),0},{v7:x(),v7:y(),0}},	   
 	   {0,1/3.,2./3.,1},{1,1,1,1,1,1,1},{5,1,1,5}); 							   
 
+f1 = g:extrude(e1, {0,0,0}, {0,0,1})
diff --git a/contrib/bamg/CMakeLists.txt b/contrib/bamg/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..adfc2be32d650df0055a405d82643a5b2dd95d02
--- /dev/null
+++ b/contrib/bamg/CMakeLists.txt
@@ -0,0 +1,24 @@
+# Gmsh - Copyright (C) 1997-2010 C. Geuzaine, J.-F. Remacle
+#
+# See the LICENSE.txt file for license information. Please report all
+# bugs and problems to <gmsh@geuz.org>.
+
+set(SRC
+  Mesh2d.cpp 
+  bamg-gmsh.cpp 
+  bamglib/Mesh2.cpp
+  bamglib/MeshGeom.cpp	
+  bamglib/MeshRead.cpp	
+  bamglib/Metric.cpp	
+  bamglib/R2.cpp
+  bamglib/MeshDraw.cpp
+  bamglib/MeshQuad.cpp	
+  bamglib/Mesh2.cpp
+  bamglib/MeshWrite.cpp	
+  bamglib/Meshio.cpp	
+  bamglib/QuadTree.cpp	
+  bamglib/SetOfE4.cpp
+)
+
+file(GLOB_RECURSE HDR RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} *.hpp)
+append_gmsh_src(contrib/bamg "${SRC};${HDR}")
diff --git a/contrib/bamg/Label.hpp b/contrib/bamg/Label.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..5c6357ae14148cec3ea8dcc72f3beea594bca0e3
--- /dev/null
+++ b/contrib/bamg/Label.hpp
@@ -0,0 +1,15 @@
+#ifndef LABEL_HPP
+#define LABEL_HPP
+ 
+class Label {  // reference number for the physics
+  public: 
+  int lab;
+  Label(int r=0):lab(r){}
+  bool onGamma() const { return lab;} 
+  };
+ inline ostream& operator <<(ostream& f,const Label & r  )
+    { f <<  r.lab ; return f; }
+ inline istream& operator >>(istream& f, Label & r  )
+    { f >>  r.lab ; return f; }
+
+#endif
diff --git a/contrib/bamg/Mesh2d.cpp b/contrib/bamg/Mesh2d.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..315d404f54dde8fe1141e4fb53e48fbedca1be28
--- /dev/null
+++ b/contrib/bamg/Mesh2d.cpp
@@ -0,0 +1,48 @@
+#include <cassert>
+#include <fstream>
+#include <iostream>
+#include "ufunction.hpp"
+#include "Mesh2d.hpp"
+
+Mesh2::Mesh2(const char * filename)
+  : nv(0),nt(0),nbe(0),
+    area(0),peri(0),
+    vertices(0),triangles(0),borderelements(0)
+{ // read the mesh
+  int i,iv[3],ir;
+  ifstream f(filename);
+  if(!f) {cerr << "Mesh2::Mesh2 Erreur openning " << filename<<endl;exit(1);}
+  cout << " Read On file \"" <<filename<<"\""<<  endl;
+  f >> nv >> nt >> nbe ;
+  cout << " Nb of Vertex " << nv << " Nb of Triangle2s " << nt 
+       << " Nb of Border Seg : " << nbe << endl;
+  assert(f.good() && (nt>0) && (nv>0) &&( nbe>0) ) ;
+  triangles = new Triangle2 [nt];
+  vertices = new Vertex[nv];
+  borderelements = new Seg[nbe];
+  area=0;
+  assert(triangles && vertices && borderelements);
+  for (i=0;i<nv;i++)    
+    {
+      f >> vertices[i];
+      assert(f.good());
+    }
+  for (i=0;i<nt;i++) 
+    { 
+      f >> iv[0] >> iv[1] >> iv[2] >> ir;
+      assert(f.good() && iv[0]>0 && iv[0]<=nv && iv[1]>0 && iv[1]<=nv && iv[2]>0 && iv[2]<=nv);
+      for (int v=0;v<3;++v) iv[v]--;
+      triangles[i].init(vertices,iv,ir); 
+      area += triangles[i].area;
+    }
+  for (i=0;i<nbe;i++) 
+    { 
+      f >> iv[0] >> iv[1]  >> ir;
+      assert(f.good() && iv[0]>0 && iv[0]<=nv && iv[1]>0 && iv[1]<=nv);
+      for (int v=0;v<2;++v) iv[v]--;
+      borderelements[i].init(vertices,iv,ir); 
+      peri += borderelements[i].l;
+    }
+
+  cout << " End of read: area = " << area << "  perimeter: " << peri << endl;  
+}
diff --git a/contrib/bamg/Mesh2d.hpp b/contrib/bamg/Mesh2d.hpp
new file mode 100755
index 0000000000000000000000000000000000000000..4c54887ceae1b681c29dd92d291761e2b70705a8
--- /dev/null
+++ b/contrib/bamg/Mesh2d.hpp
@@ -0,0 +1,170 @@
+// la regle de programmation 3  
+#include "assertion.hpp" 
+#include <cstdlib>
+using namespace std;
+// definition R
+#include "Label.hpp"
+#include "R2.hpp"
+  
+
+class Vertex2 : public R2,public Label {
+  friend  ostream& operator <<(ostream& f, const Vertex2 & v )
+    { f << (R2) v << ' ' << (Label &) v   ; return f; }
+  friend  istream& operator >> (istream& f,  Vertex2 & v )
+      { f >> (R2 &) v >> (Label &) v ; return f; }
+   public:
+   Vertex2() : R2(),Label(){};
+  //   Vertex2(R2 P,int r=0): R2(P),Label(r){}
+   private: // pas de copie pour ne pas perdre l'adresse
+     Vertex2(const Vertex2 &);
+     void operator=(const Vertex2 &); 
+};
+
+
+
+
+
+
+
+class Triangle2: public Label {
+  // variable prive 
+  Vertex2 *vertices[3]; // an array of 3 pointer to vertex
+  public:
+  R area;
+  Triangle2() :area() {vertices[0]=vertices[1]=vertices[2]=0;}; // constructor empty for array
+  Vertex2 & operator[](int i) const {
+     ASSERTION(i>=0 && i <3);
+     return *vertices[i];} // to see traingle as a array of vertex
+  Vertex2 * & operator()(int i) {
+     ASSERTION(i>=0 && i <3);
+     return vertices[i];} // to see traingle as a array of vertex
+  void init(Vertex2 * v0,int * iv,int r) 
+    { vertices[0]=v0+iv[0];
+      vertices[1]=v0+iv[1];
+      vertices[2]=v0+iv[2]; 
+      R2 AB(*vertices[0],*vertices[1]);
+      R2 AC(*vertices[0],*vertices[2]);
+      area = (AB^AC)*0.5;
+      lab=r;
+      ASSERTION(area>0);    
+    }
+  R2 Edge(int i) const {ASSERTION(i>=0 && i <3);
+      return R2(*vertices[(i+1)%3],*vertices[(i+2)%3]);}// opposite edge vertex i
+  R2 H(int i) const { ASSERTION(i>=0 && i <3);
+      R2 E=Edge(i);return E.perp()/(2*area);} // heigth 
+
+  void Gradlambda(R2 * GradL) const
+  {
+    GradL[1]= H(1);
+    GradL[2]= H(2);
+    GradL[0]=-GradL[1]-GradL[2];
+  }
+
+  R lenEdge(int i) const {ASSERTION(i>=0 && i <3);
+      R2 E=Edge(i);return sqrt((E,E));}
+
+  // Transformation:  $\hat{K} \mapsto K$ 
+  R2 operator()(const R2 & Phat) const   {
+    const R2 &A =*vertices[0];
+    const R2 &B =*vertices[1];
+    const R2 &C =*vertices[2];
+    return (1-Phat.x- Phat.y)* A + Phat.x *B  +Phat.y*C  ;} 
+    
+ private:
+   Triangle2(const Triangle2 &); // pas de construction par copie
+   void operator=(const Triangle2 &);// pas affectation par copy 
+  // Ajoute FH  dernier cours ----
+public:
+  R  mesure() const {return area;}
+  static const int nv=3;  
+};
+
+
+
+
+
+// la classe pour le maillage du bord, ici des Segment: 
+class Seg: public Label {
+public:
+  static const int nv=2;     // the nomber of vertices 
+private:
+  Vertex2 *vertices[nv]; // an array of 2 pointer to vertex
+public:
+  R l; // lhe lenght of the segment
+
+  Seg() :l() {vertices[0]=vertices[1]=0;} // constructor empty for array
+
+  Vertex2 & operator[](int i) const {
+    ASSERTION(i>=0 && i <nv);
+    return *vertices[i];} // to see the segment  as a array of vertex
+
+  void init(Vertex2 * v0,int * iv,int r)  // the true constructor
+  { 
+    vertices[0]=v0+iv[0];
+    vertices[1]=v0+iv[1];
+    R2 AB(*vertices[0],*vertices[1]);
+    l=  AB.norme();
+    lab=r;
+    ASSERTION(l>0);    
+  }
+  
+  // Transformation:  $[0,1]  \mapsto K$ 
+  R2 operator()(const R & Phat) const   {
+    const R2 &A =*vertices[0];
+    const R2 &B =*vertices[1];
+    return (1-Phat)* A + Phat *B  ;} 
+
+  R  mesure() const {return l;}
+
+private:
+  Seg(const Seg &); // pas de construction par copie
+  void operator=(const Seg &);// pas affectation par copy 
+};
+
+
+
+
+class Mesh2 
+{ 
+public:
+  typedef Triangle2 Element;   
+  typedef Seg  BorderElement;
+  typedef R2 Rd;
+  typedef Vertex2  Vertex;
+  int nv,nt, nbe;
+  R area,peri;
+  Vertex2 *vertices;
+  Triangle2 *triangles;
+  Seg * borderelements;
+  Triangle2 & operator[](int i) const {return triangles[CheckT(i)];}
+  Vertex2 & operator()(int i) const {return vertices[CheckV(i)];}
+  Seg & be(int i) const {return borderelements[CheckBE(i)];} // boundary element ..
+  Mesh2(const char * filename); // read on a file
+  Mesh2(int nnv,int nnt,int nnbe, Vertex2 *v,Triangle2 *t, Seg *b_e)
+    : nv(nnv),nt(nnt),nbe(nnbe),vertices(v),triangles(t),borderelements(b_e),area(0.),peri(0.)  
+  {
+    for(int i=0;i<nt;++i) area += triangles[i].mesure();
+    for(int i=0;i<nbe;++i) peri += borderelements[i].mesure();
+  }
+  int operator()(const Triangle2 & t) const {return CheckT(&t - triangles);}
+  int operator()(const Triangle2 * t) const {return CheckT(t - triangles);}
+  int operator()(const Vertex2 & v) const {return CheckV(&v - vertices);}
+  int operator()(const Vertex2  * v) const{return CheckV(v - vertices);}
+  int operator()(const Seg & v) const {return CheckBE(&v - borderelements);}
+  int operator()(const Seg  * v) const{return CheckBE(v - borderelements);}
+  int operator()(int it,int j) const {return (*this)(triangles[it][j]);}// Nu vertex j of triangle it
+  //  to check the bound 
+  int CheckV(int i) const { ASSERTION(i>=0 && i < nv); return i;} 
+  int CheckT(int i) const { ASSERTION(i>=0 && i < nt); return i;}
+  int CheckBE(int i) const { ASSERTION(i>=0 && i < nbe); return i;}
+  ~Mesh2() { 
+    delete [] vertices; 
+    delete [] triangles;
+    delete [] borderelements;}
+ private:
+   Mesh2(const Mesh2 &); // pas de construction par copie
+   void operator=(const Mesh2 &);// pas affectation par copy 
+};
+
+
+ 
diff --git a/contrib/bamg/R2.hpp b/contrib/bamg/R2.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..98581dd13cd55e10005b0f528c35d99dacb3b279
--- /dev/null
+++ b/contrib/bamg/R2.hpp
@@ -0,0 +1,71 @@
+#ifndef R2_HPP
+#define  R2_HPP
+#include <cmath>
+#include <cstdlib>
+#include <iostream>
+// Definition de la class R2 
+//  sans compilation separe toute les fonctions 
+// sous defini dans ce R2.hpp avec des inline 
+//  
+// definition R (les nombres reals)
+// remarque la fonction abort est defini dans 
+// #include <cstdlib> 
+typedef double R;
+
+// The class R2
+class R2 {
+public:  
+  typedef double R;
+  static const int d=2;
+
+  R x,y;  // declaration de membre 
+  // les 3 constructeurs ---
+  R2 () :x(0.),y(0.) {} // rappel : x(0), y(0)  sont initialiser via le constructeur de double 
+  R2 (R a,R b):x(a),y(b)  {}
+  R2 (const R2 & a,const R2 & b):x(b.x-a.x),y(b.y-a.y)  {}
+  // le constucteur par defaut est inutile
+  R2 (const R2 & a) :x(a.x),y(a.y) {} 
+
+  // rappel les operator definis dans une class on un parametre
+  // cache qui est la classe elle meme (*this)
+
+  // les operateurs affectation
+  //  operateur affection (*this) = P est inutil par defaut il fait le travail correctement
+  R2 &  operator=(const R2 & P)  {x = P.x;y = P.y;return *this;}
+  // les autre operoteur affectations
+  R2 &  operator+=(const R2 & P)  {x += P.x;y += P.y;return *this;}
+  R2 &  operator-=(const R2 & P) {x -= P.x;y -= P.y;return *this;}
+  // operateur binaire + - * , ^ /
+  R2   operator+(const R2 & P)const   {return R2(x+P.x,y+P.y);}
+  R2   operator-(const R2 & P)const   {return R2(x-P.x,y-P.y);}
+  R    operator,(const R2 & P)const  {return  x*P.x+y*P.y;} // produit scalaire
+  R    operator^(const R2 & P)const {return  x*P.y-y*P.x;} // produit mixte
+  R2   operator*(R c)const {return R2(x*c,y*c);}
+  R2   operator/(R c)const {return R2(x/c,y/c);}
+  // operateur unaire 
+  R2   operator-()const  {return R2(-x,-y);} 
+  R2   operator+()const  {return *this;}
+  // un methode
+  R2   perp() const {return R2(-y,x);} // la perpendiculaire
+  // les operators  tableau
+  // version qui peut modifie la class  via l'adresse de x ou y 
+  R  &  operator[](int i){ return (&x)[i];}
+  const R  &  operator[](int i) const { return (&x)[i];}
+
+
+  R norme() const { return std::sqrt(x*x+y*y);}
+  R norme2() const { return (x*x+y*y);}
+
+friend  R2 operator*(R c,const R2 & P) {return P*c;} 
+friend  R2 perp(const R2 & P) { return R2(-P.y,P.x) ; }
+//inline R2 Perp(const R2 & P) { return P.perp(); }  // autre ecriture  de la fonction perp
+friend R  det(const R2 & A,const R2 & B,const R2 &C) { return R2(A,B)^R2(A,C);}
+
+friend  std::ostream& operator <<(std::ostream& f, const R2 & P )
+       { f << P.x << ' ' << P.y   ; return f; }
+friend  std::istream& operator >>(std::istream& f,  R2 & P)
+       { f >>  P.x >>  P.y  ; return f; }
+};
+
+#endif
+
diff --git a/contrib/bamg/RNM.hpp b/contrib/bamg/RNM.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..053efd1d3b50892f6988602abfa0dc839f09021d
--- /dev/null
+++ b/contrib/bamg/RNM.hpp
@@ -0,0 +1,1588 @@
+// ********** DO NOT REMOVE THIS BANNER **********
+// ORIG-DATE:    29 fev 2000  
+// -*- Mode : c++ -*-
+//
+// SUMMARY  : array modelisation 
+// USAGE    : LGPL      
+// ORG      : LJLL Universite Pierre et Marie Curie, Paris,  FRANCE 
+// AUTHOR   : Frederic Hecht
+// E-MAIL   : frederic.hecht@ann.jussieu.fr
+//
+
+/*
+ 
+
+ 
+ Freefem++ is free software; you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+ 
+ Freefem++  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 Lesser General Public License for more details.
+ 
+ You should have received a copy of the GNU Lesser General Public License
+ along with Freefem++; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ 
+
+ */
+#ifndef KNM_H_
+#define KNM_H_
+// version march  2010 FH.
+// add iterator for compatibility with gmm++
+// ----------------------
+// une tentative qui ne marche pas 
+// de tableau constant 
+#include <complex>
+#include <iostream>
+#include <iomanip>
+#include <cmath>
+#include <cassert>
+
+
+using namespace std;
+#define const_R   R
+
+#include <cstdlib>
+inline void Check_Kn(const char * str,const char * file,int line)
+{
+ cerr << "CHECK_KN: " << str << " in file: " << file << ", line " << line <<endl;
+ assert(0);
+ abort();
+}
+
+#define K_bigassert(i)  if (!(i)) Check_Kn(#i,__FILE__,__LINE__);
+#define RNM_FATAL_ERROR(i) Check_Kn(i,__FILE__,__LINE__);
+#ifdef CHECK_KN
+
+#define K_throwassert(i)  if (!(i)) Check_Kn(#i,__FILE__,__LINE__);
+
+#else
+#define K_throwassert(i) 
+#endif
+// version du 29 fev 2000  
+//  correction   for (... lj++,ui++  qui apelle le produit scalaire
+//  petite correction  throwassert 
+// ajoute de operateur /= et *= sur des vecteurs
+//   suppression de constructeur qui pose de probleme   
+//   correction oper +=  ...  dans RNM_op.h ligne 56  change = en oper
+// version de 25 nov 99  sans const R
+// ajoute de '.' pour extraire une colonne, ou ligne  , ...
+//  version du 22 nov 1999   cast to KN_<const R> 
+//   version du 21 nov 1999  correction delete 
+//  version du 13 nov 1999
+//  version du 18 mars 99
+//  F. Hecht 
+// attention les indexations les indexations peuvent changer
+//  puisque que l'on peut prendre la transposer d'une matrice
+// tableau 
+// mais ils partent de 0 
+// version corrigee du 15/11/98
+// version avec sous tableau  ---  mars 99 
+// -------
+//  remarque du 8 mars 99 FH
+// class pour prendre des sous-tableau
+// attention aux PB de continute dans les tableaux
+// on a supposer que les tableaux multi indices pouvait est vue comme 
+// un tableau continue ce qui est generalement faux quand l'on en 
+// prend un sous tableau
+//   exemple: un tableau 3,5 est numerote comme:
+//    0  3  6  9 12
+//    1  4  7 10 13
+//    2  5  8 11 14
+//             step
+//   indexi  n 1
+//   indexj  m n
+//   est le sous tableau  3,3  n'est pas numeroter consecutivement 
+//  
+//    Donc la fonction  IsVector1() nous dit si un tableau 
+//    a un 2 ou 3 indices est ou non consecutif en memoire
+//    
+//  --  ajoute d'une classe VirtualMatrice
+// pour modeliser le produit matrice vecteur 
+//  x = A*v; via des fonctions virtuelle 
+//  ---------------------------------- 
+//   version du 6 mars 2001 FH
+//   ---  initialisation --
+//   --------------------------------
+//   version du 9 oct 2001 FH
+//   ajoute de constructeur par defaut d'une vecteur
+//   +  set , pour definir le vecteur 
+//   ou l'affectation (bof bof) 
+// ---------------------
+//  version sep 2002
+//  ajoute  operateur >> pour  KN<R> et KN_<R>
+//  --------------------  
+//  version  april 2003
+//  ajoute un gestion auto de 
+//  la fonction InternalError pour les matriceVirtuel
+//  --------------------  
+//   version jan 2004
+//   correction pour go ++ 
+//   des operateur  #=  pour les matrices et tenseurs
+//  ----------------------
+//   version  feb 2004 
+//   v(i(:)) =  w   //  i(1:10) 
+//   w=u(i(:))  //  
+//   version mars 2004 make small correction
+//   in  ITAB operator problem if non type R a defi 
+//   -------------------
+//   Modif pour version avec les Complex   mai 2004                                                                                                 
+//   (u,v)  donne le produit complex utiliser dans le produit matrice vecteur
+//   (u,conj(v))  donne le produit hermitiene pour le gradient conjugue
+//
+//   -- de fonction dans le cas real                                                                                                                 
+// modif for g++ 4.0 and xlc++   mai 2005
+//  adding some this-> 
+//   mars 2007
+// correction in operator operation:b -1*c 
+// aout 2007, 
+//  correct y = A*x ; when y is unset 
+//  correct y += A*x ; when y is unset 
+//  re-correct += sep 2007
+//  add size of the matrix in VirtualMatrix class.
+//   mars 2010 add  unset KNM case ...
+// ----------------
+inline double  conj(const double & x){return x;}
+inline float  conj(const float &x){return x;}
+inline long  conj(const long &x){return x;}
+inline double  real(const double &x){return x;}
+inline float  real(const float &x){return x;}
+
+namespace RNM 
+{
+  template<class T> inline T Min (const T &a,const T &b){return a < b ? a : b;}
+  template<class T> inline T Max (const T &a,const T & b){return a > b ? a : b;}
+  template<class T> inline T Abs (const T &a){return a <0 ? -a : a;}
+  
+  template<class T> inline void Exchange (T& a,T& b) {T c=a;a=b;b=c;}
+  template<class T> inline T Max (const T &a,const T & b,const T & c){return Max(Max(a,b),c);}
+  template<class T> inline T Min (const T &a,const T & b,const T & c){return Min(Min(a,b),c);}
+  // specialisation cas complex ---
+  template<class T> 
+  inline complex<T> Min(const complex<T> &a,complex<T> &b)
+  { return complex<T>(min(a.real(),b.real()),min(a.imag(),b.imag()));}
+  template<class T> 
+  inline complex<T> Max(const complex<T> &a,const complex<T> &b)
+  { return complex<T>(max(a.real(),b.real()),max(a.imag(),b.imag()));}
+  
+  /*inline complex<double> Min(const complex<double> &a,complex<double> &b)
+    { return complex<double>(Min(real(a),real(b)),Min(imag(a),imag(b)));}
+    inline complex<double> Max(const complex<double> &a,const complex<double> &b)
+    { return complex<double>(Max(real(a),real(b)),Max(imag(a),imag(b)));}
+  */ 
+}
+//  ----                                                                                                                                             
+
+template<class R> class KNMK_ ;
+template<class R> class KNM_ ;
+template<class R> class KN_ ;
+template<class R> class KN__iterator ;
+template<class R> class KN__const_iterator ;
+template<class R> class TKN_ ; // KN_ transpose 
+template<class R> class notKN_ ; // KN_ not 
+template<class R> class notnotKN_ ; // KN_ not not 
+
+template<class R> class KNMK ;
+template<class R> class KNM ;
+template<class R> class KN ;
+
+template<class R> class conj_KN_ ;
+template<class R> class Add_KN_;
+template<class R> class Sub_KN_;
+template<class R> class Mulc_KN_;
+template<class R> class Add_Mulc_KN_;
+template<class R> class Mul_KNM_KN_; 
+template<class R> class DotStar_KN_;
+template<class R> class DotSlash_KN_;
+
+template<class R> class outProduct_KN_;
+template<class R> class if_KN_;
+template<class R> class if_arth_KN_;
+template<class R> class ifnot_KN_;
+template<class R,class I> class KN_ITAB; 
+
+template<class R,typename A,typename B> class F_KN_;
+
+
+#ifndef ffassert
+#define ffassert assert
+#endif
+
+// gestion des erreur interne --
+#ifndef InternalError
+typedef void (* TypeofInternalErrorRoutine)(const char *) ;
+static TypeofInternalErrorRoutine &InternalErrorRoutinePtr()
+{ 
+  static TypeofInternalErrorRoutine routine=0;
+  return routine;
+}
+
+static void InternalError(const char * str) {
+  if (InternalErrorRoutinePtr() ) (*InternalErrorRoutinePtr())(str);
+  cerr << str; 
+  exit(1);
+}
+inline void  SetInternalErrorRoutine(TypeofInternalErrorRoutine f) 
+{
+  InternalErrorRoutinePtr()=f;
+}
+#endif
+//  -- 
+template<class P,class Q> 
+   struct PplusQ { const P & p;const Q & q;
+    PplusQ(const P & pp,const Q & qq) : p(pp),q(qq){}
+    };
+
+template<class R> 
+struct  VirtualMatrice { public:
+    int N,M;
+    VirtualMatrice(int nn,int mm): N(nn),M(mm) {}
+    VirtualMatrice(int nn): N(nn),M(nn) {}
+  //  y += A x
+  virtual void addMatMul(const KN_<R> &  x, KN_<R> & y) const =0; 
+  virtual void addMatTransMul(const KN_<R> &  , KN_<R> & ) const 
+    { InternalError("VirtualMatrice::addMatTransMul not implemented "); }
+  virtual bool WithSolver() const {return false;} // by default no solver          
+  virtual void Solve( KN_<R> &  ,const KN_<R> & ) const 
+    { InternalError("VirtualMatrice::solve not implemented "); } 
+
+#ifdef VersionFreeFempp
+  virtual bool ChecknbLine  (int n) const= 0; 
+  virtual bool ChecknbColumn  (int m) const =0; 
+#else
+  virtual bool ChecknbLine  (int n) const {return true;} 
+  virtual bool ChecknbColumn  (int m) const {return true;}
+#endif
+  struct  plusAx { const VirtualMatrice * A; const KN_<R>   x;
+   plusAx( const VirtualMatrice * B,const KN_<R> &  y) :A(B),x(y) 
+      { ffassert(B->ChecknbColumn(y.N())); }
+    };
+    
+   plusAx operator*(const KN_<R> &  x) const {return plusAx(this,x);}
+   
+  struct  plusAtx { const VirtualMatrice * A; const KN_<R>   x;
+   plusAtx( const VirtualMatrice * B,const KN_<R> &  y) :A(B),x(y) 
+    {ffassert(B->ChecknbLine(y.N()));} };
+    
+  struct  solveAxeqb { const VirtualMatrice * A; const KN_<R>   b;
+   solveAxeqb( const VirtualMatrice * B,const KN_<R> &  y) :A(B),b(y) 
+    {ffassert(B->ChecknbColumn(y.N()));} };
+  
+  virtual ~VirtualMatrice(){} 
+};
+
+    
+
+//template <class R> class MatriceCreuseMulKN_;
+//template <class R> class MatriceCreuseDivKN_;
+
+class ShapeOfArray;
+
+class FromTo{ public:
+  long from,to;
+  FromTo(long i,long j):from(i),to(j) {K_throwassert(i<j);} 
+ };
+ 
+class SubArray{ public:
+  const long n,step,start;
+//  SubArray(char  nn): n(-1),step(1),start(0) {}  
+ explicit SubArray(long nn,long sta=0,long s=1): n(nn),step(s),start(sta) {}
+  SubArray(const FromTo& ft) : n(ft.to-ft.from+1),step(1),start(ft.from) {}
+  SubArray(const ShapeOfArray & ); // all 
+  long end()  const  { return start+ step*n;}
+  long last() const  { return start+ step*(n-1);}
+  long len1() const  { return step*(n-1);}  
+};
+
+
+class ShapeOfArray{ protected:
+  public:
+
+    long n;     //   n  nb of item
+    long step;  //   step  nb of between 2 item
+    long next;  //  the   next array of same type in matrix for subarray  
+              // by default  no next ( in case of KN, and KNM  -next is
+              // a counter of destruction  (use in frefem++)
+  ShapeOfArray(const ShapeOfArray & s,long nn): n(s.n),step(s.n),next(nn) {}              
+  ShapeOfArray(long nn): n(nn),step(1),next(-1) {}
+  
+  ShapeOfArray(long nn,long s): n(nn),step(s),next(-1) {}
+  
+  ShapeOfArray(long nn,long s,long nextt): n(nn),step(s),next(nextt) {}
+  
+  ShapeOfArray(const ShapeOfArray &old,const SubArray &sub) 
+         : n(sub.n),step(old.step*sub.step),next(old.next)
+          { K_throwassert((sub.last())*old.step <= old.last());} // a constructor 
+          
+  ShapeOfArray(const ShapeOfArray &old,long stepo,long start) 
+         : n(old.n-start),step(old.step*stepo),next(old.next) 
+          { K_throwassert(n>=0);}        
+          
+  long end()  const      { return n*step;}
+  long last()      const      { return (n-1)*step;}
+  long constant()  const { return step==0;}
+  long index(long k) const { K_throwassert( (k>=0) && ( (k <n) || !step) );
+           return step*k;}
+  ShapeOfArray operator*(long stepp) const {return  ShapeOfArray(n,step*stepp,next);}  
+  bool SameShape(const ShapeOfArray & a) const 
+          { return  !step || !a.step || a.n == n ;} 
+  long  N(const ShapeOfArray & a) { return step ? n : a.n;} // size of 2 shape 
+
+  
+// protected:
+  long operator[](long k) const {  
+    //if( k<0 || ( k<n && !step) )
+    //  cout << "k,n,step=" << k << " " << n << " " << step << endl;
+    K_throwassert( (k>=0) && ( (k <n) || !step) );
+           return step*k;}     
+  void init(long nn,long s=1,long nextt=-1) { n=nn; step=s; next=nextt;}         
+};
+
+ostream & operator<<(ostream & f,const ShapeOfArray & s);
+
+inline bool  SameShape(const ShapeOfArray & a,const ShapeOfArray & b) 
+           { return  !a.step || !b.step || a.n == b.n ;} 
+   
+inline long N(const ShapeOfArray & a,const ShapeOfArray & b) 
+           { K_throwassert(SameShape(a,b)); return  a.step ? a.n :  b.n ;}
+
+inline SubArray::SubArray(const ShapeOfArray & s) 
+           :n(s.n),step(s.step),start(0) {}
+           
+   
+
+template<class R> 
+ostream & operator<<(ostream & f,const KN_<const_R> & v) ;
+
+template<class R> istream & operator>>(istream & f, KN_<R> & v);
+template<class R> istream & operator>>(istream & f, KN<R> & v);
+
+template<class R>
+class SetArray { public:
+    R o,step;
+    long n;
+    explicit SetArray(long nn,R oo=R(),R sstep=R(1)): o(oo),n(nn),step(sstep) {}
+    template<class K>   SetArray(SetArray<K> sa): o(sa.o),n(sa.n),step(sa.step) {}
+    
+  R operator[](long i) const { return i <= n ? o + R(i)*step : R();}
+    long size() const {return n;}
+};
+
+// add for gmm++  march 2010 ....
+  template<typename T> struct KN__iterator {
+    typedef T                   value_type;
+    typedef value_type*         pointer;
+    typedef value_type&         reference;
+    typedef size_t              size_type;
+    typedef ptrdiff_t           difference_type;
+    typedef std::bidirectional_iterator_tag iterator_category;
+    typedef KN__iterator<T> iterator;
+  private:
+    T* v;
+    long step;
+  public:
+    reference operator *() const { return *v; }
+    pointer operator->() const { return &(operator*()); }
+
+    iterator &operator ++() { v += step; return *this; }
+    iterator operator ++(int) { iterator tmp = *this; ++(*this); return tmp; }
+    iterator &operator --() { v -= step; return *this; }
+    iterator operator --(int) { iterator tmp = *this; --(*this); return tmp; }
+
+    bool operator ==(const iterator &i) const { return v == i.v; }
+    bool operator !=(const iterator &i) const { return !(v == i.v); }
+
+    KN__iterator(T *vv,int s) : v(vv),step(s) {K_throwassert(v);}
+    friend class KN__const_iterator<T>;
+  };
+
+template<typename T> struct KN__const_iterator {
+  typedef T                   value_type;
+  typedef const value_type*   pointer;
+  typedef const value_type&   reference;
+  typedef size_t              size_type;
+  typedef ptrdiff_t           difference_type;
+  typedef std::forward_iterator_tag iterator_category;
+  typedef KN__const_iterator<T> iterator;
+  
+private:
+  const T* v;
+  long step;
+public:
+  
+    reference operator *() const { return *v; }
+    pointer operator->() const { return &(operator*()); }
+
+    iterator &operator ++() { v += step; return *this; }
+    iterator operator ++(int) { iterator tmp = *this; ++(*this); return tmp; }
+    iterator &operator --() { v -= step; return *this; }
+    iterator operator --(int) { iterator tmp = *this; --(*this); return tmp; }
+
+    bool operator ==(const iterator &i) const { return v == i.v; }
+    bool operator !=(const iterator &i) const { return !(v == i.v); }
+
+  KN__const_iterator(const T *vv,int s) : v(vv),step(s) {K_throwassert(v);}
+  KN__const_iterator(const KN__const_iterator<T> & i) : v(i.v),step(i.step){}
+
+};
+
+
+template<class R>
+class KN_: public  ShapeOfArray {
+protected:
+  R *v;
+public:
+  typedef R K; // type of data 
+  typedef KN__iterator<R> iterator;
+  typedef KN__const_iterator<R> const_iterator;
+  iterator end(){ return iterator(v+n*step,step);}
+  iterator begin(){ return iterator(v,step);}
+  const_iterator end() const { return const_iterator(v+n*step,step);}
+  const_iterator begin() const { return const_iterator(v,step);}
+  void clear() { *this=R();}
+  long N() const {return n;}
+  bool unset() const { return !v;}
+  void set(R * vv,int nn,int st=1,int nx=-1) {v=vv;n=nn;step=st;next=nx;}
+  long size() const{return step?n*step:n;}
+  operator R *() const {return v;}
+  KN_(const KN_<R> & u) :ShapeOfArray(u),v(u.v){} 
+  KN_(const KN_<R> & U,const SubArray & sa)  : ShapeOfArray(U,sa),v(U.v + U.index(sa.start)) {}
+
+  KN_ operator()(const SubArray & sa) const { return KN_(*this,sa);} // sub array 
+  
+  R & operator[](long i) const {return v[index(i)];}
+  R & operator()(long i) const {return v[index(i)];}
+  R & operator[](int i) const {return v[index(i)];}
+  R & operator()(int i) const {return v[index(i)];}
+
+  R operator,(const KN_<const_R> & v) const; // dot  product 
+
+   KN_& operator  =(const SetArray<R> & u)  ;
+   KN_& operator +=(const SetArray<R> & u)  ;
+   KN_& operator -=(const SetArray<R> & u)  ;  
+   KN_& operator *=(const SetArray<R> & u)  ;
+   KN_& operator /=(const SetArray<R> & u)  ;
+
+    KN_& operator  =(const KN_<const_R> & u)  ;
+    KN_& operator +=(const KN_<const_R> & u)  ;
+    KN_& operator -=(const KN_<const_R> & u)  ;
+    
+    KN_& operator *=(const KN_<const_R> & u)  ;
+    KN_& operator /=(const KN_<const_R> & u)  ;
+    
+  
+   KN_& operator = (const_R  a) ;  
+   KN_& operator +=(const_R  a) ;
+   KN_& operator -=(const_R  a) ;  
+   KN_& operator /=(const_R  a) ;
+   KN_& operator *=(const_R  a) ;
+  
+   KN_& operator  = (R*  a) { return operator =(KN_<R>(a,n));}
+   KN_& operator += (R*  a) { return operator+=(KN_<R>(a,n));}  
+   KN_& operator -= (R*  a) { return operator-=(KN_<R>(a,n));}  
+   KN_& operator *= (R*  a) { return operator*=(KN_<R>(a,n));}  
+   KN_& operator /= (R*  a) { return operator/=(KN_<R>(a,n));}  
+
+
+  
+  R min() const ;
+  R max() const ;
+  R sum() const ;
+  double norm() const ;
+  double l2() const ;
+  double l1() const ;
+  double linfty() const ;
+  double lp(double p) const ;
+  
+  template<class T> long last(const T &) const;
+  template<class T> long first(const T &) const;
+  
+  void map(R (*f)(R )); // apply the f fonction a all element of the array
+  void map(R (*f)(const  R& )); // apply the f fonction a all element of the array
+
+ template<class T>
+   void set(R (*f)(const  T& ),KN_<T> & u); // apply the f fonction a all element of the array u
+  
+   KN_& operator =(const DotStar_KN_<R> & u) ;
+   KN_& operator+=(const DotStar_KN_<R> & u) ;
+   KN_& operator-=(const DotStar_KN_<R> & u) ;
+   KN_& operator*=(const DotStar_KN_<R> & u) ;
+   KN_& operator/=(const DotStar_KN_<R> & u) ;
+
+   KN_& operator =(const DotSlash_KN_<R> & u) ;
+   KN_& operator+=(const DotSlash_KN_<R> & u) ;
+   KN_& operator-=(const DotSlash_KN_<R> & u) ;
+   KN_& operator*=(const DotSlash_KN_<R> & u) ;
+   KN_& operator/=(const DotSlash_KN_<R> & u) ;
+
+   KN_& operator =(const if_KN_<R> & u) ;
+   KN_& operator+=(const if_KN_<R> & u) ;
+   KN_& operator-=(const if_KN_<R> & u) ;
+   KN_& operator*=(const if_KN_<R> & u) ;
+   KN_& operator/=(const if_KN_<R> & u) ;
+
+   KN_& operator =(const ifnot_KN_<R> & u) ;
+   KN_& operator+=(const ifnot_KN_<R> & u) ;
+   KN_& operator-=(const ifnot_KN_<R> & u) ;
+   KN_& operator*=(const ifnot_KN_<R> & u) ;
+   KN_& operator/=(const ifnot_KN_<R> & u) ;
+
+   KN_& operator =(const Add_KN_<R> & u) ;
+   KN_& operator+=(const Add_KN_<R> & u) ;
+   KN_& operator-=(const Add_KN_<R> & u) ;
+   KN_& operator*=(const Add_KN_<R> & u) ;
+   KN_& operator/=(const Add_KN_<R> & u) ;
+  
+   template<class I,class T> KN_& operator =  (const KN_ITAB<T,I> & u);
+   template<class I,class T> KN_& operator +=  (const KN_ITAB<T,I> & u);
+   template<class I,class T> KN_& operator -=  (const KN_ITAB<T,I> & u);
+   template<class I,class T> KN_& operator *=  (const KN_ITAB<T,I> & u);
+   template<class I,class T> KN_& operator /=  (const KN_ITAB<T,I> & u);
+
+
+   KN_ITAB< KN_<R>,const KN_<int> >  operator()(const KN_<int> &itab) ;
+   KN_ITAB< KN_<R>,const KN_<long> >  operator()(const KN_<long> &itab) ;
+   KN_ITAB<const KN_<R>,const KN_<int> > operator()(const KN_<int> &itab) const ;
+   KN_ITAB<const KN_<R>,const KN_<long> >  operator()(const KN_<long> &itab) const ;
+
+
+    
+
+  
+   KN_& operator =(const Sub_KN_<R> & u) ;
+   KN_& operator-=(const Sub_KN_<R> & u) ;
+   KN_& operator+=(const Sub_KN_<R> & u) ;
+   KN_& operator*=(const Sub_KN_<R> & u) ;
+   KN_& operator/=(const Sub_KN_<R> & u) ;
+  
+   KN_& operator =(const Mulc_KN_<R> & u) ;
+   KN_& operator+=(const Mulc_KN_<R> & u) ;
+   KN_& operator-=(const Mulc_KN_<R> & u) ;
+   KN_& operator*=(const Mulc_KN_<R> & u) ;
+   KN_& operator/=(const Mulc_KN_<R> & u) ;
+  
+   KN_& operator =(const Add_Mulc_KN_<R> & u) ;
+   KN_& operator+=(const Add_Mulc_KN_<R> & u) ;
+   KN_& operator-=(const Add_Mulc_KN_<R> & u) ;
+   KN_& operator*=(const Add_Mulc_KN_<R> & u) ;
+   KN_& operator/=(const Add_Mulc_KN_<R> & u) ;
+
+   KN_& operator =(const if_arth_KN_<R> & u) ;
+   KN_& operator+=(const if_arth_KN_<R> & u) ;
+   KN_& operator-=(const if_arth_KN_<R> & u) ;
+   KN_& operator*=(const if_arth_KN_<R> & u) ;
+   KN_& operator/=(const if_arth_KN_<R> & u) ;
+
+  
+   KN_& operator =(const Mul_KNM_KN_<R> & u) ; 
+   KN_& operator+=(const Mul_KNM_KN_<R> & u) ; 
+   KN_& operator-=(const Mul_KNM_KN_<R> & u) ; 
+   KN_& operator*=(const Mul_KNM_KN_<R> & u) ; 
+   KN_& operator/=(const Mul_KNM_KN_<R> & u) ; 
+  
+ //  KN_& operator =(const MatriceCreuseMulKN_<R> & ) ;
+ //  KN_& operator +=(const MatriceCreuseMulKN_<R> & ) ;
+   KN_& operator =(const typename VirtualMatrice<R>::plusAx & Ax)  
+    {*this=R(); Ax.A->addMatMul(Ax.x,*this);return *this;}
+   KN_& operator =(const typename VirtualMatrice<R>::plusAtx & Ax)  
+    {*this=R(); Ax.A->addMatTransMul(Ax.x,*this);return *this;}
+   KN_& operator +=(const typename VirtualMatrice<R>::plusAx & Ax)  
+    {  Ax.A->addMatMul(Ax.x,*this);return *this;}
+   KN_& operator +=(const typename VirtualMatrice<R>::plusAtx & Ax)  
+    {  Ax.A->addMatTransMul(Ax.x,*this);return *this;}
+   KN_& operator =(const typename VirtualMatrice<R>::solveAxeqb & Ab)  
+    {*this=R(); Ab.A->Solve(*this,Ab.b);return *this;}
+    
+  template<class  A,class B,class C> KN_&  operator =  (const F_KN_<A,B,C>  & u) ;
+  template<class  A,class B,class C> KN_&  operator +=  (const F_KN_<A,B,C>  & u) ;
+  template<class  A,class B,class C> KN_&  operator -=  (const F_KN_<A,B,C>  & u) ;
+  template<class  A,class B,class C> KN_&  operator /=  (const F_KN_<A,B,C>  & u) ;
+  template<class  A,class B,class C> KN_&  operator *=  (const F_KN_<A,B,C>  & u) ;
+    
+   
+//   KN_& operator =(const MatriceCreuseDivKN_<R> &)  ;
+
+ friend   ostream & operator<< <R>(ostream & f,const KN_<const_R> & v)  ;
+ 
+  KN_(R *u,const ShapeOfArray & s):ShapeOfArray(s),v(u){}
+  KN_(R *u,long nn,long s):ShapeOfArray(nn,s),v(u){}
+  KN_(R *u,long nn,long s,long nextt):ShapeOfArray(nn,s,nextt),v(u){}
+  KN_(R *u,long nn):ShapeOfArray(nn),v(u){}
+
+
+  TKN_<R>  t() ; // transpose
+  const TKN_<R>  t() const ; // transpose
+  notKN_<R>  operator!()  ; //  not
+  const  notKN_<R>  operator!() const ; // not
+
+  //  operator KN<R> &();
+  // operator const KN<R> &() const;
+
+ private:
+ 
+  KN_&  operator++(){K_throwassert(next>=0);v += next;return *this;} //    ++U
+  KN_&  operator--(){K_throwassert(next>=0);v -= next;return *this;} //    --U
+  KN_   operator++(int ){K_throwassert(next>=0); KN_ old=*this;v = v +next;return old;} // U++
+  KN_   operator--(int ){K_throwassert(next>=0); KN_ old=*this;v = v -next;return old;} // U++
+ 
+  KN_(const KN_<R> & u,long offset) :ShapeOfArray(u),v(&u[offset]){} 
+  KN_(const KN_<R> & u,const ShapeOfArray &sh,long startv=0)
+         :ShapeOfArray(sh*u.step),v(&u[startv]){}
+  KN_(const KN_<R> & u,long nnext,const ShapeOfArray &sh,long startv=0)
+         :ShapeOfArray(sh.n,sh.step*u.step,nnext),v(&u[startv]){ }
+  // Add for gmm++ compatibityly ...................
+  //  iterator end() {return iterator(v,step)
+
+  
+// friend class KN_<R>;   
+ friend class KNM_<R>;   
+ friend class KNMK_<R>;   
+ friend class KN<R>;   
+ friend class KNM<R>;   
+ friend class KNMK<R>;   
+  
+};
+
+template<class R>
+class KNM_: public KN_<R> {
+  public:
+  ShapeOfArray shapei;
+  ShapeOfArray shapej;
+  public:
+  long IsVector1() const  {  return (shapei.n*shapej.n) ==  this->n ;} 
+  long N() const {return shapei.n;}
+  long M() const {return shapej.n;}  
+  long size() const { return shapei.n*shapej.n;}
+  
+  KNM_(R* u,const ShapeOfArray & s,
+            const ShapeOfArray & si,
+            const ShapeOfArray & sj)
+             : KN_<R>(u,s),shapei(si),shapej(sj){} 
+  KNM_(R* u,long n,long m)
+             : KN_<R>(u,ShapeOfArray(n*m)),shapei(n,1,n),shapej(m,n,1){}
+  KNM_(R* u,long n,long m,long s)
+             : KN_<R>(u,ShapeOfArray(n*m,s)),shapei(n,1,n),shapej(m,n,1){}                     
+  KNM_(KN_<R> u,long n,long m) 
+             : KN_<R>(u,ShapeOfArray(m*n)),shapei(n,1,n),shapej(m,n,1){ }
+             
+  KNM_(const KN_<R> &u,const ShapeOfArray & si,const ShapeOfArray & sj,long offset=0) 
+             : KN_<R>(&u[offset],si.last()+sj.last()+1,u.step),shapei(si),shapej(sj) 
+             {K_throwassert( offset>=0 && this->n+ (this->v-(R*)u) <= u.n);}
+  KNM_(const KN_<R> &u,const ShapeOfArray & si,const ShapeOfArray & sj,long offset,long nnext) 
+             : KN_<R>(&u[offset],si.last()+sj.last()+1,u.step,nnext),shapei(si),shapej(sj) 
+             {K_throwassert( offset>=0 && this->n+ (this->v-(R*)u) <= u.n);}
+  
+  KNM_(KNM_<R> U,const SubArray & si,const SubArray & sj)  
+             :KN_<R>(U,SubArray(U.ij(si.len1(),sj.len1())+1,U.ij(si.start,sj.start))),
+                     shapei(U.shapei,si),shapej(U.shapej,sj){} 
+
+  KNM_(KNM_<R> U,const SubArray & sa,const SubArray & si,const SubArray & sj)  
+             :KN_<R>(U,SubArray(sa)),shapei(U.shapei,si),shapej(U.shapej,sj){} 
+
+  KNM_(const KNM_<R> & u) 
+             :KN_<R>(u),shapei(u.shapei),shapej(u.shapej) {}
+
+  KNM_ operator()(const SubArray & sa,const SubArray & sb) const 
+            { return KNM_(*this,sa,sb);} // sub array 
+  
+  long ij(long i,long j) const   
+            { return shapei.index(i)+shapej.index(j);}
+  long indexij(long i,long j)        const   
+            { return this->index(shapei.index(i)+shapej.index(j));}
+  R & operator()(long i,long j)     const   
+            { return this->v[indexij(i,j)];}
+  R & operator()(int i,int j)     const   
+            { return this->v[indexij(i,j)];}
+            
+            
+  KN_<R> operator()(const char,long j    )  const   // une colonne j  ('.',j)
+            { return KN_<R>(&this->v[this->index(shapej.index(j))],shapei*this->step);} 
+  KN_<R> operator()(long i    ,const char)  const   // une ligne i  (i,'.')
+            { return KN_<R>(&this->v[this->index(shapei.index(i))],shapej*this->step);}  
+  KN_<R> operator()(const char,int j    )  const   // une colonne j  ('.',j)
+            { return KN_<R>(&this->v[this->index(shapej.index(j))],shapei*this->step);} 
+  KN_<R> operator()(int i    ,const char)  const   // une ligne i  (i,'.')
+            { return KN_<R>(&this->v[this->index(shapei.index(i))],shapej*this->step);}  
+  KN_<R> operator()(const char,const char)  const   // tous 
+            { return *this;}
+  KNM_<R> t() const
+    { return KNM_<R>(this->v,*this,shapej,shapei);} //  before  { return KNM_<R>(*this,shapej,shapei,v);}
+  
+   KNM_& operator =(const KNM_<const_R> & u) ;
+   KNM_& operator =(const_R a)               ;
+   KNM_& operator+=(const_R a)               ;
+   KNM_& operator-=(const_R a)               ; 
+   KNM_& operator/=(const_R a)               ;
+   KNM_& operator*=(const_R a)               ; 
+   KNM_& operator+=(const KNM_<const_R> & u) ;
+   KNM_& operator-=(const KNM_<const_R> & u) ;
+   KNM_& operator*=(const KNM_<const_R> & u) ;
+   KNM_& operator/=(const KNM_<const_R> & u) ;
+   
+   KNM_ &operator =(const outProduct_KN_<R> &);
+   KNM_ &operator +=(const outProduct_KN_<R> &);
+   KNM_ &operator -=(const outProduct_KN_<R> &);
+   KNM_ &operator /=(const outProduct_KN_<R> &); // bofbof
+   KNM_ &operator *=(const outProduct_KN_<R> &); // bofbof
+
+private:  
+  KNM_& operator++() {this->v += this->next;return *this;} // ++U
+  KNM_& operator--() {this->v -= this->next;return *this;} // ++U
+  KNM_  operator++(int ){KNM_<R> old=*this;this->v = this->v +this->next;return old;} // U++
+  KNM_  operator--(int ){KNM_<R> old=*this;this->v = this->v -this->next;return old;} // U--
+
+
+ friend class KN_<R>;   
+// friend class KNM_<R>;   
+ friend class KNMK_<R>;   
+ friend class KN<R>;   
+ friend class KNM<R>;   
+ friend class KNMK<R>;   
+};
+
+template<class T,class I> 
+struct KN_ITAB
+{
+  KN_ITAB(const T &vv,const I &iindex) : v(vv),index(iindex) {}
+  T  v;
+  I  index;
+  KN_ITAB & operator=(const T & t);
+  KN_ITAB & operator+=(const T & t);
+  KN_ITAB & operator-=(const T & t);
+  KN_ITAB & operator*=(const T & t);
+  KN_ITAB & operator/=(const T & t);
+  typename T::R & operator[](long i){ return v[index[i]];}
+  const typename T::R &  operator[](long i) const { return v[index[i]];}
+  long N() const { return index.N();}    
+};
+
+template<class R>  KN_ITAB<const KN_<R>,const KN_<int> >  KN_<R>::operator()(const KN_<int>  &itab) const { return KN_ITAB<const KN_<R>,const KN_<int> > (*this,itab);}
+template<class R>  KN_ITAB<const KN_<R>,const KN_<long> >  KN_<R>::operator()(const KN_<long>  &itab) const { return KN_ITAB<const KN_<R>,const KN_<long> > (*this,itab);}
+template<class R>  KN_ITAB< KN_<R>,const KN_<int> >  KN_<R>::operator()(const KN_<int>  &itab) { return KN_ITAB<KN_<R>,const KN_<int> > (*this,itab);}
+template<class R>  KN_ITAB< KN_<R>,const KN_<long> >  KN_<R>::operator()(const KN_<long>  &itab) { return KN_ITAB<KN_<R>,const KN_<long> > (*this,itab);}
+
+
+template<class R>
+struct TKN_:public KN_<R> {
+    TKN_(const KN_<R> &x) : KN_<R>(x) {}
+};
+
+template<class R>
+struct notKN_:public KN_<R> {
+    notKN_(const KN_<R> &x) : KN_<R>(x) {}
+    notnotKN_<R>  operator!()  ; //  not
+    const  notnotKN_<R>  operator!() const ; // not
+};
+
+template<class R>
+struct notnotKN_:public KN_<R> {
+    notnotKN_(const notKN_<R> &x) : KN_<R>(x) {}
+    notKN_<R>  operator!()  ; //  notnot
+    const  notKN_<R>  operator!() const ; // notnot
+};
+
+template<class R>
+TKN_<R>  KN_<R>::t() { return *this;} // transpose
+
+template<class R>
+const TKN_<R>  KN_<R>::t() const { return *this;} // transpose
+
+template<class R>
+notKN_<R>  KN_<R>::operator!() { return *this;} // not
+
+template<class R>
+const notKN_<R>  KN_<R>::operator!() const { return *this;} // not
+
+template<class R>
+notnotKN_<R>  notKN_<R>::operator!() { return *this;} // not
+
+template<class R>
+const notnotKN_<R>  notKN_<R>::operator!() const { return *this;} // not
+
+
+template<class R>
+struct outProduct_KN_ {
+    const KN_<R>  a,b;
+    R c;
+    long N() const {return a.N();    }
+    long M() const {return b.N();    }
+    outProduct_KN_(const KN_<R> & aa, const KN_<R> &bb,R cc=(R)1) : a(aa),b(bb),c(cc) {}
+    outProduct_KN_(const KN_<R> * aa, const KN_<R> &bb,R cc=(R)1) : a(*aa),b(bb),c(cc) {}
+    outProduct_KN_(const KN_<R> * aa, const KN_<R> *bb,R cc=(R)1) : a(*aa),b(*bb),c(cc) {}
+    outProduct_KN_(const Mulc_KN_<R> & aa,const KN_<R> & bb) : a(aa.a),b(bb),c(aa.b) {}    
+    outProduct_KN_ operator * (R cc) { return outProduct_KN_(a,b,c*cc);}    
+};
+
+template<class R>
+struct if_KN_ {
+    const KN_<R> & a,&b;
+    R c;
+    if_KN_(const KN_<R> & aa, const KN_<R> &bb,R cc=1.) : a(aa),b(bb),c(cc) {}
+    if_KN_ operator * (R cc) { return if_KN_(a,b,c*cc);}    
+};
+
+template<class R>
+struct ifnot_KN_ {
+    const KN_<R> & a,&b;
+    R c;
+    ifnot_KN_(const KN_<R> & aa, const KN_<R> &bb,R cc=1.) : a(aa),b(bb),c(cc) {}
+    ifnot_KN_ operator * (R cc) { return ifnot_KN_(a,b,c*cc);}    
+};
+
+
+template<class R> 
+outProduct_KN_<R> operator*(const KN_<R> &a,const TKN_<R> &b) 
+{ return outProduct_KN_<R>(a,b);}
+
+template<class R> 
+ifnot_KN_<R> operator*(const KN_<R> &a,const notKN_<R> &b) 
+{ return ifnot_KN_<R>(b,a);}
+
+template<class R> 
+ifnot_KN_<R> operator*(const KN_<R> &a,const notnotKN_<R> &b) 
+{ return if_KN_<R>(b,a);}
+
+template<class R> 
+ifnot_KN_<R> operator*(const notKN_<R> &b,const KN_<R> &a) 
+{ return ifnot_KN_<R>(b,a);}
+
+template<class R> 
+ifnot_KN_<R> operator*(const notnotKN_<R> &b,const KN_<R> & a) 
+{ return if_KN_<R>(b,a);}
+
+
+template<class R> 
+R operator*(const TKN_<R> &a,const KN_<R> &b) 
+{ return (a,b);}
+
+template<class R>
+class KNMK_: public KN_<R> {
+  friend class KNMK<R>;
+  public:
+  ShapeOfArray shapei;
+  ShapeOfArray shapej;
+  ShapeOfArray shapek;
+  public:
+  long IsVector1() const {  return (shapei.n*shapej.n*shapek.n) == this->n ;} 
+  long N() const {return shapei.n;}
+  long M() const {return shapej.n;}
+  long K() const {return shapek.n;}
+  long size() const { return shapei.n*shapej.n*shapek.n;}
+  KNMK_(const ShapeOfArray & s,
+        const ShapeOfArray & si,
+        const ShapeOfArray & sj,
+        const ShapeOfArray & sk,
+	    R * u)
+    : KN_<R>(u,s),shapei(si),shapej(sj),shapek(sk){} 
+    
+  KNMK_(R* u,long n,long m,long k)
+    : KN_<R>(u, ShapeOfArray(n*m*k)),shapei(n,1,n),shapej(m,n,1),shapek(k,n*m,n*m){};
+    
+//  KNMK_(const KN_<R> & u,long n,long m,long k)
+//   : KN_<R>(ShapeOfArray(n*m*k)),shapei(n,1,n),shapekj(m,n,1),u),
+//     shapek(k,n*m,n*m){};
+
+  KNMK_(const KNMK_<R> &U,const SubArray & si,const SubArray & sj,const SubArray & sk)  :
+    KN_<R>(U,SubArray(U.ijk(si.len1(),sj.len1(),sk.len1())+1,
+                       U.ijk(si.start,sj.start,sk.start))),
+                       shapei(U.shapei,si),
+                       shapej(U.shapej,sj),
+                       shapek(U.shapek,sk){} 
+
+  KNMK_(const KNMK_<R> & u) :KN_<R>(u),shapei(u.shapei),shapej(u.shapej),shapek(u.shapek) {}
+
+    
+  long ijk(long i,long j,long k) const 
+              { return shapei.index(i)+shapej.index(j)+shapek.index(k);}
+  long indexijk(long i,long j,long k) const 
+              {return this->index(shapei.index(i)+shapej.index(j)+shapek.index(k));} 
+                           
+  R & operator()(long i,long j,long k)   const   {return this->v[indexijk(i,j,k)];}
+  R & operator()(int i,int j,int k)   const   {return this->v[indexijk(i,j,k)];}
+  
+//  pas de tableau suivant
+ KN_<R>  operator()(const char ,long j,long k)  const  { // le tableau (.,j,k) 
+        return KN_<R>(*this,-1,shapei,shapej[j]+shapek[k]);}
+ KN_<R>  operator()(long i,const char ,long k)  const  { // le tableau (i,.,k) 
+        return KN_<R>(*this,-1,shapej,shapei[i]+shapek[k]);}
+ KN_<R>  operator()(long i,long j,const char )  const  { // le tableau (i,j,.) 
+        return KN_<R>(*this,-1,shapek,shapei[i]+shapej[j]);}
+
+ KN_<R>  operator()(const char ,int j,int k)  const  { // le tableau (.,j,k) 
+        return KN_<R>(*this,-1,shapei,shapej[j]+shapek[k]);}
+ KN_<R>  operator()(int i,const char ,int k)  const  { // le tableau (i,.,k) 
+        return KN_<R>(*this,-1,shapej,shapei[i]+shapek[k]);}
+ KN_<R>  operator()(int i,int j,const char )  const  { // le tableau (i,j,.) 
+        return KN_<R>(*this,-1,shapek,shapei[i]+shapej[j]);}
+//                                              
+ KNM_<R>  operator()(const char ,const char ,long k)  const  { // le tableau (.,.,k) 
+        return KNM_<R>(*this,shapei,shapej,shapek[k],shapek.next);} // step = n*m
+ //attention les suivants ne marche pas
+ KNM_<R>  operator()(const char ,long j,const char )  const  { // le tableau (.,j,.) 
+        return KNM_<R>(*this,shapei,shapek,shapej[j],-1/*shapej.next*/);} // step = n
+        
+ KNM_<R>  operator()(long i,const char ,const char )  const  { // le tableau (i,.,.) 
+        return KNM_<R>(*this,shapej,shapek,shapei[i],-1/*shapei.next*/);}  // step = 1
+
+ KNM_<R>  operator()(const char ,const char ,int k)  const  { // le tableau (.,.,k) 
+        return KNM_<R>(*this,shapei,shapej,shapek[k],shapek.next);} // step = n*m
+ //attention les suivants ne marche pas
+ KNM_<R>  operator()(const char ,int j,const char )  const  { // le tableau (.,j,.) 
+        return KNM_<R>(*this,shapei,shapek,shapej[j],-1/*shapej.next*/);} // step = n
+        
+ KNM_<R>  operator()(int i,const char ,const char )  const  { // le tableau (i,.,.) 
+        return KNM_<R>(*this,shapej,shapek,shapei[i],-1/*shapei.next*/);}  // step = 1
+
+   KNMK_& operator =(const KNMK_<const_R> & u) ;
+   KNMK_& operator+=(const KNMK_<const_R> & u)  ;
+   KNMK_& operator-=(const KNMK_<const_R> & u)  ;
+   KNMK_& operator/=(const KNMK_<const_R> & u)  ;
+   KNMK_& operator*=(const KNMK_<const_R> & u)  ;
+   KNMK_& operator =(const_R a)  ; 
+   KNMK_& operator+=(const_R a)  ;
+   KNMK_& operator-=(const_R a)  ;
+   KNMK_& operator/=(const_R a)  ;
+   KNMK_& operator*=(const_R a)  ;
+
+  KNMK_  operator()(SubArray si,SubArray sj,SubArray sk) const 
+        {return KNMK_(*this,si,sj,sk);}
+
+  private:
+//  KNMK_&  operator++(){v += next;return *this;} // ++U
+//  KNMK_&  operator--(){v -= next;return *this;} // --U
+//  KNMK_  operator++(long ){KNMK_ old=*this;v = v +next;return old;} // U++ 
+//  KNMK_  operator--(long ){KNMK_ old=*this;v = v -next;return old;} // U--
+ 
+        
+friend class KNM_<R>;   
+friend class KN_<R>;   
+
+};
+
+
+
+template<class R>
+class KN :public KN_<R> { public:
+
+  typedef R K;
+
+ // explicit  KN(const R & u):KN_<R>(new R(uu),1,0) {}
+  KN() : KN_<R>(0,0) {}
+  KN(long nn) : KN_<R>(new R[nn],nn)         {} 
+  KN(long nn, R * p) : KN_<R>(new R[nn],nn)  
+    { KN_<R>::operator=(KN_<R>(p,nn));}
+  KN(long nn,R (*f)(long i) ) : KN_<R>(new R[nn],nn) 
+        {for(long i=0;i<this->n;i++) this->v[i]=f(i);}  
+  KN(long nn,const  R & a) : KN_<R>(new R[nn],nn) 
+        { KN_<R>::operator=(a);} 
+  KN(long nn,long s,const  R  a) : KN_<R>(new R[nn],nn,s) 
+        { KN_<R>::operator=(a);} 
+  template<class S>   KN(const KN_<S> & s):KN_<R>(new R[s.n],s.n) 
+        {for (long i=0;i<this->n;i++) this->v[i] = s[i];}
+  template<class S>  KN(const KN_<S> & s,R (*f)(S )):KN_<R>(new R[s.n],s.n) 
+        {for (long i=0;i<this->n;i++) this->v[i] = f(s[i]);}
+  KN(const KN<R> & u):KN_<R>(new R[u.n],u.n)
+        { KN_<R>::operator=(u);}
+  KN(bool ,KN<R> & u):KN_<R>(u) {u.v=0;u.n=0;}// remove copy for return of local KN. 
+    
+  //  explicit KN(const KN_<R> & u):KN_<R>(new R[u.n],u.n) 
+  //      { KN_<R>::operator=(u);}
+        
+  ~KN(){delete [] this->v;}
+   
+  void CheckSet() { if(!(this->n)) {cerr << "Error RNM set array\n";K_throwassert(0); exit(1);}}
+   KN& operator  = (R*  a) { CheckSet(); return operator =(KN_<R>(a,this->n));}
+   KN& operator += (R*  a) { CheckSet(); return operator+=(KN_<R>(a,this->n));}  
+   KN& operator -= (R*  a) { CheckSet(); return operator-=(KN_<R>(a,this->n));}  
+   KN& operator *= (R*  a) { CheckSet(); return operator*=(KN_<R>(a,this->n));}  
+   KN& operator /= (R*  a) { CheckSet(); return operator/=(KN_<R>(a,this->n));}  
+  
+   KN& operator  =(const SetArray<R> & u)  
+     { if(this->unset())
+	 this->set(new R[u.size()],u.size(),0,0);
+       KN_<R>::operator= (u);
+       return *this;}
+   KN& operator +=(const SetArray<R> & u)  
+     { if(this->unset()) 
+	 this->set(new R[u.size()],u.size(),0,0);
+       KN_<R>::operator+= (u);
+       return *this;}
+   KN& operator -=(const SetArray<R> & u)    
+     { if(this->unset())  this->set(new R[u.size()],u.size(),0,0); KN_<R>::operator-= (u);return *this;}
+   KN& operator *=(const SetArray<R> & u)  
+     { if(this->unset())  this->set(new R[u.size()],u.size(),0,0); KN_<R>::operator*= (u);return *this;}
+   KN& operator /=(const SetArray<R> & u)  
+     { if(this->unset())  this->set(new R[u.size()],u.size(),0,0); KN_<R>::operator/= (u);return *this;}
+
+   KN& operator =(const_R a)  
+        { if(this->unset()) this->set(new R[1],1,0,0); KN_<R>::operator= (a);return *this;}
+   KN& operator =(const KN_<R>& a)  
+        { if(this->unset())  this->set(new R[a.N()],a.N()); KN_<R>::operator= (a);return *this;}                
+   KN& operator =(const KN<R>& a)  
+        { if(this->unset()) this->set(new R[a.N()],a.N()); KN_<R>::operator= (a);return *this;}                
+   KN& operator =(const Add_KN_<R> & u)  
+        { if(this->unset())  this->set(new R[u.a.N()],u.a.N());KN_<R>::operator=(u);return *this;}
+   KN& operator =(const DotStar_KN_<R> & u)  
+        { if(this->unset())  this->set(new R[u.a.N()],u.a.N());KN_<R>::operator=(u);return *this;}
+   KN& operator =(const if_KN_<R> & u)  
+        { if(this->unset())  this->set(new R[u.a.N()],u.a.N());KN_<R>::operator=(u);return *this;}
+   KN& operator =(const ifnot_KN_<R> & u)  
+        { if(this->unset())  this->set(new R[u.a.N()],u.a.N());KN_<R>::operator=(u);return *this;}
+   KN& operator =(const DotSlash_KN_<R> & u)  
+        { if(this->unset())  this->set(new R[u.a.N()],u.a.N());KN_<R>::operator=(u);return *this;}
+   KN& operator =(const Sub_KN_<R> & u)  
+        { if(this->unset())  this->set(new R[u.a.N()],u.a.N());KN_<R>::operator=(u);return *this;}
+   KN& operator =(const Mulc_KN_<R> & u)  
+        { if(this->unset())  this->set(new R[u.a.N()],u.a.N());KN_<R>::operator=(u);return *this;}
+   KN& operator =(const Add_Mulc_KN_<R> & u)  
+        { if(this->unset())  this->set(new R[u.a.N()],u.a.N());KN_<R>::operator=(u);return *this;}
+   KN& operator =(const if_arth_KN_<R> & u)  
+        { if(this->unset())  this->set(new R[u.a.N()],u.a.N());KN_<R>::operator=(u);return *this;}
+        
+        
+   KN& operator =(const Mul_KNM_KN_<R> & u) 
+        { if(this->unset())  this->set(new R[u.b.N()],u.b.N());KN_<R>::operator=(u);return *this;}
+//   KN& operator =(const MatriceCreuseMulKN_<R> & Ax) 
+//       {if(this->unset())  this->set(new R[Ax.v.N()],Ax.v.N()); KN_<R>::operator=(Ax);return *this;}
+//   KN& operator +=(const MatriceCreuseMulKN_<R> & Ax) 
+//       {if(this->unset())  this->set(new R[Ax.v.N()],Ax.v.N()); KN_<R>::operator+=(Ax);return *this;}
+//   KN& operator =(const MatriceCreuseDivKN_<R> & A1x)  
+//       { if(this->unset())  this->set(new R[A1x.v.N()],A1x.v.N());KN_<R>::operator=(A1x);return *this;}
+  // correcton aout 2007 FH  add N,M flied in VirtualMatrice
+   KN& operator =(const typename VirtualMatrice<R>::plusAx & Ax)  
+        { if(this->unset() && Ax.A->N )  this->set(new R[Ax.A->N],Ax.A->N);KN_<R>::operator=(Ax);return *this;}
+   KN& operator =(const typename VirtualMatrice<R>::solveAxeqb & Ab)  
+        { if(this->unset())  this->set(new R[Ab.b.N()],Ab.b.N());KN_<R>::operator=(Ab);return *this;}
+   KN& operator +=(const typename  VirtualMatrice<R>::plusAx & Ax)  
+  { if(this->unset()  && Ax.A->N) {
+         this->set(new R[Ax.A->N],Ax.A->N);
+        KN_<R>::operator=(R());}
+    KN_<R>::operator+=(Ax);
+    return *this;}
+   KN& operator =(const typename VirtualMatrice<R>::plusAtx & Ax)  
+        { if(this->unset()&&Ax.A->M)  this->set(new R[Ax.A->M],Ax.A->M);KN_<R>::operator=(Ax);return *this;}
+   KN& operator +=(const typename VirtualMatrice<R>::plusAtx & Ax)  
+  { if(this->unset()&&Ax.A->M) {
+        this->set(new R[Ax.A->M],Ax.A->M);
+      KN_<R>::operator=(R());}
+      KN_<R>::operator+=(Ax);
+     return *this;}
+// end correcton FH
+   template<class P,class Q> 
+     KN& operator =(const  PplusQ<P,Q> & PQ)  
+      { *this=PQ.p; *this+=PQ.q;return *this; } 
+   template<class P,class Q> 
+     KN& operator +=(const  PplusQ<P,Q> & PQ)  
+      { *this+=PQ.p; *this+=PQ.q;return *this; } 
+           
+   KN& operator -=(const_R a)  
+        { KN_<R>::operator-=(a);return *this;}
+   KN& operator -=(const KN_<R>& a)  
+        { KN_<R>::operator-= (a);return *this;}
+   KN& operator -=(const Add_KN_<R> & u)  
+        { KN_<R>::operator-=(u);return *this;}
+   KN& operator -=(const DotStar_KN_<R> & u)  
+        { KN_<R>::operator-=(u);return *this;}
+   KN& operator -=(const DotSlash_KN_<R> & u)  
+        { KN_<R>::operator-=(u);return *this;}
+   KN& operator -=(const Sub_KN_<R> & u)  
+        { KN_<R>::operator-=(u);return *this;}
+   KN& operator -=(const Mulc_KN_<R> & u)  
+        { KN_<R>::operator-=(u);return *this;}
+   KN& operator -=(const Add_Mulc_KN_<R> & u)  
+        { KN_<R>::operator-=(u);return *this;}
+   KN& operator -=(const if_arth_KN_<R> & u)  
+        { KN_<R>::operator-=(u);return *this;}
+   KN& operator -=(const Mul_KNM_KN_<R> & u) 
+        { KN_<R>::operator-=(u);return *this;}
+ 
+   KN& operator +=(const_R a)  
+        { KN_<R>::operator += (a);return *this;}
+   KN& operator += (const KN_<R>& a)  
+        { KN_<R>::operator+= (a);return *this;}
+   KN& operator +=(const Add_KN_<R> & u)  
+        { KN_<R>::operator+=(u);return *this;}
+   KN& operator +=(const DotStar_KN_<R> & u)  
+        { KN_<R>::operator+=(u);return *this;}
+   KN& operator +=(const DotSlash_KN_<R> & u)  
+        { KN_<R>::operator+=(u);return *this;}
+   KN& operator +=(const Sub_KN_<R> & u)  
+        { KN_<R>::operator+=(u);return *this;}
+   KN& operator +=(const Mulc_KN_<R> & u)  
+        { KN_<R>::operator+=(u);return *this;}
+   KN& operator +=(const Add_Mulc_KN_<R> & u)  
+        { KN_<R>::operator+=(u);return *this;}
+   KN& operator +=(const if_arth_KN_<R> & u)  
+        { KN_<R>::operator+=(u);return *this;}
+   KN& operator +=(const Mul_KNM_KN_<R> & u) 
+        { KN_<R>::operator+=(u);return *this;}
+        
+
+   KN& operator/=(const_R a)  
+        { KN_<R>::operator/=(a);return *this;}
+   KN& operator /= (const KN_<R>& a)  
+        { KN_<R>::operator/= (a);return *this;}
+   KN& operator /=(const Add_KN_<R> & u)  
+        { KN_<R>::operator/=(u);return *this;}
+   KN& operator /=(const Sub_KN_<R> & u)  
+        { KN_<R>::operator/=(u);return *this;}
+   KN& operator /=(const Mulc_KN_<R> & u)  
+        { KN_<R>::operator/=(u);return *this;}
+   KN& operator /=(const Add_Mulc_KN_<R> & u)  
+        { KN_<R>::operator/=(u);return *this;}
+   KN& operator /=(const if_arth_KN_<R> & u)  
+        { KN_<R>::operator/=(u);return *this;}
+        
+   KN& operator /=(const Mul_KNM_KN_<R> & u) 
+        { KN_<R>::operator/=(u);return *this;}
+        
+   KN& operator*=(const_R a)  
+        { KN_<R>::operator*=(a);return *this;}
+   KN& operator*=(const KN_<const_R>& a)  
+        { KN_<R>::operator*= (a);return *this;}
+   KN& operator *=(const Add_KN_<R> & u)  
+        { KN_<R>::operator*=(u);return *this;}
+   KN& operator *=(const Sub_KN_<R> & u)  
+        { KN_<R>::operator*=(u);return *this;}
+   KN& operator *=(const Mulc_KN_<R> & u)  
+        { KN_<R>::operator*=(u);return *this;}
+   KN& operator *=(const Add_Mulc_KN_<R> & u)  
+        { KN_<R>::operator*=(u);return *this;}
+   KN& operator *=(const if_arth_KN_<R> & u)  
+        { KN_<R>::operator*=(u);return *this;}
+   KN& operator *=(const Mul_KNM_KN_<R> & u) 
+        { KN_<R>::operator*=(u);return *this;}
+        
+  
+  template<class I,class T> KN& operator =   (const KN_ITAB<T ,I> & ui)
+     {  KN_<R>::operator =(ui);  return *this;}
+  template<class I,class T> KN& operator +=   (const KN_ITAB<T ,I> & ui)
+     {  KN_<R>::operator +=(ui);  return *this;}
+  template<class I,class T> KN& operator -=   (const KN_ITAB<T ,I> & ui)
+     {  KN_<R>::operator -=(ui);  return *this;}
+  template<class I,class T> KN& operator *=   (const KN_ITAB<T ,I> & ui)
+     {  KN_<R>::operator *=(ui);  return *this;}
+  template<class I,class T> KN& operator /=   (const KN_ITAB<T ,I> & ui)
+     {  KN_<R>::operator /=(ui);  return *this;}
+        
+        
+  //  two opertor to cast to an array of constant      
+//    operator KN_<const_R> & ()  
+//          { return *  (KN_<const_R>*) this;}
+//    operator KN_<const_R> const & ()  const 
+//          { return *(const KN_<const_R>*) this;}
+//    operator KN<const_R> & () 
+//          { return   (KN<const_R> &) *this;}
+//    operator KN<const_R> const & ()  const 
+//          { return (const KN<const_R>& ) *this;}
+  void init(long nn) {this->n=nn;this->step=1;this->next=-1;this->v=new R[nn];}
+  void init() {this->n=0;this->step=1;this->next=-1;this->v=0;}
+  void init(const KN_<R> & a){init(a.N()); operator=(a);}
+  void resize(long nn) {
+    if ( nn != this->n) 
+     {
+       R *vo=this->v;
+       long no=std::min(this->n,nn), so=this->step;
+       ShapeOfArray::init(nn);
+       this->v=new R[this->n];
+       // copy
+       if(this->v && vo) 
+         for(long i=0,j=0;j<no;i++,j+=so) 
+           this->v[i]=vo[j]; 
+        delete [] vo;} }//  mars 2010
+    void destroy(){assert(this->next<0);  if(this->next++ ==-1) {delete [] this->v; this->v=0;this->n=0;}}//  mars 2010
+    void increment() {assert(this->next<0);  this->next--;}
+};
+
+//  Array with 2 indices
+//  ---------------------
+
+template<class R>
+class KNM: public KNM_<R>{ public:
+
+  KNM(long nn,long mm) 
+        :KNM_<R>(new R[nn*mm],nn,mm){}
+   KNM(const KNM<R> & u)  // PB si stepi ou stepj nulle
+        :KNM_<R>(new R[u.size()],u.N(),u.M()) 
+       { KN_<R>::operator=(u);}
+  explicit KNM(const KNM_<R> & u)
+        :KNM_<R>(new R[u.size()],u.N(),u.M()) 
+        { KNM_<R>::operator=(u);}
+        
+  ~KNM(){delete [] this->v;}
+  
+   KNM& operator=(const KNM_<const_R> & u)   
+    { if(this->unset()) this->init(u.N(),u.M()) ; KNM_<R>::operator=(u);return *this;}
+   KNM& operator=(const_R a)                 
+    { if(this->unset()) RNM_FATAL_ERROR(" KNM operator=(double)"); KNM_<R>::operator=(a);return *this;}
+   KNM& operator+=(const_R  a)               
+        { if(this->unset()) RNM_FATAL_ERROR(" KNM operator+=(double)"); KNM_<R>::operator+=(a);return *this;}
+   KNM& operator-=(const_R  a)               
+        {if(this->unset()) RNM_FATAL_ERROR(" KNM operator-=(double)"); KNM_<R>::operator-=(a);return *this;}
+   KNM& operator/=(const_R  a)               
+        {if(this->unset()) RNM_FATAL_ERROR(" KNM operator/=(double)"); KNM_<R>::operator/=(a);return *this;}
+   KNM& operator*=(const_R  a)               
+        {if(this->unset()) RNM_FATAL_ERROR(" KNM operator*=(double)"); KNM_<R>::operator*=(a);return *this;}
+   KNM& operator+=(const KNM_<const_R> & u)  
+        { if(this->unset()) this->init(u.N(),u.M()) ; KNM_<R>::operator+=(u);return *this;}
+   KNM& operator-=(const KNM_<const_R> & u)  
+        {  if(this->unset()) this->init(u.N(),u.M()) ;KNM_<R>::operator-=(u);return *this;}
+
+   KNM& operator/=(const KNM_<const_R> & u)  
+        {  if(this->unset()) this->init(u.N(),u.M()) ;KNM_<R>::operator/=(u);return *this;}
+   KNM& operator*=(const KNM_<const_R> & u)  
+        { if(this->unset()) this->init(u.N(),u.M()) ; KNM_<R>::operator*=(u);return *this;}
+
+
+   KNM &operator  =(const outProduct_KN_<R> & u)
+        { if(this->unset()) this->init(u.N(),u.M()) ; KNM_<R>::operator =(u);return *this;}
+   KNM &operator +=(const outProduct_KN_<R> & u)
+        { if(this->unset()) this->init(u.N(),u.M()) ; KNM_<R>::operator+=(u);return *this;}
+   KNM &operator -=(const outProduct_KN_<R> & u)
+        { if(this->unset()) this->init(u.N(),u.M()) ; KNM_<R>::operator-=(u);return *this;}
+   KNM &operator /=(const outProduct_KN_<R> & u) 
+        {  if(this->unset()) this->init(u.N(),u.M()) ;KNM_<R>::operator/=(u);return *this;}
+   KNM &operator *=(const outProduct_KN_<R> & u)
+        {  if(this->unset()) this->init(u.N(),u.M()) ;KNM_<R>::operator*=(u);return *this;}
+  
+        
+  //  two opertors to cast to un array of constant        
+//    operator KNM_<const_R> & ()  
+//          { return *  (KNM_<const_R>*) this;}
+//    operator KNM_<const_R> const & ()  const 
+//          { return *(const KNM_<const_R>*) this;}
+
+//    operator KNM<const_R> & ()  
+//          { return *  (KNM<const_R>*) this;}
+//    operator KNM<const_R> const & ()  const 
+//          { return *(const KNM<const_R>*) this;}
+ 
+    void init() { //  add mars 2010 ...
+	this->n=0;this->step=1;this->next=-1;this->v=0;
+	this->shapei.init(0);
+	this->shapej.init(0);}
+    
+  void init(long nn,long mm) {
+    ShapeOfArray::init(nn*mm);
+    this->shapei.init(nn,1,nn);
+    this->shapej.init(mm,nn,1),
+    this->v=new R[nn*mm];}
+    
+  void resize(long nn,long mm) {     
+    long kk=nn*mm;
+      
+    long lso = this->size();
+    long n = this->shapei.n;
+    long m = this->shapej.n;
+    
+    if( n !=nn && m != mm) 
+     {
+    KNM_ <R> old(*this); 
+    long no=std::min(n,nn);
+    long mo=std::min(m,mm);
+    R *vo=this->v;
+    
+    // new mat 
+    ShapeOfArray::init(kk);
+    this->v=new R[this->n];
+    this->shapei.init(nn,1,nn);
+    this->shapej.init(mm,nn,1);
+    
+    if(this->v && vo)  // copy
+        (*this)(SubArray(no),SubArray(mo)) = old(SubArray(no),SubArray(mo));
+      
+    delete []vo;
+    }
+        
+   }
+    void destroy(){assert(this->next<0);  if(this->next++ ==-1) {delete [] this->v; this->v=0;this->n=0;}} 
+    void increment() {assert(this->next<0);  this->next--;}
+    
+//  void destroy(){delete [] this->v;this->n=0 ;}
+
+};
+
+//  Array with 3 indices
+//  ---------------------
+template<class R>
+class KNMK: public KNMK_<R>{ public:
+
+  KNMK(long n,long m,long k) 
+     :KNMK_<R>(new R[n*m*k],n,m,k){}
+  explicit KNMK(const KNMK_<R> & u)
+     :KNMK_<R>(new R[u.size()],u.N(),u.M(),u.K()) 
+     { KNMK_<R>::operator=(u);}
+   KNMK(const KNMK<R> & u)
+     :KNMK_<R>(new R[u.size()],u.N(),u.M(),u.K()) 
+     { KNMK_<R>::operator=(u);}
+     
+  ~KNMK(){delete [] this->v;}
+  
+  KNMK& operator=(const KNMK_<const_R> & u)   
+     { KNMK_<R>::operator=(u);return *this;}
+  KNMK& operator=(const_R a)                  
+     { KNMK_<R>::operator=(a);return *this;}
+  KNMK& operator+=(const_R  a)                
+     { KNMK_<R>::operator+=(a);return *this;}
+  KNMK& operator-=(const_R  a)                
+     { KNMK_<R>::operator-=(a);return *this;}
+  KNMK& operator/=(const_R  a)                
+     { KNMK_<R>::operator/=(a);return *this;}
+  KNMK& operator*=(const_R  a)                
+     { KNMK_<R>::operator*=(a);return *this;}
+  KNMK& operator+=(const KNMK_<const_R> & u)  
+     { KNMK_<R>::operator+=(u);return *this;}
+  // ici jd 
+  KNMK& operator-=(const KNMK_<const_R> & u)  
+     { KNMK_<R>::operator-=(u);return *this;}
+  KNMK& operator*=(const KNMK_<const_R> & u)   
+     { KNMK_<R>::operator*=(u);return *this;}
+  KNMK& operator/=(const KNMK_<const_R> & u)   
+     { KNMK_<R>::operator/=(u);return *this;}
+     
+//  two opertor to cast to un array of constant          
+//    operator KNMK_<const_R> & ()  
+//       { return *  (KNMK_<const_R>*) this;}
+//    operator KNMK_<const_R> const & ()  const 
+//       { return *(const KNMK_<const_R>*) this;}  
+
+//    operator KNMK<const_R> & ()  
+//       { return *  (KNMK<const_R>*) this;}
+//    operator KNMK<const_R> const & ()  const 
+//       { return *(const KNMK<const_R>*) this;}  
+};
+
+//  -------------  optimization ---------------------
+template<class R> 
+class conj_KN_{public:
+  const KN_<const_R> & a;
+  conj_KN_(const KN_<const_R> & aa) : a(aa){}
+};
+
+
+inline const KN_<long> conj(const KN_<long> &a){ return a;}
+inline const KN_<double> conj(const KN_<double> &a){ return a;}
+inline const KN_<float> conj(const KN_<float> &a){ return a;}
+
+//template<class R> conj_KN_<R> conj(const KN<R> &a){ return a;}
+template<class R> conj_KN_<R> conj(const KN_<R> &a){ return a;}
+
+template<class R> 
+class DotStar_KN_{public: 
+  const KN_<const_R>  a; const KN_<const_R>  b;
+  DotStar_KN_(const KN_<const_R> & aa,const KN_<const_R> & bb) : a(aa),b(bb)  {}
+ }; 
+
+ 
+template<class R> 
+class DotSlash_KN_{public: 
+  const KN_<const_R>  a; const KN_<const_R>  b;
+  DotSlash_KN_(const KN_<const_R> & aa,const KN_<const_R> & bb) : a(aa),b(bb)  {}
+ }; 
+
+template<class R> 
+class Add_KN_{public: 
+  const KN_<const_R>  a; const KN_<const_R>  b;
+  Add_KN_(const KN_<const_R> & aa,const KN_<const_R> & bb) 
+     : a(aa),b(bb)  { K_throwassert(SameShape(a,b));}
+ };  
+ 
+template<class R> 
+class Sub_KN_{public: 
+  const KN_<const_R>  a; const KN_<const_R>  b;
+  Sub_KN_(const KN_<const_R> & aa,const KN_<const_R> & bb) 
+    : a(aa),b(bb) { K_throwassert(SameShape(a,b));}
+ };
+ 
+template<class R> 
+class Mulc_KN_ { public: 
+  const KN_<const_R>  a;  const_R  b;
+  Mulc_KN_(const KN_<const_R> & aa,const_R  bb) : a(aa),b(bb) {}
+  Mulc_KN_(const Mulc_KN_<R> & aa,const_R  bb) : a(aa.a),b(aa.b*bb) {}
+  Mulc_KN_ operator-() const {return Mulc_KN_(a,-b);}
+  outProduct_KN_<R> operator*(const  TKN_<double> & bb)
+{  return outProduct_KN_<R>(a,bb,b);} 
+
+ };  
+
+template<class R> 
+class Add_Mulc_KN_ { public:
+  const KN_<const_R> a,b;
+  const R ca,cb; 
+  Add_Mulc_KN_(const Mulc_KN_<R> & aa,const Mulc_KN_<R> & bb)  
+        : a(aa.a),b(bb.a),ca(aa.b),cb(bb.b) { K_throwassert(SameShape(a,b));}
+  Add_Mulc_KN_(const Mulc_KN_<R> & aa,const KN_<const_R> & bb,const R cbb) 
+        : a(aa.a),b(bb),ca(aa.b),cb(cbb)  { K_throwassert(SameShape(a,b));}
+  Add_Mulc_KN_(const KN_<const_R> & aa,const R caa,const KN_<const_R> & bb,const R cbb) 
+        : a(aa),b(bb),ca(caa),cb(cbb) { K_throwassert(SameShape(a,b));}
+ };  
+
+template<class R> 
+class if_arth_KN_ { public:
+  const KN_<const_R> a,b,c;
+  if_arth_KN_(const KN_<R> & aa,const KN_<R> & bb,const KN_<R> & cc)  
+        : a(aa),b(bb),c(cc){ K_throwassert(SameShape(a,b)&&SameShape(a,c));}
+ };  
+
+
+
+template<class R> 
+class Mul_KNM_KN_ { public:
+  const KNM_<const_R> &A;
+  const KN_<const_R> &b;
+  Mul_KNM_KN_(const  KNM_<const_R>  &aa,const KN_<const_R>  &bb)  
+        : A(aa),b(bb) {K_throwassert(SameShape(A.shapej,b));} 
+};
+
+
+ostream & operator<<(ostream & f,const ShapeOfArray & s);
+
+template<class R> ostream & operator<<(ostream & f,const KN_<const_R>   & v);
+template<class R> ostream & operator<<(ostream & f,const KNM_<const_R>  & v);
+template<class R> ostream & operator<<(ostream & f,const KNMK_<const_R> & v);
+template<class R> inline ostream & operator<<(ostream & f,const KN<const_R>   & v) 
+    { return f << (const KN_<const_R> &) v;}
+template<class R> inline ostream & operator<<(ostream & f,const KNM<const_R>  & v) 
+    { return f << (const KNM_<const_R> &) v;}
+template<class R> inline ostream & operator<<(ostream & f,const KNMK<const_R> & v) 
+    { return f << (const KNMK_<const_R> &) v;}
+
+
+template<class R> inline Add_KN_<R> operator+(const KN_<const_R> &a,const KN_<const_R> &b) 
+    { return Add_KN_<R>(a,b);}
+template<class R> inline Sub_KN_<R> operator-(const KN_<const_R> &a,const KN_<const_R> &b) 
+    { return Sub_KN_<R>(a,b);}
+template<class R> inline Mulc_KN_<R> operator*(const KN_<const_R> &a,const R &b) 
+    { return Mulc_KN_<R>(a,b);}
+template<class R> inline Mulc_KN_<R> operator/(const KN_<const_R> &a,const R &b) 
+    { return Mulc_KN_<R>(a,1/b);}
+template<class R> inline Mulc_KN_<R> operator*(const R &b,const KN_<const_R> &a) 
+    { return Mulc_KN_<R>(a,b);}
+template<class R> inline Mulc_KN_<R> operator-(const KN_<const_R> &a) 
+    { return Mulc_KN_<R>(a,-1);}
+
+
+
+template<class R> inline Add_Mulc_KN_<R> operator+(const  Mulc_KN_<R>& a,const Mulc_KN_<R> &b) 
+    { return Add_Mulc_KN_<R>(a,b);}
+template<class R> inline Add_Mulc_KN_<R> operator-(const  Mulc_KN_<R>& a,const Mulc_KN_<R> &b) 
+    { return Add_Mulc_KN_<R>(a,b.a,-b.b);}
+
+template<class R> inline Add_Mulc_KN_<R> operator+(const  Mulc_KN_<R>& a,const KN_<const_R> &b) 
+   { return Add_Mulc_KN_<R>(a,b,R(1));}
+template<class R> inline Add_Mulc_KN_<R> operator-(const  Mulc_KN_<R>& a,const KN_<const_R> &b) 
+   { return Add_Mulc_KN_<R>(a,b,R(-1));}
+
+template<class R> inline Add_Mulc_KN_<R> operator+(const KN_<const_R> & b,const  Mulc_KN_<R>& a) 
+   { return Add_Mulc_KN_<R>(a,b,R(1));}
+
+// modif FH mars 2007 
+template<class R> inline Add_Mulc_KN_<R> operator-(const KN_<const_R> & a,const  Mulc_KN_<R>& b) 
+   { return Add_Mulc_KN_<R>(a,R(1),b.a,-b.b);}// modif FH mars 2007  
+
+template<class R> inline Mul_KNM_KN_<R> operator*(const  KNM_<const_R> & A,const  KN_<const_R> & b) 
+    { return Mul_KNM_KN_<R>(A,b);}
+
+
+template<class R> inline bool  SameShape(const ShapeOfArray & a,const Add_Mulc_KN_<R> & b) 
+           { return SameShape(a,b.a) ;} 
+template<class R> inline bool  SameShape(const ShapeOfArray & a,const if_arth_KN_<R> & b) 
+           { return SameShape(a,b.a) ;} 
+template<class R> inline bool  SameShape(const ShapeOfArray & a,const Add_KN_<R> & b) 
+           { return SameShape(a,b.a) ;} 
+template<class R> inline bool  SameShape(const ShapeOfArray & a,const Sub_KN_<R> & b) 
+           { return SameShape(a,b.a) ;} 
+template<class R> inline bool  SameShape(const ShapeOfArray & a,const Mulc_KN_<R> & b) 
+           { return SameShape(a,b.a) ;} 
+template<class R> inline bool  SameShape(const ShapeOfArray & a,const DotStar_KN_<R> & b) 
+           { return SameShape(a,b.a) ;} 
+template<class R> inline bool  SameShape(const ShapeOfArray & a,const DotSlash_KN_<R> & b) 
+           { return SameShape(a,b.a) ;} 
+template<class R> inline bool  SameShape(const ShapeOfArray & a,const Mul_KNM_KN_<R> & b) 
+           { return a.n==b.A.N() ;} 
+ inline bool  SameShape(const ShapeOfArray & ,const VirtualMatrice<double>::plusAx & ) 
+           { return true ;} //  pas de test car la matrice peut etre rectangulaire
+ inline bool  SameShape(const ShapeOfArray & ,const VirtualMatrice<double>::plusAtx & ) 
+           { return true ;} //  pas de test car la matrice peut etre rectangulaire
+ inline bool  SameShape(const ShapeOfArray & ,const VirtualMatrice<complex<double> >::plusAx & ) 
+           { return true ;} //  pas de test car la matrice peut etre rectangulaire
+ inline bool  SameShape(const ShapeOfArray & ,const VirtualMatrice<complex<double> >::plusAtx & ) 
+           { return true ;} //  pas de test car la matrice peut etre rectangulaire
+
+ inline bool  SameShape(const ShapeOfArray & ,const double) 
+           { return true;} 
+ inline bool  SameShape(const ShapeOfArray & ,const complex<double>) 
+           { return true;} 
+ inline bool  SameShape(const ShapeOfArray & ,const complex<float>) 
+           { return true;}            
+
+template<class R>
+ inline bool SameShape(KNM<R>& m, const outProduct_KN_<R>& p)
+ { return p.a.N()>=m.N() && m.M()>=p.b.N(); } 
+
+template<class R> inline long SameAdress(const KN_<R> &a, const KN_<R> &b) { return &a[0]==&b[0];}
+// bof -bof 
+//template<class R> inline
+//  KN_<R>::operator KN<R> &() { return *(KN<R> *) (void *) this;}
+//template<class R> inline
+//  KN_<R>::operator const KN<R> &() const { return *(const KN<R> *) ( const void *) this;}
+
+//  operateur y=Ax-b ou y=Ax + b pour le GC
+template<class R> 
+   PplusQ< typename VirtualMatrice<R>::plusAx, Mulc_KN_<R> >  operator-(const typename VirtualMatrice<R>::plusAx & A,const KN_<R> & B)  
+    { return PplusQ< typename VirtualMatrice<R>::plusAx, Mulc_KN_<R> >(A,Mulc_KN_<R>(B,R(-1.)));}
+
+template<class R> 
+   PplusQ< typename VirtualMatrice<R>::plusAx, KN_<R> >  operator+(const typename VirtualMatrice<R>::plusAx & A,const KN_<R> & B)  
+    { return PplusQ< typename VirtualMatrice<R>::plusAx, KN_<R> >(A,B);}
+
+template<class R> 
+   PplusQ< typename VirtualMatrice<R>::plusAx, Mulc_KN_<R> >  operator-(const typename VirtualMatrice<R>::plusAx & A,const KN<R> & B)  
+    { return PplusQ< typename VirtualMatrice<R>::plusAx, Mulc_KN_<R> >(A,Mulc_KN_<R>(B,R(-1.)));}
+
+template<class R> 
+   PplusQ< typename VirtualMatrice<R>::plusAx, KN_<R> >  operator+(const typename VirtualMatrice<R>::plusAx & A,const KN<R> & B)  
+    { return PplusQ< typename VirtualMatrice<R>::plusAx, KN_<R> >(A,B);}
+    
+
+template<class R>
+KN_<R> diagonal(const KNM<R> & A) { 
+  K_throwassert(A.N() == A.M()); 
+  return KN_<R>(A,SubArray(A.N(),0,A.N()+1));}
+
+// to def  inv permutation FH mars 2006 
+class Inv_KN_long{ public:
+  KN_<long>  t;
+  Inv_KN_long(const KN_<long> & v)
+   : t(v) {}
+  Inv_KN_long( KN_<long> const  * & v)
+   : t(*v) {}
+  operator const KN_<long> & () const {return t;}
+};
+
+
+template<class R,typename A,typename B=R> class  F_KN_ 
+{ 
+  public: 
+  A (*f)(B);
+  KN_<R> a;
+  long N() const {return a.N();}
+  F_KN_( A (*ff)(B),const KN_<R> & aa): f(ff),a(aa) {}
+  A operator[](long i) const { return f(a[i]);}
+  bool check(long n)  const { return  n <= a.N() || a.constant(); }
+  bool constant() const {return a.constant();}
+}; 
+
+template<class R,typename A,typename B>
+inline bool  SameShape(const ShapeOfArray & a,const F_KN_<R,A,B>  & b) 
+           { return  !a.step || b.constant()  || a.n == b.N() ;} 
+           
+#include "RNM_tpl.hpp"
+#ifdef K_throwassert
+#undef K_throwassert
+#endif
+#endif
diff --git a/contrib/bamg/RNM_op.hpp b/contrib/bamg/RNM_op.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..c067e89821312d3bf5e0e83b09f27973bdb47cea
--- /dev/null
+++ b/contrib/bamg/RNM_op.hpp
@@ -0,0 +1,157 @@
+// ********** DO NOT REMOVE THIS BANNER **********
+// ORIG-DATE:    29 fev 2000  
+// -*- Mode : c++ -*-
+//
+// SUMMARY  : array modelisation 
+// USAGE    : LGPL      
+// ORG      : LJLL Universite Pierre et Marie Curie, Paris,  FRANCE 
+// AUTHOR   : Frederic Hecht
+// E-MAIL   : frederic.hecht@ann.jussieu.fr
+//
+
+/*
+ 
+ 
+ 
+ Freefem++ is free software; you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+ 
+ Freefem++  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 Lesser General Public License for more details.
+ 
+ You should have received a copy of the GNU Lesser General Public License
+ along with Freefem++; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ 
+ 
+ */
+
+template<class R>  
+KNM_<R> & KNM_<R>::operator oper (const outProduct_KN_<R> & u)  
+{
+  //   *this  oper  A* t B 
+    K_throwassert (shapei.SameShape(u.a) && shapej.SameShape(u.b) );
+    long n= N(), m= M();
+    
+    R * ai(u.a),cc, c= u.c;
+    long stepi=u.a.step;
+    R * bj, *bb(u.b);
+    long stepj=u.b.step;
+    KN_<const_R>  li((*this)(0,'.')); //  first line
+    int stepij= li.step;
+    for (long i=0;i<n;i++,ai += stepi,++li)
+      {
+        cc= c * *ai;
+        R * mij = li;
+        bj = bb;
+        for (long j=0;   j<m; j++, bj += stepj, mij += stepij )         
+          *mij oper cc * conj(*bj) ; 
+       }
+    return *this;
+ }
+
+
+template<class R>
+template<class  A,class B,class C>
+ KN_<R>& KN_<R>::operator oper (const F_KN_<A,B,C> & u)  {
+    K_throwassert ( u.check(this->N()) );
+    R * l(v);  //  first line   
+    for (long i=0;i<n;i++,l += step)  
+      *l oper  u[i]; 
+    return *this;}
+
+template<class R>
+KN_<R>& KN_<R>::operator oper (const SetArray<R> & u)  {
+    R * l(v);  //  first line   
+    for (long i=0;i<n;i++,l += step)  
+	*l oper  u[i]; 
+return *this;}
+
+
+
+template<class R>
+ KN_<R>& KN_<R>::operator oper (const Mul_KNM_KN_<R> & u)  {
+    K_throwassert (SameShape(u.A.shapei) && !constant());
+    R * l(v); KN_<const_R>  li(u.A(0,'.')); //  first line   
+    for (long i=0;i<n;i++,l += step,++li)  
+      *l oper (li,u.b); 
+    return *this;}
+
+
+template<class R>
+ KN_<R>&  KN_<R>::operator oper (const DotStar_KN_<R> & u) {
+    K_throwassert(u.a.N() == N()  );
+    long stepa(u.a.step),stepb(u.b.step);
+    R * l(v); const_R  *aa(u.a), *bb(u.b);    
+    for (long i=0;i<n;i++,l += step, aa +=stepa, bb += stepb)
+      *l oper *aa * *bb;
+    return *this;
+  }
+template<class R>
+ KN_<R>&  KN_<R>::operator oper (const DotSlash_KN_<R> & u) {
+    K_throwassert(u.a.N() == N()  );
+    long stepa(u.a.step),stepb(u.b.step);
+    R * l(v); const_R  *aa(u.a), *bb(u.b);    
+    for (long i=0;i<n;i++,l += step, aa +=stepa, bb += stepb)
+      *l oper *aa / *bb;
+    return *this;
+  }
+
+  
+template<class R>
+ KN_<R>&  KN_<R>::operator oper (const Add_KN_<R> & u) {
+    K_throwassert(u.a.N() == N()  );
+    long stepa(u.a.step),stepb(u.b.step);
+    R * l(v); const_R  *aa(u.a), *bb(u.b);    
+    for (long i=0;i<n;i++,l += step, aa +=stepa, bb += stepb)
+      *l oper *aa+*bb;
+    return *this;
+  }
+
+template<class R>
+ KN_<R>&  KN_<R>::operator oper (const Sub_KN_<R> & u) {
+    K_throwassert(u.a.N() == N()  );
+    long stepa(u.a.step),stepb(u.b.step);
+    R * l(v); const_R  *aa(u.a), *bb(u.b);    
+    for (long i=0;i<n;i++,l += step, aa +=stepa, bb += stepb)
+      *l oper  *aa-*bb;
+    return *this;
+  }
+  
+template<class R>
+ KN_<R>&  KN_<R>::operator oper (const Mulc_KN_<R> & u) {
+    K_throwassert(u.a.N() == N()  );
+    long stepa(u.a.step);
+    R * l(v); const_R  *aa(u.a),bb(u.b)  ;
+    for (long i=0;i<n;i++,l += step, aa +=stepa)
+      *l oper *aa * bb;
+    return *this;
+  }
+  
+template<class R>
+ KN_<R>&  KN_<R>::operator oper (const Add_Mulc_KN_<R> & u) {
+    K_throwassert(u.a.N() == N()  );
+    const long stepa(u.a.step),stepb(u.b.step);
+    const R ca(u.ca),cb(u.cb);    
+    R * l(v);
+    const R *aa(u.a),*bb(u.b);    
+    for (long i=0;i<n;i++,l += step, aa +=stepa, bb += stepb)
+      *l oper *aa*ca + *bb*cb;
+    return *this;
+  }
+
+template<class R>
+ KN_<R>&  KN_<R>::operator oper (const if_arth_KN_<R> & u) {
+    K_throwassert(u.a.N() == N()  );
+    R zero=R();
+    const long stepa(u.a.step),stepb(u.b.step),stepc(u.c.step);
+    R * l(v);
+    const R *aa(u.a),*bb(u.b),*cc(u.c);    
+    for (long i=0;i<n;i++,l += step, aa +=stepa, bb += stepb ,  cc += stepc)
+      *l oper ( (*aa != zero) ?  *bb : *cc);
+    return *this;
+  }
diff --git a/contrib/bamg/RNM_opc.hpp b/contrib/bamg/RNM_opc.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..fdab0e8eadcc126c96a50b3db91e82f46c41a2f5
--- /dev/null
+++ b/contrib/bamg/RNM_opc.hpp
@@ -0,0 +1,108 @@
+// ********** DO NOT REMOVE THIS BANNER **********
+// ORIG-DATE:    29 fev 2000  
+// -*- Mode : c++ -*-
+//
+// SUMMARY  : array modelisation 
+// USAGE    : LGPL      
+// ORG      : LJLL Universite Pierre et Marie Curie, Paris,  FRANCE 
+// AUTHOR   : Frederic Hecht
+// E-MAIL   : frederic.hecht@ann.jussieu.fr
+//
+
+/*
+ 
+ 
+ 
+ Freefem++ is free software; you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+ 
+ Freefem++  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 Lesser General Public License for more details.
+ 
+ You should have received a copy of the GNU Lesser General Public License
+ along with Freefem++; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ 
+ 
+ */
+
+template<class R>
+inline KN_<R>&  KN_<R>::operator oper (const_R a)  {
+    R * l(v);    
+    for (long i=0;i<n;i++,l += step) 
+      *l oper a;
+    return *this;
+  }
+    
+template<class R> 
+inline    KNM_<R> & KNM_<R>::operator oper (const_R a)    
+{ 
+  if(IsVector1() ) 
+        KN_<R>::operator oper (a);
+  else {  
+          KN_<R>  lj(operator()('.',0)); //  (.,.,O)
+          for (long  j=0;j<M();++j,++lj) 
+             lj oper a;}       
+  return *this;
+}
+
+template<class R> 
+inline    KNMK_<R> & KNMK_<R>::operator oper (const_R a)    
+{ 
+  if(IsVector1() ) 
+        KN_<R>::operator oper (a);
+  else {  
+          KNM_<R>  lj(operator()('.','.',0)); //  (.,.,O)
+          long j=K();
+           while(j--)
+            {lj oper a;++lj;}
+       }
+  return *this;
+}
+
+template<class R>
+inline KN_<R>&  KN_<R>::operator oper (const KN_<const_R> & u)   {
+    K_throwassert(u.n == n);
+    R * l(v);
+    const R *r(u);    
+    for (long i=0;i<n;i++,l += step, r += u.step) *l oper *r;
+    return *this;
+  }
+  
+template<class R> 
+inline    KNM_<R> & KNM_<R>::operator oper (const KNM_<const_R> & u)    
+{ 
+  if(IsVector1() && u.IsVector1() ) 
+        KN_<R>::operator oper(u); // modif FH jan 2004
+  else {  
+          KN_<R>  lj(operator()('.',0)); //  (.,O)
+          KN_<const_R>  uj(u('.',0));
+          long  j=M();
+          while ( j--)
+            { lj oper uj;++lj;++uj;} 
+        }      
+  return *this;
+}
+
+
+template<class R> 
+inline  KNMK_<R> & KNMK_<R>::operator oper (const KNMK_<const_R> & u)    
+{ 
+  if(IsVector1() && u.IsVector1() ) 
+        KN_<R>::operator oper(u); // modif FH 2004
+  else {  
+          K_throwassert( K() == u.K());
+          KNM_<R>  lj(operator()('.','.',0)); //  (.,O)
+          KNM_<const_R>  uj(u('.','.',0));
+          long j=K();
+          while (j--)
+           { lj oper uj;++lj;++uj;}
+       }
+  return *this;
+}
+
+#undef oper
diff --git a/contrib/bamg/RNM_tpl.hpp b/contrib/bamg/RNM_tpl.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..02dfdb6488f0b097789ee04fc562515c7eb9b388
--- /dev/null
+++ b/contrib/bamg/RNM_tpl.hpp
@@ -0,0 +1,344 @@
+// ********** DO NOT REMOVE THIS BANNER **********
+// ORIG-DATE:    29 fev 2000  
+// -*- Mode : c++ -*-
+//
+// SUMMARY  : array modelisation 
+// USAGE    : LGPL      
+// ORG      : LJLL Universite Pierre et Marie Curie, Paris,  FRANCE 
+// AUTHOR   : Frederic Hecht
+// E-MAIL   : frederic.hecht@ann.jussieu.fr
+//
+
+/*
+ 
+ 
+ 
+ Freefem++ is free software; you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+ 
+ Freefem++  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 Lesser General Public License for more details.
+ 
+ You should have received a copy of the GNU Lesser General Public License
+ along with Freefem++; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ 
+ 
+ */
+
+#ifndef  RNM_tpl_
+#define  RNM_tpl_
+
+#include "RNM.hpp"
+
+//   version du 22 nov 1999
+//   Voila une debut de class vecteur + matrice 
+//   les class avec termine avec un _ ne travail que sur 
+//   un pointeur existant => pas de new et delete de pointeur
+//   la class correspondant sans de _ genere les pointeurs
+//  
+//   avec ses classes on peut prendre une ligne 
+//   ou une colonne d'une matrice
+// -----------------------
+
+namespace RNM  {
+
+template <class T> inline double norm(const T & x){return std::norm(x);}
+inline double norm(double x){return x*x;} 
+inline double norm(float x){return x*x;}
+inline long norm(long x){return x*x;}
+inline int norm(int x){return x*x;}
+
+}
+
+template<class R>
+void MatMul(KNM_<R> & ab, KNM_<R> &  a, KNM_<R> & b){
+  // attention ne marche que si les adresses ne sont pas les memes
+  long N= a.shapei.n;
+  long M= a.shapej.n;
+  K_throwassert(a.shapej.n == a.shapei.n);
+  K_throwassert(a.shapei.n == ab.shapei.n);
+  K_throwassert(b.shapej.n == ab.shapej.n);
+  K_throwassert(b.v != ab.v);
+  K_throwassert(a.v != ab.v);
+  KN_<R> ai =a(0);
+  for(long i=0;i<N;i++,++ai){
+    KN_<R> bj=b[0];
+    for(long j=0;j<M;j++,++bj)
+      ab(i,j) = (ai , bj)  ;}
+}
+
+
+
+inline ostream & operator<<(ostream & f,const ShapeOfArray & s)
+  { f << s.n ; 
+     const int i10=10; 
+     int prec=f.precision();
+     if(prec<i10) f.precision(i10);
+     if(s.step != 1)
+       f << ":" << s.step ;
+     if (s.step*s.n  !=  s.next ) 
+       f << " n: " << setw(3) << s.next ;
+     f << ",";
+     if(prec<i10) f.precision(prec);
+     return f;
+  };
+
+
+template<class R> ostream & operator<<(ostream & f,const KN_<const_R> & v)
+  { //f <<  " KN_ : " << (ShapeOfArray) v << " "   <<  (const_R *) v << " :\n\t"  ;
+    f << v.N() << "\t\n\t" ; 
+    const int i10=10; 
+    int prec=f.precision();
+    if(prec<i10) f.precision(i10);    
+    for (long i=0;i<v.N();i++)
+      f   << setw(3) << v[i] << ((i % 5) == 4 ? "\n\t" : "\t");
+    if(prec<i10) f.precision(prec); 
+    return f;
+  };
+
+template<class R> istream & operator>>(istream & f, KN_<R> & v)
+ {
+     int n;char c;
+     f >> n;
+     ffassert(f.good());
+     ffassert(n==v.N());
+     while (f.get(c) &&  (c!='\n' && c!='\r' ) ) ; // eat until control (new line
+
+     for (int i=0;i<n;i++)
+      {  f >> v[i] ;
+       ffassert(f.good());} // modif FH  main 2006
+     return f;
+}
+
+template<class R> istream & operator>>(istream & f, KN<R> & v)
+ {
+     int n;char c;
+     f >> n;
+     if (v.unset()) v.init(n);
+     cout << n << " == " << v.N() << endl;
+     ffassert(n==v.N());
+     while (f.get(c) &&  (c!='\n' && c!='\r' ) ) ; // eat until control (new line
+
+     for (int i=0;i<n;i++)
+       {
+       f >> v[i] ;
+       ffassert(f.good());}// modif FH  main 2006
+     return f;
+}
+
+
+template<class R> ostream & operator<<(ostream & f,const KNM_<const_R> & v)
+  {  //f << " KNM_ "<<v.N()<<"x"<<v.M()<< ": " << (ShapeOfArray) v  
+     //<< " i "  << v.shapei
+     // << " j "  << v.shapej
+     // << " " << &v(0,0) << " :\n\t";
+    const int i10=10; 
+    int prec=f.precision();
+    if(prec<i10) f.precision(i10);    
+     f << v.N()<<' '<<v.M() /*<< "  n" << v.next<<" :"<< v.shapei.next << "," << v.shapej.next */<< "\t\n\t" ;
+    for (long i=0;i<v.N();i++) {
+      for (long j=0;j<v.M();j++) 
+        f << " " << setw(3) << v(i,j);
+       f << "\n\t";}
+    if(prec<i10) f.precision(prec);
+  return f;
+    
+   };
+
+template<class R> ostream & operator<<(ostream & f,const KNMK_<const_R> & v)
+  { //f << " KNM_" <<v.N()<<"x"<<v.M()<<"x"<<v.K()<< " : " << (ShapeOfArray) v  
+    // << " i "  << v.shapei
+    // << " j "  << v.shapej
+    // << " k "  << v.shapek << endl;
+    // << " " << (void *) & v(0,0,0) << "\n\t" ;
+    f << v.N()<< 'x' <<v.M()<< 'x'<<v.K() << "\t:\n\t" ;    
+    const int i10=10; 
+    int prec=f.precision();
+    if(prec<i10) f.precision(i10);    
+    for (long i=0;i<v.shapei.n;i++){
+      for (long j=0;j<v.shapej.n;j++){
+	for (long k=0;k<v.shapek.n;k++)
+	  f << " " << setw(3) << v(i,j,k);
+	f << "\n\t";}
+      f << "\n\t";}
+    if(prec<i10) f.precision(prec);
+    return f;
+    
+  };
+
+template<class R>
+ R  KN_<R>::operator,(const KN_<const_R> & u) const {
+    K_throwassert(u.n == n);
+    R  s=0; 
+    R * l(v);
+    R  *r(u.v);    
+    for (long i=0;i<n;i++,l += step, r += u.step) s += *l * *r;
+    return s;
+  }
+
+template<class R>
+ R  operator,(const KN_<const_R> & u,const conj_KN_<const_R> & vc) {
+  int n=u.n;
+    K_throwassert(n == vc.a.n);
+    R  s=0; 
+    R * l(u);
+    R  *r(vc.a);
+    int stepl= u.step, stepr=vc.a.step;    
+    for (long i=0;i<n;i++,l += stepl, r += stepr) s += *l * conj(*r);
+    return s;
+  }
+
+template<class R>
+ R  operator,(const conj_KN_<const_R> & u,const KN_<const_R> & vc) {
+  int n=u.a.n;
+    K_throwassert(n == vc.n);
+    R  s=0; 
+    R * l(u.a);
+    R  *r(vc);
+    int stepl= u.a.step, stepr=vc.step;    
+    for (long i=0;i<n;i++,l += stepl, r += stepr) s += conj(*l) * (*r);
+    return s;
+  }
+
+template<class R>
+ R  operator,(const KN<const_R> & u,const conj_KN_<const_R> & vc) {  return ( (KN_<R>) u,vc);}
+template<class R>
+ R  operator,(const conj_KN_<const_R> & u,const KN<const_R> & vc) {  return (  u, (KN_<R>) vc);}
+
+
+template<class R>
+R  KN_<R>::min() const {
+    R minv = v[index(0)];
+    for (long i=1;i<n;i++)
+      minv = RNM::Min(minv, v[index(i)]) ;
+    return minv;
+  }
+template<class R>
+R  KN_<R>::max() const {
+    R maxv = v[index(0)];
+    for (long i=1;i<n;i++)
+      maxv = RNM::Max(maxv ,v[index(i)]);
+    return maxv;
+  }
+
+
+  
+template<class R>
+R  KN_<R>::sum() const {
+    R s = v[index(0)];
+    for (long i=1;i<n;i++)
+      s +=  v[index(i)];
+    //    cout << " sum = " << s << endl;
+    return s;
+  }
+
+template<class R>
+double  KN_<R>::norm() const {
+  double s = 0.;
+    for (long i=0;i<n;i++)
+      s +=  RNM::norm(v[index(i)]);
+    return s;
+  }
+
+template<class R>
+double  KN_<R>::l2() const {
+  double s = 0.;
+    for (long i=0;i<n;i++)
+      s +=  RNM::norm(v[index(i)]);
+    return sqrt(s);
+  }
+template<class R>
+double  KN_<R>::l1() const {
+  double s = 0.;
+    for (long i=0;i<n;i++)
+      s +=  std::abs(v[index(i)]);
+    return (s);
+  }
+template<class R>
+double  KN_<R>::linfty() const {
+  double s = 0.;
+    for (long i=0;i<n;i++)
+      s = std::max( (double) std::abs(v[index(i)]),s);
+    return (s);
+  }
+template<class R>
+double  KN_<R>::lp(double p) const {
+  if( p==1.) return l1();
+  else if (p==2.) return l2();
+  else if(p>1.e10) return linfty();
+  else
+  {
+  double s = 0.;
+    for (long i=0;i<n;i++)
+      s = pow(std::max( (double) std::abs(v[index(i)]),s),p);
+    return pow(s,1./p);
+   }
+  }
+
+template<class R> template<class T>
+long  KN_<R>::last(const T & a) const {
+    for (long i=n;i-- >0;)
+      if  (a(v[index(i)])) 
+        return i;
+    return -1;
+ }
+ 
+template<class R> template<class T>
+long  KN_<R>::first(const T & a) const {
+    for (long i=0;i<n;i++)
+      if  (a(v[index(i)])) return i;
+    return n;
+ }
+
+
+template<class R>
+ void  KN_<R>::map(R (*f)(R )) {
+    for (long i=0;i<n;i++)
+      {  R & x(v[index(i)]);
+          x =  f(x);}
+   
+  }
+
+template<class R>
+ void  KN_<R>::map(R (*f)(const R& )) {
+    for (long i=0;i<n;i++)
+      {  R & x(v[index(i)]);
+          x =  f(x);}
+   
+  }
+  
+template<class R>
+template<class T>
+ void  KN_<R>::set(R (*f)(const  T& ),KN_<T> & u)
+ { 
+   K_throwassert(N() == u.N());
+   for (long i=0;i<n;i++)
+      {  R & x(v[index(i)]);
+          v[index(i)]= f(u[i]);}
+ } 
+  
+
+
+///////////////// definition des operateurs d'affectation /////////////////////////
+#define oper =
+#include "RNM_op.hpp"
+#include "RNM_opc.hpp"
+#define oper +=
+#include "RNM_op.hpp"
+#include "RNM_opc.hpp"
+#define oper -=
+#include "RNM_op.hpp"
+#include "RNM_opc.hpp"
+#define oper *=
+#include "RNM_op.hpp"
+#include "RNM_opc.hpp"
+#define oper /=
+#include "RNM_op.hpp"
+#include "RNM_opc.hpp"
+
+#endif
diff --git a/contrib/bamg/assertion.hpp b/contrib/bamg/assertion.hpp
new file mode 100755
index 0000000000000000000000000000000000000000..9894ab57e5e83ca7e3a813e37587ba733640abe4
--- /dev/null
+++ b/contrib/bamg/assertion.hpp
@@ -0,0 +1,14 @@
+#ifndef ASSERTION_HPP_
+#define ASSERTION_HPP_
+//  to compile all assertion
+//#define ASSERTION
+// to remove all the assert  
+//#define NDEBUG
+#ifndef ASSERTION
+#define ASSERTION(i)  ((void )  0)
+#else
+#include <cassert>
+#undef ASSERTION
+#define ASSERTION(i) assert(i)
+#endif
+#endif
diff --git a/contrib/bamg/bamg-gmsh.cpp b/contrib/bamg/bamg-gmsh.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..710b1d0a042deb6db891d9565f8ce4a7bf75bd43
--- /dev/null
+++ b/contrib/bamg/bamg-gmsh.cpp
@@ -0,0 +1,578 @@
+// -*- Mode : c++ -*-
+//
+// SUMMARY  :      
+// USAGE    :        
+// ORG      : 
+// AUTHOR   : Frederic Hecht
+// E-MAIL   : hecht@ann.jussieu.fr
+//
+
+/*
+ 
+ This file is part of Freefem++
+ 
+ Freefem++ is free software; you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+ 
+ Freefem++  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 Lesser General Public License for more details.
+ 
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with Freefem++; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+#include <iostream>
+using namespace std;
+#include <stdio.h>
+#include <string.h>
+
+
+#include "Mesh2.h"
+#include "RNM.hpp"
+#include "Mesh2d.hpp"
+#include "bamg-gmsh.hpp"
+
+#include <set>
+void ExecError(const char *s) { cout << s << endl;exit(1);}
+
+
+Mesh2 *bamg2msh( bamg::Triangles* tTh,bool renumbering)
+{ 
+  using  bamg::Triangles;
+  using  bamg::Triangle;
+  using  bamg::Vertex;
+  using  bamg::TriangleAdjacent;
+  using  bamg::EdgesVertexTriangle;
+  using  bamg::Int4;
+  using  bamg::VerticesOfTriangularEdge;
+
+  bamg::Triangles & th (*tTh);
+  tTh->ReNumberingTheTriangleBySubDomain(!renumbering);//  just compress 
+  //tTh->NbRef++;
+  Int4  i,j,k=0;
+  int nv  =  tTh->nbv;
+  int nt  =   tTh->nbt - tTh->NbOutT;
+  int neb =   tTh->nbe;
+  
+  int nbcrakev = 0;
+  tTh->ReMakeTriangleContainingTheVertex();
+  Triangle2 * t =  new Triangle2[nt]  ;
+  Seg * b_e = new Seg[neb];
+  
+  Vertex2 vbase;        
+  Vertex2 *vb(&vbase);
+  if (verbosity>5)
+    cout << "  -- Before cracking mesh:  Nb Triangles = " << nt << " Nb of Vertices " << nv << endl;
+  for (int iv=0;iv<th.nbv;iv++) // vertex 
+    {
+      // cout << iv << " : " ;
+      const Vertex & v(th[iv]); 
+      int kk=0; // nb cracked
+      int kc=0; 
+      int kkk =0; // nb triangle  with same number 
+      Triangle * tbegin = v.t;
+      Vertex2 * vv = vb+iv;
+      int i  = v.vint;       
+      assert(tbegin && (i >= 0 ) && (i <3));
+      // turn around the vertex v
+      TriangleAdjacent ta(tbegin,EdgesVertexTriangle[i][0]);// previous edge
+      int k=0;
+      do {
+        int kv = VerticesOfTriangularEdge[ta][1];
+        k++; 
+        Triangle * tt (ta);
+        assert( &v == & (*  tt)[kv] );            
+        if ( ta.Cracked() ) 
+          {   // cout << " || "    ;                    
+            if ( kk == 0) tbegin=ta,kkk=0;  //  begin by a cracked edge  => restart                
+            if (  kkk ) { kc =1;vv = vb +  nv++;  kkk = 0; } // new vertex if use 
+            kk++;
+            // number of cracked edge view                 
+          }
+        if ( tt->link ) { // if good triangles store the value 
+          int it = th.Number(tt);
+          assert(it < nt);
+          //int iiv=vv-vb;
+          t[it](kv) = vv;
+          /*
+          cout << it << " " << kv << " "<< iiv  << endl;
+          if (&th(it)[kv] != &th[iiv])
+             cout << it << " " << kv << " "<< iiv << " != " << th.Number(th(it)[kv]) << endl ;
+          */
+          kkk++;
+        } else if (kk) { // crack + boundary 
+          if (  kkk ) { kc =1;vv = vb +  nv++;  kkk = 0; } // new vertex if use 
+        }
+        
+        ta = Next(ta).Adj(); 
+      } while ( (tbegin != ta)); 
+      assert(k);
+      if (kc)  nbcrakev++;
+    }
+  Vertex2 * v = new Vertex2[nv];
+  //  set the vertices --
+  for (i=0;i<nt;i++)
+    { 
+      for (j=0;j<3;j++)
+        {
+          assert( t[i](j) );             
+          int k = t[i](j) - vb;
+          t[i](j) = v+ k;
+          assert(k>=0 && k < nv);
+          Vertex & thv(th(i)[j]);
+          v[k].x    =  thv.r.x;
+          v[k].y    =  thv.r.y;
+          v[k].lab  =  thv.ref();        
+        }  
+    }
+  // warning in cracked edges 
+  // construction of the edges --
+  
+  if (nbcrakev && verbosity>2)
+    cout << "  -- Nb of craked vertices = " << nbcrakev << " Nb of created vertices " << nv - th.nbv << endl;
+  
+   
+  for (i=0;i<tTh->nbe;i++)
+    {
+      int ii[]={tTh->Number(tTh->edges[i][0]),tTh->Number(tTh->edges[i][1])};
+      assert(ii[0]>=0 && ii[0] <nv);
+      assert(ii[1]>=0 && ii[1] <nv);      
+      b_e[i].init(v,ii,tTh->edges[i].ref);
+    }      
+  Int4 *reft = new Int4[tTh->nbt];
+  //Int4 nbref =
+  tTh->ConsRefTriangle(reft);
+  for( i=0,k=0;i<tTh->nbt;i++)
+    if(tTh->triangles[i].link)
+      { 
+        
+        R2 A(t[k][0]),B(t[k][1]),C(t[k][2]);
+        t[k].area = (( B-A)^(C-A))*0.5 ;
+        t[k].lab = tTh->subdomains[reft[i]].ref;  // a faire
+        assert(k == i);
+        k++;
+      }
+  delete [] reft;
+  assert ( nt == k);
+  tTh->ReMakeTriangleContainingTheVertex();
+  
+  if (verbosity)
+    cout << "  --  mesh:  Nb of Triangles = "  << setw(6) <<  nt << ", Nb of Vertices " << nv << endl;
+  
+  {  
+    Mesh2 *m = new Mesh2(nv,nt,neb,v,t,b_e);
+    //    if (renumbering) m->renum();
+    //< m->MakeQuadTree();
+    return m;
+  }
+}
+
+
+
+bamg::Triangles * msh2bamg(const Mesh2 & Th,double cutoffradian,long * reqedgeslab,int nreqedgeslab)
+
+{
+    using namespace bamg;
+    Triangles *Tn=new Triangles(Th.nv);
+    Tn->nbv = Th.nv;
+    Tn->nbt = Th.nt;
+    Tn->nbe = Th.nbe;
+    Tn->name= new char[strlen("msh2bamg")+1];
+    strcpy(Tn->name,"msh2bamg");
+    //  Tn->triangles = new Triangle [Tn->nbtx];
+    assert(Tn->triangles);
+    //  Tn->vertices = new Vertex [Tn->nbvx];
+    //  Tn->ordre = new (Vertex* [Tn->nbvx]);
+    Tn->edges = new Edge [Th.nbe];
+    
+    Int4 i;
+    Metric Mid(1.);
+    for (i = 0; i < Th.nv; i++)
+      {
+	Tn->vertices[i].r.x = Th(i).x;
+	Tn->vertices[i].r.y = Th(i).y;
+	Tn->vertices[i].m=Mid;
+	Tn->vertices[i].ReferenceNumber = Th(i).lab;
+      }
+    
+    //  Int4 i1 [nbt],i2 [nbt],i3 [nbt];
+    for (i = 0; i < Th.nt; i++)
+      {
+	int i1 = Th(Th[i][0]);
+	int i2 = Th(Th[i][1]);
+	int i3 = Th(Th[i][2]);
+	Tn->triangles[i]= Triangle( Tn,i1 ,i2 ,i3 );
+	Tn->triangles[i].color = Th[i].lab;
+      }
+    //  Real8 cutoffradian = -1;    
+    // add code   un change boundary part ...  frev 2009 JYU FH
+    set<int> labreq;
+    if(nreqedgeslab && verbosity) cout << " label of required edges " ;
+    for (int i=0; i <nreqedgeslab;++i)
+      {
+	if(verbosity)
+	    cout << " " << reqedgeslab[i];
+	labreq.insert(reqedgeslab[i]);
+      }
+    bamg::GeometricalEdge paszero;  // add JYU    fevr 2009   for  required edge ....
+    if(nreqedgeslab && verbosity) cout << endl;
+    int k=0;  
+    for (i = 0; i < Th.nbe; i++)
+      {
+	Tn->edges[i].v[0] = Tn->vertices + Th(Th.be(i)[0]);
+	Tn->edges[i].v[1] = Tn->vertices + Th(Th.be(i)[1]);
+	Tn->edges[i].ref = Th.be(i).lab;
+	Tn->edges[i].on = 0; 
+	if( labreq.find( Tn->edges[i].ref) != labreq.end())
+	  {
+	    k++; 
+	    Tn->edges[i].on = &paszero; 
+	  }
+	
+      }
+    if(verbosity)cout << "  number of required edges : "<< k << endl;
+    
+    
+    Tn->ConsGeometry(cutoffradian);   
+    Tn->Gh.AfterRead();    
+    Tn->SetIntCoor();
+    Tn->FillHoleInMesh();
+    return Tn;
+}
+
+
+bamg::Triangles * msh2bamg(const Mesh2 & Th,double cutoffradian, 
+                           int  nbdfv, int * ndfv,int  nbdfe, int * ndfe,
+			   long * reqedgeslab,int nreqedgeslab)
+{
+    using namespace bamg;
+    Triangles *Tn=new Triangles(Th.nv);
+    KN<int> equiedges(Th.nbe);
+    for(int i=0;i<Th.nbe;i++)
+	equiedges[i]=2*i;
+    if(nbdfe !=0 )
+      {
+	KN<int>  kk(Th.nbe),kn(Th.nbe);
+	kk=0;
+	for(int i=0;i<Th.nbe;i++)
+	  {
+	    int df=ndfe[i];
+	    kk[df]++;
+	    if(kk[df]==1) kn[df]=i;
+	    else { 
+		int k=kn[df],sens=0;
+		int di0=ndfv[Th(Th.be(i)[0])];
+		int di1=ndfv[Th(Th.be(i)[1])];
+		int dk0=ndfv[Th(Th.be(k)[0])];
+		int dk1=ndfv[Th(Th.be(k)[1])];
+		if ((di0==dk0) &&(di1==dk1) ) sens=0;
+		else if ((di1==dk0) &&(di0==dk1) ) sens=1;
+		else  {
+		    cout << "Error in periodic mesh " << di0 << " " << di1 << " <=> " << dk0 << " " << dk1 << endl;
+		    ExecError("bug periodic mesh in ??? ");
+		}
+		equiedges[i]=2*k+sens;
+		
+	    }
+	  }
+	
+      }; // a faire pour les maillages periodique 
+    
+    Tn->nbv = Th.nv;
+    Tn->nbt = Th.nt;
+    Tn->nbe = Th.nbe;
+    Tn->name= new char[strlen("msh2bamg")+1];
+    strcpy(Tn->name,"msh2bamg");
+    //  Tn->triangles = new Triangle [Tn->nbtx];
+    assert(Tn->triangles);
+    //  Tn->vertices = new Vertex [Tn->nbvx];
+    //  Tn->ordre = new (Vertex* [Tn->nbvx]);
+    Tn->edges = new Edge [Th.nbe];
+    
+    Int4 i;
+    Metric Mid(1.);  
+    for (i = 0; i < Th.nv; i++)
+      {
+	Tn->vertices[i].r.x = Th(i).x;
+	Tn->vertices[i].r.y = Th(i).y;
+	Tn->vertices[i].ReferenceNumber = Th(i).lab;
+	Tn->vertices[i].m=Mid;
+      }
+    
+    //  Int4 i1 [nbt],i2 [nbt],i3 [nbt];
+    for (i = 0; i < Th.nt; i++)
+      {
+	int i1 = Th(Th[i][0]);
+	int i2 = Th(Th[i][1]);
+	int i3 = Th(Th[i][2]);
+	Tn->triangles[i]= Triangle( Tn,i1 ,i2 ,i3 );
+	Tn->triangles[i].color = Th[i].lab;
+      }
+    
+    // add code   un change boundary part ...  frev 2009 JYU FH
+    set<int> labreq;
+    if(nreqedgeslab && verbosity) cout << " label of required edges " ;
+    for (int i=0; i <nreqedgeslab;++i)
+      {
+	if(verbosity)
+	    cout << " " << reqedgeslab[i];
+	labreq.insert(reqedgeslab[i]);
+      }
+    bamg::GeometricalEdge paszero;  // add JYU    fevr 2009   for  required edge ....
+    if(nreqedgeslab && verbosity) cout << endl;
+    int k=0;  
+    
+    for (i = 0; i < Th.nbe; i++)
+      {
+	Tn->edges[i].v[0] = Tn->vertices + Th(Th.be(i)[0]);
+	Tn->edges[i].v[1] = Tn->vertices + Th(Th.be(i)[1]);
+	Tn->edges[i].ref = Th.be(i).lab;
+	Tn->edges[i].on = 0; 
+	if( labreq.find( Tn->edges[i].ref) != labreq.end())
+	  {
+	    k++; 
+	    Tn->edges[i].on = &paszero; 
+	  }
+      }
+    //  Real8 cutoffradian = -1;
+    Tn->ConsGeometry(cutoffradian,equiedges);
+    Tn->Gh.AfterRead();    
+    Tn->SetIntCoor();
+    Tn->FillHoleInMesh();
+    return Tn;
+}
+
+
+template<class T> T arg(int i,double *args,const T & d)
+{
+    return args[i]<= -1.e100  ? d: (T) args[i];
+}
+Mesh2 *Bamg(Mesh2 *Thh, double * args,double *mm11,double *mm12,double *mm22, bool initialMesh)
+{
+  using namespace bamg;
+  using RNM::Min;
+  using RNM::Max;
+  using RNM::Abs;
+
+
+  Real8 err         = arg(2,args,0.01);    // coef in the metric
+  Real8  errg       = Min(arg(3,args,0.01),err);
+  long nbsx         = Max(100L,arg(4,args,900000L));
+  long nbsmooth     =  arg(5,args,3L);
+  long nbjacobi     =  arg(6,args,0L) ;              // if increased will be more smooth
+  const Real8 raison = arg(7,args,1.5); // 1.8
+  const Real8 omega =  arg(8,args,1.0) ; 
+  bool iso          =   arg(9,args,false);
+  bool AbsError     =   arg(10,args,true);
+  Real8 CutOff      =   arg(11,args, 1.0e-6);
+  verbosity         =   arg(12,args, (long) verbosity);   
+  bool inq          =   arg(13,args,false);
+  bool SplitEdgeWith2Boundary =  arg(14,args,true);
+  double maxsubdiv             = Max(Min( arg(15,args,10.0),10.0),0.1);
+  double anisomax              =   Max((double) arg(16,args,1.0e6),1.0);
+  bool rescaling               = arg(17,args,true) ;
+  bool KeepBackVertices        =   arg(18,args,true) ;
+  int givenmetric              =  arg(19,args,false) ;
+  double powerM                = arg(20,args,1.0) ;
+  double cutoffradian          = arg(21,args,-1.0)* bamg::Pi/180. ;
+  bool split                    = arg(22,args,false) ;
+  bool nomeshgeneration         = arg(23,args,false) ;
+  //   the 24th param is metrix  and is store at compilation time
+  //  const E_Array * expmetrix = dynamic_cast<const E_Array *>(nargs[24]);
+  //   the 25th param is periodic and it store at compilation time
+  // in nbcperiodic,periodic  variable 
+  //  KN<long> reqedges0;
+  //  list of label of required edges , for no adapattion on this part of the boundary.     
+  //    KN<long> reqedges ( nargs[26] ? GetAny< KN_<long> >( (*nargs[26])(stack) ): (KN_<long>)reqedges0); 
+  
+  KN<long> reqedges(Thh->nbe);
+  for (int i=0;i<Thh->nbe;i++)reqedges[i]=Thh->be(i).lab;
+
+  if(reqedges.N() && verbosity)
+      cout << " reqedges labels "  << reqedges << endl;
+  //  KN<double> *mm11=0, *mm12=0,* mm22=0;
+
+  // using MeshPoint;
+  //using Mesh;
+  ffassert(Thh);
+    Triangles * oTh =0;
+    int nbcperiodic=0;
+  /*   A change ...
+  if (nbcperiodic) {
+    KN<int> ndfv(Thh->nv);
+    KN<int> ndfe(Thh->nbe);
+    int nbdfv=0,nbdfe=0;      
+    BuildPeriodic(nbcperiodic,periodic,*Thh,stack,nbdfv,ndfv,nbdfe,ndfe);
+    oTh = msh2bamg(*Thh,cutoffradian,nbdfv,ndfv,nbdfe,ndfe,reqedges,reqedges.N());
+  }
+  else */
+   oTh = msh2bamg(*Thh,cutoffradian,reqedges,reqedges.N());
+  Triangles &Th(*oTh);
+
+  //  printf("COUCOUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU\n");
+  //  Th.Write("toto.mesh",bamg::Triangles::AutoMesh);  
+
+
+  bool mtx=true;
+  KN_<double> m11(mm11,Thh->nv);
+  KN_<double> m12(mm12,Thh->nv);
+  KN_<double> m22(mm22,Thh->nv);
+ 
+  Real8 hmax = 0.3*Th.MaximalHmax(); // final largest edge 
+  Real8 hmin = Th.MinimalHmin();        // final smallest edge
+  
+
+  Real8 coef =1;                // a priori don't touch
+  // gestion des arguments 
+  hmin              = Max(hmin, arg(0,args,hmin));
+  hmax              = Min(hmax,arg(1,args,hmax));
+
+  
+  if (iso)  anisomax=1;
+  if (verbosity>2) 
+    {
+      cout << endl  << endl; 
+      cout << " \t\t ## adapt :   nbsx = " << nbsx << ", err = " << err ;
+      cout << ", hmin = " << hmin << ", hmax = " << hmax <<endl;
+      cout << " \t\t    ratio  = " << raison << ", nbsmooth = " << nbsmooth ;
+      cout << ", omega = " << omega <<  ", coef = " << coef << ", iso = " << iso << endl;
+      cout << " \t\t    AbsError =" << AbsError << ", CutOff = " << CutOff << ", nbjacobi = " << nbjacobi <<endl;
+      cout << " \t\t    maxsubdiv = " << maxsubdiv << " splitpbedge = " << SplitEdgeWith2Boundary  <<endl;
+      cout << " \t\t    anisomax = " << anisomax << ", rescaling = " << rescaling << ", power = " << powerM
+           << ", KeepBackvertices = " << KeepBackVertices << " IsMetric = " << givenmetric
+      << endl << endl ; 
+    }
+    
+ // 
+ Th.ReMakeTriangleContainingTheVertex();
+    /*
+  //MeshPoint* mp(MeshPointStack(stack));
+   
+  Int4 i,iv; 
+  int ksol =0;
+  for (i=0;i<nbsol;i++)
+    ksol += typesol[i]+1; //  marche en 2d 
+   
+  double * lessol = new double [Th.nbv*ksol];
+  double *ss = lessol;
+  // be careful because renum --
+  // the triangle was no renum 
+  for ( iv=0;iv<Th.nbv;iv++) 
+    Th[iv].color=1; // color 
+ for (Int4  it = 0; it < Thh->nt; it++)
+    for (Int4  jt = 0; jt < 3; jt++)
+      { 
+        bamg::Vertex & v= Th(it)[jt];
+	//   const Vertex & vf = (*Thh)[it][jt];
+        if (&v && v.color)
+          {
+            v.color =0; // uncolor
+            mp->setP(Thh ,it,jt);
+ 
+            ss = lessol + ksol* Th.Number(v);
+            for (int j =0; j < ksol; j++)
+              *ss++= GetAny<double>( (*sol[j])(stack) );
+           
+          }
+      }
+  mp->unset();
+     */
+  // computation of the metric --- 
+  // better thing -> create keyword in the language 
+  //    a faire F Hecht .
+  Metric Mhmax(hmax);
+  for (int iv=0;iv<Th.nbv;iv++) 
+    Th[iv].m = Mhmax;
+    
+   if (mtx) 
+     for (int iv=0;iv<Th.nbv;iv++) {
+       //      if ( Max(m11[iv],m12[iv],m22[iv]) > hmax) 
+       Th[iv].m.IntersectWith(MetricAnIso(m11[iv],m12[iv],m22[iv]));
+     }
+  /* 
+  if ( givenmetric)
+    if (ksol == 1) 
+      {
+        for (Int4  iv = 0,k=0; iv < Th.nbv ; iv++)
+          Th[iv].m.IntersectWith(Metric(lessol[k++]));
+      }
+    else if (ksol == 3) 
+      {
+        for (Int4  iv = 0,k=0; iv < Th.nbv ; iv++, k += 3)
+          {
+	    Metric MM(lessol[k],lessol[k+1],lessol[k+2]);
+	    MatVVP2x2 vp(MM);
+	    vp.Abs();
+	    Th[iv].m.IntersectWith(vp);
+          }
+      }
+    else
+      lgerror("Adapt mesh: ksol is wrong, IsMetric  and ksol != 1 or 3");
+  else
+  Th.IntersectConsMetric(lessol,nbsol,typesol,hmin,hmax,sqrt(err)*coef,anisomax,AbsError?0.0:CutOff,nbjacobi,rescaling,powerM,0);
+    
+    delete [] lessol;
+   */
+  //Th.IntersectGeomMetric(errg,iso);
+
+  Th.SmoothMetric(raison);
+  Th.MaxSubDivision(maxsubdiv);
+  Th.BoundAnisotropy(anisomax);
+  // end of metric's computation 
+   if (mtx) 
+    for (int iv=0;iv<Th.nbv;iv++) 
+      {
+       m11[iv] = Th[iv].m.a11  ;
+       m22[iv] = Th[iv].m.a22 ; 
+       m12[iv] = Th[iv].m.a21;
+      }
+  
+  Triangles* nTh = 0;
+  
+   //   Th.Write("toto.msh",bamg::Triangles::AutoMesh);
+
+  if (initialMesh){
+    nTh= new Triangles(nbsx,Th.Gh);     
+  }
+  else {
+    nTh= new Triangles(nbsx,Th,KeepBackVertices); // Adaption is here
+  }
+
+  //  nTh->Write("tata.mesh",bamg::Triangles::AutoMesh);  
+
+
+  if (split)
+    nTh->SplitElement(1); // modif FH mai 2009 (thank J-M Mirebeau) : Th ->nTh
+ 
+  if(SplitEdgeWith2Boundary)
+    nTh->SplitInternalEdgeWithBorderVertices();
+  if(verbosity>3) 
+    nTh->ShowHistogram();
+  if (nbsmooth)
+    nTh->SmoothingVertex(nbsmooth,omega);
+  if(verbosity>2 && nbsmooth) 
+    nTh->ShowHistogram();
+  if(verbosity>0)  
+      nTh->ShowRegulaty()  ;
+   
+  inq=0;
+  Metric M(hmax);
+  for (int iv=0;iv < Th.nbv;iv++)
+    Th[iv].m = M;
+
+  Mesh2 * g=  bamg2msh(nTh,true);
+
+  delete nTh;
+  delete oTh;
+ //  Add2StackOfPtr2FreeRC(stack,g);// 07/2008  FH
+     
+  return g;
+
+}   
+
+ 
diff --git a/contrib/bamg/bamg-gmsh.hpp b/contrib/bamg/bamg-gmsh.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..f567dda92c6917afe87fa6c2b3d949d516b2e049
--- /dev/null
+++ b/contrib/bamg/bamg-gmsh.hpp
@@ -0,0 +1,6 @@
+Mesh2 *bamg2msh( bamg::Triangles* tTh,bool renumbering);
+bamg::Triangles * msh2bamg(const Mesh2 & Th,double cutoffradian,long * reqedgeslab,int nreqedgeslab);
+bamg::Triangles * msh2bamg(const Mesh2 & Th,double cutoffradian, 
+                           int  nbdfv, int * ndfv,int  nbdfe, int * ndfe,
+			   long * reqedgeslab,int nreqedgeslab);
+Mesh2 *Bamg(Mesh2 *Thh, double * args,double *mm11,double *mm12,double *mm22);
diff --git a/contrib/bamg/bamglib/Mesh2.cpp b/contrib/bamg/bamglib/Mesh2.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..2f99240946710360457a804cd45a4e23cf87d081
--- /dev/null
+++ b/contrib/bamg/bamglib/Mesh2.cpp
@@ -0,0 +1,5177 @@
+// -*- Mode : c++ -*-
+//
+// SUMMARY  :      
+// USAGE    :        
+// ORG      : 
+// AUTHOR   : Frederic Hecht
+// E-MAIL   : hecht@ann.jussieu.fr
+//
+
+/*
+ 
+ This file is part of Freefem++
+ 
+ Freefem++ is free software; you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+ 
+ Freefem++  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 Lesser General Public License for more details.
+ 
+ You should have received a copy of the GNU Lesser General Public License
+ along with Freefem++; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+#ifdef __MWERKS__
+#ifdef __INTEL__
+//#pragma global_optimizer off
+//#pragma inline_depth(0)
+//#pragma optimization_level 2
+#endif
+//#pragma inline_depth 0
+#endif
+extern bool withrgraphique;
+#include <stdio.h>
+#include <string.h>
+#include <math.h> 
+#include <time.h>
+#include <iostream>
+using namespace std; 
+
+#include "Mesh2.h"
+#include "QuadTree.h"
+#include "SetOfE4.h"
+
+namespace bamg {
+
+
+#ifdef DEBUG1
+extern int SHOW ; // for debugging 
+int SHOW = 0; // for debugging 
+
+#endif
+
+int  Triangles::counter = 0;
+
+Triangles * CurrentTh =0;
+
+int hinterpole=1;
+
+
+long NbUnSwap =0;
+int  ForDebugging = 0;
+const Direction NoDirOfSearch = Direction();
+#ifndef NDEBUG 
+inline void MyAssert(int i,char*ex,char * file,long line) 
+{
+  if( i) {
+    cerr << "Error Assert:" << ex << " in " << file << " line: " << line << endl;
+#ifdef  NOTFREEFEM
+    exit(1); 
+#else
+    throw(ErrorExec("exit",1000));
+#endif
+  }
+}
+#endif
+
+Int4 AGoodNumberPrimeWith(Int4 n)
+{
+  const Int4 BigPrimeNumber[] ={ 567890359L,
+				 567890431L,  567890437L,  567890461L,  567890471L,
+				 567890483L,  567890489L,  567890497L,  567890507L,
+				 567890591L,  567890599L,  567890621L,  567890629L , 0};
+  
+  Int4 o = 0;
+  Int4 pi = BigPrimeNumber[1];
+  for (int i=0; BigPrimeNumber[i]; i++) {
+    Int4 r = BigPrimeNumber[i] % n;
+    Int4 oo = Min(Min(r,n-r),Min(Abs(n-2*r),Abs(n-3*r)));
+    if ( o < oo) 
+      o=oo,pi=BigPrimeNumber[i];}
+  //  cout << " AGoodNumberPrimeWith " << n << " " <<pi << " "<< o << endl;
+  return pi; 
+}
+
+class Triangles;
+void MeshError(int Err,Triangles *Th){ 
+ cerr << " Fatal error in the meshgenerator " << Err << endl ;
+#ifdef  NOTFREEFEM
+    exit(1); 
+#else
+  throw(ErrorMesh("Bamg",Err,Th));
+#endif
+}
+
+ ostream& operator <<(ostream& f, const  Triangle & ta)
+  {
+    if(CurrentTh)
+      f << "[" << CurrentTh->Number(ta) << "::" 
+     <<  CurrentTh->Number(ta.ns[0]) << "," 
+     <<  CurrentTh->Number(ta.ns[1]) << "," 
+     <<  CurrentTh->Number(ta.ns[2]) << "," 
+     << "{" <<  CurrentTh->Number(ta.at[0]) << " " << ta.aa[0] << "} " 
+     << "{" <<  CurrentTh->Number(ta.at[1]) << " " << ta.aa[1] << "} " 
+     << "{" <<  CurrentTh->Number(ta.at[2]) << " " << ta.aa[2] << "} " 
+     << "]" ;
+     else
+       f << "[" 
+     << ta.ns[0] << "," 
+     << ta.ns[1] << "," 
+     << ta.ns[2] << "," 
+     << "{" << ta.at[0] << " " << ta.aa[0] << "} " 
+     << "{" << ta.at[1] << " " << ta.aa[1] << "} " 
+     << "{" << ta.at[2] << " " << ta.aa[2] << "} " 
+     << "]" ;
+   return f;}
+
+void  swap(Triangle *t1,Int1 a1,
+                 Triangle *t2,Int1 a2,
+                 Vertex *s1,Vertex *s2,Icoor2 det1,Icoor2 det2)
+{ // swap 
+  // --------------------------------------------------------------
+  // Int1 a2=aa[a];// les 2 numero de l arete dans les 2 triangles
+  //                               
+  //               sb                     sb    
+  //             / | \                   /   \                      !
+  //         as1/  |  \                 /a2   \                     !
+  //           /   |   \               /    t2 \                    !
+  //       s1 /t1  | t2 \s2  -->   s1 /___as2___\s2                 !
+  //          \  a1|a2  /             \   as1   /  
+  //           \   |   /               \ t1    /   
+  //            \  |  / as2             \   a1/    
+  //             \ | /                   \   /     
+  //              sa                       sa   
+  //  -------------------------------------------------------------
+  int as1 = NextEdge[a1];
+  int as2 = NextEdge[a2];
+  int ap1 = PreviousEdge[a1];
+  int ap2 = PreviousEdge[a2];
+#ifdef DRAWING1
+  couleur(0);
+  t1->Draw();
+  t2->Draw();
+#endif
+#ifdef DEBUG1
+  t1->check();
+  t2->check();
+#endif
+  (*t1)(VerticesOfTriangularEdge[a1][1]) = s2 ; // avant sb
+  (*t2)(VerticesOfTriangularEdge[a2][1]) = s1  ; // avant sa
+  // mise a jour des 2 adjacences externes 
+  TriangleAdjacent taas1 = t1->Adj(as1),
+    taas2 = t2->Adj(as2),
+    tas1(t1,as1), tas2(t2,as2),
+    ta1(t1,a1),ta2(t2,a2);
+#ifdef DEBUG
+  assert( ! ta1.Locked());
+  assert( ! ta2.Locked());
+#endif
+  // externe haut gauche
+  taas1.SetAdj2(ta2, taas1.GetAllFlag_UnSwap());
+   // externe bas droite
+  taas2.SetAdj2(ta1, taas2.GetAllFlag_UnSwap());
+  // remove the Mark  UnMarkSwap 
+  t1->SetUnMarkUnSwap(ap1);
+  t2->SetUnMarkUnSwap(ap2);
+  // interne 
+  tas1.SetAdj2(tas2);
+
+  t1->det = det1;
+  t2->det = det2;
+
+  t1->SetTriangleContainingTheVertex();
+  t2->SetTriangleContainingTheVertex();
+#ifdef DEBUG1
+  t1->check();
+  t2->check();
+#endif
+#ifdef DRAWING1 
+  couleur(1);
+  t1->Draw();
+  t2->Draw();
+#endif 
+#ifdef DRAWING1
+  if(  CurrentTh)
+    CurrentTh->inquire();
+#endif
+
+} // end swap 
+
+
+
+
+
+Int4 FindTriangle(Triangles &Th, Real8 x, Real8 y, double* a,int & inside)
+ {
+   CurrentTh=&Th;
+   assert(&Th);
+   I2 I = Th.toI2(R2(Min(Max(Th.pmin.x,x),Th.pmax.x),Min(Max(Th.pmin.y,y),Th.pmax.y))); 
+   Icoor2 dete[3];
+   Triangle & tb = *Th.FindTriangleContening(I,dete);
+   
+   if  (tb.link) 
+     { // internal point in a true triangles
+       a[0]= (Real8) dete[0]/ tb.det;
+       a[1]= (Real8) dete[1] / tb.det;
+       a[2] = (Real8) dete[2] / tb.det;
+	 inside = 1;	 
+	 return Th.Number(tb);
+     } 
+   else 
+     {
+       inside = 0; 
+       double aa,bb;
+       TriangleAdjacent  ta=CloseBoundaryEdgeV2(I,&tb,aa,bb);	 
+       int k = ta;
+       Triangle * tc = ta;
+       if (!tc->link) 
+	 { ta = ta.Adj();
+	 tc=ta;
+	 k = ta;
+	 Exchange(aa,bb);
+	 assert(tc->link);
+	 }
+       a[VerticesOfTriangularEdge[k][0]] = aa;
+       a[VerticesOfTriangularEdge[k][1]] = bb;
+       a[OppositeVertex[k]] = 1- aa -bb;
+       return Th.Number(tc);
+     }
+ }
+
+
+TriangleAdjacent CloseBoundaryEdge(I2 A,Triangle *t, double &a,double &b) {
+// 
+  //  cout << " - ";   	 
+  int k=(*t)(0) ?  ((  (*t)(1) ? ( (*t)(2) ? -1 : 2) : 1  )) : 0;
+  int dir=0;
+  assert(k>=0);
+  int kkk=0;  
+  Icoor2 IJ_IA,IJ_AJ;
+  TriangleAdjacent edge(t,OppositeEdge[k]);          
+  for (;;edge = dir >0 ? Next(Adj(Next(edge))) : Previous(Adj(Previous(edge)))) 
+   {  
+   
+    assert(kkk++<1000);      
+    Vertex  &vI =  *edge.EdgeVertex(0);
+    Vertex  &vJ =  *edge.EdgeVertex(1);
+    I2 I=vI, J=vJ, IJ= J-I;
+    IJ_IA = (IJ ,(A-I));
+    //   cout << A << vI.i << vJ.i << edge << " " <<  IJ_IA << " dir " << dir <<endl;
+    if (IJ_IA<0) {
+     if (dir>0) {a=1;b=0;return edge;}// change of signe => I
+     else {dir=-1;
+        continue;}};// go in direction i 
+    IJ_AJ = (IJ ,(J-A));
+    if (IJ_AJ<0) {
+    if(dir<0)  {a=0;b=1;return edge;}            
+    else {dir = 1;
+       continue;}}// go in direction j
+    double IJ2 = IJ_IA + IJ_AJ;
+    assert(IJ2);
+    a= IJ_AJ/IJ2;
+    b= IJ_IA/IJ2;
+    //    cout<< "CloseBoundaryEdge a = " << a << " b= " << b << endl;
+    return edge;
+  } 
+}
+
+TriangleAdjacent Triangle::FindBoundaryEdge(int i) const
+{
+  // turn around  the vertex ns[i] also call  s
+#ifdef DEBUG
+  register Vertex * s  =  ns[i];
+#endif
+  Triangle   *t = (Triangle *) this , *ttc;
+  int k=0,j = EdgesVertexTriangle[i][0],jc;
+  int exterieur  = !link  ;
+  
+  do 
+    {
+      int exterieurp = exterieur;
+      k++; 
+#ifdef DEBUG
+      assert( s == & (*t)[VerticesOfTriangularEdge[j][1]] );
+#endif
+      ttc =  t->at[j];
+      exterieur = !ttc->link;
+      if (exterieur+exterieurp == 1) 
+	return TriangleAdjacent(t,j);
+      jc = NextEdge[t->aa[j]&3];
+      t = ttc;
+      j = NextEdge[jc];
+      assert(k<2000);
+    } while ( (this!= t)); 
+  return TriangleAdjacent(0,0);
+ 
+}
+
+
+TriangleAdjacent CloseBoundaryEdgeV2(I2 C,Triangle *t, double &a,double &b) 
+{ 
+ // walk around the vertex 
+ // version 2 for remove the probleme if we fill the hole
+  //int bug=1;
+  //  Triangle *torigine = t;
+  // restart:
+  //   int dir=0;
+  assert(t->link == 0);
+  // to have a starting edges 
+  // try the 3 edge bourna-- in case of internal hole 
+  // and choice  the best 
+  // 
+  // 
+  // the probleme is in case of  the fine and long internal hole
+  // for exemple neart the training edge of a wing
+  // 
+  Vertex * s=0,*s1=0, *s0=0;
+  Icoor2 imax = MaxICoor22;
+  Icoor2 l0 = imax,l1 = imax;
+  double dd2 =  imax;// infinity
+  TriangleAdjacent er; 
+  int  cas=-2;
+  for (int j=0;j<3;j++)
+    { 
+      TriangleAdjacent ta=t->FindBoundaryEdge(j);
+      if  (! (Triangle *) ta) continue;
+      s0 = ta.EdgeVertex(0);
+      s1 = ta.EdgeVertex(1);
+      I2 A = * s0;
+      I2 B = *ta.EdgeVertex(1);
+      I2 AB = B-A,AC=C-A,BC=B-C;
+      Icoor2  ACAC = (AC,AC), BCBC = (BC,BC);
+      Icoor2  AB2  =   Norme2_2(AB); //  ||AB||^2
+      Icoor2  ABAC  =   (AB,AC);         //  AB.AC|
+      
+      double d2;
+      if ( ABAC < 0 )   // DIST A
+        {
+           if ( (d2=(double) ACAC)  <  dd2) 
+             {
+	       //  cout << " A "  << d2  << " " <<  dd2;
+               er = ta;
+               l0 = ACAC;
+               l1 = BCBC;
+               cas = 0;
+               s = s0;
+             }
+        }
+      else if (ABAC > AB2)  // DIST B
+        {
+           if ( (d2=(double) BCBC)  <  dd2) 
+             {
+	       // cout << " B "  << d2  << " " <<  dd2;
+               dd2 = d2;
+               er = Adj(ta); // other direction
+               l0 = BCBC;
+               l1 = ACAC;
+               cas = 1;
+               s = s1;
+             }
+        }
+      else  // DIST AB
+        { 
+
+          double det_2 =  (double) Det(AB,AC); 
+          det_2 *= det_2; // square of area*2 of triangle ABC
+          d2 = det_2/ (double) AB2; // hauteur^2 in C of of triangle ABC      
+	  //	  cout << " AB " << d2 << " " << dd2 
+	  //      << " " << CurrentTh->Number(ta.EdgeVertex(0)) 
+	  //     << " " << CurrentTh->Number(ta.EdgeVertex(1)) << " " ;
+
+          if (d2 < dd2) 
+	       {
+	         dd2 = d2;
+	         er = ta;
+	         l0 = (AC,AC);
+	         l1 = (BC,BC);
+	         s = 0;
+                 cas = -1;
+		 //	 cout << " ABAC " <<  ABAC << " ABAC " << ABAC
+		 //	      << " AB2 " << AB2 << endl;
+		 b = ((double) ABAC/(double) AB2);
+		 a = 1 - b;
+	       }
+        }
+     }
+   assert(cas !=-2);
+   // l1 = ||C s1||  , l0 = ||C s0||
+   // where s0,s1 are the vertex of the edge er
+
+   if ( s) 
+     { 
+       t=er;
+       TriangleAdjacent edge(er); 
+       
+       int kkk=0;  
+       int linkp = t->link == 0;
+       
+       Triangle * tt=t=edge=Adj(Previous(edge));
+       //  cout << CurrentTh->Number(t) << " " << linkp << endl;
+       do  {  // loop around vertex s
+	 
+	 assert(edge.EdgeVertex(0)==s && kkk++<10000);
+	 
+	 int link = tt->link == 0;
+	 //	 cout << CurrentTh->Number(tt) << " " << link << " " << CurrentTh->Number(s) 
+	 //	      << " " << CurrentTh->Number(er.EdgeVertex(0)) 
+	 //	      << " " << CurrentTh->Number(er.EdgeVertex(1)) 
+	 //	      << " " << CurrentTh->Number(edge.EdgeVertex(0)) 
+	 //	      << " " << CurrentTh->Number(edge.EdgeVertex(1)) 
+	 //	      <<  endl;
+	 if ((link + linkp) == 1) 
+	   { // a boundary edge 
+	     Vertex * st = edge.EdgeVertex(1);
+	     I2 I=*st;
+	     Icoor2  ll = Norme2_2 (C-I);
+	     if (ll < l1) {  // the other vertex is neart 
+	       s1=st;
+	       l1=ll;
+	       er = edge;
+	       if(ll<l0) { // change of direction --
+		 s1=s;
+		 l1=l0;
+		 s=st;
+		 l0=ll;
+		 t=tt;
+		 edge=Adj(edge);
+		 link=linkp;
+		 er = edge;
+	       }
+	     }
+	   }
+	 
+	 linkp=link;
+	 edge=Adj(Previous(edge));
+	 tt = edge;
+       } while (t!=tt);
+
+       assert((Triangle *) er);
+       I2 A((I2)*er.EdgeVertex(0));
+       I2 B((I2)*er.EdgeVertex(1));
+       I2 AB=B-A,AC=C-A,CB=B-C;
+       double aa =  (double) (AB,AC);
+       double bb =  (double) (AB,CB);
+       //  cout << " " << aa << " " << bb 
+       //    << " " << CurrentTh->Number(er.EdgeVertex(0)) 
+       //	    << " " << CurrentTh->Number(er.EdgeVertex(1)) ;
+       if (aa<0)       a=1,b=0;
+       else if(bb<0)   a=0,b=1;
+       else  
+	 {
+	   a  = bb/(aa+bb);
+	   b  = aa/(aa+bb);
+	 }
+     }
+   
+   //   cout <<" return= " <<  CurrentTh->Number(er.EdgeVertex(0)) << " " 
+   //	<<  CurrentTh->Number(er.EdgeVertex(1)) << " " << a 
+   //	<< " " << b <<" " << l0 << " " <<l1 <<endl;
+   return er;
+} 
+
+
+
+Metric Triangles::MetricAt  (const R2 & A) const
+  { //if ((vertices <= &v) && (vertices < v+nbv)) return v.m;
+    I2 a = toI2(A);
+    Icoor2 deta[3];
+    Triangle * t =FindTriangleContening(a,deta);
+    if (t->det <0) { // outside
+      double ba,bb;
+      TriangleAdjacent edge= CloseBoundaryEdge(a,t,ba,bb) ;
+      return Metric(ba,*edge.EdgeVertex(0),bb,*edge.EdgeVertex(1));}
+     else { // inside
+      Real8   aa[3];
+      Real8 s = deta[0]+deta[1]+deta[2];
+      aa[0]=deta[0]/s;
+      aa[1]=deta[1]/s;
+      aa[2]=deta[2]/s;
+      return Metric(aa,(*t)[0],(*t)[1],(*t)[2]);
+     }
+  }
+
+
+void ListofIntersectionTriangles::SplitEdge(const Triangles & Bh,
+       const R2 &A,const R2  &B,int nbegin)
+{ //  SplitEdge
+  //  if(SHOW)  cout << " splitedge " << A << B << " " <<  nbegin << endl;
+  Triangle *tbegin, *t;
+
+  Icoor2 deta[3], deti,detj;
+  Real8 ba[3];
+  int nbt =0,ifirst=-1,ilast;
+  int i0,i1,i2;
+  int ocut,i,j,k=-1;
+  //  int OnAVertices =0;
+  Icoor2 dt[3];
+  I2 a = Bh.toI2(A) ,b= Bh.toI2(B);// compute  the Icoor a,b
+  I2 vi,vj;  
+  int iedge =-1;// not a edge
+
+  if(nbegin)  {// optimisation 
+    // we suppose  knowing the starting  triangle
+    t=tbegin=lIntTria[ilast=(Size-1)].t;
+    if (tbegin->det>=0) 
+    ifirst = ilast;}  
+  else {// not optimisation 
+    init();
+    t=tbegin = Bh.FindTriangleContening(a,deta);
+    //    if(SHOW) cout <<t << " " << Real8(deta[0])/t->det<< " " << Real8(deta[1])/t->det
+    //		  << " " << Real8(deta[2])/t->det << endl;
+    if( t->det>=0)
+      ilast=NewItem(t,Real8(deta[0])/t->det,Real8(deta[1])/t->det,Real8(deta[2])/t->det);
+    else 
+     {// find the nearest boundary edge  of the vertex A
+      // find a edge or such normal projection a the edge IJ is on the edge
+      //   <=> IJ.IA >=0 && IJ.AJ >=0
+      ilast=ifirst;
+      double ba,bb;
+      TriangleAdjacent edge=CloseBoundaryEdge(a,t,ba,bb);
+      Vertex & v0 = *edge.EdgeVertex(0), & v1 = *edge.EdgeVertex(1);
+      NewItem(A,Metric(ba,v0,bb,v1));
+      t=edge;
+      // test if the point b is in the same side
+      if (det(v0.i,v1.i,b)>=0) {
+	//cout << " All the edge " << A << B << endl;
+	TriangleAdjacent edge=CloseBoundaryEdge(a,t,ba,bb);
+	Vertex & v0 = *edge.EdgeVertex(0), & v1 = *edge.EdgeVertex(1);
+	NewItem(A,Metric(ba,v0,bb,v1));
+	return;
+      }
+     } // find the nearest boundary edge  of the vertex A
+   } // end not optimisation 
+  if (t->det<0) {  // outside departure
+    while (t->det <0) { // intersection boundary edge and a,b,
+      k=(*t)(0) ?  ((  (*t)(1) ? ( (*t)(2) ? -1 : 2) : 1  )) : 0;
+      assert(k>=0);
+      ocut = OppositeEdge[k];
+      i=VerticesOfTriangularEdge[ocut][0];
+      j=VerticesOfTriangularEdge[ocut][1];
+      vi=(*t)[i];
+      vj=(*t)[j];
+      deti = bamg::det(a,b,vi);
+      detj = bamg::det(a,b,vj);
+     //  if(SHOW) {  penthickness(3);
+// 	Move(vi);Line(vj);CurrentTh->inquire();penthickness(1);
+//         cout << Bh.Number(tbegin) << " " << Bh.Number(t) << " i= " << i <<" j= " <<  j << " k=" << k 
+//       	   << " deti= " << deti << " detj= " << detj 
+// 	     << " v = " << Bh.Number((*t)[i]) << (*t)[i].r <<  " " << Bh.Number((*t)[j]) << (*t)[j].r  << endl;}
+      if (deti>0) // go to  i direction on gamma
+	ocut = PreviousEdge[ocut];      
+      else if (detj<=0) // go to j direction on gamma
+	ocut = NextEdge[ocut];         
+      TriangleAdjacent tadj =t->Adj(ocut);
+      t = tadj;
+      iedge= tadj; 
+      if (t == tbegin) { // 
+	double ba,bb;
+	if (verbosity>7) 
+	  cout << "       SplitEdge: All the edge " << A << B << nbegin <<  det(vi,vj,b) 
+	       << " deti= " << deti <<  " detj=" <<detj << endl;
+	TriangleAdjacent edge=CloseBoundaryEdge(a,t,ba,bb);
+	Vertex & v0 = *edge.EdgeVertex(0), & v1 = *edge.EdgeVertex(1);
+	NewItem(A,Metric(ba,v0,bb,v1));
+	return;
+	/*
+	cerr << nbegin <<  det(vi,vj,b) << " deti= " << deti <<  " detj=" <<detj << endl;
+	cerr << "SplitEdge on boucle A" << A << " B = " << B << endl;
+
+#ifdef DRAWING
+	reffecran();
+	Bh.Draw();
+        penthickness(5);
+	Move(A);
+	Line(B);
+        penthickness(1);
+
+	Bh.inquire();
+        penthickness(5);
+	Move(A);
+	Line(B);
+        penthickness(1);
+	Bh.inquire();
+#endif	
+	MeshError(997);*/
+      }
+    } //  end while (t->det <0)
+    // theoriticaly we have: deti =<0 and detj>0
+  
+      // computation of barycentric coor
+    // test if the point b is on size on t
+    // we revert vi,vj because vi,vj is def in Adj triangle
+    if ( det(vi,vj,b)>=0) {
+      if (verbosity>7)
+      cout << "       SplitEdge: all AB outside " << A << B << endl;
+      t=tbegin;
+      Real8 ba,bb;
+      TriangleAdjacent edge=CloseBoundaryEdge(b,t,ba,bb);
+      NewItem(B,Metric(ba,*edge.EdgeVertex(0),bb,*edge.EdgeVertex(1)));
+      return;
+    }
+    else
+      {
+	k = OppositeVertex[iedge];
+	i=VerticesOfTriangularEdge[iedge][0];
+	j=VerticesOfTriangularEdge[iedge][1];
+	Real8 dij = detj-deti;
+	assert(i+j+k == 0 + 1 +2);
+	ba[j] =  detj/dij;
+	ba[i] = -deti/dij;
+	ba[k] = 0;
+// 	if(SHOW) cout << i << " " << j << " " << k << " " << ba[i] << " " << ba[j] << endl;
+	ilast=NewItem(t,ba[0],ba[1],ba[2]); }
+  }  //  outside departure
+
+     
+   
+  // recherche the intersection of [a,b] with Bh Mesh.
+  // we know  a triangle ta contening the vertex a
+  // we have 2 case for intersection [a,b] with a edge [A,B] of Bh
+  // 1) the intersection point is in ]A,B[
+  // 2)                        is A or B
+  // first version --- 
+  for (;;) {
+    //    t->Draw();
+    if (iedge < 0) {
+      i0 =0;i1=1;i2=2;
+      dt[0] =bamg::det(a,b,(*t)[0]);
+      dt[1] =bamg::det(a,b,(*t)[1]);
+      dt[2] =bamg::det(a,b,(*t)[2]);}
+    else {
+      i2 = iedge;
+      i0 = NextEdge[i2];
+      i1 = NextEdge[i0]; 
+      dt[VerticesOfTriangularEdge[iedge][0]] = detj;// we revert i,j because
+      dt[VerticesOfTriangularEdge[iedge][1]] = deti;// we take the Triangle by the other side
+      dt[iedge] = det(a,b,(*t)[OppositeVertex[iedge]]);}
+    
+    // so we have just to see the transition from - to + of the det0..2 on edge of t
+    // because we are going from a to b
+    if       ((dt[i=VerticesOfTriangularEdge[i0][0]] <  0) &&
+              ( dt[j=VerticesOfTriangularEdge[i0][1]] > 0))
+      ocut =i0;
+    else  if ((dt[i=VerticesOfTriangularEdge[i1][0]] <  0) &&
+              (dt[j=VerticesOfTriangularEdge[i1][1]] >  0))
+      ocut =i1;
+    else  if ((dt[i=VerticesOfTriangularEdge[i2][0]] <  0) && 
+              (dt[j=VerticesOfTriangularEdge[i2][1]] >  0))
+      ocut =i2;
+    else if   ((dt[i=VerticesOfTriangularEdge[i0][0]] == 0) &&
+              ( dt[j=VerticesOfTriangularEdge[i0][1]] >  0))
+      ocut =i0;
+    else  if ((dt[i=VerticesOfTriangularEdge[i1][0]] == 0) &&
+              (dt[j=VerticesOfTriangularEdge[i1][1]] >  0))
+      ocut =i1;
+    else  if ((dt[i=VerticesOfTriangularEdge[i2][0]] == 0) && 
+              (dt[j=VerticesOfTriangularEdge[i2][1]] >  0))
+      ocut =i2;
+    else if   ((dt[i=VerticesOfTriangularEdge[i0][0]] <  0) &&
+              ( dt[j=VerticesOfTriangularEdge[i0][1]] == 0))
+      ocut =i0;
+    else  if ((dt[i=VerticesOfTriangularEdge[i1][0]] <  0) &&
+              (dt[j=VerticesOfTriangularEdge[i1][1]] == 0))
+      ocut =i1;
+    else  if ((dt[i=VerticesOfTriangularEdge[i2][0]] <  0) && 
+              (dt[j=VerticesOfTriangularEdge[i2][1]] == 0))
+      ocut =i2;
+    else { //  On a edge (2 zero)
+      k =0;
+      if (dt[0]) ocut=0,k++; 
+      if (dt[1]) ocut=1,k++; 
+      if (dt[2]) ocut=2,k++;
+      if(k == 1) {
+        if (dt[ocut] >0) // triangle upper AB
+          ocut = NextEdge[ocut];
+        i= VerticesOfTriangularEdge[ocut][0];
+        j= VerticesOfTriangularEdge[ocut][1];
+      }
+      else  {
+        cerr << " Bug Split Edge " << endl;
+        cerr << " dt[0]= " << dt[0] 
+             << " dt[1]= " << dt[1] 
+             << " dt[2]= "<< dt[2] << endl;
+        cerr << i0 << " " << i1 << " " << i2 << endl;
+        cerr << " A = " << A << " B= " << B << endl;
+        cerr << " Triangle t = " <<  *t << endl;
+        cerr << (*t)[0] << (*t)[1] << (*t)[0] << endl;
+        cerr << " nbt = " << nbt << endl;
+        MeshError(100);}}
+    
+    k = OppositeVertex[ocut];
+
+    Icoor2 detbij = bamg::det((*t)[i],(*t)[j],b);
+
+    
+    if (detbij >= 0) { //we find the triangle contening b
+      dt[0]=bamg::det((*t)[1],(*t)[2],b);
+      dt[1]=bamg::det((*t)[2],(*t)[0],b);
+      dt[2]=bamg::det((*t)[0],(*t)[1],b);
+#ifdef DEBUG 
+      assert(dt[0] >= 0);
+      assert(dt[1] >= 0);
+      assert(dt[2] >= 0);
+#endif
+      Real8 dd = t->det;
+      NewItem(t,dt[0]/dd,dt[1]/dd,dt[2]/dd);      
+      return ;}
+    else { // next triangle by  adjacent by edge ocut 
+      deti = dt[i];
+      detj = dt[j];
+      Real4 dij = detj-deti;
+      ba[i] =  detj/dij;
+      ba[j] = -deti/dij;
+      ba[3-i-j ] = 0;
+      ilast=NewItem(t, ba[0],ba[1],ba[2]);      
+      
+      TriangleAdjacent ta =t->Adj(ocut);
+      t = ta;
+      iedge= ta; 
+      if (t->det <= 0)  {
+        double ba,bb;
+        TriangleAdjacent edge=CloseBoundaryEdge(b,t,ba,bb);
+        NewItem(B,Metric(ba,*edge.EdgeVertex(0),bb,*edge.EdgeVertex(1)));
+	// 	cout << " return " << ba << " " << bb << endl;
+	// ajoute le 03 frev 1997 par F. hecht
+        return;
+        }
+     }// we  go outside of omega 
+  } // for(;;)
+ 
+   
+} // routine SplitEdge
+
+
+int  ListofIntersectionTriangles::NewItem(Triangle * tt,Real8 d0,Real8 d1,Real8 d2) { 
+  register int n;
+  R2 x(0,0);
+  if ( d0) x =      (*tt)[0].r * d0;
+  if ( d1) x = x +  (*tt)[1].r * d1;
+  if ( d2) x = x +  (*tt)[2].r * d2;
+  // newer add same point 
+  if(!Size ||  Norme2_2(lIntTria[Size-1].x-x)) {
+    if (Size==MaxSize) ReShape();
+    lIntTria[Size].t=tt;
+    lIntTria[Size].bary[0]=d0;
+    lIntTria[Size].bary[1]=d1;
+    lIntTria[Size].bary[2]=d2;
+    lIntTria[Size].x = x;
+    Metric m0,m1,m2;
+    register Vertex * v;
+    if ((v=(*tt)(0))) m0    = v->m;
+    if ((v=(*tt)(1))) m1    = v->m;
+    if ((v=(*tt)(2))) m2    = v->m;
+    lIntTria[Size].m =  Metric(lIntTria[Size].bary,m0,m1,m2);
+#ifdef DEBUG1
+    if(SHOW) { cout << "SHOW       ++ NewItem =" << Size << x ;
+    cout << " " << d0 << " " << d1 << " " << d2 <<endl;}
+#endif
+    n=Size++;}
+  else n=Size-1;
+  return n;
+}
+int ListofIntersectionTriangles::NewItem(R2 A,const Metric & mm) {  
+  register int n;
+  if(!Size ||  Norme2_2(lIntTria[Size-1].x-A)) {
+    if (Size==MaxSize) ReShape();
+    lIntTria[Size].t=0;
+    lIntTria[Size].x=A;
+    lIntTria[Size].m=mm;
+#ifdef DEBUG1
+    if (SHOW)  cout << "SHOW       ++ NewItem A" << Size << A << endl;
+#endif
+    n=Size++;
+   }
+  else  n=Size-1;
+ return  n; 
+}
+
+Real8  ListofIntersectionTriangles::Length()
+{
+  //  cout << " n= " << Size << ":" ;
+  assert(Size>0);
+  // computation of the length      
+  R2 C;
+  Metric Mx,My;
+  int ii,jj;
+  R2 x,y,xy;
+  
+  SegInterpolation *SegI=lSegsI;
+  SegI=lSegsI;
+  lSegsI[NbSeg].last=Size;// improvement 
+  
+  int EndSeg=Size;
+     
+  y = lIntTria[0].x;
+  Real8 sxy, s = 0;
+  lIntTria[0].s =0;
+  SegI->lBegin=s;
+
+  for (jj=0,ii=1;ii<Size;jj=ii++) 
+    {  
+      // seg jj,ii
+      x=y;
+      y = lIntTria[ii].x;
+      xy = y-x;
+      Mx = lIntTria[ii].m;
+      My = lIntTria[jj].m;
+      //      Real8 &sx=  lIntTria[ii].sp; // previous seg
+      //  Real8 &sy=  lIntTria[jj].sn; // next seg
+      //      sx = Mx(xy);
+      //      sy = My(xy);
+      //   sxy = (Mx(xy)+ My(xy))/2.0;
+      sxy =  LengthInterpole(Mx,My,xy);
+      s += sxy;
+      lIntTria[ii].s = s;
+      if (ii == EndSeg) 
+	SegI->lEnd=s,
+	  SegI++,
+	  EndSeg=SegI->last,
+	  SegI->lBegin=s;
+      
+      //    cout << ii << " " << jj << x<< y <<xy << s <<  lIntTria[ii].m  ;
+    }
+  len = s;
+  SegI->lEnd=s;
+
+  //  cout << " len= " << s << endl;
+  return s;
+}
+
+Int4 ListofIntersectionTriangles::NewPoints(Vertex * vertices,Int4 & nbv,Int4  nbvx)
+{
+
+  const Int4 nbvold = nbv;
+  Real8 s = Length();
+  if (s <  1.5 ) return 0;
+  //////////////////////   
+  int ii = 1 ;
+  R2 y,x;
+  Metric My,Mx ;
+  Real8 sx =0,sy;
+  int nbi = Max(2,(int) (s+0.5));
+  Real8 sint = s/nbi;
+  Real8 si = sint;
+
+  int EndSeg=Size;
+  SegInterpolation *SegI=0;
+  if (NbSeg) 
+    SegI=lSegsI,EndSeg=SegI->last;
+  
+  for (int k=1;k<nbi;k++)
+    {
+      while ((ii < Size) && ( lIntTria[ii].s <= si )) 
+	if (ii++ == EndSeg) 
+	  SegI++,EndSeg=SegI->last;
+
+      int ii1=ii-1;
+      x  =lIntTria[ii1].x;
+      sx =lIntTria[ii1].s;
+      Metric Mx=lIntTria[ii1].m;
+#ifdef DEBUG    
+      double lx = lIntTria[ii-1].sn;
+#endif
+      y  =lIntTria[ii].x;
+      sy =lIntTria[ii].s;
+      Metric My=lIntTria[ii].m;
+#ifdef DEBUG    
+      double ly =lIntTria[ii].sp;  
+      assert( sx <= si);
+      assert( si <= sy);
+      assert( sy != sx);
+#endif 
+
+      Real8 lxy = sy-sx;
+      Real8 cy = abscisseInterpole(Mx,My,y-x,(si-sx)/lxy);
+      
+      R2 C;
+      Real8 cx = 1-cy;
+      C = SegI ? SegI->F(si): x * cx + y *cy;
+
+    si += sint;
+    if ( nbv<nbvx) {
+      vertices[nbv].r = C;
+      vertices[nbv++].m = Metric(cx,lIntTria[ii-1].m,cy,lIntTria[ii].m);
+      if((verbosity/100%10)==2)
+      cout << "   -- Add point " << nbv-1 << " " << vertices[nbv-1] << " " << vertices[nbv-1].m << endl;
+
+#ifdef DEBUG
+      if(k>1) {
+	R2 AB = vertices[nbv-2].r - vertices[nbv-1].r ;
+	Real8 dp = LengthInterpole(vertices[nbv-2].m,vertices[nbv-1].m,AB);
+	if (dp > 1.6) {
+	  cerr << "PB calcul new Int.  points trop loin l=" << dp << " v=" << nbv-1 << " " << nbv-2 <<Mx<<My<<y-x << endl;
+	}
+	}
+#endif
+    }
+    else return nbv-nbvold;
+  }
+  return nbv-nbvold;
+}
+
+int SwapForForcingEdge(Vertex   *  & pva ,Vertex  * &   pvb ,
+      TriangleAdjacent & tt1,Icoor2 & dets1, Icoor2 & detsa,Icoor2 & detsb, int & NbSwap)
+{ // l'arete ta coupe l'arete pva pvb
+  // de cas apres le swap sa coupe toujours
+  // on cherche l'arete suivante 
+  // on suppose que detsa >0 et detsb <0
+  // attention la routine echange pva et pvb 
+
+   if(tt1.Locked()) return 0; // frontiere croise 
+
+  TriangleAdjacent tt2 = Adj(tt1);
+  Triangle *t1=tt1,*t2=tt2;// les 2 triangles adjacent
+  Int1 a1=tt1,a2=tt2;// les 2 numero de l arete dans les 2 triangles
+  assert ( a1 >= 0 && a1 < 3 );
+   
+  Vertex & sa= (* t1)[VerticesOfTriangularEdge[a1][0]];
+  Vertex & s1= (*t1)[OppositeVertex[a1]];
+  Vertex & s2= (*t2)[OppositeVertex[a2]];
+  
+
+  Icoor2 dets2 = det(*pva,*pvb,s2);
+
+#ifdef DEBUG
+  Vertex & sb= (*t1)[VerticesOfTriangularEdge[a1][1]];
+  Icoor2 wdets1 = det(*pva,*pvb,s1);  
+  Icoor2 wdetsa = det(*pva,*pvb,sa);
+  Icoor2 wdetsb = det(*pva,*pvb,sb);
+  assert(wdets1 == dets1);
+  assert(wdetsa == detsa);
+  assert(wdetsb == detsb);
+#endif
+  
+  Icoor2 det1=t1->det , det2=t2->det ;
+#ifdef DEBUG  
+  assert(det1>0 && det2 >0);
+  Icoor2 ddet1 = det((*t1)[0],(*t1)[1],(*t1)[2]);
+  Icoor2 ddet2 = det((*t2)[0],(*t2)[1],(*t2)[2]);
+   if ((det1 != ddet1) || (det2 != ddet2) )
+    {
+      assert(det1 == ddet1);
+      assert(det2 == ddet2);
+     }
+   Icoor2 detvasasb = det(*pva,sa,sb);
+   Icoor2 detvbsasb = det(*pvb,sa,sb);
+   if (  CurrentTh && !  ( ( (detvasasb <= 0) && (detvbsasb >= 0)) || ( (detvasasb >= 0) && (detvbsasb <= 0)))) 
+     {
+       cout << " detvasasb =" <<  detvasasb << "detvbsasb = " <<  detvbsasb 
+	    << " " << pva << " " << pvb << " "  <<CurrentTh <<endl;
+#ifdef DRAWING1
+       reffecran();
+       CurrentTh->Draw();
+       penthickness(10);
+       pva->MoveTo();pvb->LineTo();
+       penthickness(1);
+       CurrentTh->inquire();
+#endif       
+   }
+     assert( ( (detvasasb <= 0) && (detvbsasb >= 0)) || ( (detvasasb >= 0) && (detvbsasb <= 0)));
+#endif
+
+  Icoor2 detT = det1+det2;
+  assert((det1>0 ) && (det2 > 0));
+  assert ( (detsa < 0) && (detsb >0) ); // [a,b] cut infinite line va,bb
+  Icoor2 ndet1 = bamg::det(s1,sa,s2);
+  Icoor2 ndet2 = detT - ndet1;
+
+  int ToSwap =0; //pas de swap
+  if ((ndet1 >0) && (ndet2 >0)) 
+    { // on peut swaper  
+      if ((dets1 <=0 && dets2 <=0) || (dets2 >=0 && detsb >=0))
+        ToSwap =1; 
+      else // swap alleatoire 
+        if (BinaryRand()) 
+          ToSwap =2; 
+    }
+#ifdef DEBUG
+  if (ForDebugging) {
+    cerr << "swap = " << ToSwap << " ndet1 " << ndet1 << ", ndet2 " << ndet2 << "det1  " << det1 << " det2 " <<  det2  
+	 << " if1 = " << ((ndet1 >0) && (ndet2 >0)) 
+	 << " if2 = " << ((dets1 <=0 && dets2 <=0) || (dets2 >=0 && detsb >=0)) << endl;
+#ifdef DRAWING
+  couleur(0);
+  t1->Draw();
+  t2->Draw();
+#endif
+  }
+#endif
+  if (ToSwap) NbSwap++,
+     bamg::swap(t1,a1,t2,a2,&s1,&s2,ndet1,ndet2);
+  
+#ifdef DEBUG
+  if (ForDebugging) {
+#ifdef DRAWING
+  couleur(4);
+  t1->Draw();
+  t2->Draw();
+  rattente(1);
+#endif
+  }
+#endif
+  int ret=1;
+
+  if (dets2 < 0) {// haut
+    dets1 = ToSwap ? dets1 : detsa ;
+    detsa = dets2; 
+    tt1 =  Previous(tt2) ;}
+  else if (dets2 > 0){// bas 
+    dets1 = ToSwap ? dets1 : detsb ;
+    detsb = dets2;
+    //xxxx tt1 = ToSwap ? tt1 : Next(tt2);
+    if(!ToSwap) tt1 =  Next(tt2);
+    }
+  else { // changement de sens 
+     if (ForDebugging)  cout << "changement de sens" << endl;
+    ret = -1;
+    Exchange(pva,pvb);
+    Exchange(detsa,detsb);
+    Exchange(dets1,dets2);
+    Exchange(tt1,tt2);
+    dets1=-dets1;
+    dets2=-dets2;
+    detsa=-detsa;
+    detsb=-detsb;
+
+    if (ToSwap) 
+      if (dets2 < 0) {// haut
+        dets1 = (ToSwap ? dets1 : detsa) ;
+        detsa = dets2; 
+        tt1 =  Previous(tt2) ;}
+      else if (dets2 > 0){// bas 
+        dets1 = (ToSwap ? dets1 : detsb) ;
+        detsb =  dets2;
+        if(!ToSwap) tt1 =  Next(tt2);
+       }
+      else {// on a fin ???
+        tt1 = Next(tt2);
+        ret =0;}
+
+  }
+  return ret;
+}
+
+int ForceEdge(Vertex &a, Vertex & b,TriangleAdjacent & taret)  
+{ 
+#ifdef DEBUG
+ restart: // for debug 
+#endif
+  int NbSwap =0;
+  assert(a.t && b.t); // the 2 vertex is in a mesh 
+  int k=0;
+  taret=TriangleAdjacent(0,0); // erreur 
+  
+  TriangleAdjacent tta(a.t,EdgesVertexTriangle[a.vint][0]);
+  Vertex   *v1, *v2 = tta.EdgeVertex(0),*vbegin =v2;
+  // we turn around a in the  direct sens  
+   
+  Icoor2 det2 = v2 ? det(*v2,a,b): -1 , det1;
+  if(v2) // normal case 
+    det2 = det(*v2,a,b);
+  else { // no chance infini vertex try the next
+    tta= Previous(Adj(tta));
+    v2 = tta.EdgeVertex(0);
+    vbegin =v2;
+    assert(v2);
+    det2 = det(*v2,a,b);
+ //   cout << " No Change try the next" << endl;
+  }
+
+#ifdef DRAWING1
+  a.MoveTo();b.LineTo();
+#endif
+
+  while (v2 != &b) {
+    TriangleAdjacent tc = Previous(Adj(tta));    
+    v1 = v2; 
+    v2 = tc.EdgeVertex(0);
+    det1 = det2;
+#ifdef DEBUG
+    assert( v1 ==  tta.EdgeVertex(0));
+    assert( &a ==  tc.EdgeVertex(1) );
+#endif
+    det2 =  v2 ? det(*v2,a,b): det2; 
+    
+    if((det1 < 0) && (det2 >0)) { 
+      // try to force the edge 
+      Vertex * va = &a, *vb = &b;
+      tc = Previous(tc);
+      assert ( v1 && v2);
+      Icoor2 detss = 0,l=0,ks;
+      // cout << "Real ForcingEdge " << *va << *vb << detss << endl;
+#ifdef DEBUG
+      Icoor2 dettt1 =  det(*v1,a,b);
+      Icoor2 dettt2 =  det(*v2,a,b);
+
+      if (!(dettt1==det1 && dettt2==det2))
+	{
+	  assert(ForDebugging==0);
+          ForDebugging=1;
+	  goto restart;
+	}
+	
+#endif 
+      while ((ks=SwapForForcingEdge(  va,  vb, tc, detss, det1,det2,NbSwap)))
+	if(l++ > 10000000) {
+	  cerr << " Loop in forcing Egde AB" 
+               <<"\n vertex A " << a 
+               <<"\n vertex B " <<  b 
+               <<"\n nb de swap " << NbSwap 
+               <<"\n nb of try  swap too big = " <<  l << " gearter than " <<  1000000 << endl;
+   
+         if ( CurrentTh ) 
+            cerr << " vertex number " << CurrentTh->Number(a) << " " <<  CurrentTh->Number(b) << endl;
+#ifdef DEBUG
+	  ForDebugging = 1;
+#endif
+#ifdef DRAWING1
+          if (  CurrentTh ) {
+	    reffecran();
+            couleur(6);
+	    CurrentTh->Draw();
+            couleur(1);
+	    penthickness(10);
+	    a.MoveTo();b.LineTo();
+	    penthickness(1);
+	    CurrentTh->inquire();
+            couleur(6);
+	    l=0;
+	    reffecran();
+            while (ks=SwapForForcingEdge(  va,  vb, tc, detss, det1,det2,NbSwap) && (l++ < 1000))
+             cerr << " " << CurrentTh->Number(tc.EdgeVertex(0))<<" " <<CurrentTh->Number(tc.EdgeVertex(1)) << " ";
+	  }
+#endif	  
+	  MeshError(990);
+	}
+      Vertex *aa = tc.EdgeVertex(0), *bb = tc.EdgeVertex(1);
+      if (( aa == &a ) && (bb == &b) ||  (bb ==  &a ) && (aa == &b)) {
+	tc.SetLock();
+	a.Optim(1,0);
+	b.Optim(1,0);
+	taret = tc;
+	return NbSwap;
+      }
+      else 
+      {
+	  taret = tc;
+	  return -2; // error  boundary is crossing
+/*	  cerr << "Fatal Error  boundary is crossing  ";
+	  if(CurrentTh)
+	  {
+	      cerr << " edge:  [" << CurrentTh->Number(a) << ", " << CurrentTh->Number(b) <<  " ] and [ ";
+	      cerr    << CurrentTh->Number(aa) << " " << CurrentTh->Number(bb) << " ] " << endl;
+	  }
+	  MeshError(991);
+*/	  
+      }
+    }
+    tta = tc;
+    assert(k++<2000);
+    if ( vbegin == v2 ) return -1;// error 
+  }
+
+  tta.SetLock();
+  taret=tta;
+  a.Optim(1,0);
+  b.Optim(1,0);
+  return NbSwap; 
+}
+
+
+int Triangle::swap(Int2 a,int koption){
+#ifdef DEBUG
+  if(a &4 ) return 0;// arete lock 
+  int munswap1 = a/4;
+  a &=3;
+#else
+ if(a/4 !=0) return 0;// arete lock or MarkUnSwap
+#endif
+
+  register Triangle *t1=this,*t2=at[a];// les 2 triangles adjacent
+  register Int1 a1=a,a2=aa[a];// les 2 numero de l arete dans les 2 triangles
+#ifdef DEBUG
+  if(a2 & 4) return 0; // arete lock
+  int munswap2 = a2/4;
+  a2 &= 3;
+#else
+  if(a2/4 !=0) return 0; // arete lock or MarkUnSwap
+#endif
+  
+  register Vertex  *sa=t1->ns[VerticesOfTriangularEdge[a1][0]];
+  register Vertex  *sb=t1->ns[VerticesOfTriangularEdge[a1][1]];
+  register Vertex  *s1=t1->ns[OppositeVertex[a1]];
+  register Vertex  *s2=t2->ns[OppositeVertex[a2]];
+
+#ifdef DEBUG
+  assert ( a >= 0 && a < 3 );  
+#endif
+  
+   Icoor2 det1=t1->det , det2=t2->det ;
+   Icoor2 detT = det1+det2;
+   Icoor2 detA = Abs(det1) + Abs(det2);
+   Icoor2 detMin = Min(det1,det2);
+
+   int OnSwap = 0;       
+   // si 2 triangle infini (bord) => detT = -2;
+   if (sa == 0) {// les deux triangles sont frontieres
+     det2=bamg::det(s2->i,sb->i,s1->i);
+     OnSwap = det2 >0;}
+   else if (sb == 0) { // les deux triangles sont frontieres
+     det1=bamg::det(s1->i,sa->i,s2->i);
+     OnSwap = det1 >0;}
+   else if(( s1 != 0) && (s2 != 0) ) {
+     det1 = bamg::det(s1->i,sa->i,s2->i);
+     det2 = detT - det1;
+     OnSwap = (Abs(det1) + Abs(det2)) < detA;
+   
+     Icoor2 detMinNew=Min(det1,det2);
+     //     if (detMin<0 && (Abs(det1) + Abs(det2) == detA)) OnSwap=BinaryRand();// just for test   
+     if (! OnSwap &&(detMinNew>0)) {
+       OnSwap = detMin ==0;
+       if (! OnSwap) {
+	 int  kopt = koption;
+        while (1)
+	 if(kopt) {
+	 // critere de Delaunay pure isotrope
+	 register Icoor2 xb1 = sb->i.x - s1->i.x,
+	   x21 = s2->i.x - s1->i.x,
+	   yb1 = sb->i.y - s1->i.y,
+	   y21 = s2->i.y - s1->i.y,
+	   xba = sb->i.x - sa->i.x, 
+	   x2a = s2->i.x - sa->i.x,
+	   yba = sb->i.y - sa->i.y,
+	   y2a = s2->i.y - sa->i.y;
+	 register double
+	   cosb12 =  double(xb1*x21 + yb1*y21),
+	   cosba2 =  double(xba*x2a + yba*y2a) ,
+	   sinb12 = double(det2),
+	   sinba2 = double(t2->det);
+
+	 
+	 // angle b12 > angle ba2 => cotg(angle b12) < cotg(angle ba2)
+	 OnSwap =  ((double) cosb12 * (double)  sinba2) <  ((double) cosba2 * (double) sinb12);
+//  	 if(CurrentTh) 
+//  	   cout << "swap " << CurrentTh->Number(sa) << " " << CurrentTh->Number(sb) << " " ;
+//  	 cout <<  cosb12 << " " <<  sinba2 << " "  <<  cosba2 << " " << sinb12 
+//  	      << " Onswap = " <<  OnSwap << endl;
+	  break;
+	 }
+	 else 
+	   {	
+	     // critere de Delaunay anisotrope 
+	     Real8 som;
+	     I2 AB=(I2) *sb - (I2) *sa;
+	     I2 MAB2=((I2) *sb + (I2) *sa);
+	     R2 MAB(MAB2.x*0.5,MAB2.y*0.5);
+	     I2 A1=(I2) *s1 - (I2) *sa;
+	     I2 D = (I2) * s1 - (I2) * sb ;
+	     R2 S2(s2->i.x,s2->i.y);
+	     R2 S1(s1->i.x,s1->i.y);
+	     {
+	       Metric M=s1->m;
+	       R2 ABo = M.Orthogonal(AB);
+	       R2 A1o = M.Orthogonal(A1);
+	       // (A+B)+ x ABo = (S1+B)/2+ y A1 
+	       // ABo x - A1o y =  (S1+B)/2-(A+B)/2 = (S1-B)/2 = D/2
+	       double dd = Abs(ABo.x*A1o.y)+Abs(ABo.y*A1o.x);
+	       double d = (ABo.x*A1o.y - ABo.y*A1o.x)*2; // because D/2
+	       if (Abs(d) > dd*1.e-3) {
+		 R2 C(MAB+ABo*((D.x*A1o.y - D.y*A1o.x)/d));
+		 som  = M(C - S2)/M(C - S1);
+	       } else 
+		{kopt=1;continue;}
+		
+	     }
+	     {
+	       Metric M=s2->m;
+	       R2 ABo = M.Orthogonal(AB);
+	       R2 A1o = M.Orthogonal(A1);
+	       // (A+B)+ x ABo = (S1+B)/2+ y A1 
+	       // ABo x - A1o y =  (S1+B)/2-(A+B)/2 = (S1-B)/2 = D/2 
+	       double dd = Abs(ABo.x*A1o.y)+Abs(ABo.y*A1o.x);
+	       double d = (ABo.x*A1o.y - ABo.y*A1o.x)*2; // because D/2
+	       if(Abs(d) > dd*1.e-3) {
+		 R2 C(MAB+ABo*((D.x*A1o.y - D.y*A1o.x)/d));
+		 som  += M(C - S2)/M(C -  S1);
+	       } else 
+		{kopt=1;continue;}
+	     }
+	     OnSwap = som < 2;
+	     break;
+	 }
+  
+       } // OnSwap 
+     } // (! OnSwap &&(det1 > 0) && (det2 > 0) )
+   }
+#ifdef  DEBUG1   
+   if (OnSwap &&  ( munswap1  || munswap2)) {
+     cout << " erreur Mark unswap T " << CurrentTh->Number(t1) << " " <<  CurrentTh->Number(t2) << endl
+	  << *t1 << endl
+          << *t2 << endl;
+     return 0;
+   }
+#endif 
+   if( OnSwap ) 
+       bamg::swap(t1,a1,t2,a2,s1,s2,det1,det2);
+   else {
+     NbUnSwap ++;
+      t1->SetMarkUnSwap(a1);     
+   }
+   return OnSwap;
+}
+
+Real8  Vertex::Smoothing(Triangles & Th,const Triangles & BTh,Triangle  * & tstart ,Real8 omega)
+{
+#ifdef DEBUG  
+  register  Int4 NbSwap =0;
+#endif
+  register Vertex * s  = this;
+  Vertex &vP = *s,vPsave=vP;
+  //  if (vP.on) return 0;// Don't move boundary vertex  
+  
+  register Triangle * tbegin= t , *tria = t , *ttc;
+ 
+  register int k=0,kk=0,j = EdgesVertexTriangle[vint][0],jc;
+  R2 P(s->r),PNew(0,0);
+  //  cout << BTh.quadtree << " " <<  BTh.quadtree->root << endl;
+  // assert(BTh.quadtree && BTh.quadtree->root);
+  do {
+	k++; 
+	
+#ifdef DEBUG
+    assert( s == & (*tria)[VerticesOfTriangularEdge[j][1]] );
+    assert( tria->det >0);
+#endif
+    if (!tria->Hidden(j))
+      {
+	Vertex &vQ = (*tria)[VerticesOfTriangularEdge[j][0]]; 
+	
+	R2 Q = vQ,QP(P-Q);
+	Real8 lQP = LengthInterpole(vP,vQ,QP);
+	PNew += Q+QP/Max(lQP,1e-20);
+	kk ++;
+      }
+     ttc =  tria->TriangleAdj(j);
+     jc = NextEdge[tria->NuEdgeTriangleAdj(j)];
+     tria = ttc;
+     j = NextEdge[jc];
+     assert(k<2000);
+  } while ( tbegin != tria); 
+  if (kk<4) return 0;
+  PNew = PNew/(Real8)kk;
+  R2 Xmove((PNew-P)*omega);
+  PNew = P+Xmove;
+  Real8 delta=Norme2_2(Xmove); 
+  
+  
+  // 
+  Icoor2 deta[3];
+  I2 IBTh  = BTh.toI2(PNew);
+  
+  tstart=BTh.FindTriangleContening(IBTh,deta,tstart);  
+  
+  if (tstart->det <0) 
+    { // outside
+      double ba,bb;
+      TriangleAdjacent edge= CloseBoundaryEdge(IBTh,tstart,ba,bb) ;
+      tstart = edge;
+      vP.m= Metric(ba,*edge.EdgeVertex(0),bb,*edge.EdgeVertex(1));
+    }
+  else 
+    { // inside
+      Real8   aa[3];
+      Real8 s = deta[0]+deta[1]+deta[2];
+      aa[0]=deta[0]/s;
+      aa[1]=deta[1]/s;
+      aa[2]=deta[2]/s;
+      vP.m = Metric(aa,(*tstart)[0],(*tstart)[1],(*tstart)[2]);
+    }
+  
+  // recompute the det of the triangle
+  vP.r = PNew;
+  
+  vP.i = Th.toI2(PNew);
+
+  Vertex vPnew = vP;
+  
+  int ok=1;
+  int loop=1;
+  k=0;
+  while (ok) 
+    {
+      ok =0;
+      do {
+	k++; 
+	double detold = tria->det;
+	tria->det =  bamg::det( (*tria)[0],(*tria)[1]  ,(*tria)[2]);
+	if (loop) 
+	  {
+	    Vertex *v0,*v1,*v2,*v3;
+	    if (tria->det<0) ok =1;			       
+	    else if (tria->Quadrangle(v0,v1,v2,v3))
+	      {
+		vP = vPsave;
+		Real8 qold =QuadQuality(*v0,*v1,*v2,*v3);
+		vP = vPnew;
+		Real8 qnew = QuadQuality(*v0,*v1,*v2,*v3);
+		if (qnew<qold) ok = 1;
+	      }
+	    else if ( (double)tria->det < detold/2 ) ok=1;
+	    
+	  }
+        tria->SetUnMarkUnSwap(0);
+        tria->SetUnMarkUnSwap(1);
+        tria->SetUnMarkUnSwap(2);
+	ttc =  tria->TriangleAdj(j);
+	jc = NextEdge[tria->NuEdgeTriangleAdj(j)];
+	tria = ttc;
+	j = NextEdge[jc];
+	assert(k<2000);
+      } while ( tbegin != tria); 
+      if (ok && loop) vP=vPsave; // no move 
+      loop=0;
+    }
+  return delta;
+}
+
+
+
+
+void Triangles::Add( Vertex & s,Triangle * t, Icoor2 * det3) 
+{
+  // -------------------------------------------
+  //             s2
+  //                                            !
+  //             /|\                            !
+  //            / | \                           !
+  //           /  |  \                          !
+  //    tt1   /   |   \ tt0                     !
+  //         /    |s   \                        !
+  //        /     .     \                       !
+  //       /  .      `   \                      !
+  //      / .           ` \                     !
+  //      ----------------                      !
+  //   s0       tt2       s1
+  //-------------------------------------------- 
+  
+  Triangle * tt[3]; // the 3 new Triangles
+  Vertex &s0 = (* t)[0], &s1=(* t)[1], &s2=(* t)[2];
+  Icoor2  det3local[3];
+  int infv = &s0 ?  ((  &s1 ? ( &s2  ? -1 : 2) : 1  )) : 0;
+  // infv = ordre of the infini vertex (null)
+  register int nbd0 =0; // number of zero det3
+  register int izerodet=-1,iedge; // izerodet = egde contening the vertex s
+  Icoor2 detOld = t->det;
+  
+  if ( ( infv <0 ) && (detOld <0) ||  ( infv >=0  ) && (detOld >0) ) 
+    {
+      cerr << "  infv " << infv << " det = " << detOld << endl;
+      cerr << Number(s) << " "<< Number(s0) << " "  
+	   << Number(s1) << " "  << Number(s2) << endl;
+      MeshError(3);
+    }
+  
+  // if det3 do not exist then constuct det3
+  if (!det3) { 
+    det3 = det3local; // alloc 
+    if ( infv<0 ) {
+      det3[0]=bamg::det(s ,s1,s2);
+      det3[1]=bamg::det(s0,s ,s2);
+      det3[2]=bamg::det(s0,s1,s );}
+    else { 
+      // one of &s1  &s2  &s0 is NULL so (&si || &sj) <=> !&sk
+      det3[0]=  &s0 ? -1  : bamg::det(s ,s1,s2) ;
+      det3[1]=  &s1 ? -1 : bamg::det(s0,s ,s2) ;
+      det3[2]=  &s2 ? -1 : bamg::det(s0,s1,s ) ;}}
+
+  
+  if (!det3[0]) izerodet=0,nbd0++;
+  if (!det3[1]) izerodet=1,nbd0++;
+  if (!det3[2]) izerodet=2,nbd0++;
+  
+  if  (nbd0 >0 ) // point s on a egde or on a vertex 
+    if (nbd0 == 1) {
+      iedge = OppositeEdge[izerodet];
+      TriangleAdjacent ta = t->Adj(iedge);
+
+#ifdef DEBUG1      
+      cout << " the point " << Number(s) << " is the edge " <<  izerodet 
+	   << " of " << Number(t)	   << " det3 = " 
+	   << det3[0] << " " <<  det3[1] << " " <<  det3[2] << " " <<  endl;
+      cout  << " ta = "  <<  ta << "ta->det =" << ((Triangle*) ta)->det  
+	    << " "<< t->det<< endl;
+#endif
+
+      // the point is on the edge 
+      // if the point is one the boundary 
+      // add the point in outside part 
+      if ( t->det >=0) { // inside triangle
+	if ((( Triangle *) ta)->det < 0 ) {
+	  // add in outside triangle 
+	  Add(s,( Triangle *) ta);
+	  return;}
+      }}
+    else {
+      cerr << " bug  " << nbd0 <<endl;
+      cerr << " Bug double points in " << endl ;
+      cerr << " s = " << Number(s) << " " <<  s << endl;
+      cerr << " s0 = "<< Number(s0) << " "  << s0 << endl;
+      cerr << " s1 = "<< Number(s1) << " "  << s1 << endl;
+      cerr << " s2 = "<< Number(s2) << " "  << s2 << endl;
+      MeshError(5,this);}
+
+  // remove de MarkUnSwap edge
+  t->SetUnMarkUnSwap(0);     
+  t->SetUnMarkUnSwap(1);     
+  t->SetUnMarkUnSwap(2);
+
+  tt[0]= t;
+  tt[1]= &triangles[nbt++];
+  tt[2]= &triangles[nbt++];
+  
+  if (nbt>nbtx) {
+    cerr << " No enougth triangles " << endl;
+    MeshError(999,this);
+  }
+
+  *tt[1]=   *tt[2]= *t;
+// gestion of the link
+   tt[0]->link=tt[1];
+   tt[1]->link=tt[2]; 
+  
+  (* tt[0])(OppositeVertex[0])=&s;
+  (* tt[1])(OppositeVertex[1])=&s;
+  (* tt[2])(OppositeVertex[2])=&s;
+
+  tt[0]->det=det3[0];
+  tt[1]->det=det3[1];
+  tt[2]->det=det3[2];         
+
+  //  update adj des triangles externe 
+  tt[0]->SetAdjAdj(0);
+  tt[1]->SetAdjAdj(1);
+  tt[2]->SetAdjAdj(2);
+  //  update des adj des 3 triangle interne
+  const int i0 = 0;
+  const int i1= NextEdge[i0];
+  const int i2 = PreviousEdge[i0];
+
+  tt[i0]->SetAdj2(i2,tt[i2],i0);
+  tt[i1]->SetAdj2(i0,tt[i0],i1);
+  tt[i2]->SetAdj2(i1,tt[i1],i2);
+  
+  tt[0]->SetTriangleContainingTheVertex();
+  tt[1]->SetTriangleContainingTheVertex();
+  tt[2]->SetTriangleContainingTheVertex();
+ 
+ 
+  // swap if the point s is on a edge
+  if(izerodet>=0) {
+    //  cout << " the point s is on a edge =>swap " << iedge << " "  << *tt[izerodet] << endl;
+    int rswap =tt[izerodet]->swap(iedge);
+    
+    if (!rswap) 
+     {
+       cout << " Pb swap the point s is on a edge =>swap " << iedge << " "  << *tt[izerodet] << endl;
+#ifdef DRAWING
+       if(  CurrentTh &&  withrgraphique) 
+        {
+       reffecran();
+       
+       DrawMark(s.r);
+          CurrentTh->inquire();
+       DrawMark(s.r);
+       rattente(1); 
+        }      
+#endif
+     }
+    assert(rswap);
+  }
+ 
+#ifdef DEBUG 
+  tt[0]->check();
+  tt[1]->check();
+  tt[2]->check();
+#endif
+#ifdef DRAWING1 
+  tt[0]->Draw();
+  tt[1]->Draw();
+  tt[2]->Draw();
+#endif
+  
+}
+
+
+Int4  Triangles::SplitInternalEdgeWithBorderVertices()
+{
+  Int4 NbSplitEdge=0;
+  SetVertexFieldOn();  
+  Int4 it;
+  Int4 nbvold=nbv;
+  for (it=0;it<nbt;it++)
+    {
+      Triangle &t=triangles[it];
+      if (t.link)
+	for (int j=0;j<3;j++)
+	  if(!t.Locked(j) && !t.Hidden(j)){
+	    Triangle &tt = *t.TriangleAdj(j);
+	    if ( &tt && tt.link && it < Number(tt)) 
+	      { // an internal edge 
+		Vertex &v0 = t[VerticesOfTriangularEdge[j][0]];
+		Vertex &v1 = t[VerticesOfTriangularEdge[j][1]];
+		if (v0.on && v1.on)
+		  {
+		    R2 P= ((R2) v0 + (R2) v1)*0.5;
+		    if ( nbv<nbvx) {
+		      vertices[nbv].r = P;
+		      vertices[nbv++].m = Metric(0.5,v0.m,0.5,v1.m);
+		      vertices[nbv].ReferenceNumber=0;
+		      vertices[nbv].DirOfSearch = NoDirOfSearch ;
+		    }
+		    NbSplitEdge++;
+		    if (verbosity>7)
+		      cout <<" Internal edge with two vertices on boundary" 
+			   << Number(v0) << " " << Number(v1) << " by " <<  endl;
+		  }
+	      }
+	  }
+    }
+  ReMakeTriangleContainingTheVertex();    
+  if (nbvold!=nbv) 
+    {
+      Int4  iv = nbvold;
+      Int4 NbSwap = 0;
+      Icoor2 dete[3];  
+      for (Int4 i=nbvold;i<nbv;i++) 
+	{// for all the new point
+	  Vertex & vi = vertices[i];
+	  vi.i = toI2(vi.r);
+      vi.r = toR2(vi.i);
+      //      if (!quadtree->ToClose(vi,seuil,hi,hj)) {
+      // a good new point 
+      vi.ReferenceNumber=0; 
+      vi.DirOfSearch =NoDirOfSearch;
+      //	cout << " Add " << Number(vi) << " " << vi 
+      // << "   " <<  Number(vi) << " <--> " << Number(vi) <<endl;
+      Triangle *tcvi = FindTriangleContening(vi.i,dete);
+      if (tcvi && !tcvi->link) {
+	cout << i <<  " PB insert point " << Number(vi) << vi << Number(vi) 
+	     << " tcvi = " << tcvi << " " << tcvi->link << endl;
+	cout << (*tcvi)[1] <<  (*tcvi)[2] << endl;
+	tcvi = FindTriangleContening(vi.i,dete);
+	cout << (*tcvi)[1] <<  (*tcvi)[2] << endl;
+#ifdef DRAWING1
+	inquire();
+	penthickness(5);
+	DrawMark(vi.r);
+	penthickness(1);
+	inquire();
+#endif
+	
+	MeshError(1001,this);
+      }
+      
+      
+      quadtree->Add(vi);
+#ifdef DRAWING1
+      DrawMark(vi.r);
+#endif
+      assert (tcvi && tcvi->det >= 0) ;// internal 
+      Add(vi,tcvi,dete);
+      NbSwap += vi.Optim(1);          
+      iv++;
+      //      }
+	}
+      if (verbosity>3) 
+	{
+	  cout << "    Nb Of New Point " << iv ;
+	  cout << " Nb swap = " << NbSwap << " to  split internal edges with border vertices" ;}
+      
+      nbv = iv;
+    }
+  if (NbSplitEdge >  nbv-nbvold)
+    cout << " Warning not enough vertices  to split all internal edges "  << endl
+	 << "    we lost " << NbSplitEdge - ( nbv-nbvold) << " Edges Sorry " << endl;
+  if (verbosity>2)
+  cout << "SplitInternalEdgeWithBorderVertices: Number of splited edge " << NbSplitEdge << endl;
+  return  NbSplitEdge;
+}
+Int4 Triangles::InsertNewPoints(Int4 nbvold,Int4 & NbTSwap)
+ {
+  Real8 seuil= 1.414/2 ;// for two close point 
+  Int4 i;
+ // insertion part --- 
+
+  const Int4 nbvnew = nbv-nbvold;
+  if (verbosity>5) 
+    cout << "    Try to Insert the " <<nbvnew<< " new points " << endl;  
+  Int4 NbSwap=0;
+  Icoor2 dete[3];
+  
+  // construction d'un ordre aleatoire 
+  if (! nbvnew) 
+    return 0; 
+  if (nbvnew) {
+  const Int4 PrimeNumber= AGoodNumberPrimeWith(nbv)  ;
+  Int4 k3 = rand()%nbvnew ; 
+  for (Int4 is3=0; is3<nbvnew; is3++) {
+    register Int4 j = nbvold +(k3 = (k3 + PrimeNumber)% nbvnew);
+    register Int4 i = nbvold+is3; 
+    ordre[i]= vertices + j;
+    ordre[i]->ReferenceNumber=i;
+  }
+  // be carefull 
+  Int4  iv = nbvold;
+  for (i=nbvold;i<nbv;i++) 
+    {// for all the new point
+      Vertex & vi = *ordre[i];
+      vi.i = toI2(vi.r);
+      vi.r = toR2(vi.i);
+      Real4 hx,hy;
+      vi.m.Box(hx,hy);
+      Icoor1 hi=(Icoor1) (hx*coefIcoor),hj=(Icoor1) (hy*coefIcoor);
+      if (!quadtree->ToClose(vi,seuil,hi,hj)) 
+        {
+			// a good new point 
+			Vertex & vj = vertices[iv];
+			Int4 j = vj.ReferenceNumber; 
+			assert( &vj== ordre[j]);
+			if(i!=j)
+			  { //  for valgring 
+			    Exchange(vi,vj);
+			    Exchange(ordre[j],ordre[i]);
+			  }
+		      vj.ReferenceNumber=0; 
+			//	cout << " Add " << Number(vj) << " " << vj 
+			// << "   " <<  Number(vi) << " <--> " << Number(vj) <<endl;
+			Triangle *tcvj = FindTriangleContening(vj.i,dete);
+			if (tcvj && !tcvj->link) 
+			 {
+			  cerr << i <<  " PB insert point " << Number(vj) << vj << Number(vi) 
+			       << " tcvj = " << tcvj << " " << tcvj->link << endl;
+			  cerr << (*tcvj)[1] <<  (*tcvj)[2] << endl;
+			  tcvj = FindTriangleContening(vj.i,dete);
+			  cout << (*tcvj)[1] <<  (*tcvj)[2] << endl;
+#ifdef DRAWING1
+		 	  inquire();
+			  penthickness(5);
+			  DrawMark(vj.r);
+			  penthickness(1);
+			  
+			  inquire();
+#endif
+	  
+	          MeshError(1001,this);
+	         }
+	
+	
+	        quadtree->Add(vj);
+#ifdef DRAWING1
+	        DrawMark(vj.r);
+#endif
+			assert (tcvj && tcvj->det >= 0) ;// internal 
+			Add(vj,tcvj,dete);
+			NbSwap += vj.Optim(1);          
+			iv++;
+         }
+    } 
+  if (verbosity>3) {
+    cout << "    Nb Of New Point " << iv << " Nb Of To close Points " << nbv-iv ;
+    cout << " Nb swap = " << NbSwap << " after " ;}
+
+    nbv = iv;
+  }
+
+#ifdef DRAWING1
+  inquire();
+#endif
+
+  for (i=nbvold;i<nbv;i++) 
+    NbSwap += vertices[i].Optim(1);  
+   if (verbosity>3) 
+     cout << " NbSwap = " <<  NbSwap << endl;
+
+
+  NbTSwap +=  NbSwap ;
+#ifdef DEBUG
+{  
+  Int4 NbErr=0;
+  Int4 i;
+  for (i=0;i<nbt;i++)
+    if (triangles[i].link) 
+      {
+      double dd =Det(triangles[i][1].r-triangles[i][0].r,triangles[i][2].r-triangles[i][0].r);
+      if(dd <=0) 
+	{
+	  NbErr++;
+	  cerr << " det triangle i " << i << " = " << triangles[i].det ;
+	  cerr << " det triangle  " << dd ;
+	    cerr << " Les trois sommets " ;
+	    cerr << Number(triangles[i][0]) << " "  << Number(triangles[i][1]) << " " 
+		 << Number(triangles[i][2]) << endl;
+	    cerr << "I2     " <<triangles[i][0].r << triangles[i][1].r << triangles[i][2].r << endl;
+	    cerr << "R2     " << triangles[i][0].i << triangles[i][1].i << triangles[i][2].i << endl;
+	    cerr << "I2-R2 =" <<toR2(triangles[i][0].i)-triangles[i][0].r 
+		 << toR2(triangles[i][1].i)-triangles[i][1].r
+		 << toR2(triangles[i][2].i)-triangles[i][2].r << endl;
+	}
+      }
+  if(NbErr) { 
+#ifdef DRAWING
+    Int4 kkk=0;
+    //  UnMarkUnSwapTriangle();
+    //  for (i=0;i<nbv;i++)
+    //  kkk += vertices[i].Optim(0);
+    if(verbosity>3)
+    cout << "    Nb of swap louche " << kkk << endl;
+    if(kkk) {
+  for (i=0;i<nbt;i++)
+    if (triangles[i].link) 
+      {
+      double dd =Det(triangles[i][1].r-triangles[i][0].r,triangles[i][2].r-triangles[i][0].r);
+      if(dd <=0) 
+	{
+	  NbErr++;
+	  cerr << " xxxdet triangle i " << i << " = " << triangles[i].det ;
+	  cerr << " xxxdet triangle  " << dd ;
+	    cerr << " xxxLes trois sommets " ;
+	    cerr << Number(triangles[i][0]) << " "  << Number(triangles[i][1]) << " " 
+		 << Number(triangles[i][2]) << endl;
+	    cerr << triangles[i][0].r << triangles[i][1].r << triangles[i][2].r << endl;
+	    cerr << triangles[i][0].i << triangles[i][1].i << triangles[i][2].i << endl;
+	}
+      } }
+   inquire();
+#endif
+    //   MeshError(11);
+  }
+  
+}
+#endif
+  return nbv-nbvold;
+ 
+ }
+void  Triangles::NewPoints(Triangles & Bh,int KeepBackVertex)
+{ // Triangles::NewPoints
+  Int4 nbtold(nbt),nbvold(nbv);
+  if (verbosity>2) 
+    cout << "  -- Triangles::NewPoints ";
+  if (verbosity>3)cout <<  " nbv (in)  on Boundary  = " << nbv  <<endl;
+  Int4 i,k;
+  int j;
+  Int4 *first_np_or_next_t = new Int4[nbtx];
+  Int4 NbTSwap =0;
+//    insert old point
+    nbtold = nbt;
+    
+  if (KeepBackVertex && (&Bh != this) && (nbv+Bh.nbv< nbvx)) 
+   {
+  //   Bh.SetVertexFieldOn();
+     for (i=0;i<Bh.nbv;i++)
+      { 
+        Vertex & bv = Bh[i];
+        if (!bv.on) {
+          vertices[nbv].r = bv.r;
+          vertices[nbv++].m = bv.m;}
+      }
+     int nbv1=nbv;
+     Bh.ReMakeTriangleContainingTheVertex();     
+     InsertNewPoints(nbvold,NbTSwap)   ;            
+     if (verbosity>2)
+        cout <<  "      (Nb of Points from background mesh  = " 
+             << nbv-nbvold  << " / " << nbv1-nbvold << ")" << endl;
+   }  
+  else 
+    Bh.ReMakeTriangleContainingTheVertex();     
+
+  Triangle *t;
+  // generation of the list of next Triangle 
+  // at 1 time we test all the triangles
+  Int4 Headt =0,next_t;
+  for(i=0;i<nbt;i++)
+    first_np_or_next_t[i]=-(i+1);
+  // end list i >= nbt 
+  // the list of test triangle is 
+  // the next traingle on i is  -first_np_or_next_t[i]
+  int iter=0;
+  // Big loop 
+  do {
+    iter++;
+    nbtold = nbt;
+    nbvold = nbv;
+#ifdef DRAWING1  
+  inquire();
+#endif  
+
+  // default size of  IntersectionTriangle
+
+  i=Headt;
+  next_t=-first_np_or_next_t[i];
+  for(t=&triangles[i];i<nbt;t=&triangles[i=next_t],next_t=-first_np_or_next_t[i]) 
+    { // for each triangle  t
+      // we can change first_np_or_next_t[i]
+      //      cout << " Do the triangle " << i << " Next_t=" << next_t << endl;
+      assert(i>=0 && i < nbt );
+      first_np_or_next_t[i] = iter; 
+      for(j=0;j<3;j++)
+	{ // for each edge 
+	  TriangleAdjacent tj(t,j);
+	  Vertex & vA = * tj.EdgeVertex(0);
+	  Vertex & vB = * tj.EdgeVertex(1);
+	  
+	  if (!t->link) continue;// boundary
+	  if (t->det <0) continue;
+	  if (t->Locked(j)) continue;
+
+	  TriangleAdjacent tadjj = t->Adj(j);	  
+	  Triangle * ta= tadjj;
+
+	  if (ta->det <0) continue;	  
+	  
+	  R2 A = vA;
+	  R2 B = vB;
+	  
+	  k=Number(ta);
+	  
+	  if(first_np_or_next_t[k]==iter)  // this edge is done before 
+	    continue; // next edge of the triangle 
+	  
+	  //const Int4 NbvOld = nbv;
+	  lIntTria.SplitEdge(Bh,A,B);
+	  lIntTria.NewPoints(vertices,nbv,nbvx);
+	} // end loop for each edge 
+      
+    }// for triangle   
+  
+#ifdef DRAWING1
+  cout << "  -------------------------------------------- " << endl;
+  inquire();
+  reffecran();
+  Draw();
+  penthickness(2);
+#endif
+
+   if (!InsertNewPoints(nbvold,NbTSwap)) 
+     break;
+     
+   for (i=nbtold;i<nbt;i++)
+     first_np_or_next_t[i]=iter;
+
+  Headt = nbt; // empty list 
+  for (i=nbvold;i<nbv;i++) 
+    { // for all the triangle contening the vertex i
+       Vertex * s  = vertices + i;
+       TriangleAdjacent ta(s->t, EdgesVertexTriangle[s->vint][1]);
+       Triangle * tbegin= (Triangle*) ta;
+       Int4 kt;
+       do { 
+	 kt = Number((Triangle*) ta);
+	 if (first_np_or_next_t[kt]>0) 
+	   first_np_or_next_t[kt]=-Headt,Headt=kt;
+	 assert( ta.EdgeVertex(0) == s);
+	 ta = Next(Adj(ta));
+       } while ( (tbegin != (Triangle*) ta)); 
+    }   
+   
+  } while (nbv!=nbvold);
+  
+  delete []  first_np_or_next_t;
+
+  Int4 NbSwapf =0,NbSwp;
+  
+  // bofbof 
+  
+  
+  NbSwp = NbSwapf;
+  for (i=0;i<nbv;i++)
+    NbSwapf += vertices[i].Optim(0);
+  /*
+  for (i=0;i<nbv;i++)
+    NbSwapf += vertices[i].Optim(0);
+  for (i=0;i<nbv;i++)
+    NbSwapf += vertices[i].Optim(0);
+  for (i=0;i<nbv;i++)
+    NbSwapf += vertices[i].Optim(0);
+  for (i=0;i<nbv;i++)
+    NbSwapf += vertices[i].Optim(0);
+    */
+  NbTSwap +=  NbSwapf ;
+  if (verbosity>3) cout << "   " ;
+  if (verbosity>2) 
+     cout << " Nb Of Vertices =" << nbv << " Nb of triangles = " << nbt-NbOutT 
+	  << " NbSwap final = " << NbSwapf << " Nb Total Of Swap = " << NbTSwap << endl;
+
+
+}
+
+void  Triangles::NewPointsOld(Triangles & Bh)
+{ // Triangles::NewPointsOld
+  Real8 seuil= 0.7 ;// for two neart point 
+  if (verbosity>1) 
+    cout << " begin :  Triangles::NewPointsOld " << endl;
+  Int4 i,k;
+  int j;
+  Int4 BeginNewPoint[3];
+  Int4 EndNewPoint[3];
+#ifdef TRACETRIANGLE
+  Int4 trace=0;
+#endif
+  int step[3];
+  Int4 *first_np_or_next_t = new Int4[nbtx];
+  Int4 ColorEdge[3];
+  Int4 color=-1;
+  Triangle *t;
+  // generation of the list of next Triangle 
+  // at 1 time we test all the triangles
+  Int4 Headt =0,next_t;
+  for(i=0;i<nbt;i++)
+    first_np_or_next_t[i]=-(i+1);
+  // end list i >= nbt 
+  // the list of test triangle is 
+  // the next Triangle on i is  -first_np_or_next_t[i]
+  Int4 nbtold,nbvold;
+
+  // Big loop 
+  do {
+    nbtold = nbt;
+    nbvold = nbv;
+#ifdef DRAWING1  
+  inquire();
+#endif  
+
+  // default size of  IntersectionTriangle
+
+  i=Headt;
+  next_t=-first_np_or_next_t[i];
+  for(t=&triangles[i];i<nbt;t=&triangles[i=next_t],next_t=-first_np_or_next_t[i]) 
+    { // for each triangle  t
+      // we can change first_np_or_next_t[i]
+#ifdef TRACETRIANGLE
+      trace =  TRACETRIANGLE <0 ? 1 : i == TRACETRIANGLE;
+#endif
+      //      cout << " Do the triangle " << i << " Next_t=" << next_t << endl;
+      assert(i>=0 && i < nbt );
+      first_np_or_next_t[i] = nbv; // to save the fist new point of triangle
+      for(j=0;j<3;j++)
+	{ // for each edge 
+	  TriangleAdjacent tj(t,j);
+	  // color++;// the color is 3i+j
+          color = 3*i + j ;;
+	  ColorEdge[j]=color;
+	  BeginNewPoint[j]=nbv;
+	  EndNewPoint[j]=nbv-1;
+	  step[j]=1;// right sens 
+	  Vertex & vA = * tj.EdgeVertex(0);
+	  Vertex & vB = * tj.EdgeVertex(1);
+	  
+#ifdef TRACETRIANGLE
+	  if(trace) {
+	    cout << " i " << Number(vA) <<" j "<<  Number(vB) 
+		 << " "  << t->Locked(j) ;
+	  }
+#endif
+	  if (!t->link) continue;// boundary
+	  if (t->det <0) continue;
+	  if (t->Locked(j)) continue;
+
+	  TriangleAdjacent tadjj = t->Adj(j);	  
+	  Triangle * ta= tadjj;
+
+	  if (ta->det <0) continue;	  
+	  
+	  R2 A = vA;
+	  R2 B = vB;
+	  
+	  k=Number(ta);
+	  // the 2 opposite vertices 
+	  const Vertex & vC1  =  *tj.OppositeVertex();
+	  const Vertex & vC2 = *tadjj.OppositeVertex();
+	  
+#ifdef TRACETRIANGLE
+	  trace = trace || k == TRACETRIANGLE;
+	  if(trace) {
+	    cout << "Test Arete " << i << " AB = " << A << B 
+		 << "i "  <<Number(vA)<< "j" <<Number(vB); 
+	    cout << " link" <<(int)t->link << " ta=" << Number( ta) 
+		 << " det " <<ta->det ;
+	    cout << " hA = " <<vA.m.h << " hB = " <<vB.m.h ;
+	    cout << " loc " << ta->Locked(j) << endl;
+	  }
+#endif
+	  
+	  if(first_np_or_next_t[k]>0) { // this edge is done before 
+	    // find the color of the edge and begin , end of newpoint
+	    register int kk = t->NuEdgeTriangleAdj(j);
+	    assert ((*t)(VerticesOfTriangularEdge[j][0]) == (*ta)(VerticesOfTriangularEdge[kk][1]));
+	    assert ((*t)(VerticesOfTriangularEdge[j][1]) == (*ta)(VerticesOfTriangularEdge[kk][0]));
+	    register Int4 kolor =3*k + kk;
+	    ColorEdge[j]=kolor;
+	    register Int4 kkk= 1;
+	    step[j]=-1;// other sens 
+	    BeginNewPoint[j]=0;
+	    EndNewPoint[j]=-1; // empty list          
+	    for (Int4 iv=first_np_or_next_t[k];iv<nbv;iv++) 
+	      if (vertices[iv].color > kolor) 
+		break; // the color is passed            
+	      else if (vertices[iv].color == kolor) {
+		EndNewPoint[j]=iv; 
+		if (kkk) // one time test
+		  kkk=0,BeginNewPoint[j]=iv;}
+	    continue; // next edge of the triangle 
+	  } // end  if( k < i) 
+       
+	  
+#ifdef DRAWING1
+	  penthickness(2); Move(A);Line(B);   penthickness(1);
+#endif
+	  const Int4 NbvOld = nbv;
+	  lIntTria.SplitEdge(Bh,A,B);
+	  // Int4 NbvNp =
+	  lIntTria.NewPoints(vertices,nbv,nbvx);
+	  Int4 nbvNew=nbv;
+	  nbv = NbvOld;
+	  for (Int4 iv=NbvOld;iv<nbvNew;iv++) {
+	    vertices[nbv].color = color;
+	    vertices[nbv].ReferenceNumber=nbv;// circular link
+	    R2 C =  vertices[iv].r;
+	    vertices[nbv].r =  C;
+	    vertices[nbv].m =  vertices[iv].m ;
+	    // test if the new point is not to close to the 2 opposite vertex
+	    R2 CC1 = C-vC1 , CC2 = C-vC2;
+	    if (   (  (vC1.m(CC1) + vertices[nbv].m(CC1)) >  seuil)
+		&& (  (vC2.m(CC2) + vertices[nbv].m(CC2)) >  seuil) )
+	      nbv++;
+	  }
+	    
+	  EndNewPoint[j] = nbv-1;
+	} // end loop for each edge 
+
+#ifdef TRACETRIANGLE
+      if(trace) {
+	// verification des point cree 
+	cout << "\n ------------ " << t->link << " " << t->det 
+	     << " b " << BeginNewPoint[0] << " " << BeginNewPoint[1]
+	     << " " << BeginNewPoint[2] << " " 
+	     << " e " << EndNewPoint[0] << " " << EndNewPoint[1] 
+	     << " " << EndNewPoint[2] << " " 
+	     << " s " << step[0] << " " << step[1] << " " << step[2] << " " 
+	     <<  endl;
+      }
+#endif
+
+      if (!t->link) continue;// boundary
+      if (t->det<=0) continue;// outside 
+      //      continue;
+      for(int j0=0;j0<3;j0++)
+	for (Int4 i0= BeginNewPoint[j0]; i0 <= EndNewPoint[j0];i0++)
+	  {
+	   // find the neart  point one the opposite edge 
+           // to compute i1
+	    Vertex & vi0 = vertices[i0];
+	    int kstack = 0;
+	    Int4 stack[10];
+	 //   Int4 savRef[10];
+	    int j1 = j0; 
+	    while (j0 != (j1 = NextEdge[j1])) {//loop on the 2 other edge
+	      // computation of the intersection of edge j1 and DOrto
+	      // take the good sens 
+	      
+	      if (BeginNewPoint[j1]> EndNewPoint[j1])
+	        continue; // 
+              else if (EndNewPoint[j1] - BeginNewPoint[j1] <1) {
+                for (Int4 ii1= BeginNewPoint[j1];ii1<=EndNewPoint[j1];ii1++)
+                    stack[kstack++] = ii1;
+                 continue;}
+	      
+                
+	      int k0,k1;
+	      if (step[j1]<0) k0=1,k1=0; // reverse
+	      else k0=0,k1=1; 
+	      R2 V10 = (R2)(*t)[VerticesOfTriangularEdge[j1][k0]];
+	      R2 V11 = (R2)(*t)[VerticesOfTriangularEdge[j1][k1]];
+	      R2 D = V11-V10;
+	      Real8 c0 =  vi0.m(D,(R2) vi0);
+
+	      Real8 c10 =  vi0.m(D,V10);
+	      Real8 c11 =  vi0.m(D,V11);
+
+	      Real8 s;
+	      //cout << " --i0 = " << i0  << D  << V10 << V11 << endl ;
+	      //cout << "   c10 " <<  c10 << " c0 " << c0 << " c11 " << c11 << endl;
+	      if (( c10 < c0 ) && (c0 < c11)) 
+		s = (c11-c0)/(c11-c10);
+	      else if  (( c11 < c0 ) && (c0 < c10)) 
+		s = (c11-c0) /(c11-c10);
+	      else break;
+	      R2 VP = V10*s + V11*(1-s);
+	      int sss = (c11-c10) >0 ? 1 : -1;
+#ifdef DRAWING1
+	      penthickness(2);
+	      Move((R2) vi0);
+	      Line(VP);
+	      penthickness(1);
+#endif
+	      // find the 2 point by dichotomie
+	      //cout << "   t =" << Number(t) << " c0 " << c0  ;
+	      Int4 ii0 =  BeginNewPoint[j1];
+	      Int4 ii1 =  EndNewPoint[j1];	     
+              Real8 ciii=-1,cii0=-1,cii1=-1  ;
+ 	      if ( sss * ((cii0=vi0.m(D,(R2) vertices[ii0]))- c0) >0 )  
+		stack[kstack++] = ii0;//cout << " add+0 " << ii0;
+ 	      else if ( sss * ((cii1=  vi0.m(D ,(R2) vertices[ii1]))- c0) < 0 )  
+		stack[kstack++] = ii1;//cout << " add+1 " << ii1;
+              else {
+	        while ((ii1-ii0)> 1) {
+		  Int4 iii = (ii0+ii1)/2;
+	          ciii = vi0.m( D ,(R2) vertices[iii]);
+		  //cout << " (iii = " << iii << " " <<  ciii << ") ";
+		  if ( sss * (ciii - c0) <0 )  ii0 = iii;
+		  else ii1 = iii;}	        	      
+	        stack[kstack++] = ii0;// cout << " add0 " << ii0;
+	        if (ii1 != ii0)  stack[kstack++] = ii1;//cout << " add1 " << ii1;
+              }
+#ifdef DEBUG2
+	      cout << "ii1 = " << ii1 
+		   << " ii0 = " << ii0 << endl;
+              cout << "   cccc = " << cii0 << " " << ciii 
+		   << " " << cii1 << " sss=" << sss << endl;
+#endif
+	      if (kstack >5) // bug ?
+	    	cout << "NewPoints: bug????? " << kstack << " stack  " << stack[kstack]<< endl;
+	    }
+	    
+	    stack[kstack++] = -1; // to stop
+	    Int4 i1;
+	    kstack =0; 
+	    while( (i1=stack[kstack++]) >= 0) 
+	      { // the two parameter is i0 and i1 
+	      assert(i1 < nbv && i1 >= 0);
+	      assert(i0 < nbv && i0 >= 0);
+	      assert(i1 != i0);
+	      R2 v01 = (R2) vertices[i1]- (R2) vertices[i0];
+	      Real8 d01 = (vertices[i0].m(v01) + vertices[i1].m(v01));
+		
+
+#ifdef DRAWING1
+	      Move(vertices[i0].r);
+	      Line(vertices[i1].r);
+#endif
+#ifdef TRACETRIANGLE
+	      if(trace) {
+		cout << "\n test j" << j <<" "  << i0 
+		     << " " << i1 << " d01=" << d01 <<endl;}
+#endif
+	      assert (i0 >= nbvold);
+	      assert (i1 >= nbvold);
+	      assert(i0 != i1);
+	      if (d01 == 0) 
+		break; 
+	      if ( d01 < seuil) 
+		if (i1<nbvold) {
+		  // remove all the points i0;
+		  register Int4 ip,ipp;
+		  for  (ip=i0;i0 != (ipp = vertices[ip].ReferenceNumber);ip=ipp)
+		    vertices[ip].ReferenceNumber = -1;// mark remove
+		  vertices[ip].ReferenceNumber = -1;// mark remove
+		}
+	      else {
+		// remove on of two points
+		register Int4 ip0, ip1, ipp0,ipp1;
+		register int kk0=1,kk1=1;
+		// count the number of common points to compute weight w0,w1
+		for  (ip0=i0;i0 != (ipp0 = vertices[ip0].ReferenceNumber);ip0=ipp0) kk0++;
+		for  (ip1=i1;i1 != (ipp1 = vertices[ip1].ReferenceNumber);ip1=ipp1) kk1++;
+		
+		register Real8 w0 = ((Real8) kk0)/(kk0+kk1);
+		register Real8 w1 = ((Real8) kk1)/(kk0+kk1);
+
+		// make a circular link
+		Exchange(vertices[i0].ReferenceNumber,vertices[i1].ReferenceNumber);
+		// the new coordinate 
+		R2 C //= vertices[i0] ;
+		  =  vertices[i0].r *w0 + vertices[i1].r* w1;
+
+#ifdef TRACETRIANGLE
+		if(trace) {
+		  cout << "\n ref = "<< vertices[i0].ref << " " <<vertices[i1].ref <<endl;
+		}
+#endif    
+#ifdef DRAWING1  
+		Move(vertices[i0].r);
+		Line(vertices[i1].r);
+		DrawMark(C);
+#endif		
+		// update the new point points of the list 
+		for  (ip0=i0;i0 != (ipp0 = vertices[ip0].ReferenceNumber);ip0=ipp0)
+		  vertices[ip0].r = C;	      
+		vertices[ip0].r = C;
+	      }
+	    }
+	} // for (i0= ....
+  }// for triangle   
+
+#ifdef DRAWING1
+  cout << " -------------------------------------------- " << endl;
+  inquire();
+  reffecran();
+  Draw();
+  penthickness(2);
+#endif
+  
+  // remove of all the double points
+
+  Int4 ip,ipp,kkk=nbvold;
+  for (i=nbvold;i<nbv;i++) 
+     if (vertices[i].ReferenceNumber>=0) {// good points
+    //  cout <<" i = " << i ;
+      for  (ip=i;i != (ipp = vertices[ip].ReferenceNumber);ip=ipp)
+         vertices[ip].ReferenceNumber = -1;// mark remove
+      vertices[ip].ReferenceNumber = -1;// mark remove
+      // cout << i << " ---> " << kkk << endl;        
+      vertices[kkk] = vertices[i];
+      vertices[kkk].i = toI2(vertices[kkk].r);
+#ifdef DRAWING1
+      DrawMark(vertices[kkk]);
+#endif
+      vertices[kkk++].ReferenceNumber = 0;
+      
+     } 
+#ifdef DRAWING1  
+  penthickness(1);
+#endif
+    
+ // insertion part --- 
+
+  const Int4 nbvnew = kkk-nbvold;
+
+  cout << "    Remove " << nbv - kkk  << " to close  vertex " ;
+  cout << " and   Insert the " <<nbvnew<< " new points " << endl;  
+  nbv = kkk;
+  Int4 NbSwap=0;
+  Icoor2 dete[3];
+  
+  // construction d'un ordre aleatoire 
+  if (! nbvnew) 
+    break; 
+  if (nbvnew) {
+  const Int4 PrimeNumber= AGoodNumberPrimeWith(nbv)  ;
+  Int4 k3 = rand()%nbvnew ; 
+  for (Int4 is3=0; is3<nbvnew; is3++) 
+    ordre[nbvold+is3]= &vertices[nbvold +(k3 = (k3 + PrimeNumber)% nbvnew)];
+
+  for (i=nbvold;i<nbv;i++) 
+    { Vertex * vi = ordre[i];
+      Triangle *tcvi = FindTriangleContening(vi->i,dete);
+      //     Vertex * nv =  quadtree->NearestVertex(vi->i.x,vi->i.y);
+      //      cout << " Neart Vertex of "  << Number(vi)<< vi->i << " is " 
+      //   << Number(nv) << nv->i  << endl;
+      // Int4  kt = Number(tcvi);
+      // 
+      
+      quadtree->Add(*vi); //
+#ifdef DRAWING1
+      DrawMark(vi->r);
+#endif
+      assert (tcvi->det >= 0) ;// internal 
+      Add(*vi,tcvi,dete),NbSwap += vi->Optim(1);          
+    }  
+  }
+  cout << " Nb swap = " << NbSwap << " after " ;
+#ifdef DRAWING1
+  inquire();
+#endif
+
+  for (i=nbvold;i<nbv;i++) 
+    NbSwap += vertices[i].Optim(1);  
+  cout << NbSwap << endl;
+
+  for (i=nbtold;i<nbt;i++)
+     first_np_or_next_t[i]=1;
+
+  Headt = nbt; // empty list 
+  for (i=nbvold;i<nbv;i++) 
+    { // for all the triangle contening the vertex i
+       Vertex * s  = vertices + i;
+       TriangleAdjacent ta(s->t, EdgesVertexTriangle[s->vint][1]);
+       Triangle * tbegin= (Triangle*) ta;
+       Int4 kt;
+       do { 
+	 kt = Number((Triangle*) ta);
+	 if (first_np_or_next_t[kt]>0) 
+	   first_np_or_next_t[kt]=-Headt,Headt=kt;
+	 assert( ta.EdgeVertex(0) == s);
+	 ta = Next(Adj(ta));
+       } while ( (tbegin != (Triangle*) ta)); 
+    }
+
+
+  } while (nbv!=nbvold);
+  delete []  first_np_or_next_t;
+#ifdef  DEBUG
+  int nberr=0;
+  for (int it=0;it<nbt;it++)
+    if(triangles[it].det==0) 
+      if(nberr++<10) cerr << "Bug Triangle nul" << it << triangles[it] << endl;
+  if(nberr) MeshError(992,this);
+#endif
+  cout << " end :  Triangles::NewPoints old  nbv=" << nbv << endl;
+
+}
+
+void Triangles::Insert() 
+{
+  if (verbosity>2) cout << "  -- Insert initial " << nbv << " vertices " << endl ;
+  Triangles * OldCurrentTh =CurrentTh;
+
+  CurrentTh=this;
+  double time0=CPUtime(),time1,time2,time3;
+  SetIntCoor();
+  Int4 i;
+  for (i=0;i<nbv;i++) 
+    ordre[i]= &vertices[i] ;
+
+  // construction d'un ordre aleatoire 
+  const Int4 PrimeNumber= AGoodNumberPrimeWith(nbv) ;
+  Int4 k3 = rand()%nbv ; 
+  for (int is3=0; is3<nbv; is3++) 
+    ordre[is3]= &vertices[k3 = (k3 + PrimeNumber)% nbv];
+
+
+
+
+  for (i=2 ; det( ordre[0]->i, ordre[1]->i, ordre[i]->i ) == 0;) 
+    if  ( ++i >= nbv) {
+      cerr << " All the vertices are aline " << endl;
+      MeshError(998,this); }
+          
+  // echange i et 2 dans ordre afin 
+  // que les 3 premiers ne soit pas aligne
+  Exchange( ordre[2], ordre[i]);
+  
+  // on ajoute un point a l'infini pour construire le maillage
+  // afin d'avoir une definition simple des aretes frontieres
+  nbt = 2;
+  
+  
+  // on construit un maillage trivale forme
+  // d'une arete et de 2 triangles
+  // construit avec le 2 aretes orientes et 
+  Vertex *  v0=ordre[0], *v1=ordre[1];
+  
+  triangles[0](0) = 0; // sommet pour infini 
+  triangles[0](1) = v0;
+  triangles[0](2) = v1;
+  
+  triangles[1](0) = 0;// sommet pour infini 
+  triangles[1](2) = v0;
+  triangles[1](1) = v1;
+  const int e0 = OppositeEdge[0];
+  const int e1 = NextEdge[e0];
+  const int e2 = PreviousEdge[e0];
+  triangles[0].SetAdj2(e0, &triangles[1] ,e0);
+  triangles[0].SetAdj2(e1, &triangles[1] ,e2);
+  triangles[0].SetAdj2(e2, &triangles[1] ,e1);
+  
+  triangles[0].det = -1;  // faux triangles
+  triangles[1].det = -1;  // faux triangles
+  
+  triangles[0].SetTriangleContainingTheVertex();
+  triangles[1].SetTriangleContainingTheVertex();
+  
+  triangles[0].link=&triangles[1];
+  triangles[1].link=&triangles[0];
+  
+#ifdef DEBUG 
+  triangles[0].check();
+  triangles[1].check();
+#endif  
+  //  nbtf = 2;
+   if (  !quadtree )  quadtree = new QuadTree(this,0);
+   quadtree->Add(*v0);
+   quadtree->Add(*v1);
+   
+  // on ajoute les sommets un Ã’ un 
+  Int4 NbSwap=0;
+
+  time1=CPUtime();
+
+    if (verbosity>3) cout << "  -- Begin of insertion process " << endl;
+
+  for (Int4 icount=2; icount<nbv; icount++) {
+    Vertex *vi  = ordre[icount];
+    //    cout << " Insert " << Number(vi) << endl;
+    Icoor2 dete[3];
+    Triangle *tcvi = FindTriangleContening(vi->i,dete);
+    quadtree->Add(*vi); 
+    Add(*vi,tcvi,dete);
+    NbSwap += vi->Optim(1,0);
+#ifdef DRAWING1
+    inquire();
+#endif
+    
+  }// fin de boucle en icount
+  time2=CPUtime();
+  if (verbosity>3) 
+    cout << "    NbSwap of insertion " <<    NbSwap 
+	 << " NbSwap/Nbv " <<  (float) NbSwap / (float) nbv 
+	 << " NbUnSwap " << NbUnSwap << " Nb UnSwap/Nbv " 
+	 << (float)NbUnSwap /(float) nbv 
+	 <<endl;
+  NbUnSwap = 0;
+  // construction d'un ordre aleatoire 
+  //  const int PrimeNumber= (nbv % 999983) ? 1000003: 999983 ;
+#ifdef NBLOOPOPTIM
+
+  k3 = rand()%nbv ; 
+  for (int is4=0; is4<nbv; is4++) 
+    ordre[is4]= &vertices[k3 = (k3 + PrimeNumber)% nbv];
+  
+  double timeloop = time2 ;
+  for(int Nbloop=0;Nbloop<NBLOOPOPTIM;Nbloop++) 
+    {
+      double time000 = timeloop;
+      Int4  NbSwap = 0;
+      for (int is1=0; is1<nbv; is1++) 
+	NbSwap += ordre[is1]->Optim(0,0);
+      timeloop = CPUtime();
+  if (verbosity>3) 
+      cout << "    Optim Loop "<<Nbloop<<" NbSwap: " <<  NbSwap 
+	   << " NbSwap/Nbv " 	   <<  (float) NbSwap / (float) nbv 
+	   << " CPU=" << timeloop - time000 << "  s, " 
+	   << " NbUnSwap/Nbv " << (float)NbUnSwap /(float) nbv  
+	   <<  endl;
+      NbUnSwap = 0;
+      if(!NbSwap) break;
+    }
+  ReMakeTriangleContainingTheVertex(); 
+  // because we break the TriangleContainingTheVertex
+#endif
+#ifdef  DEBUG
+  int nberr=0;
+  for (int it=0;it<nbt;it++)
+    if(triangles[it].det==0) 
+      if(nberr++<10) cerr << "Bug Triangle nul" << it << triangles[it] << endl;
+  if(nberr) MeshError(991,this);
+#endif
+  time3=CPUtime();
+  if (verbosity>4) 
+  cout << "    init " << time1 - time0 << " initialisation,  " 
+       << time2 - time1 << "s, insert point  " 
+       << time3 -time2 << "s, optim " << endl
+       << "     Init Total Cpu Time = " << time3 - time0 << "s " << endl;
+  
+#ifdef DRAWING1
+  inquire();
+#endif  
+  CurrentTh=OldCurrentTh;
+}
+
+
+void Triangles::ForceBoundary()
+{
+  if (verbosity > 2)
+    cout << "  -- ForceBoundary  nb of edge " << nbe << endl;
+  int k=0;
+  Int4  nbfe=0,nbswp=0,Nbswap=0;
+  for (Int4 t = 0; t < nbt; t++)  
+    if (!triangles[t].det)
+      k++,cerr << " det T" << t << " = " << 0 << endl;
+  if (k!=0) {
+    cerr << " ther is  " << k << "  triangles of mes = 0 " << endl;
+    MeshError(11,this);}
+  
+  TriangleAdjacent ta(0,0);
+  for (Int4 i = 0; i < nbe; i++) 
+    {
+      nbswp =  ForceEdge(edges[i][0],edges[i][1],ta);
+      
+      if ( nbswp < 0) 	k++;
+      else Nbswap += nbswp;
+      if (nbswp) nbfe++;
+      if ( nbswp < 0 && k < 5)
+      {
+         cerr << " Missing  Edge " << i << " v0 =  " << Number(edges[i][0]) << edges[i][0].r
+      	   <<" v1= " << Number(edges[i][1]) << edges[i][1].r << " " << edges[i].on->Cracked() << "  " << (Triangle *) ta ;
+	  if(ta.t)
+	  {
+	      Vertex *aa = ta.EdgeVertex(0), *bb = ta.EdgeVertex(1);  
+	      cerr << " crossing with  [" << Number(aa) << ", " << Number(bb) << "]\n";
+	  }
+	  else cerr << endl;
+	   
+      }
+      if ( nbswp >=0 && edges[i].on->Cracked())
+	  ta.SetCracked();
+    }
+		  
+  
+  if (k!=0) {
+    cerr << " they is " << k << " lost edges " << endl;
+    cerr << " The boundary is crossing may be!" << endl;
+    MeshError(10,this);
+  }
+  for (Int4 j=0;j<nbv;j++)
+    Nbswap +=  vertices[j].Optim(1,0);
+  if (verbosity > 3)
+    cout << "     Nb of inforced edge = " << nbfe << " Nb of Swap " << Nbswap << endl;
+
+}
+
+void Triangles::FindSubDomain(int OutSide=0)
+{
+    //#define DRAWING1
+    
+    if (verbosity >2)
+    {
+	if (OutSide)
+	    cout << "  -- Find all external sub-domain ";	
+	else
+	    cout << "  -- Find all internal sub-domain ";
+      if(verbosity>99)
+	{
+	  
+	  for(int i=0;i<nbt;++i)
+	      cout << i<< " " << triangles[i] << endl;
+	}
+	
+    }
+    // if (verbosity > 4) cout << " OutSide=" << OutSide << endl;
+    short * HeapArete = new short[nbt];
+    Triangle  **  HeapTriangle = new Triangle*  [nbt];
+    Triangle *t,*t1;
+    Int4 k,it;
+    
+    for (Int4 itt=0;itt<nbt;itt++) 
+	triangles[itt].link=0; // par defaut pas de couleur
+#ifdef DRAWING1
+    reffecran();
+#endif
+    
+    Int4  NbSubDomTot =0;
+    for ( it=0;it<nbt;it++)  { 
+	if ( ! triangles[it].link  ) {
+	    t = triangles + it;
+	    NbSubDomTot++;; // new composante connexe
+	    Int4 i = 0; // niveau de la pile 
+	    t->link = t ; // sd forme d'un triangle cicular link
+#ifdef DRAWING1
+	    t->Draw(NbSubDomTot-1);
+#endif
+	    
+	    
+	    HeapTriangle[i] =t ; 
+	    HeapArete[i] = 3;
+	    
+	    while (i >= 0) // boucle sur la pile
+	    { while ( HeapArete[i]--) // boucle sur les 3 aretes 
+	    { 
+		int na =  HeapArete[i];
+		Triangle * tc =  HeapTriangle[i]; // triangle courant
+		if( ! tc->Locked(na)) // arete non frontiere
+		{
+		    Triangle * ta = tc->TriangleAdj(na) ; // næ triangle adjacent
+		    if (ta->link == 0 ) // non deja chainer => on enpile
+		    { 
+			i++;
+#ifdef DRAWING1
+			ta->Draw(NbSubDomTot-1);
+#endif
+			ta->link = t->link ;  // on chaine les triangles
+			t->link = ta ;  // d'un meme sous domaine          
+			HeapArete[i] = 3; // pour les 3 triangles adjacents
+			HeapTriangle[i] = ta;
+		    }}
+	    } // deplie fin de boucle sur les 3 adjacences
+		i--;
+	    }          
+	}      
+    }
+    
+    // supression de tous les sous domaine infini <=>  contient le sommet NULL
+    it =0;
+    NbOutT = 0;
+    while (it<nbt) {
+	if (triangles[it].link) 
+	{ 
+	    if (!( triangles[it](0) &&  triangles[it](1) &&  triangles[it](2) )) 
+	    {
+		// infini triangle 
+		NbSubDomTot --;
+		//  cout << " triangle infini " << it << triangles[it] << endl;
+		t=&triangles[it];
+		NbOutT--;  // on fait un coup de trop. 
+		while  (t){ // cout << Number(t) << " " << endl;
+		    NbOutT++;
+		    t1=t;
+		    t=t->link;
+		    t1->link=0;}//while (t)
+	    }
+	}   
+	it++;} // end while (it<nbt)
+    if (nbt == NbOutT ||  !NbSubDomTot) 
+    {
+	cout << "\n error : " <<  NbOutT << " " << NbSubDomTot <<" " << nbt << endl;
+	cerr << "Error: The boundary is not close => All triangles are outside " << endl;
+	MeshError(888,this);
+    }
+    
+    delete [] HeapArete;
+    delete [] HeapTriangle;
+    
+    
+    if (OutSide|| !Gh.subdomains || !Gh.NbSubDomains ) 
+    { // No geom sub domain
+	Int4 i;
+	if (subdomains) delete [] subdomains;
+	subdomains = new SubDomain[ NbSubDomTot];
+	NbSubDomains=  NbSubDomTot;
+	for ( i=0;i<NbSubDomains;i++) {
+	    subdomains[i].head=NULL;
+	    subdomains[i].ref=i+1;
+	}
+	Int4 * mark = new Int4[nbt];
+	for (it=0;it<nbt;it++)
+	    mark[it]=triangles[it].link ? -1 : -2;
+	
+	it =0;
+	k = 0;
+	while (it<nbt) {
+	    if (mark[it] == -1) {
+		t1 = & triangles[it];
+		t = t1->link;
+		mark[it]=k;
+#ifdef DRAWING1  
+		t1->Draw(k);
+#endif
+		subdomains[k].head = t1;
+		// cout << " New -- " << Number(t1) << " " << it << endl;
+		do {// cout << " k " << k << " " << Number(t) << endl;
+		    mark[Number(t)]=k;
+#ifdef DRAWING1  
+		    t->Draw(k);
+#endif
+		    t=t->link;
+		} while (t!=t1);
+#ifdef DRAWING1  
+		t1->Draw(k);
+#endif
+		mark[it]=k++;}
+	    //    else if(mark[it] == -2 ) triangles[it].Draw(999);
+	    it++;} // end white (it<nbt)
+	assert(k== NbSubDomains);
+	if(OutSide) 
+	{
+	    //  to remove all the sub domain by parity adjacents
+	    //  because in this case we have only the true boundary edge
+	    // so teh boundary is manifold
+	    Int4 nbk = NbSubDomains;
+	    while (nbk)
+		for (it=0;it<nbt && nbk ;it++)
+		    for (int na=0;na<3 && nbk ;na++)
+		    {
+			Triangle *ta = triangles[it].TriangleAdj(na);
+			Int4 kl = ta ? mark[Number(ta)] : -2;
+			Int4 kr = mark[it];
+			if(kr !=kl) {
+			    //cout << kl << " " << kr << " rl "  << subdomains[kl].ref
+			    // << " rr " << subdomains[kr].ref ;
+			    if (kl >=0 && subdomains[kl].ref <0 && kr >=0 && subdomains[kr].ref>=0)
+				nbk--,subdomains[kr].ref=subdomains[kl].ref-1;
+			    if (kr >=0 && subdomains[kr].ref <0 && kl >=0 && subdomains[kl].ref>=0)
+				nbk--,subdomains[kl].ref=subdomains[kr].ref-1;
+			    if(kr<0 && kl >=0 && subdomains[kl].ref>=0)
+				nbk--,subdomains[kl].ref=-1;
+			    if(kl<0 && kr >=0 && subdomains[kr].ref>=0)
+				nbk--,subdomains[kr].ref=-1;
+			    //   cout << " after \t "   
+			    //	 << kl << subdomains[kl].ref << " rr " << kr 
+			    // << subdomains[kr].ref << endl;
+			}
+		    }
+			//  cout << subdomains[0].ref << subdomains[1].ref << endl;
+			Int4  j=0;
+	    for ( i=0;i<NbSubDomains;i++)
+		if((-subdomains[i].ref) %2) { // good 
+					      //cout << " sudom ok  = " << i << " " << subdomains[i].ref
+					      // << " " << (-subdomains[i].ref) %2 << endl;
+		    if(i != j) 
+			Exchange(subdomains[i],subdomains[j]);
+		    j++;}
+		    else
+		    { //cout << " remove sub domain " << i << endl;
+			t= subdomains[i].head;
+			while  (t){// cout << Number(t) << " " << endl;
+			    NbOutT++;
+			    t1=t;
+			    t=t->link;
+			    t1->link=0;}//while (t)
+		    }
+		    
+		    if(verbosity>4)
+			cout << " Number of remove sub domain (OutSideMesh) =" << NbSubDomains-j << endl;
+	    NbSubDomains=j;
+	}
+	
+	delete []  mark; 
+	
+    }
+    else
+    { // find the head for all sub domaine
+	if (Gh.NbSubDomains != NbSubDomains && subdomains)
+	    delete [] subdomains, subdomains=0;
+	if (! subdomains  ) 
+	    subdomains = new SubDomain[ Gh.NbSubDomains];
+	NbSubDomains =Gh.NbSubDomains;
+	if(verbosity>4)
+	    cout << "     find the " << NbSubDomains << " sub domain " << endl;
+	Int4 err=0;
+	ReMakeTriangleContainingTheVertex();
+	Int4 * mark = new Int4[nbt];
+	Edge **GeometricalEdgetoEdge = MakeGeometricalEdgeToEdge();
+        
+	for (it=0;it<nbt;it++)
+	    mark[it]=triangles[it].link ? -1 : -2;
+	Int4 inew =0;
+	for (Int4 i=0;i<NbSubDomains;i++) 
+	{
+	    GeometricalEdge &eg = *Gh.subdomains[i].edge;
+	    subdomains[i].ref = Gh.subdomains[i].ref;
+	    int ssdlab = subdomains[i].ref;
+	    // by carefull is not easy to find a edge create from a GeometricalEdge 
+	    // see routine MakeGeometricalEdgeToEdge
+	    Edge &e = *GeometricalEdgetoEdge[Gh.Number(eg)];
+	    assert(&e);
+	    Vertex * v0 =  e(0),*v1 = e(1);
+	    Triangle *t  = v0->t;
+	    int sens = Gh.subdomains[i].sens;
+	    // test if ge and e is in the same sens 
+	    //	cout << " geom edge = " <<  Gh.Number(eg) <<" @" << &eg << " ref = " << subdomains[i].ref 
+	    //     << " ref edge =" << eg.ref << " sens " << sens ;
+	    if (((eg[0].r-eg[1].r),(e[0].r-e[1].r))<0)
+		sens = -sens ;
+	    subdomains[i].sens = sens;
+	    subdomains[i].edge = &e;
+	    //	cout << " sens " << sens << " in geom " << eg[0].r << eg[1].r << " in mesh  " << e[0].r << e[1].r << endl;
+	    //	cout << "  v0 , v1 = " << Number(v0) << " "  << Number(v1) << endl;
+	    assert(t && sens);
+	    
+	    TriangleAdjacent  ta(t,EdgesVertexTriangle[v0->vint][0]);// previous edges
+		
+	    while (1) 
+	    {
+		assert( v0 == ta.EdgeVertex(1) );
+		//	 cout << " recherche " << Number( ta.EdgeVertex(0)) << endl;
+		if (ta.EdgeVertex(0) == v1) { // ok we find the edge
+		    if (sens>0)  
+			subdomains[i].head=t=Adj(ta);
+		    else 
+			subdomains[i].head=t=ta;
+		    //cout << "      triangle  =" << Number(t) << " = " << (*t)[0].r <<  (*t)[1].r <<  (*t)[2].r << endl;
+		    if(t<triangles || t >= triangles+nbt || t->det < 0 
+		        || t->link == 0) // Ajoute aout 200 
+		     {
+			cerr << " Error in the def of sub domain "<<i
+			     << " form border " << NbSubDomains - i  << "/" << NbSubDomains
+			     << ": Bad sens  " << Gh.Number(eg) <<" "<< sens <<  endl;  
+			err++;
+			break;}
+		    Int4 it = Number(t);
+		    if (mark[it] >=0) {
+			if(verbosity>10)
+			    cerr << "     Warning: the sub domain " << i << " ref = " << subdomains[i].ref 
+				<< " is previouly defined with "  <<mark[it] << " ref = " << subdomains[mark[it]].ref
+				<< " skip this def " << endl;
+			break;}
+		    if(i != inew) 
+			Exchange(subdomains[i],subdomains[inew]);
+		    inew++;
+		    Triangle *tt=t;
+		    Int4 kkk=0;
+		    do 
+		    {
+			kkk++;
+			assert(mark[Number(tt)]<0);
+#ifdef DRAWING1
+			tt->Draw(i);
+#endif
+			mark[Number(tt)]=i;
+			tt=tt->link;
+		    } while (tt!=t);
+		    if(verbosity>7)
+			cout << "     Nb de triangles dans le sous domaine " << i << " de ref " << subdomains[i].ref << " = " << kkk << endl;
+		    break;}
+		ta = Previous(Adj(ta));         
+		if(t == (Triangle *) ta) {
+		    err++;
+		    cerr << " Error in the def of sub domain " << i 
+			<< " edge=" << Gh.Number(eg) << " " << sens << endl;
+		    break;}
+		//         cout << " NB of remove subdomain " << NbSubDomTot-NbSubDomains<< endl;
+		
+	    }
+		
+	}
+	if (err) MeshError(777,this);
+	
+	if (inew < NbSubDomains) {
+	    if (verbosity>5) 
+		cout << "     Warning: We remove " << NbSubDomains-inew << " SubDomains " << endl;
+	    NbSubDomains=inew;}
+	
+	
+	for (it=0;it<nbt;it++)
+	    if ( mark[it] ==-1 ) 
+		NbOutT++,triangles[it].link =0;
+	delete [] GeometricalEdgetoEdge;
+	delete [] mark;
+	
+    }
+    
+#ifdef DRAWING1
+    inquire();
+#endif
+    NbOutT=0;
+    for (it=0;it<nbt;it++) 
+	if(!triangles[it].link)  NbOutT++;
+    if (verbosity> 4)
+	cout << "    " ;
+    if (verbosity> 2)
+	cout << " Nb of Sub borned Domain  = " <<  NbSubDomTot << " NbOutTriangles = " << NbOutT <<endl;
+#ifdef DRAWING1
+    inquire();
+#endif
+    
+    //#undef DRAWING1
+    
+    
+}
+void Triangles::ReNumberingVertex(Int4 * renu)
+{
+  // warning be carfull because pointeur
+  // from on mesh to over mesh 
+  //  --  so do ReNumbering a the beginning
+  Vertex * ve = vertices+nbv;
+  Int4 it,ie,i;
+  
+  for ( it=0;it<nbt;it++) 
+    triangles[it].ReNumbering(vertices,ve,renu);
+  
+  for ( ie=0;ie<nbe;ie++) 
+    edges[ie].ReNumbering(vertices,ve,renu);
+  
+  for (i=0;i< NbVerticesOnGeomVertex;i++)
+    {
+      Vertex *v = VerticesOnGeomVertex[i].mv;
+      if (v>=vertices && v < ve)
+	VerticesOnGeomVertex[i].mv=vertices+renu[Number(v)];
+    }
+  
+  for (i=0;i< NbVerticesOnGeomEdge;i++)
+    {
+      Vertex *v =VerticesOnGeomEdge[i].mv;
+      if (v>=vertices && v < ve)
+	 VerticesOnGeomEdge[i].mv=vertices+renu[Number(v)];
+    }
+
+  for (i=0;i< NbVertexOnBThVertex;i++)
+    {
+      Vertex *v=VertexOnBThVertex[i].v;
+      if (v>=vertices && v < ve)
+	VertexOnBThVertex[i].v=vertices+renu[Number(v)];
+    }
+  
+  for (i=0;i< NbVertexOnBThEdge;i++)
+    {
+      Vertex *v=VertexOnBThEdge[i].v;
+      if (v>=vertices && v < ve)
+	VertexOnBThEdge[i].v=vertices+renu[Number(v)];
+    }
+
+  // move the Vertices without a copy of the array 
+  // be carefull not trivial code 
+  Int4 j;
+  for ( it=0;it<nbv;it++) // for all sub cycles of the permutation renu
+    if (renu[it] >= 0) // a new sub cycle
+      { 
+        i=it;
+        Vertex ti=vertices[i],tj;
+        while ( (j=renu[i]) >= 0) 
+         { // i is old, and j is new 
+           renu[i] = -1-renu[i]; // mark 
+           tj = vertices[j]; // save new
+           vertices[j]= ti; // new <- old
+           i=j;     // next 
+           ti = tj;
+         }  
+     }
+  if (quadtree) 
+  {  delete quadtree;
+   quadtree = new QuadTree(this);
+  }
+ for ( it=0;it<nbv;it++)
+   renu[i]= -renu[i]-1;
+  
+}
+void Triangles::ReNumberingTheTriangleBySubDomain(bool justcompress)
+ {
+  Int4 *renu= new Int4[nbt];
+  register Triangle *t0,*t,*te=triangles+nbt;
+  register Int4 k=0,it,i,j;
+      
+  for ( it=0;it<nbt;it++) 
+    renu[it]=-1; // outside triangle 
+  for ( i=0;i<NbSubDomains;i++)
+   { 
+     t=t0=subdomains[i].head;
+     assert(t0); // no empty sub domain
+     do { 
+       Int4 kt = Number(t);
+       assert(kt>=0 && kt < nbt );
+       assert(renu[kt]==-1);
+       renu[kt]=k++;
+       }
+     while (t0 != (t=t->link));
+   }
+  if (verbosity>9)
+    cout << " number of inside triangles " << k << " nbt = " << nbt << endl;
+  // take is same numbering if possible    
+  if(justcompress)
+      for ( k=0,it=0;it<nbt;it++) 
+     if(renu[it] >=0 ) 
+       renu[it]=k++;
+   
+   // put the outside triangles at the end
+   for ( it=0;it<nbt;it++) 
+    if (renu[it]==-1) 
+      renu[it]=k++;
+      
+    assert(k == nbt);
+   // do the change on all the pointeur 
+   for ( it=0;it<nbt;it++)
+     triangles[it].ReNumbering(triangles,te,renu);
+     
+   for ( i=0;i<NbSubDomains;i++)
+     subdomains[i].head=triangles+renu[Number(subdomains[i].head)];
+   
+  // move the Triangles  without a copy of the array 
+  // be carefull not trivial code 
+  for ( it=0;it<nbt;it++) // for all sub cycles of the permutation renu
+    if (renu[it] >= 0) // a new sub cycle
+      { 
+        i=it;
+        Triangle ti=triangles[i],tj;
+        while ( (j=renu[i]) >= 0) 
+         { // i is old, and j is new 
+           renu[i] = -1; // mark 
+           tj = triangles[j]; // save new
+           triangles[j]= ti; // new <- old
+           i=j;     // next 
+           ti = tj;
+         }  
+     }
+   delete [] renu;
+   nt = nbt - NbOutT;
+
+#ifdef DEBUG
+// verif 
+     for ( it=0;it<nbt;it++)
+      triangles[it].check();
+#endif   
+ }
+Int4  Triangles::ConsRefTriangle(Int4 *reft) const
+{
+  assert(reft);
+  register Triangle *t0,*t;
+  register Int4 k=0, num;   
+  for (Int4 it=0;it<nbt;it++) 
+    reft[it]=-1; // outside triangle 
+  for (Int4 i=0;i<NbSubDomains;i++)
+   { 
+     t=t0=subdomains[i].head;
+     assert(t0); // no empty sub domain
+     // register Int4 color=i+1;// because the color 0 is outside triangle
+     do { k++;
+       num = Number(t);
+       assert(num>=0 &&num < nbt);
+       reft[num]=i;
+       //  cout << Number(t0) << " " <<Number(t)<< " "  << i << endl;
+       }
+     while (t0 != (t=t->link));
+   }
+  //  NbOutT = nbt - k;
+  if (verbosity>5) 
+    cout << " Nb of Sub Domain =" << NbSubDomains  << " Nb of In Triangles " << k 
+	 << " Nbt = " << nbt << " Out Triangles = " << nbt - k <<  endl;
+   
+  return k;   
+
+}
+
+/*
+void Triangles::ConsLinkTriangle()
+{
+  for (Int4 i=0;i<NbSubDomains;i++)
+    subdomains[i].head=0;
+  register Triangle * t=triangles,*tend = triangles+nbt,*hst;
+  for (;t<tend;t++)
+   {  
+       if (t->link) 
+        {
+          register Int4 color = t->color-1;
+          assert(color<NbSubDomains && color>=0);
+          if (hst=subdomains[color].head) {
+            t->link=hst->link;
+            hst->link=t; }
+          else {
+            subdomains[color].head = t;
+            t->link=t;}// circular link         
+        }
+     }
+ {
+   for (Int4 i=0;i<NbSubDomains;i++)
+     assert(subdomains[i].head);
+ }
+   
+}
+*/
+/* void Triangles::RandomInit() 
+{ 
+ //  Meshbegin = vertices;
+ //  Meshend  = vertices + nbvx;
+   nbv = nbvx;
+   for (int i = 0; i < nbv; i++)
+     {
+        vertices[i].r.x= rand();
+        vertices[i].r.y= rand();
+        vertices[i].ref = 0;
+     }
+}
+void Triangles::CubeInit(int n,int m) 
+{ 
+  //  nbvx = n*m;
+ //  Meshbegin = vertices;
+  // Meshend  = vertices + nbvx;
+   nbv = n*m;
+   assert(nbv <= nbvx);
+   int k =0;
+   for (int i = 0; i < n; i++)
+   for (int j = 0; j < m; j++)
+     {
+        vertices[k].r.x= i;
+        vertices[k].r.y= j;
+        vertices[k++].ref = 0;
+     }
+}
+*/
+Vertex * Triangles::NearestVertex(Icoor1 i,Icoor1 j) 
+   { return  quadtree->NearestVertex(i,j); } 
+
+
+void Triangles::PreInit(Int4 inbvx,char *fname)
+{
+  srand(19999999);
+  OnDisk =0;
+  NbRef=0;
+  //  allocGeometry=0;
+  identity=0;
+  NbOfTriangleSearchFind =0;
+  NbOfSwapTriangle =0;
+  nbiv=0;
+  nbv=0;
+  nbvx=inbvx;
+  nbt=0;
+  NbOfQuad = 0;
+  nbtx=2*inbvx-2;
+  NbSubDomains=0;
+  NbVertexOnBThVertex=0;
+  NbVertexOnBThEdge=0;
+  VertexOnBThVertex=0;
+  VertexOnBThEdge=0;
+  
+  NbCrackedVertices=0;
+  NbCrackedEdges =0;
+  CrackedEdges  =0;  
+  nbe = 0; 
+  name = fname ;
+
+  if (inbvx) {
+    vertices=new Vertex[nbvx];
+    assert(vertices);
+    ordre=new (Vertex* [nbvx]);
+    assert(ordre);
+    triangles=new Triangle[nbtx];
+    assert(triangles);}
+  else {
+    vertices=0;
+    ordre=0;
+    triangles=0;
+    nbtx=0;
+   }
+  if ( name || inbvx)
+    {
+      time_t timer =time(0);
+      char buf[70];     
+      strftime(buf ,70,", Date: %y/%m/%d %H:%M %Ss",localtime(&timer));
+      counter++; 
+      char countbuf[30];   
+      sprintf(countbuf,"%d",counter);
+      int lg =0 ;
+      if (&BTh != this && BTh.name)
+	lg = strlen(BTh.name)+4;
+      identity = new char[ lg + strlen(buf) + strlen(countbuf)+ 2  + 10 + ( Gh.name ? strlen(Gh.name) + 4 : 0)];
+      identity[0]=0;
+      if (lg)
+	strcat(strcat(strcat(identity,"B="),BTh.name),", ");
+
+      if (Gh.name)
+	strcat(strcat(identity,"G="),Gh.name);
+      strcat(strcat(identity,";"),countbuf);
+      strcat(identity,buf);
+      // cout << "New MAILLAGE "<< identity << endl;
+    } 
+  
+  quadtree=0;
+//  edgescomponante=0;
+  edges=0;
+  VerticesOnGeomVertex=0;
+  VerticesOnGeomEdge=0;
+  NbVerticesOnGeomVertex=0;
+  NbVerticesOnGeomEdge=0;
+//  nbMaxIntersectionTriangles=0;
+//  lIntTria;
+  subdomains=0;
+  NbSubDomains=0;
+//  Meshbegin = vertices;
+//  Meshend  = vertices + nbvx;
+  if (verbosity>98) 
+    cout << "Triangles::PreInit() " << nbvx << " " << nbtx 
+	 << " " << vertices 
+	 << " " << ordre << " " <<  triangles <<endl;
+
+}
+
+void Triangles::GeomToTriangles1(Int4 inbvx,int KeepBackVertices) 
+{ 
+//#define DRAWING1
+  Gh.NbRef++;// add a ref to Gh
+
+  
+/************************************************************************* 
+// methode in 2 step
+// 1 - compute the number of new edge to allocate
+// 2 - construct the edge
+ remark: 
+  in this part we suppose to have a background mesh with the same
+  geometry 
+  
+  To construct the discretisation of the new mesh we have to 
+  rediscretize the boundary of background Mesh 
+  because we have only the pointeur from the background mesh to the geometry.
+  We need the abcisse of the background mesh vertices on geometry
+  so a vertex is 
+  0 on GeometricalVertex ;
+  1 on GeometricalEdge + abcisse
+  2 internal 
+  
+  *************************************************************************/
+  assert(&BTh.Gh == &Gh);
+
+ // if(verbosity==100) Gh.Write("/tmp/gg.gmsh");
+  BTh.NbRef++; // add a ref to BackGround Mesh
+  PreInit(inbvx);
+  BTh.SetVertexFieldOn();
+#ifdef DRAWING
+  if (withrgraphique)
+   { BTh.InitDraw();
+  reffecran(); 
+  CurrentTh = this;}
+#endif
+  int * bcurve = new int[Gh.NbOfCurves]; // 
+  
+  // we have 2 ways to make the loop 
+  // 1) on the geometry 
+  // 2) on the background mesh
+  //  if you do the loop on geometry, we don't have the pointeur on background,
+  //  and if you do the loop in background we have the pointeur on geometry
+  // so do the walk on  background
+  //  Int4 NbVerticesOnGeomVertex;
+  //  VertexOnGeom * VerticesOnGeomVertex;  
+  //  Int4 NbVerticesOnGeomEdge;
+  //  VertexOnGeom * VerticesOnGeomEdge;
+  
+  
+  NbVerticesOnGeomVertex=0;
+  NbVerticesOnGeomEdge=0;
+  //1 copy of the  Required vertex
+  int i; 
+  for ( i=0;i<Gh.nbv;i++)
+    if (Gh[i].Required()) NbVerticesOnGeomVertex++;
+  
+  VerticesOnGeomVertex = new VertexOnGeom[NbVerticesOnGeomVertex];
+  VertexOnBThVertex = new VertexOnVertex[NbVerticesOnGeomVertex];
+  //
+  if( NbVerticesOnGeomVertex >= nbvx) 
+    {
+      cerr << " Too much vertices on geometry " << NbVerticesOnGeomVertex << " >= " << nbvx << endl; 
+      MeshError(1,this);
+    }
+  assert(vertices);
+  for (i=0;i<Gh.nbv;i++)
+    if (Gh[i].Required()) {//Gh  vertices Required
+        vertices[nbv] =  Gh[i];
+        vertices[nbv].i = I2(0,0);
+        Gh[i].to = vertices + nbv;// save Geom -> Th
+        VerticesOnGeomVertex[nbv]= VertexOnGeom(vertices[nbv],Gh[i]);
+	// cout << "--------- "  <<Number(Gh[i].to) << " " << Gh[i].to << " " << i << endl;
+	nbv++;}
+    else Gh[i].to=0;
+  // 
+  for (i=0;i<BTh.NbVerticesOnGeomVertex;i++)
+    { 
+      VertexOnGeom & vog = BTh.VerticesOnGeomVertex[i];
+      if (vog.IsRequiredVertex()) {
+	 GeometricalVertex * gv = vog;
+	 Vertex *bv = vog;
+	 assert(gv->to);// use of Geom -> Th
+	 VertexOnBThVertex[NbVertexOnBThVertex++] = VertexOnVertex(gv->to,bv);
+	 gv->to->m = bv->m; // for taking the metrix of the background mesh
+	 ;}
+    }
+  assert(NbVertexOnBThVertex == NbVerticesOnGeomVertex);
+// new stuff FH with curve
+//  find the begin of the curve in BTh
+{
+  Gh.UnMarkEdges();	
+  int bfind=0;
+/*
+   cout << " nb curves = " << Gh.NbOfCurves << endl;
+   for(int i=0;i<Gh.NbOfCurves ;i++)
+     {
+        cout << " Curve " << i << " begin e=" << Gh.Number(Gh.curves[i].be) << " k=" << Gh.curves[i].kb 
+             << "  end e= " << Gh.Number(Gh.curves[i].ee) << " k=" << Gh.curves[i].ke << endl;
+     }*/
+  for (int i=0;i<Gh.NbOfCurves;i++)
+   {
+    bcurve[i]=-1; 
+   }
+  
+  for (int iedge=0;iedge<BTh.nbe;iedge++) 
+    {      
+      Edge & ei = BTh.edges[iedge];
+      for(int je=0;je<2;je++) // for the 2 extremites
+	 if (!ei.on->Mark() && ei[je].on->IsRequiredVertex() )
+	    {
+	      // a begin of curve 
+	      int nc = ei.on->CurveNumber;
+	      
+	      //cout << "curve " <<  nc << " v " << Gh.Number((GeometricalVertex *) *ei[je].on) << " "
+	      //     << " e "  << " " << Gh.Number(ei.on) << " vc " << Gh.Number((*Gh.curves[nc].be)[Gh.curves[nc].kb]) << endl;
+	      if(
+	         ei.on==Gh.curves[nc].be    && 
+	         (GeometricalVertex *) *ei[je].on == &(*Gh.curves[nc].be)[Gh.curves[nc].kb] //  same extremity 
+	         )     
+	        { 
+	        // cout << " find " << endl;
+	         bcurve[nc]=iedge*2+je;
+	         bfind++;	
+	        }      
+            }
+    } 
+   assert( bfind==Gh.NbOfCurves);
+}          
+// method in 2 + 1 step 
+//  0.0) compute the length and the number of vertex to do allocation
+//  1.0)  recompute the length
+//  1.1)   compute the  vertex 
+  Int4 nbex=0,NbVerticesOnGeomEdgex=0;
+  for (int step=0; step <2;step++)
+    {
+      Int4 NbOfNewPoints=0;
+      Int4 NbOfNewEdge=0;
+      Int4 iedge;
+      Gh.UnMarkEdges();	
+/*   add Curve loop  FH    
+      // find a starting back groud edges to walk 
+      for (iedge=0;iedge<BTh.nbe;iedge++) {      
+	    Edge & ei = BTh.edges[iedge];
+	    for(int jedge=0;jedge<2;jedge++) // for the 2 extremites
+	     if (!ei.on->Mark() && ei[jedge].on->IsRequiredVertex() )
+	    {
+*/  
+// new code FH 2004 
+       Real8 L=0;
+       for (int icurve=0;icurve<Gh.NbOfCurves;icurve++)
+            { 
+              iedge=bcurve[icurve]/2;
+              int jedge=bcurve[icurve]%2;
+              if( ! Gh.curves[icurve].master) continue; // we skip all equi curve
+	      Edge & ei = BTh.edges[iedge];
+	      // warning: ei.on->Mark() can be change in
+	      // loop for(jedge=0;jedge<2;jedge++) 
+	      // new curve  
+	      // good the find a starting edge 
+	      Real8 Lstep=0,Lcurve=0;// step between two points   (phase==1) 
+	      Int4 NbCreatePointOnCurve=0;// Nb of new points on curve     (phase==1) 
+
+	      
+	      //    cout.precision(16);
+	      for(int phase=0;phase<=step;phase++) 
+		{
+
+		  for(Curve * curve= Gh.curves+icurve;curve;curve= curve->next)
+		     {
+
+		    int icurveequi= Gh.Number(curve);
+  
+                   if( phase == 0 &&  icurveequi != icurve)  continue;
+
+                  int k0=jedge,k1;
+                  Edge * pe=  BTh.edges+iedge;
+		  //GeometricalEdge *ong = ei.on;
+                   int iedgeequi=bcurve[icurveequi]/2;
+                   int jedgeequi=bcurve[icurveequi]%2;
+
+                  int k0equi=jedgeequi,k1equi;		  
+                  Edge * peequi= BTh.edges+iedgeequi;
+		  GeometricalEdge *ongequi = peequi->on;
+		  
+                  Real8 sNew=Lstep;// abcisse of the new points (phase==1) 
+                  L=0;// length of the curve
+                  Int4 i=0;// index of new points on the curve
+                  register GeometricalVertex * GA0 = *(*peequi)[k0equi].on;
+                  Vertex *A0;
+                  A0 = GA0->to;  // the vertex in new mesh
+                  Vertex *A1;
+		  VertexOnGeom *GA1;
+                  Edge * PreviousNewEdge = 0;
+		  //  cout << "  --------------New Curve phase " << phase 
+		  //       << "---------- A0=" << *A0 << ei[k0]  <<endl;
+                  assert (A0-vertices>=0 && A0-vertices <nbv);
+                  if(ongequi->Required() ) 
+                        {
+                         GeometricalVertex *GA1 = *(*peequi)[1-k0equi].on;
+                         A1 = GA1->to;  //
+                        }       
+                  else 
+                  for(;;) 
+		    {
+		      //   assert(pe && BTh.Number(pe)>=0 && BTh.Number(pe)<=BTh.nbe);
+		      Edge &ee=*pe; 
+		      Edge &eeequi=*peequi; 
+		      k1 = 1-k0; // next vertex of the edge 
+		      k1equi= 1 - k0equi;
+		      
+		      assert(pe  && ee.on);
+		      ee.on->SetMark();
+		      Vertex & v0=ee[0], & v1=ee[1];
+		      R2 AB= (R2) v1 - (R2) v0;
+		      Real8 L0=L,LAB;
+		      LAB =  LengthInterpole(v0.m,v1.m,AB);
+		      L+= LAB;    
+		      if (phase) {// computation of the new points
+			while ((i!=NbCreatePointOnCurve) && sNew <= L) { 
+			  //    cout  << " L0= " << L0 << " L " << L << " sN=" 
+			  //         << sNew << " LAB=" << LAB << " NBPC =" <<NbCreatePointOnCurve<< " i " << i  << endl;
+			  assert (sNew >= L0);
+			  assert(LAB);
+			  
+			  
+			  assert(vertices && nbv<nbvx);
+			  assert(edges && nbe < nbex);
+			  assert(VerticesOnGeomEdge && NbVerticesOnGeomEdge < NbVerticesOnGeomEdgex);
+			  // new vertex on edge
+			  A1=vertices+nbv++;
+			  GA1=VerticesOnGeomEdge+NbVerticesOnGeomEdge;
+			  Edge *e = edges + nbe++;
+			  Real8 se= (sNew-L0)/LAB;
+			  assert(se>=0 && se < 1.000000001);
+#ifdef DEBUG
+			  se =  abscisseInterpole(v0.m,v1.m,AB,se); // because code \ref(xxx)
+#else
+			  se =  abscisseInterpole(v0.m,v1.m,AB,se,1);
+#endif
+			  assert(se>=0 && se <= 1);
+			  //((k1==1) != (k1==k1equi))
+			  se = k1 ? se : 1. - se;
+			  se = k1==k1equi ? se : 1. - se;
+			  VertexOnBThEdge[NbVerticesOnGeomEdge++] = VertexOnEdge(A1,&eeequi,se); // save 
+			  ongequi = Gh.ProjectOnCurve(eeequi,se,*A1,*GA1); 
+			  A1->ReferenceNumber = eeequi.ref;
+			  A1->DirOfSearch =NoDirOfSearch;
+			  //cout << icurveequi << " " << i << " " <<  *A1 << endl;
+			  e->on = ongequi;
+			  e->v[0]=  A0;
+			  e->v[1]=  A1;
+			  if(verbosity>99)
+				cout << i << "+ New P "<< nbv-1 << " "  <<sNew<< " L0=" << L0 
+				<< " AB=" << LAB << " s=" << (sNew-L0)/LAB << " se= "  
+				<< se <<" B edge " << BTh.Number(ee) << " signe = " << k1 <<" " << A1->r <<endl;
+			    
+#ifdef DEBUG
+			  // code \label(xxx)
+			    R2  A1A0 = A1->r - A0->r;
+			    Real8 dp = LengthInterpole(A0->m,A1->m,A1A0);
+			    if (dp > 1.4) {
+			      cerr << " PB new Points "<< nbv-1 ;
+			      cerr << " AB=" << LAB << " s=" << (sNew-L0)/LAB << " se= "  ;
+			      cerr << se <<" B edge " << BTh.Number(ee) << " signe = " << k1 <<endl;	      
+			      cerr << " PB calcul new on cuver points trop loin l=" << dp 
+				   << " v=" << nbv-1 << " " << nbv-2 << " Lcurve = " << Lcurve << AB <<v0.m<< v1.m <<endl;
+			    }
+
+#endif
+			  e->ref = eeequi.ref;
+			  e->adj[0]=PreviousNewEdge;
+			  
+			  if (PreviousNewEdge)
+			    PreviousNewEdge->adj[1] =  e;
+			  PreviousNewEdge = e;
+#ifdef DRAWING1
+			  e->Draw();
+			  //         A0->Draw();
+			  A1->m.Draw(*A1);
+			  A1->Draw(Number(A1));
+#endif
+			  A0=A1;
+			  sNew += Lstep;
+			  //   cout << " sNew = " << sNew << " L = " << L 
+			  //        << "  ------" <<NbCreatePointOnCurve << " " << i <<  endl;
+			  if (++i== NbCreatePointOnCurve) break;
+			}
+			
+		      }               
+		      assert(ee.on->CurveNumber==ei.on->CurveNumber);
+		      if(verbosity>98) cout <<  BTh.Number(ee) << " " << " on=" << *ee[k1].on << " "<< ee[k1].on->IsRequiredVertex() <<  endl;
+		      if ( ee[k1].on->IsRequiredVertex()) {
+		         assert(eeequi[k1equi].on->IsRequiredVertex());
+			register GeometricalVertex * GA1 = *eeequi[k1equi].on;
+			A1=GA1->to;// the vertex in new mesh
+			assert (A1-vertices>=0 && A1-vertices <nbv);
+			break;}
+		      if (!ee.adj[k1])
+			{cerr << "Error adj edge " << BTh.Number(ee) << ", nbe = "  << nbe 
+			      << " Gh.vertices " << Gh.vertices 
+			      << " k1 = " << k1 << " on=" << *ee[k1].on << endl;
+			cerr << ee[k1].on->gv-Gh.vertices << endl;
+			}
+		      pe = ee.adj[k1]; // next edge
+		      k0 = pe->Intersection(ee); 
+		      peequi= eeequi.adj[k1equi];  // next edge
+		      k0equi=peequi->Intersection(eeequi);            
+		    }// for(;;) end of the curve
+		  
+
+		  if (phase) // construction of the last edge
+                    {
+		      Edge *e = edges + nbe++;
+		      if (verbosity>10) 
+			cout << " Fin curve A1" << *A1 << " " << icurve << " <=> " << icurveequi <<"-----" <<
+			  NbCreatePointOnCurve << " == " <<i<<endl;
+                      e->on  = ongequi;
+                      e->v[0]=  A0;
+                      e->v[1]=	A1;
+                      e->ref = peequi->ref;
+                      e->adj[0]=PreviousNewEdge;
+                      e->adj[1]=0;
+                      if (PreviousNewEdge)
+			PreviousNewEdge->adj[1] =  e;
+                      PreviousNewEdge = e;
+		      //		      cout << "Last new edge " << nbe << " " << " on " << Gh.Number(pe->on) 
+		      //   << " of curve =" <<pe->on->CurveNumber <<endl;
+	    
+
+#ifdef DRAWING1 
+                      e->Draw();
+                      A1->Draw();
+                      A0->Draw();
+		      //                      inquire();
+#endif
+                      assert(i==NbCreatePointOnCurve);
+  
+                    }
+		   } //  end loop on equi curve 
+                     
+		  if (!phase)  { // 
+		    Int4 NbSegOnCurve = Max((Int4)(L+0.5),(Int4) 1);// nb of seg
+		    Lstep = L/NbSegOnCurve; 
+		    Lcurve = L;
+		    NbCreatePointOnCurve = NbSegOnCurve-1;
+		    
+		    for(Curve * curve= Gh.curves+icurve;curve;curve= curve->next)
+		     {
+		       NbOfNewEdge += NbSegOnCurve;
+		       NbOfNewPoints += NbCreatePointOnCurve;
+		     }
+		    if(verbosity>5)
+		      cout << icurve << " NbSegOnCurve = " <<  NbSegOnCurve << " Lstep=" 
+			   << Lstep <<" " << NbOfNewPoints<< " NBPC= " << NbCreatePointOnCurve <<endl;
+		    // do'nt 
+		    //  if(NbCreatePointOnCurve<1) break;
+		  }
+		}//for(phase;;)
+/*  modif FH add Curve class  		  
+	    }}//for (iedge=0;iedge<BTh.nbe;iedge++) 
+*/
+// new code Curve class  	
+     } //  end of curve loop 
+// end new code	    
+       // do the allocation
+    if(step==0) 
+      {
+	//if(!NbOfNewPoints) break;// nothing ????? bug 
+	if(nbv+NbOfNewPoints > nbvx) 
+	  {
+	    cerr << " Too much vertices on geometry " << nbv+NbOfNewPoints  << " >= " << nbvx << endl;
+	    MeshError(3,this);
+	  }
+	//cout << " NbOfNewEdge" << NbOfNewEdge << " NbOfNewPoints " << NbOfNewPoints << endl;
+	edges = new Edge[NbOfNewEdge];
+	nbex = NbOfNewEdge;
+	if(NbOfNewPoints) { // 
+	   VerticesOnGeomEdge = new VertexOnGeom[NbOfNewPoints];
+	   NbVertexOnBThEdge =NbOfNewPoints;
+	   VertexOnBThEdge = new  VertexOnEdge[NbOfNewPoints];
+	   NbVerticesOnGeomEdgex = NbOfNewPoints; }
+	NbOfNewPoints =0;
+	NbOfNewEdge = 0;
+      }
+    } // for(step;;)
+  assert(nbe);
+
+ delete [] bcurve;
+ 
+  
+#ifdef DRAWING1
+  reffecran();
+  InitDraw();
+  Draw();
+  inquire();
+#endif
+  
+  Insert();
+  ForceBoundary();
+  FindSubDomain();
+  
+#ifdef DRAWING1
+  reffecran();
+  Draw();
+  inquire();
+#endif
+  // NewPointsOld(*this) ;
+//  BTh.ReMakeTriangleContainingTheVertex(); //  FH change => put in NewPoints
+  //  for (Int4 iv=0;iv<BTh.nbv;iv++)
+  //    BTh[iv].i = toI2(BTh[iv].r);
+  NewPoints(BTh,KeepBackVertices) ;
+  CurrentTh = 0;
+//#undef  DRAWING1 
+}
+
+void Triangles::GeomToTriangles0(Int4 inbvx) 
+{
+  Gh.NbRef++;// add a ref to GH
+
+
+  Int4 i,NbOfCurves=0,NbNewPoints,NbEdgeCurve;
+  Real8 lcurve, lstep,s;
+#ifdef DRAWING
+ if (withrgraphique)
+   {
+  Gh.InitDraw() ;
+  CurrentTh = this; }
+#endif
+  
+  R2 AB;
+  GeometricalVertex *a,*b;
+  Vertex *va,*vb;
+  GeometricalEdge * e;
+  PreInit(inbvx);
+  int  background = &BTh != this;
+  //  int  SameGeom = background && (&BTh.Gh == &Gh);
+  nbv = 0;
+  NbVerticesOnGeomVertex=0;
+  NbVerticesOnGeomEdge=0;
+  for (i=0;i<Gh.nbv;i++)
+    if (Gh[i].Required() && Gh[i].IsThe() ) NbVerticesOnGeomVertex++;
+  VerticesOnGeomVertex = new VertexOnGeom[NbVerticesOnGeomVertex];  
+//
+  if( NbVerticesOnGeomVertex >= nbvx) 
+    {
+      cerr << " Too much vertices on geometry " << NbVerticesOnGeomVertex << " >= " << nbvx << endl;
+      MeshError(1,this);
+    }
+  for (i=0;i<Gh.nbv;i++)
+    if (Gh[i].Required()&& Gh[i].IsThe()  ) {//Gh  vertices Required
+      if (nbv < nbvx)
+	vertices[nbv] = Gh[i];
+      Gh[i].to = vertices + nbv;// save Geom -> Th
+      VerticesOnGeomVertex[nbv]= VertexOnGeom(*Gh[i].to,Gh[i]);
+    //  cout << "--------- "  <<Number(Gh[i].to) << " " << Gh[i].to << " " << i << endl;
+      nbv++;
+    }
+//  assert( Gh.nbv < nbvx);
+  
+  // Method in 2 step:  0 and 1 
+  // 1) compute de nb of edge 
+  // 2) construct the edge    
+  // generation of the curves
+  assert(! edges);
+#ifdef DRAWING1
+  reffecran();
+#endif
+// 2 step 
+// --step=0 to compute the number of edges + alloc at end
+// --step=1 to construct the edges
+  for (int step=0;step<2;step++) 
+    {//  for (int step=0;step<2;step++) 
+      Int4 nbex = 0;
+      nbe = 0;
+      Int4 NbVerticesOnGeomEdge0=NbVerticesOnGeomEdge;
+    //  cout <<  "  -------------- step =" << step << endl;
+      Gh.UnMarkEdges();	
+      NbOfCurves = 0;
+      for (i=0;i<Gh.nbe;i++) {
+	GeometricalEdge & ei = Gh.edges[i];   
+	if (!ei.Dup()) // a good curve (not dup )
+	for(int j=0;j<2;j++) 
+	  if (!ei.Mark() && ei[j].Required()) { 
+	    // warning ei.Mark() can be change in loop for(j=0;j<2;j++) 
+	    //  cout << " New curve = " << NbOfCurves << endl;
+	    Int4 nbvend  =0;
+	  
+           Edge * PreviousNewEdge=0;
+
+          lstep = -1;//to do not create points
+	  if(ei.Required())
+	    {
+	      if (j==0)
+		if(step==0)
+		  nbe++;
+		else
+		  { 
+		    e = & ei;
+		    a=ei(0)->The();
+		    b=ei(1)->The();
+		    assert(edges);
+		    edges[nbe].v[0]=a->to;
+		    edges[nbe].v[1]=b->to;;
+		    edges[nbe].ref = e->ref;
+		    edges[nbe].on = e;
+		    edges[nbe].adj[0] = 0;
+		    edges[nbe].adj[1] = 0;
+#ifdef DRAWING1
+		    edges[nbe].Draw();
+#endif
+		    nbe++;}
+	    }
+          else 
+	    { // on curve ------
+	      for ( int kstep=0;kstep<= step;kstep++)
+		{ // begin  for ( int kstep=0;kstep<= step;kstep++)
+		  // if 2nd step where 2 step
+		  // -- 1 compute le length of the curve
+		  // -- create the points and edge
+		  PreviousNewEdge=0;
+		  NbNewPoints=0;
+		  NbEdgeCurve=0;
+		  assert(nbvend < nbvx); 
+		  lcurve =0;
+		  s = lstep;
+		  int k=j;
+		  e = & ei;
+		  a=ei(k)->The();
+		  va = a->to;
+		  e->SetMark();
+		  //  cout << " New curve " ;
+		  
+		  // if SameGeo  We have go in the background geometry 
+		  // to find the discretisation of the curve
+		  
+		  for(;;) 
+		    { 
+		      k = 1-k;
+		      b= (*e)(k)->The();
+		      AB = b->r - a->r;
+		      Metric MA = background ? BTh.MetricAt(a->r) :a->m ;
+		      Metric MB =  background ? BTh.MetricAt(b->r) :b->m ;
+		      Real8 ledge = (MA(AB) + MB(AB))/2;
+		      // 
+		      const int MaxSubEdge = 10;
+		      int NbSubEdge = 1;
+		      Real8 lSubEdge[MaxSubEdge];
+		      R2 A,B;
+		      if (ledge < 1.5) 
+			lSubEdge[0] = ledge;
+		      else {
+			NbSubEdge = Min( MaxSubEdge, (int) (ledge +0.5));
+			A= a->r;
+			Metric MAs =MA,MBs;
+			// cout << " lSubEdge old=" << ledge 
+			//      << " new " << A << MA << endl;
+			ledge = 0; 
+			Real8 x =0, xstep= 1. /  NbSubEdge;
+			for (int kk=0; kk < NbSubEdge; kk++,A=B,MAs=MBs ) {
+			  x += xstep;
+			  B =  e->F(k ? x : 1-x);
+			  MBs= background ? BTh.MetricAt(B) :Metric(1-x, MA, x ,MB);
+			  AB = A-B;
+			  lSubEdge[kk]= (ledge += (MAs(AB)+MBs(AB))/2);
+			  // cout << "     " << lSubEdge[kk] << " x " << x  
+			  //      << " " << A << B << MA << MB<< endl ;
+			}
+			//  cout << endl;
+		      }
+		      
+		      Real8 lcurveb = lcurve+ ledge ;
+		      while (lcurve<=s && s <= lcurveb && nbv < nbvend)
+			{
+			  // New points
+			  
+			  // Real8 aa=(lcurveb-s)/ledge;
+			  // Real8 bb=(s-lcurve)/ledge;
+			  
+			  Real8 ss = s-lcurve;
+			  // 1) find the SubEdge containing ss by dichotomie
+			  int kk0=-1,kk1=NbSubEdge-1,kkk;
+			  Real8 ll0=0,ll1=ledge,llk;
+			  while (kk1-kk0>1)
+			    {
+			      if (ss < (llk=lSubEdge[kkk=(kk0+kk1)/2]))
+				kk1=kkk,ll1=llk;
+			      else
+				kk0=kkk,ll0=llk;}
+			  assert(kk1 != kk0);
+			  
+			  Real8 sbb = (ss-ll0  )/(ll1-ll0);
+			  Real8 bb = (kk1+sbb)/NbSubEdge, aa=1-bb;
+			  
+			  // new vertex on edge
+			  vb = &vertices[nbv++];
+			  vb->m = Metric(aa,a->m,bb,b->m);
+			  vb->ReferenceNumber = e->ref;
+			  vb->DirOfSearch =NoDirOfSearch;
+			  Real8 abcisse = k ? bb : aa;
+			  vb->r =  e->F( abcisse );
+			  VerticesOnGeomEdge[NbVerticesOnGeomEdge++]= VertexOnGeom(*vb,*e,abcisse);        
+			  
+			  // to take in account the sens of the edge
+			  
+			  s += lstep;
+			  edges[nbe].v[0]=va;
+			  edges[nbe].v[1]=vb;
+			  edges[nbe].ref = e->ref;
+			  edges[nbe].on = e;
+			  edges[nbe].adj[0] = PreviousNewEdge;
+			  if(PreviousNewEdge)
+			    PreviousNewEdge->adj[1] = &edges[nbe];
+#ifdef DRAWING1
+			  vb->Draw();
+			  edges[nbe].Draw();
+#endif
+			  PreviousNewEdge = edges + nbe;
+			  nbe++;
+#ifdef DEBUG1                 
+			  cout << " new points " << nbv-1 << " " << vb->r ;
+			  cout << " new edge " << nbe-1 << " " ;
+			  cout << va << vb <<  " kk0 = " << kk0 
+			       << " " << kk1 << " ss=" << ss ;
+			  cout << " " << sbb << endl;
+			  cout << "      " << aa << va->r << bb << vb->r 
+			       <<" length=" << Norme(va->r-vb->r) << endl;
+			  cout << "      s " << s << " lstep= " << lstep 
+			       << " ledge= " << ledge 
+			       << " lcurve= " << lcurve << endl;
+#endif
+			  va = vb;
+			}
+		      lcurve = lcurveb;
+		      e->SetMark();
+		      // cout << e-Gh.edges << ", " << k << " " 
+		      //      <<(*e)[k].r <<" " <<(*e)[1-k].r <<" " 
+		      //      << lcurve<< ";; " ;                          
+		      a=b;
+		      if (b->Required() ) break;
+		      int kprev=k;
+		      k = e->SensAdj[kprev];// next vertices
+		      e = e->Adj[kprev];
+		      assert(e);
+		    }// for(;;)
+		  vb = b->to;
+		  //            cout << endl;
+		  NbEdgeCurve = Max((Int4) (lcurve +0.5), (Int4) 1);
+		  NbNewPoints = NbEdgeCurve-1;
+		  if(!kstep)
+		    { NbVerticesOnGeomEdge0 += NbNewPoints;
+		    NbOfCurves++;}
+		  
+		  nbvend=nbv+NbNewPoints; 
+		  
+		  lstep = lcurve / NbEdgeCurve;
+		  //   cout <<"lstep " << lstep << " lcurve " 
+		  //    << lcurve << " NbEdgeCurve " << NbEdgeCurve << " " <<NbVerticesOnGeomEdge0<<" " <<NbVerticesOnGeomEdge<<" step =" <<step<<  endl;
+		} 
+	      // end of curve --
+	      if (edges) { // last edges of the curves 
+		edges[nbe].v[0]=va;
+		edges[nbe].v[1]=vb;
+		edges[nbe].ref = e->ref;
+		edges[nbe].on = e;
+		edges[nbe].adj[0] = PreviousNewEdge;
+		edges[nbe].adj[1] = 0;
+		if(PreviousNewEdge)
+		  PreviousNewEdge->adj[1] = & edges[nbe];
+		
+		
+#ifdef DRAWING1
+		edges[nbe].Draw();
+#endif
+		nbe++;}
+	      else
+		nbe += NbEdgeCurve;
+	    } // end on  curve ---
+	} // if (edges[i][j].Corner())  
+    } // for (i=0;i<nbe;i++)
+    if(!step) {
+     // cout << "edges " << edges << " VerticesOnGeomEdge " <<VerticesOnGeomEdge << endl;
+      assert(!edges);
+      assert(!VerticesOnGeomEdge);
+      edges = new Edge[nbex=nbe];
+      if(NbVerticesOnGeomEdge0)
+	VerticesOnGeomEdge = new VertexOnGeom[NbVerticesOnGeomEdge0];
+      assert(edges);
+      assert(VerticesOnGeomEdge || NbVerticesOnGeomEdge0 ==0);
+        // do the vertex on a geometrical vertex
+       NbVerticesOnGeomEdge0 = NbVerticesOnGeomEdge;       
+     }
+     else 
+       assert(NbVerticesOnGeomEdge == NbVerticesOnGeomEdge0);
+    //     cout << " Nb of Curves = " << NbOfCurves << "nbe = " << nbe 
+    //	  << "== " << nbex << "  nbv = " << nbv <<  endl;
+    assert(nbex=nbe);
+   } // for (step=0;step<2;step++)
+
+#ifdef DRAWING1
+  reffecran();
+  InitDraw();
+  Draw();
+  inquire();
+#endif
+ 
+  Insert();
+  ForceBoundary();
+  FindSubDomain();
+
+#ifdef DRAWING1
+  reffecran();
+  Draw();
+  inquire();
+#endif
+   // NewPointsOld(*this) ;
+    NewPoints(*this,0) ;
+  CurrentTh = 0;
+}
+
+Edge** Triangles::MakeGeometricalEdgeToEdge()
+ {
+  assert(Gh.nbe);
+  Edge **e= new (Edge* [Gh.nbe]);
+  
+  Int4 i;
+  for ( i=0;i<Gh.nbe ; i++)
+    e[i]=NULL;
+  for ( i=0;i<nbe ; i++) 
+    { 
+      Edge * ei = edges+i;
+      GeometricalEdge *on = ei->on; 
+      e[Gh.Number(on)] = ei;    
+    }
+  for ( i=0;i<nbe ; i++) 
+    for (int ii=0;ii<2;ii++) { 
+       Edge * ei = edges+i;
+       GeometricalEdge *on = ei->on;
+      int j= ii;
+      while (!(*on)[j].Required()) { 
+	//	cout << i << " " << ii << " j= " << j << " curve = " 
+	//           <<  on->CurveNumber << "  " << Gh.Number(on) << " on " << j 
+	//   << " s0 " << Gh.Number( (*on)[0]) << " s1  " << Gh.Number( (*on)[1]) 
+	//   << " ->  " ;
+       Adj(on,j); // next geom edge
+       j=1-j;
+       //       cout << Gh.Number(on) << "  " << j  << " e[ON] =  " <<  e[Gh.Number(on)] 
+       //    << " s0 " << Gh.Number( (*on)[0]) << " s1  " << Gh.Number( (*on)[1]) << endl; 
+       if (e[Gh.Number(on)])  break; // optimisation     
+       e[Gh.Number(on)] = ei; 
+       }
+   }
+
+  int kk=0;
+     for ( i=0;i<Gh.nbe ; i++)
+       if (!e[i]) 
+	 if(kk++<10) {
+	   cerr << " Bug -- the geometrical edge " << i << " is on no edge curve = " << Gh.edges[i].CurveNumber 
+		<< " s0 " << Gh.Number( Gh.edges[i][0]) << " s1  " << Gh.Number( Gh.edges[i][1]) << endl; 
+	 //	 assert( e[i]);
+       }
+  if(kk) MeshError(997,this);
+
+  return e;
+ }
+
+Triangles::~Triangles() 
+{
+  assert(NbRef<=0);
+  if (CurrentTh == this) CurrentTh=0;
+  if(verbosity>10)
+    cout << " ~Triangles "<< this  <<" "<< identity << endl;
+  if(vertices)  delete [] vertices;
+  if(edges)     delete [] edges;
+  if(triangles) delete [] triangles;
+  if(quadtree)  delete  quadtree;
+  if(ordre)     delete [] ordre;
+  if( subdomains) delete []  subdomains;
+  if (VerticesOnGeomEdge) delete [] VerticesOnGeomEdge;
+  if (VerticesOnGeomVertex) delete [] VerticesOnGeomVertex;
+  if (name) delete [] name;
+  if (identity) delete [] identity;
+  if (VertexOnBThVertex) delete [] VertexOnBThVertex;
+  if (VertexOnBThEdge) delete [] VertexOnBThEdge;
+  
+  if (&Gh) 
+    {
+      if (Gh.NbRef>0) Gh.NbRef--;
+      else if (Gh.NbRef==0) delete &Gh;
+    }
+  if (&BTh && (&BTh != this))
+    {
+      if (BTh.NbRef>0) BTh.NbRef--;
+      else if (BTh.NbRef==0) delete &BTh;
+    }
+  PreInit(0); // set all to zero 
+  
+}
+
+void Triangles::SetIntCoor(const char * strfrom)
+{
+    pmin =  vertices[0].r;
+    pmax =  vertices[0].r;
+
+    // recherche des extrema des vertices pmin,pmax
+    Int4 i;
+    for (i=0;i<nbv;i++) {
+      pmin.x = Min(pmin.x,vertices[i].r.x);
+      pmin.y = Min(pmin.y,vertices[i].r.y);
+      pmax.x = Max(pmax.x,vertices[i].r.x);
+      pmax.y = Max(pmax.y,vertices[i].r.y);
+    }
+    R2 DD = (pmax-pmin)*0.05;
+    pmin = pmin-DD;
+    pmax = pmax+DD; 
+    coefIcoor= (MaxICoor)/(Max(pmax.x-pmin.x,pmax.y-pmin.y));
+    assert(coefIcoor >0);
+
+    // generation of integer coord  
+    for (i=0;i<nbv;i++) {
+      vertices[i].i = toI2(vertices[i].r);    
+    }
+#ifdef DRAWING
+    xGrafCoef = coefIcoor;
+    yGrafCoef = coefIcoor;
+    xGrafOffSet = pmin.x;
+    yGrafOffSet = pmin.y;
+#ifdef DRAWING1
+    rattente(1);
+#endif
+#endif
+
+    // computation of the det 
+    int Nberr=0;
+    for (i=0;i<nbt;i++)
+      {
+	Vertex & v0 = triangles[i][0];
+	Vertex & v1 = triangles[i][1];
+	Vertex & v2 = triangles[i][2];
+      if ( &v0 && &v1 &&  &v2 ) // a good triangles;
+      {
+	triangles[i].det= det(v0,v1,v2);
+	if (triangles[i].det <=0 && Nberr++ <10)
+	  {
+	    if(Nberr==1)
+	      if (strfrom)
+		cerr << "+++ Fatal Error " << strfrom << "(SetInCoor)  Error :  area of Triangle < 0 " << endl; 
+	      else 
+		cerr << "+++  Fatal Error Triangle (in SetInCoor) area of Triangle < 0" << endl;
+	    cerr << " Triangle " << i << "  det  (I2) = " << triangles[i].det ;
+	    cerr << " (R2) " << Det(v1.r-v0.r,v2.r-v0.r);
+	    cerr << "; The 3  vertices " << endl;
+	    cerr << Number(v0) << " "  << Number(v1) << " " 
+		 << Number(v2) << " : " ;
+	    cerr << v0.r << v1.r << v2.r << " ; ";
+	    cerr << v0.i << v1.i << v2.i << endl;
+	  }
+      }
+    else
+      triangles[i].det= -1; // Null triangle; 
+      }
+    if (Nberr) MeshError(899,this);
+	
+}
+
+void Triangles::FillHoleInMesh() 
+{
+  Triangles * OldCurrentTh =CurrentTh;
+  CurrentTh=this;
+  //  Int4 NbTold = nbt;
+  // generation of the integer coor
+  {
+ 
+    //  double coef = coefIcoor;
+    // recherche des extrema des vertices pmin,pmax
+    Int4 i;
+    if(verbosity>2)
+      cout << "  -- FillHoleInMesh: Nb of vertices =" << nbv 
+	   << " Pmin = "<< pmin << " Pmax = "<< pmax << endl;
+    
+    assert(ordre);
+    for (i=0;i<nbv;i++) 
+      ordre[i]= 0 ;
+    
+
+    NbSubDomains =0;
+    
+  // generation of the adjacence of the triangles
+    SetOfEdges4 * edge4= new SetOfEdges4(nbt*3,nbv);
+    Int4 * st = new Int4[nbt*3];
+    for (i=0;i<nbt*3;i++)
+      st[i]=-1;
+    Int4 kk =0;
+    for (i=0;i<nbe;i++)
+      kk += (i == edge4->addtrie(Number(edges[i][0]),Number(edges[i][1])));
+    if (kk != nbe)
+      { 
+	cerr << " Some Double edge in the mesh, the number is " << kk-nbe << endl;
+	MeshError(1002,this);
+      }
+    for (i=0;i<nbt;i++)
+      for (int j=0;j<3;j++)
+	{
+	  // Int4 i0,i1;
+	  Int4 k =edge4->addtrie(Number(triangles[i][VerticesOfTriangularEdge[j][0]]),
+				 Number(triangles[i][VerticesOfTriangularEdge[j][1]]));
+	  Int4 invisible = triangles[i].Hidden(j);
+	  if(st[k]==-1)
+	    st[k]=3*i+j;
+	  else if(st[k]>=0) {
+	    assert( ! triangles[i].TriangleAdj(j) && !triangles[st[k] / 3].TriangleAdj((int) (st[k]%3)));
+	    
+	    triangles[i].SetAdj2(j,triangles + st[k] / 3,(int) (st[k]%3));
+	    if (invisible)  triangles[i].SetHidden(j);
+	    if (k<nbe) {
+	      triangles[i].SetLocked(j);
+	    }
+	    st[k]=-2-st[k]; }
+	  else {
+	    cerr << " The edge (" 
+	     << Number(triangles[i][VerticesOfTriangularEdge[j][0]])
+		 << " , " 
+		 << Number(triangles[i][VerticesOfTriangularEdge[j][1]])
+		 << " ) is in more than 2 triangles " <<k <<endl;
+	    cerr << " Edge " << j << " Of Triangle " << i << endl;
+	    cerr << " Edge " << (-st[k]+2)%3 << " Of Triangle " << (-st[k]+2)/3  << endl;
+	    cerr << " Edge " << triangles[(-st[k]+2)/3].NuEdgeTriangleAdj((int)((-st[k]+2)%3))
+		 << " Of Triangle " <<  Number(triangles[(-st[k]+2)/3].TriangleAdj((int)((-st[k]+2)%3))) << endl;
+	    MeshError(9999,this);}	
+
+
+	}
+    if(verbosity>5) {
+      cout << "    On Mesh " << name << endl;
+      cout << "    - The number of Vertices  = " << nbv << endl;
+      cout << "    - The number of Triangles = " << nbt << endl;
+      cout << "    - The number of given edge = " << nbe << endl;
+      cout << "    - The number of all edges = " << edge4->nb() << endl;
+      cout << "    - The Euler number = 1-Nb Of Hole = " << nbt-edge4->nb()+nbv << endl; }
+    
+    
+    // check the consistant of edge[].adj and the geometrical required  vertex
+     Int4 k=0;
+     for (i=0;i<edge4->nb();i++)
+       if (st[i] >=0) // edge alone 
+	 if (i < nbe) 
+	   {
+	     Int4 i0=edge4->i(i);ordre[i0] = vertices+i0;
+	     Int4 i1=edge4->j(i);ordre[i1] = vertices+i1;
+	   }
+     	 else {
+	   k++;
+	   if (verbosity>20 && k <20) 
+	     {
+	     Int4 i0=edge4->i(i);
+	     Int4 i1=edge4->j(i);
+	     cerr << " Lose boundary edges " << i << " : " << i0 << " " << i1 << endl;
+	     }
+	 }
+     	 
+      if(k != 0) {
+	if (verbosity>20)
+	  {
+	    cout << " The given edge are " << endl;
+	      for (int i=0;i< nbe;i++)
+		cout <<  " Edge " << i << " : " <<  Number(edges[i][0]) << " " <<  Number(edges[i][1]) 
+		     << " " << edges[i].ref << endl; 
+	  }
+	cerr << k << " boundary edges  are not defined as edges " << endl;
+	MeshError(9998,this);
+      }
+      // generation of the mesh with boundary points   
+      Int4 nbvb = 0;
+      for (i=0;i<nbv;i++)
+	{ 
+	  vertices[i].t=0;
+	  vertices[i].vint=0;
+	if (ordre[i]) 
+	  ordre[nbvb++] = ordre[i];
+	}
+
+      Triangle *savetriangles= triangles;
+      Int4 savenbt=nbt;
+      Int4 savenbtx=nbtx;
+      SubDomain * savesubdomains = subdomains;
+      subdomains = 0;
+
+      Int4  Nbtriafillhole = 2*nbvb;
+      Triangle * triafillhole =new Triangle[Nbtriafillhole];
+      if (verbosity>9)
+	cout << " Nbtriafillhole triafillhole*" << triafillhole << endl; 
+      triangles =  triafillhole;
+
+      nbt=2;
+      nbtx= Nbtriafillhole;
+      
+	for (i=2 ; det( ordre[0]->i, ordre[1]->i, ordre[i]->i ) == 0;) 
+	  if  ( ++i >= nbvb) {
+	    cerr << "FillHoleInMesh: All the vertices are aline " << nbvb << endl;
+	    MeshError(998,this); }
+	Exchange( ordre[2], ordre[i]);
+
+	Vertex *  v0=ordre[0], *v1=ordre[1];
+
+
+	triangles[0](0) = 0; // sommet pour infini 
+	triangles[0](1) = v0;
+	triangles[0](2) = v1;
+	
+	triangles[1](0) = 0;// sommet pour infini 
+	triangles[1](2) = v0;
+	triangles[1](1) = v1;
+	const int e0 = OppositeEdge[0];
+	const int e1 = NextEdge[e0];
+	const int e2 = PreviousEdge[e0];
+	triangles[0].SetAdj2(e0, &triangles[1] ,e0);
+	triangles[0].SetAdj2(e1, &triangles[1] ,e2);
+	triangles[0].SetAdj2(e2, &triangles[1] ,e1);
+	
+	triangles[0].det = -1;  // faux triangles
+	triangles[1].det = -1;  // faux triangles
+	
+	triangles[0].SetTriangleContainingTheVertex();
+	triangles[1].SetTriangleContainingTheVertex();
+	
+	triangles[0].link=&triangles[1];
+	triangles[1].link=&triangles[0];
+	
+#ifdef DEBUG 
+	triangles[0].check();
+	triangles[1].check();
+#endif  
+	//  nbtf = 2;
+	if (  !quadtree ) 
+	   delete  quadtree; // ->ReInitialise();
+	
+	  quadtree = new QuadTree(this,0);
+	quadtree->Add(*v0);
+	quadtree->Add(*v1);
+	
+	// on ajoute les sommets un a un 
+	Int4 NbSwap=0;
+	for (Int4 icount=2; icount<nbvb; icount++) {
+	  
+	  Vertex *vi  = ordre[icount];
+	  //	  cout << " Add vertex " <<  Number(vi) << endl;
+	  Icoor2 dete[3];
+	  Triangle *tcvi = FindTriangleContening(vi->i,dete);
+	  quadtree->Add(*vi); 
+	  Add(*vi,tcvi,dete);
+	  NbSwap += vi->Optim(1,1);
+	  
+#ifdef DRAWING2
+	  cout << Number(vi) << " " <<  NbSwap <<  endl;
+	reffecran();
+	Draw();
+	vi->Draw();
+	inquire();
+#endif
+	}// end loop on  icount	
+#ifdef DRAWING1
+	inquire();
+#endif
+	
+	//Int4 nbtfillhole = nbt;
+	 // inforce the boundary 
+	 TriangleAdjacent ta(0,0);
+	 Int4 nbloss = 0,knbe=0;
+	 for ( i = 0; i < nbe; i++) 
+	  if (st[i] >=0)  // edge alone => on border ...  FH oct 2009
+	   {
+	     Vertex & a=edges[i][0], & b =    edges[i][1];
+	     if (a.t && b.t) // le bug est la si maillage avec des bod non raffine 1.
+	       {
+		 knbe++;
+		 if (ForceEdge(a,b,ta)<0)
+		   nbloss++;
+	       }
+	   }
+	 if(nbloss)
+	   {
+	     cerr << " we loss some  " << nbloss << " "  << " edges other " << knbe << endl;
+	     MeshError(1100,this);
+	   }
+	 FindSubDomain(1);
+         // remove all the hole 
+	 // remove all the good sub domain
+	 Int4 krm =0;
+	 for (i=0;i<nbt;i++)
+	   if (triangles[i].link) // remove triangles
+	     {
+	       krm++;
+	       for (int j=0;j<3;j++)
+		 {
+		   TriangleAdjacent ta =  triangles[i].Adj(j);
+		   Triangle & tta = * (Triangle *) ta;
+		   if(! tta.link) // edge between remove and not remove 
+		     { // change the link of ta;
+		       int ja = ta;
+		       Vertex *v0= ta.EdgeVertex(0);
+		       Vertex *v1= ta.EdgeVertex(1);
+		       Int4 k =edge4->addtrie(v0?Number(v0):nbv,v1? Number(v1):nbv);
+		       assert(st[k] >=0); 
+		       tta.SetAdj2(ja,savetriangles + st[k] / 3,(int) (st[k]%3));
+		       ta.SetLock();
+		       st[k]=-2-st[k]; 
+		     }
+		 }
+	     }
+	 Int4 NbTfillHoll =0;
+	 for (i=0;i<nbt;i++)
+	   if (triangles[i].link) {
+	     triangles[i]=Triangle((Vertex *) NULL,(Vertex *) NULL,(Vertex *) NULL);
+	     triangles[i].color=-1;
+	   }
+	   else
+	     {
+	      triangles[i].color= savenbt+ NbTfillHoll++;
+#ifdef DEBUG 
+	     triangles[i].check();
+#endif
+      }
+	 // cout <<      savenbt+NbTfillHoll << " " <<  savenbtx  << endl;
+     assert(savenbt+NbTfillHoll <= savenbtx );
+     // copy of the outside triangles in saveTriangles 
+     for (i=0;i<nbt;i++)
+       if(triangles[i].color>=0) 
+	 {
+          savetriangles[savenbt]=triangles[i];
+	  savetriangles[savenbt].link=0;
+	  savenbt++;
+	 }
+     // gestion of the adj
+      k =0;
+      Triangle * tmax = triangles + nbt;
+      for (i=0;i<savenbt;i++)  
+	{ 
+	  Triangle & ti = savetriangles[i];
+	  for (int j=0;j<3;j++)
+	    {
+	      Triangle * ta = ti.TriangleAdj(j);
+	      int aa = ti.NuEdgeTriangleAdj(j);
+	      int lck = ti.Locked(j);
+	      if (!ta) k++; // bug 
+	      else if ( ta >= triangles && ta < tmax) 
+		{
+		  ta= savetriangles + ta->color;
+		  ti.SetAdj2(j,ta,aa);
+		  if(lck) ti.SetLocked(j);
+		}
+	    }
+	}
+     //	 OutSidesTriangles = triangles;
+      //	Int4 NbOutSidesTriangles = nbt;
+	 
+	 // restore triangles;
+	 nbt=savenbt;
+	 nbtx=savenbtx;
+	 delete [] triangles;
+	 delete [] subdomains;
+	 triangles = savetriangles;
+	 subdomains = savesubdomains;
+	 //	 cout <<  triangles << " <> " << OutSidesTriangles << endl; 
+	     /*	 k=0;
+	 for (i=0;i<nbt;i++)
+	   for (int j=0;j<3;j++)
+	     if (!triangles[i].TriangleAdj(j))
+	     k++;
+	     */
+	 if (k) {
+	   cerr << "Error Nb of triangles edge alone = " << k << endl;
+	   MeshError(9997,this);
+	 }
+	 FindSubDomain();
+	 // cout << " NbTOld = " << NbTold << " ==  " << nbt - NbOutT << " " << nbt << endl;
+  
+    // 
+
+    delete edge4;
+    delete [] st;
+    for (i=0;i<nbv;i++)
+      quadtree->Add(vertices[i]);
+    
+    SetVertexFieldOn();
+
+    for (i=0;i<nbe;i++)
+      if(edges[i].on) 
+	for(int j=0;j<2;j++)
+	  if (!edges[i].adj[j])
+	    if(!edges[i][j].on->IsRequiredVertex()) {
+	      cerr << " Erreur adj et sommet requis edges [" << i <<  "][ " << j << "]= "
+		   <<  Number(edges[i][j]) << " : "  << " on = " << Gh.Number(edges[i].on) ;
+	      if (edges[i][j].on->OnGeomVertex())
+		cerr << " vertex " << Gh.Number(edges[i][j].on->gv);
+	      else if (edges[i][j].on->OnGeomEdge())
+		cerr << "Edges " << Gh.Number(edges[i][j].on->ge);
+	      else
+		cerr << " = " << edges[i][j].on ;
+	      cerr << endl;
+	  }
+    
+#ifdef DRAWING1
+    InitDraw();
+#endif
+    
+  }
+  CurrentTh=OldCurrentTh;
+}
+
+Triangles::Triangles(Triangles & Th,Geometry * pGh,Triangles * pBth,Int4 nbvxx) // COPY OPERATOR
+: Gh(*(pGh?pGh:&Th.Gh)), BTh(*(pBth?pBth:this))
+{
+  Gh.NbRef++;
+  nbvxx = Max(nbvxx,Th.nbv); 
+  Int4 i;
+  // do all the allocation to be sure all the pointer existe
+  
+  char * cname = 0;
+  if (Th.name) 
+    {
+      cname = new char[strlen(Th.name)+1];
+      strcpy(cname,Th.name);
+    }
+  PreInit(nbvxx,cname);// to make the allocation 
+  // copy of triangles
+  nt=Th.nt;
+  nbv = Th.nbv;
+  nbt = Th.nbt;
+  nbiv = Th.nbiv;
+  nbe = Th.nbe;
+  NbSubDomains = Th.NbSubDomains;
+  NbOutT = Th.NbOutT;
+  NbOfQuad =  Th.NbOfQuad ;
+  NbOfSwapTriangle =0;
+  NbVerticesOnGeomVertex = Th.NbVerticesOnGeomVertex;
+  if(NbVerticesOnGeomVertex)
+    VerticesOnGeomVertex = new VertexOnGeom[NbVerticesOnGeomVertex];
+  NbVerticesOnGeomEdge = Th.NbVerticesOnGeomEdge;
+  if (NbVerticesOnGeomEdge)
+     VerticesOnGeomEdge = new VertexOnGeom[NbVerticesOnGeomEdge] ;
+  if (& BTh == & Th.BTh) // same back ground 
+    {
+      BTh.NbRef++;
+      NbVertexOnBThVertex = Th.NbVertexOnBThVertex;
+      if(NbVertexOnBThVertex)
+	VertexOnBThVertex = new VertexOnVertex[NbVertexOnBThVertex];
+      NbVertexOnBThEdge = Th.NbVertexOnBThEdge;
+      if(NbVertexOnBThEdge)
+	VertexOnBThEdge = new VertexOnEdge[NbVertexOnBThEdge];
+    }
+   else 
+     { // no add on back ground mesh 
+       BTh.NbRef++;
+       NbVertexOnBThVertex=0;
+       VertexOnBThVertex=0;
+       NbVertexOnBThEdge=0;
+       VertexOnBThEdge=0;
+       //       assert (& BTh == this); // --- a voir 
+		     
+    }
+
+
+  if(nbe)
+    edges = new Edge[nbe];
+  if(NbSubDomains)
+    subdomains = new SubDomain[NbSubDomains];
+  pmin = Th.pmin;
+  pmax = Th.pmax;
+  coefIcoor = Th.coefIcoor;
+  for(i=0;i<nbt;i++)
+     triangles[i].Set(Th.triangles[i],Th,*this);
+  for(i=0;i<nbe;i++)
+     edges[i].Set(Th,i,*this);
+  for(i=0;i<nbv;i++)
+     vertices[i].Set(Th.vertices[i],Th,*this);
+  for(i=0;i<NbSubDomains;i++)  
+    subdomains[i].Set(Th,i,*this);
+  for (i=0;i<NbVerticesOnGeomVertex;i++)
+    VerticesOnGeomVertex[i].Set(Th.VerticesOnGeomVertex[i],Th,*this);
+  for (i=0;i<NbVerticesOnGeomEdge;i++)
+    VerticesOnGeomEdge[i].Set(Th.VerticesOnGeomEdge[i],Th,*this);
+  quadtree=0;
+
+
+  //  assert(!OutSidesTriangles);
+}
+
+/** -- old with a bug we loss some time last swap
+
+Int4  Triangle::Optim(Int2 i,int koption)
+{
+  // turn in the positif sens around vertex s  
+  register  Int4 NbSwap =0;
+  register Vertex * s  = ns[i];
+  register Triangle * tbegin=0 , *t = this , *ttc;
+  register int k=0,j = EdgesVertexTriangle[i][0],jc;
+  tbegin=t;
+  do {
+    k++; 
+#ifdef DEBUG
+    assert( s == & (*t)[VerticesOfTriangularEdge[j][1]] );
+#endif
+#ifdef DRAWING1 
+    t->Draw();
+    DrawMark( s->r);
+#endif
+     ttc =  t->at[j];
+     jc = NextEdge[t->aa[j]&3];
+     cout << *t << " " <<  VerticesOfTriangularEdge[j][1] << "\n\t try swap " << * ttc << " " << jc ;
+    while ( ttc->swap(jc,koption)) {
+      NbSwap++,assert(k++<20000);
+      ttc =  t->at[j];
+      jc = NextEdge[t->aa[j]&3];
+      cout << "\n\t s  " <<  *ttc << " " << jc << endl;
+    }
+    cout << endl;
+    t = ttc;
+    j = NextEdge[jc];
+    assert(k<20000);
+  } while ( (tbegin != t)); 
+  
+  return NbSwap;
+}
+*/
+Int4  Triangle::Optim(Int2 i,int koption)
+{
+  // turne around in positif sens
+  Int4 NbSwap =0;
+#ifdef DEBUG
+   Vertex * s  = ns[i];
+#endif
+   Triangle  *t = this;
+   int k=0,j =OppositeEdge[i];
+   int jp = PreviousEdge[j];
+   // initialise   tp, jp the previous triangle & edge
+   Triangle *tp= at[jp];
+   jp = aa[jp]&3;
+#ifdef DEBUG
+   assert(tp->at[jp] == this);
+#endif
+   do {
+#ifdef DEBUG
+    assert(k++<20000);
+    assert( s == & (*t)[OppositeVertex[j]] );
+#endif
+    //    cout << *t << " " <<  j  << "\n\t try swap " ;
+    while (t->swap(j,koption))
+      {
+	NbSwap++;
+	assert(k++<20000);
+	t=  tp->at[jp];      // set unchange t qnd j for previous triangles
+	j=  NextEdge[tp->aa[jp]&3];
+	//   cout << "\n\t s  " <<  *t << " " << j << endl;
+#ifdef DEBUG
+	assert( s == & (*t)[OppositeVertex[j]] );
+#endif
+      }
+    // end on this  Triangle 
+    tp = t;
+    jp = NextEdge[j];
+
+    t=  tp->at[jp];      // set unchange t qnd j for previous triangles
+    j=  NextEdge[tp->aa[jp]&3];
+
+   } while( t != this);
+   return NbSwap;
+}
+
+ void Triangles::SmoothingVertex(int nbiter,Real8 omega )
+  { 
+  //  if quatree exist remove it end reconstruct
+    if (quadtree) delete quadtree;
+    quadtree=0;
+    ReMakeTriangleContainingTheVertex();
+    Triangle vide; // a triangle to mark the boundary vertex
+    Triangle   ** tstart= new Triangle* [nbv];
+    Int4 i,j,k;
+    //   attention si Background == Triangle alors on ne peut pas utiliser la rechech rapide 
+    if ( this == & BTh)
+     for ( i=0;i<nbv;i++)
+      tstart[i]=vertices[i].t;     
+    else 
+     for ( i=0;i<nbv;i++)
+      tstart[i]=0;
+    for ( j=0;j<NbVerticesOnGeomVertex;j++ ) 
+      tstart[ Number(VerticesOnGeomVertex[j].mv)]=&vide;
+    for ( k=0;k<NbVerticesOnGeomEdge;k++ ) 
+      tstart[ Number(VerticesOnGeomEdge[k].mv)]=&vide;
+    if(verbosity>2) 
+      cout << "  -- SmoothingVertex: nb Iteration = " << nbiter << " Omega = " << omega << endl;
+    for (k=0;k<nbiter;k++)
+     {
+      Int4 i,NbSwap =0;
+      Real8 delta =0;
+      for ( i=0;i<nbv;i++)
+        if (tstart[i] != &vide) // not a boundary vertex 
+	  delta=Max(delta,vertices[i].Smoothing(*this,BTh,tstart[i],omega));
+      if (!NbOfQuad)
+      for ( i=0;i<nbv;i++)
+        if (tstart[i] != &vide) // not a boundary vertex 
+	  NbSwap += vertices[i].Optim(1);
+       if (verbosity>3)
+	 cout << "    Move max = " <<  sqrt(delta) << " iteration = " 
+	      << k << " Nb of Swap = " << NbSwap << endl;
+       }
+
+    delete [] tstart;
+    if (quadtree) quadtree= new QuadTree(this);
+  }
+void Triangles::MakeQuadTree()
+{  
+  if(verbosity>8)
+    cout << "      MakeQuadTree" << endl;
+  if (  !quadtree )  quadtree = new QuadTree(this);
+
+  
+#ifdef DRAWING1
+  quadtree->Draw();
+  rattente(1);
+  reffecran();
+  quadtree->Draw();
+  rattente(1);
+#endif
+  
+}
+void  Triangles::ShowRegulaty() const// Add FH avril 2007 
+{
+   const  Real8  sqrt32=sqrt(3.)*0.5; 
+   const Real8  aireKh=sqrt32*0.5;
+   D2  Beq(1,0),Heq(0.5,sqrt32);
+   D2xD2 Br(D2xD2(Beq,Heq).t());
+   D2xD2 B1r(Br.inv());
+   /*   D2xD2 BB = Br.t()*Br;
+    cout << " BB = " << BB << " " << Br*B1r <<  endl; 
+    MetricAnIso MMM(BB.x.x,BB.x.y,BB.y.y);
+    MatVVP2x2 VMM(MMM);
+    cout << " " << VMM.lambda1 << " " << VMM.lambda2 <<  endl; 
+   */
+    double gammamn=1e100,hmin=1e100;
+    double gammamx=0,hmax=0;
+    double beta=1e100;
+    double beta0=0;
+    double  alpha2=0;
+    double area=0,Marea=0;
+   // Real8 cf= Real8(coefIcoor);
+   // Real8 cf2= 6.*cf*cf;
+    int nt=0;
+    for (int it=0;it<nbt;it++)
+      if ( triangles[it].link) 
+	{
+	  nt++;
+	  Triangle &K=triangles[it];
+	  Real8  area3= Area2((R2) K[0],(R2) K[1],(R2) K[2])/6.;
+	  area+= area3;
+	  D2xD2 B_Kt(K[0],K[1],K[2]);
+	  D2xD2 B_K(B_Kt.t());
+	  D2xD2 B1K = Br*B_K.inv();
+	  D2xD2 BK =  B_K*B1r;
+	  D2xD2 B1B1 = B1K.t()*B1K;
+	  MetricAnIso MK(B1B1.x.x,B1B1.x.y,B1B1.y.y);
+	  MatVVP2x2 VMK(MK);
+	  alpha2 = Max(alpha2,Max(VMK.lambda1/VMK.lambda2,VMK.lambda2/VMK.lambda1));
+	  // cout << B_K << " * " << B1r << " == " << BK << " " << B_K*B_K.inv() << endl;
+	  Real8 betaK=0;
+	  
+	  for (int j=0;j<3;j++)
+	    {
+	      Real8 he= Norme2(R2(K[j],K[(j+1)%3]));
+	      hmin=Min(hmin,he);
+	      hmax=Max(hmax,he);
+	      Vertex & v=K[j];
+	      D2xD2 M((MetricAnIso)v);
+	      betaK += sqrt(M.det());
+	      
+	      D2xD2 BMB = BK.t()*M*BK;
+	      MetricAnIso M1(BMB.x.x,BMB.x.y,BMB.y.y);
+	      MatVVP2x2 VM1(M1);
+	      //cout << B_K <<" " <<  M << " " <<  he << " " << BMB << " " << VM1.lambda1 << " " << VM1.lambda2<<   endl; 
+	      gammamn=Min3(gammamn,VM1.lambda1,VM1.lambda2);
+	      gammamx=Max3(gammamx,VM1.lambda1,VM1.lambda2);		
+	    }
+	  betaK *= area3;//  1/2 (somme sqrt(det))* area(K)
+	  Marea+= betaK;
+	  // cout << betaK << " " << area3 << " " << beta << " " << beta0 << " " << area3*3*3*3 <<endl;
+	  beta=min(beta,betaK);
+	  beta0=max(beta0,betaK);
+	}   
+    area*=3; 
+    gammamn=sqrt(gammamn);
+    gammamx=sqrt(gammamx);    
+    cout << "  -- adaptmesh Regulary:  Nb triangles " << nt <<  " , h  min " << hmin  << " , h max " << hmax << endl;  
+    cout << "     area =  " << area << " , M area = " << Marea << " , M area/( |Khat| nt) " << Marea/(aireKh*nt) << endl; 
+    cout << "     infiny-regulaty:  min " << gammamn << "  max " << gammamx << endl;  
+    cout << "     anisomax  "<< sqrt(alpha2) << ", beta max = " << 1./sqrt(beta/aireKh) 
+	 << " min  "<<  1./sqrt(beta0/aireKh)  << endl;
+}
+void  Triangles::ShowHistogram() const
+ {
+
+    const Int4 kmax=10;
+    const Real8 llmin = 0.5,llmax=2;
+     const Real8 lmin=log(llmin),lmax=log(llmax),delta= kmax/(lmax-lmin);
+    Int4 histo[kmax+1];
+    Int4 i,it,k, nbedges =0;
+    for (i=0;i<=kmax;i++) histo[i]=0;
+    for (it=0;it<nbt;it++)
+	if ( triangles[it].link) 
+	{
+	     
+	    for (int j=0;j<3;j++)
+	    {
+		Triangle *ta = triangles[it].TriangleAdj(j);
+		if ( !ta || !ta->link || Number(ta) >= it) 
+		{ 
+		    Vertex & vP = triangles[it][VerticesOfTriangularEdge[j][0]];
+		    Vertex & vQ = triangles[it][VerticesOfTriangularEdge[j][1]];
+		    if ( !& vP || !&vQ) continue;
+		    R2 PQ = vQ.r - vP.r;
+		    Real8 l = log(LengthInterpole(vP,vQ,PQ));
+#ifdef DRAWING2             
+		    if (l>1.4)  {
+			penthickness(3);
+			vP.MoveTo(),vQ.LineTo();
+			penthickness(1);
+			cout << "   l = " << l << Number(vP) << " edge = " << Number(vQ) << endl;
+		    }
+#endif             
+		    nbedges++;
+		    k = (int) ((l - lmin)*delta);
+		    k = Min(Max(k,0L),kmax);
+		    histo[k]++;
+		}
+	    }
+	}  
+	    cout << "  -- Histogram of the unit mesh,  nb of edges" << nbedges << endl <<endl;
+ 
+    cout << "        length of edge in   | % of edge  | Nb of edges " << endl;
+    cout << "        ------------------- | ---------- | ----------- " << endl;
+    for   (i=0;i<=kmax;i++)
+      { 
+       cout << "    " ;
+        cout.width(10);
+        if (i==0) cout  << " 0 " ;
+        else cout  << exp(lmin+i/delta) ;
+        cout.width(); cout << "," ;
+        cout.width(10);
+        if (i==kmax) cout << " +infty " ;
+        else cout  << exp(lmin+(i+1)/delta) ;
+        cout.width();cout << "   |   " ;
+        
+       cout.precision(4);
+       cout.width(6);
+       cout <<  ((long)  ((10000.0 * histo[i])/ nbedges))/100.0 ;
+       cout.width();
+       cout.precision();
+       cout <<  "   |   " << histo[i] <<endl;
+      }
+    cout << "        ------------------- | ---------- | ----------- " << endl <<endl;
+    
+ }
+
+int  Triangles::Crack()
+  { 
+    assert(NbCrackedEdges ==0 || NbCrackedVertices >0); 
+    for (int i=0;i<NbCrackedEdges;i++)
+       CrackedEdges[i].Crack();
+    return NbCrackedEdges;
+  }
+  
+int Triangles::UnCrack() 
+{ 
+  assert(NbCrackedEdges ==0 || NbCrackedVertices >0); 
+  for (int i=0;i<NbCrackedEdges;i++)
+    CrackedEdges[i].UnCrack();
+  return NbCrackedEdges;
+}
+
+int Triangles::CrackMesh()
+{
+    Triangles *CurrentThOld = CurrentTh;
+  //  computed the number of cracked edge
+  int i,k;
+  for (k=i=0;i<nbe;i++)
+    if(edges[i].on->Cracked()) k++;
+  if( k==0) return 0;
+    CurrentTh = this;
+  cout << " Nb of Cracked Edges = " << k << endl;
+  NbCrackedEdges =k;
+  CrackedEdges = new  CrackedEdge[k];
+  //  new edge
+  Edge * e = new Edge[ nbe + k];
+
+  // copy
+  for (i=0;i<nbe;i++) 
+    e[i] = edges[i];
+  delete edges;
+  edges = e;
+
+  const int  nbe0  = nbe;
+  for (k=i=0;i<nbe0;i++) // on double les arete cracked 
+    if(edges[i].on->Cracked())
+      {
+	e[nbe] = e[i];
+	//  return the edge 
+	e[nbe].v[0] =  e[i].v[1];
+	e[nbe].v[1] =  e[i].v[0];
+	e[nbe].on = e[i].on->link ; // fqux 
+	CrackedEdges[k++]=CrackedEdge(edges,i,nbe);
+	nbe++;
+      }
+  ReMakeTriangleContainingTheVertex() ; 
+  //  
+  int nbcrakev  =0;
+  Vertex *vlast = vertices + nbv;
+  Vertex *vend = vertices + nbvx; // end of array
+  for (int iv=0;iv<nbv;iv++) // vertex 
+    {
+      Vertex & v= vertices[iv];
+      Vertex * vv = & v;  
+      int kk=0; // nb cracked
+      int kc=0; 
+      int kkk =0; // nb triangle  with same number 
+      Triangle * tbegin = v.t;
+      int i  = v.vint;       
+      assert(tbegin && (i >= 0 ) && (i <3));
+      // turn around the vertex v
+      TriangleAdjacent ta(tbegin,EdgesVertexTriangle[i][0]);// previous edge
+      int k=0;
+      do {
+	int kv = VerticesOfTriangularEdge[ta][1];
+	k++; 
+	Triangle * tt (ta);
+	if ( ta.Cracked() ) 
+	  {   
+	    TriangleAdjacent tta=(ta.Adj());
+	    assert(tta.Cracked());
+	    if ( kk == 0) tbegin=ta,kkk=0;  //  begin by a cracked edge  => restart                
+	    if (  kkk ) { kc =1;vv = vlast++;  kkk = 0; } // new vertex if use 
+	    kk++;// number of cracked edge view                 
+	  }
+	if ( tt->link ) { // if good triangles store the value 
+	  int it = Number(tt);
+	  assert(it < nt);
+	  (*tt)(kv)= vv; //   Change the vertex of triangle 
+	  if(vv<vend) {*vv= v;vv->ReferenceNumber=iv;} // copy the vertex value + store the old vertex number in ref 
+	  //	  tt->SetTriangleContainingTheVertex();
+	  kkk++;
+	} else if (kk) { // crack + boundary 
+	  if (  kkk ) { kc =1;vv = vlast++;  kkk = 0; } // new vertex if use 
+	}
+	
+	ta = Next(ta).Adj(); 
+      } while ( (tbegin != ta)); 
+      assert(k);
+      if (kc)  nbcrakev++;
+    }
+  
+  if ( nbcrakev ) 
+      for (int iec =0;iec < NbCrackedEdges; iec ++)
+	  CrackedEdges[iec].Set();
+  
+  //  set the ref 
+  cout << " set the ref " <<  endl ;
+  NbCrackedVertices =   nbcrakev;
+  // int nbvo = nbv;
+  nbv = vlast - vertices;
+  int nbnewv =  nbv - nbv; // nb of new vrtices 
+  if (nbcrakev && verbosity > 1 )
+    cout << " Nb of craked vertices = " << nbcrakev << " Nb of created vertices " <<   nbnewv<< endl;
+  // all the new vertices are on geometry 
+  //  BOFBO--  A VOIR
+  if (nbnewv)
+    { // 
+      Int4 n = nbnewv+NbVerticesOnGeomVertex;
+      Int4 i,j,k;
+      VertexOnGeom * vog = new VertexOnGeom[n];
+      for ( i =0; i<NbVerticesOnGeomVertex;i++) 
+	vog[i]=VerticesOnGeomVertex[i];
+      delete [] VerticesOnGeomVertex;
+      VerticesOnGeomVertex = vog;
+      // loop on cracked edge 
+      Vertex * LastOld = vertices + nbv - nbnewv;
+      for (int iec =0;iec < NbCrackedEdges; iec ++)
+	for (k=0;k<2;k++)
+	  {
+	    Edge & e = *( k ? CrackedEdges[iec].a.edge : CrackedEdges[iec].b.edge);
+	    for (j=0;j<2;j++) 
+	      {
+		Vertex * v = e(j);
+		if ( v >=  LastOld)
+		  { // a new vertex 
+		    Int4 old = v->ReferenceNumber ; // the old same vertex 
+		    Int4 i  = ( v - LastOld);
+		    //  if the old is on vertex => warning
+		    // else the old is on edge => ok 
+		    vog[i] = vog[old];
+				//  		    vog[i].mv = v;
+				//g[i].ge = ;
+				//og[i].abcisse = ;
+		  }
+		
+	      }
+	  }
+
+	NbVerticesOnGeomVertex = n;
+  }
+  SetVertexFieldOn();
+
+ 
+  if (vlast >= vend)
+    {  
+      cerr << " Not enougth vertices to crack the mesh we need " << nbv << " vertices " << endl;
+      MeshError(555,this);
+    }
+  cout << "  NbCrackedVertices " <<  NbCrackedVertices << endl;
+  CurrentTh = CurrentThOld;
+  return  NbCrackedVertices;
+}
+      
+Triangles::Triangles(const Triangles & Tho,const int *flag ,const int *bb)
+  : Gh(*(new Geometry())), BTh(*this)
+{ // truncature
+  // 
+  
+  char cname[] = "trunc";
+
+  int i,k,itadj;
+  int kt=0;
+  int * kk    = new int [Tho.nbv];
+  Int4 * reft = new Int4[Tho.nbt];
+  Int4 nbInT =    Tho.ConsRefTriangle(reft);
+  Int4 * refv = new Int4[Tho.nbv];
+
+  for (i=0;i<Tho.nbv;i++)
+    kk[i]=-1;
+  for (i=0;i<Tho.nbv;i++)
+    refv[i]=0;
+  int nbNewBedge =0;
+  //  int nbOldBedge =0;  
+  for (i=0;i<Tho.nbt;i++)
+    if(  reft[i] >=0 && flag[i]) 
+      {
+        const Triangle & t = Tho.triangles[i];
+        kt++;
+        kk[Tho.Number(t[0])]=1;
+        kk[Tho.Number(t[1])]=1;
+        kk[Tho.Number(t[2])]=1;
+        itadj=Tho.Number(t.TriangleAdj(0));
+        if (  reft[itadj] >=0 && !flag[itadj])
+          { nbNewBedge++;
+          refv[Tho.Number(t[VerticesOfTriangularEdge[0][0]])]=bb[i];
+          refv[Tho.Number(t[VerticesOfTriangularEdge[0][1]])]=bb[i];
+          }
+        itadj=Tho.Number(t.TriangleAdj(1));
+        if (  reft[itadj] >=0 && !flag[itadj])
+          { nbNewBedge++;
+          refv[Tho.Number(t[VerticesOfTriangularEdge[1][0]])]=bb[i];
+          refv[Tho.Number(t[VerticesOfTriangularEdge[1][1]])]=bb[i];}
+        itadj=Tho.Number(t.TriangleAdj(2));
+        if (  reft[itadj] >=0 && !flag[itadj])
+          { nbNewBedge++;
+          refv[Tho.Number(t[VerticesOfTriangularEdge[2][0]])]=bb[i];
+          refv[Tho.Number(t[VerticesOfTriangularEdge[2][1]])]=bb[i];}
+      }
+  k=0;
+  for (i=0;i<Tho.nbv;i++)
+    if (kk[i]>=0) 
+      kk[i]=k++;
+  cout << " number of vertices " << k << " remove = " << Tho.nbv - k << endl;
+  cout << " number of triangles " << kt << " remove = " << nbInT-kt << endl;
+  cout << " number of New boundary edge " << nbNewBedge << endl;
+  Int4 inbvx =k;
+  PreInit(inbvx,cname);
+  for (i=0;i<Tho.nbv;i++)
+    if (kk[i]>=0) 
+      {
+        vertices[nbv] = Tho.vertices[i];
+        if (!vertices[nbv].ref())
+          vertices[nbv].ReferenceNumber = refv[i];
+        nbv++;
+      }
+  assert(inbvx == nbv);
+  for (i=0;i<Tho.nbt;i++)
+    if(  reft[i] >=0 && flag[i]) 
+      {
+        const Triangle & t = Tho.triangles[i];
+        int i0 = Tho.Number(t[0]);
+        int i1 = Tho.Number(t[1]);
+        int i2 = Tho.Number(t[2]);
+        assert(i0>=0 && i1 >= 0 && i2  >= 0);
+        assert(i0<Tho.nbv && i1 <Tho.nbv && i2  <Tho.nbv);
+        // cout <<i<< " F" <<  flag[i] << " T " << nbt << "   = " <<  kk[i0] << " " << kk[i1] << " " << kk[i2] ;
+        // cout << " OT  " <<  i0 << " "  << i1 << " " << i2  << " " << reft[i] << endl;
+        triangles[nbt] = Triangle(this,kk[i0],kk[i1],kk[i2]);
+        triangles[nbt].color = Tho.subdomains[reft[i]].ref; 
+        nbt++;           
+      }
+  assert(kt==nbt);
+  if (nbt ==0 && nbv ==0) {
+    cout << "Error all triangles was remove " << endl;
+    MeshError(999,this);
+  }
+  delete [] kk;
+  delete [] reft;
+  delete [] refv;
+  double cutoffradian = 10.0/180.0*Pi;
+  ConsGeometry(cutoffradian);
+  Gh.AfterRead(); 
+  SetIntCoor();
+  FillHoleInMesh();
+   
+  assert(NbSubDomains);
+  assert(subdomains[0].head && subdomains[0].head->link);
+             
+}
+  
+Triangle * Triangles::FindTriangleContening(const I2 & B,Icoor2 dete[3], Triangle *tstart) const
+{ // in: B 
+  // out: t
+  // out : dete[3]
+  // t the triangle and s0,s1,s2 the 3 vertices of t
+  // in dete[3] = { det(B,s1,s2) , det(s0,B,s2), det(s0,s1,B)}
+  // with det(a,b,c ) = -1 if one of 3 vertices a,b,c is NULL 
+  Triangle * t=0;	
+  int j,jp,jn,jj;
+  if (tstart) 
+    t=tstart;
+  else 
+   {
+   assert(quadtree);
+   Vertex *a = quadtree->NearestVertex(B.x,B.y) ;
+  
+  if (! a || !a->t ) {
+    if (a) 
+      {cerr << " Attention PB TriangleConteningTheVertex  vertex number=" << Number(a) << endl;
+       cerr  << "We forget a call to ReMakeTriangleContainingTheVertex" << endl;}
+    cerr << " Pb with " << B << toR2(B) << endl;
+    MeshError(7777);
+  }
+  assert(a>= vertices && a < vertices+nbv);
+#ifdef DRAWING1 
+  a->Draw();
+#endif 
+  //  int k=0;
+   t = a->t;
+  assert(t>= triangles && t < triangles+nbt);
+   
+   }
+  Icoor2  detop ;
+  int kkkk =0; // number of test triangle 
+
+  while ( t->det < 0) 
+    { // the initial triangles is outside  
+      int k0=(*t)(0) ?  ((  (*t)(1) ? ( (*t)(2) ? -1 : 2) : 1  )) : 0;
+      assert(k0>=0); // k0 the NULL  vertex 
+      int k1=NextVertex[k0],k2=PreviousVertex[k0];
+      dete[k0]=det(B,(*t)[k1],(*t)[k2]);
+      dete[k1]=dete[k2]=-1;     
+      if (dete[k0] > 0) // outside B 
+        return t; 
+      t = t->TriangleAdj(OppositeEdge[k0]);
+      assert(kkkk++ < 2);
+    }
+
+  jj=0;
+  detop = det(*(*t)(VerticesOfTriangularEdge[jj][0]),*(*t)(VerticesOfTriangularEdge[jj][1]),B);
+ 
+  while(t->det  > 0 ) 
+    { 
+      assert( kkkk++ < 2000 ); 
+      j= OppositeVertex[jj];
+      
+#ifdef DRAWING1
+      t->Draw();
+#endif 
+      dete[j] = detop;  //det(*b,*s1,*s2);
+      jn = NextVertex[j];
+      jp = PreviousVertex[j];
+      dete[jp]= det(*(*t)(j),*(*t)(jn),B);
+      dete[jn] = t->det-dete[j] -dete[jp];
+      
+#ifdef DEBUG
+      const Vertex * s0 = (*t)(0);
+      const Vertex * s1 = (*t)(1);
+      const Vertex * s2 = (*t)(2);
+      assert(dete[0] == det(B ,*s1,*s2));
+      assert(dete[1] == det(*s0,B ,*s2));
+      assert(dete[2] == det(*s0,*s1,B ));
+      assert(t->det== (dete[0] + dete[1] +dete[2]));
+#endif
+      // count the number k of  dete <0
+      int k=0,ii[3];
+      if (dete[0] < 0 ) ii[k++]=0; 
+      if (dete[1] < 0 ) ii[k++]=1;
+      if (dete[2] < 0 ) ii[k++]=2;
+      // 0 => ok
+      // 1 => go in way 1
+      // 2 => two way go in way 1 or 2 randomly
+      
+      if (k==0) 
+	break;
+      if (k == 2 && BinaryRand())
+	Exchange(ii[0],ii[1]);
+      assert ( k  < 3);
+      TriangleAdjacent t1 = t->Adj(jj=ii[0]);
+      if ((t1.det() < 0 ) && (k == 2))
+	t1 = t->Adj(jj=ii[1]);
+      t=t1;
+      j=t1;// for optimisation we now the -det[OppositeVertex[j]];
+      detop = -dete[OppositeVertex[jj]];
+      jj = j;
+    }
+  
+  if (t->det<0) // outside triangle 
+    dete[0]=dete[1]=dete[2]=-1,dete[OppositeVertex[jj]]=detop;
+  //  NbOfTriangleSearchFind += kkkk;  
+  return t;
+}
+
+}
+
diff --git a/contrib/bamg/bamglib/Mesh2.h b/contrib/bamg/bamglib/Mesh2.h
new file mode 100644
index 0000000000000000000000000000000000000000..4d02159a19ecf2d45d12187d58696d6d5d464214
--- /dev/null
+++ b/contrib/bamg/bamglib/Mesh2.h
@@ -0,0 +1,1492 @@
+// -*- Mode : c++ -*-
+//
+// SUMMARY  :      
+// USAGE    :        
+// ORG      : 
+// AUTHOR   : Frederic Hecht
+// E-MAIL   : hecht@ann.jussieu.fr
+//
+
+/*
+ 
+ This file is part of Freefem++
+ 
+ Freefem++ is free software; you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+ 
+ Freefem++  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 Lesser General Public License for more details.
+ 
+ You should have received a copy of the GNU Lesser General Public License
+ along with Freefem++; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include <stdlib.h>
+#include <math.h>
+#include <limits.h>
+#include <time.h>
+#if  (defined(unix) || defined(__unix)) && !defined(__AIX)
+#define SYSTIMES
+#include <sys/times.h>
+#include <unistd.h>
+#endif
+#ifdef  DRAWING
+#include "rgraph.hpp"
+#endif
+
+extern long verbosity;
+extern int SHOW;
+#include "meshtype.h"
+
+#include "error.hpp"
+
+
+#include "R2.h"
+
+namespace bamg {
+
+
+
+const  double Pi =  3.14159265358979323846264338328;
+const  float fPi =  3.14159265358979323846264338328;
+
+
+class MeshIstream;
+class OFortranUnFormattedFile;
+class IFortranUnFormattedFile;
+
+extern int hinterpole;
+
+
+typedef P2<Icoor1,Icoor2> I2;
+
+inline int BinaryRand(){
+#ifdef RAND_MAX
+ const long HalfRandMax = RAND_MAX/2;
+ return rand() <HalfRandMax;
+#else
+ return rand() & 16384; // 2^14 (for sun because RAND_MAX is not def in stdlib.h)
+#endif
+
+} 
+typedef P2<Real8,Real8> R2;
+typedef P2xP2<Int2,Int4> I2xI2;
+typedef P2<Real4,Real8> R2xR2;
+
+}
+
+#include "Metric.h"
+
+namespace bamg {
+inline float OppositeAngle(float a)
+ {return a<0 ? fPi + a :a - fPi ;}
+inline double OppositeAngle(double a)
+ {return a<0 ? Pi + a :a - Pi ;}
+ 
+#ifdef DRAWING
+extern Real4  xGrafCoef,yGrafCoef,xGrafOffSet,yGrafOffSet;
+extern R2 GrafPMin,GrafPMax;
+extern Real8 Grafh;
+#endif
+
+Icoor2 inline det(const I2 &a,const I2 & b,const I2 &c)
+{
+  register  Icoor2 bax = b.x - a.x ,bay = b.y - a.y; 
+  register  Icoor2 cax = c.x - a.x ,cay = c.y - a.y; 
+  return  bax*cay - bay*cax;}
+
+
+
+// def de numerotation dans un triangles 
+static const Int2 VerticesOfTriangularEdge[3][2] = {{1,2},{2,0},{0,1}};
+static const Int2 EdgesVertexTriangle[3][2] = {{1,2},{2,0},{0,1}};
+static const Int2 OppositeVertex[3] = {0,1,2};
+static const Int2 OppositeEdge[3] =  {0,1,2};
+static const Int2 NextEdge[3] = {1,2,0};
+static const Int2 PreviousEdge[3] = {2,0,1};
+static const Int2 NextVertex[3] = {1,2,0};
+static const Int2 PreviousVertex[3] = {2,0,1};
+
+Int4 AGoodNumberPrimeWith(Int4 n);
+
+// remark all the angle are in radian beetwen [-Pi,Pi]
+
+
+class Geometry;
+//static Geometry *NULLGeometry=0;
+class Triangles;
+class Triangle;
+class QuadTree;
+class GeometricalEdge;
+class VertexOnGeom;
+class VertexOnEdge;
+/////////////////////////////////////////////////////////////////////////////////////
+const int IsVertexOnGeom = 8;
+const int IsVertexOnVertex = 16;
+const int IsVertexOnEdge = 32;
+/////////////////////////////////////////////////////////////////////////////////////
+#ifndef  NOTFREEFEM
+class ErrorMesh : public Error
+{  
+public:
+    Triangles *Th;
+    ErrorMesh(const char * Text,int l,Triangles * TTh=0, const char *t2="") :
+	Error(MESH_ERROR,"Meshing error: ",Text,"\n number : ",l,", ",t2),Th(TTh)  {}
+};
+#endif
+
+class Direction { //   
+  private:
+  Icoor1 dir;
+  public:
+  Direction(): dir(MaxICoor){}; //  no direction set
+  Direction(Icoor1 i,Icoor1 j) { Icoor2  n2 = 2*(Abs(i)+Abs(j));  
+                                 Icoor2 r = MaxICoor* (Icoor2) i;
+                                 Icoor1 r1 = (Icoor1) (2*(r/ n2)); // odd number 
+                                 dir = (j>0) ? r1 : r1+1; //  odd -> j>0 even -> j<0
+                               }
+  int sens(    Icoor1 i,Icoor1 j) { int r =1; 
+                                   if (dir!= MaxICoor) {
+                                     Icoor2 x(dir/2),y1(MaxICoor/2-Abs(x)),y(dir%2?-y1:y1);
+                                     r = (x*i + y*j) >=0;}
+                                   return r;}
+#ifdef DRAWING
+ void  Draw() {
+                         if (dir!= MaxICoor) {
+                                     Icoor2 x(dir/2),y1(MaxICoor/2-Abs(x)),y(dir%2?-y1:y1);
+                                     R2 D(x,y);
+                                     double eps = Grafh/Norme2(D)/20;
+                                     D = D*eps;
+                                     rmoveto(D.x,D.y);
+                                    }
+  }
+#endif                                   
+                                   
+      
+                              
+  
+};
+/////////////////////////////////////////////////////////////////////////////////////
+class Vertex {public:
+  I2 i;  // allow to use i.x, and i.y in long int (beware of scale and centering)
+  R2 r;  // allow to use r.x, and r.y in double
+  Metric m;
+  Int4 ReferenceNumber;
+  Direction DirOfSearch;
+  union {
+    Triangle * t; // one triangle which contained  the vertex
+    Int4 color;
+    Vertex * to;// use in geometry Vertex to now the Mesh Vertex associed 
+    VertexOnGeom * on;     // if vint 8; // set with Triangles::SetVertexFieldOn()
+    Vertex * onbv; // if vint == 16 on Background vertex Triangles::SetVertexFieldOnBTh()
+    VertexOnEdge * onbe;   // if vint == 32 on Background edge
+  };
+  Int1 vint;  // the vertex number in triangle; varies between 0 and 2 in t
+  operator  I2   () const {return i;} // operator de cast 
+  operator  const R2 & () const {return r;}// operator de cast 
+//  operator  R2 & () {return r;}// operator de cast 
+  Real8 operator()(R2 x) const { return m(x);}
+  operator Metric () const {return m;}// operator de cast 
+  Int4  Optim(int  = 1,int =0); 
+  //  Vertex(){}
+  //  ~Vertex(){}
+  Real8  Smoothing(Triangles & ,const Triangles & ,Triangle  * & ,Real8 =1);
+  int ref() const { return ReferenceNumber;}
+
+  friend ostream& operator <<(ostream& f, const  Vertex & v)
+  {f << "(" << v.i  << "," << v.r << MatVVP2x2(v.m) << ")" ;   return f;}
+  inline void Set(const Vertex & rec,const Triangles &,Triangles &);
+  
+#ifdef DRAWING
+  void  Draw(Int4 =-1) const ;
+  void MoveTo() const  {    rmoveto(r.x,r.y);  }
+  void LineTo() const {    rlineto(r.x,r.y);  }
+#endif  
+};
+
+double QuadQuality(const Vertex &,const Vertex &,const Vertex &,const Vertex &);
+
+// extern Vertex *Meshend , *Meshbegin;
+
+/////////////////////////////////////////////////////////////////////////////////////
+class TriangleAdjacent {
+  friend ostream& operator <<(ostream& f, const  TriangleAdjacent & ta)
+  {f << "{" << ta.t << "," << ((int) ta.a) << "}" ;
+   return f;}
+
+public:
+  Triangle * t; // le triangle 
+  int  a; // le numero de l arete
+  
+  TriangleAdjacent(Triangle  * tt,int  aa): t(tt),a(aa &3) {};
+  TriangleAdjacent() {};
+  
+  operator Triangle * () const {return t;}
+  operator Triangle & () const {return *t;}
+    operator int() const {return a;}
+  TriangleAdjacent & operator++() 
+  {
+    a= NextEdge[a];
+    return *this;}
+  TriangleAdjacent operator--()
+  { 
+    a= PreviousEdge[a];
+    return *this;}
+  inline  TriangleAdjacent  Adj() const ;
+  int swap();
+  inline void SetAdj2(const TriangleAdjacent& , int =0);
+  inline Vertex *  EdgeVertex(const int &) const ;
+  inline Vertex *  OppositeVertex() const ;
+  inline Icoor2 & det() const;
+  inline int Locked() const  ;
+  inline int GetAllFlag_UnSwap() const ;
+  inline void SetLock();
+  inline int MarkUnSwap()  const;
+  inline void SetMarkUnSwap();
+  inline void SetCracked();
+  inline int Cracked() const ;
+};// end of Vertex class  
+
+
+/////////////////////////////////////////////////////////////////////////////////////
+class Edge { public:
+   Vertex * v[2];
+   Int4 ref;
+    GeometricalEdge * on;
+   Vertex & operator[](int i){return *v[i];};
+   Vertex * operator()(int i){return v[i];};
+
+  void ReNumbering(Vertex *vb,Vertex *ve, Int4 *renu) 
+   {
+    if (v[0] >=vb && v[0] <ve) v[0] = vb + renu[v[0]-vb];
+    if (v[1] >=vb && v[1] <ve) v[1] = vb + renu[v[1]-vb];
+   }
+
+  const Vertex & operator[](int i) const { return *v[i];};
+  R2 operator()(double t) const; // return the point 
+  //                                on the curve edge a t in [0:1]
+  Edge * adj[2]; // the 2 adj edges if on the same curve 
+  int Intersection(const  Edge & e) const { 
+    if (!(adj[0]==&e || adj[1]==&e)) 
+      cerr << "Bug : Intersection " << (void*) &e <<  "  " 
+	   << adj[0] << " " <<  adj[1] << endl;
+    assert(adj[0]==&e || adj[1]==&e);
+    return adj[0]==&e ? 0 : 1;}
+  Real8 MetricLength() const ;  
+  inline void Set(const Triangles &,Int4,Triangles &);
+  
+#ifdef DRAWING
+  void  Draw(Int4 = -1) const ;
+#endif
+}; // end of Edge class 
+
+/////////////////////////////////////////////////////////////////////////////////////
+class GeometricalVertex :public Vertex {
+  int cas;
+  friend class Geometry;
+  GeometricalVertex * link; //  link all the same GeometricalVertex circular (Crack) 
+public:
+  int Corner() const {return cas&4;}
+  int Required()const {return cas&6;}// a corner is required
+  void  SetCorner(){ cas |= 4;}
+  void  SetRequired(){ cas |= 2;}
+  void  Set(){cas=0;}
+  GeometricalVertex() :cas(0), link(this) {};
+  GeometricalVertex * The() { assert(link); return link;}// return a unique vertices
+  int IsThe() const { return link == this;}  
+  
+inline void Set(const GeometricalVertex & rec,const Geometry & Gh ,const Geometry & GhNew);
+  inline friend ostream& operator <<(ostream& f, const  GeometricalVertex & s) 
+     { f << s.r << "," << s.cas << ".";return f; }
+};
+
+/////////////////////////////////////////////////////////////////////////////////////
+class GeometricalEdge {
+  public:
+   GeometricalVertex * v[2];
+   Int4 ref;
+   Int4  CurveNumber;
+  R2 tg[2]; // the 2 tangente 
+  //   if tg[0] =0 => no continuite 
+  GeometricalEdge * Adj [2]; 
+  int SensAdj[2];
+//  private:
+  int flag ;
+  public: 
+  GeometricalEdge * link; // if   Cracked() or Equi()
+
+// end of data 
+  
+  GeometricalVertex & operator[](int i){return *v[i];};
+  const GeometricalVertex & operator[](int i) const { return *v[i];};
+  GeometricalVertex * operator()(int i){return v[i];};  
+ // inline void Set(const Geometry &,Int4,Geometry &);
+
+  R2 F(Real8 theta) const ; // parametrization of the curve edge
+  Real8 R1tg(Real8 theta,R2 &t) const ; // 1/radius of curvature + tangente
+  int Cracked() const {return flag & 1;}
+  int Dup() const { return flag & 32;}
+  int Equi()const {return flag & 2;}
+  int ReverseEqui()const {return flag & 128;}
+  int TgA()const {return flag &4;}
+  int TgB()const {return flag &8;}
+  int Tg(int i) const{return i==0 ? TgA() : TgB();}
+  int Mark()const {return flag &16;}
+  int Required() { return flag & 64;}
+  void SetCracked() { flag |= 1;}
+  void SetDup()     { flag |= 32;} // not a real edge 
+  void SetEqui()    { flag |= 2;}
+  void SetTgA()     { flag|=4;}
+  void SetTgB()     { flag|=8;}
+  void SetMark()    { flag|=16;}
+  void SetUnMark()  { flag &= 1007 /* 1023-16*/;}
+  void SetRequired() { flag |= 64;}
+  void SetReverseEqui() {flag |= 128;}
+  
+  inline void Set(const GeometricalEdge & rec,const Geometry & Th ,Geometry & ThNew);
+
+#ifdef DRAWING 
+  void Draw(Int4  =-1);
+#endif
+  
+};
+  
+class Curve {public:
+ GeometricalEdge * be,*ee; // begin et end edge
+ int kb,ke;  //  begin vetex and end vertex
+ Curve *next; // next curve equi to this
+ bool master; // true => of equi curve point on this curve  
+ inline void Set(const Curve & rec,const Geometry & Th ,Geometry & ThNew);
+ Curve() : be(0),ee(0),kb(0),ke(0),next(0),master(true) {} 
+ void Reverse() { Exchange(be,ee); Exchange(kb,ke);} //  revese the sens of the curse 
+};
+  
+   
+
+/////////////////////////////////////////////////////////////////////////////////////
+class Triangle {
+  friend class TriangleAdjacent;
+  friend ostream& operator <<(ostream& f, const  Triangle & ta);
+
+
+  private: // les arete sont opposes a un sommet
+  Vertex * ns [3]; // 3 vertices if t is triangle, t[i] allowed by access function, (*t)[i] if pointer
+  Triangle * at [3]; // nu triangle adjacent  
+  Int1  aa[3];  // les nu des arete dans le triangles (mod 4)
+  public: 
+  Icoor2 det; // determinant du triangle (2 fois l aire des vertices entieres)
+  union { 
+    Triangle * link ;
+    Int4 color;
+  };
+  void SetDet() {
+    if(ns[0] && ns[1] && ns[2])    det = bamg::det(*ns[0],*ns[1],*ns[2]);
+    else det = -1; }
+  Triangle() {}
+  Triangle(Triangles *Th,Int4 i,Int4 j,Int4 k);
+  Triangle(Vertex *v0,Vertex *v1,Vertex *v2);
+  inline void Set(const Triangle &,const Triangles &,Triangles &);
+  inline int In(Vertex *v) const { return ns[0]==v || ns[1]==v || ns[2]==v ;}
+  TriangleAdjacent FindBoundaryEdge(int ) const;
+
+  void ReNumbering(Triangle *tb,Triangle *te, Int4 *renu) 
+   {
+    if (link  >=tb && link  <te) link  = tb + renu[link -tb];
+    if (at[0] >=tb && at[0] <te) at[0] = tb + renu[at[0]-tb];
+    if (at[1] >=tb && at[1] <te) at[1] = tb + renu[at[1]-tb];
+    if (at[2] >=tb && at[2] <te) at[2] = tb + renu[at[2]-tb];    
+   }
+  void ReNumbering(Vertex *vb,Vertex *ve, Int4 *renu) 
+   {
+    if (ns[0] >=vb && ns[0] <ve) ns[0] = vb + renu[ns[0]-vb];
+    if (ns[1] >=vb && ns[1] <ve) ns[1] = vb + renu[ns[1]-vb];
+    if (ns[2] >=vb && ns[2] <ve) ns[2] = vb + renu[ns[2]-vb];    
+   }
+
+
+  const Vertex & operator[](int i) const {return *ns[i];};
+  Vertex & operator[](int i)  {return *ns[i];};
+  
+  const Vertex  *  operator()(int i) const {return ns[i];};
+  Vertex  * & operator()(int i)  {return ns[i];};
+  
+  TriangleAdjacent Adj(int  i) const  // triangle adjacent + arete 
+  { return TriangleAdjacent(at[i],aa[i]&3);};
+
+  Triangle * TriangleAdj(int  i) const 
+  {return at[i&3];} // triangle adjacent + arete 
+  Int1  NuEdgeTriangleAdj(int  i) const 
+  {return aa[i&3]&3;} // Number of the  adjacent edge in adj tria  
+
+  inline Real4 qualite() ;
+  
+
+  void SetAdjAdj(Int1 a) 
+  { a &= 3;
+   register  Triangle *tt=at[a];
+   aa [a] &= 55; // remove MarkUnSwap
+   register Int1 aatt = aa[a] & 3;
+   if(tt){ 
+     tt->at[aatt]=this;
+     tt->aa[aatt]=a + (aa[a] & 60 ) ;}// Copy all the mark 
+  }
+  
+  void SetAdj2(Int1 a,Triangle *t,Int1 aat)
+    {  at[a]=t;aa[a]=aat;
+    if(t) {t->at[aat]=this;t->aa[aat]=a;}
+    }
+    
+  void SetTriangleContainingTheVertex()
+   { 
+     if (ns[0]) (ns[0]->t=this,ns[0]->vint=0);
+     if (ns[1]) (ns[1]->t=this,ns[1]->vint=1);
+     if (ns[2]) (ns[2]->t=this,ns[2]->vint=2);
+   }
+   
+  int swap(Int2 a1,int=0);
+  Int4  Optim(Int2 a,int =0);
+
+  int  Locked(int a)const { return aa[a]&4;} 
+  int  Hidden(int a)const { return aa[a]&16;} 
+  int  Cracked(int a) const { return aa[a] & 32;}
+  // for optimisation 
+  int  GetAllflag(int a){return aa[a] & 1020;}
+  void SetAllFlag(int a,int f){aa[a] = (aa[a] &3) + (1020 & f);}
+
+  void SetHidden(int a){
+   register Triangle * t = at[a];
+    if(t) t->aa[aa[a] & 3] |=16;
+    aa[a] |= 16;}
+  void SetCracked(int a){
+   register Triangle * t = at[a];
+    if(t) t->aa[aa[a] & 3] |=32;
+    aa[a] |= 32;}
+  
+  double   QualityQuad(int a,int option=1) const;
+  Triangle * Quadrangle(Vertex * & v0,Vertex * & v1,Vertex * & v2,Vertex * & v3) const ;
+
+  void SetLocked(int a){
+    register Triangle * t = at[a];
+    t->aa[aa[a] & 3] |=4;
+    aa[a] |= 4;}
+
+  void SetMarkUnSwap(int a){
+    register Triangle * t = at[a];
+    t->aa[aa[a] & 3] |=8;
+    aa[a] |=8 ;}
+
+
+  void SetUnMarkUnSwap(int a){ 
+    register Triangle * t = at[a];
+    t->aa[aa[a] & 3] &=55; // 23 + 32 
+    aa[a] &=55 ;}
+  
+
+ 
+#ifdef DEBUG       
+  void inline checka(Int1 a); 
+  void inline check();
+#endif
+
+#ifdef DRAWING
+  void  Draw(Int4 i=-1) const;
+  int swapDRAW(Int2 a1);
+
+#endif
+
+};  // end of Triangle class 
+
+
+
+
+class ListofIntersectionTriangles {
+/////////////////////////////////////////////////////////////////////////////////////
+class IntersectionTriangles {
+public: 
+  Triangle *t;
+  Real8  bary[3];  // use if t != 0
+  R2 x;
+  Metric m;
+  Real8 s;// abscisse curviline
+  Real8 sp; // len of the previous seg in m
+  Real8 sn;// len of the  next seg in m
+};
+/////////////////////////////////////////////////////////////////////////////////////
+class SegInterpolation {
+ public:
+  GeometricalEdge * e;
+  Real8 sBegin,sEnd; // abscisse of the seg on edge parameter
+  Real8 lBegin,lEnd; // length abscisse  set in ListofIntersectionTriangles::Length
+  int last;// last index  in ListofIntersectionTriangles for this Sub seg of edge
+  R2 F(Real8 s){ 
+    Real8 c01=lEnd-lBegin, c0=(lEnd-s)/c01, c1=(s-lBegin)/c01;
+    assert(lBegin<= s && s <=lEnd);
+    return e->F(sBegin*c0+sEnd*c1);}
+};
+ 
+ int MaxSize; // 
+ int Size; //
+ Real8 len; //
+ int state;
+ IntersectionTriangles * lIntTria;
+ int NbSeg;
+ int MaxNbSeg;
+ SegInterpolation * lSegsI;
+ public:
+ IntersectionTriangles & operator[](int i) {return lIntTria[i];}
+ operator int&() {return Size;}
+ ListofIntersectionTriangles(int n=256,int m=16)
+   :   MaxSize(n), Size(0), len(-1),state(-1),lIntTria(new IntersectionTriangles[n]) ,
+    NbSeg(0), MaxNbSeg(m), lSegsI(new SegInterpolation[m])  
+  { if (verbosity>9) 
+    cout << "      construct ListofIntersectionTriangles"
+			  << MaxSize << " " <<  MaxNbSeg<< endl;};
+  ~ListofIntersectionTriangles(){
+    if (lIntTria) delete [] lIntTria,lIntTria=0;
+    if (lSegsI) delete [] lSegsI,lSegsI=0;} 
+  void init(){state=0;len=0;Size=0;}
+  
+  int NewItem(Triangle * tt,Real8 d0,Real8 d1,Real8 d2);
+  int NewItem(R2,const Metric & );
+  void NewSubSeg(GeometricalEdge *e,Real8 s0,Real8 s1) 
+    { 
+      if (NbSeg>=MaxNbSeg) {
+           int mneo= MaxNbSeg;
+           MaxNbSeg *= 2;
+          if (verbosity>3) 
+	    cout <<" reshape lSegsI from " << mneo << " to " 
+		 << MaxNbSeg <<endl;
+           SegInterpolation * lEn =  new SegInterpolation[MaxNbSeg];
+           assert(lSegsI && NbSeg < MaxNbSeg);
+           for (int i=0;i< NbSeg;i++) 
+              lEn[i] = lSegsI[MaxNbSeg]; // copy old to new            
+           delete []  lSegsI; // remove old
+           lSegsI = lEn;        
+           }
+       if (NbSeg) 
+         lSegsI[NbSeg-1].last=Size;
+       lSegsI[NbSeg].e=e;
+       lSegsI[NbSeg].sBegin=s0;
+       lSegsI[NbSeg].sEnd=s1;     
+       NbSeg++;           
+    }
+    
+//  void CopyMetric(int i,int j){ lIntTria[j].m=lIntTria[i].m;}
+//  void CopyMetric(const Metric & mm,int j){ lIntTria[j].m=mm;}
+
+  void ReShape() { 
+    register int newsize = MaxSize*2;
+    IntersectionTriangles * nw = new IntersectionTriangles[newsize];
+    assert(nw);
+    for (int i=0;i<MaxSize;i++) // recopy
+      nw[i] = lIntTria[i];       
+    if(verbosity>3)
+      cout << " ListofIntersectionTriangles  ReShape MaxSize " 
+	   << MaxSize << " -> " 
+	 <<  newsize << endl;
+    MaxSize = newsize; 
+    delete [] lIntTria;// remove old
+    lIntTria = nw; // copy pointer
+  }
+  
+  void SplitEdge(const Triangles & ,const R2 &,const R2  &,int nbegin=0); 
+  Real8 Length(); 
+  Int4 NewPoints(Vertex *,Int4 & nbv,Int4 nbvx);
+};
+
+
+/////////////////////////////////////////////////////////////////////////////////////
+class GeometricalSubDomain {
+public:
+  GeometricalEdge *edge;
+  int sens; // -1 or 1
+  Int4 ref;
+  inline void Set(const GeometricalSubDomain &,const Geometry & ,const Geometry &);
+  
+};
+/////////////////////////////////////////////////////////////////////////////////////
+class SubDomain {
+public:
+  Triangle * head;
+  Int4  ref;  
+  int sens; // -1 or 1
+  Edge * edge; // to  geometrical 	
+  inline void Set(const Triangles &,Int4,Triangles &);
+  	 
+};
+/////////////////////////////////////////////////////////////////////////////////////
+class VertexOnGeom {  public:
+
+  Vertex * mv;
+  Real8 abscisse;  
+  union{ 
+    GeometricalVertex * gv; // if abscisse <0; 
+    GeometricalEdge * ge;  // if abscisse in [0..1]
+  };
+  inline void Set(const VertexOnGeom&,const Triangles &,Triangles &);  
+  int OnGeomVertex()const {return this? abscisse <0 :0;}
+  int OnGeomEdge() const {return this? abscisse >=0 :0;}
+  VertexOnGeom(): mv(0),abscisse(0){gv=0;} 
+  VertexOnGeom(Vertex & m,GeometricalVertex &g) : mv(&m),abscisse(-1){gv=&g;}
+   //  cout << "        mv = " <<mv << " gv = "  << gv << endl;} 
+  VertexOnGeom(Vertex & m,GeometricalEdge &g,Real8 s) : mv(&m),abscisse(s){ge=&g;}
+    //cout << &g << " "  << ge << endl;} 
+  operator Vertex * () const  {return mv;}
+  operator GeometricalVertex * () const  {return gv;}
+  operator GeometricalEdge * () const  {return ge;}
+//  operator Real8 & () {return abscisse;}
+  operator const Real8 & () const {return abscisse;}
+  int IsRequiredVertex(){ return this? (( abscisse<0 ? (gv?gv->Required():0):0 )) : 0;}
+  void SetOn(){mv->on=this;mv->vint=IsVertexOnGeom;}
+  friend ostream& operator <<(ostream& f, const  VertexOnGeom & vog){
+    f << vog.abscisse << " " << vog.mv << " " << vog.gv << " ; ";
+    if (vog.abscisse < 0) f << *vog.gv << " ;; " ;
+    //    else f << *vog.ge << " ;; " ;
+    return f;}
+  inline void Set(const Triangles &,Int4,Triangles &);
+    
+};
+/////////////////////////////////////////////////////////////////////////////////////
+class VertexOnVertex {public:
+  Vertex * v, *bv;
+  VertexOnVertex(Vertex * w,Vertex *bw) :v(w),bv(bw){}
+  VertexOnVertex() {};
+  inline void Set(const Triangles &,Int4,Triangles &);
+  void SetOnBTh(){v->onbv=bv;v->vint=IsVertexOnVertex;}
+};
+/////////////////////////////////////////////////////////////////////////////////////
+class VertexOnEdge {public:
+  Vertex * v;
+  Edge * be;
+  Real8 abcisse;
+  VertexOnEdge( Vertex * w, Edge *bw,Real8 s) :v(w),be(bw),abcisse(s) {}
+  VertexOnEdge(){}
+  inline void Set(const Triangles &,Int4,Triangles &);  
+  void SetOnBTh(){v->onbe=this;v->vint=IsVertexOnEdge;}  
+  Vertex & operator[](int i) const { return (*be)[i];}
+  operator Real8 () const { return abcisse;}
+  operator  Vertex *  () const { return v;}  
+  operator  Edge *  () const { return be;}  
+};
+
+ inline TriangleAdjacent FindTriangleAdjacent(Edge &E);
+ inline Vertex * TheVertex(Vertex * a); // for remove crak in mesh 
+/////////////////////////////////////////////////////////////////////////////////////
+ 
+class CrackedEdge { // a small class to store on crack an uncrack information 
+  friend class Triangles;
+  friend ostream& operator <<(ostream& f, const   Triangles & Th) ;  
+ class CrackedTriangle {
+  friend class Triangles;
+  friend class CrackedEdge;
+  friend ostream& operator <<(ostream& f, const   Triangles & Th) ;  
+  Triangle * t; // edge of triangle t
+  int i; //  edge number of in triangle
+  Edge *edge; // the  2 edge 
+  Vertex *New[2]; // new vertex number 
+  CrackedTriangle() : t(0),i(0),edge(0) { New[0]=New[1]=0;} 
+  CrackedTriangle(Edge * a) : t(0),i(0),edge(a) { New[0]=New[1]=0;} 
+  void Crack(){ 
+    Triangle & T(*t); 
+    int i0=VerticesOfTriangularEdge[i][0];
+    int i1=VerticesOfTriangularEdge[i][0];
+    assert(New[0] && New[1]);
+    T(i0) = New[0];
+    T(i1) = New[1];}    
+  void UnCrack(){ 
+    Triangle & T(*t); 
+    int i0=VerticesOfTriangularEdge[i][0];
+    int i1=VerticesOfTriangularEdge[i][0];
+    assert(New[0] && New[1]);
+    T(i0) = TheVertex(T(i0));
+    T(i1) = TheVertex(T(i1));} 
+  void Set() {
+     TriangleAdjacent ta ( FindTriangleAdjacent(*edge));
+     t = ta;
+     i = ta;
+     
+     New[0] = ta.EdgeVertex(0);
+     New[1] = ta.EdgeVertex(1);
+     // warning the ref 
+     
+     }    
+     
+  }; // end of class CrackedTriangle
+ public:  
+  CrackedTriangle a,b; 
+  CrackedEdge() :a(),b() {}
+  CrackedEdge(Edge * start, Int4  i,Int4 j) : a(start+i),b(start+j) {};
+  CrackedEdge(Edge * e0, Edge * e1 ) : a(e0),b(e1) {};
+
+  void Crack() { a.Crack(); b.Crack();}
+  void UnCrack() { a.UnCrack(); b.UnCrack();}
+  void Set() { a.Set(), b.Set();}
+};
+
+/////////////////////////////////////////////////////////////////////////////////////
+
+class Triangles { 
+public:
+
+  enum TypeFileMesh {
+    AutoMesh=0,BDMesh=1,NOPOMesh=2,amMesh=3,am_fmtMesh=4,amdbaMesh=5,
+    ftqMesh=6,mshMesh=7};
+
+  int static counter; // to kown the number of mesh in memory 
+  int OnDisk;       // true if on disk 
+  Geometry & Gh;   // Geometry
+  Triangles & BTh; // Background Mesh Bth==*this =>no  background 
+  
+  Int4 NbRef; // counter of ref on the this class if 0 we can delete
+  Int4 nbvx,nbtx;  // nombre max  de sommets , de  triangles
+  
+  Int4 nt,nbv,nbt,nbiv,nbe; // nb of legal triangles, nb of vertex, of triangles, 
+  // of initial vertices, of edges with reference,
+  Int4 NbOfQuad; // nb of quadrangle 
+
+  Int4 NbSubDomains; // 
+  Int4 NbOutT; // Nb of oudeside triangle
+  Int4 NbOfTriangleSearchFind;
+  Int4 NbOfSwapTriangle;
+  char * name, *identity;
+  Vertex * vertices;   // data of vertices des sommets
+  
+  Int4 NbVerticesOnGeomVertex;
+  VertexOnGeom * VerticesOnGeomVertex;
+  
+  Int4 NbVerticesOnGeomEdge;
+  VertexOnGeom * VerticesOnGeomEdge;
+
+  Int4 NbVertexOnBThVertex;
+  VertexOnVertex *VertexOnBThVertex;
+
+  Int4 NbVertexOnBThEdge;
+  VertexOnEdge *VertexOnBThEdge;
+
+  
+  Int4 NbCrackedVertices;
+  
+
+  Int4 NbCrackedEdges;
+  CrackedEdge *CrackedEdges;
+  
+  
+  R2 pmin,pmax; // extrema
+  Real8 coefIcoor;  // coef to integer Icoor1;
+
+  Triangle * triangles;
+  Edge * edges; 
+
+  QuadTree *quadtree;
+  Vertex ** ordre;
+  SubDomain * subdomains;
+  ListofIntersectionTriangles  lIntTria;
+// end of variable
+  
+  Triangles(Int4 i);//:BTh(*this),Gh(*new Geometry()){PreInit(i);}
+  
+  ~Triangles(); 
+  Triangles(const char * ,Real8=-1) ;
+  
+  Triangles(Int4 nbvx,Triangles & BT,int keepBackVertices=1)
+         :Gh(BT.Gh),BTh(BT) {
+	     try {GeomToTriangles1(nbvx,keepBackVertices);}
+	      catch(...) { this->~Triangles(); throw; } }
+  
+  Triangles(Int4 nbvx,Geometry & G)
+         :Gh(G),BTh(*this){
+	     try { GeomToTriangles0(nbvx);}
+	     catch(...) { this->~Triangles(); throw; } }
+  Triangles(Triangles &,Geometry * pGh=0,Triangles* pBTh=0,Int4 nbvxx=0 ); // COPY OPERATEUR
+  //  Triangles(Triangles &){ cerr << " BUG call copy opretor of Triangles" << endl;MeshError(111);}
+  Triangles(const Triangles &,const int *flag,const int *bb); // truncature
+  
+
+  void SetIntCoor(const char * from =0);
+
+ // void  RandomInit();
+ // void  CubeInit(int ,int);
+  
+  Real8 MinimalHmin() {return 2.0/coefIcoor;}
+  Real8 MaximalHmax() {return Max(pmax.x-pmin.x,pmax.y-pmin.y);}
+  const Vertex & operator[]  (Int4 i) const { return vertices[i];};
+  Vertex & operator[](Int4 i) { return vertices[i];};
+  const Triangle & operator()  (Int4 i) const { return triangles[i];};
+  Triangle & operator()(Int4 i) { return triangles[i];};
+  I2 toI2(const R2 & P) const {
+          return  I2( (Icoor1) (coefIcoor*(P.x-pmin.x))
+	                 ,(Icoor1) (coefIcoor*(P.y-pmin.y)) );}
+  R2 toR2(const I2 & P) const {
+          return  R2( (double) P.x/coefIcoor+pmin.x, (double) P.y/coefIcoor+pmin.y);}
+  void Add( Vertex & s,Triangle * t,Icoor2 *  =0) ;
+  void Insert();
+  //  void InsertOld();
+  void ForceBoundary();
+  void Heap();
+  void FindSubDomain(int );
+  Int4  ConsRefTriangle(Int4 *) const;
+  void ShowHistogram() const;
+  void  ShowRegulaty() const; // Add FH avril 2007 
+//  void ConsLinkTriangle();
+
+  void ReMakeTriangleContainingTheVertex();
+  void UnMarkUnSwapTriangle();
+  void SmoothMetric(Real8 raisonmax) ;
+  void BoundAnisotropy(Real8 anisomax,double hminaniso= 1e-100) ;
+  void MaxSubDivision(Real8 maxsubdiv);
+  void WriteMetric(ostream &,int iso) ;
+  Edge** MakeGeometricalEdgeToEdge();
+  void  SetVertexFieldOn();  
+  void  SetVertexFieldOnBTh();
+  Int4 SplitInternalEdgeWithBorderVertices();
+  void MakeQuadrangles(double costheta);
+  int SplitElement(int choice);
+  void MakeQuadTree();
+  void NewPoints( Triangles &,int KeepBackVertex =1 );
+  Int4 InsertNewPoints(Int4 nbvold,Int4 & NbTSwap) ; 
+  void NewPointsOld( Triangles & );
+  void NewPoints(int KeepBackVertex=1){ NewPoints(*this,KeepBackVertex);}
+  void ReNumberingTheTriangleBySubDomain(bool justcompress=false);
+  void ReNumberingVertex(Int4 * renu);
+  void SmoothingVertex(int =3,Real8=0.3);
+  Metric MetricAt (const R2 &) const;
+  GeometricalEdge * ProjectOnCurve( Edge & AB, Vertex &  A, Vertex & B,Real8 theta,
+                      Vertex & R,VertexOnEdge & BR,VertexOnGeom & GR);
+   
+  
+  void WriteElements(ostream& f,Int4 * reft ,Int4 nbInT) const;
+
+  
+  Int4 Number(const Triangle & t) const  { return &t - triangles;}
+  Int4 Number(const Triangle * t) const  { return t - triangles;}
+  Int4 Number(const Vertex & t) const  { return &t - vertices;}
+  Int4 Number(const Vertex * t) const  { return t - vertices;}
+  Int4 Number(const Edge & t) const  { return &t - edges;}
+  Int4 Number(const Edge * t) const  { return t - edges;}
+  Int4 Number2(const Triangle * t) const  {
+    //   if(t>= triangles && t < triangles + nbt )
+      return t - triangles;
+      //  else  return t - OutSidesTriangles;
+  }
+  
+  Vertex * NearestVertex(Icoor1 i,Icoor1 j) ;
+  Triangle * FindTriangleContening(const I2 & ,Icoor2 [3],Triangle *tstart=0) const;
+  void Write(const char * filename,const TypeFileMesh type = AutoMesh);
+  void Write_am_fmt(ostream &) const ;
+  void Write_am(ostream &) const ;
+  void Write_ftq(ostream &) const ;
+  void Write_nopo(ostream &) const ;
+  void Write_msh(ostream &) const ;
+  void Write_amdba(ostream &) const ;
+
+  void Read(MeshIstream &,int version,Real8 cutoffradian);
+  void Read_am_fmt(MeshIstream &);
+  void Read_amdba(MeshIstream &);
+  void Read_am(MeshIstream &);
+  void Read_nopo(MeshIstream &);
+  void Read_ftq(MeshIstream &);
+  void Read_msh(MeshIstream &);
+
+  void ReadMetric(const char * fmetrix,const Real8 hmin,const Real8 hmax,const Real8 coef);
+  void IntersectConsMetric(const double * s,const Int4 nbsol,const int * typsols,
+			   const  Real8 hmin,const Real8 hmax, const Real8 coef,
+			   const Real8  anisomax,const Real8 CutOff=1.e-4,const int NbJacobi=1,
+			   const int DoNormalisation=1,
+			   const double power=1.0,
+			   const int choise=0);
+  void IntersectGeomMetric(const Real8 err,const int iso);
+  
+  
+  int  isCracked() const {return NbCrackedVertices != 0;}
+  int  Crack();
+  int UnCrack();
+  
+#ifdef DEBUG
+  void inline Check(); 
+#endif
+#ifdef DRAWING
+  void  Draw() const ;
+  void  InitDraw() const ;
+  void   inquire()  ;
+#endif
+ friend ostream& operator <<(ostream& f,  const  Triangles & Th); 
+  void  Write(const char * filename);
+  void ConsGeometry(Real8 =-1.0,int *equiedges=0); // construct a geometry if no geo 
+  void FillHoleInMesh() ;
+  int CrackMesh();
+ private:
+  void GeomToTriangles1(Int4 nbvx,int KeepBackVertices=1);// the  real constructor mesh adaption
+  void GeomToTriangles0(Int4 nbvx);// the  real constructor mesh generator
+  void PreInit(Int4,char * =0 );
+  //
+  void Write_nop5(OFortranUnFormattedFile * f,
+			     Int4 &lnop5,Int4 &nef,Int4 &lgpdn,Int4 ndsr) const ;
+
+  
+}; // End Class Triangles
+/////////////////////////////////////////////////////////////////////////////////////
+class Geometry { 
+public:
+  int OnDisk; 
+  Int4 NbRef; // counter of ref on the this class if 0 we can delete
+
+  char *name;
+  Int4 nbvx,nbtx; // nombre max  de sommets , de  Geometry
+  Int4 nbv,nbt,nbiv,nbe; // nombre de sommets, de Geometry, de sommets initiaux,
+  Int4 NbSubDomains; // 
+  Int4 NbEquiEdges;
+  Int4 NbCrackedEdges; 
+//  Int4 nbtf;//  de triangle frontiere
+  Int4 NbOfCurves;
+  int empty(){return (nbv ==0) && (nbt==0) && (nbe==0) && (NbSubDomains==0); }
+  GeometricalVertex * vertices;   // data of vertices des sommets 
+  Triangle * triangles; 
+  GeometricalEdge * edges;
+  QuadTree *quadtree;
+  GeometricalSubDomain *subdomains;
+  Curve *curves;
+  ~Geometry(); 
+  Geometry(const Geometry & Gh); //Copy  Operator 
+  Geometry(int nbg,const Geometry ** ag); // intersection operator 
+  
+  R2 pmin,pmax; // extrema
+  Real8 coefIcoor;  // coef to integer Icoor1;
+  Real8 MaximalAngleOfCorner;
+  
+//  end of data 
+
+  
+  I2 toI2(const R2 & P) const {
+          return  I2( (Icoor1) (coefIcoor*(P.x-pmin.x))
+	                 ,(Icoor1) (coefIcoor*(P.y-pmin.y)) );}
+  
+  Real8 MinimalHmin() {return 2.0/coefIcoor;}
+  Real8 MaximalHmax() {return Max(pmax.x-pmin.x,pmax.y-pmin.y);}
+  void ReadGeometry(const char * ) ;
+  void ReadGeometry(MeshIstream & ,const char *)  ;
+
+  void EmptyGeometry();
+  Geometry() {EmptyGeometry();}// empty Geometry
+  void AfterRead();
+  Geometry(const char * filename) {EmptyGeometry();OnDisk=1;ReadGeometry(filename);AfterRead();}
+
+  void ReadMetric(const char *,Real8 hmin,Real8 hmax,Real8 coef);
+  const GeometricalVertex & operator[]  (Int4 i) const { return vertices[i];};
+  GeometricalVertex & operator[](Int4 i) { return vertices[i];};
+  const  GeometricalEdge & operator()  (Int4 i) const { return edges[i];};
+  GeometricalEdge & operator()(Int4 i) { return edges[i];}; 
+  Int4 Number(const GeometricalVertex & t) const  { return &t - vertices;}
+  Int4 Number(const GeometricalVertex * t) const  { return t - vertices;}
+  Int4 Number(const GeometricalEdge & t) const  { return &t - edges;}
+  Int4 Number(const GeometricalEdge * t) const  { return t - edges;}
+  Int4 Number(const Curve * c) const  { return c - curves;}
+  
+  void UnMarkEdges() {
+    for (Int4 i=0;i<nbe;i++) edges[i].SetUnMark();}
+
+ GeometricalEdge *  ProjectOnCurve(const Edge & ,Real8,Vertex &,VertexOnGeom &) const ;
+  GeometricalEdge *  Contening(const R2 P,  GeometricalEdge * start) const;
+ friend ostream& operator <<(ostream& f, const   Geometry & Gh); 
+ void Write(const char * filename);
+ 
+#ifdef DEBUG
+  void inline Check();   
+#endif
+#ifdef DRAWING
+  void  Draw() const ;
+  void  InitDraw() const ;
+#endif
+  
+}; // End Class Geometry
+
+/////////////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////////////
+///////////////////           END CLASS          ////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////////////
+
+inline Triangles::Triangles(Int4 i) :Gh(*new Geometry()),BTh(*this){PreInit(i);}
+
+extern Triangles * CurrentTh;
+
+TriangleAdjacent CloseBoundaryEdge(I2 ,Triangle *, double &,double &) ;
+TriangleAdjacent CloseBoundaryEdgeV2(I2 A,Triangle *t, double &a,double &b);
+
+Int4 FindTriangle(Triangles &Th, Real8 x, Real8 y, double* a,int & inside);
+
+
+
+inline Triangle *    Triangle::Quadrangle(Vertex * & v0,Vertex * & v1,Vertex * & v2,Vertex * & v3) const
+{
+// return the other triangle of the quad if a quad or 0 if not a quat
+  Triangle * t =0;
+  if (link) {
+    int a=-1;
+    if (aa[0] & 16 ) a=0;
+    if (aa[1] & 16 ) a=1;
+    if (aa[2] & 16 ) a=2;
+    if (a>=0) {
+      t = at[a];
+      //  if (t-this<0) return 0;
+      v2 = ns[VerticesOfTriangularEdge[a][0]];
+      v0 = ns[VerticesOfTriangularEdge[a][1]];
+      v1 = ns[OppositeEdge[a]];
+      v3 = t->ns[OppositeEdge[aa[a]&3]];
+    }
+  }
+  return t;
+}
+
+inline   double   Triangle::QualityQuad(int a,int option) const
+{ // first do the logique part 
+  double q;
+  if (!link || aa[a] &4)
+    q=  -1;
+  else {
+    Triangle * t = at[a];
+    if (t-this<0) q=  -1;// because we do 2 times 
+    else if (!t->link ) q=  -1;
+    else if (aa[0] & 16 || aa[1] & 16  || aa[2] & 16 || t->aa[0] & 16 || t->aa[1] & 16 || t->aa[2] & 16 )
+      q= -1;
+    else if(option) 
+      { 
+	const Vertex & v2 = *ns[VerticesOfTriangularEdge[a][0]];
+	const Vertex & v0 = *ns[VerticesOfTriangularEdge[a][1]];
+	const Vertex & v1 = *ns[OppositeEdge[a]];
+	const Vertex & v3 = * t->ns[OppositeEdge[aa[a]&3]];
+	q =  QuadQuality(v0,v1,v2,v3); // do the float part
+      }
+    else q= 1;
+  }
+  return  q;
+}
+
+
+inline void Vertex::Set(const Vertex & rec,const Triangles & ,Triangles & )
+ { 
+   *this  = rec;
+ }
+inline void GeometricalVertex::Set(const GeometricalVertex & rec,const Geometry & ,const Geometry & )
+ { 
+   *this  = rec;
+ }
+inline void Edge::Set(const Triangles & Th ,Int4 i,Triangles & ThNew)
+ { 
+   *this = Th.edges[i];
+   v[0] = ThNew.vertices + Th.Number(v[0]);    
+   v[1] = ThNew.vertices + Th.Number(v[1]);
+   if (on) 
+     on =  ThNew.Gh.edges+Th.Gh.Number(on);
+   if (adj[0]) adj[0] =   ThNew.edges +   Th.Number(adj[0]);
+   if (adj[1]) adj[1] =   ThNew.edges +   Th.Number(adj[1]);
+
+ }
+inline void GeometricalEdge::Set(const GeometricalEdge & rec,const Geometry & Gh ,Geometry & GhNew)
+ { 
+   *this = rec;
+   v[0] = GhNew.vertices + Gh.Number(v[0]);    
+   v[1] = GhNew.vertices + Gh.Number(v[1]); 
+   if (Adj[0]) Adj[0] =  GhNew.edges + Gh.Number(Adj[0]);     
+   if (Adj[1]) Adj[1] =  GhNew.edges + Gh.Number(Adj[1]);     
+ }
+ 
+inline void Curve::Set(const Curve & rec,const Geometry & Gh ,Geometry & GhNew)
+{
+  *this = rec;
+   be = GhNew.edges + Gh.Number(be);    
+   ee = GhNew.edges + Gh.Number(ee); 
+   if(next) next= GhNew.curves + Gh.Number(next); 
+}
+
+inline void Triangle::Set(const Triangle & rec,const Triangles & Th ,Triangles & ThNew)
+ { 
+   *this = rec;
+   if ( ns[0] ) ns[0] = ThNew.vertices +  Th.Number(ns[0]);
+   if ( ns[1] ) ns[1] = ThNew.vertices +  Th.Number(ns[1]);
+   if ( ns[2] ) ns[2] = ThNew.vertices +  Th.Number(ns[2]);
+   if(at[0]) at[0] =  ThNew.triangles + Th.Number(at[0]);
+   if(at[1]) at[1] =  ThNew.triangles + Th.Number(at[1]);
+   if(at[2]) at[2] =  ThNew.triangles + Th.Number(at[2]);
+   if (link  >= Th.triangles && link  < Th.triangles + Th.nbt)
+     link = ThNew.triangles + Th.Number(link);
+ }
+inline void VertexOnVertex::Set(const Triangles & Th ,Int4 i,Triangles & ThNew)
+{ 
+  *this = Th.VertexOnBThVertex[i];  
+  v = ThNew.vertices + Th.Number(v);
+
+}
+inline void SubDomain::Set(const Triangles & Th ,Int4 i,Triangles & ThNew)
+{
+  *this = Th.subdomains[i];
+  assert( head - Th.triangles >=0 && head - Th.triangles < Th.nbt);
+  head = ThNew.triangles + Th.Number(head) ; 
+  assert(edge - Th.edges >=0 && edge - Th.edges < Th.nbe); 
+  edge = ThNew.edges+ Th.Number(edge);
+}
+ inline void GeometricalSubDomain::Set(const GeometricalSubDomain & rec,const Geometry & Gh ,const Geometry & GhNew)
+{
+   *this = rec;
+   edge = Gh.Number(edge) + GhNew.edges;
+}
+inline void VertexOnEdge::Set(const Triangles & Th ,Int4 i,Triangles & ThNew)
+{
+  *this = Th.VertexOnBThEdge[i];  
+  v = ThNew.vertices + Th.Number(v);
+}
+
+inline void VertexOnGeom::Set(const VertexOnGeom & rec,const Triangles & Th ,Triangles & ThNew)
+{
+  *this = rec;  
+  mv = ThNew.vertices + Th.Number(mv);
+  if (gv)
+    if (abscisse < 0 )
+      gv = ThNew.Gh.vertices + Th.Gh.Number(gv);
+    else
+      ge = ThNew.Gh.edges + Th.Gh.Number(ge);
+  
+}
+inline Real8 Edge::MetricLength() const
+  { 
+    return LengthInterpole(v[0]->m,v[1]->m,v[1]->r - v[0]->r) ;
+  }
+
+inline  void  Triangles::ReMakeTriangleContainingTheVertex()
+ {
+  register Int4 i;
+  for ( i=0;i<nbv;i++) 
+    {
+	vertices[i].vint = 0;
+	vertices[i].t=0;
+    }
+  for ( i=0;i<nbt;i++) 
+    triangles[i].SetTriangleContainingTheVertex();
+ }
+
+inline  void  Triangles::UnMarkUnSwapTriangle()
+ {
+  register Int4 i;
+  for ( i=0;i<nbt;i++) 
+    for(int  j=0;j<3;j++)
+      triangles[i].SetUnMarkUnSwap(j);
+ }
+
+inline  void   Triangles::SetVertexFieldOn()
+  {
+    for (Int4 i=0;i<nbv;i++) 
+       vertices[i].on=0;
+    for (Int4 j=0;j<NbVerticesOnGeomVertex;j++ ) 
+       VerticesOnGeomVertex[j].SetOn();
+    for (Int4 k=0;k<NbVerticesOnGeomEdge;k++ ) 
+       VerticesOnGeomEdge[k].SetOn();
+    }	       
+inline  void   Triangles::SetVertexFieldOnBTh()
+  {
+    for (Int4 i=0;i<nbv;i++) 
+       vertices[i].on=0;
+    for (Int4 j=0;j<NbVertexOnBThVertex;j++ ) 
+       VertexOnBThVertex[j].SetOnBTh();
+    for (Int4 k=0;k<NbVertexOnBThEdge;k++ ) 
+       VertexOnBThEdge[k].SetOnBTh();
+       
+    }	       
+
+inline  void  TriangleAdjacent::SetAdj2(const TriangleAdjacent & ta, int l  )
+{ // set du triangle adjacent 
+  if(t) {
+    t->at[a]=ta.t;
+    t->aa[a]=ta.a|l;}
+  if(ta.t) {
+    ta.t->at[ta.a] = t ;
+    ta.t->aa[ta.a] = a| l ;
+  }
+}
+
+
+inline int  TriangleAdjacent::Locked() const
+{ return t->aa[a] &4;}
+inline int  TriangleAdjacent::Cracked() const
+{ return t->aa[a] &32;}
+inline int  TriangleAdjacent::GetAllFlag_UnSwap() const
+{ return t->aa[a] & 1012;} // take all flag except MarkUnSwap
+
+inline int  TriangleAdjacent::MarkUnSwap() const
+{ return t->aa[a] &8;}
+
+inline void  TriangleAdjacent::SetLock(){ t->SetLocked(a);}
+
+inline void  TriangleAdjacent::SetCracked() { t->SetCracked(a);}
+
+inline  TriangleAdjacent TriangleAdjacent::Adj() const
+{ return  t->Adj(a);}
+
+inline Vertex  * TriangleAdjacent::EdgeVertex(const int & i) const
+ {return t->ns[VerticesOfTriangularEdge[a][i]]; }
+inline Vertex  * TriangleAdjacent::OppositeVertex() const
+{return t->ns[bamg::OppositeVertex[a]]; }
+inline Icoor2 &  TriangleAdjacent::det() const
+{ return t->det;}
+inline  TriangleAdjacent Adj(const TriangleAdjacent & a)
+{ return  a.Adj();}
+
+inline TriangleAdjacent Next(const TriangleAdjacent & ta) 
+{ return TriangleAdjacent(ta.t,NextEdge[ta.a]);}
+
+inline TriangleAdjacent Previous(const TriangleAdjacent & ta) 
+{ return TriangleAdjacent(ta.t,PreviousEdge[ta.a]);}
+ 
+inline void Adj(GeometricalEdge * & on,int &i) 
+  {int j=i;i=on->SensAdj[i];on=on->Adj[j];}
+  
+inline Real4 qualite(const Vertex &va,const Vertex &vb,const Vertex &vc)
+{
+  Real4 ret; 
+  I2 ia=va,ib=vb,ic=vc;
+  I2 ab=ib-ia,bc=ic-ib,ac=ic-ia;
+  Icoor2 deta=Det(ab,ac);
+  if (deta <=0) ret = -1;
+   else {
+     Real8 a = sqrt((Real8) (ac,ac)),
+       b = sqrt((Real8) (bc,bc)),
+       c = sqrt((Real8) (ab,ab)),
+       p = a+b+c;
+     Real8 h= Max(Max(a,b),c),ro=deta/p;
+   ret = ro/h;}
+  return ret;
+}
+
+
+inline  Triangle::Triangle(Triangles *Th,Int4 i,Int4 j,Int4 k) {
+  Vertex *v=Th->vertices;
+  Int4 nbv = Th->nbv;
+  assert(i >=0 && j >=0 && k >=0);
+  assert(i < nbv && j < nbv && k < nbv);
+  ns[0]=v+i;
+  ns[1]=v+j;
+  ns[2]=v+k;
+  at[0]=at[1]=at[2]=0;
+  aa[0]=aa[1]=aa[2]=0;
+  det=0;
+}
+
+inline  Triangle::Triangle(Vertex *v0,Vertex *v1,Vertex *v2){
+  ns[0]=v0;
+  ns[1]=v1;
+  ns[2]=v2;
+  at[0]=at[1]=at[2]=0;
+  aa[0]=aa[1]=aa[2]=0;
+  if (v0) det=0;
+  else {
+    det=-1;
+    link=NULL;};  
+}
+
+inline    Real4 Triangle::qualite()
+{
+  return det < 0 ? -1 :  bamg::qualite(*ns[0],*ns[1],*ns[2]);
+}
+
+Int4 inline  Vertex::Optim(int i,int koption)
+{ 
+  Int4 ret=0;
+  if ( t && (vint >= 0 ) && (vint <3) )
+    {
+      ret = t->Optim(vint,koption);
+      if(!i) 
+	{
+	  t =0; // for no future optime 
+	  vint= 0; }
+    }
+  return ret;
+}
+
+Icoor2 inline det(const Vertex & a,const Vertex & b,const Vertex & c)
+{
+  register  Icoor2 bax = b.i.x - a.i.x ,bay = b.i.y - a.i.y; 
+  register  Icoor2 cax = c.i.x - a.i.x ,cay = c.i.y - a.i.y; 
+  return  bax*cay - bay*cax;}
+
+
+void  swap(Triangle *t1,Int1 a1,
+	   Triangle *t2,Int1 a2,
+	   Vertex *s1,Vertex *s2,Icoor2 det1,Icoor2 det2);
+
+
+
+int inline TriangleAdjacent::swap()
+{ return  t->swap(a);}
+
+
+
+int SwapForForcingEdge(Vertex   *  & pva ,Vertex  * &   pvb ,
+		       TriangleAdjacent & tt1,Icoor2 & dets1,
+		       Icoor2 & detsa,Icoor2 & detsb, int & nbswap);
+
+int ForceEdge(Vertex &a, Vertex & b,TriangleAdjacent & taret) ;
+
+// inline bofbof   FH 
+inline  TriangleAdjacent FindTriangleAdjacent(Edge &E)
+  {
+    Vertex * a = E.v[0];
+    Vertex * b = E.v[1];
+    
+    Triangle * t = a->t;
+    int i = a->vint;
+    TriangleAdjacent ta(t,EdgesVertexTriangle[i][0]); // Previous edge
+    assert(t && i>=0 && i < 3);
+    assert( a == (*t)(i));
+    int k=0;
+    do { // turn around vertex in direct sens (trigo)
+      k++;assert(k< 20000);
+      //  in no crack => ta.EdgeVertex(1) == a otherwise ??? 
+      if (ta.EdgeVertex(1) ==  a && ta.EdgeVertex(0) ==  b) return ta; // find 
+      ta = ta.Adj();
+      if (ta.EdgeVertex(0) ==  a && ta.EdgeVertex(1) ==  b) return ta; // find 
+      --ta;
+      } while (t != (Triangle *)ta);
+    assert(0);
+    return TriangleAdjacent(0,0);// error 
+  }
+  
+inline Vertex * TheVertex(Vertex * a) // give a unique vertex with smallest number
+{ // in case on crack in mesh 
+    Vertex * r(a), *rr;
+    Triangle * t = a->t;
+    int i = a->vint;
+    TriangleAdjacent ta(t,EdgesVertexTriangle[i][0]); // Previous edge
+    assert(t && i>=0 && i < 3);
+    assert( a == (*t)(i));
+    int k=0;
+    do { // turn around vertex in direct sens (trigo)
+      k++;assert(k< 20000);
+      //  in no crack => ta.EdgeVertex(1) == a
+      if ((rr=ta.EdgeVertex(0)) < r) r = rr;
+      ta = ta.Adj();
+      if ((rr=ta.EdgeVertex(1)) < r) r =rr;
+      --ta;
+     } while (t != (Triangle*) ta);  
+    return r;
+}
+
+inline double CPUtime(){
+#ifdef SYSTIMES
+  struct tms buf;
+  if (times(&buf)!=-1)
+    return ((double)buf.tms_utime+(double)buf.tms_stime)/(long) sysconf(_SC_CLK_TCK);
+  else
+#endif
+    return ((double) clock())/CLOCKS_PER_SEC;
+}
+
+#ifdef DEBUG
+void inline Triangle::checka(Int1 a) {
+  // verif de la coherence des adjacences de l arete a
+  a = a%4;
+  assert(a < 3 && a >= 0 );
+  Triangle *t1=this,*t2=at[a];
+  Int2 a1=a,a2=aa[a]%4;
+  
+  assert(a2 < 3 && a2 >= 0 );
+  if (t2 && ( ((*t1).ns[VerticesOfTriangularEdge[a1][0]] != (*t2).ns[VerticesOfTriangularEdge[a2][1]])
+	      || ((*t1).ns[VerticesOfTriangularEdge[a1][1]] != (*t2).ns[VerticesOfTriangularEdge[a2][0]])))
+    {
+      if (CurrentTh) cerr << " In Triangles beetween Triangle " << CurrentTh->Number(t1) << " and " 
+		     <<  CurrentTh->Number(t2) <<  endl;
+      cerr << "---- t1="<< t1 << " " << a1 <<",  t2="<< t2 << " " << a2 << endl;
+      cerr <<"t1="<< t1 << " " << a1 << " " << t1->ns[VerticesOfTriangularEdge[a1][0]] 
+	   << " " << t1->ns[VerticesOfTriangularEdge[a1][1]] <<endl;
+      if (CurrentTh)
+	cerr <<"t1="<< t1 << " " << a1 << " " << CurrentTh->Number(t1->ns[VerticesOfTriangularEdge[a1][0]])
+	   << " " << CurrentTh->Number(t1->ns[VerticesOfTriangularEdge[a1][1]]) <<endl;
+      if (t2) cerr <<"t2="<< t2 << " " << a2 << " " 
+		   <<  t2->ns[VerticesOfTriangularEdge[a2][0]] 
+		   << " " << t2->ns[VerticesOfTriangularEdge[a2][1]] <<endl;
+      if (t2 &&CurrentTh)
+	cerr <<"t2="<< t2 << " " << a2 << " " 
+	     <<  CurrentTh->Number(t2->ns[VerticesOfTriangularEdge[a2][0]])
+	     << " " << CurrentTh->Number(t2->ns[VerticesOfTriangularEdge[a2][1]]) <<endl;
+      assert(0); 
+    } 
+  if (t2)   assert(t1->aa[a1]/4 == t2->aa[a2]/4); // lock compatibite
+}
+
+
+void inline  Triangle::check() {
+  Icoor2 det2=0;
+  //  cout << " check " << this << endl;
+  int  infv=ns[0] ?  ((  ns[1] ? ( ns[2] ? -1 : 2) : 1  )) : 0;
+  if (det<0) {
+      if (infv<0 )
+	{  if (CurrentTh) cerr << " In Triangles " << CurrentTh->Number(this) << endl;
+	cerr << " det = " <<  det << " and " << infv << endl;
+	MeshError(5);
+	}}
+  else  if (infv>=0 )
+ 	{  if (CurrentTh) cerr << " In Triangles " << CurrentTh->Number(this) << endl;
+	cerr << " det = " << det << " and " << infv << endl;
+	MeshError(5);
+	}  
+  
+  if (det >=0) 
+    if( det != (det2=bamg::det(*ns[0],*ns[1],*ns[2])))
+	{ // penthickness(4);Draw();
+	  if (CurrentTh) cerr << " In Triangles" << CurrentTh->Number(this) 
+			 << endl;
+      cerr << *ns[0] << *ns[1] << " " << *ns[2]  << " " << endl;
+	   cerr << " Bug in triangle " << this 
+		<< ":" << det << " !=  " << det2 << endl;
+	   MeshError(5);
+	}
+  checka(0);
+  checka(1);
+  checka(2);
+//  if (ns[0]) assert( ns[0] - Meshbegin  >= 0 );
+//  if (ns[0]) assert( Meshend  - ns[0] >= 0 );
+//  if (ns[1]) assert( ns[1] - Meshbegin  >= 0 );
+//  if (ns[1]) assert( Meshend  - ns[1] >= 0 );
+//  if (ns[2]) assert( ns[2] - Meshbegin  >= 0 );
+//  if (ns[2]) assert( Meshend  - ns[2] >= 0 );
+  assert(ns[0] != ns[2]);
+  assert(ns[1] != ns[2]);
+  assert(ns[0] != ns[1]);
+}
+
+
+#endif
+
+
+
+
+#ifdef DRAWING 
+extern Real4 xGrafCoef,yGrafCoef,xGrafOffSet,yGrafOffSet; // R2 -> I2 transform
+extern R2 Gpmin,Gpmax;
+//extern Real8 Gh;
+// cf routine ILineTo IMoveto
+
+extern void  IMoveTo(long i,long j);
+extern void  ILineTo(long i,long j);
+extern char Getxyc(long &i,long &j);
+extern void Draw(float ,float );
+extern void Draw(long ,long );
+extern void DrawMark(R2 r);
+//inline void DrawMark(D2 r) {DrawMark(R2(r.x,r.y));}
+inline void Move(I2 x) {IMoveTo(x.x,x.y);}
+inline void Move(R2 x) {rmoveto(x.x,x.y);}
+//inline void Move(D2 x) {rmoveto(x.x,x.y);}
+inline void Line(I2 x){ILineTo(x.x,x.y);}
+inline void Line(R2 x) {rlineto(x.x,x.y);}
+//inline void Line(D2 x) {rlineto(x.x,x.y);}
+#endif
+
+}
+
+
+
+
+
+
diff --git a/contrib/bamg/bamglib/MeshDraw.cpp b/contrib/bamg/bamglib/MeshDraw.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..58168072d393efa2d3530ae0b5f1be3acb9a736c
--- /dev/null
+++ b/contrib/bamg/bamglib/MeshDraw.cpp
@@ -0,0 +1,808 @@
+// -*- Mode : c++ -*-
+//
+// SUMMARY  :      
+// USAGE    :        
+// ORG      : 
+// AUTHOR   : Frederic Hecht
+// E-MAIL   : hecht@ann.jussieu.fr
+//
+
+/*
+ 
+ This file is part of Freefem++
+ 
+ Freefem++ is free software; you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+ 
+ Freefem++  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 Lesser General Public License for more details.
+ 
+ You should have received a copy of the GNU Lesser General Public License
+ along with Freefem++; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+#ifdef DRAWING
+
+#include <stdio.h>
+#include <string.h>
+#include <math.h>
+#include <time.h>
+#include <iostream>
+using namespace std;
+
+#include "Mesh2.h"
+#include "QuadTree.h"
+#include "SetOfE4.h"
+extern bool withrgraphique;
+
+
+
+namespace bamg {
+Real4  xGrafCoef,yGrafCoef,xGrafOffSet,yGrafOffSet;
+R2 GrafPMin,GrafPMax;
+Real8 Grafh=0;
+
+
+
+void  IMoveTo(long i,long j)
+{  if (!withrgraphique) return;
+   rmoveto(float(i)/xGrafCoef+xGrafOffSet ,float(j)/yGrafCoef+yGrafOffSet );}
+
+void  ILineTo(long i,long j)
+{      if (!withrgraphique) return;
+  rlineto(float(i)/xGrafCoef+xGrafOffSet ,float(j)/yGrafCoef+yGrafOffSet );}
+
+
+void   Triangles::Draw(   ) const {
+    if (!withrgraphique) return;
+  showgraphic();
+//  if (!init) InitDraw();
+  Int4 i;
+//  for (i=0;i<nbv;i++)
+//    vertices[i].Draw(i);    
+  for (i=0;i<nbe;i++)
+    edges[i].Draw();
+  for (i=0;i<nbt;i++) 
+      if (triangles[i].link) 
+	triangles[i].Draw(-2);
+//  for (i=0;i<nbv;i++)
+//   ((Metric) vertices[i]).Draw(vertices[i]);    
+   
+  //  rattente(1);
+  
+}
+
+
+void    Edge::Draw(Int4  i) const 
+{
+      if (!withrgraphique) return;
+  if (InRecScreen(Min(v[0]->r.x,v[1]->r.x),
+		  Max(v[0]->r.y,v[1]->r.y),
+		  Min(v[0]->r.x,v[1]->r.x),
+		  Max(v[0]->r.y,v[1]->r.y))) {
+    v[0]->MoveTo();
+    v[1]->LineTo();
+    R2 M= ((R2) *v[0] + (R2) * v[1])*0.5;
+    Move(M);
+    char VertexDraw_i10[20];
+    if (i<0)
+      sprintf(VertexDraw_i10,"%p",this);
+    else 
+      sprintf(VertexDraw_i10,"%ld",i);
+    if (i>=0)
+      plotstring(&VertexDraw_i10[0]); 
+    
+  }
+}
+void    Vertex::Draw(Int4 i) const 
+{
+      if (!withrgraphique) return;
+  if (CurrentTh && i<0&& i != -2 )
+    {
+      if (CurrentTh->vertices <= this && this < CurrentTh->vertices + CurrentTh->nbv)
+	i = CurrentTh->Number(this);
+    }
+  if (InPtScreen(r.x,r.y)) {
+   char VertexDraw_i10[20];
+   if (i<0)
+     sprintf(VertexDraw_i10,"%p",this);
+   else 
+     sprintf(VertexDraw_i10,"%ld",i);
+  
+  showgraphic();
+  //  float eps = (MaxICoor/yGrafCoef)/100;
+  DrawMark(r);
+  
+  if (i>=0)
+    plotstring(&VertexDraw_i10[0]); }
+}
+
+void  DrawMark(R2 r) 
+{
+      if (!withrgraphique) return;
+  if (InPtScreen(r.x,r.y)) {
+  float eps = Grafh/100;
+  rmoveto(r.x+eps,r.y);
+  rlineto(r.x,r.y+eps);
+  rlineto(r.x-eps,r.y);
+  rlineto(r.x,r.y-eps);
+  rlineto(r.x+eps,r.y);}
+ 
+}
+void  Triangle::Draw(Int4 i ) const
+{
+      if (!withrgraphique) return;
+  //  int cc=LaCouleur();
+  if (CurrentTh && i<0 && i != -2)
+    {
+      if (CurrentTh->triangles <= this && this < CurrentTh->triangles + CurrentTh->nbt)
+	i = CurrentTh->Number(this);
+    }	
+  char i10[20];
+  if (i<0)   sprintf(i10,"%p",this);
+  else  sprintf(i10,"%ld",i);
+  showgraphic();
+
+  if (ns[0] == 0) {
+  if (InRecScreen(Min(ns[1]->r.x,ns[2]->r.x),
+		  Min(ns[1]->r.y,ns[2]->r.y),
+		  Max(ns[1]->r.x,ns[2]->r.x),
+		  Max(ns[1]->r.y,ns[2]->r.y)))
+    { rmoveto(ns[1]->r.x,ns[1]->r.y);
+      rlineto(ns[2]->r.x,ns[2]->r.y);
+      rmoveto( (ns[1]->r.x + ns[2]->r.x)/2.0 + (ns[1]->r.y - ns[2]->r.y)*0.1,
+              (ns[1]->r.y + ns[2]->r.y)/2.0 - (ns[1]->r.x - ns[2]->r.x)*0.1 );
+      if(i>=0)  plotstring(&i10[0]);    
+    }}
+  else
+  if (InRecScreen(Min3(ns[0]->r.x,ns[1]->r.x,ns[2]->r.x),
+		  Min3(ns[0]->r.y,ns[1]->r.y,ns[2]->r.y),
+		  Max3(ns[0]->r.x,ns[1]->r.x,ns[2]->r.x),
+		  Max3(ns[0]->r.y,ns[1]->r.y,ns[2]->r.y))) {
+    { 
+      const int i0=0                               , j01=EdgesVertexTriangle[i0][1];//     j01==2
+      const int i1=VerticesOfTriangularEdge[j01][1], j12=EdgesVertexTriangle[i1][1];//i1=1,j12=0
+      const int i2=VerticesOfTriangularEdge[j12][1], j20=EdgesVertexTriangle[i2][1];//i1=2,j20=1
+
+      rmoveto(ns[i0]->r.x,ns[i0]->r.y);
+      if(Hidden(j01)) rmoveto(ns[i1]->r.x,ns[i1]->r.y); else  rlineto(ns[i1]->r.x,ns[i1]->r.y);
+      if(Hidden(j12)) rmoveto(ns[i2]->r.x,ns[i2]->r.y); else  rlineto(ns[i2]->r.x,ns[i2]->r.y);
+      if(Hidden(j20)) rmoveto(ns[i0]->r.x,ns[i0]->r.y); else  rlineto(ns[i0]->r.x,ns[i0]->r.y);
+      
+    rmoveto( (ns[0]->r.x + ns[1]->r.x + ns[2]->r.x)/3.0 ,
+             (ns[0]->r.y + ns[1]->r.y + ns[2]->r.y)/3.0);
+    
+    }
+  
+  if(i>=0)  plotstring(&i10[0]);    
+  }
+  //  LaCouleur(cc);
+}
+
+void  Triangles::InitDraw() const
+{ 
+   if (!withrgraphique) return; 
+   couleur(1);
+   GrafPMin =  vertices[0].r;
+   GrafPMax =  vertices[0].r;
+  // recherche des extrema des vertices GrafPMin,GrafPMax
+  Int4 i;
+  for (i=0;i<nbv;i++) {
+    //    GrafPMax = Max2(GrafPMax,vertices[i].r);
+    //    GrafPMin = Min2(GrafPMin,vertices[i].r);
+    GrafPMin.x = Min(GrafPMin.x,vertices[i].r.x);
+    GrafPMin.y = Min(GrafPMin.y,vertices[i].r.y);
+    GrafPMax.x = Max(GrafPMax.x,vertices[i].r.x);
+    GrafPMax.y = Max(GrafPMax.y,vertices[i].r.y);
+  }
+  float hx = (GrafPMax.x-GrafPMin.x);
+  float hy = (GrafPMax.y-GrafPMin.y);
+  Grafh = Max(hx,hy)*0.55;
+  cadreortho((GrafPMin.x+GrafPMax.x)*0.5,(GrafPMin.y+GrafPMax.y)*0.5,Grafh);
+  
+}
+void Show(const char * s,int k=1)
+{
+  if (!withrgraphique) return;
+  if(k) {
+  couleur(1);
+  float xmin,xmax,ymin,ymax;
+       getcadre(xmin,xmax,ymin,ymax);
+       rmoveto(xmin+(xmax-xmin)/100,ymax-(k)*(ymax-ymin)/30);
+       plotstring(s);
+       //  couleur(1);	
+  }
+}
+void Triangles::inquire() 
+{    
+  if (! withrgraphique) return;
+  int PS=0;
+  cout << flush;
+   Triangles *OldCurrentTh=CurrentTh;
+  CurrentTh = this;
+  if (! Grafh ) InitDraw();
+  unsigned  char c;
+  int rd;
+  float x,y;
+  int setv =0;
+  Int4 nbtrel=0;
+  Int4 * reft = new Int4 [Max(nbt,1L)];
+  if (NbSubDomains && subdomains[0].head)
+    nbtrel = ConsRefTriangle(reft);
+  else
+    for (Int4 kkk=0;kkk<nbt;kkk++) reft[kkk]=0;
+  // cout << "inquire **********************************************************************"<<endl ;
+      if (verbosity>2)
+	cout << "inquire: Nb de Triangle reel = " <<ConsRefTriangle(reft)<<endl;
+
+  while (Show("Enter ? for help",PS==0), c=::Getxyc(x,y), ( c && c != 'F'  && c != 'f')  && c < 250 )
+    { rd = 0;
+      couleur(1);
+    //  cout << " #"<< c << "# " << (int) c << " xy=" << x << " "<< y  <<endl ;
+      //     penthickness(2);
+      if (c=='?') { int i=3;
+        reffecran();
+	Show("enter a keyboard character in graphic window to do",i++);
+	i++;
+	Show("f or mouse click: to continue the process",i++);
+	Show("p: openPS file to save plot, P: close PS file ",i++);
+        Show("B: set backgound mesh has drawing mesh",i++);
+	Show("H: show histogramme",i++);
+	Show("i: initDraw",i++);
+	Show("+ or - : zoom + or -",i++);
+	Show("r: redraw  , =: reinit the viewport ",i++);
+	Show("q: quit / abort / stop ",i++);
+	Show("Q: show quadtree",i++);
+	Show("g: show geometry",i++);
+	Show("d: show triangle with det = 0",i++);
+	Show("m: show all the metric",i++);
+	Show("V: show all the vertices",i++);
+	Show("T: show all the sub domain ref number",i++);
+	Show("V: show all the vertices",i++);
+	Show("D: Inforce the mesh to be Delaunay",i++);
+	Show("b: show all the boundary edges ref number",i++);
+	Show("k: find the triangle contening the point",i++);
+	Show("v,o,s : print the nearest vertex  s=> draw metric o=> optim around (debug)",i++);
+	Show("t: find triangle contening the point  with brute force",i++);	
+	Show("e: find the nearest edge of triangle contening the point",i++);
+	Show("C: construct the in-circle in anistrope way",i++);
+	Show("n: show normal for find ",i++);
+      }
+      if (c=='p') openPS(0),PS=1;
+      if (c=='P') closePS(),PS=0;
+      if (c=='B') BTh.inquire();
+      if ( c=='D') {
+	for(int iter=0;iter < 50;iter++)
+	  { int k = 0;
+	  for (Int4 icount=0; icount<nbv; icount++) {
+	    k += vertices[icount].Optim(1,0);
+	  }
+	  if (k !=0) cout << " Bizarre le maillage n'est  pas delaunay  nbswap = " << k << endl;
+	  else break;
+	  }
+	rd =1;
+      }
+      
+      if (c=='H') ShowHistogram();
+      if (c=='i') {InitDraw();
+      }
+      if (c=='+') Grafh /= 2.,rd=1,cadreortho(x,y,Grafh);
+      if (c=='-') Grafh *= 2.,rd=1,cadreortho(x,y,Grafh);
+      if (c=='r') rd =1;
+      if (c=='Q') CurrentTh=0,MeshError(1);
+      if (c=='q' && quadtree) penthickness(2),
+				couleur(6), 
+				quadtree->Draw(),
+				couleur(1),
+				penthickness(1);
+      if (c=='g') couleur(6),Gh.Draw();
+      if (c=='n') {
+        for (int i=0;i<nbv;i++)
+         {
+           vertices[i].MoveTo();
+           vertices[1].DirOfSearch.Draw();;
+         }
+      }
+      if (c=='d')
+	{      
+          couleur(4);
+	  for(int i=0;i<nbt;i++)
+	    if(triangles[i].det == 0) {
+	      triangles[i].Draw();
+	      cout << " Bizzare " << i << endl;
+	    }
+          couleur(1);
+       
+	}
+      if (c=='m')  {Int4 i;
+        couleur(2);
+        for (i=0;i<nbv;i++)
+	((Metric) vertices[i]).Draw(vertices[i]); 
+        couleur(1);}
+      if (c=='V')  {Int4 i;
+        for (i=0;i<nbv;i++)
+	 vertices[i].Draw(); }
+      if (c=='T') {
+	Int4 i;
+	for( i=0;i<nbt;i++)
+	  if(reft[i]>=0)
+	    { couleur(2+(reft[i])%6);
+	      triangles[i].Draw(reft[i]);
+              couleur(1); 
+	    }
+      }
+	
+      if (c=='b') {
+	Int4 i;
+	reffecran();
+	for (i=0;i<nbe;i++)
+	  edges[i].Draw(edges[i].ref);
+	
+      }
+      if (c=='k') 
+	{ 
+	  if(!setv) ReMakeTriangleContainingTheVertex();
+	  R2 P(x,y);
+	  I2 I = toI2(P);
+	  Icoor2 dete[3];
+	  Triangle * tb = FindTriangleContening(I,dete);
+	  penthickness(1);
+	  tb->Draw(Number(tb));
+	  penthickness(1);
+	  if(tb->link==0) {
+	    double a,b;
+	    TriangleAdjacent ta=CloseBoundaryEdgeV2(I,tb,a,b);
+	    R2 A = *ta.EdgeVertex(0);
+	    R2 B = *ta.EdgeVertex(1);
+	    //Triangle * tt  = ta;
+	    //    tt->Draw(Number(tt));
+	    penthickness(5);
+	    //   ta.EdgeVertex(0)->MoveTo();
+	    //  ta.EdgeVertex(1)->LineTo();
+	    DrawMark(A*a+B*b);
+	    penthickness(1);
+	      }
+	}
+      if (c=='v' || c=='o' || c=='s' )
+	{ 
+	  couleur(3);
+	  if(!setv) ReMakeTriangleContainingTheVertex();
+	  setv=1;
+	  
+	  R2 XY(x,y),P;
+	  Real8 d;
+	  Int4 i,j=0;
+	  P  = XY - vertices[0].r;
+	  d = (P,P);
+	  for (i=0;i<nbv;i++) {
+	    P  = XY - vertices[i].r;
+	  Real8 dd = (P,P);
+	  if(dd < d) {
+	    j=i;
+	    d=dd;}}
+	  cout << " sommet " << j << "= " <<	vertices[j]  << ", d = " << d << " " << vertices[j].m << endl;
+	  vertices[j].Draw(j);
+	  DrawMark(vertices[j].r);
+	  if( c=='s')  vertices[j].m.Draw(vertices[j]);
+	  if (c=='o')   cout << " Nb Swap = " << vertices[j].Optim(1) << endl;
+	  couleur(1);
+      }
+      if (c=='t' || c=='c'||c=='e') {
+	    couleur(4);
+            R2 XY(x,y);
+	    Real8 a12,a02,a01;
+	    for (Int4 i=0;i<nbt;i++) {
+	      if(triangles[i].det<=0)  continue;
+	      //	      cout << " T = " << i << " " << triangles[i].det << " ";
+	      //	      cout << Number(triangles[i][0]) << " "
+	      //		   << Number(triangles[i][1]) << " "
+	      //		   << Number(triangles[i][2]) << " ";
+	      //    cout << area2(triangles[i][0].r,triangles[i][1].r,triangles[i][2].r) << " " ;
+	      //	      cout << area2(XY,triangles[i][1].r,triangles[i][2].r) << " " ;
+	      //      cout << area2(triangles[i][0].r,XY,triangles[i][2].r) << " " ;
+	      //     cout << area2(triangles[i][0].r,triangles[i][1].r,XY) << endl;
+			   
+	      if( (a12=Area2(XY,triangles[i][1].r,triangles[i][2].r)) < 0) continue;
+	      if( (a02=Area2(triangles[i][0].r,XY,triangles[i][2].r)) < 0) continue;
+	      if( (a01=Area2(triangles[i][0].r,triangles[i][1].r,XY)) < 0) continue;
+	      if(c=='e'|| c=='E') {
+		int ie =0;
+		Real8 am = a12;
+		if(a02 < am) am=a02,ie=1;
+		if(a01 < am) am=a01,ie=2;
+		TriangleAdjacent tta(triangles+i,ie);
+		Vertex *v0 =tta.EdgeVertex(0);
+		Vertex *v1 =tta.EdgeVertex(1);
+		tta.EdgeVertex(0)->MoveTo();
+		tta.EdgeVertex(1)->LineTo();
+		cout << " Edge " << Number(tta.EdgeVertex(0)) << " " <<  Number(tta.EdgeVertex(1)) << endl;
+		for (Int4 k=0;k<nbe;k++)
+		  if ( ( edges[k](0) == v0 &&  edges[k](1) == v1) ||
+		       ( edges[k](0) == v1 &&  edges[k](1) == v0)	)			
+		    cout << " Edge " << k << "  on Geo = " << Gh.Number(edges[k].on)<< endl;
+		
+		  
+		if(c=='e') {
+		  triangles[i].SetUnMarkUnSwap(ie);
+		  triangles[i].swapDRAW(ie);}
+		else if(c=='E')
+		  {
+		    ;
+		  }
+
+		break;
+	      }
+	      cout << " In triangle " << i << triangles[i];
+	      triangles[i].Draw(i);
+	      if(c=='c') {
+		Vertex *s1=&triangles[i][0];
+		Vertex *sa=&triangles[i][1];
+		Vertex *sb=&triangles[i][2];
+		D2 S1(s1->r.x,s1->r.y);
+		D2 SA(sa->r.x,sa->r.y);
+		D2 SB(sb->r.x,sb->r.y);
+		D2 AB= SB-SA;
+		D2 MAB2=SB + SA;
+		D2 M1A=(S1 + SA)*0.5;
+		D2 MAB(MAB2.x*0.5,MAB2.y*0.5);
+		D2 A1=S1-SA;
+		D2 D = S1 - SB ;
+		{
+		  Metric M=s1->m;
+		  D2 ABo = M.Orthogonal(AB);
+		  D2 A1o = M.Orthogonal(A1);
+		  penthickness(1);
+		  Move(MAB);
+		  Line(MAB+ABo);
+		  Line(MAB-ABo);
+		  Move(M1A);
+		  Line(M1A+A1o);
+		  Line(M1A-A1o);
+		  penthickness(3);
+		  
+		  // (A+B)+ x ABo = (S1+B)/2+ y A1 
+		  // ABo x - A1o y =  (S1+B)/2-(A+B)/2 = (S1-B)/2 = D/2
+		  double dd = Abs(ABo.x*A1o.y)+Abs(ABo.y*A1o.x);
+		  double d = (ABo.x*A1o.y - ABo.y*A1o.x)*2; // because D/2
+		  cout << " d = " << d << " dd= " << dd << endl;
+		  if (Abs(d) > dd*1.e-10) {
+		    D2 C(MAB+ABo*((D.x*A1o.y - D.y*A1o.x)/d));
+		    cout << C << s1->r <<sa->r  <<sb->r << endl;
+		    DrawMark(C);
+		    cout << M << " l = "<<  M(C-S1) << " lnew = 1 == " ;
+		    //M.Draw(R2(C.x,C.y));
+		    M=M/M(C-S1);	
+		    cout << M(C-S1) << M << endl;	 
+		    M.Draw(R2(C.x,C.y));
+		  }
+		  
+		}
+	      }
+	      break;
+	    }
+	    cout << " fin recherche triangle " << endl;
+	   couleur(1); 
+      }            
+      if (c=='='||c==249) {
+	rd=1;
+	float hx = (GrafPMax.x-GrafPMin.x);
+	float hy = (GrafPMax.y-GrafPMin.y);
+	Grafh = Max(hx,hy)*0.55;
+	cadreortho((GrafPMin.x+GrafPMax.x)*0.5,(GrafPMin.y+GrafPMax.y)*0.55,Grafh);
+      }
+       penthickness(1);
+      if (rd) 
+        reffecran(),Draw();
+
+    }
+  // cout << endl;
+  delete [] reft;
+  CurrentTh = OldCurrentTh;
+ }
+void Draw(float x,float y)
+{
+ if (!withrgraphique) return;
+
+  if (InPtScreen(x,y)) {
+  float eps = Max(GrafPMax.x-GrafPMin.x,GrafPMax.y-GrafPMin.y)/100;
+  rmoveto(x+eps,y);
+  rlineto(x,y+eps);
+  rlineto(x-eps,y);
+  rlineto(x,y-eps);
+  rlineto(x+eps,y);}
+}
+char Getxyc(long &i,long &j)
+{ 
+   if (!withrgraphique) return 0;
+ 
+   float x,y;
+   char c=::Getxyc(x,y);
+   i = (long)( (x - xGrafOffSet)*xGrafCoef);
+   j = (long)((y - yGrafOffSet)*yGrafCoef);
+   return c;
+}
+
+
+void Draw(long i,long j)
+{
+  if (!withrgraphique) return;
+  Draw(((float) i)/xGrafCoef+xGrafOffSet ,((float) j)/yGrafCoef+yGrafOffSet );
+}
+
+int Triangle::swapDRAW(Int2 a){
+  int NbUnSwap=0;
+  if(a/4 !=0)  {cout << a << "arete lock"<< a <<endl;return 0;}// arete lock or MarkUnSwap
+
+  register Triangle *t1=this,*t2=at[a];// les 2 triangles adjacent
+  register Int1 a1=a,a2=aa[a];// les 2 numero de l arete dans les 2 triangles
+  
+  if(a2/4 !=0) {cout << a2 << "arete lock adj"<< a2 << endl; return 0;} // arete lock
+  
+  register Vertex  *sa=t1->ns[VerticesOfTriangularEdge[a1][0]];
+  register Vertex  *sb=t1->ns[VerticesOfTriangularEdge[a1][1]];
+  register Vertex  *s1=t1->ns[OppositeVertex[a1]];
+  register Vertex  *s2=t2->ns[OppositeVertex[a2]];
+
+#ifdef DEBUG
+  assert ( a >= 0 && a < 3 );  
+#endif
+  
+   Icoor2 det1=t1->det , det2=t2->det ;
+   Icoor2 detT = det1+det2;
+   Icoor2 detA = Abs(det1) + Abs(det2);
+   Icoor2 detMin = Min(det1,det2);
+
+   int OnSwap = 0;       
+   // si 2 triangle infini (bord) => detT = -2;
+   if (sa == 0) {// les deux triangles sont frontieres
+     det2=bamg::det(s2->i,sb->i,s1->i);
+     OnSwap = det2 >0;}
+   else if (sb == 0) { // les deux triangles sont frontieres
+     det1=bamg::det(s1->i,sa->i,s2->i);
+     OnSwap = det1 >0;}
+   else if(( s1 != 0) && (s2 != 0) ) {
+     det1 = bamg::det(s1->i,sa->i,s2->i);
+     det2 = detT - det1;
+     OnSwap = (Abs(det1) + Abs(det2)) < detA;
+     Icoor2 detMinNew=Min(det1,det2);
+     cout << " detMin = " << detMin << "  detMinNew " <<  detMinNew << endl;
+     if (! OnSwap &&(detMinNew>0)) {
+       OnSwap = detMin ==0;
+       if (! OnSwap) {
+	 int  kopt = 1;
+        while (1)
+	 if(kopt) {
+	 // critere de Delaunay pure 
+	 register Real8 xb1 = sb->i.x - s1->i.x,
+	   x21 = s2->i.x - s1->i.x,
+	   yb1 = sb->i.y - s1->i.y,
+	   y21 = s2->i.y - s1->i.y,
+	   xba = sb->i.x - sa->i.x, 
+	   x2a = s2->i.x - sa->i.x,
+	   yba = sb->i.y - sa->i.y,
+	   y2a = s2->i.y - sa->i.y,
+	   cosb12 =  xb1*x21 + yb1*y21 ,
+	   cosba2 =  xba*x2a + yba*y2a ,
+	   sinb12 = det2,
+	   sinba2 = t2->det,
+	   //zsinba2 = t2->det;
+	 
+	 // angle b12 > angle ba2 => cotg(angle b12) < cotg(angle ba2)
+	 OnSwap =  (cosb12 *  sinba2) <  (cosba2 *  sinb12);
+	 if(CurrentTh) 
+	   cout << "swap s1=" << CurrentTh->Number(sa) << " s2=" << CurrentTh->Number(sb) 
+		<< " t1= " <<  CurrentTh->Number(t1) << " t2=" <<  CurrentTh->Number(t2) << " " ;
+
+
+	 cout <<  cosb12 << " " <<  sinba2 << " "  <<  cosba2 << " " << sinb12 
+	      << " Onswap = " <<  OnSwap << endl;
+
+	  break;
+	 }
+	 else 
+	   {	
+	     // critere de Delaunay pure 
+	     Real8 som;
+	     I2 AB=(I2) *sb - (I2) *sa;
+	     I2 MAB2=((I2) *sb + (I2) *sa);
+	     D2 MAB(MAB2.x*0.5,MAB2.y*0.5);
+	     I2 A1=(I2) *s1 - (I2) *sa;
+	     I2 D = (I2) * s1 - (I2) * sb ;
+	     D2 S2(s2->i.x,s2->i.y);
+	     D2 S1(s1->i.x,s1->i.y);
+	     D2 SA(sa->i.x,sa->i.y);
+	     D2 SB(sb->i.x,sb->i.y);
+	     DrawMark(s2->r);
+	     DrawMark(s1->r);
+	     DrawMark(sa->r);
+	     DrawMark(sb->r);
+	     {
+	       Metric M=s1->m;
+	       D2 ABo = M.Orthogonal(SB-SA);
+	       D2 A1o = M.Orthogonal(S1-SA);
+	       // (A+B)+ x ABo = (S1+B)/2+ y A1 
+	       // ABo x - A1o y =  (S1+B)/2-(A+B)/2 = (S1-B)/2 = D/2
+	       double dd = Abs(ABo.x*A1o.y)+Abs(ABo.y*A1o.x);
+	       double d = (ABo.x*A1o.y - ABo.y*A1o.x)*2; // because D/2
+	       if (Abs(d) > dd*1.e-3) {
+		 D2 C(MAB+ABo*((D.x*A1o.y - D.y*A1o.x)/d));
+		 cout << "M1 r2 =" <<  M(C - S2) << " r1 = " << M(C - S1) 
+		      << "ra = " << M(C - SA) << " rb = " << M(C-SB) ;
+		 som  = M(C - S2)/M(C - S1);
+		 cout << " r1/r2 = " << som << endl;
+	       } else 
+		{kopt=1;continue;}
+		
+	     }
+	     {
+	       Metric M=s2->m;
+	       D2 ABo = M.Orthogonal(SB-SA);
+	       D2 A1o = M.Orthogonal(S1-SA);
+	       // (A+B)+ x ABo = (S1+B)/2+ y A1 
+	       // ABo x - A1o y =  (S1+B)/2-(A+B)/2 = (S1-B)/2 = D/2 
+	       double dd = Abs(ABo.x*A1o.y)+Abs(ABo.y*A1o.x);
+	       double d = (ABo.x*A1o.y - ABo.y*A1o.x)*2; // because D/2
+	       cout << " d = " << Abs(d) << " dd " << dd << endl;
+	       if(Abs(d) > dd*1.e-3) {
+		 D2 C(MAB+ABo*((D.x*A1o.y - D.y*A1o.x)/d));
+		 cout << "M2 r1 =" <<  M(C - S2) << " r2 = " << M(C - S1) 
+		      << "ra = " << M(C - SA) << " rb = " << M(C-SB) 
+		      << " r1/r2 =  " << M(C - S2)/M(C -  S1)  << endl;
+		 som  += M(C - S2)/M(C -  S1);
+	       } else 
+		{kopt=1;continue;}
+	     }
+	     {
+	       Metric M=sa->m;
+	       D2 ABo = M.Orthogonal(SB-SA);
+	       D2 A1o = M.Orthogonal(S1-SA);
+	       // (A+B)+ x ABo = (S1+B)/2+ y A1 
+	       // ABo x - A1o y =  (S1+B)/2-(A+B)/2 = (S1-B)/2 = D/2 
+	       double dd = Abs(ABo.x*A1o.y)+Abs(ABo.y*A1o.x);
+	       double d = (ABo.x*A1o.y - ABo.y*A1o.x)*2; // because D/2
+	       cout << " d = " << Abs(d) << " dd " << dd << endl;
+	       if(Abs(d) > dd*1.e-3) {
+		 D2 C(MAB+ABo*((D.x*A1o.y - D.y*A1o.x)/d));
+		 cout << "M2 r1 =" <<  M(C - S2) << " r2 = " << M(C - S1) 
+		      << "ra = " << M(C - SA) << " rb = " << M(C-SB) 
+		      << " r1/r2 =  " << M(C - S2)/M(C -  S1)  << endl;
+		 som  += M(C - S2)/M(C -  S1);
+	       } else 
+		{kopt=1;continue;}
+	     }
+  	     {
+	       Metric M=sb->m;
+	       D2 ABo = M.Orthogonal(SB-SA);
+	       D2 A1o = M.Orthogonal(S1-SA);
+	       // (A+B)+ x ABo = (S1+B)/2+ y A1 
+	       // ABo x - A1o y =  (S1+B)/2-(A+B)/2 = (S1-B)/2 = D/2 
+	       double dd = Abs(ABo.x*A1o.y)+Abs(ABo.y*A1o.x);
+	       double d = (ABo.x*A1o.y - ABo.y*A1o.x)*2; // because D/2
+	       cout << " d = " << Abs(d) << " dd " << dd << endl;
+	       if(Abs(d) > dd*1.e-3) {
+		 D2 C(MAB+ABo*((D.x*A1o.y - D.y*A1o.x)/d));
+		 cout << "M2 r1 =" <<  M(C - S2) << " r2 = " << M(C - S1) 
+		      << "ra = " << M(C - SA) << " rb = " << M(C-SB) 
+		      << " r1/r2 =  " << M(C - S2)/M(C -  S1)  << endl;
+		 som  += M(C - S2)/M(C -  S1);
+	       } else 
+		{kopt=1;continue;}
+	     }
+	     cout <<  som  << endl;
+	     OnSwap = som < 4;
+	     break;
+	 }
+
+       } // OnSwap 
+     } // (! OnSwap &&(det1 > 0) && (det2 > 0) )
+   }
+   cout << OnSwap << endl;
+   if( OnSwap ) {
+     couleur(0);
+     t1->Draw();
+     t2->Draw();    
+     bamg::swap(t1,a1,t2,a2,s1,s2,det1,det2);		
+     couleur(1);
+     t1->Draw();
+     t2->Draw();    
+   }
+   else {
+     NbUnSwap ++;
+     t1->SetMarkUnSwap(a1);     
+   }
+   return OnSwap;
+}
+
+
+	   
+
+void GeometricalEdge::Draw(Int4  i)
+{ 
+    if (!withrgraphique) return;
+
+  if (CurrentTh && i<0 && i != -2)
+    {
+      if (CurrentTh->Gh.edges <= this && this < CurrentTh->Gh.edges + CurrentTh->Gh.nbe)
+	i = CurrentTh->Gh.Number((this));
+    }	
+
+    v[0]->MoveTo();
+    R2 x,x50;
+    int k=0,k50=0;
+    for (int ii = 0;ii<100;ii++) {
+      x= F( Real4(ii)/100.0);
+      if(ii==50) x50=x,k50=1;
+      if (InPtScreen(x.x,x.y) )
+	if(k) rlineto(x.x,x.y);
+	else k=1,rmoveto(x.x,x.y);
+    }
+      if (InPtScreen(v[1]->r.x,v[1]->r.y))      
+	v[1]->LineTo();  
+
+      char VertexDraw_i10[20];
+      if( k50) {
+	if (i<0)
+	  sprintf(VertexDraw_i10,"Eg%p",this);
+	else 
+	  sprintf(VertexDraw_i10,"Eg%ld",i);
+	rmoveto(x50.x,x50.y);
+	plotstring(&VertexDraw_i10[0]); }  
+
+}
+
+void  Geometry::InitDraw() const
+{ 
+   GrafPMin =  vertices[0].r;
+   GrafPMax =  vertices[0].r;
+  // recherche des extrema des vertices GrafPMin,GrafPMax
+  Int4 i;
+  for (i=0;i<nbv;i++) {
+    //    GrafPMax = Max2(GrafPMax,vertices[i].r);
+    //    GrafPMin = Min2(GrafPMin,vertices[i].r);
+    GrafPMin.x = Min(GrafPMin.x,vertices[i].r.x);
+    GrafPMin.y = Min(GrafPMin.y,vertices[i].r.y);
+    GrafPMax.x = Max(GrafPMax.x,vertices[i].r.x);
+    GrafPMax.y = Max(GrafPMax.y,vertices[i].r.y);
+  }
+  float hx = (GrafPMax.x-GrafPMin.x);
+  float hy = (GrafPMax.y-GrafPMin.y);
+  Grafh = Max(hx,hy)*7/10;
+  if (withrgraphique)
+   cadreortho((GrafPMin.x+GrafPMax.x)*0.5,(GrafPMin.y+GrafPMax.y)*0.55,Grafh);
+
+  
+}
+
+void   Geometry::Draw() const {
+    if (!withrgraphique) return;
+
+  showgraphic();
+  //  InitDraw();
+  Int4 i;
+  for (i=0;i<nbv;i++)
+    vertices[i].Draw();    
+  for (i=0;i<nbe;i++)
+    {
+	if(edges[i].Cracked()) couleur(4);
+	else couleur(6);
+    edges[i].Draw(i);
+    }
+   couleur(6);
+  for (i=0;i<nbv;i++)
+    if (vertices[i].Required()) {
+      char i10[40];
+      sprintf(i10,"%ld:%d",i,vertices[i].Required());
+      Move(vertices[i].r);
+      if(vertices[i].Corner()) couleur(2);
+      plotstring(i10);  
+      if(vertices[i].Corner()) couleur(6);
+      }
+  // rattente(1);
+ }
+
+}
+#endif
diff --git a/contrib/bamg/bamglib/MeshGeom.cpp b/contrib/bamg/bamglib/MeshGeom.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..44ee4ab83a0345f4dcf334f3f69e9d863cdd437e
--- /dev/null
+++ b/contrib/bamg/bamglib/MeshGeom.cpp
@@ -0,0 +1,1186 @@
+// -*- Mode : c++ -*-
+//
+// SUMMARY  :      
+// USAGE    :        
+// ORG      : 
+// AUTHOR   : Frederic Hecht
+// E-MAIL   : hecht@ann.jussieu.fr
+//
+
+/*
+ 
+ This file is part of Freefem++
+ 
+ Freefem++ is free software; you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+ 
+ Freefem++  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 Lesser General Public License for more details.
+ 
+ You should have received a copy of the GNU Lesser General Public License
+ along with Freefem++; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+// #define TRACETRIANGLE 3
+extern long verbosity ;
+//#define strcasecmp strcmp
+#include <cstdio>
+#include <string.h>
+#include <cmath>
+#include <time.h>
+#include <iostream>
+using namespace std;
+
+
+#include "Mesh2.h"
+#include "QuadTree.h"
+#include "SetOfE4.h"
+namespace bamg {
+void Triangles::ConsGeometry(Real8 cutoffradian,int *equiedges) // construct a geometry if no geo 
+ {
+  //  if equiedges existe taille nbe 
+  //   equiedges[i]/2 == i  original
+  //   equiedges[i]/2 = j  =>   equivalence entre i et j => meme maillage
+  //   equiedges[i]%2   : 0 meme sens , 1 pas meme sens 
+  //       
+  // --------------------------
+  if (verbosity>1) 
+    cout << "  -- construction of the geometry from the 2d mesh " << endl;
+  if (nbt<=0 || nbv <=0 ) { MeshError(101);}
+
+  // construction of the edges 
+  //  Triangles * OldCurrentTh =CurrentTh;
+  CurrentTh=this;
+  //  Int4 NbTold = nbt;
+  // generation of the integer coor
+  // generation of the adjacence of the triangles
+  if (cutoffradian>=0)
+    Gh.MaximalAngleOfCorner = cutoffradian;
+  SetOfEdges4 * edge4= new SetOfEdges4(nbt*3,nbv);
+  Int4 * st = new Int4[nbt*3];
+  Int4 i,k;
+  int j; 
+  if (Gh.name) delete Gh.name;
+  Gh.name = new char [ name ? strlen(name) + 15 : 50 ];
+  Gh.name[0]=0;
+  strcat(Gh.name,"cons from: ");
+  if (name) strcat(Gh.name,name);
+  else strcat(Gh.name," a mesh with no name");
+  for (i=0;i<nbt*3;i++)
+    st[i]=-1;
+  Int4 kk =0;
+
+  Int4 nbeold = nbe;
+  for (i=0;i<nbe;i++)
+    {
+      //      cout << i << " " << Number(edges[i][0]) << " " << Number(edges[i][1]) << endl;
+      edge4->addtrie(Number(edges[i][0]),Number(edges[i][1]));
+    }
+  if (nbe !=  edge4->nb())
+      { 
+      cerr << " Some Double edge in the mesh, the number is " << nbe 
+	   << " nbe4=" << edge4->nb()  << endl;
+      MeshError(1002);
+    }
+  for (i=0;i<nbt;i++)
+    for  (j=0;j<3;j++)
+      {
+	// Int4 i0,i1;
+	Int4 k =edge4->addtrie(Number(triangles[i][VerticesOfTriangularEdge[j][0]]),
+			       Number(triangles[i][VerticesOfTriangularEdge[j][1]]));
+	Int4 invisible = triangles[i].Hidden(j);
+	if(st[k]==-1)
+	  st[k]=3*i+j;
+	else if(st[k]>=0) {
+	  assert( ! triangles[i].TriangleAdj(j) && !triangles[st[k] / 3].TriangleAdj((int) (st[k]%3)));
+	  
+	  triangles[i].SetAdj2(j,triangles + st[k] / 3,(int) (st[k]%3));
+	  if (invisible)  triangles[i].SetHidden(j);
+	  if (k<nbe) {
+	    triangles[i].SetLocked(j);
+	  }
+	  st[k]=-2-st[k]; }
+	else {
+	  cerr << " The edge (" 
+	       << Number(triangles[i][VerticesOfTriangularEdge[j][0]])
+	       << " , " 
+	       << Number(triangles[i][VerticesOfTriangularEdge[j][1]])
+	       << " ) is in more than 2 triangles " <<k <<endl;
+	  cerr << " Edge " << j << " Of Triangle " << i << endl;
+	  cerr << " Edge " << (-st[k]+2)%3 << " Of Triangle " << (-st[k]+2)/3  << endl;
+	  cerr << " Edge " << triangles[(-st[k]+2)/3].NuEdgeTriangleAdj((int)((-st[k]+2)%3))
+	       << " Of Triangle " <<  Number(triangles[(-st[k]+2)/3].TriangleAdj((int)((-st[k]+2)%3))) 
+	       << endl;
+	  MeshError(9999);}	
+	
+	
+      }
+  Int4 nbedges = edge4->nb(); // the total number of edges 
+    delete edge4;
+  edge4 =0;
+
+  if(verbosity>5) {
+    if (name)
+     cout << "    On Mesh " << name << endl;
+    cout << "    - The number of Vertices  = " << nbv << endl;
+    cout << "    - The number of Triangles = " << nbt << endl;
+    cout << "    - The number of given edge = " << nbe << endl;
+    cout << "    - The number of all edges = " << nbedges << endl;
+    cout << "    - The Euler number = 1-Nb Of Hole = " << nbt-nbedges+nbv << endl; }
+  
+  
+  // check the consistant of edge[].adj and the geometrical required  vertex
+  k=0;
+  kk=0;
+  Int4 it;
+
+  for (i=0;i<nbedges;i++)
+    if (st[i] <-1) // edge internal
+      { 
+	it =  (-2-st[i])/3;
+	j  =  (int) ((-2-st[i])%3);
+	Triangle & tt = * triangles[it].TriangleAdj(j);
+	//cout << it << " c="  << triangles[it].color <<  " " << Number(tt) << " c="  << tt.color << endl;
+	if (triangles[it].color != tt.color|| i < nbeold) // Modif FH 06122055 // between 2 sub domai
+	  k++;
+      }
+    else if (st[i] >=0) // edge alone 
+       // if (i >= nbeold) 
+	     kk++;
+  
+  if(verbosity>4 && (k+kk) )
+    cout << "    Nb of  ref edge " << kk+k << " (internal " << k << ")"
+	 << " in file " << nbe  << endl;
+  k += kk;
+  kk=0;
+    if (k)
+    {
+      
+      //      if (nbe) {
+      //	cerr << k << " boundary edges  are not defined as edges " << endl;
+      //	MeshError(9998);
+      // }
+      // construction of the edges 
+      nbe = k;
+      Edge * edgessave = edges;
+      edges = new Edge[nbe];
+      k =0;
+      // construction of the edges 
+      if(verbosity>4)
+	cout << "    Construction of the edges  " << nbe << endl;
+
+      for (i=0;i<nbedges;i++)
+	{ 
+	  Int4  add= -1;
+	  
+	  if (st[i] <-1) // edge internal
+	    { 
+	      it =  (-2-st[i])/3;
+	      j  =  (int) ((-2-st[i])%3);
+	      Triangle & tt = * triangles[it].TriangleAdj(j);
+	      if (triangles[it].color !=  tt.color || i < nbeold) // Modif FH 06122055
+		  add=k++;
+	    }
+	  else if (st[i] >=0) // edge alone 
+	    {
+	      it = st[i]/3;
+	      j  = (int) (st[i]%3);
+	      add=k++;
+	    }
+	  
+	  if (add>=0 && add < nbe)
+	    {
+	      
+	      edges[add].v[0] = &triangles[it][VerticesOfTriangularEdge[j][0]];
+	      edges[add].v[1] = &triangles[it][VerticesOfTriangularEdge[j][1]];
+	      edges[add].on=0; 
+	      if (i<nbeold) // in file edge // Modif FH 06122055 
+		{
+		  edges[add].ref = edgessave[i].ref; 		      
+		  edges[add].on = edgessave[i].on; //  HACK pour recuperer les aretes requise midf FH avril 2006 ???? 
+		}
+	      else
+		edges[add].ref = Min(edges[add].v[0]->ref(),edges[add].v[1]->ref()); // no a good choice
+	    }
+	}
+      assert(k==nbe);
+      if (edgessave) delete [] edgessave;
+    }
+    
+    // construction of edges[].adj 
+    for (i=0;i<nbv;i++) 
+      vertices[i].color =0;
+    for (i=0;i<nbe;i++)
+      for (j=0;j<2;j++) 
+	edges[i].v[j]->color++;
+    
+    for (i=0;i<nbv;i++) 
+      vertices[i].color = (vertices[i].color ==2) ? -1 : -2;
+    for (i=0;i<nbe;i++)
+      for (j=0;j<2;j++) 
+	{ 
+	  Vertex *v=edges[i].v[j];
+	  Int4 i0=v->color,j0;
+	  if(i0<0)
+	     edges[i ].adj[ j ]=0;  // Add FH Jan 2008   
+	  if(i0==-1)
+	    v->color=i*2+j;
+	  else if (i0>=0) {// i and i0 edge are adjacent by the vertex v
+	    j0 =  i0%2;
+	    i0 =  i0/2;
+	    assert( v ==  edges[i0 ].v[j0]);
+	    edges[i ].adj[ j ] =edges +i0;
+	    edges[i0].adj[ j0] =edges +i ;
+	    assert(edges[i0].v[j0] == v);
+	    //	    if(verbosity>8)
+	    //  cout << " edges adj " << i0 << " "<< j0 << " <-->  "  << i << " " << j << endl;
+	    v->color = -3;}
+	}
+    // now reconstruct the sub domain info 
+    assert(!NbSubDomains);
+  NbSubDomains=0;
+  
+  { 
+    Int4 it;
+    // find all the sub domain
+    Int4 *colorT = new Int4[nbt];
+    Triangle *tt,*t;
+    Int4 k;
+    for ( it=0;it<nbt;it++)
+      colorT[it]=-1;
+    for (it=0;it<nbt;it++)
+      {
+	if (colorT[it]<0) 
+	  {
+	    colorT[it]=NbSubDomains;
+	    Int4 level =1,j,jt,kolor=triangles[it].color;
+	    st[0]=it; // stack 
+	    st[1]=0;
+	    k=1;
+	    while (level>0)
+	      if( ( j=st[level]++) <3)
+		{ 
+		  t = &triangles[st[level-1]];
+		  tt=t->TriangleAdj((int)j);
+		  
+		  if ( ! t->Locked(j) && tt && (colorT[jt = Number(tt)] == -1) && ( tt->color==kolor))
+		    {
+		      colorT[jt]=NbSubDomains;
+		      st[++level]=jt;
+		      st[++level]=0;
+		      k++;
+		    }
+		}
+	      else 
+		level-=2;
+	    if (verbosity>5) 
+	      cout << "   Nb of triangles " << k << " of Subdomain "  
+		   <<  NbSubDomains << " " << kolor << endl;
+	    NbSubDomains++;
+	  }
+      }
+    if (verbosity> 3)
+      cout << "   The Number of sub domain = " << NbSubDomains << endl;
+    
+    Int4 isd;
+    subdomains = new SubDomain[NbSubDomains];
+    for (isd=0;isd<NbSubDomains;isd++)
+      {
+	subdomains[isd].head =0;
+      }
+    k=0;
+    for (it=0;it<nbt;it++)
+      for (int j=0;j<3;j++)
+	{
+	  tt=triangles[it].TriangleAdj(j);
+	  if ((!tt ||  triangles[it].Locked(j) || tt->color != triangles[it].color) && !subdomains[isd=colorT[it]].head)
+	    {
+	      subdomains[isd].head = triangles+it;
+	      subdomains[isd].ref =  triangles[it].color;
+	      subdomains[isd].sens = j; // hack
+	      subdomains[isd].edge = 0;
+	      k++;
+	    }
+	}  
+    assert(k== NbSubDomains);
+    
+    delete [] colorT;
+    
+    
+  }      
+  delete [] st;
+  // now make the geometry
+  // 1 compress the vertices 
+  Int4 * colorV = new Int4[nbv];
+  for (i=0;i<nbv;i++) 
+    colorV[i]=-1;
+  for (i=0;i<nbe;i++)
+    for ( j=0;j<2;j++)
+      colorV[Number(edges[i][j])]=0;
+  k=0;
+  for (i=0;i<nbv;i++) 
+    if(!colorV[i])
+      colorV[i]=k++;
+  
+  Gh.nbv=k;
+  Gh.nbe = nbe;
+  Gh.vertices = new GeometricalVertex[k];
+  Gh.edges = new GeometricalEdge[nbe];
+  Gh.NbSubDomains = NbSubDomains;
+  Gh.subdomains = new GeometricalSubDomain[NbSubDomains];
+  if (verbosity>3)
+    cout << "    Nb of  vertices  = " << Gh.nbv << " Nb of edges = " << Gh.nbe << endl;
+  NbVerticesOnGeomVertex = Gh.nbv;
+  VerticesOnGeomVertex = new VertexOnGeom[NbVerticesOnGeomVertex];
+  NbVerticesOnGeomEdge =0;
+  VerticesOnGeomEdge =0;
+  {
+    Int4 j;
+    for (i=0;i<nbv;i++) 
+      if((j=colorV[i])>=0)
+	{
+	  
+	  Vertex & v = Gh.vertices[j];
+	  v = vertices[i];
+	  v.color =0;
+	  VerticesOnGeomVertex[j] = VertexOnGeom(vertices[i], Gh.vertices[j]);
+	}
+    
+  }
+  edge4= new SetOfEdges4(nbe,nbv);  
+  
+  Real4 * len = new Real4[Gh.nbv];
+  for(i=0;i<Gh.nbv;i++)
+    len[i]=0;
+  
+  Gh.pmin =  Gh.vertices[0].r;
+  Gh.pmax =  Gh.vertices[0].r;
+  // recherche des extrema des vertices pmin,pmax
+  for (i=0;i<Gh.nbv;i++) {
+    Gh.pmin.x = Min(Gh.pmin.x,Gh.vertices[i].r.x);
+    Gh.pmin.y = Min(Gh.pmin.y,Gh.vertices[i].r.y);
+    Gh.pmax.x = Max(Gh.pmax.x,Gh.vertices[i].r.x);
+    Gh.pmax.y = Max(Gh.pmax.y,Gh.vertices[i].r.y);
+  }
+  
+  R2 DD05 = (Gh.pmax-Gh.pmin)*0.05;
+  Gh.pmin -=  DD05;
+  Gh.pmax +=  DD05;
+  
+  Gh.coefIcoor= (MaxICoor)/(Max(Gh.pmax.x-Gh.pmin.x,Gh.pmax.y-Gh.pmin.y));
+  assert(Gh.coefIcoor >0);
+  
+  Real8 hmin = HUGE_VAL;
+     int kreq=0;
+  for (i=0;i<nbe;i++)
+    {
+      Int4 i0 = Number(edges[i][0]);
+      Int4 i1 = Number(edges[i][1]);
+      Int4 j0 =	 colorV[i0];
+      Int4 j1 =  colorV[i1];
+      
+      Gh.edges[i].v[0] = Gh.vertices +  j0;
+      Gh.edges[i].v[1] = Gh.vertices +  j1;
+      Gh.edges[i].flag = 0;
+      Gh.edges[i].tg[0]=R2();
+      Gh.edges[i].tg[1]=R2();
+      bool requis= edges[i].on; 
+	if(requis) kreq++;
+      edges[i].on =  Gh.edges + i;
+      if(equiedges && i < nbeold ) {
+        int j=equiedges[i]/2;
+        int sens=equiedges[i]%2;
+        if(i!=j && equiedges[i]>=0) {
+          if(verbosity>9)  
+             cout << " Edges Equi " << i << " <=> " << j << " sens = " << sens  << endl;
+           if( sens==0)
+           Gh.edges[i].SetEqui();
+           else 
+            Gh.edges[i].SetReverseEqui();
+           Gh.edges[i].link= & Gh.edges[j];
+           //assert(sens==0);//  meme sens pour l'instant
+        }
+	
+       }
+      if(requis)  {  // correction fevr 2009 JYU ...
+	Gh.edges[i].v[0]->SetRequired();
+	Gh.edges[i].v[1]->SetRequired();
+	Gh.edges[i].SetRequired(); // fin modif ... 
+      }
+      R2 x12 = Gh.vertices[j0].r-Gh.vertices[j1].r;
+      Real8 l12=Norme2(x12);        
+      hmin = Min(hmin,l12);
+      
+      Gh.vertices[j1].color++;
+      Gh.vertices[j0].color++;
+      
+      len[j0]+= l12;
+      len[j1] += l12;
+      hmin = Min(hmin,l12);
+      
+      Gh.edges[i].ref  = edges[i].ref;
+      
+      k = edge4->addtrie(i0,i1);
+      
+      assert(k == i);
+      
+    }
+  
+  
+  for (i=0;i<Gh.nbv;i++) 
+    if (Gh.vertices[i].color > 0) 
+      Gh.vertices[i].m=  Metric(len[i] /(Real4) Gh.vertices[i].color);
+    else 
+      Gh.vertices[i].m=  Metric(hmin);
+  delete [] len;
+  for (i=0;i<NbSubDomains;i++)
+    {
+      Int4 it = Number(subdomains[i].head);
+      int j = subdomains[i].sens;
+      Int4 i0 = Number(triangles[it][VerticesOfTriangularEdge[j][0]]);
+      Int4 i1 = Number(triangles[it][VerticesOfTriangularEdge[j][1]]);
+      k = edge4->findtrie(i0,i1);
+      if(k>=0)
+	{
+	  subdomains[i].sens = (vertices + i0 == edges[k].v[0]) ? 1 : -1;
+	  subdomains[i].edge = edges+k;
+	  Gh.subdomains[i].edge = Gh.edges + k;
+	  Gh.subdomains[i].sens  =  subdomains[i].sens;
+	  Gh.subdomains[i].ref =  subdomains[i].ref;
+	}
+      else
+	MeshError(103);
+    }
+  
+  delete edge4;
+  delete [] colorV;
+  //  -- unset adj
+  for (i=0;i<nbt;i++)
+    for ( j=0;j<3;j++)
+      triangles[i].SetAdj2(j,0,triangles[i].GetAllflag(j));
+  
+}
+
+
+void Geometry::EmptyGeometry()  // empty geometry
+  {
+  OnDisk=0;
+  NbRef=0;
+  name =0;
+  quadtree=0;
+  curves=0;
+ // edgescomponante=0;
+  triangles=0;
+  edges=0;
+  vertices=0;
+  NbSubDomains=0;
+  //  nbtf=0;
+//  BeginOfCurve=0;  
+  nbiv=nbv=nbvx=0;
+  nbe=nbt=nbtx=0;
+  NbOfCurves=0;
+//  BeginOfCurve=0;
+  subdomains=0;
+  MaximalAngleOfCorner = 10*Pi/180;
+  }
+
+
+
+Geometry::Geometry(const Geometry & Gh)
+ { Int4 i;
+   *this = Gh;
+   NbRef =0;
+   quadtree=0;
+   name = new char[strlen(Gh.name)+4];
+   strcpy(name,"cp:");
+   strcat(name,Gh.name);
+   vertices = nbv ? new GeometricalVertex[nbv] : NULL;
+   triangles = nbt ? new  Triangle[nbt]:NULL;
+   edges = nbe ? new GeometricalEdge[nbe]:NULL;
+   curves= NbOfCurves ? new Curve[NbOfCurves]:NULL;
+   subdomains = NbSubDomains ? new GeometricalSubDomain[NbSubDomains]:NULL;
+   for (i=0;i<nbv;i++)
+     vertices[i].Set(Gh.vertices[i],Gh,*this);
+   for (i=0;i<nbe;i++)
+     edges[i].Set(Gh.edges[i],Gh,*this);
+   for (i=0;i<NbOfCurves;i++)
+     curves[i].Set(Gh.curves[i],Gh,*this);
+   for (i=0;i<NbSubDomains;i++)
+     subdomains[i].Set(Gh.subdomains[i],Gh,*this);
+     
+   //    for (i=0;i<nbt;i++)
+   //      triangles[i].Set(Gh.triangles[i],Gh,*this);
+   assert(!nbt);   
+ }
+
+
+GeometricalEdge* Geometry::Contening(const R2 P,  GeometricalEdge * start) const
+{
+  GeometricalEdge* on =start,* pon=0;
+  // walk with the cos on geometry
+  //  cout << P ;
+  int k=0;
+   while(pon != on)
+     {  
+       pon = on;
+       assert(k++<100);
+       R2 A= (*on)[0];
+       R2 B= (*on)[1];
+       R2 AB = B-A;
+       R2 AP = P-A;
+       R2 BP = P-B;
+       //   cout << "::  " << on - edges << " "  <<  AB*AP  << " " <<  AB*BP << " " << A << B << endl;
+       if ( (AB,AP) < 0) 
+	 on = on->Adj[0];
+       else if ( (AB,BP)  > 0) 
+	 on = on->Adj[1];
+       else
+	 return on;
+     }
+   return on;
+}
+GeometricalEdge* Geometry::ProjectOnCurve(const Edge & e,Real8 s,Vertex &V,VertexOnGeom &GV ) const 
+ {  
+    Real8 save_s=s;
+    int NbTry=0;
+retry:    
+    s=save_s;
+    GeometricalEdge * on = e.on;
+    assert(on);
+    assert( e[0].on &&  e[1].on);
+    const Vertex &v0=e[0],&v1=e[1];
+    V.m = Metric(1.0-s, v0,s, v1);
+#define MXE__LINE  __LINE__+1
+    const int mxe =100;
+    GeometricalEdge *ge[mxe+1];
+    int    sensge[mxe+1];
+    Real8  lge[mxe+1];
+    int bge=mxe/2,tge=bge;
+    ge[bge] = e.on;
+    sensge[bge]=1;
+
+    R2 V0 = v0,V1=v1,V01=V1-V0;
+    VertexOnGeom  vg0= *v0.on,  vg1=*v1.on;
+    if(NbTry) cout << "bug: s==== " << s << " e=" <<  V0 << " " << V1 << endl;
+
+    //    GeometricalEdge * eg0 = e.on,* eg1 = e.on, *eg=NULL;
+    GeometricalEdge * eg0=on, *eg1=on;
+    R2 Ag=(R2) (*on)[0],Bg=(R2)(*on)[1],AB=Bg-Ag; 
+    if(NbTry) cout <<" G edge= " << Ag << Bg << endl << " v edge" << V01 << " v geom " << AB  <<  (V01,AB) <<endl; 
+    int OppositeSens = (V01,AB) < 0;
+    int sens0=0,sens1=1;
+    if (OppositeSens)
+      s=1-s,Exchange(vg0,vg1),Exchange(V0,V1);
+    // find all the discretisation of the egde 
+#ifdef DEBUG
+    // we supposee  edge on=[Ag,Bg]  intersect edge [V0,V1];
+    // =>   V0Ag.V0V1 > 0 ||  V0Bg.V0V1 >0
+    // =>   V1Ag.V0V1 < 0 ||  V0Bg.V0V1 <0
+    R2 V0V1 = V1-V0;
+    Real8 cos0A = ((Ag-V0),V0V1);
+    Real8 cos0B = ((Bg-V0),V0V1);
+    Real8 cos1A = ((Ag-V1),V0V1);
+    Real8 cos1B = ((Bg-V1),V0V1);
+    if ( (cos0A < 0 && cos0B <0) || (cos1A> 0 && cos1B >0))
+      {
+	cerr << "  Bug on pointer edge  [" << V0 << " , " << V1 << " ] "
+	     << "  on geometrical edge " << Number(on) << " = [" << Ag << " , " << Bg << " ] " << endl;
+	cerr << cos0A << "> 0  ||  " << cos0B <<  " >  0  and  ";
+	cerr << cos1A << "< 0  ||  " << cos1B <<  " <  0  " << endl;
+	
+	exit (1);
+	}
+    
+#endif    
+    if(NbTry) cout << "bug: edge = " << v0.r << " -> " << v1.r << endl 
+		   << "sg 0 = " << vg0 
+		   << " on = " << Number(on) << ":" << Ag << Bg << "; " 
+		   <<  " sg 1= " << vg1 
+		   << "--------------------------------------------" << endl;
+    while (eg0 != (GeometricalEdge*) vg0  &&  (*eg0)(sens0) != (GeometricalVertex*) vg0)
+      { 
+      if (bge<=0) {
+	//          int kkk;
+          // if (NbTry) cout <<"Read (int) to Show Sioux window", cin >> kkk ;
+	       if(NbTry) 
+	          {
+		    cerr << " -- Fatal Error: on the class triangles before call Geometry::ProjectOnCurve" << endl; 
+		    cerr << "   The mesh of the  Geometry is to fine: ";
+		    cerr << "     1)  a mesh edge  contening more than "<< mxe/2 << " geometrical edges." << endl;
+		    cerr << "     2)  code bug : be sure that we call   Triangles::SetVertexFieldOn() before " << endl;
+		    cerr << "   To solve the problem do a coarsening of the geometrical mesh " << endl;
+		    cerr << " or change the constant value of mxe in " << __FILE__ << " line " << MXE__LINE << "( dangerous way )" << endl;	  
+		    MeshError(222);
+		  }
+	    NbTry++;
+	    goto retry;}
+        GeometricalEdge* tmpge = eg0;
+	 if(NbTry)
+		cout << "bug: --Edge @" <<  Number(tmpge)  << " = "<< Number(eg0) << ":" <<Number(eg0->Adj[0]) << "," <<  
+			 Number(eg0->Adj[1]) <<"," ;
+	ge[--bge] =eg0 = eg0->Adj[sens0];
+	assert(bge>=0 && bge <= mxe);
+	sens0 = 1-( sensge[bge] = tmpge->SensAdj[sens0]);
+	if(NbTry)
+		cout << "bug: Edge "  <<  Number(eg0) << " "<< 1-sens0 <<  " S "
+		     << Number((*eg0)[1-sens0]) <<":" << Number(eg0->Adj[0]) << "," 
+		     <<  Number(eg0->Adj[1]) <<"," << endl
+	 	     <<Number(eg0)<< (*eg0)[sens0].r << "v = " << Number((*eg1)(sens0)) << " e = " << eg0 <<  endl;
+     }
+      if(NbTry) cout << Number((GeometricalEdge*) vg1) << " " << Number((GeometricalVertex*) vg1) << endl;
+    while (eg1 != (GeometricalEdge*) vg1  &&  (*eg1)(sens1) != (GeometricalVertex*) vg1)
+      { 
+        if(tge>=mxe ) { 
+	  cerr << " --Fatal Error: on the class triangles before call Geometry::ProjectOnCurve" << endl; 
+	  NbTry++;
+	  if (NbTry<2) goto retry;
+	  cerr << "   The mesh of the  Geometry is to fine:" ;
+	  cerr << "     1)  a mesh edge  contening more than "<< mxe/2 << " geometrical edges." << endl;
+	  cerr << "     2)  code bug : be sure that we call   Triangles::SetVertexFieldOn() before " << endl;
+	  cerr << "   To solve the problem do a coarsening of the geometrical mesh " << endl;
+	  cerr << " or change the constant value of mxe in " << __FILE__ << " line " << MXE__LINE << "( dangerous way )" << endl;	
+	  MeshError(223);
+	}
+
+	GeometricalEdge* tmpge = eg1;
+	if(NbTry)
+		cout << "++Edge @" << tmpge << " = " <<  Number(eg1) <<"%" << Number(eg1->Adj[0]) << "," 
+		 <<  Number(eg1->Adj[1]) <<"," ;
+	ge[++tge] =eg1 = eg1->Adj[sens1];
+	sensge[tge]= sens1 = 1-tmpge->SensAdj[sens1];
+	assert(tge>=0 && tge <= mxe);
+         if(NbTry)
+		cout << "  Edge "  <<  Number(eg1) << " " << sens1 << " S "
+		     <<Number((*eg1)[sens1]) <<"%"<< Number(eg1->Adj[0]) << "," <<  Number(eg1->Adj[1]) <<"," 
+	             <<Number(eg1)<< (*eg1)[sens1].r << "v = " << Number((*eg1)(sens1)) << " e = " << Number(eg1) <<  endl;
+      }
+
+    	if(NbTry)    cout << endl;
+        
+
+    if ( (*eg0)(sens0) == (GeometricalVertex*) vg0 )
+      vg0 = VertexOnGeom( *(Vertex *) vg0,*eg0,sens0);
+    
+    if ( (*eg1)(sens1) == (GeometricalVertex*) vg1)
+       vg1 = VertexOnGeom( *(Vertex *) vg1,*eg1,sens1);
+
+    Real8 sg;
+    //   cout << "           " << Number(on) << " " <<  Number(eg0) << " " <<  Number(eg1) << " "  ; 
+    if (eg0 == eg1) { 
+       register Real8 s0= vg0,s1=vg1;
+       sg =  s0 * (1.0-s) +  s * s1;
+       //    cout <<"                s0=" << s0 << " s1=" << s1 
+       //             << " s = " << s << " sens= " << OppositeSens << "\t\t sg = " << sg << endl ;
+       on=eg0;}
+    else {
+       R2 AA=V0,BB;
+       Real8 s0,s1;
+       
+       //cout << endl << "s= " << s << Number(eg0) << " " << (Real8) vg0 << " " 
+       //	    << Number(eg1) << " " << (Real8) vg1 << V0 << V1 << "  Interpol = " 
+       // << V0*(1-s)+V1*s << ";;; " <<  endl;
+       int i=bge;
+       Real8 ll=0;
+       for(i=bge;i<tge;i++) 
+	 {
+	   assert( i>=0 && i <= mxe);
+	   BB =  (*ge[i])[sensge[i]];
+	   lge[i]=ll += Norme2(AA-BB);
+	   //   cout << " ll " << i << BB << ll << " " <<sensge[i] <<" on = " <<
+	   // Number(ge[i]) << " sens= " << sensge[i] ;
+	   AA=BB ;}
+       lge[tge]=ll+=Norme2(AA-V1); 
+       // cout << " ll " << tge << " " << ll <<  sensge[tge] 
+       //	     <<" on = " << Number(ge[tge]) <<  " sens= " << sensge[tge] << endl;
+    // search the geometrical edge
+      assert(s <= 1.0);
+      Real8 ls= s*ll;
+      on =0;
+      s0 = vg0;
+      s1= sensge[bge];
+      Real8 l0=0,l1;
+      i=bge;
+      while (  (l1=lge[i]) < ls ) {
+	assert(i >= 0 && i <= mxe);
+	i++,s0=1-(s1=sensge[i]),l0=l1;}
+      on=ge[i];
+      if (i==tge) 
+	s1=vg1;
+     
+      s=(ls-l0)/(l1-l0);
+      //  cout << "on =" << Number(on) << sens0 << sens1 <<  "s0  " << s0 << " s1 =" 
+      //	     << s1 << " l0 =" << l0 << " ls= " << ls << " l1= " << l1 << " s= " << s;
+       sg =  s0 * (1.0-s) +  s * s1;    
+       } 
+    assert(on);
+    // assert(sg && sg-1);
+    V.r= on->F(sg);
+    //  if (eg0 != eg1) 
+    //        cout << "----- sg = "<< sg << " Sens =" << OppositeSens << " Edge = " 
+    //     << Number(on) <<"  V=" << V << endl;
+    GV=VertexOnGeom(V,*on,sg);
+    return on;
+ }
+
+void Geometry::AfterRead()
+ {// -----------------
+    if (verbosity>20)
+    cout << "Geometry::AfterRead()" <<  nbv << " " << nbe << endl;
+    Int4 i,k=0;        ;
+    int jj; // jj in [0,1]
+    Int4 * hv = new Int4 [ nbv];
+    Int4 * ev = new Int4 [ 2 * nbe ];
+    float  * eangle = new float[ nbe ];
+    {
+      double eps = 1e-20;
+      QuadTree quadtree; // to find same vertices
+      Vertex * v0 = vertices; 
+      GeometricalVertex  * v0g = (GeometricalVertex  *) (void *) v0;   
+      int k=0;
+      for (i=0;i<nbv;i++) 
+        vertices[i].link = vertices +i;
+      for (i=0;i<nbv;i++) 
+	     {
+	      vertices[i].i = toI2(vertices[i].r); // set integer coordinate
+	      Vertex *v= quadtree.NearestVertex(vertices[i].i.x,vertices[i].i.y); 
+	      if( v && Norme1(v->r - vertices[i]) < eps )
+	       { // link v & vertices[i] 
+	         // vieille ruse pour recuperer j 
+	         GeometricalVertex * vg = (GeometricalVertex  *) (void *) v;
+	         int j = vg-v0g;
+	         assert( v ==  & (Vertex &) vertices[j]);
+	         vertices[i].link = vertices + j;
+            k++;	      
+	       }
+	      else  quadtree.Add(vertices[i]); 
+	     }
+      if (k) {
+	cout << " Number of distinte vertices " << nbv - k << " Over " << nbv << endl;
+	//if (verbosity>10) 
+	{
+	  cout << " The duplicate vertex " << endl;
+	  for (i=0;i<nbv;i++)
+	    if (!vertices[i].IsThe())
+	      cout << " " << i << " and " << Number(vertices[i].The()) << endl;
+	  MeshError(102);
+	  //throw(ErrorExec("exit",1));    
+	}
+      }
+      
+      //  verification of cracked edge
+      int err =0;
+      for (i=0;i<nbe;i++)
+	if (edges[i].Cracked() )
+	  {
+	    //    verification of crack
+	    GeometricalEdge & e1=edges[i];
+	    GeometricalEdge & e2=*e1.link;
+            cerr << i << " " << e1[0].The() << " " << e2[0].The() << " " <<  e1[1].The() << " " << e2[1].The() << endl;
+	    if ( e1[0].The() == e2[0].The() && e1[1].The() == e2[1].The() )
+	      {
+	      }
+	    else 
+	      if ( e1[0].The() == e2[1].The() && e1[1].The() == e2[0].The() )
+		{
+		}
+	      else
+		{
+		  err++;
+		  cerr << " Cracked edges with no same vertex " << &e1-edges << " " << &e2 -edges << endl;
+		}
+	  }
+	else
+	  {
+	    //  if (!edges[i][0].IsThe()) err++;
+	    // if (!edges[i][1].IsThe()) err++;
+	  }
+      if (err)
+	{
+	  cerr << " Some vertex was not distint and not on cracked edge " << err<< endl;
+	  MeshError(222);
+	}
+    }
+    if(verbosity>7) 
+      for (i=0;i<nbv;i++)
+	if (vertices[i].Required())
+	  cout << "     The geo vertices  " << i << " is required" << endl;
+
+    for (i=0;i<nbv;i++) 
+      hv[i]=-1;// empty list
+
+    for (i=0;i<nbe;i++) 
+      {
+        R2 v10  =  edges[i].v[1]->r -  edges[i].v[0]->r;
+        Real8 lv10 = Norme2(v10);
+        if(lv10 == 0) {
+          cerr << "The length  of " <<i<< "th Egde is 0 " << endl ;
+          MeshError(1);}
+        eangle[i] = atan2(v10.y,v10.x)  ; // angle in [ -Pi,Pi ]
+	if(verbosity>9) 
+	  cout << "     angle edge " << i <<" " << eangle[i]*180/Pi<< v10<<endl;
+        for (jj=0;jj<2;jj++)
+          { // generation of list
+            Int4 v =  Number(edges[i].v[jj]);
+            ev[k] = hv[v];
+            hv[v] = k++;
+          }
+      }
+    // bulle sort on the angle of edge  
+    for (i=0;i<nbv;i++) {
+      int exch = 1,ord =0;      
+      while (exch) {
+        exch = 0;
+        Int4  *p =  hv + i, *po = p;
+	Int4 n = *p;
+        register float angleold = -1000 ; // angle = - infini 
+        ord = 0;
+        while (n >=0) 
+        {
+          ord++;
+          register Int4 i1= n /2;
+          register Int4  j1 = n % 2;
+          register Int4 *pn = ev + n;
+          float angle = j1 ? OppositeAngle(eangle[i1]):  eangle[i1];
+          n = *pn;
+          if (angleold > angle) // exch to have : po -> pn -> p 
+            exch=1,*pn = *po,*po=*p,*p=n,po = pn;
+          else //  to have : po -> p -> pn 
+            angleold =  angle, po = p,p  = pn;
+        }
+      } // end while (exch)
+      
+      if (ord >= 1 ) 
+	{ /*
+	  Int4 n = hv[i];
+	  while ( n >=0) 
+	    { Int4 i1 = n/2,j1 = n%2;
+	    //float a = 180*(j1 ? OppositeAngle(eangle[i1]): eangle[i1])/Pi;
+	    n = ev[n];
+	    }
+	  */
+	} 
+      if(ord == 2) { // angulare test to find a corner 
+        Int4 n1 = hv[i];
+        Int4 n2 = ev[n1];
+        Int4 i1 = n1 /2, i2 = n2/2; // edge number
+        Int4  j1 = n1 %2, j2 = n2%2; // vertex in the edge 
+        float angle1= j1 ? OppositeAngle(eangle[i1]) :  eangle[i1];
+        float angle2= !j2 ? OppositeAngle(eangle[i2]) :  eangle[i2];
+	float da12 = Abs(angle2-angle1);
+	if(verbosity>9)
+	  cout <<"     check angle " << i << " " << i1 << " " << i2  << " " << 180*(da12)/Pi 
+	       << " " << 180*MaximalAngleOfCorner/Pi << vertices[i] << endl;
+
+        if (( da12 >= MaximalAngleOfCorner ) 
+            && (da12 <= 2*Pi -MaximalAngleOfCorner)) {
+	  vertices[i].SetCorner() ; 
+	  if(verbosity>7)
+	    cout << "     The vertex " << i << " is a corner (angle) " 
+		 << 180*(da12)/ Pi<< " " << 180*MaximalAngleOfCorner/Pi << endl;}
+	// if the ref a changing then is     SetRequired();
+	
+	if (edges[i1].flag != edges[i2].flag || edges[i1].Required()) 
+	 {
+	  vertices[i].SetRequired();
+	  if(verbosity>7)
+	    cout << "     The vertex " << i << " is Required the flag change (crack or equi, or require)" << endl;}
+	  
+	if (edges[i1].ref != edges[i2].ref) {
+	  vertices[i].SetRequired();
+	  if(verbosity>7)
+	    cout << "     The vertex " << i << " is Required ref" << endl;}
+      } ;
+      
+      if(ord != 2) {
+        vertices[i].SetCorner();
+	if(verbosity>7)
+	  cout << "     the vertex " << i << " is a corner ordre = " << ord << endl;
+      }
+      // close the liste around the vertex 
+      { Int4 no=-1, ne = hv[i];
+        while ( ne >=0) 
+                 ne = ev[no=ne];        
+            if(no>=0) 
+              ev[no] = hv[i];
+          } // now the list around the vertex is circular
+      
+    } // end for (i=0;i<nbv;i++)
+ 
+    k =0;
+    for (i=0;i<nbe;i++)
+      for (jj=0;jj<2;jj++){
+            Int4 n1 = ev[k++]; 
+            Int4 i1 = n1/2 ,j1=n1%2;
+            if( edges[i1].v[j1] != edges[i].v[jj]) 
+              { cerr << " Bug Adj edge " << i << " " << jj << 
+                  " et " << i1 << " " << j1 << " k=" << k;
+                cerr << Number(edges[i].v[jj]) <<" <> " 
+                     << Number(edges[i1].v[j1])  <<endl;
+                cerr << "edge " << Number(edges[i].v[0]) << " " 
+                     << Number(edges[i].v[1]) << endl; 
+            //    cerr << "in file " <<filename <<endl;
+                MeshError(1);
+              }
+            edges[i1].Adj[j1] = edges + i;
+            edges[i1].SensAdj[j1] = jj;
+	    if (verbosity>10)
+	      cout << " edges. Adj " << i1 << " " << j1 << " <--- " << i << " " << jj << endl;
+      }
+    
+    // generation of  all the tangente 
+    for (i=0;i<nbe;i++) {
+        R2 AB = edges[i].v[1]->r -edges[i].v[0]->r;        
+	Real8 lAB = Norme2(AB); // length of current edge AB
+        Real8 ltg2[2];
+        ltg2[0]=0;ltg2[1]=0;
+        for (jj=0;jj<2;jj++) {
+             R2 tg =  edges[i].tg[jj];
+             Real8 ltg = Norme2(tg); // length of tg
+             if(ltg == 0) {// no tg
+	       if( ! edges[i].v[jj]->Corner())   { // not a Corner       
+		 tg =  edges[i].v[1-jj]->r 
+		   - edges[i].Adj[jj]->v[1-edges[i].SensAdj[jj]]->r;
+		 ltg =  Norme2(tg);
+		 tg =  tg *(lAB/ltg),ltg=lAB;
+		/*
+		   if(edges[i].ref >=4) 
+		   cout << " tg " << tg.x << " "<< tg.y  << " " << edges[i].v[1-jj]->r << edges[i].Adj[jj]->v[1-edges[i].SensAdj[jj]]->r << " y-y = "
+		     << edges[i].v[1-jj]->r.y -edges[i].Adj[jj]->v[1-edges[i].SensAdj[jj]]->r.y <<  endl;
+		*/
+	       }
+	       
+	       //else ;// a Corner with no tangent => nothing to do    
+             } // a tg 
+             else 
+               tg = tg *(lAB/ltg),ltg=lAB;
+             ltg2[jj] = ltg;
+             if ( (tg,AB) < 0) 
+               tg = -tg;
+	    //if(edges[i].ref >=4) cout << " tg = " << tg << endl;
+             edges[i].tg[jj] = tg;
+	}     // for (jj=0;jj<2;jj++) 
+	
+	if (ltg2[0]!=0) edges[i].SetTgA();
+	if (ltg2[1]!=0) edges[i].SetTgB();
+    } // for (i=0;i<nbe;i++)
+
+    if(verbosity>7)
+      for (i=0;i<nbv;i++)
+	if (vertices[i].Required())
+	  cout << "     The  geo  vertices " << i << " is required " << endl;
+  
+   for (int step=0;step<2;step++)
+   {
+    for (i=0;i<nbe;i++) 
+      edges[i].SetUnMark();
+    
+    NbOfCurves = 0;
+    Int4  nbgem=0;
+    for (int level=0;level < 2 && nbgem != nbe;level++)
+      for (i=0;i<nbe;i++) {
+	GeometricalEdge & ei = edges[i];   
+	for(jj=0;jj<2;jj++) 
+	  if (!ei.Mark() && (level || ei[jj].Required())) { 
+	    // warning ei.Mark() can be change in loop for(jj=0;jj<2;jj++) 
+	    int k0=jj,k1;
+	    GeometricalEdge *e = & ei;
+	    GeometricalVertex *a=(*e)(k0); // begin 
+	    if(curves) {
+	      curves[NbOfCurves].be=e;
+	      curves[NbOfCurves].kb=k0;
+	    }
+	    int nee=0;
+	    for(;;) { 
+		nee++;
+	      k1 = 1-k0; // next vertex of the edge 
+	      e->SetMark();
+	      nbgem++;
+	      e->CurveNumber=NbOfCurves;
+	      if(curves) {
+	      curves[NbOfCurves].ee=e;
+	      curves[NbOfCurves].ke=k1;
+	      }
+	      
+	      GeometricalVertex *b=(*e)(k1);
+	      if (a == b ||  b->Required() ) break;
+	      k0 = e->SensAdj[k1];//  vertex in next edge
+	      e = e->Adj[k1]; // next edge
+	      
+	    }// for(;;)
+	      if(verbosity>10 && curves==0) cout << NbOfCurves <<" curve :  nb edges=  "<< nee<<  endl; 
+	    NbOfCurves++;
+	    if(level) {
+	      if(verbosity>4)
+		cout << "    Warning: Curve "<< NbOfCurves << " without required vertex " 
+		     << "so the vertex " << Number(a) << " become required " <<endl;
+	      a->SetRequired();
+	    }
+       
+	  }} 
+	  assert(nbgem && nbe);
+
+	  if(step==0) {
+	    curves = new Curve[NbOfCurves];
+	  }
+    	} 
+    for(int i=0;i<NbOfCurves ;i++)
+     {
+       GeometricalEdge * be=curves[i].be, *eqbe=be->link;
+       //GeometricalEdge * ee=curves[i].ee, *eqee=be->link;
+       curves[i].master=true;
+       if(be->Equi() || be->ReverseEqui() ) 
+        {
+          assert(eqbe);
+          int nc = eqbe->CurveNumber;
+          assert(i!=nc);
+          curves[i].next=curves[nc].next;
+          curves[i].master=false;
+          curves[nc].next=curves+i;
+          if(be->ReverseEqui())
+           curves[i].Reverse();           
+        }
+     }
+    	 
+    if(verbosity>3)
+      cout << "    End ReadGeometry: Number of curves in geometry is " << NbOfCurves <<endl; 
+    if(verbosity>4)
+    for(int i=0;i<NbOfCurves ;i++)
+     {
+        cout << " Curve " << i << " begin e=" << Number(curves[i].be) << " k=" << curves[i].kb 
+             << "  end e= " << Number(curves[i].ee) << " k=" << curves[i].ke << endl;
+     }
+    delete []ev;
+    delete []hv;
+    delete []eangle;
+    
+}
+Geometry::~Geometry() 
+{
+  assert(NbRef<=0);
+  if(verbosity>9)
+    cout << "DELETE      ~Geometry "<< this  << endl;
+  if(vertices)  delete [] vertices;vertices=0;
+  if(edges)     delete [] edges;edges=0;
+ // if(edgescomponante) delete [] edgescomponante; edgescomponante=0;
+  if(triangles) delete [] triangles;triangles=0;
+  if(quadtree)  delete  quadtree;quadtree=0;
+  if(curves)  delete  []curves;curves=0;NbOfCurves=0;
+  if(name) delete [] name;name=0;
+  if(subdomains) delete [] subdomains;subdomains=0;
+//  if(ordre)     delete [] ordre;
+  EmptyGeometry();
+
+}
+
+Real8 GeometricalEdge::R1tg(Real8 theta,R2 & t) const // 1/R of radius of cuvature
+{ R2 A=v[0]->r,B=v[1]->r;
+ Real8 dca,dcb,dcta,dctb;
+ Real8 ddca,ddcb,ddcta,ddctb;
+ // Real8 t1 = 1 -theta;
+ // Real8 t1t1 = t1*t1;
+ Real8 tt = theta*theta;
+ assert( theta >=0);
+ assert( theta <=1);
+ if (TgA()) 
+  if (TgB()) // interpolation d'hermite
+    { //cb =  theta*theta*(3-2*theta);
+     dcb = 6*theta*(1-theta);
+     ddcb = 6*(1-2*theta);
+     //ca =  1-cb;     
+     dca = -dcb;
+     ddca = -ddcb;
+
+       // cta = (1-theta)*(1-theta)*theta;
+     dcta =  (3*theta - 4)*theta + 1;
+     ddcta=6*theta-4;
+
+     //ctb = (theta-1)*theta*theta ;
+     dctb = 3*tt - 2*theta;
+     ddctb = 6*theta-2;
+    }
+  else { // 1-t*t, t-t*t, t*t
+    Real8 t = theta;
+    // cb = t*t;
+    dcb = 2*t;
+    ddcb = 2;
+    //ca = 1-cb;
+    dca = -dcb;
+    ddca = -2;
+    // cta= t-cb;
+    dcta = 1-dcb;
+    ddcta = -ddcb;
+    // ctb =0;
+    dctb=0;    
+    ddctb=0;    
+  }    
+ else
+  if (TgB()){
+    Real8 t = 1-theta;
+    //ca = t*t;
+    dca = -2*t;
+    ddca = 2;
+    //cb = 1-ca;
+    dcb = -dca;
+    ddcb = -2;
+    //ctb= -t+ca;
+    dctb = 1+dca;
+    ddctb= ddca;
+    //cta=0;    
+    dcta =0;
+    ddcta =0;
+   }
+  else {t=B-A;return 0;} // lagrange P1
+  R2 d =  A*dca + B*dcb + tg[0]* dcta + tg[1] * dctb;
+  
+  R2 dd =  A*ddca + B*ddcb + tg[0]* ddcta + tg[1] * ddctb;
+  Real8 d2=(d,d);
+  Real8 sd2 = sqrt(d2);
+  t=d;
+  if(d2>1.0e-20) {t/=sd2;return Abs(Det(d,dd))/(d2*sd2);}
+  else return 0;
+
+}
+
+
+R2 GeometricalEdge::F(Real8 theta) const // parametrization of the curve edge
+{ R2 A=v[0]->r,B=v[1]->r;
+ Real8 ca,cb,cta,ctb;
+ assert( theta >=-1e-12);
+ assert( theta <=1+1e-12);
+ if (TgA()) 
+  if (TgB()) // interpolation d'hermite
+   { cb =  theta*theta*(3-2*theta);
+     ca =  1-cb;     
+     cta = (1-theta)*(1-theta)*theta;
+     ctb = (theta-1)*theta*theta ;
+   //  if(ref==4 || ref==5)
+   //  cout << " FFF " << tg[0] << tg[1] << A << B << " => " << A*ca + B*cb + tg[0]* cta + tg[1] * ctb << endl;
+    }
+  else { // 1-t*t, t-t*t, t*t
+    Real8 t = theta;
+    cb = t*t;
+    ca = 1-cb;
+    cta= t-cb;
+    ctb=0;    
+  }    
+ else
+  if (TgB()){
+    Real8 t = 1-theta;
+    ca = t*t;
+    cb = 1-ca;
+    ctb= -t+ca;
+    cta=0;    
+   }
+  else {
+      ca =(1-theta),cb = theta,cta=ctb=0; // lagrange P1
+   }
+ return A*ca + B*cb + tg[0]* cta + tg[1] * ctb;
+
+}
+
+}
diff --git a/contrib/bamg/bamglib/MeshQuad.cpp b/contrib/bamg/bamglib/MeshQuad.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..a890a38a874f2654cd32aa15e263069c91266306
--- /dev/null
+++ b/contrib/bamg/bamglib/MeshQuad.cpp
@@ -0,0 +1,943 @@
+// -*- Mode : c++ -*-
+//
+// SUMMARY  :      
+// USAGE    :        
+// ORG      : 
+// AUTHOR   : Frederic Hecht
+// E-MAIL   : hecht@ann.jussieu.fr
+//
+// ********** DO NOT REMOVE THIS BANNER **********
+/*
+ 
+ This file is part of Freefem++
+ 
+ Freefem++ is free software; you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+ 
+ Freefem++  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 Lesser General Public License for more details.
+ 
+ You should have received a copy of the GNU Lesser General Public License
+ along with Freefem++; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+//
+// SUMMARY: Bamg: Bidimensional Anisotrope Mesh Generator
+// RELEASE: 0 
+// AUTHOR:   F. Hecht,    
+// ORG    :  UMPC
+// E-MAIL :   Frederic.Hecht@Inria.fr   
+//
+// ORIG-DATE:     frev 98
+//---------------------------------------------------------
+//  to make quad 
+// -------------------
+
+#include <stdio.h>
+#include <string.h>
+#include <math.h>
+#include <time.h>
+
+#include "Meshio.h"
+#include "Mesh2.h"
+#include "QuadTree.h"
+#include "SetOfE4.h"
+
+namespace bamg {
+
+static const  Direction NoDirOfSearch=Direction();
+
+#ifdef __MWERKS__
+#pragma global_optimizer on
+#pragma optimization_level 1
+//#pragma inline_depth 0
+#endif
+
+class DoubleAndInt4 {
+public: double q; Int4 i3j;
+  int operator<(DoubleAndInt4 a){return q > a.q;}
+};// to sort by decroissant
+
+
+
+template<class T>  inline void  HeapSort(T *c,long n)
+{
+  long l,j,r,i;
+  T crit;
+  c--; // on decale de 1 pour que le tableau commence a 1
+  if( n <= 1) return;
+  l = n/2 + 1;
+  r = n;
+  while (1) { // label 2
+    if(l <= 1 ) { // label 20
+      crit = c[r];
+      c[r--] = c[1];
+    if ( r == 1 ) { c[1]=crit; return;}
+    } else  crit = c[--l]; 
+    j=l;
+    while (1) {// label 4
+      i=j;
+      j=2*j;
+      if  (j>r) {c[i]=crit;break;} // L8 -> G2
+      if ((j<r) && (c[j] < c[j+1])) j++; // L5
+      if (crit < c[j]) c[i]=c[j]; // L6+1 G4
+      else {c[i]=crit;break;} //L8 -> G2
+    }
+  }
+}
+
+Triangle * swapTest(Triangle *t1,Int2 a);
+// 
+
+
+double QuadQuality(const Vertex & a,const Vertex &b,const Vertex &c,const Vertex &d)
+{
+  // calcul de 4 angles --
+  R2 A((R2)a),B((R2)b),C((R2)c),D((R2)d);
+  R2 AB(B-A),BC(C-B),CD(D-C),DA(A-D);
+  //  Move(A),Line(B),Line(C),Line(D),Line(A);
+  const Metric & Ma  = a;
+  const Metric & Mb  = b;
+  const Metric & Mc  = c;
+  const Metric & Md  = d;
+    
+  double lAB=Norme2(AB);
+  double lBC=Norme2(BC);
+  double lCD=Norme2(CD);
+  double lDA=Norme2(DA);
+  AB /= lAB;  BC /= lBC;  CD /= lCD;  DA /= lDA;
+  // version aniso 
+  double cosDAB= Ma(DA,AB)/(Ma(DA)*Ma(AB)),sinDAB= Det(DA,AB);
+  double cosABC= Mb(AB,BC)/(Mb(AB)*Mb(BC)),sinABC= Det(AB,BC);
+  double cosBCD= Mc(BC,CD)/(Mc(BC)*Mc(CD)),sinBCD= Det(BC,CD);
+  double cosCDA= Md(CD,DA)/(Md(CD)*Md(DA)),sinCDA= Det(CD,DA);
+  double sinmin=Min(Min(sinDAB,sinABC),Min(sinBCD,sinCDA));
+  // cout << A << B << C << D ;
+  // cout << " sinmin " << sinmin << " " << cosDAB << " " << cosABC << " " << cosBCD << " " << cosCDA << endl;
+  // rattente(1);
+  if (sinmin<=0) return sinmin;
+  return 1.0-Max(Max(Abs(cosDAB),Abs(cosABC)),Max(Abs(cosBCD),Abs(cosCDA)));
+}
+
+ GeometricalEdge *   Triangles::ProjectOnCurve( Edge & BhAB, Vertex &  vA, Vertex & vB,
+						Real8 theta,
+						Vertex & R,VertexOnEdge &  BR,VertexOnGeom & GR) 
+                      
+{
+   void *pA=0,*pB=0;
+   Real8 tA=0,tB=0;
+   R2 A=vA,B=vB;
+    Vertex * pvA=&vA, * pvB=&vB;
+  if (vA.vint == IsVertexOnVertex)
+    {
+      //  cout << " Debut vertex = " << BTh.Number(vA.onbv) ;
+      pA=vA.onbv;
+    }
+  else if (vA.vint == IsVertexOnEdge)
+    {
+      pA=vA.onbe->be;
+      tA=vA.onbe->abcisse;
+      // cout << " Debut edge = " << BTh.Number(vA.onbv) << " " << tA ;
+
+    }
+  else
+    {cerr << "ProjectOnCurve On Vertex " << BTh.Number(vA) << " " << endl;
+     cerr << " forget call to SetVertexFieldOnBTh" << endl;
+     MeshError(-1);
+    } 
+    
+  if (vB.vint == IsVertexOnVertex)
+    {
+      // cout << " Fin vertex = " << BTh.Number(vB.onbv) << endl;
+      pB=vB.onbv;
+    }
+  else if(vB.vint == IsVertexOnEdge)
+    {
+      pB=vB.onbe->be;
+      tB=vB.onbe->abcisse;
+      // cout << " Fin edge = " << BTh.Number(vB.onbe->be) << " " <<  tB ;
+
+    }
+  else
+    {cerr << "ProjectOnCurve On Vertex " << BTh.Number(vB) << " " << endl;
+     cerr << " forget call to SetVertexFieldOnBTh" << endl;
+     MeshError(-1);
+    } 
+  Edge * e = &BhAB;
+ assert( pA && pB && e);
+ // be carefull the back ground edge e is on same geom edge 
+ // of the initiale edge def by the 2 vertex A B;
+ assert(e>=BTh.edges && e<BTh.edges+BTh.nbe);// Is a background Mesh;   
+// walk on BTh edge 
+ //assert(0 /* not finish ProjectOnCurve with BackGround Mesh*/);
+// 1 first find a back ground edge contening the vertex A
+// 2 walk n back gound boundary to find the final vertex B
+
+
+#ifdef DEBUG
+// we suppose if the vertex A is on a background edge and
+// the abcisse is 0 or 1 when the related point is not
+// a end of curve <=>  !IsRequiredVertex
+    if (vA.vint == IsVertexOnEdge)
+      if (tA<=0)
+	assert(! (*vA.onbe->be)[0].on->IsRequiredVertex());
+      else if (tA>=1) 
+      	assert(!(*vA.onbe->be)[1].on->IsRequiredVertex());
+#endif
+
+     if( vA.vint == IsVertexOnEdge) 
+       { // find the start edge 
+	     e = vA.onbe->be;	 
+
+       } 
+     else if (vB.vint == IsVertexOnEdge) 
+       {
+         theta = 1-theta;
+	 Exchange(tA,tB);
+	 Exchange(pA,pB);
+	 Exchange(pvA,pvB);
+	 Exchange(A,B);
+	 e =  vB.onbe->be;
+
+	 // cout << " EXCHANGE  A et B) " << endl;
+       } 
+     else
+       { // do the search by walking 
+	 assert(0 /* A FAIRE */);
+       }
+
+     // find the direction of walking with sens of edge and pA,PB;
+   R2 AB=B-A;
+
+   Real8 cosE01AB = (( (R2) (*e)[1] - (R2) (*e)[0] ) , AB);
+   int kkk=0;
+   int sens = (cosE01AB>0) ? 1 : 0;
+ 
+   //   Real8 l=0; // length of the edge AB
+   Real8 abscisse = -1;
+ 
+   for (int cas=0;cas<2;cas++)
+     {// 2 times algo:
+       //    1 for computing the length l
+       //    2 for find the vertex 
+       int  iii;
+        Vertex  *v0=pvA,*v1; 
+       Edge *neee,*eee;
+       Real8 lg =0; // length of the curve 
+       Real8 te0;
+       // we suppose take the curve's abcisse 
+       // cout << kkk << " e = " << BTh.Number(e) << "  v0=  " 
+       //    << BTh.Number(v0) << " v1 = " << BTh.Number((*e)[sens]) << endl;
+       for ( eee=e,iii=sens,te0=tA;
+             eee && ((( void*) eee) != pB) && (( void*) (v1=&((*eee)[iii]))) != pB ;
+             neee = eee->adj[iii],iii = 1-neee->Intersection(*eee),eee = neee,v0=v1,te0=1-iii )   
+	      { 
+		//	cout << kkk << " eee = " << BTh.Number(eee) << "  v0=  " 
+		//     << BTh.Number(v0) << " v1 = " << BTh.Number(v1) << endl;
+		
+		assert(kkk++<100);
+		assert(eee);
+		Real8 lg0 = lg;
+		Real8 dp = LengthInterpole(v0->m,v1->m,(R2) *v1 - (R2) *v0);
+	     	lg += dp;
+		if (cas && abscisse <= lg)
+		  { // ok we find the geom edge 
+		    Real8 sss  =   (abscisse-lg0)/dp;
+		    Real8 thetab = te0*(1-sss)+ sss*iii;
+		    assert(thetab>=0 && thetab<=1);
+		    BR = VertexOnEdge(&R,eee,thetab);
+
+		    // cout << Number(R) << " = " <<  thetab << " on  " <<  BTh.Number(eee)
+		    //	 << " = " << R << endl;
+
+		    return  Gh.ProjectOnCurve(*eee,thetab,R,GR);
+
+		  }
+	      }
+       // we find the end 
+       if (v1 != pvB) 
+	 {
+	   if (( void*) v1 == pB)
+	      tB = iii;
+	     
+	   Real8 lg0 = lg;
+	   assert(eee);
+	   v1 = pvB;
+	   Real8 dp = LengthInterpole(v0->m,v1->m,(R2) *v1 - (R2) *v0);
+	   lg += dp;	
+	   abscisse = lg*theta;
+	   if (abscisse <= lg && abscisse >= lg0 ) // small optimisation we know the lenght because end
+	     { // ok we find the geom edge 
+	       Real8 sss  =   (abscisse-lg0)/dp;
+	       Real8 thetab = te0*(1-sss)+ sss*tB;
+	       assert(thetab>=0 && thetab<=1);
+	       BR = VertexOnEdge(&R,eee,thetab);
+	      
+	       //	cout << kkk << " eee = " << BTh.Number(eee) << "  v0=  " 
+	       //     << BTh.Number(v0) << " " << te0
+	       //      << " v1 = " << BTh.Number(v1) <<  " " << tB  << endl;
+
+	       //out << Number(R) << " Opt  = " <<  thetab << " on  " <<  BTh.Number(eee) 
+	       //	    << " = " << R << endl;
+
+	       return  Gh.ProjectOnCurve(*eee,thetab,R,GR);
+	     }
+	 }
+       abscisse = lg*theta;
+       
+     }
+   cerr << " Big Bug" << endl;
+   MeshError(678);
+   return 0; // just for the compiler 
+      
+}                  
+
+
+void Triangles::MakeQuadrangles(double costheta)
+{
+  if (verbosity>2) 
+    cout << "  -- MakeQuadrangles costheta = " << costheta << endl;
+  if (verbosity>5)  
+    cout << "    (in)  Nb of Quadrilaterals = " << NbOfQuad 
+	 << " Nb Of Triangles = " << nbt-NbOutT- NbOfQuad*2 
+         << " Nb of outside triangles = " << NbOutT << endl;
+
+  if (costheta >1) {
+    if (verbosity>5)
+      cout << "     do nothing costheta >1 "<< endl;
+    return;}
+
+  
+  Int4 nbqq = (nbt*3)/2;
+  DoubleAndInt4  *qq = new DoubleAndInt4[nbqq];
+
+  Int4 i,ij;
+  int j;
+  Int4 k=0;
+  for (i=0;i<nbt;i++)
+    for (j=0;j<3;j++)
+      if ((qq[k].q=triangles[i].QualityQuad(j))>=costheta)
+ 	   qq[k++].i3j=i*3+j;
+//  sort  qq
+  HeapSort(qq,k);
+  
+  Int4 kk=0;
+  for (ij=0;ij<k;ij++)
+    { 
+      //      cout << qq[ij].q << " " << endl;
+      i=qq[ij].i3j/3;
+      j=(int) (qq[ij].i3j%3);
+      // optisamition no float computation  
+      if (triangles[i].QualityQuad(j,0) >=costheta) 
+        triangles[i].SetHidden(j),kk++;
+    }
+  NbOfQuad = kk;
+  if (verbosity>2) 
+    {
+    cout << "    (out)  Nb of Quadrilaterals = " << NbOfQuad 
+	 << " Nb Of Triangles = " << nbt-NbOutT- NbOfQuad*2 
+         << " Nb of outside triangles = " << NbOutT << endl;
+    }
+  delete [] qq;
+#ifdef DRAWING2 
+  Draw();
+  inquire();
+#endif
+
+}
+/*
+Triangles::BThBoundary(Edge e,Real 8) const 
+{
+  // pointeur of the background must be on 
+  // 
+  Edge be = e.on;
+}
+*/
+int  Triangles::SplitElement(int choice)
+{
+  Direction NoDirOfSearch;
+  const  int withBackground = &BTh != this && &BTh;
+ if (verbosity>2) 
+   cout << "  -- SplitElement " << (choice? " Q->4Q and T->4T " : " Q->4Q or T->3Q " ) << endl;;
+ if (verbosity>5)
+   cout << endl << "    (in)  Nb of Quadrilaterals = " << NbOfQuad 
+	<< " Nb Of Triangles = " << nbt-NbOutT- NbOfQuad*2 
+	<< " Nb of outside triangles = " << NbOutT << endl;
+ 
+ ReNumberingTheTriangleBySubDomain();
+#ifdef DRAWING2 
+  Draw();
+ inquire();
+#endif
+ //int nswap =0;
+  const Int4 nfortria( choice ? 4 : 6);
+    if(withBackground) 
+    {
+      BTh.SetVertexFieldOn();
+      SetVertexFieldOnBTh();
+    }
+   else
+     BTh.SetVertexFieldOn();
+   
+  Int4 newnbt=0,newnbv=0;
+  Int4 * kedge = 0;
+ Int4 newNbOfQuad=NbOfQuad;
+  Int4 * ksplit= 0, * ksplitarray=0;
+  Int4 kkk=0;
+  int ret =0;
+  if (nbvx<nbv+nbe) return 1;//   
+  Triangles *  OCurrentTh= CurrentTh;
+  CurrentTh = this;
+  // 1) create  the new points by spliting the internal edges 
+  // set the 
+  Int4 nbvold = nbv;
+  Int4 nbtold = nbt;
+  Int4 NbOutTold  = NbOutT;
+  Int4  NbEdgeOnGeom=0;
+  Int4 i;
+  
+  nbt = nbt - NbOutT; // remove all the  the ouside triangles 
+  Int4 nbtsave = nbt;
+  Triangle * lastT = triangles + nbt;
+  for (i=0;i<nbe;i++)
+    if(edges[i].on) NbEdgeOnGeom++;
+  Int4 newnbe=nbe+nbe;
+  //  Int4 newNbVerticesOnGeomVertex=NbVerticesOnGeomVertex;
+  Int4 newNbVerticesOnGeomEdge=NbVerticesOnGeomEdge+NbEdgeOnGeom;
+  // Int4 newNbVertexOnBThVertex=NbVertexOnBThVertex;
+  Int4 newNbVertexOnBThEdge=withBackground ? NbVertexOnBThEdge+NbEdgeOnGeom:0;
+
+  // do allocation for pointeur to the geometry and background
+  VertexOnGeom * newVerticesOnGeomEdge = new VertexOnGeom[newNbVerticesOnGeomEdge];
+  VertexOnEdge *newVertexOnBThEdge = newNbVertexOnBThEdge ?  new VertexOnEdge[newNbVertexOnBThEdge]:0;
+  if (NbVerticesOnGeomEdge)
+    memcpy(newVerticesOnGeomEdge,VerticesOnGeomEdge,sizeof(VertexOnGeom)*NbVerticesOnGeomEdge);
+  if (NbVertexOnBThEdge)
+    memcpy(newVertexOnBThEdge,VertexOnBThEdge,sizeof(VertexOnEdge)*NbVertexOnBThEdge);
+  Edge *newedges = new Edge [newnbe];
+  //  memcpy(newedges,edges,sizeof(Edge)*nbe);
+  SetOfEdges4 * edge4= new SetOfEdges4(nbe,nbv);
+#ifdef DEBUG
+  for (i=0;i<nbt;i++)
+    triangles[i].check();
+#endif
+#ifdef DRAWING2  
+  reffecran();
+#endif  
+  Int4 k=nbv;
+  Int4 kk=0;
+  Int4 kvb = NbVertexOnBThEdge;
+  Int4 kvg = NbVerticesOnGeomEdge;
+  Int4 ie =0;
+  Edge ** edgesGtoB=0;
+  if (withBackground)
+   edgesGtoB= BTh.MakeGeometricalEdgeToEdge();
+  Int4 ferr=0;
+  for (i=0;i<nbe;i++)
+     newedges[ie].on=0;
+
+  for (i=0;i<nbe;i++)
+    {
+      GeometricalEdge *ong =  edges[i].on;
+
+      newedges[ie]=edges[i];
+      newedges[ie].adj[0]=newedges+(edges[i].adj[0]-edges) ;
+      newedges[ie].adj[1]=newedges + ie +1;
+      R2 A = edges[i][0],B = edges[i][1];
+      // cout << " ie = " << ie <<"  v0 = " <<  Number(newedges[ie][0]) << endl;
+
+
+      kk += (i == edge4->addtrie(Number(edges[i][0]),Number(edges[i][1])));
+      if (ong) // a geometrical edges 
+	{ 
+	  if (withBackground)
+	    {
+	      // walk on back ground mesh 
+	      //  newVertexOnBThEdge[ibe++] = VertexOnEdge(vertices[k],bedge,absicsseonBedge); 
+	      // a faire -- difficile 
+	      // the first PB is to now a background edge between the 2 vertices
+	      assert(edgesGtoB); 
+	      // cout << " ie = " << ie <<"  v0 = " <<  Number(newedges[ie][0]) << endl;
+             ong= ProjectOnCurve(*edgesGtoB[Gh.Number(edges[i].on)],
+			     edges[i][0],edges[i][1],0.5,vertices[k],
+                             newVertexOnBThEdge[kvb],
+                             newVerticesOnGeomEdge[kvg++]);
+	     vertices[k].ReferenceNumber= edges[i].ref;
+	     vertices[k].DirOfSearch =   NoDirOfSearch;        
+;
+	     // get the Info on background mesh 
+	     Real8 s =        newVertexOnBThEdge[kvb];
+	     Vertex &  bv0  = newVertexOnBThEdge[kvb][0];
+	     Vertex &  bv1  = newVertexOnBThEdge[kvb][1];
+	     // compute the metrix of the new points 
+	     vertices[k].m =  Metric(1-s,bv0,s,bv1); 
+	     kvb++;
+	     // cout << " ie = " << ie <<"  v0 = " <<  Number(newedges[ie][0]) << endl;
+	    }
+	  else 
+	    {
+	      ong=Gh.ProjectOnCurve(edges[i],
+				    0.5,vertices[k],newVerticesOnGeomEdge[kvg++]);
+	      // vertices[k].i = toI2( vertices[k].r);
+	      vertices[k].ReferenceNumber = edges[i].ref;
+	      vertices[k].DirOfSearch = NoDirOfSearch;
+	      vertices[k].m =  Metric(0.5,edges[i][0],0.5,edges[i][1]);	      
+	    }  
+	}
+      else // straigth line edge ---
+	{ 
+	  vertices[k].r = ((R2) edges[i][0] + (R2)  edges[i][1] )*0.5;
+	  vertices[k].m =  Metric(0.5,edges[i][0],0.5,edges[i][1]);
+	  vertices[k].on = 0;
+	}
+      //vertices[k].i = toI2( vertices[k].r);
+      R2 AB =  vertices[k].r;
+      R2 AA = (A+AB)*0.5;
+      R2 BB = (AB+B)*0.5;
+      vertices[k].ReferenceNumber = edges[i].ref;
+	    vertices[k].DirOfSearch = NoDirOfSearch;
+	    
+      newedges[ie].on = Gh.Contening(AA,ong);
+      newedges[ie++].v[1]=vertices+k;
+
+      newedges[ie]=edges[i];
+      newedges[ie].adj[0]=newedges + ie -1;
+      newedges[ie].adj[1]=newedges+(edges[i].adj[1]-edges) ;
+      newedges[ie].on =  Gh.Contening(BB,ong);
+      newedges[ie++].v[0]=vertices+k;
+      // cout << " ie = " << ie-2 << " vm " << k << " v0 = " <<  Number(newedges[ie-2][0])
+      //	   << " v1 = " << Number(newedges[ie-1][1])  
+      //	   << " ong =" << ong-Gh.edges 
+      //	   << " on 0 =" <<  newedges[ie-2].on -Gh.edges << AA
+      //	   << " on 1 =" <<  newedges[ie-1].on -Gh.edges << BB 
+      //	   << endl;
+      k++;
+    }
+#ifdef DEBUG
+  assert(kvb ==  newNbVertexOnBThEdge);
+  // verif edge 
+  { Vertex *v0 = vertices, *v1 = vertices+ k;
+    for (Int4  i=0;i<ie;i++)
+     {
+       assert( &newedges[i][0] >= v0 &&  &newedges[i][0] < v1);
+       assert( &newedges[i][1] >= v0 &&  &newedges[i][1] < v1);
+     }
+  }
+#endif
+  if (edgesGtoB) delete [] edgesGtoB;
+  edgesGtoB=0;
+
+  newnbv=k;
+  newNbVerticesOnGeomEdge=kvg;
+  if (newnbv> nbvx) goto Error;// bug 
+    
+  nbv = k;
+
+
+  kedge = new Int4[3*nbt+1];
+  ksplitarray = new Int4[nbt+1];
+  ksplit = ksplitarray +1; // because ksplit[-1] == ksplitarray[0]
+ 
+  for (i=0;i<3*nbt;i++)
+    kedge[i]=-1;
+
+  //  
+
+ for (i=0;i<nbt;i++)
+   {  
+
+     Triangle & t = triangles[i];
+     assert(t.link);
+     for(int j=0;j<3;j++)
+       {
+	 const TriangleAdjacent ta = t.Adj(j);
+	 const Triangle & tt = ta;
+	 if (&tt >= lastT)
+	   t.SetAdj2(j,0,0);// unset adj
+	 const Vertex & v0 = t[VerticesOfTriangularEdge[j][0]];
+	 const Vertex & v1 = t[VerticesOfTriangularEdge[j][1]];
+	 Int4  ke =edge4->findtrie(Number(v0),Number(v1));
+	 if (ke>0) 
+	   {
+	     Int4 ii = Number(tt);
+	     int  jj = ta;
+	     Int4 ks = ke + nbvold;
+	     kedge[3*i+j] = ks;
+	     if (ii<nbt) // good triangle
+	       kedge[3*ii+jj] = ks;
+	     Vertex &A=vertices[ks];
+	     Real8 aa,bb,cc,dd;
+	     if ((dd=Area2(v0.r,v1.r,A.r)) >=0)
+	       { // warning PB roundoff error 
+		 if (t.link && ( (aa=Area2( A.r    , t[1].r , t[2].r )) < 0.0 
+				||   (bb=Area2( t[0].r , A.r    , t[2].r )) < 0.0  
+				||   (cc=Area2( t[0].r , t[1].r , A.r    )) < 0.0))
+		   ferr++, cerr << " Error : " <<  ke + nbvold << " not in triangle " 
+				<< i << " In=" << !!t.link
+				<< " " <<  aa  << " " << bb << " " << cc << " " << dd << endl;
+		 
+	       }
+	     
+	     else
+	       {
+		 if (tt.link && ( (aa=Area2( A.r     , tt[1].r , tt[2].r )) < 0 
+				 ||   (bb=Area2( tt[0].r , A.r     , tt[2].r )) < 0 
+				 ||   (cc=Area2( tt[0].r , tt[1].r , A.r     )) < 0)) 
+		   ferr++, cerr << " Warning : " <<  ke + nbvold << " not in triangle " << ii 
+				<< " In=" << !!tt.link 
+				<< " " <<  aa  << " " << bb << " " << cc << " " << dd << endl;
+				
+	       } 
+	     
+	   }
+       }
+   }
+  if(ferr)
+    {
+      cerr << " Number of triangles with P2 interpolation Probleme " << ferr << endl;;
+      MeshError(9);
+    }
+
+  for (i=0;i<nbt;i++)
+    {
+      ksplit[i]=1; // no split by default
+      const Triangle & t = triangles[ i];
+      // cout << " Triangle " << i << " " << t  << !!t.link << ":: " ;
+      int nbsplitedge =0;
+      int nbinvisible =0;
+      int invisibleedge=0;
+      int kkk[3];      
+      for (int j=0;j<3;j++)
+	{
+	  if (t.Hidden(j)) invisibleedge=j,nbinvisible++;
+	  
+	  const TriangleAdjacent ta = t.Adj(j);
+	  const Triangle & tt = ta;
+
+	  
+	  const Vertex & v0 = t[VerticesOfTriangularEdge[j][0]];
+	  const Vertex & v1 = t[VerticesOfTriangularEdge[j][1]];
+	 //  cout << " ke = " << kedge[3*i+j]  << " " << Number(v0) << " " << Number(v1) << "/ ";
+	  if ( kedge[3*i+j] < 0) 
+	    {
+	      Int4  ke =edge4->findtrie(Number(v0),Number(v1));
+	      //  cout << ":" << ke << "," << !!t.link << " " <<  &tt ;
+	      if (ke<0) // new 
+		{
+		  if (&tt) // internal triangles all the boundary 
+		      { // new internal edges 
+			Int4 ii = Number(tt);
+			int  jj = ta;
+	      
+			kedge[3*i+j]=k;// save the vertex number 
+			kedge[3*ii+jj]=k;
+			if (k<nbvx) 
+			  {
+			    vertices[k].r = ((R2) v0+(R2) v1 )/2;
+			    //vertices[k].i = toI2( vertices[k].r);
+			    vertices[k].ReferenceNumber=0;
+	        vertices[k].DirOfSearch =NoDirOfSearch;
+			    vertices[k].m =  Metric(0.5,v0,0.5,v1);
+			  }
+			k++;
+			kkk[nbsplitedge++]=j;		      
+		    } // tt 
+		  else
+		    cerr <<endl <<  " Bug " <<i<< " " << j << " t=" << t << endl;
+		  
+		} // ke<0	       
+	      else
+		{ // ke >=0
+		  kedge[3*i+j]=nbvold+ke;
+		  kkk[nbsplitedge++]=j;// previously splited
+		}
+	    }
+	  else 
+	    kkk[nbsplitedge++]=j;// previously splited
+	  
+	} 
+      assert (nbinvisible<2);
+     // cout << " " <<  nbinvisible << " " <<  nbsplitedge << endl;
+      switch (nbsplitedge) {
+      case 0: ksplit[i]=10; newnbt++; break;   // nosplit
+      case 1: ksplit[i]=20+kkk[0];newnbt += 2; break; // split in 2 
+      case 2: ksplit[i]=30+3-kkk[0]-kkk[1];newnbt += 3; break; // split in 3 
+      case 3:
+	if (nbinvisible) ksplit[i]=40+invisibleedge,newnbt += 4;
+	else   ksplit[i]=10*nfortria,newnbt+=nfortria;
+	break;
+      } 
+    assert(ksplit[i]>=40);
+    }
+  //  now do the element split
+  newNbOfQuad = 4*NbOfQuad;
+  nbv = k;
+#ifdef DRAWING2  
+  inquire();
+#endif  
+//  cout << " Nbv = " << nbv << endl;
+  kkk = nbt;
+  ksplit[-1] = nbt;
+  // look on  old true  triangles 
+
+  for (i=0;i<nbtsave;i++)
+    {
+      //     cout << "Triangle " << i << " " << ksplit[i] << ":" << triangles[i]
+      //	   << "  ----------------------------------------------- " <<endl;
+      // Triangle * tc=0;
+      int  nbmkadj=0;
+      Int4 mkadj [100];
+      mkadj[0]=i;
+      Int4 kk=ksplit[i]/10;
+      int  ke=(int) (ksplit[i]%10);
+      assert(kk<7 && kk >0);
+      
+      // def the numbering   k (edge) i vertex 
+      int k0 = ke;
+      int k1 = NextEdge[k0];
+      int k2 = PreviousEdge[k0];
+      int i0 = OppositeVertex[k0];
+      int i1 = OppositeVertex[k1];
+      int i2 = OppositeVertex[k2];
+       
+       Triangle &t0=triangles[i];
+       Vertex * v0=t0(i0);           
+       Vertex * v1=t0(i1);           
+       Vertex * v2=t0(i2);
+
+       // cout << "nbmkadj " << nbmkadj << " it=" << i <<endl;
+       assert(nbmkadj< 10);
+       // --------------------------
+       TriangleAdjacent ta0(t0.Adj(i0)),ta1(t0.Adj(i1)),ta2(t0.Adj(i2));
+       // save the flag Hidden
+       int hid[]={t0.Hidden(0),t0.Hidden(1),t0.Hidden(2)};
+       // un set all adj -- save Hidden flag --
+       t0.SetAdj2(0,0,hid[0]);
+       t0.SetAdj2(1,0,hid[1]);
+       t0.SetAdj2(2,0,hid[2]);
+       // --  remake 
+       switch  (kk) {
+       case 1: break;// nothing 
+       case 2: // 
+	 {
+	   Triangle &t1=triangles[kkk++];
+	   t1=t0;
+	   assert (kedge[3*i+i0]>=0);
+	   Vertex * v3 = vertices + kedge[3*i+k0];
+	   
+	   t0(i2) = v3;
+	   t1(i1) = v3;
+	   t0.SetAllFlag(k2,0);
+	   t1.SetAllFlag(k1,0);
+	 } 
+	 break; 
+       case 3: //
+	 {
+	   Triangle &t1=triangles[kkk++];
+            Triangle &t2=triangles[kkk++];
+            t2=t1=t0;
+            assert (kedge[3*i+k1]>=0);
+            assert (kedge[3*i+k2]>=0);
+            
+            Vertex * v01 = vertices + kedge[3*i+k2];
+            Vertex * v02 = vertices + kedge[3*i+k1]; 
+            t0(i1) = v01; 
+            t0(i2) = v02; 
+            t1(i2) = v02;
+            t1(i0) = v01; 
+            t2(i0) = v02; 
+	    t0.SetAllFlag(k0,0);
+	    t1.SetAllFlag(k1,0);
+	    t1.SetAllFlag(k0,0);
+	    t2.SetAllFlag(k2,0);
+	 } 
+	 break;
+       case 4: // 
+       case 6: // split in 4 
+	 {
+	   Triangle &t1=triangles[kkk++];
+	   Triangle &t2=triangles[kkk++];
+	   Triangle &t3=triangles[kkk++];
+	   t3=t2=t1=t0;
+	   assert(kedge[3*i+k0] >=0 && kedge[3*i+k1] >=0 && kedge[3*i+k2] >=0);
+	   Vertex * v12 = vertices + kedge[3*i+k0];
+	   Vertex * v02 = vertices + kedge[3*i+k1]; 
+	   Vertex * v01 = vertices + kedge[3*i+k2];
+	   // cout << Number(t0(i0))  << " " << Number(t0(i1)) 
+	   //     << " " <<  Number(t0(i2)) 
+	   //     << " " <<  kedge[3*i+k0] 
+	   //     << " " <<  kedge[3*i+k1] 
+	   //     << " " <<  kedge[3*i+k2] << endl;
+	   t0(i1) = v01;
+	   t0(i2) = v02;
+	   t0.SetAllFlag(k0,hid[k0]);
+
+	   t1(i0) = v01;
+	   t1(i2) = v12;
+	   t0.SetAllFlag(k1,hid[k1]);
+	   
+	   t2(i0) = v02;
+	   t2(i1) = v12;
+	   t2.SetAllFlag(k2,hid[k2]);
+	   
+	   t3(i0) = v12;
+	   t3(i1) = v02;
+	   t3(i2) = v01;
+	   	   
+	   t3.SetAllFlag(0,hid[0]);	   
+	   t3.SetAllFlag(1,hid[1]);	   
+	   t3.SetAllFlag(2,hid[2]);
+
+	   if ( kk == 6)
+	     {
+	       
+	       Triangle &t4=triangles[kkk++];
+	       Triangle &t5=triangles[kkk++];
+	       
+	       t4 = t3;
+	       t5 = t3;
+
+	       t0.SetHidden(k0);
+	       t1.SetHidden(k1);
+	       t2.SetHidden(k2);
+	       t3.SetHidden(0);
+	       t4.SetHidden(1);
+	       t5.SetHidden(2);
+	       
+		if (nbv < nbvx ) 
+		  {
+		    vertices[nbv].r = ((R2) *v01 + (R2) *v12  + (R2) *v02 ) / 3.0;
+		    vertices[nbv].ReferenceNumber =0;
+	      vertices[nbv].DirOfSearch =NoDirOfSearch;
+		    //vertices[nbv].i = toI2(vertices[nbv].r);
+		    Real8 a3[]={1./3.,1./3.,1./3.};
+		    vertices[nbv].m = Metric(a3,v0->m,v1->m,v2->m);
+		    Vertex * vc =  vertices +nbv++;
+		    t3(i0) = vc;
+		    t4(i1) = vc;
+		    t5(i2) = vc;
+
+		  }
+		else
+		  goto Error; 
+	     }
+		    
+	 } 
+	 break;         
+       }
+ 
+       // cout << "  -- " << i << " " << nbmkadj << " " << kkk << " " << tc << endl;
+       //  t0.SetDetf();
+       // save all the new triangles
+       mkadj[nbmkadj++]=i;
+       Int4 jj;
+       if (t0.link) 
+	 for (jj=nbt;jj<kkk;jj++)
+	   {
+	     triangles[jj].link=t0.link;
+	     t0.link= triangles+jj;
+	     mkadj[nbmkadj++]=jj;
+	     // triangles[jj].SetDet();
+	   }
+       // cout << "  -- " << i << " " << nbmkadj << endl;
+       assert(nbmkadj<=13);// 13 = 6 + 4 + 3
+  
+       if (kk==6)  newNbOfQuad+=3;
+	 //	 triangles[i].Draw();       
+
+       for (jj=ksplit[i-1];jj<kkk;jj++)
+	 // triangles[jj].SetDet();
+       //	   triangles[jj].Draw();
+	 
+
+
+       nbt = kkk;
+       ksplit[i]= nbt; // save last adresse of the new triangles
+       kkk = nbt;
+       
+    }
+
+//  cout << " nv = " << nbv << " nbt = " << nbt << endl;
+  for (i=0;i<nbv;i++)
+    vertices[i].m = vertices[i].m*2.;
+  //
+  if(withBackground)
+    for (i=0;i<BTh.nbv;i++)
+      BTh.vertices[i].m =  BTh.vertices[i].m*2.;
+#ifdef DRAWING2
+  Draw();
+  inquire();
+#endif
+  
+  
+  ret = 2;
+  if (nbt>= nbtx) goto Error; // bug 
+  if (nbv>= nbvx) goto Error; // bug 
+  // generation of the new triangles 
+
+  SetIntCoor("In SplitElement"); 
+
+  ReMakeTriangleContainingTheVertex();
+  if(withBackground)
+    BTh.ReMakeTriangleContainingTheVertex();
+
+  delete [] edges;
+  edges = newedges;
+  nbe = newnbe;
+  NbOfQuad = newNbOfQuad;
+
+  for (i=0;i<NbSubDomains;i++)
+    { 
+      Int4 k = subdomains[i].edge- edges;
+      subdomains[i].edge =  edges+2*k; // spilt all edge in 2 
+    }
+    
+  if (ksplitarray) delete [] ksplitarray;
+  if (kedge) delete [] kedge;
+  if (edge4) delete edge4;
+  if (VerticesOnGeomEdge) delete [] VerticesOnGeomEdge;
+  VerticesOnGeomEdge= newVerticesOnGeomEdge;
+  if(VertexOnBThEdge) delete []  VertexOnBThEdge;
+  VertexOnBThEdge = newVertexOnBThEdge;
+  NbVerticesOnGeomEdge = newNbVerticesOnGeomEdge;
+  NbVertexOnBThEdge=newNbVertexOnBThEdge;
+  //  ReMakeTriangleContainingTheVertex();
+
+  FillHoleInMesh();
+
+#ifdef DEBUG
+  for (i=0;i<nbt;i++)
+    triangles[i].check();
+#endif
+  
+ if (verbosity>2)
+   cout << "    (out) Nb of Quadrilaterals = " << NbOfQuad 
+	<< " Nb Of Triangles = " << nbt-NbOutT- NbOfQuad*2 
+	<< " Nb of outside triangles = " << NbOutT << endl;
+
+ CurrentTh=OCurrentTh;
+ return 0; //ok
+
+ Error:
+  nbv = nbvold;
+  nbt = nbtold;
+  NbOutT = NbOutTold;
+  // cleaning memory ---
+  delete newedges;
+  if (ksplitarray) delete [] ksplitarray;
+  if (kedge) delete [] kedge;
+  if (newVerticesOnGeomEdge) delete [] newVerticesOnGeomEdge;
+  if (edge4) delete edge4;
+  if(newVertexOnBThEdge) delete []  newVertexOnBThEdge;
+  
+
+  CurrentTh= OCurrentTh;
+  return ret; // ok 
+}
+
+} //  end of namespcae bamg 
diff --git a/contrib/bamg/bamglib/MeshRead.cpp b/contrib/bamg/bamglib/MeshRead.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..ade1afb6c17a5781d981c2e72f76561164f55b9b
--- /dev/null
+++ b/contrib/bamg/bamglib/MeshRead.cpp
@@ -0,0 +1,1227 @@
+// -*- Mode : c++ -*-
+//
+// SUMMARY  :      
+// USAGE    :        
+// ORG      : 
+// AUTHOR   : Frederic Hecht
+// E-MAIL   : hecht@ann.jussieu.fr
+//
+
+/*
+ 
+ This file is part of Freefem++
+ 
+ Freefem++ is free software; you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+ 
+ Freefem++  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 Lesser General Public License for more details.
+ 
+ You should have received a copy of the GNU Lesser General Public License
+ along with Freefem++; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+#include <stdio.h>
+#include <string.h>
+#include <math.h>
+#include <time.h>
+
+#include "Meshio.h"
+#include "Mesh2.h"
+#include "QuadTree.h"
+#include "SetOfE4.h"
+#ifdef __MWERKS__
+#pragma optimization_level 2
+//#pragma inline_depth 1
+#endif
+
+#ifdef DRAWING1
+  extern bool withrgraphique ;
+#endif
+
+namespace bamg {
+
+static const  Direction NoDirOfSearch=Direction();
+
+void Triangles::Read(MeshIstream & f_in,int Version,Real8 cutoffradian)
+{
+  Real8 hmin = HUGE_VAL;// the infinie value 
+  //  Real8 MaximalAngleOfCorner = 10*Pi/180;// 
+  Int4 i;
+  Int4 dim=0;
+  Int4 hvertices =0;
+  Int4 ifgeom=0;
+  Metric M1(1);
+  if (verbosity>1)
+    cout << "  -- ReadMesh " << f_in.CurrentFile  << " Version = " << Version << endl;
+  int field=0;
+  int showfield=0;
+  while (f_in.cm()) 
+    {  
+      field=0;
+      char  fieldname[256];
+      if(f_in.eof()) break;
+      f_in.cm() >> fieldname ;;
+      if(f_in.eof()) break;
+      f_in.err() ;
+      if(verbosity>9)
+	cout <<  "    " << fieldname << endl;
+      if (!strcmp(fieldname,"MeshVersionFormatted") )
+         f_in >>   Version ;
+      else if(!strcmp(fieldname,"End"))
+         break;
+      else if (!strcmp(fieldname,"Dimension"))
+         {
+           f_in >>   dim ;
+           assert(dim ==2);
+         }
+      else if  (!strcmp(fieldname,"Geometry"))
+	{ 
+	  char * fgeom ;
+	  f_in >> fgeom;
+	  //	  if (cutoffradian>=0) => bug if change edit the file geometry 
+	  //  Gh.MaximalAngleOfCorner = cutoffradian;
+	  if (strlen(fgeom))
+	      Gh.ReadGeometry(fgeom);
+	  else 
+	    { 
+	      // include geometry 
+	      f_in.cm();
+	      Gh.ReadGeometry(f_in,fgeom);
+	    }
+
+	  Gh.AfterRead();
+	  ifgeom=1;
+	  delete [] fgeom;
+	}
+      else if (!strcmp(fieldname,"Identifier"))
+	{
+	  if (identity) delete [] identity;
+	  f_in >> identity;
+	}
+      else if (!strcmp(fieldname,"hVertices"))
+         { hvertices =1;
+	   Real4 h;
+           for (i=0;i< nbv;i++) {
+            f_in >>  h ;
+	    vertices[i].m = Metric(h);}
+         }
+      else if (!strcmp(fieldname,"Vertices"))
+         { 
+           assert(dim ==2);
+           f_in >>   nbv ;
+	   if(verbosity>3)
+	     cout << "   Nb of Vertices = " << nbv << endl;
+	   nbvx=nbv;
+	   vertices=new Vertex[nbvx];
+	   assert(vertices);
+	   ordre=new (Vertex* [nbvx]);
+	   assert(ordre);
+	   
+	   nbiv = nbv;
+           for (i=0;i<nbv;i++) {
+             f_in >> 
+	       	 	 vertices[i].r.x >>  
+	           vertices[i].r.y >> 
+             vertices[i].ReferenceNumber  ;
+             vertices[i].DirOfSearch =NoDirOfSearch;
+	           vertices[i].m=M1;
+	     vertices[i].color =0;}
+	   nbtx =  2*nbv-2; // for filling The Holes and quadrilaterals 
+	   triangles =new Triangle[nbtx];
+	   assert(triangles);
+	   nbt =0;
+         }
+      else if (!strcmp(fieldname,"Triangles"))
+	{ 
+	  if (dim !=2)
+	    cerr << "ReadMesh: Dimension <> 2" <<endl , f_in.ShowIoErr(0);
+	  if(! vertices || !triangles  || !nbv )
+	    cerr << "ReadMesh:Triangles before Vertices" <<endl,
+	      f_in.ShowIoErr(0);
+	  int NbOfTria;
+	  f_in >>  NbOfTria ;
+	  if(verbosity>3)
+	    cout << "   NbOfTria = " << NbOfTria << endl;
+	  if (nbt+NbOfTria >= nbtx)
+	    cerr << "ReadMesh: We must have 2*NbOfQuad + NbOfTria  = "
+		 << nbt + NbOfTria<<"  < 2*nbv-2 ="  << nbtx << endl,
+	      f_in.ShowIoErr(0); 
+	  //	  begintria = nbt;
+	  for (i=0;i<NbOfTria;i++)  
+	    {
+	      Int4 i1,i2,i3,iref;
+	      Triangle & t = triangles[nbt++];
+	      f_in >>  i1 >>  i2 >>   i3 >>   iref ;
+	      t = Triangle(this,i1-1,i2-1,i3-1);
+	      t.color=iref;
+	    }
+	  // endtria=nbt;
+	}
+      else if (!strcmp(fieldname,"Quadrilaterals"))
+        { 
+
+	  if (dim !=2)
+	    cerr << "ReadMesh: Dimension <> 2" <<endl , f_in.ShowIoErr(0);
+	  if(! vertices || !triangles  || !nbv )
+	    cerr << "ReadMesh:Quadrilaterals before Vertices" <<endl,
+	      f_in.ShowIoErr(0);
+	  f_in >>   NbOfQuad ;
+	  if(verbosity>3)
+	    cout << "   NbOfQuad= " << NbOfQuad << endl;
+	  if (nbt+2*NbOfQuad >= nbtx)
+	    cerr << "ReadMesh: We must have 2*NbOfQuad + NbOfTria  = "
+		 << nbt + 2*NbOfQuad <<"  < 2*nbv-2 ="  << nbtx << endl,
+	      f_in.ShowIoErr(0);
+	  //  beginquad=nbt;
+	  for (i=0;i<NbOfQuad;i++)  
+	    { 
+	      Int4 i1,i2,i3,i4,iref;
+	      Triangle & t1 = triangles[nbt++];
+	      Triangle & t2 = triangles[nbt++];
+	      f_in >>  i1 >>  i2 >>   i3 >> i4 >>    iref ;
+	      t1 = Triangle(this,i1-1,i2-1,i3-1);
+	      t1.color=iref;
+	      t2 = Triangle(this,i3-1,i4-1,i1-1);
+	      t2.color=iref;
+	      t1.SetHidden(OppositeEdge[1]); // two time  because the adj was not created 
+	      t2.SetHidden(OppositeEdge[1]); 
+	    }
+	  // endquad=nbt;
+	}
+      else if (!strcmp(fieldname,"VertexOnGeometricVertex"))
+	{ 
+           f_in  >> NbVerticesOnGeomVertex ;
+ 	   if(verbosity>5)
+	     cout << "   NbVerticesOnGeomVertex = "   << NbVerticesOnGeomVertex << endl
+		  << " Gh.vertices " << Gh.vertices << endl;
+	   if( NbVerticesOnGeomVertex) 
+	     {
+	       VerticesOnGeomVertex= new  VertexOnGeom[NbVerticesOnGeomVertex] ;
+	       if(verbosity>7)
+		 cout << "   VerticesOnGeomVertex = " << VerticesOnGeomVertex << endl
+		      << "   Gh.vertices " << Gh.vertices << endl;
+	       assert(VerticesOnGeomVertex);
+	       for (Int4 i0=0;i0<NbVerticesOnGeomVertex;i0++)  
+		 { 
+		   Int4  i1,i2;
+		   //VertexOnGeom & v =VerticesOnGeomVertex[i0];
+		   f_in >>  i1 >> i2 ;
+		   VerticesOnGeomVertex[i0]=VertexOnGeom(vertices[i1-1],Gh.vertices[i2-1]);
+		 }
+	     }
+	 }
+      else if (!strcmp(fieldname,"VertexOnGeometricEdge"))
+         { 
+           f_in >>  NbVerticesOnGeomEdge ;
+ 	   if(verbosity>3)
+	     cout << "   NbVerticesOnGeomEdge = " << NbVerticesOnGeomEdge << endl;
+	   if(NbVerticesOnGeomEdge) 
+	     {
+	       VerticesOnGeomEdge= new  VertexOnGeom[NbVerticesOnGeomEdge] ;
+	       assert(VerticesOnGeomEdge);
+	       for (Int4 i0=0;i0<NbVerticesOnGeomEdge;i0++)  
+		 { 
+		   Int4  i1,i2;
+		   Real8 s;
+		   //VertexOnGeom & v =VerticesOnGeomVertex[i0];
+		   f_in >>  i1 >> i2  >> s;
+		   VerticesOnGeomEdge[i0]=VertexOnGeom(vertices[i1-1],Gh.edges[i2-1],s);
+		 }
+	     }
+         }
+      else if (!strcmp(fieldname,"Edges"))
+	{ 
+          Int4 i,j, i1,i2;
+          f_in >>  nbe ;
+          edges = new Edge[nbe];
+	  if(verbosity>5)
+	    cout << "     Record Edges: Nb of Edge " << nbe << " edges " <<  edges << endl;
+          assert(edges);
+	  Real4 *len =0;
+          if (!hvertices) 
+	    {
+	      len = new Real4[nbv];
+	      for(i=0;i<nbv;i++)
+		len[i]=0;
+	    }
+          for (i=0;i<nbe;i++) 
+	    {
+	      f_in  >> i1  >> i2  >> edges[i].ref ;
+                 
+	      assert(i1 >0 && i2 >0);
+	      assert(i1 <= nbv && i2 <= nbv);
+	      i1--;
+	      i2--;
+	      edges[i].v[0]= vertices +i1;
+	      edges[i].v[1]= vertices +i2;
+	      edges[i].adj[0]=0;
+	      edges[i].adj[1]=0;
+
+	      R2 x12 = vertices[i2].r-vertices[i1].r;
+	      Real8 l12=sqrt( (x12,x12));        
+	      if (!hvertices) {
+		vertices[i1].color++;
+		vertices[i2].color++;
+		len[i1]+= l12;
+		len[i2] += l12;}
+	      hmin = Min(hmin,l12);
+	    }
+	  // definition  the default of the given mesh size 
+          if (!hvertices) 
+	    {
+            for (i=0;i<nbv;i++) 
+	      if (vertices[i].color > 0) 
+		vertices[i].m=  Metric(len[i] /(Real4) vertices[i].color);
+	      else 
+		vertices[i].m=  Metric(hmin);
+	      delete [] len;
+	    }
+	  if(verbosity>5)
+	    cout << "     hmin " << hmin << endl;
+	  // construction of edges[].adj 
+	    for (i=0;i<nbv;i++) 
+	      vertices[i].color = (vertices[i].color ==2) ? -1 : -2;
+	    for (i=0;i<nbe;i++)
+	      for (j=0;j<2;j++) 
+		{ 
+		  Vertex *v=edges[i].v[j];
+		  Int4 i0=v->color,j0;
+		  if(i0==-1)
+		    v->color=i*2+j;
+		  else if (i0>=0) {// i and i0 edge are adjacent by the vertex v
+		    j0 =  i0%2;
+		    i0 =  i0/2;
+		    assert( v ==  edges[i0 ].v[j0]);
+		    edges[i ].adj[ j ] =edges +i0;
+		    edges[i0].adj[ j0] =edges +i ;
+		    assert(edges[i0].v[j0] == v);
+		    //	    if(verbosity>8)
+		    //  cout << " edges adj " << i0 << " "<< j0 << " <-->  "  << i << " " << j << endl;
+		      v->color = -3;}
+		}
+
+	}
+	
+/*   ne peut pas marche car il n'y a pas de flag dans les aretes du maillages
+       else if (!strcmp(fieldname,"RequiredEdges"))
+        { 
+          int i,j,n;
+          f_in  >> n ;
+
+          for (i=0;i<n;i++) {     
+            f_in  >>  j ;
+            assert( j <= nbe );
+            assert( j > 0 );
+            j--;
+            edges[j].SetRequired();  }
+      }
+*/	
+      else if (!strcmp(fieldname,"EdgeOnGeometricEdge"))
+	{ 
+	  assert(edges);
+	  int i1,i2,i,j;
+	  f_in >> i2 ;
+	  if(verbosity>3)
+	    cout << "     Record EdgeOnGeometricEdge: Nb " << i2 <<endl;
+	  for (i1=0;i1<i2;i1++)
+	    {
+	      f_in  >> i >> j ;
+	      if(!(i>0 && j >0 && i <= nbe && j <= Gh.nbe))
+		{
+		  cerr << "      Record EdgeOnGeometricEdge i=" << i << " j = " << j;
+		  cerr << " nbe = " << nbe << " Gh.nbe = " <<  Gh.nbe << endl;
+		  cerr << " We must have : (i>0 && j >0 && i <= nbe && j <= Gh.nbe) ";
+		  cerr << " Fatal error in file " << name << " line " << f_in.LineNumber << endl;
+		  MeshError(1);
+		}
+		
+		
+	      edges[i-1].on = Gh.edges + j-1;
+	    }
+	  //	  cout << "end EdgeOnGeometricEdge" << endl;
+	}
+      else if (!strcmp(fieldname,"SubDomain") || !strcmp(fieldname,"SubDomainFromMesh") )
+	{ 
+	  
+	  f_in >> NbSubDomains ;
+	  subdomains = new SubDomain [ NbSubDomains ];
+	    for (i=0;i< NbSubDomains;i++)
+	      { Int4 i3,head,sens;
+	      f_in  >>  i3 >>	head >> sens  >> subdomains[i].ref ;
+		assert (i3==3);
+		head --;
+		assert(head < nbt && head >=0);
+		subdomains[i].head = triangles+head;		
+	      }
+	}
+      else
+	{ // unkown field
+	  field = ++showfield;
+	  if(showfield==1) // just to show one time 
+	    if (verbosity>5)
+	      cout << "     Warning we skip the field " << fieldname << " at line " << f_in.LineNumber << endl;
+	}
+      showfield=field; // just to show one time 
+    }
+    
+    if (ifgeom==0)
+      {
+	if (verbosity)
+	  cout  << " ## Warning: Mesh without geometry we construct a geometry (theta =" 
+		<< cutoffradian*180/Pi << " degres )" << endl;
+	ConsGeometry(cutoffradian);	
+	Gh.AfterRead();
+      }	  
+}
+
+
+
+
+void Triangles::Read_am_fmt(MeshIstream & f_in)
+{
+  Metric M1(1);
+
+  if (verbosity>1)
+    cout << "  -- ReadMesh .am_fmt file " <<  f_in.CurrentFile  << endl;
+   	
+     Int4 i;
+     f_in.cm() >> nbv >> nbt ;
+     if (verbosity>3)
+       cout << "    nbv = " << nbv  << " nbt = " << nbt << endl;
+     f_in.eol() ;// 
+     nbvx = nbv;
+     nbtx =  2*nbv-2; // for filling The Holes and quadrilaterals 
+     triangles =new Triangle[nbtx];
+     assert(triangles);
+     vertices=new Vertex[nbvx];
+     ordre=new (Vertex* [nbvx]);
+     
+     for (     i=0;i<nbt;i++)
+       {
+	 Int4 i1,i2,i3;
+	 f_in >>  i1 >>  i2 >>   i3 ;
+	 triangles[i]  = Triangle(this,i1-1,i2-1,i3-1);	 
+       }
+      f_in.eol() ;// 
+      
+      for ( i=0;i<nbv;i++)
+	f_in >> vertices[i].r.x >>   vertices[i].r.y,
+	  vertices[i].m = M1,vertices[i].DirOfSearch =NoDirOfSearch;
+
+      f_in.eol() ;// 
+      
+      for ( i=0;i<nbt;i++)  
+	f_in >> triangles[i].color;
+      f_in.eol() ;// 
+      
+      for ( i=0;i<nbv;i++)  
+	     f_in >> vertices[i].ReferenceNumber;
+      
+      
+}
+
+////////////////////////
+
+void  Triangles::Read_am(MeshIstream &ff)
+{
+  if (verbosity>1)
+    cout << "  -- ReadMesh .am_fmt file " <<  ff.CurrentFile  << endl;
+    Metric M1(1);	
+  
+  IFortranUnFormattedFile f_in(ff);
+
+  Int4  l=f_in.Record();
+  assert(l==2*sizeof(Int4));
+  f_in >> nbv >> nbt ;
+  l=f_in.Record();
+  assert((size_t) l==nbt*sizeof(long)*4 + nbv*(2*sizeof(float)+sizeof(long)));
+  if (verbosity>3)
+    cout << "    nbv = " << nbv  << " nbt = " << nbt << endl;
+  
+  nbvx = nbv;
+  nbtx =  2*nbv-2; // for filling The Holes and quadrilaterals 
+  triangles =new Triangle[nbtx];
+  assert(triangles);
+  vertices=new Vertex[nbvx];
+  ordre=new (Vertex* [nbvx]);
+  
+
+  Int4 i;
+  for (     i=0;i<nbt;i++) {
+    long i1,i2,i3;
+    f_in >>  i1 >>  i2 >>   i3 ;
+    triangles[i]  = Triangle(this,i1-1,i2-1,i3-1); }
+  
+  for ( i=0;i<nbv;i++) {
+    float x,y;
+    f_in >> x >> y;
+    vertices[i].r.x =x;
+    vertices[i].r.y=y;
+    vertices[i].m=M1;}
+  
+  for ( i=0;i<nbt;i++) {
+    long i;
+    f_in >> i;
+    triangles[i].color=i;}
+  
+  for ( i=0;i<nbv;i++) {
+    long i;
+    f_in >> i;
+    vertices[i].ReferenceNumber=i;}
+}
+
+//////////////////////////////////
+
+void  Triangles::Read_nopo(MeshIstream & ff)
+{
+
+ if (verbosity>1)
+    cout << "  -- ReadMesh .nopo file " <<  ff.CurrentFile  << endl;
+ IFortranUnFormattedFile f_in(ff);
+ 
+ 
+ Int4  l,i,j;
+ l=f_in.Record(); 
+ l=f_in.Record();
+ f_in >> i;
+ assert(i==32);
+ Int4 niveau,netat,ntacm;
+
+ char titre[80+1],  date[2*4+1], nomcre[6*4+1], typesd[5];
+ f_in.read4(titre,20);
+ f_in.read4(date,2);
+ f_in.read4(nomcre,6);
+ f_in.read4(typesd,1);
+
+
+   f_in >> niveau>>netat>>ntacm;
+ if (strcmp("NOPO",typesd))
+   {
+     cout << " where in record  " << f_in.where() << " " << strcmp("NOPO",typesd) << endl;
+     cerr << " not a  nopo file but `" << typesd <<"`"<< " len = " << strlen(typesd) << endl;
+     cerr << (int) typesd[0] << (int) typesd[1] << (int) typesd[2] << (int) typesd[3] << (int) typesd[4] << endl;
+     cout << " nomcre :" << nomcre << endl;
+     cout << " date   :" << date << endl;
+     cout << " titre  :" << titre<< endl;
+     MeshError(112);
+   }
+ if(verbosity>2)
+   cout << "    nb de tableau associe : " << ntacm << " niveau =" << niveau << endl;
+ 
+ for (i=0;i<ntacm;i++)
+   f_in.Record();
+
+ f_in.Record();
+ f_in >> l;
+ assert(l == 27);
+ Int4 nop2[27];
+ for (i=0;i<27;i++)
+   f_in >> nop2[i];
+ Int4 ndim = nop2[0];
+ Int4 ncopnp = nop2[3];
+ Int4 ne = nop2[4];
+ Int4 ntria = nop2[7];
+ Int4 nquad = nop2[8];
+ Int4 np = nop2[21];
+ // Int4 nef = nop2[13];
+ Metric M1(1);
+ if(verbosity>2) 
+   cout << "    ndim = " << ndim << " ncopnp= " << ncopnp << " ne = " << ne 
+	<< "    ntri = " << ntria << " nquad = " << nquad << " np = " << np << endl;
+ nbv = np;
+ nbt = 2*nquad + ntria;
+ if (ne != nquad+ntria || ndim !=2 || ncopnp != 1 )
+   {
+     cerr << " not only tria & quad in nopo mesh on dim != 2 ou ncopnp != 1 " << endl;
+     MeshError(113);
+   }
+ if( nop2[24]>=0)  f_in.Record();
+  NbOfQuad = nquad;
+  nbvx = nbv;
+  nbtx =  2*nbv-2; // for filling The Holes and quadrilaterals 
+  triangles =new Triangle[nbtx];
+  assert(triangles);
+  vertices=new Vertex[nbvx];
+  ordre=new (Vertex* [nbvx]);
+
+
+ f_in >> l;
+
+  if(verbosity>9)
+    cout << " Read cnop4 nb of float  " << l << endl;
+  
+  assert(l==2*np);
+  for (i=0;i<np;i++)
+    {  float x,y;
+    f_in >>  x>> y;
+    vertices[i].r.x=x;
+    vertices[i].r.y=y;
+    vertices[i].m=M1;
+    vertices[i].DirOfSearch =NoDirOfSearch;
+
+    }
+  f_in.Record();
+  // lecture de nop5 bonjour les degats
+  f_in >> l;
+  if(verbosity>9)
+    cout << " Read nop5  nb of int4 " << l << endl;
+ Int4 k=0;
+ Int4 nbe4 =  3*ntria + 4*nquad;
+ // cout << " nbv = " << nbv << " nbe4 " << nbe4 << endl;
+ SetOfEdges4 * edge4= new SetOfEdges4(nbe4,nbv); 
+ Int4 * refe = new Int4[nbe4];
+ Int4 kr =0;
+ for (i=0;i<ne;i++)
+   {
+     // Int4 ng[4]={0,0,0,0};
+     Int4 np[4],rv[4],re[4];
+     Int4 ncge,nmae,ndsde,npo;
+     f_in >> ncge >> nmae >> ndsde >> npo ;
+     //cout << " element " << i << " " << ncge << " "  
+     // << nmae <<" " <<  npo << endl;
+     if (ncge != 3 && ncge != 4)
+       {
+	 cerr << " read nopo type element[" << i << "] =" 
+	      << ncge << " not 3 or 4 " << endl;
+	 MeshError(115);
+       }
+     if (npo != 3 && npo != 4)
+       {
+	 cerr << " read nopo element[" << i << "] npo = "  
+	      << npo << " not 3 or 4 " << endl;
+	 MeshError(115);
+       }
+     
+     for( j=0;j<npo;j++)
+       {f_in >>np[j];np[j]--;}
+     
+     if (ncopnp !=1) 
+       {
+	 f_in >> npo;
+	 if (npo != 3 || npo != 4)
+	   {
+	     cerr << " read nopo type element[" << i << "]= "  
+		  << ncge << " not 3 or 4 " << endl;
+	     MeshError(115);
+	   }
+	 
+	 for(j=0;j<npo;j++)
+	   {f_in >>np[j];np[j]--;}
+	 
+       }
+     if (nmae>0) 
+       {
+	 Int4  ining; // no ref 
+	 
+	 f_in>>ining;
+	 if (ining==1)
+	   MeshError(116);
+	 if (ining==2)
+	   for (j=0;j<npo;j++)
+	     f_in >>re[j];
+	 for (j=0;j<npo;j++)
+	   f_in >>rv[j];
+	 
+	 
+	 // set the ref on vertex and the shift np of -1 to start at 0
+	 for (j=0;j<npo;j++)
+	   vertices[np[j]].ReferenceNumber = rv[j];
+	 
+	 if (ining==2)
+	   for (j=0;j<npo;j++)
+	     if (re[j])
+	       {
+		 kr++;
+		 Int4 i0 = np[j];
+		 Int4 i1 = np[(j+1)%npo];
+		 // cout << kr << " ref  edge " << i0 << " " << i1 << " " << re[j] << endl;
+		 refe[edge4->addtrie(i0,i1)]=re[j];
+	       }
+       }
+     
+     if (npo==3) 
+       { // triangles 
+	 triangles[k]  = Triangle(this,np[0],np[1],np[2]); 
+	 triangles[k].color = ndsde;
+	 k++;
+       }
+     else if (npo==4)
+       { // quad 
+	 Triangle & t1 = triangles[k++];
+	 Triangle & t2 = triangles[k++];
+	 t1 = Triangle(this,np[0],np[1],np[2]);
+	 t2 = Triangle(this,np[2],np[3],np[0]);
+	 t1.SetHidden(OppositeEdge[1]); // two time  because the adj was not created 
+	 t2.SetHidden(OppositeEdge[1]); 
+	 t1.color = ndsde;
+	 t2.color = ndsde;
+       }
+     else
+       {
+	 cerr << " read nopo type element =" << npo << " not 3 or 4 " << endl;
+	 MeshError(114);
+       }
+     
+     
+   }
+ // cout << k << " == " << nbt << endl;
+ assert(k==nbt);
+
+ nbe = edge4->nb();
+ if (nbe)
+   {
+     if (verbosity>7)
+     cout << " Nb of ref edges = " << nbe << endl;
+     if (edges)
+       delete [] edges;
+     edges = new Edge[nbe];
+     for (i=0;i<nbe;i++)
+       {
+	 edges[i].v[0] = vertices + edge4->i(i);
+	 edges[i].v[1] = vertices + edge4->j(i);
+	 edges[i].ref = refe[i];
+	 //	 cout << i << " " <<  edge4->i(i) << " " <<  edge4->j(i) << endl;
+       }
+      if (verbosity>7)
+	cout << " Number of reference edge in the  mesh = " << nbe << endl;
+   }
+ delete [] refe;
+ delete edge4;
+}
+  void  Triangles::Read_ftq(MeshIstream & f_in)
+{
+  //  
+  if (verbosity>1)
+    cout << "  -- ReadMesh .ftq file " <<  f_in.CurrentFile  << endl;
+  
+  Int4 i,ne,nt,nq;
+  f_in.cm() >> nbv >> ne >> nt >> nq ;
+  if (verbosity>3)
+    cout << "    nbv = " << nbv  << " nbtra = " << nt << " nbquad = " << nq << endl;
+  nbt = nt+2*nq;
+  
+
+  nbvx = nbv;
+  nbtx =  2*nbv-2; // for filling The Holes and quadrilaterals 
+  triangles =new Triangle[nbtx];
+  assert(triangles);
+  vertices=new Vertex[nbvx];
+  ordre=new (Vertex* [nbvx]);
+  Int4 k=0;
+  
+  for ( i=0;i<ne;i++) 
+    {
+      long ii,i1,i2,i3,i4,ref;
+      f_in >>  ii;
+	if (ii==3) 
+	  { // triangles 
+	    f_in >> i1>>  i2 >>   i3 >> ref ;
+	    triangles[k]  = Triangle(this,i1-1,i2-1,i3-1); 
+	    triangles[k++].color = ref;
+	  }
+	else if (ii==4)
+	  { // quad 
+	    f_in >> i1>>  i2 >>   i3 >> i4 >> ref ;
+	    Triangle & t1 = triangles[k++];
+	    Triangle & t2 = triangles[k++];
+	    t1 = Triangle(this,i1-1,i2-1,i3-1);
+	    t1.color=ref;
+	    t2 = Triangle(this,i3-1,i4-1,i1-1);
+	    t2.color=ref;
+	    t1.SetHidden(OppositeEdge[1]); // two time  because the adj was not created 
+	    t2.SetHidden(OppositeEdge[1]); 	  
+	  }
+	else
+	  {
+	    cout << " read ftq type element =" << ii << " not 3 or 4 " << endl;
+	    MeshError(111);
+	  }
+    }
+  assert(k==nbt);
+  Metric M1(1);
+  for ( i=0;i<nbv;i++)
+    {
+      f_in >> vertices[i].r.x >>   vertices[i].r.y >> vertices[i].ReferenceNumber;
+       vertices[i].DirOfSearch =NoDirOfSearch;
+       vertices[i].m = M1;
+
+    }
+}
+
+///////////////////////////////////////////////
+
+void  Triangles::Read_msh(MeshIstream &f_in)
+{
+    Metric M1(1.);
+  if (verbosity>1)
+    cout << "  -- ReadMesh .msh file " <<  f_in.CurrentFile  << endl;
+   	
+     Int4 i;
+     f_in.cm() >> nbv >> nbt ;
+     while (f_in.in.peek()==' ')
+         f_in.in.get();
+     if(isdigit(f_in.in.peek())) 
+       f_in >> nbe;
+     if (verbosity>3)
+       cout << "    nbv = " << nbv  << " nbt = " << nbt << " nbe = " << nbe << endl;
+     nbvx = nbv;
+     nbtx =  2*nbv-2; // for filling The Holes and quadrilaterals 
+     triangles =new Triangle[nbtx];
+     assert(triangles);
+     vertices=new Vertex[nbvx];
+     ordre=new (Vertex* [nbvx]);
+      edges = new Edge[nbe];
+     for ( i=0;i<nbv;i++)
+	{
+	 f_in >> vertices[i].r.x >>   vertices[i].r.y >> vertices[i].ReferenceNumber;
+	    vertices[i].on=0;
+	    vertices[i].m=M1;
+         //if(vertices[i].ReferenceNumber>NbRef)	NbRef=vertices[i].ReferenceNumber;  
+  	}
+     for (     i=0;i<nbt;i++)
+       {
+	 Int4 i1,i2,i3,r;
+	 f_in >>  i1 >>  i2 >>   i3 >> r;
+	 triangles[i]  = Triangle(this,i1-1,i2-1,i3-1);
+	 triangles[i].color = r;	 
+       }
+     for (i=0;i<nbe;i++)
+       {
+	 Int4 i1,i2,r;
+	 f_in >>  i1 >>  i2 >> r;
+	      edges[i].v[0]= vertices +i1-1;
+	      edges[i].v[1]= vertices +i2-1;
+	      edges[i].adj[0]=0;
+	      edges[i].adj[1]=0;
+	      edges[i].ref = r;
+	      edges[i].on=0;
+       }
+      
+}
+
+//////////////////////////////////////////////////
+
+void  Triangles::Read_amdba(MeshIstream &f_in )
+{
+  Metric M1(1);
+  if (verbosity>1)
+    cout << "  -- ReadMesh .amdba file " <<  f_in.CurrentFile  << endl;
+   	
+     Int4 i;
+     f_in.cm() >> nbv >> nbt ;
+     //    if (verbosity>3)
+       cout << "    nbv = " << nbv  << " nbt = " << nbt << endl;
+     f_in.eol() ;// 
+     nbvx = nbv;
+     nbtx =  2*nbv-2; // for filling The Holes and quadrilaterals 
+     triangles =new Triangle[nbtx];
+     assert(triangles);
+     vertices=new Vertex[nbvx];
+     ordre=new (Vertex* [nbvx]);
+     Int4 j;
+      for ( i=0;i<nbv;i++)
+	{
+	  f_in >> j ;
+	  assert( j >0 && j <= nbv);
+	  j--;
+	  f_in >> vertices[j].r.x >>   vertices[j].r.y >> vertices[j].ReferenceNumber;
+	   vertices[j].m=M1;
+	   vertices[j].DirOfSearch=NoDirOfSearch;
+	}
+     
+      for (     i=0;i<nbt;i++)
+       {
+	 Int4 i1,i2,i3,ref;
+	   f_in >> j ;
+	   assert( j >0 && j <= nbt);
+	   j--;
+	   f_in >> i1 >>  i2 >>   i3 >> ref;
+	 triangles[j]  = Triangle(this,i1-1,i2-1,i3-1);
+	 triangles[j].color =ref;
+       }
+      f_in.eol() ;// 
+      
+  // cerr << " a faire " << endl;
+  //MeshError(888);
+}
+
+
+Triangles::Triangles(const char * filename,Real8 cutoffradian) 
+: Gh(*(new Geometry())), BTh(*this)
+{ 
+#ifdef DRAWING1
+   if (!withrgraphique) {initgraphique();withrgraphique=true;}   
+#endif
+
+  //  Int4 beginquad=0,begintria=0;
+  // Int4 endquad=0;endtria=0;
+  //int type_file=0;
+
+  int lll = strlen(filename);
+  int  am_fmt = !strcmp(filename + lll - 7,".am_fmt");
+  int  amdba = !strcmp(filename + lll - 6,".amdba");
+  int  am = !strcmp(filename + lll - 3,".am");
+  int  nopo = !strcmp(filename + lll - 5,".nopo");
+  int  msh = !strcmp(filename + lll - 4,".msh");
+  int  ftq = !strcmp(filename + lll - 4,".ftq");
+
+ // cout << " Lecture type  :" << filename + lll - 7 <<":" <<am_fmt<<  endl;
+
+  char * cname = new char[lll+1];
+  strcpy(cname,filename);
+  Int4 inbvx =0;
+  PreInit(inbvx,cname);
+  OnDisk = 1;
+  //  allocGeometry = &Gh; // after Preinit ; 
+
+  MeshIstream f_in (filename);
+  
+  if (f_in.IsString("MeshVersionFormatted"))
+    {
+      int version ;
+      f_in >> version ;
+      Read(f_in,version,cutoffradian);
+    }
+  else {     
+    if (am_fmt) Read_am_fmt(f_in);
+    else if (am) Read_am(f_in);
+    else if (amdba) Read_amdba(f_in);
+    else if (msh) Read_msh(f_in);
+    else if (nopo) Read_nopo(f_in);
+    else if (ftq) Read_ftq(f_in);
+    else 
+      { 
+	cerr << " Unkown type mesh " << filename << endl;
+	MeshError(2);
+      }
+      ConsGeometry(cutoffradian);
+      Gh.AfterRead();    
+  }
+
+  SetIntCoor();
+  FillHoleInMesh();
+  // Make the quad ---
+   
+}
+
+void Geometry::ReadGeometry(const char * filename)
+{
+  OnDisk = 1;
+  if(verbosity>1)
+      cout << "  -- ReadGeometry " << filename << endl;
+  MeshIstream f_in (filename);
+  ReadGeometry(f_in,filename);
+}
+
+
+
+void Geometry::ReadGeometry(MeshIstream & f_in,const char * filename)  
+{
+  if(verbosity>1)
+    cout << "  -- ReadGeometry " << filename << endl;
+  assert(empty());
+  nbiv=nbv=nbvx=0;
+  nbe=nbt=nbtx=0;
+  NbOfCurves=0;
+ // BeginOfCurve=0;
+  name=new char [strlen(filename)+1];
+  strcpy(name,filename);
+  Real8 Hmin = HUGE_VAL;// the infinie value 
+//  Real8 MaximalAngleOfCorner = 10*Pi/180; ; 
+  Int4 hvertices =0;
+  Int4 i;
+  Int4 Version,dim=0;
+  int field=0;
+  int showfield=0;
+  int NbErr=0;
+
+  while (f_in.cm()) 
+    { 
+      field=0;
+      // warning ruse for on allocate fiedname at each time 
+      char fieldname[256];
+      f_in.cm() >> fieldname ;
+      f_in.err();
+      if(f_in.eof()) break;
+//      cout <<  fieldname <<  " line " << LineNumber  <<endl;
+      if (!strcmp(fieldname,"MeshVersionFormatted") )
+        f_in  >> Version ;
+      else if (!strcmp(fieldname,"End"))
+	break;
+      else if (!strcmp(fieldname,"end"))
+	break;
+      else if (!strcmp(fieldname,"Dimension"))
+        {
+          f_in   >>  dim ;
+	  if(verbosity>5) 
+	    cout << "     Geom Record Dimension dim = " << dim << endl;        
+          assert(dim ==2);
+         }
+       else if (!strcmp(fieldname,"hVertices"))
+         { 
+	   if (nbv <=0) {
+	     cerr<<"Error: the field Vertex is not found before hVertices " << filename<<endl;
+	     NbErr++;}       
+	   if(verbosity>5) 
+	    cout << "     Geom Record hVertices nbv=" << nbv <<  endl;
+	   hvertices =1;
+           for (i=0;i< nbv;i++) 
+	     {
+	       Real4 h;
+	       f_in  >>  h ; 
+	       vertices[i].m = Metric(h);
+	     }
+	 }
+       else if (!strcmp(fieldname,"MetricVertices"))
+         { hvertices =1;
+	   if (nbv <=0) {
+	     cerr<<"Error: the field Vertex is not found before MetricVertices " << filename<<endl;
+	     NbErr++;}       
+           if(verbosity>5) 
+	     cout << "     Geom Record MetricVertices nbv =" << nbv <<  endl;
+           for (i=0;i< nbv;i++) 
+	     {
+	       Real4 a11,a21,a22;
+	       f_in  >>  a11 >> a21 >> a22  ; 
+	       vertices[i].m = Metric(a11,a21,a22);
+	     }
+	 }
+       else if (!strcmp(fieldname,"h1h2VpVertices"))
+         { hvertices =1;
+	   if (nbv <=0) {
+	     cerr<<"Error: the field Vertex is not found before h1h2VpVertices " << filename<<endl;
+	     NbErr++;}       
+           if(verbosity>5) 
+	     cout << "     Geom Record h1h2VpVertices nbv=" << nbv << endl;
+
+           for (i=0;i< nbv;i++) 
+	     {
+	       Real4 h1,h2,v1,v2;
+	       f_in  >> h1 >> h2 >>v1 >>v2 ; 
+	       vertices[i].m = Metric(MatVVP2x2(1/(h1*h1),1/(h2*h2),D2(v1,v2)));
+	     }
+	 }
+      else if (!strcmp(fieldname,"Vertices"))
+        { 
+          assert(dim ==2);
+          f_in   >>  nbv ;
+	  //          if(LineError) break;
+          nbvx = nbv;
+          
+          vertices = new GeometricalVertex[nbvx];
+	  if(verbosity>5) 
+	    cout << "     Geom Record Vertices nbv = " << nbv << "vertices = " << vertices<<endl;
+          assert(nbvx >= nbv);
+          nbiv = nbv;
+          for (i=0;i<nbv;i++) {
+            f_in  >> vertices[i].r.x  ;
+            // if(LineError) break;
+            f_in  >> vertices[i].r.y ;
+	    // if(LineError) break;
+            f_in >>   vertices[i].ReferenceNumber   ;
+            vertices[i].DirOfSearch=NoDirOfSearch;
+	    //            vertices[i].m.h = 0;
+            vertices[i].color =0;
+            vertices[i].Set();}
+	  // if(LineError) break;
+	    pmin =  vertices[0].r;
+	    pmax =  vertices[0].r;
+	    // recherche des extrema des vertices pmin,pmax
+	    for (i=0;i<nbv;i++) {
+	      pmin.x = Min(pmin.x,vertices[i].r.x);
+	      pmin.y = Min(pmin.y,vertices[i].r.y);
+	      pmax.x = Max(pmax.x,vertices[i].r.x);
+	      pmax.y = Max(pmax.y,vertices[i].r.y);
+	    }
+	    
+	      R2 DD05 = (pmax-pmin)*0.05;
+	      pmin -=  DD05;
+	      pmax +=  DD05;
+	    
+	    coefIcoor= (MaxICoor)/(Max(pmax.x-pmin.x,pmax.y-pmin.y));
+	    assert(coefIcoor >0);
+	    if (verbosity>5) {
+	      cout << "     Geom: min="<< pmin << "max ="<< pmax << " hmin = " << MinimalHmin() <<  endl;}
+        }
+      else if(!strcmp(fieldname,"MaximalAngleOfCorner")||!strcmp(fieldname,"AngleOfCornerBound"))
+        {         
+          f_in >> MaximalAngleOfCorner;
+              
+	  if(verbosity>5) 
+	    cout << "     Geom Record MaximalAngleOfCorner " << MaximalAngleOfCorner <<endl;
+          MaximalAngleOfCorner *= Pi/180;
+        }
+      else if (!strcmp(fieldname,"Edges"))
+        {
+	  if (nbv <=0) {
+	    cerr<<"Error: the field edges is not found before MetricVertices " << filename<<endl;
+	    NbErr++;}   
+	  else 
+	    {
+	      int i1,i2;
+	      R2 zero2(0,0);
+	      f_in   >>  nbe ;
+	      
+	      edges = new GeometricalEdge[nbe];
+	      if(verbosity>5) 
+		cout << "     Record Edges: Nb of Edge " << nbe <<endl;
+	      assert(edges);
+	      assert (nbv >0); 
+	      Real4 *len =0;
+	      if (!hvertices) 
+		{
+		  len = new Real4[nbv];
+		  for(i=0;i<nbv;i++)
+		    len[i]=0;
+		}
+	      
+	      for (i=0;i<nbe;i++) 
+		{
+		  f_in  >> i1   >> i2 >>  edges[i].ref  ;
+		  
+		  i1--;i2--; // for C index
+		  edges[i].v[0]=  vertices + i1;
+		  edges[i].v[1]=  vertices + i2;
+		  R2 x12 = vertices[i2].r-vertices[i1].r;
+		  Real8 l12=sqrt((x12,x12));
+		  edges[i].tg[0]=zero2;
+		  edges[i].tg[1]=zero2;
+		  edges[i].SensAdj[0] = edges[i].SensAdj[1] = -1;
+		  edges[i].Adj[0] = edges[i].Adj[1] = 0;
+		  edges[i].flag = 0;
+		  if (!hvertices) 
+		    {
+		      vertices[i1].color++;
+		      vertices[i2].color++;
+		      len[i1] += l12;
+		      len[i2] += l12;
+		    }
+		  
+		  Hmin = Min(Hmin,l12);
+		}
+	      // definition  the default of the given mesh size 
+	      if (!hvertices) 
+		{
+		  for (i=0;i<nbv;i++) 
+		    if (vertices[i].color > 0) 
+		      vertices[i].m=  Metric(len[i] /(Real4) vertices[i].color);
+		    else 
+		      vertices[i].m=  Metric(Hmin);
+		  delete [] len;
+		  
+		  if(verbosity>3) 
+		    cout << "     Geom Hmin " << Hmin << endl;
+		}
+	      
+	    }
+	}
+      else if (!strcmp(fieldname,"EdgesTangence") ||!strcmp(fieldname,"TangentAtEdges")  )
+        { 
+          int n,i,j,k;
+          R2 tg;
+          f_in  >> n ;
+          
+	  if(verbosity>5) 
+	    cout << "     Record TangentAtEdges: Nb of Edge " << n <<endl;
+          
+          for (k=0;k<n;k++)
+            {
+	      f_in  >>  i  >> j ;
+	      f_in >> tg.x  >> tg.y ;
+	      assert( i <= nbe );
+	      assert( i > 0 );
+	      assert ( j == 1 || j==2 );
+	      i--;j--;// for C index
+	      edges[i].tg[j] = tg;
+            }
+        }
+      else if (!strcmp(fieldname,"Corners"))
+        { 
+          int i,j,n;
+          f_in  >> n ;
+	  if(verbosity>5) 
+	    cout << "     Record Corner: Nb of Corner " << n <<endl;
+          
+          for (i=0;i<n;i++) {     
+            f_in  >>  j ;
+            assert( j <= nbv );
+            assert( j > 0 );
+            j--;
+            vertices[j].SetCorner();
+            vertices[j].SetRequired();  }
+        }
+      else if (!strcmp(fieldname,"RequiredVertices"))
+        { 
+          int i,j,n;
+          f_in  >> n ;
+
+          for (i=0;i<n;i++) {     
+            f_in  >>  j ;
+            assert( j <= nbv );
+            assert( j > 0 );
+            j--;
+            vertices[j].SetRequired();  }
+      }
+      else if (!strcmp(fieldname,"RequiredEdges"))
+        { 
+          int i,j,n;
+          f_in  >> n ;
+
+          for (i=0;i<n;i++) {     
+            f_in  >>  j ;
+            assert( j <= nbe );
+            assert( j > 0 );
+            j--;
+            edges[j].SetRequired();  }
+      }
+    else if (!strcmp(fieldname,"SubDomain") || !strcmp(fieldname,"SubDomainFromGeom"))
+      { 
+	f_in   >>  NbSubDomains ;
+	if (NbSubDomains>0) 
+	  {
+	    subdomains = new GeometricalSubDomain[  NbSubDomains];
+	    Int4 i0,i1,i2,i3;
+	    for (i=0;i<NbSubDomains;i++) 
+	      {
+		f_in  >> i0  >>i1 
+		      >> i2  >>i3 ; 
+		
+		assert(i0 == 2);
+		assert(i1<=nbe && i1>0);
+		subdomains[i].edge=edges + (i1-1);
+		subdomains[i].sens = (int) i2;
+		subdomains[i].ref = i3;
+	      }
+	  }
+      }
+      else
+	{ // unkown field
+	  field = ++showfield;
+	  if(showfield==1) // just to show one time 
+	    if (verbosity>3)
+	      cout << "    Warning we skip the field " << fieldname << " at line " << f_in.LineNumber << endl;
+	}
+      showfield=field; // just to show one time 
+    } // while !eof()
+  // generation  de la geometrie 
+  // 1 construction des aretes 
+  // construire des aretes en chaque sommets 
+  
+  if (nbv <=0) {
+    cerr<<"Error: the field Vertex is not found in " << filename<<endl;
+    NbErr++;}
+  if(nbe <=0) {
+    cerr <<"Error: the field Edges is not found in "<< filename<<endl
+      ;NbErr++;}
+  if(NbErr) MeshError(1);
+
+ 
+}
+
+
+}  // end of namespace bamg 
diff --git a/contrib/bamg/bamglib/MeshWrite.cpp b/contrib/bamg/bamglib/MeshWrite.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..8547dea25bad60743c37601d00663bbdee2e55a2
--- /dev/null
+++ b/contrib/bamg/bamglib/MeshWrite.cpp
@@ -0,0 +1,947 @@
+// -*- Mode : c++ -*-
+//
+// SUMMARY  :      
+// USAGE    :        
+// ORG      : 
+// AUTHOR   : Frederic Hecht
+// E-MAIL   : hecht@ann.jussieu.fr
+//
+
+/*
+ 
+ This file is part of Freefem++
+ 
+ Freefem++ is free software; you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+ 
+ Freefem++  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 Lesser General Public License for more details.
+ 
+ You should have received a copy of the GNU Lesser General Public License
+ along with Freefem++; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+#include <cstdio>
+#include <cstring>
+#include <cmath>
+#include <ctime>
+#include "Meshio.h"
+#include "Mesh2.h"
+#include "QuadTree.h"
+#include "SetOfE4.h"
+
+
+namespace bamg {
+
+void Triangles::Write(const char * filename,const TypeFileMesh typein )
+{
+  TypeFileMesh type = typein;
+  const char * gsuffix=".gmsh";
+  int ls=0;
+  int lll = strlen(filename);
+  if (type==AutoMesh)
+    {
+      type = BDMesh;
+      if      (!strcmp(filename + lll - (ls=7),".am_fmt")) type = am_fmtMesh;
+      else if (!strcmp(filename + lll - (ls=6),".amdba"))  type = amdbaMesh;
+      else if (!strcmp(filename + lll - (ls=3),".am"))     type = amMesh;
+      else if (!strcmp(filename + lll - (ls=5),".nopo"))   type = NOPOMesh;
+      else if (!strcmp(filename + lll - (ls=4),".msh"))    type = mshMesh;
+      else if (!strcmp(filename + lll - (ls=4),".ftq"))    type = ftqMesh;
+      else if (!strcmp(filename + lll - (ls=7),".AM_FMT")) type = am_fmtMesh;
+      else if (!strcmp(filename + lll - (ls=6),".AMDBA"))  type = amdbaMesh;
+      else if (!strcmp(filename + lll - (ls=3),".AM"))     type = amMesh;
+      else if (!strcmp(filename + lll - (ls=5),".NOPO"))   type = NOPOMesh;
+      else if (!strcmp(filename + lll - (ls=4),".MSH"))    type = mshMesh;
+      else if (!strcmp(filename + lll - (ls=4),".FTQ"))    type = ftqMesh;
+      else ls=0;
+    } 
+  if (verbosity>1)
+    {
+      cout << "  -- Writing the file " << filename << " of type " ;
+     switch (type) 
+       {
+       case BDMesh     :  cout << " BD Mesh "  ; break;
+       case NOPOMesh   :  cout << " NOPO "     ; break;
+       case amMesh     :  cout << " am "       ; break;
+       case am_fmtMesh :  cout << " am_fmt "   ; break;
+       case amdbaMesh  :  cout << " amdba "    ; break;
+       case ftqMesh    :  cout << " ftq "      ; break;
+       case mshMesh    :  cout << " msh "      ; break;
+	default: 
+	  cerr << endl 
+	       <<  " Unkown type mesh file " << (int) type << " for Writing " << filename <<endl;
+	  MeshError(1);
+       }     
+     Int4 NbOfTria =  nbt-2*NbOfQuad-NbOutT ;
+     if (NbOfTria)      cout << " NbOfTria = " << NbOfTria;
+     if (NbOfQuad)      cout << " NbOfQuad = " << NbOfQuad;
+     if (nbe)   	cout << " NbOfRefEdge = " << nbe ;
+     cout    << endl;
+
+    }
+  ofstream f(filename /*,ios::trunc*/);
+ f.precision(12);
+
+   if (f)
+     switch (type) 
+       {
+       case BDMesh     : 
+          {
+             if ( ! Gh.OnDisk)
+              {
+                 delete [] Gh.name;
+                 Gh.name = new char[lll+1+strlen(gsuffix)];
+                 strcpy(Gh.name,filename);
+                 if (Gh.name[lll-ls-1]=='.') strcpy(Gh.name+lll-ls, gsuffix+1);
+                 else strcpy(Gh.name+lll-ls,gsuffix);
+                cout << " write geo in " << Gh.name << endl;
+                  ofstream f(Gh.name) ;
+                  f << Gh ;
+                  Gh.OnDisk=true;
+              }
+	     f << *this     ;
+	     break;
+           }
+       case NOPOMesh   :  Write_nopo(f)  ; break;
+       case amMesh     :  Write_am(f)    ; break;
+       case am_fmtMesh :  Write_am_fmt(f); break;
+       case amdbaMesh  :  Write_amdba(f) ; break;
+       case ftqMesh    :  Write_ftq(f)   ; break;
+       case mshMesh    :  Write_msh(f)   ; break;
+	default: 
+	  cerr << " Unkown type mesh file " << (int) type << " for Writing " << filename <<endl;
+	  MeshError(1);
+       }
+   else
+     {
+       cerr << " Error openning file " << filename << endl;
+       MeshError(1);
+     }
+   if(verbosity>5)
+   cout << "end write" << endl;
+      
+}
+void Triangles::Write_nop5(OFortranUnFormattedFile * f,
+			   Int4 &lnop5,Int4 &nef,Int4 &lgpdn,Int4 ndsr) const 
+{
+  ndsr =0;
+  Int4 * reft = new Int4[nbt];
+  //Int4 nbInT = ;
+  ConsRefTriangle(reft);
+  Int4 no5l[20];
+
+  Int4 i5 = 0;
+  Int4 i,j,k=0,l5;
+  //  Int4 ining=0;
+  Int4 imax,imin;
+
+  lgpdn = 0;
+  nef=0;
+  // construction of a liste linked  of edge
+  Edge ** head  = new Edge *[nbv];
+  Edge  ** link = new Edge * [nbe];
+  for (i=0;i<nbv;i++)
+    head[i]=0; // empty liste
+  
+  for (i=0;i<nbe;i++)
+    { 
+      j = Min(Number(edges[i][0]),Number(edges[i][1]));
+      link[i]=head[j];
+      head[j]=edges +i;
+    }
+  for ( i=0;i<nbt;i++)
+    {
+      no5l[0]    = 0;
+      Int4 kining=0;
+      Int4 ining=0;
+      Int4 nmae =0;
+      Int4 np=0;
+      l5 = 2;
+      Triangle & t = triangles[i];
+      Triangle * ta; // 
+      Vertex *v0,*v1,*v2,*v3;
+      if (reft[i]<0) continue;
+      ta = t.Quadrangle(v0,v1,v2,v3);
+      if (!ta)
+	{ // a triangles
+	  no5l[l5++] = Max(subdomains[reft[i]].ref,(Int4) 1);
+	  np = 3;
+	  no5l[l5++] = np;
+	  no5l[0]    = np;
+	  no5l[l5++] = Number(triangles[i][0]) +1;
+	  no5l[l5++] = Number(triangles[i][1]) +1;
+	  no5l[l5++] = Number(triangles[i][2]) +1;
+	  imax = Max3(no5l[l5-1],no5l[l5-2],no5l[l5-3]);
+	  imin = Min3(no5l[l5-1],no5l[l5-2],no5l[l5-3]);
+	  lgpdn = Max(lgpdn,imax-imin);
+          kining=l5++;
+	  // ref of 3 edges 
+	  for (j=0;j<3;j++)
+	    {
+	      no5l[l5] = 0;
+	      int i0 = (int) j;
+	      int i1 = (i0+1) %3;
+	      Int4 j1= no5l[4+i0];
+	      Int4 j2= no5l[4+i1];
+	      Int4 ji = Min(j1,j2)-1;
+	      Int4 ja = j1+j2-2;
+	      Edge * e=head[ji];
+	      while (e)
+		if(Number((*e)[0])+Number((*e)[1]) == ja) 
+		   {
+		     no5l[l5] = e->ref;
+		     break;
+		   }
+		else
+		  e = link[Number(e)];
+	      l5++;
+	    }
+	  if ( no5l[l5-1] || no5l[l5-2] || no5l[l5-3]  )
+	    ining=2;
+	  else 
+	    l5 -= 3;
+	  
+	  no5l[l5++] = triangles[i][0].ref();
+	  no5l[l5++] = triangles[i][1].ref();
+	  no5l[l5++] = triangles[i][2].ref();
+	  if (ining ||  no5l[l5-1] || no5l[l5-2] || no5l[l5-3]  )
+            ining= ining ? ining : 3;
+	  else
+	    l5 -= 3,ining=0;
+
+	  
+	}
+      else if ( &t<ta)
+	{ 
+	  k++;
+	  no5l[l5++] = Max(subdomains[reft[i]].ref,(Int4) 1);
+	  np =4;
+	  no5l[l5++] = np;
+	  no5l[0]    = np;
+	  
+	  no5l[l5++] = Number(v0) +1;
+	  no5l[l5++] = Number(v1) +1;
+	  no5l[l5++] = Number(v2) +1;
+	  no5l[l5++] = Number(v3) +1;
+	  
+	  imax = Max(Max(no5l[l5-1],no5l[l5-2]),Max(no5l[l5-3],no5l[l5-4]));
+	  imin = Min(Min(no5l[l5-1],no5l[l5-2]),Min(no5l[l5-3],no5l[l5-4]));
+	  lgpdn = Max(lgpdn,imax-imin);
+
+
+          kining=l5++;
+	  // ref of the 4 edges 
+	  // ref of 3 edges 
+	  for (j=0;j<4;j++)
+	    {
+	      no5l[l5] = 0;
+	      int i0 = (int) j;
+	      int i1 = (i0+1) %4;
+	      Int4 j1= no5l[4+i0];
+	      Int4 j2= no5l[4+i1];
+	      Int4 ji = Min(j1,j2)-1;
+	      Int4 ja = j1+j2-2;
+	      Edge *e=head[ji];
+	      while (e)
+		if(Number((*e)[0])+Number((*e)[1]) == ja) 
+		   {
+		     no5l[l5] = e->ref;
+		     break;
+		   }
+		else
+		  e = link[Number(e)];
+	      l5++;
+	    }
+	  if ( no5l[l5-1] || no5l[l5-2] || no5l[l5-3] || no5l[l5-4] )
+	    ining=2;
+	  else 
+	    l5 -= 4;
+
+	  no5l[l5++] = v0->ref();
+	  no5l[l5++] = v1->ref();
+	  no5l[l5++] = v2->ref();
+	  no5l[l5++] = v3->ref();
+	  if (ining || no5l[l5-1] || no5l[l5-2] || no5l[l5-3] || no5l[l5-4] )
+            ining= ining ? ining : 3;
+          else
+	    l5 -= 4;
+
+	}
+      else l5=0;
+
+     if (l5)
+       {
+	 if (ining)
+	   {
+	     nef ++;
+	     nmae = l5-kining;
+	     no5l[kining] = ining;
+	   }
+	 else l5--;
+	 no5l[1]=nmae;
+	 // for all ref  
+	 for (j=kining+1;j<l5;j++)
+	   {
+	     no5l[j] = Abs(no5l[j]);
+	     ndsr = Max(ndsr,no5l[j]);
+	   }
+	 
+	 if (f && i < 10 && verbosity > 10)
+	   { 
+	     cout << " e[ " << i << " @" << i5 << "]=";
+	     for (j=0;j<l5;j++)
+	       cout << " " << no5l[j]; 
+	     cout << endl;
+	   }
+	 
+	 if (f)
+	   for (j=0;j<l5;j++)
+	     *f << no5l[j]; 
+	 i5 += l5;
+       }
+    }
+  if(verbosity>10)
+  cout << "   fin write nopo 5 i5=" << i5 << " " << i5*4 << endl;
+  lnop5=i5; 
+  lgpdn++; // add 1
+  delete [] reft;
+  delete [] head;
+  delete [] link;
+  
+}
+
+void Triangles::Write_nopo(ostream &ff) const
+
+{
+ Int4  nef=0;
+ Int4 lpgdn=0;
+ Int4 ndsr=0;
+ Int4 i;
+ Int4 ndsd=1;
+ Int4 lnop5=0;
+ 
+ OFortranUnFormattedFile f(ff);
+ 
+ for (i=0;i<NbSubDomains ;i++)
+   ndsd=Max(ndsd,subdomains[i].ref);
+ 
+ // to compute the lnop5,nef,lpgdn,ndsr parameter 
+ Write_nop5(0,lnop5,nef,lpgdn,ndsr);
+ 
+ f.Record();
+ 
+ f <<  Int4(13)<<Int4(6)<<Int4(32)<<Int4(0)<<Int4(27)<<Int4(0) ;
+ f << Int4(nbv+nbv) ;
+ f << lnop5;
+ f << Int4(1 )<<Int4(1)<<Int4(1 )<<Int4(1)<<Int4(2)<<Int4(1);
+
+ f.Record(33*sizeof(Int4)); 
+
+ f << Int4(32) ;
+ 
+ //char *c=identity;
+ time_t timer =time(0);
+ char buf[10];
+ strftime(buf ,10,"%y/%m/%d",localtime(&timer));
+ f.write4(identity,20);
+ f.write4(buf,2);
+ f.write4("created with BAMG",6);
+ f.write4("NOPO",1);
+
+ 
+ f << Int4(0) << Int4(1) << Int4(0) ;
+ f.Record();
+ Int4 nbquad= NbOfQuad;
+ Int4 nbtria= nbt-NbOutT - 2*NbOfQuad;
+
+ cout << " lnop5      = " << lnop5 << endl;
+ cout << " nbquad     = " << nbquad << endl;
+ cout << " nbtrai     = " << nbtria << endl;
+ cout << " lpgdn      = " << lpgdn << endl;
+ cout << " nef        = " << nef  << endl;
+ cout << " np         = " << nbv  << endl;
+ cout << " ndsr       = " << ndsr << endl;
+ f << Int4(27)  
+   << Int4(2)  << ndsr     << ndsd    << Int4(1) << nbtria+nbquad
+   << Int4(0)  << Int4(0)  << nbtria  << nbquad  << Int4(0)
+   << Int4(0)  << Int4(0)  << Int4(0) << nef     << Int4(nbv)
+   << Int4(0)  << Int4(0)  << Int4(0) << Int4(0) << Int4(0)
+   << Int4(0)  << nbv      << Int4(2) << lpgdn   << Int4(0)
+   << lnop5    << Int4(1) ;
+  f.Record();
+  f << (Int4) 2*nbv;
+  for (i=0;i<nbv;i++)
+    f << (float) vertices[i].r.x <<  (float) vertices[i].r.y;
+  f.Record();
+  f << lnop5;
+  Write_nop5(&f,lnop5,nef,lpgdn,ndsr);
+  // cout << "fin write nopo" << endl;
+}
+
+void Triangles::Write_am_fmt(ostream &f) const 
+{
+  Int4 i,j;
+  assert(this && nbt);
+  Int4 * reft = new Int4[nbt];
+  Int4 nbInT =    ConsRefTriangle(reft);
+  f.precision(12);
+  f << nbv << " " << nbInT << endl;
+  for (i=0;i<nbt;i++)
+    if(reft[i]>=0)
+      {
+	f << Number(triangles[i][0]) +1 << " " ;
+	f << Number(triangles[i][1]) +1 << " " ;
+	f << Number(triangles[i][2]) +1 << " " ;
+	f << endl;
+      }
+  for (i=0;i<nbv;i++)
+      f << vertices[i].r.x << " " << vertices[i].r.y << endl;
+   for (j=i=0;i<nbt;i++) 
+     if (reft[i]>=0)
+       f << subdomains[reft[i]].ref  << (j++%10 == 9 ?  '\n' : ' ');
+   f << endl;
+   for (i=0;i<nbv;i++)
+     f << vertices[i].ref()  << (i%10 == 9 ?  '\n' : ' ');
+   f << endl;
+   delete [] reft;
+
+
+}
+
+void Triangles::Write_am(ostream &ff) const 
+{
+  OFortranUnFormattedFile f(ff);  
+  Int4 i,j;
+  assert(this && nbt);
+  Int4 * reft = new Int4[nbt];
+  Int4 nbInT =    ConsRefTriangle(reft);
+  f.Record();
+  f << nbv << nbInT ;
+  f.Record();
+  for (i=0;i<nbt;i++)
+    if(reft[i]>=0)
+      {
+	f << Number(triangles[i][0]) +1 ;
+	f << Number(triangles[i][1]) +1 ;
+	f << Number(triangles[i][2]) +1 ;
+      }
+  for (i=0;i<nbv;i++)
+    {
+      float x= vertices[i].r.x;
+      float y= vertices[i].r.y;
+      f << x << y ;
+    }
+  for (j=i=0;i<nbt;i++) 
+    if (reft[i]>=0)
+      f << subdomains[reft[i]].ref;
+  for (i=0;i<nbv;i++)
+    f << vertices[i].ref() ;
+  delete [] reft;
+}
+
+void Triangles::Write_ftq(ostream &f) const 
+{
+
+  Int4 i;
+  assert(this && nbt);
+  Int4 * reft = new Int4[nbt];
+  Int4 nbInT =    ConsRefTriangle(reft);
+  f.precision(12);
+  Int4 nele = nbInT-NbOfQuad;
+  Int4 ntri =  nbInT-2*NbOfQuad;
+  Int4 nqua =  NbOfQuad;
+
+  f << nbv << " " << nele << " " << ntri <<  " " << nqua << endl;
+  Int4 k=0;
+  for( i=0;i<nbt;i++)
+    { 
+      Triangle & t = triangles[i];
+      Triangle * ta; // 
+      Vertex *v0,*v1,*v2,*v3;
+      if (reft[i]<0) continue;
+      ta = t.Quadrangle(v0,v1,v2,v3);
+      if (!ta)
+	{ // a triangles
+	  f << "3 " 
+	    << Number(triangles[i][0]) +1 << " " 
+	    << Number(triangles[i][1]) +1 << " " 
+	    << Number(triangles[i][2]) +1 << " " 
+	    << subdomains[reft[i]].ref << endl;
+	  k++;
+	}
+      if ( &t<ta)
+	{ 
+	  k++;
+	  f << "4 " << Number(v0)+1 << " " << Number(v1)+1  << " "  
+	    << Number(v2)+1 << " "  << Number(v3)+1 << " "  
+	    << subdomains[reft[i]].ref << endl;
+	}
+    }
+  assert(k == nele);
+  
+  for (i=0;i<nbv;i++)
+    f << vertices[i].r.x << " " << vertices[i].r.y 
+      << " " <<  vertices[i].ref() << endl;
+  delete [] reft;
+  
+  
+}
+void Triangles::Write_msh(ostream &f) const 
+{
+  Int4 i;
+  assert(this && nbt);
+  Int4 * reft = new Int4[nbt];
+  Int4 nbInT =    ConsRefTriangle(reft);
+  f.precision(12);
+  f << nbv << " " << nbInT << " " << nbe <<  endl;
+
+  for (i=0;i<nbv;i++)
+    f << vertices[i].r.x << " " << vertices[i].r.y << " " 
+      << vertices[i].ref() <<   endl;
+
+  for (i=0;i<nbt;i++)
+    if(reft[i]>=0)
+      f << Number(triangles[i][0]) +1 << " " 
+	<< Number(triangles[i][1]) +1 << " " 
+	<< Number(triangles[i][2]) +1 << " " 
+	<< subdomains[reft[i]].ref << endl;
+  
+
+  for (i=0;i<nbe;i++)
+    f << Number(edges[i][0]) +1 << " "  << Number(edges[i][1]) +1 
+      << " " << edges[i].ref << endl;
+      
+   delete [] reft;
+
+}
+
+void Triangles::Write_amdba(ostream &f) const 
+{
+  assert(this && nbt);
+
+  Int4 i,j;
+  Int4 * reft = new Int4[nbt];
+  Int4 nbInT =    ConsRefTriangle(reft);
+  f << nbv << " " << nbInT << endl;
+  cout.precision(12);
+  for (i=0;i<nbv;i++)
+    f << i+1 << " " 
+      << vertices[i].r.x 
+      << " " << vertices[i].r.y 
+      << " " << vertices[i].ref() << endl;
+  j=1;
+  for (i=0;i<nbt;i++)
+    if(reft[i]>=0)
+	f << j++ << " " 
+	  << Number(triangles[i][0]) +1 << " " 
+	  << Number(triangles[i][1]) +1 << " " 
+	  << Number(triangles[i][2]) +1 << " " 
+	  << subdomains[reft[i]].ref  << endl ;
+	f << endl;
+   delete [] reft;
+
+
+}
+
+void Triangles::Write(const char * filename)
+{
+  ofstream f(filename);
+  if (f)
+    {
+       if (name) delete name;
+       name = new char[strlen(filename)+1];
+       strcpy(name,filename);
+       OnDisk =1;
+       f << *this;
+    }
+}
+void Triangles::WriteElements(ostream& f,Int4 * reft ,Int4 nbInT) const
+   { 
+     const Triangles & Th= *this;
+     // do triangle and quad 
+     if(verbosity>9) 
+       cout  << " In Triangles::WriteElements " << endl
+	     << "   Nb of In triangles " << nbInT-Th.NbOfQuad*2 << endl
+	     << "   Nb of Quadrilaterals " <<  Th.NbOfQuad << endl
+	     << "   Nb of in+out+quad  triangles " << Th.nbt << " " << nbInT << endl;
+	 
+     Int4 k=nbInT-Th.NbOfQuad*2;
+     Int4 num =0;
+     if (k>0) {
+       f << "\nTriangles\n"<< k << endl;
+       for(Int4 i=0;i<Th.nbt;i++)
+	 { 
+	   Triangle & t = Th.triangles[i];
+	   if (reft[i]>=0 && !( t.Hidden(0) || t.Hidden(1) || t.Hidden(2) ))
+	    { k--;
+	      f << Th.Number(t[0])+1 << " " << Th.Number(t[1])+1 
+		   << " "  << Th.Number(t[2])+1  << " " << Th.subdomains[reft[i]].ref << endl;
+		   reft[i] = ++num;
+		 }
+	 }
+     } 
+     if (Th.NbOfQuad>0) {
+       f << "\nQuadrilaterals\n"<<Th.NbOfQuad << endl;
+       k = Th.NbOfQuad;
+       for(Int4 i=0;i<Th.nbt;i++)
+	 { 
+	   Triangle & t = Th.triangles[i];
+	   Triangle * ta; // 
+	   Vertex *v0,*v1,*v2,*v3;
+	   if (reft[i]<0) continue;
+	   if ((ta=t.Quadrangle(v0,v1,v2,v3)) !=0 && &t<ta)
+	      { 
+		k--;
+		f << Th.Number(v0)+1 << " " << Th.Number(v1)+1  << " "  
+		  << Th.Number(v2)+1 << " "  << Th.Number(v3)+1 << " "  
+		  << Th.subdomains[reft[i]].ref << endl;
+		  reft[i] = ++num;
+		  reft[Number(ta)] = num;
+	      }
+	 }
+       assert(k==0);
+     }
+     // warning reft is now the element number 
+   }
+
+ostream& operator <<(ostream& f, const   Triangles & Th) 
+ {
+  //  Th.FindSubDomain();
+   // warning just on say the class is on the disk
+  //  ((Triangles *) &Th)->OnDisk = 1;
+
+   Int4 * reft = new Int4[Th.nbt];
+   Int4 nbInT =    Th.ConsRefTriangle(reft);
+   {
+     f << "MeshVersionFormatted 0" <<endl;
+     f << "\nDimension\n"  << 2 << endl;
+     f << "\nIdentifier\n" ;
+     WriteStr(f,Th.identity);
+     f << "\n\nGeometry\n" ;
+     if( Th.Gh.OnDisk)
+       WriteStr(f,Th.Gh.name),     f <<endl;
+     else
+       { // empty file name -> geom in same file
+	 f << "\"\"" << endl << endl;
+	 f << "# BEGIN of the include geometry file because geometry is not on the disk"
+	   << Th.Gh << endl;
+	 f << "End" << endl 
+	   << "# END of the include geometrie file because geometry is not on the disk"
+	   << endl ;
+       }
+   }
+   { 
+     f.precision(12);
+     f << "\nVertices\n" << Th.nbv <<endl;
+     for (Int4 i=0;i<Th.nbv;i++)
+       {
+	 Vertex & v =  Th.vertices[i];
+	 f << v.r.x << " " << v.r.y << " " << v.ref() << endl;
+       }
+   }
+  Int4 ie; 
+   {
+     f << "\nEdges\n"<< Th.nbe << endl;
+     for(ie=0;ie<Th.nbe;ie++)
+       { 
+	 Edge & e = Th.edges[ie];
+	 f << Th.Number(e[0])+1 << " " << Th.Number(e[1])+1;
+	f << " " << e.ref <<endl;
+       }
+     if(Th.NbCrackedEdges)
+       {
+	 f << "\nCrackedEdges\n"<< Th.NbCrackedEdges << endl;
+	 for( ie=0;ie<Th.NbCrackedEdges;ie++)
+	   { 
+	     Edge & e1 = *Th.CrackedEdges[ie].a.edge;
+	     Edge & e2 = *Th.CrackedEdges[ie].b.edge;
+	     f << Th.Number(e1)+1 << " " << Th.Number(e2)+1 <<endl;;
+	   }
+       }
+   }
+
+   Th.WriteElements(f,reft,nbInT);
+   {
+     f << "\nSubDomainFromMesh\n" << Th.NbSubDomains<< endl ;
+     for (Int4 i=0;i<Th.NbSubDomains;i++)
+       f << 3 << " " << reft[Th.Number(Th.subdomains[i].head)] << " " << 1 << " " 
+	 <<  Th.subdomains[i].ref << endl;
+     
+   }
+   if (Th.Gh.NbSubDomains)
+     {
+        f << "\nSubDomainFromGeom\n" << Th.Gh.NbSubDomains << endl ;
+       for (Int4 i=0;i<Th.NbSubDomains;i++)
+	 {  
+	 f << 2 << " " << Th.Number(Th.subdomains[i].edge)+1 << " " 
+	   <<  Th.subdomains[i].sens  << " " <<  Th.Gh.subdomains[i].ref << endl;
+	 } 
+   }
+   {
+     f << "\nVertexOnGeometricVertex\n"<<  Th.NbVerticesOnGeomVertex << endl;
+     for (Int4 i0=0;i0<Th.NbVerticesOnGeomVertex;i0++)
+       {
+	 VertexOnGeom & v =Th.VerticesOnGeomVertex[i0];
+	 assert(v.OnGeomVertex()) ;
+	 f << " " << Th.Number(( Vertex *)v)+1  
+	   << " " << Th.Gh.Number(( GeometricalVertex * )v)+1 
+	   << endl;
+       }
+   }
+   { 
+     f << "\nVertexOnGeometricEdge\n"<<  Th.NbVerticesOnGeomEdge << endl;
+     for (Int4 i0=0;i0<Th.NbVerticesOnGeomEdge;i0++)
+       {
+	 const VertexOnGeom & v =Th.VerticesOnGeomEdge[i0];
+	 assert(v.OnGeomEdge()) ;   
+	 f << " " << Th.Number((Vertex * )v)+1  ;
+	 f << " " << Th.Gh.Number((const  GeometricalEdge * )v)+1  ;
+	 f << " " << (Real8 ) v << endl;
+       }
+   }
+   {
+     Int4 i0,k=0;
+
+     for (i0=0;i0<Th.nbe;i0++)
+       if ( Th.edges[i0].on ) k++;
+     
+     f << "\nEdgeOnGeometricEdge\n"<< k << endl;
+      for (i0=0;i0<Th.nbe;i0++)
+	if ( Th.edges[i0].on ) 
+	  f << (i0+1) << " "  << (1+Th.Gh.Number(Th.edges[i0].on)) <<  endl;
+      if (Th.NbCrackedEdges)
+	{
+	  f << "\nCrackedEdges\n"<< Th.NbCrackedEdges << endl;	  
+	  for(i0=0;i0< Th.NbCrackedEdges; i0++) 
+	    {
+	      f << Th.Number(Th.CrackedEdges[i0].a.edge) << " " ;
+	      f  << Th.Number(Th.CrackedEdges[i0].b.edge) << endl;
+	    }
+	}
+   }  
+   if (&Th.BTh != &Th && Th.BTh.OnDisk && Th.BTh.name) 
+     {
+       int *mark=new int[Th.nbv];
+       Int4 i;
+       for (i=0;i<Th.nbv;i++)
+	 mark[i]=-1;
+       f << "\nMeshSupportOfVertices\n" <<endl;
+       WriteStr(f,Th.BTh.name);
+       f <<endl;
+       f << "\nIdentityOfMeshSupport" << endl;
+       WriteStr(f,Th.BTh.identity);
+       f<<endl;
+
+       f << "\nVertexOnSupportVertex" << endl;
+       f<< Th.NbVertexOnBThVertex << endl;
+       for(i=0;i<Th.NbVertexOnBThVertex;i++) {
+	 const VertexOnVertex & vov = Th.VertexOnBThVertex[i];
+	 Int4 iv = Th.Number(vov.v);
+	 mark[iv] =0;
+	 f << iv+1<< " " << Th.BTh.Number(vov.bv)+1 << endl;}
+
+       f << "\nVertexOnSupportEdge" << endl;
+       f << Th.NbVertexOnBThEdge << endl;
+       for(i=0;i<Th.NbVertexOnBThEdge;i++) {
+	 const VertexOnEdge & voe = Th.VertexOnBThEdge[i];
+	 Int4 iv = Th.Number(voe.v);
+	 //	 assert(mark[iv] == -1]);
+	 mark[iv] = 1;
+	 f << iv+1 << " " << Th.BTh.Number(voe.be)+1 << " " << voe.abcisse <<  endl;}
+       
+       f << "\nVertexOnSupportTriangle" << endl;   
+       Int4 k = Th.nbv -  Th.NbVertexOnBThEdge - Th.NbVertexOnBThVertex;
+       f << k << endl;
+       //       Int4 kkk=0;
+       CurrentTh=&Th.BTh;
+       for (i=0;i<Th.nbv;i++) 
+	 if (mark[i] == -1) {
+	   k--;
+	   Icoor2 dete[3];
+	   I2 I = Th.BTh.toI2(Th.vertices[i].r);
+	   Triangle * tb = Th.BTh.FindTriangleContening(I,dete);
+	   if (tb->link) // a true triangle
+	     {
+	       Real8 aa= (Real8) dete[1]/ tb->det, bb= (Real8) dete[2] / tb->det;
+	       f << i+1 << " " << Th.BTh.Number(tb)+1 << " " << aa << " " << bb << endl ;
+	     }
+	   else 
+	     {
+	       double aa,bb,det[3];
+	       TriangleAdjacent ta=CloseBoundaryEdgeV2(I,tb,aa,bb);
+	       int k = ta;
+	       det[VerticesOfTriangularEdge[k][1]] =aa;
+	       det[VerticesOfTriangularEdge[k][0]] = bb;
+	       det[OppositeVertex[k]] = 1- aa -bb;
+	       Triangle * tb = ta;
+	       f << i+1 << Th.BTh.Number(tb)+1 << " " << det[1] << " " << det[2] <<endl;
+	     }
+	 }
+       assert(!k);
+       delete [] mark;
+	 
+
+     }
+   f << "\nEnd" << endl;
+   //  Th.ConsLinkTriangle();
+   delete [] reft;
+   return f;
+   
+}
+
+
+
+void Geometry::Write(const char * filename)
+{
+  ofstream f(filename);
+  if (f)
+    {
+      if(verbosity>1)
+	cout << "  -- write geometry in file " << filename << endl;
+       if (name) delete name;
+       name = new char[strlen(filename)+1];
+       strcpy(name,filename);
+       OnDisk =1;
+       f << *this;
+    }
+}
+
+ostream& operator <<(ostream& f, const   Geometry & Gh) 
+{
+   Int4  NbCorner=0;
+   {
+     f << "MeshVersionFormatted 0" <<endl;
+     f << "\nDimension\n"  << 2 << endl;
+//     f << "\nIdentifier\n" ;
+//     WriteStr(f,Gh.identity);
+//     f <<endl;
+   }
+   int nbreqv=0;
+   { 
+     
+     f.precision(12);
+     f << "\nVertices\n" << Gh.nbv <<endl;
+     for (Int4 i=0;i<Gh.nbv;i++)
+       {
+	 GeometricalVertex & v =  Gh.vertices[i];
+	 if (v.Required()) nbreqv++;
+	 f << v.r.x << " " << v.r.y << " " << v.ref() << endl;
+	 if (v.Corner()) NbCorner++;
+       }
+   }
+   
+   int nbcracked=0;
+
+   {
+     int nbreq=0;
+     f << "\nEdges\n"<< Gh.nbe << endl;
+     for(Int4 ie=0;ie<Gh.nbe;ie++)
+       { 
+	 
+	 GeometricalEdge & e = Gh.edges[ie];
+	 if (e.Required()) nbreq++;
+	 if (e.Cracked()) { 
+	   Int4 ie1 = Gh.Number(e.link);
+	   if (ie <= ie1)  ++nbcracked;}
+	 f << Gh.Number(e[0])+1 << " " << Gh.Number(e[1])+1;
+	 f << " " << e.ref <<endl;
+       }
+     
+     if (nbcracked)
+       {
+	 f << "\nCrackedEdges\n"<< nbcracked<< endl;
+	 for(Int4 ie=0;ie<Gh.nbe;ie++)
+	   {
+	     GeometricalEdge & e = Gh.edges[ie];
+	     if (e.Cracked()) { 
+	       Int4  ie1 = Gh.Number(e.link);
+	       if (ie <= ie1)  f << ie+1 << " " << ie1+1<< endl;
+	     }
+	   }
+       }
+     if(nbreq)
+       {
+	 f << "\nRequiredEdges\n"<< nbreq<< endl;
+         for(Int4 ie=0;ie<Gh.nbe;ie++)
+           {
+             GeometricalEdge & e = Gh.edges[ie];
+             if (e.Required()) 
+	       f << ie+1 << endl;
+	   }
+       }
+     
+     
+     
+   }
+
+    f << "\nAngleOfCornerBound\n" 
+     << Gh.MaximalAngleOfCorner*180/Pi << endl;
+    if (NbCorner) 
+      {
+	f << "\nCorners\n" << NbCorner << endl;
+	for (Int4 i=0,j=0;i<Gh.nbv;i++)
+	  {
+	    GeometricalVertex & v =  Gh.vertices[i];
+	    if (v.Corner()) 
+	      j++,f << Gh.Number(v)+1 << (j % 5 ? ' ' : '\n');
+	  }
+        
+      
+      }
+
+    if(nbreqv)
+      {
+	f << "\nRequiredVertices\n"<< nbreqv<< endl;
+	for (Int4 j=0,i=0;i<Gh.nbv;i++)
+	  {
+	    GeometricalVertex & v =  Gh.vertices[i];
+	    
+	    if (v.Required()) 
+	      j++,f << i+1 << (j % 5 ? ' ' : '\n');
+	  }
+	f << endl;
+      }
+    
+    { 
+       Int4 i;
+       f << "\nSubDomainFromGeom\n" ;
+       f << Gh.NbSubDomains<< endl;
+       for (i=0;i<Gh.NbSubDomains;i++) 
+         f << "2 " << Gh.Number(Gh.subdomains[i].edge)+1 << " " << Gh.subdomains[i].sens 
+           << " " << Gh.subdomains[i].ref << endl;        
+     }
+     {
+       Int4 n=0,i;
+
+       for(i=0;i< Gh.nbe;i++)
+	 {
+	   if(Gh.edges[i].TgA() && Gh.edges[i][0].Corner() ) 
+	     n++;
+	   if(Gh.edges[i].TgB() && Gh.edges[i][1].Corner() ) 
+	     n++;
+	 }
+       if (n) {
+	 f << "TangentAtEdges " << n << endl;
+	 for(i=0;i< Gh.nbe;i++)
+	   {
+	     if (Gh.edges[i].TgA() && Gh.edges[i][0].Corner() ) 
+	       f << i+1 << " 1 " << Gh.edges[i].tg[0].x 
+		 << " " << Gh.edges[i].tg[0].y << endl;
+	     if (Gh.edges[i].TgB() && Gh.edges[i][1].Corner() ) 
+	       f << i+1 << " 2 " << Gh.edges[i].tg[1].x 
+		 << " " << Gh.edges[i].tg[1].y << endl;
+	   }
+	 
+       }}
+     //  f << " Not Yet Implemented" << endl;
+     
+     return f;
+}
+
+
+} // end of namespace bamg 
diff --git a/contrib/bamg/bamglib/Meshgibbs.cpp b/contrib/bamg/bamglib/Meshgibbs.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..5e9803afdbbb0077fb6e8babe6fe63dd625d15ba
--- /dev/null
+++ b/contrib/bamg/bamglib/Meshgibbs.cpp
@@ -0,0 +1,1067 @@
+// -*- Mode : c++ -*-
+//
+// SUMMARY  :      
+// USAGE    :        
+// ORG      : 
+// AUTHOR   : Frederic Hecht
+// E-MAIL   : hecht@ann.jussieu.fr
+//
+
+/*
+ 
+ This file is part of Freefem++
+ 
+ Freefem++ is free software; you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+ 
+ Freefem++  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 Lesser General Public License for more details.
+ 
+ You should have received a copy of the GNU Lesser General Public License
+ along with Freefem++; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <iostream>
+#include <fstream>
+using namespace std; 
+using namespace bamg; 
+#include "Mesh2.h"
+
+#define mmax(a,b)(a>b?a:b)
+#define mmin(a,b)(a<b?a:b)
+#define ffalse 0
+#define ttrue 1
+
+/*  -- translated by f2c (version of 23 May 1992  14:18:33).
+   You must link the resulting object file with the libraries:
+	-lF77 -lI77 -lm -lc   (in that order)
+*/
+
+
+#define integer long
+#define logical long
+
+int gibbs1_(integer* n,integer*  record,integer*  ptvois);
+int gibbs2_(integer* n,integer*  record,integer*  criter);
+int gibbsa_(integer* n,integer*  ptvois,integer*  vois,integer*  r,integer*  m,
+             integer*  nv,integer*  nx,integer*  ny,integer*  nn,integer*  w1,integer*  w2, 
+	integer* pfold,integer*  pfnew,integer*  impre,integer*  nfout);
+int gibbsb_(integer* x,integer*  y,integer*  n,integer*  ptvois,
+						integer*  vois,integer*  nx,integer*  ny,integer*  nv,integer*  nn,integer*  m,
+						integer*  wh,integer*  wl,integer* r, integer* impre, integer* nfout);
+int gibbsc_(integer* nz,integer*  nv,integer*  niveau,integer*  n,integer* );
+int gibbsd_(integer* racine,integer*  n,integer*  ptvois,integer*  
+							vois,integer*  nv,integer*  r,integer*  niveau);
+int gibbst_(integer* n,integer*  p,integer*  nv,integer*  nn,integer*  ptvois,integer*  vois,
+						integer*  m,integer*  r,integer*  new_,integer*  option, 
+						integer* pfnew,integer*  impre,integer*  nfout);
+
+/* Subroutine */ int gibbs1_(integer* n,integer*  record,integer*  ptvois)
+{
+    /* System generated locals */
+    integer i__1;
+
+    /* Local variables */
+    static integer crit, i, j, l, r, rec;
+
+/* -----------------------------------------------------------------------
+ */
+/*     routine appele par gibbs0 */
+/* -----------------------------------------------------------------------
+ */
+/*     but: trie record (ensemble de n sommet) telle que l'ordre des somm 
+*/
+/*     soit croissant (ordre du sommet i est ptvois(i+1)-ptvois(i)) */
+/* -----------------------------------------------------------------------
+ */
+
+    /* Parameter adjustments */
+    --ptvois;
+    --record;
+
+    /* Function Body */
+    if (*n <= 1) {
+	return 0;
+    }
+    l = *n / 2 + 1;
+    r = *n;
+L2:
+    if (l <= 1) {
+	goto L20;
+    }
+    --l;
+    rec = record[l];
+    crit = ptvois[record[l] + 1] - ptvois[record[l]];
+    goto L3;
+L20:
+    rec = record[r];
+    crit = ptvois[record[r] + 1] - ptvois[record[r]];
+    record[r] = record[1];
+    --r;
+    if (r == 1) {
+	goto L999;
+    }
+L3:
+    j = l;
+L4:
+    i = j;
+    j <<= 1;
+    if ((i__1 = j - r) < 0) {
+	goto L5;
+    } else if (i__1 == 0) {
+	goto L6;
+    } else {
+	goto L8;
+    }
+L5:
+    if (ptvois[record[j] + 1] - ptvois[record[j]] < ptvois[record[j + 1] + 1] 
+	    - ptvois[record[j + 1]]) {
+	++j;
+    }
+L6:
+    if (crit >= ptvois[record[j] + 1] - ptvois[record[j]]) {
+	goto L8;
+    }
+    record[i] = record[j];
+    goto L4;
+L8:
+    record[i] = rec;
+    goto L2;
+L999:
+    record[1] = rec;
+    return 0;
+} /* gibbs1_ */
+
+/* Subroutine */ int gibbs2_(integer* n,integer*  record,integer*  criter)
+{
+    static integer crit, i, j, l, r, rec;
+
+
+/*     trie record selon les valeurs de criter(record(.)) croissantes */
+
+
+    /* Parameter adjustments */
+    --criter;
+    --record;
+
+    /* Function Body */
+    if (*n <= 1) {
+	return 0;
+    }
+    l = *n / 2 + 1;
+    r = *n;
+L2:
+    if (l <= 1) {
+	goto L20;
+    }
+    --l;
+    rec = record[l];
+    crit = criter[rec];
+    goto L3;
+L20:
+    rec = record[r];
+    crit = criter[rec];
+    record[r] = record[1];
+    --r;
+    if (r == 1) {
+	goto L999;
+    }
+L3:
+    j = l;
+L4:
+    i = j;
+    j <<= 1;
+    if (j - r < 0) {
+	goto L5;
+    } else if (j == r) {
+	goto L6;
+    } else {
+	goto L8;
+    }
+L5:
+    if (criter[record[j]] < criter[record[j + 1]]) {
+	++j;
+    }
+L6:
+    if (crit >= criter[record[j]]) {
+	goto L8;
+    }
+    record[i] = record[j];
+    goto L4;
+L8:
+    record[i] = rec;
+    goto L2;
+L999:
+    record[1] = rec;
+    return 0;
+} /* gibbs2_ */
+
+/* Subroutine */ 
+int gibbsa_(integer* n,integer*  ptvois,integer*  vois,integer*  r,integer*  m,
+             integer*  nv,integer*  nx,integer*  ny,integer*  nn,integer*  w1,integer*  w2, 
+	integer* pfold,integer*  pfnew,integer*  impre,integer*  nfout)
+{
+    /* System generated locals */
+    integer i__1, i__2, i__3, i__4;
+
+    /* Builtin functions */
+    /* Subroutine */ int s_stop();
+
+    /* Local variables */
+    static integer nbcc, degi, bold, bnew, i, j, k, p, degre, x, y, p1, p2;
+/*    extern  Subroutine  int gibbs1_();*/
+    static integer pf;
+/*    extern  Subroutine int gibbsb_(), gibbsd_(), gibbst_();*/
+    static integer nbpass, niveau, pf1, option, old, new_, opt, new1;
+
+/* -----------------------------------------------------------------------
+ */
+/*  but: calculer une renumerotation des sommets d'un graphe defini par: 
+*/
+/*     par la methode de gibbs */
+/* -----------------------------------------------------------------------
+ */
+/*  entree */
+/* -------- */
+/*     n = nb de sommet du graphe */
+/*      les voisins d'un sommet i ont pour numero : */
+/*     ( vois(j) , j=ptvois(i),ptvois(i+1)-1 ) */
+
+/*     impre   parametre d'impression */
+/*     nfout   numero du fichier pour impression */
+
+/*  sortie */
+/*  ------ */
+/*     r(1:n) tableau donnant la nouvelle numerotation: */
+/*       r(i) = nouveau numero du sommet i */
+/*     pfolf = ancien  profile */
+/*     pfnew = nouveau profile */
+
+/*  tableau de travail : */
+/*  -------------------- */
+/*     m(n) */
+/*     nv(0:n+n) */
+/*     nx(n) */
+/*     ny(n) */
+/*     nn(0:n) */
+/*     w1(n) */
+/*     w2(n) */
+
+/* -----------------------------------------------------------------------
+ */
+/*     programmeur f. hecht  le 3/02/1987 */
+/* -----------------------------------------------------------------------
+ */
+
+/*     tri des voisins d'un sommet du graphe par degre croissant */
+/* --------------------------------------------------------------- */
+    /* Parameter adjustments */
+    --w2;
+    --w1;
+    --ny;
+    --nx;
+    --m;
+    --r;
+    --vois;
+    --ptvois;
+
+    /* Function Body */
+    p2 = ptvois[1] - 1;
+    i__1 = *n;
+    for (i = 1; i <= i__1; ++i) {
+	p1 = p2 + 1;
+	p2 = ptvois[i + 1] - 1;
+	i__2 = p2 - p1 + 1;
+	gibbs1_(&i__2, &vois[p1], &ptvois[1]);
+/*       if(impre.le.-9) then */
+/*        write (nfout,*) 'les voisin de ',i,'sont: ', (vois(j),j=p1,p
+2) */
+/*       endif */
+/* L10: */
+    }
+    i__1 = *n;
+    for (i = 1; i <= i__1; ++i) {
+	r[i] = 0;
+/* L20: */
+    }
+/*     boucle sur les composante connexe du graphe */
+    new_ = 0;
+    nbcc = 0;
+L30:
+    if (new_ < *n) {
+	++nbcc;
+/*       recherche d'une racine y (un sommet non numerote) de degree m
+ini */
+	y = 0;
+	degre = *n + 1;
+	i__1 = *n;
+	for (i = 1; i <= i__1; ++i) {
+	    if (r[i] <= 0) {
+		degi = ptvois[i + 1] - ptvois[i];
+		if (degi < degre) {
+		    degre = degi;
+		    y = i;
+		}
+	    }
+/* L40: */
+	}
+	if (y == 0) {
+	   return -3;/*  s_stop("fatal erreur  gibbs 2 : pb racine", 33L); */
+	}
+	gibbsd_(&y, n, &ptvois[1], &vois[1], nv, &r[1], &niveau);
+	nbpass = 0;
+L50:
+	++nbpass;
+	x = y;
+	p = niveau;
+	k = 0;
+	i__1 = nv[p + 1];
+	for (i = nv[p] + 1; i <= i__1; ++i) {
+	    ++k;
+	    m[k] = nv[i];
+/* L60: */
+	}
+	gibbs1_(&k, &m[1], &ptvois[1]);
+	i__1 = k;
+	for (i = 1; i <= i__1; ++i) {
+	    y = m[i];
+	    gibbsd_(&y, n, &ptvois[1], &vois[1], nv, &r[1], &niveau);
+	    if (niveau > p) {
+		goto L50;
+	    }
+/* L70: */
+	}
+	y = m[1];
+/*        if(impre.lt.0) then */
+/*          write(nfout,*) */
+/*     +  '    nb de pass pour trouver le pseudo diametre',nbpass */
+/*     +         ,' x=',x,',y=',y,' de la composante connexe ',nbcc */
+
+/*          write (nfout,*) ('-',i=1,78) */
+/*        endif */
+/*       optimisation de la descendance de la numerotation */
+/*       ------------------------------------------------- */
+	gibbsb_(&x, &y, n, &ptvois[1], &vois[1], &nx[1], &ny[1], nv, nn, &m[1]
+		, &w1[1], &w2[1], &r[1], impre, nfout);
+
+/*     renumerotation de cuthill mac kee avec la meilleur des 4 option
+s */
+/*     --------------------------------------------------------------
+--- */
+	pf = 1073741824;
+	option = -2;
+	new1 = new_;
+	for (opt = -2; opt <= 2; ++opt) {
+	    new_ = new1;
+	    if (opt != 0) {
+		gibbst_(n, &p, nv, nn, &ptvois[1], &vois[1], &m[1], &r[1], &
+			new_, &opt, &pf1, impre, nfout);
+		if (pf1 < pf) {
+		    pf = pf1;
+		    option = opt;
+		}
+	    }
+/* L80: */
+	}
+/*        if(impre.ne.0) write (nfout,*) '    on a choisi l''option ',
+ */
+/*     +             option,', new =',new */
+	new_ = new1;
+	gibbst_(n, &p, nv, nn, &ptvois[1], &vois[1], &m[1], &r[1], &new_, &
+		option, &pf1, impre, nfout);
+	goto L30;
+    }
+/*      if(impre.ne.0) write(nfout,*) */
+/*     +       '   nb de composante connexe du graphe =',nbcc */
+/*     calcul du profile */
+    *pfold = 0;
+    *pfnew = 0;
+    bnew = 0;
+    bold = 0;
+    i__1 = *n;
+    for (i = 1; i <= i__1; ++i) {
+	old = i;
+	new_ = r[i];
+	i__2 = ptvois[i + 1] - 1;
+	for (j = ptvois[i]; j <= i__2; ++j) {
+/* Computing MIN */
+	    i__3 = old, i__4 = vois[j];
+	    old = mmin(i__3,i__4);
+/* Computing MIN */
+	    i__3 = new_, i__4 = r[vois[j]];
+	    new_ = mmin(i__3,i__4);
+/* L100: */
+	}
+	*pfold = *pfold + i - old + 1;
+/* Computing MAX */
+	i__2 = bold, i__3 = i - old + 1;
+	bold = mmax(i__2,i__3);
+	*pfnew = *pfnew + r[i] - new_ + 1;
+/* Computing MAX */
+	i__2 = bnew, i__3 = r[i] - new_ + 1;
+	bnew = mmax(i__2,i__3);
+/* L110: */
+    }
+/*      if(impre.ne.0) then */
+/*        write(nfout,*)'profile  old  = ',pfold,', profile  new = ',pfnew
+ */
+/*        write(nfout,*)'1/2 bande old = ',bold ,', 1/2 band new = ',bnew 
+*/
+/*      endif */
+return 0;
+} /* gibbsa_ */
+
+/* Subroutine */ int gibbsb_(integer* x,integer*  y,integer*  n,integer*  ptvois,
+integer*  vois,integer*  nx,integer*  ny,integer*  nv,integer*  nn,integer*  m,
+integer*  wh,integer*  wl,integer* r, integer* impre, integer* nfout)
+{
+    /* System generated locals */
+    integer i__1, i__2;
+
+    /* Local variables */
+    static  flag_;
+    static integer i, j, k, p, s, h0, i1, l0, i2;
+/*    extern  Subroutine  int gibbs1_(); */
+    static integer lg;
+/*    extern  Subroutine  int gibbsd_(), gibbsc_();*/
+    static integer niveau, mxcanx, mxcany, nbc;
+
+/* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ */
+/* ...................................................................... 
+*/
+/*     attention on met la descente optimiser dans r <0 ou nulle */
+/* .......................................................................
+ */
+    /* Parameter adjustments */
+    --r;
+    --m;
+    --ny;
+    --nx;
+    --vois;
+    --ptvois;
+
+    /* Function Body */
+    gibbsd_(y, n, &ptvois[1], &vois[1], nv, &r[1], &niveau);
+    gibbsc_(&ny[1], nv, &niveau, n, &mxcany);
+    gibbsd_(x, n, &ptvois[1], &vois[1], nv, &r[1], &niveau);
+    p = niveau;
+    gibbsc_(&nx[1], nv, &niveau, n, &mxcanx);
+    flag_ = ffalse;
+    i__1 = *n;
+    for (i = 1; i <= i__1; ++i) {
+	if (nx[i] + ny[i] == p) {
+	    r[i] = -nx[i];
+	} else if (nx[i] >= 0) {
+	    flag_ = ttrue;
+	    r[i] = -1073741824;
+	} else {
+	    if (r[i] <= 0) {
+		r[i] = -1073741822;
+	    }
+	}
+/* L20: */
+    }
+    if (flag_) {
+/*       calcul des composantes connexe du graphe sans les sommets de 
+nn */
+/*       ------------------------------------------------------------
+--- */
+	j = *n;
+	k = 0;
+	nbc = 0;
+	nv[nbc] = j;
+L30:
+	++k;
+	if (k <= *n) {
+	    if (r[k] == -1073741824) {
+/*           recherche de la fermeture transitive partant de k
+ */
+		++nbc;
+		i = -1;
+		s = k;
+L40:
+		++i;
+		wl[i] = ptvois[s];
+		wh[i] = ptvois[s + 1];
+		++j;
+		nv[j] = s;
+		r[s] = -1073741823;
+L50:
+		if (i >= 0) {
+		    if (wl[i] < wh[i]) {
+			s = vois[wl[i]];
+			++wl[i];
+			if (r[s] == -1073741824) {
+			    goto L40;
+			}
+			goto L50;
+		    }
+		    --i;
+		    goto L50;
+		}
+		nv[nbc] = j;
+		m[nbc] = nbc;
+	    }
+	    goto L30;
+	}
+/*        if(impre.lt.0) write(nfout,*) */
+/*     +         ' nb de composante connexe du graphe reduit =',nbc */
+
+/* --------------- fin de construction des composantes connexes------
+--- */
+/*        nv(0)=n */
+/*        if(impre.le.-10) write(nfout,5555)'nv(0:n+n) = ',(nv(i),i=0,
+n+n) */
+	gibbs1_(&nbc, &m[1], nv);
+/*        if(impre.le.-10)write(nfout,5555)'trie m =',(m(i),i=1,nbc) 
+*/
+	i__1 = p;
+	for (i = 0; i <= i__1; ++i) {
+	    nn[i] = 0;
+/* L60: */
+	}
+	i__1 = *n;
+	for (i = 1; i <= i__1; ++i) {
+	    j = -r[i];
+	    if (j >= 0 && j <= p) {
+		++nn[j];
+	    }
+/* L70: */
+	}
+
+/*       boucle sur les composante connexes par ordre croissantes */
+/*       -------------------------------------------------------- */
+	for (k = nbc; k >= 1; --k) {
+	    i = m[k];
+	    i1 = nv[i - 1] + 1;
+	    i2 = nv[i];
+	    lg = i2 - i1 + 1;
+/*         if(impre.le.-7) */
+/*     +       write(nfout,*) k,' composante ',i,',lg=',lg,',i1,i2
+=',i1,i2 */
+/*         if(impre.le.-8) */
+/*     +       write (nfout,5555)' ',(nv(i),i=i1,i2) */
+	    h0 = 0;
+	    l0 = 0;
+	    i__1 = p;
+	    for (j = 0; j <= i__1; ++j) {
+		wh[j] = nn[j];
+		wl[j] = nn[j];
+/* L90: */
+	    }
+	    i__1 = i2;
+	    for (i = i1; i <= i__1; ++i) {
+		s = nv[i];
+		++wh[nx[s]];
+		++wl[p - ny[s]];
+/* L100: */
+	    }
+	    i__1 = p;
+	    for (j = 0; j <= i__1; ++j) {
+		if (wh[j] != nn[j]) {
+/* Computing MAX */
+		    i__2 = wh[j];
+		    h0 = mmax(i__2,h0);
+		}
+		if (wl[j] != nn[j]) {
+/* Computing MAX */
+		    i__2 = wl[j];
+		    l0 = mmax(i__2,l0);
+		}
+/* L110: */
+	    }
+	    if (h0 < l0 || h0 == l0 && mxcanx <= mxcany) {
+/*           if(impre.le.-2) write(nfout,*) */
+/*     +       '         h0 = ',h0,',l0 = ',l0,'  ------- XXXX
+ --------' */
+		i__1 = i2;
+		for (i = i1; i <= i__1; ++i) {
+		    s = nv[i];
+		    r[s] = -nx[s];
+		    ++nn[-r[s]];
+/* L120: */
+		}
+	    } else {
+/*           if (impre.le.-2) write(nfout,*) */
+/*     +       '         h0 = ',h0,',l0 = ',l0,'  ------- YYYY
+ --------' */
+		i__1 = i2;
+		for (i = i1; i <= i__1; ++i) {
+		    s = nv[i];
+		    r[s] = -p + ny[s];
+		    ++nn[-r[s]];
+/* L130: */
+		}
+	    }
+/* L140: */
+	}
+    }
+/*     on met les nouveaux niveaux de la descendance optimiser dans nn */
+/*     ----------------------------------------------------------------- 
+*/
+    i__1 = *n;
+    for (i = 1; i <= i__1; ++i) {
+	if (r[i] > 0) {
+	    nn[i] = -1;
+	} else if (r[i] == -1073741822) {
+	    nn[i] = -2;
+	} else {
+	    nn[i] = -r[i];
+	}
+/* L150: */
+    }
+/*      if(impre.le.-10)write (nfout,5555)' nn(i)=',(nn(i),i=1,n) */
+/* 5555  format('            --------   ',a,/,5(15x,10(i5)/)) */
+return 0;} /* gibbsb_ */
+
+/* Subroutine */ int gibbsc_(integer* nz,integer*  nv,integer*  niveau,integer*  n,integer*  mxz)
+{
+    /* System generated locals */
+    integer i__1, i__2, i__3;
+
+    /* Local variables */
+    static integer i, j;
+
+/* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ */
+    /* Parameter adjustments */
+    --nz;
+
+    /* Function Body */
+    i__1 = *n;
+    for (i = 1; i <= i__1; ++i) {
+	nz[i] = -1;
+/* L10: */
+    }
+    *mxz = 0;
+    i__1 = *niveau;
+    for (i = 0; i <= i__1; ++i) {
+/* Computing MAX */
+	i__2 = *mxz, i__3 = nv[i + 1] - nv[i];
+	*mxz = mmax(i__2,i__3);
+	i__2 = nv[i + 1];
+	for (j = nv[i] + 1; j <= i__2; ++j) {
+	    nz[nv[j]] = i;
+/* L20: */
+	}
+    }
+return 0;} /* gibbsc_ */
+
+/* Subroutine */ int gibbsd_(integer* racine,integer*  n,integer*  ptvois,integer*  vois,integer*  nv,integer*  r,integer*  niveau)
+{
+    /* System generated locals */
+    integer i__1, i__2;
+
+    /* Local variables */
+    static integer i, k, s, sv, stk, stk1, stk2;
+
+/* -----------------------------------------------------------------------
+ */
+/*     but construire la structure des descendant de racine  du graphe */
+/* -----------------------------------------------------------------------
+ */
+/*     sortie : */
+/*     -------- */
+/*     nv est la structure des niveaux */
+/*     les sommets du niveau (i =0,niveau_ sont defini par : */
+/*        (nv(j),j=nv(i),nv(i+1)-1) */
+
+/*     le tableau r(i) n'est modifier que sur les sommets */
+/*       de la composante connexe du graphe contenant la racine */
+
+/* -----------------------------------------------------------------------
+ */
+
+/*     on demark tout les sommets non remuneroter */
+/* -------------------------------------------------- */
+    /* Parameter adjustments */
+    --r;
+    --vois;
+    --ptvois;
+
+    /* Function Body */
+    i__1 = *n;
+    for (i = 1; i <= i__1; ++i) {
+	if (r[i] < 0) {
+	    r[i] = 0;
+	}
+/* L10: */
+    }
+
+/*    initialisation */
+
+    stk = *n - 1;
+    nv[0] = stk;
+    stk2 = stk;
+    *niveau = 0;
+    ++stk;
+    nv[stk] = *racine;
+    r[*racine] = -1;
+L20:
+    if (stk2 < stk) {
+	++(*niveau);
+	stk1 = stk2 + 1;
+	nv[*niveau] = stk;
+	stk2 = stk;
+/*        print *,' ------- niveau =',niveau,' stk=',stk1,stk2 */
+	i__1 = stk2;
+	for (k = stk1; k <= i__1; ++k) {
+	    s = nv[k];
+/*         print *,'----------------- s=',s */
+	    i__2 = ptvois[s + 1] - 1;
+	    for (i = ptvois[s]; i <= i__2; ++i) {
+/*               pour tout les sommets (sv) voisin */
+/*                d'un sommet (s) du niveau precedent */
+		sv = vois[i];
+/*          print *,' voisin =',sv */
+/*               si le sommet n'est pas marque on le marque et
+ on l'ajout */
+		if (r[sv] == 0) {
+		    ++stk;
+		    nv[stk] = sv;
+		    r[sv] = -1;
+		}
+/* L30: */
+	    }
+/* L40: */
+	}
+	goto L20;
+    }
+    --(*niveau);
+/*      call pnv(' gibbsd ',n,nv,niveau) */
+return 0;} /* gibbsd_ */
+
+
+/* Subroutine */ int gibbst_(integer* n,integer*  p,integer*  nv,integer*  nn,integer*  ptvois,integer*  vois,integer*  m,integer*  r,integer*  new_,integer*  option, 
+	integer* pfnew,integer*  impre,integer*  nfout)
+{
+    /* System generated locals */
+    integer i__1, i__2, i__3, i__4, i__5;
+
+    /* Local variables */
+    static integer nbsc, bnew, knew, step, plus, i, j, k, s, debut, i1, i2;
+/*    extern Subroutine int gibbs2_();*/
+    static integer fin;
+
+
+/*     construction de la stucture de niveau dans nv a partir de nn */
+/*     ------------------------------------------------------------ */
+    /* Parameter adjustments */
+    --r;
+    --m;
+    --vois;
+    --ptvois;
+
+    /* Function Body */
+    nv[0] = *n;
+    i__1 = *p + 1;
+    for (i = 1; i <= i__1; ++i) {
+	nv[i] = 0;
+/* L150: */
+    }
+    i__1 = *n;
+    for (i = 1; i <= i__1; ++i) {
+	if (nn[i] >= 0) {
+	    ++nv[nn[i] + 1];
+	}
+/* L160: */
+    }
+    i__1 = *p;
+    for (i = 0; i <= i__1; ++i) {
+	nv[i + 1] += nv[i];
+/* L170: */
+    }
+    i__1 = *n;
+    for (i = 1; i <= i__1; ++i) {
+	if (nn[i] >= 0) {
+	    j = nn[i];
+	    ++nv[j];
+	    nv[nv[j]] = i;
+	}
+/* L180: */
+    }
+    for (i = *p; i >= 0; --i) {
+	nv[i + 1] = nv[i];
+/* L190: */
+    }
+    nv[0] = *n;
+    nbsc = nv[*p + 1] - nv[0];
+/*     --- fin de la construction ------------------------------------ */
+    if (*option == -2) {
+	i__1 = *impre - 1;
+    }
+    i__1 = *n;
+    for (i = 1; i <= i__1; ++i) {
+	m[i] = *n * 3 + ptvois[i + 1] - ptvois[i];
+/* L10: */
+    }
+    if ((((int)*option) == 1)||(((int)*option) == -1)) {
+	debut = 0;
+	fin = *p;
+	step = 1;
+    } else {
+	debut = *p;
+	fin = 0;
+	step = -1;
+    }
+    i__1 = fin;
+    i__2 = step;
+    for (i = debut; i__2 < 0 ? i >= i__1 : i <= i__1; i += i__2) {
+	i1 = nv[i] + 1;
+	i2 = nv[i + 1];
+	i__3 = i2 - i1 + 1;
+	gibbs2_(&i__3, &nv[i1], &m[1]);
+	i__3 = i2;
+	for (j = i1; j <= i__3; ++j) {
+	    s = nv[j];
+	    i__4 = ptvois[s + 1] - 1;
+	    for (k = ptvois[s]; k <= i__4; ++k) {
+/* Computing MIN */
+		i__5 = m[vois[k]];
+		m[vois[k]] = mmin(i__5,j);
+/* L20: */
+	    }
+/* L30: */
+	}
+/* L40: */
+    }
+    if (*option > 0) {
+	knew = *new_;
+	plus = 1;
+    } else {
+	knew = *new_ + nbsc + 1;
+	plus = -1;
+    }
+    *new_ += nbsc;
+/*      if(option.gt.0) then */
+/*        do 60 k = debut , fin , step */
+/*          do 60 j = nv(k+1),nv(k)+1,-1 */
+/*            knew = knew + plus */
+/*            r(nv(j)) = knew */
+/* 60      continue */
+/*      else */
+    i__2 = fin;
+    i__1 = step;
+    for (k = debut; i__1 < 0 ? k >= i__2 : k <= i__2; k += i__1) {
+	i__3 = nv[k + 1];
+	for (j = nv[k] + 1; j <= i__3; ++j) {
+	    knew += plus;
+	    r[nv[j]] = knew;
+/* L70: */
+	}
+    }
+/*      endif */
+    *pfnew = 0;
+    bnew = 0;
+    i__3 = *n;
+    for (i = 1; i <= i__3; ++i) {
+	k = r[i];
+	if (k > 0) {
+	    i__1 = ptvois[i + 1] - 1;
+	    for (j = ptvois[i]; j <= i__1; ++j) {
+		if (r[vois[j]] > 0) {
+/* Computing MIN */
+		    i__2 = k, i__4 = r[vois[j]];
+		    k = mmin(i__2,i__4);
+		}
+/* L100: */
+	    }
+	    *pfnew = *pfnew + r[i] - k + 1;
+/* Computing MAX */
+	    i__1 = bnew, i__2 = r[i] - k + 1;
+	    bnew = mmax(i__1,i__2);
+	}
+/* L110: */
+    }
+/*      if(impre.lt.0.or.impre.gt.2) then */
+/*        write(nfout,*) '      option =',option,', profile =',pfnew */
+/*     +       ,', 1/2 bande =',bnew,', new=',new,', nbss composante=',nbsc
+ */
+/*      endif */
+return 0;} /* gibbst_ */
+
+/* function */ 
+int Triangles::gibbsv (integer* ptvoi,
+		       integer* vois,integer* lvois,integer* w,integer* v)
+{
+  /* System generated locals */
+  integer  i__2;
+  
+  /* Local variables */
+  integer i, j, k, T, ss, iii, ptv, ptv1;
+  integer nbss = nbv; 
+  /*--- Prepare les donees pour gibbsa en construisant ptvoi, vois, lvois -
+    ------------*/
+  /*     in */
+  /*     ---   nbnt =3 pour des triangles 2D, */
+  /* 			nbt =  nb de triangle */
+  /*    		nbss = nb de sommets */
+  /*           nsea = numeros de 3 sommets de chaque triangle (me) */
+  /*     out */
+  /*     --- 	ptvoi, vois, lvois, err */
+  /*      tableaux de travail w, v */
+  /*-----------------------------------------------------------------------
+    ----------*/
+  /* Parameter adjustments */
+  --v;
+  --w;
+  --vois;
+  --ptvoi;
+  long nt = nbt-NbOutT;
+  /* Function Body */
+  for (i = 1; i <= nbss; ++i) {
+    w[i] = -1;
+    ptvoi[i] = 0; }
+  ptvoi[nbss + 1] = 0;
+  for (i = 0; i < nt; ++i) 
+    { 
+      assert(triangles[i].link);
+      for (j = 0; j < 3; ++j)
+	{
+	  ss = Number(triangles[i][j])+1;
+	  ++ptvoi[ss + 1];
+	  w[ss] = 0;
+	}
+    }
+  
+  for (i = 1; i <= nbss; ++i) 
+    ptvoi[i + 1] += ptvoi[i];
+  
+  for (i = 0; i < nt; ++i)
+    if (triangles[i].link) 
+      for (j = 0; j < 3; ++j) 
+	{
+	  ss = Number(triangles[i][j])+1;
+	  ++ptvoi[ss];
+	  v[ptvoi[ss]] = i;
+	}
+  
+    ptv1 = 0;
+    iii = 1;
+    for (i = 1; i <= nbss; ++i) {
+      ptv = ptv1 + 1;
+      ptv1 = ptvoi[i];
+      ptvoi[i] = iii;
+      i__2 = ptv1;
+      for (j = ptv; j <= i__2; ++j) {
+	T = v[j];
+	for (k = 0; k < 3; ++k) {
+	  ss = Number(triangles[T][k])+1;  /*  nsea[k + T * nsea_dim1]; */
+	  if (w[ss] != i) {
+	    w[ss] = i;
+	    if (iii > *lvois)  return 2 ;
+	    /* print*,'pas assez de place memoire' */
+	    
+	    vois[iii] = ss;
+	    ++iii;}
+	}
+      }
+    }
+    ptvoi[nbss + 1] = iii;
+    *lvois = iii - 1;
+    return 0; /* OK */
+    return 0;} /* gibbsv_ */
+
+int Triangles::gibbs()
+/* -------- 
+	renumber vertices by gibbs method; updates triangle and edge array
+	in:   mesh  
+	out:   mesh
+ 	auxiliary arrays: ptvois,vois,r,m,nv,nx,ny,nn,w1,w2,f 
+ 	all of size nv+1 except vois (10(nv+1)) and nv (2(nv+1))
+ 	err = -1 : memory alloc pb; err = -3: fatal erreur  gibbs 2 : pb racine
+*/
+{
+  long nv = nbv;
+  long nt = nbt-NbOutT;
+    long i, j, pfold, pfnew;
+    long* ptvois=NULL;
+    long* vois=NULL;
+    long* nn =NULL;
+    long* r =NULL;
+    long* m =NULL;
+    long* nnv =NULL;
+    long* nx =NULL;
+    long* ny =NULL;
+    long* w1 =NULL;
+    long* w2=NULL;
+    long nbvoisin =  10*nv;
+    long printint=0, iodev=6;
+    int err=0;
+    ptvois = new long[nv+1]; 		//(long*)calloc((long)(nv + 1) , sizeof(long));
+    nn = 	 new long[3*nt]; 			//(long*)calloc(3 * nt ,sizeof(long));
+    vois = 	 new long[nbvoisin+10];	//(long*)calloc((long)(nbvoisin + 10) , sizeof(long)); 
+    r = 	 new long[nv+1];				//(long*)calloc((long)(nv + 1) , sizeof(long));
+    if((!ptvois)||(!nn)||(!vois)||(!r)) return -1;
+    err = gibbsv(ptvois,vois,&nbvoisin,r,nn) ;
+    delete [] nn;					// free(nn);
+    if(err==0)
+      {
+	m = new long[nv+1];
+	nn = new long[nv+1];
+	nnv = new long[(nv+1)<<1];
+	nx = new long[nv+1];
+	ny = new long[nv+1];
+	w1 = new long[nv+1];
+	w2 = new long[nv+1];
+	long lnv = nv;
+	err = gibbsa_ (&lnv, ptvois, vois, r, m, nnv, nx, ny, nn, w1, w2, &pfold, &pfnew,
+		      &printint, &iodev);
+	delete [] m;
+	delete [] nnv;
+	delete [] nn;
+	delete [] nx;
+	delete [] ny;
+	delete [] w1;
+	delete [] w2;
+      }
+    
+    delete [] vois;
+  delete [] ptvois;
+  /*          
+	      if (err == 0 && (pfnew <= pfold))
+	      {
+	      A<bVertex> f(nv);
+	      for (i = 0; i < nv; ++i)
+	      {	f[i].x = v[i].x;
+	      f[i].y = v[i].y;
+	      f[i].where = v[i].where;
+	      }
+	      for (i = 0; i < nv; ++i)
+	      {	v[r[i] - 1].x = f[i].x;
+	 		v[r[i] - 1].y = f[i].y;
+	 		v[r[i] - 1].where = f[i].where;
+			}
+			
+       for (j = 0; j < nt; ++j)  // updates triangle array
+       for (i = 0; i < 3; i++)
+       t[j].v[i] = &v[r[no(t[j].v[i])] - 1];
+       
+       for (j = 0; j < ne; ++j)	// updates edge array
+       {
+	   		e[j].in = &v[r[no(e[j].in)] - 1];
+	   		e[j].out = &v[r[no(e[j].out)] - 1];
+			}
+			f.destroy();
+       if (!NumThinGrid) 
+       {  NumThinGrid= new int [nv];
+       for (i=0;i<nv;i++) NumThinGrid[i]=i;// Same numbering 
+       }
+       for (i=0;i<nv;i++) NumThinGrid[i]=r[NumThinGrid[i]]-1;  
+       
+       }
+  */
+  delete [] r;
+  return err;
+} 
+			
+/*  message d'erreur:         *err = 2;    print*,'pas assez de place memoire'   */
diff --git a/contrib/bamg/bamglib/Meshio.cpp b/contrib/bamg/bamglib/Meshio.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..6e7ac404e044541b8d68a630fec1543f6eb63dd8
--- /dev/null
+++ b/contrib/bamg/bamglib/Meshio.cpp
@@ -0,0 +1,373 @@
+// -*- Mode : c++ -*-
+//
+// SUMMARY  :      
+// USAGE    :        
+// ORG      : 
+// AUTHOR   : Frederic Hecht
+// E-MAIL   : hecht@ann.jussieu.fr
+//
+
+/*
+ 
+ This file is part of Freefem++
+ 
+ Freefem++ is free software; you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+ 
+ Freefem++  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 Lesser General Public License for more details.
+ 
+ You should have received a copy of the GNU Lesser General Public License
+ along with Freefem++; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include "meshtype.h"
+#include "Meshio.h"
+namespace bamg {
+
+const char *OFortranUnFormattedFile::unkown("unkown file name");
+void (*MeshIstreamErrorHandler)(ios & ) =0;
+///////////////////////////////////////////////////////////
+ void WriteStr(ostream & out,char * str)
+{ 
+  int i=0;
+  char c;
+  out << '"' ;
+  while (i++,c=*str++) {
+   if (i==70) 
+      cout << " //\n",i=0;
+   if (c == '"') out << "\"\"" ;
+   else out << c ;}
+ out << '"' ;
+}
+///////////////////////////////////////////////////////////
+double * ReadbbFile(const char * file,long & nbsol,long & lsol,const int typesol,const int dim)
+{
+
+  MeshIstream frbb(file);
+  int dimlu,typesollu;
+  long i;
+ double *sol =0;
+  frbb >>    dimlu >> nbsol >> lsol >> typesollu ;
+  if(typesol != typesollu )
+    { 
+      cerr << " incorrect type of solution (read) " << typesollu << " != (wanted) " <<  typesol << endl;
+      cerr << "  or       dim  of solution (read) " << dimlu  << " != (wanted) " <<  dim << endl;
+      nbsol=0;
+      lsol=0;
+    }
+  else
+    {
+      sol = new double[lsol*nbsol];
+      double *s=sol;
+      for(  i=0;i<lsol;i++)
+	for (long j=0;j<nbsol;j++)
+	  frbb >>  *s++ ;
+      //      frbb.close();
+    }
+
+  
+  return sol;
+}
+
+///////////////////////////////////////////////////////////
+double * ReadBBFile(const char * file,long & nbsol,long & lsol,int *& typesols,
+  const int dim,const int typesol)
+{
+
+  MeshIstream frbb(file);
+  int dimlu,typesollu;
+  typesols = 0;
+  long i,n=0;
+  double *sol =0;
+  int sizeoftype[] = { 1, dim ,dim * (dim+1) / 2, dim * dim } ;
+  // char * charoftype[] = {  "Scalar" , "dim Vector" ,"dim x dim Sym-Matric","dim x dim Full-Matric" } ;
+  frbb >>    dimlu >> nbsol ;
+  typesols = new int [nbsol] ;
+  for (i=0;i<nbsol;i++)
+    {
+     frbb >> typesols[i];
+     typesols[i]--;
+     if (typesols[i]<0 || typesols[i]>= 4)
+       {
+	 cerr << " Error reading BBFile the type solution " << i+1 << " is " << typesols[i]+1 
+	      << " is not in [1..4] " << endl;
+	   frbb.ShowIoErr(998);
+	 nbsol=0;
+	 lsol=0;
+	 delete [] typesols;
+	 typesols=0;
+	 return 0; 
+       }
+     n += sizeoftype[ typesols[i]];
+    }
+  frbb >> lsol >> typesollu ;
+  if(typesol != typesollu )
+    { 
+      cerr << " incorrect type of solution (read) " << typesollu << " != (wanted) " <<  typesol << endl;
+      cerr << "  or       dim  of solution (read) " << dimlu  << " != (wanted) " <<  dim << endl;
+      frbb.ShowIoErr(999);
+      nbsol=0;
+      lsol=0;
+    }
+  else
+    {
+      if (verbosity> 5)
+	cout << "     read BB file " << file << "  with nbsol " << nbsol << " total nb of field = " << n << endl; 
+      if (verbosity>9) 
+	for (i=0;i<nbsol;i++)
+	  cout << "      the type of solution " << i+1 << " is " <<  sizeoftype[ typesols[i]]  
+	       << " and  the number of sub-field are " << sizeoftype[ typesols[i]] << endl; 
+      sol = new double[lsol*n];
+      double *s=sol;
+      for(  i=0;i<lsol;i++)
+	for (long j=0;j<n;j++)
+	  frbb >>  *s++ ;
+      //      frbb.close();
+    }
+
+  
+  return sol;
+}
+
+
+void MeshIstream::ShowIoErr(int s) {
+  LineError = 1;
+  if (CurrentFile)
+    cerr << " In  file " <<  CurrentFile ;
+  cerr << ", Erreur Lecture "  << s << 
+    ", good="  << (s & ios::goodbit) <<
+    ", bad=" << (s & ios::badbit) <<
+    ", fail=" << (s & ios::failbit) <<
+    ", eof=" << (s & ios::eofbit) << " Line " << LineNumber <<
+    endl;
+  if(!in.eof()) 
+    {
+      in.clear(ios::goodbit);
+      int i=0;
+      char c;
+      cerr << " the next character :" ;
+      while (i++<80 && in.get(c) && (c != '\n' || i < 30 ))
+	cerr.put(c);
+      cerr << endl; 
+    }
+  if (MeshIstreamErrorHandler)
+    MeshIstreamErrorHandler(in);
+  else 
+   { 
+    in.clear(ios::failbit);
+   }
+}
+int  MeshIstream::IsString(const char* s)
+{ 
+  int n=0;
+  char c;
+  const char * ss = s;
+  while (in.get(c) && c ==' ') n++; // eat whitespace 
+  if (in.good())
+    while ( *ss && c == *ss && in.get(c) )
+      ss++; 
+
+  if (*ss) { // no 
+    if (verbosity>9) 
+      cout << "IsString: not " << s << " " << n  << "  putback " << ss-s << " :" << c  ;
+    if (in.good())
+      in.putback(c),ss--;
+    while(ss-s>0)
+      {
+	cout << *ss ;
+	in.putback(*ss--);
+      };
+    if (verbosity>9) 
+      cout << ":"<< endl;
+    return 0;}
+  else return 1;
+}
+
+ char * MeshIstream::ReadStr()
+{ 
+  static char buf[1025];
+  int  instr=0,k=0;
+  char * b=buf, bb=0, *bend=buf+1023;
+  
+  for (b=buf;b<bend &&  in.get(*b);instr && b++)
+    {
+      int kold = k;
+      if(isspace(*b))
+	{
+	  if (*b == '\n') LineNumber++;
+	  if (instr && !bb) break;
+	}
+      else if (*b == bb) 
+	{
+	  if(++k%2) b--;
+	}
+      else if( !instr) 
+	{
+	  instr =1;
+	  if  ((*b == '"') ||  (*b == '\'' ) )
+	    bb=*b--,k=0;
+	}
+      else
+	instr =1;
+      
+      if( k%2 && kold==k ) // even and fin
+	break;
+    }
+  *b=0;
+  in.clear(ios::goodbit);
+  //  cout << " l = " << b-buf << " " ;
+  char * r = new char [b-buf+1];
+  strcpy(r,buf);
+  return r ;  
+}
+///////////////////////////////////////////////////////////
+OFortranUnFormattedFile::~OFortranUnFormattedFile()
+{
+  // save the last record 
+  if (l==0) { // l rec no set --
+    l=where();
+  if (verbosity>9)
+    cout << " size of last record  = " 
+	 << l << " n = " << nb_rec << " i= " << i << endl;
+   if (!f->good()) Error(3);
+    f->seekp(i-sizeof(long));
+   if (!f->good()) Error(3);
+    f->write((char*)&l,sizeof(l)); 
+    if (!f->good()) Error(3);
+   n=j;
+  }
+
+  f->seekp(n);
+  if (!f->good()) Error(3);
+   f->write((char*) &l,sizeof(l));
+  if (!f->good()) Error(3);
+   
+  if (f && to_close) {
+    if (verbosity>9)
+      cout << "delete OFortranUnFormattedFile " << file_name 
+	   << " @end  = " << n <<  endl;
+    delete f;} f=0;
+}
+
+IFortranUnFormattedFile::~IFortranUnFormattedFile()
+{
+  if (f && to_close) {
+    if (verbosity>9)
+      cout << " delete IFortranUnFormattedFile" << file_name 
+	   << "  @end = " << n <<  endl;
+    delete f;} f=0;
+}
+
+long IFortranUnFormattedFile::Record()
+{
+  nb_rec++;
+  n += sizeof(long);
+  f->seekg(n);
+  f->read((char*)&l,sizeof(l));
+  if (!f->good()) Error(3);
+  i=j= n+sizeof(l); 
+  n +=   l + sizeof(l) ; // end 
+  if (verbosity>9)
+  cout << " Read  rec end =" << n << " l=  " << l 
+       << " current= " << j << " begin= " << i << endl;
+  return l;
+}
+
+long OFortranUnFormattedFile::Record(long ll) //
+{
+  if (j==4 && l==0) 
+    { 
+      l=ll;
+      f->seekp(0);
+      f->write((char*)&ll,sizeof(l));
+      if (!f->good()) Error(3);
+      return 0;
+    }
+  if (n>=0) 
+    {
+      if (l==0) 
+	{ // l rec no set --
+	  l=where();
+	  if (verbosity>9)
+	    cout << " set len  of rec  " << nb_rec  << " = " << l 
+		 << " @ " << i-sizeof(long) << endl;
+
+	  f->seekp(i-sizeof(long));
+	  f->write((char*)&l,sizeof(l)); 
+	  n=j;
+	}
+      f->seekp(n);
+      f->write((char*)&l,sizeof(l)); 
+      if (!f->good()) Error(3);
+    }
+  else 
+    f->seekp(0);
+  n += sizeof(long);
+  nb_rec++;
+  f->write((char*)&ll,sizeof(l));
+  if (!f->good()) Error(3);
+  
+  l=ll;
+  n +=  sizeof(long);
+  j = n;
+  i = n;
+  n +=   l;
+  if (verbosity>9)
+    cout << " Write rec end =" << n << " l=  " << l 
+	 << " current= " << j << " begin= " << i << endl;
+  return l;
+}
+void OFortranUnFormattedFile::Error(int err)
+{
+  cerr << "Fatal Error Output FortranUnFormattedFile " << endl;
+  if (err==0) 
+    cerr << "-- Error openning ";
+  else if (err==1)
+    cerr<< "-- OverFlow write ";
+  else if (err==2)
+    cerr<< "-- Erreur  write " ;
+  else if (err==3)
+    cerr<< "-- Erreur  write record info " ;
+  else 
+    cerr << " unkown err " << err ;
+
+  cerr << " Record number = "    << nb_rec << endl
+       << " read position  in file " << j << " < " << n 
+       << " =  end on record " << endl;
+  cerr << " position in the record = " << where() 
+       << " length of record = " << l <<endl;
+  cerr 	<< " file = " << file_name<< endl ;
+  MeshError(900);
+  //  throw(ErrorMesh("exit",1));
+}
+void IFortranUnFormattedFile::Error(int err)
+{
+  cerr << "Fatal Error Input FortranUnFormattedFile " << endl;
+  if (err==0) 
+    cerr << " Error openning ";
+  else if (err==1)
+    cerr<< " OverFlow read";
+  else if (err==2)
+    cerr<< " Erreur  read" ;
+  else if (err==3)
+    cerr<< " Erreur  read record info " ;
+  else 
+    cerr << " unkown err " << err ;
+
+  cerr << " Record number = "    << nb_rec << endl
+       << " read position  in file " << j << " < " << n 
+       << " =  end on record " << endl;
+  cerr << " position in the record = " << where() 
+       << " length of record = " << l <<endl;
+  cerr 	<< " file = " << file_name<< endl ;
+    MeshError(900);
+    //  throw(ErrorMesh("exit",1));
+}
+
+}// end of namespace bamg 
diff --git a/contrib/bamg/bamglib/Meshio.h b/contrib/bamg/bamglib/Meshio.h
new file mode 100644
index 0000000000000000000000000000000000000000..7c12651075bdcfb8cf8b1c2dfd8a0d2e77598b57
--- /dev/null
+++ b/contrib/bamg/bamglib/Meshio.h
@@ -0,0 +1,245 @@
+// -*- Mode : c++ -*-
+//
+// SUMMARY  :      
+// USAGE    :        
+// ORG      : 
+// AUTHOR   : Frederic Hecht
+// E-MAIL   : hecht@ann.jussieu.fr
+//
+
+/*
+ 
+ This file is part of Freefem++
+ 
+ Freefem++ is free software; you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+ 
+ Freefem++  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 Lesser General Public License for more details.
+ 
+ You should have received a copy of the GNU Lesser General Public License
+ along with Freefem++; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include <cstdio>
+#include <iostream>
+#include <fstream>
+#include "error.hpp"
+#include <cstring>
+#include <cstdlib>
+#include <cctype>
+using namespace std;
+//  PB compilo HP aCC 
+#if defined(__hpux) || defined(__SUNPRO_CC) 
+#define IOS_OPENMODE int
+#else
+#define IOS_OPENMODE ios::openmode
+#endif
+extern  long verbosity ;
+
+namespace bamg {
+
+
+extern  void (*MeshIstreamErrorHandler)(ios & );
+
+void WriteStr(ostream & out,char * str);
+
+double * ReadbbFile(const char * file,long & nbsol,long & lsol,const int dim=2,const int typesol=2);
+double * ReadBBFile(const char * file,long & nbsol,long & lsol,int *& typesols,const int dim=2,const int typesol=2);
+// solution at vertex (P1)
+
+union Char4orLong {  char c[4];    long l;} ;
+
+class  MeshIstream {
+public:
+  istream  & in ;
+  const char * CurrentFile;
+  //  ifstream  fin;
+  int LineNumber,LineError,opened;
+
+
+  istream & cm ()//  mange les blancs et les commentaire 
+  { 
+    char c;
+    int cmm=0;
+    while ( in.get(c) &&  
+	    ( isspace(c) ?
+	      (( ( c=='\n'|| c==char(12) || c==char(15)) && (LineNumber++,cmm=0)),1) 
+	      : (cmm || (c=='#' && (cmm=1) )) ) 
+	    ) ((void ) 0);
+	   if (in.good()) in.putback(c);
+    return in;
+  }
+
+  // void rewind(){ fin.clear();fin.seekg(0);}
+    
+  void eol()// go to end of line
+  { 
+    char c;
+    while ( in.get(c) &&  ( c!='\n') && ( c!='\r')) (void) 0;
+  }
+  void ShowIoErr(int );
+  MeshIstream  & err () 
+  { 
+    if ( ! in.good() ) ShowIoErr(in.rdstate());
+    return *this;
+  }
+  //  MeshIstream(istream & i): in(i),CurrentFile(0),LineNumber(1),LineError(0) {}
+
+  MeshIstream(const char * file_name)
+    : in(*new ifstream(file_name)),CurrentFile(file_name), LineNumber(1),LineError(0) 
+  {    if (!in) {cerr << " Error Opening file " << file_name,CurrentFile=0;ShowIoErr(1);}
+  if(verbosity>4) cout << "    Openfile : " << file_name << endl;err();  }
+
+  /*  //  void close()
+  {
+      if (CurrentFile) {
+        if(verbosity>5) cout << "    Closefile: " <<  CurrentFile << endl;
+	CurrentFile=0;in.close();}
+  } */
+  int eof(){return in.eof();}
+  ~MeshIstream(){delete &in;}
+  int IsString(const char* s);
+  char * ReadStr();
+  MeshIstream&   operator>>(short& i)   { cm() >> i ;return err();}
+  MeshIstream&   operator>>(long& i)   { cm() >> i ;return err();}
+  MeshIstream&   operator>>(int& i)   { cm() >> i ;return err();}
+  MeshIstream&   operator>>(float& i)   { cm() >> i ;return err();}
+  MeshIstream&   operator>>(double& i)   { cm() >> i ;return err();}
+  MeshIstream&   operator>>(char * & i ) { i=ReadStr();return err();}
+
+};
+// Fortran unformatted file  interface ----------
+
+class IFortranUnFormattedFile {
+//  template<class T> friend IFortranUnFormattedFile & operator>>(IFortranUnFormattedFile &f,T & l);
+  istream * f;
+  long i,l,n,j,nb_rec;
+  const char * file_name;
+  int to_close;
+ public:
+  IFortranUnFormattedFile(char *name)
+    : f(new ifstream(name)),i(0),l(0),n((long)-sizeof(long)),
+      nb_rec(0),file_name(name), to_close(1)
+    { if(!*f) Error(0);}
+
+  IFortranUnFormattedFile(MeshIstream & ff)
+    : f(&ff.in),i(0),l(0),n((long)-sizeof(long)),nb_rec(0),
+      file_name(ff.CurrentFile), to_close(0)
+    { if(! *f)  Error(0);}
+  
+ ~IFortranUnFormattedFile();
+  long Record();
+  long where(){return j-i;}
+  void  read4(char *c,int );// for the fortran 77 char4
+  void  read(char * p,const size_t lg);
+  void Error(int);
+};
+
+class OFortranUnFormattedFile {
+//  template<class T> friend OFortranUnFormattedFile & operator<<(OFortranUnFormattedFile &f,const T & l);
+  ostream * f;
+  long i,l,n,j,nb_rec;
+  const static char * unkown;
+  const char * file_name;
+  int to_close;
+ public:
+  
+  OFortranUnFormattedFile(const char *name,IOS_OPENMODE  mm=ios::trunc)
+    : f(new ofstream(name,mm)),i(0),l(0),n((long) -sizeof(long)),nb_rec(0),file_name(name), to_close(1)
+    { if(!*f) Error(0);}
+  OFortranUnFormattedFile(ostream &ff)
+    : f(&ff),i(0),l(0),n((long) -sizeof(long)),nb_rec(0),file_name(unkown), to_close(0)
+    { if(!*f) Error(0);}
+  
+  ~OFortranUnFormattedFile();
+
+  long Record(long ll=0);
+  long where(){return j-i;} 
+  void write4(const char *c,int );// for the fortran 77 char4
+  void write(const char * p,const size_t lg);
+  void Error(int );
+};
+
+/// ---------- inline -------------------------
+
+inline void  IFortranUnFormattedFile::read(char * p,const size_t lg){  
+  f->read(p,lg);
+  j+=lg;
+  if (j>n) Error(1);
+  else if (!f->good()) Error(2) ;
+}
+
+inline void  OFortranUnFormattedFile::write(const char * p,const size_t lg){  
+   f->write(p,lg);
+   j+=lg;
+   if (l && j>n)  Error(1);
+   else if (!f->good()) Error(2);
+}
+
+template<class T> inline
+IFortranUnFormattedFile & operator>>(IFortranUnFormattedFile &f,T & l)
+{  
+  f.read((char *) &l,sizeof(l));return f;
+}
+/*  bug sur sun  
+template inline 
+ OFortranUnFormattedFile & operator<<(OFortranUnFormattedFile &f,const T & l)
+ { 
+   f.write((char *) &l,sizeof(l));return f;
+ }
+on ex les template  */ 
+
+inline 
+ OFortranUnFormattedFile & operator<<(OFortranUnFormattedFile &f,const int  & l)
+ { 
+   f.write((char *) &l,sizeof(l));return f;
+ }
+inline 
+ OFortranUnFormattedFile & operator<<(OFortranUnFormattedFile &f,const long  & l)
+ { 
+   f.write((char *) &l,sizeof(l));return f;
+ }
+inline 
+ OFortranUnFormattedFile & operator<<(OFortranUnFormattedFile &f,const double  & l)
+ { 
+   f.write((char *) &l,sizeof(l));return f;
+ }
+inline 
+ OFortranUnFormattedFile & operator<<(OFortranUnFormattedFile &f,const float & l)
+ { 
+   f.write((char *) &l,sizeof(l));return f;
+ }
+
+inline void OFortranUnFormattedFile::write4(const char *c,int ll)
+{
+  int i,j;
+  Char4orLong ch4;
+  for ( i=0;i<ll;i++)
+    {
+      ch4.l=0;
+      for (j=0;j<4;j++)
+	ch4.c[j]=*c? *c++:' ';
+      *this << ch4.l;
+    }
+}
+inline void IFortranUnFormattedFile::read4(char *c,int ll)
+{
+  int i,j;
+  Char4orLong ch4;
+
+  for ( i=0;i<ll;i++)
+    {
+      *this >> ch4.l;
+      for (j=0;j<4;j++)
+	*c++= ch4.c[j];
+    }
+  *c=0;// end of string 
+}
+
+}
diff --git a/contrib/bamg/bamglib/Metric.cpp b/contrib/bamg/bamglib/Metric.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..f65141383d53d11c97466016659736b6c144d87a
--- /dev/null
+++ b/contrib/bamg/bamglib/Metric.cpp
@@ -0,0 +1,1213 @@
+// -*- Mode : c++ -*-
+//
+// SUMMARY  :      
+// USAGE    :        
+// ORG      : 
+// AUTHOR   : Frederic Hecht
+// E-MAIL   : hecht@ann.jussieu.fr
+//
+
+/*
+ 
+ This file is part of Freefem++
+ 
+ Freefem++ is free software; you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+ 
+ Freefem++  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 Lesser General Public License for more details.
+ 
+ You should have received a copy of the GNU Lesser General Public License
+ along with Freefem++; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include <stdio.h>
+#include "Meshio.h"
+#include "Mesh2.h"
+
+
+namespace bamg {
+
+
+inline Real8 det3x3(Real8 A[3] ,Real8 B[3],Real8 C[3])
+{ return    A[0] * ( B[1]*C[2]-B[2]*C[1])
+          - A[1] * ( B[0]*C[2]-B[2]*C[0])
+          + A[2] * ( B[0]*C[1]-B[1]*C[0]);
+}
+
+SaveMetricInterpole  LastMetricInterpole;
+
+void ReductionSimultanee( MetricAnIso M1,  MetricAnIso M2,double & l1,double & l2, D2xD2 & V) 
+{
+  double a11=M1.a11,a21=M1.a21,a22=M1.a22;
+  double b11=M2.a11,b21=M2.a21,b22=M2.a22;
+  //  M1 v = l M2 v
+  // (M1 - l M2) v =0
+  // det (M1 - l M2) =0
+  // det (M1 - l M2) = a l^2 + b l + c;
+  // = (a11 - l * b11) * (a22 - l * b22) - (a21 - l * b21 ) ^2
+  //  const double eps = 1.e-5;
+  const double /*c11 = a11*a11,*/ c21= a21*a21;
+  const double /*d11 = b11*b11,*/ d21= b21*b21;
+  const double a=b11*b22 - d21;
+  const double b=-a11*b22-a22*b11+2*a21*b21;
+  const double c=-c21+a11*a22;
+  const double bb = b*b,ac= a*c;
+  const double delta = bb - 4 * ac;
+  //  const double kk=c11+c22+c21+d11+d21+d22;
+  // modif F Hecht feb 1998 
+  // cerr.precision(14);
+  //cerr  <<  bb << " " << ac << " " <<  bb <<  " " <<a << endl;
+  // cerr << a11 << " " << a21 << " " << a22 << endl;
+  //cerr << b11 << " " << b21 << " " << b22 << endl;
+  if (bb + Abs(ac) < 1.0e-20 || (delta< 1.0E-4 * bb ) )
+   {
+   // racine double;
+     // cerr << "double " << endl ;
+    if (Abs(a) < 1.e-30 )
+     l1 = l2 = 0;
+    else 
+     l1=l2=-b/(2*a); 
+    V= D2xD2(1,0,0,1);
+   }
+  else {
+    // cerr << "  -- " << a << endl ;
+    const double delta2 = sqrt(delta);
+    l1= (-b - delta2)/(2*a);
+    l2= (-b + delta2)/(2*a);
+    // M1 v = l M2 v
+    //  ( (M1 - I M2) x,y)  = (x,(M1 - I M2) y) \forall y
+    // so Ker((M1 - I M2)) = Im((M1 - I M2))^\perp
+      double v0 = a11-l1*b11, v1 = a21-l1*b21,v2 = a22 - l1*b22;
+      double s0 = v0*v0 + v1*v1, s1 = v1*v1 +v2*v2;
+      double vp1x,vp1y,vp2x,vp2y;
+
+      if(s1 < s0)
+	s0=sqrt(s0),vp1x=v1/s0,vp1y=-v0/s0;
+      else
+	s1=sqrt(s1),vp1x=v2/s1,vp1y=-v1/s1;
+
+      v0 = a11-l2*b11, v1 = a21-l2*b21,v2 = a22 - l2*b22;
+      s0 = v0*v0 + v1*v1, s1 = v1*v1 +v2*v2;
+      if(s1 < s0)
+	s0=sqrt(s0),vp2x=v1/s0,vp2y=-v0/s0;
+      else
+	s1=sqrt(s1),vp2x=v2/s1,vp2y=-v1/s1;
+#ifdef DEBUG
+      assert(Abs(vp1y)+Abs(vp2y)>0);
+#endif
+      V=D2xD2(vp1x,vp2x,vp1y,vp2y);
+  }
+  return;
+
+}
+
+MetricAnIso Intersection(const MetricAnIso M1,const MetricAnIso M2) ;
+MetricAnIso Intersection(const MetricAnIso M1,const MetricAnIso M2) 
+{
+      D2xD2 M;
+      double l1,l2;
+      ReductionSimultanee(M1,M2,l1,l2,M);
+      R2 v0(M.x.x,M.y.x);
+      R2 v1(M.x.y,M.y.y);
+      D2xD2 M_1(M.inv());
+      D2xD2 D(Max(M1(v0,v0),M2(v0,v0)),0,0,Max(M1(v1,v1),M2(v1,v1)));
+      D2xD2 Mi(M_1.t()*D*M_1);
+      return MetricAnIso(Mi.x.x,0.5*(Mi.x.y+Mi.y.x),Mi.y.y);
+}
+
+MetricAnIso::MetricAnIso(const Real8  a[3],const  MetricAnIso m0,
+	   const  MetricAnIso m1,const  MetricAnIso m2 )
+{
+  MetricAnIso mab(a[0]*m0.a11 + a[1]*m1.a11 + a[2]*m2.a11,
+		  a[0]*m0.a21 + a[1]*m1.a21 + a[2]*m2.a21,
+		  a[0]*m0.a22 + a[1]*m1.a22 + a[2]*m2.a22);
+  
+  MatVVP2x2 vab(mab);
+ 
+  R2 v1(vab.v.x,vab.v.y);
+  R2 v2(-v1.y,v1.x);
+  
+  Real8 h1 = a[0] / m0(v1) + a[1] / m1(v1) + a[2] / m2(v1);
+  Real8 h2 = a[0] / m0(v2) + a[1] / m1(v2) + a[2] / m2(v2);
+
+  vab.lambda1 =  1 / (h1*h1);
+  vab.lambda2 =  1 / (h2*h2);
+  *this = vab;
+}
+
+ MetricAnIso::MetricAnIso( Real8  a,const  MetricAnIso ma,
+	                   Real8  b,const  MetricAnIso mb)
+{ 
+  MetricAnIso mab(a*ma.a11+b*mb.a11,a*ma.a21+b*mb.a21,a*ma.a22+b*mb.a22);
+  MatVVP2x2 vab(mab);
+  
+  R2 v1(vab.v.x,vab.v.y);
+  R2 v2(-v1.y,v1.x);
+  
+
+  Real8 h1 = a / ma(v1) + b / mb(v1);
+  Real8 h2 = a / ma(v2) + b / mb(v2);
+  vab.lambda1 =  1 / (h1*h1);
+  vab.lambda2 =  1 / (h2*h2);
+  *this = vab;
+}
+
+
+
+ MatVVP2x2::MatVVP2x2(const MetricAnIso M) 
+{
+  double a11=M.a11,a21=M.a21,a22=M.a22;
+  const double eps = 1.e-5;
+  double c11 = a11*a11, c22 = a22*a22, c21= a21*a21;
+  double b=-a11-a22,c=-c21+a11*a22;
+  double   delta = b*b - 4 * c ;
+  double n2=(c11+c22+c21);
+  if ( n2 < 1e-30) 
+     lambda1=lambda2=0,v.x=1,v.y=0;
+  else if (delta < eps*n2)
+    { 
+      lambda1=lambda2=-b/2, v.x=1,v.y=0;
+    }
+  else 
+    {  //    ---  construction  de 2 vecteur dans (Im ( A - D(i) Id) ortogonal 
+      delta = sqrt(delta);
+      lambda1 = (-b-delta)/2.0,lambda2 = (-b+delta)/2.0;
+      double v0 = a11-lambda1, v1 = a21,v2 = a22 - lambda1;
+      double s0 = v0*v0 + v1*v1, s1 = v1*v1 +v2*v2;
+ 
+      if(s1 < s0)
+	s0=sqrt(s0),v.x=v1/s0,v.y=-v0/s0;
+      else
+	s1=sqrt(s1),v.x=v2/s1,v.y=-v1/s1;
+    };
+}
+
+
+ int MetricAnIso::IntersectWith(const MetricAnIso M2) 
+{
+  //cerr << " - " << *this << M2 <<  endl;
+      int r=0;
+      MetricAnIso & M1 = *this;
+      D2xD2 M;
+      double l1,l2;
+      
+      ReductionSimultanee(*this,M2,l1,l2,M);
+      // cerr << M << endl;
+      R2 v1(M.x.x,M.y.x);
+      R2 v2(M.x.y,M.y.y);
+      double l11=M1(v1,v1);
+      double l12=M1(v2,v2);
+      double l21=M2(v1,v1);
+      double l22=M2(v2,v2);
+      if ( l11 < l21 )  r=1,l11=l21;
+      if ( l12 < l22 )  r=1,l12=l22; 
+      // cerr << r << endl;
+      if (r) { // change
+        D2xD2 M_1(M.inv());
+        D2xD2 D(l11,0,0,l12); 
+        D2xD2 Mi(M_1.t()*D*M_1);
+        a11=Mi.x.x;
+        a21=0.5*(Mi.x.y+Mi.y.x);
+        a22=Mi.y.y; }
+      return r;
+}
+void Triangles::IntersectGeomMetric(const Real8 err=1,const int iso=0)
+
+{
+  if(verbosity>1)
+    cout << "  -- IntersectGeomMetric geometric err=" << err << (iso ? " iso " : " aniso "  ) << endl;
+  Real8 ss[2]={0.00001,0.99999};
+  Real8 errC = 2*sqrt(2*err);
+  Real8 hmax = Gh.MaximalHmax();
+  Real8 hmin = Gh.MinimalHmin();
+  Real8 maxaniso = 1e6;
+  assert(hmax>0);
+  SetVertexFieldOn();
+  if (errC > 1) errC = 1;
+  for (Int4  i=0;i<nbe;i++)
+   for (int j=0;j<2;j++)
+    {
+      
+      Vertex V;
+      VertexOnGeom GV;
+      // cerr << Number(edges[i]) << " " << ss[j] << endl;
+      Gh.ProjectOnCurve(edges[i],ss[j],V,GV);
+	{
+	  GeometricalEdge * eg = GV;
+	  Real8 s = GV;
+	  R2 tg;
+	  //	   cerr << i << " " << j << " " << Number(V) << " on = " 
+	  //	<< Gh.Number(eg) << " at s = " << s << " " << endl;
+	  Real8  R1= eg->R1tg(s,tg);
+	  // cerr << " R = " << 1/Max(R1,1e-20) << tg << " on x " 
+	  //    << V.r << errC/ Max(R1,1e-20) <<  " hold=" <<V.m(tg) << " "  << endl;
+	  Real8 ht = hmax;
+          if (R1>1.0e-20) 
+	    {  // err relative to the length of the edge
+	      ht = Min(Max(errC/R1,hmin),hmax);
+	    }
+	  Real8 hn = iso? ht : Min(hmax,ht*maxaniso);
+	  //cerr << ht << " " << hn << "m=" << edges[i][j].m <<  endl;
+	  assert(ht>0 && hn>0);
+	  MatVVP2x2 Vp(1/(ht*ht),1/(hn*hn),tg);
+	  //cerr << " : " ;
+	  Metric MVp(Vp);
+	  // cerr << " : "  << MVp  << endl;
+	  edges[i][j].m.IntersectWith(MVp);
+	  //cerr << " . " << endl;
+	}
+
+    }
+  // the problem is for the vertex on vertex 
+     
+}
+/*
+void  Triangles::BoundAnisotropy(Real8 anisomax)
+{
+  if (verbosity > 1) 
+    cout << "  -- BoundAnisotropy by  " << anisomax << endl; 
+  Real8 h1=1.e30,h2=1e-30,rx=0;
+  Real8 coef = 1./(anisomax*anisomax);
+  Real8 hn1=1.e30,hn2=1e-30,rnx =1.e-30;  
+  for (Int4 i=0;i<nbv;i++)
+    {
+
+      MatVVP2x2 Vp(vertices[i]);
+      
+      h1=Min(h1,Vp.lmin());
+      h2=Max(h2,Vp.lmax());
+      rx = Max(rx,Vp.Aniso2());
+      
+      Vp.BoundAniso2(coef);
+      
+      hn1=Min(hn1,Vp.lmin());
+      hn2=Max(hn2,Vp.lmax());
+      rnx = Max(rnx,Vp.Aniso2());
+
+      
+      vertices[i].m = Vp;
+
+    }
+
+  if (verbosity>2)
+    {
+      cout << "     input :  Hmin = " << sqrt(1/h2)  << " Hmax = " << sqrt(1/h1) 
+	   << " factor of anisotropy max  = " << sqrt(rx) << endl;
+      cout << "     output:  Hmin = " << sqrt(1/hn2) << " Hmax = " << sqrt(1/hn1) 
+	   << " factor of anisotropy max  = " << sqrt(rnx) << endl;
+    }
+}
+*/
+void  Triangles::BoundAnisotropy(Real8 anisomax,Real8 hminaniso)
+{
+  double lminaniso = 1/ (Max(hminaniso*hminaniso,1e-100));
+  if (verbosity > 1) 
+    cout << "  -- BoundAnisotropy by  " << anisomax << endl; 
+  Real8 h1=1.e30,h2=1e-30,rx=0;
+  Real8 coef = 1./(anisomax*anisomax);
+  Real8 hn1=1.e30,hn2=1e-30,rnx =1.e-30;  
+  for (Int4 i=0;i<nbv;i++)
+    {
+
+      MatVVP2x2 Vp(vertices[i]);
+      double lmax=Vp.lmax();
+      h1=Min(h1,Vp.lmin());
+      h2=Max(h2,Vp.lmax());
+      rx = Max(rx,Vp.Aniso2());
+
+      Vp *= Min(lminaniso,lmax)/lmax;
+      
+      Vp.BoundAniso2(coef);
+      
+      hn1=Min(hn1,Vp.lmin());
+      hn2=Max(hn2,Vp.lmax());
+      rnx = Max(rnx,Vp.Aniso2());
+
+      
+      vertices[i].m = Vp;
+
+    }
+
+  if (verbosity>2)
+    {
+      cout << "     input :  Hmin = " << sqrt(1/h2)  << " Hmax = " << sqrt(1/h1) 
+	   << " factor of anisotropy max  = " << sqrt(rx) << endl;
+      cout << "     output:  Hmin = " << sqrt(1/hn2) << " Hmax = " << sqrt(1/hn1) 
+	   << " factor of anisotropy max  = " << sqrt(rnx) << endl;
+    }
+}
+void Triangles::IntersectConsMetric(const double * s,const Int4 nbsol,const int * typsols,
+				    const  Real8 hmin1,const Real8 hmax1,const Real8 coef,
+				    const Real8 anisomax ,const Real8 CutOff,const int NbJacobi,
+				    const int DoNormalisation,const double power,const int choice)
+{ //  the array of solution s is store    
+  // sol0,sol1,...,soln    on vertex 0
+  //  sol0,sol1,...,soln   on vertex 1
+  //  etc.
+  //  choise = 0 =>  H is computed with green formule
+  //   otherwise  => H is computed from P2 on 4T 
+  const int dim = 2;
+  
+  int sizeoftype[] = { 1, dim ,dim * (dim+1) / 2, dim * dim } ; 
+
+  // computation of the nb of field 
+  Int4 ntmp = 0;
+  if (typsols)
+    {
+      for (Int4 i=0;i<nbsol;i++)
+	     ntmp += sizeoftype[typsols[i]];
+    }
+  else
+    ntmp = nbsol;
+
+  // n is the total number of fields
+
+  const Int4 n = ntmp;
+
+  Int4 i,k,iA,iB,iC,iv;
+  R2 O(0,0);
+  int RelativeMetric = CutOff>1e-30;
+  Real8 hmin = Max(hmin1,MinimalHmin());
+  Real8 hmax = Min(hmax1,MaximalHmax());
+  Real8 coef2 = 1/(coef*coef);
+
+  if(verbosity>1) 
+    {
+      cout << "  -- Construction of Metric: Nb of field. " << n << " nbt = " 
+	   << nbt << " nbv= " << nbv 
+	   << " coef = " << coef << endl
+	   << "     hmin = " << hmin << " hmax=" << hmax 
+	   << " anisomax = " << anisomax <<  " Nb Jacobi " << NbJacobi << " Power = " << power ;
+      if (RelativeMetric)
+	cout << " RelativeErr with CutOff= "  <<  CutOff << endl;
+      else
+	cout << " Absolute Err" <<endl;
+    }
+  double *ss=(double*)s;//, *ssiii = ss;
+
+  double sA,sB,sC;
+
+  Real8 *detT = new Real8[nbt];
+  Real8 *Mmass= new Real8[nbv];
+  Real8 *Mmassxx= new Real8[nbv];
+  Real8 *dxdx= new Real8[nbv];
+  Real8 *dxdy= new Real8[nbv];
+  Real8 *dydy= new Real8[nbv];
+  Real8 *workT= new Real8[nbt];
+  Real8 *workV= new Real8[nbv];
+  int *OnBoundary = new int[nbv];
+  for (iv=0;iv<nbv;iv++)
+    {
+      Mmass[iv]=0;
+      OnBoundary[iv]=0;
+      Mmassxx[iv]=0;
+    }
+
+  for (i=0;i<nbt;i++) 
+    if(triangles[i].link) // the real triangles 
+      {
+	const Triangle &t=triangles[i];
+	// coor of 3 vertices 
+	R2 A=t[0];
+	R2 B=t[1];
+	R2 C=t[2];
+
+
+	// number of the 3 vertices
+	iA = Number(t[0]);
+	iB = Number(t[1]);
+	iC = Number(t[2]);
+	
+	Real8 dett = bamg::Area2(A,B,C);
+	detT[i]=dett;
+	dett /= 6;
+
+	// construction of on boundary 
+	int nbb =0;
+	for(int j=0;j<3;j++)
+          {
+	    Triangle *ta=t.Adj(j);
+	    if ( ! ta || !ta->link) // no adj triangle => edge on boundary
+	      OnBoundary[Number(t[VerticesOfTriangularEdge[j][0]])]=1,
+		OnBoundary[Number(t[VerticesOfTriangularEdge[j][1]])]=1,
+		nbb++;
+	  }
+	
+	workT[i] = nbb;
+	Mmass[iA] += dett;
+	Mmass[iB] += dett;
+	Mmass[iC] += dett;
+	
+	if((nbb==0)|| !choice)
+	  {
+	    Mmassxx[iA] += dett;
+	    Mmassxx[iB] += dett;
+	    Mmassxx[iC] += dett;
+	  }
+      }
+  else
+    workT[i]=-1;
+
+//  for (Int4 kcount=0;kcount<n;kcount++,ss++)
+    for (Int4 nusol=0;nusol<nbsol;nusol++)
+    { //for all Solution  
+
+      Real8 smin=ss[0],smax=ss[0];
+      
+      Real8 h1=1.e30,h2=1e-30,rx=0;
+      Real8 coef = 1./(anisomax*anisomax);
+      Real8 hn1=1.e30,hn2=1e-30,rnx =1.e-30;  
+      int nbfield = typsols? sizeoftype[typsols[nusol]] : 1; 
+      if (nbfield == 1) 
+       for ( iv=0,k=0; iv<nbv; iv++,k+=n )
+				{
+				  dxdx[iv]=dxdy[iv]=dydy[iv]=0;
+				  smin=Min(smin,ss[k]);
+				  smax=Max(smax,ss[k]);
+				 }
+			  else
+			   {
+         //  cas vectoriel 
+          for ( iv=0,k=0; iv<nbv; iv++,k+=n )
+          {	
+           double v=0;		     
+			     for (int i=0;i<nbfield;i++) 
+			         v += ss[k+i]*ss[k+i];
+			     v = sqrt(v);
+				   smin=Min(smin,v);
+				   smax=Max(smax,v);
+			    }
+			   }
+      Real8 sdelta = smax-smin;
+      Real8 absmax=Max(Abs(smin),Abs(smax));
+      Real8 cnorm = DoNormalisation ? coef2/sdelta : coef2;
+      
+      if(verbosity>2) 
+	     cout << "    Solution " << nusol <<  " Min = " << smin << " Max = " 
+	       << smax << " Delta =" << sdelta << " cnorm = " << cnorm <<  " Nb of fields =" << nbfield << endl;
+
+      
+      if ( sdelta < 1.0e-10*Max(absmax,1e-20) && (nbfield ==1)) 
+				{
+				  if (verbosity>2)
+				    cout << "      Solution " << nusol << " is constant. We skip. " 
+					 << " Min = " << smin << " Max = " << smax << endl;
+				continue;
+				}
+				
+	 double *sf  = ss; 
+	 for (Int4 nufield=0;nufield<nbfield;nufield++,ss++) 
+	   {
+	     for ( iv=0,k=0; iv<nbv; iv++,k+=n )
+		       dxdx[iv]=dxdy[iv]=dydy[iv]=0;
+       for (i=0;i<nbt;i++) 
+	      if(triangles[i].link)
+	  {// for real all triangles 
+	    // coor of 3 vertices 
+	    R2 A=triangles[i][0];
+	    R2 B=triangles[i][1];
+	    R2 C=triangles[i][2];
+	    
+	    
+	    // warning the normal is internal and the 
+	    //   size is the length of the edge
+	    R2 nAB = Orthogonal(B-A);
+	    R2 nBC = Orthogonal(C-B);
+	    R2 nCA = Orthogonal(A-C);
+	    // remark :  nAB + nBC + nCA == 0 
+
+	    // number of the 3 vertices
+	    iA = Number(triangles[i][0]);
+	    iB = Number(triangles[i][1]);
+	    iC = Number(triangles[i][2]);
+	    
+	    // for the test of  boundary edge
+	    // the 3 adj triangles 
+	    Triangle *tBC = triangles[i].TriangleAdj(OppositeEdge[0]);
+	    Triangle *tCA = triangles[i].TriangleAdj(OppositeEdge[1]);
+	    Triangle *tAB = triangles[i].TriangleAdj(OppositeEdge[2]);
+
+	    // value of the P1 fonction on 3 vertices 
+	    sA = ss[iA*n];
+	    sB = ss[iB*n];
+	    sC = ss[iC*n];
+
+	    R2 Grads = (nAB * sC + nBC * sA + nCA * sB ) /detT[i] ;
+	    if(choice) 
+	      {
+		int nbb = 0;
+		Real8 dd = detT[i];
+		Real8 lla,llb,llc,llf;
+		Real8  taa[3][3],bb[3];
+		// construction of the trans of lin system
+		for (int j=0;j<3;j++)
+		  {
+		    int ie = OppositeEdge[j];
+		    TriangleAdjacent ta = triangles[i].Adj(ie);
+		    Triangle *tt = ta;
+		    if (tt && tt->link)
+		      {
+			Vertex &v = *ta.OppositeVertex();
+			R2 V = v;
+			Int4 iV = Number(v);
+			Real8 lA  = bamg::Area2(V,B,C)/dd;
+			Real8 lB  = bamg::Area2(A,V,C)/dd;
+			Real8 lC  = bamg::Area2(A,B,V)/dd;
+			taa[0][j] =  lB*lC;
+			taa[1][j] =  lC*lA;
+			taa[2][j] =  lA*lB;
+			//Real8 xx = V.x-V.y;
+			//Real8 yy = V.x + V.y;
+			//cout << " iv " << ss[iV*n] << " == " << (8*xx*xx+yy*yy)
+			//     << " l = " << lA << " " << lB << " " << lC 
+			//     << " = " << lA+lB+lC << " " <<  V << " == " << A*lA+B*lB+C*lC << endl;
+			
+			lla = lA,llb=lB,llc=lC,llf=ss[iV*n] ;
+
+			bb[j]     =  ss[iV*n] - ( sA*lA + sB*lB + sC*lC ) ;
+		      }
+		    else
+		      {
+			nbb++;
+			taa[0][j]=0;
+			taa[1][j]=0;
+			taa[2][j]=0;
+			taa[j][j]=1;
+			bb[j]=0;
+		      }
+		  }
+
+		// resolution of 3x3 lineaire system transpose
+		Real8 det33 =  det3x3(taa[0],taa[1],taa[2]);		
+		Real8 cBC   =  det3x3(bb,taa[1],taa[2]);
+		Real8 cCA   =  det3x3(taa[0],bb,taa[2]);
+		Real8 cAB   =  det3x3(taa[0],taa[1],bb);
+		
+		assert(det33);
+		//	det33=1;
+		// verif
+		//	cout << " " << (taa[0][0]*cBC +  taa[1][0]*cCA + taa[2][0] * cAB)/det33 << " == " << bb[0] ;
+		//	cout << " " << (taa[0][1]*cBC +  taa[1][1]*cCA + taa[2][1] * cAB)/det33 << " == " << bb[1];
+		//	cout << " " << (taa[0][2]*cBC +  taa[1][2]*cCA + taa[2][2] * cAB)/det33 << " == " << bb[2] 
+		//	     << "  -- " ;
+		//cout << lla*sA + llb*sB+llc*sC+ (lla*llb* cAB +  llb*llc* cBC + llc*lla*cCA)/det33 
+		//   << " == " << llf <<  endl;
+		// computation of the gradient in the element 
+		
+		// H( li*lj) = grad li grad lj + grad lj grad lj
+		// grad li = njk  / detT ; with i j k ={A,B,C)
+		Real8 Hxx = cAB * ( nBC.x*nCA.x) +  cBC * ( nCA.x*nAB.x) + cCA * (nAB.x*nBC.x);
+		Real8 Hyy = cAB * ( nBC.y*nCA.y) +  cBC * ( nCA.y*nAB.y) + cCA * (nAB.y*nBC.y);
+		Real8 Hxy = cAB * ( nBC.y*nCA.x) +  cBC * ( nCA.y*nAB.x) + cCA * (nAB.y*nBC.x) 
+		          + cAB * ( nBC.x*nCA.y) +  cBC * ( nCA.x*nAB.y) + cCA * (nAB.x*nBC.y);
+		Real8 coef = 1.0/(3*dd*det33);
+		Real8 coef2 = 2*coef;
+		//	cout << " H = " << Hxx << " " << Hyy << " " <<  Hxy/2 << " coef2 = " << coef2 << endl;
+		Hxx *= coef2;
+		Hyy *= coef2;
+		Hxy *= coef2;
+		//cout << i  << " H = " << 3*Hxx/dd << " " << 3*Hyy/dd << " " <<  3*Hxy/(dd*2) << " nbb = " << nbb << endl;
+		if(nbb==0)
+		  {
+		    dxdx[iA] += Hxx;
+		    dydy[iA] += Hyy;
+		    dxdy[iA] += Hxy;
+		    
+		    dxdx[iB] += Hxx;
+		    dydy[iB] += Hyy;
+		    dxdy[iB] += Hxy;
+		    
+		    dxdx[iC] += Hxx;
+		    dydy[iC] += Hyy;
+		    dxdy[iC] += Hxy;
+		  }
+		
+	      }
+	    else
+	      {
+		
+		// if edge on boundary no contribution  => normal = 0
+		if ( ! tBC || ! tBC->link ) nBC = O;
+		if ( ! tCA || ! tCA->link ) nCA = O;
+		if ( ! tAB || ! tAB->link ) nAB = O;
+	    
+		// remark we forgot a 1/2 because
+		//       $\\int_{edge} w_i = 1/2 $ if $i$ is in edge 
+		//                          0  if not
+		// if we don't take the  boundary 
+		// dxdx[iA] += ( nCA.x + nAB.x ) *Grads.x;
+		
+		dxdx[iA] += ( nCA.x + nAB.x ) *Grads.x;
+		dxdx[iB] += ( nAB.x + nBC.x ) *Grads.x;
+		dxdx[iC] += ( nBC.x + nCA.x ) *Grads.x;
+		
+		// warning optimization (1) the divide by 2 is done on the metrix construction
+		dxdy[iA] += (( nCA.y + nAB.y ) *Grads.x + ( nCA.x + nAB.x ) *Grads.y) ;
+		dxdy[iB] += (( nAB.y + nBC.y ) *Grads.x + ( nAB.x + nBC.x ) *Grads.y) ;
+		dxdy[iC] += (( nBC.y + nCA.y ) *Grads.x + ( nBC.x + nCA.x ) *Grads.y) ; 
+		
+		dydy[iA] += ( nCA.y + nAB.y ) *Grads.y;
+		dydy[iB] += ( nAB.y + nBC.y ) *Grads.y;
+		dydy[iC] += ( nBC.y + nCA.y ) *Grads.y;
+	      }
+	    
+	  } // for real all triangles 
+     Int4 kk=0;
+      for ( iv=0,k=0 ; iv<nbv; iv++,k+=n )
+	if(Mmassxx[iv]>0) 
+	  {
+	    dxdx[iv] /= 2*Mmassxx[iv];
+	    // warning optimization (1) on term dxdy[iv]*ci/2 
+	    dxdy[iv] /= 4*Mmassxx[iv];
+	    dydy[iv] /= 2*Mmassxx[iv];
+	    // Compute the matrix with abs(eigen value)
+	    Metric M(dxdx[iv], dxdy[iv], dydy[iv]);
+	    MatVVP2x2 Vp(M);
+	    //cout <<iv <<  "  M  = " <<  M <<  " aniso= " << Vp.Aniso() ;
+	    Vp.Abs();
+	    M = Vp;
+	      dxdx[iv] = M.a11;
+	      dxdy[iv] = M.a21;
+	      dydy[iv] = M.a22;
+	      //  cout << " (abs)  iv M  = " <<  M <<  " aniso= " << Vp.Aniso() <<endl;
+	  }
+	else kk++;
+      
+      
+      // correction of second derivate
+      // by a laplacien
+
+      Real8 *d2[3] = { dxdx, dxdy, dydy};
+      Real8 *dd;
+      for (int xy = 0;xy<3;xy++)
+	{
+	  dd = d2[xy];
+      // do leat 2 iteration for boundary problem
+	  for (int ijacobi=0;ijacobi<Max(NbJacobi,2);ijacobi++)
+	    {
+	      for (i=0;i<nbt;i++) 
+		if(triangles[i].link) // the real triangles 
+		  {
+		    // number of the 3 vertices
+		    iA = Number(triangles[i][0]);
+		    iB = Number(triangles[i][1]);
+		    iC = Number(triangles[i][2]);
+		    Real8 cc=3;
+		    if(ijacobi==0)
+		      cc = Max((Real8) ((Mmassxx[iA]>0)+(Mmassxx[iB]>0)+(Mmassxx[iC]>0)),1.);
+		    workT[i] = (dd[iA]+dd[iB]+dd[iC])/cc;
+		  }
+	      for (iv=0;iv<nbv;iv++)
+		workV[iv]=0;
+
+	      for (i=0;i<nbt;i++) 
+		if(triangles[i].link) // the real triangles 
+		  {
+		    // number of the 3 vertices
+		    iA = Number(triangles[i][0]);
+		    iB = Number(triangles[i][1]);
+		    iC = Number(triangles[i][2]);
+		    Real8 cc =  workT[i]*detT[i];
+		    workV[iA] += cc;
+		    workV[iB] += cc;
+		    workV[iC] += cc;
+		  }
+
+	      for (iv=0;iv<nbv;iv++)
+		if( ijacobi<NbJacobi || OnBoundary[iv])
+		  dd[iv] = workV[iv]/(Mmass[iv]*6);
+	      
+
+	    }
+
+	  
+	}
+
+      // constuction  of the metrix from the Hessian dxdx. dxdy,dydy
+
+      Real8 rCutOff=CutOff*absmax;// relative cut off 
+
+      for ( iv=0,k=0 ; iv<nbv; iv++,k+=n )
+	{ // for all vertices 
+	  //{
+	  //Metric M(dxdx[iv], dxdy[iv], dydy[iv]);
+	  // MatVVP2x2 Vp(M);	  
+	  //cout << " iv M="<<  M << "  Vp = " << Vp << " aniso  " << Vp.Aniso() << endl;
+	  //}
+	  MetricIso Miso;
+// new code to compute ci ---	  
+	  Real8 ci ;
+	  if (RelativeMetric)
+	    { //   compute the norm of the solution
+	       double xx =0,*sfk=sf+k; 
+	       for (int ifield=0;ifield<nbfield;ifield++,sfk++)
+	          xx += *sfk* *sfk;	       
+	       xx=sqrt(xx);
+	       ci = coef2/Max(xx,rCutOff);
+	    }
+	  else ci = cnorm;
+	  
+ // old 
+//	  Real8 ci = RelativeMetric ? coef2/(Max(Abs(ss[k]),rCutOff)) : cnorm ;
+ //   modif F Hecht 101099
+	  Metric Miv(dxdx[iv]*ci, dxdy[iv]*ci,  dydy[iv]*ci);
+	  MatVVP2x2 Vp(Miv);
+
+	  Vp.Abs();
+	 if(power!=1.0) 
+	      Vp.pow(power);
+	  
+
+
+	  h1=Min(h1,Vp.lmin());
+	  h2=Max(h2,Vp.lmax());
+
+	  Vp.Maxh(hmin);
+	  Vp.Minh(hmax);
+
+	  rx = Max(rx,Vp.Aniso2());
+
+	  Vp.BoundAniso2(coef);
+
+	  hn1=Min(hn1,Vp.lmin());
+	  hn2=Max(hn2,Vp.lmax());
+	  rnx = Max(rnx,Vp.Aniso2());
+
+	  Metric MVp(Vp);
+	  vertices[iv].m.IntersectWith(MVp);
+	}// for all vertices 
+      if (verbosity>2)
+	{ 
+	  cout << "              Field " << nufield << " of solution " << nusol  << endl;
+	  cout << "              before bounding :  Hmin = " << sqrt(1/h2) << " Hmax = " 
+	       << sqrt(1/h1)  << " factor of anisotropy max  = " << sqrt(rx) << endl;
+	  cout << "              after  bounding :  Hmin = " << sqrt(1/hn2) << " Hmax = " 
+	       << sqrt(1/hn1)  << " factor of anisotropy max  = " << sqrt(rnx) << endl;
+	}
+	 } //  end of for all field
+    }// end for all solution 
+
+  delete [] detT;
+  delete [] Mmass;
+  delete [] dxdx;
+  delete [] dxdy;
+  delete [] dydy;
+  delete []  workT;
+  delete [] workV;
+  delete [] Mmassxx;
+  delete []  OnBoundary;
+ 
+}
+
+
+void Triangles::ReadMetric(const char * fmetrix,const Real8 hmin1=1.0e-30,const Real8 hmax1=1.0e30,const Real8 coef=1)
+{
+  Real8 hmin = Max(hmin1,MinimalHmin());
+  Real8 hmax = Min(hmax1,MaximalHmax());
+  MeshIstream f_metrix(fmetrix);
+  Int4 k,j;
+  f_metrix >>  k >> j ;
+  if(verbosity>1)
+    cout << " metrix: open " << fmetrix 
+	 << ", le coef = " << coef
+	 << ", hmin = " << hmin 
+	 << ", hmax = " << hmax 
+	 << (  (j == 1)? " Iso " : " AnIso " )<< endl;
+  
+  if (k != nbv || !(j == 1 || j == 3)) 
+    {
+      cerr << " Error Pb metrix " << k << " <> " 
+	   <<  nbv << " or  1 or 3 <> " << j << endl;
+      MeshError(1002);
+    }
+  
+  cout << " j = " << j << endl;
+  //  Int4 nberr = 0;
+  for (Int4 iv=0;iv<nbv;iv++)
+    {
+      Real8 h;
+      if (j == 1) 
+	{
+	f_metrix >>  h ;
+	vertices[iv].m=Metric(Max(hmin,Min(hmax, h*coef)));
+	}
+      else if (j==3) 
+	{
+	  Real8 a,b,c;	     
+	  f_metrix >>  a >> b >> c  ;
+	  MetricAnIso M(a,b,c);
+	  MatVVP2x2 Vp(M/coef);
+	  
+	  Vp.Maxh(hmin);
+	  Vp.Minh(hmax);
+	  vertices[iv].m = Vp;
+	  
+	}
+    }
+ 
+}
+
+void Triangles::WriteMetric(ostream & f,int iso)
+{
+  if (iso)
+    {
+      f <<  nbv <<" " << 1 << endl ;
+      for (Int4 iv=0;iv<nbv;iv++)
+	{
+	  MatVVP2x2 V=vertices[iv].m;
+	  f <<  V.hmin()  << endl;
+	}
+    }
+else
+  {
+    f <<  nbv <<" " << 3 << endl ;
+    for (Int4 iv=0;iv<nbv;iv++)
+      f <<  vertices[iv].m.a11 << " " 
+	<<  vertices[iv].m.a21 << " " 
+	<<  vertices[iv].m.a22 << endl;
+  }
+}
+void  Triangles::MaxSubDivision(Real8 maxsubdiv)
+{
+const  Real8 maxsubdiv2 = maxsubdiv*maxsubdiv;
+#ifdef DRAWING2
+  inquire();
+#endif	    
+  if(verbosity>1)
+    cout << "  -- Limit the subdivision of a edges in the new mesh by " << maxsubdiv <<   endl  ;
+  // for all the edges 
+  // if the len of the edge is to long 
+  Int4 it,nbchange=0;    
+  Real8 lmax=0;
+  for (it=0;it<nbt;it++)
+    {
+      Triangle &t=triangles[it];
+      for (int j=0;j<3;j++)
+	{
+	  Triangle &tt = *t.TriangleAdj(j);
+	  if ( ! &tt ||  it < Number(tt) && ( tt.link || t.link)) 
+	    {
+		Vertex &v0 = t[VerticesOfTriangularEdge[j][0]];
+		Vertex &v1 = t[VerticesOfTriangularEdge[j][1]];
+		R2 AB= (R2) v1-(R2) v0;
+		Metric M = v0;
+		Real8 l = M(AB,AB);
+		lmax = Max(lmax,l);
+		if(l> maxsubdiv2)
+		  { R2 AC = M.Orthogonal(AB);// the ortogonal vector of AB in M
+		    Real8 lc = M(AC,AC);
+		    D2xD2 Rt(AB,AC);// Rt.x = AB , Rt.y = AC;
+		    D2xD2 Rt1(Rt.inv());
+		    D2xD2 D(maxsubdiv2,0,0,lc);
+		    D2xD2 MM = Rt1*D*Rt1.t();
+#ifdef DRAWING1
+		    v0.m.Draw(v0);
+#endif	    
+		    v0.m =  M = MetricAnIso(MM.x.x,MM.y.x,MM.y.y);
+#ifdef DRAWING1
+		    v0.m.Draw(v0);
+#endif	    
+		    //		    cout << " M(AB,AB) = " << M(AB,AB) << " == " << maxsubdiv 
+		    //	 << " M(AC,AC) = " << M(AC,AC) << " == " << lc << endl; 
+		    nbchange++;
+		  }
+		M = v1;
+		l = M(AB,AB);
+		lmax = Max(lmax,l);
+		if(l> maxsubdiv2)
+		  { R2 AC = M.Orthogonal(AB);// the ortogonal vector of AB in M
+		    Real8 lc = M(AC,AC);
+		    D2xD2 Rt(AB,AC);// Rt.x = AB , Rt.y = AC;
+		    D2xD2 Rt1(Rt.inv());
+		    D2xD2 D(maxsubdiv2,0,0,lc);
+		    D2xD2  MM = Rt1*D*Rt1.t();
+#ifdef DRAWING1
+		    v1.m.Draw(v1);
+#endif	    
+		    v1.m =  M = MetricAnIso(MM.x.x,MM.y.x,MM.y.y);
+#ifdef DRAWING1
+		    v1.m.Draw(v1);
+		    inquire();
+#endif	    
+		    // cout << " M(AB,AB) = " << M(AB,AB) << " == " << maxsubdiv 
+		    //	 << " M(AC,AC) = " << M(AC,AC) << " == " << lc << endl; 
+		    nbchange++;
+		  }
+		
+		
+	    }
+	}
+    }
+  if(verbosity>3)
+  cout << "    Nb of metric change = " << nbchange 
+       << " Max  of the subdivision of a edges before change  = " << sqrt(lmax) << endl;
+#ifdef DRAWING2
+  inquire();
+#endif	    
+
+}
+
+void Triangles::SmoothMetric(Real8 raisonmax) 
+{ 
+  if(raisonmax<1.1) return;
+  if(verbosity > 1)
+     cout << "  -- Triangles::SmoothMetric raisonmax = " << raisonmax << " " <<nbv <<endl;
+  ReMakeTriangleContainingTheVertex();
+  Int4 i,j,kch,kk,ip;
+  Int4 *first_np_or_next_t0 = new Int4[nbv];
+  Int4 *first_np_or_next_t1 = new Int4[nbv];
+  Int4 Head0 =0,Head1=-1;
+  Real8 logseuil= log(raisonmax);
+
+  for(i=0;i<nbv-1;i++)
+    first_np_or_next_t0[i]=i+1; 
+  first_np_or_next_t0[nbv-1]=-1;// end;
+  for(i=0;i<nbv;i++)
+    first_np_or_next_t1[i]=-1;
+  kk=0;
+  while (Head0>=0&& kk++<100) {
+    kch=0;
+    for (i=Head0;i>=0;i=first_np_or_next_t0[ip=i],first_np_or_next_t0[ip]=-1)
+      {  //  pour tous les triangles autour du sommet s
+	// 	cout << kk << " i = " << i << " " << ip << endl;
+	register Triangle * t= vertices[i].t;
+	assert(t);
+	Vertex & vi = vertices[i];
+	TriangleAdjacent ta(t,EdgesVertexTriangle[vertices[i].vint][0]);
+	Vertex *pvj0 = ta.EdgeVertex(0);
+	while (1) {
+	  //	  cout << i << " " <<  Number(ta.EdgeVertex(0)) << " "
+	  //      << Number(ta.EdgeVertex(1)) << "  ---> " ;
+	  ta=Previous(Adj(ta));
+	  // cout <<  Number(ta.EdgeVertex(0)) << " " << Number(ta.EdgeVertex(1)) << endl;
+	  assert(vertices+i == ta.EdgeVertex(1));
+	  Vertex & vj = *(ta.EdgeVertex(0));
+	  if ( &vj ) {
+	    j= &vj-vertices;
+	    assert(j>=0 && j < nbv);
+	    R2 Aij = (R2) vj - (R2) vi;
+	    Real8 ll =  Norme2(Aij);
+	    if (0) {  
+	      Real8 hi = ll/vi.m(Aij);
+	      Real8 hj = ll/vj.m(Aij);
+	      if(hi < hj)
+		{
+		  Real8 dh=(hj-hi)/ll;
+		  //cout << " dh = " << dh << endl;
+		  if (dh>logseuil) {
+		    vj.m.IntersectWith(vi.m/(1 +logseuil*ll/hi));
+		    if(first_np_or_next_t1[j]<0)
+		      kch++,first_np_or_next_t1[j]=Head1,Head1=j;
+		  }
+		}
+	    } 
+	    else
+	      {
+		Real8 li = vi.m(Aij);
+		//Real8 lj = vj.m(Aij);
+		//		if ( i == 2 || j == 2)
+		//  cout << " inter " << i << " " << j << " " << ((1 +logseuil*li)) <<  endl;
+	      	if( vj.m.IntersectWith(vi.m/(1 +logseuil*li)) )
+		  //if( vj.m.IntersectWith(vi.m*(lj/li/(1 +logseuil*lj))) )
+		  if(first_np_or_next_t1[j]<0) // if the metrix change 
+		    kch++,first_np_or_next_t1[j]=Head1,Head1=j;
+	      }
+	  }
+	  if  ( &vj ==  pvj0 ) break;
+	}
+      }
+    Head0 = Head1;
+    Head1 = -1;
+    Exchange(first_np_or_next_t0,first_np_or_next_t1);
+    if(verbosity>5)
+    cout << "     Iteration " << kk << " Nb de  vertices with change  " << kch << endl;
+  }
+  if(verbosity>2 && verbosity < 5) 
+    cout << "    Nb of Loop " << kch << endl;
+  delete [] first_np_or_next_t0;
+  delete [] first_np_or_next_t1;
+}
+
+void Geometry::ReadMetric(const char * fmetrix,Real8 hmin=1.0e-30,Real8 hmax=1.0e30,Real8 coef=1)
+{
+  hmin = Max(hmin,MinimalHmin());
+  MeshIstream f_metrix(fmetrix);
+  Int4 k,j;
+  f_metrix >>  k >> j ;
+  if(verbosity>1)
+    cout << "  -- ReadMetric  " << fmetrix 
+	 << ",  coef = " << coef
+	 << ", hmin = " << hmin 
+	 << ", hmax = " << hmax 
+	 << (  (j == 1)? " Iso " : " AnIso " ) << endl;
+  
+  if (k != nbv ||  !(j == 1 || j == 3)) {
+    cerr << " Error Pb metrix " << k << " <> " 
+	 <<  nbv << " or  1 or 3  <> " << j << endl;
+    MeshError(1003);}
+	 
+  
+  //  Int4 nberr = 0;
+  for (Int4 iv=0;iv<nbv;iv++)
+    {
+    Real8 h;
+    if (j == 1) 
+      {
+      f_metrix >>  h ;
+      vertices[iv].m=Metric(Max(hmin,Min(hmax, h*coef)));
+      }
+    else if (j==3) 
+      {
+	Real8 a,b,c;	     
+	f_metrix >>  a >> b >> c  ;
+	MetricAnIso M(a,b,c);
+	MatVVP2x2 Vp(M/coef);
+	Vp.Maxh(hmin);
+      Vp.Minh(hmax);
+      vertices[iv].m = Vp;
+      }
+    }
+  
+}
+
+
+Real8 LengthInterpole(const MetricAnIso Ma,const  MetricAnIso Mb, R2 AB)
+{
+  Real8 k=1./2.;
+  int level=0;
+  static int kkk=0;
+  static  Metric Ms1[32],Ms2[32];
+  static Real8 lMs1[32],lMs2[32];
+  static double K[32];
+  Real8 l=0,sss=0;
+  Ms1[level]=Ma;
+  Ms2[level]=Mb;
+  Real8 sa =  Ma(AB);
+  Real8 sb =  Mb(AB);
+  lMs1[level]=sa;
+  lMs2[level]=sb;
+  K[level]=k;
+  level++;
+  int i=0;
+  Real8 * L= LastMetricInterpole.L, *S = LastMetricInterpole.S;
+  Real8  sstop = 0.1; // Max(0.6,(sa+sb)/5000);
+  while (level) {
+    level--;
+    Metric M1=Ms1[level];
+    Metric M2=Ms2[level];
+    k=K[level];
+    Real8 s1=  lMs1[level];
+    Real8 s2=  lMs2[level];
+
+    Real8 s= (s1+s2)*k;
+//    if (level >20  && i < 2030-level)
+//    cout << "                  level " << level << " " << i << " " << s << " " << k <<endl;
+    if( s > sstop   && level < 30 && i < 500-level ) {
+      Metric Mi(0.5,M1,0.5,M2);
+      Real8 si = Mi(AB);
+      if( Abs((s1+s2)-(si+si)) > s1*0.001) 
+	{
+	  k=k/2;
+	  // we begin by the end to walk in the correct sens from a to b
+	       // due to the stack 
+	       Ms1[level]=Mi;
+	  Ms2[level]=M2;
+	  lMs1[level]=si;
+	  lMs2[level]=s2;
+	  K[level]=k;
+	  level++;
+	  Ms1[level]=M1;
+	  Ms2[level]=Mi;
+	  lMs1[level]=s1;
+	  lMs2[level]=si;
+	  K[level]=k;
+	  level++;
+	}
+      else
+	L[i]= l += s,S[i]=sss+=k,i++;
+    }
+    else 
+      L[i]= l += s,S[i]=sss+=k,i++;//cout << i << " l = " << l << " sss = " << sss << endl;
+  }
+  // warning for optimisation S is in [0:0.5] not in [0:1]
+  assert(i<512);
+  LastMetricInterpole.lab=l;
+  LastMetricInterpole.opt=i;
+  if (i>200 && kkk++<10)
+     cout << "Warning LengthInterpole: ( i = " << i << " l = " << l << " sss " << sss << " ) " << sstop <<endl;
+  return l;
+}
+
+Real8 abscisseInterpole(const MetricAnIso Ma,const  MetricAnIso Mb, R2 AB,Real8 s,int optim)
+{ 
+  if(!optim)  LengthInterpole(Ma,Mb,AB);
+  Real8 l  = s* LastMetricInterpole.lab,r;
+  int j=LastMetricInterpole.opt-1,i=0,k;
+  
+  Real8 * L= LastMetricInterpole.L, *S = LastMetricInterpole.S;
+  // warning for optimisation S is the abcisse in [0:0.5]
+  // and L is le lenght 
+  if(l<=L[0])
+    r=2*S[0]*l/L[0];
+  else if (l>=L[j])
+    r=1;
+  else 
+    {
+      while (j-i>1)
+	{
+	  k= (i+j)/2;
+	  if(l<=L[k])
+	    j=k;// l<=L[j] 
+	  else
+	    i=k; //  L[i]<l
+	};
+      //   cout  << i << " " << j  <<" " << L[i] << " " << L[j] << " " << S[i] << " " <<  S[j]  << " l=" << l << endl;
+      if (i==j)
+	r = 2*S[i];
+      else
+	r =  2*(S[i]*(L[j]-l)+ S[j]*(l-L[i]))/(L[j]-L[i]);
+    }
+  assert(r<=1 && r>=0);
+  return r ;
+    
+}
+
+
+#ifdef DRAWING 
+
+void MetricAnIso::Draw(R2 c) const 
+{ 
+  float x= c.x,y= c.y;
+  if (InPtScreen(x,y)) {
+  R2 X(cos(0.0),sin(0.0));
+  X = X / operator()(X);
+  rmoveto(x+X.x,y+X.y);
+  
+  for (int i=1;i<=100;i++)
+   { double t= 2*Pi*i/100.0;
+     R2 X(cos(t),sin(t));
+     X = X / Max(operator()(X),1.0e-5);
+     rlineto(x+X.x,y+X.y); } 
+  }
+}
+
+void MetricIso::Draw(R2 c) const 
+{ 
+  float x= c.x,y= c.y;
+  if (InPtScreen(x,y)) {
+  rmoveto(x+h,y);
+  for (int i=1;i<=40;i++)
+   { double t= Pi*i/20.0;
+     rlineto(x+h*cos(t),y+h*sin(t)); } 
+  }
+}
+
+
+#endif
+}   // end of namespace bamg 
diff --git a/contrib/bamg/bamglib/Metric.h b/contrib/bamg/bamglib/Metric.h
new file mode 100644
index 0000000000000000000000000000000000000000..18bbf4d6d35287ba947f41167d3eeb2f5c4236ed
--- /dev/null
+++ b/contrib/bamg/bamglib/Metric.h
@@ -0,0 +1,225 @@
+// -*- Mode : c++ -*-
+//
+// SUMMARY  :      
+// USAGE    :        
+// ORG      : 
+// AUTHOR   : Frederic Hecht
+// E-MAIL   : hecht@ann.jussieu.fr
+//
+
+/*
+ 
+ This file is part of Freefem++
+ 
+ Freefem++ is free software; you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+ 
+ Freefem++  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 Lesser General Public License for more details.
+ 
+ You should have received a copy of the GNU Lesser General Public License
+ along with Freefem++; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#ifndef TYPEMETRIX
+#define TYPEMETRIX MetricAnIso
+#endif
+
+//#include "R2.h"
+namespace bamg {
+
+typedef P2<double,double> D2;
+typedef P2xP2<double,double> D2xD2;
+
+class  MetricAnIso;
+class MatVVP2x2;
+class MetricIso;
+
+typedef TYPEMETRIX Metric;
+
+
+class MetricIso{
+  friend class MatVVP2x2;
+   Real4 h;
+public:
+  MetricIso(Real4 a): h(a){}
+  MetricIso(const MetricAnIso M);// {MatVVP2x2 vp(M);h=1/sqrt(Max(vp.lambda1,vp.lambda2));}
+  MetricIso(Real8 a11,Real8 a21,Real8 a22);// {*this=MetricAnIso(a11,a21,a22));}
+  MetricIso(): h(1) {}; // 
+  MetricIso(const Real8  a[3],const  MetricIso m0,
+	   const  MetricIso m1,const  MetricIso m2 )
+    : h(hinterpole 
+	? (a[0]*m0.h+a[1]*m1.h+a[2]*m2.h)
+	: 1/sqrt(a[0]/(m0.h*m0.h)+a[1]/(m1.h*m1.h)+a[2]/(m2.h*m2.h))) {}
+    MetricIso(const Real8  a,const  MetricIso ma,
+	          const Real8  b,const  MetricIso mb)
+    : h(hinterpole
+	? a*ma.h+b*mb.h
+	:1/sqrt(a/(ma.h*ma.h)+b/(mb.h*mb.h))) {}
+  R2 Orthogonal(const R2 A)const {return R2(-h*A.y,h*A.x);}
+  R2 Orthogonal(const I2 A)const {return R2(-h*A.y,h*A.x);}
+//  D2 Orthogonal(const D2 A)const {return D2(-h*A.y,h*A.x);}
+  Real8 operator()(R2 x) const { return sqrt((x,x))/h;};
+  Real8 operator()(R2 x,R2 y) const { return ((x,y))/(h*h);};
+  int  IntersectWith(MetricIso M) {int r=0;if (M.h<h) r=1,h=M.h;return r;}
+  MetricIso operator*(Real8 c) const {return  MetricIso(h/c);} 
+  MetricIso operator/(Real8 c) const {return  MetricIso(h*c);}
+  Real8 det() const {return 1./(h*h*h*h);}    
+  operator D2xD2(){ return D2xD2(1/(h*h),0.,0.,1/(h*h));}
+  void     Box(Real4 & hx,Real4 & hy) { hx=h,hy=h;}
+  friend ostream& operator <<(ostream& f, const  MetricIso & M)
+  {f << " h=" << M.h<< ";" ;   return f;}
+
+#ifdef DRAWING
+  void Draw(R2 ) const;
+#endif
+};
+
+
+class MetricAnIso{ public:
+  friend class MatVVP2x2;
+  Real8 a11,a21,a22;
+  MetricAnIso(Real8 a): a11(1/(a*a)),a21(0),a22(1/(a*a)){}
+  MetricAnIso(Real8 a,Real8 b,Real8 c) :a11(a),a21(b),a22(c){}
+  MetricAnIso()  {}; // 
+  MetricAnIso(const Real8  a[3],const  MetricAnIso m0,
+	      const  MetricAnIso m1,const  MetricAnIso m2 );
+  R2 mul(const R2 x)const {return R2(a11*x.x+a21*x.y,a21*x.x+a22*x.y);}
+  Real8 det() const {return a11*a22-a21*a21;}  
+  R2 Orthogonal(const R2 x){return R2(-(a21*x.x+a22*x.y),a11*x.x+a21*x.y);}
+  R2 Orthogonal(const I2 x){return R2(-(a21*x.x+a22*x.y),a11*x.x+a21*x.y);}
+//  D2 Orthogonal(const D2 x){return D2(-(a21*x.x+a22*x.y),a11*x.x+a21*x.y);}
+  MetricAnIso( Real8  a,const  MetricAnIso ma,
+	       Real8  b,const  MetricAnIso mb);
+  int  IntersectWith(const MetricAnIso M);
+  MetricAnIso operator*(Real8 c) const {Real8 c2=c*c;return  MetricAnIso(a11*c2,a21*c2,a22*c2);} 
+  MetricAnIso operator/(Real8 c) const {Real8 c2=1/(c*c);return  MetricAnIso(a11*c2,a21*c2,a22*c2);} 
+  operator D2xD2(){ return D2xD2(a11,a21,a21,a22);}
+
+  Real8 operator()(R2 x) const { return sqrt(x.x*x.x*a11+2*x.x*x.y*a21+x.y*x.y*a22);};
+//  Real8 operator()(D2 x) const { return sqrt(x.x*x.x*a11+2*x.x*x.y*a21+x.y*x.y*a22);};
+  Real8 operator()(R2 x,R2 y) const { return x.x*y.x*a11+(x.x*x.y+x.y*y.x)*a21+x.y*y.y*a22;};
+  inline void  Box(Real4 &hx,Real4 &hy) const ;  
+ friend ostream& operator <<(ostream& f, const  MetricAnIso & M)
+  {f << " mtr a11=" << M.a11 << " a21=a12=" << M.a21 << " a22=" << M.a22 << ";" ;   return f;}
+#ifdef DRAWING
+  void Draw(R2 ) const;
+#endif
+  MetricAnIso(const MatVVP2x2);
+};
+
+
+class MatVVP2x2 
+{
+  friend  class MetricAnIso;
+  friend  class MetricIso;
+public:
+  double lambda1,lambda2;
+  D2 v;
+
+
+  MatVVP2x2(double r1,double r2,const D2 vp1): lambda1(r1),lambda2(r2),v(vp1){}
+  
+  void  Abs(){lambda1=bamg::Abs(lambda1),lambda2=bamg::Abs(lambda2);}
+  void  pow(double p){lambda1=::pow(lambda1,p);lambda2=::pow(lambda2,p);}
+  void  Min(double a) { lambda1=bamg::Min(a,lambda1); lambda2=bamg::Min(a,lambda2) ;}
+  void  Max(double a) { lambda1=bamg::Max(a,lambda1); lambda2=bamg::Max(a,lambda2) ;}
+
+  void Minh(double h) {Max(1.0/(h*h));}
+  void Maxh(double h) {Min(1.0/(h*h));}
+  void Isotrope() {lambda1=lambda2=bamg::Max(lambda1,lambda2);}
+  friend ostream& operator <<(ostream& f, const MatVVP2x2 & c)
+  { f << '{' << 1/sqrt(c.lambda1)<< ',' << 1/sqrt(c.lambda2) << ','<< c.v << '}' <<flush ; return f; }
+  friend istream& operator >>(istream& f,  MatVVP2x2 & c)
+  { f >> c.lambda1 >>c.lambda2 >> c.v.x >> c.v.y ;c.v /= Norme2(c.v); return f; }
+  MatVVP2x2(const MetricAnIso );
+  MatVVP2x2(const MetricIso M) :  lambda1(1/(M.h*M.h)),lambda2(1/(M.h*M.h)),v(1,0) {}
+  Real8 hmin() const {return sqrt(1/bamg::Max3(lambda1,lambda2,1e-30));}
+  Real8 hmax() const {return sqrt(1/bamg::Max(bamg::Min(lambda1,lambda2),1e-30));}
+  Real8 lmax() const {return bamg::Max3(lambda1,lambda2,1e-30);}
+  Real8 lmin() const {return bamg::Max(bamg::Min(lambda1,lambda2),1e-30);}
+  Real8 Aniso2() const  { return lmax()/lmin();}
+  inline void BoundAniso2(const Real8 coef);
+  Real8 Aniso() const  { return sqrt( Aniso2());}
+  void BoundAniso(const Real8 c){ BoundAniso2(1/(c*c));}
+  void operator *=(double coef){ lambda1*=coef;lambda2*=coef;}
+};
+
+inline void  MatVVP2x2::BoundAniso2(const Real8 coef) 
+{
+  if (coef<=1.00000000001) 
+    if (lambda1 < lambda2)
+      lambda1 = bamg::Max(lambda1,lambda2*coef);
+    else
+      lambda2 = bamg::Max(lambda2,lambda1*coef);
+  else  // a verifier 
+    if (lambda1 > lambda2)
+      lambda1 = bamg::Min(lambda1,lambda2*coef);
+    else
+      lambda2 = bamg::Min(lambda2,lambda1*coef);
+}
+
+
+
+
+void ReductionSimultanee( MetricAnIso M1,  MetricAnIso M2,double & l1,double & l2, D2xD2 & V) ;
+
+inline MetricAnIso::MetricAnIso(const MatVVP2x2 M)  
+{
+ //     recompose M in: M = V^t lambda V 
+  //     V = ( v,v^\perp)
+  //  where v^\perp = (-v_1,v_0)
+  double v00=M.v.x*M.v.x;
+  double v11=M.v.y*M.v.y;
+  double v01=M.v.x*M.v.y;
+  a11=v00*M.lambda1+v11*M.lambda2;
+  a21=v01*(M.lambda1-M.lambda2);
+  a22=v00*M.lambda2+v11*M.lambda1;
+}
+
+
+inline   void  MetricAnIso::Box(Real4 &hx,Real4 &hy) const 
+{
+  Real8 d=  a11*a22-a21*a21;
+  hx = sqrt(a22/d);
+  hy = sqrt(a11/d);
+  //  cerr << " hx = " << hx << " hy =  " << hy << endl;
+}
+
+
+inline MetricIso::MetricIso(const MetricAnIso M) 
+  {MatVVP2x2 vp(M);h=1/sqrt(Max(vp.lambda1,vp.lambda2));}
+  
+inline  MetricIso::MetricIso(Real8 a11,Real8 a21,Real8 a22)
+  {MatVVP2x2 vp(MetricAnIso(a11,a21,a22));h=1/sqrt(Max(vp.lambda1,vp.lambda2));}
+
+
+
+class SaveMetricInterpole {
+  friend  Real8 LengthInterpole(const MetricAnIso ,const  MetricAnIso , R2 );
+  friend Real8 abscisseInterpole(const MetricAnIso ,const  MetricAnIso , R2 ,Real8 ,int );
+  int opt;
+  Real8 lab;
+  Real8 L[1024],S[1024];
+};
+
+extern SaveMetricInterpole  LastMetricInterpole; // for optimization 
+
+
+ Real8 LengthInterpole(const MetricAnIso Ma,const  MetricAnIso Mb, R2 AB);
+ Real8 abscisseInterpole(const MetricAnIso Ma,const  MetricAnIso Mb, R2 AB,Real8 s,int optim=0);
+
+
+
+inline Real8 LengthInterpole(Real8 la,Real8 lb) 
+{   return ( Abs(la - lb) < 1.0e-6*Max3(la,lb,1.0e-20) ) ?  (la+lb)/2  : la*lb*log(la/lb)/(la-lb);}
+
+inline Real8 abscisseInterpole(Real8 la,Real8 lb,Real8 lab,Real8 s)
+{ return ( Abs(la - lb) <1.0e-6*Max3(la,lb,1.0e-20))  ? s : (exp(s*lab*(la-lb)/(la*lb))-1)*lb/(la-lb);}
+
+}
diff --git a/contrib/bamg/bamglib/QuadTree.cpp b/contrib/bamg/bamglib/QuadTree.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..44a22f2efedd88c0b861be8aa96f9c54b60380b5
--- /dev/null
+++ b/contrib/bamg/bamglib/QuadTree.cpp
@@ -0,0 +1,542 @@
+// -*- Mode : c++ -*-
+//
+// SUMMARY  :      
+// USAGE    :        
+// ORG      : 
+// AUTHOR   : Frederic Hecht
+// E-MAIL   : hecht@ann.jussieu.fr
+//
+
+/*
+ 
+ This file is part of Freefem++
+ 
+ Freefem++ is free software; you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+ 
+ Freefem++  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 Lesser General Public License for more details.
+ 
+ You should have received a copy of the GNU Lesser General Public License
+ along with Freefem++; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include <limits.h>
+//#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "Meshio.h"
+#include "Mesh2.h"
+#include "QuadTree.h"
+
+namespace bamg {
+
+#define INTER_SEG(a,b,x,y) (((y) > (a)) && ((x) <(b)))
+#define ABS(i) ((i)<0 ?-(i) :(i))
+#define MAX1(i,j) ((i)>(j) ?(i) :(j))
+#define NORM(i1,j1,i2,j2) MAX1(ABS((i1)-(j1)),ABS((i2)-(j2)))
+
+#define IJ(i,j,l) ( ( j & l) ? (( i & l) ? 3 : 2 ) :( ( i & l)? 1 : 0 ))
+#define I_IJ(k,l)  (( k&1) ? l : 0)
+#define J_IJ(k,l)  (( k&2) ? l : 0)
+
+
+#ifdef DRAWING
+
+void  QuadTree::Draw()
+{
+  QuadTreeBox * pb[ MaxDeep ];
+  int  pi[ MaxDeep  ];
+  Icoor1 ii[  MaxDeep ], jj [ MaxDeep];
+  register int l=0; // level
+  register QuadTreeBox * b;
+  IntQuad hb =  MaxISize;
+  if(!root) return;
+  //  Int4 kkk =0;
+  pb[0]=  root;
+  pi[0]= root->n>0 ?(int)  root->n : 4  ;
+  ii[0]=jj[0]=0;
+  do{    
+    b= pb[l];
+
+    while (pi[l]--)
+      { 
+	if (b->n>0) // Vertex QuadTreeBox none empty
+	    { // 
+	      for (int k=0;k<b->n;k++)
+		{
+		  I2 i2 =  b->v[k]->i;
+		  IMoveTo(i2.x,i2.y+50);
+		  ILineTo(i2.x,i2.y-50);
+		  IMoveTo(i2.x+50,i2.y);
+		  ILineTo(i2.x-50,i2.y);
+
+		  assert(ii[l] <= i2.x);
+		  assert(jj[l] <= i2.y);
+		  assert(ii[l] +hb > i2.x);
+		  assert(jj[l] +hb > i2.y);
+
+		}
+	      break;
+	    }
+	else // Pointer QuadTreeBox 
+	    { 
+	      register int lll = pi[l];
+	      register QuadTreeBox *b0=b;
+	      
+	      if ((b=b->b[lll])) 
+		{ 
+		  hb >>=1 ; // div by 2
+		  register Icoor1 iii = ii[l]+I_IJ(lll,hb);
+		  register Icoor1 jjj = jj[l]+J_IJ(lll,hb);
+		  
+		  pb[++l]=  b;
+		  pi[l]= 4;
+		  ii[l]= iii;
+		  jj[l]= jjj;
+		  
+		  IMoveTo(ii[l],jj[l]);
+		  ILineTo(ii[l]+hb,jj[l]);
+		  ILineTo(ii[l]+hb,jj[l]+hb);
+		  ILineTo(ii[l]   ,jj[l]+hb);
+		  ILineTo(ii[l]   ,jj[l]);
+		  
+		  
+		}
+	      else
+		{
+		  register Icoor1 iii = ii[l]+I_IJ(lll,hb/2);
+		  register Icoor1 jjj = jj[l]+J_IJ(lll,hb/2);
+		  b=b0;
+
+		  IMoveTo(iii,     jjj);
+		  ILineTo(iii+hb/2,jjj+hb/2);
+		  IMoveTo(iii+hb/2,jjj);
+		  ILineTo(iii     ,jjj+hb/2);
+
+		}
+	    }
+      }
+    hb <<= 1; // mul by 2 
+  } while (l--);
+
+}
+
+#endif
+
+Vertex *  QuadTree::NearestVertex(Icoor1 i,Icoor1 j)
+{
+  QuadTreeBox * pb[ MaxDeep ];
+  int  pi[ MaxDeep  ];
+  Icoor1 ii[  MaxDeep ], jj [ MaxDeep];
+  register int l=0; // level
+  register QuadTreeBox * b;
+  IntQuad  h=MaxISize,h0;
+  IntQuad hb =  MaxISize;
+  Icoor1  i0=0,j0=0;
+  Icoor1  iplus( i<MaxISize?(i<0?0:i):MaxISize-1);
+  Icoor1  jplus( j<MaxISize?(j<0?0:j):MaxISize-1);
+  
+  Vertex *vn=0;
+  
+  // init for optimisation ---
+  b = root;
+  register Int4  n0;
+  if (!root->n)
+    return vn; // empty tree 
+  
+  while( (n0 = b->n) < 0) 
+    {
+      // search the non empty 
+      // QuadTreeBox containing  the point (i,j)
+      register Icoor1 hb2 = hb >> 1 ;
+      register  int k = IJ(iplus,jplus,hb2);// QuadTreeBox number of size hb2 contening i;j
+      register QuadTreeBox * b0= b->b[k];
+      if ( ( b0 == 0) || (b0->n == 0) ) 
+	break; // null box or empty   => break 	    
+      NbQuadTreeBoxSearch++;
+      b=b0;	
+      i0 += I_IJ(k,hb2); // i orign of QuadTreeBox
+      j0 += J_IJ(k,hb2); // j orign of QuadTreeBox 
+      hb = hb2; 
+    }
+  
+  
+  if ( n0 > 0) 
+    {  
+      for(register int k=0;k<n0;k++)
+	{
+	  I2 i2 =  b->v[k]->i;
+	  h0 = NORM(iplus,i2.x,jplus,i2.y);
+	  if (h0 <h) {
+	    h = h0;
+	    vn = b->v[k];}
+	  NbVerticesSearch++;
+	}
+      return vn;
+    }
+  // general case -----
+  pb[0]= b;
+  pi[0]=b->n>0 ?(int)  b->n : 4  ;
+  ii[0]=i0;
+  jj[0]=j0;
+  h=hb;
+  do {    
+    b= pb[l];
+    while (pi[l]--)
+      { 	      
+	register int k = pi[l];
+	
+	if (b->n>0) // Vertex QuadTreeBox none empty
+	  { 
+	    NbVerticesSearch++;
+	    I2 i2 =  b->v[k]->i;
+	    h0 = NORM(iplus,i2.x,jplus,i2.y);
+	    if (h0 <h) 
+	      {
+		h = h0;
+		vn = b->v[k];
+	      }
+	  }
+	else // Pointer QuadTreeBox 
+	  { 
+	    register QuadTreeBox *b0=b;
+	    NbQuadTreeBoxSearch++;
+	    if ((b=b->b[k])) 
+	      {
+		hb >>=1 ; // div by 2
+		register Icoor1 iii = ii[l]+I_IJ(k,hb);
+		register Icoor1 jjj = jj[l]+J_IJ(k,hb);
+		
+		if  (INTER_SEG(iii,iii+hb,iplus-h,iplus+h) && INTER_SEG(jjj,jjj+hb,jplus-h,jplus+h)) 
+		  {
+		    pb[++l]=  b;
+		    pi[l]= b->n>0 ?(int)  b->n : 4  ;
+		    ii[l]= iii;
+		    jj[l]= jjj;
+		    
+		  }
+		else
+		  b=b0, hb <<=1 ;
+	      }
+	    else
+	      b=b0;
+	  }
+      }
+    hb <<= 1; // mul by 2 
+  } while (l--);
+  
+  return vn;
+}
+
+
+
+Vertex *   QuadTree::ToClose(Vertex & v,Real8 seuil,Icoor1 hx,Icoor1 hy)
+{
+  const Icoor1 i=v.i.x;
+  const Icoor1 j=v.i.y;
+  const R2 X(v.r);
+  const Metric  Mx(v.m);
+
+  QuadTreeBox * pb[ MaxDeep ];
+  int  pi[ MaxDeep  ];
+  Icoor1 ii[  MaxDeep ], jj [ MaxDeep];
+  register int l=0; // level
+  register QuadTreeBox * b;
+  Icoor1 h=MaxISize;
+  Icoor1 hb =  MaxISize;
+  Icoor1 i0=0,j0=0;
+  
+  //  Vertex *vn=0;
+  
+  if (!root->n)
+    return 0; // empty tree 
+  
+  // general case -----
+  pb[0]=root;
+  pi[0]=root->n>0 ?(int)  root->n : 4  ;
+  ii[0]=i0;
+  jj[0]=j0;
+  h=hb;
+  do {    
+    b= pb[l];
+    while (pi[l]--)
+      { 	      
+	register int k = pi[l];
+	
+	if (b->n>0) // Vertex QuadTreeBox none empty
+	  { 
+	    NbVerticesSearch++;
+	    I2 i2 =  b->v[k]->i;
+	    if ( ABS(i-i2.x) <hx && ABS(j-i2.y) <hy )
+	      {
+		R2 XY(X,b->v[k]->r);
+		Real8 dd;
+	      // old code	        if( Mx(XY) + b->v[k]->m(XY) < seuil )
+	        if( (dd= LengthInterpole(Mx(XY), b->v[k]->m(XY)))  < seuil )
+		  {
+		    //  cout <<  CurrentTh->Number(v) << "is To Close " 
+		    // << CurrentTh->Number( b->v[k]) << " l=" <<dd<<endl;
+		    return b->v[k]; 
+		  }
+	      }
+	  }
+	else // Pointer QuadTreeBox 
+	  { 
+	    register QuadTreeBox *b0=b;
+	    NbQuadTreeBoxSearch++;
+	    if ((b=b->b[k]))
+	      {
+		hb >>=1 ; // div by 2
+		register long iii = ii[l]+I_IJ(k,hb);
+		register long jjj = jj[l]+J_IJ(k,hb);
+		
+		if  (INTER_SEG(iii,iii+hb,i-hx,i+hx) && INTER_SEG(jjj,jjj+hb,j-hy,j+hy)) 
+		  {
+		    pb[++l]=  b;
+		    pi[l]= b->n>0 ?(int)  b->n : 4  ;
+		    ii[l]= iii;
+		    jj[l]= jjj;
+		    
+		  }
+		else
+		  b=b0, hb <<=1 ;
+	      }
+	    else
+	      b=b0;
+	  }
+      }
+    hb <<= 1; // mul by 2 
+  } while (l--);
+  
+  return 0;
+}
+
+
+void  QuadTree::Add( Vertex & w)
+{
+  QuadTreeBox ** pb , *b;
+  register long i=w.i.x, j=w.i.y,l=MaxISize;
+  pb = &root;
+  //    cout << pb << " " << &root << endl;
+  while( (b=*pb) && (b->n<0))
+    { 
+      b->n--;
+      l >>= 1;
+      pb = &b->b[IJ(i,j,l)];
+    }
+  if  (b) {      
+    if (b->n > 3 &&  b->v[3] == &w) return;
+    if (b->n > 2 &&  b->v[2] == &w) return;
+    if (b->n > 1 &&  b->v[1] == &w) return;
+    if (b->n > 0 &&  b->v[0] == &w) return;
+  }
+  assert(l);
+  while ((b= *pb) && (b->n == 4)) // the QuadTreeBox is full
+    { 
+      Vertex *v4[4]; // copy of the QuadTreeBox vertices
+      
+      v4[0]= b->v[0];
+      v4[1]= b->v[1];
+      v4[2]= b->v[2];
+      v4[3]= b->v[3];
+      b->n = -b->n; // mark is pointer QuadTreeBox
+      b->b[0]=b->b[1]=b->b[2]=b->b[3]=0; // set empty QuadTreeBox ptr
+      l >>= 1;    // div the size by 2
+      for (register int k=0;k<4;k++) // for the 4 vertices find the sub QuadTreeBox ij
+	{ 
+	  register int ij;
+	  register QuadTreeBox * bb =  b->b[ij=IJ(v4[k]->i.x,v4[k]->i.y,l)];
+	  if (!bb) 
+	    bb=b->b[ij]=NewQuadTreeBox(); // alloc the QuadTreeBox 
+	  //    cout << bb << " " << k << " "  << ij <<  endl;
+	  bb->v[bb->n++] = v4[k];
+	}
+      pb = &b->b[IJ(i,j,l)];
+    }
+  if (!(b = *pb))
+    b=*pb= NewQuadTreeBox(); //  alloc the QuadTreeBox 
+  //   cout << b << " " << b->n << endl;
+  b->v[b->n++]=&w; // we add the vertex 
+  NbVertices++;    
+}
+
+QuadTree::QuadTree(Triangles * t,long nbv) : 
+  lenStorageQuadTreeBox(t->nbvx/8+10),
+  th(t),
+  NbQuadTreeBox(0),
+  NbVertices(0),
+  NbQuadTreeBoxSearch(0),
+  NbVerticesSearch(0)
+{ 
+  if (nbv == -1) nbv = t->nbv;
+  sb =new StorageQuadTreeBox(lenStorageQuadTreeBox);
+  root=NewQuadTreeBox();
+  assert( MaxISize > MaxICoor);
+  for (Int4 i=0;i<nbv;i++) 
+    Add(t->vertices[i]);
+#ifdef DRAWING1
+  Draw();
+#endif
+}
+
+QuadTree::QuadTree() : 
+  lenStorageQuadTreeBox(100),
+  th(0),
+  NbQuadTreeBox(0),
+  NbVertices(0),
+  NbQuadTreeBoxSearch(0),
+  NbVerticesSearch(0)
+{
+  sb =new StorageQuadTreeBox(lenStorageQuadTreeBox);
+  root=NewQuadTreeBox();
+}
+QuadTree::StorageQuadTreeBox::StorageQuadTreeBox(long ll,StorageQuadTreeBox *nn)
+{
+  len = ll;
+  n = nn;
+  b = new QuadTreeBox[ll];
+  for (int i = 0; i <ll;i++)
+    b[i].n =0,b[i].b[0]=b[i].b[1]=b[i].b[2]=b[i].b[3]=0;
+  bc =b;
+  be = b +ll;
+  assert(b);
+}
+
+QuadTree::~QuadTree()
+{
+  delete sb; 
+  root=0;
+}
+
+ostream& operator <<(ostream& f, const  QuadTree & qt)
+{ 
+  f << " the quadtree "  << endl;
+  f << " NbQuadTreeBox = " << qt.NbQuadTreeBox 
+    << " Nb Vertices = " <<  qt.NbVertices << endl;
+  f << " NbQuadTreeBoxSearch " << qt.NbQuadTreeBoxSearch  
+    << " NbVerticesSearch " << qt.NbVerticesSearch << endl;
+  f << " SizeOf QuadTree" << qt.SizeOf() << endl;
+  //     return  dump(f,*qt.root);
+  return  f;
+}
+
+Vertex *  QuadTree::NearestVertexWithNormal(Icoor1 i,Icoor1 j)
+{
+  QuadTreeBox * pb[ MaxDeep ];
+  int  pi[ MaxDeep  ];
+  Icoor1 ii[  MaxDeep ], jj [ MaxDeep];
+  int l; // level
+  QuadTreeBox * b;
+  IntQuad  h=MaxISize,h0;
+  IntQuad hb =  MaxISize;
+  Icoor1  i0=0,j0=0;
+  Icoor1  iplus( i<MaxISize?(i<0?0:i):MaxISize-1);
+  Icoor1  jplus( j<MaxISize?(j<0?0:j):MaxISize-1);
+  
+  Vertex *vn=0;
+  
+  // init for optimisation ---
+  b = root;
+  register Int4  n0;
+  if (!root->n)
+    return vn; // empty tree 
+  
+  while( (n0 = b->n) < 0) 
+    {
+      // search the non empty 
+      // QuadTreeBox containing  the point (i,j)
+      register Icoor1 hb2 = hb >> 1 ;
+      register  int k = IJ(iplus,jplus,hb2);// QuadTreeBox number of size hb2 contening i;j
+      register QuadTreeBox * b0= b->b[k];
+      if ( ( b0 == 0) || (b0->n == 0) ) 
+	break; // null box or empty   => break 	    
+      NbQuadTreeBoxSearch++;
+      b=b0;	
+      i0 += I_IJ(k,hb2); // i orign of QuadTreeBox
+      j0 += J_IJ(k,hb2); // j orign of QuadTreeBox 
+      hb = hb2; 
+    }
+  
+  
+  if ( n0 > 0) 
+    {  
+      for(register int k=0;k<n0;k++)
+	{
+	  I2 i2 =  b->v[k]->i;
+	  //   try if is in the right sens -- 
+	  h0 = NORM(iplus,i2.x,jplus,i2.y);
+	  if (h0 <h) {
+	    h = h0;
+	    vn = b->v[k];}
+	  NbVerticesSearch++;
+	}
+	if (vn) return vn; 
+    }
+  // general case -----
+  // INITIALISATION OF THE HEAP 
+  l =0; // level 
+  pb[0]= b;
+  pi[0]=b->n>0 ?(int)  b->n : 4  ;
+  ii[0]=i0;
+  jj[0]=j0;
+  h=hb;
+  do {   // walk on the tree  
+    b= pb[l];
+    while (pi[l]--) // loop on 4 element of the box
+      { 	      
+       int k = pi[l];
+	
+	if (b->n>0) // Vertex QuadTreeBox none empty
+	  { 
+	    NbVerticesSearch++;
+	    I2 i2 =  b->v[k]->i;
+	    // if good sens when try -- 
+	    
+	    h0 = NORM(iplus,i2.x,jplus,i2.y);
+	    if (h0 <h) 
+	      {
+		h = h0;
+		vn = b->v[k];
+	      }
+	  }
+	else // Pointer QuadTreeBox 
+	  { 
+	    register QuadTreeBox *b0=b;
+	    NbQuadTreeBoxSearch++;
+	    if ((b=b->b[k])) 
+	      {
+		hb >>=1 ; // div by 2
+		register Icoor1 iii = ii[l]+I_IJ(k,hb);
+		register Icoor1 jjj = jj[l]+J_IJ(k,hb);
+		
+		if  (INTER_SEG(iii,iii+hb,iplus-h,iplus+h) && INTER_SEG(jjj,jjj+hb,jplus-h,jplus+h)) 
+		  {
+		    pb[++l]=  b;
+		    pi[l]= b->n>0 ?(int)  b->n : 4  ;
+		    ii[l]= iii;
+		    jj[l]= jjj;
+		    
+		  }
+		else
+		  b=b0, hb <<=1 ;
+	      }
+	    else
+	      b=b0;
+	  }
+      }
+    hb <<= 1; // mul by 2 
+  } while (l--);
+  
+  return vn;
+}
+
+
+}  // end of namespace bamg
+
diff --git a/contrib/bamg/bamglib/QuadTree.h b/contrib/bamg/bamglib/QuadTree.h
new file mode 100644
index 0000000000000000000000000000000000000000..016698140798d01370d160ae3316ee46e72ff2db
--- /dev/null
+++ b/contrib/bamg/bamglib/QuadTree.h
@@ -0,0 +1,111 @@
+// -*- Mode : c++ -*-
+//
+// SUMMARY  :      
+// USAGE    :        
+// ORG      : 
+// AUTHOR   : Frederic Hecht
+// E-MAIL   : hecht@ann.jussieu.fr
+//
+
+/*
+ 
+ This file is part of Freefem++
+ 
+ Freefem++ is free software; you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+ 
+ Freefem++  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 Lesser General Public License for more details.
+ 
+ You should have received a copy of the GNU Lesser General Public License
+ along with Freefem++; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+namespace bamg {
+
+const int MaxDeep = 30;
+typedef  long  IntQuad;
+const IntQuad MaxISize = ( 1L << MaxDeep);
+
+
+class Triangles;
+class Vertex;
+
+class QuadTree {
+ public:
+
+  class QuadTreeBox { 
+  public:
+
+    long n; // if n < 4 => Vertex else =>  QuadTreeBox;
+    union {
+      QuadTreeBox *b[4];
+      Vertex * v[4];
+    };
+    
+
+  }; // end class QuadTreeBox  /////////////////
+
+  class StorageQuadTreeBox {
+  public:
+    QuadTreeBox *b,*bc,*be;
+    long len;
+    StorageQuadTreeBox *n; // next StorageQuadTreeBox
+    StorageQuadTreeBox(long ,StorageQuadTreeBox * =0);
+    ~StorageQuadTreeBox()
+    { //cout <<  "~StorageQuadTreeBox " << this << " n " << n << " b " << b << endl;
+      if(n) delete n;
+      delete [] b;
+    }
+    long  SizeOf() const {
+      return len*sizeof(QuadTreeBox)+sizeof(StorageQuadTreeBox)+ (n?n->SizeOf():0);
+    }
+  }; // end class  StorageQuadTreeBox 
+  
+  StorageQuadTreeBox * sb;
+  
+  
+  long  lenStorageQuadTreeBox;
+
+public:
+  QuadTreeBox * root;
+  Triangles *th;
+  long NbQuadTreeBox,NbVertices;
+  long NbQuadTreeBoxSearch,NbVerticesSearch;
+  Vertex * NearestVertex(Icoor1 i,Icoor1 j);
+  Vertex *  NearestVertexWithNormal(Icoor1 i,Icoor1 j); // new version  
+  Vertex * ToClose(Vertex & ,Real8 ,Icoor1,Icoor1);
+  long SizeOf() const {return sizeof(QuadTree)+sb->SizeOf();}
+
+#ifdef DRAWING
+    void Draw();
+#endif
+
+  void  Add( Vertex & w);
+
+  QuadTreeBox* NewQuadTreeBox()
+  {
+    ///cout << "NewQuadTreeBox " << sb << " " << sb->bc << " " 
+    //<< sb->be << " " <<lenStorageQuadTreeBox <<endl;
+    if(! (sb->bc<sb->be)) 
+	sb=new StorageQuadTreeBox(lenStorageQuadTreeBox,sb);
+
+    assert(sb && (sb->bc->n == 0));
+    NbQuadTreeBox++;
+    return sb->bc++;
+  }
+  ~QuadTree();
+  QuadTree(Triangles * t,long nbv=-1);
+  QuadTree();
+  friend ostream& operator <<(ostream& f, const  QuadTree & qt);
+
+
+	
+};
+}
+//#undef IJ
diff --git a/contrib/bamg/bamglib/R2.cpp b/contrib/bamg/bamglib/R2.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..5e79e4bf99129c13864cb3d7ec64a0c2ceee9f4d
--- /dev/null
+++ b/contrib/bamg/bamglib/R2.cpp
@@ -0,0 +1,31 @@
+// -*- Mode : c++ -*-
+//
+// SUMMARY  :      
+// USAGE    :        
+// ORG      : 
+// AUTHOR   : Frederic Hecht
+// E-MAIL   : hecht@ann.jussieu.fr
+//
+
+/*
+ 
+ This file is part of Freefem++
+ 
+ Freefem++ is free software; you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+ 
+ Freefem++  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 Lesser General Public License for more details.
+ 
+ You should have received a copy of the GNU Lesser General Public License
+ along with Freefem++; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include <iostream>
+using namespace std;
+#include "R2.h"
diff --git a/contrib/bamg/bamglib/R2.h b/contrib/bamg/bamglib/R2.h
new file mode 100644
index 0000000000000000000000000000000000000000..cbb3df46e29723cecce546fb466e4ba70d9533e5
--- /dev/null
+++ b/contrib/bamg/bamglib/R2.h
@@ -0,0 +1,135 @@
+// -*- Mode : c++ -*-
+//
+// SUMMARY  :      
+// USAGE    :        
+// ORG      : 
+// AUTHOR   : Frederic Hecht
+// E-MAIL   : hecht@ann.jussieu.fr
+//
+
+/*
+ 
+ This file is part of Freefem++
+ 
+ Freefem++ is free software; you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+ 
+ Freefem++  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 Lesser General Public License for more details.
+ 
+ You should have received a copy of the GNU Lesser General Public License
+ along with Freefem++; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+namespace bamg {
+template <class R,class RR> class P2xP2;
+
+template <class R,class RR>
+class P2 {
+  
+public:  
+  R x,y;
+  P2 () :x(0),y(0) {};
+  P2 (R a,R b)  :x(a),y(b)  {}
+  P2 (P2 A,P2 B) : x(B.x-A.x),y(B.y-A.y) {}
+  P2<R,RR>   operator+(const P2<R,RR> & cc) const {return P2<R,RR>(x+cc.x,y+cc.y);}
+  P2<R,RR>   operator-(const P2<R,RR> & cc) const {return P2<R,RR>(x-cc.x,y-cc.y);}
+  P2<R,RR>   operator-()  const{return P2<R,RR>(-x,-y);}
+//  RR   operator*(const P2<R,RR> & cc) const {return  (RR) x* (RR) cc.x+(RR) y* (RR) cc.y;} // produit scalaire
+  RR   operator,(const P2<R,RR> & cc) const {return  (RR) x* (RR) cc.x+(RR) y* (RR) cc.y;} // produit scalaire
+  P2<R,RR>   operator*(R  cc) const {return P2<R,RR>(x*cc,y*cc);}
+ // P2<R,RR>   operator*(RR  cc) const {return P2<R,RR>((R)(x*cc),(R)(y*cc));}
+  P2<R,RR>   operator/(R  cc) const {return P2<R,RR>(x/cc,y/cc);}
+  P2<R,RR>  operator+=(const  P2<R,RR> & cc) {x += cc.x;y += cc.y;return *this;}
+  P2<R,RR>  operator/=(const  R r) {x /= r;y /= r;return *this;}
+  P2<R,RR>  operator*=(const  R r) {x *= r;y *= r;return *this;}
+  P2<R,RR>  operator-=(const  P2<R,RR> & cc) {x -= cc.x;y -= cc.y;return *this;}
+//  P2<R,RR> Orthogonal(const   P2<R,RR> r) {return P2<R,RR>(-r.y,r.x);}
+ };
+
+template <class R,class RR>
+class P2xP2 { // x ligne 1 y ligne2 
+
+  friend ostream& operator <<(ostream& f, const P2xP2<R,RR> & c) 
+     { f << '[' << c.x << ',' << c.y << ']' <<flush ; return f; }
+     
+  friend P2<R,RR> operator*(P2<R,RR> c,P2xP2<R,RR> cc)
+     {return P2<R,RR>(c.x*cc.x.x + c.y*cc.y.x, c.x*cc.x.y + c.y*cc.y.y);} 
+
+
+ public:
+  P2<R,RR> x,y; 
+  P2xP2 (): x(),y()  {}
+  P2xP2 (P2<R,RR> a,P2<R,RR> b): x(a),y(b) {}
+  P2xP2 (P2<R,RR> a,P2<R,RR> b,P2<R,RR> c ): x(b-a),y(c-a) {}
+  P2xP2 (R xx,R xy,R yx,R yy) :x(xx,xy),y(yx,yy) {}
+  P2<R,RR> operator*(const P2<R,RR> c) const {return P2<R,RR>(x.x*c.x + x.y*c.y, y.x*c.x + y.y*c.y);}
+  P2xP2<R,RR>  operator*(P2xP2<R,RR> c) const 
+    { return  P2xP2<R,RR>(x.x*c.x.x + x.y*c.y.x,
+			  x.x*c.x.y + x.y*c.y.y,
+			  y.x*c.x.x + y.y*c.y.x,
+			  y.x*c.x.y + y.y*c.y.y);}
+  RR det() const {return (RR) x.x* (RR) y.y - (RR) x.y * (RR) y.x;}
+  P2xP2<R,RR> inv()  const
+     { RR d = (*this).det(); 
+       return P2xP2<R,RR>((R)( y.y /d) ,(R)(-x.y/d),(R)( -y.x/d) ,(R)( x.x/d) );
+     };
+   P2xP2<R,RR> t() {return P2xP2<R,RR>(x.x,y.x,x.y,y.y);} //transposer 
+   P2<R,RR>tx() {return P2<R,RR>(x.x,y.x);} 
+   P2<R,RR>ty() {return P2<R,RR>(x.y,y.y);} 
+
+};  
+
+
+
+//template  <class R,class RR>  // transposer
+//inline P2xP2<R,RR> t(P2xP2<R,RR> m) 
+//   {return P2xP2<R,RR>(m.x.x,m.y.x,m.x.y,m.y.y);} 
+
+template  <class R,class RR>  
+inline RR Det(const P2<R,RR> x,const P2<R,RR> y) {
+  return (RR) x.x * (RR) y.y - (RR) x.y * (RR) y.x ;} 
+
+template  <class R,class RR>  
+inline RR Area2 (const P2<R,RR> a,const P2<R,RR> b,const P2<R,RR> c) {
+  return Det(b-a,c-a) ;} 
+
+template  <class R,class RR>  
+inline R Norme1 (const P2<R,RR> x) {
+  return (Abs(x.x)+Abs(x.y)) ;} 
+
+template  <class R,class RR>  
+inline R NormeInfini (const P2<R,RR> x) {
+  return Max(Abs(x.x),Abs(x.y)) ;} 
+
+template  <class R,class RR>  
+inline RR Norme2_2 (const P2<R,RR> x) {
+  return (RR)x.x*(RR)x.x + (RR)x.y*(RR)x.y ;} 
+
+template  <class R,class RR>  
+inline RR Norme2 (const P2<R,RR> x) {
+  return sqrt((RR)x.x*(RR)x.x + (RR)x.y*(RR)x.y) ;} 
+
+template  <class R,class RR>  
+inline P2<R,RR> Orthogonal (const P2<R,RR> x) {
+  return  P2<R,RR>(-x.y,x.x);} 
+
+template <class R,class RR>
+inline  ostream& operator <<(ostream& f, const P2<R,RR> & c)
+  { f << '[' << c.x << ',' << c.y <<']' <<flush ; return f; }
+
+   
+/*template  <class R,class RR>
+inline P2<R,RR> Min2(P2<R,RR> x,P2<R,RR> y) 
+   {return  P2<R,RR>(Min(x.x,y.x),Min(x.y,y.y) ;} 
+
+template  <class R,class RR>
+inline P2<R,RR> Max2(P2<R,RR> x,P2<R,RR> y) 
+   {return  P2<R,RR>(Max(x.x,y.x),Max(x.y,y.y) ;} 
+*/
+}
diff --git a/contrib/bamg/bamglib/SetOfE4.cpp b/contrib/bamg/bamglib/SetOfE4.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..c68b5ab26ba2e9208fc8d28a3127ac0e6cfdcd5f
--- /dev/null
+++ b/contrib/bamg/bamglib/SetOfE4.cpp
@@ -0,0 +1,84 @@
+// -*- Mode : c++ -*-
+//
+// SUMMARY  :      
+// USAGE    :        
+// ORG      : 
+// AUTHOR   : Frederic Hecht
+// E-MAIL   : hecht@ann.jussieu.fr
+//
+
+/*
+ 
+ This file is part of Freefem++
+ 
+ Freefem++ is free software; you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+ 
+ Freefem++  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 Lesser General Public License for more details.
+ 
+ You should have received a copy of the GNU Lesser General Public License
+ along with Freefem++; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+#include <iostream> 
+using namespace std;
+#include "meshtype.h"
+#include "SetOfE4.h"
+
+namespace bamg {
+
+ SetOfEdges4::SetOfEdges4(Int4 mmx,Int4 nnx)
+   {nx=nnx;
+    nbax=mmx;
+    NbOfEdges = 0;
+    tete= new Int4 [nx];
+    Int4 i=nx;
+    while (i--)
+      tete[i] = -1;// vide 
+    Edges =new Int4Edge[nbax];
+   }
+    
+ Int4 SetOfEdges4::find(Int4 ii,Int4 jj)
+{ 
+  if (tete == 0 ) {
+    cerr <<"SetOfEdges4::find \nplus de tete de liste\n";
+    MeshError(888);}
+  Int4 n = tete[ Abs( ii ) % nx ];
+  
+  while (n >= 0) 
+    if (ii == Edges[n].i && jj == Edges[n].j)
+      return n;
+    else n = Edges[n].next;
+  return -1; // n'existe pas
+}
+
+ Int4 SetOfEdges4::add(Int4 ii,Int4 jj)
+{
+  if (tete == 0 ) {
+    cerr << "SetOfEdges4::add\n plus de tete de liste \n" << endl;
+    MeshError(888);}
+  
+  Int4 h;
+  Int4 n = tete[ h = Abs( ii ) % nx ];
+  while (n >= 0) 
+   if (ii == Edges[n].i && jj == Edges[n].j)
+            return n;
+   else n = Edges[n].next;
+  if (nbax <=NbOfEdges ) {
+    cerr << " SetOfEdges4::add\noverflow de la pile "  << nbax << " " << NbOfEdges << endl;
+    MeshError(888);}
+  
+   Edges[NbOfEdges].i=ii;
+   Edges[NbOfEdges].j=jj;
+   Edges[NbOfEdges].next= tete[h];
+   tete[h] = NbOfEdges;
+   return NbOfEdges ++;
+}
+
+
+}  // end of namespace bamg 
diff --git a/contrib/bamg/bamglib/SetOfE4.h b/contrib/bamg/bamglib/SetOfE4.h
new file mode 100644
index 0000000000000000000000000000000000000000..5179ce9a911b4df270e1a88eda8dc6f0cbd0b80f
--- /dev/null
+++ b/contrib/bamg/bamglib/SetOfE4.h
@@ -0,0 +1,64 @@
+// -*- Mode : c++ -*-
+//
+// SUMMARY  :      
+// USAGE    :        
+// ORG      : 
+// AUTHOR   : Frederic Hecht
+// E-MAIL   : hecht@ann.jussieu.fr
+//
+
+/*
+ 
+ This file is part of Freefem++
+ 
+ Freefem++ is free software; you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+ 
+ Freefem++  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 Lesser General Public License for more details.
+ 
+ You should have received a copy of the GNU Lesser General Public License
+ along with Freefem++; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#ifndef _SetOfEdge4_h
+#define _SetOfEdge4_h
+
+namespace bamg {
+
+class SetOfEdges4 ;
+class Int4Edge{
+friend class SetOfEdges4;
+public:
+  Int4 i,j;
+  Int4 next; 
+};
+
+class SetOfEdges4 {
+  Int4 nx,nbax,NbOfEdges;
+  Int4 * tete; 
+  Int4Edge * Edges;
+
+public:
+  SetOfEdges4(Int4 ,Int4);// nb Edges mx , nb de sommet 
+  ~SetOfEdges4() {// cout << " delete SetofArete " << endl ;
+  delete [] tete; delete [] Edges;}
+   Int4 add (Int4 ii,Int4 jj);
+  Int4 addtrie (Int4 ii,Int4 jj) {return ii <=jj ? add (ii,jj)  : add (jj,ii) ;}
+  Int4  nb(){return NbOfEdges;}
+  Int4 find (Int4 ii,Int4 jj);
+  Int4 findtrie (Int4 ii,Int4 jj) {return ii <=jj ? find (ii,jj)  : find (jj,ii) ;}
+  // inline void close();
+  Int4 i(Int4 k){return Edges[k].i;}
+  Int4 j(Int4 k){return Edges[k].j;}
+  Int4 newarete(Int4 k){return NbOfEdges == k+1;}
+  Int4Edge & operator[](Int4 k){return  Edges[k];}
+};
+}
+
+#endif 
diff --git a/contrib/bamg/bamglib/error.hpp b/contrib/bamg/bamglib/error.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..a87240be5d99c4eab9460fa2b81c69963d7c0aff
--- /dev/null
+++ b/contrib/bamg/bamglib/error.hpp
@@ -0,0 +1,135 @@
+// -*- Mode : c++ -*-
+//
+// SUMMARY  :      
+// USAGE    :        
+// ORG      : 
+// AUTHOR   : Frederic Hecht
+// E-MAIL   : hecht@ann.jussieu.fr
+//
+
+/*
+ 
+ This file is part of Freefem++
+ 
+ Freefem++ is free software; you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+ 
+ Freefem++  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 Lesser General Public License for more details.
+ 
+ You should have received a copy of the GNU Lesser General Public License
+ along with Freefem++; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+#ifndef ERROR_H
+#define ERROR_H
+#include <cassert>
+#include <string>
+// #include "throwassert.hpp"
+#include <exception>
+
+extern int TheCurrentLine; 
+
+#if defined(__GNUC__) && __GNUC__+0 < 3
+#include <strstream.h>
+ typedef  istrstream istringstream   ;
+ typedef  ostrstream ostringstream   ;
+#define ENDS << '\0'
+#define OLDCPP 1 
+#else
+// car ostringstream n'est pas encore defin sous g++
+//  
+#include <sstream>
+#define ENDS 
+
+#endif
+
+  using std::exception;
+
+//extern long mpirank;
+
+class Error : public exception
+{ public:
+  enum CODE_ERROR { NONE, COMPILE_ERROR,EXEC_ERROR, MEM_ERROR,MESH_ERROR,ASSERT_ERROR,INTERNAL_ERROR, UNKNOWN };
+  
+  
+private: 
+  std::string  message;
+  const CODE_ERROR code;
+protected:
+  Error(CODE_ERROR c,const char * t1,const char * t2,const char * t3=0,
+	int n=0,const char * t4=0,const char * t5=0,const char * t6=0,
+	const char * t7=0,const char * t8=0,const char * t9=0)     
+    : message(),code(c)
+  {
+    using namespace std;
+    ostringstream mess;
+    if(t1)  mess << t1;
+    if(t2)  mess << t2;
+    if(t3)  mess << t3 << n ;
+    if(t4)  mess << t4;
+    if(t5)  mess << t5;
+    if(t6)  mess << t6;
+    if(t7)  mess << t7;
+    if(t8)  mess << t8;
+    if(t9)  mess << t9;
+    message = mess.str();
+    //    extern void ShowDebugStack();
+    //ShowDebugStack();
+    if (c!=NONE) cerr  << message << endl; // cerr << " at exec line  " << TheCurrentLine << endl; 
+    }
+public:
+  virtual int errcode() const {return code;} 
+  virtual const char *  what() const   throw () { return message.c_str(); } 
+  virtual  ~Error() throw () {}      
+};
+
+class ErrorCompile : public Error
+{
+ public:
+  ErrorCompile(const char * Text,int l,const char * t2="") : 
+    Error(COMPILE_ERROR,"Compile error : ",Text,"\n\tline number :",l,", ", t2) {}
+};
+
+class ErrorExec : public Error
+{  
+ public:
+  ErrorExec(const char * Text,int l) :
+    Error(UNKNOWN,"Exec error : ",Text, "\n   -- number :", l)  {}
+};
+
+class ErrorInternal : public Error
+{  
+ public:
+  ErrorInternal(const char * Text,int l,const char * t2="") :
+    Error(INTERNAL_ERROR,"Internal error : ",Text, "\n\tline  :",l,", in file ", t2)  {}
+};
+class ErrorAssert : public Error
+{  
+ public:
+  ErrorAssert(const char * Text,const char *file,const int line) :
+    Error(ASSERT_ERROR,"Assertion fail : (",Text, ")\n\tline :", line,", in file ",file)  {}
+};
+
+
+class ErrorMemory : public Error
+{ public:
+  ErrorMemory(const char * Text,int l=0) : 
+    Error(MEM_ERROR,"Memory Error : ",Text," number: ",l)  {}
+};
+
+class ErrorExit : public Error
+{
+  int codeexit;
+public:
+  ErrorExit(const char * ,int l) :
+    Error(NONE,"exit","(","",l,")"), codeexit(l)   {}
+    // the exit code fo freefem++ is given by l 
+  int errcode() const{return codeexit;}
+};
+
+#endif
diff --git a/contrib/bamg/bamglib/meshtype.h b/contrib/bamg/bamglib/meshtype.h
new file mode 100644
index 0000000000000000000000000000000000000000..4ab54460630a77565cce6f1244ae55caf4960ded
--- /dev/null
+++ b/contrib/bamg/bamglib/meshtype.h
@@ -0,0 +1,71 @@
+// -*- Mode : c++ -*-
+//
+// SUMMARY  :      
+// USAGE    :        
+// ORG      : 
+// AUTHOR   : Frederic Hecht
+// E-MAIL   : hecht@ann.jussieu.fr
+//
+
+/*
+ 
+ This file is part of Freefem++
+ 
+ Freefem++ is free software; you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+ 
+ Freefem++  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 Lesser General Public License for more details.
+ 
+ You should have received a copy of the GNU Lesser General Public License
+ along with Freefem++; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+#ifndef MESHTYPE_H
+#define MESHTYPE_H
+#include <limits.h>
+namespace bamg {
+template<class T> inline T Square (const T &a) { return a*a;} 
+template<class T> inline T Min (const T &a,const T &b){return a < b ? a : b;}
+template<class T> inline T Max (const T &a,const T & b){return a > b ? a : b;}
+template<class T> inline T Abs (const T &a){return a <0 ? -a : a;}
+template<class T> inline double Norme (const T &a){return sqrt(a*a);}
+template<class T> inline void Exchange (T& a,T& b) {T c=a;a=b;b=c;}
+// for pb on microsoft compiler 
+template<class T> inline T Max3 (const T &a,const T & b,const T & c){return Max(Max(a,b),c);}
+template<class T> inline T Min3 (const T &a,const T & b,const T & c){return Min(Min(a,b),c);}
+
+typedef float  Real4;
+typedef double Real8;
+typedef short  Int1;
+typedef short  Int2;
+typedef long   Int4;
+
+#if LONG_BIT > 63
+// for alpha and silicon 
+ typedef int  Icoor1;  
+ typedef long   Icoor2;
+ const Icoor1 MaxICoor = 1073741823; // 2^30-1
+ const  Icoor2 MaxICoor22 = Icoor2(2)*Icoor2(MaxICoor) * Icoor2(MaxICoor) ;
+
+#elif  defined(BAMG_LONG_LONG)
+ typedef long  Icoor1;
+ typedef long long   Icoor2;
+ const Icoor1 MaxICoor =   1073741823;// 2^30-1
+// not a const due to a bug in hp compiler
+#define  MaxICoor22 2305843004918726658LL
+//const  Icoor2 MaxICoor22 = Icoor2(2)*Icoor2(MaxICoor) * Icoor2(MaxICoor) ;
+#else
+ typedef int  Icoor1;
+ typedef double   Icoor2;
+ const Icoor1 MaxICoor = 8388608; // 2^23
+ const  Icoor2 MaxICoor22 = Icoor2(2)*Icoor2(MaxICoor) * Icoor2(MaxICoor) ;
+#endif
+ class Triangles;
+extern void MeshError(int Err,Triangles *Th=0) ;
+}
+#endif
diff --git a/contrib/bamg/error.hpp b/contrib/bamg/error.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..a87240be5d99c4eab9460fa2b81c69963d7c0aff
--- /dev/null
+++ b/contrib/bamg/error.hpp
@@ -0,0 +1,135 @@
+// -*- Mode : c++ -*-
+//
+// SUMMARY  :      
+// USAGE    :        
+// ORG      : 
+// AUTHOR   : Frederic Hecht
+// E-MAIL   : hecht@ann.jussieu.fr
+//
+
+/*
+ 
+ This file is part of Freefem++
+ 
+ Freefem++ is free software; you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+ 
+ Freefem++  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 Lesser General Public License for more details.
+ 
+ You should have received a copy of the GNU Lesser General Public License
+ along with Freefem++; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+#ifndef ERROR_H
+#define ERROR_H
+#include <cassert>
+#include <string>
+// #include "throwassert.hpp"
+#include <exception>
+
+extern int TheCurrentLine; 
+
+#if defined(__GNUC__) && __GNUC__+0 < 3
+#include <strstream.h>
+ typedef  istrstream istringstream   ;
+ typedef  ostrstream ostringstream   ;
+#define ENDS << '\0'
+#define OLDCPP 1 
+#else
+// car ostringstream n'est pas encore defin sous g++
+//  
+#include <sstream>
+#define ENDS 
+
+#endif
+
+  using std::exception;
+
+//extern long mpirank;
+
+class Error : public exception
+{ public:
+  enum CODE_ERROR { NONE, COMPILE_ERROR,EXEC_ERROR, MEM_ERROR,MESH_ERROR,ASSERT_ERROR,INTERNAL_ERROR, UNKNOWN };
+  
+  
+private: 
+  std::string  message;
+  const CODE_ERROR code;
+protected:
+  Error(CODE_ERROR c,const char * t1,const char * t2,const char * t3=0,
+	int n=0,const char * t4=0,const char * t5=0,const char * t6=0,
+	const char * t7=0,const char * t8=0,const char * t9=0)     
+    : message(),code(c)
+  {
+    using namespace std;
+    ostringstream mess;
+    if(t1)  mess << t1;
+    if(t2)  mess << t2;
+    if(t3)  mess << t3 << n ;
+    if(t4)  mess << t4;
+    if(t5)  mess << t5;
+    if(t6)  mess << t6;
+    if(t7)  mess << t7;
+    if(t8)  mess << t8;
+    if(t9)  mess << t9;
+    message = mess.str();
+    //    extern void ShowDebugStack();
+    //ShowDebugStack();
+    if (c!=NONE) cerr  << message << endl; // cerr << " at exec line  " << TheCurrentLine << endl; 
+    }
+public:
+  virtual int errcode() const {return code;} 
+  virtual const char *  what() const   throw () { return message.c_str(); } 
+  virtual  ~Error() throw () {}      
+};
+
+class ErrorCompile : public Error
+{
+ public:
+  ErrorCompile(const char * Text,int l,const char * t2="") : 
+    Error(COMPILE_ERROR,"Compile error : ",Text,"\n\tline number :",l,", ", t2) {}
+};
+
+class ErrorExec : public Error
+{  
+ public:
+  ErrorExec(const char * Text,int l) :
+    Error(UNKNOWN,"Exec error : ",Text, "\n   -- number :", l)  {}
+};
+
+class ErrorInternal : public Error
+{  
+ public:
+  ErrorInternal(const char * Text,int l,const char * t2="") :
+    Error(INTERNAL_ERROR,"Internal error : ",Text, "\n\tline  :",l,", in file ", t2)  {}
+};
+class ErrorAssert : public Error
+{  
+ public:
+  ErrorAssert(const char * Text,const char *file,const int line) :
+    Error(ASSERT_ERROR,"Assertion fail : (",Text, ")\n\tline :", line,", in file ",file)  {}
+};
+
+
+class ErrorMemory : public Error
+{ public:
+  ErrorMemory(const char * Text,int l=0) : 
+    Error(MEM_ERROR,"Memory Error : ",Text," number: ",l)  {}
+};
+
+class ErrorExit : public Error
+{
+  int codeexit;
+public:
+  ErrorExit(const char * ,int l) :
+    Error(NONE,"exit","(","",l,")"), codeexit(l)   {}
+    // the exit code fo freefem++ is given by l 
+  int errcode() const{return codeexit;}
+};
+
+#endif
diff --git a/contrib/bamg/main.cpp b/contrib/bamg/main.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..4b2c3fd2b564961cc44ad1c7e35c55d83e63d898
--- /dev/null
+++ b/contrib/bamg/main.cpp
@@ -0,0 +1,22 @@
+#include <iostream>
+using namespace std;
+#include "Mesh2.h"
+#include "RNM.hpp"
+#include "Mesh2d.hpp"
+#include <set>
+#include "bamg-gmsh.hpp"
+long verbosity=1;
+int main(int argc,const char ** argv)
+{
+  assert(argc>1);
+  Mesh2 Th(argv[1]);
+  KN<double> data(30);
+  data = -1e200;
+  int nv = Th.nv;
+  KN<double> m11(nv),m12(nv),m22(nv);
+  double h=0.01;
+  m11=1/(h*h);
+  m22=1/(h*h);
+  m12=0.;
+  
+}
diff --git a/contrib/bamg/ufunction.hpp b/contrib/bamg/ufunction.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..dd2e1193108603355249999ecde8ad8ef32a9d13
--- /dev/null
+++ b/contrib/bamg/ufunction.hpp
@@ -0,0 +1,9 @@
+
+// some usefull function
+template<class T> inline T Min (const T &a,const T &b){return a < b ? a : b;}
+template<class T> inline T Max (const T &a,const T & b){return a > b ? a : b;}
+template<class T> inline T Abs (const T &a){return a <0 ? -a : a;}
+template<class T> inline double Norme (const T &a){return sqrt(a*a);}
+template<class T> inline void Exchange (T& a,T& b) {T c=a;a=b;b=c;}
+template<class T> inline T Max (const T &a,const T & b,const T & c){return Max(Max(a,b),c);}
+template<class T> inline T Min (const T &a,const T & b,const T & c){return Min(Min(a,b),c);}