From 8c73c5cc7ddffacc03aacec9286fbfba1f0ccb27 Mon Sep 17 00:00:00 2001
From: Amaury Johnan <amjohnen@gmail.com>
Date: Wed, 14 Mar 2012 10:38:50 +0000
Subject: [PATCH] added new strategies + correction of bugs computation reward

---
 Mesh/meshGFaceRecombine.cpp | 455 +++++++++++++++++++++++++++++-------
 Mesh/meshGFaceRecombine.h   |  34 ++-
 2 files changed, 403 insertions(+), 86 deletions(-)

diff --git a/Mesh/meshGFaceRecombine.cpp b/Mesh/meshGFaceRecombine.cpp
index 615f7b97cb..5a11b9594a 100644
--- a/Mesh/meshGFaceRecombine.cpp
+++ b/Mesh/meshGFaceRecombine.cpp
@@ -7,7 +7,7 @@
 //   Amaury Johnen (a.johnen@ulg.ac.be)
 //
 
-#define REC2D_WAIT_TIME .01
+#define REC2D_WAIT_TIME .05
 #define REC2D_NUM_ACTIO 1000
 
 // #define REC2D_SMOOTH
@@ -154,6 +154,7 @@ Recombine2D::Recombine2D(GFace *gf) : _gf(gf), _strategy(0), _numChange(0)
       double angle = _geomAngle(it->first,
                                 it->second._gEdges,
                                 it->second._mElements);
+      Msg::Info("ang %g", angle);
       new Rec2DVertex(it->second._rv, angle);
     }
   }
@@ -258,18 +259,67 @@ bool Recombine2D::recombine()
 
 double Recombine2D::recombine(int depth)
 {
+  Rec2DData::checkAngle();
+  //return .0;
   Rec2DData::clearChanges();
   double bestGlobalQuality;
-  Rec2DNode *root = new Rec2DNode(NULL, NULL, bestGlobalQuality, depth);
+  _data->sortActions();
+  _data->printActions();
+  _numChange++;
+  _data->printActions();
+  //Rec2DNode *root = new Rec2DNode(NULL, NULL, bestGlobalQuality, depth);
+  //_data->printActions();
+  
+  /*Rec2DNode *root = new Rec2DNode(NULL, NULL, bestGlobalQuality, depth);
   Rec2DNode *currentNode = root->selectBestNode();
   
-  while (currentNode) {
+  double time = Cpu();
+  //int num = 20, i = 0;
+  //double dx = .0, dy = .0;
+  
+  int k = 0;
+  while (currentNode && ++k < 90) {
+    _data->printActions();
+    FlGui::instance()->check();
+#if 0 //def REC2D_DRAW // draw state at origin
+    //_gf->triangles = _data->_tri;
+    //_gf->quadrangles = _data->_quad;
+    CTX::instance()->mesh.changed = ENT_ALL;
+    drawContext::global()->draw();
+    while (Cpu()-time < REC2D_WAIT_TIME)
+      FlGui::instance()->check();
+    time = Cpu();
+#endif
+//#ifdef REC2D_DRAW
+//    if ( !((i+1) % ((int)std::sqrt(num)+1)) ) {
+//      dx = .0;
+//      dy -= 1.1;
+//    }
+//    else
+//      dx += 1.1;
+//    drawState(dx, dy);
+//    CTX::instance()->mesh.changed = ENT_ALL;
+//    drawContext::global()->draw();
+//    while (Cpu()-time < REC2D_WAIT_TIME)
+//      FlGui::instance()->check();
+//    ++i;
+//    time = Cpu();
+//#endif
     currentNode->develop(depth, bestGlobalQuality);
     currentNode = currentNode->selectBestNode();
   }
   
   return Rec2DData::getGlobalQuality();
-  //_data->printState();
+  //_data->printState();*/
+}
+
+void Recombine2D::clearChanges()
+{
+  Rec2DData::clearChanges();
+#ifdef REC2D_DRAW
+    CTX::instance()->mesh.changed = ENT_ALL;
+    drawContext::global()->draw();
+#endif
 }
 
 bool Recombine2D::developTree()
@@ -289,31 +339,62 @@ bool Recombine2D::developTree()
 void Recombine2D::nextTreeActions(std::vector<Rec2DAction*> &actions,
                                   std::vector<Rec2DElement*> &neighbourEl)
 {
+  std::vector<Rec2DElement*> elements;
   actions.clear();
   Rec2DAction *ra = NULL;
   Rec2DElement *rel = NULL;
   switch (_current->_strategy) {
     case 0 : // random triangle of random action
-      //ra = Rec2DData::getRandomAction();
-      //rel = ra->getRandomTriangle();
-      //break;
+      ra = Rec2DData::getRandomAction();
+      if (!ra) return;
+      rel = ra->getRandomElement();
+      break;
       
-    case 1 : // random triangle of best action
-      //ra = Rec2DData::getBestAction();
-      //rel = ra->getRandomTriangle();
-      //break;
+    default :
+    case 3 : // triangle of best neighbour action
+      for (unsigned int i = 0; i < neighbourEl.size(); ++i) {
+        neighbourEl[i]->getUniqueActions(actions);
+      }
+      std::sort(actions.begin(), actions.end(), gterRec2DAction());
+      if (actions.size()) {
+        actions[0]->getElements(elements);
+        for (unsigned int i = 0; i < elements.size(); ++i) {
+          for (unsigned int j = 0; j < neighbourEl.size(); ++j) {
+            if (elements[i] == neighbourEl[j]) {
+              rel = elements[i];
+              goto end;
+            }
+          }
+        }
+      }
+      end :
+      if (rel) break;
       
     case 2 : // random neighbour triangle
+      if (neighbourEl.size()) {
+        rel = neighbourEl[rand() % (int)neighbourEl.size()];
+        break;
+      }
       
-      
-    case 3 : // triangle of best neighbour action
-    default :
+    case 1 : // random triangle of best action
       ra = Rec2DData::getBestAction();
       if (!ra) return;
       rel = ra->getRandomElement();
       break;
   }
   rel->getActions(actions);
+  unsigned int i = 0;
+  while (i < actions.size()) {
+    if (actions[i]->isObsolete()) {
+#ifdef REC2D_DRAW
+      //actions[i]->color(190, 0, 0);
+#endif
+      actions[i] = actions.back();
+      actions.pop_back();
+    }
+    else
+      ++i;
+  }
 }
 
 void Recombine2D::drawState(double shiftx, double shifty)
@@ -351,7 +432,7 @@ double Recombine2D::_geomAngle(MVertex *v,
     vectub -= vectv;
     double normlb, normub;
     if ((normlb = norm(vectlb)) > prec * (normub = norm(vectub)))
-      firstDer1 = -1 * ge->firstDer(ge->getUpperBound());
+      firstDer1 = -1. * ge->firstDer(ge->getUpperBound());
     else if (normub > prec * normlb)
       firstDer1 = ge->firstDer(ge->getLowerBound());
     else {
@@ -362,8 +443,8 @@ double Recombine2D::_geomAngle(MVertex *v,
       firstDer0 = firstDer1;
   }
   
-  firstDer0 = firstDer0 * (1 / norm(firstDer0));
-  firstDer1 = firstDer1 * (1 / norm(firstDer1));
+  firstDer0 = firstDer0 * (1. / norm(firstDer0));
+  firstDer1 = firstDer1 * (1. / norm(firstDer1));
   
   double angle1 = acos(dot(firstDer0, firstDer1));
   double angle2 = 2. * M_PI - angle1;
@@ -522,6 +603,18 @@ bool Recombine2D::_remainAllQuad(std::set<Rec2DElement*> &elem)
   return true;
 }
 
+void Recombine2D::add(MQuadrangle *q)
+{
+  _current->_gf->quadrangles.push_back(q);
+  _current->_data->_quad.push_back(q);
+}
+
+void Recombine2D::add(MTriangle *t)
+{
+  _current->_gf->triangles.push_back(t);
+  _current->_data->_tri.push_back(t);
+}
+
 
 /**  Rec2DData  **/
 /*****************/
@@ -651,8 +744,8 @@ void Rec2DData::printState()
   Msg::Info(" ");
   Msg::Info("State");
   Msg::Info("-----");
-  Msg::Info("numEdge %d (%d), valEdge %g => %g", _numEdge, _edges.size(), (double)_valEdge, (double)_valEdge/_numEdge);
-  Msg::Info("numVert %d (%d), valVert %g => %g", _numVert, _vertices.size(), (double)_valVert, (double)_valVert/_numVert);
+  Msg::Info("numEdge %d (%d), valEdge %g => %g", _numEdge, _edges.size(), (double)_valEdge, (double)_valEdge/(double)_numEdge);
+  Msg::Info("numVert %d (%d), valVert %g => %g", _numVert, _vertices.size(), (double)_valVert, (double)_valVert/(double)_numVert);
   Msg::Info("Element (%d)", _elements.size());
   Msg::Info("global Value %g", Rec2DData::getGlobalQuality());
   Msg::Info("num action %d", _actions.size());
@@ -679,13 +772,33 @@ void Rec2DData::printState()
 
 void Rec2DData::printActions()
 {
-  Recombine2D::incNumChange();
-  _actions.sort(lessRec2DAction());
+  std::map<int, std::vector<double> > data;
   std::list<Rec2DAction*>::iterator it = _actions.begin();
   for (; it != _actions.end(); ++it) {
-    Msg::Info("action %d -> reward %g", *it, (*it)->getReward());
-  }
+    std::vector<Rec2DElement*> tri;
+    (*it)->getElements(tri);
+    Msg::Info("action %d (%d, %d) -> reward %g", *it, tri[0]->getNum(), tri[1]->getNum(), (*it)->getReward());
+      //Msg::Info("action %d -> reward %g", *it, (*it)->getReward());
+    data[tri[0]->getNum()].resize(1);
+    data[tri[1]->getNum()].resize(1);
+    data[tri[0]->getNum()][0] = (*it)->getReward();
+    data[tri[1]->getNum()][0] = (*it)->getReward();
+  }
+  new PView("Jmin_bad", "ElementData", Recombine2D::getGFace()->model(), data);
   Msg::Info(" ");
+  _actions.front()->print();
+  it = _actions.end();
+  (*(--it))->print();
+  (*(--it))->print();
+  (*(--it))->print();
+}
+
+void Rec2DData::checkAngle()
+{
+  iter_rel it = firstElement();
+  for (; it != lastElement(); ++it) {
+    (*it)->printAngles();
+  }
 }
 
 int Rec2DData::getNewParity()
@@ -746,9 +859,11 @@ void Rec2DData::removeParity(Rec2DVertex *rv, int p)
   }
   if (!b)
     Msg::Error("[Rec2DData] No vertex 1");
+  else if (vect->empty())
+    _current->_parities.erase(it);
 }
 
