Skip to content
Snippets Groups Projects
Select Git revision
  • 1954cb29afbfb5edadf26ccf21db1cbe2076c4d9
  • master default protected
  • alphashapes
  • quadMeshingTools
  • cygwin_conv_path
  • macos_arm64
  • add-transfiniteautomatic-to-geo
  • patch_releases_4_10
  • HierarchicalHDiv
  • isuruf-master-patch-63355
  • hyperbolic
  • hexdom
  • hxt_update
  • jf
  • 1618-pythonocc-and-gmsh-api-integration
  • octreeSizeField
  • hexbl
  • alignIrregularVertices
  • getEdges
  • patch_releases_4_8
  • isuruf-master-patch-51992
  • gmsh_4_11_0
  • gmsh_4_10_5
  • gmsh_4_10_4
  • gmsh_4_10_3
  • gmsh_4_10_2
  • gmsh_4_10_1
  • gmsh_4_10_0
  • gmsh_4_9_5
  • gmsh_4_9_4
  • gmsh_4_9_3
  • gmsh_4_9_2
  • gmsh_4_9_1
  • gmsh_4_9_0
  • gmsh_4_8_4
  • gmsh_4_8_3
  • gmsh_4_8_2
  • gmsh_4_8_1
  • gmsh_4_8_0
  • gmsh_4_7_1
  • gmsh_4_7_0
41 results

meshRecombine2D_2.cpp

