From 7d08e0731690dfb8e2d7edd0f8eb7e89c2977f97 Mon Sep 17 00:00:00 2001 From: Jean-Francois Remacle <jean-francois.remacle@uclouvain.be> Date: Sat, 10 Mar 2012 10:28:47 +0000 Subject: [PATCH] frontal mesher is now fully functional for compound faces --- Geo/CMakeLists.txt | 1 + Geo/GFaceCompound.cpp | 101 ++++++++++++++++++++++++++++ Geo/GFaceCompound.h | 2 + Mesh/CMakeLists.txt | 2 +- Mesh/meshGFace.cpp | 4 +- Mesh/meshGFaceDelaunayInsertion.cpp | 75 +++++++++------------ Mesh/meshGFaceOptimize.cpp | 30 ++------- Mesh/meshGFaceOptimize.h | 1 - Numeric/Numeric.cpp | 3 +- Numeric/fullMatrix.cpp | 8 +-- benchmarks/stl/artery.geo | 4 +- benchmarks/stl/skull.geo | 4 +- 12 files changed, 155 insertions(+), 80 deletions(-) diff --git a/Geo/CMakeLists.txt b/Geo/CMakeLists.txt index 32bbeeb13d..17466e538b 100644 --- a/Geo/CMakeLists.txt +++ b/Geo/CMakeLists.txt @@ -4,6 +4,7 @@ # bugs and problems to <gmsh@geuz.org>. set(SRC + intersectCurveSurface.cpp GEntity.cpp STensor3.cpp GVertex.cpp GEdge.cpp GFace.cpp GRegion.cpp GEdgeLoop.cpp GEdgeCompound.cpp GFaceCompound.cpp diff --git a/Geo/GFaceCompound.cpp b/Geo/GFaceCompound.cpp index cc4b6e3a65..78b3d77db3 100644 --- a/Geo/GFaceCompound.cpp +++ b/Geo/GFaceCompound.cpp @@ -11,6 +11,7 @@ #include "GmshDefines.h" #include "GFaceCompound.h" #include "GEdgeCompound.h" +#include "intersectCurveSurface.h" #if defined(HAVE_SOLVER) @@ -2495,5 +2496,105 @@ void GFaceCompound::printStuff(int iNewton) const // fclose(uvm); } +// useful for mesh generators ---------------------------------------- +// Intersection of a circle and a plane + +GPoint GFaceCompound::intersectionWithCircle (const SVector3 &n1, const SVector3 &n2, const SVector3 &p, const double &d, double uv[2]) const +{ + SVector3 n = crossprod(n1,n2); + n.normalize(); + for (int i=-1;i<nbT;i++){ + GFaceCompoundTriangle *ct; + double U,V; + if (i == -1) getTriangle(uv[0],uv[1], &ct, U,V); + else ct = &_gfct[i]; + if (!ct) continue; + // we have two planes, defined with n1,n2 and t1,t2 + // we have then a direction m = (n1 x n2) x (t1 x t2) + // and a point p that defines a straight line + // 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; + + // 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 + // X(x,y,z) = ax + by + cz - (v1_x a + v1_y b + v1_z * c) = 0 + // Then + // 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 = dot(ct->v1-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 + // We have now to intersect that line with the sphere + // (x-p_x)^2 + (y-p_y)^2 + (z-p_z)^2 = d^2 + // Inserting the parametric form of the line into the sphere gives + // (t m_x + q_x - p_x)^2 + (t m_y + q_y - p_y)^2 + (t m_z + q_z - p_z)^2 = d^2 + // t^2 (m_x^2 + m_y^2 + m_z^2) + 2 t (m_x (q_x - p_x) + m_y (q_y - p_z) + m_z (q_z - p_z)) + ((q_x - p_x)^2 + (q_y - p_y)^2 + (q_z - p_z)^2 - d^2) = 0 + // t^2 m^2 + 2 t (m . (q-p)) + ((q-p)^2 - d^2) = 0 + // Let us call ta and tb the two roots + // they correspond to two points s_1 = q + ta m and s_2 = q + tb m + // 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); + SVector3 s1 = q + m * ta; + SVector3 s2 = q + m * tb; + SVector3 s; + if (dot(s1-p,n1) > 0){ + s = s1; + } + else if (dot(s2-p,n1) > 0){ + s = s2; + } + else continue; + + // we have now to look if the point is inside the triangle + // s = v1 + u t1 + v t2 + // we know the system has a solution because s is in the plane + // defined by v1 and v2 we solve then + // (s - v1) . t1 = u t1^2 + v t2 . t1 + // (s - v1) . t2 = u t1 . t2 + v t2^2 + + double mat[2][2], b[2],uv[2]; + 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) ; + 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] ; + // GPoint ttt = point(pp.x(),pp.y()); + // printf("%g %g %g vs %g %g %g\n",ttt.x(),ttt.y(),ttt.z(),s.x(),s.y(),s.z()); + // printf("%d/%d\n",i,nbT); + return GPoint(s.x(),s.y(),s.z(),this,pp); + } + } + } + GPoint pp(0); + pp.setNoSuccess(); + return pp; +} + #endif diff --git a/Geo/GFaceCompound.h b/Geo/GFaceCompound.h index 1424595bc0..3cd63b4d13 100644 --- a/Geo/GFaceCompound.h +++ b/Geo/GFaceCompound.h @@ -142,6 +142,8 @@ class GFaceCompound : public GFace { int getNbSplit() const { return nbSplit; } int allowPartition() const{ return _allowPartition; } void setType(typeOfIsomorphism type){ _type=type;} + // useful for mesh generators ---------------------------------------- + GPoint intersectionWithCircle (const SVector3 &n1, const SVector3 &n2, const SVector3 &p, const double &d, double uv[2]) const; private: mutable typeOfCompound _toc; mutable typeOfMapping _mapping; diff --git a/Mesh/CMakeLists.txt b/Mesh/CMakeLists.txt index 81d880f5e2..9118de87c7 100644 --- a/Mesh/CMakeLists.txt +++ b/Mesh/CMakeLists.txt @@ -7,7 +7,7 @@ set(SRC CenterlineField.cpp Generator.cpp Field.cpp - meshGEdge.cpp + meshGEdge.cpp meshGEdgeExtruded.cpp meshGFace.cpp meshGFaceTransfinite.cpp meshGFaceExtruded.cpp diff --git a/Mesh/meshGFace.cpp b/Mesh/meshGFace.cpp index d1a9771d51..e39f254da1 100644 --- a/Mesh/meshGFace.cpp +++ b/Mesh/meshGFace.cpp @@ -521,7 +521,7 @@ void modifyInitialMeshForTakingIntoAccountBoundaryLayers(GFace *gf) //avoid convergent errors if (dv2.length() < 0.5 * dv.length())break; - blQuads.push_back(new MQuadrangle(v11,v12,v22,v21)); + blQuads.push_back(new MQuadrangle(v11,v21,v22,v12)); fprintf(ff2,"SQ (%g,%g,%g,%g,%g,%g,%g,%g,%g,%g,%g,%g){1,1,1,1};\n", v11->x(),v11->y(),v11->z(), v12->x(),v12->y(),v12->z(), @@ -1141,7 +1141,7 @@ bool meshGenerator(GFace *gf, int RECUR_ITER, if((CTX::instance()->mesh.recombineAll || gf->meshAttributes.recombine) && !CTX::instance()->mesh.optimizeLloyd && !onlyInitialMesh) - recombineIntoQuadsIterative(gf); + recombineIntoQuads(gf); computeElementShapes(gf, gf->meshStatistics.worst_element_shape, gf->meshStatistics.average_element_shape, diff --git a/Mesh/meshGFaceDelaunayInsertion.cpp b/Mesh/meshGFaceDelaunayInsertion.cpp index 793f8fa035..a2d200abf4 100644 --- a/Mesh/meshGFaceDelaunayInsertion.cpp +++ b/Mesh/meshGFaceDelaunayInsertion.cpp @@ -20,6 +20,8 @@ #include "MQuadrangle.h" #include "Field.h" #include "GModel.h" +#include "GFaceCompound.h" +#include "intersectCurveSurface.h" double LIMIT_ = 0.5 * sqrt(2.0) * 1; @@ -269,8 +271,6 @@ MTri3::MTri3(MTriangle *t, double lc, SMetric3 *metric, const std::vector<double double pc[3] = {base->getVertex(2)->x(), base->getVertex(2)->y(), base->getVertex(2)->z()}; - // compute the circumradius of the triangle - if (!metric){ if (radiusNorm == 2){ circumCenterXYZ(pa, pb, pc, center); @@ -1072,30 +1072,6 @@ double optimalPointFrontal (GFace *gf, and the edge length */ -struct intersectCurveSurfaceData -{ - GFace *gf; - SVector3 &n1,&n2; - SVector3 &middle; - double d; - intersectCurveSurfaceData (GFace *_gf, SVector3 & _n1, SVector3 & _n2, SVector3 & _middle, double &_d) - : gf(_gf),n1(_n1),n2(_n2),middle(_middle),d(_d) - { } -}; - -static void intersectCircleSurface(fullVector<double> &uvt, - fullVector<double> &res, void *_data){ - intersectCurveSurfaceData *data = (intersectCurveSurfaceData*)_data; - GPoint gp = data->gf->point(uvt(0),uvt(1)); - SVector3 dir = (data->n1*cos(uvt(2))+data->n2*sin(uvt(2)))*data->d; - SVector3 pp = data->middle + dir; - res(0) = gp.x() - pp.x(); - res(1) = gp.y() - pp.y(); - res(2) = gp.z() - pp.z(); - // printf("f(%g %g %g) = %12.5E %12.5E %12.5E \n",uvt(0),uvt(1),uvt(2),res(0),res(1),res(2)); -} - - void optimalPointFrontalB (GFace *gf, MTri3* worst, int active_edge, @@ -1105,6 +1081,7 @@ void optimalPointFrontalB (GFace *gf, std::vector<double> &vSizesBGM, double newPoint[2], double metric[3]){ + static int missed = 1; // as a starting point, let us use the "fast algo" double d = optimalPointFrontal (gf,worst,active_edge,Us,Vs,vSizes,vSizesBGM,newPoint,metric); int ip1 = active_edge - 1 < 0 ? 2 : active_edge - 1; @@ -1127,19 +1104,31 @@ void optimalPointFrontalB (GFace *gf, // we look for a point that is // P = d * (n1 cos(t) + n2 sin(t)) that is on the surface // so we have to find t, starting with t = 0 - fullVector<double> uvt(3); - uvt(0) = newPoint[0]; - uvt(1) = newPoint[1]; - uvt(2) = 0.0; - intersectCurveSurfaceData data (gf,n1,n2,middle,d); - //printf("----------------------------\n"); - if(newton_fd(intersectCircleSurface, uvt, &data)){ - //printf("--- CONVERGED -- %12.5E -----------\n",d); - newPoint[0] = uvt(0); - newPoint[1] = uvt(1); - return; + + if (gf->geomType() == GEntity::CompoundSurface){ + GFaceCompound *gfc = dynamic_cast<GFaceCompound*> (gf); + if (gfc){ + GPoint gp = gfc->intersectionWithCircle(n1,n2,middle,d,newPoint); + if (gp.succeeded()){ + newPoint[0] = gp.u(); + newPoint[1] = gp.v(); + return ; + } + } + } + + double uvt[3] = {newPoint[0],newPoint[1],0.0}; + curveFunctorCircle cc (n1,n2,middle,d); + surfaceFunctorGFace ss (gf); + + if (intersectCurveSurface (cc,ss,uvt,d*1.e-8)){ + newPoint[0] = uvt[0]; + newPoint[1] = uvt[1]; } - //printf("--- NOT CONVERGED ----------\n"); + else { + Msg::Debug("--- Non optimal point found -----------"); + } + // fclose(f); } void bowyerWatsonFrontal(GFace *gf) @@ -1168,13 +1157,13 @@ void bowyerWatsonFrontal(GFace *gf) // insert points while (1){ - /* - if(ITER % 1== 0){ + + /* if(ITER % 100== 0){ char name[245]; sprintf(name,"delfr2d%d-ITER%d.pos",gf->tag(),ITER); - _printTris (name, AllTris, Us,Vs,false); - sprintf(name,"delfr2dA%d-ITER%d.pos",gf->tag(),ITER); - _printTris (name, ActiveTris, Us,Vs,false); + _printTris (name, AllTris, Us,Vs,true); + // sprintf(name,"delfr2dA%d-ITER%d.pos",gf->tag(),ITER); + // _printTris (name, ActiveTris, Us,Vs,false); } */ if (!ActiveTris.size())break; diff --git a/Mesh/meshGFaceOptimize.cpp b/Mesh/meshGFaceOptimize.cpp index 0148e46973..1a70c55c42 100644 --- a/Mesh/meshGFaceOptimize.cpp +++ b/Mesh/meshGFaceOptimize.cpp @@ -860,6 +860,7 @@ void createRegularMesh (GFace *gf, // create quads for (int i=0;i<=N;i++){ for (int j=0;j<=M;j++){ + //MQuadrangle *qnew = new MQuadrangle (tab[j][i],tab[j+1][i],tab[j+1][i+1],tab[j][i+1]); MQuadrangle *qnew = new MQuadrangle (tab[j][i],tab[j][i+1],tab[j+1][i+1],tab[j+1][i]); // printf("%p %p %p %p\n",tab[j][i],tab[j][i+1],tab[j+1][i+1],tab[j+1][i]); q.push_back(qnew); @@ -1011,7 +1012,11 @@ struct quadBlob { int topo_convex_region = 1; for (int i=0; i<bnodes.size();i++){ MVertex *v = bnodes[i]; - // if (v->onWhat()->dim() != 2)return 0; + // do not do anything in boundary layers !!! + if (v->onWhat()->dim() == 2){ + MFaceVertex *fv = dynamic_cast<MFaceVertex*>(v); + if(fv && fv->bl_data) return 0; + } //if (v->onWhat()->dim() == 2){ int topo_angle = topologicalAngle(v); if (topo_angle < 0){ @@ -3006,29 +3011,6 @@ void quadsToTriangles(GFace *gf, double minqual) gf->quadrangles = qds; } -void recombineIntoQuadsIterative(GFace *gf) -{ - recombineIntoQuads(gf); - // quadsToTriangles(gf, 1. - gf->meshAttributes.recombineAngle/90. ); - return; - int COUNT = 0; - while (1){ - quadsToTriangles(gf,-10000); - {char NAME[245];sprintf(NAME,"iterT%d.msh",COUNT); gf->model()->writeMSH(NAME);} - std::set<MTri3*,compareTri3Ptr> AllTris; - std::vector<double> vSizes, vSizesBGM, Us, Vs; - std::vector<SMetric3> vMetricsBGM; - // buildMeshGenerationDataStructures - // (gf, AllTris, vSizes, vSizesBGM, vMetricsBGM, Us, Vs); - // int nbSwaps = edgeSwapPass(gf, AllTris, SWCR_DEL, Us, Vs, vSizes, vSizesBGM); - // transferDataStructure(gf, AllTris, Us, Vs); - {char NAME[245];sprintf(NAME,"iterTD%d.msh",COUNT); gf->model()->writeMSH(NAME);} - recombineIntoQuads(gf,false,true); - {char NAME[245];sprintf(NAME,"iter%d.msh",COUNT++); gf->model()->writeMSH(NAME);} - if (COUNT == 5)break; - } -} - double Temporary::w1,Temporary::w2,Temporary::w3; std::vector<SVector3> Temporary::gradients; diff --git a/Mesh/meshGFaceOptimize.h b/Mesh/meshGFaceOptimize.h index 289f0b3351..2a44576ea5 100644 --- a/Mesh/meshGFaceOptimize.h +++ b/Mesh/meshGFaceOptimize.h @@ -97,7 +97,6 @@ void transferDataStructure(GFace *gf, std::set<MTri3*, compareTri3Ptr> &AllTris, void recombineIntoQuads(GFace *gf, bool topologicalOpti = true, bool nodeRepositioning = true); -void recombineIntoQuadsIterative(GFace *gf); void quadsToTriangles(GFace *gf, double minqual); struct swapquad{ diff --git a/Numeric/Numeric.cpp b/Numeric/Numeric.cpp index 1e5d1ef91a..1867dec2c3 100644 --- a/Numeric/Numeric.cpp +++ b/Numeric/Numeric.cpp @@ -680,7 +680,8 @@ bool newton_fd(void (*func)(fullVector<double> &, fullVector<double> &, void *), if (N == 1) dx(0) = f(0) / J(0, 0); else - J.luSolve(f, dx); + if (!J.luSolve(f, dx)) + return false; for (int i = 0; i < N; i++) x(i) -= relax * dx(i); diff --git a/Numeric/fullMatrix.cpp b/Numeric/fullMatrix.cpp index 4b716034d4..52314e78d1 100644 --- a/Numeric/fullMatrix.cpp +++ b/Numeric/fullMatrix.cpp @@ -285,10 +285,10 @@ bool fullMatrix<double>::luSolve(const fullVector<double> &rhs, fullVector<doubl F77NAME(dgesv)(&N, &nrhs, _data, &lda, ipiv, result._data, &ldb, &info); delete [] ipiv; if(info == 0) return true; - if(info > 0) - Msg::Debug("U(%d,%d)=0 in LU decomposition", info, info); - else - Msg::Debug("Wrong %d-th argument in LU decomposition", -info); + // if(info > 0) + // Msg::Error("U(%d,%d)=0 in LU decomposition", info, info); + // else + // Msg::Error("Wrong %d-th argument in LU decomposition", -info); return false; } diff --git a/benchmarks/stl/artery.geo b/benchmarks/stl/artery.geo index 2eabc40ad2..2f9d95a1c4 100644 --- a/benchmarks/stl/artery.geo +++ b/benchmarks/stl/artery.geo @@ -1,5 +1,5 @@ -Mesh.RemeshParametrization=1; //(0) harmonic (1) conformal -Mesh.RemeshAlgorithm=1; //(0) nosplit (1) automatic (2) split metis +Mesh.RemeshParametrization=0; //(0) harmonic (1) conformal +Mesh.RemeshAlgorithm=2; //(0) nosplit (1) automatic (2) split metis Mesh.CharacteristicLengthFactor=0.05; diff --git a/benchmarks/stl/skull.geo b/benchmarks/stl/skull.geo index ff18adfc99..3dee977428 100644 --- a/benchmarks/stl/skull.geo +++ b/benchmarks/stl/skull.geo @@ -1,8 +1,8 @@ Mesh.RemeshParametrization=0; //(0) harmonic (1) conformal Mesh.RemeshAlgorithm=2; //(0) nosplit (1) automatic (2) split metis -Mesh.CharacteristicLengthFactor=0.3; -Mesh.Algorithm3D = 4; //Frontal (4) Delaunay(1) +Mesh.CharacteristicLengthFactor=0.2; +//Mesh.Algorithm3D = 4; //Frontal (4) Delaunay(1) Merge "skullU.stl"; CreateTopology; -- GitLab