Skip to content
Snippets Groups Projects
Select Git revision
  • 97565c65c436821da304f75fd9cd5c58f25441ab
  • master default
  • cgnsUnstructured
  • partitioning
  • poppler
  • HighOrderBLCurving
  • gmsh_3_0_4
  • gmsh_3_0_3
  • gmsh_3_0_2
  • gmsh_3_0_1
  • gmsh_3_0_0
  • gmsh_2_16_0
  • gmsh_2_15_0
  • gmsh_2_14_1
  • gmsh_2_14_0
  • gmsh_2_13_2
  • gmsh_2_13_1
  • gmsh_2_12_0
  • gmsh_2_11_0
  • gmsh_2_10_1
  • gmsh_2_10_0
  • gmsh_2_9_3
  • gmsh_2_9_2
  • gmsh_2_9_1
  • gmsh_2_9_0
  • gmsh_2_8_6
26 results

meshRecombine2D_2.cpp

Blame
  • Forked from gmsh / gmsh
    8941 commits behind the upstream repository.
    meshRecombine2D_2.cpp 45.74 KiB
    // Gmsh - Copyright (C) 1997-2016 C. Geuzaine, J.-F. Remacle
    //
    // See the LICENSE.txt file for license information. Please report all
    // bugs and problems to the public mailing list <gmsh@onelab.info>.
    //
    // Contributor(s):
    //   Amaury Johnen, adapted from meshGFaceOptimize
    //
    
    #include "meshRecombine2D.h"
    #include "BackgroundMeshTools.h"
    #include "GFace.h"
    #include <cmath>
    #include <FL/Fl.H>
    #include "drawContext.h"
    #include "FlGui.h"
    #include "Context.h"
    #include "OpenFile.h"//pas propre
    #include "Field.h"
    #include "OS.h"
    #define HORIZ2 1
    #define SMOOTH 0
    
    double **Rec2d_vertex::_Vvalues = NULL;
    double **Rec2d_vertex::_Vbenefs = NULL;
    int TrianglesUnion::_RECOMPUTE = 0;
    int TrianglesUnion::_NumEdge = 0;
    int TrianglesUnion::_NumVert = 0;
    double TrianglesUnion::_ValEdge = .0;
    double TrianglesUnion::_ValVert = .0;
    int Recombine2D::ra = 0;
    
    /*
      a faire :
      - fonction retournant qualite
      - verifier la qualite
      - action supplementaire (faire classe de base)
      - Faire un super conteneur pour les actions
      - pourquoi infini
      - pourquoi premier pas meilleur
      - implementer field
      ~ limiter sequence
    */
    
    Recombine2D::Recombine2D(GFace *gf)
    : _horizon(0), _gf(gf), _benef(.0), _applied(true)
    {
      //GModel::current()->createTopologyFromMesh(1);
      int popopo = 0;
    
      TrianglesUnion::clear();
      Msg::Warning("[meshRecombine2D] Alignement computation ok uniquely for xy or yz plane mesh !");
    
      // 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++) {
          if ((*itge)->getBeginVertex()->getNumMeshElements() > 1 ||
              (*itge)->getEndVertex()->getNumMeshElements() > 1     )
            Msg::Warning("[meshRecombine2D] Why more than one MPoint, what should I do ?");
          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;
      std::map<MVertex*, std::list<MEdge> > mapVtoE;
      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);
          for (int k = 0; k < 3; k++) {
            mapVtoE[t->getVertex(j)].push_back(t->getEdge(k));
          }
        }
      }
    
      // Create the 'Rec2d_vertex' and store iterator to vertices which have degree 4
      std::map<MVertex*, std::list<MTriangle*> >::iterator itvert = mapVert.begin();
      std::map<MVertex*, Rec2d_vertex*> mapV2N;
      std::map<MVertex*, Rec2d_vertex*>::iterator itV2N = mapV2N.begin();
      std::list<std::map<MVertex*, std::list<MTriangle*> >::iterator> fourTri;
      for (; itvert != mapVert.end(); itvert++) {
        if (itvert->second.size() == 4 && itvert->first->onWhat()->dim() == 2)
          fourTri.push_back(itvert);
        std::list<MEdge>::iterator itti = mapVtoE[itvert->first].begin();
        bool ab = false;
        for (; itti != mapVtoE[itvert->first].end(); ++itti) {
          if (mapEdge[*itti].size() == 1) ab = true;
        }
        if (ab) ++popopo;
        Rec2d_vertex *n = new Rec2d_vertex(itvert->first, itvert->second, mapCornerVert, ab);
        itV2N = mapV2N.insert(itV2N, std::make_pair(itvert->first,n));
        TrianglesUnion::_NumVert++;
        TrianglesUnion::_ValVert += n->getReward();
      }
    
      // store mesh size for better performance
      std::map<MVertex*,double> mapV2LcUV;
    
      // Create 'TrianglesUnion' for pattern of 4 triangles
    /*
      +-----+
      |\   /|
      | \ / |
      |  +  |
      | / \ |
      |/   \|
      +-----+
    */
      std::list<std::map<MVertex*, std::list<MTriangle*> >::iterator>::iterator it4;
      int j = 0;
      for (it4 = fourTri.begin(); it4 != fourTri.end(); it4++) {
        std::list<MEdge> listEmbEdge;
        std::list<Rec2d_vertex*> listVert;
        {
          std::set<MVertex*> setVert;
          std::multiset<MEdge, Less_Edge> msetEdge;
          std::list<MTriangle*>::iterator itTri = (*it4)->second.begin();
          for (; itTri != (*it4)->second.end(); itTri++) {
            MVertex *vt;
            for (int i = 0; i < 3; i++) {
              msetEdge.insert((*itTri)->getEdge(i));
              vt = (*itTri)->getVertex(i);
              if (vt != (*it4)->first)
                setVert.insert(vt);
            }
          }
          std::multiset<MEdge>::iterator itEdge = msetEdge.begin();
          MEdge me = *(itEdge++);
          for (; itEdge != msetEdge.end(); itEdge++) {
            if (*itEdge == me)
              listEmbEdge.push_back(*itEdge);
            me = *itEdge;
          }
          std::set<MVertex*>::iterator itsVert = setVert.begin();
          for (; itsVert != setVert.end(); itsVert++)
            listVert.push_back(mapV2N[*itsVert]);
          listVert.push_back(mapV2N[(*it4)->first]);
        }
        Msg::Info("%d",++j);
        TrianglesUnion *tu = new TrianglesUnion(gf, (*it4)->second, listEmbEdge, listVert, mapV2LcUV, mapEdge);
        std::list<MTriangle*>::iterator itTri = (*it4)->second.begin();
        for (; itTri != (*it4)->second.end(); itTri++)
          _possibleActions[*itTri].insert(tu);
        _setQuads.push_back(tu);
      }
    
      // Create 'TrianglesUnion' for pattern of 2 triangles
    /*
      +---+
      |\  |
      | \ |
      |  \|
      +---+
    */
      std::map<MEdge, std::list<MTriangle*> >::iterator itedge = mapEdge.begin();
      for (; itedge != mapEdge.end(); itedge++) {
        if (itedge->second.size() == 2) {
          std::list<MEdge> listEmbEdge;
          listEmbEdge.push_back(itedge->first);
          std::list<Rec2d_vertex*> listVert;
          listVert.push_back(mapV2N[itedge->first.getVertex(0)]);
          listVert.push_back(mapV2N[itedge->first.getVertex(1)]);
          TrianglesUnion *tu = new TrianglesUnion(gf, itedge->second, listEmbEdge, listVert, mapV2LcUV, mapEdge);
          _setQuads.push_back(tu);
          TrianglesUnion::_NumEdge++;
          TrianglesUnion::_ValEdge += tu->getEdgeValue();
          std::list<MTriangle*>::iterator itTri = itedge->second.begin();
          for (; itTri != itedge->second.end(); itTri++)
            _possibleActions[*itTri].insert(tu);
        }
        else
          ;//Msg::Info("[bord] %d", itedge->second.size());
      }
      TrianglesUnion::addRec();
      //_setQuads.sort(lessTriUnion());
    
      if (SMOOTH) laplaceSmoothing(_gf,10);
      Msg::Error("%d", popopo);
      _recombine(true);
      _applied = false;
    }
    
    
    void Recombine2D::_recombine(bool a)
    {
      SetBoundingBox();
    
      int i = 0;
      std::list<TrianglesUnion*> vectTu;
      TrianglesUnion::addRec();
    
      while (!_setQuads.empty() && i < 2000) {
        TrianglesUnion *tu;
      if (SMOOTH) laplaceSmoothing(_gf,1);
        if (_lastQuad.empty()) {
          if (/*true ||*/ vectTu.size() < 2 || i % 1 == 0)
            tu = *std::max_element(_setQuads.begin(), _setQuads.end(), lessTriUnion());
          else {
            vectTu.pop_front();
            //tu = *std::max_element(vectTu.begin(),vectTu.end(), lessTriUnion());
            tu = *vectTu.begin();
          }
          vectTu.clear();
          vectTu.insert(vectTu.begin(), tu);
    
                Msg::Info("------------------ %d", _setQuads.size());
          _lookAhead(vectTu, HORIZ2);
        }
        else {
          tu = *_lastQuad.begin();
          vectTu.clear();
          vectTu.insert(vectTu.begin(), tu);
          std::set<MTriangle*> touched;
          for (int i = 0; i < tu->getNumTriangles(); i++) {
            touched.insert(tu->getTriangle(i));
          }
          std::list<TrianglesUnion*>::iterator it = _lastQuad.begin();
          while (it != _lastQuad.end()) {
            bool toBeErased = false;
            for (int i = 0; i < (*it)->getNumTriangles(); i++) {
              if (touched.find((*it)->getTriangle(i)) != touched.end())
                toBeErased = true;
            }
            if (toBeErased)
              _lastQuad.erase(it++);
            else
              ++it;
          }
        }
        tu = *vectTu.begin();
        tu->select();
        _quads.push_back(tu->createQuad());
        _removeImpossible(tu);
        if (i % 5 == 0) { // draw Mesh
          Msg::Info("Expected return %lf", tu->getReturn());
          _applied = false;
          apply(true);
          _applied = false;
          CTX::instance()->mesh.changed = (ENT_ALL);
          //drawContext::global()->draw();
          FlGui::instance()->check();
          drawContext::global()->draw();
          double t = Cpu();
          while (Cpu() - t < .0001);
          if (i % 1000 == 0)
          if (!Msg::GetAnswer("Continue ?", 1, "no", "yes"))
            Msg::Info("I continue anyway :p");
        }
    
        ++i;
      }
      Msg::Info("Done %d (%d)", i, _pairs.size());
    }
    
    void printIt(std::vector<list_actions::iterator> &vIt, int size)
    {
      switch (size) {
        case 3 :
          Msg::Info("--Iterators : %d , %d , %d", vIt[0].getPos(), vIt[1].getPos(), vIt[2].getPos());
          break;
        case 2 :
          Msg::Info("--Iterators : %d , %d", vIt[0].getPos(), vIt[1].getPos());
          break;
        case 1 :
          Msg::Info("--Iterators : %d", vIt[0].getPos());
          break;
        default :
          break;
      }
    }
    
    void Recombine2D::_lookAhead(std::list<TrianglesUnion*> &candidate, int horiz)
    {
      if (horiz < 1)
        horiz = 1;
      _lessActions.clear();
    
      int t = (int) Cpu() * 100;
      bool newt = true;
    
      double maxReturn = -100.;
      //TrianglesUnion *bestAction;
      int numbers[2] = {0, 0}; // number of embedded verts & edges
      double values[2] = {.0, .0}; // embedded vert & edge values
      std::set<MTriangle*> setTri;
      std::map<Rec2d_vertex*, int> modifiedVert;
      std::vector<list_actions::iterator> vecIt(horiz);
      std::vector<std::pair<TrianglesUnion*, int> > bestSequence;
    
      list_actions la(horiz);
      {
        setTriUnion candidates;
        _getIncompatibles(*candidate.begin(), candidates);
        la.add(candidates);
      }
    
      vecIt[0] = la.begin();
      (*vecIt[0])->addTri(setTri);
      (*vecIt[0])->addInfluence(numbers, values, modifiedVert);
      _addNeighbors(horiz, vecIt, 0, &la);
    
      int current = 1;
      int num=0;
    
      while (current > 0) {
        bool best = false;
        // set first acceptable action for each step
        while (current < horiz && vecIt[current-1] != la.end()) {
          vecIt[current] = vecIt[current-1];
          while (++vecIt[current] != la.end() && (*vecIt[current])->isIn(setTri));
          if (vecIt[current] != la.end()) {
            (*vecIt[current])->addTri(setTri);
            (*vecIt[current])->addInfluence(numbers, values, modifiedVert);
            _addNeighbors(horiz, vecIt, current, &la);
          }
          ++current;
        }
    
        { // color
          for (int i = 1; i < current &&  vecIt[i] != la.end(); ++i) {
            TrianglesUnion *tu = *vecIt[i];
            int pos = vecIt[i].getPos();
            double frac = (double)pos / (double)(horiz-1);
            unsigned int col;
            //la.sizes();
            //Msg::Info("%d / %d -> %d", pos, horiz, (int)(200.*frac));
            col = CTX::instance()->packColor(50 - (int)(25.*frac), 200 - (int)(25.*frac), (int)(200.*frac), 255);
            for (int j = 0; j < tu->getNumTriangles(); ++j) {
              tu->getTriangle(j)->setCol(col);
            }
          }
        }
    
        double expectedReturn = TrianglesUnion::computeReturn(numbers, values, modifiedVert);
        if (maxReturn < expectedReturn) {
          int sizeSequence = current;
          if (vecIt[sizeSequence - 1] == la.end())
            --sizeSequence;
          expectedReturn = _realisticReturn(numbers, values, modifiedVert, vecIt, sizeSequence, setTri);
          if (maxReturn < expectedReturn) {
            maxReturn = expectedReturn;
            //bestAction = *vecIt[0];
            bestSequence.resize(sizeSequence);
            for (int i = 0; i < sizeSequence; ++i)
              bestSequence[i] = std::make_pair(*vecIt[i], vecIt[i].getPos());
            { //color
              best = true;
              TrianglesUnion *tu = *vecIt[0];
              unsigned int col;
              col = CTX::instance()->packColor(190, 0, 190, 255);
              for (int j = 0; j < tu->getNumTriangles(); ++j) {
                tu->getTriangle(j)->setCol(col);
              }
            }
          }
        }
        else { //color
          TrianglesUnion *tu = *vecIt[0];
          unsigned int col;
          col = CTX::instance()->packColor(190, 0, 0, 255);
          for (int j = 0; j < tu->getNumTriangles(); ++j) {
            tu->getTriangle(j)->setCol(col);
          }
        }
    
        if (/*true ||*/ best /*|| (((int)(Cpu()*100) - t) % 5 == 0 && newt)*/) { // draw mesh
          newt = false;
          apply(false);
      if (SMOOTH) laplaceSmoothing(_gf,1);
          CTX::instance()->mesh.changed = (ENT_ALL);
          FlGui::instance()->check();
          drawContext::global()->draw();
          double t = Cpu();
          while (Cpu() - t < .0001);
          //if (i % 1 == 0)
          if (false && best && !Msg::GetAnswer("Continue ?", 1, "no", "yes"))
            Msg::Info("I continue anyway :p");
          best = false;
        }
        /*if (((int)(Cpu()*100) - t) % 5 != 0)
          newt = true;*/
    
        { // decolor
          for (int i = 0; i < current &&  vecIt[i] != la.end(); ++i) {
            TrianglesUnion *tu = *vecIt[i];
            int pos = vecIt[i].getPos();
            double frac = (double)pos / (double)horiz;
            unsigned int col;
            col = CTX::instance()->packColor(255, 255, 0, 255);
            for (int j = 0; j < tu->getNumTriangles(); ++j) {
              tu->getTriangle(j)->setCol(col);
            }
          }
        }
    
        if (vecIt[current-1] != la.end() || --current > 0) {
          do {
            (*vecIt[current-1])->removeTri(setTri);
            (*vecIt[current-1])->removeInfluence(numbers, values, modifiedVert);
            _removeNeighbors(horiz, current - 1, &la);
            while (++vecIt[current-1] != la.end() && (*vecIt[current-1])->isIn(setTri));
          } while (vecIt[current-1] == la.end() && --current > 0);
          if (current > 0) {
            (*vecIt[current-1])->addTri(setTri);
            (*vecIt[current-1])->addInfluence(numbers, values, modifiedVert);
            _addNeighbors(horiz, vecIt, current - 1, &la);
          }
        }
      }
    
      { // color
        for (int i = 1; i < bestSequence.size(); ++i) {
          TrianglesUnion *tu = bestSequence[i].first;
          unsigned int col = CTX::instance()->packColor(50, 200, 0, 255);
          for (int j = 0; j < tu->getNumTriangles(); ++j) {
            tu->getTriangle(j)->setCol(col);
          }
        }
      }
    
      candidate.clear();
      for (int i = 0; i < bestSequence.size(); ++i) {
        candidate.insert(candidate.end(), bestSequence[i].first);
      }
    }
    
    void Recombine2D::_lookAhead2(std::list<TrianglesUnion*> &candidate, int horiz)
    {
      if (horiz < 1)
        horiz = 1;
      _lessActions.clear();
    
      //int t = (int) Cpu() * 100;
      //bool newt = true;
    
      double maxReturn = -100.;
      int numbers[2] = {0, 0}; // number of embedded verts & edges
      double values[2] = {.0, .0}; // embedded vert & edge values
      std::set<MTriangle*> setTri;
      std::map<Rec2d_vertex*, int> modifiedVert;
      std::vector<list_actions::iterator> vecIt(horiz);
      std::vector<std::pair<TrianglesUnion*, int> > bestSequence;
    
      list_actions la(horiz);
      {
        setTriUnion candidates;
        _getIncompatibles(*candidate.begin(), candidates);
        la.add(candidates);
      }
    
      vecIt[0] = la.begin();
      (*vecIt[0])->addTri(setTri);
      (*vecIt[0])->addInfluence(numbers, values, modifiedVert);
      //_addNeighbors(horiz, vecIt, 0, &la);
    
      std::vector<list_actions::iterator> lastLayer(horiz);
      std::vector<int> numLayer(horiz);
      lastLayer[0] = la.end();
      numLayer[0] = 0;
      bool haveSequence = false;
      int current = 1, currentLayer = 0, maxLayer = 0;
      int num=0;
    
      while (current > 0) {
            //Msg::Info(" ");
        bool best = false;
        // add max of actions in sequence
        while (current < horiz && vecIt[current-1] != la.end()) {
          vecIt[current] = vecIt[current-1];
          //vecIt[current].print();
          while (++vecIt[current] != lastLayer[currentLayer]
                 && vecIt[current] != la.end()
                 && (*vecIt[current])->isIn(setTri)         );
          if (vecIt[current] != lastLayer[currentLayer] && vecIt[current] == la.end())
            {Msg::Error("Ca a foir mec");Msg::Error(" ");}
          if (vecIt[current] != lastLayer[currentLayer] && vecIt[current] != la.end()) {
            (*vecIt[current])->addTri(setTri);
            (*vecIt[current])->addInfluence(numbers, values, modifiedVert);
            if (currentLayer < maxLayer) {
              if (current == numLayer[currentLayer])
                lastLayer[currentLayer] = --la.end();
              _addNeighbors(horiz, vecIt, current, &la);
              if (current == numLayer[currentLayer])
                ++lastLayer[currentLayer];
              lastLayer[currentLayer+1] = la.end();
            }
            ++current;
          }
          else {
            //Msg::Info("in else");
            if (!haveSequence) {
              ++maxLayer;
              --lastLayer[currentLayer];
              for (int i = numLayer[currentLayer]; i < current; ++i) {
                _addNeighbors(horiz, vecIt, i, &la);
              }
              ++lastLayer[currentLayer];
              ++currentLayer;
              lastLayer[currentLayer] = la.end();
              numLayer[currentLayer] = current;
            }
            else if (currentLayer < maxLayer) {
              /*for (int i = numLayer[currentLayer]; i < current; ++i) {
                _addNeighbors(horiz, vecIt, i, &la);
              }*/
              //Msg::Error("++layer'");
              ++currentLayer;
              lastLayer[currentLayer] = la.end();
              numLayer[currentLayer] = current;
            }
            else{
              //Msg::Error("++current : %d/%d", current, horiz);
              //if(lastLayer[currentLayer] != la.end())
              //Msg::Error(" ");
              ++current;
            }
          }
        }
        haveSequence = true;
        //Msg::Info("maxLayer %d, current %d", maxLayer, current);
    
    /*Msg::Info("LAYER %d - num{%d,%d} - last :", currentLayer, numLayer[0], numLayer[1]);
    lastLayer[0].print();
    lastLayer[1].print();
    Msg::Info("current %d - iterator : ", current-1);
    vecIt[current-1].print();
    Msg::Info(" ");*/
    
        { // color
          for (int i = 1; i < current &&  vecIt[i] != la.end(); ++i) {
            TrianglesUnion *tu = *vecIt[i];
            int pos = vecIt[i].getPos();
            double frac = (double)pos / (double)(horiz-1);
            unsigned int col;
            //la.sizes();
            //Msg::Info("%d / %d -> %d", pos, horiz, (int)(200.*frac));
            col = CTX::instance()->packColor(50 - (int)(25.*frac), 200 - (int)(25.*frac), (int)(200.*frac), 255);
            for (int j = 0; j < tu->getNumTriangles(); ++j) {
              tu->getTriangle(j)->setCol(col);
            }
          }
        }
    
        double expectedReturn = TrianglesUnion::computeReturn(numbers, values, modifiedVert);
        if (maxReturn < expectedReturn) {
          int sizeSequence = current;
          if (vecIt[sizeSequence - 1] == la.end())
            --sizeSequence;
          expectedReturn = _realisticReturn(numbers, values, modifiedVert, vecIt, sizeSequence, setTri);
          if (maxReturn < expectedReturn) {
            //Msg::Info("best");
            //Msg::Info(" ");
            maxReturn = expectedReturn;
            //bestAction = *vecIt[0];
            bestSequence.resize(sizeSequence);
            for (int i = 0; i < sizeSequence; ++i)
              bestSequence[i] = std::make_pair(*vecIt[i], vecIt[i].getPos());
            { //color
              best = true;
              TrianglesUnion *tu = *vecIt[0];
              unsigned int col;
              col = CTX::instance()->packColor(190, 0, 190, 255);
              for (int j = 0; j < tu->getNumTriangles(); ++j) {
                tu->getTriangle(j)->setCol(col);
              }
            }
          }
          else { //color
            TrianglesUnion *tu = *vecIt[0];
            unsigned int col;
            col = CTX::instance()->packColor(190, 130, 0, 255);
            for (int j = 0; j < tu->getNumTriangles(); ++j) {
              tu->getTriangle(j)->setCol(col);
            }
          }
        }
        else { //color
          TrianglesUnion *tu = *vecIt[0];
          unsigned int col;
          col = CTX::instance()->packColor(190, 0, 0, 255);
          for (int j = 0; j < tu->getNumTriangles(); ++j) {
            tu->getTriangle(j)->setCol(col);
          }
        }
    
        if (/*true ||*/ best /*|| (((int)(Cpu()*100) - t) % 5 == 0 && newt)*/) { // draw mesh
          //newt = false;
          apply(false);
          CTX::instance()->mesh.changed = (ENT_ALL);
          FlGui::instance()->check();
            //Msg::Info("before");
            //Msg::Info(" ");
          drawContext::global()->draw();
            //Msg::Info("after");
            //Msg::Info(" ");
          double t = Cpu();
          while (Cpu() - t < .0001);
          //if (i % 1 == 0)
          if (false && best && !Msg::GetAnswer("Continue ?", 1, "no", "yes"))
            Msg::Info("I continue anyway :p");
          best = false;
        }
        /*if (((int)(Cpu()*100) - t) % 5 != 0)
          newt = true;*/
    
        { // decolor
          for (int i = 0; i < current &&  vecIt[i] != la.end(); ++i) {
            TrianglesUnion *tu = *vecIt[i];
            int pos = vecIt[i].getPos();
            double frac = (double)pos / (double)horiz;
            unsigned int col;
            col = CTX::instance()->packColor(255, 255, 0, 255);
            for (int j = 0; j < tu->getNumTriangles(); ++j) {
              tu->getTriangle(j)->setCol(col);
            }
          }
        }
    
        if (vecIt[current-1] != la.end() || --current > 0) {
          do {
            while (current-1 < numLayer[currentLayer])
              --currentLayer;
            (*vecIt[current-1])->removeTri(setTri);
            (*vecIt[current-1])->removeInfluence(numbers, values, modifiedVert);
            //Msg::Info(" - current %d, currentLayer %d", current, currentLayer);
            if (currentLayer < maxLayer) {
              _removeNeighbors(horiz, current - 1, &la);
              if (current-1 == numLayer[currentLayer])
                lastLayer[currentLayer] = la.end();
              else
                lastLayer[currentLayer+1] = la.end();
            }
            while (++vecIt[current-1] != la.end() && (*vecIt[current-1])->isIn(setTri)) {
              //Msg::Info(" - - curent %d & layer %d & numLayer %d", current, currentLayer, numLayer[currentLayer]);
              //vecIt[current-1].print(); lastLayer[currentLayer].print();
              if (vecIt[current-1] == lastLayer[currentLayer]) {
                //Msg::Warning("++layer");
                ++currentLayer;
                numLayer[currentLayer] = current - 1;
              }
            }
            if (currentLayer < maxLayer && vecIt[current-1] == lastLayer[currentLayer]) {
              //Msg::Warning("++ layer");
              //vecIt[current-1].print(); lastLayer[currentLayer].print();
              ++currentLayer;
              numLayer[currentLayer] = current - 1;
            }
            //Msg::Info("b %d, %d - %d, %d", vecIt[current-1] == lastLayer[currentLayer], current-2, numLayer[currentLayer], currentLayer);
          } while (vecIt[current-1] == la.end() && --current > 0);
            //Msg::Info("current %d, currentLayer %d", current, currentLayer);
          if (current > 0) {
            (*vecIt[current-1])->addTri(setTri);
            (*vecIt[current-1])->addInfluence(numbers, values, modifiedVert);
            if (currentLayer < maxLayer) {
              if (current-1 == numLayer[currentLayer])
                --lastLayer[currentLayer];
              _addNeighbors(horiz, vecIt, current - 1, &la);
              if (current-1 == numLayer[currentLayer])
                ++lastLayer[currentLayer];
              lastLayer[currentLayer+1] = la.end();
            }
          }
        }
    /*    if (current > 0) {
    Msg::Info("layer %d - num{%d,%d} - last :", currentLayer, numLayer[0], numLayer[1]);
    lastLayer[0].print();
    lastLayer[1].print();
    Msg::Info("current %d - iterator : ", current-1);
    vecIt[current-1].print();
    Msg::Info(" ");
    }*/
      }
    
      /*{ // color
        for (int i = 1; i < bestSequence.size(); ++i) {
          TrianglesUnion *tu = bestSequence[i].first;
          unsigned int col = CTX::instance()->packColor(50, 200, 0, 255);
          for (int j = 0; j < tu->getNumTriangles(); ++j) {
            tu->getTriangle(j)->setCol(col);
          }
        }
      }*/
    
      candidate.clear();
      for (int i = 0; i < bestSequence.size(); ++i) {
        candidate.insert(candidate.end(), bestSequence[i].first);
      }
    }
    
    void Recombine2D::_getIncompatibles(const TrianglesUnion *tu, setTriUnion &set)
    {
      for (int i = 0; i < tu->getNumTriangles(); i++) {
        mapTriUnion::iterator it = _lessActions.find(tu->getTriangle(i));
        if (it == _lessActions.end()) {
          it = _possibleActions.find(tu->getTriangle(i));
          if (it == _possibleActions.end()) {
            Msg::Error("[Rec2D] error no triangle !, stopping with partially filled set");
            Msg::Error(" ");
          }
          _lessActions.insert(*it);
        }
        setTriUnion::iterator it2 = it->second.begin();
        for (; it2 != it->second.end(); ++it2) {
          set.insert(*it2);
        }
      }
    }
    
    void Recombine2D::_getNeighbors(const TrianglesUnion *tu, setTriUnion &set)
    {
      setTriUnion incomp;
      setTriUnion neighbors;
      _getIncompatibles(tu, incomp);
      setTriUnion::iterator it = incomp.begin();
      for (; it != incomp.end(); ++it)
        _getIncompatibles(*it, neighbors);
      it = incomp.begin();
      for (; it != incomp.end(); ++it)
        neighbors.erase(*it);
      it = neighbors.begin();
      for (; it != neighbors.end(); ++it)
        set.insert(*it);
    }
    
    void Recombine2D::_addNeighbors(int horiz, std::vector<list_actions::iterator> &vecIt, int current, list_actions *la)
    {
      if (current < horiz - 1 && current > -1) {
        //Msg::Info("+ra %d", ++ra);
        setTriUnion neighbors;
        _getNeighbors(*vecIt[current], neighbors);
        la->add(neighbors);
      }
    }
    
    void Recombine2D::_removeNeighbors(int horiz, int current, list_actions *la)
    {
      if (current < horiz - 1 && current > -1) {
        //Msg::Info("-ra %d", --ra);
        la->pop_back();
      }
    }
    
    
    double Recombine2D::_realisticReturn(const int *num,
                                         const double *val,
                                         const std::map<Rec2d_vertex*, int> &mapVert,
                                         const std::vector<list_actions::iterator> &vecIt,
                                         int size,
                                         const std::set<MTriangle*> &seqTri)
    {
      //Msg::Info("before (%d) : %lf -> %lf", size, TrianglesUnion::getActualReturn(), TrianglesUnion::computeReturn(num, val, mapVert));
      int newNum[2] = {num[0], num[1]}, numIsolatedTri, numRecomb = size;
      double newVal[2] = {val[0], val[1]};
      std::map<Rec2d_vertex*, int> newMapVert = mapVert;
    
      setTriUnion setIncompTu;
      for (int i = 0; i < size; ++i) {
        _getIncompatibles(*vecIt[i], setIncompTu);
      }
    
      std::set<MTriangle*> setTri = seqTri, touched;
    
      numIsolatedTri = _checkIsolatedTri(vecIt, size, setTri);
      //Msg::Info("numisolated %d, last %d", numIsolatedTri, setTri.size());
    
      std::set<MTriangle*>::iterator itTri = setTri.begin();
      int kl = 0;
      while (itTri != setTri.end()) {
        //Msg::Info("%d.", ++kl);
        mapTriUnion::iterator itTmp = _possibleActions.find(*itTri);
        setTriUnion::iterator it_tu = itTmp->second.begin();
        TrianglesUnion *tu;
        int numPossible = 0;
        for (; it_tu != itTmp->second.end(); ++it_tu) {
          bool possible = true;
          TrianglesUnion *tu1 = *it_tu;
          for (int i = 0; i < tu1->getNumTriangles(); i++)
          if (seqTri.find(tu1->getTriangle(i)) != seqTri.end() ||
              touched.find(tu1->getTriangle(i)) != touched.end() )
            possible = false;
          if (possible) {
            tu = tu1;
            ++numPossible;
          }
        }
    
        setTri.erase(itTri);
    
        if (numPossible < 1){
          ++numIsolatedTri;
          Msg::Info("'m here");
        }
        else if (numPossible > 1)
          Msg::Info("Oh oh, trouble");
        else {
          //Msg::Info("possible");
          ++numRecomb;
          tu->addInfluence(newNum, newVal, newMapVert);
          for (int i = 0; i < tu->getNumTriangles(); i++) {
            touched.insert(tu->getTriangle(i));
            setTri.erase(tu->getTriangle(i));
          }
          _getIncompatibles(tu, setIncompTu);
    
          setTriUnion setTu;
          setTu.clear();
          _getIncompatibles(tu, setTu);
    
          std::set<MTriangle*> setBoundaryTri;
          setTriUnion::iterator it = setTu.begin();
          for (; it != setTu.end(); ++it) {
            for (int i = 0; i < (*it)->getNumTriangles(); i++)
            if (seqTri.find((*it)->getTriangle(i)) == seqTri.end() &&
                touched.find((*it)->getTriangle(i)) == touched.end() )
              setBoundaryTri.insert((*it)->getTriangle(i));
          }
    
          //Msg::Info("size boundary : %d", setBoundaryTri.size());
    
          std::set<MTriangle*>::iterator itTri2 = setBoundaryTri.begin();
          for (; itTri2 != setBoundaryTri.end(); ++itTri2) {
            mapTriUnion::iterator it1 = _possibleActions.find(*itTri2);
            if (it1 == _possibleActions.end()) {
              Msg::Error("[Rec2D] error no triangle !, stopping with partially filled set");
              Msg::Error(" ");
            }
            int numPossibleRecombinations = 0;
            setTriUnion::iterator it2 = it1->second.begin();
            for (; it2 != it1->second.end(); ++it2)
            if (setIncompTu.find(*it2) == setIncompTu.end())
              ++numPossibleRecombinations;
            if (!numPossibleRecombinations) {
              ++numIsolatedTri;
              setTri.erase(*itTri2);
            }
            if (numPossibleRecombinations == 1)
              setTri.insert(*itTri2);
          }
        }
        itTri = setTri.begin();
      }
    
      double oldReturn = TrianglesUnion::getActualReturn();
      double newReturn = TrianglesUnion::computeReturn(newNum, newVal, newMapVert);
    
      //Msg::Info("after (%d) : %lf -> %lf - %d", numRecomb, TrianglesUnion::getActualReturn(), (newReturn-oldReturn) * size/numRecomb + oldReturn, numIsolatedTri);
    
      return (newReturn-oldReturn) * size/numRecomb + oldReturn - numIsolatedTri;
    }
    
    int Recombine2D::_checkIsolatedTri(const std::vector<list_actions::iterator> &vecIt,
                                       int size, std::set<MTriangle*> &seqTri)
    {
      setTriUnion setTu;
      for (int i = 0; i < size; ++i) {
        _getIncompatibles(*vecIt[i], setTu);
      }
    
      std::set<MTriangle*> setBoundaryTri;
      setTriUnion::iterator it = setTu.begin();
      for (; it != setTu.end(); ++it) {
        for (int i = 0; i < (*it)->getNumTriangles(); i++)
        if (seqTri.find((*it)->getTriangle(i)) == seqTri.end())
          setBoundaryTri.insert((*it)->getTriangle(i));
      }
    
      seqTri.clear();
    
      int num = 0;
      std::set<MTriangle*>::iterator itTri = setBoundaryTri.begin();
      for (; itTri != setBoundaryTri.end(); ++itTri) {
        mapTriUnion::iterator it1 = _lessActions.find(*itTri);
        if (it1 == _lessActions.end()) {
          it1 = _possibleActions.find(*itTri);
          if (it1 == _possibleActions.end()) {
            Msg::Error("[Rec2D] error no triangle !, stopping with partially filled set");
          }
          _lessActions.insert(*it1);
        }
        int numPossibleRecombinations = 0;
        setTriUnion::iterator it2 = it1->second.begin();
        for (; it2 != it1->second.end(); ++it2)
        if (setTu.find(*it2) == setTu.end())
          ++numPossibleRecombinations;
        if (!numPossibleRecombinations)
          ++num;
        if (numPossibleRecombinations == 1)
          seqTri.insert(*itTri);
      }
      return num;
    }
    
    int Recombine2D::apply(bool a)
    {
      //Msg::Info("(%d, %d, %d)", _quads.size(), _gf->triangles.size(), _isolated.size());
      if (a) {
        _gf->triangles.clear();
        //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;
        _isolated.clear();
      }
    
      _applied = true;
      return 1;
    }
    
    void Recombine2D::_removeImpossible(TrianglesUnion *tu)
    {
      for (int i = 0; i < tu->getNumTriangles(); i++) {
        _isolated.insert(tu->getTriangle(i));
      }// for test
    
      std::set<MTriangle*> touched;
      for (int i = 0; i < tu->getNumTriangles(); i++) {
        touched.insert(tu->getTriangle(i));
      }
    
      setTriUnion incomp;
      std::set<MTriangle*>::iterator itTri = touched.begin();
      for (; itTri != touched.end(); ++itTri) {
        mapTriUnion::iterator it = _possibleActions.find(*itTri);
        if (it != _possibleActions.end()) {
          setTriUnion::iterator it2 = it->second.begin();
          for (; it2 != it->second.end(); ++it2)
            incomp.insert(*it2);
        }
      }
    
      setTriUnion::iterator itTu = incomp.begin();
      for (; itTu != incomp.end(); ++itTu) {
        for (int i = 0; i < (*itTu)->getNumTriangles(); i++) {
          mapTriUnion::iterator it4 = _possibleActions.find((*itTu)->getTriangle(i));
          it4->second.erase(*itTu);
          TrianglesUnion *tu;
          if (touched.find(it4->first) == touched.end())
          switch (it4->second.size()) {
            case 1 :
              _lastQuad.insert(_lastQuad.begin(), *it4->second.begin());
              tu = *it4->second.begin();
              unsigned int col;
              col = CTX::instance()->packColor(0, 0, 0, 0);
              for (int j = 0; j < tu->getNumTriangles(); ++j)
                tu->getTriangle(j)->setCol(col);
              break;
            case 0 :
            default :
              break;
          }
        }
        //_setQuads.erase(*itTu); //marche pas avec list
      }
    
      std::list<TrianglesUnion*>::iterator it = _setQuads.begin();
      while (it != _setQuads.end()) {
        if (incomp.find(*it) != incomp.end())
          it = _setQuads.erase(it); // replacement de _setQuads.erase(*itTu);
        else
          ++it;
      }
    
      for (int i = 0; i < tu->getNumTriangles(); i++) {
        _possibleActions.erase(tu->getTriangle(i));
      }
    
      /*std::list<TrianglesUnion*>::iterator it = _setQuads.begin();
      while (it != _setQuads.end()) {
        bool b = false;
        for (int i = 0; i < (*it)->getNumTriangles(); i++) {
          if (touched.find((*it)->getTriangle(i)) != touched.end())
            b = true;
        }
        if (b)
          it = _setQuads.erase(it);
        else
          ++it;
      }*/
    }
    
    Rec2d_vertex::Rec2d_vertex(MVertex *v,
                               std::list<MTriangle*> &setTri,
                               std::map<MVertex*, std::set<GEdge*> > &mapVert, bool a)
    : _numEl(setTri.size()), _angle(.0)
    {
      _onWhat = v->onWhat()->dim() - 1;
      if (a) _onWhat = 1;
    
      if (_onWhat < 0) {
        std::map<MVertex*, std::set<GEdge*> >::iterator it = mapVert.find(v);
        if (it != mapVert.end()) {
          _angle = _computeAngle(v, setTri, it->second);
        }
        else {
          Msg::Warning("[meshRecombine2D] Can't compute corner angle, setting angle to pi/2");
          _angle = M_PI / 2.;
        }
      }
    
      if (_Vvalues == NULL)
        _initStaticTable();
    }
    
    void Rec2d_vertex::_initStaticTable()
    {
      if (_Vvalues == NULL) {
        // _Vvalues[onWhat][nEl]; onWhat={0:edge,1:face} / nEl=_numEl-1
        // _Vbenefs[onWhat][nEl]; onWhat={0:edge,1:face} / nEl=_numEl-1 (benef of adding an element)
        int nE = 5, nF = 10;
    
        _Vvalues = new double*[2];
        _Vvalues[0] = new double[nE];
        for (int i = 0; i < nE; i++)
          _Vvalues[0][i] = 1. - fabs(2. / (i+1) - 1.);
        _Vvalues[1] = new double[nF];
        for (int i = 0; i < nF; i++)
          _Vvalues[1][i] = 1. - fabs(4. / (i+1) - 1.);
    
        _Vbenefs = new double*[2];
        _Vbenefs[0] = new double[nE-1];
        for (int i = 0; i < nE-1; i++)
          _Vbenefs[0][i] = _Vvalues[0][i+1] - _Vvalues[0][i];
        _Vbenefs[1] = new double[nF-1];
        for (int i = 0; i < nF-1; i++)
          _Vbenefs[1][i] = _Vvalues[1][i+1] - _Vvalues[1][i];
      }
    }
    
    
    double Rec2d_vertex::_computeAngle(MVertex *v,
                                       std::list<MTriangle*> &setTri,
                                       std::set<GEdge*> &setEdge)
      {
      if (setEdge.size() != 2) {
        Msg::Warning("[meshRecombine2D] Wrong number of edge : %d, returning pi/2", setEdge.size());
        return M_PI / 2.;
      }
      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("[meshRecombine2D] 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 = setTri.begin();
      for (; it2 != setTri.end(); it2++) {
        MTriangle *t = *it2;
        int k = 0;
        while (t->getVertex(k) != v && k < 3)
          k++;
        if (k == 3) {
          Msg::Warning("[meshRecombine2D] 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 Rec2d_vertex::getReward()
    {
      if (_onWhat > -1)
        return _Vvalues[_onWhat][_numEl-1];
      else
        return 1. - fabs(2. / M_PI * _angle / _numEl - 1.);
    }
    
    double Rec2d_vertex::getReward(int n)
    {
      static double t= Cpu();
      if (_onWhat > -1) {
        switch (n) {
          case 1 :
            return _Vbenefs[_onWhat][_numEl-1];
          case -1 :
            return - _Vbenefs[_onWhat][_numEl-2];
          default :
            return _Vvalues[_onWhat][_numEl-1+n] - _Vvalues[_onWhat][_numEl-1];
        }
      }
      else
        return fabs(2./M_PI*_angle/_numEl - 1.) - fabs(2./M_PI*_angle/(_numEl + n) - 1.);
    }
    
    
    TrianglesUnion::TrianglesUnion(GFace *gf,
                                   std::list<MTriangle*> &t,
                                   std::list<MEdge> &e,
                                   std::list<Rec2d_vertex*> &v,
                                   std::map<MVertex*,double> &v2lcUV,
                                   std::map<MEdge, std::list<MTriangle*>, Less_Edge> &mapEdge)
    {
      _numTri = t.size();
      _numEmbEdge = e.size();
      _numBoundVert = v.size() == 2 ? 2 : 4;
      _numEmbVert = v.size() - _numBoundVert;
      _globValIfExecuted = _embEdgeValue = _embVertValue = .0;
    
      _triangles = new MTriangle*[_numTri];
      std::list<MTriangle*>::iterator itt = t.begin();
      std::set<MEdge, Less_Edge> setEdge;
      for (int k = 0; itt != t.end(); itt++, k++) {
        _triangles[k] = *itt;
        for (int i = 0; i < 3; ++i) {
          setEdge.insert((*itt)->getEdge(i));
        }
      }
    
      std::list<MEdge>::iterator ite = e.begin();
      for (; ite != e.end(); ite++) {
        double sumlc = .0, u[2], v[2];
        MVertex *vert[2];
        for (int i = 0; i < 2; i++) {
          vert[i] = ite->getVertex(i);
          vert[i]->getParameter(0, u[i]);
          vert[i]->getParameter(1, v[i]); // Warning : should check if vertex on face or on edge
          std::map<MVertex*,double>::iterator itlc = v2lcUV.find(vert[i]);
          if (itlc == v2lcUV.end()) {
            sumlc += v2lcUV[vert[i]] = BGM_MeshSize(gf, u[i], v[i], vert[i]->x(), vert[i]->y(), vert[i]->z());
          }
          else
            sumlc += itlc->second;
        }
    
        sumlc = .2; // FIXME BGM_MeshSize returns wrong meshsize
    
        double length = _computeEdgeLength(gf, vert, u, v, 0);
        double a = .0;
        _embEdgeValue += length / sumlc * (a + (2-a)*_computeAlignment(*ite, t, mapEdge));
        setEdge.erase(*ite);
      }
    
      std::set<MEdge, Less_Edge>::iterator ite2 = setEdge.begin();
      for (; ite2 != setEdge.end(); ite2++) {
        double sumlc = .0, u[2], v[2];
        MVertex *vert[2];
        for (int i = 0; i < 2; i++) {
          vert[i] = ite2->getVertex(i);
          vert[i]->getParameter(0, u[i]);
          vert[i]->getParameter(1, v[i]); // Warning : should check if vertex on face or on edge
          std::map<MVertex*,double>::iterator itlc = v2lcUV.find(vert[i]);
          if (itlc == v2lcUV.end()) {
            sumlc += v2lcUV[vert[i]] = BGM_MeshSize(gf, u[i], v[i], vert[i]->x(), vert[i]->y(), vert[i]->z());
          }
          else
            sumlc += itlc->second;
        }
    
        sumlc = .2; // FIXME BGM_MeshSize returns wrong meshsize
    
        double length = _computeEdgeLength(gf, vert, u, v, 0);
        double a = .0;
        _boundEdgeValue += length / sumlc * (a + (2-a)*_computeAlignment(*ite2, t, mapEdge));
        _boundEdgeValue = 1;
      }
      _boundEdgeValue /= 2.;
      _numboundEdge = 2;
    
      _vertices = new Rec2d_vertex*[_numBoundVert];
      std::list<Rec2d_vertex*>::iterator itv = v.begin();
      for (int k = 0; itv != v.end() && k < _numBoundVert; itv++, k++)
        _vertices[k] = *itv;
      for (_numEmbVert = 0; itv != v.end(); itv++, _numEmbVert++)
        _embVertValue += (*itv)->getReward();
    
      _computation = _RECOMPUTE - 1;
    }
    
    
    double TrianglesUnion::_computeEdgeLength(GFace *gf, MVertex **vert,
                                              double *u, double *v, int n)
    {
      double dx, dy, dz, l = .0;
      if (n == 0) {
        dx = vert[1]->x() - vert[0]->x();
        dy = vert[1]->y() - vert[0]->y();
        dz = vert[1]->z() - vert[0]->z();
        l = sqrt(dx * dx + dy * dy + dz * dz);
      }
      else if (n == 1) {
        double edgeCenter[2] ={(u[0] + u[1]) * .5, (v[0] + v[1]) * .5};
        GPoint GP = gf->point (edgeCenter[0], edgeCenter[1]);
        dx = vert[1]->x() - GP.x();
        dy = vert[1]->y() - GP.y();
        dz = vert[1]->z() - GP.z();
        l += sqrt(dx * dx + dy * dy + dz * dz);
        dx = vert[0]->x() - GP.x();
        dy = vert[0]->y() - GP.y();
        dz = vert[0]->z() - GP.z();
        l += sqrt(dx * dx + dy * dy + dz * dz);
      }
      else {
        Msg::Warning("[meshRecombine2D] edge length computation not implemented for n=%d, returning 0", n);
        return .0;
      }
      return l;
    }
    double TrianglesUnion::_computeAlignment(const MEdge &e, std::list<MTriangle*> &lt,
                                             std::map<MEdge, std::list<MTriangle*>, Less_Edge> &mapEdge)
    {
      std::list<MTriangle*>::iterator itlt = lt.begin();
      //if (lt.size() == 2)
      //  return Temporary::compute_alignment(e, *itlt, *(++itlt));
    
      MVertex *v0 = e.getVertex(0);
      MVertex *v1 = e.getVertex(1);
      MTriangle *tris[2];
      int k = 0;
      for (; itlt != lt.end(); itlt++) {
        MTriangle *t = *itlt;
        if ((t->getVertex(0) == v0 || t->getVertex(1) == v0 || t->getVertex(2) == v0) &&
            (t->getVertex(0) == v1 || t->getVertex(1) == v1 || t->getVertex(2) == v1)   )
          tris[k++] = t;
      }
      if (k < 2) {
        k = 0;
        std::map<MEdge, std::list<MTriangle*> >::iterator itmEdge = mapEdge.find(e);
        if (itmEdge == mapEdge.end()) {
          Msg::Info("g po :( (szie %d)", mapEdge.size());
          return .0;
        }
        itlt = itmEdge->second.begin();
        int num = 0;
        for (; itlt != itmEdge->second.end(); itlt++) {
          MTriangle *t = *itlt;
          if ((t->getVertex(0) == v0 || t->getVertex(1) == v0 || t->getVertex(2) == v0) &&
              (t->getVertex(0) == v1 || t->getVertex(1) == v1 || t->getVertex(2) == v1)   )
            tris[k++] = t;
        }
      }
      if (k < 2 || k > 2) {
        //Msg::Warning("[meshRecombine2D] error in alignment computation, returning 1");
        return 1.;
      }
      return Temporary::compute_alignment(e, tris[0], tris[1]);
    }
    void TrianglesUnion::_update()
    {
      if (_computation >= _RECOMPUTE)
        return;
      double alpha = _ValVert - _embVertValue;
      for (int i = 0; i < _numBoundVert; i++) {
        alpha += _vertices[i]->getReward(-1);
      }
      alpha /= _NumVert - _numEmbVert;
      double beta = (_ValEdge - _embEdgeValue + _boundEdgeValue) / (_NumEdge - _numEmbEdge + _numboundEdge);
      _globValIfExecuted = alpha * alpha * beta;
    
      _computation = _RECOMPUTE;
    }
    
    MQuadrangle *TrianglesUnion::createQuad() const
    {
      std::list<MEdge> listBoundEdge;
      {
        std::multiset<MEdge, Less_Edge> msetEdge;
        for (int i = 0; i < _numTri; i++) {
          MTriangle *t = _triangles[i];
          for (int i = 0; i < 3; i++) {
            msetEdge.insert(t->getEdge(i));
          }
        }
        std::multiset<MEdge>::iterator itEdge = msetEdge.begin();
        MEdge me = *(itEdge++);
        bool precWasSame = false;
        for (; itEdge != msetEdge.end(); itEdge++) {
          if (*itEdge == me)
            precWasSame = true;
          else if (precWasSame)
            precWasSame = false;
          else
            listBoundEdge.push_back(me);
          me = *itEdge;
        }
        if (!precWasSame)
          listBoundEdge.push_back(me);
      }
      if (listBoundEdge.size() != 4)
        Msg::Warning("[meshRecombine2D] Not 4 edges !");
    
      MVertex *v1, *v2, *v3, *v4;
      v1 = listBoundEdge.begin()->getMinVertex();
      v2 = listBoundEdge.begin()->getMaxVertex();
      std::list<MEdge>::iterator it = listBoundEdge.begin();
      for (it++; it != listBoundEdge.end(); it++) {
        if (v2 == it->getMinVertex()) {
          v3 = it->getMaxVertex();
          listBoundEdge.erase(it);
          break;
        }
        if (v2 == it->getMaxVertex()) {
          v3 = it->getMinVertex();
          listBoundEdge.erase(it);
          break;
        }
      }
      for (it = listBoundEdge.begin(); it != listBoundEdge.end(); it++) {
        if (v3 == it->getMinVertex()) {
          v4 = it->getMaxVertex();
          break;
        }
        if (v3 == it->getMaxVertex()) {
          v4 = it->getMinVertex();
          break;
        }
      }
    
      return new MQuadrangle(v1, v2, v3, v4);
    }
    
    void TrianglesUnion::addTri(std::set<MTriangle*> &setTri) const
    {
      for (int i = 0; i < _numTri; ++i)
        setTri.insert(_triangles[i]);
    }
    
    void TrianglesUnion::removeTri(std::set<MTriangle*> &setTri) const
    {
      for (int i = 0; i < _numTri; ++i)
        setTri.erase(_triangles[i]);
    }
    
    bool TrianglesUnion::isIn(std::set<MTriangle*> &setTri) const
    {
      for (int i = 0; i < _numTri; ++i)
      if (setTri.find(_triangles[i]) != setTri.end())
        return true;
      return false;
    }
    
    void TrianglesUnion::addInfluence(int *num, double *val, std::map<Rec2d_vertex*, int> &mapVert) const
    {
      num[0] += _numEmbVert;
      num[1] += _numEmbEdge;
      num[1] -= _numboundEdge;
      val[0] += _embVertValue;
      val[1] += _embEdgeValue;
      val[1] -= _boundEdgeValue;
      for (int i = 0; i < _numBoundVert; ++i) {
        if (mapVert.find(_vertices[i]) == mapVert.end())
          mapVert[_vertices[i]] = -1;
        else
          mapVert[_vertices[i]] -= 1;
      }
    }
    
    void TrianglesUnion::removeInfluence(int *num, double *val, std::map<Rec2d_vertex*, int> &mapVert) const
    {
      num[0] -= _numEmbVert;
      num[1] -= _numEmbEdge;
      num[1] += _numboundEdge;
      val[0] -= _embVertValue;
      val[1] -= _embEdgeValue;
      val[1] += _boundEdgeValue;
      for (int i = 0; i < _numBoundVert; ++i) {
        mapVert[_vertices[i]] += 1;
      }
    }
    
    double TrianglesUnion::computeReturn(const int *num,
                                         const double *val,
                                         const std::map<Rec2d_vertex*, int> &mapVert)
    {
      double alpha = _ValVert - val[0];
      std::map<Rec2d_vertex*, int>::const_iterator it = mapVert.begin();
      for (; it != mapVert.end(); ++it) {
        alpha += it->first->getReward(it->second);
      }
      alpha /= _NumVert - num[0];
      double beta = (_ValEdge - val[1]) / (_NumEdge - num[1]);
      return alpha * alpha * beta;
    }
    
    bool TrianglesUnion::operator<(TrianglesUnion &other)
    {
      _update();
      other._update();
      return _globValIfExecuted < other._globValIfExecuted;
    }
    
    bool lessTriUnion::operator()(TrianglesUnion *tu1, TrianglesUnion *tu2) const
    {
      return *tu1 < *tu2;
    }
    
    bool lessTriUnionInv::operator()(TrianglesUnion *tu1, TrianglesUnion *tu2) const
    {
      return *tu2 < *tu1;
    }
    
    /*map tri to recomb
    //map edge to double value (constructor)
    set Recomb sorted
    function best(copy vertex*[], copy set Recomb sorted);
    
    construction :
     - list of vertex
     - set of recomb
     - map tri to recomb
    
    destruction :
     - vertices, recomb
    
    execution :
     - take best recomb
     - determine recomb to execute
     - maj E N e n
     - reduce maptrirecomb, setrecomb
     - sort setrecomb*/