diff --git a/Common/CommandLine.cpp b/Common/CommandLine.cpp index c16ad6482a21c8567a3a8a58fd3a868432f8da17..a38d80711e8ed7b841b78a246dba1916a823f162 100644 --- a/Common/CommandLine.cpp +++ b/Common/CommandLine.cpp @@ -1,4 +1,4 @@ -// $Id: CommandLine.cpp,v 1.87 2006-12-16 15:44:27 geuzaine Exp $ +// $Id: CommandLine.cpp,v 1.88 2007-01-12 13:16:59 remacle Exp $ // // Copyright (C) 1997-2007 C. Geuzaine, J.-F. Remacle // @@ -406,8 +406,10 @@ void Get_Options(int argc, char *argv[]) else if(!strcmp(argv[i] + 1, "algo")) { i++; if(argv[i] != NULL) { - if(!strncmp(argv[i], "iso", 3)) - CTX.mesh.algo2d = DELAUNAY_ISO; + if(!strncmp(argv[i], "bds", 3)) + CTX.mesh.algo2d = MESHADAPT; + else if(!strncmp(argv[i], "del", 3)) + CTX.mesh.algo2d = DELAUNAY2D; else if(!strncmp(argv[i], "tri", 3)) CTX.mesh.algo2d = DELAUNAY_TRIANGLE; else if(!strncmp(argv[i], "netgen", 6)) diff --git a/Common/DefaultOptions.h b/Common/DefaultOptions.h index 9625829a94a28f572f051db44ccd3b0a65468a13..08f9c12ece52727bdb3b14126b969c6127b60b82 100644 --- a/Common/DefaultOptions.h +++ b/Common/DefaultOptions.h @@ -836,8 +836,8 @@ StringXNumber GeometryOptions_Number[] = { } ; StringXNumber MeshOptions_Number[] = { - { F|O, "Algorithm" , opt_mesh_algo2d , DELAUNAY_ISO , - "2D mesh algorithm (1=isotropic, 2=anisotropic, 3=triangle)" }, + { F|O, "Algorithm" , opt_mesh_algo2d , MESHADAPT , + "2D mesh algorithm (1=meshadapt, 2=delaunay)" }, { F|O, "Algorithm3D" , opt_mesh_algo3d , #if defined(HAVE_TETGEN) DELAUNAY_ISO, diff --git a/Common/GmshDefines.h b/Common/GmshDefines.h index d2e48de5c555bbb907e4dc40d438e9ad7d7b0445..a35873417a857a65b4be29061784fa8e747f2e22 100644 --- a/Common/GmshDefines.h +++ b/Common/GmshDefines.h @@ -66,6 +66,8 @@ #define DELAUNAY_TRIANGLE 3 #define FRONTAL_NETGEN 4 #define DELAUNAY_TETGEN 5 +#define MESHADAPT 6 +#define DELAUNAY2D 7 #define TRANSFINI 1 #define LIBRE 2 diff --git a/Fltk/Callbacks.cpp b/Fltk/Callbacks.cpp index c868fa05010b45a31ea73dcdba2442de7d82dd8c..922c46c399863a96ef053b008916d489bbaaded1 100644 --- a/Fltk/Callbacks.cpp +++ b/Fltk/Callbacks.cpp @@ -1,4 +1,4 @@ -// $Id: Callbacks.cpp,v 1.499 2006-12-18 19:47:37 geuzaine Exp $ +// $Id: Callbacks.cpp,v 1.500 2007-01-12 13:16:59 remacle Exp $ // // Copyright (C) 1997-2007 C. Geuzaine, J.-F. Remacle // @@ -1092,7 +1092,8 @@ void mesh_options_ok_cb(CALLBACK_ARGS) opt_mesh_point_type(0, GMSH_SET, WID->mesh_choice[0]->value()); opt_mesh_algo2d(0, GMSH_SET, - (WID->mesh_choice[2]->value() == 0) ? DELAUNAY_ISO : + (WID->mesh_choice[2]->value() == 0) ? MESHADAPT : + (WID->mesh_choice[2]->value() == 1) ? DELAUNAY2D : DELAUNAY_TRIANGLE); opt_mesh_recombine_algo(0, GMSH_SET, (WID->mesh_choice[5]->value() == 0) ? 1 : 2); diff --git a/Fltk/GUI.cpp b/Fltk/GUI.cpp index bd7b1dde0e267eeaea11d762b2c2ab7fd6453c96..80bce128b52f37e6044ea90eb64e568ecbeb2e44 100644 --- a/Fltk/GUI.cpp +++ b/Fltk/GUI.cpp @@ -1,4 +1,4 @@ -// $Id: GUI.cpp,v 1.588 2006-12-21 21:47:05 geuzaine Exp $ +// $Id: GUI.cpp,v 1.589 2007-01-12 13:16:59 remacle Exp $ // // Copyright (C) 1997-2007 C. Geuzaine, J.-F. Remacle // @@ -2229,7 +2229,8 @@ void GUI::create_option_window() o->hide(); static Fl_Menu_Item menu_2d_algo[] = { - {"Isotropic", 0, 0, 0}, + {"MeshAdapt", 0, 0, 0}, + {"Delaunay", 0, 0, 0}, {"Triangle", 0, 0, 0}, {0} }; diff --git a/Geo/GModel.cpp b/Geo/GModel.cpp index 9ea6da85471a4969e2671b40aaff4279add25200..0d3f234024717052afe07aea505308f4de8c91a0 100644 --- a/Geo/GModel.cpp +++ b/Geo/GModel.cpp @@ -1,4 +1,4 @@ -// $Id: GModel.cpp,v 1.26 2006-12-17 22:23:17 geuzaine Exp $ +// $Id: GModel.cpp,v 1.27 2007-01-12 13:16:59 remacle Exp $ // // Copyright (C) 1997-2007 C. Geuzaine, J.-F. Remacle // @@ -301,6 +301,7 @@ double GModel::getMeshSize () if(meshSize < 0){ SBoundingBox3d b = bounds(); return 0.1 * norm(SVector3(b.max(), b.min())); + } else return meshSize; diff --git a/Geo/GModelIO_Geo.cpp b/Geo/GModelIO_Geo.cpp index 77a3860e0c0340f8f46721b29247ce058e95f884..c4d4cfcd23c966e4309d83b220697fc7f3bb03b9 100644 --- a/Geo/GModelIO_Geo.cpp +++ b/Geo/GModelIO_Geo.cpp @@ -1,4 +1,4 @@ -// $Id: GModelIO_Geo.cpp,v 1.5 2007-01-12 08:10:32 geuzaine Exp $ +// $Id: GModelIO_Geo.cpp,v 1.6 2007-01-12 13:16:59 remacle Exp $ // // Copyright (C) 1997-2007 C. Geuzaine, J.-F. Remacle // @@ -128,6 +128,8 @@ int GModel::importTHEM() ge->physicals.push_back(pnum); } } + + meshSize = 1.e22; Msg(DEBUG, "Gmsh model imported:"); Msg(DEBUG, "%d Vertices", vertices.size()); diff --git a/Geo/MElement.cpp b/Geo/MElement.cpp index bbc667e492a9f193b5d8fa3d464c261c49b76a78..2c8ce8ed8915957dfe885cbd85b2f0ccf1669040 100644 --- a/Geo/MElement.cpp +++ b/Geo/MElement.cpp @@ -1,4 +1,4 @@ -// $Id: MElement.cpp,v 1.25 2006-12-20 15:50:57 remacle Exp $ +// $Id: MElement.cpp,v 1.26 2007-01-12 13:16:59 remacle Exp $ // // Copyright (C) 1997-2007 C. Geuzaine, J.-F. Remacle // @@ -412,6 +412,7 @@ bool MTriangle::invertmappingXY(double *p, double *uv, double tol) b[0] = p[0] - getVertex(0)->x(); b[1] = p[1] - getVertex(0)->y(); sys2x2(mat, b, uv); + if(uv[0] >= -tol && uv[1] >= -tol && uv[0] <= 1. + tol && @@ -464,6 +465,8 @@ void MTriangle::circumcenterXY(double *res) const res[0] = (double)((a1 * (y3 - y2) + a2 * (y1 - y3) + a3 * (y2 - y1)) / d); res[1] = (double)((a1 * (x2 - x3) + a2 * (x3 - x1) + a3 * (x1 - x2)) / d); + // printf("%g %g - %g %g - %g %g cc %g %g\n",x1,y1,x2,y2,x3,y3,res[0],res[1]); + return ; } diff --git a/Mesh/BackgroundMesh.cpp b/Mesh/BackgroundMesh.cpp index e78d4f19701d0b022fa2af4a8b7d246cfc1685e4..aeb38945894c44cc80d35626d5e996af3be85493 100644 --- a/Mesh/BackgroundMesh.cpp +++ b/Mesh/BackgroundMesh.cpp @@ -1,4 +1,4 @@ -// $Id: BackgroundMesh.cpp,v 1.10 2006-12-05 14:22:05 remacle Exp $ +// $Id: BackgroundMesh.cpp,v 1.11 2007-01-12 13:16:59 remacle Exp $ // // Copyright (C) 1997-2007 C. Geuzaine, J.-F. Remacle // @@ -173,6 +173,7 @@ double BGM_MeshSize ( GEntity *ge, double U, double V , double X, double Y, doub double l3 = ge->model()->getMeshSize(); double l4 = LC_MVertex_BGM ( ge, X, Y , Z ); if (ge->dim() < 2) l2 = LC_MVertex_PNTS ( ge, U, V ); + // printf("ge->dim() %d l2 = %g l4 = %g l3 = %g\n",ge->dim(),l2,l3,l4); double l = std::min(std::min(l2,l4),l3); l *= CTX.mesh.lc_factor ; diff --git a/Mesh/Makefile b/Mesh/Makefile index 3e62ac0a87b54a467770b76a6474a89a5fc62edc..6bc744d029610775147303d9a4dc82fd618f648d 100644 --- a/Mesh/Makefile +++ b/Mesh/Makefile @@ -1,4 +1,4 @@ -# $Id: Makefile,v 1.158 2006-12-21 17:10:15 geuzaine Exp $ +# $Id: Makefile,v 1.159 2007-01-12 13:16:59 remacle Exp $ # # Copyright (C) 1997-2007 C. Geuzaine, J.-F. Remacle # @@ -36,6 +36,7 @@ SRC = Generator.cpp \ meshGFace.cpp \ meshGFaceTransfinite.cpp \ meshGFaceExtruded.cpp \ + meshGFaceDelaunayInsertion.cpp \ meshGRegion.cpp \ meshGRegionDelaunayInsertion.cpp \ meshGRegionTransfinite.cpp \ diff --git a/Mesh/meshGEdge.cpp b/Mesh/meshGEdge.cpp index ccb2282aaefdceb675e058f651e169e4f86c2a65..c103dd28000499d2bf020e2eb4cee99815653105 100644 --- a/Mesh/meshGEdge.cpp +++ b/Mesh/meshGEdge.cpp @@ -1,4 +1,4 @@ -// $Id: meshGEdge.cpp,v 1.25 2006-12-16 15:48:51 geuzaine Exp $ +// $Id: meshGEdge.cpp,v 1.26 2007-01-12 13:16:59 remacle Exp $ // // Copyright (C) 1997-2007 C. Geuzaine, J.-F. Remacle // @@ -56,6 +56,7 @@ double F_Lc(double t) else lc_here = BGM_MeshSize(_myGEdge, t , 0 , p.x(),p.y(),p.z()); SVector3 der = _myGEdge -> firstDer(t) ; + const double d = norm(der); return d/lc_here; } diff --git a/Mesh/meshGFace.cpp b/Mesh/meshGFace.cpp index 2cdc22bdee303c899aed43a62f81b52a1fa606cd..340e0c82bf51580dfdebbd13fd77247c3fe94f48 100644 --- a/Mesh/meshGFace.cpp +++ b/Mesh/meshGFace.cpp @@ -1,4 +1,4 @@ -// $Id: meshGFace.cpp,v 1.45 2006-12-21 17:10:15 geuzaine Exp $ +// $Id: meshGFace.cpp,v 1.46 2007-01-12 13:16:59 remacle Exp $ // // Copyright (C) 1997-2007 C. Geuzaine, J.-F. Remacle // @@ -20,6 +20,7 @@ // Please report all bugs and problems to <gmsh@geuz.org>. #include "meshGFace.h" +#include "meshGFaceDelaunayInsertion.h" #include "DivideAndConquer.h" #include "BackgroundMesh.h" #include "GVertex.h" @@ -807,16 +808,14 @@ bool gmsh2DMeshGenerator ( GFace *gf ) m->del_point(m->find_point(-3)); m->del_point(m->find_point(-4)); - // goto hhh; - // start mesh generation - - RefineMesh (gf,*m,100); - // OptimizeMesh (gf,*m,2); - - - if (gf->meshAttributes.recombine) + // start mesh generation + // if (CTX.mesh.algo2d == MESHADAPT) { - m->recombineIntoQuads (gf->meshAttributes.recombineAngle,gf); + RefineMesh (gf,*m,100); + if (gf->meshAttributes.recombine) + { + m->recombineIntoQuads (gf->meshAttributes.recombineAngle,gf); + } } // fill the small gmsh structures @@ -829,7 +828,6 @@ bool gmsh2DMeshGenerator ( GFace *gf ) if (numbered_vertices.find(p->iD) == numbered_vertices.end()) { MVertex *v = new MFaceVertex (p->X,p->Y,p->Z,gf,p->u,p->v); - //MVertex *v = new MFaceVertex (p->u,p->v,0,gf,p->u,p->v); numbered_vertices[p->iD]=v; gf->mesh_vertices.push_back(v); } @@ -861,11 +859,19 @@ bool gmsh2DMeshGenerator ( GFace *gf ) } } + // the delaunay algo is based directly on internal gmsh structures + // BDS mesh is passed in order not to recompute local coordinates + // of vertices +// if (CTX.mesh.algo2d == DELAUNAY2D ||CTX.mesh.algo2d == DELAUNAY_ISO) +// { +// insertVerticesInFace (gf,m) ; +// } // delete the mesh delete m; + delete [] U_; delete [] V_; @@ -1260,9 +1266,6 @@ bool gmsh2DMeshGeneratorPeriodic ( GFace *gf ) m->cleanup(); - - - { std::list<BDS_Edge*>::iterator ite = m->edges.begin(); while (ite != m->edges.end()) @@ -1291,16 +1294,14 @@ bool gmsh2DMeshGeneratorPeriodic ( GFace *gf ) // goto hhh; // start mesh generation - RefineMesh (gf,*m,100); - // OptimizeMesh (gf,*m,2); - - - - if (gf->meshAttributes.recombine) + // if (CTX.mesh.algo2d == MESHADAPT) { - m->recombineIntoQuads (gf->meshAttributes.recombineAngle,gf); + RefineMesh (gf,*m,100); + if (gf->meshAttributes.recombine) + { + m->recombineIntoQuads (gf->meshAttributes.recombineAngle,gf); + } } - // fill the small gmsh structures { @@ -1344,11 +1345,17 @@ bool gmsh2DMeshGeneratorPeriodic ( GFace *gf ) // delete the mesh - char name[245]; - sprintf(name,"param%d.pos",gf->tag()); + // char name[245]; + // sprintf(name,"param%d.pos",gf->tag()); //outputScalarField(m->triangles, name,1); - sprintf(name,"real%d.pos",gf->tag()); + // sprintf(name,"real%d.pos",gf->tag()); //outputScalarField(m->triangles, name,0); + +// if (CTX.mesh.algo2d == DELAUNAY2D ||CTX.mesh.algo2d == DELAUNAY_ISO) +// { +// insertVerticesInFace (gf,m) ; +// } + delete m; return true; @@ -1390,8 +1397,11 @@ void meshGFace :: operator() (GFace *gf) Msg(DEBUG1, "Generating the mesh"); // temp fix until we create MEdgeLoops in gmshFace: - if(gf->getNativeType() == GEntity::GmshModel || gf->edgeLoops.empty()) - gmsh2DMeshGenerator ( gf ) ; + if(gf->getNativeType() == GEntity::GmshModel || + gf->edgeLoops.empty() ) + { + gmsh2DMeshGenerator ( gf ); + } else { if (!gmsh2DMeshGeneratorPeriodic ( gf )) diff --git a/Mesh/meshGFaceDelaunayInsertion.cpp b/Mesh/meshGFaceDelaunayInsertion.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a08cd3ceb1fcb983378f0e365275836ff230d1c6 --- /dev/null +++ b/Mesh/meshGFaceDelaunayInsertion.cpp @@ -0,0 +1,569 @@ +// $Id: meshGFaceDelaunayInsertion.cpp,v 1.1 2007-01-12 13:16:59 remacle Exp $ +// +// Copyright (C) 1997-2007 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 "BDS.h" +#include "BackgroundMesh.h" +#include "meshGFaceDelaunayInsertion.h" +#include "GFace.h" +#include "Numeric.h" +#include "Message.h" +#include <set> +#include <map> +#include <algorithm> + +// computes the center of the circum circle in the tangent plane +// the metric given by a b d is supposed to be constant +void MTri3::Center_Circum_Aniso(double a, double b, double d, double &x, double &y, double &r) const +{ + double sys[2][2], X[2]; + double rhs[2]; + double x1, y1, x2, y2, x3, y3; + + x1 = base->getVertex(0)->x(); + y1 = base->getVertex(0)->y(); + x2 = base->getVertex(1)->x(); + y2 = base->getVertex(1)->y(); + x3 = base->getVertex(2)->x(); + y3 = base->getVertex(2)->y(); + + sys[0][0] = 2. * a * (x1 - x2) + 2. * b * (y1 - y2); + sys[0][1] = 2. * d * (y1 - y2) + 2. * b * (x1 - x2); + sys[1][0] = 2. * a * (x1 - x3) + 2. * b * (y1 - y3); + sys[1][1] = 2. * d * (y1 - y3) + 2. * b * (x1 - x3); + + rhs[0] = + a * (x1 * x1 - x2 * x2) + d * (y1 * y1 - y2 * y2) + 2. * b * (x1 * y1 - + x2 * y2); + rhs[1] = + a * (x1 * x1 - x3 * x3) + d * (y1 * y1 - y3 * y3) + 2. * b * (x1 * y1 - + x3 * y3); + sys2x2(sys, rhs, X); + + x = X[0]; + y = X[1]; + + r = sqrt((X[0] - x1) * (X[0] - x1) * a + + (X[1] - y1) * (X[1] - y1) * d + + 2. * (X[0] - x1) * (X[1] - y1) * b); +} + + +// find a common basis for 2 metrics in 2D +void simultaneousMetricReduction( const gmsh2dMetric &M1, const gmsh2dMetric &M2, + double & l1,double & l2, double V[2][2]) +{ + double a11=M1.a11,a21=M1.a21,a22=M1.a22; + double b11=M2.a11,b21=M2.a21,b22=M2.a22; + const double /*c11 = a11*a11,*/ c21= a21*a21; + const double /*d11 = b11*b11,*/ d21= b21*b21; + const double a=b11*b22 - d21; + const double b=-a11*b22-a22*b11+2*a21*b21; + const double c=-c21+a11*a22; + const double bb = b*b,ac= a*c; + const double delta = bb - 4 * ac; + if (bb + fabs(ac) < 1.0e-20 || (delta< 1.0E-4 * bb ) ) + { + if (fabs(a) < 1.e-30 ) + l1 = l2 = 0; + else + l1=l2=-b/(2*a); + V[0][0] = 1.; + V[1][0] = 0.; + V[0][1] = 0.; + V[1][1] = 1.; + } + else { + const double delta2 = sqrt(delta); + l1= (-b - delta2)/(2*a); + l2= (-b + delta2)/(2*a); + double v0 = a11-l1*b11, v1 = a21-l1*b21,v2 = a22 - l1*b22; + double s0 = v0*v0 + v1*v1, s1 = v1*v1 +v2*v2; + double vp1x,vp1y,vp2x,vp2y; + if(s1 < s0) + s0=sqrt(s0),vp1x=v1/s0,vp1y=-v0/s0; + else + s1=sqrt(s1),vp1x=v2/s1,vp1y=-v1/s1; + + v0 = a11-l2*b11, v1 = a21-l2*b21,v2 = a22 - l2*b22; + s0 = v0*v0 + v1*v1, s1 = v1*v1 +v2*v2; + if(s1 < s0) + s0=sqrt(s0),vp2x=v1/s0,vp2y=-v0/s0; + else + s1=sqrt(s1),vp2x=v2/s1,vp2y=-v1/s1; + V[0][0] = vp1x; + V[0][1] = vp2x; + V[1][0] = vp1y; + V[1][1] = vp2y; + } +} + +gmsh2dMetric metricIntersection(const gmsh2dMetric &Ma,const gmsh2dMetric &Mb) +{ + double M[2][2],M1[2][2]; + double l1,l2; + simultaneousMetricReduction(Ma,Mb,l1,l2,M); + inv2x2 ( M, M1 ); + const double M1ev1 = Ma.eval(M[0][0],M[0][1]); + const double M1ev2 = Ma.eval(M[0][0],M[0][1]); + const double M2ev1 = Mb.eval(M[1][0],M[1][1]); + const double M2ev2 = Mb.eval(M[1][0],M[1][1]); + + const double D0 = std::max( M1ev1,M1ev2); + const double D1 = std::max( M2ev1,M2ev2); + + return gmsh2dMetric(M1[0][0] * D0 * M1[0][0] + M1[0][1] * D1 * M1[0][1] , + 0.5 * ( M1[0][0] * D0 * M1[1][0] + M1[0][1] * D1 * M1[1][1] + + M1[1][0] * D0 * M1[0][0] + M1[1][1] * D1 * M1[0][1] ), + M1[1][0] * D0 * M1[1][0] + M1[1][1] * D1 * M1[1][1] ); +} + +gmsh2dMetric metricInterpolationTriangle(const gmsh2dMetric &M1, + const gmsh2dMetric &M2, + const gmsh2dMetric &M3, + const double u, + const double v) +{ + double m1[2][2] = {{M1.a11,0.5*M1.a21},{0.5*M1.a21,M1.a22}}; + double m2[2][2] = {{M2.a11,0.5*M2.a21},{0.5*M2.a21,M2.a22}}; + double m3[2][2] = {{M3.a11,0.5*M3.a21},{0.5*M3.a21,M3.a22}}; + double invm1 [2][2]; inv2x2 ( m1, invm1 ); + double invm2 [2][2]; inv2x2 ( m2, invm2 ); + double invm3 [2][2]; inv2x2 ( m3, invm3 ); + double invm [2][2] ; + for (int i=0;i<2;i++) + for (int j=0;j<2;j++) + invm[i][j] = (1.-u-v) * invm1[i][j] + u * invm2[i][j] + v * invm3[i][j]; + double m [2][2]; inv2x2 ( invm, m ); + return gmsh2dMetric ( m[0][0] , m[0][1] , m[1][1] ); +} + +gmsh2dMetric :: gmsh2dMetric ( double lc ) + : a11 ( 1./(lc*lc) ) ,a21 ( 0.0 ) ,a22 ( 1./(lc*lc) ) +{ +} + + +MTri3::MTri3 ( MTriangle * t, std::vector<gmsh2dMetric> & sizes) : deleted(false), base (t) +{ + neigh[0] = neigh[1] = neigh[2] = 0; + // compute the metric at the centroid + metric = metricInterpolationTriangle(sizes [base->getVertex(0)->getNum()] , + sizes [base->getVertex(1)->getNum()] , + sizes [base->getVertex(2)->getNum()] , + 1./3., 1./3.); + Center_Circum_Aniso(metric.a11,metric.a21,metric.a22, xc, yc, circum_radius); + // printf("metric %g %g %g circum_radius = %g\n",metric.a11,metric.a21,metric.a22,circum_radius); +} + +int inCircumCircle ( MTri3 *t , const double *p , const gmsh2dMetric &metric ) +{ + double xc, yc; + double eps, d1, d2, x[2]; + t->Center_Circum_Aniso(metric.a11,metric.a21,metric.a22,xc, yc, d1); + + x[0] = xc - p[0]; + x[1] = yc - p[1]; + + d2 = sqrt(fabs(metric.eval(x[0],x[1]))); + + eps = fabs(d1 - d2) / (d1 + d2); + if(eps < 1.e-12) { + return 0; + } + if(d2 < d1) + return 1; + return 0; + +} + +int MTri3::inCircumCircle ( const double *p ) const +{ + +// double pa[2] = {base->getVertex(0)->x(),base->getVertex(0)->y()}; +// double pb[2] = {base->getVertex(1)->x(),base->getVertex(1)->y()}; +// double pc[2] = {base->getVertex(2)->x(),base->getVertex(2)->y()}; +// double result = gmsh::incircle(pa, pb, pc, (double*)p) * gmsh::orient2d(pa, pb, pc); +// return (result > 0) ? 1 : 0; + + + double eps, d1, d2, x[2]; + + x[0] = xc - p[0]; + x[1] = yc - p[1]; + + d1 = circum_radius; + d2 = sqrt(fabs(metric.eval(x[0],x[1]))); + + eps = fabs(d1 - d2) / (d1 + d2); + if(eps < 1.e-12) { + return 0; + } + if(d2 < d1) + return 1; + return 0; +} + +struct edgeXface +{ + MVertex *v[2]; + MTri3 * t1; + int i1; + edgeXface ( MTri3 *_t, int iFac) + : t1(_t),i1(iFac) + { + v[0] = t1->tri()->getVertex ( iFac == 0 ? 2 : iFac-1 ); + v[1] = t1->tri()->getVertex ( iFac ); + std::sort ( v, v+2 ); + } + inline bool operator < ( const edgeXface & other) const + { + if (v[0] < other.v[0])return true; + if (v[0] > other.v[0])return false; + if (v[1] < other.v[1])return true; + return false; + } +}; + +template <class ITER> +void connectTris ( ITER beg, ITER end) +{ + std::set<edgeXface> conn; + { + while (beg != end) + { + if (!(*beg)->isDeleted()) + { + for (int i=0;i<3;i++) + { + edgeXface fxt ( *beg , i ); + std::set<edgeXface>::iterator found = conn.find (fxt); + if (found == conn.end()) + conn.insert ( fxt ); + else if (found->t1 != *beg) + { + found->t1->setNeigh(found->i1,*beg); + (*beg)->setNeigh ( i, found->t1); + } + } + } + ++beg; + } + } +} + + +void recurFindCavity (const gmsh2dMetric &metric, + std::list<edgeXface> & shell, + std::list<MTri3*> & cavity, + double *v, + MTri3 *t) +{ + t->setDeleted(true); + // the cavity that has to be removed + // because it violates delaunay criterion + cavity.push_back(t); + + for (int i=0;i<3;i++) + { + MTri3 *neigh = t->getNeigh(i) ; + if (!neigh) + shell.push_back ( edgeXface ( t, i ) ); + else if (!neigh->isDeleted()) + { + int circ = inCircumCircle ( neigh, v, metric ); + if (circ) + recurFindCavity ( metric,shell, cavity,v , neigh); + else + shell.push_back ( edgeXface ( t, i ) ); + } + } +} + +bool insertVertex (MVertex *v , + MTri3 *t , + std::set<MTri3*,compareTri3Ptr> &allTets, + std::vector<gmsh2dMetric> & vSizes, + const gmsh2dMetric &metric) +{ + std::list<edgeXface> shell; + std::list<MTri3*> cavity; + std::list<MTri3*> new_cavity; + + double p[2] = {v->x(),v->y()}; + + recurFindCavity ( metric,shell, cavity, p , t); + + // check that volume is conserved + double newVolume = 0; + double oldVolume = 0; + + std::list<MTri3*>::iterator ittet = cavity.begin(); + std::list<MTri3*>::iterator ittete = cavity.end(); + while ( ittet != ittete ) + { + oldVolume += fabs((*ittet)->getSurfaceXY()); + ++ittet; + } + +// char name[245]; +// int III = 1; +// sprintf(name,"test%d.pos",III); +// FILE *ff = fopen (name,"w"); +// fprintf(ff,"View\"test\"{\n"); + + + MTri3** newTris = new MTri3*[shell.size()];; + int k = 0; + std::list<edgeXface>::iterator it = shell.begin(); + + while (it != shell.end()) + { + MTriangle *t = new MTriangle ( it->v[0], + it->v[1], + v); + MTri3 *t4 = new MTri3 ( t , vSizes); +// fprintf(ff,"ST(%g,%g,%g,%g,%g,%g,%g,%g,%g) {0,0,0};\n", +// it->v[0]->x(), +// it->v[0]->y(), +// it->v[0]->z(), +// it->v[1]->x(), +// it->v[1]->y(), +// it->v[1]->z(), +// v->x(), +// v->y(), +// v->z()); + newTris[k++]=t4; + // all new triangles are pushed front in order to + // ba able to destroy them if the cavity is not + // star shaped around the new vertex. + new_cavity.push_back (t4); + MTri3 *otherSide = it->t1->getNeigh(it->i1); + + if (otherSide) + new_cavity.push_back (otherSide); + // if (!it->t1->isDeleted())throw; + double ss = fabs(t4->getSurfaceXY()); + if (ss < 1.e-12)ss = 1256172121; + newVolume += ss; + ++it; + } +// fprintf(ff,"};\n"); +// fclose (ff); +// printf("%d %d newVolume %g oldVolume %g\n",cavity.size(),new_cavity.size(),newVolume,oldVolume); +// getchar(); + + + if (fabs(oldVolume - newVolume) < 1.e-10 * oldVolume ) + { + connectTris ( new_cavity.begin(),new_cavity.end() ); + allTets.insert(newTris,newTris+shell.size()); + delete [] newTris; + return true; + } + // The cavity is NOT star shaped + else + { + for (unsigned int i=0;i<shell.size();i++)delete newTris[i]; + delete [] newTris; + ittet = cavity.begin(); + ittete = cavity.end(); + while ( ittet != ittete ) + { + (*ittet)->setDeleted(false); + ++ittet; + } + return false; + } +} + +static gmsh2dMetric evalMetricTensor ( GFace *gf , MVertex *mv , double lc ) +{ + Pair<SVector3,SVector3> der = gf->firstDer(SPoint2(mv->x(),mv->y())) ; + const double oneoverlc2 = 1./(lc*lc); + const double a11 = dot(der.first() ,der.first() ) * oneoverlc2; + const double a21 = dot(der.second(),der.first() ) * oneoverlc2; + const double a22 = dot(der.second(),der.second()) * oneoverlc2; + + // printf("metric : %g %g %g - %g %g\n",a11,a21,a22,oneoverlc2,lc); + + return gmsh2dMetric ( a11, a21 , a22); +} + +static void setLcs ( MTriangle *t, std::map<MVertex*,double> &vSizes) +{ + for (int i=0;i<3;i++) + { + for (int j=i+1;j<3;j++) + { + MVertex *vi = t->getVertex(i); + MVertex *vj = t->getVertex(j); + double dx = vi->x()-vj->x(); + double dy = vi->y()-vj->y(); + double dz = vi->z()-vj->z(); + double l = sqrt(dx*dx+dy*dy+dz*dz); + std::map<MVertex*,double>::iterator iti = vSizes.find(vi); + std::map<MVertex*,double>::iterator itj = vSizes.find(vj); + if (iti==vSizes.end() || iti->second > l)vSizes[vi] = l; + if (itj==vSizes.end() || itj->second > l)vSizes[vj] = l; + } + } +} + +void insertVerticesInFace (GFace *gf, BDS_Mesh *bds) +{ + + std::set<MTri3*,compareTri3Ptr> AllTris; + std::map<MVertex*,double> vSizesMap; + std::map<const BDS_Point*,MVertex*> recoverMap; + std::vector<gmsh2dMetric> vMetrics; + std::vector<double> vSizes; + + + // compute edge sizes on the contour and propagate thos sizes inside the surface + for (unsigned int i=0;i<gf->triangles.size();i++)setLcs ( gf->triangles[i] , vSizesMap); + + // set vertex positions to local coordinates of the face + // compute metric tensors of the surface + int NUM=0; + for (std::map<MVertex*,double>::iterator it = vSizesMap.begin();it!=vSizesMap.end();++it) + { + BDS_Point *p; + p = bds->find_point(it->first->getNum()); + it->first->x() = p->u; + it->first->y() = p->v; + it->first->z() = 0; + it->first->setNum(NUM++); + vSizes.push_back(it->second); + recoverMap[p]= (it->first); + vMetrics.push_back(evalMetricTensor ( gf , it->first, it->second)); + } + + for (unsigned int i=0;i<gf->triangles.size();i++) + AllTris.insert ( new MTri3 ( gf->triangles[i] ,vMetrics ) ); + + gf->triangles.clear(); + connectTris ( AllTris.begin(), AllTris.end() ); + + Msg(DEBUG,"All %d tris were connected",AllTris.size()); + + // here the classification should be done + + int ITER = 0; + + while (1) + { + MTri3 *worst = *AllTris.begin(); + + if (worst->isDeleted()) + { + delete worst->tri(); + delete worst; + AllTris.erase(AllTris.begin()); + // Msg(INFO,"Worst tet is deleted"); + } + else + { + if(ITER++%5000 ==0) + Msg(DEBUG,"%7d points created -- Worst tri radius is %8.3f",vSizes.size(),worst->getRadius()); + if (worst->getRadius() < 0.5 * sqrt(2.0)) break; + double center[2],uv[2]; + worst->getCenter(center); + // worst->tri()->circumcenterXY(center); + bool inside = worst->tri()->invertmappingXY(center,uv); + if (inside || 1) + { + // we use here local coordinates as real coordinates + // x,y and z will be computed hereafter + // Msg(INFO,"Point is inside"); + MVertex *v = new MFaceVertex (center[0],center[1],0.0,gf,center[0],center[1]); + v->setNum(NUM++); + double lc1 = (1.-uv[0]-uv[1]) * vSizes [worst->tri()->getVertex(0)->getNum()] + + uv[0] * vSizes [worst->tri()->getVertex(1)->getNum()] + + uv[1] * vSizes [worst->tri()->getVertex(2)->getNum()] ; + GPoint p = gf->point (center[0],center[1]); + double lc = std::min(lc1,BGM_MeshSize(gf,center[0],center[1],p.x(),p.y(),p.z())); + vSizes.push_back(lc); + gmsh2dMetric metr = evalMetricTensor ( gf , v, lc); + vMetrics.push_back(metr); + + // compute mesh spacing there + if (!insertVertex ( v , worst, AllTris,vMetrics,metr)) + { + AllTris.erase(AllTris.begin()); + worst->forceRadius(0); + AllTris.insert(worst); + delete v; + } + else + { + gf->mesh_vertices.push_back(v); + } + } + else + { + // Msg(INFO,"Point is outside"); + AllTris.erase(AllTris.begin()); + worst->forceRadius(0); + AllTris.insert(worst); + } + } + } + + // restore real coordinates of vertices + if (1){ + std::map<const BDS_Point*,MVertex*>::const_iterator itx = recoverMap.begin(); + while (itx != recoverMap.end()) + { + MVertex *v = (itx->second); + const BDS_Point *p = (itx->first); + v->x() = p->X; + v->y() = p->Y; + v->z() = p->Z; + ++itx; + } + for (unsigned int i=0;i<gf->mesh_vertices.size();i++) + { + double u = gf->mesh_vertices[i]->x(); + double v = gf->mesh_vertices[i]->y(); + GPoint p = gf->point(u,v); + gf->mesh_vertices[i]->x() = p.x(); + gf->mesh_vertices[i]->y() = p.y(); + gf->mesh_vertices[i]->z() = p.z(); + } + } + + // fill new gmsh structures with triangles + while (1) + { + if (AllTris.begin() == AllTris.end() ) break; + MTri3 *worst = *AllTris.begin(); + if (worst->isDeleted()) + { + delete worst->tri(); + } + else + { + gf->triangles.push_back(worst->tri()); + } + delete worst; + AllTris.erase(AllTris.begin()); + } +} diff --git a/Mesh/meshGFaceDelaunayInsertion.h b/Mesh/meshGFaceDelaunayInsertion.h new file mode 100644 index 0000000000000000000000000000000000000000..778489ec07721ebc51606ced190dff72e57c6c1f --- /dev/null +++ b/Mesh/meshGFaceDelaunayInsertion.h @@ -0,0 +1,114 @@ +#ifndef _DELAUNAYINSERTIONFACE_H_ +#define _DELAUNAYINSERTIONFACE_H_ + +// Copyright (C) 1997-2007 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 "MElement.h" +#include <list> +#include <set> +#include <map> + +class GFace; +class BDS_Mesh; +class BDS_Point; + +struct gmsh2dMetric +{ + double a11,a21,a22; + gmsh2dMetric (double lc); // uniform metric + gmsh2dMetric (double _a11 = 1, double _a21= 0, double _a22=1) + : a11(_a11),a21(_a21),a22(_a22) + {} + inline double eval ( const double &x, const double &y ) const + { + return x * a11 * x + 2 * x * a21 * y + y * a22 * y; + } +}; + + +class MTri3 +{ + bool deleted; + gmsh2dMetric metric; + double xc,yc; + double circum_radius; + MTriangle *base; + MTri3 *neigh[3]; + public : + + bool isDeleted () const {return deleted;} + void forceRadius (double r){circum_radius=r;} + double getRadius ()const {return circum_radius;} + inline void getCenter (double c[2]) const {c[0]=xc;c[1]=yc;} + + MTri3 ( MTriangle * t, std::vector<gmsh2dMetric> & sizes); + inline MTriangle * tri() const {return base;} + inline void setNeigh (int iN , MTri3 *n) {neigh[iN]=n;} + inline MTri3 *getNeigh (int iN ) const {return neigh[iN];} + int inCircumCircle ( const double *p ) const; + inline int inCircumCircle ( double x, double y ) const + { + const double p[2] = {x,y}; + return inCircumCircle ( p ); + } + inline int inCircumCircle ( const MVertex * v) const + { + return inCircumCircle ( v->x(), v->y() ); + } + + void Center_Circum_Aniso(double a, double b, double d, double &x, double &y, double &r) const ; + + double getSurfaceXY () const { return base -> getSurfaceXY() ; }; + inline void setDeleted (bool d) + { + deleted = d; + } + inline bool assertNeigh() const + { + if (deleted) return true; + for (int i=0;i<3;i++) + if (neigh[i] && (neigh[i]->isNeigh(this)==false))return false; + return true; + } + + inline bool isNeigh (const MTri3 *t) const + { + for (int i=0;i<3;i++) + if (neigh[i]==t) return true; + return false; + } + +}; + +void connectTriangles ( std::list<MTri3*> & ); +void insertVerticesInFace (GFace *gf, BDS_Mesh *); + +class compareTri3Ptr +{ + public: + inline bool operator () ( const MTri3 *a, const MTri3 *b ) + { + if (a->getRadius() > b->getRadius())return true; + if (a->getRadius() < b->getRadius())return false; + return a<b; + } +}; + +#endif diff --git a/Mesh/meshGRegionDelaunayInsertion.cpp b/Mesh/meshGRegionDelaunayInsertion.cpp index 07d1204a156360b5c15ee2e8dfeaadb240435c3a..aec76e24f8adb9bbce9d317346cf2697ec842a09 100644 --- a/Mesh/meshGRegionDelaunayInsertion.cpp +++ b/Mesh/meshGRegionDelaunayInsertion.cpp @@ -1,4 +1,4 @@ -// $Id: meshGRegionDelaunayInsertion.cpp,v 1.9 2006-12-01 16:16:50 remacle Exp $ +// $Id: meshGRegionDelaunayInsertion.cpp,v 1.10 2007-01-12 13:16:59 remacle Exp $ // // Copyright (C) 1997-2007 C. Geuzaine, J.-F. Remacle // @@ -319,7 +319,7 @@ void insertVerticesInRegion (GRegion *gr) gr->tetrahedra.clear(); connectTets ( allTets.begin(), allTets.end() ); - Msg(INFO,"All %d tets were connected",allTets.size()); + Msg(DEBUG,"All %d tets were connected",allTets.size()); // here the classification should be done @@ -339,7 +339,7 @@ void insertVerticesInRegion (GRegion *gr) else { if(ITER++%5000 ==0) - Msg(INFO,"%d points created -- Worst tet radius is %g",vSizes.size(),worst->getRadius()); + Msg(DEBUG,"%d points created -- Worst tet radius is %g",vSizes.size(),worst->getRadius()); if (worst->getRadius() < 1) break; double center[3]; worst->tet()->circumcenter(center); diff --git a/Numeric/Numeric.cpp b/Numeric/Numeric.cpp index 2316304da01137324c88bd23e001ff7ac4ec4359..7274d758340e529902b12f19ed20bddf2bdfcf3f 100644 --- a/Numeric/Numeric.cpp +++ b/Numeric/Numeric.cpp @@ -1,4 +1,4 @@ -// $Id: Numeric.cpp,v 1.30 2006-11-27 22:22:17 geuzaine Exp $ +// $Id: Numeric.cpp,v 1.31 2007-01-12 13:16:59 remacle Exp $ // // Copyright (C) 1997-2007 C. Geuzaine, J.-F. Remacle // @@ -257,6 +257,30 @@ int sys3x3_with_tol(double mat[3][3], double b[3], double res[3], double *det) return out; } +double det2x2(double mat[2][2]) +{ + return mat[0][0] *mat[1][1] -mat[1][0] *mat[0][1]; +} + +double inv2x2(double mat[2][2], double inv[2][2]) +{ + const double det = det2x2 ( mat ); + if(det){ + double ud = 1. / det; + inv[0][0] = ( mat[1][1] ) * ud ; + inv[1][0] = -( mat[1][0] ) * ud ; + inv[0][1] = -( mat[0][1] ) * ud ; + inv[1][1] = ( mat[0][0] ) * ud ; + } + else{ + Msg(GERROR, "Singular matrix"); + for(int i = 0; i < 2; i++) + for(int j = 0; j < 2; j++) + inv[i][j] = 0.; + } + return det; +} + double inv3x3(double mat[3][3], double inv[3][3]) { double det = det3x3(mat); diff --git a/Numeric/Numeric.h b/Numeric/Numeric.h index 675a0eea5e6783235587ec2d86a002f9d51b9804..2829edb7dabb2c0e388ea66bcdb333c3cd442f16 100644 --- a/Numeric/Numeric.h +++ b/Numeric/Numeric.h @@ -70,10 +70,12 @@ void normal3points(double x0, double y0, double z0, int sys2x2(double mat[2][2], double b[2], double res[2]); int sys3x3(double mat[3][3], double b[3], double res[3], double *det); int sys3x3_with_tol(double mat[3][3], double b[3], double res[3], double *det); +double det2x2(double mat[2][2]); double det3x3(double mat[3][3]); double trace3x3(double mat[3][3]); double trace2 (double mat[3][3]); double inv3x3(double mat[3][3], double inv[3][3]); +double inv2x2(double mat[2][2], double inv[2][2]); void invert_singular_matrix3x3(double MM[3][3], double II[3][3]); double angle_02pi(double A3); double angle_plan(double V[3], double P1[3], double P2[3], double n[3]); diff --git a/Parser/OpenFile.cpp b/Parser/OpenFile.cpp index 65cfffe728984947a7fda7737214087223ac334b..99b5a7a7c81a318ebb3ad151fb658c1bfaf53c51 100644 --- a/Parser/OpenFile.cpp +++ b/Parser/OpenFile.cpp @@ -1,4 +1,4 @@ -// $Id: OpenFile.cpp,v 1.137 2007-01-10 13:48:50 geuzaine Exp $ +// $Id: OpenFile.cpp,v 1.138 2007-01-12 13:17:00 remacle Exp $ // // Copyright (C) 1997-2007 C. Geuzaine, J.-F. Remacle // @@ -386,8 +386,8 @@ int MergeFile(char *name, int warn_if_missing) SBoundingBox3d bb; bb = GMODEL->bounds(); - - GMODEL->setMeshSize(0.1 * norm( SVector3 ( bb.max() , bb.min() ))); + if (GMODEL->getMeshSize() < 0) + GMODEL->setMeshSize(0.1 * norm( SVector3 ( bb.max() , bb.min() ))); CTX.geom.draw = 1; CTX.mesh.changed = ENT_ALL; diff --git a/benchmarks/2d/Square-01.geo b/benchmarks/2d/Square-01.geo index 0feef348ca6643e9ef529f2f6aaa9a52dcc41f2c..72c04246dbca630c5e0c642ebd48b6dabad34709 100644 --- a/benchmarks/2d/Square-01.geo +++ b/benchmarks/2d/Square-01.geo @@ -1,7 +1,7 @@ /****************************** Square uniformly meshed ******************************/ -lc = .49999; +lc = .3; Point(1) = {0.0,0.0,0,lc}; Point(2) = {1,0.0,0,lc}; Point(3) = {1,1,0,lc}; @@ -14,5 +14,5 @@ Line Loop(5) = {1,2,3,4}; Plane Surface(6) = {5}; //Attractor Point{2} = {0.05,0.05,2}; //Mesh.Algorithm = 2; -Transfinite Line {4,-2} = 130 Using Bump 5; -Transfinite Line {1,3} = 5 Using Progression 1; +//Transfinite Line {4,-2} = 130 Using Bump 5; +//Transfinite Line {1,3} = 5 Using Progression 1;