diff --git a/Geo/GFaceCompound.cpp b/Geo/GFaceCompound.cpp index 840c799e2943f95dfa407bb3f021e1f46cd90f27..57dc316fdaf928403f33155f29324743ccaea245 100644 --- a/Geo/GFaceCompound.cpp +++ b/Geo/GFaceCompound.cpp @@ -664,20 +664,10 @@ bool GFaceCompound::parametrize() const int variableEps = 0; int radFunInd = 1; //MQ RBF - double delta = 0.33*getDistMin(); - double epsilon = 0.5/getDistMin(); //0.15*(allNodes.size()/150.0)/delta; //max(2.5, 0.5*(nbNodes/150.0)/dist_min); - double radius= 3.*getSizeH()/sqrt(allNodes.size()); - - Msg::Info("*****************************************"); - Msg::Info("*** RBF nbNodes=%d ", allNodes.size()); - Msg::Info("*** RBF rad=%g dist_min =%g ", radius, 3.*delta); - Msg::Info("*** RBF eps=%g delta =%g ", epsilon, delta); - Msg::Info("*****************************************"); - - // printf("allNodes=%d \n", allNodes.size()); - // exit(1); + double sizeBox = getSizeH(); + fullMatrix<double> Oper(3*allNodes.size(),3*allNodes.size()); - _rbf = new GRbf(epsilon, delta, radius, variableEps, radFunInd, _normals, allNodes); + _rbf = new GRbf(sizeBox, variableEps, radFunInd, _normals, allNodes, _ordered); //_rbf->RbfLapSurface_global_CPM_low(_rbf->getXYZ(), _rbf->getN(), Oper); //_rbf->RbfLapSurface_local_CPM(true, _rbf->getXYZ(), _rbf->getN(), Oper); @@ -687,9 +677,9 @@ bool GFaceCompound::parametrize() const //_rbf->RbfLapSurface_local_projection(_rbf->getXYZ(), _rbf->getN(), Oper); _rbf->solveHarmonicMap(Oper, _ordered, _coords, coordinates); + printStuff(); - } buildOct(); @@ -781,21 +771,6 @@ double GFaceCompound::getSizeH() const return H; } -double GFaceCompound::getDistMin() const -{ - double dist_min = 1.e6; - double tol = CTX::instance()->geom.tolerance; - for(std::set<MVertex *>::iterator itv = allNodes.begin(); itv !=allNodes.end() ; itv++){ - for(std::set<MVertex *>::iterator itv2 = allNodes.begin(); itv2 !=allNodes.end() ; itv2++){ - MVertex *v1 = *itv; - MVertex *v2 = *itv2; - double dist = sqrt((v1->x()-v2->x())*(v1->x()-v2->x())+(v1->y()-v2->y())*(v1->y()-v2->y()) - +(v1->z()-v2->z())*(v1->z()-v2->z())); - if (dist<dist_min && dist > tol) dist_min = dist; - } - } - return dist_min; -} double GFaceCompound::getSizeBB(const std::list<GEdge* > &elist) const { //SOrientedBoundingBox obboxD = obb_boundEdges(elist); diff --git a/Geo/GFaceCompound.h b/Geo/GFaceCompound.h index 4d9f98cadeff9139da9ecdc7e8f0a2b03959b5a9..3ee67a2a1eaf6e090db6122116ce68320e6a6b83 100644 --- a/Geo/GFaceCompound.h +++ b/Geo/GFaceCompound.h @@ -102,7 +102,6 @@ class GFaceCompound : public GFace { linearSystem <double> *_lsys; double getSizeH() const; double getSizeBB(const std::list<GEdge* > &elist) const; - double getDistMin() const; SBoundingBox3d boundEdges(const std::list<GEdge* > &elist) const; SOrientedBoundingBox obb_boundEdges(const std::list<GEdge* > &elist) const; void fillNeumannBCS() const; diff --git a/Geo/GRbf.cpp b/Geo/GRbf.cpp index f5febe14bf6a54102488e0ac0190dcdb89ad0398..4a0984541d457c302a1dd43e5c519e5a2867bd29 100644 --- a/Geo/GRbf.cpp +++ b/Geo/GRbf.cpp @@ -9,6 +9,7 @@ #include "SBoundingBox3d.h" #include "OS.h" #include "MVertex.h" +#include "MVertexPositionSet.h" #if defined(HAVE_ANN) #include <ANN/ANN.h> @@ -41,30 +42,70 @@ static int SphereInEle(void *a, double*c){ } return 0; } +static void printNodes(std::set<MVertex *> myNodes){ + FILE * xyz = fopen("myNodes.pos","w"); + fprintf(xyz,"View \"\"{\n"); + for(std::set<MVertex *>::iterator itv = myNodes.begin(); itv !=myNodes.end() ; ++itv){ + MVertex *v = *itv; + fprintf(xyz,"SP(%g,%g,%g){%g};\n", v->x(), v->y(), v->z(), 1.0); + } + fprintf(xyz,"};\n"); + fclose(xyz); +} - -GRbf::GRbf (double eps, double del, double rad, int variableEps, int rbfFun, - std::map<MVertex*, SVector3> _normals, std::set<MVertex *> allNodes) - : delta(del), radius (rad), variableShapeParam(variableEps), - radialFunctionIndex (rbfFun), XYZkdtree(0), _inUV(0) +GRbf::GRbf (double sizeBox, int variableEps, int rbfFun, std::map<MVertex*, SVector3> _normals, + std::set<MVertex *> allNodes, std::vector<MVertex*> bcNodes) + : sBox(sizeBox), variableShapeParam(variableEps), radialFunctionIndex (rbfFun), XYZkdtree(0), _inUV(0) { - - nbNodes= allNodes.size(); + + allCenters.resize(allNodes.size(),3); + double tol= 8.e-2*sBox; + + //remove duplicate vertices + //add bc nodes + for(unsigned int i = 0; i < bcNodes.size(); i++) myNodes.insert(bcNodes[i]); + //then create Mvertex position + std::vector<MVertex*> vertices( allNodes.begin(), allNodes.end() ); + MVertexPositionSet pos(vertices); + for(unsigned int i = 0; i < vertices.size(); i++){ + MVertex *v = vertices[i]; + pos.find(v->x(), v->y(), v->z(), tol); + allCenters(i,0) = v->x()/sBox; + allCenters(i,1) = v->y()/sBox; + allCenters(i,2) = v->z()/sBox; + _mapAllV.insert(std::make_pair(v, i)); + } + //keep only no duplicate vertices + for(unsigned int i = 0; i < vertices.size(); i++) + if(vertices[i]->getIndex()) myNodes.insert(vertices[i]); + + //initialize with points + nbNodes= myNodes.size(); centers.resize(nbNodes,3); normals.resize(nbNodes,3); int index = 0; - for(std::set<MVertex *>::iterator itv = allNodes.begin(); itv !=allNodes.end() ; ++itv){ - MVertex *v = *itv; - centers(index,0) = v->x(); - centers(index,1) = v->y(); - centers(index,2) = v->z(); - std::map<MVertex*, SVector3>::iterator itn = _normals.find(v); + double dist_min = 1.e6; + for(std::set<MVertex *>::iterator itv = myNodes.begin(); itv !=myNodes.end() ; ++itv){ + MVertex *v1 = *itv; + centers(index,0) = v1->x()/sBox; + centers(index,1) = v1->y()/sBox; + centers(index,2) = v1->z()/sBox; + std::map<MVertex*, SVector3>::iterator itn = _normals.find(v1); normals(index,0) = itn->second.x(); normals(index,1) = itn->second.y(); normals(index,2) = itn->second.z(); - _mapV.insert(std::make_pair(v, index)); + _mapV.insert(std::make_pair(v1, index)); + for(std::set<MVertex *>::iterator itv2 = myNodes.begin(); itv2 !=myNodes.end() ; itv2++){ + MVertex *v2 = *itv2; + double dist = sqrt((v1->x()-v2->x())*(v1->x()-v2->x())+(v1->y()-v2->y())*(v1->y()-v2->y()) + +(v1->z()-v2->z())*(v1->z()-v2->z()))/sBox; + if (dist<dist_min && *itv != *itv2) dist_min = dist; + } index++; } + + delta = 0.33*dist_min;//0.6 + radius= nbNodes/10.; matAInv.resize(nbNodes, nbNodes); matAInv = generateRbfMat(0,centers,centers); @@ -72,6 +113,14 @@ GRbf::GRbf (double eps, double del, double rad, int variableEps, int rbfFun, isLocal = false; extendedX.resize(3*nbNodes,3); + Msg::Info("*****************************************"); + Msg::Info("*** RBF nbNodes=%d (all=%d) ", myNodes.size(), allNodes.size()); + Msg::Info("*** RBF rad=%g dist_min =%g ", radius, dist_min); + Msg::Info("*****************************************"); + + printNodes(myNodes); + //exit(1); + } GRbf::~GRbf(){ @@ -235,7 +284,7 @@ fullMatrix<double> GRbf::generateRbfMat(int p, fullMatrix<double> rbfMat(m,n); double eps =0.5/delta; //0.0677*(nbNodes^0.28)/min_dist; - if (_inUV) eps = epsilonUV; + if (_inUV) eps = 0.4/deltaUV; for (int i = 0; i < m; i++) { for (int j = 0; j < n; j++) { double dx = nodes2(i,0)-nodes1(j,0); @@ -637,7 +686,7 @@ void GRbf::RbfLapSurface_global_CPM_low(const fullMatrix<double> &cntrs, } void GRbf::solveHarmonicMap(fullMatrix<double> Oper, - std::vector<MVertex*> ordered, + std::vector<MVertex*> bcNodes, std::vector<double> coords, std::map<MVertex*, SPoint3> &rbf_param){ int nb = Oper.size2(); @@ -645,15 +694,17 @@ void GRbf::solveHarmonicMap(fullMatrix<double> Oper, fullMatrix<double> F(nb,2); F.scale(0.0); - for (int i=0; i < ordered.size(); i++){ - std::map<MVertex*, int>::iterator itm = _mapV.find(ordered[i]); - double theta = 2 * M_PI * coords[i]; - int iFix = itm->second; - for (int j=0;j<nb ; ++j) Oper(iFix,j) = 0.0; - Oper(iFix,iFix) = 1.0; - F(iFix,0) = cos(theta); - F(iFix,1) = sin(theta); - + for (int i=0; i < bcNodes.size(); i++){ + // std::set<MVertex *>::iterator itN = myNodes.find(bcNodes[i]); + // if (itN != myNodes.end()){ + std::map<MVertex*, int>::iterator itm = _mapV.find(bcNodes[i]); + double theta = 2 * M_PI * coords[i]; + int iFix = itm->second; + for (int j=0;j<nb ; ++j) Oper(iFix,j) = 0.0; + Oper(iFix,iFix) = 1.0; + F(iFix,0) = cos(theta); + F(iFix,1) = sin(theta); + //} } Oper.invertInPlace(); Oper.mult(F,UV); @@ -672,109 +723,22 @@ void GRbf::solveHarmonicMap(fullMatrix<double> Oper, if (dist<dist_min) dist_min = dist; } } - epsilonUV = 0.5/dist_min; deltaUV = 0.6*dist_min; UVkdtree = new ANNkd_tree(UVnodes, nbNodes, 3); #endif + //interpolate + fullMatrix<double> UVall(allCenters.size1(), 3); + evalRbfDer(0,centers,allCenters,UV,UVall); + //fill rbf_param - std::map<MVertex*, int>::iterator itm = _mapV.begin(); - for (; itm != _mapV.end(); itm++){ + std::map<MVertex*, int>::iterator itm = _mapAllV.begin(); + for (; itm != _mapAllV.end(); itm++){ int index = itm->second; - SPoint3 coords(UV(index,0), UV(index,1), 0.0); + SPoint3 coords(UVall(index,0), UVall(index,1), 0.0); rbf_param.insert(std::make_pair(itm->first,coords)); } -} - - //WARNING: THIS IS KO FOR PROJECTION -bool GRbf::UVStoXYZ_global(const double u_eval, const double v_eval, - double &XX, double &YY, double &ZZ, - SVector3 &dXdu, SVector3& dXdv, int num_neighbours) { - bool converged = true; -#if defined (HAVE_ANN) - - int numNodes = 3*nbNodes; - double norm_s = 0.0; - fullMatrix<double> u_temp(1,3); - fullMatrix<double> ux(1,3), uy(1,3), uz(1,3); - fullMatrix<double> nodes_eval(1,3); - - // u_vec = [u v s] : These are the u,v,s that are on the surface *and* outside of it also! - fullMatrix<double> u_vec(numNodes,3); - for (int i = 0; i < numNodes; i++){ - u_vec(i,0) = UV(i,0); - u_vec(i,1) = UV(i,1); - u_vec(i,2) = surfInterp(i,0); - } - - // u_vec_eval = [u_eval v_eval s_eval] - fullMatrix<double> u_vec_eval(1, 3); - u_vec_eval(0,0) = u_eval; - u_vec_eval(0,1) = v_eval; - u_vec_eval(0,2) = 0.0; - - //Start with the closest point (u,v) - double uvw[3] = { u_eval, v_eval, 0.0 }; - ANNidxArray index = new ANNidx[num_neighbours]; - ANNdistArray dist = new ANNdist[num_neighbours]; - UVkdtree->annkSearch(uvw, num_neighbours, index, dist); - - nodes_eval(0,0) = extendedX(index[0],0); - nodes_eval(0,1) = extendedX(index[0],1); - nodes_eval(0,2) = extendedX(index[0],2); - u_temp(0,0) = UV(index[0],0); - u_temp(0,1) = UV(index[0],1); - u_temp(0,2) = 0.0; - - delete [] index; - delete [] dist; - - int incr =0; - fullMatrix<double> Jac(3,3); - while(norm_s < 5 && incr < 10){ - - // Find the entries of the m Jacobians - evalRbfDer(1,extendedX,nodes_eval,u_vec,ux); - evalRbfDer(2,extendedX,nodes_eval,u_vec,uy); - evalRbfDer(3,extendedX,nodes_eval,u_vec,uz); - - // Jacobian of the UVS coordinate system w.r.t. XYZ - for (int k = 0; k < 3;k++){ - Jac(k,0) = ux(0,k); - Jac(k,1) = uy(0,k); - Jac(k,2) = uz(0,k); - } - Jac.invertInPlace(); - - for (int j = 0; j< 3;j++) - nodes_eval(0,j) = nodes_eval(0,j) - + Jac(j,0)*(u_vec_eval(0,0) - u_temp(0,0)) - + Jac(j,1)*(u_vec_eval(0,1) - u_temp(0,1)) - + Jac(j,2)*(0.0 - u_temp(0,2)); - - // Find the corresponding u, v, s - evalRbfDer(0,extendedX,nodes_eval,u_vec,u_temp); - - double normSq = sqrt(u_temp(0,2)*u_temp(0,2)); - norm_s = fabs(log10(normSq)); - - incr++; - } - if (norm_s < 5 ){ - printf("Newton not converged for point (uv)=(%g,%g -> norm_s =%g )\n", u_eval, v_eval, norm_s); - converged = false; - } - - XX = nodes_eval(0,0); - YY = nodes_eval(0,1); - ZZ = nodes_eval(0,2); - - dXdu = SVector3(Jac(0,0), Jac(1,0), Jac(2,0)); - dXdv = SVector3(Jac(0,1), Jac(1,1), Jac(2,1)); - - return converged; -#endif } bool GRbf::UVStoXYZ(const double u_eval, const double v_eval, @@ -845,7 +809,6 @@ bool GRbf::UVStoXYZ(const double u_eval, const double v_eval, u_temp(0,1) = temp_u_temp(0,1); u_temp(0,2) = temp_u_temp(0,2); - //we use the closest point for (int i_nbr = 1; i_nbr < N_nbr; i_nbr++){ nodes_eval(i_nbr,0) = extendedX(index[i_nbr-1],0); @@ -883,7 +846,6 @@ bool GRbf::UVStoXYZ(const double u_eval, const double v_eval, } Jac.invertInPlace(); JacV.push_back(Jac); - for (int j = 0; j< 3;j++) nodes_eval(i_nbr,j) = nodes_eval(i_nbr,j) + Jac(j,0)*( u_vec_eval(0,0) - u_temp(i_nbr,0)) @@ -917,17 +879,17 @@ bool GRbf::UVStoXYZ(const double u_eval, const double v_eval, if (norm < norm_treshhold ){ printf("Newton not converged (norm=%g, dist=%g) for uv=(%g,%g) UVS=(%g,%g,%g) NB=%d \n", norm, dist_test,u_eval, v_eval, u_test_vec_eval(0,0), u_test_vec_eval(0,1), u_test_vec_eval(0,2), num_neighbours); - //converged = false; - return UVStoXYZ(u_eval, v_eval, XX, YY,ZZ, dXdu, dXdv, num_neighbours+5); - } + if (num_neighbours+5 < nbNodes) + return UVStoXYZ(u_eval, v_eval, XX, YY,ZZ, dXdu, dXdv, num_neighbours+5); + else converged = false; +} + +XX = nodes_vec_eval(0,0)*sBox; +YY = nodes_vec_eval(0,1)*sBox; +ZZ = nodes_vec_eval(0,2)*sBox; +dXdu = SVector3(best_Jac(0,0)*sBox, best_Jac(1,0)*sBox, best_Jac(2,0)*sBox); +dXdv = SVector3(best_Jac(0,1)*sBox, best_Jac(1,1)*sBox, best_Jac(2,1)*sBox); -XX = nodes_vec_eval(0,0); -YY = nodes_vec_eval(0,1); -ZZ = nodes_vec_eval(0,2); -dXdu = SVector3(best_Jac(0,0), best_Jac(1,0), best_Jac(2,0)); -dXdv = SVector3(best_Jac(0,1), best_Jac(1,1), best_Jac(2,1)); -// printf("Converged (norm=%g, dist=%g) for uv=(%g,%g) UVS=(%g,%g,%g) NB=%d \n", norm, dist_test,u_eval, v_eval,u_test_vec_eval(0,0), u_test_vec_eval(0,1), u_test_vec_eval(0,2), num_neighbours); - printf("Converged (norm=%g, dist=%g) for uvs-UVS=(%g,%g,%g) NB=%d \n", norm, dist_test,u_eval-u_test_vec_eval(0,0), v_eval-u_test_vec_eval(0,1), u_test_vec_eval(0,2), num_neighbours); return converged; #endif diff --git a/Geo/GRbf.h b/Geo/GRbf.h index 0a1100d47fd34bd4fe797a83f05953157b70ad78..c79f94c7c9e24c0d7b604b98db04920303b3df00 100644 --- a/Geo/GRbf.h +++ b/Geo/GRbf.h @@ -7,6 +7,7 @@ #include "SPoint3.h" #include "SVector3.h" #include "MVertex.h" +#include "Context.h" #if defined(HAVE_ANN) #include <ANN/ANN.h> #endif @@ -22,6 +23,7 @@ class Sphere{ class GRbf { std::map<MVertex*, int> _mapV; + std::map<MVertex*, int> _mapAllV; std::map<int, std::vector<int> > nodesInSphere; fullMatrix<double> matA, matAInv; @@ -33,17 +35,17 @@ class GRbf { int num_neighbours; int _inUV; - double epsilonUV; - - double epsilonXYZ; // Shape parameter double delta; //offset level set double deltaUV; //offset level set double radius; + double sBox; int variableShapeParam; int radialFunctionIndex; // Index for the radial function used (0 - GA,1 - MQ, ... ) - fullMatrix<double> centers; // Data centers + std::set<MVertex *> myNodes; + fullMatrix<double> centers; // Data centers (without duplicates) + fullMatrix<double> allCenters; // Data centers fullMatrix<double> normals; // Data normals fullMatrix<double> surfInterp;//level set fullMatrix<double> extendedX;//X values extend in and out @@ -58,8 +60,9 @@ class GRbf { public: - GRbf (double eps, double del, double radius, int variableEps, int rbfFun, - std::map<MVertex*, SVector3> normals, std::set<MVertex *> allNodes); + GRbf (double sizeBox, int variableEps, int rbfFun, + std::map<MVertex*, SVector3> normals, + std::set<MVertex *> allNodes, std::vector<MVertex*> bcNodes); ~GRbf(); //build octree @@ -134,16 +137,12 @@ class GRbf { const fullMatrix<double> &node, fullMatrix<double> &curvature); - bool UVStoXYZ_global(const double u_eval, const double v_eval, - double &XX, double &YY, double &ZZ, - SVector3 &dXdu, SVector3& dxdv, int num_neighbours=10); - //Finds the U,V,S (in the 0-level set) that are the 'num_neighbours' closest to u_eval and v_eval. //Thus in total, we're working with '3*num_neighbours' nodes //Say that the vector 'index' gives us the indices of the closest points bool UVStoXYZ(const double u_eval, const double v_eval, double &XX, double &YY, double &ZZ, - SVector3 &dXdu, SVector3& dxdv, int num_neighbours=10); + SVector3 &dXdu, SVector3& dxdv, int num_neighbours=15); void solveHarmonicMap(fullMatrix<double> Oper, std::vector<MVertex*> ordered, std::vector<double> coords, std::map<MVertex*, SPoint3> &rbf_param);