Skip to content
Snippets Groups Projects
Select Git revision
  • cc748abcbf2b4b2ffc855b0c00e8a8490053fb21
  • 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

OptionsViewController.mm

Blame
  • Forked from gmsh / gmsh
    Source project has a limited visibility.
    CAD.cpp 55.97 KiB
    // $Id: CAD.cpp,v 1.78 2004-08-12 16:55:00 geuzaine Exp $
    //
    // Copyright (C) 1997-2004 C. Geuzaine, J.-F. Remacle
    //
    // This program is free software; you can redistribute it and/or modify
    // it under the terms of the GNU General Public License as published by
    // the Free Software Foundation; either version 2 of the License, or
    // (at your option) any later version.
    //
    // This program is distributed in the hope that it will be useful,
    // but WITHOUT ANY WARRANTY; without even the implied warranty of
    // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    // GNU General Public License for more details.
    //
    // You should have received a copy of the GNU General Public License
    // along with this program; if not, write to the Free Software
    // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
    // USA.
    // 
    // Please report all bugs and problems to <gmsh@geuz.org>.
    
    #include "Gmsh.h"
    #include "Numeric.h"
    #include "Geo.h"
    #include "Mesh.h"
    #include "Interpolation.h"
    #include "Create.h"
    #include "CAD.h"
    #include "Edge.h"
    #include "Visibility.h"
    #include "Context.h"
    
    extern Mesh *THEM;
    extern Context_T CTX;
    
    static List_T *ListOfTransformedPoints = NULL;
    
    // Basic functions
    
    int NEWPOINT(void)
    {
      return (THEM->MaxPointNum + 1);
    }
    
    int NEWLINE(void)
    {
      if(CTX.geom.old_newreg)
        return NEWREG();
      else
        return (THEM->MaxLineNum + 1);
    }
    
    int NEWLINELOOP(void)
    {
      if(CTX.geom.old_newreg)
        return NEWREG();
      else
        return (THEM->MaxLineLoopNum + 1);
    }
    
    int NEWSURFACE(void)
    {
      if(CTX.geom.old_newreg)
        return NEWREG();
      else
        return (THEM->MaxSurfaceNum + 1);
    }
    
    int NEWSURFACELOOP(void)
    {
      if(CTX.geom.old_newreg)
        return NEWREG();
      else
        return (THEM->MaxSurfaceLoopNum + 1);
    }
    
    int NEWVOLUME(void)
    {
      if(CTX.geom.old_newreg)
        return NEWREG();
      else
        return (THEM->MaxVolumeNum + 1);
    }
    
    int NEWPHYSICAL(void)
    {
      if(CTX.geom.old_newreg)
        return NEWREG();
      else
        return (THEM->MaxPhysicalNum + 1);
    }
    
    int NEWREG(void)
    {
      return (IMAX(THEM->MaxLineNum,
                   IMAX(THEM->MaxLineLoopNum,
                        IMAX(THEM->MaxSurfaceNum,
                             IMAX(THEM->MaxSurfaceLoopNum,
                                  IMAX(THEM->MaxVolumeNum,
                                       THEM->MaxPhysicalNum)))))
              + 1);
    }
    
    
    
    
    int compare2Lists(List_T * List1, List_T * List2,
                      int (*fcmp) (const void *a, const void *b))
    {
      int i, found;
    
      if(List_Nbr(List1) != List_Nbr(List2))
        return List_Nbr(List1) - List_Nbr(List2);
    
      List_T *List1Prime = List_Create(List_Nbr(List1), 1, List1->size);
      List_T *List2Prime = List_Create(List_Nbr(List2), 1, List2->size);
      List_Copy(List1, List1Prime);
      List_Copy(List2, List2Prime);
      List_Sort(List1Prime, fcmp);
      List_Sort(List2Prime, fcmp);
    
      for(i = 0; i < List_Nbr(List1Prime); i++) {
        found = fcmp(List_Pointer(List1Prime, i), List_Pointer(List2Prime, i));
        if(found != 0) {
          List_Delete(List1Prime);
          List_Delete(List2Prime);
          return found;
        }
      }
      List_Delete(List1Prime);
      List_Delete(List2Prime);
      return 0;
    }
    
    Vertex *FindPoint(int inum, Mesh * M)
    {
      Vertex C, *pc;
      pc = &C;
      pc->Num = inum;
      if(Tree_Query(M->Points, &pc)) {
        return pc;
      }
      return NULL;
    }
    
    Vertex *FindVertex(int inum, Mesh * M)
    {
      Vertex C, *pc;
      pc = &C;
      pc->Num = inum;
      if(Tree_Query(M->Vertices, &pc)) {
        return pc;
      }
      return NULL;
    }
    
    Curve *FindCurve(int inum, Mesh * M)
    {
      Curve C, *pc;
      pc = &C;
      pc->Num = inum;
      if(Tree_Query(M->Curves, &pc)) {
        return pc;
      }
      return NULL;
    }
    
    Surface *FindSurface(int inum, Mesh * M)
    {
      Surface S, *ps;
      ps = &S;
      ps->Num = inum;
      if(Tree_Query(M->Surfaces, &ps)) {
        return ps;
      }
      return NULL;
    }
    
    Volume *FindVolume(int inum, Mesh * M)
    {
      Volume V, *pv;
      pv = &V;
      pv->Num = inum;
      if(Tree_Query(M->Volumes, &pv)) {
        return pv;
      }
      return NULL;
    }
    
    EdgeLoop *FindEdgeLoop(int inum, Mesh * M)
    {
      EdgeLoop S, *ps;
      ps = &S;
      ps->Num = inum;
      if(Tree_Query(M->EdgeLoops, &ps)) {
        return ps;
      }
      return NULL;
    }
    
    SurfaceLoop *FindSurfaceLoop(int inum, Mesh * M)
    {
      SurfaceLoop S, *ps;
      ps = &S;
      ps->Num = inum;
      if(Tree_Query(M->SurfaceLoops, &ps)) {
        return ps;
      }
      return NULL;
    }
    
    PhysicalGroup *FindPhysicalGroup(int num, int type, Mesh * M)
    {
      PhysicalGroup P, *pp, **ppp;
      pp = &P;
      pp->Num = num;
      pp->Typ = type;
      if((ppp = (PhysicalGroup **) List_PQuery(M->PhysicalGroups, &pp,
                                               comparePhysicalGroup))) {
        return *ppp;
      }
      return NULL;
    }
    
    void CopyVertex(Vertex * v, Vertex * vv)
    {
      vv->lc = v->lc;
      vv->u = v->u;
      vv->Pos.X = v->Pos.X;
      vv->Pos.Y = v->Pos.Y;
      vv->Pos.Z = v->Pos.Z;
      vv->Freeze.X = v->Freeze.X;
      vv->Freeze.Y = v->Freeze.Y;
      vv->Freeze.Z = v->Freeze.Z;
    }
    
    Vertex *DuplicateVertex(Vertex * v)
    {
      Vertex *pv;
      pv = Create_Vertex(NEWPOINT(), 0, 0, 0, 0, 0);
      CopyVertex(v, pv);
      Tree_Insert(THEM->Points, &pv);
      return pv;
    }
    
    void CopyCurve(Curve * c, Curve * cc)
    {
      int i, j;
      cc->Typ = c->Typ;
      // We should not copy the meshing method : if the meshes are to be
      // copied, the meshing algorithm will take care of it
      // (e.g. ExtrudeMesh()).
      //cc->Method = c->Method; 
      for(i = 0; i < 4; i++)
        cc->ipar[i] = c->ipar[i];
      for(i = 0; i < 4; i++)
        cc->dpar[i] = c->dpar[i];
      cc->l = c->l;
      for(i = 0; i < 4; i++)
        for(j = 0; j < 4; j++)
          cc->mat[i][j] = c->mat[i][j];
      cc->beg = c->beg;
      cc->end = c->end;
      cc->ubeg = c->ubeg;
      cc->uend = c->uend;
      cc->Control_Points =
        List_Create(List_Nbr(c->Control_Points), 1, sizeof(Vertex *));
      List_Copy(c->Control_Points, cc->Control_Points);
      if(c->Typ == MSH_SEGM_PARAMETRIC){
        strcpy(cc->functu, c->functu);
        strcpy(cc->functv, c->functv);
        strcpy(cc->functw, c->functw);
      }
      End_Curve(cc);
      Tree_Insert(THEM->Curves, &cc);
    }
    
    Curve *DuplicateCurve(Curve * c)
    {
      Curve *pc;
      Vertex *v, *newv;
      pc = Create_Curve(NEWLINE(), 0, 1, NULL, NULL, -1, -1, 0., 1.);
      CopyCurve(c, pc);
      for(int i = 0; i < List_Nbr(c->Control_Points); i++) {
        List_Read(pc->Control_Points, i, &v);
        newv = DuplicateVertex(v);
        List_Write(pc->Control_Points, i, &newv);
      }
      pc->beg = DuplicateVertex(c->beg);
      pc->end = DuplicateVertex(c->end);
      CreateReversedCurve(THEM, pc);
    
      return pc;
    }
    
    void CopySurface(Surface * s, Surface * ss)
    {
      int i, j;
      ss->Typ = s->Typ;
      // We should not copy the meshing method (or the recombination
      // status): if the meshes are to be copied, the meshing algorithm
      // will take care of it (e.g. ExtrudeMesh()).
      //ss->Method = s->Method;
      //ss->Recombine = s->Recombine;
      //ss->RecombineAngle = s->RecombineAngle;
      for(i = 0; i < 4; i++)
        ss->ipar[i] = s->ipar[i];
      ss->Nu = s->Nu;
      ss->Nv = s->Nv;
      ss->a = s->a;
      ss->b = s->b;
      ss->c = s->c;
      ss->d = s->d;
      for(i = 0; i < 3; i++)
        for(j = 0; j < 3; j++)
          ss->plan[i][j] = s->plan[i][j];
      for(i = 0; i < 3; i++)
        for(j = 0; j < 3; j++)
          ss->invplan[i][j] = s->invplan[i][j];
      ss->Generatrices =
        List_Create(List_Nbr(s->Generatrices), 1, sizeof(Curve *));
      List_Copy(s->Generatrices, ss->Generatrices);
      if(s->Control_Points) {
        ss->Control_Points =
          List_Create(List_Nbr(s->Control_Points), 1, sizeof(Vertex *));
        List_Copy(s->Control_Points, ss->Control_Points);
      }
      End_Surface(ss);
      Tree_Insert(THEM->Surfaces, &ss);
    }
    
    Surface *DuplicateSurface(Surface * s)
    {
      Surface *ps;
      Curve *c, *newc;
      Vertex *v, *newv;
      int i;
    
      ps = Create_Surface(NEWSURFACE(), 0);
      CopySurface(s, ps);
      for(i = 0; i < List_Nbr(ps->Generatrices); i++) {
        List_Read(ps->Generatrices, i, &c);
        newc = DuplicateCurve(c);
        List_Write(ps->Generatrices, i, &newc);
      }
    
      for(i = 0; i < List_Nbr(ps->Control_Points); i++) {
        List_Read(ps->Control_Points, i, &v);
        newv = DuplicateVertex(v);
        List_Write(ps->Control_Points, i, &newv);
      }
    
      return ps;
    }
    
    void CopyShape(int Type, int Num, int *New)
    {
      Surface *s, *news;
      Curve *c, *newc;
      Vertex *v, *newv;
    
      switch (Type) {
      case MSH_POINT:
        if(!(v = FindPoint(Num, THEM))) {
          Msg(GERROR, "Unknown vertex %d", Num);
          return;
        }
        newv = DuplicateVertex(v);
        *New = newv->Num;
        break;
      case MSH_SEGM_LINE:
      case MSH_SEGM_SPLN:
      case MSH_SEGM_BSPLN:
      case MSH_SEGM_BEZIER:
      case MSH_SEGM_CIRC:
      case MSH_SEGM_ELLI:
      case MSH_SEGM_NURBS:
      case MSH_SEGM_PARAMETRIC:
        if(!(c = FindCurve(Num, THEM))) {
          Msg(GERROR, "Unknown curve %d", Num);
          return;
        }
        newc = DuplicateCurve(c);
        *New = newc->Num;
        break;
      case MSH_SURF_NURBS:
      case MSH_SURF_TRIC:
      case MSH_SURF_REGL:
      case MSH_SURF_PLAN:
        if(!(s = FindSurface(Num, THEM))) {
          Msg(GERROR, "Unknown surface %d", Num);
          return;
        }
        news = DuplicateSurface(s);
        *New = news->Num;
        break;
      default:
        Msg(GERROR, "Impossible to copy entity %d (of type %d)", Num, Type);
        break;
      }
    }
    
    // FIXME: we still need to actually free the entity!
    
    void DeletePoint(int ip)
    {
      Vertex *v = FindPoint(ip, THEM);
      if(!v)
        return;
      List_T *Curves = Tree2List(THEM->Curves);
      for(int i = 0; i < List_Nbr(Curves); i++) {
        Curve *c;
        List_Read(Curves, i, &c);
        for(int j = 0; j < List_Nbr(c->Control_Points); j++) {
          if(!compareVertex(List_Pointer(c->Control_Points, j), &v))
            return;
        }
      }
      List_Delete(Curves);
      if(v->Num == THEM->MaxPointNum)
        THEM->MaxPointNum--;
      Tree_Suppress(THEM->Points, &v);
      Free_Vertex(&v, NULL);
    }
    
    void DeleteCurve(int ip)
    {
      Curve *c = FindCurve(ip, THEM);
      if(!c)
        return;
      List_T *Surfs = Tree2List(THEM->Surfaces);
      for(int i = 0; i < List_Nbr(Surfs); i++) {
        Surface *s;
        List_Read(Surfs, i, &s);
        for(int j = 0; j < List_Nbr(s->Generatrices); j++) {
          if(!compareCurve(List_Pointer(s->Generatrices, j), &c))
            return;
        }
      }
      List_Delete(Surfs);
      if(c->Num == THEM->MaxLineNum)
        THEM->MaxLineNum--;
      Tree_Suppress(THEM->Curves, &c);
      Free_Curve(&c, NULL);
    }
    
    void DeleteSurface(int is)
    {
      Surface *s = FindSurface(is, THEM);
      if(!s)
        return;
      List_T *Vols = Tree2List(THEM->Volumes);
      for(int i = 0; i < List_Nbr(Vols); i++) {
        Volume *v;
        List_Read(Vols, i, &v);
        for(int j = 0; j < List_Nbr(v->Surfaces); j++) {
          if(!compareSurface(List_Pointer(v->Surfaces, j), &s))
            return;
        }
      }
      List_Delete(Vols);
      if(s->Num == THEM->MaxSurfaceNum)
        THEM->MaxSurfaceNum--;
      Tree_Suppress(THEM->Surfaces, &s);
      Free_Surface(&s, NULL);
    }
    
    void DeleteVolume(int iv)
    {
      Volume *v = FindVolume(iv, THEM);
      if(!v)
        return;
      if(v->Num == THEM->MaxVolumeNum)
        THEM->MaxVolumeNum--;
      Tree_Suppress(THEM->Volumes, &v);
      Free_Volume(&v, NULL);
    }
    
    void DeleteShape(int Type, int Num)
    {
      switch (Type) {
      case MSH_POINT:
        DeletePoint(Num);
        break;
      case MSH_SEGM_LINE:
      case MSH_SEGM_SPLN:
      case MSH_SEGM_BSPLN:
      case MSH_SEGM_BEZIER:
      case MSH_SEGM_CIRC:
      case MSH_SEGM_ELLI:
      case MSH_SEGM_NURBS:
      case MSH_SEGM_PARAMETRIC:
        DeleteCurve(Num);
        break;
      case MSH_SURF_NURBS:
      case MSH_SURF_TRIC:
      case MSH_SURF_REGL:
      case MSH_SURF_PLAN:
        DeleteSurface(Num);
        break;
      case MSH_VOLUME:
        DeleteVolume(Num);
        break;
      default:
        Msg(GERROR, "Impossible to delete entity %d (of type %d)", Num, Type);
        break;
      }
    }
    
    void ColorCurve(int ip, unsigned int col)
    {
      Curve *c = FindCurve(ip, THEM);
      if(!c)
        return;
      c->Color.type = 1;
      c->Color.mesh = c->Color.geom = col;
    }
    
    void ColorSurface(int is, unsigned int col)
    {
      Surface *s = FindSurface(is, THEM);
      if(!s)
        return;
      s->Color.type = 1;
      s->Color.mesh = s->Color.geom = col;
    }
    
    void ColorVolume(int iv, unsigned int col)
    {
      Volume *v = FindVolume(iv, THEM);
      if(!v)
        return;
      v->Color.type = 1;
      v->Color.mesh = v->Color.geom = col;
    }
    
    void ColorShape(int Type, int Num, unsigned int Color)
    {
      switch (Type) {
      case MSH_POINT:
        break;
      case MSH_SEGM_LINE:
      case MSH_SEGM_SPLN:
      case MSH_SEGM_BSPLN:
      case MSH_SEGM_BEZIER:
      case MSH_SEGM_CIRC:
      case MSH_SEGM_ELLI:
      case MSH_SEGM_NURBS:
      case MSH_SEGM_PARAMETRIC:
        ColorCurve(Num, Color);
        break;
      case MSH_SURF_NURBS:
      case MSH_SURF_TRIC:
      case MSH_SURF_REGL:
      case MSH_SURF_PLAN:
        ColorSurface(Num, Color);
        break;
      case MSH_VOLUME:
        ColorVolume(Num, Color);
        break;
      default:
        break;
      }
    }
    
    void VisibilityShape(int Type, int Num, int Mode)
    {
      switch (Type) {
      case MSH_POINT:
        SetVisibilityByNumber(Num, 2, Mode);
        break;
      case MSH_SEGM_LINE:
      case MSH_SEGM_SPLN:
      case MSH_SEGM_BSPLN:
      case MSH_SEGM_BEZIER:
      case MSH_SEGM_CIRC:
      case MSH_SEGM_ELLI:
      case MSH_SEGM_NURBS:
      case MSH_SEGM_PARAMETRIC:
        SetVisibilityByNumber(Num, 3, Mode);
        break;
      case MSH_SURF_NURBS:
      case MSH_SURF_TRIC:
      case MSH_SURF_REGL:
      case MSH_SURF_PLAN:
        SetVisibilityByNumber(Num, 4, Mode);
        break;
      case MSH_VOLUME:
        SetVisibilityByNumber(Num, 5, Mode);
        break;
      default:
        break;
      }
    }
    
    Curve *CreateReversedCurve(Mesh * M, Curve * c)
    {
      Curve *newc;
      Vertex *e1, *e2, *e3, *e4;
      int i;
      newc = Create_Curve(-c->Num, c->Typ, 1, NULL, NULL, -1, -1, 0., 1.);
      newc->Control_Points =
        List_Create(List_Nbr(c->Control_Points), 1, sizeof(Vertex *));
      if(c->Typ == MSH_SEGM_ELLI || c->Typ == MSH_SEGM_ELLI_INV) {
        List_Read(c->Control_Points, 0, &e1);
        List_Read(c->Control_Points, 1, &e2);
        List_Read(c->Control_Points, 2, &e3);
        List_Read(c->Control_Points, 3, &e4);
        List_Add(newc->Control_Points, &e4);
        List_Add(newc->Control_Points, &e2);
        List_Add(newc->Control_Points, &e3);
        List_Add(newc->Control_Points, &e1);
      }
      else
        List_Invert(c->Control_Points, newc->Control_Points);
    
      if(c->Typ == MSH_SEGM_NURBS && c->k) {
        newc->k =
          (float *)malloc((c->degre + List_Nbr(c->Control_Points) + 1) *
                          sizeof(float));
        for(i = 0; i < c->degre + List_Nbr(c->Control_Points) + 1; i++)
          newc->k[c->degre + List_Nbr(c->Control_Points) - i] = c->k[i];
      }
    
      if(c->Typ == MSH_SEGM_CIRC)
        newc->Typ = MSH_SEGM_CIRC_INV;
      if(c->Typ == MSH_SEGM_CIRC_INV)
        newc->Typ = MSH_SEGM_CIRC;
      if(c->Typ == MSH_SEGM_ELLI)
        newc->Typ = MSH_SEGM_ELLI_INV;
      if(c->Typ == MSH_SEGM_ELLI_INV)
        newc->Typ = MSH_SEGM_ELLI;
      newc->Vertices = List_Create(10, 1, sizeof(Vertex *));
      newc->Method = c->Method;
      newc->degre = c->degre;
      newc->beg = c->end;
      newc->end = c->beg;
      newc->ubeg = 1. - c->uend;
      newc->uend = 1. - c->ubeg;
      End_Curve(newc);
    
      Curve **pc;
    
      if((pc = (Curve **) Tree_PQuery(M->Curves, &newc))) {
        Free_Curve(&newc, NULL);
        return *pc;
      }
      else{
        Tree_Add(M->Curves, &newc);
        return newc;
      }
    }
    
    void ModifyLcPoint(int ip, double lc)
    {
      Vertex *v = FindPoint(ip, THEM);
      if(v)
        v->lc = lc;
    }
    
    int recognize_seg(int typ, List_T * liste, int *seg)
    {
      int i, beg, end;
      Curve *pc;
    
      List_T *temp = Tree2List(THEM->Curves);
      List_Read(liste, 0, &beg);
      List_Read(liste, List_Nbr(liste) - 1, &end);
      for(i = 0; i < List_Nbr(temp); i++) {
        List_Read(temp, i, &pc);
        if(pc->Typ == typ && pc->beg->Num == beg && pc->end->Num == end) {
          List_Delete(temp);
          *seg = pc->Num;
          return 1;
        }
      }
      List_Delete(temp);
      return 0;
    }
    
    int recognize_loop(List_T * liste, int *loop)
    {
      int i, res;
      EdgeLoop *pe;
    
      res = 0;
      *loop = 0;
      List_T *temp = Tree2List(THEM->EdgeLoops);
      for(i = 0; i < List_Nbr(temp); i++) {
        List_Read(temp, i, &pe);
        if(!compare2Lists(pe->Curves, liste, fcmp_absint)) {
          res = 1;
          *loop = pe->Num;
          break;
        }
      }
      List_Delete(temp);
      return res;
    }
    
    int recognize_surfloop(List_T * liste, int *loop)
    {
      int i, res;
      EdgeLoop *pe;
    
      res = 0;
      *loop = 0;
      List_T *temp = Tree2List(THEM->SurfaceLoops);
      for(i = 0; i < List_Nbr(temp); i++) {
        List_Read(temp, i, &pe);
        if(!compare2Lists(pe->Curves, liste, fcmp_absint)) {
          res = 1;
          *loop = pe->Num;
          break;
        }
      }
      List_Delete(temp);
      return res;
    }
    
    // Linear applications
    
    void SetTranslationMatrix(double matrix[4][4], double T[3])
    {
      int i, j;
    
      for(i = 0; i < 4; i++) {
        for(j = 0; j < 4; j++) {
          matrix[i][j] = (i == j) ? 1.0 : 0.0;
        }
      }
      for(i = 0; i < 3; i++)
        matrix[i][3] = T[i];
    }
    
    void SetSymmetryMatrix(double matrix[4][4], double A, double B, double C,
                           double D)
    {
      double F = -2.0 / (A * A + B * B + C * C);
      matrix[0][0] = 1. + A * A * F;
      matrix[0][1] = A * B * F;
      matrix[0][2] = A * C * F;
      matrix[0][3] = A * D * F;
      matrix[1][0] = A * B * F;
      matrix[1][1] = 1. + B * B * F;
      matrix[1][2] = B * C * F;
      matrix[1][3] = B * D * F;
      matrix[2][0] = A * C * F;
      matrix[2][1] = B * C * F;
      matrix[2][2] = 1. + C * C * F;
      matrix[2][3] = C * D * F;
      matrix[3][0] = B * C * F;
      matrix[3][1] = 0.0;
      matrix[3][2] = 0.0;
      matrix[3][3] = 1.0;
    }
    
    void SetDilatationMatrix(double matrix[4][4], double T[3], double A)
    {
      matrix[0][0] = A;
      matrix[0][1] = 0.0;
      matrix[0][2] = 0.0;
      matrix[0][3] = T[0] * (1.0 - A);
      matrix[1][0] = 0.0;
      matrix[1][1] = A;
      matrix[1][2] = 0.0;
      matrix[1][3] = T[1] * (1.0 - A);
      matrix[2][0] = 0.0;
      matrix[2][1] = 0.0;
      matrix[2][2] = A;
      matrix[2][3] = T[2] * (1.0 - A);
      matrix[3][0] = 0.0;
      matrix[3][1] = 0.0;
      matrix[3][2] = 0.0;
      matrix[3][3] = 1.0;
    }
    
    static void GramSchmidt(double v1[3], double v2[3], double v3[3])
    {
      double tmp[3];
      norme(v1);
      prodve(v3, v1, tmp);
      norme(tmp);
      v2[0] = tmp[0];
      v2[1] = tmp[1];
      v2[2] = tmp[2];
      prodve(v1, v2, v3);
      norme(v3);
    }
    
    void SetRotationMatrix(double matrix[4][4], double Axe[3], double alpha)
    {
      double t1[3], t2[3];
      if(Axe[0] != 0.0) {
        t1[0] = 0.0;
        t1[1] = 1.0;
        t1[2] = 0.0;
        t2[0] = 0.0;
        t2[1] = 0.0;
        t2[2] = 1.0;
      }
      else if(Axe[1] != 0.0) {
        t1[0] = 1.0;
        t1[1] = 0.0;
        t1[2] = 0.0;
        t2[0] = 0.0;
        t2[1] = 0.0;
        t2[2] = 1.0;
      }
      else {
        t1[0] = 1.0;
        t1[1] = 0.0;
        t1[2] = 0.0;
        t2[0] = 0.0;
        t2[1] = 1.0;
        t2[2] = 0.0;
      }
      GramSchmidt(Axe, t1, t2);
      double rot[3][3], plan[3][3], invplan[3][3];
      plan[0][0] = Axe[0];
      plan[0][1] = Axe[1];
      plan[0][2] = Axe[2];
      plan[1][0] = t1[0];
      plan[1][1] = t1[1];
      plan[1][2] = t1[2];
      plan[2][0] = t2[0];
      plan[2][1] = t2[1];
      plan[2][2] = t2[2];
      rot[2][2] = cos(alpha);
      rot[2][1] = sin(alpha);
      rot[2][0] = 0.;
      rot[1][2] = -sin(alpha);
      rot[1][1] = cos(alpha);
      rot[1][0] = 0.;
      rot[0][2] = 0.;
      rot[0][1] = 0.;
      rot[0][0] = 1.;
      int i, j, k;
      for(i = 0; i < 3; i++)
        for(j = 0; j < 3; j++)
          invplan[i][j] = plan[j][i];
      double interm[3][3];
      for(i = 0; i < 3; i++)
        for(j = 0; j < 3; j++) {
          interm[i][j] = 0.0;
          for(k = 0; k < 3; k++)
            interm[i][j] += invplan[i][k] * rot[k][j];
        }
      for(i = 0; i < 4; i++)
        for(j = 0; j < 4; j++)
          matrix[i][j] = 0.0;
      for(i = 0; i < 3; i++)
        for(j = 0; j < 3; j++) {
          for(k = 0; k < 3; k++)
            matrix[i][j] += interm[i][k] * plan[k][j];
        }
      matrix[3][3] = 1.0;
    }
    
    static void vecmat4x4(double mat[4][4], double vec[4], double res[4])
    {
      int i, j;
      for(i = 0; i < 4; i++) {
        res[i] = 0.0;
        for(j = 0; j < 4; j++) {
          res[i] += mat[i][j] * vec[j];
        }
      }
    }
    
    void ApplyTransformationToPoint(double matrix[4][4], Vertex * v)
    {
      double pos[4], vec[4];
    
      if(!ListOfTransformedPoints)
        ListOfTransformedPoints = List_Create(50, 50, sizeof(int));
    
      if(!List_Search(ListOfTransformedPoints, &v->Num, fcmp_absint)) {
        List_Add(ListOfTransformedPoints, &v->Num);
      }
      else
        return;
    
      vec[0] = v->Pos.X;
      vec[1] = v->Pos.Y;
      vec[2] = v->Pos.Z;
      vec[3] = v->w;
      vecmat4x4(matrix, vec, pos);
      v->Pos.X = pos[0];
      v->Pos.Y = pos[1];
      v->Pos.Z = pos[2];
      v->w = pos[3];
    }
    
    void ApplyTransformationToCurve(double matrix[4][4], Curve * c)
    {
      Vertex *v;
    
      ApplyTransformationToPoint(matrix, c->beg);
      ApplyTransformationToPoint(matrix, c->end);
    
      for(int i = 0; i < List_Nbr(c->Control_Points); i++) {
        List_Read(c->Control_Points, i, &v);
        ApplyTransformationToPoint(matrix, v);
      }
      End_Curve(c);
    }
    
    void printCurve(Curve * c)
    {
      Vertex *v;
      int N = List_Nbr(c->Control_Points);
      Msg(DEBUG, "Curve %d %d cp (%d->%d)", c->Num, N, c->beg->Num, c->end->Num);
      for(int i = 0; i < N; i++) {
        List_Read(c->Control_Points, i, &v);
        Msg(DEBUG, "Vertex %d (%g,%g,%g,%g)", v->Num, v->Pos.X, v->Pos.Y,
            v->Pos.Z, v->lc);
      }
    }
    
    void ApplyTransformationToSurface(double matrix[4][4], Surface * s)
    {
      Curve *c;
      Vertex *v;
      int i;
    
      for(i = 0; i < List_Nbr(s->Generatrices); i++) {
        List_Read(s->Generatrices, i, &c);
        ApplyTransformationToCurve(matrix, c);
      }
      for(i = 0; i < List_Nbr(s->Control_Points); i++) {
        List_Read(s->Control_Points, i, &v);
        ApplyTransformationToPoint(matrix, v);
      }
      End_Surface(s);
    }
    
    void printSurface(Surface * s)
    {
      Curve *c;
      int N = List_Nbr(s->Generatrices);
    
      Msg(DEBUG, "Surface %d, %d generatrices", s->Num, N);
      for(int i = 0; i < N; i++) {
        List_Read(s->Generatrices, i, &c);
        printCurve(c);
      }
    }
    
    void ApplicationOnShapes(double matrix[4][4], List_T * ListShapes)
    {
      int i;
      Shape O;
      Vertex *v;
      Curve *c;
      Surface *s;
    
      List_Reset(ListOfTransformedPoints);
    
      for(i = 0; i < List_Nbr(ListShapes); i++) {
        List_Read(ListShapes, i, &O);
        switch (O.Type) {
        case MSH_POINT:
          v = FindPoint(O.Num, THEM);
          if(v)
            ApplyTransformationToPoint(matrix, v);
          else
            Msg(GERROR, "Unknown point %d", O.Num);
          break;
        case MSH_SEGM_LINE:
        case MSH_SEGM_SPLN:
        case MSH_SEGM_BSPLN:
        case MSH_SEGM_BEZIER:
        case MSH_SEGM_CIRC:
        case MSH_SEGM_ELLI:
        case MSH_SEGM_NURBS:
        case MSH_SEGM_PARAMETRIC:
          c = FindCurve(O.Num, THEM);
          if(c)
            ApplyTransformationToCurve(matrix, c);
          else
            Msg(GERROR, "Unknown curve %d", O.Num);
          break;
        case MSH_SURF_NURBS:
        case MSH_SURF_REGL:
        case MSH_SURF_TRIC:
        case MSH_SURF_PLAN:
          s = FindSurface(O.Num, THEM);
          if(s)
            ApplyTransformationToSurface(matrix, s);
          else
            Msg(GERROR, "Unknown surface %d", O.Num);
          break;
        default:
          Msg(GERROR, "Impossible to transform entity %d (of type %d)", O.Num,
              O.Type);
          break;
        }
      }
    
      List_Reset(ListOfTransformedPoints);
    }
    
    void TranslateShapes(double X, double Y, double Z,
                         List_T * ListShapes, int final)
    {
      double T[3], matrix[4][4];
    
      T[0] = X;
      T[1] = Y;
      T[2] = Z;
      SetTranslationMatrix(matrix, T);
      ApplicationOnShapes(matrix, ListShapes);
    
      if(CTX.geom.auto_coherence && final)
        ReplaceAllDuplicates(THEM);
    }
    
    void DilatShapes(double X, double Y, double Z, double A,
                     List_T * ListShapes, int final)
    {
      double T[3], matrix[4][4];
    
      T[0] = X;
      T[1] = Y;
      T[2] = Z;
      SetDilatationMatrix(matrix, T, A);
      ApplicationOnShapes(matrix, ListShapes);
    
      if(CTX.geom.auto_coherence && final)
        ReplaceAllDuplicates(THEM);
    }
    
    
    void RotateShapes(double Ax, double Ay, double Az,
                      double Px, double Py, double Pz,
                      double alpha, List_T * ListShapes, int final)
    {
      double A[3], T[3], matrix[4][4];
    
      T[0] = -Px;
      T[1] = -Py;
      T[2] = -Pz;
      SetTranslationMatrix(matrix, T);
      ApplicationOnShapes(matrix, ListShapes);
    
      A[0] = Ax;
      A[1] = Ay;
      A[2] = Az;
      SetRotationMatrix(matrix, A, alpha);
      ApplicationOnShapes(matrix, ListShapes);
    
      T[0] = Px;
      T[1] = Py;
      T[2] = Pz;
      SetTranslationMatrix(matrix, T);
      ApplicationOnShapes(matrix, ListShapes);
    
      if(CTX.geom.auto_coherence && final)
        ReplaceAllDuplicates(THEM);
    }
    
    void SymmetryShapes(double A, double B, double C,
                        double D, List_T * ListShapes, int final)
    {
      double matrix[4][4];
    
      SetSymmetryMatrix(matrix, A, B, C, D);
      ApplicationOnShapes(matrix, ListShapes);
    
      if(CTX.geom.auto_coherence && final)
        ReplaceAllDuplicates(THEM);
    }
    
    
    // Extrusion routines
    
    void ProtudeXYZ(double &x, double &y, double &z, ExtrudeParams * e)
    {
      double matrix[4][4];
      double T[3];
      Vertex v(x, y, z);
    
      T[0] = -e->geo.pt[0];
      T[1] = -e->geo.pt[1];
      T[2] = -e->geo.pt[2];
      SetTranslationMatrix(matrix, T);
      List_Reset(ListOfTransformedPoints);
      ApplyTransformationToPoint(matrix, &v);
    
      SetRotationMatrix(matrix, e->geo.axe, e->geo.angle);
      List_Reset(ListOfTransformedPoints);
      ApplyTransformationToPoint(matrix, &v);
    
      T[0] = -T[0];
      T[1] = -T[1];
      T[2] = -T[2];
      SetTranslationMatrix(matrix, T);
      List_Reset(ListOfTransformedPoints);
      ApplyTransformationToPoint(matrix, &v);
    
      x = v.Pos.X;
      y = v.Pos.Y;
      z = v.Pos.Z;
    
      List_Reset(ListOfTransformedPoints);
    }
    
    int Extrude_ProtudePoint(int type, int ip,
    			 double T0, double T1, double T2,
    			 double A0, double A1, double A2,
    			 double X0, double X1, double X2, double alpha,
    			 Curve ** pc, Curve ** prc, int final, 
    			 ExtrudeParams * e)
    {
      double matrix[4][4], T[3], Ax[3], d;
      Vertex V, *pv, *newp, *chapeau;
      Curve *c;
      int i;
    
      pv = &V;
      pv->Num = ip;
      *pc = *prc = NULL;
      if(!Tree_Query(THEM->Points, &pv))
        return 0;
    
      Msg(DEBUG, "Extrude Point %d", ip);
    
      chapeau = DuplicateVertex(pv);
    
      switch (type) {
    
      case TRANSLATE:
        T[0] = T0;
        T[1] = T1;
        T[2] = T2;
        SetTranslationMatrix(matrix, T);
        List_Reset(ListOfTransformedPoints);
        ApplyTransformationToPoint(matrix, chapeau);
    
        if(!comparePosition(&pv, &chapeau))
          return pv->Num;
        c = Create_Curve(NEWLINE(), MSH_SEGM_LINE, 1, NULL, NULL, -1, -1, 0., 1.);
        c->Control_Points = List_Create(2, 1, sizeof(Vertex *));
        c->Extrude = new ExtrudeParams;
        c->Extrude->fill(type, T0, T1, T2, A0, A1, A2, X0, X1, X2, alpha);
        c->Extrude->useZonLayer(final);
        if(e)
          c->Extrude->mesh = e->mesh;
    
        List_Add(c->Control_Points, &pv);
        List_Add(c->Control_Points, &chapeau);
        c->beg = pv;
        c->end = chapeau;
        break;
    
      case ROTATE:
        T[0] = -X0;
        T[1] = -X1;
        T[2] = -X2;
        SetTranslationMatrix(matrix, T);
        List_Reset(ListOfTransformedPoints);
        ApplyTransformationToPoint(matrix, chapeau);
    
        Ax[0] = A0;
        Ax[1] = A1;
        Ax[2] = A2;
        SetRotationMatrix(matrix, Ax, alpha);
        List_Reset(ListOfTransformedPoints);
        ApplyTransformationToPoint(matrix, chapeau);
    
        T[0] = X0;
        T[1] = X1;
        T[2] = X2;
        SetTranslationMatrix(matrix, T);
        List_Reset(ListOfTransformedPoints);
        ApplyTransformationToPoint(matrix, chapeau);
    
        if(!comparePosition(&pv, &chapeau))
          return pv->Num;
        c = Create_Curve(NEWLINE(), MSH_SEGM_CIRC, 1, NULL, NULL, -1, -1, 0., 1.);
        c->Control_Points = List_Create(3, 1, sizeof(Vertex *));
        c->Extrude = new ExtrudeParams;
        c->Extrude->fill(type, T0, T1, T2, A0, A1, A2, X0, X1, X2, alpha);
        if(e)
          c->Extrude->mesh = e->mesh;
        List_Add(c->Control_Points, &pv);
        // compute circle center
        newp = DuplicateVertex(pv);
        Ax[0] = A0;
        Ax[1] = A1;
        Ax[2] = A2;
        norme(Ax);
        T[0] = pv->Pos.X - X0;
        T[1] = pv->Pos.Y - X1;
        T[2] = pv->Pos.Z - X2;
        prosca(T, Ax, &d);
        newp->Pos.X = X0 + d * Ax[0];
        newp->Pos.Y = X1 + d * Ax[1]; 
        newp->Pos.Z = X2 + d * Ax[2]; 
        List_Add(c->Control_Points, &newp);
        List_Add(c->Control_Points, &chapeau);
        c->beg = pv;
        c->end = chapeau;
        break;
    
      case TRANSLATE_ROTATE:
        d = CTX.geom.extrude_spline_points;
        d = d ? d : 1;
        c = Create_Curve(NEWLINE(), MSH_SEGM_SPLN, 1, NULL, NULL, -1, -1, 0., 1.);
        c->Control_Points =
          List_Create(CTX.geom.extrude_spline_points + 1, 1, sizeof(Vertex *));
        c->Extrude = new ExtrudeParams;
        c->Extrude->fill(type, T0, T1, T2, A0, A1, A2, X0, X1, X2, alpha);
        if(e)
          c->Extrude->mesh = e->mesh;
        List_Add(c->Control_Points, &pv);
        c->beg = pv;
        for(i = 0; i < CTX.geom.extrude_spline_points; i++) {
          if(i)
            chapeau = DuplicateVertex(chapeau);
    
          T[0] = -X0;
          T[1] = -X1;
          T[2] = -X2;
          SetTranslationMatrix(matrix, T);
          List_Reset(ListOfTransformedPoints);
          ApplyTransformationToPoint(matrix, chapeau);
    
          Ax[0] = A0;
          Ax[1] = A1;
          Ax[2] = A2;
          SetRotationMatrix(matrix, Ax, alpha / d);
          List_Reset(ListOfTransformedPoints);
          ApplyTransformationToPoint(matrix, chapeau);
    
          T[0] = X0;
          T[1] = X1;
          T[2] = X2;
          SetTranslationMatrix(matrix, T);
          List_Reset(ListOfTransformedPoints);
          ApplyTransformationToPoint(matrix, chapeau);
    
          T[0] = T0 / d;
          T[1] = T1 / d;
          T[2] = T2 / d;
          SetTranslationMatrix(matrix, T);
          List_Reset(ListOfTransformedPoints);
          ApplyTransformationToPoint(matrix, chapeau);
    
          List_Add(c->Control_Points, &chapeau);
        }
        c->end = chapeau;
        break;
    
      default:
        Msg(GERROR, "Unknown extrusion type");
        return pv->Num;
      }
    
      End_Curve(c);
      Tree_Add(THEM->Curves, &c);
      CreateReversedCurve(THEM, c);
      *pc = c;
      *prc = FindCurve(-c->Num, THEM);
    
      List_Reset(ListOfTransformedPoints);
    
      if(CTX.geom.auto_coherence && final)
        ReplaceAllDuplicates(THEM);
    
      return chapeau->Num;
    }
    
    int Extrude_ProtudeCurve(int type, int ic,
    			 double T0, double T1, double T2,
    			 double A0, double A1, double A2,
    			 double X0, double X1, double X2, double alpha,
    			 Surface ** ps, int final, 
    			 ExtrudeParams * e)
    {
      double matrix[4][4], T[3], Ax[3];
      Curve *CurveBeg, *CurveEnd;
      Curve *ReverseChapeau, *ReverseBeg, *ReverseEnd;
      Curve *pc, *revpc, *chapeau;
      Surface *s;
    
      pc = FindCurve(ic, THEM);
      revpc = FindCurve(-ic, THEM);
      *ps = NULL;
    
      if(!pc || !revpc){
        return 0;
      }
    
      Msg(DEBUG, "Extrude Curve %d", ic);
    
      chapeau = DuplicateCurve(pc);
    
      chapeau->Extrude = new ExtrudeParams(COPIED_ENTITY);
      chapeau->Extrude->fill(type, T0, T1, T2, A0, A1, A2, X0, X1, X2, alpha);
      chapeau->Extrude->geo.Source = pc->Num;
      if(e)
        chapeau->Extrude->mesh = e->mesh;
    
      switch (type) {
      case TRANSLATE:
        T[0] = T0;
        T[1] = T1;
        T[2] = T2;
        SetTranslationMatrix(matrix, T);
        List_Reset(ListOfTransformedPoints);
        ApplyTransformationToCurve(matrix, chapeau);
        break;
      case ROTATE:
        T[0] = -X0;
        T[1] = -X1;
        T[2] = -X2;
        SetTranslationMatrix(matrix, T);
        List_Reset(ListOfTransformedPoints);
        ApplyTransformationToCurve(matrix, chapeau);
    
        Ax[0] = A0;
        Ax[1] = A1;
        Ax[2] = A2;
        SetRotationMatrix(matrix, Ax, alpha);
        List_Reset(ListOfTransformedPoints);
        ApplyTransformationToCurve(matrix, chapeau);
    
        T[0] = X0;
        T[1] = X1;
        T[2] = X2;
        SetTranslationMatrix(matrix, T);
        List_Reset(ListOfTransformedPoints);
        ApplyTransformationToCurve(matrix, chapeau);
        break;
      case TRANSLATE_ROTATE:
        T[0] = -X0;
        T[1] = -X1;
        T[2] = -X2;
        SetTranslationMatrix(matrix, T);
        List_Reset(ListOfTransformedPoints);
        ApplyTransformationToCurve(matrix, chapeau);
    
        Ax[0] = A0;
        Ax[1] = A1;
        Ax[2] = A2;
        SetRotationMatrix(matrix, Ax, alpha);
        List_Reset(ListOfTransformedPoints);
        ApplyTransformationToCurve(matrix, chapeau);
    
        T[0] = X0;
        T[1] = X1;
        T[2] = X2;
        SetTranslationMatrix(matrix, T);
        List_Reset(ListOfTransformedPoints);
        ApplyTransformationToCurve(matrix, chapeau);
    
        T[0] = T0;
        T[1] = T1;
        T[2] = T2;
        SetTranslationMatrix(matrix, T);
        List_Reset(ListOfTransformedPoints);
        ApplyTransformationToCurve(matrix, chapeau);
        break;
      default:
        Msg(GERROR, "Unknown extrusion type");
        return pc->Num;
      }
    
      Extrude_ProtudePoint(type, pc->beg->Num, T0, T1, T2,
                           A0, A1, A2, X0, X1, X2, alpha,
                           &CurveBeg, &ReverseBeg, 0, e);
      Extrude_ProtudePoint(type, pc->end->Num, T0, T1, T2,
                           A0, A1, A2, X0, X1, X2, alpha,
                           &CurveEnd, &ReverseEnd, 0, e);
    
      if(!CurveBeg && !CurveEnd){
        return pc->Num;
      }
    
      if(!CurveBeg || !CurveEnd)
        s = Create_Surface(NEWSURFACE(), MSH_SURF_TRIC);
      else
        s = Create_Surface(NEWSURFACE(), MSH_SURF_REGL);
    
      s->Generatrices = List_Create(4, 1, sizeof(Curve *));
      s->Extrude = new ExtrudeParams;
      s->Extrude->fill(type, T0, T1, T2, A0, A1, A2, X0, X1, X2, alpha);
      s->Extrude->useZonLayer(final);
      s->Extrude->geo.Source = pc->Num;
      if(e)
        s->Extrude->mesh = e->mesh;
    
      ReverseChapeau = FindCurve(-chapeau->Num, THEM);
    
      if(!CurveBeg) {
        List_Add(s->Generatrices, &pc);
        List_Add(s->Generatrices, &CurveEnd);
        List_Add(s->Generatrices, &ReverseChapeau);
      }
      else if(!CurveEnd) {
        List_Add(s->Generatrices, &ReverseChapeau);
        List_Add(s->Generatrices, &ReverseBeg);
        List_Add(s->Generatrices, &pc);
      }
      else {
        List_Add(s->Generatrices, &pc);
        List_Add(s->Generatrices, &CurveEnd);
        List_Add(s->Generatrices, &ReverseChapeau);
        List_Add(s->Generatrices, &ReverseBeg);
      }
    
      End_Surface(s);
      Tree_Add(THEM->Surfaces, &s);
    
      List_Reset(ListOfTransformedPoints);
    
      *ps = s;
    
      if(CTX.geom.auto_coherence && final)
        ReplaceAllDuplicates(THEM);
    
      return chapeau->Num;
    }
    
    int Extrude_ProtudeSurface(int type, int is,
    			   double T0, double T1, double T2,
    			   double A0, double A1, double A2,
    			   double X0, double X1, double X2, double alpha,
    			   Volume **pv, ExtrudeParams * e)
    {
      double matrix[4][4], T[3], Ax[3];
      Curve *c, *c2;
      int i;
      Surface *s, *ps, *chapeau;
    
      *pv = NULL;
    
      if(!(ps = FindSurface(is, THEM)))
        return 0;
    
      Msg(DEBUG, "Extrude Surface %d", is);
    
      chapeau = DuplicateSurface(ps);
    
      chapeau->Extrude = new ExtrudeParams(COPIED_ENTITY);
      chapeau->Extrude->fill(type, T0, T1, T2, A0, A1, A2, X0, X1, X2, alpha);
      chapeau->Extrude->geo.Source = ps->Num;
      if(e)
        chapeau->Extrude->mesh = e->mesh;
    
      for(i = 0; i < List_Nbr(chapeau->Generatrices); i++) {
        List_Read(ps->Generatrices, i, &c2);
        List_Read(chapeau->Generatrices, i, &c);
        if(c->Num < 0)
          if(!(c = FindCurve(-c->Num, THEM))) {
            Msg(GERROR, "Unknown curve %d", -c->Num);
            return ps->Num;
          }
        c->Extrude = new ExtrudeParams(COPIED_ENTITY);
        c->Extrude->fill(type, T0, T1, T2, A0, A1, A2, X0, X1, X2, alpha);
        //pas de abs()! il faut le signe pour copy_mesh dans ExtrudeMesh
        c->Extrude->geo.Source = c2->Num;
        if(e)
          c->Extrude->mesh = e->mesh;
      }
    
      // FIXME: this is a really ugly hack for backward compatibility, so
      // that we don't screw up the old .geo files too much. (Before
      // version 1.54, we didn't always create new volumes during "Extrude
      // Surface". Now we do, but with "CTX.geom.old_newreg==1", this
      // bumps the NEWREG() counter, and thus changes the whole automatic
      // numbering sequence.) So we locally force old_newreg to 0: in most
      // cases, since we define points, curves, etc., before defining
      // volumes, the NEWVOLUME() call below will return a fairly low
      // number, that will not interfere with the other numbers...
      int tmp = CTX.geom.old_newreg;
      CTX.geom.old_newreg = 0;
      Volume *v = Create_Volume(NEWVOLUME(), MSH_VOLUME);
      CTX.geom.old_newreg = tmp;
    
      v->Extrude = new ExtrudeParams;
      v->Extrude->fill(type, T0, T1, T2, A0, A1, A2, X0, X1, X2, alpha);
      v->Extrude->geo.Source = is;
      if(e)
        v->Extrude->mesh = e->mesh;
      int ori = 1;;
      List_Add(v->Surfaces, &ps);
      List_Add(v->SurfacesOrientations, &ori);
      ori = -1;
      List_Add(v->Surfaces, &chapeau);
      List_Add(v->SurfacesOrientations, &ori);
    
      for(i = 0; i < List_Nbr(ps->Generatrices); i++) {
        List_Read(ps->Generatrices, i, &c);
        Extrude_ProtudeCurve(type, c->Num, T0, T1, T2, A0, A1, A2, X0, X1, X2,
    			 alpha, &s, 0, e);
        if(s){
          ori = -1;
          List_Add(v->Surfaces, &s);
          List_Add(v->SurfacesOrientations, &ori);
        }
      }
    
      switch (type) {
      case TRANSLATE:
        T[0] = T0;
        T[1] = T1;
        T[2] = T2;
        SetTranslationMatrix(matrix, T);
        List_Reset(ListOfTransformedPoints);
        ApplyTransformationToSurface(matrix, chapeau);
        break;
      case ROTATE:
        T[0] = -X0;
        T[1] = -X1;
        T[2] = -X2;
        SetTranslationMatrix(matrix, T);
        List_Reset(ListOfTransformedPoints);
        ApplyTransformationToSurface(matrix, chapeau);
    
        Ax[0] = A0;
        Ax[1] = A1;
        Ax[2] = A2;
        SetRotationMatrix(matrix, Ax, alpha);
        List_Reset(ListOfTransformedPoints);
        ApplyTransformationToSurface(matrix, chapeau);
    
        T[0] = X0;
        T[1] = X1;
        T[2] = X2;
        SetTranslationMatrix(matrix, T);
        List_Reset(ListOfTransformedPoints);
        ApplyTransformationToSurface(matrix, chapeau);
        break;
      case TRANSLATE_ROTATE:
        T[0] = -X0;
        T[1] = -X1;
        T[2] = -X2;
        SetTranslationMatrix(matrix, T);
        List_Reset(ListOfTransformedPoints);
        ApplyTransformationToSurface(matrix, chapeau);
    
        Ax[0] = A0;
        Ax[1] = A1;
        Ax[2] = A2;
        SetRotationMatrix(matrix, Ax, alpha);
        List_Reset(ListOfTransformedPoints);
        ApplyTransformationToSurface(matrix, chapeau);
    
        T[0] = X0;
        T[1] = X1;
        T[2] = X2;
        SetTranslationMatrix(matrix, T);
        List_Reset(ListOfTransformedPoints);
        ApplyTransformationToSurface(matrix, chapeau);
    
        T[0] = T0;
        T[1] = T1;
        T[2] = T2;
        SetTranslationMatrix(matrix, T);
        List_Reset(ListOfTransformedPoints);
        ApplyTransformationToSurface(matrix, chapeau);
        break;
      default:
        Msg(GERROR, "Unknown extrusion type");
        return ps->Num;
      }
    
      // FIXME: why do we do this? only for backward compatibility?
      Tree_Suppress(THEM->Surfaces, &chapeau);
      chapeau->Num = NEWSURFACE();
      THEM->MaxSurfaceNum = chapeau->Num;
      Tree_Add(THEM->Surfaces, &chapeau);
    
      Tree_Add(THEM->Volumes, &v);
    
      *pv = v;
    
      if(CTX.geom.auto_coherence)
        ReplaceAllDuplicates(THEM);
    
      List_Reset(ListOfTransformedPoints);
    
      return chapeau->Num;
    }
    
    // Duplicate removal
    
    int compareTwoCurves(const void *a, const void *b)
    {
      Curve *c1, *c2;
      c1 = *(Curve **) a;
      c2 = *(Curve **) b;
      int comp;
    
      if(c1->Typ != c2->Typ){
        if((c1->Typ == MSH_SEGM_CIRC && c2->Typ == MSH_SEGM_CIRC_INV) ||
           (c1->Typ == MSH_SEGM_CIRC_INV && c2->Typ == MSH_SEGM_CIRC) ||
           (c1->Typ == MSH_SEGM_ELLI && c2->Typ == MSH_SEGM_ELLI_INV) ||
           (c1->Typ == MSH_SEGM_ELLI_INV && c2->Typ == MSH_SEGM_ELLI)){
          // this is still ok
        }
        else
          return c1->Typ - c2->Typ;
      }
    
      if(List_Nbr(c1->Control_Points) != List_Nbr(c2->Control_Points))
        return List_Nbr(c1->Control_Points) - List_Nbr(c2->Control_Points);
      
      if(!List_Nbr(c1->Control_Points)){
        comp = compareVertex(&c1->beg, &c2->beg);
        if(comp)
          return comp;
        comp = compareVertex(&c1->end, &c2->end);
        if(comp)
          return comp;
      }
      else {
        for(int i = 0; i < List_Nbr(c1->Control_Points); i++){
          Vertex *v1, *v2;
          List_Read(c1->Control_Points, i, &v1);
          List_Read(c2->Control_Points, i, &v2);
          comp = compareVertex(&v1, &v2);
          if(comp)
    	return comp;
        }
      }
    
      return 0;
    }
    
    int compareAbsCurve(const void *a, const void *b)
    {
      Curve **q, **w;
    
      q = (Curve **) a;
      w = (Curve **) b;
      return (abs((*q)->Num) - abs((*w)->Num));
    }
    
    int compareTwoSurfaces(const void *a, const void *b)
    {
      Surface *s1, *s2;
      s1 = *(Surface **) a;
      s2 = *(Surface **) b;
      return compare2Lists(s1->Generatrices, s2->Generatrices, compareAbsCurve);
    }
    
    void MaxNumPoint(void *a, void *b)
    {
      Vertex *v = *(Vertex **) a;
      THEM->MaxPointNum = MAX(THEM->MaxPointNum, v->Num);
    }
    
    void MaxNumCurve(void *a, void *b)
    {
      Curve *c = *(Curve **) a;
      THEM->MaxLineNum = MAX(THEM->MaxLineNum, c->Num);
    }
    
    void MaxNumSurface(void *a, void *b)
    {
      Surface *s = *(Surface **) a;
      THEM->MaxSurfaceNum = MAX(THEM->MaxSurfaceNum, s->Num);
    }
    
    void ReplaceDuplicatePoints(Mesh * m)
    {
      List_T *All;
      Tree_T *allNonDuplicatedPoints;
      Vertex *v, **pv, **pv2;
      Curve *c;
      Surface *s;
      Volume *vol;
      int i, j, start, end;
    
      List_T *points2delete = List_Create(100, 100, sizeof(Vertex *));
    
      // Create unique points
    
      start = Tree_Nbr(m->Points);
    
      All = Tree2List(m->Points);
      allNonDuplicatedPoints = Tree_Create(sizeof(Vertex *), comparePosition);
      for(i = 0; i < List_Nbr(All); i++) {
        List_Read(All, i, &v);
        if(!Tree_Search(allNonDuplicatedPoints, &v)) {
          Tree_Insert(allNonDuplicatedPoints, &v);
        }
        else {
          Tree_Suppress(m->Points, &v);
          Tree_Suppress(m->Vertices, &v);
          //List_Add(points2delete,&v);      
        }
      }
      List_Delete(All);
    
      end = Tree_Nbr(m->Points);
    
      if(start == end) {
        Tree_Delete(allNonDuplicatedPoints);
        List_Delete(points2delete);
        return;
      }
    
      Msg(DEBUG, "Removed %d duplicate points", start - end);
    
      if(CTX.geom.old_newreg) {
        m->MaxPointNum = 0;
        Tree_Action(m->Points, MaxNumPoint);
        Tree_Action(m->Vertices, MaxNumPoint);
      }
    
      // Replace old points in curves
    
      All = Tree2List(m->Curves);
      for(i = 0; i < List_Nbr(All); i++) {
        List_Read(All, i, &c);
        if(!Tree_Query(allNonDuplicatedPoints, &c->beg))
          Msg(GERROR, "Weird point %d in Coherence", c->beg->Num);
        if(!Tree_Query(allNonDuplicatedPoints, &c->end))
          Msg(GERROR, "Weird point %d in Coherence", c->end->Num);
        for(j = 0; j < List_Nbr(c->Control_Points); j++) {
          pv = (Vertex **) List_Pointer(c->Control_Points, j);
          if(!(pv2 = (Vertex **) Tree_PQuery(allNonDuplicatedPoints, pv)))
            Msg(GERROR, "Weird point %d in Coherence", (*pv)->Num);
          else
            List_Write(c->Control_Points, j, pv2);
        }
      }
      List_Delete(All);
    
      // Replace old points in surfaces
    
      All = Tree2List(m->Surfaces);
      for(i = 0; i < List_Nbr(All); i++) {
        List_Read(All, i, &s);
        for(j = 0; j < List_Nbr(s->Control_Points); j++) {
          pv = (Vertex **) List_Pointer(s->Control_Points, j);
          if(!(pv2 = (Vertex **) Tree_PQuery(allNonDuplicatedPoints, pv)))
            Msg(GERROR, "Weird point %d in Coherence", (*pv)->Num);
          else
            List_Write(s->Control_Points, j, pv2);
        }
        for(j = 0; j < List_Nbr(s->TrsfPoints); j++){
          pv = (Vertex **) List_Pointer(s->TrsfPoints, j);
          if(!(pv2 = (Vertex **) Tree_PQuery(allNonDuplicatedPoints, pv)))
    	Msg(GERROR, "Weird point %d in Coherence", (*pv)->Num);
          else
    	List_Write(s->TrsfPoints, j, pv2);
        }
      }
      List_Delete(All);
      
      // Replace old points in volumes
    
      All = Tree2List(m->Volumes);
      for(i = 0; i < List_Nbr(All); i++) {
        List_Read(All, i, &vol);
        for(j = 0; j < List_Nbr(vol->TrsfPoints); j++){
          pv = (Vertex **) List_Pointer(vol->TrsfPoints, j);
          if(!(pv2 = (Vertex **) Tree_PQuery(allNonDuplicatedPoints, pv)))
    	Msg(GERROR, "Weird point %d in Coherence", (*pv)->Num);
          else
    	List_Write(vol->TrsfPoints, j, pv2);
        }
      }
      List_Delete(All);
    
      for(int k = 0; k < List_Nbr(points2delete); k++) {
        List_Read(points2delete, i, &v);
        Free_Vertex(&v, 0);
      }
    
      Tree_Delete(allNonDuplicatedPoints);
      List_Delete(points2delete);
    
    }
    
    void ReplaceDuplicateCurves(Mesh * m)
    {
      List_T *All;
      Tree_T *allNonDuplicatedCurves;
      Curve *c, *c2, **pc, **pc2;
      Surface *s;
      int i, j, start, end;
    
      // Create unique curves
    
      start = Tree_Nbr(m->Curves);
    
      All = Tree2List(m->Curves);
      allNonDuplicatedCurves = Tree_Create(sizeof(Curve *), compareTwoCurves);
      for(i = 0; i < List_Nbr(All); i++) {
        List_Read(All, i, &c);
        if(c->Num > 0) {
          if(!Tree_Search(allNonDuplicatedCurves, &c)) {
            Tree_Insert(allNonDuplicatedCurves, &c);
            if(!(c2 = FindCurve(-c->Num, m))) {
              Msg(GERROR, "Unknown curve %d", -c->Num);
              List_Delete(All);
              return;
            }
            Tree_Insert(allNonDuplicatedCurves, &c2);
          }
          else {
            Tree_Suppress(m->Curves, &c);
            if(!(c2 = FindCurve(-c->Num, m))) {
              Msg(GERROR, "Unknown curve %d", -c->Num);
              List_Delete(All);
              return;
            }
            Tree_Suppress(m->Curves, &c2);
          }
        }
      }
      List_Delete(All);
    
      end = Tree_Nbr(m->Curves);
    
      if(start == end) {
        Tree_Delete(allNonDuplicatedCurves);
        return;
      }
    
      Msg(DEBUG, "Removed %d duplicate curves", start - end);
    
      if(CTX.geom.old_newreg) {
        m->MaxLineNum = 0;
        Tree_Action(m->Curves, MaxNumCurve);
      }
    
      // Replace old curves in surfaces
    
      All = Tree2List(m->Surfaces);
      for(i = 0; i < List_Nbr(All); i++) {
        List_Read(All, i, &s);
        for(j = 0; j < List_Nbr(s->Generatrices); j++) {
          pc = (Curve **) List_Pointer(s->Generatrices, j);
          if(!(pc2 = (Curve **) Tree_PQuery(allNonDuplicatedCurves, pc)))
            Msg(GERROR, "Weird curve %d in Coherence", (*pc)->Num);
          else {
            List_Write(s->Generatrices, j, pc2);
            // Arghhh. Revoir compareTwoCurves !
            End_Curve(*pc2);
          }
        }
      }
      List_Delete(All);
    
      Tree_Delete(allNonDuplicatedCurves);
    }
    
    void ReplaceDuplicateSurfaces(Mesh * m)
    {
      List_T *All;
      Tree_T *allNonDuplicatedSurfaces;
      Surface *s, **ps, **ps2;
      Volume *vol;
      int i, j, start, end;
    
      // Create unique surfaces
    
      start = Tree_Nbr(m->Surfaces);
    
      All = Tree2List(m->Surfaces);
      allNonDuplicatedSurfaces = Tree_Create(sizeof(Curve *), compareTwoSurfaces);
      for(i = 0; i < List_Nbr(All); i++) {
        List_Read(All, i, &s);
        if(s->Num > 0) {
          if(!Tree_Search(allNonDuplicatedSurfaces, &s)) {
            Tree_Insert(allNonDuplicatedSurfaces, &s);
          }
          else {
            Tree_Suppress(m->Surfaces, &s);
          }
        }
      }
      List_Delete(All);
    
      end = Tree_Nbr(m->Surfaces);
    
      if(start == end) {
        Tree_Delete(allNonDuplicatedSurfaces);
        return;
      }
    
      Msg(DEBUG, "Removed %d duplicate surfaces", start - end);
    
      if(CTX.geom.old_newreg) {
        m->MaxSurfaceNum = 0;
        Tree_Action(m->Surfaces, MaxNumSurface);
      } 
    
      // Replace old surfaces in volumes
    
      All = Tree2List(m->Volumes);
      for(i = 0; i < List_Nbr(All); i++) {
        List_Read(All, i, &vol);
        for(j = 0; j < List_Nbr(vol->Surfaces); j++) {
          ps = (Surface **) List_Pointer(vol->Surfaces, j);
          if(!(ps2 = (Surface **) Tree_PQuery(allNonDuplicatedSurfaces, ps)))
            Msg(GERROR, "Weird surface %d in Coherence", (*ps)->Num);
          else
            List_Write(vol->Surfaces, j, ps2);
        }
      }
      List_Delete(All);
    
      Tree_Delete(allNonDuplicatedSurfaces);
    }
    
    void ReplaceAllDuplicates(Mesh * m)
    {
      ReplaceDuplicatePoints(m);
      ReplaceDuplicateCurves(m);
      ReplaceDuplicateSurfaces(m);
    }
    
    
    // Inetersection routines
    // FIXME: this code is full of crap :-)
    
    /*
      S = (sx(u,v),sy(u,v),sz(u,v))
      C = (cx(w),cy(w),cz(w))
    
      sx - cx = 0
      sy - cy = 0
      sz - cz = 0
      
      3eqs 3incs
    */
    
    static Curve *CURVE, *CURVE_2;
    static Surface *SURFACE;
    static Vertex *VERTEX;
    
    double min1d(double (*funct) (double), double *xmin)
    {
      // we should think about the tolerance more carefully...
      double ax = 1.e-15, bx = 1.e-12, cx = 1.e-11, fa, fb, fx, tol = 1.e-4;
      mnbrak(&ax, &bx, &cx, &fa, &fx, &fb, funct);
      //Msg(INFO, "--MIN1D : ax %12.5E bx %12.5E cx %12.5E",ax,bx,cx);  
      return (brent(ax, bx, cx, funct, tol, xmin));
    }
    
    static void intersectCS(int N, double x[], double res[])
    {
      //x[1] = u x[2] = v x[3] = w
      Vertex s, c;
      s = InterpolateSurface(SURFACE, x[1], x[2], 0, 0);
      c = InterpolateCurve(CURVE, x[3], 0);
      res[1] = s.Pos.X - c.Pos.X;
      res[2] = s.Pos.Y - c.Pos.Y;
      res[3] = s.Pos.Z - c.Pos.Z;
    }
    
    static void intersectCC(int N, double x[], double res[])
    {
      //x[1] = u x[2] = v
      Vertex c2, c;
      c2 = InterpolateCurve(CURVE_2, x[2], 0);
      c = InterpolateCurve(CURVE, x[1], 0);
      res[1] = c2.Pos.X - c.Pos.X;
      res[2] = c2.Pos.Y - c.Pos.Y;
    }
    
    static void projectPS(int N, double x[], double res[])
    {
      //x[1] = u x[2] = v
      Vertex du, dv, c;
      c = InterpolateSurface(SURFACE, x[1], x[2], 0, 0);
      du = InterpolateSurface(SURFACE, x[1], x[2], 1, 1);
      dv = InterpolateSurface(SURFACE, x[1], x[2], 1, 2);
      res[1] =
        (c.Pos.X - VERTEX->Pos.X) * du.Pos.X +
        (c.Pos.Y - VERTEX->Pos.Y) * du.Pos.Y +
        (c.Pos.Z - VERTEX->Pos.Z) * du.Pos.Z;
      res[2] =
        (c.Pos.X - VERTEX->Pos.X) * dv.Pos.X +
        (c.Pos.Y - VERTEX->Pos.Y) * dv.Pos.Y +
        (c.Pos.Z - VERTEX->Pos.Z) * dv.Pos.Z;
    }
    
    static double projectPC(double u)
    {
      //x[1] = u x[2] = v
      if(u < CURVE->ubeg)
        u = CURVE->ubeg;
      if(u < CURVE->ubeg)
        u = CURVE->ubeg;
      Vertex c;
      c = InterpolateCurve(CURVE, u, 0);
      return sqrt(DSQR(c.Pos.X - VERTEX->Pos.X) +
                  DSQR(c.Pos.Y - VERTEX->Pos.Y) + DSQR(c.Pos.Z - VERTEX->Pos.Z));
    }
    
    static int UFIXED = 0;
    static double FIX;
    static double projectPCS(double u)
    {
      //x[1] = u x[2] = v
      double tmin, tmax;
      if(UFIXED) {
        tmin = SURFACE->kv[0];
        tmax = SURFACE->kv[SURFACE->Nv + SURFACE->OrderV];
      }
      else {
        tmin = SURFACE->ku[0];
        tmax = SURFACE->ku[SURFACE->Nu + SURFACE->OrderU];
      }
    
      if(u < tmin)
        u = tmin;
      if(u > tmax)
        u = tmax;
      Vertex c;
      if(UFIXED)
        c = InterpolateSurface(SURFACE, FIX, u, 0, 0);
      else
        c = InterpolateSurface(SURFACE, u, FIX, 0, 0);
      return sqrt(DSQR(c.Pos.X - VERTEX->Pos.X) +
                  DSQR(c.Pos.Y - VERTEX->Pos.Y) + DSQR(c.Pos.Z - VERTEX->Pos.Z));
    }
    
    bool ProjectPointOnCurve(Curve * c, Vertex * v, Vertex * RES, Vertex * DER)
    {
      double xmin;
      CURVE = c;
      VERTEX = v;
      min1d(projectPC, &xmin);
      *RES = InterpolateCurve(CURVE, xmin, 0);
      *DER = InterpolateCurve(CURVE, xmin, 1);
      if(xmin > c->uend) {
        *RES = InterpolateCurve(CURVE, c->uend, 0);
        *DER = InterpolateCurve(CURVE, c->uend, 1);
      }
      else if(xmin < c->ubeg) {
        *RES = InterpolateCurve(CURVE, c->ubeg, 0);
        *DER = InterpolateCurve(CURVE, c->ubeg, 1);
      }
      return true;
    }
    
    bool search_in_boundary(Surface * s, Vertex * p, double t, int Fixu,
                            double *uu, double *vv)
    {
      double l, umin = 0., vmin = 0., lmin = 1.e200;
      int i, N;
      Vertex vr;
      double tmin, tmax, u, v;
    
      if(Fixu) {
        tmin = s->kv[0];
        tmax = s->kv[s->Nv + s->OrderV];
        N = 3 * s->Nu;
      }
      else {
        tmin = s->ku[0];
        tmax = s->ku[s->Nu + s->OrderU];
        N = 3 * s->Nv;
      }
      for(i = 0; i < N; i++) {
        if(Fixu) {
          u = t;
          v = tmin + (tmax - tmin) * (double)(i) / (double)(N - 1);
        }
        else {
          v = t;
          u = tmin + (tmax - tmin) * (double)(i) / (double)(N - 1);
        }
        vr = InterpolateSurface(SURFACE, u, v, 0, 0);
        l = sqrt(DSQR(vr.Pos.X - p->Pos.X) +
                 DSQR(vr.Pos.Y - p->Pos.Y) + DSQR(vr.Pos.Z - p->Pos.Z));
        if(l < lmin) {
          lmin = l;
          umin = u;
          vmin = v;
        }
      }
    
      FIX = t;
      UFIXED = Fixu;
      double xm;
      if(Fixu)
        xm = vmin;
      else
        xm = umin;
      if(lmin > 1.e-3)
        min1d(projectPCS, &xm);
      if(Fixu) {
        *uu = t;
        *vv = xm;
      }
      else {
        *vv = t;
        *uu = xm;
      }
      vr = InterpolateSurface(SURFACE, *uu, *vv, 0, 0);
      l = sqrt(DSQR(vr.Pos.X - p->Pos.X) +
               DSQR(vr.Pos.Y - p->Pos.Y) + DSQR(vr.Pos.Z - p->Pos.Z));
      if(l < 1.e-3)
        return true;
      return false;
    }
    
    bool try_a_value(Surface * s, Vertex * p, double u, double v, double *uu,
                     double *vv)
    {
      Vertex vr = InterpolateSurface(s, u, v, 0, 0);
      double l = sqrt(DSQR(vr.Pos.X - p->Pos.X) +
                      DSQR(vr.Pos.Y - p->Pos.Y) + DSQR(vr.Pos.Z - p->Pos.Z));
      *uu = u;
      *vv = v;
      if(l < 1.e-3)
        return true;
      return false;
    }
    
    bool ProjectPointOnSurface(Surface * s, Vertex & p)
    {
      double x[3] = { 0.5, 0.5, 0.5 };
      Vertex vv;
      int check;
      SURFACE = s;
      VERTEX = &p;
      double UMIN = 0.;
      double UMAX = 1.;
      double VMIN = 0.;
      double VMAX = 1.;
      while(1) {
        newt(x, 2, &check, projectPS);
        vv = InterpolateSurface(s, x[1], x[2], 0, 0);
        if(x[1] >= UMIN && x[1] <= UMAX && x[2] >= VMIN && x[2] <= VMAX)
          break;
        x[1] = UMIN + (UMAX - UMIN) * ((rand() % 10000) / 10000.);
        x[2] = VMIN + (VMAX - VMIN) * ((rand() % 10000) / 10000.);
      }
      p.Pos.X = vv.Pos.X;
      p.Pos.Y = vv.Pos.Y;
      p.Pos.Z = vv.Pos.Z;
      if(!check) {
        return false;
      }
      return true;
    }
    
    bool ProjectPointOnSurface(Surface * s, Vertex * p, double *u, double *v)
    {
      static double x[3];
      int check;
      static int deb = 1;
      double VMIN, VMAX, UMIN, UMAX, l, lmin;
      Vertex vv;
    
      SURFACE = s;
      VERTEX = p;
      lmin = 1.e24;
      UMAX = s->ku[s->Nu + s->OrderU];
      UMIN = s->ku[0];
      VMAX = s->kv[s->Nv + s->OrderV];
      VMIN = s->kv[0];
      if(deb) {
        x[1] = UMIN + (UMAX - UMIN) * ((rand() % 10000) / 10000.);
        x[2] = VMIN + (VMAX - VMIN) * ((rand() % 10000) / 10000.);
        deb = 0;
      }
    
      if(p->Num == 160) {
        lmin += 1.e90;
        if(p->Num == 133)
          UMAX = s->ku[s->Nu + s->OrderU];
      }
    
      if(try_a_value(SURFACE, VERTEX, SURFACE->ku[0] + VERTEX->u,
                     SURFACE->kv[0], u, v))
        return true;
      if(try_a_value(SURFACE, VERTEX, SURFACE->ku[0] + VERTEX->u,
                     SURFACE->kv[SURFACE->Nv + SURFACE->OrderV], u, v))
        return true;
      if(try_a_value
         (SURFACE, VERTEX, SURFACE->ku[SURFACE->Nu + SURFACE->OrderU] - VERTEX->u,
          SURFACE->kv[0], u, v))
        return true;
      if(try_a_value
         (SURFACE, VERTEX, SURFACE->ku[SURFACE->Nu + SURFACE->OrderU] - VERTEX->u,
          SURFACE->kv[SURFACE->Nv + SURFACE->OrderV], u, v))
        return true;
      if(try_a_value
         (SURFACE, VERTEX, SURFACE->ku[0], SURFACE->kv[0] + VERTEX->u, u, v))
        return true;
      if(try_a_value(SURFACE, VERTEX, SURFACE->ku[0],
                     SURFACE->kv[SURFACE->Nv + SURFACE->OrderV] - VERTEX->u, u,
                     v))
        return true;
      if(try_a_value(SURFACE, VERTEX, SURFACE->ku[SURFACE->Nu + SURFACE->OrderU],
                     SURFACE->kv[0] + VERTEX->u, u, v))
        return true;
      if(try_a_value(SURFACE, VERTEX, SURFACE->ku[SURFACE->Nu + SURFACE->OrderU],
                     SURFACE->kv[SURFACE->Nv + SURFACE->OrderV] - VERTEX->u, u,
                     v))
        return true;
    
    
      if(search_in_boundary(SURFACE, VERTEX, SURFACE->kv[0], 0, u, v))
        return true;
      if(search_in_boundary
         (SURFACE, VERTEX, SURFACE->kv[SURFACE->Nv + SURFACE->OrderV], 0, u, v))
        return true;
      if(search_in_boundary(SURFACE, VERTEX, SURFACE->ku[0], 1, u, v))
        return true;
      if(search_in_boundary
         (SURFACE, VERTEX, SURFACE->ku[SURFACE->Nu + SURFACE->OrderU], 1, u, v))
        return true;
    
      while(1) {
        newt(x, 2, &check, projectPS);
        vv = InterpolateSurface(s, x[1], x[2], 0, 0);
        l = sqrt(DSQR(vv.Pos.X - p->Pos.X) +
                 DSQR(vv.Pos.Y - p->Pos.Y) + DSQR(vv.Pos.Z - p->Pos.Z));
        if(l < 1.e-1)
          break;
        else {
          x[1] = UMIN + (UMAX - UMIN) * ((rand() % 10000) / 10000.);
          x[2] = VMIN + (VMAX - VMIN) * ((rand() % 10000) / 10000.);
        }
      }
      *u = x[1];
      *v = x[2];
    
      if(!check) {
        return false;
      }
      return true;
    }
    
    bool IntersectCurveSurface(Curve * c, Surface * s)
    {
      double x[4];
      int check;
      SURFACE = s;
      CURVE = c;
      newt(x, 3, &check, intersectCS);
      if(!check)
        return false;
      return true;
    }
    
    
    void DivideCurve(Curve * c, double u, Vertex * v, Curve ** c1, Curve ** c2)
    {
      (*c1) = Create_Curve(NEWLINE(), c->Typ, 1, NULL, NULL, -1, -1, 0., 1.);
      (*c2) = Create_Curve(NEWLINE(), c->Typ, 1, NULL, NULL, -1, -1, 0., 1.);
      CopyCurve(c, *c1);
      CopyCurve(c, *c2);
      (*c1)->uend = u;
      (*c2)->ubeg = u;
      (*c1)->end = v;
      (*c2)->beg = v;
    }
    
    bool IntersectCurves(Curve * c1, Curve * c2,
                         Curve ** c11, Curve ** c12,
                         Curve ** c21, Curve ** c22, Vertex ** v)
    {
      double x[3];
      Vertex v1, v2;
      int check;
    
      if(!compareVertex(&c1->beg, &c2->beg))
        return false;
      if(!compareVertex(&c1->end, &c2->end))
        return false;
      if(!compareVertex(&c1->beg, &c2->end))
        return false;
      if(!compareVertex(&c2->beg, &c1->end))
        return false;
    
      CURVE_2 = c2;
      CURVE = c1;
      x[1] = x[2] = 0.0;
      newt(x, 2, &check, intersectCC);
      if(check)
        return false;
      v1 = InterpolateCurve(c1, x[1], 0);
      v2 = InterpolateCurve(c2, x[2], 0);
      //  Msg(INFO, "success : %lf %lf,%lf,%lf\n",v1.Pos.X,v1.Pos.Y,x[1],x[2]);
      if(x[1] <= c1->ubeg)
        return false;
      if(x[1] >= c1->uend)
        return false;
      if(x[2] <= c2->ubeg)
        return false;
      if(x[2] >= c2->uend)
        return false;
      if(fabs(v1.Pos.Z - v2.Pos.Z) > 1.e-08 * CTX.lc)
        return false;
      *v = Create_Vertex(NEWPOINT(), v1.Pos.X, v1.Pos.Y, v1.Pos.Z, v1.lc, x[1]);
      Tree_Insert(THEM->Points, v);
      DivideCurve(c1, x[1], *v, c11, c12);
      DivideCurve(c2, x[2], *v, c21, c22);
      return true;
    }
    
    bool IntersectAllSegmentsTogether(void)
    {
      bool intersectionfound = true;
      List_T *TempList;
      Curve *c1, *c2, *c11, *c12, *c21, *c22;
      Vertex *v;
      int i, j;
    
      while(intersectionfound) {
        TempList = Tree2List(THEM->Curves);
        if(!List_Nbr(TempList))
          return true;
        for(i = 0; i < List_Nbr(TempList); i++) {
          List_Read(TempList, i, &c1);
          intersectionfound = false;
          for(j = 0; j < List_Nbr(TempList); j++) {
            List_Read(TempList, j, &c2);
            if(c1->Num > 0 && c2->Num > 0 && i != j && intersectionfound == false) {
              if(IntersectCurves(c1, c2, &c11, &c12, &c21, &c22, &v)) {
                Msg(INFO, "Intersection Curve %d->%d", c1->Num, c2->Num);
                intersectionfound = true;
                DeleteCurve(c1->Num);
                DeleteCurve(c2->Num);
                Tree_Add(THEM->Curves, &c11);
                Tree_Add(THEM->Curves, &c12);
                Tree_Add(THEM->Curves, &c21);
                Tree_Add(THEM->Curves, &c22);
    
                CreateReversedCurve(THEM, c11);
                CreateReversedCurve(THEM, c12);
                CreateReversedCurve(THEM, c21);
                CreateReversedCurve(THEM, c22);
                return true;
              }
            }
          }
          if(intersectionfound)
            break;
        }
        List_Delete(TempList);
      }
      return false;
    
    }
    
    void IntersectSurfaces(Surface * s1, Surface * s2)
    {
      ;
    }