-void Rec2DData::associateParity(int pOld, int pNew)
+void Rec2DData::associateParity(int pOld, int pNew, Rec2DDataChange *rdc)
 {
   if (pOld/2 == pNew/2) {
     Msg::Error("[Rec2DData] Do you want to make a mess of parities ?");
@@ -760,18 +875,20 @@ void Rec2DData::associateParity(int pOld, int pNew)
     if (++a == 10)
       Msg::Warning("[Rec2DData] AND LOOK AT ME WHEN I TALK TO YOU !");
   }
+  
   std::map<int, std::vector<Rec2DVertex*> >::iterator it;
   std::vector<Rec2DVertex*> *vect, *vectNew;
-  
   {
     it = _current->_parities.find(pOld);
     if (it == _current->_parities.end()) {
       static int a = -1;
-      if (++a == 0)
+      if (++a < 1)
         Msg::Error("[Rec2DData] You are mistaken, I'll never talk to you again !");
       return;
     }
     vect = &it->second;
+    if (rdc)
+      rdc->saveParity(*vect);
     for (unsigned int i = 0; i < vect->size(); ++i)
       vect->at(i)->setParityWD(pOld, pNew);
     vectNew = &_current->_parities[pNew];
@@ -788,6 +905,8 @@ void Rec2DData::associateParity(int pOld, int pNew)
       return;
     }
     vect = &it->second;
+    if (rdc)
+      rdc->saveParity(*vect);
     for (unsigned int i = 0; i < vect->size(); ++i)
       vect->at(i)->setParityWD(pOld, pNew);
     vectNew = &_current->_parities[pNew];
@@ -910,15 +1029,15 @@ void Rec2DData::revertAssumedParities()
 
 double Rec2DData::getGlobalQuality()
 {
-  double a = (_current->_valVert) / (_current->_numVert);
-  return a * (_current->_valEdge) / (_current->_numEdge);
+  double a = (double)_current->_valVert / (double)_current->_numVert;
+  return a * a * (double)_current->_valEdge / (double)_current->_numEdge;
 }
 
 double Rec2DData::getGlobalQuality(int numEdge, double valEdge,
-                                   int numVert, double valVert)
+                                   int numVert, double valVert )
 {
-  double a = (_current->_valVert + valVert) / (_current->_numVert + numVert);
-  return a * (_current->_valEdge + valEdge) / (_current->_numEdge + numEdge);
+  double a = ((double)_current->_valVert + valVert) / (double)(_current->_numVert + numVert);
+  return a * a * ((double)_current->_valEdge + valEdge) / (double)(_current->_numEdge + numEdge);
 }
 
 Rec2DAction* Rec2DData::getBestAction()
@@ -928,6 +1047,17 @@ Rec2DAction* Rec2DData::getBestAction()
   return *std::max_element(_current->_actions.begin(),
                            _current->_actions.end(), lessRec2DAction());
 }
+Rec2DAction* Rec2DData::getRandomAction()
+{
+  if (_current->_actions.size() == 0)
+    return NULL;
+  int index = rand() % (int)_current->_actions.size();
+  std::list<Rec2DAction*>::iterator it = _current->_actions.begin();
+  static int a = -1;
+  if (++a < 1) Msg::Warning("FIXME what type is size of list ?");
+  for (int i = 0; i < index; ++i) ++it;
+  return *it;
+}
 void Rec2DData::drawTriangles(double shiftx, double shifty)
 {
   iter_rel it = firstElement();
@@ -1000,13 +1130,61 @@ void Rec2DDataChange::hide(std::vector<Rec2DAction*> actions)
   }
 }
 
+void Rec2DDataChange::hide(Rec2DAction *action)
+{
+  _hiddenAction.push_back(action);
+  action->hide();
+}
+
 void Rec2DDataChange::append(Rec2DElement *rel)
 {
   _newElement.push_back(rel);
 }
 
+void Rec2DDataChange::changeParity(Rec2DVertex *rv, int par)
+{
+  for (unsigned int i = 0; i < _oldParity.size(); ++i) {
+    if (_oldParity[i].first == rv)
+      return;
+  }
+  _oldParity.push_back(std::make_pair(rv, rv->getParity()));
+  rv->setParity(par);
+}
+
+void Rec2DDataChange::saveParity(std::vector<Rec2DVertex*> &vect)
+{
+  int sizeOldParity = _oldParity.size();
+  for (unsigned int i = 0; i < vect.size(); ++i) {
+    bool notThere = true;
+    for (unsigned int j = 0; j < sizeOldParity; ++j) {
+      if (_oldParity[j].first == vect[i])
+        notThere = false;
+    }
+    if (notThere) {
+      _oldParity.push_back(std::make_pair(vect[i], vect[i]->getParity()));
+    }
+  }
+}
+
+void Rec2DDataChange::checkObsoleteActions()
+{
+  std::vector<Rec2DAction*> actions;
+  for (unsigned int i = 0; i < _oldParity.size(); ++i) {
+    _oldParity[i].first->getUniqueActions(actions);
+  }
+  for (unsigned int i = 0; i < actions.size(); ++i) {
+    if (actions[i]->isObsolete())
+      hide(actions[i]);
+  }
+}
+
 void Rec2DDataChange::revert()
 {
+  for (unsigned int i = 0; i < _oldParity.size(); ++i)
+    _oldParity[i].first->setParity(_oldParity[i].second);
+  //for (unsigned int i = 0; i < _oldCoordinate.size(); ++i)
+  //  _oldCoordinate[i].first->relocate(_oldCoordinate[i].second);
+  
   for (unsigned int i = 0; i < _newAction.size(); ++i)
     delete _newAction[i];
   for (unsigned int i = 0; i < _newElement.size(); ++i)
@@ -1024,6 +1202,8 @@ void Rec2DDataChange::revert()
     _hiddenElement[i]->reveal();
   for (unsigned int i = 0; i < _hiddenAction.size(); ++i)
     _hiddenAction[i]->reveal();
+  _oldParity.clear();
+  _oldCoordinate.clear();
   _newEdge.clear();
   _newVertex.clear();
   _newAction.clear();
@@ -1048,13 +1228,13 @@ bool gterRec2DAction::operator()(Rec2DAction *ra1, Rec2DAction *ra2) const
 }
 
 Rec2DAction::Rec2DAction()
