28 #ifdef DEBUG_BOUNDARY_RECOVERY
30 static void testIfBoundaryIsRecovered(
GRegion *gr)
32 std::vector<GEdge *>
const &e = gr->
edges();
33 std::vector<GFace *>
f = gr->
faces();
35 std::map<MEdge, GEdge *, MEdgeLessThan>
edges;
36 std::map<MFace, GFace *, MFaceLessThan>
faces;
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)),
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)),
57 Msg::Info(
"Searching for %d mesh edges and %d mesh faces among %d elements "
69 Msg::Info(
"All edges and faces are present in the initial mesh");
72 Msg::Error(
"All edges and faces are not present in the initial mesh");
79 std::vector<std::vector<MEdge> >
_hash;
95 const std::vector<MEdge> &v =
_hash[
H(e)];
96 return std::find(v.begin(), v.end(), e) != v.end();
103 std::vector<MEdge> &v =
_hash[
H(e)];
105 if(std::find(v.begin(), v.end(), e) != v.end())
return false;
116 std::set<MEdge, MEdgeLessThan> &allEmbeddedEdges)
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)));
130 for(
auto it = e.begin(); it != e.end(); ++it) {
131 for(std::size_t i = 0; i < (*it)->lines.size(); i++) {
133 MEdge((*it)->lines[i]->getVertex(0), (*it)->lines[i]->getVertex(1)));
140 std::set<MFace, MFaceLessThan> &allEmbeddedFaces)
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));
162 return (result > 0) ? 1 : 0;
165 static int faces[4][3] = {{0, 1, 2}, {0, 2, 3}, {0, 3, 1}, {1, 3, 2}};
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;
202 return (
v[0]->getNum() == other.
v[0]->
getNum() &&
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()};
222 template <
class ITER>
224 std::vector<faceXtet> &
conn)
227 conn.reserve(4 * _size);
228 for(ITER IT = beg; IT != end; ++IT) {
231 for(
int j = 0; j < 4; j++) {
conn.push_back(
faceXtet(t, j)); }
234 if(!
conn.size())
return;
236 std::sort(
conn.begin(),
conn.end());
238 for(std::size_t i = 0; i <
conn.size() - 1; i++) {
241 if(f1 == f2 && f1.
t1 != f2.
t1) {
249 template <
class ITER>
252 const std::set<MFace, MFaceLessThan> *allEmbeddedFaces =
nullptr)
254 std::set<faceXtet>
conn;
256 if(!(*beg)->isDeleted()) {
257 for(
int i = 0; i < 4; i++) {
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())
266 else if(found->t1 != *beg) {
267 found->t1->setNeigh(found->i1, *beg);
268 (*beg)->setNeigh(i, found->t1);
278 const std::set<MFace, MFaceLessThan> *embeddedFaces)
284 const std::set<MFace, MFaceLessThan> *embeddedFaces)
304 std::vector<MTet4 *> &cavity,
faceXtet &toRemove)
308 std::remove_if(cavity.begin(), cavity.end(),
309 std::bind2nd(std::equal_to<MTet4 *>(), toRemove.
t1)));
311 for(
int i = 0; i < 4; i++) {
313 auto it = std::find(shell.begin(), shell.end(), fxt2);
314 if(it == shell.end()) {
317 for(
int j = 0; j < 4; j++) {
319 if(fxt3 == fxt2) { shell.push_back(fxt3); }
329 std::vector<MTet4 *> &cavity,
faceXtet &toExtend)
333 for(
int i = 0; i < 4; i++) {
335 auto it = std::find(shell.begin(), shell.end(), fxt);
336 if(it == shell.end())
337 shell.push_back(fxt);
341 cavity.push_back(opposite);
351 int NBAD_BEFORE = 0, NBAD_AFTER = 0;
352 for(
int i = 0; i < 4; i++) {
354 bool starShaped = fxt.
visible(v);
356 auto its = std::find(shell.begin(), shell.end(), fxt);
357 if(its == shell.end())
364 return (NBAD_AFTER < NBAD_BEFORE);
368 std::vector<MTet4 *> &cavity,
MVertex *v)
370 std::vector<faceXtet> wrong;
371 for(
auto it = shell.begin(); it != shell.end(); ++it) {
373 bool starShaped = fxt.
visible(v);
374 if(!starShaped) { wrong.push_back(fxt); }
376 if(wrong.empty())
return 0;
380 while(!wrong.empty()) {
382 if(std::find(shell.begin(), shell.end(), fxt) != shell.end()) {
396 wrong.erase(wrong.begin());
403 void findCavity(std::vector<faceXtet> &shell, std::vector<MTet4 *> &cavity,
409 std::queue<MTet4 *> cavity_queue;
411 if(!cavity.empty()) { cavity_queue.push(cavity.back()); }
413 while(!cavity_queue.empty()) {
414 for(
int i = 0; i < 4; i++) {
416 if(!neighbour) { shell.push_back(
faceXtet(cavity_queue.front(), i)); }
419 (neighbour->
onWhat() == cavity_queue.front()->onWhat())) {
422 cavity.push_back(neighbour);
423 cavity_queue.push(neighbour);
426 shell.push_back(
faceXtet(cavity_queue.front(), i));
436 static void printTets(
const char *fn, std::list<MTet4 *> &cavity,
441 fprintf(
f,
"View \"\"{\n");
442 auto ittet = cavity.begin();
443 auto ittete = cavity.end();
444 while(ittet != ittete) {
448 t->
writePOS(
f,
false,
false,
false,
false,
true,
false);
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,
463 std::set<MTet4 *, compareTet4Ptr> &allTets,
464 const std::set<MFace, MFaceLessThan> &allEmbeddedFaces)
466 std::vector<MTet4 *> new_cavity;
467 new_cavity.reserve(shell.size());
469 std::vector<MTet4 *> new_tets;
470 new_tets.reserve(shell.size());
472 auto it = shell.begin();
474 bool onePointIsTooClose =
false;
475 while(it != shell.end()) {
477 new MTetrahedron(it->getVertex(0), it->getVertex(1), it->getVertex(2), v);
478 MTet4 *t4 = myFactory.
Create(tr, vSizes, vSizesBGM, lc1, lc2);
484 onePointIsTooClose =
true;
486 new_tets.push_back(t4);
487 new_cavity.push_back(t4);
491 if(otherSide) new_cavity.push_back(otherSide);
494 if(!onePointIsTooClose) {
495 if(allEmbeddedFaces.empty()) {
496 std::vector<faceXtet>
conn;
500 connectTets(new_cavity.begin(), new_cavity.end(), &allEmbeddedFaces);
503 allTets.insert(new_tets.begin(), new_tets.end());
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);
520 std::map<MVertex *, double, MVertexPtrLessThan> &vSizes,
521 std::set<MVertex *, MVertexPtrLessThan> &bndVertices)
523 for(
int i = 0; i < 3; i++) {
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);
536 if(iti == vSizes.end() || iti->second > l) vSizes[vi] = l;
537 if(itj == vSizes.end() || itj->second > l) vSizes[vj] = l;
541 if(iti == vSizes.end() || iti->second < l) vSizes[vi] = l;
542 if(itj == vSizes.end() || itj->second < l) vSizes[vj] = l;
574 std::map<MVertex *, double, MVertexPtrLessThan> &vSizes,
575 std::set<MVertex *, MVertexPtrLessThan> &bndVertices)
577 for(
int i = 0; i < 4; i++) {
578 for(
int j = i + 1; j < 4; j++) {
583 if(bndVertices.find(vi) == bndVertices.end()) {
584 auto iti = vSizes.find(vi);
589 if(iti == vSizes.end() || iti->second >
length) { vSizes[vi] =
length; }
592 if(bndVertices.find(vj) == bndVertices.end()) {
593 auto itj = vSizes.find(vj);
598 if(itj == vSizes.end() || itj->second >
length) { vSizes[vj] =
length; }
606 std::set<GFace *> toAdd;
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);
617 faces_bound.insert(toAdd.begin(), toAdd.end());
621 std::set<GFace *> &faces_bound)
634 std::vector<GFace *> _faces = (*git)->faces();
635 if(_faces.size() == faces_bound.size()) {
637 for(
auto it = _faces.begin(); it != _faces.end(); ++it) {
638 if(faces_bound.find(*it) == faces_bound.end()) ok =
false;
649 std::set<GFace *> &faces_bound,
GRegion *bidon,
652 std::stack<MTet4 *> _stackounette;
653 _stackounette.push(t);
655 bool touchesOutsideBox =
false;
657 while(!_stackounette.empty()) {
658 t = _stackounette.top();
661 Msg::Warning(
"A tetrahedron is not connected to a boundary face");
662 touchesOutsideBox =
true;
665 theRegion.push_back(t);
667 bool FF[4] = {0, 0, 0, 0};
668 for(
int i = 0; i < 4; i++) {
674 if(faces_bound.find(gfound) == faces_bound.end())
675 faces_bound.insert(gfound);
678 for(
int i = 0; i < 4; i++) {
679 if(!
FF[i]) _stackounette.push(t->
getNeigh(i));
683 if(touchesOutsideBox) faces_bound.clear();
690 typedef std::list<MTet4 *> CONTAINER;
692 for(std::size_t i = 0; i < gr->
tetrahedra.size(); i++) {
697 std::set<MFace, MFaceLessThan> allEmbeddedFaces;
699 std::set<MEdge, MEdgeLessThan> allEmbeddedEdges;
702 connectTets(allTets.begin(), allTets.end(), &allEmbeddedFaces);
705 std::vector<MTet4 *> illegals;
706 const int nbRanges = 10;
707 int quality_ranges[nbRanges];
709 double totalVolumeb = 0.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);
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]++;
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,
740 double sliverLimit = 0.2;
742 int nbESwap = 0, nbFSwap = 0, nbReloc = 0, nbCollapse = 0;
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++) {
759 for(
auto it = allTets.begin(); it != allTets.end(); ++it) {
760 if(!(*it)->isDeleted()) {
761 double qq = (*it)->getQuality();
763 for(
int i = 0; i < 4; i++) {
764 if(
faceSwap(newTets, *it, i, qm, allEmbeddedFaces)) {
774 for(
int i = 0; i < nbRanges; i++) quality_ranges[i] = 0;
776 for(
auto it = allTets.begin(); it != allTets.end(); ++it) {
777 if(!(*it)->isDeleted()) {
778 double qq = (*it)->getQuality();
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)) {
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]++;
800 if(!newTets.size())
break;
803 for(std::size_t i = 0; i < newTets.size(); i++) {
804 if(!newTets[i]->isDeleted()) { allTets.push_back(newTets[i]); }
806 delete newTets[i]->tet();
812 for(
auto it = allTets.begin(); it != allTets.end(); ++it) {
813 if(!(*it)->isDeleted()) {
814 double qq = (*it)->getQuality();
816 for(
int i = 0; i < 4; i++) {
822 double totalVolumeb = 0.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);
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);
846 for(std::size_t i = 0; i < illegals.size(); i++)
847 if(!(illegals[i]->isDeleted())) nbSlivers++;
850 Msg::Info(
"%d illegal tets are still in the mesh, trying to remove them",
854 Msg::Info(
"No illegal tets in the mesh :-)", nbSlivers);
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,
864 for(
auto it = allTets.begin(); it != allTets.end(); ++it) {
865 if(!(*it)->isDeleted()) {
880 if(qMin <= 0.0)
return;
884 typedef std::vector<MTet4 *> CONTAINER;
886 for(std::size_t i = 0; i < gr->
tetrahedra.size(); i++) {
889 allTets.push_back(t);
893 std::set<MFace, MFaceLessThan> allEmbeddedFaces;
896 std::set<MEdge, MEdgeLessThan> allEmbeddedEdges;
899 if(allEmbeddedFaces.empty()) {
900 std::vector<faceXtet>
conn;
905 connectTets(allTets.begin(), allTets.end(), &allEmbeddedFaces);
909 std::vector<MTet4 *> illegals;
910 const int nbRanges = 10;
911 int quality_ranges[nbRanges];
913 double totalVolumeb = 0.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);
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]++;
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,
944 double sliverLimit = 0.001;
945 int nbESwap = 0, nbReloc = 0;
948 std::set<MTetrahedron*> to_delete;
951 std::vector<MTet4 *> newTets;
954 for(
int i = 0; i < nbRanges; i++) quality_ranges[i] = 0;
956 for(
auto it = allTets.begin(); it != allTets.end(); ++it) {
957 if(!(*it)->isDeleted()) {
958 double qq = (*it)->getQuality();
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)) {
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]++;
981 if(!newTets.size()) {
break; }
984 for(std::size_t i = 0; i < newTets.size(); i++) {
985 if(!newTets[i]->isDeleted()) { allTets.push_back(newTets[i]); }
987 to_delete.insert(newTets[i]->tet());
994 for(
auto it = allTets.begin(); it != allTets.end(); ++it) {
995 if(!(*it)->isDeleted()) {
996 double qq = (*it)->getQuality();
998 for(
int i = 0; i < 4; i++) {
1006 double totalVolumeb = 0.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);
1017 totalVolumeb += vol;
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,
1026 if(worstA != 0.0 && worst - worstA < 1.e-6)
break;
1030 for(
auto t : to_delete)
delete t;
1032 if(illegals.size()) {
1033 Msg::Warning(
"%d ill-shaped tets are still in the mesh", illegals.size());
1036 Msg::Info(
"No ill-shaped tets in the mesh :-)");
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,
1046 for(
auto it = allTets.begin(); it != allTets.end(); ++it) {
1047 if(!(*it)->isDeleted()) {
1059 double circumcenter[3],
double *xi,
double *eta,
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;
1068 double xcirca, ycirca, zcirca;
1081 balength = xba * xba + yba * yba + zba * zba;
1082 calength = xca * xca + yca * yca + zca * zca;
1083 dalength = xda * xda + yda * yda + zda * zda;
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;
1100 denominator = 0.5 / xxx;
1103 xcirca = (balength * xcrosscd + calength * xcrossdb + dalength * xcrossbc) *
1105 ycirca = (balength * ycrosscd + calength * ycrossdb + dalength * ycrossbc) *
1107 zcirca = (balength * zcrosscd + calength * zcrossdb + dalength * zcrossbc) *
1109 circumcenter[0] = xcirca + a[0];
1110 circumcenter[1] = ycirca + a[1];
1111 circumcenter[2] = zcirca + a[2];
1113 if(xi != (
double *)
nullptr) {
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);
1130 std::set<MTet4 *, compareTet4Ptr> &allTets)
1133 auto itd = allTets.begin();
1134 while(itd != allTets.end()) {
1135 if((*itd)->isDeleted()) {
1136 myFactory.
Free((*itd));
1137 allTets.erase(itd++);
1146 std::vector<faceXtet> &shell,
1149 if(allEmbeddedEdges.
empty())
return 1;
1150 std::vector<MEdge> ed;
1151 ed.reserve(shell.size() * 3);
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]));
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)) {
1172 const std::vector<MTet4 *> &cavity,
const std::vector<faceXtet> &shell,
1173 const std::set<MFace, MFaceLessThan> &allEmbeddedFaces)
1175 if(allEmbeddedFaces.empty())
return 1;
1176 std::vector<MFace> shellFaces;
1177 shellFaces.reserve(shell.size());
1179 for(
auto it = shell.begin(); it != shell.end(); it++) {
1181 shellFaces.push_back(
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)) {
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));
1218 double worstTetRadiusTarget,
bool _classify,
1221 #ifdef DEBUG_BOUNDARY_RECOVERY
1222 testIfBoundaryIsRecovered(gr);
1225 std::vector<double> vSizes, vSizesBGM;
1227 std::set<MTet4 *, compareTet4Ptr> &allTets = myFactory.
getAllTets();
1232 std::map<MVertex *, double, MVertexPtrLessThan> vSizesMap;
1233 std::set<MVertex *, MVertexPtrLessThan> bndVertices;
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);
1247 auto iti = vSizesMap.find(vi);
1248 auto itj = vSizesMap.find(vj);
1251 if(iti == vSizesMap.end() || iti->second > l) vSizesMap[vi] = l;
1252 if(itj == vSizesMap.end() || itj->second > l) vSizesMap[vj] = l;
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;
1271 for(std::size_t i = 0; i < gf->
triangles.size(); i++) {
1275 for(std::size_t i = 0; i < gr->
tetrahedra.size(); i++)
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);
1285 for(std::size_t i = 0; i < gr->
tetrahedra.size(); i++) {
1300 if(
sqr) search.insert(
sqr->getTri().begin(),
sqr->getTri().end());
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;
1308 Msg::Debug(
"start with a non classified tet");
1312 Msg::Debug(
"Found %d tets with %d faces (Wall %gs, CPU %gs)",
1313 theRegion.size(), faces_bound.size(), _w2 - _w1, _t2 - _t1);
1316 if(myGRegion && myGRegion->
tetrahedra.empty()) {
1320 for(
auto it2 = theRegion.begin(); it2 != theRegion.end(); ++it2) {
1321 (*it2)->setOnWhat(myGRegion);
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) {
1330 (*itv)->setEntity(myGRegion);
1338 for(
auto it2 = theRegion.begin(); it2 != theRegion.end(); ++it2)
1339 (*it2)->setDeleted(
true);
1347 for(
auto it = allTets.begin(); it != allTets.end(); ++it)
1348 (*it)->setOnWhat(gr);
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);
1358 std::set<MFace, MFaceLessThan> allEmbeddedFaces;
1362 for(
auto e : (*it)->embeddedEdges())
1363 N += e->getNumMeshElements();
1371 connectTets(allTets.begin(), allTets.end(), &allEmbeddedFaces);
1372 Msg::Debug(
"All %d tets were connected", allTets.size());
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;
1386 if(maxIter > 0 && ITER >= maxIter)
break;
1387 if(allTets.empty()) {
1392 MTet4 *worst = *allTets.begin();
1395 myFactory.
Free(worst);
1396 allTets.erase(allTets.begin());
1399 if(ITER++ % 500 == 0)
1400 Msg::Info(
"It. %d - %d nodes created - worst tet radius %g (nodes "
1402 ITER - 1, REALCOUNT, worst->
getRadius(), COUNT_MISS_1,
1404 if(worst->
getRadius() < worstTetRadiusTarget)
break;
1421 std::vector<faceXtet> shell;
1422 std::vector<MTet4 *> cavity;
1423 MVertex vv(center[0], center[1], center[2], worst->
onWhat());
1426 for(
auto itc = cavity.begin(); itc != cavity.end(); ++itc) {
1430 if(toto->
isInside(uvw[0], uvw[1], uvw[2])) {
1438 if(FOUND && (!allEmbeddedEdges.
empty() || !allEmbeddedFaces.empty())) {
1441 allEmbeddedEdges) &&
1445 bool correctedCavityIncompatibleWithEmbeddedEntities =
false;
1449 new MVertex(center[0], center[1], center[2], worst->
onWhat());
1452 printTets(
"before.pos", cavity,
true);
1454 bool starShaped =
true;
1455 bool correctCavity =
false;
1465 correctCavity =
true;
1467 if(correctCavity && starShaped) {
1468 NB_CORRECTION_OF_CAVITY++;
1470 allEmbeddedEdges) ||
1472 allEmbeddedFaces)) {
1473 correctedCavityIncompatibleWithEmbeddedEntities =
true;
1476 double lc1 = (1 - uvw[0] - uvw[1] - uvw[2]) *
1484 if(correctedCavityIncompatibleWithEmbeddedEntities || !starShaped ||
1485 !
insertVertexB(shell, cavity, v, lc1, lc2, vSizes, vSizesBGM, worst,
1486 myFactory, allTets, allEmbeddedFaces)) {
1489 for(
auto itc = cavity.begin(); itc != cavity.end(); ++itc)
1490 (*itc)->setDeleted(
false);
1495 vSizes.push_back(lc1);
1496 vSizesBGM.push_back(lc2);
1505 for(
auto itc = cavity.begin(); itc != cavity.end(); ++itc)
1506 (*itc)->setDeleted(
false);
1513 if(allTets.size() > 7 * vSizes.size() && ITER > 1000) {
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));
1532 for(
auto it = allTets.begin(); it != allTets.end(); ++it) {
1533 if(!(*it)->isDeleted()) {
1534 double qq = (*it)->getQuality();
1536 for(
int i = 0; i < 4; i++) {
1544 if(allTets.begin() == allTets.end())
break;
1545 MTet4 *worst = *allTets.begin();
1548 worst->
tet() =
nullptr;
1550 myFactory.
Free(worst);
1551 allTets.erase(allTets.begin());
1560 std::vector<MTetrahedron *> &result,
bool removeBox)
1562 Msg::Info(
"Tetrahedrizing %d nodes...", v.size());
1566 Msg::Info(
"Done tetrahedrizing %d nodes (Wall %gs, CPU %gs)", v.size(),