Skip to content
Snippets Groups Projects
Commit 0f0f1535 authored by Christophe Geuzaine's avatar Christophe Geuzaine
Browse files

No commit message

No commit message
parent 47e1c394
No related branches found
No related tags found
No related merge requests found
// Gmsh - Copyright (C) 1997-2014 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 <stdlib.h>
#include <vector>
#include "GmshConfig.h"
#include "GmshMessage.h"
#include "meshGRegion.h"
#include "meshGFace.h"
#include "meshGFaceOptimize.h"
#include "boundaryLayersData.h"
#include "meshGRegionBoundaryRecovery.h"
#include "meshGRegionDelaunayInsertion.h"
#include "GModel.h"
#include "GRegion.h"
#include "GFace.h"
#include "GEdge.h"
#include "gmshRegion.h"
#include "MLine.h"
#include "MTriangle.h"
#include "MQuadrangle.h"
#include "MTetrahedron.h"
#include "MPyramid.h"
#include "MPrism.h"
#include "MHexahedron.h"
#include "BDS.h"
#include "OS.h"
#include "Context.h"
#include "GFaceCompound.h"
#include "meshGRegionMMG3D.h"
#include "simple3D.h"
#include "Levy3D.h"
#include "directions3D.h"
#include "discreteFace.h"
#include "filterElements.h"
#if defined(HAVE_ANN)
#include "ANN/ANN.h"
#endif
// hybrid mesh recovery structure
class splitQuadRecovery {
std::multimap<GEntity*, std::pair<MVertex*,MFace> >_data;
bool _empty;
public :
std::map<MFace, MVertex*, Less_Face>_invmap;
std::set<MFace, Less_Face>_toDelete;
splitQuadRecovery() : _empty(true) {}
bool empty(){ return _empty; }
void setEmpty(bool val){ _empty = val; }
void add (const MFace &f, MVertex *v, GEntity*ge)
{
_data.insert(std::make_pair(ge, std::make_pair(v,f)));
}
int buildPyramids(GModel *gm)
{
if(empty()) return 0;
int NBPY = 0;
for (GModel::fiter it = gm->firstFace(); it != gm->lastFace(); ++it){
std::set<MFace, Less_Face> allFaces;
for (unsigned int i = 0; i < (*it)->triangles.size(); i++){
allFaces.insert ((*it)->triangles[i]->getFace(0));
delete (*it)->triangles[i];
}
(*it)->triangles.clear();
for (std::multimap<GEntity*, std::pair<MVertex*,MFace> >::iterator it2 =
_data.lower_bound(*it); it2 != _data.upper_bound(*it) ; ++it2){
const MFace &f = it2->second.second;
MVertex *v = it2->second.first;
v->onWhat()->mesh_vertices.erase(std::find(v->onWhat()->mesh_vertices.begin(),
v->onWhat()->mesh_vertices.end(), v));
std::set<MFace, Less_Face>::iterator itf0 = allFaces.find(MFace(f.getVertex(0),
f.getVertex(1),v));
std::set<MFace, Less_Face>::iterator itf1 = allFaces.find(MFace(f.getVertex(1),
f.getVertex(2),v));
std::set<MFace, Less_Face>::iterator itf2 = allFaces.find(MFace(f.getVertex(2),
f.getVertex(3),v));
std::set<MFace, Less_Face>::iterator itf3 = allFaces.find(MFace(f.getVertex(3),
f.getVertex(0),v));
if (itf0 != allFaces.end() && itf1 != allFaces.end() &&
itf2 != allFaces.end() && itf3 != allFaces.end()){
(*it)->quadrangles.push_back(new MQuadrangle(f.getVertex(0), f.getVertex(1),
f.getVertex(2), f.getVertex(3)));
allFaces.erase(*itf0);
allFaces.erase(*itf1);
allFaces.erase(*itf2);
allFaces.erase(*itf3);
// printf("some pyramids should be created %d regions\n", (*it)->numRegions());
for (int iReg = 0; iReg < (*it)->numRegions(); iReg++){
if (iReg == 1) {
Msg::Error("Cannot build pyramids on non manifold faces");
v = new MVertex(v->x(), v->y(), v->z(), (*it)->getRegion(iReg));
}
else
v->setEntity ((*it)->getRegion(iReg));
// A quad face connected to an hex or a primsm --> leave the quad face as is
if (_toDelete.find(f) == _toDelete.end()){
(*it)->getRegion(iReg)->pyramids.push_back
(new MPyramid(f.getVertex(0), f.getVertex(1), f.getVertex(2), f.getVertex(3), v));
(*it)->getRegion(iReg)->mesh_vertices.push_back(v);
NBPY++;
}
else {
delete v;
}
}
}
}
for (std::set<MFace, Less_Face>::iterator itf = allFaces.begin();
itf != allFaces.end(); ++itf){
(*it)->triangles.push_back
(new MTriangle(itf->getVertex(0), itf->getVertex(1), itf->getVertex(2)));
}
}
return NBPY;
}
};
void printVoronoi(GRegion *gr, std::set<SPoint3> &candidates)
{
std::vector<MTetrahedron*> elements = gr->tetrahedra;
std::list<GFace*> allFaces = gr->faces();
//building maps
std::map<MVertex*, std::set<MTetrahedron*> > node2Tet;
std::map<MFace, std::vector<MTetrahedron*> , Less_Face> face2Tet;
for(unsigned int i = 0; i < elements.size(); i++){
MTetrahedron *ele = elements[i];
for (int j=0; j<4; j++){
MVertex *v = ele->getVertex(j);
std::map<MVertex*, std::set<MTetrahedron*> >::iterator itmap = node2Tet.find(v);
if (itmap == node2Tet.end()){
std::set<MTetrahedron*> oneTet;
oneTet.insert(ele);
node2Tet.insert(std::make_pair(v, oneTet));
}
else{
std::set<MTetrahedron*> allTets = itmap->second;
allTets.insert(allTets.begin(), ele);
itmap->second = allTets;
}
}
for (int j = 0; j < 4; j++){
MFace f = ele->getFace(j);
std::map<MFace, std::vector<MTetrahedron*>, Less_Face >::iterator itmap =
face2Tet.find(f);
if (itmap == face2Tet.end()){
std::vector<MTetrahedron*> oneTet;
oneTet.push_back(ele);
face2Tet.insert(std::make_pair(f, oneTet));
}
else{
std::vector<MTetrahedron*> allTets = itmap->second;
allTets.insert(allTets.begin(), ele);
itmap->second = allTets;
}
}
}
//print voronoi poles
FILE *outfile;
//smooth_normals *snorm = gr->model()->normals;
outfile = Fopen("nodes.pos", "w");
fprintf(outfile, "View \"Voronoi poles\" {\n");
std::map<MVertex*, std::set<MTetrahedron*> >::iterator itmap = node2Tet.begin();
for(; itmap != node2Tet.end(); itmap++){
//MVertex *v = itmap->first;
std::set<MTetrahedron*> allTets = itmap->second;
std::set<MTetrahedron*>::const_iterator it = allTets.begin();
MTetrahedron *poleTet = *it;
double maxRadius = poleTet->getCircumRadius();
for(; it != allTets.end(); it++){
double radius = (*it)->getCircumRadius();
if (radius > maxRadius){
maxRadius = radius;
poleTet = *it;
}
}
//if (v->onWhat()->dim() == 2 ){
SPoint3 pc = poleTet->circumcenter();
//double nx,ny,nz;
// SVector3 vN = snorm->get(v->x(), v->y(), v->z(), nx,ny,nz);
// SVector3 pcv(pc.x()-nx, pc.y()-ny,pc.z()-nz);
// printf("nx=%g ny=%g nz=%g dot=%g \n", nx,ny,nz, dot(vN, pcv));
// if ( dot(vN, pcv) > 0.0 )
double x[3] = {pc.x(), pc.y(), pc.z()};
double uvw[3];
poleTet->xyz2uvw(x, uvw);
//bool inside = poleTet->isInside(uvw[0], uvw[1], uvw[2]);
//if (inside){
fprintf(outfile,"SP(%g,%g,%g) {%g};\n",
pc.x(), pc.y(), pc.z(), maxRadius);
candidates.insert(pc);
//}
//}
}
fprintf(outfile,"};\n");
fclose(outfile);
//print scalar lines
FILE *outfile2;
outfile2 = Fopen("edges.pos", "w");
fprintf(outfile2, "View \"Voronoi edges\" {\n");
std::map<MFace, std::vector<MTetrahedron*> , Less_Face >::iterator itmap2 = face2Tet.begin();
for(; itmap2 != face2Tet.end(); itmap2++){
std::vector<MTetrahedron*> allTets = itmap2->second;
if (allTets.size() != 2 ) continue;
SPoint3 pc1 = allTets[0]->circumcenter();
SPoint3 pc2 = allTets[1]->circumcenter();
//std::set<SPoint3>::const_iterator it1 = candidates.find(pc1);
//std::set<SPoint3>::const_iterator it2 = candidates.find(pc2);
//if( it1 != candidates.end() || it2 != candidates.end())
fprintf(outfile2,"SL(%g,%g,%g,%g,%g,%g) {%g,%g};\n",
pc1.x(), pc1.y(), pc1.z(), pc2.x(), pc2.y(), pc2.z(),
allTets[0]->getCircumRadius(),allTets[1]->getCircumRadius());
}
fprintf(outfile2,"};\n");
fclose(outfile2);
}
void getBoundingInfoAndSplitQuads(GRegion *gr,
std::map<MFace,GEntity*,Less_Face> &allBoundingFaces,
std::set<MVertex*> &allBoundingVertices,
splitQuadRecovery &sqr)
{
std::map<MFace, GEntity*, Less_Face> allBoundingFaces_temp;
// Get all the faces that are on the boundary
std::list<GFace*> faces = gr->faces();
std::list<GFace*>::iterator it = faces.begin();
while (it != faces.end()){
GFace *gf = (*it);
for(unsigned int i = 0; i < gf->getNumMeshElements(); i++){
allBoundingFaces_temp[gf->getMeshElement(i)->getFace(0)] = gf;
}
++it;
}
// if some elements pre-exist in the mesh, then use the internal faces of
// those
for (unsigned int i=0;i<gr->getNumMeshElements();i++){
MElement *e = gr->getMeshElement(i);
for (int j = 0; j < e->getNumFaces(); j++){
std::map<MFace, GEntity*, Less_Face>::iterator it = allBoundingFaces_temp.find(e->getFace(j));
if (it == allBoundingFaces_temp.end()) allBoundingFaces_temp[e->getFace(j)] = gr;
else allBoundingFaces_temp.erase(it);
}
}
std::map<MFace, GEntity*, Less_Face>::iterator itx = allBoundingFaces_temp.begin();
for (; itx != allBoundingFaces_temp.end();++itx){
const MFace &f = itx->first;
// split the quad face into 4 triangular faces
if (f.getNumVertices() == 4){
sqr.setEmpty(false);
MVertex *v0 = f.getVertex(0);
MVertex *v1 = f.getVertex(1);
MVertex *v2 = f.getVertex(2);
MVertex *v3 = f.getVertex(3);
MVertex *newv = new MVertex ((v0->x() + v1->x() + v2->x() + v3->x())*0.25,
(v0->y() + v1->y() + v2->y() + v3->y())*0.25,
(v0->z() + v1->z() + v2->z() + v3->z())*0.25,itx->second);
sqr.add(f,newv,itx->second);
sqr._invmap[f] = newv;
allBoundingFaces[MFace(v0,v1,newv)] = itx->second;
allBoundingFaces[MFace(v1,v2,newv)] = itx->second;
allBoundingFaces[MFace(v2,v3,newv)] = itx->second;
allBoundingFaces[MFace(v3,v0,newv)] = itx->second;
itx->second->mesh_vertices.push_back(newv);
allBoundingVertices.insert(v0);
allBoundingVertices.insert(v1);
allBoundingVertices.insert(v2);
allBoundingVertices.insert(v3);
allBoundingVertices.insert(newv);
}
else{
allBoundingFaces[f] = itx->second;
allBoundingVertices.insert(f.getVertex(0));
allBoundingVertices.insert(f.getVertex(1));
allBoundingVertices.insert(f.getVertex(2));
}
}
}
#if defined(HAVE_TETGEN)
#include "tetgen.h"
void buildTetgenStructure(GRegion *gr, tetgenio &in, std::vector<MVertex*> &numberedV,
splitQuadRecovery &sqr)
{
std::set<MVertex*> allBoundingVertices;
std::map<MFace,GEntity*,Less_Face> allBoundingFaces;
getBoundingInfoAndSplitQuads(gr, allBoundingFaces, allBoundingVertices, sqr);
//// TEST
{
std::vector<MVertex*>ALL;
std::vector<MTetrahedron*> MESH;
ALL.insert(ALL.begin(),allBoundingVertices.begin(),allBoundingVertices.end());
// delaunayMeshIn3D (ALL,MESH);
// exit(1);
}
in.mesh_dim = 3;
in.firstnumber = 1;
in.numberofpoints = allBoundingVertices.size() + Filler::get_nbr_new_vertices() +
LpSmoother::get_nbr_interior_vertices();
in.pointlist = new REAL[in.numberofpoints * 3];
in.pointmarkerlist = NULL;
std::set<MVertex*>::iterator itv = allBoundingVertices.begin();
int I = 1;
while(itv != allBoundingVertices.end()){
in.pointlist[(I - 1) * 3 + 0] = (*itv)->x();
in.pointlist[(I - 1) * 3 + 1] = (*itv)->y();
in.pointlist[(I - 1) * 3 + 2] = (*itv)->z();
(*itv)->setIndex(I++);
numberedV.push_back(*itv);
++itv;
}
for(int i=0;i<Filler::get_nbr_new_vertices();i++){
MVertex* v;
v = Filler::get_new_vertex(i);
in.pointlist[(I - 1) * 3 + 0] = v->x();
in.pointlist[(I - 1) * 3 + 1] = v->y();
in.pointlist[(I - 1) * 3 + 2] = v->z();
I++;
}
for(int i=0;i<LpSmoother::get_nbr_interior_vertices();i++){
MVertex* v;
v = LpSmoother::get_interior_vertex(i);
in.pointlist[(I - 1) * 3 + 0] = v->x();
in.pointlist[(I - 1) * 3 + 1] = v->y();
in.pointlist[(I - 1) * 3 + 2] = v->z();
I++;
}
in.numberoffacets = allBoundingFaces.size();
in.facetlist = new tetgenio::facet[in.numberoffacets];
in.facetmarkerlist = new int[in.numberoffacets];
I = 0;
std::map<MFace,GEntity*,Less_Face>::iterator it = allBoundingFaces.begin();
for (; it != allBoundingFaces.end();++it){
const MFace &fac = it->first;
tetgenio::facet *f = &in.facetlist[I];
tetgenio::init(f);
f->numberofholes = 0;
f->numberofpolygons = 1;
f->polygonlist = new tetgenio::polygon[f->numberofpolygons];
tetgenio::polygon *p = &f->polygonlist[0];
tetgenio::init(p);
p->numberofvertices = 3;
p->vertexlist = new int[p->numberofvertices];
p->vertexlist[0] = fac.getVertex(0)->getIndex();
p->vertexlist[1] = fac.getVertex(1)->getIndex();
p->vertexlist[2] = fac.getVertex(2)->getIndex();
in.facetmarkerlist[I] = (it->second->dim() == 3) ? -it->second->tag() : it->second->tag();
++I;
}
}
void TransferTetgenMesh(GRegion *gr, tetgenio &in, tetgenio &out,
std::vector<MVertex*> &numberedV)
{
// improvement has to be done here : tetgen splits some of the existing edges
// of the mesh. If those edges are classified on some model faces, new points
// SHOULD be classified on the model face and get the right set of parametric
// coordinates.
const int initialSize = (int)numberedV.size();
for(int i = numberedV.size(); i < out.numberofpoints; i++){
MVertex *v = new MVertex(out.pointlist[i * 3 + 0],
out.pointlist[i * 3 + 1],
out.pointlist[i * 3 + 2], gr);
gr->mesh_vertices.push_back(v);
numberedV.push_back(v);
}
Msg::Info("%d points %d edges and %d faces in the initial mesh",
out.numberofpoints, out.numberofedges, out.numberoftrifaces);
// Tetgen modifies both surface & edge mesh, so we need to re-create
// everything
gr->model()->destroyMeshCaches();
std::list<GFace*> faces = gr->faces();
for(std::list<GFace*>::iterator it = faces.begin(); it != faces.end(); it++){
GFace *gf = (*it);
for(unsigned int i = 0; i < gf->triangles.size(); i++)
delete gf->triangles[i];
for(unsigned int i = 0; i < gf->quadrangles.size(); i++)
delete gf->quadrangles[i];
gf->triangles.clear();
gf->quadrangles.clear();
gf->deleteVertexArrays();
}
// TODO: re-create 1D mesh
/*for(int i = 0; i < out.numberofedges; i++){
MVertex *v[2];
v[0] = numberedV[out.edgelist[i * 2 + 0] - 1];
v[1] = numberedV[out.edgelist[i * 2 + 1] - 1];
//implement here the 1D mesh ...
}*/
bool needParam = (CTX::instance()->mesh.order > 1 &&
CTX::instance()->mesh.secondOrderExperimental);
// re-create the triangular meshes FIXME: this can lead to hanging nodes for
// non manifold geometries (single surface connected to volume)
for(int i = 0; i < out.numberoftrifaces; i++){
// printf("%d %d %d\n",i,out.numberoftrifaces,needParam);
if (out.trifacemarkerlist[i] > 0) {
MVertex *v[3];
v[0] = numberedV[out.trifacelist[i * 3 + 0] - 1];
v[1] = numberedV[out.trifacelist[i * 3 + 1] - 1];
v[2] = numberedV[out.trifacelist[i * 3 + 2] - 1];
// do not recover prismatic faces !!!
GFace *gf = gr->model()->getFaceByTag(out.trifacemarkerlist[i]);
double guess[2] = {0, 0};
if (needParam) {
int Count = 0;
for(int j = 0; j < 3; j++){
if(!v[j]->onWhat()){
Msg::Error("Uncategorized vertex %d", v[j]->getNum());
}
else if(v[j]->onWhat()->dim() == 2){
double uu,vv;
v[j]->getParameter(0, uu);
v[j]->getParameter(1, vv);
guess[0] += uu;
guess[1] += vv;
Count++;
}
else if(v[j]->onWhat()->dim() == 1){
GEdge *ge = (GEdge*)v[j]->onWhat();
double UU;
v[j]->getParameter(0, UU);
SPoint2 param;
param = ge->reparamOnFace(gf, UU, 1);
guess[0] += param.x();
guess[1] += param.y();
Count++;
}
else if(v[j]->onWhat()->dim() == 0){
SPoint2 param;
GVertex *gv = (GVertex*)v[j]->onWhat();
param = gv->reparamOnFace(gf,1);
guess[0] += param.x();
guess[1] += param.y();
Count++;
}
}
if(Count != 0){
guess[0] /= Count;
guess[1] /= Count;
}
}
for(int j = 0; j < 3; j++){
if (out.trifacelist[i * 3 + j] - 1 >= initialSize){
printf("aaaaaaaaaaaaaaargh\n");
// if(v[j]->onWhat()->dim() == 3){
v[j]->onWhat()->mesh_vertices.erase
(std::find(v[j]->onWhat()->mesh_vertices.begin(),
v[j]->onWhat()->mesh_vertices.end(),
v[j]));
MVertex *v1b;
if(needParam){
// parametric coordinates should be set for the vertex ! (this is
// not 100 % safe yet, so we reserve that operation for high order
// meshes)
GPoint gp = gf->closestPoint(SPoint3(v[j]->x(), v[j]->y(), v[j]->z()), guess);
if(gp.g()){
v1b = new MFaceVertex(gp.x(), gp.y(), gp.z(), gf, gp.u(), gp.v());
}
else{
v1b = new MVertex(v[j]->x(), v[j]->y(), v[j]->z(), gf);
Msg::Warning("The point was not projected back to the surface (%g %g %g)",
v[j]->x(), v[j]->y(), v[j]->z());
}
}
else{
v1b = new MVertex(v[j]->x(), v[j]->y(), v[j]->z(), gf);
}
gf->mesh_vertices.push_back(v1b);
numberedV[out.trifacelist[i * 3 + j] - 1] = v1b;
delete v[j];
v[j] = v1b;
}
}
// printf("new triangle %d %d %d\n",v[0]->onWhat()->dim(), v[1]->onWhat()->dim(), v[2]->onWhat()->dim());
MTriangle *t = new MTriangle(v[0], v[1], v[2]);
gf->triangles.push_back(t);
}// do not do anything with prismatic faces
}
for(int i = 0; i < out.numberoftetrahedra; i++){
MVertex *v1 = numberedV[out.tetrahedronlist[i * 4 + 0] - 1];
MVertex *v2 = numberedV[out.tetrahedronlist[i * 4 + 1] - 1];
MVertex *v3 = numberedV[out.tetrahedronlist[i * 4 + 2] - 1];
MVertex *v4 = numberedV[out.tetrahedronlist[i * 4 + 3] - 1];
MTetrahedron *t = new MTetrahedron(v1, v2, v3, v4);
gr->tetrahedra.push_back(t);
}
}
#endif
static void addOrRemove(const MFace &f,
MElement *e,
std::map<MFace,MElement*,Less_Face> & bfaces,
splitQuadRecovery &sqr)
{
{
std::map<MFace, MVertex*, Less_Face>::const_iterator it = sqr._invmap.find(f);
if (it != sqr._invmap.end()){
addOrRemove (MFace(it->second, f.getVertex(0),f.getVertex(1)),e,bfaces,sqr);
addOrRemove (MFace(it->second, f.getVertex(1),f.getVertex(2)),e,bfaces,sqr);
addOrRemove (MFace(it->second, f.getVertex(2),f.getVertex(3)),e,bfaces,sqr);
addOrRemove (MFace(it->second, f.getVertex(3),f.getVertex(0)),e,bfaces,sqr);
return;
}
}
std::map<MFace,MElement*,Less_Face>::iterator it = bfaces.find(f);
if (it == bfaces.end())bfaces.insert(std::make_pair(f,e));
else bfaces.erase(it);
}
/*
here, we have a list of elements that actually do not form a mesh
--> a set boundary layer elements (prism, hexes, pyramids (and soon tets)
--> a set of tetrahedra that respect the external boundary of the BL mesh,
yet possiblty containing elements that are on the other side of the boundary
and therefore overlapping those elements. We have to extract the good ones !
*/
static bool AssociateElementsToModelRegionWithBoundaryLayers (GRegion *gr,
std::vector<MTetrahedron*> &tets,
std::vector<MHexahedron*> &hexes,
std::vector<MPrism*> &prisms,
std::vector<MPyramid*> &pyramids,
splitQuadRecovery & sqr)
{
std::set<MElement*> all;
all.insert(hexes.begin(),hexes.end());
all.insert(prisms.begin(),prisms.end());
all.insert(pyramids.begin(),pyramids.end());
// start with one BL element !
MElement *FIRST = all.size() ? *(all.begin()) : 0;
if (!FIRST) return true;
all.insert(tets.begin(),tets.end());
// printf("coucou1 %d eleemnts\n",all.size());
fs_cont search;
buildFaceSearchStructure(gr->model(), search);
// create the graph face 2 elements for the region
std::map<MFace,std::pair<MElement*,MElement*> ,Less_Face> myGraph;
for (std::set<MElement*>::iterator it = all.begin(); it != all.end(); ++it){
MElement *t = *it;
const int nbf = t->getNumFaces();
for (int j=0;j<nbf;j++){
MFace f = t->getFace(j);
std::map<MFace,std::pair<MElement*,MElement*>,Less_Face>::iterator itf = myGraph.find(f);
if (itf == myGraph.end())myGraph.insert (std::make_pair (f, std::make_pair (t,(MElement*)0)));
else {
// what to do ??????
// two tets and one prism --> the prism should be
// geometrically on the other side of the tet
if (itf->second.second) {
MElement *prism=0, *t1=0, *t2=0;
if (itf->second.second->getType () == TYPE_PRI || itf->second.second->getType () == TYPE_PYR) {
prism = itf->second.second;
t1 = itf->second.first;
t2 = t;
}
else if (itf->second.first->getType () == TYPE_PRI || itf->second.first->getType () == TYPE_PYR) {
prism = itf->second.first;
t1 = itf->second.second;
t2 = t;
}
else if (t->getType () == TYPE_PRI || t->getType () == TYPE_PYR) {
prism = t;
t1 = itf->second.second;
t2 = itf->second.first;
}
else {
printf("types %d %d %d\n",t->getType () ,itf->second.first->getType (),itf->second.second->getType () );
}
if (!t1 || !t2 || !prism){
gr->model()->writeMSH("ooops.msh");
Msg::Error ("Wrong BL configuration");
return false;
}
SVector3 n = f.normal();
SPoint3 c = f.barycenter();
MVertex *v_prism = 0, *v_t1 = 0, *v_t2 = 0;
for (int i=0;i<4;i++){
if (t1->getVertex(i) != f.getVertex(0) &&
t1->getVertex(i) != f.getVertex(1) &&
t1->getVertex(i) != f.getVertex(2))v_t1 = t1->getVertex(i);
if (t2->getVertex(i) != f.getVertex(0) &&
t2->getVertex(i) != f.getVertex(1) &&
t2->getVertex(i) != f.getVertex(2))v_t2 = t2->getVertex(i);
}
for (int i=0;i<prism->getNumVertices();i++){
if (prism->getVertex(i) != f.getVertex(0) &&
prism->getVertex(i) != f.getVertex(1) &&
prism->getVertex(i) != f.getVertex(2)) v_prism = prism->getVertex(i);
}
SVector3 vf1 (v_t1->x() - c.x(),v_t1->y() - c.y(),v_t1->z() - c.z());
SVector3 vf2 (v_t2->x() - c.x(),v_t2->y() - c.y(),v_t2->z() - c.z());
SVector3 vfp (v_prism->x() - c.x(),v_prism->y() - c.y(),v_prism->z() - c.z());
// printf("%12.5E %12.5E%12.5E\n",dot(vf1,n),dot(vf2,n),dot(vfp,n));
if (dot (vf1,n) * dot (vfp,n) > 0){itf->second.first = prism;itf->second.second=t2; /*delete t1;*/}
else if (dot (vf2,n) * dot (vfp,n) > 0){itf->second.first = prism;itf->second.second=t1; /*delete t2;*/}
// else if (dot (vf2,vfp) > 0){itf->second.first = prism;itf->second.second=t2;}
else Msg::Fatal("Impossible Geom Config");
}
else itf->second.second = t;
}
}
}
std::stack<MElement*> myStack;
std::set<MElement*> connected;
std::set<GFace*> faces_bound;
myStack.push(FIRST);
while (!myStack.empty()){
FIRST = myStack.top();
myStack.pop();
connected.insert(FIRST);
for (int i=0;i<FIRST->getNumFaces();i++){
MFace f = FIRST->getFace(i);
std::map<MFace, MVertex*, Less_Face>::iterator it = sqr._invmap.find(f);
GFace* gfound = 0;
if (it != sqr._invmap.end()){
gfound = (GFace*)it->second->onWhat();
// one pyramid is useless because one element with a quad face impacts the
// boundary of the domain.
sqr._toDelete.insert(f);
}
else gfound = findInFaceSearchStructure (f,search);
if (!gfound){
std::map<MFace,std::pair<MElement*,MElement*>,Less_Face>::iterator
itf = myGraph.find(f);
MElement *t_neigh = itf->second.first == FIRST ?
itf->second.second : itf->second.first;
if (!t_neigh)printf("oulalalalalalalala %d vertices\n",f.getNumVertices());
if (connected.find(t_neigh) == connected.end())myStack.push(t_neigh);
}
else {
// if (faces_bound.find(gfound) == faces_bound.end())printf("face %d\n",gfound->tag());
faces_bound.insert(gfound);
}
}
}
// printf ("found a set of %d elements that are connected with %d bounding faces\n",connected.size(),faces_bound.size());
GRegion *myGRegion = getRegionFromBoundingFaces(gr->model(), faces_bound);
// printf("REGION %d %d\n",myGRegion->tag(),gr->tag());
if (myGRegion == gr){
// printf("one region %d is found : %d elements\n",myGRegion->tag(),connected.size());
myGRegion->tetrahedra.clear();
for (std::set<MElement*>::iterator it = connected.begin(); it != connected.end(); ++it){
MElement *t = *it;
std::set<MVertex*> _mesh_vertices;
for (int i=0;i<t->getNumVertices();i++){
MVertex *_v = t->getVertex(i);
if (_v->onWhat() == gr){
_mesh_vertices.insert(_v);
}
}
// myGRegion->mesh_vertices.insert(myGRegion->mesh_vertices.end(),_mesh_vertices.begin(),_mesh_vertices.end());
if (t->getType() == TYPE_TET)
myGRegion->tetrahedra.push_back((MTetrahedron*)t);
else if (t->getType() == TYPE_HEX)
myGRegion->hexahedra.push_back((MHexahedron*)t);
else if (t->getType() == TYPE_PRI)
myGRegion->prisms.push_back((MPrism*)t);
else if (t->getType() == TYPE_PYR)
myGRegion->pyramids.push_back((MPyramid*)t);
}
}
else {
return false;
}
return true;
}
static int getWedge(BoundaryLayerColumns* _columns, MVertex *v1, MVertex *v2,
int indicesVert1 [], int indicesVert2 [])
{
int N1 = _columns->getNbColumns(v1) ;
int N2 = _columns->getNbColumns(v2) ;
int fanSize = 4;
int NW1 = 0;
int NW2 = 0;
for (int i=0;i<N1;i++){
const BoundaryLayerData & c1 = _columns->getColumn(v1,i);
if (c1._joint.size())NW1++;
}
for (int i=0;i<N2;i++){
const BoundaryLayerData & c2 = _columns->getColumn(v2,i);
if (c2._joint.size())NW2++;
}
std::map<int,int> one2two;
for (int i=0;i<NW1;i++){
const BoundaryLayerData & c1 = _columns->getColumn(v1,i);
for (int j=0;j<NW2;j++){
const BoundaryLayerData & c2 = _columns->getColumn(v2,j);
for (unsigned int k=0;k<c2._joint.size();k++){
if (std::find(c1._joint.begin(),c1._joint.end(),c2._joint[k]) !=
c1._joint.end()) {
one2two[i] = j;
}
}
}
}
// printf("%d %d %d %d \n",N1,N2,NW1,NW2);
// for (std::map<int,int>::iterator it = one2two.begin(); it != one2two.end(); it++){
// printf("one2two[%d] = %d\n",it->first,it->second);
// }
if (one2two.size() != 2)return 0;
int vert1Start,vert1End;
int vert2Start,vert2End;
std::map<int,int>::iterator it = one2two.begin();
vert1Start = it->first;
vert2Start = it->second;
++it;
vert1End = it->first;
vert2End = it->second;
int INDEX1 = 0, count = 0;
for (int i=0;i<NW1;i++){
for (int j=i+1;j<NW1;j++){
if ((vert1Start == i && vert1End == j) ||
(vert1Start == j && vert1End == i))
{
INDEX1 = count;
}
count++;
}
}
int INDEX2 = 0;
count = 0;
for (int i=0;i<NW2;i++){
for (int j=i+1;j<NW2;j++){
if ((vert2Start == i && vert2End == j) ||
(vert2Start == j && vert2End == i))
{
INDEX2 = count;
}
count++;
}
}
int indexVert1Start = NW1 + fanSize * ( 0 + INDEX1);
int indexVert1End = NW1 + fanSize * ( 1 + INDEX1);
int indexVert2Start = NW2 + fanSize * ( 0 + INDEX2);
int indexVert2End = NW2 + fanSize * ( 1 + INDEX2);
indicesVert1[0] = vert1Start;
int k=1;
for (int i=indexVert1Start;i< indexVert1End;++i)indicesVert1[k++] = i;
indicesVert1[fanSize+1] = vert1End;
indicesVert2[0] = vert2Start;
k = 1;
if (indexVert2End > indexVert2Start){
for (int i=indexVert2Start;i< indexVert2End;++i)indicesVert2[k++] = i;
}
else {
for (int i=indexVert2Start-1;i<= indexVert2End;--i)indicesVert2[k++] = i;
}
indicesVert2[fanSize+1] = vert2End;
// printf("%d %d %d %d %d %d %d %d\n",vert1Start,vert1End,vert2Start,vert2End,indexVert1Start,indexVert1End,indexVert2Start,indexVert2End);
// return 0;
return fanSize + 2;
}
static bool modifyInitialMeshForTakingIntoAccountBoundaryLayers(GRegion *gr, splitQuadRecovery & sqr)
{
if (getBLField(gr->model())) insertVerticesInRegion(gr,-1);
if (!buildAdditionalPoints3D (gr)) return false;
BoundaryLayerColumns* _columns = gr->getColumns();
std::map<MFace,MElement*,Less_Face> bfaces;
std::vector<MPrism*> blPrisms;
std::vector<MHexahedron*> blHexes;
std::vector<MPyramid*> blPyrs;
std::list<GFace*> faces = gr->faces();
std::list<GFace*> embedded_faces = gr->embeddedFaces();
faces.insert(faces.begin(), embedded_faces.begin(),embedded_faces.end());
std::set<MVertex*> verts;
{
std::list<GFace*>::iterator itf = faces.begin();
while(itf != faces.end()){
for(unsigned int i = 0; i< (*itf)->getNumMeshElements(); i++){
MElement *e = (*itf)->getMeshElement(i);
addOrRemove (e->getFace(0),0,bfaces,sqr);
}
++itf;
}
}
std::list<GFace*>::iterator itf = faces.begin();
while(itf != faces.end()){
for(unsigned int i = 0; i< (*itf)->triangles.size(); i++){
MVertex *v1 = (*itf)->triangles[i]->getVertex(0);
MVertex *v2 = (*itf)->triangles[i]->getVertex(1);
MVertex *v3 = (*itf)->triangles[i]->getVertex(2);
MFace dv (v1,v2,v3);
for (unsigned int SIDE = 0 ; SIDE < _columns->_normals3D.count(dv); SIDE ++){
faceColumn fc = _columns->getColumns(*itf,v1, v2, v3, SIDE);
const BoundaryLayerData & c1 = fc._c1;
const BoundaryLayerData & c2 = fc._c2;
const BoundaryLayerData & c3 = fc._c3;
int N = std::min(c1._column.size(),std::min(c2._column.size(),c3._column.size()));
// double distMax = getDistMax (v1, v2, v3, c1._n, c2._n, c3._n);
MFace f_low (v1,v2,v3);
SVector3 n_low = f_low.normal();
// printf("%d Layers\n",N);
std::vector<MElement*> myCol;
for (int l=0;l < N ;++l){
MVertex *v11,*v12,*v13,*v21,*v22,*v23;
v21 = c1._column[l];
v22 = c2._column[l];
v23 = c3._column[l];
if (l == 0){
v11 = v1;
v12 = v2;
v13 = v3;
}
else {
v11 = c1._column[l-1];
v12 = c2._column[l-1];
v13 = c3._column[l-1];
}
MFace f_up (v21,v22,v23);
SVector3 n_up = f_up.normal();
double dotProd = dot(n_up,n_low);
MPrism *prism = new MPrism(v11,v12,v13,v21,v22,v23);
if (dotProd > 0.2 && prism->skewness() > 0.1){
blPrisms.push_back(prism);
myCol.push_back(prism);
}
else {
delete prism;
l = N+1;
}
}
if (!myCol.empty()){
for (unsigned int l=0;l<myCol.size();l++)_columns->_toFirst[myCol[l]] = myCol[0];
_columns->_elemColumns[myCol[0]] = myCol;
}
}
}
++itf;
}
std::set<MEdge,Less_Edge> edges;
{
std::list<GEdge*> gedges = gr->edges();
for (std::list<GEdge*>::iterator it = gedges.begin(); it != gedges.end() ; ++it){
for (unsigned int i=0;i<(*it)->lines.size();++i){
edges.insert(MEdge((*it)->lines[i]->getVertex(0),(*it)->lines[i]->getVertex(1)));
}
}
}
// now treat the Wedges
// we have to know the two target GFaces that are concerned with a GEdge
std::set<MEdge>::iterator ite = edges.begin();
while(ite != edges.end()){
MEdge e = *ite;
MVertex *v1 = e.getVertex(0);
MVertex *v2 = e.getVertex(1);
if (v1 != v2){
int indices1[256];
int indices2[256];
int NbW = getWedge (_columns, v1, v2, indices1,indices2);
for (int i=0;i<NbW-1;i++){
int i11 = indices1[i];
int i12 = indices1[i+1];
int i21 = indices2[i];
int i22 = indices2[i+1];
BoundaryLayerData c11 = _columns->getColumn(v1,i11);
BoundaryLayerData c12 = _columns->getColumn(v1,i12);
BoundaryLayerData c21 = _columns->getColumn(v2,i21);
BoundaryLayerData c22 = _columns->getColumn(v2,i22);
int N = std::min(c11._column.size(),
std::min(c12._column.size(),
std::min(c21._column.size(), c22._column.size())));
std::vector<MElement*> myCol;
for (int l=0;l < N ;++l){
MVertex *v11,*v12,*v13,*v14;
MVertex *v21,*v22,*v23,*v24;
v21 = c11._column[l];
v22 = c12._column[l];
v23 = c22._column[l];
v24 = c21._column[l];
if (l == 0){
v11 = v12 = v1;
v13 = v14 = v2;
}
else {
v11 = c11._column[l-1];
v12 = c12._column[l-1];
v13 = c22._column[l-1];
v14 = c21._column[l-1];
}
if (l == 0){
MPrism *prism = new MPrism(v12,v21,v22,v13,v24,v23);
// store the layer the element belongs
myCol.push_back(prism);
blPrisms.push_back(prism);
}
else {
MHexahedron *hex = new MHexahedron(v11,v12,v13,v14,v21,v22,v23,v24);
// store the layer the element belongs
myCol.push_back(hex);
blHexes.push_back(hex);
}
}
if (!myCol.empty()){
for (unsigned int l=0;l<myCol.size();l++)_columns->_toFirst[myCol[l]] = myCol[0];
_columns->_elemColumns[myCol[0]] = myCol;
}
}
}
++ite;
}
// ------------------------------------------------------------------------------------
// FIXME : NOT 100 % CORRECT
// filterOverlappingElements (blPrisms,blHexes,_columns->_elemColumns,_columns->_toFirst);
// ------------------------------------------------------------------------------------
{
FILE *ff2 = fopen ("tato3D.pos","w");
fprintf(ff2,"View \" \"{\n");
for (unsigned int i = 0; i < blPrisms.size();i++){
blPrisms[i]->writePOS(ff2,1,0,0,0,0,0);
}
for (unsigned int i = 0; i < blHexes.size();i++){
blHexes[i]->writePOS(ff2,1,0,0,0,0,0);
}
fprintf(ff2,"};\n");
fclose(ff2);
}
for (unsigned int i = 0; i < blPrisms.size();i++){
for (unsigned int j=0;j<5;j++)
addOrRemove(blPrisms[i]->getFace(j),blPrisms[i],bfaces,sqr);
for (int j = 0; j < 6; j++)
if(blPrisms[i]->getVertex(j)->onWhat() == gr)verts.insert(blPrisms[i]->getVertex(j));
}
for (unsigned int i = 0; i < blHexes.size();i++){
for (unsigned int j=0;j<6;j++)
addOrRemove(blHexes[i]->getFace(j),blHexes[i],bfaces, sqr);
for (int j = 0; j < 8; j++)
if(blHexes[i]->getVertex(j)->onWhat() == gr)verts.insert(blHexes[i]->getVertex(j));
}
discreteFace *nf = new discreteFace(gr->model(), 444444);
gr->model()->add (nf);
std::list<GFace*> hop;
std::map<MFace,MElement*,Less_Face>::iterator it = bfaces.begin();
FILE *ff = fopen ("toto3D.pos","w");
fprintf(ff,"View \" \"{\n");
for (; it != bfaces.end(); ++it){
if (it->first.getNumVertices() == 3){
nf->triangles.push_back(new MTriangle (it->first.getVertex(0),it->first.getVertex(1),it->first.getVertex(2)));
fprintf(ff,"ST (%g,%g,%g,%g,%g,%g,%g,%g,%g){1,1,1};\n",
it->first.getVertex(0)->x(),it->first.getVertex(0)->y(),it->first.getVertex(0)->z(),
it->first.getVertex(1)->x(),it->first.getVertex(1)->y(),it->first.getVertex(1)->z(),
it->first.getVertex(2)->x(),it->first.getVertex(2)->y(),it->first.getVertex(2)->z());
}
else {
// we have a quad face --> create a pyramid
MElement *e = it->second;
// compute the center of the face;
SPoint3 center (0.25*(it->first.getVertex(0)->x()+it->first.getVertex(1)->x()+it->first.getVertex(2)->x()+it->first.getVertex(3)->x()),
0.25*(it->first.getVertex(0)->y()+it->first.getVertex(1)->y()+it->first.getVertex(2)->y()+it->first.getVertex(3)->y()),
0.25*(it->first.getVertex(0)->z()+it->first.getVertex(1)->z()+it->first.getVertex(2)->z()+it->first.getVertex(3)->z()));
// compute the center of the opposite face;
SPoint3 opposite (0,0,0);
int counter=0;
for (int i=0;i<e->getNumVertices();i++){
MVertex *vv = e->getVertex(i);
bool found = false;
for (int j=0;j<4;j++){
MVertex *ww = it->first.getVertex(j);
if (ww == vv)found = true;
}
if (!found){
counter ++;
opposite += SPoint3(vv->x(),vv->y(),vv->z());
}
}
// printf("counter = %d\n",counter);
if(counter)
opposite /= (double)counter;
SVector3 dir = center - opposite;
MTriangle temp (it->first.getVertex(0),it->first.getVertex(1),it->first.getVertex(2));
double D = temp.minEdge();
dir.normalize();
const double eps = D*1.e-2;
MVertex *newv = new MVertex (center.x() + eps * dir.x(),center.y() + eps * dir.y(), center.z() + eps * dir.z(), gr);
MPyramid *pyr = new MPyramid (it->first.getVertex(0),it->first.getVertex(1),it->first.getVertex(2),it->first.getVertex(3),newv);
verts.insert(newv);
blPyrs.push_back(pyr);
nf->triangles.push_back(new MTriangle (it->first.getVertex(0),it->first.getVertex(1),newv));
nf->triangles.push_back(new MTriangle (it->first.getVertex(1),it->first.getVertex(2),newv));
nf->triangles.push_back(new MTriangle (it->first.getVertex(2),it->first.getVertex(3),newv));
nf->triangles.push_back(new MTriangle (it->first.getVertex(3),it->first.getVertex(0),newv));
fprintf(ff,"ST (%g,%g,%g,%g,%g,%g,%g,%g,%g){2,2,2};\n",
it->first.getVertex(0)->x(),it->first.getVertex(0)->y(),it->first.getVertex(0)->z(),
it->first.getVertex(1)->x(),it->first.getVertex(1)->y(),it->first.getVertex(1)->z(),
newv->x(),newv->y(),newv->z());
fprintf(ff,"ST (%g,%g,%g,%g,%g,%g,%g,%g,%g){2,2,2};\n",
it->first.getVertex(1)->x(),it->first.getVertex(1)->y(),it->first.getVertex(1)->z(),
it->first.getVertex(2)->x(),it->first.getVertex(2)->y(),it->first.getVertex(2)->z(),
newv->x(),newv->y(),newv->z());
fprintf(ff,"ST (%g,%g,%g,%g,%g,%g,%g,%g,%g){2,2,2};\n",
it->first.getVertex(2)->x(),it->first.getVertex(2)->y(),it->first.getVertex(2)->z(),
it->first.getVertex(3)->x(),it->first.getVertex(3)->y(),it->first.getVertex(3)->z(),
newv->x(),newv->y(),newv->z());
fprintf(ff,"ST (%g,%g,%g,%g,%g,%g,%g,%g,%g){2,2,2};\n",
it->first.getVertex(3)->x(),it->first.getVertex(3)->y(),it->first.getVertex(3)->z(),
it->first.getVertex(0)->x(),it->first.getVertex(0)->y(),it->first.getVertex(0)->z(),
newv->x(),newv->y(),newv->z());
fprintf(ff,"SQ (%g,%g,%g,%g,%g,%g,%g,%g,%g,%g,%g,%g){3,3,3,3};\n",
it->first.getVertex(0)->x(),it->first.getVertex(0)->y(),it->first.getVertex(0)->z(),
it->first.getVertex(1)->x(),it->first.getVertex(1)->y(),it->first.getVertex(1)->z(),
it->first.getVertex(2)->x(),it->first.getVertex(2)->y(),it->first.getVertex(2)->z(),
it->first.getVertex(3)->x(),it->first.getVertex(3)->y(),it->first.getVertex(3)->z());
}
}
fprintf(ff,"};\n");
fclose(ff);
printf("discrete face with %d %d elems\n", (int)nf->triangles.size(),
(int)nf->quadrangles.size());
hop.push_back(nf);
for(unsigned int i = 0; i < gr->tetrahedra.size(); i++) delete gr->tetrahedra[i];
gr->tetrahedra.clear();
gr->set(hop);
CreateAnEmptyVolumeMesh(gr);
printf("%d tets\n", (int)gr->tetrahedra.size());
deMeshGFace _kill;
_kill (nf);
//<<<<<<< .mine
gr->model()->remove(nf);
// delete nf;
//=======
//>>>>>>> .r18259
delete nf;
gr->set(faces);
gr->mesh_vertices.insert(gr->mesh_vertices.begin(),verts.begin(),verts.end());
gr->model()->writeMSH("BL_start.msh");
AssociateElementsToModelRegionWithBoundaryLayers (gr, gr->tetrahedra , blHexes, blPrisms, blPyrs, sqr);
gr->model()->writeMSH("BL_start2.msh");
return true;
}
void _relocateVertex(MVertex *ver,
const std::vector<MElement*> &lt)
{
if(ver->onWhat()->dim() != 3) return;
double x = 0, y=0, z=0;
int N = 0;
bool isPyramid = false;
for(unsigned int i = 0; i < lt.size(); i++){
double XCG=0,YCG=0,ZCG=0;
for (int j=0;j<lt[i]->getNumVertices();j++){
XCG += lt[i]->getVertex(j)->x();
YCG += lt[i]->getVertex(j)->y();
ZCG += lt[i]->getVertex(j)->z();
}
x += XCG;
y += YCG;
z += ZCG;
if (lt[i]->getNumVertices() == 5) isPyramid = true;
N += lt[i]->getNumVertices();
}
if (isPyramid){
ver->x() = x / N;
ver->y() = y / N;
ver->z() = z / N;
}
}
#if defined(HAVE_TETGEN)
bool CreateAnEmptyVolumeMesh(GRegion *gr)
{
printf("creating an empty volume mesh\n");
splitQuadRecovery sqr;
tetgenio in, out;
std::vector<MVertex*> numberedV;
char opts[128];
buildTetgenStructure(gr, in, numberedV, sqr);
printf("tetgen structure created\n");
sprintf(opts, "-Ype%c",
(Msg::GetVerbosity() < 3) ? 'Q':
(Msg::GetVerbosity() > 6) ? 'V': '\0');
try{
tetrahedralize(opts, &in, &out);
}
catch (int error){
Msg::Error("Self intersecting surface mesh");
return false;
}
printf("creating an empty volume mesh done\n");
TransferTetgenMesh(gr, in, out, numberedV);
return true;
}
#else
bool CreateAnEmptyVolumeMesh(GRegion *gr)
{
Msg::Error("You should compile with TETGEN in order to create an empty volume mesh");
return false;
}
#endif
void MeshDelaunayVolumeTetgen(std::vector<GRegion*> &regions)
{
if(regions.empty()) return;
#if !defined(HAVE_TETGEN)
Msg::Error("Tetgen is not compiled in this version of Gmsh");
#else
for(unsigned int i = 0; i < regions.size(); i++)
Msg::Info("Meshing volume %d (Delaunay)", regions[i]->tag());
// put all the faces in the same model
GRegion *gr = regions[0];
std::list<GFace*> faces = gr->faces();
std::set<GFace*> allFacesSet;
for(unsigned int i = 0; i < regions.size(); i++){
std::list<GFace*> f = regions[i]->faces();
allFacesSet.insert(f.begin(), f.end());
f = regions[i]->embeddedFaces();
allFacesSet.insert(f.begin(), f.end());
}
std::list<GFace*> allFaces;
for(std::set<GFace*>::iterator it = allFacesSet.begin(); it != allFacesSet.end(); it++){
allFaces.push_back(*it);
}
gr->set(allFaces);
// mesh with tetgen, possibly changing the mesh on boundaries (leave
// this in block, so in/out are destroyed before we refine the mesh)
splitQuadRecovery sqr;
{
tetgenio in, out;
std::vector<MVertex*> numberedV;
char opts[128];
buildTetgenStructure(gr, in, numberedV, sqr);
if(CTX::instance()->mesh.algo3d == ALGO_3D_FRONTAL_DEL ||
CTX::instance()->mesh.algo3d == ALGO_3D_FRONTAL_HEX ||
CTX::instance()->mesh.algo3d == ALGO_3D_MMG3D ||
CTX::instance()->mesh.algo2d == ALGO_2D_FRONTAL_QUAD ||
CTX::instance()->mesh.algo2d == ALGO_2D_BAMG){
sprintf(opts, "Ype%c", (Msg::GetVerbosity() < 3) ? 'Q':
(Msg::GetVerbosity() > 6) ? 'V': '\0');
// removed -q because mesh sizes at new vertices are wrong
// sprintf(opts, "-q1.5pY%c", (Msg::GetVerbosity() < 3) ? 'Q':
// (Msg::GetVerbosity() > 6) ? 'V': '\0');
}
else if (CTX::instance()->mesh.algo3d == ALGO_3D_RTREE){
sprintf(opts, "S0Ype%c", (Msg::GetVerbosity() < 3) ? 'Q':
(Msg::GetVerbosity() > 6) ? 'V': '\0');
}
else {
sprintf(opts, "Ype%c",
(Msg::GetVerbosity() < 3) ? 'Q':
(Msg::GetVerbosity() > 6) ? 'V': '\0');
// removed -q because mesh sizes at new vertices are wrong
// sprintf(opts, "-q3.5Ype%c", (Msg::GetVerbosity() < 3) ? 'Q':
// (Msg::GetVerbosity() > 6) ? 'V': '\0');*/
}
try{
tetrahedralize(opts, &in, &out);
}
catch (int error){
Msg::Error("Self intersecting surface mesh, computing intersections "
"(this could take a while)");
sprintf(opts, "dV");
try{
tetrahedralize(opts, &in, &out);
Msg::Info("%d intersecting faces have been saved into 'intersect.pos'",
out.numberoftrifaces);
FILE *fp = Fopen("intersect.pos", "w");
if(fp){
fprintf(fp, "View \"intersections\" {\n");
for(int i = 0; i < out.numberoftrifaces; i++){
MVertex *v1 = numberedV[out.trifacelist[i * 3 + 0] - 1];
MVertex *v2 = numberedV[out.trifacelist[i * 3 + 1] - 1];
MVertex *v3 = numberedV[out.trifacelist[i * 3 + 2] - 1];
int surf = out.trifacemarkerlist[i];
fprintf(fp, "ST(%g,%g,%g,%g,%g,%g,%g,%g,%g){%d,%d,%d};\n",
v1->x(), v1->y(), v1->z(), v2->x(), v2->y(), v2->z(),
v3->x(), v3->y(), v3->z(), surf, surf, surf);
}
fprintf(fp, "};\n");
fclose(fp);
}
else
Msg::Error("Could not open file 'intersect.pos'");
}
catch (int error2){
Msg::Error("Surface mesh is wrong, cannot do the 3D mesh");
}
gr->set(faces);
return;
}
TransferTetgenMesh(gr, in, out, numberedV);
}
// sort triangles in all model faces in order to be able to search in vectors
std::list<GFace*>::iterator itf = allFaces.begin();
while(itf != allFaces.end()){
compareMTriangleLexicographic cmp;
std::sort((*itf)->triangles.begin(), (*itf)->triangles.end(), cmp);
++itf;
}
// restore the initial set of faces
gr->set(faces);
bool _BL = modifyInitialMeshForTakingIntoAccountBoundaryLayers(gr,sqr);
// now do insertion of points
if(CTX::instance()->mesh.algo3d == ALGO_3D_FRONTAL_DEL)
bowyerWatsonFrontalLayers(gr, false);
else if(CTX::instance()->mesh.algo3d == ALGO_3D_FRONTAL_HEX)
bowyerWatsonFrontalLayers(gr, true);
else if(CTX::instance()->mesh.algo3d == ALGO_3D_MMG3D){
refineMeshMMG(gr);
}
else
if(!Filler::get_nbr_new_vertices() && !LpSmoother::get_nbr_interior_vertices()){
insertVerticesInRegion(gr,2000000000,!_BL);
}
//emi test frame field
// int NumSmooth = 10;//CTX::instance()->mesh.smoothCrossField
// std::cout << "NumSmooth = " << NumSmooth << std::endl;
// if(NumSmooth && (gr->dim() == 3)){
// double scale = gr->bounds().diag()*1e-2;
// Frame_field::initRegion(gr,NumSmooth);
// Frame_field::saveCrossField("cross0.pos",scale);
// //Frame_field::smoothRegion(gr,NumSmooth);
// //Frame_field::saveCrossField("cross1.pos",scale);
// GFace *gf = GModel::current()->getFaceByTag(2);
// Frame_field::continuousCrossField(gr,gf);
// Frame_field::saveCrossField("cross2.pos",scale);
// }
// Frame_field::init_region(gr);
// Frame_field::clear();
// exit(1);
//fin test emi
if (sqr.buildPyramids (gr->model())){
// relocate vertices if pyramids
for(unsigned int k = 0; k < regions.size(); k++){
v2t_cont adj;
buildVertexToElement(regions[k]->tetrahedra, adj);
buildVertexToElement(regions[k]->pyramids, adj);
v2t_cont::iterator it = adj.begin();
while (it != adj.end()){
_relocateVertex( it->first, it->second);
++it;
}
}
}
#endif
}
// uncomment this to test the new code
//##define NEW_CODE
void MeshDelaunayVolume(std::vector<GRegion*> &regions)
{
if(regions.empty()) return;
#if !defined(NEW_CODE) && defined(HAVE_TETGEN)
MeshDelaunayVolumeTetgen(regions);
return;
#endif
splitQuadRecovery sqr;
for(unsigned int i = 0; i < regions.size(); i++)
Msg::Info("Meshing volume %d (Delaunay)", regions[i]->tag());
// put all the faces in the same model
GRegion *gr = regions[0];
std::list<GFace*> faces = gr->faces();
std::set<GFace*> allFacesSet;
for(unsigned int i = 0; i < regions.size(); i++){
std::list<GFace*> f = regions[i]->faces();
allFacesSet.insert(f.begin(), f.end());
f = regions[i]->embeddedFaces();
allFacesSet.insert(f.begin(), f.end());
}
std::list<GFace*> allFaces;
for(std::set<GFace*>::iterator it = allFacesSet.begin();
it != allFacesSet.end(); it++){
allFaces.push_back(*it);
}
gr->set(allFaces);
try{
meshGRegionBoundaryRecovery *init = new meshGRegionBoundaryRecovery();
init->reconstructmesh(gr);
delete init;
}
catch(int err){
Msg::Error("Could not recover boundary: error %d", err);
}
// sort triangles in all model faces in order to be able to search in vectors
std::list<GFace*>::iterator itf = allFaces.begin();
while(itf != allFaces.end()){
compareMTriangleLexicographic cmp;
std::sort((*itf)->triangles.begin(), (*itf)->triangles.end(), cmp);
++itf;
}
// restore the initial set of faces
gr->set(faces);
bool _BL = modifyInitialMeshForTakingIntoAccountBoundaryLayers(gr,sqr);
// now do insertion of points
if(CTX::instance()->mesh.algo3d == ALGO_3D_FRONTAL_DEL)
bowyerWatsonFrontalLayers(gr, false);
else if(CTX::instance()->mesh.algo3d == ALGO_3D_FRONTAL_HEX)
bowyerWatsonFrontalLayers(gr, true);
else if(CTX::instance()->mesh.algo3d == ALGO_3D_MMG3D){
refineMeshMMG(gr);
}
else if(!Filler::get_nbr_new_vertices() && !LpSmoother::get_nbr_interior_vertices()){
insertVerticesInRegion(gr,2000000000,!_BL);
}
}
#if defined(HAVE_NETGEN)
namespace nglib {
#include "nglib_gmsh.h"
}
using namespace nglib;
static void getAllBoundingVertices(GRegion *gr, std::set<MVertex*> &allBoundingVertices)
{
std::list<GFace*> faces = gr->faces();
std::list<GFace*>::iterator it = faces.begin();
while (it != faces.end()){
GFace *gf = (*it);
for(unsigned int i = 0; i < gf->triangles.size(); i++){
MTriangle *t = gf->triangles[i];
for(int k = 0; k < 3; k++)
if(allBoundingVertices.find(t->getVertex(k)) == allBoundingVertices.end())
allBoundingVertices.insert(t->getVertex(k));
}
++it;
}
}
Ng_Mesh *buildNetgenStructure(GRegion *gr, bool importVolumeMesh,
std::vector<MVertex*> &numberedV)
{
Ng_Init();
Ng_Mesh *ngmesh = Ng_NewMesh();
std::set<MVertex*> allBoundingVertices;
getAllBoundingVertices(gr, allBoundingVertices);
std::set<MVertex*>::iterator itv = allBoundingVertices.begin();
int I = 1;
while(itv != allBoundingVertices.end()){
double tmp[3];
tmp[0] = (*itv)->x();
tmp[1] = (*itv)->y();
tmp[2] = (*itv)->z();
(*itv)->setIndex(I++);
numberedV.push_back(*itv);
Ng_AddPoint(ngmesh, tmp);
++itv;
}
if(importVolumeMesh){
for(unsigned int i = 0; i < gr->mesh_vertices.size(); i++){
double tmp[3];
tmp[0] = gr->mesh_vertices[i]->x();
tmp[1] = gr->mesh_vertices[i]->y();
tmp[2] = gr->mesh_vertices[i]->z();
gr->mesh_vertices[i]->setIndex(I++);
Ng_AddPoint(ngmesh, tmp);
}
}
std::list<GFace*> faces = gr->faces();
std::list<GFace*>::iterator it = faces.begin();
while(it != faces.end()){
GFace *gf = (*it);
for(unsigned int i = 0; i< gf->triangles.size(); i++){
MTriangle *t = gf->triangles[i];
int tmp[3];
tmp[0] = t->getVertex(0)->getIndex();
tmp[1] = t->getVertex(1)->getIndex();
tmp[2] = t->getVertex(2)->getIndex();
Ng_AddSurfaceElement(ngmesh, NG_TRIG, tmp);
}
++it;
}
if(importVolumeMesh){
for(unsigned int i = 0; i< gr->tetrahedra.size(); i++){
MTetrahedron *t = gr->tetrahedra[i];
// netgen expects tet with negative volume
if(t->getVolumeSign() > 0) t->reverse();
int tmp[4];
tmp[0] = t->getVertex(0)->getIndex();
tmp[1] = t->getVertex(1)->getIndex();
tmp[2] = t->getVertex(2)->getIndex();
tmp[3] = t->getVertex(3)->getIndex();
Ng_AddVolumeElement(ngmesh, NG_TET, tmp);
}
}
return ngmesh;
}
void TransferVolumeMesh(GRegion *gr, Ng_Mesh *ngmesh,
std::vector<MVertex*> &numberedV)
{
// Gets total number of vertices of Netgen's mesh
int nbv = Ng_GetNP(ngmesh);
if(!nbv) return;
int nbpts = numberedV.size();
// Create new volume vertices
for(int i = nbpts; i < nbv; i++){
double tmp[3];
Ng_GetPoint(ngmesh, i + 1, tmp);
MVertex *v = new MVertex (tmp[0], tmp[1], tmp[2], gr);
numberedV.push_back(v);
gr->mesh_vertices.push_back(v);
}
// Get total number of simplices of Netgen's mesh
int nbe = Ng_GetNE(ngmesh);
// Create new volume simplices
for(int i = 0; i < nbe; i++){
int tmp[4];
Ng_GetVolumeElement(ngmesh, i + 1, tmp);
MTetrahedron *t = new MTetrahedron(numberedV[tmp[0] - 1],
numberedV[tmp[1] - 1],
numberedV[tmp[2] - 1],
numberedV[tmp[3] - 1]);
gr->tetrahedra.push_back(t);
}
}
#endif
void deMeshGRegion::operator() (GRegion *gr)
{
if(gr->geomType() == GEntity::DiscreteVolume) return;
gr->deleteMesh();
}
/// X_1 (1-u-v) + X_2 u + X_3 v = P_x + t N_x
/// Y_1 (1-u-v) + Y_2 u + Y_3 v = P_y + t N_y
/// Z_1 (1-u-v) + Z_2 u + Z_3 v = P_z + t N_z
int intersect_line_triangle(double X[3], double Y[3], double Z[3] ,
double P[3], double N[3], const double eps_prec)
{
double mat[3][3], det;
double b[3], res[3];
mat[0][0] = X[1] - X[0];
mat[0][1] = X[2] - X[0];
mat[0][2] = N[0];
mat[1][0] = Y[1] - Y[0];
mat[1][1] = Y[2] - Y[0];
mat[1][2] = N[1];
mat[2][0] = Z[1] - Z[0];
mat[2][1] = Z[2] - Z[0];
mat[2][2] = N[2];
b[0] = P[0] - X[0];
b[1] = P[1] - Y[0];
b[2] = P[2] - Z[0];
if(!sys3x3_with_tol(mat, b, res, &det))
{
return 0;
}
// printf("coucou %g %g %g\n",res[0],res[1],res[2]);
if(res[0] >= eps_prec && res[0] <= 1.0 - eps_prec &&
res[1] >= eps_prec && res[1] <= 1.0 - eps_prec &&
1 - res[0] - res[1] >= eps_prec && 1 - res[0] - res[1] <= 1.0 - eps_prec){
// the line clearly intersects the triangle
return (res[2] > 0) ? 1 : 0;
}
else if(res[0] < -eps_prec || res[0] > 1.0 + eps_prec ||
res[1] < -eps_prec || res[1] > 1.0 + eps_prec ||
1 - res[0] - res[1] < -eps_prec || 1 - res[0] - res[1] > 1.0 + eps_prec){
// the line clearly does NOT intersect the triangle
return 0;
}
else{
printf("non robust stuff\n");
// the intersection is not robust, try another triangle
return -10000;
}
}
void setRand(double r[6])
{
for(int i = 0; i < 6; i++)
r[i] = 0.0001 * ((double)rand() / (double)RAND_MAX);
}
void meshNormalsPointOutOfTheRegion(GRegion *gr)
{
std::list<GFace*> faces = gr->faces();
std::list<GFace*>::iterator it = faces.begin();
//for (std::list<GFace*>::iterator itb = faces.begin(); itb != faces.end(); itb ++)
// printf("face=%d size =%d\n", (*itb)->tag(), faces.size());
double rrr[6];
setRand(rrr);
while(it != faces.end()){
GFace *gf = (*it);
int nb_intersect = 0;
for(unsigned int i = 0; i < gf->triangles.size(); i++){
MTriangle *t = gf->triangles[i];
double X[3] = {t->getVertex(0)->x(), t->getVertex(1)->x(), t->getVertex(2)->x()};
double Y[3] = {t->getVertex(0)->y(), t->getVertex(1)->y(), t->getVertex(2)->y()};
double Z[3] = {t->getVertex(0)->z(), t->getVertex(1)->z(), t->getVertex(2)->z()};
double P[3] = {(X[0] + X[1] + X[2]) / 3.,
(Y[0] + Y[1] + Y[2]) / 3.,
(Z[0] + Z[1] + Z[2]) / 3.};
double v1[3] = {X[0] - X[1], Y[0] - Y[1], Z[0] - Z[1]};
double v2[3] = {X[2] - X[1], Y[2] - Y[1], Z[2] - Z[1]};
double N[3];
prodve(v1, v2, N);
norme(v1);
norme(v2);
norme(N);
N[0] += rrr[0] * v1[0] + rrr[1] * v2[0];
N[1] += rrr[2] * v1[1] + rrr[3] * v2[1];
N[2] += rrr[4] * v1[2] + rrr[5] * v2[2];
norme(N);
std::list<GFace*>::iterator it_b = faces.begin();
while(it_b != faces.end()){
GFace *gf_b = (*it_b);
for(unsigned int i_b = 0; i_b < gf_b->triangles.size(); i_b++){
MTriangle *t_b = gf_b->triangles[i_b];
if(t_b != t){
double X_b[3] = {t_b->getVertex(0)->x(), t_b->getVertex(1)->x(),
t_b->getVertex(2)->x()};
double Y_b[3] = {t_b->getVertex(0)->y(), t_b->getVertex(1)->y(),
t_b->getVertex(2)->y()};
double Z_b[3] = {t_b->getVertex(0)->z(), t_b->getVertex(1)->z(),
t_b->getVertex(2)->z()};
int inters = intersect_line_triangle(X_b, Y_b, Z_b, P, N, 1.e-9);
nb_intersect += inters;
}
}
++it_b;
}
Msg::Info("Region %d Face %d, %d intersect", gr->tag(), gf->tag(), nb_intersect);
if(nb_intersect >= 0) break; // negative value means intersection is not "robust"
}
if(nb_intersect < 0){
setRand(rrr);
}
else{
if(nb_intersect % 2 == 1){
// odd nb of intersections: the normal points inside the region
for(unsigned int i = 0; i < gf->triangles.size(); i++){
gf->triangles[i]->reverse();
}
}
++it;
}
}
// FILE *fp = Fopen("debug.pos", "w");
// fprintf(fp, "View \"debug\" {\n");
// for(std::list<GFace*>::iterator it = faces.begin(); it != faces.end(); it++)
// for(unsigned int i = 0; i < (*it)->triangles.size(); i++)
// (*it)->triangles[i]->writePOS(fp, 1., (*it)->tag());
// fprintf(fp, "};\n");
// fclose(fp);
}
void meshGRegion::operator() (GRegion *gr)
{
gr->model()->setCurrentMeshEntity(gr);
if(gr->geomType() == GEntity::DiscreteVolume) return;
if(gr->meshAttributes.method == MESH_NONE) return;
if(CTX::instance()->mesh.meshOnlyVisible && !gr->getVisibility()) return;
ExtrudeParams *ep = gr->meshAttributes.extrude;
if(ep && ep->mesh.ExtrudeMesh) return;
// destroy the mesh if it exists
deMeshGRegion dem;
dem(gr);
if(MeshTransfiniteVolume(gr)) return;
std::list<GFace*> faces = gr->faces();
// sanity check for frontal algo
if(CTX::instance()->mesh.algo3d == ALGO_3D_FRONTAL){
for(std::list<GFace*>::iterator it = faces.begin(); it != faces.end(); it++){
if((*it)->quadrangles.size()){
Msg::Error("Cannot use frontal 3D algorithm with quadrangles on boundary");
return;
}
}
}
// replace discreteFaces by their compounds
{
std::set<GFace*> mySet;
std::list<GFace*>::iterator it = faces.begin();
while(it != faces.end()){
if((*it)->getCompound())
mySet.insert((*it)->getCompound());
else
mySet.insert(*it);
++it;
}
faces.clear();
faces.insert(faces.begin(), mySet.begin(), mySet.end());
gr->set(faces);
}
if(CTX::instance()->mesh.algo3d != ALGO_3D_FRONTAL){
delaunay.push_back(gr);
}
else if(CTX::instance()->mesh.algo3d == ALGO_3D_FRONTAL){
#if !defined(HAVE_NETGEN)
Msg::Error("Netgen is not compiled in this version of Gmsh");
#else
Msg::Info("Meshing volume %d (Frontal)", gr->tag());
// orient the triangles of with respect to this region
meshNormalsPointOutOfTheRegion(gr);
std::vector<MVertex*> numberedV;
Ng_Mesh *ngmesh = buildNetgenStructure(gr, false, numberedV);
Ng_GenerateVolumeMesh(ngmesh, CTX::instance()->mesh.lcMax);
TransferVolumeMesh(gr, ngmesh, numberedV);
Ng_DeleteMesh(ngmesh);
Ng_Exit();
#endif
}
}
void optimizeMeshGRegionNetgen::operator() (GRegion *gr)
{
gr->model()->setCurrentMeshEntity(gr);
if(gr->geomType() == GEntity::DiscreteVolume) return;
// don't optimize transfinite or extruded meshes
if(gr->meshAttributes.method == MESH_TRANSFINITE) return;
ExtrudeParams *ep = gr->meshAttributes.extrude;
if(ep && ep->mesh.ExtrudeMesh && ep->geo.Mode == EXTRUDED_ENTITY) return;
#if !defined(HAVE_NETGEN)
Msg::Error("Netgen is not compiled in this version of Gmsh");
#else
Msg::Info("Optimizing volume %d", gr->tag());
// import mesh into netgen, including volume tets
std::vector<MVertex*> numberedV;
Ng_Mesh *ngmesh = buildNetgenStructure(gr, true, numberedV);
// delete volume vertices and tets
deMeshGRegion dem;
dem(gr);
// optimize mesh
Ng_OptimizeVolumeMesh(ngmesh, CTX::instance()->mesh.lcMax);
TransferVolumeMesh(gr, ngmesh, numberedV);
Ng_DeleteMesh(ngmesh);
Ng_Exit();
#endif
}
void optimizeMeshGRegionGmsh::operator() (GRegion *gr)
{
gr->model()->setCurrentMeshEntity(gr);
if(gr->geomType() == GEntity::DiscreteVolume) return;
// don't optimize extruded meshes
if(gr->meshAttributes.method == MESH_TRANSFINITE) return;
ExtrudeParams *ep = gr->meshAttributes.extrude;
if(ep && ep->mesh.ExtrudeMesh && ep->geo.Mode == EXTRUDED_ENTITY) return;
Msg::Info("Optimizing volume %d", gr->tag());
optimizeMesh(gr, QMTET_2);
}
bool buildFaceSearchStructure(GModel *model, fs_cont &search)
{
search.clear();
std::set<GFace*> faces_to_consider;
GModel::riter rit = model->firstRegion();
while(rit != model->lastRegion()){
std::list <GFace *> _faces = (*rit)->faces();
faces_to_consider.insert( _faces.begin(),_faces.end());
rit++;
}
std::set<GFace*>::iterator fit = faces_to_consider.begin();
while(fit != faces_to_consider.end()){
for(unsigned int i = 0; i < (*fit)->getNumMeshElements(); i++){
MFace ff = (*fit)->getMeshElement(i)->getFace(0);
search[ff] = *fit;
}
++fit;
}
return true;
}
bool buildEdgeSearchStructure(GModel *model, es_cont &search)
{
search.clear();
GModel::eiter eit = model->firstEdge();
while(eit != model->lastEdge()){
for(unsigned int i = 0; i < (*eit)->lines.size(); i++){
MVertex *p1 = (*eit)->lines[i]->getVertex(0);
MVertex *p2 = (*eit)->lines[i]->getVertex(1);
MVertex *p = std::min(p1, p2);
search.insert(std::pair<MVertex*, std::pair<MLine*, GEdge*> >
(p, std::pair<MLine*, GEdge*>((*eit)->lines[i], *eit)));
}
++eit;
}
return true;
}
GFace *findInFaceSearchStructure(MVertex *p1, MVertex *p2, MVertex *p3,
const fs_cont &search)
{
MFace ff(p1,p2,p3);
fs_cont::const_iterator it = search.find(ff);
if (it == search.end())return 0;
return it->second;
}
GFace *findInFaceSearchStructure(const MFace &ff,
const fs_cont &search)
{
fs_cont::const_iterator it = search.find(ff);
if (it == search.end())return 0;
return it->second;
}
GEdge *findInEdgeSearchStructure(MVertex *p1, MVertex *p2, const es_cont &search)
{
MVertex *p = std::min(p1, p2);
for(es_cont::const_iterator it = search.lower_bound(p);
it != search.upper_bound(p);
++it){
MLine *l = it->second.first;
GEdge *ge = it->second.second;
if((l->getVertex(0) == p1 || l->getVertex(0) == p2) &&
(l->getVertex(1) == p1 || l->getVertex(1) == p2))
return ge;
}
return 0;
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment