gmsh-TingyuanDoc  0.1
An Open-Source Timing-driven Analytical Mixed-size FPGA Placer
meshGFaceBipartiteLabelling.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 // Original idea of Christos Georgiadis -- 2021
7 
8 #include <queue>
9 #include <unordered_map>
10 #include "meshTriangulation.h"
11 #include "SVector3.h"
12 #include "GModel.h"
13 #include "GFace.h"
14 #include "meshOctreeLibOL.h"
15 
16 #if defined(HAVE_QUADMESHINGTOOLS)
17 #include "qmtMeshGeometryOptimization.h"
18 #include "qmtMeshUtils.h"
19 
20 static void computeNaturalCross(PolyMesh::Vertex *v, SVector3 &n, SVector3 &t1,
21  SVector3 &t2)
22 {
23  PolyMesh::HalfEdge *he = v->he;
24  n = SVector3(0, 0, 0);
25  while(1) {
26  if(he->opposite == NULL) {
27  t1 = he->d();
28  break;
29  }
30  SVector3 ta = he->d();
31  he = he->opposite->next;
32  SVector3 tb = he->d();
33  n += crossprod(ta, tb);
34  }
35 
36  he = v->he->prev;
37  while(1) {
38  if(he->opposite == NULL) {
39  t2 = -he->d();
40  break;
41  }
42  SVector3 ta = -he->d();
43  he = he->opposite->prev;
44  SVector3 tb = -he->d();
45  n += crossprod(ta, tb);
46  }
47 
48  n.normalize();
49 
50  if(fabs(dot(t1, t2)) > 0.95) {
51  t2 = crossprod(n, t1);
52  t2.normalize();
53  }
54  else if(fabs(dot(t1, t2)) > 0.5) {
55  t1 = t1 - t2;
56  t1.normalize();
57  t2 = crossprod(n, t1);
58  t2.normalize();
59  }
60 }
61 
62 static void printLabelling(const char *fn, PolyMesh *pm,
63  std::unordered_map<PolyMesh::Vertex *, int> &_labels)
64 {
65  if(Msg::GetVerbosity() < 99) return;
66  FILE *f = fopen(fn, "w");
67  fprintf(f, "View \"labels\"{\n");
68  for(auto v : pm->vertices) {
69  fprintf(f, "SP(%g,%g,%g){%d};\n", v->position.x(), v->position.y(),
70  v->position.z(), _labels[v]);
71  /*
72  if (pm->degree(v) == -1){
73  SVector3 n,t1,t2;
74  computeNaturalCross (v,n,t1,t2);
75  fprintf(f,"VP(%g,%g,%g){%g,%g,%g};\n",
76  v->position.x(),v->position.y(),v->position.z(),t1.x(),t1.y(),t1.z());
77  fprintf(f,"VP(%g,%g,%g){%g,%g,%g};\n",
78  v->position.x(),v->position.y(),v->position.z(),t2.x(),t2.y(),t2.z());
79 
80  }
81  */
82  }
83 
84  for(auto face : pm->faces) {
85  PolyMesh::Vertex *v0 = face->he->v;
86  PolyMesh::Vertex *v1 = face->he->next->v;
87  PolyMesh::Vertex *v2 = face->he->next->next->v;
88  PolyMesh::Vertex *v3 = face->he->next->next->next->v;
89  int l0 = _labels[v0];
90  int l1 = _labels[v1];
91  int l2 = _labels[v2];
92  int color;
93  if((l0 == 0 && l1 == 0 && l2 == 0) || (l0 == 1 && l1 == 1 && l2 == 1))
94  color = 1;
95  else
96  color = 0;
97  if(v0 == v3)
98  fprintf(f, "ST(%g,%g,%g,%g,%g,%g,%g,%g,%g){%d,%d,%d};\n",
99  v0->position.x(), v0->position.y(), v0->position.z(),
100  v1->position.x(), v1->position.y(), v1->position.z(),
101  v2->position.x(), v2->position.y(), v2->position.z(), color,
102  color, color);
103  else
104  fprintf(f, "SQ(%g,%g,%g,%g,%g,%g,%g,%g,%g,%g,%g,%g){%d,%d,%d,%d};\n",
105  v0->position.x(), v0->position.y(), v0->position.z(),
106  v1->position.x(), v1->position.y(), v1->position.z(),
107  v2->position.x(), v2->position.y(), v2->position.z(),
108  v3->position.x(), v3->position.y(), v3->position.z(), 0, 0, 0, 0);
109  }
110  fprintf(f, "};\n");
111  fclose(f);
112 }
113 
114 // inline int merge_faces_2(PolyMesh::HalfEdge *he){
115 // PolyMesh::HalfEdge *heo = he->opposite;
116 
117 // if(heo == nullptr) return -1;
118 
119 // PolyMesh::Face *to_delete = heo->f;
120 
121 // do{
122 // heo->f = he->f;
123 // heo = heo->next;
124 // }while(heo != he->opposite);
125 
126 // he->next->prev = heo->prev;
127 // heo->prev->next = he->next;
128 // he->prev->next = heo->next;
129 // heo->next->prev = he->prev;
130 
131 // he->f->he = he->next;
132 // he->v->he = heo->next;
133 // heo->v->he = he->next;
134 
135 // // remove afterwards...
136 // he->v = nullptr;
137 // heo->v = nullptr;
138 // to_delete->he = nullptr;
139 // return 0;
140 // }
141 
143 {
144  PolyMesh *pm = nullptr;
145  Msg::Debug("Quadrangulation of face %d using Bipartite Labelling", faceTag);
146 
147  printf("%d Quadrangulation of face\n", faceTag);
148  int result = GFace2PolyMesh(faceTag, &pm);
149  printf("%d Transfer to Half Edge done\n", faceTag);
150  if(result == -1) return;
151  std::queue<PolyMesh::Vertex *> _queue;
152  std::unordered_map<PolyMesh::Vertex *, int> _labels;
153  std::unordered_map<PolyMesh::Vertex *, SVector3> _dirs;
154 
155  for(auto v : pm->vertices) _labels[v] = -1;
156 
157  for(auto v : pm->vertices) {
158  // boundary vertex , degree returns 1 (one of the halfedges has no opposite)
159  // printf("vertex %d\n",v->data);
160  // printf("vertex %d has degree %d\n",v->data,pm->degree(v));
161  if(_labels[v] == -1 && pm->degree(v) == -1) {
162  // printf("vertex %d is on the boundary\n",v->data);
163  PolyMesh::HalfEdge *he = v->he;
164  bool currentLabel = true;
165  _labels[v] = currentLabel;
166  _queue.push(v);
167  size_t nodeCount = 0;
168  while(1) {
169  if(he->opposite == NULL) {
170  he = he->next;
171  // printf("--> vertex %d is on the boundary\n",he->v->data);
172  nodeCount++;
173  if(_labels[he->v] != -1) break;
174  currentLabel = !currentLabel;
175  _labels[he->v] = currentLabel;
176  _queue.push(he->v);
177  }
178  else
179  he = he->opposite->next;
180  }
181  if(nodeCount % 2 != 0) {
182  Msg::Warning("Bipartite algorithm requires an even numer of boundary"
183  " vertices on every edge loop that bounds face %d. This "
184  "loop has %d nodes and some triangles will remain.",
185  faceTag, nodeCount);
186  }
187  }
188  }
189 
190  printf("%d Initial labelling done\n", faceTag);
191 
192  while(!_queue.empty()) {
193  // printf("SIZE %lu\n",_queue.size());
194  auto v = _queue.front();
195  _queue.pop();
196  bool currentLabel = _labels[v];
197 
198  if(pm->degree(v) == -1) {
199  SVector3 n, t1, t2;
200  computeNaturalCross(v, n, t1, t2);
201  PolyMesh::HalfEdge *he = v->he;
202  while(he->opposite) he = he->opposite->next;
203  double dot_max = 0.0;
204  PolyMesh::HalfEdge *best = nullptr;
205  // printf("treating %lu\n",v->data);
206  while(he) {
207  // printf(" %lu\n",he->prev->v->data);
208  SVector3 t = he->d();
209  if(_labels[he->next->v] == -1) {
210  double dd = std::max(fabs(dot(t1, t)), fabs(dot(t2, t)));
211  if(dd > dot_max) {
212  dot_max = dd;
213  best = he;
214  }
215  }
216  he = he->prev->opposite;
217  }
218  if(best && dot_max > 0.9) {
219  // printf("connecting %lu to (%lu %lu) (%g
220  //%g)\n",v->data,best->v->data,best->next->v->data,
221  // best->d().x(),best->d().y());
222  _dirs[best->next->v] = best->d();
223  _labels[best->next->v] = !currentLabel;
224  _queue.push(best->next->v);
225  }
226  }
227  else {
228  SVector3 n = pm->normal(v);
229  SVector3 t1 = _dirs[v];
230  SVector3 t2 = crossprod(n, t1);
231  PolyMesh::HalfEdge *he = v->he;
232  std::vector<std::pair<double, PolyMesh::HalfEdge *> > bests;
233  // printf ("Vertex %d (%g %g): ",v->data,t1.x(),t1.y());
234  do {
235  SVector3 t = he->d();
236  double dd = -std::max(fabs(dot(t1, t)), fabs(dot(t2, t)));
237  bests.push_back(std::make_pair(dd, he));
238  // printf ("(%d,%g,%g,%g) ",he->next->v->data,dd,t.x(),t.y());
239  he = he->opposite->next;
240  } while(he != v->he);
241 
242  std::sort(bests.begin(), bests.end());
243 
244  int count = 0;
245  for(auto it : bests) {
246  if(count++ > 3) break;
247  PolyMesh::HalfEdge *best = it.second;
248  if(_labels[best->next->v] == -1) {
249  // printf("(%lu %g)", best->next->v->data, it.first);
250  _dirs[best->next->v] = best->d();
251  _labels[best->next->v] = /*rand()%2; // TEST*/ !currentLabel;
252  _queue.push(best->next->v);
253  }
254  }
255  // printf("\n");
256  }
257  }
258 
259  printf("%d internal labelling done\n", faceTag);
260 
261  // enhancement.
262  bool changed = false;
263  printLabelling("labelling_initial.pos", pm, _labels);
264  do {
265  changed = false;
266  for(auto v : pm->vertices) {
267  if(pm->degree(v) != -1) {
268  PolyMesh::HalfEdge *he = v->he;
269  int myIndex = _labels[v];
270  if(myIndex == -1) { _labels[v] = myIndex = 1; }
271  int oppositeIndex = (myIndex == 1) ? 0 : 1;
272  std::vector<int> l;
273  do {
274  l.push_back(_labels[he->next->v]);
275  he = he->opposite->next;
276  } while(he != v->he);
277  int nbInvalidBefore = 0;
278  int nbInvalidAfter = 0;
279  for(size_t i = 0; i < l.size(); i++) {
280  int i0 = l[i];
281  int i1 = l[(i + 1) % l.size()];
282  if(i0 == i1 && i0 == myIndex) nbInvalidBefore++;
283  if(i0 == i1 && i0 == oppositeIndex) nbInvalidAfter++;
284  }
285  if(nbInvalidBefore > nbInvalidAfter) {
286  // printf("%d %d\n",nbInvalidBefore,nbInvalidAfter);
287  _labels[v] = oppositeIndex;
288  changed = true;
289  }
290  }
291  }
292  } while(changed);
293  printLabelling("labelling_final.pos", pm, _labels);
294 
295  printf("%d optimum labelling done\n", faceTag);
296 
297  // split invalid edges
298 
299  for(auto he : pm->hedges) {
300  if(he->opposite != nullptr) {
301  PolyMesh::Vertex *v0 = he->v;
302  PolyMesh::Vertex *v1 = he->next->v;
303  PolyMesh::Vertex *v2 = he->next->next->v;
304  PolyMesh::Vertex *v3 = he->opposite->next->next->v;
305  int l0 = _labels[v0];
306  int l1 = _labels[v1];
307  int l2 = _labels[v2];
308  int l3 = _labels[v3];
309  if(l0 == l1 && l0 == l2 && l0 == l3) {
310  SVector3 pos = (v0->position + v1->position) * .5;
311  if(pm->split_edge(he, pos, -1) == 0) {
312  _labels[pm->vertices[pm->vertices.size() - 1]] = l0 == 1 ? 0 : 1;
313  }
314  }
315  else if(l0 == l1 && l0 == l2) {
316  SVector3 pos = (v0->position + v1->position) * .5;
317  if(pm->split_edge(he, pos, -1) == 0) {
318  _labels[pm->vertices[pm->vertices.size() - 1]] = l0 == 1 ? 0 : 1;
319  }
320  }
321  }
322  }
323 
324  printf("%d steiner points added\n", faceTag);
325 
326  printLabelling("labelling_final_split.pos", pm, _labels);
327 
328  for(auto he : pm->hedges) {
329  if(he->v != nullptr && he->opposite != nullptr) {
330  PolyMesh::Vertex *v0 = he->v;
331  PolyMesh::Vertex *v1 = he->next->v;
332  int l0 = _labels[v0];
333  int l1 = _labels[v1];
334  if(l0 == l1 && pm->num_sides(he) == 3 && pm->num_sides(he->opposite) == 3)
335  pm->merge_faces(he);
336  }
337  }
338  pm->clean();
339  printLabelling("labelling_final_split_quad.pos", pm, _labels);
340 
341  printf("%d quads created\n", faceTag);
342 
343  PolyMesh2GFace(pm, faceTag);
344 
345  printf("%d 2 gmsh done\n", faceTag);
346 
347  delete pm;
348 
349  /* GFace *gf = GModel::current()->getFaceByTag(faceTag);
350  SurfaceProjector sp;
351  fillSurfaceProjector(gf, &sp);
352  optimizeGeometryQuadMesh(gf, &sp);
353  */
354 }
355 
356 #else
357 
359 {
360  Msg::Error("This requires quad meshing tools");
361 }
362 
363 #endif
crossprod
SVector3 crossprod(const SVector3 &a, const SVector3 &b)
Definition: SVector3.h:150
PolyMesh::normal
SVector3 normal(const Vertex *v) const
Definition: meshPolyMesh.h:127
PolyMesh::num_sides
int num_sides(const HalfEdge *he) const
Definition: meshPolyMesh.h:115
dot
double dot(const SVector3 &a, const SMetric3 &m, const SVector3 &b)
Definition: STensor3.h:71
Msg::GetVerbosity
static int GetVerbosity()
Definition: GmshMessage.cpp:254
GFace.h
PolyMesh::HalfEdge::v
Vertex * v
Definition: meshPolyMesh.h:38
Msg::Debug
static void Debug(const char *fmt,...)
Definition: GmshMessage.cpp:752
Msg::Warning
static void Warning(const char *fmt,...)
Definition: GmshMessage.cpp:543
Msg::Error
static void Error(const char *fmt,...)
Definition: GmshMessage.cpp:482
LegendrePolynomials::f
void f(int n, double u, double *val)
Definition: orthogonalBasis.cpp:77
PolyMesh::HalfEdge::d
SVector3 d() const
Definition: meshPolyMesh.h:44
SVector3
Definition: SVector3.h:16
PolyMesh::clean
void clean()
Definition: meshPolyMesh.h:282
SVector3.h
PolyMesh::HalfEdge::next
HalfEdge * next
Definition: meshPolyMesh.h:41
BDS_Point::v
double v
Definition: BDS.h:57
PolyMesh::Vertex
Definition: meshPolyMesh.h:21
GFace2PolyMesh
int GFace2PolyMesh(int faceTag, PolyMesh **pm)
Definition: meshTriangulation.cpp:195
PolyMesh::faces
std::vector< Face * > faces
Definition: meshPolyMesh.h:61
SVector3::x
double x(void) const
Definition: SVector3.h:30
PolyMesh::HalfEdge::prev
HalfEdge * prev
Definition: meshPolyMesh.h:40
meshGFaceQuadrangulateBipartiteLabelling
void meshGFaceQuadrangulateBipartiteLabelling(int faceTag)
Definition: meshGFaceBipartiteLabelling.cpp:358
PolyMesh::hedges
std::vector< HalfEdge * > hedges
Definition: meshPolyMesh.h:60
meshTriangulation.h
SVector3::y
double y(void) const
Definition: SVector3.h:31
SVector3::z
double z(void) const
Definition: SVector3.h:32
PolyMesh::HalfEdge::opposite
HalfEdge * opposite
Definition: meshPolyMesh.h:42
PolyMesh::Vertex::he
PolyMesh::HalfEdge * he
Definition: meshPolyMesh.h:28
GModel.h
PolyMesh::merge_faces
int merge_faces(HalfEdge *he)
Definition: meshPolyMesh.h:217
PolyMesh
Definition: meshPolyMesh.h:15
PolyMesh::degree
int degree(const Vertex *v) const
Definition: meshPolyMesh.h:102
PolyMesh::split_edge
int split_edge(HalfEdge *he0m, const SVector3 &position, int data)
Definition: meshPolyMesh.h:289
PolyMesh::Vertex::position
SVector3 position
Definition: meshPolyMesh.h:27
meshOctreeLibOL.h
PolyMesh::vertices
std::vector< Vertex * > vertices
Definition: meshPolyMesh.h:59
PolyMesh::HalfEdge
Definition: meshPolyMesh.h:32
PolyMesh2GFace
int PolyMesh2GFace(PolyMesh *pm, int faceTag)
Definition: meshTriangulation.cpp:88
SVector3::normalize
double normalize()
Definition: SVector3.h:38