Skip to content
Snippets Groups Projects
Select Git revision
  • b07bc38e1f959072b6d736a49c0224bfc8ff487a
  • master default protected
  • albertpiwonski-master-patch-57409
  • quadspheres
  • fix_Tmatrix_code_epsr_background
  • albertpiwonski-master-patch-12427
  • cavity
  • c1
8 results

grating3D_data_solarcell.geo

Blame
  • BDS.cpp 35.08 KiB
    // Gmsh - Copyright (C) 1997-2017 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>.
    
    #include <stack>
    #include <math.h>
    #include <stdio.h>
    #include "GmshMessage.h"
    #include "OS.h"
    #include "robustPredicates.h"
    #include "Numeric.h"
    #include "BDS.h"
    #include "GFace.h"
    #include "meshGFaceDelaunayInsertion.h"
    #include "qualityMeasures.h"
    
    void outputScalarField(std::list<BDS_Face*> t, const char *iii, int param, GFace *gf)
    {
    
      if (gf){
        FILE* view_c = Fopen("param_c.pos","w");
        if(!view_c){
          Msg::Error("Could not open file 'param_c.pos");
          return;
        }
        fprintf(view_c,"View \"paramC\"{\n");
        std::set<MEdge,Less_Edge> all;
        std::list<BDS_Face*>::iterator tit = t.begin();
        std::list<BDS_Face*>::iterator tite = t.end();
        while(tit != tite) {
          BDS_Point *pts[4];
          if (!(*tit)->deleted){
    	(*tit)->getNodes(pts);
    	for (int j=0;j<3;j++){
    	  SPoint2 p1(pts[j]->u,pts[j]->v);
    	  SPoint2 p2(pts[(j+1)%3]->u,pts[(j+1)%3]->v);
    	  SPoint2 prev = p1;
    	  for (int k=1;k<30;k++){
    	    double t = (double)k/29;
    	    SPoint2 p = p1*(1.-t) + p2*t;
    	    GPoint pa = gf->point(p.x(),p.y());
    	    GPoint pb = gf->point(prev.x(),prev.y());
    	    fprintf(view_c,"SL(%g,%g,%g,%g,%g,%g){1,1,1};\n",pa.x(),pa.y(),pa.z(),pb.x(),pb.y(),pb.z());
    	    prev = p;
    	  }
    	}
          }
          ++tit;
        }
        fprintf(view_c,"};\n");
        fclose(view_c);
      }
    
    
      FILE *f = Fopen(iii, "w");
      if(!f){
        Msg::Error("Could not open file '%s'", iii);
        return;
      }
      fprintf(f, "View \"scalar\" {\n");
      std::list<BDS_Face*>::iterator tit = t.begin();
      std::list<BDS_Face*>::iterator tite = t.end();
      while(tit != tite) {
        BDS_Point *pts[4];
        if (!(*tit)->deleted){
          (*tit)->getNodes(pts);
          if(param)
            fprintf(f, "ST(%g,%g,%g,%g,%g,%g,%g,%g,%g){%d,%d,%d};\n",
                    pts[0]->u, pts[0]->v, 0.0,
                    pts[1]->u, pts[1]->v, 0.0,
                    pts[2]->u, pts[2]->v, 0.0,
                    pts[0]->iD, pts[1]->iD, pts[2]->iD);
          else{
            if(!gf){
              if (pts[3]){
                fprintf(f, "SQ(%g,%g,%g,%g,%g,%g,%g,%g,%g,%g,%g,%g){%d,%d,%d,%d};\n",
                        pts[0]->X, pts[0]->Y, pts[0]->Z,
                        pts[1]->X, pts[1]->Y, pts[1]->Z,
                        pts[2]->X, pts[2]->Y, pts[2]->Z,
                        pts[3]->X, pts[3]->Y, pts[3]->Z,
                        pts[0]->iD, pts[1]->iD, pts[2]->iD, pts[3]->iD);
              }
              else{
    	    if (pts[0]->iD >= 0 && pts[1]->iD  >= 0 && pts[2]->iD  >= 0)
    	      fprintf(f, "ST(%g,%g,%g,%g,%g,%g,%g,%g,%g){%d,%d,%d};\n",
    		      pts[0]->X, pts[0]->Y, pts[0]->Z,
    		      pts[1]->X, pts[1]->Y, pts[1]->Z,
    		      pts[2]->X, pts[2]->Y, pts[2]->Z,
    		      pts[0]->iD, pts[1]->iD, pts[2]->iD);
              }
            }
            else{
              if (pts[3]){
                fprintf(f, "SQ(%g,%g,%g,%g,%g,%g,%g,%g,%g,%g,%g,%g){%g,%g,%g,%g};\n",
                        pts[0]->X, pts[0]->Y, pts[0]->Z,
                        pts[1]->X, pts[1]->Y, pts[1]->Z,
                        pts[2]->X, pts[2]->Y, pts[2]->Z,
                        pts[3]->X, pts[3]->Y, pts[3]->Z,
                        gf->curvatureDiv(SPoint2(pts[0]->u, pts[0]->v)),
                        gf->curvatureDiv(SPoint2(pts[1]->u, pts[1]->v)),
                        gf->curvatureDiv(SPoint2(pts[2]->u, pts[2]->v)),
                        gf->curvatureDiv(SPoint2(pts[3]->u, pts[3]->v)));
              }
              else{
                fprintf(f, "ST(%g,%g,%g,%g,%g,%g,%g,%g,%g){%g,%g,%g};\n",
                        pts[0]->X, pts[0]->Y, pts[0]->Z,
                        pts[1]->X, pts[1]->Y, pts[1]->Z,
                        pts[2]->X, pts[2]->Y, pts[2]->Z,
                        gf->curvatureDiv(SPoint2(pts[0]->u, pts[0]->v)),
                        gf->curvatureDiv(SPoint2(pts[1]->u, pts[1]->v)),
                        gf->curvatureDiv(SPoint2(pts[2]->u, pts[2]->v)));
              }
            }
          }
        }
        ++tit;
      }
      fprintf(f, "};\n");
      fclose(f);
    }
    
    BDS_Vector::BDS_Vector(const BDS_Point &p2, const BDS_Point &p1)
      : x(p2.X - p1.X), y(p2.Y - p1.Y), z(p2.Z - p1.Z)
    {
    }
    
    static void vector_triangle(BDS_Point *p1, BDS_Point *p2, BDS_Point *p3,
                                double c[3])
    {
      double a[3] = {p1->X - p2->X, p1->Y - p2->Y, p1->Z - p2->Z};
      double b[3] = {p1->X - p3->X, p1->Y - p3->Y, p1->Z - p3->Z};
      c[2] = a[0] * b[1] - a[1] * b[0];
      c[1] = -a[0] * b[2] + a[2] * b[0];
      c[0] = a[1] * b[2] - a[2] * b[1];
    }
    
    static void vector_triangle_parametric(BDS_Point *p1, BDS_Point *p2, BDS_Point *p3,
                                           double &c)
    {
      double a[2] = {p1->u - p2->u, p1->v - p2->v};
      double b[2] = {p1->u - p3->u, p1->v - p3->v};
      c = a[0] * b[1] - a[1] * b[0];
    }
    
    void normal_triangle(BDS_Point *p1, BDS_Point *p2, BDS_Point *p3,
                         double c[3])
    {
      vector_triangle(p1, p2, p3, c);
      norme(c);
    }
    
    /*
    static double surface_triangle(BDS_Point *p1, BDS_Point *p2, BDS_Point *p3)
    {
      double c[3];
      vector_triangle(p1, p2, p3, c);
      return 0.5 * sqrt(c[0] * c[0] + c[1] * c[1] + c[2] * c[2]);
    }
    */
    
    static double surface_triangle_param(BDS_Point *p1, BDS_Point *p2, BDS_Point *p3)
    {
      double c;
      vector_triangle_parametric(p1, p2, p3, c);
      return (0.5 * c);
    }
    
    void BDS_Point::getTriangles(std::list<BDS_Face*> &t) const
    {
      t.clear();
      std::list<BDS_Edge*>::const_iterator it = edges.begin();
      std::list<BDS_Edge*>::const_iterator ite = edges.end();
      while(it != ite) {
        int NF = (*it)->numfaces();
        for(int i = 0; i < NF; ++i) {
          BDS_Face *tt = (*it)->faces(i);
          if(tt) {
            std::list<BDS_Face*>::iterator tit = t.begin();
            std::list<BDS_Face*>::iterator tite = t.end();
            int found = 0;
            while(tit != tite) {
              if(tt == *tit)
                found = 1;
              ++tit;
            }
            if(!found)
              t.push_back(tt);
          }
        }
        ++it;
      }
    }
    
    BDS_Point *BDS_Mesh::add_point(int num, double x, double y, double z)
    {
      BDS_Point *pp = new BDS_Point(num, x, y, z);
      points.insert(pp);
      MAXPOINTNUMBER = (MAXPOINTNUMBER < num) ? num : MAXPOINTNUMBER;
      return pp;
    }
    
    BDS_Point *BDS_Mesh::add_point(int num, double u, double v, GFace *gf)
    {
      GPoint gp = gf->point(u*scalingU,v*scalingV);
      BDS_Point *pp = new BDS_Point(num, gp.x(), gp.y(), gp.z());
      pp->u = u;
      pp->v = v;
      points.insert(pp);
      MAXPOINTNUMBER = (MAXPOINTNUMBER < num) ? num : MAXPOINTNUMBER;
      return pp;
    }
    
    BDS_Point *BDS_Mesh::find_point(int p)
    {
      BDS_Point P(p);
      std::set<BDS_Point *, PointLessThan>::iterator it = points.find(&P);
      if(it != points.end())
        return (BDS_Point*)(*it);
      else
        return 0;
    }
    
    BDS_Edge *BDS_Mesh::find_edge(BDS_Point *p, int num2)
    {
      std::list<BDS_Edge*>::iterator eit = p->edges.begin();
      while(eit != p->edges.end()) {
        if((*eit)->p1 == p && (*eit)->p2->iD == num2)
          return (*eit);
        if((*eit)->p2 == p && (*eit)->p1->iD == num2)
          return (*eit);
        ++eit;
      }
      return 0;
    }
    
    BDS_Edge *BDS_Mesh::find_edge(BDS_Point *p1, BDS_Point *p2)
    {
      return find_edge(p1, p2->iD);
    }
    
    BDS_Edge *BDS_Mesh::find_edge(int num1, int num2)
    {
      BDS_Point *p = find_point(num1);
      return find_edge(p, num2);
    }
    
    int Intersect_Edges_2d(double x1, double y1, double x2, double y2,
                           double x3, double y3, double x4, double y4,double x[2])
    {
    
    //   double p1[2] = {x1,y1};
    //   double p2[2] = {x2,y2};
    //   double q1[2] = {x3,y3};
    //   double q2[2] = {x4,y4};
    
    //   double rp1 = robustPredicates::orient2d(p1, p2, q1);
    //   double rp2 = robustPredicates::orient2d(p1, p2, q2);
    //   double rq1 = robustPredicates::orient2d(q1, q2, p1);
    //   double rq2 = robustPredicates::orient2d(q1, q2, p2);
    
    //   if(rp1*rp2<=0 && rq1*rq2<=0){
    // //      printf("p1 %22.15E %22.15E %22.15E %22.15E \n",x1,y1,x2,y2);
    // //      printf("p2 %22.15E %22.15E %22.15E %22.15E \n",x3,y3,x4,y4);
    // //      printf("or %22.15E %22.15E %22.15E %22.15E\n",rp1,rp2,rq1,rq2);
    //     return 1;
    //   }
    //   return 0;
    
      double mat[2][2];
      double rhs[2];
      mat[0][0] = (x2 - x1);
      mat[0][1] = -(x4 - x3);
      mat[1][0] = (y2 - y1);
      mat[1][1] = -(y4 - y3);
      rhs[0] = x3 - x1;
      rhs[1] = y3 - y1;
      if(!sys2x2(mat, rhs, x))
        return 0;
      if(x[0] >= 0.0 && x[0] <= 1.0 && x[1] >= 0.0 && x[1] <= 1.0)
        return 1;
      return 0;
    }
    
    BDS_Edge *BDS_Mesh::recover_edge_fast(BDS_Point *p1, BDS_Point *p2){
    
      std::list<BDS_Face*> ts;
      p1->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 (p1);
          BDS_Face *f= e->otherFace (t);
          if (!f->e4){
            BDS_Point *p2b = f->oppositeVertex(e);
            if (p2 == p2b){
              if (swap_edge(e, BDS_SwapEdgeTestQuality(false,false))){
                 return find_edge (p1,p2->iD);
              }
            }
          }
        }
        ++it;
      }
      return 0;
    }
    
    BDS_Edge *BDS_Mesh::recover_edge(int num1, int num2, bool &_fatal,
                                     std::set<EdgeToRecover> *e2r,
                                     std::set<EdgeToRecover> *not_recovered)
    {
      BDS_Edge *e = find_edge(num1, num2);
      _fatal = false;
    
      if(e) return e;
    
      BDS_Point *p1 = find_point(num1);
      BDS_Point *p2 = find_point(num2);
    
      if(!p1 || !p2) {
        Msg::Fatal("Could not find points %d or %d in BDS mesh", num1, num2);
        return 0;
      }
    
      Msg::Debug("edge %d %d has to be recovered", num1, num2);
    
      int ix = 0;
      double x[2];
      while(1){
        std::vector<BDS_Edge*> intersected;
        std::list<BDS_Edge*>::iterator it = edges.begin();
    
        bool selfIntersection = false;
    
        while(it != edges.end()){
          e = (*it);
          if(!e->deleted && e->p1 != p1 && e->p1 != p2 && e->p2 != p1 && e->p2 != p2)
            if(Intersect_Edges_2d(e->p1->u, e->p1->v,
                                  e->p2->u, e->p2->v,
                                  p1->u, p1->v,
                                  p2->u, p2->v,x)){
              // intersect
              if(e2r && e2r->find(EdgeToRecover(e->p1->iD, e->p2->iD, 0)) != e2r->end()){
                std::set<EdgeToRecover>::iterator itr1 =
                  e2r->find(EdgeToRecover(e->p1->iD, e->p2->iD, 0));
                std::set<EdgeToRecover>::iterator itr2 =
                  e2r->find(EdgeToRecover(num1, num2, 0));
                Msg::Debug("edge %d %d on model edge %d cannot be recovered because"
                           " it intersects %d %d on model edge %d", num1, num2, itr2->ge->tag(),
                           e->p1->iD, e->p2->iD, itr1->ge->tag());
                // now throw a class that contains the diagnostic
                not_recovered->insert(EdgeToRecover(num1, num2, itr2->ge));
                not_recovered->insert(EdgeToRecover(e->p1->iD, e->p2->iD, itr1->ge));
                selfIntersection = true;
              }
              if (e->numfaces() != e->numTriangles()) return 0;
              intersected.push_back(e);
            }
          ++it;
        }
    
        if (selfIntersection) return 0;
    
        // if(ix > 300){
        //   Msg::Warning("edge %d %d cannot be recovered after %d iterations, trying again",
        //      num1, num2, ix);
        //   ix = 0;
        // }
        // printf("%d %d\n",intersected.size(),ix);
    
        if(!intersected.size() || ix > 1000){
          BDS_Edge *eee = find_edge(num1, num2);
          if(!eee){
            outputScalarField(triangles, "debugp.pos", 1);
            outputScalarField(triangles, "debugr.pos", 0);
            Msg::Debug("edge %d %d cannot be recovered at all, look at debugp.pos "
                       "and debugr.pos", num1, num2);
    	_fatal = true;
            return 0;
          }
          return eee;
        }
    
        int ichoice = ix++ % intersected.size();
        //bool success =
          swap_edge(intersected[ichoice], BDS_SwapEdgeTestQuality(false, false));
        // printf("trying to swop %d %d = %d (%d %d)\n", intersected[ichoice]->p1->iD,
        //        intersected[ichoice]->p2->iD, success, intersected[ichoice]->deleted,
        //        intersected[ichoice]->numfaces());
      }
      return 0;
    }
    
    BDS_Edge *BDS_Mesh::find_edge(BDS_Point *p1, BDS_Point *p2, BDS_Face *t) const
    {
      BDS_Point P1(p1->iD);
      BDS_Point P2(p2->iD);
      BDS_Edge E(&P1, &P2);
      if(t->e1->p1->iD == E.p1->iD && t->e1->p2->iD == E.p2->iD)
        return t->e1;
      if(t->e2->p1->iD == E.p1->iD && t->e2->p2->iD == E.p2->iD)
        return t->e2;
      if(t->e3->p1->iD == E.p1->iD && t->e3->p2->iD == E.p2->iD)
        return t->e3;
      return 0;
    }
    
    BDS_Face *BDS_Mesh::find_triangle(BDS_Edge *e1, BDS_Edge *e2, BDS_Edge *e3)
    {
      int i;
      for(i = 0; i < e1->numfaces(); i++) {
        BDS_Face *t = e1->faces(i);
        BDS_Edge *o1 = t->e1;
        BDS_Edge *o2 = t->e2;
        BDS_Edge *o3 = t->e3;
        if((o1 == e1 && o2 == e2 && o3 == e3) ||
           (o1 == e1 && o2 == e3 && o3 == e2) ||
           (o1 == e2 && o2 == e1 && o3 == e3) ||
           (o1 == e2 && o2 == e3 && o3 == e1) ||
           (o1 == e3 && o2 == e1 && o3 == e2) ||
           (o1 == e3 && o2 == e2 && o3 == e1))
          return t;
      }
      for(i = 0; i < e2->numfaces(); i++) {
        BDS_Face *t = e2->faces(i);
        BDS_Edge *o1 = t->e1;
        BDS_Edge *o2 = t->e2;
        BDS_Edge *o3 = t->e3;
        if((o1 == e1 && o2 == e2 && o3 == e3) ||
           (o1 == e1 && o2 == e3 && o3 == e2) ||
           (o1 == e2 && o2 == e1 && o3 == e3) ||
           (o1 == e2 && o2 == e3 && o3 == e1) ||
           (o1 == e3 && o2 == e1 && o3 == e2) ||
           (o1 == e3 && o2 == e2 && o3 == e1))
          return t;
      }
      for(i = 0; i < e3->numfaces(); i++) {
        BDS_Face *t = e3->faces(i);
        BDS_Edge *o1 = t->e1;
        BDS_Edge *o2 = t->e2;
        BDS_Edge *o3 = t->e3;
        if((o1 == e1 && o2 == e2 && o3 == e3) ||
           (o1 == e1 && o2 == e3 && o3 == e2) ||
           (o1 == e2 && o2 == e1 && o3 == e3) ||
           (o1 == e2 && o2 == e3 && o3 == e1) ||
           (o1 == e3 && o2 == e1 && o3 == e2) ||
           (o1 == e3 && o2 == e2 && o3 == e1))
          return t;
      }
      return 0;
    }
    
    BDS_Edge *BDS_Mesh::add_edge(int p1, int p2)
    {
      BDS_Edge *efound = find_edge(p1, p2);
      if(efound) return efound;
    
      BDS_Point *pp1 = find_point(p1);
      BDS_Point *pp2 = find_point(p2);
      if(!pp1 || !pp2){
        Msg::Fatal("Could not find points %d or %d in BDS mesh", p1, p2);
        return 0;
      }
      BDS_Edge *e = new BDS_Edge(pp1, pp2);
      edges.push_back(e);
      return e;
    }
    
    BDS_Face *BDS_Mesh::add_triangle(int p1, int p2, int p3)
    {
      BDS_Edge *e1 = add_edge(p1, p2);
      BDS_Edge *e2 = add_edge(p2, p3);
      BDS_Edge *e3 = add_edge(p3, p1);
      return add_triangle(e1, e2, e3);
    }
    
    BDS_Face *BDS_Mesh::add_triangle(BDS_Edge *e1, BDS_Edge *e2, BDS_Edge *e3)
    {
      // BDS_Face *tfound = find_triangle(e1, e2, e3);
      // if(tfound) return tfound;
    
      BDS_Face *t = new BDS_Face(e1, e2, e3);
      triangles.push_back(t);
      return t;
    }
    
    BDS_Face *BDS_Mesh::add_quadrangle(BDS_Edge *e1, BDS_Edge *e2,
                                       BDS_Edge *e3, BDS_Edge *e4)
    {
      BDS_Face *t = new BDS_Face(e1, e2, e3, e4);
      triangles.push_back(t);
      return t;
    }
    
    void BDS_Mesh::del_face(BDS_Face *t)
    {
      t->e1->del(t);
      t->e2->del(t);
      t->e3->del(t);
      if(t->e4) t->e4->del(t);
      t->deleted = true;
    }
    
    void BDS_Mesh::del_edge(BDS_Edge *e)
    {
      e->p1->del(e);
      e->p2->del(e);
      e->deleted = true;
    }
    
    void BDS_Mesh::del_point(BDS_Point *p)
    {
      points.erase(p);
      delete p;
    }
    
    void BDS_Mesh::add_geom(int p1, int p2)
    {
      geom.insert(new BDS_GeomEntity(p1, p2));
    }
    
    void BDS_Edge::oppositeof(BDS_Point *oface[2]) const
    {
      oface[0] = oface[1] = 0;
      if(faces(0)) {
        BDS_Point *pts[4];
        faces(0)->getNodes(pts);
        if(pts[0] != p1 && pts[0] != p2)
          oface[0] = pts[0];
        else if(pts[1] != p1 && pts[1] != p2)
          oface[0] = pts[1];
        else
          oface[0] = pts[2];
      }
      if(faces(1)) {
        BDS_Point *pts[4];
        faces(1)->getNodes(pts);
        if(pts[0] != p1 && pts[0] != p2)
          oface[1] = pts[0];
        else if(pts[1] != p1 && pts[1] != p2)
          oface[1] = pts[1];
        else
          oface[1] = pts[2];
      }
    }
    
    BDS_GeomEntity *BDS_Mesh::get_geom(int p1, int p2)
    {
      BDS_GeomEntity ge(p1, p2);
      std::set<BDS_GeomEntity *, GeomLessThan >::iterator it = geom.find(&ge);
      if(it == geom.end()) return 0;
      return (BDS_GeomEntity*)(*it);
    }
    
    void recur_tag(BDS_Face *t, BDS_GeomEntity *g)
    {
      std::stack<BDS_Face*> _stack;
      _stack.push(t);
    
      while(!_stack.empty()){
        t = _stack.top();
        _stack.pop();
        if(!t->g) {
          t->g = g;
          // g->t.push_back(t);
          if(!t->e1->g && t->e1->numfaces() == 2) {
    	_stack.push(t->e1->otherFace(t));
    	//	recur_tag(t->e1->otherFace(t), g);
          }
          if(!t->e2->g && t->e2->numfaces() == 2) {
    	_stack.push(t->e2->otherFace(t));
    	//	recur_tag(t->e2->otherFace(t), g);
          }
          if(!t->e3->g && t->e3->numfaces() == 2) {
    	_stack.push(t->e3->otherFace(t));
    	//	recur_tag(t->e3->otherFace(t), g);
          }
        }
      }
    }
    
    double PointLessThanLexicographic::t = 0;
    double BDS_Vector::t = 0;
    
    template <class IT> void DESTROOOY(IT beg, IT end)
    {
      while(beg != end) {
        delete *beg;
        beg++;
      }
    }
    
    void BDS_Mesh::cleanup()
    {
      {
        std::list<BDS_Face*>::iterator it = triangles.begin();
        while(it != triangles.end()){
          if((*it)->deleted){
            delete *it;
            it = triangles.erase(it);
          }
          else
            it++;
        }
      }
      {
        std::list<BDS_Edge*>::iterator it = edges.begin();
        while(it != edges.end()){
          if((*it)->deleted){
            delete *it;
            it = edges.erase(it);
          }
          else
            it++;
        }
      }
    }
    
    BDS_Mesh::~BDS_Mesh()
    {
      DESTROOOY(geom.begin(), geom.end());
      DESTROOOY(points.begin(), points.end());
      cleanup();
      DESTROOOY(edges.begin(), edges.end());
      DESTROOOY(triangles.begin(), triangles.end());
    }
    
    bool BDS_Mesh::split_face(BDS_Face *f, BDS_Point *mid)
    {
      BDS_Point *p1 = f->e1->commonvertex(f->e2);
      BDS_Point *p2 = f->e3->commonvertex(f->e2);
      BDS_Point *p3 = f->e1->commonvertex(f->e3);
      BDS_Edge *p1_mid = new BDS_Edge(p1, mid);
      edges.push_back(p1_mid);
      BDS_Edge *p2_mid = new BDS_Edge(p2, mid);
      edges.push_back(p2_mid);
      BDS_Edge *p3_mid = new BDS_Edge(p3, mid);
      edges.push_back(p2_mid);
      BDS_Face *t1, *t2, *t3;
      t1 = new BDS_Face(f->e1, p1_mid, p3_mid);
      t2 = new BDS_Face(f->e2, p2_mid, p1_mid);
      t3 = new BDS_Face(f->e3, p3_mid, p2_mid);
    
      t1->g = f->g;
      t2->g = f->g;
      t3->g = f->g;
    
      p1_mid->g = f->g;
      p2_mid->g = f->g;
      p3_mid->g = f->g;
    
      mid->g = f->g;
    
      triangles.push_back(t1);
      triangles.push_back(t2);
      triangles.push_back(t3);
    
      // config has changed
      p1->config_modified = true;
      p2->config_modified = true;
      p3->config_modified = true;
    
      // delete the face
      del_face(f);
    
      return true;
    }
    
    bool BDS_Mesh::split_edge(BDS_Edge *e, BDS_Point *mid)
    {
      /*
            p1
          / | \
         /  |  \
     op1/ 0mid1 \op2
        \   |   /
         \  |  /
          \ p2/
    
         //  p1,op1,mid -
         //  p2,op2,mid -
         //  p2,op1,mid +
         //  p1,op2,mid +
      */
    
      BDS_Point *op[2];
      BDS_Point *p1 = e->p1;
      BDS_Point *p2 = e->p2;
    
      e->oppositeof(op);
    
      BDS_Point *pts1[4];
      e->faces(0)->getNodes(pts1);
    
      int orientation = 0;
      for(int i = 0; i < 3; i++) {
        if(pts1[i] == p1) {
          if(pts1[(i + 1) % 3] == p2)
            orientation = 1;
          else
            orientation = -1;
          break;
        }
      }
    
      // we should project
      BDS_GeomEntity *g1 = 0, *g2 = 0, *ge = e->g;
    
      BDS_Edge *p1_op1 = find_edge(p1, op[0], e->faces(0));
      BDS_Edge *op1_p2 = find_edge(op[0], p2, e->faces(0));
      BDS_Edge *p1_op2 = find_edge(p1, op[1], e->faces(1));
      BDS_Edge *op2_p2 = find_edge(op[1], p2, e->faces(1));
    
      if(e->faces(0)) {
        g1 = e->faces(0)->g;
        del_face(e->faces(0));
      }
      // not a bug !!!
      if(e->faces(0)) {
        g2 = e->faces(0)->g;
        del_face(e->faces(0));
      }
    
      //  double t_l = e->target_length;
    
      del_edge(e);
    
      BDS_Edge *p1_mid = new BDS_Edge(p1, mid);
      edges.push_back(p1_mid);
      BDS_Edge *mid_p2 = new BDS_Edge(mid, p2);
      edges.push_back(mid_p2);
      BDS_Edge *op1_mid = new BDS_Edge(op[0], mid);
      edges.push_back(op1_mid);
      BDS_Edge *mid_op2 = new BDS_Edge(mid, op[1]);
      edges.push_back(mid_op2);
    
      BDS_Face *t1, *t2, *t3, *t4;
      if(orientation == 1) {
        t1 = new BDS_Face(op1_mid, p1_op1, p1_mid);
        t2 = new BDS_Face(mid_op2, op2_p2, mid_p2);
        t3 = new BDS_Face(op1_p2, op1_mid, mid_p2);
        t4 = new BDS_Face(p1_op2, mid_op2, p1_mid);
      }
      else {
        t1 = new BDS_Face(p1_op1, op1_mid, p1_mid);
        t2 = new BDS_Face(op2_p2, mid_op2, mid_p2);
        t3 = new BDS_Face(op1_mid, op1_p2, mid_p2);
        t4 = new BDS_Face(mid_op2, p1_op2, p1_mid);
      }
      t1->g = g1;
      t2->g = g2;
      t3->g = g1;
      t4->g = g2;
    
      p1_mid->g = ge;
      mid_p2->g = ge;
      op1_mid->g = g1;
      mid_op2->g = g2;
    
      mid->g = ge;
    
      triangles.push_back(t1);
      triangles.push_back(t2);
      triangles.push_back(t3);
      triangles.push_back(t4);
    
      // config has changed
      p1->config_modified = true;
      p2->config_modified = true;
      op[0]->config_modified = true;
      op[1]->config_modified = true;
      return true;
    }
    
    // This function does actually the swap without taking into account
    // the feasability of the operation. Those conditions have to be
    // taken into account before doing the edge swap
    
    bool BDS_SwapEdgeTestQuality::operator () (BDS_Point *_p1, BDS_Point *_p2,
                                               BDS_Point *_q1, BDS_Point *_q2) const
    {
      if(!testSmallTriangles){
        double p1 [2] = {_p1->u,_p1->v};
        double p2 [2] = {_p2->u,_p2->v};
        double op1[2] = {_q1->u,_q1->v};
        double op2[2] = {_q2->u,_q2->v};
    
        double ori_t1 = robustPredicates::orient2d(op1, p1, op2);
        double ori_t2 = robustPredicates::orient2d(op1, op2, p2);
    
        // printf("%d %d %d %d %g %g\n",_p1->iD,_p2->iD,_q1->iD,_q2->iD,ori_t1,ori_t2);
        return (ori_t1 * ori_t2 > 0); // the quadrangle was strictly convex !
      }
    
      double s1 = fabs(surface_triangle_param(_p1, _p2, _q1));
      double s2 = fabs(surface_triangle_param(_p1, _p2, _q2));
      double s3 = fabs(surface_triangle_param(_p1, _q1, _q2));
      double s4 = fabs(surface_triangle_param(_p2, _q1, _q2));
      if(fabs(s1 + s2 - s3 - s4) > 1.e-12 * (s1 + s2)) return false;
      if(s3 < .02 * (s1 + s2) || s4 < .02 * (s1 + s2))
        return false;
      return true;
    }
    
    bool BDS_SwapEdgeTestQuality::operator () (BDS_Point *_p1, BDS_Point *_p2, BDS_Point *_p3,
                                               BDS_Point *_q1, BDS_Point *_q2, BDS_Point *_q3,
                                               BDS_Point *_op1, BDS_Point *_op2, BDS_Point *_op3,
                                               BDS_Point *_oq1, BDS_Point *_oq2, BDS_Point *_oq3) const
    {
      if(!testQuality) return true;
      double n[3], q[3], on[3], oq[3];
      normal_triangle(_p1, _p2, _p3, n);
      normal_triangle(_q1, _q2, _q3, q);
      normal_triangle(_op1, _op2, _op3, on);
      normal_triangle(_oq1, _oq2, _oq3, oq);
    
      double cosnq; prosca(n, q, &cosnq);
      double cosonq; prosca(on, oq, &cosonq);
    
      double qa1 = qmTriangle::gamma(_p1, _p2, _p3);
      double qa2 = qmTriangle::gamma(_q1, _q2, _q3);
      double qb1 = qmTriangle::gamma(_op1, _op2, _op3);
      double qb2 = qmTriangle::gamma(_oq1, _oq2, _oq3);
    
      // we swap for a better configuration
      double mina = std::min(qa1,qa2);
      double minb = std::min(qb1,qb2);
    
      // if(cosnq < .3 && cosonq > .5 && minb > .1)
      //   printf("mina = %g minb = %g cos %g %g\n",mina,minb,cosnq,cosonq);
    
      if(cosnq < .3 && cosonq > .5 && minb > .1) return true;
    
      if(minb > mina) return true;
      //  if(mina > minb && cosnq <= cosonq)return true;
      return false;
    }
    
    void swap_config(BDS_Edge *e,
                     BDS_Point **p11, BDS_Point **p12, BDS_Point **p13,
                     BDS_Point **p21, BDS_Point **p22, BDS_Point **p23,
                     BDS_Point **p31, BDS_Point **p32, BDS_Point **p33,
                     BDS_Point **p41, BDS_Point **p42, BDS_Point **p43)
    {
      BDS_Point *op[2];
      BDS_Point *p1 = e->p1;
      BDS_Point *p2 = e->p2;
      e->oppositeof(op);
    
      BDS_Point *pts1[4];
      e->faces(0)->getNodes(pts1);
    
      // compute the orientation of the face
      // with respect to the edge
      int orientation = 0;
      for(int i = 0; i < 3; i++) {
        if(pts1[i] == p1) {
          if(pts1[(i + 1) % 3] == p2)
            orientation = 1;
          else
            orientation = -1;
          break;
        }
      }
    
      if(orientation == 1) {
        *p11 = p1;
        *p12 = p2;
        *p13 = op[0];
    
        *p21 = p2;
        *p22 = p1;
        *p23 = op[1];
    
        *p31 = p1;
        *p32 = op[1];
        *p33 = op[0];
    
        *p41 = op[1];
        *p42 = p2;
        *p43 = op[0];
      }
      else{
        *p11 = p2;
        *p12 = p1;
        *p13 = op[0];
        *p21 = p1;
        *p22 = p2;
        *p23 = op[1];
        *p31 = p1;
        *p32 = op[0];
        *p33 = op[1];
        *p41 = op[1];
        *p42 = op[0];
        *p43 = p2;
      }
    }
    
    bool BDS_Mesh::swap_edge(BDS_Edge *e, const BDS_SwapEdgeTest &theTest)
    {
    
      /*
            p1
          / | \
         /  |  \
     op1/ 0 | 1 \op2
        \   |   /
         \  |  /
          \ p2/
    
         // op1 p1 op2
         // op1 op2 p2
       */
    
      // we test if the edge is deleted
      //  return false;
    
      if(e->deleted)
        return false;
    
      int nbFaces = e->numfaces();
      if(nbFaces != 2)
        return false;
    
      if(e->g && e->g->classif_degree == 1)
        return false;
    
      BDS_Point *op[2];
      BDS_Point *p1 = e->p1;
      BDS_Point *p2 = e->p2;
      e->oppositeof(op);
    
      BDS_GeomEntity *g1 = 0, *g2 = 0, *ge = e->g;
    
      BDS_Point *pts1[4];
      e->faces(0)->getNodes(pts1);
    
      // compute the orientation of the face
      // with respect to the edge
      int orientation = 0;
      for(int i = 0; i < 3; i++) {
        if(pts1[i] == p1) {
          if(pts1[(i + 1) % 3] == p2)
            orientation = 1;
          else
            orientation = -1;
          break;
        }
      }
    
      if(orientation == 1) {
        if(!theTest(p1, p2, op[0],
                    p2, p1, op[1],
                    p1, op[1], op[0],
                    op[1], p2, op[0]))
          return false;
      }
      else{
        if(!theTest(p2, p1, op[0],
                    p1, p2, op[1],
                    p1, op[0], op[1],
                    op[1], op[0], p2))
          return false;
      }
    
      if(!theTest(p1, p2, op[0], op[1]))
        return false;
    
      BDS_Edge *p1_op1 = find_edge(p1, op[0], e->faces(0));
      BDS_Edge *op1_p2 = find_edge(op[0], p2, e->faces(0));
      BDS_Edge *p1_op2 = find_edge(p1, op[1], e->faces(1));
      BDS_Edge *op2_p2 = find_edge(op[1], p2, e->faces(1));
    
      if(e->faces(0)) {
        g1 = e->faces(0)->g;
        del_face(e->faces(0));
      }
      // not a bug !!!
      if(e->faces(0)) {
        g2 = e->faces(0)->g;
        del_face(e->faces(0));
      }
      del_edge(e);
    
      BDS_Edge *op1_op2 = new BDS_Edge(op[0], op[1]);
      edges.push_back(op1_op2);
    
      BDS_Face *t1, *t2;
      if(orientation == 1) {
        t1 = new BDS_Face(p1_op1, p1_op2, op1_op2);
        t2 = new BDS_Face(op1_op2, op2_p2, op1_p2);
      }
      else {
        t1 = new BDS_Face(p1_op2, p1_op1, op1_op2);
        t2 = new BDS_Face(op2_p2, op1_op2, op1_p2);
      }
    
      t1->g = g1;
      t2->g = g2;
    
      op1_op2->g = ge;
    
      triangles.push_back(t1);
      triangles.push_back(t2);
    
      p1->config_modified = true;
      p2->config_modified = true;
      op[0]->config_modified = true;
      op[1]->config_modified = true;
    
      return true;
    }
    
    int BDS_Edge::numTriangles() const
    {
      int NT = 0;
      for(unsigned int i = 0; i < _faces.size(); i++)
        if(faces(i)->numEdges() == 3) NT++;
      return NT;
    }
    
    // use robust predicates for not allowing to revert a triangle by
    // moving one of its vertices
    
    static bool test_move_point_parametric_quad(BDS_Point *p, double u, double v, BDS_Face *t)
    {
      BDS_Point *pts[4];
      t->getNodes(pts);
    
      double pa[2] = {pts[0]->u, pts[0]->v};
      double pb[2] = {pts[1]->u, pts[1]->v};
      double pc[2] = {pts[2]->u, pts[2]->v};
      double pd[2] = {pts[3]->u, pts[3]->v};
    
      double ori_init1 = robustPredicates::orient2d(pa, pb, pc);
      double ori_init2 = robustPredicates::orient2d(pc, pd, pa);
    
      if(p == pts[0]){
        pa[0] = u;
        pa[1] = v;
      }
      else if(p == pts[1]){
        pb[0] = u;
        pb[1] = v;
      }
      else if(p == pts[2]){
        pc[0] = u;
        pc[1] = v;
      }
      else if(p == pts[3]){
        pd[0] = u;
        pd[1] = v;
      }
      else{
        Msg::Error("Something wrong in move_point_parametric_quad");
        return false;
      }
    
      double ori_final1 = robustPredicates::orient2d(pa, pb, pc);
      double ori_final2 = robustPredicates::orient2d(pc, pd, pa);
      // allow to move a point when a triangle was flat
      return (ori_init1 * ori_final1 > 0) && (ori_init2 * ori_final2 > 0);
    }
    
    static bool test_move_point_parametric_triangle(BDS_Point *p, double u, double v, BDS_Face *t)
    {
      if (t->e4)
        return test_move_point_parametric_quad(p, u, v, t);
      BDS_Point *pts[4];
      t->getNodes(pts);
    
      double pa[2] = {pts[0]->u, pts[0]->v};
      double pb[2] = {pts[1]->u, pts[1]->v};
      double pc[2] = {pts[2]->u, pts[2]->v};
    
      double a[2] = {pb[0] - pa[0], pb[1] - pa[1]};
      double b[2] = {pc[0] - pa[0], pc[1] - pa[1]};
    
      double area_init = fabs(a[0] * b[1] - a[1] * b[0]);
    
      if(area_init == 0.0) return true;
    
      double ori_init = robustPredicates::orient2d(pa, pb, pc);
    
      if(p == pts[0]){
        pa[0] = u;
        pa[1] = v;
      }
      else if(p == pts[1]){
        pb[0] = u;
        pb[1] = v;
      }
      else if(p == pts[2]){
        pc[0] = u;
        pc[1] = v;
      }
      else
        return false;
    
      a[0] = pb[0] - pa[0]; a[1] = pb[1] - pa[1];
      b[0] = pc[0] - pa[0]; b[1] = pc[1] - pa[1];
    
      double area_final = fabs(a[0] * b[1] - a[1] * b[0]);
      if(area_final < 0.1 * area_init) return false;
      double ori_final = robustPredicates::orient2d(pa, pb, pc);
      // allow to move a point when a triangle was flat
      return ori_init * ori_final > 0;
    }
    
    bool BDS_Mesh::collapse_edge_parametric(BDS_Edge *e, BDS_Point *p)
    {
      if(e->numfaces() != 2)
        return false;
      if(p->g && p->g->classif_degree == 0)
        return false;
      // not really ok but 'til now this is the best choice not to do collapses on model edges
      if(p->g && p->g->classif_degree == 1)
        return false;
      if(e->g && p->g) {
        if(e->g->classif_degree == 2 && p->g != e->g)
          return false;
      }
    
      std::list<BDS_Face*> t;
      BDS_Point *o = e->othervertex(p);
    
      //  if(o->g != p->g)
      //    return false;
    
      // printf("collapsing an edge :");
      // print_edge(e);
    
      BDS_Point *pt[3][1024];
      BDS_GeomEntity *gs[1024];
      int ept[2][1024];
      BDS_GeomEntity *egs[1024];
      int nt = 0;
      {
        p->getTriangles(t);
        std::list<BDS_Face*>::iterator it = t.begin();
        std::list<BDS_Face*>::iterator ite = t.end();
        while(it != ite) {
          BDS_Face *t = *it;
          if(t->e1 != e && t->e2 != e && t->e3 != e) {
            if(!test_move_point_parametric_triangle(p, o->u, o->v, t))
              return false;
            gs[nt] = t->g;
            BDS_Point *pts[4];
            t->getNodes(pts);
            pt[0][nt] = (pts[0] == p) ? o : pts[0];
            pt[1][nt] = (pts[1] == p) ? o : pts[1];
            pt[2][nt] = (pts[2] == p) ? o : pts[2];
    
    //      double qnew = qmTriangle::gamma(pt[0][nt], pt[1][nt], pt[2][nt]);
    //      double qold = qmTriangle::gamma(pts[0], pts[1], pts[2]);
    //      if(qold > 1.e-4 && qnew < 1.e-4) return false;
            nt++;
    //      pt[0][nt] = (pts[0] == p) ? o->iD : pts[0]->iD;
    //      pt[1][nt] = (pts[1] == p) ? o->iD : pts[1]->iD;
    //      pt[2][nt++] = (pts[2] == p) ? o->iD : pts[2]->iD;
          }
          ++it;
        }
      }
    
      {
        std::list<BDS_Face*>::iterator it = t.begin();
        std::list<BDS_Face*>::iterator ite = t.end();
    
        while(it != ite) {
          BDS_Face *t = *it;
          del_face(t);
          ++it;
        }
      }
    
      // printf("%d triangles 2 add\n",nt);
    
      int kk = 0;
      {
        std::list<BDS_Edge*> edges(p->edges);
        std::list<BDS_Edge*>::iterator eit = edges.begin();
        std::list<BDS_Edge*>::iterator eite = edges.end();
        while(eit != eite) {
          (*eit)->p1->config_modified = (*eit)->p2->config_modified = true;
          ept[0][kk] = ((*eit)->p1 == p) ? o->iD : (*eit)->p1->iD;
          ept[1][kk] = ((*eit)->p2 == p) ? o->iD : (*eit)->p2->iD;
          egs[kk++] = (*eit)->g;
          del_edge(*eit);
          ++eit;
        }
      }
    
      del_point(p);
    
      {
        for(int k = 0; k < nt; k++) {
          BDS_Face *t = add_triangle(pt[0][k]->iD, pt[1][k]->iD, pt[2][k]->iD);
          t->g = gs[k];
        }
      }
    
      for(int i = 0; i < kk; ++i) {
        BDS_Edge *e = find_edge(ept[0][i], ept[1][i]);
        if(e && !e->g)
          e->g = egs[i];
      }
    
      return true;
    }
    
    bool BDS_Mesh::smooth_point_centroid(BDS_Point *p, GFace *gf, bool test_quality)
    {
    
      if(!p->config_modified) return false;
      if(p->g && p->g->classif_degree <= 1) return false;
      if(p->g && p->g->classif_tag < 0) {
        p->config_modified = true;
        return true;
      }
      std::list<BDS_Edge*>::iterator eit = p->edges.begin();
      while(eit != p->edges.end()) {
        if((*eit)->numfaces() == 1) return false;
        eit++;
      }
    
      /*    TEST    */
      bool isSphere = gf->geomType() == GEntity::Sphere;
      double XX=0,YY=0,ZZ=0;
    
      double U = 0;
      double V = 0;
      double LC = 0;
      double oldU = p->u;
      double oldV = p->v;
    
      std::list<BDS_Face*> ts;
      p->getTriangles(ts);
      std::list<BDS_Edge *>::iterator ited = p->edges.begin();
      std::list<BDS_Edge *>::iterator itede = p->edges.end();
    
      double sTot = 0;
      while(ited != itede) {
        BDS_Edge  *e = *ited;
        BDS_Point *n = e->othervertex(p);
        double fact = 1.0;
        sTot += fact;
        U  += n->u * fact;
        V  += n->v * fact;
        XX += n->X;
        YY += n->Y;
        ZZ += n->Z;
        LC += n->lc() * fact;
        ++ited;
      }
      U /= (sTot);
      V /= (sTot);
      LC /= (sTot);
      XX/= (sTot);
      YY/= (sTot);
      ZZ/= (sTot);
    
      GPoint gp;double uv[2];
      if (isSphere){
        gp = gf->closestPoint(SPoint3(XX, YY, ZZ), uv);
        U = gp.u();
        V = gp.v();
      }
      else
        gp = gf->point(U * scalingU, V * scalingV);
    
      if (!gp.succeeded()){
        return false;
      }
      const double oldX = p->X;
      const double oldY = p->Y;
      const double oldZ = p->Z;
    
      std::list<BDS_Face*>::iterator it = ts.begin();
      std::list<BDS_Face*>::iterator ite = ts.end();
      double s1 = 0, s2 = 0;
    
      double newWorst = 1.0;
      double oldWorst = 1.0;
      while(it != ite) {
        BDS_Face *t = *it;
        BDS_Point *n[4];
        t->getNodes(n);
        p->u = U;
        p->v = V;
        double snew = fabs(surface_triangle_param(n[0], n[1], n[2]));
        s1 += snew;
        p->u = oldU;
        p->v = oldV;
        double sold = fabs(surface_triangle_param(n[0], n[1], n[2]));
        s2 += sold;
        // printf("%22.15E %22.15E\n", snew, sold);
        if(snew < .1 * sold) return false;
    
        if(1 || test_quality){
          p->X = gp.x();
          p->Y = gp.y();
          p->Z = gp.z();
          newWorst = std::min(newWorst, qmTriangle::gamma(*it));
          double norm1[3],norm2[3];
          normal_triangle(n[0], n[1], n[2], norm1);
          p->X = oldX;
          p->Y = oldY;
          p->Z = oldZ;
          normal_triangle(n[0], n[1], n[2], norm2);
          oldWorst = std::min(oldWorst, qmTriangle::gamma(*it));
          double ps;
          prosca(norm1, norm2, &ps);
          double threshold = (isSphere ? 0.95 : 0.5);
          if(ps < threshold){
            return false;
          }
        }
        ++it;
      }
    
      // printf("%22.15E %22.15E %22.15E\n",s1,s2,fabs(s2-s1));
      if(fabs(s2-s1) > 1.e-14 * (s2 + s1)) return false;
    
      if(test_quality && newWorst < oldWorst){
        return false;
      }
    
      p->u = U;
      p->v = V;
      p->lc() = LC;
      p->X = gp.x();
      p->Y = gp.y();
      p->Z = gp.z();
      eit = p->edges.begin();
      while(eit != p->edges.end()) {
        (*eit)->update();
        ++eit;
      }
      return true;
    }
    
    bool BDS_Mesh::smooth_point_parametric(BDS_Point *p, GFace *gf)
    {
    
      if(!p->config_modified)return false;
      if(p->g && p->g->classif_degree <= 1)
        return false;
    
      double U = 0;
      double V = 0;
      double tot_length = 0;
      double LC = 0;
    
    
      std::list<BDS_Face*> ts;
      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;
        BDS_Point *n[4];
        t->getNodes(n);
        for (int i = 0; i<t->numEdges();i++){
          U += n[i]->u;
          V += n[i]->v;
          LC += n[i]->lc();
          tot_length += 1;
        }
        ++it;
      }
      U /= tot_length;
      V /= tot_length;
      LC /= p->edges.size();
    
      it = ts.begin();
      while(it != ite) {
        BDS_Face *t = *it;
        if(!test_move_point_parametric_triangle(p, U, V, t)){
          printf("coucou %g %g -> %g %g\n", p->u, p->v,U,V);
          return false;
        }
        ++it;
      }
    
      GPoint gp = gf->point(U * scalingU, V * scalingV);
      if (!gp.succeeded())return false;
    
      p->u = U;
      p->v = V;
      p->lc() = LC;
      p->X = gp.x();
      p->Y = gp.y();
      p->Z = gp.z();
      std::list<BDS_Edge*>::iterator eit = p->edges.begin();
      while(eit != p->edges.end()) {
        (*eit)->update();
        ++eit;
      }
    
      return true;
    }