// Gmsh - Copyright (C) 1997-2016 C. Geuzaine, J.-F. Remacle // // See the LICENSE.txt file for license information. Please report all // bugs and problems to the public mailing list <gmsh@onelab.info>. // // Contributor(s): // Tristan Carrier François Henrotte #include <fstream> #include "GModel.h" #include "BackgroundMesh.h" #include "meshGFaceDelaunayInsertion.h" #include "MTetrahedron.h" #include "directions3D.h" #include "OS.h" #include "GFaceCompound.h" #if defined(HAVE_PETSC) #include "dofManager.h" #include "laplaceTerm.h" #include "linearSystemPETSc.h" #include "linearSystemFull.h" #endif /****************class Frame_field****************/ Frame_field::Frame_field(){} void Frame_field::init_region(GRegion* gr){ #if defined(HAVE_ANN) // Fill in a ANN tree with the boundary cross field of region gr unsigned int i; GFace* gf; std::list<GFace*> faces; std::list<GFace*>::iterator it; Nearest_point::init_region(gr); faces = gr->faces(); field.clear(); labels.clear(); for(it=faces.begin();it!=faces.end();it++){ gf = *it; init_face(gf); } ANNpointArray duplicate = annAllocPts(field.size(),3); for(i=0;i<field.size();i++){ duplicate[i][0] = field[i].first.x(); duplicate[i][1] = field[i].first.y(); duplicate[i][2] = field[i].first.z(); } kd_tree = new ANNkd_tree(duplicate,field.size(),3); #endif } void Frame_field::init_face(GFace* gf){ // Fills the auxiliary std::map "field" with a pair <SPoint3, STensor3> // for each vertex of the face gf. unsigned int i; SPoint3 point; SVector3 v1; SVector3 v2; SVector3 v3; STensor3 m(1.0); for(i=0;i<gf->storage1.size();i++){ point = gf->storage1[i]; v1 = gf->storage2[i]; v2 = gf->storage3[i]; v1.normalize(); v2.normalize(); v3 = crossprod(v1,v2); v3.normalize(); m.set_m11(v1.x()); m.set_m21(v1.y()); m.set_m31(v1.z()); m.set_m12(v2.x()); m.set_m22(v2.y()); m.set_m32(v2.z()); m.set_m13(v3.x()); m.set_m23(v3.y()); m.set_m33(v3.z()); field.push_back(std::pair<SPoint3,STensor3>(point,m)); labels.push_back(gf->tag()); } } STensor3 Frame_field::search(double x,double y,double z){ // Determines the frame/cross at location (x,y,z) int index1; int index2; double distance1; double distance2; double e2; index1 = 0; index2 = 0; distance1 = 1000000.0; distance2 = 1000000.0; e2 = 0.000001; #if defined(HAVE_ANN) ANNpoint query; ANNidxArray indices; ANNdistArray distances; if(field.size()<=1){ return STensor3(1.0); } query = annAllocPt(3); query[0] = x; query[1] = y; query[2] = z; indices = new ANNidx[2]; distances = new ANNdist[2]; double e = 0.0; kd_tree->annkSearch(query,2,indices,distances,e); index1 = indices[0]; index2 = indices[1]; distance1 = distances[0]; distance2 = distances[1]; annDeallocPt(query); delete[] indices; delete[] distances; #endif if(fabs(sqrt(distance2)-sqrt(distance1))<e2){ if(labels[index2]<labels[index1]){ return field[index2].second; } else{ return field[index1].second; } } else{ return field[index1].second; } } STensor3 Frame_field::combine(double x,double y,double z){ // Determines the frame/cross at location (x,y,z) // Alternative to Frame_field::search bool ok; double val1,val2,val3; SVector3 vec,other; SVector3 vec1,vec2,vec3; SVector3 final1,final2; STensor3 m(1.0),m2(1.0); m = search(x,y,z); m2 = m; ok = Nearest_point::search(x,y,z,vec); vec.normalize(); if(ok){ vec1 = SVector3(m.get_m11(),m.get_m21(),m.get_m31()); vec2 = SVector3(m.get_m12(),m.get_m22(),m.get_m32()); vec3 = SVector3(m.get_m13(),m.get_m23(),m.get_m33()); val1 = fabs(dot(vec,vec1)); val2 = fabs(dot(vec,vec2)); val3 = fabs(dot(vec,vec3)); if(val1<=val2 && val1<=val3){ other = vec1; } else if(val2<=val1 && val2<=val3){ other = vec2; } else{ other = vec3; } final1 = crossprod(vec,other); final1.normalize(); final2 = crossprod(vec,final1); final2.normalize(); m2.set_m11(vec.x()); m2.set_m21(vec.y()); m2.set_m31(vec.z()); m2.set_m12(final1.x()); m2.set_m22(final1.y()); m2.set_m32(final1.z()); m2.set_m13(final2.x()); m2.set_m23(final2.y()); m2.set_m33(final2.z()); } return m2; } void Frame_field::print_segment(SPoint3 p1,SPoint3 p2,double val1,double val2,std::ofstream& file){ file << "SL (" << p1.x() << ", " << p1.y() << ", " << p1.z() << ", " << p2.x() << ", " << p2.y() << ", " << p2.z() << ")" << "{" << val1 << "," << val2 << "};\n"; } void Frame_field::print_field1(){ // Saves a file with the surface cross field contained in Frame_field.temp // Frame_field.temp is constructed by Frame_field::init_region unsigned int i; double k; double color1; double color2; SPoint3 point; SPoint3 p1,p2,p3,p4,p5,p6; STensor3 m(1.0); k = 0.05; std::ofstream file("frame1.pos"); file << "View \"cross field\" {\n"; color1 = 10.0; color2 = 20.0; for(i=0;i<field.size();i++){ point = field[i].first; m = field[i].second; p1 = SPoint3(point.x() + k*m.get_m11(), point.y() + k*m.get_m21(), point.z() + k*m.get_m31()); p2 = SPoint3(point.x() - k*m.get_m11(), point.y() - k*m.get_m21(), point.z() - k*m.get_m31()); p3 = SPoint3(point.x() + k*m.get_m12(), point.y() + k*m.get_m22(), point.z() + k*m.get_m32()); p4 = SPoint3(point.x() - k*m.get_m12(), point.y() - k*m.get_m22(), point.z() - k*m.get_m32()); p5 = SPoint3(point.x() + k*m.get_m13(), point.y() + k*m.get_m23(), point.z() + k*m.get_m33()); p6 = SPoint3(point.x() - k*m.get_m13(), point.y() - k*m.get_m23(), point.z() - k*m.get_m33()); print_segment(point,p1,color1,color2,file); print_segment(point,p2,color1,color2,file); print_segment(point,p3,color1,color2,file); print_segment(point,p4,color1,color2,file); print_segment(point,p5,color1,color2,file); print_segment(point,p6,color1,color2,file); } file << "};\n"; } void Frame_field::print_field2(GRegion* gr){ // Saves a file with the cross fields inside the given GRegion, excluding the boundary. unsigned int i; int j; double k; double color1; double color2; SPoint3 point; SPoint3 p1,p2,p3,p4,p5,p6; MVertex* vertex; MElement* element; STensor3 m(1.0); k = 0.05; std::ofstream file("frame2.pos"); file << "View \"cross field\" {\n"; color1 = 10.0; color2 = 20.0; for(i=0;i<gr->getNumMeshElements();i++){ element = gr->getMeshElement(i); for(j=0;j<element->getNumVertices();j++){ vertex = element->getVertex(j); if(vertex->onWhat()->dim()>2){ point = SPoint3(vertex->x(),vertex->y(),vertex->z()); m = search(vertex->x(),vertex->y(),vertex->z()); p1 = SPoint3(point.x() + k*m.get_m11(), point.y() + k*m.get_m21(), point.z() + k*m.get_m31()); p2 = SPoint3(point.x() - k*m.get_m11(), point.y() - k*m.get_m21(), point.z() - k*m.get_m31()); p3 = SPoint3(point.x() + k*m.get_m12(), point.y() + k*m.get_m22(), point.z() + k*m.get_m32()); p4 = SPoint3(point.x() - k*m.get_m12(), point.y() - k*m.get_m22(), point.z() - k*m.get_m32()); p5 = SPoint3(point.x() + k*m.get_m13(), point.y() + k*m.get_m23(), point.z() + k*m.get_m33()); p6 = SPoint3(point.x() - k*m.get_m13(), point.y() - k*m.get_m23(), point.z() - k*m.get_m33()); print_segment(point,p1,color1,color2,file); print_segment(point,p2,color1,color2,file); print_segment(point,p3,color1,color2,file); print_segment(point,p4,color1,color2,file); print_segment(point,p5,color1,color2,file); print_segment(point,p6,color1,color2,file); } } } file << "};\n"; } GRegion* Frame_field::test(){ GRegion* gr; GModel* model = GModel::current(); gr = *(model->firstRegion()); return gr; } void Frame_field::clear(){ Nearest_point::clear(); field.clear(); labels.clear(); #if defined(HAVE_ANN) delete kd_tree->thePoints(); delete kd_tree; annClose(); #endif #if defined(HAVE_ANN) if(annTree && annTree->thePoints()) delete annTree->thePoints(); if(annTree) delete annTree; #endif } // BARYCENTRIC #include "cross3D.h" //double max(const double a, const double b) { return (b>a)?b:a;} double min(const double a, const double b) { return (b<a)?b:a; } double squ(const double a) { return a*a; } int Frame_field::build_vertex_to_vertices(GEntity* gr, int onWhat, bool initialize){ // build vertex to vertices data std::set<MVertex*> vertices; if(initialize) vertex_to_vertices.clear(); for(unsigned int i=0; i<gr->getNumMeshElements(); i++){ MElement* pElem = gr->getMeshElement(i); unsigned int n = pElem->getNumVertices(); for(unsigned int j=0; j<n; j++){ MVertex* pVertex = pElem->getVertex(j); if(onWhat >0 && pVertex->onWhat()->dim() != onWhat) continue; std::map<MVertex*,std::set<MVertex*> >::iterator it = vertex_to_vertices.find(pVertex); if(it != vertex_to_vertices.end()){ for(unsigned int k=1; k<n; k++) it->second.insert(pElem->getVertex((j+k) % n)); } else{ vertices.clear(); for(unsigned int k=1; k<n; k++) vertices.insert(pElem->getVertex((j+k) % n)); vertex_to_vertices.insert(std::pair<MVertex*,std::set<MVertex*> >(pVertex,vertices)); } } } return vertex_to_vertices.size(); } int Frame_field::build_vertex_to_elements(GEntity* gr, bool initialize){ std::set<MElement*> elements; if(initialize) vertex_to_elements.clear(); for(unsigned int i=0; i<gr->getNumMeshElements(); i++){ MElement* pElem = gr->getMeshElement(i); unsigned int n = pElem->getNumVertices(); for(unsigned int j=0; j<n; j++){ MVertex* pVertex = pElem->getVertex(j); std::map<MVertex*,std::set<MElement*> >::iterator it = vertex_to_elements.find(pVertex); if(it != vertex_to_elements.end()) it->second.insert(pElem); else{ elements.clear(); elements.insert(pElem); vertex_to_elements.insert(std::pair<MVertex*,std::set<MElement*> >(pVertex,elements)); } } } return vertex_to_elements.size(); } void Frame_field::build_listVertices(GEntity* gr, int dim, bool initialize){ std::set<MVertex*> list; for(unsigned int i=0; i<gr->getNumMeshElements(); i++){ MElement* pElem = gr->getMeshElement(i); for(int j=0; j<pElem->getNumVertices(); j++){ MVertex * pVertex = pElem->getVertex(j); if(pVertex->onWhat()->dim() == dim) list.insert(pVertex); } } if(initialize) listVertices.clear(); for(std::set<MVertex*>::const_iterator it=list.begin(); it!=list.end(); it++) listVertices.push_back(*it); } int Frame_field::buildAnnData(GEntity* ge, int dim){ build_listVertices(ge,dim); int n = listVertices.size(); #if defined(HAVE_ANN) ANNpointArray annTreeData = annAllocPts(n,3); for(int i=0; i<n; i++){ MVertex* pVertex = listVertices[i]; annTreeData[i][0] = pVertex->x(); annTreeData[i][1] = pVertex->y(); annTreeData[i][2] = pVertex->z(); } annTree = new ANNkd_tree(annTreeData,n,3); #endif std::cout << "ANN data for " << ge->tag() << "(" << dim << ") contains " << n << " vertices" << std::endl; return n; } void Frame_field::deleteAnnData(){ #if defined(HAVE_ANN) if(annTree && annTree->thePoints()) delete annTree->thePoints(); if(annTree) delete annTree; annTree = NULL; #endif } int Frame_field::findAnnIndex(SPoint3 p){ int index = 0; #if defined(HAVE_ANN) ANNpoint query = annAllocPt(3); ANNidxArray indices = new ANNidx[1]; ANNdistArray distances = new ANNdist[1]; query[0] = p.x(); query[1] = p.y(); query[2] = p.z(); double e = 0.; annTree->annkSearch(query,1,indices,distances,e); annDeallocPt(query); index = indices[0]; delete[] indices; delete[] distances; #endif return index; } void Frame_field::initFace(GFace* gf){ // align crosses of "gf" with the normal (average on neighbour elements) // at all vertices of the GFace gf build_vertex_to_elements(gf); for(std::map<MVertex*, std::set<MElement*> >::const_iterator it = vertex_to_elements.begin(); it != vertex_to_elements.end(); it++){ std::set<MElement*> elements = it->second; SVector3 Area = SVector3(0,0,0); for(std::set<MElement*>::const_iterator iter=elements.begin(); iter != elements.end(); iter++){ MElement *pElem = *iter; int n = pElem->getNumVertices(); int i; for(i=0; i<n; i++){ if(pElem->getVertex(i) == it->first) break; if(i == n-1) { std::cout << "This should not happen" << std:: endl; exit(1); } } SVector3 V0 = pElem->getVertex(i)->point(); SVector3 V1 = pElem->getVertex((i+n-1)%n)->point(); // previous vertex SVector3 V2 = pElem->getVertex((i+1)%n)->point(); // next vertex Area += crossprod(V2-V0,V1-V0); } Area.normalize(); // average normal over neighbour face elements STensor3 m = convert(cross3D(Area)); std::map<MVertex*, STensor3>::iterator iter = crossField.find(it->first); if(iter == crossField.end()) crossField.insert(std::pair<MVertex*, STensor3>(it->first,m)); else crossField[it->first] = m; } std::cout << "Nodes in face = " << vertex_to_elements.size() << std::endl; // compute cumulative cross-data "vertices x elements" for the whole contour of gf std::list<GEdge*> edges = gf->edges(); vertex_to_elements.clear(); //Replace edges by their compounds std::set<GEdge*> mySet; std::list<GEdge*>::iterator it = edges.begin(); while(it != edges.end()){ if((*it)->getCompound()){ GEdge *gec = (GEdge*)(*it)->getCompound(); mySet.insert(gec); } else{ mySet.insert(*it); } ++it; } edges.clear(); edges.insert(edges.begin(), mySet.begin(), mySet.end()); for( std::list<GEdge*>::const_iterator it=edges.begin(); it!=edges.end(); it++){ build_vertex_to_elements(*it,false); } // align crosses of the contour of "gf" with the tangent to the contour for(std::map<MVertex*, std::set<MElement*> >::const_iterator it = vertex_to_elements.begin(); it != vertex_to_elements.end(); it++){ MVertex* pVertex = it->first; std::set<MElement*> elements = it->second; if(elements.size() != 2){ std::cout << "The face has an open boundary" << std::endl; exit(1); } MEdge edg1 = (*elements.begin())->getEdge(0); MEdge edg2 = (*elements.rbegin())->getEdge(0); SVector3 tangent = edg1.scaledTangent() + edg2.scaledTangent(); tangent.normalize(); std::map<MVertex*, STensor3>::iterator iter = crossField.find(pVertex); if(iter == crossField.end()) { std::cout << "This should not happen: cross not found 1" << std::endl; exit(1); } cross3D x(cross3D((*iter).second)); STensor3 m = convert(cross3D(x.getFrst(), tangent)); crossField[pVertex] = m; } // fills ANN data with the vertices of the contour (dim=1) of "gf" buildAnnData(gf,1); std::cout << "Nodes on contour = " << vertex_to_elements.size() << std::endl; std::cout << "crossField = " << crossField.size() << std::endl; std::cout << "region = " << gf->getNumMeshVertices() << std::endl; // align crosses.scnd with the nearest cross of the contour // fixme: we have to rebuild the vertex_to_elements list // to have a working iterator oin the verticies of gf // The natural iterator gf->getMeshVertex(i) seems not to work // when the option PackingOfParallelogram is on. build_vertex_to_elements(gf); for(std::map<MVertex*, std::set<MElement*> >::const_iterator it = vertex_to_elements.begin(); it != vertex_to_elements.end(); it++){ //for(unsigned int i=0; i<gf->getNumMeshVertices(); i++){ //MVertex* pVertex0 = gf->getMeshVertex(i); MVertex* pVertex0 = it->first; if(pVertex0->onWhat()->dim() != 2) continue; std::map<MVertex*, STensor3>::iterator iter = crossField.find(pVertex0); cross3D y; if(iter == crossField.end()){ std::cout << "This should not happen: cross not found 2" << std::endl; std::cout << pVertex0->x() << "," << pVertex0->y() << "," << pVertex0->z() << std::endl; //exit(1); y = cross3D(); } else y = cross3D((*iter).second); //local cross y.getFirst() is the normal // Find the index of the nearest cross on the contour, using annTree int index = findAnnIndex(pVertex0->point()); MVertex* pVertex = listVertices[index]; //nearest vertex on contour iter = crossField.find(pVertex); if(iter == crossField.end()){ std::cout << "This should not happen: cross not found 3" << std::endl; exit(1); } cross3D x = cross3D((*iter).second); //nearest cross on contour, x.getFrst() is the normal //STensor3 m = convert(cross3D(x.getFrst(),y.getScnd())); SVector3 v1 = y.getFrst(); STensor3 m = convert( y.rotate(conj(x.rotationToOnSurf(y)))); //rotation around the normal SVector3 v2 = y.getFrst(); if(fabs(angle(v1,v2)) > 1e-8){ std::cout << "This should not happen: rotation affected the normal" << std::endl; exit(1); } crossField[pVertex0] = m; } checkAnnData(gf, "zzz.pos"); deleteAnnData(); } void Frame_field::initRegion(GRegion* gr, int n){ std::list<GFace*> faces = gr->faces(); for(std::list<GFace*>::const_iterator iter=faces.begin(); iter!=faces.end(); iter++){ initFace(*iter); // smoothing must be done immediately because crosses on the contour vertices // are now initialized with the normal to THIS face. smoothFace(*iter, n); } // Fills ANN data with the vertices of the surface (dim=2) of "gr" buildAnnData(gr,2); for(unsigned int i=0; i<gr->getNumMeshVertices(); i++){ MVertex* pVertex0 = gr->getMeshVertex(i); if(pVertex0->onWhat()->dim() != 3) continue; // Find the index of the nearest cross on the contour, using annTree int index = findAnnIndex(pVertex0->point()); MVertex* pVertex = listVertices[index]; STensor3 m = crossField[pVertex]; crossField.insert(std::pair<MVertex*, STensor3>(pVertex0,m)); } deleteAnnData(); buildAnnData(gr,3); } STensor3 Frame_field::findCross(double x, double y, double z){ int index = Frame_field::findAnnIndex(SPoint3(x,y,z)); MVertex* pVertex = Frame_field::listVertices[index]; return crossField[pVertex]; } double Frame_field::findBarycenter(std::map<MVertex*, std::set<MVertex*> >::const_iterator iter, STensor3 &m0){ double theta, gradient, energy; STensor3 m; SVector3 axis; bool debug = false; MVertex* pVertex0 = iter->first; std::set<MVertex*> list = iter->second; cross3D x(m0); if(debug) std::cout << "# " << pVertex0->getNum() << " with " << list.size() << " neighbours" << std::endl; SVector3 T = SVector3(0.), dT; double temp = 0.; energy = 0; for (std::set<MVertex*>::const_iterator it=list.begin(); it != list.end(); ++it){ MVertex *pVertex = *it; if(pVertex->getNum() == pVertex0->getNum()) std::cout << "This should not happen!" << std::endl; std::map<MVertex*, STensor3>::const_iterator itB = crossField.find(pVertex); if(itB == crossField.end()){ // not found std::cout << "This should not happen: cross not found 4" << std::endl; exit(1); } else m = itB->second; cross3D y(m); Qtn Rxy = x.rotationTo(y); MEdge edge(pVertex0, pVertex); theta = eulerAngleFromQtn(Rxy); gradient = theta/edge.length(); energy += gradient * gradient; crossDist[edge] = theta; if (fabs(theta) > 1e-10) { axis = eulerAxisFromQtn(Rxy); // undefined if theta==0 dT = axis * (theta / edge.length() / edge.length()) ; T += dT; } temp += 1. / edge.length() / edge.length(); } if(temp) T *= 1.0/temp; // average rotation vector theta = T.norm(); if(fabs(theta) > 1e-10){ axis = T; if(debug) std::cout << "-> " << pVertex0->getNum() << " : " << T << std::endl; Qtn R(axis.unit(),theta); x.rotate(R); m0 = convert(x); } return energy; } void Frame_field::buildSmoothness(){ GModel *m = GModel::current(); std::vector<GEntity*> entities; m->getEntities(entities); //pour commencer on va creer une map de connectique des Mvertex std::map<MVertex*, std::vector<MVertex* > > Neighbours; for(unsigned int i = 0; i < entities.size(); i++){ GEntity* eTmp = entities[i]; for (unsigned int j = 0; j < eTmp->getNumMeshElements();j++){ MElement* elem = eTmp->getMeshElement(j); for (int k = 0;k < elem->getNumVertices();k++){ for (int l = k;l < elem->getNumVertices();l++){ if (k != l){ MVertex* v1 = elem->getVertex(k); MVertex* v2 = elem->getVertex(l); Neighbours[v1].push_back(v2); Neighbours[v2].push_back(v1); } } } } } for(unsigned int i = 0; i < entities.size(); i++){ for (unsigned int j = 0;j < entities[i]->mesh_vertices.size();j++){ //on va traiter chaque noeud std::set<MVertex*> V1; std::set<MVertex*> V2; std::set<MVertex*> V3; MVertex* v0 = entities[i]->mesh_vertices[j]; V1.insert(v0); std::vector<MVertex* > v0vec = Neighbours[v0]; for (unsigned int k = 0;k < v0vec.size();k++){ V1.insert(v0vec[k]); } for (std::set<MVertex*>::iterator itSet = V1.begin();itSet != V1.end();itSet++){ MVertex* vTmp = (*itSet); V2.insert(vTmp); v0vec = Neighbours[vTmp]; for (unsigned int k = 0;k < v0vec.size();k++){ V2.insert(v0vec[k]); } } for (std::set<MVertex*>::iterator itSet = V2.begin();itSet != V2.end();itSet++){ MVertex* vTmp = (*itSet); V3.insert(vTmp); v0vec = Neighbours[vTmp]; for (unsigned int k = 0;k < v0vec.size();k++){ V3.insert(v0vec[k]); } } //we have all three set here, time to compute the smoothnesses for each one std::vector<cross3D> C1; std::vector<cross3D> C2; std::vector<cross3D> C3; double S1 = 0.0; double S2 = 0.0; double S3 = 0.0; for (std::set<MVertex*>::iterator itSet = V1.begin();itSet != V1.end();itSet++){ MVertex* vTmp = (*itSet); STensor3 tTmp = crossField[vTmp]; cross3D cTmp = cross3D(tTmp); C1.push_back(cTmp); } for (std::set<MVertex*>::iterator itSet = V2.begin();itSet != V2.end();itSet++){ MVertex* vTmp = (*itSet); STensor3 tTmp = crossField[vTmp]; cross3D cTmp = cross3D(tTmp); C2.push_back(cTmp); } for (std::set<MVertex*>::iterator itSet = V3.begin();itSet != V3.end();itSet++){ MVertex* vTmp = (*itSet); STensor3 tTmp = crossField[vTmp]; cross3D cTmp = cross3D(tTmp); C3.push_back(cTmp); } S1 = computeSetSmoothness(C1); S2 = computeSetSmoothness(C2); S3 = computeSetSmoothness(C3); double finalSmoothness = (9.0 * S1 + 3.0 * S2 + S3) / 13.0 ; crossFieldSmoothness[v0] = finalSmoothness; } } } double Frame_field::smoothFace(GFace *gf, int n){ double energy=0; build_vertex_to_vertices(gf, 2); build_vertex_to_vertices(gf, 0, false); for(int i=0; i<n; i++){ energy = smooth(); std::cout << "energy = " << energy << std::endl; } return energy; } double Frame_field::smoothRegion(GRegion *gr, int n){ double energy=0; build_vertex_to_vertices(gr, 3); //build_vertex_to_vertices(gr, 1, false); //build_vertex_to_vertices(gr, 0, false); for(int i=0; i<n; i++){ energy = smooth(); std::cout << "energy = " << energy << std::endl; } return energy; } double Frame_field::smooth(){ STensor3 m(1.0), m0(1.0); double enew, eold; double energy = 0; for(std::map<MVertex*, std::set<MVertex*> >::const_iterator iter = vertex_to_vertices.begin(); iter != vertex_to_vertices.end(); ++iter){ //MVertex* pVertex0 = iter->first; SVector3 T(0, 0, 0); std::map<MVertex*, STensor3>::iterator itA = crossField.find(iter->first); if(itA == crossField.end()){ std::cout << "This should not happen" << std::endl; exit(1); } else m0 = itA->second; m = m0; unsigned int NbIter = 0; enew = findBarycenter(iter, m); // initial energy in cell do{ eold = enew; crossField[itA->first] = m; enew = findBarycenter(iter, m); } while ((enew < eold) && (++NbIter < 10)); energy += eold; } return energy; } void Frame_field::save(const std::vector<std::pair<SPoint3, STensor3> > data, const std::string& filename){ const cross3D origin(SVector3(1,0,0), SVector3(0,1,0)); SPoint3 p1; double k = 0.1; std::ofstream file(filename.c_str()); file << "View \"cross field\" {\n"; for(unsigned int i=0; i<data.size(); i++){ SPoint3 p = data[i].first; STensor3 m = data[i].second; double val1 = eulerAngleFromQtn(cross3D(m).rotationTo(origin)), val2=val1; p1 = SPoint3(p.x() + k*m.get_m11(), p.y() + k*m.get_m21(), p.z() + k*m.get_m31()); print_segment(p,p1,val1,val2,file); p1 = SPoint3(p.x() - k*m.get_m11(), p.y() - k*m.get_m21(), p.z() - k*m.get_m31()); print_segment(p,p1,val1,val2,file); p1 = SPoint3(p.x() + k*m.get_m12(), p.y() + k*m.get_m22(), p.z() + k*m.get_m32()); print_segment(p,p1,val1,val2,file); p1 = SPoint3(p.x() - k*m.get_m12(), p.y() - k*m.get_m22(), p.z() - k*m.get_m32()); print_segment(p,p1,val1,val2,file); p1 = SPoint3(p.x() + k*m.get_m13(), p.y() + k*m.get_m23(), p.z() + k*m.get_m33()); print_segment(p,p1,val1,val2,file); p1 = SPoint3(p.x() - k*m.get_m13(), p.y() - k*m.get_m23(), p.z() - k*m.get_m33()); print_segment(p,p1,val1,val2,file); } file << "};\n"; file.close(); } // BARYCENTRIC End void Frame_field::recur_connect_vert(FILE *fi, int count, MVertex *v, STensor3 &cross, std::multimap<MVertex*,MVertex*> &v2v, std::set<MVertex*> &touched) { if (touched.find(v) != touched.end()) return; touched.insert(v); count++; for (std::multimap <MVertex*,MVertex*>::iterator it = v2v.lower_bound(v); it != v2v.upper_bound(v) ; ++it){ MVertex *nextV = it->second; if (touched.find(nextV) == touched.end()){ //compute dot product (N0,R0,A0) dot (Ni,Ri,Ai)^T //where N,R,A are the 3 directions std::map<MVertex*, STensor3>::iterator iter = crossField.find(nextV); STensor3 nextCross = iter->second; STensor3 nextCrossT = nextCross.transpose(); STensor3 prod = cross.operator*=(nextCrossT); fullMatrix<double> mat(3,3); prod.getMat(mat); //find biggest dot product fullVector<int> Id(3); Id(0) = Id(1) = Id(2) = 0; for (int j = 0; j < 3; j++){ double maxVal = 0.0; for (int i = 0; i < 3; i++){ double val = fabs(mat(i,j)); if( val > maxVal ){ maxVal = val; Id(j) = i; } } } //check if (Id(0) +Id(1)+ Id(2) != 3 || (Id(0) == 1 && Id(1)==1 && Id(2)==1)) { std::cout << "This should not happen: sum should be 0+1+2" << std::endl; printf("Id =%d %d %d \n", Id(0), Id(1), Id(2)); return; } //create new cross fullMatrix<double> newmat(3,3); for (int i = 0; i < 3; i++){ for (int j = 0; j < 3; j++){ newmat(i,j) = nextCross(Id(i),j) ; } } STensor3 newcross(0.0); newcross.setMat(newmat); crossField[iter->first] = newcross; //print info printf("************** COUNT = %d \n", count); if (Id(0) == 0 && Id(1) == 1 && Id(2) == 2) printf("orient OK Id=%d %d %d\n", Id(0), Id(1), Id(2)); else{ printf("change orientation Id=%d %d %d \n", Id(0), Id(1), Id(2)); cross.print("cross "); nextCross.print("nextCross "); prod.print("product"); newcross.print("newcross"); } if(fi) fprintf(fi,"SP(%g,%g,%g) {%g};\n",nextV->x(),nextV->y(),nextV->z(), (double)count); //continue recursion recur_connect_vert (fi, count, nextV, newcross, v2v,touched); } } } void Frame_field::continuousCrossField(GRegion *gr, GFace *gf) { printf("continuous cross field \n"); //start from a vertex of a face std::list<GFace*> faces = gr->faces(); bool foundFace = false; for(std::list<GFace*>::const_iterator iter=faces.begin(); iter!=faces.end(); iter++){ if (*iter == gf){ foundFace = true; break; } } if (!foundFace){ std::cout << "This should not happen: face does not belong to region" << std::endl; exit(1); } //build connectivity build_vertex_to_vertices(gr, -1, true); std::multimap<MVertex*,MVertex*> v2v; for(std::map<MVertex*, std::set<MVertex*> >::const_iterator iter = vertex_to_vertices.begin(); iter != vertex_to_vertices.end(); ++iter){ MVertex *v = iter->first; std::set<MVertex*> mySet = iter->second; for (std::set<MVertex*>::iterator it = mySet.begin(); it!=mySet.end(); ++it){ v2v.insert(std::make_pair(v,*it)); } } //recursive loop MVertex *beginV = gf->getMeshVertex(0); std::set<MVertex*> touched; std::map<MVertex*, STensor3>::iterator iter = crossField.find(beginV); STensor3 bCross = iter->second; FILE *fi = Fopen ("cross_recur.pos","w"); if(fi){ fprintf(fi,"View \"\"{\n"); fprintf(fi,"SP(%g,%g,%g) {%g};\n",beginV->x(),beginV->y(),beginV->z(), 0.0); } int count = 0; recur_connect_vert(fi, count, beginV,bCross,v2v,touched); if(fi){ fprintf(fi,"};\n"); fclose (fi); } //printf("touched =%d vert =%d \n", touched.size(), vertex_to_vertices.size()); } void Frame_field::saveCrossField(const std::string& filename, double scale, bool full){ const cross3D origin(SVector3(1,0,0), SVector3(0,1,0)); SPoint3 p1; double k = scale; std::ofstream file(filename.c_str()); file << "View \"cross field\" {\n"; for(std::map<MVertex*, STensor3>::const_iterator it = crossField.begin(); it != crossField.end(); it++){ SPoint3 p = it->first->point(); STensor3 m = it->second; //double val1 = eulerAngleFromQtn(cross3D(m).rotationTo(origin))*180./M_PI, val2=val1; double val1=1.0, val2=1.0; p1 = SPoint3(p.x() + k*m.get_m11(), p.y() + k*m.get_m21(), p.z() + k*m.get_m31()); print_segment(p,p1,val1,val2,file); p1 = SPoint3(p.x() - k*m.get_m11(), p.y() - k*m.get_m21(), p.z() - k*m.get_m31()); if(full) print_segment(p,p1,val1,val2,file); val1=2.0; val2=2.0; p1 = SPoint3(p.x() + k*m.get_m12(), p.y() + k*m.get_m22(), p.z() + k*m.get_m32()); print_segment(p,p1,val1,val2,file); p1 = SPoint3(p.x() - k*m.get_m12(), p.y() - k*m.get_m22(), p.z() - k*m.get_m32()); if(full) print_segment(p,p1,val1,val2,file); val1=3.0; val2=3.0; p1 = SPoint3(p.x() + k*m.get_m13(), p.y() + k*m.get_m23(), p.z() + k*m.get_m33()); if(full) print_segment(p,p1,val1,val2,file); p1 = SPoint3(p.x() - k*m.get_m13(), p.y() - k*m.get_m23(), p.z() - k*m.get_m33()); if(full) print_segment(p,p1,val1,val2,file); } file << "};\n"; file.close(); } void Frame_field::save_dist(const std::string& filename){ std::ofstream file(filename.c_str()); file << "View \"Distance\" {\n"; for(std::map<MEdge, double, Less_Edge>::iterator it = crossDist.begin(); it != crossDist.end(); it++){ MVertex* pVerta = it->first.getVertex(0); MVertex* pVertb = it->first.getVertex(1); double value = it->second*180./M_PI; if(it->first.length()) value /= it->first.length(); file << "SL (" << pVerta->x() << ", " << pVerta->y() << ", " << pVerta->z() << ", " << pVertb->x() << ", " << pVertb->y() << ", " << pVertb->z() << ")" << "{" << value << "," << value << "};\n"; } file << "};\n"; file.close(); } void Frame_field::checkAnnData(GEntity* ge, const std::string& filename){ #if defined(HAVE_ANN) std::ofstream file(filename.c_str()); file << "View \"ANN pairing\" {\n"; for(unsigned int i=0; i<ge->getNumMeshVertices(); i++){ MVertex* pVerta = ge->getMeshVertex(i); MVertex* pVertb = listVertices[findAnnIndex(pVerta->point())]; double value = pVerta->distance(pVertb); file << "SL (" << pVerta->x() << ", " << pVerta->y() << ", " << pVerta->z() << ", " << pVertb->x() << ", " << pVertb->y() << ", " << pVertb->z() << ")" << "{" << value << "," << value << "};\n"; } file << "};\n"; file.close(); #endif } #include "PView.h" #include "PViewDataList.h" void Frame_field::save_energy(GRegion* gr, const std::string& filename){ #ifdef HAVE_POST MElement* pElem; const int order = 1; const int NumNodes = 4; PViewDataList *data = new PViewDataList(); for(unsigned int i = 0; i < gr->getNumMeshElements(); i++){ pElem = gr->getMeshElement(i); MTetrahedron* pTet = new MTetrahedron(pElem->getVertex(0), pElem->getVertex(1), pElem->getVertex(2), pElem->getVertex(3)); //std::vector<double> *out = data->incrementList(1, TYPE_TET, NumNodes); std::vector<double> *out = data->incrementList(3, TYPE_TET, NumNodes); for(int j = 0; j < pTet->getNumVertices(); j++) out->push_back(pTet->getVertex(j)->x()); for(int j = 0; j < pTet->getNumVertices(); j++) out->push_back(pTet->getVertex(j)->y()); for(int j = 0; j < pTet->getNumVertices(); j++) out->push_back(pTet->getVertex(j)->z()); for(int j = 0; j < pTet->getNumVertices(); j++){ double u, v, w; pTet->getNode(j,u,v,w); double sf[4], gsf[4][3]; pTet->getShapeFunctions(u, v, w, sf, order); pTet->getGradShapeFunctions(u, v, w, gsf, order); double jac[3][3], inv[3][3]; pTet->getJacobian(u, v, w, jac); inv3x3(jac, inv); SVector3 sum(0,0,0); for(int k = 0; k < pTet->getNumEdges(); k++){ int nod1 = pTet->edges_tetra(k,0); int nod2 = pTet->edges_tetra(k,1); double grd1[3], grd2[3]; matvec(inv, gsf[nod1], grd1); matvec(inv, gsf[nod2], grd2); SVector3 esf = sf[nod1] * SVector3(grd2) - sf[nod2] * SVector3(grd1); std::map<MEdge, double, Less_Edge>::iterator it = crossDist.find(pTet->getEdge(k)); sum += it->second * esf; //sum += (pTet->getVertex(nod2)->z() - pTet->getVertex(nod1)->z()) * esf; } out->push_back(sum[0]); out->push_back(sum[1]); out->push_back(sum[2]); //out->push_back(sum.norm()); } delete pTet; } data->setName("energy"); //data->setFileName("energ.pos"); data->writePOS(filename + ".pos"); data->writeMSH(filename + ".msh"); data->finalize(); #endif } /****************class Size_field****************/ Size_field::Size_field(){} void Size_field::init_region(GRegion* gr){ #if defined(HAVE_ANN) unsigned int i; int j; int index; double h; double e; SPoint3 point; MElement* element; MVertex* vertex; GFace* gf; GModel* model = GModel::current(); std::list<GFace*> faces; std::list<GFace*>::iterator it; ANNpoint query; ANNidxArray indices; ANNdistArray distances; faces = gr->faces(); field.clear(); for(it=faces.begin();it!=faces.end();it++){ gf = *it; for(i=0;i<gf->storage1.size();i++){ point = gf->storage1[i]; h = gf->storage4[i]; field.push_back(std::pair<SPoint3,double>(point,h)); } } ANNpointArray duplicate = annAllocPts(field.size(),3); for(i=0;i<field.size();i++){ duplicate[i][0] = field[i].first.x(); duplicate[i][1] = field[i].first.y(); duplicate[i][2] = field[i].first.z(); } kd_tree = new ANNkd_tree(duplicate,field.size(),3); boundary.clear(); query = annAllocPt(3); indices = new ANNidx[1]; distances = new ANNdist[1]; index = 0; e = 0.0; for(it=faces.begin();it!=faces.end();it++){ gf = *it; for(i=0;i<gf->getNumMeshElements();i++){ element = gf->getMeshElement(i); for(j=0;j<element->getNumVertices();j++){ vertex = element->getVertex(j); query[0] = vertex->x(); query[1] = vertex->y(); query[2] = vertex->z(); kd_tree->annkSearch(query,1,indices,distances,e); index = indices[0]; boundary.insert(std::pair<MVertex*,double>(vertex,field[index].second)); } } } octree = new MElementOctree(model); annDeallocPt(query); delete[] indices; delete[] distances; #endif } void Size_field::solve(GRegion* gr){ #if defined(HAVE_PETSC) linearSystem<double>* system = 0; system = new linearSystemPETSc<double>; size_t i; int count; int count2; double val; double volume; std::set<MVertex*> interior; std::set<MVertex*>::iterator it; std::map<MVertex*,double>::iterator it2; interior.clear(); dofManager<double> assembler(system); count = 0; for(it2=boundary.begin();it2!=boundary.end();it2++){ assembler.fixVertex(it2->first,0,1,it2->second); count++; } //printf("\n"); //printf("number of boundary vertices = %d\n",count); for(i=0;i<gr->tetrahedra.size();i++){ interior.insert(gr->tetrahedra[i]->getVertex(0)); interior.insert(gr->tetrahedra[i]->getVertex(1)); interior.insert(gr->tetrahedra[i]->getVertex(2)); interior.insert(gr->tetrahedra[i]->getVertex(3)); } for(it=interior.begin();it!=interior.end();it++){ it2 = boundary.find(*it); if(it2==boundary.end()){ assembler.numberVertex(*it,0,1); } } for(i=0;i<gr->tetrahedra.size();i++){ gr->tetrahedra[i]->setVolumePositive(); } count2 = 0; volume = 0.0; simpleFunction<double> ONE(1.0); laplaceTerm term(0,1,&ONE); for(i=0;i<gr->tetrahedra.size();i++){ SElement se(gr->tetrahedra[i]); term.addToMatrix(assembler,&se); count2++; volume = volume + gr->tetrahedra[i]->getVolume(); } //printf("number of tetrahedra = %d\n",count2); //printf("volume = %f\n",volume); if(assembler.sizeOfR()){ system->systemSolve(); } for(it=interior.begin();it!=interior.end();it++){ assembler.getDofValue(*it,0,1,val); boundary.insert(std::pair<MVertex*,double>(*it,val)); } delete system; #endif } double Size_field::search(double x,double y,double z){ double u,v,w; double val; MElement* element; double temp1[3]; double temp2[3]; std::map<MVertex*,double>::iterator it1; std::map<MVertex*,double>::iterator it2; std::map<MVertex*,double>::iterator it3; std::map<MVertex*,double>::iterator it4; val = 1.0; element = (MElement*)octree->find(x,y,z,3,true); if(element!=NULL){ temp1[0] = x; temp1[1] = y; temp1[2] = z; element->xyz2uvw(temp1,temp2); u = temp2[0]; v = temp2[1]; w = temp2[2]; it1 = boundary.find(element->getVertex(0)); it2 = boundary.find(element->getVertex(1)); it3 = boundary.find(element->getVertex(2)); it4 = boundary.find(element->getVertex(3)); if(it1!=boundary.end() && it2!=boundary.end() && it3!=boundary.end() && it4!=boundary.end()){ val = (it1->second)*(1.0-u-v-w) + (it2->second)*u + (it3->second)*v + (it4->second)*w; } } return val; } void Size_field::print_field(GRegion* gr){ size_t i; double min,max; //double x,y,z; double x1,y1,z1,h1; double x2,y2,z2,h2; double x3,y3,z3,h3; double x4,y4,z4,h4; std::map<MVertex*,double>::iterator it; std::map<MVertex*,double>::iterator it1; std::map<MVertex*,double>::iterator it2; std::map<MVertex*,double>::iterator it3; std::map<MVertex*,double>::iterator it4; min = 1000000000.0; max = -1000000000.0; for(it=boundary.begin();it!=boundary.end();it++){ //x = (it->first)->x(); //y = (it->first)->y(); //z = (it->first)->z(); if(it->second>max){ max = it->second; } if(it->second<min){ min = it->second; } //printf("x = %f, y = %f, z = %f, mesh size = %f\n",x,y,z,it->second); } //printf("\n"); printf("min mesh size = %f\n",min); printf("max mesh size = %f\n",max); printf("total number of vertices = %zu\n",boundary.size()); printf("\n"); std::ofstream file("laplace.pos"); file << "View \"test\" {\n"; for(i=0;i<gr->tetrahedra.size();i++){ x1 = gr->tetrahedra[i]->getVertex(0)->x(); y1 = gr->tetrahedra[i]->getVertex(0)->y(); z1 = gr->tetrahedra[i]->getVertex(0)->z(); it1 = boundary.find(gr->tetrahedra[i]->getVertex(0)); x2 = gr->tetrahedra[i]->getVertex(1)->x(); y2 = gr->tetrahedra[i]->getVertex(1)->y(); z2 = gr->tetrahedra[i]->getVertex(1)->z(); it2 = boundary.find(gr->tetrahedra[i]->getVertex(1)); x3 = gr->tetrahedra[i]->getVertex(2)->x(); y3 = gr->tetrahedra[i]->getVertex(2)->y(); z3 = gr->tetrahedra[i]->getVertex(2)->z(); it3 = boundary.find(gr->tetrahedra[i]->getVertex(2)); x4 = gr->tetrahedra[i]->getVertex(3)->x(); y4 = gr->tetrahedra[i]->getVertex(3)->y(); z4 = gr->tetrahedra[i]->getVertex(3)->z(); it4 = boundary.find(gr->tetrahedra[i]->getVertex(3)); if(it1!=boundary.end() && it2!=boundary.end() && it3!=boundary.end() && it4!=boundary.end()){ h1 = it1->second; h2 = it2->second; h3 = it3->second; h4 = it4->second; file << "SS (" << x1 << ", " << y1 << ", " << z1 << ", " << x2 << ", " << y2 << ", " << z2 << ", " << x3 << ", " << y3 << ", " << z3 << ", " << x4 << ", " << y4 << ", " << z4 << "){" << h1 << ", " << h2 << ", " << h3 << ", " << h4 << "};\n"; } } file << "};\n"; } GRegion* Size_field::test(){ GRegion* gr; GModel* model = GModel::current(); gr = *(model->firstRegion()); return gr; } void Size_field::clear(){ delete octree; field.clear(); boundary.clear(); #if defined(HAVE_ANN) delete kd_tree->thePoints(); delete kd_tree; annClose(); #endif } /****************class Nearest_point****************/ Nearest_point::Nearest_point(){} void Nearest_point::init_region(GRegion* gr){ #if defined(HAVE_ANN) unsigned int i; int j; int gauss_num; double u,v; double x,y,z; double x1,y1,z1; double x2,y2,z2; double x3,y3,z3; MElement* element; GFace* gf; std::list<GFace*> faces; std::set<MVertex*> temp; std::list<GFace*>::iterator it; std::set<MVertex*>::iterator it2; fullMatrix<double> gauss_points; fullVector<double> gauss_weights; gaussIntegration::getTriangle(8,gauss_points,gauss_weights); gauss_num = gauss_points.size1(); faces = gr->faces(); field.clear(); vicinity.clear(); temp.clear(); for(it=faces.begin();it!=faces.end();it++){ gf = *it; for(i=0;i<gf->getNumMeshElements();i++){ element = gf->getMeshElement(i); x1 = element->getVertex(0)->x(); y1 = element->getVertex(0)->y(); z1 = element->getVertex(0)->z(); x2 = element->getVertex(1)->x(); y2 = element->getVertex(1)->y(); z2 = element->getVertex(1)->z(); x3 = element->getVertex(2)->x(); y3 = element->getVertex(2)->y(); z3 = element->getVertex(2)->z(); for(j=0;j<gauss_num;j++){ u = gauss_points(j,0); v = gauss_points(j,1); x = T(u,v,x1,x2,x3); y = T(u,v,y1,y2,y3); z = T(u,v,z1,z2,z3); field.push_back(SPoint3(x,y,z)); vicinity.push_back(element); } temp.insert(element->getVertex(0)); temp.insert(element->getVertex(1)); temp.insert(element->getVertex(2)); } } for(it2=temp.begin();it2!=temp.end();it2++){ x = (*it2)->x(); y = (*it2)->y(); z = (*it2)->z(); //field.push_back(SPoint3(x,y,z)); //vicinity.push_back(NULL); } ANNpointArray duplicate = annAllocPts(field.size(),3); for(i=0;i<field.size();i++){ duplicate[i][0] = field[i].x(); duplicate[i][1] = field[i].y(); duplicate[i][2] = field[i].z(); } kd_tree = new ANNkd_tree(duplicate,field.size(),3); #endif } bool Nearest_point::search(double x,double y,double z,SVector3& vec) { int index; bool val = false; #if defined(HAVE_ANN) double e; double e2; SPoint3 found; ANNpoint query; ANNidxArray indices; ANNdistArray distances; query = annAllocPt(3); query[0] = x; query[1] = y; query[2] = z; indices = new ANNidx[1]; distances = new ANNdist[1]; e = 0.0; kd_tree->annkSearch(query,1,indices,distances,e); index = indices[0]; annDeallocPt(query); delete[] indices; delete[] distances; if(vicinity[index]!=NULL){ found = closest(vicinity[index],SPoint3(x,y,z)); } else{ found = field[index]; } e2 = 0.000001; if(fabs(found.x()-x)>e2 || fabs(found.y()-y)>e2 || fabs(found.z()-z)>e2){ vec = SVector3(found.x()-x,found.y()-y,found.z()-z); vec.normalize(); val = 1; } else{ vec = SVector3(1.0,0.0,0.0); val = 0; } #endif return val; } double Nearest_point::T(double u,double v,double val1,double val2,double val3){ return (1.0-u-v)*val1 + u*val2 + v*val3; } //The following method comes from this page : gamedev.net/topic/552906-closest-point-on-triangle //It can also be found on this page : geometrictools.com/LibMathematics/Distance/Distance.html SPoint3 Nearest_point::closest(MElement* element,SPoint3 point){ SVector3 edge0 = SVector3(element->getVertex(1)->x()-element->getVertex(0)->x(),element->getVertex(1)->y()-element->getVertex(0)->y(), element->getVertex(1)->z()-element->getVertex(0)->z()); SVector3 edge1 = SVector3(element->getVertex(2)->x()-element->getVertex(0)->x(),element->getVertex(2)->y()-element->getVertex(0)->y(), element->getVertex(2)->z()-element->getVertex(0)->z()); SVector3 v0 = SVector3(element->getVertex(0)->x()-point.x(),element->getVertex(0)->y()-point.y(), element->getVertex(0)->z()-point.z()); double a = dot(edge0,edge0); double b = dot(edge0,edge1); double c = dot(edge1,edge1); double d = dot(edge0,v0); double e = dot(edge1,v0); double det = a*c-b*b; double s = b*e-c*d; double t = b*d-a*e; if(s+t<det){ if(s<0.0){ if(t<0.0){ if(d<0.0){ s = clamp(-d/a,0.0,1.0); t = 0.0; } else{ s = 0.0; t = clamp(-e/c,0.0,1.0); } } else{ s = 0.0; t = clamp(-e/c,0.0,1.0); } } else if(t<0.0){ s = clamp(-d/a,0.0,1.0); t = 0.0; } else{ double invDet = 1.0/det; s *= invDet; t *= invDet; } } else{ if(s<0.0){ double tmp0 = b+d; double tmp1 = c+e; if(tmp1>tmp0){ double numer = tmp1-tmp0; double denom = a-2.0*b+c; s = clamp(numer/denom,0.0,1.0); t = 1.0-s; } else{ t = clamp(-e/c,0.0,1.0); s = 0.0; } } else if(t<0.0){ if(a+d>b+e){ double numer = c+e-b-d; double denom = a-2.0*b+c; s = clamp(numer/denom,0.0,1.0); t = 1.0-s; } else{ s = clamp(-e/c,0.0,1.0); t = 0.0; } } else{ double numer = c+e-b-d; double denom = a-2.0*b+c; s = clamp(numer/denom,0.0,1.0); t = 1.0-s; } } return SPoint3(element->getVertex(0)->x()+s*edge0.x()+t*edge1.x(),element->getVertex(0)->y()+s*edge0.y()+t*edge1.y(), element->getVertex(0)->z()+s*edge0.z()+t*edge1.z()); } double Nearest_point::clamp(double x,double min,double max){ double val; val = x; if(val<min){ val = min; } else if(val>max){ val = max; } return val; } void Nearest_point::print_field(GRegion* gr){ unsigned int i; int j; bool val; double k; double x,y,z; MElement* element; MVertex* vertex; SVector3 vec; k = 0.05; std::ofstream file("nearest.pos"); file << "View \"test\" {\n"; for(i=0;i<gr->getNumMeshElements();i++){ element = gr->getMeshElement(i); for(j=0;j<element->getNumVertices();j++){ vertex = element->getVertex(j); x = vertex->x(); y = vertex->y(); z = vertex->z(); val = search(x,y,z,vec); if(val){ print_segment(SPoint3(x+k*vec.x(),y+k*vec.y(),z+k*vec.z()), SPoint3(x-k*vec.x(),y-k*vec.y(),z-k*vec.z()),file); } } } file << "};\n"; } void Nearest_point::print_segment(SPoint3 p1,SPoint3 p2,std::ofstream& file){ file << "SL (" << p1.x() << ", " << p1.y() << ", " << p1.z() << ", " << p2.x() << ", " << p2.y() << ", " << p2.z() << ")" << "{10, 20};\n"; } GRegion* Nearest_point::test(){ GRegion* gr; GModel* model = GModel::current(); gr = *(model->firstRegion()); return gr; } void Nearest_point::clear(){ field.clear(); vicinity.clear(); #if defined(HAVE_ANN) delete kd_tree->thePoints(); delete kd_tree; annClose(); #endif } /****************static declarations****************/ std::vector<std::pair<SPoint3,STensor3> > Frame_field::field; std::vector<int> Frame_field::labels; std::map<MVertex*, STensor3> Frame_field::crossField; std::map<MVertex*, double> Frame_field::crossFieldSmoothness; std::map<MEdge, double, Less_Edge> Frame_field::crossDist; std::map<MVertex*,std::set<MVertex*> > Frame_field::vertex_to_vertices; std::map<MVertex*,std::set<MElement*> > Frame_field::vertex_to_elements; std::vector<MVertex*> Frame_field::listVertices; #if defined(HAVE_ANN) ANNkd_tree* Frame_field::kd_tree; ANNkd_tree* Frame_field::annTree; #endif std::vector<std::pair<SPoint3,double> > Size_field::field; std::map<MVertex*,double> Size_field::boundary; MElementOctree* Size_field::octree; #if defined(HAVE_ANN) ANNkd_tree* Size_field::kd_tree; #endif std::vector<SPoint3> Nearest_point::field; std::vector<MElement*> Nearest_point::vicinity; #if defined(HAVE_ANN) ANNkd_tree* Nearest_point::kd_tree; #endif