From 6ab4d46a8437be1e32eb675cde587b5e482fd8a7 Mon Sep 17 00:00:00 2001
From: Jean-Francois Remacle <jean-francois.remacle@uclouvain.be>
Date: Wed, 3 Nov 2010 16:24:20 +0000
Subject: [PATCH] added hessian based error estimation & adaptation better quad
 meshing

---
 Common/OctreeInternals.cpp         |   2 +-
 Fltk/statisticsWindow.cpp          |   2 -
 Geo/GModel.cpp                     |   1 -
 Geo/MElement.cpp                   |  12 +
 Geo/MElement.h                     |   1 +
 Geo/MElementOctree.cpp             |  28 ++-
 Geo/MElementOctree.h               |   1 +
 Geo/MQuadrangle.cpp                |  12 +
 Geo/OCCEdge.cpp                    |   2 +-
 Mesh/BDS.cpp                       |   6 +-
 Mesh/BDS.h                         |   2 +-
 Mesh/BackgroundMesh.cpp            |   5 +-
 Mesh/meshGFace.cpp                 |  28 ++-
 Mesh/meshGFaceOptimize.cpp         | 391 +++++++++++++++++++----------
 Mesh/meshGFaceOptimize.h           |  23 +-
 Mesh/meshGFaceQuadrilateralize.cpp |   3 +-
 Mesh/meshRefine.cpp                |   6 +-
 benchmarks/boolean/sphere.lua      |   4 +-
 18 files changed, 371 insertions(+), 158 deletions(-)

diff --git a/Common/OctreeInternals.cpp b/Common/OctreeInternals.cpp
index a12113f9a2..2c500d379a 100644
--- a/Common/OctreeInternals.cpp
+++ b/Common/OctreeInternals.cpp
@@ -417,6 +417,6 @@ void *searchAllElements(octantBucket *_buckets_head, double *_pt, globalInfo *_g
   if (flag1)
     return (void *)(_elements);
   
-  Msg::Warning("This point is not found in any element! It is not in the domain");
+  //  Msg::Warning("This point is not found in any element! It is not in the domain");
   return NULL;
 }
diff --git a/Fltk/statisticsWindow.cpp b/Fltk/statisticsWindow.cpp
index beeb11201c..5a431cc4e0 100644
--- a/Fltk/statisticsWindow.cpp
+++ b/Fltk/statisticsWindow.cpp
@@ -205,8 +205,6 @@ void statisticsWindow::compute(bool elementQuality)
   // meanAngle  = meanAngle / count;
   // printf("Angles = min=%g av=%g \n", minAngle, meanAngle);
   //hack emi
-
-  
   //Emi hack - MESH DEGREE VERTICES
   // std::vector<GEntity*> entities;
   // std::set<MEdge, Less_Edge> edges;
diff --git a/Geo/GModel.cpp b/Geo/GModel.cpp
index d63236b4ca..9697d63b11 100644
--- a/Geo/GModel.cpp
+++ b/Geo/GModel.cpp
@@ -2508,5 +2508,4 @@ void GModel::registerBindings(binding *b)
   cm->setDescription("Assigns partition tags to boundary elements. Should be called "
                      "only after the partitions have been assigned");
   cm->setArgNames("createGhostCells",NULL);
-
 }
diff --git a/Geo/MElement.cpp b/Geo/MElement.cpp
index d8416bafe5..1d36d466a9 100644
--- a/Geo/MElement.cpp
+++ b/Geo/MElement.cpp
@@ -1095,6 +1095,15 @@ const fullMatrix<double> &MElement::getGradShapeFunctionsAtNodes (int functionSp
   return mat;
 }
 
+void MElement::xyzTouvw(fullMatrix<double> *xu){
+  double _xyz[3] = {(*xu)(0,0),(*xu)(0,1),(*xu)(0,2)},_uvw[3] ;
+  xyz2uvw(_xyz,_uvw);
+  (*xu)(1,0) = _uvw[0];
+  (*xu)(1,1) = _uvw[1];
+  (*xu)(1,2) = _uvw[2];
+}
+
+
 #include "Bindings.h"
 
 void MElement::registerBindings(binding *b)
@@ -1125,4 +1134,7 @@ void MElement::registerBindings(binding *b)
   cm = cb->addMethod("getJacobianDeterminant", &MElement::getJacobianDeterminant);
   cm->setDescription("return the jacobian of the determinant of the transformation");
   cm->setArgNames("u","v","w",NULL);
+  cm = cb->addMethod("xyzTouvw", &MElement::xyzTouvw);
+  cm->setDescription("get uvw from xyz");
+  cm->setArgNames("xyzuvw",NULL);
 }
diff --git a/Geo/MElement.h b/Geo/MElement.h
index f758c8c166..5f7a974ac2 100644
--- a/Geo/MElement.h
+++ b/Geo/MElement.h
@@ -244,6 +244,7 @@ class MElement
 
   // invert the parametrisation
   virtual void xyz2uvw(double xyz[3], double uvw[3]);
+  void xyzTouvw(fullMatrix<double> *xu);
 
   // move point between parent and element parametric spaces
   virtual void movePointFromParentSpaceToElementSpace(double &u, double &v, double &w);
diff --git a/Geo/MElementOctree.cpp b/Geo/MElementOctree.cpp
index c74568b713..9e2d94aa50 100644
--- a/Geo/MElementOctree.cpp
+++ b/Geo/MElementOctree.cpp
@@ -55,7 +55,7 @@ static int MElementInEle(void *a, double *x)
   return e->isInside(uvw[0], uvw[1], uvw[2]) ? 1 : 0;
 }
 
