diff --git a/Mesh/meshRecombine2D.cpp b/Mesh/meshRecombine2D.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..fc535af1096ab06552d44253bda56b5e1115f7bc
--- /dev/null
+++ b/Mesh/meshRecombine2D.cpp
@@ -0,0 +1,437 @@
+// 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 (amjohnen@gmail.com) adapted from meshGFaceOptimize
+//
+
+#include "meshRecombine2D.h"
+#include "GFace.h"
+
+static int HORIZ = 25;
+
+static int NUM_NEW = 0;
+static int NEW_REC = 0;
+static int NEW_NODE = 0;
+static int NEW_QUAD = 0;
+
+static int NUM_DEL = 0;
+static int DEL_REC = 0;
+static int DEL_NODE = 0;
+static int DEL_QUAD = 0;
+
+Recombine2D::Recombine2D(GFace *gf, int horizon)
+    : _horizon(horizon), _gf(gf), _benef(.0), _applied(false)
+{
+  if (_horizon < 1) _horizon = 1;
+  
+  Msg::Info("Branching with horizon %d", _horizon = HORIZ);
+  
+  _haveParam = gf->geomType() != GEntity::DiscreteSurface || gf->getCompound();
+  if(!_haveParam) {
+    Msg::Warning("Surfaces must have prametrization in order to recombine triangles");
+    //return;
+    _haveParam=true;
+  }
+  
+  e2t_cont adj;
+  _buildEdgeToElement(gf->triangles, adj);
+  
+  std::map<MElement*, int> boundaryTriangle;
+  std::pair<Set_Recomb::iterator, bool> ret;
+  
+  for (e2t_cont::iterator it = adj.begin(); it != adj.end(); ++it) {
+    if (it->second.second) {
+      RecombTriangle *rt = new RecombTriangle(it->first, it->second.first, it->second.second);
+NUM_NEW++;
+NEW_REC++;
+      do {
+        rt->touch();
+        ret = _pairs.insert(rt);
+      } while (ret.second == false);
+      _possibleRecomb[it->second.first].insert(rt);
+      _possibleRecomb[it->second.second].insert(rt);
+    }
+    else {
+      if (boundaryTriangle.find(it->second.first) == boundaryTriangle.end())
+        boundaryTriangle[it->second.first] = 1;
+      else
+        boundaryTriangle[it->second.first] = 2;
+    }
+  }
+  
+  std::map<MElement*, int>::iterator itt;
+  
+  for (itt = boundaryTriangle.begin(); itt != boundaryTriangle.end(); ++itt) {
+    RecombTriangle *rt;
+    if (itt->second == 1)
+      rt = new RecombTriangle(itt->first, -100);
+    else
+      rt = new RecombTriangle(itt->first, -200);
+NUM_NEW++;
+NEW_REC++;
+    
+    ret = _pairs.insert(rt);
+    while (!ret.second) {
+      rt->touch();
+      ret = _pairs.insert(rt);
+    }
+    _possibleRecomb[itt->first].insert(rt);
+  }
+  
+  Msg::Info("poss %d", _possibleRecomb.size());
+  Msg::Info("pairs %d", _pairs.size());
+  Msg::Info("tri %d", gf->triangles.size());
+  
+  _recombine();
+  
+  Msg::Info("new %d = %d + %d + %d", NUM_NEW, NEW_REC, NEW_NODE, NEW_QUAD);
+  Msg::Info("del %d = %d + %d + %d", NUM_DEL, DEL_REC, DEL_NODE, DEL_QUAD);
+}
+
+Recombine2D::~Recombine2D()
+{
+  if (!_applied)
+  for (int i = 0; i < _quads.size(); i++) {
+    delete _quads[i];
+NUM_DEL++;
+DEL_QUAD++;
+  }
+}
+
+template <class E>
+void Recombine2D::_buildEdgeToElement(std::vector<E*> &elements, e2t_cont &adj)
+{
+  for (unsigned int i = 0; i < elements.size(); i++) {
+    E *el = elements[i];
+    for (int j = 0; j < el->getNumEdges(); j++) {
+      MEdge e = el->getEdge(j);
+      e2t_cont::iterator it = adj.find(e);
+      if (it == adj.end()) {
+        std::pair<MElement*, MElement*> one = std::make_pair(el, (MElement*)0);
+        adj[e] = one;
+      }
+      else
+        it->second.second = el;
+    }
+  }
+}
+
+void Recombine2D::_recombine()
+{
+  int i = 0;
+  while ((!_pairs.empty() || !_lastRecomb.empty()) && i < 1000) {
+    Msg::Info("%d",i);
+    Set_Recomb::iterator it = _bestNextRecombination();
+    _benef += (*it)->getBenef();
+    if ((*it)->isQuad())
+      _quads.push_back((*it)->createQuad());
+    else
+      for (int i = 0; i < (*it)->numTriangles(); i++)
+        _isolated.insert((*it)->triangle(i));
+    _removeImpossible(it);
+    i++;
+  }
+  Msg::Info("Done %d (%d)", i, _pairs.size());
+}
+
+Set_Recomb::iterator Recombine2D::_bestNextRecombination()
+{
+  if (!_lastRecomb.empty())
+    return _lastRecomb.begin();
+  
+  int h = 0, nSkip = 0;
+  double maxBenef = _horizon * -200.;
+  
+  
+  Map_Tri_Node touched;
+  std::vector<Node*> nodes(_horizon);
+  Set_Recomb::iterator it = _pairs.begin(), itmax = _pairs.begin();
+  
+  bool end = false;
+  
+  int numb = 0;
+  while (!end) {
+    numb++;
+    while (h < _horizon && it != _pairs.end()) {
+      bool possible = true;
+      
+      Map_Tri_Node::iterator itm;
+      for (int i = 0; i < (*it)->numTriangles(); i++) {
+        itm = touched.find((*it)->triangle(i));
+        if (itm != touched.end()) {
+          itm->second->blocking(itm);
+          possible = false;
+        }
+      }
+        
+      if (possible) {
+        if (h == 0) nodes[h] = new Node(it, touched, nSkip);
+        else        nodes[h] = new Node(it, touched, nSkip, nodes[h-1]->getTotBenef());
+NUM_NEW++;
+NEW_NODE++;
+        h++;
+        nSkip = 0;
+      }
+      else
+        nSkip++;
+      
+      it++;
+    }
+    
+    if (nodes[--h]->getTotBenef() > maxBenef) {
+      maxBenef = nodes[h]->getTotBenef();
+      itmax = nodes[0]->getItRecomb();
+    }
+    
+    /*nSkip = 0;
+    while (h >= 0 && nSkip < 2) {
+      nodes[h]->erase();
+      nSkip += nodes[h--]->getnSkip();
+    
+    if (h == _horizon - 2 && nodes[h]->getnSkip() >= 3) nodes[h--]->erase(); //probleme si h=-1
+    while (h >= 0 &&
+           nodes[h]->beSkipped() &&
+           nodes[h]->getnSkip() >= 2 * (_horizon - h))
+      nodes[h--]->erase();*/
+    delete nodes[h];
+NUM_DEL++;
+DEL_NODE++;
+    while (--h >= 0 &&
+           (nodes[h]->isBetter() ||
+            nodes[h]->getnSkip() >= 2 * (_horizon - h))){
+NUM_DEL++;
+DEL_NODE++;
+      delete nodes[h];
+    }
+    
+    if (h < 0) end = true;
+    else {
+      it = ++nodes[h]->getItRecomb();
+      nSkip = nodes[h]->getnSkip() + 1;
+      delete nodes[h];
+NUM_DEL++;
+DEL_NODE++;
+    }
+  }
+  
+  Msg::Info("num test %d", numb);
+    
+  return itmax;
+}
+
+void Recombine2D::_removeImpossible(Set_Recomb::iterator it)
+{
+  std::vector<MElement *> t;
+  (*it)->triangles(t);
+  
+  Map_Tri_Recomb::iterator itm;
+  std::set<RecombTriangle*>::iterator itrt;
+  
+  for (int i = 0; i < t.size(); i++) {
+    
+    itm = _possibleRecomb.find(t[i]);
+    if (itm == _possibleRecomb.end())
+      Msg::Info("not _possibleRecomb");
+    else {
+      itrt = itm->second.begin();
+      while (itrt != itm->second.end()) { // loop over unusable RecombTriangle
+        if (*itrt != *it)
+          _rmRT(*itrt, t[i]);
+        itrt++;
+      }
+    }
+    _possibleRecomb.erase(itm);
+  }
+  
+  RecombTriangle *rt = *it;
+  if (!_lastRecomb.erase(*it))
+    _pairs.erase(it);
+  delete rt;
+NUM_DEL++;
+DEL_REC++;
+}
+
+void Recombine2D::_rmRT(RecombTriangle *rt, MElement *el)
+{
+  MElement *tri;
+  Map_Tri_Recomb::iterator itmtri;
+  
+  for (int i = 0; i < rt->numTriangles(); i++)
+  if ((tri = rt->triangle(i)) != el) {
+    itmtri = _possibleRecomb.find(tri);
+    if (itmtri == _possibleRecomb.end())
+      Msg::Info("-not _possibleRecomb");
+    else {
+    itmtri->second.erase(rt);
+    switch (itmtri->second.size()) {
+      case 1 :
+        _pairs.erase(*itmtri->second.begin());
+        _lastRecomb.insert(*itmtri->second.begin());
+        break;
+      case 0 :
+        _isolated.insert(tri);
+        _possibleRecomb.erase(itmtri);
+      default :;
+    }
+    }
+  }
+  _pairs.erase(rt);
+  _lastRecomb.erase(rt);
+  delete rt;
+NUM_DEL++;
+DEL_REC++;
+}
+
+int Recombine2D::apply()
+{
+  if (!_haveParam && !_applied) return 0;
+  
+  std::vector<MTriangle*> triangles2;
+  for (int i = 0; i < _gf->triangles.size(); i++) {
+    if (_isolated.find(_gf->triangles[i]) == _isolated.end())
+      delete _gf->triangles[i];
+    else
+      triangles2.push_back(_gf->triangles[i]);
+  }
+  _gf->triangles = triangles2;
+  _gf->quadrangles = _quads;
+  
+  _applied = true;
+  return 1;
+}
+
+RecombTriangle::RecombTriangle(const MEdge &me, MElement *t1, MElement *t2)
+    : _formingQuad(true)
+{
+  _t.push_back(t1);
+  _t.push_back(t2);
+  _n1 = me.getVertex(0);
+  _n2 = me.getVertex(1);
+
+  if(t1->getVertex(0) != _n1 && t1->getVertex(0) != _n2) _n3 = t1->getVertex(0);
+  else if(t1->getVertex(1) != _n1 && t1->getVertex(1) != _n2) _n3 = t1->getVertex(1);
+  else if(t1->getVertex(2) != _n1 && t1->getVertex(2) != _n2) _n3 = t1->getVertex(2);
+  if(t2->getVertex(0) != _n1 && t2->getVertex(0) != _n2) _n4 = t2->getVertex(0);
+  else if(t2->getVertex(1) != _n1 && t2->getVertex(1) != _n2) _n4 = t2->getVertex(1);
+  else if(t2->getVertex(2) != _n1 && t2->getVertex(2) != _n2) _n4 = t2->getVertex(2);
+
+  double a1 = 180 * angle3Vertices(_n1, _n4, _n2) / M_PI;
+  double a2 = 180 * angle3Vertices(_n4, _n2, _n3) / M_PI;
+  double a3 = 180 * angle3Vertices(_n2, _n3, _n1) / M_PI;
+  double a4 = 180 * angle3Vertices(_n3, _n1, _n4) / M_PI;
+  _angle = fabs(90. - a1);
+  _angle = std::max(fabs(90. - a2), _angle);
+  _angle = std::max(fabs(90. - a3), _angle);
+  _angle = std::max(fabs(90. - a4), _angle);
+  
+  _benefit = std::max(1. - _angle/90., .0);
+  //_benefit = compute_alignment(me,t1,t2);
+      
+      //cost_alignment = Temporary::compute_alignment(me,_t1,_t2); //addition for class Temporary
+      //total_cost = Temporary::compute_total_cost(cost_quality,cost_alignment); //addition for class Temporary
+      //total_cost = 100.0*cost_quality; //addition for class Temporary
+}
+
+RecombTriangle::RecombTriangle(MElement *t, double a)
+    : _benefit(a), _formingQuad(false) {
+  _t.push_back(t);
+}
+
+double RecombTriangle::touch()
+{
+  double prec = 1e-10;
+  
+  double a = (double)(rand() - RAND_MAX / 2) / RAND_MAX * prec;
+  _benefit += a;
+  return a;
+}
+
+MQuadrangle *RecombTriangle::createQuad() const
+{
+NUM_NEW++;
+NEW_QUAD++;
+  switch (_t.size()) {
+    case 1 :
+    {
+      Msg::Error("Can't make a quad from only one triangle");
+      return new MQuadrangle(_t[0]->getVertex(0),
+                             _t[0]->getVertex(1),
+                             _t[0]->getVertex(2),
+                             _t[0]->getVertex(0));
+    }
+    case 2 :
+    {
+      int orientation = 0;
+      for (int i = 0; i < 3; i++) {
+        if (_t[0]->getVertex(i) == _n1) {
+          if (_t[0]->getVertex((i + 1) % 3) == _n2)
+            orientation = 1;
+          else
+            orientation = -1;
+          break;
+        }
+      }
+      if (orientation < 0)
+        return new MQuadrangle(_n1, _n3, _n2, _n4);
+      else
+        return new MQuadrangle(_n1, _n4, _n2, _n3);
+    }
+    default :
+    {
+      Msg::Warning("Quad creation not yet implemented for more than two triangles");
+      return new MQuadrangle(_n1, _n2, _n3, _n4);
+    }
+  }
+}
+
+double RecombTriangle::compute_alignment(const MEdge &edge, MElement *e1, MElement* e2)
+{
+  return 1 - Temporary::compute_alignment(edge, e1, e2);
+}
+
+bool RecombTriangle::operator<(const RecombTriangle &other) const
+{
+  return _benefit < other._benefit;
+}
+
+bool lessRecombTri::operator()(RecombTriangle *rt1, RecombTriangle *rt2) const
+{
+  return *rt2 < *rt1;
+}
+
+Node::Node(Set_Recomb::iterator it,
+           Map_Tri_Node &touched,
+           int nskp, double ben) : _nskip(nskp), _recomb(it)
+{
+  _benef = (*it)->getBenef();
+  _totBenef = ben + _benef;
+  for (int i = 0; i < (*it)->numTriangles(); i++)
+    _vit.push_back(touched.insert( touched.begin(), std::make_pair((*it)->triangle(i), this) ));
+  _touch = &touched;
+}
+
+Node::~Node()
+{
+  for (int i = 0; i < _vit.size(); i++)
+    _touch->erase(_vit[i]);
+}
+
+void Node::erase()
+{
+  for (int i = 0; i < _vit.size(); i++)
+    _touch->erase(_vit[i]);
+}
+
+void Node::blocking(const Map_Tri_Node::iterator &it)
+{
+  for (int i = 0; i < _vit.size(); i++) {
+    if (it == _vit[i]) {
+      _blocking.insert(i);
+    }
+  }
+}
+
+//
diff --git a/Mesh/meshRecombine2D.h b/Mesh/meshRecombine2D.h
new file mode 100644
index 0000000000000000000000000000000000000000..dc216e6f79e2225171c7e0e386ca355a8d5953c5
--- /dev/null
+++ b/Mesh/meshRecombine2D.h
@@ -0,0 +1,111 @@
+// 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 (amjohnen@gmail.com)
+//
+
+#ifndef _MESH_RECOMBINE_2D_H_
+#define _MESH_RECOMBINE_2D_H_
+
+#include <map>
+#include <set>
+#include <vector>
+#include "MVertex.h"
+#include "MTriangle.h"
+#include "MQuadrangle.h"
+#include "meshGFaceOptimize.h"
+
+class RecombTriangle;
+class Node;
+struct lessRecombTri {
+  bool operator()(RecombTriangle *rt1, RecombTriangle *rt2) const;
+};
+
+typedef std::set<RecombTriangle*,lessRecombTri> Set_Recomb;
+typedef std::map<MElement*,std::set<RecombTriangle*> > Map_Tri_Recomb;
+typedef std::map<MElement*,Node*> Map_Tri_Node;
+
+class Recombine2D {
+  private :
+    GFace *_gf;
+    int _horizon;
+    double _benef;
+    bool _haveParam, _applied;
+    Set_Recomb _pairs, _lastRecomb;
+    Map_Tri_Recomb _possibleRecomb;
+    std::set<MElement*> _isolated;
+    std::vector<MQuadrangle*> _quads;
+    
+    template <class E>
+    void _buildEdgeToElement(std::vector<E*> &, e2t_cont &);
+    void _recombine();
+    Set_Recomb::iterator _bestNextRecombination();
+    void _removeImpossible(Set_Recomb::iterator);
+    void _rmRT(RecombTriangle *, MElement *);
+    
+  public :
+    Recombine2D(GFace*, int horizon);
+    ~Recombine2D();
+    
+    int apply();
+    double getBenef() const {return _benef;}
+    int numTriangle() const {return _isolated.size();}
+};
+
+class RecombTriangle {
+  private :
+    std::vector<MElement *> _t;
+    MVertex *_n1, *_n2, *_n3, *_n4;
+    double _angle;
+    double _benefit;
+    bool _formingQuad;
+    
+  public :
+    RecombTriangle(const MEdge &, MElement *, MElement *);
+    RecombTriangle(MElement *, double);
+    
+    double touch();
+    
+    MQuadrangle *createQuad() const;
+    bool operator<(const RecombTriangle &other) const;
+    
+    void triangles(std::vector<MElement *> &v) const {v = _t;}
+    int numTriangles() const {return (int) _t.size();}
+    MElement *triangle(int i) const {
+      if (i >= 0 && i < _t.size())
+	return _t[i];
+      return NULL;
+    }
+    bool isQuad() const {return _formingQuad;}
+    double getBenef() const {return _benefit;}
+    
+    double compute_alignment(const MEdge&, MElement*, MElement*);
+};
+
+class Node {
+  private :  
+    double _benef, _totBenef;
+    int _nskip;
+    Set_Recomb::iterator _recomb;
+    Map_Tri_Node *_touch;
+    std::vector<Map_Tri_Node::iterator> _vit;
+    std::set<int> _blocking;
+  
+  public :
+    //Node(){}
+    Node(Set_Recomb::iterator, Map_Tri_Node &, int, double ben = .0);
+    ~Node();
+    
+    void erase();
+    void blocking(const Map_Tri_Node::iterator &);
+    bool isBetter() {return _blocking.size() < 2;}
+    Set_Recomb::iterator getItRecomb() {return _recomb;}
+    double getTotBenef() {return _totBenef;}
+    double getnSkip() {return _nskip;}
+};
+
+
+#endif