diff --git a/Mesh/meshGFaceRecombine.cpp b/Mesh/meshGFaceRecombine.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..53abddba3d31f5e740b3fce7cc8a61733c14633b
--- /dev/null
+++ b/Mesh/meshGFaceRecombine.cpp
@@ -0,0 +1,863 @@
+// Gmsh - Copyright (C) 1997-2011 C. Geuzaine, J.-F. Remacle
+//
+// See the LICENSE.txt file for license information. Please report all
+// bugs and problems to <gmsh@geuz.org>.
+//
+// Contributor(s):
+//   Amaury Johnen (a.johnen@ulg.ac.be)
+//
+
+// TODO :
+//   - recombine w. take care of parity, update of quality...
+
+#include "meshGFaceRecombine.h"
+#include "MElement.h"
+#include "MTriangle.h"
+
+#define EDGE_BASE 2 
+#define EDGE_QUAD 1
+
+Recombine2D *Recombine2D::_current = NULL;
+bool Recombine2D::bo = 0;
+double **Rec2DVertex::_qualVSnum = NULL;
+double **Rec2DVertex::_gains = NULL;
+
+/**  Recombine2D  **/
+/*******************/
+Recombine2D::Recombine2D(GFace *gf) : _gf(gf)
+{
+  if (Recombine2D::_current != NULL) {
+    Msg::Info("An instance of recombination is already in execution");
+    return;
+  }
+  Recombine2D::_current = this;
+  _numChange = 0;
+  backgroundMesh::set(gf);
+  _bgm = backgroundMesh::current();
+  Rec2DVertex::initStaticTable();
+  _numEdge = _numVert = 0;
+  _valEdge = _valVert = .0;
+  
+  // Be able to compute geometrical angle at corners
+  std::map<MVertex*, std::set<GEdge*> > mapCornerVert;
+  {
+    std::list<GEdge*> listge = gf->edges();
+    std::list<GEdge*>::iterator itge = listge.begin();
+    for (; itge != listge.end(); ++itge) {
+      mapCornerVert[(*itge)->getBeginVertex()->getMeshElement(0)->getVertex(0)]
+        .insert(*itge);
+      mapCornerVert[(*itge)->getEndVertex()->getMeshElement(0)->getVertex(0)]
+        .insert(*itge);
+    }
+  }
+  
+  // Find all Vertices and edges
+  std::map<MVertex*, std::list<MTriangle*> > mapVert;
+  std::map<MEdge, std::list<MTriangle*>, Less_Edge> mapEdge;
+  for (unsigned int i = 0; i < gf->triangles.size(); ++i) {
+    MTriangle *t = gf->triangles[i];
+    for (int j = 0; j < 3; ++j) {
+      mapVert[t->getVertex(j)].push_back(t);
+      mapEdge[t->getEdge(j)].push_back(t);
+    }
+  }
+  
+  // Create the 'Rec2DVertex' and store iterator to vertices which have degree 4
+  std::list<std::map<MVertex*, std::list<MTriangle*> >::iterator> fourTri;
+  {
+    mapofVertices::iterator itV2N = _vertices.begin();
+    std::map<MVertex*, std::list<MTriangle*> >::iterator itvert = mapVert.begin();
+    for (; itvert != mapVert.end(); ++itvert) {
+      MVertex *v = itvert->first;
+      int onWhat = 1;
+      if (mapCornerVert.find(v) != mapCornerVert.end())
+        onWhat = -1;
+      Rec2DVertex *rv = new Rec2DVertex(v, itvert->second, onWhat, mapCornerVert);
+      itV2N = _vertices.insert(itV2N, std::make_pair(v,rv));
+      ++_numVert;
+      if (itvert->second.size() == 4)
+        fourTri.push_back(itvert);
+    }
+  }
+  
+  // Create the 'Rec2DEdge' and store boundary edges
+  std::map<MVertex*, std::list<MEdge> > boundV2E;
+  {
+    mapofEdges::iterator itE2E = _edges.begin();
+    std::map<MEdge, std::list<MTriangle*> >::iterator itedge = mapEdge.begin();
+    for (; itedge != mapEdge.end(); ++itedge) {
+      MEdge e = itedge->first;
+      Rec2DEdge *re = new Rec2DEdge(e, _vertices, itedge->second);
+      itE2E = _edges.insert(itE2E, std::make_pair(e,re));
+      _vertices[e.getVertex(0)]->add(re);
+      _vertices[e.getVertex(1)]->add(re);
+      _numEdge += EDGE_BASE;
+      _valEdge += EDGE_BASE * re->getQual();
+      if (itedge->second.size() == 1) {
+        _numEdge += EDGE_QUAD;
+        _valEdge += EDGE_QUAD * re->getQual();
+        _vertices[e.getVertex(0)]->setOnBoundary();
+        _vertices[e.getVertex(1)]->setOnBoundary();
+        boundV2E[e.getVertex(0)].push_back(e);
+        boundV2E[e.getVertex(1)].push_back(e);
+      }
+    }
+  }
+  
+  // We know now on what are vertices, compute reward
+  {
+    mapofVertices::iterator itV2N = _vertices.begin();
+    for (; itV2N != _vertices.end(); ++itV2N)
+      _valVert += itV2N->second->getQual();
+  }
+  
+  // Be dealing with "parity" on boundaries
+  {
+    std::map<MVertex*, std::list<MEdge> >::iterator itBound = boundV2E.begin();
+    int actualParity = 0;
+    bool p = 0;
+    while (itBound != boundV2E.end()) {
+      MVertex *firstV = itBound->first, *actualV = firstV;
+      MEdge actualEdge = *itBound->second.begin();
+      Rec2DVertex *rv = _vertices[firstV];
+      rv->setParity(actualParity+p);
+      _parities[actualParity+p].insert(rv);
+      p = !p;
+      if (actualEdge.getVertex(0) == actualV)
+        actualV = actualEdge.getVertex(1);
+      else
+        actualV = actualEdge.getVertex(0);
+      while (actualV != firstV) {
+        rv = _vertices[actualV];
+        rv->setParity(actualParity+p);
+        _parities[actualParity+p].insert(rv);
+        p = !p;
+        itBound = boundV2E.find(actualV);
+        std::list<MEdge>::iterator it = itBound->second.begin();
+        if (*it == actualEdge)
+          actualEdge = *(++it);
+        else
+          actualEdge = *it;
+        if (actualEdge.getVertex(0) == actualV)
+          actualV = actualEdge.getVertex(1);
+        else
+          actualV = actualEdge.getVertex(0);
+        boundV2E.erase(itBound);
+      }
+      if (_vertices[actualV]->getParity() != actualParity+p)
+        Msg::Error("Not even number of mesh edges on boundary !");
+      
+      boundV2E.erase(boundV2E.begin());
+      itBound = boundV2E.begin();
+      actualParity += 2;
+    }
+  }
+  
+  // Create the 'Rec2DTwoTri2Quad' and 'Rec2DCollapseTri'
+  {
+    mapofEdges::iterator itE2E = _edges.begin();
+    std::map<MEdge, std::list<MTriangle*> >::iterator ite = mapEdge.begin();
+    for (; ite != mapEdge.end(); ++ite)
+    if (ite->second.size() == 2) {
+      _actions.insert(new Rec2DTwoTri2Quad(_edges[ite->first], ite->second));
+      _actions.insert(new Rec2DCollapseTri(_edges[ite->first], ite->second));
+    }
+  }
+  
+  // Create the 'Rec2DFourTri2Quad' and 'Rec2DCollapseTri'
+  {
+    std::list<std::map<MVertex*, std::list<MTriangle*> >::iterator>::iterator it4;
+    for (it4 = fourTri.begin(); it4 != fourTri.end(); it4++) {
+      Rec2DVertex *rv = _vertices[(*it4)->first];
+      if (!rv->getIsOnBoundary()) {
+        _actions.insert(new Rec2DFourTri2Quad(rv, (*it4)->second));
+        _actions.insert(new Rec2DCollapseTri(rv, (*it4)->second));
+      }
+    }
+  }
+  
+  Msg::Info("State");
+  Msg::Info("-----");
+  Msg::Info("numEdge %d (%d), valEdge %g", _numEdge, _edges.size(), _valEdge);
+  Msg::Info("numVert %d (%d), valVert %g", _numVert, _vertices.size(), _valVert);
+  Msg::Info("global Value %g", Recombine2D::getGlobalValue(0,0,0,0));
+  Msg::Info("num action %d", _actions.size());
+  std::map<int, std::set<Rec2DVertex*> >::iterator it = _parities.begin();
+  for (; it != _parities.end(); ++it) {
+    Msg::Info("par %d, #%d", it->first, it->second.size());
+  }
+  mapofElementActions::iterator it2 = _mea.begin();
+  int a = 0;
+  for (; it2 != _mea.end(); ++it2) {
+    a += it2->second.size();
+  }
+  if (a > 0)
+    Msg::Info("%d elements in mapof elem to action, with average action %g", _mea.size(), (double)a/_mea.size());
+  Msg::Info(" ");
+}
+
+Recombine2D::~Recombine2D()
+{
+  Recombine2D::_current = NULL;
+  //delete vertices, edges, actions;
+}
+
+double Recombine2D::getGlobalValue(int numEdge, double valEdge,
+                                   int numVert, double valVert )
+{
+  return (_current->_valEdge + valEdge) / (_current->_numEdge + numEdge) *
+         (_current->_valVert + valVert) / (_current->_numVert + numVert);
+}
+
+Rec2DEdge* Recombine2D::getREdge(MEdge e)
+{
+  mapofEdges::iterator it = _current->_edges.find(e);
+  if (it != _current->_edges.end())
+    return it->second;
+  Msg::Error("[Recombine2D::getREdge] edge not found");
+  return NULL;
+}
+
+Rec2DVertex* Recombine2D::getRVertex(MVertex *v)
+{
+  mapofVertices::iterator it = _current->_vertices.find(v);
+  if (it != _current->_vertices.end())
+    return it->second;
+  Msg::Error("[Recombine2D::getRVertex] vertex not found");
+  return NULL;
+}
+
+
+/**  Rec2DTwoTri2Quad  **/
+/************************/
+Rec2DTwoTri2Quad::Rec2DTwoTri2Quad(Rec2DEdge *re, std::list<MTriangle*> &tri)
+{
+  int i;
+  std::set<MEdge, Less_Edge> extEdges;
+  {
+    std::list<MTriangle*>::iterator it = tri.begin();
+    for (i = 0; it != tri.end() && i < 2; ++it, ++i) {
+      for (int j = 0; j < 3; ++j)
+        extEdges.insert((*it)->getEdge(j));
+      _triangles[i] = *it;
+    }
+    if (it != tri.end() || i < 2)
+      Msg::Error("[Rec2DTwoTri2Quad] Wrong number of triangles");
+    extEdges.erase(re->getMEdge());
+  }
+  
+  _edges[0] = re;
+  std::set<MEdge>::iterator ite = extEdges.begin();
+  for (i = 1; ite != extEdges.end() && i < 5; ++ite, ++i)
+    _edges[i] = Recombine2D::getREdge(*ite);
+  if (ite != extEdges.end() || i < 5)
+    Msg::Error("[Rec2DTwoTri2Quad] Wrong number of edges");
+  
+  _vertices[0] = re->getRVertex(0);
+  _vertices[1] = re->getRVertex(1);
+  MVertex *v2, *v3;
+  v2 = _triangles[0]->getOtherVertex(_vertices[0]->getMVertex(),
+                                    _vertices[1]->getMVertex());
+  v3 = _triangles[1]->getOtherVertex(_vertices[0]->getMVertex(),
+                                    _vertices[1]->getMVertex());
+  _vertices[2] = Recombine2D::getRVertex(v2);
+  _vertices[3] = Recombine2D::getRVertex(v3);
+  
+  _computeGlobVal();
+}
+
+bool Rec2DTwoTri2Quad::isObsolete()
+{
+  int p0 = _vertices[0]->getParity();
+  int p1 = _vertices[1]->getParity();
+  int p2 = _vertices[2]->getParity();
+  int p3 = _vertices[3]->getParity();
+  if (p0>-1 && p1>-1 && p0/2 == p1/2 && p0 % 2 != p1 % 2 ||
+      p2>-1 && p3>-1 && p2/2 == p3/2 && p2 % 2 != p3 % 2 ||
+      p0>-1 && p0 == p2                                  ||
+      p0>-1 && p0 == p3                                  ||
+      p1>-1 && p1 == p2                                  ||
+      p1>-1 && p1 == p3                                    )
+    return true;
+  return false;
+}
+
+void Rec2DTwoTri2Quad::_computeGlobVal()
+{
+  double valEdge = - EDGE_BASE * _edges[0]->getQual();
+  for (int i = 1; i < 5; ++i)
+    valEdge += EDGE_QUAD * _edges[i]->getQual();
+  
+  double valVert = _vertices[0]->getGain(-1) + _vertices[1]->getGain(-1);
+  
+  _globValIfExecuted = Recombine2D::getGlobalValue(4*EDGE_QUAD - EDGE_BASE,
+                                                   valEdge, 0, valVert     );
+  _lastUpdate = Recombine2D::getNumChange();
+}
+
+/**  Rec2DFourTri2Quad  **/
+/*************************/
+Rec2DFourTri2Quad::Rec2DFourTri2Quad(Rec2DVertex *rv, std::list<MTriangle*> &tri)
+{
+  int i, j;
+  std::set<MEdge, Less_Edge> edges;
+  {
+    std::list<MTriangle*>::iterator it = tri.begin();
+    for (i = 0; it != tri.end() && i < 4; ++it, ++i) {
+      for (j = 0; j < 3; ++j)
+        edges.insert((*it)->getEdge(j));
+      _triangles[i] = *it;
+    }
+    if (it != tri.end() || i < 4)
+      Msg::Error("[Rec2DFourTri2Quad] Wrong number of triangles");
+  }
+  
+  std::set<MEdge>::iterator ite = edges.begin();
+  for (i = 0, j = 4; ite != edges.end() && (i < 4 || j < 8); ++ite) {
+    if ((*ite).getVertex(0) == rv->getMVertex() ||
+        (*ite).getVertex(1) == rv->getMVertex()   )
+      _edges[i++] = Recombine2D::getREdge(*ite);
+    else if (j < 8)
+      _edges[j++] = Recombine2D::getREdge(*ite);
+    else
+      Msg::Error("[Rec2DFourTri2Quad] Too much exterior edges");
+  }
+  if (edges.size() > 8 || ite != edges.end() || i < 4 || i > 4 || j < 8)
+    Msg::Error("[Rec2DFourTri2Quad] Wrong number of edges");
+  
+  _vertices[4] = rv;
+  // the 4 other must be in order : 2 non adjacent + last 2
+  _vertices[1] = _edges[4]->getRVertex(0);
+  _vertices[3] = _edges[4]->getRVertex(1);
+  for (int i = 5; i < 8; ++i) {
+    if (_edges[i]->getRVertex(0) == _vertices[1])
+      _vertices[0] = _edges[i]->getRVertex(1);
+    if (_edges[i]->getRVertex(1) == _vertices[1])
+      _vertices[0] = _edges[i]->getRVertex(0);
+    if (_edges[i]->getRVertex(0) == _vertices[3])
+      _vertices[2] = _edges[i]->getRVertex(1);
+    if (_edges[i]->getRVertex(1) == _vertices[3])
+      _vertices[2] = _edges[i]->getRVertex(0);
+  }
+  
+  _computeGlobVal();
+}
+
+bool Rec2DFourTri2Quad::isObsolete()
+{
+  int p0 = _vertices[0]->getParity();
+  int p1 = _vertices[1]->getParity();
+  int p2 = _vertices[2]->getParity();
+  int p3 = _vertices[3]->getParity();
+  if (p0>-1 && p1>-1 && p0/2 == p1/2 && p0 % 2 != p1 % 2 ||
+      p2>-1 && p3>-1 && p2/2 == p3/2 && p2 % 2 != p3 % 2 ||
+      p0>-1 && p0 == p2                                  ||
+      p0>-1 && p0 == p3                                  ||
+      p1>-1 && p1 == p2                                  ||
+      p1>-1 && p1 == p3                                    )
+    return true;
+  return false;
+}
+
+void Rec2DFourTri2Quad::_computeGlobVal()
+{
+  double valEdge = 0;
+  for (int i = 0; i < 4; ++i)
+    valEdge -= EDGE_BASE * _edges[i]->getQual();
+  for (int i = 4; i < 8; ++i)
+    valEdge += EDGE_QUAD * _edges[i]->getQual();
+    
+  double valVert = - _vertices[0]->getQual();
+  for (int i = 1; i < 5; ++i)
+    valEdge += _vertices[i]->getGain(-1);
+  
+  _globValIfExecuted = Recombine2D::getGlobalValue(4*EDGE_QUAD - 4*EDGE_BASE,
+                                                   valEdge, -1, valVert      );
+  _lastUpdate = Recombine2D::getNumChange();
+}
+
+/**  Rec2DCollapseTri  **/
+/*********************/
+Rec2DCollapseTri::Rec2DCollapseTri(Rec2DVertex *rv, std::list<MTriangle*> &tri)
+{
+  int i;
+  std::set<MEdge, Less_Edge> extEdges;
+  {
+    std::list<MTriangle*>::iterator it = tri.begin();
+    for (i = 0; it != tri.end() && i < 4; ++it, ++i) {
+      for (int j = 0; j < 3; ++j)
+      if ((*it)->getEdge(j).getVertex(0) != rv->getMVertex() &&
+          (*it)->getEdge(j).getVertex(1) != rv->getMVertex()   )
+        extEdges.insert((*it)->getEdge(j));
+    }
+    if (it != tri.end() || i < 4)
+      Msg::Error("[Rec2DFourTri2Quad] Wrong number of triangles");
+  }
+  
+  _vertices[4] = rv;
+  // the 4 other must be in order : 2 non adjacent + last 2
+  std::set<MEdge>::iterator ite = extEdges.begin();
+  Rec2DEdge *re = Recombine2D::getREdge(*ite);
+  _vertices[1] = re->getRVertex(0);
+  _vertices[3] = re->getRVertex(1);
+  ++ite;
+  for (; ite != extEdges.end(); ++ite) {
+    re = Recombine2D::getREdge(*ite);
+    if (re->getRVertex(0) == _vertices[1])
+      _vertices[0] = re->getRVertex(1);
+    if (re->getRVertex(1) == _vertices[1])
+      _vertices[0] = re->getRVertex(0);
+    if (re->getRVertex(0) == _vertices[3])
+      _vertices[2] = re->getRVertex(1);
+    if (re->getRVertex(1) == _vertices[3])
+      _vertices[2] = re->getRVertex(0);
+  }
+  
+  _computeGlobVal();
+}
+
+Rec2DCollapseTri::Rec2DCollapseTri(Rec2DEdge *re, std::list<MTriangle*> &tri)
+: _edge(re)
+{
+  int i;
+  std::set<MEdge, Less_Edge> extEdges;
+  {
+    std::list<MTriangle*>::iterator it = tri.begin();
+    for (i = 0; it != tri.end() && i < 2; ++it, ++i) {
+      for (int j = 0; j < 3; ++j)
+        extEdges.insert((*it)->getEdge(j));
+      _triangles[i] = *it;
+    }
+    if (it != tri.end() || i < 2)
+      Msg::Error("[Rec2DTwoTri2Quad] Wrong number of triangles");
+    extEdges.erase(re->getMEdge());
+  }
+  _triangles[2] = _triangles[3] = NULL;
+  
+  _vertices[0] = re->getRVertex(0);
+  _vertices[1] = re->getRVertex(1);
+  MVertex *v2, *v3;
+  v2 = _triangles[0]->getOtherVertex(_vertices[0]->getMVertex(),
+                                    _vertices[1]->getMVertex());
+  v3 = _triangles[1]->getOtherVertex(_vertices[0]->getMVertex(),
+                                    _vertices[1]->getMVertex());
+  _vertices[2] = Recombine2D::getRVertex(v2);
+  _vertices[3] = Recombine2D::getRVertex(v3);
+  _vertices[4] = NULL;
+  
+  _computeGlobVal();
+}
+
+bool Rec2DCollapseTri::isObsolete()
+{
+  int p0 = _vertices[0]->getParity();
+  int p1 = _vertices[1]->getParity();
+  int p2 = _vertices[2]->getParity();
+  int p3 = _vertices[3]->getParity();
+  int b0 = _vertices[0]->getIsOnBoundary();
+  int b1 = _vertices[1]->getIsOnBoundary();
+  int b2 = _vertices[2]->getIsOnBoundary();
+  int b3 = _vertices[3]->getIsOnBoundary();
+  if ((b0 && b1) || (p0>-1 && p1>-1 && p0/2 == p1/2 && p0 % 2 != p1 % 2) &&
+      (b2 && b3) || (p2>-1 && p3>-1 && p2/2 == p3/2 && p2 % 2 != p3 % 2)   )
+    return true;
+  return false;
+}
+
+void Rec2DCollapseTri::_computeGlobVal()
+{
+  int b0 = _vertices[0]->getIsOnBoundary();
+  int b1 = _vertices[1]->getIsOnBoundary();
+  int b2 = _vertices[2]->getIsOnBoundary();
+  int b3 = _vertices[3]->getIsOnBoundary();
+  
+  std::map<Rec2DVertex*, int> neighbourVert;
+  std::set<Rec2DEdge*> neighbourEdge; 
+  if (!b0 || !b1) {
+    _vertices[0]->getNeighbours(neighbourVert, neighbourEdge);
+    _vertices[1]->getNeighbours(neighbourVert, neighbourEdge);
+    if (_vertices[4]) {
+      neighbourVert.erase(_vertices[4]);
+      _vertices[4]->getNeighbourEdges(neighbourEdge);
+    }
+    //else
+    //  neighbourEdge.insert(_edge);
+    
+    int numEdge = 0, numVert = 0;
+    double valEdge = .0, valVert = .0;
+    {
+      std::set<Rec2DEdge*>::iterator it = neighbourEdge.begin();
+      for (; it != neighbourEdge.end(); ++it) {
+        valEdge -= (*it)->getWeightedQual();
+        numEdge -= (*it)->getWeight();
+      }
+      valVert -= _vertices[0]->getQual();
+      valVert -= _vertices[1]->getQual();
+      if (_vertices[4]) {
+        valVert -= _vertices[4]->getQual();
+        numVert -= 1;
+        valVert += _vertices[2]->getGain(-2);
+        valVert += _vertices[3]->getGain(-2);
+      }
+      else {
+        valVert += _vertices[2]->getGain(-1);
+        valVert += _vertices[3]->getGain(-1);
+      }
+    }
+    if (b0)
+      _qualCavity(valVert, valEdge, numEdge, neighbourVert, _vertices[0]);
+    else if (b1)
+      _qualCavity(valVert, valEdge, numEdge, neighbourVert, _vertices[1]);
+    else
+      _qualCavity(valVert, valEdge, numEdge, neighbourVert);
+    numVert -= 1;
+    
+    _globValIfExecuted =
+        Recombine2D::getGlobalValue(numEdge, valEdge, numVert, valVert);
+  }
+  else
+    _globValIfExecuted = -1.;
+  
+  
+  neighbourVert.clear();
+  neighbourEdge.clear();
+  if (!b2 || !b3) {
+    _vertices[2]->getNeighbours(neighbourVert, neighbourEdge);
+    _vertices[3]->getNeighbours(neighbourVert, neighbourEdge);
+    if (_vertices[4]) {
+      neighbourVert.erase(_vertices[4]);
+      _vertices[4]->getNeighbourEdges(neighbourEdge);
+    }
+    else
+      neighbourEdge.insert(_edge);
+    
+    int numEdge = 0, numVert = 0;
+    double valEdge = .0, valVert = .0;
+    {
+      std::set<Rec2DEdge*>::iterator it = neighbourEdge.begin();
+      for (; it != neighbourEdge.end(); ++it) {
+        valEdge -= (*it)->getWeightedQual();
+        numEdge -= (*it)->getWeight();
+      }
+      valVert -= _vertices[2]->getQual();
+      valVert -= _vertices[3]->getQual();
+      if (_vertices[4]) {
+        valVert -= _vertices[4]->getQual();
+        numVert -= 1;
+        valVert += _vertices[0]->getGain(-2);
+        valVert += _vertices[1]->getGain(-2);
+      }
+      else {
+        valVert += _vertices[0]->getGain(-2);
+        valVert += _vertices[1]->getGain(-2);
+      }
+    }
+    if (b2)
+      _qualCavity(valVert, valEdge, numEdge, neighbourVert, _vertices[2]);
+    else if (b3)
+      _qualCavity(valVert, valEdge, numEdge, neighbourVert, _vertices[3]);
+    else
+      _qualCavity(valVert, valEdge, numEdge, neighbourVert);
+    numVert -= 1;
+    
+    _globValIfExecuted2 =
+        Recombine2D::getGlobalValue(numEdge, valEdge, numVert, valVert);
+  }
+  else
+    _globValIfExecuted2 = -1.;
+    
+  _lastUpdate = Recombine2D::getNumChange();
+}
+
+void Rec2DCollapseTri::_qualCavity(double &valVert, double &valEdge,
+                                   int &numEdge,
+                                   std::map<Rec2DVertex*, int> &vert,
+                                   Rec2DVertex *imposedVert          )
+{
+  Recombine2D::bo = true;
+  std::map<Rec2DVertex*, int>::iterator it;
+  Rec2DVertex *rv = imposedVert;
+  if (rv == NULL) {
+    double u, v = u = .0;
+    it = vert.begin();
+    for (; it != vert.end(); ++it) {
+      u += it->first->u();
+      v += it->first->v();
+    }
+    u /= vert.size();
+    v /= vert.size();
+    
+    rv = new Rec2DVertex(u, v);
+  }
+  valVert = rv->getQual(vert.size());
+  it = vert.begin();
+  for (; it != vert.end(); ++it) {
+    Rec2DEdge re(rv, it->first);
+    valEdge += it->second * re.getQual();
+    numEdge += it->second;
+  }
+  if (imposedVert == NULL) {
+    rv->deleteMVertex();
+    delete rv;
+  }
+}
+
+/**  Rec2DVertex  **/
+/*******************/
+Rec2DVertex::Rec2DVertex(MVertex *v, std::list<MTriangle*> tri, int onWhat,
+                         std::map<MVertex*, std::set<GEdge*> > gEdges)
+: _v(v), _onWhat(onWhat), _parity(-1), _lastChange(-1), _numEl(tri.size())
+{
+  if (_onWhat == -1) {
+    std::map<MVertex*, std::set<GEdge*> >::iterator it = gEdges.find(_v);
+    if (it != gEdges.end()) {
+      _angle = _computeAngle(_v, tri, it->second);
+    }
+    else {
+      Msg::Warning("[meshRecombine2D] Can't compute corner angle, setting angle to pi/2");
+      _angle = M_PI / 2.;
+    }
+  }
+  reparamMeshVertexOnFace(_v, Recombine2D::getGFace(), _param); 
+  _computeQual();
+}
+
+Rec2DVertex::Rec2DVertex(double u, double v)
+: _onWhat(1), _parity(-1), _lastChange(-1)
+{
+  _param[0] = u;
+  _param[1] = v;
+  
+  GPoint p = Recombine2D::getGFace()->point(_param);
+  _v = new MVertex(p.x(), p.y(), p.z(), Recombine2D::getGFace());
+  static int i = 0;
+  if (++i < 20)
+    Msg::Info("resulting point = [%g,%g,%g]", p.x(), p.y(), p.z());
+}
+
+double Rec2DVertex::_computeAngle(MVertex *v,
+                                  std::list<MTriangle*> &listTri,
+                                  std::set<GEdge*> &setEdge)
+{
+  if (setEdge.size() != 2) {
+    Msg::Warning("[meshGFaceRecombine] Wrong number of edge : %d, returning pi/2", setEdge.size());
+    return M_PI / 2.;
+  }
+  static const double prec = 100.;
+  
+  SVector3 vectv = SVector3(v->x(), v->y(), v->z());
+  SVector3 firstDer0, firstDer1;
+  
+  std::set<GEdge*>::iterator it = setEdge.begin();
+  for (int k = 0; k < 2; ++it, ++k) {
+    GEdge *ge = *it;
+    SVector3 vectlb = ge->position(ge->getLowerBound());
+    SVector3 vectub = ge->position(ge->getUpperBound());
+    vectlb -= vectv;
+    vectub -= vectv;
+    double normlb, normub;
+    if ((normlb = norm(vectlb)) > prec * (normub = norm(vectub)))
+      firstDer1 = ge->firstDer(ge->getUpperBound());
+    else if (normub > prec * normlb)
+      firstDer1 = ge->firstDer(ge->getLowerBound());
+    else {
+      Msg::Warning("[meshGFaceRecombine] Bad precision, returning pi/2");
+      return M_PI / 2.;
+    }
+    if (k == 0)
+      firstDer0 = firstDer1;
+  }
+  
+  firstDer0 = firstDer0 * (1 / norm(firstDer0));
+  firstDer1 = firstDer1 * (1 / norm(firstDer1));
+  
+  double angle1 = acos(dot(firstDer0, firstDer1));
+  double angle2 = 2. * M_PI - angle1;
+  
+  double angleMesh = .0;
+  std::list<MTriangle*>::iterator it2 = listTri.begin();
+  for (; it2 != listTri.end(); ++it2) {
+    MTriangle *t = *it2;
+    int k = 0;
+    while (t->getVertex(k) != v && k < 3)
+      ++k;
+    if (k == 3) {
+      Msg::Warning("[meshGFaceRecombine] Wrong triangle, returning pi/2");
+      return M_PI / 2.;
+    }
+    angleMesh += angle3Vertices(t->getVertex((k+1)%3), v, t->getVertex((k+2)%3));
+  }
+  
+  if (angleMesh < M_PI)
+    return angle1;
+  return angle2;
+}
+
+double Rec2DVertex::getQual(int numEdge)
+{
+  if (numEdge > 1) {
+    switch (_onWhat) {
+      case 1 :
+        return _qualVSnum[_onWhat][numEdge-1];
+      case 0 :
+        return _qualVSnum[_onWhat][numEdge-2];
+      case -1 :
+        return 1. - fabs(2./M_PI * _angle/(numEdge-1) - 1.);
+      default :
+        Msg::Error("[Rec2DVertex] Don't know on what is the vertex");
+        return -1.;
+    }
+  }
+  if (_lastChange < Recombine2D::getNumChange())
+    _computeQual();
+  return _qual;
+}
+
+void Rec2DVertex::_computeQual()
+{
+  if (_onWhat > -1)
+    _qual = _qualVSnum[_onWhat][_numEl-1];
+  else
+    _qual = 1. - fabs(2./M_PI * _angle/_numEl - 1.);
+  _lastChange = Recombine2D::getNumChange();
+}
+
+double Rec2DVertex::getGain(int n)
+{
+  if (_onWhat > -1) {
+    switch (n) {
+      case 1 :
+        return _gains[_onWhat][_numEl-1];
+      case -1 :
+        return - _gains[_onWhat][_numEl-2];
+      default :
+        return _qualVSnum[_onWhat][_numEl-1+n] - _qualVSnum[_onWhat][_numEl-1];
+    }
+  }
+  else
+    return fabs(2./M_PI * _angle/_numEl - 1.)
+         - fabs(2./M_PI * _angle/(_numEl + n) - 1.);
+}
+
+void Rec2DVertex::getNeighbours(std::map<Rec2DVertex*, int> &vert,
+                                std::set<Rec2DEdge*> &edge        )
+{
+  Rec2DVertex *rv;
+  std::map<Rec2DVertex*, int>::iterator it;
+  for (unsigned int i = 0; i < _edges.size(); ++i){
+    edge.insert(_edges[i]);
+    if (_edges[i]->getRVertex(0) != this)
+      rv = _edges[i]->getRVertex(0);
+    else
+      rv = _edges[i]->getRVertex(1);
+    if ((it = vert.find(rv)) != vert.end())
+      it->second += _edges[i]->getWeight() - EDGE_BASE;
+    else
+      vert[rv] = _edges[i]->getWeight();
+  }
+}
+
+void Rec2DVertex::getNeighbourEdges(std::set<Rec2DEdge*> &edge)
+{
+  for (unsigned int i = 0; i < _edges.size(); ++i)
+    edge.insert(_edges[i]);
+}
+
+void Rec2DVertex::initStaticTable()
+{
+  if (_qualVSnum == NULL) {
+    // _qualVSnum[onWhat][nEl]; onWhat={0:edge,1:face} / nEl=_numEl-1
+    // _gains[onWhat][nEl]; onWhat={0:edge,1:face} / nEl=_numEl-1 (earning of adding an element)
+    int nE = 10, nF = 20;
+    
+    _qualVSnum = new double*[2];
+    _qualVSnum[0] = new double[nE];
+    for (int i = 0; i < nE; ++i)
+      _qualVSnum[0][i] = 1. - fabs(2./(i+1) - 1.);
+    _qualVSnum[1] = new double[nF];
+    for (int i = 0; i < nF; ++i)
+      _qualVSnum[1][i] = 1. - fabs(4./(i+1) - 1.);
+      
+    _gains = new double*[2];
+    _gains[0] = new double[nE-1];
+    for (int i = 0; i < nE-1; ++i)
+      _gains[0][i] = _qualVSnum[0][i+1] - _qualVSnum[0][i];
+    _gains[1] = new double[nF-1];
+    for (int i = 0; i < nF-1; ++i)
+      _gains[1][i] = _qualVSnum[1][i+1] - _qualVSnum[1][i];
+  }
+}
+
+/**  Rec2DEdge  **/
+/*****************/
+Rec2DEdge::Rec2DEdge(MEdge e, mapofVertices &vert, std::list<MTriangle*> &tri)
+: _lastChange(-1), _qual(.0), _weight(EDGE_BASE),
+  _rv1(vert[e.getVertex(0)]), _rv2(vert[e.getVertex(1)])
+{
+  _rv1->add(this);
+  _rv2->add(this);
+}
+
+Rec2DEdge::Rec2DEdge(Rec2DVertex *rv1, Rec2DVertex *rv2)
+: _lastChange(-1), _qual(.0), _weight(EDGE_BASE), _rv1(rv1), _rv2(rv2)
+{
+}
+
+double Rec2DEdge::getQual()
+{
+  if (_lastChange < Recombine2D::getNumChange())
+    _computeQual();
+  return _qual;
+}
+
+void Rec2DEdge::_computeQual()
+{
+  static int i = 0; if (++i < 2) Msg::Warning("FIXME compute qual edge and update of vertex");
+  //_rv1->update();
+  //_rv2->update();
+  double adimLength = _straightAdimLength();
+  double alignment = _straightAlignment();
+  _qual = Recombine2D::edgeReward(adimLength, alignment);
+  _lastChange = Recombine2D::getNumChange();
+}
+
+double Rec2DEdge::_straightAdimLength()
+{
+  double dx, dy, dz, **xyz;
+  xyz = new double*[2];
+  xyz[0] = new double[3];
+  xyz[1] = new double[3];
+  _rv1->getxyz(xyz[0]);
+  _rv2->getxyz(xyz[1]);
+  dx = xyz[0][0] - xyz[1][0];
+  dy = xyz[0][1] - xyz[1][1];
+  dz = xyz[0][2] - xyz[1][2];
+  double length = sqrt(dx * dx + dy * dy + dz * dz);
+  delete[] xyz[0];
+  delete[] xyz[1];
+  delete[] xyz;
+  
+  double lc1 = (*Recombine2D::bgm())(_rv1->u(), _rv1->v(), .0);
+  double lc2 = (*Recombine2D::bgm())(_rv2->u(), _rv2->v(), .0);
+  
+  return length * (1/lc1 + 1/lc2) / 2;
+}
+
+double Rec2DEdge::_straightAlignment()
+{
+  double angle1 = Recombine2D::bgm()->getAngle(_rv1->u(), _rv1->v(), .0);
+  double angle2 = Recombine2D::bgm()->getAngle(_rv1->u(), _rv1->v(), .0);
+  double angleEdge = atan2(_rv1->u()-_rv2->u(), _rv1->v()-_rv2->v());
+  
+  double alpha1 = angleEdge - angle1;
+  double alpha2 = angleEdge - angle2;
+  crossField2d::normalizeAngle(alpha1);
+  crossField2d::normalizeAngle(alpha2);
+  alpha1 = std::min(alpha1, .5 * M_PI - alpha1);
+  alpha2 = std::min(alpha2, .5 * M_PI - alpha2);
+  
+  double lc1 = (*Recombine2D::bgm())(_rv1->u(), _rv1->v(), .0);
+  double lc2 = (*Recombine2D::bgm())(_rv1->u(), _rv1->v(), .0);
+  
+  return (alpha1/lc1 + alpha2/lc2) / (1/lc1 + 1/lc2);
+}
\ No newline at end of file
diff --git a/Mesh/meshGFaceRecombine.h b/Mesh/meshGFaceRecombine.h
new file mode 100644
index 0000000000000000000000000000000000000000..619221cec55a15ba016511a4f3a348252219cca0
--- /dev/null
+++ b/Mesh/meshGFaceRecombine.h
@@ -0,0 +1,211 @@
+// Gmsh - Copyright (C) 1997-2011 C. Geuzaine, J.-F. Remacle
+//
+// See the LICENSE.txt file for license information. Please report all
+// bugs and problems to <gmsh@geuz.org>.
+//
+// Contributor(s):
+//   Amaury Johnen (a.johnen@ulg.ac.be)
+//
+
+#ifndef _MESH_GFACE_RECOMBINE_H_
+#define _MESH_GFACE_RECOMBINE_H_
+
+#include "GFace.h"
+#include "GModel.h"
+#include "MEdge.h"
+#include "BackgroundMesh.h"
+
+class Rec2DEdge;
+class Rec2DVertex;
+class Rec2DAction;
+
+typedef std::set<Rec2DAction*/*, lessRec2DAction*/> setofRec2DAction;
+typedef std::map<MVertex*, Rec2DVertex*> mapofVertices;
+typedef std::map<MEdge, Rec2DEdge*, Less_Edge> mapofEdges;
+typedef std::map<MElement*, std::set<Rec2DAction*> > mapofElementActions;
+typedef std::map<MQuadrangle*, std::set<MElement*> > mapofAdjacencies;
+
+class Recombine2D {
+  private :
+    int _numEdge, _numVert, _numChange;
+    double _valEdge, _valVert;
+    GFace *_gf;
+    backgroundMesh *_bgm;
+    mapofEdges _edges;
+    mapofVertices _vertices;
+    setofRec2DAction _actions;
+    mapofElementActions _mea;
+    mapofAdjacencies _ma;
+    std::map<int, std::set<Rec2DVertex*> > _parities;
+    std::vector<Rec2DAction*> _obsoleteAction;
+    static Recombine2D *_current;
+    
+  public :
+    static bool bo;
+    
+    Recombine2D(GFace*);
+    Recombine2D(GModel*);
+    ~Recombine2D();
+    
+    void apply(bool){return;}
+    
+    static inline double edgeReward(double adimLength, double alignment)
+      {return adimLength * (.5 + .5 * alignment);}
+    static inline int getNumChange() {return _current->_numChange;}
+    static inline backgroundMesh* bgm() {return _current->_bgm;}
+    static inline double getGlobalValue(int numEdge, double valEdge,
+                                        int numVert, double valVert );
+    static Rec2DEdge* getREdge(MEdge);
+    static Rec2DVertex* getRVertex(MVertex*);
+    static inline GFace* getGFace() {return _current->_gf;}
+    static inline void addObsleteAction(Rec2DAction *a) {
+      _current->_obsoleteAction.push_back(a);
+    }
+    //static inline int* getPtrNumChange() {return &_numChange;}
+};
+
+class Rec2DAction {
+  private :
+    int _position;
+    
+  protected :
+    int _lastUpdate;
+    double _globValIfExecuted;
+    
+  public :
+    inline int getVectPosition() {return _position;}
+    inline void setVectPosition(int p) {_position = p;}
+    //virtual double getReward() = 0;
+    virtual bool isObsolete() = 0;
+  
+  private :
+    virtual void _computeGlobVal() = 0;
+};
+
+class Rec2DTwoTri2Quad : public Rec2DAction {
+  private :
+    MTriangle *_triangles[2];
+    Rec2DEdge *_edges[5]; // 1 embedded, 4 boundary
+    Rec2DVertex *_vertices[4]; // 4 boundary (2 on embedded edge + 2)
+    
+  public :
+    Rec2DTwoTri2Quad(Rec2DEdge*, std::list<MTriangle*>&);
+    //double getReward();
+    bool isObsolete();
+  
+  private :
+    void _computeGlobVal();
+};
+
+class Rec2DFourTri2Quad : public Rec2DAction {
+  private :
+    MTriangle *_triangles[4];
+    Rec2DEdge *_edges[8]; // 4 embedded, 4 boundary
+    Rec2DVertex *_vertices[5]; // 4 boundary (2 non adjacent + 2), 1 embedded
+    
+  public :
+    Rec2DFourTri2Quad(Rec2DVertex*, std::list<MTriangle*>&);
+    //double getReward();
+    bool isObsolete();
+  
+  private :
+    void _computeGlobVal();
+};
+
+class Rec2DCollapseTri : public Rec2DAction {
+  private :
+    MTriangle *_triangles[4]; // either 2 or 4 triangles
+    Rec2DEdge *_edge; // 1 embedded or NULL
+    Rec2DVertex *_vertices[5]; // 4 boundary (2 on embedded edge + 2), 1 embedded or NULL
+    double _globValIfExecuted2;
+    
+  public :
+    Rec2DCollapseTri(Rec2DVertex*, std::list<MTriangle*>&);
+    Rec2DCollapseTri(Rec2DEdge*, std::list<MTriangle*>&);
+    //double getReward();
+    bool isObsolete();
+  
+  private :
+    void _computeGlobVal();
+    void _qualCavity(double &valVert, double &valEdge, int &numEdge,
+                     std::map<Rec2DVertex*, int> &vertices,
+                     Rec2DVertex *imposedVert = NULL                );
+    
+};
+
+class Rec2DListAction {
+  private :
+    
+    
+  public :
+    
+};
+
+class Rec2DVertex {
+  private :
+    MVertex *_v;
+    std::vector<Rec2DEdge*> _edges;
+    int _onWhat, _numEl, _parity, _lastChange;
+    // _onWhat={-1:corner,0:edge,1:face,(2:volume)}
+    double _angle, _qual;
+    SPoint2 _param;
+    
+    static double **_qualVSnum;
+    static double **_gains;
+    
+  public :
+    Rec2DVertex(MVertex*, std::list<MTriangle*>, int onWhat,
+                std::map<MVertex*, std::set<GEdge*> >);
+    Rec2DVertex(double u, double v);
+    
+    void add(Rec2DEdge *re) {_edges.push_back(re);}
+    void setOnBoundary() {if (_onWhat > 0) _onWhat = -1;
+      static bool a=1; if(a){Msg::Error("FIXME boundary");a=0;}}
+    bool getIsOnBoundary() {return _onWhat < 1;}
+    double getQual(int numEdge = -1);
+    inline int getParity() {return _parity;}
+    inline void setParity(int p) {_parity = p;}
+    inline MVertex* getMVertex() {return _v;}
+    void getxyz(double *xyz) {
+      xyz[0] = _v->x(); xyz[1] = _v->y(); xyz[2] = _v->z();}
+    inline double u() {return _param[0];}
+    inline double v() {return _param[1];}
+    inline void deleteMVertex() {delete _v;}
+    
+    double getGain(int);
+    void getNeighbours(std::map<Rec2DVertex*, int>&, std::set<Rec2DEdge*>&);
+    void getNeighbourEdges(std::set<Rec2DEdge*>&);
+    
+    static void initStaticTable();
+    
+  private :
+    void _computeQual();
+    double _computeAngle(MVertex*, std::list<MTriangle*>&, std::set<GEdge*>&);
+};
+
+class Rec2DEdge {
+  private :
+    Rec2DVertex *_rv1, *_rv2;
+    double _qual;
+    int _lastChange, _weight;
+    
+  public :
+    Rec2DEdge(MEdge, mapofVertices&, std::list<MTriangle*>&);
+    Rec2DEdge(Rec2DVertex*, Rec2DVertex*);
+    
+    double getQual();
+    inline MEdge getMEdge() {return MEdge(_rv1->getMVertex(), _rv2->getMVertex());}
+    inline Rec2DVertex* getRVertex(int i) {if (i) return _rv2; return _rv1;}
+    int getWeight() {return _weight;}
+    double getWeightedQual() {return _weight * _qual;}
+    
+  private :
+    void _computeQual();
+    double _straightAdimLength();
+    double _straightAlignment();
+};
+
+#endif
+
+//idee : lors du parcours de larbre avec un horizon : copier les Rec2dVertex et les Rec2DEdge.
+//idee : faire carr�ment : arrete d'un triangle = 0, arrete d'un quad = 1/2