-: _lastUpdate(Recombine2D::getNumChange()-1), _globQualIfExecuted(.0), _globQualIfExecuted2(.0), _globQualIfExecuted3(.0)
+: _lastUpdate(Recombine2D::getNumChange()-1), _globQualIfExecuted(.0)
 {
+  static int num = 0;
 }
 
 bool Rec2DAction::operator<(Rec2DAction &other)
 {
-  //return doub < other.getReward();
   return getReward() < other.getReward();
 }
 
@@ -1131,14 +1311,12 @@ void Rec2DTwoTri2Quad::reveal()
 
 void Rec2DTwoTri2Quad::_computeGlobQual()
 {
-  static const Rec2DAction *ra = this;
-  
-  double valEdge = -REC2D_EDGE_BASE * _edges[4]->getQual();
+  double valEdge = -(double)REC2D_EDGE_BASE * _edges[4]->getQual();
   for (int i = 0; i < 4; ++i)
-    valEdge += REC2D_EDGE_QUAD * _edges[i]->getQual();
+    valEdge += (double)REC2D_EDGE_QUAD * _edges[i]->getQual();
   
   double valVert;
-  valVert += _vertices[0]->getGainMerge(_triangles[0], _triangles[1]);
+  valVert = _vertices[0]->getGainMerge(_triangles[0], _triangles[1]);
   valVert += _vertices[1]->getGainMerge(_triangles[0], _triangles[1]);
   
   _globQualIfExecuted =
@@ -1146,9 +1324,6 @@ void Rec2DTwoTri2Quad::_computeGlobQual()
                                 valEdge, 0, valVert                 );
   
   _lastUpdate = Recombine2D::getNumChange();
-  if (ra == this) { 
- 	  Msg::Info("       %d %g %g", 4*REC2D_EDGE_QUAD - REC2D_EDGE_BASE, valEdge, valVert); 
- 	}
 }
 
 void Rec2DTwoTri2Quad::color(int a, int b, int c)
@@ -1219,7 +1394,15 @@ void Rec2DTwoTri2Quad::apply(std::vector<Rec2DVertex*> &newPar)
 
 void Rec2DTwoTri2Quad::apply(Rec2DDataChange *rdc)
 {
+  if (isObsolete()) {
+    Msg::Error("[Rec2DTwoTri2Quad] I was obsolete !");
+  }
+  else {
+    _doWhatYouHaveToDoWithParity(rdc);
+  }
+#ifdef REC2D_DRAW
   rdc->setAction(this);
+#endif
   std::vector<Rec2DAction*> actions;
   _triangles[0]->getUniqueActions(actions);
   _triangles[1]->getUniqueActions(actions);
@@ -1228,10 +1411,42 @@ void Rec2DTwoTri2Quad::apply(Rec2DDataChange *rdc)
   rdc->hide(_triangles[1]);
   rdc->hide(_edges[4]);
   rdc->append(new Rec2DElement((MQuadrangle*)NULL, _edges));
-  
   Recombine2D::incNumChange();
 }
 
+void Rec2DTwoTri2Quad::_doWhatYouHaveToDoWithParity(Rec2DDataChange *rdc)
+{
+  int parMin = Rec2DData::getNewParity(), index = -1;
+  for (int i = 0; i < 4; ++i) {
+    if (_vertices[i]->getParity() && parMin > _vertices[i]->getParity()) {
+      parMin = _vertices[i]->getParity();
+      index = i;
+    }
+  }
+  if (index == -1) {
+    rdc->changeParity(_vertices[0], parMin);
+    rdc->changeParity(_vertices[1], parMin);
+    rdc->changeParity(_vertices[2], parMin+1);
+    rdc->changeParity(_vertices[3], parMin+1);
+  }
+  else {
+    for (int i = 0; i < 4; i += 2) {
+      int par;
+      if ((index/2) * 2 == i)
+        par = parMin;
+      else
+        par = otherParity(parMin);
+      for (int j = 0; j < 2; ++j) {
+        if (!_vertices[i+j]->getParity())
+          rdc->changeParity(_vertices[i+j], par);
+        else if (_vertices[i+j]->getParity() != par)
+          Rec2DData::associateParity(_vertices[i+j]->getParity(), par, rdc);
+      }
+    }
+    rdc->checkObsoleteActions();
+  }
+}
+
 bool Rec2DTwoTri2Quad::isObsolete()
 {
   int p[4];
@@ -1356,6 +1571,21 @@ int Rec2DTwoTri2Quad::getNum(double shiftx, double shifty)
   return quad->getNum();
 }
 
+void Rec2DTwoTri2Quad::print()
+{
+  Msg::Info("Printing Action %d (%d,%d)...", this, _triangles[0]->getNum(), _triangles[1]->getNum());
+  Msg::Info("edge0 %g", _edges[0]->getQual());
+  Msg::Info("edge1 %g", _edges[1]->getQual());
+  Msg::Info("edge2 %g", _edges[2]->getQual());
+  Msg::Info("edge3 %g", _edges[3]->getQual());
+  Msg::Info("edge4 %g", _edges[4]->getQual());
+  Msg::Info("angles %g - %g", _vertices[0]->getAngle(), _vertices[1]->getAngle());
+  Msg::Info("merge0 %g", _vertices[0]->getGainMerge(_triangles[0], _triangles[1]));
+  Msg::Info("merge1 %g", _vertices[1]->getGainMerge(_triangles[0], _triangles[1]));
+  _vertices[0]->printGainMerge(_triangles[0], _triangles[1]);
+  _vertices[1]->printGainMerge(_triangles[0], _triangles[1]);
+}
+
 void Rec2DTwoTri2Quad::printCoord()
 {
   Msg::Info("(%g %g) (%g %g) (%g %g) (%g %g) %d %d", _vertices[0]->u(),
@@ -1407,8 +1637,8 @@ void Rec2DEdge::_computeQual() //*
   double adimLength = _straightAdimLength();
   double alignment = _straightAlignment();
   if (adimLength > 1)
-    adimLength = 1/adimLength;
-  _qual = adimLength * ((1-REC2D_ALIGNMENT) + REC2D_ALIGNMENT * alignment);
+    adimLength = 1./adimLength;
+  _qual = adimLength * ((double)(1-REC2D_ALIGNMENT) + (double)REC2D_ALIGNMENT * alignment);
   _lastUpdate = Recombine2D::getNumChange();
 }
 
@@ -1430,7 +1660,7 @@ double Rec2DEdge::getWeightedQual()
        _rv1->getLastMove() > _lastUpdate   )      ) {
     _computeQual(); 
   }
