36 #define TRAN_QUA(c1, c2, c3, c4, s1, s2, s3, s4, u, v) \
37 (1. - u) * c4 + u * c2 + (1. - v) * c1 + v * c3 - \
38 ((1. - u) * (1. - v) * s1 + u * (1. - v) * s2 + u * v * s3 + \
43 #define TRAN_TRI(c1, c2, c3, s1, s2, s3, u, v) \
44 u * c2 + (1. - v) * c1 + v * c3 - (u * (1. - v) * s2 + u * v * s3)
55 std::vector<GEdge *> fedges = gf->
edges();
57 for(
auto it = el.
begin(); it != el.
end(); it++)
58 corners.push_back(it->getBeginVertex()->mesh_vertices[0]);
61 if(corners.size() == 3) {
62 GEdge *first =
nullptr, *last =
nullptr;
63 for(
auto it = fedges.begin(); it != fedges.end(); it++) {
64 if(((*it)->getBeginVertex()->mesh_vertices[0] == corners[0] &&
65 (*it)->getEndVertex()->mesh_vertices[0] == corners[1]) ||
66 ((*it)->getBeginVertex()->mesh_vertices[0] == corners[1] &&
67 (*it)->getEndVertex()->mesh_vertices[0] == corners[0])) {
70 if(((*it)->getBeginVertex()->mesh_vertices[0] == corners[2] &&
71 (*it)->getEndVertex()->mesh_vertices[0] == corners[0]) ||
72 ((*it)->getBeginVertex()->mesh_vertices[0] == corners[0] &&
73 (*it)->getEndVertex()->mesh_vertices[0] == corners[2])) {
78 if(first->
mesh_vertices.size() != last->mesh_vertices.size()) {
79 std::vector<MVertex *> corners2(3);
80 corners2[0] = corners[1];
81 corners2[1] = corners[2];
82 corners2[2] = corners[0];
91 std::vector<MVertex *> &all_mvertices,
92 std::vector<int> &indices)
94 std::vector<GEdge *>
const &e = gf->
edges();
97 std::vector<GEdge *>
edges;
99 for(std::size_t i = 0; i < e.size(); i++) {
100 if(!e[i]->degenerate(0)) {
101 edges.push_back(e[i]);
102 ori.push_back(i < o.size() ? o[i] : 1);
106 auto it =
edges.begin();
107 auto ito = ori.begin();
108 indices.push_back(0);
110 ((*ito) == 1) ? (*it)->getBeginVertex() : (*it)->getEndVertex();
112 ((*ito) != 1) ? (*it)->getBeginVertex() : (*it)->getEndVertex();
116 for(std::size_t i = 0; i < (*it)->mesh_vertices.size(); i++)
117 all_mvertices.push_back((*it)->mesh_vertices[i]);
119 for(
int i = (*it)->mesh_vertices.size() - 1; i >= 0; i--)
120 all_mvertices.push_back((*it)->mesh_vertices[i]);
127 indices.push_back(all_mvertices.size());
128 if(it ==
edges.end())
break;
129 start = ((*ito) == 1) ? (*it)->getBeginVertex() : (*it)->getEndVertex();
130 v_end = ((*ito) != 1) ? (*it)->getBeginVertex() : (*it)->getEndVertex();
134 if(it ==
edges.end()) {
135 Msg::Error(
"Something wrong in edge loop computation");
138 v_start = ((*ito) == 1) ? (*it)->getBeginVertex() : (*it)->getEndVertex();
139 if(v_start != v_end) {
140 Msg::Error(
"Something wrong in edge loop computation");
143 v_end = ((*ito) != 1) ? (*it)->getBeginVertex() : (*it)->getEndVertex();
147 for(std::size_t i = 0; i < (*it)->mesh_vertices.size(); i++)
148 all_mvertices.push_back((*it)->mesh_vertices[i]);
150 for(
int i = (*it)->mesh_vertices.size() - 1; i >= 0; i--)
151 all_mvertices.push_back((*it)->mesh_vertices[i]);
155 double maxDistParam(
const std::vector<double> &U,
const std::vector<double> &V)
157 if(U.size() < 2 || (U.size() != V.size()))
return 1e22;
159 sqrt(std::pow(U.back() - U.front(), 2) + std::pow(V.back() - V.front(), 2));
160 for(std::size_t i = 1; i < U.size(); i++)
162 d, sqrt(std::pow(U[i] - U[i - 1], 2) + std::pow(V[i] - V[i - 1], 2)));
170 Msg::Info(
"Meshing surface %d (Transfinite)", gf->
tag());
174 const std::vector<GEdge *> &
edges = gf->
edges();
175 for(
auto it =
edges.begin(); it !=
edges.end(); it++) {
176 if(!(*it)->getBeginVertex() || !(*it)->getEndVertex()) {
177 Msg::Error(
"Transfinite algorithm cannot be applied with curve %d which "
178 "has no begin or end point",
184 std::vector<MVertex *> corners;
186 if(corners.size() != 3 && corners.size() != 4) {
187 Msg::Error(
"Surface %d is transfinite but has %d corner%s", gf->
tag(),
188 corners.size(), corners.size() > 1 ?
"s" :
"");
192 std::vector<MVertex *> d_vertices;
193 std::vector<int> indices;
196 if(indices.size() != 2) {
197 int nh = indices.size() - 2;
198 Msg::Error(
"Surface %d is transfinite but has %d hole%s", gf->
tag(), nh,
205 std::vector<MVertex *> m_vertices;
207 for(I = 0; I < d_vertices.size(); I++)
208 if(d_vertices[I] == corners[0])
break;
209 for(std::size_t j = 0; j < d_vertices.size(); j++)
210 m_vertices.push_back(d_vertices[(I + j) % d_vertices.size()]);
215 bool reverse =
false;
216 for(std::size_t i = 1; i < m_vertices.size(); i++) {
218 if(v == corners[1] || v == corners[2] ||
219 (corners.size() == 4 && v == corners[3])) {
220 if(v != corners[1]) reverse =
true;
225 std::vector<MVertex *> tmp;
226 tmp.push_back(m_vertices[0]);
227 for(
int i = m_vertices.size() - 1; i > 0; i--) tmp.push_back(m_vertices[i]);
233 int iCorner = 0, N[4] = {0, 0, 0, 0};
234 std::vector<double> U, V, U2, V2;
235 for(std::size_t i = 0; i < m_vertices.size(); i++) {
237 if(v == corners[0] || v == corners[1] || v == corners[2] ||
238 (corners.size() == 4 && v == corners[3])) {
240 Msg::Error(
"Surface %d transfinite parameters are incoherent",
248 U.push_back(param[0]);
249 V.push_back(param[1]);
252 U2.push_back(param[0]);
253 V2.push_back(param[1]);
261 Msg::Debug(
"Choosing alternate parametrization on surface %d", gf->
tag());
266 int N1 = N[0], N2 = N[1], N3 = N[2], N4 = N[3];
267 int L = N2 - N1, H = N3 - N2;
268 if(corners.size() == 4) {
269 int Lb = N4 - N3, Hb = m_vertices.size() - N4;
270 if(Lb != L || Hb != H) {
271 Msg::Error(
"Surface %d cannot be meshed using the transfinite algo "
272 "(divisions %d != %d or %d != %d)",
273 gf->
tag(), Lb, L, Hb, H);
278 int Lb = m_vertices.size() - N3;
279 if(
CTX::instance()->mesh.transfiniteTri && Lb == L && H == L) {
281 Msg::Info(
"Using specific algorithm for 3-sided surface %d", gf->
tag());
285 Msg::Error(
"Surface %d cannot be meshed using the transfinite algo "
286 "(divisions %d != %d)",
305 bool symmetric =
true;
307 std::vector<double> lengths_i;
308 lengths_i.reserve(L);
309 lengths_i.push_back(0.0);
311 for(
int i = 0; i < L; i++) {
313 MVertex *v2 = m_vertices[i + 1];
317 m_vertices[(corners.size() == 3 && !i) ? 0 : (2 * L + H - i)];
318 MVertex *v4 = m_vertices[2 * L + H - i - 1];
320 L_i += 0.5 * (d1 + d2);
325 lengths_i.push_back(L_i);
328 std::vector<double> lengths_j;
329 lengths_j.reserve(H);
330 lengths_j.push_back(0.0);
332 for(
int i = 0; i < H; i++) {
333 MVertex *v1 = m_vertices[L + i];
334 MVertex *v2 = m_vertices[L + i + 1];
336 if(symmetric && corners.size() == 4) {
337 MVertex *v3 = m_vertices[(!i) ? 0 : (2 * L + 2 * H - i)];
338 MVertex *v4 = m_vertices[2 * L + 2 * H - i - 1];
340 L_j += 0.5 * (d1 + d2);
345 lengths_j.push_back(L_j);
350 for(
int i = 0; i <= L; i++) tab[i].resize(H + 1);
352 if(corners.size() == 4) {
353 tab[0][0] = m_vertices[0];
354 tab[L][0] = m_vertices[L];
355 tab[L][H] = m_vertices[L + H];
356 tab[0][H] = m_vertices[2 * L + H];
357 for(
int i = 1; i < L; i++) {
358 tab[i][0] = m_vertices[i];
359 tab[i][H] = m_vertices[2 * L + H - i];
361 for(
int i = 1; i < H; i++) {
362 tab[L][i] = m_vertices[L + i];
363 tab[0][i] = m_vertices[2 * L + 2 * H - i];
367 tab[0][0] = m_vertices[0];
368 tab[L][0] = m_vertices[L];
369 tab[L][H] = m_vertices[L + H];
371 tab[0][H] = m_vertices[0];
372 for(
int i = 1; i < L; i++) {
373 tab[i][0] = m_vertices[i];
374 tab[i][H] = m_vertices[2 * L + H - i];
376 for(
int i = 1; i < H; i++) {
377 tab[L][i] = m_vertices[L + i];
379 tab[0][i] = m_vertices[0];
383 double UC1 = U[N1], UC2 = U[N2], UC3 = U[N3];
384 double VC1 = V[N1], VC2 = V[N2], VC3 = V[N3];
387 if(corners.size() == 4) {
390 for(
int i = 1; i < L; i++) {
391 double u = lengths_i[i] / L_i;
392 for(
int j = 1; j < H; j++) {
393 double v = lengths_j[j] / L_j;
397 int iP4 = (N4 + (N3 - N2) - j) % m_vertices.size();
399 TRAN_QUA(U[iP1], U[iP2], U[iP3], U[iP4], UC1, UC2, UC3, UC4, u, v);
401 TRAN_QUA(V[iP1], V[iP2], V[iP3], V[iP4], VC1, VC2, VC3, VC4, u, v);
410 std::vector<double> u2, v2;
413 for(
int j = 0; j <= H; j++) u2.push_back(U[N2 + j]);
415 for(
int j = 0; j <= H; j++) v2.push_back(V[N2 + j]);
418 for(
int i = 1; i < L; i++) {
419 double u = lengths_i[i] / L_i;
420 for(
int j = 1; j < H; j++) {
421 double v = lengths_j[j] / L_j;
424 int iP3 = ((N3 + N2) - i) % m_vertices.size();
428 Up =
TRAN_TRI(U[iP1], U[iP2], U[iP3], UC1, UC2, UC3, u, v);
429 Vp =
TRAN_TRI(V[iP1], V[iP2], V[iP3], VC1, VC2, VC3, u, v);
433 tab[i][j] = tab[i][H];
437 double t = double(j) / double(i);
440 for(k = 1; k <= H; k++)
441 if(t < lengths_j[k] / L_j && t > lengths_j[k - 1] / L_j)
break;
444 (t * L_j - lengths_j[k - 1]) / (lengths_j[k] - lengths_j[k - 1]);
445 double UP2 = u2[k - 1] + a * (u2[k] - u2[k - 1]);
446 double VP2 = v2[k - 1] + a * (v2[k] - v2[k - 1]);
447 Up =
TRAN_TRI(U[iP1], UP2, U[iP3], UC1, UC2, UC3, u, v);
448 Vp =
TRAN_TRI(V[iP1], VP2, V[iP3], VC1, VC2, VC3, u, v);
456 double xp =
TRAN_TRI(m_vertices[iP1]->x(), m_vertices[iP2]->x(),
457 m_vertices[iP3]->x(), m_vertices[N1]->x(),
458 m_vertices[N2]->x(), m_vertices[N3]->x(), u, v);
459 double yp =
TRAN_TRI(m_vertices[iP1]->y(), m_vertices[iP2]->y(),
460 m_vertices[iP3]->y(), m_vertices[N1]->y(),
461 m_vertices[N2]->y(), m_vertices[N3]->y(), u, v);
462 double zp =
TRAN_TRI(m_vertices[iP1]->
z(), m_vertices[iP2]->
z(),
463 m_vertices[iP3]->
z(), m_vertices[N1]->
z(),
464 m_vertices[N2]->
z(), m_vertices[N3]->
z(), u, v);
466 gf->
XYZtoUV(xp, yp, zp, Up, Vp, 1.0,
false);
485 std::vector<std::vector<double> > u(L + 1), v(L + 1);
486 for(
int i = 0; i <= L; i++) {
490 for(
int i = 0; i <= L; i++) {
491 for(
int j = 0; j <= H; j++) {
495 int iP4 = (N4 + (N3 - N2) - j) % m_vertices.size();
513 tab[i][j]->getParameter(0, u[i][j]);
514 tab[i][j]->getParameter(1, v[i][j]);
518 for(
int IT = 0; IT < numSmooth; IT++) {
519 for(
int i = 1; i < L; i++) {
520 for(
int j = 1; j < H; j++) {
521 double alpha = 0.25 * (std::pow(u[i][j + 1] - u[i][j - 1], 2) +
522 std::pow(v[i][j + 1] - v[i][j - 1], 2));
523 double gamma = 0.25 * (std::pow(u[i + 1][j] - u[i - 1][j], 2) +
524 std::pow(v[i + 1][j] - v[i - 1][j], 2));
527 ((u[i + 1][j] - u[i - 1][j]) * (u[i][j + 1] - u[i][j - 1]) +
528 (v[i + 1][j] - v[i - 1][j]) * (v[i][j + 1] - v[i][j - 1]));
530 (alpha * (u[i + 1][j] + u[i - 1][j]) +
531 gamma * (u[i][j + 1] + u[i][j - 1]) -
533 (u[i + 1][j + 1] - u[i - 1][j + 1] - u[i + 1][j - 1] +
537 (alpha * (v[i + 1][j] + v[i - 1][j]) +
538 gamma * (v[i][j + 1] + v[i][j - 1]) -
540 (v[i + 1][j + 1] - v[i - 1][j + 1] - v[i + 1][j - 1] +
546 for(
int i = 1; i < L; i++) {
547 for(
int j = 1; j < H; j++) {
549 tab[i][j]->
x() = p.
x();
550 tab[i][j]->y() = p.
y();
551 tab[i][j]->z() = p.
z();
552 tab[i][j]->setParameter(0, u[i][j]);
553 tab[i][j]->setParameter(1, v[i][j]);
559 if(corners.size() == 4) {
560 for(
int i = 0; i < L; i++) {
561 for(
int j = 0; j < H; j++) {
564 MVertex *v3 = tab[i + 1][j + 1];
570 ((i % 2 == 0 && j % 2 == 1) || (i % 2 == 1 && j % 2 == 0))) ||
572 ((i % 2 == 0 && j % 2 == 0) || (i % 2 == 1 && j % 2 == 1)))) {
586 for(
int j = 0; j < H; j++) {
592 for(
int i = 1; i < L; i++) {
593 for(
int j = 0; j < H; j++) {
596 MVertex *v3 = tab[i + 1][j + 1];
602 ((i % 2 == 0 && j % 2 == 1) ||
603 (i % 2 == 1 && j % 2 == 0))) ||
605 ((i % 2 == 0 && j % 2 == 0) ||
606 (i % 2 == 1 && j % 2 == 1)))) {
618 for(
int i = 0; i < L; i++) {
622 MVertex *v3 = tab[i + 1][j + 1];
625 for(
int i = 1; i < L; i++) {
626 for(
int j = 0; j < i; j++) {
629 MVertex *v3 = tab[i + 1][j + 1];
643 std::vector<int> &loop)
648 if(pairs.size() < 2)
return false;
649 loop.reserve(pairs.size());
650 std::vector<bool> done(pairs.size(),
false);
652 loop[0] = pairs[0][0];
653 loop[1] = pairs[0][1];
655 while(loop.size() != pairs.size()) {
656 int cv = loop.back();
658 for(std::size_t i = 0; i < pairs.size(); ++i)
660 const std::array<int, 2> &vs = pairs[i];
662 loop.push_back(vs[1]);
666 else if(vs[1] == cv) {
667 loop.push_back(vs[0]);
683 if(gf->
edges().size() != 4)
return false;
685 std::vector<std::array<int, 2> > vpairs;
688 {{ge->getBeginVertex()->tag(), ge->getEndVertex()->tag()}});
690 std::vector<int> loop;
692 if(!ok || loop.size() != vpairs.size())
return false;
694 if(angle_threshold_rad > 0.) {
696 for(std::size_t i = 0; i < loop.size(); ++i) {
698 int v2 = loop[(i + 1) % loop.size()];
699 int v3 = loop[(i + 2) % loop.size()];
702 int e_v1 = ge->getBeginVertex()->tag();
703 int e_v2 = ge->getEndVertex()->tag();
704 if(e_v1 == v1 && e_v2 == v2) {
710 else if(e_v1 == v2 && e_v2 == v1) {
716 else if(e_v1 == v2 && e_v2 == v3) {
722 else if(e_v1 == v3 && e_v2 == v2) {
729 double agl =
angle(t21, t23);
730 if(agl > angle_threshold_rad) {
731 Msg::Debug(
"quadrangular face %i rejected for automatic transfinite "
732 "because corner angle = %.3f deg > threshold = %.3f deg\n",
733 gf->
tag(), 180. / M_PI * agl,
734 180. / M_PI * angle_threshold_rad);
745 if(face->
edges().size() != 4)
return nullptr;
749 bool edgeInside =
false;
755 int cv1 = ge->getBeginVertex()->tag();
756 int cv2 = ge->getEndVertex()->tag();
757 if(cv1 != v1 && cv1 != v2 && cv2 != v1 && cv2 != v2) {
758 if(op ==
nullptr) { op = ge; }
764 if(!edgeInside)
return nullptr;
769 std::vector<std::set<GEdge *> > &chords,
double maxDiffRel,
770 bool ignoreEmbedded =
false)
773 std::map<GEdge *, std::vector<GFace *> > edge2faces;
775 if(!ignoreEmbedded &&
776 (gf->embeddedEdges().size() > 0 || gf->embeddedVertices().size() > 0))
778 for(
GEdge *ge : gf->
edges()) { edge2faces[ge].push_back(gf); }
784 std::map<GEdge *, bool> done;
785 for(
auto &kv : edge2faces) {
786 GEdge *geInit = kv.first;
787 if(done.find(geInit) != done.end())
continue;
790 std::queue<GEdge *> Q;
794 std::set<GEdge *> chord;
795 while(Q.size() > 0) {
796 GEdge *ge = Q.front();
800 for(
GFace *gf : edge2faces[ge]) {
802 if(ge2 && done.find(ge2) == done.end()) {
804 if(
double(std::abs(n2 - n)) /
double(std::max(n, n2)) > maxDiffRel) {
813 if(chord.size() >= 2) { chords.push_back(chord); }
818 double cornerAngle,
bool setRecombine,
819 double maxDiffRel,
bool ignoreEmbedded)
822 std::set<GFace *>
faces;
823 for(
GFace *gf : candidate_faces) {
824 if(!ignoreEmbedded &&
825 (gf->embeddedEdges().size() > 0 || gf->embeddedVertices().size() > 0))
832 "transfinite automatic: building chords from %li quadrangular faces ...",
834 std::vector<std::set<GEdge *> > chords;
836 Msg::Debug(
"... found %li chords", chords.size());
839 Msg::Debug(
"transfinite automatic: assigning number of points ...");
841 for(std::set<GEdge *> &chord : chords) {
842 double avgNbPoints = 0;
843 for(
GEdge *ge : chord) {
845 avgNbPoints += double(n);
847 avgNbPoints /= chord.size();
849 int N = int(avgNbPoints + 0.5);
851 if(N % 2 == 1) N = N + 1;
853 Msg::Debug(
"- chord with %li edges -> %i points\n", chord.size(), N);
855 for(
GEdge *ge : chord) {
857 ge->meshAttributes.nbPointsTransfinite = N;
858 ge->meshAttributes.typeTransfinite = 1;
859 ge->meshAttributes.coeffTransfinite = 1.;
861 ge->meshAttributes.typeTransfinite = 4;
866 Msg::Debug(
"transfinite automatic: transfinite set on %li edges", ne);
870 bool transfinite =
true;
871 std::vector<int> nPoints(4, 0);
872 std::size_t count = 0;
878 nPoints[count] = ge->meshAttributes.nbPointsTransfinite;
881 if(transfinite && nPoints[0] == nPoints[2] && nPoints[1] == nPoints[3]) {
884 gf->meshAttributes.transfiniteArrangement = 1;
886 gf->meshAttributes.recombine = 1;
887 gf->meshAttributes.recombineAngle = 45.;
891 Msg::Debug(
"transfinite automatic: transfinite set on %li faces", nf);