gmsh-TingyuanDoc  0.1
An Open-Source Timing-driven Analytical Mixed-size FPGA Placer
meshGRegionDelaunayInsertion.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 <set>
7 #include <map>
8 #include <algorithm>
9 #include <queue>
10 #include "GmshMessage.h"
11 #include "robustPredicates.h"
12 #include "OS.h"
13 #include "meshGRegion.h"
16 #include "GModel.h"
17 #include "GRegion.h"
18 #include "MTriangle.h"
19 #include "Numeric.h"
20 #include "Context.h"
21 #include "delaunay3d.h"
22 #include "MEdge.h"
23 #include "MLine.h"
24 #include "ExtrudeParams.h"
25 
26 int MTet4::radiusNorm = 2;
27 
28 #ifdef DEBUG_BOUNDARY_RECOVERY
29 
30 static void testIfBoundaryIsRecovered(GRegion *gr)
31 {
32  std::vector<GEdge *> const &e = gr->edges();
33  std::vector<GFace *> f = gr->faces();
34 
35  std::map<MEdge, GEdge *, MEdgeLessThan> edges;
36  std::map<MFace, GFace *, MFaceLessThan> faces;
37 
38  auto it = e.begin();
39  auto itf = f.begin();
40  for(; it != e.end(); ++it) {
41  for(std::size_t i = 0; i < (*it)->lines.size(); ++i) {
42  if(distance((*it)->lines[i]->getVertex(0),
43  (*it)->lines[i]->getVertex(1)) > 1.e-12)
44  edges.insert(std::make_pair(
45  MEdge((*it)->lines[i]->getVertex(0), (*it)->lines[i]->getVertex(1)),
46  *it));
47  }
48  }
49  for(; itf != f.end(); ++itf) {
50  for(std::size_t i = 0; i < (*itf)->triangles.size(); ++i) {
51  faces.insert(std::make_pair(MFace((*itf)->triangles[i]->getVertex(0),
52  (*itf)->triangles[i]->getVertex(1),
53  (*itf)->triangles[i]->getVertex(2)),
54  *itf));
55  }
56  }
57  Msg::Info("Searching for %d mesh edges and %d mesh faces among %d elements "
58  "in region %d",
59  edges.size(), faces.size(), gr->getNumMeshElements(), gr->tag());
60  for(std::size_t k = 0; k < gr->getNumMeshElements(); k++) {
61  for(int j = 0; j < gr->getMeshElement(k)->getNumEdges(); j++) {
62  edges.erase(gr->getMeshElement(k)->getEdge(j));
63  }
64  for(int j = 0; j < gr->getMeshElement(k)->getNumFaces(); j++) {
65  faces.erase(gr->getMeshElement(k)->getFace(j));
66  }
67  }
68  if(edges.empty() && faces.empty()) {
69  Msg::Info("All edges and faces are present in the initial mesh");
70  }
71  else {
72  Msg::Error("All edges and faces are not present in the initial mesh");
73  }
74 }
75 
76 #endif
77 
79  std::vector<std::vector<MEdge> > _hash;
80  std::size_t _size, _size_obj;
81 
82  edgeContainerB(std::size_t N = 1000000)
83  : _hash(N > 0 ? N : 1), _size(0), _size_obj(sizeof(MEdge))
84  {
85  }
86 
87  std::size_t H(const MEdge &e) const
88  {
89  const std::size_t h = ((std::size_t)e.getSortedVertex(0));
90  return (h / _size_obj) % _hash.size();
91  }
92 
93  bool find(const MEdge &e) const
94  {
95  const std::vector<MEdge> &v = _hash[H(e)];
96  return std::find(v.begin(), v.end(), e) != v.end();
97  }
98 
99  bool empty() const { return _size == 0; }
100 
101  bool addNewEdge(const MEdge &e)
102  {
103  std::vector<MEdge> &v = _hash[H(e)];
104 
105  if(std::find(v.begin(), v.end(), e) != v.end()) return false;
106 
107  v.push_back(e);
108  _size++;
109 
110  return true;
111  }
112 };
113 
114 static void
116  std::set<MEdge, MEdgeLessThan> &allEmbeddedEdges)
117 {
118  std::vector<GEdge *> const &e = gr->embeddedEdges();
119  for(auto it = e.begin(); it != e.end(); ++it) {
120  for(std::size_t i = 0; i < (*it)->lines.size(); i++) {
121  allEmbeddedEdges.insert(
122  MEdge((*it)->lines[i]->getVertex(0), (*it)->lines[i]->getVertex(1)));
123  }
124  }
125 }
126 
127 static void createAllEmbeddedEdges(GRegion *gr, edgeContainerB &embedded)
128 {
129  std::vector<GEdge *> const &e = gr->embeddedEdges();
130  for(auto it = e.begin(); it != e.end(); ++it) {
131  for(std::size_t i = 0; i < (*it)->lines.size(); i++) {
132  embedded.addNewEdge(
133  MEdge((*it)->lines[i]->getVertex(0), (*it)->lines[i]->getVertex(1)));
134  }
135  }
136 }
137 
138 static void
140  std::set<MFace, MFaceLessThan> &allEmbeddedFaces)
141 {
142  std::vector<GFace *> const &f = gr->embeddedFaces();
143  for(auto it = f.begin(); it != f.end(); ++it) {
144  for(std::size_t i = 0; i < (*it)->triangles.size(); i++) {
145  allEmbeddedFaces.insert((*it)->triangles[i]->getFace(0));
146  }
147  }
148 }
149 
150 int MTet4::inCircumSphere(const double *p) const
151 {
152  double pa[3] = {base->getVertex(0)->x(), base->getVertex(0)->y(),
153  base->getVertex(0)->z()};
154  double pb[3] = {base->getVertex(1)->x(), base->getVertex(1)->y(),
155  base->getVertex(1)->z()};
156  double pc[3] = {base->getVertex(2)->x(), base->getVertex(2)->y(),
157  base->getVertex(2)->z()};
158  double pd[3] = {base->getVertex(3)->x(), base->getVertex(3)->y(),
159  base->getVertex(3)->z()};
160  double result = robustPredicates::insphere(pa, pb, pc, pd, (double *)p) *
161  robustPredicates::orient3d(pa, pb, pc, pd);
162  return (result > 0) ? 1 : 0;
163 }
164 
165 static int faces[4][3] = {{0, 1, 2}, {0, 2, 3}, {0, 3, 1}, {1, 3, 2}};
166 
168  bool operator()(MVertex *const a, MVertex *const b) const
169  {
170  return a->getNum() < b->getNum();
171  }
172 };
173 
174 struct faceXtet {
175  MVertex *v[3], *unsorted[3];
177  int i1;
178 
179  faceXtet(MTet4 *_t = nullptr, int iFac = 0) : t1(_t), i1(iFac)
180  {
181  unsorted[0] = v[0] = t1->tet()->getVertex(faces[iFac][0]);
182  unsorted[1] = v[1] = t1->tet()->getVertex(faces[iFac][1]);
183  unsorted[2] = v[2] = t1->tet()->getVertex(faces[iFac][2]);
184 
185  std::sort(v, v + 3, vertex_comparator());
186  }
187 
188  MVertex *getVertex(int i) const { return unsorted[i]; }
189 
190  bool operator<(const faceXtet &other) const
191  {
192  if(v[0]->getNum() < other.v[0]->getNum()) return true;
193  if(v[0]->getNum() > other.v[0]->getNum()) return false;
194  if(v[1]->getNum() < other.v[1]->getNum()) return true;
195  if(v[1]->getNum() > other.v[1]->getNum()) return false;
196  if(v[2]->getNum() < other.v[2]->getNum()) return true;
197  return false;
198  }
199 
200  bool operator==(const faceXtet &other) const
201  {
202  return (v[0]->getNum() == other.v[0]->getNum() &&
203  v[1]->getNum() == other.v[1]->getNum() &&
204  v[2]->getNum() == other.v[2]->getNum());
205  }
206 
208  {
209  MVertex const *const v0 = t1->tet()->getVertex(faces[i1][0]);
210  MVertex const *const v1 = t1->tet()->getVertex(faces[i1][1]);
211  MVertex const *const v2 = t1->tet()->getVertex(faces[i1][2]);
212 
213  double a[3] = {v0->x(), v0->y(), v0->z()};
214  double b[3] = {v1->x(), v1->y(), v1->z()};
215  double c[3] = {v2->x(), v2->y(), v2->z()};
216  double d[3] = {v->x(), v->y(), v->z()};
217 
218  return robustPredicates::orient3d(a, b, c, d) < 0.0;
219  }
220 };
221 
222 template <class ITER>
223 void connectTets_vector2_templ(std::size_t _size, ITER beg, ITER end,
224  std::vector<faceXtet> &conn)
225 {
226  conn.clear();
227  conn.reserve(4 * _size);
228  for(ITER IT = beg; IT != end; ++IT) {
229  MTet4 *t = *IT;
230  if(!t->isDeleted()) {
231  for(int j = 0; j < 4; j++) { conn.push_back(faceXtet(t, j)); }
232  }
233  }
234  if(!conn.size()) return;
235 
236  std::sort(conn.begin(), conn.end());
237 
238  for(std::size_t i = 0; i < conn.size() - 1; i++) {
239  faceXtet &f1 = conn[i];
240  faceXtet &f2 = conn[i + 1];
241  if(f1 == f2 && f1.t1 != f2.t1) {
242  f1.t1->setNeigh(f1.i1, f2.t1);
243  f2.t1->setNeigh(f2.i1, f1.t1);
244  ++i;
245  }
246  }
247 }
248 
249 template <class ITER>
251  ITER beg, ITER end,
252  const std::set<MFace, MFaceLessThan> *allEmbeddedFaces = nullptr)
253 {
254  std::set<faceXtet> conn;
255  while(beg != end) {
256  if(!(*beg)->isDeleted()) {
257  for(int i = 0; i < 4; i++) {
258  faceXtet fxt(*beg, i);
259  // if a face is embedded, do not connect tets on both sides!
260  if(!allEmbeddedFaces ||
261  allEmbeddedFaces->find(MFace(fxt.v[0], fxt.v[1], fxt.v[2])) ==
262  allEmbeddedFaces->end()) {
263  auto found = conn.find(fxt);
264  if(found == conn.end())
265  conn.insert(fxt);
266  else if(found->t1 != *beg) {
267  found->t1->setNeigh(found->i1, *beg);
268  (*beg)->setNeigh(i, found->t1);
269  }
270  }
271  }
272  }
273  ++beg;
274  }
275 }
276 
277 void connectTets(std::list<MTet4 *> &l,
278  const std::set<MFace, MFaceLessThan> *embeddedFaces)
279 {
280  connectTets(l.begin(), l.end(), embeddedFaces);
281 }
282 
283 void connectTets(std::vector<MTet4 *> &l,
284  const std::set<MFace, MFaceLessThan> *embeddedFaces)
285 {
286  connectTets(l.begin(), l.end(), embeddedFaces);
287 }
288 
289 void connectTets_vector2(std::list<MTet4 *> &l, std::vector<faceXtet> &conn)
290 {
291  connectTets_vector2_templ(l.size(), l.begin(), l.end(), conn);
292 }
293 
294 void connectTets_vector2(std::vector<MTet4 *> &l, std::vector<faceXtet> &conn)
295 {
296  connectTets_vector2_templ(l.size(), l.begin(), l.end(), conn);
297 }
298 
299 // Ensure the star-shapeness of the delaunay cavity
300 // We use the visibility criterion : the vertex should be visible
301 // by all the facets of the cavity
302 
303 static void removeFromCavity(std::vector<faceXtet> &shell,
304  std::vector<MTet4 *> &cavity, faceXtet &toRemove)
305 {
306  toRemove.t1->setDeleted(false);
307  cavity.erase(
308  std::remove_if(cavity.begin(), cavity.end(),
309  std::bind2nd(std::equal_to<MTet4 *>(), toRemove.t1)));
310 
311  for(int i = 0; i < 4; i++) {
312  faceXtet fxt2(toRemove.t1, i);
313  auto it = std::find(shell.begin(), shell.end(), fxt2);
314  if(it == shell.end()) {
315  MTet4 *opposite = toRemove.t1->getNeigh(toRemove.i1);
316  if(opposite) {
317  for(int j = 0; j < 4; j++) {
318  faceXtet fxt3(opposite, j);
319  if(fxt3 == fxt2) { shell.push_back(fxt3); }
320  }
321  }
322  }
323  else
324  shell.erase(it);
325  }
326 }
327 
328 static void extendCavity(std::vector<faceXtet> &shell,
329  std::vector<MTet4 *> &cavity, faceXtet &toExtend)
330 {
331  MTet4 *t = toExtend.t1;
332  MTet4 *opposite = t->getNeigh(toExtend.i1);
333  for(int i = 0; i < 4; i++) {
334  faceXtet fxt(opposite, i);
335  auto it = std::find(shell.begin(), shell.end(), fxt);
336  if(it == shell.end())
337  shell.push_back(fxt);
338  else
339  shell.erase(it);
340  }
341  cavity.push_back(opposite);
342  opposite->setDeleted(true);
343 }
344 
345 // if all faces of the tet that are not in the shell see v, then it is ok
346 // either to add or to remove t from the shell
347 static bool verifyShell(MVertex *v, MTet4 *t, std::vector<faceXtet> &shell)
348 {
349  if(!t) return false;
350  return 1;
351  int NBAD_BEFORE = 0, NBAD_AFTER = 0;
352  for(int i = 0; i < 4; i++) {
353  faceXtet fxt(t, i);
354  bool starShaped = fxt.visible(v);
355  if(!starShaped) {
356  auto its = std::find(shell.begin(), shell.end(), fxt);
357  if(its == shell.end())
358  NBAD_AFTER++;
359  else
360  NBAD_BEFORE++;
361  }
362  }
363  return 1;
364  return (NBAD_AFTER < NBAD_BEFORE);
365 }
366 
367 int makeCavityStarShaped(std::vector<faceXtet> &shell,
368  std::vector<MTet4 *> &cavity, MVertex *v)
369 {
370  std::vector<faceXtet> wrong;
371  for(auto it = shell.begin(); it != shell.end(); ++it) {
372  faceXtet &fxt = *it;
373  bool starShaped = fxt.visible(v);
374  if(!starShaped) { wrong.push_back(fxt); }
375  }
376  if(wrong.empty()) return 0;
377  // printf("cavity %p (shell size %d cavity size %d)is not star shaped "
378  // "(%d faces not visible), correcting it\n",
379  // v, shell.size(), cavity.size(), wrong.size());
380  while(!wrong.empty()) {
381  faceXtet &fxt = *(wrong.begin());
382  if(std::find(shell.begin(), shell.end(), fxt) != shell.end()) {
383  if(fxt.t1->getNeigh(fxt.i1) &&
384  fxt.t1->getNeigh(fxt.i1)->onWhat() == fxt.t1->onWhat() &&
385  verifyShell(v, fxt.t1->getNeigh(fxt.i1), shell)) {
386  extendCavity(shell, cavity, fxt);
387  }
388  else if(verifyShell(v, fxt.t1, shell)) {
389  return -1;
390  removeFromCavity(shell, cavity, fxt);
391  }
392  else {
393  return -1;
394  }
395  }
396  wrong.erase(wrong.begin());
397  }
398  // printf("after : shell size %d cavity size %d\n", shell.size(),
399  // cavity.size());
400  return 1;
401 }
402 
403 void findCavity(std::vector<faceXtet> &shell, std::vector<MTet4 *> &cavity,
404  MVertex *v, MTet4 *t)
405 {
406  t->setDeleted(true);
407  cavity.push_back(t);
408 
409  std::queue<MTet4 *> cavity_queue;
410 
411  if(!cavity.empty()) { cavity_queue.push(cavity.back()); }
412 
413  while(!cavity_queue.empty()) {
414  for(int i = 0; i < 4; i++) {
415  MTet4 *const neighbour = cavity_queue.front()->getNeigh(i);
416  if(!neighbour) { shell.push_back(faceXtet(cavity_queue.front(), i)); }
417  else if(!neighbour->isDeleted()) {
418  if(neighbour->inCircumSphere(v) &&
419  (neighbour->onWhat() == cavity_queue.front()->onWhat())) {
420  neighbour->setDeleted(true);
421 
422  cavity.push_back(neighbour);
423  cavity_queue.push(neighbour);
424  }
425  else {
426  shell.push_back(faceXtet(cavity_queue.front(), i));
427  }
428  }
429  }
430  cavity_queue.pop();
431  }
432 }
433 
434 #ifdef PRINT_TETS
435 
436 static void printTets(const char *fn, std::list<MTet4 *> &cavity,
437  bool force = false)
438 {
439  FILE *f = Fopen(fn, "w");
440  if(f) {
441  fprintf(f, "View \"\"{\n");
442  auto ittet = cavity.begin();
443  auto ittete = cavity.end();
444  while(ittet != ittete) {
445  MTet4 *tet = *ittet;
446  if(force || !tet->isDeleted()) {
447  MTetrahedron *t = tet->tet();
448  t->writePOS(f, false, false, false, false, true, false);
449  }
450  ittet++;
451  }
452  fprintf(f, "};\n");
453  fclose(f);
454  }
455 }
456 
457 #endif
458 
459 bool insertVertexB(std::vector<faceXtet> &shell, std::vector<MTet4 *> &cavity,
460  MVertex *v, double lc1, double lc2,
461  std::vector<double> &vSizes, std::vector<double> &vSizesBGM,
462  MTet4 *t, MTet4Factory &myFactory,
463  std::set<MTet4 *, compareTet4Ptr> &allTets,
464  const std::set<MFace, MFaceLessThan> &allEmbeddedFaces)
465 {
466  std::vector<MTet4 *> new_cavity;
467  new_cavity.reserve(shell.size());
468 
469  std::vector<MTet4 *> new_tets;
470  new_tets.reserve(shell.size());
471 
472  auto it = shell.begin();
473 
474  bool onePointIsTooClose = false;
475  while(it != shell.end()) {
476  MTetrahedron *tr =
477  new MTetrahedron(it->getVertex(0), it->getVertex(1), it->getVertex(2), v);
478  MTet4 *t4 = myFactory.Create(tr, vSizes, vSizesBGM, lc1, lc2);
479  t4->setOnWhat(t->onWhat());
480 
481  double const lc = Extend2dMeshIn3dVolumes() ? std::min(lc1, lc2) : lc2;
482  if(distance(it->v[0], v) < lc * .05 || distance(it->v[1], v) < lc * .05 ||
483  distance(it->v[2], v) < lc * .05)
484  onePointIsTooClose = true;
485 
486  new_tets.push_back(t4);
487  new_cavity.push_back(t4);
488 
489  MTet4 *otherSide = it->t1->getNeigh(it->i1);
490 
491  if(otherSide) new_cavity.push_back(otherSide);
492  ++it;
493  }
494  if(!onePointIsTooClose) {
495  if(allEmbeddedFaces.empty()) {
496  std::vector<faceXtet> conn;
497  connectTets_vector2(new_cavity, conn);
498  }
499  else {
500  connectTets(new_cavity.begin(), new_cavity.end(), &allEmbeddedFaces);
501  }
502 
503  allTets.insert(new_tets.begin(), new_tets.end());
504 
505  return true;
506  }
507  else /* one point is too close */ {
508  for(std::size_t i = 0; i < shell.size(); i++) myFactory.Free(new_tets[i]);
509  auto ittet = cavity.begin();
510  auto ittete = cavity.end();
511  while(ittet != ittete) {
512  (*ittet)->setDeleted(false);
513  ++ittet;
514  }
515  return false;
516  }
517 }
518 
519 static void setLcs(MTriangle *t,
520  std::map<MVertex *, double, MVertexPtrLessThan> &vSizes,
521  std::set<MVertex *, MVertexPtrLessThan> &bndVertices)
522 {
523  for(int i = 0; i < 3; i++) {
524  bndVertices.insert(t->getVertex(i));
525  MEdge e = t->getEdge(i);
526  MVertex *vi = e.getVertex(0);
527  MVertex *vj = e.getVertex(1);
528  double dx = vi->x() - vj->x();
529  double dy = vi->y() - vj->y();
530  double dz = vi->z() - vj->z();
531  double l = std::sqrt(dx * dx + dy * dy + dz * dz);
532  auto iti = vSizes.find(vi);
533  auto itj = vSizes.find(vj);
534  if(CTX::instance()->mesh.lcExtendFromBoundary == 2) {
535  // use smallest edge length
536  if(iti == vSizes.end() || iti->second > l) vSizes[vi] = l;
537  if(itj == vSizes.end() || itj->second > l) vSizes[vj] = l;
538  }
539  else {
540  // use largest edge length
541  if(iti == vSizes.end() || iti->second < l) vSizes[vi] = l;
542  if(itj == vSizes.end() || itj->second < l) vSizes[vj] = l;
543  }
544  }
545 
546  // use average edge length
547  /*
548  double l = 0;
549  for(int i = 0; i < 3; i++){
550  MEdge e = t->getEdge(i);
551  MVertex *vi = e.getVertex(0);
552  MVertex *vj = e.getVertex(1);
553  double dx = vi->x()-vj->x();
554  double dy = vi->y()-vj->y();
555  double dz = vi->z()-vj->z();
556  l += sqrt(dx * dx + dy * dy + dz * dz);
557  }
558  l /= 3;
559  for(int i = 0; i < 3; i++){
560  bndVertices.insert(t->getVertex(i));
561  MEdge e = t->getEdge(i);
562  MVertex *vi = e.getVertex(0);
563  MVertex *vj = e.getVertex(1);
564  auto iti = vSizes.find(vi);
565  auto itj = vSizes.find(vj);
566  // use largest edge length
567  if (iti == vSizes.end() || iti->second > l) vSizes[vi] = l;
568  if (itj == vSizes.end() || itj->second > l) vSizes[vj] = l;
569  }
570  */
571 }
572 
573 static void setLcs(MTetrahedron *t,
574  std::map<MVertex *, double, MVertexPtrLessThan> &vSizes,
575  std::set<MVertex *, MVertexPtrLessThan> &bndVertices)
576 {
577  for(int i = 0; i < 4; i++) {
578  for(int j = i + 1; j < 4; j++) {
579  MVertex *vi = t->getVertex(i);
580  MVertex *vj = t->getVertex(j);
581 
582  // smallest tet edge
583  if(bndVertices.find(vi) == bndVertices.end()) {
584  auto iti = vSizes.find(vi);
585 
586  double const length =
587  hypotenuse(vi->x() - vj->x(), vi->y() - vj->y(), vi->z() - vj->z());
588 
589  if(iti == vSizes.end() || iti->second > length) { vSizes[vi] = length; }
590  }
591 
592  if(bndVertices.find(vj) == bndVertices.end()) {
593  auto itj = vSizes.find(vj);
594 
595  double const length =
596  hypotenuse(vi->x() - vj->x(), vi->y() - vj->y(), vi->z() - vj->z());
597 
598  if(itj == vSizes.end() || itj->second > length) { vSizes[vj] = length; }
599  }
600  }
601  }
602 }
603 
604 static void completeTheSetOfFaces(GModel *model, std::set<GFace *> &faces_bound)
605 {
606  std::set<GFace *> toAdd;
607  for(auto it = model->firstFace(); it != model->lastFace(); ++it) {
608  if(faces_bound.find(*it) != faces_bound.end()) {
609  if((*it)->compound.size()) {
610  for(std::size_t i = 0; i < (*it)->compound.size(); ++i) {
611  GFace *gf = static_cast<GFace *>((*it)->compound[i]);
612  if(gf) toAdd.insert(gf);
613  }
614  }
615  }
616  }
617  faces_bound.insert(toAdd.begin(), toAdd.end());
618 }
619 
621  std::set<GFace *> &faces_bound)
622 {
623  completeTheSetOfFaces(model, faces_bound);
624 
625  auto git = model->firstRegion();
626  while(git != model->lastRegion()) {
627  GRegion *gr = *git;
629  if((ep && ep->mesh.ExtrudeMesh) ||
631  // extruded meshes or transfinite should be considered as "void"
632  }
633  else {
634  std::vector<GFace *> _faces = (*git)->faces();
635  if(_faces.size() == faces_bound.size()) {
636  bool ok = true;
637  for(auto it = _faces.begin(); it != _faces.end(); ++it) {
638  if(faces_bound.find(*it) == faces_bound.end()) ok = false;
639  }
640  if(ok) return *git;
641  }
642  }
643  ++git;
644  }
645  return nullptr;
646 }
647 
648 void non_recursive_classify(MTet4 *t, std::list<MTet4 *> &theRegion,
649  std::set<GFace *> &faces_bound, GRegion *bidon,
650  GModel *model, const fs_cont &search)
651 {
652  std::stack<MTet4 *> _stackounette;
653  _stackounette.push(t);
654 
655  bool touchesOutsideBox = false;
656 
657  while(!_stackounette.empty()) {
658  t = _stackounette.top();
659  _stackounette.pop();
660  if(!t) {
661  Msg::Warning("A tetrahedron is not connected to a boundary face");
662  touchesOutsideBox = true;
663  }
664  else if(!t->onWhat()) {
665  theRegion.push_back(t);
666  t->setOnWhat(bidon);
667  bool FF[4] = {0, 0, 0, 0};
668  for(int i = 0; i < 4; i++) {
670  t->tet()->getVertex(faces[i][0]), t->tet()->getVertex(faces[i][1]),
671  t->tet()->getVertex(faces[i][2]), search);
672  if(gfound) {
673  FF[i] = true;
674  if(faces_bound.find(gfound) == faces_bound.end())
675  faces_bound.insert(gfound);
676  }
677  }
678  for(int i = 0; i < 4; i++) {
679  if(!FF[i]) _stackounette.push(t->getNeigh(i));
680  }
681  }
682  }
683  if(touchesOutsideBox) faces_bound.clear();
684 }
685 
687 {
689 
690  typedef std::list<MTet4 *> CONTAINER;
691  CONTAINER allTets;
692  for(std::size_t i = 0; i < gr->tetrahedra.size(); i++) {
693  allTets.push_back(new MTet4(gr->tetrahedra[i], qm));
694  }
695  gr->tetrahedra.clear();
696 
697  std::set<MFace, MFaceLessThan> allEmbeddedFaces;
698  createAllEmbeddedFaces(gr, allEmbeddedFaces);
699  std::set<MEdge, MEdgeLessThan> allEmbeddedEdges;
700  createAllEmbeddedEdges(gr, allEmbeddedEdges);
701 
702  connectTets(allTets.begin(), allTets.end(), &allEmbeddedFaces);
703 
704  double t1 = Cpu(), w1 = TimeOfDay();
705  std::vector<MTet4 *> illegals;
706  const int nbRanges = 10;
707  int quality_ranges[nbRanges];
708  {
709  double totalVolumeb = 0.0;
710  double worst = 1.0;
711  double avg = 0;
712  int count = 0;
713  for(int i = 0; i < nbRanges; i++) quality_ranges[i] = 0;
714  for(auto it = allTets.begin(); it != allTets.end(); ++it) {
715  if(!(*it)->isDeleted()) {
716  double vol = fabs((*it)->tet()->getVolume());
717  double qual = (*it)->getQuality();
718  worst = std::min(qual, worst);
719  avg += qual;
720  count++;
721  totalVolumeb += vol;
722  for(int i = 0; i < nbRanges; i++) {
723  double low = (double)i / nbRanges;
724  double high = (double)(i + 1) / nbRanges;
725  if(qual >= low && qual < high) quality_ranges[i]++;
726  }
727  }
728  }
729  Msg::Info("Adaptation starts (volume = %g) with worst = %g / average = %g:",
730  totalVolumeb, worst, avg / count);
731  for(int i = 0; i < nbRanges; i++) {
732  double low = (double)i / nbRanges;
733  double high = (double)(i + 1) / nbRanges;
734  Msg::Info("%3.2f < quality < %3.2f: %9d elements ", low, high,
735  quality_ranges[i]);
736  }
737  }
738 
739  double qMin = 0.5;
740  double sliverLimit = 0.2;
741 
742  int nbESwap = 0, nbFSwap = 0, nbReloc = 0, nbCollapse = 0;
743 
744  while(1) {
745  std::vector<MTet4 *> newTets;
746  for(auto it = allTets.begin(); it != allTets.end(); ++it) {
747  if(!(*it)->isDeleted()) {
748  for(int i = 0; i < 4; i++) {
749  for(int j = 0; j < 4; j++) {
750  if(collapseVertex(newTets, *it, i, j, qmTetrahedron::QMTET_GAMMA)) {
751  nbCollapse++;
752  i = j = 10;
753  }
754  }
755  }
756  }
757  }
758 
759  for(auto it = allTets.begin(); it != allTets.end(); ++it) {
760  if(!(*it)->isDeleted()) {
761  double qq = (*it)->getQuality();
762  if(qq < qMin) {
763  for(int i = 0; i < 4; i++) {
764  if(faceSwap(newTets, *it, i, qm, allEmbeddedFaces)) {
765  nbFSwap++;
766  break;
767  }
768  }
769  }
770  }
771  }
772 
773  illegals.clear();
774  for(int i = 0; i < nbRanges; i++) quality_ranges[i] = 0;
775 
776  for(auto it = allTets.begin(); it != allTets.end(); ++it) {
777  if(!(*it)->isDeleted()) {
778  double qq = (*it)->getQuality();
779  if(qq < qMin)
780  for(int i = 0; i < 6; i++) {
781  MEdge ed = (*it)->tet()->getEdge(i);
782  if(allEmbeddedEdges.find(ed) == allEmbeddedEdges.end()) {
783  if(edgeSwap(newTets, *it, i, qm, allEmbeddedFaces)) {
784  nbESwap++;
785  break;
786  }
787  }
788  }
789  if(!(*it)->isDeleted()) {
790  if(qq < sliverLimit) illegals.push_back(*it);
791  for(int i = 0; i < nbRanges; i++) {
792  double low = (double)i / nbRanges;
793  double high = (double)(i + 1) / nbRanges;
794  if(qq >= low && qq < high) quality_ranges[i]++;
795  }
796  }
797  }
798  }
799 
800  if(!newTets.size()) break;
801 
802  // add all the new tets in the container
803  for(std::size_t i = 0; i < newTets.size(); i++) {
804  if(!newTets[i]->isDeleted()) { allTets.push_back(newTets[i]); }
805  else {
806  delete newTets[i]->tet();
807  delete newTets[i];
808  }
809  }
810 
811  // relocate vertices
812  for(auto it = allTets.begin(); it != allTets.end(); ++it) {
813  if(!(*it)->isDeleted()) {
814  double qq = (*it)->getQuality();
815  if(qq < qMin)
816  for(int i = 0; i < 4; i++) {
817  if(smoothVertex(*it, i, qm)) nbReloc++;
818  }
819  }
820  }
821 
822  double totalVolumeb = 0.0;
823  double worst = 1.0;
824  double avg = 0;
825  int count = 0;
826  for(auto it = allTets.begin(); it != allTets.end(); ++it) {
827  if(!(*it)->isDeleted()) {
828  double vol = fabs((*it)->tet()->getVolume());
829  double qual = (*it)->getQuality();
830  worst = std::min(qual, worst);
831  avg += qual;
832  count++;
833  totalVolumeb += vol;
834  }
835  }
836  double t2 = Cpu(), w2 = TimeOfDay();
837  Msg::Info("%d edge swaps, %d face swaps, %d node collapse, %d node "
838  "relocations (volume = %g): worst = %g / average = %g "
839  "(Wall %gs, CPU %gs)",
840  nbESwap, nbFSwap, nbCollapse, nbReloc, totalVolumeb, worst,
841  avg / count, w2 - w1, t2 - t1);
842  break;
843  }
844 
845  int nbSlivers = 0;
846  for(std::size_t i = 0; i < illegals.size(); i++)
847  if(!(illegals[i]->isDeleted())) nbSlivers++;
848 
849  if(nbSlivers) {
850  Msg::Info("%d illegal tets are still in the mesh, trying to remove them",
851  nbSlivers);
852  }
853  else {
854  Msg::Info("No illegal tets in the mesh :-)", nbSlivers);
855  }
856 
857  for(int i = 0; i < nbRanges; i++) {
858  double low = (double)i / nbRanges;
859  double high = (double)(i + 1) / nbRanges;
860  Msg::Info("%3.2f < quality < %3.2f: %9d elements", low, high,
861  quality_ranges[i]);
862  }
863 
864  for(auto it = allTets.begin(); it != allTets.end(); ++it) {
865  if(!(*it)->isDeleted()) {
866  gr->tetrahedra.push_back((*it)->tet());
867  delete *it;
868  }
869  else {
870  delete(*it)->tet();
871  delete *it;
872  }
873  }
874 }
875 
877 {
878  double qMin = CTX::instance()->mesh.optimizeThreshold;
879 
880  if(qMin <= 0.0) return;
881 
882  if(gr->tetrahedra.empty()) return;
883 
884  typedef std::vector<MTet4 *> CONTAINER;
885  CONTAINER allTets;
886  for(std::size_t i = 0; i < gr->tetrahedra.size(); i++) {
887  MTet4 *t = new MTet4(gr->tetrahedra[i], qm);
888  t->setOnWhat(gr);
889  allTets.push_back(t);
890  }
891  gr->tetrahedra.clear();
892 
893  std::set<MFace, MFaceLessThan> allEmbeddedFaces;
894  createAllEmbeddedFaces(gr, allEmbeddedFaces);
895 
896  std::set<MEdge, MEdgeLessThan> allEmbeddedEdges;
897  createAllEmbeddedEdges(gr, allEmbeddedEdges);
898 
899  if(allEmbeddedFaces.empty()) {
900  std::vector<faceXtet> conn;
901  connectTets_vector2(allTets, conn);
902  }
903  else {
904  // daaaaaaamn slow !!!
905  connectTets(allTets.begin(), allTets.end(), &allEmbeddedFaces);
906  }
907 
908  double t1 = Cpu(), w1 = TimeOfDay();
909  std::vector<MTet4 *> illegals;
910  const int nbRanges = 10;
911  int quality_ranges[nbRanges];
912  {
913  double totalVolumeb = 0.0;
914  double worst = 1.0;
915  double avg = 0;
916  int count = 0;
917  for(int i = 0; i < nbRanges; i++) quality_ranges[i] = 0;
918  for(auto it = allTets.begin(); it != allTets.end(); ++it) {
919  if(!(*it)->isDeleted()) {
920  double vol = fabs((*it)->tet()->getVolume());
921  double qual = (*it)->getQuality();
922  worst = std::min(qual, worst);
923  avg += qual;
924  count++;
925  totalVolumeb += vol;
926  for(int i = 0; i < nbRanges; i++) {
927  double low = (double)i / nbRanges;
928  double high = (double)(i + 1) / nbRanges;
929  if(qual >= low && qual < high) quality_ranges[i]++;
930  }
931  }
932  }
933  Msg::Info(
934  "Optimization starts (volume = %g) with worst = %g / average = %g:",
935  totalVolumeb, worst, avg / count);
936  for(int i = 0; i < nbRanges; i++) {
937  double low = (double)i / nbRanges;
938  double high = (double)(i + 1) / nbRanges;
939  Msg::Info("%3.2f < quality < %3.2f : %9d elements", low, high,
940  quality_ranges[i]);
941  }
942  }
943 
944  double sliverLimit = 0.001;
945  int nbESwap = 0, nbReloc = 0;
946  double worstA = 0.0;
947 
948  std::set<MTetrahedron*> to_delete;
949 
950  while(1) {
951  std::vector<MTet4 *> newTets;
952 
953  illegals.clear();
954  for(int i = 0; i < nbRanges; i++) quality_ranges[i] = 0;
955 
956  for(auto it = allTets.begin(); it != allTets.end(); ++it) {
957  if(!(*it)->isDeleted()) {
958  double qq = (*it)->getQuality();
959  if(qq < qMin) {
960  for(int i = 0; i < 6; i++) {
961  MEdge ed = (*it)->tet()->getEdge(i);
962  if(allEmbeddedEdges.find(ed) == allEmbeddedEdges.end()) {
963  if(edgeSwap(newTets, *it, i, qm, allEmbeddedFaces)) {
964  nbESwap++;
965  break;
966  }
967  }
968  }
969  }
970  if(!(*it)->isDeleted()) {
971  if(qq < sliverLimit) illegals.push_back(*it);
972  for(int i = 0; i < nbRanges; i++) {
973  double low = (double)i / nbRanges;
974  double high = (double)(i + 1) / nbRanges;
975  if(qq >= low && qq < high) quality_ranges[i]++;
976  }
977  }
978  }
979  }
980 
981  if(!newTets.size()) { break; }
982 
983  // add all the new tets in the container
984  for(std::size_t i = 0; i < newTets.size(); i++) {
985  if(!newTets[i]->isDeleted()) { allTets.push_back(newTets[i]); }
986  else {
987  to_delete.insert(newTets[i]->tet());
988  delete newTets[i];
989  }
990  }
991 
992  // relocate vertices
993  if(gr->hexahedra.empty() && gr->prisms.empty() && gr->pyramids.empty()) {
994  for(auto it = allTets.begin(); it != allTets.end(); ++it) {
995  if(!(*it)->isDeleted()) {
996  double qq = (*it)->getQuality();
997  if(qq < qMin) {
998  for(int i = 0; i < 4; i++) {
999  if(smoothVertex(*it, i, qm)) nbReloc++;
1000  }
1001  }
1002  }
1003  }
1004  }
1005 
1006  double totalVolumeb = 0.0;
1007  double worst = 1.0;
1008  double avg = 0;
1009  int count = 0;
1010  for(auto it = allTets.begin(); it != allTets.end(); ++it) {
1011  if(!(*it)->isDeleted()) {
1012  double vol = fabs((*it)->tet()->getVolume());
1013  double qual = (*it)->getQuality();
1014  worst = std::min(qual, worst);
1015  avg += qual;
1016  count++;
1017  totalVolumeb += vol;
1018  }
1019  }
1020 
1021  double t2 = Cpu(), w2 = TimeOfDay();
1022  Msg::Info("%d edge swaps, %d node relocations (volume = %g): "
1023  "worst = %g / average = %g (Wall %gs, CPU %gs)",
1024  nbESwap, nbReloc, totalVolumeb, worst, avg / count, w2 - w1,
1025  t2 - t1);
1026  if(worstA != 0.0 && worst - worstA < 1.e-6) break;
1027  worstA = worst;
1028  }
1029 
1030  for(auto t : to_delete) delete t;
1031 
1032  if(illegals.size()) {
1033  Msg::Warning("%d ill-shaped tets are still in the mesh", illegals.size());
1034  }
1035  else {
1036  Msg::Info("No ill-shaped tets in the mesh :-)");
1037  }
1038 
1039  for(int i = 0; i < nbRanges; i++) {
1040  double low = (double)i / nbRanges;
1041  double high = (double)(i + 1) / nbRanges;
1042  Msg::Info("%3.2f < quality < %3.2f : %9d elements", low, high,
1043  quality_ranges[i]);
1044  }
1045 
1046  for(auto it = allTets.begin(); it != allTets.end(); ++it) {
1047  if(!(*it)->isDeleted()) {
1048  gr->tetrahedra.push_back((*it)->tet());
1049  delete *it;
1050  }
1051  else {
1052  delete(*it)->tet();
1053  delete *it;
1054  }
1055  }
1056 }
1057 
1058 double tetcircumcenter(double a[3], double b[3], double c[3], double d[3],
1059  double circumcenter[3], double *xi, double *eta,
1060  double *zeta)
1061 {
1062  double xba, yba, zba, xca, yca, zca, xda, yda, zda;
1063  double balength, calength, dalength;
1064  double xcrosscd, ycrosscd, zcrosscd;
1065  double xcrossdb, ycrossdb, zcrossdb;
1066  double xcrossbc, ycrossbc, zcrossbc;
1067  double denominator;
1068  double xcirca, ycirca, zcirca;
1069 
1070  /* Use coordinates relative to point `a' of the tetrahedron. */
1071  xba = b[0] - a[0];
1072  yba = b[1] - a[1];
1073  zba = b[2] - a[2];
1074  xca = c[0] - a[0];
1075  yca = c[1] - a[1];
1076  zca = c[2] - a[2];
1077  xda = d[0] - a[0];
1078  yda = d[1] - a[1];
1079  zda = d[2] - a[2];
1080  /* Squares of lengths of the edges incident to `a'. */
1081  balength = xba * xba + yba * yba + zba * zba;
1082  calength = xca * xca + yca * yca + zca * zca;
1083  dalength = xda * xda + yda * yda + zda * zda;
1084  /* Cross products of these edges. */
1085  xcrosscd = yca * zda - yda * zca;
1086  ycrosscd = zca * xda - zda * xca;
1087  zcrosscd = xca * yda - xda * yca;
1088  xcrossdb = yda * zba - yba * zda;
1089  ycrossdb = zda * xba - zba * xda;
1090  zcrossdb = xda * yba - xba * yda;
1091  xcrossbc = yba * zca - yca * zba;
1092  ycrossbc = zba * xca - zca * xba;
1093  zcrossbc = xba * yca - xca * yba;
1094 
1095  /* Calculate the denominator of the formulae. */
1096  /* Use orient3d() from http://www.cs.cmu.edu/~quake/robust.html */
1097  /* to ensure a correctly signed (and reasonably accurate) result, */
1098  /* avoiding any possibility of division by zero. */
1099  const double xxx = robustPredicates::orient3d(b, c, d, a);
1100  denominator = 0.5 / xxx;
1101 
1102  /* Calculate offset (from `a') of circumcenter. */
1103  xcirca = (balength * xcrosscd + calength * xcrossdb + dalength * xcrossbc) *
1104  denominator;
1105  ycirca = (balength * ycrosscd + calength * ycrossdb + dalength * ycrossbc) *
1106  denominator;
1107  zcirca = (balength * zcrosscd + calength * zcrossdb + dalength * zcrossbc) *
1108  denominator;
1109  circumcenter[0] = xcirca + a[0];
1110  circumcenter[1] = ycirca + a[1];
1111  circumcenter[2] = zcirca + a[2];
1112 
1113  if(xi != (double *)nullptr) {
1114  /* To interpolate a linear function at the circumcenter, define a */
1115  /* coordinate system with a xi-axis directed from `a' to `b', */
1116  /* an eta-axis directed from `a' to `c', and a zeta-axis directed */
1117  /* from `a' to `d'. The values for xi, eta, and zeta are computed */
1118  /* by Cramer's Rule for solving systems of linear equations. */
1119  *xi = (xcirca * xcrosscd + ycirca * ycrosscd + zcirca * zcrosscd) *
1120  (2.0 * denominator);
1121  *eta = (xcirca * xcrossdb + ycirca * ycrossdb + zcirca * zcrossdb) *
1122  (2.0 * denominator);
1123  *zeta = (xcirca * xcrossbc + ycirca * ycrossbc + zcirca * zcrossbc) *
1124  (2.0 * denominator);
1125  }
1126  return xxx;
1127 }
1128 
1129 static void memoryCleanup(MTet4Factory &myFactory,
1130  std::set<MTet4 *, compareTet4Ptr> &allTets)
1131 {
1132  // int n1 = allTets.size();
1133  auto itd = allTets.begin();
1134  while(itd != allTets.end()) {
1135  if((*itd)->isDeleted()) {
1136  myFactory.Free((*itd));
1137  allTets.erase(itd++);
1138  }
1139  else
1140  itd++;
1141  }
1142  // Msg::Info("Cleaning up memory %d -> %d", n1, allTets.size());
1143 }
1144 
1145 static int isCavityCompatibleWithEmbeddedEdges(std::vector<MTet4 *> &cavity,
1146  std::vector<faceXtet> &shell,
1147  edgeContainerB &allEmbeddedEdges)
1148 {
1149  if(allEmbeddedEdges.empty()) return 1;
1150  std::vector<MEdge> ed;
1151  ed.reserve(shell.size() * 3);
1152 
1153  for(auto it = shell.begin(); it != shell.end(); it++) {
1154  ed.push_back(MEdge(it->v[0], it->v[1]));
1155  ed.push_back(MEdge(it->v[1], it->v[2]));
1156  ed.push_back(MEdge(it->v[2], it->v[0]));
1157  }
1158 
1159  for(auto itc = cavity.begin(); itc != cavity.end(); ++itc) {
1160  for(int j = 0; j < 6; j++) {
1161  MEdge e = (*itc)->tet()->getEdge(j);
1162  if(std::find(ed.begin(), ed.end(), e) == ed.end() &&
1163  allEmbeddedEdges.find(e)) {
1164  return 0;
1165  }
1166  }
1167  }
1168  return 1;
1169 }
1170 
1172  const std::vector<MTet4 *> &cavity, const std::vector<faceXtet> &shell,
1173  const std::set<MFace, MFaceLessThan> &allEmbeddedFaces)
1174 {
1175  if(allEmbeddedFaces.empty()) return 1;
1176  std::vector<MFace> shellFaces;
1177  shellFaces.reserve(shell.size());
1178 
1179  for(auto it = shell.begin(); it != shell.end(); it++) {
1180  const faceXtet &face = (*it);
1181  shellFaces.push_back(
1182  MFace(face.unsorted[0], face.unsorted[1], face.unsorted[2]));
1183  }
1184 
1185  for(auto itc = cavity.begin(); itc != cavity.end(); ++itc) {
1186  for(int j = 0; j < 4; j++) {
1187  MFace f = (*itc)->tet()->getFace(j);
1188  if((std::find(shellFaces.begin(), shellFaces.end(), f) ==
1189  shellFaces.end()) &&
1190  (allEmbeddedFaces.count(f) > 0)) {
1191  return 0;
1192  }
1193  }
1194  }
1195  return 1;
1196 }
1197 
1199 {
1200  std::set<MVertex *, MVertexPtrLessThan> allverts;
1201  for(std::size_t i = 0; i < gr->tetrahedra.size(); i++) {
1202  for(int j = 0; j < 4; j++) {
1203  if(gr->tetrahedra[i]->getVertex(j)->onWhat() == gr)
1204  allverts.insert(gr->tetrahedra[i]->getVertex(j));
1205  }
1206  }
1207  for(std::size_t i = 0; i < gr->mesh_vertices.size(); i++) {
1208  // FIXME: investigate crash on exit (e.g. t16.geo)
1209  // if(allverts.find(gr->mesh_vertices[i]) == allverts.end())
1210  // delete gr->mesh_vertices[i];
1211  }
1212  gr->mesh_vertices.clear();
1213  gr->mesh_vertices.insert(gr->mesh_vertices.end(), allverts.begin(),
1214  allverts.end());
1215 }
1216 
1217 void insertVerticesInRegion(GRegion *gr, int maxIter,
1218  double worstTetRadiusTarget, bool _classify,
1220 {
1221 #ifdef DEBUG_BOUNDARY_RECOVERY
1222  testIfBoundaryIsRecovered(gr);
1223 #endif
1224 
1225  std::vector<double> vSizes, vSizesBGM;
1226  MTet4Factory myFactory(1600000);
1227  std::set<MTet4 *, compareTet4Ptr> &allTets = myFactory.getAllTets();
1228  int NUM = 0;
1229 
1230  // leave this in a block so the map gets deallocated directly
1231  {
1232  std::map<MVertex *, double, MVertexPtrLessThan> vSizesMap;
1233  std::set<MVertex *, MVertexPtrLessThan> bndVertices;
1234 
1235  for(auto rit = gr->model()->firstRegion(); rit != gr->model()->lastRegion();
1236  ++rit) {
1237  std::vector<GEdge *> const &e = (*rit)->embeddedEdges();
1238  for(auto it = e.begin(); it != e.end(); ++it) {
1239  for(std::size_t i = 0; i < (*it)->lines.size(); i++) {
1240  MVertex *vi = (*it)->lines[i]->getVertex(0);
1241  MVertex *vj = (*it)->lines[i]->getVertex(1);
1242  double dx = vi->x() - vj->x();
1243  double dy = vi->y() - vj->y();
1244  double dz = vi->z() - vj->z();
1245  double l = std::sqrt(dx * dx + dy * dy + dz * dz);
1246 
1247  auto iti = vSizesMap.find(vi);
1248  auto itj = vSizesMap.find(vj);
1249 
1250  // smallest tet edge
1251  if(iti == vSizesMap.end() || iti->second > l) vSizesMap[vi] = l;
1252  if(itj == vSizesMap.end() || itj->second > l) vSizesMap[vj] = l;
1253  }
1254  }
1255  }
1256 
1257  for(auto rit = gr->model()->firstRegion(); rit != gr->model()->lastRegion();
1258  ++rit) {
1259  std::vector<GVertex *> const &vertices = (*rit)->embeddedVertices();
1260  for(auto it = vertices.begin(); it != vertices.end(); ++it) {
1261  MVertex *v = (*it)->getMeshVertex(0);
1262  double l = (*it)->prescribedMeshSizeAtVertex();
1263  auto itv = vSizesMap.find(v);
1264  if(itv == vSizesMap.end() || itv->second > l) vSizesMap[v] = l;
1265  }
1266  }
1267 
1268  for(auto it = gr->model()->firstFace(); it != gr->model()->lastFace();
1269  ++it) {
1270  GFace *gf = *it;
1271  for(std::size_t i = 0; i < gf->triangles.size(); i++) {
1272  setLcs(gf->triangles[i], vSizesMap, bndVertices);
1273  }
1274  }
1275  for(std::size_t i = 0; i < gr->tetrahedra.size(); i++)
1276  setLcs(gr->tetrahedra[i], vSizesMap, bndVertices);
1277 
1278  for(auto it = vSizesMap.begin(); it != vSizesMap.end(); ++it) {
1279  it->first->setIndex(NUM++);
1280  vSizes.push_back(it->second);
1281  vSizesBGM.push_back(it->second);
1282  }
1283  }
1284 
1285  for(std::size_t i = 0; i < gr->tetrahedra.size(); i++) {
1286  gr->tetrahedra[i]->setVolumePositive();
1287  allTets.insert(myFactory.Create(gr->tetrahedra[i], vSizes, vSizesBGM));
1288  }
1289 
1290  gr->tetrahedra.clear();
1291 
1292  // SLOW
1293  connectTets(allTets.begin(), allTets.end());
1294 
1295  // classify the tets on the right region
1296 
1297  if(_classify) {
1298  fs_cont search;
1299  buildFaceSearchStructure(gr->model(), search, true); // only triangles
1300  if(sqr) search.insert(sqr->getTri().begin(), sqr->getTri().end());
1301 
1302  for(auto it = allTets.begin(); it != allTets.end(); ++it) {
1303  if(!(*it)->onWhat()) {
1304  std::list<MTet4 *> theRegion;
1305  std::set<GFace *> faces_bound;
1306  GRegion *bidon = (GRegion *)123;
1307  double _t1 = Cpu(), _w1 = TimeOfDay();
1308  Msg::Debug("start with a non classified tet");
1309  non_recursive_classify(*it, theRegion, faces_bound, bidon, gr->model(),
1310  search);
1311  double _t2 = Cpu(), _w2 = TimeOfDay();
1312  Msg::Debug("Found %d tets with %d faces (Wall %gs, CPU %gs)",
1313  theRegion.size(), faces_bound.size(), _w2 - _w1, _t2 - _t1);
1314  GRegion *myGRegion =
1315  getRegionFromBoundingFaces(gr->model(), faces_bound);
1316  if(myGRegion && myGRegion->tetrahedra.empty()) {
1317  // a geometrical region (with no mesh) associated to the list of faces
1318  // has been found
1319  Msg::Info("Found volume %d", myGRegion->tag());
1320  for(auto it2 = theRegion.begin(); it2 != theRegion.end(); ++it2) {
1321  (*it2)->setOnWhat(myGRegion);
1322 
1323  // Make sure that Steiner points will end up in the right region
1324  std::vector<MVertex *> vertices;
1325  (*it2)->tet()->getVertices(vertices);
1326  for(auto itv = vertices.begin(); itv != vertices.end(); ++itv) {
1327  if((*itv)->onWhat() != nullptr && (*itv)->onWhat()->dim() == 3 &&
1328  (*itv)->onWhat() != myGRegion) {
1329  myGRegion->addMeshVertex((*itv));
1330  (*itv)->setEntity(myGRegion);
1331  }
1332  }
1333  }
1334  }
1335  else {
1336  // the tets are in the void
1337  Msg::Info("Found void region");
1338  for(auto it2 = theRegion.begin(); it2 != theRegion.end(); ++it2)
1339  (*it2)->setDeleted(true);
1340  }
1341  }
1342  }
1343  search.clear();
1344  }
1345  else {
1346  // FIXME ... too simple
1347  for(auto it = allTets.begin(); it != allTets.end(); ++it)
1348  (*it)->setOnWhat(gr);
1349  }
1350 
1351  for(auto it = allTets.begin(); it != allTets.end(); ++it) {
1352  (*it)->setNeigh(0, nullptr);
1353  (*it)->setNeigh(1, nullptr);
1354  (*it)->setNeigh(2, nullptr);
1355  (*it)->setNeigh(3, nullptr);
1356  }
1357  // store all embedded edges and faces
1358  std::set<MFace, MFaceLessThan> allEmbeddedFaces;
1359  std::size_t N = 0;
1360  for(auto it = gr->model()->firstRegion(); it != gr->model()->lastRegion();
1361  ++it) {
1362  for(auto e : (*it)->embeddedEdges())
1363  N += e->getNumMeshElements();
1364  }
1365  edgeContainerB allEmbeddedEdges(N);
1366  for(auto it = gr->model()->firstRegion(); it != gr->model()->lastRegion();
1367  ++it) {
1368  createAllEmbeddedFaces((*it), allEmbeddedFaces);
1369  createAllEmbeddedEdges((*it), allEmbeddedEdges);
1370  }
1371  connectTets(allTets.begin(), allTets.end(), &allEmbeddedFaces);
1372  Msg::Debug("All %d tets were connected", allTets.size());
1373 
1374  // here the classification should be done
1375 
1376  int ITER = 0, REALCOUNT = 0;
1377  int NB_CORRECTION_OF_CAVITY = 0;
1378  int COUNT_MISS_1 = 0;
1379  int COUNT_MISS_2 = 0;
1380 
1381  double t1 = TimeOfDay();
1382 
1383  // main loop in Delaunay inserstion starts here
1384 
1385  while(1) {
1386  if(maxIter > 0 && ITER >= maxIter) break;
1387  if(allTets.empty()) {
1388  Msg::Warning("No tetrahedra in region %d", gr->tag());
1389  break;
1390  }
1391 
1392  MTet4 *worst = *allTets.begin();
1393 
1394  if(worst->isDeleted()) {
1395  myFactory.Free(worst);
1396  allTets.erase(allTets.begin());
1397  }
1398  else {
1399  if(ITER++ % 500 == 0)
1400  Msg::Info("It. %d - %d nodes created - worst tet radius %g (nodes "
1401  "removed %d %d)",
1402  ITER - 1, REALCOUNT, worst->getRadius(), COUNT_MISS_1,
1403  COUNT_MISS_2);
1404  if(worst->getRadius() < worstTetRadiusTarget) break;
1405  double center[3];
1406  double uvw[3];
1407  MTetrahedron *base = worst->tet();
1408 
1409  double pa[3] = {base->getVertex(0)->x(), base->getVertex(0)->y(),
1410  base->getVertex(0)->z()};
1411  double pb[3] = {base->getVertex(1)->x(), base->getVertex(1)->y(),
1412  base->getVertex(1)->z()};
1413  double pc[3] = {base->getVertex(2)->x(), base->getVertex(2)->y(),
1414  base->getVertex(2)->z()};
1415  double pd[3] = {base->getVertex(3)->x(), base->getVertex(3)->y(),
1416  base->getVertex(3)->z()};
1417 
1418  tetcircumcenter(pa, pb, pc, pd, center, nullptr, nullptr, nullptr);
1419 
1420  // A TEST !!!
1421  std::vector<faceXtet> shell;
1422  std::vector<MTet4 *> cavity;
1423  MVertex vv(center[0], center[1], center[2], worst->onWhat());
1424  findCavity(shell, cavity, &vv, worst);
1425  bool FOUND = false;
1426  for(auto itc = cavity.begin(); itc != cavity.end(); ++itc) {
1427  MTetrahedron *toto = (*itc)->tet();
1428  // (*itc)->setDeleted(false);
1429  toto->xyz2uvw(center, uvw);
1430  if(toto->isInside(uvw[0], uvw[1], uvw[2])) {
1431  worst = (*itc);
1432  FOUND = true;
1433  break;
1434  }
1435  }
1436  // END TEST
1437 
1438  if(FOUND && (!allEmbeddedEdges.empty() || !allEmbeddedFaces.empty())) {
1439  FOUND =
1441  allEmbeddedEdges) &&
1442  isCavityCompatibleWithEmbeddedFace(cavity, shell, allEmbeddedFaces);
1443  }
1444 
1445  bool correctedCavityIncompatibleWithEmbeddedEntities = false;
1446 
1447  if(FOUND) {
1448  MVertex *v =
1449  new MVertex(center[0], center[1], center[2], worst->onWhat());
1450  v->setIndex(NUM++);
1451 #ifdef PRINT_TETS
1452  printTets("before.pos", cavity, true);
1453 #endif
1454  bool starShaped = true;
1455  bool correctCavity = false;
1456  while(1) {
1457  int k = makeCavityStarShaped(shell, cavity, v);
1458  if(k == -1) {
1459  starShaped = false;
1460  break;
1461  }
1462  else if(k == 0)
1463  break;
1464  else if(k == 1)
1465  correctCavity = true;
1466  }
1467  if(correctCavity && starShaped) {
1468  NB_CORRECTION_OF_CAVITY++;
1469  if(!isCavityCompatibleWithEmbeddedEdges(cavity, shell,
1470  allEmbeddedEdges) ||
1471  !isCavityCompatibleWithEmbeddedFace(cavity, shell,
1472  allEmbeddedFaces)) {
1473  correctedCavityIncompatibleWithEmbeddedEntities = true;
1474  }
1475  }
1476  double lc1 = (1 - uvw[0] - uvw[1] - uvw[2]) *
1477  vSizes[worst->tet()->getVertex(0)->getIndex()] +
1478  uvw[0] * vSizes[worst->tet()->getVertex(1)->getIndex()] +
1479  uvw[1] * vSizes[worst->tet()->getVertex(2)->getIndex()] +
1480  uvw[2] * vSizes[worst->tet()->getVertex(3)->getIndex()];
1481  double lc2 =
1482  BGM_MeshSize(worst->onWhat(), 0, 0, center[0], center[1], center[2]);
1483 
1484  if(correctedCavityIncompatibleWithEmbeddedEntities || !starShaped ||
1485  !insertVertexB(shell, cavity, v, lc1, lc2, vSizes, vSizesBGM, worst,
1486  myFactory, allTets, allEmbeddedFaces)) {
1487  COUNT_MISS_1++;
1488  myFactory.changeTetRadius(allTets.begin(), 0.);
1489  for(auto itc = cavity.begin(); itc != cavity.end(); ++itc)
1490  (*itc)->setDeleted(false);
1491  delete v;
1492  NUM--;
1493  }
1494  else {
1495  vSizes.push_back(lc1);
1496  vSizesBGM.push_back(lc2);
1497  REALCOUNT++;
1498  v->onWhat()->mesh_vertices.push_back(v);
1499  }
1500  }
1501 
1502  else {
1503  myFactory.changeTetRadius(allTets.begin(), 0.0);
1504  COUNT_MISS_2++;
1505  for(auto itc = cavity.begin(); itc != cavity.end(); ++itc)
1506  (*itc)->setDeleted(false);
1507  }
1508  }
1509 
1510  // Normally, a tet mesh contains about 6 times more tets than vertices. This
1511  // allows to clean up the set of tets when lots of deleted ones are present
1512  // in the mesh
1513  if(allTets.size() > 7 * vSizes.size() && ITER > 1000) {
1514  memoryCleanup(myFactory, allTets);
1515  }
1516  }
1517 
1518  memoryCleanup(myFactory, allTets);
1519  double t2 = TimeOfDay();
1520  double dt = (t2 - t1);
1521  int COUNT_MISS = COUNT_MISS_1 + COUNT_MISS_2;
1522  Msg::Info("3D refinement terminated (%d nodes total):", (int)vSizes.size());
1523  Msg::Info(" - %d Delaunay cavities modified for star shapeness",
1524  NB_CORRECTION_OF_CAVITY);
1525  Msg::Info(" - %d nodes could not be inserted", COUNT_MISS);
1526  Msg::Info(" - %d tetrahedra created in %g sec. (%d tets/s)", allTets.size(),
1527  dt, (int)(allTets.size() / dt));
1528 
1529  // relocate vertices
1530  int nbReloc = 0;
1531  for(int SM = 0; SM < CTX::instance()->mesh.nbSmoothing; SM++) {
1532  for(auto it = allTets.begin(); it != allTets.end(); ++it) {
1533  if(!(*it)->isDeleted()) {
1534  double qq = (*it)->getQuality();
1535  if(qq < .4)
1536  for(int i = 0; i < 4; i++) {
1537  if(smoothVertex(*it, i, qmTetrahedron::QMTET_GAMMA)) nbReloc++;
1538  }
1539  }
1540  }
1541  }
1542 
1543  while(1) {
1544  if(allTets.begin() == allTets.end()) break;
1545  MTet4 *worst = *allTets.begin();
1546  if(!worst->isDeleted()) {
1547  worst->onWhat()->tetrahedra.push_back(worst->tet());
1548  worst->tet() = nullptr;
1549  }
1550  myFactory.Free(worst);
1551  allTets.erase(allTets.begin());
1552  }
1553 
1555 }
1556 
1557 // do a 3D delaunay mesh assuming a set of vertices
1558 
1559 void delaunayMeshIn3D(std::vector<MVertex *> &v,
1560  std::vector<MTetrahedron *> &result, bool removeBox)
1561 {
1562  Msg::Info("Tetrahedrizing %d nodes...", v.size());
1563  double t1 = Cpu(), w1 = TimeOfDay();
1564  delaunayTriangulation(1, 1, v, result, removeBox);
1565  double t2 = Cpu(), w2 = TimeOfDay();
1566  Msg::Info("Done tetrahedrizing %d nodes (Wall %gs, CPU %gs)", v.size(),
1567  w2 - w1, t2 - t1);
1568 }
tetcircumcenter
double tetcircumcenter(double a[3], double b[3], double c[3], double d[3], double circumcenter[3], double *xi, double *eta, double *zeta)
Definition: meshGRegionDelaunayInsertion.cpp:1058
non_recursive_classify
void non_recursive_classify(MTet4 *t, std::list< MTet4 * > &theRegion, std::set< GFace * > &faces_bound, GRegion *bidon, GModel *model, const fs_cont &search)
Definition: meshGRegionDelaunayInsertion.cpp:648
MTriangle.h
isCavityCompatibleWithEmbeddedEdges
static int isCavityCompatibleWithEmbeddedEdges(std::vector< MTet4 * > &cavity, std::vector< faceXtet > &shell, edgeContainerB &allEmbeddedEdges)
Definition: meshGRegionDelaunayInsertion.cpp:1145
TimeOfDay
double TimeOfDay()
Definition: OS.cpp:399
MEdge::getSortedVertex
MVertex * getSortedVertex(std::size_t i) const
Definition: MEdge.h:40
sqr
static int sqr(int x)
Definition: gl2gif.cpp:266
MTetrahedron::xyz2uvw
virtual void xyz2uvw(double xyz[3], double uvw[3]) const
Definition: MTetrahedron.cpp:121
MTet4::base
MTetrahedron * base
Definition: meshGRegionDelaunayInsertion.h:52
MEdge
Definition: MEdge.h:14
contextMeshOptions::nbSmoothing
int nbSmoothing
Definition: Context.h:29
connectTets_vector2_templ
void connectTets_vector2_templ(std::size_t _size, ITER beg, ITER end, std::vector< faceXtet > &conn)
Definition: meshGRegionDelaunayInsertion.cpp:223
setLcs
static void setLcs(MTriangle *t, std::map< MVertex *, double, MVertexPtrLessThan > &vSizes, std::set< MVertex *, MVertexPtrLessThan > &bndVertices)
Definition: meshGRegionDelaunayInsertion.cpp:519
GRegion::method
char method
Definition: GRegion.h:146
meshGRegionDelaunayInsertion.h
distance
double distance(MVertex *v1, MVertex *v2)
Definition: MVertex.h:245
MTetrahedron
Definition: MTetrahedron.h:34
meshGRegionLocalMeshMod.h
GFace
Definition: GFace.h:33
GFace::triangles
std::vector< MTriangle * > triangles
Definition: GFace.h:428
edgeContainerB::addNewEdge
bool addNewEdge(const MEdge &e)
Definition: meshGRegionDelaunayInsertion.cpp:101
Msg::Info
static void Info(const char *fmt,...)
Definition: GmshMessage.cpp:587
GEntity::model
GModel * model() const
Definition: GEntity.h:277
OS.h
faceXtet::t1
MTet4 * t1
Definition: meshGRegionDelaunayInsertion.cpp:176
Msg::Debug
static void Debug(const char *fmt,...)
Definition: GmshMessage.cpp:752
robustPredicates.h
c
static double c(int i, int j, fullMatrix< double > &CA, const std::vector< SPoint3 > &P, const std::vector< SPoint3 > &Q)
Definition: discreteFrechetDistance.cpp:15
MESH_TRANSFINITE
#define MESH_TRANSFINITE
Definition: GmshDefines.h:259
MVertex
Definition: MVertex.h:24
verifyShell
static bool verifyShell(MVertex *v, MTet4 *t, std::vector< faceXtet > &shell)
Definition: meshGRegionDelaunayInsertion.cpp:347
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
edgeContainerB::H
std::size_t H(const MEdge &e) const
Definition: meshGRegionDelaunayInsertion.cpp:87
LegendrePolynomials::f
void f(int n, double u, double *val)
Definition: orthogonalBasis.cpp:77
findInFaceSearchStructure
GFace * findInFaceSearchStructure(MVertex *p1, MVertex *p2, MVertex *p3, const fs_cont &search)
Definition: meshGRegion.cpp:333
edgeContainerB::_hash
std::vector< std::vector< MEdge > > _hash
Definition: meshGRegionDelaunayInsertion.cpp:79
MVertex::getNum
std::size_t getNum() const
Definition: MVertex.h:86
removeFromCavity
static void removeFromCavity(std::vector< faceXtet > &shell, std::vector< MTet4 * > &cavity, faceXtet &toRemove)
Definition: meshGRegionDelaunayInsertion.cpp:303
MTet4::setNeigh
void setNeigh(int iN, MTet4 *n)
Definition: meshGRegionDelaunayInsertion.h:170
createAllEmbeddedEdges
static void createAllEmbeddedEdges(GRegion *gr, std::set< MEdge, MEdgeLessThan > &allEmbeddedEdges)
Definition: meshGRegionDelaunayInsertion.cpp:115
GRegion::getNumMeshElements
std::size_t getNumMeshElements() const
Definition: GRegion.cpp:60
faceXtet::v
MVertex * v[3]
Definition: meshGRegionDelaunayInsertion.cpp:175
MTriangle::getVertex
virtual MVertex * getVertex(int num)
Definition: MTriangle.h:62
memoryCleanup
static void memoryCleanup(MTet4Factory &myFactory, std::set< MTet4 *, compareTet4Ptr > &allTets)
Definition: meshGRegionDelaunayInsertion.cpp:1129
MVertex::onWhat
GEntity * onWhat() const
Definition: MVertex.h:82
edgeContainerB::_size_obj
std::size_t _size_obj
Definition: meshGRegionDelaunayInsertion.cpp:80
GmshMessage.h
MLine.h
edges
static int edges[6][2]
Definition: meshGRegionLocalMeshMod.cpp:23
w1
const double w1
Definition: GaussQuadratureHex.cpp:18
edgeSwap
bool edgeSwap(std::vector< MTet4 * > &newTets, MTet4 *tet, int iLocalEdge, const qmTetrahedron::Measures &cr, const std::set< MFace, MFaceLessThan > &embeddedFaces)
Definition: meshGRegionLocalMeshMod.cpp:237
edgeContainerB::find
bool find(const MEdge &e) const
Definition: meshGRegionDelaunayInsertion.cpp:93
MTet4Factory::Free
void Free(MTet4 *t)
Definition: meshGRegionDelaunayInsertion.h:296
delaunay3d.h
insertVertexB
bool insertVertexB(std::vector< faceXtet > &shell, std::vector< MTet4 * > &cavity, MVertex *v, double lc1, double lc2, std::vector< double > &vSizes, std::vector< double > &vSizesBGM, MTet4 *t, MTet4Factory &myFactory, std::set< MTet4 *, compareTet4Ptr > &allTets, const std::set< MFace, MFaceLessThan > &allEmbeddedFaces)
Definition: meshGRegionDelaunayInsertion.cpp:459
MTet4
Definition: meshGRegionDelaunayInsertion.h:46
insertVerticesInRegion
void insertVerticesInRegion(GRegion *gr, int maxIter, double worstTetRadiusTarget, bool _classify, splitQuadRecovery *sqr)
Definition: meshGRegionDelaunayInsertion.cpp:1217
Fopen
FILE * Fopen(const char *f, const char *mode)
Definition: OS.cpp:273
faceXtet::unsorted
MVertex * unsorted[3]
Definition: meshGRegionDelaunayInsertion.cpp:175
extendCavity
static void extendCavity(std::vector< faceXtet > &shell, std::vector< MTet4 * > &cavity, faceXtet &toExtend)
Definition: meshGRegionDelaunayInsertion.cpp:328
connectTets
void connectTets(ITER beg, ITER end, const std::set< MFace, MFaceLessThan > *allEmbeddedFaces=nullptr)
Definition: meshGRegionDelaunayInsertion.cpp:250
CTX::instance
static CTX * instance()
Definition: Context.cpp:122
getRegionFromBoundingFaces
GRegion * getRegionFromBoundingFaces(GModel *model, std::set< GFace * > &faces_bound)
Definition: meshGRegionDelaunayInsertion.cpp:620
GRegion::faces
virtual std::vector< GFace * > faces() const
Definition: GRegion.h:64
GRegion::hexahedra
std::vector< MHexahedron * > hexahedra
Definition: GRegion.h:164
MElement::getEdge
virtual MEdge getEdge(int num) const =0
GModel::lastFace
fiter lastFace()
Definition: GModel.h:359
GRegion::extrude
ExtrudeParams * extrude
Definition: GRegion.h:148
conn
Definition: delaunay3d.cpp:257
MFace
Definition: MFace.h:20
GRegion.h
MVertex::setIndex
void setIndex(long int index)
Definition: MVertex.h:94
ExtrudeParams::mesh
struct ExtrudeParams::@14 mesh
MEdge::getVertex
MVertex * getVertex(std::size_t i) const
Definition: MEdge.h:39
delaunayMeshIn3D
void delaunayMeshIn3D(std::vector< MVertex * > &v, std::vector< MTetrahedron * > &result, bool removeBox)
Definition: meshGRegionDelaunayInsertion.cpp:1559
vertex_comparator::operator()
bool operator()(MVertex *const a, MVertex *const b) const
Definition: meshGRegionDelaunayInsertion.cpp:168
GEntity::mesh_vertices
std::vector< MVertex * > mesh_vertices
Definition: GEntity.h:56
MTet4::tet
MTetrahedron * tet() const
Definition: meshGRegionDelaunayInsertion.h:167
edgeContainerB
Definition: meshGRegionDelaunayInsertion.cpp:78
MTetrahedron::getVertex
virtual MVertex * getVertex(int num)
Definition: MTetrahedron.h:67
MTet4::onWhat
GRegion * onWhat() const
Definition: meshGRegionDelaunayInsertion.h:160
Numeric.h
MElement::getFace
virtual MFace getFace(int num) const =0
GModel
Definition: GModel.h:44
FF
FILE * FF
Definition: meshGFacePack.cpp:175
Cpu
double Cpu()
Definition: OS.cpp:366
BGM_MeshSize
double BGM_MeshSize(GEntity *ge, double U, double V, double X, double Y, double Z)
Definition: BackgroundMeshTools.cpp:255
connectTets_vector2
void connectTets_vector2(std::list< MTet4 * > &l, std::vector< faceXtet > &conn)
Definition: meshGRegionDelaunayInsertion.cpp:289
Extend2dMeshIn3dVolumes
bool Extend2dMeshIn3dVolumes()
Definition: BackgroundMeshTools.cpp:345
ExtrudeParams.h
robustPredicates::insphere
REAL insphere(REAL *pa, REAL *pb, REAL *pc, REAL *pd, REAL *pe)
Definition: robustPredicates.cpp:4200
GModel::firstFace
fiter firstFace()
Definition: GModel.h:355
faceXtet::operator==
bool operator==(const faceXtet &other) const
Definition: meshGRegionDelaunayInsertion.cpp:200
GRegion::edges
virtual std::vector< GEdge * > const & edges() const
Definition: GRegion.cpp:459
CTX::mesh
contextMeshOptions mesh
Definition: Context.h:313
adaptMeshGRegion::operator()
void operator()(GRegion *)
Definition: meshGRegionDelaunayInsertion.cpp:686
GEntity::tag
int tag() const
Definition: GEntity.h:280
MTet4Factory::getAllTets
container & getAllTets()
Definition: meshGRegionDelaunayInsertion.h:314
splitQuadRecovery
Definition: meshGRegion.h:72
edgeContainerB::edgeContainerB
edgeContainerB(std::size_t N=1000000)
Definition: meshGRegionDelaunayInsertion.cpp:82
GRegion
Definition: GRegion.h:28
createAllEmbeddedFaces
static void createAllEmbeddedFaces(GRegion *gr, std::set< MFace, MFaceLessThan > &allEmbeddedFaces)
Definition: meshGRegionDelaunayInsertion.cpp:139
contextMeshOptions::optimizeThreshold
double optimizeThreshold
Definition: Context.h:22
ExtrudeParams::ExtrudeMesh
bool ExtrudeMesh
Definition: ExtrudeParams.h:36
GRegion::prisms
std::vector< MPrism * > prisms
Definition: GRegion.h:165
MTriangle
Definition: MTriangle.h:26
length
double length(Quaternion &q)
Definition: Camera.cpp:346
faceXtet::faceXtet
faceXtet(MTet4 *_t=nullptr, int iFac=0)
Definition: meshGRegionDelaunayInsertion.cpp:179
GRegion::pyramids
std::vector< MPyramid * > pyramids
Definition: GRegion.h:166
GModel::firstRegion
riter firstRegion()
Definition: GModel.h:354
GModel::lastRegion
riter lastRegion()
Definition: GModel.h:358
faceXtet::getVertex
MVertex * getVertex(int i) const
Definition: meshGRegionDelaunayInsertion.cpp:188
MEdge.h
MVertex::getIndex
long int getIndex() const
Definition: MVertex.h:93
Context.h
GRegion::embeddedEdges
std::vector< GEdge * > & embeddedEdges()
Definition: GRegion.h:80
faceSwap
bool faceSwap(std::vector< MTet4 * > &newTets, MTet4 *t1, int iLocalFace, const qmTetrahedron::Measures &cr, const std::set< MFace, MFaceLessThan > &embeddedFaces)
Definition: meshGRegionLocalMeshMod.cpp:390
MTet4Factory
Definition: meshGRegionDelaunayInsertion.h:230
MTriangle::getEdge
virtual MEdge getEdge(int num) const
Definition: MTriangle.h:74
GRegion::embeddedFaces
std::vector< GFace * > & embeddedFaces()
Definition: GRegion.h:81
GRegion::meshAttributes
struct GRegion::@20 meshAttributes
MTet4::setOnWhat
void setOnWhat(GRegion *g)
Definition: meshGRegionDelaunayInsertion.h:161
faceXtet::i1
int i1
Definition: meshGRegionDelaunayInsertion.cpp:177
isCavityCompatibleWithEmbeddedFace
static int isCavityCompatibleWithEmbeddedFace(const std::vector< MTet4 * > &cavity, const std::vector< faceXtet > &shell, const std::set< MFace, MFaceLessThan > &allEmbeddedFaces)
Definition: meshGRegionDelaunayInsertion.cpp:1171
hypotenuse
double hypotenuse(T const &a, T const &b, T const &c)
Definition: Numeric.h:23
completeTheSetOfFaces
static void completeTheSetOfFaces(GModel *model, std::set< GFace * > &faces_bound)
Definition: meshGRegionDelaunayInsertion.cpp:604
qmTetrahedron::QMTET_GAMMA
@ QMTET_GAMMA
Definition: qualityMeasures.h:68
buildFaceSearchStructure
bool buildFaceSearchStructure(GModel *model, fs_cont &search, bool onlyTriangles)
Definition: meshGRegion.cpp:286
meshGRegion.h
makeCavityStarShaped
int makeCavityStarShaped(std::vector< faceXtet > &shell, std::vector< MTet4 * > &cavity, MVertex *v)
Definition: meshGRegionDelaunayInsertion.cpp:367
fs_cont
std::map< MFace, GFace *, MFaceLessThan > fs_cont
Definition: meshGRegion.h:60
edgeContainerB::empty
bool empty() const
Definition: meshGRegionDelaunayInsertion.cpp:99
robustPredicates::orient3d
REAL orient3d(REAL *pa, REAL *pb, REAL *pc, REAL *pd)
Definition: robustPredicates.cpp:2321
GModel.h
vertex_comparator
Definition: meshGRegionDelaunayInsertion.cpp:167
MTet4::inCircumSphere
int inCircumSphere(const double *p) const
Definition: meshGRegionDelaunayInsertion.cpp:150
MVertex::y
double y() const
Definition: MVertex.h:61
optimizeMesh
void optimizeMesh(GRegion *gr, const qmTetrahedron::Measures &qm)
Definition: meshGRegionDelaunayInsertion.cpp:876
smoothVertex
bool smoothVertex(MTet4 *t, int iVertex, const qmTetrahedron::Measures &cr)
Definition: meshGRegionLocalMeshMod.cpp:624
MTet4Factory::Create
MTet4 * Create(MTetrahedron *t, std::vector< double > &sizes, std::vector< double > &sizesBGM)
Definition: meshGRegionDelaunayInsertion.h:273
findCavity
void findCavity(std::vector< faceXtet > &shell, std::vector< MTet4 * > &cavity, MVertex *v, MTet4 *t)
Definition: meshGRegionDelaunayInsertion.cpp:403
_deleteUnusedVertices
static void _deleteUnusedVertices(GRegion *gr)
Definition: meshGRegionDelaunayInsertion.cpp:1198
qmTetrahedron::Measures
Measures
Definition: qualityMeasures.h:68
MTetrahedron::isInside
virtual bool isInside(double u, double v, double w) const
Definition: MTetrahedron.h:174
ExtrudeParams
Definition: ExtrudeParams.h:26
MTet4::getRadius
double getRadius() const
Definition: meshGRegionDelaunayInsertion.h:164
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
faceXtet::visible
bool visible(MVertex *v)
Definition: meshGRegionDelaunayInsertion.cpp:207
MTet4Factory::changeTetRadius
void changeTetRadius(iterator it, double r)
Definition: meshGRegionDelaunayInsertion.h:307
faceXtet
Definition: meshGRegionDelaunayInsertion.cpp:174
faceXtet::operator<
bool operator<(const faceXtet &other) const
Definition: meshGRegionDelaunayInsertion.cpp:190
MTet4::getNeigh
MTet4 * getNeigh(int iN) const
Definition: meshGRegionDelaunayInsertion.h:171
GRegion::getMeshElement
MElement * getMeshElement(std::size_t index) const
Definition: GRegion.cpp:127
GRegion::tetrahedra
std::vector< MTetrahedron * > tetrahedra
Definition: GRegion.h:163
MTet4::radiusNorm
static int radiusNorm
Definition: meshGRegionDelaunayInsertion.h:57
MTet4::isDeleted
bool isDeleted() const
Definition: meshGRegionDelaunayInsertion.h:162
edgeContainerB::_size
std::size_t _size
Definition: meshGRegionDelaunayInsertion.cpp:80
delaunayTriangulation
static void delaunayTriangulation(const int numThreads, const int nptsatonce, std::vector< Vert * > &S, Vert *box[8], tetContainer &allocator)
Definition: delaunay3d.cpp:1197
MTet4::setDeleted
void setDeleted(bool const d)
Definition: meshGRegionDelaunayInsertion.h:194
MVertex::x
double x() const
Definition: MVertex.h:60
GEntity::addMeshVertex
void addMeshVertex(MVertex *v)
Definition: GEntity.h:382
faces
static int faces[4][3]
Definition: meshGRegionDelaunayInsertion.cpp:165
collapseVertex
bool collapseVertex(std::vector< MTet4 * > &newTets, MTet4 *t, int iVertex, int iTarget, const qmTetrahedron::Measures &cr, const localMeshModAction action, double *minQual)
Definition: meshGRegionLocalMeshMod.cpp:529