-  return _weight * _qual;
+  return (double)_weight * _qual;
 }
 
 void Rec2DEdge::_addWeight(int w)
@@ -1442,7 +1672,7 @@ void Rec2DEdge::_addWeight(int w)
   if (_weight < REC2D_EDGE_BASE)
     Msg::Error("[Rec2DEdge] Weight too low : %d (%d min)",
                _weight, REC2D_EDGE_BASE                   );
-  Rec2DData::addEdge(w, w*getQual());
+  Rec2DData::addEdge(w, (double)w*getQual());
 }
 
 Rec2DElement* Rec2DEdge::getUniqueElement(Rec2DEdge *re)
@@ -1484,7 +1714,7 @@ double Rec2DEdge::_straightAdimLength() const
   double lc0 = (*Recombine2D::bgm())(_rv0->u(), _rv0->v(), .0);
   double lc1 = (*Recombine2D::bgm())(_rv1->u(), _rv1->v(), .0);
   
-  return length * (1/lc0 + 1/lc1) / 2;
+  return length * (1./lc0 + 1./lc1) / 2.;
 }
 
 double Rec2DEdge::_straightAlignment() const
@@ -1497,13 +1727,13 @@ double Rec2DEdge::_straightAlignment() const
   double alpha1 = angleEdge - angle1;
   crossField2d::normalizeAngle(alpha0);
   crossField2d::normalizeAngle(alpha1);
-  alpha0 = 1 - 4 * std::min(alpha0, .5 * M_PI - alpha0) / M_PI;
-  alpha1 = 1 - 4 * std::min(alpha1, .5 * M_PI - alpha1) / M_PI;
+  alpha0 = 1. - 4. * std::min(alpha0, .5 * M_PI - alpha0) / M_PI;
+  alpha1 = 1. - 4. * std::min(alpha1, .5 * M_PI - alpha1) / M_PI;
   
   double lc0 = (*Recombine2D::bgm())(_rv0->u(), _rv0->v(), .0);
   double lc1 = (*Recombine2D::bgm())(_rv1->u(), _rv1->v(), .0);
   
-  return (alpha0/lc0 + alpha1/lc1) / (1/lc0 + 1/lc1);
+  return (alpha0/lc0 + alpha1/lc1) / (1./lc0 + 1./lc1);
 }
 
 Rec2DVertex* Rec2DEdge::getOtherVertex(Rec2DVertex *rv) const
@@ -1520,7 +1750,7 @@ Rec2DVertex* Rec2DEdge::getOtherVertex(Rec2DVertex *rv) const
 /**  Rec2DVertex  **/
 /*******************/
 Rec2DVertex::Rec2DVertex(MVertex *v)
-: _v(v), _angle(4*M_PI), _onWhat(1), _parity(0), _assumedParity(0),
+: _v(v), _angle(4.*M_PI), _onWhat(1), _parity(0), _assumedParity(0),
   _lastMove(Recombine2D::getNumChange()), _sumQualAngle(.0)
 {
   reparamMeshVertexOnFace(_v, Recombine2D::getGFace(), _param);
@@ -1535,7 +1765,7 @@ Rec2DVertex::Rec2DVertex(Rec2DVertex *rv, double ang)
 : _v(rv->_v), _angle(ang), _onWhat(-1), _parity(rv->_parity),
   _assumedParity(rv->_assumedParity), _lastMove(rv->_lastMove),
   _sumQualAngle(rv->_sumQualAngle), _edges(rv->_edges),
-  _elements(rv->_elements), _param(_param)
+  _elements(rv->_elements), _param(rv->_param)
 {
   static int a = -1;
   if (++a < -1) Msg::Warning("FIXME Edges really necessary ?");
@@ -1544,7 +1774,7 @@ Rec2DVertex::Rec2DVertex(Rec2DVertex *rv, double ang)
     _edges[i]->swap(rv, this);
   }
   Rec2DData::add(this);
-  if (!_elements.empty())
+  if (_elements.size())
     Rec2DData::addVert(2, getQual());
   delete rv;
 #ifdef REC2D_DRAW
@@ -1561,7 +1791,7 @@ void Rec2DVertex::hide()
     Rec2DData::removeAssumedParity(this, _assumedParity);
   
   Rec2DData::remove(this);
-  if  (!_elements.empty())
+  if  (_elements.size())
     Rec2DData::addVert(-2, -getQual());
 }
 
@@ -1573,7 +1803,7 @@ void Rec2DVertex::reveal()
     Rec2DData::addAssumedParity(this, _assumedParity);
   
   Rec2DData::add(this);
-  if  (!_elements.empty())
+  if  (_elements.size())
     Rec2DData::addVert(2, getQual());
 }
 
@@ -1590,9 +1820,9 @@ void Rec2DVertex::initStaticTable()
     _qualVSnum[0][0] = -10.;
     _qualVSnum[1][0] = -10.;
     for (int i = 1; i < nE; ++i)
-      _qualVSnum[0][i] = 1. - fabs(2./i - 1.);
+      _qualVSnum[0][i] = 1. - fabs(2./(double)i - 1.);
     for (int i = 1; i < nF; ++i)
