gmsh-TingyuanDoc  0.1
An Open-Source Timing-driven Analytical Mixed-size FPGA Placer
meshGFaceOptimize.cpp
Go to the documentation of this file.
1 // Gmsh - Copyright (C) 1997-2022 C. Geuzaine, J.-F. Remacle
2 //
3 // See the LICENSE.txt file in the Gmsh root directory for license information.
4 // Please report all issues on https://gitlab.onelab.info/gmsh/gmsh/issues.
5 
6 #include <stack>
7 #include "GmshConfig.h"
8 #include "meshGFaceOptimize.h"
9 #include "qualityMeasures.h"
10 #include "GFace.h"
11 #include "GEdge.h"
12 #include "GVertex.h"
13 #include "GModel.h"
14 #include "MVertex.h"
15 #include "MTriangle.h"
16 #include "MQuadrangle.h"
17 #include "MLine.h"
18 #include "BackgroundMeshTools.h"
19 #include "Numeric.h"
20 #include "GmshMessage.h"
21 #include "Context.h"
22 #include "OS.h"
23 #include "SVector3.h"
24 #include "SPoint3.h"
25 #include "meshRelocateVertex.h"
26 #include "Field.h"
27 
28 #if defined(HAVE_BLOSSOM)
29 extern "C" struct CCdatagroup;
30 extern "C" int perfect_match(int ncount, CCdatagroup *dat, int ecount,
31  int **elist, int **elen, char *blo_filename,
32  char *mat_filename, int just_fractional,
33  int no_fractional, int use_all_trees,
34  int partialprice, double *totalzeit);
35 #endif
36 
38  MElement *_t2, Field *cross_field)
39  : t1(_t1), t2(_t2)
40 {
41  n1 = me.getVertex(0);
42  n2 = me.getVertex(1);
43  n3 = 0;
44  n4 = 0;
45 
46  if(t1->getVertex(0) != n1 && t1->getVertex(0) != n2)
47  n3 = t1->getVertex(0);
48  else if(t1->getVertex(1) != n1 && t1->getVertex(1) != n2)
49  n3 = t1->getVertex(1);
50  else if(t1->getVertex(2) != n1 && t1->getVertex(2) != n2)
51  n3 = t1->getVertex(2);
52 
53  if(t2->getVertex(0) != n1 && t2->getVertex(0) != n2)
54  n4 = t2->getVertex(0);
55  else if(t2->getVertex(1) != n1 && t2->getVertex(1) != n2)
56  n4 = t2->getVertex(1);
57  else if(t2->getVertex(2) != n1 && t2->getVertex(2) != n2)
58  n4 = t2->getVertex(2);
59 
60  if(!n3) {
61  Msg::Warning("Invalid quadrangle in recombination");
62  n3 = n1;
63  }
64  if(!n4) {
65  Msg::Warning("Invalid quadrangle in recombination");
66  n4 = n2;
67  }
68 
69  MQuadrangle q(n1, n3, n2, n4);
70  angle = q.etaShapeMeasure();
71 
72  double const a1 = 180 * angle3Vertices(n1, n4, n2) / M_PI;
73  double const a2 = 180 * angle3Vertices(n4, n2, n3) / M_PI;
74  double const a3 = 180 * angle3Vertices(n2, n3, n1) / M_PI;
75  double const a4 = 180 * angle3Vertices(n3, n1, n4) / M_PI;
76  quality = std::abs(90. - a1);
77  quality = std::max(std::abs(90. - a2), quality);
78  quality = std::max(std::abs(90. - a3), quality);
79  quality = std::max(std::abs(90. - a4), quality);
80 
81  if(cross_field) {
82  SVector3 t1;
83  SVector3 t2(me.getVertex(1)->x() - me.getVertex(0)->x(),
84  me.getVertex(1)->y() - me.getVertex(0)->y(),
85  me.getVertex(1)->z() - me.getVertex(0)->z());
86  (*cross_field)(0.5 * (me.getVertex(0)->x() + me.getVertex(1)->x()),
87  0.5 * (me.getVertex(0)->y() + me.getVertex(1)->y()),
88  0.5 * (me.getVertex(0)->z() + me.getVertex(1)->z()), t1,
89  NULL);
90  // double L1 = t1.norm();
91  t1.normalize();
92  // double L2 = t2.norm();
93  t2.normalize();
94  SVector3 n = crossprod(t1, t2);
95  double ErrDir = std::min(fabs(dot(t1, t2)), n.norm());
96  // double ErrL = fabs(L1-L2)/(L1);
97  // printf("quality %g err %g L %g %g\n",quality,ErrL,L1,L2);
98  quality /= ErrDir;
99  if(n1->onWhat()->dim() < 2 || n2->onWhat()->dim() < 2) quality /= 10;
100  }
101 }
102 
104  : v1(_v1), v2(_v2)
105 {
106  if(!t2)
107  angle = 0;
108  else {
109  double c1[3];
110  double c2[3];
111  double c3[3];
112  {
113  MVertex *p1 = t1->getVertex(0);
114  MVertex *p2 = t1->getVertex(1);
115  MVertex *p3 = t1->getVertex(2);
116  double a[3] = {p1->x() - p2->x(), p1->y() - p2->y(), p1->z() - p2->z()};
117  double b[3] = {p1->x() - p3->x(), p1->y() - p3->y(), p1->z() - p3->z()};
118  c1[2] = a[0] * b[1] - a[1] * b[0];
119  c1[1] = -a[0] * b[2] + a[2] * b[0];
120  c1[0] = a[1] * b[2] - a[2] * b[1];
121  }
122  {
123  MVertex *p1 = t2->getVertex(0);
124  MVertex *p2 = t2->getVertex(1);
125  MVertex *p3 = t2->getVertex(2);
126  double a[3] = {p1->x() - p2->x(), p1->y() - p2->y(), p1->z() - p2->z()};
127  double b[3] = {p1->x() - p3->x(), p1->y() - p3->y(), p1->z() - p3->z()};
128  c2[2] = a[0] * b[1] - a[1] * b[0];
129  c2[1] = -a[0] * b[2] + a[2] * b[0];
130  c2[0] = a[1] * b[2] - a[2] * b[1];
131  }
132  norme(c1);
133  norme(c2);
134  prodve(c1, c2, c3);
135  double const cosa = prosca(c1, c2);
136  double const sina = norme(c3);
137  angle = std::atan2(sina, cosa);
138  }
139 }
140 
141 static void setLcsInit(MTriangle *t, std::map<MVertex *, double> &vSizes)
142 {
143  for(int i = 0; i < 3; i++) {
144  for(int j = i + 1; j < 3; j++) {
145  MVertex *vi = t->getVertex(i);
146  MVertex *vj = t->getVertex(j);
147  vSizes[vi] = -1;
148  vSizes[vj] = -1;
149  }
150  }
151 }
152 
153 static void setLcs(MTriangle *t, std::map<MVertex *, double> &vSizes,
154  bidimMeshData &data)
155 {
156  for(int i = 0; i < 3; i++) {
157  for(int j = i + 1; j < 3; j++) {
158  MVertex *vi = t->getVertex(i);
159  MVertex *vj = t->getVertex(j);
160  if(vi != data.equivalent(vj) && vj != data.equivalent(vi)) {
161  double dx = vi->x() - vj->x();
162  double dy = vi->y() - vj->y();
163  double dz = vi->z() - vj->z();
164  double l = sqrt(dx * dx + dy * dy + dz * dz);
165  auto iti = vSizes.find(vi);
166  auto itj = vSizes.find(vj);
167  if(iti->second < 0 || iti->second > l) iti->second = l;
168  if(itj->second < 0 || itj->second > l) itj->second = l;
169  }
170  }
171  }
172 }
173 
175  GFace *gf, std::set<MTri3 *, compareTri3Ptr> &AllTris, bidimMeshData &data)
176 {
177  std::map<MVertex *, double> vSizesMap;
178 
179  for(std::size_t i = 0; i < gf->triangles.size(); i++)
180  setLcsInit(gf->triangles[i], vSizesMap);
181 
182  auto itfind = vSizesMap.find(nullptr);
183  if(itfind != vSizesMap.end()) {
184  Msg::Error("Some NULL points exist in 2D mesh");
185  return false;
186  }
187 
188  for(std::size_t i = 0; i < gf->triangles.size(); i++)
189  setLcs(gf->triangles[i], vSizesMap, data);
190 
191  // take care of embedded vertices
192  std::set<MVertex *> embeddedVertices;
193  {
194  std::vector<GVertex *> emb_vertx = gf->getEmbeddedVertices();
195  auto itvx = emb_vertx.begin();
196  while(itvx != emb_vertx.end()) {
197  if((*itvx)->mesh_vertices.size()) {
198  MVertex *v = *((*itvx)->mesh_vertices.begin());
199  vSizesMap[v] =
200  std::min(vSizesMap[v], (*itvx)->prescribedMeshSizeAtVertex());
201  embeddedVertices.insert(v);
202  }
203  ++itvx;
204  }
205  }
206 
207  // take good care of embedded edges
208  {
209  std::vector<GEdge *> embedded_edges = gf->getEmbeddedEdges();
210  auto ite = embedded_edges.begin();
211  while(ite != embedded_edges.end()) {
212  if(!(*ite)->isMeshDegenerated()) {
213  for(std::size_t i = 0; i < (*ite)->lines.size(); i++)
214  data.internalEdges.insert(MEdge((*ite)->lines[i]->getVertex(0),
215  (*ite)->lines[i]->getVertex(1)));
216  }
217  ++ite;
218  }
219  }
220 
221  // take care of small edges in order not to "pollute" the size field
222  {
223  std::vector<GEdge *> _edges = gf->edges();
224  auto ite = _edges.begin();
225  while(ite != _edges.end()) {
226  if(!(*ite)->isMeshDegenerated()) {
227  for(std::size_t i = 0; i < (*ite)->lines.size(); i++) {
228  double d = distance((*ite)->lines[i]->getVertex(0),
229  (*ite)->lines[i]->getVertex(1));
230  double d0 = vSizesMap[(*ite)->lines[i]->getVertex(0)];
231  double d1 = vSizesMap[(*ite)->lines[i]->getVertex(1)];
232  if(d0 < .5 * d) vSizesMap[(*ite)->lines[i]->getVertex(0)] = .5 * d;
233  if(d1 < .5 * d) vSizesMap[(*ite)->lines[i]->getVertex(1)] = .5 * d;
234  }
235  }
236  ++ite;
237  }
238  }
239 
240  for(auto it = vSizesMap.begin(); it != vSizesMap.end(); ++it) {
241  SPoint2 param;
242  reparamMeshVertexOnFace(it->first, gf, param);
243  // Add size of background mesh to embedded vertices. For the other nodes,
244  // use the size in vSizesMap
245  const double lcBGM = (embeddedVertices.count(it->first) > 0) ?
246  BGM_MeshSize(gf, param[0], param[1], it->first->x(),
247  it->first->y(), it->first->z()) :
248  it->second;
249  data.addVertex(it->first, param[0], param[1], it->second, lcBGM);
250  }
251  for(std::size_t i = 0; i < gf->triangles.size(); i++) {
252  double lc = 0.3333333333 *
253  (data.vSizes[data.getIndex(gf->triangles[i]->getVertex(0))] +
254  data.vSizes[data.getIndex(gf->triangles[i]->getVertex(1))] +
255  data.vSizes[data.getIndex(gf->triangles[i]->getVertex(2))]);
256  double lcBGM =
257  0.3333333333 *
258  (data.vSizesBGM[data.getIndex(gf->triangles[i]->getVertex(0))] +
259  data.vSizesBGM[data.getIndex(gf->triangles[i]->getVertex(1))] +
260  data.vSizesBGM[data.getIndex(gf->triangles[i]->getVertex(2))]);
261 
262  double LL = Extend1dMeshIn2dSurfaces(gf) ? std::min(lc, lcBGM) : lcBGM;
263  AllTris.insert(new MTri3(gf->triangles[i], LL, nullptr, &data, gf));
264  }
265  gf->triangles.clear();
266  connectTriangles(AllTris);
267 
268  return true;
269 }
270 
272 {
273  if(data.equivalence) {
274  std::vector<MTriangle *> newT;
275  for(std::size_t i = 0; i < gf->triangles.size(); i++) {
276  MTriangle *t = gf->triangles[i];
277  MVertex *v[3];
278  for(int j = 0; j < 3; j++) {
279  v[j] = t->getVertex(j);
280  auto it = data.equivalence->find(v[j]);
281  if(it != data.equivalence->end()) { v[j] = it->second; }
282  }
283  if(v[0] != v[1] && v[0] != v[2] && v[2] != v[1])
284  newT.push_back(new MTriangle(v[0], v[1], v[2]));
285  delete t;
286  }
287  gf->triangles = newT;
288  }
289 }
290 
293  MVertex *_v[3];
294  equivalentTriangle(MTriangle *t, std::map<MVertex *, MVertex *> *equivalence)
295  : _t(t)
296  {
297  for(int i = 0; i < 3; i++) {
298  MVertex *v = t->getVertex(i);
299  auto it = equivalence->find(v);
300  if(it == equivalence->end())
301  _v[i] = v;
302  else
303  _v[i] = it->second;
304  }
305  std::sort(_v, _v + 3);
306  }
307  bool operator<(const equivalentTriangle &other) const
308  {
309  for(int i = 0; i < 3; i++) {
310  if(other._v[i] > _v[i]) return true;
311  if(other._v[i] < _v[i]) return false;
312  }
313  return false;
314  }
315 };
316 
318  std::map<MVertex *, MVertex *> *equivalence)
319 {
320  if(!equivalence) return false;
321  std::vector<MTriangle *> WTF;
322  if(!equivalence) return false;
323  std::set<equivalentTriangle> eqTs;
324  for(std::size_t i = 0; i < gf->triangles.size(); i++) {
325  equivalentTriangle et(gf->triangles[i], equivalence);
326  auto iteq = eqTs.find(et);
327  if(iteq == eqTs.end())
328  eqTs.insert(et);
329  else {
330  WTF.push_back(iteq->_t);
331  WTF.push_back(gf->triangles[i]);
332  }
333  }
334 
335  if(WTF.size()) {
336  Msg::Info("%d triangles are equivalent", WTF.size());
337  for(std::size_t i = 0; i < WTF.size(); i++) {}
338  return true;
339  }
340  return false;
341 }
342 
344 {
346 }
347 
349  std::set<MTri3 *, compareTri3Ptr> &AllTris,
350  bidimMeshData &data)
351 {
352  while(1) {
353  if(AllTris.begin() == AllTris.end()) break;
354  MTri3 *worst = *AllTris.begin();
355  if(worst->isDeleted())
356  delete worst->tri();
357  else
358  gf->triangles.push_back(worst->tri());
359  delete worst;
360  AllTris.erase(AllTris.begin());
361  }
362 
363  // make sure all the triangles are oriented in the same way in
364  // parameter space (it would be nicer to change the actual algorithm
365  // to ensure that we create correctly-oriented triangles in the
366  // first place)
367 
368  // if BL triangles are considered, then all that is WRONG !
369 
370  if(gf->triangles.size() > 1) {
371  bool BL = !gf->getColumns()->_toFirst.empty();
372 
373  double n1[3], n2[3];
374  MTriangle *t = gf->triangles[0];
375  MVertex *v0 = t->getVertex(0), *v1 = t->getVertex(1), *v2 = t->getVertex(2);
376 
377  if(!BL) {
378  int index0 = data.getIndex(v0);
379  int index1 = data.getIndex(v1);
380  int index2 = data.getIndex(v2);
381  normal3points(data.Us[index0], data.Vs[index0], 0., data.Us[index1],
382  data.Vs[index1], 0., data.Us[index2], data.Vs[index2], 0.,
383  n1);
384  }
385  else {
386  // BL --> PLANAR FACES !!!
387  normal3points(v0->x(), v0->y(), v0->z(), v1->x(), v1->y(), v1->z(),
388  v2->x(), v2->y(), v2->z(), n1);
389  }
390  for(std::size_t j = 1; j < gf->triangles.size(); j++) {
391  t = gf->triangles[j];
392  v0 = t->getVertex(0);
393  v1 = t->getVertex(1);
394  v2 = t->getVertex(2);
395  if(!BL) {
396  int index0 = data.getIndex(v0);
397  int index1 = data.getIndex(v1);
398  int index2 = data.getIndex(v2);
399  normal3points(data.Us[index0], data.Vs[index0], 0., data.Us[index1],
400  data.Vs[index1], 0., data.Us[index2], data.Vs[index2], 0.,
401  n2);
402  }
403  else {
404  // BL --> PLANAR FACES !!!
405  normal3points(v0->x(), v0->y(), v0->z(), v1->x(), v1->y(), v1->z(),
406  v2->x(), v2->y(), v2->z(), n2);
407  }
408  // orient the bignou
409  if(prosca(n1, n2) < 0.0) t->reverse();
410  }
411  }
412  splitEquivalentTriangles(gf, data);
413  computeEquivalences(gf, data);
414 }
415 
416 template <class T>
417 void buildEdgeToElement(std::vector<T *> &elements, e2t_cont &adj)
418 {
419  for(std::size_t i = 0; i < elements.size(); i++) {
420  T *t = elements[i];
421  for(int j = 0; j < t->getNumEdges(); j++) {
422  MEdge e = t->getEdge(j);
423  auto it = adj.find(e);
424  if(it == adj.end()) {
425  std::pair<MElement *, MElement *> one =
426  std::make_pair(t, (MElement *)nullptr);
427  adj[e] = one;
428  }
429  else {
430  it->second.second = t;
431  }
432  }
433  }
434 }
435 
437 {
438  adj.clear();
439  buildEdgeToElement(gf->triangles, adj);
441 }
442 
443 void buildEdgeToTriangle(std::vector<MTriangle *> &tris, e2t_cont &adj)
444 {
445  adj.clear();
446  buildEdgeToElement(tris, adj);
447 }
448 
449 void buildEdgeToElements(std::vector<MElement *> &tris, e2t_cont &adj)
450 {
451  adj.clear();
452  buildEdgeToElement(tris, adj);
453 }
454 
455 void buildListOfEdgeAngle(e2t_cont adj, std::vector<edge_angle> &edges_detected,
456  std::vector<edge_angle> &edges_lonly)
457 {
458  auto it = adj.begin();
459  for(; it != adj.end(); ++it) {
460  if(it->second.second)
461  edges_detected.push_back(edge_angle(it->first.getVertex(0),
462  it->first.getVertex(1),
463  it->second.first, it->second.second));
464  else
465  edges_lonly.push_back(edge_angle(it->first.getVertex(0),
466  it->first.getVertex(1), it->second.first,
467  it->second.second));
468  }
469  std::sort(edges_detected.begin(), edges_detected.end());
470 }
471 
472 static void parametricCoordinates(MElement *t, GFace *gf, double u[4],
473  double v[4], MVertex *close = nullptr)
474 {
475  for(std::size_t j = 0; j < t->getNumVertices(); j++) {
476  MVertex *ver = t->getVertex(j);
477  SPoint2 param, dummy;
478  if(!close)
479  reparamMeshVertexOnFace(ver, gf, param);
480  else
481  reparamMeshEdgeOnFace(ver, close, gf, param, dummy);
482  u[j] = param[0];
483  v[j] = param[1];
484  }
485 }
486 
487 double surfaceFaceUV(MElement *t, GFace *gf, bool maximal = true)
488 {
489  const int N = t->getNumVertices();
490  if(N > 4) {
491  Msg::Warning("surfaceFaceUV only for first order elements");
492  return 0;
493  }
494 
495  double u[4], v[4];
496  parametricCoordinates(t, gf, u, v);
497  if(N == 3)
498  return 0.5 *
499  fabs((u[1] - u[0]) * (v[2] - v[0]) - (u[2] - u[0]) * (v[1] - v[0]));
500  else {
501  const double a1 =
502  0.5 *
503  fabs((u[1] - u[0]) * (v[2] - v[0]) - (u[2] - u[0]) * (v[1] - v[0])) +
504  0.5 * fabs((u[3] - u[2]) * (v[0] - v[2]) - (u[0] - u[2]) * (v[3] - v[2]));
505  const double a2 =
506  0.5 *
507  fabs((u[2] - u[1]) * (v[3] - v[1]) - (u[3] - u[1]) * (v[2] - v[1])) +
508  0.5 * fabs((u[0] - u[3]) * (v[1] - v[3]) - (u[1] - u[3]) * (v[0] - v[3]));
509  return maximal ? std::max(a2, a1) : std::min(a2, a1);
510  }
511 }
512 
514 {
515  v2t_cont adj;
518  auto it = adj.begin();
519  std::set<MElement *> touched;
520  std::set<MVertex *> vtouched;
521  while(it != adj.end()) {
522  MVertex *v = it->first;
523  if(it->second.size() == 2 && v->onWhat() == gf) {
524  MElement *q1 = it->second[0];
525  MElement *q2 = it->second[1];
526  if(q1->getNumVertices() == 4 && q2->getNumVertices() == 4 &&
527  touched.find(q1) == touched.end() &&
528  touched.find(q2) == touched.end()) {
529  int comm = 0;
530  for(int i = 0; i < 4; i++) {
531  if(q1->getVertex(i) == v) {
532  comm = i;
533  break;
534  }
535  }
536  MVertex *v1 = q1->getVertex((comm + 1) % 4);
537  MVertex *v2 = q1->getVertex((comm + 2) % 4);
538  MVertex *v3 = q1->getVertex((comm + 3) % 4);
539  MVertex *v4 = nullptr;
540  for(int i = 0; i < 4; i++) {
541  if(q2->getVertex(i) != v1 && q2->getVertex(i) != v3 &&
542  q2->getVertex(i) != v) {
543  v4 = q2->getVertex(i);
544  break;
545  }
546  }
547  if(!v4) {
548  Msg::Error("Bug in removeTwoQuadsNodes %p,%p,%p", v1, v2, v3);
549  q1->writePOS(stdout, true, false, false, false, false, false);
550  q2->writePOS(stdout, true, false, false, false, false, false);
551  return 0;
552  }
553  MQuadrangle *q = new MQuadrangle(v1, v2, v3, v4);
554  touched.insert(q1);
555  touched.insert(q2);
556  gf->quadrangles.push_back(q);
557  vtouched.insert(v);
558  }
559  }
560  it++;
561  }
562  std::vector<MQuadrangle *> quadrangles2;
563  quadrangles2.reserve(gf->quadrangles.size() - touched.size());
564  for(std::size_t i = 0; i < gf->quadrangles.size(); i++) {
565  if(touched.find(gf->quadrangles[i]) == touched.end()) {
566  quadrangles2.push_back(gf->quadrangles[i]);
567  }
568  else {
569  delete gf->quadrangles[i];
570  }
571  }
572  gf->quadrangles = quadrangles2;
573 
574  std::vector<MVertex *> mesh_vertices2;
575  mesh_vertices2.reserve(gf->mesh_vertices.size() - vtouched.size());
576  for(std::size_t i = 0; i < gf->mesh_vertices.size(); i++) {
577  if(vtouched.find(gf->mesh_vertices[i]) == vtouched.end()) {
578  mesh_vertices2.push_back(gf->mesh_vertices[i]);
579  }
580  else {
581  delete gf->mesh_vertices[i];
582  }
583  }
584  gf->mesh_vertices = mesh_vertices2;
585 
586  return vtouched.size();
587 }
588 
590 {
591  int nbRemove = 0;
592  while(1) {
593  int x = _removeTwoQuadsNodes(gf);
594  if(!x) break;
595  nbRemove += x;
596  }
597  Msg::Debug("%i two-quadrangles nodes removed", nbRemove);
598  return nbRemove;
599 }
600 
601 static bool _tryToCollapseThatVertex2(GFace *gf, std::vector<MElement *> &e1,
602  std::vector<MElement *> &e2, MElement *q,
603  MVertex *v1, MVertex *v2)
604 {
605  std::vector<MElement *> e = e1;
606  e.insert(e.end(), e2.begin(), e2.end());
607 
608  double x1 = v1->x();
609  double y1 = v1->y();
610  double z1 = v1->z();
611 
612  double x2 = v2->x();
613  double y2 = v2->y();
614  double z2 = v2->z();
615 
616  // new position of v1 && v2
617  double initialGuess[2] = {0, 0};
618  GPoint pp = gf->closestPoint(
619  SPoint3(0.5 * (x1 + x2), 0.5 * (y1 + y2), 0.5 * (z1 + z2)), initialGuess);
620 
621  double worst_quality_old = 1.0;
622  double worst_quality_new = 1.0;
623 
624  int count = 0;
625  for(std::size_t j = 0; j < e.size(); ++j) {
626  if(e[j] != q) {
627  count++;
628  worst_quality_old = std::min(worst_quality_old, e[j]->etaShapeMeasure());
629  v1->x() = pp.x();
630  v1->y() = pp.y();
631  v1->z() = pp.z();
632  v2->x() = pp.x();
633  v2->y() = pp.y();
634  v2->z() = pp.z();
635  worst_quality_new = std::min(worst_quality_new, e[j]->etaShapeMeasure());
636  v1->x() = x1;
637  v1->y() = y1;
638  v1->z() = z1;
639  v2->x() = x2;
640  v2->y() = y2;
641  v2->z() = z2;
642  }
643  }
644 
645  if(worst_quality_new > worst_quality_old) {
646  v1->x() = pp.x();
647  v1->y() = pp.y();
648  v1->z() = pp.z();
649  for(std::size_t j = 0; j < e.size(); ++j) {
650  if(e[j] != q) {
651  for(int k = 0; k < 4; k++) {
652  if(e[j]->getVertex(k) == v2) { e[j]->setVertex(k, v1); }
653  }
654  }
655  }
656  return true;
657  }
658  return false;
659 }
660 
661 // collapse v1 & v2 to their middle and replace into e1 & e2
662 static bool _tryToCollapseThatVertex(GFace *gf, std::vector<MElement *> &e1,
663  std::vector<MElement *> &e2, MElement *q,
664  MVertex *v1, MVertex *v2)
665 {
666  std::vector<MElement *> e = e1;
667  e.insert(e.end(), e2.begin(), e2.end());
668 
669  double uu1, vv1;
670  if(!v1->getParameter(0, uu1)) {
671  return _tryToCollapseThatVertex2(gf, e1, e2, q, v1, v2);
672  }
673  v1->getParameter(1, vv1);
674  double x1 = v1->x();
675  double y1 = v1->y();
676  double z1 = v1->z();
677 
678  double uu2, vv2;
679  v2->getParameter(0, uu2);
680  v2->getParameter(1, vv2);
681  double x2 = v2->x();
682  double y2 = v2->y();
683  double z2 = v2->z();
684 
685  // new position of v1 && v2
686  GPoint pp = gf->point(0.5 * (uu1 + uu2), 0.5 * (vv1 + vv2));
687  double worst_quality_old = 1.0;
688  double worst_quality_new = 1.0;
689  int count = 0;
690  for(std::size_t j = 0; j < e.size(); ++j) {
691  if(e[j] != q) {
692  count++;
693  worst_quality_old = std::min(worst_quality_old, e[j]->etaShapeMeasure());
694  v1->x() = pp.x();
695  v1->y() = pp.y();
696  v1->z() = pp.z();
697  v1->setParameter(0, pp.u());
698  v1->setParameter(1, pp.v());
699  v2->x() = pp.x();
700  v2->y() = pp.y();
701  v2->z() = pp.z();
702  v2->setParameter(0, pp.u());
703  v2->setParameter(1, pp.v());
704  worst_quality_new = std::min(worst_quality_new, e[j]->etaShapeMeasure());
705  v1->x() = x1;
706  v1->y() = y1;
707  v1->z() = z1;
708  v1->setParameter(0, uu1);
709  v1->setParameter(1, vv1);
710  v2->x() = x2;
711  v2->y() = y2;
712  v2->z() = z2;
713  v2->setParameter(0, uu2);
714  v1->setParameter(1, vv2);
715  }
716  }
717 
718  if(worst_quality_new > worst_quality_old) {
719  v1->x() = pp.x();
720  v1->y() = pp.y();
721  v1->z() = pp.z();
722  v1->setParameter(0, pp.u());
723  v1->setParameter(1, pp.v());
724  for(std::size_t j = 0; j < e.size(); ++j) {
725  if(e[j] != q) {
726  for(int k = 0; k < 4; k++) {
727  if(e[j]->getVertex(k) == v2) { e[j]->setVertex(k, v1); }
728  }
729  }
730  }
731  return true;
732  }
733  return false;
734 }
735 
737  const std::vector<MElement *> &e1,
738  MVertex *v1, const SPoint2 &before,
739  const SPoint2 &after)
740 {
741  double surface_old = 0;
742  double surface_new = 0;
743 
744  GPoint gp = gf->point(after);
745  if(!gp.succeeded()) return false;
746  SPoint3 pafter(gp.x(), gp.y(), gp.z());
747  SPoint3 pbefore(v1->x(), v1->y(), v1->z());
748 
749  double minq = 1.0;
750  for(std::size_t j = 0; j < e1.size(); ++j) {
751  surface_old += surfaceFaceUV(e1[j], gf, false);
752  minq = std::min(e1[j]->etaShapeMeasure(), minq);
753  }
754 
755  v1->setParameter(0, after.x());
756  v1->setParameter(1, after.y());
757  v1->setXYZ(pafter.x(), pafter.y(), pafter.z());
758 
759  double minq_new = 1.0;
760  for(std::size_t j = 0; j < e1.size(); ++j) {
761  surface_new += surfaceFaceUV(e1[j], gf, false);
762  minq_new = std::min(e1[j]->etaShapeMeasure(), minq_new);
763  }
764 
765  v1->setParameter(0, before.x());
766  v1->setParameter(1, before.y());
767  v1->setXYZ(pbefore.x(), pbefore.y(), pbefore.z());
768  if((1. + 1.e-10) * surface_old < surface_new || minq_new < minq) {
769  return false;
770  }
771  return true;
772 }
773 
774 static bool has_none_of(std::set<MVertex *> const &touched, MVertex *const v1,
775  MVertex *const v2, MVertex *const v3, MVertex *const v4)
776 {
777  return touched.find(v1) == touched.end() &&
778  touched.find(v2) == touched.end() &&
779  touched.find(v3) == touched.end() && touched.find(v4) == touched.end();
780 }
781 
782 static bool are_all_on_surface(MVertex *const v1, MVertex *const v2,
783  MVertex *const v3, MVertex *const v4, GFace *gf)
784 {
785  return v1->onWhat() == gf && v2->onWhat() == gf && v3->onWhat() == gf &&
786  v4->onWhat() == gf;
787 }
788 
789 template <class InputIterator>
790 bool are_size_three(InputIterator iterator1, InputIterator iterator2)
791 {
792  return iterator1->second.size() == 3 && iterator2->second.size() == 3;
793 }
794 
795 static int _removeDiamonds(GFace *const gf)
796 {
797  v2t_cont adj;
799 
800  std::vector<MElement *> diamonds;
801  std::set<MVertex *> touched;
802  std::vector<MVertex *> deleted;
803 
804  std::vector<MQuadrangle *> quadrangles2;
805  quadrangles2.reserve(gf->quadrangles.size());
806 
807  for(std::size_t i = 0; i < gf->triangles.size(); i++) {
808  touched.insert(gf->triangles[i]->getVertex(0));
809  touched.insert(gf->triangles[i]->getVertex(1));
810  touched.insert(gf->triangles[i]->getVertex(2));
811  }
812 
813  for(std::size_t i = 0; i < gf->quadrangles.size(); i++) {
814  MQuadrangle *const q = gf->quadrangles[i];
815 
816  MVertex *const v1 = q->getVertex(0);
817  MVertex *const v2 = q->getVertex(1);
818  MVertex *const v3 = q->getVertex(2);
819  MVertex *const v4 = q->getVertex(3);
820 
821  if(has_none_of(touched, v1, v2, v3, v4)) {
822  auto it1 = adj.find(v1);
823  auto it2 = adj.find(v2);
824  auto it3 = adj.find(v3);
825  auto it4 = adj.find(v4);
826 
827  if(are_all_on_surface(v1, v2, v3, v4, gf) && are_size_three(it1, it3) &&
828  _tryToCollapseThatVertex(gf, it1->second, it3->second, q, v1, v3)) {
829  touched.insert(v1);
830  touched.insert(v2);
831  touched.insert(v3);
832  touched.insert(v4);
833 
834  deleted.push_back(v3);
835 
836  diamonds.push_back(q);
837  }
838  else if(are_all_on_surface(v1, v2, v3, v4, gf) &&
839  are_size_three(it2, it4) &&
840  _tryToCollapseThatVertex(gf, it2->second, it4->second, q, v2,
841  v4)) {
842  touched.insert(v1);
843  touched.insert(v2);
844  touched.insert(v3);
845  touched.insert(v4);
846 
847  deleted.push_back(v4);
848 
849  diamonds.push_back(q);
850  }
851  else {
852  quadrangles2.push_back(q);
853  }
854  }
855  else {
856  quadrangles2.push_back(q);
857  }
858  }
859  std::sort(deleted.begin(), deleted.end());
860  deleted.erase(std::unique(deleted.begin(), deleted.end()), deleted.end());
861 
862  gf->quadrangles = quadrangles2;
863 
864  std::vector<MVertex *> mesh_vertices2;
865  mesh_vertices2.reserve(gf->mesh_vertices.size());
866 
867  for(std::size_t i = 0; i < gf->mesh_vertices.size(); i++) {
868  if(!std::binary_search(deleted.begin(), deleted.end(),
869  gf->mesh_vertices[i])) {
870  mesh_vertices2.push_back(gf->mesh_vertices[i]);
871  }
872  else {
873  delete gf->mesh_vertices[i];
874  }
875  }
876  gf->mesh_vertices = mesh_vertices2;
877 
878  std::sort(diamonds.begin(), diamonds.end());
879 
880  return std::distance(diamonds.begin(),
881  std::unique(diamonds.begin(), diamonds.end()));
882 }
883 
885 {
886  std::size_t nbRemove = 0;
887  while(1) {
888  int x = _removeDiamonds(gf);
889  if(!x) break;
890  nbRemove += x;
891  }
892  Msg::Debug("%i diamond quads removed", nbRemove);
893  return nbRemove;
894 }
895 
896 struct p1p2p3 {
898 };
899 
900 static void _relocate(GFace *gf, MVertex *ver,
901  const std::vector<MElement *> &lt)
902 {
903  if(ver->onWhat() != gf) return;
904  MFaceVertex *fv = dynamic_cast<MFaceVertex *>(ver);
905  if(fv && fv->bl_data) return;
906 
907  double initu, initv;
908  ver->getParameter(0, initu);
909  ver->getParameter(1, initv);
910 
911  // compute the vertices connected to that one
912  std::map<MVertex *, SPoint2, MVertexPtrLessThan> pts;
913  for(std::size_t i = 0; i < lt.size(); i++) {
914  for(int j = 0; j < lt[i]->getNumEdges(); j++) {
915  MEdge e = lt[i]->getEdge(j);
916  SPoint2 param0, param1;
917  if(e.getVertex(0) == ver) {
918  reparamMeshEdgeOnFace(e.getVertex(0), e.getVertex(1), gf, param0,
919  param1);
920  pts[e.getVertex(1)] = param1;
921  }
922  else if(e.getVertex(1) == ver) {
923  reparamMeshEdgeOnFace(e.getVertex(0), e.getVertex(1), gf, param0,
924  param1);
925  pts[e.getVertex(0)] = param0;
926  }
927  }
928  }
929 
930  SPoint2 before(initu, initv);
931  double metric[3];
932  SPoint2 after(0, 0);
933  double COUNT = 0.0;
934  for(auto it = pts.begin(); it != pts.end(); ++it) {
935  SPoint2 adj = it->second;
936  SVector3 d(adj.x() - before.x(), adj.y() - before.y(), 0.0);
937  d.normalize();
938  buildMetric(gf, adj, metric);
939  const double F =
940  sqrt(metric[0] * d.x() * d.x() + 2 * metric[1] * d.x() * d.y() +
941  metric[2] * d.y() * d.y());
942  after += adj * F;
943  COUNT += F;
944  }
945  after *= (1.0 / COUNT);
946  double FACTOR = 1.0;
947  const int MAXITER = 5;
948  SPoint2 actual = before;
949  for(int ITER = 0; ITER < MAXITER; ITER++) {
950  SPoint2 trial = after * FACTOR + before * (1. - FACTOR);
951  bool success = _isItAGoodIdeaToMoveThatVertex(gf, lt, ver, actual, trial);
952  if(success) {
953  GPoint pt = gf->point(trial);
954  if(pt.succeeded()) {
955  actual = trial;
956  ver->setParameter(0, trial.x());
957  ver->setParameter(1, trial.y());
958  ver->x() = pt.x();
959  ver->y() = pt.y();
960  ver->z() = pt.z();
961  }
962  }
963  FACTOR /= 1.4;
964  }
965 }
966 
967 void getAllBoundaryLayerVertices(GFace *gf, std::set<MVertex *> &vs)
968 {
969  vs.clear();
970  BoundaryLayerColumns *_columns = gf->getColumns();
971  if(!_columns) return;
972  for(auto it = _columns->_data.begin(); it != _columns->_data.end(); it++) {
973  BoundaryLayerData &data = it->second;
974  for(size_t i = 0; i < data._column.size(); i++) vs.insert(data._column[i]);
975  }
976 }
977 
978 void laplaceSmoothing(GFace *gf, int niter, bool infinity_norm)
979 {
980  if((gf->triangles.size() > 0 && gf->triangles[0]->getPolynomialOrder() > 1) ||
981  (gf->quadrangles.size() > 0 &&
982  gf->quadrangles[0]->getPolynomialOrder() > 1)) {
983  Msg::Error(
984  "Surface mesh smoothing only valid for first order mesh (use the high-"
985  "order optimization tools for high-order meshes)");
986  return;
987  }
988 
989  if(!niter) return;
990 
991  Msg::Debug("laplacian smoothing ...");
992 
993  std::set<MVertex *> vs;
995  v2t_cont adj;
998  for(int i = 0; i < niter; i++) {
999  auto it = adj.begin();
1000  while(it != adj.end()) {
1001  if(vs.find(it->first) == vs.end()) {
1002  _relocate(gf, it->first, it->second);
1003  }
1004  ++it;
1005  }
1006  }
1007 }
1008 
1009 static void _recombineIntoQuads(GFace *gf, bool blossom, bool cubicGraph = 1)
1010 {
1011  if(gf->triangles.empty()) return;
1012  if(gf->compound.size()) return;
1013 
1014  std::vector<MVertex *> emb_edgeverts;
1015  {
1016  std::vector<GEdge *> emb_edges = gf->getEmbeddedEdges();
1017  auto ite = emb_edges.begin();
1018  while(ite != emb_edges.end()) {
1019  if(!(*ite)->isMeshDegenerated()) {
1020  emb_edgeverts.insert(emb_edgeverts.end(), (*ite)->mesh_vertices.begin(),
1021  (*ite)->mesh_vertices.end());
1022  if((*ite)->getBeginVertex())
1023  emb_edgeverts.insert(emb_edgeverts.end(),
1024  (*ite)->getBeginVertex()->mesh_vertices.begin(),
1025  (*ite)->getBeginVertex()->mesh_vertices.end());
1026  if((*ite)->getEndVertex())
1027  emb_edgeverts.insert(emb_edgeverts.end(),
1028  (*ite)->getEndVertex()->mesh_vertices.begin(),
1029  (*ite)->getEndVertex()->mesh_vertices.end());
1030  }
1031  ++ite;
1032  }
1033  }
1034 
1035  {
1036  std::vector<GEdge *> const &_edges = gf->edges();
1037  auto ite = _edges.begin();
1038  while(ite != _edges.end()) {
1039  if(!(*ite)->isMeshDegenerated()) {
1040  if((*ite)->isSeam(gf)) {
1041  emb_edgeverts.insert(emb_edgeverts.end(),
1042  (*ite)->mesh_vertices.begin(),
1043  (*ite)->mesh_vertices.end());
1044  if((*ite)->getBeginVertex())
1045  emb_edgeverts.insert(
1046  emb_edgeverts.end(),
1047  (*ite)->getBeginVertex()->mesh_vertices.begin(),
1048  (*ite)->getBeginVertex()->mesh_vertices.end());
1049  if((*ite)->getEndVertex())
1050  emb_edgeverts.insert(emb_edgeverts.end(),
1051  (*ite)->getEndVertex()->mesh_vertices.begin(),
1052  (*ite)->getEndVertex()->mesh_vertices.end());
1053  }
1054  }
1055  ++ite;
1056  }
1057  }
1058 
1059  // sort and erase the duplicates
1060  std::sort(emb_edgeverts.begin(), emb_edgeverts.end());
1061  emb_edgeverts.erase(std::unique(emb_edgeverts.begin(), emb_edgeverts.end()),
1062  emb_edgeverts.end());
1063 
1064  e2t_cont adj;
1065  buildEdgeToElement(gf->triangles, adj);
1066 
1067  FieldManager *fields = gf->model()->getFields();
1068  Field *cross_field = NULL;
1069  SVector3 t1;
1070 
1071  if(fields->getBackgroundField() > 0) {
1072  cross_field = fields->get(fields->getBackgroundField());
1073  if(cross_field->numComponents() != 3) { // we hae a true scaled cross fiel
1074  cross_field = NULL;
1075  }
1076  }
1077 
1078  std::vector<RecombineTriangle> pairs;
1079 
1080  std::map<MVertex *, std::pair<MElement *, MElement *> > makeGraphPeriodic;
1081 
1082  for(auto it = adj.begin(); it != adj.end(); ++it) {
1083  if(it->second.second && it->second.first->getNumVertices() == 3 &&
1084  it->second.second->getNumVertices() == 3 &&
1085  (!std::binary_search(emb_edgeverts.begin(), emb_edgeverts.end(),
1086  it->first.getVertex(0)) ||
1087  !std::binary_search(emb_edgeverts.begin(), emb_edgeverts.end(),
1088  it->first.getVertex(1)))) {
1089  pairs.push_back(RecombineTriangle(it->first, it->second.first,
1090  it->second.second, cross_field));
1091  }
1092  else if(!it->second.second && it->second.first->getNumVertices() == 3) {
1093  for(int i = 0; i < 2; i++) {
1094  MVertex *const v = it->first.getVertex(i);
1095  auto itv = makeGraphPeriodic.find(v);
1096  if(itv == makeGraphPeriodic.end()) {
1097  makeGraphPeriodic[v] =
1098  std::make_pair(it->second.first, static_cast<MElement *>(nullptr));
1099  }
1100  else {
1101  if(itv->second.first != it->second.first)
1102  itv->second.second = it->second.first;
1103  else
1104  makeGraphPeriodic.erase(itv);
1105  }
1106  }
1107  }
1108  }
1109 
1110  std::sort(pairs.begin(), pairs.end());
1111  std::set<MElement *> touched;
1112 
1113  if(blossom) {
1114 #if defined(HAVE_BLOSSOM)
1115  int ncount = gf->triangles.size();
1116  if(ncount % 2 != 0) {
1117  Msg::Warning("Cannot apply Blossom: odd number of triangles (%d) in "
1118  "surface %d",
1119  ncount, gf->tag());
1120  }
1121  else {
1122  int ecount =
1123  cubicGraph ? (pairs.size() + makeGraphPeriodic.size()) : pairs.size();
1124  Msg::Info("Blossom: %d internal %d closed", (int)pairs.size(),
1125  (int)makeGraphPeriodic.size());
1126  Msg::Debug("Perfect Match Starts %d edges %d nodes", ecount, ncount);
1127  std::map<MElement *, int> t2n;
1128  std::map<int, MElement *> n2t;
1129  for(std::size_t i = 0; i < gf->triangles.size(); ++i) {
1130  t2n[gf->triangles[i]] = i;
1131  n2t[i] = gf->triangles[i];
1132  }
1133  // do not use new[] here, blossom will free it with free() and not with
1134  // delete
1135  int *elist = (int *)malloc(sizeof(int) * 2 * ecount);
1136  int *elen = (int *)malloc(sizeof(int) * ecount);
1137 
1138  for(std::size_t i = 0; i < pairs.size(); ++i) {
1139  elist[2 * i] = t2n[pairs[i].t1];
1140  elist[2 * i + 1] = t2n[pairs[i].t2];
1141  elen[i] = (int)1000 * std::exp(-pairs[i].angle);
1142  int NB = 0;
1143  if(pairs[i].n1->onWhat()->dim() < 2) NB++;
1144  if(pairs[i].n2->onWhat()->dim() < 2) NB++;
1145  if(pairs[i].n3->onWhat()->dim() < 2) NB++;
1146  if(pairs[i].n4->onWhat()->dim() < 2) NB++;
1147  if(elen[i] > static_cast<int>(1000 * std::exp(0.1)) && NB > 2) {
1148  elen[i] = 5000;
1149  }
1150  else if(elen[i] >= 1000 && NB > 2) {
1151  elen[i] = 10000;
1152  }
1153  }
1154 
1155  if(cubicGraph) {
1156  auto itv = makeGraphPeriodic.begin();
1157  std::size_t CC = pairs.size();
1158  for(; itv != makeGraphPeriodic.end(); ++itv) {
1159  elist[2 * CC] = t2n[itv->second.first];
1160  elist[2 * CC + 1] = t2n[itv->second.second];
1161  elen[CC++] = 100000;
1162  }
1163  }
1164 
1165  double matzeit = 0.0;
1166  char MATCHFILE[256];
1167  sprintf(MATCHFILE, ".face.match");
1168  if(perfect_match(ncount, nullptr, ecount, &elist, &elen, nullptr,
1169  MATCHFILE, 0, 0, 0, 0, &matzeit)) {
1170  Msg::Error(
1171  "Perfect Match failed in quadrangulation, try something else");
1172  free(elist);
1173  pairs.clear();
1174  }
1175  else {
1176  // TEST
1177  for(int k = 0; k < elist[0]; k++) {
1178  int i1 = elist[1 + 3 * k], i2 = elist[1 + 3 * k + 1],
1179  an = elist[1 + 3 * k + 2];
1180  // FIXME !
1181  if(an == 100000 /*|| an == 1000*/) {
1182  // toProcess.push_back(std::make_pair(n2t[i1],n2t[i2]));
1183  // Msg::Warning("Extra edge found in blossom algorithm,
1184  // optimization"
1185  // "will be required");
1186  }
1187  else {
1188  MElement *t1 = n2t[i1];
1189  MElement *t2 = n2t[i2];
1190  touched.insert(t1);
1191  touched.insert(t2);
1192  MVertex *other = nullptr;
1193  for(int i = 0; i < 3; i++) {
1194  if(t1->getVertex(0) != t2->getVertex(i) &&
1195  t1->getVertex(1) != t2->getVertex(i) &&
1196  t1->getVertex(2) != t2->getVertex(i)) {
1197  other = t2->getVertex(i);
1198  break;
1199  }
1200  }
1201  int start = 0;
1202  for(int i = 0; i < 3; i++) {
1203  if(t2->getVertex(0) != t1->getVertex(i) &&
1204  t2->getVertex(1) != t1->getVertex(i) &&
1205  t2->getVertex(2) != t1->getVertex(i)) {
1206  start = i;
1207  break;
1208  }
1209  }
1210  MQuadrangle *q = new MQuadrangle(
1211  t1->getVertex(start), t1->getVertex((start + 1) % 3), other,
1212  t1->getVertex((start + 2) % 3));
1213  gf->quadrangles.push_back(q);
1214  }
1215  }
1216  free(elist);
1217  pairs.clear();
1218  Msg::Debug("Perfect Match Succeeded in Quadrangulation (%g sec)",
1219  matzeit);
1220  }
1221  }
1222 #else
1223  Msg::Warning("Gmsh should be compiled with the Blossom IV code and "
1224  " CONCORDE in order to allow the Blossom optimization");
1225 #endif
1226  }
1227 
1228  // simple greedy recombination
1229  auto itp = pairs.begin();
1230  while(itp != pairs.end()) {
1231  if(itp->angle < gf->meshAttributes.recombineAngle) {
1232  MElement *t1 = itp->t1;
1233  MElement *t2 = itp->t2;
1234  if(touched.find(t1) == touched.end() &&
1235  touched.find(t2) == touched.end()) {
1236  touched.insert(t1);
1237  touched.insert(t2);
1238  int orientation = 0;
1239  for(int i = 0; i < 3; i++) {
1240  if(t1->getVertex(i) == itp->n1) {
1241  if(t1->getVertex((i + 1) % 3) == itp->n2)
1242  orientation = 1;
1243  else
1244  orientation = -1;
1245  break;
1246  }
1247  }
1248  gf->quadrangles.push_back(
1249  new MQuadrangle(itp->n1, orientation < 0 ? itp->n3 : itp->n4, itp->n2,
1250  orientation < 0 ? itp->n4 : itp->n3));
1251  }
1252  }
1253  ++itp;
1254  }
1255 
1256  std::vector<MTriangle *> triangles2;
1257  triangles2.reserve(gf->triangles.size());
1258  for(std::size_t i = 0; i < gf->triangles.size(); i++) {
1259  if(touched.find(gf->triangles[i]) == touched.end()) {
1260  triangles2.push_back(gf->triangles[i]);
1261  }
1262  else {
1263  delete gf->triangles[i];
1264  }
1265  }
1266  gf->triangles = triangles2;
1267 }
1268 
1269 static double printStats(GFace *gf, const char *message)
1270 {
1271  int nbBad = 0;
1272  int nbInv = 0;
1273  double Qav = 0;
1274  double Qmin = 1;
1275  for(std::size_t i = 0; i < gf->quadrangles.size(); i++) {
1276  double Q = gf->quadrangles[i]->etaShapeMeasure();
1277  if(Q <= 0.0) nbInv++;
1278  if(Q <= 0.1) nbBad++;
1279  Qav += Q;
1280  Qmin = std::min(Q, Qmin);
1281  }
1282  Msg::Info(
1283  "%s: %d quads, %d triangles, %d invalid quads, %d quads with Q < 0.1, "
1284  "avg Q = %g, min Q = %g",
1285  message, gf->quadrangles.size(), gf->triangles.size(), nbInv, nbBad,
1286  Qav / gf->quadrangles.size(), Qmin);
1287  return Qmin;
1288 }
1289 
1290 // The topological optimization routines assume that a full topology of the
1291 // model exists. When reading multi-surface STL files for example, if
1292 // CreateTopology or ReclassifySurfaces is not called, quads can have nodes
1293 // owned by an adjacent surface. Since the topological optimization routines
1294 // remove nodes, this will produce an invalide model mesh (and crash).
1296 {
1297  for(auto it = m->firstFace(); it != m->lastFace(); it++) {
1298  GFace *gf = *it;
1299  for(std::size_t j = 0; j < gf->getNumMeshElements(); j++) {
1300  MElement *e = gf->getMeshElement(j);
1301  for(std::size_t k = 0; k < e->getNumVertices(); k++) {
1302  GEntity *ge = e->getVertex(k)->onWhat();
1303  if(!ge) return false;
1304  if(ge->dim() == 2 && ge != gf) return false;
1305  }
1306  }
1307  }
1308  return true;
1309 }
1310 
1311 void recombineIntoQuads(GFace *gf, bool blossom, int topologicalOptiPasses,
1312  bool nodeRepositioning, double minqual)
1313 {
1314  double t1 = Cpu(), w1 = TimeOfDay();
1315 
1316  bool haveParam = (gf->geomType() != GEntity::DiscreteSurface);
1317  bool debug = (Msg::GetVerbosity() == 99);
1318 
1319  if(debug) gf->model()->writeMSH("recombine_0before.msh");
1320 
1321  _recombineIntoQuads(gf, blossom);
1322 
1323  if(debug) gf->model()->writeMSH("recombine_1raw.msh");
1324 
1325  if(haveParam && nodeRepositioning) {
1326  RelocateVertices(gf, CTX::instance()->mesh.nbSmoothing);
1327  if(debug) gf->model()->writeMSH("recombine_2smoothed.msh");
1328  }
1329 
1330 // FIXME: not thread-safe
1331 #pragma omp critical
1332  {
1333  if(topologicalOptiPasses > 0) {
1334  if(!_isModelOkForTopologicalOpti(gf->model())) {
1335  Msg::Info
1336  ("Skipping topological optimization - mesh topology is not complete");
1337  }
1338  else {
1339  int iter = 0, nbTwoQuadNodes = 1, nbDiamonds = 1;
1340  while(nbTwoQuadNodes || nbDiamonds) {
1341  Msg::Debug("Topological optimization of quad mesh: pass %d", iter);
1342  nbTwoQuadNodes = removeTwoQuadsNodes(gf);
1343  // removeDiamonds uses the parametrization or searches for closest point
1344  nbDiamonds = haveParam ? removeDiamonds(gf) : 0;
1345  if(haveParam && nodeRepositioning)
1346  RelocateVertices(gf, CTX::instance()->mesh.nbSmoothing);
1347  iter++;
1348  if(iter > topologicalOptiPasses) break;
1349  }
1350  if(debug) gf->model()->writeMSH("recombine_3topo.msh");
1351  }
1352  }
1353  }
1354 
1355  // re-split bad quads into triangles
1356  if(minqual > 0)
1357  quadsToTriangles(gf, minqual);
1358 
1359  if(debug) gf->model()->writeMSH("recombine_4quality.msh");
1360 
1361  if(haveParam && nodeRepositioning)
1362  RelocateVertices(gf, CTX::instance()->mesh.nbSmoothing);
1363 
1364  double t2 = Cpu(), w2 = TimeOfDay();
1365 
1366  char name[256];
1367  sprintf(name, "%s recombination completed (Wall %gs, CPU %gs)",
1368  blossom ? "Blossom" : "Simple", w2 - w1, t2 - t1);
1369  printStats(gf, name);
1370 
1371  if(debug) gf->model()->writeMSH("recombine_5final.msh");
1372 }
1373 
1374 void quadsToTriangles(GFace *gf, double minqual)
1375 {
1376  std::vector<MQuadrangle *> qds;
1377  std::map<MElement *, std::pair<MElement *, MElement *> > change;
1378  for(std::size_t i = 0; i < gf->quadrangles.size(); i++) {
1379  MQuadrangle *q = gf->quadrangles[i];
1380  if(q->etaShapeMeasure() < minqual + 1e-12) {
1381  MTriangle *t11 =
1382  new MTriangle(q->getVertex(0), q->getVertex(1), q->getVertex(2));
1383  MTriangle *t12 =
1384  new MTriangle(q->getVertex(2), q->getVertex(3), q->getVertex(0));
1385  MTriangle *t21 =
1386  new MTriangle(q->getVertex(1), q->getVertex(2), q->getVertex(3));
1387  MTriangle *t22 =
1388  new MTriangle(q->getVertex(3), q->getVertex(0), q->getVertex(1));
1389  double qual1 =
1390  std::min(t11->gammaShapeMeasure(), t12->gammaShapeMeasure());
1391  double qual2 =
1392  std::min(t21->gammaShapeMeasure(), t22->gammaShapeMeasure());
1393  double ori2 = dot(t21->getFace(0).normal(), t22->getFace(0).normal());
1394  // choose (t11, t12) if it leads to the best quality OR if choosing (t21,
1395  // t22) would revert the orientation (which can happen if q is not convex)
1396  if(qual1 > qual2 || ori2 < 0) {
1397  gf->triangles.push_back(t11);
1398  gf->triangles.push_back(t12);
1399  change[q] = std::make_pair(t11, t12);
1400  delete t21;
1401  delete t22;
1402  }
1403  else {
1404  gf->triangles.push_back(t21);
1405  gf->triangles.push_back(t22);
1406  change[q] = std::make_pair(t21, t22);
1407  delete t11;
1408  delete t12;
1409  }
1410  delete q;
1411  }
1412  else {
1413  qds.push_back(q);
1414  }
1415  }
1416  gf->quadrangles = qds;
1417 
1418  BoundaryLayerColumns *_columns = gf->getColumns();
1419  if(!_columns) return;
1420 
1421  // Update the data struture for boundary layers
1422  // WARNING: First quad element is replaced by one of the two triangles,
1423  // without taking care of if it is the truly the first one or not.
1424 
1425  // std::map<MElement*,MElement*> _toFirst;
1426  std::map<MElement *, std::vector<MElement *> > newElemColumns;
1427 
1428  for(auto it = _columns->_elemColumns.begin();
1429  it != _columns->_elemColumns.end(); it++) {
1430  MElement *firstEl = it->first;
1431  auto it2 = change.find(firstEl);
1432  if(it2 != change.end()) firstEl = it2->second.first;
1433  // it2->second.first may be the one that touch boundary or not...
1434 
1435  std::vector<MElement *> &newColumn = newElemColumns[firstEl];
1436  std::vector<MElement *> &oldColumn = it->second;
1437 
1438  for(std::size_t i = 0; i < oldColumn.size(); i++) {
1439  MElement *oldEl = oldColumn[i];
1440  it2 = change.find(oldEl);
1441  if(it2 == change.end()) {
1442  newColumn.push_back(oldEl);
1443  _columns->_toFirst[oldEl] = firstEl;
1444  }
1445  else {
1446  newColumn.push_back(it2->second.first);
1447  newColumn.push_back(it2->second.second);
1448  _columns->_toFirst.erase(oldEl);
1449  _columns->_toFirst[it2->second.first] = firstEl;
1450  _columns->_toFirst[it2->second.second] = firstEl;
1451  }
1452  }
1453  }
1454  _columns->_elemColumns = newElemColumns;
1455 }
1456 
1458 {
1459  if(!CTX::instance()->mesh.recombineAll && !gf->meshAttributes.recombine) {
1460  int numSplit = 0;
1461  int numNoSplit = 0;
1462  FieldManager *fields = gf->model()->getFields();
1463  int n = fields->getNumBoundaryLayerFields();
1464  for(int i = 0; i < n; ++i) {
1465  Field *bl_field = fields->get(fields->getBoundaryLayerField(i));
1466  if(bl_field == nullptr) continue;
1467  BoundaryLayerField *blf = dynamic_cast<BoundaryLayerField *>(bl_field);
1468  if(blf->iRecombine)
1469  ++numNoSplit;
1470  else
1471  ++numSplit;
1472  }
1473 
1474  if(numSplit > 0 && numNoSplit > 0)
1475  Msg::Warning("Cannot generate simplicial and non-simplicial boundary "
1476  "layers together. Keeping them non-simplicial...");
1477  if(numNoSplit == 0 && numSplit > 0) quadsToTriangles(gf, 10000);
1478  }
1479 }
parametricCoordinates
static void parametricCoordinates(MElement *t, GFace *gf, double u[4], double v[4], MVertex *close=nullptr)
Definition: meshGFaceOptimize.cpp:472
buildVertexToElement
void buildVertexToElement(std::vector< T * > const &elements, v2t_cont &adj)
Definition: meshGFaceOptimize.h:38
crossprod
SVector3 crossprod(const SVector3 &a, const SVector3 &b)
Definition: SVector3.h:150
RecombineTriangle::quality
double quality
Definition: meshGFaceOptimize.h:111
GPoint::succeeded
bool succeeded() const
Definition: GPoint.h:63
equivalentTriangle::_v
MVertex * _v[3]
Definition: meshGFaceOptimize.cpp:293
MTriangle.h
qualityMeasures.h
TimeOfDay
double TimeOfDay()
Definition: OS.cpp:399
_relocate
static void _relocate(GFace *gf, MVertex *ver, const std::vector< MElement * > &lt)
Definition: meshGFaceOptimize.cpp:900
MTriangle::getFace
virtual MFace getFace(int num) const
Definition: MTriangle.h:91
GFace::edges
virtual std::vector< GEdge * > const & edges() const
Definition: GFace.h:121
Field.h
buildListOfEdgeAngle
void buildListOfEdgeAngle(e2t_cont adj, std::vector< edge_angle > &edges_detected, std::vector< edge_angle > &edges_lonly)
Definition: meshGFaceOptimize.cpp:455
equivalentTriangle
Definition: meshGFaceOptimize.cpp:291
MEdge
Definition: MEdge.h:14
RecombineTriangle::n2
MVertex * n2
Definition: meshGFaceOptimize.h:112
dot
double dot(const SVector3 &a, const SMetric3 &m, const SVector3 &b)
Definition: STensor3.h:71
buildEdgeToTriangle
void buildEdgeToTriangle(std::vector< MTriangle * > &tris, e2t_cont &adj)
Definition: meshGFaceOptimize.cpp:443
splitElementsInBoundaryLayerIfNeeded
void splitElementsInBoundaryLayerIfNeeded(GFace *gf)
Definition: meshGFaceOptimize.cpp:1457
Msg::GetVerbosity
static int GetVerbosity()
Definition: GmshMessage.cpp:254
GPoint::y
double y() const
Definition: GPoint.h:22
GFace::recombine
int recombine
Definition: GFace.h:344
GFace.h
distance
double distance(MVertex *v1, MVertex *v2)
Definition: MVertex.h:245
_tryToCollapseThatVertex
static bool _tryToCollapseThatVertex(GFace *gf, std::vector< MElement * > &e1, std::vector< MElement * > &e2, MElement *q, MVertex *v1, MVertex *v2)
Definition: meshGFaceOptimize.cpp:662
splitEquivalentTriangles
void splitEquivalentTriangles(GFace *gf, bidimMeshData &data)
Definition: meshGFaceOptimize.cpp:343
MTri3::tri
MTriangle * tri() const
Definition: meshGFaceDelaunayInsertion.h:105
GFace::getEmbeddedVertices
std::vector< GVertex * > getEmbeddedVertices(bool force=false) const
Definition: GFace.cpp:355
GFace
Definition: GFace.h:33
GFace::triangles
std::vector< MTriangle * > triangles
Definition: GFace.h:428
MQuadrangle::getVertex
virtual MVertex * getVertex(int num)
Definition: MQuadrangle.h:64
Msg::Info
static void Info(const char *fmt,...)
Definition: GmshMessage.cpp:587
GEntity::model
GModel * model() const
Definition: GEntity.h:277
F
#define F
Definition: DefaultOptions.h:23
angle
double angle(const SVector3 &a, const SVector3 &b)
Definition: SVector3.h:157
SPoint2
Definition: SPoint2.h:12
quadsToTriangles
void quadsToTriangles(GFace *gf, double minqual)
Definition: meshGFaceOptimize.cpp:1374
OS.h
_recombineIntoQuads
static void _recombineIntoQuads(GFace *gf, bool blossom, bool cubicGraph=1)
Definition: meshGFaceOptimize.cpp:1009
Msg::Debug
static void Debug(const char *fmt,...)
Definition: GmshMessage.cpp:752
p1p2p3
Definition: meshGFaceOptimize.cpp:896
bidimMeshData::equivalence
std::map< MVertex *, MVertex * > * equivalence
Definition: meshGFaceDelaunayInsertion.h:27
MVertex
Definition: MVertex.h:24
MTriangle::gammaShapeMeasure
virtual double gammaShapeMeasure()
Definition: MTriangle.cpp:115
a4
#define a4
Definition: GaussQuadratureTet.cpp:11
RecombineTriangle
Definition: meshGFaceOptimize.h:108
bidimMeshData
Definition: meshGFaceDelaunayInsertion.h:23
Msg::Warning
static void Warning(const char *fmt,...)
Definition: GmshMessage.cpp:543
Msg::Error
static void Error(const char *fmt,...)
Definition: GmshMessage.cpp:482
MVertex::z
double z() const
Definition: MVertex.h:62
bidimMeshData::addVertex
void addVertex(MVertex *mv, double u, double v, double size, double sizeBGM)
Definition: meshGFaceDelaunayInsertion.h:31
reparamMeshVertexOnFace
bool reparamMeshVertexOnFace(MVertex const *v, const GFace *gf, SPoint2 &param, bool onSurface, bool failOnSeam, int dir)
Definition: MVertex.cpp:522
edge_angle::angle
double angle
Definition: meshGFaceOptimize.h:24
SPoint3
Definition: SPoint3.h:14
MFace::normal
SVector3 normal() const
Definition: MFace.cpp:204
GFace::meshAttributes
struct GFace::@18 meshAttributes
GFace::point
virtual GPoint point(double par1, double par2) const =0
SVector3
Definition: SVector3.h:16
meshGFaceOptimize.h
printStats
static double printStats(GFace *gf, const char *message)
Definition: meshGFaceOptimize.cpp:1269
edge_angle::edge_angle
edge_angle(MVertex *_v1, MVertex *_v2, MElement *t1, MElement *t2)
Definition: meshGFaceOptimize.cpp:103
equivalentTriangle::_t
MTriangle * _t
Definition: meshGFaceOptimize.cpp:292
MTriangle::getVertex
virtual MVertex * getVertex(int num)
Definition: MTriangle.h:62
MVertex::onWhat
GEntity * onWhat() const
Definition: MVertex.h:82
SVector3.h
computeEquivalentTriangles
bool computeEquivalentTriangles(GFace *gf, std::map< MVertex *, MVertex * > *equivalence)
Definition: meshGFaceOptimize.cpp:317
Field::numComponents
virtual int numComponents() const
Definition: Field.h:114
BoundaryLayerColumns
Definition: boundaryLayersData.h:51
transferDataStructure
void transferDataStructure(GFace *gf, std::set< MTri3 *, compareTri3Ptr > &AllTris, bidimMeshData &data)
Definition: meshGFaceOptimize.cpp:348
GmshMessage.h
MLine.h
v2t_cont
std::map< MVertex *, std::vector< MElement * >, MVertexPtrLessThan > v2t_cont
Definition: meshGFaceOptimize.h:31
BoundaryLayerColumns::_elemColumns
std::map< MElement *, std::vector< MElement * > > _elemColumns
Definition: boundaryLayersData.h:57
w1
const double w1
Definition: GaussQuadratureHex.cpp:18
GEntity
Definition: GEntity.h:31
connectTriangles
void connectTriangles(std::list< MTri3 * > &l)
Definition: meshGFaceDelaunayInsertion.cpp:543
GPoint
Definition: GPoint.h:13
GFace::closestPoint
virtual GPoint closestPoint(const SPoint3 &queryPoint, const double initialGuess[2]) const
Definition: GFace.cpp:1323
buildMetric
void buildMetric(GFace *gf, double *uv, double *metric)
Definition: meshGFaceDelaunayInsertion.cpp:332
MElement::getNumVertices
virtual std::size_t getNumVertices() const =0
getAllBoundaryLayerVertices
void getAllBoundaryLayerVertices(GFace *gf, std::set< MVertex * > &vs)
Definition: meshGFaceOptimize.cpp:967
Extend1dMeshIn2dSurfaces
bool Extend1dMeshIn2dSurfaces(GFace *gf)
Definition: BackgroundMeshTools.cpp:339
GFace::quadrangles
std::vector< MQuadrangle * > quadrangles
Definition: GFace.h:429
RecombineTriangle::RecombineTriangle
RecombineTriangle(const MEdge &me, MElement *_t1, MElement *_t2, Field *f)
Definition: meshGFaceOptimize.cpp:37
_isItAGoodIdeaToMoveThatVertex
static bool _isItAGoodIdeaToMoveThatVertex(GFace *gf, const std::vector< MElement * > &e1, MVertex *v1, const SPoint2 &before, const SPoint2 &after)
Definition: meshGFaceOptimize.cpp:736
are_size_three
bool are_size_three(InputIterator iterator1, InputIterator iterator2)
Definition: meshGFaceOptimize.cpp:790
_removeDiamonds
static int _removeDiamonds(GFace *const gf)
Definition: meshGFaceOptimize.cpp:795
GPoint::z
double z() const
Definition: GPoint.h:23
CTX::instance
static CTX * instance()
Definition: Context.cpp:122
MElement::getVertex
virtual const MVertex * getVertex(int num) const =0
SPoint3::x
double x(void) const
Definition: SPoint3.h:125
GModel::lastFace
fiter lastFace()
Definition: GModel.h:359
GEdge.h
MTri3
Definition: meshGFaceDelaunayInsertion.h:78
MVertex::setParameter
virtual bool setParameter(int i, double par)
Definition: MVertex.h:102
BoundaryLayerColumns::_data
std::multimap< MVertex *, BoundaryLayerData > _data
Definition: boundaryLayersData.h:59
MEdge::getVertex
MVertex * getVertex(std::size_t i) const
Definition: MEdge.h:39
GPoint::u
double u() const
Definition: GPoint.h:27
_tryToCollapseThatVertex2
static bool _tryToCollapseThatVertex2(GFace *gf, std::vector< MElement * > &e1, std::vector< MElement * > &e2, MElement *q, MVertex *v1, MVertex *v2)
Definition: meshGFaceOptimize.cpp:601
GEntity::mesh_vertices
std::vector< MVertex * > mesh_vertices
Definition: GEntity.h:56
GFace::recombineAngle
double recombineAngle
Definition: GFace.h:346
BoundaryLayerData
Definition: boundaryLayersData.h:24
MVertex.h
a1
const double a1
Definition: GaussQuadratureHex.cpp:10
setLcsInit
static void setLcsInit(MTriangle *t, std::map< MVertex *, double > &vSizes)
Definition: meshGFaceOptimize.cpp:141
Numeric.h
FieldManager::get
Field * get(int id)
Definition: Field.cpp:74
GModel
Definition: GModel.h:44
RecombineTriangle::angle
double angle
Definition: meshGFaceOptimize.h:110
Cpu
double Cpu()
Definition: OS.cpp:366
reparamMeshEdgeOnFace
bool reparamMeshEdgeOnFace(MVertex *v1, MVertex *v2, GFace *gf, SPoint2 &param1, SPoint2 &param2)
Definition: MVertex.cpp:474
BGM_MeshSize
double BGM_MeshSize(GEntity *ge, double U, double V, double X, double Y, double Z)
Definition: BackgroundMeshTools.cpp:255
MVertex::setXYZ
void setXYZ(double x, double y, double z)
Definition: MVertex.h:68
equivalentTriangle::operator<
bool operator<(const equivalentTriangle &other) const
Definition: meshGFaceOptimize.cpp:307
MTriangle::reverse
virtual void reverse()
Definition: MTriangle.h:120
buildEdgeToElement
void buildEdgeToElement(std::vector< T * > &elements, e2t_cont &adj)
Definition: meshGFaceOptimize.cpp:417
FieldManager
Definition: Field.h:145
GEntity::geomType
virtual GeomType geomType() const
Definition: GEntity.h:238
GModel::firstFace
fiter firstFace()
Definition: GModel.h:355
e2t_cont
std::map< MEdge, std::pair< MElement *, MElement * >, MEdgeLessThan > e2t_cont
Definition: meshGFaceOptimize.h:35
SVector3::norm
double norm() const
Definition: SVector3.h:33
SPoint3::y
double y(void) const
Definition: SPoint3.h:127
RelocateVertices
void RelocateVertices(GFace *gf, int niter, double tol)
Definition: meshRelocateVertex.cpp:410
GEntity::compound
std::vector< GEntity * > compound
Definition: GEntity.h:59
RecombineTriangle::t2
MElement * t2
Definition: meshGFaceOptimize.h:109
prosca
double prosca(double const a[3], double const b[3])
Definition: Numeric.h:112
GModel::getFields
FieldManager * getFields()
Definition: GModel.h:325
MElement
Definition: MElement.h:30
angle3Vertices
double angle3Vertices(const MVertex *p1, const MVertex *p2, const MVertex *p3)
Definition: MVertex.cpp:16
GEntity::tag
int tag() const
Definition: GEntity.h:280
MFaceVertex
Definition: MVertex.h:168
BoundaryLayerField
Definition: Field.h:191
bidimMeshData::internalEdges
std::set< MEdge, MEdgeLessThan > internalEdges
Definition: meshGFaceDelaunayInsertion.h:29
Field
Definition: Field.h:103
BoundaryLayerField::iRecombine
int iRecombine
Definition: Field.h:206
prodve
void prodve(double a[3], double b[3], double c[3])
Definition: Numeric.h:105
bidimMeshData::getIndex
int getIndex(MVertex *mv)
Definition: meshGFaceDelaunayInsertion.h:51
BoundaryLayerData::_column
std::vector< MVertex * > _column
Definition: boundaryLayersData.h:26
SVector3::x
double x(void) const
Definition: SVector3.h:30
a2
const double a2
Definition: GaussQuadratureHex.cpp:12
_removeTwoQuadsNodes
static int _removeTwoQuadsNodes(GFace *gf)
Definition: meshGFaceOptimize.cpp:513
buildEdgeToElements
void buildEdgeToElements(std::vector< MElement * > &tris, e2t_cont &adj)
Definition: meshGFaceOptimize.cpp:449
has_none_of
static bool has_none_of(std::set< MVertex * > const &touched, MVertex *const v1, MVertex *const v2, MVertex *const v3, MVertex *const v4)
Definition: meshGFaceOptimize.cpp:774
GFace::getMeshElement
MElement * getMeshElement(std::size_t index) const
Definition: GFace.cpp:234
MTriangle
Definition: MTriangle.h:26
GEntity::DiscreteSurface
@ DiscreteSurface
Definition: GEntity.h:117
GFace::getColumns
BoundaryLayerColumns * getColumns()
Definition: GFace.h:453
GModel::writeMSH
int writeMSH(const std::string &name, double version=2.2, bool binary=false, bool saveAll=false, bool saveParametric=false, double scalingFactor=1.0, int elementStartNum=0, int saveSinglePartition=0, bool append=false)
Definition: GModelIO_MSH.cpp:76
FieldManager::getBackgroundField
int getBackgroundField()
Definition: Field.h:178
GFace::getEmbeddedEdges
std::vector< GEdge * > getEmbeddedEdges(bool force=false) const
Definition: GFace.cpp:362
p1p2p3::p2
MVertex * p2
Definition: meshGFaceOptimize.cpp:897
recombineIntoQuads
void recombineIntoQuads(GFace *gf, bool blossom, int topologicalOptiPasses, bool nodeRepositioning, double minqual)
Definition: meshGFaceOptimize.cpp:1311
bidimMeshData::equivalent
MVertex * equivalent(MVertex *v1) const
Definition: meshGFaceDelaunayInsertion.h:56
BoundaryLayerColumns::_toFirst
std::map< MElement *, MElement * > _toFirst
Definition: boundaryLayersData.h:56
MVertex::getParameter
virtual bool getParameter(int i, double &par) const
Definition: MVertex.h:97
SPoint2::x
double x(void) const
Definition: SPoint2.h:86
surfaceFaceUV
double surfaceFaceUV(MElement *t, GFace *gf, bool maximal=true)
Definition: meshGFaceOptimize.cpp:487
FieldManager::getBoundaryLayerField
int getBoundaryLayerField(int i)
Definition: Field.h:183
Context.h
setLcs
static void setLcs(MTriangle *t, std::map< MVertex *, double > &vSizes, bidimMeshData &data)
Definition: meshGFaceOptimize.cpp:153
RecombineTriangle::n1
MVertex * n1
Definition: meshGFaceOptimize.h:112
removeDiamonds
int removeDiamonds(GFace *gf)
Definition: meshGFaceOptimize.cpp:884
SVector3::y
double y(void) const
Definition: SVector3.h:31
MTri3::isDeleted
bool isDeleted() const
Definition: meshGFaceDelaunayInsertion.h:88
laplaceSmoothing
void laplaceSmoothing(GFace *gf, int niter, bool infinity_norm)
Definition: meshGFaceOptimize.cpp:978
GVertex.h
MQuadrangle.h
computeEquivalences
void computeEquivalences(GFace *gf, bidimMeshData &data)
Definition: meshGFaceOptimize.cpp:271
MFaceVertex::bl_data
MVertexBoundaryLayerData * bl_data
Definition: MVertex.h:173
normal3points
void normal3points(double x0, double y0, double z0, double x1, double y1, double z1, double x2, double y2, double z2, double n[3])
Definition: Numeric.cpp:76
FieldManager::getNumBoundaryLayerFields
int getNumBoundaryLayerFields()
Definition: Field.h:179
MQuadrangle::etaShapeMeasure
virtual double etaShapeMeasure()
Definition: MQuadrangle.cpp:300
SPoint3::z
double z(void) const
Definition: SPoint3.h:129
GPoint::v
double v() const
Definition: GPoint.h:28
BackgroundMeshTools.h
GModel.h
p1p2p3::p1
MVertex * p1
Definition: meshGFaceOptimize.cpp:897
MVertex::y
double y() const
Definition: MVertex.h:61
RecombineTriangle::t1
MElement * t1
Definition: meshGFaceOptimize.h:109
RecombineTriangle::n3
MVertex * n3
Definition: meshGFaceOptimize.h:112
bidimMeshData::Vs
std::vector< double > Vs
Definition: meshGFaceDelaunayInsertion.h:25
are_all_on_surface
static bool are_all_on_surface(MVertex *const v1, MVertex *const v2, MVertex *const v3, MVertex *const v4, GFace *gf)
Definition: meshGFaceOptimize.cpp:782
norme
double norme(double a[3])
Definition: Numeric.h:123
GFace::getNumMeshElements
std::size_t getNumMeshElements() const
Definition: GFace.cpp:181
bidimMeshData::Us
std::vector< double > Us
Definition: meshGFaceDelaunayInsertion.h:25
GEntity::dim
virtual int dim() const
Definition: GEntity.h:196
SPoint3.h
GPoint::x
double x() const
Definition: GPoint.h:21
equivalentTriangle::equivalentTriangle
equivalentTriangle(MTriangle *t, std::map< MVertex *, MVertex * > *equivalence)
Definition: meshGFaceOptimize.cpp:294
MElement::writePOS
virtual void writePOS(FILE *fp, bool printElementary, bool printElementNumber, bool printSICN, bool printSIGE, bool printGamma, bool printDisto, double scalingFactor=1.0, int elementary=1)
Definition: MElement.cpp:1515
c1
const double c1
Definition: GaussQuadratureHex.cpp:16
bidimMeshData::vSizesBGM
std::vector< double > vSizesBGM
Definition: meshGFaceDelaunayInsertion.h:25
_isModelOkForTopologicalOpti
static bool _isModelOkForTopologicalOpti(GModel *m)
Definition: meshGFaceOptimize.cpp:1295
edge_angle
Definition: meshGFaceOptimize.h:22
MQuadrangle
Definition: MQuadrangle.h:26
buildMeshGenerationDataStructures
bool buildMeshGenerationDataStructures(GFace *gf, std::set< MTri3 *, compareTri3Ptr > &AllTris, bidimMeshData &data)
Definition: meshGFaceOptimize.cpp:174
bidimMeshData::vSizes
std::vector< double > vSizes
Definition: meshGFaceDelaunayInsertion.h:25
meshRelocateVertex.h
RecombineTriangle::n4
MVertex * n4
Definition: meshGFaceOptimize.h:112
MVertex::x
double x() const
Definition: MVertex.h:60
SVector3::normalize
double normalize()
Definition: SVector3.h:38
SPoint2::y
double y(void) const
Definition: SPoint2.h:88
removeTwoQuadsNodes
int removeTwoQuadsNodes(GFace *gf)
Definition: meshGFaceOptimize.cpp:589