10 #include "GmshConfig.h"
24 #if defined(HAVE_POST)
29 #if defined(HAVE_SOLVER) && defined(HAVE_POST)
38 static inline double lifting(
double a,
double _a)
41 if(fabs(_a - a) < fabs(_a - (a +
D)) && fabs(_a - a) < fabs(_a - (a -
D))) {
44 else if(fabs(_a - (a +
D)) < fabs(_a - a) &&
45 fabs(_a - (a +
D)) < fabs(_a - (a -
D))) {
53 static inline double compat_orientation_extrinsic(
const double *o0,
56 const double *n1,
double *
a1,
59 double t0[3] = {n0[1] * o0[2] - n0[2] * o0[1], n0[2] * o0[0] - n0[0] * o0[2],
60 n0[0] * o0[1] - n0[1] * o0[0]};
61 double t1[3] = {n1[1] * o1[2] - n1[2] * o1[1], n1[2] * o1[0] - n1[0] * o1[2],
62 n1[0] * o1[1] - n1[1] * o1[0]};
64 const size_t permuts[8][2] = {{0, 0}, {1, 0}, {2, 0}, {3, 0},
65 {0, 1}, {1, 1}, {2, 1}, {3, 1}};
66 const double A[4][3] = {{o0[0], o0[1], o0[2]},
67 {t0[0], t0[1], t0[2]},
68 {-o0[0], -o0[1], -o0[2]},
69 {-t0[0], -t0[1], -t0[2]}};
70 const double B[2][3] = {{o1[0], o1[1], o1[2]}, {t1[0], t1[1], t1[2]}};
74 for(
size_t i = 0; i < 8; i++) {
75 const size_t II = permuts[i][0];
76 const size_t JJ = permuts[i][1];
78 A[II][0] * B[JJ][0] + A[II][1] * B[JJ][1] + A[II][2] * B[JJ][2];
84 a1[0] = A[permuts[index][0]][0];
85 a1[1] = A[permuts[index][0]][1];
86 a1[2] = A[permuts[index][0]][2];
87 b1[0] = B[permuts[index][1]][0];
88 b1[1] = B[permuts[index][1]][1];
89 b1[2] = B[permuts[index][1]][2];
94 static inline double compat_orientation_extrinsic(
const SVector3 &o0,
103 const size_t permuts[8][2] = {{0, 0}, {1, 0}, {2, 0}, {3, 0},
104 {0, 1}, {1, 1}, {2, 1}, {3, 1}};
110 for(
size_t i = 0; i < 8; i++) {
111 const double xx =
dot(A[permuts[i][0]], B[permuts[i][1]]);
117 a1 = A[permuts[index][0]];
118 b1 = B[permuts[index][1]];
127 bool inInternalBoundary;
133 std::vector<MEdge> _neighbors;
134 std::vector<cross2d *> _cneighbors;
136 double _cc[4], _ss[4];
139 double _atemp, _btemp, _ctemp;
140 std::vector<MTriangle *> _t;
142 : _e(e), inCutGraph(false), inBoundary(false), inInternalBoundary(false),
146 _neighbors.push_back(e1);
147 _neighbors.push_back(e2);
151 double D = M_PI * .5;
155 while(a >=
D) a -=
D;
159 if(_cneighbors.size() == 4) {
161 _a = _atemp = atan2(
dot(_tgt2, x),
dot(_tgt, x));
162 if(!inBoundary && !inInternalBoundary) {
163 _b = _btemp = sin(4 * _a);
164 _c = _ctemp = cos(4 * _a);
170 for(
size_t i = 0; i < 4; i++) {
171 da[i] = atan2(
dot(_tgt2, _cneighbors[i]->_tgt),
172 dot(_tgt, _cneighbors[i]->_tgt));
173 _cc[i] = cos(4 * da[i]);
174 _ss[i] = sin(4 * da[i]);
179 void finish(std::map<MEdge, cross2d, MEdgeLessThan> &C)
184 SVector3 v10(_t[0]->getVertex(1)->x() - _t[0]->getVertex(0)->x(),
185 _t[0]->getVertex(1)->y() - _t[0]->getVertex(0)->y(),
186 _t[0]->getVertex(1)->
z() - _t[0]->getVertex(0)->
z());
187 SVector3 v20(_t[0]->getVertex(2)->x() - _t[0]->getVertex(0)->x(),
188 _t[0]->getVertex(2)->y() - _t[0]->getVertex(0)->y(),
189 _t[0]->getVertex(2)->
z() - _t[0]->getVertex(0)->
z());
194 SVector3 v10b(_t[1]->getVertex(1)->x() - _t[1]->getVertex(0)->x(),
195 _t[1]->getVertex(1)->y() - _t[1]->getVertex(0)->y(),
196 _t[1]->getVertex(1)->
z() - _t[1]->getVertex(0)->
z());
197 SVector3 v20b(_t[1]->getVertex(2)->x() - _t[1]->getVertex(0)->x(),
198 _t[1]->getVertex(2)->y() - _t[1]->getVertex(0)->y(),
199 _t[1]->getVertex(2)->
z() - _t[1]->getVertex(0)->
z());
214 if(_t.size() == 1) { inBoundary =
true; }
215 else if(_t.size() >= 2) {
218 inInternalBoundary =
true;
222 for(
size_t i = 0; i < _neighbors.size(); i++) {
223 auto it = C.find(_neighbors[i]);
227 _cneighbors.push_back(&(it->second));
229 if(_cneighbors.size() != 4) {
234 _b = _btemp = sin(4 * _a);
235 _c = _ctemp = cos(4 * _a);
237 double average_init()
239 if(!inBoundary && !inInternalBoundary) {
242 for(
int i = 0; i < 4; i++) {
243 _ctemp += (_cneighbors[i]->_c * _cc[i] - _cneighbors[i]->_b * _ss[i]);
244 _btemp += (_cneighbors[i]->_c * _ss[i] + _cneighbors[i]->_b * _cc[i]);
256 if(!inBoundary && !inInternalBoundary) {
257 double D = M_PI * .5;
258 double a[4] = {_cneighbors[0]->_a, _cneighbors[1]->_a, _cneighbors[2]->_a,
260 for(
int i = 0; i < 4; i++) {
266 for(
int i = 0; i < 4; i++) {
267 if(fabs(_a - a[i]) < fabs(_a - (a[i] +
D)) &&
268 fabs(_a - a[i]) < fabs(_a - (a[i] -
D))) {
271 else if(fabs(_a - (a[i] +
D)) < fabs(_a - (a[i])) &&
272 fabs(_a - (a[i] +
D)) < fabs(_a - (a[i] -
D))) {
279 return fabs(_a - b[0]) + fabs(_a - b[1]) + fabs(_a - b[2]) +
285 double lifting(
double a)
287 double D = M_PI * .5;
288 if(fabs(_a - a) < fabs(_a - (a +
D)) && fabs(_a - a) < fabs(_a - (a -
D))) {
291 else if(fabs(_a - (a +
D)) < fabs(_a - a) &&
292 fabs(_a - (a +
D)) < fabs(_a - (a -
D))) {
302 _a = _atemp = 0.25 * atan2(_btemp, _ctemp);
304 o_i = _tgt * cos(_atemp) + _tgt2 * sin(_atemp);
309 if(_cneighbors.size() != 4)
return;
310 double _anew = atan2(
dot(_tgt2, o_i),
dot(_tgt, o_i));
319 if(_cneighbors.size() != 4)
return 0;
323 for(
int i = 0; i < 4; i++) {
325 SVector3 n_j = _cneighbors[i]->_nrml;
327 compat_orientation_extrinsic(o_i, n_i, o_j, n_j, x, y);
328 o_i = x * weight + y;
329 o_i -= n_i *
dot(o_i, n_i);
333 return std::min(1. - fabs(
dot(o_i, o_i_old)), fabs(
dot(o_i, o_i_old)));
338 if(_cneighbors.size() == 4) {
339 double D = M_PI * .5;
340 double a[4] = {_cneighbors[0]->_a, _cneighbors[1]->_a, _cneighbors[2]->_a,
342 for(
int i = 0; i < 4; i++) {
349 for(
int i = 0; i < 4; i++) {
350 if(fabs(_a - a[i]) < fabs(_a - (a[i] +
D)) &&
351 fabs(_a - a[i]) < fabs(_a - (a[i] -
D))) {
354 else if(fabs(_a - (a[i] +
D)) < fabs(_a - (a[i])) &&
355 fabs(_a - (a[i] +
D)) < fabs(_a - (a[i] -
D))) {
362 avg = 0.25 * (b[0] + b[1] + b[2] + b[3]);
366 double d = fabs(_a - avg);
375 struct cross2dPtrLessThan {
377 bool operator()(
const cross2d *v1,
const cross2d *v2)
const
379 return l(v1->_e, v2->_e);
388 static void closest(
const cross2d &
c1,
const cross2d &c2,
double &
a2,
395 SVector3 d1 = c2._tgt * cos(c2._atemp) + c2._tgt2 * sin(c2._atemp);
396 SVector3 d2 = c2._tgt * cos(c2._atemp + P) + c2._tgt2 * sin(c2._atemp + P);
398 c2._tgt * cos(c2._atemp + 2 * P) + c2._tgt2 * sin(c2._atemp + 2 * P);
400 c2._tgt * cos(c2._atemp + 3 * P) + c2._tgt2 * sin(c2._atemp + 3 * P);
402 double D1 =
dot(d, d1);
403 double D2 =
dot(d, d2);
404 double D3 =
dot(d, d3);
405 double D4 =
dot(d, d4);
407 if(D1 > D2 && D1 > D3 && D1 > D4) {
a2 = c2._atemp; }
408 else if(D2 > D1 && D2 > D3 && D2 > D4) {
411 else if(D3 > D1 && D3 > D2 && D3 > D4) {
412 a2 = c2._atemp + 2 * P;
415 a2 = c2._atemp + 3 * P;
419 static void computeLifting(cross2d *first,
int branch,
420 std::set<MEdge, MEdgeLessThan> &cutG,
421 std::set<MVertex *, MVertexPtrLessThan> &sing,
422 std::set<MVertex *, MVertexPtrLessThan> &bnd,
423 std::set<cross2d *> &visited)
426 std::set<MVertex *, MVertexPtrLessThan> cg;
428 auto it = cutG.begin();
429 for(; it != cutG.end(); ++it) {
430 cg.insert(it->getVertex(0));
431 cg.insert(it->getVertex(1));
435 FILE *_f = fopen(
"visited.pos",
"w");
436 fprintf(_f,
"View\"\"{\n");
438 std::queue<cross2d *> _s;
440 first->_atemp = first->_a + branch * M_PI / 2.0;
441 first->_btemp = 10000.;
442 visited.insert(first);
444 cross2d *
c = _s.front();
446 if(cutG.find(
c->_e) == cutG.end()) {
447 for(
size_t i = 0; i <
c->_cneighbors.size(); i++) {
449 cross2d *n =
c->_cneighbors[i];
451 if(n->_btemp < 1000) {
454 bool s0 = sing.find(n->_e.getVertex(0)) != sing.end();
455 bool s1 = sing.find(n->_e.getVertex(1)) != sing.end();
456 bool c0 = cg.find(n->_e.getVertex(0)) != cg.end();
457 bool c1 = cg.find(n->_e.getVertex(1)) != cg.end();
458 bool b0 = bnd.find(n->_e.getVertex(0)) != bnd.end();
459 bool b1 = bnd.find(n->_e.getVertex(1)) != bnd.end();
463 if(((s0 &&
c1) || (s0 &&
b1)) || ((s1 && c0) || (s1 && b0))) {
464 printf(
"BLOCKED \n");
467 if((!s0 && !s1)) _s.push(n);
471 SVector3 d = n->_tgt * cos(n->_atemp) + n->_tgt2 * sin(n->_atemp);
472 fprintf(_f,
"VL(%g,%g,%g,%g,%g,%g){%g,%g,%g,%g,%g,%g};\n",
473 n->_e.getVertex(0)->x(), n->_e.getVertex(0)->y(),
474 n->_e.getVertex(0)->z(), n->_e.getVertex(1)->x(),
475 n->_e.getVertex(1)->y(), n->_e.getVertex(1)->z(), d.
x(),
476 d.
y(), d.
z(), d.
x(), d.
y(), d.
z());
485 struct groupOfCross2d {
489 std::vector<MVertex *> vertices;
490 std::vector<MVertex *> singularities;
491 std::vector<MVertex *> left;
492 std::vector<MVertex *> right;
493 std::vector<cross2d *> crosses;
494 std::vector<MTriangle *> side;
497 for(
size_t i = 0; i < crosses.size(); i++) {
499 f,
"SL(%g,%g,%g,%g,%g,%g){%d,%d};\n", crosses[i]->_e.
getVertex(0)->
x(),
500 crosses[i]->_e.getVertex(0)->y(), crosses[i]->_e.getVertex(0)->z(),
501 crosses[i]->_e.getVertex(1)->x(), crosses[i]->_e.getVertex(1)->y(),
502 crosses[i]->_e.getVertex(1)->z(), groupId, groupId);
504 for(
size_t i = 0; i < side.size(); i++) {
505 fprintf(
f,
"ST(%g,%g,%g,%g,%g,%g,%g,%g,%g){%d,%d,%d};\n",
506 side[i]->getVertex(0)->x(), side[i]->getVertex(0)->y(),
507 side[i]->getVertex(0)->
z(), side[i]->getVertex(1)->x(),
508 side[i]->getVertex(1)->y(), side[i]->getVertex(1)->
z(),
509 side[i]->getVertex(2)->x(), side[i]->getVertex(2)->y(),
510 side[i]->getVertex(2)->
z(), groupId, groupId, groupId);
513 groupOfCross2d(
int id) : groupId(id) {}
516 static void unDuplicateNodesInCutGraph(
517 std::vector<GFace *> &
f,
518 std::map<MVertex *, MVertex *, MVertexPtrLessThan> &new2old)
520 for(
size_t i = 0; i <
f.size(); i++) {
521 for(
size_t j = 0; j <
f[i]->triangles.size(); j++) {
523 for(
size_t k = 0; k < 3; k++) {
525 if(it != new2old.end()) t->
setVertex(k, it->second);
531 static void duplicateNodesInCutGraph(
532 std::vector<GFace *> &
f, std::map<MEdge, cross2d, MEdgeLessThan> &C,
533 std::map<MVertex *, MVertex *, MVertexPtrLessThan> &new2old,
534 std::multimap<MVertex *, MVertex *, MVertexPtrLessThan> &old2new,
535 std::map<MEdge, MEdge, MEdgeLessThan> &duplicateEdges,
536 std::set<MVertex *, MVertexPtrLessThan> &sing,
v2t_cont &adj,
537 std::vector<groupOfCross2d> &G)
539 FILE *_f = fopen(
"nodes.pos",
"w");
540 fprintf(_f,
"View \" nodes \"{\n");
542 auto it = adj.begin();
543 std::set<MElement *> touched;
544 std::set<MVertex *, MVertexPtrLessThan> vtouched;
546 std::vector<std::pair<MElement *, std::pair<int, MVertex *> > > replacements;
548 while(it != adj.end()) {
549 std::vector<MElement *> els = it->second;
551 while(!els.empty()) {
552 std::vector<MElement *> _side;
553 std::stack<MElement *> _s;
555 _side.push_back(els[0]);
556 els.erase(els.begin());
560 for(
int i = 0; i < 3; i++) {
562 auto it0 = C.find(e0);
563 if(!it0->second.inCutGraph) {
564 for(
size_t j = 0; j < it0->second._t.size(); j++) {
565 auto ite = std::find(els.begin(), els.end(), it0->second._t[j]);
566 if(ite != els.end()) {
568 _side.push_back(it0->second._t[j]);
569 _s.push(it0->second._t[j]);
578 new MVertex(it->first->x(), it->first->y(), it->first->z(),
f[0]);
579 std::pair<MVertex *, MVertex *> p = std::make_pair(it->first, v);
581 f[0]->mesh_vertices.push_back(v);
582 for(
size_t i = 0; i < _side.size(); i++) {
583 for(
size_t j = 0; j < 3; j++) {
584 if(_side[i]->getVertex(j) == it->first) {
585 std::pair<int, MVertex *> r = std::make_pair(j, v);
586 std::pair<MElement *, std::pair<int, MVertex *> > r2 =
587 std::make_pair(_side[i], r);
588 replacements.push_back(r2);
592 fprintf(_f,
"SP(%g,%g,%g){%d};\n", it->first->x(), it->first->y(),
593 it->first->z(), (
int)els.size());
604 for(
size_t i = 0; i < replacements.size(); i++) {
605 MElement *e = replacements[i].first;
606 int j = replacements[i].second.first;
607 MVertex *v = replacements[i].second.second;
624 computeUniqueVectorPerTriangle(
GModel *gm, std::vector<GFace *> &
f,
625 std::map<MEdge, cross2d, MEdgeLessThan> &C,
626 int dir, std::map<MTriangle *, SVector3> &d)
628 for(
size_t i = 0; i <
f.size(); i++) {
629 for(
size_t j = 0; j <
f[i]->triangles.size(); j++) {
633 for(
int k = 0; k < 3; k++) {
637 if(!it->second.inCutGraph) {
640 (dir == 1) ? cos(it->second._atemp) : sin(it->second._atemp);
642 (dir == 1) ? sin(it->second._atemp) : -cos(it->second._atemp);
643 SVector3 aa = it->second._tgt * C + it->second._tgt2 *
S;
651 if(n) a0.normalize();
665 if(g.singularities.size() == 1) {
676 if(g.groupId == ZERO_) {
677 myAssembler.
numberVertex(g.left[0], 0, 3 + 10000 * g.groupId);
680 for(
size_t K = 1; K < g.left.size(); K++) {
681 myAssembler.
numberVertex(g.left[K], 0, 3 + 100 * g.groupId);
682 myAssembler.
numberVertex(g.left[K], 0, 4 + 100 * g.groupId);
688 std::map<MTriangle *, SVector3> &d0,
692 if(g.crosses[0]->inInternalBoundary) {
695 for(
size_t K = 1; K < g.left.size(); K++) {
696 myAssembler.
numberVertex(g.left[K], 0, 12 + 100 * g.groupId);
697 myAssembler.
numberVertex(g.left[K], 0, 13 + 100 * g.groupId);
707 if(std::find(g.side.begin(), g.side.end(), t1) != g.side.end()) {
712 printf(
"%12.5E %12.5E\n", fabs(
dot(g.crosses[0]->_tgt, dir0)),
713 fabs(
dot(g.crosses[0]->_tgt, dir1)));
719 for(
size_t K = 1; K < g.left.size(); K++) {
720 Dof E1(g.left[K]->getNum(),
722 Dof E2(g.left[K]->getNum(),
729 if(fabs(
dot(g.crosses[0]->_tgt, dir0)) > .5) {
732 myAssembler.
assemble(E1, U1R, -1.0);
733 myAssembler.
assemble(U1R, E1, -1.0);
738 myAssembler.
assemble(E1, V1R, -1.0);
739 myAssembler.
assemble(V1R, E1, -1.0);
742 if(fabs(
dot(g.crosses[0]->_tgt, dir1)) > .5) {
746 myAssembler.
assemble(E2, U2R, -1.0);
747 myAssembler.
assemble(U2R, E2, -1.0);
753 myAssembler.
assemble(E2, V2R, -1.0);
754 myAssembler.
assemble(V2R, E2, -1.0);
777 if(g.singularities.size() == 1) {
784 myAssembler.
assemble(E1, U1R, -1.0);
786 myAssembler.
assemble(E1, U, -g.mat[0][0]);
787 myAssembler.
assemble(E1, V, -g.mat[0][1]);
788 myAssembler.
assemble(E1, U2R, g.mat[0][0]);
789 myAssembler.
assemble(E1, V2R, g.mat[0][1]);
792 myAssembler.
assemble(E2, V1R, -1.0);
794 myAssembler.
assemble(E2, U, -g.mat[1][0]);
795 myAssembler.
assemble(E2, V, -g.mat[1][1]);
796 myAssembler.
assemble(E2, U2R, g.mat[1][0]);
797 myAssembler.
assemble(E2, V2R, g.mat[1][1]);
802 myAssembler.
assemble(U1R, E1, -1.0);
804 myAssembler.
assemble(U, E1, -g.mat[0][0]);
805 myAssembler.
assemble(V, E1, -g.mat[0][1]);
806 myAssembler.
assemble(U2R, E1, g.mat[0][0]);
807 myAssembler.
assemble(V2R, E1, g.mat[0][1]);
810 myAssembler.
assemble(V1R, E2, -1.0);
812 myAssembler.
assemble(U, E2, -g.mat[1][0]);
813 myAssembler.
assemble(V, E2, -g.mat[1][1]);
814 myAssembler.
assemble(U2R, E2, g.mat[1][0]);
815 myAssembler.
assemble(V2R, E2, g.mat[1][1]);
819 if(g.groupId == ZERO_) {
820 Dof E1(g.left[0]->getNum(),
826 for(
size_t K = 1; K < g.left.size(); K++) {
829 Dof E1(g.left[K]->getNum(),
831 Dof E2(g.left[K]->getNum(),
841 myAssembler.
assemble(E1, U1R, -1.0);
843 myAssembler.
assemble(E1, U2, -g.mat[0][0]);
844 myAssembler.
assemble(E1, V2, -g.mat[0][1]);
845 myAssembler.
assemble(E1, U2R, g.mat[0][0]);
846 myAssembler.
assemble(E1, V2R, g.mat[0][1]);
849 myAssembler.
assemble(E2, V1R, -1.0);
851 myAssembler.
assemble(E2, U2, -g.mat[1][0]);
852 myAssembler.
assemble(E2, V2, -g.mat[1][1]);
853 myAssembler.
assemble(E2, U2R, g.mat[1][0]);
854 myAssembler.
assemble(E2, V2R, g.mat[1][1]);
859 myAssembler.
assemble(U1R, E1, -1.0);
860 myAssembler.
assemble(U2, E1, -g.mat[0][0]);
861 myAssembler.
assemble(V2, E1, -g.mat[0][1]);
862 myAssembler.
assemble(U2R, E1, g.mat[0][0]);
863 myAssembler.
assemble(V2R, E1, g.mat[0][1]);
866 myAssembler.
assemble(V1R, E2, -1.0);
867 myAssembler.
assemble(U2, E2, -g.mat[1][0]);
868 myAssembler.
assemble(V2, E2, -g.mat[1][1]);
869 myAssembler.
assemble(U2R, E2, g.mat[1][0]);
870 myAssembler.
assemble(V2R, E2, g.mat[1][1]);
876 std::map<MEdge, cross2d, MEdgeLessThan> &C,
877 std::vector<std::vector<cross2d *> > &groups,
878 std::map<MEdge, MEdge, MEdgeLessThan> &duplicateEdges,
879 bool assemble, std::map<MTriangle *, SVector3> &lift)
881 for(
size_t i = 0; i < groups.size(); i++) {
882 size_t N = groups[i].size();
883 MEdge ed = groups[i][0]->_e;
884 auto ite = duplicateEdges.find(ed);
885 if(ite != duplicateEdges.end()) ed = ite->second;
887 auto it = C.find(groups[i][0]->_e);
888 SVector3 aaa = lift[it->second._t[0]];
890 double S = fabs(
dot(it->second._tgt, aaa));
895 for(
size_t j = 0; j < N; j++) {
896 ed = groups[i][j]->_e;
897 ite = duplicateEdges.find(ed);
898 if(ite != duplicateEdges.end()) ed = ite->second;
899 for(
int k = 0; k < 2; k++) {
902 if(!assemble) { myAssembler.
numberVertex(vk, 0, 5 + 100 * i); }
908 myAssembler.
assemble(Eref, Uref, 1.0);
909 myAssembler.
assemble(Eref, U, -1.0);
910 myAssembler.
assemble(Uref, Eref, 1.0);
911 myAssembler.
assemble(U, Eref, -1.0);
920 struct cutGraphPassage {
924 cutGraphPassage(
int id,
int uv,
const SPoint3 &p) : _id(id), _uv(uv), _p(p) {}
928 std::set<MVertex *, MVertexPtrLessThan> &vs)
930 for(
auto it = vs.begin(); it != vs.end(); ++it)
935 std::vector<groupOfCross2d> &G,
936 std::vector<cutGraphPassage> &passages)
944 std::vector<groupOfCross2d> &G,
945 std::vector<cutGraphPassage> &passages)
948 int groups[2][2] = {{14, 1}, {13, 2}};
952 for(
int i = 0; i < nConn; i++) {
953 groupOfCross2d &g = G[groups[i][0]];
954 int index = groups[i][1];
959 myAssembler.
assemble(E, U2, -g.mat[index - 1][0]);
960 myAssembler.
assemble(E, V2, -g.mat[index - 1][1]);
962 myAssembler.
assemble(U2, E, -g.mat[index - 1][0]);
963 myAssembler.
assemble(V2, E, -g.mat[index - 1][1]);
967 static void computePotential(
969 std::map<MEdge, cross2d, MEdgeLessThan> &C,
970 std::map<MVertex *, MVertex *, MVertexPtrLessThan> &new2old,
971 std::vector<std::vector<cross2d *> > &groups,
972 std::map<MEdge, MEdge, MEdgeLessThan> &duplicateEdges,
973 std::map<MTriangle *, SVector3> &lift, std::map<MTriangle *, SVector3> &lift2,
974 std::vector<groupOfCross2d> &G, std::map<MVertex *, double> &res,
975 std::map<MVertex *, double> &res2, std::vector<cutGraphPassage> &passages)
978 std::set<MVertex *, MVertexPtrLessThan> vs;
979 for(
size_t i = 0; i <
f.size(); i++) {
980 for(
size_t j = 0; j <
f[i]->triangles.size(); j++) {
982 for(
size_t k = 0; k < 3; k++) { vs.insert(t->
getVertex(k)); }
986 #if defined(HAVE_PETSC)
988 #elif defined(HAVE_GMM)
1000 createDofs(myAssembler, 1, vs);
1001 createDofs(myAssembler, 2, vs);
1002 LagrangeMultipliers2(myAssembler, 1, C, groups, duplicateEdges,
false, lift);
1003 LagrangeMultipliers2(myAssembler, 2, C, groups, duplicateEdges,
false, lift2);
1005 createExtraConnexions(myAssembler, G, passages);
1007 for(
size_t i = 0; i < G.size(); i++) {
1008 createLagrangeMultipliers(myAssembler, G[i]);
1009 LagrangeMultipliers3(myAssembler, G[i], lift,
false);
1012 LagrangeMultipliers2(myAssembler, 1, C, groups, duplicateEdges,
true, lift);
1013 LagrangeMultipliers2(myAssembler, 2, C, groups, duplicateEdges,
true, lift2);
1014 for(
size_t i = 0; i < G.size(); i++) {
1015 assembleLagrangeMultipliers(myAssembler, G[i]);
1016 LagrangeMultipliers3(myAssembler, G[i], lift,
true);
1019 assembleExtraConnexions(myAssembler, G, passages);
1025 for(
size_t i = 0; i <
f.size(); i++) {
1026 for(
size_t j = 0; j <
f[i]->triangles.size(); j++) {
1029 l.addToMatrix(myAssembler, &se);
1030 l2.addToMatrix(myAssembler, &se);
1034 auto itx = new2old.find(t->
getVertex(0));
1044 double F = (exp(va) + exp(vb) + exp(vc)) / 3.0;
1050 double G1[3] = {a0.
x(), a0.
y(), a0.
z()};
1051 double G2[3] = {a0.
x(), a0.
y(), a0.
z()};
1052 double G3[3] = {a0.
x(), a0.
y(), a0.
z()};
1053 double G11[3] = {
a1.x(),
a1.y(),
a1.z()};
1054 double G21[3] = {
a1.x(),
a1.y(),
a1.z()};
1055 double G31[3] = {
a1.x(),
a1.y(),
a1.z()};
1061 double RHS1 = g1[0] * G1[0] + g1[1] * G1[1] + g1[2] * G1[2];
1062 double RHS11 = g1[0] * G11[0] + g1[1] * G11[1] + g1[2] * G11[2];
1067 double RHS2 = g1[0] * G2[0] + g1[1] * G2[1] + g1[2] * G2[2];
1068 double RHS21 = g1[0] * G21[0] + g1[1] * G21[1] + g1[2] * G21[2];
1073 double RHS3 = g1[0] * G3[0] + g1[1] * G3[1] + g1[2] * G3[2];
1074 double RHS31 = g1[0] * G31[0] + g1[1] * G31[1] + g1[2] * G31[2];
1075 int num1 = myAssembler.
getDofNumber(l.getLocalDofR(&se, 0));
1076 int num2 = myAssembler.
getDofNumber(l.getLocalDofR(&se, 1));
1077 int num3 = myAssembler.
getDofNumber(l.getLocalDofR(&se, 2));
1078 int num11 = myAssembler.
getDofNumber(l2.getLocalDofR(&se, 0));
1079 int num21 = myAssembler.
getDofNumber(l2.getLocalDofR(&se, 1));
1080 int num31 = myAssembler.
getDofNumber(l2.getLocalDofR(&se, 2));
1094 Msg::Info(
"Computing potentials (%d unknowns) in %3lf seconds",
1095 myAssembler.
sizeOfR(), B - A);
1097 FILE *
F = fopen(
"map.pos",
"w");
1098 FILE *F2 = fopen(
"mapstr.pos",
"w");
1099 fprintf(
F,
"View \"MAP\"{\n");
1100 fprintf(F2,
"View \"MAPSTR\"{\n");
1101 for(
size_t i = 0; i <
f.size(); i++) {
1102 for(
size_t j = 0; j <
f[i]->triangles.size(); j++) {
1112 fprintf(
F,
"ST(%g,%g,%g,%g,%g,%g,%g,%g,%g){%g,%g,%g,%g,%g,%g};\n", a,
a1,
1113 0., b,
b1, 0.,
c,
c1, 0., a, b,
c,
a1,
b1,
c1);
1114 fprintf(F2,
"ST(%g,%g,%g,%g,%g,%g,%g,%g,%g){%g,%g,%g,%g,%g,%g};\n",
1131 fprintf(F2,
"};\n");
1136 std::set<MVertex *, MVertexPtrLessThan> &boundaries)
1140 double dmin = 1.e22;
1141 for(
auto it = boundaries.begin(); it != boundaries.end(); ++it) {
1142 SPoint3 pp((*it)->x(), (*it)->y(), (*it)->z());
1144 if(d < dmin) { dmin = d; }
1155 ref->_e.getVertex(0) == v ? ref->_e.getVertex(1) : ref->_e.getVertex(0);
1157 c->_e.getVertex(0) == v ?
c->_e.getVertex(1) :
c->_e.getVertex(0);
1159 SVector3 t1(tref->
x() - v->
x(), tref->
y() - v->
y(), tref->
z() - v->
z());
1160 SVector3 t2(tc->
x() - v->
x(), tc->
y() - v->
y(), tc->
z() - v->
z());
1164 double cosTheta =
dot(t1, t2);
1171 a = atan2(sinTheta, cosTheta);
1173 bool operator<(
const temp_comp &other)
const {
return a < other.a; }
1176 static bool isSingular(
MVertex *v, std::vector<cross2d *> &adj,
double &
MAX)
1178 const std::size_t TEST = 0;
1179 if(v->
getNum() == TEST) printf(
"VERTEX %lu\n", v->
getNum());
1181 for(
size_t i = 0; i < adj.size(); i++) {
1182 if(adj[i]->inBoundary || adj[i]->inInternalBoundary)
return false;
1187 std::vector<temp_comp> cc;
1188 for(
size_t i = 0; i < adj.size(); i++) {
1189 cc.push_back(temp_comp(v, adj[i], adj[0], n));
1191 std::sort(cc.begin(), cc.end());
1192 SVector3 ref = cc[0].cr->_tgt * cos(cc[0].cr->_atemp) +
1193 cc[0].cr->_tgt2 * sin(cc[0].cr->_atemp);
1195 for(
size_t i = 1; i < cc.size() + 1; i++) {
1196 cross2d &c2 = *(cc[i % cc.size()].cr);
1197 double P = M_PI / 2;
1198 SVector3 d1 = c2._tgt * cos(c2._atemp) + c2._tgt2 * sin(c2._atemp);
1199 SVector3 d2 = c2._tgt * cos(c2._atemp + P) + c2._tgt2 * sin(c2._atemp + P);
1201 c2._tgt * cos(c2._atemp + 2 * P) + c2._tgt2 * sin(c2._atemp + 2 * P);
1203 c2._tgt * cos(c2._atemp + 3 * P) + c2._tgt2 * sin(c2._atemp + 3 * P);
1204 double D1 =
dot(ref, d1);
1205 double D2 =
dot(ref, d2);
1206 double D3 =
dot(ref, d3);
1207 double D4 =
dot(ref, d4);
1208 if(D1 > D2 && D1 > D3 && D1 > D4)
1210 else if(D2 > D1 && D2 > D3 && D2 > D4)
1212 else if(D3 > D1 && D3 > D2 && D3 > D4)
1219 printf(
"VERTEX %lu %12.5E %12.5E %12.5E\n", v->
getNum(), n.
x(), n.
y(),
1222 std::vector<double> angles;
1223 for(
size_t i = 0; i < adj.size(); i++) {
1226 (adj[i]->_e.getVertex(0) == v) ? -adj[i]->_tgt : adj[i]->_tgt;
1227 t -= n * (
dot(t, n));
1234 SVector3 repr = adj[i]->o_i - n *
dot(adj[i]->o_i, n);
1238 double angle = atan2(
dot(repr, t0),
dot(repr, b0));
1239 adj[i]->normalize(
angle);
1240 angles.push_back(
angle);
1241 if(v->
getNum() == TEST) {
1243 adj[i]->_e.getVertex(1)->getNum());
1244 printf(
"o %12.5E %12.5E %12.5E\n", adj[i]->o_i.
x(), adj[i]->o_i.y(),
1246 printf(
"ANGLE = %12.5E %12.5E\n",
angle * 180 / M_PI,
1247 lifting(angles[0], angles[i]) * 180 / M_PI);
1252 for(
size_t i = 0; i < angles.size(); i++) {
1253 if(v->
getNum() == TEST) printf(
"%12.5E ", angles[i]);
1254 for(
size_t j = 0; j < i; j++) {
1255 MAX = std::max(
MAX, fabs(angles[i] - lifting(angles[j], angles[i])));
1258 if(v->
getNum() == TEST) printf(
"\n");
1260 printf(
"vertex %lu %lu edges %12.5E\n", v->
getNum(), adj.size(),
MAX);
1267 bool &isMin,
bool &isMax)
1270 isMin = isMax =
true;
1272 for(
size_t i = 0; i < adj.size(); i++) {
1275 adj[i]->_e.getVertex(0),
1277 if(a < aa) isMin =
false;
1278 if(a > aa) isMax =
false;
1283 computeSingularities(std::map<MEdge, cross2d, MEdgeLessThan> &C,
1284 std::set<MVertex *, MVertexPtrLessThan> &singularities,
1287 FILE *f_ = fopen(
"sing.pos",
"w");
1288 fprintf(f_,
"View \"S\"{\n");
1289 std::multimap<MVertex *, cross2d *, MVertexPtrLessThan>
conn;
1290 for(
auto it = C.begin(); it != C.end(); ++it) {
1291 std::pair<MVertex *, cross2d *> p =
1292 std::make_pair(it->first.getVertex(0), &it->second);
1294 p = std::make_pair(it->first.getVertex(1), &it->second);
1298 std::vector<cross2d *> adj;
1299 for(
auto it =
conn.begin(); it !=
conn.end(); ++it) {
1300 if(it->first == v) { adj.push_back(it->second); }
1303 if(v && isSingular(v, adj,
MAX)) {
1304 singularities.insert(v);
1306 isMinMax(v, adj, dof, isMin, isMax);
1312 printf(
"ERROR -- \n");
1313 fprintf(f_,
"SP(%g,%g,%g){%d};\n", v->
x(), v->
y(), v->
z(), indices[v]);
1317 adj.push_back(it->second);
1320 fprintf(f_,
"};\n");
1324 static void cutGraph(std::map<MEdge, cross2d, MEdgeLessThan> &C,
1325 std::set<MEdge, MEdgeLessThan> &cutG,
1326 std::set<MVertex *, MVertexPtrLessThan> &singularities,
1327 std::set<MVertex *, MVertexPtrLessThan> &boundaries)
1329 std::set<MTriangle *, MElementPtrLessThan> touched;
1330 std::vector<cross2d *> tree;
1331 std::vector<MEdge> cotree;
1332 std::set<std::pair<double, MTriangle *> > _distances;
1334 auto it = C.begin();
1335 for(; it != C.end(); ++it) {
1336 if(it->second._t.size() == 1) {
1337 boundaries.insert(it->first.getVertex(0));
1338 boundaries.insert(it->first.getVertex(1));
1342 std::set<MVertex *, MVertexPtrLessThan> _all = boundaries;
1343 _all.insert(singularities.begin(), singularities.end());
1345 FILE *fff2 = fopen(
"tree.pos",
"w");
1346 fprintf(fff2,
"View \"sides\"{\n");
1348 MTriangle *t = (C.begin())->second._t[0];
1349 std::pair<double, MTriangle *> pp = std::make_pair(
distance(t, _all), t);
1350 _distances.insert(pp);
1352 while(!_distances.empty()) {
1353 t = (_distances.begin()->second);
1354 _distances.erase(_distances.begin());
1356 for(
int i = 0; i < 3; i++) {
1358 auto it = C.find(e);
1359 for(
size_t j = 0; j < it->second._t.size(); j++) {
1361 if(touched.find(tt) == touched.end()) {
1362 std::pair<double, MTriangle *> pp =
1363 std::make_pair(
distance(t, _all), tt);
1364 _distances.insert(pp);
1366 tree.push_back(&it->second);
1372 std::sort(tree.begin(), tree.end());
1373 auto it = C.begin();
1375 for(; it != C.end(); ++it) {
1376 if(!std::binary_search(tree.begin(), tree.end(), &it->second)) {
1377 for(
int i = 0; i < 2; i++) {
1378 auto it0 = _graph.find(it->first.getVertex(i));
1379 if(it0 == _graph.end()) {
1380 std::vector<MEdge> ee;
1381 ee.push_back(it->first);
1382 _graph[it->first.getVertex(i)] = ee;
1385 it0->second.push_back(it->first);
1387 cotree.push_back(it->first);
1388 fprintf(fff2,
"SL(%g,%g,%g,%g,%g,%g){%d,%d};\n",
1389 it->first.getVertex(0)->x(), it->first.getVertex(0)->y(),
1390 it->first.getVertex(0)->z(), it->first.getVertex(1)->x(),
1391 it->first.getVertex(1)->y(), it->first.getVertex(1)->z(), 1, 1);
1395 fprintf(fff2,
"};\n");
1406 bool somethingDone =
false;
1407 auto it = _graph.begin();
1408 for(; it != _graph.end(); ++it) {
1409 if(it->second.size() == 1) {
1410 MVertex *v1 = it->second[0].getVertex(0);
1411 MVertex *v2 = it->second[0].getVertex(1);
1412 if(boundaries.find(it->first) == boundaries.end() &&
1413 singularities.find(it->first) == singularities.end()) {
1414 somethingDone =
true;
1415 auto it2 = _graph.find(v1 == it->first ? v2 : v1);
1417 std::find(it2->second.begin(), it2->second.end(), it->second[0]);
1418 it2->second.erase(position);
1423 if(!somethingDone)
break;
1426 FILE *fff = fopen(
"cotree.pos",
"w");
1427 fprintf(fff,
"View \"sides\"{\n");
1429 auto it = _graph.begin();
1430 for(; it != _graph.end(); ++it) {
1431 for(
size_t i = 0; i < it->second.size(); i++) {
1432 MEdge e = it->second[i];
1433 if(boundaries.find(e.
getVertex(0)) == boundaries.end() ||
1434 boundaries.find(e.
getVertex(1)) == boundaries.end()) {
1443 auto it = C.begin();
1444 for(; it != C.end(); ++it) {
1445 if(it->second._t.size() > 1 && it->second.inInternalBoundary) {
1446 cutG.insert(it->second._e);
1452 auto it = cutG.begin();
1453 for(; it != cutG.end(); ++it) {
1455 fprintf(fff,
"SL(%g,%g,%g,%g,%g,%g){%d,%d};\n", e.
getVertex(0)->
x(),
1460 fprintf(fff,
"};\n");
1464 int analyzeCorner(std::multimap<MVertex *, cross2d *> &
conn,
MVertex *v)
1471 groupBoundaries(
GModel *gm, std::map<MEdge, cross2d, MEdgeLessThan> &C,
1472 std::vector<std::vector<cross2d *> > &groups,
1473 std::set<MVertex *, MVertexPtrLessThan> singularities,
1474 std::set<MVertex *, MVertexPtrLessThan> &corners,
1475 bool cutGraph =
false)
1477 std::set<MVertex *, MVertexPtrLessThan> cutgraph;
1478 std::set<MVertex *, MVertexPtrLessThan> boundaries;
1479 for(
auto it = C.begin(); it != C.end(); ++it) {
1480 MVertex *v0 = it->first.getVertex(0);
1481 MVertex *v1 = it->first.getVertex(1);
1482 if(it->second.inBoundary) {
1483 boundaries.insert(v0);
1484 boundaries.insert(v1);
1486 else if(it->second.inCutGraph) {
1487 cutgraph.insert(v0);
1488 cutgraph.insert(v1);
1492 std::set<cross2d *> _all;
1494 std::multimap<MVertex *, cross2d *>
conn;
1495 for(
auto it = C.begin(); it != C.end(); ++it) {
1496 std::pair<MVertex *, cross2d *> p =
1497 std::make_pair(it->first.getVertex(0), &it->second);
1499 p = std::make_pair(it->first.getVertex(1), &it->second);
1503 for(
auto it = boundaries.begin(); it != boundaries.end(); ++it) {
1505 std::vector<cross2d *> bnd;
1506 int countCutGraph = 0;
1507 for(
auto it2 =
conn.lower_bound(v); it2 !=
conn.upper_bound(v); ++it2) {
1508 if(it2->second->inBoundary) { bnd.push_back(it2->second); }
1509 if(it2->second->inCutGraph) { countCutGraph++; }
1511 if(bnd.size() == 2) {
1512 if(fabs(
dot(bnd[0]->o_i, bnd[1]->o_i)) < .25) {
1516 if(countCutGraph == 1) { singularities.insert(v); }
1518 if(bnd.size() > 2) { cutgraph.insert(v); }
1521 std::string ss = gm->
getName();
1522 std::string fn = cutGraph ? ss +
"_groups_cg.pos" : ss +
"_groups_bnd.pos";
1524 FILE *
f = fopen(fn.c_str(),
"w");
1526 fprintf(
f,
"View \" \"{\n");
1528 std::set<MVertex *, MVertexPtrLessThan> endPoints = singularities;
1530 for(
auto it =
conn.begin(); it !=
conn.end(); ++it) {
1532 for(
auto it2 =
conn.lower_bound(it->first);
1533 it2 !=
conn.upper_bound(it->first); ++it2) {
1534 if(it2->second->inCutGraph) { count++; }
1536 if(count > 2) endPoints.insert(it->first);
1540 for(
int AA = 0; AA < 4; AA++) {
1542 for(
auto it = endPoints.begin(); it != endPoints.end(); ++it) {
1544 std::vector<cross2d *> group;
1547 for(
auto it2 =
conn.lower_bound(v); it2 !=
conn.upper_bound(v);
1549 if((_all.find(it2->second) == _all.end()) &&
1550 (group.empty() || group[group.size() - 1] != it2->second) &&
1551 it2->second->inCutGraph) {
1552 group.push_back(it2->second);
1553 vnew = (it2->second->_e.getVertex(0) == v) ?
1554 it2->second->_e.getVertex(1) :
1555 it2->second->_e.getVertex(0);
1556 fprintf(
f,
"SL(%g,%g,%g,%g,%g,%g){%lu,%lu};\n",
1557 it2->second->_e.getVertex(0)->x(),
1558 it2->second->_e.getVertex(0)->y(),
1559 it2->second->_e.getVertex(0)->z(),
1560 it2->second->_e.getVertex(1)->x(),
1561 it2->second->_e.getVertex(1)->y(),
1562 it2->second->_e.getVertex(1)->z(), groups.size(),
1567 if(vnew ==
nullptr)
break;
1569 }
while((boundaries.find(v) == boundaries.end()) &&
1570 (endPoints.find(v) == endPoints.end()));
1572 groups.push_back(group);
1573 _all.insert(group.begin(), group.end());
1578 for(
auto it = boundaries.begin(); it != boundaries.end(); ++it) {
1580 if(cutgraph.find(v) != cutgraph.end() ||
1581 singularities.find(v) != singularities.end()) {
1585 std::vector<cross2d *> group;
1588 for(
auto it2 =
conn.lower_bound(v); it2 !=
conn.upper_bound(v);
1590 if((_all.find(it2->second) == _all.end()) &&
1591 (group.empty() || group[group.size() - 1] != it2->second) &&
1592 (it2->second->inBoundary)) {
1593 group.push_back(it2->second);
1594 vnew = (it2->second->_e.getVertex(0) == v) ?
1595 it2->second->_e.getVertex(1) :
1596 it2->second->_e.getVertex(0);
1602 fprintf(
f,
"SL(%g,%g,%g,%g,%g,%g){%lu,%lu};\n",
1603 it2->second->_e.getVertex(0)->x(),
1604 it2->second->_e.getVertex(0)->y(),
1605 it2->second->_e.getVertex(0)->z(),
1606 it2->second->_e.getVertex(1)->x(),
1607 it2->second->_e.getVertex(1)->y(),
1608 it2->second->_e.getVertex(1)->z(), groups.size(),
1613 if(vnew ==
nullptr)
break;
1618 }
while(cutgraph.find(v) == cutgraph.end() &&
1619 singularities.find(v) == singularities.end());
1620 if(group.size() && _all.find(group[0]) == _all.end()) {
1621 groups.push_back(group);
1622 _all.insert(group.begin(), group.end());
1633 fastImplementationExtrinsic(std::map<MEdge, cross2d, MEdgeLessThan> &C,
1634 double tol = 1.e-10)
1636 double *data =
new double[C.size() * 6];
1637 size_t *graph =
new size_t[C.size() * 4];
1638 auto it = C.begin();
1641 for(; it != C.end(); ++it) {
1642 data[6 * counter + 0] = it->second.o_i.x();
1643 data[6 * counter + 1] = it->second.o_i.y();
1644 data[6 * counter + 2] = it->second.o_i.z();
1645 data[6 * counter + 3] = it->second._nrml.x();
1646 data[6 * counter + 4] = it->second._nrml.y();
1647 data[6 * counter + 5] = it->second._nrml.z();
1648 it->second.counter = counter;
1654 for(; it != C.end(); ++it) {
1655 graph[4 * counter + 0] = graph[4 * counter + 1] = graph[4 * counter + 2] =
1656 graph[4 * counter + 3] = it->second.counter;
1657 for(
size_t i = 0; i < it->second._cneighbors.size(); i++) {
1658 graph[4 * counter + i] = it->second._cneighbors[i]->counter;
1660 if(it->second.inBoundary || it->second.inInternalBoundary) {
1661 graph[4 * counter + 2] = graph[4 * counter + 3] = it->second.counter;
1667 size_t N = C.size();
1668 int MAXITER = 10000;
1670 while(ITER++ < MAXITER) {
1673 for(
size_t i = 0; i < N; i++) {
1674 double *r = &data[6 * i + 0];
1675 double *n = &data[6 * i + 3];
1677 size_t *neigh = &graph[4 * i];
1679 if(neigh[2] != neigh[3]) {
1680 for(
int j = 0; j < 4; j++) {
1681 size_t k = neigh[j];
1682 const double *r2 = &data[6 * k + 0];
1683 const double *n2 = &data[6 * k + 3];
1684 compat_orientation_extrinsic(r, n, r2, n2, x, y);
1685 r[0] = x[0] * weight + y[0];
1686 r[1] = x[1] * weight + y[1];
1687 r[2] = x[2] * weight + y[2];
1688 const double dd = r[0] * n[0] + r[1] * n[1] + r[2] * n[2];
1692 double NRM = sqrt(r[0] * r[0] + r[1] * r[1] + r[2] * r[2]);
1700 double dp = r[0] * ro[0] + r[1] * ro[1] + r[2] * ro[2];
1701 RES += std::min(1. - fabs(dp), fabs(dp));
1707 if(ITER % 1000 == 0)
1708 Msg::Info(
"NL smooth : iter %6d RES = %12.5E", ITER, RES);
1709 if(RES < tol)
break;
1713 for(; it != C.end(); ++it) {
1714 counter = it->second.counter;
1715 it->second.o_i[0] = data[6 * counter + 0];
1716 it->second.o_i[1] = data[6 * counter + 1];
1717 it->second.o_i[2] = data[6 * counter + 2];
1724 std::set<MVertex *, MVertexPtrLessThan> &vs,
1725 std::map<MEdge, cross2d, MEdgeLessThan> &C)
1727 #if defined(HAVE_PETSC)
1729 #elif defined(HAVE_GMM)
1739 for(
auto it = vs.begin(); it != vs.end(); ++it)
1742 std::string ss = gm->
getName();
1743 std::string fn = ss +
"_grad.pos";
1745 FILE *_f = fopen(fn.c_str(),
"w");
1746 fprintf(_f,
"View \"grad\"{\n");
1751 std::map<MTriangle *, SVector3> gradients_of_theta;
1753 for(
size_t i = 0; i <
f.size(); i++) {
1754 for(
size_t j = 0; j <
f[i]->triangles.size(); j++) {
1767 l.addToMatrix(*myAssembler, &se);
1771 auto it0 = C.find(e0);
1772 auto it1 = C.find(e1);
1773 auto it2 = C.find(e2);
1777 double a0 = it0->second._a;
1779 it1->second._a + atan2(
dot(it0->second._tgt2, it1->second._tgt),
1780 dot(it0->second._tgt, it1->second._tgt));
1781 it0->second.normalize(A1);
1782 double a1 = it0->second.lifting(A1);
1784 it2->second._a + atan2(
dot(it0->second._tgt2, it2->second._tgt),
1785 dot(it0->second._tgt, it2->second._tgt));
1786 it0->second.normalize(A2);
1787 double a2 = it0->second.lifting(A2);
1791 t_i -= xx *
dot(xx, t_i);
1794 o_i -= xx *
dot(xx, o_i);
1797 o_1 -= xx *
dot(xx, o_1);
1800 o_2 -= xx *
dot(xx, o_2);
1802 compat_orientation_extrinsic(o_i, xx, o_1, xx, x0, x1);
1803 compat_orientation_extrinsic(o_i, xx, o_2, xx, x2, x3);
1811 a0 = atan2(
dot(t_i, o_i),
dot(it0->second._tgt, o_i));
1813 x0 -= xx *
dot(xx, x0);
1815 x1 -= xx *
dot(xx, x1);
1817 x2 -= xx *
dot(xx, x2);
1819 x3 -= xx *
dot(xx, x3);
1822 it0->second.normalize(a0);
1823 it0->second._a = a0;
1828 A1 = atan2(
dot(t_i, x1),
dot(it0->second._tgt, x1));
1829 A2 = atan2(
dot(t_i, x3),
dot(it0->second._tgt, x3));
1830 it0->second.normalize(A1);
1831 a1 = it0->second.lifting(A1);
1832 it0->second.normalize(A2);
1833 a2 = it0->second.lifting(A2);
1840 double a[3] = {a0 +
a2 -
a1, a0 +
a1 -
a2,
a1 +
a2 - a0};
1841 double g[3] = {0, 0, 0};
1843 gradients_of_theta[t] =
SVector3(g[0], g[1], g[2]);
1855 fprintf(_f,
"VP(%g,%g,%g){%g,%g,%g};\n", pp.
x(), pp.
y(), pp.
z(), g[0],
1871 double RHS1 = g1[0] * GT.
x() + g1[1] * GT.
y() + g1[2] * GT.
z();
1877 double RHS2 = g1[0] * GT.
x() + g1[1] * GT.
y() + g1[2] * GT.
z();
1883 double RHS3 = g1[0] * GT.
x() + g1[1] * GT.
y() + g1[2] * GT.
z();
1885 int num1 = myAssembler->
getDofNumber(l.getLocalDofR(&se, 0));
1886 int num2 = myAssembler->
getDofNumber(l.getLocalDofR(&se, 1));
1887 int num3 = myAssembler->
getDofNumber(l.getLocalDofR(&se, 2));
1894 fprintf(_f,
"};\n");
1908 static double coord1d(
double a0,
double a1,
double a)
1910 if(
a1 == a0)
return 0.0;
1911 return (a - a0) / (
a1 - a0);
1915 std::vector<SPoint3> ps;
1916 std::vector<MVertex *> vs;
1917 std::vector<int> indexOfCuts;
1918 std::vector<int> idsOfCuts;
1919 bool add(
const SPoint3 &p,
int ind,
int id)
1921 for(
size_t i = 0; i < ps.size(); i++) {
1923 if(v.norm() < 1.e-10) {
return false; }
1926 indexOfCuts.push_back(ind);
1927 idsOfCuts.push_back(
id);
1930 void finish(
GModel *gm, FILE *
f =
nullptr)
1932 for(
size_t i = 0; i < ps.size(); i++) {
1939 new MEdgeVertex(ps[i].x(), ps[i].y(), ps[i].
z(), ge, 0.0);
1941 fprintf(
f,
"SP(%g,%g,%g){%d};\n", ps[i].x(), ps[i].y(), ps[i].
z(),
1950 static bool addCut(
const SPoint3 &p,
const MEdge &e,
int COUNT,
int ID,
1951 std::map<MEdge, edgeCuts, MEdgeLessThan> &cuts)
1953 auto itc = cuts.find(e);
1954 if(itc != cuts.end()) {
1955 if(!itc->second.add(p, COUNT, ID))
return false;
1960 if(!cc.add(p, COUNT, ID))
return false;
1966 static void computeOneIsoRecur(
1968 SPoint3 &p, std::map<MVertex *, double> &pot,
1969 std::map<MEdge, int, MEdgeLessThan> &visited,
1970 std::map<
MEdge, std::pair<std::map<MVertex *, double> *,
double>,
1972 std::map<MEdge, MEdge, MEdgeLessThan> &d1, std::vector<groupOfCross2d> &G,
1973 FILE *
f,
int COUNT, std::map<MEdge, edgeCuts, MEdgeLessThan> &cuts,
int &NB,
1980 if(
distance(&vvv, vsing) < 1.e-10) {
1985 bool added = addCut(p, e, COUNT, NB, cuts);
1992 if(d1.find(e) != d1.end()) {
1993 std::pair<std::map<MVertex *, double> *,
double> aa =
1994 std::make_pair(&pot, VAL);
1995 std::pair<MEdge, std::pair<std::map<MVertex *, double> *,
double> > p =
1996 std::make_pair(e, aa);
1997 cutGraphEnds.insert(p);
1999 std::vector<MElement *> lst = adj[v0];
2001 MVertex *vs[2] = {
nullptr,
nullptr};
2003 for(
size_t i = 0; i < lst.size(); i++) {
2004 if((lst[i]->getVertex(0) == v0 && lst[i]->getVertex(1) == v1) ||
2005 (lst[i]->getVertex(0) == v1 && lst[i]->getVertex(1) == v0)) {
2006 vs[count++] = lst[i]->getVertex(2);
2008 if((lst[i]->getVertex(0) == v0 && lst[i]->getVertex(2) == v1) ||
2009 (lst[i]->getVertex(0) == v1 && lst[i]->getVertex(2) == v0)) {
2010 vs[count++] = lst[i]->getVertex(1);
2012 if((lst[i]->getVertex(1) == v0 && lst[i]->getVertex(2) == v1) ||
2013 (lst[i]->getVertex(1) == v1 && lst[i]->getVertex(2) == v0)) {
2014 vs[count++] = lst[i]->getVertex(0);
2018 double U[2] = {pot[v0], pot[v1]};
2021 for(
int i = 0; i < 2; i++) {
2023 double U2 = pot[vs[i]];
2024 SPoint3 ppp(vs[i]->x(), vs[i]->y(), vs[i]->
z());
2025 if((U[0] - VAL) * (U2 - VAL) <= 0) {
2026 double xi = coord1d(U[0], U2, VAL);
2027 SPoint3 pp = p0 * (1. - xi) + ppp * xi;
2028 fprintf(
f,
"SL(%g,%g,%g,%g,%g,%g){%d,%d};\n", p.x(), p.y(), p.z(),
2029 pp.
x(), pp.
y(), pp.
z(), COUNT, COUNT);
2030 computeOneIsoRecur(vsing, adj, VAL, v0, vs[i], pp, pot, visited,
2031 cutGraphEnds, d1, G,
f, COUNT, cuts, NB, circular);
2033 else if((U[1] - VAL) * (U2 - VAL) <= 0) {
2034 double xi = coord1d(U[1], U2, VAL);
2035 SPoint3 pp = p1 * (1. - xi) + ppp * xi;
2036 fprintf(
f,
"SL(%g,%g,%g,%g,%g,%g){%d,%d};\n", p.x(), p.y(), p.z(),
2037 pp.
x(), pp.
y(), pp.
z(), COUNT, COUNT);
2038 computeOneIsoRecur(vsing, adj, VAL, v1, vs[i], pp, pot, visited,
2039 cutGraphEnds, d1, G,
f, COUNT, cuts, NB, circular);
2042 printf(
"strange\n");
2051 std::map<MVertex *, double> *potU,
2052 std::map<MVertex *, double> *potV,
2053 std::map<MEdge, MEdge, MEdgeLessThan> &d1,
2054 std::vector<groupOfCross2d> &G, FILE *
f,
int COUNT,
2055 std::map<MEdge, edgeCuts, MEdgeLessThan> &cuts,
2056 std::vector<cutGraphPassage> &passages)
2058 std::map<MEdge, int, MEdgeLessThan> visited;
2059 std::map<MEdge, std::pair<std::map<MVertex *, double> *,
double>,
2065 computeOneIsoRecur(vsing, adj, VAL, v0, v1, p, *potU, visited, cutGraphEnds,
2066 d1, G,
f, COUNT, cuts, NB, circular);
2070 while(!cutGraphEnds.empty()) {
2071 MEdge e = (*cutGraphEnds.begin()).first;
2072 std::map<MVertex *, double> *POT = (*cutGraphEnds.begin()).second.first;
2073 VAL = (*cutGraphEnds.begin()).second.second;
2082 cutGraphEnds.erase(cutGraphEnds.begin());
2087 int cutGraphId = -1;
2088 for(
size_t i = 0; i < G.size(); i++) {
2090 count += (std::find(G[i].left.begin(), G[i].left.end(), o.
getVertex(0)) !=
2094 count += (std::find(G[i].left.begin(), G[i].left.end(), o.
getVertex(1)) !=
2098 count += (std::find(G[i].right.begin(), G[i].right.end(),
2102 count += (std::find(G[i].right.begin(), G[i].right.end(),
2106 count += (std::find(G[i].left.begin(), G[i].left.end(), e.
getVertex(0)) !=
2110 count += (std::find(G[i].left.begin(), G[i].left.end(), e.
getVertex(1)) !=
2114 count += (std::find(G[i].right.begin(), G[i].right.end(),
2118 count += (std::find(G[i].right.begin(), G[i].right.end(),
2122 if(count > maxCount) {
2124 ROT = fabs(G[i].mat[0][0]) > .6 ? 0 : 1;
2128 if(maxCount == 0) printf(
"IMPOSSIBLE\n");
2130 int pot = POT == potU ? 0 : 1;
2134 for(std::size_t k = 0; k < passages.size(); k++) {
2135 if(pot == passages[k]._uv && cutGraphId == passages[k]._id) count++;
2139 printf(
"CYCLE DETECTED for SING %lu : ", vsing->
getNum());
2140 for(
size_t k = 0; k < passages.size(); k++)
2141 printf(
"(%d,%d) ", passages[k]._id, passages[k]._uv);
2146 if(passages.empty() || passages[passages.size() - 1]._uv != pot ||
2147 passages[passages.size() - 1]._id != cutGraphId) {
2148 passages.push_back(cutGraphPassage(cutGraphId, pot, p));
2151 if(ROT) { POT = (POT == potU ? potV : potU); }
2161 visited, cutGraphEnds, d1, G,
f, COUNT, cuts, NB,
2163 if(XX > 1200)
break;
2169 std::map<MVertex *, double> &potU,
2170 std::map<MVertex *, double> &potV, FILE *
f,
2171 std::map<MEdge, MEdge, MEdgeLessThan> &d1,
2172 std::vector<groupOfCross2d> &G,
int DIR,
2173 std::map<MEdge, edgeCuts, MEdgeLessThan> &cuts,
2174 std::vector<cutGraphPassage> &passages)
2176 int COUNT = 100 * vsing->
getNum() + 10 * DIR;
2177 std::vector<MElement *>
faces = adj[vsing];
2178 for(
size_t i = 0; i <
faces.size(); i++) {
2182 double U0 = potU[v0];
2183 double U1 = potU[v1];
2184 double U2 = potU[v2];
2189 if(v2 == vsing && (U0 - u) * (U1 - u) <= 0) {
2190 double xi = coord1d(U0, U1, u);
2191 SPoint3 pp = p0 * (1 - xi) + p1 * xi;
2192 circular = computeOneIso(vsing, adj, u, v0, v1, pp, &potU, &potV, d1, G,
2193 f, COUNT++, cuts, passages);
2195 else if(v1 == vsing && (U0 - u) * (U2 - u) <= 0) {
2196 double xi = coord1d(U0, U2, u);
2197 SPoint3 pp = p0 * (1 - xi) + p2 * xi;
2198 circular = computeOneIso(vsing, adj, u, v0, v2, pp, &potU, &potV, d1, G,
2199 f, COUNT++, cuts, passages);
2201 else if(v0 == vsing && (U1 - u) * (U2 - u) <= 0) {
2202 double xi = coord1d(U1, U2, u);
2203 SPoint3 pp = p1 * (1 - xi) + p2 * xi;
2204 circular = computeOneIso(vsing, adj, u, v1, v2, pp, &potU, &potV, d1, G,
2205 f, COUNT++, cuts, passages);
2207 if(circular == 2) printf(
"ISO %d is circular %d\n", COUNT - 1, circular);
2208 if(circular == -1) {
2209 printf(
"ISO %d is CYCLIC\n", COUNT - 1);
2216 static bool computeIsos(
2218 std::set<MVertex *, MVertexPtrLessThan> singularities,
2219 std::map<MEdge, cross2d, MEdgeLessThan> &C,
2220 std::map<MVertex *, MVertex *, MVertexPtrLessThan> &new2old,
2221 std::map<MEdge, MEdge, MEdgeLessThan> &duplicateEdges,
2222 std::vector<std::vector<cross2d *> > &groups,
2223 std::vector<std::vector<cross2d *> > &groups_cg,
2224 std::map<MVertex *, double> &potU, std::map<MVertex *, double> &potV,
2225 std::set<MEdge, MEdgeLessThan> &cutG, std::vector<groupOfCross2d> &G,
2226 std::map<MEdge, edgeCuts, MEdgeLessThan> &cuts,
2227 std::vector<cutGraphPassage> &passages)
2230 for(
size_t i = 0; i <
faces.size(); i++) {
2235 auto it = new2old.begin();
2236 for(; it != new2old.end(); ++it) {
2237 if(singularities.find(it->second) != singularities.end()) {
2238 singularities.insert(it->first);
2243 std::map<MVertex *, MVertex *, MVertexPtrLessThan> duplicates;
2245 auto it = new2old.begin();
2246 for(; it != new2old.end(); ++it) {
2247 duplicates[it->first] = it->second;
2248 duplicates[it->second] = it->first;
2252 std::map<MEdge, MEdge, MEdgeLessThan> d1;
2254 for(
size_t i = 0; i < G.size(); i++) {
2255 for(
size_t j = 0; j < G[i].side.size(); j++) {
2256 for(
size_t k = 0; k < 3; k++) {
2257 MVertex *v0 = G[i].side[j]->getVertex(k);
2258 MVertex *v1 = G[i].side[j]->getVertex((k + 1) % 3);
2260 for(
size_t l = 0; l < G[i].left.size(); l++) {
2261 if(G[i].left[l] == v0) { I = l; }
2262 if(G[i].left[l] == v1) { J = l; }
2264 if(I >= 0 && J >= 0) {
2265 MEdge l(G[i].left[I], G[i].left[J]);
2266 MEdge r(G[i].right[I], G[i].right[J]);
2272 if(G[i].singularities.size() == 1) {
2273 MEdge l(G[i].singularities[0], G[i].left[G[i].left.size() - 1]);
2274 MEdge r(G[i].singularities[0], G[i].right[G[i].right.size() - 1]);
2280 std::string fn = gm->
getName() +
"_QLayoutResults.pos";
2281 FILE *
f = fopen(fn.c_str(),
"w");
2282 fprintf(
f,
"View\"Big Cut\"{\n");
2284 auto it = singularities.begin();
2285 for(; it != singularities.end(); ++it) {
2286 GEntity *ge = (*it)->onWhat();
2287 if(ge->
dim() == 2 || ge->
edges().size() == 0) {
2288 printf(
"%lu %d %d %lu %22.15E %22.15E\n", ge->
edges().size(), ge->
tag(),
2289 ge->
dim(), singularities.size(), potU[*it], potV[*it]);
2290 bool success = computeIso(*it, adj, potU[*it], potU, potV,
f, d1, G, 0,
2293 printf(
"CYCLIC STUFF\n");
2296 success = computeIso(*it, adj, potV[*it], potV, potU,
f, d1, G, 1, cuts,
2299 printf(
"CYCLIC STUFF\n");
2309 void getAllConnectedTriangles(
2310 cross2d *start, std::vector<cross2d *> &group,
2311 std::set<MVertex *, MVertexPtrLessThan> &isolated_singularities,
2312 std::set<MVertex *, MVertexPtrLessThan> &all, std::set<MTriangle *> &t,
2313 std::set<MTriangle *> &allTrianglesConsidered)
2315 std::set<cross2d *> touched;
2320 for(
size_t i = 0; i < group.size(); i++) {
2321 if(isolated_singularities.find(group[i]->_e.getVertex(0)) ==
2322 isolated_singularities.end())
2324 if(isolated_singularities.find(group[i]->_e.getVertex(1)) ==
2325 isolated_singularities.end())
2329 if(allTrianglesConsidered.find(start->_t[0]) !=
2330 allTrianglesConsidered.end()) {
2331 if(!start->_cneighbors[0]->inCutGraph)
2332 start = start->_cneighbors[0];
2333 else if(!start->_cneighbors[1]->inCutGraph)
2334 start = start->_cneighbors[1];
2338 else if(start->_cneighbors.size() == 4 &&
2339 allTrianglesConsidered.find(start->_t[1]) !=
2340 allTrianglesConsidered.end()) {
2341 if(start->_cneighbors.size() == 4 && !start->_cneighbors[2]->inCutGraph)
2342 start = start->_cneighbors[2];
2343 else if(start->_cneighbors.size() == 4 &&
2344 !start->_cneighbors[3]->inCutGraph)
2345 start = start->_cneighbors[3];
2350 if(!start->_cneighbors[0]->inCutGraph)
2351 start = start->_cneighbors[0];
2352 else if(!start->_cneighbors[1]->inCutGraph)
2353 start = start->_cneighbors[1];
2354 else if(start->_cneighbors.size() == 4 &&
2355 !start->_cneighbors[2]->inCutGraph)
2356 start = start->_cneighbors[2];
2357 else if(start->_cneighbors.size() == 4 &&
2358 !start->_cneighbors[3]->inCutGraph)
2359 start = start->_cneighbors[3];
2364 std::stack<cross2d *> _s;
2367 while(!_s.empty()) {
2369 touched.insert(start);
2371 for(
size_t i = 0; i < start->_t.size(); i++) {
2372 t.insert(start->_t[i]);
2373 allTrianglesConsidered.insert(start->_t[i]);
2376 for(
size_t i = 0; i < start->_cneighbors.size(); i++) {
2377 cross2d *
c = start->_cneighbors[i];
2378 if(!
c->inCutGraph && touched.find(
c) == touched.end()) {
2379 if(all.find(
c->_e.getVertex(0)) != all.end() ||
2380 all.find(
c->_e.getVertex(1)) != all.end()) {
2388 static bool computeLeftRight(groupOfCross2d &g,
MVertex **left,
MVertex **right)
2390 for(
size_t i = 0; i < g.side.size(); i++) {
2391 if(g.side[i]->getVertex(0) == *right || g.side[i]->getVertex(1) == *right ||
2392 g.side[i]->getVertex(2) == *right) {
2398 if(g.side[i]->getVertex(0) == *left || g.side[i]->getVertex(1) == *left ||
2399 g.side[i]->getVertex(2) == *left) {
2406 static void createJumpyPairs(
2407 groupOfCross2d &g, std::set<MVertex *, MVertexPtrLessThan> &singularities,
2408 std::set<MVertex *, MVertexPtrLessThan> &boundaries,
2409 std::multimap<MVertex *, MVertex *, MVertexPtrLessThan> &old2new)
2411 std::set<MVertex *, MVertexPtrLessThan> touched;
2414 for(
size_t i = 0; i < g.crosses.size(); ++i) {
2415 cross2d *
c = g.crosses[i];
2416 for(
size_t j = 0; j < 2; j++) {
2418 if(touched.find(vv) == touched.end()) {
2428 else if(v1 ==
nullptr)
2437 else if(v1 ==
nullptr)
2442 for(
auto it = old2new.lower_bound(vv); it != old2new.upper_bound(vv);
2449 else if(v1 ==
nullptr)
2458 else if(v1 ==
nullptr)
2464 if(!v1 || !v0)
Msg::Error(
"error in JumpyPairs 3");
2465 if(computeLeftRight(g, &v0, &v1)) {
2466 if(boundaries.find(vv) != boundaries.end()) {
2467 g.left.insert(g.left.begin(), v0);
2468 g.right.insert(g.right.begin(), v1);
2471 g.left.push_back(v0);
2472 g.right.push_back(v1);
2478 else if(singularities.find(vv) != singularities.end()) {
2479 g.singularities.push_back(vv);
2492 analyzeGroup(std::vector<cross2d *> &group, groupOfCross2d &g,
2493 std::map<MTriangle *, SVector3> &d,
2494 std::map<MTriangle *, SVector3> &d2,
v2t_cont &adj,
2495 std::set<MVertex *, MVertexPtrLessThan> &isolated_singularities,
2496 std::set<MVertex *, MVertexPtrLessThan> &boundaries,
2497 std::set<MTriangle *> &allTrianglesConsidered)
2501 for(
size_t i = 0; i < g.crosses.size(); ++i) {
2502 cross2d *
c = g.crosses[i];
2503 if(
c->_t.size() == 2) {
2513 for(
size_t i = 0; i < g.crosses.size(); ++i) {
2514 cross2d *
c = g.crosses[i];
2515 c->rotation = g.rot;
2518 std::set<MTriangle *> t;
2519 std::set<MVertex *, MVertexPtrLessThan> all;
2520 getAllConnectedTriangles(group[0], group, isolated_singularities, all, t,
2521 allTrianglesConsidered);
2522 g.side.insert(g.side.begin(), t.begin(), t.end());
2523 g.vertices.insert(g.vertices.begin(), all.begin(), all.end());
2526 for(
size_t i = 0; i < g.crosses.size(); ++i) {
2527 cross2d *
c = g.crosses[i];
2528 if(
c->_t.size() == 2) {
2529 if(t.find(
c->_t[0]) != t.end()) {
2530 g.mat[0][0] =
dot(d[
c->_t[0]], d[
c->_t[1]]);
2531 g.mat[0][1] =
dot(d[
c->_t[0]], d2[
c->_t[1]]);
2532 g.mat[1][0] =
dot(d2[
c->_t[0]], d[
c->_t[1]]);
2533 g.mat[1][1] =
dot(d2[
c->_t[0]], d2[
c->_t[1]]);
2535 else if(t.find(
c->_t[1]) != t.end()) {
2536 g.mat[0][0] =
dot(d[
c->_t[0]], d[
c->_t[1]]);
2537 g.mat[1][0] =
dot(d[
c->_t[0]], d2[
c->_t[1]]);
2538 g.mat[0][1] =
dot(d2[
c->_t[0]], d[
c->_t[1]]);
2539 g.mat[1][1] =
dot(d2[
c->_t[0]], d2[
c->_t[1]]);
2543 for(
int j = 0; j < 2; j++) {
2544 for(
int k = 0; k < 2; k++) {
2545 if(g.mat[j][k] > .7)
2547 else if(g.mat[j][k] < -.7)
2556 class quadLayoutData {
2559 std::vector<GFace *>
f;
2560 std::map<MEdge, cross2d, MEdgeLessThan> C;
2562 std::set<MVertex *, MVertexPtrLessThan> vs;
2563 std::set<MEdge, MEdgeLessThan> cutG;
2564 std::set<MVertex *, MVertexPtrLessThan> singularities;
2565 std::map<MVertex *, int> indices;
2566 std::map<MVertex *, double> gaussianCurvatures;
2567 std::set<MVertex *, MVertexPtrLessThan> boundaries;
2568 std::set<MVertex *, MVertexPtrLessThan> corners;
2569 std::vector<std::vector<cross2d *> > groups;
2570 std::vector<std::vector<cross2d *> > groups_cg;
2571 std::map<MVertex *, MVertex *, MVertexPtrLessThan> new2old;
2572 std::string modelName;
2573 std::map<MTriangle *, SVector3> d0, d1;
2574 std::vector<groupOfCross2d> G;
2576 void printTheta(
const char *name)
2578 std::string fn = modelName +
"_" + name +
".pos";
2579 FILE *of = fopen(fn.c_str(),
"w");
2580 fprintf(of,
"View \"Theta\"{\n");
2581 for(
size_t i = 0; i <
f.size(); i++) {
2582 for(
size_t j = 0; j <
f[i]->triangles.size(); j++) {
2584 auto it0 = C.find(t->
getEdge(0));
2585 auto it1 = C.find(t->
getEdge(1));
2586 auto it2 = C.find(t->
getEdge(2));
2591 double a = atan2(d0.
y(), d0.
x());
2592 double b = atan2(d1.
y(), d1.
x());
2593 double c = atan2(d2.
y(), d2.
x());
2594 it0->second.normalize(a);
2595 it0->second.normalize(b);
2596 it0->second.normalize(
c);
2597 double A =
c + a - b;
2598 double B = a + b -
c;
2599 double C = b +
c - a;
2600 it0->second.normalize(A);
2601 it0->second.normalize(B);
2602 it0->second.normalize(C);
2603 fprintf(of,
"ST(%g,%g,%g,%g,%g,%g,%g,%g,%g){%g,%g,%g};\n",
2611 fprintf(of,
"};\n");
2615 void printCross(
const char *name)
2617 std::string fn = modelName +
"_" + name +
".pos";
2618 FILE *of = fopen(fn.c_str(),
"w");
2619 fprintf(of,
"View \"Direction fields\"{\n");
2620 auto it = C.begin();
2621 for(it = C.begin(); it != C.end(); ++it) {
2622 double a0 = it->second._a;
2623 MEdge e0 = it->second._e;
2624 SVector3 d1 = (it->second._tgt * cos(a0) + it->second._tgt2 * sin(a0));
2625 SVector3 d2 = (it->second._tgt * (-sin(a0)) + it->second._tgt2 * cos(a0));
2626 SVector3 d3 = (it->second._tgt * (-cos(a0)) - it->second._tgt2 * sin(a0));
2627 SVector3 d4 = (it->second._tgt * sin(a0) - it->second._tgt2 * cos(a0));
2629 for(
size_t I = 0; I < it->second._t.size(); I++) {
2630 fprintf(of,
"VP(%g,%g,%g){%g,%g,%g};\n",
2635 fprintf(of,
"VP(%g,%g,%g){%g,%g,%g};\n",
2640 fprintf(of,
"VP(%g,%g,%g){%g,%g,%g};\n",
2645 fprintf(of,
"VP(%g,%g,%g){%g,%g,%g};\n",
2652 fprintf(of,
"};\n");
2656 int computeCrossFieldExtrinsic(
double tol,
size_t nIterLaplace = 2000)
2658 std::vector<cross2d *> pc;
2659 for(
auto it = C.begin(); it != C.end(); ++it) pc.push_back(&(it->second));
2662 while(ITER++ < nIterLaplace) {
2663 if(ITER % 200 == 0) std::random_shuffle(pc.begin(), pc.end());
2664 for(
size_t i = 0; i < pc.size(); i++) pc[i]->average_init();
2665 if(ITER % 1000 == 0)
Msg::Info(
"Linear smooth : iter %6lu", ITER);
2668 for(
size_t i = 0; i < pc.size(); i++) pc[i]->computeVector();
2670 fastImplementationExtrinsic(C, tol);
2672 for(
size_t i = 0; i < pc.size(); i++) pc[i]->computeAngle();
2679 std::string fn = modelName +
"_" +
c +
".pos";
2681 FILE *_f = fopen(fn.c_str(),
"w");
2682 fprintf(_f,
"View \"H\"{\n");
2684 for(
size_t i = 0; i <
f.size(); i++) {
2685 for(
size_t j = 0; j <
f[i]->triangles.size(); j++) {
2691 fprintf(_f,
"ST(%g,%g,%g,%g,%g,%g,%g,%g,%g){%g,%g,%g};\n",
2699 fprintf(_f,
"};\n");
2705 computeCrossFieldExtrinsic(1.e-9);
2706 myAssembler = computeH(gm,
f, vs, C);
2708 computeSingularities(C, singularities, indices, myAssembler);
2716 #if defined(HAVE_PETSC)
2718 #elif defined(HAVE_GMM)
2726 auto it = C.begin();
2727 std::vector<MEdge>
edges;
2728 for(; it != C.end(); ++it) {
2729 if(it->second.inBoundary) {
edges.push_back(it->first); }
2731 std::vector<std::vector<MVertex *> > vsorted;
2737 for(
auto it = vs.begin(); it != vs.end(); ++it) {
2744 std::set<GEntity *> firsts;
2745 for(
size_t i = 0; i <
f.size(); i++) {
2746 std::vector<GEdge *> e =
f[i]->edges();
2747 if(e.size()) firsts.insert(e[0]);
2749 for(
size_t j = 0; j <
f[i]->triangles.size(); j++) {
2752 l.addToMatrix(*dof, &se);
2756 for(
size_t j = 0; j < vsorted.size(); ++j) {
2757 if(vsorted[j][0] == vsorted[j][vsorted[j].size() - 1]) {
2758 vsorted[j].erase(vsorted[j].begin());
2761 std::vector<double> CURVATURE;
2762 CURVATURE.resize(vsorted[j].size());
2763 for(
size_t i = 0; i < vsorted[j].size(); ++i) { CURVATURE[i] = 0.0; }
2765 for(
size_t i = 0; i < vsorted[j].size(); ++i) {
2767 MVertex *vip = vsorted[j][(i + 1) % vsorted[j].size()];
2769 vsorted[j][(i + vsorted[j].size() - 1) % vsorted[j].size()];
2770 SVector3 vv(vip->
x() - vi->
x(), vip->
y() - vi->
y(), vip->
z() - vi->
z());
2771 SVector3 ww(vi->
x() - vim->
x(), vi->
y() - vim->
y(), vi->
z() - vim->
z());
2775 double ccos =
dot(vv, ww);
2776 double ANGLE = atan2(xx.
norm(), ccos);
2779 MEdge edze(vi, vim);
2780 auto itip = C.find(edze);
2782 if(itip != C.end()) {
2794 vrv->
z() - vim->
z());
2797 sign = -
dot(zz, xx);
2803 CURVATURE[i] += ANGLE * sign;
2807 for(
size_t i = 0; i < vsorted[j].size(); ++i) {
2813 for(
auto it = gaussianCurvatures.begin(); it != gaussianCurvatures.end();
2819 for(
auto it = sing.begin(); it != sing.end(); ++it) {
2822 2.0 * M_PI * (
double)it->second / nbTurns);
2829 for(
auto it = vs.begin(); it != vs.end(); ++it) {
2839 int computeHFromSingularities(std::map<MVertex *, int> &s)
2841 myAssembler = computeHFromSingularities(s, 4);
2842 for(
auto it = s.begin(); it != s.end(); ++it) {
2843 singularities.insert(it->first);
2851 void computeThetaUsingHCrouzeixRaviart(
2852 std::map<
int, std::vector<double> > &dataTHETA)
2854 #if defined(HAVE_PETSC)
2856 #elif defined(HAVE_GMM)
2863 std::map<MEdge, size_t, MEdgeLessThan> aaa;
2865 for(
size_t i = 0; i <
f.size(); i++) {
2866 for(
size_t j = 0; j <
f[i]->triangles.size(); j++) {
2867 for(
size_t k = 0; k < 3; k++) {
2868 if(aaa.find(
f[i]->triangles[j]->getEdge(k)) == aaa.end()) {
2871 aaa[
f[i]->triangles[j]->getEdge(k)] = count++;
2877 for(
size_t i = 0; i <
f.size(); i++) {
2878 for(
size_t j = 0; j <
f[i]->triangles.size(); j++) {
2881 double g1[3], g2[3], g3[3];
2896 G[0] =
SVector3(g1[0] + g2[0] - g3[0], g1[1] + g2[1] - g3[1],
2897 g1[2] + g2[2] - g3[2]);
2898 G[1] =
SVector3(g2[0] + g3[0] - g1[0], g2[1] + g3[1] - g1[1],
2899 g2[2] + g3[2] - g1[2]);
2900 G[2] =
SVector3(g1[0] + g3[0] - g2[0], g1[1] + g3[1] - g2[1],
2901 g1[2] + g3[2] - g2[2]);
2912 for(
int k = 0; k < 3; k++) {
2913 auto itk = new2old.find(t->
getVertex(k));
2914 if(itk == new2old.end())
2917 myAssembler->
getDofValue(itk->second, 0, 1, H[k]);
2922 SVector3 temp(gradH[0], gradH[1], gradH[2]);
2925 double RHS[3] = {
dot(gradHOrtho, G[0]),
dot(gradHOrtho, G[1]),
2926 dot(gradHOrtho, G[2])};
2928 for(
size_t k = 0; k < 3; k++) {
2931 for(
size_t l = 0; l < 3; l++) {
2944 auto it = aaa.begin();
2945 for(; it != aaa.end(); ++it) {
2950 auto it0 = new2old.find(it->first.getVertex(0));
2951 if(it0 == new2old.end())
2952 v0 = it->first.getVertex(0);
2955 it0 = new2old.find(it->first.getVertex(1));
2956 if(it0 == new2old.end())
2957 v1 = it->first.getVertex(1);
2961 auto itc = C.find(e);
2963 itc->second.o_i =
SVector3(cos(t), sin(t), 0.0);
2965 double aa = atan2(
dot(itc->second._tgt2, itc->second.o_i),
2966 dot(itc->second._tgt, itc->second.o_i));
2967 itc->second.normalize(aa);
2968 if(!itc->second.inBoundary) { itc->second._a = aa; }
2980 auto itc = C.begin();
2981 for(; itc != C.end(); ++itc) {
2982 if(!itc->second.inBoundary) {
2983 itc->second._a -= sum;
2984 itc->second._atemp = itc->second._a;
2985 itc->second.normalize(itc->second._a);
2994 for(
size_t i = 0; i <
f.size(); i++) {
2995 for(
size_t j = 0; j <
f[i]->triangles.size(); j++) {
2997 Dof d0(aaa[
f[i]->triangles[j]->getEdge(0)],
2999 Dof d1(aaa[
f[i]->triangles[j]->getEdge(1)],
3001 Dof d2(aaa[
f[i]->triangles[j]->getEdge(2)],
3007 double A =
c + a - b;
3008 double B = a + b -
c;
3009 double C = b +
c - a;
3010 std::vector<double> ts;
3014 dataTHETA[t->
getNum()] = ts;
3028 quadLayoutData(
GModel *_gm, std::vector<GFace *> &_f,
const std::string &name,
3029 bool includeFeatureEdges =
true)
3030 : gm(_gm),
f(_f), myAssembler(nullptr)
3033 for(
size_t i = 0; i <
f.size(); i++) {
3034 for(
size_t j = 0; j <
f[i]->triangles.size(); j++) {
3036 for(
size_t k = 0; k < 3; k++) {
3047 vk1->
z() - vk->
z());
3049 vk2->
z() - vk->
z());
3050 double CURV =
angle(v1, v2);
3051 auto itg = gaussianCurvatures.find(vk);
3052 if(
itg == gaussianCurvatures.end())
3053 gaussianCurvatures[vk] = 2 * M_PI - CURV;
3055 itg->second -= CURV;
3058 cross2d
c(e, t, e1, e2);
3059 auto it = C.find(e);
3061 C.insert(std::make_pair(e,
c));
3063 it->second._t.push_back(t);
3064 it->second._neighbors.push_back(e1);
3065 it->second._neighbors.push_back(e2);
3070 if(includeFeatureEdges) {
3071 for(
size_t i = 0; i <
f.size(); i++) {
3072 std::vector<GEdge *> e =
f[i]->edges();
3073 for(
size_t j = 0; j < e.size(); j++) {
3074 for(
size_t k = 0; k < e[j]->lines.size(); k++) {
3075 MLine *l = e[j]->lines[k];
3077 auto it = C.find(e);
3078 if(it != C.end()) { it->second.inBoundary =
true; }
3083 auto it = C.begin();
3084 for(; it != C.end(); ++it) it->second.finish(C);
3086 for(; it != C.end(); ++it) it->second.finish2();
3087 FILE *
F = fopen(
"gc.pos",
"w");
3088 fprintf(
F,
"View\"\"{\n");
3090 for(
auto it = gaussianCurvatures.begin(); it != gaussianCurvatures.end();
3092 fprintf(
F,
"SP(%g,%g,%g){%g};\n", it->first->x(), it->first->y(),
3093 it->first->z(), it->second);
3096 printf(
"%22.15E %22.15E\n", dd, dd - 4 * M_PI);
3101 void restoreInitialMesh()
3103 unDuplicateNodesInCutGraph(
f, new2old);
3110 auto it = C.begin();
3111 for(; it != C.end(); ++it) {
3112 it->second.inCutGraph =
false;
3113 it->second._btemp = 0;
3117 int computeUniqueVectorsPerTriangle()
3120 std::set<cross2d *> visited;
3121 while(visited.size() != C.size()) {
3122 for(
auto it = C.begin(); it != C.end(); ++it) {
3123 if(visited.find(&(it->second)) == visited.end() &&
3124 cutG.find(it->second._e) == cutG.end()) {
3125 computeLifting(&(it->second), 0, cutG, singularities, boundaries,
3131 computeUniqueVectorPerTriangle(gm,
f, C, 0, d0);
3132 computeUniqueVectorPerTriangle(gm,
f, C, 1, d1);
3136 int computeCutGraph(std::map<MEdge, MEdge, MEdgeLessThan> &duplicateEdges)
3139 cutGraph(C, cutG, singularities, boundaries);
3140 for(
auto it = C.begin(); it != C.end(); ++it) {
3141 MEdge e0 = it->second._e;
3142 if(cutG.find(e0) != cutG.end()) it->second.inCutGraph =
true;
3145 groupBoundaries(gm, C, groups, singularities, corners,
false);
3146 groupBoundaries(gm, C, groups_cg, singularities, corners,
true);
3149 for(
size_t i = 0; i <
f.size(); i++) {
3153 std::string fn = modelName +
"_groups_analyzed.pos";
3154 FILE *_f = fopen(fn.c_str(),
"w");
3155 fprintf(_f,
"View \"groups\"{\n");
3157 std::set<MVertex *, MVertexPtrLessThan> isolated_singularities;
3159 for(
auto it = singularities.begin(); it != singularities.end(); ++it) {
3161 for(
size_t i = 0; i < groups_cg.size(); i++) {
3162 for(
size_t k = 0; k < groups_cg[i].size(); k++) {
3163 for(
size_t j = 0; j < 2; j++) {
3164 MVertex *v = groups_cg[i][k]->_e.getVertex(j);
3165 if(v == *it) count++;
3169 if(count == 1) { isolated_singularities.insert(*it); }
3171 isolated_singularities.insert(*it);
3178 computeUniqueVectorsPerTriangle();
3182 std::set<MTriangle *> allTrianglesConsidered;
3183 for(
size_t i = 0; i < groups_cg.size(); i++) {
3184 groupOfCross2d g(i);
3185 analyzeGroup(groups_cg[i], g, d0, d1, adj, isolated_singularities,
3186 boundaries, allTrianglesConsidered);
3191 fprintf(_f,
"};\n");
3194 std::multimap<MVertex *, MVertex *, MVertexPtrLessThan> old2new;
3195 duplicateNodesInCutGraph(
f, C, new2old, old2new, duplicateEdges,
3196 singularities, adj, G);
3198 for(
size_t i = 0; i < groups_cg.size(); i++) {
3199 createJumpyPairs(G[i], singularities, boundaries, old2new);
3205 std::map<
int, std::vector<double> > &dataTHETA)
3208 computeHFromSingularities(*s);
3210 Msg::Info(
"Real part H (nodal) has been computed in %4g sec", b - a);
3212 std::map<MEdge, MEdge, MEdgeLessThan> duplicateEdges;
3215 computeCutGraph(duplicateEdges);
3216 Msg::Info(
"Cut Graph has been computed in %4g sec",
c - b);
3219 computeThetaUsingHCrouzeixRaviart(dataTHETA);
3220 Msg::Info(
"Imaginary part H (crouzeix raviart/multi-valued) has been "
3221 "computed in %4g sec",
3223 restoreInitialMesh();
3232 if(e1 == v2)
return nullptr;
3233 if(e2 == v2)
return nullptr;
3235 SVector3 e1e2(e2->
x() - e1->
x(), e2->
y() - e1->
y(), e2->
z() - e1->
z());
3236 SVector3 e1v1(v1->
x() - e1->
x(), v1->
y() - e1->
y(), v1->
z() - e1->
z());
3237 SVector3 e2v1(v1->
x() - e2->
x(), v1->
y() - e2->
y(), v1->
z() - e2->
z());
3240 double b =
dot(e1v1, e2v1);
3241 if(a.
norm() < 1.e-10 && b < 0)
return v1;
3248 SVector3 e2v2(v2->
x() - e2->
x(), v2->
y() - e2->
y(), v2->
z() - e2->
z());
3249 SVector3 e1v2(v2->
x() - e1->
x(), v2->
y() - e1->
y(), v2->
z() - e1->
z());
3251 b =
dot(e1v2, e2v2);
3252 if(a.
norm() < 1.e-10 && b < 0)
return v2;
3261 if(!inters)
return nullptr;
3262 return new MEdgeVertex(v2->
x() * x[1] + v1->
x() * (1. - x[1]),
3263 v2->
y() * x[1] + v1->
y() * (1. - x[1]),
3264 v2->
z() * x[1] + v1->
z() * (1. - x[1]),
nullptr, 0);
3267 void cut_edge(std::map<MEdge, int, MEdgeLessThan> &ecuts,
MVertex *v0,
3271 auto it = ecuts.find(e);
3272 if(it != ecuts.end()) {
3273 int index = it->second;
3282 void cutTriangles(std::vector<MTriangle *> &ts,
GFace *gf,
MVertex *v1,
3284 std::map<MEdge, int, MEdgeLessThan> &ecuts,
int index,
3287 std::map<MEdge, MVertex *, MEdgeLessThan> e_cut;
3288 std::vector<MTriangle *> newt;
3290 for(
size_t i = 0; i < ts.size(); ++i) {
3291 MVertex *vs[3] = {
nullptr,
nullptr,
nullptr};
3292 for(
size_t j = 0; j < 3; ++j) {
3293 MEdge e = ts[i]->getEdge(j);
3294 if(e_cut.find(e) == e_cut.end()) {
3295 MVertex *v = intersectEdgeEdge(e, v1, v2, gf);
3296 if(v && v != v1 && v != v2) {
3299 fprintf(
f,
"SP(%g,%g,%g){%d};\n", v->
x(), v->
y(), v->
z(),
3307 if(!vs[0] && !vs[1] && !vs[2])
3308 newt.push_back(ts[i]);
3309 else if(vs[0] && !vs[1] && !vs[2]) {
3312 new MTriangle(ts[i]->getVertex(0), vs[0], ts[i]->getVertex(2)));
3314 new MTriangle(vs[0], ts[i]->getVertex(1), ts[i]->getVertex(2)));
3315 cut_edge(ecuts, ts[i]->getVertex(0), ts[i]->getVertex(1), vs[0]);
3316 MEdge ed(ts[i]->getVertex(2), vs[0]);
3319 else if(!vs[0] && vs[1] && !vs[2]) {
3322 new MTriangle(ts[i]->getVertex(0), ts[i]->getVertex(1), vs[1]));
3324 new MTriangle(ts[i]->getVertex(0), vs[1], ts[i]->getVertex(2)));
3325 cut_edge(ecuts, ts[i]->getVertex(2), ts[i]->getVertex(1), vs[1]);
3326 MEdge ed(ts[i]->getVertex(0), vs[1]);
3329 else if(!vs[0] && !vs[1] && vs[2]) {
3332 new MTriangle(ts[i]->getVertex(0), ts[i]->getVertex(1), vs[2]));
3334 new MTriangle(vs[2], ts[i]->getVertex(1), ts[i]->getVertex(2)));
3335 cut_edge(ecuts, ts[i]->getVertex(2), ts[i]->getVertex(0), vs[2]);
3336 MEdge ed(ts[i]->getVertex(1), vs[2]);
3339 else if(vs[0] && vs[1] && !vs[2]) {
3340 newt.push_back(
new MTriangle(ts[i]->getVertex(0), vs[0], vs[1]));
3341 newt.push_back(
new MTriangle(ts[i]->getVertex(1), vs[1], vs[0]));
3343 new MTriangle(ts[i]->getVertex(0), vs[1], ts[i]->getVertex(2)));
3344 cut_edge(ecuts, ts[i]->getVertex(0), ts[i]->getVertex(1), vs[0]);
3345 cut_edge(ecuts, ts[i]->getVertex(2), ts[i]->getVertex(1), vs[1]);
3346 MEdge ed(vs[0], vs[1]);
3349 else if(vs[0] && !vs[1] && vs[2]) {
3350 newt.push_back(
new MTriangle(ts[i]->getVertex(0), vs[0], vs[2]));
3351 newt.push_back(
new MTriangle(ts[i]->getVertex(2), vs[2], vs[0]));
3353 new MTriangle(ts[i]->getVertex(2), vs[0], ts[i]->getVertex(1)));
3354 cut_edge(ecuts, ts[i]->getVertex(0), ts[i]->getVertex(1), vs[0]);
3355 cut_edge(ecuts, ts[i]->getVertex(2), ts[i]->getVertex(0), vs[2]);
3356 MEdge ed(vs[0], vs[2]);
3359 else if(!vs[0] && vs[1] && vs[2]) {
3360 newt.push_back(
new MTriangle(ts[i]->getVertex(2), vs[2], vs[1]));
3361 newt.push_back(
new MTriangle(ts[i]->getVertex(0), vs[1], vs[2]));
3363 new MTriangle(ts[i]->getVertex(1), vs[1], ts[i]->getVertex(0)));
3364 cut_edge(ecuts, ts[i]->getVertex(1), ts[i]->getVertex(2), vs[1]);
3365 cut_edge(ecuts, ts[i]->getVertex(2), ts[i]->getVertex(0), vs[2]);
3366 MEdge ed(vs[1], vs[2]);
3369 else if(vs[0] && vs[1] && vs[2]) {
3370 newt.push_back(
new MTriangle(vs[0], vs[1], vs[2]));
3371 newt.push_back(
new MTriangle(ts[i]->getVertex(0), vs[0], vs[2]));
3372 newt.push_back(
new MTriangle(ts[i]->getVertex(1), vs[1], vs[0]));
3373 newt.push_back(
new MTriangle(ts[i]->getVertex(2), vs[2], vs[1]));
3376 newt.push_back(ts[i]);
3383 void cutMesh(std::map<MEdge, edgeCuts, MEdgeLessThan> &cuts)
3385 auto it = cuts.begin();
3386 std::map<MEdge, int, MEdgeLessThan> ecuts;
3388 FILE *
F = fopen(
"addedpoints.pos",
"w");
3389 fprintf(
F,
"View \"\"{\n");
3390 for(; it != cuts.end(); ++it) { it->second.finish(gm,
F); }
3392 for(
size_t i = 0; i <
f.size(); i++) {
3393 std::vector<MTriangle *> newT;
3394 for(
size_t j = 0; j <
f[i]->triangles.size(); j++) {
3395 std::set<int> indices;
3396 std::multimap<int, std::pair<MVertex *, std::pair<int, int> > > tcuts;
3398 for(
size_t k = 0; k < 3; k++) {
3399 MEdge e =
f[i]->triangles[j]->getEdge(k);
3400 auto it = cuts.find(e);
3401 if(it != cuts.end()) {
3402 for(
size_t l = 0; l < it->second.vs.size(); ++l) {
3403 std::pair<int, std::pair<MVertex *, std::pair<int, int> > > pp =
3405 it->second.indexOfCuts[l],
3406 std::make_pair(it->second.vs[l],
3407 std::make_pair(k, it->second.idsOfCuts[l])));
3409 indices.insert(it->second.indexOfCuts[l]);
3414 auto iti = indices.begin();
3415 std::vector<MTriangle *> ttt;
3416 ttt.push_back(
f[i]->triangles[j]);
3417 for(; iti != indices.end(); ++iti) {
3420 if(tcuts.count(*iti) == 1) {
3421 auto itt = tcuts.lower_bound(*iti);
3422 MVertex *v0 = itt->second.first;
3423 int k = itt->second.second.first;
3424 cutTriangles(ttt,
f[i], v0,
3425 f[i]->triangles[j]->getVertex((k + 2) % 3), ge, ecuts,
3428 else if(tcuts.count(*iti) == 2) {
3429 auto itt = tcuts.lower_bound(*iti);
3430 MVertex *v0 = itt->second.first;
3432 MVertex *v1 = itt->second.first;
3433 cutTriangles(ttt,
f[i], v0, v1, ge, ecuts, *iti,
F);
3435 else if(tcuts.count(*iti) == 3) {
3436 auto itt = tcuts.lower_bound(*iti);
3437 int k0 = itt->second.second.first;
3438 int id0 = itt->second.second.second;
3439 MVertex *v0 = itt->second.first;
3441 int k1 = itt->second.second.first;
3442 int id1 = itt->second.second.second;
3443 MVertex *v1 = itt->second.first;
3445 int k2 = itt->second.second.first;
3446 int id2 = itt->second.second.second;
3447 MVertex *v2 = itt->second.first;
3450 if(abs(id0 - id1) <= 2) {
3451 cutTriangles(ttt,
f[i], v2,
3452 f[i]->triangles[j]->getVertex((k2 + 2) % 3), ge,
3454 cutTriangles(ttt,
f[i], v0, v1, ge, ecuts, *iti,
F);
3456 else if(abs(id0 - id2) <= 2) {
3457 cutTriangles(ttt,
f[i], v1,
3458 f[i]->triangles[j]->getVertex((k1 + 2) % 3), ge,
3460 cutTriangles(ttt,
f[i], v0, v2, ge, ecuts, *iti,
F);
3462 else if(abs(id1 - id2) <= 2) {
3463 cutTriangles(ttt,
f[i], v0,
3464 f[i]->triangles[j]->getVertex((k0 + 2) % 3), ge,
3466 cutTriangles(ttt,
f[i], v1, v2, ge, ecuts, *iti,
F);
3469 printf(
"BAD BEHAVIOR 3\n");
3472 printf(
"%d %d %d\n", id0, id1, id2);
3475 else if(tcuts.count(*iti) == 4) {
3476 auto itt = tcuts.lower_bound(*iti);
3477 int id0 = itt->second.second.second;
3478 MVertex *v0 = itt->second.first;
3480 int id1 = itt->second.second.second;
3481 MVertex *v1 = itt->second.first;
3483 int id2 = itt->second.second.second;
3484 MVertex *v2 = itt->second.first;
3486 int id3 = itt->second.second.second;
3487 MVertex *v3 = itt->second.first;
3488 if(abs(id0 - id1) <= 2 || abs(id2 - id3) <= 2) {
3489 cutTriangles(ttt,
f[i], v0, v1, ge, ecuts, *iti,
F);
3490 cutTriangles(ttt,
f[i], v2, v3, ge, ecuts, *iti,
F);
3492 else if(abs(id0 - id2) <= 2 || abs(id1 - id3) <= 2) {
3493 cutTriangles(ttt,
f[i], v0, v2, ge, ecuts, *iti,
F);
3494 cutTriangles(ttt,
f[i], v1, v3, ge, ecuts, *iti,
F);
3496 else if(abs(id0 - id3) <= 2 || abs(id1 - id2) <= 2) {
3497 cutTriangles(ttt,
f[i], v0, v3, ge, ecuts, *iti,
F);
3498 cutTriangles(ttt,
f[i], v1, v2, ge, ecuts, *iti,
F);
3501 printf(
"%d %d %d %d\n", id0, id1, id2, id3);
3504 else if(tcuts.count(*iti) == 6) {
3505 auto itt = tcuts.lower_bound(*iti);
3506 std::pair<int, MVertex *>
id[10];
3507 for(std::size_t kk = 0; kk < tcuts.count(*iti); kk++) {
3509 std::make_pair(itt->second.second.second, itt->second.first);
3512 std::sort(
id,
id + 6);
3513 cutTriangles(ttt,
f[i],
id[0].second,
id[1].second, ge, ecuts, *iti,
3515 cutTriangles(ttt,
f[i],
id[2].second,
id[3].second, ge, ecuts, *iti,
3517 cutTriangles(ttt,
f[i],
id[4].second,
id[5].second, ge, ecuts, *iti,
3519 printf(
"%d %d %d %d %d %d\n",
id[0].first,
id[1].first,
id[2].first,
3520 id[3].first,
id[4].first,
id[5].first);
3523 Msg::Error(
"TODO %lu in CutMesh !!!!!!!", tcuts.count(*iti));
3526 newT.insert(newT.begin(), ttt.begin(), ttt.end());
3528 f[i]->triangles = newT;
3534 F = fopen(
"edges.pos",
"w");
3535 fprintf(
F,
"View \"\"{\n");
3537 for(
auto it = ecuts.begin(); it != ecuts.end(); ++it) {
3539 ge->
lines.push_back(
3540 new MLine(it->first.getVertex(0), it->first.getVertex(1)));
3541 fprintf(
F,
"SL(%g,%g,%g,%g,%g,%g){1,1};\n", it->first.getVertex(0)->x(),
3542 it->first.getVertex(0)->y(), it->first.getVertex(0)->z(),
3543 it->first.getVertex(1)->x(), it->first.getVertex(1)->y(),
3544 it->first.getVertex(1)->z());
3545 for(
int i = 0; i < 2; i++) {
3549 it->first.getVertex(i)->setEntity(ge);
3558 int correctionOnCutGraph(
3559 std::map<MEdge, edgeCuts, MEdgeLessThan> &cuts,
3560 std::map<MVertex *, MVertex *, MVertexPtrLessThan> &new2old)
3562 std::map<MEdge, MEdge, MEdgeLessThan> duplicateEdges;
3564 for(
auto it = cuts.begin(); it != cuts.end(); ++it) {
3565 MVertex *v0 = it->first.getVertex(0);
3566 MVertex *v1 = it->first.getVertex(1);
3567 MVertex *v2 = new2old.find(v0) == new2old.end() ? v0 : new2old[v0];
3568 MVertex *v3 = new2old.find(v1) == new2old.end() ? v1 : new2old[v1];
3571 duplicateEdges[e0] = e1;
3574 for(
auto it2 = duplicateEdges.begin(); it2 != duplicateEdges.end(); ++it2) {
3575 auto it3 = cuts.find(it2->first);
3576 auto it4 = cuts.find(it2->second);
3577 if(it3 != cuts.end() && it4 == cuts.end()) {
3578 cuts[it2->second] = it3->second;
3580 else if(it4 != cuts.end() && it3 == cuts.end()) {
3581 cuts[it2->first] = it4->second;
3583 else if(it4 != cuts.end() && it3 != cuts.end()) {
3584 it4->second.vs.insert(it4->second.vs.begin(), it3->second.vs.begin(),
3585 it3->second.vs.end());
3586 it4->second.indexOfCuts.insert(it4->second.indexOfCuts.begin(),
3587 it3->second.indexOfCuts.begin(),
3588 it3->second.indexOfCuts.end());
3589 it3->second.vs.insert(it3->second.vs.begin(), it4->second.vs.begin(),
3590 it4->second.vs.end());
3591 it3->second.indexOfCuts.insert(it3->second.indexOfCuts.begin(),
3592 it4->second.indexOfCuts.begin(),
3593 it4->second.indexOfCuts.end());
3600 std::map<MVertex *, double> &potV,
3601 std::map<MEdge, MEdge, MEdgeLessThan> &duplicateEdges,
3602 std::map<MEdge, edgeCuts, MEdgeLessThan> &cuts)
3604 std::vector<cutGraphPassage> passages;
3606 computePotential(gm,
f, *myAssembler, C, new2old, groups, duplicateEdges,
3607 d0, d1, G, potU, potV, passages);
3609 if(computeIsos(gm,
f, singularities, C, new2old, duplicateEdges, groups,
3610 groups_cg, potU, potV, cutG, G, cuts, passages) ==
true) {
3611 printf(
"COMPUTE ISOS DONE\n");
3617 correctionOnCutGraph(cuts, new2old);
3620 for(
size_t i = 0; i < groups_cg.size(); i++) {
3621 double MAXD1 = -1.e22, MIND1 = 1.e22, MAXD2 = -1.e22, MIND2 = 1.e22;
3622 for(
size_t j = 0; j < G[i].left.size(); j++) {
3623 double Ul = potU[G[i].left[j]];
3624 double Ur = potU[G[i].right[j]];
3625 double Vl = potV[G[i].left[j]];
3626 double Vr = potV[G[i].right[j]];
3627 double D1 = Ul - G[i].mat[0][0] * Ur - G[i].mat[0][1] * Vr;
3628 double D2 = Vl - G[i].mat[1][0] * Ur - G[i].mat[1][1] * Vr;
3629 MAXD1 = std::max(D1, MAXD1);
3630 MAXD2 = std::max(D2, MAXD2);
3631 MIND1 = std::min(D1, MIND1);
3632 MIND2 = std::min(D2, MIND2);
3635 Msg::Debug(
"group %3d ROT (%12.5E %12.5E) (%12.5E %12.5E)", G[i].groupId,
3636 G[i].mat[0][0], G[i].mat[0][1], G[i].mat[1][0],
3639 Msg::Debug(
"group %3d DA(%12.5E %12.5E %12.5E) D2(%12.5E %12.5E %12.5E)",
3640 G[i].groupId, MAXD1, MIND1, MAXD1 - MIND1, MAXD2, MIND2,
3642 MAXX = std::max(MAXD2 - MIND2, MAXX);
3645 Msg::Info(
"Success in computing potentials (all jumps are OK)");
3652 static void findPhysicalGroupsForSingularities(
GModel *gm,
3653 std::vector<GFace *> &
f,
3654 std::map<MVertex *, int> &temp)
3656 std::map<int, std::vector<GEntity *> > groups[4];
3658 for(
auto it = groups[0].begin(); it != groups[0].end(); ++it) {
3660 if(name ==
"SINGULARITY_OF_INDEX_THREE") {
3661 for(
size_t j = 0; j < it->second.size(); j++) {
3662 if(!it->second[j]->mesh_vertices.empty())
3663 temp[it->second[j]->mesh_vertices[0]] = 1;
3666 else if(name ==
"SINGULARITY_OF_INDEX_FIVE") {
3667 for(
size_t j = 0; j < it->second.size(); j++) {
3668 if(!it->second[j]->mesh_vertices.empty())
3669 temp[it->second[j]->mesh_vertices[0]] = -1;
3672 else if(name ==
"SINGULARITY_OF_INDEX_SIX") {
3673 for(
size_t j = 0; j < it->second.size(); j++) {
3674 if(!it->second[j]->mesh_vertices.empty())
3675 temp[it->second[j]->mesh_vertices[0]] = -2;
3678 else if(name ==
"SINGULARITY_OF_INDEX_EIGHT") {
3679 for(
size_t j = 0; j < it->second.size(); j++) {
3680 if(!it->second[j]->mesh_vertices.empty())
3681 temp[it->second[j]->mesh_vertices[0]] = -4;
3684 else if(name ==
"SINGULARITY_OF_INDEX_TWO") {
3685 for(
size_t j = 0; j < it->second.size(); j++) {
3686 if(!it->second[j]->mesh_vertices.empty())
3687 temp[it->second[j]->mesh_vertices[0]] = 2;
3694 std::vector<int> &
tags,
bool layout =
true)
3696 quadLayoutData qLayout(gm,
f, gm->
getName());
3697 std::map<MVertex *, int> temp;
3698 std::map<int, std::vector<double> > dataH;
3699 std::map<int, std::vector<double> > dataTHETA;
3700 std::map<int, std::vector<double> > dataDir;
3701 std::map<int, std::vector<double> > dataDirOrtho;
3702 std::map<int, std::vector<double> > dataU;
3703 std::map<int, std::vector<double> > dataV;
3704 std::map<MVertex *, double> potU, potV;
3705 findPhysicalGroupsForSingularities(gm,
f, temp);
3706 std::map<MEdge, MEdge, MEdgeLessThan> duplicateEdges;
3707 std::map<MEdge, edgeCuts, MEdgeLessThan> cuts;
3709 Msg::Info(
"Computing cross field from %d prescribed singularities",
3711 qLayout.computeCrossFieldAndH(&temp, dataTHETA);
3712 qLayout.computeCutGraph(duplicateEdges);
3716 qLayout.computeCrossFieldAndH();
3717 qLayout.computeCutGraph(duplicateEdges);
3718 qLayout.computeThetaUsingHCrouzeixRaviart(dataTHETA);
3720 if(layout) { qLayout.computeQuadLayout(potU, potV, duplicateEdges, cuts); }
3725 std::string name = gm->
getName() +
"_H";
3728 name = gm->
getName() +
"_Theta";
3731 name = gm->
getName() +
"_Directions";
3746 for(
size_t i = 0; i <
f.size(); i++) {
3747 for(
size_t j = 0; j <
f[i]->triangles.size(); j++) {
3749 double a = potU[
f[i]->triangles[j]->getVertex(0)];
3750 double b = potU[
f[i]->triangles[j]->getVertex(1)];
3751 double c = potU[
f[i]->triangles[j]->getVertex(2)];
3752 std::vector<double> ts;
3757 a = potV[
f[i]->triangles[j]->getVertex(0)];
3758 b = potV[
f[i]->triangles[j]->getVertex(1)];
3759 c = potV[
f[i]->triangles[j]->getVertex(2)];
3768 U->
addData(gm, dataU, 0, 0.0, 1, 1);
3770 V->
addData(gm, dataV, 0, 0.0, 1, 1);
3773 for(
auto it = qLayout.d0.begin(); it != qLayout.d0.end(); ++it) {
3774 std::vector<double> jj;
3775 jj.push_back(it->second.x());
3776 jj.push_back(it->second.y());
3777 jj.push_back(it->second.z());
3778 dataDir[it->first->getNum()] = jj;
3780 for(
auto it = qLayout.d1.begin(); it != qLayout.d1.end(); ++it) {
3781 std::vector<double> jj;
3782 jj.push_back(it->second.x());
3783 jj.push_back(it->second.y());
3784 jj.push_back(it->second.z());
3785 dataDirOrtho[it->first->getNum()] = jj;
3787 for(
auto it = qLayout.vs.begin(); it != qLayout.vs.end(); ++it) {
3789 qLayout.myAssembler->getDofValue(*it, 0, 1, h);
3790 std::vector<double> jj;
3793 dataH[(*it)->getNum()] = jj;
3796 d->
addData(gm, dataH, 0, 0.0, 1, 1);
3798 dt->
addData(gm, dataTHETA, 0, 0.0, 1, 1);
3800 dd->
addData(gm, dataDir, 0, 0.0, 1, 3);
3801 dd->
addData(gm, dataDirOrtho, 1, 0.0, 1, 3);
3804 std::string posout = gm->
getName() +
"_QLayoutResults.pos";
3806 qLayout.restoreInitialMesh();
3807 dt->
writePOS(posout,
false,
true,
true);
3808 dd->
writePOS(posout,
false,
true,
true);
3809 d->
writePOS(posout,
false,
true,
true);
3811 U->
writePOS(posout,
false,
true,
true);
3812 V->
writePOS(posout,
false,
true,
true);
3817 qLayout.cutMesh(cuts);
3830 std::string mshout = gm->
getName() +
"_Cut.msh";
3831 gm->
writeMSH(mshout, 4.0,
false,
true);
3836 if((*it)->edges().size() != 4) {
3837 Msg::Warning(
"quad layout failed : face %lu has %lu boundaries",
3838 (*it)->tag(), (*it)->edges().size());
3844 "Quad layout success : the model is partitioned in %d master quads",
3846 Msg::Info(
"Partitioned mesh has been saved in %s", mshout.c_str());
3847 Msg::Info(
"Result of computations have been saved in %s", posout.c_str());
3872 std::vector<GFace *>
f;
3874 #if defined(HAVE_SOLVER) && defined(HAVE_POST)
3877 Msg::Error(
"Cross field computation requires solver and post-pro module");
3884 std::vector<GFace *>
f;
3887 #if defined(HAVE_SOLVER) && defined(HAVE_POST)
3890 Msg::Error(
"Cross field computation requires solver and post-pro module");
3897 std::vector<GFace *>
f;
3900 #if defined(HAVE_SOLVER) && defined(HAVE_POST)
3904 Msg::Error(
"Cross field computation requires solver and post-pro module");