-MElementOctree::MElementOctree(GModel *m)
+MElementOctree::MElementOctree(GModel *m) : _gm(m)
 {
   SBoundingBox3d bb = m->bounds();
   // make bounding box larger up to (absolute) geometrical tolerance
@@ -80,9 +80,11 @@ MElementOctree::MElementOctree(GModel *m)
 
 MElementOctree::MElementOctree(std::vector<MElement*> &v)
 {
+  _gm = 0;
   SBoundingBox3d bb;
   for (unsigned int i = 0; i < v.size(); i++){
     for(int j = 0; j < v[i]->getNumVertices(); j++){
+      if (!_gm)_gm = v[i]->getVertex(j)->onWhat()->model();
       bb += SPoint3(v[i]->getVertex(j)->x(),
                     v[i]->getVertex(j)->y(),
                     v[i]->getVertex(j)->z());
@@ -114,6 +116,30 @@ MElement *MElementOctree::find(double x, double y, double z, int dim)
 {
   double P[3] = {x, y, z};
   MElement *e = (MElement*)Octree_Search(P, _octree);
+  
+  if (!e){
+    double initialTol = 1.e-6;
+    double tol = initialTol;
+    while ( tol < .1){
+      tol *= 10;
+      MElement::setTolerance(tol);
+      std::vector<GEntity*> entities;
+      _gm->getEntities(entities);
+      for(unsigned int i = 0; i < entities.size(); i++){
+	for(unsigned int j = 0; j < entities[i]->getNumMeshElements(); j++){
+	  e = entities[i]->getMeshElement(j);
+	  if (dim == -1 ||  e->getDim() == dim){
+	    if (MElementInEle(e, P)){
+	      MElement::setTolerance(initialTol);
+	      return e;
+	    }	    
+	  }
+	}
+      }
+    }
+  }
+  
+
   if (dim == -1 || !e || e->getDim() == dim)
     return e;
   std::list<void*> l;
diff --git a/Geo/MElementOctree.h b/Geo/MElementOctree.h
index 112589611f..4b8511f52f 100644
--- a/Geo/MElementOctree.h
+++ b/Geo/MElementOctree.h
@@ -15,6 +15,7 @@ class MElement;
 class MElementOctree{
  private:
   Octree *_octree;
+  GModel *_gm;
  public:
   MElementOctree(GModel *);
   MElementOctree(std::vector<MElement*> &);
diff --git a/Geo/MQuadrangle.cpp b/Geo/MQuadrangle.cpp
index 0563ae6d29..2d74ebfc12 100644
--- a/Geo/MQuadrangle.cpp
+++ b/Geo/MQuadrangle.cpp
@@ -219,6 +219,18 @@ void MQuadrangle::getIntegrationPoints(int pOrder, int *npts, IntPt **pts)
 
 double  MQuadrangle::etaShapeMeasure()
 {
+  SVector3 v01 (_v[1]->x()-_v[0]->x(),_v[1]->y()-_v[0]->y(),_v[1]->z()-_v[0]->z());
+  SVector3 v12 (_v[2]->x()-_v[1]->x(),_v[2]->y()-_v[1]->y(),_v[2]->z()-_v[1]->z());
+  SVector3 v23 (_v[3]->x()-_v[2]->x(),_v[3]->y()-_v[2]->y(),_v[3]->z()-_v[2]->z());
+  SVector3 v30 (_v[0]->x()-_v[3]->x(),_v[0]->y()-_v[3]->y(),_v[0]->z()-_v[3]->z());
+
+  SVector3 a = crossprod(v01,v12);
+  SVector3 b = crossprod(v12,v23);
+  SVector3 c = crossprod(v23,v30);
+  SVector3 d = crossprod(v30,v01);
+
+  if (dot(a,b) < 0 || dot(a,c) < 0 || dot(a,d) < 0 )return 0.0;
+
   double a1 = 180 * angle3Vertices(_v[0], _v[1], _v[2]) / M_PI;
   double a2 = 180 * angle3Vertices(_v[1], _v[2], _v[3]) / M_PI;
   double a3 = 180 * angle3Vertices(_v[2], _v[3], _v[0]) / M_PI;
diff --git a/Geo/OCCEdge.cpp b/Geo/OCCEdge.cpp
index 15b14e8196..142413f49f 100644
--- a/Geo/OCCEdge.cpp
+++ b/Geo/OCCEdge.cpp
@@ -97,7 +97,7 @@ SPoint2 OCCEdge::reparamOnFace(const GFace *face, double epar, int dir) const
   const double dx = p1.x()-p2.x();
   const double dy = p1.y()-p2.y();
   const double dz = p1.z()-p2.z();
-  if(sqrt(dx * dx + dy * dy + dz * dz) > 1.e-4 * CTX::instance()->lc){
+  if(sqrt(dx * dx + dy * dy + dz * dz) > 1.e-2 * CTX::instance()->lc && 0){
     // return reparamOnFace(face, epar,-1);      
     Msg::Warning("Reparam on face partially failed for curve %d surface %d at point %g",
                  tag(), face->tag(), epar);
diff --git a/Mesh/BDS.cpp b/Mesh/BDS.cpp
index 1c98232a95..d25cb34423 100644
--- a/Mesh/BDS.cpp
+++ b/Mesh/BDS.cpp
@@ -263,10 +263,11 @@ BDS_Edge *BDS_Mesh::recover_edge_fast(BDS_Point *p1, BDS_Point *p2){
   return 0;
 }
 
-BDS_Edge *BDS_Mesh::recover_edge(int num1, int num2, std::set<EdgeToRecover> *e2r, 
+BDS_Edge *BDS_Mesh::recover_edge(int num1, int num2, bool &_fatal, std::set<EdgeToRecover> *e2r, 
                                  std::set<EdgeToRecover> *not_recovered)
 {
   BDS_Edge *e = find_edge(num1, num2);
+  _fatal = false;
 
   if(e) return e;
 
@@ -331,6 +332,7 @@ BDS_Edge *BDS_Mesh::recover_edge(int num1, int num2, std::set<EdgeToRecover> *e2
         outputScalarField(triangles, "debugr.pos", 0);
         Msg::Debug("edge %d %d cannot be recovered at all, look at debugp.pos "
                    "and debugr.pos", num1, num2);
+	_fatal = true;
         return 0;
       }
       return eee;
@@ -1170,7 +1172,7 @@ bool BDS_Mesh::smooth_point_centroid(BDS_Point *p, GFace *gf, bool test_quality)
   }
 
   /*    TEST    */
-  double R; SPoint3 c; bool isSphere = gf->isSphere(R,c);
+  bool isSphere = gf->geomType() == GEntity::Sphere;
   double XX=0,YY=0,ZZ=0;
 
   double U = 0;
diff --git a/Mesh/BDS.h b/Mesh/BDS.h
index 937a75d9ef..4542f69c1f 100644
--- a/Mesh/BDS.h
+++ b/Mesh/BDS.h
@@ -440,7 +440,7 @@ class BDS_Mesh
   void add_geom(int degree, int tag);
   BDS_GeomEntity *get_geom(int p1, int p2);
   // 2D operators
-  BDS_Edge *recover_edge(int p1, int p2, std::set<EdgeToRecover> *e2r=0,
+  BDS_Edge *recover_edge(int p1, int p2, bool &_fatal, std::set<EdgeToRecover> *e2r=0,
                          std::set<EdgeToRecover> *not_recovered=0);
   BDS_Edge *recover_edge_fast(BDS_Point *p1, BDS_Point *p2);
   bool swap_edge(BDS_Edge*, const BDS_SwapEdgeTest &theTest);
diff --git a/Mesh/BackgroundMesh.cpp b/Mesh/BackgroundMesh.cpp
index aeaf804e12..026f80a21f 100644
--- a/Mesh/BackgroundMesh.cpp
+++ b/Mesh/BackgroundMesh.cpp
@@ -250,9 +250,10 @@ double BGM_MeshSize(GEntity *ge, double U, double V,
 
   // lc from fields
   double l4 = MAX_LC;
-  FieldManager *fields = GModel::current()->getFields();
+  FieldManager *fields = ge->model()->getFields();
   if(fields->background_field > 0){
     Field *f = fields->get(fields->background_field);
+    //    printf("field %p %s %d %p\n",f,f->getName(),fields->size(), ge->model());
     if(f) l4 = (*f)(X, Y, Z, ge);
   }
 
@@ -294,7 +295,7 @@ SMetric3 BGM_MeshMetric(GEntity *ge,
 
   // lc from fields
   SMetric3 l4(1./(MAX_LC*MAX_LC));
-  FieldManager *fields = GModel::current()->getFields();
+  FieldManager *fields = ge->model()->getFields();
   if(fields->background_field > 0){
     Field *f = fields->get(fields->background_field);
     if(f){
diff --git a/Mesh/meshGFace.cpp b/Mesh/meshGFace.cpp
index a1737ba6fc..a4b0c830af 100644
--- a/Mesh/meshGFace.cpp
+++ b/Mesh/meshGFace.cpp
@@ -335,6 +335,8 @@ static bool recoverEdge(BDS_Mesh *m, GEdge *ge,
     g = m->get_geom(ge->tag(), 1);
   }
   
+  bool _fatallyFailed;
+
   for(unsigned int i = 0; i < ge->lines.size(); i++){
     MVertex *vstart = ge->lines[i]->getVertex(0);
     MVertex *vend = ge->lines[i]->getVertex(1);
@@ -346,14 +348,14 @@ static bool recoverEdge(BDS_Mesh *m, GEdge *ge,
       if(pass == 1) 
         e2r->insert(EdgeToRecover(pstart->iD, pend->iD, ge));
       else{
-        BDS_Edge *e = m->recover_edge(pstart->iD, pend->iD, e2r, notRecovered);
+        BDS_Edge *e = m->recover_edge(pstart->iD, pend->iD, _fatallyFailed, e2r, notRecovered);
         if(e) e->g = g;
-        //else {
-        //   Msg::Error("Unable to recover an edge %g %g && %g %g (%d/%d)",
-        //              vstart->x(), vstart->y(), vend->x(), vend->y(), i, 
-        //              ge->mesh_vertices.size());
-        //   return false;
-        // }
+        else {
+	  if (_fatallyFailed) Msg::Error("Unable to recover an edge %g %g && %g %g (%d/%d)",
+					 vstart->x(), vstart->y(), vend->x(), vend->y(), i, 
+					 ge->mesh_vertices.size());
+	  return !_fatallyFailed;
+	}
       }
     }
   }
@@ -575,7 +577,11 @@ static bool meshGenerator(GFace *gf, int RECUR_ITER,
     ite = edges.begin();
     while(ite != edges.end()){
       if(!(*ite)->isMeshDegenerated()){
-        recoverEdge(m, *ite, recoverMapInv, &edgesToRecover, &edgesNotRecovered, 2);
+        if (!recoverEdge(m, *ite, recoverMapInv, &edgesToRecover, &edgesNotRecovered, 2)){
+	  delete m;
+	  gf->meshStatistics.status = GFace::FAILED;
+	  return false;
+	}
       }
       ++ite;
     }
@@ -900,7 +906,7 @@ static bool meshGenerator(GFace *gf, int RECUR_ITER,
 
   if((CTX::instance()->mesh.recombineAll || gf->meshAttributes.recombine) && 
      !CTX::instance()->mesh.optimizeLloyd)
-    recombineIntoQuads(gf);
+    recombineIntoQuadsIterative(gf);
 
   computeElementShapes(gf, gf->meshStatistics.worst_element_shape,
                        gf->meshStatistics.average_element_shape,
@@ -1283,11 +1289,13 @@ static bool meshGeneratorPeriodic(GFace *gf, bool debug = true)
     outputScalarField(m->triangles, name, 1);
   }
 
+  bool _fatallyFailed;
+
   for(unsigned int i = 0; i < edgeLoops_BDS.size(); i++){
     std::vector<BDS_Point*> &edgeLoop_BDS = edgeLoops_BDS[i];
     for(unsigned int j = 0; j < edgeLoop_BDS.size(); j++){
       BDS_Edge * e = m->recover_edge
-        (edgeLoop_BDS[j]->iD, edgeLoop_BDS[(j + 1) % edgeLoop_BDS.size()]->iD);
+        (edgeLoop_BDS[j]->iD, edgeLoop_BDS[(j + 1) % edgeLoop_BDS.size()]->iD, _fatallyFailed);
       if(!e){
         Msg::Error("Impossible to recover the edge %d %d", edgeLoop_BDS[j]->iD,
                    edgeLoop_BDS[(j + 1) % edgeLoop_BDS.size()]->iD);
diff --git a/Mesh/meshGFaceOptimize.cpp b/Mesh/meshGFaceOptimize.cpp
index b6f5180171..f3be29529e 100644
--- a/Mesh/meshGFaceOptimize.cpp
+++ b/Mesh/meshGFaceOptimize.cpp
@@ -187,26 +187,6 @@ void transferDataStructure(GFace *gf, std::set<MTri3*, compareTri3Ptr> &AllTris,
   }
 }
 
-template <class T>
-void buildVertexToElement(std::vector<T*> &eles, v2t_cont &adj)
-{
-  for(unsigned int i = 0; i < eles.size(); i++){
-    T *t = eles[i];
-    for(int j = 0; j < t->getNumVertices(); j++){
-      MVertex *v = t->getVertex(j);
-      v2t_cont :: iterator it = adj.find(v);
-      if(it == adj.end()){
-        std::vector<MElement*> one;
-        one.push_back(t);
-        adj[v] = one;
-      }
-      else{
-        it->second.push_back(t);
-      }
-    }
-  }
-}
-
 void buildVertexToTriangle(std::vector<MTriangle*> &eles, v2t_cont &adj)
 {
   adj.clear();
@@ -569,7 +549,7 @@ static bool _isItAGoodIdeaToCollapseThatVertex (GFace *gf,
 
 
 static bool _isItAGoodIdeaToMoveThatVertex (GFace *gf,
-					    std::vector<MElement*> &e1,					 
+					    const std::vector<MElement*> &e1,					 
 					    MVertex *v1, 
 					    const SPoint2 &before, 
 					    const SPoint2 &after){
@@ -775,67 +755,65 @@ int removeDiamonds(GFace *gf){
   return nbRemove;
 }
 
-
+static void _relocateVertex (GFace *gf, 
+			     MVertex *ver, 
+			     const std::vector<MElement*> &lt){
+  double R; SPoint3 c; bool isSphere = gf->isSphere(R,c);
+  if( ver->onWhat()->dim() == 2){
+    double initu,initv;
+    ver->getParameter(0, initu);
+    ver->getParameter(1, initv);
+    double cu = 0, cv = 0;
+    double XX=0,YY=0,ZZ=0;
+    double pu[4], pv[4];
+    double fact  = 0.0;
+    for(unsigned int i = 0; i < lt.size(); i++){
+      parametricCoordinates(lt[i], gf, pu, pv, ver);
+      cu += (pu[0] + pu[1] + pu[2]);
+      cv += (pv[0] + pv[1] + pv[2]);
+      XX += lt[i]->getVertex(0)->x()+lt[i]->getVertex(1)->x()+lt[i]->getVertex(2)->x();
+      YY += lt[i]->getVertex(0)->y()+lt[i]->getVertex(1)->y()+lt[i]->getVertex(2)->y();
+      ZZ += lt[i]->getVertex(0)->z()+lt[i]->getVertex(1)->z()+lt[i]->getVertex(2)->z();
+      if(lt[i]->getNumVertices() == 4){
+	cu += pu[3];
+	cv += pv[3];
+	XX += lt[i]->getVertex(3)->x();
+	YY += lt[i]->getVertex(3)->y();
+	ZZ += lt[i]->getVertex(3)->z();
+      }         
+      fact += lt[i]->getNumVertices();
+    }
+    if(fact != 0.0){
+      SPoint2 before(initu,initv);
+      SPoint2 after(cu / fact,cv / fact);
+      if (isSphere){
+	GPoint gp = gf->closestPoint(SPoint3(XX/fact, YY/fact, ZZ/fact), after);
+	after = SPoint2(gp.u(),gp.v());
+      }
+      bool success = _isItAGoodIdeaToMoveThatVertex (gf,  lt, ver,before,after);
+      if (success){
+	ver->setParameter(0, after.x());
+	ver->setParameter(1, after.y());
+	GPoint pt = gf->point(after);
+	if(pt.succeeded()){
+	  ver->x() = pt.x();
+	  ver->y() = pt.y();
+	  ver->z() = pt.z();
+	}
+      }
+    }
+  }
+}
+  
 void laplaceSmoothing(GFace *gf)
 {
   v2t_cont adj;
   buildVertexToElement(gf->triangles, adj);
   buildVertexToElement(gf->quadrangles, adj);
-
-  /*    TEST    */
-  double R; SPoint3 c; bool isSphere = gf->isSphere(R,c);
-
   for(int i = 0; i < 5; i++){
     v2t_cont :: iterator it = adj.begin();
     while (it != adj.end()){
-      MVertex *ver= it->first;
-      GEntity *ge = ver->onWhat();
-      // this vertex in internal to the face
-      if(ge->dim() == 2){
-        double initu,initv;
-        ver->getParameter(0, initu);
-        ver->getParameter(1, initv);
-        const std::vector<MElement*> &lt = it->second;
-        double cu = 0, cv = 0;
-	double XX=0,YY=0,ZZ=0;
-        double pu[4], pv[4];
-        double fact  = 0.0;
-        for(unsigned int i = 0; i < lt.size(); i++){
-          parametricCoordinates(lt[i], gf, pu, pv, ver);
-          cu += (pu[0] + pu[1] + pu[2]);
-          cv += (pv[0] + pv[1] + pv[2]);
-	  XX += lt[i]->getVertex(0)->x()+lt[i]->getVertex(1)->x()+lt[i]->getVertex(2)->x();
-	  YY += lt[i]->getVertex(0)->y()+lt[i]->getVertex(1)->y()+lt[i]->getVertex(2)->y();
-	  ZZ += lt[i]->getVertex(0)->z()+lt[i]->getVertex(1)->z()+lt[i]->getVertex(2)->z();
-          if(lt[i]->getNumVertices() == 4){
-            cu += pu[3];
-            cv += pv[3];
-	    XX += lt[i]->getVertex(3)->x();
-	    YY += lt[i]->getVertex(3)->y();
-	    ZZ += lt[i]->getVertex(3)->z();
-          }         
-          fact += lt[i]->getNumVertices();
-        }
-        if(fact != 0.0){
-	  SPoint2 before(initu,initv);
-	  SPoint2 after(cu / fact,cv / fact);
-	  if (isSphere){
-	    GPoint gp = gf->closestPoint(SPoint3(XX/fact, YY/fact, ZZ/fact), after);
-	    after = SPoint2(gp.u(),gp.v());
-	  }
-	  bool success = _isItAGoodIdeaToMoveThatVertex (gf,  it->second, ver,before,after);
-	  if (success){
-	    ver->setParameter(0, after.x());
-	    ver->setParameter(1, after.y());
-	    GPoint pt = gf->point(after);
-	    if(pt.succeeded()){
-	      ver->x() = pt.x();
-	      ver->y() = pt.y();
-	      ver->z() = pt.z();
-	    }
-	  }
-        }
-      }
+      _relocateVertex(gf,it->first,it->second);
       ++it;
     }  
   }
@@ -843,16 +821,11 @@ void laplaceSmoothing(GFace *gf)
 
 
 int  _edgeSwapQuadsForBetterQuality ( GFace *gf ) {
-  return 0;
-
-  v2t_cont adj_v;
-  buildVertexToElement(gf->quadrangles,adj_v);
 
   e2t_cont adj;
   //  buildEdgeToElement(gf->triangles, adj);
   buildEdgeToElement(gf->quadrangles, adj);
   
-  std::set<MElement*>touched;
   std::vector<MQuadrangle*>created;
   std::set<MElement*>deleted;
 
@@ -866,8 +839,12 @@ int  _edgeSwapQuadsForBetterQuality ( GFace *gf ) {
       MVertex *v2 = it->first.getVertex(1);
       MElement *e1 = it->second.first;
       MElement *e2 = it->second.second;
-      if (deleted.find(e1) == deleted.end() ||
-	  deleted.find(e2) == deleted.end()){
+
+      double worst_quality_old = std::min(e1->etaShapeMeasure(),e2->etaShapeMeasure());
+
+      if (worst_quality_old < .1 && ( 
+	  deleted.find(e1) == deleted.end() ||
+	  deleted.find(e2) == deleted.end())){
 	MVertex *v12,*v11,*v22,*v21;
 	for (int i=0;i<4;i++){
 	  MEdge ed = e1->getEdge(i);
@@ -881,38 +858,41 @@ int  _edgeSwapQuadsForBetterQuality ( GFace *gf ) {
 	  if (ed.getVertex(0) == v2 && ed.getVertex(1) != v1)v22 = ed.getVertex(1);
 	  if (ed.getVertex(1) == v2 && ed.getVertex(0) != v1)v22 = ed.getVertex(0);
 	}	
-	MQuadrangle *q1=0,*q2=0;
-	v2t_cont :: iterator it2 = adj_v.find(v2);
-	v2t_cont :: iterator it1 = adj_v.find(v1);
-	v2t_cont :: iterator it22 = adj_v.find(v22);
-	v2t_cont :: iterator it12 = adj_v.find(v12);
-	v2t_cont :: iterator it21 = adj_v.find(v21);
-	v2t_cont :: iterator it11 = adj_v.find(v11);
-	/*
-	int connectivity_default_config_1 = 
-	  abs(it1->size() - 4) + 
-	  abs(it2->size() - 4) + 
-	  abs(it2->size() - 4) + 
-	  abs(it2->size() - 4) ; 
-	*/
-	if (it2->second.size() >= 5 && it1->second.size() >= 5){	  
-	  if (it22->second.size() <= 3 && it11->second.size() <= 3) {
-	    q1 = new MQuadrangle (v11,v22,v2,v12);
-	    q2 = new MQuadrangle (v22,v11,v1,v21);
-	  }
-	  else if (it21->second.size() <= 3 && it12->second.size() <= 3) {
-	    q1 = new MQuadrangle (v11,v12,v21,v1);
-	    q2 = new MQuadrangle (v21,v12,v2,v22);
-	  }
+
+	MQuadrangle *q1A = new MQuadrangle (v11,v22,v2,v12);
+	MQuadrangle *q2A = new MQuadrangle (v22,v11,v1,v21);
+	MQuadrangle *q1B = new MQuadrangle (v11,v12,v21,v1);
+	MQuadrangle *q2B = new MQuadrangle (v21,v12,v2,v22);
+	double worst_quality_A = std::min(q1A->etaShapeMeasure(),q2A->etaShapeMeasure());
+	double worst_quality_B = std::min(q1B->etaShapeMeasure(),q2B->etaShapeMeasure());
+	//	printf("worst_quality_old = %g worst_quality_A = %g worst_quality_B = %g\n",worst_quality_old,worst_quality_A,worst_quality_B);
+
+	if (0.8*worst_quality_A > worst_quality_old && 0.8*worst_quality_A > worst_quality_B){
+	  deleted.insert(e1);
+	  deleted.insert(e2);
+	  created.push_back(q1A);
+	  created.push_back(q2A);
+	  delete q1B;
+	  delete q2B;
+	  //	  printf("edge swap performed\n");
+	  COUNT++;
 	}
-	if (q1 && q2){
+	else if (0.8*worst_quality_B > worst_quality_old && 0.8*worst_quality_B > worst_quality_A){
 	  deleted.insert(e1);
 	  deleted.insert(e2);
-	  created.push_back(q1);
-	  created.push_back(q2);
-	  printf("edge swap performed\n");
+	  created.push_back(q1B);
+	  created.push_back(q2B);
+	  delete q1A;
+	  delete q2A;
+	  //	  printf("edge swap performed\n");
 	  COUNT++;
 	}
+	else {
+	  delete q1A;
+	  delete q2A;
+	  delete q1B;
+	  delete q2B;
+	}
       }
     }
     if (COUNT)break;
@@ -927,10 +907,116 @@ int  _edgeSwapQuadsForBetterQuality ( GFace *gf ) {
     }    
   } 
   gf->quadrangles = created;
-  Msg::Debug("%i swap quads performed",COUNT);
   return COUNT;
 }
 
+static int  edgeSwapQuadsForBetterQuality ( GFace *gf ) {
+  return 0;
+  int COUNT = 0;
+  while(1){
+    int k = _edgeSwapQuadsForBetterQuality (gf);
+    COUNT += k;
+    if (!k || COUNT > 10)break;
+  }
+  Msg::Debug("%i swap quads performed",COUNT);
+}
+
+
+
+int postProcessExtraEdges (GFace *gf, std::vector<std::pair<MElement*,MElement*> > &toProcess){
+
+  /*
+  v2t_cont adj;
+  buildVertexToElement(gf->triangles, adj);
+  buildVertexToElement(gf->quadrangles, adj);
+
+  std::set<MElement*>deleted;
+
+  for (int i=0; i<toProcess.size() ; i++){
+    MElement *t1 = toProcess[i].first;
+    MElement *t2 = toProcess[i].second;
+    MVertex *common = 0;
+    for (int j=0;j<3;j++){
+      if (t1->getVertex(j) == t2->getVertex(0) ||
+	  t1->getVertex(j) == t2->getVertex(1) ||
+	  t1->getVertex(j) == t2->getVertex(2) ){
+	common = t1->getVertex(j);
+	break;
+      }
+    }
+    if (common){
+      
+      deleted.insert(t1);
+      deleted.insert(t2);
+      v2t_cont :: iterator it = adj.find(common);
+      if(it != adj.end()){
+	SPoint2 p;
+	bool success = reparamMeshVertexOnFace(it->first,gf, p);
+	MFaceVertex *newVertex = new MVertex (it->first->x(),
+					      it->first->y(),
+					      it->first->z(),
+					      gf,
+					      p.x(),
+					      p.y());
+	int start1,start2;
+	int orientation1, orientation2;
+	for (int k=0;k<3;k++){
+	  if (t1->getVertex(k) == it->first)start1 = k;
+	  if (t2->getVertex(k) == it->first)start2 = k;
+	}
+	MQuadrangle *q1;
+	if (orientation1)
+	  q1 = new MQuadrangle(newVertex,
+			       t1->getVertex(start1),
+			       t1->getVertex((start1+1)%3),
+			       t1->getVertex((start1+2)%3));
+	else
+	  q1 = new MQuadrangle(newVertex,
+			       t1->getVertex((start1+2)%3),
+			       t1->getVertex((start1+1)%3),
+			       t1->getVertex(start1));
+
+	MQuadrangle *q2;
+	if (orientation2)
+	  q2 = new MQuadrangle(newVertex,
+			       t2->getVertex(start2),
+			       t2->getVertex((start2+1)%3),
+			       t2->getVertex((start2+2)%3));
+	else
+	  q2 = new MQuadrangle(newVertex,
+			       t2->getVertex((start2+2)%3),
+			       t2->getVertex((start2+1)%3),
+			       t2->getVertex(start2));
+
+	
+	MQuadrangle *q2 = new MQuadrangle();
+	std::vector<MElement*> newAdj;
+	newAdj.push_back(q1);
+	newAdj.push_back(q2);
+	for (int k=0;k<it->second.size();k++){
+	  if (it->second[k]->getNumVertices() == 4)
+	    newAdj.push_back(it->second[k]);
+	}
+	gf->quadrangles.insert(q1);
+	gf->quadrangles.insert(q2);	
+	_relocateVertex(gf,newVertex,newAdj);
+      }
+    }
+  }
+  
+  std::vector<MTriangle*>remained;
+  for(unsigned int i = 0; i < gf->triangles.size(); i++){
+    if(deleted.find(gf->triangles[i]) == deleted.end()){
+      remained.push_back(gf->triangles[i]);
+    }
+    else {
+      delete gf->triangles[i];
+    }    
+  } 
+  gf->triangles = remained;
+  */
+}
+
 bool edgeSwap(std::set<swapquad> &configs, MTri3 *t1, GFace *gf, int iLocalEdge,
               std::vector<MTri3*> &newTris, const swapCriterion &cr,               
               const std::vector<double> &Us, const std::vector<double> &Vs,
@@ -1387,7 +1473,7 @@ static int _recombineIntoQuads(GFace *gf, int recur_level, bool cubicGraph = 1)
 	double x = .5*(pairs[i].n1->x()+pairs[i].n2->x());
 	double y = .5*(pairs[i].n1->y()+pairs[i].n2->y());
 	double opti = atan2(y,x);
-	angle -= opti;
+	//angle -= opti;
 	while (angle < 0 || angle > M_PI/2){
 	  if (angle < 0) angle += M_PI/2;
 	  if (angle > M_PI/2) angle -= M_PI/2;
@@ -1483,9 +1569,12 @@ static int _recombineIntoQuads(GFace *gf, int recur_level, bool cubicGraph = 1)
 	//	FILE *f = fopen (MATCHFILE,"r");
 	//	int nn,ne;
 	//	fscanf(f,"%d %d",&nn,&ne);
+	std::vector<std::pair<MElement*,MElement*> > toProcess;
 	for (int k=0;k<elist[0];k++){
 	  int i1 = elist[1+3*k],i2 = elist[1+3*k+1],an=elist[1+3*k+2];	  
-	  if (an == 100000){
+	  // FIXME !!
+	  if (an == 100000){// || an == 1000){
+	    toProcess.push_back(std::make_pair(n2t[i1],n2t[i2]));
 	    Msg::Debug("Forbidden quad found in blossom quadrangulation, optimization will be required");
 	  }
 	  else{
@@ -1579,41 +1668,49 @@ static int _recombineIntoQuads(GFace *gf, int recur_level, bool cubicGraph = 1)
   return success;
 }
 
-void recombineIntoQuads(GFace *gf)
+void recombineIntoQuads(GFace *gf, 
+			bool topologicalOpti,
+			bool nodeRepositioning)
 {
 
   double t1 = Cpu();
 
   //gf->model()->writeMSH("before.msh");
-  removeFourTrianglesNodes(gf, false);
+  if (topologicalOpti)removeFourTrianglesNodes(gf, false);
   int success = _recombineIntoQuads(gf,0);
   //gf->model()->writeMSH("raw.msh");
-  for(int i = 0; i < CTX::instance()->mesh.nbSmoothing; i++) 
-    laplaceSmoothing(gf);
+  if (nodeRepositioning)  
+    for(int i = 0; i < CTX::instance()->mesh.nbSmoothing; i++) 
+      laplaceSmoothing(gf);
 
-  //blossom-quad algo
+    //blossom-quad algo
   if(success && CTX::instance()->mesh.algoRecombine == 1){    
-    //gf->model()->writeMSH("smoothed.msh");
-    int COUNT = 0;
-    //char NAME[256];
-    while(1){
-      int x = removeTwoQuadsNodes(gf);
-      //if(x){ sprintf(NAME,"iter%dTQ.msh",COUNT++); gf->model()->writeMSH(NAME);}
-      int y= removeDiamonds(gf);
-      //if(y){ sprintf(NAME,"iter%dD.msh",COUNT++); gf->model()->writeMSH(NAME); }
-      int  z = _edgeSwapQuadsForBetterQuality ( gf );
+    if (topologicalOpti){
+      //gf->model()->writeMSH("smoothed.msh");
+      int COUNT = 0;
+      //char NAME[256];
+      while(1){
+	int x = removeTwoQuadsNodes(gf);
+	//if(x){ sprintf(NAME,"iter%dTQ.msh",COUNT++); gf->model()->writeMSH(NAME);}
+	int y= removeDiamonds(gf);
+	//if(y){ sprintf(NAME,"iter%dD.msh",COUNT++); gf->model()->writeMSH(NAME); }
+	laplaceSmoothing(gf);
+	int  z = 0 ;//edgeSwapQuadsForBetterQuality ( gf );
+	//if(z){ sprintf(NAME,"iter%dS.msh",COUNT++); gf->model()->writeMSH(NAME); }
+	if (!(x+y+z))break;
+      }
+      edgeSwapQuadsForBetterQuality ( gf );
       //if(z){ sprintf(NAME,"iter%dS.msh",COUNT++); gf->model()->writeMSH(NAME); }
-      if (!(x+y+z))break;
-    }
-    for(int i = 0; i < CTX::instance()->mesh.nbSmoothing; i++){ 
-      laplaceSmoothing(gf);
+      for(int i = 0; i < CTX::instance()->mesh.nbSmoothing; i++){ 
+	laplaceSmoothing(gf);
+      }
     }
     double t2 = Cpu();
     Msg::Info("Blossom recombination algorithm completed (%g s)", t2 - t1);
     return;
   }
 
-  //simple recombination algo
+    //simple recombination algo
   _recombineIntoQuads(gf,0);
   for(int i = 0; i < CTX::instance()->mesh.nbSmoothing; i++) 
     laplaceSmoothing(gf);
@@ -1626,3 +1723,37 @@ void recombineIntoQuads(GFace *gf)
   Msg::Info("Simple recombination algorithm completed (%g s)", t2 - t1);
 
 }
+
+void quadsToTriangles(GFace *gf){
+  for (int i=0;i<gf->quadrangles.size();i++){
+    MQuadrangle *q = gf->quadrangles[i];
+    MTriangle *t1 = new MTriangle (q->getVertex(0),q->getVertex(1),q->getVertex(2));
+    MTriangle *t2 = new MTriangle (q->getVertex(2),q->getVertex(3),q->getVertex(0));
+    gf->triangles.push_back(t1);
+    gf->triangles.push_back(t2);
+    delete q;
+  }
+  gf->quadrangles.clear();
+}    
+
+void recombineIntoQuadsIterative(GFace *gf){
+  
+  recombineIntoQuads(gf);
+  //  return;
+  int COUNT = 0;
+  while (1){
+    quadsToTriangles(gf);    
+    {char NAME[245];sprintf(NAME,"iterT%d.msh",COUNT); gf->model()->writeMSH(NAME);}
+    std::set<MTri3*,compareTri3Ptr> AllTris;
+    std::vector<double> vSizes, vSizesBGM, Us, Vs;
+    std::vector<SMetric3> vMetricsBGM;
+    //    buildMeshGenerationDataStructures
+    //      (gf, AllTris, vSizes, vSizesBGM, vMetricsBGM, Us, Vs);    
+    //    int nbSwaps = edgeSwapPass(gf, AllTris, SWCR_DEL, Us, Vs, vSizes, vSizesBGM);
+    //    transferDataStructure(gf, AllTris, Us, Vs); 
+    {char NAME[245];sprintf(NAME,"iterTD%d.msh",COUNT); gf->model()->writeMSH(NAME);}
+    recombineIntoQuads(gf,false,true);       
+    {char NAME[245];sprintf(NAME,"iter%d.msh",COUNT++); gf->model()->writeMSH(NAME);}
+    if (COUNT == 5)break;
+  }
+}
diff --git a/Mesh/meshGFaceOptimize.h b/Mesh/meshGFaceOptimize.h
index bda526530a..327d1d49ec 100644
--- a/Mesh/meshGFaceOptimize.h
+++ b/Mesh/meshGFaceOptimize.h
@@ -30,7 +30,23 @@ class edge_angle {
 typedef std::map<MVertex*, std::vector<MElement*> > v2t_cont;
 typedef std::map<MEdge, std::pair<MElement*, MElement*>, Less_Edge> e2t_cont;
 
-template <class T> void buildVertexToElement(std::vector<T*> &eles, v2t_cont &adj);
+template <class T> void buildVertexToElement(std::vector<T*> &eles, v2t_cont &adj){
+  for(unsigned int i = 0; i < eles.size(); i++){
+    T *t = eles[i];
+    for(int j = 0; j < t->getNumVertices(); j++){
+      MVertex *v = t->getVertex(j);
+      v2t_cont :: iterator it = adj.find(v);
+      if(it == adj.end()){
+        std::vector<MElement*> one;
+        one.push_back(t);
+        adj[v] = one;
+      }
+      else{
+        it->second.push_back(t);
+      }
+    }
+  }
+}
 template <class T> void buildEdgeToElement(std::vector<T*> &eles, e2t_cont &adj);
 
 void buildVertexToTriangle(std::vector<MTriangle*> &, v2t_cont &adj);
@@ -73,7 +89,10 @@ void buildMeshGenerationDataStructures(GFace *gf,
                                        std::vector<double> &Vs);
 void transferDataStructure(GFace *gf, std::set<MTri3*, compareTri3Ptr> &AllTris,
                            std::vector<double> &Us, std::vector<double> &Vs);
-void recombineIntoQuads(GFace *gf);
+void recombineIntoQuads(GFace *gf, 
+			bool topologicalOpti   = true, 
+			bool nodeRepositioning = true);
+void recombineIntoQuadsIterative(GFace *gf);
 
 struct swapquad{
   int v[4];
diff --git a/Mesh/meshGFaceQuadrilateralize.cpp b/Mesh/meshGFaceQuadrilateralize.cpp
index 27865202e7..ce2bd31e7f 100644
--- a/Mesh/meshGFaceQuadrilateralize.cpp
+++ b/Mesh/meshGFaceQuadrilateralize.cpp
@@ -292,7 +292,8 @@ bool edgeFront::formQuad(BDS_Edge *e, BDS_Edge *left, BDS_Edge *right)
     //    printf("recover\n");
     //    top = m->recover_edge_fast(pleft,pright);
     //    if(!top)
-    top = m->recover_edge(pleft->iD, pright->iD);
+    bool _fatallyFailed;
+    top = m->recover_edge(pleft->iD, pright->iD,_fatallyFailed);
     //    printf("recover done %p\n",top);
     if(!top) return false;
   }
diff --git a/Mesh/meshRefine.cpp b/Mesh/meshRefine.cpp
index 496834387a..4cefa59b8e 100644
--- a/Mesh/meshRefine.cpp
+++ b/Mesh/meshRefine.cpp
@@ -377,8 +377,10 @@ void RefineMesh(GModel *m, bool linear, bool splitIntoQuads, bool splitIntoHexas
   // mesh
   for(GModel::eiter it = m->firstEdge(); it != m->lastEdge(); ++it)
     Subdivide(*it);
-  for(GModel::fiter it = m->firstFace(); it != m->lastFace(); ++it)
-    Subdivide(*it, splitIntoQuads, splitIntoHexas, faceVertices);
+  for(GModel::fiter it = m->firstFace(); it != m->lastFace(); ++it){
+    bool splitIntoQuadsForThisFace = true;
+    Subdivide(*it, splitIntoQuadsForThisFace, splitIntoHexas, faceVertices);
+  }
   for(GModel::riter it = m->firstRegion(); it != m->lastRegion(); ++it)
     Subdivide(*it, splitIntoHexas, faceVertices);
 
diff --git a/benchmarks/boolean/sphere.lua b/benchmarks/boolean/sphere.lua
index 78ace91695..6477c57e48 100644
--- a/benchmarks/boolean/sphere.lua
+++ b/benchmarks/boolean/sphere.lua
@@ -1,6 +1,6 @@
 options = gmshOptions()
 options:initOptions()
-options:numberSet('Mesh', 0, 'CharacteristicLengthFactor', 0.9grep -IIr)
+options:numberSet('Mesh', 0, 'CharacteristicLengthFactor', 0.9);
 
 R = 1.0;
 myModel = GModel();
@@ -8,4 +8,4 @@ myModel:addSphere(0,0,0,R);
 
 myModel:setAsCurrent();
 
-myModel:mesh(2);
+--myModel:mesh(2);
-- 
GitLab