-      _qualVSnum[1][i] = 1. - fabs(4./i - 1.);
+      _qualVSnum[1][i] = 1. - fabs(4./(double)i - 1.);
       
     _gains = new double*[2];
     _gains[0] = new double[nE-1];
@@ -1684,7 +1914,7 @@ void Rec2DVertex::setOnBoundary()
 void Rec2DVertex::setParity(int p, bool tree)
 {
   if (_parity && !tree) {
-    Msg::Warning("[Rec2DVertex] I don't like to do it. Think about that !");
+    //Msg::Warning("[Rec2DVertex] I don't like to do it. Think about that !");
     Rec2DData::removeParity(this, _parity);
   }
   _parity = p;
@@ -1692,9 +1922,12 @@ void Rec2DVertex::setParity(int p, bool tree)
     Rec2DData::removeAssumedParity(this, _assumedParity);
     _assumedParity = 0;
   }
-  Rec2DData::addParity(this, _parity);
+  if (_parity)
+    Rec2DData::addParity(this, _parity);
+#ifdef REC2D_DRAW
   if (_v)
     _v->setIndex(_parity);
+#endif
 }
 
 void Rec2DVertex::setParityWD(int pOld, int pNew)
@@ -1709,8 +1942,10 @@ void Rec2DVertex::setParityWD(int pOld, int pNew)
     Rec2DData::removeAssumedParity(this, _assumedParity);
     _assumedParity = 0;
   }
+#ifdef REC2D_DRAW
   if (_v)
     _v->setIndex(_parity);
+#endif
 }
 
 int Rec2DVertex::getAssumedParity() const
@@ -1737,8 +1972,10 @@ bool Rec2DVertex::setAssumedParity(int p)
   }
   _assumedParity = p;
   Rec2DData::addAssumedParity(this, _assumedParity);
+#ifdef REC2D_DRAW
   if (_v)
     _v->setIndex(_assumedParity);
+#endif
   return true;
 }
 
@@ -1787,7 +2024,7 @@ double Rec2DVertex::getQualDegree(int numEl) const
     Msg::Error("[Rec2DVertex] I don't want this anymore !");
     return -10.;
   }
-  return 1. - fabs(2./M_PI * _angle/nEl - 1.);
+  return 1. - fabs(2./M_PI * _angle/(double)nEl - 1.);
 }
 
 double Rec2DVertex::getGainDegree(int n) const
@@ -1814,29 +2051,46 @@ double Rec2DVertex::getGainDegree(int n) const
   
   if (_elements.size() == 0) {
     Msg::Error("[Rec2DVertex] I don't want this anymore !");
-    return 11 - fabs(2./M_PI * _angle/(_elements.size() + n) - 1.);
+    return 11. - fabs(2./M_PI * _angle/(double)(_elements.size() + n) - 1.);
   }
   
   if (_elements.size() + n == 0) {
     Msg::Error("[Rec2DVertex] I don't want this anymore !");
-    return fabs(2./M_PI * _angle/_elements.size() - 1.) - 11;
+    return fabs(2./M_PI * _angle/(double)_elements.size() - 1.) - 11.;
   }
   
-  return fabs(2./M_PI * _angle/_elements.size() - 1.)
-         - fabs(2./M_PI * _angle/(_elements.size() + n) - 1.);
+  return fabs(2./M_PI * _angle/(double)_elements.size() - 1.)
+         - fabs(2./M_PI * _angle/(double)(_elements.size() + n) - 1.);
 }
 
 double Rec2DVertex::getGainMerge(Rec2DElement *rel1, Rec2DElement *rel2)
 {
   double qualAngle = _sumQualAngle;
-  qualAngle += _angle2Qual(rel1->getAngle(this) + rel2->getAngle(this));
   qualAngle -= _angle2Qual(rel1->getAngle(this));
   qualAngle -= _angle2Qual(rel2->getAngle(this));
+  qualAngle += _angle2Qual(rel1->getAngle(this) + rel2->getAngle(this));
   
-  return qualAngle / (_elements.size()-1) - getQualAngle();
+  return qualAngle / (double)(_elements.size()-1) - getQualAngle()
          + getGainDegree(-1);
 }
 
+void Rec2DVertex::printGainMerge(Rec2DElement *rel1, Rec2DElement *rel2)
+{
+  double qualAngle = _sumQualAngle;
+  Msg::Info("qualAngle %g", getQualAngle());
+  Msg::Info("sumAngle %g", qualAngle);
+  Msg::Info("- %g (ang %g)", _angle2Qual(rel1->getAngle(this)), rel1->getAngle(this));
+  Msg::Info("- %g (ang %g)", _angle2Qual(rel2->getAngle(this)), rel2->getAngle(this));
+  Msg::Info("+ %g (ang %g)", _angle2Qual(rel1->getAngle(this) + rel2->getAngle(this)), rel1->getAngle(this) + rel2->getAngle(this));
+  qualAngle -= _angle2Qual(rel1->getAngle(this));
+  qualAngle -= _angle2Qual(rel2->getAngle(this));
+  qualAngle += _angle2Qual(rel1->getAngle(this) + rel2->getAngle(this));
+  Msg::Info("= %g", qualAngle);
+  Msg::Info("gainDegree %g", getGainDegree(-1));
+  Msg::Info("return %g", qualAngle / (double)(_elements.size()-1) - getQualAngle()
+         + getGainDegree(-1));
+}
+
 void Rec2DVertex::add(Rec2DEdge *re)
 {
   for (unsigned int i = 0; i < _edges.size(); ++i) {
@@ -1879,7 +2133,7 @@ void Rec2DVertex::add(Rec2DElement *rel)
       return;
     }
   }
