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

BasisHierarchical1From.h

Blame
  • Forked from gmsh / gmsh
    Source project has a limited visibility.
    Curvature.cpp 61.18 KiB
    // Gmsh - Copyright (C) 1997-2011 C. Geuzaine, J.-F. Remacle
    //
    // See the LICENSE.txt file for license information. Please report all
    // bugs and problems to <gmsh@geuz.org>.
    
    #include "Curvature.h"
    #include "MElement.h"
    #include "MTriangle.h"
    #include "GEntity.h"
    #include "GFaceCompound.h"
    #include "MLine.h"
    #include "GRbf.h"
    #include "OS.h"
    #include "SBoundingBox3d.h"
    #include "discreteEdge.h"
    
    #include<iostream>
    #include<fstream>
    #include<cmath>
    
    #define NEXT(i) ((i)<2 ? (i)+1 : (i)-2)
    #define PREV(i) ((i)>0 ? (i)-1 : (i)+2)
    //========================================================================================================
    
    //Initialization of the static variables:
    Curvature* Curvature::_instance = 0;
    bool Curvature::_destroyed = false;
    bool Curvature::_alreadyComputedCurvature = false;
    
    //========================================================================================================
    
    //CONSTRUCTOR
    Curvature::Curvature() : _isMapInitialized(false)
    {
    }
    
    // Curvature::Curvature(std::list<GFace*> &myFaces){
    
    //   std::list<GFace*>::const_iterator it = myFaces.begin();
    //   for( ; it != myFaces.end() ; ++it){
    //          _ptFinalEntityList.push_back(*it);
    //   }
    
    // }
    
    //========================================================================================================
    
    Curvature::~Curvature()
    {
       _instance = 0;
      _destroyed = true;
    
    }
    //========================================================================================================
    void Curvature::onDeadReference()
    {
      std::cout << "Dead reference of Curvature detected" << std::endl;
    }
    //========================================================================================================
    
    Curvature& Curvature::getInstance()
    {
      if (!_instance)  {
        if(_destroyed){
          onDeadReference();
        }
        else{
          create();
        }
      }
      return *_instance;
    }
    //========================================================================================================
      bool Curvature::valueAlreadyComputed()
      {
        return _alreadyComputedCurvature;
      }
    
    //========================================================================================================
    
     void Curvature::create()
     {
       static Curvature instance;
       _instance = & instance;
     }
    
     //========================================================================================================
     void Curvature::retrieveCompounds()  {
    #if defined(HAVE_SOLVER)
    
       /// -------------------------------------------------------------------------------------------
       // Loop over all faces. Check if the face is a compound. If it is, store all of its discrete
       // faces in _EntityArray
    
       std::list<GFace*> global_face_list;
    
       for(GModel::fiter face_iter = _model->firstFace(); face_iter != _model->lastFace(); ++face_iter)
       {
         if ( (*face_iter)->geomType() == GEntity::CompoundSurface )
         {
    
           GFaceCompound* compound = dynamic_cast<GFaceCompound*>(*face_iter);
           std::list<GFace*> tempcompounds = compound->getCompounds();
           std::list<GFace*>::iterator surfIterator;
    
           for(surfIterator = tempcompounds.begin(); surfIterator != tempcompounds.end(); ++surfIterator)
           {
             if ((*surfIterator)->geomType() == GEntity::DiscreteSurface)
             {
               global_face_list.push_back(*surfIterator);
             }
           }
         }
    
       } // Loop over faces of the model
    
       global_face_list.sort();
       global_face_list.unique();
       _EntityArray.resize(global_face_list.size());
       std::copy(global_face_list.begin(),global_face_list.end(),_EntityArray.begin());
    
    //   std::cout << "Retrieve compounds: some preliminary info:" << std::endl;
    //   std::cout << "The size of _ptFinalEntityList = " << _EntityArray.size() << std::endl;
    //   std::cout << "Number of elements in all faces: " << std::endl;
    //   for(int i = 0; i < _EntityArray.size(); ++i)
    //   {
    //     std::cout << "\t" << _EntityArray[i]->getNumMeshElements() << " elements" << std::endl;
    //   }
    
    #endif
     }
    
     //========================================================================================================
    
     // Method to detect boundary edges of the mesh. We want to find which edges are on the boundary in order
     // to correct the curvature field close to boundaries
    
     void Curvature::correctOnEdges()
     {
    #if defined(HAVE_SOLVER)
    
       if (! _alreadyComputedCurvature )
       {
         Msg::Error("Cannot correct the curvature values at the edges because the curvatures weren't computed yet");
         return;
       }
       // Remark: this can only be used after the call to initializeMap() !
    
      buildEdgeList();
    
      std::list<MeshEdgeInfo>::iterator VertToEdgeListIter;
    
       _isOnBoundary.resize(_VertexToInt.size());
       for (int i = 0; i < _VertexToInt.size(); ++i)
       {
         _isOnBoundary[i] = 0;
       }
    
       // To detect the nodes on the egdes of a geometry, we create a list of all edges on the mesh. The
       // edges which are shared by only one mesh element are boundary edges. Their nodes are tagged by 1
       for (int i = 0; i < _VertexToInt.size(); ++i)
       {
         for (VertToEdgeListIter = _VertexToEdgeList[i].begin(); VertToEdgeListIter != _VertexToEdgeList[i].end();
                                                                                        ++VertToEdgeListIter)
         {
           if ((*VertToEdgeListIter).NbElemNeighbour == 1)
           {
             _isOnBoundary[(*VertToEdgeListIter).StartV] = 1;
             _isOnBoundary[(*VertToEdgeListIter).EndV] = 1;
           }
         }
    
       }
    
       // We want to find the nodes that are the immediate neighbours of the boundary nodes. Those nodes are
       // considered nodes with 'level 2'. The neighbours of neighbours have 'level 3' etc.
       // We want to construct levels 1,2,3. Nodes with level 0 are internal nodes of the mesh
       //Loop over the vector of edgelist
       for (int level = 1; level < 3; ++level)
       {
         for (int i = 0; i < _VertexToEdgeList.size(); ++i)
         {
           for (VertToEdgeListIter = _VertexToEdgeList[i].begin(); VertToEdgeListIter != _VertexToEdgeList[i].end();
                                                                                    ++VertToEdgeListIter)
           {
             if (_isOnBoundary[(*VertToEdgeListIter).StartV] == level && _isOnBoundary[(*VertToEdgeListIter).EndV] == 0)
             {
              _isOnBoundary[(*VertToEdgeListIter).EndV] = level+1;
             }
             if (_isOnBoundary[(*VertToEdgeListIter).EndV] == level && _isOnBoundary[(*VertToEdgeListIter).StartV] == 0)
             {
               _isOnBoundary[(*VertToEdgeListIter).StartV] = level+1;
             }
           }
         }
       }//Loop over the level of the ring
    
    
       // Check test to see the tag of the nodes on the boundary:
    //   for (int i = 0; i< _EntityArray.size(); ++i)
    //   {
    //     GFace* face = _EntityArray[i]; //List of all the discrete face on which we compute the curvature
    
    //     for (int iElem = 0; iElem < face->getNumMeshElements(); iElem++)
    //     {
    //       MElement *e = face->getMeshElement(iElem);
    
    //       // The NEW tag of the corresponding element
    //       const int E = _ElementToInt[e->getNum()];
    
    //       // Pointers to vertices of triangle
    //       MVertex* A = e->getVertex(0);
    //       MVertex* B = e->getVertex(1);
    //       MVertex* C = e->getVertex(2);
    
    //       V[0] = _VertexToInt[A->getNum()];  //The new number of the vertex
    //       V[1] = _VertexToInt[B->getNum()];
    //       V[2] = _VertexToInt[C->getNum()];
    
    //       if (_isOnBoundary[V[0]] == 3)
    //       {
    //         std::cout << "Vertex: " << A->getNum() << " -- " << A->x() << "; " << A->y() << "; " << A->z() << std::endl;
    //       }
    //       if (_isOnBoundary[V[1]] == 3)
    //       {
    //         std::cout << "Vertex: " << B->getNum() << " -- " << B->x() << "; " << B->y() << "; " << B->z() << std::endl;
    //       }
    //       if (_isOnBoundary[V[2]] == 3)
    //       {
    //         std::cout << "Vertex: " << C->getNum() << " -- " << C->x() << "; " << C->y() << "; " << C->z() << std::endl;
    //       }
    //     }
    //   }
    
    
       // Now we'll propagate the cuvature values from inside nodes with level = 3 close to the boundary - first
       // to nodes with level 2, then from nodes with level 2 to nodes with level 1 (on the boundary)
       _NbNeighbour.resize(_VertexToInt.size());
       for(int i = 0; i < _NbNeighbour.size(); ++i)
       {
         _NbNeighbour[i] = 0;
       }
    
       for (int level = 2; level > 0 ; --level)
       {
    
         for (int i = 0; i< _NbNeighbour.size(); ++i)
         {
           _NbNeighbour[i] = 0;
           if (_isOnBoundary[i] == level)
           {
            _VertexCurve[i] = 0.0;
           }
         }
    
    
         for (int i = 0; i < _VertexToEdgeList.size(); ++i)
         {
           for (VertToEdgeListIter = _VertexToEdgeList[i].begin(); VertToEdgeListIter != _VertexToEdgeList[i].end();
                                                                                    ++VertToEdgeListIter)
           {
    
             if (_isOnBoundary[(*VertToEdgeListIter).StartV] == level && _isOnBoundary[(*VertToEdgeListIter).EndV] == level+1)
             {
                _VertexCurve[(*VertToEdgeListIter).StartV] += _VertexCurve[(*VertToEdgeListIter).EndV];
                _NbNeighbour[(*VertToEdgeListIter).StartV] ++;
    
             }
             if (_isOnBoundary[(*VertToEdgeListIter).EndV] == level && _isOnBoundary[(*VertToEdgeListIter).StartV] == level+1)
             {
                _VertexCurve[(*VertToEdgeListIter).EndV] += _VertexCurve[(*VertToEdgeListIter).StartV];
                _NbNeighbour[(*VertToEdgeListIter).EndV] ++;
             }
    
           }
         }
    
         // Correction for a degenerate case when a node has neighbours with the same or lower level, but zero
         // neighbours with level+1
    
         for (int i = 0; i < _VertexToEdgeList.size(); ++i)
         {
           for (VertToEdgeListIter = _VertexToEdgeList[i].begin(); VertToEdgeListIter != _VertexToEdgeList[i].end();
                                                                                    ++VertToEdgeListIter)
           {
    
             if (_isOnBoundary[(*VertToEdgeListIter).StartV] == level
                 && _isOnBoundary[(*VertToEdgeListIter).EndV] == level
                 && _NbNeighbour[(*VertToEdgeListIter).StartV] == 0)
             {
               _VertexCurve[(*VertToEdgeListIter).StartV] += _VertexCurve[(*VertToEdgeListIter).EndV];
               _NbNeighbour[(*VertToEdgeListIter).StartV] = _NbNeighbour[(*VertToEdgeListIter).EndV];
             }
             if (_isOnBoundary[(*VertToEdgeListIter).EndV] == level
                 && _isOnBoundary[(*VertToEdgeListIter).StartV] == level
                 && _NbNeighbour[(*VertToEdgeListIter).EndV] == 0)
             {
               _VertexCurve[(*VertToEdgeListIter).EndV] += _VertexCurve[(*VertToEdgeListIter).StartV];
               _NbNeighbour[(*VertToEdgeListIter).EndV] = _NbNeighbour[(*VertToEdgeListIter).StartV];
             }
           }
         }
    
         for (int i = 0; i < _isOnBoundary.size(); ++i)
         {
           if (_isOnBoundary[i] == level)
           {
             if (_NbNeighbour[i] == 0)
             {
               std::cout << "ERROR: VERTEX " << i << " WITH LEVEL " << level << " HAS 0 NEIGHBOURS" << std::endl;
             }
             _VertexCurve[i] = _VertexCurve[i]/_NbNeighbour[i];
           }
         }
    
       }//Loop over the levels of the ring
    
    //   for (int i = 0; i < _isOnBoundary.size(); ++i)
    //   {
    //     _VertexCurve[i] = _isOnBoundary[i];
    //   }
    
    #endif
     }
    
    //========================================================================================================
    
    //INITIALIZATION OF THE MAP  AND  RENUMBERING OF THE SELECTED ENTITIES:
    
    void Curvature::initializeMap()
    {
      if (! _isMapInitialized)
      {
        for (int i = 0; i< _EntityArray.size(); ++i)
        {
          GFace* face = _EntityArray[i];
    
          for (int iElem = 0; iElem < face->getNumMeshElements(); iElem++)
          {
            MElement *e = face->getMeshElement(iElem);
            const int E = e->getNum();
            _ElementToInt[E] = 1;
    
            const int A = e->getVertex(0)->getNum();   //Pointer to 1st vertex of the triangle
            const int B = e->getVertex(1)->getNum();
            const int C = e->getVertex(2)->getNum();
    
            _VertexToInt[A] = 1;
            _VertexToInt[B] = 1;
            _VertexToInt[C] = 1;
          }
        }
    
        /// Set up a new numbering of chosen vertices and triangles
        int idx = 0;
    
        // map between the pointer to vertex and the new numbering of the vertex
        std::map<int,int>::iterator vertex_iterator;
        // map between the pointer to element and the new numbering of the element
        std::map<int,int>::iterator element_iterator;
    
        for (vertex_iterator = _VertexToInt.begin() ; vertex_iterator !=_VertexToInt.end() ; ++ vertex_iterator, ++idx)
          (*vertex_iterator).second = idx;
    
        idx = 0;
    
        for (element_iterator = _ElementToInt.begin() ; element_iterator !=_ElementToInt.end() ; ++ element_iterator, ++idx)
          (*element_iterator).second = idx;
    
       _isMapInitialized = true;
    
      }
    
    }
    
    //========================================================================================================
    
    //COMPUTE THE NORMAL AT THE VERTEX AND THE AREA AROUND
    
    void Curvature::computeVertexNormals()
    {
      SVector3 vector_AB;
      SVector3 vector_AC;
    
      _TriangleArea.resize(_ElementToInt.size() );
      _VertexArea.resize(_ElementToInt.size() );
      _VertexNormal.resize(_VertexToInt.size());
    
      for (int i = 0; i< _EntityArray.size(); ++i)
      {
        // face is a pointer to one surface of the group "FinalEntityList"
        GFace* face = _EntityArray[i];
    
        //Loop over the element all the element of the "myTag"-surface
        for (int iElem = 0; iElem < face->getNumMeshElements(); iElem++)
        {
          // Pointer to one element
          MElement *e = face->getMeshElement(iElem);
          // The NEW tag of the corresponding element
          const int E = _ElementToInt[e->getNum()];
          // std::cout << "We are now looking at element Nr: " << E << std::endl;
    
          // Pointers to vertices of triangle
          MVertex* A = e->getVertex(0);
          MVertex* B = e->getVertex(1);
          MVertex* C = e->getVertex(2);
    
          const int V0 = _VertexToInt[A->getNum()];  //The new number of the vertex
          const int V1 = _VertexToInt[B->getNum()];
          const int V2 = _VertexToInt[C->getNum()];
    
          vector_AB = SVector3(B->x() - A->x(), B->y() - A->y(), B->z() - A->z() );
          vector_AC = SVector3(C->x() - A->x(), C->y() - A->y(), C->z() - A->z() );
    
          const SVector3 cross = crossprod(vector_AB, vector_AC);
    
          // Area of the triangles:
          _TriangleArea[E] = 0.5*cross.norm();
          // std::cout << "The area of the triangle nr: " << e->getNum() << " is: "<< TriangleArea[E] << std::endl;
    
          _VertexArea[V0] += _TriangleArea[E];
          _VertexArea[V1] += _TriangleArea[E];
          _VertexArea[V2] += _TriangleArea[E];
    
          _VertexNormal[V0] += cross;  //here we are actually computing the unit normal vector per vertex
          _VertexNormal[V1] += cross;
          _VertexNormal[V2] += cross;
    
        } // end of loop over elements of one face
    
      } //Loop over _ptFinalEntityList
    
        ///////Normalize the vertex-normals.
        for (unsigned int n = 0; n < _VertexToInt.size(); ++ n)
        {
          _VertexNormal[n].normalize();
        }
    }
    
    //========================================================================================================
    
    void Curvature::curvatureTensor()
    {
    
      STensor3 TempTensor;
      STensor3 TijABTensorProduct;
      SVector3 TijAB;
      SVector3 vector_AB;
    
      _CurveTensor.resize(_VertexToInt.size());
    
      for (int i = 0; i< _EntityArray.size(); ++i)
      {
        GFace* face = _EntityArray[i]; //face is a pointer to one surface of the group "FinalEntityList"
    
        for (int iElem = 0; iElem < face->getNumMeshElements(); iElem++) //Loop over the element all the element of the "myTag"-surface
        {
          MElement *e = face->getMeshElement(iElem);  //Pointer to one element
          const int E = _ElementToInt[e->getNum()]; //The NEW tag of the corresponding element
    
          for (unsigned int i = 0; i<3; ++i)  // Loop over the 3 edges of each element
          {
    
            MVertex* A = e->getVertex(i);                   //Pointer to 1st vertex of the edge A-to-B
            MVertex* B = e->getVertex((i+1)%3);             //Pointer to 2nd vertex of the edge A-to-B
    
            const int V0 = _VertexToInt[A->getNum()];       //Tag of the 1st vertex of the edge A-to-B
            const int V1 = _VertexToInt[B->getNum()];       //Tag of the 2nd vertex of the edge A-to-B
    
            //Weight for triangle-i-th's contribution to the shape tensor:
            const double Wij0 = _TriangleArea[E] / (2 * _VertexArea[V0]);
            const double Wij1 = _TriangleArea[E] / (2 * _VertexArea[V1]);
    
            //Approximate Curvature "kappa" along some tangential vector T:
            vector_AB = SVector3(B->x() - A->x(), B->y() - A->y(), B->z() - A->z() );
            const double k_nominator0 =  dot(_VertexNormal[V0], vector_AB); //Dot-product of the 2 vectors
            const double k_nominator1 = -dot(_VertexNormal[V1], vector_AB);
    
            const double coeff   = 2.0/vector_AB.normSq(); //normSq is the norm to the power 2
            const double KijAB_0 = coeff*k_nominator0;
            const double KijAB_1 = coeff*k_nominator1;
    
            //Projection of the edge vector AB on the tangential plane:
            //** For Vertex 0
            tensprod(_VertexNormal[V0], _VertexNormal[V0], TempTensor);
            TempTensor      *= -1.0; //-N*Nt
            TempTensor(0,0) +=  1.0; //I-N*Nt
            TempTensor(1,1) +=  1.0;
            TempTensor(2,2) +=  1.0;
    
            for (int m = 0; m<3; ++m)
            {
              TijAB(m) = 0.0;
              for (int n = 0; n<3; ++n)
              {
                TijAB(m) += TempTensor(m,n) * vector_AB(n);
              }
            }
    
            TijAB.normalize();
            tensprod(TijAB, TijAB, TijABTensorProduct);
            _CurveTensor[V0] += Wij0*KijAB_0*TijABTensorProduct;
    
            //** For Vertex 1
            tensprod(_VertexNormal[V1], _VertexNormal[V1], TempTensor);
            TempTensor      *= -1.0; //-N*Nt
            TempTensor(0,0) +=  1.0; //I-N*Nt
            TempTensor(1,1) +=  1.0;
            TempTensor(2,2) +=  1.0;
    
             for (int m = 0; m<3; ++m)
            {
              TijAB(m) = 0.0;
              for (int n = 0; n<3; ++n)
              {
                TijAB(m) += TempTensor(m,n) * vector_AB(n);
              }
            }
    
            TijAB.normalize();
            tensprod(TijAB, TijAB, TijABTensorProduct);
            _CurveTensor[V1] += Wij1*KijAB_1*TijABTensorProduct;
    
          }//end of loop over the edges
    
        }//end of loop over all elements of one GFace
    
      }//End of loop over ptFinalEntityList
    
    }//End of method
    
    //========================================================================================================
    
    void Curvature::computeCurvature_Simple()
    {
      SVector3 vector_E;
      SVector3 vector_A;
      SVector3 vector_B;
      SVector3 vector_Wvi;
      STensor3 Qvi;
      STensor3 QviT;
      STensor3 Holder;
    
      initializeMap();
      computeVertexNormals();
      curvatureTensor();
    
      _VertexCurve.resize(_VertexToInt.size());
    
      for (unsigned int n = 0; n < _VertexToInt.size(); ++ n) //Loop over the vertex
      {
        vector_E = SVector3(1,0,0);
        vector_A = vector_E + _VertexNormal[n];
        vector_B = vector_E - _VertexNormal[n];
    
        const double MagA = vector_A.norm();
        const double MagB = vector_B.norm();
    
        if (MagB > MagA)
        {
          vector_Wvi = vector_B;
        }
        else
        {
          vector_Wvi = vector_A;
        }
    
        vector_Wvi.normalize();
        //to obtain the Qvi = Id -2*Wvi*Wvi^t
        tensprod(vector_Wvi, vector_Wvi, Qvi); //Qvi = Wvi*Wvi^t
        Qvi      *= -2.0;                      //-2*Wvi*Wvi^t
        Qvi(0,0) +=  1.0;                      //I - 2*Wvi*Wvi^t  ==> Householder transformation
        Qvi(1,1) +=  1.0;
        Qvi(2,2) +=  1.0;
    
        //Transpose the matrix:
        for (int i = 0; i<3; ++i)
        {
          for (int j = 0; j<3; ++j)
          {
            QviT(i,j) = Qvi(j,i);
           }
         }
    
         QviT *= _CurveTensor[n];
         QviT *=Qvi;
         Holder = QviT;
    
         //Eigenvalues of the 2*2 minor from the Householder matrix
         const double A = 1.0;
         const double B = -(Holder(1,1) + Holder(2,2));
         const double C = Holder(1,1)*Holder(2,2) - Holder(1,2)*Holder(2,1);
         const double Delta = std::sqrt(B*B-4*A*C);
    
         if((B*B-4.*A*C) < 0.0)
         {
           std::cout << "WARNING: negative discriminant: " << B*B-4.*A*C << std::endl;
         }
    
         const double m11 = (-B + Delta)/(2*A);  //Eigenvalue of Householder submatrix
         const double m22 = (-B - Delta)/(2*A);
    
         //_VertexCurve[n] = (3*m11-m22)*(3*m22-m11);  //Gaussian Curvature
         _VertexCurve[n] = ((3*m11-m22) + (3*m22-m11))*0.5; //Mean Curvature
    
      }
    }
    
    //========================================================================================================
    
    //COMPUTE THE NORMAL AT THE VERTEX AND THE AREA AROUND
    
    void Curvature::computeRusinkiewiczNormals()
    {
      SVector3 vector_AB;
      SVector3 vector_AC;
      SVector3 vector_BC;
    
      _TriangleArea.resize(_ElementToInt.size() );
      _VertexNormal.resize(_VertexToInt.size());
    
      for (int i = 0; i< _EntityArray.size(); ++i)
      {
        // face is a pointer to one surface of the group "FinalEntityList"
        GFace* face = _EntityArray[i];
    
        //Loop over the element all the element of the "myTag"-surface
        for (int iElem = 0; iElem < face->getNumMeshElements(); iElem++)
        {
          // Pointer to one element
          MElement *e = face->getMeshElement(iElem);
          const int E = _ElementToInt[e->getNum()];
        
          // Pointers to vertices of triangle
          MVertex* A = e->getVertex(0);
          MVertex* B = e->getVertex(1);
          MVertex* C = e->getVertex(2);
    
          const int V0 = _VertexToInt[A->getNum()];  //The new number of the vertex
          const int V1 = _VertexToInt[B->getNum()];
          const int V2 = _VertexToInt[C->getNum()];
    
          vector_AB = SVector3(B->x() - A->x(), B->y() - A->y(), B->z() - A->z() );
          vector_AC = SVector3(C->x() - A->x(), C->y() - A->y(), C->z() - A->z() );
          vector_BC = SVector3(C->x() - B->x(), C->y() - B->y(), C->z() - B->z() );
    
          const SVector3 cross = crossprod(vector_AB, vector_AC);
    
          // Area of the triangles:
          _TriangleArea[E] = 0.5*cross.norm();
    
          const double l_AB = vector_AB.normSq();
          const double l_AC = vector_AC.normSq();
          const double l_BC = vector_BC.normSq();
    
          _VertexNormal[V0] += cross * (1.0/ (l_AB*l_AC));
          _VertexNormal[V1] += cross * (1.0/ (l_AB*l_BC));
          _VertexNormal[V2] += cross * (1.0/ (l_AC*l_BC));
    
        } // end of loop over elements of one face
    
      } //Loop over _ptFinalEntityList
    
        ///////Normalize the vertex-normals.
        for (unsigned int n = 0; n < _VertexToInt.size(); ++ n)
        {
          _VertexNormal[n].normalize();
        }
    }
    
    //========================================================================================================
    // Compute per-vertex point areas
    void Curvature::computePointareas(){
    
      SVector3 e[3];
      SVector3 l2;
      SVector3 ew;
      double factor[3];
    
      _pointareas.resize(_VertexToInt.size());
      _cornerareas.resize(_ElementToInt.size());
    
      for (int i = 0; i< _EntityArray.size(); ++i)
      {
        GFace* face = _EntityArray[i]; //face is a pointer to one surface of the group "FinalEntityList"
    
        for (int iElem = 0; iElem < face->getNumMeshElements(); iElem++) //Loop over the element all the element of the "myTag"-surface
        {
          MElement *E = face->getMeshElement(iElem);  //Pointer to one element
          // The NEW tag of the corresponding element
          const int EIdx = _ElementToInt[E->getNum()];
    
          MVertex* A = E->getVertex(0);  //Pointers to vertices of triangle
          MVertex* B = E->getVertex(1);
          MVertex* C = E->getVertex(2);
    
          const int V0 = _VertexToInt[A->getNum()];
          const int V1 = _VertexToInt[B->getNum()];
          const int V2 = _VertexToInt[C->getNum()];
    
          if (_isOnBoundary[V0])
          {
              factor[0] = 1.0;
          }
          else {factor[0] = 1.0;}
    
          if (_isOnBoundary[V1])
          {
              factor[1] = 1.0;
          }
          else {factor[1] = 1.0;}
    
          if (_isOnBoundary[V2])
          {
              factor[2] = 1.0;
          }
          else {factor[2] = 1.0;}
    
          //Edges
          e[0] = SVector3(C->x() - B->x(), C->y() - B->y(), C->z() - B->z()); //vector side of a triangular element
          e[1] = SVector3(A->x() - C->x(), A->y() - C->y(), A->z() - C->z());
          e[2] = SVector3(B->x() - A->x(), B->y() - A->y(), B->z() - A->z());
    
          // Compute corner weights
          //SVector3 len = crossprod(e[0], e[1]);
          //len = norm
          //len2 = normSq
          double area = 0.5 * norm(crossprod(e[0], e[1])); //area of a triangle
          l2 = SVector3( normSq(e[0]), normSq(e[1]), normSq(e[2]) );
          ew = SVector3( l2[0] * (l2[1] + l2[2] - l2[0]),
                         l2[1] * (l2[2] + l2[0] - l2[1]),
                         l2[2] * (l2[0] + l2[1] - l2[2]) );
    
          if (ew[0] <= 0.0)
          {
            _cornerareas[EIdx][1] = -0.25 * l2[2] * area / dot(e[0], e[2]);
            _cornerareas[EIdx][2] = -0.25 * l2[1] * area / dot(e[0], e[1]);
            _cornerareas[EIdx][0] = area - _cornerareas[EIdx][1] - _cornerareas[EIdx][2];
          }
          else if (ew[1] <= 0.0)
          {
            _cornerareas[EIdx][2] = -0.25 * l2[0] * area / dot(e[1], e[0]);
            _cornerareas[EIdx][0] = -0.25 * l2[2] * area / dot(e[1], e[2]);
            _cornerareas[EIdx][1] = area - _cornerareas[EIdx][2] - _cornerareas[EIdx][0];
          }
          else if (ew[2] <= 0.0)
          {
            _cornerareas[EIdx][0] = -0.25 * l2[1] * area / dot(e[2], e[1]);
            _cornerareas[EIdx][1] = -0.25 * l2[0] * area / dot(e[2], e[0]);
            _cornerareas[EIdx][2] = area - _cornerareas[EIdx][0] - _cornerareas[EIdx][1];
          }
          else
          {
            float ewscale = 0.5 * area / (ew[0] + ew[1] + ew[2]);
            for (int j = 0; j < 3; j++)
              _cornerareas[EIdx][j] = ewscale * (ew[(j+1)%3] + ew[(j+2)%3]);
          }
    
          _pointareas[V0] += _cornerareas[EIdx][0];
    
          _pointareas[V1] += _cornerareas[EIdx][1];
    
          _pointareas[V2] += _cornerareas[EIdx][2];
    
          for (int j = 0; j < 3; j++)
          {
              _cornerareas[EIdx][j] = factor[j]*_cornerareas[EIdx][j];
          }
    
    
        } //End of loop over iElem
    
    //      std::cout << "_pointareas.size = " << _pointareas.size() << std::endl;
    //      std::cout << "_cornerareas.size = " << _cornerareas.size() << std::endl;
    
      } //End of loop over _ptFinalEntityList
    
    } //End of the method "computePointareas"
    
    
    //========================================================================================================
    //Rotate a coordinate system to be perpendicular to the given normal
    void Curvature::rot_coord_sys(const SVector3 &old_u, const SVector3 &old_v, const SVector3 &new_norm, SVector3 &new_u, SVector3 &new_v){
    
      new_u = old_u;
      new_v = old_v;
      SVector3 old_norm = crossprod(old_u, old_v);
      double ndot = dot(old_norm, new_norm);
    //  if (unlikely(ndot <= -1.0f))
      if (ndot <= -1.0f)
      {
        new_u = -1.0*new_u;
        new_v = -1.0*new_v;
        return;
      }
    
      SVector3 perp_old = new_norm - ndot*old_norm;
      SVector3 dperp = 1.0f/(1 + ndot) * (old_norm + new_norm);
      new_u -= dperp*dot(new_u, perp_old);
      new_v -= dperp*dot(new_v, perp_old);
    }
    
    //========================================================================================================
    
    //Project a curvature tensor from the basis spanned by old_u and old_v
    //(which are assumed to be unit-length and perpendicular) to the new_u
    //and new_v basis
    
    void Curvature::proj_curv( const SVector3 &old_u, const SVector3 &old_v,
                              double old_ku, double old_kuv, double old_kv,
                              const SVector3  &new_u, const SVector3 &new_v,
                              double &new_ku, double &new_kuv, double &new_kv){
      SVector3 r_new_u;
      SVector3 r_new_v;
      rot_coord_sys(new_u, new_v, crossprod(old_u,old_v), r_new_u, r_new_v);
    
      const double u1 = dot(r_new_u, old_u);
      const double v1 = dot(r_new_u, old_v);
      const double u2 = dot(r_new_v, old_u);
      const double v2 = dot(r_new_v, old_v);
    
      new_ku  =   old_ku*u1*u1 + old_kuv*(2.0f * u1*v1)   + old_kv*v1*v1;
      new_kuv  =  old_ku*u1*u2 + old_kuv*(u1*v2 * u2*v1)  + old_kv*v1*v2;
      new_kv  =   old_ku*u2*u2 + old_kuv*(2.0f * u2*v2)   + old_kv*v2*v2;
    }
    
    
    //========================================================================================================
    
    //Given a curvature tensor, find principal directions and curvatures
    //Makes sure that pdir1 and pdir2 are perpendicular to normal
    
    void Curvature::diagonalize_curv(const SVector3 &old_u, const SVector3 &old_v,
                          double ku, double kuv, double kv,
                          const SVector3 &new_norm,
                          SVector3 &pdir1, SVector3 &pdir2, double &k1, double &k2){
      SVector3 r_old_u;
      SVector3 r_old_v;
    
      double c = 1.0;
      double s = 0.0;
      double tt = 0.0;
    
      rot_coord_sys(old_u, old_v, new_norm, r_old_u, r_old_v);
    
    //  if(unlikely(kuv !=0.0f))
      if(kuv !=0.0)  {
        //Jacobi rotation to diagonalize
        double h= 0.5*(kv -ku)/ kuv;
        tt = (h<0.0) ?
              1.0 / (h - std::sqrt(1.0 + h*h)):
              1.0 / (h + std::sqrt(1.0 + h*h));
        c = 1.0 / std::sqrt(1.0 + tt*tt);
        s = tt*c;
      }
    
      k1 = ku - tt *kuv;
      k2 = kv + tt *kuv;
    
      if(std::abs(k1) >= std::abs(k2))  {
        pdir1 = c*r_old_u - s*r_old_v;
      }
      else  {
        std::swap(k1,k2);
        pdir1 = s*r_old_u + c*r_old_v;
      }
      pdir2 = crossprod(new_norm, pdir1);
    }
    
    //========================================================================================================
    void Curvature::computeCurvature(GModel* model, typeOfCurvature typ)
    {
    
      _model = model;
    
      double t0 = Cpu();
      Msg::StatusBar(2, true, "(C) Computing Curvature");
      if (typ == RUSIN)
        computeCurvature_Rusinkiewicz(0);
      else if (typ == RBF)
        computeCurvature_RBF();
      else if (typ == SIMPLE)
        computeCurvature_Simple();
    
      double t1 = Cpu();
      Msg::StatusBar(2, true, "(C) Done Computing Curvature (%g s)", t1-t0);
    
      writeToMshFile("curvature.msh");
      writeToPosFile("curvature.pos");
      writeToVtkFile("curvature.vtk");
    
    }
    
    //========================================================================================================
    
    void Curvature::buildEdgeList()
    {
    
      int V[3];
      bool edgefound;
    
      _VertexToEdgeList.clear();
    
      std::list<MeshEdgeInfo>::iterator VertToEdgeListIter;
      MeshEdgeInfo TempEdge;
    
      _VertexToEdgeList.resize(_VertexToInt.size());
    
      for (int i = 0; i< _EntityArray.size(); ++i)
      {
        GFace* face = _EntityArray[i]; //List of all the discrete face on which we compute the curvature
    
        for (int iElem = 0; iElem < face->getNumMeshElements(); iElem++)
        {
          MElement *e = face->getMeshElement(iElem);
    
          // The NEW tag of the corresponding element
          const int E = _ElementToInt[e->getNum()];
    
          // Pointers to vertices of triangle
          MVertex* A = e->getVertex(0);
          MVertex* B = e->getVertex(1);
          MVertex* C = e->getVertex(2);
    
          V[0] = _VertexToInt[A->getNum()];  //The new number of the vertex
          V[1] = _VertexToInt[B->getNum()];
          V[2] = _VertexToInt[C->getNum()];
    
          // Try to add edge [V0,V1] to the global list
          for (int j = 0; j < 3; ++j)
          {
              const int StartV = std::min(V[j], V[(j+1)%3]);
              const int EndV = std::max(V[j], V[(j+1)%3]);
    
              edgefound = false;
              for (VertToEdgeListIter = _VertexToEdgeList[StartV].begin(); VertToEdgeListIter != _VertexToEdgeList[StartV].end();
                                                                                       ++VertToEdgeListIter)
              {
                if(StartV == (*VertToEdgeListIter).StartV && EndV == (*VertToEdgeListIter).EndV)
                {
                  (*VertToEdgeListIter).NbElemNeighbour ++;
                  edgefound = true;
                }
    
              }
              if (false == edgefound)
              {
                TempEdge.StartV = StartV;
                TempEdge.EndV = EndV;
                TempEdge.NbElemNeighbour = 1;
                _VertexToEdgeList[StartV].push_back(TempEdge);
              }
    
    
          } // Loop over j
    
    
        } // Loop over the elements (triangles) of the face
      }
    
      int NbEdges = 0;
      for(int i = 0; i < _VertexToEdgeList.size(); ++i)
      {
        NbEdges += _VertexToEdgeList[i].size();
      }
    
      //std::cout << "Euler formula:" << std::endl;
      //std::cout << "Edges + 2 =        " << NbEdges + 2 << std::endl;
      //std::cout << "Elements + Nodes = " << _VertexToInt.size() + _ElementToInt.size() << std::endl;
    
    }
    
    //========================================================================================================
    
    void Curvature::smoothCurvatureField(const int NbIter)
    {
      if ( _VertexToEdgeList.size() == 0 ) { buildEdgeList(); }
    
      std::vector<double> smoothedCurvature;
      smoothedCurvature.resize( _VertexToInt.size() );
    
      _NbNeighbour.resize(_VertexToInt.size());
      for(int i = 0; i < _VertexToInt.size(); ++i)
      {
        _NbNeighbour[i] = 0;
      }
    
    
      // Smoothing iterations
      for(int iter = 0; iter < NbIter; ++iter)
      {
    
        for(int i = 0; i < smoothedCurvature.size(); ++i)
        {
          smoothedCurvature[i] = 0.0;
        }
    
        std::list<MeshEdgeInfo>::const_iterator edgeIterator;
    
    
        for(int i = 0; i < _VertexToEdgeList.size(); ++i)
        {
          for(edgeIterator = _VertexToEdgeList[i].begin(); edgeIterator != _VertexToEdgeList[i].end(); ++edgeIterator)
          {
            const int N0 = (*edgeIterator).StartV;
            const int N1 = (*edgeIterator).EndV;
    
            const int V0 = _VertexToInt[N0];
            const int V1 = _VertexToInt[N1];
    
            smoothedCurvature[V0] += _VertexCurve[V1];
            smoothedCurvature[V1] += _VertexCurve[V0];
            _NbNeighbour[V0]++;
            _NbNeighbour[V1]++;
          }
        }
    
    
    
        const double Lambda = 0.3;
        for(int i = 0; i < _VertexCurve.size(); ++i)
        {
          _VertexCurve[i] = Lambda*_VertexCurve[i] + (1-Lambda)*smoothedCurvature[i] / _NbNeighbour[i];
        }
      }
    
    }
    
    //========================================================================================================
    
    
    
    void Curvature::computeCurvature_Rusinkiewicz(int isMax)
    {
      retrieveCompounds();
      initializeMap();
    
      computeRusinkiewiczNormals();
      computePointareas();
    
      SVector3 e[3];
      STensor3 w;
      SVector3 t;
      SVector3 n;
      SVector3 b;
      SVector3 m;
      SVector3 dn;
    
      double u;
      double v;
      double dnu;
      double dnv;
      double c1;
      double c2;
      double c12;
      double wt;
    
      _pdir1.resize(_VertexToInt.size());
      _pdir2.resize(_VertexToInt.size());
    
      _curv1.resize(_VertexToInt.size());
      _curv2.resize(_VertexToInt.size());
      _curv12.resize(_VertexToInt.size());
    
      for (int i = 0; i< _EntityArray.size(); ++i)
      {
        GFace* face = _EntityArray[i]; //face is a pointer to one surface of the group "FinalEntityList"
    
        for (int iElem = 0; iElem < face->getNumMeshElements(); iElem++) //Loop over the element all the element of the "myTag"-surface
        {
          MElement *E = face->getMeshElement(iElem);  //Pointer to one element
    
          MVertex* A = E->getVertex(0);  //Pointers to vertices of triangle
          MVertex* B = E->getVertex(1);
          MVertex* C = E->getVertex(2);
    
          const int V0 = _VertexToInt[A->getNum()];  //Tag of the 1st vertex of the triangle
          const int V1 = _VertexToInt[B->getNum()];
          const int V2 = _VertexToInt[C->getNum()];
    
          ///Set up an initial coordinate system per vertex:
    
          _pdir1[V0] = SVector3(B->x() - A->x(), B->y() - A->y(), B->z() - A->z());
          _pdir1[V1] = SVector3(C->x() - B->x(), C->y() - B->y(), C->z() - B->z());
          _pdir1[V2] = SVector3(A->x() - C->x(), A->y() - C->y(), A->z() - C->z());
        }
      }
    
      for (int ivertex = 0; ivertex < _VertexToInt.size(); ++ivertex)
      {
        _pdir1[ivertex] = crossprod(_pdir1[ivertex], _VertexNormal[ivertex]);
        _pdir1[ivertex].normalize();
        _pdir2[ivertex] = crossprod(_VertexNormal[ivertex], _pdir1[ivertex]);
      }
    
      // Compute curvature per face:
      for (int i = 0; i< _EntityArray.size(); ++i)
      {
        //face is a pointer to one surface of the group "FinalEntityList"
        GFace* face = _EntityArray[i];
    
        //Loop over all elements of this face:
        for (int iElem = 0; iElem < face->getNumMeshElements(); iElem++)
        {
          MElement *E = face->getMeshElement(iElem);  //Pointer to one element
          // The NEW tag of the corresponding element
          const int EIdx = _ElementToInt[E->getNum()];
    
          MVertex* A = E->getVertex(0);  //Pointers to vertices of triangle
          MVertex* B = E->getVertex(1);
          MVertex* C = E->getVertex(2);
    
          e[0] = SVector3(C->x() - B->x(), C->y() - B->y(), C->z() - B->z());
          e[1] = SVector3(A->x() - C->x(), A->y() - C->y(), A->z() - C->z());
          e[2] = SVector3(B->x() - A->x(), B->y() - A->y(), B->z() - A->z());
    
          //SVector3 e[3] = {SVector3(C->x() - B->x(), C->y() - B->y(), C->z() - B->z()), SVector3(A->x() - C->x(), A->y() - C->y(), A->z() - C->z()), SVector3(B->x() - A->x(), B->y() - A->y(), B->z() - A->z()) };
    
          //N-T-B coordinate system per face
          t = e[0];
          t.normalize();
          n = crossprod( e[0], e[1]);
          b = crossprod(n, t);
          b.normalize();
    
          //Estimate curvature based on variations of normals along edges:
          //intialization:
          m = SVector3(0.0, 0.0, 0.0);
          //maybe double m[3] = { 0.0, 0.0, 0.0 };
          // w *= 0.0; //Reset w to zero
          for (int i  = 0; i< 3; ++i)
          {
            for (int j = 0; j<3; ++j)
            {
              w(i,j) = 0.0;
            }
          }
    
          //filling:
          for (int j = 0; j< 3; ++j)
          {
            u = dot(e[j], t);
            v = dot(e[j], b);
    
            w(0,0) += u*u;
            w(0,1) += u*v;
            w(2,2) += v*v;
    
            MVertex* U = E->getVertex(PREV(j));
            MVertex* V = E->getVertex(NEXT(j));
    
            const int UIdx = _VertexToInt[U->getNum()];
            const int VIdx = _VertexToInt[V->getNum()];
    
            dn = _VertexNormal[UIdx] - _VertexNormal[VIdx];
    
            dnu = dot(dn, t);
            dnv = dot(dn, b);
    
            m[0] += dnu*u;
            m[1] += dnu*v + dnv*u;
            m[2] += dnv*v;
          }
    
          w(1,1) = w(0,0) + w(2,2);
          w(1,2) = w(0,1);
    
          //Least Squares Solution
          double diag[3];
          if (!ldltdc(w, diag))
          {
            std::cout << "ldltdc failed" << std::endl;
            continue;
          }
          ldltsl(w, diag, m, m);
    
          //Push it back out to the vertices
          for (int j = 0; j< 3; ++j)
          {
            const int old_vj = E->getVertex(j)->getNum();
            const int vj = _VertexToInt[old_vj];
            proj_curv(t, b, m[0], m[1], m[2], _pdir1[vj], _pdir2[vj], c1, c12, c2);
            wt = _cornerareas[EIdx][j]/_pointareas[vj];
    //          wt = 1.0;
    //        if (_isOnBoundary[vj])
    //        {
    //            wt = 2.0*wt;
    //        }
    
            _curv1[vj]  += wt*c1;
            _curv12[vj] += wt*c12;
            _curv2[vj]  += wt*c2;
          }
    
        } //End of loop over the element (iElem)
    
      } //End of loop over "_EntityArray"
    
    
      //Compute principal directions and curvatures at each vertex
      for (int ivertex = 0; ivertex < _VertexToInt.size(); ++ivertex)  {
        diagonalize_curv(_pdir1[ivertex], _pdir2[ivertex], _curv1[ivertex], _curv12[ivertex], _curv2[ivertex],
                         _VertexNormal[ivertex], _pdir1[ivertex], _pdir2[ivertex], _curv1[ivertex], _curv2[ivertex]);
      }
    
      _VertexCurve.resize( _VertexToInt.size() );
    
      for (int ivertex = 0; ivertex < _VertexToInt.size(); ++ivertex){
    
        if (isMax){
          _VertexCurve[ivertex] = std::max(fabs(_curv1[ivertex]), fabs(_curv2[ivertex]));
        }
        else{
        //  _VertexCurve[ivertex] = (_curv1[ivertex]+_curv2[ivertex])*0.5; //Mean curvature
        //_VertexCurve[ivertex] = std::abs(_curv1[ivertex]) + std::abs(_curv2[ivertex]);
        _VertexCurve[ivertex] = _curv1[ivertex]*_curv2[ivertex]; //Gaussian
        //_VertexCurve[ivertex] = std::abs(_VertexCurve[ivertex]);
        }
    
      }
    
    //   smoothCurvatureField(1);
      _alreadyComputedCurvature = true;
    
    // Propagate the value of curvature from nodes close the edges of the geometry onto the edges
      correctOnEdges();
    
    } //End of the "computeCurvature_Rusinkiewicz" method
    
     //========================================================================================================
    
    void Curvature::computeCurvature_RBF()
    {
      retrieveCompounds();
      initializeMap();
      
      //fill set of MVertex
      std::set<MVertex*> allNodes;
      for (int i = 0; i< _EntityArray.size(); ++i)  {
        GFaceCompound* face = (GFaceCompound*)_EntityArray[i];
        for (unsigned iElem = 0; iElem < face->getNumMeshElements(); iElem++) {
          MElement *e = face->getMeshElement(iElem);
          for(int j = 0; j < e->getNumVertices(); j++){
            allNodes.insert(e->getVertex(j));
          }
        }
      }
    
      //bounding box
      SBoundingBox3d bb;
      std::vector<SPoint3> vertices;
      for(std::set<MVertex *>::iterator itv = allNodes.begin(); itv !=allNodes.end() ; ++itv){
        SPoint3 pt((*itv)->x(),(*itv)->y(), (*itv)->z());
        vertices.push_back(pt);
        bb +=pt;
      }
      double sizeBox = norm(SVector3(bb.max(), bb.min()));
    
      //compure curvature RBF
      std::map<MVertex*, SVector3> _normals;
      std::vector<MVertex*> _ordered;
      std::map<MVertex*, double> curvRBF;
      //GLOBAL
      GRbf *_rbf = new GRbf(sizeBox, 0, 1, _normals, allNodes, _ordered); 
      _rbf->computeCurvature(_rbf->getXYZ(),curvRBF);
      //LOCAL FD
      //GRbf *_rbf = new GRbf(sizeBox, 0, 1, _normals, allNodes, _ordered, true); 
      //_rbf->computeLocalCurvature(_rbf->getXYZ(),curvRBF);
    
      //fill vertex curve
      _VertexCurve.resize( _VertexToInt.size() );
      for(std::set<MVertex *>::iterator itv = allNodes.begin(); itv !=allNodes.end() ; ++itv){
        MVertex *v = *itv;
        std::map<int,int>::iterator vertexIterator;
        int V0;
        vertexIterator = _VertexToInt.find( v->getNum() );
        if ( vertexIterator != _VertexToInt.end() )  V0 = (*vertexIterator).second;
        _VertexCurve[V0] = curvRBF[v];
       }
    
     _alreadyComputedCurvature = true;
    
    } //End of the "computeCurvature_RBF" method
    
    
     //========================================================================================================
    
    void Curvature::triangleNodalValues(MTriangle* triangle, double& c0, double& c1, double& c2, int isAbs)
      {
        MVertex* A = triangle->getVertex(0);
        MVertex* B = triangle->getVertex(1);
        MVertex* C = triangle->getVertex(2);
    
        int V0 = 0;
        int V1 = 0;
        int V2 = 0;
    
        std::map<int,int>::iterator vertexIterator;
        vertexIterator = _VertexToInt.find( A->getNum() );
        if ( vertexIterator != _VertexToInt.end() )  V0 = (*vertexIterator).second;
        else
          std::cout << "Didn't find vertex with number " << A->getNum() << " in _VertextToInt !" << std::endl;
        
        vertexIterator = _VertexToInt.find( B->getNum() );
        if ( vertexIterator != _VertexToInt.end() )   V1 = (*vertexIterator).second;
        else
          std::cout << "Didn't find vertex with number " << B->getNum() << " in _VertextToInt !" << std::endl;
        
        vertexIterator = _VertexToInt.find( C->getNum() );
        if ( vertexIterator != _VertexToInt.end() )  V2 = (*vertexIterator).second;
        else
          std::cout << "Didn't find vertex with number " << C->getNum() << " in _VertextToInt !" << std::endl;
        
        if (isAbs){
          c0 = std::abs(_VertexCurve[V0]); //Mean curvature in vertex 0
          c1 = std::abs(_VertexCurve[V1]); //Mean curvature in vertex 1
          c2 = std::abs(_VertexCurve[V2]); //Mean curvature in vertex 2
        }
        else{
          c0 = _VertexCurve[V0]; //Mean curvature in vertex 0
          c1 = _VertexCurve[V1]; //Mean curvature in vertex 1
          c2 = _VertexCurve[V2]; //Mean curvature in vertex 2
        }
    
      }
    
    //========================================================================================================
    
    void Curvature::triangleNodalValuesAndDirections(MTriangle* triangle, SVector3* dMax, SVector3* dMin, double* cMax, double* cMin, int isAbs)
    {
      MVertex* A = triangle->getVertex(0);
      MVertex* B = triangle->getVertex(1);
      MVertex* C = triangle->getVertex(2);
    
      int V0 = 0;
      int V1 = 0;
      int V2 = 0;
    
      std::map<int,int>::iterator vertexIterator;
      vertexIterator = _VertexToInt.find( A->getNum() );
      if ( vertexIterator != _VertexToInt.end() )  V0 = (*vertexIterator).second;
      else
        std::cout << "Didn't find vertex with number " << A->getNum() << " in _VertextToInt !" << std::endl;
    
      vertexIterator = _VertexToInt.find( B->getNum() );
      if ( vertexIterator != _VertexToInt.end() )  V1 = (*vertexIterator).second;
      else
        std::cout << "Didn't find vertex with number " << B->getNum() << " in _VertextToInt !" << std::endl;
    
      vertexIterator = _VertexToInt.find( C->getNum() );
      if ( vertexIterator != _VertexToInt.end() )  V2 = (*vertexIterator).second;
      else
        std::cout << "Didn't find vertex with number " << C->getNum() << " in _VertextToInt !" << std::endl;
    
      if (isAbs){
        dMax[0] = _pdir1[V0];
        dMax[1] = _pdir1[V1];
        dMax[2] = _pdir1[V2];
    
        dMin[0] = _pdir2[V0];
        dMin[1] = _pdir2[V1];
        dMin[2] = _pdir2[V2];
    
        cMax[0]  = std::abs(_curv1[V0]);
        cMax[1]  = std::abs(_curv1[V1]);
        cMax[2]  = std::abs(_curv1[V2]);
    
        cMin[0]  = std::abs(_curv2[V0]);
        cMin[1]  = std::abs(_curv2[V1]);
        cMin[2]  = std::abs(_curv2[V2]);
    
      }
      else{
    
        dMax[0] = _pdir1[V0];
        dMax[1] = _pdir1[V1];
        dMax[2] = _pdir1[V2];
    
        dMin[0] = _pdir2[V0];
        dMin[1] = _pdir2[V1];
        dMin[2] = _pdir2[V2];
    
        cMax[0]  = _curv1[V0];
        cMax[1]  = _curv1[V1];
        cMax[2]  = _curv1[V2];
    
        cMin[0]  = _curv2[V0];
        cMin[1]  = _curv2[V1];
        cMin[2]  = _curv2[V2];
      }
    }
    
    
    
      //========================================================================================================
    
    void Curvature::edgeNodalValues(MLine* edge, double& c0, double& c1, int isAbs)
       {
         MVertex* A = edge->getVertex(0);
         MVertex* B = edge->getVertex(1);
    
         int V0 = 0;
         int V1 = 0;
    
         std::map<int,int>::iterator vertexIterator;
    
         vertexIterator = _VertexToInt.find( A->getNum() );
         if ( vertexIterator != _VertexToInt.end() )  V0 = (*vertexIterator).second;
         else  std::cout << "Didn't find vertex with number " << A->getNum() << " in _VertextToInt !" << std::endl;
         
         vertexIterator = _VertexToInt.find( B->getNum() );
         if ( vertexIterator != _VertexToInt.end() ) V1 = (*vertexIterator).second;
         else std::cout << "Didn't find vertex with number " << B->getNum() << " in _VertextToInt !" << std::endl;
         
         if (isAbs){
           c0 = std::abs(_VertexCurve[V0]); //Mean curvature in vertex 0
           c1 = std::abs(_VertexCurve[V1]); //Mean curvature in vertex 1
         }
         else{
           c0 = _VertexCurve[V0]; //Mean curvature in vertex 0
           c1 = _VertexCurve[V1]; //Mean curvature in vertex 1
         }
    
       }
    
    //========================================================================================================
    
    double Curvature::getAtVertex(const MVertex *v) const {
      std::map<int,int>::const_iterator it = _VertexToInt.find(v->getNum());
      if (it == _VertexToInt.end()) {
        Msg::Error("curvature has not been computed for vertex %i (%i)", v->getNum(), _VertexToInt.size());
        return 1;
      }
      return _VertexCurve[it->second];
    }
    
    //========================================================================================================
    
    void Curvature::writeToMshFile(const std::string &filename)
    {
      std::ofstream outfile;
      outfile.precision(18);
      outfile.open(filename.c_str());
    
      /// Write the values of curvature
      outfile << "$MeshFormat"    << std::endl;
      outfile << "2.1 0 8"        << std::endl;
      outfile << "$EndMeshFormat" << std::endl;
      outfile << "$NodeData" << std::endl;
      outfile << "1" << std::endl;                 // One string tag
      outfile << "\"Curvature\"" << std::endl;     // The name of the view
      outfile << "1"             << std::endl;     // One real tag
      outfile << "0.0"           << std::endl;     // The time value
      outfile << "3"             << std::endl;     // Three integer tags
      outfile << "0"             << std::endl;     // The time step (time steps always start at 0)
      outfile << "1"             << std::endl;     // 1-component (scalar) field
      outfile << _VertexToInt.size() << std::endl; // How many associated nodal values
    
      std::map<int,int>::const_iterator vertex_iterator;
      for(vertex_iterator = _VertexToInt.begin(); vertex_iterator != _VertexToInt.end(); ++vertex_iterator)
      {
        outfile << vertex_iterator->first << " " << _VertexCurve[vertex_iterator->second] << std::endl;
      }
    
      outfile << "$EndNodeData" << std::endl;
    
    
      /// Write the values of characteristic length
    
      double lc;
    
      outfile << "$MeshFormat"    << std::endl;
      outfile << "2.1 0 8"        << std::endl;
      outfile << "$EndMeshFormat" << std::endl;
      outfile << "$NodeData" << std::endl;
      outfile << "1" << std::endl;                 // One string tag
      outfile << "\"Characteristic mesh length\"" << std::endl;     // The name of the view
      outfile << "1"             << std::endl;     // One real tag
      outfile << "0.0"           << std::endl;     // The time value
      outfile << "3"             << std::endl;     // Three integer tags
      outfile << "0"             << std::endl;     // The time step (time steps always start at 0)
      outfile << "1"             << std::endl;     // 1-component (scalar) field
      outfile << _VertexToInt.size() << std::endl; // How many associated nodal values
    
      for(vertex_iterator = _VertexToInt.begin(); vertex_iterator != _VertexToInt.end(); ++vertex_iterator)
      {
        lc = 2.0*M_PI/( fabs(_VertexCurve[vertex_iterator->second]) * CTX::instance()->mesh.minCircPoints );
        lc = std::max(lc, CTX::instance()->mesh.lcMin);
        lc = std::min(lc, CTX::instance()->mesh.lcMax);
        outfile << vertex_iterator->first << " " << 1.0/(lc*lc) << std::endl;
      }
    
      outfile << "$EndNodeData" << std::endl;
    
      /// Write the values of curvature direction - principal direction 1
      outfile << "$NodeData" << std::endl;
      outfile << "1" << std::endl;                 // One string tag
      outfile << "\"Principal curvature direction 1\"" << std::endl;     // The name of the view
      outfile << "1"             << std::endl;     // One real tag
      outfile << "0.0"           << std::endl;     // The time value
      outfile << "3"             << std::endl;     // Three integer tags
      outfile << "0"             << std::endl;     // The time step (time steps always start at 0)
      outfile << "3"             << std::endl;     // 3-component (vector) field
      outfile << _VertexToInt.size() << std::endl; // How many associated nodal values
    
      for(vertex_iterator = _VertexToInt.begin(); vertex_iterator != _VertexToInt.end(); ++vertex_iterator)
      {
        outfile << vertex_iterator->first << " " << _pdir1[vertex_iterator->second].x() << " "
                                                 << _pdir1[vertex_iterator->second].y() << " "
                                                 << _pdir1[vertex_iterator->second].z() << std::endl;
      }
    
      outfile << "$EndNodeData" << std::endl;
    
    
      /// Write the values of curvature direction - principal direction 1
      outfile << "$NodeData" << std::endl;
      outfile << "1" << std::endl;                 // One string tag
      outfile << "\"Principal curvature direction 2\"" << std::endl;     // The name of the view
      outfile << "1"             << std::endl;     // One real tag
      outfile << "0.0"           << std::endl;     // The time value
      outfile << "3"             << std::endl;     // Three integer tags
      outfile << "0"             << std::endl;     // The time step (time steps always start at 0)
      outfile << "3"             << std::endl;     // 3-component (vector) field
      outfile << _VertexToInt.size() << std::endl; // How many associated nodal values
    
      for(vertex_iterator = _VertexToInt.begin(); vertex_iterator != _VertexToInt.end(); ++vertex_iterator)
      {
        outfile << vertex_iterator->first << " " << _pdir2[vertex_iterator->second].x() << " "
                                                 << _pdir2[vertex_iterator->second].y() << " "
                                                 << _pdir2[vertex_iterator->second].z() << std::endl;
      }
    
      outfile << "$EndNodeData" << std::endl;
    
      outfile.close();
    
    
    }
    
    //========================================================================================================
    
    void Curvature::writeToPosFile( const std::string & filename)
    {
      std::ofstream outfile;
      outfile.precision(18);
      outfile.open(filename.c_str());
      outfile << "View \"Curvature \"{" << std::endl;
    
      int idxelem = 0;
    
      for (int i = 0; i< _EntityArray.size(); ++i) {
        GFace* face = _EntityArray[i];
    
        for (unsigned iElem = 0; iElem < face->getNumMeshElements(); iElem++){
          MElement *e = face->getMeshElement(iElem);  
          const int E = _ElementToInt[e->getNum()]; 
          //std::cout << "We are now looking at element Nr: " << E << std::endl;
    
          MVertex* A = e->getVertex(0);  //Pointers to vertices of triangle
          MVertex* B = e->getVertex(1);
          MVertex* C = e->getVertex(2);
    
          const int V1 = _VertexToInt[A->getNum()];                //Tag of the 1st vertex of the triangle
          const int V2 = _VertexToInt[B->getNum()];                //Tag of the 2nd vertex of the triangle
          const int V3 = _VertexToInt[C->getNum()];                //Tag of the 3rd vertex of the triangle
    
          //Here is printing the triplet X-Y-Z of each vertex:
          //*************************************************
    
          outfile << "ST("; //VT = vector triangles   //ST = scalar triangle
          outfile << A->x() << ","<< A->y() << "," << A->z()<< ",";
          outfile << B->x() << ","<< B->y() << "," << B->z()<< ",";
          outfile << C->x() << ","<< C->y() << "," << C->z();
    
          outfile << ")";
          outfile <<"{";
    
          //Here is printing the 3 components of the normal vector for each vertex:
          //**********************************************************************
    
    //      outfile << _VertexNormal[V1].x() << ","<< _VertexNormal[V1].y() << ","<< _VertexNormal[V1].z() << ",";
    //      outfile << _VertexNormal[V2].x() << ","<< _VertexNormal[V2].y() << ","<< _VertexNormal[V2].z() << ",";
    //      outfile << _VertexNormal[V3].x() << ","<< _VertexNormal[V3].y() << ","<< _VertexNormal[V3].z();
    
          outfile << _VertexCurve[V1] << "," << _VertexCurve[V2] << "," << _VertexCurve[V3];
    
          outfile << "};" << std::endl;
    
          idxelem++;
    
      } //Loop over elements
     
    } // Loop over ptFinalEntityList
    
    outfile << "};" << std::endl;
    
    outfile.close();
    }
    
    //========================================================================================================
    
    void Curvature::writeToVtkFile( const std::string & filename)
    {
    
      std::ofstream outfile;
      outfile.precision(18);
      outfile.open(filename.c_str());
      outfile << "# vtk DataFile Version 2.0" << std::endl;
      outfile << "Surface curvature computed by Gmsh" << std::endl;
      outfile << "ASCII" << std::endl;
      outfile << "DATASET UNSTRUCTURED_GRID" << std::endl;
    
      const int npoints = _VertexToInt.size();
    
      outfile << "POINTS " << npoints << " double" << std::endl;
    
      /// Build a table of coordinates
      /// Loop over all elements and look at the 'old' (not necessarily continuous) numbers of vertices
      /// Get the 'new' index of each vertex through _VertexToInt and the [x,y,z] coordinates of this vertex
      /// Store them in coordx,coordy and coordz
    
    
      std::vector<VtkPoint> coord;
    
      coord.resize(npoints);
    
      for (int i = 0; i< _EntityArray.size(); ++i)
      {
        GFace* face = _EntityArray[i];
    
        for (int iElem = 0; iElem < face->getNumMeshElements(); iElem++)
        {
          MElement *e = face->getMeshElement(iElem);
    
          MVertex* A = e->getVertex(0);  //Pointers to vertices of triangle
          MVertex* B = e->getVertex(1);
          MVertex* C = e->getVertex(2);
    
          const int oldIdxA = A->getNum();
          const int oldIdxB = B->getNum();
          const int oldIdxC = C->getNum();
    
          const int newIdxA = _VertexToInt[oldIdxA];
          const int newIdxB = _VertexToInt[oldIdxB];
          const int newIdxC = _VertexToInt[oldIdxC];
    
          coord[newIdxA].x = A->x();
          coord[newIdxA].y = A->y();
          coord[newIdxA].z = A->z();
    
          coord[newIdxB].x = B->x();
          coord[newIdxB].y = B->y();
          coord[newIdxB].z = B->z();
    
          coord[newIdxC].x = C->x();
          coord[newIdxC].y = C->y();
          coord[newIdxC].z = C->z();
        }
      }
    
      for (int v = 0; v < npoints; ++v)
      {
        outfile << coord[v].x << " " << coord[v].y << " " << coord[v].z << std::endl;
      }
    
      /// Empty the array 'coord' to free the memory
      /// Point coordinates will not be needed anymore
      coord.clear();
    
      /// Write the cell connectivity
    
      outfile << std::endl << "CELLS " << _ElementToInt.size() << " " << 4*_ElementToInt.size() << std::endl;
    
      for (int i = 0; i< _EntityArray.size(); ++i)
      {
        GFace* face = _EntityArray[i];
    
        for (int iElem = 0; iElem < face->getNumMeshElements(); iElem++)
        {
          MElement *e = face->getMeshElement(iElem);
    
          MVertex* A = e->getVertex(0);  //Pointers to vertices of triangle
          MVertex* B = e->getVertex(1);
          MVertex* C = e->getVertex(2);
    
          const int oldIdxA = A->getNum();
          const int oldIdxB = B->getNum();
          const int oldIdxC = C->getNum();
    
          const int newIdxA = _VertexToInt[oldIdxA];
          const int newIdxB = _VertexToInt[oldIdxB];
          const int newIdxC = _VertexToInt[oldIdxC];
    
          outfile << "3 " << newIdxA << " " << newIdxB << " " << newIdxC << std::endl;
        }
      }
    
      outfile << std::endl << "CELL_TYPES " << _ElementToInt.size() << std::endl;
      for(int ie = 0; ie < _ElementToInt.size(); ++ie)
      {
        outfile << "5" << std::endl; //Triangle is element type 5 in vtk
    
      }
    
      /// Write the curvature values as vtk 'point data'
    
      outfile << std::endl << "POINT_DATA " << npoints << std::endl;
      outfile << "SCALARS Curvature float 1" << std::endl;
      outfile << "LOOKUP_TABLE default" << std::endl;
    
      for (int iv = 0; iv < npoints; ++iv)
      {
        outfile << _VertexCurve[iv] << std::endl;
      }
    
      outfile << "SCALARS CharacteristicMeshLength float 1" << std::endl;
      outfile << "LOOKUP_TABLE default" << std::endl;
    
      double lc;
    
      for (int iv = 0; iv < npoints; ++iv)
      {
        lc = 2.0*M_PI / ( fabs(_VertexCurve[iv]) * CTX::instance()->mesh.minCircPoints );
        lc = std::max(lc, CTX::instance()->mesh.lcMin);
        lc = std::min(lc, CTX::instance()->mesh.lcMax);
        outfile << 1.0/(lc*lc) << std::endl;
      }
    
      outfile << "VECTORS CurvatureDir1 float" << std::endl;
      for (int iv = 0; iv < npoints; ++iv)
      {
        outfile << _pdir1[iv].x() << " " << _pdir1[iv].y() << " " << _pdir1[iv].z() << std::endl;
      }
    
      outfile << "VECTORS CurvatureDir2 float" << std::endl;
      for (int iv = 0; iv < npoints; ++iv)
      {
        outfile << _pdir2[iv].x() << " " << _pdir2[iv].y() << " " << _pdir2[iv].z() << std::endl;
      }
    
      outfile.close();
    
    }
    
    //========================================================================================================
    
    void Curvature::writeDirectionsToPosFile( const std::string & filename)
    {
      std::ofstream outfile;
      outfile.precision(18);
      outfile.open(filename.c_str());
      outfile << "View \"Curvature_DirMax \"{" << std::endl;
    
      for (int i = 0; i< _EntityArray.size(); ++i)
      {
        GFace* face = _EntityArray[i]; //face is a pointer to one surface of the group "FinalEntityList"
    
        for (int iElem = 0; iElem < face->getNumMeshElements(); iElem++) //Loop over the element all the element of the "myTag"-surface
        {
          MElement *e = face->getMeshElement(iElem);  //Pointer to one element
          const int E = _ElementToInt[e->getNum()]; //The NEW tag of the corresponding element
    
          //std::cout << "We are now looking at element Nr: " << E << std::endl;
    
          MVertex* A = e->getVertex(0);  //Pointers to vertices of triangle
          MVertex* B = e->getVertex(1);
          MVertex* C = e->getVertex(2);
    
          const int V1 = _VertexToInt[A->getNum()];                //Tag of the 1st vertex of the triangle
          const int V2 = _VertexToInt[B->getNum()];                //Tag of the 2nd vertex of the triangle
          const int V3 = _VertexToInt[C->getNum()];                //Tag of the 3rd vertex of the triangle
    
          //Here is printing the triplet X-Y-Z of each vertex:
          //*************************************************
    
          outfile << "VT("; //VT = vector triangles   //ST = scalar triangle
          outfile << A->x() << ","<< A->y() << "," << A->z()<< ",";
          outfile << B->x() << ","<< B->y() << "," << B->z()<< ",";
          outfile << C->x() << ","<< C->y() << "," << C->z();
    
          outfile << ")";
          outfile <<"{";
    
          //Here is printing the 3 components of the curvature max direction for each vertex:
          //*********************************************************************************
    
             outfile << _pdir1[V1].x() << ","<< _pdir1[V1].y() << ","<< _pdir1[V1].z() << ",";
             outfile << _pdir1[V2].x() << ","<< _pdir1[V2].y() << ","<< _pdir1[V2].z() << ",";
             outfile << _pdir1[V3].x() << ","<< _pdir1[V3].y() << ","<< _pdir1[V3].z();
    
    
          outfile << "};" << std::endl;
    
      } //Loop over elements
    
    } // Loop over ptFinalEntityList
    
    outfile << "};" << std::endl;
    
    
    //----------------------------------------------------------------------------------------------
    
    outfile << "View \"Curvature_DirMin \"{" << std::endl;
    
    for (int i = 0; i< _EntityArray.size(); ++i)
    {
      GFace* face = _EntityArray[i]; //face is a pointer to one surface of the group "FinalEntityList"
    
      for (int iElem = 0; iElem < face->getNumMeshElements(); iElem++) //Loop over the element all the element of the "myTag"-surface
      {
        MElement *e = face->getMeshElement(iElem);  //Pointer to one element
        const int E = _ElementToInt[e->getNum()]; //The NEW tag of the corresponding element
    
        //std::cout << "We are now looking at element Nr: " << E << std::endl;
    
        MVertex* A = e->getVertex(0);  //Pointers to vertices of triangle
        MVertex* B = e->getVertex(1);
        MVertex* C = e->getVertex(2);
    
        const int V1 = _VertexToInt[A->getNum()];                //Tag of the 1st vertex of the triangle
        const int V2 = _VertexToInt[B->getNum()];                //Tag of the 2nd vertex of the triangle
        const int V3 = _VertexToInt[C->getNum()];                //Tag of the 3rd vertex of the triangle
    
        //Here is printing the triplet X-Y-Z of each vertex:
        //*************************************************
    
        outfile << "VT("; //VT = vector triangles   //ST = scalar triangle
        outfile << A->x() << ","<< A->y() << "," << A->z()<< ",";
        outfile << B->x() << ","<< B->y() << "," << B->z()<< ",";
        outfile << C->x() << ","<< C->y() << "," << C->z();
    
        outfile << ")";
        outfile <<"{";
    
        //Here is printing the 3 components of the curvature min direction for each vertex:
        //*********************************************************************************
    
           outfile << _pdir2[V1].x() << ","<< _pdir2[V1].y() << ","<< _pdir2[V1].z() << ",";
           outfile << _pdir2[V2].x() << ","<< _pdir2[V2].y() << ","<< _pdir2[V2].z() << ",";
           outfile << _pdir2[V3].x() << ","<< _pdir2[V3].y() << ","<< _pdir2[V3].z();
    
    
        outfile << "};" << std::endl;
    
    } //Loop over elements
    
    } // Loop over ptFinalEntityList
    
    outfile << "};" << std::endl;
    
    outfile.close();
    }
    //========================================================================================================