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

MElement.h

Blame
  • Forked from gmsh / gmsh
    Source project has a limited visibility.
    MElement.h 54.12 KiB
    #ifndef _MELEMENT_H_
    #define _MELEMENT_H_
    
    // Copyright (C) 1997-2007 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 <stdio.h>
    #include <algorithm>
    #include <string>
    #include "GmshDefines.h"
    #include "MVertex.h"
    #include "MEdge.h"
    #include "MFace.h"
    
    class GFace;
    
    // A mesh element.
    class MElement 
    {
     private:
      static int _globalNum;
      int _num;
      short _partition;
      char _visible;
     protected:
      void _getEdgeRep(MVertex *v0, MVertex *v1, 
    		   double *x, double *y, double *z, SVector3 *n,
    		   int faceIndex=-1);
      void _getFaceRep(MVertex *v0, MVertex *v1, MVertex *v2, 
    		   double *x, double *y, double *z, SVector3 *n);
     public :
      MElement(int num=0, int part=0) 
        : _visible(true) 
      {
        if(num){
          _num = num;
          _globalNum = std::max(_globalNum, _num);
        }
        else{
          _num = ++_globalNum;
        }
        _partition = (short)part; 
      }
      virtual ~MElement(){}
    
      // reset the global node number
      static void resetGlobalNumber(){ _globalNum = 0; }
    
      // returns the tag of the element
      virtual int getNum(){ return _num; }
    
      // returns the geometrical dimension of the element
      virtual int getDim() = 0;
    
      // returns the polynomial order the element
      virtual int getPolynomialOrder(){ return 1; }
    
      // get/set the partition to which the element belongs
      virtual int getPartition(){ return _partition; }
      virtual void setPartition(int num){ _partition = (short)num; }
    
      // get/set the visibility flag
      virtual char getVisibility();
      virtual void setVisibility(char val){ _visible = val; }
    
      // get the vertices
      virtual int getNumVertices() = 0;
      virtual MVertex *getVertex(int num) = 0;
    
      // get the vertex using the I-deas UNV ordering
      virtual MVertex *getVertexUNV(int num){ return getVertex(num); }
    
      // get the vertex using the Nastran BDF ordering
      virtual MVertex *getVertexBDF(int num){ return getVertex(num); }
    
      // get the number of vertices associated with edges, faces and
      // volumes (nonzero only for higher order elements)
      virtual int getNumEdgeVertices(){ return 0; }
      virtual int getNumFaceVertices(){ return 0; }
      virtual int getNumVolumeVertices(){ return 0; }
    
      // get the number of primary vertices (first-order element)
      int getNumPrimaryVertices()
      {
        return getNumVertices() - getNumEdgeVertices() - 
          getNumFaceVertices() - getNumVolumeVertices();
      }
    
      // get the edges
      virtual int getNumEdges() = 0;
      virtual MEdge getEdge(int num) = 0;
    
      // get an edge representation for drawing
      virtual int getNumEdgesRep() = 0;
      virtual void getEdgeRep(int num, double *x, double *y, double *z, SVector3 *n) = 0;
    
      // get the faces
      virtual int getNumFaces() = 0;
      virtual MFace getFace(int num) = 0;
    
      // get a face representation for drawing
      virtual int getNumFacesRep() = 0;
      virtual void getFaceRep(int num, double *x, double *y, double *z, SVector3 *n) = 0;
    
      // get the max/min edge length
      virtual double maxEdge();
      virtual double minEdge();
    
      // get the quality measures
      virtual double rhoShapeMeasure();
      virtual double gammaShapeMeasure(){ return 0.; }
      virtual double etaShapeMeasure(){ return 0.; }
    
      // computes the barycenter
      virtual SPoint3 barycenter();
    
      // revert the orientation of the element
      virtual void revert() = 0;
    
      // compute and change the orientation of 3D elements to get
      // positive volume
      virtual double getVolume(){ return 0.; }
      virtual int getVolumeSign(){ return 1; }
      virtual void setVolumePositive(){ if(getVolumeSign() < 0) revert(); }
    
      // Returns an information string for the element
      virtual std::string getInfoString();
    
      // IO routines
      virtual void writeMSH(FILE *fp, double version=1.0, bool binary=false, 
    			int num=0, int elementary=1, int physical=1);
      virtual void writePOS(FILE *fp, bool printElementary, bool printElementNumber, 
    			bool printGamma, bool printEta, bool printRho, 
    			double scalingFactor=1.0, int elementary=1);
      virtual void writeSTL(FILE *fp, bool binary=false, double scalingFactor=1.0);
      virtual void writeVRML(FILE *fp);
      virtual void writeUNV(FILE *fp, int num=0, int elementary=1, int physical=1);
      virtual void writeMESH(FILE *fp, int elementary=1);
      virtual void writeBDF(FILE *fp, int format=0, int elementary=1);
    
      // info for specific IO formats
      virtual int getTypeForMSH() = 0;
      virtual int getTypeForUNV() = 0;
      virtual const char *getStringForPOS() = 0;
      virtual const char *getStringForBDF() = 0;
    };
    
    class MElementLessThanLexicographic{
     public:
      static double tolerance;
      bool operator()(MElement *e1, MElement *e2) const
      {
        SPoint3 b1 = e1->barycenter();
        SPoint3 b2 = e2->barycenter();
        if(b1.x() - b2.x() >  tolerance) return true;
        if(b1.x() - b2.x() < -tolerance) return false;
        if(b1.y() - b2.y() >  tolerance) return true;
        if(b1.y() - b2.y() < -tolerance) return false;
        if(b1.z() - b2.z() >  tolerance) return true;
        return false;
      }
    };
    
    class MLine : public MElement {
     protected:
      MVertex *_v[2];
     public :
      MLine(MVertex *v0, MVertex *v1, int num=0, int part=0) 
        : MElement(num, part)
      {
        _v[0] = v0; _v[1] = v1;
      }
      MLine(std::vector<MVertex*> &v, int num=0, int part=0) 
        : MElement(num, part)
      {
        for(int i = 0; i < 2; i++) _v[i] = v[i];
      }
      ~MLine(){}
      virtual int getDim(){ return 1; }
      virtual int getNumVertices(){ return 2; }
      virtual MVertex *getVertex(int num){ return _v[num]; }
      virtual int getNumEdges(){ return 1; }
      virtual MEdge getEdge(int num){ return MEdge(_v[0], _v[1]); }
      virtual int getNumEdgesRep(){ return 1; }
      virtual void getEdgeRep(int num, double *x, double *y, double *z, SVector3 *n)
      { 
        _getEdgeRep(_v[0], _v[1], x, y, z, n);
      }
      virtual int getNumFaces(){ return 0; }
      virtual MFace getFace(int num){ throw; }
      virtual int getNumFacesRep(){ return 0; }
      virtual void getFaceRep(int num, double *x, double *y, double *z, SVector3 *n)
      { 
        throw; 
      }
      virtual int getTypeForMSH(){ return MSH_LIN_2; }
      virtual int getTypeForUNV(){ return 21; } // linear beam
      virtual const char *getStringForPOS(){ return "SL"; }
      virtual const char *getStringForBDF(){ return "CBAR"; }
      virtual void revert() 
      {
        MVertex *tmp = _v[0]; _v[0] = _v[1]; _v[1] = tmp;
      }
    };
    
    class MLine3 : public MLine {
     protected:
      MVertex *_vs[1];
     public :
      MLine3(MVertex *v0, MVertex *v1, MVertex *v2, int num=0, int part=0) 
        : MLine(v0, v1, num, part)
      {
        _vs[0] = v2;
        _vs[0]->setPolynomialOrder(2);
      }
      MLine3(std::vector<MVertex*> &v, int num=0, int part=0) 
        : MLine(v, num, part)
      {
        _vs[0] = v[2];
        _vs[0]->setPolynomialOrder(2);
      }
      ~MLine3(){}
      virtual int getPolynomialOrder(){ return 2; }
      virtual int getNumVertices(){ return 3; }
      virtual MVertex *getVertex(int num){ return num < 2 ? _v[num] : _vs[num - 2]; }
      virtual MVertex *getVertexUNV(int num)
      {
        static const int map[3] = {0, 2, 1};
        return getVertex(map[num]); 
      }
      virtual int getNumEdgeVertices(){ return 1; }
      virtual int getNumEdgesRep(){ return 2; }
      virtual void getEdgeRep(int num, double *x, double *y, double *z, SVector3 *n)
      { 
        static const int e[2][2] = {
          {0, 2}, {2, 1}
        };
        _getEdgeRep(getVertex(e[num][0]), getVertex(e[num][1]), x, y, z, n);
      }
      virtual int getTypeForMSH(){ return MSH_LIN_3; }
      virtual int getTypeForUNV(){ return 24; } // parabolic beam
      virtual const char *getStringForPOS(){ return "SL2"; }
      virtual const char *getStringForBDF(){ return 0; } // not available
    };
    
    class MLineN : public MLine {
     protected:
      std::vector<MVertex *> _vs;
     public :
      MLineN(MVertex *v0, MVertex *v1, const std::vector<MVertex*> &vs, int num=0, int part=0) 
        : MLine(v0, v1, num, part), _vs(vs)
      {
        for(unsigned int i = 0; i < _vs.size(); i++)
          _vs[i]->setPolynomialOrder(_vs.size() + 1);
      }
      MLineN(const std::vector<MVertex*> &v, int num=0, int part=0) 
        : MLine(v[0] , v[1], num, part)
      {
        for(unsigned int i = 2; i < v.size(); i++)
          _vs.push_back(v[i]);
        for(unsigned int i = 0 ; i < _vs.size(); i++)
          _vs[i]->setPolynomialOrder(_vs.size() + 1);
      }
      ~MLineN(){}
      virtual int getPolynomialOrder(){ return _vs.size() + 1; }
      virtual int getNumVertices(){ return _vs.size() + 2; }
      virtual MVertex *getVertex(int num){ return num < 2 ? _v[num] : _vs[num - 2]; }
      virtual int getNumEdgeVertices(){ return _vs.size(); }
      virtual int getNumEdgesRep(){ return _vs.size() + 1; }
      virtual void getEdgeRep(int num, double *x, double *y, double *z, SVector3 *n)
      { 
        _getEdgeRep(getVertex((num == 0) ? 0 : num + 1), 
    		getVertex((num == getNumEdgesRep() - 1) ? 1 : num + 2),
    		x, y, z, n);
      }
      virtual int getTypeForMSH(){ 
        if(_vs.size() == 2) return MSH_LIN_4; 
        if(_vs.size() == 3) return MSH_LIN_5; 
        if(_vs.size() == 4) return MSH_LIN_6; 
        throw;
      }
      virtual int getTypeForUNV(){ return 0; } // not available
      virtual const char *getStringForPOS(){ return 0; } // not available
      virtual const char *getStringForBDF(){ return 0; } // not available
    };
    
    class MTriangle : public MElement {
     protected:
      MVertex *_v[3];
     public :
      virtual void jac(int order, MVertex *verts[], double u, double v, double jac[2][3]);
      virtual void pnt(int order, MVertex *verts[], double u, double v, SPoint3 &);
      MTriangle(MVertex *v0, MVertex *v1, MVertex *v2, int num=0, int part=0) 
        : MElement(num, part)
      {
        _v[0] = v0; _v[1] = v1; _v[2] = v2;
      }
      MTriangle(std::vector<MVertex*> &v, int num=0, int part=0) 
        : MElement(num, part)
      {
        for(int i = 0; i < 3; i++) _v[i] = v[i];
      }
      ~MTriangle(){}
      virtual int getDim(){ return 2; }
      virtual void getMat(double mat[2][2])
      {
        mat[0][0] = _v[1]->x() - _v[0]->x();
        mat[0][1] = _v[2]->x() - _v[0]->x();
        mat[1][0] = _v[1]->y() - _v[0]->y();
        mat[1][1] = _v[2]->y() - _v[0]->y();
      }
      void circumcenterXY(double *res) const; 
      virtual double gammaShapeMeasure();
      void circumcenterUV(GFace*,double *res); 
      static void circumcenterXYZ(double *p1, double *p2, double *p3, double *res,
    			      double *uv = 0);
      static void circumcenterXY(double *p1, double *p2, double *p3, double *res);
      double getSurfaceXY() const;
      double getSurfaceUV(GFace*);
      bool invertmappingXY(double *p, double *uv, double tol = 1.e-8);
      bool invertmappingUV(GFace*,double *p, double *uv, double tol = 1.e-8);
      virtual int getNumVertices(){ return 3; }
      virtual MVertex *getVertex(int num){ return _v[num]; }
      virtual MVertex *getOtherVertex(MVertex *v1, MVertex *v2)
      { 
        if(_v[0] != v1 && _v[0] != v2) return _v[0];
        if(_v[1] != v1 && _v[1] != v2) return _v[1];
        if(_v[2] != v1 && _v[2] != v2) return _v[2];
        throw;
      }
      virtual int getNumEdges(){ return 3; }
      virtual MEdge getEdge(int num)
      {
        static const int edges_tri[3][2] = {
          {0, 1},
          {1, 2},
          {2, 0}
        };
        return MEdge(_v[edges_tri[num][0]], _v[edges_tri[num][1]]);
      }
      virtual int getNumEdgesRep(){ return 3; }
      virtual void getEdgeRep(int num, double *x, double *y, double *z, SVector3 *n)
      { 
        MEdge e(getEdge(num));
        _getEdgeRep(e.getVertex(0), e.getVertex(1), x, y, z, n, 0);
      }
      virtual int getNumFaces(){ return 1; }
      virtual MFace getFace(int num)
      { 
        return MFace(_v[0], _v[1], _v[2]); 
      }
      virtual int getNumFacesRep(){ return 1; }
      virtual void getFaceRep(int num, double *x, double *y, double *z, SVector3 *n)
      { 
        _getFaceRep(_v[0], _v[1], _v[2], x, y, z, n);
      }
      virtual int getTypeForMSH(){ return MSH_TRI_3; }
      virtual int getTypeForUNV(){ return 91; } // thin shell linear triangle
      virtual const char *getStringForPOS(){ return "ST"; }
      virtual const char *getStringForBDF(){ return "CTRIA3"; }
      virtual void revert() 
      {
        MVertex *tmp = _v[1]; _v[1] = _v[2]; _v[2] = tmp;
      }
      virtual void jac(double u, double v, double j[2][3]);
      virtual void pnt(double u, double v, SPoint3&);
    };
    
    class MTriangle6 : public MTriangle {
     protected:
      MVertex *_vs[3];
     public :
      MTriangle6(MVertex *v0, MVertex *v1, MVertex *v2, MVertex *v3, MVertex *v4,
    	     MVertex *v5, int num=0, int part=0) 
        : MTriangle(v0, v1, v2, num, part)
      {
        _vs[0] = v3; _vs[1] = v4; _vs[2] = v5;
        for(int i = 0; i < 3; i++) _vs[i]->setPolynomialOrder(2);
      }
      MTriangle6(std::vector<MVertex*> &v, int num=0, int part=0) 
        : MTriangle(v, num, part)
      {
        for(int i = 0; i < 3; i++) _vs[i] = v[3 + i];
        for(int i = 0; i < 3; i++) _vs[i]->setPolynomialOrder(2);
      }
      ~MTriangle6(){}
      virtual int getPolynomialOrder(){ return 2; }
      virtual int getNumVertices(){ return 6; }
      virtual MVertex *getVertex(int num){ return num < 3 ? _v[num] : _vs[num - 3]; }
      virtual MVertex *getVertexUNV(int num)
      {
        static const int map[6] = {0, 3, 1, 4, 2, 5};
        return getVertex(map[num]); 
      }
      virtual int getNumEdgeVertices(){ return 3; }
      virtual int getNumEdgesRep();
      virtual void getEdgeRep(int num, double *x, double *y, double *z, SVector3 *n);
    /*   {  */
    /*     static const int e[6][2] = { */
    /*       {0, 3}, {3, 1}, */
    /*       {1, 4}, {4, 2}, */
    /*       {2, 5}, {5, 0} */
    /*     }; */
    /*     _getEdgeRep(getVertex(e[num][0]), getVertex(e[num][1]), x, y, z, n, 0); */
    /*   } */
      virtual int getNumFacesRep(){ return 4; }
      virtual void getFaceRep(int num, double *x, double *y, double *z, SVector3 *n)
      { 
        static const int f[4][3] = {
          {0, 3, 5}, {1, 4, 3}, {2, 5, 4}, {3, 4, 5}
        };
        _getFaceRep(getVertex(f[num][0]), getVertex(f[num][1]), getVertex(f[num][2]),
    		x, y, z, n);
      }
      virtual int getTypeForMSH(){ return MSH_TRI_6; }
      virtual int getTypeForUNV(){ return 92; } // thin shell parabolic triangle
      virtual const char *getStringForPOS(){ return "ST2"; }
      virtual const char *getStringForBDF(){ return "CTRIA6"; }
      virtual void revert() 
      {
        MVertex *tmp;
        tmp = _v[1]; _v[1] = _v[2]; _v[2] = tmp;
        tmp = _vs[0]; _vs[0] = _vs[2]; _vs[2] = tmp;
      }
      virtual void jac ( double u, double v , double j[2][3]) ;
      virtual void pnt(double u, double v, SPoint3&);
    };
    
    class MTriangleN : public MTriangle {
     protected:
      std::vector<MVertex *> _vs;
      const short _order;
      int _orderedIndex(int num)
      {
        if(num == 0) return 0;
        else if(num < _order) return num + 2;
        else if(num == _order) return 1;
        else if(num < 2 * _order) return num + 1;
        else if(num == 2 * _order) return 2;
        else return num;
      }
     public:
      MTriangleN(MVertex *v0, MVertex *v1, MVertex *v2, 
    	     std::vector<MVertex*> &v, int order, int num=0, int part=0) 
        : MTriangle(v0, v1, v2, num, part) , _vs (v), _order(order)
      {
        for(unsigned int i = 0; i < _vs.size(); i++) _vs[i]->setPolynomialOrder(_order);
      }
      MTriangleN(std::vector<MVertex*> &v, int order, int num=0, int part=0) 
        : MTriangle(v[0], v[1], v[2], num, part) , _order(order)
      {
        for(unsigned int i = 3; i < v.size(); i++) _vs.push_back(v[i]);
        for(unsigned int i = 0; i < _vs.size(); i++) _vs[i]->setPolynomialOrder(_order);
      }
      ~MTriangleN(){}
      virtual int getPolynomialOrder(){ return _order; }
      virtual int getNumVertices(){ return 3 + _vs.size() ; }
      virtual MVertex *getVertex(int num){ return num < 3 ? _v[num] : _vs[num - 3]; }
      virtual int getNumFaceVertices()
      {
        if(_order == 3 && _vs.size() == 6) return 0;
        if(_order == 3 && _vs.size() == 7) return 1;
        if(_order == 4 && _vs.size() == 9) return 0;
        if(_order == 4 && _vs.size() == 12) return 3;
        if(_order == 5 && _vs.size() == 12) return 0;
        if(_order == 5 && _vs.size() == 18) return 6;
        throw;
      }
      virtual int getNumEdgeVertices(){ return _order - 1; }
      virtual int getNumEdgesRep();
      virtual void getEdgeRep(int num, double *x, double *y, double *z, SVector3 *n);
      virtual int getNumFacesRep(){ return 0; }
      virtual void getFaceRep(int num, double *x, double *y, double *z, SVector3 *n)
      { 
        throw;
      }
      virtual int getTypeForMSH()
      {
        if(_order == 3 && _vs.size() == 6) return MSH_TRI_9; 
        if(_order == 3 && _vs.size() == 7) return MSH_TRI_10; 
        if(_order == 4 && _vs.size() == 9) return MSH_TRI_12; 
        if(_order == 4 && _vs.size() == 12) return MSH_TRI_15; 
        if(_order == 5 && _vs.size() == 12) return MSH_TRI_15I; 
        if(_order == 5 && _vs.size() == 18) return MSH_TRI_21;
        throw;
      }
      virtual int getTypeForUNV(){ return 0; } // not available
      virtual const char *getStringForPOS(){ return 0; }
      virtual const char *getStringForBDF(){ return 0; }
      virtual void revert() 
      {
        MVertex *tmp;
        tmp = _v[1]; _v[1] = _v[2]; _v[2] = tmp;
        std::vector<MVertex*> inv;
        inv.insert(inv.begin(), _vs.rbegin(), _vs.rend());
        _vs = inv;
      }
      virtual void jac(double u, double v, double jac[2][3]);
      virtual void pnt(double u, double v, SPoint3&);
    };
    
    class MQuadrangle : public MElement {
     protected:
      MVertex *_v[4];
     public :
      MQuadrangle(MVertex *v0, MVertex *v1, MVertex *v2, MVertex *v3, int num=0, int part=0) 
        : MElement(num, part)
      {
        _v[0] = v0; _v[1] = v1; _v[2] = v2; _v[3] = v3;
      }
      MQuadrangle(std::vector<MVertex*> &v, int num=0, int part=0) 
        : MElement(num, part)
      {
        for(int i = 0; i < 4; i++) _v[i] = v[i];
      }
      ~MQuadrangle(){}
      virtual int getDim(){ return 2; }
      virtual int getNumVertices(){ return 4; }
      virtual MVertex *getVertex(int num){ return _v[num]; }
      virtual int getNumEdges(){ return 4; }
      virtual MEdge getEdge(int num)
      {
        static const int edges_quad[4][2] = {
          {0, 1},
          {1, 2},
          {2, 3},
          {3, 0}
        };
        return MEdge(_v[edges_quad[num][0]], _v[edges_quad[num][1]]);
      }
      virtual int getNumEdgesRep(){ return 4; }
      virtual void getEdgeRep(int num, double *x, double *y, double *z, SVector3 *n)
      { 
        MEdge e(getEdge(num));
        _getEdgeRep(e.getVertex(0), e.getVertex(1), x, y, z, n, 0);
      }
      virtual int getNumFaces(){ return 1; }
      virtual MFace getFace(int num){ return MFace(_v[0], _v[1], _v[2], _v[3]); }
      virtual int getNumFacesRep(){ return 2; }
      virtual void getFaceRep(int num, double *x, double *y, double *z, SVector3 *n)
      { 
        static const int f[2][3] = {
          {0, 1, 2}, {0, 2, 3}
        };
        _getFaceRep(getVertex(f[num][0]), getVertex(f[num][1]), getVertex(f[num][2]),
    		x, y, z, n);
      }
      virtual int getTypeForMSH(){ return MSH_QUA_4; }
      virtual int getTypeForUNV(){ return 94; } // thin shell linear quadrilateral
      virtual const char *getStringForPOS(){ return "SQ"; }
      virtual const char *getStringForBDF(){ return "CQUAD4"; }
      virtual void revert() 
      {
        MVertex *tmp = _v[1]; _v[1] = _v[3]; _v[3] = tmp;
      }
    };
    
    class MQuadrangle8 : public MQuadrangle {
     protected:
      MVertex *_vs[4];
     public :
      MQuadrangle8(MVertex *v0, MVertex *v1, MVertex *v2, MVertex *v3, MVertex *v4, 
    	       MVertex *v5, MVertex *v6, MVertex *v7, int num=0, int part=0) 
        : MQuadrangle(v0, v1, v2, v3, num, part)
      {
        _vs[0] = v4; _vs[1] = v5; _vs[2] = v6; _vs[3] = v7;
        for(int i = 0; i < 4; i++) _vs[i]->setPolynomialOrder(2);
      }
      MQuadrangle8(std::vector<MVertex*> &v, int num=0, int part=0) 
        : MQuadrangle(v, num, part)
      {
        for(int i = 0; i < 4; i++) _vs[i] = v[4 + i];
        for(int i = 0; i < 4; i++) _vs[i]->setPolynomialOrder(2);
      }
      ~MQuadrangle8(){}
      virtual int getPolynomialOrder(){ return 2; }
      virtual int getNumVertices(){ return 8; }
      virtual MVertex *getVertex(int num){ return num < 4 ? _v[num] : _vs[num - 4]; }
      virtual MVertex *getVertexUNV(int num)
      {
        static const int map[8] = {0, 4, 1, 5, 2, 6, 3, 7};
        return getVertex(map[num]); 
      }
      virtual int getNumEdgeVertices(){ return 4; }
      virtual int getNumEdgesRep(){ return 8; }
      virtual void getEdgeRep(int num, double *x, double *y, double *z, SVector3 *n)
      { 
        static const int e[8][2] = {
          {0, 4}, {4, 1},
          {1, 5}, {5, 2},
          {2, 6}, {6, 3},
          {3, 7}, {7, 0}
        };
        _getEdgeRep(getVertex(e[num][0]), getVertex(e[num][1]), x, y, z, n, 0);
      }
      virtual int getNumFacesRep(){ return 6; }
      virtual void getFaceRep(int num, double *x, double *y, double *z, SVector3 *n)
      { 
        static const int f[6][3] = {
          {0, 4, 7}, {1, 5, 4}, {2, 6, 5}, {3, 7, 6}, {4, 5, 6}, {4, 6, 7}
        };
        _getFaceRep(getVertex(f[num][0]), getVertex(f[num][1]), getVertex(f[num][2]),
    		x, y, z, n);
      }
      virtual int getTypeForMSH(){ return MSH_QUA_8; }
      virtual int getTypeForUNV(){ return 95; } // shell parabolic quadrilateral
      virtual const char *getStringForPOS(){ return 0; } // not available
      virtual const char *getStringForBDF(){ return "CQUAD8"; }
      virtual void revert() 
      {
        MVertex *tmp;
        tmp = _v[1]; _v[1] = _v[3]; _v[3] = tmp;
        tmp = _vs[0]; _vs[0] = _vs[3]; _vs[3] = tmp;
        tmp = _vs[1]; _vs[1] = _vs[2]; _vs[2] = tmp;
      }
    };
    
    class MQuadrangle9 : public MQuadrangle {
     protected:
      MVertex *_vs[5];
     public :
      MQuadrangle9(MVertex *v0, MVertex *v1, MVertex *v2, MVertex *v3, MVertex *v4, 
    	       MVertex *v5, MVertex *v6, MVertex *v7, MVertex *v8, int num=0, int part=0) 
        : MQuadrangle(v0, v1, v2, v3, num, part)
      {
        _vs[0] = v4; _vs[1] = v5; _vs[2] = v6; _vs[3] = v7; _vs[4] = v8;
        for(int i = 0; i < 5; i++) _vs[i]->setPolynomialOrder(2);
      }
      MQuadrangle9(std::vector<MVertex*> &v, int num=0, int part=0) 
        : MQuadrangle(v, num, part)
      {
        for(int i = 0; i < 5; i++) _vs[i] = v[4 + i];
        for(int i = 0; i < 5; i++) _vs[i]->setPolynomialOrder(2);
      }
      ~MQuadrangle9(){}
      virtual int getPolynomialOrder(){ return 2; }
      virtual int getNumVertices(){ return 9; }
      virtual MVertex *getVertex(int num){ return num < 4 ? _v[num] : _vs[num - 4]; }
      virtual int getNumEdgeVertices(){ return 4; }
      virtual int getNumFaceVertices(){ return 1; }
      virtual int getNumEdgesRep(){ return 8; }
      virtual void getEdgeRep(int num, double *x, double *y, double *z, SVector3 *n)
      { 
        static const int e[8][2] = {
          {0, 4}, {4, 1},
          {1, 5}, {5, 2},
          {2, 6}, {6, 3},
          {3, 7}, {7, 0}
        };
        _getEdgeRep(getVertex(e[num][0]), getVertex(e[num][1]), x, y, z, n, 0);
      }
      virtual int getNumFacesRep(){ return 8; }
      virtual void getFaceRep(int num, double *x, double *y, double *z, SVector3 *n)
      { 
        static const int f[8][4] = {
          {0, 4, 8}, {0, 8, 7}, {1, 5, 8}, {1, 8, 4}, 
          {2, 6, 8}, {2, 8, 5}, {3, 7, 8}, {3, 8, 6}
        };
        _getFaceRep(getVertex(f[num][0]), getVertex(f[num][1]), getVertex(f[num][2]),
    		x, y, z, n);
      }
      virtual int getTypeForMSH(){ return MSH_QUA_9; }
      virtual int getTypeForUNV(){ return 0; } // not available
      virtual const char *getStringForPOS(){ return "SQ2"; }
      virtual const char *getStringForBDF(){ return 0; } // not available
      virtual void revert() 
      {
        MVertex *tmp;
        tmp = _v[1]; _v[1] = _v[3]; _v[3] = tmp;
        tmp = _vs[0]; _vs[0] = _vs[3]; _vs[3] = tmp;
        tmp = _vs[1]; _vs[1] = _vs[2]; _vs[2] = tmp;
      }
    };
    
    class MTetrahedron : public MElement {
     protected:
      MVertex *_v[4];
     public :
      MTetrahedron(MVertex *v0, MVertex *v1, MVertex *v2, MVertex *v3, int num=0, int part=0) 
        : MElement(num, part)
      {
        _v[0] = v0; _v[1] = v1; _v[2] = v2; _v[3] = v3;
      }
      MTetrahedron(std::vector<MVertex*> &v, int num=0, int part=0) 
        : MElement(num, part)
      {
        for(int i = 0; i < 4; i++) _v[i] = v[i];
      }
      ~MTetrahedron(){}
      virtual int getDim(){ return 3; }
      virtual int getNumVertices(){ return 4; }
      virtual MVertex *getVertex(int num){ return _v[num]; }
      virtual int getNumEdges(){ return 6; }
      virtual MEdge getEdge(int num)
      {
        static const int edges_tetra[6][2] = {
          {0, 1},
          {1, 2},
          {2, 0},
          {3, 0},
          {3, 2},
          {3, 1}
        };
        return MEdge(_v[edges_tetra[num][0]], _v[edges_tetra[num][1]]);
      }
      virtual int getNumEdgesRep(){ return 6; }
      virtual void getEdgeRep(int num, double *x, double *y, double *z, SVector3 *n)
      {
        static const int f[6] = {0, 0, 0, 1, 2, 3};
        MEdge e(getEdge(num));
        _getEdgeRep(e.getVertex(0), e.getVertex(1), x, y, z, n, f[num]);
      }
      virtual int getNumFaces(){ return 4; }
      virtual MFace getFace(int num)
      {
        static const int faces_tetra[4][3] = {
          {0, 2, 1},
          {0, 1, 3},
          {0, 3, 2},
          {3, 1, 2}
        };
        return MFace(_v[faces_tetra[num][0]],
    		 _v[faces_tetra[num][1]],
    		 _v[faces_tetra[num][2]]);
      }
      virtual int getNumFacesRep(){ return 4; }
      virtual void getFaceRep(int num, double *x, double *y, double *z, SVector3 *n)
      { 
        MFace f(getFace(num));
        _getFaceRep(f.getVertex(0), f.getVertex(1), f.getVertex(2), x, y, z, n);
      }
      virtual int getTypeForMSH(){ return MSH_TET_4; }
      virtual int getTypeForUNV(){ return 111; } // solid linear tetrahedron
      virtual const char *getStringForPOS(){ return "SS"; }
      virtual const char *getStringForBDF(){ return "CTETRA"; }
      virtual void revert()
      {
        MVertex *tmp = _v[0]; _v[0] = _v[1]; _v[1] = tmp;
      }
      virtual void  getMat(double mat[3][3]);
      virtual double getVolume();
      virtual int getVolumeSign(){ return (getVolume() >= 0) ? 1 : -1; }
      virtual double gammaShapeMeasure();
      virtual double etaShapeMeasure();
      // returns true if the point lies inside the tet
      bool invertmapping(double *p, double *uvw, double tol = 1.e-8);
      static void circumcenter(double X[4],double Y[4],double Z[4],double *res);
      void circumcenter(double *res)
      {
        double X[4] = {_v[0]->x(), _v[1]->x(), _v[2]->x(), _v[3]->x()};
        double Y[4] = {_v[0]->y(), _v[1]->y(), _v[2]->y(), _v[3]->y()};
        double Z[4] = {_v[0]->z(), _v[1]->z(), _v[2]->z(), _v[3]->z()};
        MTetrahedron::circumcenter(X, Y, Z, res); 
      }
    };
    
    class MTetrahedron10 : public MTetrahedron {
     protected:
      MVertex *_vs[6];
     public :
      MTetrahedron10(MVertex *v0, MVertex *v1, MVertex *v2, MVertex *v3, MVertex *v4, 
    		 MVertex *v5, MVertex *v6, MVertex *v7, MVertex *v8, MVertex *v9,
    		 int num=0, int part=0) 
        : MTetrahedron(v0, v1, v2, v3, num, part)
      {
        _vs[0] = v4; _vs[1] = v5; _vs[2] = v6; _vs[3] = v7; _vs[4] = v8; _vs[5] = v9;
        for(int i = 0; i < 6; i++) _vs[i]->setPolynomialOrder(2);
      }
      MTetrahedron10(std::vector<MVertex*> &v, int num=0, int part=0) 
        : MTetrahedron(v, num, part)
      {
        for(int i = 0; i < 6; i++) _vs[i] = v[4 + i];
        for(int i = 0; i < 6; i++) _vs[i]->setPolynomialOrder(2);
      }
      ~MTetrahedron10(){}
      virtual int getPolynomialOrder(){ return 2; }
      virtual int getNumVertices(){ return 10; }
      virtual MVertex *getVertex(int num){ return num < 4 ? _v[num] : _vs[num - 4]; }
      virtual MVertex *getVertexUNV(int num)
      {
        static const int map[10] = {0, 4, 1, 5, 2, 6, 8, 9, 7, 3};
        return getVertex(map[num]); 
      }
      virtual MVertex *getVertexBDF(int num)
      {
        static const int map[10] = {0, 1, 2, 3, 4, 5, 6, 7, 9, 8};
        return getVertex(map[num]); 
      }
      virtual int getNumEdgeVertices(){ return 6; }
      virtual int getNumEdgesRep(){ return 12; }
      virtual void getEdgeRep(int num, double *x, double *y, double *z, SVector3 *n)
      { 
        static const int e[12][2] = {
          {0, 4}, {4, 1},
          {1, 5}, {5, 2},
          {2, 6}, {6, 0},
          {3, 7}, {7, 0},
          {3, 8}, {8, 2},
          {3, 9}, {9, 1}
        };
        static const int f[12] = {0, 0, 0, 1, 2, 3};
        _getEdgeRep(getVertex(e[num][0]), getVertex(e[num][1]), x, y, z, n, f[num / 2]);
      }
      virtual int getNumFacesRep(){ return 16; }
      virtual void getFaceRep(int num, double *x, double *y, double *z, SVector3 *n)
      { 
        static const int f[16][3] = {
          {0, 6, 4}, {2, 5, 6}, {1, 4, 5}, {6, 5, 4},
          {0, 4, 7}, {1, 9, 4}, {3, 7, 9}, {4, 9, 7},
          {0, 7, 6}, {3, 8, 7}, {2, 6, 8}, {7, 8, 6},
          {3, 9, 8}, {1, 5, 9}, {2, 8, 5}, {9, 5, 8}
        };
        _getFaceRep(getVertex(f[num][0]), getVertex(f[num][1]), getVertex(f[num][2]),
    		x, y, z, n);
      }
      virtual int getTypeForMSH(){ return MSH_TET_10; }
      virtual int getTypeForUNV(){ return 118; } // solid parabolic tetrahedron
      virtual const char *getStringForPOS(){ return "SS2"; }
      virtual const char *getStringForBDF(){ return "CTETRA"; }
      virtual void revert()
      {
        MVertex *tmp;
        tmp = _v[0]; _v[0] = _v[1]; _v[1] = tmp;
        tmp = _vs[1]; _vs[1] = _vs[2]; _vs[2] = tmp;
        tmp = _vs[5]; _vs[5] = _vs[3]; _vs[3] = tmp;
      }
    };
    
    class MHexahedron : public MElement {
     protected:
      MVertex *_v[8];
     public :
      MHexahedron(MVertex *v0, MVertex *v1, MVertex *v2, MVertex *v3, MVertex *v4, 
    	      MVertex *v5, MVertex *v6, MVertex *v7, int num=0, int part=0) 
        : MElement(num, part)
      {
        _v[0] = v0; _v[1] = v1; _v[2] = v2; _v[3] = v3;
        _v[4] = v4; _v[5] = v5; _v[6] = v6; _v[7] = v7;
      }
      MHexahedron(std::vector<MVertex*> &v, int num=0, int part=0) 
        : MElement(num, part)
      {
        for(int i = 0; i < 8; i++) _v[i] = v[i];
      }
      ~MHexahedron(){}
      virtual int getDim(){ return 3; }
      virtual int getNumVertices(){ return 8; }
      virtual MVertex *getVertex(int num){ return _v[num]; }
      virtual int getNumEdges(){ return 12; }
      virtual MEdge getEdge(int num)
      {
        static const int edges_hexa[12][2] = {
          {0, 1},
          {0, 3},
          {0, 4},
          {1, 2},
          {1, 5},
          {2, 3},
          {2, 6},
          {3, 7},
          {4, 5},
          {4, 7},
          {5, 6},
          {6, 7}
        };
        return MEdge(_v[edges_hexa[num][0]], _v[edges_hexa[num][1]]);
      }
      virtual int getNumEdgesRep(){ return 12; }
      virtual void getEdgeRep(int num, double *x, double *y, double *z, SVector3 *n)
      {
        static const int f[12] = {0, 0, 1, 0, 1, 0, 3, 2, 1, 2, 3, 4};
        MEdge e(getEdge(num));
        _getEdgeRep(e.getVertex(0), e.getVertex(1), x, y, z, n, f[num]);
      }
      virtual int getNumFaces(){ return 6; }
      virtual MFace getFace(int num)
      {
        static const int faces_hexa[6][4] = {
          {0, 3, 2, 1},
          {0, 1, 5, 4},
          {0, 4, 7, 3},
          {1, 2, 6, 5},
          {2, 3, 7, 6},
          {4, 5, 6, 7}
        };
        return MFace(_v[faces_hexa[num][0]],
    		 _v[faces_hexa[num][1]],
    		 _v[faces_hexa[num][2]],
    		 _v[faces_hexa[num][3]]);
      }
      virtual int getNumFacesRep(){ return 12; }
      virtual void getFaceRep(int num, double *x, double *y, double *z, SVector3 *n)
      { 
        static const int f[12][3] = {
          {0, 3, 2}, {0, 2, 1},
          {0, 1, 5}, {0, 5, 4},
          {0, 4, 7}, {0, 7, 3},
          {1, 2, 6}, {1, 6, 5},
          {2, 3, 7}, {2, 7, 6},
          {4, 5, 6}, {4, 6, 7}
        };
        _getFaceRep(getVertex(f[num][0]), getVertex(f[num][1]), getVertex(f[num][2]),
    		x, y, z, n);
      }
      virtual int getTypeForMSH(){ return MSH_HEX_8; }
      virtual int getTypeForUNV(){ return 115; } // solid linear brick
      virtual const char *getStringForPOS(){ return "SH"; }
      virtual const char *getStringForBDF(){ return "CHEXA"; }
      virtual void revert()
      {
        MVertex *tmp;
        tmp = _v[0]; _v[0] = _v[2]; _v[2] = tmp;
        tmp = _v[4]; _v[4] = _v[6]; _v[6] = tmp;
      }
      virtual int getVolumeSign();
    };
    
    class MHexahedron20 : public MHexahedron {
     protected:
      MVertex *_vs[12];
     public :
      MHexahedron20(MVertex *v0, MVertex *v1, MVertex *v2, MVertex *v3, MVertex *v4, 
    		MVertex *v5, MVertex *v6, MVertex *v7, MVertex *v8, MVertex *v9,
    		MVertex *v10, MVertex *v11, MVertex *v12, MVertex *v13, MVertex *v14,
    		MVertex *v15, MVertex *v16, MVertex *v17, MVertex *v18, MVertex *v19,
    		int num=0, int part=0) 
        : MHexahedron(v0, v1, v2, v3, v4, v5, v6, v7, num, part)
      {
        _vs[0] = v8; _vs[1] = v9; _vs[2] = v10; _vs[3] = v11; _vs[4] = v12; 
        _vs[5] = v13; _vs[6] = v14; _vs[7] = v15; _vs[8] = v16; _vs[9] = v17; 
        _vs[10] = v18; _vs[11] = v19; 
        for(int i = 0; i < 12; i++) _vs[i]->setPolynomialOrder(2);
      }
      MHexahedron20(std::vector<MVertex*> &v, int num=0, int part=0) 
        : MHexahedron(v, num, part)
      {
        for(int i = 0; i < 12; i++) _vs[i] = v[8 + i];
        for(int i = 0; i < 12; i++) _vs[i]->setPolynomialOrder(2);
      }
      ~MHexahedron20(){}
      virtual int getPolynomialOrder(){ return 2; }
      virtual int getNumVertices(){ return 20; }
      virtual MVertex *getVertex(int num){ return num < 8 ? _v[num] : _vs[num - 8]; }
      virtual MVertex *getVertexUNV(int num)
      {
        static const int map[20] = {0, 8, 1, 11, 2, 13, 3, 9, 10, 12, 
    				14, 15, 4, 16, 5, 18, 6, 19, 7, 17};
        return getVertex(map[num]); 
      }
      virtual MVertex *getVertexBDF(int num)
      {
        static const int map[20] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 11, 13, 
    				9, 10, 12, 14, 15, 16, 18, 19, 17};
        return getVertex(map[num]); 
      }
      virtual int getNumEdgeVertices(){ return 12; }
      virtual int getNumEdgesRep(){ return 24; }
      virtual void getEdgeRep(int num, double *x, double *y, double *z, SVector3 *n)
      { 
        static const int e[24][2] = {
          {0, 8}, {8, 1},
          {0, 9}, {9, 3},
          {0, 10}, {10, 4},
          {1, 11}, {11, 2},
          {1, 12}, {12, 5},
          {2, 13}, {13, 3},
          {2, 14}, {14, 6},
          {3, 15}, {15, 7},
          {4, 16}, {16, 5},
          {4, 17}, {17, 7},
          {5, 18}, {18, 6},
          {6, 19}, {19, 7}
        };
        static const int f[12] = {0, 0, 1, 0, 1, 0, 3, 2, 1, 2, 3, 4};
        _getEdgeRep(getVertex(e[num][0]), getVertex(e[num][1]), x, y, z, n, f[num / 2]);
      }
      virtual int getNumFacesRep(){ return 36; }
      virtual void getFaceRep(int num, double *x, double *y, double *z, SVector3 *n)
      { 
        static const int f[36][3] = {
          {0, 9, 8}, {3, 13, 9}, {2, 11, 13}, {1, 8, 11}, {8, 9, 13}, {8, 13, 11},
          {0, 8, 10}, {1, 12, 8}, {5, 16, 12}, {4, 10, 16}, {8, 12, 16}, {8, 16, 10},
          {0, 10, 9}, {4, 17, 10}, {7, 15, 17}, {3, 9, 7}, {9, 10, 17}, {9, 17, 15},
          {1, 11, 12}, {2, 14, 11}, {6, 18, 14}, {5, 12, 18}, {11, 14, 18}, {11, 18, 12},
          {2, 13, 14}, {3, 15, 13}, {7, 19, 15}, {6, 14, 19}, {13, 15, 19}, {13, 19, 14},
          {4, 16, 17}, {5, 18, 16}, {6, 19, 18}, {7, 17, 19}, {16, 18, 19}, {16, 19, 17}
        };
        _getFaceRep(getVertex(f[num][0]), getVertex(f[num][1]), getVertex(f[num][2]),
    		x, y, z, n);
      }
      virtual int getTypeForMSH(){ return MSH_HEX_20; }
      virtual int getTypeForUNV(){ return 116; } // solid parabolic brick
      virtual const char *getStringForPOS(){ return 0; } // not available
      virtual const char *getStringForBDF(){ return "CHEXA"; }
      virtual void revert()
      {
        MVertex *tmp;
        tmp = _v[0]; _v[0] = _v[2]; _v[2] = tmp;
        tmp = _v[4]; _v[4] = _v[6]; _v[6] = tmp;
        MVertex *old[12];
        for(int i = 0; i < 12; i++) old[i] = _vs[i];
        _vs[0] = old[3]; _vs[1] = old[5]; _vs[2] = old[6];
        _vs[3] = old[0]; _vs[4] = old[4]; _vs[5] = old[1];
        _vs[6] = old[2]; _vs[7] = old[7]; _vs[8] = old[10];
        _vs[9] = old[11]; _vs[10] = old[8]; _vs[11] = old[9];
      }
    };
    
    class MHexahedron27 : public MHexahedron {
     protected:
      MVertex *_vs[19];
     public :
      MHexahedron27(MVertex *v0, MVertex *v1, MVertex *v2, MVertex *v3, MVertex *v4, 
    		MVertex *v5, MVertex *v6, MVertex *v7, MVertex *v8, MVertex *v9,
    		MVertex *v10, MVertex *v11, MVertex *v12, MVertex *v13, MVertex *v14,
    		MVertex *v15, MVertex *v16, MVertex *v17, MVertex *v18, MVertex *v19,
    		MVertex *v20, MVertex *v21, MVertex *v22, MVertex *v23, MVertex *v24,
    		MVertex *v25, MVertex *v26, int num=0, int part=0) 
        : MHexahedron(v0, v1, v2, v3, v4, v5, v6, v7, num, part)
      {
        _vs[0] = v8; _vs[1] = v9; _vs[2] = v10; _vs[3] = v11; _vs[4] = v12; 
        _vs[5] = v13; _vs[6] = v14; _vs[7] = v15; _vs[8] = v16; _vs[9] = v17; 
        _vs[10] = v18; _vs[11] = v19; _vs[12] = v20; _vs[13] = v21; _vs[14] = v22;
        _vs[15] = v23; _vs[16] = v24; _vs[17] = v25; _vs[18] = v26;
        for(int i = 0; i < 19; i++) _vs[i]->setPolynomialOrder(2);
      }
      MHexahedron27(std::vector<MVertex*> &v, int num=0, int part=0) 
        : MHexahedron(v, num, part)
      {
        for(int i = 0; i < 19; i++) _vs[i] = v[8 + i];
        for(int i = 0; i < 19; i++) _vs[i]->setPolynomialOrder(2);
      }
      ~MHexahedron27(){}
      virtual int getPolynomialOrder(){ return 2; }
      virtual int getNumVertices(){ return 27; }
      virtual MVertex *getVertex(int num){ return num < 8 ? _v[num] : _vs[num - 8]; }
      virtual int getNumEdgeVertices(){ return 12; }
      virtual int getNumFaceVertices(){ return 6; }
      virtual int getNumVolumeVertices(){ return 1; }
      virtual int getNumEdgesRep(){ return 24; }
      virtual void getEdgeRep(int num, double *x, double *y, double *z, SVector3 *n)
      { 
        static const int e[24][2] = {
          {0, 8}, {8, 1},
          {0, 9}, {9, 3},
          {0, 10}, {10, 4},
          {1, 11}, {11, 2},
          {1, 12}, {12, 5},
          {2, 13}, {13, 3},
          {2, 14}, {14, 6},
          {3, 15}, {15, 7},
          {4, 16}, {16, 5},
          {4, 17}, {17, 7},
          {5, 18}, {18, 6},
          {6, 19}, {19, 7}
        };
        static const int f[12] = {0, 0, 1, 0, 1, 0, 3, 2, 1, 2, 3, 4};
        _getEdgeRep(getVertex(e[num][0]), getVertex(e[num][1]), x, y, z, n, f[num / 2]);
      }
      virtual int getNumFacesRep(){ return 48; }
      virtual void getFaceRep(int num, double *x, double *y, double *z, SVector3 *n)
      { 
        static const int f[48][3] = {
          {0, 9, 20}, {0, 20, 8}, {3, 13, 20}, {3, 20, 9}, 
          {2, 11, 20}, {2, 20, 13}, {1, 8, 20}, {1, 20, 11},
          {0, 8, 21}, {0, 21, 10}, {1, 12, 21}, {1, 21, 8}, 
          {5, 16, 21}, {5, 21, 12}, {4, 10, 21}, {4, 21, 16}, 
          {0, 10, 22}, {0, 22, 9}, {4, 17, 22}, {4, 22, 10}, 
          {7, 15, 22}, {7, 22, 17}, {3, 9, 22}, {3, 22, 15},  
          {1, 11, 23}, {1, 23, 12}, {2, 14, 23}, {2, 23, 11}, 
          {6, 18, 23}, {6, 23, 14}, {5, 12, 23}, {5, 23, 18}, 
          {2, 13, 24}, {2, 24, 14}, {3, 15, 24}, {3, 24, 13}, 
          {7, 19, 24}, {7, 24, 15}, {6, 14, 24}, {6, 24, 19}, 
          {4, 16, 25}, {4, 25, 17}, {5, 18, 25}, {5, 25, 16}, 
          {6, 19, 25}, {6, 25, 18}, {7, 17, 25}, {7, 25, 19}  
        };
        _getFaceRep(getVertex(f[num][0]), getVertex(f[num][1]), getVertex(f[num][2]),
    		x, y, z, n);
      }
      virtual int getTypeForMSH(){ return MSH_HEX_27; }
      virtual int getTypeForUNV(){ return 0; } // not available
      virtual const char *getStringForPOS(){ return "SH2"; }
      virtual const char *getStringForBDF(){ return 0; } // not available
      virtual void revert()
      {
        MVertex *tmp;
        tmp = _v[0]; _v[0] = _v[2]; _v[2] = tmp;
        tmp = _v[4]; _v[4] = _v[6]; _v[6] = tmp;
        MVertex *old[12];
        for(int i = 0; i < 12; i++) old[i] = _vs[i];
        _vs[0] = old[3]; _vs[1] = old[5]; _vs[2] = old[6];
        _vs[3] = old[0]; _vs[4] = old[4]; _vs[5] = old[1];
        _vs[6] = old[2]; _vs[7] = old[7]; _vs[8] = old[10];
        _vs[9] = old[11]; _vs[10] = old[8]; _vs[11] = old[9];
      }
    };
    
    class MPrism : public MElement {
     protected:
      MVertex *_v[6];
     public :
      MPrism(MVertex *v0, MVertex *v1, MVertex *v2, MVertex *v3, MVertex *v4, 
    	 MVertex *v5, int num=0, int part=0) 
        : MElement(num, part)
      {
        _v[0] = v0; _v[1] = v1; _v[2] = v2; _v[3] = v3;
        _v[4] = v4; _v[5] = v5; 
      }
      MPrism(std::vector<MVertex*> &v, int num=0, int part=0) 
        : MElement(num, part)
      {
        for(int i = 0; i < 6; i++) _v[i] = v[i];
      }
      ~MPrism(){}
      virtual int getDim(){ return 3; }
      virtual int getNumVertices(){ return 6; }
      virtual MVertex *getVertex(int num){ return _v[num]; }
      virtual int getNumEdges(){ return 9; }
      virtual MEdge getEdge(int num)
      {
        static const int edges_prism[9][2] = {
          {0, 1},
          {0, 2},
          {0, 3},
          {1, 2},
          {1, 4},
          {2, 5},
          {3, 4},
          {3, 5},
          {4, 5}
        };
        return MEdge(_v[edges_prism[num][0]], _v[edges_prism[num][1]]);
      }
      virtual int getNumEdgesRep(){ return 9; }
      virtual void getEdgeRep(int num, double *x, double *y, double *z, SVector3 *n)
      {
        static const int f[9] = {0, 1, 2, 0, 2, 3, 1, 1, 1};
        MEdge e(getEdge(num));
        _getEdgeRep(e.getVertex(0), e.getVertex(1), x, y, z, n, f[num]);
      }
      virtual int getNumFaces(){ return 5; }
      virtual MFace getFace(int num)
      {
        static const int trifaces_prism[2][3] = {
          {0, 2, 1},
          {3, 4, 5}
        };
        static const int quadfaces_prism[3][4] = {
          {0, 1, 4, 3},
          {0, 3, 5, 2},
          {1, 2, 5, 4}
        };
        if(num < 2)
          return MFace(_v[trifaces_prism[num][0]],
    		   _v[trifaces_prism[num][1]],
    		   _v[trifaces_prism[num][2]]);
        else
          return MFace(_v[quadfaces_prism[num - 2][0]],
    		   _v[quadfaces_prism[num - 2][1]],
    		   _v[quadfaces_prism[num - 2][2]],
    		   _v[quadfaces_prism[num - 2][3]]);
      }
      virtual int getNumFacesRep(){ return 8; }
      virtual void getFaceRep(int num, double *x, double *y, double *z, SVector3 *n)
      { 
        static const int f[8][3] = {
          {0, 2, 1},
          {3, 4, 5},
          {0, 1, 4}, {0, 4, 3},
          {0, 3, 5}, {0, 5, 2},
          {1, 2, 5}, {1, 5, 4}
        };
        _getFaceRep(getVertex(f[num][0]), getVertex(f[num][1]), getVertex(f[num][2]),
    		x, y, z, n);
      }
      virtual int getTypeForMSH(){ return MSH_PRI_6; }
      virtual int getTypeForUNV(){ return 112; } // solid linear wedge
      virtual const char *getStringForPOS(){ return "SI"; }
      virtual const char *getStringForBDF(){ return "CPENTA"; }
      virtual void revert()
      {
        MVertex *tmp;
        tmp = _v[0]; _v[0] = _v[1]; _v[1] = tmp;
        tmp = _v[3]; _v[3] = _v[4]; _v[4] = tmp;
      }
      virtual int getVolumeSign();
    };
    
    class MPrism15 : public MPrism {
     protected:
      MVertex *_vs[9];
     public :
      MPrism15(MVertex *v0, MVertex *v1, MVertex *v2, MVertex *v3, MVertex *v4, 
    	   MVertex *v5, MVertex *v6, MVertex *v7, MVertex *v8, MVertex *v9,
    	   MVertex *v10, MVertex *v11, MVertex *v12, MVertex *v13, MVertex *v14,
    	   int num=0, int part=0) 
        : MPrism(v0, v1, v2, v3, v4, v5, num, part)
      {
        _vs[0] = v6; _vs[1] = v7; _vs[2] = v8; _vs[3] = v9; _vs[4] = v10; 
        _vs[5] = v11; _vs[6] = v12; _vs[7] = v13; _vs[8] = v14;
        for(int i = 0; i < 9; i++) _vs[i]->setPolynomialOrder(2);
      }
      MPrism15(std::vector<MVertex*> &v, int num=0, int part=0) 
        : MPrism(v, num, part)
      {
        for(int i = 0; i < 9; i++) _vs[i] = v[6 + i];
        for(int i = 0; i < 9; i++) _vs[i]->setPolynomialOrder(2);
      }
      ~MPrism15(){}
      virtual int getPolynomialOrder(){ return 2; }
      virtual int getNumVertices(){ return 15; }
      virtual MVertex *getVertex(int num){ return num < 6 ? _v[num] : _vs[num - 6]; }
      virtual MVertex *getVertexUNV(int num)
      {
        static const int map[15] = {0, 6, 1, 9, 2, 7, 8, 10, 11, 3, 12, 4, 14, 5, 13};
        return getVertex(map[num]); 
      }
      virtual MVertex *getVertexBDF(int num)
      {
        static const int map[15] = {0, 1, 2, 3, 4, 5, 6, 9, 7, 8, 10, 11, 12, 14, 13};
        return getVertex(map[num]); 
      }
      virtual int getNumEdgeVertices(){ return 9; }
      virtual int getNumEdgesRep(){ return 18; }
      virtual void getEdgeRep(int num, double *x, double *y, double *z, SVector3 *n)
      { 
        static const int e[18][2] = {
          {0, 6}, {6, 1},
          {0, 7}, {7, 2},
          {0, 8}, {8, 3},
          {1, 9}, {9, 2},
          {1, 10}, {10, 4},
          {2, 11}, {11, 5},
          {3, 12}, {12, 4},
          {3, 13}, {13, 5},
          {4, 14}, {14, 5}
        };
        static const int f[9] = {0, 1, 2, 0, 2, 3, 1, 1, 1};
        _getEdgeRep(getVertex(e[num][0]), getVertex(e[num][1]), x, y, z, n, f[num / 2]);
      }
      virtual int getNumFacesRep(){ return 26; }
      virtual void getFaceRep(int num, double *x, double *y, double *z, SVector3 *n)
      { 
        static const int f[26][3] = {
          {0, 7, 6}, {2, 9, 7}, {1, 6, 9}, {6, 7, 9},
          {3, 12, 13}, {4, 14, 12}, {5, 13, 14}, {12, 14, 13},
          {0, 6, 8}, {1, 10, 6}, {4, 12, 10}, {3, 8, 12}, {6, 10, 12}, {6, 12, 8},
          {0, 8, 7}, {3, 13, 8}, {5, 11, 13}, {2, 7, 11}, {7, 8, 13}, {7, 13, 11},
          {1, 9, 10}, {2, 11, 9}, {5, 14, 11}, {4, 10, 14}, {9, 11, 14}, {9, 14, 10}
        };
        _getFaceRep(getVertex(f[num][0]), getVertex(f[num][1]), getVertex(f[num][2]),
    		x, y, z, n);
      }
      virtual int getTypeForMSH(){ return MSH_PRI_15; }
      virtual int getTypeForUNV(){ return 113; } // solid parabolic wedge
      virtual const char *getStringForPOS(){ return 0; } // not available
      virtual const char *getStringForBDF(){ return "CPENTA"; }
      virtual void revert()
      {
        MVertex *tmp;
        tmp = _v[0]; _v[0] = _v[1]; _v[1] = tmp;
        tmp = _v[3]; _v[3] = _v[4]; _v[4] = tmp;
        tmp = _vs[1]; _vs[1] = _vs[3]; _vs[3] = tmp;
        tmp = _vs[2]; _vs[2] = _vs[4]; _vs[4] = tmp;
        tmp = _vs[7]; _vs[7] = _vs[8]; _vs[8] = tmp;
      }
    };
    
    class MPrism18 : public MPrism {
     protected:
      MVertex *_vs[12];
     public :
      MPrism18(MVertex *v0, MVertex *v1, MVertex *v2, MVertex *v3, MVertex *v4, 
    	   MVertex *v5, MVertex *v6, MVertex *v7, MVertex *v8, MVertex *v9,
    	   MVertex *v10, MVertex *v11, MVertex *v12, MVertex *v13, MVertex *v14,
    	   MVertex *v15, MVertex *v16, MVertex *v17, int num=0, int part=0) 
        : MPrism(v0, v1, v2, v3, v4, v5, num, part)
      {
        _vs[0] = v6; _vs[1] = v7; _vs[2] = v8; _vs[3] = v9; _vs[4] = v10; 
        _vs[5] = v11; _vs[6] = v12; _vs[7] = v13; _vs[8] = v14; _vs[9] = v15; 
        _vs[10] = v16; _vs[11] = v17; 
        for(int i = 0; i < 12; i++) _vs[i]->setPolynomialOrder(2);
      }
      MPrism18(std::vector<MVertex*> &v, int num=0, int part=0) 
        : MPrism(v, num, part)
      {
        for(int i = 0; i < 12; i++) _vs[i] = v[6 + i];
        for(int i = 0; i < 12; i++) _vs[i]->setPolynomialOrder(2);
      }
      ~MPrism18(){}
      virtual int getPolynomialOrder(){ return 2; }
      virtual int getNumVertices(){ return 18; }
      virtual MVertex *getVertex(int num){ return num < 6 ? _v[num] : _vs[num - 6]; }
      virtual int getNumEdgeVertices(){ return 9; }
      virtual int getNumFaceVertices(){ return 3; }
      virtual int getNumEdgesRep(){ return 18; }
      virtual void getEdgeRep(int num, double *x, double *y, double *z, SVector3 *n)
      { 
        static const int e[18][2] = {
          {0, 6}, {6, 1},
          {0, 7}, {7, 2},
          {0, 8}, {8, 3},
          {1, 9}, {9, 2},
          {1, 10}, {10, 4},
          {2, 11}, {11, 5},
          {3, 12}, {12, 4},
          {3, 13}, {13, 5},
          {4, 14}, {14, 5}
        };
        static const int f[9] = {0, 1, 2, 0, 2, 3, 1, 1, 1};
        _getEdgeRep(getVertex(e[num][0]), getVertex(e[num][1]), x, y, z, n, f[num / 2]);
      }
      virtual int getNumFacesRep(){ return 32; }
      virtual void getFaceRep(int num, double *x, double *y, double *z, SVector3 *n)
      { 
        static const int f[32][3] = {
          {0, 7, 6}, {2, 9, 7}, {1, 6, 9}, {6, 7, 9},
          {3, 12, 13}, {4, 14, 12}, {5, 13, 14}, {12, 14, 13},
          {0, 6, 15}, {0, 15, 8}, {1, 10, 15}, {1, 15, 6},  
          {4, 12, 15}, {4, 15, 10}, {3, 8, 15}, {3, 15, 12},  
          {0, 8, 16}, {0, 16, 7}, {3, 13, 16}, {3, 16, 8},  
          {5, 11, 16}, {5, 16, 13}, {2, 7, 16}, {2, 16, 11},  
          {1, 9, 17}, {1, 17, 10}, {2, 11, 17}, {2, 17, 9},  
          {5, 14, 17}, {5, 17, 11}, {4, 10, 17}, {4, 17, 14}
        };
        _getFaceRep(getVertex(f[num][0]), getVertex(f[num][1]), getVertex(f[num][2]),
    		x, y, z, n);
      }
      virtual int getTypeForMSH(){ return MSH_PRI_18; }
      virtual int getTypeForUNV(){ return 0; } // not available
      virtual const char *getStringForPOS(){ return "SI2"; }
      virtual const char *getStringForBDF(){ return 0; } // not available
      virtual void revert()
      {
        MVertex *tmp;
        tmp = _v[0]; _v[0] = _v[1]; _v[1] = tmp;
        tmp = _v[3]; _v[3] = _v[4]; _v[4] = tmp;
        tmp = _vs[1]; _vs[1] = _vs[3]; _vs[3] = tmp;
        tmp = _vs[2]; _vs[2] = _vs[4]; _vs[4] = tmp;
        tmp = _vs[7]; _vs[7] = _vs[8]; _vs[8] = tmp;
      }
    };
    
    class MPyramid : public MElement {
     protected:
      MVertex *_v[5];
     public :
      MPyramid(MVertex *v0, MVertex *v1, MVertex *v2, MVertex *v3, MVertex *v4, 
    	   int num=0, int part=0) 
        : MElement(num, part)
      {
        _v[0] = v0; _v[1] = v1; _v[2] = v2; _v[3] = v3; _v[4] = v4;
      }
      MPyramid(std::vector<MVertex*> &v, int num=0, int part=0) 
        : MElement(num, part)
      {
        for(int i = 0; i < 5; i++) _v[i] = v[i];
      }
      ~MPyramid(){}
      virtual int getDim(){ return 3; }
      virtual int getNumVertices(){ return 5; }
      virtual MVertex *getVertex(int num){ return _v[num]; }
      virtual int getNumEdges(){ return 8; }
      virtual MEdge getEdge(int num)
      {
        static const int edges_pyramid[8][2] = {
          {0, 1},
          {0, 3},
          {0, 4},
          {1, 2},
          {1, 4},
          {2, 3},
          {2, 4},
          {3, 4}
        };
        return MEdge(_v[edges_pyramid[num][0]], _v[edges_pyramid[num][1]]);
      }
      virtual int getNumEdgesRep(){ return 8; }
      virtual void getEdgeRep(int num, double *x, double *y, double *z, SVector3 *n)
      {
        static const int f[8] = {0, 1, 1, 2, 0, 3, 2, 3};
        MEdge e(getEdge(num));
        _getEdgeRep(e.getVertex(0), e.getVertex(1), x, y, z, n, f[num]);
      }
      virtual int getNumFaces(){ return 5; }
      virtual MFace getFace(int num)
      {
        static const int faces_pyramid[4][3] = {
          {0, 1, 4},
          {3, 0, 4},
          {1, 2, 4},
          {2, 3, 4}
        };
        if(num < 4)
          return MFace(_v[faces_pyramid[num][0]],
    		   _v[faces_pyramid[num][1]],
    		   _v[faces_pyramid[num][2]]);
        else
          return MFace(_v[0], _v[3], _v[2], _v[1]);
      }
      virtual int getNumFacesRep(){ return 6; }
      virtual void getFaceRep(int num, double *x, double *y, double *z, SVector3 *n)
      { 
        static const int f[6][3] = {
          {0, 1, 4},
          {3, 0, 4},
          {1, 2, 4},
          {2, 3, 4},
          {0, 3, 2}, {0, 2, 1}
        };
        _getFaceRep(getVertex(f[num][0]), getVertex(f[num][1]), getVertex(f[num][2]),
    		x, y, z, n);
      }
      virtual int getTypeForMSH(){ return MSH_PYR_5; }
      virtual int getTypeForUNV(){ return 0; } // not available
      virtual const char *getStringForPOS(){ return "SY"; }
      virtual const char *getStringForBDF(){ return "CPYRAM"; }
      virtual void revert()
      {
        MVertex *tmp = _v[0]; _v[0] = _v[2]; _v[2] = tmp;
      }
      virtual int getVolumeSign();
    };
    
    class MPyramid13 : public MPyramid {
     protected:
      MVertex *_vs[8];
     public :
      MPyramid13(MVertex *v0, MVertex *v1, MVertex *v2, MVertex *v3, MVertex *v4, 
    	     MVertex *v5, MVertex *v6, MVertex *v7, MVertex *v8, MVertex *v9,
    	     MVertex *v10, MVertex *v11, MVertex *v12, int num=0, int part=0) 
        : MPyramid(v0, v1, v2, v3, v4, num, part)
      {
        _vs[0] = v5; _vs[1] = v6; _vs[2] = v7; _vs[3] = v8; _vs[4] = v9; 
        _vs[5] = v10; _vs[6] = v11; _vs[7] = v12;
        for(int i = 0; i < 8; i++) _vs[i]->setPolynomialOrder(2);
      }
      MPyramid13(std::vector<MVertex*> &v, int num=0, int part=0) 
        : MPyramid(v, num, part)
      {
        for(int i = 0; i < 8; i++) _vs[i] = v[5 + i];
        for(int i = 0; i < 8; i++) _vs[i]->setPolynomialOrder(2);
      }
      ~MPyramid13(){}
      virtual int getPolynomialOrder(){ return 2; }
      virtual int getNumVertices(){ return 13; }
      virtual MVertex *getVertex(int num){ return num < 5 ? _v[num] : _vs[num - 5]; }
      virtual int getNumEdgeVertices(){ return 8; }
      virtual int getNumEdgesRep(){ return 16; }
      virtual void getEdgeRep(int num, double *x, double *y, double *z, SVector3 *n)
      { 
        static const int e[16][2] = {
          {0, 5}, {5, 1},
          {0, 6}, {6, 3},
          {0, 7}, {7, 4},
          {1, 8}, {8, 2},
          {1, 9}, {9, 4},
          {2, 10}, {10, 3},
          {2, 11}, {11, 4},
          {3, 12}, {12, 4}
        };
        static const int f[8] = {0, 1, 1, 2, 0, 3, 2, 3};
        _getEdgeRep(getVertex(e[num][0]), getVertex(e[num][1]), x, y, z, n, f[num / 2]);
      }
      virtual int getNumFacesRep(){ return 22; }
      virtual void getFaceRep(int num, double *x, double *y, double *z, SVector3 *n)
      { 
        static const int f[22][3] = {
          {0, 5, 7}, {1, 9, 5}, {4, 7, 9}, {5, 9, 7},
          {3, 6, 12}, {0, 7, 6}, {4, 12, 7}, {6, 7, 12},
          {1, 8, 9}, {2, 11, 8}, {4, 9, 11}, {8, 11, 9},
          {2, 10, 11}, {3, 12, 10}, {4, 11, 12}, {10, 12, 11},
          {0, 6, 5}, {3, 10, 6}, {2, 8, 10}, {1, 5, 8}, {5, 6, 10}, {5, 10, 8}
        };
        _getFaceRep(getVertex(f[num][0]), getVertex(f[num][1]), getVertex(f[num][2]),
    		x, y, z, n);
      }
      virtual int getTypeForMSH(){ return MSH_PYR_13; }
      virtual int getTypeForUNV(){ return 0; } // not available
      virtual const char *getStringForPOS(){ return 0; } // not available
      virtual const char *getStringForBDF(){ return 0; } // not available
      virtual void revert()
      {
        MVertex *tmp;
        tmp = _v[0]; _v[0] = _v[2]; _v[2] = tmp;
        tmp = _vs[0]; _vs[0] = _vs[3]; _vs[3] = tmp;
        tmp = _vs[1]; _vs[1] = _vs[5]; _vs[5] = tmp;
        tmp = _vs[2]; _vs[2] = _vs[6]; _vs[6] = tmp;
      }
    };
    
    class MPyramid14 : public MPyramid {
     protected:
      MVertex *_vs[9];
     public :
      MPyramid14(MVertex *v0, MVertex *v1, MVertex *v2, MVertex *v3, MVertex *v4, 
    	     MVertex *v5, MVertex *v6, MVertex *v7, MVertex *v8, MVertex *v9,
    	     MVertex *v10, MVertex *v11, MVertex *v12, MVertex *v13, 
    	     int num=0, int part=0) 
        : MPyramid(v0, v1, v2, v3, v4, num, part)
      {
        _vs[0] = v5; _vs[1] = v6; _vs[2] = v7; _vs[3] = v8; _vs[4] = v9; 
        _vs[5] = v10; _vs[6] = v11; _vs[7] = v12; _vs[8] = v13; 
        for(int i = 0; i < 9; i++) _vs[i]->setPolynomialOrder(2);   
      }
      MPyramid14(std::vector<MVertex*> &v, int num=0, int part=0) 
        : MPyramid(v, num, part)
      {
        for(int i = 0; i < 9; i++) _vs[i] = v[5 + i];
        for(int i = 0; i < 9; i++) _vs[i]->setPolynomialOrder(2);   
      }
      ~MPyramid14(){}
      virtual int getPolynomialOrder(){ return 2; }
      virtual int getNumVertices(){ return 14; }
      virtual MVertex *getVertex(int num){ return num < 5 ? _v[num] : _vs[num - 5]; }
      virtual int getNumEdgeVertices(){ return 8; }
      virtual int getNumFaceVertices(){ return 1; }
      virtual int getNumEdgesRep(){ return 16; }
      virtual void getEdgeRep(int num, double *x, double *y, double *z, SVector3 *n)
      { 
        static const int e[16][2] = {
          {0, 5}, {5, 1},
          {0, 6}, {6, 3},
          {0, 7}, {7, 4},
          {1, 8}, {8, 2},
          {1, 9}, {9, 4},
          {2, 10}, {10, 3},
          {2, 11}, {11, 4},
          {3, 12}, {12, 4}
        };
        static const int f[8] = {0, 1, 1, 2, 0, 3, 2, 3};
        _getEdgeRep(getVertex(e[num][0]), getVertex(e[num][1]), x, y, z, n, f[num / 2]);
      }
      virtual int getNumFacesRep(){ return 24; }
      virtual void getFaceRep(int num, double *x, double *y, double *z, SVector3 *n)
      { 
        static const int f[24][3] = {
          {0, 5, 7}, {1, 9, 5}, {4, 7, 9}, {5, 9, 7},
          {3, 6, 12}, {0, 7, 6}, {4, 12, 7}, {6, 7, 12},
          {1, 8, 9}, {2, 11, 8}, {4, 9, 11}, {8, 11, 9},
          {2, 10, 11}, {3, 12, 10}, {4, 11, 12}, {10, 12, 11},
          {0, 6, 13}, {0, 13, 5}, {3, 10, 13}, {3, 13, 6}, 
          {2, 8, 13}, {2, 13, 10}, {1, 5, 13}, {1, 13, 8}
        };
        _getFaceRep(getVertex(f[num][0]), getVertex(f[num][1]), getVertex(f[num][2]),
    		x, y, z, n);
      }
      virtual int getTypeForMSH(){ return MSH_PYR_14; }
      virtual int getTypeForUNV(){ return 0; } // not available
      virtual const char *getStringForPOS(){ return "SY2"; }
      virtual const char *getStringForBDF(){ return 0; } // not available
      virtual void revert()
      {
        MVertex *tmp;
        tmp = _v[0]; _v[0] = _v[2]; _v[2] = tmp;
        tmp = _vs[0]; _vs[0] = _vs[3]; _vs[3] = tmp;
        tmp = _vs[1]; _vs[1] = _vs[5]; _vs[5] = tmp;
        tmp = _vs[2]; _vs[2] = _vs[6]; _vs[6] = tmp;
      }
    };
    
    template <class T> 
    void sort3(T *t[3])
    {
      T *temp;
      if(t[0] > t[1]){
        temp = t[1];
        t[1] = t[0];
        t[0] = temp;
      }
      if(t[1] > t[2]){
        temp = t[2];
        t[2] = t[1];
        t[1] = temp;
      }
      if(t[0] > t[1]){
        temp = t[1];
        t[1] = t[0];
        t[0] = temp;
      }
    }
    
    struct compareMTriangleLexicographic
    {
      bool operator () (MTriangle *t1, MTriangle *t2) const
      {
        MVertex *_v1[3] = {t1->getVertex(0), t1->getVertex(1), t1->getVertex(2)};
        MVertex *_v2[3] = {t2->getVertex(0), t2->getVertex(1), t2->getVertex(2)};
        sort3(_v1);
        sort3(_v2);
        if(_v1[0] < _v2[0]) return true;
        if(_v1[0] > _v2[0]) return false;
        if(_v1[1] < _v2[1]) return true;
        if(_v1[1] > _v2[1]) return false;
        if(_v1[2] < _v2[2]) return true;
        return false;
      }
    };
    
    #endif