-  if (!_elements.empty())
+  if (_elements.size())
     Rec2DData::addVert(-2, -getQual());
   
   _elements.push_back(rel);
@@ -1906,7 +2160,7 @@ void Rec2DVertex::rmv(Rec2DElement *rel)
       _elements[i] = _elements.back();
       _elements.pop_back();
       
-      if (!_elements.empty())
+      if (_elements.size())
         Rec2DData::addVert(2, getQual());
       return;
     }
@@ -1915,6 +2169,24 @@ void Rec2DVertex::rmv(Rec2DElement *rel)
   Msg::Error("[Rec2DVertex] Didn't removed element, didn't have it");
 }
 
+void Rec2DVertex::getUniqueActions(std::vector<Rec2DAction*> &actions) const
+{
+  std::vector<Rec2DAction*> actions2;
+  for (unsigned int i = 0; i < _elements.size(); ++i) {
+    _elements[i]->getUniqueActions(actions2);
+  }
+  unsigned int size = actions.size();
+  for (unsigned int i = 0; i < actions2.size(); ++i) {
+    bool notThere = true;
+    for (unsigned int j = 0; j < size; ++j) {
+      if (actions2[i] == actions[j])
+        notThere = false;
+    }
+    if (notThere)
+      actions.push_back(actions2[i]);
+  }
+}
+
 
 /**  Rec2DElement  **/
 /********************/
