Skip to content
Snippets Groups Projects
Select Git revision
  • 298d74b3c28a96c6c074008e97a5db10fffd7604
  • master default protected
  • patch_releases_4_14
  • overlaps_tags_and_distributed_export
  • overlaps_tags_and_distributed_export_rebased
  • relaying
  • alphashapes
  • steplayer
  • bl
  • pluginMeshQuality
  • fixBugsAmaury
  • hierarchical-basis
  • new_export_boris
  • oras_vs_osm
  • reassign_partitions
  • distributed_fwi
  • rename-classes
  • fix/fortran-api-example-t4
  • robust_partitions
  • reducing_files
  • fix_overlaps
  • gmsh_4_14_0
  • gmsh_4_13_1
  • gmsh_4_13_0
  • gmsh_4_12_2
  • gmsh_4_12_1
  • gmsh_4_12_0
  • gmsh_4_11_1
  • 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
41 results

GModelIO_SU2.cpp

Blame
  • meshGFaceQuadrilateralize.cpp 17.48 KiB
    // Gmsh - Copyright (C) 1997-2013 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@geuz.org>.
    
    #include "meshGFaceQuadrilateralize.h"
    #include "GmshMessage.h"
    #include "Numeric.h"
    #include "GFace.h"
    #include "meshGFaceDelaunayInsertion.h"
    #include "meshGFaceOptimize.h"
    #include "meshGFaceBDS.h"
    #include "BDS.h"
    #include "SVector3.h"
    
    class edgeFront {
     public:
      typedef std::set<BDS_Edge *>::const_iterator eiter;
     private:
      BDS_Mesh *m;
      GFace *gf;
      void getFrontEdges(BDS_Point *p, eiter & it1, eiter & it2) const;  
      void getFrontEdges(BDS_Point *p, std::vector<eiter> & f) const;
     public:
      std::set<BDS_Edge *> edges;  
      std::set<BDS_Edge*> stat[5];
      eiter begin() { return edges.begin(); }
      eiter end() { return edges.end(); }
      edgeFront(BDS_Mesh *_m, GFace *_gf) : m(_m), gf(_gf) {}
      // initiate edges in the front i.e.
      // take all edges that have one neighbor 
      // and all edges that have a quad and a triangle 
      // neighbor
      void initiate();
      // compute normal vector to an edge that points
      // inside the domain
      SVector3 normal(BDS_Edge *e) const;    
      // compute the state of a front edge
      // 0 both vertices have edge angles < 60 deg 
      // 1 e->p1 have and edge angle > 60 deg 
      // 2 e->p2 have and edge angle > 60 deg 
      // 3 both vertices have edge angles > 60 deg 
      int computeStatus(BDS_Edge *e) const;
      inline bool inFront(BDS_Edge *e) const{ return getStatus(e) != -1; }
      inline int getStatus(BDS_Edge *e) const{
        for(int i = 0; i < 5; i++){
          if(stat[i].find(e) != stat[i].end()) return i;
        }
        return -1;
      }
      // get one edge of the front that is tagged "tag"
      // and do whatever has to be done to remove it from
      // the front/tag. return false if the front is not empty.
      bool emptyFront(int tag);
      // update the status of the edge
      void updateStatus(BDS_Edge *e);
      // form a quad now
      bool formQuad(BDS_Edge *e, BDS_Edge *left, BDS_Edge *right);
      // delete the cavity delimitated by 4 edges
      void emptyCavity(BDS_Edge *bottom, BDS_Edge *top, BDS_Edge *left, BDS_Edge *right);
      // delete an edge from the front
      void deleteFromFront(BDS_Edge *e)
      {
        edges.erase(e);
        for(int i = 0; i < 5; i++){
          std::set<BDS_Edge*>::iterator it = stat[i].find(e);
          if(it != stat[i].end()){
            stat[i].erase(it);
            return;
          }
        }
      }
      // taking a point from the front, find the optimal edge
      BDS_Edge *findOptimalEdge(BDS_Point *p, BDS_Point *avoid);
    };
    
    void edgeFront::updateStatus(BDS_Edge *e)
    {
      for(int i = 0; i < 5; i++){
        std::set<BDS_Edge*>::iterator it = stat[i].find(e);
        if(it !=stat[i].end()){
          stat[i].erase(it);
          stat[computeStatus(e)].insert(e);
          return;
        }
      }
      Msg::Error("Something wrong in updateStatus");
    }
    
    SVector3 norm_edge(BDS_Point *p1, BDS_Point *p2)
    {
      SVector3 n(p2->X-p1->X,p2->Y-p1->Y,p2->Z-p1->Z);
      n.normalize();
      return n;
    }
    
    void recur_empty_cavity(BDS_Face *f,
                            BDS_Edge   *be[4],
                            BDS_Point *bv[4],
                            std::set<BDS_Face*> & faces, 
                            std::set<BDS_Edge*> & edges, 
                            std::set<BDS_Point*> & vertices)
    {
      if(faces.find(f) != faces.end()) return;
      faces.insert(f);
      BDS_Edge *ee[3] = {f->e1,f->e2,f->e3};
      for(int i=0;i<3;i++){
        BDS_Edge *e = ee[i];
        if(e != be[0] && e != be[1] && e != be[2] && e != be[3]){
          edges.insert(e);
          BDS_Face *of = e->otherFace(f);
          recur_empty_cavity(of,be,bv,faces,edges,vertices);
        }
      }
    }
    
    void edgeFront::emptyCavity(BDS_Edge *bottom, BDS_Edge *top, BDS_Edge *left, 
                                BDS_Edge *right)
    {
      // not optimal for now, will be improved further away
      BDS_Face *f = 0;
      if(bottom->faces(0) && bottom->faces(0)->numEdges() == 3) f=bottom->faces(0);
      else if(bottom->faces(1))f = bottom->faces(1);
    
      std::set<BDS_Face*> m_faces;
      std::set<BDS_Edge*> m_edges;
      std::set<BDS_Point*> m_vertices;
      BDS_Edge   *be[4] = {bottom,top,left,right};
      BDS_Point *bv[4] = {bottom->commonvertex(left),
                          left->commonvertex(top),
                          top->commonvertex(right),
                          right->commonvertex(bottom)};
    
      recur_empty_cavity(f, be, bv, m_faces, m_edges, m_vertices);
      //  printf("%d edges %d faces\n",m_edges.size(),m_faces.size());
      for(std::set<BDS_Face*>::iterator it = m_faces.begin(); 
          it != m_faces.end(); ++it) m->del_face(*it);
      for(std::set<BDS_Edge*>::iterator it = m_edges.begin(); 
          it != m_edges.end(); ++it) m->del_edge(*it);
    }
    
    
    SVector3 edgeFront::normal(BDS_Edge*e) const
    {
      BDS_Face *t = e->faces(0);
      if(e->numfaces() == 2 && e->faces(1)->numEdges() == 3)t=e->faces(1);
    
      /*
        points p1, p2 and p3
        p3 does NOT belong to the edge
        p = p1 (1-u-v) + p2 u + p3 v;
        J = [p2-p1 p3-p1 (p2-p1)x(p3-p1)]
        N = - J^-1 * {0,1,0}
        n = N/|N|    
       */
      BDS_Point *p1 = e->p1;
      BDS_Point *p2 = e->p2;
      BDS_Point *p3;
      if(e == t->e1)
        p3 = t->e2->commonvertex(t->e3);
      else if(e == t->e2)
        p3 = t->e1->commonvertex(t->e3);
      else if(e == t->e3)
        p3 = t->e2->commonvertex(t->e1);
      else {
        Msg::Error("Could not compute fron normal");
        return SVector3();
      }
      
      SVector3 t1(p2->X-p1->X,p2->Y-p1->Y,p2->Z-p1->Z);
      SVector3 t2(p3->X-p1->X,p3->Y-p1->Y,p3->Z-p1->Z);
      SVector3 t3 = crossprod(t1,t2);
      double m[3][3] = {{t1.x(),t2.x(),t3.x()},
                        {t1.y(),t2.y(),t3.y()},
                        {t1.z(),t2.z(),t3.z()}};
      double im[3][3];
      inv3x3(m,im);
      SVector3 n(im[1][0],im[1][1],im[1][2]);
      n.normalize();
      return n;
    }
    
    void edgeFront::getFrontEdges(BDS_Point *p, std::vector<eiter> & fe) const
    {
      for(std::list<BDS_Edge*>::iterator itp = p->edges.begin(); 
          itp != p->edges.end(); ++ itp){
        eiter it = edges.find(*itp); 
        if(it != edges.end())
          fe.push_back(it);
      }
    }
    
    void edgeFront::getFrontEdges(BDS_Point *p, eiter & it1, eiter & it2) const
    {
      int count = 0;
      for(std::list<BDS_Edge*>::iterator itp = p->edges.begin(); 
          itp != p->edges.end(); ++ itp){
        if(count == 0){
          it1 = edges.find(*itp); 
          if(it1 != edges.end()) count++;
        }
        else if(count == 1){
          it2 = edges.find(*itp); 
          if(it2 != edges.end()) return;
        }
      }  
      Msg::Error("point %d is in the front but has only %d edges\n",p->iD,count);
    }
    
    void edgeFront::initiate()
    {
      edges.clear();
      for(int i = 0; i < 5; i++) stat[i].clear();
      std::list<BDS_Edge*>::iterator it = m->edges.begin();
      while(it != m->edges.end()){
        if(((*it)->numfaces() == 1 && (*it)->faces(0)->e4 == 0) ||
            ((*it)->numfaces() == 2 && (*it)->numTriangles() == 1)) {
          edges.insert(*it);
        }
        ++it;
      }
      for(eiter it2 = begin(); it2 !=end(); ++it2){
        int status = computeStatus(*it2);
        stat[status].insert(*it2);
      }
    }
    
    static double angle3Points(BDS_Point *p1, BDS_Point *p2, BDS_Point *p3)
    {
      SVector3 a(p1->X - p2->X, p1->Y - p2->Y, p1->Z - p2->Z);
      SVector3 b(p3->X - p2->X, p3->Y - p2->Y, p3->Z - p2->Z);
      SVector3 c = crossprod(a,b);
      double sinA = c.norm();
      double cosA = dot(a,b);
      //  printf("%d %d %d -> %g %g\n",p1->iD,p2->iD,p3->iD,cosA,sinA);
      return atan2(sinA, cosA);
    }
    
    int edgeFront::computeStatus(BDS_Edge *e) const
    {
      eiter it11, it12, it21,it22;
      getFrontEdges(e->p1, it11, it12);  
      getFrontEdges(e->p2, it21, it22);  
      
      BDS_Edge *e1 = (*it11) == e ? *it12 : *it11;
      BDS_Edge *e2 = (*it21) == e ? *it22 : *it21;
      
      double angle1 = angle3Points((*it11)->othervertex(e->p1), e->p1,
                                   (*it12)->othervertex(e->p1));
      double angle2 = angle3Points((*it21)->othervertex(e->p2), e->p2,
                                   (*it22)->othervertex(e->p2));
    
      SVector3 n1 = normal(e);
      SVector3 n2 = norm_edge(e->p1, e1->othervertex(e->p1));
      SVector3 n3 = norm_edge(e->p2, e2->othervertex(e->p2));
      if(dot(n1,n2) < 0)angle1 = M_PI;
      if(dot(n1,n3) < 0)angle2 = M_PI;
    
      const double angleLimit = 3 * M_PI/4.;
    
      if(angle1 > angleLimit && angle2 > angleLimit) return 0;
      if(angle1 > angleLimit && angle2 < angleLimit) return 1;
      if(angle1 < angleLimit && angle2 > angleLimit) return 2;
      return 3;
    }
    
    bool edgeFront::formQuad(BDS_Edge *e, BDS_Edge *left, BDS_Edge *right)
    {
    
      printf("e (%d,%d), l(%d,%d), r(%d,%d)\n",
             e->p1->iD,e->p2->iD,
             left->p1->iD,left->p2->iD,
             right->p1->iD,right->p2->iD);
      
      //  outputScalarField(m->triangles, "deb_before.pos", 0);
    
      std::vector<BDS_Point*> toUpdate;
    
      BDS_Point *pleft  = left->othervertex(e->p1);
      BDS_Point *pright = right->othervertex(e->p2);
      
      // recover edge pleft->pright
      BDS_Edge *top = m->find_edge(pleft,pright);
    
      /*
        We first have to ensure that, if left or right
        are closing the front, then even number of edges should remain in
        both left and right parts of the front
       */
    
      if(!top) {
        //    printf("recover\n");
        //    top = m->recover_edge_fast(pleft,pright);
        //    if(!top)
        bool _fatallyFailed;
        top = m->recover_edge(pleft->iD, pright->iD,_fatallyFailed);
        //    printf("recover done %p\n",top);
        if(!top) return false;
      }
      // delete internal triangles
      emptyCavity(e, top, left, right);
      // add the quad
      m->add_quadrangle(e, left, top, right);
      // update the edge status
      // bottom edge leaves the front
      deleteFromFront(e);
      // top edge becomes part of the front
    
      /*  printf("(%d,%d),(%d,%d),(%d,%d),(%d,%d)\n",
             e->p1->iD,e->p2->iD,
             left->p1->iD,left->p2->iD,
             top->p1->iD,top->p2->iD,
             right->p1->iD,right->p2->iD);
      */
      //  outputScalarField(m->triangles, "deb.pos", 0);
    
    
      // if left edge was in the front, then it leaves the front
      // because it has either 2 neighboring quads or one quad
      // and the void
      // if the left edge was not in the front, then it becomes
      // part of it. 
      //  printf("coucou1\n");
      if(inFront(left)) deleteFromFront(left);
      else edges.insert(left);
    
      //  printf("coucou2\n");
      if(inFront(right)) deleteFromFront(right);
      else edges.insert(right);
    
      //  printf("coucou3\n");
      if(inFront(top)) deleteFromFront(top);
      else edges.insert(top);
      
      toUpdate.push_back(e->p1);
      toUpdate.push_back(e->p2);
      toUpdate.push_back(pleft);
      toUpdate.push_back(pright);
    
      for(unsigned int i = 0; i < toUpdate.size(); i++){
        toUpdate[i]->config_modified = true;
        //bool done = 
        m->smooth_point_parametric(toUpdate[i], gf);
        //    printf("smooth done %d (g %d)\n",done,toUpdate[i]->g->classif_degree);
      }
    
      for(unsigned int i = 0; i < toUpdate.size(); i++){
        BDS_Point *p = toUpdate[i];
        for(std::list<BDS_Edge*>::iterator itp = p->edges.begin(); 
            itp != p->edges.end(); ++ itp){
          if(inFront(*itp)){
            updateStatus(*itp);     
          } 
        }
      }  
      return true;
    }
    
    BDS_Edge *edgeFront::findOptimalEdge(BDS_Point *p, BDS_Point *avoid)
    {
      eiter it1, it2;
      getFrontEdges(p, it1, it2);
      // compute bissector of front edges, this is the optimal direction
      SVector3 n1 = normal(*it1);
      SVector3 n2 = normal(*it2);
      SVector3 n = n1 + n2;
      n.normalize();
    
      //  printf("POINT %g %g %g N %g %g %g\n",p->X,p->Y,p->Z,n.x(),n.y(),n.z());
      
      double lowerBound = cos(M_PI / 6.0);
      BDS_Edge *found = 0;
      for(std::list<BDS_Edge*>::iterator itp = p->edges.begin(); 
          itp != p->edges.end(); ++ itp){
        // the edge is not in the front and is not bounded by quads only
        if(*it1 != *itp && *it2 != *itp && (*itp)->numTriangles()){
          BDS_Point *q = (*itp)->othervertex(p);
          SVector3 d(q->X - p->X, q->Y - p->Y, q->Z - p->Z);
          d.normalize();
          double COS = dot(n,d);
          if(COS > lowerBound && q != avoid){
            lowerBound = COS;
            found = *itp;
          } 
        }    
      }
      if(found) return found;
      else{
        std::list<BDS_Face*> ts;
        double x[2];
        const double L = 0.5*sqrt(3.0)*((*it2)->length() * (*it1)->length());
        p->getTriangles(ts);
        std::list<BDS_Face*>::iterator it = ts.begin();
        std::list<BDS_Face*>::iterator ite = ts.end();
        while(it != ite) {
          BDS_Face *t = *it;
          if(!t->e4){
            BDS_Edge *e = t->oppositeEdge(p);
            if(e->numfaces() == 2){
              BDS_Face *f = e->otherFace(t);
              if(!f->e4){
                BDS_Point *target = f->oppositeVertex(e);
                // ONLY WORKS IN 2D for now !!!!!!!!!!!!!!!!!!!
                Intersect_Edges_2d(e->p1->X, e->p1->Y,
                                   e->p2->X, e->p2->Y,
                                   p->X, p->Y,
                                   p->X + n.x(), p->Y + n.y(), x);
                if(x[0] >= 0 && x[0] <= 1){
                  SVector3 d(target->X-p->X,target->Y-p->Y,target->Z-p->Z);
                  d.normalize();
                  double COS = dot(n,d);
                  double L2 = sqrt((target->X - p->X) *(target->X - p->X) +
                                   (target->X - p->Y) *(target->X - p->Y) +
                                   (target->X - p->Z) *(target->X - p->Z) );
                  
                  // swapping the edge alllow to find an edgge that has the right direction and
                  // right size
                  if(COS > cos(M_PI/6.0) && L2 < L){
                    m->swap_edge(e, BDS_SwapEdgeTestQuality(false,false));
                    BDS_Edge *newE = m->find_edge(p,target);
                    //            printf("swapping -> %p\n",newE);
                    return newE;          
                  }
                  // split the edge
                  else{          
                    BDS_Point *mid;
                    mid  = m->add_point(++m->MAXPOINTNUMBER,(1.-x[0])*e->p1->u + x[0]*e->p2->u,
                                        (1.-x[0])*e->p1->v + x[0]*e->p2->v,gf);
                    mid->lc() = 0.5 * (p->lc() +  target->lc());
                    mid->g = e->p1->g;
                    m->split_edge(e, mid);
                    BDS_Edge *newE = m->find_edge(p,mid);
                    //            printf("splitting -> %p %p\n",newE,e->p1->g);
                    //            m->cleanup();
                    return newE;
                  }
                }
              }
            }
          }
          ++it;
        }    
      }
      printf("zarbi\n");
      return 0;
    }
    
    bool edgeFront::emptyFront(int tag)
    {
      // front edges tagged "tag" is empty
      if(stat[tag].size() == 0) return true;
      BDS_Edge *e = *(stat[tag].begin());
      BDS_Edge *left, *right = 0;
      eiter it1, it2;
    
      std::vector<eiter> fe1, fe2;
     
      printf("front edges %d %d tag %d\n", e->p1->iD, e->p2->iD, tag);
    
      switch(tag){
        // both left and right neighboring edges are
        // sufficiently angled in order to allow to
        // form the quad
      case 3:
        {
          getFrontEdges(e->p1, it1, it2);
          if(*it1 == e) left=*it2;
          else left = *it1;
          getFrontEdges(e->p2, it1, it2);
          if(*it1 == e) right = *it2;
          else right = *it1;
          //      printf("case 3\n");
        }
        break;
        // right edge is angled with current edge
        // we therefore find a new front edge in the
        // mesh that allows to move to tag 3
      case 2:
        getFrontEdges(e->p1, it1, it2);
        if(*it1 == e) left = *it2;
        else left = *it1;
        //    printf("case 2 left edge %p\n",left);
        right = findOptimalEdge(e->p2, left->othervertex(e->p1));
        if(right) getFrontEdges(right->othervertex(e->p2), fe2);
        break;
        // left edge is angled with current edge
        // we therefore find a new front edge in the
        // mesh that allows to move to tag 3
      case 1:
        getFrontEdges(e->p2, it1, it2);
        if(*it2 == e) right = *it1;
        else right = *it2;
        //    printf("case 1 right edge %p %p\n",e,right);
        left = findOptimalEdge(e->p1, right->othervertex(e->p2));
        if(left) getFrontEdges(left->othervertex(e->p1), fe1);
        break;
        // no neighboring edge is angled with current edge
        // we therefore find a new front edge in the
        // mesh that allows to move to tag 3
      case 0:
        left = findOptimalEdge(e->p1, 0);
        if(left) right= findOptimalEdge(e->p2, left->othervertex(e->p1));
        if(right) getFrontEdges(right->othervertex(e->p2), fe2);
        if(left) getFrontEdges(left->othervertex(e->p1), fe1);
        //    printf("strange\n");
        break;
      default:
        Msg::Error("Unknown case in emptyFront");
        return false;
      }
    
      if(fe1.size() || fe2.size() || !left || !right || !formQuad(e, left, right)){
        //    printf("front cloeses : algo has to be finished\n");
        stat[tag].erase(stat[tag].begin());
        stat[4].insert(e);
      }
      return false;
    }
    
    static int numQuads(BDS_Mesh *m)
    {
      int N = 0;
      for(std::list<BDS_Face*>::iterator it = m->triangles.begin();
          it != m->triangles.end(); ++it){
        if((*it)->e4) N++;
      }
      return N;
    }
    
    int gmshQMorph(GFace *gf)
    {
      // assert first that there exist a triangulation of
      // the face  
      if(!gf->triangles.size()){
        Msg::Warning("Cannot Quadrilaterize a face that has not been triangulated");
        return -1;
      }
    
      // create data structures for mesh manipulations
      std::list<GFace*> l; l.push_back(gf);
      BDS_Mesh *pm = gmsh2BDS(l);
    
      // create the front
      edgeFront front(pm,gf);
      front.initiate();
      
      int ITER = 1;
      
      // empty the front for front edges tagged 3, 2, 1 then 0
      int _numQuads = 0;
      while(1){
        if(front.emptyFront(3)){
          if(front.emptyFront(2)){
            if(front.emptyFront(1)){
              if(front.emptyFront(0)){
                int ns;
                smoothVertexPass(gf,*pm,ns,false);
                printf("nex row iter %6d->>>\n",ITER);
                front.initiate();
                int _numQuadsNew = numQuads(pm);
                if(front.edges.size() == 0 || _numQuads == _numQuadsNew)
                  break;
                _numQuads = _numQuadsNew;
              }
            }
          }
        }
        ITER++;
        if(1 || ITER%100 == 0){
          char name[256];
          sprintf(name,"qmorph-face%d-iter%d.pos",gf->tag(),ITER);
          outputScalarField(pm->triangles, name, 0);
        }
        //    if(ITER == 1123)break;
      }
      // delete the BDS
      delete pm;
      return 1;
    }