From eb326ae9e563ab27f5fc98f330622b0932cacca1 Mon Sep 17 00:00:00 2001 From: Paul-Emile Bernard <paul-emile.bernard@uclouvain.be> Date: Fri, 20 Mar 2015 11:03:57 +0000 Subject: [PATCH] New implementation of bulk points insertion for hexa... with new background mesh. Previous version still used... --- Mesh/BGMBase.cpp | 286 + Mesh/BGMBase.h | 99 + Mesh/BackgroundMesh.cpp | 760 +- Mesh/BackgroundMesh.h | 30 +- Mesh/BackgroundMesh2D.cpp | 812 +++ Mesh/BackgroundMesh2D.h | 142 + Mesh/BackgroundMesh3D.cpp | 1182 +++ Mesh/BackgroundMesh3D.h | 176 + Mesh/BackgroundMeshManager.cpp | 72 + Mesh/BackgroundMeshManager.h | 34 + Mesh/BackgroundMeshTools.cpp | 450 ++ Mesh/BackgroundMeshTools.h | 35 + Mesh/CMakeLists.txt | 7 + Mesh/CenterlineField.cpp | 2 +- Mesh/DivideAndConquer.cpp | 2 +- Mesh/Field.cpp | 43 +- Mesh/Field.h | 24 + Mesh/Generator.cpp | 135 +- Mesh/meshGEdge.cpp | 2 +- Mesh/meshGFaceBamg.cpp | 2 +- Mesh/meshGFaceDelaunayInsertion.cpp | 809 ++- Mesh/meshGFaceElliptic.cpp | 2 +- Mesh/meshGFaceOptimize.cpp | 75 +- Mesh/meshGRegion.cpp | 22 +- Mesh/meshGRegionDelaunayInsertion.cpp | 8 +- Mesh/meshGRegionDelaunayInsertion.h | 2 +- Mesh/meshGRegionMMG3D.cpp | 2 +- Mesh/meshRecombine2D_2.cpp | 2 +- Mesh/pointInsertion.cpp | 850 +++ Mesh/pointInsertion.h | 82 + Mesh/pointInsertionRTreeTools.cpp | 245 + Mesh/pointInsertionRTreeTools.h | 387 + Mesh/simple3D.cpp | 2 + Mesh/simple3D.h | 8 + Mesh/surfaceFiller.cpp | 444 +- Mesh/surfaceFiller.h | 6 + Mesh/yamakawa.cpp | 9480 ++++++++++++++++--------- Mesh/yamakawa.h | 890 ++- 38 files changed, 12990 insertions(+), 4621 deletions(-) create mode 100644 Mesh/BGMBase.cpp create mode 100644 Mesh/BGMBase.h create mode 100644 Mesh/BackgroundMesh2D.cpp create mode 100644 Mesh/BackgroundMesh2D.h create mode 100644 Mesh/BackgroundMesh3D.cpp create mode 100644 Mesh/BackgroundMesh3D.h create mode 100644 Mesh/BackgroundMeshManager.cpp create mode 100644 Mesh/BackgroundMeshManager.h create mode 100644 Mesh/BackgroundMeshTools.cpp create mode 100644 Mesh/BackgroundMeshTools.h create mode 100644 Mesh/pointInsertion.cpp create mode 100644 Mesh/pointInsertion.h create mode 100644 Mesh/pointInsertionRTreeTools.cpp create mode 100644 Mesh/pointInsertionRTreeTools.h diff --git a/Mesh/BGMBase.cpp b/Mesh/BGMBase.cpp new file mode 100644 index 0000000000..385ea364e0 --- /dev/null +++ b/Mesh/BGMBase.cpp @@ -0,0 +1,286 @@ +#include "BGMBase.h" + +#include <iostream> + +#include "OS.h" +#include "GPoint.h" +#include "GFace.h" +#include "GmshDefines.h" +#include "MElementOctree.h" + +void BGMBase::export_scalar(const string &filename, const DoubleStorageType &_whatToPrint) const{ +// cout << "BGMBase::size of sizeField: " << sizeField.size() << endl; + FILE *f = Fopen (filename.c_str(),"w"); + fprintf(f,"View \"Background Mesh\"{\n"); + + const MElement *elem; + int nvertex; + int type; + + for(unsigned int i=0;i<getNumMeshElements();i++){ + elem = getElement(i); + nvertex = elem->getNumVertices(); + type = elem->getType(); + const char *s = 0; + switch(type){ + case TYPE_PNT: s = "SP"; break; + case TYPE_LIN: s = "SL"; break; + case TYPE_TRI: s = "ST"; break; + case TYPE_QUA: s = "SQ"; break; + case TYPE_TET: s = "SS"; break; + case TYPE_HEX: s = "SH"; break; + case TYPE_PRI: s = "SI"; break; + case TYPE_PYR: s = "SY"; break; + default: throw; + } + + fprintf(f,"%s(",s); + const MVertex *v; + vector<double> values(nvertex); + for (int iv=0;iv<nvertex;iv++){ + v = elem->getVertex(iv); + values[iv] = get_nodal_value(v,_whatToPrint); + //GPoint p = gf->point(SPoint2(v->x(),v->y())); + GPoint p = get_GPoint_from_MVertex(v); + fprintf(f,"%g,%g,%g",p.x(),p.y(),p.z()); + if (iv!=nvertex-1) fprintf(f,","); + else fprintf(f,"){"); + } + for (int iv=0;iv<nvertex;iv++){ + fprintf(f,"%g",values[iv]); + if (iv!=nvertex-1) fprintf(f,","); + else fprintf(f,"};\n"); + } + } + fprintf(f,"};\n"); + fclose(f); +// cout << "export_scalar DONE " << endl; +} + +//------------------------------------------------------------------------ + +void BGMBase::export_vector(const string &filename, const VectorStorageType &_whatToPrint)const{ + FILE *f = Fopen (filename.c_str(),"w"); + fprintf(f,"View \"Background Mesh\"{\n"); + + const MElement *elem; + int nvertex; + int type; + + for(unsigned int i=0;i<getNumMeshElements();i++){ + elem = getElement(i); + nvertex = elem->getNumVertices(); + type = elem->getType(); + const char *s = 0; + switch(type){ + case TYPE_PNT: s = "VP"; break; + case TYPE_LIN: s = "VL"; break; + case TYPE_TRI: s = "VT"; break; + case TYPE_QUA: s = "VQ"; break; + case TYPE_TET: s = "VS"; break; + case TYPE_HEX: s = "VH"; break; + case TYPE_PRI: s = "VI"; break; + case TYPE_PYR: s = "VY"; break; + default: throw; + } + + fprintf(f,"%s(",s); + const MVertex *v; + vector<double> values(nvertex*3); + for (int iv=0;iv<nvertex;iv++){ + v = elem->getVertex(iv); + vector<double> temp = get_nodal_value(v,_whatToPrint); + for (int j=0;j<3;j++) + values[iv*3+j] = temp[j]; + GPoint p = get_GPoint_from_MVertex(v); + fprintf(f,"%g,%g,%g",p.x(),p.y(),p.z()); + if (iv!=nvertex-1) fprintf(f,","); + else fprintf(f,"){"); + } + for (int iv=0;iv<nvertex;iv++){ + for (int j=0;j<3;j++){ + fprintf(f,"%g",values[iv*3+j]); + if (!((iv==nvertex-1)&&(j==2))) fprintf(f,","); + else fprintf(f,"};\n"); + } + } + } + fprintf(f,"};\n"); + fclose(f); +} + +//------------------------------------------------------------------------ + +void BGMBase::export_tensor_as_vectors(const string &filename, const TensorStorageType &_whatToPrint)const{ + FILE *f = Fopen (filename.c_str(),"w"); + fprintf(f,"View \"Background Mesh\"{\n"); + + TensorStorageType::const_iterator it = _whatToPrint.begin(); + const char *s = "VP"; + MVertex *v; + for (;it!=_whatToPrint.end();it++){// for all vertices + v = it->first; + GPoint p = get_GPoint_from_MVertex(v); + for (int i=0;i<3;i++){ + fprintf(f,"%s(%g,%g,%g){%g,%g,%g};\n",s,p.x(),p.y(),p.z(),(it->second)(0,i),(it->second)(1,i),(it->second)(2,i)); + fprintf(f,"%s(%g,%g,%g){%g,%g,%g};\n",s,p.x(),p.y(),p.z(),-(it->second)(0,i),-(it->second)(1,i),-(it->second)(2,i)); + } + } + fprintf(f,"};\n"); + fclose(f); +} + +//------------------------------------------------------------------------ + +BGMBase::BGMBase(int dim,GEntity *_gf):octree(NULL),gf(_gf), DIM(dim), order(1),debug(false){ + if(debug) cout << "BGMBase::constructor " << endl; +} + +//------------------------------------------------------------------------ + +BGMBase::~BGMBase(){ +} + +//------------------------------------------------------------------------ + +bool BGMBase::inDomain (double u, double v, double w){ + return (findElement(u, v, w) != NULL); +} + +//------------------------------------------------------------------------ + +const MElement* BGMBase::findElement(double u, double v, double w, bool strict){ + return (getOctree()->find(u, v, w, DIM, strict)); +} + +//------------------------------------------------------------------------ + +vector<double> BGMBase::get_field_value(double u, double v, double w, const VectorStorageType &data){ + MElement *e = const_cast<MElement*>(findElement(u, v, w )); + if (!e) return vector<double>(3,-1000.); + vector<vector<double> > val = get_nodal_values(e,data); + vector<double> element_uvw = get_element_uvw_from_xyz(e,u,v,w); + + vector<double> res(3); + for (int j=0;j<3;j++){ + double values[e->getNumVertices()]; + for (int i=0;i<e->getNumVertices();i++) values[i]=val[i][j]; + res[j] = e->interpolate(values, element_uvw[0], element_uvw[1], element_uvw[2], 1, order); + } + return res; +} + +//------------------------------------------------------------------------ + +double BGMBase::get_field_value(double u, double v, double w, const DoubleStorageType &data){ + MElement *e = const_cast<MElement*>(findElement(u, v, w)); + if (!e) return -1000.; + vector<double> val = get_nodal_values(e,data); + vector<double> element_uvw = get_element_uvw_from_xyz(e,u,v,w); + double values[e->getNumVertices()]; + for (int i=0;i<e->getNumVertices();i++) + values[i]=val[i]; + + return e->interpolate(values, element_uvw[0], element_uvw[1], element_uvw[2], 1, order); +} + +//------------------------------------------------------------------------ + +double BGMBase::size(double u, double v, double w){ + return get_field_value(u,v,w,sizeField); +} + +//------------------------------------------------------------------------ + +double BGMBase::size(const MVertex *v){ + return get_nodal_value(v,sizeField); +} + +//------------------------------------------------------------------------ + +vector<double> BGMBase::get_nodal_value(const MVertex *v,const VectorStorageType &data)const{ + if(debug) cout << "BGMBase::get_nodal_value(const MVertex *v,const map<MVertex*,vector<double> > &data)" << endl; + VectorStorageType::const_iterator itfind = data.find(const_cast<MVertex*>(v)); + if (itfind==data.end()){ + cout << "WARNING: BGMBase::get_nodal_value (vector): unknown vertex ! " << v << endl; + throw; + return vector<double>(3,0.); + } + return itfind->second; +} + +//------------------------------------------------------------------------ + +double BGMBase::get_nodal_value(const MVertex *v,const DoubleStorageType &data)const{ + if(debug) cout << "BGMBase::get_nodal_value(const MVertex *v,const map<MVertex*,double> &data)" << endl; + DoubleStorageType::const_iterator itfind = data.find(const_cast<MVertex*>(v)); + if (itfind==data.end()){ + cout << "WARNING: BGMBase::get_nodal_value: unknown vertex ! " << endl; + throw; + return 0.; + } + return itfind->second; +} + +//------------------------------------------------------------------------ + +vector<vector<double> > BGMBase::get_nodal_values(const MElement *e,const VectorStorageType &data)const{ + if(debug) cout << "BGMBase::get_nodal_values(const MElement *e,const tr1::unordered_map<MVertex*,vector<double> > &data)" << endl; + vector<vector<double> > res(e->getNumVertices()); + + for (int i=0;i<e->getNumVertices();i++){ + VectorStorageType::const_iterator itfind = data.find(const_cast<MVertex*>(e->getVertex(i))); + for (int j=0;j<3;j++) + res[i].push_back((itfind->second)[j]); + } + return res; +} + +//------------------------------------------------------------------------ + +vector<double> BGMBase::get_nodal_values(const MElement *e,const DoubleStorageType &data)const{ + if(debug) cout << "BGMBase::get_nodal_values(const MElement *e,const tr1::unordered_map<MVertex*,double> &data)" << endl; + vector<double> res(e->getNumVertices(),0.); + + for (int i=0;i<e->getNumVertices();i++) + res[i] = (data.find(const_cast<MVertex*>(e->getVertex(i))))->second; + return res; +} + +//------------------------------------------------------------------------ + +vector<double> BGMBase::get_element_uvw_from_xyz (const MElement *e, double x, double y,double z) const{ + double element_uvw[3]; + double xyz[3] = {x, y, z}; + e->xyz2uvw(xyz, element_uvw); + vector<double> res(3,0.); + for (int i=0;i<3;i++) { + res[i] = element_uvw[i]; + } + return res; +} + +//------------------------------------------------------------------------ + +set<MVertex*> BGMBase::get_vertices_of_maximum_dim(int dim){ + set<MVertex*> bnd_vertices; + for(unsigned int i=0;i<gf->getNumMeshElements();i++){ + MElement* element = gf->getMeshElement(i); + for(int j=0;j<element->getNumVertices();j++){ + MVertex *vertex = element->getVertex(j); + if (vertex->onWhat()->dim() <= dim)bnd_vertices.insert(vertex); + } + } + return bnd_vertices; +} + +//------------------------------------------------------------------------ + +GEntity* BGMBase::getBackgroundGEntity(){ + return gf; +} + +//------------------------------------------------------------------------ + + + diff --git a/Mesh/BGMBase.h b/Mesh/BGMBase.h new file mode 100644 index 0000000000..bcbd8b9308 --- /dev/null +++ b/Mesh/BGMBase.h @@ -0,0 +1,99 @@ +// 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@geuz.org>. + +#ifndef _BACKGROUND_MESH_BASE_H_ +#define _BACKGROUND_MESH_BASE_H_ + + +#include <string> +#include <map> +#include <vector> +#include <set> +#include "STensor3.h" + +#include "MElement.h" +#include "simpleFunction.h" + +#include <tr1/unordered_map> +#include <tr1/unordered_set> + + +class MElementOctree; +class GFace; +class GRegion; +class GVertex; +class GEdge; +class GPoint; +class MElement; +class MVertex; +class GEntity; + +using namespace std; + +class BGMBase{ + public: + typedef MVertex* hash_key_ptr; + typedef tr1::unordered_map<hash_key_ptr, STensor3 > TensorStorageType; + typedef tr1::unordered_map<hash_key_ptr, double > DoubleStorageType; + typedef tr1::unordered_map<hash_key_ptr, vector<double> > VectorStorageType; + + protected: + mutable MElementOctree *octree; + GEntity *gf; + + + DoubleStorageType sizeField; // an attached size field + + + int DIM,order; + + virtual void export_scalar(const string &filename, const DoubleStorageType&) const; + virtual void export_vector(const string &filename, const VectorStorageType&) const; + virtual void export_tensor_as_vectors(const string &filename, const TensorStorageType &_whatToPrint)const; + + virtual void propagateValues(DoubleStorageType &dirichlet, simpleFunction<double> &eval_diffusivity, bool in_parametric_plane = false)=0; + virtual void computeSizeField()=0; + virtual GPoint get_GPoint_from_MVertex(const MVertex *) const=0; + virtual const MElement* getElement(unsigned int i)const=0; + virtual unsigned int getNumMeshElements()const=0; + + virtual vector<double> get_nodal_values(const MElement *e,const DoubleStorageType &data)const; + virtual vector<vector<double> > get_nodal_values(const MElement *e,const VectorStorageType &data)const; + + virtual vector<double> get_nodal_value(const MVertex *v,const VectorStorageType &data)const; + virtual double get_nodal_value(const MVertex *v,const DoubleStorageType &data)const; + + virtual vector<double> get_element_uvw_from_xyz (const MElement *e, double x, double y,double z) const; + + virtual double get_field_value(double u, double v, double w, const DoubleStorageType &data); + virtual vector<double> get_field_value(double u, double v, double w, const VectorStorageType &data); + + + public: + BGMBase(int dim,GEntity *_gf); + ~BGMBase(); + + virtual MElementOctree* getOctree()=0; + + const bool debug; + + virtual GEntity* getBackgroundGEntity(); + + virtual double size(double u, double v, double w=0.);// get the size field, element interpolation + virtual double size(const MVertex *v);// get the nodal size field + + virtual bool inDomain (double u, double v, double w=0.); + + virtual inline void exportSizeField(const string &filename) const{export_scalar(filename,sizeField);}; + + // warning: these are "3D", "real" vertices, not copies in a parametric domain + virtual set<MVertex*> get_vertices_of_maximum_dim(int dim); + virtual const MElement* findElement(double u, double v, double w=0.,bool strict=true); + +}; + +//------------------------------------------------------------------------ + +#endif diff --git a/Mesh/BackgroundMesh.cpp b/Mesh/BackgroundMesh.cpp index f4c4a3daee..00f7dbbea4 100644 --- a/Mesh/BackgroundMesh.cpp +++ b/Mesh/BackgroundMesh.cpp @@ -40,117 +40,117 @@ static int _NBANN = 2; #endif -SMetric3 buildMetricTangentToCurve(SVector3 &t, double l_t, double l_n) -{ - if (l_t == 0.0) return SMetric3(1.e-22); - SVector3 a; - if (fabs(t(0)) <= fabs(t(1)) && fabs(t(0)) <= fabs(t(2))){ - a = SVector3(1,0,0); - } - else if (fabs(t(1)) <= fabs(t(0)) && fabs(t(1)) <= fabs(t(2))){ - a = SVector3(0,1,0); - } - else{ - a = SVector3(0,0,1); - } - SVector3 b = crossprod (t,a); - SVector3 c = crossprod (b,t); - b.normalize(); - c.normalize(); - t.normalize(); - SMetric3 Metric (1./(l_t*l_t),1./(l_n*l_n),1./(l_n*l_n),t,b,c); - // printf("bmttc %g %g %g %g %g\n",l_t,l_n,Metric(0,0),Metric(0,1),Metric(1,1)); - return Metric; -} - -SMetric3 buildMetricTangentToSurface(SVector3 &t1, SVector3 &t2, - double l_t1, double l_t2, double l_n) -{ - t1.normalize(); - t2.normalize(); - SVector3 n = crossprod (t1,t2); - n.normalize(); - - l_t1 = std::max(l_t1, CTX::instance()->mesh.lcMin); - l_t2 = std::max(l_t2, CTX::instance()->mesh.lcMin); - l_t1 = std::min(l_t1, CTX::instance()->mesh.lcMax); - l_t2 = std::min(l_t2, CTX::instance()->mesh.lcMax); - SMetric3 Metric (1./(l_t1*l_t1),1./(l_t2*l_t2),1./(l_n*l_n),t1,t2,n); - return Metric; -} - -SMetric3 max_edge_curvature_metric(const GVertex *gv) -{ - SMetric3 val (1.e-12); - std::list<GEdge*> l_edges = gv->edges(); - for (std::list<GEdge*>::const_iterator ite = l_edges.begin(); - ite != l_edges.end(); ++ite){ - GEdge *_myGEdge = *ite; - Range<double> range = _myGEdge->parBounds(0); - SMetric3 cc; - if (gv == _myGEdge->getBeginVertex()) { - SVector3 t = _myGEdge->firstDer(range.low()); - t.normalize(); - double l_t = ((2 * M_PI) /( fabs(_myGEdge->curvature(range.low())) - * CTX::instance()->mesh.minCircPoints )); - double l_n = 1.e12; - cc = buildMetricTangentToCurve(t,l_t,l_n); - } - else { - SVector3 t = _myGEdge->firstDer(range.high()); - t.normalize(); - double l_t = ((2 * M_PI) /( fabs(_myGEdge->curvature(range.high())) - * CTX::instance()->mesh.minCircPoints )); - double l_n = 1.e12; - cc = buildMetricTangentToCurve(t,l_t,l_n); - } - val = intersection(val,cc); - } - return val; -} - -SMetric3 max_edge_curvature_metric(const GEdge *ge, double u) -{ - SVector3 t = ge->firstDer(u); - t.normalize(); - double l_t = ((2 * M_PI) /( fabs(ge->curvature(u)) - * CTX::instance()->mesh.minCircPoints )); - double l_n = 1.e12; - return buildMetricTangentToCurve(t,l_t,l_n); -} - -static double max_edge_curvature(const GVertex *gv) -{ - double val = 0; - std::list<GEdge*> l_edges = gv->edges(); - for (std::list<GEdge*>::const_iterator ite = l_edges.begin(); - ite != l_edges.end(); ++ite){ - GEdge *_myGEdge = *ite; - Range<double> range = _myGEdge->parBounds(0); - double cc; - if (gv == _myGEdge->getBeginVertex()) cc = _myGEdge->curvature(range.low()); - else cc = _myGEdge->curvature(range.high()); - val = std::max(val, cc); - } - return val; -} - -static double max_surf_curvature(const GEdge *ge, double u) -{ - double val = 0; - std::list<GFace *> faces = ge->faces(); - std::list<GFace *>::iterator it = faces.begin(); - while(it != faces.end()){ - if ((*it)->geomType() != GEntity::CompoundSurface && - (*it)->geomType() != GEntity::DiscreteSurface){ - SPoint2 par = ge->reparamOnFace((*it), u, 1); - double cc = (*it)->curvature(par); - val = std::max(cc, val); - } - ++it; - } - return val; -} +//SMetric3 buildMetricTangentToCurve(SVector3 &t, double l_t, double l_n) +//{ +// if (l_t == 0.0) return SMetric3(1.e-22); +// SVector3 a; +// if (fabs(t(0)) <= fabs(t(1)) && fabs(t(0)) <= fabs(t(2))){ +// a = SVector3(1,0,0); +// } +// else if (fabs(t(1)) <= fabs(t(0)) && fabs(t(1)) <= fabs(t(2))){ +// a = SVector3(0,1,0); +// } +// else{ +// a = SVector3(0,0,1); +// } +// SVector3 b = crossprod (t,a); +// SVector3 c = crossprod (b,t); +// b.normalize(); +// c.normalize(); +// t.normalize(); +// SMetric3 Metric (1./(l_t*l_t),1./(l_n*l_n),1./(l_n*l_n),t,b,c); +// // printf("bmttc %g %g %g %g %g\n",l_t,l_n,Metric(0,0),Metric(0,1),Metric(1,1)); +// return Metric; +//} + +//SMetric3 buildMetricTangentToSurface(SVector3 &t1, SVector3 &t2, +// double l_t1, double l_t2, double l_n) +//{ +// t1.normalize(); +// t2.normalize(); +// SVector3 n = crossprod (t1,t2); +// n.normalize(); +// +// l_t1 = std::max(l_t1, CTX::instance()->mesh.lcMin); +// l_t2 = std::max(l_t2, CTX::instance()->mesh.lcMin); +// l_t1 = std::min(l_t1, CTX::instance()->mesh.lcMax); +// l_t2 = std::min(l_t2, CTX::instance()->mesh.lcMax); +// SMetric3 Metric (1./(l_t1*l_t1),1./(l_t2*l_t2),1./(l_n*l_n),t1,t2,n); +// return Metric; +//} + +//SMetric3 max_edge_curvature_metric(const GVertex *gv) +//{ +// SMetric3 val (1.e-12); +// std::list<GEdge*> l_edges = gv->edges(); +// for (std::list<GEdge*>::const_iterator ite = l_edges.begin(); +// ite != l_edges.end(); ++ite){ +// GEdge *_myGEdge = *ite; +// Range<double> range = _myGEdge->parBounds(0); +// SMetric3 cc; +// if (gv == _myGEdge->getBeginVertex()) { +// SVector3 t = _myGEdge->firstDer(range.low()); +// t.normalize(); +// double l_t = ((2 * M_PI) /( fabs(_myGEdge->curvature(range.low())) +// * CTX::instance()->mesh.minCircPoints )); +// double l_n = 1.e12; +// cc = buildMetricTangentToCurve(t,l_t,l_n); +// } +// else { +// SVector3 t = _myGEdge->firstDer(range.high()); +// t.normalize(); +// double l_t = ((2 * M_PI) /( fabs(_myGEdge->curvature(range.high())) +// * CTX::instance()->mesh.minCircPoints )); +// double l_n = 1.e12; +// cc = buildMetricTangentToCurve(t,l_t,l_n); +// } +// val = intersection(val,cc); +// } +// return val; +//} + +//SMetric3 max_edge_curvature_metric(const GEdge *ge, double u) +//{ +// SVector3 t = ge->firstDer(u); +// t.normalize(); +// double l_t = ((2 * M_PI) /( fabs(ge->curvature(u)) +// * CTX::instance()->mesh.minCircPoints )); +// double l_n = 1.e12; +// return buildMetricTangentToCurve(t,l_t,l_n); +//} + +//static double max_edge_curvature(const GVertex *gv) +//{ +// double val = 0; +// std::list<GEdge*> l_edges = gv->edges(); +// for (std::list<GEdge*>::const_iterator ite = l_edges.begin(); +// ite != l_edges.end(); ++ite){ +// GEdge *_myGEdge = *ite; +// Range<double> range = _myGEdge->parBounds(0); +// double cc; +// if (gv == _myGEdge->getBeginVertex()) cc = _myGEdge->curvature(range.low()); +// else cc = _myGEdge->curvature(range.high()); +// val = std::max(val, cc); +// } +// return val; +//} +// +//static double max_surf_curvature(const GEdge *ge, double u) +//{ +// double val = 0; +// std::list<GFace *> faces = ge->faces(); +// std::list<GFace *>::iterator it = faces.begin(); +// while(it != faces.end()){ +// if ((*it)->geomType() != GEntity::CompoundSurface && +// (*it)->geomType() != GEntity::DiscreteSurface){ +// SPoint2 par = ge->reparamOnFace((*it), u, 1); +// double cc = (*it)->curvature(par); +// val = std::max(cc, val); +// } +// ++it; +// } +// return val; +//} // static double max_surf_curvature_vertex(const GVertex *gv) @@ -170,108 +170,108 @@ static double max_surf_curvature(const GEdge *ge, double u) // } -SMetric3 metric_based_on_surface_curvature(const GFace *gf, double u, double v, - bool surface_isotropic, - double d_normal , - double d_tangent_max) -{ - if (gf->geomType() == GEntity::Plane)return SMetric3(1.e-12); - double cmax, cmin; - SVector3 dirMax,dirMin; - cmax = gf->curvatures(SPoint2(u, v),&dirMax, &dirMin, &cmax,&cmin); - if (cmin == 0)cmin =1.e-12; - if (cmax == 0)cmax =1.e-12; - double lambda1 = ((2 * M_PI) /( fabs(cmin) * CTX::instance()->mesh.minCircPoints ) ); - double lambda2 = ((2 * M_PI) /( fabs(cmax) * CTX::instance()->mesh.minCircPoints ) ); - SVector3 Z = crossprod(dirMax,dirMin); - if (surface_isotropic) lambda2 = lambda1 = std::min(lambda2,lambda1); - dirMin.normalize(); - dirMax.normalize(); - Z.normalize(); - lambda1 = std::max(lambda1, CTX::instance()->mesh.lcMin); - lambda2 = std::max(lambda2, CTX::instance()->mesh.lcMin); - lambda1 = std::min(lambda1, CTX::instance()->mesh.lcMax); - lambda2 = std::min(lambda2, CTX::instance()->mesh.lcMax); - double lambda3 = std::min(d_normal, CTX::instance()->mesh.lcMax); - lambda3 = std::max(lambda3, CTX::instance()->mesh.lcMin); - lambda1 = std::min(lambda1, d_tangent_max); - lambda2 = std::min(lambda2, d_tangent_max); - - SMetric3 curvMetric (1./(lambda1*lambda1),1./(lambda2*lambda2), - 1./(lambda3*lambda3), - dirMin, dirMax, Z ); - return curvMetric; -} - -static SMetric3 metric_based_on_surface_curvature(const GEdge *ge, double u, bool iso_surf) -{ - const GEdgeCompound* ptrCompoundEdge = dynamic_cast<const GEdgeCompound*>(ge); - if (ptrCompoundEdge){ - double cmax, cmin; - SVector3 dirMax,dirMin; - cmax = ptrCompoundEdge->curvatures(u,&dirMax, &dirMin, &cmax,&cmin); - if (cmin == 0)cmin =1.e-12; - if (cmax == 0)cmax =1.e-12; - double lambda2 = ((2 * M_PI) /( fabs(cmax) * CTX::instance()->mesh.minCircPoints ) ); - double lambda1 = ((2 * M_PI) /( fabs(cmin) * CTX::instance()->mesh.minCircPoints ) ); - SVector3 Z = crossprod(dirMax,dirMin); - - lambda1 = std::max(lambda1, CTX::instance()->mesh.lcMin); - lambda2 = std::max(lambda2, CTX::instance()->mesh.lcMin); - lambda1 = std::min(lambda1, CTX::instance()->mesh.lcMax); - lambda2 = std::min(lambda2, CTX::instance()->mesh.lcMax); - - SMetric3 curvMetric (1. / (lambda1 * lambda1), 1. / (lambda2 * lambda2), - 1.e-12, dirMin, dirMax, Z); - return curvMetric; - } - else{ - SMetric3 mesh_size(1.e-12); - std::list<GFace *> faces = ge->faces(); - std::list<GFace *>::iterator it = faces.begin(); - // we choose the metric eigenvectors to be the ones - // related to the edge ... - SMetric3 curvMetric = max_edge_curvature_metric(ge, u); - while(it != faces.end()){ - if (((*it)->geomType() != GEntity::CompoundSurface) && - ((*it)->geomType() != GEntity::DiscreteSurface)){ - SPoint2 par = ge->reparamOnFace((*it), u, 1); - SMetric3 m = metric_based_on_surface_curvature (*it, par.x(), par.y(), iso_surf); - curvMetric = intersection_conserveM1(curvMetric,m); - } - ++it; - } - - return curvMetric; - } -} - -static SMetric3 metric_based_on_surface_curvature(const GVertex *gv, bool iso_surf) -{ - SMetric3 mesh_size(1.e-15); - std::list<GEdge*> l_edges = gv->edges(); - for (std::list<GEdge*>::const_iterator ite = l_edges.begin(); - ite != l_edges.end(); ++ite){ - GEdge *_myGEdge = *ite; - Range<double> bounds = _myGEdge->parBounds(0); - - // ES: Added extra if condition to use the code below only with compund curves - // This is because we want to call the function - // metric_based_on_surface_curvature(const GEdge *ge, double u) for the case when - // ge is a compound edge - if (_myGEdge->geomType() == GEntity::CompoundCurve){ - if (gv == _myGEdge->getBeginVertex()) - mesh_size = intersection - (mesh_size, - metric_based_on_surface_curvature(_myGEdge, bounds.low(), iso_surf)); - else - mesh_size = intersection - (mesh_size, - metric_based_on_surface_curvature(_myGEdge, bounds.high(), iso_surf)); - } - } - return mesh_size; -} +//SMetric3 metric_based_on_surface_curvature(const GFace *gf, double u, double v, +// bool surface_isotropic, +// double d_normal , +// double d_tangent_max) +//{ +// if (gf->geomType() == GEntity::Plane)return SMetric3(1.e-12); +// double cmax, cmin; +// SVector3 dirMax,dirMin; +// cmax = gf->curvatures(SPoint2(u, v),&dirMax, &dirMin, &cmax,&cmin); +// if (cmin == 0)cmin =1.e-12; +// if (cmax == 0)cmax =1.e-12; +// double lambda1 = ((2 * M_PI) /( fabs(cmin) * CTX::instance()->mesh.minCircPoints ) ); +// double lambda2 = ((2 * M_PI) /( fabs(cmax) * CTX::instance()->mesh.minCircPoints ) ); +// SVector3 Z = crossprod(dirMax,dirMin); +// if (surface_isotropic) lambda2 = lambda1 = std::min(lambda2,lambda1); +// dirMin.normalize(); +// dirMax.normalize(); +// Z.normalize(); +// lambda1 = std::max(lambda1, CTX::instance()->mesh.lcMin); +// lambda2 = std::max(lambda2, CTX::instance()->mesh.lcMin); +// lambda1 = std::min(lambda1, CTX::instance()->mesh.lcMax); +// lambda2 = std::min(lambda2, CTX::instance()->mesh.lcMax); +// double lambda3 = std::min(d_normal, CTX::instance()->mesh.lcMax); +// lambda3 = std::max(lambda3, CTX::instance()->mesh.lcMin); +// lambda1 = std::min(lambda1, d_tangent_max); +// lambda2 = std::min(lambda2, d_tangent_max); +// +// SMetric3 curvMetric (1./(lambda1*lambda1),1./(lambda2*lambda2), +// 1./(lambda3*lambda3), +// dirMin, dirMax, Z ); +// return curvMetric; +//} + +//static SMetric3 metric_based_on_surface_curvature(const GEdge *ge, double u, bool iso_surf) +//{ +// const GEdgeCompound* ptrCompoundEdge = dynamic_cast<const GEdgeCompound*>(ge); +// if (ptrCompoundEdge){ +// double cmax, cmin; +// SVector3 dirMax,dirMin; +// cmax = ptrCompoundEdge->curvatures(u,&dirMax, &dirMin, &cmax,&cmin); +// if (cmin == 0)cmin =1.e-12; +// if (cmax == 0)cmax =1.e-12; +// double lambda2 = ((2 * M_PI) /( fabs(cmax) * CTX::instance()->mesh.minCircPoints ) ); +// double lambda1 = ((2 * M_PI) /( fabs(cmin) * CTX::instance()->mesh.minCircPoints ) ); +// SVector3 Z = crossprod(dirMax,dirMin); +// +// lambda1 = std::max(lambda1, CTX::instance()->mesh.lcMin); +// lambda2 = std::max(lambda2, CTX::instance()->mesh.lcMin); +// lambda1 = std::min(lambda1, CTX::instance()->mesh.lcMax); +// lambda2 = std::min(lambda2, CTX::instance()->mesh.lcMax); +// +// SMetric3 curvMetric (1. / (lambda1 * lambda1), 1. / (lambda2 * lambda2), +// 1.e-12, dirMin, dirMax, Z); +// return curvMetric; +// } +// else{ +// SMetric3 mesh_size(1.e-12); +// std::list<GFace *> faces = ge->faces(); +// std::list<GFace *>::iterator it = faces.begin(); +// // we choose the metric eigenvectors to be the ones +// // related to the edge ... +// SMetric3 curvMetric = max_edge_curvature_metric(ge, u); +// while(it != faces.end()){ +// if (((*it)->geomType() != GEntity::CompoundSurface) && +// ((*it)->geomType() != GEntity::DiscreteSurface)){ +// SPoint2 par = ge->reparamOnFace((*it), u, 1); +// SMetric3 m = metric_based_on_surface_curvature (*it, par.x(), par.y(), iso_surf); +// curvMetric = intersection_conserveM1(curvMetric,m); +// } +// ++it; +// } +// +// return curvMetric; +// } +//} + +//static SMetric3 metric_based_on_surface_curvature(const GVertex *gv, bool iso_surf) +//{ +// SMetric3 mesh_size(1.e-15); +// std::list<GEdge*> l_edges = gv->edges(); +// for (std::list<GEdge*>::const_iterator ite = l_edges.begin(); +// ite != l_edges.end(); ++ite){ +// GEdge *_myGEdge = *ite; +// Range<double> bounds = _myGEdge->parBounds(0); +// +// // ES: Added extra if condition to use the code below only with compund curves +// // This is because we want to call the function +// // metric_based_on_surface_curvature(const GEdge *ge, double u) for the case when +// // ge is a compound edge +// if (_myGEdge->geomType() == GEntity::CompoundCurve){ +// if (gv == _myGEdge->getBeginVertex()) +// mesh_size = intersection +// (mesh_size, +// metric_based_on_surface_curvature(_myGEdge, bounds.low(), iso_surf)); +// else +// mesh_size = intersection +// (mesh_size, +// metric_based_on_surface_curvature(_myGEdge, bounds.high(), iso_surf)); +// } +// } +// return mesh_size; +//} // the mesh vertex is classified on a model vertex. we compute the // maximum of the curvature of model faces surrounding this point if @@ -279,180 +279,180 @@ static SMetric3 metric_based_on_surface_curvature(const GVertex *gv, bool iso_su // faces surrounding it if it is on a model face, we compute the // curvature at this location -static double LC_MVertex_CURV(GEntity *ge, double U, double V) -{ - double Crv = 0; - switch(ge->dim()){ - case 0: - Crv = max_edge_curvature((const GVertex *)ge); - //Crv = std::max(max_surf_curvature_vertex((const GVertex *)ge), Crv); - // Crv = max_surf_curvature((const GVertex *)ge); - break; - case 1: - { - GEdge *ged = (GEdge *)ge; - Crv = ged->curvature(U); - Crv = std::max(Crv, max_surf_curvature(ged, U)); - // Crv = max_surf_curvature(ged, U); - } - break; - case 2: - { - GFace *gf = (GFace *)ge; - Crv = gf->curvature(SPoint2(U, V)); - } - break; - } - double lc = Crv > 0 ? 2 * M_PI / Crv / CTX::instance()->mesh.minCircPoints : MAX_LC; - return lc; -} - -SMetric3 LC_MVertex_CURV_ANISO(GEntity *ge, double U, double V) -{ - bool iso_surf = CTX::instance()->mesh.lcFromCurvature == 2; - - switch(ge->dim()){ - case 0: return metric_based_on_surface_curvature((const GVertex *)ge, iso_surf); - case 1: return metric_based_on_surface_curvature((const GEdge *)ge, U, iso_surf); - case 2: return metric_based_on_surface_curvature((const GFace *)ge, U, V, iso_surf); - } - Msg::Error("Curvature control impossible to compute for a volume!"); - return SMetric3(); -} +//static double LC_MVertex_CURV(GEntity *ge, double U, double V) +//{ +// double Crv = 0; +// switch(ge->dim()){ +// case 0: +// Crv = max_edge_curvature((const GVertex *)ge); +// //Crv = std::max(max_surf_curvature_vertex((const GVertex *)ge), Crv); +// // Crv = max_surf_curvature((const GVertex *)ge); +// break; +// case 1: +// { +// GEdge *ged = (GEdge *)ge; +// Crv = ged->curvature(U); +// Crv = std::max(Crv, max_surf_curvature(ged, U)); +// // Crv = max_surf_curvature(ged, U); +// } +// break; +// case 2: +// { +// GFace *gf = (GFace *)ge; +// Crv = gf->curvature(SPoint2(U, V)); +// } +// break; +// } +// double lc = Crv > 0 ? 2 * M_PI / Crv / CTX::instance()->mesh.minCircPoints : MAX_LC; +// return lc; +//} + +//SMetric3 LC_MVertex_CURV_ANISO(GEntity *ge, double U, double V) +//{ +// bool iso_surf = CTX::instance()->mesh.lcFromCurvature == 2; +// +// switch(ge->dim()){ +// case 0: return metric_based_on_surface_curvature((const GVertex *)ge, iso_surf); +// case 1: return metric_based_on_surface_curvature((const GEdge *)ge, U, iso_surf); +// case 2: return metric_based_on_surface_curvature((const GFace *)ge, U, V, iso_surf); +// } +// Msg::Error("Curvature control impossible to compute for a volume!"); +// return SMetric3(); +//} // compute the mesh size at a given vertex due to prescribed sizes at // mesh vertices -static double LC_MVertex_PNTS(GEntity *ge, double U, double V) -{ - switch(ge->dim()){ - case 0: - { - GVertex *gv = (GVertex *)ge; - double lc = gv->prescribedMeshSizeAtVertex(); - // FIXME we might want to remove this to make all lc treatment consistent - if(lc >= MAX_LC) return CTX::instance()->lc / 10.; - return lc; - } - case 1: - { - GEdge *ged = (GEdge *)ge; - GVertex *v1 = ged->getBeginVertex(); - GVertex *v2 = ged->getEndVertex(); - if (v1 && v2){ - Range<double> range = ged->parBounds(0); - double a = (U - range.low()) / (range.high() - range.low()); - double lc = (1 - a) * v1->prescribedMeshSizeAtVertex() + - (a) * v2->prescribedMeshSizeAtVertex() ; - // FIXME we might want to remove this to make all lc treatment consistent - if(lc >= MAX_LC) return CTX::instance()->lc / 10.; - return lc; - } - else - return MAX_LC; - } - default: - return MAX_LC; - } -} - -// This is the only function that is used by the meshers -double BGM_MeshSize(GEntity *ge, double U, double V, - double X, double Y, double Z) -{ - // default lc (mesh size == size of the model) - double l1 = CTX::instance()->lc; - - // lc from points - double l2 = MAX_LC; - if(CTX::instance()->mesh.lcFromPoints && ge->dim() < 2) - l2 = LC_MVertex_PNTS(ge, U, V); - - // lc from curvature - double l3 = MAX_LC; - if(CTX::instance()->mesh.lcFromCurvature && ge->dim() < 3) - l3 = LC_MVertex_CURV(ge, U, V); - - // lc from fields - double l4 = MAX_LC; - FieldManager *fields = ge->model()->getFields(); - if(fields->getBackgroundField() > 0){ - Field *f = fields->get(fields->getBackgroundField()); - if(f) l4 = (*f)(X, Y, Z, ge); - } - - // take the minimum, then constrain by lcMin and lcMax - double lc = std::min(std::min(std::min(l1, l2), l3), l4); - lc = std::max(lc, CTX::instance()->mesh.lcMin); - lc = std::min(lc, CTX::instance()->mesh.lcMax); - - if(lc <= 0.){ - Msg::Error("Wrong mesh element size lc = %g (lcmin = %g, lcmax = %g)", - lc, CTX::instance()->mesh.lcMin, CTX::instance()->mesh.lcMax); - lc = l1; - } - - //Msg::Debug("BGM X,Y,Z=%g,%g,%g L4=%g L3=%g L2=%g L1=%g LC=%g LFINAL=%g DIM =%d ", - //X, Y, Z, l4, l3, l2, l1, lc, lc * CTX::instance()->mesh.lcFactor, ge->dim()); - - //Emi fix - //if (lc == l1) lc /= 10.; - - return lc * CTX::instance()->mesh.lcFactor; -} - - -// anisotropic version of the background field -SMetric3 BGM_MeshMetric(GEntity *ge, - double U, double V, - double X, double Y, double Z) -{ - - // Metrics based on element size - // Element size = min. between default lc and lc from point (if applicable), constrained by lcMin and lcMax - double lc = CTX::instance()->lc; - if(CTX::instance()->mesh.lcFromPoints && ge->dim() < 2) lc = std::min(lc, LC_MVertex_PNTS(ge, U, V)); - lc = std::max(lc, CTX::instance()->mesh.lcMin); - lc = std::min(lc, CTX::instance()->mesh.lcMax); - if(lc <= 0.){ - Msg::Error("Wrong mesh element size lc = %g (lcmin = %g, lcmax = %g)", - lc, CTX::instance()->mesh.lcMin, CTX::instance()->mesh.lcMax); - lc = CTX::instance()->lc; - } - SMetric3 m0(1./(lc*lc)); - - // Intersect with metrics from fields if applicable - FieldManager *fields = ge->model()->getFields(); - SMetric3 m1 = m0; - if(fields->getBackgroundField() > 0){ - Field *f = fields->get(fields->getBackgroundField()); - if(f) { - SMetric3 l4; - if (!f->isotropic()) (*f)(X, Y, Z, l4, ge); - else { - const double L = (*f)(X, Y, Z, ge); - l4 = SMetric3(1/(L*L)); - } - m1 = intersection(l4, m0); - } - } - - // Intersect with metrics from curvature if applicable - SMetric3 m = (CTX::instance()->mesh.lcFromCurvature && ge->dim() < 3) ? - intersection(m1, LC_MVertex_CURV_ANISO(ge, U, V)) : m1; +//static double LC_MVertex_PNTS(GEntity *ge, double U, double V) +//{ +// switch(ge->dim()){ +// case 0: +// { +// GVertex *gv = (GVertex *)ge; +// double lc = gv->prescribedMeshSizeAtVertex(); +// // FIXME we might want to remove this to make all lc treatment consistent +// if(lc >= MAX_LC) return CTX::instance()->lc / 10.; +// return lc; +// } +// case 1: +// { +// GEdge *ged = (GEdge *)ge; +// GVertex *v1 = ged->getBeginVertex(); +// GVertex *v2 = ged->getEndVertex(); +// if (v1 && v2){ +// Range<double> range = ged->parBounds(0); +// double a = (U - range.low()) / (range.high() - range.low()); +// double lc = (1 - a) * v1->prescribedMeshSizeAtVertex() + +// (a) * v2->prescribedMeshSizeAtVertex() ; +// // FIXME we might want to remove this to make all lc treatment consistent +// if(lc >= MAX_LC) return CTX::instance()->lc / 10.; +// return lc; +// } +// else +// return MAX_LC; +// } +// default: +// return MAX_LC; +// } +//} + +//// This is the only function that is used by the meshers +//double BGM_MeshSize(GEntity *ge, double U, double V, +// double X, double Y, double Z) +//{ +// // default lc (mesh size == size of the model) +// double l1 = CTX::instance()->lc; +// +// // lc from points +// double l2 = MAX_LC; +// if(CTX::instance()->mesh.lcFromPoints && ge->dim() < 2) +// l2 = LC_MVertex_PNTS(ge, U, V); +// +// // lc from curvature +// double l3 = MAX_LC; +// if(CTX::instance()->mesh.lcFromCurvature && ge->dim() < 3) +// l3 = LC_MVertex_CURV(ge, U, V); +// +// // lc from fields +// double l4 = MAX_LC; +// FieldManager *fields = ge->model()->getFields(); +// if(fields->getBackgroundField() > 0){ +// Field *f = fields->get(fields->getBackgroundField()); +// if(f) l4 = (*f)(X, Y, Z, ge); +// } +// +// // take the minimum, then constrain by lcMin and lcMax +// double lc = std::min(std::min(std::min(l1, l2), l3), l4); +// lc = std::max(lc, CTX::instance()->mesh.lcMin); +// lc = std::min(lc, CTX::instance()->mesh.lcMax); +// +// if(lc <= 0.){ +// Msg::Error("Wrong mesh element size lc = %g (lcmin = %g, lcmax = %g)", +// lc, CTX::instance()->mesh.lcMin, CTX::instance()->mesh.lcMax); +// lc = l1; +// } +// +// //Msg::Debug("BGM X,Y,Z=%g,%g,%g L4=%g L3=%g L2=%g L1=%g LC=%g LFINAL=%g DIM =%d ", +// //X, Y, Z, l4, l3, l2, l1, lc, lc * CTX::instance()->mesh.lcFactor, ge->dim()); +// +// //Emi fix +// //if (lc == l1) lc /= 10.; +// +// return lc * CTX::instance()->mesh.lcFactor; +//} - return m; -} +//// anisotropic version of the background field +//SMetric3 BGM_MeshMetric(GEntity *ge, +// double U, double V, +// double X, double Y, double Z) +//{ +// +// // Metrics based on element size +// // Element size = min. between default lc and lc from point (if applicable), constrained by lcMin and lcMax +// double lc = CTX::instance()->lc; +// if(CTX::instance()->mesh.lcFromPoints && ge->dim() < 2) lc = std::min(lc, LC_MVertex_PNTS(ge, U, V)); +// lc = std::max(lc, CTX::instance()->mesh.lcMin); +// lc = std::min(lc, CTX::instance()->mesh.lcMax); +// if(lc <= 0.){ +// Msg::Error("Wrong mesh element size lc = %g (lcmin = %g, lcmax = %g)", +// lc, CTX::instance()->mesh.lcMin, CTX::instance()->mesh.lcMax); +// lc = CTX::instance()->lc; +// } +// SMetric3 m0(1./(lc*lc)); +// +// // Intersect with metrics from fields if applicable +// FieldManager *fields = ge->model()->getFields(); +// SMetric3 m1 = m0; +// if(fields->getBackgroundField() > 0){ +// Field *f = fields->get(fields->getBackgroundField()); +// if(f) { +// SMetric3 l4; +// if (!f->isotropic()) (*f)(X, Y, Z, l4, ge); +// else { +// const double L = (*f)(X, Y, Z, ge); +// l4 = SMetric3(1/(L*L)); +// } +// m1 = intersection(l4, m0); +// } +// } +// +// // Intersect with metrics from curvature if applicable +// SMetric3 m = (CTX::instance()->mesh.lcFromCurvature && ge->dim() < 3) ? +// intersection(m1, LC_MVertex_CURV_ANISO(ge, U, V)) : m1; +// +// return m; +// +//} -bool Extend1dMeshIn2dSurfaces() -{ - return CTX::instance()->mesh.lcExtendFromBoundary ? true : false; -} +//bool Extend1dMeshIn2dSurfaces() +//{ +// return CTX::instance()->mesh.lcExtendFromBoundary ? true : false; +//} -bool Extend2dMeshIn3dVolumes() -{ - return CTX::instance()->mesh.lcExtendFromBoundary ? true : false; -} +//bool Extend2dMeshIn3dVolumes() +//{ +// return CTX::instance()->mesh.lcExtendFromBoundary ? true : false; +//} void backgroundMesh::set(GFace *gf) { diff --git a/Mesh/BackgroundMesh.h b/Mesh/BackgroundMesh.h index 3bb73aa311..7eeba70348 100644 --- a/Mesh/BackgroundMesh.h +++ b/Mesh/BackgroundMesh.h @@ -6,10 +6,12 @@ #ifndef _BACKGROUND_MESH_H_ #define _BACKGROUND_MESH_H_ -#include "STensor3.h" +//#include "STensor3.h" +#include <math.h> #include <vector> #include <list> #include "simpleFunction.h" +#include "BackgroundMeshTools.h" #if defined(HAVE_ANN) #include <ANN/ANN.h> @@ -18,11 +20,9 @@ class ANNkd_tree; class MElementOctree; class GFace; -class GVertex; class GEdge; class MElement; class MVertex; -class GEntity; struct crossField2d { @@ -102,17 +102,17 @@ class backgroundMesh : public simpleFunction<double> std::vector<MElement*>::const_iterator end_triangles()const{return _triangles.end();} }; -SMetric3 buildMetricTangentToCurve (SVector3 &t, double l_t, double l_n); -SMetric3 buildMetricTangentToSurface (SVector3 &t1, SVector3 &t2, double l_t1, double l_t2, double l_n); -double BGM_MeshSize(GEntity *ge, double U, double V, double X, double Y, double Z); -SMetric3 BGM_MeshMetric(GEntity *ge, double U, double V, double X, double Y, double Z); -bool Extend1dMeshIn2dSurfaces(); -bool Extend2dMeshIn3dVolumes(); -SMetric3 max_edge_curvature_metric(const GVertex *gv); -SMetric3 max_edge_curvature_metric(const GEdge *ge, double u, double &l); -SMetric3 metric_based_on_surface_curvature(const GFace *gf, double u, double v, - bool surface_isotropic = false, - double d_normal = 1.e12, - double d_tangent_max = 1.e12); +//SMetric3 buildMetricTangentToCurve (SVector3 &t, double l_t, double l_n); +//SMetric3 buildMetricTangentToSurface (SVector3 &t1, SVector3 &t2, double l_t1, double l_t2, double l_n); +//double BGM_MeshSize(GEntity *ge, double U, double V, double X, double Y, double Z); +//SMetric3 BGM_MeshMetric(GEntity *ge, double U, double V, double X, double Y, double Z); +//bool Extend1dMeshIn2dSurfaces(); +//bool Extend2dMeshIn3dVolumes(); +//SMetric3 max_edge_curvature_metric(const GVertex *gv); +//SMetric3 max_edge_curvature_metric(const GEdge *ge, double u, double &l); +//SMetric3 metric_based_on_surface_curvature(const GFace *gf, double u, double v, +// bool surface_isotropic = false, +// double d_normal = 1.e12, +// double d_tangent_max = 1.e12); #endif diff --git a/Mesh/BackgroundMesh2D.cpp b/Mesh/BackgroundMesh2D.cpp new file mode 100644 index 0000000000..8f49d36279 --- /dev/null +++ b/Mesh/BackgroundMesh2D.cpp @@ -0,0 +1,812 @@ +// 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@geuz.org>. + +#include "BackgroundMesh2D.h" +#include "BackgroundMeshTools.h" + +#include "GmshMessage.h" +#include "GVertex.h" +#include "GEdge.h" +#include "GEdgeCompound.h" +#include "GFace.h" +#include "GFaceCompound.h" +#include "MElement.h" +#include "MElementOctree.h" +#include "MTriangle.h" +#include "MVertex.h" +#include "Numeric.h" +#include "MLine.h" +#include "MTriangle.h" +#include "Field.h" +#include "OS.h" + +#if defined(HAVE_SOLVER) +#include "dofManager.h" +#include "laplaceTerm.h" +#include "linearSystemGMM.h" +#include "linearSystemCSR.h" +#include "linearSystemFull.h" +#include "linearSystemPETSc.h" +#endif + + +using namespace std; + +//------------------------------------------------------------------------ + +class evalDiffusivityFunction : public simpleFunction<double>{ + public: + evalDiffusivityFunction(frameFieldBackgroundMesh2D *_bgm, double t=0.95):bgm(_bgm),threshold(t){}; + double operator () (double u, double v, double w) const{ + return ((bgm->get_smoothness(u,v) >= threshold) ? 1. : 1.e-3); + } + private: + frameFieldBackgroundMesh2D *bgm; + const double threshold; +}; + +//------------------------------------------------------------------------ + +//TODO: move this fct ??? +/* applies rotations of amplitude pi to set the + angle in the first quadrant (in [0,pi/2[ ) */ +void normalizeAngle(double &angle) { + if (angle < 0) + while ( angle < 0 ) angle += (M_PI * .5); + else if (angle >= M_PI * .5) + while ( angle >= M_PI * .5 ) angle -= (M_PI * .5); +} + +//------------------------------------------------------------------------ + +void backgroundMesh2D::create_face_mesh(){ + + quadsToTriangles(dynamic_cast<GFace*>(gf), 100000); + + // storing the initial mesh from GFace + tempTR.clear(); + GFace *face = dynamic_cast<GFace*>(gf); + for(unsigned int i = 0; i < face->triangles.size(); i++) + tempTR.push_back(new MTriangle(face->triangles[i]->getVertex(0), face->triangles[i]->getVertex(1), face->triangles[i]->getVertex(2))); + + // avoid computing curvatures on the fly : only on the + // BGM computes once curvatures at each node + // Disable curvature control + int CurvControl = CTX::instance()->mesh.lcFromCurvature; + CTX::instance()->mesh.lcFromCurvature = 0; + // Create a background mesh + bowyerWatson(face,4000); + // Re-enable curv control if asked + CTX::instance()->mesh.lcFromCurvature = CurvControl; + + // creates a copy of GFace's vertices and triangles + create_mesh_copy(); +} + +//------------------------------------------------------------------------ + +MElementOctree* backgroundMesh2D::getOctree(){ + if(!octree){ + Msg::Debug("Rebuilding BackgroundMesh element octree"); + octree = new MElementOctree(elements); + } + return octree; +} + +//------------------------------------------------------------------------ + +const MElement* backgroundMesh2D::getElement(unsigned int i)const{ + return elements[i]; +} + +//------------------------------------------------------------------------ + +void backgroundMesh2D::reset(bool erase_2D3D){ + unset(); + + // create face mesh - this was previously done for old backgroundmesh in buildBackGroundMesh ! + create_face_mesh(); + + // computes the mesh sizes at nodes + if (CTX::instance()->mesh.lcFromPoints){ + computeSizeField(); + } + else + for (map<MVertex*, MVertex*>::iterator itv2 = _2Dto3D.begin() ; itv2 != _2Dto3D.end(); ++itv2) + sizeField[itv2->first] = CTX::instance()->mesh.lcMax; + + // ensure that other criteria are fullfilled + updateSizes(); + + if (erase_2D3D){ + _3Dto2D.clear(); + _2Dto3D.clear(); + } +} + +//------------------------------------------------------------------------ + +void backgroundMesh2D::unset(){ + for (unsigned int i = 0; i < vertices.size(); i++) delete vertices[i]; + for (unsigned int i = 0; i < getNumMeshElements(); i++) delete elements[i]; + if (octree)delete octree; + octree=NULL; +} + +//------------------------------------------------------------------------ + +void backgroundMesh2D::create_mesh_copy(){ + // TODO: useful to extend it to other elements ??? + //set<SPoint2> myBCNodes; + GFace *face = dynamic_cast<GFace*>(gf); + for (unsigned int i = 0; i < face->triangles.size(); i++){ + MTriangle *e = face->triangles[i]; + MVertex *news[3]; + for (int j=0;j<3;j++){ + MVertex *v = e->getVertex(j); + map<MVertex*,MVertex*>::iterator it = _3Dto2D.find(v); + MVertex *newv =0; + if (it == _3Dto2D.end()){ + SPoint2 p; + reparamMeshVertexOnFace(v, face, p); + newv = new MVertex (p.x(), p.y(), 0.0);// creates new vertex with xyz= u,v,0. + vertices.push_back(newv); + _3Dto2D[v] = newv; + _2Dto3D[newv] = v; + //if(v->onWhat()->dim()<2) myBCNodes.insert(p); + } + else newv = it->second; + news[j] = newv; + } + elements.push_back(new MTriangle(news[0],news[1],news[2])); + } +} + +//------------------------------------------------------------------------------------------ + +GPoint backgroundMesh2D::get_GPoint_from_MVertex(const MVertex *v)const{ + return dynamic_cast<GFace*>(gf)->point(SPoint2(v->x(),v->y())); +} + +//------------------------------------------------------------------------ + +backgroundMesh2D::backgroundMesh2D(GFace *_gf, bool erase_2D3D):BGMBase(2,_gf),sizeFactor(1.){ + if(debug) cout << "backgroundMesh2D::constructor " << endl; + reset(erase_2D3D); + + if (erase_2D3D){ + // now, the new mesh has been copied in local in backgroundMesh2D, deleting the mesh from GFace, back to the previous one ! + GFace *face = dynamic_cast<GFace*>(gf); + face->triangles = tempTR; + } + +} + +//------------------------------------------------------------------------ + +backgroundMesh2D::~backgroundMesh2D(){ + unset(); +} + +//------------------------------------------------------------------------ + +void backgroundMesh2D::propagateValues(DoubleStorageType &dirichlet, simpleFunction<double> &eval_diffusivity, bool in_parametric_plane){ +#if defined(HAVE_SOLVER) + linearSystem<double> *_lsys = 0; +#if defined(HAVE_PETSC) && !defined(HAVE_TAUCS) + _lsys = new linearSystemPETSc<double>; +#elif defined(HAVE_GMM) && !defined(HAVE_TAUCS) + linearSystemGmm<double> *_lsysb = new linearSystemGmm<double>; + _lsysb->setGmres(1); + _lsys = _lsysb; +#elif defined(HAVE_TAUCS) + _lsys = new linearSystemCSRTaucs<double>; +#else + _lsys = new linearSystemFull<double>; +#endif + + dofManager<double> myAssembler(_lsys); + + // fix boundary conditions + DoubleStorageType::iterator itv = dirichlet.begin(); + for ( ; itv != dirichlet.end(); ++itv){ + myAssembler.fixVertex(itv->first, 0, 1, itv->second); + } + + + // Number vertices + set<MVertex*> vs; + GFace *face = dynamic_cast<GFace*>(gf); + for (unsigned int k = 0; k < face->triangles.size(); k++) + for (int j=0;j<3;j++)vs.insert(face->triangles[k]->getVertex(j)); + for (unsigned int k = 0; k < face->quadrangles.size(); k++) + for (int j=0;j<4;j++)vs.insert(face->quadrangles[k]->getVertex(j)); + + + map<MVertex*,SPoint3> theMap; + if ( in_parametric_plane) { + for (set<MVertex*>::iterator it = vs.begin(); it != vs.end(); ++it){ + SPoint2 p; + reparamMeshVertexOnFace ( *it, face, p); + theMap[*it] = SPoint3((*it)->x(),(*it)->y(),(*it)->z()); + (*it)->setXYZ(p.x(),p.y(),0.0); + } + } + + for (set<MVertex*>::iterator it = vs.begin(); it != vs.end(); ++it) + myAssembler.numberVertex(*it, 0, 1); + + // Assemble + laplaceTerm l(0, 1, &eval_diffusivity); + for (unsigned int k = 0; k < face->triangles.size(); k++){ + MTriangle *t = face->triangles[k]; + SElement se(t); + l.addToMatrix(myAssembler, &se); + } + + // Solve + if (myAssembler.sizeOfR()){ + _lsys->systemSolve(); + } + + // save solution + for (set<MVertex*>::iterator it = vs.begin(); it != vs.end(); ++it){ + myAssembler.getDofValue(*it, 0, 1, dirichlet[*it]); + } + + if ( in_parametric_plane) { + for (set<MVertex*>::iterator it = vs.begin(); it != vs.end(); ++it){ + SPoint3 p = theMap[(*it)]; + (*it)->setXYZ(p.x(),p.y(),p.z()); + } + } + delete _lsys; +#endif +} + +//------------------------------------------------------------------------ + +void backgroundMesh2D::computeSizeField(){ + GFace *face = dynamic_cast<GFace*>(gf); + list<GEdge*> e;// = face->edges(); + replaceMeshCompound(face, e); + list<GEdge*>::const_iterator it = e.begin(); + DoubleStorageType sizes; + + for( ; it != e.end(); ++it ){ + if (!(*it)->isSeam(face)){ + for(unsigned int i = 0; i < (*it)->lines.size(); i++ ){ + MVertex *v1 = (*it)->lines[i]->getVertex(0); + MVertex *v2 = (*it)->lines[i]->getVertex(1); + if (v1 != v2){ + double d = sqrt((v1->x() - v2->x()) * (v1->x() - v2->x()) + + (v1->y() - v2->y()) * (v1->y() - v2->y()) + + (v1->z() - v2->z()) * (v1->z() -v2->z())); + for (int k=0;k<2;k++){ + MVertex *v = (*it)->lines[i]->getVertex(k); + DoubleStorageType::iterator itv = sizes.find(v); + if (itv == sizes.end()) + sizes[v] = log(d); + else + itv->second = 0.5 * (itv->second + log(d)); + } + } + } + } + } + + simpleFunction<double> ONE(1.0); + propagateValues(sizes,ONE); + + map<MVertex*,MVertex*>::iterator itv2 = _2Dto3D.begin(); + for ( ; itv2 != _2Dto3D.end(); ++itv2){ + MVertex *v_2D = itv2->first; + MVertex *v_3D = itv2->second; + sizeField[v_2D] = exp(sizes[v_3D]); + } +} + +//------------------------------------------------------------------------ + +inline double myAngle (const SVector3 &a, const SVector3 &b, const SVector3 &d){ + double cosTheta = dot(a,b); + double sinTheta = dot(crossprod(a,b),d); + return atan2 (sinTheta,cosTheta); +} + +//------------------------------------------------------------------------ + +void backgroundMesh2D::updateSizes(){ + DoubleStorageType::iterator itv = sizeField.begin(); + for ( ; itv != sizeField.end(); ++itv){ + SPoint2 p; + MVertex *v = _2Dto3D[itv->first]; + double lc; + if (v->onWhat()->dim() == 0){ + lc = sizeFactor * BGM_MeshSize(v->onWhat(), 0,0,v->x(),v->y(),v->z()); + } + else if (v->onWhat()->dim() == 1){ + double u; + v->getParameter(0, u); + lc = sizeFactor * BGM_MeshSize(v->onWhat(), u, 0, v->x(), v->y(), v->z()); + } + else{ + GFace *face = dynamic_cast<GFace*>(gf); + reparamMeshVertexOnFace(v, face, p); + lc = sizeFactor * BGM_MeshSize(face, p.x(), p.y(), v->x(), v->y(), v->z()); + } + // printf("2D -- %g %g 3D -- %g %g\n",p.x(),p.y(),v->x(),v->y()); + itv->second = min(lc,itv->second); + itv->second = max(itv->second, sizeFactor * CTX::instance()->mesh.lcMin); + itv->second = min(itv->second, sizeFactor * CTX::instance()->mesh.lcMax); + } + // do not allow large variations in the size field + // (Int. J. Numer. Meth. Engng. 43, 1143-1165 (1998) MESH GRADATION + // CONTROL, BOROUCHAKI, HECHT, FREY) + set<MEdge,Less_Edge> edges; + for (unsigned int i = 0; i < getNumMeshElements(); i++){ + for (int j = 0; j < getElement(i)->getNumEdges(); j++){ + edges.insert(getElement(i)->getEdge(j)); + } + } + const double _beta = 1.3; + for (int i=0;i<0;i++){ + set<MEdge,Less_Edge>::iterator it = edges.begin(); + for ( ; it != edges.end(); ++it){ + MVertex *v0 = it->getVertex(0); + MVertex *v1 = it->getVertex(1); + MVertex *V0 = _2Dto3D[v0]; + MVertex *V1 = _2Dto3D[v1]; + DoubleStorageType::iterator s0 = sizeField.find(V0); + DoubleStorageType::iterator s1 = sizeField.find(V1); + if (s0->second < s1->second)s1->second = min(s1->second,_beta*s0->second); + else s0->second = min(s0->second,_beta*s1->second); + } + } +} + + +//------------------------------------------------------------------------ +//------------------------------------------------------------------------ +//------------------------------------------------------------------------ +//------------------------------------------------------------------------ +//------------------------------------------------------------------------ + + +//------------------------------------------------------------------------ + +frameFieldBackgroundMesh2D::frameFieldBackgroundMesh2D(GFace *_gf):backgroundMesh2D(_gf,false){ + + if(debug) cout << "frameFieldBackgroundMesh2D::constructor " << endl; + + reset(); + + // now, the new mesh has been copied in local in backgroundMesh2D, deleting the mesh from GFace, back to the previous one ! + GFace *face = dynamic_cast<GFace*>(gf); + face->triangles = tempTR; +} + +//------------------------------------------------------------------------ + +frameFieldBackgroundMesh2D::~frameFieldBackgroundMesh2D(){} + +//------------------------------------------------------------------------ + +void frameFieldBackgroundMesh2D::reset(bool erase_2D3D){ + + // computes cross field + if(debug) cout << "frameFieldBackgroundMesh2D::reset " << endl; + + + simpleFunction<double> ONE(1.0); + computeCrossField(ONE); + computeSmoothness(); + +// evalDiffusivityFunction eval_diff(this); +// exportSmoothness("smoothness_iter_0.pos"); +// for (int i=1;i<30;i++){ +// computeCrossField(eval_diff); +// computeSmoothness(); +// +// stringstream ss; +// ss << "smoothness_iter_" << i << ".pos"; +// exportSmoothness(ss.str()); +// +// stringstream sscf; +// sscf << "crossfield_iter_" << i << ".pos"; +// exportCrossField(sscf.str()); +// } + + if (erase_2D3D){ + _3Dto2D.clear(); + _2Dto3D.clear(); + } +} + +//------------------------------------------------------------------------ + +double frameFieldBackgroundMesh2D::get_smoothness(MVertex *v){ + if(debug) cout << "frameFieldBackgroundMesh2D::get_smoothness(MVertex *v)" << endl; + return get_nodal_value(v,smoothness); +} + +//------------------------------------------------------------------------ + +double frameFieldBackgroundMesh2D::get_smoothness(double u, double v){ + if(debug) cout << "frameFieldBackgroundMesh2D::get_smoothness(double u, double v)" << endl; + return get_field_value(u,v,0.,smoothness); +} + +//------------------------------------------------------------------------ + +double frameFieldBackgroundMesh2D::angle(MVertex *v){ + if(debug) cout << "frameFieldBackgroundMesh2D::angle(MVertex *v)" << endl; + return get_nodal_value(v,angles); +} + +//------------------------------------------------------------------------ + +double frameFieldBackgroundMesh2D::angle(double u, double v){ + MElement *e = const_cast<MElement*>(findElement(u, v)); + if (!e) return -1000.0; + vector<double> val = get_nodal_values(e,angles); + vector<double> element_uvw = get_element_uvw_from_xyz(e,u,v,0.); + double cosvalues[e->getNumVertices()],sinvalues[e->getNumVertices()]; + for (int i=0;i<e->getNumVertices();i++){ + cosvalues[i]=cos(4*val[i]); + sinvalues[i]=sin(4*val[i]); + } + double cos4 = e->interpolate(cosvalues, element_uvw[0], element_uvw[1], element_uvw[2], 1, order); + double sin4 = e->interpolate(sinvalues, element_uvw[0], element_uvw[1], element_uvw[2], 1, order); + double a = atan2(sin4,cos4)/4.0; + normalizeAngle (a); + return a; +} + +//------------------------------------------------------------------------ + +void frameFieldBackgroundMesh2D::computeCrossField(simpleFunction<double> &eval_diffusivity){ + angles.clear(); + if(debug) cout << "frameFieldBackgroundMesh2D::computeCrossField " << endl; + + DoubleStorageType _cosines4,_sines4; + + list<GEdge*> e; + GFace *face = dynamic_cast<GFace*>(gf); + replaceMeshCompound(face, e); + + list<GEdge*>::const_iterator it = e.begin(); + + for( ; it != e.end(); ++it ){ + if (!(*it)->isSeam(face)){ + for(unsigned int i = 0; i < (*it)->lines.size(); i++ ){ + MVertex *v[2]; + v[0] = (*it)->lines[i]->getVertex(0); + v[1] = (*it)->lines[i]->getVertex(1); + SPoint2 p1,p2; + reparamMeshEdgeOnFace(v[0],v[1],face,p1,p2); + Pair<SVector3, SVector3> der = face->firstDer((p1+p2)*.5); + SVector3 t1 = der.first(); + SVector3 t2 = der.second(); + SVector3 n = crossprod(t1,t2); + n.normalize(); + SVector3 d1(v[1]->x()-v[0]->x(),v[1]->y()-v[0]->y(),v[1]->z()-v[0]->z()); + t1.normalize(); + d1.normalize(); + double _angle = myAngle (t1,d1,n); + normalizeAngle (_angle); + for (int i=0;i<2;i++){ + DoubleStorageType::iterator itc = _cosines4.find(v[i]); + DoubleStorageType::iterator its = _sines4.find(v[i]); + if (itc != _cosines4.end()){ + itc->second = 0.5*(itc->second + cos(4*_angle)); + its->second = 0.5*(its->second + sin(4*_angle)); + } + else { + _cosines4[v[i]] = cos(4*_angle); + _sines4[v[i]] = sin(4*_angle); + } + } + } + } + } + + propagateValues(_cosines4,eval_diffusivity,false); + propagateValues(_sines4,eval_diffusivity,false); + + + + map<MVertex*,MVertex*>::iterator itv2 = _2Dto3D.begin(); + for ( ; itv2 != _2Dto3D.end(); ++itv2){ + MVertex *v_2D = itv2->first; + MVertex *v_3D = itv2->second; + double angle = atan2(_sines4[v_3D],_cosines4[v_3D]) / 4.0; + normalizeAngle (angle); + angles[v_2D] = angle; + } +} + +//------------------------------------------------------------------------ + +void frameFieldBackgroundMesh2D::eval_crossfield(double u, double v, STensor3 &cf){ + double quadAngle = angle(u,v); + Pair<SVector3, SVector3> dirs = compute_crossfield_directions(u,v,quadAngle); + SVector3 n = crossprod(dirs.first(),dirs.second()); + + for (int i=0;i<3;i++){ + cf(i,0) = dirs.first()[i]; + cf(i,1) = dirs.second()[i]; + cf(i,2) = n[i]; + } + + + + // SVector3 t1,t2,n; + // GFace *face = dynamic_cast<GFace*>(gf); + // Pair<SVector3, SVector3> der = face->firstDer(SPoint2(u,v)); + // SVector3 s1 = der.first(); + // SVector3 s2 = der.second(); + // n = crossprod(s1,s2); + // n.normalize(); + // s1.normalize(); + // s2=crossprod(n,s1); + // t1 = s1 * cos(quadAngle) + s2 * sin(quadAngle) ; + // t1.normalize(); + // t2 = crossprod(n,t1); + // for (int i=0;i<3;i++){ + // cf(i,0) = t1[i]; + // cf(i,1) = t2[i]; + // cf(i,2) = n[i]; + // } + + return; +} + +//------------------------------------------------------------------------ + +void frameFieldBackgroundMesh2D::eval_crossfield(MVertex *vert, STensor3 &cf){ + SPoint2 parampoint; + GFace *face = dynamic_cast<GFace*>(gf); + reparamMeshVertexOnFace(vert, face, parampoint); + return eval_crossfield(parampoint[0], parampoint[1], cf); +} + +//------------------------------------------------------------------------ + +void frameFieldBackgroundMesh2D::computeSmoothness(){ + smoothness.clear(); + + if(debug) cout << "frameFieldBackgroundMesh2D::computeSmoothness " << endl; + + // build vertex -> neighbors table + multimap<MVertex*,MVertex*> vertex2vertex; + for (std::vector<MElement*>::iterator it = beginelements();it!=endelements();it++){ + MElement *e = *it; + for (int i=0;i<e->getNumVertices();i++){ + MVertex *current = e->getVertex(i); + for (int j=0;j<e->getNumVertices();j++){ + if (i==j) continue; + MVertex *neighbor = e->getVertex(j); + vertex2vertex.insert(make_pair(current,neighbor)); + } + } + } + + // compute smoothness + for (std::vector<MVertex*>::iterator it = beginvertices();it!=endvertices();it++){ + MVertex *v = *it; + double angle_current = angle(v); + // compare to all neighbors... + pair<multimap<MVertex*,MVertex*>::iterator, multimap<MVertex*,MVertex*>::iterator> range = vertex2vertex.equal_range(v); + double minangle,totalangle=0.; + int N=0; + for (multimap<MVertex*,MVertex*>::iterator itneighbor = range.first;itneighbor!=range.second;itneighbor++){ + N++; + minangle=M_PI/2; + MVertex *v_nb = itneighbor->second; + double angle_nb = angle(v_nb); + // angle comparison... + minangle = std::min(minangle, fabs(angle_current-angle_nb)); + minangle = std::min(minangle, fabs(angle_current-(angle_nb+M_PI/2.))); + minangle = std::min(minangle, fabs(angle_current-(angle_nb-M_PI/2.))); + totalangle += minangle; + } + totalangle /= N; + smoothness[v] = 1. - (totalangle/M_PI*2); + } +} + +//------------------------------------------------------------------------ + +void frameFieldBackgroundMesh2D::exportCrossField(const string &filename){ + FILE *f = Fopen (filename.c_str(),"w"); + fprintf(f,"View \"Cross Field\"{\n"); + vector<double> deltas(2); + deltas[0] = 0.; + deltas[1] = M_PI; + + for (std::vector<MVertex*>::iterator it = beginvertices();it!=endvertices();it++){ + MVertex *v = *it; + double angle_current = angle(v); + GPoint p = get_GPoint_from_MVertex(v); + for (int i=0;i<2;i++){ + Pair<SVector3, SVector3> dirs = compute_crossfield_directions(v->x(),v->y(),angle_current+deltas[i]); + fprintf(f,"VP(%g,%g,%g) {%g,%g,%g};\n",p.x(),p.y(),p.z(),dirs.first()[0], dirs.first()[1], dirs.first()[2]); + fprintf(f,"VP(%g,%g,%g) {%g,%g,%g};\n",p.x(),p.y(),p.z(),dirs.second()[0], dirs.second()[1], dirs.second()[2]); + } + } + fprintf(f,"};\n"); + fclose(f); +} + +//------------------------------------------------------------------------ + +// returns the cross field as a pair of othogonal vectors (NOT in parametric coordinates, but real 3D coordinates) +Pair<SVector3, SVector3> frameFieldBackgroundMesh2D::compute_crossfield_directions(double u,double v, double angle_current){ + + // get the unit normal at that point + GFace *face = dynamic_cast<GFace*>(gf); + Pair<SVector3, SVector3> der = face->firstDer(SPoint2(u,v)); + SVector3 s1 = der.first(); + SVector3 s2 = der.second(); + SVector3 n = crossprod(s1,s2); + n.normalize(); + + SVector3 basis_u = s1; basis_u.normalize(); + SVector3 basis_v = crossprod(n,basis_u); + + // normalize vector t1 that is tangent to gf at uv + SVector3 t1 = basis_u * cos(angle_current) + basis_v * sin(angle_current) ; + t1.normalize(); + + // compute the second direction t2 and normalize (t1,t2,n) is the tangent frame + SVector3 t2 = crossprod(n,t1); + t2.normalize(); + + return Pair<SVector3,SVector3>(SVector3(t1[0],t1[1],t1[2]), + SVector3(t2[0],t2[1],t2[2])); +} + +//------------------------------------------------------------------------ + +bool frameFieldBackgroundMesh2D::compute_RK_infos(double u,double v, double x, double y, double z, RK_form &infos){ + + // check if point is in domain + if (!inDomain(u,v)) return false; + + // get stored angle + + double angle_current = angle(u,v); + + // compute t1,t2: cross field directions + + // get the unit normal at that point + GFace *face = dynamic_cast<GFace*>(gf); + Pair<SVector3, SVector3> der = face->firstDer(SPoint2(u,v)); + SVector3 s1 = der.first(); + SVector3 s2 = der.second(); + SVector3 n = crossprod(s1,s2); + n.normalize(); + SVector3 basis_u = s1; basis_u.normalize(); + SVector3 basis_v = crossprod(n,basis_u); + // normalize vector t1 that is tangent to gf at uv + SVector3 t1 = basis_u * cos(angle_current) + basis_v * sin(angle_current) ; + t1.normalize(); + // compute the second direction t2 and normalize (t1,t2,n) is the tangent frame + SVector3 t2 = crossprod(n,t1); + t2.normalize(); + + // get metric + + double L = size(u,v); + infos.metricField = SMetric3(1./(L*L)); + FieldManager *fields = gf->model()->getFields(); + if(fields->getBackgroundField() > 0){ + Field *f = fields->get(fields->getBackgroundField()); + if (!f->isotropic()){ + (*f)(x,y,z, infos.metricField,gf); + } + else { + L = (*f)(x,y,z,gf); + infos.metricField = SMetric3(1./(L*L)); + } + } + double M = dot(s1,s1); + double N = dot(s2,s2); + double E = dot(s1,s2); + // compute the first fundamental form i.e. the metric tensor at the point + // M_{ij} = s_i \cdot s_j + double metric[2][2] = {{M,E},{E,N}}; + + // get sizes + + double size_1 = sqrt(1. / dot(t1,infos.metricField,t1)); + double size_2 = sqrt(1. / dot(t2,infos.metricField,t2)); + + // compute covariant coordinates of t1 and t2 - cross field directions in parametric domain + double covar1[2],covar2[2]; + // t1 = a s1 + b s2 --> + // t1 . s1 = a M + b E + // t1 . s2 = a E + b N --> solve the 2 x 2 system + // and get covariant coordinates a and b + double rhs1[2] = {dot(t1,s1),dot(t1,s2)}; + bool singular = false; + if (!sys2x2(metric,rhs1,covar1)){ + Msg::Info("Argh surface %d %g %g %g -- %g %g %g -- %g %g",gf->tag(),s1.x(),s1.y(),s1.z(),s2.x(),s2.y(),s2.z(),size_1,size_2); + covar1[1] = 1.0; covar1[0] = 0.0; + singular = true; + } + double rhs2[2] = {dot(t2,s1),dot(t2,s2)}; + if (!sys2x2(metric,rhs2,covar2)){ + Msg::Info("Argh surface %d %g %g %g -- %g %g %g",gf->tag(),s1.x(),s1.y(),s1.z(),s2.x(),s2.y(),s2.z()); + covar2[0] = 1.0; covar2[1] = 0.0; + singular = true; + } + + // transform the sizes with respect to the metric + // consider a vector v of size 1 in the parameter plane + // its length is sqrt (v^T M v) --> if I want a real size + // of size1 in direction v, it should be sqrt(v^T M v) * size1 + double l1 = sqrt(covar1[0]*covar1[0]+covar1[1]*covar1[1]); + double l2 = sqrt(covar2[0]*covar2[0]+covar2[1]*covar2[1]); + + covar1[0] /= l1;covar1[1] /= l1; + covar2[0] /= l2;covar2[1] /= l2; + + double size_param_1 = size_1 / sqrt ( M*covar1[0]*covar1[0]+ + 2*E*covar1[1]*covar1[0]+ + N*covar1[1]*covar1[1]); + double size_param_2 = size_2 / sqrt ( M*covar2[0]*covar2[0]+ + 2*E*covar2[1]*covar2[0]+ + N*covar2[1]*covar2[1]); + if (singular){ + size_param_1 = size_param_2 = std::min (size_param_1,size_param_2); + } + + + // filling form... + + infos.t1 = t1; + infos.h.first = size_1; + infos.h.second = size_2; + infos.paramh.first = size_param_1; + infos.paramh.second = size_param_2; + infos.paramt1 = SPoint2(covar1[0],covar1[1]); + infos.paramt2 = SPoint2(covar2[0],covar2[1]); + infos.angle = angle_current; + infos.localsize = L; + infos.normal = n; + + return true; + +} + + + + +// if (use_previous_basis){ +// std::map<double, double> angles; +// SVector3 temp = crossprod(previous_t1, t1); +// double a = atan2(dot(t1, previous_t1), sign(dot(temp,n))*temp.norm() ); +// angles.insert(std::make_pair(abs(a),a)); +// temp = crossprod(previous_t2, t1); +// a = atan2(dot(t1, previous_t2), sign(dot(temp,n))*temp.norm()); +// angles.insert(std::make_pair(abs(a),a)); +// temp = crossprod(-1.*previous_t1, t1); +// a = atan2(dot(t1, -1.*previous_t1), sign(dot(temp,n))*temp.norm()); +// angles.insert(std::make_pair(abs(a),a)); +// temp = crossprod(-1.*previous_t2, t1); +// a = atan2(dot(t1, -1.*previous_t2), sign(dot(temp,n))*temp.norm()); +// angles.insert(std::make_pair(abs(a),a)); +// // std::if(debug) cout << "angles: " << std::endl; +// // for (int i=0;i<4;i++) std::if(debug) cout << angles[i] << " " << std::endl; +// double min_angle = -(angles.begin()->second); +// // std::if(debug) cout << "min angle = " << min_angle << std::endl; +// t1 = cos(min_angle)*previous_t1 + sin(min_angle)*previous_t2; +// t2 = -sin(min_angle)*previous_t1 + cos(min_angle)*previous_t2; +// // std::if(debug) cout << "new corrected t : (" << t1(0) << "," << t1(1) << ") (" << t2(0) << "," << t2(1) << std::endl; +// } + + diff --git a/Mesh/BackgroundMesh2D.h b/Mesh/BackgroundMesh2D.h new file mode 100644 index 0000000000..a0820bcba2 --- /dev/null +++ b/Mesh/BackgroundMesh2D.h @@ -0,0 +1,142 @@ +// 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@geuz.org>. + +#ifndef _BACKGROUND_MESH2D_H_ +#define _BACKGROUND_MESH2D_H_ + + +#include <string> +#include <map> +#include <vector> +#include "Pair.h" +#include "STensor3.h" + +#include "BGMBase.h" + +class MTriangle; + +using namespace std; + +/* + The backgroundMesh2D creates a bunch of triangles on the parametric space of a GFace. + Those triangles are local to the backgroundMesh2D so that + they do not depend on the actual mesh that can be deleted. + It extends the sizefield from the edges. + */ +class backgroundMesh2D : public BGMBase { + protected: + virtual void propagateValues(DoubleStorageType &dirichlet, simpleFunction<double> &eval_diffusivity, bool in_parametric_plane = false); + virtual void computeSizeField(); + + virtual inline unsigned int getNumMeshElements()const{return elements.size();} + virtual const MElement* getElement(unsigned int i)const; + + virtual GPoint get_GPoint_from_MVertex(const MVertex *) const; + + // only 2D: + void updateSizes(); + // copy the mesh stored in GFace in local + void create_mesh_copy(); + // creates a mesh of GFace and store it in local !!!, does not store the mesh in GFace ! + void create_face_mesh(); + + double sizeFactor; + + + std::vector<MTriangle*> tempTR; + vector<MElement*> elements; + vector<MVertex*> vertices; + + map<MVertex*,MVertex*> _3Dto2D; + map<MVertex*,MVertex*> _2Dto3D; + + + public: + backgroundMesh2D(GFace *, bool erase_2D3D=true); + virtual ~backgroundMesh2D(); + + virtual MElementOctree* getOctree(); + + // TODO: only 2D + virtual void reset(bool erase_2D3D=true);// deletes everything and rebuild with GFace* + virtual void unset();// deletes everything... called by destructor. + + // not used !!!! TODO !!! + void setSizeFactor (double s) {sizeFactor = s;} + + + virtual vector<MVertex*>::iterator beginvertices(){return vertices.begin();} + virtual vector<MVertex*>::iterator endvertices(){return vertices.end();} + virtual vector<MElement*>::iterator beginelements(){return elements.begin();} + virtual vector<MElement*>::iterator endelements(){return elements.end();} + virtual vector<MVertex*>::const_iterator beginvertices()const{return vertices.begin();} + virtual vector<MVertex*>::const_iterator endvertices()const{return vertices.end();} + virtual vector<MElement*>::const_iterator beginelements()const{return elements.begin();} + virtual vector<MElement*>::const_iterator endelements()const{return elements.end();} + +}; + +//------------------------------------------------------------------------ + +class RK_form{// informations for RK at one point + public: + RK_form(){ + } +// RK_form(const RK_form &other){ +// t1 = other.t1; +// t2 = other.t2; +// h.first = other.h.first; +// h.second = other.h.second; +// paramh.first = other.paramh.first; +// paramh.second = other.paramh.second; +// paramt1 = other.paramt1; +// paramt2 = other.paramt2; +// angle = other.angle; +// } + + SMetric3 metricField; + SVector3 t1, t2;// 3D cross field directions + SVector3 normal;// 3D cross field directions + pair<double,double> h;// 3D sizes + pair<double,double> paramh;// sizes in parametric domain + SPoint2 paramt1,paramt2; + double angle,localsize; +}; + +//------------------------------------------------------------------------ + + +class frameFieldBackgroundMesh2D : public backgroundMesh2D{ + private: + // specification for cross field + DoubleStorageType angles; // an attached angle + DoubleStorageType smoothness; + + void computeCrossField(simpleFunction<double> &eval_diffusivity); + void computeSmoothness(); + + public: + frameFieldBackgroundMesh2D(GFace *_gf); + virtual ~frameFieldBackgroundMesh2D(); + + virtual void reset(bool erase_2D3D=true); + + double angle(double u, double v); + double angle(MVertex *v); + + double get_smoothness(double u, double v); + double get_smoothness(MVertex *v); + + void eval_crossfield(double u, double v, STensor3 &cf); + void eval_crossfield(MVertex *vert, STensor3 &cf); + + void exportCrossField(const string &filename); + Pair<SVector3, SVector3> compute_crossfield_directions(double u,double v, double angle_current); + bool compute_RK_infos(double u,double v, double x, double y, double z,RK_form &infos); + + inline void exportSmoothness(const string &filename) const{export_scalar(filename,smoothness);}; +}; + +#endif diff --git a/Mesh/BackgroundMesh3D.cpp b/Mesh/BackgroundMesh3D.cpp new file mode 100644 index 0000000000..628431c443 --- /dev/null +++ b/Mesh/BackgroundMesh3D.cpp @@ -0,0 +1,1182 @@ + +#include "BackgroundMesh3D.h" +#include <fstream> +#include <algorithm> +#include <iostream> +#include <string> +#include <numeric> + +#include <time.h> + +#include "MElement.h" +#include "GFace.h" +#include "GRegion.h" +#include "BackgroundMeshManager.h" +#include "BackgroundMesh2D.h" + +#include "MElementOctree.h" + +//#include "pointInsertion.h" + +#include "MTetrahedron.h" +#include "OS.h" + +#if defined(HAVE_PETSC) +#include "dofManager.h" +#include "laplaceTerm.h" +#include "linearSystemPETSc.h" +#include "linearSystemFull.h" +#endif + + +int signof(int i){ + return ((i < 0) ? -1 : 1); +} + +//------------------------------------------------------------------------ + +// TODO: virer les trucs "vertextorank", mettre cette classe-ci : + +//class evalDiffusivity3DFunction : public simpleFunction<double>{ +// public: +// evalDiffusivity3DFunction(frameFieldBackgroundMesh3D *_bgm, double t=0.95):bgm(_bgm),threshold(t){}; +// double operator () (double u, double v, double w) const{ +// return ((bgm->get_smoothness(u,v) >= threshold) ? 1. : 1.e-3); +// } +// private: +// frameFieldBackgroundMesh2D *bgm; +// const double threshold; +//}; + +//------------------------------------------------------------------------------------------ + +backgroundMesh3D::backgroundMesh3D(GRegion *_gr):BGMBase(3,_gr),debug(false),verbose(false){ + computeSizeField(); +} + +//------------------------------------------------------------------------------------------ + +backgroundMesh3D::~backgroundMesh3D(){ +} + +//------------------------------------------------------------------------------------------ + +void backgroundMesh3D::computeSizeField(){ + + cout << "backgroundMesh3D::computeSizeField() " << endl; + + // fills dirichlet BC + GRegion *region = dynamic_cast<GRegion*>(gf); + list<GFace*> faces = region->faces(); + MVertex *v; + MElement *e; + + for (list<GFace*>::iterator it=faces.begin();it!=faces.end();it++){// for all GFace + GFace *face = *it; + frameFieldBackgroundMesh2D *bgm2d = dynamic_cast<frameFieldBackgroundMesh2D*>(BGMManager::get(face)); + for (unsigned int i=0;i<face->getNumMeshElements();i++){// for all elements + e = face->getMeshElement(i); + if (e->getDim()!=2) continue;// of dim=2 + for (int iv=0;iv<e->getNumVertices();iv++){ + v = e->getVertex(iv); + SPoint2 p; + reparamMeshVertexOnFace(v, face, p); + sizeField[v] = bgm2d->size(p.x(),p.y()); +// cout << "sets sizefield for vertex " << v << endl; + } + } + } + + // propagate + simpleFunction<double> ONE(1.0); + propagateValues(sizeField,ONE); + +// cout << "backgroundMesh3D::size of sizeField: " << sizeField.size() << endl; +} + +//------------------------------------------------------------------------------------------ + +void backgroundMesh3D::propagateValues(DoubleStorageType &dirichlet, simpleFunction<double> &eval_diffusivity, bool in_parametric_plane){ + // same as Size_field::solve() + GRegion *gr = dynamic_cast<GRegion*>(gf); + +#if defined(HAVE_PETSC) + linearSystem<double>* system = 0; + system = new linearSystemPETSc<double>; + + size_t i; + int count; + int count2; + double val; + double volume; + std::set<MVertex*> interior; + std::set<MVertex*>::iterator it; + DoubleStorageType::iterator it2; + + dofManager<double> assembler(system); + + count = 0; + for(it2=dirichlet.begin();it2!=dirichlet.end();it2++){ + assembler.fixVertex(it2->first,0,1,it2->second); + count++; + } + //printf("\n"); + //printf("number of boundary vertices = %d\n",count); + + for(i=0;i<gr->tetrahedra.size();i++){ + interior.insert(gr->tetrahedra[i]->getVertex(0)); + interior.insert(gr->tetrahedra[i]->getVertex(1)); + interior.insert(gr->tetrahedra[i]->getVertex(2)); + interior.insert(gr->tetrahedra[i]->getVertex(3)); + } + + for(it=interior.begin();it!=interior.end();it++){ + it2 = dirichlet.find(*it); + if(it2==dirichlet.end()){ + assembler.numberVertex(*it,0,1); + } + } + + for(i=0;i<gr->tetrahedra.size();i++){ + gr->tetrahedra[i]->setVolumePositive(); + } + + count2 = 0; + volume = 0.0; + laplaceTerm term(0,1,&eval_diffusivity); + for(i=0;i<gr->tetrahedra.size();i++){ + SElement se(gr->tetrahedra[i]); + term.addToMatrix(assembler,&se); + count2++; + volume = volume + gr->tetrahedra[i]->getVolume(); + } + //printf("number of tetrahedra = %d\n",count2); + //printf("volume = %f\n",volume); + + if(assembler.sizeOfR()){ + system->systemSolve(); + } + + for(it=interior.begin();it!=interior.end();it++){ + assembler.getDofValue(*it,0,1,val); + dirichlet.insert(std::pair<MVertex*,double>(*it,val)); + } + + delete system; +#endif +} + +//------------------------------------------------------------------------------------------ + +GPoint backgroundMesh3D::get_GPoint_from_MVertex(const MVertex *v)const{ + return GPoint(v->x(),v->y(),v->z(),dynamic_cast<GRegion*>(gf)); +} + +//------------------------------------------------------------------------------------------ + +MVertex* backgroundMesh3D::get_nearest_neighbor(const MVertex *v){ + double distance; + return get_nearest_neighbor(v->x(),v->y(),v->z(), distance); +} + +//------------------------------------------------------------------------------------------ + +MVertex* backgroundMesh3D::get_nearest_neighbor(const double* xyz){ + double distance; + return get_nearest_neighbor(xyz, distance); +} + +//------------------------------------------------------------------------------------------ + +MVertex* backgroundMesh3D::get_nearest_neighbor(double x, double y, double z){ + double distance; + return get_nearest_neighbor(x,y,z,distance); +} + +//------------------------------------------------------------------------------------------ + +MVertex* backgroundMesh3D::get_nearest_neighbor(double x, double y, double z, double &distance ){ + double xyz[3] = {x,y,z}; + return get_nearest_neighbor(xyz, distance); +} + +//------------------------------------------------------------------------ + +MElementOctree* backgroundMesh3D::getOctree(){ + if(!octree){ + GRegion *gr = dynamic_cast<GRegion*>(gf); + Msg::Debug("Rebuilding BackgroundMesh element octree"); + octree = new MElementOctree(gr->tetrahedra); + } + return octree; +} + +//------------------------------------------------------------------------------------------ + +MVertex* backgroundMesh3D::get_nearest_neighbor(const double* xyz, double & distance ){ + // using the octree instead of ANN, faster. + MElement *elem = const_cast<MElement*>(findElement(xyz[0],xyz[1],xyz[2])); + if (!elem) return NULL; + vector<MVertex*> candidates(elem->getNumVertices()); + vector<double> distances(elem->getNumVertices()); + SPoint3 p(xyz[0],xyz[1],xyz[2]); + for (int i=0;i<elem->getNumVertices();i++){ + MVertex *v = elem->getVertex(i); + candidates[i] = v; + distances[i] = p.distance(v->point()); + } + vector<double>::iterator itmax = std::max_element(distances.begin(),distances.end()); + return candidates[std::distance(distances.begin(),itmax)]; + + +// map<double,MVertex*> distances; +// SPoint3 p(xyz[0],xyz[1],xyz[2]); +// for (int i=0;i<elem->getNumVertices();i++){ +// MVertex *v = elem->getVertex(i); +// distances.insert(make_pair(p.distance(v->point()),v)); +// } +// map<double,MVertex*>::iterator it = distances.begin(); +// distance = it->first; +// return it->second; +} + +//------------------------------------------------------------------------------------------ +//------------------------------------------------------------------------------------------ +//------------------------------------------------------------------------------------------ +//------------------------------------------------------------------------------------------ +//------------------------------------------------------------------------------------------ +//------------------------------------------------------------------------------------------ + +vector<montripletbis> frameFieldBackgroundMesh3D::permutation = vector<montripletbis>(); + +//------------------------------------------------------------------------------------------ + +frameFieldBackgroundMesh3D::frameFieldBackgroundMesh3D(GRegion *_gr):backgroundMesh3D(_gr){ + + +// readValue("param.dat","SMOOTHCF",smooth_the_crossfield); + smooth_the_crossfield = true; + + // for the different "quaternion" permutations... + if (permutation.empty()){ + permutation.push_back(montripletbis( 1, 2, 3)); + permutation.push_back(montripletbis( 2,-1, 3)); + permutation.push_back(montripletbis(-1,-2, 3)); + permutation.push_back(montripletbis(-2, 1, 3)); + permutation.push_back(montripletbis( 2, 1,-3)); + permutation.push_back(montripletbis(-1, 2,-3)); + permutation.push_back(montripletbis(-2,-1,-3)); + permutation.push_back(montripletbis( 1,-2,-3)); + } + + build_vertex_to_element_table(); + + int max_recursion_level=1; + if ((max_recursion_level>3)||(max_recursion_level<1)) throw; + build_neighbors(max_recursion_level); + + initiate_ANN_research(); + initiate_crossfield(); + + if (smooth_the_crossfield){ + computeCrossField(); + } + else{ + computeSmoothnessOnlyFromBoundaries(); + } +} + +//------------------------------------------------------------------------------------------ + +frameFieldBackgroundMesh3D::~frameFieldBackgroundMesh3D(){ +#if defined(HAVE_ANN) + if(annTreeBnd) delete annTreeBnd; + if(dataPtsBnd) annDeallocPts(dataPtsBnd); +#endif +} + +//------------------------------------------------------------------------------------------ + +void frameFieldBackgroundMesh3D::initiate_ANN_research(){ +#ifdef HAVE_ANN + // ANN research for 2D !!! + int maxPts = listOfBndVertices.size(); + dataPtsBnd= annAllocPts(maxPts, 3); + int i=0; + MVertex *v; + for (set<MVertex*>::iterator it = listOfBndVertices.begin();it!=listOfBndVertices.end();it++){ + v= *it; + for (int k=0; k< 3; ++k) + dataPtsBnd[i][k] = (v->point())[k]; + ++i; + } + annTreeBnd=new ANNkd_tree(dataPtsBnd, maxPts , 3); +#endif + return; +} + +//------------------------------------------------------------------------------------------ + +void frameFieldBackgroundMesh3D::computeSmoothnessOnlyFromBoundaries(){ + // this is used when the crossfield is not smoothed !!! + // otherwise, the smoothness is computed on the fly while smoothing the cf ! + + smoothness_threshold = 0.; + MVertex* current; + set<MVertex*> neighbors; + multimap<double,MVertex*> themap; + SVector3 mean_axis(0.); + double mean_angle=0.; + vector<double> vectorial_smoothness(3); + + for (vert2elemtype::iterator it_vertex=vert2elem.begin();it_vertex!=vert2elem.end();it_vertex++){// for all vertices + themap.clear(); + neighbors.clear(); + current = it_vertex->first; + pair<graphtype::iterator,graphtype::iterator> range = graph.equal_range(current); + graphtype::iterator itgraph = range.first; + for (;itgraph!=range.second;itgraph++){// for all neighbors + neighbors.insert(itgraph->second.second); + } + for (set<MVertex*>::iterator it= neighbors.begin();it!=neighbors.end();it++){ + themap.insert(make_pair(1.,*it)); + } + + TensorStorageType::iterator itcurrent = crossField.find(current); + STensor3 &ref = itcurrent->second; + multimap<double,MVertex*>::iterator it_neighbors_begin = themap.begin(); + + crossFieldSmoothness[current] = compare_to_neighbors(current->point(), ref, it_neighbors_begin, themap.end(), mean_axis,mean_angle,vectorial_smoothness); +// crossFieldVectorialSmoothness[current] = vectorial_smoothness; + } +} + +//------------------------------------------------------------------------------------------ + +void frameFieldBackgroundMesh3D::computeCrossField(){ + // TODO: mettre des parametres façon gmsh ??? + // reading parameters + int Niter = 3; + double norme_threshold = 1.; + double localangle_threshold = 1.; + + Niter=40; + norme_threshold = 3.e-2; + localangle_threshold=5.e-3; + smoothness_threshold=0.85; + double percentage_threshold = 0.98; + + + vector<double> scal_prods; + vector<double> signs; + vector<double> angles; + STensor3 identity(1.); + + if (debug) exportCrossField("cf_initial.pos"); + + // initiation + multimap<double,MVertex*> rank,rank_temp; + map<MVertex*,bool> vertex_is_still; + map<MVertex*,double> vertex_movement; + MVertex *current; + for (vert2elemtype::iterator it_vertex=vert2elem.begin();it_vertex!=vert2elem.end();it_vertex++){ + current = it_vertex->first; + if (current->onWhat()->dim()<=2) + vertex_is_still[current] = true; + else + vertex_is_still[current] = false; + rank.insert(make_pair(0.,current)); + } + + // OLD - NEW COMPARISON + map<MVertex*,double> vertex_to_rank; + for (vert2elemtype::iterator it_vertex=vert2elem.begin();it_vertex!=vert2elem.end();it_vertex++){// for all vertices + //vertex_to_rank[it_vertex->first] = 0.; + vertex_to_rank[it_vertex->first] = 1.; + rank.insert(make_pair(0.,it_vertex->first)); + } + // END OLD - NEW COMPARISON + + + + double percentage_not_done=0.; + double norme = 10.*norme_threshold; + double norme_inf=10.*norme_threshold; + int iIter=0; + SVector3 mean_axis(0.); + double mean_angle=0.; + vector<double> vectorial_smoothness(3); +// vector<int> nb_local_iterations; + + + // main smoothing loop + while (((norme_inf>norme_threshold) && (percentage_not_done<percentage_threshold)) && (iIter<Niter)){// for maximum Niter iterations, or until convergence +// nb_local_iterations.clear(); + angles.clear(); + norme_inf=0.; + int counter_done=0; + int counter_not_done=0; + while (rank.size()){// for all vertices, i.e. all cavities + // for (vert2elemtype::iterator it_vertex=vert2elem.begin();it_vertex!=vert2elem.end();it_vertex++)// for all vertices, i.e. all cavities + //MVertex *current = it_vertex->first; + current = (rank.begin())->second; + rank.erase((rank.begin())); + + + // smooth 3D vertices only + if (current->onWhat()->dim()<=2){ + if (verbose) cout << "-------------------- discard point " << current->getNum() << " on dim " << current->onWhat()->dim() << " coord (" << current->x() << "," << current->y() << "," << current->z()<< ")" << endl; + continue; + } + + TensorStorageType::iterator itcurrent = crossField.find(current); + STensor3 &ref = itcurrent->second; + if (verbose) cout << "-------------------- working on point " << current->getNum() << " on dim " << current->onWhat()->dim() << " coord (" << current->x() << "," << current->y() << "," << current->z()<< ")" << endl; + + pair<graphtype::iterator, graphtype::iterator> range = graph.equal_range(current); + graphtype::iterator itgraph = range.first; + bool all_neighbors_still=true;// if nothing has changed since previous iteration: nothing to do ! + for (;itgraph!=range.second;itgraph++){// for all neighbors + if (vertex_is_still[itgraph->second.second]==false){ + all_neighbors_still = false; + break; + } + } + + if (all_neighbors_still && vertex_is_still[current]){// neighbors didn't move, and current didn't move either -> nothing to do ! + vertex_movement[current] = 0.; + rank_temp.insert(make_pair(0.,current)); + counter_not_done++; + continue; + } + + + + // OLD - NEW COMPARISON + multimap<double,MVertex*> neighbors_to_trust; + itgraph = range.first; + for (;itgraph!=range.second;itgraph++){// for all neighbors + neighbors_to_trust.insert(make_pair(vertex_to_rank[itgraph->second.second],itgraph->second.second)); + // if (vertex_to_rank[itgraph->second.second] <= 1. /180.*M_PI){ + // neighbors_to_trust.insert(make_pair(vertex_to_rank[itgraph->second.second],itgraph->second.second)); + // } + } + if (!neighbors_to_trust.size()){ + rank_temp.insert(make_pair(M_PI,current)); + vertex_to_rank[current] = M_PI; + continue; + } + // END OLD - NEW COMPARISON + + + + + + + counter_done++; + + double angle_to_go;; + + int Nlocaliter=0; + STensor3 ref_original(ref); + + for (;Nlocaliter<20;Nlocaliter++){// iterations, convergence of the local cavity... + multimap<double,MVertex*>::iterator it_neighbors_to_trust = neighbors_to_trust.begin(); + crossFieldSmoothness[current] = compare_to_neighbors(current->point(), ref, it_neighbors_to_trust, neighbors_to_trust.end(), mean_axis,mean_angle,vectorial_smoothness); +// crossFieldVectorialSmoothness[current] = vectorial_smoothness; + + // rotating directions to align closest vectors... + angle_to_go = mean_angle; + ref = apply_rotation(mean_axis,angle_to_go,ref); + // cout << " iter " << Nlocaliter << ": mean_angle = " << mean_angle << endl; + if (fabs(mean_angle)<localangle_threshold/3.) break; + } +// nb_local_iterations.push_back(Nlocaliter+1); + if (verbose) cout << "iIter " << iIter << ", Nlocaliter = " << Nlocaliter << endl; + + + // computing the total rotation + //get_min_rotation_matrix(ref_original, ref, mean_angle, mean_axis,localangle_threshold,true); + get_min_rotation_matrix(ref_original, ref, mean_angle, mean_axis,localangle_threshold);//,true); + norme_inf = max(norme_inf,mean_angle); + // cout << " #local_iter=" << Nlocaliter << " final mean_angle = " << mean_angle << " threshold=" << localangle_threshold << " condition :" << (mean_angle <= localangle_threshold) << endl; + + + angles.push_back(mean_angle); + vertex_is_still[current] = (mean_angle <= localangle_threshold); + vertex_movement[current] = mean_angle; + rank_temp.insert(make_pair(mean_angle,current)); + // OLD - NEW COMPARISON + //vertex_to_rank[current] = mean_angle; + vertex_to_rank[current] = crossFieldSmoothness[current]; + // // HACK + // vertex_to_rank[current] = 0.; + // END OLD - NEW COMPARISON + + }// end vertices loop + + rank = rank_temp; + rank_temp.clear(); + + norme = std::accumulate(angles.begin(),angles.end(),0.); + if (angles.size()) norme = norme/M_PI*180./angles.size(); + percentage_not_done = ((double)counter_not_done)/(counter_done+counter_not_done); + cout << " --- iter " << iIter << " NormeInf=" << norme_inf << " mean Angle=" << norme << " counter_not_done=" << counter_not_done << " NotDone (%)=" << (percentage_not_done*100.) << " %" << endl; +// cout << "Average number of local iterations: " << ((double)std::accumulate(nb_local_iterations.begin(),nb_local_iterations.end(),0))/nb_local_iterations.size() << endl; + + //if (debug){ + double temp = log10(Niter); + stringstream ss; + ss << "cf_iter_" << setfill('0') << setw ((int)(ceil(temp))) << iIter << ".pos"; + exportCrossField(ss.str().c_str()); + //} + + iIter++; + }// end Niter iterations + + + + // also computes smoothness for boundary points + for (vert2elemtype::iterator it_vertex=vert2elem.begin();it_vertex!=vert2elem.end();it_vertex++){ + current = it_vertex->first; + if (current->onWhat()->dim()<=2){ + TensorStorageType::iterator itcurrent = crossField.find(current); + STensor3 &ref = itcurrent->second; + pair<graphtype::iterator, graphtype::iterator> range = graph.equal_range(current); + graphtype::iterator itgraph = range.first; + + + multimap<double,MVertex*> neighbors_to_trust; + itgraph = range.first; + for (;itgraph!=range.second;itgraph++){// for all neighbors + neighbors_to_trust.insert(make_pair(0.,itgraph->second.second)); + } + crossFieldSmoothness[current] = compare_to_neighbors(current->point(), ref, neighbors_to_trust.begin(), neighbors_to_trust.end(), mean_axis,mean_angle,vectorial_smoothness); + + //crossFieldSmoothness[current] = compare_to_neighbors(current->point(), ref, itgraph, range.second, mean_axis,mean_angle,vectorial_smoothness); +// crossFieldVectorialSmoothness[current] = vectorial_smoothness; + } + } + + + + return; + +} + +//------------------------------------------------------------------------------------------ + +//STensor3 frameFieldBackgroundMesh3D::get_random_cross()const{ +// SVector3 vec1(rand()%10000/9999. , rand()%10000/9999. , rand()%10000/9999. ); +// vec1.normalize(); +// SVector3 ref(1.,0.,0.); +// SVector3 vec2 = crossprod(ref,vec1); +// vec2.normalize(); +// SVector3 vec3 = crossprod(vec1,vec2); +// vec3.normalize(); +// STensor3 random_cross; +// for (int j=0;j<3;j++){ +// random_cross(j,0) = vec1(j); +// random_cross(j,1) = vec2(j); +// random_cross(j,2) = vec3(j); +// } +// return random_cross; +//} + +//------------------------------------------------------------------------------------------ + +void frameFieldBackgroundMesh3D::initiate_crossfield(){ + crossField.clear(); + MVertex *v; + + // first, for boundaries : + GRegion *gr = dynamic_cast<GRegion*>(gf); + list<GFace*> faces = gr->faces(); + // here, not using the gm2D since we are interested by the new 2D vertices, not the old (now erased) ones... alternative would be to reset the 2DBGM... + for (list<GFace*>::iterator it=faces.begin();it!=faces.end();it++){// for all GFace + GFace *face = *it; + frameFieldBackgroundMesh2D *bgm2d = dynamic_cast<frameFieldBackgroundMesh2D*>(BGMManager::get(face)); + // initializing the vertices on the faces + for (unsigned int i=0;i<face->getNumMeshElements();i++){// for all elements + MElement *e = face->getMeshElement(i); + if (e->getDim()!=2) continue;// of dim=2 + + for (int iv=0;iv<e->getNumVertices();iv++){ + v = e->getVertex(iv); + + // if already done: continue + TensorStorageType::iterator itfind = crossField.find(v); + if (itfind!=crossField.end()) continue; + + STensor3 cf; + bgm2d->eval_crossfield(v,cf); + crossField[v] = cf; + } + } + } + + // then, for volume : + for (unsigned int i=0;i<gr->getNumMeshElements();i++){// for all elements + MElement *e = gr->getMeshElement(i); + if (e->getDim()!=3) continue; + + for (int iv=0;iv<e->getNumVertices();iv++){ + v = e->getVertex(iv); + + // if not in volume: continue + if (v->onWhat()->dim()<=2) continue; + // if already done: continue + TensorStorageType::iterator itfind = crossField.find(v); + if (itfind!=crossField.end()) continue; + MVertex *closer_on_bnd = get_nearest_neighbor_on_boundary(v); + crossField[v] = crossField[closer_on_bnd];// prend l'info Bnd (ANN) la plus proche... + } + } +} + +//------------------------------------------------------------------------------------------ + +MVertex* frameFieldBackgroundMesh3D::get_nearest_neighbor_on_boundary(MVertex* v){ + double distance; + return get_nearest_neighbor_on_boundary(v,distance); +} + +//------------------------------------------------------------------------------------------ + +MVertex* frameFieldBackgroundMesh3D::get_nearest_neighbor_on_boundary(MVertex* v, double &distance){ +#ifdef HAVE_ANN + ANNpoint q = annAllocPt(3); + for (int k=0; k< 3; ++k) + q[k] = v->point()[k]; + ANNidxArray nn_idx = new ANNidx[1]; + ANNdistArray dists = new ANNdist[1]; + annTreeBnd->annkSearch(q, 1, nn_idx, dists ); + distance = sqrt(dists [0]); + int i = nn_idx[0]; + delete [] nn_idx; + delete [] dists; + annDeallocPt(q); + + set<MVertex*>::iterator it = listOfBndVertices.begin(); + std::advance(it,i); + return (*it); +#else + return NULL; +#endif +} + +//------------------------------------------------------------------------------------------ + +double frameFieldBackgroundMesh3D::get_smoothness(double x, double y, double z){ + return get_field_value(x,y,z,crossFieldSmoothness); +}; + +//------------------------------------------------------------------------------------------ + +double frameFieldBackgroundMesh3D::get_approximate_smoothness(double x, double y, double z){ + return crossFieldSmoothness[get_nearest_neighbor(x,y,z)]; +} + +//------------------------------------------------------------------------------------------ + +double frameFieldBackgroundMesh3D::get_approximate_smoothness(MVertex *v){ + return get_approximate_smoothness(v->x(),v->y(),v->z()); +} + +//------------------------------------------------------------------------------------------ + +double frameFieldBackgroundMesh3D::get_smoothness(MVertex *v){ + return get_nodal_value(v,crossFieldSmoothness); +}; + +//------------------------------------------------------------------------------------------ + +void frameFieldBackgroundMesh3D::eval_approximate_crossfield(double x, double y, double z, STensor3 &cf){ + cf = crossField[get_nearest_neighbor(x,y,z)]; +}; + +//------------------------------------------------------------------------------------------ + +void frameFieldBackgroundMesh3D::eval_approximate_crossfield(const MVertex *vert, STensor3 &cf){ + // check if vertex is ours... + TensorStorageType::const_iterator itfind = crossField.find(const_cast<MVertex*>(vert)); + if (itfind != crossField.end()) + cf = itfind->second; + else// if not, find closest + eval_approximate_crossfield(vert->x(),vert->y(),vert->z(),cf); +}; + +//------------------------------------------------------------------------------------------ + +void frameFieldBackgroundMesh3D::get_vectorial_smoothness(double x, double y, double z, SVector3 &cf){ + vector<double>res = get_field_value(x,y,z,crossFieldVectorialSmoothness); + for (int i=0;i<3;i++) cf(i)=res[i]; +}; + +//------------------------------------------------------------------------------------------ + +void frameFieldBackgroundMesh3D::get_vectorial_smoothness(const MVertex *vert, SVector3 &cf){ + vector<double> res = get_nodal_value(vert,crossFieldVectorialSmoothness); + for (int i=0;i<3;i++) cf(i)=res[i]; +}; + +//------------------------------------------------------------------------------------------ + +double frameFieldBackgroundMesh3D::get_vectorial_smoothness(const int idir, double x, double y, double z){ + vector<double>res = get_field_value(x,y,z,crossFieldVectorialSmoothness); + return res[idir]; +}; + +//------------------------------------------------------------------------------------------ + +double frameFieldBackgroundMesh3D::get_vectorial_smoothness(const int idir, const MVertex *vert){ + vector<double> res = get_nodal_value(vert,crossFieldVectorialSmoothness); + return res[idir]; +}; + +//------------------------------------------------------------------------------------------ + +void frameFieldBackgroundMesh3D::build_vertex_to_element_table(){ + GRegion *gr = dynamic_cast<GRegion*>(gf); + MElement *e; + MVertex *v; + + // cout << "build_vertex_to_element_table nbelem=" << gr->getNumMeshElements() << endl; + + for (unsigned int i=0;i<gr->getNumMeshElements();i++){// for all elements + e = gr->getMeshElement(i); + if (e->getDim()!=3) continue;// of dim=3 + // cout << "elem " << i << endl; + for (int iv=0;iv<e->getNumVertices();iv++){// for all vertices + v = e->getVertex(iv); + vert2elem[v].insert(e); + elem2vert[e].insert(v); + // cout << "node " << iv << " on " << v->onWhat()->dim() << endl; + if (v->onWhat()->dim()<=2){ + // cout << "adding " << endl; + listOfBndVertices.insert(v); + } + } + } +} + +//------------------------------------------------------------------------ + +const MElement* backgroundMesh3D::getElement(unsigned int i)const{ + GRegion *gr = dynamic_cast<GRegion*>(gf); + return gr->getMeshElement(i); +} + +//------------------------------------------------------------------------ + +unsigned int backgroundMesh3D::getNumMeshElements()const{ + GRegion *gr = dynamic_cast<GRegion*>(gf); + return gr->getNumMeshElements(); +} + +//------------------------------------------------------------------------------------------ + +// this function fills the multimap "graph": vertex to direct neighbors, or indirect neighbors, depending on the "max_recursion_level". +void frameFieldBackgroundMesh3D::build_neighbors(const int &max_recursion_level){ + + set<MVertex*> visited,start; + set<MElement*> visited_elements; + multimap<int,MVertex*> proximity; + //int counter=0; + + for (vert2elemtype::iterator it_vertex=vert2elem.begin();it_vertex!=vert2elem.end();it_vertex++){// for all vertices + MVertex *current_vertex = it_vertex->first; + visited.clear(); + visited_elements.clear(); + visited.insert(current_vertex); + start.clear(); + start.insert(current_vertex); + proximity.clear(); + + get_recursive_neighbors(start, visited, visited_elements, proximity, max_recursion_level); + + for (multimap<int,MVertex*>::iterator it1 = proximity.begin();it1!=proximity.end();it1++){ + graph.insert(make_pair(current_vertex, make_pair(it1->first,it1->second))); + } + + // if (debug){// check + // if (verbose) cout << "vertex (" << counter++ << "): " << current_vertex->getNum() << " connected to " << it_vertex->second.size() << " elements, coord: (" << current_vertex->x() << "," << current_vertex->y() << "," << current_vertex->z() << ")" << endl; + // set<MVertex*> allvertex; + // for (multimap<int,MVertex*>::iterator it1 = proximity.begin();it1!=proximity.end();it1++){ + // if (verbose) { + // for (int i=0;i<it1->first;i++) cout << " "; + // cout << it1->first << " : " << it1->second->getNum() << endl; + // } + // set<MVertex*>::iterator itfind = allvertex.find(it1->second); + // if (itfind!=allvertex.end()){ + // cerr << " ERROR : vertex duplicate !!!" << endl; + // throw; + // } + // allvertex.insert(it1->second); + // } + // }// end check + } +} + +//------------------------------------------------------------------------------------------ + +void frameFieldBackgroundMesh3D::get_recursive_neighbors(set<MVertex*> &start, set<MVertex*> &visited, set<MElement*> &visited_elements, multimap<int,MVertex*> &proximity, int max_level, int level){ + level++; + if (level>max_level) return; + + set<MVertex*> new_vertices; + + for (set<MVertex*>::iterator it_start=start.begin();it_start!=start.end();it_start++){// for all initial vertices + MVertex *current = *it_start; + // cout << "get_recursive_neighbors : on vertex " << current->getNum() << " (" << current << ")" << endl; + vert2elemtype::iterator itfind = vert2elem.find(current); + if (itfind==vert2elem.end()) continue; + set<MElement*>::iterator it_elem = itfind->second.begin(); + for (;it_elem!=itfind->second.end();it_elem++){// for all connected elements + MElement *current_elem = *it_elem; + // cout << " get_recursive_neighbors : on elem " << current_elem; + set<MElement*>::iterator itfindelem = visited_elements.find(current_elem); + if (itfindelem!=visited_elements.end()){// element already visited + // cout << " ... already visited ! " << endl; + continue; + } + // cout << current_elem->getNum() << endl; + for (int i=0;i<current_elem->getNumVertices();i++){ + MVertex *ver = current_elem->getVertex(i); + set<MVertex*>::iterator itfind_vertex = visited.find(ver); + if (itfind_vertex!=visited.end()) continue;// vertex already visited + proximity.insert(make_pair(level, ver)); + new_vertices.insert(ver); + visited.insert(ver); + } + visited_elements.insert(current_elem); + } + } + + get_recursive_neighbors(new_vertices, visited, visited_elements, proximity, max_level, level); + +} + +//------------------------------------------------------------------------------------------ + +double frameFieldBackgroundMesh3D::compare_to_neighbors(SPoint3 current, STensor3 &ref, multimap<double,MVertex*>::iterator itbegin, multimap<double,MVertex*>::iterator itend, SVector3 &mean_axis,double &mean_angle, vector<double> &vectorial_smoothness){ + for (int i=0;i<3;i++) mean_axis(i)=0.; + multimap<double,MVertex*>::iterator it = itbegin; + SVector3 rotation_axis; + double minimum_angle; + MVertex *neighbor; + vector<double>all_angle; + vector<SVector3>all_axis; + TensorStorageType::iterator itneighbor; + +// vectorial_smoothness.assign(3,0.); +// vector<double> temp(3); + + vector<double> ponderations_vec; + + vector<double> alternative; + + for (;it!=itend;it++){// for all trusted neighbors + //neighbor = it->second.second; + neighbor = it->second; + //ponderations_vec.push_back(1.); + ponderations_vec.push_back((fabs(it->first) >= smoothness_threshold) ? 1. : 1.e-3); + //ponderations_vec.push_back(((fabs(it->first) >= smoothness_threshold) ? 1. : 1.e-3) / (current.distance(neighbor->point()))); + itneighbor = crossField.find(neighbor); + STensor3 &neibcross = itneighbor->second; + + get_min_rotation_matrix(neibcross, ref, minimum_angle, rotation_axis); + all_axis.push_back(rotation_axis); + all_angle.push_back(minimum_angle); + alternative.push_back(fabs(minimum_angle)); + +// // now, computing vectorial smoothness +// for (int j=0;j<3;j++){// for every cross field vector +// temp.assign(3,0.); +// for (int ivec=0;ivec<3;ivec++){// for every neighbor vector +// for (int k=0;k<3;k++){ +// temp[ivec] += (neibcross(k,ivec)*ref(k,j));// scalar products +// } +// temp[ivec] = fabs(temp[ivec]); +// } +// vectorial_smoothness[j] += acos(fmin(*std::max_element(temp.begin(),temp.end()),1.)); +// } + + + } + + // Watch out !!! acos(mean_angle) != mean_acos -> second option gives better results, better contrast between smooth and not smooth +// for (int j=0;j<3;j++){ +// vectorial_smoothness[j] = (1. - (vectorial_smoothness[j]/all_angle.size())/M_PI*4.);// between 0 (not smooth) and 1 (smooth) +// } + + + // ---------------------------------------------------------------------------- + // Watch out !!! The following definition of smoothness may change A LOT !!! + // ---------------------------------------------------------------------------- + // may seem against intuition in some case, but min gives much better results + // finally... mean angle !!! + +// double smoothness_scalar = (*std::max_element(vectorial_smoothness.begin(),vectorial_smoothness.end())); +// double smoothness_scalar = (*std::min_element(vectorial_smoothness.begin(),vectorial_smoothness.end())); + double smoothness_scalar = 1. - (std::accumulate(alternative.begin(),alternative.end(),0.)/alternative.size())/M_PI*4.;// APPROXIMATELY between 0 (not smooth) and 1 (smooth), (sometimes <0, always > 1). + + + + + vector<double>::iterator itan=all_angle.begin(); + vector<double>::iterator itpond=ponderations_vec.begin(); + + for (vector<SVector3>::iterator ita = all_axis.begin();ita!=all_axis.end();ita++,itan++,itpond++){ + //mean_axis += ((*ita)*(*itan)); + mean_axis += ((*ita)*(*itan))*(*itpond); + } + + //mean_angle = mean_axis.norm()/all_angle.size(); + double pond_total = std::accumulate(ponderations_vec.begin(),ponderations_vec.end(),0.); + mean_angle = mean_axis.norm()/pond_total; + mean_axis.normalize(); + + + + return smoothness_scalar; +} + +//------------------------------------------------------------------------------------------ + +STensor3 frameFieldBackgroundMesh3D::apply_rotation(const SVector3 &axis, const double &angle, const STensor3 &thecross){ + double rotmat[3][3]; + STensor3 res2; + get_rotation_matrix(angle,axis,&rotmat[0][0]); + + + // cout << "from matrice, rotation of " << angle/M_PI*180 << "° axis(" << axis(0) << "," << axis(1) << "," << axis(2) << ")" << endl; + // cout << "rotation matrix is :" << endl; + // for (int i=0;i<3;i++){ + // for (int j=0;j<3;j++) + // cout << rotmat[i][j] << " "; + // cout << endl; + // } + // + + + for (int i=0;i<3;i++) + for (int j=0;j<3;j++) + for (int k=0;k<3;k++) + res2(i,j) += rotmat[i][k] * thecross(k,j); + // return res; + + + // cout << "result:" << endl; + // for (int i=0;i<3;i++){ + // for (int j=0;j<3;j++) + // cout << res2(i,j) << " "; + // cout << endl; + // } + + + // STensor3 res; + // double crossv[4],q[4],qconj[4],resq[4]; + // double coss = cos(angle/2.); + // double sinn = sin(angle/2.); + // q[0] = coss; + // q[1] = sinn*axis[0]; + // q[2] = sinn*axis[1]; + // q[3] = sinn*axis[2]; + // qconj[0] = q[0]; + // for (int i=1;i<4;i++) qconj[i] = -q[i]; + // + // for (int i=0;i<3;i++){ + // crossv[0] = 0.; + // crossv[1] = thecross(0,i); + // crossv[2] = thecross(1,i); + // crossv[3] = thecross(2,i); + // + //// quat_prod(q,crossv,resq); + //// quat_prod(resq,qconj,resq); + // quat_prod(crossv,qconj,resq); + // quat_prod(q,resq,resq); + // for (int j=0;j<3;j++) + // res(j,i)=resq[j+1]; + // + // } + // cout << "from quat:" << endl; + // for (int i=0;i<3;i++){ + // for (int j=0;j<3;j++) + // cout << res(j,i) << " "; + // cout << endl; + // } + // cout << "w="<<resq[0] << endl; + return res2; + + + // STensor3 res; + // double coss = cos(angle); + // double sinn = sin(angle); + // SVector3 temp; + // for (int i=0;i<3;i++){ + // SVector3 v(thecross(0,i),thecross(1,i),thecross(2,i)); + // temp = axis*my_scal_prod(axis,v); + // SVector3 vres = (v - temp)*coss + crossprod(axis,v)*sinn + temp; + // for (int j=0;j<3;j++) + // res(j,i)=vres(j); + // } + // return res; +} + +//------------------------------------------------------------------------------------------ + +// TODO: ce genre de fct... mettre dans une classe FrameField ? Ou bien juste un set de fcts à part ? Parce que ça devient bizarre d'avoir ça dans un BGM ??? +void frameFieldBackgroundMesh3D::get_rotation_matrix(const double &angle_to_go, const SVector3 &rotvec, double* rotmat){ + + double c = cos(angle_to_go); + double s = sin(angle_to_go); + double temp01 = rotvec[0]*rotvec[1]*(1.-c); + double temp02 = rotvec[0]*rotvec[2]*(1.-c); + double temp12 = rotvec[1]*rotvec[2]*(1.-c); + double square0 = rotvec[0]*rotvec[0]; + double square1 = rotvec[1]*rotvec[1]; + double square2 = rotvec[2]*rotvec[2]; + rotmat[0] = square0 +(1.-square0)*c; + rotmat[1] = temp01-rotvec[2]*s; + rotmat[2] = temp02+rotvec[1]*s; + rotmat[3] = temp01+rotvec[2]*s; + rotmat[4] = square1 +(1.-square1)*c; + rotmat[5] = temp12-rotvec[0]*s; + rotmat[6] = temp02-rotvec[1]*s; + rotmat[7] = temp12+rotvec[0]*s; + rotmat[8] = square2 +(1.-square2)*c; +} + +//------------------------------------------------------------------------------------------ + +void frameFieldBackgroundMesh3D::get_min_rotation_matrix(const STensor3 &reference, const STensor3 &thecross, double &minimum_angle, SVector3 &rotation_axis, double threshold, bool debugflag){ + + minimum_angle = M_PI/2.; + pair<int,int> p; + + for (unsigned int iperm=0;iperm<permutation.size();iperm++){ + if (minimum_angle<threshold) break; + for (int i_rotation_perm=0;i_rotation_perm<3;i_rotation_perm++){ + double a; + SVector3 v; + get_rotation_angle_and_axis(reference,thecross,a,v,i_rotation_perm,permutation[iperm]); + if (debugflag){ + if (fabs(a)<M_PI/2.){ + cout << " temp parameters: angle=" << a*180./M_PI << "pair=(" << iperm << "," << i_rotation_perm << ") axis=(" << v(0) << "," << v(1) << "," << v(2) << ")" << endl; + } + else + cout << " temp parameters: angle=" << a*180./M_PI << endl; + } + if (fabs(a)<fabs(minimum_angle)){ + p = make_pair(iperm,i_rotation_perm); + minimum_angle = a; + rotation_axis = v; + } + + + if (minimum_angle<threshold) break; + } + } + // cout << "pair=(" << p.first << "," << p.second << ")" << endl; + if (debugflag){ + cout << " ---> MIN parameters: angle=" << minimum_angle*180./M_PI << " axis=(" << rotation_axis(0) << "," << rotation_axis(1) << "," << rotation_axis(2) << ")" << endl; + } + return; +} + +//------------------------------------------------------------------------------------------ + +// compute the angle and axis of rotation between two (unit-orthogonal) cross fields +// using crossfield vectors permutations defined by modulo and trip +// The rotation matrix between cross fields C and M is R = C M^T +void frameFieldBackgroundMesh3D::get_rotation_angle_and_axis(const STensor3 &reference, const STensor3 &thecross, double &minimum_angle, SVector3 &rotation_axis, int modulo, montripletbis &trip){ + + //double MT[3][3],C[3][3],R[3][3]; + double C[3][3],R[3][3]; + + for (int i=0;i<3;i++){ + for (int j=0;j<3;j++){ + C[i][j] = signof(trip(j)) * thecross(i,((abs(trip(j))-1)+modulo)%3); + //MT[j][i] = reference(i,j);//transpose ! + } + } + + // //////////////////// + // for (int k=0;k<2;k++){ + // double test1 = C[0][k]*C[0][k]*C[1][k]*C[1][k] + C[0][k]*C[0][k]*C[2][k]*C[2][k] + C[2][k]*C[2][k]*C[1][k]*C[1][k]; + // double test2 = reference(0,k)*reference(0,k)*reference(1,k)*reference(1,k) + reference(0,k)*reference(0,k)*reference(2,k)*reference(2,k) + reference(2,k)*reference(2,k)*reference(1,k)*reference(1,k); + // cout << " --- k=" << k << " test1=" << test1 << endl; + // cout << " --- k=" << k << " test2=" << test2 << endl; + // } + // //////////////////// + + // computing the trace for the angle... + // MT is transpose of reference !!! + // R[0][0] = C[0][0]*MT[0][0] + C[0][1]*MT[1][0] + C[0][2]*MT[2][0]; + // R[1][1] = C[1][0]*MT[0][1] + C[1][1]*MT[1][1] + C[1][2]*MT[2][1]; + // R[2][2] = C[2][0]*MT[0][2] + C[2][1]*MT[1][2] + C[2][2]*MT[2][2]; + R[0][0] = C[0][0]*reference(0,0) + C[0][1]*reference(0,1) + C[0][2]*reference(0,2); + R[1][1] = C[1][0]*reference(1,0) + C[1][1]*reference(1,1) + C[1][2]*reference(1,2); + R[2][2] = C[2][0]*reference(2,0) + C[2][1]*reference(2,1) + C[2][2]*reference(2,2); + + // computing rotation angle + double trace = R[0][0] + R[1][1] + R[2][2]; + minimum_angle = acos(max(min(0.5*(trace-1.),1.),-1.));// tjrs > 0 + + // cout << "minimum_angle=" << minimum_angle << " trace=" << trace << endl; + + if (fabs(minimum_angle)>M_PI/2.) return;// no need to continue... + + // computing rotation axis + // computing the remaining terms, not on diagonal + if (fabs(minimum_angle)<1.e-6){ + rotation_axis(0)=0.; + rotation_axis(1)=0.; + rotation_axis(2)=1.; + return; + } + + R[0][1] = C[0][0]*reference(1,0) + C[0][1]*reference(1,1) + C[0][2]*reference(1,2); + R[0][2] = C[0][0]*reference(2,0) + C[0][1]*reference(2,1) + C[0][2]*reference(2,2); + R[1][0] = C[1][0]*reference(0,0) + C[1][1]*reference(0,1) + C[1][2]*reference(0,2); + R[1][2] = C[1][0]*reference(2,0) + C[1][1]*reference(2,1) + C[1][2]*reference(2,2); + R[2][0] = C[2][0]*reference(0,0) + C[2][1]*reference(0,1) + C[2][2]*reference(0,2); + R[2][1] = C[2][0]*reference(1,0) + C[2][1]*reference(1,1) + C[2][2]*reference(1,2); + + double factor = -0.5/sin(minimum_angle); + rotation_axis(0) = (R[2][1]-R[1][2])*factor; + rotation_axis(1) = (R[0][2]-R[2][0])*factor; + rotation_axis(2) = (R[1][0]-R[0][1])*factor; + return; +} + +//------------------------------------------------------------------------ + +void frameFieldBackgroundMesh3D::exportVectorialSmoothness(const string &filename){ + FILE *f = Fopen (filename.c_str(),"w"); + fprintf(f,"View \"Background Mesh\"{\n"); + + set<const MVertex*> done; + + for (unsigned int ie=0;ie<getNumMeshElements();ie++){// for all elements + const MElement *e = getElement(ie); + for (int iv = 0;iv<e->getNumVertices();iv++){ + const MVertex *v = e->getVertex(iv); + set<const MVertex*>::iterator itfind = done.find(v); + if (itfind!=done.end()) continue; + done.insert(v); + STensor3 cf; + eval_approximate_crossfield(v,cf); + for (int i=0;i<3;i++){ + double vs = get_vectorial_smoothness(i,v); + fprintf(f,"VP(%g,%g,%g){%g,%g,%g};\n",v->x(),v->y(),v->z(),cf(0,i)*vs,cf(1,i)*vs,cf(2,i)*vs); + } + } + } + fprintf(f,"};\n"); + fclose(f); +} + +//------------------------------------------------------------------------------------------ + diff --git a/Mesh/BackgroundMesh3D.h b/Mesh/BackgroundMesh3D.h new file mode 100644 index 0000000000..544555a738 --- /dev/null +++ b/Mesh/BackgroundMesh3D.h @@ -0,0 +1,176 @@ +// 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@geuz.org>. + +#ifndef _BACKGROUND_MESH3D_H_ +#define _BACKGROUND_MESH3D_H_ + +#include <set> +#include <vector> +#include <map> +#include <fstream> +#include <sstream> +#include <iostream> +#include <iomanip> +#include <numeric> + + + +//#include "SVector3.h" +//#include "STensor3.h" +#include "BGMBase.h" + + +#include "pointInsertion.h" + +#if defined(HAVE_ANN) +#include <ANN/ANN.h> +class ANNkd_tree; +#endif + + + +// TODO: do we really need to build the graph vertex2elem-> vertex 2 neighbors ? This was useful for the smoothness computation, if we want to take into account vertices at a given topological distance... but using distance=1, it seems to work... ?! + + +using namespace std; + + + +//------------------------------------------------------------------------------------------ + +class montripletbis{ + public: + ~montripletbis(){}; + montripletbis(int a,int b, int c):vec(3){ + vec[0] = a; + vec[1] = b; + vec[2] = c; + }; + inline int operator()(int i)const{return vec[i];} + private: + vector<int> vec; +}; + +//------------------------------------------------------------------------------------------ + +// difference with BackgroundMesh2D: no copy of components, working directly on the vertices and elements of GRegion + +class backgroundMesh3D : public BGMBase { + protected: + virtual void computeSizeField(); + virtual void propagateValues(DoubleStorageType &dirichlet, simpleFunction<double> &eval_diffusivity, bool in_parametric_plane = false); + virtual GPoint get_GPoint_from_MVertex(const MVertex *) const; + + virtual const MElement* getElement(unsigned int i)const; + virtual unsigned int getNumMeshElements()const; + + const bool debug; + const bool verbose; + + public: + + backgroundMesh3D(GRegion *_gr); + virtual ~backgroundMesh3D(); + + virtual MElementOctree* getOctree(); + + virtual MVertex* get_nearest_neighbor(const double* xyz, double & distance ); + virtual MVertex* get_nearest_neighbor(const double* xyz); + virtual MVertex* get_nearest_neighbor(const MVertex *v); + virtual MVertex* get_nearest_neighbor(double x, double y, double z); + virtual MVertex* get_nearest_neighbor(double x, double y, double z, double &distance ); +}; + +//------------------------------------------------------------------------ + + +class frameFieldBackgroundMesh3D : public backgroundMesh3D{ + public: + typedef tr1::unordered_map<hash_key_ptr, set<MElement*> > vert2elemtype; + typedef tr1::unordered_map<MElement*, set<MVertex*> > elem2verttype; + typedef multimap<MVertex*, pair<int,MVertex*> > graphtype; + + protected: + bool smooth_the_crossfield; + + void initiate_crossfield(); + void initiate_ANN_research(); + void computeCrossField(); + void computeSmoothnessOnlyFromBoundaries(); + + void build_vertex_to_element_table(); + + // fills the multimap "graph": vertex to direct neighbors, or indirect neighbors, depending on the "max_recursion_level". + void build_neighbors(const int &max_recursion_level); + + // function called only by "build_neighbors", recursively recovering vertices neighbors. + void get_recursive_neighbors(set<MVertex*> &start, set<MVertex*> &visited, set<MElement*> &visited_elements, multimap<int,MVertex*> &proximity, int max_level, int level=0); + + + double compare_to_neighbors(SPoint3 current, STensor3 &ref, multimap<double,MVertex*>::iterator itbegin, multimap<double,MVertex*>::iterator itend, SVector3 &mean_axis,double &mean_angle, vector<double> &vectorial_smoothness); + STensor3 apply_rotation(const SVector3 &axis, const double &angle, const STensor3 &thecross); + void get_rotation_matrix(const double &angle_to_go, const SVector3 &rotvec, double* rotmat); + void get_min_rotation_matrix(const STensor3 &reference, const STensor3 &thecross, double &minimum_angle, SVector3 &rotation_axis, double threshold=-1., bool debugflag=false); + void get_rotation_angle_and_axis(const STensor3 &reference, const STensor3 &thecross, double &minimum_angle, SVector3 &rotation_axis, int modulo, montripletbis &trip); + + + + TensorStorageType crossField; + DoubleStorageType crossFieldSmoothness; + VectorStorageType crossFieldVectorialSmoothness; + vert2elemtype vert2elem; + elem2verttype elem2vert; + + set<MVertex*> listOfBndVertices; + graphtype graph; + double smoothness_threshold; + + static vector<montripletbis> permutation; + +#if defined(HAVE_ANN) + ANNkd_tree* annTree; + ANNpointArray dataPts; + ANNkd_tree* annTreeBnd; + ANNpointArray dataPtsBnd; +#endif + + public: + frameFieldBackgroundMesh3D(GRegion *_gf); + virtual ~frameFieldBackgroundMesh3D(); + + MVertex* get_nearest_neighbor_on_boundary(MVertex* v); + MVertex* get_nearest_neighbor_on_boundary(MVertex* v, double &distance); + +// bool findvertex(const MVertex *v)const{ +// map<MVertex*,double>::const_iterator it = sizeField.find(const_cast<MVertex*>(v)); +// if (it==sizeField.end()) return false; +// return true; +// }; + + double get_smoothness(double x, double y, double z); + double get_smoothness(MVertex *v); + + double get_approximate_smoothness(double x, double y, double z); + double get_approximate_smoothness(MVertex *v); + + void eval_approximate_crossfield(double x, double y, double z, STensor3 &cf); + void eval_approximate_crossfield(const MVertex *vert, STensor3 &cf); + + void get_vectorial_smoothness(double x, double y, double z, SVector3 &cf); + void get_vectorial_smoothness(const MVertex *vert, SVector3 &cf); + double get_vectorial_smoothness(const int idir, double x, double y, double z); + double get_vectorial_smoothness(const int idir, const MVertex *vert); + + inline void exportCrossField(const string &filename){export_tensor_as_vectors(filename,crossField);}; + inline void exportSmoothness(const string &filename) const{export_scalar(filename,crossFieldSmoothness);}; + void exportVectorialSmoothness(const string &filename); + +// private: +// STensor3 get_random_cross()const; + +}; + + +#endif diff --git a/Mesh/BackgroundMeshManager.cpp b/Mesh/BackgroundMeshManager.cpp new file mode 100644 index 0000000000..1aa93c3ad5 --- /dev/null +++ b/Mesh/BackgroundMeshManager.cpp @@ -0,0 +1,72 @@ + +#include "BackgroundMeshManager.h" +#include "BGMBase.h" +#include "BackgroundMesh2D.h" +#include "GEntity.h" +#include "GFace.h" +#include "GRegion.h" +#include "BackgroundMesh3D.h" + + +//------------------------------------------------------------------------ + +map<GEntity*,BGMBase*> BGMManager::data = map<GEntity*,BGMBase*>(); +BGMBase* BGMManager::latest2Dbgm = NULL; +bool BGMManager::use_cross_field = true; + +//------------------------------------------------------------------------ + +void BGMManager::set_use_cross_field(bool b){ + if (b && (BGMManager::use_cross_field==false)){// need to change... + data.clear(); + } + BGMManager::use_cross_field = b; +} + +//------------------------------------------------------------------------ + +BGMBase* BGMManager::get(GRegion* gf){ + map<GEntity*,BGMBase*>::iterator itfind = data.find(gf); + if (itfind!=data.end()){ + return itfind->second; + } + + BGMBase *bgm; + if (use_cross_field){ + bgm = new frameFieldBackgroundMesh3D(gf); + } + else{ + bgm = new backgroundMesh3D(gf); + } + data.insert(make_pair(gf,bgm)); + return bgm; +} + +//------------------------------------------------------------------------ + +BGMBase* BGMManager::get(GFace* gf){ + map<GEntity*,BGMBase*>::iterator itfind = data.find(gf); + if (itfind!=data.end()){ + latest2Dbgm = itfind->second; + return itfind->second; + } + + BGMBase *bgm; + if (use_cross_field) + bgm = new frameFieldBackgroundMesh2D(gf); + else + bgm = new backgroundMesh2D(gf); + data.insert(make_pair(gf,bgm)); + latest2Dbgm = bgm; + return bgm; +} + +//------------------------------------------------------------------------ + +BGMBase* BGMManager::current2D(){return latest2Dbgm;}; + +//------------------------------------------------------------------------ + + + + diff --git a/Mesh/BackgroundMeshManager.h b/Mesh/BackgroundMeshManager.h new file mode 100644 index 0000000000..c05bee9293 --- /dev/null +++ b/Mesh/BackgroundMeshManager.h @@ -0,0 +1,34 @@ +// 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@geuz.org>. + +#ifndef _BACKGROUND_MESH_MANAGER_H_ +#define _BACKGROUND_MESH_MANAGER_H_ + +#include <map> +#include "BGMBase.h" + +using namespace std; + +class GEntity; +class GFace; +class GRegion; + + +class BGMManager{ + public: + static BGMBase* get(GFace *gf); + static BGMBase* get(GRegion *gf); + static BGMBase* current2D(); + static void set_use_cross_field(bool b); + private: + static bool use_cross_field; + static BGMBase *latest2Dbgm; + static map<GEntity*,BGMBase*> data; +}; + + + + +#endif diff --git a/Mesh/BackgroundMeshTools.cpp b/Mesh/BackgroundMeshTools.cpp new file mode 100644 index 0000000000..bed3c28f5b --- /dev/null +++ b/Mesh/BackgroundMeshTools.cpp @@ -0,0 +1,450 @@ + +#include "BackgroundMeshTools.h" + +#include "GFace.h" +#include "GVertex.h" +#include "GEdge.h" +#include "GEdgeCompound.h" +#include "GEntity.h" +#include "Context.h" +#include "Field.h" +#include "GModel.h" + +#include <iostream> + +//------------------------------------------------------------------------ + +static double max_surf_curvature(const GEdge *ge, double u) +{ + double val = 0; + std::list<GFace *> faces = ge->faces(); + std::list<GFace *>::iterator it = faces.begin(); + while(it != faces.end()){ + if ((*it)->geomType() != GEntity::CompoundSurface && + (*it)->geomType() != GEntity::DiscreteSurface){ + SPoint2 par = ge->reparamOnFace((*it), u, 1); + double cc = (*it)->curvature(par); + val = std::max(cc, val); + } + ++it; + } + return val; +} + + +//------------------------------------------------------------------------ + +static double max_edge_curvature(const GVertex *gv) +{ + double val = 0; + std::list<GEdge*> l_edges = gv->edges(); + for (std::list<GEdge*>::const_iterator ite = l_edges.begin(); + ite != l_edges.end(); ++ite){ + GEdge *_myGEdge = *ite; + Range<double> range = _myGEdge->parBounds(0); + double cc; + if (gv == _myGEdge->getBeginVertex()) cc = _myGEdge->curvature(range.low()); + else cc = _myGEdge->curvature(range.high()); + val = std::max(val, cc); + } + return val; +} + +//------------------------------------------------------------------------ + +// the mesh vertex is classified on a model vertex. we compute the +// maximum of the curvature of model faces surrounding this point if +// it is classified on a model edge, we do the same for all model +// faces surrounding it if it is on a model face, we compute the +// curvature at this location + +static double LC_MVertex_CURV(GEntity *ge, double U, double V) +{ + double Crv = 0; + switch(ge->dim()){ + case 0: + Crv = max_edge_curvature((const GVertex *)ge); + //Crv = std::max(max_surf_curvature_vertex((const GVertex *)ge), Crv); + // Crv = max_surf_curvature((const GVertex *)ge); + break; + case 1: + { + GEdge *ged = (GEdge *)ge; + Crv = ged->curvature(U); + Crv = std::max(Crv, max_surf_curvature(ged, U)); + // Crv = max_surf_curvature(ged, U); + } + break; + case 2: + { + GFace *gf = (GFace *)ge; + Crv = gf->curvature(SPoint2(U, V)); + } + break; + } + double lc = Crv > 0 ? 2 * M_PI / Crv / CTX::instance()->mesh.minCircPoints : MAX_LC; + return lc; +} + +//------------------------------------------------------------------------ + +SMetric3 max_edge_curvature_metric(const GEdge *ge, double u) +{ + SVector3 t = ge->firstDer(u); + t.normalize(); + double l_t = ((2 * M_PI) /( fabs(ge->curvature(u)) + * CTX::instance()->mesh.minCircPoints )); + double l_n = 1.e12; + return buildMetricTangentToCurve(t,l_t,l_n); +} + +//------------------------------------------------------------------------ + +static SMetric3 metric_based_on_surface_curvature(const GEdge *ge, double u, bool iso_surf) +{ + const GEdgeCompound* ptrCompoundEdge = dynamic_cast<const GEdgeCompound*>(ge); + if (ptrCompoundEdge){ + double cmax, cmin; + SVector3 dirMax,dirMin; + cmax = ptrCompoundEdge->curvatures(u,&dirMax, &dirMin, &cmax,&cmin); + if (cmin == 0)cmin =1.e-12; + if (cmax == 0)cmax =1.e-12; + double lambda2 = ((2 * M_PI) /( fabs(cmax) * CTX::instance()->mesh.minCircPoints ) ); + double lambda1 = ((2 * M_PI) /( fabs(cmin) * CTX::instance()->mesh.minCircPoints ) ); + SVector3 Z = crossprod(dirMax,dirMin); + + lambda1 = std::max(lambda1, CTX::instance()->mesh.lcMin); + lambda2 = std::max(lambda2, CTX::instance()->mesh.lcMin); + lambda1 = std::min(lambda1, CTX::instance()->mesh.lcMax); + lambda2 = std::min(lambda2, CTX::instance()->mesh.lcMax); + + SMetric3 curvMetric (1. / (lambda1 * lambda1), 1. / (lambda2 * lambda2), + 1.e-12, dirMin, dirMax, Z); + return curvMetric; + } + else{ + SMetric3 mesh_size(1.e-12); + std::list<GFace *> faces = ge->faces(); + std::list<GFace *>::iterator it = faces.begin(); + // we choose the metric eigenvectors to be the ones + // related to the edge ... + SMetric3 curvMetric = max_edge_curvature_metric(ge, u); + while(it != faces.end()){ + if (((*it)->geomType() != GEntity::CompoundSurface) && + ((*it)->geomType() != GEntity::DiscreteSurface)){ + SPoint2 par = ge->reparamOnFace((*it), u, 1); + SMetric3 m = metric_based_on_surface_curvature (*it, par.x(), par.y(), iso_surf); + curvMetric = intersection_conserveM1(curvMetric,m); + } + ++it; + } + + return curvMetric; + } +} + +//------------------------------------------------------------------------ + +static SMetric3 metric_based_on_surface_curvature(const GVertex *gv, bool iso_surf) +{ + SMetric3 mesh_size(1.e-15); + std::list<GEdge*> l_edges = gv->edges(); + for (std::list<GEdge*>::const_iterator ite = l_edges.begin(); + ite != l_edges.end(); ++ite){ + GEdge *_myGEdge = *ite; + Range<double> bounds = _myGEdge->parBounds(0); + + // ES: Added extra if condition to use the code below only with compund curves + // This is because we want to call the function + // metric_based_on_surface_curvature(const GEdge *ge, double u) for the case when + // ge is a compound edge + if (_myGEdge->geomType() == GEntity::CompoundCurve){ + if (gv == _myGEdge->getBeginVertex()) + mesh_size = intersection + (mesh_size, + metric_based_on_surface_curvature(_myGEdge, bounds.low(), iso_surf)); + else + mesh_size = intersection + (mesh_size, + metric_based_on_surface_curvature(_myGEdge, bounds.high(), iso_surf)); + } + } + return mesh_size; +} + +//------------------------------------------------------------------------ + +SMetric3 LC_MVertex_CURV_ANISO(GEntity *ge, double U, double V) +{ + bool iso_surf = CTX::instance()->mesh.lcFromCurvature == 2; + + switch(ge->dim()){ + case 0: return metric_based_on_surface_curvature((const GVertex *)ge, iso_surf); + case 1: return metric_based_on_surface_curvature((const GEdge *)ge, U, iso_surf); + case 2: return metric_based_on_surface_curvature((const GFace *)ge, U, V, iso_surf); + } + Msg::Error("Curvature control impossible to compute for a volume!"); + return SMetric3(); +} + +//------------------------------------------------------------------------ + +// compute the mesh size at a given vertex due to prescribed sizes at +// mesh vertices +static double LC_MVertex_PNTS(GEntity *ge, double U, double V) +{ + switch(ge->dim()){ + case 0: + { + GVertex *gv = (GVertex *)ge; + double lc = gv->prescribedMeshSizeAtVertex(); + // FIXME we might want to remove this to make all lc treatment consistent + if(lc >= MAX_LC) return CTX::instance()->lc / 10.; + return lc; + } + case 1: + { + GEdge *ged = (GEdge *)ge; + GVertex *v1 = ged->getBeginVertex(); + GVertex *v2 = ged->getEndVertex(); + if (v1 && v2){ + Range<double> range = ged->parBounds(0); + double a = (U - range.low()) / (range.high() - range.low()); + double lc = (1 - a) * v1->prescribedMeshSizeAtVertex() + + (a) * v2->prescribedMeshSizeAtVertex() ; + + // FIXME we might want to remove this to make all lc treatment consistent + if(lc >= MAX_LC) return CTX::instance()->lc / 10.; + return lc; + } + else + return MAX_LC; + } + default: + return MAX_LC; + } +} + +//------------------------------------------------------------------------ +//------------------------------------------------------------------------ +//------------------------------------------------------------------------ +//------------------------------------------------------------------------ +//------------------------------------------------------------------------ + +SMetric3 buildMetricTangentToCurve(SVector3 &t, double l_t, double l_n) +{ + if (l_t == 0.0) return SMetric3(1.e-22); + SVector3 a; + if (fabs(t(0)) <= fabs(t(1)) && fabs(t(0)) <= fabs(t(2))){ + a = SVector3(1,0,0); + } + else if (fabs(t(1)) <= fabs(t(0)) && fabs(t(1)) <= fabs(t(2))){ + a = SVector3(0,1,0); + } + else{ + a = SVector3(0,0,1); + } + SVector3 b = crossprod (t,a); + SVector3 c = crossprod (b,t); + b.normalize(); + c.normalize(); + t.normalize(); + SMetric3 Metric (1./(l_t*l_t),1./(l_n*l_n),1./(l_n*l_n),t,b,c); + // printf("bmttc %g %g %g %g %g\n",l_t,l_n,Metric(0,0),Metric(0,1),Metric(1,1)); + return Metric; +} + +//------------------------------------------------------------------------ + +SMetric3 buildMetricTangentToSurface(SVector3 &t1, SVector3 &t2, + double l_t1, double l_t2, double l_n) +{ + t1.normalize(); + t2.normalize(); + SVector3 n = crossprod (t1,t2); + n.normalize(); + + l_t1 = std::max(l_t1, CTX::instance()->mesh.lcMin); + l_t2 = std::max(l_t2, CTX::instance()->mesh.lcMin); + l_t1 = std::min(l_t1, CTX::instance()->mesh.lcMax); + l_t2 = std::min(l_t2, CTX::instance()->mesh.lcMax); + SMetric3 Metric (1./(l_t1*l_t1),1./(l_t2*l_t2),1./(l_n*l_n),t1,t2,n); + return Metric; +} + +//------------------------------------------------------------------------ + +// This is the only function that is used by the meshers +double BGM_MeshSize(GEntity *ge, double U, double V, + double X, double Y, double Z) +{ + // default lc (mesh size == size of the model) + double l1 = CTX::instance()->lc; + + // lc from points + double l2 = MAX_LC; + if(CTX::instance()->mesh.lcFromPoints && ge->dim() < 2) + l2 = LC_MVertex_PNTS(ge, U, V); + + // lc from curvature + double l3 = MAX_LC; + if(CTX::instance()->mesh.lcFromCurvature && ge->dim() < 3) + l3 = LC_MVertex_CURV(ge, U, V); + + // lc from fields + double l4 = MAX_LC; + FieldManager *fields = ge->model()->getFields(); + if(fields->getBackgroundField() > 0){ + Field *f = fields->get(fields->getBackgroundField()); + if(f) l4 = (*f)(X, Y, Z, ge); + } + + // take the minimum, then constrain by lcMin and lcMax + double lc = std::min(std::min(std::min(l1, l2), l3), l4); + lc = std::max(lc, CTX::instance()->mesh.lcMin); + lc = std::min(lc, CTX::instance()->mesh.lcMax); + + if(lc <= 0.){ + Msg::Error("Wrong mesh element size lc = %g (lcmin = %g, lcmax = %g)", + lc, CTX::instance()->mesh.lcMin, CTX::instance()->mesh.lcMax); + lc = l1; + } + + //Msg::Debug("BGM X,Y,Z=%g,%g,%g L4=%g L3=%g L2=%g L1=%g LC=%g LFINAL=%g DIM =%d ", + //X, Y, Z, l4, l3, l2, l1, lc, lc * CTX::instance()->mesh.lcFactor, ge->dim()); + + //Emi fix + //if (lc == l1) lc /= 10.; + + return lc * CTX::instance()->mesh.lcFactor; +} + + +//------------------------------------------------------------------------ + +// anisotropic version of the background field +SMetric3 BGM_MeshMetric(GEntity *ge, + double U, double V, + double X, double Y, double Z) +{ + + // Metrics based on element size + // Element size = min. between default lc and lc from point (if applicable), constrained by lcMin and lcMax + double lc = CTX::instance()->lc; + if(CTX::instance()->mesh.lcFromPoints && ge->dim() < 2) lc = std::min(lc, LC_MVertex_PNTS(ge, U, V)); + lc = std::max(lc, CTX::instance()->mesh.lcMin); + lc = std::min(lc, CTX::instance()->mesh.lcMax); + if(lc <= 0.){ + Msg::Error("Wrong mesh element size lc = %g (lcmin = %g, lcmax = %g)", + lc, CTX::instance()->mesh.lcMin, CTX::instance()->mesh.lcMax); + lc = CTX::instance()->lc; + } + SMetric3 m0(1./(lc*lc)); + + // Intersect with metrics from fields if applicable + FieldManager *fields = ge->model()->getFields(); + SMetric3 m1 = m0; + if(fields->getBackgroundField() > 0){ + Field *f = fields->get(fields->getBackgroundField()); + if(f) { + SMetric3 l4; + if (!f->isotropic()) (*f)(X, Y, Z, l4, ge); + else { + const double L = (*f)(X, Y, Z, ge); + l4 = SMetric3(1/(L*L)); + } + m1 = intersection(l4, m0); + } + } + + // Intersect with metrics from curvature if applicable + SMetric3 m = (CTX::instance()->mesh.lcFromCurvature && ge->dim() < 3) ? + intersection(m1, LC_MVertex_CURV_ANISO(ge, U, V)) : m1; + + return m; + +} + +//------------------------------------------------------------------------ + +bool Extend1dMeshIn2dSurfaces() +{ + return CTX::instance()->mesh.lcExtendFromBoundary ? true : false; +} + +//------------------------------------------------------------------------ + +bool Extend2dMeshIn3dVolumes() +{ + return CTX::instance()->mesh.lcExtendFromBoundary ? true : false; +} + +//------------------------------------------------------------------------ + +SMetric3 max_edge_curvature_metric(const GVertex *gv) +{ + SMetric3 val (1.e-12); + std::list<GEdge*> l_edges = gv->edges(); + for (std::list<GEdge*>::const_iterator ite = l_edges.begin(); + ite != l_edges.end(); ++ite){ + GEdge *_myGEdge = *ite; + Range<double> range = _myGEdge->parBounds(0); + SMetric3 cc; + if (gv == _myGEdge->getBeginVertex()) { + SVector3 t = _myGEdge->firstDer(range.low()); + t.normalize(); + double l_t = ((2 * M_PI) /( fabs(_myGEdge->curvature(range.low())) + * CTX::instance()->mesh.minCircPoints )); + double l_n = 1.e12; + cc = buildMetricTangentToCurve(t,l_t,l_n); + } + else { + SVector3 t = _myGEdge->firstDer(range.high()); + t.normalize(); + double l_t = ((2 * M_PI) /( fabs(_myGEdge->curvature(range.high())) + * CTX::instance()->mesh.minCircPoints )); + double l_n = 1.e12; + cc = buildMetricTangentToCurve(t,l_t,l_n); + } + val = intersection(val,cc); + } + return val; +} + +//------------------------------------------------------------------------ + +SMetric3 metric_based_on_surface_curvature(const GFace *gf, double u, double v, + bool surface_isotropic, + double d_normal , + double d_tangent_max) +{ + if (gf->geomType() == GEntity::Plane)return SMetric3(1.e-12); + double cmax, cmin; + SVector3 dirMax,dirMin; + cmax = gf->curvatures(SPoint2(u, v),&dirMax, &dirMin, &cmax,&cmin); + if (cmin == 0)cmin =1.e-12; + if (cmax == 0)cmax =1.e-12; + double lambda1 = ((2 * M_PI) /( fabs(cmin) * CTX::instance()->mesh.minCircPoints ) ); + double lambda2 = ((2 * M_PI) /( fabs(cmax) * CTX::instance()->mesh.minCircPoints ) ); + SVector3 Z = crossprod(dirMax,dirMin); + if (surface_isotropic) lambda2 = lambda1 = std::min(lambda2,lambda1); + dirMin.normalize(); + dirMax.normalize(); + Z.normalize(); + lambda1 = std::max(lambda1, CTX::instance()->mesh.lcMin); + lambda2 = std::max(lambda2, CTX::instance()->mesh.lcMin); + lambda1 = std::min(lambda1, CTX::instance()->mesh.lcMax); + lambda2 = std::min(lambda2, CTX::instance()->mesh.lcMax); + double lambda3 = std::min(d_normal, CTX::instance()->mesh.lcMax); + lambda3 = std::max(lambda3, CTX::instance()->mesh.lcMin); + lambda1 = std::min(lambda1, d_tangent_max); + lambda2 = std::min(lambda2, d_tangent_max); + + SMetric3 curvMetric (1./(lambda1*lambda1),1./(lambda2*lambda2), + 1./(lambda3*lambda3), + dirMin, dirMax, Z ); + return curvMetric; +} + +//------------------------------------------------------------------------ + diff --git a/Mesh/BackgroundMeshTools.h b/Mesh/BackgroundMeshTools.h new file mode 100644 index 0000000000..dccae2c8de --- /dev/null +++ b/Mesh/BackgroundMeshTools.h @@ -0,0 +1,35 @@ + + +#ifndef _BACKGROUND_MESH_TOOLS_H_ +#define _BACKGROUND_MESH_TOOLS_H_ + +#include "STensor3.h" + +class GFace; +class GVertex; +class GEdge; +class GEntity; + +//------------------------------------------------------------- + +SMetric3 buildMetricTangentToCurve (SVector3 &t, double l_t, double l_n); +SMetric3 buildMetricTangentToSurface (SVector3 &t1, SVector3 &t2, double l_t1, double l_t2, double l_n); +double BGM_MeshSize(GEntity *ge, double U, double V, double X, double Y, double Z); +SMetric3 BGM_MeshMetric(GEntity *ge, double U, double V, double X, double Y, double Z); +bool Extend1dMeshIn2dSurfaces(); +bool Extend2dMeshIn3dVolumes(); +SMetric3 max_edge_curvature_metric(const GVertex *gv); +SMetric3 max_edge_curvature_metric(const GEdge *ge, double u, double &l); +SMetric3 metric_based_on_surface_curvature(const GFace *gf, double u, double v, bool surface_isotropic = false,double d_normal = 1.e12,double d_tangent_max = 1.e12); + +//------------------------------------------------------------- +// +//static double LC_MVertex_CURV(GEntity *ge, double U, double V); +//SMetric3 LC_MVertex_CURV_ANISO(GEntity *ge, double U, double V); +//static double LC_MVertex_PNTS(GEntity *ge, double U, double V); +//static double max_edge_curvature(const GVertex *gv); +//static double max_surf_curvature(const GEdge *ge, double u); +//static SMetric3 metric_based_on_surface_curvature(const GEdge *ge, double u, bool iso_surf); +//static SMetric3 metric_based_on_surface_curvature(const GVertex *gv, bool iso_surf); + +#endif diff --git a/Mesh/CMakeLists.txt b/Mesh/CMakeLists.txt index 35170688e0..c1cef52f21 100644 --- a/Mesh/CMakeLists.txt +++ b/Mesh/CMakeLists.txt @@ -18,7 +18,14 @@ set(SRC meshGRegionExtruded.cpp meshGRegionCarveHole.cpp meshGRegionLocalMeshMod.cpp meshGRegionMMG3D.cpp meshMetric.cpp + BackgroundMeshTools.cpp BackgroundMesh.cpp + BGMBase.cpp + BackgroundMesh2D.cpp + BackgroundMesh3D.cpp + BackgroundMeshManager.cpp + pointInsertionRTreeTools.cpp + pointInsertion.cpp qualityMeasures.cpp BoundaryLayers.cpp BDS.cpp diff --git a/Mesh/CenterlineField.cpp b/Mesh/CenterlineField.cpp index c90f471f83..10a483ae7a 100644 --- a/Mesh/CenterlineField.cpp +++ b/Mesh/CenterlineField.cpp @@ -33,7 +33,7 @@ #include "discreteFace.h" #include "GEdgeCompound.h" #include "GFaceCompound.h" -#include "BackgroundMesh.h" +#include "BackgroundMeshTools.h" #include "meshGFace.h" #include "meshGEdge.h" #include "MQuadrangle.h" diff --git a/Mesh/DivideAndConquer.cpp b/Mesh/DivideAndConquer.cpp index 9794a33fc4..751e095111 100644 --- a/Mesh/DivideAndConquer.cpp +++ b/Mesh/DivideAndConquer.cpp @@ -19,7 +19,7 @@ #include "DivideAndConquer.h" #include "Numeric.h" #include "robustPredicates.h" -#include "BackgroundMesh.h" +#include "BackgroundMeshTools.h" #include "OS.h" #include "GPoint.h" #include "GFace.h" diff --git a/Mesh/Field.cpp b/Mesh/Field.cpp index 74b35f61b0..fd50f7e586 100644 --- a/Mesh/Field.cpp +++ b/Mesh/Field.cpp @@ -14,6 +14,7 @@ #include <string> #include <string.h> #include <sstream> +#include <algorithm> #include "GmshConfig.h" #include "Context.h" #include "Field.h" @@ -22,7 +23,7 @@ #include "GmshMessage.h" #include "Numeric.h" #include "mathEvaluator.h" -#include "BackgroundMesh.h" +#include "BackgroundMeshTools.h" #include "CenterlineField.h" #include "STensor3.h" #include "meshMetric.h" @@ -2397,3 +2398,43 @@ void FieldManager::setBackgroundMesh(int iView) (*this)[id] = f; _background_field = id; } + + + +//-------------------------------------------------- + +GenericField::GenericField(){}; + +//-------------------------------------------------- + +GenericField::~GenericField(){}; + +//-------------------------------------------------- + +double GenericField::operator() (double x, double y, double z, GEntity *ge){ + std::vector<double> sizes(cbs.size()); + std::vector<ptrfunction>::iterator itcbs = cbs.begin(); + std::vector<void*>::iterator itdata = user_data.begin(); +// std::cout << "#callbacks=" << cbs.size() << std::endl; +// std::cout << "#user_data=" << user_data.size() << std::endl; + for (std::vector<double>::iterator it = sizes.begin();it!=sizes.end();it++,itdata++,itcbs++){ + bool ok = (*itcbs)(x,y,z,(*itdata),(*it)); + if (!ok){ + Msg::Warning("GenericField::ERROR from callback "); + std::cout << "GenericField::ERROR from callback number " << std::distance(sizes.begin(),it) << std::endl; + } +// std::cout << "callback " << std::distance(sizes.begin(),it) << ": size set to " << *it << std::endl; + } +// std::cout << " ----> min = " << (*std::min_element(sizes.begin(),sizes.end())) << std::endl; + return (*std::min_element(sizes.begin(),sizes.end())); +} + +//-------------------------------------------------- + +void GenericField::setCallbackWithData(ptrfunction fct, void *data){ + user_data.push_back(data); + cbs.push_back(fct); +} + +//-------------------------------------------------- + diff --git a/Mesh/Field.h b/Mesh/Field.h index 814a6ffc2a..1a2f78d7ca 100644 --- a/Mesh/Field.h +++ b/Mesh/Field.h @@ -8,6 +8,7 @@ #include <string> #include <map> +#include <vector> #include <list> #include "GmshConfig.h" #include "STensor3.h" @@ -336,4 +337,27 @@ template<class F> class FieldFactoryT : public FieldFactory { Field * operator()() { return new F; } }; + + +// the class GenericField contains a set of void* functions, which give a mesh size +// All these functions are called when calling operator() ; then, the minimum size is returned. +class GenericField : public Field{ + public: + // callback prototypes: + // this callback is called with a void* previously given to the GenericField ! + typedef bool (*ptrfunction)(double, double, double, void*, double&); + + GenericField(); + ~GenericField(); + virtual double operator() (double x, double y, double z, GEntity *ge=0); + virtual const char *getName(){return "GenericField";}; + + // sets the callbacks + void setCallbackWithData(ptrfunction fct, void *data); + + private: + std::vector<ptrfunction> cbs;// the callbacks + std::vector<void*> user_data;// the data to be sent to the callbacks +}; + #endif diff --git a/Mesh/Generator.cpp b/Mesh/Generator.cpp index 8dec7d46ca..6799a94a25 100644 --- a/Mesh/Generator.cpp +++ b/Mesh/Generator.cpp @@ -36,6 +36,8 @@ #include "simple3D.h" #include "yamakawa.h" +#include "pointInsertion.h" + #if defined(HAVE_OPTHOM) #include "OptHomRun.h" #include "OptHomElastic.h" @@ -46,7 +48,7 @@ #include "PViewData.h" #endif -template<class T> + template<class T> static void GetQualityMeasure(std::vector<T*> &ele, double &gamma, double &gammaMin, double &gammaMax, double &minSICN, double &minSICNMin, double &minSICNMax, @@ -219,8 +221,8 @@ static void Mesh0D(GModel *m) GVertex *gv = *it; if (gv->meshMaster() != gv->tag()){ if (gv->correspondingVertices.empty()){ - GVertex *master = m->getVertexByTag(abs(gv->meshMaster())); - if(master)gv->correspondingVertices[gv->mesh_vertices[0]] = (master->mesh_vertices[0]); + GVertex *master = m->getVertexByTag(abs(gv->meshMaster())); + if(master)gv->correspondingVertices[gv->mesh_vertices[0]] = (master->mesh_vertices[0]); } } } @@ -244,8 +246,8 @@ static void Mesh1D(GModel *m) int nPending = 0; for(GModel::eiter it = m->firstEdge(); it != m->lastEdge(); ++it){ if ((*it)->meshStatistics.status == GEdge::PENDING){ - mesher(*it); - nPending++; + mesher(*it); + nPending++; } if(!nIter) Msg::ProgressMeter(nPending, nTot, false, "Meshing 1D..."); } @@ -274,8 +276,8 @@ static void PrintMesh2dStatistics(GModel *m) if(CTX::instance()->createAppendMeshStatReport == 1){ fprintf(statreport, "2D stats\tname\t\t#faces\t\t#fail\t\t" - "#t\t\tQavg\t\tQbest\t\tQworst\t\t#Q>90\t\t#Q>90/#t\t" - "#e\t\ttau\t\t#Egood\t\t#Egood/#e\tCPU\n"); + "#t\t\tQavg\t\tQbest\t\tQworst\t\t#Q>90\t\t#Q>90/#t\t" + "#e\t\ttau\t\t#Egood\t\t#Egood/#e\tCPU\n"); if(m->empty()){ fclose(statreport); return; @@ -291,7 +293,7 @@ static void PrintMesh2dStatistics(GModel *m) e_long = std::max((*it)->meshStatistics.longest_edge_length, e_long); e_short = std::min((*it)->meshStatistics.smallest_edge_length, e_short); if ((*it)->meshStatistics.status == GFace::FAILED || - (*it)->meshStatistics.status == GFace::PENDING) nUnmeshed++; + (*it)->meshStatistics.status == GFace::PENDING) nUnmeshed++; nTotT += (*it)->meshStatistics.nbTriangle; nTotE += (*it)->meshStatistics.nbEdge; nTotGoodLength += (*it)->meshStatistics.nbGoodLength; @@ -304,11 +306,11 @@ static void PrintMesh2dStatistics(GModel *m) fprintf(statreport,"\t%16s\t%d\t\t%d\t\t", m->getName().c_str(), numFaces, nUnmeshed); fprintf(statreport,"%d\t\t%8.7f\t%8.7f\t%8.7f\t%d\t\t%8.7f\t", - nTotT, avg / (double)nTotT, best, worst, nTotGoodQuality, - (double)nTotGoodQuality / nTotT); + nTotT, avg / (double)nTotT, best, worst, nTotGoodQuality, + (double)nTotGoodQuality / nTotT); fprintf(statreport,"%d\t\t%8.7f\t%d\t\t%8.7f\t%8.1f\n", - nTotE, exp(e_avg / (double)nTotE), nTotGoodLength, - (double)nTotGoodLength / nTotE, CTX::instance()->meshTimer[1]); + nTotE, exp(e_avg / (double)nTotE), nTotGoodLength, + (double)nTotGoodLength / nTotE, CTX::instance()->meshTimer[1]); fclose(statreport); } @@ -343,10 +345,10 @@ static void Mesh2D(GModel *m) #pragma omp parallel for schedule (dynamic) #endif for(size_t K = 0 ; K < temp.size() ; K++){ - if (temp[K]->meshStatistics.status == GFace::PENDING){ + if (temp[K]->meshStatistics.status == GFace::PENDING){ backgroundMesh::current()->unset(); - meshGFace mesher(true); - mesher(temp[K]); + meshGFace mesher(true); + mesher(temp[K]); #if defined(HAVE_BFGS) if(CTX::instance()->mesh.optimizeLloyd){ @@ -358,8 +360,8 @@ static void Mesh2D(GModel *m) //m->writeMSH("beforeLLoyd.msh"); smm.optimize_face(temp[K]); int rec = ((CTX::instance()->mesh.recombineAll || - temp[K]->meshAttributes.recombine) && - !CTX::instance()->mesh.recombine3DAll); + temp[K]->meshAttributes.recombine) && + !CTX::instance()->mesh.recombine3DAll); //m->writeMSH("afterLLoyd.msh"); if (rec) recombineIntoQuads(temp[K]); //m->writeMSH("afterRecombine.msh"); @@ -371,10 +373,10 @@ static void Mesh2D(GModel *m) #if defined(_OPENMP) #pragma omp critical #endif - { - nPending++; - } - } + { + nPending++; + } + } if(!nIter) Msg::ProgressMeter(nPending, nTot, false, "Meshing 2D..."); } #if defined(_OPENMP) @@ -397,8 +399,8 @@ static void Mesh2D(GModel *m) //m->writeMSH("beforeLLoyd.msh"); smm.optimize_face(*it); int rec = ((CTX::instance()->mesh.recombineAll || - (*it)->meshAttributes.recombine) && - !CTX::instance()->mesh.recombine3DAll); + (*it)->meshAttributes.recombine) && + !CTX::instance()->mesh.recombine3DAll); //m->writeMSH("afterLLoyd.msh"); if (rec) recombineIntoQuads(*it); //m->writeMSH("afterRecombine.msh"); @@ -426,7 +428,7 @@ static void Mesh2D(GModel *m) } static void FindConnectedRegions(std::vector<GRegion*> &delaunay, - std::vector<std::vector<GRegion*> > &connected) + std::vector<std::vector<GRegion*> > &connected) { const unsigned int nbVolumes = delaunay.size(); if (!nbVolumes)return; @@ -441,10 +443,10 @@ static void FindConnectedRegions(std::vector<GRegion*> &delaunay, oneDomain.insert(r); std::list<GFace*> faces = r->faces(); for (std::list<GFace*> :: iterator it = faces.begin(); it != faces.end() ; ++it){ - GFace *gf = *it; - GRegion *other = gf->getRegion(0) == r ? gf->getRegion(1) : gf->getRegion(0); - if (other != 0 && oneDomain.find(other) == oneDomain.end()) - _stack.push (other); + GFace *gf = *it; + GRegion *other = gf->getRegion(0) == r ? gf->getRegion(1) : gf->getRegion(0); + if (other != 0 && oneDomain.find(other) == oneDomain.end()) + _stack.push (other); } } std::vector<GRegion*> temp1,temp2; @@ -457,7 +459,7 @@ static void FindConnectedRegions(std::vector<GRegion*> &delaunay, delaunay=temp1; } Msg::Info("Delaunay Meshing %d volumes with %d connected components", - nbVolumes,connected.size()); + nbVolumes,connected.size()); } static void Mesh3D(GModel *m) @@ -492,14 +494,18 @@ static void Mesh3D(GModel *m) for(unsigned j=0;j<connected[i].size();j++){ GRegion *gr = connected[i][j]; if(CTX::instance()->mesh.recombine3DAll || gr->meshAttributes.recombine3D){ - std::list<GFace*> f = gr->faces(); - for (std::list<GFace*>::iterator it = f.begin(); - it != f.end() ; ++it) quadsToTriangles (*it,1000000); + std::list<GFace*> f = gr->faces(); + for (std::list<GFace*>::iterator it = f.begin(); + it != f.end() ; ++it) quadsToTriangles (*it,1000000); } } } // pragma OMP ICI ?? + double time_recombination, vol_element_recombination, vol_hexa_recombination; + int nb_elements_recombination,nb_hexa_recombination; + time_recombination = vol_hexa_recombination = vol_element_recombination = 0.; + nb_elements_recombination = nb_hexa_recombination = 0; for(unsigned int i = 0; i < connected.size(); i++){ MeshDelaunayVolume(connected[i]); @@ -507,21 +513,62 @@ static void Mesh3D(GModel *m) for(unsigned j=0;j<connected[i].size();j++){ GRegion *gr = connected[i][j]; //R-tree + bool treat_region_ok=false; if(CTX::instance()->mesh.algo3d == ALGO_3D_RTREE){ - Filler f; - f.treat_region(gr); + // PEB MODIF + if (old_algo_hexa()){ + Filler f; + f.treat_region(gr); + treat_region_ok=true; + } + else{ + Filler3D f; + treat_region_ok = f.treat_region(gr); + } + // END PEB MODIF } //Recombine3D into hex - if(CTX::instance()->mesh.recombine3DAll || gr->meshAttributes.recombine3D){ - Recombinator rec; - rec.execute(); - Supplementary sup; - sup.execute(); - PostOp post; - post.execute(0); + if((CTX::instance()->mesh.recombine3DAll || gr->meshAttributes.recombine3D) && treat_region_ok){ + clock_t a = clock(); + // Recombinator rec; + // rec.execute(); + Recombinator rec; + rec.execute(gr); +// Recombinator_Graph rec; +// rec.execute(1.e7,"test"); + // Supplementary sup; + // sup.execute(); + // PostOp post; + // post.execute(0); + Supplementary sup; + sup.execute(gr); + PostOp post; + post.execute(gr,0); + + nb_elements_recombination += post.get_nb_elements(); + nb_hexa_recombination += post.get_nb_hexahedra(); + vol_element_recombination += post.get_vol_elements(); + vol_hexa_recombination += post.get_vol_hexahedra(); + + // -- partial export + stringstream ss; + ss << "yamakawa_part_"; + ss << gr->tag(); + ss << ".msh"; + export_gregion_mesh(gr,ss.str().c_str()); + // -- end partial export + + time_recombination += (clock() - a) / (double)CLOCKS_PER_SEC; } } } + if(CTX::instance()->mesh.recombine3DAll){ + cout << "RECOMBINATION timing:" << endl; + cout << " ------- CUMULATIVE TIME RECOMBINATION : " << time_recombination << " s." << endl; + cout << "RECOMBINATION CUMULATIVE STATISTICS:" << endl; + cout << "............................ Percentage of hexahedra (#) : " << nb_hexa_recombination*100./nb_elements_recombination << endl; + cout << "............................ Percentage of hexahedra (Vol) : " << vol_hexa_recombination*100./vol_element_recombination << endl; + } // Ensure that all volume Jacobians are positive m->setAllVolumesPositive(); @@ -637,7 +684,7 @@ void GenerateMesh(GModel *m, int ask) // Optimize quality of 3D tet mesh if(m->getMeshStatus() == 3){ for(int i = 0; i < std::max(CTX::instance()->mesh.optimize, - CTX::instance()->mesh.optimizeNetgen); i++){ + CTX::instance()->mesh.optimizeNetgen); i++){ if(CTX::instance()->mesh.optimize > i) OptimizeMesh(m); if(CTX::instance()->mesh.optimizeNetgen > i) OptimizeMeshNetgen(m); } @@ -655,7 +702,7 @@ void GenerateMesh(GModel *m, int ask) // Create high order elements if(m->getMeshStatus() && CTX::instance()->mesh.order > 1) SetOrderN(m, CTX::instance()->mesh.order, CTX::instance()->mesh.secondOrderLinear, - CTX::instance()->mesh.secondOrderIncomplete); + CTX::instance()->mesh.secondOrderIncomplete); // Optimize high order elements if(CTX::instance()->mesh.hoOptimize){ @@ -678,7 +725,7 @@ void GenerateMesh(GModel *m, int ask) } Msg::Info("%d vertices %d elements", - m->getNumMeshVertices(), m->getNumMeshElements()); + m->getNumMeshVertices(), m->getNumMeshElements()); Msg::PrintErrorCounter("Mesh generation error summary"); diff --git a/Mesh/meshGEdge.cpp b/Mesh/meshGEdge.cpp index 3dcd0173a4..33bd7df668 100644 --- a/Mesh/meshGEdge.cpp +++ b/Mesh/meshGEdge.cpp @@ -8,7 +8,7 @@ #include "meshGEdge.h" #include "GEdge.h" #include "MLine.h" -#include "BackgroundMesh.h" +#include "BackgroundMeshTools.h" #include "boundaryLayersData.h" #include "Numeric.h" #include "GmshMessage.h" diff --git a/Mesh/meshGFaceBamg.cpp b/Mesh/meshGFaceBamg.cpp index ce5134f7c7..a5281768ec 100644 --- a/Mesh/meshGFaceBamg.cpp +++ b/Mesh/meshGFaceBamg.cpp @@ -16,7 +16,7 @@ #include "Context.h" #include <list> #include <map> -#include "BackgroundMesh.h" +#include "BackgroundMeshTools.h" #include "meshGFaceDelaunayInsertion.h" #include "Options.h" #include "meshGFace.h" diff --git a/Mesh/meshGFaceDelaunayInsertion.cpp b/Mesh/meshGFaceDelaunayInsertion.cpp index 3cb1530911..b0fa516970 100644 --- a/Mesh/meshGFaceDelaunayInsertion.cpp +++ b/Mesh/meshGFaceDelaunayInsertion.cpp @@ -9,7 +9,11 @@ #include "GmshMessage.h" #include "OS.h" #include "robustPredicates.h" +// PEB MODIF #include "BackgroundMesh.h" +#include "surfaceFiller.h" +#include "pointInsertion.h" +// END PEB MODIF #include "meshGFaceDelaunayInsertion.h" #include "meshGFaceOptimize.h" #include "meshGFace.h" @@ -23,7 +27,6 @@ #include "GModel.h" #include "GFaceCompound.h" #include "intersectCurveSurface.h" -#include "surfaceFiller.h" #include "HilbertCurve.h" double LIMIT_ = 0.5 * sqrt(2.0) * 1; @@ -1518,20 +1521,29 @@ void optimalPointFrontalQuad (GFace *gf, } void optimalPointFrontalQuadB (GFace *gf, - MTri3* worst, - int active_edge, - bidimMeshData &data, - double newPoint[2], - double metric[3]) + MTri3* worst, + int active_edge, + bidimMeshData &data, + double newPoint[2], + double metric[3]) { optimalPointFrontalQuad (gf,worst,active_edge,data,newPoint,metric); return; } void buildBackGroundMesh (GFace *gf, - std::map<MVertex* , MVertex*>* equivalence, - std::map<MVertex*, SPoint2> * parametricCoordinates) + std::map<MVertex* , MVertex*>* equivalence, + std::map<MVertex*, SPoint2> * parametricCoordinates) { + // TODO PEB : + // this is now done in the new backgroundMesh !!! + // on le vire ? On insère ici les operations sur le new backgmesh ? + // parce que les opérations qui suivent sur l'ancien BGM sont inutiles maintenant... ! + if (!old_algo_hexa()) + return; +//#else + // END PEB + endif... + // printf("build bak mesh\n"); quadsToTriangles(gf, 100000); @@ -1540,17 +1552,17 @@ void buildBackGroundMesh (GFace *gf, // std::vector<MQuadrangle*> QR; for(unsigned int i = 0; i < gf->triangles.size(); i++){ TR.push_back(new MTriangle(gf->triangles[i]->getVertex(0), - gf->triangles[i]->getVertex(1), - gf->triangles[i]->getVertex(2))); + gf->triangles[i]->getVertex(1), + gf->triangles[i]->getVertex(2))); } /* - for(int i=0;i<gf->quadrangles.size();i++){ - QR.push_back(new MQuadrangle(gf->quadrangles[i]->getVertex(0), - gf->quadrangles[i]->getVertex(1), - gf->quadrangles[i]->getVertex(2), - gf->quadrangles[i]->getVertex(3))); - } - */ + for(int i=0;i<gf->quadrangles.size();i++){ + QR.push_back(new MQuadrangle(gf->quadrangles[i]->getVertex(0), + gf->quadrangles[i]->getVertex(1), + gf->quadrangles[i]->getVertex(2), + gf->quadrangles[i]->getVertex(3))); + } + */ // avoid computing curvatures on the fly : only on the // BGM computes once curvatures at each node // Disable curvature control @@ -1575,11 +1587,12 @@ void buildBackGroundMesh (GFace *gf, // gf->quadrangles = QR; } +//#endif } void bowyerWatsonFrontalLayers(GFace *gf, bool quad, - std::map<MVertex* , MVertex*>* equivalence, - std::map<MVertex*, SPoint2> * parametricCoordinates) + std::map<MVertex* , MVertex*>* equivalence, + std::map<MVertex*, SPoint2> * parametricCoordinates) { std::set<MTri3*,compareTri3Ptr> AllTris; @@ -1632,11 +1645,11 @@ void bowyerWatsonFrontalLayers(GFace *gf, bool quad, if (!ActiveTris.size())break; /* if (1 || gf->tag() == 1900){ - char name[245]; - sprintf(name,"x_GFace_%d_Layer_%d.pos",gf->tag(),ITER); - _printTris (name, AllTris, Us,Vs,true); - } - */ + char name[245]; + sprintf(name,"x_GFace_%d_Layer_%d.pos",gf->tag(),ITER); + _printTris (name, AllTris, Us,Vs,true); + } + */ std::set<MTri3*,compareTri3Ptr>::iterator WORST_ITER = ActiveTris.begin(); MTri3 *worst = (*WORST_ITER); @@ -1644,38 +1657,38 @@ void bowyerWatsonFrontalLayers(GFace *gf, bool quad, if (!worst->isDeleted() && (ITERATION > max_layers ? isActive(worst, LIMIT_, active_edge) : isActive(worst, LIMIT_, active_edge,&_front) ) && - worst->getRadius() > LIMIT_){ - // for (active_edge = 0 ; active_edge < 0 ; active_edge ++){ - // if (active_edges[active_edge])break; - // } - // Msg::Info("%7d points created -- Worst tri infinite radius is %8.3f -- " + worst->getRadius() > LIMIT_){ + // for (active_edge = 0 ; active_edge < 0 ; active_edge ++){ + // if (active_edges[active_edge])break; + // } + // Msg::Info("%7d points created -- Worst tri infinite radius is %8.3f -- " // "front size %6d", vSizes.size(), worst->getRadius(),_front.size()); - if(ITER++ % 5000 == 0) - Msg::Debug("%7d points created -- Worst tri infinite radius is %8.3f -- " - "front size %6d", DATA.vSizes.size(), worst->getRadius(),_front.size()); - - // compute the middle point of the edge - double newPoint[2],metric[3]={1,0,1}; - if (quad) optimalPointFrontalQuadB (gf,worst,active_edge,DATA,newPoint,metric); - else optimalPointFrontalB (gf,worst,active_edge,DATA,newPoint,metric); - - // printf("start INSERT A POINT %g %g \n",newPoint[0],newPoint[1]); - insertAPoint(gf, AllTris.end(), newPoint, 0, DATA, AllTris, &ActiveTris, worst); - // else if (!worst->isDeleted() && worst->getRadius() > LIMIT_){ - // ActiveTrisNotInFront.insert(worst); - // } - // printf("-----------------> size %d\n",AllTris.size()); - - /* - if(ITER % 1== 0){ - char name[245]; - sprintf(name,"frontal%d-ITER%d.pos",gf->tag(),ITER); - _printTris (name, AllTris, Us,Vs,false); - } - */ + if(ITER++ % 5000 == 0) + Msg::Debug("%7d points created -- Worst tri infinite radius is %8.3f -- " + "front size %6d", DATA.vSizes.size(), worst->getRadius(),_front.size()); + + // compute the middle point of the edge + double newPoint[2],metric[3]={1,0,1}; + if (quad) optimalPointFrontalQuadB (gf,worst,active_edge,DATA,newPoint,metric); + else optimalPointFrontalB (gf,worst,active_edge,DATA,newPoint,metric); + + // printf("start INSERT A POINT %g %g \n",newPoint[0],newPoint[1]); + insertAPoint(gf, AllTris.end(), newPoint, 0, DATA, AllTris, &ActiveTris, worst); + // else if (!worst->isDeleted() && worst->getRadius() > LIMIT_){ + // ActiveTrisNotInFront.insert(worst); + // } + // printf("-----------------> size %d\n",AllTris.size()); + + /* + if(ITER % 1== 0){ + char name[245]; + sprintf(name,"frontal%d-ITER%d.pos",gf->tag(),ITER); + _printTris (name, AllTris, Us,Vs,false); + } + */ } else if (!worst->isDeleted() && worst->getRadius() > LIMIT_){ - ActiveTrisNotInFront.insert(worst); + ActiveTrisNotInFront.insert(worst); } } _front.clear(); @@ -1684,400 +1697,408 @@ void bowyerWatsonFrontalLayers(GFace *gf, bool quad, for ( ; it!=ActiveTrisNotInFront.end();++it){ // for ( ; it!=AllTris.end();++it){ if((*it)->getRadius() > LIMIT_ && isActive(*it,LIMIT_,active_edge)){ - ActiveTris.insert(*it); - updateActiveEdges(*it, LIMIT_, _front); + ActiveTris.insert(*it); + updateActiveEdges(*it, LIMIT_, _front); } } // Msg::Info("%d active tris %d front edges %d not in front", // ActiveTris.size(),_front.size(),ActiveTrisNotInFront.size()); if (!ActiveTris.size()) break; - } + } - // char name[245]; - // sprintf(name,"frontal%d-real.pos", gf->tag()); - // _printTris (name, AllTris, Us, Vs,false); - // sprintf(name,"frontal%d-param.pos", gf->tag()); - // _printTris (name, AllTris, Us, Vs,true); - transferDataStructure(gf, AllTris, DATA); - MTri3::radiusNorm = 2; - LIMIT_ = 0.5 * sqrt(2.0) * 1; - backgroundMesh::unset(); + // char name[245]; + // sprintf(name,"frontal%d-real.pos", gf->tag()); + // _printTris (name, AllTris, Us, Vs,false); + // sprintf(name,"frontal%d-param.pos", gf->tag()); + // _printTris (name, AllTris, Us, Vs,true); + transferDataStructure(gf, AllTris, DATA); + MTri3::radiusNorm = 2; + LIMIT_ = 0.5 * sqrt(2.0) * 1; + + backgroundMesh::unset(); #if defined(HAVE_ANN) - { - FieldManager *fields = gf->model()->getFields(); - BoundaryLayerField *blf = 0; - if(fields->getBoundaryLayerField() > 0){ - Field *bl_field = fields->get(fields->getBoundaryLayerField()); - blf = dynamic_cast<BoundaryLayerField*> (bl_field); - if (blf && !blf->iRecombine)quadsToTriangles(gf,10000); + { + FieldManager *fields = gf->model()->getFields(); + BoundaryLayerField *blf = 0; + if(fields->getBoundaryLayerField() > 0){ + Field *bl_field = fields->get(fields->getBoundaryLayerField()); + blf = dynamic_cast<BoundaryLayerField*> (bl_field); + if (blf && !blf->iRecombine)quadsToTriangles(gf,10000); + } } - } #endif -} - -void bowyerWatsonParallelograms(GFace *gf, - std::map<MVertex* , MVertex*>* equivalence, - std::map<MVertex*, SPoint2> * parametricCoordinates) -{ - std::set<MTri3*,compareTri3Ptr> AllTris; - bidimMeshData DATA(equivalence, parametricCoordinates); - std::vector<MVertex*> packed; - std::vector<SMetric3> metrics; - - // printf("creating the points\n"); - packingOfParallelograms(gf, packed, metrics); - // printf("points created\n"); - - buildMeshGenerationDataStructures (gf, AllTris, DATA); - - // delaunise the initial mesh - int nbSwaps = edgeSwapPass(gf, AllTris, SWCR_DEL, DATA); - Msg::Debug("Delaunization of the initial mesh done (%d swaps)", nbSwaps); - - //std::sort(packed.begin(), packed.end(), MVertexLessThanLexicographic()); - SortHilbert(packed); + } - // printf("staring to insert points\n"); - N_GLOBAL_SEARCH = 0; - N_SEARCH = 0; - DT_INSERT_VERTEX = 0; - double t1 = Cpu(); - MTri3 *oneNewTriangle = 0; - for (unsigned int i=0;i<packed.size();){ - MTri3 *worst = *AllTris.begin(); - if (worst->isDeleted()){ - delete worst->tri(); - delete worst; - AllTris.erase(AllTris.begin()); - } + void bowyerWatsonParallelograms(GFace *gf, + std::map<MVertex* , MVertex*>* equivalence, + std::map<MVertex*, SPoint2> * parametricCoordinates) + { + std::set<MTri3*,compareTri3Ptr> AllTris; + bidimMeshData DATA(equivalence, parametricCoordinates); + std::vector<MVertex*> packed; + std::vector<SMetric3> metrics; + + // printf("creating the points\n"); + // PEB MODIF + if (old_algo_hexa()) + packingOfParallelograms(gf, packed, metrics); else{ - double newPoint[2] ; - packed[i]->getParameter(0,newPoint[0]); - packed[i]->getParameter(1,newPoint[1]); - delete packed[i]; - double metric[3]; - // buildMetric(gf, newPoint, metrics[i], metric); - buildMetric(gf, newPoint, metric); - - bool success = insertAPoint(gf, AllTris.begin(), newPoint, metric, DATA , AllTris, 0, oneNewTriangle, &oneNewTriangle); - if (!success) oneNewTriangle = 0; - // if (!success)printf("success %d %d\n",success,AllTris.size()); - i++; + Filler2D f; + f.pointInsertion2D(gf, packed, metrics); } + // END PEB MODIF + // printf("points created\n"); + + buildMeshGenerationDataStructures (gf, AllTris, DATA); + + // delaunise the initial mesh + int nbSwaps = edgeSwapPass(gf, AllTris, SWCR_DEL, DATA); + Msg::Debug("Delaunization of the initial mesh done (%d swaps)", nbSwaps); + + //std::sort(packed.begin(), packed.end(), MVertexLessThanLexicographic()); + SortHilbert(packed); + + // printf("staring to insert points\n"); + N_GLOBAL_SEARCH = 0; + N_SEARCH = 0; + DT_INSERT_VERTEX = 0; + double t1 = Cpu(); + MTri3 *oneNewTriangle = 0; + for (unsigned int i=0;i<packed.size();){ + MTri3 *worst = *AllTris.begin(); + if (worst->isDeleted()){ + delete worst->tri(); + delete worst; + AllTris.erase(AllTris.begin()); + } + else{ + double newPoint[2] ; + packed[i]->getParameter(0,newPoint[0]); + packed[i]->getParameter(1,newPoint[1]); + delete packed[i]; + double metric[3]; + // buildMetric(gf, newPoint, metrics[i], metric); + buildMetric(gf, newPoint, metric); + + bool success = insertAPoint(gf, AllTris.begin(), newPoint, metric, DATA , AllTris, 0, oneNewTriangle, &oneNewTriangle); + if (!success) oneNewTriangle = 0; + // if (!success)printf("success %d %d\n",success,AllTris.size()); + i++; + } - if(1.0* AllTris.size() > 2.5 * DATA.vSizes.size()){ - // int n1 = AllTris.size(); - std::set<MTri3*,compareTri3Ptr>::iterator itd = AllTris.begin(); - while(itd != AllTris.end()){ - if((*itd)->isDeleted()){ - delete *itd; - AllTris.erase(itd++); + if(1.0* AllTris.size() > 2.5 * DATA.vSizes.size()){ + // int n1 = AllTris.size(); + std::set<MTri3*,compareTri3Ptr>::iterator itd = AllTris.begin(); + while(itd != AllTris.end()){ + if((*itd)->isDeleted()){ + delete *itd; + AllTris.erase(itd++); + } + else + itd++; } - else - itd++; + // Msg::Info("cleaning up the memory %d -> %d", n1, AllTris.size()); } - // Msg::Info("cleaning up the memory %d -> %d", n1, AllTris.size()); - } - } - // printf("%d vertices \n",(int)packed.size()); - double t2 = Cpu(); - double DT = (double)(t2-t1); - if (packed.size()) - printf("points inserted DT %12.5E points per minute : %12.5E %d global searchs %d searchs per insertion\n", - DT,60.*packed.size()/DT,N_GLOBAL_SEARCH, (int)(N_SEARCH/packed.size())); - transferDataStructure(gf, AllTris, DATA); - backgroundMesh::unset(); + } + // printf("%d vertices \n",(int)packed.size()); + double t2 = Cpu(); + double DT = (double)(t2-t1); + if (packed.size()) + printf("points inserted DT %12.5E points per minute : %12.5E %d global searchs %d searchs per insertion\n", + DT,60.*packed.size()/DT,N_GLOBAL_SEARCH, (int)(N_SEARCH/packed.size())); + transferDataStructure(gf, AllTris, DATA); + backgroundMesh::unset(); #if defined(HAVE_ANN) - { - FieldManager *fields = gf->model()->getFields(); - BoundaryLayerField *blf = 0; - if(fields->getBoundaryLayerField() > 0){ - Field *bl_field = fields->get(fields->getBoundaryLayerField()); - blf = dynamic_cast<BoundaryLayerField*> (bl_field); - if (blf && !blf->iRecombine)quadsToTriangles(gf,10000); + { + FieldManager *fields = gf->model()->getFields(); + BoundaryLayerField *blf = 0; + if(fields->getBoundaryLayerField() > 0){ + Field *bl_field = fields->get(fields->getBoundaryLayerField()); + blf = dynamic_cast<BoundaryLayerField*> (bl_field); + if (blf && !blf->iRecombine)quadsToTriangles(gf,10000); + } } - } #endif -} - - -static void initialSquare(std::vector<MVertex*> &v, - MVertex *box[4], - std::vector<MTri3*> &t){ - SBoundingBox3d bbox ; - for (size_t i=0;i<v.size();i++){ - MVertex *pv = v[i]; - bbox += SPoint3(pv->x(),pv->y(),pv->z()); } - bbox *= 1.3; - box[0] = new MVertex (bbox.min().x(),bbox.min().y(),0); - box[1] = new MVertex (bbox.max().x(),bbox.min().y(),0); - box[2] = new MVertex (bbox.max().x(),bbox.max().y(),0); - box[3] = new MVertex (bbox.min().x(),bbox.max().y(),0); - MTriangle *t0 = new MTriangle (box[0],box[1],box[2]); - MTriangle *t1 = new MTriangle (box[2],box[3],box[0]); - t.push_back(new MTri3(t0,0.0)); - t.push_back(new MTri3(t1,0.0)); - connectTriangles(t); -} -MTri3 * getTriToBreak (MVertex *v, std::vector<MTri3*> &t, int &NB_GLOBAL_SEARCH, int &ITER){ - // last inserted is used as starting point - // we know it is not deleted - unsigned int k = t.size() - 1; - while(t[k]->isDeleted()){ - k--; - } - MTri3 *start = t[k]; - start = search4Triangle (start,v,(int)t.size(),ITER); - if (start)return start; - // printf("Global Search has to be done\n"); - NB_GLOBAL_SEARCH++; - for (size_t i = 0;i<t.size();i++){ - if (!t[i]->isDeleted() && inCircumCircleXY(t[i]->tri(),v))return t[i]; + static void initialSquare(std::vector<MVertex*> &v, + MVertex *box[4], + std::vector<MTri3*> &t){ + SBoundingBox3d bbox ; + for (size_t i=0;i<v.size();i++){ + MVertex *pv = v[i]; + bbox += SPoint3(pv->x(),pv->y(),pv->z()); + } + bbox *= 1.3; + box[0] = new MVertex (bbox.min().x(),bbox.min().y(),0); + box[1] = new MVertex (bbox.max().x(),bbox.min().y(),0); + box[2] = new MVertex (bbox.max().x(),bbox.max().y(),0); + box[3] = new MVertex (bbox.min().x(),bbox.max().y(),0); + MTriangle *t0 = new MTriangle (box[0],box[1],box[2]); + MTriangle *t1 = new MTriangle (box[2],box[3],box[0]); + t.push_back(new MTri3(t0,0.0)); + t.push_back(new MTri3(t1,0.0)); + connectTriangles(t); + } + + + MTri3 * getTriToBreak (MVertex *v, std::vector<MTri3*> &t, int &NB_GLOBAL_SEARCH, int &ITER){ + // last inserted is used as starting point + // we know it is not deleted + unsigned int k = t.size() - 1; + while(t[k]->isDeleted()){ + k--; + } + MTri3 *start = t[k]; + start = search4Triangle (start,v,(int)t.size(),ITER); + if (start)return start; + // printf("Global Search has to be done\n"); + NB_GLOBAL_SEARCH++; + for (size_t i = 0;i<t.size();i++){ + if (!t[i]->isDeleted() && inCircumCircleXY(t[i]->tri(),v))return t[i]; + } + return 0; } - return 0; -} -bool triOnBox (MTriangle *t, MVertex *box[4]){ - for (size_t i = 0;i<3;i++){ - for (size_t j = 0;j<4;j++){ - if (t->getVertex(i) == box[j]) - return true; + bool triOnBox (MTriangle *t, MVertex *box[4]){ + for (size_t i = 0;i<3;i++){ + for (size_t j = 0;j<4;j++){ + if (t->getVertex(i) == box[j]) + return true; + } } + return false; } - return false; -} - -// vertices are supposed to be sitting in the XY plane ! -void recoverEdges (std::vector<MTri3*> &t, std::vector<MEdge> &edges); + // vertices are supposed to be sitting in the XY plane ! -void delaunayMeshIn2D(std::vector<MVertex*> &v, - std::vector<MTriangle*> &result, - bool removeBox, - std::vector<MEdge> *edgesToRecover, - bool hilbertSort) -{ - std::vector<MTri3*> t; - t.reserve (v.size()*2); - std::vector<edgeXface> conn; - std::vector<edgeXface> shell; - std::vector<MTri3*> cavity; - MVertex *box[4]; - initialSquare (v,box,t); - - int NB_GLOBAL_SEARCH = 0; - double AVG_ITER = 0; - double AVG_CAVSIZE = 0; - - double t1 = Cpu(); - - // Msg::Info("Delaunay 2D SORTING"); - if(hilbertSort) SortHilbert(v); - - double ta=0,tb=0,tc=0,td=0,T; - // Msg::Info("Delaunay 2D INSERTING"); - for (size_t i=0;i<v.size();i++){ - MVertex *pv = v[i]; - - int NITER = 0; - T = Cpu(); - MTri3 * found = getTriToBreak (pv,t,NB_GLOBAL_SEARCH,NITER); - ta += Cpu()-T; - AVG_ITER += (double)NITER; - if(!found) { - Msg::Error("Cannot insert a point in 2D Delaunay"); - continue; - } - shell.clear(); - cavity.clear(); + void recoverEdges (std::vector<MTri3*> &t, std::vector<MEdge> &edges); - T = Cpu(); - recurFindCavity(shell, cavity, pv, found); - AVG_CAVSIZE += (double)cavity.size(); - tb += Cpu()-T; - //double V = 0.0; - //for (unsigned int k=0;k<cavity.size();k++)V+=fabs(cavity[k]->tri()->getVolume()); - - std::vector<MTri3*> extended_cavity; - //double Vb = 0.0; - - T = Cpu(); - for (unsigned int count = 0; count < shell.size(); count++){ - const edgeXface &fxt = shell[count]; - MTriangle *tr; - MTri3 *t3; - MVertex *v0 = fxt.v[0]; - MVertex *v1 = fxt.v[1]; - MTri3 *otherSide = fxt.t1->getNeigh(fxt.i1); - if (count < cavity.size()){ - t3 = cavity[count]; - tr = t3->tri() ; - tr->setVertex(0,v0); - tr->setVertex(1,v1); - tr->setVertex(2,pv); + void delaunayMeshIn2D(std::vector<MVertex*> &v, + std::vector<MTriangle*> &result, + bool removeBox, + std::vector<MEdge> *edgesToRecover, + bool hilbertSort) + { + std::vector<MTri3*> t; + t.reserve (v.size()*2); + std::vector<edgeXface> conn; + std::vector<edgeXface> shell; + std::vector<MTri3*> cavity; + MVertex *box[4]; + initialSquare (v,box,t); + + int NB_GLOBAL_SEARCH = 0; + double AVG_ITER = 0; + double AVG_CAVSIZE = 0; + + double t1 = Cpu(); + + // Msg::Info("Delaunay 2D SORTING"); + if(hilbertSort) SortHilbert(v); + + double ta=0,tb=0,tc=0,td=0,T; + // Msg::Info("Delaunay 2D INSERTING"); + for (size_t i=0;i<v.size();i++){ + MVertex *pv = v[i]; + + int NITER = 0; + T = Cpu(); + MTri3 * found = getTriToBreak (pv,t,NB_GLOBAL_SEARCH,NITER); + ta += Cpu()-T; + AVG_ITER += (double)NITER; + if(!found) { + Msg::Error("Cannot insert a point in 2D Delaunay"); + continue; } - else{ - tr = new MTriangle(v0,v1,pv); - t3 = new MTri3(tr, 0.0); - t.push_back(t3); + shell.clear(); + cavity.clear(); + + T = Cpu(); + recurFindCavity(shell, cavity, pv, found); + AVG_CAVSIZE += (double)cavity.size(); + tb += Cpu()-T; + //double V = 0.0; + //for (unsigned int k=0;k<cavity.size();k++)V+=fabs(cavity[k]->tri()->getVolume()); + + std::vector<MTri3*> extended_cavity; + //double Vb = 0.0; + + T = Cpu(); + for (unsigned int count = 0; count < shell.size(); count++){ + const edgeXface &fxt = shell[count]; + MTriangle *tr; + MTri3 *t3; + MVertex *v0 = fxt.v[0]; + MVertex *v1 = fxt.v[1]; + MTri3 *otherSide = fxt.t1->getNeigh(fxt.i1); + if (count < cavity.size()){ + t3 = cavity[count]; + tr = t3->tri() ; + tr->setVertex(0,v0); + tr->setVertex(1,v1); + tr->setVertex(2,pv); + } + else{ + tr = new MTriangle(v0,v1,pv); + t3 = new MTri3(tr, 0.0); + t.push_back(t3); + } + //Vb+= fabs(tr->getVolume()); + extended_cavity.push_back(t3); + if (otherSide) + extended_cavity.push_back(otherSide); } - //Vb+= fabs(tr->getVolume()); - extended_cavity.push_back(t3); - if (otherSide) - extended_cavity.push_back(otherSide); - } - tc += Cpu()-T; - //if (fabs(Vb-V) > 1.e-8 * (Vb+V))printf("%12.5E %12.5E\n",Vb,V); + tc += Cpu()-T; + //if (fabs(Vb-V) > 1.e-8 * (Vb+V))printf("%12.5E %12.5E\n",Vb,V); - for (unsigned int k=0;k<std::min(cavity.size(),shell.size());k++){ - cavity[k]->setDeleted(false); - for (unsigned int l=0;l<3;l++){ - cavity[k]->setNeigh(l,0); + for (unsigned int k=0;k<std::min(cavity.size(),shell.size());k++){ + cavity[k]->setDeleted(false); + for (unsigned int l=0;l<3;l++){ + cavity[k]->setNeigh(l,0); + } } + T = Cpu(); + connectTris(extended_cavity.begin(),extended_cavity.end(),conn); + td += Cpu()-T; } - T = Cpu(); - connectTris(extended_cavity.begin(),extended_cavity.end(),conn); - td += Cpu()-T; - } - double t2 = Cpu(); - Msg::Debug("Delaunay 2D done for %d points : CPU = %g, %d global searches, AVG walk size %g , AVG cavity size %g", - v.size(), t2-t1,NB_GLOBAL_SEARCH,1.+AVG_ITER/v.size(),AVG_CAVSIZE/v.size()); - // printf("%g %g %g %g --> %g(%g)\n",ta,tb,tc,td,t2-t1,ta+tb+tc+td); + double t2 = Cpu(); + Msg::Debug("Delaunay 2D done for %d points : CPU = %g, %d global searches, AVG walk size %g , AVG cavity size %g", + v.size(), t2-t1,NB_GLOBAL_SEARCH,1.+AVG_ITER/v.size(),AVG_CAVSIZE/v.size()); + // printf("%g %g %g %g --> %g(%g)\n",ta,tb,tc,td,t2-t1,ta+tb+tc+td); - if (edgesToRecover)recoverEdges (t,*edgesToRecover); + if (edgesToRecover)recoverEdges (t,*edgesToRecover); - // FILE *f = fopen ("tri.pos","w"); - // fprintf(f,"View \"\"{\n"); - for (size_t i = 0;i<t.size();i++){ - if (t[i]->isDeleted() || (removeBox && triOnBox (t[i]->tri(),box))) delete t[i]->tri(); - else { - result.push_back(t[i]->tri()); - // t[i]->tri()->writePOS (f, false,false,true,false,false,false); + // FILE *f = fopen ("tri.pos","w"); + // fprintf(f,"View \"\"{\n"); + for (size_t i = 0;i<t.size();i++){ + if (t[i]->isDeleted() || (removeBox && triOnBox (t[i]->tri(),box))) delete t[i]->tri(); + else { + result.push_back(t[i]->tri()); + // t[i]->tri()->writePOS (f, false,false,true,false,false,false); + } + delete t[i]; } - delete t[i]; - } - if (removeBox){for (int i=0;i<4;i++)delete box[i];} - else {for (int i=0;i<4;i++)v.push_back(box[i]);} + if (removeBox){for (int i=0;i<4;i++)delete box[i];} + else {for (int i=0;i<4;i++)v.push_back(box[i]);} - // fprintf(f,"};\n"); - // fclose(f); -} - -bool swapedge (MVertex *v1 ,MVertex *v2, MVertex *v3, MVertex *v4, MTri3* t1, int iLocalEdge){ - MTri3 *t2 = t1->getNeigh(iLocalEdge); - if(!t2) return false; - - MTriangle *t1b = new MTriangle(v2, v3, v4); - MTriangle *t2b = new MTriangle(v4, v3, v1); - double BEFORE = t1->tri()->getVolume()+t2->tri()->getVolume(); - double AFTER = t1b->getVolume()+t2b->getVolume(); - // printf("swapping %d %d %d %d %g %g\n",v1->getNum(),v2->getNum(),v3->getNum(),v4->getNum(),BEFORE,AFTER); - if (fabs(BEFORE-AFTER)/BEFORE > 1.e-8){ - delete t1b; - delete t2b; - return false; + // fprintf(f,"};\n"); + // fclose(f); } - // printf("volumes ok\n"); - - delete t1->tri(); - delete t2->tri(); - t1->setTri(t1b); - t2->setTri(t2b); - - std::set<MTri3*> cavity; - cavity.insert(t1); - cavity.insert(t2); - for(int i = 0; i < 3; i++){ - if(t1->getNeigh(i)) - cavity.insert(t1->getNeigh(i)); - if(t2->getNeigh(i)) - cavity.insert(t2->getNeigh(i)); - } - std::vector<edgeXface> conn; - connectTris(cavity.begin(), cavity.end(), conn); - return true; -} -bool diffend (MVertex *v1, MVertex *v2, MVertex *p1, MVertex *p2){ - if (v1 == p1 || v2 == p1 || v1 == p2 || v2 == p2)return false; - return true; -} + bool swapedge (MVertex *v1 ,MVertex *v2, MVertex *v3, MVertex *v4, MTri3* t1, int iLocalEdge){ + MTri3 *t2 = t1->getNeigh(iLocalEdge); + if(!t2) return false; -/* + MTriangle *t1b = new MTriangle(v2, v3, v4); + MTriangle *t2b = new MTriangle(v4, v3, v1); + double BEFORE = t1->tri()->getVolume()+t2->tri()->getVolume(); + double AFTER = t1b->getVolume()+t2b->getVolume(); + // printf("swapping %d %d %d %d %g %g\n",v1->getNum(),v2->getNum(),v3->getNum(),v4->getNum(),BEFORE,AFTER); + if (fabs(BEFORE-AFTER)/BEFORE > 1.e-8){ + delete t1b; + delete t2b; + return false; + } + // printf("volumes ok\n"); + + delete t1->tri(); + delete t2->tri(); + t1->setTri(t1b); + t2->setTri(t2b); + + std::set<MTri3*> cavity; + cavity.insert(t1); + cavity.insert(t2); + for(int i = 0; i < 3; i++){ + if(t1->getNeigh(i)) + cavity.insert(t1->getNeigh(i)); + if(t2->getNeigh(i)) + cavity.insert(t2->getNeigh(i)); + } + std::vector<edgeXface> conn; + connectTris(cavity.begin(), cavity.end(), conn); + return true; + } -*/ + bool diffend (MVertex *v1, MVertex *v2, MVertex *p1, MVertex *p2){ + if (v1 == p1 || v2 == p1 || v1 == p2 || v2 == p2)return false; + return true; + } + + /* -static bool recoverEdgeBySwaps (std::vector<MTri3*> &t, MVertex *mv1, MVertex *mv2, std::vector<MEdge> &edges){ - - SPoint3 pv1 (mv1->x(),mv1->y(),0); - SPoint3 pv2 (mv2->x(),mv2->y(),0); - double xcc[2]; - for (unsigned int i=0;i<t.size();i++){ - for (unsigned int j=0;j<3;j++){ - MVertex *v1 = t[i]->tri()->getVertex((j+2)%3); - MVertex *v2 = t[i]->tri()->getVertex(j); - MVertex *v3 = t[i]->tri()->getVertex((j+1)%3); - MVertex *o = t[i]->otherSide(j); - if (o){ - SPoint3 p1 (v1->x(),v1->y(),0); - SPoint3 p2 (v2->x(),v2->y(),0); - SPoint3 p3 (v3->x(),v3->y(),0); - SPoint3 po (o->x(),o->y(),0); - if (diffend(v1,v2,mv1,mv2)){ - if (intersection_segments (p1, p2, pv1, pv2,xcc)){ - // if (std::binary_search(edges.begin(),edges.end(),MEdge(v1,v2),Less_Edge)){ - // Msg::Error("1D mesh self intersects"); - // } - if (!intersection_segments(po, p3, pv1, pv2,xcc) || (v3 == mv1 || o == mv1 || v3 == mv2 || o == mv2)){ - if(swapedge (v1,v2,v3,o,t[i],j))return true; - } - } - } + */ + + static bool recoverEdgeBySwaps (std::vector<MTri3*> &t, MVertex *mv1, MVertex *mv2, std::vector<MEdge> &edges){ + + SPoint3 pv1 (mv1->x(),mv1->y(),0); + SPoint3 pv2 (mv2->x(),mv2->y(),0); + double xcc[2]; + for (unsigned int i=0;i<t.size();i++){ + for (unsigned int j=0;j<3;j++){ + MVertex *v1 = t[i]->tri()->getVertex((j+2)%3); + MVertex *v2 = t[i]->tri()->getVertex(j); + MVertex *v3 = t[i]->tri()->getVertex((j+1)%3); + MVertex *o = t[i]->otherSide(j); + if (o){ + SPoint3 p1 (v1->x(),v1->y(),0); + SPoint3 p2 (v2->x(),v2->y(),0); + SPoint3 p3 (v3->x(),v3->y(),0); + SPoint3 po (o->x(),o->y(),0); + if (diffend(v1,v2,mv1,mv2)){ + if (intersection_segments (p1, p2, pv1, pv2,xcc)){ + // if (std::binary_search(edges.begin(),edges.end(),MEdge(v1,v2),Less_Edge)){ + // Msg::Error("1D mesh self intersects"); + // } + if (!intersection_segments(po, p3, pv1, pv2,xcc) || (v3 == mv1 || o == mv1 || v3 == mv2 || o == mv2)){ + if(swapedge (v1,v2,v3,o,t[i],j))return true; + } + } + } + } } } + return false; } - return false; -} -// recover the edges by edge swapping in the triangulation. -// edges are not supposed to + // recover the edges by edge swapping in the triangulation. + // edges are not supposed to -void recoverEdges (std::vector<MTri3*> &t, std::vector<MEdge> &edges) -{ - Less_Edge le; - std::sort(edges.begin(),edges.end(),le); - std::set<MEdge,Less_Edge> setOfMeshEdges; - for (size_t i = 0;i<t.size();i++){ - for (int j=0;j<3;j++){ - setOfMeshEdges.insert(t[i]->tri()->getEdge(j)); + void recoverEdges (std::vector<MTri3*> &t, std::vector<MEdge> &edges) + { + Less_Edge le; + std::sort(edges.begin(),edges.end(),le); + std::set<MEdge,Less_Edge> setOfMeshEdges; + for (size_t i = 0;i<t.size();i++){ + for (int j=0;j<3;j++){ + setOfMeshEdges.insert(t[i]->tri()->getEdge(j)); + } } - } - std::vector<MEdge> edgesToRecover; - for (unsigned int i=0;i<edges.size();i++){ - if (setOfMeshEdges.find(edges[i])==setOfMeshEdges.end()) - edgesToRecover.push_back(edges[i]); - } + std::vector<MEdge> edgesToRecover; + for (unsigned int i=0;i<edges.size();i++){ + if (setOfMeshEdges.find(edges[i])==setOfMeshEdges.end()) + edgesToRecover.push_back(edges[i]); + } - Msg::Info("%d edges to recover among %d edges",edgesToRecover.size(),edges.size()); - // int iter = 0; - // char name[256]; - // sprintf(name,"iter%d.pos",iter++); - // _printTris (name, t.begin(),t.end(),0); - for (unsigned int i=0;i<edgesToRecover.size();i++){ - MVertex *mstart = edgesToRecover[i].getVertex(0); - MVertex *mend = edgesToRecover[i].getVertex(1); - Msg::Info("recovering edge %d %d",mstart->getNum(),mend->getNum()); - //int iter; - while(recoverEdgeBySwaps (t, mstart, mend,edges)) { - //iter ++; + Msg::Info("%d edges to recover among %d edges",edgesToRecover.size(),edges.size()); + // int iter = 0; + // char name[256]; + // sprintf(name,"iter%d.pos",iter++); + // _printTris (name, t.begin(),t.end(),0); + for (unsigned int i=0;i<edgesToRecover.size();i++){ + MVertex *mstart = edgesToRecover[i].getVertex(0); + MVertex *mend = edgesToRecover[i].getVertex(1); + Msg::Info("recovering edge %d %d",mstart->getNum(),mend->getNum()); + //int iter; + while(recoverEdgeBySwaps (t, mstart, mend,edges)) { + //iter ++; + } } } -} diff --git a/Mesh/meshGFaceElliptic.cpp b/Mesh/meshGFaceElliptic.cpp index c722cb7474..c0c5ee2de6 100644 --- a/Mesh/meshGFaceElliptic.cpp +++ b/Mesh/meshGFaceElliptic.cpp @@ -16,7 +16,7 @@ #include "MTriangle.h" #include "MQuadrangle.h" #include "MLine.h" -#include "BackgroundMesh.h" +#include "BackgroundMeshTools.h" #include "Numeric.h" #include "GmshMessage.h" #include "Generator.h" diff --git a/Mesh/meshGFaceOptimize.cpp b/Mesh/meshGFaceOptimize.cpp index 80254a7a70..a061d38082 100644 --- a/Mesh/meshGFaceOptimize.cpp +++ b/Mesh/meshGFaceOptimize.cpp @@ -15,7 +15,7 @@ #include "MTriangle.h" #include "MQuadrangle.h" #include "MLine.h" -#include "BackgroundMesh.h" +#include "BackgroundMeshTools.h" #include "Numeric.h" #include "GmshMessage.h" #include "Generator.h" @@ -148,6 +148,11 @@ void buildMeshGenerationDataStructures(GFace *gf, for(unsigned int i = 0;i < gf->triangles.size(); i++) setLcsInit(gf->triangles[i], vSizesMap); + std::map<MVertex*, double>::iterator itfind = vSizesMap.find(NULL); + if (itfind!=vSizesMap.end()){ + std::cout << "***************************************** NULL" << std::endl; + throw; + } for(unsigned int i = 0;i < gf->triangles.size(); i++) setLcs(gf->triangles[i], vSizesMap, data); @@ -3628,9 +3633,9 @@ void recombineIntoQuads(GFace *gf, if(haveParam){ if (saveAll) gf->model()->writeMSH("smoothed.msh"); int ITER=0; - // int optistatus[6] = {0,0,0,0,0,0}; - std::set<MEdge,Less_Edge> prioritory; - double exbad = -100; + // int optistatus[6] = {0,0,0,0,0,0}; + std::set<MEdge,Less_Edge> prioritory; + double exbad = -100; while(1){ // int maxCavitySize = CTX::instance()->mesh.bunin; // optistatus[0] = (ITERB == 1) ?splitFlatQuads(gf, .01, prioritory) : 0; @@ -3654,8 +3659,8 @@ void recombineIntoQuads(GFace *gf, } } if(haveParam) { - laplaceSmoothing(gf,CTX::instance()->mesh.nbSmoothing, true); - optiSmoothing(gf,CTX::instance()->mesh.nbSmoothing,true); + laplaceSmoothing(gf,CTX::instance()->mesh.nbSmoothing, true); + optiSmoothing(gf,CTX::instance()->mesh.nbSmoothing,true); } // untangleInvalidQuads(gf,CTX::instance()->mesh.nbSmoothing); } @@ -3736,24 +3741,24 @@ Temporary::~Temporary(){} SVector3 Temporary::compute_gradient(MElement*element) { /*double x1,y1,z1; - double x2,y2,z2; - double x3,y3,z3; - double x,y,z; - MVertex*vertex1 = element->getVertex(0); - MVertex*vertex2 = element->getVertex(1); - MVertex*vertex3 = element->getVertex(2); - x1 = vertex1->x(); - y1 = vertex1->y(); - z1 = vertex1->z(); - x2 = vertex2->x(); - y2 = vertex2->y(); - z2 = vertex2->z(); - x3 = vertex3->x(); - y3 = vertex3->y(); - z3 = vertex3->z(); - x = (x1+x2+x3)/3.0; - y = (y1+y2+y3)/3.0; - z = (z1+z2+z3)/3.0;*/ + double x2,y2,z2; + double x3,y3,z3; + double x,y,z; + MVertex*vertex1 = element->getVertex(0); + MVertex*vertex2 = element->getVertex(1); + MVertex*vertex3 = element->getVertex(2); + x1 = vertex1->x(); + y1 = vertex1->y(); + z1 = vertex1->z(); + x2 = vertex2->x(); + y2 = vertex2->y(); + z2 = vertex2->z(); + x3 = vertex3->x(); + y3 = vertex3->y(); + z3 = vertex3->z(); + x = (x1+x2+x3)/3.0; + y = (y1+y2+y3)/3.0; + z = (z1+z2+z3)/3.0;*/ return SVector3(0.0,1.0,0.0); } @@ -3815,7 +3820,7 @@ SVector3 Temporary::compute_other_vector(MElement *element) } double Temporary::compute_alignment(const MEdge &_edge, MElement *element1, - MElement *element2) + MElement *element2) { //int number; double scalar_productA,scalar_productB; @@ -3831,7 +3836,7 @@ double Temporary::compute_alignment(const MEdge &_edge, MElement *element1, vertexA = _edge.getVertex(0); vertexB = _edge.getVertex(1); edge = SVector3(vertexB->x()-vertexA->x(), vertexB->y()-vertexA->y(), - vertexB->z()-vertexA->z()); + vertexB->z()-vertexA->z()); edge = edge * (1/norm(edge)); scalar_productA = fabs(dot(gradient,edge)); scalar_productB = fabs(dot(other_vector,edge)); @@ -3852,15 +3857,15 @@ void Temporary::read_data(std::string file_name) for(i = 0;i < data->getNumEntities(0);i++) { if(data->skipEntity(0,i)) continue; - for(j = 0;j < data->getNumElements(0,i);j++){ - if(data->skipElement(0,i,j)) continue; - element = data->getElement(0,i,j); - number = element->getNum(); - data->getValue(0,i,j,0,x); - data->getValue(0,i,j,1,y); - data->getValue(0,i,j,2,z); - gradients[number] = SVector3(x,y,z); - } + for(j = 0;j < data->getNumElements(0,i);j++){ + if(data->skipElement(0,i,j)) continue; + element = data->getElement(0,i,j); + number = element->getNum(); + data->getValue(0,i,j,0,x); + data->getValue(0,i,j,1,y); + data->getValue(0,i,j,2,z); + gradients[number] = SVector3(x,y,z); + } } #endif } diff --git a/Mesh/meshGRegion.cpp b/Mesh/meshGRegion.cpp index e6c3f97ec4..fec89fa4b3 100644 --- a/Mesh/meshGRegion.cpp +++ b/Mesh/meshGRegion.cpp @@ -31,11 +31,13 @@ #include "GFaceCompound.h" #include "meshGRegionMMG3D.h" #include "simple3D.h" -#include "Levy3D.h" #include "directions3D.h" +#include "pointInsertion.h" +#include "Levy3D.h" #include "discreteFace.h" #include "filterElements.h" + #if defined(HAVE_ANN) #include "ANN/ANN.h" #endif @@ -309,7 +311,8 @@ void buildTetgenStructure(GRegion *gr, tetgenio &in, std::vector<MVertex*> &numb in.mesh_dim = 3; in.firstnumber = 1; - in.numberofpoints = allBoundingVertices.size() + Filler::get_nbr_new_vertices() + + int nbvertices_filler = (old_algo_hexa()) ? Filler::get_nbr_new_vertices() : Filler3D::get_nbr_new_vertices(); + in.numberofpoints = allBoundingVertices.size() + nbvertices_filler + LpSmoother::get_nbr_interior_vertices(); in.pointlist = new REAL[in.numberofpoints * 3]; in.pointmarkerlist = NULL; @@ -325,9 +328,12 @@ void buildTetgenStructure(GRegion *gr, tetgenio &in, std::vector<MVertex*> &numb ++itv; } - for(int i=0;i<Filler::get_nbr_new_vertices();i++){ + for(int i=0;i<nbvertices_filler;i++){ MVertex* v; - v = Filler::get_new_vertex(i); + if (old_algo_hexa()) + v = Filler::get_new_vertex(i); + else + v = Filler3D::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(); @@ -1278,9 +1284,11 @@ void MeshDelaunayVolumeTetgen(std::vector<GRegion*> ®ions) 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); + else{ + int nbvertices_filler = (old_algo_hexa()) ? Filler::get_nbr_new_vertices() : Filler3D::get_nbr_new_vertices(); + if(!nbvertices_filler && !LpSmoother::get_nbr_interior_vertices()){ + insertVerticesInRegion(gr,2000000000,!_BL); + } } //emi test frame field diff --git a/Mesh/meshGRegionDelaunayInsertion.cpp b/Mesh/meshGRegionDelaunayInsertion.cpp index a9606e4835..9c210689ee 100644 --- a/Mesh/meshGRegionDelaunayInsertion.cpp +++ b/Mesh/meshGRegionDelaunayInsertion.cpp @@ -9,7 +9,7 @@ #include "GmshMessage.h" #include "robustPredicates.h" #include "OS.h" -#include "BackgroundMesh.h" +//#include "BackgroundMesh.h" #include "meshGRegion.h" #include "meshGRegionLocalMeshMod.h" #include "meshGRegionDelaunayInsertion.h" @@ -1531,9 +1531,9 @@ void bowyerWatsonFrontalLayers(GRegion *gr, bool hex) std::set<MTet4*, compareTet4Ptr> activeTets; int NUM = 0; - if (!backgroundMesh::current()) { - // TODO !!! - } +// if (!backgroundMesh::current()) { +// // TODO !!! +// } if (hex){ LIMIT_ = sqrt(2.) * .99; diff --git a/Mesh/meshGRegionDelaunayInsertion.h b/Mesh/meshGRegionDelaunayInsertion.h index 39fb5c9be7..f3684b677d 100644 --- a/Mesh/meshGRegionDelaunayInsertion.h +++ b/Mesh/meshGRegionDelaunayInsertion.h @@ -12,7 +12,7 @@ #include <stack> #include "MTetrahedron.h" #include "Numeric.h" -#include "BackgroundMesh.h" +#include "BackgroundMeshTools.h" #include "qualityMeasures.h" #include "robustPredicates.h" diff --git a/Mesh/meshGRegionMMG3D.cpp b/Mesh/meshGRegionMMG3D.cpp index 1e71678124..57e72fc724 100644 --- a/Mesh/meshGRegionMMG3D.cpp +++ b/Mesh/meshGRegionMMG3D.cpp @@ -15,7 +15,7 @@ #include "MTetrahedron.h" #include "MTriangle.h" #include "MVertex.h" -#include "BackgroundMesh.h" +#include "BackgroundMeshTools.h" #include "Context.h" extern "C" { diff --git a/Mesh/meshRecombine2D_2.cpp b/Mesh/meshRecombine2D_2.cpp index edb628c275..6fe83b6c37 100644 --- a/Mesh/meshRecombine2D_2.cpp +++ b/Mesh/meshRecombine2D_2.cpp @@ -8,7 +8,7 @@ // #include "meshRecombine2D.h" -#include "BackgroundMesh.h" +#include "BackgroundMeshTools.h" #include "GFace.h" #include <cmath> #include <FL/Fl.H> diff --git a/Mesh/pointInsertion.cpp b/Mesh/pointInsertion.cpp new file mode 100644 index 0000000000..22afd6c7ac --- /dev/null +++ b/Mesh/pointInsertion.cpp @@ -0,0 +1,850 @@ + +#include "pointInsertion.h" +#include "BackgroundMeshManager.h" +#include "BackgroundMesh2D.h" +#include "BackgroundMesh3D.h" +#include "GFace.h" +#include "GRegion.h" + + +#include "OS.h" + +#include <iostream> +#include <fstream> +#include <sstream> +#include <string> + +#include "Context.h" +#include "meshGRegion.h" + +#include "pointInsertionRTreeTools.h" + +#include "intersectCurveSurface.h" + +//#include "google/profiler.h" + + +using namespace std; + +//------------------------------------------------------------------------ + +bool old_algo_hexa(){ + return true; +} + +//------------------------------------------------------------------------ + +template<typename T> +void print_nodal_info(string filename, map<MVertex*, T> &mapp){ + ofstream out(filename.c_str()); + + out << "View \"\"{" << endl; + for (typename map<MVertex*, T>::iterator it = mapp.begin();it!=mapp.end();it++){ + MVertex *v = it->first; + out << "SP( " << v->x() << "," << v->y() << "," << v->z() << "){" << it->second << "};" << endl;; + } + out << "};" << endl; + + out.close(); +} + +//------------------------------------------------------------------------ + +bool shoot(const SPoint2 &start, const SPoint2 &dir, const double &h, SPoint2 &res){ + + const int RK = 1; + + if (RK==1){ + res = start + (dir*h); + // cout << "(" << start[0] << "," <<start[1] << ") -> (" << res[0] << "," <<res[1] << ") " << endl; + return true; + } + + return false; +} + +//------------------------------------------------------------------------ + +bool computeFourNeighbors (frameFieldBackgroundMesh2D *bgm, MVertex *v_center, // the vertex for which we want to generate 4 neighbors (real vertex (xyz), not parametric !!! ) + SPoint2 &midpoint, + bool goNonLinear, // do we compute the position in the real surface which is nonlinear + SPoint2 newP[4][NUMDIR], // look into other directions + SMetric3 &metricField) // the mesh metric +{ + // we assume that v is on surface gf, and backgroundMesh2D has been created based on gf + + // get BGM and GFace + GFace *gf = dynamic_cast<GFace*>(bgm->getBackgroundGEntity()); + + // get the parametric coordinates of the point on the surface + reparamMeshVertexOnFace(v_center, gf, midpoint); + + // get RK info on midpoint (infos in two directions...) + RK_form infos; + bgm->compute_RK_infos(midpoint[0],midpoint[1],v_center->x(), v_center->y(),v_center->z(),infos); + metricField = infos.metricField; + + // shoot in four directions + SPoint2 param_vec; + double h; + // cout << "shooting..." << endl; + for (int i=0;i<4;i++){// in four directions + switch (i){ + case 0: + param_vec = infos.paramt1; + h = infos.paramh.first; + break; + case 1: + param_vec = infos.paramt2; + h = infos.paramh.second; + break; + case 2: + param_vec = infos.paramt1 * -1.; + h = infos.paramh.first; + break; + case 3: + param_vec = infos.paramt2 * -1.; + h = infos.paramh.second; + break; + } + shoot(midpoint,param_vec,h,newP[i][0]); + // cout << "(" << midpoint[0] << "," <<midpoint[1] << ") -> (" << newP[i][0][0] << "," << newP[i][0][1] << ") " << endl; + } + + + + // ------------------------------------------------- + // the following comes from surfaceFiller.cpp... + // ------------------------------------------------- + + const double EPS = 1.e-7; + for (int j=0;j<2;j++){ + for (int i=0;i<4;i++){ + newP[i][0][j] += (EPS* (double)rand() / RAND_MAX); + } + } + + // We could stop here. Yet, if the metric varies a lot, we can solve + // a nonlinear problem in order to find a better approximation in the real + // surface + if (1 && goNonLinear){//---------------------------------------------------// + double L = infos.localsize; + double newPoint[4][2]; + for (int j=0;j<2;j++){ + for (int i=0;i<4;i++){ + newPoint[i][j] = newP[i][0][j]; + } + } + double ERR[4]; + for (int i=0;i<4;i++){ // + // if (newPoint[i][0] < rangeU.low())newPoint[i][0] = rangeU.low(); + // if (newPoint[i][0] > rangeU.high())newPoint[i][0] = rangeU.high(); + // if (newPoint[i][1] < rangeV.low())newPoint[i][1] = rangeV.low(); + // if (newPoint[i][1] > rangeV.high())newPoint[i][1] = rangeV.high(); + GPoint pp = gf->point(newP[i][0]); + double D = sqrt ((pp.x() - v_center->x())*(pp.x() - v_center->x()) + + (pp.y() - v_center->y())*(pp.y() - v_center->y()) + + (pp.z() - v_center->z())*(pp.z() - v_center->z()) ); + ERR[i] = 100*fabs(D-L)/(D+L); + // printf("L = %12.5E D = %12.5E ERR = %12.5E\n",L,D,100*fabs(D-L)/(D+L)); + } + + surfaceFunctorGFace ss (gf); + SVector3 dirs[4] = {infos.t1*(-1.0),infos.t2*(-1.0),infos.t1*(1.0),infos.t2*(1.0)}; + for (int i=0;i<4;i++){ + if (ERR[i] > 12){ + double uvt[3] = {newPoint[i][0],newPoint[i][1],0.0}; + // printf("Intersecting with circle N = %g %g %g dir = %g %g %g R = %g p = %g %g %g\n",n.x(),n.y(),n.z(),dirs[i].x(),dirs[i].y(),dirs[i].z(),L,v_center->x(),v_center->y(),v_center->z()); + curveFunctorCircle cf (dirs[i],infos.normal, SVector3(v_center->x(),v_center->y(),v_center->z()), L); + if (intersectCurveSurface (cf,ss,uvt,infos.paramh.first*1.e-3)){ + GPoint pp = gf->point(SPoint2(uvt[0],uvt[1])); + double D = sqrt ((pp.x() - v_center->x())*(pp.x() - v_center->x()) + + (pp.y() - v_center->y())*(pp.y() - v_center->y()) + + (pp.z() - v_center->z())*(pp.z() - v_center->z()) ); + double DP = sqrt ((newPoint[i][0]-uvt[0])*(newPoint[i][0]-uvt[0]) + + (newPoint[i][1]-uvt[1])*(newPoint[i][1]-uvt[1])); + double newErr = 100*fabs(D-L)/(D+L); + // if (v_center->onWhat() != gf && gf->tag() == 3){ + // crossField2d::normalizeAngle (uvt[2]); + // printf("INTERSECT angle = %g DP %g\n",uvt[2],DP); + // } + if (newErr < 1 && DP < .1){ + // printf("%12.5E vs %12.5E : %12.5E %12.5E vs %12.5E %12.5E \n",ERR[i],newErr,newPoint[i][0],newPoint[i][1],uvt[0],uvt[1]); + newPoint[i][0] = uvt[0]; // + newPoint[i][1] = uvt[1]; // + } // + // printf("OK\n"); + } + else{ + Msg::Debug("Cannot put a new point on Surface %d",gf->tag()); + // printf("NOT OK\n"); + } + } + } // + + // return the four new vertices + for (int i=0;i<4;i++){ + newP[i][0] = SPoint2(newPoint[i][0],newPoint[i][1]); + } + } /// end non linear -------------------------------------------------// + + return true; +} + +//------------------------------------------------------------------------ + +void computeTwoNeighbors(frameFieldBackgroundMesh3D *bgm, MVertex *parent, vector<MVertex*> &spawns, SVector3 dir, double h){ + + // using approximate size, RK1... + double x = parent->x(); + double y = parent->y(); + double z = parent->z(); + double newx,newy,newz; + GRegion *gr = dynamic_cast<GRegion*>(bgm->getBackgroundGEntity()); + + newx = x + h * dir(0); + newy = y + h * dir(1); + newz = z + h * dir(2); + spawns[0] = new MVertex(newx,newy,newz,gr,0); + + newx = x - h * dir(0); + newy = y - h * dir(1); + newz = z - h * dir(2); + spawns[1] = new MVertex(newx,newy,newz,gr,0); +} + + +//------------------------------------------------------------------------ + +void computeSixNeighbors(frameFieldBackgroundMesh3D *bgm, MVertex *parent, vector<MVertex*> &spawns, STensor3 dir, double h){ + + // using approximate size, RK1... + double x = parent->x(); + double y = parent->y(); + double z = parent->z(); + double newx,newy,newz; + GRegion *gr = dynamic_cast<GRegion*>(bgm->getBackgroundGEntity()); + + for (int i=0;i<3;i++){ + newx = x + h * dir(0,i); + newy = y + h * dir(1,i); + newz = z + h * dir(2,i); + spawns[i*2] = new MVertex(newx,newy,newz,gr,0); + + newx = x - h * dir(0,i); + newy = y - h * dir(1,i); + newz = z - h * dir(2,i); + spawns[i*2+1] = new MVertex(newx,newy,newz,gr,0); + } +} + +//------------------------------------------------------------------------ + +double Filler2D::time_bgm_and_smoothing = 0.; +double Filler2D::time_insertion = 0.; + +//------------------------------------------------------------------------ + +Filler2D::Filler2D(){} + +//------------------------------------------------------------------------ + +Filler2D::~Filler2D(){ + cout << "FILLER2D timing:" << endl; + cout << " ------- CUMULATIVE TIME2D bgm & smoothing : " << time_bgm_and_smoothing << " s." << endl; + cout << " ------- CUMULATIVE TIME2D inserting points : " << time_insertion << " s." << endl; + cout << " ------- TOTAL 2D TIME (new) : " << time_bgm_and_smoothing+time_insertion << " s." << endl; +} + +//------------------------------------------------------------------------ + +void Filler2D::pointInsertion2D(GFace* gf, vector<MVertex*> &packed, vector<SMetric3> &metrics){ + // NB/ do not use the mesh in GFace, use the one in backgroundMesh2D !!! + + + // if(debug) cout << " ------------------ OLD -------------------" << endl; + // stringstream ssa; + //// ssa << "oldbgm_angles_" << gf->tag() << ".pos"; + //// backgroundMesh::current()->print(ssa.str(),gf,1); + // ssa << "oldbgm_sizes_" << gf->tag() << ".pos"; + // backgroundMesh::current()->print(ssa.str(),gf,0); + // + // + // + // + // if(debug) cout << " ------------------ NEW -------------------" << endl; + // backgroundMesh2D *bgm2 = dynamic_cast<backgroundMesh2D*>(BGMManager::get(gf)); + // stringstream ss2; + // ss2 << "basebg_sizefield_" << gf->tag() << ".pos"; + // bgm2->exportSizeField(ss2.str()); + // + // + // + // return; + // + + + + BGMManager::set_use_cross_field(true); + + const bool goNonLinear = true; + const bool debug=false; + const bool export_stuff=true; + + if (debug) cout << "ENTERING POINTINSERTION2D" << endl; + + clock_t a; + + // acquire background mesh + if(debug) cout << "pointInsertion2D: recover BGM" << endl; + a=clock(); + frameFieldBackgroundMesh2D *bgm = dynamic_cast<frameFieldBackgroundMesh2D*>(BGMManager::get(gf)); + time_bgm_and_smoothing += (clock() - a) / (double)CLOCKS_PER_SEC; + + + if (!bgm){ + cout << "pointInsertion2D:: BGM dynamic cast failed ! " << endl; + throw; + } + + + // export BGM size field + if(export_stuff){ + cout << "pointInsertion2D: export size field " << endl; + stringstream ss; + ss << "bg2D_sizefield_" << gf->tag() << ".pos"; + bgm->exportSizeField(ss.str()); + + cout << "pointInsertion2D : export crossfield " << endl; + stringstream sscf; + sscf << "bg2D_crossfield_" << gf->tag() << ".pos"; + bgm->exportCrossField(sscf.str()); + + cout << "pointInsertion2D : export smoothness " << endl; + stringstream sss; + sss << "bg2D_smoothness_" << gf->tag() << ".pos"; + bgm->exportSmoothness(sss.str()); + } + + + + // point insertion algorithm: + a=clock(); + + // for debug check... + int priority_counter=0; + map<MVertex*,int> vert_priority; + + // get all the boundary vertices + if(debug) cout << "pointInsertion2D : get bnd vertices " << endl; + set<MVertex*> bnd_vertices = bgm->get_vertices_of_maximum_dim(1); + + // put boundary vertices in a fifo queue + set<smoothness_point_pair, compareSurfacePointWithExclusionRegionPtr_Smoothness> fifo; + vector<surfacePointWithExclusionRegion*> vertices; + + + // initiate the rtree + if(debug) cout << "pointInsertion2D : initiate RTree " << endl; + RTree<surfacePointWithExclusionRegion*,double,2,double> rtree; + SMetric3 metricField(1.0); + SPoint2 newp[4][NUMDIR]; + set<MVertex*>::iterator it = bnd_vertices.begin() ; + + for (; it != bnd_vertices.end() ; ++it){ + SPoint2 midpoint; + computeFourNeighbors(bgm,*it, midpoint, goNonLinear, newp, metricField); + surfacePointWithExclusionRegion *sp = new surfacePointWithExclusionRegion (*it, newp, midpoint,metricField); + + // if(debug){ + // cout << " treating parent uv=(" << midpoint[0] << "," << midpoint[1] << ")" << endl; + // for (int ii=0;ii<4;ii++) + // cout << " child is uv=(" << newp[ii][0][0] << "," << newp[ii][0][1] << ")" << endl; + // } + + + smoothness_point_pair mp; + mp.ptr = sp; + mp.rank=(1.-bgm->get_smoothness(midpoint[0],midpoint[1])); + fifo.insert(mp); + + vertices.push_back(sp); + double _min[2],_max[2]; + sp->minmax(_min,_max); + rtree.Insert(_min,_max,sp); + } + + + + + // ---------- main loop ----------------- + while(!fifo.empty()){ + if(debug) cout << " -------- fifo.size() = " << fifo.size() << endl; + int count_nbaddedpt = 0; + + surfacePointWithExclusionRegion * parent = (*fifo.begin()).ptr; + fifo.erase(fifo.begin()); + + // if(debug) cout << " treating parent (" << parent->_v->x() << "," << parent->_v->y() << "," << parent->_v->z() << ") uv=(" << parent->_center[0] << "," << parent->_center[1] << ")" << endl; + + for (int dir=0;dir<NUMDIR;dir++){ + for (int i=0;i<4;i++){ + //if(debug) cout << "pointInsertion2D main loop: check child " << i << endl; + // if(debug) cout << " treating child (" << gp.x() << "," << gp.y() << "," << gp.z() << ") uv=(" << gp.u() << "," << gp.v() << ")" << endl; + //// if(debug) cout << " child is uv=(" << parent->_p[i][dir][0] << "," << parent->_p[i][dir][1] << ")" << endl; + + if (!inExclusionZone (parent->_p[i][dir], rtree, vertices) ){ + + GPoint gp = gf->point(parent->_p[i][dir]); + + //if(debug) cout << "pointInsertion2D main loop: one child not in exclusion zone "<< endl; + MFaceVertex *v = new MFaceVertex(gp.x(),gp.y(),gp.z(),gf,gp.u(),gp.v()); + SPoint2 midpoint; + //if(debug) cout << "pointInsertion2D main loop: computeFourNeighbors " << endl; + computeFourNeighbors(bgm,v, midpoint, goNonLinear, newp, metricField); + //if(debug) cout << "pointInsertion2D main loop: create new surfacePointWithExclusionRegion " << endl; + surfacePointWithExclusionRegion *sp = new surfacePointWithExclusionRegion (v, newp, midpoint, metricField, parent); + //if(debug) cout << "pointInsertion2D main loop: get smoothness " << endl; + smoothness_point_pair mp;mp.ptr = sp;mp.rank=(1.-bgm->get_smoothness(gp.u(),gp.v())); + + if (debug) vert_priority[v] = priority_counter++; + + //if(debug) cout << "pointInsertion2D main loop: insert in RTree " << endl; + fifo.insert(mp); + vertices.push_back(sp); + double _min[2],_max[2]; + sp->minmax(_min,_max); + rtree.Insert(_min,_max,sp); + + if (debug){ + cout << " adding node (" << sp->_v->x() << "," << sp->_v->y() << "," << sp->_v->z() << ")" << endl; + cout << " ----------------------------- sub --- fifo.size() = " << fifo.size() << endl; + } + count_nbaddedpt++; + + } + } + } + if(debug) cout << "////////// nbre of added point: " << count_nbaddedpt << endl; + } + time_insertion += (clock() - a) / (double)CLOCKS_PER_SEC; + + + if (debug){ + stringstream ss; + ss << "priority_" << gf->tag() << ".pos"; + print_nodal_info(ss.str().c_str(),vert_priority); + ss.clear(); + } + + + // add the vertices as additional vertices in the + // surface mesh + char ccc[256]; sprintf(ccc,"points%d.pos",gf->tag()); + FILE *f = Fopen(ccc,"w"); + fprintf(f,"View \"\"{\n"); + for (unsigned int i=0;i<vertices.size();i++){ + vertices[i]->print(f,i); + if(vertices[i]->_v->onWhat() == gf) { + packed.push_back(vertices[i]->_v); + metrics.push_back(vertices[i]->_meshMetric); + SPoint2 midpoint; + reparamMeshVertexOnFace(vertices[i]->_v, gf, midpoint); + } + delete vertices[i]; + } + fprintf(f,"};"); + fclose(f); + + + + + +} + +//------------------------------------------------------------------------ + +bool Filler3D::treat_region(GRegion *gr){ + + //if (gr->tag()>=11) return false; + // if (gr->tag()==11) return false; + // if (gr->tag()==12) return false; + // if (gr->tag()==13) return false; + // if (gr->tag()==17) return false; + + + + BGMManager::set_use_cross_field(true); + + bool use_vectorial_smoothness; + bool use_fifo; + string algo; + +// readValue("param.dat","SMOOTHNESSALGO",algo); + algo.assign("SCALAR"); + + if (!algo.compare("SCALAR")){ + compareSmoothnessVertexPairs::vectorial = false; + use_vectorial_smoothness = false; + use_fifo = false; + } + else if (!algo.compare("VECTORIAL")){ + compareSmoothnessVertexPairs::vectorial = true; + use_vectorial_smoothness = true; + use_fifo = false; + cout << "Vectorial smoothness algo: abandonné pour l'instant !" << endl; + throw; + } + else if (!algo.compare("FIFO")){ + compareSmoothnessVertexPairs::vectorial = false; + use_vectorial_smoothness = false; + use_fifo = true; + } + else{ + cout << "unknown SMOOTHNESSALGO !" << endl; + throw; + } + + const bool debug=false; + const bool export_stuff=true; + clock_t a; + + cout << "ENTERING POINTINSERTION3D" << endl; + + + // acquire background mesh + cout << "pointInsertion3D: recover BGM" << endl; + a = clock(); + frameFieldBackgroundMesh3D *bgm = dynamic_cast<frameFieldBackgroundMesh3D*>(BGMManager::get(gr)); + time_smoothing += (clock() - a) / (double)CLOCKS_PER_SEC; + + if (!bgm){ + cout << "pointInsertion3D:: BGM dynamic cast failed ! " << endl; + throw; + } + + + // export BGM fields + if(export_stuff){ + cout << "pointInsertion3D: export size field " << endl; + stringstream ss; + ss << "bg3D_sizefield_" << gr->tag() << ".pos"; + bgm->exportSizeField(ss.str()); + + cout << "pointInsertion3D : export crossfield " << endl; + stringstream sscf; + sscf << "bg3D_crossfield_" << gr->tag() << ".pos"; + bgm->exportCrossField(sscf.str()); + + cout << "pointInsertion3D : export smoothness " << endl; + stringstream sss; + sss << "bg3D_smoothness_" << gr->tag() << ".pos"; + bgm->exportSmoothness(sss.str()); + + if (use_vectorial_smoothness){ + cout << "pointInsertion3D : export vectorial smoothness " << endl; + stringstream ssvs; + ssvs << "bg3D_vectorial_smoothness_" << gr->tag() << ".pos"; + bgm->exportVectorialSmoothness(ssvs.str()); + } + } + + + + // ---------------- START FILLING NEW POINTS ---------------- + cout << "pointInsertion3D : inserting points in region " << gr->tag() << endl; + + //ProfilerStart("/home/bernard/profile"); + a = clock(); + + // ----- initialize fifo list ----- + + RTree<MVertex*,double,3,double> rtree; + listOfPoints *fifo; + if (use_fifo) + fifo = new listOfPointsFifo(); + else if (use_vectorial_smoothness) + fifo = new listOfPointsVectorialSmoothness(); + else + fifo = new listOfPointsScalarSmoothness(); + + set<MVertex*> temp; + vector<MVertex*> boundary_vertices; + map<MVertex*,int> vert_priority; + map<MVertex*,double> smoothness_forplot; + MElement *element; + MVertex *vertex; + list<GFace*> faces = gr->faces(); + for(list<GFace*>::iterator it=faces.begin();it!=faces.end();it++){// for all faces + GFace *gf = *it; + // int limit = code_kesskessai(gf->tag()); + for(unsigned int i=0;i<gf->getNumMeshElements();i++){ + element = gf->getMeshElement(i); + for(int j=0;j<element->getNumVertices();j++){// for all vertices + vertex = element->getVertex(j); + temp.insert(vertex); + // limits.insert(make_pair(vertex,limit)); + } + } + } + + int geodim; + for(set<MVertex*>::iterator it=temp.begin();it!=temp.end();it++){ + geodim = (*it)->onWhat()->dim(); + if ((geodim==0) || (geodim==1) || (geodim==2)) boundary_vertices.push_back(*it); + } + + double min[3],max[3],x,y,z,h; + for(unsigned int i=0;i<boundary_vertices.size();i++){ + + x = boundary_vertices[i]->x(); + y = boundary_vertices[i]->y(); + z = boundary_vertices[i]->z(); + + MVertex *closest = bgm->get_nearest_neighbor_on_boundary(boundary_vertices[i]);// "on boundary since working on boundary_vertices ... + h = bgm->size(closest);// get approximate size, closest vertex, faster ?! + + fill_min_max(x,y,z,h,min,max); + + rtree.Insert(min,max,boundary_vertices[i]); + + if (!use_vectorial_smoothness){ + smoothness_vertex_pair *svp = new smoothness_vertex_pair(); + svp->v = boundary_vertices[i]; + svp->rank = bgm->get_smoothness(x,y,z); + svp->dir = 0; + svp->layer = 0; + svp->size = h; + bgm->eval_approximate_crossfield(closest, svp->cf); + + fifo->insert(svp); + if (debug){ + smoothness_forplot[svp->v] = svp->rank; + } + } + else{ + STensor3 temp; + bgm->eval_approximate_crossfield(closest, temp); + for (int idir=0;idir<3;idir++){ + smoothness_vertex_pair *svp = new smoothness_vertex_pair(); + svp->v = boundary_vertices[i]; + svp->rank = bgm->get_vectorial_smoothness(idir,x,y,z); + svp->dir = idir; + svp->layer = 0; + svp->size = h; + svp->cf = temp; + for (int k=0;k<3;k++) svp->direction(k) = temp(k,idir); + + // cout << "fifo size=" << fifo->size() << " inserting " ; + fifo->insert(svp); + // cout << " -> fifo size=" << fifo->size() << endl; + } + } + } + + // TODO: si fifo était list of *PTR -> pas de copies, gain temps ? + + + Wrapper3D wrapper; + wrapper.set_bgm(bgm); + MVertex *parent,*individual; + new_vertices.clear(); + bool spawn_created; + int priority_counter=0; + STensor3 crossfield; + int parent_layer; + + while(!fifo->empty()){ + + parent = fifo->get_first_vertex(); + // parent_limit = fifo->get_first_limit(); + parent_layer = fifo->get_first_layer(); + + // if(parent_limit!=-1 && parent_layer>=parent_limit()){ + // continue; + // } + + vector<MVertex*> spawns; + if (!use_vectorial_smoothness){ + spawns.resize(6); + computeSixNeighbors(bgm,parent,spawns,fifo->get_first_crossfield(),fifo->get_first_size()); + } + else{ + spawns.resize(2); + computeTwoNeighbors(bgm,parent,spawns,fifo->get_first_direction(),fifo->get_first_size()); + } + fifo->erase_first(); + + // cout << "while, fifo->size()=" << fifo->size() << " parent=(" << parent->x() << "," << parent->y() << "," << parent->z() << ")" << endl; + + for(unsigned int i=0;i<spawns.size();i++){ + spawn_created = false; + individual = spawns[i]; + x = individual->x(); + y = individual->y(); + z = individual->z(); + // cout << " working on candidate " << "(" << individual->x() << "," << individual->y() << "," << individual->z() << ")" << endl; + + if(bgm->inDomain(x,y,z)){ + // cout << " spawn " << i << " in domain" << endl; + + MVertex *closest = bgm->get_nearest_neighbor(individual); + h = bgm->size(closest);// get approximate size, closest vertex, faster ?! + + if(far_from_boundary_3D(bgm,individual,h)){ + // cout << " spawn " << i << " far from bnd" << endl; + bgm->eval_approximate_crossfield(closest, crossfield); + wrapper.set_ok(true); + wrapper.set_individual(individual); + wrapper.set_parent(parent); + wrapper.set_size(&h); + wrapper.set_crossfield(&crossfield); + + fill_min_max(x,y,z,h,min,max); + + rtree.Search(min,max,rtree_callback_3D,&wrapper); + + if(wrapper.get_ok()){ + // cout << " spawn " << i << " wrapper OK" << endl; + + if (!use_vectorial_smoothness){ + smoothness_vertex_pair *svp = new smoothness_vertex_pair(); + svp->v = individual; + svp->rank=bgm->get_smoothness(individual->x(),individual->y(),individual->z()); + svp->dir = 0; + svp->layer = parent_layer+1; + svp->size = h; + svp->cf = crossfield; + fifo->insert(svp); + if (debug){ + smoothness_forplot[svp->v] = svp->rank; + vert_priority[individual] = priority_counter++; + } + + } + else{ + if (debug) vert_priority[individual] = priority_counter++; + for (int idir=0;idir<3;idir++){ + smoothness_vertex_pair *svp = new smoothness_vertex_pair(); + svp->v = individual; + svp->rank = bgm->get_vectorial_smoothness(idir,x,y,z); + svp->dir = idir; + svp->layer = parent_layer+1; + svp->size = h; + for (int k=0;k<3;k++) svp->direction(k) = crossfield(k,idir); + svp->cf = crossfield; + fifo->insert(svp); + } + } + + rtree.Insert(min,max,individual); + new_vertices.push_back(individual); + spawn_created = true; + + } + } + } + if(!spawn_created){ + delete individual; + } + }// end loop on spawns + } + + //ProfilerStop(); + + time_insert_points += (clock() - a) / (double)CLOCKS_PER_SEC; + + + // --- output --- + if (debug){ + stringstream ss; + ss << "priority_3D_" << gr->tag() << ".pos"; + print_nodal_info(ss.str().c_str(),vert_priority); + ss.clear(); + + stringstream sss; + sss << "smoothness_3D_" << gr->tag() << ".pos"; + print_nodal_info(sss.str().c_str(),smoothness_forplot); + sss.clear(); + } + + // ------- meshing using new points + cout << "tets in gr before= " << gr->tetrahedra.size() << endl; + cout << "nb new vertices= " << new_vertices.size() << endl; + a=clock(); + + int option = CTX::instance()->mesh.algo3d; + CTX::instance()->mesh.algo3d = ALGO_3D_DELAUNAY; + + + deMeshGRegion deleter; + deleter(gr); + std::vector<GRegion*> regions; + regions.push_back(gr); + meshGRegion mesher(regions); //? + mesher(gr); //? + MeshDelaunayVolume(regions); + time_meshing += (clock() - a) / (double)CLOCKS_PER_SEC; + + cout << "tets in gr after= " << gr->tetrahedra.size() << endl; + cout << "gr tag=" << gr->tag() << endl; + + CTX::instance()->mesh.algo3d = option; + + delete fifo; + for(unsigned int i=0;i<new_vertices.size();i++) delete new_vertices[i]; + new_vertices.clear(); + rtree.RemoveAll(); + + + + return true; +} + +//------------------------------------------------------------------------ + +int Filler3D::get_nbr_new_vertices(){ + return new_vertices.size(); +} + +//------------------------------------------------------------------------ + +MVertex* Filler3D::get_new_vertex(int i){ + return new_vertices[i]; +} + +//------------------------------------------------------------------------ + +Filler3D::Filler3D(){} + +//------------------------------------------------------------------------ + +Filler3D::~Filler3D(){ + cout << "FILLER3D timing:" << endl; + cout << " ------- CUMULATIVE TIME3D bgm & smoothing : " << time_smoothing << " s." << endl; + cout << " ------- CUMULATIVE TIME3D inserting points : " << time_insert_points << " s." << endl; + cout << " ------- CUMULATIVE TIME3D meshing region : " << time_meshing << " s." << endl; + cout << " ------- CUMULATIVE TOTAL 3D TIME (new) : " << time_meshing+time_smoothing+time_insert_points << " s." << endl; +} + +//------------------------------------------------------------------------ + +std::vector<MVertex*> Filler3D::new_vertices; + +//------------------------------------------------------------------------ + +double Filler3D::time_smoothing = 0.; +double Filler3D::time_insert_points = 0.; +double Filler3D::time_meshing = 0.; + +//------------------------------------------------------------------------ + + + + + + + + + + diff --git a/Mesh/pointInsertion.h b/Mesh/pointInsertion.h new file mode 100644 index 0000000000..655b76b8c9 --- /dev/null +++ b/Mesh/pointInsertion.h @@ -0,0 +1,82 @@ +// 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@geuz.org>. +// + +#ifndef _POINTINSERTION_H_ +#define _POINTINSERTION_H_ + + + +#include "STensor3.h" +#include <vector> +#include <string> +#include <fstream> +#include <iostream> + +class GFace; +class GRegion; +class MVertex; + +using namespace std; + +extern bool old_algo_hexa(); + +//------------------------------------------------------------------------ + +class Filler2D{ + public: + Filler2D(); + ~Filler2D(); + void pointInsertion2D(GFace* gf, std::vector<MVertex*> &packed, std::vector<SMetric3> &metrics ); + private: + static double time_bgm_and_smoothing,time_insertion; +}; + +//------------------------------------------------------------------------ + +class Filler3D{ + private: + static std::vector<MVertex*> new_vertices;// these are used in meshGRegion.cpp using static !!! + static double time_smoothing,time_insert_points, time_meshing; + public: + Filler3D(); + ~Filler3D(); + virtual bool treat_region(GRegion*); + static int get_nbr_new_vertices(); + static MVertex* get_new_vertex(int); +}; + + + + + +//------------------------------------------------------------------------------------------ + +//template<class T> +//bool readValue(string filename, string keystr, T &value){ +// ifstream in(filename.c_str()); +// if (!in.is_open()){ +// cerr << "Can't open file " << filename << endl; +// throw; +// return false; +// } +// string name; +// +// bool found=false; +// while (!(in.eof())){ +// in.ignore(100,'$'); +// in >> name; +// if (in.eof()) break; +// if (!name.compare(keystr.c_str())){// strings are equals +// found=true; +// in >> value; +// } +// } +// in.close(); +// return found; +//} + + +#endif diff --git a/Mesh/pointInsertionRTreeTools.cpp b/Mesh/pointInsertionRTreeTools.cpp new file mode 100644 index 0000000000..868d107714 --- /dev/null +++ b/Mesh/pointInsertionRTreeTools.cpp @@ -0,0 +1,245 @@ +#include "pointInsertionRTreeTools.h" + +#include "BackgroundMesh.h" +#include "BackgroundMeshManager.h" + +#include "pointInsertion.h" + +#include "GEntity.h" + + +//------------------------------------------------------------------------ + +surfacePointWithExclusionRegion::surfacePointWithExclusionRegion (MVertex *v, SPoint2 p[4][NUMDIR], SPoint2 &_mp, SMetric3 & meshMetric, surfacePointWithExclusionRegion *father){ + _v = v; + _meshMetric = meshMetric; + _center = _mp; + for (int i=0;i<4;i++)_q[i] = _center + (p[i][0]+p[(i+1)%4][0]-_center*2)*FACTOR; + for (int i=0;i<4;i++)for (int j=0;j<NUMDIR;j++)_p[i][j] = p[i][j]; + + if (!father){ + fullMatrix<double> V(3,3); + fullVector<double> S(3); + meshMetric.eig(V,S); + double l = std::max(std::max(S(0),S(1)),S(2)); + _distanceSummed = sqrt(1/(l*l)); + } + else { + _distanceSummed = father->_distanceSummed + distance (father->_v,_v); + } +} + +//------------------------------------------------------------------------ + +bool surfacePointWithExclusionRegion::inExclusionZone (const SPoint2 &p){ + double mat[2][2]; + double b[2] , uv[2]; + mat[0][0]= _q[1].x()-_q[0].x(); + mat[0][1]= _q[2].x()-_q[0].x(); + mat[1][0]= _q[1].y()-_q[0].y(); + mat[1][1]= _q[2].y()-_q[0].y(); + b[0] = p.x() - _q[0].x(); + b[1] = p.y() - _q[0].y(); + sys2x2(mat, b, uv); + // printf("inversion 1 : %g %g \n",uv[0],uv[1]); + if (uv[0] >= 0 && uv[1] >= 0 && 1.-uv[0] - uv[1] >= 0)return true; + mat[0][0]= _q[3].x()-_q[2].x(); + mat[0][1]= _q[0].x()-_q[2].x(); + mat[1][0]= _q[3].y()-_q[2].y(); + mat[1][1]= _q[0].y()-_q[2].y(); + b[0] = p.x() - _q[2].x(); + b[1] = p.y() - _q[2].y(); + sys2x2(mat, b, uv); + // printf("inversion 2 : %g %g \n",uv[0],uv[1]); + if (uv[0] >= 0 && uv[1] >= 0 && 1.-uv[0] - uv[1] >= 0)return true; + return false; +} + +//------------------------------------------------------------------------ + +void surfacePointWithExclusionRegion::minmax (double _min[2], double _max[2]) const{ + _min[0] = std::min(std::min(std::min(_q[0].x(),_q[1].x()),_q[2].x()),_q[3].x()); + _min[1] = std::min(std::min(std::min(_q[0].y(),_q[1].y()),_q[2].y()),_q[3].y()); + _max[0] = std::max(std::max(std::max(_q[0].x(),_q[1].x()),_q[2].x()),_q[3].x()); + _max[1] = std::max(std::max(std::max(_q[0].y(),_q[1].y()),_q[2].y()),_q[3].y()); +} + +//------------------------------------------------------------------------ + +void surfacePointWithExclusionRegion::print (FILE *f, int i){ + fprintf(f,"SP(%g,%g,%g){%d};\n",_center.x(),_center.y(),0.0,i); + fprintf(f,"SQ(%g,%g,%g,%g,%g,%g,%g,%g,%g,%g,%g,%g){%d,%d,%d,%d};\n", + _q[0].x(),_q[0].y(),0.0, + _q[1].x(),_q[1].y(),0.0, + _q[2].x(),_q[2].y(),0.0, + _q[3].x(),_q[3].y(),0.0,i,i,i,i); + +} + +//------------------------------------------------------------------------ + + +my_wrapper::my_wrapper (SPoint2 sp) : _tooclose (false), _p(sp) {} + + + +//------------------------------------------------------------------------ + + +bool rtree_callback(surfacePointWithExclusionRegion *neighbour,void* point){ + my_wrapper *w = static_cast<my_wrapper*>(point); + + if (neighbour->inExclusionZone(w->_p)){ + w->_tooclose = true; + return false; + } + + return true; +} + + +//------------------------------------------------------------------------ + +bool inExclusionZone (SPoint2 &p, + RTree<surfacePointWithExclusionRegion*,double,2,double> &rtree, + std::vector<surfacePointWithExclusionRegion*> & all ){ + // should assert that the point is inside the domain + // OLD BGM + if (old_algo_hexa()){ + if (!backgroundMesh::current()->inDomain(p.x(),p.y(),0)) return true; + } + else{ + // NEW BGM + if (!BGMManager::current2D()->inDomain(p.x(),p.y(),0)) return true; + } + + my_wrapper w (p); + double _min[2] = {p.x()-1.e-1, p.y()-1.e-1},_max[2] = {p.x()+1.e-1,p.y()+1.e-1}; + rtree.Search(_min,_max,rtree_callback,&w); + + return w._tooclose; + + for (unsigned int i=0;i<all.size();++i){ + if (all[i]->inExclusionZone(p)){ + // printf("%g %g is in exclusion zone of %g %g\n",p.x(),p.y(),all[i]._center.x(),all[i]._center.y()); + return true; + } + } + return false; +} + + + +// ------------------------------------------------------------------------------------ +// --------------------------------- 3D -------------------------------------------- +// ------------------------------------------------------------------------------------ + +frameFieldBackgroundMesh3D* Wrapper3D::bgmesh = NULL; + +bool compareSmoothnessVertexPairs::vectorial = false; + +//------------------------------------------------------------------------ + +double infinity_distance_3D(const MVertex *v1,const MVertex *v2,STensor3 &cf){ + SPoint3 p1 = v1->point(); + SPoint3 p2 = v2->point(); + double x1=0.; + double y1=0.; + double z1=0.; + double x2=0.; + double y2=0.; + double z2=0.; + for (int i=0;i<3;i++){ + x1 += cf(i,0) * p1[i]; + y1 += cf(i,1) * p1[i]; + z1 += cf(i,2) * p1[i]; + } + for (int i=0;i<3;i++){ + x2 += cf(i,0) * p2[i]; + y2 += cf(i,1) * p2[i]; + z2 += cf(i,2) * p2[i]; + } + return std::max(std::max(fabs(x2-x1),fabs(y2-y1)),fabs(z2-z1));// distance +}; + +//------------------------------------------------------------------------ + +void fill_min_max(double x,double y,double z,double h,double *min,double *max){ + min[0] = x - sqrt3*h; + max[0] = x + sqrt3*h; + min[1] = y - sqrt3*h; + max[1] = y + sqrt3*h; + min[2] = z - sqrt3*h; + max[2] = z + sqrt3*h; +}; + +//------------------------------------------------------------------------ + +bool rtree_callback_3D(MVertex* neighbour,void* w){ + Wrapper3D* wrapper; + wrapper = static_cast<Wrapper3D*>(w); + const MVertex* individual = wrapper->get_individual(); + const MVertex *parent = wrapper->get_parent(); + if (parent==neighbour) return true; + +// frameFieldBackgroundMesh3D* bgm = wrapper->bgm(); +// const MVertex *closest = bgm->get_nearest_neighbor(individual); +// const double h = bgm->size(closest);// get approximate size, closest vertex, faster ?! +// STensor3 crossfield; +// bgm->eval_approximate_crossfield(closest, crossfield); + double *h = wrapper->get_size(); + STensor3 *crossfield = wrapper->get_crossfield(); + + const double distance = infinity_distance_3D(individual,neighbour,(*crossfield)); + if(distance<k1*(*h)){ + wrapper->set_ok(false); + return false; + } + return true; +}; + +//------------------------------------------------------------------------ + +bool far_from_boundary_3D(frameFieldBackgroundMesh3D *bgm, MVertex* v, double h){ + // check if the box (v->point +- k2*h) is in domain + + const double x = v->x(); + const double y = v->y(); + const double z = v->z(); + const double boxsize = k2*h; + if (!(bgm->inDomain(x+boxsize, y, z))) return false; + if (!(bgm->inDomain(x-boxsize, y, z))) return false; + if (!(bgm->inDomain(x, y+boxsize, z))) return false; + if (!(bgm->inDomain(x, y-boxsize, z))) return false; + if (!(bgm->inDomain(x, y, z+boxsize))) return false; + if (!(bgm->inDomain(x, y, z-boxsize))) return false; + + return true; +}; + +//------------------------------------------------------------------------ + +// vient de l'ancien code hexa, mais... kesskessai ? +//int code_kesskessai(int tag){ +// int limit; +// std::string s; +// std::stringstream s2; +// +// limit = -1; +// s2 << tag; +// s = s2.str(); +// +// if(s.length()>=5){ +// if(s.at(0)=='1' && s.at(1)=='1' && s.at(2)=='1' && s.at(3)=='1' && s.at(4)=='1'){ +// limit = 0; +// } +// else if(s.at(0)=='2' && s.at(1)=='2' && s.at(2)=='2' && s.at(3)=='2' && s.at(4)=='2'){ +// limit = 1; +// } +// } +// +// return limit; +//} + +//------------------------------------------------------------------------ + diff --git a/Mesh/pointInsertionRTreeTools.h b/Mesh/pointInsertionRTreeTools.h new file mode 100644 index 0000000000..69d00dc900 --- /dev/null +++ b/Mesh/pointInsertionRTreeTools.h @@ -0,0 +1,387 @@ + +#ifndef _POINTINSERTIONTOOLS_H_ +#define _POINTINSERTIONTOOLS_H_ + + +#include "MVertex.h" +#include "STensor3.h" + +#include "BackgroundMesh3D.h" +#include "GEntity.h" + +#include "rtree.h" + +#include <math.h> +#include <queue> + +//using namespace std; + +static const double k1 = 0.61; //k1*h is the minimal distance between two nodes +static const double k2 = 0.5; //k2*h is the minimal distance to the boundary +static const double sqrt3 = 1.73205081; +static const double FACTOR = .71; + +static const int NUMDIR = 1; +static const double DIRS [NUMDIR] = {0.0}; + +//static const int NUMDIR = 3; +//static const double DIRS [NUMDIR] = {0.0, M_PI/20.,-M_PI/20.}; + + + +//------------------------------------------------------------------------ + + +class surfacePointWithExclusionRegion { + public: + MVertex *_v; + SPoint2 _center; + SPoint2 _p[4][NUMDIR]; + SPoint2 _q[4]; + SMetric3 _meshMetric; + double _distanceSummed; + /* + + p3 + p4 | + +----c-----+ p2 + | + + p1 + + */ + + surfacePointWithExclusionRegion (MVertex *v, SPoint2 p[4][NUMDIR], SPoint2 &_mp, SMetric3 & meshMetric, surfacePointWithExclusionRegion *father = 0); + + bool inExclusionZone (const SPoint2 &p); + void minmax (double _min[2], double _max[2]) const; + void print (FILE *f, int i); +}; + +//------------------------------------------------------------------------ + + +class my_wrapper { + public: + bool _tooclose; + SPoint2 _p; + my_wrapper (SPoint2 sp); +}; + +//------------------------------------------------------------------------ + + +struct smoothness_point_pair{ + double rank; + surfacePointWithExclusionRegion* ptr; +}; + +//------------------------------------------------------------------------ + + +class compareSurfacePointWithExclusionRegionPtr_Smoothness +{ + public: + inline bool operator () (const smoothness_point_pair &a, const smoothness_point_pair &b) const + { + if (a.rank == b.rank){ + if(a.ptr->_distanceSummed > b.ptr->_distanceSummed) return false; + if(a.ptr->_distanceSummed < b.ptr->_distanceSummed) return true; + return a.ptr<b.ptr; + } + // else + return (a.rank < b.rank); + } +}; + + +//------------------------------------------------------------------------ + + +class compareSurfacePointWithExclusionRegionPtr +{ + public: + inline bool operator () (const surfacePointWithExclusionRegion *a, const surfacePointWithExclusionRegion *b) const + { + if(a->_distanceSummed > b->_distanceSummed) return false; + if(a->_distanceSummed < b->_distanceSummed) return true; + return a<b; + } +}; + + +//------------------------------------------------------------------------ + + +extern bool rtree_callback(surfacePointWithExclusionRegion *neighbour,void* point); + +//------------------------------------------------------------------------ + + + +extern bool inExclusionZone (SPoint2 &p, RTree<surfacePointWithExclusionRegion*,double,2,double> &rtree, std::vector<surfacePointWithExclusionRegion*> & all ); + + +//------------------------------------------------------------------------ + + + + + +// ------------------------------------------------------------------------------------ +// --------------------------------- 3D -------------------------------------------- +// ------------------------------------------------------------------------------------ + + + +class Wrapper3D{ + private: + static frameFieldBackgroundMesh3D* bgmesh; + MVertex *individual,*parent; + double *size; + STensor3 *cf; + SVector3 *vec; + bool ok; + // Node* individual; + // Node* parent; + public: + Wrapper3D():ok(true){}; + Wrapper3D(MVertex* _i,MVertex* _p):individual(_i), parent(_p),ok(true){}; + ~Wrapper3D(){}; + void set_ok(bool b){ok=b;}; + void set_individual(MVertex *vertex){individual=vertex;}; + void set_parent(MVertex *vertex){parent=vertex;}; + void set_size(double *h){size=h;}; + void set_crossfield(STensor3 *_cf){cf=_cf;}; + void set_direction(SVector3 *_v){vec=_v;}; + bool get_ok(){return ok;}; + void set_bgm(frameFieldBackgroundMesh3D *bgm){bgmesh = bgm;}; + frameFieldBackgroundMesh3D * bgm(){return bgmesh;}; + MVertex* get_individual(){return individual;}; + MVertex* get_parent(){return parent;}; + STensor3* get_crossfield(){return cf;}; + SVector3* get_direction(){return vec;}; + double* get_size(){return size;}; +}; + +//------------------------------------------------------------------------ + + + +extern double infinity_distance_3D(const MVertex *v1,const MVertex *v2,STensor3 &cf); +extern bool rtree_callback_3D(MVertex* neighbour,void* w); +extern bool far_from_boundary_3D(frameFieldBackgroundMesh3D *bgm, MVertex* v, double h); +//extern int code_kesskessai(int tag); +extern void fill_min_max(double x,double y,double z,double h,double *min,double *max); + +//------------------------------------------------------------------------ + + + +// TODO: this is not a pair anymore, the name has to be changed +// this will be in listOfPoints AND !!! in RTree: larger memory footprint but less CPU time... +class smoothness_vertex_pair{ + public: + smoothness_vertex_pair(){}; +// smoothness_vertex_pair(const smoothness_vertex_pair &other){ +// rank = other.rank; +// v = other.v; +// dir = other.dir; +// layer = other.layer; +// }; + ~smoothness_vertex_pair(){}; + STensor3 cf; + SVector3 direction; + double rank,size; + MVertex *v; + int dir,layer; +}; + +//------------------------------------------------------------------------ + + +class compareSmoothnessVertexPairs +{ + private: + const double threshold; + double roundit(const double &d)const{ + return (round(d/threshold)*threshold); + } + public: + static bool vectorial; + + compareSmoothnessVertexPairs():threshold(0.05){}; + + inline bool operator () (const smoothness_vertex_pair *a, const smoothness_vertex_pair *b) const + { + + // THIS IS USED : + if (!vectorial){ + if (a->rank==b->rank) return (a->v<b->v); + return (a->rank > b->rank); + } + + // THE FOLLOWING IS USUALLY NOT USED... IT WAS AN ATTEMPT TO USE VECTORIAL SMOOTHNESS, SHOULD BE DELETED... + + + // cout << " operator() " << endl; + if (roundit(a->rank)==roundit(b->rank) && ((a->rank+b->rank)/2.>=0.9)){// if good smoothness and approximately equal + // cout << " smoothness same,"; + if (a->layer!=b->layer){// layers are different + // cout << "layers different, return " << (a->layer > b->layer) << endl; + return (a->layer > b->layer);// priority to larger layer + } + //cout << "a b rankls: " << roundit(a->rank) << "," << roundit(b->rank) << " layers=" << a->layer << "," << b->layer << " -> return " << (a->layer > b->layer) << endl; + + if ((a->layer==0) && (b->layer==0)){// both on boundaries + // cout << "both on boundaries,"; + if ((a->v->onWhat()->dim()==2) && (b->v->onWhat()->dim()==2)){// both on faces + // cout << "both on faces,"; + if ((a->v->onWhat()->tag()) != (b->v->onWhat()->tag())){// with different tags + + + // cout << "with different tags, return " << (a->v->onWhat()->tag() < b->v->onWhat()->tag()) << endl; + return (a->v->onWhat()->tag() < b->v->onWhat()->tag());// priority to smaller tag + } + } + } + } + + if (a->rank==b->rank){// same smoothness + // cout << " same smoothness"; + if (a->v==b->v){// same vertex + // cout << " same vertex, return " << (a->dir < b->dir) << endl; + return (a->dir < b->dir); + } + // cout << "return " << (a->v < b->v) << endl; + return (a->v<b->v); + } + // cout << " comparing smoothness, return " << (a->rank > b->rank) << endl; + // cout << "no roundit !!!" << endl; + + return (a->rank > b->rank); + } +}; + + +//------------------------------------------------------------------------ + +class listOfPoints{ + public: + listOfPoints(){}; + virtual ~listOfPoints(){}; + virtual void insert(smoothness_vertex_pair *svp)=0; + virtual unsigned int size()=0; + virtual MVertex* get_first_vertex()=0; + virtual STensor3 get_first_crossfield()=0; + virtual double get_first_size()=0; + virtual int get_first_layer()=0; + virtual SVector3 get_first_direction()=0; + virtual void erase_first()=0; + virtual bool empty()=0; +}; + +//------------------------------------------------------------------------ + +class listOfPointsScalarSmoothness : public listOfPoints{ + public: + listOfPointsScalarSmoothness(){ + cout << "USING SMOOTHNESS-BASED LIST" << endl; + }; + virtual ~listOfPointsScalarSmoothness(){ + while (!empty()) + erase_first(); + }; + virtual void insert(smoothness_vertex_pair *svp){points.insert(svp);}; + virtual unsigned int size(){return points.size();}; + virtual MVertex* get_first_vertex(){return (*points.begin())->v;}; + virtual STensor3 get_first_crossfield(){return (*points.begin())->cf;}; + virtual double get_first_size(){return (*points.begin())->size;}; + virtual int get_first_layer(){return (*points.begin())->layer;}; + virtual SVector3 get_first_direction(){ + cout << "listOfPointsScalarSmoothness:: get_first_direction NOT applicable ! " << endl; + throw; + return SVector3(0.); + }; + virtual void erase_first(){ + smoothness_vertex_pair *ptr = *(points.begin()); + points.erase(points.begin()); + delete ptr; + }; + virtual bool empty(){return points.empty();}; + + protected: + set<smoothness_vertex_pair*, compareSmoothnessVertexPairs> points; +}; + +//------------------------------------------------------------------------ + +class listOfPointsVectorialSmoothness : public listOfPointsScalarSmoothness{ + public: + listOfPointsVectorialSmoothness(){ + cout << "USING VECTORIAL SMOOTHNESS-BASED LIST" << endl; + }; + virtual ~listOfPointsVectorialSmoothness(){ + while (!empty()) + erase_first(); + }; + virtual SVector3 get_first_direction(){return (*points.begin())->direction;}; + + protected: + set<smoothness_vertex_pair*, compareSmoothnessVertexPairs> points; +}; + +//------------------------------------------------------------------------ + +class listOfPointsFifo : public listOfPoints{ + public: + listOfPointsFifo(){ + cout << "USING FIFO LIST" << endl; + }; + virtual ~listOfPointsFifo(){ + while (!empty()) + erase_first(); + }; + virtual void insert(smoothness_vertex_pair *svp){points.push(svp);}; + virtual unsigned int size(){return points.size();}; + virtual MVertex* get_first_vertex(){return (points.front())->v;}; + virtual STensor3 get_first_crossfield(){return (points.front())->cf;}; + virtual double get_first_size(){return (points.front())->size;}; + virtual int get_first_layer(){return (points.front())->layer;}; + virtual SVector3 get_first_direction(){ + cout << "listOfPointsFifo:: get_first_direction NOT applicable ! " << endl; + throw; + return SVector3(0.); + }; + virtual void erase_first(){ + smoothness_vertex_pair *ptr = points.front(); + points.pop(); + delete ptr; + }; + virtual bool empty(){return points.empty();}; + + protected: + queue<smoothness_vertex_pair*> points; +}; + + + + + + + +////class 3DNode{ +//// private: +//// SPoint3 point; +//// public: +//// double min[3]; +//// double max[3]; +//// Node(SPoint3); +//// Node(double x, double y, double z); +//// ~Node(); +////}; +//// + + + + + +#endif diff --git a/Mesh/simple3D.cpp b/Mesh/simple3D.cpp index be71ada29f..efda800069 100644 --- a/Mesh/simple3D.cpp +++ b/Mesh/simple3D.cpp @@ -6,6 +6,7 @@ // Contributor(s): // Tristan Carrier François Henrotte + #include "simple3D.h" #include "GModel.h" #include "MElement.h" @@ -835,3 +836,4 @@ void Filler::print_node(Node* node,std::ofstream& file) /*********static declarations*********/ std::vector<MVertex*> Filler::new_vertices; + diff --git a/Mesh/simple3D.h b/Mesh/simple3D.h index 131349172c..a176ae73fe 100644 --- a/Mesh/simple3D.h +++ b/Mesh/simple3D.h @@ -6,6 +6,11 @@ // Contributor(s): // Tristan Carrier François Henrotte + +#ifndef _SIMPLE3D_H_ +#define _SIMPLE3D_H_ + + #include "SVector3.h" #include <list> #include "GRegion.h" @@ -37,3 +42,6 @@ class Filler{ static int get_nbr_new_vertices(); static MVertex* get_new_vertex(int); }; + +#endif + diff --git a/Mesh/surfaceFiller.cpp b/Mesh/surfaceFiller.cpp index 69b24e12a1..36f57cec04 100644 --- a/Mesh/surfaceFiller.cpp +++ b/Mesh/surfaceFiller.cpp @@ -1,4 +1,4 @@ -// Gmsh - Copyright (C) 1997-2015 C. Geuzaine, J.-F. Remacle +// 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@geuz.org>. @@ -6,6 +6,7 @@ // Contributor(s): // Tristan Carrier Baudoin + #include "GmshConfig.h" #include "surfaceFiller.h" #include "Field.h" @@ -13,187 +14,188 @@ #include "OS.h" #include <queue> #include <stack> + +/// Here, we aim at producing a set of points that +/// enables to generate a nice quad mesh + #include "rtree.h" + #include "MVertex.h" #include "MElement.h" +//#include "directions3D.h" #include "BackgroundMesh.h" #include "intersectCurveSurface.h" -// Here, we aim at producing a set of points that enables to generate a nice -// quad mesh +#include "pointInsertionRTreeTools.h" using namespace std; -static const double FACTOR = .71; -static const int NUMDIR = 3; -static const double DIRS [NUMDIR] = {0.0, M_PI/20.,-M_PI/20.}; +//static const double FACTOR = .71; +//static const int NUMDIR = 3; +//static const double DIRS [NUMDIR] = {0.0, M_PI/20.,-M_PI/20.}; //PE MODIF //static const int NUMDIR = 1; //static const double DIRS [NUMDIR] = {0.0}; // END PE MODIF -// a rectangle in the tangent plane is transformed into a parallelogram. We -// define an exclusion zone that is centered around a vertex and that is used in -// a r-tree structure for generating points with the right spacing in the -// tangent plane - -struct surfacePointWithExclusionRegion { - MVertex *_v; - SPoint2 _center; - SPoint2 _p[4][NUMDIR]; - SPoint2 _q[4]; - SMetric3 _meshMetric; - double _distanceSummed; - double mat1[2][2], mat2[2][2]; - /* - + p3 - p4 | - +----c-----+ p2 - | - + p1 - - */ - surfacePointWithExclusionRegion (MVertex *v, SPoint2 p[4][NUMDIR], - SPoint2 &_mp, SMetric3 & meshMetric, - surfacePointWithExclusionRegion *father = 0) - { - _v = v; - _meshMetric = meshMetric; - _center = _mp; - for (int i=0;i<4;i++)_q[i] = _center + (p[i][0]+p[(i+1)%4][0]-_center*2)*FACTOR; - for (int i=0;i<4;i++)for (int j=0;j<NUMDIR;j++)_p[i][j] = p[i][j]; - - if (!father){ - fullMatrix<double> V(3,3); - fullVector<double> S(3); - meshMetric.eig(V,S); - double l = std::max(std::max(S(0),S(1)),S(2)); - _distanceSummed = sqrt(1/(l*l)); - } - else { - _distanceSummed = father->_distanceSummed + distance (father->_v,_v); - } - //test !!! - // const double s = backgroundMesh::current()->getSmoothness(_mp.x(),_mp.y(),0); - // if(s > 0.02) - // _distanceSummed = 10000*s; - } - bool inExclusionZone (const SPoint2 &p) - { - double mat[2][2]; - double b[2] , uv[2]; - mat[0][0]= _q[1].x()-_q[0].x(); - mat[0][1]= _q[2].x()-_q[0].x(); - mat[1][0]= _q[1].y()-_q[0].y(); - mat[1][1]= _q[2].y()-_q[0].y(); - b[0] = p.x() - _q[0].x(); - b[1] = p.y() - _q[0].y(); - sys2x2(mat, b, uv); - // printf("inversion 1 : %g %g \n",uv[0],uv[1]); - if (uv[0] >= 0 && uv[1] >= 0 && 1.-uv[0] - uv[1] >= 0)return true; - mat[0][0]= _q[3].x()-_q[2].x(); - mat[0][1]= _q[0].x()-_q[2].x(); - mat[1][0]= _q[3].y()-_q[2].y(); - mat[1][1]= _q[0].y()-_q[2].y(); - b[0] = p.x() - _q[2].x(); - b[1] = p.y() - _q[2].y(); - sys2x2(mat, b, uv); - // printf("inversion 2 : %g %g \n",uv[0],uv[1]); - if (uv[0] >= 0 && uv[1] >= 0 && 1.-uv[0] - uv[1] >= 0)return true; - return false; - } - void minmax (double _min[2], double _max[2]) const - { - _min[0] = std::min(std::min(std::min(_q[0].x(),_q[1].x()),_q[2].x()),_q[3].x()); - _min[1] = std::min(std::min(std::min(_q[0].y(),_q[1].y()),_q[2].y()),_q[3].y()); - _max[0] = std::max(std::max(std::max(_q[0].x(),_q[1].x()),_q[2].x()),_q[3].x()); - _max[1] = std::max(std::max(std::max(_q[0].y(),_q[1].y()),_q[2].y()),_q[3].y()); - } - void print (FILE *f, int i) - { - fprintf(f,"SP(%g,%g,%g){%d};\n",_center.x(),_center.y(),0.0,i); - fprintf(f,"SQ(%g,%g,%g,%g,%g,%g,%g,%g,%g,%g,%g,%g){%d,%d,%d,%d};\n", - _q[0].x(),_q[0].y(),0.0, - _q[1].x(),_q[1].y(),0.0, - _q[2].x(),_q[2].y(),0.0, - _q[3].x(),_q[3].y(),0.0,i,i,i,i); - } -}; -struct my_wrapper { - bool _tooclose; - SPoint2 _p; - my_wrapper (SPoint2 sp) : _tooclose (false), _p(sp) {} -}; +/// a rectangle in the tangent plane is transformed +/// into a parallelogram. We define an exclusion zone +/// that is centered around a vertex and that is used +/// in a r-tree structure for generating points with the +/// right spacing in the tangent plane -struct smoothness_point_pair{ - double rank; - surfacePointWithExclusionRegion* ptr; -}; -class compareSurfacePointWithExclusionRegionPtr_Smoothness -{ - public: - inline bool operator () (const smoothness_point_pair &a, - const smoothness_point_pair &b) const - { - if (a.rank == b.rank){ - if(a.ptr->_distanceSummed > b.ptr->_distanceSummed) return false; - if(a.ptr->_distanceSummed < b.ptr->_distanceSummed) return true; - return a.ptr<b.ptr; - } - // else - return (a.rank < b.rank); - } -}; - -class compareSurfacePointWithExclusionRegionPtr -{ - public: - inline bool operator () (const surfacePointWithExclusionRegion *a, - const surfacePointWithExclusionRegion *b) const - { - if(a->_distanceSummed > b->_distanceSummed) return false; - if(a->_distanceSummed < b->_distanceSummed) return true; - return a<b; - } -}; - -bool rtree_callback(surfacePointWithExclusionRegion *neighbour,void* point) -{ - my_wrapper *w = static_cast<my_wrapper*>(point); - - if (neighbour->inExclusionZone(w->_p)){ - w->_tooclose = true; - return false; - } - - return true; -} - -bool inExclusionZone (SPoint2 &p, - RTree<surfacePointWithExclusionRegion*,double,2,double> &rtree, - std::vector<surfacePointWithExclusionRegion*> & all) -{ - // should assert that the point is inside the domain - if (!backgroundMesh::current()->inDomain(p.x(),p.y(),0)) return true; +//struct surfacePointWithExclusionRegion { +// MVertex *_v; +// SPoint2 _center; +// SPoint2 _p[4][NUMDIR]; +// SPoint2 _q[4]; +// SMetric3 _meshMetric; +// double _distanceSummed; +// /* +// + p3 +// p4 | +// +----c-----+ p2 +// | +// + p1 +// +//*/ +// +// surfacePointWithExclusionRegion (MVertex *v, SPoint2 p[4][NUMDIR], SPoint2 &_mp, SMetric3 & meshMetric, surfacePointWithExclusionRegion *father = 0){ +// _v = v; +// _meshMetric = meshMetric; +// _center = _mp; +// for (int i=0;i<4;i++)_q[i] = _center + (p[i][0]+p[(i+1)%4][0]-_center*2)*FACTOR; +// for (int i=0;i<4;i++)for (int j=0;j<NUMDIR;j++)_p[i][j] = p[i][j]; +// +// if (!father){ +// fullMatrix<double> V(3,3); +// fullVector<double> S(3); +// meshMetric.eig(V,S); +// double l = std::max(std::max(S(0),S(1)),S(2)); +// _distanceSummed = sqrt(1/(l*l)); +// } +// else { +// _distanceSummed = father->_distanceSummed + distance (father->_v,_v); +// } +// } +// bool inExclusionZone (const SPoint2 &p){ +// double mat[2][2]; +// double b[2] , uv[2]; +// mat[0][0]= _q[1].x()-_q[0].x(); +// mat[0][1]= _q[2].x()-_q[0].x(); +// mat[1][0]= _q[1].y()-_q[0].y(); +// mat[1][1]= _q[2].y()-_q[0].y(); +// b[0] = p.x() - _q[0].x(); +// b[1] = p.y() - _q[0].y(); +// sys2x2(mat, b, uv); +// // printf("inversion 1 : %g %g \n",uv[0],uv[1]); +// if (uv[0] >= 0 && uv[1] >= 0 && 1.-uv[0] - uv[1] >= 0)return true; +// mat[0][0]= _q[3].x()-_q[2].x(); +// mat[0][1]= _q[0].x()-_q[2].x(); +// mat[1][0]= _q[3].y()-_q[2].y(); +// mat[1][1]= _q[0].y()-_q[2].y(); +// b[0] = p.x() - _q[2].x(); +// b[1] = p.y() - _q[2].y(); +// sys2x2(mat, b, uv); +// // printf("inversion 2 : %g %g \n",uv[0],uv[1]); +// if (uv[0] >= 0 && uv[1] >= 0 && 1.-uv[0] - uv[1] >= 0)return true; +// return false; +// } +// void minmax (double _min[2], double _max[2]) const{ +// _min[0] = std::min(std::min(std::min(_q[0].x(),_q[1].x()),_q[2].x()),_q[3].x()); +// _min[1] = std::min(std::min(std::min(_q[0].y(),_q[1].y()),_q[2].y()),_q[3].y()); +// _max[0] = std::max(std::max(std::max(_q[0].x(),_q[1].x()),_q[2].x()),_q[3].x()); +// _max[1] = std::max(std::max(std::max(_q[0].y(),_q[1].y()),_q[2].y()),_q[3].y()); +// } +// void print (FILE *f, int i){ +// fprintf(f,"SP(%g,%g,%g){%d};\n",_center.x(),_center.y(),0.0,i); +// fprintf(f,"SQ(%g,%g,%g,%g,%g,%g,%g,%g,%g,%g,%g,%g){%d,%d,%d,%d};\n", +// _q[0].x(),_q[0].y(),0.0, +// _q[1].x(),_q[1].y(),0.0, +// _q[2].x(),_q[2].y(),0.0, +// _q[3].x(),_q[3].y(),0.0,i,i,i,i); +// +// } +//}; +// +//struct my_wrapper { +// bool _tooclose; +// SPoint2 _p; +// my_wrapper (SPoint2 sp) : _tooclose (false), _p(sp) {} +//}; +// +//struct smoothness_point_pair{ +// double rank; +// surfacePointWithExclusionRegion* ptr; +//}; +// +//class compareSurfacePointWithExclusionRegionPtr_Smoothness +//{ +// public: +// inline bool operator () (const smoothness_point_pair &a, const smoothness_point_pair &b) const +// { +// if (a.rank == b.rank){ +// if(a.ptr->_distanceSummed > b.ptr->_distanceSummed) return false; +// if(a.ptr->_distanceSummed < b.ptr->_distanceSummed) return true; +// return a.ptr<b.ptr; +// } +// // else +// return (a.rank < b.rank); +// } +//}; +// +// +//class compareSurfacePointWithExclusionRegionPtr +//{ +// public: +// inline bool operator () (const surfacePointWithExclusionRegion *a, const surfacePointWithExclusionRegion *b) const +// { +// if(a->_distanceSummed > b->_distanceSummed) return false; +// if(a->_distanceSummed < b->_distanceSummed) return true; +// return a<b; +// } +//}; +// +// +// +// +//bool rtree_callback(surfacePointWithExclusionRegion *neighbour,void* point){ +// my_wrapper *w = static_cast<my_wrapper*>(point); +// +// if (neighbour->inExclusionZone(w->_p)){ +// w->_tooclose = true; +// return false; +// } +// +// return true; +//} +// +//bool inExclusionZone (SPoint2 &p, +// RTree<surfacePointWithExclusionRegion*,double,2,double> &rtree, +// std::vector<surfacePointWithExclusionRegion*> & all ){ +// // should assert that the point is inside the domain +// if (!backgroundMesh::current()->inDomain(p.x(),p.y(),0)) return true; +// +// my_wrapper w (p); +// double _min[2] = {p.x()-1.e-1, p.y()-1.e-1},_max[2] = {p.x()+1.e-1,p.y()+1.e-1}; +// rtree.Search(_min,_max,rtree_callback,&w); +// +// return w._tooclose; +// +// for (unsigned int i=0;i<all.size();++i){ +// if (all[i]->inExclusionZone(p)){ +// // printf("%g %g is in exclusion zone of %g %g\n",p.x(),p.y(),all[i]._center.x(),all[i]._center.y()); +// return true; +// } +// } +// return false; +//} - my_wrapper w (p); - double _min[2] = {p.x()-1.e-8, p.y()-1.e-8},_max[2] = {p.x()+1.e-8,p.y()+1.e-8}; - rtree.Search(_min,_max,rtree_callback,&w); - return w._tooclose; - for (unsigned int i=0;i<all.size();++i){ - if (all[i]->inExclusionZone(p)){ - // printf("%g %g is in exclusion zone of %g %g\n", - // p.x(),p.y(),all[i]._center.x(),all[i]._center.y()); - return true; - } - } - return false; -} // assume a point on the surface, compute the 4 possible neighbors. // @@ -217,6 +219,7 @@ bool compute4neighbors (GFace *gf, // the surface SPoint2 newP[4][NUMDIR], // look into other directions SMetric3 &metricField, FILE *crossf = 0) // the mesh metric { + //Range<double> rangeU = gf->parBounds(0); //Range<double> rangeV = gf->parBounds(1); @@ -240,6 +243,7 @@ bool compute4neighbors (GFace *gf, // the surface } } + // get the unit normal at that point Pair<SVector3, SVector3> der = gf->firstDer(SPoint2(midpoint[0],midpoint[1])); SVector3 s1 = der.first(); @@ -251,6 +255,7 @@ bool compute4neighbors (GFace *gf, // the surface double N = dot(s2,s2); double E = dot(s1,s2); + // compute the first fundamental form i.e. the metric tensor at the point // M_{ij} = s_i \cdot s_j double metric[2][2] = {{M,E},{E,N}}; @@ -261,8 +266,7 @@ bool compute4neighbors (GFace *gf, // the surface SVector3 basis_v = crossprod(n,basis_u); for (int DIR = 0 ; DIR < NUMDIR ; DIR ++){ - double quadAngle = backgroundMesh::current()->getAngle - (midpoint[0], midpoint[1],0) + DIRS[DIR]; + double quadAngle = backgroundMesh::current()->getAngle (midpoint[0],midpoint[1],0) + DIRS[DIR]; // normalize vector t1 that is tangent to gf at midpoint SVector3 t1 = basis_u * cos (quadAngle) + basis_v * sin (quadAngle) ; @@ -271,18 +275,10 @@ bool compute4neighbors (GFace *gf, // the surface // compute the second direction t2 and normalize (t1,t2,n) is the tangent frame SVector3 t2 = crossprod(n,t1); t2.normalize(); - if (DIR == 0 && crossf) - fprintf(crossf,"VP(%g,%g,%g) {%g,%g,%g};\n", - v_center->x(),v_center->y(),v_center->z(),t1.x(),t1.y(),t1.z()); - if (DIR == 0 && crossf) - fprintf(crossf,"VP(%g,%g,%g) {%g,%g,%g};\n", - v_center->x(),v_center->y(),v_center->z(),t2.x(),t2.y(),t2.z()); - if (DIR == 0 && crossf) - fprintf(crossf,"VP(%g,%g,%g) {%g,%g,%g};\n", - v_center->x(),v_center->y(),v_center->z(),-t1.x(),-t1.y(),-t1.z()); - if (DIR == 0 && crossf) - fprintf(crossf,"VP(%g,%g,%g) {%g,%g,%g};\n", - v_center->x(),v_center->y(),v_center->z(),-t2.x(),-t2.y(),-t2.z()); + if (DIR == 0 && crossf)fprintf(crossf,"VP(%g,%g,%g) {%g,%g,%g};\n",v_center->x(),v_center->y(),v_center->z(),t1.x(),t1.y(),t1.z()); + if (DIR == 0 && crossf)fprintf(crossf,"VP(%g,%g,%g) {%g,%g,%g};\n",v_center->x(),v_center->y(),v_center->z(),t2.x(),t2.y(),t2.z()); + if (DIR == 0 && crossf)fprintf(crossf,"VP(%g,%g,%g) {%g,%g,%g};\n",v_center->x(),v_center->y(),v_center->z(),-t1.x(),-t1.y(),-t1.z()); + if (DIR == 0 && crossf)fprintf(crossf,"VP(%g,%g,%g) {%g,%g,%g};\n",v_center->x(),v_center->y(),v_center->z(),-t2.x(),-t2.y(),-t2.z()); double size_1 = sqrt(1. / dot(t1,metricField,t1)); double size_2 = sqrt(1. / dot(t2,metricField,t2)); @@ -295,22 +291,21 @@ bool compute4neighbors (GFace *gf, // the surface double rhs1[2] = {dot(t1,s1),dot(t1,s2)}, covar1[2]; bool singular = false; if (!sys2x2(metric,rhs1,covar1)){ - Msg::Info("Argh surface %d %g %g %g -- %g %g %g -- %g %g", - gf->tag(),s1.x(),s1.y(),s1.z(),s2.x(),s2.y(),s2.z(),size_1,size_2); + Msg::Info("Argh surface %d %g %g %g -- %g %g %g -- %g %g",gf->tag(),s1.x(),s1.y(),s1.z(),s2.x(),s2.y(),s2.z(),size_1,size_2); covar1[1] = 1.0; covar1[0] = 0.0; singular = true; } double rhs2[2] = {dot(t2,s1),dot(t2,s2)}, covar2[2]; if (!sys2x2(metric,rhs2,covar2)){ - Msg::Info("Argh surface %d %g %g %g -- %g %g %g", - gf->tag(),s1.x(),s1.y(),s1.z(),s2.x(),s2.y(),s2.z()); + Msg::Info("Argh surface %d %g %g %g -- %g %g %g",gf->tag(),s1.x(),s1.y(),s1.z(),s2.x(),s2.y(),s2.z()); covar2[0] = 1.0; covar2[1] = 0.0; singular = true; } - // transform the sizes with respect to the metric consider a vector v of - // size 1 in the parameter plane its length is sqrt (v^T M v) --> if I want - // a real size of size1 in direction v, it should be sqrt(v^T M v) * size1 + // transform the sizes with respect to the metric + // consider a vector v of size 1 in the parameter plane + // its length is sqrt (v^T M v) --> if I want a real size + // of size1 in direction v, it should be sqrt(v^T M v) * size1 double l1 = sqrt(covar1[0]*covar1[0]+covar1[1]*covar1[1]); double l2 = sqrt(covar2[0]*covar2[0]+covar2[1]*covar2[1]); @@ -378,17 +373,17 @@ bool compute4neighbors (GFace *gf, // the surface // printf("L = %12.5E D = %12.5E ERR = %12.5E\n",L,D,100*fabs(D-L)/(D+L)); } - if (1 && goNonLinear){ - surfaceFunctorGFace ss (gf); - SVector3 dirs[4] = {t1*(-1.0),t2*(-1.0),t1*(1.0),t2*(1.0)}; - for (int i=0;i<4;i++){ + if (1 && goNonLinear){//---------------------------------------------------// + surfaceFunctorGFace ss (gf); // + SVector3 dirs[4] = {t1*(-1.0),t2*(-1.0),t1*(1.0),t2*(1.0)}; // + for (int i=0;i<4;i++){ // if (ERR[i] > 12){ - double uvt[3] = {newPoint[i][0],newPoint[i][1],0.0}; + double uvt[3] = {newPoint[i][0],newPoint[i][1],0.0}; // // printf("Intersecting with circle N = %g %g %g dir = %g %g %g R = %g p = %g %g %g\n",n.x(),n.y(),n.z(),dirs[i].x(),dirs[i].y(),dirs[i].z(),L,v_center->x(),v_center->y(),v_center->z()); curveFunctorCircle cf (dirs[i],n, SVector3(v_center->x(),v_center->y(),v_center->z()), L); - if (intersectCurveSurface (cf,ss,uvt,size_param_1*1.e-3)){ + if (intersectCurveSurface (cf,ss,uvt,size_param_1*1.e-3)){ // GPoint pp = gf->point(SPoint2(uvt[0],uvt[1])); double D = sqrt ((pp.x() - v_center->x())*(pp.x() - v_center->x()) + (pp.y() - v_center->y())*(pp.y() - v_center->y()) + @@ -396,15 +391,15 @@ bool compute4neighbors (GFace *gf, // the surface double DP = sqrt ((newPoint[i][0]-uvt[0])*(newPoint[i][0]-uvt[0]) + (newPoint[i][1]-uvt[1])*(newPoint[i][1]-uvt[1])); double newErr = 100*fabs(D-L)/(D+L); - // if (v_center->onWhat() != gf && gf->tag() == 3){ - // crossField2d::normalizeAngle (uvt[2]); - // printf("INTERSECT angle = %g DP %g\n",uvt[2],DP); - // } + // if (v_center->onWhat() != gf && gf->tag() == 3){ + // crossField2d::normalizeAngle (uvt[2]); + // printf("INTERSECT angle = %g DP %g\n",uvt[2],DP); + // } if (newErr < 1 && DP < .1){ // printf("%12.5E vs %12.5E : %12.5E %12.5E vs %12.5E %12.5E \n",ERR[i],newErr,newPoint[i][0],newPoint[i][1],uvt[0],uvt[1]); - newPoint[i][0] = uvt[0]; - newPoint[i][1] = uvt[1]; - } + newPoint[i][0] = uvt[0]; // + newPoint[i][1] = uvt[1]; // + } // // printf("OK\n"); } else{ @@ -412,8 +407,8 @@ bool compute4neighbors (GFace *gf, // the surface // printf("NOT OK\n"); } } - } - } // end non linear + } // + } /// end non linear -------------------------------------------------// // return the four new vertices for (int i=0;i<4;i++){ @@ -423,10 +418,10 @@ bool compute4neighbors (GFace *gf, // the surface return true; } +// --------------------------------------------------------------------------------------------- + // recover element around vertex v and interpolate smoothness on this element... -double get_smoothness(MVertex *v, GFace *gf, - const map<MVertex*,double> &vertices2smoothness) -{ +double get_smoothness(MVertex *v, GFace *gf, const map<MVertex*,double> &vertices2smoothness){ // recover element around MVertex v //cout << "Looking for element around point (" << v->x() << "," << v->y() << "," << v->z() << ")" << endl; SPoint3 sp3(v->x(), v->y(), v->z()); @@ -475,8 +470,9 @@ double get_smoothness(MVertex *v, GFace *gf, return res; } -void print_nodal_info_int(string filename, map<MVertex*, int> &mapp) -{ +// --------------------------------------------------------------------------------------------- + +void print_nodal_info_int(string filename, map<MVertex*, int> &mapp){ ofstream out(filename.c_str()); out << "View \"\"{" << endl; @@ -489,8 +485,9 @@ void print_nodal_info_int(string filename, map<MVertex*, int> &mapp) out.close(); } -void print_nodal_info_double(string filename, map<MVertex*, double> &mapp) -{ +// --------------------------------------------------------------------------------------------- + +void print_nodal_info_double(string filename, map<MVertex*, double> &mapp){ ofstream out(filename.c_str()); out << "View \"\"{" << endl; @@ -503,8 +500,9 @@ void print_nodal_info_double(string filename, map<MVertex*, double> &mapp) out.close(); } -void export_point(surfacePointWithExclusionRegion *sp, int DIR, FILE *crossf, GFace *gf) -{ +// --------------------------------------------------------------------------------------------- + +void export_point(surfacePointWithExclusionRegion *sp, int DIR, FILE *crossf, GFace *gf){ // get the unit normal at that point Pair<SVector3, SVector3> der = gf->firstDer(sp->_center); SVector3 s1 = der.first(); @@ -552,12 +550,9 @@ void export_point(surfacePointWithExclusionRegion *sp, int DIR, FILE *crossf, GF fprintf(crossf,"VP(%g,%g,%g) {%g,%g,%g};\n",sp->_v->x(),sp->_v->y(),sp->_v->z(),-t2.x()*size_2,-t2.y()*size_2,-t2.z()*size_2); } -bool get_local_sizes_and_directions(const MVertex *v_center, const SPoint2 &midpoint, - const int DIR, GFace* gf, double (&covar1)[2], - double (&covar2)[2], double &size_param_1, - double &size_param_2, double &L, SVector3 &t1, - SVector3 &t2, SVector3 &n, FILE *crossf=NULL) -{ +// --------------------------------------------------------------------------------------------- + +bool get_local_sizes_and_directions(const MVertex *v_center, const SPoint2 &midpoint, const int DIR, GFace* gf, double (&covar1)[2], double (&covar2)[2], double &size_param_1, double &size_param_2, double &L, SVector3 &t1, SVector3 &t2, SVector3 &n, FILE *crossf=NULL){ //bool get_RK_stuff(const MVertex *v_center, const SPoint2 &midpoint, const int DIR, GFace* gf, double (&covar1)[2], double (&covar2)[2], double &size_param_1, double &size_param_2, double &L, SVector3 &t1, SVector3 &t2, SVector3 &n, FILE *crossf, const SVector3 &previous_t1, const SVector3 &previous_t2, bool use_previous_basis=false, bool export_cross=true){ // !!!!!!!!!!!! check if point is in domain (for RK !!!) @@ -692,12 +687,14 @@ bool get_local_sizes_and_directions(const MVertex *v_center, const SPoint2 &midp return true; } + +// --------------------------------------------------------------------------------------------- + // using fifo based on smoothness criteria -void packingOfParallelogramsSmoothness(GFace* gf, std::vector<MVertex*> &packed, - std::vector<SMetric3> &metrics) -{ +void packingOfParallelogramsSmoothness(GFace* gf, std::vector<MVertex*> &packed, std::vector<SMetric3> &metrics){ cout << endl << "------------------------------------------" << endl << " PACKINGOFPARALLELOGRAMS: NEW ALGO BASED ON SMOOTHNESS" << endl << "------------------------------------------" << endl; const bool goNonLinear = true; + const bool debug = false; // build vertex -> neighbors table @@ -911,11 +908,13 @@ void packingOfParallelogramsSmoothness(GFace* gf, std::vector<MVertex*> &packed fclose(f); } + +// --------------------------------------------------------------------------------------------- + + // fills a surface with points in order to build a nice // quad mesh ------------ -void packingOfParallelograms(GFace* gf, std::vector<MVertex*> &packed, - std::vector<SMetric3> &metrics) -{ +void packingOfParallelograms(GFace* gf, std::vector<MVertex*> &packed, std::vector<SMetric3> &metrics){ //PE MODIF // packingOfParallelogramsSmoothness(gf,packed,metrics); // return; @@ -925,6 +924,13 @@ void packingOfParallelograms(GFace* gf, std::vector<MVertex*> &packed, // FILE *f = Fopen ("parallelograms.pos","w"); + + // test test test + stringstream ssa; + ssa << "oldbgm_angles_" << gf->tag() << ".pos"; + backgroundMesh::current()->print(ssa.str(),gf,1); + // test test test + // get all the boundary vertices std::set<MVertex*> bnd_vertices; for(unsigned int i=0;i<gf->getNumMeshElements();i++){ @@ -965,6 +971,7 @@ void packingOfParallelograms(GFace* gf, std::vector<MVertex*> &packed, // printf("initially : %d vertices in the domain\n",vertices.size()); + while(!fifo.empty()){ //surfacePointWithExclusionRegion & parent = fifo.top(); // surfacePointWithExclusionRegion * parent = fifo.front(); @@ -1031,3 +1038,4 @@ void packingOfParallelograms(GFace* gf, std::vector<MVertex*> &packed, // printf("packed.size = %d\n",packed.size()); // delete rtree; } + diff --git a/Mesh/surfaceFiller.h b/Mesh/surfaceFiller.h index c83d195cd6..e7fba84897 100644 --- a/Mesh/surfaceFiller.h +++ b/Mesh/surfaceFiller.h @@ -4,9 +4,15 @@ // bugs and problems to the public mailing list <gmsh@geuz.org>. // +#ifndef _SURFACEFILLER_H_ +#define _SURFACEFILLER_H_ + + #include "STensor3.h" #include <vector> class GFace; class MVertex; void packingOfParallelogramsSmoothness(GFace* gf, std::vector<MVertex*> &packed, std::vector<SMetric3> &metrics ); void packingOfParallelograms(GFace* gf, std::vector<MVertex*> &packed, std::vector<SMetric3> &metrics ); + +#endif diff --git a/Mesh/yamakawa.cpp b/Mesh/yamakawa.cpp index 2ab1893b87..d3051fdde3 100644 --- a/Mesh/yamakawa.cpp +++ b/Mesh/yamakawa.cpp @@ -12,1274 +12,3985 @@ #include "MVertex.h" #include "MElement.h" #include <fstream> +#include <sstream> #include "MHexahedron.h" #include "MQuadrangle.h" +#include "MTriangle.h" #include "MPyramid.h" #include "MPrism.h" #include "MTetrahedron.h" +#include "MHexahedron.h" +#include <numeric> +#include <math.h> -/*****************************************/ -/****************class Hex****************/ -/*****************************************/ -Hex::Hex(){} -Hex::Hex(MVertex* a2,MVertex* b2,MVertex* c2,MVertex* d2,MVertex* e2,MVertex* f2,MVertex* g2,MVertex* h2){ - a = a2; - b = b2; - c = c2; - d = d2; - e = e2; - f = f2; - g = g2; - h = h2; -} +// -------------------------------------------------------------------- -Hex::~Hex(){} +void export_gregion_mesh(GRegion *gr, string filename){ -double Hex::get_quality() const{ - return quality; -} + // create set of all tets + map<MVertex*,int> vertices; + int counterv=1; + + for (vector<MTetrahedron*>::iterator it = gr->tetrahedra.begin();it!=gr->tetrahedra.end();it++){ + for (int i=0;i<(*it)->getNumVertices();i++){ + vertices.insert(make_pair((*it)->getVertex(i),counterv)); + counterv++; + } + } + for (vector<MHexahedron*>::iterator it = gr->hexahedra.begin();it!=gr->hexahedra.end();it++){ + for (int i=0;i<(*it)->getNumVertices();i++){ + vertices.insert(make_pair((*it)->getVertex(i),counterv)); + counterv++; + } + } + for (vector<MPrism*>::iterator it = gr->prisms.begin();it!=gr->prisms.end();it++){ + for (int i=0;i<(*it)->getNumVertices();i++){ + vertices.insert(make_pair((*it)->getVertex(i),counterv)); + counterv++; + } + } + for (vector<MPyramid*>::iterator it = gr->pyramids.begin();it!=gr->pyramids.end();it++){ + for (int i=0;i<(*it)->getNumVertices();i++){ + vertices.insert(make_pair((*it)->getVertex(i),counterv)); + counterv++; + } + } -void Hex::set_quality(double new_quality){ - quality = new_quality; -} + // export mesh + ofstream out(filename.c_str()); + out << "$MeshFormat" << endl << "2.2 0 8" << endl << "$EndMeshFormat" << endl << "$Nodes" << endl << vertices.size() << endl; + // write vertices + for (map<MVertex*,int>::iterator it = vertices.begin();it!=vertices.end();it++) + out << it->second << " " << it->first->x() << " " << it->first->y() << " " << it->first->z() << endl; + out << "$EndNodes" << endl << "$Elements" << endl << (gr->tetrahedra.size()+gr->hexahedra.size()+gr->prisms.size()+gr->pyramids.size()) << endl; + + // write elems + int counter=1; + for (vector<MTetrahedron*>::iterator it = gr->tetrahedra.begin();it!=gr->tetrahedra.end();it++){ + out << counter << " 4 2 0 26"; + for (int i=0;i<(*it)->getNumVertices();i++){ + MVertex *v = (*it)->getVertex(i); + out << " " << vertices[v]; + } + out << endl; + counter++; + } + for (vector<MHexahedron*>::iterator it = gr->hexahedra.begin();it!=gr->hexahedra.end();it++){ + out << counter << " 5 2 0 26"; + for (int i=0;i<(*it)->getNumVertices();i++){ + MVertex *v = (*it)->getVertex(i); + out << " " << vertices[v]; + } + out << endl; + counter++; + } + for (vector<MPrism*>::iterator it = gr->prisms.begin();it!=gr->prisms.end();it++){ + out << counter << " 6 2 0 26"; + for (int i=0;i<(*it)->getNumVertices();i++){ + MVertex *v = (*it)->getVertex(i); + out << " " << vertices[v]; + } + out << endl; + counter++; + } + for (vector<MPyramid*>::iterator it = gr->pyramids.begin();it!=gr->pyramids.end();it++){ + out << counter << " 7 2 0 26"; + for (int i=0;i<(*it)->getNumVertices();i++){ + MVertex *v = (*it)->getVertex(i); + out << " " << vertices[v]; + } + out << endl; + counter++; + } + + + + out << "$EndElements" << endl; + out.close(); -MVertex* Hex::get_a(){ - return a; -} -MVertex* Hex::get_b(){ - return b; } -MVertex* Hex::get_c(){ - return c; -} -MVertex* Hex::get_d(){ - return d; -} +// -------------------------------------------------------------------- -MVertex* Hex::get_e(){ - return e; -} +template <class T> +void export_the_clique_graphviz_format(cliques_compatibility_graph<T> &cl, int clique_number,string filename){ -MVertex* Hex::get_f(){ - return f; -} + ofstream out(filename.c_str()); + out << "Graph G {" << endl; + typename multimap<int,set<T> >::reverse_iterator it_all = cl.allQ.rbegin(); + // multimap<int,set<T> >::reverse_iterator it_allen = cl.allQ.rend(); + for (int i=0;i<clique_number;i++){ + it_all++; + } + // int clique_size = it_all->second.size(); + typename set<T>::iterator ithex = it_all->second.begin(); + typename set<T>::iterator ithexen = it_all->second.end(); -MVertex* Hex::get_g(){ - return g; -} + //typedef tr1::unordered_multimap<hash_key, T> graph_data; + //typedef tr1::unordered_multimap<hash_key, pair<T, graph_data > > graph; -MVertex* Hex::get_h(){ - return h; -} -void Hex::set_vertices(MVertex* a2,MVertex* b2,MVertex* c2,MVertex* d2,MVertex* e2,MVertex* f2,MVertex* g2,MVertex* h2){ - a = a2; - b = b2; - c = c2; - d = d2; - e = e2; - f = f2; - g = g2; - h = h2; -} + int counter=1; + map<T,int> visited_hex; + multimap<int,int> done; -bool Hex::operator<(const Hex& hex) const{ - return quality>hex.get_quality(); -} + // export all hex + typename cliques_compatibility_graph<T>::graph::const_iterator itgraph = cl.begin_graph(); + typename cliques_compatibility_graph<T>::graph_data::const_iterator itgraphdata; + int countttttt=0; + for (;itgraph!=cl.end_graph();itgraph++){ + // cout << "counttttt : " << ++countttttt << endl; -/*******************************************/ -/****************class Facet****************/ -/*******************************************/ + T firsthex = itgraph->second.first; + // if (!post_check_validation(firsthex)) continue; -Facet::Facet(){} + typename map<T,int>::iterator itfind = visited_hex.find(firsthex); + int num1=0; + if (itfind==visited_hex.end()){ + num1=counter; + visited_hex[firsthex] = counter++; + } + else + num1 = itfind->second; -Facet::Facet(MVertex* a2,MVertex* b2,MVertex* c2){ - a = a2; - b = b2; - c = c2; - compute_hash(); -} -Facet::~Facet(){} -MVertex* Facet::get_a(){ - return a; -} -MVertex* Facet::get_b(){ - return b; -} + itgraphdata = itgraph->second.second.begin(); + for(;itgraphdata!=itgraph->second.second.end();itgraphdata++){ + T secondhex = itgraphdata->second; + // if (!post_check_validation(secondhex)) continue; + itfind = visited_hex.find(secondhex); + int num2=0; + if (itfind==visited_hex.end()){ + num2=counter; + visited_hex[secondhex] = counter++; + } + else + num2 = itfind->second; + + // search if num1 - num2 has already been written... + bool found=false; + pair<multimap<int,int>::iterator, multimap<int,int>::iterator> range = done.equal_range(num1); + for(multimap<int,int>::iterator it = range.first;it!=range.second;it++){ + if (it->second==num2){ + found=true; + break; + } + } -MVertex* Facet::get_c(){ - return c; -} + if (!found){ + done.insert(make_pair(num1,num2)); + done.insert(make_pair(num2,num1)); + out << num1 << " -- " << num2 << " ;" << endl; + } -void Facet::set_vertices(MVertex* a2,MVertex* b2,MVertex* c2){ - a = a2; - b = b2; - c = c2; - compute_hash(); -} + } -bool Facet::same_vertices(Facet facet){ - bool c1,c2,c3; - c1 = (a==facet.get_a()) || (a==facet.get_b()) || (a==facet.get_c()); - c2 = (b==facet.get_a()) || (b==facet.get_b()) || (b==facet.get_c()); - c3 = (c==facet.get_a()) || (c==facet.get_b()) || (c==facet.get_c()); + } + // export chosen hex with different color + for (;ithex!=ithexen;ithex++){ // brutal post-check: random pickup of hexahedra in clique + typename map<T,int>::iterator itfind = visited_hex.find(*ithex); + if (itfind==visited_hex.end()){ + cout << "graph export: should not happen ! " << endl; + throw; + int num2=0; + num2=counter; + visited_hex[itfind->first] = counter++; + out << num2 << " [shape=circle, style=filled, fillcolor=red];" << endl; + } + else + out << itfind->second << " [shape=circle, style=filled, fillcolor=red];" << endl; + } - return c1 && c2 && c3; -} -void Facet::compute_hash(){ - hash = a->getNum() + b->getNum() + c->getNum(); -} -unsigned long long Facet::get_hash() const{ - return hash; + out << "}" << endl; + out.close(); } -bool Facet::operator<(const Facet& facet) const{ - return hash<facet.get_hash(); -} -/**********************************************/ -/****************class Diagonal****************/ -/**********************************************/ -Diagonal::Diagonal(){} -Diagonal::Diagonal(MVertex* a2,MVertex* b2){ - a = a2; - b = b2; - compute_hash(); -} +//-------------------------------------------------------------------------------------- -Diagonal::~Diagonal(){} +template<class T> +clique_stop_criteria<T>::clique_stop_criteria(map<T, std::set<MElement*> > &_m, int _i):hex_to_tet(_m),total_number_tet(_i){ +}; -MVertex* Diagonal::get_a(){ - return a; -} +//-------------------------------------------------------------------------------------- -MVertex* Diagonal::get_b(){ - return b; -} +template<class T> +clique_stop_criteria<T>::~clique_stop_criteria(){}; -void Diagonal::set_vertices(MVertex* a2,MVertex* b2){ - a = a2; - b = b2; - compute_hash(); -} +//-------------------------------------------------------------------------------------- -bool Diagonal::same_vertices(Diagonal diagonal){ - bool c1,c2; +template<class T> +void clique_stop_criteria<T>::export_corresponding_mesh(const graph_data_no_hash &clique)const{ + // NB: fct not often called... - c1 = (a==diagonal.get_a()) || (a==diagonal.get_b()); - c2 = (b==diagonal.get_a()) || (b==diagonal.get_b()); + // filename + string filename("best_clique_so_far.msh"); + string filenametets("best_clique_so_far_remaining_tets.msh"); - return c1 && c2; -} + // create set of all tets + set<MElement*> tets; + set<MElement*> hexs; + map<MVertex*,int> vertices; + int counterv=1; + typename map<T, std::set<MElement*> >::const_iterator it = hex_to_tet.begin(); + for (;it!=hex_to_tet.end();it++){ + std::set<MElement*>::const_iterator itt = it->second.begin(); + for (;itt!=it->second.end();itt++){ + tets.insert(*itt); + for (int i=0;i<4;i++){ + vertices.insert(make_pair((*itt)->getVertex(i),counterv)); + counterv++; + } + } + } -void Diagonal::compute_hash(){ - hash = a->getNum() + b->getNum(); -} + // create MHexahedron, remove included tets from set "tets" + for (typename graph_data_no_hash::const_iterator it = clique.begin();it!=clique.end();it++){ + typename map<T, std::set<MElement*> >::const_iterator itfind = hex_to_tet.find(*it); + if (itfind==hex_to_tet.end()){ + cout << "clique_stop_criteria::void export_corresponding_mesh : not found !!!" << endl; + throw; + } + // remove tets + for (set<MElement*>::const_iterator ittet = itfind->second.begin();ittet!=itfind->second.end();ittet++){ + tets.erase(*ittet); + } + // create MHexahedron + Hex* hex=*it; + MHexahedron *h = new MHexahedron(hex->getVertex(0),hex->getVertex(1),hex->getVertex(2),hex->getVertex(3),hex->getVertex(4),hex->getVertex(5),hex->getVertex(6),hex->getVertex(7)); + for (int i=0;i<8;i++){ + vertices.insert(make_pair(hex->getVertex(i),counterv)); + counterv++; + } + hexs.insert(h); + } + + // export mesh + ofstream out(filename.c_str()); + ofstream outtets(filenametets.c_str()); + out << "$MeshFormat" << endl << "2.2 0 8" << endl << "$EndMeshFormat" << endl << "$Nodes" << endl << vertices.size() << endl; + outtets << "$MeshFormat" << endl << "2.2 0 8" << endl << "$EndMeshFormat" << endl << "$Nodes" << endl << vertices.size() << endl; + // write vertices + for (map<MVertex*,int>::iterator it = vertices.begin();it!=vertices.end();it++){ + out << it->second << " " << it->first->x() << " " << it->first->y() << " " << it->first->z() << endl; + outtets << it->second << " " << it->first->x() << " " << it->first->y() << " " << it->first->z() << endl; + } + out << "$EndNodes" << endl << "$Elements" << endl << (hexs.size()+tets.size()) << endl; + outtets << "$EndNodes" << endl << "$Elements" << endl << (hexs.size()+tets.size()) << endl; + // write hexs + int counter=1; + int countertets=1; + for (set<MElement*>::iterator it = hexs.begin();it!=hexs.end();it++){ + out << counter << " 5 2 0 26"; + for (int i=0;i<(*it)->getNumVertices();i++){ + MVertex *v = (*it)->getVertex(i); + out << " " << vertices[v]; + } + out << endl; + counter++; + } + // write tets + for (set<MElement*>::iterator it = tets.begin();it!=tets.end();it++){ + out << counter << " 4 2 0 26"; + outtets << counter << " 4 2 0 26"; + for (int i=0;i<(*it)->getNumVertices();i++){ + MVertex *v = (*it)->getVertex(i); + out << " " << vertices[v]; + outtets << " " << vertices[v]; + } + out << endl; + outtets << endl; + counter++; + countertets++; + } + out << "$EndElements" << endl; + out.close(); + outtets << "$EndElements" << endl; + outtets.close(); -unsigned long long Diagonal::get_hash() const{ - return hash; -} -bool Diagonal::operator<(const Diagonal& diagonal) const{ - return hash<diagonal.get_hash(); } -/**********************************************/ -/******************class Tuple*****************/ -/**********************************************/ +//-------------------------------------------------------------------------------------- -Tuple::Tuple(){} +template<class T> +bool clique_stop_criteria<T>::stop(const graph_data_no_hash &clique)const{ + unsigned int total = 0; -Tuple::Tuple(MVertex* a,MVertex* b,MVertex* c,MElement* element2,GFace* gf2){ - if(a<=b && a<=c){ - v1 = a; - } - else if(b<=a && b<=c){ - v1 = b; - } - else{ - v1 = c; - } + // need to detect slivers !!!!!!!!!!!!!!!!!!!!!!!!!! + + // it seems like slivers are presents in different potential hex. + // So, can be located by finding dupli!cates, instead of computing volumes...?????? + + set<MElement*> thetets; + // set<MElement*> slivers; + for (typename graph_data_no_hash::const_iterator it = clique.begin();it!=clique.end();it++){ + typename map<T, std::set<MElement*> >::const_iterator itfind = hex_to_tet.find(*it); + if (itfind==hex_to_tet.end()){ + cout << "clique_stop_criteria::bool stop : not found !!!" << endl; + throw; + } + // total += (itfind->second.size()); + // cout << "volumes=" << endl; + for (set<MElement*>::const_iterator ittet = itfind->second.begin();ittet!=itfind->second.end();ittet++){ + // set<MElement*>::iterator itfindtet = thetets.find(*ittet); + // if (itfindtet!=thetets.end()){ + // cout << "Tet " << *ittet << " already done !!!" << endl; + // slivers.insert(*ittet); + // } + thetets.insert(*ittet); + //cout << (*ittet) << " : " << (*ittet)->getVolume()<< endl;; + } - if(a>=b && a>=c){ - v3 = a; - } - else if(b>=a && b>=c){ - v3 = b; - } - else{ - v3 = c; - } - if(a!=v1 && a!=v3){ - v2 = a; } - else if(b!=v1 && b!=v3){ - v2 = b; + + // to be sure, adding volume criteria... + vector<double> volumes; + for (set<MElement*>::iterator it = thetets.begin();it!=thetets.end();it++){ + volumes.push_back((*it)->getVolume()); } - else{ - v2 = c; + int meanvolume = (std::accumulate(volumes.begin(), volumes.end(), 0))/volumes.size(); + int nb_slivers = 0; + double threshold = 1.e-3*meanvolume; + for (set<MElement*>::iterator it = thetets.begin();it!=thetets.end();it++){ + if ((*it)->getVolume() < threshold){ + nb_slivers++; + } } - element = element2; - gf = gf2; - hash = a->getNum() + b->getNum() + c->getNum(); + total = thetets.size() - nb_slivers; + + // cout << "# tet = " << total << " on " << total_number_tet << endl; + // cout << "#slivers = " << slivers.size() << endl; + if (total >= total_number_tet) return true;// the maximum clique is maximum !!! only hex !!! + return false; } -Tuple::Tuple(MVertex* a,MVertex* b,MVertex* c){ - if(a<=b && a<=c){ - v1 = a; - } - else if(b<=a && b<=c){ - v1 = b; +//-------------------------------------------------------------------------------------- + +template<class T> +cliques_compatibility_graph<T>::cliques_compatibility_graph(graph &_g, const map<T, std::vector<double> > &_hex_ranks, unsigned int _max_nb_cliques, unsigned int _nb_hex_potentiels, clique_stop_criteria<T> *csc, ptrfunction_export fct):debug(false), max_nb_cliques(_max_nb_cliques), nb_hex_potentiels(_nb_hex_potentiels), max_clique_size(0), position(0), total_nodes_number(0), cancel_search(false), hex_ranks(_hex_ranks), G(_g),criteria(csc),export_clique_graph(fct),found_the_ultimate_max_clique(false){ + + total_nb_of_cliques_searched = 0; + max_nb_of_stored_cliques = 10; + +}; + +//-------------------------------------------------------------------------------------- + +template<class T> +cliques_compatibility_graph<T>::~cliques_compatibility_graph(){ +}; + +//-------------------------------------------------------------------------------------- + +template<class T> +void cliques_compatibility_graph<T>::find_cliques(){ + // init + graph_data s; + for (typename graph::iterator it = G.begin();it!=G.end();it++){ + s.insert(make_pair(it->first, it->second.first)); } - else{ - v1 = c; + find_cliques(s,0); + + if (!cancel_search){ + cout << total_nb_of_cliques_searched << " cliques have been found." << endl << flush; } - if(a>=b && a>=c){ - v3 = a; +}; + +//-------------------------------------------------------------------------------------- + +template<class T> +void cliques_compatibility_graph<T>::export_cliques(){ + typename multimap<int, set<T> >::reverse_iterator itstore = allQ.rbegin(); + for (;itstore!=allQ.rend();itstore++){ + cout << "clique of size " << itstore->first << ": {"; + for (typename set<T>::iterator it = itstore->second.begin(); it!=itstore->second.end();it++){ + cout << *it << " "; + } + cout << "}" << endl; } - else if(b>=a && b>=c){ - v3 = b; +}; + +//-------------------------------------------------------------------------------------- + +template<class T> +void cliques_compatibility_graph<T>::store_clique(int n){ + + total_nb_of_cliques_searched++; + + + if(total_nb_of_cliques_searched%10000==0){ + if (max_nb_cliques>0) + cout << "found " << total_nb_of_cliques_searched << " cliques on " << max_nb_cliques << endl << flush; + else + cout << "found " << total_nb_of_cliques_searched << " cliques " << endl << flush; } - else{ - v3 = c; + + + if (debug){ + for (int i=0;i<n;i++) cout << " "; + cout << "entering store_clique." << endl; } - if(a!=v1 && a!=v3){ - v2 = a; + + // // check if the current clique already exists + // typename multimap<int, set<T> >::iterator itall = allQ.begin(); + // size_t currentsize = Q.size(); + // for (;itall!=allQ.end();itall++){ + // if (itall->first != currentsize) continue; + // typename std::vector<T> common(currentsize); + // typename std::vector<T>::iterator itfind = std::set_intersection (itall->second.begin(),itall->second.end(), Q.begin(),Q.end(), common.begin()); + // common.resize(itfind-common.begin()); + // if (common.size()==currentsize){ + // cout << "deux cliques les mêmes !!!" << endl; + // cout << "première: " << endl; + // typename std::set<T>::iterator itt = itall->second.begin(); + // for (;itt!=itall->second.end();itt++){ + // cout << " " << *itt ; + // } + // cout << endl << "seconde (current): " << endl; + // itt = Q.begin(); + // for (;itt!=Q.end();itt++){ + // cout << " " << *itt ; + // } + // throw; + // } + // + // } + // // END + + + + bool found_best_clique_so_far=false; + if (Q.size()>max_clique_size){ + max_clique_size=Q.size(); + cout << "found a maximum clique of size " << Q.size() << ", exporting" << endl; + found_best_clique_so_far=true; } - else if(b!=v1 && b!=v3){ - v2 = b; + + // this is done to possibly stop the algorithm after a given number of cliques found: + if ((max_nb_cliques!=0) && (total_nb_of_cliques_searched>=max_nb_cliques)){ + cancel_search=true; + cout << max_nb_cliques << " cliques have been searched, quit searching." << endl; } - else{ - v2 = c; + + // check the additional criteria + if (criteria->stop(Q)){ + cancel_search = true; + cout << endl << " ************** criteria reached, domain is filled with hex !!! ***************" << endl << endl; + found_the_ultimate_max_clique=true; } - hash = a->getNum() + b->getNum() + c->getNum(); -} -Tuple::~Tuple(){} -MVertex* Tuple::get_v1(){ - return v1; -} -MVertex* Tuple::get_v2(){ - return v2; -} + const bool verbose=false; + if (verbose) cout << "MAX CLIQUE found of size " << Q.size() << " # total cliques searched:" << total_nb_of_cliques_searched << endl; -MVertex* Tuple::get_v3(){ - return v3; -} + if (debug){ + for (int i=0;i<n;i++) cout << " "; + cout << "MAX CLIQUE found of size " << Q.size() << ": "; + } -MElement* Tuple::get_element() const{ - return element; -} + // storing the current clique... or not, depending of the number of cliques to store, to reduce memory footprint. + bool store_it = true; + bool delete_worst=false; + if ((max_nb_of_stored_cliques) && (allQ.size()>=max_nb_of_stored_cliques)){ + // then, compare sizes... + int worst_clique_size = (allQ.begin())->first; + if (Q.size() <= worst_clique_size){ + store_it = false;// don't store if not good enough + } + else{ + delete_worst=true; + } + } -GFace* Tuple::get_gf() const{ - return gf; -} + if (!store_it) return; -bool Tuple::same_vertices(Tuple tuple){ - if(v1==tuple.get_v1() && v2==tuple.get_v2() && v3==tuple.get_v3()){ - return 1; + // actually storing current clique + typename multimap<int, set<T> >::iterator itstore = allQ.insert(make_pair(Q.size(),set<T>())); + for (typename graph_data_no_hash::iterator it = Q.begin();it!=Q.end();it++){ + itstore->second.insert(*it); + if (debug){ + //for (int i=0;i<n;i++) cout << " "; + cout << *it << " "; + } } - else{ - return 0; + + // finally, possibly delete worst clique, to reduce memory footprint + if (delete_worst) allQ.erase(allQ.begin()); + + if (debug){ + cout << endl; } -} -unsigned long long Tuple::get_hash() const{ - return hash; -} -bool Tuple::operator<(const Tuple& tuple) const{ - return hash<tuple.get_hash(); -} + if (found_best_clique_so_far){ + string filename("best_clique_so_far.dot"); + export_clique_graph(const_cast<cliques_compatibility_graph<T>& >(*this),0,filename); + criteria->export_corresponding_mesh(Q); + } -/**************************************************/ -/****************class Recombinator****************/ -/**************************************************/ +}; -Recombinator::Recombinator(){} +//-------------------------------------------------------------------------------------- -Recombinator::~Recombinator(){} +template<class T> +void cliques_compatibility_graph<T>::find_cliques(graph_data &s, int n){ + // possible end + if (s.size()==0){ + store_clique(n); + return; + } + if (s.size()==1){ + typename graph_data::iterator ittemp = s.begin(); + T u = ittemp->second; + Q.insert(u); + if (debug){ + for (int i=0;i<n;i++) cout << " "; + cout << "level " << n << ", inserting (finished) " << u << endl; + } + store_clique(n); + if (debug){ + for (int i=0;i<n;i++) cout << " "; + cout << "erasing " << u << endl; + } + Q.erase(u); + if (debug){ + for (int i=0;i<n;i++) cout << " "; + cout << "and BACK" << endl; + } + return; + } -void Recombinator::execute(){ - GRegion* gr; - GModel* model = GModel::current(); - GModel::riter it; + // splitting set s into white and black nodes + graph_data white,black; + T u; + hash_key u_key; + choose_u(s,u,u_key); + split_set_BW(u,u_key,s,white,black); + if (debug){ + for (int i=0;i<n;i++) cout << " "; + cout << "level " << n << " u=" << u << " white={"; + for (typename graph_data::iterator it=white.begin();it!=white.end();it++){ + //for (int i=0;i<n;i++) cout << " "; + cout << it->second << " "; + } + cout << "} black={"; + for (typename graph_data::iterator it=black.begin();it!=black.end();it++){ + //for (int i=0;i<n;i++) cout << " "; + cout << it->second << " "; + } + cout << "}" <<endl; + } + + + // recursive loop + while (white.size()){ + //T u = (*(s.begin())); + Q.insert(u); + if (debug){ + for (int i=0;i<n;i++) cout << " "; + cout << "level " << n << ", inserting (recursive loop) " << u << endl; + } + if (n==0){ + unsigned int temp=white.size(); + total_nodes_number = std::max(total_nodes_number, temp); + position++; + cout << "treating root node " << position << "/" << total_nodes_number << endl; + } + + find_cliques(black,n+1); + if (cancel_search) break; + + erase_entry(white, u, u_key); + erase_entry(s, u, u_key); + Q.erase(u); + + black.clear(); + if (white.size()){ + typename graph_data::iterator ittemp = white.begin(); + u = ittemp->second; + u_key = ittemp->first; + fill_black_set(u,u_key,s,black);// building the black set only + + if (debug){ + for (int i=0;i<n;i++) cout << " "; + cout << "level " << n << " u=" << u << " white={"; + for (typename graph_data::iterator it=white.begin();it!=white.end();it++){ + //for (int i=0;i<n;i++) cout << " "; + cout << it->second << " "; + } + cout << "} black={"; + for (typename graph_data::iterator it=black.begin();it!=black.end();it++){ + //for (int i=0;i<n;i++) cout << " "; + cout << it->second << " "; + } + cout << "}" <<endl; + } + } + else{ + if (debug){ + for (int i=0;i<n;i++) cout << " "; + cout << "no more white" << endl; + } + } + } - for(it=model->firstRegion();it!=model->lastRegion();it++) - { - gr = *it; - if(gr->getNumMeshElements()>0){ - execute(gr); + if (debug){ + for (int i=0;i<n;i++) cout << " "; + cout << "BACK " << endl; + } + + +} + +//-------------------------------------------------------------------------------------- + +template<class T> +void cliques_compatibility_graph<T>::erase_entry(graph_data &s, T &u, hash_key &key){ + pair<typename graph_data::iterator, typename graph_data::iterator> range = s.equal_range(key); + + typename graph_data::iterator it = range.first; + for (;it!=range.second;it++){ + if (it->second==u){ + s.erase(it); + return; } } } -void Recombinator::execute(GRegion* gr){ - printf("................HEXAHEDRA................\n"); - build_tuples(gr); - init_markings(gr); +//-------------------------------------------------------------------------------------- - Msg::Info("Building Connectivity..."); - build_vertex_to_vertices(gr); - build_vertex_to_elements(gr); +template<class T> +void cliques_compatibility_graph<T>::choose_u(const graph_data &s, T &u, hash_key &u_key){ + if (s.size()==0){ + u=T(); + u_key=0; + return; + } + // choosing u + // typename graph_data::const_iterator it = s.begin(); + // ranking_data m; + // int value; + // for (;it!=s.end();it++){ + // value = function_to_maximize_for_u(*it,s); + // m.insert(make_pair(value,*it)); + // } + // typename ranking_data::iterator itm = m.end(); + // itm--; + // T u = itm->second; + // return u; - potential.clear(); - pattern1(gr); - Msg::Info("Hex-merging pattern nb. 1..."); - pattern2(gr); - Msg::Info("Hex-merging pattern nb. 2..."); - pattern3(gr); - Msg::Info("Hex-merging pattern nb. 3..."); + typename graph_data::const_iterator it = s.begin(); + u = it->second; + u_key = it->first; + double value = function_to_maximize_for_u(u,u_key,s); + double valuemax=value; + it++; + for (;it!=s.end();it++){ + value = function_to_maximize_for_u(it->second,it->first,s); + if (value>valuemax){ + valuemax=value; + u = it->second; + u_key = it->first; + } + } - std::sort(potential.begin(),potential.end()); - hash_tableA.clear(); - hash_tableB.clear(); - hash_tableC.clear(); - merge(gr); - rearrange(gr); + // typename map<T, std::vector<double> >::const_iterator itfind = hex_ranks.find(u); + // cout << "u: " << u << " # face tri: " << itfind->second[0] << " quality: " << u->get_quality() << " value max: " << valuemax << endl; - statistics(gr); - modify_surfaces(gr); + + return; } -void Recombinator::init_markings(GRegion* gr){ - size_t i; - MElement* element; +//-------------------------------------------------------------------------------------- - markings.clear(); +template<class T> +void cliques_compatibility_graph<T>::split_set_BW(const T &u, const hash_key &u_key, const graph_data &s, graph_data &white, graph_data &black){ + // splitting set s into white and black nodes + white.insert(make_pair(u_key,u)); + typename graph_data::const_iterator it = s.begin(); + for (;it!=s.end();it++){ + if (u==(it->second)) continue; + if (!compatibility(u,u_key, it->second, it->first)) + white.insert(make_pair(it->first, it->second)); + else + black.insert(make_pair(it->first, it->second)); + } +} - for(i=0;i<gr->getNumMeshElements();i++){ - element = gr->getMeshElement(i); - markings.insert(std::pair<MElement*,bool>(element,false)); +//-------------------------------------------------------------------------------------- + + +template<class T> +void cliques_compatibility_graph<T>::fill_black_set(const T &u, const hash_key &u_key, const graph_data &s, graph_data &black){ + // filling black set + typename graph_data::const_iterator it = s.begin(); + for (;it!=s.end();it++){ + if (u==(it->second)) continue; + if (compatibility(u,u_key, it->second,it->first)) + black.insert(make_pair(it->first, it->second)); } } -void Recombinator::pattern1(GRegion* gr){ - size_t i; - int index; - double quality; - MElement* element; - MVertex *a,*b,*c,*d; - MVertex *p,*q,*r,*s; - std::vector<MVertex*> already; - std::set<MVertex*> bin1; - std::set<MVertex*> bin2; - std::set<MVertex*> bin3; - std::set<MVertex*> bin4; - std::set<MVertex*>::iterator it1; - std::set<MVertex*>::iterator it2; - std::set<MVertex*>::iterator it3; - std::set<MVertex*>::iterator it4; - Hex hex; +//-------------------------------------------------------------------------------------- - for(i=0;i<gr->getNumMeshElements();i++){ - element = gr->getMeshElement(i); - //for(index=0;index<4;index++){ - max_scaled_jacobian(element,index); +// the maximum score (int) will be chosen... +template<class T> +double cliques_compatibility_graph<T>::function_to_maximize_for_u(const T &u, const hash_key &u_key, const graph_data &s){ + typename graph_data::const_iterator it = s.begin(); + int counter=0; + for (;it!=s.end();it++){ + if ((it->second)==u) continue; + if (compatibility(u,u_key, it->second,it->first)) + counter++; + } - a = element->getVertex(index); - b = element->getVertex((index+1)%4); - c = element->getVertex((index+2)%4); - d = element->getVertex((index+3)%4); + typename map<T, std::vector<double> >::const_iterator itfind = hex_ranks.find(u); + // cout << "u: " << u << " boundary score: " << itfind->second[0]*(nb_hex_potentiels/2.) << " counter score : " << counter << " total: " << (itfind->second[0]*(nb_hex_potentiels/2.) + counter) << endl; + // return (itfind->second[0]*(nb_hex_potentiels/2.) + itfind->second[1]*1000 + counter); + //return (itfind->second[0]*(nb_hex_potentiels/2.)*1000. + itfind->second[1]*3 + counter); + //return (itfind->second[0]*(nb_hex_potentiels/2.) + itfind->second[1]*10 + counter); - already.clear(); - already.push_back(a); - already.push_back(b); - already.push_back(c); - already.push_back(d); - bin1.clear(); - bin2.clear(); - bin3.clear(); - find(b,d,already,bin1); - find(b,c,already,bin2); - find(c,d,already,bin3); + //return (itfind->second[2]*nb_hex_potentiels*10000. + itfind->second[0]*(nb_hex_potentiels/2.) + itfind->second[1]*10 + counter); + return counter; +} - for(it1=bin1.begin();it1!=bin1.end();it1++){ - p = *it1; - for(it2=bin2.begin();it2!=bin2.end();it2++){ - q = *it2; - for(it3=bin3.begin();it3!=bin3.end();it3++){ - r = *it3; - if(p!=q && p!=r && q!=r){ - already.clear(); - already.push_back(a); - already.push_back(b); - already.push_back(c); - already.push_back(d); - already.push_back(p); - already.push_back(q); - already.push_back(r); - bin4.clear(); - find(p,q,r,already,bin4); - for(it4=bin4.begin();it4!=bin4.end();it4++){ - s = *it4; - hex = Hex(a,b,q,c,d,p,s,r); - quality = min_scaled_jacobian(hex); - hex.set_quality(quality); - if(valid(hex)){ - potential.push_back(hex); - } - } - } - } - } +//-------------------------------------------------------------------------------------- + +template<class T> +bool cliques_compatibility_graph<T>::compatibility(const T &u, const hash_key &u_key, const T &v, const hash_key &v_key){ + + // first, find u in graph + pair<typename graph::const_iterator, typename graph::const_iterator> range_ukey = G.equal_range(u_key); + typename graph::const_iterator itfind_u = range_ukey.first; + for (;itfind_u!=range_ukey.second;itfind_u++){ + if (itfind_u->second.first == u) break; + } + // at this point, "G[u]" = itfind_u + + // now, find v in graph_data + pair<typename graph_data::const_iterator, typename graph_data::const_iterator> range_vkey = itfind_u->second.second.equal_range(v_key); + bool found_it=false; + for (typename graph_data::const_iterator itfind_v = range_vkey.first;itfind_v!=range_vkey.second;itfind_v++){ + if (itfind_v->second == v){ + found_it=true; + break; } - //} } + return (found_it); } -void Recombinator::pattern2(GRegion* gr){ - size_t i; - int index1,index2,index3,index4; - double quality; - MElement* element; - MVertex *a,*b,*c,*d; - MVertex *p,*q,*r,*s; - std::set<MElement*> verif; - Hex hex; - - for(i=0;i<gr->getNumMeshElements();i++){ - element = gr->getMeshElement(i); - //for(index1=0;index1<3;index1++){ - //for(index2=index1+1;index2<4;index2++){ - diagonal(element,index1,index2); - two_others(index1,index2,index3,index4); +//-------------------------------------------------------------------------------------- +//-------------------------------------------------------------------------------------- - b = element->getVertex(index1); - d = element->getVertex(index2); - a = element->getVertex(index3); - c = element->getVertex(index4); +template<class T> +bool cliques_losses_graph<T>::compatibility(const T &u, const hash_key &u_key, const T &v, const hash_key &v_key){ - verif.clear(); - find(b,d,verif); - if(verif.size()==6){ - s = find(a,b,d,c,verif); - p = find(b,c,d,a,verif); - if(s!=0 && p!=0){ - r = find(s,b,d,a,verif); - q = find(p,b,d,c,verif); - if(r!=0 && q!=0){ - hex = Hex(a,s,b,c,d,r,q,p); - quality = min_scaled_jacobian(hex); - hex.set_quality(quality); - if(valid(hex)){ - potential.push_back(hex); - } + // first, find u in graph + pair<typename graph::const_iterator, typename graph::const_iterator> range_ukey = G.equal_range(u_key); + typename graph::const_iterator itfind_u = range_ukey.first; + for (;itfind_u!=range_ukey.second;itfind_u++){ + if (itfind_u->second.first == u) break; + } + // at this point, "G[u]" = itfind_u - hex = Hex(a,c,d,s,b,p,q,r); - quality = min_scaled_jacobian(hex); - hex.set_quality(quality); - if(valid(hex)){ - potential.push_back(hex); - } - } - } + // now, find v in graph_data + pair<typename graph_data::const_iterator, typename graph_data::const_iterator> range_vkey = itfind_u->second.second.equal_range(v_key); + bool found_it=false; + for (typename graph_data::const_iterator itfind_v = range_vkey.first;itfind_v!=range_vkey.second;itfind_v++){ + if (itfind_v->second == v){ + found_it=true; + break; } - //} - //} } + return (!found_it); } -void Recombinator::pattern3(GRegion* gr){ - size_t i; - int index1,index2,index3,index4; - bool c1,c2,c3,c4,c5; - bool c6,c7,c8,c9,c10; - double quality; - MElement* element; - MVertex *a,*b,*c,*d; - MVertex *p,*q,*r,*s; - MVertex *fA,*fB,*bA,*bB; - std::set<MElement*> verif1; - std::set<MElement*> verif2; - Hex hex; +//-------------------------------------------------------------------------------------- - for(i=0;i<gr->getNumMeshElements();i++){ - element = gr->getMeshElement(i); - diagonal(element,index1,index2); - two_others(index1,index2,index3,index4); +template<class T> +cliques_losses_graph<T>::cliques_losses_graph(graph &_g, const map<T, std::vector<double> > &_hex_ranks, unsigned int _max_nb_cliques, unsigned int _nb_hex_potentiels, clique_stop_criteria<T> *csc, ptrfunction_export fct):cliques_compatibility_graph<T>(_g, _hex_ranks, _max_nb_cliques, _nb_hex_potentiels,csc,fct),G(_g){ +}; - b = element->getVertex(index1); - d = element->getVertex(index2); - a = element->getVertex(index3); - c = element->getVertex(index4); +//-------------------------------------------------------------------------------------- - verif1.clear(); - verif2.clear(); - find(b,d,verif1); - find(a,c,verif2); +template<class T> +cliques_losses_graph<T>::~cliques_losses_graph(){ +}; - if(verif1.size()==4 && verif2.size()==4){ - fA = find(b,d,a,c,verif1); - fB = find(b,d,c,a,verif1); - bA = find(a,c,b,d,verif2); - bB = find(a,c,d,b,verif2); +//-------------------------------------------------------------------------------------- - if(fA!=0 && fB!=0 && bA!=0 && bB!=0 && fA!=fB && bA!=bB){ - if(scalar(fA,fB,a,b)>scalar(fA,fB,b,c) && scalar(bA,bB,a,b)>scalar(bA,bB,b,c)){ - if(distance(fA,b,c)<distance(fB,b,c)){ - p = fA; - q = fB; - } - else{ - p = fB; - q = fA; - } - if(distance(bA,b,c)<distance(bB,b,c)){ - r = bA; - s = bB; - } - else{ - r = bB; - s = bA; - } - c1 = linked(b,p); - c2 = linked(c,p); - c3 = linked(p,q); - c4 = linked(a,q); - c5 = linked(d,q); - c6 = linked(b,r); - c7 = linked(c,r); - c8 = linked(r,s); - c9 = linked(a,s); - c10 = linked(d,s); - if(c1 && c2 && c3 && c4 && c5 && c6 && c7 && c8 && c9 && c10){ - hex = Hex(p,c,r,b,q,d,s,a); - quality = min_scaled_jacobian(hex); - hex.set_quality(quality); - if(valid(hex)){ - potential.push_back(hex); - } - } - } - else if(scalar(fA,fB,a,b)<=scalar(fA,fB,b,c) && scalar(bA,bB,a,b)<=scalar(bA,bB,b,c)){ - if(distance(fA,a,b)<distance(fB,a,b)){ - p = fA; - q = fB; - } - else{ - p = fB; - q = fA; - } +// -------------------------------------------------------------------- - if(distance(bA,a,b)<distance(bB,a,b)){ - r = bA; - s = bB; - } - else{ - r = bB; - s = bA; - } +bool compare_hex_ptr_by_quality (Hex *a,Hex *b) { return (a->get_quality()>(b->get_quality())); } - c1 = linked(b,p); - c2 = linked(a,p); - c3 = linked(p,q); - c4 = linked(c,q); - c5 = linked(d,q); - c6 = linked(b,r); - c7 = linked(a,r); - c8 = linked(r,s); - c9 = linked(c,s); - c10 = linked(d,s); +/*****************************************/ +/****************class Hex****************/ +/*****************************************/ - if(c1 && c2 && c3 && c4 && c5 && c6 && c7 && c8 && c9 && c10){ - hex = Hex(p,b,r,a,q,c,s,d); - quality = min_scaled_jacobian(hex); - hex.set_quality(quality); - if(valid(hex)){ - potential.push_back(hex); - } - } - } - } - } - } +Hex::Hex():hash(0.),a(NULL),b(NULL),c(NULL),d(NULL),e(NULL),f(NULL),g(NULL),h(NULL){} + +Hex::Hex(MVertex* a2,MVertex* b2,MVertex* c2,MVertex* d2,MVertex* e2,MVertex* f2,MVertex* g2,MVertex* h2){ + a = a2; + b = b2; + c = c2; + d = d2; + e = e2; + f = f2; + g = g2; + h = h2; + set_hash(); } -void Recombinator::merge(GRegion* gr){ - unsigned int i; - int count; - bool flag; - double threshold; - double quality; - MVertex *a,*b,*c,*d; - MVertex *e,*f,*g,*h; - MElement* element; - std::set<MElement*> parts; - std::vector<MTetrahedron*> opt; - std::set<MElement*>::iterator it; - std::map<MElement*,bool>::iterator it2; - Hex hex; +void Hex::set_hash(){ + hash = (a->getNum() + b->getNum() + c->getNum() + d->getNum() + e->getNum() + f->getNum() + g->getNum() + h->getNum()); +} - count = 1; - quality = 0.0; +unsigned long long Hex::get_hash(){ + if ((hash==0.)&&(a)) set_hash(); + return hash; +} - for(i=0;i<potential.size();i++){ - hex = potential[i]; +bool Hex::hasVertex(const MVertex *v){ + for (int i=0;i<8;i++) + if (getVertex(i)==v) return true; + return false; +} - threshold = 0.25; - if(hex.get_quality()<threshold){ - break; - } - a = hex.get_a(); - b = hex.get_b(); - c = hex.get_c(); - d = hex.get_d(); - e = hex.get_e(); - f = hex.get_f(); - g = hex.get_g(); - h = hex.get_h(); +bool Hex::same_vertices(Hex *h){ + for (int i=0;i<8;i++) + if (!(h->hasVertex(getVertex(i)))) + return false; + return true; +} - parts.clear(); - find(a,hex,parts); - find(b,hex,parts); - find(c,hex,parts); - find(d,hex,parts); - find(e,hex,parts); - find(f,hex,parts); - find(g,hex,parts); - find(h,hex,parts); +Hex::~Hex(){} - flag = 1; - for(it=parts.begin();it!=parts.end();it++){ - element = *it; - it2 = markings.find(element); - if(it2->second==1 && !sliver(element,hex)){ - flag = 0; - break; - } - } - if(!flag) continue; +double Hex::get_quality(){ + return quality; +} - if(!valid(hex,parts)){ - continue; - } +void Hex::set_quality(double new_quality){ + quality = new_quality; +} - if(!conformityA(hex)){ - continue; - } +MVertex* Hex::get_a(){ + return a; +} - if(!conformityB(hex)){ - continue; - } +MVertex* Hex::get_b(){ + return b; +} - if(!conformityC(hex)){ - continue; - } +MVertex* Hex::get_c(){ + return c; +} - if(!faces_statuquo(hex)){ - continue; - } +MVertex* Hex::get_d(){ + return d; +} - //printf("%d - %d/%d - %f\n",count,i,(int)potential.size(),hex.get_quality()); - quality = quality + hex.get_quality(); - for(it=parts.begin();it!=parts.end();it++){ - element = *it; - it2 = markings.find(element); - it2->second = 1; - } - gr->addHexahedron(new MHexahedron(a,b,c,d,e,f,g,h)); - build_hash_tableA(hex); - build_hash_tableB(hex); - build_hash_tableC(hex); - count++; - } +MVertex* Hex::get_e(){ + return e; +} - opt.clear(); - opt.resize(gr->tetrahedra.size()); - opt = gr->tetrahedra; - gr->tetrahedra.clear(); +MVertex* Hex::get_f(){ + return f; +} - for(i=0;i<opt.size();i++){ - element = (MElement*)(opt[i]); - it2 = markings.find(element); - if(it2->second==0){ - gr->tetrahedra.push_back(opt[i]); - } - } +MVertex* Hex::get_g(){ + return g; +} - printf("hexahedra average quality (0->1) : %f\n",quality/count); +MVertex* Hex::get_h(){ + return h; } -void Recombinator::improved_merge(GRegion* gr){ - unsigned int i; - int count; - bool flag; - double threshold; - double quality; - MVertex *a,*b,*c,*d; - MVertex *e,*f,*g,*h; - MElement* element; - std::set<MElement*> parts; - std::vector<MTetrahedron*> opt; - std::set<MElement*>::iterator it; - std::map<MElement*,bool>::iterator it2; - std::vector<MTetrahedron*>::iterator it3; - Hex hex; +MVertex* Hex::getVertex(int n){ + MVertex *v; + switch (n){ + case 0: + v = get_a(); + break; + case 1: + v = get_b(); + break; + case 2: + v = get_c(); + break; + case 3: + v = get_d(); + break; + case 4: + v = get_e(); + break; + case 5: + v = get_f(); + break; + case 6: + v = get_g(); + break; + case 7: + v = get_h(); + break; + default: + cout << "Hex: unknown vertex number " << n << endl; + throw; + } + return v; +} - count = 1; - quality = 0.0; - for(i=0;i<potential.size();i++){ - hex = potential[i]; +void Hex::set_vertices(MVertex* a2,MVertex* b2,MVertex* c2,MVertex* d2,MVertex* e2,MVertex* f2,MVertex* g2,MVertex* h2){ + a = a2; + b = b2; + c = c2; + d = d2; + e = e2; + f = f2; + g = g2; + h = h2; +} - threshold = 0.25; - if(hex.get_quality()<threshold){ - break; - } +bool Hex::operator<(Hex& hex){ + return quality>hex.get_quality(); +} - a = hex.get_a(); - b = hex.get_b(); - c = hex.get_c(); - d = hex.get_d(); - e = hex.get_e(); - f = hex.get_f(); - g = hex.get_g(); - h = hex.get_h(); - parts.clear(); - find(a,hex,parts); - find(b,hex,parts); - find(c,hex,parts); - find(d,hex,parts); - find(e,hex,parts); - find(f,hex,parts); - find(g,hex,parts); - find(h,hex,parts); +////////////////////////////////////////////////////////////////////////////////////////////////////////// - flag = 1; - for(it=parts.begin();it!=parts.end();it++){ - element = *it; - it2 = markings.find(element); - if(it2->second==1 && !sliver(element,hex)){ - flag = 0; - break; - } - } - if(!flag) continue; +PEEntity::PEEntity(const vector<const MVertex*> &_v):vertices(_v){ + compute_hash(); +} - if(!valid(hex,parts)){ - continue; - } +//PEEntity::PEEntity(unsigned long long l):hash(l){ +//} - if(!conformityA(hex)){ - continue; - } +void PEEntity::compute_hash(){ + hash=0; + for (vector<const MVertex*>::const_iterator it = vertices.begin();it!=vertices.end();it++) + hash+=(*it)->getNum(); +} - if(!conformityB(hex)){ - continue; - } +size_t PEEntity::get_hash() const{ + return hash; +} - if(!conformityC(hex)){ - continue; - } +PEEntity::~PEEntity(){} - //printf("%d - %d/%d - %f\n",count,i,(int)potential.size(),hex.get_quality()); - quality = quality + hex.get_quality(); - for(it=parts.begin();it!=parts.end();it++){ - element = *it; - it2 = markings.find(element); - it2->second = 1; - } - gr->addHexahedron(new MHexahedron(a,b,c,d,e,f,g,h)); - build_hash_tableA(hex); - build_hash_tableB(hex); - build_hash_tableC(hex); - count++; +const MVertex* PEEntity::getVertex(size_t n)const{ + if ((n<0) || (n>get_max_nb_vertices()) || vertices.empty()){ + cout << " PEEntity::getVertex : wrong vertex number : int n = " << n << endl; + throw; } + return vertices[n]; +} - opt.clear(); - opt.resize(gr->tetrahedra.size()); - opt = gr->tetrahedra; - gr->tetrahedra.clear(); +bool PEEntity::hasVertex(const MVertex *v)const{ + return (find(vertices.begin(),vertices.end(), v)!=vertices.end()); +} - for(i=0;i<opt.size();i++){ - element = (MElement*)(opt[i]); - it2 = markings.find(element); - if(it2->second==0){ - gr->tetrahedra.push_back(opt[i]); - } +bool PEEntity::same_vertices(const PEEntity *t)const{ + for (vector<const MVertex*>::const_iterator it=vertices.begin();it!=vertices.end();it++){ + if (!(t->hasVertex(*it))) + return false; } + return true; +} - printf("hexahedra average quality (0->1) : %f\n",quality/count); +bool PEEntity::operator<(const PEEntity& t) const{ + return hash<t.get_hash(); } -void Recombinator::rearrange(GRegion* gr){ - size_t i; - MElement* element; +//bool PEEntity::operator==(const PEEntity& t) const{ +// return (hash==t.get_hash()); +//} - for(i=0;i<gr->getNumMeshElements();i++){ - element = gr->getMeshElement(i); - element->setVolumePositive(); +//bool PEEntity::operator==(const size_t& l) const{ +// return (hash==l); +//} + +// -------------------------------------------------------------------- + +PELine::~PELine(){}; + +PELine::PELine(const vector<const MVertex*> &_v):PEEntity(_v){ + if (vertices.size()!=get_max_nb_vertices()){ + cout << "PELine: wrong number of vertices given !!! aborting ! " << endl; + throw; } + compute_hash(); } -void Recombinator::statistics(GRegion* gr){ - size_t i; - int all_nbr,hex_nbr; - double all_volume,hex_volume,volume; - MElement* element; - - all_nbr = 0; - hex_nbr = 0; - all_volume = 0.0; - hex_volume = 0.0; +size_t PELine::get_max_nb_vertices()const{return 2;}; - for(i=0;i<gr->getNumMeshElements();i++){ - element = gr->getMeshElement(i); - volume = element->getVolume(); +// -------------------------------------------------------------------- - if(element->getNumVertices()==8){ - hex_nbr = hex_nbr + 1; - hex_volume = hex_volume + volume; - } +PETriangle::~PETriangle(){}; - all_nbr = all_nbr + 1; - all_volume = all_volume + volume; +PETriangle::PETriangle(const vector<const MVertex*> &_v):PEEntity(_v){ + if (vertices.size()!=get_max_nb_vertices()){ + cout << "PETriangle: wrong number of vertices given !!! aborting ! " << endl; + throw; } - - printf("percentage of hexahedra (number) : %.2f\n",hex_nbr*100.0/all_nbr); - printf("percentage of hexahedra (volume) : %.2f\n",hex_volume*100.0/all_volume); + compute_hash(); } -void Recombinator::build_tuples(GRegion* gr){ - unsigned int i; - MVertex *a,*b,*c; - MElement* element; - GFace* gf; - std::list<GFace*> faces; - std::list<GFace*>::iterator it; - - tuples.clear(); - triangles.clear(); - faces.clear(); - - faces = gr->faces(); +//PETriangle::PETriangle(const unsigned long long l):PEEntity(l){ +//} - for(it=faces.begin();it!=faces.end();it++) - { - gf = *it; +size_t PETriangle::get_max_nb_vertices()const{return 3;}; - for(i=0;i<gf->getNumMeshElements();i++){ - element = gf->getMeshElement(i); +// -------------------------------------------------------------------- - if(element->getNumVertices()==3){ - a = element->getVertex(0); - b = element->getVertex(1); - c = element->getVertex(2); +PEQuadrangle::~PEQuadrangle(){}; - tuples.insert(Tuple(a,b,c,element,gf)); - } - } +PEQuadrangle::PEQuadrangle(const vector<const MVertex*> &_v):PEEntity(_v){ + if (vertices.size()!=get_max_nb_vertices()){ + cout << "PEQuadrangle: wrong number of vertices given !!! aborting ! " << endl; + throw; } + compute_hash(); } -void Recombinator::modify_surfaces(GRegion* gr){ - unsigned int i; - MVertex *a,*b,*c,*d; - MVertex *e,*f,*g,*h; - MElement* element; - GFace* gf; - std::list<GFace*> faces; - std::vector<MElement*> opt; - std::list<GFace*>::iterator it; - std::set<MElement*>::iterator it2; +//PEQuadrangle::PEQuadrangle(const unsigned long long l):PEEntity(l){ +//} - for(i=0;i<gr->getNumMeshElements();i++){ - element = gr->getMeshElement(i); +size_t PEQuadrangle::get_max_nb_vertices()const{return 4;}; - if(element->getNumVertices()==8){ - a = element->getVertex(0); - b = element->getVertex(1); - c = element->getVertex(2); - d = element->getVertex(3); - e = element->getVertex(4); - f = element->getVertex(5); - g = element->getVertex(6); - h = element->getVertex(7); - modify_surfaces(a,b,c,d); - modify_surfaces(e,f,g,h); - modify_surfaces(a,e,h,d); - modify_surfaces(b,f,g,c); - modify_surfaces(a,e,f,b); - modify_surfaces(d,h,g,c); - } - } +/*******************************************/ +/****************class Facet****************/ +/*******************************************/ - faces = gr->faces(); +Facet::Facet(){} - for(it=faces.begin();it!=faces.end();it++) - { - gf = *it; +Facet::Facet(MVertex* a2,MVertex* b2,MVertex* c2){ + a = a2; + b = b2; + c = c2; + compute_hash(); +} - opt.clear(); +Facet::~Facet(){} - for(i=0;i<gf->getNumMeshElements();i++){ - element = gf->getMeshElement(i); +MVertex* Facet::get_a(){ + return a; +} - if(element->getNumVertices()==3){ - it2 = triangles.find(element); - if(it2==triangles.end()){ - opt.push_back(element); - } - } - } +MVertex* Facet::get_b(){ + return b; +} - gf->triangles.clear(); +MVertex* Facet::get_c(){ + return c; +} - for(i=0;i<opt.size();i++){ - gf->triangles.push_back((MTriangle*)opt[i]); - } - } +void Facet::set_vertices(MVertex* a2,MVertex* b2,MVertex* c2){ + a = a2; + b = b2; + c = c2; + compute_hash(); } -void Recombinator::modify_surfaces(MVertex* a,MVertex* b,MVertex* c,MVertex* d){ - bool flag1,flag2; - MElement *element1,*element2; - GFace *gf1;//,*gf2; - Tuple tuple1,tuple2; - std::multiset<Tuple>::iterator it1; - std::multiset<Tuple>::iterator it2; +bool Facet::same_vertices(Facet facet){ + bool c1,c2,c3; - gf1 = NULL; - //gf2 = NULL; + c1 = (a==facet.get_a()) || (a==facet.get_b()) || (a==facet.get_c()); + c2 = (b==facet.get_a()) || (b==facet.get_b()) || (b==facet.get_c()); + c3 = (c==facet.get_a()) || (c==facet.get_b()) || (c==facet.get_c()); - tuple1 = Tuple(a,b,c); - tuple2 = Tuple(c,d,a); + return c1 && c2 && c3; +} - it1 = tuples.find(tuple1); - it2 = tuples.find(tuple2); +void Facet::compute_hash(){ + hash = a->getNum() + b->getNum() + c->getNum(); +} - flag1 = 0; - flag2 = 0; +unsigned long long Facet::get_hash() const{ + return hash; +} - while(it1!=tuples.end()){ - if(tuple1.get_hash()!=it1->get_hash()){ - break; - } +bool Facet::operator<(const Facet& facet) const{ + return hash<facet.get_hash(); +} - if(tuple1.same_vertices(*it1)){ - flag1 = 1; - element1 = it1->get_element(); - gf1 = it1->get_gf(); - } +/**********************************************/ +/****************class Diagonal****************/ +/**********************************************/ - it1++; - } +Diagonal::Diagonal(){} - while(it2!=tuples.end()){ - if(tuple2.get_hash()!=it2->get_hash()){ - break; - } +Diagonal::Diagonal(MVertex* a2,MVertex* b2){ + a = a2; + b = b2; + compute_hash(); +} - if(tuple2.same_vertices(*it2)){ - flag2 = 1; - element2 = it2->get_element(); - //gf2 = it2->get_gf(); - } +Diagonal::~Diagonal(){} - it2++; - } +MVertex* Diagonal::get_a(){ + return a; +} - if(flag1 && flag2){ - triangles.insert(element1); - triangles.insert(element2); +MVertex* Diagonal::get_b(){ + return b; +} - gf1->addQuadrangle(new MQuadrangle(a,b,c,d)); - } +void Diagonal::set_vertices(MVertex* a2,MVertex* b2){ + a = a2; + b = b2; + compute_hash(); +} - tuple1 = Tuple(a,b,d); - tuple2 = Tuple(b,c,d); +bool Diagonal::same_vertices(Diagonal diagonal){ + bool c1,c2; - it1 = tuples.find(tuple1); - it2 = tuples.find(tuple2); + c1 = (a==diagonal.get_a()) || (a==diagonal.get_b()); + c2 = (b==diagonal.get_a()) || (b==diagonal.get_b()); - flag1 = 0; - flag2 = 0; + return c1 && c2; +} - while(it1!=tuples.end()){ - if(tuple1.get_hash()!=it1->get_hash()){ - break; - } +void Diagonal::compute_hash(){ + hash = a->getNum() + b->getNum(); +} - if(tuple1.same_vertices(*it1)){ - flag1 = 1; - element1 = it1->get_element(); - gf1 = it1->get_gf(); - } +unsigned long long Diagonal::get_hash() const{ + return hash; +} - it1++; - } +bool Diagonal::operator<(const Diagonal& diagonal) const{ + return hash<diagonal.get_hash(); +} - while(it2!=tuples.end()){ - if(tuple2.get_hash()!=it2->get_hash()){ - break; - } +/**********************************************/ +/******************class Tuple*****************/ +/**********************************************/ - if(tuple2.same_vertices(*it2)){ - flag2 = 1; - element2 = it2->get_element(); - //gf2 = it2->get_gf(); - } +Tuple::Tuple(){} - it2++; +Tuple::Tuple(MVertex* a,MVertex* b,MVertex* c,MElement* element2,GFace* gf2){ + if(a<=b && a<=c){ + v1 = a; + } + else if(b<=a && b<=c){ + v1 = b; + } + else{ + v1 = c; } - if(flag1 && flag2){ - triangles.insert(element1); - triangles.insert(element2); - - gf1->addQuadrangle(new MQuadrangle(a,b,c,d)); + if(a>=b && a>=c){ + v3 = a; + } + else if(b>=a && b>=c){ + v3 = b; + } + else{ + v3 = c; } -} -bool Recombinator::sliver(MElement* element,Hex hex){ - bool val; - bool flag1,flag2,flag3,flag4; - MVertex *a,*b,*c,*d; + if(a!=v1 && a!=v3){ + v2 = a; + } + else if(b!=v1 && b!=v3){ + v2 = b; + } + else{ + v2 = c; + } - val = 0; - a = element->getVertex(0); - b = element->getVertex(1); - c = element->getVertex(2); - d = element->getVertex(3); + element = element2; + gf = gf2; + hash = a->getNum() + b->getNum() + c->getNum(); +} - flag1 = inclusion(a,hex.get_a(),hex.get_b(),hex.get_c(),hex.get_d()); - flag2 = inclusion(b,hex.get_a(),hex.get_b(),hex.get_c(),hex.get_d()); - flag3 = inclusion(c,hex.get_a(),hex.get_b(),hex.get_c(),hex.get_d()); - flag4 = inclusion(d,hex.get_a(),hex.get_b(),hex.get_c(),hex.get_d()); - if(flag1 && flag2 && flag3 && flag4) val = 1; +Tuple::Tuple(MVertex* a,MVertex* b,MVertex* c){ + if(a<=b && a<=c){ + v1 = a; + } + else if(b<=a && b<=c){ + v1 = b; + } + else{ + v1 = c; + } - flag1 = inclusion(a,hex.get_e(),hex.get_f(),hex.get_g(),hex.get_h()); - flag2 = inclusion(b,hex.get_e(),hex.get_f(),hex.get_g(),hex.get_h()); - flag3 = inclusion(c,hex.get_e(),hex.get_f(),hex.get_g(),hex.get_h()); - flag4 = inclusion(d,hex.get_e(),hex.get_f(),hex.get_g(),hex.get_h()); - if(flag1 && flag2 && flag3 && flag4) val = 1; + if(a>=b && a>=c){ + v3 = a; + } + else if(b>=a && b>=c){ + v3 = b; + } + else{ + v3 = c; + } - flag1 = inclusion(a,hex.get_a(),hex.get_b(),hex.get_e(),hex.get_f()); - flag2 = inclusion(b,hex.get_a(),hex.get_b(),hex.get_e(),hex.get_f()); - flag3 = inclusion(c,hex.get_a(),hex.get_b(),hex.get_e(),hex.get_f()); - flag4 = inclusion(d,hex.get_a(),hex.get_b(),hex.get_e(),hex.get_f()); - if(flag1 && flag2 && flag3 && flag4) val = 1; + if(a!=v1 && a!=v3){ + v2 = a; + } + else if(b!=v1 && b!=v3){ + v2 = b; + } + else{ + v2 = c; + } - flag1 = inclusion(a,hex.get_b(),hex.get_c(),hex.get_g(),hex.get_f()); - flag2 = inclusion(b,hex.get_b(),hex.get_c(),hex.get_g(),hex.get_f()); - flag3 = inclusion(c,hex.get_b(),hex.get_c(),hex.get_g(),hex.get_f()); - flag4 = inclusion(d,hex.get_b(),hex.get_c(),hex.get_g(),hex.get_f()); - if(flag1 && flag2 && flag3 && flag4) val = 1; + hash = a->getNum() + b->getNum() + c->getNum(); +} - flag1 = inclusion(a,hex.get_c(),hex.get_d(),hex.get_g(),hex.get_h()); - flag2 = inclusion(b,hex.get_c(),hex.get_d(),hex.get_g(),hex.get_h()); - flag3 = inclusion(c,hex.get_c(),hex.get_d(),hex.get_g(),hex.get_h()); - flag4 = inclusion(d,hex.get_c(),hex.get_d(),hex.get_g(),hex.get_h()); - if(flag1 && flag2 && flag3 && flag4) val = 1; +Tuple::~Tuple(){} - flag1 = inclusion(a,hex.get_a(),hex.get_d(),hex.get_e(),hex.get_h()); - flag2 = inclusion(b,hex.get_a(),hex.get_d(),hex.get_e(),hex.get_h()); - flag3 = inclusion(c,hex.get_a(),hex.get_d(),hex.get_e(),hex.get_h()); - flag4 = inclusion(d,hex.get_a(),hex.get_d(),hex.get_e(),hex.get_h()); - if(flag1 && flag2 && flag3 && flag4) val = 1; +MVertex* Tuple::get_v1(){ + return v1; +} - return val; +MVertex* Tuple::get_v2(){ + return v2; } -double Recombinator::diagonal(MElement* element,int& index1,int& index2){ - double max; - double l1,l2,l3,l4,l5,l6; - MVertex *a,*b,*c,*d; +MVertex* Tuple::get_v3(){ + return v3; +} - a = element->getVertex(0); - b = element->getVertex(1); - c = element->getVertex(2); - d = element->getVertex(3); +MElement* Tuple::get_element() const{ + return element; +} - max = 1000000.0; - l1 = distance(a,b); - l2 = distance(a,c); - l3 = distance(a,d); - l4 = distance(b,c); - l5 = distance(c,d); - l6 = distance(d,b); +GFace* Tuple::get_gf() const{ + return gf; +} - if(l1>=l2 && l1>=l3 && l1>=l4 && l1>=l5 && l1>=l6){ - index1 = 0; - index2 = 1; - max = l1; - } - else if(l2>=l1 && l2>=l3 && l2>=l4 && l2>=l5 && l2>=l6){ - index1 = 0; - index2 = 2; - max = l2; - } - else if(l3>=l1 && l3>=l2 && l3>=l4 && l3>=l5 && l3>=l6){ - index1 = 0; - index2 = 3; - max = l3; - } - else if(l4>=l1 && l4>=l2 && l4>=l3 && l4>=l5 && l4>=l6){ - index1 = 1; - index2 = 2; - max = l4; - } - else if(l5>=l1 && l5>=l2 && l5>=l3 && l5>=l4 && l5>=l6){ - index1 = 2; - index2 = 3; - max = l5; +bool Tuple::same_vertices(Tuple tuple){ + if(v1==tuple.get_v1() && v2==tuple.get_v2() && v3==tuple.get_v3()){ + return 1; } - else if(l6>=l1 && l6>=l2 && l6>=l3 && l6>=l4 && l6>=l5){ - index1 = 3; - index2 = 1; - max = l6; + else{ + return 0; } +} - return max; +unsigned long long Tuple::get_hash() const{ + return hash; } -double Recombinator::distance(MVertex* v1,MVertex* v2){ - double val; - double x,y,z; +bool Tuple::operator<(const Tuple& tuple) const{ + return hash<tuple.get_hash(); +} - x = v2->x() - v1->x(); - y = v2->y() - v1->y(); - z = v2->z() - v1->z(); +/**************************************************/ +/****************class Recombinator****************/ +/**************************************************/ - val = sqrt(x*x + y*y + z*z); - return val; +Recombinator::Recombinator(){} + +Recombinator::~Recombinator(){ + for (std::vector<Hex*>::iterator it = potential.begin();it!=potential.end();it++){ + delete *it; + } } -double Recombinator::distance(MVertex* v,MVertex* v1,MVertex* v2){ - double val; - double x,y,z; +void Recombinator::execute(){ - x = 0.5*(v2->x() + v1->x()) - v->x(); - y = 0.5*(v2->y() + v1->y()) - v->y(); - z = 0.5*(v2->z() + v1->z()) - v->z(); + GRegion* gr; + GModel* model = GModel::current(); + GModel::riter it; - val = sqrt(x*x + y*y + z*z); - return val; + for(it=model->firstRegion();it!=model->lastRegion();it++) + { + gr = *it; + if(gr->getNumMeshElements()>0){ + execute(gr); + } + } } -double Recombinator::scalar(MVertex* v1,MVertex* v2,MVertex* v3,MVertex* v4){ - double val; - double l1,l2; - SVector3 vec1,vec2; +void Recombinator::execute(GRegion* gr){ + printf("................HEXAHEDRA................\n"); + build_tuples(gr); + init_markings(gr); - vec1 = SVector3(v2->x()-v1->x(),v2->y()-v1->y(),v2->z()-v1->z()); - vec2 = SVector3(v4->x()-v3->x(),v4->y()-v3->y(),v4->z()-v3->z()); + Msg::Info("Building Connectivity..."); + build_vertex_to_vertices(gr); + build_vertex_to_elements(gr); - l1 = vec1.norm(); - l2 = vec2.norm(); + potential.clear(); + Msg::Info("Hex-merging pattern nb. 1..."); + pattern1(gr); + Msg::Info("Hex-merging pattern nb. 2..."); + pattern2(gr); + Msg::Info("Hex-merging pattern nb. 3..."); + pattern3(gr); - val = dot(vec1,vec2); - return fabs(val)/(l1*l2); + std::sort(potential.begin(),potential.end(),compare_hex_ptr_by_quality); + + + // /// SORTIE TOUS HEX POT + // cout << "__________________________ START POT HEX LISTING ____________________ " << endl; + // for (std::vector<Hex*>::iterator it = potential.begin();it!=potential.end();it++){ + // cout << "--- pot hex : " << *it << " " << (*it)->get_quality() << endl; + // } + // cout << "__________________________ END POT HEX LISTING ____________________ " << endl; + // /// END + + hash_tableA.clear(); + hash_tableB.clear(); + hash_tableC.clear(); + merge(gr); + + rearrange(gr); + + statistics(gr); + + + modify_surfaces(gr); } -void Recombinator::two_others(int index1,int index2,int& index3,int& index4){ - int i; +void Recombinator::init_markings(GRegion* gr){ + size_t i; + MElement* element; - for(i=0;i<4;i++){ - if(i!=index1 && i!=index2){ - index3 = i; - break; - } - } + markings.clear(); - for(i=0;i<4;i++){ - if(i!=index1 && i!=index2 && i!=index3){ - index4 = i; - break; - } + for(i=0;i<gr->getNumMeshElements();i++){ + element = gr->getMeshElement(i); + markings.insert(std::pair<MElement*,bool>(element,false)); } } -bool Recombinator::valid(Hex hex,const std::set<MElement*>& parts){ +void Recombinator::pattern1(GRegion* gr){ + size_t i; + int index; + double quality; + MElement* element; + MVertex *a,*b,*c,*d; + MVertex *p,*q,*r,*s; + std::vector<MVertex*> already; + std::set<MVertex*> bin1; + std::set<MVertex*> bin2; + std::set<MVertex*> bin3; + std::set<MVertex*> bin4; + std::set<MVertex*>::iterator it1; + std::set<MVertex*>::iterator it2; + std::set<MVertex*>::iterator it3; + std::set<MVertex*>::iterator it4; + Hex *hex; + + for(i=0;i<gr->getNumMeshElements();i++){ + element = gr->getMeshElement(i); + //for(index=0;index<4;index++){ + max_scaled_jacobian(element,index); + + a = element->getVertex(index); + b = element->getVertex((index+1)%4); + c = element->getVertex((index+2)%4); + d = element->getVertex((index+3)%4); + + already.clear(); + already.push_back(a); + already.push_back(b); + already.push_back(c); + already.push_back(d); + bin1.clear(); + bin2.clear(); + bin3.clear(); + find(b,d,already,bin1); + find(b,c,already,bin2); + find(c,d,already,bin3); + + for(it1=bin1.begin();it1!=bin1.end();it1++){ + p = *it1; + for(it2=bin2.begin();it2!=bin2.end();it2++){ + q = *it2; + for(it3=bin3.begin();it3!=bin3.end();it3++){ + r = *it3; + if(p!=q && p!=r && q!=r){ + already.clear(); + already.push_back(a); + already.push_back(b); + already.push_back(c); + already.push_back(d); + already.push_back(p); + already.push_back(q); + already.push_back(r); + bin4.clear(); + find(p,q,r,already,bin4); + for(it4=bin4.begin();it4!=bin4.end();it4++){ + s = *it4; + hex = new Hex(a,b,q,c,d,p,s,r); + quality = min_scaled_jacobian(*hex); + hex->set_quality(quality); + if(valid(*hex)){ + potential.push_back(hex); + } + else delete hex; + } + } + } + } + } + //} + } +} + +void Recombinator::pattern2(GRegion* gr){ + size_t i; + int index1,index2,index3,index4; + double quality; + MElement* element; + MVertex *a,*b,*c,*d; + MVertex *p,*q,*r,*s; + std::set<MElement*> verif; + Hex *hex; + + for(i=0;i<gr->getNumMeshElements();i++){ + element = gr->getMeshElement(i); + //for(index1=0;index1<3;index1++){ + //for(index2=index1+1;index2<4;index2++){ + diagonal(element,index1,index2); + two_others(index1,index2,index3,index4); + + b = element->getVertex(index1); + d = element->getVertex(index2); + a = element->getVertex(index3); + c = element->getVertex(index4); + + verif.clear(); + find(b,d,verif); + if(verif.size()==6){ + s = find(a,b,d,c,verif); + p = find(b,c,d,a,verif); + if(s!=0 && p!=0){ + r = find(s,b,d,a,verif); + q = find(p,b,d,c,verif); + if(r!=0 && q!=0){ + hex = new Hex(a,s,b,c,d,r,q,p); + quality = min_scaled_jacobian(*hex); + hex->set_quality(quality); + if(valid(*hex)){ + potential.push_back(hex); + } + else delete hex; + + hex = new Hex(a,c,d,s,b,p,q,r); + quality = min_scaled_jacobian(*hex); + hex->set_quality(quality); + if(valid(*hex)){ + potential.push_back(hex); + } + else delete hex; + } + } + } + //} + //} + } +} + +void Recombinator::pattern3(GRegion* gr){ + size_t i; + int index1,index2,index3,index4; + bool c1,c2,c3,c4,c5; + bool c6,c7,c8,c9,c10; + double quality; + MElement* element; + MVertex *a,*b,*c,*d; + MVertex *p,*q,*r,*s; + MVertex *fA,*fB,*bA,*bB; + std::set<MElement*> verif1; + std::set<MElement*> verif2; + Hex *hex; + + for(i=0;i<gr->getNumMeshElements();i++){ + element = gr->getMeshElement(i); + diagonal(element,index1,index2); + two_others(index1,index2,index3,index4); + + b = element->getVertex(index1); + d = element->getVertex(index2); + a = element->getVertex(index3); + c = element->getVertex(index4); + + verif1.clear(); + verif2.clear(); + find(b,d,verif1); + find(a,c,verif2); + + if(verif1.size()==4 && verif2.size()==4){ + fA = find(b,d,a,c,verif1); + fB = find(b,d,c,a,verif1); + bA = find(a,c,b,d,verif2); + bB = find(a,c,d,b,verif2); + + if(fA!=0 && fB!=0 && bA!=0 && bB!=0 && fA!=fB && bA!=bB){ + if(scalar(fA,fB,a,b)>scalar(fA,fB,b,c) && scalar(bA,bB,a,b)>scalar(bA,bB,b,c)){ + if(distance(fA,b,c)<distance(fB,b,c)){ + p = fA; + q = fB; + } + else{ + p = fB; + q = fA; + } + + if(distance(bA,b,c)<distance(bB,b,c)){ + r = bA; + s = bB; + } + else{ + r = bB; + s = bA; + } + + c1 = linked(b,p); + c2 = linked(c,p); + c3 = linked(p,q); + c4 = linked(a,q); + c5 = linked(d,q); + + c6 = linked(b,r); + c7 = linked(c,r); + c8 = linked(r,s); + c9 = linked(a,s); + c10 = linked(d,s); + + if(c1 && c2 && c3 && c4 && c5 && c6 && c7 && c8 && c9 && c10){ + hex = new Hex(p,c,r,b,q,d,s,a); + quality = min_scaled_jacobian(*hex); + hex->set_quality(quality); + if(valid(*hex)){ + potential.push_back(hex); + } + else delete hex; + } + } + else if(scalar(fA,fB,a,b)<=scalar(fA,fB,b,c) && scalar(bA,bB,a,b)<=scalar(bA,bB,b,c)){ + if(distance(fA,a,b)<distance(fB,a,b)){ + p = fA; + q = fB; + } + else{ + p = fB; + q = fA; + } + + if(distance(bA,a,b)<distance(bB,a,b)){ + r = bA; + s = bB; + } + else{ + r = bB; + s = bA; + } + + c1 = linked(b,p); + c2 = linked(a,p); + c3 = linked(p,q); + c4 = linked(c,q); + c5 = linked(d,q); + + c6 = linked(b,r); + c7 = linked(a,r); + c8 = linked(r,s); + c9 = linked(c,s); + c10 = linked(d,s); + + if(c1 && c2 && c3 && c4 && c5 && c6 && c7 && c8 && c9 && c10){ + hex = new Hex(p,b,r,a,q,c,s,d); + quality = min_scaled_jacobian(*hex); + hex->set_quality(quality); + if(valid(*hex)){ + potential.push_back(hex); + } + else delete hex; + } + } + } + } + } +} + +void Recombinator::merge(GRegion* gr){ + unsigned int i; + int count; + bool flag; + double threshold; + double quality; + MVertex *a,*b,*c,*d; + MVertex *e,*f,*g,*h; + MElement* element; + std::set<MElement*> parts; + std::vector<MTetrahedron*> opt; + std::set<MElement*>::iterator it; + std::map<MElement*,bool>::iterator it2; + Hex *hex; + + count = 1; + quality = 0.0; + + for(i=0;i<potential.size();i++){ + hex = potential[i]; + + threshold = 0.25; + if(hex->get_quality()<threshold){ + break; + } + + a = hex->get_a(); + b = hex->get_b(); + c = hex->get_c(); + d = hex->get_d(); + e = hex->get_e(); + f = hex->get_f(); + g = hex->get_g(); + h = hex->get_h(); + + parts.clear(); + find(a,*hex,parts); + find(b,*hex,parts); + find(c,*hex,parts); + find(d,*hex,parts); + find(e,*hex,parts); + find(f,*hex,parts); + find(g,*hex,parts); + find(h,*hex,parts); + + flag = 1; + // bool found_used_sliver=false; + for(it=parts.begin();it!=parts.end();it++){ + element = *it; + it2 = markings.find(element); + // if(it2->second==1 && sliver(element,*hex)){ + // found_used_sliver=true; + // } + if(it2->second==1 && !sliver(element,*hex)){ + flag = 0; + break; + } + } + if(!flag) continue; + + if(!valid(*hex,parts)){ + continue; + } + + if(!conformityA(*hex)){ + continue; + } + + if(!conformityB(*hex)){ + continue; + } + + if(!conformityC(*hex)){ + continue; + } + + if(!faces_statuquo(*hex)){ + continue; + } + + // if (found_used_sliver){ + // cout << " ************************************* a used sliver passed the tests !!!!! " << endl; + // } + + //printf("%d - %d/%d - %f\n",count,i,(int)potential.size(),hex.get_quality()); + quality = quality + hex->get_quality(); + for(it=parts.begin();it!=parts.end();it++){ + element = *it; + it2 = markings.find(element); + it2->second = 1; + } + gr->addHexahedron(new MHexahedron(a,b,c,d,e,f,g,h)); + build_hash_tableA(*hex); + build_hash_tableB(*hex); + build_hash_tableC(*hex); + count++; + } + + opt.clear(); + opt.resize(gr->tetrahedra.size()); + opt = gr->tetrahedra; + gr->tetrahedra.clear(); + + for(i=0;i<opt.size();i++){ + element = (MElement*)(opt[i]); + it2 = markings.find(element); + if(it2->second==0){ + gr->tetrahedra.push_back(opt[i]); + } + } + + printf("hexahedra average quality (0->1) : %f\n",quality/count); +} + +void Recombinator::improved_merge(GRegion* gr){ + unsigned int i; + int count; + bool flag; + double threshold; + double quality; + MVertex *a,*b,*c,*d; + MVertex *e,*f,*g,*h; + MElement* element; + std::set<MElement*> parts; + std::vector<MTetrahedron*> opt; + std::set<MElement*>::iterator it; + std::map<MElement*,bool>::iterator it2; + std::vector<MTetrahedron*>::iterator it3; + Hex *hex; + + count = 1; + quality = 0.0; + + for(i=0;i<potential.size();i++){ + hex = potential[i]; + + threshold = 0.25; + if(hex->get_quality()<threshold){ + break; + } + + a = hex->get_a(); + b = hex->get_b(); + c = hex->get_c(); + d = hex->get_d(); + e = hex->get_e(); + f = hex->get_f(); + g = hex->get_g(); + h = hex->get_h(); + + parts.clear(); + find(a,*hex,parts); + find(b,*hex,parts); + find(c,*hex,parts); + find(d,*hex,parts); + find(e,*hex,parts); + find(f,*hex,parts); + find(g,*hex,parts); + find(h,*hex,parts); + + flag = 1; + for(it=parts.begin();it!=parts.end();it++){ + element = *it; + it2 = markings.find(element); + if(it2->second==1 && !sliver(element,*hex)){ + flag = 0; + break; + } + } + if(!flag) continue; + + if(!valid(*hex,parts)){ + continue; + } + + if(!conformityA(*hex)){ + continue; + } + + if(!conformityB(*hex)){ + continue; + } + + if(!conformityC(*hex)){ + continue; + } + + //printf("%d - %d/%d - %f\n",count,i,(int)potential->size(),hex->get_quality()); + quality = quality + hex->get_quality(); + for(it=parts.begin();it!=parts.end();it++){ + element = *it; + it2 = markings.find(element); + it2->second = 1; + } + gr->addHexahedron(new MHexahedron(a,b,c,d,e,f,g,h)); + build_hash_tableA(*hex); + build_hash_tableB(*hex); + build_hash_tableC(*hex); + count++; + } + + opt.clear(); + opt.resize(gr->tetrahedra.size()); + opt = gr->tetrahedra; + gr->tetrahedra.clear(); + + for(i=0;i<opt.size();i++){ + element = (MElement*)(opt[i]); + it2 = markings.find(element); + if(it2->second==0){ + gr->tetrahedra.push_back(opt[i]); + } + } + + printf("hexahedra average quality (0->1) : %f\n",quality/count); +} + +void Recombinator::rearrange(GRegion* gr){ + size_t i; + MElement* element; + + for(i=0;i<gr->getNumMeshElements();i++){ + element = gr->getMeshElement(i); + element->setVolumePositive(); + } +} + +void Recombinator::statistics(GRegion* gr){ + size_t i; + int all_nbr,hex_nbr; + double all_volume,hex_volume,volume; + MElement* element; + + all_nbr = 0; + hex_nbr = 0; + all_volume = 0.0; + hex_volume = 0.0; + + for(i=0;i<gr->getNumMeshElements();i++){ + element = gr->getMeshElement(i); + volume = element->getVolume(); + + if(element->getNumVertices()==8){ + hex_nbr = hex_nbr + 1; + hex_volume = hex_volume + volume; + } + + all_nbr = all_nbr + 1; + all_volume = all_volume + volume; + } + + printf("percentage of hexahedra (number) : %.2f\n",hex_nbr*100.0/all_nbr); + printf("percentage of hexahedra (volume) : %.2f\n",hex_volume*100.0/all_volume); +} + +void Recombinator::build_tuples(GRegion* gr){ + unsigned int i; + MVertex *a,*b,*c; + MElement* element; + GFace* gf; + std::list<GFace*> faces; + std::list<GFace*>::iterator it; + + tuples.clear(); + triangles.clear(); + faces.clear(); + + faces = gr->faces(); + + for(it=faces.begin();it!=faces.end();it++) + { + gf = *it; + + for(i=0;i<gf->getNumMeshElements();i++){ + element = gf->getMeshElement(i); + + if(element->getNumVertices()==3){ + a = element->getVertex(0); + b = element->getVertex(1); + c = element->getVertex(2); + + tuples.insert(Tuple(a,b,c,element,gf)); + } + } + } +} + +void Recombinator::modify_surfaces(GRegion* gr){ + unsigned int i; + MVertex *a,*b,*c,*d; + MVertex *e,*f,*g,*h; + MElement* element; + GFace* gf; + std::list<GFace*> faces; + std::vector<MElement*> opt; + std::list<GFace*>::iterator it; + std::set<MElement*>::iterator it2; + + for(i=0;i<gr->getNumMeshElements();i++){ + element = gr->getMeshElement(i); + + if(element->getNumVertices()==8){ + a = element->getVertex(0); + b = element->getVertex(1); + c = element->getVertex(2); + d = element->getVertex(3); + e = element->getVertex(4); + f = element->getVertex(5); + g = element->getVertex(6); + h = element->getVertex(7); + + modify_surfaces(a,b,c,d); + modify_surfaces(e,f,g,h); + modify_surfaces(a,e,h,d); + modify_surfaces(b,f,g,c); + modify_surfaces(a,e,f,b); + modify_surfaces(d,h,g,c); + } + } + + faces = gr->faces(); + + for(it=faces.begin();it!=faces.end();it++) + { + gf = *it; + + opt.clear(); + + for(i=0;i<gf->getNumMeshElements();i++){ + element = gf->getMeshElement(i); + + if(element->getNumVertices()==3){ + it2 = triangles.find(element); + if(it2==triangles.end()){ + opt.push_back(element); + } + } + } + + gf->triangles.clear(); + + for(i=0;i<opt.size();i++){ + gf->triangles.push_back((MTriangle*)opt[i]); + } + } +} + +void Recombinator::modify_surfaces(MVertex* a,MVertex* b,MVertex* c,MVertex* d){ + bool flag1,flag2; + MElement *element1,*element2; + GFace *gf1;//,*gf2; + Tuple tuple1,tuple2; + std::multiset<Tuple>::iterator it1; + std::multiset<Tuple>::iterator it2; + + gf1 = NULL; + //gf2 = NULL; + + tuple1 = Tuple(a,b,c); + tuple2 = Tuple(c,d,a); + + it1 = tuples.find(tuple1); + it2 = tuples.find(tuple2); + + flag1 = 0; + flag2 = 0; + + while(it1!=tuples.end()){ + if(tuple1.get_hash()!=it1->get_hash()){ + break; + } + + if(tuple1.same_vertices(*it1)){ + flag1 = 1; + element1 = it1->get_element(); + gf1 = it1->get_gf(); + } + + it1++; + } + + while(it2!=tuples.end()){ + if(tuple2.get_hash()!=it2->get_hash()){ + break; + } + + if(tuple2.same_vertices(*it2)){ + flag2 = 1; + element2 = it2->get_element(); + //gf2 = it2->get_gf(); + } + + it2++; + } + + if(flag1 && flag2){ + triangles.insert(element1); + triangles.insert(element2); + + gf1->addQuadrangle(new MQuadrangle(a,b,c,d)); + } + + tuple1 = Tuple(a,b,d); + tuple2 = Tuple(b,c,d); + + it1 = tuples.find(tuple1); + it2 = tuples.find(tuple2); + + flag1 = 0; + flag2 = 0; + + while(it1!=tuples.end()){ + if(tuple1.get_hash()!=it1->get_hash()){ + break; + } + + if(tuple1.same_vertices(*it1)){ + flag1 = 1; + element1 = it1->get_element(); + gf1 = it1->get_gf(); + } + + it1++; + } + + while(it2!=tuples.end()){ + if(tuple2.get_hash()!=it2->get_hash()){ + break; + } + + if(tuple2.same_vertices(*it2)){ + flag2 = 1; + element2 = it2->get_element(); + //gf2 = it2->get_gf(); + } + + it2++; + } + + if(flag1 && flag2){ + triangles.insert(element1); + triangles.insert(element2); + + gf1->addQuadrangle(new MQuadrangle(a,b,c,d)); + } +} + +bool Recombinator::sliver(MElement* element,Hex &hex){ + bool val; + bool flag1,flag2,flag3,flag4; + MVertex *a,*b,*c,*d; + + val = 0; + a = element->getVertex(0); + b = element->getVertex(1); + c = element->getVertex(2); + d = element->getVertex(3); + + flag1 = inclusion(a,hex.get_a(),hex.get_b(),hex.get_c(),hex.get_d()); + flag2 = inclusion(b,hex.get_a(),hex.get_b(),hex.get_c(),hex.get_d()); + flag3 = inclusion(c,hex.get_a(),hex.get_b(),hex.get_c(),hex.get_d()); + flag4 = inclusion(d,hex.get_a(),hex.get_b(),hex.get_c(),hex.get_d()); + if(flag1 && flag2 && flag3 && flag4) val = 1; + + flag1 = inclusion(a,hex.get_e(),hex.get_f(),hex.get_g(),hex.get_h()); + flag2 = inclusion(b,hex.get_e(),hex.get_f(),hex.get_g(),hex.get_h()); + flag3 = inclusion(c,hex.get_e(),hex.get_f(),hex.get_g(),hex.get_h()); + flag4 = inclusion(d,hex.get_e(),hex.get_f(),hex.get_g(),hex.get_h()); + if(flag1 && flag2 && flag3 && flag4) val = 1; + + flag1 = inclusion(a,hex.get_a(),hex.get_b(),hex.get_e(),hex.get_f()); + flag2 = inclusion(b,hex.get_a(),hex.get_b(),hex.get_e(),hex.get_f()); + flag3 = inclusion(c,hex.get_a(),hex.get_b(),hex.get_e(),hex.get_f()); + flag4 = inclusion(d,hex.get_a(),hex.get_b(),hex.get_e(),hex.get_f()); + if(flag1 && flag2 && flag3 && flag4) val = 1; + + flag1 = inclusion(a,hex.get_b(),hex.get_c(),hex.get_g(),hex.get_f()); + flag2 = inclusion(b,hex.get_b(),hex.get_c(),hex.get_g(),hex.get_f()); + flag3 = inclusion(c,hex.get_b(),hex.get_c(),hex.get_g(),hex.get_f()); + flag4 = inclusion(d,hex.get_b(),hex.get_c(),hex.get_g(),hex.get_f()); + if(flag1 && flag2 && flag3 && flag4) val = 1; + + flag1 = inclusion(a,hex.get_c(),hex.get_d(),hex.get_g(),hex.get_h()); + flag2 = inclusion(b,hex.get_c(),hex.get_d(),hex.get_g(),hex.get_h()); + flag3 = inclusion(c,hex.get_c(),hex.get_d(),hex.get_g(),hex.get_h()); + flag4 = inclusion(d,hex.get_c(),hex.get_d(),hex.get_g(),hex.get_h()); + if(flag1 && flag2 && flag3 && flag4) val = 1; + + flag1 = inclusion(a,hex.get_a(),hex.get_d(),hex.get_e(),hex.get_h()); + flag2 = inclusion(b,hex.get_a(),hex.get_d(),hex.get_e(),hex.get_h()); + flag3 = inclusion(c,hex.get_a(),hex.get_d(),hex.get_e(),hex.get_h()); + flag4 = inclusion(d,hex.get_a(),hex.get_d(),hex.get_e(),hex.get_h()); + if(flag1 && flag2 && flag3 && flag4) val = 1; + + return val; +} + +double Recombinator::diagonal(MElement* element,int& index1,int& index2){ + double max; + double l1,l2,l3,l4,l5,l6; + MVertex *a,*b,*c,*d; + + a = element->getVertex(0); + b = element->getVertex(1); + c = element->getVertex(2); + d = element->getVertex(3); + + max = 1000000.0; + l1 = distance(a,b); + l2 = distance(a,c); + l3 = distance(a,d); + l4 = distance(b,c); + l5 = distance(c,d); + l6 = distance(d,b); + + if(l1>=l2 && l1>=l3 && l1>=l4 && l1>=l5 && l1>=l6){ + index1 = 0; + index2 = 1; + max = l1; + } + else if(l2>=l1 && l2>=l3 && l2>=l4 && l2>=l5 && l2>=l6){ + index1 = 0; + index2 = 2; + max = l2; + } + else if(l3>=l1 && l3>=l2 && l3>=l4 && l3>=l5 && l3>=l6){ + index1 = 0; + index2 = 3; + max = l3; + } + else if(l4>=l1 && l4>=l2 && l4>=l3 && l4>=l5 && l4>=l6){ + index1 = 1; + index2 = 2; + max = l4; + } + else if(l5>=l1 && l5>=l2 && l5>=l3 && l5>=l4 && l5>=l6){ + index1 = 2; + index2 = 3; + max = l5; + } + else if(l6>=l1 && l6>=l2 && l6>=l3 && l6>=l4 && l6>=l5){ + index1 = 3; + index2 = 1; + max = l6; + } + + return max; +} + +double Recombinator::distance(MVertex* v1,MVertex* v2){ + double val; + double x,y,z; + + x = v2->x() - v1->x(); + y = v2->y() - v1->y(); + z = v2->z() - v1->z(); + + val = sqrt(x*x + y*y + z*z); + return val; +} + +double Recombinator::distance(MVertex* v,MVertex* v1,MVertex* v2){ + double val; + double x,y,z; + + x = 0.5*(v2->x() + v1->x()) - v->x(); + y = 0.5*(v2->y() + v1->y()) - v->y(); + z = 0.5*(v2->z() + v1->z()) - v->z(); + + val = sqrt(x*x + y*y + z*z); + return val; +} + +double Recombinator::scalar(MVertex* v1,MVertex* v2,MVertex* v3,MVertex* v4){ + double val; + double l1,l2; + SVector3 vec1,vec2; + + vec1 = SVector3(v2->x()-v1->x(),v2->y()-v1->y(),v2->z()-v1->z()); + vec2 = SVector3(v4->x()-v3->x(),v4->y()-v3->y(),v4->z()-v3->z()); + + l1 = vec1.norm(); + l2 = vec2.norm(); + + val = dot(vec1,vec2); + return fabs(val)/(l1*l2); +} + +void Recombinator::two_others(int index1,int index2,int& index3,int& index4){ + int i; + + for(i=0;i<4;i++){ + if(i!=index1 && i!=index2){ + index3 = i; + break; + } + } + + for(i=0;i<4;i++){ + if(i!=index1 && i!=index2 && i!=index3){ + index4 = i; + break; + } + } +} + + +// soit une face du cube: abcd +// en principe, on doit avoir soit les facets (abc) et (acd), soit les facets (abd) et(bcd) qui sont inclues dans un des tets qui forment l'hex. +// si c'est le cas pour toutes les 6 faces de l'hex, return true. +// ce test permet probablement de virer les hex "avec des trous" (avec 8 noeuds ok, mais un tet manquant, ce qui peut occasionner un hex à 14 faces, par exemple, si l'on compte les faces à partir des tets inclus) +bool Recombinator::valid(Hex &hex,const std::set<MElement*>& parts){ bool ok1,ok2,ok3; bool ok4,ok5,ok6; bool flag1A,flag1B,flag1C,flag1D; bool flag2A,flag2B,flag2C,flag2D; bool flag3A,flag3B,flag3C,flag3D; - bool flag4A,flag4B,flag4C,flag4D; - bool flag5A,flag5B,flag5C,flag5D; - bool flag6A,flag6B,flag6C,flag6D; - MVertex *a,*b,*c,*d; - MVertex *e,*f,*g,*h; + bool flag4A,flag4B,flag4C,flag4D; + bool flag5A,flag5B,flag5C,flag5D; + bool flag6A,flag6B,flag6C,flag6D; + MVertex *a,*b,*c,*d; + MVertex *e,*f,*g,*h; + + a = hex.get_a(); + b = hex.get_b(); + c = hex.get_c(); + d = hex.get_d(); + e = hex.get_e(); + f = hex.get_f(); + g = hex.get_g(); + h = hex.get_h(); + + flag1A = inclusion(a,b,c,parts); + flag1B = inclusion(a,c,d,parts); + flag1C = inclusion(b,c,d,parts); + flag1D = inclusion(a,b,d,parts); + ok1 = (flag1A && flag1B) || (flag1C && flag1D); + + flag2A = inclusion(e,f,g,parts); + flag2B = inclusion(e,g,h,parts); + flag2C = inclusion(f,g,h,parts); + flag2D = inclusion(e,f,h,parts); + ok2 = (flag2A && flag2B) || (flag2C && flag2D); + + flag3A = inclusion(a,b,f,parts); + flag3B = inclusion(a,f,e,parts); + flag3C = inclusion(b,e,f,parts); + flag3D = inclusion(a,b,e,parts); + ok3 = (flag3A && flag3B) || (flag3C && flag3D); + + flag4A = inclusion(b,c,g,parts); + flag4B = inclusion(b,g,f,parts); + flag4C = inclusion(c,g,f,parts); + flag4D = inclusion(b,c,f,parts); + ok4 = (flag4A && flag4B) || (flag4C && flag4D); + + flag5A = inclusion(c,d,g,parts); + flag5B = inclusion(d,g,h,parts); + flag5C = inclusion(c,g,h,parts); + flag5D = inclusion(c,d,h,parts); + ok5 = (flag5A && flag5B) || (flag5C && flag5D); + + flag6A = inclusion(a,d,h,parts); + flag6B = inclusion(a,e,h,parts); + flag6C = inclusion(d,e,h,parts); + flag6D = inclusion(a,d,e,parts); + ok6 = (flag6A && flag6B) || (flag6C && flag6D); + + if(ok1 && ok2 && ok3 && ok4 && ok5 && ok6){ + return 1; + } + else{ + return 0; + } +} + +// renvoie true si le "MQuadrangle::etaShapeMeasure" des 6 faces est plus grand que 0.000001 +bool Recombinator::valid(Hex &hex){ + double k; + double eta1,eta2,eta3; + double eta4,eta5,eta6; + MVertex *a,*b,*c,*d; + MVertex *e,*f,*g,*h; + + k = 0.000001; + + a = hex.get_a(); + b = hex.get_b(); + c = hex.get_c(); + d = hex.get_d(); + e = hex.get_e(); + f = hex.get_f(); + g = hex.get_g(); + h = hex.get_h(); + + eta1 = eta(a,b,c,d); + eta2 = eta(e,f,g,h); + eta3 = eta(a,b,f,e); + eta4 = eta(b,c,g,f); + eta5 = eta(d,a,e,h); + eta6 = eta(d,c,g,h); + + if(eta1>k && eta2>k && eta3>k && eta4>k && eta5>k && eta6>k){ + return 1; + } + else{ + return 0; + } +} + +double Recombinator::eta(MVertex* a,MVertex* b,MVertex* c,MVertex* d){ + double val; + MQuadrangle* quad; + + quad = new MQuadrangle(a,b,c,d); + val = quad->etaShapeMeasure(); + delete quad; + return val; +} + +bool Recombinator::linked(MVertex* v1,MVertex* v2){ + bool flag; + std::map<MVertex*,std::set<MVertex*> >::iterator it; + std::set<MVertex*>::iterator it2; + + it = vertex_to_vertices.find(v1); + flag = 0; + + for(it2=(it->second).begin();it2!=(it->second).end();it2++){ + if(*it2==v2){ + flag = 1; + break; + } + } + + return flag; +} + +void Recombinator::find(MVertex* v1,MVertex* v2,const std::vector<MVertex*>& already,std::set<MVertex*>& final){ + std::map<MVertex*,std::set<MVertex*> >::iterator it1; + std::map<MVertex*,std::set<MVertex*> >::iterator it2; + + it1 = vertex_to_vertices.find(v1); + it2 = vertex_to_vertices.find(v2); + + intersection(it1->second,it2->second,already,final); +} + +void Recombinator::find(MVertex* v1,MVertex* v2,MVertex* v3,const std::vector<MVertex*>& already,std::set<MVertex*>& final){ + std::map<MVertex*,std::set<MVertex*> >::iterator it1; + std::map<MVertex*,std::set<MVertex*> >::iterator it2; + std::map<MVertex*,std::set<MVertex*> >::iterator it3; + + it1 = vertex_to_vertices.find(v1); + it2 = vertex_to_vertices.find(v2); + it3 = vertex_to_vertices.find(v3); + + intersection(it1->second,it2->second,it3->second,already,final); +} + +void Recombinator::find(MVertex* v1,MVertex* v2,std::set<MElement*>& final){ + std::map<MVertex*,std::set<MElement*> >::iterator it1; + std::map<MVertex*,std::set<MElement*> >::iterator it2; + + it1 = vertex_to_elements.find(v1); + it2 = vertex_to_elements.find(v2); + + intersection(it1->second,it2->second,final); +} + +void Recombinator::find(MVertex* vertex,Hex hex,std::set<MElement*>& final){ + bool flag1,flag2,flag3,flag4; + MVertex *a,*b,*c,*d; + std::map<MVertex*,std::set<MElement*> >::iterator it; + std::set<MElement*>::iterator it2; + + it = vertex_to_elements.find(vertex); + + for(it2=(it->second).begin();it2!=(it->second).end();it2++){ + a = (*it2)->getVertex(0); + b = (*it2)->getVertex(1); + c = (*it2)->getVertex(2); + d = (*it2)->getVertex(3); + + flag1 = inclusion(a,hex); + flag2 = inclusion(b,hex); + flag3 = inclusion(c,hex); + flag4 = inclusion(d,hex); + + if(flag1 && flag2 && flag3 && flag4){ + final.insert(*it2); + } + } +} + +MVertex* Recombinator::find(MVertex* v1,MVertex* v2,MVertex* v3,MVertex* already,const std::set<MElement*>& bin){ + bool flag1,flag2,flag3,flag4; + MElement* element; + MVertex *a,*b,*c,*d; + MVertex* pointer; + std::set<MElement*>::const_iterator it; + + pointer = 0; + + for(it=bin.begin();it!=bin.end();it++){ + element = *it; + + a = element->getVertex(0); + b = element->getVertex(1); + c = element->getVertex(2); + d = element->getVertex(3); + + flag1 = inclusion(v1,a,b,c,d); + flag2 = inclusion(v2,a,b,c,d); + flag3 = inclusion(v3,a,b,c,d); + flag4 = inclusion(already,a,b,c,d); + + if(flag1 && flag2 && flag3 && !flag4){ + if(a!=v1 && a!=v2 && a!=v3){ + pointer = a; + } + else if(b!=v1 && b!=v2 && b!=v3){ + pointer = b; + } + else if(c!=v1 && c!=v2 && c!=v3){ + pointer = c; + } + else{ + pointer = d; + } + break; + } + } + + return pointer; +} + +void Recombinator::intersection(const std::set<MVertex*>& bin1,const std::set<MVertex*>& bin2, + const std::vector<MVertex*>& already,std::set<MVertex*>& final){ + size_t i; + bool ok; + std::set<MVertex*> temp; + std::set<MVertex*>::iterator it; + + std::set_intersection(bin1.begin(),bin1.end(),bin2.begin(),bin2.end(),std::inserter(temp,temp.end())); + + for(it=temp.begin();it!=temp.end();it++){ + ok = 1; + + for(i=0;i<already.size();i++){ + if((*it)==already[i]){ + ok = 0; + break; + } + } + + if(ok){ + final.insert(*it); + } + } +} + +void Recombinator::intersection(const std::set<MVertex*>& bin1,const std::set<MVertex*>& bin2,const std::set<MVertex*>& bin3, + const std::vector<MVertex*>& already,std::set<MVertex*>& final){ + size_t i; + bool ok; + std::set<MVertex*> temp; + std::set<MVertex*> temp2; + std::set<MVertex*>::iterator it; + + std::set_intersection(bin1.begin(),bin1.end(),bin2.begin(),bin2.end(),std::inserter(temp,temp.end())); + std::set_intersection(temp.begin(),temp.end(),bin3.begin(),bin3.end(),std::inserter(temp2,temp2.end())); + + for(it=temp2.begin();it!=temp2.end();it++){ + ok = 1; + + for(i=0;i<already.size();i++){ + if((*it)==already[i]){ + ok = 0; + break; + } + } + + if(ok){ + final.insert(*it); + } + } +} + +void Recombinator::intersection(const std::set<MElement*>& bin1,const std::set<MElement*>& bin2,std::set<MElement*>& final){ + std::set_intersection(bin1.begin(),bin1.end(),bin2.begin(),bin2.end(),std::inserter(final,final.end())); +} + +// return true if vertex belong to hex +bool Recombinator::inclusion(MVertex* vertex,Hex hex){ + bool flag; + + flag = 0; + + if(vertex==hex.get_a()) flag = 1; + else if(vertex==hex.get_b()) flag = 1; + else if(vertex==hex.get_c()) flag = 1; + else if(vertex==hex.get_d()) flag = 1; + else if(vertex==hex.get_e()) flag = 1; + else if(vertex==hex.get_f()) flag = 1; + else if(vertex==hex.get_g()) flag = 1; + else if(vertex==hex.get_h()) flag = 1; + + return flag; +} + +// pfffffff... renvoie true si vertex se trouve dans [a,b,c] +// en gros, return (abcd.find(vertex)!=abcd.end()); +bool Recombinator::inclusion(MVertex* vertex,MVertex* a,MVertex* b,MVertex* c,MVertex* d){ + bool flag; + + flag = 0; + + if(vertex==a) flag = 1; + else if(vertex==b) flag = 1; + else if(vertex==c) flag = 1; + else if(vertex==d) flag = 1; + + return flag; +} + + +// return true if all three vertices v1,v2 and v3 belong to one tet +// on pourrait plutot faire: est-ce que la face (v1v2v3) fait partie d'un tet, avec l'info hashée de tet to triangle ??? +bool Recombinator::inclusion(MVertex* v1,MVertex* v2,MVertex* v3,const std::set<MElement*>& bin){ + bool ok; + bool flag1,flag2,flag3; + MVertex *a,*b,*c,*d; + MElement* element; + std::set<MElement*>::const_iterator it; + + ok = 0; + + for(it=bin.begin();it!=bin.end();it++){ + element = *it; + + a = element->getVertex(0); + b = element->getVertex(1); + c = element->getVertex(2); + d = element->getVertex(3); + + flag1 = inclusion(v1,a,b,c,d); + flag2 = inclusion(v2,a,b,c,d); + flag3 = inclusion(v3,a,b,c,d); + + if(flag1 && flag2 && flag3){ + ok = 1; + break; + } + } + + return ok; +} + +// return true si la facet existe dans la table A +bool Recombinator::inclusion(Facet facet){ + bool flag; + std::multiset<Facet>::iterator it; + + it = hash_tableA.find(facet); + flag = 0; + + while(it!=hash_tableA.end()){ + if(facet.get_hash()!=it->get_hash()){ + break; + } + + if(facet.same_vertices(*it)){ + flag = 1; + break; + } + + it++; + } + + return flag; +} + +bool Recombinator::inclusion(Diagonal diagonal){ + bool flag; + std::multiset<Diagonal>::iterator it; + + it = hash_tableB.find(diagonal); + flag = 0; + + while(it!=hash_tableB.end()){ + if(diagonal.get_hash()!=it->get_hash()){ + break; + } + + if(diagonal.same_vertices(*it)){ + flag = 1; + break; + } + + it++; + } + + return flag; +} + +bool Recombinator::duplicate(Diagonal diagonal){ + bool flag; + std::multiset<Diagonal>::iterator it; + + it = hash_tableC.find(diagonal); + flag = 0; + + while(it!=hash_tableC.end()){ + if(diagonal.get_hash()!=it->get_hash()){ + break; + } + + if(diagonal.same_vertices(*it)){ + flag = 1; + break; + } + + it++; + } + + return flag; +} + +// return true si un hex est "conforme A" +// est "conforme A" un hex dont les 6 faces sont "conforme A" +// est "conforme A" une face si ses 4 facets existent dans tableA, ou bien si aucune des ses facets ne se trouve dans table A +// ça veut dire: un hex est condorme A s'il est tout seul. +// Sinon, s'il est pas tout seul, s'il a des "voisins de face"... il faut que les faces en contact soient bien en contact... pas juste un triangle en commun, mais il faut un QUAD en commun ! +// ne pouvait-on pas écrire ça avec des quad, du coup ??? +// ça veut dire que pour les slivers, qu'ils soient ou pas dans l'hex, dans tous les cas, les hex sont compatibles ! +bool Recombinator::conformityA(Hex &hex){ + bool c1,c2,c3,c4,c5,c6; + MVertex *a,*b,*c,*d; + MVertex *e,*f,*g,*h; + + a = hex.get_a(); + b = hex.get_b(); + c = hex.get_c(); + d = hex.get_d(); + e = hex.get_e(); + f = hex.get_f(); + g = hex.get_g(); + h = hex.get_h(); + + c1 = conformityA(a,b,c,d); + c2 = conformityA(e,f,g,h); + c3 = conformityA(a,b,f,e); + c4 = conformityA(b,c,g,f); + c5 = conformityA(d,c,g,h); + c6 = conformityA(d,a,e,h); + + return c1 && c2 && c3 && c4 && c5 && c6; +} + +bool Recombinator::conformityA(MVertex* a,MVertex* b,MVertex* c,MVertex* d){ + bool c1,c2,c3,c4; + + c1 = inclusion(Facet(a,b,c)); + c2 = inclusion(Facet(a,c,d)); + c3 = inclusion(Facet(a,b,d)); + c4 = inclusion(Facet(b,c,d)); + + // if (((c1 && c2 && c3 && c4) || (!c1 && !c2 && !c3 && !c4))==false){ + // // info si non conforme + // cout << " treating facet made of abcd: " << a->getNum() << " " << b->getNum() << " " << c->getNum() << " " << d->getNum() << endl; + // cout << "c1 (abc) connu: " << c1 << endl; + // cout << "c2 (acd) connu: " << c2 << endl; + // cout << "c3 (abd) connu: " << c3 << endl; + // cout << "c4 (bcd) connu: " << c4 << endl; + // } + + return (c1 && c2 && c3 && c4) || (!c1 && !c2 && !c3 && !c4); +} + +// return false si: +//- une des 12 arrêtes de l'hex se trouve dans tableB !!! (pas C !!!), cà d si une arrete a été utilisée comme diagonale d'un autre hex +//- (ou bien) si, pour chaque face de l'hex, on a une diagonale dans tableB et pas l'autre +// ce test conformityB n'est-il pas redondant avec conformityA ??? +bool Recombinator::conformityB(Hex &hex){ + bool flag1; + bool flag2; + bool c1,c2,c3,c4; + bool c5,c6,c7,c8; + bool c9,c10,c11,c12; + MVertex *a,*b,*c,*d; + MVertex *e,*f,*g,*h; + + a = hex.get_a(); + b = hex.get_b(); + c = hex.get_c(); + d = hex.get_d(); + e = hex.get_e(); + f = hex.get_f(); + g = hex.get_g(); + h = hex.get_h(); + + flag1 = inclusion(Diagonal(a,b)); + flag1 = flag1 || inclusion(Diagonal(b,f)); + flag1 = flag1 || inclusion(Diagonal(f,e)); + flag1 = flag1 || inclusion(Diagonal(e,a)); + flag1 = flag1 || inclusion(Diagonal(d,c)); + flag1 = flag1 || inclusion(Diagonal(c,g)); + flag1 = flag1 || inclusion(Diagonal(g,h)); + flag1 = flag1 || inclusion(Diagonal(h,d)); + flag1 = flag1 || inclusion(Diagonal(b,c)); + flag1 = flag1 || inclusion(Diagonal(f,g)); + flag1 = flag1 || inclusion(Diagonal(e,h)); + flag1 = flag1 || inclusion(Diagonal(a,d)); + + c1 = inclusion(Diagonal(a,f)); + c2 = inclusion(Diagonal(b,e)); + flag2 = (c1 && !c2) || (!c1 && c2); + c3 = inclusion(Diagonal(d,g)); + c4 = inclusion(Diagonal(c,h)); + flag2 = flag2 || (c3 && !c4) || (!c3 && c4); + c5 = inclusion(Diagonal(b,g)); + c6 = inclusion(Diagonal(c,f)); + flag2 = flag2 || (c5 && !c6) || (!c5 && c6); + c7 = inclusion(Diagonal(e,g)); + c8 = inclusion(Diagonal(f,h)); + flag2 = flag2 || (c7 && !c8) || (!c7 && c8); + c9 = inclusion(Diagonal(a,h)); + c10 = inclusion(Diagonal(d,e)); + flag2 = flag2 || (c9 && !c10) || (!c9 && c10); + c11 = inclusion(Diagonal(a,c)); + c12 = inclusion(Diagonal(b,d)); + flag2 = flag2 || (c11 && !c12) || (!c11 && c12); + + if(flag1 || flag2){ + return 0; + } + else{ + return 1; + } +} + +// return false si une des 12 diagonales du cube se trouve dans tableC, cà d a été utilisée comme arrête +bool Recombinator::conformityC(Hex &hex){ + bool flag; + MVertex *a,*b,*c,*d; + MVertex *e,*f,*g,*h; + + a = hex.get_a(); + b = hex.get_b(); + c = hex.get_c(); + d = hex.get_d(); + e = hex.get_e(); + f = hex.get_f(); + g = hex.get_g(); + h = hex.get_h(); + + flag = duplicate(Diagonal(a,f)); + flag = flag || duplicate(Diagonal(b,e)); + flag = flag || duplicate(Diagonal(d,g)); + flag = flag || duplicate(Diagonal(c,h)); + flag = flag || duplicate(Diagonal(b,g)); + flag = flag || duplicate(Diagonal(c,f)); + flag = flag || duplicate(Diagonal(e,g)); + flag = flag || duplicate(Diagonal(f,h)); + flag = flag || duplicate(Diagonal(a,h)); + flag = flag || duplicate(Diagonal(d,e)); + flag = flag || duplicate(Diagonal(a,c)); + flag = flag || duplicate(Diagonal(b,d)); + + if(flag){ + return 0; + } + else{ + return 1; + } +} + +// return true si les 6 faces de l'hex sont "faces_statuquo" +bool Recombinator::faces_statuquo(Hex &hex){ + bool c1,c2,c3,c4,c5,c6; + MVertex *a,*b,*c,*d; + MVertex *e,*f,*g,*h; + + a = hex.get_a(); + b = hex.get_b(); + c = hex.get_c(); + d = hex.get_d(); + e = hex.get_e(); + f = hex.get_f(); + g = hex.get_g(); + h = hex.get_h(); + + c1 = faces_statuquo(a,b,c,d); + c2 = faces_statuquo(e,f,g,h); + c3 = faces_statuquo(a,b,f,e); + c4 = faces_statuquo(b,c,g,f); + c5 = faces_statuquo(d,c,g,h); + c6 = faces_statuquo(d,a,e,h); + + return c1 && c2 && c3 && c4 && c5 && c6; +} + +// return false si, parmis les deux paires de facets de la face, il existe un couple de facet qui soinent toutes les deux des tuples, mais correspondant à des geometric faces différentes. Bref, une arrête géométrique confondue avec une diagonale de la face. +bool Recombinator::faces_statuquo(MVertex* a,MVertex* b,MVertex* c,MVertex* d){ + bool ok; + bool flag1,flag2; + GFace *gf1,*gf2; + Tuple tuple1,tuple2; + std::multiset<Tuple>::iterator it1; + std::multiset<Tuple>::iterator it2; + + ok = 1; + + gf1 = NULL; + gf2 = NULL; + + tuple1 = Tuple(a,b,c); + tuple2 = Tuple(c,d,a); + + it1 = tuples.find(tuple1); + it2 = tuples.find(tuple2); + + flag1 = 0; + flag2 = 0; + + while(it1!=tuples.end()){ + if(tuple1.get_hash()!=it1->get_hash()){ + break; + } + + if(tuple1.same_vertices(*it1)){ + flag1 = 1; + gf1 = it1->get_gf(); + } + + it1++; + } + + while(it2!=tuples.end()){ + if(tuple2.get_hash()!=it2->get_hash()){ + break; + } + + if(tuple2.same_vertices(*it2)){ + flag2 = 1; + gf2 = it2->get_gf(); + } + + it2++; + } + + if(flag1 && flag2){// si on a trouvé les deux tuples (abc) et (cda) dans la liste des tuples + if(gf1!=gf2){// si les geometrical faces des deux tuples sont différentes + ok = 0; + } + } + + // on fait pareil pour l'autre paire de facets, abd et bcd + tuple1 = Tuple(a,b,d); + tuple2 = Tuple(b,c,d); + + it1 = tuples.find(tuple1); + it2 = tuples.find(tuple2); + + flag1 = 0; + flag2 = 0; + + while(it1!=tuples.end()){ + if(tuple1.get_hash()!=it1->get_hash()){ + break; + } + + if(tuple1.same_vertices(*it1)){ + flag1 = 1; + gf1 = it1->get_gf(); + } + + it1++; + } + + while(it2!=tuples.end()){ + if(tuple2.get_hash()!=it2->get_hash()){ + break; + } + + if(tuple2.same_vertices(*it2)){ + flag2 = 1; + gf2 = it2->get_gf(); + } + + it2++; + } + + if(flag1 && flag2){ + if(gf1!=gf2){ + ok = 0; + } + } + + return ok; +} + +void Recombinator::build_vertex_to_vertices(GRegion* gr){ + size_t i; + int j; + MElement* element; + MVertex *a,*b,*c,*d; + std::set<MVertex*> bin; + std::map<MVertex*,std::set<MVertex*> >::iterator it; + + cout << "... stage1, building vertex->vertices connectivity " << endl; + + vertex_to_vertices.clear(); + + int nbElements = gr->getNumMeshElements(); + double percentage=0.05; + double done=0.; + int progress = ceil(nbElements*percentage); + for(i=0;i<gr->getNumMeshElements();i++){ + if(i%progress==0){ + done += percentage*100; + cout << "..." << done << "% " << flush; + } + element = gr->getMeshElement(i); + for(j=0;j<element->getNumVertices();j++){ + a = element->getVertex(j); + b = element->getVertex((j+1)%4); + c = element->getVertex((j+2)%4); + d = element->getVertex((j+3)%4); + + it = vertex_to_vertices.find(a); + if(it!=vertex_to_vertices.end()){ + it->second.insert(b); + it->second.insert(c); + it->second.insert(d); + } + else{ + bin.clear(); + bin.insert(b); + bin.insert(c); + bin.insert(d); + vertex_to_vertices.insert(std::pair<MVertex*,std::set<MVertex*> >(a,bin)); + } + } + } + cout << endl; +} + +void Recombinator::build_vertex_to_elements(GRegion* gr){ + cout << "... stage2, building vertex->elements connectivity " << endl; + size_t i; + int j; + MElement* element; + MVertex* vertex; + std::set<MElement*> bin; + std::map<MVertex*,std::set<MElement*> >::iterator it; + + int nbElements = gr->getNumMeshElements(); + double percentage=0.05; + double done=0.; + int progress = ceil(nbElements*percentage); + + vertex_to_elements.clear(); + + for(i=0;i<gr->getNumMeshElements();i++){ + if(i%progress==0){ + done += percentage*100; + cout << "..." << done << "% " << flush; + } + element = gr->getMeshElement(i); + for(j=0;j<element->getNumVertices();j++){ + vertex = element->getVertex(j); + + it = vertex_to_elements.find(vertex); + if(it!=vertex_to_elements.end()){ + it->second.insert(element); + } + else{ + bin.clear(); + bin.insert(element); + vertex_to_elements.insert(std::pair<MVertex*,std::set<MElement*> >(vertex,bin)); + } + } + } + cout << endl; +} + +// pour les 6 faces de l'hex, stocke les 4 "facet" (équivalent à PETriangle) possibles dans la table A +void Recombinator::build_hash_tableA(Hex hex){ + MVertex *a,*b,*c,*d; + MVertex *e,*f,*g,*h; + + a = hex.get_a(); + b = hex.get_b(); + c = hex.get_c(); + d = hex.get_d(); + e = hex.get_e(); + f = hex.get_f(); + g = hex.get_g(); + h = hex.get_h(); + + build_hash_tableA(a,b,c,d); + build_hash_tableA(e,f,g,h); + build_hash_tableA(a,b,f,e); + build_hash_tableA(b,c,g,f); + build_hash_tableA(d,c,g,h); + build_hash_tableA(d,a,e,h); +} + +void Recombinator::build_hash_tableA(MVertex* a,MVertex* b,MVertex* c,MVertex* d){ + build_hash_tableA(Facet(a,b,c)); + build_hash_tableA(Facet(a,c,d)); + build_hash_tableA(Facet(a,b,d)); + build_hash_tableA(Facet(b,d,c)); +} + +void Recombinator::build_hash_tableA(Facet facet){ + bool flag; + std::multiset<Facet>::iterator it; + + it = hash_tableA.find(facet); + flag = 1; + + while(it!=hash_tableA.end()){ + if(facet.get_hash()!=it->get_hash()){ + break;// empoyer RANGE à la place ? + lisible ? + efficace ? + } + + if(facet.same_vertices(*it)){ + flag = 0; + break; + } + + it++; + } + + // à ce stade, flag==0 si facet existe dans la table + + if(flag){ + hash_tableA.insert(facet); + } +} + +// pour les 6 faces de l'hex, stoke les 2 "diagonal" possibles dans la table B +void Recombinator::build_hash_tableB(Hex hex){ + MVertex *a,*b,*c,*d; + MVertex *e,*f,*g,*h; + + a = hex.get_a(); + b = hex.get_b(); + c = hex.get_c(); + d = hex.get_d(); + e = hex.get_e(); + f = hex.get_f(); + g = hex.get_g(); + h = hex.get_h(); + + build_hash_tableB(a,b,c,d); + build_hash_tableB(e,f,g,h); + build_hash_tableB(a,b,f,e); + build_hash_tableB(b,c,g,f); + build_hash_tableB(d,c,g,h); + build_hash_tableB(d,a,e,h); +} + +void Recombinator::build_hash_tableB(MVertex* a,MVertex* b,MVertex* c,MVertex* d){ + build_hash_tableB(Diagonal(a,c)); + build_hash_tableB(Diagonal(b,d)); +} + +void Recombinator::build_hash_tableB(Diagonal diagonal){ + bool flag; + std::multiset<Diagonal>::iterator it; + + it = hash_tableB.find(diagonal); + flag = 1; + + while(it!=hash_tableB.end()){ + if(diagonal.get_hash()!=it->get_hash()){ + break; + } + + if(diagonal.same_vertices(*it)){ + flag = 0; + break; + } + + it++; + } + + if(flag){ + hash_tableB.insert(diagonal); + } +} + +// pour les 6 faces de l'hex, stoke les 12 arretes (aussi enregistrées comme "diagonal") possibles dans la table C +void Recombinator::build_hash_tableC(Hex hex){ + MVertex *a,*b,*c,*d; + MVertex *e,*f,*g,*h; + + a = hex.get_a(); + b = hex.get_b(); + c = hex.get_c(); + d = hex.get_d(); + e = hex.get_e(); + f = hex.get_f(); + g = hex.get_g(); + h = hex.get_h(); + + build_hash_tableC(Diagonal(a,b)); + build_hash_tableC(Diagonal(b,c)); + build_hash_tableC(Diagonal(c,d)); + build_hash_tableC(Diagonal(d,a)); + build_hash_tableC(Diagonal(e,f)); + build_hash_tableC(Diagonal(f,g)); + build_hash_tableC(Diagonal(g,h)); + build_hash_tableC(Diagonal(h,e)); + build_hash_tableC(Diagonal(a,e)); + build_hash_tableC(Diagonal(b,f)); + build_hash_tableC(Diagonal(c,g)); + build_hash_tableC(Diagonal(d,h)); +} + +void Recombinator::build_hash_tableC(Diagonal diagonal){ + bool flag; + std::multiset<Diagonal>::iterator it; + + it = hash_tableC.find(diagonal); + flag = 1; + + while(it!=hash_tableC.end()){ + if(diagonal.get_hash()!=it->get_hash()){ + break; + } + + if(diagonal.same_vertices(*it)){ + flag = 0; + break; + } + + it++; + } + + if(flag){ + hash_tableC.insert(diagonal); + } +} + +void Recombinator::print_vertex_to_vertices(GRegion* gr){ + size_t i; + int j; + SPoint3 p1,p2; + MElement* element; + MVertex* vertex; + std::map<MVertex*,std::set<MVertex*> >::iterator it; + std::set<MVertex*>::iterator it2; + + std::ofstream file("vertex_to_vertices.pos"); + file << "View \"test\" {\n"; + + for(i=0;i<gr->getNumMeshElements();i++){ + element = gr->getMeshElement(i); + for(j=0;j<element->getNumVertices();j++){ + vertex = element->getVertex(j); + p1 = SPoint3(vertex->x(),vertex->y(),vertex->z()); + it = vertex_to_vertices.find(vertex); + for(it2=(it->second).begin();it2!=(it->second).end();it2++){ + p2 = SPoint3((*it2)->x(),(*it2)->y(),(*it2)->z()); + print_segment(p1,p2,file); + } + } + } + file << "};\n"; +} + +void Recombinator::print_vertex_to_elements(GRegion* gr){ + size_t i; + int j; + MElement* element; + MVertex* vertex; + std::map<MVertex*,std::set<MElement*> >::iterator it; + std::map<MVertex*,std::set<MVertex*> >::iterator it2; + + for(i=0;i<gr->getNumMeshElements();i++){ + element = gr->getMeshElement(i); + for(j=0;j<element->getNumVertices();j++){ + vertex = element->getVertex(j); + it = vertex_to_elements.find(vertex); + it2 = vertex_to_vertices.find(vertex); + printf("%d %d\n",(int)(it->second).size(),(int)(it2->second).size()); + } + } +} + +void Recombinator::print_hash_tableA(){ + std::multiset<Facet>::iterator it; + + for(it=hash_tableA.begin();it!=hash_tableA.end();it++){ + printf("%lld\n",it->get_hash()); + } +} + +void Recombinator::print_segment(SPoint3 p1,SPoint3 p2,std::ofstream& file){ + file << "SL (" + << p1.x() << ", " << p1.y() << ", " << p1.z() << ", " + << p2.x() << ", " << p2.y() << ", " << p2.z() << ")" + << "{10, 20};\n"; +} + +double Recombinator::scaled_jacobian(MVertex* a,MVertex* b,MVertex* c,MVertex* d){ + double val; + double l1,l2,l3; + SVector3 vec1,vec2,vec3; + + vec1 = SVector3(b->x()-a->x(),b->y()-a->y(),b->z()-a->z()); + vec2 = SVector3(c->x()-a->x(),c->y()-a->y(),c->z()-a->z()); + vec3 = SVector3(d->x()-a->x(),d->y()-a->y(),d->z()-a->z()); + + l1 = vec1.norm(); + l2 = vec2.norm(); + l3 = vec3.norm(); + + val = dot(vec1,crossprod(vec2,vec3)); + return fabs(val)/(l1*l2*l3); +} + +double Recombinator::max_scaled_jacobian(MElement* element,int& index){ + double val; + double j1,j2,j3,j4; + MVertex *a,*b,*c,*d; + + a = element->getVertex(0); + b = element->getVertex(1); + c = element->getVertex(2); + d = element->getVertex(3); + + j1 = scaled_jacobian(a,b,c,d); + j2 = scaled_jacobian(b,c,d,a); + j3 = scaled_jacobian(c,d,a,b); + j4 = scaled_jacobian(d,a,b,c); + + if(j1>=j2 && j1>=j3 && j1>=j4){ + index = 0; + val = j1; + } + else if(j2>=j3 && j2>=j4 && j2>=j1){ + index = 1; + val = j2; + } + else if(j3>=j4 && j3>=j1 && j3>=j2){ + index = 2; + val = j3; + } + else{ + index = 3; + val = j4; + } + + return val; +} + +double Recombinator::min_scaled_jacobian(Hex &hex){ + int i; + double min; + double j1,j2,j3,j4,j5,j6,j7,j8; + MVertex *a,*b,*c,*d; + MVertex *e,*f,*g,*h; + std::vector<double> jacobians; + + a = hex.get_a(); + b = hex.get_b(); + c = hex.get_c(); + d = hex.get_d(); + e = hex.get_e(); + f = hex.get_f(); + g = hex.get_g(); + h = hex.get_h(); + + j1 = scaled_jacobian(a,b,d,e); + j2 = scaled_jacobian(b,a,c,f); + j3 = scaled_jacobian(c,b,d,g); + j4 = scaled_jacobian(d,a,c,h); + j5 = scaled_jacobian(e,a,f,h); + j6 = scaled_jacobian(f,b,e,g); + j7 = scaled_jacobian(g,c,f,h); + j8 = scaled_jacobian(h,d,e,g); + + jacobians.push_back(j1); + jacobians.push_back(j2); + jacobians.push_back(j3); + jacobians.push_back(j4); + jacobians.push_back(j5); + jacobians.push_back(j6); + jacobians.push_back(j7); + jacobians.push_back(j8); + + min = 1000000000.0; + for(i=0;i<8;i++){ + if(jacobians[i]<=min){ + min = jacobians[i]; + } + } + + return min; +} + +/*******************************************/ +/****************class Prism****************/ +/*******************************************/ + +Prism::Prism(){} + +Prism::Prism(MVertex* a2,MVertex* b2,MVertex* c2,MVertex* d2,MVertex* e2,MVertex* f2){ + a = a2; + b = b2; + c = c2; + d = d2; + e = e2; + f = f2; +} + +Prism::~Prism(){} + +double Prism::get_quality() const{ + return quality; +} + +void Prism::set_quality(double new_quality){ + quality = new_quality; +} + +MVertex* Prism::get_a(){ + return a; +} + +MVertex* Prism::get_b(){ + return b; +} + +MVertex* Prism::get_c(){ + return c; +} + +MVertex* Prism::get_d(){ + return d; +} + +MVertex* Prism::get_e(){ + return e; +} + +MVertex* Prism::get_f(){ + return f; +} + +void Prism::set_vertices(MVertex* a2,MVertex* b2,MVertex* c2,MVertex* d2,MVertex* e2,MVertex* f2){ + a = a2; + b = b2; + c = c2; + d = d2; + e = e2; + f = f2; +} + +bool Prism::operator<(const Prism& prism) const{ + return quality>prism.get_quality(); +} + +/***************************************************/ +/****************class Supplementary****************/ +/***************************************************/ + +Supplementary::Supplementary(){} + +Supplementary::~Supplementary(){} + +void Supplementary::execute(){ + GRegion* gr; + GModel* model = GModel::current(); + GModel::riter it; + + for(it=model->firstRegion();it!=model->lastRegion();it++) + { + gr = *it; + if(gr->getNumMeshElements()>0){ + execute(gr); + } + } +} + +void Supplementary::execute(GRegion* gr){ + unsigned int i; + MElement* element; + MVertex *a,*b,*c,*d; + MVertex *e,*f,*g,*h; + + printf("................PRISMS................\n"); + build_tuples(gr); + init_markings(gr); + + build_vertex_to_vertices(gr); + build_vertex_to_tetrahedra(gr); + printf("connectivity\n"); + + potential.clear(); + pattern(gr); + printf("pattern\n"); + + hash_tableA.clear(); + hash_tableB.clear(); + hash_tableC.clear(); + for(i=0;i<gr->getNumMeshElements();i++){ + element = gr->getMeshElement(i); + if(eight(element)){ + a = element->getVertex(0); + b = element->getVertex(1); + c = element->getVertex(2); + d = element->getVertex(3); + e = element->getVertex(4); + f = element->getVertex(5); + g = element->getVertex(6); + h = element->getVertex(7); + + build_hash_tableA(a,b,c,d); + build_hash_tableA(e,f,g,h); + build_hash_tableA(a,b,f,e); + build_hash_tableA(b,c,g,f); + build_hash_tableA(d,c,g,h); + build_hash_tableA(d,a,e,h); + + build_hash_tableB(a,b,c,d); + build_hash_tableB(e,f,g,h); + build_hash_tableB(a,b,f,e); + build_hash_tableB(b,c,g,f); + build_hash_tableB(d,c,g,h); + build_hash_tableB(d,a,e,h); + + build_hash_tableC(Diagonal(a,b)); + build_hash_tableC(Diagonal(b,c)); + build_hash_tableC(Diagonal(c,d)); + build_hash_tableC(Diagonal(d,a)); + build_hash_tableC(Diagonal(e,f)); + build_hash_tableC(Diagonal(f,g)); + build_hash_tableC(Diagonal(g,h)); + build_hash_tableC(Diagonal(h,e)); + build_hash_tableC(Diagonal(a,e)); + build_hash_tableC(Diagonal(b,f)); + build_hash_tableC(Diagonal(c,g)); + build_hash_tableC(Diagonal(d,h)); + } + } + + std::sort(potential.begin(),potential.end()); + + merge(gr); + + rearrange(gr); + + statistics(gr); + + modify_surfaces(gr); +} + +void Supplementary::init_markings(GRegion* gr){ + unsigned int i; + MElement* element; + + markings.clear(); + + for(i=0;i<gr->getNumMeshElements();i++){ + element = gr->getMeshElement(i); + if(four(element)){ + markings.insert(std::pair<MElement*,bool>(element,false)); + } + } +} + +void Supplementary::pattern(GRegion* gr){ + size_t i; + int j,k; + double quality; + MElement* element; + MVertex *a,*b,*c,*d; + MVertex *p,*q; + std::vector<MVertex*> vertices; + std::vector<MVertex*> already; + std::set<MVertex*> bin1; + std::set<MVertex*> bin2; + std::set<MVertex*>::iterator it1; + std::set<MVertex*>::iterator it2; + Prism prism; + + vertices.resize(3); + + for(i=0;i<gr->getNumMeshElements();i++){ + element = gr->getMeshElement(i); + if(four(element)){ + for(j=0;j<4;j++){ + a = element->getVertex(j); + vertices[0] = element->getVertex((j+1)%4); + vertices[1] = element->getVertex((j+2)%4); + vertices[2] = element->getVertex((j+3)%4); + for(k=0;k<3;k++){ + b = vertices[k%3]; + c = vertices[(k+1)%3]; + d = vertices[(k+2)%3]; + already.clear(); + already.push_back(a); + already.push_back(b); + already.push_back(c); + already.push_back(d); + bin1.clear(); + bin2.clear(); + find(b,d,already,bin1); + find(c,d,already,bin2); + for(it1=bin1.begin();it1!=bin1.end();it1++){ + p = *it1; + for(it2=bin2.begin();it2!=bin2.end();it2++){ + q = *it2; + if(p!=q && linked(p,q)){ + prism = Prism(a,b,c,d,p,q); + quality = min_scaled_jacobian(prism); + prism.set_quality(quality); + if(valid(prism)){ + potential.push_back(prism); + } + } + } + } + } + } + } + } +} + +void Supplementary::merge(GRegion* gr){ + unsigned int i; + int count; + bool flag; + double threshold; + double quality; + MVertex *a,*b,*c; + MVertex *d,*e,*f; + MElement* element; + std::set<MElement*> parts; + std::vector<MTetrahedron*> opt; + std::set<MElement*>::iterator it; + std::map<MElement*,bool>::iterator it2; + Prism prism; + + count = 1; + quality = 0.0; + + for(i=0;i<potential.size();i++){ + prism = potential[i]; + + threshold = 0.15; + if(prism.get_quality()<threshold){ + break; + } + + a = prism.get_a(); + b = prism.get_b(); + c = prism.get_c(); + d = prism.get_d(); + e = prism.get_e(); + f = prism.get_f(); + + parts.clear(); + find(a,prism,parts); + find(b,prism,parts); + find(c,prism,parts); + find(d,prism,parts); + find(e,prism,parts); + find(f,prism,parts); + + flag = 1; + for(it=parts.begin();it!=parts.end();it++){ + element = *it; + it2 = markings.find(element); + if(it2->second==1 && !sliver(element,prism)){ + flag = 0; + break; + } + } + if(!flag) continue; + + if(!valid(prism,parts)){ + continue; + } + + if(!conformityA(prism)){ + continue; + } + + if(!conformityB(prism)){ + continue; + } + + if(!conformityC(prism)){ + continue; + } + + if(!faces_statuquo(prism)){ + continue; + } + + //printf("%d - %d/%d - %f\n",count,i,(int)potential.size(),prism.get_quality()); + quality = quality + prism.get_quality(); + for(it=parts.begin();it!=parts.end();it++){ + element = *it; + it2 = markings.find(element); + it2->second = 1; + } + gr->addPrism(new MPrism(a,b,c,d,e,f)); + build_hash_tableA(prism); + build_hash_tableB(prism); + build_hash_tableC(prism); + count++; + } + + opt.clear(); + opt.resize(gr->tetrahedra.size()); + opt = gr->tetrahedra; + gr->tetrahedra.clear(); + + for(i=0;i<opt.size();i++){ + element = (MElement*)(opt[i]); + it2 = markings.find(element); + if(it2->second==0){ + gr->tetrahedra.push_back(opt[i]); + } + } + + printf("prisms average quality (0->1) : %f\n",quality/count); +} + +void Supplementary::rearrange(GRegion* gr){ + size_t i; + MElement* element; + + for(i=0;i<gr->getNumMeshElements();i++){ + element = gr->getMeshElement(i); + element->setVolumePositive(); + } +} + +void Supplementary::statistics(GRegion* gr){ + size_t i; + int all_nbr,prism_nbr; + double all_volume,prism_volume,volume; + MElement* element; + + all_nbr = 0; + prism_nbr = 0; + all_volume = 0.0; + prism_volume = 0.0; + + for(i=0;i<gr->getNumMeshElements();i++){ + element = gr->getMeshElement(i); + volume = element->getVolume(); + + if(six(element)){ + prism_nbr = prism_nbr + 1; + prism_volume = prism_volume + volume; + } + + all_nbr = all_nbr + 1; + all_volume = all_volume + volume; + } + + printf("percentage of prisms (number) : %.2f\n",prism_nbr*100.0/all_nbr); + printf("percentage of prisms (volume) : %.2f\n",prism_volume*100.0/all_volume); +} + +void Supplementary::build_tuples(GRegion* gr){ + unsigned int i; + MVertex *a,*b,*c; + MElement* element; + GFace* gf; + std::list<GFace*> faces; + std::list<GFace*>::iterator it; + + tuples.clear(); + triangles.clear(); + faces.clear(); + + faces = gr->faces(); + + for(it=faces.begin();it!=faces.end();it++) + { + gf = *it; + + for(i=0;i<gf->getNumMeshElements();i++){ + element = gf->getMeshElement(i); + + if(element->getNumVertices()==3){ + a = element->getVertex(0); + b = element->getVertex(1); + c = element->getVertex(2); + + tuples.insert(Tuple(a,b,c,element,gf)); + } + } + } +} + +void Supplementary::modify_surfaces(GRegion* gr){ + unsigned int i; + MVertex *a,*b,*c; + MVertex *d,*e,*f; + MElement* element; + GFace* gf; + std::list<GFace*> faces; + std::vector<MElement*> opt; + std::list<GFace*>::iterator it; + std::set<MElement*>::iterator it2; + + for(i=0;i<gr->getNumMeshElements();i++){ + element = gr->getMeshElement(i); + + if(element->getNumVertices()==6){ + a = element->getVertex(0); + b = element->getVertex(1); + c = element->getVertex(2); + d = element->getVertex(3); + e = element->getVertex(4); + f = element->getVertex(5); + + modify_surfaces(a,d,e,b); + modify_surfaces(a,d,f,c); + modify_surfaces(b,e,f,c); + } + } + + faces = gr->faces(); + + for(it=faces.begin();it!=faces.end();it++) + { + gf = *it; + + opt.clear(); + + for(i=0;i<gf->getNumMeshElements();i++){ + element = gf->getMeshElement(i); + + if(element->getNumVertices()==3){ + it2 = triangles.find(element); + if(it2==triangles.end()){ + opt.push_back(element); + } + } + } + + gf->triangles.clear(); + + for(i=0;i<opt.size();i++){ + gf->triangles.push_back((MTriangle*)opt[i]); + } + } +} + +void Supplementary::modify_surfaces(MVertex* a,MVertex* b,MVertex* c,MVertex* d){ + bool flag1,flag2; + MElement *element1,*element2; + GFace *gf1;//,*gf2; + Tuple tuple1,tuple2; + std::multiset<Tuple>::iterator it1; + std::multiset<Tuple>::iterator it2; + + gf1 = NULL; + //gf2 = NULL; + + tuple1 = Tuple(a,b,c); + tuple2 = Tuple(c,d,a); + + it1 = tuples.find(tuple1); + it2 = tuples.find(tuple2); + + flag1 = 0; + flag2 = 0; + + while(it1!=tuples.end()){ + if(tuple1.get_hash()!=it1->get_hash()){ + break; + } + + if(tuple1.same_vertices(*it1)){ + flag1 = 1; + element1 = it1->get_element(); + gf1 = it1->get_gf(); + } + + it1++; + } + + while(it2!=tuples.end()){ + if(tuple2.get_hash()!=it2->get_hash()){ + break; + } + + if(tuple2.same_vertices(*it2)){ + flag2 = 1; + element2 = it2->get_element(); + //gf2 = it2->get_gf(); + } + + it2++; + } + + if(flag1 && flag2){ + triangles.insert(element1); + triangles.insert(element2); + + gf1->addQuadrangle(new MQuadrangle(a,b,c,d)); + } + + tuple1 = Tuple(a,b,d); + tuple2 = Tuple(b,c,d); + + it1 = tuples.find(tuple1); + it2 = tuples.find(tuple2); + + flag1 = 0; + flag2 = 0; + + while(it1!=tuples.end()){ + if(tuple1.get_hash()!=it1->get_hash()){ + break; + } + + if(tuple1.same_vertices(*it1)){ + flag1 = 1; + element1 = it1->get_element(); + gf1 = it1->get_gf(); + } + + it1++; + } + + while(it2!=tuples.end()){ + if(tuple2.get_hash()!=it2->get_hash()){ + break; + } + + if(tuple2.same_vertices(*it2)){ + flag2 = 1; + element2 = it2->get_element(); + //gf2 = it2->get_gf(); + } + + it2++; + } + + if(flag1 && flag2){ + triangles.insert(element1); + triangles.insert(element2); + + gf1->addQuadrangle(new MQuadrangle(a,b,c,d)); + } +} + +bool Supplementary::four(MElement* element){ + if(element->getNumVertices()==4) return 1; + else return 0; +} + +bool Supplementary::five(MElement* element){ + if(element->getNumVertices()==5) return 1; + else return 0; +} + +bool Supplementary::six(MElement* element){ + if(element->getNumVertices()==6) return 1; + else return 0; +} + +bool Supplementary::eight(MElement* element){ + if(element->getNumVertices()==8) return 1; + else return 0; +} + +bool Supplementary::sliver(MElement* element,Prism prism){ + bool val; + bool flag1,flag2,flag3,flag4; + MVertex *a,*b,*c,*d; + + val = 0; + a = element->getVertex(0); + b = element->getVertex(1); + c = element->getVertex(2); + d = element->getVertex(3); + + flag1 = inclusion(a,prism.get_a(),prism.get_d(),prism.get_f(),prism.get_c()); + flag2 = inclusion(b,prism.get_a(),prism.get_d(),prism.get_f(),prism.get_c()); + flag3 = inclusion(c,prism.get_a(),prism.get_d(),prism.get_f(),prism.get_c()); + flag4 = inclusion(d,prism.get_a(),prism.get_d(),prism.get_f(),prism.get_c()); + if(flag1 && flag2 && flag3 && flag4) val = 1; + + flag1 = inclusion(a,prism.get_a(),prism.get_b(),prism.get_e(),prism.get_d()); + flag2 = inclusion(b,prism.get_a(),prism.get_b(),prism.get_e(),prism.get_d()); + flag3 = inclusion(c,prism.get_a(),prism.get_b(),prism.get_e(),prism.get_d()); + flag4 = inclusion(d,prism.get_a(),prism.get_b(),prism.get_e(),prism.get_d()); + if(flag1 && flag2 && flag3 && flag4) val = 1; + + flag1 = inclusion(a,prism.get_b(),prism.get_c(),prism.get_f(),prism.get_e()); + flag2 = inclusion(b,prism.get_b(),prism.get_c(),prism.get_f(),prism.get_e()); + flag3 = inclusion(c,prism.get_b(),prism.get_c(),prism.get_f(),prism.get_e()); + flag4 = inclusion(d,prism.get_b(),prism.get_c(),prism.get_f(),prism.get_e()); + if(flag1 && flag2 && flag3 && flag4) val = 1; + + return val; +} + +bool Supplementary::valid(Prism prism,const std::set<MElement*>& parts){ + bool ok1,ok2,ok3,ok4; + bool flag1A,flag1B,flag1C,flag1D; + bool flag2A,flag2B,flag2C,flag2D; + bool flag3A,flag3B,flag3C,flag3D; + bool flag4,flag5; + MVertex *a,*b,*c; + MVertex *d,*e,*f; - a = hex.get_a(); - b = hex.get_b(); - c = hex.get_c(); - d = hex.get_d(); - e = hex.get_e(); - f = hex.get_f(); - g = hex.get_g(); - h = hex.get_h(); + a = prism.get_a(); + b = prism.get_b(); + c = prism.get_c(); + d = prism.get_d(); + e = prism.get_e(); + f = prism.get_f(); - flag1A = inclusion(a,b,c,parts); - flag1B = inclusion(a,c,d,parts); - flag1C = inclusion(b,c,d,parts); - flag1D = inclusion(a,b,d,parts); + flag1A = inclusion(a,d,f,parts); + flag1B = inclusion(a,f,c,parts); + flag1C = inclusion(a,c,d,parts); + flag1D = inclusion(c,d,f,parts); ok1 = (flag1A && flag1B) || (flag1C && flag1D); - flag2A = inclusion(e,f,g,parts); - flag2B = inclusion(e,g,h,parts); - flag2C = inclusion(f,g,h,parts); - flag2D = inclusion(e,f,h,parts); + flag2A = inclusion(a,b,d,parts); + flag2B = inclusion(b,d,e,parts); + flag2C = inclusion(a,d,e,parts); + flag2D = inclusion(a,b,e,parts); ok2 = (flag2A && flag2B) || (flag2C && flag2D); - flag3A = inclusion(a,b,f,parts); - flag3B = inclusion(a,f,e,parts); - flag3C = inclusion(b,e,f,parts); - flag3D = inclusion(a,b,e,parts); + flag3A = inclusion(b,c,f,parts); + flag3B = inclusion(b,e,f,parts); + flag3C = inclusion(b,c,e,parts); + flag3D = inclusion(c,e,f,parts); ok3 = (flag3A && flag3B) || (flag3C && flag3D); - flag4A = inclusion(b,c,g,parts); - flag4B = inclusion(b,g,f,parts); - flag4C = inclusion(c,g,f,parts); - flag4D = inclusion(b,c,f,parts); - ok4 = (flag4A && flag4B) || (flag4C && flag4D); - - flag5A = inclusion(c,d,g,parts); - flag5B = inclusion(d,g,h,parts); - flag5C = inclusion(c,g,h,parts); - flag5D = inclusion(c,d,h,parts); - ok5 = (flag5A && flag5B) || (flag5C && flag5D); - - flag6A = inclusion(a,d,h,parts); - flag6B = inclusion(a,e,h,parts); - flag6C = inclusion(d,e,h,parts); - flag6D = inclusion(a,d,e,parts); - ok6 = (flag6A && flag6B) || (flag6C && flag6D); + flag4 = inclusion(a,b,c,parts); + flag5 = inclusion(d,e,f,parts); + ok4 = flag4 && flag5; - if(ok1 && ok2 && ok3 && ok4 && ok5 && ok6){ + if(ok1 && ok2 && ok3 && ok4){ return 1; } else{ @@ -1287,32 +3998,26 @@ bool Recombinator::valid(Hex hex,const std::set<MElement*>& parts){ } } -bool Recombinator::valid(Hex hex){ +bool Supplementary::valid(Prism prism){ double k; double eta1,eta2,eta3; - double eta4,eta5,eta6; - MVertex *a,*b,*c,*d; - MVertex *e,*f,*g,*h; + MVertex *a,*b,*c; + MVertex *d,*e,*f; k = 0.000001; - a = hex.get_a(); - b = hex.get_b(); - c = hex.get_c(); - d = hex.get_d(); - e = hex.get_e(); - f = hex.get_f(); - g = hex.get_g(); - h = hex.get_h(); + a = prism.get_a(); + b = prism.get_b(); + c = prism.get_c(); + d = prism.get_d(); + e = prism.get_e(); + f = prism.get_f(); - eta1 = eta(a,b,c,d); - eta2 = eta(e,f,g,h); - eta3 = eta(a,b,f,e); - eta4 = eta(b,c,g,f); - eta5 = eta(d,a,e,h); - eta6 = eta(d,c,g,h); + eta1 = eta(a,d,f,c); + eta2 = eta(a,b,e,d); + eta3 = eta(b,c,f,e); - if(eta1>k && eta2>k && eta3>k && eta4>k && eta5>k && eta6>k){ + if(eta1>k && eta2>k && eta3>k){ return 1; } else{ @@ -1320,7 +4025,7 @@ bool Recombinator::valid(Hex hex){ } } -double Recombinator::eta(MVertex* a,MVertex* b,MVertex* c,MVertex* d){ +double Supplementary::eta(MVertex* a,MVertex* b,MVertex* c,MVertex* d){ double val; MQuadrangle* quad; @@ -1330,7 +4035,7 @@ double Recombinator::eta(MVertex* a,MVertex* b,MVertex* c,MVertex* d){ return val; } -bool Recombinator::linked(MVertex* v1,MVertex* v2){ +bool Supplementary::linked(MVertex* v1,MVertex* v2){ bool flag; std::map<MVertex*,std::set<MVertex*> >::iterator it; std::set<MVertex*>::iterator it2; @@ -1338,152 +4043,67 @@ bool Recombinator::linked(MVertex* v1,MVertex* v2){ it = vertex_to_vertices.find(v1); flag = 0; - for(it2=(it->second).begin();it2!=(it->second).end();it2++){ - if(*it2==v2){ - flag = 1; - break; + if(it!=vertex_to_vertices.end()){ + for(it2=(it->second).begin();it2!=(it->second).end();it2++){ + if(*it2==v2){ + flag = 1; + break; + } } } return flag; } -void Recombinator::find(MVertex* v1,MVertex* v2,const std::vector<MVertex*>& already,std::set<MVertex*>& final){ - std::map<MVertex*,std::set<MVertex*> >::iterator it1; - std::map<MVertex*,std::set<MVertex*> >::iterator it2; - - it1 = vertex_to_vertices.find(v1); - it2 = vertex_to_vertices.find(v2); - - intersection(it1->second,it2->second,already,final); -} - -void Recombinator::find(MVertex* v1,MVertex* v2,MVertex* v3,const std::vector<MVertex*>& already,std::set<MVertex*>& final){ +void Supplementary::find(MVertex* v1,MVertex* v2,const std::vector<MVertex*>& already,std::set<MVertex*>& final){ std::map<MVertex*,std::set<MVertex*> >::iterator it1; std::map<MVertex*,std::set<MVertex*> >::iterator it2; - std::map<MVertex*,std::set<MVertex*> >::iterator it3; it1 = vertex_to_vertices.find(v1); it2 = vertex_to_vertices.find(v2); - it3 = vertex_to_vertices.find(v3); - - intersection(it1->second,it2->second,it3->second,already,final); -} - -void Recombinator::find(MVertex* v1,MVertex* v2,std::set<MElement*>& final){ - std::map<MVertex*,std::set<MElement*> >::iterator it1; - std::map<MVertex*,std::set<MElement*> >::iterator it2; - - it1 = vertex_to_elements.find(v1); - it2 = vertex_to_elements.find(v2); - intersection(it1->second,it2->second,final); + if(it1!=vertex_to_vertices.end() && it2!=vertex_to_vertices.end()){ + intersection(it1->second,it2->second,already,final); + } } -void Recombinator::find(MVertex* vertex,Hex hex,std::set<MElement*>& final){ +void Supplementary::find(MVertex* vertex,Prism prism,std::set<MElement*>& final){ bool flag1,flag2,flag3,flag4; MVertex *a,*b,*c,*d; std::map<MVertex*,std::set<MElement*> >::iterator it; std::set<MElement*>::iterator it2; - it = vertex_to_elements.find(vertex); - - for(it2=(it->second).begin();it2!=(it->second).end();it2++){ - a = (*it2)->getVertex(0); - b = (*it2)->getVertex(1); - c = (*it2)->getVertex(2); - d = (*it2)->getVertex(3); - - flag1 = inclusion(a,hex); - flag2 = inclusion(b,hex); - flag3 = inclusion(c,hex); - flag4 = inclusion(d,hex); - - if(flag1 && flag2 && flag3 && flag4){ - final.insert(*it2); - } - } -} - -MVertex* Recombinator::find(MVertex* v1,MVertex* v2,MVertex* v3,MVertex* already,const std::set<MElement*>& bin){ - bool flag1,flag2,flag3,flag4; - MElement* element; - MVertex *a,*b,*c,*d; - MVertex* pointer; - std::set<MElement*>::const_iterator it; - - pointer = 0; - - for(it=bin.begin();it!=bin.end();it++){ - element = *it; - - a = element->getVertex(0); - b = element->getVertex(1); - c = element->getVertex(2); - d = element->getVertex(3); - - flag1 = inclusion(v1,a,b,c,d); - flag2 = inclusion(v2,a,b,c,d); - flag3 = inclusion(v3,a,b,c,d); - flag4 = inclusion(already,a,b,c,d); - - if(flag1 && flag2 && flag3 && !flag4){ - if(a!=v1 && a!=v2 && a!=v3){ - pointer = a; - } - else if(b!=v1 && b!=v2 && b!=v3){ - pointer = b; - } - else if(c!=v1 && c!=v2 && c!=v3){ - pointer = c; - } - else{ - pointer = d; - } - break; - } - } - - return pointer; -} - -void Recombinator::intersection(const std::set<MVertex*>& bin1,const std::set<MVertex*>& bin2, - const std::vector<MVertex*>& already,std::set<MVertex*>& final){ - size_t i; - bool ok; - std::set<MVertex*> temp; - std::set<MVertex*>::iterator it; + it = vertex_to_tetrahedra.find(vertex); - std::set_intersection(bin1.begin(),bin1.end(),bin2.begin(),bin2.end(),std::inserter(temp,temp.end())); + if(it!=vertex_to_tetrahedra.end()){ + for(it2=(it->second).begin();it2!=(it->second).end();it2++){ + a = (*it2)->getVertex(0); + b = (*it2)->getVertex(1); + c = (*it2)->getVertex(2); + d = (*it2)->getVertex(3); - for(it=temp.begin();it!=temp.end();it++){ - ok = 1; + flag1 = inclusion(a,prism); + flag2 = inclusion(b,prism); + flag3 = inclusion(c,prism); + flag4 = inclusion(d,prism); - for(i=0;i<already.size();i++){ - if((*it)==already[i]){ - ok = 0; - break; + if(flag1 && flag2 && flag3 && flag4){ + final.insert(*it2); } } - - if(ok){ - final.insert(*it); - } } } -void Recombinator::intersection(const std::set<MVertex*>& bin1,const std::set<MVertex*>& bin2,const std::set<MVertex*>& bin3, - const std::vector<MVertex*>& already,std::set<MVertex*>& final){ +void Supplementary::intersection(const std::set<MVertex*>& bin1,const std::set<MVertex*>& bin2, + const std::vector<MVertex*>& already,std::set<MVertex*>& final){ size_t i; bool ok; std::set<MVertex*> temp; - std::set<MVertex*> temp2; std::set<MVertex*>::iterator it; std::set_intersection(bin1.begin(),bin1.end(),bin2.begin(),bin2.end(),std::inserter(temp,temp.end())); - std::set_intersection(temp.begin(),temp.end(),bin3.begin(),bin3.end(),std::inserter(temp2,temp2.end())); - for(it=temp2.begin();it!=temp2.end();it++){ + for(it=temp.begin();it!=temp.end();it++){ ok = 1; for(i=0;i<already.size();i++){ @@ -1499,28 +4119,22 @@ void Recombinator::intersection(const std::set<MVertex*>& bin1,const std::set<MV } } -void Recombinator::intersection(const std::set<MElement*>& bin1,const std::set<MElement*>& bin2,std::set<MElement*>& final){ - std::set_intersection(bin1.begin(),bin1.end(),bin2.begin(),bin2.end(),std::inserter(final,final.end())); -} - -bool Recombinator::inclusion(MVertex* vertex,Hex hex){ +bool Supplementary::inclusion(MVertex* vertex,Prism prism){ bool flag; flag = 0; - if(vertex==hex.get_a()) flag = 1; - else if(vertex==hex.get_b()) flag = 1; - else if(vertex==hex.get_c()) flag = 1; - else if(vertex==hex.get_d()) flag = 1; - else if(vertex==hex.get_e()) flag = 1; - else if(vertex==hex.get_f()) flag = 1; - else if(vertex==hex.get_g()) flag = 1; - else if(vertex==hex.get_h()) flag = 1; + if(vertex==prism.get_a()) flag = 1; + else if(vertex==prism.get_b()) flag = 1; + else if(vertex==prism.get_c()) flag = 1; + else if(vertex==prism.get_d()) flag = 1; + else if(vertex==prism.get_e()) flag = 1; + else if(vertex==prism.get_f()) flag = 1; return flag; } -bool Recombinator::inclusion(MVertex* vertex,MVertex* a,MVertex* b,MVertex* c,MVertex* d){ +bool Supplementary::inclusion(MVertex* vertex,MVertex* a,MVertex* b,MVertex* c,MVertex* d){ bool flag; flag = 0; @@ -1533,7 +4147,7 @@ bool Recombinator::inclusion(MVertex* vertex,MVertex* a,MVertex* b,MVertex* c,MV return flag; } -bool Recombinator::inclusion(MVertex* v1,MVertex* v2,MVertex* v3,const std::set<MElement*>& bin){ +bool Supplementary::inclusion(MVertex* v1,MVertex* v2,MVertex* v3,const std::set<MElement*>& bin){ bool ok; bool flag1,flag2,flag3; MVertex *a,*b,*c,*d; @@ -1563,7 +4177,7 @@ bool Recombinator::inclusion(MVertex* v1,MVertex* v2,MVertex* v3,const std::set< return ok; } -bool Recombinator::inclusion(Facet facet){ +bool Supplementary::inclusion(Facet facet){ bool flag; std::multiset<Facet>::iterator it; @@ -1586,7 +4200,7 @@ bool Recombinator::inclusion(Facet facet){ return flag; } -bool Recombinator::inclusion(Diagonal diagonal){ +bool Supplementary::inclusion(Diagonal diagonal){ bool flag; std::multiset<Diagonal>::iterator it; @@ -1609,7 +4223,7 @@ bool Recombinator::inclusion(Diagonal diagonal){ return flag; } -bool Recombinator::duplicate(Diagonal diagonal){ +bool Supplementary::duplicate(Diagonal diagonal){ bool flag; std::multiset<Diagonal>::iterator it; @@ -1632,31 +4246,26 @@ bool Recombinator::duplicate(Diagonal diagonal){ return flag; } -bool Recombinator::conformityA(Hex hex){ - bool c1,c2,c3,c4,c5,c6; - MVertex *a,*b,*c,*d; - MVertex *e,*f,*g,*h; +bool Supplementary::conformityA(Prism prism){ + bool c1,c2,c3; + MVertex *a,*b,*c; + MVertex *d,*e,*f; - a = hex.get_a(); - b = hex.get_b(); - c = hex.get_c(); - d = hex.get_d(); - e = hex.get_e(); - f = hex.get_f(); - g = hex.get_g(); - h = hex.get_h(); + a = prism.get_a(); + b = prism.get_b(); + c = prism.get_c(); + d = prism.get_d(); + e = prism.get_e(); + f = prism.get_f(); - c1 = conformityA(a,b,c,d); - c2 = conformityA(e,f,g,h); - c3 = conformityA(a,b,f,e); - c4 = conformityA(b,c,g,f); - c5 = conformityA(d,c,g,h); - c6 = conformityA(d,a,e,h); + c1 = conformityA(a,d,f,c); + c2 = conformityA(a,d,e,b); + c3 = conformityA(b,c,f,e); - return c1 && c2 && c3 && c4 && c5 && c6; + return c1 && c2 && c3; } -bool Recombinator::conformityA(MVertex* a,MVertex* b,MVertex* c,MVertex* d){ +bool Supplementary::conformityA(MVertex* a,MVertex* b,MVertex* c,MVertex* d){ bool c1,c2,c3,c4; c1 = inclusion(Facet(a,b,c)); @@ -1667,55 +4276,40 @@ bool Recombinator::conformityA(MVertex* a,MVertex* b,MVertex* c,MVertex* d){ return (c1 && c2 && c3 && c4) || (!c1 && !c2 && !c3 && !c4); } -bool Recombinator::conformityB(Hex hex){ +bool Supplementary::conformityB(Prism prism){ bool flag1; bool flag2; - bool c1,c2,c3,c4; - bool c5,c6,c7,c8; - bool c9,c10,c11,c12; - MVertex *a,*b,*c,*d; - MVertex *e,*f,*g,*h; + bool c1,c2,c3; + bool c4,c5,c6; + MVertex *a,*b,*c; + MVertex *d,*e,*f; - a = hex.get_a(); - b = hex.get_b(); - c = hex.get_c(); - d = hex.get_d(); - e = hex.get_e(); - f = hex.get_f(); - g = hex.get_g(); - h = hex.get_h(); + a = prism.get_a(); + b = prism.get_b(); + c = prism.get_c(); + d = prism.get_d(); + e = prism.get_e(); + f = prism.get_f(); - flag1 = inclusion(Diagonal(a,b)); - flag1 = flag1 || inclusion(Diagonal(b,f)); - flag1 = flag1 || inclusion(Diagonal(f,e)); - flag1 = flag1 || inclusion(Diagonal(e,a)); - flag1 = flag1 || inclusion(Diagonal(d,c)); - flag1 = flag1 || inclusion(Diagonal(c,g)); - flag1 = flag1 || inclusion(Diagonal(g,h)); - flag1 = flag1 || inclusion(Diagonal(h,d)); + flag1 = inclusion(Diagonal(a,c)); + flag1 = flag1 || inclusion(Diagonal(d,f)); + flag1 = flag1 || inclusion(Diagonal(d,a)); + flag1 = flag1 || inclusion(Diagonal(f,c)); + flag1 = flag1 || inclusion(Diagonal(e,b)); + flag1 = flag1 || inclusion(Diagonal(d,e)); + flag1 = flag1 || inclusion(Diagonal(e,f)); + flag1 = flag1 || inclusion(Diagonal(a,b)); flag1 = flag1 || inclusion(Diagonal(b,c)); - flag1 = flag1 || inclusion(Diagonal(f,g)); - flag1 = flag1 || inclusion(Diagonal(e,h)); - flag1 = flag1 || inclusion(Diagonal(a,d)); c1 = inclusion(Diagonal(a,f)); - c2 = inclusion(Diagonal(b,e)); + c2 = inclusion(Diagonal(d,c)); flag2 = (c1 && !c2) || (!c1 && c2); - c3 = inclusion(Diagonal(d,g)); - c4 = inclusion(Diagonal(c,h)); + c3 = inclusion(Diagonal(a,e)); + c4 = inclusion(Diagonal(b,d)); flag2 = flag2 || (c3 && !c4) || (!c3 && c4); - c5 = inclusion(Diagonal(b,g)); - c6 = inclusion(Diagonal(c,f)); + c5 = inclusion(Diagonal(b,f)); + c6 = inclusion(Diagonal(c,e)); flag2 = flag2 || (c5 && !c6) || (!c5 && c6); - c7 = inclusion(Diagonal(e,g)); - c8 = inclusion(Diagonal(f,h)); - flag2 = flag2 || (c7 && !c8) || (!c7 && c8); - c9 = inclusion(Diagonal(a,h)); - c10 = inclusion(Diagonal(d,e)); - flag2 = flag2 || (c9 && !c10) || (!c9 && c10); - c11 = inclusion(Diagonal(a,c)); - c12 = inclusion(Diagonal(b,d)); - flag2 = flag2 || (c11 && !c12) || (!c11 && c12); if(flag1 || flag2){ return 0; @@ -1725,32 +4319,24 @@ bool Recombinator::conformityB(Hex hex){ } } -bool Recombinator::conformityC(Hex hex){ +bool Supplementary::conformityC(Prism prism){ bool flag; - MVertex *a,*b,*c,*d; - MVertex *e,*f,*g,*h; + MVertex *a,*b,*c; + MVertex *d,*e,*f; - a = hex.get_a(); - b = hex.get_b(); - c = hex.get_c(); - d = hex.get_d(); - e = hex.get_e(); - f = hex.get_f(); - g = hex.get_g(); - h = hex.get_h(); + a = prism.get_a(); + b = prism.get_b(); + c = prism.get_c(); + d = prism.get_d(); + e = prism.get_e(); + f = prism.get_f(); flag = duplicate(Diagonal(a,f)); - flag = flag || duplicate(Diagonal(b,e)); - flag = flag || duplicate(Diagonal(d,g)); - flag = flag || duplicate(Diagonal(c,h)); - flag = flag || duplicate(Diagonal(b,g)); - flag = flag || duplicate(Diagonal(c,f)); - flag = flag || duplicate(Diagonal(e,g)); - flag = flag || duplicate(Diagonal(f,h)); - flag = flag || duplicate(Diagonal(a,h)); - flag = flag || duplicate(Diagonal(d,e)); - flag = flag || duplicate(Diagonal(a,c)); + flag = flag || duplicate(Diagonal(d,c)); + flag = flag || duplicate(Diagonal(a,e)); flag = flag || duplicate(Diagonal(b,d)); + flag = flag || duplicate(Diagonal(b,f)); + flag = flag || duplicate(Diagonal(c,e)); if(flag){ return 0; @@ -1760,31 +4346,26 @@ bool Recombinator::conformityC(Hex hex){ } } -bool Recombinator::faces_statuquo(Hex hex){ - bool c1,c2,c3,c4,c5,c6; - MVertex *a,*b,*c,*d; - MVertex *e,*f,*g,*h; +bool Supplementary::faces_statuquo(Prism prism){ + bool c1,c2,c3; + MVertex *a,*b,*c; + MVertex *d,*e,*f; - a = hex.get_a(); - b = hex.get_b(); - c = hex.get_c(); - d = hex.get_d(); - e = hex.get_e(); - f = hex.get_f(); - g = hex.get_g(); - h = hex.get_h(); + a = prism.get_a(); + b = prism.get_b(); + c = prism.get_c(); + d = prism.get_d(); + e = prism.get_e(); + f = prism.get_f(); - c1 = faces_statuquo(a,b,c,d); - c2 = faces_statuquo(e,f,g,h); - c3 = faces_statuquo(a,b,f,e); - c4 = faces_statuquo(b,c,g,f); - c5 = faces_statuquo(d,c,g,h); - c6 = faces_statuquo(d,a,e,h); + c1 = faces_statuquo(a,d,f,c); + c2 = faces_statuquo(a,d,e,b); + c3 = faces_statuquo(b,c,f,e); - return c1 && c2 && c3 && c4 && c5 && c6; + return c1 && c2 && c3; } -bool Recombinator::faces_statuquo(MVertex* a,MVertex* b,MVertex* c,MVertex* d){ +bool Supplementary::faces_statuquo(MVertex* a,MVertex* b,MVertex* c,MVertex* d){ bool ok; bool flag1,flag2; GFace *gf1,*gf2; @@ -1882,7 +4463,7 @@ bool Recombinator::faces_statuquo(MVertex* a,MVertex* b,MVertex* c,MVertex* d){ return ok; } -void Recombinator::build_vertex_to_vertices(GRegion* gr){ +void Supplementary::build_vertex_to_vertices(GRegion* gr){ size_t i; int j; MElement* element; @@ -1894,86 +4475,85 @@ void Recombinator::build_vertex_to_vertices(GRegion* gr){ for(i=0;i<gr->getNumMeshElements();i++){ element = gr->getMeshElement(i); - for(j=0;j<element->getNumVertices();j++){ - a = element->getVertex(j); - b = element->getVertex((j+1)%4); - c = element->getVertex((j+2)%4); - d = element->getVertex((j+3)%4); + if(four(element)){ + for(j=0;j<element->getNumVertices();j++){ + a = element->getVertex(j); + b = element->getVertex((j+1)%4); + c = element->getVertex((j+2)%4); + d = element->getVertex((j+3)%4); - it = vertex_to_vertices.find(a); - if(it!=vertex_to_vertices.end()){ - it->second.insert(b); - it->second.insert(c); - it->second.insert(d); - } - else{ - bin.clear(); - bin.insert(b); - bin.insert(c); - bin.insert(d); - vertex_to_vertices.insert(std::pair<MVertex*,std::set<MVertex*> >(a,bin)); + it = vertex_to_vertices.find(a); + if(it!=vertex_to_vertices.end()){ + it->second.insert(b); + it->second.insert(c); + it->second.insert(d); + } + else{ + bin.clear(); + bin.insert(b); + bin.insert(c); + bin.insert(d); + vertex_to_vertices.insert(std::pair<MVertex*,std::set<MVertex*> >(a,bin)); + } } } } } -void Recombinator::build_vertex_to_elements(GRegion* gr){ - size_t i; +void Supplementary::build_vertex_to_tetrahedra(GRegion* gr){ + unsigned int i; int j; MElement* element; MVertex* vertex; std::set<MElement*> bin; std::map<MVertex*,std::set<MElement*> >::iterator it; - vertex_to_elements.clear(); + vertex_to_tetrahedra.clear(); for(i=0;i<gr->getNumMeshElements();i++){ element = gr->getMeshElement(i); - for(j=0;j<element->getNumVertices();j++){ - vertex = element->getVertex(j); + if(four(element)){ + for(j=0;j<element->getNumVertices();j++){ + vertex = element->getVertex(j); - it = vertex_to_elements.find(vertex); - if(it!=vertex_to_elements.end()){ - it->second.insert(element); - } - else{ - bin.clear(); - bin.insert(element); - vertex_to_elements.insert(std::pair<MVertex*,std::set<MElement*> >(vertex,bin)); + it = vertex_to_tetrahedra.find(vertex); + if(it!=vertex_to_tetrahedra.end()){ + it->second.insert(element); + } + else{ + bin.clear(); + bin.insert(element); + vertex_to_tetrahedra.insert(std::pair<MVertex*,std::set<MElement*> >(vertex,bin)); + } } } } } -void Recombinator::build_hash_tableA(Hex hex){ - MVertex *a,*b,*c,*d; - MVertex *e,*f,*g,*h; +void Supplementary::build_hash_tableA(Prism prism){ + MVertex *a,*b,*c; + MVertex *d,*e,*f; - a = hex.get_a(); - b = hex.get_b(); - c = hex.get_c(); - d = hex.get_d(); - e = hex.get_e(); - f = hex.get_f(); - g = hex.get_g(); - h = hex.get_h(); + a = prism.get_a(); + b = prism.get_b(); + c = prism.get_c(); + d = prism.get_d(); + e = prism.get_e(); + f = prism.get_f(); - build_hash_tableA(a,b,c,d); - build_hash_tableA(e,f,g,h); - build_hash_tableA(a,b,f,e); - build_hash_tableA(b,c,g,f); - build_hash_tableA(d,c,g,h); - build_hash_tableA(d,a,e,h); + build_hash_tableA(a,d,f,c); + build_hash_tableA(a,d,e,b); + build_hash_tableA(b,c,f,e); } -void Recombinator::build_hash_tableA(MVertex* a,MVertex* b,MVertex* c,MVertex* d){ +void Supplementary::build_hash_tableA(MVertex* a,MVertex* b,MVertex* c,MVertex* d){ build_hash_tableA(Facet(a,b,c)); build_hash_tableA(Facet(a,c,d)); build_hash_tableA(Facet(a,b,d)); build_hash_tableA(Facet(b,d,c)); } -void Recombinator::build_hash_tableA(Facet facet){ +void Supplementary::build_hash_tableA(Facet facet){ bool flag; std::multiset<Facet>::iterator it; @@ -1998,33 +4578,28 @@ void Recombinator::build_hash_tableA(Facet facet){ } } -void Recombinator::build_hash_tableB(Hex hex){ - MVertex *a,*b,*c,*d; - MVertex *e,*f,*g,*h; +void Supplementary::build_hash_tableB(Prism prism){ + MVertex *a,*b,*c; + MVertex *d,*e,*f; - a = hex.get_a(); - b = hex.get_b(); - c = hex.get_c(); - d = hex.get_d(); - e = hex.get_e(); - f = hex.get_f(); - g = hex.get_g(); - h = hex.get_h(); + a = prism.get_a(); + b = prism.get_b(); + c = prism.get_c(); + d = prism.get_d(); + e = prism.get_e(); + f = prism.get_f(); - build_hash_tableB(a,b,c,d); - build_hash_tableB(e,f,g,h); - build_hash_tableB(a,b,f,e); - build_hash_tableB(b,c,g,f); - build_hash_tableB(d,c,g,h); - build_hash_tableB(d,a,e,h); + build_hash_tableB(a,d,f,c); + build_hash_tableB(a,d,e,b); + build_hash_tableB(b,e,f,c); } -void Recombinator::build_hash_tableB(MVertex* a,MVertex* b,MVertex* c,MVertex* d){ +void Supplementary::build_hash_tableB(MVertex* a,MVertex* b,MVertex* c,MVertex* d){ build_hash_tableB(Diagonal(a,c)); build_hash_tableB(Diagonal(b,d)); } -void Recombinator::build_hash_tableB(Diagonal diagonal){ +void Supplementary::build_hash_tableB(Diagonal diagonal){ bool flag; std::multiset<Diagonal>::iterator it; @@ -2049,34 +4624,29 @@ void Recombinator::build_hash_tableB(Diagonal diagonal){ } } -void Recombinator::build_hash_tableC(Hex hex){ - MVertex *a,*b,*c,*d; - MVertex *e,*f,*g,*h; +void Supplementary::build_hash_tableC(Prism prism){ + MVertex *a,*b,*c; + MVertex *d,*e,*f; - a = hex.get_a(); - b = hex.get_b(); - c = hex.get_c(); - d = hex.get_d(); - e = hex.get_e(); - f = hex.get_f(); - g = hex.get_g(); - h = hex.get_h(); + a = prism.get_a(); + b = prism.get_b(); + c = prism.get_c(); + d = prism.get_d(); + e = prism.get_e(); + f = prism.get_f(); + build_hash_tableC(Diagonal(a,d)); + build_hash_tableC(Diagonal(d,f)); + build_hash_tableC(Diagonal(f,c)); + build_hash_tableC(Diagonal(a,c)); + build_hash_tableC(Diagonal(e,b)); + build_hash_tableC(Diagonal(d,e)); + build_hash_tableC(Diagonal(f,e)); build_hash_tableC(Diagonal(a,b)); build_hash_tableC(Diagonal(b,c)); - build_hash_tableC(Diagonal(c,d)); - build_hash_tableC(Diagonal(d,a)); - build_hash_tableC(Diagonal(e,f)); - build_hash_tableC(Diagonal(f,g)); - build_hash_tableC(Diagonal(g,h)); - build_hash_tableC(Diagonal(h,e)); - build_hash_tableC(Diagonal(a,e)); - build_hash_tableC(Diagonal(b,f)); - build_hash_tableC(Diagonal(c,g)); - build_hash_tableC(Diagonal(d,h)); } -void Recombinator::build_hash_tableC(Diagonal diagonal){ +void Supplementary::build_hash_tableC(Diagonal diagonal){ bool flag; std::multiset<Diagonal>::iterator it; @@ -2089,156 +4659,56 @@ void Recombinator::build_hash_tableC(Diagonal diagonal){ } if(diagonal.same_vertices(*it)){ - flag = 0; - break; - } - - it++; - } - - if(flag){ - hash_tableC.insert(diagonal); - } -} - -void Recombinator::print_vertex_to_vertices(GRegion* gr){ - size_t i; - int j; - SPoint3 p1,p2; - MElement* element; - MVertex* vertex; - std::map<MVertex*,std::set<MVertex*> >::iterator it; - std::set<MVertex*>::iterator it2; - - std::ofstream file("vertex_to_vertices.pos"); - file << "View \"test\" {\n"; - - for(i=0;i<gr->getNumMeshElements();i++){ - element = gr->getMeshElement(i); - for(j=0;j<element->getNumVertices();j++){ - vertex = element->getVertex(j); - p1 = SPoint3(vertex->x(),vertex->y(),vertex->z()); - it = vertex_to_vertices.find(vertex); - for(it2=(it->second).begin();it2!=(it->second).end();it2++){ - p2 = SPoint3((*it2)->x(),(*it2)->y(),(*it2)->z()); - print_segment(p1,p2,file); - } - } - } - file << "};\n"; -} - -void Recombinator::print_vertex_to_elements(GRegion* gr){ - size_t i; - int j; - MElement* element; - MVertex* vertex; - std::map<MVertex*,std::set<MElement*> >::iterator it; - std::map<MVertex*,std::set<MVertex*> >::iterator it2; - - for(i=0;i<gr->getNumMeshElements();i++){ - element = gr->getMeshElement(i); - for(j=0;j<element->getNumVertices();j++){ - vertex = element->getVertex(j); - it = vertex_to_elements.find(vertex); - it2 = vertex_to_vertices.find(vertex); - printf("%d %d\n",(int)(it->second).size(),(int)(it2->second).size()); - } - } -} - -void Recombinator::print_hash_tableA(){ - std::multiset<Facet>::iterator it; - - for(it=hash_tableA.begin();it!=hash_tableA.end();it++){ - printf("%lld\n",it->get_hash()); - } -} - -void Recombinator::print_segment(SPoint3 p1,SPoint3 p2,std::ofstream& file){ - file << "SL (" - << p1.x() << ", " << p1.y() << ", " << p1.z() << ", " - << p2.x() << ", " << p2.y() << ", " << p2.z() << ")" - << "{10, 20};\n"; -} - -double Recombinator::scaled_jacobian(MVertex* a,MVertex* b,MVertex* c,MVertex* d){ - double val; - double l1,l2,l3; - SVector3 vec1,vec2,vec3; - - vec1 = SVector3(b->x()-a->x(),b->y()-a->y(),b->z()-a->z()); - vec2 = SVector3(c->x()-a->x(),c->y()-a->y(),c->z()-a->z()); - vec3 = SVector3(d->x()-a->x(),d->y()-a->y(),d->z()-a->z()); - - l1 = vec1.norm(); - l2 = vec2.norm(); - l3 = vec3.norm(); - - val = dot(vec1,crossprod(vec2,vec3)); - return fabs(val)/(l1*l2*l3); -} - -double Recombinator::max_scaled_jacobian(MElement* element,int& index){ - double val; - double j1,j2,j3,j4; - MVertex *a,*b,*c,*d; - - a = element->getVertex(0); - b = element->getVertex(1); - c = element->getVertex(2); - d = element->getVertex(3); - - j1 = scaled_jacobian(a,b,c,d); - j2 = scaled_jacobian(b,c,d,a); - j3 = scaled_jacobian(c,d,a,b); - j4 = scaled_jacobian(d,a,b,c); - - if(j1>=j2 && j1>=j3 && j1>=j4){ - index = 0; - val = j1; - } - else if(j2>=j3 && j2>=j4 && j2>=j1){ - index = 1; - val = j2; - } - else if(j3>=j4 && j3>=j1 && j3>=j2){ - index = 2; - val = j3; + flag = 0; + break; + } + + it++; } - else{ - index = 3; - val = j4; + + if(flag){ + hash_tableC.insert(diagonal); } +} - return val; +double Supplementary::scaled_jacobian(MVertex* a,MVertex* b,MVertex* c,MVertex* d){ + double val; + double l1,l2,l3; + SVector3 vec1,vec2,vec3; + + vec1 = SVector3(b->x()-a->x(),b->y()-a->y(),b->z()-a->z()); + vec2 = SVector3(c->x()-a->x(),c->y()-a->y(),c->z()-a->z()); + vec3 = SVector3(d->x()-a->x(),d->y()-a->y(),d->z()-a->z()); + + l1 = vec1.norm(); + l2 = vec2.norm(); + l3 = vec3.norm(); + + val = dot(vec1,crossprod(vec2,vec3)); + return fabs(val)/(l1*l2*l3); } -double Recombinator::min_scaled_jacobian(Hex hex){ +double Supplementary::min_scaled_jacobian(Prism prism){ int i; double min; - double j1,j2,j3,j4,j5,j6,j7,j8; - MVertex *a,*b,*c,*d; - MVertex *e,*f,*g,*h; + double j1,j2,j3,j4,j5,j6; + MVertex *a,*b,*c; + MVertex *d,*e,*f; std::vector<double> jacobians; - a = hex.get_a(); - b = hex.get_b(); - c = hex.get_c(); - d = hex.get_d(); - e = hex.get_e(); - f = hex.get_f(); - g = hex.get_g(); - h = hex.get_h(); + a = prism.get_a(); + b = prism.get_b(); + c = prism.get_c(); + d = prism.get_d(); + e = prism.get_e(); + f = prism.get_f(); - j1 = scaled_jacobian(a,b,d,e); - j2 = scaled_jacobian(b,a,c,f); - j3 = scaled_jacobian(c,b,d,g); - j4 = scaled_jacobian(d,a,c,h); - j5 = scaled_jacobian(e,a,f,h); - j6 = scaled_jacobian(f,b,e,g); - j7 = scaled_jacobian(g,c,f,h); - j8 = scaled_jacobian(h,d,e,g); + j1 = scaled_jacobian(a,b,c,d); + j2 = scaled_jacobian(b,a,c,e); + j3 = scaled_jacobian(c,a,b,f); + j4 = scaled_jacobian(d,a,e,f); + j5 = scaled_jacobian(e,b,d,f); + j6 = scaled_jacobian(f,c,d,e); jacobians.push_back(j1); jacobians.push_back(j2); @@ -2246,11 +4716,9 @@ double Recombinator::min_scaled_jacobian(Hex hex){ jacobians.push_back(j4); jacobians.push_back(j5); jacobians.push_back(j6); - jacobians.push_back(j7); - jacobians.push_back(j8); min = 1000000000.0; - for(i=0;i<8;i++){ + for(i=0;i<6;i++){ if(jacobians[i]<=min){ min = jacobians[i]; } @@ -2259,339 +4727,451 @@ double Recombinator::min_scaled_jacobian(Hex hex){ return min; } -/*******************************************/ -/****************class Prism****************/ -/*******************************************/ +/********************************************/ +/****************class PostOp****************/ +/********************************************/ -Prism::Prism(){} +PostOp::PostOp(){} -Prism::Prism(MVertex* a2,MVertex* b2,MVertex* c2,MVertex* d2,MVertex* e2,MVertex* f2){ - a = a2; - b = b2; - c = c2; - d = d2; - e = e2; - f = f2; -} +PostOp::~PostOp(){} -Prism::~Prism(){} +void PostOp::execute(bool flag){ + GRegion* gr; + GModel* model = GModel::current(); + GModel::riter it; -double Prism::get_quality() const{ - return quality; + for(it=model->firstRegion();it!=model->lastRegion();it++) + { + gr = *it; + if(gr->getNumMeshElements()>0){ + execute(gr,flag); + } + } } -void Prism::set_quality(double new_quality){ - quality = new_quality; -} +void PostOp::execute(GRegion* gr,bool flag){ + printf("................PYRAMIDS................\n"); + estimate1 = 0; + estimate2 = 0; + iterations = 0; -MVertex* Prism::get_a(){ - return a; -} + build_tuples(gr); + init_markings(gr); + build_vertex_to_tetrahedra(gr); + pyramids1(gr); + rearrange(gr); -MVertex* Prism::get_b(){ - return b; -} + if(flag){ + init_markings(gr); + build_vertex_to_tetrahedra(gr); + build_vertex_to_pyramids(gr); + pyramids2(gr); + rearrange(gr); + } -MVertex* Prism::get_c(){ - return c; -} + statistics(gr); -MVertex* Prism::get_d(){ - return d; + modify_surfaces(gr); } -MVertex* Prism::get_e(){ - return e; -} +void PostOp::init_markings(GRegion* gr){ + unsigned int i; + MElement* element; -MVertex* Prism::get_f(){ - return f; -} + markings.clear(); -void Prism::set_vertices(MVertex* a2,MVertex* b2,MVertex* c2,MVertex* d2,MVertex* e2,MVertex* f2){ - a = a2; - b = b2; - c = c2; - d = d2; - e = e2; - f = f2; + for(i=0;i<gr->getNumMeshElements();i++){ + element = gr->getMeshElement(i); + if(four(element) || five(element)){ + markings.insert(std::pair<MElement*,bool>(element,false)); + } + } } -bool Prism::operator<(const Prism& prism) const{ - return quality>prism.get_quality(); -} +void PostOp::pyramids1(GRegion* gr){ + unsigned int i; + MVertex *a,*b,*c,*d; + MVertex *e,*f,*g,*h; + MElement* element; + std::vector<MElement*> hexahedra; + std::vector<MElement*> prisms; + std::vector<MTetrahedron*> opt; + std::map<MElement*,bool>::iterator it; -/***************************************************/ -/****************class Supplementary****************/ -/***************************************************/ + hexahedra.clear(); + prisms.clear(); -Supplementary::Supplementary(){} + for(i=0;i<gr->getNumMeshElements();i++){ + element = gr->getMeshElement(i); + if(eight(element)){ + hexahedra.push_back(element); + } + else if(six(element)){ + prisms.push_back(element); + } + } -Supplementary::~Supplementary(){} + for(i=0;i<hexahedra.size();i++){ + element = hexahedra[i]; -void Supplementary::execute(){ - GRegion* gr; - GModel* model = GModel::current(); - GModel::riter it; + a = element->getVertex(0); + b = element->getVertex(1); + c = element->getVertex(2); + d = element->getVertex(3); + e = element->getVertex(4); + f = element->getVertex(5); + g = element->getVertex(6); + h = element->getVertex(7); - for(it=model->firstRegion();it!=model->lastRegion();it++) - { - gr = *it; - if(gr->getNumMeshElements()>0){ - execute(gr); + pyramids1(a,b,c,d,gr); + pyramids1(e,f,g,h,gr); + pyramids1(a,b,f,e,gr); + pyramids1(b,c,g,f,gr); + pyramids1(d,c,g,h,gr); + pyramids1(d,a,e,h,gr); + } + + for(i=0;i<prisms.size();i++){ + element = prisms[i]; + + a = element->getVertex(0); + b = element->getVertex(1); + c = element->getVertex(2); + d = element->getVertex(3); + e = element->getVertex(4); + f = element->getVertex(5); + + pyramids1(a,d,f,c,gr); + pyramids1(a,b,e,d,gr); + pyramids1(b,c,f,e,gr); + } + + opt.clear(); + opt.resize(gr->tetrahedra.size()); + opt = gr->tetrahedra; + gr->tetrahedra.clear(); + + for(i=0;i<opt.size();i++){ + element = (MElement*)(opt[i]); + it = markings.find(element); + if(it->second==0){ + gr->tetrahedra.push_back(opt[i]); + } + } +} + +void PostOp::pyramids2(GRegion* gr){ + unsigned int i; + MVertex *a,*b,*c,*d; + MVertex *e,*f,*g,*h; + MElement* element; + std::vector<MElement*> hexahedra; + std::vector<MElement*> prisms; + std::vector<MTetrahedron*> opt1; + std::vector<MPyramid*> opt2; + std::map<MElement*,bool>::iterator it; + + hexahedra.clear(); + prisms.clear(); + + for(i=0;i<gr->getNumMeshElements();i++){ + element = gr->getMeshElement(i); + if(eight(element)){ + hexahedra.push_back(element); + } + else if(six(element)){ + prisms.push_back(element); } } -} -void Supplementary::execute(GRegion* gr){ - unsigned int i; - MElement* element; - MVertex *a,*b,*c,*d; - MVertex *e,*f,*g,*h; + for(i=0;i<hexahedra.size();i++){ + element = hexahedra[i]; - printf("................PRISMS................\n"); - build_tuples(gr); - init_markings(gr); + a = element->getVertex(0); + b = element->getVertex(1); + c = element->getVertex(2); + d = element->getVertex(3); + e = element->getVertex(4); + f = element->getVertex(5); + g = element->getVertex(6); + h = element->getVertex(7); - build_vertex_to_vertices(gr); - build_vertex_to_tetrahedra(gr); - printf("connectivity\n"); + pyramids2(a,b,c,d,gr); + pyramids2(e,f,g,h,gr); + pyramids2(a,b,f,e,gr); + pyramids2(b,c,g,f,gr); + pyramids2(d,c,g,h,gr); + pyramids2(d,a,e,h,gr); + } - potential.clear(); - pattern(gr); - printf("pattern\n"); + for(i=0;i<prisms.size();i++){ + element = prisms[i]; - hash_tableA.clear(); - hash_tableB.clear(); - hash_tableC.clear(); - for(i=0;i<gr->getNumMeshElements();i++){ - element = gr->getMeshElement(i); - if(eight(element)){ - a = element->getVertex(0); - b = element->getVertex(1); - c = element->getVertex(2); - d = element->getVertex(3); - e = element->getVertex(4); - f = element->getVertex(5); - g = element->getVertex(6); - h = element->getVertex(7); + a = element->getVertex(0); + b = element->getVertex(1); + c = element->getVertex(2); + d = element->getVertex(3); + e = element->getVertex(4); + f = element->getVertex(5); - build_hash_tableA(a,b,c,d); - build_hash_tableA(e,f,g,h); - build_hash_tableA(a,b,f,e); - build_hash_tableA(b,c,g,f); - build_hash_tableA(d,c,g,h); - build_hash_tableA(d,a,e,h); + pyramids2(a,d,f,c,gr); + pyramids2(a,b,e,d,gr); + pyramids2(b,c,f,e,gr); + } - build_hash_tableB(a,b,c,d); - build_hash_tableB(e,f,g,h); - build_hash_tableB(a,b,f,e); - build_hash_tableB(b,c,g,f); - build_hash_tableB(d,c,g,h); - build_hash_tableB(d,a,e,h); + opt1.clear(); + opt1.resize(gr->tetrahedra.size()); + opt1 = gr->tetrahedra; + gr->tetrahedra.clear(); - build_hash_tableC(Diagonal(a,b)); - build_hash_tableC(Diagonal(b,c)); - build_hash_tableC(Diagonal(c,d)); - build_hash_tableC(Diagonal(d,a)); - build_hash_tableC(Diagonal(e,f)); - build_hash_tableC(Diagonal(f,g)); - build_hash_tableC(Diagonal(g,h)); - build_hash_tableC(Diagonal(h,e)); - build_hash_tableC(Diagonal(a,e)); - build_hash_tableC(Diagonal(b,f)); - build_hash_tableC(Diagonal(c,g)); - build_hash_tableC(Diagonal(d,h)); + for(i=0;i<opt1.size();i++){ + element = (MElement*)(opt1[i]); + it = markings.find(element); + if(it->second==0){ + gr->tetrahedra.push_back(opt1[i]); } } - std::sort(potential.begin(),potential.end()); + opt2.clear(); + opt2.resize(gr->pyramids.size()); + opt2 = gr->pyramids; + gr->pyramids.clear(); - merge(gr); + for(i=0;i<opt2.size();i++){ + element = (MElement*)(opt2[i]); + it = markings.find(element); + if(it->second==0){ + gr->pyramids.push_back(opt2[i]); + } + } +} - rearrange(gr); +void PostOp::pyramids1(MVertex* a,MVertex* b,MVertex* c,MVertex* d,GRegion* gr){ + MVertex* vertex; + std::set<MElement*> bin; + std::set<MElement*> bin1; + std::set<MElement*> bin2; + std::set<MElement*>::iterator it; + std::map<MElement*,bool>::iterator it1; + std::map<MElement*,bool>::iterator it2; - statistics(gr); + bin1.clear(); + bin2.clear(); + find_tetrahedra(a,c,bin1); + find_tetrahedra(b,d,bin2); - modify_surfaces(gr); -} + bin.clear(); + for(it=bin1.begin();it!=bin1.end();it++){ + bin.insert(*it); + } + for(it=bin2.begin();it!=bin2.end();it++){ + bin.insert(*it); + } -void Supplementary::init_markings(GRegion* gr){ - unsigned int i; - MElement* element; + if(bin.size()==2){ + it = bin.begin(); + it1 = markings.find(*it); + it++; + it2 = markings.find(*it); - markings.clear(); + if(it1->second==0 && it2->second==0){ + vertex = find(a,b,c,d,*it); - for(i=0;i<gr->getNumMeshElements();i++){ - element = gr->getMeshElement(i); - if(four(element)){ - markings.insert(std::pair<MElement*,bool>(element,false)); + if(vertex!=0){ + gr->addPyramid(new MPyramid(a,b,c,d,vertex)); + it1->second = 1; + it2->second = 1; + } } } } -void Supplementary::pattern(GRegion* gr){ - size_t i; - int j,k; - double quality; - MElement* element; - MVertex *a,*b,*c,*d; - MVertex *p,*q; - std::vector<MVertex*> vertices; - std::vector<MVertex*> already; - std::set<MVertex*> bin1; - std::set<MVertex*> bin2; - std::set<MVertex*>::iterator it1; - std::set<MVertex*>::iterator it2; - Prism prism; +void PostOp::pyramids2(MVertex* a,MVertex* b,MVertex* c,MVertex* d,GRegion* gr){ + bool flag; + double x,y,z; + MVertex* mid; + MVertex *diagA,*diagB; + MVertex *N1,*N2; + MVertex *v1,*v2,*v3,*v4,*v5; + MTetrahedron* temp; + MPyramid* temp2; + std::vector<MElement*> movables; + std::set<MVertex*> Ns; + std::set<MElement*> bin1; + std::set<MElement*> bin2; + std::set<MElement*> bin3; + std::set<MElement*> bin4; + std::set<MElement*> tetrahedra; + std::set<MElement*> pyramids; + std::set<MElement*>::iterator it; + std::map<MElement*,bool>::iterator it2; - vertices.resize(3); + flag = 0; - for(i=0;i<gr->getNumMeshElements();i++){ - element = gr->getMeshElement(i); - if(four(element)){ - for(j=0;j<4;j++){ - a = element->getVertex(j); - vertices[0] = element->getVertex((j+1)%4); - vertices[1] = element->getVertex((j+2)%4); - vertices[2] = element->getVertex((j+3)%4); - for(k=0;k<3;k++){ - b = vertices[k%3]; - c = vertices[(k+1)%3]; - d = vertices[(k+2)%3]; - already.clear(); - already.push_back(a); - already.push_back(b); - already.push_back(c); - already.push_back(d); - bin1.clear(); - bin2.clear(); - find(b,d,already,bin1); - find(c,d,already,bin2); - for(it1=bin1.begin();it1!=bin1.end();it1++){ - p = *it1; - for(it2=bin2.begin();it2!=bin2.end();it2++){ - q = *it2; - if(p!=q && linked(p,q)){ - prism = Prism(a,b,c,d,p,q); - quality = min_scaled_jacobian(prism); - prism.set_quality(quality); - if(valid(prism)){ - potential.push_back(prism); - } - } - } - } - } - } - } + bin1.clear(); + bin2.clear(); + find_tetrahedra(a,c,bin1); + find_tetrahedra(b,d,bin2); + if(bin1.size()!=0) flag = 1; + + bin3.clear(); + bin4.clear(); + find_pyramids(a,c,bin3); + find_pyramids(b,d,bin4); + if(bin3.size()!=0) flag = 1; + + tetrahedra.clear(); + for(it=bin1.begin();it!=bin1.end();it++){ + tetrahedra.insert(*it); + } + for(it=bin2.begin();it!=bin2.end();it++){ + tetrahedra.insert(*it); + } + + pyramids.clear(); + for(it=bin3.begin();it!=bin3.end();it++){ + pyramids.insert(*it); + } + for(it=bin4.begin();it!=bin4.end();it++){ + pyramids.insert(*it); + } + + /*if(pyramids.size()==0 && tetrahedra.size()==1){ + printf("tetrahedron deleted\n"); + it2 = markings.find(*tetrahedra.begin()); + it2->second = 1; + return; + }*/ + + if(flag){ + diagA = a; + diagB = c; + } + else{ + diagA = b; + diagB = d; } -} -void Supplementary::merge(GRegion* gr){ - unsigned int i; - int count; - bool flag; - double threshold; - double quality; - MVertex *a,*b,*c; - MVertex *d,*e,*f; - MElement* element; - std::set<MElement*> parts; - std::vector<MTetrahedron*> opt; - std::set<MElement*>::iterator it; - std::map<MElement*,bool>::iterator it2; - Prism prism; + Ns.clear(); + Ns.insert(diagA); + Ns.insert(diagB); - count = 1; - quality = 0.0; + x = (diagA->x() + diagB->x())/2.0; + y = (diagA->y() + diagB->y())/2.0; + z = (diagA->z() + diagB->z())/2.0; - for(i=0;i<potential.size();i++){ - prism = potential[i]; + mid = 0; + movables.clear(); - threshold = 0.15; - if(prism.get_quality()<threshold){ - break; - } + if(tetrahedra.size()>0 || pyramids.size()>0){ + estimate1 = estimate1 + tetrahedra.size() + 2*pyramids.size(); + estimate2 = estimate2 + 1; - a = prism.get_a(); - b = prism.get_b(); - c = prism.get_c(); - d = prism.get_d(); - e = prism.get_e(); - f = prism.get_f(); + mid = new MVertex(x,y,z,gr); + gr->addMeshVertex(mid); - parts.clear(); - find(a,prism,parts); - find(b,prism,parts); - find(c,prism,parts); - find(d,prism,parts); - find(e,prism,parts); - find(f,prism,parts); + temp2 = new MPyramid(a,b,c,d,mid); + gr->addPyramid(temp2); + markings.insert(std::pair<MElement*,bool>(temp2,false)); + build_vertex_to_pyramids(temp2); - flag = 1; - for(it=parts.begin();it!=parts.end();it++){ - element = *it; - it2 = markings.find(element); - if(it2->second==1 && !sliver(element,prism)){ - flag = 0; - break; + for(it=tetrahedra.begin();it!=tetrahedra.end();it++){ + N1 = other(*it,diagA,diagB); + N2 = other(*it,diagA,diagB,N1); + + if(N1!=0 && N2!=0){ + Ns.insert(N1); + Ns.insert(N2); + + temp = new MTetrahedron(N1,N2,diagA,mid); + gr->addTetrahedron(temp); + markings.insert(std::pair<MElement*,bool>(temp,false)); + build_vertex_to_tetrahedra(temp); + movables.push_back(temp); + + temp = new MTetrahedron(N1,N2,diagB,mid); + gr->addTetrahedron(temp); + markings.insert(std::pair<MElement*,bool>(temp,false)); + build_vertex_to_tetrahedra(temp); + movables.push_back(temp); + + it2 = markings.find(*it); + it2->second = 1; + erase_vertex_to_tetrahedra(*it); } } - if(!flag) continue; - if(!valid(prism,parts)){ - continue; - } + for(it=pyramids.begin();it!=pyramids.end();it++){ + v1 = (*it)->getVertex(0); + v2 = (*it)->getVertex(1); + v3 = (*it)->getVertex(2); + v4 = (*it)->getVertex(3); + v5 = (*it)->getVertex(4); - if(!conformityA(prism)){ - continue; - } + if(v1!=diagA && v1!=diagB){ + Ns.insert(v1); + } + if(v2!=diagA && v2!=diagB){ + Ns.insert(v2); + } + if(v3!=diagA && v3!=diagB){ + Ns.insert(v3); + } + if(v4!=diagA && v4!=diagB){ + Ns.insert(v4); + } + if(v5!=diagA && v5!=diagB){ + Ns.insert(v5); + } - if(!conformityB(prism)){ - continue; - } + temp2 = new MPyramid(v1,v2,v3,v4,mid); + gr->addPyramid(temp2); + markings.insert(std::pair<MElement*,bool>(temp2,false)); + build_vertex_to_pyramids(temp2); - if(!conformityC(prism)){ - continue; - } + if(different(v1,v2,diagA,diagB)){ + temp = new MTetrahedron(v1,v2,mid,v5); + gr->addTetrahedron(temp); + markings.insert(std::pair<MElement*,bool>(temp,false)); + build_vertex_to_tetrahedra(temp); + movables.push_back(temp); + } - if(!faces_statuquo(prism)){ - continue; - } + if(different(v2,v3,diagA,diagB)){ + temp = new MTetrahedron(v2,v3,mid,v5); + gr->addTetrahedron(temp); + markings.insert(std::pair<MElement*,bool>(temp,false)); + build_vertex_to_tetrahedra(temp); + movables.push_back(temp); + } - //printf("%d - %d/%d - %f\n",count,i,(int)potential.size(),prism.get_quality()); - quality = quality + prism.get_quality(); - for(it=parts.begin();it!=parts.end();it++){ - element = *it; - it2 = markings.find(element); - it2->second = 1; - } - gr->addPrism(new MPrism(a,b,c,d,e,f)); - build_hash_tableA(prism); - build_hash_tableB(prism); - build_hash_tableC(prism); - count++; - } + if(different(v3,v4,diagA,diagB)){ + temp = new MTetrahedron(v3,v4,mid,v5); + gr->addTetrahedron(temp); + markings.insert(std::pair<MElement*,bool>(temp,false)); + build_vertex_to_tetrahedra(temp); + movables.push_back(temp); + } - opt.clear(); - opt.resize(gr->tetrahedra.size()); - opt = gr->tetrahedra; - gr->tetrahedra.clear(); + if(different(v4,v1,diagA,diagB)){ + temp = new MTetrahedron(v4,v1,mid,v5); + gr->addTetrahedron(temp); + markings.insert(std::pair<MElement*,bool>(temp,false)); + build_vertex_to_tetrahedra(temp); + movables.push_back(temp); + } - for(i=0;i<opt.size();i++){ - element = (MElement*)(opt[i]); - it2 = markings.find(element); - if(it2->second==0){ - gr->tetrahedra.push_back(opt[i]); + it2 = markings.find(*it); + it2->second = 1; + erase_vertex_to_pyramids(*it); } - } - printf("prisms average quality (0->1) : %f\n",quality/count); + mean(Ns,mid,movables); + } } -void Supplementary::rearrange(GRegion* gr){ - size_t i; +void PostOp::rearrange(GRegion* gr){ + unsigned int i; MElement* element; for(i=0;i<gr->getNumMeshElements();i++){ @@ -2600,35 +5180,71 @@ void Supplementary::rearrange(GRegion* gr){ } } -void Supplementary::statistics(GRegion* gr){ - size_t i; - int all_nbr,prism_nbr; - double all_volume,prism_volume,volume; +void PostOp::statistics(GRegion* gr){ + unsigned int i; MElement* element; - all_nbr = 0; - prism_nbr = 0; - all_volume = 0.0; - prism_volume = 0.0; + nbr = 0; + nbr8 = 0; + nbr6 = 0; + nbr5 = 0; + nbr4 = 0; + vol = 0.0; + vol8 = 0.0; + vol6 = 0.0; + vol5 = 0.0; + vol4 = 0.0; for(i=0;i<gr->getNumMeshElements();i++){ element = gr->getMeshElement(i); - volume = element->getVolume(); + + if(eight(element)){ + nbr8 = nbr8 + 1; + vol8 = vol8 + element->getVolume(); + } if(six(element)){ - prism_nbr = prism_nbr + 1; - prism_volume = prism_volume + volume; + nbr6 = nbr6 + 1; + vol6 = vol6 + element->getVolume(); } - all_nbr = all_nbr + 1; - all_volume = all_volume + volume; + if(five(element)){ + nbr5 = nbr5 + 1; + vol5 = vol5 + workaround(element); + } + + if(four(element)){ + nbr4 = nbr4 + 1; + vol4 = vol4 + element->getVolume(); + } + + nbr = nbr + 1; + + if(!five(element)){ + vol = vol + element->getVolume(); + } + else{ + //vol = vol + workaround(element); + vol = vol + element->getVolume(); + } } - printf("percentage of prisms (number) : %.2f\n",prism_nbr*100.0/all_nbr); - printf("percentage of prisms (volume) : %.2f\n",prism_volume*100.0/all_volume); + printf("Number :\n"); + printf(" percentage of hexahedra : %.2f\n",nbr8*100.0/nbr); + printf(" percentage of prisms : %.2f\n",nbr6*100.0/nbr); + printf(" percentage of pyramids : %.2f\n",nbr5*100.0/nbr); + printf(" percentage of tetrahedra : %.2f\n",nbr4*100.0/nbr); + printf("Volume :\n"); + printf(" percentage of hexahedra : %.2f\n",vol8*100.0/vol); + printf(" percentage of prisms : %.2f\n",vol6*100.0/vol); + printf(" percentage of pyramids : %.2f\n",vol5*100.0/vol); + printf(" percentage of tetrahedra : %.2f\n",vol4*100.0/vol); + printf("Total number of elements : %d\n",gr->getNumMeshElements()); + printf("Total volume : %f\n",vol); + printf("Misc : %d %d %d\n",estimate1,estimate2,iterations); } -void Supplementary::build_tuples(GRegion* gr){ +void PostOp::build_tuples(GRegion* gr){ unsigned int i; MVertex *a,*b,*c; MElement* element; @@ -2660,10 +5276,9 @@ void Supplementary::build_tuples(GRegion* gr){ } } -void Supplementary::modify_surfaces(GRegion* gr){ +void PostOp::modify_surfaces(GRegion* gr){ unsigned int i; - MVertex *a,*b,*c; - MVertex *d,*e,*f; + MVertex *a,*b,*c,*d;//,*e; MElement* element; GFace* gf; std::list<GFace*> faces; @@ -2674,17 +5289,14 @@ void Supplementary::modify_surfaces(GRegion* gr){ for(i=0;i<gr->getNumMeshElements();i++){ element = gr->getMeshElement(i); - if(element->getNumVertices()==6){ + if(element->getNumVertices()==5){ a = element->getVertex(0); b = element->getVertex(1); c = element->getVertex(2); d = element->getVertex(3); - e = element->getVertex(4); - f = element->getVertex(5); + //e = element->getVertex(4); - modify_surfaces(a,d,e,b); - modify_surfaces(a,d,f,c); - modify_surfaces(b,e,f,c); + modify_surfaces(a,b,c,d); } } @@ -2715,7 +5327,7 @@ void Supplementary::modify_surfaces(GRegion* gr){ } } -void Supplementary::modify_surfaces(MVertex* a,MVertex* b,MVertex* c,MVertex* d){ +void PostOp::modify_surfaces(MVertex* a,MVertex* b,MVertex* c,MVertex* d){ bool flag1,flag2; MElement *element1,*element2; GFace *gf1;//,*gf2; @@ -2780,877 +5392,864 @@ void Supplementary::modify_surfaces(MVertex* a,MVertex* b,MVertex* c,MVertex* d) flag2 = 0; while(it1!=tuples.end()){ - if(tuple1.get_hash()!=it1->get_hash()){ - break; - } - - if(tuple1.same_vertices(*it1)){ - flag1 = 1; - element1 = it1->get_element(); - gf1 = it1->get_gf(); - } - - it1++; - } - - while(it2!=tuples.end()){ - if(tuple2.get_hash()!=it2->get_hash()){ - break; - } - - if(tuple2.same_vertices(*it2)){ - flag2 = 1; - element2 = it2->get_element(); - //gf2 = it2->get_gf(); - } - - it2++; - } - - if(flag1 && flag2){ - triangles.insert(element1); - triangles.insert(element2); - - gf1->addQuadrangle(new MQuadrangle(a,b,c,d)); - } -} - -bool Supplementary::four(MElement* element){ - if(element->getNumVertices()==4) return 1; - else return 0; -} - -bool Supplementary::five(MElement* element){ - if(element->getNumVertices()==5) return 1; - else return 0; -} - -bool Supplementary::six(MElement* element){ - if(element->getNumVertices()==6) return 1; - else return 0; -} - -bool Supplementary::eight(MElement* element){ - if(element->getNumVertices()==8) return 1; - else return 0; -} - -bool Supplementary::sliver(MElement* element,Prism prism){ - bool val; - bool flag1,flag2,flag3,flag4; - MVertex *a,*b,*c,*d; - - val = 0; - a = element->getVertex(0); - b = element->getVertex(1); - c = element->getVertex(2); - d = element->getVertex(3); - - flag1 = inclusion(a,prism.get_a(),prism.get_d(),prism.get_f(),prism.get_c()); - flag2 = inclusion(b,prism.get_a(),prism.get_d(),prism.get_f(),prism.get_c()); - flag3 = inclusion(c,prism.get_a(),prism.get_d(),prism.get_f(),prism.get_c()); - flag4 = inclusion(d,prism.get_a(),prism.get_d(),prism.get_f(),prism.get_c()); - if(flag1 && flag2 && flag3 && flag4) val = 1; - - flag1 = inclusion(a,prism.get_a(),prism.get_b(),prism.get_e(),prism.get_d()); - flag2 = inclusion(b,prism.get_a(),prism.get_b(),prism.get_e(),prism.get_d()); - flag3 = inclusion(c,prism.get_a(),prism.get_b(),prism.get_e(),prism.get_d()); - flag4 = inclusion(d,prism.get_a(),prism.get_b(),prism.get_e(),prism.get_d()); - if(flag1 && flag2 && flag3 && flag4) val = 1; - - flag1 = inclusion(a,prism.get_b(),prism.get_c(),prism.get_f(),prism.get_e()); - flag2 = inclusion(b,prism.get_b(),prism.get_c(),prism.get_f(),prism.get_e()); - flag3 = inclusion(c,prism.get_b(),prism.get_c(),prism.get_f(),prism.get_e()); - flag4 = inclusion(d,prism.get_b(),prism.get_c(),prism.get_f(),prism.get_e()); - if(flag1 && flag2 && flag3 && flag4) val = 1; - - return val; -} - -bool Supplementary::valid(Prism prism,const std::set<MElement*>& parts){ - bool ok1,ok2,ok3,ok4; - bool flag1A,flag1B,flag1C,flag1D; - bool flag2A,flag2B,flag2C,flag2D; - bool flag3A,flag3B,flag3C,flag3D; - bool flag4,flag5; - MVertex *a,*b,*c; - MVertex *d,*e,*f; - - a = prism.get_a(); - b = prism.get_b(); - c = prism.get_c(); - d = prism.get_d(); - e = prism.get_e(); - f = prism.get_f(); - - flag1A = inclusion(a,d,f,parts); - flag1B = inclusion(a,f,c,parts); - flag1C = inclusion(a,c,d,parts); - flag1D = inclusion(c,d,f,parts); - ok1 = (flag1A && flag1B) || (flag1C && flag1D); - - flag2A = inclusion(a,b,d,parts); - flag2B = inclusion(b,d,e,parts); - flag2C = inclusion(a,d,e,parts); - flag2D = inclusion(a,b,e,parts); - ok2 = (flag2A && flag2B) || (flag2C && flag2D); - - flag3A = inclusion(b,c,f,parts); - flag3B = inclusion(b,e,f,parts); - flag3C = inclusion(b,c,e,parts); - flag3D = inclusion(c,e,f,parts); - ok3 = (flag3A && flag3B) || (flag3C && flag3D); - - flag4 = inclusion(a,b,c,parts); - flag5 = inclusion(d,e,f,parts); - ok4 = flag4 && flag5; - - if(ok1 && ok2 && ok3 && ok4){ - return 1; - } - else{ - return 0; - } -} - -bool Supplementary::valid(Prism prism){ - double k; - double eta1,eta2,eta3; - MVertex *a,*b,*c; - MVertex *d,*e,*f; - - k = 0.000001; - - a = prism.get_a(); - b = prism.get_b(); - c = prism.get_c(); - d = prism.get_d(); - e = prism.get_e(); - f = prism.get_f(); - - eta1 = eta(a,d,f,c); - eta2 = eta(a,b,e,d); - eta3 = eta(b,c,f,e); - - if(eta1>k && eta2>k && eta3>k){ - return 1; - } - else{ - return 0; - } -} - -double Supplementary::eta(MVertex* a,MVertex* b,MVertex* c,MVertex* d){ - double val; - MQuadrangle* quad; - - quad = new MQuadrangle(a,b,c,d); - val = quad->etaShapeMeasure(); - delete quad; - return val; -} - -bool Supplementary::linked(MVertex* v1,MVertex* v2){ - bool flag; - std::map<MVertex*,std::set<MVertex*> >::iterator it; - std::set<MVertex*>::iterator it2; - - it = vertex_to_vertices.find(v1); - flag = 0; - - if(it!=vertex_to_vertices.end()){ - for(it2=(it->second).begin();it2!=(it->second).end();it2++){ - if(*it2==v2){ - flag = 1; - break; - } - } - } - - return flag; -} - -void Supplementary::find(MVertex* v1,MVertex* v2,const std::vector<MVertex*>& already,std::set<MVertex*>& final){ - std::map<MVertex*,std::set<MVertex*> >::iterator it1; - std::map<MVertex*,std::set<MVertex*> >::iterator it2; - - it1 = vertex_to_vertices.find(v1); - it2 = vertex_to_vertices.find(v2); - - if(it1!=vertex_to_vertices.end() && it2!=vertex_to_vertices.end()){ - intersection(it1->second,it2->second,already,final); - } -} - -void Supplementary::find(MVertex* vertex,Prism prism,std::set<MElement*>& final){ - bool flag1,flag2,flag3,flag4; - MVertex *a,*b,*c,*d; - std::map<MVertex*,std::set<MElement*> >::iterator it; - std::set<MElement*>::iterator it2; - - it = vertex_to_tetrahedra.find(vertex); - - if(it!=vertex_to_tetrahedra.end()){ - for(it2=(it->second).begin();it2!=(it->second).end();it2++){ - a = (*it2)->getVertex(0); - b = (*it2)->getVertex(1); - c = (*it2)->getVertex(2); - d = (*it2)->getVertex(3); - - flag1 = inclusion(a,prism); - flag2 = inclusion(b,prism); - flag3 = inclusion(c,prism); - flag4 = inclusion(d,prism); - - if(flag1 && flag2 && flag3 && flag4){ - final.insert(*it2); - } - } - } -} - -void Supplementary::intersection(const std::set<MVertex*>& bin1,const std::set<MVertex*>& bin2, - const std::vector<MVertex*>& already,std::set<MVertex*>& final){ - size_t i; - bool ok; - std::set<MVertex*> temp; - std::set<MVertex*>::iterator it; + if(tuple1.get_hash()!=it1->get_hash()){ + break; + } - std::set_intersection(bin1.begin(),bin1.end(),bin2.begin(),bin2.end(),std::inserter(temp,temp.end())); + if(tuple1.same_vertices(*it1)){ + flag1 = 1; + element1 = it1->get_element(); + gf1 = it1->get_gf(); + } - for(it=temp.begin();it!=temp.end();it++){ - ok = 1; + it1++; + } - for(i=0;i<already.size();i++){ - if((*it)==already[i]){ - ok = 0; - break; - } + while(it2!=tuples.end()){ + if(tuple2.get_hash()!=it2->get_hash()){ + break; } - if(ok){ - final.insert(*it); + if(tuple2.same_vertices(*it2)){ + flag2 = 1; + element2 = it2->get_element(); + //gf2 = it2->get_gf(); } + + it2++; } -} -bool Supplementary::inclusion(MVertex* vertex,Prism prism){ - bool flag; + if(flag1 && flag2){ + triangles.insert(element1); + triangles.insert(element2); - flag = 0; + gf1->addQuadrangle(new MQuadrangle(a,b,c,d)); + } +} - if(vertex==prism.get_a()) flag = 1; - else if(vertex==prism.get_b()) flag = 1; - else if(vertex==prism.get_c()) flag = 1; - else if(vertex==prism.get_d()) flag = 1; - else if(vertex==prism.get_e()) flag = 1; - else if(vertex==prism.get_f()) flag = 1; +bool PostOp::four(MElement* element){ + if(element->getNumVertices()==4) return 1; + else return 0; +} - return flag; +bool PostOp::five(MElement* element){ + if(element->getNumVertices()==5) return 1; + else return 0; } -bool Supplementary::inclusion(MVertex* vertex,MVertex* a,MVertex* b,MVertex* c,MVertex* d){ - bool flag; +bool PostOp::six(MElement* element){ + if(element->getNumVertices()==6) return 1; + else return 0; +} - flag = 0; +bool PostOp::eight(MElement* element){ + if(element->getNumVertices()==8) return 1; + else return 0; +} - if(vertex==a) flag = 1; - else if(vertex==b) flag = 1; - else if(vertex==c) flag = 1; - else if(vertex==d) flag = 1; +bool PostOp::equal(MVertex* v1,MVertex* v2,MVertex* v3,MVertex* v4){ + if((v1==v3 && v2==v4) || (v1==v4 && v2==v3)){ + return 1; + } + else{ + return 0; + } +} - return flag; +bool PostOp::different(MVertex* v1,MVertex* v2,MVertex* v3,MVertex* v4){ + if(v1!=v3 && v1!=v4 && v2!=v3 && v2!=v4){ + return 1; + } + else{ + return 0; + } } -bool Supplementary::inclusion(MVertex* v1,MVertex* v2,MVertex* v3,const std::set<MElement*>& bin){ - bool ok; - bool flag1,flag2,flag3; - MVertex *a,*b,*c,*d; - MElement* element; - std::set<MElement*>::const_iterator it; +MVertex* PostOp::other(MElement* element,MVertex* v1,MVertex* v2){ + int i; + MVertex* vertex; + MVertex* pointer; - ok = 0; + pointer = 0; - for(it=bin.begin();it!=bin.end();it++){ - element = *it; + for(i=0;i<element->getNumVertices();i++){ + vertex = element->getVertex(i); + if(vertex!=v1 && vertex!=v2){ + pointer = vertex; + break; + } + } - a = element->getVertex(0); - b = element->getVertex(1); - c = element->getVertex(2); - d = element->getVertex(3); + return pointer; +} - flag1 = inclusion(v1,a,b,c,d); - flag2 = inclusion(v2,a,b,c,d); - flag3 = inclusion(v3,a,b,c,d); +MVertex* PostOp::other(MElement* element,MVertex* v1,MVertex* v2,MVertex* v3){ + int i; + MVertex* vertex; + MVertex* pointer; - if(flag1 && flag2 && flag3){ - ok = 1; + pointer = 0; + + for(i=0;i<element->getNumVertices();i++){ + vertex = element->getVertex(i); + if(vertex!=v1 && vertex!=v2 && vertex!=v3){ + pointer = vertex; break; } } - return ok; + return pointer; } -bool Supplementary::inclusion(Facet facet){ +void PostOp::mean(const std::set<MVertex*>& Ns,MVertex* mid,const std::vector<MElement*>& movables){ + unsigned int i; + int j; bool flag; - std::multiset<Facet>::iterator it; - - it = hash_tableA.find(facet); - flag = 0; + double x,y,z; + double init_x,init_y,init_z; + std::set<MVertex*>::const_iterator it; - while(it!=hash_tableA.end()){ - if(facet.get_hash()!=it->get_hash()){ - break; - } + x = 0.0; + y = 0.0; + z = 0.0; - if(facet.same_vertices(*it)){ - flag = 1; - break; - } + init_x = mid->x(); + init_y = mid->y(); + init_z = mid->z(); - it++; + for(it=Ns.begin();it!=Ns.end();it++){ + x = x + (*it)->x(); + y = y + (*it)->y(); + z = z + (*it)->z(); } - return flag; -} + x = x/Ns.size(); + y = y/Ns.size(); + z = z/Ns.size(); -bool Supplementary::inclusion(Diagonal diagonal){ - bool flag; - std::multiset<Diagonal>::iterator it; + for(i=0;i<movables.size();i++){ + movables[i]->setVolumePositive(); + } - it = hash_tableB.find(diagonal); - flag = 0; + mid->setXYZ(x,y,z); - while(it!=hash_tableB.end()){ - if(diagonal.get_hash()!=it->get_hash()){ - break; + for(j=0;j<100;j++){ + flag = 0; + + for(i=0;i<movables.size();i++){ + if(movables[i]->getVolume()<0.0){ + flag = 1; + } } - if(diagonal.same_vertices(*it)){ - flag = 1; + if(!flag){ break; } - it++; - } + x = 0.1*init_x + 0.9*mid->x(); + y = 0.1*init_y + 0.9*mid->y(); + z = 0.1*init_z + 0.9*mid->z(); - return flag; -} + mid->setXYZ(x,y,z); + } -bool Supplementary::duplicate(Diagonal diagonal){ - bool flag; - std::multiset<Diagonal>::iterator it; + iterations = iterations + j; - it = hash_tableC.find(diagonal); - flag = 0; + for(j=0;j<6;j++){ + flag = 0; - while(it!=hash_tableC.end()){ - if(diagonal.get_hash()!=it->get_hash()){ - break; + for(i=0;i<movables.size();i++){ + if(movables[i]->gammaShapeMeasure()<0.2){ + flag = 1; + } } - if(diagonal.same_vertices(*it)){ - flag = 1; + if(!flag){ break; } - it++; + x = 0.1*init_x + 0.9*mid->x(); + y = 0.1*init_y + 0.9*mid->y(); + z = 0.1*init_z + 0.9*mid->z(); + + mid->setXYZ(x,y,z); } - return flag; + iterations = iterations + j; } -bool Supplementary::conformityA(Prism prism){ - bool c1,c2,c3; - MVertex *a,*b,*c; - MVertex *d,*e,*f; - - a = prism.get_a(); - b = prism.get_b(); - c = prism.get_c(); - d = prism.get_d(); - e = prism.get_e(); - f = prism.get_f(); - - c1 = conformityA(a,d,f,c); - c2 = conformityA(a,d,e,b); - c3 = conformityA(b,c,f,e); - - return c1 && c2 && c3; -} +double PostOp::workaround(MElement* element){ + double volume; + MTetrahedron* temp1; + MTetrahedron* temp2; -bool Supplementary::conformityA(MVertex* a,MVertex* b,MVertex* c,MVertex* d){ - bool c1,c2,c3,c4; + volume = 0.0; - c1 = inclusion(Facet(a,b,c)); - c2 = inclusion(Facet(a,c,d)); - c3 = inclusion(Facet(a,b,d)); - c4 = inclusion(Facet(b,c,d)); + if(five(element)){ + temp1 = new MTetrahedron(element->getVertex(0),element->getVertex(1),element->getVertex(2),element->getVertex(4)); + temp2 = new MTetrahedron(element->getVertex(2),element->getVertex(3),element->getVertex(0),element->getVertex(4)); + volume = fabs(temp1->getVolume()) + fabs(temp2->getVolume()); + delete temp1; + delete temp2; + } - return (c1 && c2 && c3 && c4) || (!c1 && !c2 && !c3 && !c4); + return volume; } -bool Supplementary::conformityB(Prism prism){ - bool flag1; - bool flag2; - bool c1,c2,c3; - bool c4,c5,c6; - MVertex *a,*b,*c; - MVertex *d,*e,*f; - - a = prism.get_a(); - b = prism.get_b(); - c = prism.get_c(); - d = prism.get_d(); - e = prism.get_e(); - f = prism.get_f(); - - flag1 = inclusion(Diagonal(a,c)); - flag1 = flag1 || inclusion(Diagonal(d,f)); - flag1 = flag1 || inclusion(Diagonal(d,a)); - flag1 = flag1 || inclusion(Diagonal(f,c)); - flag1 = flag1 || inclusion(Diagonal(e,b)); - flag1 = flag1 || inclusion(Diagonal(d,e)); - flag1 = flag1 || inclusion(Diagonal(e,f)); - flag1 = flag1 || inclusion(Diagonal(a,b)); - flag1 = flag1 || inclusion(Diagonal(b,c)); +MVertex* PostOp::find(MVertex* v1,MVertex* v2,MVertex* v3,MVertex* v4,MElement* element){ + int i; + MVertex* vertex; + MVertex* pointer; - c1 = inclusion(Diagonal(a,f)); - c2 = inclusion(Diagonal(d,c)); - flag2 = (c1 && !c2) || (!c1 && c2); - c3 = inclusion(Diagonal(a,e)); - c4 = inclusion(Diagonal(b,d)); - flag2 = flag2 || (c3 && !c4) || (!c3 && c4); - c5 = inclusion(Diagonal(b,f)); - c6 = inclusion(Diagonal(c,e)); - flag2 = flag2 || (c5 && !c6) || (!c5 && c6); + pointer = 0; - if(flag1 || flag2){ - return 0; - } - else{ - return 1; + for(i=0;i<element->getNumVertices();i++){ + vertex = element->getVertex(i); + if(vertex!=v1 && vertex!=v2 && vertex!=v3 && vertex!=v4){ + pointer = vertex; + break; + } } -} -bool Supplementary::conformityC(Prism prism){ - bool flag; - MVertex *a,*b,*c; - MVertex *d,*e,*f; + return pointer; +} - a = prism.get_a(); - b = prism.get_b(); - c = prism.get_c(); - d = prism.get_d(); - e = prism.get_e(); - f = prism.get_f(); +void PostOp::find_tetrahedra(MVertex* v1,MVertex* v2,std::set<MElement*>& final){ + std::map<MVertex*,std::set<MElement*> >::iterator it1; + std::map<MVertex*,std::set<MElement*> >::iterator it2; - flag = duplicate(Diagonal(a,f)); - flag = flag || duplicate(Diagonal(d,c)); - flag = flag || duplicate(Diagonal(a,e)); - flag = flag || duplicate(Diagonal(b,d)); - flag = flag || duplicate(Diagonal(b,f)); - flag = flag || duplicate(Diagonal(c,e)); + it1 = vertex_to_tetrahedra.find(v1); + it2 = vertex_to_tetrahedra.find(v2); - if(flag){ - return 0; - } - else{ - return 1; + if(it1!=vertex_to_tetrahedra.end() && it2!=vertex_to_tetrahedra.end()){ + intersection(it1->second,it2->second,final); } } -bool Supplementary::faces_statuquo(Prism prism){ - bool c1,c2,c3; - MVertex *a,*b,*c; - MVertex *d,*e,*f; +void PostOp::find_pyramids(MVertex* v1,MVertex* v2,std::set<MElement*>& final){ + bool flag1,flag2,flag3,flag4; + bool flag5,flag6,flag7,flag8; + std::set<MElement*>::iterator it; + std::map<MVertex*,std::set<MElement*> >::iterator it1; + std::map<MVertex*,std::set<MElement*> >::iterator it2; + std::set<MElement*> temp; - a = prism.get_a(); - b = prism.get_b(); - c = prism.get_c(); - d = prism.get_d(); - e = prism.get_e(); - f = prism.get_f(); + it1 = vertex_to_pyramids.find(v1); + it2 = vertex_to_pyramids.find(v2); - c1 = faces_statuquo(a,d,f,c); - c2 = faces_statuquo(a,d,e,b); - c3 = faces_statuquo(b,c,f,e); + temp.clear(); - return c1 && c2 && c3; + if(it1!=vertex_to_pyramids.end() && it2!=vertex_to_pyramids.end()){ + intersection(it1->second,it2->second,temp); + } + + for(it=temp.begin();it!=temp.end();it++){ + flag1 = equal(v1,v2,(*it)->getVertex(0),(*it)->getVertex(1)); + flag2 = equal(v1,v2,(*it)->getVertex(1),(*it)->getVertex(2)); + flag3 = equal(v1,v2,(*it)->getVertex(2),(*it)->getVertex(3)); + flag4 = equal(v1,v2,(*it)->getVertex(3),(*it)->getVertex(0)); + flag5 = equal(v1,v2,(*it)->getVertex(0),(*it)->getVertex(4)); + flag6 = equal(v1,v2,(*it)->getVertex(1),(*it)->getVertex(4)); + flag7 = equal(v1,v2,(*it)->getVertex(2),(*it)->getVertex(4)); + flag8 = equal(v1,v2,(*it)->getVertex(3),(*it)->getVertex(4)); + if(flag1 || flag2 || flag3 || flag4 || flag5 || flag6 || flag7 || flag8){ + final.insert(*it); + } + } } -bool Supplementary::faces_statuquo(MVertex* a,MVertex* b,MVertex* c,MVertex* d){ - bool ok; - bool flag1,flag2; - GFace *gf1,*gf2; - Tuple tuple1,tuple2; - std::multiset<Tuple>::iterator it1; - std::multiset<Tuple>::iterator it2; +void PostOp::intersection(const std::set<MElement*>& bin1,const std::set<MElement*>& bin2,std::set<MElement*>& final){ + std::set_intersection(bin1.begin(),bin1.end(),bin2.begin(),bin2.end(),std::inserter(final,final.end())); +} - ok = 1; +void PostOp::build_vertex_to_tetrahedra(GRegion* gr){ + unsigned int i; + MElement* element; - gf1 = NULL; - gf2 = NULL; + vertex_to_tetrahedra.clear(); - tuple1 = Tuple(a,b,c); - tuple2 = Tuple(c,d,a); + for(i=0;i<gr->getNumMeshElements();i++){ + element = gr->getMeshElement(i); + if(four(element)){ + build_vertex_to_tetrahedra(element); + } + } +} - it1 = tuples.find(tuple1); - it2 = tuples.find(tuple2); +void PostOp::build_vertex_to_tetrahedra(MElement* element){ + int i; + MVertex* vertex; + std::set<MElement*> bin; + std::map<MVertex*,std::set<MElement*> >::iterator it; - flag1 = 0; - flag2 = 0; + for(i=0;i<element->getNumVertices();i++){ + vertex = element->getVertex(i); - while(it1!=tuples.end()){ - if(tuple1.get_hash()!=it1->get_hash()){ - break; + it = vertex_to_tetrahedra.find(vertex); + if(it!=vertex_to_tetrahedra.end()){ + it->second.insert(element); } - - if(tuple1.same_vertices(*it1)){ - flag1 = 1; - gf1 = it1->get_gf(); + else{ + bin.clear(); + bin.insert(element); + vertex_to_tetrahedra.insert(std::pair<MVertex*,std::set<MElement*> >(vertex,bin)); } - - it1++; } +} - while(it2!=tuples.end()){ - if(tuple2.get_hash()!=it2->get_hash()){ - break; - } +void PostOp::erase_vertex_to_tetrahedra(MElement* element){ + int i; + MVertex* vertex; + std::map<MVertex*,std::set<MElement*> >::iterator it; - if(tuple2.same_vertices(*it2)){ - flag2 = 1; - gf2 = it2->get_gf(); - } + for(i=0;i<element->getNumVertices();i++){ + vertex = element->getVertex(i); - it2++; + it = vertex_to_tetrahedra.find(vertex); + if(it!=vertex_to_tetrahedra.end()){ + it->second.erase(element); + } } +} - if(flag1 && flag2){ - if(gf1!=gf2){ - ok = 0; +void PostOp::build_vertex_to_pyramids(GRegion* gr){ + unsigned int i; + MElement* element; + + vertex_to_pyramids.clear(); + + for(i=0;i<gr->getNumMeshElements();i++){ + element = gr->getMeshElement(i); + if(five(element)){ + build_vertex_to_pyramids(element); } } +} - tuple1 = Tuple(a,b,d); - tuple2 = Tuple(b,c,d); - - it1 = tuples.find(tuple1); - it2 = tuples.find(tuple2); +void PostOp::build_vertex_to_pyramids(MElement* element){ + int i; + MVertex* vertex; + std::set<MElement*> bin; + std::map<MVertex*,std::set<MElement*> >::iterator it; - flag1 = 0; - flag2 = 0; + for(i=0;i<element->getNumVertices();i++){ + vertex = element->getVertex(i); - while(it1!=tuples.end()){ - if(tuple1.get_hash()!=it1->get_hash()){ - break; + it = vertex_to_pyramids.find(vertex); + if(it!=vertex_to_pyramids.end()){ + it->second.insert(element); } - - if(tuple1.same_vertices(*it1)){ - flag1 = 1; - gf1 = it1->get_gf(); + else{ + bin.clear(); + bin.insert(element); + vertex_to_pyramids.insert(std::pair<MVertex*,std::set<MElement*> >(vertex,bin)); } - - it1++; } +} - while(it2!=tuples.end()){ - if(tuple2.get_hash()!=it2->get_hash()){ - break; +void PostOp::erase_vertex_to_pyramids(MElement* element){ + int i; + MVertex* vertex; + std::map<MVertex*,std::set<MElement*> >::iterator it; + + for(i=0;i<element->getNumVertices();i++){ + vertex = element->getVertex(i); + + it = vertex_to_pyramids.find(vertex); + if(it!=vertex_to_pyramids.end()){ + it->second.erase(element); } + } +} - if(tuple2.same_vertices(*it2)){ - flag2 = 1; - gf2 = it2->get_gf(); - } +// -------------------------------------------------------------------- - it2++; - } +void Recombinator_Graph::pattern1(GRegion* gr){ + int size_init = hex_to_tet.size(); + size_t i; + int index; + double quality; + MElement* element; + MVertex *a,*b,*c,*d; + MVertex *p,*q,*r,*s; + std::vector<MVertex*> already; + std::set<MVertex*> bin1; + std::set<MVertex*> bin2; + std::set<MVertex*> bin3; + std::set<MVertex*> bin4; + std::set<MVertex*>::iterator it1; + std::set<MVertex*>::iterator it2; + std::set<MVertex*>::iterator it3; + std::set<MVertex*>::iterator it4; + Hex *hex; - if(flag1 && flag2){ - if(gf1!=gf2){ - ok = 0; + for(i=0;i<gr->getNumMeshElements();i++){ + element = gr->getMeshElement(i); + // max_scaled_jacobian(element,index); + // todo: ici, boucle sur index + for (index = 0;index<4;index++){ + + a = element->getVertex(index); + b = element->getVertex((index+1)%4); + c = element->getVertex((index+2)%4); + d = element->getVertex((index+3)%4); + + already.clear(); + already.push_back(a); + already.push_back(b); + already.push_back(c); + already.push_back(d); + bin1.clear(); + bin2.clear(); + bin3.clear(); + find(b,d,already,bin1); + find(b,c,already,bin2); + find(c,d,already,bin3); + + for(it1=bin1.begin();it1!=bin1.end();it1++){ + p = *it1; + for(it2=bin2.begin();it2!=bin2.end();it2++){ + q = *it2; + for(it3=bin3.begin();it3!=bin3.end();it3++){ + r = *it3; + if(p!=q && p!=r && q!=r){ + already.clear(); + already.push_back(a); + already.push_back(b); + already.push_back(c); + already.push_back(d); + already.push_back(p); + already.push_back(q); + already.push_back(r); + bin4.clear(); + find(p,q,r,already,bin4); + for(it4=bin4.begin();it4!=bin4.end();it4++){ + s = *it4; + hex = new Hex(a,b,q,c,d,p,s,r); + quality = min_scaled_jacobian(*hex); + hex->set_quality(quality); + fill_tet_to_hex_table(hex); + } + } + } + } + } } } - - return ok; + cout << "Nb of hex found, pattern1: " << hex_to_tet.size()-size_init << endl; } -void Supplementary::build_vertex_to_vertices(GRegion* gr){ +// -------------------------------------------------------------------- + +void Recombinator_Graph::pattern2(GRegion* gr){ + int size_init = hex_to_tet.size(); size_t i; - int j; + int index1,index2,index3,index4; + double quality; MElement* element; MVertex *a,*b,*c,*d; - std::set<MVertex*> bin; - std::map<MVertex*,std::set<MVertex*> >::iterator it; - - vertex_to_vertices.clear(); + MVertex *p,*q,*r,*s; + std::set<MElement*> verif; + Hex *hex; for(i=0;i<gr->getNumMeshElements();i++){ element = gr->getMeshElement(i); - if(four(element)){ - for(j=0;j<element->getNumVertices();j++){ - a = element->getVertex(j); - b = element->getVertex((j+1)%4); - c = element->getVertex((j+2)%4); - d = element->getVertex((j+3)%4); - - it = vertex_to_vertices.find(a); - if(it!=vertex_to_vertices.end()){ - it->second.insert(b); - it->second.insert(c); - it->second.insert(d); - } - else{ - bin.clear(); - bin.insert(b); - bin.insert(c); - bin.insert(d); - vertex_to_vertices.insert(std::pair<MVertex*,std::set<MVertex*> >(a,bin)); + //diagonal(element,index1,index2); + // todo: ici, boucle sur index + for (index1=0;index1<4;index1++){ + for (index2=index1+1;index2<4;index2++){ + two_others(index1,index2,index3,index4); + + b = element->getVertex(index1); + d = element->getVertex(index2); + a = element->getVertex(index3); + c = element->getVertex(index4); + + verif.clear(); + find(b,d,verif); + if(verif.size()==6){ + s = find(a,b,d,c,verif); + p = find(b,c,d,a,verif); + if(s!=0 && p!=0){ + r = find(s,b,d,a,verif); + q = find(p,b,d,c,verif); + if(r!=0 && q!=0){ + hex = new Hex(a,s,b,c,d,r,q,p); + quality = min_scaled_jacobian(*hex); + hex->set_quality(quality); + fill_tet_to_hex_table(hex); + + hex = new Hex(a,c,d,s,b,p,q,r); + quality = min_scaled_jacobian(*hex); + hex->set_quality(quality); + fill_tet_to_hex_table(hex); + } + } } } } } + cout << "Nb of hex found, pattern2: " << hex_to_tet.size()-size_init << endl; } -void Supplementary::build_vertex_to_tetrahedra(GRegion* gr){ - unsigned int i; - int j; - MElement* element; - MVertex* vertex; - std::set<MElement*> bin; - std::map<MVertex*,std::set<MElement*> >::iterator it; +// -------------------------------------------------------------------- - vertex_to_tetrahedra.clear(); +void Recombinator_Graph::pattern3(GRegion* gr){ + int size_init = hex_to_tet.size(); + size_t i; + int index1,index2,index3,index4; + bool c1,c2,c3,c4,c5; + bool c6,c7,c8,c9,c10; + double quality; + MElement* element; + MVertex *a,*b,*c,*d; + MVertex *p,*q,*r,*s; + MVertex *fA,*fB,*bA,*bB; + std::set<MElement*> verif1; + std::set<MElement*> verif2; + Hex *hex; for(i=0;i<gr->getNumMeshElements();i++){ element = gr->getMeshElement(i); - if(four(element)){ - for(j=0;j<element->getNumVertices();j++){ - vertex = element->getVertex(j); + //diagonal(element,index1,index2); + // todo: ici, boucle sur index + for (index1=0;index1<4;index1++){ + for (index2=index1+1;index2<4;index2++){ + two_others(index1,index2,index3,index4); + + b = element->getVertex(index1); + d = element->getVertex(index2); + a = element->getVertex(index3); + c = element->getVertex(index4); + + verif1.clear(); + verif2.clear(); + find(b,d,verif1); + find(a,c,verif2); + + if(verif1.size()==4 && verif2.size()==4){ + fA = find(b,d,a,c,verif1); + fB = find(b,d,c,a,verif1); + bA = find(a,c,b,d,verif2); + bB = find(a,c,d,b,verif2); + + if(fA!=0 && fB!=0 && bA!=0 && bB!=0 && fA!=fB && bA!=bB){ + if(scalar(fA,fB,a,b)>scalar(fA,fB,b,c) && scalar(bA,bB,a,b)>scalar(bA,bB,b,c)){ + if(distance(fA,b,c)<distance(fB,b,c)){ + p = fA; + q = fB; + } + else{ + p = fB; + q = fA; + } - it = vertex_to_tetrahedra.find(vertex); - if(it!=vertex_to_tetrahedra.end()){ - it->second.insert(element); - } - else{ - bin.clear(); - bin.insert(element); - vertex_to_tetrahedra.insert(std::pair<MVertex*,std::set<MElement*> >(vertex,bin)); + if(distance(bA,b,c)<distance(bB,b,c)){ + r = bA; + s = bB; + } + else{ + r = bB; + s = bA; + } + + c1 = linked(b,p); + c2 = linked(c,p); + c3 = linked(p,q); + c4 = linked(a,q); + c5 = linked(d,q); + + c6 = linked(b,r); + c7 = linked(c,r); + c8 = linked(r,s); + c9 = linked(a,s); + c10 = linked(d,s); + + if(c1 && c2 && c3 && c4 && c5 && c6 && c7 && c8 && c9 && c10){ + hex = new Hex(p,c,r,b,q,d,s,a); + quality = min_scaled_jacobian(*hex); + hex->set_quality(quality); + fill_tet_to_hex_table(hex); + } + } + else if(scalar(fA,fB,a,b)<=scalar(fA,fB,b,c) && scalar(bA,bB,a,b)<=scalar(bA,bB,b,c)){ + if(distance(fA,a,b)<distance(fB,a,b)){ + p = fA; + q = fB; + } + else{ + p = fB; + q = fA; + } + + if(distance(bA,a,b)<distance(bB,a,b)){ + r = bA; + s = bB; + } + else{ + r = bB; + s = bA; + } + + c1 = linked(b,p); + c2 = linked(a,p); + c3 = linked(p,q); + c4 = linked(c,q); + c5 = linked(d,q); + + c6 = linked(b,r); + c7 = linked(a,r); + c8 = linked(r,s); + c9 = linked(c,s); + c10 = linked(d,s); + + if(c1 && c2 && c3 && c4 && c5 && c6 && c7 && c8 && c9 && c10){ + hex = new Hex(p,b,r,a,q,c,s,d); + quality = min_scaled_jacobian(*hex); + hex->set_quality(quality); + fill_tet_to_hex_table(hex); + } + } + } } } } } + cout << "Nb of hex found, pattern3: " << hex_to_tet.size()-size_init << endl; } -void Supplementary::build_hash_tableA(Prism prism){ - MVertex *a,*b,*c; - MVertex *d,*e,*f; - - a = prism.get_a(); - b = prism.get_b(); - c = prism.get_c(); - d = prism.get_d(); - e = prism.get_e(); - f = prism.get_f(); +// -------------------------------------------------------------------- - build_hash_tableA(a,d,f,c); - build_hash_tableA(a,d,e,b); - build_hash_tableA(b,c,f,e); -} +// check if hex is ok, and insert in "potential" table +void Recombinator_Graph::fill_tet_to_hex_table(Hex *hex){ + const bool very_verbose = false; -void Supplementary::build_hash_tableA(MVertex* a,MVertex* b,MVertex* c,MVertex* d){ - build_hash_tableA(Facet(a,b,c)); - build_hash_tableA(Facet(a,c,d)); - build_hash_tableA(Facet(a,b,d)); - build_hash_tableA(Facet(b,d,c)); -} + const bool bypass=true; -void Supplementary::build_hash_tableA(Facet facet){ - bool flag; - std::multiset<Facet>::iterator it; - it = hash_tableA.find(facet); - flag = 1; + if (very_verbose){ + cout << " fill_tet_to_hex_table:: treating hex " << hex << " made of "; + for (int i=0;i<8;i++) + cout << " " << hex->getVertex(i)->getNum(); + cout << endl; + } - while(it!=hash_tableA.end()){ - if(facet.get_hash()!=it->get_hash()){ - break; - } - if(facet.same_vertices(*it)){ - flag = 0; - break; - } + if (!valid(*hex)){ + if (very_verbose) cout << "NOT VALID hex !!! " << endl; + delete hex; + return; + } - it++; + MElement *element; + std::set<MElement*> parts; + // recovering all the tets forming the current hex + parts.clear(); + find(hex->get_a(),*hex,parts); + find(hex->get_b(),*hex,parts); + find(hex->get_c(),*hex,parts); + find(hex->get_d(),*hex,parts); + find(hex->get_e(),*hex,parts); + find(hex->get_f(),*hex,parts); + find(hex->get_g(),*hex,parts); + find(hex->get_h(),*hex,parts); + + if(!valid(*hex,parts)){ + if (very_verbose) cout << " NOT VALID hex (parts) " << endl; + delete hex; + return; } - if(flag){ - hash_tableA.insert(facet); + // storing all tets in tet_to_hex database (for use in indirect neighbors) + // first, check if the hex has the right number of vertices (=8 !!!) + // non, c'est pas toujours le cas !!! ??? + + set<MVertex*> vertices; + for(std::set<MElement*>::iterator it=parts.begin();it!=parts.end();it++){ + element = *it; + for (int i=0;i<4;i++){ + vertices.insert(element->getVertex(i)); + } } -} -void Supplementary::build_hash_tableB(Prism prism){ - MVertex *a,*b,*c; - MVertex *d,*e,*f; + if (vertices.size()!=8){ + if (very_verbose) cout << "------------- WARNING !!!!! An hex has " << vertices.size() << "vertices" << endl; + delete hex; + return; + } - a = prism.get_a(); - b = prism.get_b(); - c = prism.get_c(); - d = prism.get_d(); - e = prism.get_e(); - f = prism.get_f(); - build_hash_tableB(a,d,f,c); - build_hash_tableB(a,d,e,b); - build_hash_tableB(b,e,f,c); -} -void Supplementary::build_hash_tableB(MVertex* a,MVertex* b,MVertex* c,MVertex* d){ - build_hash_tableB(Diagonal(a,c)); - build_hash_tableB(Diagonal(b,d)); -} + // TODO !!!! TODO !!!! TODO !!!! TODO !!!! TODO !!!! TODO !!!! TODO !!!! TODO !!!! TODO !!!! TODO !!!! TODO !!!! TODO !!!! TODO !!!! TODO !!!! + // TODO !!!! TODO !!!! TODO !!!! TODO !!!! TODO !!!! TODO !!!! TODO !!!! TODO !!!! TODO !!!! TODO !!!! TODO !!!! TODO !!!! TODO !!!! TODO !!!! + // TODO !!!! TODO !!!! TODO !!!! TODO !!!! TODO !!!! TODO !!!! TODO !!!! TODO !!!! TODO !!!! TODO !!!! TODO !!!! TODO !!!! TODO !!!! TODO !!!! + // TODO !!!! TODO !!!! TODO !!!! TODO !!!! TODO !!!! TODO !!!! TODO !!!! TODO !!!! TODO !!!! TODO !!!! TODO !!!! TODO !!!! TODO !!!! TODO !!!! + // le test suivant déconne, cf. cube à 125 hex... sais pas pourquoi, mais ça élimine des hex potentiels tout à fait valides (et nécessaires à la solution optimale)!!! + // dans le cas cube125: ce test fait passer le #hex potentiels recensés par les patterns de recombinaison d'environ 1000 à 2434 ??? !!!, ça double aussi le nbre d'hex dans le graphe des pertes + // en fait, si les noeuds par exemple a b c d deviennent b c d a, on a une rotation et un hex tout pourri... mais qui a même hash et mêmes noeuds ?!?! + // now, check if the hex already exists... + if (!bypass){ + std::multimap<unsigned long long, Hex* >::const_iterator itfind = find_the_created_potential_hex(hex,created_potential_hex); + if (itfind!=created_potential_hex.end()){ + delete hex; + if (very_verbose) cout << "------------- WARNING !!!!! fill_tet_to_hex_table:: current hex already exists in the created potentiel hex database. Not adding the hex." << endl; + return; + } + } + // TODO !!!! TODO !!!! TODO !!!! TODO !!!! TODO !!!! TODO !!!! TODO !!!! TODO !!!! TODO !!!! TODO !!!! TODO !!!! TODO !!!! TODO !!!! TODO !!!! + // TODO !!!! TODO !!!! TODO !!!! TODO !!!! TODO !!!! TODO !!!! TODO !!!! TODO !!!! TODO !!!! TODO !!!! TODO !!!! TODO !!!! TODO !!!! TODO !!!! + // TODO !!!! TODO !!!! TODO !!!! TODO !!!! TODO !!!! TODO !!!! TODO !!!! TODO !!!! TODO !!!! TODO !!!! TODO !!!! TODO !!!! TODO !!!! TODO !!!! + // TODO !!!! TODO !!!! TODO !!!! TODO !!!! TODO !!!! TODO !!!! TODO !!!! TODO !!!! TODO !!!! TODO !!!! TODO !!!! TODO !!!! TODO !!!! TODO !!!! -void Supplementary::build_hash_tableB(Diagonal diagonal){ - bool flag; - std::multiset<Diagonal>::iterator it; - it = hash_tableB.find(diagonal); - flag = 1; - while(it!=hash_tableB.end()){ - if(diagonal.get_hash()!=it->get_hash()){ - break; + // counting the number of triangular external faces. If different from 12, discard the hex ! + // if not, build the face/hex table + std::multimap<unsigned long long, pair<PETriangle*,int> > faces_temp; + for(std::set<MElement*>::iterator it_tet=parts.begin();it_tet!=parts.end();it_tet++){// for all tets + for (int i=0;i<4;i++){// for all faces + MFace f = (*it_tet)->getFace(i); + add_face(f.getVertex(0), f.getVertex(1), f.getVertex(2), faces_temp); } + } - if(diagonal.same_vertices(*it)){ - flag = 0; - break; - } + int count=0; + std::multimap<unsigned long long, pair<PETriangle*,int> >::iterator it_face = faces_temp.begin(); + std::multimap<unsigned long long, pair<PETriangle*,int> >::iterator it_faceen = faces_temp.end(); + for (;it_face!=it_faceen;it_face++)// counting + if (it_face->second.second==1) + count++; - it++; + if (count!=12){ + if (very_verbose) cout << "------------- WARNING !!!!! fill_tet_to_hex_table:: hex has " << count << " faces ... discard the hex." << endl; + delete hex; + return; } - if(flag){ - hash_tableB.insert(diagonal); + + it_face = faces_temp.begin(); + for (;it_face!=it_faceen;it_face++){// for all faces, storing the external faces + PETriangle *t=it_face->second.first; + if (it_face->second.second==1) + add_face(t->getVertex(0), t->getVertex(1), t->getVertex(2), hex); + else + delete t; + } + + // eventually storing the hex ! + for(std::set<MElement*>::iterator it=parts.begin();it!=parts.end();it++){ + element = *it; + created_potential_hex.insert(make_pair(hex->get_hash(),hex)); + add_edges(hex); + tet_to_hex[element].insert(hex); + hex_to_tet[hex].insert(element); + } + + if (very_verbose){ + export_single_hex_all(hex,""); } } -void Supplementary::build_hash_tableC(Prism prism){ - MVertex *a,*b,*c; - MVertex *d,*e,*f; +// -------------------------------------------------------------------- - a = prism.get_a(); - b = prism.get_b(); - c = prism.get_c(); - d = prism.get_d(); - e = prism.get_e(); - f = prism.get_f(); +void Recombinator_Graph::buildGraphOnly(unsigned int max_nb_cliques,string filename){ + GRegion* gr; + GModel* model = GModel::current(); + GModel::riter it; - build_hash_tableC(Diagonal(a,d)); - build_hash_tableC(Diagonal(d,f)); - build_hash_tableC(Diagonal(f,c)); - build_hash_tableC(Diagonal(a,c)); - build_hash_tableC(Diagonal(e,b)); - build_hash_tableC(Diagonal(d,e)); - build_hash_tableC(Diagonal(f,e)); - build_hash_tableC(Diagonal(a,b)); - build_hash_tableC(Diagonal(b,c)); + for(it=model->firstRegion();it!=model->lastRegion();it++) + { + gr = *it; + if(gr->getNumMeshElements()>0){ + buildGraphOnly(gr, max_nb_cliques,filename); + } + } } -void Supplementary::build_hash_tableC(Diagonal diagonal){ - bool flag; - std::multiset<Diagonal>::iterator it; +// -------------------------------------------------------------------- - it = hash_tableC.find(diagonal); - flag = 1; +void Recombinator_Graph::buildGraphOnly(GRegion* gr, unsigned int max_nb_cliques,string filename){ + printf("................HEXAHEDRA................\n"); - while(it!=hash_tableC.end()){ - if(diagonal.get_hash()!=it->get_hash()){ - break; - } + hex_to_tet.clear(); + tet_to_hex.clear(); + created_potential_hex.clear(); + + build_tuples(gr); + + Msg::Info("Building Connectivity..."); + build_vertex_to_vertices(gr); + build_vertex_to_elements(gr); + + pattern1(gr); + Msg::Info("Hex-merging pattern nb. 1..."); + pattern2(gr); + Msg::Info("Hex-merging pattern nb. 2..."); + pattern3(gr); + Msg::Info("Hex-merging pattern nb. 3..."); - if(diagonal.same_vertices(*it)){ - flag = 0; - break; - } - it++; - } - if(flag){ - hash_tableC.insert(diagonal); - } + create_losses_graph(gr); + compute_hex_ranks(); + found_the_ultimate_max_clique=false; } -double Supplementary::scaled_jacobian(MVertex* a,MVertex* b,MVertex* c,MVertex* d){ - double val; - double l1,l2,l3; - SVector3 vec1,vec2,vec3; - vec1 = SVector3(b->x()-a->x(),b->y()-a->y(),b->z()-a->z()); - vec2 = SVector3(c->x()-a->x(),c->y()-a->y(),c->z()-a->z()); - vec3 = SVector3(d->x()-a->x(),d->y()-a->y(),d->z()-a->z()); +// -------------------------------------------------------------------- - l1 = vec1.norm(); - l2 = vec2.norm(); - l3 = vec3.norm(); +void Recombinator_Graph::execute(unsigned int max_nb_cliques,string filename){ + GRegion* gr; + GModel* model = GModel::current(); + GModel::riter it; - val = dot(vec1,crossprod(vec2,vec3)); - return fabs(val)/(l1*l2*l3); -} + model->writeMSH("beforeyamakawa.msh"); -double Supplementary::min_scaled_jacobian(Prism prism){ - int i; - double min; - double j1,j2,j3,j4,j5,j6; - MVertex *a,*b,*c; - MVertex *d,*e,*f; - std::vector<double> jacobians; + for(it=model->firstRegion();it!=model->lastRegion();it++) + { + gr = *it; + if(gr->getNumMeshElements()>0){ + execute(gr, max_nb_cliques,filename); + } + } +} - a = prism.get_a(); - b = prism.get_b(); - c = prism.get_c(); - d = prism.get_d(); - e = prism.get_e(); - f = prism.get_f(); +// -------------------------------------------------------------------- - j1 = scaled_jacobian(a,b,c,d); - j2 = scaled_jacobian(b,a,c,e); - j3 = scaled_jacobian(c,a,b,f); - j4 = scaled_jacobian(d,a,e,f); - j5 = scaled_jacobian(e,b,d,f); - j6 = scaled_jacobian(f,c,d,e); +void Recombinator_Graph::execute_blossom(unsigned int max_nb_cliques,string filename){ + GRegion* gr; + GModel* model = GModel::current(); + GModel::riter it; - jacobians.push_back(j1); - jacobians.push_back(j2); - jacobians.push_back(j3); - jacobians.push_back(j4); - jacobians.push_back(j5); - jacobians.push_back(j6); + model->writeMSH("beforeyamakawa.msh"); - min = 1000000000.0; - for(i=0;i<6;i++){ - if(jacobians[i]<=min){ - min = jacobians[i]; + for(it=model->firstRegion();it!=model->lastRegion();it++) + { + gr = *it; + if(gr->getNumMeshElements()>0){ + execute_blossom(gr, max_nb_cliques,filename); } } +} - return min; + +// -------------------------------------------------------------------- +Recombinator_Graph::~Recombinator_Graph(){ + for (iter it = triangular_faces.begin();it!=triangular_faces.end();it++){ + delete it->second; + } + for (linemap::iterator it = edges_and_diagonals.begin();it!=edges_and_diagonals.end();it++){ + delete it->second; + } } -/********************************************/ -/****************class PostOp****************/ -/********************************************/ +// -------------------------------------------------------------------- -PostOp::PostOp(){} +void Recombinator_Graph::createBlossomInfo(){ + + throw; -PostOp::~PostOp(){} -void PostOp::execute(bool flag){ GRegion* gr; GModel* model = GModel::current(); GModel::riter it; @@ -3658,1023 +6257,1428 @@ void PostOp::execute(bool flag){ for(it=model->firstRegion();it!=model->lastRegion();it++) { gr = *it; - if(gr->getNumMeshElements()>0){ - execute(gr,flag); - } + // if(gr->getNumMeshElements()>0){ + createBlossomInfo(gr); + // } } } -void PostOp::execute(GRegion* gr,bool flag){ - printf("................PYRAMIDS................\n"); - estimate1 = 0; - estimate2 = 0; - iterations = 0; +// -------------------------------------------------------------------- + +void Recombinator_Graph::createBlossomInfo(GRegion *gr){ + + throw; + + + // remove quads, create triangles, and store blossom information (triangles pairs) + std::list<GFace*> faces = gr->faces(); + GFace *gf; + MElement *element; + PETriangle *t11, *t12, *t21, *t22; + + cout << "recover blossom info" << endl; + + for(std::list<GFace*>::iterator it=faces.begin();it!=faces.end();it++){ + gf = *it; + + std::vector<MQuadrangle*>::iterator it_quad = gf->quadrangles.begin(); + + for (;it_quad!=gf->quadrangles.end();it_quad++){ + element = *it_quad; + + // recovering triangular faces + t11 = get_triangle(element, 0,1,2); + t12 = get_triangle(element, 0,2,3); + t21 = get_triangle(element, 0,1,3); + t22 = get_triangle(element, 1,2,3); + + // creating blossom info (pairs of triangles) + blossom_info[t11] = t12; + blossom_info[t12] = t11; + blossom_info[t21] = t22; + blossom_info[t22] = t21; + + tri_to_gface_info[t11] = gf; + tri_to_gface_info[t12] = gf; + tri_to_gface_info[t21] = gf; + tri_to_gface_info[t22] = gf; + + // adding triangles + gf->addTriangle(new MTriangle(element->getVertex(0), element->getVertex(1), element->getVertex(2))); + gf->addTriangle(new MTriangle(element->getVertex(0), element->getVertex(2), element->getVertex(3))); + + } + // deleting quads + gf->quadrangles.clear(); + } + + + // // cut pyramids in 2 tets, remove pyramids + // std::vector<MPyramid*>::iterator it_pyramid = gr->pyramids.begin(); + // MPyramid *p; + // vector<const MVertex*>v; + // citer it_find_tri; + // cout << "start cutting pyramids" << endl; + // for (;it_pyramid!=gr->pyramids.end();it_pyramid++){ + // // arbirary cut of the pyramid... + // p = *it_pyramid; + // // add tets + // gr->addTetrahedron(new MTetrahedron(p->getVertex(0), p->getVertex(1),p->getVertex(2),p->getVertex(4))); + // gr->addTetrahedron(new MTetrahedron(p->getVertex(0), p->getVertex(2),p->getVertex(3),p->getVertex(4))); + // + // // add triangles to the right GFace + // v.clear(); + // v.push_back(p->getVertex(0)); + // v.push_back(p->getVertex(1)); + // v.push_back(p->getVertex(2)); + // t11 = new PETriangle(v); + // it_find_tri = find_the_triangle(t11, triangular_faces); + // if (it_find_tri != triangular_faces.end()){ + // std::list<GFace*>::iterator it_find_face = std::find(faces.begin(), faces.end(),tri_to_gface_info[it_find_tri->second]); + // if (it_find_face!=faces.end()){ + // (*it_find_face)->addTriangle(new MTriangle(p->getVertex(0), p->getVertex(1), p->getVertex(2))); + // } + // else + // cout << "WARNING blossom: face not found ! Can't add triangle !" << endl; + // } + // else + // cout << "WARNING blossom: triangle not found ! " << endl; + // delete t11; + // + // v.clear(); + // v.push_back(p->getVertex(0)); + // v.push_back(p->getVertex(2)); + // v.push_back(p->getVertex(3)); + // t11 = new PETriangle(v); + // it_find_tri = find_the_triangle(t11, triangular_faces); + // if (it_find_tri != triangular_faces.end()){ + // std::list<GFace*>::iterator it_find_face = std::find(faces.begin(), faces.end(),tri_to_gface_info[it_find_tri->second]); + // if (it_find_face!=faces.end()){ + // (*it_find_face)->addTriangle(new MTriangle(p->getVertex(0), p->getVertex(2),p->getVertex(3))); + // } + // else + // cout << "WARNING blossom: face not found ! Can't add triangle !" << endl; + // } + // else + // cout << "WARNING blossom: triangle not found ! " << endl; + // delete t11; + // } + // // erase all pyramids + // cout << "erasing all pyramids" << endl; + // gr->pyramids.clear(); + + + + +} + +// -------------------------------------------------------------------- + +void Recombinator_Graph::execute_blossom(GRegion* gr, unsigned int max_nb_cliques,string filename){ + + + throw; + + printf("................HEXAHEDRA................\n"); + + hex_to_tet.clear(); + tet_to_hex.clear(); + created_potential_hex.clear(); build_tuples(gr); - init_markings(gr); - build_vertex_to_tetrahedra(gr); - pyramids1(gr); - rearrange(gr); - if(flag){ - init_markings(gr); - build_vertex_to_tetrahedra(gr); - build_vertex_to_pyramids(gr); - pyramids2(gr); - rearrange(gr); - } + Msg::Info("Building Connectivity..."); - statistics(gr); + clock_t a=clock(); - modify_surfaces(gr); -} + build_vertex_to_vertices(gr); + build_vertex_to_elements(gr); -void PostOp::init_markings(GRegion* gr){ - unsigned int i; - MElement* element; + pattern1(gr); + Msg::Info("Hex-merging pattern nb. 1..."); + pattern2(gr); + Msg::Info("Hex-merging pattern nb. 2..."); + pattern3(gr); + Msg::Info("Hex-merging pattern nb. 3..."); - markings.clear(); - for(i=0;i<gr->getNumMeshElements();i++){ - element = gr->getMeshElement(i); - if(four(element) || five(element)){ - markings.insert(std::pair<MElement*,bool>(element,false)); - } - } -} + create_losses_graph(gr); + // add points to potential hexas containing original blossom pairs of triangles + compute_hex_ranks_blossom(); + + double time_building_graph = (clock() - a) / (double)CLOCKS_PER_SEC; -void PostOp::pyramids1(GRegion* gr){ - unsigned int i; - MVertex *a,*b,*c,*d; - MVertex *e,*f,*g,*h; - MElement* element; - std::vector<MElement*> hexahedra; - std::vector<MElement*> prisms; - std::vector<MTetrahedron*> opt; - std::map<MElement*,bool>::iterator it; - hexahedra.clear(); - prisms.clear(); + a=clock(); + // a criteria to stop when the whole domain is exclusively composed of hex + clique_stop_criteria<Hex*> criteria(hex_to_tet, gr->tetrahedra.size()); - for(i=0;i<gr->getNumMeshElements();i++){ - element = gr->getMeshElement(i); - if(eight(element)){ - hexahedra.push_back(element); - } - else if(six(element)){ - prisms.push_back(element); - } - } + cliques_losses_graph<Hex*> cl(incompatibility_graph, hex_ranks, max_nb_cliques, hex_to_tet.size(),&criteria,export_the_clique_graphviz_format); + cl.find_cliques(); + //cl.export_cliques(); - for(i=0;i<hexahedra.size();i++){ - element = hexahedra[i]; - a = element->getVertex(0); - b = element->getVertex(1); - c = element->getVertex(2); - d = element->getVertex(3); - e = element->getVertex(4); - f = element->getVertex(5); - g = element->getVertex(6); - h = element->getVertex(7); + double time_cliques = (clock() - a) / (double)CLOCKS_PER_SEC; + + cout << "RECOMBINATOR_GRAPH timing:" << endl; + cout << " ------- TIME BUILDING GRAPH : " << time_building_graph << " s." << endl; + cout << " ------- TIME CLIQUE : " << time_cliques << " s." << endl; - pyramids1(a,b,c,d,gr); - pyramids1(e,f,g,h,gr); - pyramids1(a,b,f,e,gr); - pyramids1(b,c,g,f,gr); - pyramids1(d,c,g,h,gr); - pyramids1(d,a,e,h,gr); - } - for(i=0;i<prisms.size();i++){ - element = prisms[i]; - a = element->getVertex(0); - b = element->getVertex(1); - c = element->getVertex(2); - d = element->getVertex(3); - e = element->getVertex(4); - f = element->getVertex(5); + int clique_number = 0; - pyramids1(a,d,f,c,gr); - pyramids1(a,b,e,d,gr); - pyramids1(b,c,f,e,gr); - } + if (filename.empty()) filename.assign("mygraph.dot"); + // export_clique_graphviz_format(cl,1,"mygraph2.dot"); + export_the_clique_graphviz_format(cl,clique_number,filename); - opt.clear(); - opt.resize(gr->tetrahedra.size()); - opt = gr->tetrahedra; - gr->tetrahedra.clear(); + merge_clique(gr,cl,clique_number); - for(i=0;i<opt.size();i++){ - element = (MElement*)(opt[i]); - it = markings.find(element); - if(it->second==0){ - gr->tetrahedra.push_back(opt[i]); - } + + + + + rearrange(gr); + statistics(gr); + modify_surfaces(gr); + + + + return; + + + + // create_indirect_neighbors_graph(); + // update_degree(gr,true); + // create_compatibility_graph(); + // + // + // cout << "size edges : " << edges.size() << endl; + // cout << "size degree : " << idegree.size() << endl; + // cout << "size hex_to_tet : " << hex_to_tet.size() << endl; + // + // hash_tableA.clear(); + // hash_tableB.clear(); + // hash_tableC.clear(); + // + // export_direct_neighbor_table(50); + // merge(gr); + // + // rearrange(gr); + // + // statistics(gr); + // + // modify_surfaces(gr); +} + +// -------------------------------------------------------------------- + +// return the triangular face ijk if it exists. If not, creates it and returns it. +PETriangle* Recombinator_Graph::get_triangle(MElement *element, int i, int j, int k){ + vector<const MVertex*> v; + PETriangle *t; + v.push_back(element->getVertex(i)); + v.push_back(element->getVertex(j)); + v.push_back(element->getVertex(k)); + t = new PETriangle(v); + citer itfind = find_the_triangle(t,triangular_faces); + if (itfind==triangular_faces.end()){ + itfind = triangular_faces.insert(make_pair(t->get_hash(),t)); + } + else{ + delete t; + t = itfind->second; } + return t; } -void PostOp::pyramids2(GRegion* gr){ - unsigned int i; - MVertex *a,*b,*c,*d; - MVertex *e,*f,*g,*h; - MElement* element; - std::vector<MElement*> hexahedra; - std::vector<MElement*> prisms; - std::vector<MTetrahedron*> opt1; - std::vector<MPyramid*> opt2; - std::map<MElement*,bool>::iterator it; +// -------------------------------------------------------------------- - hexahedra.clear(); - prisms.clear(); +void Recombinator_Graph::execute(GRegion* gr, unsigned int max_nb_cliques,string filename){ + printf("................HEXAHEDRA................\n"); - for(i=0;i<gr->getNumMeshElements();i++){ - element = gr->getMeshElement(i); - if(eight(element)){ - hexahedra.push_back(element); - } - else if(six(element)){ - prisms.push_back(element); - } - } + hex_to_tet.clear(); + tet_to_hex.clear(); + created_potential_hex.clear(); - for(i=0;i<hexahedra.size();i++){ - element = hexahedra[i]; + build_tuples(gr); - a = element->getVertex(0); - b = element->getVertex(1); - c = element->getVertex(2); - d = element->getVertex(3); - e = element->getVertex(4); - f = element->getVertex(5); - g = element->getVertex(6); - h = element->getVertex(7); + Msg::Info("Building Connectivity..."); + build_vertex_to_vertices(gr); + build_vertex_to_elements(gr); - pyramids2(a,b,c,d,gr); - pyramids2(e,f,g,h,gr); - pyramids2(a,b,f,e,gr); - pyramids2(b,c,g,f,gr); - pyramids2(d,c,g,h,gr); - pyramids2(d,a,e,h,gr); - } + pattern1(gr); + Msg::Info("Hex-merging pattern nb. 1..."); + pattern2(gr); + Msg::Info("Hex-merging pattern nb. 2..."); + pattern3(gr); + Msg::Info("Hex-merging pattern nb. 3..."); + + + + create_losses_graph(gr); + compute_hex_ranks(); + + + // a criteria to stop when the whole domain is exclusively composed of hex + found_the_ultimate_max_clique=false; + clique_stop_criteria<Hex*> criteria(hex_to_tet, gr->tetrahedra.size()); + + + cliques_losses_graph<Hex*> cl(incompatibility_graph, hex_ranks, max_nb_cliques, hex_to_tet.size(),&criteria,export_the_clique_graphviz_format); + cl.find_cliques(); + //cl.export_cliques(); - for(i=0;i<prisms.size();i++){ - element = prisms[i]; - a = element->getVertex(0); - b = element->getVertex(1); - c = element->getVertex(2); - d = element->getVertex(3); - e = element->getVertex(4); - f = element->getVertex(5); + found_the_ultimate_max_clique = cl.found_the_ultimate_max_clique; - pyramids2(a,d,f,c,gr); - pyramids2(a,b,e,d,gr); - pyramids2(b,c,f,e,gr); - } - opt1.clear(); - opt1.resize(gr->tetrahedra.size()); - opt1 = gr->tetrahedra; - gr->tetrahedra.clear(); - for(i=0;i<opt1.size();i++){ - element = (MElement*)(opt1[i]); - it = markings.find(element); - if(it->second==0){ - gr->tetrahedra.push_back(opt1[i]); - } - } + int clique_number = 0; + if (filename.empty()) filename.assign("mygraph.dot"); + //export_clique_graphviz_format(cl,1,"mygraph2.dot"); + export_the_clique_graphviz_format(cl,clique_number,filename); - opt2.clear(); - opt2.resize(gr->pyramids.size()); - opt2 = gr->pyramids; - gr->pyramids.clear(); + merge_clique(gr,cl,clique_number); - for(i=0;i<opt2.size();i++){ - element = (MElement*)(opt2[i]); - it = markings.find(element); - if(it->second==0){ - gr->pyramids.push_back(opt2[i]); - } - } -} + rearrange(gr); + statistics(gr); + modify_surfaces(gr); -void PostOp::pyramids1(MVertex* a,MVertex* b,MVertex* c,MVertex* d,GRegion* gr){ - MVertex* vertex; - std::set<MElement*> bin; - std::set<MElement*> bin1; - std::set<MElement*> bin2; - std::set<MElement*>::iterator it; - std::map<MElement*,bool>::iterator it1; - std::map<MElement*,bool>::iterator it2; - bin1.clear(); - bin2.clear(); - find_tetrahedra(a,c,bin1); - find_tetrahedra(b,d,bin2); - bin.clear(); - for(it=bin1.begin();it!=bin1.end();it++){ - bin.insert(*it); - } - for(it=bin2.begin();it!=bin2.end();it++){ - bin.insert(*it); - } + return; - if(bin.size()==2){ - it = bin.begin(); - it1 = markings.find(*it); - it++; - it2 = markings.find(*it); - if(it1->second==0 && it2->second==0){ - vertex = find(a,b,c,d,*it); - if(vertex!=0){ - gr->addPyramid(new MPyramid(a,b,c,d,vertex)); - it1->second = 1; - it2->second = 1; - } - } - } + // create_indirect_neighbors_graph(); + // update_degree(gr,true); + // create_compatibility_graph(); + // + // + // cout << "size edges : " << edges.size() << endl; + // cout << "size degree : " << idegree.size() << endl; + // cout << "size hex_to_tet : " << hex_to_tet.size() << endl; + // + // hash_tableA.clear(); + // hash_tableB.clear(); + // hash_tableC.clear(); + // + // export_direct_neighbor_table(50); + // merge(gr); + // + // rearrange(gr); + // + // statistics(gr); + // + // modify_surfaces(gr); } -void PostOp::pyramids2(MVertex* a,MVertex* b,MVertex* c,MVertex* d,GRegion* gr){ - bool flag; - double x,y,z; - MVertex* mid; - MVertex *diagA,*diagB; - MVertex *N1,*N2; - MVertex *v1,*v2,*v3,*v4,*v5; - MTetrahedron* temp; - MPyramid* temp2; - std::vector<MElement*> movables; - std::set<MVertex*> Ns; - std::set<MElement*> bin1; - std::set<MElement*> bin2; - std::set<MElement*> bin3; - std::set<MElement*> bin4; - std::set<MElement*> tetrahedra; - std::set<MElement*> pyramids; - std::set<MElement*>::iterator it; - std::map<MElement*,bool>::iterator it2; - - flag = 0; +// -------------------------------------------------------------------- - bin1.clear(); - bin2.clear(); - find_tetrahedra(a,c,bin1); - find_tetrahedra(b,d,bin2); - if(bin1.size()!=0) flag = 1; +void Recombinator_Graph::merge_clique(GRegion* gr, cliques_losses_graph<Hex*> &cl,int clique_number){ - bin3.clear(); - bin4.clear(); - find_pyramids(a,c,bin3); - find_pyramids(b,d,bin4); - if(bin3.size()!=0) flag = 1; + multimap<int,set<Hex*> >::reverse_iterator it_all = cl.allQ.rbegin(); + multimap<int,set<Hex*> >::reverse_iterator it_allen = cl.allQ.rend(); + int clique_counter=0; + std::set<MElement*> parts; + int clique_size=0; - tetrahedra.clear(); - for(it=bin1.begin();it!=bin1.end();it++){ - tetrahedra.insert(*it); - } - for(it=bin2.begin();it!=bin2.end();it++){ - tetrahedra.insert(*it); + for (int i=0;i<clique_number;i++){ + it_all++; } - pyramids.clear(); - for(it=bin3.begin();it!=bin3.end();it++){ - pyramids.insert(*it); - } - for(it=bin4.begin();it!=bin4.end();it++){ - pyramids.insert(*it); - } + for (;it_all!=it_allen;it_all++,clique_counter++){ + if (clique_counter>=1) break; - /*if(pyramids.size()==0 && tetrahedra.size()==1){ - printf("tetrahedron deleted\n"); - it2 = markings.find(*tetrahedra.begin()); - it2->second = 1; - return; - }*/ + //cout << "--------------------- clique " << clique_counter << " made of "; + clique_size = it_all->second.size(); + set<Hex*>::iterator ithex = it_all->second.begin(); + set<Hex*>::iterator ithexen = it_all->second.end(); + double quality=0.; + int count=0; - if(flag){ - diagA = a; - diagB = c; - } - else{ - diagA = b; - diagB = d; - } + hash_tableA.clear(); + hash_tableB.clear(); + hash_tableC.clear(); - Ns.clear(); - Ns.insert(diagA); - Ns.insert(diagB); + // // sorting the hexahedra from the clique... + // multimap<double, Hex*> rank; + // create_boundaries_info_for_hex_ranking(gr); + // for (;ithex!=ithexen;ithex++){ + // rank.insert(make_pair(get_hex_rank(*ithex),*ithex)); + // //cout << "rank:" << get_hex_rank(*ithex) << endl; + // } + // multimap<double, Hex*>::iterator it_rank = rank.begin(); + // multimap<double, Hex*>::iterator it_ranken = rank.end(); - x = (diagA->x() + diagB->x())/2.0; - y = (diagA->y() + diagB->y())/2.0; - z = (diagA->z() + diagB->z())/2.0; + // set<Hex*> hex_to_export; - mid = 0; - movables.clear(); + for (;ithex!=ithexen;ithex++){ // brutal post-check: random pickup of hexahedra in clique + Hex *current_hex = *ithex; - if(tetrahedra.size()>0 || pyramids.size()>0){ - estimate1 = estimate1 + tetrahedra.size() + 2*pyramids.size(); - estimate2 = estimate2 + 1; - mid = new MVertex(x,y,z,gr); - gr->addMeshVertex(mid); + // cout << " clique merge: treating hex " << current_hex << " made of "; + // for (int i=0;i<8;i++) + // cout << " " << current_hex->getVertex(i)->getNum(); + // cout << endl; - temp2 = new MPyramid(a,b,c,d,mid); - gr->addPyramid(temp2); - markings.insert(std::pair<MElement*,bool>(temp2,false)); - build_vertex_to_pyramids(temp2); - for(it=tetrahedra.begin();it!=tetrahedra.end();it++){ - N1 = other(*it,diagA,diagB); - N2 = other(*it,diagA,diagB,N1); - if(N1!=0 && N2!=0){ - Ns.insert(N1); - Ns.insert(N2); + // for (;it_rank!=it_ranken;it_rank++) // smarter post-check: sorting hexahedra first... + // Hex *current_hex = it_rank->second; - temp = new MTetrahedron(N1,N2,diagA,mid); - gr->addTetrahedron(temp); - markings.insert(std::pair<MElement*,bool>(temp,false)); - build_vertex_to_tetrahedra(temp); - movables.push_back(temp); + // export_single_hex_all(current_hex,""); - temp = new MTetrahedron(N1,N2,diagB,mid); - gr->addTetrahedron(temp); - markings.insert(std::pair<MElement*,bool>(temp,false)); - build_vertex_to_tetrahedra(temp); - movables.push_back(temp); + if (!post_check_validation(current_hex)) + continue; - it2 = markings.find(*it); - it2->second = 1; - erase_vertex_to_tetrahedra(*it); + // inserting the hex + quality = quality + current_hex->get_quality(); + gr->addHexahedron(new MHexahedron(current_hex->get_a(), current_hex->get_b(),current_hex->get_c(),current_hex->get_d(),current_hex->get_e(),current_hex->get_f(),current_hex->get_g(),current_hex->get_h())); + count++; + // hex_to_export.insert(current_hex); + // cout << " inserting " << current_hex << " made of "; + // for (int i=0;i<8;i++) + // cout << " " << current_hex->getVertex(i)->getNum(); + // cout << endl; + + + // removing tets + // if (debug) cout << " removing tets" << endl; + std::set<MElement*>::iterator it_tet_to_remove = hex_to_tet[current_hex].begin(); + std::vector<MTetrahedron*>::iterator itfind_tet_region; + for (;it_tet_to_remove!=hex_to_tet[current_hex].end();it_tet_to_remove++){ + itfind_tet_region = std::find(gr->tetrahedra.begin(),gr->tetrahedra.end(),(MTetrahedron*)(*it_tet_to_remove)); + if (itfind_tet_region!=gr->tetrahedra.end()) + gr->tetrahedra.erase(itfind_tet_region); + // else + // cout << " WARNING: MTetrahedron* " << (MTetrahedron*)(*it_tet_to_remove) << " not found !!! " << endl; } + + + build_hash_tableA(*current_hex); + build_hash_tableB(*current_hex); + build_hash_tableC(*current_hex); + } - for(it=pyramids.begin();it!=pyramids.end();it++){ - v1 = (*it)->getVertex(0); - v2 = (*it)->getVertex(1); - v3 = (*it)->getVertex(2); - v4 = (*it)->getVertex(3); - v5 = (*it)->getVertex(4); - if(v1!=diagA && v1!=diagB){ - Ns.insert(v1); - } - if(v2!=diagA && v2!=diagB){ - Ns.insert(v2); - } - if(v3!=diagA && v3!=diagB){ - Ns.insert(v3); - } - if(v4!=diagA && v4!=diagB){ - Ns.insert(v4); - } - if(v5!=diagA && v5!=diagB){ - Ns.insert(v5); - } + // // removing tets + // for (set<Hex*>::iterator it_hex = hex_to_export.begin();it_hex!=hex_to_export.end();it_hex++){ + // Hex *current_hex = *it_hex; + // if (debug) cout << " removing tets" << endl; + // std::set<MElement*>::iterator it_tet_to_remove = hex_to_tet[current_hex].begin(); + // std::vector<MTetrahedron*>::iterator itfind_tet_region; + // for (;it_tet_to_remove!=hex_to_tet[current_hex].end();it_tet_to_remove++){ + // itfind_tet_region = std::find(gr->tetrahedra.begin(),gr->tetrahedra.end(),(MTetrahedron*)(*it_tet_to_remove)); + // if (itfind_tet_region!=gr->tetrahedra.end()) + // gr->tetrahedra.erase(itfind_tet_region); + // else + // cout << " WARNING: MTetrahedron* " << (MTetrahedron*)(*it_tet_to_remove) << " not found !!! " << endl; + // } + // } - temp2 = new MPyramid(v1,v2,v3,v4,mid); - gr->addPyramid(temp2); - markings.insert(std::pair<MElement*,bool>(temp2,false)); - build_vertex_to_pyramids(temp2); - if(different(v1,v2,diagA,diagB)){ - temp = new MTetrahedron(v1,v2,mid,v5); - gr->addTetrahedron(temp); - markings.insert(std::pair<MElement*,bool>(temp,false)); - build_vertex_to_tetrahedra(temp); - movables.push_back(temp); - } + //export_all_hex(clique_counter,gr); + // removing hexahedron + //gr->hexahedra.clear(); - if(different(v2,v3,diagA,diagB)){ - temp = new MTetrahedron(v2,v3,mid,v5); - gr->addTetrahedron(temp); - markings.insert(std::pair<MElement*,bool>(temp,false)); - build_vertex_to_tetrahedra(temp); - movables.push_back(temp); - } - if(different(v3,v4,diagA,diagB)){ - temp = new MTetrahedron(v3,v4,mid,v5); - gr->addTetrahedron(temp); - markings.insert(std::pair<MElement*,bool>(temp,false)); - build_vertex_to_tetrahedra(temp); - movables.push_back(temp); - } + cout << " ------------------------------------------ #hex potentiels recensés par les patterns de recombinaison: " << hex_to_tet.size() << endl; + cout << " ------------------------------------------ #hex potentiels recensés dans le graphe des pertes: " << nbhex_in_losses_graph << " #connectivité moyenne: " << average_connectivity<< endl; + cout << " ------------------------------------------ CLIQUE SIZE " << clique_size << endl; + cout << " ------------------------------------------ Recombinator_Graph::merge_clique: nb hex created = " << count << endl; + printf("hexahedra average quality (0->1) : %f\n",quality/count); + } - if(different(v4,v1,diagA,diagB)){ - temp = new MTetrahedron(v4,v1,mid,v5); - gr->addTetrahedron(temp); - markings.insert(std::pair<MElement*,bool>(temp,false)); - build_vertex_to_tetrahedra(temp); - movables.push_back(temp); - } + // // exporting all hex infos + // for (set<Hex*>::iterator it=hex_to_export.begin();it!=hex_to_export.end();it++){ + // Hex *hex = *it; + // cout << hex << " made of "; + // for (int i=0;i<8;i++){ + // cout << "(" << hex->getVertex(i)->x() << "," << hex->getVertex(i)->y() << "," << hex->getVertex(i)->z() << ") "; + // } + // cout << endl; + // } +} - it2 = markings.find(*it); - it2->second = 1; - erase_vertex_to_pyramids(*it); + +// -------------------------------------------------------------------- + +void Recombinator_Graph::merge(GRegion* gr){ + throw; +} + +// -------------------------------------------------------------------- + +void Recombinator_Graph::export_tets(set<MElement*> &tetset, Hex* hex, string s){ + stringstream ss; + ss << s.c_str(); + ss << "hexptr_"; + ss << hex; + ss << "_tetparts.pos"; + ofstream out(ss.str().c_str()); + + out << "View \"hex tets parts\" {" << endl; + std::set<MElement*>::iterator it = tetset.begin(); + std::set<MElement*>::iterator iten = tetset.end(); + int count=0; + for (;it!=iten;it++,count++){ + out << "SS("; + for (int n=0;n<4;n++){ + const MVertex *v = (*it)->getVertex(n); + out << v->x() << "," << v->y() << "," << v->z(); + if (n!=3) out << ","; } + out << "){"; + for (int n=0;n<4;n++){ + out << count; + if (n!=3) out << ","; + } + out << "};" << endl; - mean(Ns,mid,movables); } + out << "};" << endl; + out.close(); } -void PostOp::rearrange(GRegion* gr){ - unsigned int i; - MElement* element; +// -------------------------------------------------------------------- - for(i=0;i<gr->getNumMeshElements();i++){ - element = gr->getMeshElement(i); - element->setVolumePositive(); +void Recombinator_Graph::export_single_hex_tet(Hex* hex,string s){ + stringstream ss; + ss << s.c_str(); + ss << "hexptr_"; + ss << hex; + ss << "_tet.pos"; + ofstream out(ss.str().c_str()); + + out << "View \"hex tets\" {" << endl; + std::set<MElement*>::iterator it = hex_to_tet[hex].begin(); + std::set<MElement*>::iterator iten = hex_to_tet[hex].end(); + int count=0; + for (;it!=iten;it++,count++){ + out << "SS("; + for (int n=0;n<4;n++){ + const MVertex *v = (*it)->getVertex(n); + out << v->x() << "," << v->y() << "," << v->z(); + if (n!=3) out << ","; + } + out << "){"; + for (int n=0;n<4;n++){ + out << count; + if (n!=3) out << ","; + } + out << "};" << endl; + + } + out << "};" << endl; + out.close(); +} + +// -------------------------------------------------------------------- + +void Recombinator_Graph::export_single_hex_all(Hex* hex,string s){ + export_single_hex(hex, s); + export_single_hex_tet(hex, s); + export_single_hex_faces(hex, s); +} + +// -------------------------------------------------------------------- + +void Recombinator_Graph::export_single_hex(Hex* hex,string s){ + stringstream ss; + ss << s.c_str(); + ss << "hexptr_"; + ss << hex; + ss << ".pos"; + ofstream out(ss.str().c_str()); + + out << "View \"hex\" {" << endl; + out << "SH("; + for (int n=0;n<8;n++){ + const MVertex *v = hex->getVertex(n); + out << v->x() << "," << v->y() << "," << v->z(); + if (n!=7) out << ","; } + out << "){"; + for (int n=0;n<8;n++){ + out << "0."; + if (n!=7) out << ","; + } + out << "};" << endl; + + out << "};" << endl; + out.close(); } -void PostOp::statistics(GRegion* gr){ - unsigned int i; - int nbr,nbr8,nbr6,nbr5,nbr4; - double vol,vol8,vol6,vol5,vol4; - MElement* element; - nbr = 0; - nbr8 = 0; - nbr6 = 0; - nbr5 = 0; - nbr4 = 0; - vol = 0.0; - vol8 = 0.0; - vol6 = 0.0; - vol5 = 0.0; - vol4 = 0.0; +// -------------------------------------------------------------------- - for(i=0;i<gr->getNumMeshElements();i++){ - element = gr->getMeshElement(i); +void Recombinator_Graph::export_single_hex_faces(Hex* hex,string s){ + stringstream ss; + ss << s.c_str(); + ss << "hexptr_"; + ss << hex; + ss << "_face.pos"; + ofstream out(ss.str().c_str()); - if(eight(element)){ - nbr8 = nbr8 + 1; - vol8 = vol8 + element->getVolume(); + out << "View \"hex faces\" {" << endl; + std::set<PETriangle*>::iterator it = hex_to_faces[hex].begin(); + std::set<PETriangle*>::iterator iten = hex_to_faces[hex].end(); + int count=0; + for (;it!=iten;it++,count++){ + out << "ST("; + for (int n=0;n<3;n++){ + const MVertex *v = (*it)->getVertex(n); + out << v->x() << "," << v->y() << "," << v->z(); + if (n!=2) out << ","; } - - if(six(element)){ - nbr6 = nbr6 + 1; - vol6 = vol6 + element->getVolume(); + out << "){"; + for (int n=0;n<3;n++){ + out << count; + if (n!=2) out << ","; } + out << "};" << endl; - if(five(element)){ - nbr5 = nbr5 + 1; - vol5 = vol5 + workaround(element); - } + } + out << "};" << endl; + out.close(); +} - if(four(element)){ - nbr4 = nbr4 + 1; - vol4 = vol4 + element->getVolume(); - } +// -------------------------------------------------------------------- - nbr = nbr + 1; - if(!five(element)){ - vol = vol + element->getVolume(); +void Recombinator_Graph::export_hex_init_degree(GRegion *gr, const std::map<Hex*,int> &init_degree, const vector<Hex*> &chosen_hex){ + stringstream ss; + ss << "init_degree"; + ss << ".pos"; + ofstream out(ss.str().c_str()); + + std::vector<Hex*>::const_iterator it = chosen_hex.begin(); + out << "View \"hex\" {" << endl; + for (;it!=chosen_hex.end();it++){ + out << "SH("; + for (int n=0;n<8;n++){ + MVertex *v = (*it)->getVertex(n); + out << v->x() << "," << v->y() << "," << v->z(); + if (n!=7) out << ","; } - else{ - //vol = vol + workaround(element); - vol = vol + element->getVolume(); + map<Hex*,int>::const_iterator itfind = init_degree.find(*it); + out << "){"; + for (int n=0;n<8;n++){ + out << itfind->second; + if (n!=7) out << ","; } + out << "};" << endl; + } + out << "};" << endl; - printf("Number :\n"); - printf(" percentage of hexahedra : %.2f\n",nbr8*100.0/nbr); - printf(" percentage of prisms : %.2f\n",nbr6*100.0/nbr); - printf(" percentage of pyramids : %.2f\n",nbr5*100.0/nbr); - printf(" percentage of tetrahedra : %.2f\n",nbr4*100.0/nbr); - printf("Volume :\n"); - printf(" percentage of hexahedra : %.2f\n",vol8*100.0/vol); - printf(" percentage of prisms : %.2f\n",vol6*100.0/vol); - printf(" percentage of pyramids : %.2f\n",vol5*100.0/vol); - printf(" percentage of tetrahedra : %.2f\n",vol4*100.0/vol); - printf("Total number of elements : %d\n",gr->getNumMeshElements()); - printf("Total volume : %f\n",vol); - printf("Misc : %d %d %d\n",estimate1,estimate2,iterations); + + + out.close(); } -void PostOp::build_tuples(GRegion* gr){ - unsigned int i; - MVertex *a,*b,*c; - MElement* element; - GFace* gf; - std::list<GFace*> faces; - std::list<GFace*>::iterator it; +// -------------------------------------------------------------------- - tuples.clear(); - triangles.clear(); - faces.clear(); +void Recombinator_Graph::export_hexmesh_so_far(int &file){ + stringstream ss; + stringstream ssinit; + ss << "hex_mesh_temp"; + char chose[256]; + sprintf(chose, "_%0*d", 6, file); + ss << chose; + ss << ".msh"; + ofstream out(ss.str().c_str()); - faces = gr->faces(); + GModel* model = GModel::current(); + model->save(ss.str().c_str()); - for(it=faces.begin();it!=faces.end();it++) - { - gf = *it; + out.close(); +} - for(i=0;i<gf->getNumMeshElements();i++){ - element = gf->getMeshElement(i); - if(element->getNumVertices()==3){ - a = element->getVertex(0); - b = element->getVertex(1); - c = element->getVertex(2); +// -------------------------------------------------------------------- - tuples.insert(Tuple(a,b,c,element,gf)); - } +void Recombinator_Graph::export_all_hex(int &file, GRegion *gr){ + stringstream ss; + stringstream ssinit; + ss << "hex_progression"; + ssinit << "hex_progression_initdegree"; + // ss << file; + char chose[256]; + sprintf(chose, "_%0*d", 6, file); + ss << chose; + ss << ".pos"; + ssinit << chose; + ssinit << ".pos"; + ofstream out(ss.str().c_str()); + + std::vector<MHexahedron*>::iterator it = gr->hexahedra.begin(); + int i=1; + out << "View \"hex\" {" << endl; + for (;it!=gr->hexahedra.end();it++,i++){ + out << "SH("; + for (int n=0;n<8;n++){ + MVertex *v = (*it)->getVertex(n); + out << v->x() << "," << v->y() << "," << v->z(); + if (n!=7) out << ","; + } + out << "){"; + for (int n=0;n<8;n++){ + out << i; + if (n!=7) out << ","; } + out << "};" << endl; + } + out << "};" << endl; + + + + out.close(); } -void PostOp::modify_surfaces(GRegion* gr){ - unsigned int i; - MVertex *a,*b,*c,*d;//,*e; - MElement* element; - GFace* gf; - std::list<GFace*> faces; - std::vector<MElement*> opt; - std::list<GFace*>::iterator it; - std::set<MElement*>::iterator it2; +// -------------------------------------------------------------------- - for(i=0;i<gr->getNumMeshElements();i++){ - element = gr->getMeshElement(i); +// check if the hex is good enough to be put into the graph. If not in the graph, it cannot be chosen... +bool Recombinator_Graph::is_not_good_enough(Hex* hex){ - if(element->getNumVertices()==5){ - a = element->getVertex(0); - b = element->getVertex(1); - c = element->getVertex(2); - d = element->getVertex(3); - //e = element->getVertex(4); + // // Hack + // return false; + // // End Hack - modify_surfaces(a,b,c,d); - } + + //if((!faces_statuquo(*hex))){ + //if((hex->get_quality()<0.45)||(!faces_statuquo(*hex))){ + if((hex->get_quality()<0.5)||(!faces_statuquo(*hex))){ + //if((hex->get_quality()<0.55)||(!faces_statuquo(*hex))){ + //if((hex->get_quality()<0.72)||(!faces_statuquo(*hex))){ + //if((hex->get_quality()<0.65)||(!faces_statuquo(*hex))){ + return true; + } + return false; } - faces = gr->faces(); + // -------------------------------------------------------------------- - for(it=faces.begin();it!=faces.end();it++) - { - gf = *it; + // fills incompatibility_graph if two hex share a common (non-sliver!) tet + void Recombinator_Graph::create_indirect_neighbors_graph(){ + std::map<MElement*, std::set<Hex*> >::iterator it_tet = tet_to_hex.begin(); - opt.clear(); + for (;it_tet!=tet_to_hex.end();it_tet++){ + std::set<Hex*>::iterator it_hex1 = it_tet->second.begin(); + for (;it_hex1!=it_tet->second.end();it_hex1++){ + Hex *hex = *it_hex1; - for(i=0;i<gf->getNumMeshElements();i++){ - element = gf->getMeshElement(i); + // cout << " create_indirect_neighbors_graph:: treating hex " << hex << " made of "; + // for (int i=0;i<8;i++) + // cout << " " << hex->getVertex(i)->getNum(); + // cout << endl; - if(element->getNumVertices()==3){ - it2 = triangles.find(element); - if(it2==triangles.end()){ - opt.push_back(element); + if (is_not_good_enough(hex)){ + continue; + } + graph::iterator itfind_graph = find_hex_in_graph(hex); + if (itfind_graph==incompatibility_graph.end()){ + incompatibility_graph.insert(make_pair(hex->get_hash(),make_pair(hex,graph_data())));// this creates an entry if none exists. Important ! if hex is good, but surrounded by "not good enough" hex, it has to be in the graph anyway ! A single node in the graph, without any connection... the perfect lonely hex. + set_of_all_hex_in_graph.insert(hex); + } + // check if the hex quality is sufficient to be put into the graph... + //cout << "creating graph for hex " << hex << " with quality " << hex->get_quality() << endl; + // if (hex->get_quality()>=0.1) + // check if the tet is a sliver or not... + // if sliver, the tet should not be taken into account in the graph creation ! + bool is_sliver = sliver(it_tet->first,*hex); + if (!is_sliver){ + //cout << " is not sliver, size it_tet->second:" << it_tet->second.size() << endl; + std::set<Hex*>::iterator it_hex2 = it_tet->second.begin(); + for (;it_hex2!=it_tet->second.end();it_hex2++){ + if ((hex)!=(*it_hex2)){ + if (is_not_good_enough(*it_hex2)){ + continue; + } + //cout << " hex put in graph, linked to hex " << *it_hex2 << endl; + add_graph_entry(hex,*it_hex2); + //cout << "hex's " << hex << " and " << *it_hex2 << " have one tet in common: " << it_tet->first << endl; + // incompatibility_graph[*it_hex2].insert(hex); + } + } } + // else{ + // cout << " hex's " << hex << " has a sliver !!!!!!!!!!!!!!! : " << it_tet->first << endl; + // } } } + } - gf->triangles.clear(); + // -------------------------------------------------------------------- - for(i=0;i<opt.size();i++){ - gf->triangles.push_back((MTriangle*)opt[i]); + std::multimap<unsigned long long, Hex* >::const_iterator Recombinator_Graph::find_the_created_potential_hex(Hex *hex, const std::multimap<unsigned long long, Hex*> &list){ + std::pair<std::multimap<unsigned long long, Hex* >::const_iterator, std::multimap<unsigned long long, Hex* >::const_iterator> range = list.equal_range(hex->get_hash()); + for (std::multimap<unsigned long long, Hex*>::const_iterator it=range.first;it!=range.second;it++){ + Hex *candidate = it->second; + if (candidate->same_vertices(hex)){ + return it; + } } + return list.end(); } -} - -void PostOp::modify_surfaces(MVertex* a,MVertex* b,MVertex* c,MVertex* d){ - bool flag1,flag2; - MElement *element1,*element2; - GFace *gf1;//,*gf2; - Tuple tuple1,tuple2; - std::multiset<Tuple>::iterator it1; - std::multiset<Tuple>::iterator it2; - gf1 = NULL; - //gf2 = NULL; + // -------------------------------------------------------------------- - tuple1 = Tuple(a,b,c); - tuple2 = Tuple(c,d,a); + std::multimap<unsigned long long, pair<PETriangle*,int> >::iterator Recombinator_Graph::find_the_triangle(PETriangle *t, std::multimap<unsigned long long, pair<PETriangle*, int> > &list){ + std::pair<std::multimap<unsigned long long, pair<PETriangle*,int> >::iterator, std::multimap<unsigned long long, pair<PETriangle*,int> >::iterator> range = list.equal_range(t->get_hash()); + for (std::multimap<unsigned long long, pair<PETriangle*,int> >::iterator it=range.first;it!=range.second;it++){ + PETriangle *candidate = it->second.first; + if (candidate->same_vertices(t)){ + it->second.second++; + return it; + } + } + return list.end(); + } - it1 = tuples.find(tuple1); - it2 = tuples.find(tuple2); - flag1 = 0; - flag2 = 0; + // -------------------------------------------------------------------- - while(it1!=tuples.end()){ - if(tuple1.get_hash()!=it1->get_hash()){ - break; + Recombinator_Graph::citer Recombinator_Graph::find_the_triangle(PETriangle *t, const trimap &list){ + std::pair<citer, citer> range = list.equal_range(t->get_hash()); + for (citer it=range.first;it!=range.second;it++){ + if (it->second->same_vertices(t)) return it; } + return list.end(); + } - if(tuple1.same_vertices(*it1)){ - flag1 = 1; - element1 = it1->get_element(); - gf1 = it1->get_gf(); - } + // -------------------------------------------------------------------- - it1++; + Recombinator_Graph::linemap::const_iterator Recombinator_Graph::find_the_line(PELine *t, const linemap &list){ + std::pair<linemap::const_iterator, linemap::const_iterator> range = list.equal_range(t->get_hash()); + for (linemap::const_iterator it=range.first;it!=range.second;it++){ + if (it->second->same_vertices(t)) return it; + } + return list.end(); } - while(it2!=tuples.end()){ - if(tuple2.get_hash()!=it2->get_hash()){ - break; - } + // -------------------------------------------------------------------- - if(tuple2.same_vertices(*it2)){ - flag2 = 1; - element2 = it2->get_element(); - //gf2 = it2->get_gf(); + void Recombinator_Graph::export_direct_neighbor_table(int max){ + stringstream ss; + ss << "neighbors_table"; + ofstream out(ss.str().c_str()); + + std::multimap<int,Hex*>::iterator it = ndegree.begin(); + + int counter=0; + out << " n neighbors_rank hex* quality" << endl; + for (;it!=ndegree.end();it++,counter++){ + if (counter>=max) break; + Hex *hex = it->second; + out << counter << " " << it->first << " " << hex << " " << hex->get_quality() << endl; + stringstream ss2; + ss2 << "neighbors_table_hex"; + char chose[256]; + sprintf(chose, "_%0*d", 2, counter); + ss2 << chose; + ss2 << ".pos"; + ofstream out2(ss2.str().c_str()); + out2 << "View \"hex\" {" << endl; + out2 << "SH("; + for (int n=0;n<8;n++){ + MVertex *v = hex->getVertex(n); + out2 << v->x() << "," << v->y() << "," << v->z(); + if (n!=7) out2 << ","; + } + out2 << "){"; + for (int n=0;n<8;n++){ + out2 << it->first; + if (n!=7) out2 << ","; + } + out2 << "};" << endl; + out2 << "};" << endl; + out2.close(); } - it2++; - } - if(flag1 && flag2){ - triangles.insert(element1); - triangles.insert(element2); - gf1->addQuadrangle(new MQuadrangle(a,b,c,d)); - } - tuple1 = Tuple(a,b,d); - tuple2 = Tuple(b,c,d); + out.close(); + } - it1 = tuples.find(tuple1); - it2 = tuples.find(tuple2); + // -------------------------------------------------------------------- - flag1 = 0; - flag2 = 0; + // if two hex are not connected in the incompatibility_graph, they are compatible + void Recombinator_Graph::create_losses_graph(GRegion *gr){ + incompatibility_graph.clear(); + create_indirect_neighbors_graph(); + create_direct_neighbors_incompatibility_graph(); - while(it1!=tuples.end()){ - if(tuple1.get_hash()!=it1->get_hash()){ - break; - } - if(tuple1.same_vertices(*it1)){ - flag1 = 1; - element1 = it1->get_element(); - gf1 = it1->get_gf(); + // stats + graph::iterator it = incompatibility_graph.begin(); + graph::iterator ite = incompatibility_graph.end(); + int total=0; + for (;it!=ite;it++){ + total+=it->second.second.size(); } + nbhex_in_losses_graph = incompatibility_graph.size(); + cout << "total=" << total << endl; + cout << "nbhex_in_losses_graph=" << nbhex_in_losses_graph << endl; + average_connectivity = total/((double)(nbhex_in_losses_graph)); + cout << "#hex potentiels recensés dans le graphe des pertes: " << nbhex_in_losses_graph << " #connectivité moyenne: " << average_connectivity<< endl; + cout << "#hex potentiels recensés par les patterns de recombinaison: " << hex_to_tet.size() << endl; + }; - it1++; - } + // -------------------------------------------------------------------- - while(it2!=tuples.end()){ - if(tuple2.get_hash()!=it2->get_hash()){ - break; - } + // TODO: check only the direct neighbors !!! change the algo pour ne as parcourir les hex qui ont un tet commun. cad Filter au niveau des faces... juste les faces extérieures de l'hex !!! et attention aux slivers, du coup... c'est sans doute la source du pb... - if(tuple2.same_vertices(*it2)){ - flag2 = 1; - element2 = it2->get_element(); - //gf2 = it2->get_gf(); - } + // pour chaque hex, sortir un .pos avec l'hex, ses tets et ses faces extérieures pour checker... + // pourquoi pas sortir aussi tous les slivers à part... ? - it2++; - } - if(flag1 && flag2){ - triangles.insert(element1); - triangles.insert(element2); - gf1->addQuadrangle(new MQuadrangle(a,b,c,d)); - } -} -bool PostOp::four(MElement* element){ - if(element->getNumVertices()==4) return 1; - else return 0; -} + // fills incompatibility_graph if two hex are incompatible direct neighbors, + // i.e. (they DO NOT have one tet in common) and (they are neighbors (face(s) in common) but DO NOT pass the compatibility tests) + void Recombinator_Graph::create_direct_neighbors_incompatibility_graph(){ -bool PostOp::five(MElement* element){ - if(element->getNumVertices()==5) return 1; - else return 0; -} + vector<Hex*> visited_hex; + std::map<Hex*, std::set<MElement*> >::iterator it_hex = hex_to_tet.begin(); + for (;it_hex!=hex_to_tet.end();it_hex++){// for all hex + Hex *hex = it_hex->first; + if (is_not_good_enough(hex)) + continue; + graph::iterator itfind_graph = find_hex_in_graph(hex); + if (itfind_graph==incompatibility_graph.end()){ + incompatibility_graph.insert(make_pair(hex->get_hash(),make_pair(hex,graph_data())));// this creates an entry if none exists. Important ! if hex is good, but surrounded by "not good enough" hex, it has to be in the graph anyway ! A single node in the graph, without any connection... the perfect lonely hex. + set_of_all_hex_in_graph.insert(hex); + } -bool PostOp::six(MElement* element){ - if(element->getNumVertices()==6) return 1; - else return 0; -} + hash_tableA.clear(); + hash_tableB.clear(); + hash_tableC.clear(); + build_hash_tableA(*hex); + build_hash_tableB(*hex); + build_hash_tableC(*hex); + + visited_hex.clear(); + + std::set<PETriangle*>::iterator it_faces = hex_to_faces[hex].begin(); + std::set<PETriangle*>::iterator it_facesen = hex_to_faces[hex].end(); + for (;it_faces!=it_facesen;it_faces++){// i.e. for all triangular external face + PETriangle *face = *it_faces; + std::set<Hex*>::iterator it_neighbors = faces_to_hex[face].begin(); + std::set<Hex*>::iterator it_neighborsen = faces_to_hex[face].end(); + for (;it_neighbors!=it_neighborsen;it_neighbors++){// for all its neighbors + if ((*it_neighbors)==hex) continue; + Hex *other_hex = *it_neighbors; + + vector<Hex*>::iterator itfind_hex = std::find(visited_hex.begin(),visited_hex.end(),other_hex); + if (itfind_hex!=visited_hex.end()) continue;// already done + else visited_hex.push_back(other_hex); + + evaluate_hex_couple(hex,other_hex); + } + } + // change following... + std::set<PELine*>::iterator it_line = hex_to_edges[hex].begin(); + std::set<PELine*>::iterator it_lineen = hex_to_edges[hex].end(); + for (;it_line!=it_lineen;it_line++){// i.e. for all edges and diagonals -> check the hex neighbors too + PELine *line = *it_line; + std::set<Hex*>::iterator it_neighbors = edges_to_hex[line].begin(); + std::set<Hex*>::iterator it_neighborsen = edges_to_hex[line].end(); + for (;it_neighbors!=it_neighborsen;it_neighbors++){// for all its neighbors + if ((*it_neighbors)==hex) continue; + Hex *other_hex = *it_neighbors; + + vector<Hex*>::iterator itfind_hex = std::find(visited_hex.begin(),visited_hex.end(),other_hex); + if (itfind_hex!=visited_hex.end()) continue;// already done + else visited_hex.push_back(other_hex); + + evaluate_hex_couple(hex,other_hex); + } + } + } -bool PostOp::eight(MElement* element){ - if(element->getNumVertices()==8) return 1; - else return 0; -} -bool PostOp::equal(MVertex* v1,MVertex* v2,MVertex* v3,MVertex* v4){ - if((v1==v3 && v2==v4) || (v1==v4 && v2==v3)){ - return 1; - } - else{ - return 0; } -} -bool PostOp::different(MVertex* v1,MVertex* v2,MVertex* v3,MVertex* v4){ - if(v1!=v3 && v1!=v4 && v2!=v3 && v2!=v4){ - return 1; - } - else{ - return 0; - } -} + // -------------------------------------------------------------------- -MVertex* PostOp::other(MElement* element,MVertex* v1,MVertex* v2){ - int i; - MVertex* vertex; - MVertex* pointer; + void Recombinator_Graph::evaluate_hex_couple(Hex* hex, Hex* other_hex){ + + const bool very_verbose=false; + + + + if (very_verbose){ + // export_single_hex_all(other_hex,""); + // export_single_hex_all(hex,""); + cout << " evaluate_hex_couple:: treating hex " << hex << " made of "; + for (int i=0;i<8;i++) + cout << " " << hex->getVertex(i)->getNum(); + cout << endl; + cout << " evaluate_hex_couple:: treating other_hex " << other_hex << " made of "; + for (int i=0;i<8;i++) + cout << " " << other_hex->getVertex(i)->getNum(); + cout << endl; + } - pointer = 0; - for(i=0;i<element->getNumVertices();i++){ - vertex = element->getVertex(i); - if(vertex!=v1 && vertex!=v2){ - pointer = vertex; - break; + + if (is_not_good_enough(other_hex)){ + if (very_verbose) cout << "hex " << hex << " not good enough" << endl; + return; } - } - return pointer; -} -MVertex* PostOp::other(MElement* element,MVertex* v1,MVertex* v2,MVertex* v3){ - int i; - MVertex* vertex; - MVertex* pointer; + if (find_hex_couple_in_graph(hex,other_hex)){ + if (very_verbose) cout << "already incompatible: hex's " << hex << " and " << other_hex << endl; + return; + } - pointer = 0; + // count the number of faces in common... + // intuitivement: si !=2, c'est incompatible + // bool two_faces_in_common=true; + // std::vector<PETriangle*> common(12); + // std::vector<PETriangle*>::iterator itfind_face = std::set_intersection (hex_to_faces[other_hex].begin(),hex_to_faces[other_hex].end(), hex_to_faces[hex].begin(), hex_to_faces[hex].end(), common.begin()); + // common.resize(itfind_face-common.begin()); + // if (common.size()!=2){ + // two_faces_in_common=false; + // } - for(i=0;i<element->getNumVertices();i++){ - vertex = element->getVertex(i); - if(vertex!=v1 && vertex!=v2 && vertex!=v3){ - pointer = vertex; - break; + // check compatibility between the two neighbors + + + // if they do not pass the tests + //-> incompatible ! + + // the following depends on hex... on "hash_tables's" + // std::set<MElement*> parts = hex_to_tet[other_hex]; + // std::set<MElement*> parts; + // find(other_hex->get_a(),*other_hex,parts); + // find(other_hex->get_b(),*other_hex,parts); + // find(other_hex->get_c(),*other_hex,parts); + // find(other_hex->get_d(),*other_hex,parts); + // find(other_hex->get_e(),*other_hex,parts); + // find(other_hex->get_f(),*other_hex,parts); + // find(other_hex->get_g(),*other_hex,parts); + // find(other_hex->get_h(),*other_hex,parts); + // if(!valid(*other_hex,parts)){ + // if (very_verbose) cout << "valid incompatible: other_hex " << other_hex << " relative to " << hex << endl; + // add_graph_entry(hex,other_hex); + // return; + // } + // else if (very_verbose) cout << "valid compatible: other_hex " << other_hex << " relative to " << hex << endl; + + if(!conformityA(*other_hex)){ + if (very_verbose) cout << "conformA incompatible: other_hex " << other_hex << " relative to " << hex << endl; + add_graph_entry(hex,other_hex); + return; } - } + else if (very_verbose) cout << "conformA compatible: other_hex " << other_hex << " relative to " << hex << endl; - return pointer; -} -void PostOp::mean(const std::set<MVertex*>& Ns,MVertex* mid,const std::vector<MElement*>& movables){ - unsigned int i; - int j; - bool flag; - double x,y,z; - double init_x,init_y,init_z; - std::set<MVertex*>::const_iterator it; + if(!conformityB(*other_hex)){ + if (very_verbose) cout << "conformB incompatible: other_hex " << other_hex << " relative to " << hex << endl; + add_graph_entry(hex,other_hex); + return; + } + else if (very_verbose) cout << "conformB compatible: other_hex " << other_hex << " relative to " << hex << endl; - x = 0.0; - y = 0.0; - z = 0.0; + if(!conformityC(*other_hex)){ + if (very_verbose) cout << "conformC incompatible: other_hex " << other_hex << " relative to " << hex << endl; + add_graph_entry(hex,other_hex); + return; + } + else if (very_verbose) cout << "conformC compatible: other_hex " << other_hex << " relative to " << hex << endl; - init_x = mid->x(); - init_y = mid->y(); - init_z = mid->z(); + if(!faces_statuquo(*other_hex)){ + if (very_verbose) cout << "faces_statuquo incompatible: other_hex " << other_hex << " relative to " << hex << endl; + add_graph_entry(hex,other_hex); + return; + } + else if (very_verbose) cout << "faces_statuquo compatible: other_hex " << other_hex << " relative to " << hex << endl; - for(it=Ns.begin();it!=Ns.end();it++){ - x = x + (*it)->x(); - y = y + (*it)->y(); - z = z + (*it)->z(); + if (very_verbose) cout << "other_hex " << other_hex << " relative to " << hex << " totaly compatible !!! " << endl; + // if (!two_faces_in_common){ + // export_single_hex_all(other_hex,""); + // export_single_hex_all(hex,""); + // + // //cout << "******************************** not two faces in common and compatible !!!********************************************************** " << endl; + // } } - x = x/Ns.size(); - y = y/Ns.size(); - z = z/Ns.size(); + // -------------------------------------------------------------------- - for(i=0;i<movables.size();i++){ - movables[i]->setVolumePositive(); + bool Recombinator_Graph::post_check_validation(Hex* current_hex){ + // post check... + // std::set<MElement*> parts; + // find(current_hex->get_a(),*current_hex,parts); + // find(current_hex->get_b(),*current_hex,parts); + // find(current_hex->get_c(),*current_hex,parts); + // find(current_hex->get_d(),*current_hex,parts); + // find(current_hex->get_e(),*current_hex,parts); + // find(current_hex->get_f(),*current_hex,parts); + // find(current_hex->get_g(),*current_hex,parts); + // find(current_hex->get_h(),*current_hex,parts); + // if(!valid(*current_hex,parts)){ + // std::cout << " not valid ! : hex " << current_hex << " made of "; + // for (int i=0;i<8;i++) + // cout << " " << current_hex->getVertex(i)->getNum(); + // cout << endl; + // return false; + // } + + if(!conformityA(*current_hex)){ + std::cout << " not conform A! : hex " << current_hex << " made of "; + for (int i=0;i<8;i++) + cout << " " << current_hex->getVertex(i)->getNum(); + cout << endl; + return false; + } + + if(!conformityB(*current_hex)){ + std::cout << " not conform B! : hex " << current_hex << " made of "; + for (int i=0;i<8;i++) + cout << " " << current_hex->getVertex(i)->getNum(); + cout << endl; + return false; + } + + if(!conformityC(*current_hex)){ + std::cout << " not conform C! : hex " << current_hex << " made of "; + for (int i=0;i<8;i++) + cout << " " << current_hex->getVertex(i)->getNum(); + cout << endl; + return false; + } + + if(!faces_statuquo(*current_hex)){ + std::cout << " not ok faces status quo! : hex " << current_hex << " made of "; + for (int i=0;i<8;i++) + cout << " " << current_hex->getVertex(i)->getNum(); + cout << endl; + return false; + } + + // end post check... + + + return true; } - mid->setXYZ(x,y,z); + // -------------------------------------------------------------------- - for(j=0;j<100;j++){ - flag = 0; + void Recombinator_Graph::add_face(const MVertex *a,const MVertex* b,const MVertex *c,std::multimap<unsigned long long, pair<PETriangle*,int> > &f){ + vector<const MVertex*> v; + v.push_back(a); + v.push_back(b); + v.push_back(c); + PETriangle *q = new PETriangle(v); + std::multimap<unsigned long long, pair<PETriangle*,int> >::iterator itfind = find_the_triangle(q,f); + if (itfind==f.end()){ + f.insert(make_pair(q->get_hash(),make_pair(q,1))); + } + else{ + delete q; + } + } - for(i=0;i<movables.size();i++){ - if(movables[i]->getVolume()<0.0){ - flag = 1; - } + // -------------------------------------------------------------------- + + void Recombinator_Graph::add_face(const MVertex *a,const MVertex* b,const MVertex *c,Hex *hex){ + vector<const MVertex*> v; + v.push_back(a); + v.push_back(b); + v.push_back(c); + PETriangle *q = new PETriangle(v); + citer itfind = find_the_triangle(q,triangular_faces); + if (itfind==triangular_faces.end()){ + itfind = triangular_faces.insert(make_pair(q->get_hash(),q)); } + else{ + delete q; + q = itfind->second; + } + + hex_to_faces[hex].insert(q); + faces_to_hex[q].insert(hex); + } + + // -------------------------------------------------------------------- + + void Recombinator_Graph::add_edges(Hex *hex){ + MVertex *a,*b,*c,*d; + MVertex *e,*f,*g,*h; + + a = hex->get_a(); + b = hex->get_b(); + c = hex->get_c(); + d = hex->get_d(); + e = hex->get_e(); + f = hex->get_f(); + g = hex->get_g(); + h = hex->get_h(); + + fill_edges_table(a,b,c,d,hex); + fill_edges_table(e,f,g,h,hex); + fill_edges_table(a,b,f,e,hex); + fill_edges_table(b,c,g,f,hex); + fill_edges_table(d,c,g,h,hex); + fill_edges_table(d,a,e,h,hex); + } + + // -------------------------------------------------------------------- + + void Recombinator_Graph::fill_edges_table(const MVertex *a, const MVertex *b, const MVertex *c, const MVertex *d, Hex *hex){ + vector<const MVertex* > v; + vector<const MVertex* > u; + v.push_back(a); + v.push_back(b); + v.push_back(c); + v.push_back(d); + + vector<const MVertex*>::const_iterator it1 = v.begin(); + for (;it1!=v.end();it1++){ + vector<const MVertex*>::const_iterator it2 = it1; + for (;it2!=v.end();it2++){ + if (it1==it2) continue; + + u.clear(); + u.push_back(*it1); + u.push_back(*it2); + // see if already exists or not... + PELine *l = new PELine(u); + linemap::const_iterator itfind = find_the_line(l,edges_and_diagonals); + if (itfind==edges_and_diagonals.end()){ + itfind = edges_and_diagonals.insert(make_pair(l->get_hash(),l)); + } + else{ + delete l; + l = itfind->second; + } - if(!flag){ - break; + hex_to_edges[hex].insert(l); + edges_to_hex[l].insert(hex); + } } + } - x = 0.1*init_x + 0.9*mid->x(); - y = 0.1*init_y + 0.9*mid->y(); - z = 0.1*init_z + 0.9*mid->z(); + // -------------------------------------------------------------------- - mid->setXYZ(x,y,z); + Recombinator_Graph::graph::iterator Recombinator_Graph::find_hex_in_graph(Hex* hex){ + pair<graph::iterator, graph::iterator> range = incompatibility_graph.equal_range(hex->get_hash()); + if (range.first==range.second) return incompatibility_graph.end(); + + graph::iterator it = range.first; + for (;it!=range.second;it++){ + if (it->second.first==hex){ + return it; + } + } + return incompatibility_graph.end(); } - iterations = iterations + j; + // -------------------------------------------------------------------- - for(j=0;j<6;j++){ - flag = 0; + Recombinator_Graph::graph_data::iterator Recombinator_Graph::find_hex_in_graphrow(Hex* hex, graph_data &row){ + pair<graph_data::iterator, graph_data::iterator> range = row.equal_range(hex->get_hash()); + if (range.first==range.second) return row.end(); - for(i=0;i<movables.size();i++){ - if(movables[i]->gammaShapeMeasure()<0.2){ - flag = 1; + graph_data::iterator it = range.first; + for (;it!=range.second;it++){ + if (it->second==hex){ + return it; } } + return row.end(); + } - if(!flag){ - break; - } - x = 0.1*init_x + 0.9*mid->x(); - y = 0.1*init_y + 0.9*mid->y(); - z = 0.1*init_z + 0.9*mid->z(); + // -------------------------------------------------------------------- + + bool Recombinator_Graph::find_hex_couple_in_graph(Hex* hex, Hex* other_hex){ + graph::iterator it = find_hex_in_graph(hex); + if (it==incompatibility_graph.end()) return false; + + graph_data::iterator itt = find_hex_in_graphrow(other_hex, it->second.second); + if (itt==it->second.second.end()) return false; + return true; - mid->setXYZ(x,y,z); } - iterations = iterations + j; -} + // -------------------------------------------------------------------- -double PostOp::workaround(MElement* element){ - double volume; - MTetrahedron* temp1; - MTetrahedron* temp2; + void Recombinator_Graph::add_graph_entry(Hex* hex, Hex* other_hex){ - volume = 0.0; + graph::iterator itfind_graph = find_hex_in_graph(hex); + + if (itfind_graph==incompatibility_graph.end()){ + itfind_graph = incompatibility_graph.insert(make_pair(hex->get_hash(),make_pair(hex, graph_data()))); + itfind_graph->second.second.insert(make_pair(other_hex->get_hash(),other_hex)); + set_of_all_hex_in_graph.insert(hex); + return; + } + else{ + itfind_graph->second.second.insert(make_pair(other_hex->get_hash(),other_hex)); + } - if(five(element)){ - temp1 = new MTetrahedron(element->getVertex(0),element->getVertex(1),element->getVertex(2),element->getVertex(4)); - temp2 = new MTetrahedron(element->getVertex(2),element->getVertex(3),element->getVertex(0),element->getVertex(4)); - volume = fabs(temp1->getVolume()) + fabs(temp2->getVolume()); - delete temp1; - delete temp2; } - return volume; -} + // -------------------------------------------------------------------- -MVertex* PostOp::find(MVertex* v1,MVertex* v2,MVertex* v3,MVertex* v4,MElement* element){ - int i; - MVertex* vertex; - MVertex* pointer; + void Recombinator_Graph::compute_hex_ranks(){ - pointer = 0; + create_faces_connectivity(); - for(i=0;i<element->getNumVertices();i++){ - vertex = element->getVertex(i); - if(vertex!=v1 && vertex!=v2 && vertex!=v3 && vertex!=v4){ - pointer = vertex; - break; + PETriangle* face; + Hex *hex; + double boundary_count; + + for (map<Hex*,set<PETriangle*> >::iterator it = hex_to_faces.begin();it!=hex_to_faces.end();it++){ + hex = it->first; + boundary_count=0.; + for (set<PETriangle*>::iterator itf = it->second.begin();itf!=it->second.end();itf++){ + face = *itf; + if (faces_connectivity[face]==1) boundary_count+=1.; + } + //cout << " --- hex " << hex << " has " << boundary_count << " tri faces on boundaries, " << hex_to_faces[hex].size() << " total tri faces " << endl; + map<Hex*,vector<double> >::iterator itfind = hex_ranks.find(hex); + if (itfind==hex_ranks.end()) + hex_ranks.insert(make_pair(hex,vector<double>(1))); + hex_ranks[hex][0] = boundary_count; + hex_ranks[hex][1] = hex->get_quality(); } } - return pointer; -} + // -------------------------------------------------------------------- -void PostOp::find_tetrahedra(MVertex* v1,MVertex* v2,std::set<MElement*>& final){ - std::map<MVertex*,std::set<MElement*> >::iterator it1; - std::map<MVertex*,std::set<MElement*> >::iterator it2; + void Recombinator_Graph::create_faces_connectivity(){ + for (std::map<MElement*, std::set<Hex*> >::iterator it_tet = tet_to_hex.begin(); it_tet!=tet_to_hex.end();it_tet++){ + add_face_connectivity(it_tet->first, 0,1,2); + add_face_connectivity(it_tet->first, 0,1,3); + add_face_connectivity(it_tet->first, 0,2,3); + add_face_connectivity(it_tet->first, 1,2,3); + } + } - it1 = vertex_to_tetrahedra.find(v1); - it2 = vertex_to_tetrahedra.find(v2); + // -------------------------------------------------------------------- - if(it1!=vertex_to_tetrahedra.end() && it2!=vertex_to_tetrahedra.end()){ - intersection(it1->second,it2->second,final); + void Recombinator_Graph::add_face_connectivity(MElement *tet, int i, int j, int k){ + vector<const MVertex*> v; + PETriangle *t; + v.push_back(tet->getVertex(i)); + v.push_back(tet->getVertex(j)); + v.push_back(tet->getVertex(k)); + t = new PETriangle(v); + citer itfind = find_the_triangle(t,triangular_faces); + if (itfind!=triangular_faces.end()){ + faces_connectivity[itfind->second]++; + } + delete t; } -} -void PostOp::find_pyramids(MVertex* v1,MVertex* v2,std::set<MElement*>& final){ - bool flag1,flag2,flag3,flag4; - bool flag5,flag6,flag7,flag8; - std::set<MElement*>::iterator it; - std::map<MVertex*,std::set<MElement*> >::iterator it1; - std::map<MVertex*,std::set<MElement*> >::iterator it2; - std::set<MElement*> temp; + // -------------------------------------------------------------------- - it1 = vertex_to_pyramids.find(v1); - it2 = vertex_to_pyramids.find(v2); + void Recombinator_Graph::compute_hex_ranks_blossom(){ - temp.clear(); + create_faces_connectivity(); - if(it1!=vertex_to_pyramids.end() && it2!=vertex_to_pyramids.end()){ - intersection(it1->second,it2->second,temp); - } + PETriangle* face; + Hex *hex; + double boundary_count; + MVertex *a,*b,*c,*d; + MVertex *e,*f,*g,*h; - for(it=temp.begin();it!=temp.end();it++){ - flag1 = equal(v1,v2,(*it)->getVertex(0),(*it)->getVertex(1)); - flag2 = equal(v1,v2,(*it)->getVertex(1),(*it)->getVertex(2)); - flag3 = equal(v1,v2,(*it)->getVertex(2),(*it)->getVertex(3)); - flag4 = equal(v1,v2,(*it)->getVertex(3),(*it)->getVertex(0)); - flag5 = equal(v1,v2,(*it)->getVertex(0),(*it)->getVertex(4)); - flag6 = equal(v1,v2,(*it)->getVertex(1),(*it)->getVertex(4)); - flag7 = equal(v1,v2,(*it)->getVertex(2),(*it)->getVertex(4)); - flag8 = equal(v1,v2,(*it)->getVertex(3),(*it)->getVertex(4)); - if(flag1 || flag2 || flag3 || flag4 || flag5 || flag6 || flag7 || flag8){ - final.insert(*it); - } - } -} + for (map<Hex*,set<PETriangle*> >::iterator it = hex_to_faces.begin();it!=hex_to_faces.end();it++){ + hex = it->first; + boundary_count=0.; + for (set<PETriangle*>::iterator itf = it->second.begin();itf!=it->second.end();itf++){ + face = *itf; + if (faces_connectivity[face]==1) boundary_count+=1.; + } + //cout << " --- hex " << hex << " has " << boundary_count << " tri faces on boundaries, " << hex_to_faces[hex].size() << " total tri faces " << endl; + map<Hex*,vector<double> >::iterator itfind = hex_ranks.find(hex); + if (itfind==hex_ranks.end()) + hex_ranks.insert(make_pair(hex,vector<double>(1))); + hex_ranks[hex][0] = boundary_count; + hex_ranks[hex][1] = hex->get_quality(); -void PostOp::intersection(const std::set<MElement*>& bin1,const std::set<MElement*>& bin2,std::set<MElement*>& final){ - std::set_intersection(bin1.begin(),bin1.end(),bin2.begin(),bin2.end(),std::inserter(final,final.end())); -} -void PostOp::build_vertex_to_tetrahedra(GRegion* gr){ - unsigned int i; - MElement* element; + a = hex->get_a(); + b = hex->get_b(); + c = hex->get_c(); + d = hex->get_d(); + e = hex->get_e(); + f = hex->get_f(); + g = hex->get_g(); + h = hex->get_h(); - vertex_to_tetrahedra.clear(); + int count_blossom=0; + if (find_face_in_blossom_info(a,b,c,d)) count_blossom++; + if (find_face_in_blossom_info(e,f,g,h)) count_blossom++; + if (find_face_in_blossom_info(a,b,f,e)) count_blossom++; + if (find_face_in_blossom_info(b,c,g,f)) count_blossom++; + if (find_face_in_blossom_info(d,c,g,h)) count_blossom++; + if (find_face_in_blossom_info(d,a,e,h)) count_blossom++; + + hex_ranks[hex][2] = count_blossom; - for(i=0;i<gr->getNumMeshElements();i++){ - element = gr->getMeshElement(i); - if(four(element)){ - build_vertex_to_tetrahedra(element); } } -} -void PostOp::build_vertex_to_tetrahedra(MElement* element){ - int i; - MVertex* vertex; - std::set<MElement*> bin; - std::map<MVertex*,std::set<MElement*> >::iterator it; + // -------------------------------------------------------------------- - for(i=0;i<element->getNumVertices();i++){ - vertex = element->getVertex(i); + bool Recombinator_Graph::find_face_in_blossom_info(MVertex *a, MVertex *b, MVertex *c, MVertex *d){ + PETriangle *t1,*t2; - it = vertex_to_tetrahedra.find(vertex); - if(it!=vertex_to_tetrahedra.end()){ - it->second.insert(element); - } - else{ - bin.clear(); - bin.insert(element); - vertex_to_tetrahedra.insert(std::pair<MVertex*,std::set<MElement*> >(vertex,bin)); - } - } -} + t1 = get_triangle(a,b,c); + t2 = get_triangle(a,c,d); -void PostOp::erase_vertex_to_tetrahedra(MElement* element){ - int i; - MVertex* vertex; - std::map<MVertex*,std::set<MElement*> >::iterator it; + if (is_blossom_pair(t1,t2)) + return true; - for(i=0;i<element->getNumVertices();i++){ - vertex = element->getVertex(i); - it = vertex_to_tetrahedra.find(vertex); - if(it!=vertex_to_tetrahedra.end()){ - it->second.erase(element); - } + t1 = get_triangle(a,b,d); + t2 = get_triangle(b,c,d); + if (is_blossom_pair(t1,t2)) + return true; + + return false; } -} -void PostOp::build_vertex_to_pyramids(GRegion* gr){ - unsigned int i; - MElement* element; + // -------------------------------------------------------------------- - vertex_to_pyramids.clear(); + PETriangle* Recombinator_Graph::get_triangle(MVertex*a, MVertex* b, MVertex *c){ + vector<const MVertex*> v; + v.push_back(a); + v.push_back(b); + v.push_back(c); + PETriangle *t = new PETriangle(v); + citer it_find_tri = find_the_triangle(t, triangular_faces); + delete t; + return (it_find_tri->second); + } - for(i=0;i<gr->getNumMeshElements();i++){ - element = gr->getMeshElement(i); - if(five(element)){ - build_vertex_to_pyramids(element); + // -------------------------------------------------------------------- + + bool Recombinator_Graph::is_blossom_pair(PETriangle *t1, PETriangle *t2){ + tripair::iterator itfind = blossom_info.find(t1); + if (itfind!=blossom_info.end()){ + if (t2==itfind->second) + return true; } + return false; } -} -void PostOp::build_vertex_to_pyramids(MElement* element){ - int i; - MVertex* vertex; - std::set<MElement*> bin; - std::map<MVertex*,std::set<MElement*> >::iterator it; - for(i=0;i<element->getNumVertices();i++){ - vertex = element->getVertex(i); - it = vertex_to_pyramids.find(vertex); - if(it!=vertex_to_pyramids.end()){ - it->second.insert(element); - } - else{ - bin.clear(); - bin.insert(element); - vertex_to_pyramids.insert(std::pair<MVertex*,std::set<MElement*> >(vertex,bin)); - } - } -} -void PostOp::erase_vertex_to_pyramids(MElement* element){ - int i; - MVertex* vertex; - std::map<MVertex*,std::set<MElement*> >::iterator it; - for(i=0;i<element->getNumVertices();i++){ - vertex = element->getVertex(i); - it = vertex_to_pyramids.find(vertex); - if(it!=vertex_to_pyramids.end()){ - it->second.erase(element); - } - } -} + + + diff --git a/Mesh/yamakawa.h b/Mesh/yamakawa.h index 905b9e5892..41e22ce2a7 100644 --- a/Mesh/yamakawa.h +++ b/Mesh/yamakawa.h @@ -11,269 +11,600 @@ #include "GRegion.h" +#include "MVertex.h" #include <set> +#include <tr1/unordered_set> +#include <tr1/unordered_map> + +using namespace std; + +//-------------------------------------------------------------------------------------- + +extern void export_gregion_mesh(GRegion *gr, string filename); + +//-------------------------------------------------------------------------------------- + +class PEEntity{ + protected: + vector<const MVertex *> vertices; + size_t hash; + void compute_hash(); + public: + PEEntity(const vector<const MVertex*> &_v); + //PEEntity(size_t l); + ~PEEntity(); + virtual size_t get_max_nb_vertices() const=0; + const MVertex* getVertex(size_t n) const; + bool hasVertex(const MVertex *v)const; + size_t get_hash() const; + bool same_vertices(const PEEntity *t)const; + bool operator<(const PEEntity&) const; + //bool operator==(const PEEntity&) const; + //bool operator==(const size_t&) const; +}; + +class PELine : public PEEntity{ + public: + PELine(const vector<const MVertex*> &_v); + ~PELine(); + size_t get_max_nb_vertices() const; +}; + +class PETriangle : public PEEntity{ + public: + PETriangle(const vector<const MVertex*> &_v); + //PETriangle(size_t l); + ~PETriangle(); + size_t get_max_nb_vertices() const; +}; + +class PEQuadrangle : public PEEntity{ + public: + PEQuadrangle(const vector<const MVertex*> &_v); + //PEQuadrangle(size_t l); + ~PEQuadrangle(); + size_t get_max_nb_vertices() const; +}; + +//-------------------------------------------------------------------------------------- + +template<class T> +class clique_stop_criteria{ + public: + typedef tr1::unordered_set<T> graph_data_no_hash; + clique_stop_criteria(map<T, std::set<MElement*> > &_m, int _i); + ~clique_stop_criteria(); + bool stop(const graph_data_no_hash &clique)const; + void export_corresponding_mesh(const graph_data_no_hash &clique)const; + + private: + const map<T, std::set<MElement*> > &hex_to_tet; + const unsigned int total_number_tet; +}; + +//-------------------------------------------------------------------------------------- + +template<class T> +class cliques_compatibility_graph{ + public: + typedef unsigned long long hash_key; + +// typedef set<T> graph_data; +// typedef map<T, graph_data > graph; +// typedef multimap<int,T> ranking_data; + typedef tr1::unordered_set<T> graph_data_no_hash; + typedef tr1::unordered_multimap<hash_key, T> graph_data; + typedef tr1::unordered_multimap<hash_key, pair<T, graph_data > > graph; + typedef tr1::unordered_map<int,T> ranking_data; + + typedef void (*ptrfunction_export)(cliques_compatibility_graph<T>&, int, string); + + cliques_compatibility_graph(graph &_g, const map<T, std::vector<double> > &_hex_ranks, unsigned int _max_nb_cliques, unsigned int _nb_hex_potentiels, clique_stop_criteria<T> *csc, ptrfunction_export fct); + ~cliques_compatibility_graph(); + void find_cliques(); + void export_cliques(); + + virtual typename graph::const_iterator begin_graph(){return G.begin();}; + virtual typename graph::const_iterator end_graph(){return G.end();}; + + bool found_the_ultimate_max_clique; + + multimap<int, set<T> > allQ;// all cliques + + protected: + void erase_entry(graph_data &s, T &u, hash_key &key); + void find_cliques(graph_data &s,int n); + void split_set_BW(const T &u, const hash_key &u_key,const graph_data &s, graph_data &white, graph_data &black); + void fill_black_set(const T &u, const hash_key &u_key, const graph_data &s, graph_data &black); + void choose_u(const graph_data &s, T &u, hash_key &u_key); + // the maximum score (int) will be chosen... + double function_to_maximize_for_u(const T &u, const hash_key &u_key, const graph_data &s); + void store_clique(int n); + // returns true if two nodes are connected in the compatibility graph + virtual bool compatibility(const T &u, const hash_key &u_key, const T &v, const hash_key &v_key); + + ptrfunction_export export_clique_graph; + + const bool debug; + unsigned int max_nb_cliques; + unsigned int nb_hex_potentiels; + unsigned int max_clique_size; + unsigned int position; + unsigned int total_nodes_number; + unsigned int total_nb_of_cliques_searched; + unsigned int max_nb_of_stored_cliques;// to reduce memory footprint (set to zero if no limit) + + clique_stop_criteria<T>* criteria; + + bool cancel_search; + const map<T, std::vector<double> > &hex_ranks; + graph &G; + graph_data_no_hash Q;// the current clique +}; + + +//-------------------------------------------------------------------------------------- + +template<class T> +class cliques_losses_graph : public cliques_compatibility_graph<T> { +// typedef set<T> graph_data; +// typedef map<T, graph_data > graph; +// typedef tr1::unordered_set<T> graph_data; +// typedef tr1::unordered_map<T, graph_data > graph; + public: + typedef unsigned long long hash_key; + typedef tr1::unordered_multimap<hash_key, T> graph_data; + typedef tr1::unordered_multimap<hash_key, pair<T, graph_data > > graph; + typedef void (*ptrfunction_export)(cliques_compatibility_graph<T>&, int, string); + + cliques_losses_graph(graph &_g, const map<T, std::vector<double> > &_hex_ranks, unsigned int _max_nb_cliques, unsigned int _nb_hex_potentiels, clique_stop_criteria<T> *csc, ptrfunction_export fct); + ~cliques_losses_graph(); + + protected: + // returns false if two nodes are connected in the losses graph (i.e. true if connected in compatibility graph) + virtual bool compatibility(const T &u, const hash_key &u_key, const T &v, const hash_key &v_key); + graph &G; +}; + +//-------------------------------------------------------------------------------------- + + class Hex{ - private: - double quality; - MVertex *a,*b,*c,*d,*e,*f,*g,*h; - public: - Hex(); - Hex(MVertex*,MVertex*,MVertex*,MVertex*,MVertex*,MVertex*,MVertex*,MVertex*); - ~Hex(); - double get_quality() const; - void set_quality(double); - MVertex* get_a(); - MVertex* get_b(); - MVertex* get_c(); - MVertex* get_d(); - MVertex* get_e(); - MVertex* get_f(); - MVertex* get_g(); - MVertex* get_h(); - void set_vertices(MVertex*,MVertex*,MVertex*,MVertex*,MVertex*,MVertex*,MVertex*,MVertex*); - bool operator<(const Hex&) const; + private: + double quality; + unsigned long long hash; + MVertex *a,*b,*c,*d,*e,*f,*g,*h; + void set_hash(); + public: + Hex(); + Hex(MVertex*,MVertex*,MVertex*,MVertex*,MVertex*,MVertex*,MVertex*,MVertex*); + ~Hex(); + double get_quality(); + void set_quality(double); + MVertex* get_a(); + MVertex* get_b(); + MVertex* get_c(); + MVertex* get_d(); + MVertex* get_e(); + MVertex* get_f(); + MVertex* get_g(); + MVertex* get_h(); + MVertex* getVertex(int n); + bool hasVertex(const MVertex *v); + bool same_vertices(Hex *h); + void set_vertices(MVertex*,MVertex*,MVertex*,MVertex*,MVertex*,MVertex*,MVertex*,MVertex*); + unsigned long long get_hash(); + bool operator<( Hex&) ; }; class Facet{ - private: - MVertex *a,*b,*c; - unsigned long long hash; - public: - Facet(); - Facet(MVertex*,MVertex*,MVertex*); - ~Facet(); - MVertex* get_a(); - MVertex* get_b(); - MVertex* get_c(); - void set_vertices(MVertex*,MVertex*,MVertex*); - bool same_vertices(Facet); - void compute_hash(); - unsigned long long get_hash() const; - bool operator<(const Facet&) const; + private: + MVertex *a,*b,*c; + unsigned long long hash; + public: + Facet(); + Facet(MVertex*,MVertex*,MVertex*); + ~Facet(); + MVertex* get_a(); + MVertex* get_b(); + MVertex* get_c(); + void set_vertices(MVertex*,MVertex*,MVertex*); + bool same_vertices(Facet); + void compute_hash(); + unsigned long long get_hash() const; + bool operator<(const Facet&) const; }; class Diagonal{ - private: - MVertex *a,*b; - unsigned long long hash; - public: - Diagonal(); - Diagonal(MVertex*,MVertex*); - ~Diagonal(); - MVertex* get_a(); - MVertex* get_b(); - void set_vertices(MVertex*,MVertex*); - bool same_vertices(Diagonal); - void compute_hash(); - unsigned long long get_hash() const; - bool operator<(const Diagonal&) const; + private: + MVertex *a,*b; + unsigned long long hash; + public: + Diagonal(); + Diagonal(MVertex*,MVertex*); + ~Diagonal(); + MVertex* get_a(); + MVertex* get_b(); + void set_vertices(MVertex*,MVertex*); + bool same_vertices(Diagonal); + void compute_hash(); + unsigned long long get_hash() const; + bool operator<(const Diagonal&) const; }; class Tuple{ - private: - MVertex *v1,*v2,*v3; - MElement* element; - GFace* gf; - unsigned long long hash; - public: - Tuple(); - Tuple(MVertex*,MVertex*,MVertex*,MElement*,GFace*); - Tuple(MVertex*,MVertex*,MVertex*); - ~Tuple(); - MVertex* get_v1(); - MVertex* get_v2(); - MVertex* get_v3(); - MElement* get_element() const; - GFace* get_gf() const; - bool same_vertices(Tuple); - unsigned long long get_hash() const; - bool operator<(const Tuple&) const; + private: + MVertex *v1,*v2,*v3; + MElement* element; + GFace* gf; + unsigned long long hash; + public: + Tuple(); + Tuple(MVertex*,MVertex*,MVertex*,MElement*,GFace*); + Tuple(MVertex*,MVertex*,MVertex*); + ~Tuple(); + MVertex* get_v1(); + MVertex* get_v2(); + MVertex* get_v3(); + MElement* get_element() const; + GFace* get_gf() const; + bool same_vertices(Tuple); + unsigned long long get_hash() const; + bool operator<(const Tuple&) const; +}; + +inline std::ostream& operator<<(std::ostream& s, const PETriangle& t){ + const MVertex *v; + for (int i=0;i<3;i++){ + v = t.getVertex(i); + s << "(" << v->x() << "," << v->y() << "," << v->z() << ")"; + } + return s; }; class Recombinator{ - private: - std::vector<Hex> potential; - std::map<MElement*,bool> markings; - std::multiset<Facet> hash_tableA; - std::multiset<Diagonal> hash_tableB; - std::multiset<Diagonal> hash_tableC; - std::multiset<Tuple> tuples; - std::set<MElement*> triangles; - public: - Recombinator(); - ~Recombinator(); - - std::map<MVertex*,std::set<MVertex*> > vertex_to_vertices; - std::map<MVertex*,std::set<MElement*> > vertex_to_elements; - - void execute(); - void execute(GRegion*); - - void init_markings(GRegion*); - void pattern1(GRegion*); - void pattern2(GRegion*); - void pattern3(GRegion*); - void merge(GRegion*); - void improved_merge(GRegion*); - void rearrange(GRegion*); - void statistics(GRegion*); - void build_tuples(GRegion*); - void modify_surfaces(GRegion*); - void modify_surfaces(MVertex*,MVertex*,MVertex*,MVertex*); - - bool sliver(MElement*,Hex); - double diagonal(MElement*,int&,int&); - double distance(MVertex*,MVertex*); - double distance(MVertex*,MVertex*,MVertex*); - double scalar(MVertex*,MVertex*,MVertex*,MVertex*); - void two_others(int,int,int&,int&); - bool valid(Hex,const std::set<MElement*>&); - bool valid(Hex); - double eta(MVertex*,MVertex*,MVertex*,MVertex*); - bool linked(MVertex*,MVertex*); - - void find(MVertex*,MVertex*,const std::vector<MVertex*>&,std::set<MVertex*>&); - void find(MVertex*,MVertex*,MVertex*,const std::vector<MVertex*>&,std::set<MVertex*>&); - void find(MVertex*,MVertex*,std::set<MElement*>&); - void find(MVertex*,Hex,std::set<MElement*>&); - MVertex* find(MVertex*,MVertex*,MVertex*,MVertex*,const std::set<MElement*>&); - - void intersection(const std::set<MVertex*>&,const std::set<MVertex*>&,const std::vector<MVertex*>&,std::set<MVertex*>&); - void intersection(const std::set<MVertex*>&,const std::set<MVertex*>&,const std::set<MVertex*>&,const std::vector<MVertex*>&,std::set<MVertex*>&); - void intersection(const std::set<MElement*>&,const std::set<MElement*>&,std::set<MElement*>&); - - bool inclusion(MVertex*,Hex); - bool inclusion(MVertex*,MVertex*,MVertex*,MVertex*,MVertex*); - bool inclusion(MVertex*,MVertex*,MVertex*,const std::set<MElement*>&); - bool inclusion(Facet); - bool inclusion(Diagonal); - bool duplicate(Diagonal); - - bool conformityA(Hex); - bool conformityA(MVertex*,MVertex*,MVertex*,MVertex*); - bool conformityB(Hex); - bool conformityC(Hex); - - bool faces_statuquo(Hex); - bool faces_statuquo(MVertex*,MVertex*,MVertex*,MVertex*); - - void build_vertex_to_vertices(GRegion*); - void build_vertex_to_elements(GRegion*); - void build_hash_tableA(Hex); - void build_hash_tableA(MVertex*,MVertex*,MVertex*,MVertex*); - void build_hash_tableA(Facet); - void build_hash_tableB(Hex); - void build_hash_tableB(MVertex*,MVertex*,MVertex*,MVertex*); - void build_hash_tableB(Diagonal); - void build_hash_tableC(Hex); - void build_hash_tableC(Diagonal); - - void print_vertex_to_vertices(GRegion*); - void print_vertex_to_elements(GRegion*); - void print_hash_tableA(); - void print_segment(SPoint3,SPoint3,std::ofstream&); - - double scaled_jacobian(MVertex*,MVertex*,MVertex*,MVertex*); - double max_scaled_jacobian(MElement*,int&); - double min_scaled_jacobian(Hex); + protected: + std::vector<Hex*> potential; + std::map<MElement*,bool> markings; + std::multiset<Facet> hash_tableA; + std::multiset<Diagonal> hash_tableB; + std::multiset<Diagonal> hash_tableC; + std::multiset<Tuple> tuples; + std::set<MElement*> triangles; + public: + Recombinator(); + ~Recombinator(); + + std::map<MVertex*,std::set<MVertex*> > vertex_to_vertices; + std::map<MVertex*,std::set<MElement*> > vertex_to_elements; + + virtual void execute(); + virtual void execute(GRegion*); + + void init_markings(GRegion*); + virtual void pattern1(GRegion*); + virtual void pattern2(GRegion*); + virtual void pattern3(GRegion*); + virtual void merge(GRegion*); + void improved_merge(GRegion*); + void rearrange(GRegion*); + void statistics(GRegion*); + // tuples are triangles on geometrical faces (region boundaries...) + void build_tuples(GRegion*); + void modify_surfaces(GRegion*); + void modify_surfaces(MVertex*,MVertex*,MVertex*,MVertex*); + + bool sliver(MElement*,Hex&); + double diagonal(MElement*,int&,int&); + double distance(MVertex*,MVertex*); + double distance(MVertex*,MVertex*,MVertex*); + double scalar(MVertex*,MVertex*,MVertex*,MVertex*); + void two_others(int,int,int&,int&); + // soit une face du cube: abcd + // en principe, on doit avoir soit les facets (abc) et (acd), soit les facets (abd) et(bcd) qui sont inclues dans un des tets qui forment l'hex. + // si c'est le cas pour toutes les 6 faces de l'hex, return true. + // ce test permet probablement de virer les hex "avec des trous" (avec 8 noeuds ok, mais un tet manquant, ce qui peut occasionner un hex à 14 faces, par exemple, si l'on compte les faces à partir des tets inclus) + bool valid(Hex&,const std::set<MElement*>&); + // renvoie true si le "MQuadrangle::etaShapeMeasure" des 6 faces est plus grand que 0.000001 + bool valid(Hex&); + double eta(MVertex*,MVertex*,MVertex*,MVertex*); + bool linked(MVertex*,MVertex*); + + void find(MVertex*,MVertex*,const std::vector<MVertex*>&,std::set<MVertex*>&); + void find(MVertex*,MVertex*,MVertex*,const std::vector<MVertex*>&,std::set<MVertex*>&); + void find(MVertex*,MVertex*,std::set<MElement*>&); + void find(MVertex*,Hex,std::set<MElement*>&); + MVertex* find(MVertex*,MVertex*,MVertex*,MVertex*,const std::set<MElement*>&); + + void intersection(const std::set<MVertex*>&,const std::set<MVertex*>&,const std::vector<MVertex*>&,std::set<MVertex*>&); + void intersection(const std::set<MVertex*>&,const std::set<MVertex*>&,const std::set<MVertex*>&,const std::vector<MVertex*>&,std::set<MVertex*>&); + void intersection(const std::set<MElement*>&,const std::set<MElement*>&,std::set<MElement*>&); + + // return true if vertex belong to hex + bool inclusion(MVertex*,Hex); + // renvoie true si vertex se trouve dans [a,b,c] + bool inclusion(MVertex*,MVertex*,MVertex*,MVertex*,MVertex*); + // return true if all three vertices v1,v2 and v3 belong to one tet + bool inclusion(MVertex*,MVertex*,MVertex*,const std::set<MElement*>&); + // return true si la facet existe dans la table A + bool inclusion(Facet); + // return true si la diagonal existe dans la table B + bool inclusion(Diagonal); + // return true si la diagonal existe dans la table C !!!!!!!!! Sinon, c'est exactement la même fonction !!!!! avec un nom différent ! + bool duplicate(Diagonal); + + // return true si un hex est "conforme A" + // est "conforme A" un hex dont les 6 faces sont "conforme A" + bool conformityA(Hex&); + // est "conforme A" une face si ses 4 facets existent dans tableA, ou bien si aucune des ses facets ne se trouve dans table A + bool conformityA(MVertex*,MVertex*,MVertex*,MVertex*); +// return false si: +//- une des 12 arrêtes de l'hex se trouve dans tableB !!! (pas C !!!), cà d si une arrete a été utilisée comme diagonale d'un autre hex +//- (ou bien) si, pour chaque face de l'hex, on a une diagonale dans tableB et pas l'autre + bool conformityB(Hex&); +// return false si une des 12 diagonales du cube se trouve dans tableC, cà d a été utilisée comme arrête + bool conformityC(Hex&); + + // return true si les 6 faces de l'hex sont "faces_statuquo" + bool faces_statuquo(Hex&); + // return false si, parmis les deux paires de facets de la face, il existe un couple de facet qui soient toutes les deux des tuples, mais correspondant à des geometric faces différentes. Bref, une arrête géométrique confondue avec une diagonale de la face. + bool faces_statuquo(MVertex*,MVertex*,MVertex*,MVertex*); + + void build_vertex_to_vertices(GRegion*); + void build_vertex_to_elements(GRegion*); + void build_hash_tableA(Hex); + void build_hash_tableA(MVertex*,MVertex*,MVertex*,MVertex*); + void build_hash_tableA(Facet); + void build_hash_tableB(Hex); + void build_hash_tableB(MVertex*,MVertex*,MVertex*,MVertex*); + void build_hash_tableB(Diagonal); + void build_hash_tableC(Hex); + void build_hash_tableC(Diagonal); + + void print_vertex_to_vertices(GRegion*); + void print_vertex_to_elements(GRegion*); + void print_hash_tableA(); + void print_segment(SPoint3,SPoint3,std::ofstream&); + + double scaled_jacobian(MVertex*,MVertex*,MVertex*,MVertex*); + double max_scaled_jacobian(MElement*,int&); + double min_scaled_jacobian(Hex&); +}; + +class Recombinator_Graph : public Recombinator{ + public: + typedef size_t my_hash_key; + typedef multimap<my_hash_key,PETriangle*> trimap; + typedef map<PETriangle*, PETriangle*> tripair; + + + //typedef tr1::unordered_multimap<my_hash_key,PETriangle*> trimap; + typedef trimap::iterator iter; + typedef trimap::const_iterator citer; + + typedef multimap<my_hash_key,PELine*> linemap; + //typedef tr1::unordered_multimap<my_hash_key,PELine*> linemap; + + + bool found_the_ultimate_max_clique; + + set<Hex*>& getHexInGraph(){return set_of_all_hex_in_graph;}; + + protected: + bool debug,debug_graph; + std::map<Hex*, std::set<MElement*> > hex_to_tet; + std::map<Hex*, std::set<PELine*> > hex_to_edges; + std::map<PELine*, std::set<Hex*> > edges_to_hex; + std::map<Hex*, std::set<PETriangle*> > hex_to_faces; + std::map<PETriangle*, std::set<Hex*> > faces_to_hex; + std::map<PETriangle*, unsigned int > faces_connectivity;// # of adjacent tets (1 or 2) + std::map<MElement*, std::set<Hex*> >tet_to_hex; + std::map<Hex*, std::vector<double> > hex_ranks; + + + typedef unsigned long long hash_key; + typedef tr1::unordered_multimap<hash_key, Hex*> graph_data; + typedef tr1::unordered_multimap<hash_key, pair<Hex*, graph_data > > graph; + + graph incompatibility_graph; + set<Hex*> set_of_all_hex_in_graph; + + std::multimap<unsigned long long, Hex*>created_potential_hex; + + void create_faces_connectivity(); + void add_face_connectivity(MElement *tet, int i, int j, int k); + + void add_edges(Hex *hex); + void fill_edges_table(const MVertex *a, const MVertex *b, const MVertex *c, const MVertex *d, Hex *hex); + void add_face(const MVertex *a,const MVertex* b,const MVertex *c,Hex *hex); + void add_face(const MVertex *a,const MVertex* b,const MVertex *c,std::multimap<unsigned long long, pair<PETriangle*,int> > &f); + std::multimap<double,Hex*> degree;// degree = the final ranking of hexahedra + std::multimap<int,Hex*> idegree;// idegree = number of connected hex in indirect neighbors graph + std::multimap<int,Hex*> ndegree;// ndegree = number of direct neighbors !!! not chosen yet !!! + std::map<Hex*,int> reverse_idegree; + std::map<Hex*,int> reverse_ndegree; + // each tet has at least one neighbor, at most four. For all not chosen hex, check this data to find how many direct neighbors... +// std::map<MElement*,set<PETriangle*> > tet_to_triangle; + std::map<PETriangle*,set<MElement*> > triangle_to_tet; + std::map<MElement*,int> tet_degree; + + bool find_face_in_blossom_info(MVertex *a, MVertex *b, MVertex *c, MVertex *d); + void compute_hex_ranks_blossom(); + PETriangle* get_triangle(MVertex*a, MVertex* b, MVertex *c); + bool is_blossom_pair(PETriangle *t1, PETriangle *t2); + + tripair blossom_info; + trimap triangular_faces; + linemap edges_and_diagonals; + + map<PETriangle*, GFace*> tri_to_gface_info; + + vector<Hex*> chosen_hex; + vector<MElement*> chosen_tet; + + citer find_the_triangle(PETriangle *t, const trimap &list); + linemap::const_iterator find_the_line(PELine *t, const linemap &list); + std::multimap<unsigned long long, pair<PETriangle*,int> >::iterator find_the_triangle(PETriangle *t, std::multimap<unsigned long long, pair<PETriangle*, int> > &list); + std::multimap<unsigned long long, Hex* >::const_iterator find_the_created_potential_hex(Hex *t, const std::multimap<unsigned long long, Hex*> &list); + + int nbhex_in_losses_graph; + double average_connectivity; + bool post_check_validation(Hex* current_hex); + + PETriangle* get_triangle(MElement *element, int i, int j, int k); + + void compute_hex_ranks(); + + // check if the hex is good enough to be put into the graph. If not in the graph, it cannot be chosen... + bool is_not_good_enough(Hex* hex); + + // fills incompatibility_graph if two hex share a common (non-sliver!) tet + void create_indirect_neighbors_graph(); + + graph::iterator find_hex_in_graph(Hex* hex); + graph_data::iterator find_hex_in_graphrow(Hex* hex, graph_data &row); + bool find_hex_couple_in_graph(Hex* hex, Hex* other_hex); + void add_graph_entry(Hex* hex, Hex* other_hex); + + // fills incompatibility_graph if two hex are incompatible direct neighbors, + // i.e. they have one (or more) common face or common edge and are not compatible + void create_direct_neighbors_incompatibility_graph(); + void evaluate_hex_couple(Hex* hex, Hex* other_hex); + + // if two hex are not connected in the incompatibility_graph, they are compatible + void create_losses_graph(GRegion *gr); + + void merge_clique(GRegion* gr, cliques_losses_graph<Hex*> &cl,int clique_number=0); + + void fill_tet_to_hex_table(Hex *hex); + + virtual void pattern1(GRegion*); + virtual void pattern2(GRegion*); + virtual void pattern3(GRegion*); + + void merge(GRegion*); + + // ------- exports -------- + void export_tets(set<MElement*> &tetset, Hex* hex, string s); + void export_single_hex_all(Hex* hex,string s); + void export_single_hex(Hex* hex,string s); + void export_single_hex_faces(Hex* hex,string s); + void export_single_hex_tet(Hex* hex,string s); + void export_all_hex(int &file,GRegion *gr); + void export_hexmesh_so_far(int &file); + void export_direct_neighbor_table(int max); + void export_hex_init_degree(GRegion *gr, const std::map<Hex*,int> &init_degree, const vector<Hex*> &chosen_hex); + + public: + ~Recombinator_Graph(); + virtual void execute(unsigned int max_nb_cliques, string filename=string()); + virtual void execute(GRegion*, unsigned int max_nb_cliques, string filename=string()); + virtual void buildGraphOnly(unsigned int max_nb_cliques, string filename=string()); + virtual void buildGraphOnly(GRegion*, unsigned int max_nb_cliques, string filename=string()); + virtual void execute_blossom(unsigned int max_nb_cliques, string filename=string()); + virtual void execute_blossom(GRegion*, unsigned int max_nb_cliques, string filename=string()); + virtual void createBlossomInfo(); + void createBlossomInfo(GRegion *gr); }; class Prism{ - private: - double quality; - MVertex *a,*b,*c,*d,*e,*f; - public: - Prism(); - Prism(MVertex*,MVertex*,MVertex*,MVertex*,MVertex*,MVertex*); - ~Prism(); - double get_quality() const; - void set_quality(double); - MVertex* get_a(); - MVertex* get_b(); - MVertex* get_c(); - MVertex* get_d(); - MVertex* get_e(); - MVertex* get_f(); - void set_vertices(MVertex*,MVertex*,MVertex*,MVertex*,MVertex*,MVertex*); - bool operator<(const Prism&) const; + private: + double quality; + MVertex *a,*b,*c,*d,*e,*f; + public: + Prism(); + Prism(MVertex*,MVertex*,MVertex*,MVertex*,MVertex*,MVertex*); + ~Prism(); + double get_quality() const; + void set_quality(double); + MVertex* get_a(); + MVertex* get_b(); + MVertex* get_c(); + MVertex* get_d(); + MVertex* get_e(); + MVertex* get_f(); + void set_vertices(MVertex*,MVertex*,MVertex*,MVertex*,MVertex*,MVertex*); + bool operator<(const Prism&) const; }; class Supplementary{ - private: - std::vector<Prism> potential; - std::map<MElement*,bool> markings; - std::map<MVertex*,std::set<MVertex*> > vertex_to_vertices; - std::map<MVertex*,std::set<MElement*> > vertex_to_tetrahedra; - std::multiset<Facet> hash_tableA; - std::multiset<Diagonal> hash_tableB; - std::multiset<Diagonal> hash_tableC; - std::multiset<Tuple> tuples; - std::set<MElement*> triangles; - public: - Supplementary(); - ~Supplementary(); - - void execute(); - void execute(GRegion*); - - void init_markings(GRegion*); - void pattern(GRegion*); - void merge(GRegion*); - void rearrange(GRegion*); - void statistics(GRegion*); - void build_tuples(GRegion*); - void modify_surfaces(GRegion*); - void modify_surfaces(MVertex*,MVertex*,MVertex*,MVertex*); - - bool four(MElement*); - bool five(MElement*); - bool six(MElement*); - bool eight(MElement*); - - bool sliver(MElement*,Prism); - bool valid(Prism,const std::set<MElement*>&); - bool valid(Prism); - double eta(MVertex*,MVertex*,MVertex*,MVertex*); - bool linked(MVertex*,MVertex*); - - void find(MVertex*,MVertex*,const std::vector<MVertex*>&,std::set<MVertex*>&); - void find(MVertex*,Prism,std::set<MElement*>&); - - void intersection(const std::set<MVertex*>&,const std::set<MVertex*>&,const std::vector<MVertex*>&,std::set<MVertex*>&); - - bool inclusion(MVertex*,Prism); - bool inclusion(MVertex*,MVertex*,MVertex*,MVertex*,MVertex*); - bool inclusion(MVertex*,MVertex*,MVertex*,const std::set<MElement*>&); - bool inclusion(Facet); - bool inclusion(Diagonal); - bool duplicate(Diagonal); - - bool conformityA(Prism); - bool conformityA(MVertex*,MVertex*,MVertex*,MVertex*); - bool conformityB(Prism); - bool conformityC(Prism); - - bool faces_statuquo(Prism); - bool faces_statuquo(MVertex*,MVertex*,MVertex*,MVertex*); - - void build_vertex_to_vertices(GRegion*); - void build_vertex_to_tetrahedra(GRegion*); - void build_hash_tableA(Prism); - void build_hash_tableA(MVertex*,MVertex*,MVertex*,MVertex*); - void build_hash_tableA(Facet); - void build_hash_tableB(Prism); - void build_hash_tableB(MVertex*,MVertex*,MVertex*,MVertex*); - void build_hash_tableB(Diagonal); - void build_hash_tableC(Prism); - void build_hash_tableC(Diagonal); - - double scaled_jacobian(MVertex*,MVertex*,MVertex*,MVertex*); - double min_scaled_jacobian(Prism); + private: + std::vector<Prism> potential; + std::map<MElement*,bool> markings; + std::map<MVertex*,std::set<MVertex*> > vertex_to_vertices; + std::map<MVertex*,std::set<MElement*> > vertex_to_tetrahedra; + std::multiset<Facet> hash_tableA; + std::multiset<Diagonal> hash_tableB; + std::multiset<Diagonal> hash_tableC; + std::multiset<Tuple> tuples; + std::set<MElement*> triangles; + public: + Supplementary(); + ~Supplementary(); + + void execute(); + void execute(GRegion*); + + void init_markings(GRegion*); + void pattern(GRegion*); + void merge(GRegion*); + void rearrange(GRegion*); + void statistics(GRegion*); + void build_tuples(GRegion*); + void modify_surfaces(GRegion*); + void modify_surfaces(MVertex*,MVertex*,MVertex*,MVertex*); + + bool four(MElement*); + bool five(MElement*); + bool six(MElement*); + bool eight(MElement*); + + bool sliver(MElement*,Prism); + bool valid(Prism,const std::set<MElement*>&); + bool valid(Prism); + double eta(MVertex*,MVertex*,MVertex*,MVertex*); + bool linked(MVertex*,MVertex*); + + void find(MVertex*,MVertex*,const std::vector<MVertex*>&,std::set<MVertex*>&); + void find(MVertex*,Prism,std::set<MElement*>&); + + void intersection(const std::set<MVertex*>&,const std::set<MVertex*>&,const std::vector<MVertex*>&,std::set<MVertex*>&); + + bool inclusion(MVertex*,Prism); + bool inclusion(MVertex*,MVertex*,MVertex*,MVertex*,MVertex*); + bool inclusion(MVertex*,MVertex*,MVertex*,const std::set<MElement*>&); + bool inclusion(Facet); + bool inclusion(Diagonal); + bool duplicate(Diagonal); + + bool conformityA(Prism); + bool conformityA(MVertex*,MVertex*,MVertex*,MVertex*); + bool conformityB(Prism); + bool conformityC(Prism); + + bool faces_statuquo(Prism); + bool faces_statuquo(MVertex*,MVertex*,MVertex*,MVertex*); + + void build_vertex_to_vertices(GRegion*); + void build_vertex_to_tetrahedra(GRegion*); + void build_hash_tableA(Prism); + void build_hash_tableA(MVertex*,MVertex*,MVertex*,MVertex*); + void build_hash_tableA(Facet); + void build_hash_tableB(Prism); + void build_hash_tableB(MVertex*,MVertex*,MVertex*,MVertex*); + void build_hash_tableB(Diagonal); + void build_hash_tableC(Prism); + void build_hash_tableC(Diagonal); + + double scaled_jacobian(MVertex*,MVertex*,MVertex*,MVertex*); + double min_scaled_jacobian(Prism); }; class PostOp{ private: + int nbr,nbr8,nbr6,nbr5,nbr4; + double vol,vol8,vol6,vol5,vol4; int estimate1; int estimate2; int iterations; @@ -286,45 +617,50 @@ class PostOp{ PostOp(); ~PostOp(); - void execute(bool); - void execute(GRegion*,bool); - - void init_markings(GRegion*); - void pyramids1(GRegion*); - void pyramids2(GRegion*); - void pyramids1(MVertex*,MVertex*,MVertex*,MVertex*,GRegion*); - void pyramids2(MVertex*,MVertex*,MVertex*,MVertex*,GRegion*); - void rearrange(GRegion*); - void statistics(GRegion*); - void build_tuples(GRegion*); - void modify_surfaces(GRegion*); - void modify_surfaces(MVertex*,MVertex*,MVertex*,MVertex*); - - bool four(MElement*); - bool five(MElement*); - bool six(MElement*); - bool eight(MElement*); - - bool equal(MVertex*,MVertex*,MVertex*,MVertex*); - bool different(MVertex*,MVertex*,MVertex*,MVertex*); - MVertex* other(MElement*,MVertex*,MVertex*); - MVertex* other(MElement*,MVertex*,MVertex*,MVertex*); - void mean(const std::set<MVertex*>&,MVertex*,const std::vector<MElement*>&); - double workaround(MElement*); - - MVertex* find(MVertex*,MVertex*,MVertex*,MVertex*,MElement*); - void find_tetrahedra(MVertex*,MVertex*,std::set<MElement*>&); - void find_pyramids(MVertex*,MVertex*,std::set<MElement*>&); - - void intersection(const std::set<MElement*>&,const std::set<MElement*>&,std::set<MElement*>&); - - void build_vertex_to_tetrahedra(GRegion*); - void build_vertex_to_tetrahedra(MElement*); - void erase_vertex_to_tetrahedra(MElement*); - - void build_vertex_to_pyramids(GRegion*); - void build_vertex_to_pyramids(MElement*); - void erase_vertex_to_pyramids(MElement*); + void execute(bool); + void execute(GRegion*,bool); + + inline int get_nb_hexahedra()const{return nbr8;}; + inline double get_vol_hexahedra()const{return vol8;}; + inline int get_nb_elements()const{return nbr;}; + inline double get_vol_elements()const{return vol;}; + + void init_markings(GRegion*); + void pyramids1(GRegion*); + void pyramids2(GRegion*); + void pyramids1(MVertex*,MVertex*,MVertex*,MVertex*,GRegion*); + void pyramids2(MVertex*,MVertex*,MVertex*,MVertex*,GRegion*); + void rearrange(GRegion*); + void statistics(GRegion*); + void build_tuples(GRegion*); + void modify_surfaces(GRegion*); + void modify_surfaces(MVertex*,MVertex*,MVertex*,MVertex*); + + bool four(MElement*); + bool five(MElement*); + bool six(MElement*); + bool eight(MElement*); + + bool equal(MVertex*,MVertex*,MVertex*,MVertex*); + bool different(MVertex*,MVertex*,MVertex*,MVertex*); + MVertex* other(MElement*,MVertex*,MVertex*); + MVertex* other(MElement*,MVertex*,MVertex*,MVertex*); + void mean(const std::set<MVertex*>&,MVertex*,const std::vector<MElement*>&); + double workaround(MElement*); + + MVertex* find(MVertex*,MVertex*,MVertex*,MVertex*,MElement*); + void find_tetrahedra(MVertex*,MVertex*,std::set<MElement*>&); + void find_pyramids(MVertex*,MVertex*,std::set<MElement*>&); + + void intersection(const std::set<MElement*>&,const std::set<MElement*>&,std::set<MElement*>&); + + void build_vertex_to_tetrahedra(GRegion*); + void build_vertex_to_tetrahedra(MElement*); + void erase_vertex_to_tetrahedra(MElement*); + + void build_vertex_to_pyramids(GRegion*); + void build_vertex_to_pyramids(MElement*); + void erase_vertex_to_pyramids(MElement*); }; #endif -- GitLab