Forked from
gmsh / gmsh
8541 commits behind the upstream repository.
-
Christophe Geuzaine authoredChristophe Geuzaine authored
meshGFaceElliptic.cpp 27.55 KiB
// Gmsh - Copyright (C) 1997-2016 C. Geuzaine, J.-F. Remacle
//
// See the LICENSE.txt file for license information. Please report all
// bugs and problems to the public mailing list <gmsh@onelab.info>.
#include <stack>
#include "GmshConfig.h"
#include "meshGFaceElliptic.h"
#include "qualityMeasures.h"
#include "GFace.h"
#include "GEdge.h"
#include "GEdgeCompound.h"
#include "GVertex.h"
#include "GModel.h"
#include "MVertex.h"
#include "MTriangle.h"
#include "MQuadrangle.h"
#include "MLine.h"
#include "BackgroundMeshTools.h"
#include "Numeric.h"
#include "GmshMessage.h"
#include "Generator.h"
#include "Context.h"
#include "OS.h"
#include "SVector3.h"
#include "SPoint3.h"
#include "fullMatrix.h"
#include "CenterlineField.h"
#if defined(HAVE_ANN)
#include "ANN/ANN.h"
#endif
#define TRAN_QUAD(c1,c2,c3,c4,s1,s2,s3,s4,u,v) \
(1.-u)*c4+u*c2+(1.-v)*c1+v*c3-((1.-u)*(1.-v)*s1+u*(1.-v)*s2+u*v*s3+(1.-u)*v*s4)
static void printQuads(GFace *gf, fullMatrix<SPoint2> uv,
std::vector<MQuadrangle*> quads, int iter)
{
if(!CTX::instance()->mesh.saveAll) return;
char name[234];
sprintf(name, "quadUV_%d_%d.pos", gf->tag(), iter);
FILE *f = Fopen(name, "w");
if(!f){
Msg::Error("Could not open file '%s'", name);
return;
}
fprintf(f,"View \"%s\" {\n",name);
for (int i = 1; i < uv.size1()-1; i++)
for (int j = 0; j < uv.size2(); j++)
fprintf(f,"SP(%g,%g,%g) {%d};\n", uv(i,j).x(), uv(i,j).y(), 0.0, i);
fprintf(f,"};\n");
fclose(f);
char name3[234];
sprintf(name3, "quadXYZ_%d_%d.pos", gf->tag(), iter);
FILE *f3 = Fopen(name3,"w");
if(!f3){
Msg::Error("Could not open file '%s'", name3);
return;
}
fprintf(f3,"View \"%s\" {\n",name3);
for (unsigned int i = 0; i < quads.size(); i++){
quads[i]->writePOS(f3,true,false,false,false,false,false);
}
fprintf(f3,"};\n");
fclose(f3);
}
static void printParamGrid(GFace *gf, std::vector<MVertex*> vert1, std::vector<MVertex*> vert2,
std::vector<MVertex*> e01, std::vector<MVertex*> e10,
std::vector<MVertex*> e23, std::vector<MVertex*> e32,
std::vector<MVertex*> e02, std::vector<MVertex*> e13,
std::vector<MQuadrangle*> quads)
{
if(!CTX::instance()->mesh.saveAll) return;
std::vector<SPoint2> p1,p2;
for (unsigned int i = 0; i< vert1.size(); i++){
SPoint2 pi;
reparamMeshVertexOnFace(vert1[i], gf, pi);
p1.push_back(pi);
}
for (unsigned int j = 0; j< vert2.size(); j++){
SPoint2 pj;
reparamMeshVertexOnFace(vert2[j], gf, pj);
p2.push_back(pj);
}
char name[234];
sprintf(name,"paramGrid_%d.pos", gf->tag());
FILE *f = Fopen(name,"w");
if(!f){
Msg::Error("Could not open file '%s'", name);
return;
}
fprintf(f,"View \"%s\" {\n",name);
// for (unsigned int i = 0; i < p1.size(); i++)
// fprintf(f,"SP(%g,%g,%g) {%d};\n", p1[i].x(), p1[i].y(), 0.0, i);
// for (unsigned int j = 0; j < p2.size(); j++)
// fprintf(f,"SP(%g,%g,%g) {%d};\n", p2[j].x(), p2[j].y(), 0.0, 100+j);
for (unsigned int i = 0; i < p1.size()-1; i++)
fprintf(f,"SL(%g,%g,%g,%g,%g,%g) {%d,%d};\n", p1[i].x(), p1[i].y(), 0.0, p1[i+1].x(), p1[i+1].y(), 0.0, 1, 1);
for (unsigned int i = 0; i < p2.size()-1; i++)
fprintf(f,"SL(%g,%g,%g,%g,%g,%g) {%d,%d};\n", p2[i].x(), p2[i].y(), 0.0, p2[i+1].x(), p2[i+1].y(), 0.0, 1, 1);
fprintf(f,"SL(%g,%g,%g,%g,%g,%g) {%d,%d};\n", p1[p1.size()-1].x(), p1[ p1.size()-1].y(), 0.0, p1[0].x(), p1[0].y(), 0.0, 1, 1);
fprintf(f,"SL(%g,%g,%g,%g,%g,%g) {%d,%d};\n", p2[p2.size()-1].x(), p2[ p2.size()-1].y(), 0.0, p2[0].x(), p2[0].y(), 0.0, 1, 1);
fprintf(f,"};\n");
fclose(f);
char name2[234];
sprintf(name2,"paramEdges_%d.pos", gf->tag());
FILE *f2 = Fopen(name2,"w");
if(!f2){
Msg::Error("Could not open file '%s'", name2);
return;
}
fprintf(f2,"View \"%s\" {\n",name2);
for (unsigned int i = 0; i < e01.size(); i++){
SPoint2 pi; reparamMeshVertexOnFace(e01[i], gf, pi);
fprintf(f2,"SP(%g,%g,%g) {%d};\n", pi.x(), pi.y(), 0.0, 1);
}
for (unsigned int i = 0; i < e10.size(); i++){
SPoint2 pi; reparamMeshVertexOnFace(e10[i], gf, pi);
fprintf(f2,"SP(%g,%g,%g) {%d};\n", pi.x(), pi.y(), 0.0, 10);
}
for (unsigned int i = 0; i < e23.size(); i++){
SPoint2 pi; reparamMeshVertexOnFace(e23[i], gf, pi);
fprintf(f2,"SP(%g,%g,%g) {%d};\n", pi.x(), pi.y(), 0.0, 23);
}
for (unsigned int i = 0; i < e32.size(); i++){
SPoint2 pi; reparamMeshVertexOnFace(e32[i], gf, pi);
fprintf(f2,"SP(%g,%g,%g) {%d};\n", pi.x(), pi.y(), 0.0, 32);
}
for (unsigned int i = 0; i < e02.size(); i++){
SPoint2 pi; reparamMeshVertexOnFace(e02[i], gf, pi);
fprintf(f2,"SP(%g,%g,%g) {%d};\n", pi.x(), pi.y(), 0.0, 2);
}
for (unsigned int i = 0; i < e13.size(); i++){
SPoint2 pi; reparamMeshVertexOnFace(e13[i], gf, pi);
fprintf(f2,"SP(%g,%g,%g) {%d};\n", pi.x(), pi.y(), 0.0, 13);
}
fprintf(f2,"};\n");
fclose(f2);
char name3[234];
sprintf(name3,"quadXYZ_%d.pos", gf->tag());
FILE *f3 = Fopen(name3,"w");
if(!f3){
Msg::Error("Could not open file '%s'", name2);
return;
}
fprintf(f3,"View \"%s\" {\n",name3);
for (unsigned int i = 0; i < quads.size(); i++){
quads[i]->writePOS(f3,true,false,false,false,false,false);
}
fprintf(f3,"};\n");
fclose(f3);
}
static void createQuadsFromUV(GFace *gf, fullMatrix<SPoint2> &uv,
std::vector<std::vector<MVertex*> > &tab,
std::vector<MQuadrangle*> &newq, std::vector<MVertex*> &newv)
{
newq.clear();
newv.clear();
int M = uv.size1();
int N = uv.size2();
for (int i = 1; i < M-1; i++){
for (int j = 0; j < N-1; j++){
GPoint gp = gf->point(uv(i,j));
if (!gp.succeeded()){
printf("** QUADS FROM UV new vertex not created p=%g %g \n", uv(i,j).x(), uv(i,j).y()); //exit(1);
}
tab[i][j] = new MFaceVertex(gp.x(),gp.y(),gp.z(),gf,gp.u(),gp.v());
}
}
for (int i = 1; i < M-1; i++) tab[i][N-1] = tab[i][0];
//create vertices
for (int i = 1; i < M-1; i++)
for (int j = 0; j < N-1; j++)
newv.push_back(tab[i][j]);
// create quads
for (int i=0;i<M-1;i++){
for (int j=0;j<N-1;j++){
MQuadrangle *qnew = new MQuadrangle (tab[i][j],tab[i][j+1],tab[i+1][j+1],tab[i+1][j]);
newq.push_back(qnew);
}
}
return;
}
static std::vector<MVertex*> saturateEdgeRegular (GFace *gf, SPoint2 p1, SPoint2 p2,
int M, std::vector<SPoint2> &pe)
{
std::vector<MVertex*> pts;
for (int i=1;i<M;i++){
double s = ((double)i/((double)(M)));
SPoint2 p = p1 + (p2-p1)*s;
pe.push_back(p);
GPoint gp = gf->point(p);
if (!gp.succeeded()) printf("** SATURATE EDGE new vertex not created p=%g %g \n", p.x(), p.y());
MVertex *v = new MFaceVertex(gp.x(),gp.y(),gp.z(),gf,gp.u(),gp.v());
if (!v){ pts.clear(); pts.resize(0); return pts;}
pts.push_back(v);
}
return pts;
}
static std::vector<MVertex*> saturateEdgeHarmonic (GFace *gf, SPoint2 p1, SPoint2 p2,
double H, double L,
int M, std::vector<SPoint2> &pe)
{
std::vector<MVertex*> pts;
for (int i=1;i<M;i++){
double y = ((double)(i))*H/M;
double Yy = cosh(M_PI*y/L) - tanh(M_PI*H/L)*sinh(M_PI*y/L);
double YyH = cosh(M_PI*H/L) - tanh(M_PI*H/L)*sinh(M_PI*H/L);
double s = (1 - Yy)/(1.-YyH);
SPoint2 p = p1 + (p2-p1)*s;
pe.push_back(p);
GPoint gp = gf->point(p);
if (!gp.succeeded()) printf("** SATURATE EDGE new vertex not created p=%g %g \n", p.x(), p.y());
MVertex *v = new MFaceVertex(gp.x(),gp.y(),gp.z(),gf,gp.u(),gp.v());
if (!v){ pts.clear(); pts.resize(0); return pts;}
pts.push_back(v);
}
return pts;
}
static void transfiniteSmoother(GFace* gf,
fullMatrix<SPoint2> &uv,
std::vector<std::vector<MVertex*> > &tab,
std::vector<MQuadrangle*> &newq,
std::vector<MVertex*> &newv,
bool isPeriodic=false)
{
int M = uv.size1();
int N = uv.size2();
int jStart = isPeriodic ? 0 : 1;
int numSmooth = 150;
fullMatrix<SPoint2> uvold = uv;
for(int k = 0; k < numSmooth; k++){
double norm = 0.0;
for (int i=1; i<M-1; i++){
for (int j = jStart; j<N-1; j++){
int jm1 = (j==0) ? N-2: j-1;
int jp1 = (isPeriodic ) ? (j+1)%(N-1) : j+1;
double alpha = 0.25 * (SQU(uv(i,jp1).x() - uv(i,jm1).x()) +
SQU(uv(i,jp1).y() - uv(i,jm1).y())) ;
double gamma = 0.25 * (SQU(uv(i+1,j).x() - uv(i-1,j).x()) +
SQU(uv(i+1,j).y() - uv(i-1,j).y()));
double beta = 0.0625 *
((uv(i+1,j).x() - uv(i-1,j).x()) * (uv(i,jp1).x() - uv(i,jm1).x()) +
(uv(i+1,j).y() - uv(i-1,j).y()) * (uv(i,jp1).y() - uv(i,jm1).y()));
double uk = 0.5 *
(alpha * (uv(i+1,j).x() + uv(i-1,j).x()) +
gamma * (uv(i,jp1).x() + uv(i,jm1).x()) -
2. * beta * (uv(i+1,jp1).x() - uv(i-1,jp1).x() -
uv(i+1,jm1).x() + uv(i-1,jm1).x())) / (alpha + gamma);
double vk = 0.5 *
(alpha * (uv(i+1,j).y() + uv(i-1,j).y()) +
gamma * (uv(i,jp1).y()+ uv(i,jm1).y()) -
2. * beta * (uv(i+1,jp1).y() - uv(i-1,jp1).y() -
uv(i+1,jm1).y() + uv(i-1,jm1).y())) / (alpha + gamma);
uvold(i,j) = uv(i,j);
norm += sqrt((uv(i,j).x()-uk)*(uv(i,j).x()-uk)+(uv(i,j).y()-vk)*(uv(i,j).y()-vk));
uv(i,j) = SPoint2(uk,vk);
}
}
if (isPeriodic){
for (int i = 1; i<M-1; i++) {
uv(i,N-1) = uv(i,0);
uvold(i,N-1) = uvold(i,0);
}
}
if(k%20==0){
printf("Transfinite smoother iter (%d) = %g \n", k, norm);
createQuadsFromUV(gf, uv, tab, newq, newv);
printQuads(gf, uv, newq, k+1);
}
}
//final print
createQuadsFromUV(gf, uv, tab, newq, newv);
printQuads(gf, uv, newq, numSmooth);
}
//elliptic surface grid generator
//see eq. 9.26 page 9-24 in handbook of grid generation
static void ellipticSmoother( GFace* gf,
fullMatrix<SPoint2> &uv,
std::vector<std::vector<MVertex*> > &tab,
std::vector<MQuadrangle*> &newq,
std::vector<MVertex*> &newv,
bool isPeriodic=false)
{
printQuads(gf, uv, newq, 0);
int nbSmooth = 70;
int M = uv.size1();
int N = uv.size2();
int jStart = isPeriodic ? 0 : 1;
int jEnd = N-1;
fullMatrix<SPoint2> uvold = uv;
for (int k = 0; k< nbSmooth; k++){
double norm = 0.0;
for (int i=1; i<M-1; i++){
for (int j = jStart; j<jEnd; j++){
int jm1 = (j==0) ? N-2: j-1;
int jp1 = (isPeriodic ) ? (j+1)%(N-1) : j+1;
Pair<SVector3, SVector3> der = gf->firstDer(uv(i,j));
SVector3 xu = der.first();
SVector3 xv = der.second();
// double g11 = dot(xu,xu);
// double g12 = dot(xu,xv);
// double g22 = dot(xv,xv);
SVector3 xuu = SVector3();
SVector3 xvv = SVector3();
SVector3 xuv = SVector3();
gf->secondDer(uv(i,j), &xuu, &xvv, &xuv);
double g11_bar = dot(xu,xu);
double g12_bar = dot(xu,xv);
double g22_bar = dot(xv,xv);
double dxsi = 1.;
double deta = 1.;
double u_xsi = (uv(i,jp1).x()-uv(i,j).x())/dxsi;
double u_eta = (uv(i+1,j).x()-uv(i,j).x())/deta;
double v_xsi = (uv(i,jp1).y()-uv(i,j).y())/dxsi;
double v_eta = (uv(i+1,j).y()-uv(i,j).y())/deta;
double g11 = g11_bar*u_xsi*u_xsi+2.*g12_bar*u_xsi*v_xsi+g22_bar*v_xsi*v_xsi;
double g12 = g11_bar*u_xsi*u_eta+g12_bar*(u_xsi*v_eta+u_eta*v_xsi)+g22_bar*v_xsi*v_eta;
double g22 = g11_bar*u_eta*u_eta+2.*g12_bar*u_eta*v_eta+g22_bar*v_eta*v_eta;
double jac = u_xsi*v_eta-u_eta*v_xsi; //sqrt(g11*g22-g12*g12);
double jac_bar = sqrt(g11_bar*g22_bar-g12_bar*g12_bar);
double g11_bar_u = 2.*dot(xu,xuu);
double g11_bar_v = 2.*dot(xu,xuv);
double g22_bar_u = 2.*dot(xv,xuv);
double g22_bar_v = 2.*dot(xv,xvv);
double g12_bar_u = dot(xu,xuv)+dot(xv,xuu);
double g12_bar_v = dot(xu,xvv)+dot(xv,xuv);
double jac_bar_u = 1./(2.*jac_bar)*(g11_bar*g22_bar_u+g22_bar*g11_bar_u-2.*g12_bar*g12_bar_u);
double jac_bar_v = 1./(2.*jac_bar)*(g11_bar*g22_bar_v+g22_bar*g11_bar_v-2.*g12_bar*g12_bar_v);
double lapl_u = 1./jac_bar*(jac_bar*(g22_bar_u-g12_bar_v)-(g22_bar*jac_bar_u-g12_bar*jac_bar_v));
double lapl_v = 1./jac_bar*(jac_bar*(g11_bar_v-g12_bar_u)-(g11_bar*jac_bar_v-g12_bar*jac_bar_u));
double over = 1./(4.*(g11+g22));
double uk = over*(2.*g22*(uv(i+1,j).x()+uv(i-1,j).x())+
2.*g11*(uv(i,jp1).x()+uv(i,jm1).x())-
2*g12*(uv(i+1,jp1).x()-uv(i-1,jp1).x()-uv(i+1,jm1).x()+uv(i-1,jm1).x())-
2.*jac*jac*lapl_u);
double vk = over*(2.*g22*(uv(i+1,j).y()+uv(i-1,j).y())+
2.*g11*(uv(i,jp1).y()+uv(i,jm1).y())-
2.*g12*(uv(i+1,jp1).y()-uv(i-1,jp1).y()-uv(i+1,jm1).y()+uv(i-1,jm1).y())-
2.*jac*jac*lapl_v);
uvold(i,j) = uv(i,j);
norm += sqrt((uv(i,j).x()-uk)*(uv(i,j).x()-uk)+(uv(i,j).y()-vk)*(uv(i,j).y()-vk));
uv(i,j) = SPoint2(uk,vk);
}
}
if (isPeriodic){
for (int i = 1; i<M-1; i++) {
uv(i,N-1) = uv(i,0);
uvold(i,N-1) = uvold(i,0);
}
}
//under-relaxation
// double omega = 0.8;
// for (int i=0; i<M; i++){
// for (int j = 0; j<N; j++){
// uv(i,j) = SPoint2(omega*uv(i,j).x() + (1.-omega)*uvold(i,j).x(),
// omega*uv(i,j).y() + (1.-omega)*uvold(i,j).y());
// }
// }
if(k%10==0){
printf("Elliptic smoother iter (%d) = %g \n", k, norm);
createQuadsFromUV(gf, uv, tab, newq, newv);
printQuads(gf, uv, newq, k+1);
}
}
createQuadsFromUV(gf, uv, tab, newq, newv);
printQuads(gf, uv, newq, nbSmooth);
}
//create initial grid points MxN using transfinite interpolation
/*
c4 N c3
+--------------------------+
| | | | |
| | | | |
+--------------------------+ M
| | | | |
| | | | |
+--------------------------+
c1 c2
N
*/
static void createRegularGrid (GFace *gf,
MVertex *v1, SPoint2 &c1,
std::vector<MVertex*> &e12, std::vector<SPoint2> &pe12, int sign12,
MVertex *v2, SPoint2 &c2,
std::vector<MVertex*> &e23, std::vector<SPoint2> &pe23, int sign23,
MVertex *v3, SPoint2 &c3,
std::vector<MVertex*> &e34,std::vector<SPoint2> &pe34, int sign34,
MVertex *v4, SPoint2 &c4,
std::vector<MVertex*> &e41, std::vector<SPoint2> &pe41,int sign41,
std::vector<MQuadrangle*> &q,
std::vector<MVertex*> &newv,
fullMatrix<SPoint2> &uv,
std::vector<std::vector<MVertex*> > &tab)
{
int M = e23.size();
int N = e12.size();
uv.resize(M+2,N+2);
//std::vector<std::vector<MVertex*> > tab(M+2);
tab.resize(M+2);
for(int i = 0; i <= M+1; i++) tab[i].resize(N+2);
tab[0][0] = v1; uv(0,0) = c1;
tab[0][N+1] = v2; uv(0,N+1) = c2;
tab[M+1][N+1] = v3; uv(M+1,N+1) = c3;
tab[M+1][0] = v4; uv(M+1,0) = c4;
for (int i=0;i<N;i++){
tab[0][i+1] = sign12 > 0 ? e12 [i] : e12 [N-i-1];
tab[M+1][i+1] = sign34 < 0 ? e34 [i] : e34 [N-i-1];
uv(0,i+1) = sign12 > 0 ? pe12 [i] : pe12 [N-i-1];
uv(M+1,i+1) = sign34 < 0 ? pe34 [i] : pe34 [N-i-1];
}
for (int i=0;i<M;i++){
tab[i+1][N+1] = sign23 > 0 ? e23 [i] : e23 [M-i-1];
tab[i+1][0] = sign41 < 0 ? e41 [i] : e41 [M-i-1];
uv(i+1,N+1) = sign23 > 0 ? pe23 [i] : pe23 [M-i-1];
uv(i+1,0) = sign41 < 0 ? pe41 [i] : pe41 [M-i-1];
}
for (int i=0;i<N;i++){
for (int j=0;j<M;j++){
double u = (double) (i+1)/ ((double)(N+1));
double v = (double) (j+1)/ ((double)(M+1));
SPoint2 p12 = (sign12 >0) ? pe12[i] : pe12 [N-1-i];
SPoint2 p23 = (sign23 >0) ? pe23[j] : pe23 [M-1-j];
SPoint2 p34 = (sign34 <0) ? pe34[i] : pe34 [N-1-i];
SPoint2 p41 = (sign41 <0) ? pe41[j] : pe41 [M-1-j];
double Up = TRAN_QUAD(p12.x(), p23.x(), p34.x(), p41.x(),
c1.x(),c2.x(),c3.x(),c4.x(),u,v);
double Vp = TRAN_QUAD(p12.y(), p23.y(), p34.y(), p41.y(),
c1.y(),c2.y(),c3.y(),c4.y(),u,v);
if ((p12.x() && p12.y() == -1.0) || (p23.x() && p23.y() == -1.0) ||
(p34.x() && p34.y() == -1.0) || (p41.x() && p41.y() == -1.0)) {
Msg::Error("Wrong param -1");
return;
}
SPoint2 pij(Up,Vp);
GPoint gp = gf->point(pij);
if (!gp.succeeded()) printf("** INITIAL GRID new vertex not created p=%g %g \n", Up, Vp);
MVertex *vnew = new MFaceVertex(gp.x(),gp.y(),gp.z(),gf,gp.u(),gp.v());
newv.push_back(vnew);
uv(j+1,i+1) = pij;
tab[j+1][i+1] = vnew;
}
}
// 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][i+1],tab[j+1][i+1],tab[j+1][i]);
q.push_back(qnew);
}
}
}
//create initial grid points MxN using transfinite interpolation
/*
c2 N c2
+--------------------------+
| | | | |
| | | | |
+--------------------------+ M
| | | | |
| | | | |
+--------------------------+
c0 c0
N
*/
static void createRegularGridPeriodic (GFace *gf,int sign2,
MVertex *v0, SPoint2 &c0,
MVertex *v2, SPoint2 &c2,
std::vector<MVertex*> &e02, std::vector<SPoint2> &pe02,
std::vector<MVertex*> &e00, std::vector<SPoint2> &pe00,
std::vector<MVertex*> &e22, std::vector<SPoint2> &pe22,
std::vector<MQuadrangle*> &q,
std::vector<MVertex*> &newv,
fullMatrix<SPoint2> &uv,
std::vector<std::vector<MVertex*> > &tab)
{
int M = e02.size();
int N = e00.size();
uv.resize(M+2,N+2);
char name3[234];
sprintf(name3,"quadParam_%d.pos", gf->tag());
FILE *f3 = Fopen(name3,"w");
if(f3) fprintf(f3,"View \"%s\" {\n",name3);
tab.resize(M+2);
for(int i = 0; i < M+2; i++) tab[i].resize(N+2);
//periodic boundary mesh vertices
tab[0][0] = v0; uv(0,0) = c0;
tab[0][N+1] = v0; uv(0,N+1) = c0;
tab[M+1][N+1] = v2; uv(M+1,N+1) = c2;
tab[M+1][0] = v2; uv(M+1,0) = c2;
for (int i=0;i<N;i++){
tab[0][i+1] = e00 [i]; uv(0,i+1) = pe00 [i] ;
tab[M+1][i+1] = (sign2 > 0) ? e22 [i] : e22 [N-i-1] ;
uv(M+1,i+1) = (sign2 > 0) ? pe22 [i] : pe22 [N-i-1] ;
}
for (int i=0;i<M;i++){
tab[i+1][N+1] = e02 [i]; uv(i+1,N+1) = pe02 [i] ;
tab[i+1][0] = e02 [i]; uv(i+1,0) = pe02 [i];
}
//interior mesh_vertices
for (int i=0;i<N;i++){
SPoint2 p0 = pe00[i] ;
SPoint2 p2 = (sign2>0) ? pe22[i] : pe22 [N-i-1] ;
std::vector<SPoint2> pei;
std::vector<MVertex*> ei = saturateEdgeRegular(gf,p0,p2,M+1,pei);//M+1
for (int j=0;j<M;j++){
SPoint2 pij = pei[j];
GPoint gp = gf->point(pij);
if (!gp.succeeded()) printf("** INITIAL GRID new vertex not created p=%g %g \n", pij.x(), pij.y());
tab[j+1][i+1] = new MFaceVertex(gp.x(),gp.y(),gp.z(),gf,gp.u(),gp.v());
uv(j+1,i+1) = pij;
}
}
//create vertices
for (int i=0;i<N+1;i++)
for (int j=1;j<M+1;j++)
newv.push_back(tab[j][i]);
// 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][i+1],tab[j+1][i+1],tab[j+1][i]);
q.push_back(qnew);
}
}
//print
if(f3){
for (int i=0;i<N+2;i++)
for (int j=0;j<M+2;j++)
fprintf(f3,"SP(%g,%g,%g) {%d};\n", uv(j,i).x(), uv(j,i).y(), 0.0, j);
fprintf(f3,"};\n");
fclose(f3);
}
}
static void updateFaceQuads(GFace *gf, std::vector<MQuadrangle*> &quads, std::vector<MVertex*> &newv)
{
for (unsigned int i = 0; i < quads.size(); i++){
gf->quadrangles.push_back(quads[i]);
}
for(unsigned int i = 0; i < newv.size(); i++){
gf->mesh_vertices.push_back(newv[i]);
}
}
static bool computeRingVertices(GFace *gf, Centerline *center,
std::vector<MVertex*> &vert1, std::vector<MVertex*> &vert2,
int &N, int &M, int &close_ind, int &sign2,
double &arc, double &length)
{
#if defined(HAVE_ANN)
std::list<GEdge*> bedges = gf->edges();
std::list<GEdge*>::iterator itb = bedges.begin();
std::list<GEdge*>::iterator ite = bedges.end(); ite--;
GEdge *ge1 = (*itb)->getCompound();
GEdge *ge2 = (*ite)->getCompound();
N = ge1->mesh_vertices.size() + 1;
int N2 = ge2->mesh_vertices.size() + 1;
if (N != N2 || N%2 != 0){
Msg::Error("You should an even number nbPoints in centerline =%d \n", N);
exit(1);
return false;
}
vert1.push_back(ge1->getBeginVertex()->mesh_vertices[0]);
vert2.push_back(ge2->getBeginVertex()->mesh_vertices[0]);
for(int i = 0; i < N-1; i++) {
vert1.push_back(ge1->mesh_vertices[i]);
vert2.push_back(ge2->mesh_vertices[i]);
}
SPoint2 pv1; reparamMeshVertexOnFace(vert1[0], gf, pv1);
SPoint2 pv2; reparamMeshVertexOnFace(vert2[0], gf, pv2);
SPoint2 pv1b; reparamMeshVertexOnFace(vert1[1], gf, pv1b);
SPoint2 pv2b; reparamMeshVertexOnFace(vert2[1], gf, pv2b);
SPoint2 pv1c; reparamMeshVertexOnFace(vert1[2], gf, pv1c);
SPoint2 pv2c; reparamMeshVertexOnFace(vert2[2], gf, pv2c);
SVector3 vec1(pv1b.x()-pv1.x(),pv1b.y()-pv1.y() , 0.0);
SVector3 vec1b(pv1c.x()-pv1b.x(),pv1c.y()-pv1b.y() ,0.0);
SVector3 vec2(pv2b.x()-pv2.x(),pv2b.y()-pv2.y() ,0.0);
SVector3 vec2b(pv2c.x()-pv2b.x(),pv2c.y()-pv2b.y() , 0.0);
sign2 = (dot(crossprod(vec1,vec1b),crossprod(vec2,vec2b)) < 0) ? -1 : +1 ;
double n1 = sqrt(pv1.x()*pv1.x()+pv1.y()*pv1.y());
double n2 = sqrt(pv2.x()*pv2.x()+pv2.y()*pv2.y());
std::vector<MVertex*> vert_temp;
if (n2 > n1) {
vert_temp = vert1;
vert1.clear();
vert1 = vert2;
vert2.clear();
vert2 = vert_temp;
}
double rad = center->operator()(vert1[0]->x(), vert1[0]->y(), vert1[0]->z());
ANNpointArray nodes = annAllocPts(N, 3);
ANNidxArray index = new ANNidx[1];
ANNdistArray dist = new ANNdist[1];
for (int ind = 0; ind < N; ind++){
SPoint2 pp2; reparamMeshVertexOnFace(vert2[ind], gf, pp2);
nodes[ind][0] = pp2.x();
nodes[ind][1] = pp2.y();
nodes[ind][2] = 0.0;
}
ANNkd_tree *kdtree = new ANNkd_tree(nodes, N, 3);
SPoint2 pp1; reparamMeshVertexOnFace(vert1[0], gf, pp1);
double xyz[3] = {pp1.x(), pp1.y(),0.0};
kdtree->annkSearch(xyz, 1, index, dist);
close_ind = index[0];
SPoint2 p1; reparamMeshVertexOnFace(vert1[0], gf, p1);
SPoint2 p2; reparamMeshVertexOnFace(vert2[close_ind], gf, p2);
GPoint gp_i(vert1[0]->x(), vert1[0]->y(), vert1[0]->z());
SPoint2 p1b; reparamMeshVertexOnFace(vert1[N/2], gf, p1b);
SPoint2 p2b; reparamMeshVertexOnFace(vert2[(close_ind+N/2)%N], gf, p2b);
GPoint gp_ib(vert1[N/2]->x(), vert1[N/2]->y(), vert1[N/2]->z());
length = 0.0;
double lengthb = 0.0;
int nb = 100;
for (int i = 0; i< nb; i++){
SPoint2 pii(p1.x() + (double)(i+1)/nb*(p2.x()-p1.x()), p1.y() + (double)(i+1)/nb*(p2.y()-p1.y()));
GPoint gp_ii = gf->point(pii);
SPoint2 piib(p1b.x() + (double)(i+1)/nb*(p2b.x()-p1b.x()), p1b.y() + (double)(i+1)/nb*(p2b.y()-p1b.y()));
GPoint gp_iib = gf->point(piib);
length += gp_i.distance(gp_ii);
lengthb += gp_ib.distance(gp_iib);
gp_i = gp_ii;
gp_ib = gp_iib;
}
arc = 2*M_PI*rad;
double lc = arc/N;
M = (int)(0.5*(length+lengthb)/lc) ;
delete kdtree;
delete[]index;
delete[]dist;
annDeallocPts(nodes);
return true;
#else
return false;
#endif
}
//vert1 is the outer circle
//vert2 is the inner circle
// - - - -
// - -
// - - -
// v0- v2- - -
// - - -
// - -
// - - - -
bool createRegularTwoCircleGridPeriodic (Centerline *center, GFace *gf)
{
#if defined(HAVE_ANN)
std::vector<MVertex*> vert1, vert2;
int N, M, close_ind, sign2;
double arc, length;
bool success = computeRingVertices(gf, center, vert1, vert2, N, M, close_ind, sign2, arc,length);
if(!success) return false;
MVertex *v0 = vert1[0]; SPoint2 p0; reparamMeshVertexOnFace(v0, gf, p0);
MVertex *v2 = vert2[close_ind]; SPoint2 p2; reparamMeshVertexOnFace(v2, gf, p2);
//printf("grid N = %d M = %d\n", N , M);
std::vector<MVertex*> e00,e22;//edges without first and last vertex
for (int i=1;i<N;i++) e00.push_back(vert1[i]);
for (int i=1;i<N;i++) e22.push_back(vert2[(close_ind+i)%N]);
std::vector<SPoint2> pe00, pe22;
for (unsigned int i = 0; i < e00.size(); i++){
SPoint2 p00; reparamMeshVertexOnFace(e00[i], gf, p00);
SPoint2 p22; reparamMeshVertexOnFace(e22[i], gf, p22);
pe00.push_back(p00);
pe22.push_back(p22);
}
std::vector<SPoint2> pe02;
std::vector<MVertex*> e02 = saturateEdgeRegular(gf,p0,p2,M+1,pe02);
std::vector<MQuadrangle*> quads;
std::vector<MVertex*> newv;
fullMatrix<SPoint2> uv;
std::vector<std::vector<MVertex*> > tab;
createRegularGridPeriodic (gf,sign2,
v0, p0,
v2, p2,
e02, pe02,
e00, pe00,
e22, pe22,
quads, newv, uv, tab);
printQuads(gf, uv, quads, 0);
transfiniteSmoother(gf, uv, tab, quads, newv, true);
//ellipticSmoother(gf, uv, tab, quads, newv, true);
updateFaceQuads(gf, quads, newv);
//exit(1);
//printParamGrid(gf, vert1, vert2, e00,e22,e02,e02,e02,e02, quads);
return true;
#else
return false;
#endif
}
//vert1 is the outer circle
//vert2 is the inner circle
// - - - -
// - -
// - - -
// v0- v2- -v3 -v1
// - - -
// - -
// - - - -
bool createRegularTwoCircleGrid (Centerline *center, GFace *gf)
{
#if defined(HAVE_ANN)
std::vector<MVertex*> vert1, vert2;
int N, M, close_ind, sign2;
double arc, length;
bool success = computeRingVertices(gf, center, vert1, vert2, N, M, close_ind, sign2, arc,length);
if(!success) return false;
MVertex *v0 = vert1[0]; SPoint2 p0; reparamMeshVertexOnFace(v0, gf, p0);
MVertex *v1 = vert1[N/2]; SPoint2 p1; reparamMeshVertexOnFace(v1, gf, p1);
MVertex *v2 = vert2[close_ind]; SPoint2 p2; reparamMeshVertexOnFace(v2, gf, p2);
MVertex *v3 = vert2[(close_ind+N/2)%N]; SPoint2 p3; reparamMeshVertexOnFace(v3, gf, p3);
printf("grid N = %d M = %d\n", N , M);
std::vector<MVertex*> e01,e10,e23,e32;//edges without first and last vertex
for (int i=1;i<N/2;i++) e01.push_back(vert1[i]);
for (int i=N/2+1;i<N;i++) e10.push_back(vert1[i]);
for (int i=1;i<N/2;i++) e23.push_back(vert2[(close_ind+i)%N]);
for (int i=N/2+1;i<N;i++) e32.push_back(vert2[(close_ind+i)%N]);
std::vector<SPoint2> pe01, pe10, pe23, pe32;
for (unsigned int i = 0; i < e01.size(); i++){
SPoint2 p01; reparamMeshVertexOnFace(e01[i], gf, p01);
SPoint2 p10; reparamMeshVertexOnFace(e10[i], gf, p10);
SPoint2 p23; reparamMeshVertexOnFace(e23[i], gf, p23);
SPoint2 p32; reparamMeshVertexOnFace(e32[i], gf, p32);
pe01.push_back(p01);
pe10.push_back(p10);
pe23.push_back(p23);
pe32.push_back(p32);
}
std::vector<SPoint2> pe02, pe13;
std::vector<MVertex*> e02 = saturateEdgeHarmonic (gf,p0,p2,length, arc, M+1, pe02);
std::vector<MVertex*> e13 = saturateEdgeHarmonic (gf,p1,p3,length, arc, M+1, pe13);
std::vector<MVertex*> e_inner1 = e23;
std::vector<MVertex*> e_inner2 = e32;
std::vector<SPoint2> pe_inner1 = pe23;
std::vector<SPoint2> pe_inner2 = pe32;
if (sign2 <0){
e_inner1 = e32;
e_inner2 = e23;
pe_inner1 = pe32;
pe_inner2 = pe23;
}
std::vector<MQuadrangle*> quads, quadS1, quadS2;
std::vector<MVertex*> newv, newv1, newv2;
fullMatrix<SPoint2> uv1, uv2;
std::vector<std::vector<MVertex*> > tab1, tab2;
createRegularGrid (gf,
v0, p0,
e01, pe01, +1,
v1,p1,
e13, pe13, +1,
v3,p3,
e_inner1, pe_inner1, -sign2,
v2,p2,
e02, pe02, -1,
quads, newv, uv1, tab1);
createRegularGrid (gf,
v0,p0,
e02, pe02, +1,
v2,p2,
e_inner2, pe_inner2, -sign2,
v3,p3,
e13, pe13, -1,
v1,p1,
e10, pe10, +1,
quads, newv, uv2, tab2);
printQuads(gf, uv1, quads, 0);
ellipticSmoother(gf, uv1, tab1, quadS1, newv1);
ellipticSmoother(gf, uv2, tab2, quadS2, newv2);
quads.clear();
for (unsigned int i= 0; i< quadS1.size(); i++) quads.push_back(quadS1[i]);
for (unsigned int i= 0; i< quadS2.size(); i++) quads.push_back(quadS2[i]);
//updateFaceQuads(gf, quads, newv);
printParamGrid(gf, vert1, vert2, e01,e10,e23,e32,e02,e13, quads);
return true;
#else
return false;
#endif
}