gmsh-TingyuanDoc  0.1
An Open-Source Timing-driven Analytical Mixed-size FPGA Placer
findLinks.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 <stdlib.h>
7 #include "GmshMessage.h"
8 #include "MallocUtils.h"
9 #include "GModel.h"
10 #include "TreeUtils.h"
11 #include "ListUtils.h"
12 
13 typedef struct {
14  int n, a;
15 } nxa;
16 
17 typedef struct {
18  int n;
20 } lnk;
21 
22 static void freeLink(void *link)
23 {
24  List_Delete(((lnk *)link)->l);
25  Free(link);
26 }
27 
28 static int complink(const void *a, const void *b)
29 {
30  lnk *q = (lnk *)a;
31  lnk *w = (lnk *)b;
32  return q->n - w->n;
33 }
34 
35 // Find all linked edges (note that we use List_ISearchSeq so that the input
36 // lists don't get sorted: it's less efficient, but it allows us to do
37 // multi-level, user-friendly undos in the GUI)
38 
39 static void recurFindLinkedEdges(int ed, List_T *edges, Tree_T *points,
40  Tree_T *links)
41 {
42  GEdge *ge = GModel::current()->getEdgeByTag(ed);
43  if(!ge) {
44  Msg::Error("Unknown curve %d", ed);
45  return;
46  }
47  if(!ge->getBeginVertex() || !ge->getEndVertex()) { return; }
48 
49  int ip[2];
50  ip[0] = ge->getBeginVertex()->tag();
51  ip[1] = ge->getEndVertex()->tag();
52 
53  for(int l = 0; l < 2; l++) {
54  lnk lk;
55  lk.n = ip[l];
56  if(!Tree_Search(points, &lk.n))
57  Tree_Add(points, &lk.n);
58  else
59  Tree_Suppress(points, &lk.n);
60  Tree_Query(links, &lk);
61  if(List_Nbr(lk.l) == 2) {
62  for(int i = 0; i < 2; i++) {
63  nxa na;
64  List_Read(lk.l, i, &na);
65  if(na.a != ed) {
66  if(List_ISearchSeq(edges, &na.a, fcmp_absint) < 0) {
67  List_Add(edges, &na.a);
68  recurFindLinkedEdges(na.a, edges, points, links);
69  }
70  }
71  }
72  }
73  }
74 }
75 
76 static int createEdgeLinks(Tree_T *links)
77 {
78  GModel *m = GModel::current();
79  for(auto it = m->firstEdge(); it != m->lastEdge(); it++) {
80  GEdge *ge = *it;
81  if(!ge->getBeginVertex() || !ge->getEndVertex()) {
82  Msg::Error("Cannot link curve %d with no begin or end point", ge->tag());
83  return 0;
84  }
85  if(ge->tag() > 0) {
86  nxa na;
87  na.a = ge->tag();
88  int ip[2];
89  ip[0] = ge->getBeginVertex()->tag();
90  ip[1] = ge->getEndVertex()->tag();
91  for(int k = 0; k < 2; k++) {
92  lnk li, *pli;
93  li.n = ip[k];
94  if((pli = (lnk *)Tree_PQuery(links, &li))) { List_Add(pli->l, &na); }
95  else {
96  li.l = List_Create(20, 1, sizeof(nxa));
97  List_Add(li.l, &na);
98  Tree_Add(links, &li);
99  }
100  }
101  }
102  }
103  return 1;
104 }
105 
106 static void orientAndSortEdges(List_T *edges, Tree_T *links)
107 {
108  List_T *temp = List_Create(List_Nbr(edges), 1, sizeof(int));
109  List_Copy(edges, temp);
110  List_Reset(edges);
111 
112  int num;
113  List_Read(temp, 0, &num);
114  List_Add(edges, &num);
115 
116  GEdge *ge0 = GModel::current()->getEdgeByTag(abs(num));
117  if(!ge0) {
118  Msg::Error("Unknown curve %d", abs(num));
119  List_Delete(temp);
120  return;
121  }
122  if(!ge0->getBeginVertex() || !ge0->getEndVertex()) {
123  Msg::Error("Cannot orient curve %d with no begin or end point", ge0->tag());
124  return;
125  }
126 
127  int sign = 1;
128  while(List_Nbr(edges) < List_Nbr(temp)) {
129  lnk lk;
130  if(sign > 0)
131  lk.n = ge0->getEndVertex()->tag();
132  else
133  lk.n = ge0->getBeginVertex()->tag();
134  Tree_Query(links, &lk);
135  for(int j = 0; j < List_Nbr(lk.l); j++) {
136  nxa na;
137  List_Read(lk.l, j, &na);
138  if(ge0->tag() != na.a && List_Search(temp, &na.a, fcmp_absint)) {
139  GEdge *ge1 = GModel::current()->getEdgeByTag(abs(na.a));
140  if(!ge1) {
141  Msg::Error("Unknown curve %d", abs(na.a));
142  List_Delete(temp);
143  return;
144  }
145  if(lk.n == ge1->getBeginVertex()->tag()) {
146  sign = 1;
147  num = na.a;
148  }
149  else {
150  sign = -1;
151  num = -na.a;
152  }
153  List_Add(edges, &num);
154  ge0 = ge1;
155  break;
156  }
157  }
158  }
159 
160  List_Delete(temp);
161 }
162 
164 {
165  Tree_T *links = Tree_Create(sizeof(lnk), complink);
166  Tree_T *points = Tree_Create(sizeof(int), fcmp_int);
167 
168  if(!createEdgeLinks(links)) {
169  Tree_Delete(links, freeLink);
170  Tree_Delete(points);
171  return 0;
172  }
173 
174  // initialize point tree with all hanging points
175  for(int i = 0; i < List_Nbr(edges); i++) {
176  int num;
177  List_Read(edges, i, &num);
178  GEdge *ge = GModel::current()->getEdgeByTag(abs(num));
179  if(!ge) {
180  Msg::Error("Unknown curve %d", abs(num));
181  Tree_Delete(links, freeLink);
182  Tree_Delete(points);
183  return 0;
184  }
185  if(!ge->getBeginVertex() || !ge->getEndVertex()) {
186  Msg::Error("Cannot link curve %d with no begin or end point", ge->tag());
187  return 0;
188  }
189  int ip[2];
190  ip[0] = ge->getBeginVertex()->tag();
191  ip[1] = ge->getEndVertex()->tag();
192  for(int k = 0; k < 2; k++) {
193  if(!Tree_Search(points, &ip[k]))
194  Tree_Add(points, &ip[k]);
195  else
196  Tree_Suppress(points, &ip[k]);
197  }
198  }
199 
200  if(List_ISearchSeq(edges, &ed, fcmp_absint) < 0) {
201  List_Add(edges, &ed);
202  recurFindLinkedEdges(ed, edges, points, links);
203  }
204 
205  int found = 0;
206 
207  if(!Tree_Nbr(points)) {
208  found = 1;
209  // at this point we can orient all the edges in a curve loop in a consistent
210  // manner (left- or right-oriented, depending on the orientation of the
211  // first edge), and we can sort them so that they form a path (we can only
212  // do this now since we allow to select disconnected parts of the loop in
213  // the GUI)
214  orientAndSortEdges(edges, links);
215  }
216 
217  Tree_Delete(links, freeLink);
218  Tree_Delete(points);
219 
220  return found;
221 }
222 
223 // Find all linked faces
224 
225 static void recurFindLinkedFaces(int fac, List_T *faces, Tree_T *edges,
226  Tree_T *links)
227 {
228  GFace *gf = GModel::current()->getFaceByTag(abs(fac));
229  if(!gf) {
230  Msg::Error("Unknown surface %d", abs(fac));
231  return;
232  }
233 
234  std::vector<GEdge *> const &l = gf->edges();
235  for(auto it = l.begin(); it != l.end(); it++) {
236  GEdge *ge = *it;
237  if(ge->degenerate(0)) continue;
238  lnk lk;
239  lk.n = std::abs(ge->tag());
240  if(!Tree_Search(edges, &lk.n))
241  Tree_Add(edges, &lk.n);
242  else
243  Tree_Suppress(edges, &lk.n);
244  Tree_Query(links, &lk);
245  if(List_Nbr(lk.l) == 2) {
246  for(int i = 0; i < 2; i++) {
247  nxa na;
248  List_Read(lk.l, i, &na);
249  if(na.a != fac) {
250  if(List_ISearchSeq(faces, &na.a, fcmp_absint) < 0) {
251  List_Add(faces, &na.a);
252  recurFindLinkedFaces(na.a, faces, edges, links);
253  }
254  }
255  }
256  }
257  }
258 }
259 
260 static void createFaceLinks(Tree_T *links)
261 {
262  GModel *m = GModel::current();
263  for(auto it = m->firstFace(); it != m->lastFace(); it++) {
264  GFace *gf = *it;
265  if(gf->tag() > 0) {
266  nxa na;
267  na.a = gf->tag();
268  std::vector<GEdge *> const &l = gf->edges();
269  for(auto ite = l.begin(); ite != l.end(); ite++) {
270  GEdge *ge = *ite;
271  if(ge->degenerate(0)) continue;
272  lnk li, *pli;
273  li.n = std::abs(ge->tag());
274  if((pli = (lnk *)Tree_PQuery(links, &li))) { List_Add(pli->l, &na); }
275  else {
276  li.l = List_Create(20, 1, sizeof(nxa));
277  List_Add(li.l, &na);
278  Tree_Add(links, &li);
279  }
280  }
281  }
282  }
283 }
284 
286 {
287  Tree_T *links = Tree_Create(sizeof(lnk), complink);
288  Tree_T *edges = Tree_Create(sizeof(int), fcmp_int);
289 
290  createFaceLinks(links);
291 
292  // initialize edge tree with all boundary edges
293  for(int i = 0; i < List_Nbr(faces); i++) {
294  int num;
295  List_Read(faces, i, &num);
296  GFace *gf = GModel::current()->getFaceByTag(abs(num));
297  if(!gf) {
298  Msg::Error("Unknown surface %d", abs(num));
299  Tree_Delete(links, freeLink);
301  return 0;
302  }
303  std::vector<GEdge *> const &l = gf->edges();
304  for(auto it = l.begin(); it != l.end(); it++) {
305  GEdge *ge = *it;
306  if(ge->degenerate(0)) continue;
307  int ic = std::abs(ge->tag());
308  if(!Tree_Search(edges, &ic))
309  Tree_Add(edges, &ic);
310  else
311  Tree_Suppress(edges, &ic);
312  }
313  }
314 
315  if(List_ISearchSeq(faces, &fac, fcmp_absint) < 0) {
316  List_Add(faces, &fac);
317  // Warning: this is correct only if the surfaces are defined with correct
318  // orientations, i.e., if the hole boundaries are oriented consistently with
319  // the exterior boundaries. There is currently nothing in the code that
320  // checks this!
321  recurFindLinkedFaces(fac, faces, edges, links);
322  }
323 
324  int found = 0;
325 
326  if(!Tree_Nbr(edges)) {
327  found = 1;
328  // we could orient the faces here, but it's not really necessary...
329  }
330 
331  Tree_Delete(links, freeLink);
333 
334  return found;
335 }
lnk
Definition: findLinks.cpp:17
GModel::firstEdge
eiter firstEdge()
Definition: GModel.h:356
GFace::edges
virtual std::vector< GEdge * > const & edges() const
Definition: GFace.h:121
List_Copy
void List_Copy(List_T *a, List_T *b)
Definition: ListUtils.cpp:283
nxa::n
int n
Definition: findLinks.cpp:14
GFace
Definition: GFace.h:33
GEntity::degenerate
virtual bool degenerate(int dim) const
Definition: GEntity.h:248
Tree_Search
int Tree_Search(Tree_T *tree, void *data)
Definition: TreeUtils.cpp:61
List_T
Definition: ListUtils.h:9
Msg::Error
static void Error(const char *fmt,...)
Definition: GmshMessage.cpp:482
ListUtils.h
fcmp_int
int fcmp_int(const void *a, const void *b)
Definition: ListUtils.cpp:26
Tree_T
Definition: TreeUtils.h:12
List_Reset
void List_Reset(List_T *liste)
Definition: ListUtils.cpp:269
List_Nbr
int List_Nbr(List_T *liste)
Definition: ListUtils.cpp:106
GModel::getFaceByTag
GFace * getFaceByTag(int n) const
Definition: GModel.cpp:326
List_Create
List_T * List_Create(int n, int incr, int size)
Definition: ListUtils.cpp:46
List_Search
int List_Search(List_T *liste, void *data, int(*fcmp)(const void *a, const void *b))
Definition: ListUtils.cpp:199
GModel::getEdgeByTag
GEdge * getEdgeByTag(int n) const
Definition: GModel.cpp:336
GmshMessage.h
edges
static int edges[6][2]
Definition: meshGRegionLocalMeshMod.cpp:23
Free
void Free(void *ptr)
Definition: MallocUtils.cpp:40
List_Add
void List_Add(List_T *liste, void *data)
Definition: ListUtils.cpp:90
GModel::lastFace
fiter lastFace()
Definition: GModel.h:359
nxa::a
int a
Definition: findLinks.cpp:14
nxa
Definition: findLinks.cpp:13
Tree_Add
void * Tree_Add(Tree_T *tree, void *data)
Definition: TreeUtils.cpp:37
Tree_PQuery
void * Tree_PQuery(Tree_T *tree, void *data)
Definition: TreeUtils.cpp:77
GModel
Definition: GModel.h:44
GEdge::getBeginVertex
virtual GVertex * getBeginVertex() const
Definition: GEdge.h:63
GModel::firstFace
fiter firstFace()
Definition: GModel.h:355
List_Delete
void List_Delete(List_T *liste)
Definition: ListUtils.cpp:66
GEntity::tag
int tag() const
Definition: GEntity.h:280
List_ISearchSeq
int List_ISearchSeq(List_T *liste, void *data, int(*fcmp)(const void *a, const void *b))
Definition: ListUtils.cpp:214
Tree_Delete
void Tree_Delete(Tree_T *tree)
Definition: TreeUtils.cpp:23
TreeUtils.h
lnk::n
int n
Definition: findLinks.cpp:18
Tree_Nbr
int Tree_Nbr(Tree_T *tree)
Definition: TreeUtils.cpp:46
GEdge
Definition: GEdge.h:26
Tree_Suppress
int Tree_Suppress(Tree_T *tree, void *data)
Definition: TreeUtils.cpp:85
GModel::lastEdge
eiter lastEdge()
Definition: GModel.h:360
GModel.h
GEdge::getEndVertex
virtual GVertex * getEndVertex() const
Definition: GEdge.h:64
Tree_Create
Tree_T * Tree_Create(int size, int(*fcmp)(const void *a, const void *b))
Definition: TreeUtils.cpp:15
MallocUtils.h
List_Read
void List_Read(List_T *liste, int index, void *data)
Definition: ListUtils.cpp:111
fcmp_absint
int fcmp_absint(const void *a, const void *b)
Definition: ListUtils.cpp:28
Tree_Query
int Tree_Query(Tree_T *tree, void *data)
Definition: TreeUtils.cpp:68
GModel::current
static GModel * current(int index=-1)
Definition: GModel.cpp:136
lnk::l
List_T * l
Definition: findLinks.cpp:19
faces
static int faces[4][3]
Definition: meshGRegionDelaunayInsertion.cpp:165