Blame
  • Forked from gmsh / gmsh
    13446 commits behind the upstream repository.
    Amaury Johnan's avatar
    Amaury Johnen authored
    No commit message
    1954cb29
    History
    meshRecombine2D_2.cpp 16.27 KiB
    // 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 "BackgroundMesh.h"
    #include "GFace.h"
    #include <cmath>
    #include <FL/Fl.H>
    #include "drawContext.h"
    #include "FlGui.h"
    #include "Context.h"
    #include "OpenFile.h"//pas propre
    
    static int HORIZ = 20;
    
    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;
    
    Recombine2D::Recombine2D(GFace *gf)
    : _horizon(0), _gf(gf), _benef(.0), _applied(true)
    {
      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;
      for (unsigned int i = 0; i < gf->triangles.size(); i++) {
        MTriangle *t = gf->triangles[i];
        for (int j = 0; j < 3; j++) {
          mapVert[t->getVertex(j)].push_back(t);
          mapEdge[t->getEdge(j)].push_back(t);
        }
      }
      
      // Create the '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)
          fourTri.push_back(itvert);
        Rec2d_vertex *n = new Rec2d_vertex((*itvert).first, (*itvert).second, mapCornerVert);
        itV2N = mapV2N.insert(itV2N, std::make_pair((*itvert).first,n));
        TrianglesUnion::_NumVert++;
        TrianglesUnion::_ValVert += n->getReward();
      }
      
      // store mesh size and parametric coordinates 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);
        _setQuads.push_back(new TrianglesUnion(gf, (*(*it4)).second, listEmbEdge, listVert, mapV2LcUV));
      }
      
      // 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);
          _setQuads.push_back(tu);
          TrianglesUnion::_NumEdge++;
          TrianglesUnion::_ValEdge += tu->getEdgeValue();
        }
        else
          Msg::Info("[bord] %d", (*itedge).second.size());
      }
      _setQuads.sort(lessTriUnion());
      
      _recombine(true);
      _applied = true;*/
    }
    
    
    void Recombine2D::_recombine(bool a)
    { 
      int i = 0;
      while (!_setQuads.empty()) {
        Msg::Info("%d",i);
        std::list<TrianglesUnion*>::iterator it = _setQuads.begin();
        
        (*it)->select();
        
        _quads.push_back((*it)->createQuad());
        
        _removeImpossible(it);
        
        _setQuads.sort(lessTriUnion());
        i++;
      }
      Msg::Info("Done %d (%d)", i, _pairs.size());
    }
    
    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()->getMinVertex();
      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);
    }
    
    
    int Recombine2D::apply(bool a)
    {
      if (!_haveParam || _applied) return 0;
      
      std::vector<MTriangle*> triangles2;
      for (int i = 0; i < _gf->triangles.size(); i++) {
        delete _gf->triangles[i];
      }
      _gf->triangles = triangles2;
      _gf->quadrangles = _quads;
      
      _applied = true;
      return 1;
    }
    
    void Recombine2D::_removeImpossible(std::list<TrianglesUnion*>::iterator it)
    {
      std::set<MTriangle *> touched;
      
      for (int i = 0; i < (*it)->getNumTriangles(); i++) {
        touched.insert((*it)->getTriangle(i));
      }
      
      for (it = _setQuads.begin(); 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)
          _setQuads.erase(it++);
        else
          it++;
      }
    }
    
    
    
    Rec2d_vertex::Rec2d_vertex(MVertex *v,
                               std::list<MTriangle*> &setTri,
                               std::map<MVertex*, std::set<GEdge*> > &mapVert)
    : _numEl(setTri.size()), _angle(.0)
    {
      _onWhat = v->onWhat()->dim() - 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]; //AVERIFIER SI CA MARCHE
        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 = vectub;
        else if (normub > prec * normlb)
          firstDer1 = vectlb;
        else {
          Msg::Warning("[meshRecombine2D] Bad precision, returning pi/2");
          return M_PI / 2.;
        }
        if (k == 0)
          firstDer0 = firstDer1;
      }
      
      Msg::Info("-- %lf, %lf, %lf", norm(firstDer0), norm(firstDer1), dot(firstDer0, firstDer1));
      double n = 1 / norm(firstDer0);
      firstDer0 = firstDer0 * n;
      n = 1 / norm(firstDer1);
      firstDer1 = firstDer1 * n;
      Msg::Info("--Angles : %lf, %lf, %lf", norm(firstDer0), norm(firstDer1), dot(firstDer0, 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));
      }
      
      Msg::Info("Angles : %lf, %lf, %lf", angle1, angleMesh, angle2);
      
      return M_PI / 2.;
      
      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)
    {
      if (n == 0) return .0;
      if (_onWhat > -1) {
        if (n > 0)
          return _Vbenefs[_onWhat][_numEl-1];
        else
          return - _Vbenefs[_onWhat][_numEl-2];
      }
      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)
    {
      _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();
      for (int k = 0; itt != t.end(); itt++, k++) {
        _triangles[k] = *itt;
      }
      
      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);
          std::map<MVertex*,double*>::iterator itlc;
          if ((itlc = v2lcUV.find(vert[i])) == v2lcUV.end()) {
            double *a = new double[3];
            gf->XYZtoUV(vert[i]->x(), vert[i]->y(), vert[i]->z(), a[1], a[2], 1.);
            sumlc += a[0] = BGM_MeshSize(gf, a[1], a[2], vert[i]->x(), vert[i]->y(), vert[i]->z());
            u[i] = a[1];
            v[i] = a[2];
            v2lcUV[vert[i]] = a;
          }
          else {
            sumlc += (*itlc).second[0];
            u[i] = (*itlc).second[1];
            v[i] = (*itlc).second[2];
          }
        }
    
        double length = _computeEdgeLength(gf, vert, u, v, 0);
        _embEdgeValue += length / sumlc * (1 + _computeAlignment(*ite, t));
        Msg::Info("Edge a : %lf/%lf = %lf <-> %lf", length, sumlc / 2, 2 * length / sumlc, _computeAlignment(*ite, t));
      }
      
      _vertices = new Rec2d_vertex*[_numBoundVert];
      std::list<Rec2d_vertex*>::iterator itv = v.begin();
      for (int k = 0; itv != v.end() && k < _numBoundVert; itv++, k++) {
        _globValIfExecuted += (*itv)->getReward(-1);
        _vertices[k] = *itv;
      }
      for (_numEmbVert = 0; itv != v.end(); itv++, _numEmbVert++)
        _embVertValue += (*itv)->getReward();
      
      _computation = _RECOMPUTE - 1;
      _update();
    }
    
    
    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(MEdge &e, std::list<MTriangle*> &lt)
    {
      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 > 2) {
        Msg::Warning("[meshRecombine2D] error in alignment computation, returning 0");
        return .0;
      }
      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) / (_NumEdge - _numEmbEdge);
      _globValIfExecuted = alpha * beta;
      
      _computation = _RECOMPUTE;
    }
    bool TrianglesUnion::operator<(TrianglesUnion &other)
    {
      _update();
      other._update();
      return _globValIfExecuted < other._globValIfExecuted; 
    }
    
    bool lessTriUnion::operator()(TrianglesUnion *tu1, TrianglesUnion *tu2) const
    {
      return *tu1 < *tu2;
    }
    
    /*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*/