diff --git a/Geo/MQuadrangle.cpp b/Geo/MQuadrangle.cpp index 39ec97ab0728128da5b63854b0fa269eb83ef8ac..e3c56f5144d0c984e5ef899a6cddc6b0d8f00d2a 100644 --- a/Geo/MQuadrangle.cpp +++ b/Geo/MQuadrangle.cpp @@ -9,6 +9,7 @@ #include "Context.h" #include "Numeric.h" #include "BasisFactory.h" +#include "pointsGenerators.h" #if defined(HAVE_MESH) #include "qualityMeasures.h" @@ -369,15 +370,16 @@ void MQuadrangleN::reverse() } } -void MQuadrangle::reorient(int rot, bool swap) { +void MQuadrangle::reorient(int rot, bool swap) +{ MVertex* tmp[4]; if (swap) for (int i=0;i<4;i++) tmp[i] = _v[(4-i+rot)%4]; else for (int i=0;i<4;i++) tmp[i] = _v[(4+i-rot)%4]; std::memcpy(_v,tmp,4*sizeof(MVertex*)); } -void MQuadrangle8::reorient(int rot, bool swap) { - +void MQuadrangle8::reorient(int rot, bool swap) +{ if (rot == 0 && !swap) return; MQuadrangle::reorient(rot,swap); @@ -387,8 +389,8 @@ void MQuadrangle8::reorient(int rot, bool swap) { std::memcpy(_vs,tmp,4*sizeof(MVertex*)); } -void MQuadrangle9::reorient(int rot, bool swap) { - +void MQuadrangle9::reorient(int rot, bool swap) +{ if (rot == 0 && !swap) return; MQuadrangle::reorient(rot,swap); @@ -398,46 +400,67 @@ void MQuadrangle9::reorient(int rot, bool swap) { std::memcpy(_vs,tmp,4*sizeof(MVertex*)); } -void MQuadrangleN::reorient(int rot, bool swap) { +std::map<TupleReorientation, IndicesReoriented> MQuadrangleN::_tuple2indicesReoriented; + +namespace +{ + void _getIndicesReorientedQuad(int order, int rot, bool swap, + IndicesReoriented &indices) + { + fullMatrix<double> ref = gmshGenerateMonomialsQuadrangle(order); + ref.add(- order / 2.); + + indices.resize(ref.size1()); + for (int i = 0; i < ref.size1(); ++i) { + double u = ref(i, 0); + double v = ref(i, 1); + double tmp = u; + switch (rot) { + case 1: u = v; v = -tmp; break; + case 2: u = -u; v = -v; break; + case 3: u = -v; v = tmp; break; + } + if (swap) { + tmp = u; + u = v; + v = tmp; + } + for (int j = 0; j < ref.size1(); ++j) { + if (u == ref(j, 0) && v == ref(j, 1)) { + indices[i] = j; + break; + } + } + } + } +} +void MQuadrangleN::reorient(int rot, bool swap) +{ if (rot == 0 && !swap) return; - MQuadrangle::reorient(rot,swap); - int order = getPolynomialOrder(); - int nbEdgePts = order - 1; - unsigned int idx = 0; + TupleReorientation mytuple(getTypeForMSH(), std::make_pair(rot, swap)); + std::map<TupleReorientation, IndicesReoriented>::iterator it; + it = _tuple2indicesReoriented.find(mytuple); + if (it == _tuple2indicesReoriented.end()) { + IndicesReoriented indices; + _getIndicesReorientedQuad(_order, rot, swap, indices); + _tuple2indicesReoriented[mytuple] = indices; + it = _tuple2indicesReoriented.find(mytuple); + } - std::vector<MVertex*> tmp; + IndicesReoriented &indices = it->second; - if (swap) { - for (int iEdge=0;iEdge<4;iEdge++) { - int edgeIdx = ((7-iEdge+rot)%4)*nbEdgePts; - for (int i=nbEdgePts-1;i>=0;i--) tmp.push_back(_vs[edgeIdx+i]); - } - } - else { - for (int iEdge=0;iEdge<4;iEdge++) { - int edgeIdx = ((4+iEdge-rot)%4)*nbEdgePts; - for (int i=0;i<nbEdgePts;i++) tmp.push_back(_vs[edgeIdx+i]); - } - } + // copy vertices + std::vector<MVertex*> oldv(4 + _vs.size()); + std::copy(_v, _v+4, oldv.begin()); + std::copy(_vs.begin(), _vs.end(), oldv.begin()+4); - idx += 4*nbEdgePts; - - if (_vs.size() >= idx) { - nbEdgePts = order - 3; - if (order > 2) { - if (swap) for (int i=0;i<4;i++) tmp.push_back(_vs[idx + (4-i+rot)%4]); - else for (int i=0;i<4;i++) tmp.push_back(_vs[idx + (4+i-rot)%4]); - idx += 4; - if (order > 3) { - if (swap) for (int i=0;i<4;i++) tmp.push_back(_vs[idx + (7-i+rot)%4]); - else for (int i=0;i<4;i++) tmp.push_back(_vs[idx + (4+i-rot)%4]); - idx += 4; - if (order > 4) Msg::Error("Reorientation of quad not supported above order 4"); - } - } - tmp.push_back(_vs[idx]); + // reorient + for (int i = 0; i < 4; ++i) { + _v[i] = oldv[indices[i]]; + } + for (unsigned int i = 0; i < _vs.size(); ++i) { + _vs[i] = oldv[indices[4+i]]; } - _vs = tmp; } diff --git a/Geo/MQuadrangle.h b/Geo/MQuadrangle.h index 067d6a138e0c1ca18d92c0a2e94d037cca1dd475..15cb09446efdc2fdf675c7d849e84a9403fadfc1 100644 --- a/Geo/MQuadrangle.h +++ b/Geo/MQuadrangle.h @@ -351,6 +351,9 @@ class MQuadrangle9 : public MQuadrangle { } }; +typedef std::vector<int> IndicesReoriented; +typedef std::pair<int, std::pair<int,int> > TupleReorientation; + /* * MQuadrangle * @@ -368,6 +371,7 @@ class MQuadrangle9 : public MQuadrangle { * */ class MQuadrangleN : public MQuadrangle { + static std::map<TupleReorientation, IndicesReoriented> _tuple2indicesReoriented; protected: std::vector<MVertex *> _vs; const char _order; diff --git a/Geo/MTriangle.cpp b/Geo/MTriangle.cpp index 51a729cb3eb49efeb14aeab51faf75c2928d412b..7f4a9c7a54362d21d2bb7917c390f68df2693e56 100644 --- a/Geo/MTriangle.cpp +++ b/Geo/MTriangle.cpp @@ -8,6 +8,7 @@ #include "Numeric.h" #include "Context.h" #include "BasisFactory.h" +#include "pointsGenerators.h" #if defined(HAVE_MESH) #include "qualityMeasures.h" @@ -330,40 +331,65 @@ void MTriangle6::reorient(int rot, bool swap) else for (int i=0;i<3;i++) _vs[i] = tmp[(3-rot+i)%3]; } +std::map<TupleReorientation, IndicesReoriented> MTriangleN::_tuple2indicesReoriented; + +namespace +{ + void _getIndicesReorientedTri(int order, int rot, bool swap, + IndicesReoriented &indices) + { + fullMatrix<double> ref = gmshGenerateMonomialsTriangle(order); + + indices.resize(ref.size1()); + for (int i = 0; i < ref.size1(); ++i) { + double u = ref(i, 0); + double v = ref(i, 1); + double tmp; + switch (rot) { + case 1: tmp = u; u = order - u - v; v = tmp; break; + case 2: tmp = v; v = order - u - v; u = tmp; break; + } + if (swap) { + tmp = u; + u = v; + v = tmp; + } + for (int j = 0; j < ref.size1(); ++j) { + if (u == ref(j, 0) && v == ref(j, 1)) { + indices[i] = j; + break; + } + } + } + } +} + void MTriangleN::reorient(int rot, bool swap) { if (rot == 0 && !swap) return; - MTriangle::reorient(rot,swap); - - std::vector<MVertex*> tmp; - int order = getPolynomialOrder(); - int nbEdge = order - 1; - unsigned int idx = 0; - - if (swap) { - for (int iEdge=0;iEdge<3;iEdge++) { - int edgeIdx = ((5-iEdge+rot)%3)*nbEdge; - for (int i=nbEdge-1;i>=0;i--) tmp.push_back(_vs[edgeIdx + i]); - } - } - else { - for (int iEdge=0;iEdge<3;iEdge++) { - int edgeIdx = ((3+iEdge-rot)%3)*nbEdge; - for (int i=0;i<nbEdge;i++) tmp.push_back(_vs[edgeIdx + i]); - } + TupleReorientation mytuple(getTypeForMSH(), std::make_pair(rot, swap)); + std::map<TupleReorientation, IndicesReoriented>::iterator it; + it = _tuple2indicesReoriented.find(mytuple); + if (it == _tuple2indicesReoriented.end()) { + IndicesReoriented indices; + _getIndicesReorientedTri(_order, rot, swap, indices); + _tuple2indicesReoriented[mytuple] = indices; + it = _tuple2indicesReoriented.find(mytuple); } - idx += 3*nbEdge; + IndicesReoriented &indices = it->second; - if (_vs.size() > idx) { - if (order == 3) tmp.push_back(_vs[idx]); - if (order == 4) { - if (swap) for(int i=0;i<3;i++) tmp.push_back(_vs[idx+(3+rot-i)%3]); - else for(int i=0;i<3;i++) tmp.push_back(_vs[idx+(3+i-rot)%3]); - } - if (order >=5) - Msg::Error("Reorientation of a triangle not supported above order 4"); + // copy vertices + std::vector<MVertex*> oldv(3 + _vs.size()); + std::copy(_v, _v+4, oldv.begin()); + std::copy(_vs.begin(), _vs.end(), oldv.begin()+4); + + // reorient + for (int i = 0; i < 3; ++i) { + _v[i] = oldv[indices[i]]; + } + for (unsigned int i = 0; i < _vs.size(); ++i) { + _vs[i] = oldv[indices[3+i]]; } - _vs = tmp; } diff --git a/Geo/MTriangle.h b/Geo/MTriangle.h index 795340c31c0371167307e7b3b2e00a70124e469e..098f0a24c663dd244c8c978a50ea019ceb16c700 100644 --- a/Geo/MTriangle.h +++ b/Geo/MTriangle.h @@ -246,6 +246,9 @@ class MTriangle6 : public MTriangle { virtual void reorient(int rotation, bool swap); }; +typedef std::vector<int> IndicesReoriented; +typedef std::pair<int, std::pair<int,int> > TupleReorientation; + /* * MTriangleN FIXME: check the plot * @@ -263,6 +266,7 @@ class MTriangle6 : public MTriangle { * */ class MTriangleN : public MTriangle { + static std::map<TupleReorientation, IndicesReoriented> _tuple2indicesReoriented; protected: std::vector<MVertex *> _vs; const char _order; diff --git a/Mesh/meshGFace.cpp b/Mesh/meshGFace.cpp index c3d6625f5d6e1b1708bd6a1c9aee7b331b8785d7..6508a69dea59f6bc99ff8e86ddc14ca47b230a0f 100644 --- a/Mesh/meshGFace.cpp +++ b/Mesh/meshGFace.cpp @@ -1598,12 +1598,21 @@ bool meshGenerator(GFace *gf, int RECUR_ITER, delete m; - - gf->quadrangles.insert(gf->quadrangles.begin(),blQuads.begin(),blQuads.end()); gf->triangles.insert(gf->triangles.begin(),blTris.begin(),blTris.end()); gf->mesh_vertices.insert(gf->mesh_vertices.begin(),verts.begin(),verts.end()); +#if defined(HAVE_ANN) + if (!CTX::instance()->mesh.recombineAll && !gf->meshAttributes.recombine){ + 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 if((CTX::instance()->mesh.recombineAll || gf->meshAttributes.recombine) && !CTX::instance()->mesh.optimizeLloyd && !onlyInitialMesh && CTX::instance()->mesh.algoRecombine != 2) diff --git a/Mesh/meshGFaceOptimize.cpp b/Mesh/meshGFaceOptimize.cpp index 5ab5719a679801d8194aef7eefea28c2404d2598..bb9715703edcb45713c594e240fdb8a681d588ea 100644 --- a/Mesh/meshGFaceOptimize.cpp +++ b/Mesh/meshGFaceOptimize.cpp @@ -1522,17 +1522,16 @@ void quadsToTriangles(GFace *gf, double minqual) if (option == 1 || (option == 0 && qual1 > qual2)){ gf->triangles.push_back(t11); gf->triangles.push_back(t12); - change[q] = std::make_pair(t11,t12); + change[q] = std::make_pair(t11,t12); delete t21; delete t22; } else { gf->triangles.push_back(t21); gf->triangles.push_back(t22); - change[q] = std::make_pair(t21,t22); + change[q] = std::make_pair(t21,t22); delete t11; delete t12; } - delete q; // FIXME this makes gmsh to crash when creating BL with triangles - // FIXED (JF) + delete q; } else { qds.push_back(q); @@ -1542,23 +1541,42 @@ void quadsToTriangles(GFace *gf, double minqual) BoundaryLayerColumns* _columns = gf->getColumns(); if (!_columns)return; - for ( std::map<MElement*,std::vector<MElement*> >::iterator it = _columns->_elemColumns.begin(); - it != _columns->_elemColumns.end();it++){ - std::vector<MElement *> &e = it->second; - std::vector<MElement *> eOld = e; - e.clear(); - for (unsigned int i=0;i<eOld.size();i++){ - MElement *ee = eOld[i]; - std::map<MElement*, std::pair<MElement*,MElement*> >::iterator it2 = change.find(ee); - if (it2 == change.end()){ - e.push_back(ee); + + // Update the data struture for boundary layers + // WARNING: First quad element is replaced by one of the two triangles, + // without taking care of if it is the truly the first one or not. + +// std::map<MElement*,MElement*> _toFirst; + std::map<MElement*,std::vector<MElement*> > newElemColumns; + std::map<MElement*,std::vector<MElement*> >::iterator it; + std::map<MElement*, std::pair<MElement*,MElement*> >::iterator it2; + + for (it = _columns->_elemColumns.begin(); + it != _columns->_elemColumns.end(); it++) { + + MElement *firstEl = it->first; + it2 = change.find(firstEl); + if (it2 != change.end()) firstEl = it2->second.first; + // it2->second.first may be the one that touch boundary or not... + + std::vector<MElement *> &newColumn = newElemColumns[firstEl]; + std::vector<MElement *> &oldColumn = it->second; + + for (unsigned int i = 0; i < oldColumn.size(); i++) { + MElement *oldEl = oldColumn[i]; + it2 = change.find(oldEl); + if (it2 == change.end()) { + newColumn.push_back(oldEl); + _columns->_toFirst[oldEl] = firstEl; } else { - e.push_back(it2->second.first); - e.push_back(it2->second.second); + newColumn.push_back(it2->second.first); + newColumn.push_back(it2->second.second); + _columns->_toFirst.erase(oldEl); + _columns->_toFirst[it2->second.first] = firstEl; + _columns->_toFirst[it2->second.second] = firstEl; } } } - - + _columns->_elemColumns = newElemColumns; } diff --git a/Mesh/meshGFaceOptimizeOld.cpp b/Mesh/meshGFaceOptimizeOld.cpp deleted file mode 100644 index cfd2a9839b54049a47aebe6976ab9f81009ed5e8..0000000000000000000000000000000000000000 --- a/Mesh/meshGFaceOptimizeOld.cpp +++ /dev/null @@ -1,1497 +0,0 @@ -// Gmsh - Copyright (C) 1997-2017 C. Geuzaine, J.-F. Remacle -// -// See the LICENSE.txt file for license information. Please report all -// bugs and problems to the public mailing list <gmsh@onelab.info>. - -#include <stack> -#include "GmshConfig.h" -#include "meshGFaceOptimize.h" -#include "qualityMeasures.h" -#include "GFace.h" -#include "GEdge.h" -#include "GVertex.h" -#include "GModel.h" -#include "MVertex.h" -#include "MTriangle.h" -#include "MQuadrangle.h" -#include "MLine.h" -#include "BackgroundMeshTools.h" -#include "Numeric.h" -#include "GmshMessage.h" -#include "Generator.h" -#include "Context.h" -#include "OS.h" -#include "SVector3.h" -#include "SPoint3.h" -#include "robustPredicates.h" -#include "meshGRegionRelocateVertex.h" - -#if defined(HAVE_BLOSSOM) -extern "C" struct CCdatagroup; -extern "C" int perfect_match -(int ncount, CCdatagroup *dat, int ecount, - int **elist, int **elen, char *blo_filename, - char *mat_filename, int just_fractional, int no_fractional, - int use_all_trees, int partialprice, - double *totalzeit) ; -#endif - -edge_angle::edge_angle(MVertex *_v1, MVertex *_v2, MElement *t1, MElement *t2) - : v1(_v1), v2(_v2) -{ - if(!t2) angle = 0; - else{ - double c1[3]; - double c2[3]; - double c3[3]; - { - MVertex *p1 = t1->getVertex(0); - MVertex *p2 = t1->getVertex(1); - MVertex *p3 = t1->getVertex(2); - double a[3] = {p1->x() - p2->x(), p1->y() - p2->y(), p1->z() - p2->z()}; - double b[3] = {p1->x() - p3->x(), p1->y() - p3->y(), p1->z() - p3->z()}; - c1[2] = a[0] * b[1] - a[1] * b[0]; - c1[1] = -a[0] * b[2] + a[2] * b[0]; - c1[0] = a[1] * b[2] - a[2] * b[1]; - } - { - MVertex *p1 = t2->getVertex(0); - MVertex *p2 = t2->getVertex(1); - MVertex *p3 = t2->getVertex(2); - double a[3] = {p1->x() - p2->x(), p1->y() - p2->y(), p1->z() - p2->z()}; - double b[3] = {p1->x() - p3->x(), p1->y() - p3->y(), p1->z() - p3->z()}; - c2[2] = a[0] * b[1] - a[1] * b[0]; - c2[1] = -a[0] * b[2] + a[2] * b[0]; - c2[0] = a[1] * b[2] - a[2] * b[1]; - } - norme(c1); - norme(c2); - prodve(c1, c2, c3); - double cosa; prosca(c1, c2, &cosa); - double sina = norme(c3); - angle = atan2(sina, cosa); - } -} - -static void setLcsInit(MTriangle *t, std::map<MVertex*, double> &vSizes) -{ - for(int i = 0; i < 3; i++){ - for(int j = i + 1; j < 3; j++){ - MVertex *vi = t->getVertex(i); - MVertex *vj = t->getVertex(j); - vSizes[vi] = -1; - vSizes[vj] = -1; - } - } -} - -static void setLcs(MTriangle *t, std::map<MVertex*, double> &vSizes, bidimMeshData & data) -{ - for(int i = 0; i < 3; i++){ - for(int j = i + 1; j < 3; j++){ - MVertex *vi = t->getVertex(i); - MVertex *vj = t->getVertex(j); - if (vi != data.equivalent(vj) && vj != data.equivalent(vi) ){ - double dx = vi->x() - vj->x(); - double dy = vi->y() - vj->y(); - double dz = vi->z() - vj->z(); - double l = sqrt(dx * dx + dy * dy + dz * dz); - std::map<MVertex*,double>::iterator iti = vSizes.find(vi); - std::map<MVertex*,double>::iterator itj = vSizes.find(vj); - if(iti->second < 0 || iti->second > l) iti->second = l; - if(itj->second < 0 || itj->second > l) itj->second = l; - } - } - } -} - -void buildMeshGenerationDataStructures(GFace *gf, - std::set<MTri3*, compareTri3Ptr> &AllTris, - bidimMeshData & data) -{ - std::map<MVertex*, double> vSizesMap; - std::list<GEdge*> edges = gf->edges(); - - 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); - - // take care of embedded vertices - { - std::list<GVertex*> emb_vertx = gf->embeddedVertices(); - std::list<GVertex*>::iterator itvx = emb_vertx.begin(); - while(itvx != emb_vertx.end()){ - MVertex *v = *((*itvx)->mesh_vertices.begin()); - vSizesMap[v] = std::min(vSizesMap[v], (*itvx)->prescribedMeshSizeAtVertex()); - ++itvx; - } - } - - // take good care of embedded edges - { - std::list<GEdge*> embedded_edges = gf->embeddedEdges(); - std::list<GEdge*>::iterator ite = embedded_edges.begin(); - while(ite != embedded_edges.end()){ - if(!(*ite)->isMeshDegenerated()){ - for (unsigned int i = 0; i < (*ite)->lines.size(); i++) - data.internalEdges.insert(MEdge((*ite)->lines[i]->getVertex(0), - (*ite)->lines[i]->getVertex(1))); - } - ++ite; - } - } - - // int NUM = 0; - for(std::map<MVertex*, double>::iterator it = vSizesMap.begin(); - it != vSizesMap.end(); ++it){ - SPoint2 param; - reparamMeshVertexOnFace(it->first, gf, param); - data.addVertex (it->first, param[0], param[1], it->second, it->second); - } - for(unsigned int i = 0; i < gf->triangles.size(); i++){ - double lc = 0.3333333333 * (data.vSizes[data.getIndex(gf->triangles[i]->getVertex(0))] + - data.vSizes[data.getIndex(gf->triangles[i]->getVertex(1))] + - data.vSizes[data.getIndex(gf->triangles[i]->getVertex(2))]); - AllTris.insert(new MTri3(gf->triangles[i], lc, 0, &data, gf)); - } - gf->triangles.clear(); - connectTriangles(AllTris); -} - -void computeEquivalences(GFace *gf, bidimMeshData & data) -{ - if (data.equivalence){ - std::vector<MTriangle*> newT; - for (unsigned int i=0;i<gf->triangles.size();i++){ - MTriangle *t = gf->triangles[i]; - MVertex *v[3]; - for (int j=0;j<3;j++){ - v[j] = t->getVertex(j); - std::map<MVertex* , MVertex*>::iterator it = data.equivalence->find(v[j]); - if (it != data.equivalence->end()){ - v[j] = it->second; - } - } - if (v[0] != v[1] && v[0] != v[2] && v[2] != v[1]) - newT.push_back(new MTriangle (v[0],v[1],v[2])); - delete t; - } - gf->triangles = newT; - } -} - -struct equivalentTriangle { - MTriangle *_t; - MVertex *_v[3]; - equivalentTriangle (MTriangle *t, std::map<MVertex* , MVertex*>* equivalence) - :_t(t) { - for (int i=0;i<3;i++){ - MVertex *v = t->getVertex(i); - std::map<MVertex* , MVertex*>::iterator it = equivalence->find(v); - if (it == equivalence->end())_v[i] = v; - else _v[i] = it->second; - } - std::sort (_v,_v+3); - } - bool operator < (const equivalentTriangle &other) const{ - for (int i=0;i<3;i++){ - if (other._v[i] > _v[i])return true; - if (other._v[i] < _v[i])return false; - } - return false; - } -}; - -bool computeEquivalentTriangles (GFace *gf, - std::map<MVertex* , MVertex*>* equivalence) -{ - if (!equivalence)return false; - std::vector<MTriangle*> WTF; - if (!equivalence)return false; - std::set<equivalentTriangle> eqTs; - for (unsigned int i = 0; i < gf->triangles.size(); i++){ - equivalentTriangle et (gf->triangles[i],equivalence); - std::set<equivalentTriangle>::iterator iteq = eqTs.find(et); - if (iteq == eqTs.end())eqTs.insert(et); - else { - WTF.push_back(iteq->_t); - WTF.push_back(gf->triangles[i]); - } - } - - if (WTF.size()){ - Msg::Info("%d triangles are equivalent", WTF.size()); - for (unsigned int i=0;i<WTF.size();i++){ - } - return true; - } - return false; -} - - -void splitEquivalentTriangles(GFace *gf, bidimMeshData & data) -{ - computeEquivalentTriangles (gf,data.equivalence); -} - - -void transferDataStructure(GFace *gf, std::set<MTri3*, compareTri3Ptr> &AllTris, - bidimMeshData & data) -{ - while (1) { - if(AllTris.begin() == AllTris.end()) break; - MTri3 *worst = *AllTris.begin(); - if(worst->isDeleted()) - delete worst->tri(); - else - gf->triangles.push_back(worst->tri()); - delete worst; - AllTris.erase(AllTris.begin()); - } - - // make sure all the triangles are oriented in the same way in - // parameter space (it would be nicer to change the actual algorithm - // to ensure that we create correctly-oriented triangles in the - // first place) - - // if BL triangles are considered, then all that is WRONG ! - - - if(gf->triangles.size() > 1){ - - bool BL = !gf->getColumns()->_toFirst.empty(); - - double n1[3], n2[3]; - MTriangle *t = gf->triangles[0]; - MVertex *v0 = t->getVertex(0), *v1 = t->getVertex(1), *v2 = t->getVertex(2); - - if (!BL){ - int index0 = data.getIndex (v0); - int index1 = data.getIndex (v1); - int index2 = data.getIndex (v2); - normal3points(data.Us[index0], data.Vs[index0], 0., - data.Us[index1], data.Vs[index1], 0., - data.Us[index2], data.Vs[index2], 0., n1); - } - else { - // BL --> PLANAR FACES !!! - normal3points(v0->x(),v0->y(),v0->z(), - v1->x(),v1->y(),v1->z(), - v2->x(),v2->y(),v2->z(), n1); - } - for(unsigned int j = 1; j < gf->triangles.size(); j++){ - t = gf->triangles[j]; - v0 = t->getVertex(0); v1 = t->getVertex(1); v2 = t->getVertex(2); - if (!BL){ - int index0 = data.getIndex (v0); - int index1 = data.getIndex (v1); - int index2 = data.getIndex (v2); - normal3points(data.Us[index0], data.Vs[index0], 0., - data.Us[index1], data.Vs[index1], 0., - data.Us[index2], data.Vs[index2], 0., n2); - } - else { - // BL --> PLANAR FACES !!! - normal3points(v0->x(),v0->y(),v0->z(), - v1->x(),v1->y(),v1->z(), - v2->x(),v2->y(),v2->z(), n2); - } - double pp; prosca(n1, n2, &pp); - // orient the bignou - if(pp < 0) t->reverse(); - } - } - splitEquivalentTriangles(gf, data); - computeEquivalences(gf, data); -} - - - -void buildVertexToTriangle(std::vector<MTriangle*> &eles, v2t_cont &adj) -{ - adj.clear(); - buildVertexToElement(eles,adj); -} - -template <class T> -void buildEdgeToElement(std::vector<T*> &elements, e2t_cont &adj) -{ - for(unsigned int i = 0; i < elements.size(); i++){ - T *t = elements[i]; - for(int j = 0; j < t->getNumEdges(); j++){ - MEdge e = t->getEdge(j); - e2t_cont::iterator it = adj.find(e); - if(it == adj.end()){ - std::pair<MElement*, MElement*> one = std::make_pair(t, (MElement*)0); - adj[e] = one; - } - else{ - it->second.second = t; - } - } - } -} - -void buildEdgeToElement(GFace *gf, e2t_cont &adj) -{ - adj.clear(); - buildEdgeToElement(gf->triangles, adj); - buildEdgeToElement(gf->quadrangles, adj); -} - -void buildEdgeToTriangle(std::vector<MTriangle*> &tris, e2t_cont &adj) -{ - adj.clear(); - buildEdgeToElement(tris, adj); -} - -void buildEdgeToElements(std::vector<MElement*> &tris, e2t_cont &adj) -{ - adj.clear(); - buildEdgeToElement(tris, adj); -} - -void buildListOfEdgeAngle(e2t_cont adj, std::vector<edge_angle> &edges_detected, - std::vector<edge_angle> &edges_lonly) -{ - e2t_cont::iterator it = adj.begin(); - for(; it != adj.end(); ++it){ - if(it->second.second) - edges_detected.push_back(edge_angle(it->first.getVertex(0), - it->first.getVertex(1), - it->second.first, it->second.second)); - else - edges_lonly.push_back(edge_angle(it->first.getVertex(0), - it->first.getVertex(1), - it->second.first, it->second.second)); - } - std::sort(edges_detected.begin(), edges_detected.end()); -} - -void parametricCoordinates(MElement *t, GFace *gf, double u[4], double v[4], - MVertex *close = 0) -{ - for(int j = 0; j < t->getNumVertices(); j++){ - MVertex *ver = t->getVertex(j); - SPoint2 param, dummy; - if (!close) reparamMeshVertexOnFace(ver, gf, param); - else reparamMeshEdgeOnFace(ver, close, gf, param, dummy); - u[j] = param[0]; - v[j] = param[1]; - } -} - -double surfaceFaceUV(MElement *t,GFace *gf, bool maximal = true) -{ - double u[4],v[4]; - parametricCoordinates(t,gf,u,v); - // printf("%g %g %g %g\n",u[0],u[1],u[2],u[3]); - // printf("%g %g %g %g\n",v[0],v[1],v[2],v[3]); - if (t->getNumVertices() == 3) - return 0.5*fabs((u[1]-u[0])*(v[2]-v[0])-(u[2]-u[0])*(v[1]-v[0])); - else { - const double a1 = - 0.5*fabs((u[1]-u[0])*(v[2]-v[0])-(u[2]-u[0])*(v[1]-v[0])) + - 0.5*fabs((u[3]-u[2])*(v[0]-v[2])-(u[0]-u[2])*(v[3]-v[2])) ; - const double a2 = - 0.5*fabs((u[2]-u[1])*(v[3]-v[1])-(u[3]-u[1])*(v[2]-v[1])) + - 0.5*fabs((u[0]-u[3])*(v[1]-v[3])-(u[1]-u[3])*(v[0]-v[3])) ; - return maximal ? std::max(a2,a1) : std::min(a2,a1); - } -} - -int _removeThreeTrianglesNodes(GFace *gf) -{ - v2t_cont adj; - buildVertexToElement(gf->triangles,adj); - v2t_cont :: iterator it = adj.begin(); - int n=0; - std::set<MElement*> touched; - while (it != adj.end()) { - bool skip = false; - if(it->second.size() == 3 && it->first->onWhat()->dim() == 2) { - const std::vector<MElement*> < = it->second; - std::set<MVertex*> vs; - for(int i = 0; i < 3; i++) { - if(touched.find(lt[i])!=touched.end() || lt[i]->getNumVertices()!=3){ - skip=true; - break; - } - for(int j = 0; j < 3; j++) { - if(lt[i]->getVertex(j) == it->first) { - vs.insert(lt[i]->getVertex((j+1)%3)); - vs.insert(lt[i]->getVertex((j+2)%3)); - break; - } - } - } - if(skip){ - it++; - continue; - } - std::set<MVertex*>::iterator itt = vs.begin(); - MVertex *v1 = *itt; ++itt; - MVertex *v2 = *itt; ++itt; - MVertex *v3 = *itt; - MTriangle *newt = new MTriangle(v1,v2,v3); - n++; - gf->triangles.push_back(newt); - for(int i=0;i<3;i++) { - touched.insert(lt[i]); - } - } - it++; - } - std::vector<MTriangle*> triangles2; - for(unsigned int i = 0; i < gf->triangles.size(); i++){ - if(touched.find(gf->triangles[i]) == touched.end()){ - triangles2.push_back(gf->triangles[i]); - } - else { - delete gf->triangles[i]; - } - } - gf->triangles = triangles2; - Msg::Debug("%i three-triangles vertices removed",n); - return n; -} - - -void removeThreeTrianglesNodes(GFace *gf) -{ - while(_removeThreeTrianglesNodes(gf)); -} - -static int _removeTwoQuadsNodes(GFace *gf) -{ - v2t_cont adj; - buildVertexToElement(gf->triangles,adj); - buildVertexToElement(gf->quadrangles,adj); - v2t_cont :: iterator it = adj.begin(); - std::set<MElement*> touched; - std::set<MVertex*> vtouched; - while (it != adj.end()) { - if(it->second.size()==2 && it->first->onWhat()->dim() == 2) { - MElement *q1 = it->second[0]; - MElement *q2 = it->second[1]; - if (q1->getNumVertices() == 4 && - q2->getNumVertices() == 4 && - touched.find(q1) == touched.end() && touched.find(q2) == touched.end()){ - int comm = 0; - for (int i=0;i<4;i++){ - if (q1->getVertex(i) == it->first){ - comm = i; - break; - } - } - MVertex *v1 = q1->getVertex((comm+1)%4); - MVertex *v2 = q1->getVertex((comm+2)%4); - MVertex *v3 = q1->getVertex((comm+3)%4); - MVertex *v4 = 0; - for (int i=0;i<4;i++){ - if (q2->getVertex(i) != v1 && q2->getVertex(i) != v2 && - q2->getVertex(i) != v3 && q2->getVertex(i) != it->first){ - v4 = q2->getVertex(i); - break; - } - } - if (!v4){ - Msg::Error("BUG DISCOVERED IN _removeTwoQuadsNodes ,%p,%p,%p",v1,v2,v3); - q1->writePOS(stdout,true,false,false,false,false,false); - q2->writePOS(stdout,true,false,false,false,false,false); - return 0; - } - MQuadrangle *q = new MQuadrangle(v1,v2,v3,v4); - double s1 = surfaceFaceUV(q,gf); - double s2 = surfaceFaceUV(q1,gf) + surfaceFaceUV(q2,gf);; - if (s1 > s2){ - delete q; - } - else{ - touched.insert(q1); - touched.insert(q2); - gf->quadrangles.push_back(q); - vtouched.insert(it->first); - } - } - } - it++; - } - std::vector<MQuadrangle*> quadrangles2; - for(unsigned int i = 0; i < gf->quadrangles.size(); i++){ - if(touched.find(gf->quadrangles[i]) == touched.end()){ - quadrangles2.push_back(gf->quadrangles[i]); - } - else { - delete gf->quadrangles[i]; - } - } - gf->quadrangles = quadrangles2; - - std::vector<MVertex*> mesh_vertices2; - for(unsigned int i = 0; i < gf->mesh_vertices.size(); i++){ - if(vtouched.find(gf->mesh_vertices[i]) == vtouched.end()){ - mesh_vertices2.push_back(gf->mesh_vertices[i]); - } - else { - delete gf->mesh_vertices[i]; - } - } - gf->mesh_vertices = mesh_vertices2; - - return vtouched.size(); -} - -int removeTwoQuadsNodes(GFace *gf) -{ - int nbRemove = 0; - while(1){ - int x = _removeTwoQuadsNodes(gf); - if (!x)break; - nbRemove += x; - } - Msg::Debug("%i two-quadrangles vertices removed",nbRemove); - return nbRemove; -} - -// collapse v1 & v2 to their middle and replace into e1 & e2 -static bool _tryToCollapseThatVertex (GFace *gf, - std::vector<MElement*> &e1, - std::vector<MElement*> &e2, - MElement *q, - MVertex *v1, - MVertex *v2) -{ - std::vector<MElement*> e = e1; - e.insert(e.end(), e2.begin(), e2.end()); - - double uu1,vv1; - v1->getParameter(0,uu1); - v1->getParameter(1,vv1); - double x1 = v1->x(); - double y1 = v1->y(); - double z1 = v1->z(); - - double uu2,vv2; - v2->getParameter(0,uu2); - v2->getParameter(1,vv2); - double x2 = v2->x(); - double y2 = v2->y(); - double z2 = v2->z(); - - // new position of v1 && v2 - GPoint pp = gf->point(0.5*(uu1+uu2),0.5*(vv1+vv2)); - //GPoint pp = gf->point(uu1,vv1); - - // double surface_old = 0; - // double surface_new = 0; - double worst_quality_old = 1.0; - double worst_quality_new = 1.0; - - // surface_old = surfaceFaceUV(q,gf,false); - int count=0; - for (unsigned int j=0;j<e.size();++j){ - if (e[j] != q){ - count++; - // surface_old += surfaceFaceUV(e[j],gf,false); - worst_quality_old = std::min(worst_quality_old,e[j]-> etaShapeMeasure()); - v1->x() = pp.x();v1->y() = pp.y();v1->z() = pp.z(); - v1->setParameter(0,pp.u());v1->setParameter(1,pp.v()); - v2->x() = pp.x();v2->y() = pp.y();v2->z() = pp.z(); - v2->setParameter(0,pp.u());v2->setParameter(1,pp.v()); - // surface_new += surfaceFaceUV(e[j],gf,false); - worst_quality_new = std::min(worst_quality_new,e[j]-> etaShapeMeasure()); - v1->x() = x1;v1->y() = y1;v1->z() = z1; - v1->setParameter(0,uu1);v1->setParameter(1,vv1); - v2->x() = x2;v2->y() = y2;v2->z() = z2; - v2->setParameter(0,uu2);v1->setParameter(1,vv2); - } - } - - // printf("%d %g %g %g %g\n", count, surface_old, surface_new, worst_quality_old , worst_quality_new); - - if (worst_quality_new > worst_quality_old ) { - v1->x() = pp.x();v1->y() = pp.y();v1->z() = pp.z(); - v1->setParameter(0,pp.u());v1->setParameter(1,pp.v()); - for (unsigned int j=0;j<e.size();++j){ - if (e[j] != q){ - for (int k=0;k<4;k++){ - if (e[j]->getVertex(k) == v2){ - e[j]->setVertex(k,v1); - } - } - } - } - return true; - } - return false; -} - -static bool _isItAGoodIdeaToMoveThatVertex(GFace *gf, - const std::vector<MElement*> &e1, - MVertex *v1, - const SPoint2 &before, - const SPoint2 &after) -{ - double surface_old = 0; - double surface_new = 0; - - GPoint gp = gf->point(after); - if (!gp.succeeded())return false; - SPoint3 pafter (gp.x(),gp.y(),gp.z()); - SPoint3 pbefore (v1->x(),v1->y(),v1->z()); - - double minq = 1.0; - for (unsigned int j=0;j<e1.size();++j){ - surface_old += surfaceFaceUV(e1[j],gf,false); - minq = std::min(e1[j]->etaShapeMeasure(),minq); - } - - v1->setParameter(0,after.x()); - v1->setParameter(1,after.y()); - v1->setXYZ(pafter.x(),pafter.y(),pafter.z()); - - double minq_new = 1.0; - for (unsigned int j=0;j<e1.size();++j){ - surface_new += surfaceFaceUV(e1[j],gf,false); - minq_new = std::min(e1[j]->etaShapeMeasure(),minq_new); - } - - v1->setParameter(0,before.x()); - v1->setParameter(1,before.y()); - v1->setXYZ(pbefore.x(),pbefore.y(),pbefore.z()); - if ((1.+1.e-10)*surface_old < surface_new|| minq_new < minq) { - return false; - } - return true; -} - -static int _removeDiamonds(GFace *gf) -{ - v2t_cont adj; - buildVertexToElement(gf->quadrangles,adj); - std::set<MElement*> diamonds; - std::set<MVertex*> touched; - std::set<MVertex*> deleted; - std::vector<MVertex*> mesh_vertices2; - std::vector<MQuadrangle*> quadrangles2; - - for(unsigned int i = 0; i < gf->triangles.size(); i++){ - touched.insert(gf->triangles[i]->getVertex(0)); - touched.insert(gf->triangles[i]->getVertex(1)); - touched.insert(gf->triangles[i]->getVertex(2)); - } - - for(unsigned int i = 0; i < gf->quadrangles.size(); i++){ - MQuadrangle *q = gf->quadrangles[i]; - MVertex *v1 = q->getVertex(0); - MVertex *v2 = q->getVertex(1); - MVertex *v3 = q->getVertex(2); - MVertex *v4 = q->getVertex(3); - v2t_cont::iterator it1 = adj.find(v1); - v2t_cont::iterator it2 = adj.find(v2); - v2t_cont::iterator it3 = adj.find(v3); - v2t_cont::iterator it4 = adj.find(v4); - if (touched.find(v1) == touched.end() && - touched.find(v2) == touched.end() && - touched.find(v3) == touched.end() && - touched.find(v4) == touched.end() ) { - if (v1->onWhat()->dim() == 2 && - v2->onWhat()->dim() == 2 && - v3->onWhat()->dim() == 2 && - v4->onWhat()->dim() == 2 && - it1->second.size() ==3 && it3->second.size() == 3 && - _tryToCollapseThatVertex (gf, it1->second, it3->second, - q, v1, v3)){ - touched.insert(v1); - touched.insert(v2); - touched.insert(v3); - touched.insert(v4); - deleted.insert(v3); - diamonds.insert(q); - } - else if (v1->onWhat()->dim() == 2 && - v2->onWhat()->dim() == 2 && - v3->onWhat()->dim() == 2 && - v4->onWhat()->dim() == 2 && - it2->second.size() ==3 && it4->second.size() == 3 && - _tryToCollapseThatVertex (gf, it2->second, it4->second, - q, v2, v4)){ - touched.insert(v1); - touched.insert(v2); - touched.insert(v3); - touched.insert(v4); - deleted.insert(v4); - diamonds.insert(q); - } - else { - quadrangles2.push_back(q); - } - } - else{ - quadrangles2.push_back(q); - } - } - gf->quadrangles = quadrangles2; - - for(unsigned int i = 0; i < gf->mesh_vertices.size(); i++){ - if(deleted.find(gf->mesh_vertices[i]) == deleted.end()){ - mesh_vertices2.push_back(gf->mesh_vertices[i]); - } - else { - // FIXME : GMSH SOMETIMES CRASHES IF DELETED .... - // delete gf->mesh_vertices[i]; - } - } - - gf->mesh_vertices = mesh_vertices2; - - return diamonds.size(); -} - -int removeDiamonds(GFace *gf) -{ - int nbRemove = 0; - while(1){ - int x = _removeDiamonds(gf); - if (!x)break; - nbRemove += x; - } - Msg::Debug("%i diamond quads removed",nbRemove); - return nbRemove; -} - -struct p1p2p3 { - MVertex *p1,*p2; -}; - - -void _relocateVertex(GFace *gf, MVertex *ver, - const std::vector<MElement*> <) -{ - if(ver->onWhat()->dim() != 2) return; - MFaceVertex *fv = dynamic_cast<MFaceVertex*>(ver); - if(fv && fv->bl_data) return; - - double initu, initv; - ver->getParameter(0, initu); - ver->getParameter(1, initv); - - // compute the vertices connected to that one - std::map<MVertex*,SPoint2> pts; - for(unsigned int i = 0; i < lt.size(); i++){ - for (int j=0;j<lt[i]->getNumEdges();j++){ - MEdge e = lt[i]->getEdge(j); - SPoint2 param0, param1; - if (e.getVertex(0) == ver){ - reparamMeshEdgeOnFace(e.getVertex(0), e.getVertex(1), gf, param0, param1); - pts[e.getVertex(1)] = param1; - } - else if (e.getVertex(1) == ver){ - reparamMeshEdgeOnFace(e.getVertex(0), e.getVertex(1), gf, param0, param1); - pts[e.getVertex(0)] = param0; - } - } - } - - SPoint2 before(initu,initv); - double metric[3]; - SPoint2 after(0,0); - double COUNT = 0.0; - // printf("weights :"); - for(std::map<MVertex*,SPoint2>::iterator it = pts.begin(); it != pts.end() ; ++it) { - SPoint2 adj = it->second; - SVector3 d(adj.x() - before.x(), adj.y() - before.y(), 0.0); - d.normalize(); - buildMetric(gf, adj, metric); - const double F = sqrt(metric[0]*d.x()*d.x() + - 2*metric[1]*d.x()*d.y() + - metric[2]*d.y()*d.y()); - // printf("%g ",F); - after += adj*F; - COUNT += F; - // double RATIO = lt[i]->getVolume()/pow(metric[0]*metric[2]-metric[1]*metric[1],0.5); - } - // printf("\n"); - after *= (1.0/COUNT); - double FACTOR = 1.0; - const int MAXITER = 5; - SPoint2 actual = before; - for (int ITER = 0;ITER < MAXITER; ITER ++){ - SPoint2 trial = after * FACTOR + before * (1.-FACTOR); - bool success = _isItAGoodIdeaToMoveThatVertex (gf, lt, ver,actual,trial); - if (success){ - GPoint pt = gf->point(trial); - if(pt.succeeded()){ - actual = trial; - ver->setParameter(0, trial.x()); - ver->setParameter(1, trial.y()); - ver->x() = pt.x(); - ver->y() = pt.y(); - ver->z() = pt.z(); - } - } - FACTOR /= 1.4; - } -} - -void getAllBoundaryLayerVertices (GFace *gf, std::set<MVertex*> &vs){ - // return; - vs.clear(); - BoundaryLayerColumns* _columns = gf->getColumns(); - if (!_columns)return; - for ( std::map<MElement*,std::vector<MElement*> >::iterator it = _columns->_elemColumns.begin(); - it != _columns->_elemColumns.end();it++){ - std::vector<MElement *> &e = it->second; - for (unsigned int i=0;i<e.size();i++){ - for (int j=0;j<e[i]->getNumVertices();j++){ - vs.insert(e[i]->getVertex(j)); - } - } - } -} - -void laplaceSmoothing(GFace *gf, int niter, bool infinity_norm) -{ - if (!niter)return; - std::set<MVertex*> vs; - getAllBoundaryLayerVertices (gf, vs); - v2t_cont adj; - buildVertexToElement(gf->triangles, adj); - buildVertexToElement(gf->quadrangles, adj); - for(int i = 0; i < niter; i++){ - v2t_cont::iterator it = adj.begin(); - while (it != adj.end()){ - if (vs.find(it->first) == vs.end()){ - _relocateVertex(gf, it->first, it->second); - } - ++it; - } - } -} - -bool edgeSwapDelProj (MVertex *v1, MVertex *v2, MVertex *v3, MVertex *v4) -{ - MTriangle t1(v1,v2,v3); - MTriangle t2(v2,v1,v4); - - SVector3 n1 = t1.getFace(0).normal(); - SVector3 n2 = t2.getFace(0).normal(); - if (dot(n1,n2) <= 0) { - // printf("OLA !!!\n"); - return true; - } - return false; -} - -bool edgeSwap(std::set<swapquad> &configs, MTri3 *t1, GFace *gf, int iLocalEdge, - std::vector<MTri3*> &newTris, const swapCriterion &cr, bidimMeshData & data) -{ - MTri3 *t2 = t1->getNeigh(iLocalEdge); - if(!t2) return false; - - MVertex *v1 = t1->tri()->getVertex(iLocalEdge == 0 ? 2 : iLocalEdge - 1); - MVertex *v2 = t1->tri()->getVertex((iLocalEdge) % 3); - MVertex *v3 = t1->tri()->getVertex((iLocalEdge + 1) % 3); - MVertex *v4 = 0; - - std::set<MEdge,Less_Edge>::iterator it = data.internalEdges.find(MEdge(v1,v2)); - if (it != data.internalEdges.end())return false; - - - for(int i = 0; i < 3; i++) - if(t2->tri()->getVertex(i) != v1 && t2->tri()->getVertex(i) != v2) - v4 = t2->tri()->getVertex(i); - - swapquad sq (v1, v2, v3, v4); - if(configs.find(sq) != configs.end()) return false; - configs.insert(sq); - - if (edgeSwapDelProj(v3,v4,v2,v1))return false; - - - MTriangle *t1b = new MTriangle(v2, v3, v4); - MTriangle *t2b = new MTriangle(v4, v3, v1); - - switch(cr){ - case SWCR_QUAL: - { - const double triQualityRef = std::min(qmTriangle::gamma(t1->tri()), - qmTriangle::gamma(t2->tri())); - const double triQuality = std::min(qmTriangle::gamma(t1b), - qmTriangle::gamma(t2b)); - if (!edgeSwapDelProj(v1,v2,v3,v4)){ - if(triQuality < triQualityRef){ - delete t1b; - delete t2b; - return false; - } - } - break; - } - case SWCR_DEL: - { - int index1 = data.getIndex(v1); - int index2 = data.getIndex(v2); - int index3 = data.getIndex(v3); - int index4 = data.getIndex(v4); - double edgeCenter[2] ={(data.Us[index1] + data.Us[index2] + - data.Us[index3] + data.Us[index4]) * .25, - (data.Vs[index1] + data.Vs[index2] + - data.Vs[index3] + data.Vs[index4]) * .25}; - double uv4[2] ={data.Us[index4], data.Vs[index4]}; - double metric[3]; - buildMetric(gf, edgeCenter, metric); - if(!inCircumCircleAniso(gf, t1->tri(), uv4, metric, data)){ - delete t1b; - delete t2b; - return false; - } - } - break; - default : - Msg::Error("Unknown swapping criterion"); - delete t1b; - delete t2b; - return false; - } - - std::list<MTri3*> cavity; - for(int i = 0; i < 3; i++){ - if(t1->getNeigh(i) && t1->getNeigh(i) != t2){ - bool found = false; - for(std::list<MTri3*>::iterator it = cavity.begin(); it != cavity.end(); it++){ - if(*it == t1->getNeigh(i)) found = true; - } - if(!found)cavity.push_back(t1->getNeigh(i)); - } - } - for(int i = 0; i < 3; i++){ - if(t2->getNeigh(i) && t2->getNeigh(i) != t1){ - bool found = false; - for(std::list<MTri3*>::iterator it = cavity.begin(); it != cavity.end(); it++){ - if(*it == t2->getNeigh(i)) found = true; - } - if(!found)cavity.push_back(t2->getNeigh(i)); - } - } - - int i10 = data.getIndex(t1b->getVertex(0)); - int i11 = data.getIndex(t1b->getVertex(1)); - int i12 = data.getIndex(t1b->getVertex(2)); - - int i20 = data.getIndex(t2b->getVertex(0)); - int i21 = data.getIndex(t2b->getVertex(1)); - int i22 = data.getIndex(t2b->getVertex(2)); - - double lc1 = 0.3333333333 * (data.vSizes[i10] + data.vSizes[i11] + - data.vSizes[i12]); - double lcBGM1 = 0.3333333333 * (data.vSizesBGM[i10] + data.vSizesBGM[i11] + - data.vSizesBGM[i12]); - - double lc2 = 0.3333333333 * (data.vSizes[i20] + data.vSizes[i21] + - data.vSizes[i22]); - double lcBGM2 = 0.3333333333 * (data.vSizesBGM[i20] + data.vSizesBGM[i21] + - data.vSizesBGM[i22]); - - MTri3 *t1b3 = new MTri3(t1b, Extend1dMeshIn2dSurfaces() ? - std::min(lc1, lcBGM1) : lcBGM1, 0, &data, gf); - MTri3 *t2b3 = new MTri3(t2b, Extend1dMeshIn2dSurfaces() ? - std::min(lc2, lcBGM2) : lcBGM2, 0, &data, gf); - // printf("%d %d %d -- %d %d %d edge %d\n",t1->tri()->getVertex(0)->getNum(),t1->tri()->getVertex(1)->getNum(),t1->tri()->getVertex(2)->getNum(), - // t2->tri()->getVertex(0)->getNum(),t2->tri()->getVertex(1)->getNum(),t2->tri()->getVertex(2)->getNum(),iLocalEdge); - // printf("%d %d %d \n",v2->getNum(),v3->getNum(),v4->getNum()); - // printf("%d %d %d \n",v4->getNum(),v3->getNum(),v1->getNum()); - - cavity.push_back(t2b3); - cavity.push_back(t1b3); - t1->setDeleted(true); - t2->setDeleted(true); - connectTriangles(cavity); - newTris.push_back(t2b3); - newTris.push_back(t1b3); - // printf("%d %d\n",t1b3->isDeleted(),t2b3->isDeleted()); - - return true; -} - -int edgeSwapPass(GFace *gf, std::set<MTri3*, compareTri3Ptr> &allTris, - const swapCriterion &cr,bidimMeshData & data) -{ - typedef std::set<MTri3*, compareTri3Ptr> CONTAINER; - - int nbSwapTot = 0; - std::set<swapquad> configs; - - std::set<MTri3*, compareTri3Ptr> allTris2; - - for(int iter = 0; iter < 10; iter++){ - int nbSwap = 0; - std::vector<MTri3*> newTris; - CONTAINER::iterator it = allTris.begin(); - while(it != allTris.end()){ - CONTAINER::iterator current = it++; - if(!(*current)->isDeleted()){ - for(int i = 0; i < 3; i++){ - if(edgeSwap(configs, *current, gf, i, newTris, cr, data)){ - nbSwap++; - break; - } - } - } - else{ - delete (*current)->tri(); - delete *current; - allTris.erase(current); - } - } - - // allTris = allTris2; - - allTris.insert(newTris.begin(), newTris.end()); - - // for(CONTAINER::iterator it = allTris.begin(); it != allTris.end(); ++it){ - // printf("---> %d %d %d (%d)\n",(*it)->tri()->getVertex(0)->getNum(), - // (*it)->tri()->getVertex(1)->getNum(), - // (*it)->tri()->getVertex(2)->getNum(),(*it)->isDeleted() ); - // } - - nbSwapTot += nbSwap; - if(nbSwap == 0) break; - } - return nbSwapTot; -} - -int edgeSwapPass2(GFace *gf, std::set<MTri3*, compareTri3Ptr> &allTris, - const swapCriterion &cr,bidimMeshData & data) -{ - typedef std::set<MTri3*, compareTri3Ptr> CONTAINER; - - int nbSwapTot = 0; - std::set<swapquad> configs; - for(int iter = 0; iter < 1200; iter++){ - int nbSwap = 0; - std::vector<MTri3*> newTris; - for(CONTAINER::iterator it = allTris.begin(); it != allTris.end(); ++it){ - if(!(*it)->isDeleted()){ - for(int i = 0; i < 3; i++){ - if(edgeSwap(configs, *it, gf, i, newTris, cr, data)){ - nbSwap++; - break; - } - } - } - else{ - delete *it; - CONTAINER::iterator itb = it; - ++it; - allTris.erase(itb); - if(it == allTris.end()) break; - } - } - allTris.insert(newTris.begin(), newTris.end()); - nbSwapTot += nbSwap; - if(nbSwap == 0) break; - } - return nbSwapTot; -} - - - - -static int _recombineIntoQuads(GFace *gf, double minqual, bool cubicGraph = 1) -{ - // never recombine a face that is part of a compound! - if(gf->getCompound()) return 0; - if(gf->triangles.size() == 0) return 1; - - int success = 1; - - std::set<MVertex*> emb_edgeverts; - { - std::list<GEdge*> emb_edges = gf->embeddedEdges(); - std::list<GEdge*>::iterator ite = emb_edges.begin(); - while(ite != emb_edges.end()){ - if(!(*ite)->isMeshDegenerated()){ - emb_edgeverts.insert((*ite)->mesh_vertices.begin(), - (*ite)->mesh_vertices.end() ); - emb_edgeverts.insert((*ite)->getBeginVertex()->mesh_vertices.begin(), - (*ite)->getBeginVertex()->mesh_vertices.end()); - emb_edgeverts.insert((*ite)->getEndVertex()->mesh_vertices.begin(), - (*ite)->getEndVertex()->mesh_vertices.end()); - } - ++ite; - } - } - - { - std::list<GEdge*> _edges = gf->edges(); - std::list<GEdge*>::iterator ite = _edges.begin(); - while(ite != _edges.end()){ - if(!(*ite)->isMeshDegenerated()){ - if ((*ite)->isSeam(gf)){ - emb_edgeverts.insert((*ite)->mesh_vertices.begin(), - (*ite)->mesh_vertices.end() ); - emb_edgeverts.insert((*ite)->getBeginVertex()->mesh_vertices.begin(), - (*ite)->getBeginVertex()->mesh_vertices.end()); - emb_edgeverts.insert((*ite)->getEndVertex()->mesh_vertices.begin(), - (*ite)->getEndVertex()->mesh_vertices.end()); - } - } - ++ite; - } - } - - e2t_cont adj; - buildEdgeToElement(gf->triangles, adj); - - std::vector<RecombineTriangle> pairs; - std::map<MVertex*,std::pair<MElement*,MElement*> > makeGraphPeriodic; - - for(e2t_cont::iterator it = adj.begin(); it!= adj.end(); ++it){ - if(it->second.second && - it->second.first->getNumVertices() == 3 && - it->second.second->getNumVertices() == 3 && - (emb_edgeverts.find(it->first.getVertex(0)) == emb_edgeverts.end() || - emb_edgeverts.find(it->first.getVertex(1)) == emb_edgeverts.end())){ - pairs.push_back(RecombineTriangle(it->first, - it->second.first, - it->second.second)); - } - else if (!it->second.second && - it->second.first->getNumVertices() == 3){ - for (int i=0;i<2;i++){ - MVertex *v = it->first.getVertex(i); - std::map<MVertex*,std::pair<MElement*,MElement*> > :: iterator itv = - makeGraphPeriodic.find(v); - if (itv == makeGraphPeriodic.end()){ - makeGraphPeriodic[v] = std::make_pair(it->second.first,(MElement*)0); - } - else{ - if ( itv->second.first != it->second.first) - itv->second.second = it->second.first; - else - makeGraphPeriodic.erase(itv); - } - } - } - } - - std::sort(pairs.begin(),pairs.end()); - std::set<MElement*> touched; - - if(CTX::instance()->mesh.algoRecombine != 0){ -#if defined(HAVE_BLOSSOM) - int ncount = gf->triangles.size(); - if (ncount % 2 != 0 && CTX::instance()->mesh.algoRecombine == 1) { - Msg::Warning("Cannot apply Blosson: odd number of triangles (%d) in surface %d", - ncount, gf->tag()); - } - if (ncount % 2 == 0) { - int ecount = cubicGraph ? pairs.size() + makeGraphPeriodic.size() : pairs.size(); - Msg::Info("Blossom: %d internal %d closed", - (int)pairs.size(), (int)makeGraphPeriodic.size()); - //Msg::Info("Cubic Graph should have ne (%d) = 3 x nv (%d) ",ecount,ncount); - Msg::Debug("Perfect Match Starts %d edges %d nodes",ecount,ncount); - std::map<MElement*,int> t2n; - std::map<int,MElement*> n2t; - for (unsigned int i=0;i<gf->triangles.size();++i){ - t2n[gf->triangles[i]] = i; - n2t[i] = gf->triangles[i]; - } - //do not use new[] here, blossom will free it with free() and not with delete - int *elist = (int*)malloc(sizeof(int) * 2 * ecount); - int *elen = (int*)malloc(sizeof(int) * ecount); - for (unsigned int i = 0; i < pairs.size(); ++i){ - elist[2*i] = t2n[pairs[i].t1]; - elist[2*i+1] = t2n[pairs[i].t2]; - elen [i] = (int) 1000*exp(-pairs[i].angle); - int NB = 0; - if (pairs[i].n1->onWhat()->dim() < 2) NB++; - if (pairs[i].n2->onWhat()->dim() < 2) NB++; - if (pairs[i].n3->onWhat()->dim() < 2) NB++; - if (pairs[i].n4->onWhat()->dim() < 2) NB++; - if (elen[i] > (int)1000*exp(.1) && NB > 2) { elen[i] = 5000; } - else if (elen[i] >= 1000 && NB > 2) { elen[i] = 10000; } - // printf("%d %d %d\n", elist[2*i],elist[2*i+1],elen [i] ); - } - - if (cubicGraph){ - std::map<MVertex*, std::pair<MElement*, MElement*> >::iterator itv = - makeGraphPeriodic.begin(); - int CC = pairs.size(); - for ( ; itv != makeGraphPeriodic.end(); ++itv){ - elist[2*CC] = t2n[itv->second.first]; - elist[2*CC+1] = t2n[itv->second.second]; - elen [CC++] = 100000; - } - } - - double matzeit = 0.0; - char MATCHFILE[256]; - sprintf(MATCHFILE,".face.match"); - if(perfect_match(ncount, NULL, ecount, &elist, &elen, NULL, MATCHFILE, - 0, 0, 0, 0, &matzeit)){ - Msg::Error("Perfect Match failed in Quadrangulation, try something else"); - free(elist); - pairs.clear(); - } - else{ - // TEST - for (int k = 0; k < elist[0]; k++){ - int i1 = elist[1+3*k], i2 = elist[1+3*k+1], an=elist[1+3*k+2]; - // FIXME ! - if (an == 100000 /*|| an == 1000*/){ - // toProcess.push_back(std::make_pair(n2t[i1],n2t[i2])); - // Msg::Warning("Extra edge found in blossom algorithm, optimization " - // "will be required"); - } - else{ - MElement *t1 = n2t[i1]; - MElement *t2 = n2t[i2]; - touched.insert(t1); - touched.insert(t2); - MVertex *other = 0; - for(int i = 0; i < 3; i++) { - if (t1->getVertex(0) != t2->getVertex(i) && - t1->getVertex(1) != t2->getVertex(i) && - t1->getVertex(2) != t2->getVertex(i)){ - other = t2->getVertex(i); - break; - } - } - int start = 0; - for(int i = 0; i < 3; i++) { - if (t2->getVertex(0) != t1->getVertex(i) && - t2->getVertex(1) != t1->getVertex(i) && - t2->getVertex(2) != t1->getVertex(i)){ - start=i; - break; - } - } - MQuadrangle *q = new MQuadrangle(t1->getVertex(start), - t1->getVertex((start+1)%3), - other, - t1->getVertex((start+2)%3)); - gf->quadrangles.push_back(q); - } - } - free(elist); - pairs.clear(); - Msg::Debug("Perfect Match Succeeded in Quadrangulation (%g sec)", matzeit); - } - } - -#else - Msg::Warning("Gmsh should be compiled with the Blossom IV code and CONCORDE " - "in order to allow the Blossom optimization"); -#endif - } - - std::vector<RecombineTriangle>::iterator itp = pairs.begin(); - while(itp != pairs.end()){ - // recombine if difference between max quad angle and right - // angle is smaller than tol - // printf("%g %g\n",gf->meshAttributes.recombineAngle,itp->angle); - if(itp->angle < gf->meshAttributes.recombineAngle){ - MElement *t1 = itp->t1; - MElement *t2 = itp->t2; - if(touched.find(t1) == touched.end() && - touched.find(t2) == touched.end()){ - touched.insert(t1); - touched.insert(t2); - - int orientation = 0; - for(int i = 0; i < 3; i++) { - if(t1->getVertex(i) == itp->n1) { - if(t1->getVertex((i + 1) % 3) == itp->n2) - orientation = 1; - else - orientation = -1; - break; - } - } - MQuadrangle *q; - if(orientation < 0) - q = new MQuadrangle(itp->n1, itp->n3, itp->n2, itp->n4); - else - q = new MQuadrangle(itp->n1, itp->n4, itp->n2, itp->n3); - gf->quadrangles.push_back(q); - } - } - ++itp; - } - - std::vector<MTriangle*> triangles2; - for(unsigned int i = 0; i < gf->triangles.size(); i++){ - if(touched.find(gf->triangles[i]) == touched.end()){ - triangles2.push_back(gf->triangles[i]); - } - else { - delete gf->triangles[i]; - } - } - gf->triangles = triangles2; - - if(CTX::instance()->mesh.algoRecombine != 1){ - quadsToTriangles(gf, minqual); - } - - return success; -} - -static double printStats(GFace *gf,const char *message) -{ - int nbBad=0; - int nbInv=0; - double Qav=0; - double Qmin=1; - for (unsigned int i=0;i<gf->quadrangles.size();i++){ - double Q = gf->quadrangles[i]->etaShapeMeasure() ; - if (Q <= 0.0)nbInv ++; - if (Q <= 0.1)nbBad ++; - Qav += Q; - Qmin = std::min(Q,Qmin); - } - Msg::Info("%s: %5d quads %5d triangles %1d invalid quads %2d quads with Q < 0.1 " - "Avg Q = %5.3f Min Q %5.3f", message, gf->quadrangles.size(), - gf->triangles.size(), nbInv, nbBad, Qav/gf->quadrangles.size(), Qmin); - return Qmin; -} - -void recombineIntoQuads(GFace *gf, - bool topologicalOpti, - bool nodeRepositioning, - double minqual, - bool firstpass) -{ - double t1 = Cpu(); - - - bool haveParam = true; - bool saveAll = false; //CTX::instance()->mesh.saveAll; - if(gf->geomType() == GEntity::DiscreteSurface && !gf->getCompound()) - haveParam = false; - - if (saveAll) gf->model()->writeMSH("before.msh"); - int success = _recombineIntoQuads(gf, minqual); - - if (saveAll) gf->model()->writeMSH("raw.msh"); - if(haveParam && nodeRepositioning){ - RelocateVertices (gf,CTX::instance()->mesh.nbSmoothing); - } - - // blossom-quad algo - if(success && CTX::instance()->mesh.algoRecombine != 0){ - if(topologicalOpti){ - if(haveParam){ - if (saveAll) gf->model()->writeMSH("smoothed.msh"); - int ITER=0; - std::set<MEdge,Less_Edge> prioritory; - int nbTwoQuadNodes = 1; - int nbDiamonds = 1; - while(nbTwoQuadNodes || nbDiamonds){ - nbTwoQuadNodes = removeTwoQuadsNodes(gf); - nbDiamonds = removeDiamonds(gf) ; - if(haveParam) RelocateVertices (gf,CTX::instance()->mesh.nbSmoothing); - // printStats (gf, "toto"); - if (ITER > 20) break; - ITER ++; - } - } - } - quadsToTriangles(gf, minqual); - if(haveParam)RelocateVertices (gf,CTX::instance()->mesh.nbSmoothing); - - double t2 = Cpu(); - char name[256]; - sprintf(name,"Blossom completed (%4.2f s)", t2 - t1); - if (firstpass)printStats (gf, name); - else printStats (gf, "Second pass "); - return; - } - - // simple recombination algo - for (int IT=0;IT<2;IT++){ - _recombineIntoQuads(gf, 0); - if(haveParam) RelocateVertices (gf,CTX::instance()->mesh.nbSmoothing); - } - - if (saveAll) gf->model()->writeMSH("after.msh"); - - double t2 = Cpu(); - Msg::Info("Simple recombination algorithm completed (%g s)", t2 - t1); -} - -void quadsToTriangles(GFace *gf, double minqual) -{ - - std::vector<MQuadrangle*> qds; - std::map<MElement*, std::pair<MElement*,MElement*> > change; - for (unsigned int i = 0; i < gf->quadrangles.size(); i++){ - MQuadrangle *q = gf->quadrangles[i]; - if (q->gammaShapeMeasure() < minqual){ - MTriangle *t11 = new MTriangle (q->getVertex(0),q->getVertex(1),q->getVertex(2)); - MTriangle *t12 = new MTriangle (q->getVertex(2),q->getVertex(3),q->getVertex(0)); - MTriangle *t21 = new MTriangle (q->getVertex(1),q->getVertex(2),q->getVertex(3)); - MTriangle *t22 = new MTriangle (q->getVertex(3),q->getVertex(0),q->getVertex(1)); - double qual1 = std::min(t11->gammaShapeMeasure(),t12->gammaShapeMeasure()); - double qual2 = std::min(t21->gammaShapeMeasure(),t22->gammaShapeMeasure()); - - double surf1 = surfaceFaceUV(t11,gf) + surfaceFaceUV(t12,gf); - double surf2 = surfaceFaceUV(t21,gf) + surfaceFaceUV(t22,gf); - - int option = 0; - if (surf1 > surf2 * (1.+1.e-8))option = 2; - else if (surf2 > surf1 * (1.+1.e-8))option = 1; - - if (option == 1 || (option == 0 && qual1 > qual2)){ - gf->triangles.push_back(t11); - gf->triangles.push_back(t12); - change[q] = std::make_pair(t11,t12); - delete t21; delete t22; - } - else { - gf->triangles.push_back(t21); - gf->triangles.push_back(t22); - change[q] = std::make_pair(t21,t22); - delete t11; delete t12; - } - delete q; // FIXME this makes gmsh to crash when creating BL with triangles - // FIXED (JF) - } - else { - qds.push_back(q); - } - } - gf->quadrangles = qds; - - BoundaryLayerColumns* _columns = gf->getColumns(); - if (!_columns)return; - for ( std::map<MElement*,std::vector<MElement*> >::iterator it = _columns->_elemColumns.begin(); - it != _columns->_elemColumns.end();it++){ - std::vector<MElement *> &e = it->second; - std::vector<MElement *> eOld = e; - e.clear(); - for (unsigned int i=0;i<eOld.size();i++){ - MElement *ee = eOld[i]; - std::map<MElement*, std::pair<MElement*,MElement*> >::iterator it2 = change.find(ee); - if (it2 == change.end()){ - e.push_back(ee); - } - else { - e.push_back(it2->second.first); - e.push_back(it2->second.second); - } - } - } - - -} diff --git a/Plugin/AnalyseCurvedMesh.cpp b/Plugin/AnalyseCurvedMesh.cpp index 4f57b2f7f073283353ac3c1f2e29cdd47c6488c1..c798ab731f8d45ea8a26b9f7c94ef87afa4643af 100644 --- a/Plugin/AnalyseCurvedMesh.cpp +++ b/Plugin/AnalyseCurvedMesh.cpp @@ -172,8 +172,12 @@ PView* GMSH_AnalyseCurvedMeshPlugin::execute(PView *v) std::map<int, std::vector<double> > dataPV; for (unsigned int i = 0; i < _data.size(); ++i) { MElement *const el = _data[i].element(); - if (el->getDim() == dim) - dataPV[el->getNum()].push_back(_data[i].minJ()/_data[i].maxJ()); + if (el->getDim() == dim) { + double q = 0; + if (_data[i].maxJ() > 0) q = _data[i].minJ() / _data[i].maxJ(); + else if (_data[i].maxJ() < 0) q = _data[i].maxJ() / _data[i].minJ(); + dataPV[el->getNum()].push_back(q); + } } if (dataPV.size()) { std::stringstream name; @@ -248,6 +252,7 @@ void GMSH_AnalyseCurvedMeshPlugin::_computeMinMaxJandValidity(int dim) return; } + int cntInverted = 0; std::set<GEntity*, GEntityLessThan>::iterator it; for (it = entities.begin(); it != entities.end(); ++it) { GEntity *entity = *it; @@ -335,13 +340,14 @@ void GMSH_AnalyseCurvedMeshPlugin::_computeMinMaxJandValidity(int dim) double min, max; jacobianBasedQuality::minMaxJacobianDeterminant(el, min, max, normals); _data.push_back(data_elementMinMax(el, min, max)); - if (min < 0 && max < 0) { - Msg::Warning("Element %d is completely inverted", el->getNum()); - } + if (min < 0 && max < 0) ++cntInverted; progress.next(); } delete normals; } + if (cntInverted) { + Msg::Warning("%d elements are completely inverted", cntInverted); + } _computedJac[dim-1] = true; } @@ -354,7 +360,7 @@ void GMSH_AnalyseCurvedMeshPlugin::_computeMinIGE(int dim) for (unsigned int i = 0; i < _data.size(); ++i) { MElement *const el = _data[i].element(); if (el->getDim() != dim) continue; - if (_data[i].minJ() <= 0) { + if (_data[i].minJ() <= 0 && _data[i].maxJ() > 0) { _data[i].setMinS(0); } else { @@ -375,7 +381,7 @@ void GMSH_AnalyseCurvedMeshPlugin::_computeMinICN(int dim) for (unsigned int i = 0; i < _data.size(); ++i) { MElement *const el = _data[i].element(); if (el->getDim() != dim) continue; - if (_data[i].minJ() <= 0) { + if (_data[i].minJ() <= 0 && _data[i].maxJ() > 0) { _data[i].setMinI(0); } else { @@ -438,19 +444,22 @@ void GMSH_AnalyseCurvedMeshPlugin::_printStatJacobian() avgminJ = avgratJ = avgratJc = 0; for (unsigned int i = 0; i < _data.size(); ++i) { - double q = 0; - if ( _data[i].minJ() > 0) q = _data[i].minJ() / _data[i].maxJ(); infminJ = std::min(infminJ, _data[i].minJ()); supminJ = std::max(supminJ, _data[i].minJ()); avgminJ += _data[i].minJ(); - infratJ = std::min(infratJ, _data[i].minJ()/_data[i].maxJ()); - supratJ = std::max(supratJ, _data[i].minJ()/_data[i].maxJ()); - avgratJ += _data[i].minJ()/_data[i].maxJ(); - ++count; + + double q = 0; + if (_data[i].maxJ() > 0) q = _data[i].minJ() / _data[i].maxJ(); + else if (_data[i].maxJ() < 0) q = _data[i].maxJ() / _data[i].minJ(); + infratJ = std::min(infratJ, q); + supratJ = std::max(supratJ, q); + avgratJ += q; if (q < 1-1e-5) { avgratJc += _data[i].minJ()/_data[i].maxJ(); ++countc; } + + ++count; } avgminJ /= count; avgratJ /= count;