diff --git a/Geo/discreteDiskFace.cpp b/Geo/discreteDiskFace.cpp index c5f62c5bfc68cda651342c895fcef362c5733be8..47085b4491741e7547531a8e8fa91f587eb5d2d6 100644 --- a/Geo/discreteDiskFace.cpp +++ b/Geo/discreteDiskFace.cpp @@ -3,6 +3,7 @@ // See the LICENSE.txt file for license information. Please report all // bugs and problems to the public mailing list <gmsh@geuz.org>. +#include <queue> // #mark #include <stdlib.h> #include "GmshConfig.h" @@ -23,18 +24,33 @@ #include "laplaceTerm.h" #include "convexLaplaceTerm.h" #include "convexCombinationTerm.h" // # +#include "BasisFactory.h" // The three things that are mandatory to manipulate octrees (octree in (u;v)). static void discreteDiskFaceBB(void *a, double*mmin, double*mmax) { // called once by buildOct() discreteDiskFaceTriangle *t = (discreteDiskFaceTriangle *)a; - mmin[0] = std::min(std::min(t->p1.x(), t->p2.x()), t->p3.x()); - mmin[1] = std::min(std::min(t->p1.y(), t->p2.y()), t->p3.y()); - mmax[0] = std::max(std::max(t->p1.x(), t->p2.x()), t->p3.x()); - mmax[1] = std::max(std::max(t->p1.y(), t->p2.y()), t->p3.y()); + + + mmin[0] = std::min(std::min(t->p[0].x(), t->p[1].x()), t->p[2].x()); + mmin[1] = std::min(std::min(t->p[0].y(), t->p[1].y()), t->p[2].y()); + mmax[0] = std::max(std::max(t->p[0].x(), t->p[1].x()), t->p[2].x()); + mmax[1] = std::max(std::max(t->p[0].y(), t->p[1].y()), t->p[2].y()); + + + if (t->tri->getPolynomialOrder() == 2){ + for (int i=3; i<6; i++){ + int j = i==5 ? 0 : i-2; + double du = t->p[i].x() - (t->p[i-3].x() + t->p[j].x())/2.; + double dv = t->p[i].y() - (t->p[i-3].y() + t->p[j].y())/2.; + mmin[0] = std::min(mmin[0],t->p[i].x()+du); + mmin[1] = std::min(mmin[1],t->p[i].y()+dv); + mmax[0] = std::max(mmax[0],t->p[i].x()+du); + mmax[1] = std::max(mmax[1],t->p[i].y()+dv); + } + } mmin[2] = -1; mmax[2] = 1; - const double dx = mmax[0] - mmin[0]; const double dy = mmax[1] - mmin[1]; const double eps = 0.0;//1.e-12; @@ -47,26 +63,44 @@ static void discreteDiskFaceBB(void *a, double*mmin, double*mmax) static void discreteDiskFaceCentroid(void *a, double*c) { // called once by buildOct() discreteDiskFaceTriangle *t = (discreteDiskFaceTriangle *)a; - c[0] = (t->p1.x() + t->p2.x() + t->p3.x()) / 3.0; - c[1] = (t->p1.y() + t->p2.y() + t->p3.y()) / 3.0; + c[0] = (t->p[0].x() + t->p[1].x() + t->p[2].x()) / 3.0; + c[1] = (t->p[0].y() + t->p[1].y() + t->p[2].y()) / 3.0; c[2] = 0.0; } -static int discreteDiskFaceInEle(void *a, double*c) +static int discreteDiskFaceInEle(void *a, double*c)// # mark { // called once by buildOct() + discreteDiskFaceTriangle *t = (discreteDiskFaceTriangle *)a; - double M[2][2], R[2], X[2]; + + double X[2]; const double eps = 1.e-8; - const SPoint3 p0 = t->p1; - const SPoint3 p1 = t->p2; - const SPoint3 p2 = t->p3; - M[0][0] = p1.x() - p0.x(); - M[0][1] = p2.x() - p0.x(); - M[1][0] = p1.y() - p0.y(); - M[1][1] = p2.y() - p0.y(); - R[0] = (c[0] - p0.x()); - R[1] = (c[1] - p0.y()); - sys2x2(M, R, X); + + + + if (t->tri->getPolynomialOrder() == 1){ + + double M[2][2], R[2]; + const SPoint3 p0 = t->p[0]; + const SPoint3 p1 = t->p[1]; + const SPoint3 p2 = t->p[2]; + M[0][0] = p1.x() - p0.x(); + M[0][1] = p2.x() - p0.x(); + M[1][0] = p1.y() - p0.y(); + M[1][1] = p2.y() - p0.y(); + R[0] = (c[0] - p0.x()); + R[1] = (c[1] - p0.y()); + sys2x2(M, R, X); + } + else{ + + double uv[3] = {c[0],c[1],0.}; + double Xi[3]; + t->tri->xyz2uvw(uv,Xi); + X[0] = Xi[0]; + X[1] = Xi[1]; + } + if(X[0] > -eps && X[1] > -eps && 1. - X[0] - X[1] > -eps) return 1; @@ -99,97 +133,301 @@ static bool orderVertices(const double &tot_length, const std::vector<MVertex*> } /*BUILDER*/ -discreteDiskFace::discreteDiskFace(GFace *gf, std::vector<MTriangle*> &mesh) : +discreteDiskFace::discreteDiskFace(GFace *gf, std::vector<MTriangle*> &mesh, int p) : GFace(gf->model(),123), _parent (gf) { - if (mesh.empty())return; - std::map<MVertex*,MVertex*> v2v; - for (unsigned int i=0;i<mesh.size();i++){ - MVertex *vs[3] = {NULL, NULL, NULL}; - for (int j=0;j<3;j++){ - MVertex *v = mesh[i]->getVertex(j); + + _order = p; + _N = (p+1)*(p+2)/2; + + int tagElementOrder; + switch (_order){ + case 1: + tagElementOrder = MSH_TRI_3; + break; + case 2: + tagElementOrder = MSH_TRI_6; + break; + case 3: + tagElementOrder = MSH_TRI_10; + break; + default: + Msg::Error("discreteDiskFace:: builder, tag is not (yet) covered for this order :-) "); + } + + mynodalbasis = BasisFactory::getNodalBasis(tagElementOrder); + fullMatrix<double> myNodes; + mynodalbasis->getReferenceNodes(myNodes); + + mybezierbasis = BasisFactory::getBezierBasis(TYPE_TRI,_order); + + std::map<MVertex*,MVertex*> v2v;// mesh vertex |-> face vertex + std::map<MEdge,std::vector<MVertex*>,Less_Edge> ed2nodes; // edge to interior node(s) + for (unsigned int i=0;i<mesh.size();i++){ // triangle by triangle + + std::vector<MVertex*> vs; // MTriangle vertices + for (unsigned int j=0; j<3; j++){ // loop over vertices AND edges of the current triangle + + MVertex *v = mesh[i]->getVertex(j);// firstly, edge vertices if (v->onWhat() == gf) { std::map<MVertex*,MVertex*> :: iterator it = v2v.find(v); if (it == v2v.end()){ MFaceVertex *vv = new MFaceVertex ( v->x(), v->y(), v->z(), this, 0, 0); v2v[v] = vv; discrete_vertices.push_back(vv); - vs[j] = vv; + vs.push_back(vv); } - else vs[j] = it->second; + else vs.push_back(it->second); } else if (v->onWhat()->dim() == 1){ if (v->onWhat()->geomType() == DiscreteCurve){ discreteEdge *de = dynamic_cast<discreteEdge*> (v->onWhat()); - vs[j] = de->getGeometricalVertex(v); + vs.push_back(de->getGeometricalVertex(v)); } + else Msg::Fatal("fatality"); } - else vs[j] = v; - } - discrete_triangles.push_back(new MTriangle (vs[0], vs[1], vs[2])); - } + else vs.push_back(v); + + + }// end loop over vertices and edges + if (_order >= 2) {// then, interior nodes :-) + double Xi, Eta, X, Y,Z; + + for (unsigned int ie=0; ie<3; ie++){ // firstly, edge interior nodes :-) + + MEdge me = mesh[i]->getEdge(ie); // check if edge already visited + if(ed2nodes.find(me) == ed2nodes.end()){ + + for(unsigned int iev=3+ie*(p-1);iev<3+(ie+1)*(p-1);iev++){ + Xi = myNodes(iev,0); + Eta = myNodes(iev,1); + + X = vs[0]->x()*(1.-Xi-Eta) + vs[1]->x()*Xi + vs[2]->x()*Eta; + Y = vs[0]->y()*(1.-Xi-Eta) + vs[1]->y()*Xi + vs[2]->y()*Eta; + Z = vs[0]->z()*(1.-Xi-Eta) + vs[1]->z()*Xi + vs[2]->z()*Eta; + + MVertex* mv = new MVertex(X,Y,Z,gf); + vs.push_back(mv); + ed2nodes[me].push_back(mv); + } + } + else{ + std::vector<MVertex*> vecmv = ed2nodes[me]; + for(unsigned int iev=0; iev<(p-1); iev++) + vs.push_back(vecmv[iev]); + } + } + + for (unsigned int iv=3*_order; iv<_N; iv++){ // then, volume nodes + + Xi = myNodes(iv,0); + Eta = myNodes(iv,1); + + X = vs[0]->x()*(1.-Xi-Eta) + vs[1]->x()*Xi + vs[2]->x()*Eta; + Y = vs[0]->y()*(1.-Xi-Eta) + vs[1]->y()*Xi + vs[2]->y()*Eta; + Z = vs[0]->z()*(1.-Xi-Eta) + vs[1]->z()*Xi + vs[2]->z()*Eta; + + vs.push_back(new MVertex(X,Y,Z,gf)); + } + }// end order > 2 + + if (_order==1) + discrete_triangles.push_back(new MTriangle (vs)); + + if (_order==2) + discrete_triangles.push_back(new MTriangle6 (vs)); + + if (_order > 2) + discrete_triangles.push_back(new MTriangleN (vs,(char)_order)); + + for(unsigned int check=0; check<_N; check++) + std::cout << "(" << vs[check]->x() << ";" << vs[check]->y() << ")\t"; + std::cout << "\n"; + for(unsigned int check=0; check<_N; check++) + std::cout << "(" << myNodes(check,0) << ";" << myNodes(check,1) << ")\t"; + std::cout << "\n"; + + }// end loop over triangles + + // delete MTriangle* and MVertex ? Y E S # mark + - // triangles = mesh; uv_kdtree = NULL; - kdtree = NULL; - // checkOrientation(); // mark, need to check after parametrization ? --> no ! (3D, cf. Seb) + kdtree = NULL; + std::cout << "buildAllNodes" << std::endl; buildAllNodes(); + std::cout << "getBoundingEdges" << std::endl; getBoundingEdges(); + std::cout << "orderVertices" << std::endl; orderVertices(_totLength, _U0, _coords); + std::cout << "parametrize" << std::endl; parametrize(); + std::cout << "buildOct" << std::endl; buildOct(); - // putOnView(); + std::cout << "checkOrientation" << std::endl; + checkOrientationUV(); + std::cout << "putOnView" << std::endl; + putOnView(); + std::cout << "discreteDiskFace: The parametrization of triangulation " << gf->tag() << " is ending." << std::endl; } + void discreteDiskFace::getBoundingEdges() { + + // first of all, all the triangles have to be oriented in the same way + std::map<MEdge,std::vector<MElement*>,Less_Edge> ed2tri; // edge to 1 or 2 triangle(s) + + for(unsigned int i = 0; i < discrete_triangles.size(); ++i){ + MElement *e = discrete_triangles[i]; + for(int j = 0; j < e->getNumEdges() ; j++){ + MEdge ed = e->getEdge(j); + ed2tri[ed].push_back(e); + } + } + + // element to its neighbors + std::map<MElement*,std::vector<MElement*> > neighbors; + for (unsigned int i=0; i<discrete_triangles.size(); ++i){ + MElement* e = discrete_triangles[i]; + for( unsigned int j=0; j<e->getNumEdges(); j++){ // #fixme: efficiency could be improved by setting neighbors mutually + std::vector<MElement*> my_mt = ed2tri[e->getEdge(j)]; + if (my_mt.size() > 1){// my_mt.size() = {1;2} + MElement* neighTri = my_mt[0] == e ? my_mt[1] : my_mt[0]; + neighbors[e].push_back(neighTri); + } + } + } + + + // queue: first in, first out + std::queue<MElement*> checkList; // element for reference orientation + std::queue< std::vector<MElement*> > checkLists; // corresponding neighbor element to be checked for its orientation + std::queue<MElement*> my_todo; // todo list + std::map<MElement*,bool> check_todo; // help to complete todo list + + my_todo.push(discrete_triangles[0]); + check_todo[discrete_triangles[0]]=true; + while(!my_todo.empty()){ + + MElement* myMT = my_todo.front(); + my_todo.pop(); + + std::vector<MElement*> myV = neighbors[myMT]; + std::vector<MElement*> myInsertion; + + checkList.push(myMT); + + for(unsigned int i=0; i<myV.size(); ++i){ + if (check_todo.find(myV[i]) == check_todo.end()){ + myInsertion.push_back(myV[i]); + check_todo[myV[i]] = true; + my_todo.push(myV[i]); + } + } + checkLists.push(myInsertion); + }// end while + + + while(!checkList.empty() && !checkLists.empty()){ + MElement* current = checkList.front(); + checkList.pop(); + std::vector<MElement*> neigs = checkLists.front(); + checkLists.pop(); + for (unsigned int i=0; i<neigs.size(); i++){ + bool myCond = false; + for (unsigned int k=0; k<3; k++){ + for (unsigned int j=0; j<3; j++){ + if (current->getVertex(k) == neigs[i]->getVertex(j)){ + myCond = true; + if (!(current->getVertex(k!=2 ?k+1 : 0 ) == neigs[i]->getVertex(j!=0 ? j-1 : 2) || + current->getVertex(k!=0 ?k-1 : 2 ) == neigs[i]->getVertex(j!=2 ? j+1 : 0))){ + neigs[i]->reverse(); + std::cout << "discreteDiskFace: triangle " << neigs[i]->getNum() << " has been reoriented." << std::endl; + } + break; + } + } + if (myCond) + break; + } + } // end for unsigned int i + } // end while + + + // now, it is possible to identify the border(s) of the triangulation // allEdges contains all edges of the boundary std::set<MEdge,Less_Edge> allEdges; - + for(unsigned int i = 0; i < discrete_triangles.size(); ++i){ MElement *e = discrete_triangles[i]; for(int j = 0; j < e->getNumEdges() ; j++){ MEdge ed = e->getEdge(j); std::set<MEdge,Less_Edge>::iterator it = allEdges.find(ed); - if (it == allEdges.end()) allEdges.insert(ed); - else allEdges.erase(it); + if (it == allEdges.end()) allEdges.insert(ed); + else allEdges.erase(it); } } - std::map<MVertex*,MVertex*> edges; // useless ? - std::map<MVertex*,MVertex*> firstNode2Edge; + std::map<MVertex*,std::vector<MVertex*> > firstNode2Edge; for (std::set<MEdge>::iterator ie = allEdges.begin(); ie != allEdges.end() ; ++ie) { - MEdge ed = *ie; - MVertex *first = ed.getVertex(0); - MVertex *last = ed.getVertex(1); + MEdge ed = *ie; - std::map<MVertex*,MVertex*>::iterator im = firstNode2Edge.find(first); - if (im != firstNode2Edge.end()) Msg::Fatal("Incorrect topology in discreteDiskFace %d", tag()); + std::vector<MElement *> vectri = ed2tri[ed]; + MElement* tri = vectri[0]; // boundary edge: only one triangle :-) + + std::vector<MVertex*> vecver; + tri->getEdgeVertices(edgeLocalNum(tri,ed),vecver); + MVertex *first = vecver[0]; + MVertex *last = vecver[1]; + vecver.erase(vecver.begin()); + vecver.erase(vecver.begin()); - firstNode2Edge[first] = last; + std::map<MVertex*,std::vector<MVertex*> >::iterator im = firstNode2Edge.find(first); + if (im != firstNode2Edge.end()) Msg::Fatal("Incorrect topology in discreteDiskFace %d", tag()); + + firstNode2Edge[first] = vecver; + firstNode2Edge[first].push_back(last); } - while (!firstNode2Edge.empty()) { // quid not empty but in within the map ? + while (!firstNode2Edge.empty()) { // quid 'firstNode2Edge' is not empty but 'in' within the map ? std::vector<MVertex*> loop; double length = 0.; - std::map<MVertex*,MVertex*>::iterator in = firstNode2Edge.begin(); + + std::map<MVertex*,std::vector<MVertex*> >::iterator in = firstNode2Edge.begin(); while(in != firstNode2Edge.end()) { MVertex *first = in->first; - MVertex *last = in->second; - length += sqrt( (last->x()-first->x()) * (last->x()-first->x()) + - (last->y()-first->y()) * (last->y()-first->y()) + - (last->z()-first->z()) * (last->z()-first->z()) ); + std::vector<MVertex*> myV = in->second; + loop.push_back(first); - firstNode2Edge.erase(in); - in = firstNode2Edge.find(last); - } - _loops.insert(std::make_pair(length,loop)); // it shouldn't be possible to have twice the same length ? mark - } + MVertex* previous = first; + + for(int i=0; i<=myV.size()-1; i++){ - // dirichlet BC + MVertex* current = myV[i]; + + std::cout << "(" << current->x() << ";" << current->y() << ")" << std::endl; + + loop.push_back(current); + + length += sqrt( (current->x()-previous->x()) * (current->x()-previous->x()) + + (current->y()-previous->y()) * (current->y()-previous->y()) + + (current->z()-previous->z()) * (current->z()-previous->z()) ); + + _loops.insert(std::make_pair(length,loop)); // it shouldn't be possible to have twice the same length ? actually, it is possible, but quite seldom #fixme ----> multimap ? + + previous = current; + + } + firstNode2Edge.erase(in); + in = firstNode2Edge.find(previous); + }// end while in + } // end while firstNode2Edge + + // dirichlet BC _U0 = _loops.rbegin()->second; _totLength = _loops.rbegin()->first; } @@ -198,21 +436,26 @@ void discreteDiskFace::buildOct() const { SBoundingBox3d bb; int count = 0; - for(unsigned int i = 0; i < discrete_triangles.size(); ++i){ MTriangle *t = discrete_triangles[i]; //create bounding box - for(int j = 0; j < 3; j++){ + for(int j = 0; j < t->getNumVertices(); j++){ std::map<MVertex*,SPoint3>::const_iterator itj = coordinates.find(t->getVertex(j)); - _coordPoints.insert(std::make_pair(t->getVertex(j)->point(), itj->second));// <tr(x;y;z);tr(u;v)> - bb += SPoint3(itj->second.x(),itj->second.y(),0.0); + _coordPoints.insert(std::make_pair(t->getVertex(j)->point(), itj->second));// <tr(x;y;z);tr(u;v)> + if (_order == 2 && j>2){ + int ij = j == 5 ? 0 : j-2; + double du = itj->second.x() - (t->getVertex(j-3)->x()+t->getVertex(ij)->x())/2.; + double dv = itj->second.y() - (t->getVertex(j-3)->y()+t->getVertex(ij)->y())/2.; + bb += SPoint3(itj->second.x()+du,itj->second.y()+dv,0.); + } + else + bb += SPoint3(itj->second.x(), itj->second.y(),0.); } count++; } - //ANN octree - std::set<MVertex*> allVS; // ? useless ? - ANNpointArray nodes = annAllocPts(count, 3); + // ANN octree + ANNpointArray nodes = annAllocPts(count, _N); // make bounding box SPoint3 bbmin = bb.min(), bbmax = bb.max(); @@ -227,81 +470,90 @@ void discreteDiskFace::buildOct() const discreteDiskFaceCentroid, discreteDiskFaceInEle); count = 0; - for(unsigned int i = 0; i < discrete_triangles.size(); ++i){ MTriangle *t = discrete_triangles[i]; - std::map<MVertex*,SPoint3>::const_iterator it0 = - coordinates.find(t->getVertex(0)); - std::map<MVertex*,SPoint3>::const_iterator it1 = - coordinates.find(t->getVertex(1)); - std::map<MVertex*,SPoint3>::const_iterator it2 = - coordinates.find(t->getVertex(2)); - _ddft[count].p1 = it0->second; - _ddft[count].p2 = it1->second; - _ddft[count].p3 = it2->second; + discreteDiskFaceTriangle* my_ddft = &_ddft[count]; + init_ddft(my_ddft); // #fixme destructor + for(unsigned int io=0; io<_N; io++){ + std::map<MVertex*,SPoint3>::const_iterator it = + coordinates.find(t->getVertex(io)); + my_ddft->p[io] = it->second; + } if(geomType() != GEntity::DiscreteDiskSurface){// CAD if (t->getVertex(0)->onWhat()->dim() == 2){ - reparamMeshEdgeOnFace(t->getVertex(0), t->getVertex(1), _parent, - _ddft[count].gfp1, _ddft[count].gfp2); - reparamMeshEdgeOnFace(t->getVertex(0), t->getVertex(2), _parent, - _ddft[count].gfp1, _ddft[count].gfp3); + for(unsigned int io=1; io<_N; io++) + reparamMeshEdgeOnFace(t->getVertex(0), t->getVertex(io), _parent, + my_ddft->gfp[0], my_ddft->gfp[io]); } else if (t->getVertex(1)->onWhat()->dim() == 2){ - reparamMeshEdgeOnFace(t->getVertex(1), t->getVertex(0), _parent, - _ddft[count].gfp2, _ddft[count].gfp1); - reparamMeshEdgeOnFace(t->getVertex(1), t->getVertex(2), _parent, - _ddft[count].gfp2, _ddft[count].gfp3); + for(unsigned int io=0; io<_N; io++) + if (io != 1) + reparamMeshEdgeOnFace(t->getVertex(1), t->getVertex(io), _parent, + my_ddft->gfp[1], my_ddft->gfp[io]); } else if (t->getVertex(2)->onWhat()->dim() == 2){ - reparamMeshEdgeOnFace(t->getVertex(2), t->getVertex(0), _parent, - _ddft[count].gfp3, _ddft[count].gfp1); - reparamMeshEdgeOnFace(t->getVertex(2), t->getVertex(1), _parent, - _ddft[count].gfp3, _ddft[count].gfp2); + for(unsigned int io=0; io<_N; io++) + if (io != 2) + reparamMeshEdgeOnFace(t->getVertex(2), t->getVertex(io), _parent, + my_ddft->gfp[2], my_ddft->gfp[io]); + } + else {// quid interior vertices ? + for(unsigned int io=0; io<_N; io++) + reparamMeshVertexOnFace(t->getVertex(io), _parent, my_ddft->gfp[io]); } - else { - reparamMeshVertexOnFace(t->getVertex(0), _parent, _ddft[count].gfp1); - reparamMeshVertexOnFace(t->getVertex(1), _parent, _ddft[count].gfp2); - reparamMeshVertexOnFace(t->getVertex(2), _parent, _ddft[count].gfp3); + } + for(unsigned int io=0; io<_N; io++) + my_ddft->v[io] = SPoint3(t->getVertex(io)->x(), t->getVertex(io)->y(), + t->getVertex(io)->z()); + + my_ddft->gf = _parent; + my_ddft->tri = t; + + SVector3 dXdxi (my_ddft->v[1] - my_ddft->v[0]); // constant + SVector3 dXdeta(my_ddft->v[2] - my_ddft->v[0]); // constant + + double grads[_N][3];// u,v,w=0,grads + for(unsigned int myI=0; myI<t->getNumVertices(); myI++){ + double U,V,W; + t->getNode(myI,U,V,W); // Xi Eta + mynodalbasis->df(U,V,0,grads); + + //compute first derivatives for every triangle + // (dXi/dU)^-1 = dU/dXi + double mat[2][2] = {{0.,0.},{0.,0.}}; + for(unsigned int io=0; io<_N; io++){ + for (unsigned int ic=0; ic<2; ic++){ + mat[0][ic] += my_ddft->p[io].x() * grads[io][ic]; + mat[1][ic] += my_ddft->p[io].y() * grads[io][ic]; + } } + + double inv[2][2]; + inv2x2(mat,inv); + + SVector3 dXdu(dXdxi * inv[0][0] + dXdeta * inv[1][0]); + SVector3 dXdv(dXdxi * inv[0][1] + dXdeta * inv[1][1]); + firstElemDerivatives[(MElement*)t].push_back(Pair<SVector3,SVector3>(dXdu,dXdv)); } - _ddft[count].v1 = SPoint3(t->getVertex(0)->x(), t->getVertex(0)->y(), - t->getVertex(0)->z()); - _ddft[count].v2 = SPoint3(t->getVertex(1)->x(), t->getVertex(1)->y(), - t->getVertex(1)->z()); - _ddft[count].v3 = SPoint3(t->getVertex(2)->x(), t->getVertex(2)->y(), - t->getVertex(2)->z()); - _ddft[count].gf = _parent; - _ddft[count].tri = t; - - - //compute first derivatives for every triangle , to disappear (erase) - double mat[2][2] = {{_ddft[count].p2.x() - _ddft[count].p1.x(), - _ddft[count].p3.x() - _ddft[count].p1.x()}, - {_ddft[count].p2.y() - _ddft[count].p1.y(), - _ddft[count].p3.y() - _ddft[count].p1.y()}}; // modified higher - - double inv[2][2]; - inv2x2(mat, inv); - SVector3 dXdxi (_ddft[count].v2 - _ddft[count].v1); // constant - SVector3 dXdeta(_ddft[count].v3 - _ddft[count].v1); // constant - SVector3 dXdu(dXdxi * inv[0][0] + dXdeta * inv[1][0]); // to be modified for higher order - SVector3 dXdv(dXdxi * inv[0][1] + dXdeta * inv[1][1]); // to be modified for higher order - firstElemDerivatives[(MElement*)t] = Pair<SVector3,SVector3>(dXdu,dXdv); - - nodes[count][0] = (it0->second.x() + it1->second.x() + it2->second.x())/3.0 ; - nodes[count][1] = (it0->second.y() + it1->second.y() + it2->second.y())/3.0 ; - nodes[count][2] = 0.0; - - Octree_Insert(&_ddft[count], oct); + nodes[count][0] = 0.; + nodes[count][1] = 0.; + nodes[count][2] = 0.; + for(unsigned int io=0; io<_N; io++){ + nodes[count][0] += my_ddft->p[io].x(); + nodes[count][1] += my_ddft->p[io].y(); + } + nodes[count][0] /= (double) _N;// #notsure + nodes[count][1] /= (double) _N; + + Octree_Insert(my_ddft, oct); count++; - } + }// end big for over mesh[i] Octree_Arrange(oct); - // USELESS, laplacian //smooth first derivatives at vertices if(adjv.size() == 0){ - std::vector<MTriangle*> allTri; + std::vector<MTriangle*> allTri; // allTri.insert(allTri.end(), discrete_triangles.begin(), discrete_triangles.end() ); buildVertexToTriangle(allTri, adjv); } @@ -311,15 +563,16 @@ void discreteDiskFace::buildOct() const SVector3 dXdu(0.0), dXdv(0.0); int nbTri = vTri.size(); for (int j = 0; j < nbTri; j++){ // elements's contribution for a vertex - dXdu += firstElemDerivatives[vTri[j]].first(); - dXdv += firstElemDerivatives[vTri[j]].second(); + std::vector<Pair<SVector3,SVector3> > myVec = firstElemDerivatives[vTri[j]]; + dXdu += myVec[nodeLocalNum(vTri[j],v)].first(); + dXdv += myVec[nodeLocalNum(vTri[j],v)].second(); } dXdu *= 1./nbTri; dXdv *= 1./nbTri; firstDerivatives[v] = Pair<SVector3, SVector3>(dXdu, dXdv); } - kdtree = new ANNkd_tree(nodes, count, 3); + kdtree = new ANNkd_tree(nodes, count, _N); // #notsure } @@ -347,14 +600,10 @@ bool discreteDiskFace::parametrize() const for(size_t i = 0; i < discrete_triangles.size(); ++i){ MTriangle *t = discrete_triangles[i]; - - myAssemblerU.numberVertex(t->getVertex(0), 0, 1); - myAssemblerU.numberVertex(t->getVertex(1), 0, 1); - myAssemblerU.numberVertex(t->getVertex(2), 0, 1); - - myAssemblerV.numberVertex(t->getVertex(0), 0, 1); - myAssemblerV.numberVertex(t->getVertex(1), 0, 1); - myAssemblerV.numberVertex(t->getVertex(2), 0, 1); + for(unsigned int j=0; j<t->getNumVertices(); j++){ + myAssemblerU.numberVertex(t->getVertex(j), 0, 1); + myAssemblerV.numberVertex(t->getVertex(j), 0, 1); + } } @@ -372,10 +621,7 @@ bool discreteDiskFace::parametrize() const SElement se(discrete_triangles[i]); mappingU.addToMatrix(myAssemblerU, &se); mappingV.addToMatrix(myAssemblerV, &se); - } - - - // lsys_v->printMatlab("testv.m"); + } double t2 = Cpu(); @@ -396,7 +642,7 @@ bool discreteDiskFace::parametrize() const p[1] = value_V; coordinates[v] = p; } - else{ + else{ // #useful ? itf->second[0]= value_U; itf->second[1]= value_V; } @@ -414,39 +660,76 @@ void discreteDiskFace::getTriangleUV(const double u,const double v, double &_u, double &_v)const{ double uv[3] = {u,v,0.}; *mt = (discreteDiskFaceTriangle*) Octree_Search(uv,oct); - if (!(*mt))return; - - double M[2][2],X[2],R[2]; - const SPoint3 p0 = (*mt)->p1; - const SPoint3 p1 = (*mt)->p2; - const SPoint3 p2 = (*mt)->p3; - M[0][0] = p1.x() - p0.x(); - M[0][1] = p2.x() - p0.x(); - M[1][0] = p1.y() - p0.y(); - M[1][1] = p2.y() - p0.y(); - R[0] = (u - p0.x()); - R[1] = (v - p0.y()); - sys2x2(M, R, X); - _u = X[0]; - _v = X[1]; + if (!(*mt)) return; + + if (_order == 1){ + double M[2][2],X[2],R[2]; + const SPoint3 p0 = (*mt)->p[0]; + const SPoint3 p1 = (*mt)->p[1]; + const SPoint3 p2 = (*mt)->p[2]; + M[0][0] = p1.x() - p0.x(); + M[0][1] = p2.x() - p0.x(); + M[1][0] = p1.y() - p0.y(); + M[1][1] = p2.y() - p0.y(); + R[0] = (u - p0.x()); + R[1] = (v - p0.y()); + sys2x2(M, R, X); + _u = X[0];// xi + _v = X[1];// eta + } + else{// newton raphson + discreteDiskFaceTriangle *my_ddft = *mt; + double Xi[3]; + my_ddft->tri->xyz2uvw(uv,Xi); + _u = Xi[0]; + _v = Xi[1]; + } +} +void discreteDiskFace::checkOrientationUV(){ + + double initial, current; // initial and current orientation + discreteDiskFaceTriangle *ct; + ct = &_ddft[0]; + double p1[2] = {ct->p[0].x(), ct->p[0].y()}; + double p2[2] = {ct->p[1].x(), ct->p[1].y()}; + double p3[2] = {ct->p[2].x(), ct->p[2].y()}; + initial = robustPredicates::orient2d(p1, p2, p3); + unsigned int i=1; + for (; i<discrete_triangles.size(); i++){ + ct = &_ddft[i]; + p1[0] = ct->p[0].x(); p1[1] = ct->p[0].y(); + p2[0] = ct->p[1].x(); p2[1] = ct->p[1].y(); + p3[0] = ct->p[2].x(); p3[1] = ct->p[2].y(); + current = robustPredicates::orient2d(p1, p2, p3); + if(initial*current < 0.) break; + } + if(i < discrete_triangles.size()) + Msg::Error("discreteDiskFace: The parametrization is not one-to-one :-("); + else + std::cout << "discreteDiskFace: The parametrization is one-to-one :-)" << std::endl; + } // (u;v) |-> < (x;y;z); GFace; (u;v) > GPoint discreteDiskFace::point(const double par1, const double par2) const { - double U,V; double par[2] = {par1,par2}; discreteDiskFaceTriangle* dt; - getTriangleUV(par1,par2,&dt,U,V); + getTriangleUV(par1,par2,&dt,U,V);// return Xi,Eta if (!dt) { GPoint gp = GPoint(1.e22,1.e22,1.e22,_parent,par); gp.setNoSuccess(); return gp; } - SPoint3 p = dt->v1*(1.-U-V) + dt->v2*U + dt->v3*V; + //polynomialBasis myPolynomial = polynomialBasis(dt->tri->getTypeForMSH()); + double eval[_N]; + mynodalbasis->f(U,V,0.,eval);//#mark + SPoint3 p; + for(int io=0; io<_N; io++) + p += dt->v[io]*eval[io]; return GPoint(p.x(),p.y(),p.z(),_parent,par); } @@ -469,13 +752,13 @@ SPoint2 discreteDiskFace::parFromVertex(MVertex *v) const if (de){ MVertex *v1,*v2; double xi; - de->interpolateInGeometry (v,&v1,&v2,xi); + de->interpolateInGeometry (v,&v1,&v2,xi); // modify std::map<MVertex*,SPoint3>::iterator it1 = coordinates.find(v1); std::map<MVertex*,SPoint3>::iterator it2 = coordinates.find(v2); if(it1 == coordinates.end()) Msg::Fatal("FIXME TO DO %d %s",__LINE__,__FILE__); if(it2 == coordinates.end()) Msg::Fatal("FIXME TO DO %d %s",__LINE__,__FILE__); return SPoint2(it1->second.x(),it1->second.y()) * (1.-xi) + - SPoint2(it2->second.x(),it2->second.y()) * xi; + SPoint2(it2->second.x(),it2->second.y()) * xi; // modify } } Msg::Fatal("FIXME TO DO %d %s",__LINE__,__FILE__); @@ -506,7 +789,6 @@ double discreteDiskFace::curvatures(const SPoint2 ¶m, SVector3 *dirMax, SVec Pair<SVector3, SVector3> discreteDiskFace::firstDer(const SPoint2 ¶m) const { - double U,V; discreteDiskFaceTriangle* ddft; getTriangleUV(param.x(),param.y(),&ddft,U,V); @@ -517,34 +799,26 @@ Pair<SVector3, SVector3> discreteDiskFace::firstDer(const SPoint2 ¶m) const Msg::Warning("discreteDiskFace::firstDer << triangle not found %g %g",param[0],param[1]); return Pair<SVector3, SVector3>(SVector3(1,0,0), SVector3(0,1,0)); } + + SVector3 dXdU = 0.;//dXdu1*(1.-U-V) + dXdu2*U + dXdu3*V; + SVector3 dXdV = 0.;//dXdv1*(1.-U-V) + dXdv2*U + dXdv3*V; + + double eval[_N]; + mynodalbasis->f(U,V,0.,eval); //#mark + + for (unsigned int io=0; io<_N; io++){ + std::map<MVertex*, Pair<SVector3,SVector3> >::iterator it = + firstDerivatives.find(tri->getVertex(io)); + if (it == firstDerivatives.end()) Msg::Fatal ("Vertex %d (%d) has no firstDerivatives", + tri->getVertex(io)->getNum(),io); + SVector3 dXdu = it->second.first(); + SVector3 dXdv = it->second.second(); + + dXdU += dXdu * eval[io]; + dXdV += dXdv * eval[io]; + } - std::map<MVertex*, Pair<SVector3,SVector3> >::iterator it0 = - firstDerivatives.find(tri->getVertex(0)); - if (it0 == firstDerivatives.end()) Msg::Fatal ("Vertex %d (0) has no firstDerivatives", - tri->getVertex(0)->getNum()); - std::map<MVertex*, Pair<SVector3,SVector3> >::iterator it1 = - firstDerivatives.find(tri->getVertex(1)); - if (it1 == firstDerivatives.end()) Msg::Fatal ("Vertex %d (1) has no firstDerivatives", - tri->getVertex(1)->getNum()); - std::map<MVertex*, Pair<SVector3,SVector3> >::iterator it2 = - firstDerivatives.find(tri->getVertex(2)); - if (it2 == firstDerivatives.end()) Msg::Fatal ("Vertex %d (2) has no firstDerivatives", - tri->getVertex(2)->getNum()); - - - SVector3 dXdu1 = it0->second.first(); - SVector3 dXdu2 = it1->second.first(); - SVector3 dXdu3 = it2->second.first(); - - SVector3 dXdv1 = it0->second.second(); - SVector3 dXdv2 = it1->second.second(); - SVector3 dXdv3 = it2->second.second(); - - SVector3 dXdu = dXdu1*(1.-U-V) + dXdu2*U + dXdu3*V; - SVector3 dXdv = dXdv1*(1.-U-V) + dXdv2*U + dXdv3*V; - - - return Pair<SVector3, SVector3>(dXdu,dXdv); + return Pair<SVector3, SVector3>(dXdU,dXdV); } @@ -572,17 +846,64 @@ void discreteDiskFace::buildAllNodes() void discreteDiskFace::putOnView() { + + + + FILE* view_u = Fopen("param_u.pos","w"); + FILE* view_v = Fopen("param_v.pos","w"); + FILE* UVxyz = Fopen("UVxyz.pos","w"); + if(view_u && view_v){ + fprintf(view_u,"View \"paramU\"{\n"); + fprintf(view_v,"View \"paramV\"{\n"); + fprintf(UVxyz,"View \"Uxyz\"{\n"); + for (unsigned int i=0; i<discrete_triangles.size(); i++){ + discreteDiskFaceTriangle* my_ddft = &_ddft[i]; + if (_order == 1){ + fprintf(view_u,"ST("); + fprintf(view_v,"ST("); + fprintf(UVxyz,"ST("); + } + else{ + fprintf(view_u,"ST%d(",_order); + fprintf(view_v,"ST%d(",_order); + fprintf(UVxyz,"ST%d(",_order); + } + for (unsigned int j=0; j<_N-1; j++){ + fprintf(view_u,"%g,%g,%g,",my_ddft->v[j].x(),my_ddft->v[j].y(),my_ddft->v[j].z()); + fprintf(view_v,"%g,%g,%g,",my_ddft->v[j].x(),my_ddft->v[j].y(),my_ddft->v[j].z()); + fprintf(UVxyz,"%g,%g,%g,",my_ddft->p[j].x(),my_ddft->p[j].y(),0.); + } + fprintf(view_u,"%g,%g,%g){",my_ddft->v[_N-1].x(),my_ddft->v[_N-1].y(),my_ddft->v[_N-1].z()); + fprintf(view_v,"%g,%g,%g){",my_ddft->v[_N-1].x(),my_ddft->v[_N-1].y(),my_ddft->v[_N-1].z()); + fprintf(UVxyz,"%g,%g,%g){",my_ddft->p[_N-1].x(),my_ddft->p[_N-1].y(),0.); + for (unsigned int j=0; j<_N-1; j++){ + fprintf(view_u,"%g,",my_ddft->p[j].x()); + fprintf(view_v,"%g,",my_ddft->p[j].y()); + fprintf(UVxyz,"%g,",sqrt(my_ddft->v[j].x()*my_ddft->v[j].x()+my_ddft->v[j].z()*my_ddft->v[j].z()+my_ddft->v[j].y()*my_ddft->v[j].y())); + } + fprintf(view_u,"%g};\n",my_ddft->p[_N-1].x()); + fprintf(view_v,"%g};\n",my_ddft->p[_N-1].y()); + fprintf(UVxyz,"%g};\n",sqrt(my_ddft->v[_N-1].x()*my_ddft->v[_N-1].x()+my_ddft->v[_N-1].z()*my_ddft->v[_N-1].z()+my_ddft->v[_N-1].y()*my_ddft->v[_N-1].y())); + } + fprintf(view_u,"};\n"); + fprintf(view_v,"};\n"); + fprintf(UVxyz,"};\n"); + fclose(view_u); + fclose(view_v); + fclose(UVxyz); + } + + /* #ifdef HAVE_POST std::map<int, std::vector<double> > u; std::map<int, std::vector<double> > v; - for(std::set<MVertex*>::iterator iv = allNodes.begin(); iv!=allNodes.end(); ++iv){ MVertex *p = *iv; u[p->getNum()].push_back(coordinates[p].x()); v[p->getNum()].push_back(coordinates[p].y()); } PView* view_u = new PView("u", "NodeData", GModel::current(), u); - PView* view_v = new PView("u", "NodeData", GModel::current(), v); + PView* view_v = new PView("v", "NodeData", GModel::current(), v); view_u->setChanged(true); view_v->setChanged(true); view_u->write("param_u.msh", 5); @@ -592,6 +913,7 @@ void discreteDiskFace::putOnView() #else Msg::Error("discreteDiskFace: cannot export without post module") #endif + */ } // useful for mesh generators ---------------------------------------- @@ -614,10 +936,8 @@ GPoint discreteDiskFace::intersectionWithCircle(const SVector3 &n1, const SVecto // the point is situated in the half plane defined // by direction n1 and point p (exclude the one on the // other side) - - SVector3 t1 = ct->v2 - ct->v1; - SVector3 t2 = ct->v3 - ct->v1; - + SVector3 t1 = ct->v[1] - ct->v[0]; + SVector3 t2 = ct->v[2] - ct->v[0]; // let us first compute point q to be the intersection // of the plane of the triangle with the line L = p + t n1 // Compute w = t1 x t2 = (a,b,c) and write a point of the plabe as @@ -626,15 +946,13 @@ GPoint discreteDiskFace::intersectionWithCircle(const SVector3 &n1, const SVecto // a (p_x + t n1_x) + a (p_y + t n1_y) + c (p_z + t n1_z) - // (v1_x a + v1_y b + v1_z * c) = 0 // gives t - SVector3 w = crossprod(t1,t2); double t = d; // if everything is not coplanar ... if (fabs(dot(n1,w)) > 1.e-12){ - t = dot(ct->v1-p,w)/dot(n1,w); + t = dot(ct->v[0]-p,w)/dot(n1,w); } SVector3 q = p + n1*t; - // consider the line that intersects both planes in its // parametric form // X(x,y,z) = q + t m @@ -650,12 +968,10 @@ GPoint discreteDiskFace::intersectionWithCircle(const SVector3 &n1, const SVecto // we choose the one that corresponds to (s_i - p) . n1 > 0 SVector3 m = crossprod(w,n); - const double a = dot(m,m); const double b = 2*dot(m,q-p); const double c = dot(q-p,q-p) - d*d; const double delta = b*b-4*a*c; - if (delta >= 0){ const double ta = (-b + sqrt(delta)) / (2.*a); const double tb = (-b - sqrt(delta)) / (2.*a); @@ -681,20 +997,20 @@ GPoint discreteDiskFace::intersectionWithCircle(const SVector3 &n1, const SVecto mat[0][0] = dot(t1,t1); mat[1][1] = dot(t2,t2); mat[0][1] = mat[1][0] = dot(t1,t2); - b[0] = dot(s-ct->v1,t1) ; - b[1] = dot(s-ct->v1,t2) ; + b[0] = dot(s-ct->v[0],t1) ; + b[1] = dot(s-ct->v[0],t2) ; sys2x2(mat,b,uv); // check now if the point is inside the triangle if (uv[0] >= -1.e-6 && uv[1] >= -1.e-6 && 1.-uv[0]-uv[1] >= -1.e-6 ) { SVector3 pp = - ct->p1 * ( 1.-uv[0]-uv[1] ) + - ct->p2 *uv[0] + - ct->p3 *uv[1] ; + ct->p[0] * ( 1.-uv[0]-uv[1] ) + + ct->p[1] * uv[0] + + ct->p[2] * uv[1] ; return GPoint(s.x(),s.y(),s.z(),this,pp); } } - } + } GPoint pp(0); pp.setNoSuccess(); Msg::Debug("ARGG no success intersection circle"); @@ -702,4 +1018,6 @@ GPoint discreteDiskFace::intersectionWithCircle(const SVector3 &n1, const SVecto } + + #endif diff --git a/Geo/discreteDiskFace.h b/Geo/discreteDiskFace.h index 6aa25db7a7231383a4a4e342e51515c00ccbb075..ee37d5959837b3b8d2042440df3409d68c03c622 100644 --- a/Geo/discreteDiskFace.h +++ b/Geo/discreteDiskFace.h @@ -21,6 +21,7 @@ #include "MElementOctree.h" #include "meshGFaceOptimize.h" #include "PView.h" +#include "robustPredicates.h" class ANNkd_tree; class Octree; @@ -29,9 +30,9 @@ class GRbf; class discreteDiskFaceTriangle { public: - SPoint3 p1, p2, p3; // vertices in (u;v) - SPoint2 gfp1, gfp2, gfp3; // CAD model - SPoint3 v1, v2, v3; // vertices in (x;y;z) + SPoint3* p; // vertices in (u;v) + SPoint2* gfp; // CAD model + SPoint3* v;// vertices in (x;y;z) GFace *gf; // GFace tag MTriangle *tri; // mesh triangle in (x;y;z) discreteDiskFaceTriangle() : gf(0), tri(0) {} @@ -41,14 +42,14 @@ class discreteDiskFaceTriangle { class discreteDiskFace : public GFace { GFace *_parent; - // bool checkOrientation(int iter, bool moveBoundaries=false) const; // mark todo void buildOct() const; bool parametrize() const; void buildAllNodes() ; void getBoundingEdges(); void putOnView(); + public: - discreteDiskFace(GFace *parent, std::vector<MTriangle*> &mesh); + discreteDiskFace(GFace *parent, std::vector<MTriangle*> &mesh, int p);// MTriangle -> MTriangle 6 virtual ~discreteDiskFace() {triangles.clear();} void getTriangleUV(const double u,const double v,discreteDiskFaceTriangle **mt, double &_u, double &_v) const; GPoint point(double par1, double par2) const; @@ -63,12 +64,31 @@ class discreteDiskFace : public GFace { GPoint intersectionWithCircle(const SVector3 &n1, const SVector3 &n2, const SVector3 &p, const double &d, double uv[2]) const; + void checkOrientationUV(); protected: //------------------------------------------------ // a copy of the mesh that should not be destroyed - std::vector<MTriangle*> discrete_triangles; + std::vector<MTriangle*> discrete_triangles; // MTriangleN AND MTriangle6 are children of MTriangle std::vector<MVertex*> discrete_vertices; //------------------------------------------------ + int nodeLocalNum(MElement* e, MVertex* v) const{ + for(unsigned int i=0; i<e->getNumVertices(); i++) + if (v == e->getVertex(i)) + return i; + }; + int edgeLocalNum(MElement* e, MEdge ed) const{ + for(unsigned int i=0; i<e->getNumEdges(); i++) + if (ed == e->getEdge(i)) + return i; + }; + void init_ddft(discreteDiskFaceTriangle* ddft) const{ + ddft->p = new SPoint3[_N]; + ddft->gfp = new SPoint2[_N]; + ddft->v = new SPoint3[_N]; + }; + //------------------------------------------------ + int _order; + int _N; double _totLength; std::map<double,std::vector<MVertex*> > _loops; std::vector<MVertex*> _U0; // dirichlet's bc's @@ -77,13 +97,14 @@ class discreteDiskFace : public GFace { mutable std::map<SPoint3,SPoint3 > _coordPoints; // ? mutable v2t_cont adjv; // ? v2t_cont ? ????? mutable std::map<MVertex*, Pair<SVector3,SVector3> > firstDerivatives; - mutable std::map<MElement*, Pair<SVector3,SVector3> > firstElemDerivatives; + mutable std::map<MElement*, std::vector<Pair<SVector3,SVector3> > > firstElemDerivatives;//dXdU mutable discreteDiskFaceTriangle *_ddft; mutable ANNkd_tree *uv_kdtree; mutable ANNkd_tree *kdtree; mutable Octree *oct; mutable std::vector<double> _coords; - + const nodalBasis* mynodalbasis; + const bezierBasis* mybezierbasis; }; #endif diff --git a/Geo/discreteFace.cpp b/Geo/discreteFace.cpp index 1211b07f71f84f23cbb9b55762323197fd6e25a3..fb8388ca6c0ada40c40e6c32ecdc2f042e052233 100644 --- a/Geo/discreteFace.cpp +++ b/Geo/discreteFace.cpp @@ -16,7 +16,7 @@ #include "OS.h" discreteFace::discreteFace(GModel *model, int num) : GFace(model, num) -{ +{ Surface *s = Create_Surface(num, MSH_SURF_DISCRETE); Tree_Add(model->getGEOInternals()->Surfaces, &s); meshStatistics.status = GFace::DONE; @@ -72,79 +72,52 @@ GPoint discreteFace::point(double par1, double par2) const SPoint2 discreteFace::parFromPoint(const SPoint3 &p, bool onSurface) const { - if (getCompound()){ - return getCompound()->parFromPoint(p); - } - else{ - Msg::Error("Cannot compute parametric coordinates on discrete face"); - return SPoint2(); - } + return SPoint2(); } SVector3 discreteFace::normal(const SPoint2 ¶m) const { - if (getCompound()){ - return getCompound()->normal(param); - } - else{ - Msg::Error("Cannot evaluate normal on discrete face"); return SVector3(); - } } double discreteFace::curvatureMax(const SPoint2 ¶m) const { - if (getCompound()){ - return getCompound()->curvatureMax(param); - } - else{ - Msg::Error("Cannot evaluate curvature on discrete face"); + return false; - } } double discreteFace::curvatures(const SPoint2 ¶m, SVector3 *dirMax, SVector3 *dirMin, double *curvMax, double *curvMin) const { - if (getCompound()){ - return getCompound()->curvatures(param, dirMax, dirMin, curvMax, curvMin); - } - else{ - Msg::Error("Cannot evaluate curvatures and curvature directions on discrete face"); - return false; - } + return false; } Pair<SVector3, SVector3> discreteFace::firstDer(const SPoint2 ¶m) const { - if (getCompound()){ - return getCompound()->firstDer(param); - } - else{ - Msg::Error("Cannot evaluate derivative on discrete face"); - return Pair<SVector3, SVector3>(); - } + return Pair<SVector3, SVector3>(); } void discreteFace::secondDer(const SPoint2 ¶m, SVector3 *dudu, SVector3 *dvdv, SVector3 *dudv) const { + /*<<<<<<< .mine +======= if (getCompound()){ return getCompound()->secondDer(param, dudu, dvdv, dudv); } else{ Msg::Error("Cannot evaluate second derivative on discrete face"); + >>>>>>> .r22873*/ return; - } } // FIXME PAB ----> really create an atlas !!!!!!!!!!!!!!! void discreteFace::createGeometry() { #if defined(HAVE_ANN) && defined(HAVE_SOLVER) - if (!_atlas.empty())return; + if (!_atlas.empty())return; // parametrization is done here !!! - discreteDiskFace *df = new discreteDiskFace (this, triangles); + discreteDiskFace *df = new discreteDiskFace (this, triangles,2); df->replaceEdges(l_edges); _atlas.push_back(df); #endif