diff --git a/Geo/GFace.cpp b/Geo/GFace.cpp index 18b578588860cc0c56ae236fadee15236003cdf1..8921c9a31560da0f5c3b52b695ee60d505f33add 100644 --- a/Geo/GFace.cpp +++ b/Geo/GFace.cpp @@ -709,7 +709,7 @@ bool GFace::buildSTLTriangulation() // by default we assume that straight lines are geodesics SPoint2 GFace::geodesic(const SPoint2 &pt1 , const SPoint2 &pt2 , double t) { - if(CTX.mesh.second_order_experimental && geomType() != GEntity::Plane){ + if(CTX.mesh.second_order_experimental && geomType() != GEntity::Plane ){ // FIXME: this is buggy -- remove the CTX option once we do it in // a robust manner GPoint gp1 = point(pt1.x(), pt1.y()); @@ -719,7 +719,10 @@ SPoint2 GFace::geodesic(const SPoint2 &pt1 , const SPoint2 &pt2 , double t) gp1.y() + t * (gp2.y() - gp1.y()), gp1.z() + t * (gp2.z() - gp1.z())), (double*)guess); - return SPoint2(gp.u(), gp.v()); + if (gp.g()) + return SPoint2(gp.u(), gp.v()); + else + return pt1 + (pt2 - pt1) * t; } else{ return pt1 + (pt2 - pt1) * t; diff --git a/Geo/GPoint.h b/Geo/GPoint.h index 7eed7c4d9f4db57f0a85cf1b21b09d2044a6c2bc..4024727b680787c6aa40fc456ba5e9034a22ac11 100644 --- a/Geo/GPoint.h +++ b/Geo/GPoint.h @@ -25,6 +25,7 @@ class GPoint inline double &z() { return Z; } inline double u() const { return par[0]; } inline double v() const { return par[1]; } + inline const GEntity* g() const { return e; } GPoint (double _x=0, double _y=0, double _z=0, const GEntity *onwhat=0) : X(_x), Y(_y), Z(_z), e(onwhat) { diff --git a/Geo/MElement.cpp b/Geo/MElement.cpp index e500de751cb2fbff1b0439d5dbb00f9622b2240d..ee316e53952414639e0688cc9681355da97ce376 100644 --- a/Geo/MElement.cpp +++ b/Geo/MElement.cpp @@ -1057,6 +1057,145 @@ void MTriangleN::getEdgeRep(int num, double *x, double *y, double *z, SVector3 * } } + +int MTetrahedronN::getNumEdgesRep(){ return 6 * numSubEdges; } + +void MTetrahedronN::getEdgeRep(int num, double *x, double *y, double *z, SVector3 *n) +{ + static double pp[4][3] = {{0,0,0},{1,0,0},{0,1,0},{0,0,1}}; + static int ed [6][2] = {{0,1},{0,2},{0,3},{1,2},{1,3},{2,3}}; + int iEdge = num / numSubEdges; + int iSubEdge = num % numSubEdges; + + + int iVertex1 = ed [iEdge][0]; + int iVertex2 = ed [iEdge][1]; + double t1 = (double) iSubEdge / (double) numSubEdges; + double u1 = pp[iVertex1][0] * (1.-t1) + pp[iVertex2][0] * t1; + double v1 = pp[iVertex1][1] * (1.-t1) + pp[iVertex2][1] * t1; + double w1 = pp[iVertex1][2] * (1.-t1) + pp[iVertex2][2] * t1; + + double t2 = (double) (iSubEdge+1) / (double) numSubEdges; + double u2 = pp[iVertex1][0] * (1.-t2) + pp[iVertex2][0] * t2; + double v2 = pp[iVertex1][1] * (1.-t2) + pp[iVertex2][1] * t2; + double w2 = pp[iVertex1][2] * (1.-t2) + pp[iVertex2][2] * t2; + + SPoint3 pnt1, pnt2; + pnt(u1,v1,w1,pnt1); + pnt(u2,v2,w2,pnt2); + x[0] = pnt1.x(); x[1] = pnt2.x(); + y[0] = pnt1.y(); y[1] = pnt2.y(); + z[0] = pnt1.z(); z[1] = pnt2.z(); +} + + +int MTetrahedronN::getNumFacesRep(){ return 4 * numSubEdges * numSubEdges ; } + +void MTetrahedronN::getFaceRep(int num, double *x, double *y, double *z, SVector3 *n) +{ + static double pp[4][3] = {{0,0,0},{1,0,0},{0,1,0},{0,0,1}}; + static int fak [4][3] = {{0,1,2},{0,1,3},{0,2,3},{1,2,3}}; + int iFace = num / (numSubEdges*numSubEdges); + int iSubFace = num % (numSubEdges*numSubEdges); + + int iVertex1 = fak [iFace][0]; + int iVertex2 = fak [iFace][1]; + int iVertex3 = fak [iFace][2]; + + /* + 0 + 0 1 + 0 1 2 + 0 1 2 3 + 0 1 2 3 4 + 0 1 2 3 4 5 + */ + + // on the first layer, we have (numSubEdges-1) * 2 + 1 triangles + // on the second layer, we have (numSubEdges-2) * 2 + 1 triangles + // on the ith layer, we have (numSubEdges-1-i) * 2 + 1 triangles + int ix = 0, iy = 0; + int nbt = 0; + for (int i = 0; i < numSubEdges; i++){ + int nbl = (numSubEdges - i - 1) * 2 + 1; + nbt += nbl; + if (nbt > iSubFace){ + iy = i; + ix = nbl - (nbt - iSubFace); + break; + } + } + + const double d = 1. / numSubEdges; + + SPoint3 pnt1, pnt2, pnt3; + double J1[2][3], J2[2][3], J3[2][3]; + double u1,v1,u2,v2,u3,v3; + if (ix % 2 == 0){ + u1 = ix / 2 * d; v1= iy*d; + u2 = (ix / 2 + 1) * d ; v2 = iy * d; + u3 = ix / 2 * d ; v3 = (iy+1) * d; + } + else{ + u1 = (ix / 2 + 1) * d; v1= iy * d; + u2 = (ix / 2 + 1) * d; v2= (iy + 1) * d; + u3 = ix / 2 * d ; v3 = (iy + 1) * d; + } + + double U1 = pp[iVertex1][0] * (1.-u1-v1) + pp[iVertex2][0] * u1 + pp[iVertex3][0] * v1; + double U2 = pp[iVertex1][0] * (1.-u2-v2) + pp[iVertex2][0] * u2 + pp[iVertex3][0] * v2; + double U3 = pp[iVertex1][0] * (1.-u3-v3) + pp[iVertex2][0] * u3 + pp[iVertex3][0] * v3; + + double V1 = pp[iVertex1][1] * (1.-u1-v1) + pp[iVertex2][1] * u1 + pp[iVertex3][1] * v1; + double V2 = pp[iVertex1][1] * (1.-u2-v2) + pp[iVertex2][1] * u2 + pp[iVertex3][1] * v2; + double V3 = pp[iVertex1][1] * (1.-u3-v3) + pp[iVertex2][1] * u3 + pp[iVertex3][1] * v3; + + double W1 = pp[iVertex1][2] * (1.-u1-v1) + pp[iVertex2][2] * u1 + pp[iVertex3][2] * v1; + double W2 = pp[iVertex1][2] * (1.-u2-v2) + pp[iVertex2][2] * u2 + pp[iVertex3][2] * v2; + double W3 = pp[iVertex1][2] * (1.-u3-v3) + pp[iVertex2][2] * u3 + pp[iVertex3][2] * v3; + + pnt(U1,V1,W1,pnt1); + pnt(U2,V2,W2,pnt2); + pnt(U3,V3,W3,pnt3); + + x[0] = pnt1.x(); x[1] = pnt2.x(); x[2] = pnt3.x(); + y[0] = pnt1.y(); y[1] = pnt2.y(); y[2] = pnt3.y(); + z[0] = pnt1.z(); z[1] = pnt2.z(); z[2] = pnt3.z(); + + // facetted first + + SVector3 d1(x[1]-x[0],y[1]-y[0],z[1]-z[0]); + SVector3 d2(x[2]-x[0],y[2]-y[0],z[2]-z[0]); + n[0] = crossprod(d1, d2); + n[0].normalize(); + n[1] = n[0]; + n[2] = n[0]; + + return; + + { + SVector3 d1(J1[0][0], J1[0][1], J1[0][2]); + SVector3 d2(J1[1][0], J1[1][1], J1[1][2]); + n[0] = crossprod(d1, d2); + n[0].normalize(); + } + { + SVector3 d1(J2[0][0], J2[0][1], J2[0][2]); + SVector3 d2(J2[1][0], J2[1][1], J2[1][2]); + n[1] = crossprod(d1, d2); + n[1].normalize(); + } + { + SVector3 d1(J3[0][0], J3[0][1], J3[0][2]); + SVector3 d2(J3[1][0], J3[1][1], J3[1][2]); + n[2] = crossprod(d1, d2); + n[2].normalize(); + } +} + + + + MElement *MElementFactory::create(int type, std::vector<MVertex*> &v, int num, int part) { diff --git a/Geo/MElement.h b/Geo/MElement.h index 806cba53e7316e0a81f50fa03655a9c802db4a43..8d66a06ad44765558c354f14a641c79292c76913 100644 --- a/Geo/MElement.h +++ b/Geo/MElement.h @@ -1619,6 +1619,12 @@ class MTetrahedronN : public MTetrahedron { } } } + + virtual void getEdgeRep(int num, double *x, double *y, double *z, SVector3 *n); + virtual int getNumEdgesRep(); + virtual void getFaceRep(int num, double *x, double *y, double *z, SVector3 *n); + virtual int getNumFacesRep(); + virtual void jac(double u, double v, double w, double j[3][3]) { MTetrahedron::jac(_order, _vs , u, v, w, j); diff --git a/Geo/gmshFace.cpp b/Geo/gmshFace.cpp index 95802691d3549d1da14cc9f0fd4378240cb06169..6935469d6ed5c162615c837fe185e7986bc40554 100644 --- a/Geo/gmshFace.cpp +++ b/Geo/gmshFace.cpp @@ -240,7 +240,7 @@ GPoint gmshFace::closestPoint(const SPoint3 & qp, const double initialGuess[2]) v.Pos.Z = qp.z(); bool result = ProjectPointOnSurface(s, v, u); if (!result) - printf("Project Point on surface %d\n",result); + return GPoint(-1.e22, -1.e22, -1.e22, 0, u); return GPoint(v.Pos.X, v.Pos.Y, v.Pos.Z, this, u); } diff --git a/Mesh/HighOrder.cpp b/Mesh/HighOrder.cpp index 041d34142922a3f96b3fb35b6dd4ea5b0528b75e..a49e912c7dffa3919d0a7923260fd3ea45f6fc74 100644 --- a/Mesh/HighOrder.cpp +++ b/Mesh/HighOrder.cpp @@ -54,8 +54,9 @@ bool reparamOnFace(MVertex *v, GFace *gf, SPoint2 ¶m) double UU, VV; if(v->onWhat() == gf && v->getParameter(0, UU) && v->getParameter(1, VV)) param = SPoint2(UU, VV); - else - param = gf->parFromPoint(SPoint3(v->x(), v->y(), v->z())); + else + return false; + // param = gf->parFromPoint(SPoint3(v->x(), v->y(), v->z())); } return true; } @@ -175,6 +176,8 @@ bool computeEquidistantParameters(GFace *gf, double u0, double uN, double v0, do v[N] = vN; t[N] = 1.0; + return true; + // create the tangent matrix const int M = N - 2; Double_Matrix J(M, M); @@ -466,7 +469,10 @@ void getFaceVertices(GFace *gf, } if (reparamOK){ GPoint gp = gf->closestPoint(SPoint3(X,Y,Z),GUESS); - v = new MFaceVertex(gp.x(), gp.y(), gp.z(), gf, gp.u(), gp.v()); + if (gp.g()) + v = new MFaceVertex(gp.x(), gp.y(), gp.z(), gf, gp.u(), gp.v()); + else + v = new MVertex(X,Y,Z, gf); } else{ v = new MVertex(X,Y,Z, gf); diff --git a/Mesh/meshGRegion.cpp b/Mesh/meshGRegion.cpp index 68f649ed82124068b0d3fc5b78c3a038f9550a1b..78b33d9cabe625d85627ea9d789eeb717ebc04e0 100644 --- a/Mesh/meshGRegion.cpp +++ b/Mesh/meshGRegion.cpp @@ -179,8 +179,11 @@ void TransferTetgenMesh(GRegion *gr, tetgenio &in, tetgenio &out, Count++; } } - guess[0]/=Count; - guess[1]/=Count; + if (Count != 0){ + guess[0]/=Count; + guess[1]/=Count; + } + for(int j = 0; j < 3; j++){ if(v[j]->onWhat()->dim() == 3){ v[j]->onWhat()->mesh_vertices.erase @@ -192,16 +195,20 @@ void TransferTetgenMesh(GRegion *gr, tetgenio &in, tetgenio &out, // PARAMETRIC COORDINATES SHOULD BE SET for the vertex !!!!!!!!!!!!! // This is not 100 % safe yet, so we reserve that operation for high order // meshes. - Msg::Debug("A new point has been inserted in mesh face %d by the 3D mesher, guess %g %g",gf->tag(),guess[0],guess[1]); + // Msg::Debug("A new point has been inserted in mesh face %d by the 3D mesher, guess %g %g",gf->tag(),guess[0],guess[1]); GPoint gp = gf->closestPoint (SPoint3(v[j]->x(), v[j]->y(), v[j]->z()),guess); - Msg::Debug("The point has been projected back to the surface (%g %g %g) -> (%g %g %g), (%g,%g)", - v[j]->x(), v[j]->y(), v[j]->z(),gp.x(),gp.y(),gp.z(),gp.u(),gp.v()); // To be safe, we should ensure that this mesh motion does not lead to an invalid mesh !!!! //v1b = new MVertex(gp.x(),gp.y(),gp.z(),gf); - v1b = new MFaceVertex(gp.x(),gp.y(),gp.z(),gf,gp.u(),gp.v()); - //v1b = new MVertex(v[j]->x(), v[j]->y(), v[j]->z(),gf); - + if (gp.g()){ + v1b = new MFaceVertex(gp.x(),gp.y(),gp.z(),gf,gp.u(),gp.v()); + Msg::Info("The point has been projected back to the surface (%g %g %g) -> (%g %g %g)", + v[j]->x(), v[j]->y(), v[j]->z(),gp.x(),gp.y(),gp.z()); + } + else{ + v1b = new MVertex(v[j]->x(), v[j]->y(), v[j]->z(),gf); + Msg::Warning("The point was not projected back to the surface (%g %g %g)", v[j]->x(), v[j]->y(), v[j]->z()); + } } else{ v1b = new MVertex(v[j]->x(), v[j]->y(), v[j]->z(),gf); diff --git a/Mesh/qualityMeasures.cpp b/Mesh/qualityMeasures.cpp index f3b45dfc8e8845d24a271b747ee24e4985ebdc20..75ea2cbb2797e4ed71a3491e87518c0b3ddbb456 100644 --- a/Mesh/qualityMeasures.cpp +++ b/Mesh/qualityMeasures.cpp @@ -220,7 +220,38 @@ double qmDistorsionOfMapping (MTriangle *e) return dmin; } +static double mesh_functional_distorsion(MTetrahedron *t, double u, double v, double w) +{ + // compute uncurved element jacobian d_u x and d_v x + double mat[3][3]; + t->jac(1, 0, 0, 0, 0, mat); + const double det1 = det3x3(mat); + t->jac(u, v, w, mat); + const double detN = det3x3(mat); + + // printf("%g %g %g = %g %g\n",u,v,w,det1,detN); + + if (det1 == 0 || detN == 0) return 0; + double dist = std::min(detN/det1, det1/detN); + return dist; +} + + double qmDistorsionOfMapping (MTetrahedron *e) { - return 1.0; + if (e->getPolynomialOrder() == 1)return 1.0; + IntPt *pts; + int npts; + e->getIntegrationPoints(e->getPolynomialOrder(),&npts, &pts); + double dmin; + for (int i=0;i<npts;i++){ + const double u = pts[i].pt[0]; + const double v = pts[i].pt[1]; + const double w = pts[i].pt[2]; + const double di = mesh_functional_distorsion (e,u,v,w); + dmin = (i==0)? di : std::min(dmin,di); + } + // printf("DMIN = %g\n\n",dmin); + + return dmin< 0 ? 0 :dmin; }