gmsh-TingyuanDoc  0.1
An Open-Source Timing-driven Analytical Mixed-size FPGA Placer
gmshCrossFields.cpp
Go to the documentation of this file.
1 // Gmsh - Copyright (C) 1997-2022 C. Geuzaine, J.-F. Remacle
2 //
3 // See the LICENSE.txt file in the Gmsh root directory for license information.
4 // Please report all issues on https://gitlab.onelab.info/gmsh/gmsh/issues.
5 
6 #include <vector>
7 #include <stack>
8 #include <queue>
9 #include "OS.h"
10 #include "GmshConfig.h"
11 #include "gmshCrossFields.h"
12 #include "GModel.h"
13 #include "GFace.h"
14 #include "MEdge.h"
15 #include "MLine.h"
16 #include "MTriangle.h"
17 #include "GmshMessage.h"
18 #include "Context.h"
19 #include "meshGFaceOptimize.h"
20 #include "discreteEdge.h"
21 #include "Numeric.h"
22 #include "GModelParametrize.h"
23 
24 #if defined(HAVE_POST)
25 #include "PView.h"
26 #include "PViewDataGModel.h"
27 #endif
28 
29 #if defined(HAVE_SOLVER) && defined(HAVE_POST)
30 
31 #include "dofManager.h"
32 #include "laplaceTerm.h"
33 #include "linearSystemGmm.h"
34 #include "linearSystemCSR.h"
35 #include "linearSystemFull.h"
36 #include "linearSystemPETSc.h"
37 
38 static inline double lifting(double a, double _a)
39 {
40  double D = M_PI * .5;
41  if(fabs(_a - a) < fabs(_a - (a + D)) && fabs(_a - a) < fabs(_a - (a - D))) {
42  return a;
43  }
44  else if(fabs(_a - (a + D)) < fabs(_a - a) &&
45  fabs(_a - (a + D)) < fabs(_a - (a - D))) {
46  return a + D;
47  }
48  else {
49  return a - D;
50  }
51 }
52 
53 static inline double compat_orientation_extrinsic(const double *o0,
54  const double *n0,
55  const double *o1,
56  const double *n1, double *a1,
57  double *b1)
58 {
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]};
63 
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]}};
71 
72  double maxx = -1;
73  int index = 0;
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];
77  const double xx =
78  A[II][0] * B[JJ][0] + A[II][1] * B[JJ][1] + A[II][2] * B[JJ][2];
79  if(xx > maxx) {
80  index = i;
81  maxx = xx;
82  }
83  }
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];
90  // b1 = B[permuts[index][1]];
91  return maxx;
92 }
93 
94 static inline double compat_orientation_extrinsic(const SVector3 &o0,
95  const SVector3 &n0,
96  const SVector3 &o1,
97  const SVector3 &n1,
99 {
100  SVector3 t0 = crossprod(n0, o0);
101  SVector3 t1 = crossprod(n1, o1);
102 
103  const size_t permuts[8][2] = {{0, 0}, {1, 0}, {2, 0}, {3, 0},
104  {0, 1}, {1, 1}, {2, 1}, {3, 1}};
105  SVector3 A[4]{o0, t0, -o0, -t0};
106  SVector3 B[2]{o1, t1};
107 
108  double maxx = -1;
109  int index = 0;
110  for(size_t i = 0; i < 8; i++) {
111  const double xx = dot(A[permuts[i][0]], B[permuts[i][1]]);
112  if(xx > maxx) {
113  index = i;
114  maxx = xx;
115  }
116  }
117  a1 = A[permuts[index][0]];
118  b1 = B[permuts[index][1]];
119  return maxx;
120 }
121 
122 class cross2d {
123 public:
124  MEdge _e;
125  bool inCutGraph;
126  bool inBoundary;
127  bool inInternalBoundary;
128  bool rotation;
129  // int cutGraphPart;
130  size_t counter;
131  SVector3 o_i; // orientation vector
132  SVector3 _nrml, _tgt, _tgt2; // local system of coordinates
133  std::vector<MEdge> _neighbors;
134  std::vector<cross2d *> _cneighbors;
135  double da[4];
136  double _cc[4], _ss[4];
137  // euler angles
138  double _a, _b, _c;
139  double _atemp, _btemp, _ctemp;
140  std::vector<MTriangle *> _t;
141  cross2d(MEdge &e, MTriangle *r, MEdge &e1, MEdge &e2)
142  : _e(e), inCutGraph(false), inBoundary(false), inInternalBoundary(false),
143  _a(0), _b(0), _c(0)
144  {
145  _t.push_back(r);
146  _neighbors.push_back(e1);
147  _neighbors.push_back(e2);
148  }
149  void normalize(double &a)
150  {
151  double D = M_PI * .5;
152  if(a < 0)
153  while(a < 0) a += D;
154  if(a >= D)
155  while(a >= D) a -= D;
156  }
157  void finish2()
158  {
159  if(_cneighbors.size() == 4) {
160  SVector3 x(0, 1, 0);
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);
165  }
166  else {
167  _b = _btemp = 0;
168  _c = _ctemp = 1;
169  }
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]);
175  }
176  }
177  }
178 
179  void finish(std::map<MEdge, cross2d, MEdgeLessThan> &C)
180  {
181  _tgt = SVector3(1, 0, 0);
182  _tgt2 = SVector3(0, 1, 0);
183  if(_t.size() <= 2) {
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());
190  SVector3 xx = crossprod(v20, v10);
191  xx.normalize();
192  SVector3 yy = xx;
193  if(_t.size() == 2) {
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());
200  yy = crossprod(v20b, v10b);
201  yy.normalize();
202  // if(dot(xx, yy) < .5) inInternalBoundary = 1;
203  }
204  _nrml = xx + yy;
205  _nrml.normalize();
206  SVector3 vt(_e.getVertex(1)->x() - _e.getVertex(0)->x(),
207  _e.getVertex(1)->y() - _e.getVertex(0)->y(),
208  _e.getVertex(1)->z() - _e.getVertex(0)->z());
209  _tgt = vt;
210  _tgt.normalize();
211  _tgt2 = crossprod(_nrml, _tgt);
212  }
213 
214  if(_t.size() == 1) { inBoundary = true; }
215  else if(_t.size() >= 2) {
216  if(inBoundary) {
217  inBoundary = false;
218  inInternalBoundary = true;
219  }
220  }
221 
222  for(size_t i = 0; i < _neighbors.size(); i++) {
223  auto it = C.find(_neighbors[i]);
224  if(it == C.end())
225  Msg::Error("impossible situation");
226  else
227  _cneighbors.push_back(&(it->second));
228  }
229  if(_cneighbors.size() != 4) {
230  _a = 0;
231  _atemp = _a;
232  }
233  _neighbors.clear();
234  _b = _btemp = sin(4 * _a);
235  _c = _ctemp = cos(4 * _a);
236  }
237  double average_init()
238  {
239  if(!inBoundary && !inInternalBoundary) {
240  _btemp = 0;
241  _ctemp = 0;
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]);
245  }
246  _btemp *= 0.25;
247  _ctemp *= 0.25;
248  _b = _btemp;
249  _c = _ctemp;
250  }
251  return 1;
252  }
253 
254  double grad()
255  {
256  if(!inBoundary && !inInternalBoundary) {
257  double D = M_PI * .5;
258  double a[4] = {_cneighbors[0]->_a, _cneighbors[1]->_a, _cneighbors[2]->_a,
259  _cneighbors[3]->_a};
260  for(int i = 0; i < 4; i++) {
261  a[i] += da[i];
262  normalize(a[i]);
263  }
264 
265  double b[4];
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))) {
269  b[i] = a[i];
270  }
271  else if(fabs(_a - (a[i] + D)) < fabs(_a - (a[i])) &&
272  fabs(_a - (a[i] + D)) < fabs(_a - (a[i] - D))) {
273  b[i] = a[i] + D;
274  }
275  else {
276  b[i] = a[i] - D;
277  }
278  }
279  return fabs(_a - b[0]) + fabs(_a - b[1]) + fabs(_a - b[2]) +
280  fabs(_a - b[3]);
281  }
282  return 0;
283  }
284 
285  double lifting(double a)
286  {
287  double D = M_PI * .5;
288  if(fabs(_a - a) < fabs(_a - (a + D)) && fabs(_a - a) < fabs(_a - (a - D))) {
289  return a;
290  }
291  else if(fabs(_a - (a + D)) < fabs(_a - a) &&
292  fabs(_a - (a + D)) < fabs(_a - (a - D))) {
293  return a + D;
294  }
295  else {
296  return a - D;
297  }
298  }
299 
300  void computeVector()
301  {
302  _a = _atemp = 0.25 * atan2(_btemp, _ctemp);
303  normalize(_atemp);
304  o_i = _tgt * cos(_atemp) + _tgt2 * sin(_atemp);
305  }
306 
307  void computeAngle()
308  {
309  if(_cneighbors.size() != 4) return;
310  double _anew = atan2(dot(_tgt2, o_i), dot(_tgt, o_i));
311  normalize(_anew);
312  _a = _atemp = _anew;
313  }
314 
315  double average2()
316  {
317  // TEMPORARY VERSION, slow but correct
318  // Instant field-aligned meshes
319  if(_cneighbors.size() != 4) return 0;
320  double weight = 0.0;
321  SVector3 o_i_old = o_i;
322  SVector3 n_i = _nrml;
323  for(int i = 0; i < 4; i++) {
324  SVector3 o_j = _cneighbors[i]->o_i;
325  SVector3 n_j = _cneighbors[i]->_nrml;
326  SVector3 x, y;
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);
330  o_i.normalize();
331  weight += 1.0;
332  }
333  return std::min(1. - fabs(dot(o_i, o_i_old)), fabs(dot(o_i, o_i_old)));
334  }
335 
336  double average()
337  {
338  if(_cneighbors.size() == 4) {
339  double D = M_PI * .5;
340  double a[4] = {_cneighbors[0]->_a, _cneighbors[1]->_a, _cneighbors[2]->_a,
341  _cneighbors[3]->_a};
342  for(int i = 0; i < 4; i++) {
343  a[i] += da[i];
344  normalize(a[i]);
345  }
346 
347  double b[4];
348  double avg = 0.0;
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))) {
352  b[i] = a[i];
353  }
354  else if(fabs(_a - (a[i] + D)) < fabs(_a - (a[i])) &&
355  fabs(_a - (a[i] + D)) < fabs(_a - (a[i] - D))) {
356  b[i] = a[i] + D;
357  }
358  else {
359  b[i] = a[i] - D;
360  }
361  }
362  avg = 0.25 * (b[0] + b[1] + b[2] + b[3]);
363 
364  normalize(avg);
365 
366  double d = fabs(_a - avg);
367  _a = _atemp = avg;
368 
369  return d;
370  }
371  return 0;
372  }
373 };
374 
375 struct cross2dPtrLessThan {
376  MEdgeLessThan l;
377  bool operator()(const cross2d *v1, const cross2d *v2) const
378  {
379  return l(v1->_e, v2->_e);
380  }
381 };
382 
383 // ---------------------------------------------
384 // TODO : MAKE IT PARALLEL AND SUPERFAST
385 // DO IT ON SURFACES
386 // ---------------------------------------------
387 
388 static void closest(const cross2d &c1, const cross2d &c2, double &a2,
389  double &diff)
390 {
391  SVector3 d = c1._tgt * cos(c1._atemp) + c1._tgt2 * sin(c1._atemp);
392 
393  double P = M_PI / 2;
394 
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);
397  SVector3 d3 =
398  c2._tgt * cos(c2._atemp + 2 * P) + c2._tgt2 * sin(c2._atemp + 2 * P);
399  SVector3 d4 =
400  c2._tgt * cos(c2._atemp + 3 * P) + c2._tgt2 * sin(c2._atemp + 3 * P);
401 
402  double D1 = dot(d, d1);
403  double D2 = dot(d, d2);
404  double D3 = dot(d, d3);
405  double D4 = dot(d, d4);
406  diff = acos(D1);
407  if(D1 > D2 && D1 > D3 && D1 > D4) { a2 = c2._atemp; }
408  else if(D2 > D1 && D2 > D3 && D2 > D4) {
409  a2 = c2._atemp + P;
410  }
411  else if(D3 > D1 && D3 > D2 && D3 > D4) {
412  a2 = c2._atemp + 2 * P;
413  }
414  else {
415  a2 = c2._atemp + 3 * P;
416  }
417 }
418 
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)
424 {
425  // store in _atemp the branch of the neighbor
426  std::set<MVertex *, MVertexPtrLessThan> cg;
427  {
428  auto it = cutG.begin();
429  for(; it != cutG.end(); ++it) {
430  cg.insert(it->getVertex(0));
431  cg.insert(it->getVertex(1));
432  }
433  }
434 
435  FILE *_f = fopen("visited.pos", "w");
436  fprintf(_f, "View\"\"{\n");
437 
438  std::queue<cross2d *> _s;
439  _s.push(first);
440  first->_atemp = first->_a + branch * M_PI / 2.0;
441  first->_btemp = 10000.;
442  visited.insert(first);
443  while(!_s.empty()) {
444  cross2d *c = _s.front();
445  _s.pop();
446  if(cutG.find(c->_e) == cutG.end()) {
447  for(size_t i = 0; i < c->_cneighbors.size(); i++) {
448  double a2, diff;
449  cross2d *n = c->_cneighbors[i];
450  closest(*c, *n, a2, diff);
451  if(n->_btemp < 1000) {
452  n->_btemp = 10000;
453 
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();
460 
461  s0 = s1 = false;
462  // b0 = b1 = false;
463  if(((s0 && c1) || (s0 && b1)) || ((s1 && c0) || (s1 && b0))) {
464  printf("BLOCKED \n");
465  }
466 
467  if((!s0 && !s1)) _s.push(n);
468  // printf("%12.5E %12.5E %12.5E\n",n->a,n->_atemp,c->_atemp);
469  n->_atemp = a2;
470  visited.insert(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());
477  }
478  }
479  }
480  }
481  fprintf(_f, "};\n");
482  fclose(_f);
483 }
484 
485 struct groupOfCross2d {
486  int groupId;
487  bool rot;
488  double mat[2][2];
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;
495  void print(FILE *f)
496  {
497  for(size_t i = 0; i < crosses.size(); i++) {
498  fprintf(
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);
503  }
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);
511  }
512  };
513  groupOfCross2d(int id) : groupId(id) {}
514 };
515 
516 static void unDuplicateNodesInCutGraph(
517  std::vector<GFace *> &f,
518  std::map<MVertex *, MVertex *, MVertexPtrLessThan> &new2old)
519 {
520  for(size_t i = 0; i < f.size(); i++) {
521  for(size_t j = 0; j < f[i]->triangles.size(); j++) {
522  MTriangle *t = f[i]->triangles[j];
523  for(size_t k = 0; k < 3; k++) {
524  auto it = new2old.find(t->getVertex(k));
525  if(it != new2old.end()) t->setVertex(k, it->second);
526  }
527  }
528  }
529 }
530 
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)
538 {
539  FILE *_f = fopen("nodes.pos", "w");
540  fprintf(_f, "View \" nodes \"{\n");
541 
542  auto it = adj.begin();
543  std::set<MElement *> touched;
544  std::set<MVertex *, MVertexPtrLessThan> vtouched;
545 
546  std::vector<std::pair<MElement *, std::pair<int, MVertex *> > > replacements;
547 
548  while(it != adj.end()) {
549  std::vector<MElement *> els = it->second;
550  int ITER = 0;
551  while(!els.empty()) {
552  std::vector<MElement *> _side;
553  std::stack<MElement *> _s;
554  _s.push(els[0]);
555  _side.push_back(els[0]);
556  els.erase(els.begin());
557  while(!_s.empty()) {
558  MElement *t = _s.top();
559  _s.pop();
560  for(int i = 0; i < 3; i++) {
561  MEdge e0 = t->getEdge(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()) {
567  els.erase(ite);
568  _side.push_back(it0->second._t[j]);
569  _s.push(it0->second._t[j]);
570  }
571  }
572  }
573  }
574  }
575 
576  if(ITER) {
577  MVertex *v =
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);
580  old2new.insert(p);
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);
589  }
590  }
591  }
592  fprintf(_f, "SP(%g,%g,%g){%d};\n", it->first->x(), it->first->y(),
593  it->first->z(), (int)els.size());
594  // printf("found vertex with %d on one side\n",els.size());
595  }
596  ++ITER;
597  }
598  // if (ITER > 1)printf("ITER = %d\n",ITER);
599  ++it;
600  }
601  fprintf(_f, "};\n");
602  fclose(_f);
603 
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;
608  MVertex *old = e->getVertex(j);
609  for(int j = 0; j < e->getNumEdges(); j++) {
610  MEdge ed = e->getEdge(j);
611  if(ed.getVertex(0) == old) {
612  duplicateEdges[ed] = MEdge(v, ed.getVertex(1));
613  }
614  else if(ed.getVertex(1) == old) {
615  duplicateEdges[ed] = MEdge(ed.getVertex(0), v);
616  }
617  }
618  new2old[v] = old;
619  e->setVertex(j, v);
620  }
621 }
622 
623 static void
624 computeUniqueVectorPerTriangle(GModel *gm, std::vector<GFace *> &f,
625  std::map<MEdge, cross2d, MEdgeLessThan> &C,
626  int dir, std::map<MTriangle *, SVector3> &d)
627 {
628  for(size_t i = 0; i < f.size(); i++) {
629  for(size_t j = 0; j < f[i]->triangles.size(); j++) {
630  MTriangle *t = f[i]->triangles[j];
631  SVector3 a0(0, 0, 0);
632  int n = 0;
633  for(int k = 0; k < 3; k++) {
634  MEdge e = t->getEdge(k);
635  auto it = C.find(e);
636  if(it != C.end()) {
637  if(!it->second.inCutGraph) {
638  n++;
639  double C =
640  (dir == 1) ? cos(it->second._atemp) : sin(it->second._atemp);
641  double S =
642  (dir == 1) ? sin(it->second._atemp) : -cos(it->second._atemp);
643  SVector3 aa = it->second._tgt * C + it->second._tgt2 * S;
644  a0 += aa;
645  }
646  }
647  else {
648  printf("ERROR\n");
649  }
650  }
651  if(n) a0.normalize();
652  d[t] = a0;
653  }
654  }
655 }
656 
657 int ZERO_ = -8;
658 
659 static void createLagrangeMultipliers(dofManager<double> &myAssembler,
660  groupOfCross2d &g)
661 {
662  // return;
663  // if (g.crosses[0]->inInternalBoundary)return;
664 
665  if(g.singularities.size() == 1) {
666  // printf("group id %d singularity %lu (%lu)\n", g.groupId,
667  // g.singularities[0]->getNum(), g.singularities.size());
668  myAssembler.numberVertex(g.singularities[0], 0, 33);
669  myAssembler.numberVertex(g.singularities[0], 0, 34);
670  }
671  else {
672  // printf("group id %d %lu singularities \n", g.groupId,
673  // g.singularities.size());
674  }
675 
676  if(g.groupId == ZERO_) {
677  myAssembler.numberVertex(g.left[0], 0, 3 + 10000 * g.groupId);
678  }
679 
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);
683  }
684 }
685 
686 static void LagrangeMultipliers3(dofManager<double> &myAssembler,
687  groupOfCross2d &g,
688  std::map<MTriangle *, SVector3> &d0,
689  bool assemble)
690 {
691  return;
692  if(g.crosses[0]->inInternalBoundary) {
693  if(!assemble) {
694  // printf("group %d is internal\n",g.groupId);
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);
698  }
699  return;
700  }
701 
702  MTriangle *t0 = g.crosses[0]->_t[0];
703  MTriangle *t1 = g.crosses[0]->_t[1];
704  SVector3 dir0 = d0[t0];
705  SVector3 dir1 = d0[t1];
706 
707  if(std::find(g.side.begin(), g.side.end(), t1) != g.side.end()) {
708  dir0 = d0[t1];
709  dir1 = d0[t0];
710  }
711 
712  printf("%12.5E %12.5E\n", fabs(dot(g.crosses[0]->_tgt, dir0)),
713  fabs(dot(g.crosses[0]->_tgt, dir1)));
714 
715  Dof U1R(g.left[0]->getNum(), Dof::createTypeWithTwoInts(0, 1));
716  Dof U2R(g.right[0]->getNum(), Dof::createTypeWithTwoInts(0, 1));
717  Dof V1R(g.left[0]->getNum(), Dof::createTypeWithTwoInts(0, 2));
718  Dof V2R(g.right[0]->getNum(), Dof::createTypeWithTwoInts(0, 2));
719  for(size_t K = 1; K < g.left.size(); K++) {
720  Dof E1(g.left[K]->getNum(),
721  Dof::createTypeWithTwoInts(0, 12 + 100 * g.groupId));
722  Dof E2(g.left[K]->getNum(),
723  Dof::createTypeWithTwoInts(0, 13 + 100 * g.groupId));
724  Dof U1(g.left[K]->getNum(), Dof::createTypeWithTwoInts(0, 1));
725  Dof U2(g.right[K]->getNum(), Dof::createTypeWithTwoInts(0, 1));
726  Dof V1(g.left[K]->getNum(), Dof::createTypeWithTwoInts(0, 2));
727  Dof V2(g.right[K]->getNum(), Dof::createTypeWithTwoInts(0, 2));
728 
729  if(fabs(dot(g.crosses[0]->_tgt, dir0)) > .5) {
730  myAssembler.assemble(E1, U1, 1.0);
731  myAssembler.assemble(U1, E1, 1.0);
732  myAssembler.assemble(E1, U1R, -1.0);
733  myAssembler.assemble(U1R, E1, -1.0);
734  }
735  else {
736  myAssembler.assemble(E1, V1, 1.0);
737  myAssembler.assemble(V1, E1, 1.0);
738  myAssembler.assemble(E1, V1R, -1.0);
739  myAssembler.assemble(V1R, E1, -1.0);
740  }
741 
742  if(fabs(dot(g.crosses[0]->_tgt, dir1)) > .5) {
743  // printf("HAHAHA %d\n",g.groupId);
744  myAssembler.assemble(E2, U2, 1.0);
745  myAssembler.assemble(U2, E2, 1.0);
746  myAssembler.assemble(E2, U2R, -1.0);
747  myAssembler.assemble(U2R, E2, -1.0);
748  }
749  else {
750  // printf("HAHAHO %d\n",g.groupId);
751  myAssembler.assemble(E2, V2, 1.0);
752  myAssembler.assemble(V2, E2, 1.0);
753  myAssembler.assemble(E2, V2R, -1.0);
754  myAssembler.assemble(V2R, E2, -1.0);
755  }
756  }
757  }
758 }
759 
760 static void assembleLagrangeMultipliers(dofManager<double> &myAssembler,
761  groupOfCross2d &g)
762 {
763  Dof U1R(g.left[0]->getNum(), Dof::createTypeWithTwoInts(0, 1));
764  Dof V1R(g.left[0]->getNum(), Dof::createTypeWithTwoInts(0, 2));
765  Dof U2R(g.right[0]->getNum(), Dof::createTypeWithTwoInts(0, 1));
766  Dof V2R(g.right[0]->getNum(), Dof::createTypeWithTwoInts(0, 2));
767 
768  // if (g.groupId == 1){
769  // g.mat[0][0]=-1;
770  // g.mat[1][1]=-1;
771  // }
772 
773  // printf("GROUP %d\n",g.groupId);
774  // printf("LEFT --- RIGHT\n");
775  // printf("%3lu %3lu\n",g.left[0]->getNum(),g.right[0]->getNum());
776 
777  if(g.singularities.size() == 1) {
778  Dof E1(g.singularities[0]->getNum(), Dof::createTypeWithTwoInts(0, 33));
779  Dof E2(g.singularities[0]->getNum(), Dof::createTypeWithTwoInts(0, 34));
780  Dof U(g.singularities[0]->getNum(), Dof::createTypeWithTwoInts(0, 1));
781  Dof V(g.singularities[0]->getNum(), Dof::createTypeWithTwoInts(0, 2));
782 
783  myAssembler.assemble(E1, U, 1.0);
784  myAssembler.assemble(E1, U1R, -1.0);
785 
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]);
790 
791  myAssembler.assemble(E2, V, 1.0);
792  myAssembler.assemble(E2, V1R, -1.0);
793 
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]);
798 
799  // sym
800 
801  myAssembler.assemble(U, E1, 1.0);
802  myAssembler.assemble(U1R, E1, -1.0);
803 
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]);
808 
809  myAssembler.assemble(V, E2, 1.0);
810  myAssembler.assemble(V1R, E2, -1.0);
811 
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]);
816  }
817 
818  // TEST NO JUMP ON U for group 3 ...
819  if(g.groupId == ZERO_) {
820  Dof E1(g.left[0]->getNum(),
821  Dof::createTypeWithTwoInts(0, 3 + 10000 * g.groupId));
822  Dof U1(g.left[0]->getNum(), Dof::createTypeWithTwoInts(0, 2));
823  Dof U2(g.right[0]->getNum(), Dof::createTypeWithTwoInts(0, 1));
824  }
825 
826  for(size_t K = 1; K < g.left.size(); K++) {
827  // printf("%3lu %3lu\n",g.left[K]->getNum(),g.right[K]->getNum());
828  // EQUATION IDS (Lagrange multipliers)
829  Dof E1(g.left[K]->getNum(),
830  Dof::createTypeWithTwoInts(0, 3 + 100 * g.groupId));
831  Dof E2(g.left[K]->getNum(),
832  Dof::createTypeWithTwoInts(0, 4 + 100 * g.groupId));
833 
834  // DOF IDS
835  Dof U1(g.left[K]->getNum(), Dof::createTypeWithTwoInts(0, 1));
836  Dof V1(g.left[K]->getNum(), Dof::createTypeWithTwoInts(0, 2));
837  Dof U2(g.right[K]->getNum(), Dof::createTypeWithTwoInts(0, 1));
838  Dof V2(g.right[K]->getNum(), Dof::createTypeWithTwoInts(0, 2));
839 
840  myAssembler.assemble(E1, U1, 1.0);
841  myAssembler.assemble(E1, U1R, -1.0);
842 
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]);
847 
848  myAssembler.assemble(E2, V1, 1.0);
849  myAssembler.assemble(E2, V1R, -1.0);
850 
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]);
855 
856  // sym
857 
858  myAssembler.assemble(U1, E1, 1.0);
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]);
864 
865  myAssembler.assemble(V1, E2, 1.0);
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]);
871  }
872 }
873 
874 static void
875 LagrangeMultipliers2(dofManager<double> &myAssembler, int NUMDOF,
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)
880 {
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;
886  MVertex *v = ed.getVertex(0);
887  auto it = C.find(groups[i][0]->_e);
888  SVector3 aaa = lift[it->second._t[0]];
889 
890  double S = fabs(dot(it->second._tgt, aaa));
891 
892  // printf("DIR %d S = %12.5E\n",NUMDOF, S);
893 
894  if(S < .2 /*sqrt(2)/2.0*/) {
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++) {
900  MVertex *vk = ed.getVertex(k);
901  if(vk != v) {
902  if(!assemble) { myAssembler.numberVertex(vk, 0, 5 + 100 * i); }
903  else {
904  Dof Eref(vk->getNum(),
905  Dof::createTypeWithTwoInts(0, 5 + 100 * i));
906  Dof Uref(vk->getNum(), Dof::createTypeWithTwoInts(0, NUMDOF));
907  Dof U(v->getNum(), Dof::createTypeWithTwoInts(0, NUMDOF));
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);
912  }
913  }
914  }
915  }
916  }
917  }
918 }
919 
920 struct cutGraphPassage {
921  int _id;
922  int _uv;
923  SPoint3 _p;
924  cutGraphPassage(int id, int uv, const SPoint3 &p) : _id(id), _uv(uv), _p(p) {}
925 };
926 
927 static void createDofs(dofManager<double> &myAssembler, int NUMDOF,
928  std::set<MVertex *, MVertexPtrLessThan> &vs)
929 {
930  for(auto it = vs.begin(); it != vs.end(); ++it)
931  myAssembler.numberVertex(*it, 0, NUMDOF);
932 }
933 
934 void createExtraConnexions(dofManager<double> &myAssembler,
935  std::vector<groupOfCross2d> &G,
936  std::vector<cutGraphPassage> &passages)
937 {
938  return;
939  // give a number to the equation ...
940  myAssembler.numberVertex(G[0].left[0], 0, 10201020);
941 }
942 
943 void assembleExtraConnexions(dofManager<double> &myAssembler,
944  std::vector<groupOfCross2d> &G,
945  std::vector<cutGraphPassage> &passages)
946 {
947  int nConn = 2;
948  int groups[2][2] = {{14, 1}, {13, 2}};
949 
950  Dof E(G[0].left[0]->getNum(), Dof::createTypeWithTwoInts(0, 10201020));
951 
952  for(int i = 0; i < nConn; i++) {
953  groupOfCross2d &g = G[groups[i][0]];
954  int index = groups[i][1];
955  Dof U1(g.left[0]->getNum(), Dof::createTypeWithTwoInts(0, index));
956  Dof U2(g.right[0]->getNum(), Dof::createTypeWithTwoInts(0, 1));
957  Dof V2(g.right[0]->getNum(), Dof::createTypeWithTwoInts(0, 2));
958  myAssembler.assemble(E, U1, 1.0);
959  myAssembler.assemble(E, U2, -g.mat[index - 1][0]);
960  myAssembler.assemble(E, V2, -g.mat[index - 1][1]);
961  myAssembler.assemble(U1, E, 1.0);
962  myAssembler.assemble(U2, E, -g.mat[index - 1][0]);
963  myAssembler.assemble(V2, E, -g.mat[index - 1][1]);
964  }
965 }
966 
967 static void computePotential(
968  GModel *gm, std::vector<GFace *> &f, dofManager<double> &dof,
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)
976 {
977  double a[3];
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++) {
981  MTriangle *t = f[i]->triangles[j];
982  for(size_t k = 0; k < 3; k++) { vs.insert(t->getVertex(k)); }
983  }
984  }
985 
986 #if defined(HAVE_PETSC)
988 #elif defined(HAVE_GMM)
989  // linearSystemFull<double> *_lsys = new linearSystemFull<double>;
992 #else
994 #endif
995 
996  dofManager<double> myAssembler(_lsys);
997 
998  // int NUMDOF = dir+1;
999 
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);
1004 
1005  createExtraConnexions(myAssembler, G, passages);
1006 
1007  for(size_t i = 0; i < G.size(); i++) {
1008  createLagrangeMultipliers(myAssembler, G[i]);
1009  LagrangeMultipliers3(myAssembler, G[i], lift, false);
1010  }
1011 
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);
1017  }
1018 
1019  assembleExtraConnexions(myAssembler, G, passages);
1020 
1021  simpleFunction<double> ONE(1.0);
1022  laplaceTerm l(nullptr, 1, &ONE);
1023  laplaceTerm l2(nullptr, 2, &ONE);
1024 
1025  for(size_t i = 0; i < f.size(); i++) {
1026  for(size_t j = 0; j < f[i]->triangles.size(); j++) {
1027  MTriangle *t = f[i]->triangles[j];
1028  SElement se(t);
1029  l.addToMatrix(myAssembler, &se);
1030  l2.addToMatrix(myAssembler, &se);
1031  SVector3 a0 = lift[t];
1032  SVector3 a1 = lift2[t];
1033  double va, vb, vc;
1034  auto itx = new2old.find(t->getVertex(0));
1035  dof.getDofValue(itx == new2old.end() ? t->getVertex(0) : itx->second, 0,
1036  1, va);
1037  itx = new2old.find(t->getVertex(1));
1038  dof.getDofValue(itx == new2old.end() ? t->getVertex(1) : itx->second, 0,
1039  1, vb);
1040  itx = new2old.find(t->getVertex(2));
1041  dof.getDofValue(itx == new2old.end() ? t->getVertex(2) : itx->second, 0,
1042  1, vc);
1043 
1044  double F = (exp(va) + exp(vb) + exp(vc)) / 3.0;
1045 
1046  a0 *= F;
1047  a1 *= F;
1048 
1049  SPoint3 pp = t->barycenter();
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()};
1056  double g1[3];
1057  a[0] = 1;
1058  a[1] = 0;
1059  a[2] = 0;
1060  t->interpolateGrad(a, 0, 0, 0, g1);
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];
1063  a[0] = 0;
1064  a[1] = 1;
1065  a[2] = 0;
1066  t->interpolateGrad(a, 0, 0, 0, g1);
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];
1069  a[0] = 0;
1070  a[1] = 0;
1071  a[2] = 1;
1072  t->interpolateGrad(a, 0, 0, 0, g1);
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));
1081 
1082  double V = t->getVolume();
1083  _lsys->addToRightHandSide(num1, RHS1 * V);
1084  _lsys->addToRightHandSide(num2, RHS2 * V);
1085  _lsys->addToRightHandSide(num3, RHS3 * V);
1086  _lsys->addToRightHandSide(num11, RHS11 * V);
1087  _lsys->addToRightHandSide(num21, RHS21 * V);
1088  _lsys->addToRightHandSide(num31, RHS31 * V);
1089  }
1090  }
1091  double A = TimeOfDay();
1092  _lsys->systemSolve();
1093  double B = TimeOfDay();
1094  Msg::Info("Computing potentials (%d unknowns) in %3lf seconds",
1095  myAssembler.sizeOfR(), B - A);
1096 
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++) {
1103  MTriangle *t = f[i]->triangles[j];
1104  double a, b, c;
1105  double a1, b1, c1;
1106  myAssembler.getDofValue(t->getVertex(0), 0, 1, a);
1107  myAssembler.getDofValue(t->getVertex(1), 0, 1, b);
1108  myAssembler.getDofValue(t->getVertex(2), 0, 1, c);
1109  myAssembler.getDofValue(t->getVertex(0), 0, 2, a1);
1110  myAssembler.getDofValue(t->getVertex(1), 0, 2, b1);
1111  myAssembler.getDofValue(t->getVertex(2), 0, 2, c1);
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",
1115  .2 * a + t->getVertex(0)->x(), -.2 * a1 + t->getVertex(0)->y(),
1116  0., .2 * b + t->getVertex(1)->x(),
1117  -.2 * b1 + t->getVertex(1)->y(), 0.,
1118  .2 * c + t->getVertex(2)->x(), -.2 * c1 + t->getVertex(2)->y(),
1119  0., a, b, c, a1, b1, c1);
1120 
1121  res[t->getVertex(0)] = a;
1122  res[t->getVertex(1)] = b;
1123  res[t->getVertex(2)] = c;
1124  res2[t->getVertex(0)] = a1;
1125  res2[t->getVertex(1)] = b1;
1126  res2[t->getVertex(2)] = c1;
1127  }
1128  }
1129  fprintf(F, "};\n");
1130  fclose(F);
1131  fprintf(F2, "};\n");
1132  fclose(F2);
1133 }
1134 
1135 static double distance(MTriangle *t,
1136  std::set<MVertex *, MVertexPtrLessThan> &boundaries)
1137 {
1138  // return drand48();
1139  SPoint3 p = t->barycenter();
1140  double dmin = 1.e22;
1141  for(auto it = boundaries.begin(); it != boundaries.end(); ++it) {
1142  SPoint3 pp((*it)->x(), (*it)->y(), (*it)->z());
1143  double d = p.distance(pp);
1144  if(d < dmin) { dmin = d; }
1145  }
1146  return -dmin;
1147 }
1148 
1149 struct temp_comp {
1150  cross2d *cr;
1151  double a;
1152  temp_comp(MVertex *v, cross2d *c, cross2d *ref, SVector3 &n) : cr(c)
1153  {
1154  MVertex *tref =
1155  ref->_e.getVertex(0) == v ? ref->_e.getVertex(1) : ref->_e.getVertex(0);
1156  MVertex *tc =
1157  c->_e.getVertex(0) == v ? c->_e.getVertex(1) : c->_e.getVertex(0);
1158 
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());
1161  t1.normalize();
1162  t2.normalize();
1163 
1164  double cosTheta = dot(t1, t2);
1165  double sinTheta;
1166  SVector3 cc = crossprod(t1, t2);
1167  if(dot(cc, n) > 0)
1168  sinTheta = norm(crossprod(t1, t2));
1169  else
1170  sinTheta = -norm(crossprod(t1, t2));
1171  a = atan2(sinTheta, cosTheta);
1172  }
1173  bool operator<(const temp_comp &other) const { return a < other.a; }
1174 };
1175 
1176 static bool isSingular(MVertex *v, std::vector<cross2d *> &adj, double &MAX)
1177 {
1178  const std::size_t TEST = 0;
1179  if(v->getNum() == TEST) printf("VERTEX %lu\n", v->getNum());
1180  SVector3 n(0, 0, 0);
1181  for(size_t i = 0; i < adj.size(); i++) {
1182  if(adj[i]->inBoundary || adj[i]->inInternalBoundary) return false;
1183  n += adj[i]->_nrml;
1184  }
1185  n.normalize();
1186 
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));
1190  }
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);
1194  SVector3 ref0 = ref;
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);
1200  SVector3 d3 =
1201  c2._tgt * cos(c2._atemp + 2 * P) + c2._tgt2 * sin(c2._atemp + 2 * P);
1202  SVector3 d4 =
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)
1209  ref = d1;
1210  else if(D2 > D1 && D2 > D3 && D2 > D4)
1211  ref = d2;
1212  else if(D3 > D1 && D3 > D2 && D3 > D4)
1213  ref = d3;
1214  else
1215  ref = d4;
1216  }
1217 
1218  if(v->getNum() == TEST)
1219  printf("VERTEX %lu %12.5E %12.5E %12.5E\n", v->getNum(), n.x(), n.y(),
1220  n.z());
1221  SVector3 t0, b0;
1222  std::vector<double> angles;
1223  for(size_t i = 0; i < adj.size(); i++) {
1224  if(i == 0) {
1225  SVector3 t =
1226  (adj[i]->_e.getVertex(0) == v) ? -adj[i]->_tgt : adj[i]->_tgt;
1227  t -= n * (dot(t, n));
1228  t.normalize();
1229  SVector3 b = crossprod(n, t);
1230  b0 = b;
1231  t0 = t;
1232  }
1233 
1234  SVector3 repr = adj[i]->o_i - n * dot(adj[i]->o_i, n);
1235  repr.normalize();
1236  // t * dot (,adj[i]->_tgt) +
1237  // b * dot (adj[i]->o_i,adj[i]->_tgt2) ;
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) {
1242  printf("EDGE %lu %lu\n", adj[i]->_e.getVertex(0)->getNum(),
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(),
1245  adj[i]->o_i.z());
1246  printf("ANGLE = %12.5E %12.5E\n", angle * 180 / M_PI,
1247  lifting(angles[0], angles[i]) * 180 / M_PI);
1248  }
1249  }
1250 
1251  MAX = 0;
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])));
1256  }
1257  }
1258  if(v->getNum() == TEST) printf("\n");
1259  if(v->getNum() == TEST)
1260  printf("vertex %lu %lu edges %12.5E\n", v->getNum(), adj.size(), MAX);
1261  // if (MAX > .5)printf("vertex %lu %lu edges %12.5E -- new method %12.5E\n",
1262  // v->getNum(), adj.size(), MAX,dot(ref,ref0));
1263  return MAX > .5;
1264 }
1265 
1266 void isMinMax(MVertex *v, std::vector<cross2d *> adj, dofManager<double> *dof,
1267  bool &isMin, bool &isMax)
1268 {
1269  double aa;
1270  isMin = isMax = true;
1271  dof->getDofValue(v, 0, 1, aa);
1272  for(size_t i = 0; i < adj.size(); i++) {
1273  double a;
1274  dof->getDofValue(adj[i]->_e.getVertex(0) == v ? adj[i]->_e.getVertex(1) :
1275  adj[i]->_e.getVertex(0),
1276  0, 1, a);
1277  if(a < aa) isMin = false;
1278  if(a > aa) isMax = false;
1279  }
1280 }
1281 
1282 static void
1283 computeSingularities(std::map<MEdge, cross2d, MEdgeLessThan> &C,
1284  std::set<MVertex *, MVertexPtrLessThan> &singularities,
1285  std::map<MVertex *, int> &indices, dofManager<double> *dof)
1286 {
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);
1293  conn.insert(p);
1294  p = std::make_pair(it->first.getVertex(1), &it->second);
1295  conn.insert(p);
1296  }
1297  MVertex *v = nullptr;
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); }
1301  else {
1302  double MAX;
1303  if(v && isSingular(v, adj, MAX)) {
1304  singularities.insert(v);
1305  bool isMin, isMax;
1306  isMinMax(v, adj, dof, isMin, isMax);
1307  if(isMax)
1308  indices[v] = 1;
1309  else if(isMin)
1310  indices[v] = -1;
1311  else
1312  printf("ERROR -- \n");
1313  fprintf(f_, "SP(%g,%g,%g){%d};\n", v->x(), v->y(), v->z(), indices[v]);
1314  }
1315  adj.clear();
1316  v = it->first;
1317  adj.push_back(it->second);
1318  }
1319  }
1320  fprintf(f_, "};\n");
1321  fclose(f_);
1322 }
1323 
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)
1328 {
1329  std::set<MTriangle *, MElementPtrLessThan> touched;
1330  std::vector<cross2d *> tree;
1331  std::vector<MEdge> cotree;
1332  std::set<std::pair<double, MTriangle *> > _distances;
1333  {
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));
1339  }
1340  }
1341  }
1342  std::set<MVertex *, MVertexPtrLessThan> _all = boundaries;
1343  _all.insert(singularities.begin(), singularities.end());
1344 
1345  FILE *fff2 = fopen("tree.pos", "w");
1346  fprintf(fff2, "View \"sides\"{\n");
1347 
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);
1351  touched.insert(t);
1352  while(!_distances.empty()) {
1353  t = (_distances.begin()->second);
1354  _distances.erase(_distances.begin());
1355 
1356  for(int i = 0; i < 3; i++) {
1357  MEdge e = t->getEdge(i);
1358  auto it = C.find(e);
1359  for(size_t j = 0; j < it->second._t.size(); j++) {
1360  MTriangle *tt = it->second._t[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);
1365  touched.insert(tt);
1366  tree.push_back(&it->second);
1367  }
1368  }
1369  }
1370  }
1371 
1372  std::sort(tree.begin(), tree.end());
1373  auto it = C.begin();
1374  std::map<MVertex *, std::vector<MEdge>, MVertexPtrLessThan> _graph;
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;
1383  }
1384  else
1385  it0->second.push_back(it->first);
1386  }
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);
1392  }
1393  }
1394 
1395  fprintf(fff2, "};\n");
1396  fclose(fff2);
1397 
1398  // {
1399  // for(auto it = boundaries.begin(); it != boundaries.end(); ++it) {
1400  // auto it2 = singularities.find(*it); if(it2 != singularities.end())
1401  // singularities.erase(it2);
1402  // }
1403  // }
1404 
1405  while(1) {
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);
1416  auto position =
1417  std::find(it2->second.begin(), it2->second.end(), it->second[0]);
1418  it2->second.erase(position);
1419  it->second.clear();
1420  }
1421  }
1422  }
1423  if(!somethingDone) break;
1424  }
1425 
1426  FILE *fff = fopen("cotree.pos", "w");
1427  fprintf(fff, "View \"sides\"{\n");
1428  {
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()) {
1435  cutG.insert(e);
1436  }
1437  }
1438  }
1439  }
1440 
1441  // Add internal boundaries to the cut graph
1442  {
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);
1447  }
1448  }
1449  }
1450 
1451  {
1452  auto it = cutG.begin();
1453  for(; it != cutG.end(); ++it) {
1454  MEdge e = *it;
1455  fprintf(fff, "SL(%g,%g,%g,%g,%g,%g){%d,%d};\n", e.getVertex(0)->x(),
1456  e.getVertex(0)->y(), e.getVertex(0)->z(), e.getVertex(1)->x(),
1457  e.getVertex(1)->y(), e.getVertex(1)->z(), 1, 1);
1458  }
1459  }
1460  fprintf(fff, "};\n");
1461  fclose(fff);
1462 }
1463 
1464 int analyzeCorner(std::multimap<MVertex *, cross2d *> &conn, MVertex *v)
1465 {
1466  // compute if this is an external (1) or internal (-1) corner.
1467  return 1;
1468 }
1469 
1470 static void
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)
1476 {
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);
1485  }
1486  else if(it->second.inCutGraph) {
1487  cutgraph.insert(v0);
1488  cutgraph.insert(v1);
1489  }
1490  }
1491 
1492  std::set<cross2d *> _all;
1493 
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);
1498  conn.insert(p);
1499  p = std::make_pair(it->first.getVertex(1), &it->second);
1500  conn.insert(p);
1501  }
1502 
1503  for(auto it = boundaries.begin(); it != boundaries.end(); ++it) {
1504  MVertex *v = *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++; }
1510  }
1511  if(bnd.size() == 2) {
1512  if(fabs(dot(bnd[0]->o_i, bnd[1]->o_i)) < .25) {
1513  corners.insert(v);
1514  cutgraph.insert(v);
1515  }
1516  if(countCutGraph == 1) { singularities.insert(v); }
1517  }
1518  if(bnd.size() > 2) { cutgraph.insert(v); }
1519  }
1520 
1521  std::string ss = gm->getName();
1522  std::string fn = cutGraph ? ss + "_groups_cg.pos" : ss + "_groups_bnd.pos";
1523 
1524  FILE *f = fopen(fn.c_str(), "w");
1525 
1526  fprintf(f, "View \" \"{\n");
1527 
1528  std::set<MVertex *, MVertexPtrLessThan> endPoints = singularities;
1529  {
1530  for(auto it = conn.begin(); it != conn.end(); ++it) {
1531  int count = 0;
1532  for(auto it2 = conn.lower_bound(it->first);
1533  it2 != conn.upper_bound(it->first); ++it2) {
1534  if(it2->second->inCutGraph) { count++; }
1535  }
1536  if(count > 2) endPoints.insert(it->first);
1537  }
1538  }
1539 
1540  for(int AA = 0; AA < 4; AA++) {
1541  if(cutGraph) {
1542  for(auto it = endPoints.begin(); it != endPoints.end(); ++it) {
1543  MVertex *v = *it;
1544  std::vector<cross2d *> group;
1545  do {
1546  MVertex *vnew = nullptr;
1547  for(auto it2 = conn.lower_bound(v); it2 != conn.upper_bound(v);
1548  ++it2) {
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(),
1563  groups.size());
1564  break;
1565  }
1566  }
1567  if(vnew == nullptr) break;
1568  v = vnew;
1569  } while((boundaries.find(v) == boundaries.end()) &&
1570  (endPoints.find(v) == endPoints.end()));
1571  if(group.size()) {
1572  groups.push_back(group);
1573  _all.insert(group.begin(), group.end());
1574  }
1575  }
1576  }
1577  else {
1578  for(auto it = boundaries.begin(); it != boundaries.end(); ++it) {
1579  MVertex *v = *it;
1580  if(cutgraph.find(v) != cutgraph.end() ||
1581  singularities.find(v) != singularities.end()) {
1582  // printf("START POINT %lu %d %d\n",v->getNum(),cutgraph.find(v)
1585  std::vector<cross2d *> group;
1586  do {
1587  MVertex *vnew = nullptr;
1588  for(auto it2 = conn.lower_bound(v); it2 != conn.upper_bound(v);
1589  ++it2) {
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);
1597  // printf("EDGE %lu %lu (%d)\n",
1598  // it2->second->_e.getVertex(0)->getNum(),it2->second->_e.getVertex(1)->getNum(),
1599  // singularities.find(v) == singularities.end());
1600  // printf("v %lu EDGE %lu
1601  //%lu\n",v->getNum(),it2->second->_e.getVertex(0)->getNum(),it2->second->_e.getVertex(1)->getNum());
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(),
1609  groups.size());
1610  break;
1611  }
1612  }
1613  if(vnew == nullptr) break;
1614  v = vnew;
1615  // printf("NEXT POINT %lu %d
1616  //%lu\n",v->getNum(),singularities.find(v) == singularities.end(),
1617  // singularities.size());
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());
1623  }
1624  }
1625  }
1626  }
1627  }
1628  fprintf(f, "};\n");
1629  fclose(f);
1630 }
1631 
1632 static void
1633 fastImplementationExtrinsic(std::map<MEdge, cross2d, MEdgeLessThan> &C,
1634  double tol = 1.e-10)
1635 {
1636  double *data = new double[C.size() * 6];
1637  size_t *graph = new size_t[C.size() * 4];
1638  auto it = C.begin();
1639  int counter = 0;
1640 
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;
1649  ++counter;
1650  }
1651 
1652  it = C.begin();
1653  counter = 0;
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;
1659  }
1660  if(it->second.inBoundary || it->second.inInternalBoundary) {
1661  graph[4 * counter + 2] = graph[4 * counter + 3] = it->second.counter;
1662  }
1663 
1664  counter++;
1665  }
1666 
1667  size_t N = C.size();
1668  int MAXITER = 10000;
1669  int ITER = -1;
1670  while(ITER++ < MAXITER) {
1671  double x[3], y[3];
1672  double RES = 0;
1673  for(size_t i = 0; i < N; i++) {
1674  double *r = &data[6 * i + 0];
1675  double *n = &data[6 * i + 3];
1676  SVector3 ro(r[0], r[1], r[2]);
1677  size_t *neigh = &graph[4 * i];
1678  double weight = 0;
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];
1689  r[0] -= n[0] * dd;
1690  r[1] -= n[1] * dd;
1691  r[2] -= n[2] * dd;
1692  double NRM = sqrt(r[0] * r[0] + r[1] * r[1] + r[2] * r[2]);
1693  if(NRM != 0.0) {
1694  r[0] /= NRM;
1695  r[1] /= NRM;
1696  r[2] /= NRM;
1697  }
1698  weight += 1;
1699  }
1700  double dp = r[0] * ro[0] + r[1] * ro[1] + r[2] * ro[2];
1701  RES += std::min(1. - fabs(dp), fabs(dp));
1702  }
1703  // data[6*i+0]=r[0];
1704  // data[6*i+1]=r[1];
1705  // data[6*i+2]=r[2];
1706  }
1707  if(ITER % 1000 == 0)
1708  Msg::Info("NL smooth : iter %6d RES = %12.5E", ITER, RES);
1709  if(RES < tol) break;
1710  }
1711 
1712  it = C.begin();
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];
1718  }
1719  delete[] data;
1720  delete[] graph;
1721 }
1722 
1723 static dofManager<double> *computeH(GModel *gm, std::vector<GFace *> &f,
1724  std::set<MVertex *, MVertexPtrLessThan> &vs,
1725  std::map<MEdge, cross2d, MEdgeLessThan> &C)
1726 {
1727 #if defined(HAVE_PETSC)
1729 #elif defined(HAVE_GMM)
1730  // MUMPS !!!
1732 #else
1734 #endif
1735 
1736  dofManager<double> *myAssembler = new dofManager<double>(_lsys);
1737 
1738  // myAssembler.fixVertex(*vs.begin(), 0, 1, 0);
1739  for(auto it = vs.begin(); it != vs.end(); ++it)
1740  myAssembler->numberVertex(*it, 0, 1);
1741 
1742  std::string ss = gm->getName();
1743  std::string fn = ss + "_grad.pos";
1744 
1745  FILE *_f = fopen(fn.c_str(), "w");
1746  fprintf(_f, "View \"grad\"{\n");
1747 
1748  simpleFunction<double> ONE(1.0);
1749  laplaceTerm l(nullptr, 1, &ONE);
1750 
1751  std::map<MTriangle *, SVector3> gradients_of_theta;
1752 
1753  for(size_t i = 0; i < f.size(); i++) {
1754  for(size_t j = 0; j < f[i]->triangles.size(); j++) {
1755  MTriangle *t = f[i]->triangles[j];
1756 
1757  SVector3 v10(t->getVertex(1)->x() - t->getVertex(0)->x(),
1758  t->getVertex(1)->y() - t->getVertex(0)->y(),
1759  t->getVertex(1)->z() - t->getVertex(0)->z());
1760  SVector3 v20(t->getVertex(2)->x() - t->getVertex(0)->x(),
1761  t->getVertex(2)->y() - t->getVertex(0)->y(),
1762  t->getVertex(2)->z() - t->getVertex(0)->z());
1763  SVector3 xx = crossprod(v20, v10);
1764  xx.normalize();
1765 
1766  SElement se(t);
1767  l.addToMatrix(*myAssembler, &se);
1768  MEdge e0 = t->getEdge(0);
1769  MEdge e1 = t->getEdge(1);
1770  MEdge e2 = t->getEdge(2);
1771  auto it0 = C.find(e0);
1772  auto it1 = C.find(e1);
1773  auto it2 = C.find(e2);
1774 
1775  // printf("%g %ag %g\n",a0,a1,a2);
1776 
1777  double a0 = it0->second._a;
1778  double A1 =
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);
1783  double A2 =
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);
1788 
1789  SVector3 x0, x1, x2, x3;
1790  SVector3 t_i = crossprod(xx, it0->second._tgt);
1791  t_i -= xx * dot(xx, t_i);
1792  t_i.normalize();
1793  SVector3 o_i = it0->second.o_i;
1794  o_i -= xx * dot(xx, o_i);
1795  o_i.normalize();
1796  SVector3 o_1 = it1->second.o_i;
1797  o_1 -= xx * dot(xx, o_1);
1798  o_1.normalize();
1799  SVector3 o_2 = it2->second.o_i;
1800  o_2 -= xx * dot(xx, o_2);
1801  o_2.normalize();
1802  compat_orientation_extrinsic(o_i, xx, o_1, xx, x0, x1);
1803  compat_orientation_extrinsic(o_i, xx, o_2, xx, x2, x3);
1804 
1805  // compat_orientation_extrinsic
1806  // (it0->second.o_i,it0->second._nrml,it1->second.o_i,it1->second._nrml,x0,x1);
1807  // compat_orientation_extrinsic
1808  // (it0->second.o_i,it0->second._nrml,it2->second.o_i,it2->second._nrml,x2,x3);
1809  // a0 = atan2(dot(it0->second._tgt2,it0->second.o_i),
1810  // dot(it0->second._tgt,it0->second.o_i));
1811  a0 = atan2(dot(t_i, o_i), dot(it0->second._tgt, o_i));
1812 
1813  x0 -= xx * dot(xx, x0);
1814  x0.normalize();
1815  x1 -= xx * dot(xx, x1);
1816  x1.normalize();
1817  x2 -= xx * dot(xx, x2);
1818  x2.normalize();
1819  x3 -= xx * dot(xx, x3);
1820  x3.normalize();
1821 
1822  it0->second.normalize(a0);
1823  it0->second._a = a0;
1824  // A1 = atan2(dot(it0->second._tgt2,x1),
1825  // dot(it0->second._tgt,x1));
1826  // A2 = atan2(dot(it0->second._tgt2,x3),
1827  // dot(it0->second._tgt,x3));
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);
1834  // it0->second.normalize(a1);
1835  // it0->second.normalize(a2);
1836  // it0->second._a = a0 = 0;
1837  // a1 = it0->second.lifting(A1);
1838  // a2 = it0->second.lifting(A2);
1839 
1840  double a[3] = {a0 + a2 - a1, a0 + a1 - a2, a1 + a2 - a0};
1841  double g[3] = {0, 0, 0};
1842  t->interpolateGrad(a, 0, 0, 0, g);
1843  gradients_of_theta[t] = SVector3(g[0], g[1], g[2]);
1844  SPoint3 pp = t->barycenter();
1845 
1846  // fprintf(_f,"VP(%g,%g,%g){%g,%g,%g};\n",pp.x(),pp.y(),pp.z(),
1847  // x0.x(),x0.y(),x0.z());
1848  // fprintf(_f,"VP(%g,%g,%g){%g,%g,%g};\n",pp.x(),pp.y(),pp.z(),
1849  // x1.x(),x1.y(),x1.z());
1850  // fprintf(_f,"VP(%g,%g,%g){%g,%g,%g};\n",pp.x(),pp.y(),pp.z(),
1851  // x2.x(),x2.y(),x2.z());
1852  // fprintf(_f,"VP(%g,%g,%g){%g,%g,%g};\n",pp.x(),pp.y(),pp.z(),
1853  // x3.x(),x3.y(),x3.z());
1854 
1855  fprintf(_f, "VP(%g,%g,%g){%g,%g,%g};\n", pp.x(), pp.y(), pp.z(), g[0],
1856  g[1], g[2]);
1857  // fprintf(_f, "VP(%g,%g,%g){%g,%g,%g};\n", pp.x(), pp.y(), pp.z(),
1858  // -g[1],
1859  // g[0], g[2]);
1860  // printf("A %g vs %g\n",sqrt(
1861  // g[1]*g[1]+g[0]*g[0]), 1./(sqrt((pp.x())*(pp.x())+(pp.y())*(pp.y()))));
1862 
1863  SVector3 G(g[0], g[1], g[2]);
1864  SVector3 GT = crossprod(G, xx);
1865 
1866  double g1[3];
1867  a[0] = 1;
1868  a[1] = 0;
1869  a[2] = 0;
1870  t->interpolateGrad(a, 0, 0, 0, g1);
1871  double RHS1 = g1[0] * GT.x() + g1[1] * GT.y() + g1[2] * GT.z();
1872  // double RHS1 = g1[0]*g[0]+g1[1]*g[1]+g1[2]*g[2];
1873  a[0] = 0;
1874  a[1] = 1;
1875  a[2] = 0;
1876  t->interpolateGrad(a, 0, 0, 0, g1);
1877  double RHS2 = g1[0] * GT.x() + g1[1] * GT.y() + g1[2] * GT.z();
1878  // double RHS2 = g1[0]*g[0]+g1[1]*g[1]+g1[2]*g[2];
1879  a[0] = 0;
1880  a[1] = 0;
1881  a[2] = 1;
1882  t->interpolateGrad(a, 0, 0, 0, g1);
1883  double RHS3 = g1[0] * GT.x() + g1[1] * GT.y() + g1[2] * GT.z();
1884  // double RHS3 = g1[0]*g[0]+g1[1]*g[1]+g1[2]*g[2];
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));
1888  double V = -t->getVolume();
1889  _lsys->addToRightHandSide(num1, RHS1 * V);
1890  _lsys->addToRightHandSide(num2, RHS2 * V);
1891  _lsys->addToRightHandSide(num3, RHS3 * V);
1892  }
1893  }
1894  fprintf(_f, "};\n");
1895  fclose(_f);
1896  _lsys->systemSolve();
1897 
1898  return myAssembler;
1899 }
1900 
1901 /*
1902  1) find u_i and v_i of all singularities
1903  2) compute [MAX,MIN] max of u's and v's
1904  3) Divide this interval into
1905 
1906 */
1907 
1908 static double coord1d(double a0, double a1, double a)
1909 {
1910  if(a1 == a0) return 0.0;
1911  return (a - a0) / (a1 - a0);
1912 }
1913 
1914 struct edgeCuts {
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)
1920  {
1921  for(size_t i = 0; i < ps.size(); i++) {
1922  SVector3 v(ps[i], p);
1923  if(v.norm() < 1.e-10) { return false; }
1924  }
1925  ps.push_back(p);
1926  indexOfCuts.push_back(ind);
1927  idsOfCuts.push_back(id);
1928  return true;
1929  }
1930  void finish(GModel *gm, FILE *f = nullptr)
1931  {
1932  for(size_t i = 0; i < ps.size(); i++) {
1933  GEdge *ge = gm->getEdgeByTag(indexOfCuts[i]);
1934  if(!ge) {
1935  ge = new discreteEdge(gm, indexOfCuts[i]);
1936  gm->add(ge);
1937  }
1938  MEdgeVertex *v =
1939  new MEdgeVertex(ps[i].x(), ps[i].y(), ps[i].z(), ge, 0.0);
1940  if(f)
1941  fprintf(f, "SP(%g,%g,%g){%d};\n", ps[i].x(), ps[i].y(), ps[i].z(),
1942  ge->tag());
1943  vs.push_back(v);
1944  ge->mesh_vertices.push_back(v);
1945  }
1946  }
1947  edgeCuts() {}
1948 };
1949 
1950 static bool addCut(const SPoint3 &p, const MEdge &e, int COUNT, int ID,
1951  std::map<MEdge, edgeCuts, MEdgeLessThan> &cuts)
1952 {
1953  auto itc = cuts.find(e);
1954  if(itc != cuts.end()) {
1955  if(!itc->second.add(p, COUNT, ID)) return false;
1956  return true;
1957  }
1958  else {
1959  edgeCuts cc;
1960  if(!cc.add(p, COUNT, ID)) return false;
1961  cuts[e] = cc;
1962  return true;
1963  }
1964 }
1965 
1966 static void computeOneIsoRecur(
1967  MVertex *vsing, v2t_cont &adj, double VAL, MVertex *v0, MVertex *v1,
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>,
1971  MEdgeLessThan> &cutGraphEnds,
1972  std::map<MEdge, MEdge, MEdgeLessThan> &d1, std::vector<groupOfCross2d> &G,
1973  FILE *f, int COUNT, std::map<MEdge, edgeCuts, MEdgeLessThan> &cuts, int &NB,
1974  int &circular)
1975 {
1976  MEdge e(v0, v1);
1977 
1978  MVertex vvv(p.x(), p.y(), p.z());
1979 
1980  if(distance(&vvv, vsing) < 1.e-10) {
1981  circular++;
1982  return;
1983  }
1984 
1985  bool added = addCut(p, e, COUNT, NB, cuts);
1986  if(!added) return;
1987 
1988  NB++;
1989 
1990  // visited[e] = NB;
1991 
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);
1998  }
1999  std::vector<MElement *> lst = adj[v0];
2000 
2001  MVertex *vs[2] = {nullptr, nullptr};
2002  int count = 0;
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);
2007  }
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);
2011  }
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);
2015  }
2016  }
2017 
2018  double U[2] = {pot[v0], pot[v1]};
2019  SPoint3 p0(v0->x(), v0->y(), v0->z());
2020  SPoint3 p1(v1->x(), v1->y(), v1->z());
2021  for(int i = 0; i < 2; i++) {
2022  if(vs[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);
2032  }
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);
2040  }
2041  else {
2042  printf("strange\n");
2043  }
2044  }
2045  }
2046  return;
2047 }
2048 
2049 static int computeOneIso(MVertex *vsing, v2t_cont &adj, double VAL, MVertex *v0,
2050  MVertex *v1, SPoint3 &p,
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)
2057 {
2058  std::map<MEdge, int, MEdgeLessThan> visited;
2059  std::map<MEdge, std::pair<std::map<MVertex *, double> *, double>,
2060  MEdgeLessThan>
2061  cutGraphEnds;
2062  int NB = 0;
2063  int circular = 0;
2064 
2065  computeOneIsoRecur(vsing, adj, VAL, v0, v1, p, *potU, visited, cutGraphEnds,
2066  d1, G, f, COUNT, cuts, NB, circular);
2067 
2068  int XX = 1;
2069  passages.clear();
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;
2074  double xi = coord1d((*POT)[e.getVertex(0)], (*POT)[e.getVertex(1)], VAL);
2075  MEdge o = d1[e];
2076  p[0] = (1. - xi) * e.getVertex(0)->x() + xi * e.getVertex(1)->x();
2077  p[1] = (1. - xi) * e.getVertex(0)->y() + xi * e.getVertex(1)->y();
2078  p[2] = (1. - xi) * e.getVertex(0)->z() + xi * e.getVertex(1)->z();
2079  // printf("cutgaphends %lu
2080  // %lu\n",o.getVertex(0)->getNum(),o.getVertex(1)->getNum()); printf("%lu
2081  // ends to the cutgraph\n",cutGraphEnds.size());
2082  cutGraphEnds.erase(cutGraphEnds.begin());
2083  // visited.clear();
2084 
2085  int ROT = 0;
2086  int maxCount = 0;
2087  int cutGraphId = -1;
2088  for(size_t i = 0; i < G.size(); i++) {
2089  int count = 0;
2090  count += (std::find(G[i].left.begin(), G[i].left.end(), o.getVertex(0)) !=
2091  G[i].left.end() ?
2092  1 :
2093  0);
2094  count += (std::find(G[i].left.begin(), G[i].left.end(), o.getVertex(1)) !=
2095  G[i].left.end() ?
2096  1 :
2097  0);
2098  count += (std::find(G[i].right.begin(), G[i].right.end(),
2099  e.getVertex(0)) != G[i].right.end() ?
2100  1 :
2101  0);
2102  count += (std::find(G[i].right.begin(), G[i].right.end(),
2103  e.getVertex(1)) != G[i].right.end() ?
2104  1 :
2105  0);
2106  count += (std::find(G[i].left.begin(), G[i].left.end(), e.getVertex(0)) !=
2107  G[i].left.end() ?
2108  1 :
2109  0);
2110  count += (std::find(G[i].left.begin(), G[i].left.end(), e.getVertex(1)) !=
2111  G[i].left.end() ?
2112  1 :
2113  0);
2114  count += (std::find(G[i].right.begin(), G[i].right.end(),
2115  o.getVertex(0)) != G[i].right.end() ?
2116  1 :
2117  0);
2118  count += (std::find(G[i].right.begin(), G[i].right.end(),
2119  o.getVertex(1)) != G[i].right.end() ?
2120  1 :
2121  0);
2122  if(count > maxCount) {
2123  maxCount = count;
2124  ROT = fabs(G[i].mat[0][0]) > .6 ? 0 : 1;
2125  cutGraphId = i;
2126  }
2127  }
2128  if(maxCount == 0) printf("IMPOSSIBLE\n");
2129 
2130  int pot = POT == potU ? 0 : 1;
2131  // printf(" --> cutting cut graph %5d %5d\n",cutGraphId,
2132  // pot,passages.size());
2133  int count = 0;
2134  for(std::size_t k = 0; k < passages.size(); k++) {
2135  if(pot == passages[k]._uv && cutGraphId == passages[k]._id) count++;
2136  }
2137 
2138  if(count > 20) {
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);
2142  printf("\n");
2143  return -1;
2144  }
2145 
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));
2149  }
2150 
2151  if(ROT) { POT = (POT == potU ? potV : potU); }
2152  else {
2153  }
2154  XX += ROT;
2155  // printf("XX = %d ROT = %d %lu\n",XX,ROT,cutGraphEnds.size());
2156  if(distance(e.getVertex(0), o.getVertex(0)) < 1.e-12)
2157  VAL = (1. - xi) * (*POT)[o.getVertex(0)] + xi * (*POT)[o.getVertex(1)];
2158  else
2159  VAL = (1. - xi) * (*POT)[o.getVertex(1)] + xi * (*POT)[o.getVertex(0)];
2160  computeOneIsoRecur(vsing, adj, VAL, o.getVertex(0), o.getVertex(1), p, *POT,
2161  visited, cutGraphEnds, d1, G, f, COUNT, cuts, NB,
2162  circular);
2163  if(XX > 1200) break;
2164  }
2165  return circular;
2166 }
2167 
2168 static bool computeIso(MVertex *vsing, v2t_cont &adj, double u,
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)
2175 {
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++) {
2179  MVertex *v0 = faces[i]->getVertex(0);
2180  MVertex *v1 = faces[i]->getVertex(1);
2181  MVertex *v2 = faces[i]->getVertex(2);
2182  double U0 = potU[v0];
2183  double U1 = potU[v1];
2184  double U2 = potU[v2];
2185  SPoint3 p0(v0->x(), v0->y(), v0->z());
2186  SPoint3 p1(v1->x(), v1->y(), v1->z());
2187  SPoint3 p2(v2->x(), v2->y(), v2->z());
2188  int circular = 0;
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);
2194  }
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);
2200  }
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);
2206  }
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);
2210  return false;
2211  }
2212  }
2213  return true;
2214 }
2215 
2216 static bool computeIsos(
2217  GModel *gm, std::vector<GFace *> &faces,
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)
2228 {
2229  v2t_cont adj;
2230  for(size_t i = 0; i < faces.size(); i++) {
2231  buildVertexToElement(faces[i]->triangles, adj);
2232  }
2233 
2234  {
2235  auto it = new2old.begin();
2236  for(; it != new2old.end(); ++it) {
2237  if(singularities.find(it->second) != singularities.end()) {
2238  singularities.insert(it->first);
2239  }
2240  }
2241  }
2242 
2243  std::map<MVertex *, MVertex *, MVertexPtrLessThan> duplicates;
2244  {
2245  auto it = new2old.begin();
2246  for(; it != new2old.end(); ++it) {
2247  duplicates[it->first] = it->second;
2248  duplicates[it->second] = it->first;
2249  }
2250  }
2251 
2252  std::map<MEdge, MEdge, MEdgeLessThan> d1;
2253  {
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);
2259  int J = -1, I = -1;
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; }
2263  }
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]);
2267  d1[l] = r;
2268  d1[r] = l;
2269  }
2270  }
2271  }
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]);
2275  d1[l] = r;
2276  d1[r] = l;
2277  }
2278  }
2279  }
2280  std::string fn = gm->getName() + "_QLayoutResults.pos";
2281  FILE *f = fopen(fn.c_str(), "w");
2282  fprintf(f, "View\"Big Cut\"{\n");
2283 
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,
2291  cuts, passages);
2292  if(!success) {
2293  printf("CYCLIC STUFF\n");
2294  // return false;
2295  }
2296  success = computeIso(*it, adj, potV[*it], potV, potU, f, d1, G, 1, cuts,
2297  passages);
2298  if(!success) {
2299  printf("CYCLIC STUFF\n");
2300  // return false;
2301  }
2302  }
2303  }
2304  fprintf(f, "};\n");
2305  fclose(f);
2306  return true;
2307 }
2308 
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)
2314 {
2315  std::set<cross2d *> touched;
2316 
2317  // printf("group %lu isolated singularities\n",
2318  // isolated_singularities.size());
2319 
2320  for(size_t i = 0; i < group.size(); i++) {
2321  if(isolated_singularities.find(group[i]->_e.getVertex(0)) ==
2322  isolated_singularities.end())
2323  all.insert(group[i]->_e.getVertex(0));
2324  if(isolated_singularities.find(group[i]->_e.getVertex(1)) ==
2325  isolated_singularities.end())
2326  all.insert(group[i]->_e.getVertex(1));
2327  }
2328 
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];
2335  else
2336  printf("error\n");
2337  }
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];
2346  else
2347  printf("error\n");
2348  }
2349  else {
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];
2360  else
2361  printf("error\n");
2362  }
2363 
2364  std::stack<cross2d *> _s;
2365  _s.push(start);
2366 
2367  while(!_s.empty()) {
2368  start = _s.top();
2369  touched.insert(start);
2370  _s.pop();
2371  for(size_t i = 0; i < start->_t.size(); i++) {
2372  t.insert(start->_t[i]);
2373  allTrianglesConsidered.insert(start->_t[i]);
2374  }
2375 
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()) {
2381  _s.push(c);
2382  }
2383  }
2384  }
2385  }
2386 }
2387 
2388 static bool computeLeftRight(groupOfCross2d &g, MVertex **left, MVertex **right)
2389 {
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) {
2393  MVertex *temp = *left;
2394  *left = *right;
2395  *right = temp;
2396  return true;
2397  }
2398  if(g.side[i]->getVertex(0) == *left || g.side[i]->getVertex(1) == *left ||
2399  g.side[i]->getVertex(2) == *left) {
2400  return true;
2401  }
2402  }
2403  return false;
2404 }
2405 
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)
2410 {
2411  std::set<MVertex *, MVertexPtrLessThan> touched;
2412 
2413  // printf("GROUP %d \n",g.groupId);
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++) {
2417  MVertex *vv = c->_e.getVertex(j);
2418  if(touched.find(vv) == touched.end()) {
2419  touched.insert(vv);
2420  MTriangle *t1 = c->_t[0];
2421  MTriangle *t2 = c->_t[1];
2422  MVertex *v0 = nullptr;
2423  MVertex *v1 = nullptr;
2424  if(t1->getVertex(0) == vv || t1->getVertex(1) == vv ||
2425  t1->getVertex(2) == vv) {
2426  if(v0 == nullptr)
2427  v0 = vv;
2428  else if(v1 == nullptr)
2429  v1 = vv;
2430  else
2431  Msg::Error("error in JumpyPairs 1");
2432  }
2433  if(t2->getVertex(0) == vv || t2->getVertex(1) == vv ||
2434  t2->getVertex(2) == vv) {
2435  if(v0 == nullptr)
2436  v0 = vv;
2437  else if(v1 == nullptr)
2438  v1 = vv;
2439  else
2440  Msg::Error("error in JumpyPairs 1");
2441  }
2442  for(auto it = old2new.lower_bound(vv); it != old2new.upper_bound(vv);
2443  ++it) {
2444  MVertex *vvv = it->second;
2445  if(t1->getVertex(0) == vvv || t1->getVertex(1) == vvv ||
2446  t1->getVertex(2) == vvv) {
2447  if(v0 == nullptr)
2448  v0 = vvv;
2449  else if(v1 == nullptr)
2450  v1 = vvv;
2451  else
2452  Msg::Error("error in JumpyPairs 1");
2453  }
2454  if(t2->getVertex(0) == vvv || t2->getVertex(1) == vvv ||
2455  t2->getVertex(2) == vvv) {
2456  if(v0 == nullptr)
2457  v0 = vvv;
2458  else if(v1 == nullptr)
2459  v1 = vvv;
2460  else
2461  Msg::Error("error in JumpyPairs 2");
2462  }
2463  }
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);
2469  }
2470  else {
2471  g.left.push_back(v0);
2472  g.right.push_back(v1);
2473  }
2474  }
2475  else
2476  Msg::Error("error in jumpy pairs %lu \n", vv->getNum());
2477  }
2478  else if(singularities.find(vv) != singularities.end()) {
2479  g.singularities.push_back(vv);
2480  }
2481  // else if (singularities.find(vv) == singularities.end()){
2482  // printf("ERROR --> no counterpart vertex in the cut graph\n");
2483  // }
2484  }
2485  }
2486  // printf("GRoup %d mat [%g,%g] [%g,%g] %lu nodes on each side \n"
2487  // ,g.groupId,g.mat[0][0],g.mat[0][1],g.mat[1][0],g.mat[1][1],
2488  // g.left.size());
2489 }
2490 
2491 static void
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)
2498 {
2499  g.crosses = group;
2500  double MAX = 0.0;
2501  for(size_t i = 0; i < g.crosses.size(); ++i) {
2502  cross2d *c = g.crosses[i];
2503  if(c->_t.size() == 2) {
2504  SVector3 t1 = d[c->_t[0]];
2505  SVector3 t2 = d[c->_t[1]];
2506  MAX = std::max(dot(t1, t2), MAX);
2507  }
2508  }
2509  if(MAX > .8)
2510  g.rot = false;
2511  else
2512  g.rot = true;
2513  for(size_t i = 0; i < g.crosses.size(); ++i) {
2514  cross2d *c = g.crosses[i];
2515  c->rotation = g.rot;
2516  }
2517 
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());
2524 
2525  // compute which rotation ...
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]]);
2534  }
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]]);
2540  }
2541  }
2542  }
2543  for(int j = 0; j < 2; j++) {
2544  for(int k = 0; k < 2; k++) {
2545  if(g.mat[j][k] > .7)
2546  g.mat[j][k] = 1;
2547  else if(g.mat[j][k] < -.7)
2548  g.mat[j][k] = -1;
2549  else
2550  g.mat[j][k] = 0;
2551  }
2552  }
2553 }
2554 
2556 class quadLayoutData {
2557 public:
2558  GModel *gm;
2559  std::vector<GFace *> f;
2560  std::map<MEdge, cross2d, MEdgeLessThan> C;
2561  dofManager<double> *myAssembler;
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;
2575 
2576  void printTheta(const char *name)
2577  {
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++) {
2583  MTriangle *t = f[i]->triangles[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));
2587 
2588  SVector3 d0 = it0->second.o_i;
2589  SVector3 d1 = it1->second.o_i;
2590  SVector3 d2 = it2->second.o_i;
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",
2604  t->getVertex(0)->x(), t->getVertex(0)->y(),
2605  t->getVertex(0)->z(), t->getVertex(1)->x(),
2606  t->getVertex(1)->y(), t->getVertex(1)->z(),
2607  t->getVertex(2)->x(), t->getVertex(2)->y(),
2608  t->getVertex(2)->z(), A, B, C);
2609  }
2610  }
2611  fprintf(of, "};\n");
2612  fclose(of);
2613  }
2614 
2615  void printCross(const char *name)
2616  {
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));
2628 
2629  for(size_t I = 0; I < it->second._t.size(); I++) {
2630  fprintf(of, "VP(%g,%g,%g){%g,%g,%g};\n",
2631  0.5 * (e0.getVertex(0)->x() + e0.getVertex(1)->x()),
2632  0.5 * (e0.getVertex(0)->y() + e0.getVertex(1)->y()),
2633  0.5 * (e0.getVertex(0)->z() + e0.getVertex(1)->z()), d1.x(),
2634  d1.y(), d1.z());
2635  fprintf(of, "VP(%g,%g,%g){%g,%g,%g};\n",
2636  0.5 * (e0.getVertex(0)->x() + e0.getVertex(1)->x()),
2637  0.5 * (e0.getVertex(0)->y() + e0.getVertex(1)->y()),
2638  0.5 * (e0.getVertex(0)->z() + e0.getVertex(1)->z()), d2.x(),
2639  d2.y(), d2.z());
2640  fprintf(of, "VP(%g,%g,%g){%g,%g,%g};\n",
2641  0.5 * (e0.getVertex(0)->x() + e0.getVertex(1)->x()),
2642  0.5 * (e0.getVertex(0)->y() + e0.getVertex(1)->y()),
2643  0.5 * (e0.getVertex(0)->z() + e0.getVertex(1)->z()), d3.x(),
2644  d3.y(), d3.z());
2645  fprintf(of, "VP(%g,%g,%g){%g,%g,%g};\n",
2646  0.5 * (e0.getVertex(0)->x() + e0.getVertex(1)->x()),
2647  0.5 * (e0.getVertex(0)->y() + e0.getVertex(1)->y()),
2648  0.5 * (e0.getVertex(0)->z() + e0.getVertex(1)->z()), d4.x(),
2649  d4.y(), d4.z());
2650  }
2651  }
2652  fprintf(of, "};\n");
2653  fclose(of);
2654  }
2655 
2656  int computeCrossFieldExtrinsic(double tol, size_t nIterLaplace = 2000)
2657  {
2658  std::vector<cross2d *> pc;
2659  for(auto it = C.begin(); it != C.end(); ++it) pc.push_back(&(it->second));
2660 
2661  size_t ITER = 0;
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);
2666  }
2667 
2668  for(size_t i = 0; i < pc.size(); i++) pc[i]->computeVector();
2669 
2670  fastImplementationExtrinsic(C, tol);
2671 
2672  for(size_t i = 0; i < pc.size(); i++) pc[i]->computeAngle();
2673 
2674  return 0;
2675  }
2676 
2677  void printScalar(dofManager<double> *dof, char c)
2678  {
2679  std::string fn = modelName + "_" + c + ".pos";
2680 
2681  FILE *_f = fopen(fn.c_str(), "w");
2682  fprintf(_f, "View \"H\"{\n");
2683 
2684  for(size_t i = 0; i < f.size(); i++) {
2685  for(size_t j = 0; j < f[i]->triangles.size(); j++) {
2686  MTriangle *t = f[i]->triangles[j];
2687  double a, b, c;
2688  dof->getDofValue(t->getVertex(0), 0, 1, a);
2689  dof->getDofValue(t->getVertex(1), 0, 1, b);
2690  dof->getDofValue(t->getVertex(2), 0, 1, c);
2691  fprintf(_f, "ST(%g,%g,%g,%g,%g,%g,%g,%g,%g){%g,%g,%g};\n",
2692  t->getVertex(0)->x(), t->getVertex(0)->y(),
2693  t->getVertex(0)->z(), t->getVertex(1)->x(),
2694  t->getVertex(1)->y(), t->getVertex(1)->z(),
2695  t->getVertex(2)->x(), t->getVertex(2)->y(),
2696  t->getVertex(2)->z(), a, b, c);
2697  }
2698  }
2699  fprintf(_f, "};\n");
2700  fclose(_f);
2701  }
2702 
2703  int computeCrossFieldAndH()
2704  {
2705  computeCrossFieldExtrinsic(1.e-9);
2706  myAssembler = computeH(gm, f, vs, C);
2707  // printScalar(myAssembler,'H');
2708  computeSingularities(C, singularities, indices, myAssembler);
2709  // print_H_and_Cross(gm, f, C, *myAssembler, singularities);
2710  return 1;
2711  }
2712 
2713  dofManager<double> *computeHFromSingularities(std::map<MVertex *, int> &sing,
2714  int nbTurns)
2715  {
2716 #if defined(HAVE_PETSC)
2718 #elif defined(HAVE_GMM)
2720 #else
2722 #endif
2723 
2724  dofManager<double> *dof = new dofManager<double>(_lsys);
2725 
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); }
2730  }
2731  std::vector<std::vector<MVertex *> > vsorted;
2732  SortEdgeConsecutive(edges, vsorted);
2733 
2734  // AVERAGE
2735  dof->numberVertex(*vs.begin(), 1, 1);
2736 
2737  for(auto it = vs.begin(); it != vs.end(); ++it) {
2738  dof->numberVertex(*it, 0, 1);
2739  }
2740 
2741  simpleFunction<double> ONE(1.0);
2742  laplaceTerm l(nullptr, 1, &ONE);
2743 
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]);
2748  // printf("--> %lu\n",e[0]->tag());
2749  for(size_t j = 0; j < f[i]->triangles.size(); j++) {
2750  MTriangle *t = f[i]->triangles[j];
2751  SElement se(t);
2752  l.addToMatrix(*dof, &se);
2753  }
2754  }
2755 
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());
2759  }
2760 
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; }
2764 
2765  for(size_t i = 0; i < vsorted[j].size(); ++i) {
2766  MVertex *vi = vsorted[j][i];
2767  MVertex *vip = vsorted[j][(i + 1) % vsorted[j].size()];
2768  MVertex *vim =
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());
2772  vv.normalize();
2773  ww.normalize();
2774  SVector3 xx = crossprod(vv, ww);
2775  double ccos = dot(vv, ww);
2776  double ANGLE = atan2(xx.norm(), ccos);
2777  xx.normalize();
2778 
2779  MEdge edze(vi, vim);
2780  auto itip = C.find(edze);
2781  double sign = 1;
2782  if(itip != C.end()) {
2783  MTriangle *tt = itip->second._t[0];
2784  MVertex *vrv;
2785  if(tt->getVertex(0) != vi && tt->getVertex(0) != vim) {
2786  vrv = tt->getVertex(0);
2787  }
2788  else if(tt->getVertex(1) != vi && tt->getVertex(1) != vim) {
2789  vrv = tt->getVertex(1);
2790  }
2791  else
2792  vrv = tt->getVertex(2);
2793  SVector3 aa(vrv->x() - vim->x(), vrv->y() - vim->y(),
2794  vrv->z() - vim->z());
2795  SVector3 zz = crossprod(aa, ww);
2796  zz.normalize();
2797  sign = -dot(zz, xx); // > 0 ? -1 : 1;
2798  // sign = dot(zz, xx) > 0 ? -1 : 1;
2799  }
2800  else
2801  printf("ARGH\n");
2802  // if (vsorted.size() == 1)sign = -1;
2803  CURVATURE[i] += ANGLE * sign;
2804  // printf("%12.5E\n",sign);
2805  }
2806 
2807  for(size_t i = 0; i < vsorted[j].size(); ++i) {
2808  Dof E(vsorted[j][i]->getNum(), Dof::createTypeWithTwoInts(0, 1));
2809  _lsys->addToRightHandSide(dof->getDofNumber(E), CURVATURE[i]);
2810  }
2811  }
2812 
2813  for(auto it = gaussianCurvatures.begin(); it != gaussianCurvatures.end();
2814  ++it) {
2815  Dof E(it->first->getNum(), Dof::createTypeWithTwoInts(0, 1));
2816  //_lsys->addToRightHandSide(dof->getDofNumber(E),-it->second);
2817  }
2818 
2819  for(auto it = sing.begin(); it != sing.end(); ++it) {
2820  Dof E(it->first->getNum(), Dof::createTypeWithTwoInts(0, 1));
2821  _lsys->addToRightHandSide(dof->getDofNumber(E),
2822  2.0 * M_PI * (double)it->second / nbTurns);
2823  }
2824 
2825  // FIX DE LA MORT
2826  // AVERAGE
2827  Dof EAVG((*vs.begin())->getNum(), Dof::createTypeWithTwoInts(1, 1));
2828 
2829  for(auto it = vs.begin(); it != vs.end(); ++it) {
2830  Dof E((*it)->getNum(), Dof::createTypeWithTwoInts(0, 1));
2831  dof->assemble(EAVG, E, 1);
2832  dof->assemble(E, EAVG, 1);
2833  }
2834 
2835  _lsys->systemSolve();
2836  return dof;
2837  }
2838 
2839  int computeHFromSingularities(std::map<MVertex *, int> &s)
2840  {
2841  myAssembler = computeHFromSingularities(s, 4);
2842  for(auto it = s.begin(); it != s.end(); ++it) {
2843  singularities.insert(it->first);
2844  }
2845  // printScalar(myAssembler, 'H');
2846  return 1;
2847  }
2848 
2849  //---------------------------------------------------------------------------
2850 
2851  void computeThetaUsingHCrouzeixRaviart(
2852  std::map<int, std::vector<double> > &dataTHETA)
2853  {
2854 #if defined(HAVE_PETSC)
2856 #elif defined(HAVE_GMM)
2858 #else
2860 #endif
2861  dofManager<double> *theta = new dofManager<double>(_lsys);
2862 
2863  std::map<MEdge, size_t, MEdgeLessThan> aaa;
2864  size_t count = 0;
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()) {
2869  Dof EdgeDof(count, Dof::createTypeWithTwoInts(0, 1));
2870  theta->numberDof(EdgeDof);
2871  aaa[f[i]->triangles[j]->getEdge(k)] = count++;
2872  }
2873  }
2874  }
2875  }
2876 
2877  for(size_t i = 0; i < f.size(); i++) {
2878  for(size_t j = 0; j < f[i]->triangles.size(); j++) {
2879  MTriangle *t = f[i]->triangles[j];
2880  double V = t->getVolume();
2881  double g1[3], g2[3], g3[3];
2882  double a[3];
2883  a[0] = 1;
2884  a[1] = 0;
2885  a[2] = 0;
2886  t->interpolateGrad(a, 0, 0, 0, g1);
2887  a[0] = 0;
2888  a[1] = 1;
2889  a[2] = 0;
2890  t->interpolateGrad(a, 0, 0, 0, g2);
2891  a[0] = 0;
2892  a[1] = 0;
2893  a[2] = 1;
2894  t->interpolateGrad(a, 0, 0, 0, g3);
2895  SVector3 G[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]);
2902  SVector3 v10(t->getVertex(1)->x() - t->getVertex(0)->x(),
2903  t->getVertex(1)->y() - t->getVertex(0)->y(),
2904  t->getVertex(1)->z() - t->getVertex(0)->z());
2905  SVector3 v20(t->getVertex(2)->x() - t->getVertex(0)->x(),
2906  t->getVertex(2)->y() - t->getVertex(0)->y(),
2907  t->getVertex(2)->z() - t->getVertex(0)->z());
2908  SVector3 xx = crossprod(v20, v10);
2909  xx.normalize();
2910 
2911  double H[3];
2912  for(int k = 0; k < 3; k++) {
2913  auto itk = new2old.find(t->getVertex(k));
2914  if(itk == new2old.end())
2915  myAssembler->getDofValue(t->getVertex(k), 0, 1, H[k]);
2916  else
2917  myAssembler->getDofValue(itk->second, 0, 1, H[k]);
2918  }
2919  double gradH[3];
2920  t->interpolateGrad(H, 0, 0, 0, gradH);
2921 
2922  SVector3 temp(gradH[0], gradH[1], gradH[2]);
2923  SVector3 gradHOrtho = crossprod(temp, xx);
2924 
2925  double RHS[3] = {dot(gradHOrtho, G[0]), dot(gradHOrtho, G[1]),
2926  dot(gradHOrtho, G[2])};
2927 
2928  for(size_t k = 0; k < 3; k++) {
2929  Dof Ek(aaa[t->getEdge(k)], Dof::createTypeWithTwoInts(0, 1));
2930  theta->assemble(Ek, RHS[k] * V);
2931  for(size_t l = 0; l < 3; l++) {
2932  Dof El(aaa[t->getEdge(l)], Dof::createTypeWithTwoInts(0, 1));
2933  theta->assemble(Ek, El, -dot(G[k], G[l]) * V);
2934  }
2935  }
2936  }
2937  }
2938 
2939  _lsys->systemSolve();
2940 
2941  double sum = 0;
2942  int count_ = 0;
2943 
2944  auto it = aaa.begin();
2945  for(; it != aaa.end(); ++it) {
2946  Dof d(it->second, Dof::createTypeWithTwoInts(0, 1));
2947  double t;
2948  theta->getDofValue(d, t);
2949  MVertex *v0, *v1;
2950  auto it0 = new2old.find(it->first.getVertex(0));
2951  if(it0 == new2old.end())
2952  v0 = it->first.getVertex(0);
2953  else
2954  v0 = it0->second;
2955  it0 = new2old.find(it->first.getVertex(1));
2956  if(it0 == new2old.end())
2957  v1 = it->first.getVertex(1);
2958  else
2959  v1 = it0->second;
2960  MEdge e(v0, v1);
2961  auto itc = C.find(e);
2962  // well... at first ...
2963  itc->second.o_i = SVector3(cos(t), sin(t), 0.0);
2964  // end well
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; }
2969  else {
2970  // printf("%12.5E %lu %lu\n",aa,
2971  // itc->second._e.getVertex(0)->getNum(),
2972  // itc->second._e.getVertex(1)->getNum());
2973  itc->second._a = 0;
2974  count_++;
2975  sum += aa;
2976  }
2977  }
2978 
2979  sum /= count_;
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);
2986  }
2987  }
2988 
2989  // printCross ("crossCR");
2990  {
2991  // std::string fn = modelName + "_"+"thetaCR.pos";
2992  // FILE *of = fopen(fn.c_str(), "w");
2993  // fprintf(of, "View \"Theta - Crouzeix Raviart\"{\n");
2994  for(size_t i = 0; i < f.size(); i++) {
2995  for(size_t j = 0; j < f[i]->triangles.size(); j++) {
2996  MTriangle *t = f[i]->triangles[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)],
3003  double a, b, c;
3004  theta->getDofValue(d0, a);
3005  theta->getDofValue(d1, b);
3006  theta->getDofValue(d2, c);
3007  double A = c + a - b;
3008  double B = a + b - c;
3009  double C = b + c - a;
3010  std::vector<double> ts;
3011  ts.push_back(A);
3012  ts.push_back(B);
3013  ts.push_back(C);
3014  dataTHETA[t->getNum()] = ts;
3015  /* fprintf(of, "ST(%g,%g,%g,%g,%g,%g,%g,%g,%g){%g,%g,%g};\n",
3016  t->getVertex(0)->x(), t->getVertex(0)->y(), t->getVertex(0)->z(),
3017  t->getVertex(1)->x(), t->getVertex(1)->y(), t->getVertex(1)->z(),
3018  t->getVertex(2)->x(), t->getVertex(2)->y(), t->getVertex(2)->z(),
3019  A,B,C);*/
3020  }
3021  }
3022  // fprintf(of, "};\n");
3023  // fclose(of);
3024  }
3025  }
3026  //---------------------------------------------------------------------------
3027 
3028  quadLayoutData(GModel *_gm, std::vector<GFace *> &_f, const std::string &name,
3029  bool includeFeatureEdges = true)
3030  : gm(_gm), f(_f), myAssembler(nullptr)
3031  {
3032  modelName = name;
3033  for(size_t i = 0; i < f.size(); i++) {
3034  for(size_t j = 0; j < f[i]->triangles.size(); j++) {
3035  MTriangle *t = f[i]->triangles[j];
3036  for(size_t k = 0; k < 3; k++) {
3037  vs.insert(t->getVertex(k));
3038  MEdge e = t->getEdge(k);
3039  MEdge e1 = t->getEdge((k + 1) % 3);
3040  MEdge e2 = t->getEdge((k + 2) % 3);
3041 
3042  // Gaussian Curvatures
3043  MVertex *vk = t->getVertex(k);
3044  MVertex *vk1 = t->getVertex((k + 1) % 3);
3045  MVertex *vk2 = t->getVertex((k + 2) % 3);
3046  SVector3 v1(vk1->x() - vk->x(), vk1->y() - vk->y(),
3047  vk1->z() - vk->z());
3048  SVector3 v2(vk2->x() - vk->x(), vk2->y() - vk->y(),
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;
3054  else
3055  itg->second -= CURV;
3056  //---------------------------------------------------------------------
3057 
3058  cross2d c(e, t, e1, e2);
3059  auto it = C.find(e);
3060  if(it == C.end())
3061  C.insert(std::make_pair(e, c));
3062  else {
3063  it->second._t.push_back(t);
3064  it->second._neighbors.push_back(e1);
3065  it->second._neighbors.push_back(e2);
3066  }
3067  }
3068  }
3069  }
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];
3076  MEdge e = l->getEdge(0);
3077  auto it = C.find(e);
3078  if(it != C.end()) { it->second.inBoundary = true; }
3079  }
3080  }
3081  }
3082  }
3083  auto it = C.begin();
3084  for(; it != C.end(); ++it) it->second.finish(C);
3085  it = C.begin();
3086  for(; it != C.end(); ++it) it->second.finish2();
3087  FILE *F = fopen("gc.pos", "w");
3088  fprintf(F, "View\"\"{\n");
3089  double dd = 0;
3090  for(auto it = gaussianCurvatures.begin(); it != gaussianCurvatures.end();
3091  ++it) {
3092  fprintf(F, "SP(%g,%g,%g){%g};\n", it->first->x(), it->first->y(),
3093  it->first->z(), it->second);
3094  dd += it->second;
3095  }
3096  printf("%22.15E %22.15E\n", dd, dd - 4 * M_PI);
3097  fprintf(F, "};\n");
3098  fclose(F);
3099  }
3100 
3101  void restoreInitialMesh()
3102  {
3103  unDuplicateNodesInCutGraph(f, new2old);
3104  G.clear();
3105  groups.clear();
3106  groups_cg.clear();
3107  cutG.clear();
3108  new2old.clear();
3109  // boundaries.clear();
3110  auto it = C.begin();
3111  for(; it != C.end(); ++it) {
3112  it->second.inCutGraph = false;
3113  it->second._btemp = 0;
3114  }
3115  }
3116 
3117  int computeUniqueVectorsPerTriangle()
3118  {
3119  // LIFTING
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,
3126  visited);
3127  break;
3128  }
3129  }
3130  }
3131  computeUniqueVectorPerTriangle(gm, f, C, 0, d0);
3132  computeUniqueVectorPerTriangle(gm, f, C, 1, d1);
3133  return 0;
3134  }
3135 
3136  int computeCutGraph(std::map<MEdge, MEdge, MEdgeLessThan> &duplicateEdges)
3137  {
3138  // COMPUTING CUT GRAPH
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;
3143  }
3144 
3145  groupBoundaries(gm, C, groups, singularities, corners, false);
3146  groupBoundaries(gm, C, groups_cg, singularities, corners, true);
3147 
3148  v2t_cont adj;
3149  for(size_t i = 0; i < f.size(); i++) {
3150  buildVertexToElement(f[i]->triangles, adj);
3151  }
3152 
3153  std::string fn = modelName + "_groups_analyzed.pos";
3154  FILE *_f = fopen(fn.c_str(), "w");
3155  fprintf(_f, "View \"groups\"{\n");
3156 
3157  std::set<MVertex *, MVertexPtrLessThan> isolated_singularities;
3158  {
3159  for(auto it = singularities.begin(); it != singularities.end(); ++it) {
3160  int count = 0;
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++;
3166  }
3167  }
3168  }
3169  if(count == 1) { isolated_singularities.insert(*it); }
3170  else {
3171  isolated_singularities.insert(*it);
3172  }
3173  }
3174  }
3175 
3176  d0.clear();
3177  d1.clear();
3178  computeUniqueVectorsPerTriangle();
3179 
3180  // analyzing groups
3181  {
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);
3187  g.print(_f);
3188  G.push_back(g);
3189  }
3190  }
3191  fprintf(_f, "};\n");
3192  fclose(_f);
3193 
3194  std::multimap<MVertex *, MVertex *, MVertexPtrLessThan> old2new;
3195  duplicateNodesInCutGraph(f, C, new2old, old2new, duplicateEdges,
3196  singularities, adj, G);
3197 
3198  for(size_t i = 0; i < groups_cg.size(); i++) {
3199  createJumpyPairs(G[i], singularities, boundaries, old2new);
3200  }
3201  return 0;
3202  }
3203 
3204  int computeCrossFieldAndH(std::map<MVertex *, int> *s,
3205  std::map<int, std::vector<double> > &dataTHETA)
3206  {
3207  double a = TimeOfDay();
3208  computeHFromSingularities(*s);
3209  double b = TimeOfDay();
3210  Msg::Info("Real part H (nodal) has been computed in %4g sec", b - a);
3211 
3212  std::map<MEdge, MEdge, MEdgeLessThan> duplicateEdges;
3213 
3214  double c = TimeOfDay();
3215  computeCutGraph(duplicateEdges);
3216  Msg::Info("Cut Graph has been computed in %4g sec", c - b);
3217 
3218  double d = TimeOfDay();
3219  computeThetaUsingHCrouzeixRaviart(dataTHETA);
3220  Msg::Info("Imaginary part H (crouzeix raviart/multi-valued) has been "
3221  "computed in %4g sec",
3222  d - c);
3223  restoreInitialMesh();
3224  return 0;
3225  }
3226 
3227  MVertex *intersectEdgeEdge(MEdge &e, MVertex *v1, MVertex *v2, GFace *gf)
3228  {
3229  MVertex *e1 = e.getVertex(0);
3230  MVertex *e2 = e.getVertex(1);
3231 
3232  if(e1 == v2) return nullptr;
3233  if(e2 == v2) return nullptr;
3234 
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());
3238 
3239  SVector3 a = crossprod(e1e2, e1v1);
3240  double b = dot(e1v1, e2v1);
3241  if(a.norm() < 1.e-10 && b < 0) return v1;
3242 
3243  if(!v2) {
3244  // Msg::Error("Error In CutMesh");
3245  return nullptr;
3246  }
3247 
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());
3250  a = crossprod(e1e2, e1v2);
3251  b = dot(e1v2, e2v2);
3252  if(a.norm() < 1.e-10 && b < 0) return v2;
3253 
3254  double x[2];
3255 
3256  bool inters = intersection_segments(
3257  SPoint3(e.getVertex(0)->x(), e.getVertex(0)->y(), e.getVertex(0)->z()),
3258  SPoint3(e.getVertex(1)->x(), e.getVertex(1)->y(), e.getVertex(1)->z()),
3259  SPoint3(v1->x(), v1->y(), v1->z()), SPoint3(v2->x(), v2->y(), v2->z()),
3260  x);
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);
3265  }
3266 
3267  void cut_edge(std::map<MEdge, int, MEdgeLessThan> &ecuts, MVertex *v0,
3268  MVertex *v1, MVertex *mid)
3269  {
3270  MEdge e(v0, v1);
3271  auto it = ecuts.find(e);
3272  if(it != ecuts.end()) {
3273  int index = it->second;
3274  ecuts.erase(it);
3275  MEdge e1(v0, mid);
3276  MEdge e2(mid, v1);
3277  ecuts[e1] = index;
3278  ecuts[e2] = index;
3279  }
3280  }
3281 
3282  void cutTriangles(std::vector<MTriangle *> &ts, GFace *gf, MVertex *v1,
3283  MVertex *v2, GEdge *ge,
3284  std::map<MEdge, int, MEdgeLessThan> &ecuts, int index,
3285  FILE *f)
3286  {
3287  std::map<MEdge, MVertex *, MEdgeLessThan> e_cut;
3288  std::vector<MTriangle *> newt;
3289 
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) {
3297  gf->mesh_vertices.push_back(v);
3298  if(f)
3299  fprintf(f, "SP(%g,%g,%g){%d};\n", v->x(), v->y(), v->z(),
3300  gf->tag());
3301  }
3302  e_cut[e] = v;
3303  }
3304  vs[j] = e_cut[e];
3305  }
3306 
3307  if(!vs[0] && !vs[1] && !vs[2])
3308  newt.push_back(ts[i]);
3309  else if(vs[0] && !vs[1] && !vs[2]) {
3310  // printf("\n");
3311  newt.push_back(
3312  new MTriangle(ts[i]->getVertex(0), vs[0], ts[i]->getVertex(2)));
3313  newt.push_back(
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]);
3317  ecuts[ed] = index;
3318  }
3319  else if(!vs[0] && vs[1] && !vs[2]) {
3320  // printf("coucouc\n");
3321  newt.push_back(
3322  new MTriangle(ts[i]->getVertex(0), ts[i]->getVertex(1), vs[1]));
3323  newt.push_back(
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]);
3327  ecuts[ed] = index;
3328  }
3329  else if(!vs[0] && !vs[1] && vs[2]) {
3330  // printf("coucouc\n");
3331  newt.push_back(
3332  new MTriangle(ts[i]->getVertex(0), ts[i]->getVertex(1), vs[2]));
3333  newt.push_back(
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]);
3337  ecuts[ed] = index;
3338  }
3339  else if(vs[0] && vs[1] && !vs[2]) { // OK
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]));
3342  newt.push_back(
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]);
3347  ecuts[ed] = index;
3348  }
3349  else if(vs[0] && !vs[1] && vs[2]) { // OK
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]));
3352  newt.push_back(
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]);
3357  ecuts[ed] = index;
3358  }
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]));
3362  newt.push_back(
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]);
3367  ecuts[ed] = index;
3368  }
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]));
3374  }
3375  else {
3376  newt.push_back(ts[i]);
3377  }
3378  }
3379  // printf("replcing %lu by %lu\n",ts.size(),newt.size());
3380  ts = newt;
3381  }
3382 
3383  void cutMesh(std::map<MEdge, edgeCuts, MEdgeLessThan> &cuts)
3384  {
3385  auto it = cuts.begin();
3386  std::map<MEdge, int, MEdgeLessThan> ecuts;
3387 
3388  FILE *F = fopen("addedpoints.pos", "w");
3389  fprintf(F, "View \"\"{\n");
3390  for(; it != cuts.end(); ++it) { it->second.finish(gm, F); }
3391 
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;
3397 
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 =
3404  std::make_pair(
3405  it->second.indexOfCuts[l],
3406  std::make_pair(it->second.vs[l],
3407  std::make_pair(k, it->second.idsOfCuts[l])));
3408  tcuts.insert(pp);
3409  indices.insert(it->second.indexOfCuts[l]);
3410  }
3411  }
3412  }
3413 
3414  auto iti = indices.begin();
3415  std::vector<MTriangle *> ttt;
3416  ttt.push_back(f[i]->triangles[j]);
3417  for(; iti != indices.end(); ++iti) {
3418  // if (*iti != 313310)continue;
3419  GEdge *ge = gm->getEdgeByTag(*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,
3426  *iti, F);
3427  }
3428  else if(tcuts.count(*iti) == 2) {
3429  auto itt = tcuts.lower_bound(*iti);
3430  MVertex *v0 = itt->second.first;
3431  ++itt;
3432  MVertex *v1 = itt->second.first;
3433  cutTriangles(ttt, f[i], v0, v1, ge, ecuts, *iti, F);
3434  }
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;
3440  ++itt;
3441  int k1 = itt->second.second.first;
3442  int id1 = itt->second.second.second;
3443  MVertex *v1 = itt->second.first;
3444  ++itt;
3445  int k2 = itt->second.second.first;
3446  int id2 = itt->second.second.second;
3447  MVertex *v2 = itt->second.first;
3448  ;
3449 
3450  if(abs(id0 - id1) <= 2) {
3451  cutTriangles(ttt, f[i], v2,
3452  f[i]->triangles[j]->getVertex((k2 + 2) % 3), ge,
3453  ecuts, *iti, F);
3454  cutTriangles(ttt, f[i], v0, v1, ge, ecuts, *iti, F);
3455  }
3456  else if(abs(id0 - id2) <= 2) {
3457  cutTriangles(ttt, f[i], v1,
3458  f[i]->triangles[j]->getVertex((k1 + 2) % 3), ge,
3459  ecuts, *iti, F);
3460  cutTriangles(ttt, f[i], v0, v2, ge, ecuts, *iti, F);
3461  }
3462  else if(abs(id1 - id2) <= 2) {
3463  cutTriangles(ttt, f[i], v0,
3464  f[i]->triangles[j]->getVertex((k0 + 2) % 3), ge,
3465  ecuts, *iti, F);
3466  cutTriangles(ttt, f[i], v1, v2, ge, ecuts, *iti, F);
3467  }
3468  else {
3469  printf("BAD BEHAVIOR 3\n");
3470  printf("%lu %lu %lu \n", v0->getNum(), v1->getNum(),
3471  v2->getNum());
3472  printf("%d %d %d\n", id0, id1, id2);
3473  }
3474  }
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;
3479  ++itt;
3480  int id1 = itt->second.second.second;
3481  MVertex *v1 = itt->second.first;
3482  ++itt;
3483  int id2 = itt->second.second.second;
3484  MVertex *v2 = itt->second.first;
3485  ++itt;
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);
3491  }
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);
3495  }
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);
3499  }
3500  else {
3501  printf("%d %d %d %d\n", id0, id1, id2, id3);
3502  }
3503  }
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++) {
3508  id[kk] =
3509  std::make_pair(itt->second.second.second, itt->second.first);
3510  ++itt;
3511  }
3512  std::sort(id, id + 6);
3513  cutTriangles(ttt, f[i], id[0].second, id[1].second, ge, ecuts, *iti,
3514  F);
3515  cutTriangles(ttt, f[i], id[2].second, id[3].second, ge, ecuts, *iti,
3516  F);
3517  cutTriangles(ttt, f[i], id[4].second, id[5].second, ge, ecuts, *iti,
3518  F);
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);
3521  }
3522  else {
3523  Msg::Error("TODO %lu in CutMesh !!!!!!!", tcuts.count(*iti));
3524  }
3525  }
3526  newT.insert(newT.begin(), ttt.begin(), ttt.end());
3527  }
3528  f[i]->triangles = newT;
3529  }
3530 
3531  fprintf(F, "};\n");
3532  fclose(F);
3533 
3534  F = fopen("edges.pos", "w");
3535  fprintf(F, "View \"\"{\n");
3536 
3537  for(auto it = ecuts.begin(); it != ecuts.end(); ++it) {
3538  GEdge *ge = gm->getEdgeByTag(it->second);
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++) {
3546  if(std::find(ge->mesh_vertices.begin(), ge->mesh_vertices.end(),
3547  it->first.getVertex(i)) == ge->mesh_vertices.end()) {
3548  ge->mesh_vertices.push_back(it->first.getVertex(i));
3549  it->first.getVertex(i)->setEntity(ge);
3550  }
3551  }
3552  }
3553  fprintf(F, "};\n");
3554  fclose(F);
3556  }
3557 
3558  int correctionOnCutGraph(
3559  std::map<MEdge, edgeCuts, MEdgeLessThan> &cuts,
3560  std::map<MVertex *, MVertex *, MVertexPtrLessThan> &new2old)
3561  {
3562  std::map<MEdge, MEdge, MEdgeLessThan> duplicateEdges;
3563 
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];
3569  MEdge e0(v0, v1);
3570  MEdge e1(v2, v3);
3571  duplicateEdges[e0] = e1;
3572  }
3573 
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;
3579  }
3580  else if(it4 != cuts.end() && it3 == cuts.end()) {
3581  cuts[it2->first] = it4->second;
3582  }
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());
3594  }
3595  }
3596  return 0;
3597  }
3598 
3599  int computeQuadLayout(std::map<MVertex *, double> &potU,
3600  std::map<MVertex *, double> &potV,
3601  std::map<MEdge, MEdge, MEdgeLessThan> &duplicateEdges,
3602  std::map<MEdge, edgeCuts, MEdgeLessThan> &cuts)
3603  {
3604  std::vector<cutGraphPassage> passages;
3605  while(1) {
3606  computePotential(gm, f, *myAssembler, C, new2old, groups, duplicateEdges,
3607  d0, d1, G, potU, potV, passages);
3608 
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");
3612  break;
3613  }
3614  break;
3615  }
3616 
3617  correctionOnCutGraph(cuts, new2old);
3618 
3619  double MAXX = 0.;
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);
3633  }
3634 
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],
3637  G[i].mat[1][1]);
3638 
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,
3641  MAXD2 - MIND2);
3642  MAXX = std::max(MAXD2 - MIND2, MAXX);
3643  }
3644  if(MAXX < 1.e-09)
3645  Msg::Info("Success in computing potentials (all jumps are OK)");
3646  else
3647  Msg::Warning("Quad Layout Failure");
3648  return 0;
3649  }
3650 };
3651 
3652 static void findPhysicalGroupsForSingularities(GModel *gm,
3653  std::vector<GFace *> &f,
3654  std::map<MVertex *, int> &temp)
3655 {
3656  std::map<int, std::vector<GEntity *> > groups[4];
3657  gm->getPhysicalGroups(groups);
3658  for(auto it = groups[0].begin(); it != groups[0].end(); ++it) {
3659  std::string name = gm->getPhysicalName(0, it->first);
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;
3664  }
3665  }
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;
3670  }
3671  }
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;
3676  }
3677  }
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;
3682  }
3683  }
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;
3688  }
3689  }
3690  }
3691 }
3692 
3693 static int computeCrossFieldAndH(GModel *gm, std::vector<GFace *> &f,
3694  std::vector<int> &tags, bool layout = true)
3695 {
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;
3708  if(temp.size()) {
3709  Msg::Info("Computing cross field from %d prescribed singularities",
3710  temp.size());
3711  qLayout.computeCrossFieldAndH(&temp, dataTHETA);
3712  qLayout.computeCutGraph(duplicateEdges);
3713  }
3714  else {
3715  Msg::Info("Computing a cross field");
3716  qLayout.computeCrossFieldAndH();
3717  qLayout.computeCutGraph(duplicateEdges);
3718  qLayout.computeThetaUsingHCrouzeixRaviart(dataTHETA);
3719  }
3720  if(layout) { qLayout.computeQuadLayout(potU, potV, duplicateEdges, cuts); }
3721 
3725  std::string name = gm->getName() + "_H";
3726  d->setName(name);
3727  d->setFileName(name + ".msh");
3728  name = gm->getName() + "_Theta";
3729  dt->setName(name);
3730  dt->setFileName(name + ".msh");
3731  name = gm->getName() + "_Directions";
3732  dd->setName(name);
3733  dd->setFileName(name + ".msh");
3734  PViewDataGModel *U = nullptr;
3735  PViewDataGModel *V = nullptr;
3736  if(layout) {
3739  name = gm->getName() + "_U";
3740  U->setName(name);
3741  U->setFileName(name + ".msh");
3742  name = gm->getName() + "_V";
3743  V->setName(name);
3744  V->setFileName(name + ".msh");
3745 
3746  for(size_t i = 0; i < f.size(); i++) {
3747  for(size_t j = 0; j < f[i]->triangles.size(); j++) {
3748  MTriangle *t = f[i]->triangles[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;
3753  ts.push_back(a);
3754  ts.push_back(b);
3755  ts.push_back(c);
3756  dataU[t->getNum()] = 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)];
3760  ts.clear();
3761  ts.push_back(a);
3762  ts.push_back(b);
3763  ts.push_back(c);
3764  dataV[t->getNum()] = ts;
3765  }
3766  }
3767 
3768  U->addData(gm, dataU, 0, 0.0, 1, 1);
3769  U->finalize();
3770  V->addData(gm, dataV, 0, 0.0, 1, 1);
3771  V->finalize();
3772  }
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;
3779  }
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;
3786  }
3787  for(auto it = qLayout.vs.begin(); it != qLayout.vs.end(); ++it) {
3788  double h;
3789  qLayout.myAssembler->getDofValue(*it, 0, 1, h);
3790  std::vector<double> jj;
3791  jj.push_back(h);
3792  // printf("adding data for %lu\n",(*it)->getNum());
3793  dataH[(*it)->getNum()] = jj;
3794  }
3795 
3796  d->addData(gm, dataH, 0, 0.0, 1, 1);
3797  d->finalize();
3798  dt->addData(gm, dataTHETA, 0, 0.0, 1, 1);
3799  dt->finalize();
3800  dd->addData(gm, dataDir, 0, 0.0, 1, 3);
3801  dd->addData(gm, dataDirOrtho, 1, 0.0, 1, 3);
3802  dd->finalize();
3803 
3804  std::string posout = gm->getName() + "_QLayoutResults.pos";
3805 
3806  qLayout.restoreInitialMesh();
3807  dt->writePOS(posout, false, true, true);
3808  dd->writePOS(posout, false, true, true);
3809  d->writePOS(posout, false, true, true);
3810  if(layout) {
3811  U->writePOS(posout, false, true, true);
3812  V->writePOS(posout, false, true, true);
3813  }
3814  // return 0;
3815  Msg::Info("Cutting the mesh");
3816 
3817  qLayout.cutMesh(cuts);
3818 
3819  Msg::Info("Classifying the model");
3820  discreteEdge *de = new discreteEdge(
3821  GModel::current(), GModel::current()->getMaxElementaryNumber(1) + 1,
3822  nullptr, nullptr);
3823  GModel::current()->add(de);
3825  classifyFaces(GModel::current(), M_PI / 4 * .999);
3826  GModel::current()->remove(de);
3827  // delete de;
3829 
3830  std::string mshout = gm->getName() + "_Cut.msh";
3831  gm->writeMSH(mshout, 4.0, false, true);
3832 
3833  int countError = 0;
3834  for(auto it = GModel::current()->firstFace();
3835  it != GModel::current()->lastFace(); it++) {
3836  if((*it)->edges().size() != 4) {
3837  Msg::Warning("quad layout failed : face %lu has %lu boundaries",
3838  (*it)->tag(), (*it)->edges().size());
3839  countError++;
3840  }
3841  }
3842  if(!countError) {
3843  Msg::Info(
3844  "Quad layout success : the model is partitioned in %d master quads",
3845  GModel::current()->getNumFaces());
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());
3848  }
3849  delete d;
3850  delete dd;
3851  delete dt;
3852  if(layout) {
3853  delete U;
3854  delete V;
3855  }
3856 
3857  return 0;
3858 }
3859 
3860 #endif
3861 
3862 static void getFacesOfTheModel(GModel *gm, std::vector<GFace *> &f)
3863 {
3864  for(auto it = gm->firstFace(); it != gm->lastFace(); ++it) {
3865  GFace *gf = *it;
3866  f.push_back(gf);
3867  }
3868 }
3869 
3870 int computeCrossFieldAndH(GModel *gm, std::vector<int> &tags)
3871 {
3872  std::vector<GFace *> f;
3873  getFacesOfTheModel(gm, f);
3874 #if defined(HAVE_SOLVER) && defined(HAVE_POST)
3875  return computeCrossFieldAndH(gm, f, tags);
3876 #else
3877  Msg::Error("Cross field computation requires solver and post-pro module");
3878  return -1;
3879 #endif
3880 }
3881 
3882 int computeQuadLayout(GModel *gm, std::vector<int> &tags)
3883 {
3884  std::vector<GFace *> f;
3885  getFacesOfTheModel(gm, f);
3886 
3887 #if defined(HAVE_SOLVER) && defined(HAVE_POST)
3888  return computeCrossFieldAndH(gm, f, tags, true);
3889 #else
3890  Msg::Error("Cross field computation requires solver and post-pro module");
3891  return -1;
3892 #endif
3893 }
3894 
3895 int computeCrossField(GModel *gm, std::vector<int> &tags)
3896 {
3897  std::vector<GFace *> f;
3898  getFacesOfTheModel(gm, f);
3899 
3900 #if defined(HAVE_SOLVER) && defined(HAVE_POST)
3901  return computeCrossFieldAndH(gm, f, tags, true);
3902  // return computeQuadLayout(gm, f);
3903 #else
3904  Msg::Error("Cross field computation requires solver and post-pro module");
3905  return -1;
3906 #endif
3907 }
MElement::getNum
virtual std::size_t getNum() const
Definition: MElement.h:68
buildVertexToElement
void buildVertexToElement(std::vector< T * > const &elements, v2t_cont &adj)
Definition: meshGFaceOptimize.h:38
crossprod
SVector3 crossprod(const SVector3 &a, const SVector3 &b)
Definition: SVector3.h:150
D
#define D
Definition: DefaultOptions.h:24
MTriangle.h
TimeOfDay
double TimeOfDay()
Definition: OS.cpp:399
tags
static std::map< SPoint2, unsigned int > tags
Definition: drawGraph2d.cpp:400
MVertexPtrLessThan
Definition: MVertex.h:218
linearSystemFull
Definition: linearSystemFull.h:17
PViewDataGModel::ElementData
@ ElementData
Definition: PViewDataGModel.h:195
computeCrossField
int computeCrossField(GModel *gm, std::vector< int > &tags)
Definition: gmshCrossFields.cpp:3895
MEdge
Definition: MEdge.h:14
dot
double dot(const SVector3 &a, const SMetric3 &m, const SVector3 &b)
Definition: STensor3.h:71
PViewDataGModel
Definition: PViewDataGModel.h:191
GFace.h
distance
double distance(MVertex *v1, MVertex *v2)
Definition: MVertex.h:245
linearSystemPETSc
Definition: linearSystemPETSc.h:150
GFace
Definition: GFace.h:33
Msg::Info
static void Info(const char *fmt,...)
Definition: GmshMessage.cpp:587
GEdge::lines
std::vector< MLine * > lines
Definition: GEdge.h:42
F
#define F
Definition: DefaultOptions.h:23
angle
double angle(const SVector3 &a, const SVector3 &b)
Definition: SVector3.h:157
gmshCrossFields.h
OS.h
MAX
#define MAX(a, b)
Definition: libol1.c:81
Msg::Debug
static void Debug(const char *fmt,...)
Definition: GmshMessage.cpp:752
c
static double c(int i, int j, fullMatrix< double > &CA, const std::vector< SPoint3 > &P, const std::vector< SPoint3 > &Q)
Definition: discreteFrechetDistance.cpp:15
discreteEdge
Definition: discreteEdge.h:12
MVertex
Definition: MVertex.h:24
GModel::remove
bool remove(GRegion *r)
Definition: GModel.cpp:435
GModel::getName
std::string getName() const
Definition: GModel.h:329
Msg::Warning
static void Warning(const char *fmt,...)
Definition: GmshMessage.cpp:543
Msg::Error
static void Error(const char *fmt,...)
Definition: GmshMessage.cpp:482
MVertex::z
double z() const
Definition: MVertex.h:62
robin_hood::operator<
constexpr bool operator<(pair< A, B > const &x, pair< A, B > const &y) noexcept(noexcept(std::declval< A const & >()< std::declval< A const & >()) &&noexcept(std::declval< B const & >()< std::declval< B const & >()))
Definition: robin_hood.h:674
linearSystemPETSc.h
SPoint3
Definition: SPoint3.h:14
LegendrePolynomials::f
void f(int n, double u, double *val)
Definition: orthogonalBasis.cpp:77
MVertex::getNum
std::size_t getNum() const
Definition: MVertex.h:86
laplaceTerm
Definition: laplaceTerm.h:12
GModelParametrize.h
SVector3
Definition: SVector3.h:16
meshGFaceOptimize.h
PViewData::writePOS
virtual bool writePOS(const std::string &fileName, bool binary=false, bool parsed=true, bool append=false)
Definition: PViewDataIO.cpp:106
PView.h
MTriangle::getVertex
virtual MVertex * getVertex(int num)
Definition: MTriangle.h:62
linearSystemCSR.h
GEntity::edges
virtual std::vector< GEdge * > const & edges() const
Definition: GEntity.h:211
laplaceTerm.h
GModel::getEdgeByTag
GEdge * getEdgeByTag(int n) const
Definition: GModel.cpp:336
GmshMessage.h
MLine.h
edges
static int edges[6][2]
Definition: meshGRegionLocalMeshMod.cpp:23
v2t_cont
std::map< MVertex *, std::vector< MElement * >, MVertexPtrLessThan > v2t_cont
Definition: meshGFaceOptimize.h:31
MLine::getEdge
virtual MEdge getEdge(int num) const
Definition: MLine.h:56
computeNonManifoldEdges
void computeNonManifoldEdges(GModel *gm, std::vector< MLine * > &cut, bool addBoundary)
Definition: GModelParametrize.cpp:948
MEdgeLessThan
Definition: MEdge.h:122
GEntity
Definition: GEntity.h:31
dofManager::sizeOfR
virtual int sizeOfR() const
Definition: dofManager.h:606
PViewData::setFileName
virtual void setFileName(const std::string &val)
Definition: PViewData.h:75
closest
static double closest(double t, double u)
Definition: meshGFacePack.cpp:177
MElement::setVertex
virtual void setVertex(int num, MVertex *v)
Definition: MElement.h:109
PViewDataGModel::finalize
bool finalize(bool computeMinMax=true, const std::string &interpolationScheme="")
Definition: PViewDataGModel.cpp:88
MLine
Definition: MLine.h:21
CTX::instance
static CTX * instance()
Definition: Context.cpp:122
MElement::getVertex
virtual const MVertex * getVertex(int num) const =0
SPoint3::x
double x(void) const
Definition: SPoint3.h:125
linearSystemFull::addToRightHandSide
virtual void addToRightHandSide(int row, const scalar &val, int ith=0)
Definition: linearSystemFull.h:50
MElement::getEdge
virtual MEdge getEdge(int num) const =0
GModel::getPhysicalGroups
void getPhysicalGroups(std::map< int, std::vector< GEntity * > > groups[4]) const
Definition: GModel.cpp:837
GModel::lastFace
fiter lastFace()
Definition: GModel.h:359
conn
Definition: delaunay3d.cpp:257
SortEdgeConsecutive
bool SortEdgeConsecutive(const std::vector< MEdge > &e, std::vector< std::vector< MVertex * > > &vs)
Definition: MEdge.cpp:68
GModel::getPhysicalName
std::string getPhysicalName(int dim, int num) const
Definition: GModel.cpp:961
computeQuadLayout
int computeQuadLayout(GModel *gm, std::vector< int > &tags)
Definition: gmshCrossFields.cpp:3882
linearSystemGmm
Definition: linearSystemGmm.h:124
MEdge::getVertex
MVertex * getVertex(std::size_t i) const
Definition: MEdge.h:39
dofManager::numberVertex
void numberVertex(MVertex *v, int iComp, int iField)
Definition: dofManager.h:231
MElement::interpolateGrad
void interpolateGrad(double val[], double u, double v, double w, double f[], int stride=1, double invjac[3][3]=nullptr, int order=-1)
Definition: MElement.cpp:1230
intersection_segments
int intersection_segments(const SPoint2 &p1, const SPoint2 &p2, const SPoint2 &q1, const SPoint2 &q2, double x[2])
Definition: Numeric.cpp:1331
simpleFunction< double >
GEntity::mesh_vertices
std::vector< MVertex * > mesh_vertices
Definition: GEntity.h:56
Dof
Definition: dofManager.h:19
getFacesOfTheModel
static void getFacesOfTheModel(GModel *gm, std::vector< GFace * > &f)
Definition: gmshCrossFields.cpp:3862
MEdgeVertex
Definition: MVertex.h:137
Dof::createTypeWithTwoInts
static int createTypeWithTwoInts(int i1, int i2)
Definition: dofManager.h:28
linearSystemFull::systemSolve
virtual int systemSolve()
Definition: linearSystemFull.h:77
a1
const double a1
Definition: GaussQuadratureHex.cpp:10
norm
void norm(const double *vec, double *norm)
Definition: gmshLevelset.cpp:202
MTriangle::getVolume
virtual double getVolume()
Definition: MTriangle.cpp:59
Numeric.h
GModel
Definition: GModel.h:44
GModel::firstFace
fiter firstFace()
Definition: GModel.h:355
SVector3::norm
double norm() const
Definition: SVector3.h:33
SElement
Definition: SElement.h:18
dofManager::numberDof
virtual void numberDof(Dof key)
Definition: dofManager.h:213
SPoint3::y
double y(void) const
Definition: SPoint3.h:127
PViewData::setName
virtual void setName(const std::string &val)
Definition: PViewData.h:71
GModel::add
bool add(GRegion *r)
Definition: GModel.h:394
CTX::mesh
contextMeshOptions mesh
Definition: Context.h:313
dofManager< double >
itg
#define itg
Definition: libol1.h:69
MElement
Definition: MElement.h:30
PViewDataGModel.h
dofManager.h
GEntity::tag
int tag() const
Definition: GEntity.h:280
linearSystemFull.h
dofManager::assemble
virtual void assemble(const Dof &R, const Dof &C, const dataMat &value)
Definition: dofManager.h:393
SVector3::x
double x(void) const
Definition: SVector3.h:30
a2
const double a2
Definition: GaussQuadratureHex.cpp:12
S
#define S
Definition: DefaultOptions.h:21
MTriangle
Definition: MTriangle.h:26
dofManager::getDofValue
virtual void getDofValue(std::vector< Dof > &keys, std::vector< dataVec > &Vals)
Definition: dofManager.h:235
linearSystemGmm.h
GModel::writeMSH
int writeMSH(const std::string &name, double version=2.2, bool binary=false, bool saveAll=false, bool saveParametric=false, double scalingFactor=1.0, int elementStartNum=0, int saveSinglePartition=0, bool append=false)
Definition: GModelIO_MSH.cpp:76
contextMeshOptions::changed
int changed
Definition: Context.h:82
SPoint3::distance
double distance(const SPoint3 &p) const
Definition: SPoint3.h:176
b1
const double b1
Definition: GaussQuadratureHex.cpp:14
PViewDataGModel::ElementNodeData
@ ElementNodeData
Definition: PViewDataGModel.h:196
MEdge.h
discreteEdge.h
ENT_ALL
#define ENT_ALL
Definition: GmshDefines.h:235
Context.h
SVector3::y
double y(void) const
Definition: SVector3.h:31
MTriangle::getEdge
virtual MEdge getEdge(int num) const
Definition: MTriangle.h:74
dofManager::getDofNumber
virtual int getDofNumber(const Dof &ky)
Definition: dofManager.h:708
z
const double z
Definition: GaussQuadratureQuad.cpp:56
computeCrossFieldAndH
int computeCrossFieldAndH(GModel *gm, std::vector< int > &tags)
Definition: gmshCrossFields.cpp:3870
GEdge
Definition: GEdge.h:26
SVector3::z
double z(void) const
Definition: SVector3.h:32
GModel::pruneMeshVertexAssociations
void pruneMeshVertexAssociations()
Definition: GModel.cpp:2527
MElement::barycenter
virtual SPoint3 barycenter(bool primary=false) const
Definition: MElement.cpp:520
SPoint3::z
double z(void) const
Definition: SPoint3.h:129
normalize
void normalize(Quaternion &q)
Definition: Camera.cpp:370
GModel.h
MVertex::y
double y() const
Definition: MVertex.h:61
MTriangle::setVertex
virtual void setVertex(int num, MVertex *v)
Definition: MTriangle.h:64
classifyFaces
void classifyFaces(GModel *gm, double curveAngleThreshold)
Definition: GModelParametrize.cpp:103
GEntity::dim
virtual int dim() const
Definition: GEntity.h:196
MElement::getNumEdges
virtual int getNumEdges() const =0
c1
const double c1
Definition: GaussQuadratureHex.cpp:16
GModel::current
static GModel * current(int index=-1)
Definition: GModel.cpp:136
MVertex::x
double x() const
Definition: MVertex.h:60
PViewDataGModel::addData
bool addData(GModel *model, const std::map< int, std::vector< double > > &data, int step, double time, int partition, int numComp)
Definition: PViewDataGModelIO.cpp:19
SVector3::normalize
double normalize()
Definition: SVector3.h:38
faces
static int faces[4][3]
Definition: meshGRegionDelaunayInsertion.cpp:165