// $Id: Metric.cpp,v 1.21 2006-01-06 00:34:26 geuzaine Exp $ // // Copyright (C) 1997-2006 C. Geuzaine, J.-F. Remacle // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 2 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 // USA. // // Please report all bugs and problems to <gmsh@geuz.org>. #include <time.h> #include "Gmsh.h" #include "Numeric.h" #include "Geo.h" #include "CAD.h" #include "Mesh.h" #include "Matrix.h" #include "Interpolation.h" Matrix3x3 Matrix3x3::operator *(const Matrix3x3 & autre) { Matrix3x3 m(0.); for(int i = 0; i < 3; i++) { for(int j = 0; j < 3; j++) { for(int k = 0; k < 3; k++) m.mat[i][j] += mat[i][k] * autre.mat[k][j]; if(fabs(m.mat[i][j]) < 1.e-15) m.mat[i][j] = 0.0; } } return m; } void Matrix3x3::setMetric() { Matrix3x3 rot(eVec[0], eVec[1], eVec[2]); Matrix3x3 rotT(eVec[0], eVec[1], eVec[2]); Matrix3x3 Id(0.0); rotT.transpose(); Id.Identity(1.0); for(int i = 0; i < 3; i++) Id.mat[i][i] = eVal[i]; Matrix3x3 kk = (Id * rot); Matrix3x3 m = rotT * kk; /* Msg(INFO,"rot: %g %g %g %g %g %g %g %g %g \n ", rot[0][0], rot[0][1], rot[0][2], rot[1][0], rot[1][1], rot[1][2], rot[2][0], rot[2][1], rot[2][2]); Msg(INFO,"rotT: %g %g %g %g %g %g %g %g %g \n ", rotT[0][0], rotT[0][1], rotT[0][2], rotT[1][0], rotT[1][1], rotT[1][2], rotT[2][0], rotT[2][1], rotT[2][2]); Msg(INFO,"id: %g %g %g %g %g %g %g %g %g \n ", Id[0][0], Id[0][1], Id[0][2], Id[1][0], Id[1][1], Id[1][2], Id[2][0], Id[2][1], Id[2][2]); Msg(INFO,"kk: %g %g %g %g %g %g %g %g %g \n ", kk[0][0], kk[0][1], kk[0][2], kk[1][0], kk[1][1], kk[1][2], kk[2][0], kk[2][1], kk[2][2]); Msg(INFO,"m: %g %g %g %g %g %g %g %g %g \n ", m[0][0], m[0][1], m[0][2], m[1][0], m[1][1], m[1][2], m[2][0], m[2][1], m[2][2]); */ for(int i = 0; i < 3; i++) for(int j = 0; j < 3; j++) mat[i][j] = m.mat[i][j]; } GMSHMetric::GMSHMetric() { Identity(); Attractors = List_Create(2, 2, sizeof(Attractor *)); limite_aniso = 3000.; min_cos = 0.0095; quality_measure = QUALITY_SIMPLEX_BASED; } Matrix3x3 GMSHMetric::Intersect2Metrics(Matrix3x3 * m1[2]) { double lmax = 0.; int im = 0, ic = 0, io = 0; Vector3 cmax(0., 0, 0, 0); Matrix3x3 res(0.0); for(int i = 0; i < 3; i++) { for(int j = 0; j < 2; j++) { Vector3 v(0.0); double l; m1[j]->getEigen(i, v, l); // cout << i << " " << j << " " << l << endl; if(l > lmax) { ic = i; lmax = l; cmax = v; im = j; io = (j == 0) ? 1 : 0; } } } // cout << "lmax " << lmax << endl; res.setEigen(ic, cmax[0], cmax[1], cmax[2], lmax); for(int i = 0; i < 3; i++) { if(i != ic) { Vector3 v(0.0); double l; m1[im]->getEigen(i, v, l); double l2 = m1[io]->quadraticFormEval(v); // cout << l << " " << l2 << endl; res.setEigen(i, v[0], v[1], v[2], (l2 > l) ? l2 : l); } } // cout << "gives " << endl; // res.print(); // cout<<endl; res.setMetric(); return res; } double GMSHMetric:: Local_Metric_Of_Attractors(double X, double Y, double Z, double metric[3][3]) { int i; Attractor *a; double u, x1, x2, d = 0.; Vertex v1(X, Y, Z), v2, metr; Matrix3x3 myOldMetric(0., m); for(i = 0; i < List_Nbr(Attractors); i++) { Matrix3x3 myMetric(0.); List_Read(Attractors, i, &a); if(a->v) { d = sqrt((X - a->v->Pos.X) * (X - a->v->Pos.X) + (Y - a->v->Pos.Y) * (Y - a->v->Pos.Y) + (Z - a->v->Pos.Z) * (Z - a->v->Pos.Z)); metr = Vertex(1., 0., 0.); } if(a->c) { ProjectPointOnCurve(a->c, &v1, &v2, &metr); d = sqrt((X - v2.Pos.X) * (X - v2.Pos.X) + (Y - v2.Pos.Y) * (Y - v2.Pos.Y) + (Z - v2.Pos.Z) * (Z - v2.Pos.Z)); } double d1 = d * a->Radius; if(fabs(d1) < a->Radius * 1.e-6) d1 = 0.0; u = exp(-(d1 * d1)); x1 = (1. - u) + u * a->lc1; x2 = (1. - u) + u * a->lc2; // cout << " dist from "<< X << " " << Y << " = " << d << endl; if(u > 1.e-2) { if(a->v) { double q11 = 1. / (x1 * x1); double q22 = 1. / (x2 * x2); //double q12 = 1. / (x1 * x2); myMetric.setEigen(0, 1., 0., 0., q11); myMetric.setEigen(1, 0., 1., 0., q22); myMetric.setEigen(2, 0., 0., 1., q11); myMetric.setMetric(); } else if(a->c) { double xx = 0.0, yy = 0.0, zz = 0.0; if(metr.Pos.X != 0.0 || metr.Pos.Y != 0.0) zz = 1.0; else if(metr.Pos.Y == 0.0) yy = 1.0; else xx = 1.0; Vertex z(xx, yy, zz); Vertex d2 = metr % z; metr.norme(); d2.norme(); Vertex d3 = metr % d2; d3.norme(); myMetric.setEigen(0, metr.Pos.X, metr.Pos.Y, metr.Pos.Z, 1. / (x1 * x1)); myMetric.setEigen(1, d2.Pos.X, d2.Pos.Y, d2.Pos.Z, 1. / (x2 * x2)); myMetric.setEigen(2, d3.Pos.X, d3.Pos.Y, d3.Pos.Z, 1. / (x1 * x1)); myMetric.setMetric(); /* Msg(INFO,"%d %12.5E heigens : %12.5E %12.5E %12.5E %12.5E %12.5E %12.5E %12.5E %12.5E %12.5E \n ", a->c->Num,d, metr.Pos.X, metr.Pos.Y, metr.Pos.Z, d2.Pos.X,d2.Pos.Y,d2.Pos.Z, d3.Pos.X,d3.Pos.Y,d3.Pos.Z); Msg(INFO,"heigenv : %12.5E %12.5E \n",x1,x2); Msg(INFO,"curve Metric: %g %g %g %g %g %g %g %g %g \n ", myMetric[0][0], myMetric[0][1], myMetric[0][2], myMetric[1][0], myMetric[1][1], myMetric[1][2], myMetric[2][0], myMetric[2][1], myMetric[2][2]); */ } Matrix3x3 *M[2]; M[0] = &myMetric; M[1] = &myOldMetric; myOldMetric = Intersect2Metrics(M); // myOldMetric = myMetric; } } myOldMetric.copy(m); return 1.0; } void GMSHMetric:: setMetric(double u, double v, Surface * s) { double a, b, c; // ellipse axx+byy+cxy=1 double l1, l2; // 2 eigenvalues Identity(); Vertex p = InterpolateSurface(s, u, v, 0, 0); if(s->Typ != MSH_SURF_PLAN && s->Typ != MSH_SURF_REGL && s->Typ != MSH_SURF_TRIC) { Vertex du = InterpolateSurface(s, u, v, 1, 1); Vertex dv = InterpolateSurface(s, u, v, 1, 2); a = du * du; b = dv * dv; c = du * dv; m[0][0] = a; m[1][1] = b; m[0][1] = c; m[1][0] = c; l1 = 0.5 * ((a + b) + sqrt((a - b) * (a - b) + 4. * c * c)); l2 = 0.5 * ((a + b) - sqrt((a - b) * (a - b) + 4. * c * c)); if(l1 == 0.0 && l2 == 0.0) Identity(); else if(sqrt(l1 / l2) > limite_aniso) { // on limite les rapports de metrique a limite_ansio double r = limite_aniso * limite_aniso * (l2 / l1); m[0][0] = a / r; m[1][1] = b * r; m[0][1] = c; m[1][0] = c; } } Local_Metric_Of_Attractors(p.Pos.X, p.Pos.Y, p.Pos.Z, NULL); return; } void GMSHMetric:: setMetric(double x, double y, double z) { Identity(); Local_Metric_Of_Attractors(x, y, z, NULL); return; } void GMSHMetric:: setMetricMin(double u, double v, Surface * s) { /*setMetric(u,v,s); return; */ Identity(); if(s->Typ != MSH_SURF_PLAN && s->Typ != MSH_SURF_REGL && s->Typ != MSH_SURF_TRIC) { Vertex du = InterpolateSurface(s, u, v, 1, 1); Vertex dv = InterpolateSurface(s, u, v, 1, 2); double d = (du * du > dv * dv) ? du * du : dv * dv; m[0][0] = d; m[1][1] = d; } return; } double GMSHMetric:: getWorstEdge(Simplex * s, Surface * surf, Vertex * v[2]) { double l1, l2, l3, q1, q2, q3; v[0] = s->V[0]; v[1] = s->V[1]; l1 = EdgeLengthOnSurface(surf, v, 1); v[0] = s->V[0]; v[1] = s->V[2]; l2 = EdgeLengthOnSurface(surf, v, 1); v[0] = s->V[1]; v[1] = s->V[2]; l3 = EdgeLengthOnSurface(surf, v, 1); q1 = 2. * l1 / (s->V[0]->lc + s->V[1]->lc); q2 = 2. * l2 / (s->V[0]->lc + s->V[2]->lc); q3 = 2. * l3 / (s->V[1]->lc + s->V[2]->lc); if(q1 >= q2 && q1 >= q3) { v[0] = s->V[0]; v[1] = s->V[1]; return l1; } else if(q2 >= q3) { v[0] = s->V[0]; v[1] = s->V[2]; return l2; } return l3; } void GMSHMetric:: setSimplexQuality(Simplex * s, Surface * surf) { if(quality_measure == QUALITY_EDGES_BASED) { Vertex *v[2], vv; double l1, l2, l3, q1, q2, q3; v[0] = s->V[0]; v[1] = s->V[1]; vv = (*v[1]) - (*v[0]); l1 = LengthVector(&vv); v[0] = s->V[0]; v[1] = s->V[2]; vv = (*v[1]) - (*v[0]); l2 = LengthVector(&vv); v[0] = s->V[1]; v[1] = s->V[2]; vv = (*v[1]) - (*v[0]); l3 = LengthVector(&vv); q1 = 2. * l1 / (s->V[0]->lc + s->V[1]->lc); q2 = 2. * l2 / (s->V[0]->lc + s->V[2]->lc); q3 = 2. * l3 / (s->V[1]->lc + s->V[2]->lc); s->Quality = DMAX(DMAX(q1, q2), q3) / (RacineDeTrois); } else { /* Matrix3x3 myOldMetric (0.,m); Identity(); Local_Metric_Of_Attractors (s->V[0]->Pos.X,s->V[0]->Pos.Y,s->V[0]->Pos.Z,0); Local_Metric_Of_Attractors (s->V[1]->Pos.X,s->V[1]->Pos.Y,s->V[1]->Pos.Z,0); Local_Metric_Of_Attractors (s->V[2]->Pos.X,s->V[2]->Pos.Y,s->V[2]->Pos.Z,0); */ s->Center_Ellipsum_2D(m); s->Quality = 3. * s->Radius / (s->V[0]->lc + s->V[1]->lc + s->V[2]->lc); } } void GMSHMetric:: setSimplexQuality(Simplex * s) { if(quality_measure == QUALITY_EDGES_BASED) { Vertex *v[2], vv; double l1, l2, l3, l4, l5, l6, q1, q2, q3, q4, q5, q6; v[0] = s->V[0]; v[1] = s->V[1]; vv = (*v[1]) - (*v[0]); l1 = LengthVector(&vv); v[0] = s->V[0]; v[1] = s->V[2]; vv = (*v[1]) - (*v[0]); l2 = LengthVector(&vv); v[0] = s->V[1]; v[1] = s->V[2]; vv = (*v[1]) - (*v[0]); l3 = LengthVector(&vv); v[0] = s->V[0]; v[1] = s->V[3]; vv = (*v[1]) - (*v[0]); l4 = LengthVector(&vv); v[0] = s->V[1]; v[1] = s->V[3]; vv = (*v[1]) - (*v[0]); l5 = LengthVector(&vv); v[0] = s->V[2]; v[1] = s->V[3]; vv = (*v[1]) - (*v[0]); l6 = LengthVector(&vv); q1 = 2. * l1 / (s->V[0]->lc + s->V[1]->lc); q2 = 2. * l2 / (s->V[0]->lc + s->V[2]->lc); q3 = 2. * l3 / (s->V[1]->lc + s->V[2]->lc); q4 = 2. * l4 / (s->V[0]->lc + s->V[3]->lc); q5 = 2. * l5 / (s->V[1]->lc + s->V[3]->lc); q6 = 2. * l6 / (s->V[2]->lc + s->V[3]->lc); //s->Quality = (0.5/6.)*(q1+q2+q3+q4+q5+q6); //double qmax = (DMAX (q1, DMAX (q2, DMAX (q3, DMAX (q4, DMAX (q5, q6)))))); s->Quality = (q1 + q2 + q3 + q4 + q5 + q6) / (6. * RacineDeDeux); } else { //double x = (s->V[0]->Pos.X + s->V[1]->Pos.X + s->V[2]->Pos.X + s->V[3]->Pos.X) / 4.; //double y = (s->V[0]->Pos.Y + s->V[1]->Pos.Y + s->V[2]->Pos.Y + s->V[3]->Pos.Y) / 4.; // double z = (s->V[0]->Pos.Z + s->V[1]->Pos.Z + s->V[2]->Pos.Z + s->V[3]->Pos.Z) / 4.; // setMetric(x,y,z); s->Center_Ellipsum_3D(m); s->Quality = 4. * s->Radius / (s->V[0]->lc + s->V[1]->lc + s->V[2]->lc + s->V[3]->lc); } } double GMSHMetric::operator () (int i, int j) { return m[i][j]; } double *GMSHMetric::operator[] (int i) { if(i < 0 || i > 3) return m[0]; return m[i]; } void GMSHMetric:: Identity() { m[0][0] = m[1][1] = m[2][2] = 1.0; m[1][0] = m[1][2] = m[0][1] = 0.0; m[2][0] = m[2][1] = m[0][2] = 0.0; } void GMSHMetric:: setMetric(double u, Curve * c) { ; } double GMSHMetric:: getLc(double u, Curve * c) { double l; Identity(); Vertex v = InterpolateCurve(c, u, 0); Vertex du = InterpolateCurve(c, u, 1); Local_Metric_Of_Attractors(v.Pos.X, v.Pos.Y, v.Pos.Z, NULL); l = LengthVector(&du); /* Msg(INFO,"GetLC : u = %g l=%g lc=%g return=%g\n", u, l, v.lc, l/v.lc); Msg(INFO,"Metric: %g %g %g %g %g %g %g %g %g \n ", m[0][0], m[0][1], m[0][2], m[1][0], m[1][1], m[1][2], m[2][0], m[2][1], m[2][2]); Msg(INFO,"du = %g %g %g\n",du.Pos.X,du.Pos.Y,du.Pos.Z); */ return l / v.lc; } double GMSHMetric:: LengthVector(Vertex * v) { double qqq = v->Pos.X * (v->Pos.X * m[0][0] + v->Pos.Y * m[0][1] + v->Pos.Z * m[0][2]) + v->Pos.Y * (v->Pos.X * m[1][0] + v->Pos.Y * m[1][1] + v->Pos.Z * m[1][2]) + v->Pos.Z * (v->Pos.X * m[2][0] + v->Pos.Y * m[2][1] + v->Pos.Z * m[2][2]); // Msg(INFO,"qqq = %g\n",qqq); return sqrt(qqq); } double GMSHMetric:: EdgeLengthOnSurface(Surface * s, Vertex * v[2], int cuts) { Vertex dv; if(!s) { dv = (*v[1]) - (*v[0]); return LengthVector(&dv); } dv.Pos.X = (v[1]->Pos.X - v[0]->Pos.X) / (double)cuts; dv.Pos.Y = (v[1]->Pos.Y - v[0]->Pos.Y) / (double)cuts; double l = 0.0, posu, posv; for(int i = 0; i < cuts; i++) { posu = v[0]->Pos.X + dv.Pos.X * ((double)(i) + 0.5); posv = v[0]->Pos.Y + dv.Pos.Y * ((double)(i) + 0.5); setMetric(posu, posv, s); l += LengthVector(&dv); } return l; }