diff --git a/Geo/MHexahedron.cpp b/Geo/MHexahedron.cpp index 31f5e74d7184e8778d4aa5280d7c06a7a0f97662..39aa47f33d3c4fc36d9187169516db21ee041b1c 100644 --- a/Geo/MHexahedron.cpp +++ b/Geo/MHexahedron.cpp @@ -10,7 +10,10 @@ #include "nodalBasis.h" #include "polynomialBasis.h" #include "MQuadrangle.h" + +#if defined(HAVE_MESH) #include "qualityMeasures.h" +#endif int MHexahedron::getVolumeSign() { @@ -38,32 +41,8 @@ void MHexahedron::getIntegrationPoints(int pOrder, int *npts, IntPt **pts) double MHexahedron::angleShapeMeasure() { - #if defined(HAVE_MESH) - double angleMax = 0.0; - double angleMin = M_PI; - double zeta = 0.0; - for (int i=0; i<getNumFaces(); i++){ - std::vector<MVertex*> vv; - vv.push_back(getFace(i).getVertex(0)); - vv.push_back(getFace(i).getVertex(1)); - vv.push_back(getFace(i).getVertex(2)); - vv.push_back(getFace(i).getVertex(3)); - // MVertex *v0 = new MVertex(0, 0, 0); vv.push_back(v0); - // MVertex *v1 = new MVertex(1., 0, 0);vv.push_back(v1); - // MVertex *v2 = new MVertex(2., 1., 0);vv.push_back(v2); - // MVertex *v3 = new MVertex(1, 1., 0);vv.push_back(v3); - for (int j=0; j<4; j++){ - SVector3 a(vv[(j+2)%4]->x()-vv[(j+1)%4]->x(),vv[(j+2)%4]->y()-vv[(j+1)%4]->y(),vv[(j+2)%4]->z()-vv[(j+1)%4]->z() ); - SVector3 b(vv[(j+1)%4]->x()-vv[(j)%4]->x(), vv[(j+1)%4]->y()-vv[(j)%4]->y(), vv[(j+1)%4]->z()-vv[(j)%4]->z() ); - double angle = acos( dot(a,b)/(norm(a)*norm(b))); //*180/M_PI; - angleMax = std::max(angleMax, angle); - angleMin = std::min(angleMin, angle); - } - //printf("angle max =%g min =%g \n", angleMax*180/M_PI, angleMin*180/M_PI); - } - zeta = 1.-std::max((angleMax-0.5*M_PI)/(0.5*M_PI),(0.5*M_PI-angleMin)/(0.5*M_PI)); - return zeta; + return qmHexahedron::angles(this); #else return 1.; #endif diff --git a/Geo/MPrism.cpp b/Geo/MPrism.cpp index 41c2b69ef4bb9de236a45a7c94b8c3198a45d6e1..e1dcf182b6291fc57f74ba2af2614329b448e001 100644 --- a/Geo/MPrism.cpp +++ b/Geo/MPrism.cpp @@ -8,6 +8,10 @@ #include "BasisFactory.h" #include "Context.h" +#if defined(HAVE_MESH) +#include "qualityMeasures.h" +#endif + int MPrism::getVolumeSign() { double mat[3][3]; @@ -517,35 +521,8 @@ void MPrismN::getFaceVertices(const int num, std::vector<MVertex*> &v) const } -static double scaled_jacobian(MVertex* a,MVertex* b,MVertex* c,MVertex* d){ - double val; - double l1,l2,l3; - SVector3 vec1,vec2,vec3; - - vec1 = SVector3(b->x()-a->x(),b->y()-a->y(),b->z()-a->z()); - vec2 = SVector3(c->x()-a->x(),c->y()-a->y(),c->z()-a->z()); - vec3 = SVector3(d->x()-a->x(),d->y()-a->y(),d->z()-a->z()); - - l1 = vec1.norm(); - l2 = vec2.norm(); - l3 = vec3.norm(); - - val = dot(vec1,crossprod(vec2,vec3)); - return fabs(val)/(l1*l2*l3); -} - -double MPrism::gammaShapeMeasure() { - MVertex *a = getVertex(0),*b= getVertex(1),*c= getVertex(2); - MVertex *d = getVertex(3),*e= getVertex(4),*f= getVertex(5); - const double j [6] = { - scaled_jacobian(a,b,c,d), - scaled_jacobian(b,a,c,e), - scaled_jacobian(c,a,b,f), - scaled_jacobian(d,a,e,f), - scaled_jacobian(e,b,d,f), - scaled_jacobian(f,c,d,e)}; - const double result = *std::min_element(j,j+6); - printf("%12.5E\n",result); - return result; +double MPrism::gammaShapeMeasure() +{ + return qmPrism::minNCJ(this); } diff --git a/Geo/MQuadrangle.cpp b/Geo/MQuadrangle.cpp index 56aa05f5dc09f9fdbebd5ae6078bac686caa3611..6d5e98e26c212d194bc5cb23c89943f05ff5afe4 100644 --- a/Geo/MQuadrangle.cpp +++ b/Geo/MQuadrangle.cpp @@ -186,56 +186,26 @@ void MQuadrangle::getIntegrationPoints(int pOrder, int *npts, IntPt **pts) double MQuadrangle::etaShapeMeasure() { - double AR = 1;//(minEdge()/maxEdge()); - - SVector3 v01 (_v[1]->x()-_v[0]->x(),_v[1]->y()-_v[0]->y(),_v[1]->z()-_v[0]->z()); - SVector3 v12 (_v[2]->x()-_v[1]->x(),_v[2]->y()-_v[1]->y(),_v[2]->z()-_v[1]->z()); - SVector3 v23 (_v[3]->x()-_v[2]->x(),_v[3]->y()-_v[2]->y(),_v[3]->z()-_v[2]->z()); - SVector3 v30 (_v[0]->x()-_v[3]->x(),_v[0]->y()-_v[3]->y(),_v[0]->z()-_v[3]->z()); - - SVector3 a = crossprod(v01,v12); - SVector3 b = crossprod(v12,v23); - SVector3 c = crossprod(v23,v30); - SVector3 d = crossprod(v30,v01); - - double sign = 1.0; - if (dot(a,b) < 0 || dot(a,c) < 0 || dot(a,d) < 0 )sign = -1; - // FIXME ... - // if (a.z() > 0 || b.z() > 0 || c.z() > 0 || d.z() > 0) sign = -1; - - double a1 = 180 * angle3Vertices(_v[0], _v[1], _v[2]) / M_PI; - double a2 = 180 * angle3Vertices(_v[1], _v[2], _v[3]) / M_PI; - double a3 = 180 * angle3Vertices(_v[2], _v[3], _v[0]) / M_PI; - double a4 = 180 * angle3Vertices(_v[3], _v[0], _v[1]) / M_PI; - - a1 = std::min(180.,a1); - a2 = std::min(180.,a2); - a3 = std::min(180.,a3); - a4 = std::min(180.,a4); - double angle = fabs(90. - a1); - angle = std::max(fabs(90. - a2),angle); - angle = std::max(fabs(90. - a3),angle); - angle = std::max(fabs(90. - a4),angle); - - return sign*(1.-angle/90) * AR; +#if defined(HAVE_MESH) + return qmQuadrangle::eta(this); +#else + return 0.; +#endif } -/// a shape measure for quadrangles -/// assume (for now) 2D elements -- -/// sf = (1 \pm xi) (1 \pm eta) / 4 -/// dsf_xi = \pm (1 \pm eta) / 4 -/// 1 + eta , -(1+eta) , -(1-eta), 1-eta -/// dsf_eta = \pm (1 \pm xi) / 4 -/// 1 + xi , 1 - xi , -(1-xi), -(1+xi) double MQuadrangle::gammaShapeMeasure(){ - return etaShapeMeasure(); +#if defined(HAVE_MESH) + return qmQuadrangle::gamma(this); +#else + return 0.; +#endif } double MQuadrangle::angleShapeMeasure() { #if defined(HAVE_MESH) - return qmQuadrangleAngles(this); + return qmQuadrangle::angles(this); #else return 1.; #endif diff --git a/Geo/MTetrahedron.cpp b/Geo/MTetrahedron.cpp index 43e5587f546a76db4baf1b673e7f30ce6c19b9ae..ea2c49892c59a2aea82b971e65dc1c77f9f2afe3 100644 --- a/Geo/MTetrahedron.cpp +++ b/Geo/MTetrahedron.cpp @@ -67,7 +67,7 @@ double MTetrahedron::gammaShapeMeasure() { #if defined(HAVE_MESH) double vol; - return qmTet(this, QMTET_2, &vol); + return qmTetrahedron::qm(this, qmTetrahedron::QMTET_GAMMA, &vol); #else return 0.; #endif @@ -77,7 +77,7 @@ double MTetrahedron::etaShapeMeasure() { #if defined(HAVE_MESH) double vol; - return qmTet(this, QMTET_3, &vol); + return qmTetrahedron::qm(this, qmTetrahedron::QMTET_ETA, &vol); #else return 0.; #endif diff --git a/Geo/MTriangle.cpp b/Geo/MTriangle.cpp index 587d7a1a520771ad273ac22aecfd4795d94e1169..5c21e2e54045f4bc683162440c1f6ec2d1517806 100644 --- a/Geo/MTriangle.cpp +++ b/Geo/MTriangle.cpp @@ -65,7 +65,7 @@ double MTriangle::getOuterRadius() double MTriangle::angleShapeMeasure() { #if defined(HAVE_MESH) - return qmTriangleAngles(this); + return qmTriangle::angles(this); #else return 0.; #endif @@ -73,20 +73,18 @@ double MTriangle::angleShapeMeasure() double MTriangle::etaShapeMeasure() { - double a1 = 180 * angle3Vertices(_v[0], _v[1], _v[2]) / M_PI; - double a2 = 180 * angle3Vertices(_v[1], _v[2], _v[0]) / M_PI; - double a3 = 180 * angle3Vertices(_v[2], _v[0], _v[1]) / M_PI; - - double amin = std::min(std::min(a1,a2),a3); - double angle = fabs(60. - amin); - return 1.-angle/60; +#if defined(HAVE_MESH) + return qmTriangle::eta(this); +#else + return 0.; +#endif } double MTriangle::gammaShapeMeasure() { #if defined(HAVE_MESH) - return qmTriangle(this, QMTRI_RHO); + return qmTriangle::gamma(this); #else return 0.; #endif diff --git a/Mesh/BDS.cpp b/Mesh/BDS.cpp index 357759af15e5d97c7b864e2eab9787b7eb44b1e9..af1c2137eb51ff25b623eb286a140e0eb623dda4 100644 --- a/Mesh/BDS.cpp +++ b/Mesh/BDS.cpp @@ -779,10 +779,10 @@ bool BDS_SwapEdgeTestQuality::operator () (BDS_Point *_p1, BDS_Point *_p2, BDS_P double cosnq; prosca(n, q, &cosnq); double cosonq; prosca(on, oq, &cosonq); - double qa1 = qmTriangle(_p1, _p2, _p3, QMTRI_RHO); - double qa2 = qmTriangle(_q1, _q2, _q3, QMTRI_RHO); - double qb1 = qmTriangle(_op1, _op2, _op3, QMTRI_RHO); - double qb2 = qmTriangle(_oq1, _oq2, _oq3, QMTRI_RHO); + double qa1 = qmTriangle::gamma(_p1, _p2, _p3); + double qa2 = qmTriangle::gamma(_q1, _q2, _q3); + double qb1 = qmTriangle::gamma(_op1, _op2, _op3); + double qb2 = qmTriangle::gamma(_oq1, _oq2, _oq3); // we swap for a better configuration double mina = std::min(qa1,qa2); @@ -1113,8 +1113,8 @@ bool BDS_Mesh::collapse_edge_parametric(BDS_Edge *e, BDS_Point *p) pt[1][nt] = (pts[1] == p) ? o : pts[1]; pt[2][nt] = (pts[2] == p) ? o : pts[2]; -// double qnew = qmTriangle(pt[0][nt], pt[1][nt], pt[2][nt], QMTRI_RHO); -// double qold = qmTriangle(pts[0], pts[1], pts[2], QMTRI_RHO); +// double qnew = qmTriangle::gamma(pt[0][nt], pt[1][nt], pt[2][nt]); +// double qold = qmTriangle::gamma(pts[0], pts[1], pts[2]); // if(qold > 1.e-4 && qnew < 1.e-4) return false; nt++; // pt[0][nt] = (pts[0] == p) ? o->iD : pts[0]->iD; @@ -1263,14 +1263,14 @@ bool BDS_Mesh::smooth_point_centroid(BDS_Point *p, GFace *gf, bool test_quality) p->X = gp.x(); p->Y = gp.y(); p->Z = gp.z(); - newWorst = std::min(newWorst, qmTriangle(*it, QMTRI_RHO)); + newWorst = std::min(newWorst, qmTriangle::gamma(*it)); double norm1[3],norm2[3]; normal_triangle(n[0], n[1], n[2], norm1); p->X = oldX; p->Y = oldY; p->Z = oldZ; normal_triangle(n[0], n[1], n[2], norm2); - oldWorst = std::min(oldWorst, qmTriangle(*it, QMTRI_RHO)); + oldWorst = std::min(oldWorst, qmTriangle::gamma(*it)); double ps; prosca(norm1, norm2, &ps); double threshold = (isSphere ? 0.95 : 0.5); diff --git a/Mesh/meshGFace.cpp b/Mesh/meshGFace.cpp index 5dd68634fa5ac85e30ed3697da7c7de45c1f1323..cac622ed26719fa285bb638f6d3e50e560a7e5ff 100644 --- a/Mesh/meshGFace.cpp +++ b/Mesh/meshGFace.cpp @@ -58,7 +58,7 @@ static void computeElementShapes(GFace *gf, double &worst, double &avg, nT = 0; greaterThan = 0; for(unsigned int i = 0; i < gf->triangles.size(); i++){ - double q = qmTriangle(gf->triangles[i], QMTRI_RHO); + double q = qmTriangle::gamma(gf->triangles[i]); if(q > .9) greaterThan++; avg += q; worst = std::min(worst, q); diff --git a/Mesh/meshGFaceBDS.cpp b/Mesh/meshGFaceBDS.cpp index c96846ea13412dea12be2460bf360be6ca5be156..0103985d009b6c32a3f6d6eb42be4d2e7895e1a0 100644 --- a/Mesh/meshGFaceBDS.cpp +++ b/Mesh/meshGFaceBDS.cpp @@ -234,10 +234,10 @@ bool evalSwapForOptimize(BDS_Edge *e, GFace *gf, BDS_Mesh &m) // First, evaluate what we gain in element quality if the // swap is performed - double qa1 = qmTriangle(p11, p12, p13, QMTRI_RHO); - double qa2 = qmTriangle(p21, p22, p23, QMTRI_RHO); - double qb1 = qmTriangle(p31, p32, p33, QMTRI_RHO); - double qb2 = qmTriangle(p41, p42, p43, QMTRI_RHO); + double qa1 = qmTriangle::gamma(p11, p12, p13); + double qa2 = qmTriangle::gamma(p21, p22, p23); + double qb1 = qmTriangle::gamma(p31, p32, p33); + double qb2 = qmTriangle::gamma(p41, p42, p43); double qa = std::min(qa1, qa2); double qb = std::min(qb1, qb2); double qualIndicator = qb - qa; @@ -357,10 +357,10 @@ bool evalSwap(BDS_Edge *e, double &qa, double &qb) if(e->numfaces() != 2) return false; e->oppositeof (op); - double qa1 = qmTriangle(e->p1, e->p2, op[0], QMTRI_RHO); - double qa2 = qmTriangle(e->p1, e->p2, op[1], QMTRI_RHO); - double qb1 = qmTriangle(e->p1, op[0], op[1], QMTRI_RHO); - double qb2 = qmTriangle(e->p2, op[0], op[1], QMTRI_RHO); + double qa1 = qmTriangle::gamma(e->p1, e->p2, op[0]); + double qa2 = qmTriangle::gamma(e->p1, e->p2, op[1]); + double qb1 = qmTriangle::gamma(e->p1, op[0], op[1]); + double qb2 = qmTriangle::gamma(e->p2, op[0], op[1]); qa = std::min(qa1, qa2); qb = std::min(qb1, qb2); return true; @@ -381,10 +381,10 @@ int edgeSwapTestQuality(BDS_Edge *e, double fact=1.1, bool force=false) if (!edgeSwapTestAngle(e, cos(CTX::instance()->mesh.allowSwapEdgeAngle * M_PI / 180.))) return -1; - double qa1 = qmTriangle(e->p1, e->p2, op[0], QMTRI_RHO); - double qa2 = qmTriangle(e->p1, e->p2, op[1], QMTRI_RHO); - double qb1 = qmTriangle(e->p1, op[0], op[1], QMTRI_RHO); - double qb2 = qmTriangle(e->p2, op[0], op[1], QMTRI_RHO); + double qa1 = qmTriangle::gamma(e->p1, e->p2, op[0]); + double qa2 = qmTriangle::gamma(e->p1, e->p2, op[1]); + double qb1 = qmTriangle::gamma(e->p1, op[0], op[1]); + double qb2 = qmTriangle::gamma(e->p2, op[0], op[1]); double qa = std::min(qa1, qa2); double qb = std::min(qb1, qb2); if(qb > fact * qa) return 1; diff --git a/Mesh/meshGFaceOptimize.cpp b/Mesh/meshGFaceOptimize.cpp index d778a94a2a84233f179a0c20ad3bd7b1a0669523..b5ec7972b131000561831dcd05f9ee53e2f0f627 100644 --- a/Mesh/meshGFaceOptimize.cpp +++ b/Mesh/meshGFaceOptimize.cpp @@ -537,7 +537,7 @@ int _removeFourTrianglesNodes(GFace *gf,bool replace_by_quads) for(int i=0;i<4;i++){ newt[i] = new MTriangle(edges[i][0],edges[(i+1)%4][0],edges[(i+2)%4][0]); surf[i] = surfaceFaceUV(newt[i],gf); - qual[i] = qmTriangle(newt[i],QMTRI_RHO); + qual[i] = qmTriangle::gamma(newt[i]); } double q02=(fabs((surf[0]+surf[2]-surfaceRef)/surfaceRef)<1e-8) ? std::min(qual[0],qual[2]) : -1; @@ -2851,10 +2851,10 @@ bool edgeSwap(std::set<swapquad> &configs, MTri3 *t1, GFace *gf, int iLocalEdge, switch(cr){ case SWCR_QUAL: { - const double triQualityRef = std::min(qmTriangle(t1->tri(), QMTRI_RHO), - qmTriangle(t2->tri(), QMTRI_RHO)); - const double triQuality = std::min(qmTriangle(t1b, QMTRI_RHO), - qmTriangle(t2b, QMTRI_RHO)); + const double triQualityRef = std::min(qmTriangle::gamma(t1->tri()), + qmTriangle::gamma(t2->tri())); + const double triQuality = std::min(qmTriangle::gamma(t1b), + qmTriangle::gamma(t2b)); if (!edgeSwapDelProj(v1,v2,v3,v4)){ if(triQuality < triQualityRef){ delete t1b; diff --git a/Mesh/meshGRegion.cpp b/Mesh/meshGRegion.cpp index 7bbe110baf3505918daa44a2e726411ce3906f0e..9113a1a535fb1746bb986e430159a461da5b9568 100644 --- a/Mesh/meshGRegion.cpp +++ b/Mesh/meshGRegion.cpp @@ -1778,7 +1778,7 @@ void optimizeMeshGRegionGmsh::operator() (GRegion *gr) if(ep && ep->mesh.ExtrudeMesh && ep->geo.Mode == EXTRUDED_ENTITY) return; Msg::Info("Optimizing volume %d", gr->tag()); - optimizeMesh(gr, QMTET_2); + optimizeMesh(gr, qmTetrahedron::QMTET_GAMMA); } diff --git a/Mesh/meshGRegionDelaunayInsertion.cpp b/Mesh/meshGRegionDelaunayInsertion.cpp index 29d6c584dcde3598f33cc7dfe191c7af9baea1cf..fa04be33182491dad64feade6ebf94547dfdd6aa 100644 --- a/Mesh/meshGRegionDelaunayInsertion.cpp +++ b/Mesh/meshGRegionDelaunayInsertion.cpp @@ -734,7 +734,7 @@ void non_recursive_classify(MTet4 *t, std::list<MTet4*> &theRegion, void adaptMeshGRegion::operator () (GRegion *gr) { - const qualityMeasure4Tet qm = QMTET_2; + const qmTetrahedron::Measures qm = qmTetrahedron::QMTET_GAMMA; typedef std::list<MTet4 *> CONTAINER ; CONTAINER allTets; @@ -793,7 +793,7 @@ void adaptMeshGRegion::operator () (GRegion *gr) if (!(*it)->isDeleted()){ for (int i = 0; i < 4; i++){ for (int j = 0; j < 4; j++){ - if (collapseVertex(newTets, *it, i, j, QMTET_2)){ + if (collapseVertex(newTets, *it, i, j, qmTetrahedron::QMTET_GAMMA)){ nbCollapse++; i = j = 10; } } @@ -917,7 +917,7 @@ void adaptMeshGRegion::operator () (GRegion *gr) } //template <class CONTAINER, class DATA> -void optimizeMesh(GRegion *gr, const qualityMeasure4Tet &qm) +void optimizeMesh(GRegion *gr, const qmTetrahedron::Measures &qm) { typedef std::list<MTet4 *> CONTAINER ; @@ -1443,7 +1443,7 @@ void insertVerticesInRegion (GRegion *gr, int maxVert, bool _classify) double qq = (*it)->getQuality(); if (qq < .4) for (int i = 0; i < 4; i++){ - if (smoothVertex(*it, i, QMTET_2)) nbReloc++; + if (smoothVertex(*it, i, qmTetrahedron::QMTET_GAMMA)) nbReloc++; } } } @@ -1656,7 +1656,7 @@ void bowyerWatsonFrontalLayers(GRegion *gr, bool hex) double qq = (*it)->getQuality(); if (qq < .4) for (int i = 0; i < 4; i++){ - if (smoothVertex(*it, i, QMTET_2)) nbReloc++; + if (smoothVertex(*it, i, qmTetrahedron::QMTET_GAMMA)) nbReloc++; } } } diff --git a/Mesh/meshGRegionDelaunayInsertion.h b/Mesh/meshGRegionDelaunayInsertion.h index 996c8c75e28b693589234388ae61d8b41140293c..888bd9336fea6cd3a5b81b923af11295207d1a2f 100644 --- a/Mesh/meshGRegionDelaunayInsertion.h +++ b/Mesh/meshGRegionDelaunayInsertion.h @@ -72,12 +72,12 @@ class MTet4 { neigh[0] = neigh[1] = neigh[2] = neigh[3] = 0; } - MTet4(MTetrahedron *t, const qualityMeasure4Tet &qm) + MTet4(MTetrahedron *t, const qmTetrahedron::Measures &qm) : deleted(false), base(t), gr(0) { neigh[0] = neigh[1] = neigh[2] = neigh[3] = 0; double vol; - circum_radius = qmTet(t, qm, &vol); + circum_radius = qmTetrahedron::qm(t, qm, &vol); } void circumcenter(double *res) { @@ -266,6 +266,6 @@ class MTet4Factory container &getAllTets(){ return allTets; } }; -void optimizeMesh(GRegion *gr, const qualityMeasure4Tet &qm); +void optimizeMesh(GRegion *gr, const qmTetrahedron::Measures &qm); #endif diff --git a/Mesh/meshGRegionLocalMeshMod.cpp b/Mesh/meshGRegionLocalMeshMod.cpp index a89b892eba464bd300f741b5691b1d60e79eabdc..131c9ccf70f5f94e1c84c5129f0cf05e5b93bdf2 100644 --- a/Mesh/meshGRegionLocalMeshMod.cpp +++ b/Mesh/meshGRegionLocalMeshMod.cpp @@ -210,7 +210,7 @@ void BuildSwapPattern7(SwapPattern *sc) bool edgeSwap(std::vector<MTet4 *> &newTets, MTet4 *tet, int iLocalEdge, - const qualityMeasure4Tet &cr) + const qmTetrahedron::Measures &cr) { std::vector<MTet4*> cavity; std::vector<MTet4*> outside; @@ -250,8 +250,8 @@ bool edgeSwap(std::vector<MTet4 *> &newTets, int p1 = sp.triangles[i][0]; int p2 = sp.triangles[i][1]; int p3 = sp.triangles[i][2]; - tetQuality1[i] = qmTet(ring[p1], ring[p2], ring[p3], v1, cr, &(volume1[i])); - tetQuality2[i] = qmTet(ring[p1], ring[p2], ring[p3], v2, cr, &(volume2[i])); + tetQuality1[i] = qmTetrahedron::qm(ring[p1], ring[p2], ring[p3], v1, cr, &(volume1[i])); + tetQuality2[i] = qmTetrahedron::qm(ring[p1], ring[p2], ring[p3], v2, cr, &(volume2[i])); } // look for the best triangulation, i.e. the one that maximize the @@ -318,7 +318,7 @@ bool edgeSwap(std::vector<MTet4 *> &newTets, } bool edgeSplit(std::vector<MTet4 *> &newTets, MTet4 *tet, MVertex *newVertex, - int iLocalEdge, const qualityMeasure4Tet &cr) + int iLocalEdge, const qmTetrahedron::Measures &cr) { std::vector<MTet4*> cavity; std::vector<MTet4*> outside; @@ -352,7 +352,7 @@ bool edgeSplit(std::vector<MTet4 *> &newTets, MTet4 *tet, MVertex *newVertex, // swap a face i.e. remove a face shared by 2 tets bool faceSwap(std::vector<MTet4 *> &newTets, MTet4 *t1, int iLocalFace, - const qualityMeasure4Tet &cr) + const qmTetrahedron::Measures &cr) { MTet4 *t2 = t1->getNeigh(iLocalFace); if (!t2) return false; @@ -383,11 +383,11 @@ bool faceSwap(std::vector<MTet4 *> &newTets, MTet4 *t1, int iLocalFace, double q2 = t2->getQuality(); double vol3; - double q3 = qmTet(f1, f2, v1, v2, cr, &vol3); + double q3 = qmTetrahedron::qm(f1, f2, v1, v2, cr, &vol3); double vol4; - double q4 = qmTet(f2, f3, v1, v2, cr, &vol4); + double q4 = qmTetrahedron::qm(f2, f3, v1, v2, cr, &vol4); double vol5; - double q5 = qmTet(f3, f1, v1, v2, cr, &vol5); + double q5 = qmTetrahedron::qm(f3, f1, v1, v2, cr, &vol5); if (fabs(vol1 + vol2 - vol3 - vol4 - vol5) > 1.e-10 * (vol1 + vol2)) return false; @@ -481,7 +481,7 @@ void buildVertexCavity_recur(MTet4 *t, MVertex *v, std::vector<MTet4*> &cavity) // after that crap, the sliver is trashed bool sliverRemoval(std::vector<MTet4*> &newTets, MTet4 *t, - const qualityMeasure4Tet &cr) + const qmTetrahedron::Measures &cr) { std::vector<MTet4*> cavity; std::vector<MTet4*> outside; @@ -507,7 +507,7 @@ bool sliverRemoval(std::vector<MTet4*> &newTets, MTet4 *t, else if (nbSwappable == 1){ // classical case, the sliver has 5 edges on the boundary // try to swap first - if (edgeSwap(newTets,t,iSwappable,QMTET_3))return true; + if (edgeSwap(newTets,t,iSwappable,qmTetrahedron::QMTET_ETA))return true; // if it does not work, split, smooth and collapse MVertex *v1 = t->tet()->getVertex(edges[iSwappable][0]); MVertex *v2 = t->tet()->getVertex(edges[iSwappable][1]); @@ -516,7 +516,7 @@ bool sliverRemoval(std::vector<MTet4*> &newTets, MTet4 *t, 0.5 * (v1->z() + v2->z()), t->onWhat()); t->onWhat()->mesh_vertices.push_back(newv); - if (!edgeSplit(newTets, t, newv, iSwappable, QMTET_ONE)) return false; + if (!edgeSplit(newTets, t, newv, iSwappable, qmTetrahedron::QMTET_ONE)) return false; for (int i = 0; i < 4; i++){ if (newTets[newTets.size() - 1]->tet()->getVertex(i) == newv){ smoothVertex(newTets[newTets.size() - 1], i, cr); @@ -556,7 +556,7 @@ bool collapseVertex(std::vector<MTet4 *> &newTets, MTet4 *t, int iVertex, int iTarget, - const qualityMeasure4Tet &cr, + const qmTetrahedron::Measures &cr, const localMeshModAction action, double *minQual) { @@ -609,7 +609,7 @@ bool collapseVertex(std::vector<MTet4 *> &newTets, } for (unsigned int i = 0; i < toUpdate.size(); i++){ double vv; - newQuals[i] = qmTet(toUpdate[i]->tet(),cr,&vv); + newQuals[i] = qmTetrahedron::qm(toUpdate[i]->tet(),cr,&vv); worstAfter = std::min(worstAfter,newQuals[i]); volume_update += vv; } @@ -648,7 +648,7 @@ bool collapseVertex(std::vector<MTet4 *> &newTets, return true; } -bool smoothVertex(MTet4 *t, int iVertex, const qualityMeasure4Tet &cr) +bool smoothVertex(MTet4 *t, int iVertex, const qmTetrahedron::Measures &cr) { if(t->isDeleted()){ Msg::Error("Impossible to collapse vertex"); @@ -702,7 +702,7 @@ bool smoothVertex(MTet4 *t, int iVertex, const qualityMeasure4Tet &cr) } for (unsigned int i = 0; i < cavity.size(); i++){ double volume; - newQuals[i] = qmTet(cavity[i]->tet(),cr,&volume); + newQuals[i] = qmTetrahedron::qm(cavity[i]->tet(),cr,&volume); volumeAfter += volume; worstAfter = std::min(worstAfter,newQuals[i]); } @@ -742,7 +742,7 @@ double smoothing_objective_function_3D(double X, double Y, double Z, std::vector < MTet4 * >::iterator ite = ts.end(); double qMin = 1, vol; while(it != ite){ - qMin = std::min(qmTet((*it)->tet(), QMTET_2, &vol), qMin); + qMin = std::min(qmTetrahedron::qm((*it)->tet(), qmTetrahedron::QMTET_GAMMA, &vol), qMin); ++it; } v->x() = oldX; @@ -776,7 +776,7 @@ double smooth_obj_3D(double *XYZ, void *data) return smoothing_objective_function_3D(XYZ[0], XYZ[1], XYZ[2], svd->v, svd->ts); } -bool smoothVertexOptimize(MTet4 *t, int iVertex, const qualityMeasure4Tet &cr) +bool smoothVertexOptimize(MTet4 *t, int iVertex, const qmTetrahedron::Measures &cr) { if(t->tet()->getVertex(iVertex)->onWhat()->dim() < 3) return false; @@ -817,7 +817,7 @@ bool smoothVertexOptimize(MTet4 *t, int iVertex, const qualityMeasure4Tet &cr) } for(unsigned int i = 0; i < vd.ts.size(); i++){ double volume; - newQuals[i] = qmTet(vd.ts[i]->tet(), cr, &volume); + newQuals[i] = qmTetrahedron::qm(vd.ts[i]->tet(), cr, &volume); volumeAfter += volume; } diff --git a/Mesh/meshGRegionLocalMeshMod.h b/Mesh/meshGRegionLocalMeshMod.h index a838150ceda5144ca6c753b030bd921252404892..8cbde9c9c8a6465d104a411ff61ee486be17ff0c 100644 --- a/Mesh/meshGRegionLocalMeshMod.h +++ b/Mesh/meshGRegionLocalMeshMod.h @@ -16,28 +16,28 @@ enum localMeshModAction {GMSH_DOIT, GMSH_EVALONLY}; bool edgeSwap(std::vector<MTet4*> &newTets, MTet4 *tet, - int iLocalEdge, const qualityMeasure4Tet &cr); + int iLocalEdge, const qmTetrahedron::Measures &cr); bool faceSwap(std::vector<MTet4*> &newTets, MTet4 *tet, - int iLocalFace, const qualityMeasure4Tet &cr); + int iLocalFace, const qmTetrahedron::Measures &cr); bool smoothVertex(MTet4 *t, int iLocalVertex, - const qualityMeasure4Tet &cr); + const qmTetrahedron::Measures &cr); bool smoothVertexOptimize(MTet4 *t, int iVertex, - const qualityMeasure4Tet &cr); + const qmTetrahedron::Measures &cr); bool collapseVertex(std::vector<MTet4*> &newTets, MTet4 *t, int iVertex, int iTarget, - const qualityMeasure4Tet &cr, + const qmTetrahedron::Measures &cr, const localMeshModAction = GMSH_DOIT, double *result = 0); bool egeSplit(std::vector<MTet4*> &newTets, MTet4 *tet, MVertex *newVertex, int iLocalEdge, - const qualityMeasure4Tet &cr); + const qmTetrahedron::Measures &cr); bool sliverRemoval(std::vector<MTet4*> &newTets, MTet4 *t, - const qualityMeasure4Tet &cr); + const qmTetrahedron::Measures &cr); #endif diff --git a/Mesh/qualityMeasures.cpp b/Mesh/qualityMeasures.cpp index 84af3697cd345e433f1950d7ab3c25a74a49a42c..ea9615bf1255aeeefb0af65b8eb4ff62c92f2d73 100644 --- a/Mesh/qualityMeasures.cpp +++ b/Mesh/qualityMeasures.cpp @@ -9,330 +9,14 @@ #include "MTriangle.h" #include "MQuadrangle.h" #include "MTetrahedron.h" +#include "MPrism.h" +#include "MHexahedron.h" #include "Numeric.h" #include "polynomialBasis.h" #include "GmshMessage.h" #include <limits> #include <string.h> -double qmTriangle(const BDS_Point *p1, const BDS_Point *p2, const BDS_Point *p3, - const qualityMeasure4Triangle &cr) -{ - return qmTriangle(p1->X, p1->Y, p1->Z, p2->X, p2->Y, p2->Z, p3->X, p3->Y, p3->Z, cr); -} - -double qmTriangle(BDS_Face *t, const qualityMeasure4Triangle &cr) -{ - BDS_Point *n[4]; - t->getNodes(n); - return qmTriangle(n[0], n[1], n[2], cr); -} - -double qmTriangle(MTriangle*t, const qualityMeasure4Triangle &cr) -{ - return qmTriangle(t->getVertex(0), t->getVertex(1), t->getVertex(2), cr); -} - -double qmTriangle(const MVertex *v1, const MVertex *v2, const MVertex *v3, - const qualityMeasure4Triangle &cr) -{ - return qmTriangle(v1->x(), v1->y(), v1->z(), v2->x(), v2->y(), v2->z(), - v3->x(), v3->y(), v3->z(), cr); -} - -// Triangle abc -// quality is between 0 and 1 - -double qmTriangle(const double &xa, const double &ya, const double &za, - const double &xb, const double &yb, const double &zb, - const double &xc, const double &yc, const double &zc, - const qualityMeasure4Triangle &cr) -{ - double quality; - switch(cr){ - case QMTRI_RHO: - { - // quality = rho / R = 2 * inscribed radius / circumradius - double a [3] = {xc - xb, yc - yb, zc - zb}; - double b [3] = {xa - xc, ya - yc, za - zc}; - double c [3] = {xb - xa, yb - ya, zb - za}; - norme(a); - norme(b); - norme(c); - double pva [3]; prodve(b, c, pva); const double sina = norm3(pva); - double pvb [3]; prodve(c, a, pvb); const double sinb = norm3(pvb); - double pvc [3]; prodve(a, b, pvc); const double sinc = norm3(pvc); - - if (sina == 0.0 && sinb == 0.0 && sinc == 0.0) quality = 0.0; - else quality = 2 * (2 * sina * sinb * sinc / (sina + sinb + sinc)); - } - break; - // condition number - case QMTRI_COND: - { - /* - double a [3] = {xc - xa, yc - ya, zc - za}; - double b [3] = {xb - xa, yb - ya, zb - za}; - double c [3] ; prodve(a, b, c); norme(c); - double A[3][3] = {{a[0] , b[0] , c[0]} , - {a[1] , b[1] , c[1]} , - {a[2] , b[2] , c[2]}}; - */ - quality = -1; - } - break; - default: - Msg::Error("Unknown quality measure"); - return 0.; - } - - return quality; -} - -double qmTet(MTetrahedron *t, const qualityMeasure4Tet &cr, double *volume) -{ - return qmTet(t->getVertex(0), t->getVertex(1), t->getVertex(2), t->getVertex(3), - cr, volume); -} - -double qmTet(const MVertex *v1, const MVertex *v2, const MVertex *v3, - const MVertex *v4, const qualityMeasure4Tet &cr, double *volume) -{ - return qmTet(v1->x(), v1->y(), v1->z(), v2->x(), v2->y(), v2->z(), - v3->x(), v3->y(), v3->z(), v4->x(), v4->y(), v4->z(), cr, volume); -} - -double qmTet(const double &x1, const double &y1, const double &z1, - const double &x2, const double &y2, const double &z2, - const double &x3, const double &y3, const double &z3, - const double &x4, const double &y4, const double &z4, - const qualityMeasure4Tet &cr, double *volume) -{ - switch(cr){ - case QMTET_ONE: - return 1.0; - case QMTET_3: - { - double mat[3][3]; - mat[0][0] = x2 - x1; - mat[0][1] = x3 - x1; - mat[0][2] = x4 - x1; - mat[1][0] = y2 - y1; - mat[1][1] = y3 - y1; - mat[1][2] = y4 - y1; - mat[2][0] = z2 - z1; - mat[2][1] = z3 - z1; - mat[2][2] = z4 - z1; - *volume = fabs(det3x3(mat)) / 6.; - double l = ((x2 - x1) * (x2 - x1) + - (y2 - y1) * (y2 - y1) + - (z2 - z1) * (z2 - z1)); - l += ((x3 - x1) * (x3 - x1) + (y3 - y1) * (y3 - y1) + (z3 - z1) * (z3 - z1)); - l += ((x4 - x1) * (x4 - x1) + (y4 - y1) * (y4 - y1) + (z4 - z1) * (z4 - z1)); - l += ((x3 - x2) * (x3 - x2) + (y3 - y2) * (y3 - y2) + (z3 - z2) * (z3 - z2)); - l += ((x4 - x2) * (x4 - x2) + (y4 - y2) * (y4 - y2) + (z4 - z2) * (z4 - z2)); - l += ((x3 - x4) * (x3 - x4) + (y3 - y4) * (y3 - y4) + (z3 - z4) * (z3 - z4)); - return 12. * pow(3 * fabs(*volume), 2. / 3.) / l; - } - case QMTET_2: - { - double mat[3][3]; - mat[0][0] = x2 - x1; - mat[0][1] = x3 - x1; - mat[0][2] = x4 - x1; - mat[1][0] = y2 - y1; - mat[1][1] = y3 - y1; - mat[1][2] = y4 - y1; - mat[2][0] = z2 - z1; - mat[2][1] = z3 - z1; - mat[2][2] = z4 - z1; - *volume = fabs(det3x3(mat)) / 6.; - double p0[3] = {x1, y1, z1}; - double p1[3] = {x2, y2, z2}; - double p2[3] = {x3, y3, z3}; - double p3[3] = {x4, y4, z4}; - double s1 = fabs(triangle_area(p0, p1, p2)); - double s2 = fabs(triangle_area(p0, p2, p3)); - double s3 = fabs(triangle_area(p0, p1, p3)); - double s4 = fabs(triangle_area(p1, p2, p3)); - double rhoin = 3. * fabs(*volume) / (s1 + s2 + s3 + s4); - double l = sqrt((x2 - x1) * (x2 - x1) + - (y2 - y1) * (y2 - y1) + - (z2 - z1) * (z2 - z1)); - l = std::max(l, sqrt((x3 - x1) * (x3 - x1) + (y3 - y1) * (y3 - y1) + - (z3 - z1) * (z3 - z1))); - l = std::max(l, sqrt((x4 - x1) * (x4 - x1) + (y4 - y1) * (y4 - y1) + - (z4 - z1) * (z4 - z1))); - l = std::max(l, sqrt((x3 - x2) * (x3 - x2) + (y3 - y2) * (y3 - y2) + - (z3 - z2) * (z3 - z2))); - l = std::max(l, sqrt((x4 - x2) * (x4 - x2) + (y4 - y2) * (y4 - y2) + - (z4 - z2) * (z4 - z2))); - l = std::max(l, sqrt((x3 - x4) * (x3 - x4) + (y3 - y4) * (y3 - y4) + - (z3 - z4) * (z3 - z4))); - return 2. * sqrt(6.) * rhoin / l; - } - break; - case QMTET_COND: - { - /// condition number is defined as (see Knupp & Freitag in IJNME) - double INVW[3][3] = {{1,-1./sqrt(3.),-1./sqrt(6.)},{0,2/sqrt(3.),-1./sqrt(6.)},{0,0,sqrt(1.5)}}; - double A[3][3] = {{x2-x1,y2-y1,z2-z1},{x3-x1,y3-y1,z3-z1},{x4-x1,y4-y1,z4-z1}}; - double S[3][3],INVS[3][3]; - matmat(A,INVW,S); - *volume = inv3x3(S,INVS) * 0.70710678118654762;//2/sqrt(2); - double normS = norm2 (S); - double normINVS = norm2 (INVS); - return normS * normINVS; - } - default: - Msg::Error("Unknown quality measure"); - return 0.; - } -} - -/* -double conditionNumberAndDerivativeOfTet(const double &x1, const double &y1, const double &z1, - const double &x2, const double &y2, const double &z2, - const double &x3, const double &y3, const double &z3, - const double &x4, const double &y4, const double &z4){ - - double INVW[3][3] = {{1,-1./sqrt(3.),-1./sqrt(6.)},{0,2/sqrt(3.),-1./sqrt(6.)},{0,0,sqrt(1.5)}}; - double A[3][3] = {{x2-x1,y2-y1,z2-z1},{x3-x1,y3-y1,z3-z1},{x4-x1,y4-y1,z4-z1}}; - double S[3][3],INVS[3][3]; - matmat(A,INVW,S); - double sigma = inv3x3(S,INVS); - double normS = norm2 (S); - double normINVS = norm2 (INVS); - conditionNumber = normS * normINVS; - -} -*/ - -double qmTriangleAngles (MTriangle *e) { - double a = 500; - double worst_quality = std::numeric_limits<double>::max(); - double mat[3][3]; - double mat2[3][3]; - double den = atan(a*(M_PI/9)) + atan(a*(M_PI/9)); - - // This matrix is used to "rotate" the triangle to get each vertex - // as the "origin" of the mapping in turn - double rot[3][3]; - rot[0][0]=-1; rot[0][1]=1; rot[0][2]=0; - rot[1][0]=-1; rot[1][1]=0; rot[1][2]=0; - rot[2][0]= 0; rot[2][1]=0; rot[2][2]=1; - double tmp[3][3]; - - //double minAngle = 120.0; - for (int i = 0; i < e->getNumPrimaryVertices(); i++) { - const double u = i == 1 ? 1 : 0; - const double v = i == 2 ? 1 : 0; - const double w = 0; - e->getJacobian(u, v, w, mat); - e->getPrimaryJacobian(u,v,w,mat2); - for (int j = 0; j < i; j++) { - matmat(rot,mat,tmp); - memcpy(mat, tmp, sizeof(mat)); - } - //get angle - double v1[3] = {mat[0][0], mat[0][1], mat[0][2] }; - double v2[3] = {mat[1][0], mat[1][1], mat[1][2] }; - double v3[3] = {mat2[0][0], mat2[0][1], mat2[0][2] }; - double v4[3] = {mat2[1][0], mat2[1][1], mat2[1][2] }; - norme(v1); - norme(v2); - norme(v3); - norme(v4); - double v12[3], v34[3]; - prodve(v1,v2,v12); - prodve(v3,v4,v34); - norme(v12); - norme(v34); - double orientation; - prosca(v12,v34,&orientation); - - // If the triangle is "flipped" it's no good - if (orientation < 0) - return -std::numeric_limits<double>::max(); - - double c; - prosca(v1,v2,&c); - double x = acos(c)-M_PI/3; - //double angle = (x+M_PI/3)/M_PI*180; - double quality = (atan(a*(x+M_PI/9)) + atan(a*(M_PI/9-x)))/den; - worst_quality = std::min(worst_quality, quality); - - //minAngle = std::min(angle, minAngle); - //printf("Angle %g ", angle); - // printf("Quality %g\n",quality); - } - //printf("MinAngle %g \n", minAngle); - //return minAngle; - - return worst_quality; -} - - -double qmQuadrangleAngles (MQuadrangle *e) { - double a = 100; - double worst_quality = std::numeric_limits<double>::max(); - double mat[3][3]; - double mat2[3][3]; - double den = atan(a*(M_PI/4)) + atan(a*(2*M_PI/4 - (M_PI/4))); - - // This matrix is used to "rotate" the triangle to get each vertex - // as the "origin" of the mapping in turn - //double rot[3][3]; - //rot[0][0]=-1; rot[0][1]=1; rot[0][2]=0; - //rot[1][0]=-1; rot[1][1]=0; rot[1][2]=0; - //rot[2][0]= 0; rot[2][1]=0; rot[2][2]=1; - //double tmp[3][3]; - - const double u[9] = {-1,-1, 1, 1, 0,0,1,-1,0}; - const double v[9] = {-1, 1, 1,-1, -1,1,0,0,0}; - - for (int i = 0; i < 9; i++) { - - e->getJacobian(u[i], v[i], 0, mat); - e->getPrimaryJacobian(u[i],v[i],0,mat2); - //for (int j = 0; j < i; j++) { - // matmat(rot,mat,tmp); - // memcpy(mat, tmp, sizeof(mat)); - //} - - //get angle - double v1[3] = {mat[0][0], mat[0][1], mat[0][2] }; - double v2[3] = {mat[1][0], mat[1][1], mat[1][2] }; - double v3[3] = {mat2[0][0], mat2[0][1], mat2[0][2] }; - double v4[3] = {mat2[1][0], mat2[1][1], mat2[1][2] }; - norme(v1); - norme(v2); - norme(v3); - norme(v4); - double v12[3], v34[3]; - prodve(v1,v2,v12); - prodve(v3,v4,v34); - norme(v12); - norme(v34); - double orientation; - prosca(v12,v34,&orientation); - - // If the if the triangle is "flipped" it's no good - // if (orientation < 0) - // return -std::numeric_limits<double>::max(); - - double c; - prosca(v1,v2,&c); - double x = fabs(acos(c))-M_PI/2; - //double angle = fabs(acos(c))*180/M_PI; - double quality = (atan(a*(x+M_PI/4)) + atan(a*(2*M_PI/4 - (x+M_PI/4))))/den; - worst_quality = std::min(worst_quality, quality); - } - - return worst_quality; - -} - namespace { @@ -471,6 +155,7 @@ inline void triAreaAndGrad(const double fact, const fullMatrix<double> &vga, } +// Revert vector and gradients inline void revertVG(const fullMatrix<double> &vg, fullMatrix<double> &res) { res(0, 0) = -vg(0, 3); res(0, 1) = -vg(0, 4); res(0, 2) = -vg(0, 5); res(0, 6) = -vg(0, 6); @@ -482,10 +167,138 @@ inline void revertVG(const fullMatrix<double> &vg, fullMatrix<double> &res) } -void measuresTriangle::getNCJ(const double &x0, const double &y0, const double &z0, - const double &x1, const double &y1, const double &z1, - const double &x2, const double &y2, const double &z2, - fullVector<double> &ncj) +double qmTriangle::gamma(const BDS_Point *p1, const BDS_Point *p2, const BDS_Point *p3) +{ + return gamma(p1->X, p1->Y, p1->Z, p2->X, p2->Y, p2->Z, p3->X, p3->Y, p3->Z); +} + + +double qmTriangle::gamma(BDS_Face *t) +{ + BDS_Point *n[4]; + t->getNodes(n); + return gamma(n[0], n[1], n[2]); +} + + +double qmTriangle::gamma(MTriangle*t) +{ + return gamma(t->getVertex(0), t->getVertex(1), t->getVertex(2)); +} + + +double qmTriangle::gamma(const MVertex *v1, const MVertex *v2, const MVertex *v3) +{ + return gamma(v1->x(), v1->y(), v1->z(), v2->x(), v2->y(), v2->z(), v3->x(), v3->y(), v3->z()); +} + + +// Triangle abc +// quality is between 0 and 1 +double qmTriangle::gamma(const double &xa, const double &ya, const double &za, + const double &xb, const double &yb, const double &zb, + const double &xc, const double &yc, const double &zc) +{ + // quality = rho / R = 2 * inscribed radius / circumradius + double a [3] = {xc - xb, yc - yb, zc - zb}; + double b [3] = {xa - xc, ya - yc, za - zc}; + double c [3] = {xb - xa, yb - ya, zb - za}; + norme(a); + norme(b); + norme(c); + double pva [3]; prodve(b, c, pva); const double sina = norm3(pva); + double pvb [3]; prodve(c, a, pvb); const double sinb = norm3(pvb); + double pvc [3]; prodve(a, b, pvc); const double sinc = norm3(pvc); + + if (sina == 0.0 && sinb == 0.0 && sinc == 0.0) return 0.0; + else return 2 * (2 * sina * sinb * sinc / (sina + sinb + sinc)); +} + + +double qmTriangle::eta(MTriangle *el) +{ + MVertex *_v[3] = {el->getVertex(0), el->getVertex(1), el->getVertex(2)}; + + double a1 = 180 * angle3Vertices(_v[0], _v[1], _v[2]) / M_PI; + double a2 = 180 * angle3Vertices(_v[1], _v[2], _v[0]) / M_PI; + double a3 = 180 * angle3Vertices(_v[2], _v[0], _v[1]) / M_PI; + + double amin = std::min(std::min(a1,a2),a3); + double angle = fabs(60. - amin); + return 1.-angle/60; +} + + +double qmTriangle::angles(MTriangle *e) +{ + double a = 500; + double worst_quality = std::numeric_limits<double>::max(); + double mat[3][3]; + double mat2[3][3]; + double den = atan(a*(M_PI/9)) + atan(a*(M_PI/9)); + + // This matrix is used to "rotate" the triangle to get each vertex + // as the "origin" of the mapping in turn + double rot[3][3]; + rot[0][0]=-1; rot[0][1]=1; rot[0][2]=0; + rot[1][0]=-1; rot[1][1]=0; rot[1][2]=0; + rot[2][0]= 0; rot[2][1]=0; rot[2][2]=1; + double tmp[3][3]; + + //double minAngle = 120.0; + for (int i = 0; i < e->getNumPrimaryVertices(); i++) { + const double u = i == 1 ? 1 : 0; + const double v = i == 2 ? 1 : 0; + const double w = 0; + e->getJacobian(u, v, w, mat); + e->getPrimaryJacobian(u,v,w,mat2); + for (int j = 0; j < i; j++) { + matmat(rot,mat,tmp); + memcpy(mat, tmp, sizeof(mat)); + } + //get angle + double v1[3] = {mat[0][0], mat[0][1], mat[0][2] }; + double v2[3] = {mat[1][0], mat[1][1], mat[1][2] }; + double v3[3] = {mat2[0][0], mat2[0][1], mat2[0][2] }; + double v4[3] = {mat2[1][0], mat2[1][1], mat2[1][2] }; + norme(v1); + norme(v2); + norme(v3); + norme(v4); + double v12[3], v34[3]; + prodve(v1,v2,v12); + prodve(v3,v4,v34); + norme(v12); + norme(v34); + double orientation; + prosca(v12,v34,&orientation); + + // If the triangle is "flipped" it's no good + if (orientation < 0) + return -std::numeric_limits<double>::max(); + + double c; + prosca(v1,v2,&c); + double x = acos(c)-M_PI/3; + //double angle = (x+M_PI/3)/M_PI*180; + double quality = (atan(a*(x+M_PI/9)) + atan(a*(M_PI/9-x)))/den; + worst_quality = std::min(worst_quality, quality); + + //minAngle = std::min(angle, minAngle); + //printf("Angle %g ", angle); + // printf("Quality %g\n",quality); + } + //printf("MinAngle %g \n", minAngle); + //return minAngle; + + return worst_quality; +} + + +void qmTriangle::NCJ(const double &x0, const double &y0, const double &z0, + const double &x1, const double &y1, const double &z1, + const double &x2, const double &y2, const double &z2, + fullVector<double> &ncj) { // Compute unit vectors for each edge double x01n, y01n, z01n, x12n, y12n, z12n, x20n, y20n, z20n; @@ -495,20 +308,20 @@ void measuresTriangle::getNCJ(const double &x0, const double &y0, const double & // Compute NCJ at vertex from unit vectors a and b as 0.5*||a^b||/A_equilateral // Factor = 2./sqrt(3.) = 0.5/A_equilateral - static const double fact = 1.1547005383792517; + static const double fact = 2./sqrt(3.); ncj(0) = triArea(fact, x01n, y01n, z01n, -x20n, -y20n, -z20n); ncj(1) = triArea(fact, x12n, y12n, z12n, -x01n, -y01n, -z01n); ncj(2) = triArea(fact, x20n, y20n, z20n, -x12n, -y12n, -z12n); } -void measuresTriangle::getNCJAndGradients(const double &x0, const double &y0, const double &z0, - const double &x1, const double &y1, const double &z1, - const double &x2, const double &y2, const double &z2, - fullMatrix<double> &res) +void qmTriangle::NCJAndGradients(const double &x0, const double &y0, const double &z0, + const double &x1, const double &y1, const double &z1, + const double &x2, const double &y2, const double &z2, + fullMatrix<double> &res) { // Factor = 2./sqrt(3.) = 0.5/A_equilateral - static const double fact = 1.1547005383792517; + static const double fact = 2./sqrt(3.); // Compute unit vector and its gradients for each edge fullMatrix<double> vg01(3,7); @@ -553,11 +366,111 @@ void measuresTriangle::getNCJAndGradients(const double &x0, const double &y0, co } -void measuresQuadrangle::getNCJ(const double &x0, const double &y0, const double &z0, - const double &x1, const double &y1, const double &z1, - const double &x2, const double &y2, const double &z2, - const double &x3, const double &y3, const double &z3, - fullVector<double> &ncj) +double qmQuadrangle::eta(MQuadrangle *el) { + double AR = 1;//(minEdge()/maxEdge()); + + MVertex *_v[4] = {el->getVertex(0), el->getVertex(1), el->getVertex(2), el->getVertex(3)}; + + SVector3 v01 (_v[1]->x()-_v[0]->x(),_v[1]->y()-_v[0]->y(),_v[1]->z()-_v[0]->z()); + SVector3 v12 (_v[2]->x()-_v[1]->x(),_v[2]->y()-_v[1]->y(),_v[2]->z()-_v[1]->z()); + SVector3 v23 (_v[3]->x()-_v[2]->x(),_v[3]->y()-_v[2]->y(),_v[3]->z()-_v[2]->z()); + SVector3 v30 (_v[0]->x()-_v[3]->x(),_v[0]->y()-_v[3]->y(),_v[0]->z()-_v[3]->z()); + + SVector3 a = crossprod(v01,v12); + SVector3 b = crossprod(v12,v23); + SVector3 c = crossprod(v23,v30); + SVector3 d = crossprod(v30,v01); + + double sign = 1.0; + if (dot(a,b) < 0 || dot(a,c) < 0 || dot(a,d) < 0 )sign = -1; + // FIXME ... + // if (a.z() > 0 || b.z() > 0 || c.z() > 0 || d.z() > 0) sign = -1; + + double a1 = 180 * angle3Vertices(_v[0], _v[1], _v[2]) / M_PI; + double a2 = 180 * angle3Vertices(_v[1], _v[2], _v[3]) / M_PI; + double a3 = 180 * angle3Vertices(_v[2], _v[3], _v[0]) / M_PI; + double a4 = 180 * angle3Vertices(_v[3], _v[0], _v[1]) / M_PI; + + a1 = std::min(180.,a1); + a2 = std::min(180.,a2); + a3 = std::min(180.,a3); + a4 = std::min(180.,a4); + double angle = fabs(90. - a1); + angle = std::max(fabs(90. - a2),angle); + angle = std::max(fabs(90. - a3),angle); + angle = std::max(fabs(90. - a4),angle); + + return sign*(1.-angle/90) * AR; +} + + +double qmQuadrangle::angles(MQuadrangle *e) +{ + double a = 100; + double worst_quality = std::numeric_limits<double>::max(); + double mat[3][3]; + double mat2[3][3]; + double den = atan(a*(M_PI/4)) + atan(a*(2*M_PI/4 - (M_PI/4))); + + // This matrix is used to "rotate" the triangle to get each vertex + // as the "origin" of the mapping in turn + //double rot[3][3]; + //rot[0][0]=-1; rot[0][1]=1; rot[0][2]=0; + //rot[1][0]=-1; rot[1][1]=0; rot[1][2]=0; + //rot[2][0]= 0; rot[2][1]=0; rot[2][2]=1; + //double tmp[3][3]; + + const double u[9] = {-1,-1, 1, 1, 0,0,1,-1,0}; + const double v[9] = {-1, 1, 1,-1, -1,1,0,0,0}; + + for (int i = 0; i < 9; i++) { + + e->getJacobian(u[i], v[i], 0, mat); + e->getPrimaryJacobian(u[i],v[i],0,mat2); + //for (int j = 0; j < i; j++) { + // matmat(rot,mat,tmp); + // memcpy(mat, tmp, sizeof(mat)); + //} + + //get angle + double v1[3] = {mat[0][0], mat[0][1], mat[0][2] }; + double v2[3] = {mat[1][0], mat[1][1], mat[1][2] }; + double v3[3] = {mat2[0][0], mat2[0][1], mat2[0][2] }; + double v4[3] = {mat2[1][0], mat2[1][1], mat2[1][2] }; + norme(v1); + norme(v2); + norme(v3); + norme(v4); + double v12[3], v34[3]; + prodve(v1,v2,v12); + prodve(v3,v4,v34); + norme(v12); + norme(v34); + double orientation; + prosca(v12,v34,&orientation); + + // If the if the triangle is "flipped" it's no good + // if (orientation < 0) + // return -std::numeric_limits<double>::max(); + + double c; + prosca(v1,v2,&c); + double x = fabs(acos(c))-M_PI/2; + //double angle = fabs(acos(c))*180/M_PI; + double quality = (atan(a*(x+M_PI/4)) + atan(a*(2*M_PI/4 - (x+M_PI/4))))/den; + worst_quality = std::min(worst_quality, quality); + } + + return worst_quality; + +} + + +void qmQuadrangle::NCJ(const double &x0, const double &y0, const double &z0, + const double &x1, const double &y1, const double &z1, + const double &x2, const double &y2, const double &z2, + const double &x3, const double &y3, const double &z3, + fullVector<double> &ncj) { // Compute unit vectors for each edge double x01n, y01n, z01n, x12n, y12n, z12n, x23n, y23n, z23n, x30n, y30n, z30n; @@ -576,11 +489,11 @@ void measuresQuadrangle::getNCJ(const double &x0, const double &y0, const double } -void measuresQuadrangle::getNCJAndGradients(const double &x0, const double &y0, const double &z0, - const double &x1, const double &y1, const double &z1, - const double &x2, const double &y2, const double &z2, - const double &x3, const double &y3, const double &z3, - fullMatrix<double> &res) +void qmQuadrangle::NCJAndGradients(const double &x0, const double &y0, const double &z0, + const double &x1, const double &y1, const double &z1, + const double &x2, const double &y2, const double &z2, + const double &x3, const double &y3, const double &z3, + fullMatrix<double> &res) { // Factor = 1. = 0.5/A_triRect static const double fact = 1.; @@ -643,3 +556,215 @@ void measuresQuadrangle::getNCJAndGradients(const double &x0, const double &y0, res(3, 9) = res3(0); res(3, 10) = res3(1); res(3, 11) = res3(2); res(3, 12) = res3(9); } + + +double qmTetrahedron::qm(MTetrahedron *t, const Measures &cr, double *volume) +{ + return qm(t->getVertex(0), t->getVertex(1), t->getVertex(2), t->getVertex(3), cr, volume); +} + + +double qmTetrahedron::qm(const MVertex *v1, const MVertex *v2, const MVertex *v3, + const MVertex *v4, const Measures &cr, double *volume) +{ + return qm(v1->x(), v1->y(), v1->z(), v2->x(), v2->y(), v2->z(), + v3->x(), v3->y(), v3->z(), v4->x(), v4->y(), v4->z(), cr, volume); +} + + +double qmTetrahedron::qm(const double &x1, const double &y1, const double &z1, + const double &x2, const double &y2, const double &z2, + const double &x3, const double &y3, const double &z3, + const double &x4, const double &y4, const double &z4, + const Measures &cr, double *volume) +{ + switch(cr){ + case QMTET_ONE: + return 1.0; + case QMTET_ETA: + return eta(x1, y1, z1, x2, y2, z2, x3, y3, z3, x4, y4, z4, volume); + case QMTET_GAMMA: + return gamma(x1, y1, z1, x2, y2, z2, x3, y3, z3, x4, y4, z4, volume); + case QMTET_COND: + return cond(x1, y1, z1, x2, y2, z2, x3, y3, z3, x4, y4, z4, volume); + default: + Msg::Error("Unknown quality measure"); + return 0.; + } +} + + +double qmTetrahedron::eta(const double &x1, const double &y1, const double &z1, + const double &x2, const double &y2, const double &z2, + const double &x3, const double &y3, const double &z3, + const double &x4, const double &y4, const double &z4, + double *volume) +{ + double mat[3][3]; + mat[0][0] = x2 - x1; + mat[0][1] = x3 - x1; + mat[0][2] = x4 - x1; + mat[1][0] = y2 - y1; + mat[1][1] = y3 - y1; + mat[1][2] = y4 - y1; + mat[2][0] = z2 - z1; + mat[2][1] = z3 - z1; + mat[2][2] = z4 - z1; + *volume = fabs(det3x3(mat)) / 6.; + double l = ((x2 - x1) * (x2 - x1) + + (y2 - y1) * (y2 - y1) + + (z2 - z1) * (z2 - z1)); + l += ((x3 - x1) * (x3 - x1) + (y3 - y1) * (y3 - y1) + (z3 - z1) * (z3 - z1)); + l += ((x4 - x1) * (x4 - x1) + (y4 - y1) * (y4 - y1) + (z4 - z1) * (z4 - z1)); + l += ((x3 - x2) * (x3 - x2) + (y3 - y2) * (y3 - y2) + (z3 - z2) * (z3 - z2)); + l += ((x4 - x2) * (x4 - x2) + (y4 - y2) * (y4 - y2) + (z4 - z2) * (z4 - z2)); + l += ((x3 - x4) * (x3 - x4) + (y3 - y4) * (y3 - y4) + (z3 - z4) * (z3 - z4)); + return 12. * pow(3 * fabs(*volume), 2. / 3.) / l; +} + + +double qmTetrahedron::gamma(const double &x1, const double &y1, const double &z1, + const double &x2, const double &y2, const double &z2, + const double &x3, const double &y3, const double &z3, + const double &x4, const double &y4, const double &z4, + double *volume) +{ + double mat[3][3]; + mat[0][0] = x2 - x1; + mat[0][1] = x3 - x1; + mat[0][2] = x4 - x1; + mat[1][0] = y2 - y1; + mat[1][1] = y3 - y1; + mat[1][2] = y4 - y1; + mat[2][0] = z2 - z1; + mat[2][1] = z3 - z1; + mat[2][2] = z4 - z1; + *volume = fabs(det3x3(mat)) / 6.; + double p0[3] = {x1, y1, z1}; + double p1[3] = {x2, y2, z2}; + double p2[3] = {x3, y3, z3}; + double p3[3] = {x4, y4, z4}; + double s1 = fabs(triangle_area(p0, p1, p2)); + double s2 = fabs(triangle_area(p0, p2, p3)); + double s3 = fabs(triangle_area(p0, p1, p3)); + double s4 = fabs(triangle_area(p1, p2, p3)); + double rhoin = 3. * fabs(*volume) / (s1 + s2 + s3 + s4); + double l = sqrt((x2 - x1) * (x2 - x1) + + (y2 - y1) * (y2 - y1) + + (z2 - z1) * (z2 - z1)); + l = std::max(l, sqrt((x3 - x1) * (x3 - x1) + (y3 - y1) * (y3 - y1) + + (z3 - z1) * (z3 - z1))); + l = std::max(l, sqrt((x4 - x1) * (x4 - x1) + (y4 - y1) * (y4 - y1) + + (z4 - z1) * (z4 - z1))); + l = std::max(l, sqrt((x3 - x2) * (x3 - x2) + (y3 - y2) * (y3 - y2) + + (z3 - z2) * (z3 - z2))); + l = std::max(l, sqrt((x4 - x2) * (x4 - x2) + (y4 - y2) * (y4 - y2) + + (z4 - z2) * (z4 - z2))); + l = std::max(l, sqrt((x3 - x4) * (x3 - x4) + (y3 - y4) * (y3 - y4) + + (z3 - z4) * (z3 - z4))); + return 2. * sqrt(6.) * rhoin / l; +} + + +double qmTetrahedron::cond(const double &x1, const double &y1, const double &z1, + const double &x2, const double &y2, const double &z2, + const double &x3, const double &y3, const double &z3, + const double &x4, const double &y4, const double &z4, + double *volume) +{ + /// condition number is defined as (see Knupp & Freitag in IJNME) + double INVW[3][3] = {{1,-1./sqrt(3.),-1./sqrt(6.)},{0,2/sqrt(3.),-1./sqrt(6.)},{0,0,sqrt(1.5)}}; + double A[3][3] = {{x2-x1,y2-y1,z2-z1},{x3-x1,y3-y1,z3-z1},{x4-x1,y4-y1,z4-z1}}; + double S[3][3],INVS[3][3]; + matmat(A,INVW,S); + *volume = inv3x3(S,INVS) * 0.70710678118654762;//2/sqrt(2); + double normS = norm2 (S); + double normINVS = norm2 (INVS); + return normS * normINVS; +} + + +// TODO: Replace this +static double prismNCJ(const MVertex* a, const MVertex* b, const MVertex* c, const MVertex* d) +{ + static const double fact = 2./sqrt(3); + + const SVector3 vec1 = SVector3(b->x()-a->x(),b->y()-a->y(),b->z()-a->z()); + const SVector3 vec2 = SVector3(c->x()-a->x(),c->y()-a->y(),c->z()-a->z()); + const SVector3 vec3 = SVector3(d->x()-a->x(),d->y()-a->y(),d->z()-a->z()); + + const double l1 = vec1.norm(); + const double l2 = vec2.norm(); + const double l3 = vec3.norm(); + + const double val = dot(vec1,crossprod(vec2,vec3)); + return fact*fabs(val)/(l1*l2*l3); +} + + +double qmPrism::minNCJ(const MPrism *el) { + const MVertex *a = el->getVertex(0),*b= el->getVertex(1), *c= el->getVertex(2); + const MVertex *d = el->getVertex(3),*e= el->getVertex(4), *f= el->getVertex(5); + const double j[6] = { + prismNCJ(a,b,c,d), + prismNCJ(b,a,c,e), + prismNCJ(c,a,b,f), + prismNCJ(d,a,e,f), + prismNCJ(e,b,d,f), + prismNCJ(f,c,d,e)}; + const double result = *std::min_element(j,j+6); + return result; +} + + +//void qmPrism::NCJ(const double &x0, const double &y0, const double &z0, +// const double &x1, const double &y1, const double &z1, +// const double &x2, const double &y2, const double &z2, +// const double &x3, const double &y3, const double &z3, +// const double &x4, const double &y4, const double &z4, +// fullVector<double> &ncj) +//{ +// // Compute unit vectors for each edge +// double x01n, y01n, z01n, x12n, y12n, z12n, x23n, y23n, z23n, x30n, y30n, z30n; +// unitVec(x0, y0, z0, x1, y1, z1, x01n, y01n, z01n); +// unitVec(x1, y1, z1, x2, y2, z2, x12n, y12n, z12n); +// unitVec(x2, y2, z2, x3, y3, z3, x23n, y23n, z23n); +// unitVec(x3, y3, z3, x0, y0, z0, x30n, y30n, z30n); +// +// // Compute NCJ at vertex from unit vectors a and b as 0.5*||a^b||/A_equilateral +// // Factor = 2./sqrt(3.) = 0.5/A_equilateral +// static const double fact = 1.1547005383792517; +// ncj(0) = triArea(fact, x01n, y01n, z01n, -x20n, -y20n, -z20n); +// ncj(1) = triArea(fact, x12n, y12n, z12n, -x01n, -y01n, -z01n); +// ncj(2) = triArea(fact, x20n, y20n, z20n, -x12n, -y12n, -z12n); +//} + + +// TODO: Remove this (useless as quality measure) +double qmHexahedron::angles(MHexahedron *el) +{ + double angleMax = 0.0; + double angleMin = M_PI; + double zeta = 0.0; + for (int i=0; i<el->getNumFaces(); i++){ + std::vector<MVertex*> vv; + vv.push_back(el->getFace(i).getVertex(0)); + vv.push_back(el->getFace(i).getVertex(1)); + vv.push_back(el->getFace(i).getVertex(2)); + vv.push_back(el->getFace(i).getVertex(3)); + // MVertex *v0 = new MVertex(0, 0, 0); vv.push_back(v0); + // MVertex *v1 = new MVertex(1., 0, 0);vv.push_back(v1); + // MVertex *v2 = new MVertex(2., 1., 0);vv.push_back(v2); + // MVertex *v3 = new MVertex(1, 1., 0);vv.push_back(v3); + for (int j=0; j<4; j++){ + SVector3 a(vv[(j+2)%4]->x()-vv[(j+1)%4]->x(),vv[(j+2)%4]->y()-vv[(j+1)%4]->y(),vv[(j+2)%4]->z()-vv[(j+1)%4]->z() ); + SVector3 b(vv[(j+1)%4]->x()-vv[(j)%4]->x(), vv[(j+1)%4]->y()-vv[(j)%4]->y(), vv[(j+1)%4]->z()-vv[(j)%4]->z() ); + double angle = acos( dot(a,b)/(norm(a)*norm(b))); //*180/M_PI; + angleMax = std::max(angleMax, angle); + angleMin = std::min(angleMin, angle); + } + //printf("angle max =%g min =%g \n", angleMax*180/M_PI, angleMin*180/M_PI); + } + zeta = 1.-std::max((angleMax-0.5*M_PI)/(0.5*M_PI),(0.5*M_PI-angleMin)/(0.5*M_PI)); + return zeta; +} diff --git a/Mesh/qualityMeasures.h b/Mesh/qualityMeasures.h index 9637e25057be7394216ffcd0831dbad0a4c78689..8086d20856051492719b78ec61de90f5402f64dc 100644 --- a/Mesh/qualityMeasures.h +++ b/Mesh/qualityMeasures.h @@ -14,61 +14,121 @@ class MVertex; class MTriangle; class MQuadrangle; class MTetrahedron; +class MPrism; +class MHexahedron; class MElement; -enum qualityMeasure4Triangle {QMTRI_RHO, QMTRI_COND}; -enum qualityMeasure4Tet{QMTET_1, QMTET_2, QMTET_3, QMTET_ONE, QMTET_COND}; -double qmTriangleAngles (MTriangle *e); -double qmQuadrangleAngles (MQuadrangle *e); +class qmTriangle +{ +public: + static double gamma(MTriangle *f); + static double gamma(BDS_Face *f); + static double gamma(const BDS_Point *p1, const BDS_Point *p2, const BDS_Point *p3); + static double gamma(const MVertex *v1, const MVertex *v2, const MVertex *v3); + static double gamma(const double *d1, const double *d2, const double *d3); + static double gamma(const double &x1, const double &y1, const double &z1, + const double &x2, const double &y2, const double &z2, + const double &x3, const double &y3, const double &z3); + static double eta(MTriangle *el); + static double angles(MTriangle *e); + static double minNCJ(const MTriangle *e); + static void NCJ(const double &x0, const double &y0, const double &z0, + const double &x1, const double &y1, const double &z1, + const double &x2, const double &y2, const double &z2, + fullVector<double> &ncj); + static void NCJAndGradients(const double &x0, const double &y0, const double &z0, + const double &x1, const double &y1, const double &z1, + const double &x2, const double &y2, const double &z2, + fullMatrix<double> &ncj); +}; -double qmTriangle(MTriangle *f, const qualityMeasure4Triangle &cr); -double qmTriangle(BDS_Face *f, const qualityMeasure4Triangle &cr); -double qmTriangle(const BDS_Point *p1, const BDS_Point *p2, const BDS_Point *p3, - const qualityMeasure4Triangle &cr); -double qmTriangle(const MVertex *v1, const MVertex *v2, const MVertex *v3, - const qualityMeasure4Triangle &cr); -double qmTriangle(const double *d1, const double *d2, const double *d3, - const qualityMeasure4Triangle &cr); -double qmTriangle(const double &x1, const double &y1, const double &z1, - const double &x2, const double &y2, const double &z2, - const double &x3, const double &y3, const double &z3, - const qualityMeasure4Triangle &cr); -double qmTet(MTetrahedron *t, const qualityMeasure4Tet &cr, double *volume = 0); -double qmTet(const MVertex *v1, const MVertex *v2, const MVertex *v3, - const MVertex *v4, const qualityMeasure4Tet &cr, double *volume = 0); -double qmTet(const double &x1, const double &y1, const double &z1, - const double &x2, const double &y2, const double &z2, - const double &x3, const double &y3, const double &z3, - const double &x4, const double &y4, const double &z4, - const qualityMeasure4Tet &cr, double *volume = 0); -class measuresTriangle +class qmQuadrangle { public: - static void getNCJ(const double &x0, const double &y0, const double &z0, - const double &x1, const double &y1, const double &z1, - const double &x2, const double &y2, const double &z2, - fullVector<double> &ncj); - static void getNCJAndGradients(const double &x0, const double &y0, const double &z0, - const double &x1, const double &y1, const double &z1, - const double &x2, const double &y2, const double &z2, - fullMatrix<double> &ncj); + static double gamma(MQuadrangle *el) { return eta(el); } + static double eta(MQuadrangle *el); + static double angles(MQuadrangle *e); + static double minNCJ(const MQuadrangle *e); + static void NCJ(const double &x0, const double &y0, const double &z0, + const double &x1, const double &y1, const double &z1, + const double &x2, const double &y2, const double &z2, + const double &x3, const double &y3, const double &z3, + fullVector<double> &ncj); + static void NCJAndGradients(const double &x0, const double &y0, const double &z0, + const double &x1, const double &y1, const double &z1, + const double &x2, const double &y2, const double &z2, + const double &x3, const double &y3, const double &z3, + fullMatrix<double> &ncj); }; -class measuresQuadrangle + +class qmTetrahedron { public: - static void getNCJ(const double &x0, const double &y0, const double &z0, - const double &x1, const double &y1, const double &z1, + enum Measures {QMTET_GAMMA, QMTET_ETA, QMTET_ONE, QMTET_COND}; + static double qm(MTetrahedron *t, const Measures &cr, double *volume = 0); + static double qm(const BDS_Point *p1, const BDS_Point *p2, const BDS_Point *p3); + static double qm(const MVertex *v1, const MVertex *v2, const MVertex *v3, + const MVertex *v4, const Measures &cr, double *volume = 0); + static double qm(const double &x1, const double &y1, const double &z1, + const double &x2, const double &y2, const double &z2, + const double &x3, const double &y3, const double &z3, + const double &x4, const double &y4, const double &z4, + const Measures &cr, double *volume = 0); + static double eta(const double &x1, const double &y1, const double &z1, + const double &x2, const double &y2, const double &z2, + const double &x3, const double &y3, const double &z3, + const double &x4, const double &y4, const double &z4, + double *volume = 0); + static double gamma(const double &x1, const double &y1, const double &z1, + const double &x2, const double &y2, const double &z2, + const double &x3, const double &y3, const double &z3, + const double &x4, const double &y4, const double &z4, + double *volume = 0); + static double cond(const double &x1, const double &y1, const double &z1, const double &x2, const double &y2, const double &z2, const double &x3, const double &y3, const double &z3, - fullVector<double> &ncj); - static void getNCJAndGradients(const double &x0, const double &y0, const double &z0, - const double &x1, const double &y1, const double &z1, - const double &x2, const double &y2, const double &z2, - const double &x3, const double &y3, const double &z3, - fullMatrix<double> &ncj); + const double &x4, const double &y4, const double &z4, + double *volume = 0); + static double minNCJ(const MTetrahedron *e); + static void NCJ(const double &x0, const double &y0, const double &z0, + const double &x1, const double &y1, const double &z1, + const double &x2, const double &y2, const double &z2, + const double &x3, const double &y3, const double &z3, + fullVector<double> &ncj); + static void NCJAndGradients(const double &x0, const double &y0, const double &z0, + const double &x1, const double &y1, const double &z1, + const double &x2, const double &y2, const double &z2, + const double &x3, const double &y3, const double &z3, + fullMatrix<double> &ncj); +}; + + +class qmPrism +{ +public: + static double minNCJ(const MPrism *el); +// static void NCJ(const double &x0, const double &y0, const double &z0, +// const double &x1, const double &y1, const double &z1, +// const double &x2, const double &y2, const double &z2, +// const double &x3, const double &y3, const double &z3, +// const double &x4, const double &y4, const double &z4, +// fullVector<double> &ncj); +}; + + +class qmHexahedron +{ +public: + static double angles(MHexahedron *el); +// static void NCJ(const double &x0, const double &y0, const double &z0, +// const double &x1, const double &y1, const double &z1, +// const double &x2, const double &y2, const double &z2, +// const double &x3, const double &y3, const double &z3, +// const double &x4, const double &y4, const double &z4, +// fullVector<double> &ncj); }; #endif