gmsh-TingyuanDoc  0.1
An Open-Source Timing-driven Analytical Mixed-size FPGA Placer
meshTriangulation.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 <utility>
7 #include <list>
8 #include <map>
9 #include <unordered_map>
10 #include "Context.h"
11 #include "gmsh.h"
12 #include "GModel.h"
13 #include "GFace.h"
14 #include "GEdge.h"
15 #include "MLine.h"
16 #include "MVertex.h"
17 #include "MTriangle.h"
18 #include "MQuadrangle.h"
19 #include "meshTriangulation.h"
20 #include "SBoundingBox3d.h"
21 #include "robustPredicates.h"
23 #include "qualityMeasures.h"
24 #include "Numeric.h"
25 #include "SPoint3.h"
26 
27 void swap(double &a, double &b)
28 {
29  double temp = a;
30  a = b;
31  b = temp;
32 }
33 
34 size_t HilbertCoordinates(double x, double y, double x0, double y0, double xRed,
35  double yRed, double xBlue, double yBlue)
36 {
37  size_t BIG = 1073741824;
38  size_t RESULT = 0;
39  for(int i = 0; i < 16; i++) {
40  double coordRed = (x - x0) * xRed + (y - y0) * yRed;
41  double coordBlue = (x - x0) * xBlue + (y - y0) * yBlue;
42  xRed /= 2;
43  yRed /= 2;
44  xBlue /= 2;
45  yBlue /= 2;
46  if(coordRed <= 0 && coordBlue <= 0) { // quadrant 0
47  x0 -= (xBlue + xRed);
48  y0 -= (yBlue + yRed);
49  swap(xRed, xBlue);
50  swap(yRed, yBlue);
51  }
52  else if(coordRed <= 0 && coordBlue >= 0) { // quadrant 1
53  RESULT += BIG;
54  x0 += (xBlue - xRed);
55  y0 += (yBlue - yRed);
56  }
57  else if(coordRed >= 0 && coordBlue >= 0) { // quadrant 2
58  RESULT += 2 * BIG;
59  x0 += (xBlue + xRed);
60  y0 += (yBlue + yRed);
61  }
62  else if(coordRed >= 0 && coordBlue <= 0) { // quadrant 3
63  x0 += (-xBlue + xRed);
64  y0 += (-yBlue + yRed);
65  swap(xRed, xBlue);
66  swap(yRed, yBlue);
67  xBlue = -xBlue;
68  yBlue = -yBlue;
69  xRed = -xRed;
70  yRed = -yRed;
71  RESULT += 3 * BIG;
72  }
73  else
74  Msg::Warning("Hilbert failed %d %d", coordRed, coordBlue);
75  BIG /= 4;
76  }
77  return RESULT;
78 }
79 
80 struct pair_hash {
81  template <class T1, class T2>
82  std::size_t operator()(const std::pair<T1, T2> &pair) const
83  {
84  return std::hash<T1>()(pair.first) ^ std::hash<T2>()(pair.second);
85  }
86 };
87 
88 int PolyMesh2GFace(PolyMesh *pm, int faceTag)
89 {
90  GFace *gf = GModel::current()->getFaceByTag(faceTag);
91 
92  if(!gf){
93  Msg::Error("PolyMesh2GFace cannot find surface %d", faceTag);
94  return 0;
95  }
96 
97  for(auto t : gf->triangles) delete t;
98  for(auto q : gf->quadrangles) delete q;
99  gf->triangles.clear();
100  gf->quadrangles.clear();
101 
102  std::unordered_map<int, MVertex *> news;
103  std::unordered_map<PolyMesh::HalfEdge *, GPoint> hon;
104 
105  if(!pm->high_order_nodes.empty()) {
106  for(size_t i = 0; i < pm->high_order_nodes.size(); i++) {
107  auto it = hon.find(pm->hedges[i]);
108  if(it == hon.end()) {
109  double uv[2] = {0, 0};
110  SVector3 p = pm->high_order_nodes[i];
111  GPoint gp = gf->closestPoint(SPoint3(p.x(), p.y(), p.z()), uv);
112  if(!gp.succeeded()) {
113  gp.x() = p.x();
114  gp.y() = p.y();
115  gp.z() = p.z();
116  }
117  hon[pm->hedges[i]] = gp;
118  if(pm->hedges[i]->opposite) hon[pm->hedges[i]] = gp;
119  }
120  }
121  }
122 
123  std::map<MEdge, GPoint, MEdgeLessThan> hop;
124 
125  for(auto f : pm->faces) {
126  if(f->data == faceTag) {
127  PolyMesh::Vertex *v[4] = {f->he->v, f->he->next->v, f->he->next->next->v,
128  f->he->next->next->next->v};
129  MVertex *v_gmsh[4];
130 
131  for(int i = 0; i < pm->num_sides(f->he); i++) {
132  if(v[i]->data != -1) {
133  auto it = news.find(v[i]->data);
134  if(it == news.end())
135  v_gmsh[i] = GModel::current()->getMeshVertexByTag(v[i]->data);
136  else
137  v_gmsh[i] = it->second;
138  }
139  else {
140  double uv[2] = {0, 0};
141  GPoint gp = gf->closestPoint(
142  SPoint3(v[i]->position.x(), v[i]->position.y(), v[i]->position.z()),
143  uv);
144  if(gp.succeeded())
145  v_gmsh[i] =
146  new MFaceVertex(gp.x(), gp.y(), gp.z(), gf, gp.u(), gp.v());
147  else
148  v_gmsh[i] = new MFaceVertex(v[i]->position.x(), v[i]->position.y(),
149  v[i]->position.z(), gf,
150  v[i]->position.x(), v[i]->position.y());
151  gf->mesh_vertices.push_back(v_gmsh[i]);
152  v[i]->data = v_gmsh[i]->getNum();
153  news[v[i]->data] = v_gmsh[i];
154  }
155  }
156 
157  if(hon.size()) {
158  MEdge l01(v_gmsh[0], v_gmsh[1]);
159  hop[l01] = hon[f->he];
160  MEdge l12(v_gmsh[1], v_gmsh[2]);
161  hop[l12] = hon[f->he->next];
162  MEdge l20(v_gmsh[2], v_gmsh[0]);
163  hop[l20] = hon[f->he->next->next];
164  }
165 
166  if(pm->num_sides(f->he) == 3)
167  gf->triangles.push_back(new MTriangle(v_gmsh[0], v_gmsh[1], v_gmsh[2]));
168  else if(pm->num_sides(f->he) == 4)
169  gf->quadrangles.push_back(
170  new MQuadrangle(v_gmsh[0], v_gmsh[1], v_gmsh[2], v_gmsh[3]));
171  }
172  }
173 
174  if(!hon.empty()) {
175  GModel::current()->setOrderN(2, 0, 0, 0);
176 #if 1
177  for(auto t : gf->triangles) {
178  for(int i = 0; i < 3; i++) {
179  MEdge li(t->getVertex(i), t->getVertex((i + 1) % 3));
180  GPoint gp = hop[li];
181  MVertex *vint = t->getVertex(i + 3);
182  vint->x() = gp.x();
183  vint->y() = gp.y();
184  vint->z() = gp.z();
185  }
186  }
187 #endif
188  }
189 
191 
192  return 0;
193 }
194 
195 int GFace2PolyMesh(int faceTag, PolyMesh **pm)
196 {
197  // FIXME using the public API inside Gmsh is not a good idea
198  if(!gmsh::isInitialized()) gmsh::initialize();
199  *pm = new PolyMesh;
200 
201  std::unordered_map<size_t, size_t> nodeLabels;
202  std::unordered_map<std::pair<size_t, size_t>, PolyMesh::HalfEdge *, pair_hash>
203  opposites;
204 
205  // FIXME should probably not use the public API here
206  std::vector<int> elementTypes;
207  std::vector<std::vector<std::size_t> > elementTags;
208  std::vector<std::vector<std::size_t> > nodeTags;
209  gmsh::model::mesh::getElements(elementTypes, elementTags, nodeTags, 2,
210  faceTag);
211 
212  for(size_t K = 0; K < elementTypes.size(); K++) {
213  int eT = elementTypes[K];
214  int nNod = 0;
215  if(eT == 2)
216  nNod = 3;
217  else if(eT == 3)
218  nNod = 4;
219  else {
220  Msg::Error("GFace2PolyMesh only support quads (element type 3) and "
221  "triangles (element type 2)");
222  return -1;
223  }
224  PolyMesh::Vertex *v[4] = {nullptr, nullptr, nullptr, nullptr};
225 
226  for(size_t i = 0; i < elementTags[K].size(); i++) {
227  for(int j = 0; j < nNod; j++) {
228  size_t nodeTag = nodeTags[K][nNod * i + j];
229  auto it = nodeLabels.find(nodeTag);
230  if(it == nodeLabels.end()) {
231  // FIXME should probably not use the public API here
232  std::vector<double> coord(3), parametricCoord(3);
233  int entityDim, entityTag;
234  gmsh::model::mesh::getNode(nodeTag, coord, parametricCoord, entityDim,
235  entityTag);
236  v[j] = new PolyMesh::Vertex(coord[0], coord[1], coord[2], nodeTag);
237  nodeLabels[nodeTag] = (*pm)->vertices.size();
238  (*pm)->vertices.push_back(v[j]);
239  }
240  else
241  v[j] = (*pm)->vertices[it->second];
242  }
243 
244  PolyMesh::HalfEdge *he[4];
245  for(int j = 0; j < nNod; j++) {
246  he[j] = new PolyMesh::HalfEdge(v[j]);
247  (*pm)->hedges.push_back(he[j]);
248  v[j]->he = he[j];
249  }
250 
251  PolyMesh::Face *ff = new PolyMesh::Face(he[0]);
252  (*pm)->faces.push_back(ff);
253 
254  for(int j = 0; j < nNod; j++) {
255  he[j]->next = he[(j + 1) % nNod];
256  he[j]->prev = he[(j - 1 + nNod) % nNod];
257  he[j]->f = ff;
258  // size_t n0 = v[j]->data;
259  // size_t n1 = v[(j+1)%nNod]->data;
260  // std::pair<size_t, size_t> pj =
261  // std::make_pair(std::min(n0,n1),std::max(n0,n1));
262  // auto itj = opposites.find(pj);
263  // if(itj == opposites.end()) opposites[pj] = he[j];
264  // else {
265  // he[j]->opposite = itj->second;
266  // itj->second->opposite = he[j];
267  // }
268  }
269  }
270  }
271 
273  std::sort((*pm)->hedges.begin(), (*pm)->hedges.end(), compare);
274 
275  HalfEdgePtrEqual equal;
276  for(size_t i = 0; i < (*pm)->hedges.size() - 1; i++) {
277  PolyMesh::HalfEdge *h0 = (*pm)->hedges[i];
278  PolyMesh::HalfEdge *h1 = (*pm)->hedges[i + 1];
279  if(equal(h0, h1)) {
280  h0->opposite = h1;
281  h1->opposite = h0;
282  i++;
283  }
284  }
285  return 0;
286 }
287 
289 {
290  if(he->opposite == nullptr) return -1;
291  PolyMesh::Vertex *v0 = he->v;
292  PolyMesh::Vertex *v1 = he->next->v;
293  PolyMesh::Vertex *v2 = he->next->next->v;
294  PolyMesh::Vertex *v = he->opposite->next->next->v;
295 
296  // FIXME : should be oriented anyway !
297  double result = -robustPredicates::incircle(v0->position, v1->position,
298  v2->position, v->position);
299 
300  return (result > 0) ? 1 : 0;
301 }
302 
303 static void faceCircumCenter(PolyMesh::HalfEdge *he, GFace *gf, double *res,
304  double *uv)
305 {
306  PolyMesh::Vertex *v0 = he->v;
307  PolyMesh::Vertex *v1 = he->next->v;
308  PolyMesh::Vertex *v2 = he->next->next->v;
309  GPoint p0 = gf->point(v0->position.x(), v0->position.y());
310  GPoint p1 = gf->point(v1->position.x(), v1->position.y());
311  GPoint p2 = gf->point(v2->position.x(), v2->position.y());
312  double q0[3] = {p0.x(), p0.y(), p0.z()};
313  double q1[3] = {p1.x(), p1.y(), p1.z()};
314  double q2[3] = {p2.x(), p2.y(), p2.z()};
315  circumCenterXYZ(q0, q1, q2, res, uv);
316 }
317 
318 static double faceQuality(PolyMesh::HalfEdge *he, GFace *gf)
319 {
320  PolyMesh::Vertex *v0 = he->v;
321  PolyMesh::Vertex *v1 = he->next->v;
322  PolyMesh::Vertex *v2 = he->next->next->v;
323  GPoint p0 = gf->point(v0->position.x(), v0->position.y());
324  GPoint p1 = gf->point(v1->position.x(), v1->position.y());
325  GPoint p2 = gf->point(v2->position.x(), v2->position.y());
326  return qmTriangle::gamma(p0.x(), p0.y(), p0.z(), p1.x(), p1.y(), p1.z(),
327  p2.x(), p2.y(), p2.z());
328 }
329 
330 /*
331 static int qualityCriterion3D(PolyMesh::HalfEdge *he, void *p){
332  if (he->data > 0) return -1;
333  if (he->opposite == nullptr) return -1;
334  if (p == nullptr) return -1;
335 
336  GFace *gf = (GFace*)p;
337 
338  PolyMesh::Vertex *v0 = he->v;
339  PolyMesh::Vertex *v1 = he->next->v;
340  PolyMesh::Vertex *v2 = he->next->next->v;
341  PolyMesh::Vertex *v3 = he->opposite->next->next->v;
342 
343  GPoint p0 = gf->point (v0->position.x(),v0->position.y());
344  GPoint p1 = gf->point (v1->position.x(),v1->position.y());
345  GPoint p2 = gf->point (v2->position.x(),v2->position.y());
346  GPoint p3 = gf->point (v3->position.x(),v3->position.y());
347 
348  double q1 = qmTriangle::gamma
349 (p0.x(),p0.y(),p0.z(),p1.x(),p1.y(),p1.z(),p2.x(),p2.y(),p2.z()); double q2 =
350 qmTriangle::gamma
351 (p2.x(),p2.y(),p2.z(),p3.x(),p3.y(),p3.z(),p0.x(),p0.y(),p0.z());
352 
353  double o1 = qmTriangle::gamma
354 (p1.x(),p1.y(),p1.z(),p2.x(),p2.y(),p2.z(),p3.x(),p3.y(),p3.z()); double o2 =
355 qmTriangle::gamma
356 (p3.x(),p3.y(),p3.z(),p0.x(),p0.y(),p0.z(),p1.x(),p1.y(),p1.z());
357 
358  return std::max(fabs(q1),fabs(q2)) > std::max(fabs(o1),fabs(o2)) ? 0 : 1;
359 }
360 */
361 
362 static PolyMesh::Face *Walk(PolyMesh::Face *f, double x, double y)
363 {
364  double POS[2] = {x, y};
365  PolyMesh::HalfEdge *he = f->he;
366 
367  while(1) {
368  PolyMesh::Vertex *v0 = he->v;
369  PolyMesh::Vertex *v1 = he->next->v;
370  PolyMesh::Vertex *v2 = he->next->next->v;
371 
372  double s0 = -robustPredicates::orient2d(v0->position, v1->position, POS);
373  double s1 = -robustPredicates::orient2d(v1->position, v2->position, POS);
374  double s2 = -robustPredicates::orient2d(v2->position, v0->position, POS);
375 
376  if(s0 >= 0 && s1 >= 0 && s2 >= 0) {
377  /* printf("Face %g %g %g / %g %g %g / %g %g %g \n",
378  v0->position.x(), v0->position.y(), v0->position.z(),
379  v1->position.x(), v1->position.y(), v1->position.z(),
380  v2->position.x(), v2->position.y(), v2->position.z());
381  printf("point %g %g CURRENT FACE %p %g %g %g\n", x,y,he->f,
382  s0,s1,s2); */
383  // getchar();
384  return he->f;
385  }
386  else if(s0 <= 0 && s1 >= 0 && s2 >= 0)
387  he = he->opposite;
388  else if(s1 <= 0 && s0 >= 0 && s2 >= 0)
389  he = he->next->opposite;
390  else if(s2 <= 0 && s0 >= 0 && s1 >= 0)
391  he = he->next->next->opposite;
392  else if(s0 <= 0 && s1 <= 0)
393  he = s0 > s1 ? he->opposite : he->next->opposite;
394  else if(s0 <= 0 && s2 <= 0)
395  he = s0 > s2 ? he->opposite : he->next->next->opposite;
396  else if(s1 <= 0 && s2 <= 0)
397  he = s1 > s2 ? he->next->opposite : he->next->next->opposite;
398  else {
399  Msg::Error("Could not find half-edge in walk for point %g %g on "
400  "face %g %g %g / %g %g %g / %g %g %g "
401  "(orientation tests %g %g %g)", x, y,
402  v0->position.x(), v0->position.y(), v0->position.z(),
403  v1->position.x(), v1->position.y(), v1->position.z(),
404  v2->position.x(), v2->position.y(), v2->position.z(),
405  s0, s1, s2);
406  }
407  if(he == nullptr) break;
408  }
409  // should only come here wether the triangulated domain is not convex
410  return nullptr;
411 }
412 
413 // recover an edge that goes from v_start --> v_end
414 // ----------------------------------- assume it's internal !!!
415 
418 {
419  double s0 =
421  double s1 =
422  robustPredicates::orient2d(v0->position, v1->position, b1->position);
423  if(s0 * s1 >= 0) return 0;
424  double t0 =
425  robustPredicates::orient2d(b0->position, b1->position, v0->position);
426  double t1 =
427  robustPredicates::orient2d(b0->position, b1->position, v1->position);
428  if(t0 * t1 >= 0) return 0;
429  return 1;
430 }
431 
432 static int recover_edge(PolyMesh *pm, PolyMesh::Vertex *v_start,
433  PolyMesh::Vertex *v_end)
434 {
435  PolyMesh::HalfEdge *he = v_start->he;
436  std::list<PolyMesh::HalfEdge *> _list;
437 
438  do {
439  PolyMesh::Vertex *v1 = he->next->v;
440  if(v1 == v_end) {
441  return 0; // edge exists
442  }
443  PolyMesh::Vertex *v2 = he->next->next->v;
444  if(v2 == v_end) {
445  return 0; // edge exists
446  }
447 
448  if(intersect(v_start, v_end, v1, v2)) {
449  // printf("INTERSECTION WITH %d %d\n", v1->data, v2->data);
450  _list.push_back(he->next);
451  break;
452  }
453  he = he->next->next->opposite;
454  } while(he != v_start->he);
455 
456  if(_list.empty()) { return -1; }
457 
458  // find all intersections
459  while(1) {
460  he = _list.back();
461  he = he->opposite;
462  if(!he) return -2;
463  he = he->next;
464  PolyMesh::Vertex *v1 = he->v;
465  PolyMesh::Vertex *v2 = he->next->v;
466  if(v2 == v_end) {
467  // printf("END FOUND %d\n", v2->data);
468  break;
469  }
470  if(intersect(v_start, v_end, v1, v2)) {
471  // printf("INTESECTION %d %d\n", v1->data, v2->data);
472  _list.push_back(he);
473  }
474  else {
475  he = he->next;
476  v1 = he->v;
477  v2 = he->next->v;
478  if(v2 == v_end) {
479  // printf("END FOUND %d\n", v2->data);
480  break;
481  }
482  if(intersect(v_start, v_end, v1, v2)) {
483  // printf("INTESECTION %d %d\n", v1->data, v2->data);
484  _list.push_back(he);
485  }
486  else {
487  return -3;
488  }
489  }
490  }
491 
492  int nbIntersection = _list.size();
493  // printf("%d intersections\n", nbIntersection);
494  // int K = 100;
495  while(!_list.empty()) {
496  he = *_list.begin();
497  _list.erase(_list.begin());
498  // ensure that swap is allowed (convex quad)
499  if(intersect(he->v, he->next->v, he->next->next->v,
500  he->opposite->next->next->v)) {
501  // ensure that swap removes one intersection
502  int still_intersect = intersect(v_start, v_end, he->next->next->v,
503  he->opposite->next->next->v);
504  // printf("swapping %d %d\n", he->v->data, he->next->v->data);
505  pm->swap_edge(he);
506  // pm->print4debug(K++);
507  if(still_intersect) _list.push_back(he);
508  }
509  else
510  _list.push_back(he);
511  }
512  return nbIntersection;
513 }
514 
516 {
517  std::stack<PolyMesh::Face *> _stack;
518  _stack.push(he->f);
519 
520  PolyMesh::HalfEdge *other_side = nullptr;
521 
522  while(!_stack.empty()) {
523  PolyMesh::Face *f = _stack.top();
524  _stack.pop();
525  f->data = color;
526  he = f->he;
527  for(int i = 0; i < 3; i++) {
528  if(he->data == -1 && he->opposite != nullptr &&
529  he->opposite->f->data == -1) {
530  _stack.push(he->opposite->f);
531  }
532  else if(he->data != -1 && he->opposite != nullptr) {
533  other_side = he->opposite;
534  }
535  he = he->next;
536  }
537  }
538  return other_side;
539 }
540 
541 void GFaceDelaunayRefinement(size_t faceTag)
542 {
543  GFace *gf = GModel::current()->getFaceByTag(faceTag);
544 
545  PolyMesh *pm = GFaceInitialMesh(faceTag, 1);
546 
547  std::list<PolyMesh::HalfEdge *> _list;
548  double _limit = 0.7;
549  for(auto f : pm->faces) {
550  double q = faceQuality(f->he, gf);
551  if(q < _limit && f->data == gf->tag()) _list.push_back(f->he);
552  }
553  // int I = 1;
554  while(!_list.empty()) {
555  PolyMesh::HalfEdge *he = *_list.begin();
556  _list.erase(_list.begin());
557  double q = faceQuality(he, gf);
558  if(q < _limit) {
559  double uv[2];
560  SPoint3 cc;
561  faceCircumCenter(he, gf, cc, uv);
562  GPoint gp = gf->closestPoint(cc, uv);
563  if(gp.succeeded()) {
564  PolyMesh::Face *f = he->f;
565  f = Walk(f, gp.u(), gp.v());
566  if(f && f->data == (int)faceTag) {
567  std::vector<PolyMesh::HalfEdge *> _touched;
568  pm->split_triangle(-1, gp.u(), gp.v(), 0, f,
570  &_touched);
571  if(_touched.size() == 3) {
572  // we should unsplit ...
573  // pm->undo_split(_touched);
574  }
575  else {
576  std::vector<PolyMesh::Face *> _f;
577  for(auto h : _touched)
578  if(std::find(_f.begin(), _f.end(), h->f) == _f.end())
579  _f.push_back(h->f);
580 
581  // printf("step %d %lu touched : ", I, _f.size());
582  for(auto pf : _f) {
583  q = faceQuality(pf->he, gf);
584  // printf("%12.5E ", q);
585  if(q < _limit && pf->data == gf->tag()) _list.push_back(pf->he);
586  }
587  // printf("\n");
588  }
589  // pm->print4debug(100000 + I++);
590  }
591  }
592  }
593  }
594 }
595 
597 {
598  PolyMesh *pm = GFaceInitialMesh(faceTag);
599 
600  GFace *gf = GModel::current()->getFaceByTag(faceTag);
601 
602  // use old code ---
603 
604  for(auto f : pm->faces) {
605  if(f->data == faceTag) {
606  size_t n0 = f->he->v->data;
607  size_t n1 = f->he->next->v->data;
608  size_t n2 = f->he->next->next->v->data;
612  gf->triangles.push_back(new MTriangle(v0, v1, v2));
613  }
614  }
615  delete pm;
616  // bowyerWatsonFrontal(gf);
617 }
618 
619 struct nodeCopies {
621  size_t nbCopies;
622  double u[8], v[8]; // max 8 copies -- reduced to 4
623  size_t id[8];
624  nodeCopies(MVertex *_mv, double _u, double _v) : mv(_mv), nbCopies(1)
625  {
626  u[0] = _u;
627  v[0] = _v;
628  }
629  void addCopy(double _u, double _v)
630  {
631  for(size_t i = 0; i < nbCopies; i++) {
632  if(fabs(u[i] - _u) < 1.e-9 && fabs(v[i] - _v) < 1.e-9) return;
633  }
634  u[nbCopies] = _u;
635  v[nbCopies] = _v;
636  nbCopies++;
637  }
638  size_t closest(double _u, double _v)
639  {
640  double minD = 1.e22;
641  size_t I = 0;
642  for(size_t i = 0; i < nbCopies; i++) {
643  double dist = sqrt((_u - u[i]) * (_u - u[i]) + (_v - v[i]) * (_v - v[i]));
644  if(dist < minD) {
645  minD = dist;
646  I = i;
647  }
648  }
649  return id[I];
650  }
651 };
652 
653 // INITIAL MESH --------- colored
654 
655 static void getNodeCopies(GFace *gf,
656  std::unordered_map<size_t, nodeCopies> &copies)
657 {
658  std::vector<GEdge *> edges = gf->edges();
659  std::vector<GEdge *> emb_edges = gf->getEmbeddedEdges();
660  edges.insert(edges.end(), emb_edges.begin(), emb_edges.end());
661  std::set<GEdge *> touched;
662 
663  if(edges.empty())
664  edges.insert(edges.end(), gf->model()->firstEdge(),
665  gf->model()->lastEdge());
666 
667  for(auto e : edges) {
668  if(!e->isMeshDegenerated()) {
669  std::set<MVertex *, MVertexPtrLessThan> e_vertices;
670  for(std::size_t i = 0; i < e->lines.size(); i++) {
671  MVertex *v1 = e->lines[i]->getVertex(0);
672  MVertex *v2 = e->lines[i]->getVertex(1);
673  e_vertices.insert(v1);
674  e_vertices.insert(v2);
675  }
676  int direction = -1;
677  if(e->isSeam(gf)) {
678  direction = 0;
679  if(touched.find(e) == touched.end())
680  touched.insert(e);
681  else
682  direction = 1;
683  }
684  // printf("model edge %lu %lu vertices\n", e->tag(), e_vertices.size());
685  for(auto v : e_vertices) {
686  SPoint2 param;
687  if(direction != -1) {
688  double t = 0;
689  if(v->onWhat()->dim() == 0)
690  reparamMeshVertexOnEdge(v, e, t);
691  else if(v->onWhat()->dim() == 1)
692  v->getParameter(0, t);
693  else
694  Msg::Error("a seam edge without CAD ?");
695  param = e->reparamOnFace(gf, t, direction);
696  }
697  else {
698  // Hmm...
699  if(!gf->haveParametrization() &&
701  param = SPoint2(v->x(), v->y());
702  }
703  else
704  reparamMeshVertexOnFace(v, gf, param);
705  }
706  std::unordered_map<size_t, nodeCopies>::iterator it =
707  copies.find(v->getNum());
708  if(it == copies.end()) {
709  nodeCopies c(v, param.x(), param.y());
710  copies.insert(std::make_pair(v->getNum(), c));
711  }
712  else {
713  it->second.addCopy(param.x(), param.y());
714  }
715  }
716  }
717  }
718 
719  std::vector<GVertex *> emb_vertx = gf->getEmbeddedVertices();
720  for(auto v : emb_vertx) {
721  SPoint2 param;
722  reparamMeshVertexOnFace(v->mesh_vertices[0], gf, param);
723  nodeCopies c(v->mesh_vertices[0], param.x(), param.y());
724  copies.insert(std::make_pair(v->mesh_vertices[0]->getNum(), c));
725  }
726 }
727 
728 void addPoints(PolyMesh *pm, std::vector<double> &pts, SBoundingBox3d &bb)
729 {
730  const size_t N = pts.size() / 2;
731  std::vector<double> X(N), Y(N);
732  std::vector<size_t> HC(N), IND(N);
733  PolyMesh::Face *f = pm->faces[0];
734  for(size_t i = 0; i < N; i++) {
735  X[i] = pts[2 * i];
736  Y[i] = pts[2 * i + 1];
737  HC[i] = HilbertCoordinates(X[i], Y[i], bb.center().x(), bb.center().y(),
738  bb.max().x() - bb.center().x(), 0, 0,
739  bb.max().y() - bb.center().y());
740  IND[i] = i;
741  }
742  std::sort(IND.begin(), IND.end(),
743  [&](size_t i, size_t j) { return HC[i] < HC[j]; });
744 
745  for(size_t i = 0; i < N; i++) {
746  size_t I = IND[i];
747  f = Walk(f, X[I], Y[I]);
749  nullptr);
750  }
751 }
752 
753 PolyMesh *GFaceInitialMesh(int faceTag, int recover,
754  std::vector<double> *additional)
755 {
756  GFace *gf = GModel::current()->getFaceByTag(faceTag);
757 
758  if(!gf) Msg::Error("GFaceInitialMesh: no face with tag %d", faceTag);
759 
760  PolyMesh *pm = new PolyMesh;
761 
762  std::unordered_map<size_t, nodeCopies> copies;
763  getNodeCopies(gf, copies);
764 
765  SBoundingBox3d bb;
766  for(auto c : copies) {
767  for(size_t i = 0; i < c.second.nbCopies; i++)
768  bb += SPoint3(c.second.u[i], c.second.v[i], 0);
769  }
770  bb *= 1.1;
771  pm->initialize_rectangle(bb.min().x(), bb.max().x(), bb.min().y(),
772  bb.max().y());
773  PolyMesh::Face *f = pm->faces[0];
774  for(std::unordered_map<size_t, nodeCopies>::iterator it = copies.begin();
775  it != copies.end(); ++it) {
776  for(size_t i = 0; i < it->second.nbCopies; i++) {
777  double x = it->second.u[i];
778  double y = it->second.v[i];
779  // find face in which lies x,y
780  f = Walk(f, x, y);
781  // split f and then swap edges to recover delaunayness
783  nullptr);
784  // remember node tags
785  it->second.id[i] = pm->vertices.size() - 1;
786  pm->vertices[pm->vertices.size() - 1]->data = it->first;
787  }
788  }
789 
790  //pm->print4debug(faceTag);
791 
792  if(recover) {
793  std::vector<GEdge *> edges = gf->edges();
794  std::vector<GEdge *> emb_edges = gf->getEmbeddedEdges();
795  edges.insert(edges.end(), emb_edges.begin(), emb_edges.end());
796  if(edges.empty())
797  edges.insert(edges.end(), gf->model()->firstEdge(),
798  gf->model()->lastEdge());
799 
800  for(auto e : edges) {
801  if(!e->isMeshDegenerated()) {
802  for(auto l : e->lines) {
803  auto c0 = copies.find(l->getVertex(0)->getNum());
804  auto c1 = copies.find(l->getVertex(1)->getNum());
805  if(c0 == copies.end() || c1 == copies.end())
806  Msg::Error("unable to find %lu %lu %d %d",
807  l->getVertex(0)->getNum(), l->getVertex(1)->getNum(),
808  c0 == copies.end(), c1 == copies.end());
809  if(c0->second.nbCopies > c1->second.nbCopies) {
810  auto cc = c0;
811  c0 = c1;
812  c1 = cc;
813  }
814  for(size_t j = 0; j < c0->second.nbCopies; j++) {
815  PolyMesh::Vertex *v0 = pm->vertices[c0->second.id[j]];
816  PolyMesh::Vertex *v1 = pm->vertices[c1->second.closest(
817  c0->second.u[j], c0->second.v[j])];
818  int result = recover_edge(pm, v0, v1);
819  if(result < 0) {
820  Msg::Warning("Impossible to recover edge %lu %lu (error tag %d)",
821  l->getVertex(0)->getNum(), l->getVertex(0)->getNum(),
822  result);
823  }
824  else {
825  PolyMesh::HalfEdge *he = pm->getEdge(v0, v1);
826  if(he) {
827  if(he->opposite) he->opposite->data = e->tag();
828  he->data = e->tag();
829  }
830  }
831  }
832  }
833  }
834  }
835 
836  // color all PolyMesh::Faces
837  // the first 4 vertices are "infinite vertices" --> color them with tag -2
838  // meaning exterior
839  PolyMesh::HalfEdge *other_side = Color(pm->vertices[0]->he, -2);
840  // other_side is inthernal to the face --> color them with tag faceTag
841  other_side = Color(other_side, faceTag);
842  // holes will be tagged -1
843 
844  // flip edges that have been scrambled
845  int iter = 0;
846  while(iter++ < 100) {
847  int count = 0;
848  for(auto he : pm->hedges) {
849  if(he->opposite && he->f->data == faceTag &&
850  he->opposite->f->data == faceTag) {
851  if(delaunayEdgeCriterionPlaneIsotropic(he, nullptr)) {
852  if(intersect(he->v, he->next->v, he->next->next->v,
853  he->opposite->next->next->v)) {
854  pm->swap_edge(he);
855  count++;
856  }
857  }
858  }
859  }
860  if(!count) break;
861  }
862  }
863 
864  if(additional) addPoints(pm, *additional, bb);
865 
866  return pm;
867 }
Color
static PolyMesh::HalfEdge * Color(PolyMesh::HalfEdge *he, int color)
Definition: meshTriangulation.cpp:515
GModel::setOrderN
int setOrderN(int order, int linear, int incomplete, int onlyVisible)
Definition: GModel.cpp:1454
GPoint::succeeded
bool succeeded() const
Definition: GPoint.h:63
MTriangle.h
qualityMeasures.h
PolyMesh::num_sides
int num_sides(const HalfEdge *he) const
Definition: meshPolyMesh.h:115
nodeCopies::addCopy
void addCopy(double _u, double _v)
Definition: meshTriangulation.cpp:629
GModel::firstEdge
eiter firstEdge()
Definition: GModel.h:356
GFace::edges
virtual std::vector< GEdge * > const & edges() const
Definition: GFace.h:121
MEdge
Definition: MEdge.h:14
GPoint::y
double y() const
Definition: GPoint.h:22
GFace.h
PolyMesh::Face::data
int data
Definition: meshPolyMesh.h:56
PolyMesh::swap_edge
int swap_edge(HalfEdge *he0)
Definition: meshPolyMesh.h:197
isInitialized
static bool isInitialized
Definition: GmshGlobal.cpp:63
GFace::getEmbeddedVertices
std::vector< GVertex * > getEmbeddedVertices(bool force=false) const
Definition: GFace.cpp:355
GFace
Definition: GFace.h:33
GFace::triangles
std::vector< MTriangle * > triangles
Definition: GFace.h:428
GEntity::model
GModel * model() const
Definition: GEntity.h:277
SPoint2
Definition: SPoint2.h:12
PolyMesh::HalfEdge::v
Vertex * v
Definition: meshPolyMesh.h:38
robustPredicates.h
c
static double c(int i, int j, fullMatrix< double > &CA, const std::vector< SPoint3 > &P, const std::vector< SPoint3 > &Q)
Definition: discreteFrechetDistance.cpp:15
PolyMesh::Face
Definition: meshPolyMesh.h:52
MVertex
Definition: MVertex.h:24
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
reparamMeshVertexOnFace
bool reparamMeshVertexOnFace(MVertex const *v, const GFace *gf, SPoint2 &param, bool onSurface, bool failOnSeam, int dir)
Definition: MVertex.cpp:522
SPoint3
Definition: SPoint3.h:14
LegendrePolynomials::f
void f(int n, double u, double *val)
Definition: orthogonalBasis.cpp:77
nodeCopies::v
double v[8]
Definition: meshTriangulation.cpp:622
MVertex::getNum
std::size_t getNum() const
Definition: MVertex.h:86
GModel::getFaceByTag
GFace * getFaceByTag(int n) const
Definition: GModel.cpp:326
SBoundingBox3d::min
SPoint3 min() const
Definition: SBoundingBox3d.h:90
nodeCopies::u
double u[8]
Definition: meshTriangulation.cpp:622
GFace::point
virtual GPoint point(double par1, double par2) const =0
SVector3
Definition: SVector3.h:16
nodeCopies::nodeCopies
nodeCopies(MVertex *_mv, double _u, double _v)
Definition: meshTriangulation.cpp:624
GModel::getMeshVertexByTag
MVertex * getMeshVertexByTag(int n)
Definition: GModel.cpp:1953
MLine.h
edges
static int edges[6][2]
Definition: meshGRegionLocalMeshMod.cpp:23
pair_hash
Definition: meshTriangulation.cpp:80
HalfEdgePtrEqual
Definition: meshPolyMesh.h:512
GPoint
Definition: GPoint.h:13
GFace::closestPoint
virtual GPoint closestPoint(const SPoint3 &queryPoint, const double initialGuess[2]) const
Definition: GFace.cpp:1323
PolyMesh::HalfEdge::next
HalfEdge * next
Definition: meshPolyMesh.h:41
reparamMeshVertexOnEdge
bool reparamMeshVertexOnEdge(MVertex *v, const GEdge *ge, double &param)
Definition: MVertex.cpp:592
faceQuality
static double faceQuality(PolyMesh::HalfEdge *he, GFace *gf)
Definition: meshTriangulation.cpp:318
GFace::quadrangles
std::vector< MQuadrangle * > quadrangles
Definition: GFace.h:429
GPoint::z
double z() const
Definition: GPoint.h:23
SBoundingBox3d::center
SPoint3 center() const
Definition: SBoundingBox3d.h:92
nodeCopies::mv
MVertex * mv
Definition: meshTriangulation.cpp:620
CTX::instance
static CTX * instance()
Definition: Context.cpp:122
faceCircumCenter
static void faceCircumCenter(PolyMesh::HalfEdge *he, GFace *gf, double *res, double *uv)
Definition: meshTriangulation.cpp:303
SPoint3::x
double x(void) const
Definition: SPoint3.h:125
GEdge.h
GPoint::u
double u() const
Definition: GPoint.h:27
GEntity::mesh_vertices
std::vector< MVertex * > mesh_vertices
Definition: GEntity.h:56
recover_edge
static int recover_edge(PolyMesh *pm, PolyMesh::Vertex *v_start, PolyMesh::Vertex *v_end)
Definition: meshTriangulation.cpp:432
Walk
static PolyMesh::Face * Walk(PolyMesh::Face *f, double x, double y)
Definition: meshTriangulation.cpp:362
GFaceDelaunayRefinementOldMesher
void GFaceDelaunayRefinementOldMesher(int faceTag)
Definition: meshTriangulation.cpp:596
intersect
static int intersect(PolyMesh::Vertex *v0, PolyMesh::Vertex *v1, PolyMesh::Vertex *b0, PolyMesh::Vertex *b1)
Definition: meshTriangulation.cpp:416
SBoundingBox3d.h
MVertex.h
swap
void swap(double &a, double &b)
Definition: meshTriangulation.cpp:27
qmTriangle::gamma
static double gamma(MTriangle *f)
Definition: qualityMeasures.cpp:146
nodeCopies
Definition: meshTriangulation.cpp:619
nodeCopies::closest
size_t closest(double _u, double _v)
Definition: meshTriangulation.cpp:638
Numeric.h
PolyMesh::Vertex
Definition: meshPolyMesh.h:21
HalfEdgePtrLessThan
Definition: meshPolyMesh.h:498
meshGFaceDelaunayInsertion.h
GFace2PolyMesh
int GFace2PolyMesh(int faceTag, PolyMesh **pm)
Definition: meshTriangulation.cpp:195
GEntity::geomType
virtual GeomType geomType() const
Definition: GEntity.h:238
pair_hash::operator()
std::size_t operator()(const std::pair< T1, T2 > &pair) const
Definition: meshTriangulation.cpp:82
SPoint3::y
double y(void) const
Definition: SPoint3.h:127
PolyMesh::faces
std::vector< Face * > faces
Definition: meshPolyMesh.h:61
CTX::mesh
contextMeshOptions mesh
Definition: Context.h:313
PolyMesh::getEdge
HalfEdge * getEdge(Vertex *v0, Vertex *v1)
Definition: meshPolyMesh.h:142
PolyMesh::initialize_rectangle
void initialize_rectangle(double xmin, double xmax, double ymin, double ymax)
Definition: meshPolyMesh.h:361
GEntity::tag
int tag() const
Definition: GEntity.h:280
MFaceVertex
Definition: MVertex.h:168
getNodeCopies
static void getNodeCopies(GFace *gf, std::unordered_map< size_t, nodeCopies > &copies)
Definition: meshTriangulation.cpp:655
SVector3::x
double x(void) const
Definition: SVector3.h:30
PolyMesh::Vertex::data
int data
Definition: meshPolyMesh.h:29
PolyMesh::HalfEdge::prev
HalfEdge * prev
Definition: meshPolyMesh.h:40
MTriangle
Definition: MTriangle.h:26
GEntity::DiscreteSurface
@ DiscreteSurface
Definition: GEntity.h:117
HilbertCoordinates
size_t HilbertCoordinates(double x, double y, double x0, double y0, double xRed, double yRed, double xBlue, double yBlue)
Definition: meshTriangulation.cpp:34
contextMeshOptions::changed
int changed
Definition: Context.h:82
GFaceInitialMesh
PolyMesh * GFaceInitialMesh(int faceTag, int recover, std::vector< double > *additional)
Definition: meshTriangulation.cpp:753
GFace::getEmbeddedEdges
std::vector< GEdge * > getEmbeddedEdges(bool force=false) const
Definition: GFace.cpp:362
b1
const double b1
Definition: GaussQuadratureHex.cpp:14
SPoint2::x
double x(void) const
Definition: SPoint2.h:86
ENT_ALL
#define ENT_ALL
Definition: GmshDefines.h:235
Context.h
PolyMesh::hedges
std::vector< HalfEdge * > hedges
Definition: meshPolyMesh.h:60
meshTriangulation.h
SVector3::y
double y(void) const
Definition: SVector3.h:31
MQuadrangle.h
circumCenterXYZ
void circumCenterXYZ(double *p1, double *p2, double *p3, double *res, double *uv)
Definition: Numeric.cpp:342
SVector3::z
double z(void) const
Definition: SVector3.h:32
PolyMesh::HalfEdge::data
int data
Definition: meshPolyMesh.h:43
PolyMesh::HalfEdge::opposite
HalfEdge * opposite
Definition: meshPolyMesh.h:42
direction
static void direction(Vertex *v1, Vertex *v2, double d[3])
Definition: Geo.cpp:218
PolyMesh::split_triangle
int split_triangle(int index, double x, double y, double z, Face *f, int(*doSwap)(PolyMesh::HalfEdge *, void *)=NULL, void *data=NULL, std::vector< HalfEdge * > *_t=NULL)
Definition: meshPolyMesh.h:397
PolyMesh::Vertex::he
PolyMesh::HalfEdge * he
Definition: meshPolyMesh.h:28
nodeCopies::nbCopies
size_t nbCopies
Definition: meshTriangulation.cpp:621
GPoint::v
double v() const
Definition: GPoint.h:28
PolyMesh::high_order_nodes
std::vector< SVector3 > high_order_nodes
Definition: meshPolyMesh.h:62
GModel::lastEdge
eiter lastEdge()
Definition: GModel.h:360
delaunayEdgeCriterionPlaneIsotropic
static int delaunayEdgeCriterionPlaneIsotropic(PolyMesh::HalfEdge *he, void *)
Definition: meshTriangulation.cpp:288
GModel.h
MVertex::y
double y() const
Definition: MVertex.h:61
addPoints
void addPoints(PolyMesh *pm, std::vector< double > &pts, SBoundingBox3d &bb)
Definition: meshTriangulation.cpp:728
compare
bool compare(const MVertex *const v0, const MVertex *const v1)
Definition: MFace.cpp:15
SBoundingBox3d::max
SPoint3 max() const
Definition: SBoundingBox3d.h:91
PolyMesh
Definition: meshPolyMesh.h:15
SPoint3.h
GPoint::x
double x() const
Definition: GPoint.h:21
c1
const double c1
Definition: GaussQuadratureHex.cpp:16
PolyMesh::Vertex::position
SVector3 position
Definition: meshPolyMesh.h:27
robustPredicates::orient2d
REAL orient2d(REAL *pa, REAL *pb, REAL *pc)
Definition: robustPredicates.cpp:1633
MQuadrangle
Definition: MQuadrangle.h:26
SBoundingBox3d
Definition: SBoundingBox3d.h:21
PolyMesh::vertices
std::vector< Vertex * > vertices
Definition: meshPolyMesh.h:59
GModel::current
static GModel * current(int index=-1)
Definition: GModel.cpp:136
GFaceDelaunayRefinement
void GFaceDelaunayRefinement(size_t faceTag)
Definition: meshTriangulation.cpp:541
GEntity::haveParametrization
virtual bool haveParametrization()
Definition: GEntity.h:251
MVertex::x
double x() const
Definition: MVertex.h:60
PolyMesh::HalfEdge
Definition: meshPolyMesh.h:32
PolyMesh2GFace
int PolyMesh2GFace(PolyMesh *pm, int faceTag)
Definition: meshTriangulation.cpp:88
robustPredicates::incircle
REAL incircle(REAL *pa, REAL *pb, REAL *pc, REAL *pd)
Definition: robustPredicates.cpp:3245
PolyMesh::HalfEdge::f
Face * f
Definition: meshPolyMesh.h:39
SPoint2::y
double y(void) const
Definition: SPoint2.h:88