@@ -2104,8 +2376,8 @@ double Rec2DElement::getAngle(Rec2DVertex *rv)
 {
   std::vector<Rec2DVertex*> vert;
   getVertices(vert);
-  int index = -1;
   
+  int index = -1;
   for (int i = 0; i < _numEdge; ++i) {
     if (vert[i] == rv) {
       index = i;
@@ -2116,19 +2388,33 @@ double Rec2DElement::getAngle(Rec2DVertex *rv)
     Msg::Error("[Rec2DElement] I don't have your vertex...");
     return -1.;
   }
-  int i0 = (index+_numEdge-1)%_numEdge;
-  int i2 = (index+1)%_numEdge;
-  double ang =  atan2(vert[i2]->v() - rv->v(), vert[i2]->u() - rv->u())
-                - atan2(vert[i0]->v() - rv->v(), vert[i0]->u() - rv->u());
+  
+  int i1 = (index+_numEdge-1)%_numEdge;
+  int i0 = (index+1)%_numEdge;
+  Msg::Info("atan2 %g %g (%g %g | %g %g | %g %g)", atan2(vert[i0]->v() - rv->v(), vert[i0]->u() - rv->u()), atan2(vert[i1]->v() - rv->v(), vert[i1]->u() - rv->u()),
+            vert[i1]->u(), vert[i1]->v(), rv->u(), rv->v(), vert[i0]->u(), vert[i0]->v());
+  double ang =  atan2(vert[i0]->v() - rv->v(), vert[i0]->u() - rv->u())
+                - atan2(vert[i1]->v() - rv->v(), vert[i1]->u() - rv->u());
+  
   static int a = -1;
   if (++a < 1) Msg::Warning("FIXME use real angle instead of parametric angle");
-  if (ang < 0.)
-    return ang + 2*M_PI;
-  if (ang >= 2*M_PI)
-    return ang - 2*M_PI;
+  
+  if (ang < .0)
+    return ang + 2.*M_PI;
   return ang;
 }
 
+void Rec2DElement::printAngles()
+{
+  std::vector<Rec2DVertex*> vert;
+  getVertices(vert);
+  Msg::Info("ELEMENT %d (%g %g | %g %g | %g %g)", getNum(),
+            vert[0]->u(), vert[0]->v(), vert[1]->u(), vert[1]->v(), vert[2]->u(), vert[2]->v());
+  
+  for (int i = 0; i < _numEdge; ++i) {
+    Msg::Info("%g", getAngle(vert[i]));
+  }
+}
 
 void Rec2DElement::getAssumedParities(int *p) const
 {
@@ -2395,8 +2681,19 @@ void Rec2DNode::develop(int depth, double &bestEndGlobQual)
   bool delChanges = !_dataChange;
   std::vector<Rec2DElement*> neighbours;
   
-  if (delChanges) {
+  if (_ra) {
     _ra->getNeighbourElements(neighbours);
+    unsigned int i = 0;
+    while (i < neighbours.size()) {
+      if (!neighbours[i]->getNumActions()) {
+        neighbours[i] = neighbours.back();
+        neighbours.pop_back();
+      }
+      else
+        ++i;
+    }
+  }
+  if (delChanges) {
     _dataChange = Rec2DData::getNewDataChange();
     _ra->apply(_dataChange);
   }
@@ -2419,7 +2716,7 @@ void Rec2DNode::develop(int depth, double &bestEndGlobQual)
     std::vector<Rec2DAction*> actions;
     Recombine2D::nextTreeActions(actions, neighbours);
     
-    if (!actions.empty()) {
+    if (actions.size()) {
       for (int i = 0; i < actions.size(); ++i) {
         double bestSonEGQ;
         _son[i] = new Rec2DNode(this, actions[i], bestSonEGQ, depth-1);
diff --git a/Mesh/meshGFaceRecombine.h b/Mesh/meshGFaceRecombine.h
index 76d2cbb00d..1eb82a593d 100644
--- a/Mesh/meshGFaceRecombine.h
+++ b/Mesh/meshGFaceRecombine.h
@@ -74,8 +74,10 @@ class Recombine2D {
     static inline int getNumChange() {return _current->_numChange;}
     static inline void incNumChange() {++_current->_numChange;}
     static inline backgroundMesh* bgm() {return _current->_bgm;}
-    static void add(MQuadrangle *q) {_current->_gf->quadrangles.push_back(q);}
-    static void add(MTriangle *t) {_current->_gf->triangles.push_back(t);}
+    static void add(MQuadrangle *q);
+    static void add(MTriangle *t);
+    
+    static void clearChanges();
     
   private :
     double _geomAngle(MVertex*,
@@ -109,6 +111,7 @@ class Rec2DData {
     
     void printState();
     void printActions();
+    void sortActions() {_actions.sort(lessRec2DAction());}
     void drawTriangles(double shiftx, double shifty);
     void drawChanges(double shiftx, double shifty);
 #ifdef REC2D_DRAW
@@ -145,6 +148,7 @@ class Rec2DData {
     static inline int getNumVert() {return _current->_numVert;}
     static inline double getValVert() {return (double)_current->_valVert;}
     static Rec2DAction* getBestAction();
+    static Rec2DAction* getRandomAction();
     static inline bool hasAction() {return !_current->_actions.empty();}
     
     typedef std::set<Rec2DEdge*>::iterator iter_re;
@@ -181,7 +185,7 @@ class Rec2DData {
     static inline void addParity(Rec2DVertex *rv, int p) {
       _current->_parities[p].push_back(rv);
     }
-    static void associateParity(int pOld, int pNew);
+    static void associateParity(int pOld, int pNew, Rec2DDataChange *rdc = NULL);
     static void removeAssumedParity(Rec2DVertex*, int);
     static inline void addAssumedParity(Rec2DVertex *rv, int p) {
       _current->_assumedParities[p].push_back(rv);
@@ -191,6 +195,8 @@ class Rec2DData {
                                        std::vector<Rec2DVertex*>&);
     static inline void clearAssumedParities() {_current->_oldParity.clear();}
     static void revertAssumedParities();
+    
+    static void checkAngle();
 };
 
 class Rec2DDataChange {
@@ -200,16 +206,22 @@ class Rec2DDataChange {
     std::vector<Rec2DElement*> _hiddenElement, _newElement;
     std::vector<Rec2DAction*> _hiddenAction, _newAction;
     std::vector<std::pair<Rec2DVertex*, SPoint2> > _oldCoordinate;
+    std::vector<std::pair<Rec2DVertex*, int> > _oldParity;
     
     Rec2DAction *_ra;
     
   public :
     void hide(Rec2DEdge*);
     void hide(Rec2DElement*);
+    void hide(Rec2DAction*);
     void hide(std::vector<Rec2DAction*>);
     
     void append(Rec2DElement*);
     
+    void changeParity(Rec2DVertex*, int);
+    void saveParity(std::vector<Rec2DVertex*>&);
+    void checkObsoleteActions();
+    
     void revert();
     
     void setAction(Rec2DAction *action) {_ra = action;}
@@ -219,8 +231,6 @@ class Rec2DDataChange {
 class Rec2DAction {
   protected :
     double _globQualIfExecuted;
-    double _globQualIfExecuted2;
-    double _globQualIfExecuted3;
     int _lastUpdate;
     
   public :
@@ -245,6 +255,7 @@ class Rec2DAction {
     virtual int getNum(double shiftx, double shifty) = 0;
     virtual Rec2DElement* getRandomElement() = 0;
     virtual void printCoord() = 0;
+    virtual void print() = 0;
     
   private :
     virtual void _computeGlobQual() = 0;
@@ -280,9 +291,11 @@ class Rec2DTwoTri2Quad : public Rec2DAction {
     virtual Rec2DElement* getRandomElement();
     
     virtual void printCoord();
+    virtual void print();
     
   private :
     virtual void _computeGlobQual();
+    void _doWhatYouHaveToDoWithParity(Rec2DDataChange*);
 };
 
 class Rec2DEdge {
@@ -349,8 +362,10 @@ class Rec2DVertex {
     void hide();
     void reveal();
     
+    void printGainMerge(Rec2DElement *rel1, Rec2DElement *rel2);
+    inline double getAngle() const {return _angle;}
     inline double getQual() const {return getQualDegree() + getQualAngle();}
-    inline double getQualAngle() const {return _sumQualAngle/_elements.size();}
+    inline double getQualAngle() const {return _sumQualAngle/(double)_elements.size();}
     double getQualDegree(int numEl = -1) const;
     double getGainDegree(int) const;
     double getGainMerge(Rec2DElement*, Rec2DElement*);
@@ -388,6 +403,8 @@ class Rec2DVertex {
     bool has(Rec2DElement*) const;
     void rmv(Rec2DElement*);
     
+    void getUniqueActions(std::vector<Rec2DAction*>&) const;
+    
     static void initStaticTable();
     static Rec2DEdge* getCommonEdge(Rec2DVertex*, Rec2DVertex*);
     static void getCommonElements(Rec2DVertex*, Rec2DVertex*,
@@ -395,7 +412,7 @@ class Rec2DVertex {
     
   private :
     bool _recursiveBoundParity(Rec2DVertex *prev, int p0, int p1);
-    inline double _angle2Qual(double ang) {return 1. - fabs(ang*2/M_PI - 1.);}
+    inline double _angle2Qual(double ang) {return 1. - fabs(ang*2./M_PI - 1.);}
 };
 
 class Rec2DElement {
@@ -446,6 +463,7 @@ class Rec2DElement {
     void createElement(double shiftx, double shifty) const;
     
     double getAngle(Rec2DVertex*);
+    void printAngles();
     
     inline int getNumActions() const {return _actions.size();}
     inline Rec2DAction* getAction(int i) const {return _actions[i];}
@@ -458,6 +476,8 @@ class Rec2DElement {
     Rec2DVertex* getOtherVertex(Rec2DVertex*, Rec2DVertex*) const;
     static Rec2DEdge* getCommonEdge(Rec2DElement*, Rec2DElement*);
     
+    inline int getNum() const {return _mEl->getNum();}
+    
   private :
     MQuadrangle* _createQuad() const;
 };
-- 
GitLab