diff --git a/Geo/Curvature.cpp b/Geo/Curvature.cpp index 358daf5f2dacd1771c6f7b6016e49fcfe18af371..9a41dee7f44986e64c4403fef6f2e99742cd458d 100644 --- a/Geo/Curvature.cpp +++ b/Geo/Curvature.cpp @@ -3,9 +3,6 @@ // See the LICENSE.txt file for license information. Please report all // bugs and problems to <gmsh@geuz.org>. -#include <iostream> -#include <fstream> -#include <cmath> #include "Curvature.h" #include "MElement.h" #include "MTriangle.h" @@ -15,26 +12,53 @@ #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; + _instance = 0; _destroyed = true; -} +} +//======================================================================================================== void Curvature::onDeadReference() { std::cout << "Dead reference of Curvature detected" << std::endl; } +//======================================================================================================== -Curvature &Curvature::getInstance() +Curvature& Curvature::getInstance() { if (!_instance) { if(_destroyed){ @@ -46,83 +70,313 @@ Curvature &Curvature::getInstance() } return *_instance; } +//======================================================================================================== + bool Curvature::valueAlreadyComputed() + { + return _alreadyComputedCurvature; + } -bool Curvature::valueAlreadyComputed() -{ - return _alreadyComputedCurvature; -} +//======================================================================================================== -void Curvature::create() -{ - static Curvature instance; - _instance = & instance; -} + void Curvature::create() + { + static Curvature instance; + _instance = & instance; + } -void Curvature::retrieveCompounds() -{ + //======================================================================================================== + void Curvature::retrieveCompounds() { #if defined(HAVE_SOLVER) - std::vector<GEntity*> entities; - _model->getEntities(entities); - - for(unsigned ie = 0; ie < entities.size(); ++ie) { - - if(entities[ie]->geomType() == GEntity::CompoundSurface) { - GFaceCompound* compound = dynamic_cast<GFaceCompound*>(entities[ie]); - std::list<GFace*> tempcompounds = compound->getCompounds(); - std::list<GFace*>::iterator surfIterator; - for(surfIterator = tempcompounds.begin(); surfIterator != tempcompounds.end(); - ++surfIterator) { - if ((*surfIterator)->geomType() == GEntity::DiscreteSurface) { - _ptFinalEntityList.push_back(*surfIterator); - } - } - } - else if (entities[ie]->geomType() == GEntity::DiscreteSurface) { - _ptFinalEntityList.push_back(dynamic_cast<GFace*>(entities[ie])); - } - } + + /// ------------------------------------------------------------------------------------------- + // 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: -// initialization of the map and renumbering of the selected entities void Curvature::initializeMap() { - for (unsigned i = 0; i< _ptFinalEntityList.size(); ++i){ - GFace* face = _ptFinalEntityList[i]; - for (unsigned 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; + 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; + /// 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; + // 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; + + } - 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; - } -// compute the normal at the vertex and the area around +//======================================================================================================== + +//COMPUTE THE NORMAL AT THE VERTEX AND THE AREA AROUND + void Curvature::computeVertexNormals() { SVector3 vector_AB; @@ -132,12 +386,14 @@ void Curvature::computeVertexNormals() _VertexArea.resize(_ElementToInt.size() ); _VertexNormal.resize(_VertexToInt.size()); - for (unsigned i = 0; i < _ptFinalEntityList.size(); ++i){ + for (int i = 0; i< _EntityArray.size(); ++i) + { // face is a pointer to one surface of the group "FinalEntityList" - GFace* face = _ptFinalEntityList[i]; + GFace* face = _EntityArray[i]; //Loop over the element all the element of the "myTag"-surface - for (int iElem = 0; iElem < face->getNumMeshElements(); iElem++){ + for (int iElem = 0; iElem < face->getNumMeshElements(); iElem++) + { // Pointer to one element MElement *e = face->getMeshElement(iElem); // The NEW tag of the corresponding element @@ -160,15 +416,13 @@ void Curvature::computeVertexNormals() // 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; + // 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]; - // here we are actually computing the unit normal vector per vertex - _VertexNormal[V0] += cross; + _VertexNormal[V0] += cross; //here we are actually computing the unit normal vector per vertex _VertexNormal[V1] += cross; _VertexNormal[V2] += cross; @@ -176,14 +430,18 @@ void Curvature::computeVertexNormals() } //Loop over _ptFinalEntityList - // Normalize the vertex-normals. - for (unsigned int n = 0; n < _VertexToInt.size(); ++ n){ - _VertexNormal[n].normalize(); - } + ///////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; @@ -191,21 +449,23 @@ void Curvature::curvatureTensor() _CurveTensor.resize(_VertexToInt.size()); - for (unsigned i = 0; i< _ptFinalEntityList.size(); ++i){ - // face is a pointer to one surface of the group "FinalEntityList" - GFace* face = _ptFinalEntityList[i]; + for (int i = 0; i< _EntityArray.size(); ++i) + { + GFace* face = _EntityArray[i]; //face is a pointer to one surface of the group "FinalEntityList" - //Loop over the element all the element of the "myTag"-surface - for (unsigned iElem = 0; iElem < face->getNumMeshElements(); iElem++){ + 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 - // Loop over the 3 edges of each element - for (unsigned int i = 0; i<3; ++i){ - 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 + 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]); @@ -213,7 +473,7 @@ void Curvature::curvatureTensor() //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); + 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 @@ -228,9 +488,11 @@ void Curvature::curvatureTensor() TempTensor(1,1) += 1.0; TempTensor(2,2) += 1.0; - for (int m = 0; m<3; ++m){ + for (int m = 0; m<3; ++m) + { TijAB(m) = 0.0; - for (int n = 0; n<3; ++n){ + for (int n = 0; n<3; ++n) + { TijAB(m) += TempTensor(m,n) * vector_AB(n); } } @@ -246,9 +508,11 @@ void Curvature::curvatureTensor() TempTensor(1,1) += 1.0; TempTensor(2,2) += 1.0; - for (int m = 0; m<3; ++m){ + for (int m = 0; m<3; ++m) + { TijAB(m) = 0.0; - for (int n = 0; n<3; ++n){ + for (int n = 0; n<3; ++n) + { TijAB(m) += TempTensor(m,n) * vector_AB(n); } } @@ -265,6 +529,8 @@ void Curvature::curvatureTensor() }//End of method +//======================================================================================================== + void Curvature::computeCurvature_Simple() { SVector3 vector_E; @@ -281,8 +547,8 @@ void Curvature::computeCurvature_Simple() _VertexCurve.resize(_VertexToInt.size()); - //Loop over the vertex - for (unsigned int n = 0; n < _VertexToInt.size(); ++ n){ + 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]; @@ -290,10 +556,12 @@ void Curvature::computeCurvature_Simple() const double MagA = vector_A.norm(); const double MagB = vector_B.norm(); - if (MagB > MagA){ + if (MagB > MagA) + { vector_Wvi = vector_B; } - else{ + else + { vector_Wvi = vector_A; } @@ -306,12 +574,14 @@ void Curvature::computeCurvature_Simple() Qvi(2,2) += 1.0; //Transpose the matrix: - for (int i = 0; i<3; ++i){ - for (int j = 0; j<3; ++j){ + 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; @@ -322,7 +592,8 @@ void Curvature::computeCurvature_Simple() 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){ + if((B*B-4.*A*C) < 0.0) + { std::cout << "WARNING: negative discriminant: " << B*B-4.*A*C << std::endl; } @@ -335,6 +606,10 @@ void Curvature::computeCurvature_Simple() } } +//======================================================================================================== + +//COMPUTE THE NORMAL AT THE VERTEX AND THE AREA AROUND + void Curvature::computeRusinkiewiczNormals() { SVector3 vector_AB; @@ -344,12 +619,14 @@ void Curvature::computeRusinkiewiczNormals() _TriangleArea.resize(_ElementToInt.size() ); _VertexNormal.resize(_VertexToInt.size()); - for (unsigned i = 0; i< _ptFinalEntityList.size(); ++i){ + for (int i = 0; i< _EntityArray.size(); ++i) + { // face is a pointer to one surface of the group "FinalEntityList" - GFace* face = _ptFinalEntityList[i]; + GFace* face = _EntityArray[i]; //Loop over the element all the element of the "myTag"-surface - for (unsigned iElem = 0; iElem < face->getNumMeshElements(); iElem++){ + for (int iElem = 0; iElem < face->getNumMeshElements(); iElem++) + { // Pointer to one element MElement *e = face->getMeshElement(iElem); const int E = _ElementToInt[e->getNum()]; @@ -359,7 +636,7 @@ void Curvature::computeRusinkiewiczNormals() MVertex* B = e->getVertex(1); MVertex* C = e->getVertex(2); - const int V0 = _VertexToInt[A->getNum()]; //The new number of the vertex + const int V0 = _VertexToInt[A->getNum()]; //The new number of the vertex const int V1 = _VertexToInt[B->getNum()]; const int V2 = _VertexToInt[C->getNum()]; @@ -383,30 +660,32 @@ void Curvature::computeRusinkiewiczNormals() } // 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(); - } + + ///////Normalize the vertex-normals. + for (unsigned int n = 0; n < _VertexToInt.size(); ++ n) + { + _VertexNormal[n].normalize(); + } } +//======================================================================================================== // Compute per-vertex point areas -void Curvature::computePointareas() -{ +void Curvature::computePointareas(){ + SVector3 e[3]; SVector3 l2; SVector3 ew; + double factor[3]; _pointareas.resize(_VertexToInt.size()); _cornerareas.resize(_ElementToInt.size()); - for (unsigned i = 0; i< _ptFinalEntityList.size(); ++i) + for (int i = 0; i< _EntityArray.size(); ++i) { - //face is a pointer to one surface of the group "FinalEntityList" - GFace* face = _ptFinalEntityList[i]; + GFace* face = _EntityArray[i]; //face is a pointer to one surface of the group "FinalEntityList" - //Loop over the element all the element of the "myTag"-surface - for (unsigned iElem = 0; iElem < face->getNumMeshElements(); iElem++){ + 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()]; @@ -415,8 +694,30 @@ void Curvature::computePointareas() 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()); + 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()); @@ -430,57 +731,62 @@ void Curvature::computePointareas() l2[1] * (l2[2] + l2[0] - l2[1]), l2[2] * (l2[0] + l2[1] - l2[2]) ); - if (ew[0] <= 0.0){ + 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){ + 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){ + 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{ + 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]); } - const int V0 = _VertexToInt[A->getNum()]; - const int V1 = _VertexToInt[B->getNum()]; - const int V2 = _VertexToInt[C->getNum()]; - _pointareas[V0] += _cornerareas[EIdx][0]; - //_pointareas[faces[i][0]] += _cornerareas[i][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; +// 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) -{ +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 (unlikely(ndot <= -1.0f)) if (ndot <= -1.0f) { new_u = -1.0*new_u; @@ -494,14 +800,16 @@ void Curvature::rot_coord_sys(const SVector3 &old_u, const SVector3 &old_v, 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, +//======================================================================================================== + +//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) -{ + 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); @@ -516,14 +824,16 @@ void Curvature::proj_curv(const SVector3 &old_u, const SVector3 &old_v, 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 + +//======================================================================================================== + +//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) -{ + 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; @@ -533,7 +843,7 @@ void Curvature::diagonalize_curv(const SVector3 &old_u, const SVector3 &old_v, rot_coord_sys(old_u, old_v, new_norm, r_old_u, r_old_v); -// if(unlikely(kuv !=0.0f)) +// if(unlikely(kuv !=0.0f)) if(kuv !=0.0) { //Jacobi rotation to diagonalize double h= 0.5*(kv -ku)/ kuv; @@ -547,18 +857,20 @@ void Curvature::diagonalize_curv(const SVector3 &old_u, const SVector3 &old_v, k1 = ku - tt *kuv; k2 = kv + tt *kuv; - if(std::abs(k1) >= std::abs(k2)) { + if(std::abs(k1) >= std::abs(k2)) { pdir1 = c*r_old_u - s*r_old_v; } - else { + 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(); @@ -575,12 +887,153 @@ void Curvature::computeCurvature(GModel* model, typeOfCurvature typ) 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(); @@ -592,8 +1045,6 @@ void Curvature::computeCurvature_Rusinkiewicz(int isMax) SVector3 m; SVector3 dn; - int vj; - double u; double v; double dnu; @@ -610,43 +1061,46 @@ void Curvature::computeCurvature_Rusinkiewicz(int isMax) _curv2.resize(_VertexToInt.size()); _curv12.resize(_VertexToInt.size()); - for (int i = 0; i< _ptFinalEntityList.size(); ++i) + for (int i = 0; i< _EntityArray.size(); ++i) { - //face is a pointer to one surface of the group "FinalEntityList" - GFace* face = _ptFinalEntityList[i]; + GFace* face = _EntityArray[i]; //face is a pointer to one surface of the group "FinalEntityList" - //Loop over the element all the element of the "myTag"-surface - for (unsigned iElem = 0; iElem < face->getNumMeshElements(); iElem++){ - MElement *E = face->getMeshElement(iElem); // Pointer to one element + 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* 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 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: + ///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 (unsigned ivertex = 0; ivertex < _VertexToInt.size(); ++ivertex){ + 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< _ptFinalEntityList.size(); ++i){ + for (int i = 0; i< _EntityArray.size(); ++i) + { //face is a pointer to one surface of the group "FinalEntityList" - GFace* face = _ptFinalEntityList[i]; + GFace* face = _EntityArray[i]; //Loop over all elements of this face: - for (int iElem = 0; iElem < face->getNumMeshElements(); iElem++){ + 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()]; @@ -659,31 +1113,31 @@ void Curvature::computeCurvature_Rusinkiewicz(int isMax) 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()) }; + //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 + //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: + //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){ + 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){ + for (int j = 0; j< 3; ++j) + { u = dot(e[j], t); v = dot(e[j], b); @@ -710,21 +1164,27 @@ void Curvature::computeCurvature_Rusinkiewicz(int isMax) w(1,1) = w(0,0) + w(2,2); w(1,2) = w(0,1); - // Least Squares Solution + //Least Squares Solution double diag[3]; - if (!ldltdc(w, diag)){ + 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){ + //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; +// wt = 1.0; +// if (_isOnBoundary[vj]) +// { +// wt = 2.0*wt; +// } _curv1[vj] += wt*c1; _curv12[vj] += wt*c12; @@ -733,19 +1193,19 @@ void Curvature::computeCurvature_Rusinkiewicz(int isMax) } //End of loop over the element (iElem) - } //End of loop over "_ptFinalEntityList" + } //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]); + 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()); + + _VertexCurve.resize( _VertexToInt.size() ); for (int ivertex = 0; ivertex < _VertexToInt.size(); ++ivertex){ + if (isMax){ _VertexCurve[ivertex] = std::max(fabs(_curv1[ivertex]), fabs(_curv2[ivertex])); } @@ -757,19 +1217,26 @@ void Curvature::computeCurvature_Rusinkiewicz(int isMax) } } + +// 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 + //fill set of MVertex std::set<MVertex*> allNodes; - for (unsigned i = 0; i< _ptFinalEntityList.size(); ++i) { - GFaceCompound* face = (GFaceCompound*)_ptFinalEntityList[i]; + 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++){ @@ -778,7 +1245,7 @@ void Curvature::computeCurvature_RBF() } } - // bounding box + //bounding box SBoundingBox3d bb; std::vector<SPoint3> vertices; for(std::set<MVertex *>::iterator itv = allNodes.begin(); itv !=allNodes.end() ; ++itv){ @@ -788,18 +1255,18 @@ void Curvature::computeCurvature_RBF() } double sizeBox = norm(SVector3(bb.max(), bb.min())); - // compure curvature RBF + //compure curvature RBF std::map<MVertex*, SVector3> _normals; std::vector<MVertex*> _ordered; std::map<MVertex*, double> curvRBF; - // GLOBAL + //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); + //LOCAL FD + //GRbf *_rbf = new GRbf(sizeBox, 0, 1, _normals, allNodes, _ordered, true); + //_rbf->computeLocalCurvature(_rbf->getXYZ(),curvRBF); - // fill vertex curve + //fill vertex curve _VertexCurve.resize( _VertexToInt.size() ); for(std::set<MVertex *>::iterator itv = allNodes.begin(); itv !=allNodes.end() ; ++itv){ MVertex *v = *itv; @@ -808,58 +1275,57 @@ void Curvature::computeCurvature_RBF() 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::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) +//======================================================================================================== + +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); @@ -871,22 +1337,19 @@ void Curvature::triangleNodalValuesAndDirections(MTriangle* triangle, SVector3* std::map<int,int>::iterator vertexIterator; vertexIterator = _VertexToInt.find( A->getNum() ); - if (vertexIterator != _VertexToInt.end()) V0 = (*vertexIterator).second; + if ( vertexIterator != _VertexToInt.end() ) V0 = (*vertexIterator).second; else - std::cout << "Didn't find vertex with number " << A->getNum() - << " in _VertextToInt !" << std::endl; + 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; + if ( vertexIterator != _VertexToInt.end() ) V1 = (*vertexIterator).second; else - std::cout << "Didn't find vertex with number " << B->getNum() - << " in _VertextToInt !" << std::endl; + 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; + if ( vertexIterator != _VertexToInt.end() ) V2 = (*vertexIterator).second; else - std::cout << "Didn't find vertex with number " << C->getNum() - << " in _VertextToInt !" << std::endl; + std::cout << "Didn't find vertex with number " << C->getNum() << " in _VertextToInt !" << std::endl; if (isAbs){ dMax[0] = _pdir1[V0]; @@ -904,8 +1367,10 @@ void Curvature::triangleNodalValuesAndDirections(MTriangle* triangle, SVector3* 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]; @@ -924,42 +1389,45 @@ void Curvature::triangleNodalValuesAndDirections(MTriangle* triangle, SVector3* } } + + + //======================================================================================================== + 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; + { + 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 - } -} + 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 -{ + } + +//======================================================================================================== + +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()); + Msg::Error("curvature has not been computed for vertex %i (%i)", v->getNum(), _VertexToInt.size()); return 1; } return _VertexCurve[it->second]; @@ -971,11 +1439,11 @@ void Curvature::writeToPosFile( const std::string & filename) outfile.precision(18); outfile.open(filename.c_str()); outfile << "View \"Curvature \"{" << std::endl; - + int idxelem = 0; - for (unsigned i = 0; i< _ptFinalEntityList.size(); ++i) { - GFace* face = _ptFinalEntityList[i]; + 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); @@ -986,11 +1454,12 @@ void Curvature::writeToPosFile( const std::string & filename) 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: + 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()<< ","; @@ -1000,31 +1469,33 @@ void Curvature::writeToPosFile( const std::string & filename) outfile << ")"; outfile <<"{"; - // Here is printing the 3 components of the normal vector for each vertex: + //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 << 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(); +outfile << "};" << std::endl; + +outfile.close(); } +//======================================================================================================== + void Curvature::writeToVtkFile( const std::string & filename) { + std::ofstream outfile; outfile.precision(18); outfile.open(filename.c_str()); @@ -1037,20 +1508,22 @@ void Curvature::writeToVtkFile( const std::string & filename) 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 + /// 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 (unsigned i = 0; i< _ptFinalEntityList.size(); ++i){ - GFace* face = _ptFinalEntityList[i]; + for (int i = 0; i< _EntityArray.size(); ++i) + { + GFace* face = _EntityArray[i]; - for (int iElem = 0; iElem < face->getNumMeshElements(); iElem++){ + for (int iElem = 0; iElem < face->getNumMeshElements(); iElem++) + { MElement *e = face->getMeshElement(iElem); MVertex* A = e->getVertex(0); //Pointers to vertices of triangle @@ -1079,23 +1552,25 @@ void Curvature::writeToVtkFile( const std::string & filename) } } - for (int v = 0; v < npoints; ++v){ + 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 + /// Empty the array 'coord' to free the memory + /// Point coordinates will not be needed anymore coord.clear(); - // Write the cell connectivity + /// Write the cell connectivity - outfile << std::endl << "CELLS " << _ElementToInt.size() << " " - << 4*_ElementToInt.size() << std::endl; + outfile << std::endl << "CELLS " << _ElementToInt.size() << " " << 4*_ElementToInt.size() << std::endl; - for (unsigned i = 0; i< _ptFinalEntityList.size(); ++i){ - GFace* face = _ptFinalEntityList[i]; + for (int i = 0; i< _EntityArray.size(); ++i) + { + GFace* face = _EntityArray[i]; - for (int iElem = 0; iElem < face->getNumMeshElements(); iElem++){ + for (int iElem = 0; iElem < face->getNumMeshElements(); iElem++) + { MElement *e = face->getMeshElement(iElem); MVertex* A = e->getVertex(0); //Pointers to vertices of triangle @@ -1113,25 +1588,32 @@ void Curvature::writeToVtkFile( const std::string & filename) outfile << "3 " << newIdxA << " " << newIdxB << " " << newIdxC << std::endl; } } - + outfile << std::endl << "CELL_TYPES " << _ElementToInt.size() << std::endl; - for(int ie = 0; ie < _ElementToInt.size(); ++ie){ + 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' + /// 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){ + for (int iv = 0; iv < npoints; ++iv) + { outfile << _VertexCurve[iv] << std::endl; } - + outfile.close(); + + } +//======================================================================================================== + void Curvature::writeDirectionsToPosFile( const std::string & filename) { std::ofstream outfile; @@ -1139,26 +1621,28 @@ void Curvature::writeDirectionsToPosFile( const std::string & filename) outfile.open(filename.c_str()); outfile << "View \"Curvature_DirMax \"{" << std::endl; - for (unsigned i = 0; i< _ptFinalEntityList.size(); ++i){ - //face is a pointer to one surface of the group "FinalEntityList" - GFace* face = _ptFinalEntityList[i]; + for (int i = 0; i< _EntityArray.size(); ++i) + { + GFace* face = _EntityArray[i]; //face is a pointer to one surface of the group "FinalEntityList" - //Loop over the element all the element of the "myTag"-surface - for (unsigned iElem = 0; iElem < face->getNumMeshElements(); iElem++){ + 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 + 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()<< ","; @@ -1168,54 +1652,75 @@ void Curvature::writeDirectionsToPosFile( const std::string & filename) 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 << _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; - } - } - - outfile << "};" << std::endl; - - outfile << "View \"Curvature_DirMin \"{" << std::endl; - - for (int i = 0; i< _ptFinalEntityList.size(); ++i){ - GFace* face = _ptFinalEntityList[i]; - - for (unsigned iElem = 0; iElem < face->getNumMeshElements(); iElem++){ - 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()]; - const int V2 = _VertexToInt[B->getNum()]; - const int V3 = _VertexToInt[C->getNum()]; - - //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; - } - } - - outfile << "};" << std::endl; - - outfile.close(); + + } //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(); } +//======================================================================================================== + + + diff --git a/Geo/Curvature.h b/Geo/Curvature.h index c34a909ce87d476f31e5121f02cc0c63a07ec547..095d23f6bd694123d10d4826bc3f3f79ca724f35 100644 --- a/Geo/Curvature.h +++ b/Geo/Curvature.h @@ -3,160 +3,225 @@ // See the LICENSE.txt file for license information. Please report all // bugs and problems to <gmsh@geuz.org>. -#ifndef _CURVATURE_H_ +#ifndef _CURVATUREL_H_ #define _CURVATURE_H_ -#include <map> -#include <vector> #include "GModel.h" #include "STensor3.h" +#include<map> +#include<vector> +#include<list> + class Curvature { - private: - typedef std::vector<GFace*> GFaceList; - typedef std::map<int, GFaceList >::iterator GFaceIter; - // helper type for writing VTK files - struct VtkPoint - { - double x; - double y; - double z; - }; - - // static member variable to implement the class curvature as a Singleton - static Curvature *_instance; - static bool _destroyed; +private: + //---------------------------------------- + //TYPEDEFS: - // boolean to check if the curvature has already been computed - static bool _alreadyComputedCurvature; + typedef std::vector<GFace*> GFaceList; + //typedef std::map<int, GEntityList >::iterator GEntityIter; + typedef std::map<int, GFaceList >::iterator GFaceIter; - // map definition - std::map<int, int> _VertexToInt; - std::map<int, int> _ElementToInt; + //----------------------------------------- + // HELPER TYPE FOR WRITING TO VTK FILES + struct VtkPoint + { + double x; + double y; + double z; + }; - // model and list of selected entities with give physical tag: - GModel* _model; - GFaceList _ptFinalEntityList; + //----------------------------------------- + // HELPER TYPE FOR DETECTING BOUNDARY NODES + struct MeshEdgeInfo + { + int StartV; + int EndV; + int NbElemNeighbour; + }; - // averaged vertex normals - std::vector<SVector3> _VertexNormal; + //----------------------------------------- + // MEMBER VARIABLES - // vector of principal dircections - std::vector<SVector3> _pdir1; - std::vector<SVector3> _pdir2; + //Static member variable to implement the class curvature as a Singleton + static Curvature *_instance; + static bool _destroyed; - // vector of principal curvature - std::vector<double> _curv1; - std::vector<double> _curv2; - std::vector<double> _curv12; - - // area around point - std::vector<double> _pointareas; - std::vector<SVector3> _cornerareas; - - // curvature Tensor per mesh vertex - std::vector<STensor3> _CurveTensor; - - // area of a triangle element: - std::vector<double> _TriangleArea; - - // area around a mesh vertex: - std::vector<double> _VertexArea; - std::vector<double> _VertexCurve; - - // constructor and destructor - Curvature(){} - ~Curvature(); - static void create(); - static void onDeadReference(); - void initializeMap(); - void computeVertexNormals(); - void curvatureTensor(); - static void rot_coord_sys(const SVector3 &old_u, const SVector3 &old_v, - const SVector3 &new_norm, SVector3 &new_u, - SVector3 &new_v); - void 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); - void 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); - void computePointareas(); - void computeRusinkiewiczNormals(); - - // Perform LDL^T decomposition of a symmetric positive definite matrix. - // Like Cholesky, but no square roots. Overwrites lower triangle of matrix. - static inline bool ldltdc(STensor3& A, double rdiag[3]) - { - double v[2]; - for (int i = 0; i < 3; i++){ - for (int k = 0; k < i; k++) - v[k] = A(i,k) * rdiag[k]; - for (int j = i; j < 3; j++){ - double sum = A(i,j); + //Boolean to check if the curvature has already been computed + static bool _alreadyComputedCurvature; + + //Map definition + std::map<int, int> _VertexToInt; + std::map<int, int> _ElementToInt; + + bool _isMapInitialized; + + //Model and list of selected entities with give physical tag: + GModel* _model; + GFaceList _EntityArray; + + //Averaged vertex normals + std::vector<SVector3> _VertexNormal; + + // Vector of principal dircections + std::vector<SVector3> _pdir1; + std::vector<SVector3> _pdir2; + + // Vector of principal curvature + std::vector<double> _curv1; + std::vector<double> _curv2; + std::vector<double> _curv12; + + // Area around point + std::vector<double> _pointareas; + std::vector<SVector3> _cornerareas; + + //Curvature Tensor per mesh vertex + std::vector<STensor3> _CurveTensor; + + //Area of a triangle element: + std::vector<double> _TriangleArea; + + //Area around a mesh vertex: + std::vector<double> _VertexArea; + std::vector<double> _VertexCurve; + + + //Number of neighbour for each vertices in the mesh: + std::vector<int> _NbNeighbour; + + //Vector of 0/1 to check which nodes are on the boundary: + std::vector<int> _isOnBoundary; + + std::vector<std::list<MeshEdgeInfo> > _VertexToEdgeList; + //----------------------------------------- + // PRIVATE METHODS + + //Constructor and destructor + Curvature(); + ~Curvature(); + + static void create(); + static void onDeadReference(); + + void initializeMap(); + void computeVertexNormals(); + void curvatureTensor(); + static void rot_coord_sys(const SVector3 &old_u, const SVector3 &old_v, + const SVector3 &new_norm, SVector3 &new_u, SVector3 &new_v); + void 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); + void 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); + void computePointareas(); + void computeRusinkiewiczNormals(); + + // Perform LDL^T decomposition of a symmetric positive definite matrix. + // Like Cholesky, but no square roots. Overwrites lower triangle of matrix. + static inline bool ldltdc(STensor3& A, double rdiag[3]) + { + double v[2]; + for (int i = 0; i < 3; i++) + { for (int k = 0; k < i; k++) - sum -= v[k] * A(j,k); - if (i == j){ - //if (unlikely(sum <= T(0))) - if (sum <= 0.0) - return false; - rdiag[i] = 1.0 / sum; - } - else{ - A(j,i) = sum; + v[k] = A(i,k) * rdiag[k]; + for (int j = i; j < 3; j++) + { + double sum = A(i,j); + for (int k = 0; k < i; k++) + sum -= v[k] * A(j,k); + if (i == j) + { + //if (unlikely(sum <= T(0))) + if (sum <= 0.0) + return false; + rdiag[i] = 1.0 / sum; + } + else + { + A(j,i) = sum; + } } } + + return true; } - return true; - } - // Solve Ax=B after ldltdc - static inline void ldltsl(STensor3& A, double rdiag[3], double B[3], double x[3]) - { - int i; - for (i = 0; i < 3; i++){ - double sum = B[i]; - for (int k = 0; k < i; k++) - sum -= A(i,k) * x[k]; - x[i] = sum * rdiag[i]; - } - for (i = 3 - 1; i >= 0; i--){ - double sum = 0; - for (int k = i + 1; k < 3; k++) - sum += A(k,i) * x[k]; - x[i] -= sum * rdiag[i]; + // Solve Ax=B after ldltdc + static inline void ldltsl(STensor3& A, double rdiag[3], double B[3], double x[3]) + { + int i; + for (i = 0; i < 3; i++) + { + double sum = B[i]; + for (int k = 0; k < i; k++) + sum -= A(i,k) * x[k]; + x[i] = sum * rdiag[i]; + } + for (i = 3 - 1; i >= 0; i--) + { + double sum = 0; + for (int k = i + 1; k < 3; k++) + sum += A(k,i) * x[k]; + x[i] -= sum * rdiag[i]; + } } - } - - public: - typedef enum {RUSIN=1, RBF=2, SIMPLE=3} typeOfCurvature; + + //Build the list of all edges: + void buildEdgeList(); + + //Smooth the computed curvature field via Laplacian smoothing method: + void smoothCurvatureField(const int NbIter); + +public: + + typedef enum {RUSIN=1,RBF=2, SIMPLE=3} typeOfCurvature; static Curvature& getInstance(); static bool valueAlreadyComputed(); + + inline void setGModel(GModel* model) + { + _model = model; + } + void retrieveCompounds(); + void correctOnEdges(); double getAtVertex(const MVertex *v) const; + //void retrievePhysicalSurfaces(const std::string & face_tag); + void computeCurvature(GModel* model, typeOfCurvature typ); + /// The following function implements algorithm from: /// Implementation of an Algorithm for Approximating the Curvature Tensor /// on a Triangular Surface Mesh in the Vish Environment /// Edwin Matthews, Werner Benger, Marcel Ritter void computeCurvature_Simple(); + /// The following function implements algorithm from: /// Estimating Curvatures and Their Derivatives on Triangle Meshes /// Szymon Rusinkiewicz, Princeton University /// Code taken from Rusinkiewicz' 'trimesh2' library void computeCurvature_Rusinkiewicz(int isMax=0); + void computeCurvature_RBF(); - void triangleNodalValues(MTriangle* triangle, double& c0, double& c1, - double& c2, int isAbs=0); - void triangleNodalValuesAndDirections(MTriangle* triangle, SVector3* dMax, - SVector3* dMin, double* cMax, double* cMin, - int isAbs=0); + + void triangleNodalValues(MTriangle* triangle, double& c0, double& c1, double& c2, int isAbs=0); + void triangleNodalValuesAndDirections(MTriangle* triangle, SVector3* dMax, SVector3* dMin, double* cMax, double* cMin, int isAbs=0); + void edgeNodalValues(MLine* edge, double& c0, double& c1, int isAbs=0); + void writeToPosFile( const std::string & filename); + void writeToVtkFile( const std::string & filename); + void writeDirectionsToPosFile( const std::string & filename); + + + }; + #endif